diff --git a/.claude/skills/publish-registry/SKILL.md b/.claude/skills/publish-registry/SKILL.md deleted file mode 100644 index 3a1f60e5b..000000000 --- a/.claude/skills/publish-registry/SKILL.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: publish-registry -description: Publish @agentos-software/* registry packages (per-package semver; dist-tag dev by default, latest only deliberately). Use whenever the user asks to publish or release registry software/agent packages. ---- - -# Publish registry packages - -Registry packages version **independently** (per-package semver in each -`package.json`). Publishing never moves `latest` unless asked. Full lifecycle -reference: `registry/README.md`. - -1. **Build** (skip what's already built): - - ```bash - just registry-native # native wasm binaries, once per checkout (slow) - just registry-build [pkg] # stage bin/ + assemble dist/package - just registry-status --remote # local state vs published dist-tags - ``` - -2. **Bump the version** in `registry/software//package.json` (or - `registry/agent//`) and commit it. - -3. **Publish**: - - ```bash - just registry-publish # dist-tag dev (safe default) - just registry-publish latest # DELIBERATE release — moves latest - just registry-publish-all [tag] # every built software package - ``` - -Notes: -- secure-exec **previews** (publish.yaml, no version input) automatically - include all registry packages under the branch dist-tag — no manual step for - preview consumers. -- agent-os pins per-package: `just agentos-pkgs-update [tag]` / - `just agentos-pkgs-set-version ` over there. diff --git a/.claude/skills/release-preview/SKILL.md b/.claude/skills/release-preview/SKILL.md deleted file mode 100644 index 3ab55de4c..000000000 --- a/.claude/skills/release-preview/SKILL.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: release-preview -description: Cut a secure-exec release-preview — npm-only branch-dist-tag publish (registry packages included), no crates.io. Use when the user asks for a preview / release-preview of secure-exec, or to hand a build to a downstream. ---- - -# Release-preview secure-exec - -A preview publishes the `@secure-exec/*` packages AND the `@agentos-software/*` -registry packages to npm under the sanitized branch dist-tag, versioned -`0.0.0-.`, from a fast debug build. No crates.io publish (it has -no preview track — crate changes reach downstreams via their clone-at-sha -builds), no git tag, no release assets. - -1. **Push the branch** you want previewed (jj colocated; use - `jj --config snapshot.max-new-file-size=16777216 ...` if large assets - complain). - -2. **Dispatch + watch**: - - ```bash - just release-preview - run=$(gh run list -R rivet-dev/secure-exec --workflow=publish.yaml -L1 --json databaseId --jq '.[0].databaseId') - gh run watch -R rivet-dev/secure-exec "$run" --exit-status - ``` - -3. **Consume**: `npm install @secure-exec/core@` (same tag for - the registry packages). agent-os does NOT normally consume these directly — - it pins a sha in `.github/refs/secure-exec` and its own release-preview - auto-cuts the matching secure-exec preview (branch `agentos-dep-`). - -Notes: -- Release-preview is for previews ONLY; never cut a release with it — releases - go through the `release` skill. -- On failure: `gh run view --log-failed`, fix, re-dispatch, re-watch. diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md deleted file mode 100644 index 969c2ed6f..000000000 --- a/.claude/skills/release/SKILL.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: release -description: Cut a stable secure-exec release — npm + crates.io in lockstep, plus the manual @secure-exec/core wasm publish. Use whenever the user asks to release secure-exec (a real version, not a preview). ---- - -# Release secure-exec (stable) - -Releases publish the `@secure-exec/*` npm packages AND the `secure-exec-*` -crates at the SAME version. Previews are a different flow (npm-only branch -dist-tag; see CLAUDE.md "Preview-publishing"). - -1. **Cut the release** from a clean, pushed main checkout: - - ```bash - just release --patch -y # or --minor / --major / --version ; -rc. versions get the rc tag - ``` - - This bumps versions, commits, pushes, and dispatches `publish.yaml` with the - version input → release build: npm `@latest`, crates.io, GitHub release assets. - -2. **Watch it green**: - - ```bash - run=$(gh run list -R rivet-dev/secure-exec --workflow=publish.yaml -L1 --json databaseId --jq '.[0].databaseId') - gh run watch -R rivet-dev/secure-exec "$run" --exit-status - ``` - -3. **Manual step — `@secure-exec/core`** (CI-excluded; its tarball vendors the - wasm commands and CI does not build them): - - ```bash - make -C registry/native wasm - cd packages/core && npm publish # npm, NOT pnpm; same version CI used; prepack fails loud if commands absent - ``` - -4. **Registry packages are NOT part of a release** — they version per-package; - use the `publish-registry` skill. - -5. Downstream: an agent-os release passes this version via - `just release --secure-exec-version ` (agent-os `release-agentos` skill). diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml deleted file mode 100644 index 1e6751b43..000000000 --- a/.github/workflows/bench.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: Bench - -on: - pull_request: - paths: - - "crates/**" - - "packages/**" - schedule: - - cron: "17 9 * * *" - workflow_dispatch: - -jobs: - gate: - name: Bench gate - if: github.event_name == 'pull_request' - runs-on: [self-hosted, agentos-builder] - timeout-minutes: 40 - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: 22 - - - uses: dtolnay/rust-toolchain@stable - with: - targets: wasm32-wasip1 - - - name: Enable pnpm - run: corepack enable - - - name: Install benchmark workspace dependencies - run: pnpm install --frozen-lockfile --filter "@secure-exec/benchmarks..." --filter "@secure-exec/build-tools..." - - - name: Build @secure-exec/core (bench ops import its dist) - run: pnpm --dir packages/core build - - - name: Build guest WASM command binaries (ls_100 vmCmd row) - run: | - make -C registry/native wasm - node packages/core/scripts/copy-wasm-commands.mjs - - - name: Build release benchmark binaries - run: | - cargo build --release -p secure-exec-sidecar - cargo build --release -p native-baseline - cargo build --release -p native-baseline --target wasm32-wasip1 - - - name: Check native benchmark op wiring - run: pnpm --dir packages/benchmarks bench:check - - - name: Run quick benchmark gate - env: - SECURE_EXEC_SIDECAR_BIN: ${{ github.workspace }}/target/release/secure-exec-sidecar - run: pnpm --dir packages/benchmarks bench:gate - - nightly: - name: Nightly benchmark matrix - if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' - runs-on: [self-hosted, agentos-builder] - timeout-minutes: 90 - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: 22 - - - uses: dtolnay/rust-toolchain@stable - with: - targets: wasm32-wasip1 - - - name: Enable pnpm - run: corepack enable - - - name: Install benchmark workspace dependencies - run: pnpm install --frozen-lockfile --filter "@secure-exec/benchmarks..." --filter "@secure-exec/build-tools..." - - - name: Build @secure-exec/core (bench ops import its dist) - run: pnpm --dir packages/core build - - - name: Build guest WASM command binaries (VM boot + ecosystem rows) - run: | - make -C registry/native wasm - node packages/core/scripts/copy-wasm-commands.mjs - - - name: Build release benchmark binaries - run: | - cargo build --release -p secure-exec-sidecar - cargo build --release -p native-baseline - cargo build --release -p native-baseline --target wasm32-wasip1 - - - name: Check native benchmark op wiring - run: pnpm --dir packages/benchmarks bench:check - - - name: Run full benchmark matrix - env: - SECURE_EXEC_SIDECAR_BIN: ${{ github.workspace }}/target/release/secure-exec-sidecar - run: pnpm --dir packages/benchmarks bench:matrix - - - name: Write CI candidate baseline - env: - SECURE_EXEC_SIDECAR_BIN: ${{ github.workspace }}/target/release/secure-exec-sidecar - run: pnpm --dir packages/benchmarks bench:baseline -- --ci --from results/latency-matrix.json - - - name: Upload benchmark results - uses: actions/upload-artifact@v4 - with: - name: nightly-benchmark-results - path: | - packages/benchmarks/results/latency-matrix.json - packages/benchmarks/results/findings.json - packages/benchmarks/results/baseline-ci.json diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml deleted file mode 100644 index 61d8bd780..000000000 --- a/.github/workflows/ci-nightly.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: CI Nightly - -# The PR/push CI (ci.yml) is hermetic and fast: it skips network e2e and the -# #[ignore]d resource-saturation tests. This job runs that expensive tail once -# a day (and on demand) so the coverage still exists without taxing every PR. -on: - schedule: - - cron: "23 8 * * *" - workflow_dispatch: - -concurrency: - group: ci-nightly-${{ github.ref }} - cancel-in-progress: false - -jobs: - extras: - runs-on: [self-hosted, agentos-builder] - timeout-minutes: 90 - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - uses: dtolnay/rust-toolchain@stable - with: - targets: wasm32-wasip1 - - uses: taiki-e/install-action@v2 - with: - tool: nextest - - run: npx --yes zx@8 scripts/ci.mjs nightly-extras diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d037b96ba..fc04b178e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,14 +1,3 @@ -# INTENTIONAL: the cache-heavy rust/registry jobs here (wasm-commands, rust-lint, -# rust-test, js-test) run on the agent-os self-hosted builders -# (runs-on: [self-hosted, agentos-builder]), NOT GitHub-hosted runners. The cheap -# job (js-checks — typecheck/boundary/publish tests) stays on GitHub Actions, -# which spins up small/dynamically and doesn't need the warm cache. -# agent-os compiles the secure-exec crates (via the prepare-build clone), so both -# repos share ONE warm secure-exec build cache on those boxes — the cargo -# registry, the rusty_v8 V8 prebuilt, and sccache'd crate objects (shared -# CARGO_HOME + SCCACHE_DIR). secure-exec CI warms the cache agent-os reuses, and -# vice versa. On the self-hosted jobs the persistent on-disk target/ + CARGO_HOME -# + sccache replace the GHA cache steps, which is why they're absent there. name: CI on: @@ -17,57 +6,8 @@ on: push: branches: [main] -concurrency: - group: ci-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - jobs: - # Guest WASM command binaries are needed by both the cargo service tests and - # the JS turbo tests. Build them once here and hand them to both via an - # artifact so neither pays the cold build twice. - wasm-commands: - runs-on: [self-hosted, agentos-builder] - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - uses: dtolnay/rust-toolchain@stable - with: - targets: wasm32-wasip1 - - run: pnpm install --frozen-lockfile --filter "@secure-exec/core..." - # Cache the built guest WASM commands. `make -C registry/native wasm` is a - # ~4.5min `cargo build -Z build-std` against a PATCHED std + vendored crates, - # so it recompiles std-from-source every run and the persistent target/ - # can't warm it — but its OUTPUT is deterministic from the registry command - # sources. Key on those sources: a command/patch/toolchain change rebuilds, - # an unchanged tree restores in seconds. This is the one spot a GHA cache - # beats the on-disk target (the build is uncacheable; the output isn't). - - uses: actions/cache@v4 - id: wasm-cache - with: - path: | - packages/core/commands - registry/native/target/wasm32-wasip1/release/commands - key: wasm-commands-v1-${{ hashFiles('registry/native/crates/**', 'registry/native/patches/**', 'registry/native/scripts/**', 'registry/native/Makefile', 'registry/native/Cargo.toml', 'registry/native/Cargo.lock', 'rust-toolchain.toml') }} - - if: steps.wasm-cache.outputs.cache-hit != 'true' - run: make -C registry/native wasm - - if: steps.wasm-cache.outputs.cache-hit != 'true' - run: node packages/core/scripts/copy-wasm-commands.mjs - - uses: actions/upload-artifact@v4 - with: - name: wasm-commands - path: | - packages/core/commands - registry/native/target/wasm32-wasip1/release/commands - retention-days: 1 - if-no-files-found: error - - # Cheap job (typecheck / boundary checks / publish tests, no heavy cargo - # compile) — runs on GitHub-hosted runners, not the self-hosted pool, which is - # reserved for the cache-heavy rust/registry jobs. - js-checks: + static: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -77,60 +17,6 @@ jobs: node-version: 22 cache: pnpm - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - with: - workspaces: . -> target - key: js-checks - - run: npx --yes zx@8 scripts/ci.mjs js-checks - - run: node --test scripts/verify-fixed-versions.test.mjs - - run: pnpm --filter=publish exec tsx src/ci/verify-fixed-versions.ts - - rust-lint: - runs-on: [self-hosted, agentos-builder] - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt, clippy - - run: pnpm install --frozen-lockfile --filter "@secure-exec/build-tools..." - - run: npx --yes zx@8 scripts/ci.mjs rust-lint - - rust-test: - runs-on: [self-hosted, agentos-builder] - needs: wasm-commands - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - uses: dtolnay/rust-toolchain@stable - - uses: taiki-e/install-action@v2 - with: - tool: nextest - - run: pnpm install --frozen-lockfile --filter "@secure-exec/core..." --filter "@secure-exec/build-tools..." - - uses: actions/download-artifact@v4 - with: - name: wasm-commands - - run: npx --yes zx@8 scripts/ci.mjs rust-test - env: - NEXTEST_PROFILE: ci - - js-test: - runs-on: [self-hosted, agentos-builder] - needs: wasm-commands - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - uses: dtolnay/rust-toolchain@stable - - uses: actions/download-artifact@v4 - with: - name: wasm-commands - - run: npx --yes zx@8 scripts/ci.mjs js-test + - run: pnpm install --frozen-lockfile + - run: pnpm check-types + - run: cargo check --workspace diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 86b55fbc3..bd019fd9d 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -4,450 +4,12 @@ on: workflow_dispatch: inputs: version: - description: "Version to release. Leave empty for preview publish on the dispatched branch." - required: false - type: string - latest: - description: "Tag as @latest for release publishes" required: true - type: boolean - default: true - -concurrency: - group: publish-${{ github.ref }} - cancel-in-progress: false - -env: - R2_BUCKET: rivet-releases - R2_ENDPOINT: https://2a94c6a0ced8d35ea63cddc86c2681e7.r2.cloudflarestorage.com - SIDECAR_PLATFORMS: "linux-x64-gnu linux-arm64-gnu darwin-x64 darwin-arm64" + type: string jobs: - context: - name: "Context" - runs-on: ubuntu-latest - outputs: - trigger: ${{ steps.ctx.outputs.trigger }} - version: ${{ steps.ctx.outputs.version }} - npm_tag: ${{ steps.ctx.outputs.npm_tag }} - sha: ${{ steps.ctx.outputs.sha }} - latest: ${{ steps.ctx.outputs.latest }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - run: corepack enable - - uses: actions/setup-node@v4 - with: - node-version: "22" - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - - name: Install publish scripts - run: pnpm install --frozen-lockfile --filter=publish - - id: ctx - name: Resolve publish context - run: pnpm --filter=publish exec tsx src/ci/bin.ts context-output - - build-sidecar: - needs: [context] - name: "Build sidecar (${{ matrix.platform }})" - strategy: - fail-fast: false - # The target set is dictated by the embedded V8 (rusty_v8): the build links - # a prebuilt `librusty_v8` static lib, and rusty_v8 publishes prebuilts for - # EXACTLY these four triples (linux-gnu + darwin, x64/arm64). musl has no - # prebuilt (would force a 30+ min V8 source build). Keep this list in - # lockstep with the rusty_v8 release assets when bumping the v8 crate. - matrix: - include: - - platform: linux-x64-gnu - runner: [self-hosted, agentos-builder] - target: x86_64-unknown-linux-gnu - binary: secure-exec-sidecar - - platform: linux-arm64-gnu - runner: ubuntu-22.04-arm - target: aarch64-unknown-linux-gnu - binary: secure-exec-sidecar - runs-on: ${{ matrix.runner }} - steps: - - uses: actions/checkout@v4 - - run: corepack enable - shell: bash - - uses: actions/setup-node@v4 - with: - node-version: "22" - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - - uses: dtolnay/rust-toolchain@stable - - name: Add Rust target to the pinned toolchain - shell: bash - run: | - set -euo pipefail - # The repo pins a toolchain via rust-toolchain.toml; cross targets - # must be added to *that* toolchain (not just `stable`), or cargo - # fails with "can't find crate for `core`" for the cross target. - channel=$(awk -F'"' '/channel/ {print $2; exit}' rust-toolchain.toml) - echo "Pinned toolchain channel: ${channel}" - rustup toolchain install "${channel}" --profile minimal - rustup target add --toolchain "${channel}" "${{ matrix.target }}" - - uses: Swatinem/rust-cache@v2 - with: - workspaces: . -> target - key: ${{ matrix.target }}-${{ needs.context.outputs.trigger }} - - uses: actions/cache@v4 - with: - path: ~/.cargo/.rusty_v8 - key: ${{ runner.os }}-${{ matrix.target }}-rusty-v8-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.target }}-rusty-v8- - # The v8-runtime build script generates the V8 bridge assets from - # packages/build-tools/node_modules, so the workspace must be installed - # before cargo build. Exclude the `website` package: it is a leaf nothing - # depends on, and pnpm 10.x intermittently loses a symlink-ordering race - # creating website/node_modules (ENOENT before linking pixelmatch). - - name: Install workspace dependencies - shell: bash - run: pnpm install --frozen-lockfile --filter='!@secure-exec/website' - - name: Build sidecar binary - id: build - shell: bash - env: - MATRIX_TARGET: ${{ matrix.target }} - MATRIX_PLATFORM: ${{ matrix.platform }} - MATRIX_BINARY: ${{ matrix.binary }} - TRIGGER: ${{ needs.context.outputs.trigger }} - run: | - set -euo pipefail - - out="target/sidecar-artifacts/${MATRIX_PLATFORM}" - mkdir -p "$out" - if [ "$TRIGGER" = "release" ]; then - cargo build --release -p secure-exec-sidecar --target "$MATRIX_TARGET" - profile="release" - else - cargo build -p secure-exec-sidecar --target "$MATRIX_TARGET" - profile="debug" - fi - cp "target/${MATRIX_TARGET}/${profile}/${MATRIX_BINARY}" "$out/${MATRIX_BINARY}" - echo "dir=$out" >> "$GITHUB_OUTPUT" - - uses: actions/upload-artifact@v4 - with: - name: sidecar-${{ matrix.platform }} - path: ${{ steps.build.outputs.dir }} - if-no-files-found: error - - # darwin is cross-compiled via osxcross in a Linux container (rivet's approach) - # rather than on macOS runners — those queue for scarce macos-13/14 capacity and - # stall the whole publish. The osxcross base image carries the macOS SDK + Node - # + pnpm; we build on plain ubuntu with `docker build`. No Depot needed. - build-sidecar-darwin: - needs: [context] - name: "Build sidecar (${{ matrix.platform }})" - strategy: - fail-fast: false - matrix: - include: - - platform: darwin-x64 - target: x86_64-apple-darwin - clang: x86_64-apple-darwin20.4 - - platform: darwin-arm64 - target: aarch64-apple-darwin - clang: aarch64-apple-darwin20.4 - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - - name: Log in to ghcr.io (pull the osxcross base image) - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - name: Cross-compile via osxcross - run: | - set -euo pipefail - DOCKER_BUILDKIT=1 docker build \ - -f docker/build/darwin.Dockerfile \ - --build-arg TARGET=${{ matrix.target }} \ - --build-arg CLANG=${{ matrix.clang }} \ - --build-arg TRIGGER=${{ needs.context.outputs.trigger }} \ - -t sidecar-${{ matrix.platform }} . - out="target/sidecar-artifacts/${{ matrix.platform }}" - mkdir -p "$out" - cid=$(docker create sidecar-${{ matrix.platform }}) - docker cp "$cid:/artifacts/secure-exec-sidecar" "$out/secure-exec-sidecar" - docker rm "$cid" - test -f "$out/secure-exec-sidecar" - - uses: actions/upload-artifact@v4 - with: - name: sidecar-${{ matrix.platform }} - path: target/sidecar-artifacts/${{ matrix.platform }} - if-no-files-found: error - - publish-npm: - needs: [context, build-sidecar, build-sidecar-darwin] - name: "Publish npm" - if: ${{ !cancelled() && needs.build-sidecar.result == 'success' && needs.build-sidecar-darwin.result == 'success' }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: corepack enable - - uses: actions/setup-node@v4 - with: - node-version: "22" - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - registry-url: https://registry.npmjs.org - - uses: dtolnay/rust-toolchain@stable - - name: Install registry-native Rust toolchain - shell: bash - run: | - set -euo pipefail - channel=$(awk -F'"' '/channel/ {print $2; exit}' registry/native/rust-toolchain.toml) - echo "Registry-native toolchain channel: ${channel}" - rustup toolchain install "${channel}" --profile minimal --component rust-src --target wasm32-wasip1 - - uses: Swatinem/rust-cache@v2 - with: - workspaces: | - registry/native -> registry/native/target - # Install the full workspace except the `website` package. website is a - # leaf (nothing depends on it, and it is not published here), and pnpm 10.x - # intermittently loses a symlink-ordering race creating website/node_modules - # (ENOENT before linking pixelmatch). Excluding it deterministically avoids - # the flake. `--frozen-lockfile` still validates the full lockfile. - - name: Install workspace dependencies - shell: bash - run: pnpm install --frozen-lockfile --filter='!@secure-exec/website' - - uses: actions/download-artifact@v4 - with: - pattern: sidecar-* - path: artifacts - - name: Place sidecar binaries into platform packages - run: | - set -euo pipefail - for p in $SIDECAR_PLATFORMS; do - binname="secure-exec-sidecar" - bin="artifacts/sidecar-${p}/${binname}" - dest="packages/sidecar/npm/${p}" - if [ ! -f "$bin" ]; then - echo "::error::missing secure-exec-sidecar binary artifact for ${p}" - exit 1 - fi - if [ ! -d "$dest" ]; then - echo "::error::missing platform package dir $dest" - exit 1 - fi - cp "$bin" "${dest}/${binname}" - chmod +x "${dest}/${binname}" - echo "Placed binary for ${p}" - done - - name: Build and vendor core WASM commands - run: | - set -euo pipefail - make -C registry/native wasm - pnpm --dir packages/core run copy-commands - test -f packages/core/commands/sh - - name: Bump package versions for build - env: - # Previews publish the registry packages under the branch dist-tag too. - PUBLISH_INCLUDE_REGISTRY_PACKAGES: ${{ needs.context.outputs.trigger != 'release' && '1' || '' }} - run: | - pnpm --filter=publish exec tsx src/ci/bin.ts bump-versions \ - --version ${{ needs.context.outputs.version }} \ - --version-only - - name: Build TypeScript packages - run: | - npx turbo build \ - --filter='!./examples/*' \ - --filter='!@secure-exec/website' - - name: Finalize package versions for publish - env: - PUBLISH_INCLUDE_REGISTRY_PACKAGES: ${{ needs.context.outputs.trigger != 'release' && '1' || '' }} - run: | - pnpm --filter=publish exec tsx src/ci/bin.ts bump-versions \ - --version ${{ needs.context.outputs.version }} - - name: Publish npm packages - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - PUBLISH_INCLUDE_REGISTRY_PACKAGES: ${{ needs.context.outputs.trigger != 'release' && '1' || '' }} - run: | - pnpm --filter=publish exec tsx src/ci/bin.ts publish-npm \ - --tag ${{ needs.context.outputs.npm_tag }} \ - --parallel 16 \ - --retries 3 \ - ${{ needs.context.outputs.trigger == 'release' && '--release-mode' || '' }} - - release-assets: - needs: [context, build-sidecar, build-sidecar-darwin] - name: "Release assets" - if: ${{ !cancelled() && needs.build-sidecar.result == 'success' && needs.build-sidecar-darwin.result == 'success' && needs.context.outputs.trigger == 'release' }} - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - run: corepack enable - - uses: actions/setup-node@v4 - with: - node-version: "22" - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - - run: pnpm install --frozen-lockfile --filter=publish - - uses: actions/download-artifact@v4 - with: - pattern: sidecar-* - path: artifacts - - name: Stage release assets - env: - VERSION: ${{ needs.context.outputs.version }} - run: | - set -euo pipefail - declare -A PLATFORM_TARGET=( - [linux-x64-gnu]=x86_64-unknown-linux-gnu - [linux-arm64-gnu]=aarch64-unknown-linux-gnu - [darwin-x64]=x86_64-apple-darwin - [darwin-arm64]=aarch64-apple-darwin - ) - mkdir -p release-assets - for p in $SIDECAR_PLATFORMS; do - binname="secure-exec-sidecar" - suffix="" - bin="artifacts/sidecar-${p}/${binname}" - if [ -f "$bin" ]; then - target="${PLATFORM_TARGET[$p]}" - cp "$bin" "release-assets/secure-exec-sidecar-${target}${suffix}" - else - echo "::warning::missing secure-exec-sidecar binary for ${p}" - fi - done - for f in \ - pyodide.asm.wasm \ - pyodide.asm.js \ - python_stdlib.zip \ - numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl \ - pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl; do - cp "crates/execution/assets/pyodide/${f}" "release-assets/${f}" - done - - name: Create GitHub release and upload assets - env: - GH_TOKEN: ${{ github.token }} - VERSION: ${{ needs.context.outputs.version }} - NPM_TAG: ${{ needs.context.outputs.npm_tag }} - run: | - set -euo pipefail - if ! gh release view "v${VERSION}" >/dev/null 2>&1; then - PRERELEASE="" - if [ "${NPM_TAG}" = "rc" ]; then PRERELEASE="--prerelease"; fi - gh release create "v${VERSION}" --title "v${VERSION}" --generate-notes $PRERELEASE - fi - gh release upload "v${VERSION}" release-assets/* --clobber - - name: Keep Agent OS Pyodide release assets reachable - env: - GH_TOKEN: ${{ secrets.AGENTOS_RELEASES_TOKEN }} - VERSION: ${{ needs.context.outputs.version }} - NPM_TAG: ${{ needs.context.outputs.npm_tag }} - run: | - set -euo pipefail - if [ -z "${GH_TOKEN:-}" ]; then - echo "AGENTOS_RELEASES_TOKEN not configured; skipping Agent OS compatibility upload." - exit 0 - fi - if ! gh release view "v${VERSION}" --repo rivet-dev/agentos >/dev/null 2>&1; then - PRERELEASE="" - if [ "${NPM_TAG}" = "rc" ]; then PRERELEASE="--prerelease"; fi - gh release create "v${VERSION}" --repo rivet-dev/agentos --title "v${VERSION}" --generate-notes $PRERELEASE - fi - gh release upload "v${VERSION}" \ - release-assets/pyodide.asm.wasm \ - release-assets/pyodide.asm.js \ - release-assets/python_stdlib.zip \ - release-assets/numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl \ - release-assets/pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl \ - --repo rivet-dev/agentos \ - --clobber - - name: Upload sidecar binaries to R2 - env: - R2_RELEASES_ACCESS_KEY_ID: ${{ secrets.R2_RELEASES_ACCESS_KEY_ID }} - R2_RELEASES_SECRET_ACCESS_KEY: ${{ secrets.R2_RELEASES_SECRET_ACCESS_KEY }} - VERSION: ${{ needs.context.outputs.version }} - SHA: ${{ needs.context.outputs.sha }} - LATEST: ${{ needs.context.outputs.latest }} - run: | - set -uo pipefail - if [ -z "${R2_RELEASES_ACCESS_KEY_ID:-}" ] || [ -z "${R2_RELEASES_SECRET_ACCESS_KEY:-}" ]; then - echo "R2 credentials not configured; skipping R2 upload." - exit 0 - fi - set -e - pnpm --filter=publish exec tsx src/ci/bin.ts upload-r2 \ - --source "$GITHUB_WORKSPACE/release-assets" --sha "$SHA" - pnpm --filter=publish exec tsx src/ci/bin.ts copy-r2 \ - --sha "$SHA" --version "$VERSION" --latest "$LATEST" - - publish-crates: - needs: [context, build-sidecar, build-sidecar-darwin, release-assets] - name: "Publish crates.io" - # Release-only: on previews the crates publish is a dry-run that still does a - # full compile/package, and any error there reddened the WHOLE run even though - # the npm deliverable published fine (FALLING_OUT.md §4b). The 4 build-sidecar - # legs already compile every crate, so the preview dry-run added only noise. - if: ${{ !cancelled() && needs.build-sidecar.result == 'success' && needs.release-assets.result == 'success' && needs.context.outputs.trigger == 'release' }} + static: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: corepack enable - - uses: actions/setup-node@v4 - with: - node-version: "22" - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - with: - workspaces: . -> target - - uses: actions/cache@v4 - with: - path: ~/.cargo/.rusty_v8 - key: ${{ runner.os }}-x86_64-unknown-linux-gnu-rusty-v8-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-x86_64-unknown-linux-gnu-rusty-v8- - # Install the full workspace except the `website` package. website is a - # leaf (nothing depends on it, and it is not published here), and pnpm 10.x - # intermittently loses a symlink-ordering race creating website/node_modules - # (ENOENT before linking pixelmatch). Excluding it deterministically avoids - # the flake. `--frozen-lockfile` still validates the full lockfile. - - name: Install workspace dependencies - shell: bash - run: pnpm install --frozen-lockfile --filter='!@secure-exec/website' - - name: Bump Cargo versions - run: | - pnpm --filter=publish exec tsx src/ci/bin.ts bump-versions \ - --version ${{ needs.context.outputs.version }} \ - --version-only - - name: Stage vendored V8 bridge bundles and base filesystem - run: | - set -euo pipefail - for crate in execution v8-runtime; do - out="crates/${crate}/assets/generated" - mkdir -p "$out" - node packages/build-tools/scripts/build-v8-bridge.mjs --out-dir "$out" - done - git add -f crates/execution/assets/generated crates/v8-runtime/assets/generated - mkdir -p crates/kernel/assets crates/sidecar/assets - # The single committed base filesystem lives in the vfs crate (the vfs - # crate embeds it via include_str!); the old packages/core/fixtures/ - # path no longer exists, which broke this crates.io publish job. - cp crates/vfs/assets/base-filesystem.json crates/kernel/assets/base-filesystem.json - cp crates/vfs/assets/base-filesystem.json crates/sidecar/assets/base-filesystem.json - - name: Dry-run crate publish - if: ${{ needs.context.outputs.trigger != 'release' }} - run: | - pnpm --filter=publish exec tsx src/ci/bin.ts publish-crates \ - --version ${{ needs.context.outputs.version }} \ - --dry-run \ - --allow-dirty - - name: Publish crates - if: ${{ needs.context.outputs.trigger == 'release' }} - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - run: | - pnpm --filter=publish exec tsx src/ci/bin.ts publish-crates \ - --version ${{ needs.context.outputs.version }} \ - --allow-dirty + - run: echo "secure-exec publishes generated compatibility shims only." diff --git a/.github/workflows/sync-from-agentos.yml b/.github/workflows/sync-from-agentos.yml new file mode 100644 index 000000000..be0e6adf0 --- /dev/null +++ b/.github/workflows/sync-from-agentos.yml @@ -0,0 +1,10 @@ +name: sync-from-agentos + +on: + workflow_dispatch: + +jobs: + static: + runs-on: ubuntu-latest + steps: + - run: echo "Regenerate this mirror from AgentOS with scripts/generate-secure-exec-mirror.mjs." diff --git a/CLAUDE.md b/CLAUDE.md index 237d5efed..4be34ceb2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,185 +1,3 @@ # secure-exec -secure-exec is the fully virtualized runtime extracted from Agent OS. The kernel provides a POSIX-like VM with a virtual filesystem, process table, socket table, pipes, PTYs, permission policy, and managed language runtimes. - -## Trust Model - -secure-exec is a sandbox: it runs untrusted code safely for a trusted caller. Decide which side of this boundary something is on before judging whether it is a security bug. Three components: - -- **Client** (trusted, *except for anything it submits for execution*). The party that speaks the sidecar wire protocol. The client process and every value it sends are trusted: `CreateVmConfig`, mount descriptors and their plugin configs (host_dir paths, S3 endpoints/credentials, Google Drive, sandbox-agent), the permission policy, network allowlist, resource limits, env, and DNS overrides. Configuration is **not** an attack surface. The one thing from the client that is *not* trusted is the code/payload it asks to run, because that runs in the executor. -- **Sidecar** (trusted; the TCB and the enforcement point). Brokers client requests and owns the kernel, VFS, mount/plugin registry, socket table, and permission policy. It is responsible for enforcing the boundary against the executor. -- **Executor** — V8 isolates or WASM (untrusted; the adversary). Runs guest JS/Python/WASM plus any third-party/npm/agent-generated code. Assume everything here is actively hostile. How code reached the executor never makes it trusted. - -**The security boundary is sidecar ↔ executor.** The runtime must stop guest code in the executor from: escaping the kernel boundary (real host fs/network/process/memory), bypassing the *applied* permission policy/allowlist/limits, exhausting host resources beyond configured bounds, or reading another VM's state. - -**A defect that requires the client to supply a malicious config/endpoint/credential/policy is NOT a sandbox vulnerability** — the client is configuring its own VM and already controls the host. Treat such hardening as defense-in-depth, not as an escape, and do not add validation that only guards trusted client-provided configuration. - -Two corollaries that are easy to get wrong: - -- *Trusted policy, untrusted subject.* The permission policy and limits are trusted input, but the guest executor is the subject they bind. "Guest bypasses an applied permission / egress rule / resource cap" is in-scope and serious. Trusted = who sets the rule; untrusted = who is bound by it. -- *Trusted mount, untrusted traffic.* A host-backed mount (host_dir, s3, …) comes from trusted config, so its existence/target/credentials are not attack surface, but the guest drives I/O through it, so confining those guest operations to the mount root (symlink / `..` / TOCTOU / path-aliasing escapes) is in-scope. - -**Transport scope.** The wire protocol is same-version lockstep and single-client over stdio (one trusted client per sidecar process). There is no second, mutually-distrusting client, so wire-level authn/authz-between-clients and VM-to-VM access via forged connection ids are out of scope until a multi-client transport exists. - -## Runtime Invariants - -- All guest code must execute inside the kernel isolation boundary with zero host escapes. -- No runtime may spawn unsandboxed host processes, touch real host filesystems, open real host network sockets, or call real Node.js builtins for guest work. -- Guest JavaScript runs in V8 isolates through `crates/v8-runtime/`; never use `Command::new("node")` for guest execution. -- Every guest syscall goes through kernel-owned VFS, process, socket, pipe, PTY, permission, and DNS paths. -- **Behave like native Linux (load-bearing).** The VM must look and behave like a normal Linux machine to the guest: real subprocesses, sockets, PTYs, pipes, devices (`/dev/null`, …), a normal stdin/stdout lifecycle, and a complete-enough node/libc surface. The Workers-style in-process isolation is *how* we deliver that, never an excuse for the guest to see a degraded environment. When a tool, agent CLI, registry binary, or ported program misbehaves, the default diagnosis is "the runtime is not yet emulating Linux faithfully" and the fix lives **here** — a host bridge, a libc/std patch, a crate stub, a node-API shim, a device emulation — not a workaround in the caller (env flags, binary patches, node-API fakes in adapters, `#[cfg(target_os = "wasi")]` feature gates). Guest-side workarounds are suspected runtime bugs to drive down; only genuine third-party packaging quirks and intentional isolation properties (bounded memory/CPU, default-deny egress) are legitimate exceptions, and those get documented with the reason. -- **Build native programs with the custom libc + Rust toolchain, not bare wasi.** Programs in `registry/native` compile as normal Linux programs against the patched std sysroot + host bridges (`wasi-spawn`, `wasi-http`, `wasi-pty`), via `make -C registry/native wasm`. Never `cargo build --target wasm32-wasip1` raw and never gate out subprocess/socket/git/shell features because "wasi can't" — supply the capability through a bridge/stub/patch. The only allowed platform concession is single-threaded execution (no OS threads). - -## Limits, Bounds & Observability - -Every bound that protects a shared resource — memory/heap, CPU/wall-clock, fd/process/socket/pipe/pty counts, filesystem bytes/inodes, queue/buffer capacities, payload/frame sizes, timeouts, registration counts — MUST satisfy all of the following. A new `MAX_*`/`*_LIMIT`/`*_CAPACITY`/timeout/cap added without them is incomplete. - -- **Bounded by default.** Never `None`/`0`/unbounded (matches the Workers-style memory/CPU rule). Operators may raise a cap; they don't get an unbounded default. If a `0`/`None` genuinely means "engine default" (e.g. Pyodide old-space), say so in the inventory rationale. -- **Config-wired + audited.** Operator-tunable bounds flow through `VmLimits` → `vm-config` (`limits_struct!`, Rust is the single source; TS mirrors via ts-rs). Every limit-shaped constant is classified in `crates/sidecar/tests/fixtures/limits-inventory.json` as `policy` (must name its `wired` config path) / `policy-deferred` / `invariant`, enforced by `crates/sidecar/tests/limits_audit.rs`. Never let a hardcoded operator bound accumulate uncatalogued. -- **Registered for observability.** Register the bound with the central limit tracker (`secure_exec_bridge::queue_tracker`, generalizing to a limit registry) so usage/high-water are inspectable and it emits a **structured, edge-triggered warning as it approaches** (default ≥80% fill, re-arm <50%) naming the limit, observed/cap, fill%, and the `wired` config path. Note: the sidecar tracing level must be at least `WARN` for these to surface (`ERROR`-only swallows them). -- **Clear, typed error on breach.** Fail with a typed error that names the limit and the observed-vs-cap value **with units**, plus how to raise it: `" exceeded: > (raise via limits.)"`. Map consistently — errno for kernel limits (but attach the limit name; no bare/opaque `EAGAIN`), `ExecutionAbortReason` for runtime kills, `SidecarError`/codec errors for config/protocol. No generic "invalid"/silent failure that hides which limit fired. -- **No catastrophic reaction to transient fullness.** A full bounded queue/buffer applies **backpressure** (block the producer until the consumer drains) or returns the named error — never silently drop, silently evict, destroy the session, or crash the process. Raising a capacity is not a fix by itself; the warning + typed error must exist first. See PR #123 (event channel + stdout frame queue) for the reference pattern; audit every other channel/`VecDeque`/buffer against it. - -## Performance - -- **No expensive objects per-call.** Build once, reuse via a pool/persistent worker. Never construct per-operation: Tokio runtime, OS thread, V8 isolate/snapshot, DNS resolver, HTTP client, connection pool. Construct-then-teardown every call IS the bug. -- **No serialize→deserialize in-process.** Pass the typed struct directly; wire encoding is for the wire only. Don't encode a frame to bytes only to re-parse it into a command. -- **No whole-buffer copies per I/O.** Use chunked `Vec` + `extend_from_slice`, not byte-by-byte fills; move/`Arc`/slice payloads — never clone a record that carries its full buffer on each read/write. -- **Zero host-disk writes on VM start (mount, don't extract).** Mounting read-only packaged content (the `agentos_packages` tar projection, or any archive/content mount) MUST NOT extract the archive to host disk or write physical symlinks at VM/session start. Back content by byte-range reads over the source archive (mmap/seek into the uncompressed tar, digest-keyed and shared across VMs), and serve derived symlinks (the `/opt/agentos/bin` farm, `/current`) as **in-memory synthetic mounts**, never on-disk nodes. Extraction/staging is redundant work + state (full unpack, ~32k inodes, symlink farm, temp cleanup, double on-disk copy) for bytes the archive already holds at a known offset — reintroducing it is the bug. The only writes VM start may incur are cheap in-RAM overlay mountpoint dirs materialized by the mount table; host-disk materialization is zero. Any code that "helpfully" extracts must be reverted; the tar reader and projection carry doc comments saying why. -- **Content ops MUST follow symlinks ACROSS mounts (the projection is composed of granular leaf mounts).** `/opt/agentos` is built from many leaf mounts — a tar mount per `pkgs//`, and a single-symlink leaf mount per `pkgs//current` and per `bin/`. So `/current` and `` are symlinks whose targets live in a *different* mount. `MountTable::resolve_index` is purely lexical, so every content op (`read_file`/`stat`/`pread`) and `exec` MUST resolve the path through `realpath` (cross-mount symlink walk) before routing — reading `/opt/agentos/pkgs//current/agentos-package.json` has to follow `current → ` into the tar mount. Two invariants make this work and must not regress: (a) content ops route via `resolve_content_index` (realpath-then-route), not raw `resolve_index`; (b) `MountTable::realpath`'s single-mount delegation falls back to the component walk on **ENOENT as well as ELOOP** — a single-symlink leaf mount returns ENOENT for any descendant path (its root IS the symlink), and only the walk can follow it. This is why runtime agent/package resolution can read the live FS by name (`/opt/agentos/pkgs//current/...`) even though `` was installed as separate leaf mounts, and why dynamically-linked packages resolve without re-reading the client's `packages` list. -- **No per-call allocs/locks/clones** on the sync hot path. -- **Avoid polling**, prefer readiness/event-driven. But a read-probe can be load-bearing for protocol correctness — measure before removing one, and keep its semantic test. -- **No baseline, no merge.** Capture native + unoptimized numbers BEFORE touching code, gate every change on a measured before/after delta, and keep it measure-gated. -- **Revert no-wins.** A change with a flat or negative delta is a liability, not a win. -- **Perf must not regress correctness.** Respect existing caps/bounds and land the regression test in the same change as the optimization. - -## Benchmarks - -- **Purpose:** `packages/benchmarks` owns the differential matrix for the runtime surface. It compares four lanes: native (host Rust `crates/native-baseline`), node (host Node.js), vm-js (guest V8 Node emulation), and vm-wasm (`native-baseline` compiled to `wasm32-wasip1` and run in the VM). `guest/node` is JS-emulation tax, `wasm/native` is WASM-runtime tax, and `node/native` is Node's own cost. -- **Memory columns:** matrix rows carry `mem`/`memTax` columns, with guest-backed lanes measured above the prewarmed-sidecar baseline. -- **Ecosystem family:** `BENCH_FAMILIES=ecosystem` is command-pair only: `hostCmd` (host binary) vs `vmCmd` (VM WASM command), with `tax.command = vmCmd/hostCmd`. -- **Permissions family:** `BENCH_FAMILIES=permissions` is a guest policy-overhead A/B over hot fs+net ops, reporting `policyTax = policy_p50 / allow_p50`. -- **Layout:** matrix families and the lane engine live in `packages/benchmarks/src`; Rust op implementations live in `crates/native-baseline` and build for both host and wasm. Run one family with `BENCH_FAMILIES=fs pnpm --dir packages/benchmarks bench:matrix` or through `bash packages/benchmarks/run-benchmarks.sh`; results land in `packages/benchmarks/results/`. -- **Verify work:** every op must verify its payload or side effect, so a fast-but-broken path fails instead of passing. -- **Clock discipline:** guest clocks are 1ms-quantized by default for security. Bench VMs opt in to `jsRuntime.highResolutionTime`, or the op must amplify by call count. -- **Unsupported cells:** unsupported lane/op cells are explicit and never silently dropped. -- **Baselines:** regenerate baselines only on a canonical environment, with hardware and dependency metadata recorded. -- **Bench gate:** `packages/benchmarks/results/baseline-local.json` is the canonical-machine baseline; `baseline-ci.json` is GitHub-runner-specific and bootstrapped from the nightly artifact before PR gates enforce it. -- **Merge rule:** a perf fix whose row does not move gets reverted, matching the Performance section. -- **Keep them current:** the benches are a maintained surface, not a one-off audit. New runtime surface (a syscall, a polyfill module, an executor capability, a registry command tier) needs a matrix op or focused lane in the same change or a filed follow-up; perf-relevant changes to existing surface must re-run the affected rows and update coverage when the shape changes (new lanes, renamed ops). If a bench stops compiling or a lane can no longer run, fix or explicitly skip it with a reason — never delete coverage silently. -- **Agent OS boundary:** agent-os keeps product-surface benches only (session tax, ACP) and consumes this framework. - -## Testing - -- **Tests must run in parallel. Never fall back to `--test-threads=1`.** Serializing the whole suite to dodge a race is banned — it hides real shared-state bugs and roughly triples wall-clock. If tests interfere, fix the interference (see the categories below) or isolate the offender; do not pin the runner to one thread. Per-test process isolation via `cargo nextest` is the sanctioned way to neutralize process-global state while keeping parallelism (doctests run separately via `cargo test --doc`). -- **No process-global state coupling between tests.** A test must not depend on or mutate shared process state that a concurrent sibling sees: `std::env::set_var`/`remove_var` (an `EnvVarGuard` that mutates real env is a smell — thread config through explicit args/builders instead), `static`/`OnceLock`/`lazy_static` caches, warm-isolate/worker pools, or global counters. If a test genuinely needs a process-global (env, a shared cache's warm state), it belongs in a dedicated serial lane, not the default parallel suite. -- **Timing-sensitive tests are disabled by default.** Any test whose pass/fail depends on wall-clock — `sleep`-then-assert-elapsed, `Duration`/`Instant` comparisons in assertions, "watchdog/timeout fired within N ms" — flakes under the CPU contention of a parallel run and MUST be gated off by default (`#[ignore]` or an env/feature gate — in this repo the env gate is `SECURE_EXEC_RUN_TIMING_TESTS`, exercised only in the quiet serial nightly lane) and run only there. A test that merely *measures* timing never stays in the default suite. -- **A safeguard-firing test stays in the default suite ONLY IF the safeguard fires fast — the deciding factor is duration, not what the test proves.** A configured limit actually firing (CPU-time → runaway killed, fuel → exit 124, fd/socket/heap cap → denied) is a keeper **only when the test configures a SHORT bound** (a small CPU-time/fuel/timeout — sub-second where the mechanism allows) so the runaway dies almost immediately. If the test's runtime is instead dominated by *waiting out* a multi-second window it does NOT keep — most notably the **default ~30s V8 CPU-time watchdog** driving an infinite-loop guest module, but equally a network-denied op that hangs until a `from_secs(N)` collect/poll timeout, or a wasm fuel/timeout enforced only by a slow poll path. Those are timeout-dependent: gate them off by default (early-return on `SECURE_EXEC_RUN_TIMING_TESTS` at the call site, or `#[ignore]`) and run them only in the nightly lane. **Prefer** shrinking the configured window so the safeguard fires fast AND the coverage stays on every PR; gate only when a short window genuinely isn't achievable. This stacks with the resource-saturation `#[ignore]` rule below. -- **Auto-skip expensive resource-saturation tests.** A test that proves the *absence* of a bound by actually saturating a resource — a JS/WASM infinite loop pinning a core for the watchdog window, a heap/alloc bomb, a fork bomb, anything that aborts the process — must be `#[ignore = "expensive: saturation; run with --ignored"]` (vitest: `it.skip`/env gate). These pin cores or crash the runner. Still test the *safeguards* (a configured limit/watchdog/quota actually firing) — those are bounded, fast, and are the regression guard that the protection works; keep them in the default suite. -- **Unique ports and temp dirs per test.** Bind ephemeral ports (`:0`), never a fixed port; use a unique temp dir per test, never a fixed shared path. Fixed ports/paths collide the moment two tests run concurrently. -- **Tests never build their dependencies — they error if a prerequisite is missing.** A test harness must not shell out to `cargo build` (or any build) on demand: that build runs inside the test's own timeout and, under parallelism, spawns N concurrent builds — a deterministic-timeout footgun. If the sidecar binary (or any built artifact) is absent or stale, the harness fails fast with a clear message ("build `X` first: `cargo build -p ...`"), it does not build it. CI builds artifacts in an explicit earlier step and pins them (e.g. `SECURE_EXEC_SIDECAR_BIN`); local dev builds first, then runs tests. -- **Never delete coverage silently.** A skip/ignore/quarantine carries a one-line reason and, ideally, a follow-up. Rule of thumb: a test that ends only when a watchdog whose *absence* it documents fires → `#[ignore]`; a test that ends because a *safeguard* fires → keep it running. -- **CI test-phase wall = the single slowest test, then the compile.** nextest runs every `#[test]` in its own process in parallel, so the wall ≈ the *longest individual test*, NOT the sum. Optimize the tallest pole only — split it, gate it if it's timeout/watchdog-bound, or shrink its configured limit; splitting anything *below* the current critical path is wasted churn that just lights idle cores. Once the slowest surviving test drops under the crate's compile time, the **build is the floor** and more test surgery buys nothing. (This repo: warm rust-test is ~2m build + the slowest test; measure per-test durations before optimizing.) -- **Split a collapsed `*_suite` test for nextest ONLY when its cases are *independently* slow — the collapse guards two things, and splitting fixes one but breaks the other.** Integration suites batch sub-cases into one `#[test]` (`python_suite`, `wasm_suite`, `kill_cleanup_suite`) to dodge a shared-process V8/Pyodide teardown/init crash. nextest's process-per-test removes that crash, so cases *can* be split to parallelize — pattern: a `mod _split` whose `macro_rules!` emits one gated `#[test]` per case (`if std::env::var_os("NEXTEST").is_none() { return; } super::();`), plus an early `return` under `NEXTEST` in the collapsed suite so `cargo test` still owns it locally; cases with an in-process ordering/warm-state dependency stay grouped in one sequential `#[test]` named `*_suite` (to inherit the `nextest.toml` slow-timeout override). **But the collapse ALSO amortizes warm process-global state, which splitting defeats:** a case that's cheap only because prior cases warmed the shared Pyodide/V8 (cold Pyodide init, a cold `import micropip`, an infinite-loop module's prewarm running into the ~30s CPU watchdog) becomes *slower* split — each fresh process pays the cold cost — and grouping the bare offenders can reintroduce the SIGSEGV the collapse existed to prevent. So split only independently-expensive real-work cases; leave warm-amortized suites collapsed with a comment saying why, and always confirm the split binary's measured wall actually dropped before keeping the change. - -## Project Boundaries - -- Keep the secure-exec runtime Agent OS-agnostic: no ACP, sessions, `agentos-protocol`, `agentos-client`, or `agentos-sidecar` dependencies in runtime code. -- Packaged agent definitions/adapters live in `registry/agent/*`; generic VM software lives in `registry/software/*`. -- `crates/bridge/` is the browser/native portability seam. Shared contracts belong there. -- `crates/vfs/` is generic filesystem infrastructure: POSIX-style in-memory/overlay/mount/root engines plus generic chunked/object engines and in-memory stores. It must stay free of secure-exec sidecar, bridge, S3, SQLite, and host-disk coupling. -- `crates/secure-exec-vfs/` contains concrete secure-exec filesystem backends: S3 adapters, host-disk SQLite/file stores, and bridge/callback-backed metadata stores. Policy decisions, config validation, and mount descriptor parsing stay in sidecar plugins. -- `crates/execution/` is the native execution implementation and must not become the browser portability layer. -- `crates/sidecar/` builds the `secure-exec-sidecar` crate and binary. Extension APIs must stay transport-agnostic. -- The protocol has no backwards compatibility. The sidecar and its clients run in same-version lockstep, so never add protocol or config versioning, runtime negotiation, fallbacks, or converters. Wire types and configs such as `CreateVmConfig` carry no `version` field beyond the single same-version handshake. Change the protocol freely and update all sides together. -- Wire/client parity: every capability implemented in the wire protocol must be reachable from BOTH client APIs — the TypeScript client (`NodeRuntime` / `secure-exec`) and the Rust client. When you add or change a protocol capability, expose it on both; never leave wire functionality unreachable from the TS or Rust API. -- Config travels on the **BARE wire/structured request**, not the ambient `AGENTOS_*` env channel. Classify every setting into three buckets: (1) **process-wide / host / build / test → env** (shared across all VMs, not per-VM configurable); (2) **per-VM bootstrap-before-wire → env carve-out** (must exist at `exec` time before the wire/sync-RPC bridge is up: sandbox root, inherited bridge fds, entrypoint/payload); (3) **per-VM runtime config → BARE wire** (anything per-VM the established wire/bridge could carry — limits, virtualized identity, isolation policy). New per-VM settings default to bucket 3. Migrated so far: resource limits + virtualized identity (`process.*` via the runtime shim, `os.*` via the `__agentOSVirtualOs` global). Isolation policy (guest path mappings, extra fs read/write paths, allowed Node builtins, loopback-exempt ports, WASM permission tier) is still on env — bucket 3 but not yet moved. Anti-pattern: a value carried on the wire then silently re-emitted as an env knob (and maybe never read) is the **dead-cap** failure mode — if it's on the wire, the engine must read it from the wire path, never from a duplicated env var. See `crates/sidecar/CLAUDE.md` for the rule. -- JavaScript host-emulation config (`CreateVmConfig.jsRuntime`) mirrors esbuild's vocabulary so users carry over a known mental model. The host environment presented to guest JS is a `platform`; its values are esbuild's exactly — `node` | `browser` | `neutral` — plus the one sanctioned extension `bare` (language-only: ECMAScript spec globals + WebAssembly, nothing host-provided), for which esbuild has no equivalent. Do not invent other platform names. Wherever a JS runtime/resolution config property has an esbuild equivalent, take esbuild's name and value spelling over any other source (esbuild > tsconfig > ad-hoc); introduce a non-esbuild name only when esbuild has no equivalent concept (e.g. `moduleResolution`, `allowedBuiltins`). -- `packages/core/` is `@secure-exec/core`, the generic TypeScript protocol, client, descriptor, and runtime asset package. -- `packages/build-tools/` is `@secure-exec/build-tools`, the workspace-only generator package for V8 bridge and base filesystem assets. A fresh checkout must run `pnpm install` before any `cargo` build (including when a downstream like agent-os path-deps these crates): `v8-runtime/build.rs` generates the V8 bridge assets from `packages/build-tools/node_modules` and panics if they are absent. -- Registry software and agent packages live under `registry/` with the `@agentos-software/*` npm scope (tool packages keep `@secure-exec/*`). Their build/publish lifecycle is owned by `@rivet-dev/agentos-toolchain` (`packages/agentos-toolchain`: `stage`/`build`/`pack`/`publish`) driven by the `just registry-*` recipes; the full flow is documented in `registry/README.md`. Never add package-local copy scripts or Makefile staging — declare commands/aliases/stubs in the package's `agentos-package.json` and let `stage` populate the gitignored `bin/`. - -## Build And Assets - -- The VM base filesystem artifact is derived from Alpine Linux, but runtime source should stay generic. -- Rebuild the base filesystem (requires Docker) with `pnpm --dir packages/build-tools build:base-filesystem`. The one script snapshots Alpine, applies the secure-exec transforms, and writes the single canonical `packages/core/fixtures/base-filesystem.json`, mirroring the same bytes into the crate-vendored `crates/sidecar/assets/` and `crates/vfs/assets/` copies (those exist only as the `cargo publish` fallback; never hand-edit them). -- The V8 bridge bundle is generated from `packages/build-tools/scripts/build-v8-bridge.mjs`; keep its generated assets aligned with bridge-contract changes. -- `registry/native` owns the Rust-to-WASM command build (`just registry-native`, or `just registry-native-cmd ` for one `cmd-` crate); its `target/wasm32-wasip1/release/commands/` output feeds `agentos-toolchain stage`, which populates each package's gitignored `bin/` for `agentos-toolchain build` to assemble into `dist/package/`. - -## npm Compatibility - -- npm packages must work unmodified inside the VM. Fix module resolution or polyfills instead of bundling or patching published packages. -- Never hardcode support for specific npm packages in secure-exec. Do not special-case package names (e.g. `minimatch`, `glob`, `undici`) in module resolution, format detection, export synthesis, polyfills, or interop. When a real package exposes a general gap, fix the underlying mechanism so every package benefits; a package-name branch is a sign the real bug is elsewhere. The only allowed name-based handling is for Node.js builtins (e.g. `node:fs`), never third-party packages. -- The VM presents mounted `node_modules` faithfully, like a real filesystem (Docker-style), symlinks included. Module resolution must match naive Node.js resolution over that filesystem — the ancestor `node_modules` walk, `exports`/`imports`/conditions, and `realpath`/symlink following — and nothing more. -- No package-manager-specific resolution heuristics. The resolver must not understand pnpm/yarn internals — e.g. no scanning the `.pnpm` virtual store or guessing a version when no symlink points to it. pnpm/yarn layouts resolve because the VFS exposes their symlinks, not because the resolver special-cases them. If a real layout fails, fix VFS symlink fidelity (or `exports`/conditions handling), never add a layout-aware shortcut. -- Use `node-stdlib-browser` for pure-JS builtins and bridge-backed polyfills for kernel-backed modules such as `fs`, `net`, `child_process`, `dns`, `http`, `os`, and `crypto`. -- Guest `fetch()` must run through undici inside the V8 isolate, then through the kernel socket table. - -## Native Binary Distribution - -- Ship `secure-exec-sidecar` through `@secure-exec/sidecar` plus platform packages declared as optional dependencies. -- Publish platform binary packages with `npm publish`, not `pnpm publish`, so executable bits are preserved. -- Resolver packages must return an absolute binary path. Callers pass that typed path to process spawning instead of relying on global environment mutation. - -## Development - -### Release Tracks - -- **secure-exec runtime** — `@secure-exec/*` npm packages and `secure-exec-*` crates; releases keep npm/crates in sync, previews are npm-only. See "Release-previewing" and "Publishing" for details. -- **GATE — secure-exec product versions are always `0.0.1` in the committed tree.** Every package returned by `scripts/publish/src/lib/packages.ts` `discoverPackages(repoRoot)` and the root `Cargo.toml [workspace.package]` version stays pinned at `0.0.1`; the real version is applied ONLY transiently in the CI publish checkout by `bump-versions`, never committed. `scripts/publish/src/ci/verify-fixed-versions.ts` enforces this in CI. `@agentos-software/*` registry packages under `registry/{software,agent}/*` are exempt and stay independently versioned. -- **`@agentos-software/*` registry packages** — generic VM software from secure-exec `registry/software/*` plus agent adapters from secure-exec `registry/agent/*`; versioned independently of secure-exec runtime packages. -- **agent-os product/API** — `@rivet-dev/agentos*`, AgentOs APIs, sidecar wrapper, docs, quickstarts, and examples; see agent-os `CLAUDE.md` for its pinning workflow. - -### Release-previewing - -`just release-preview ` dispatches `.github/workflows/publish.yaml` (workflow_dispatch, no version input) to cut a **preview** (debug sidecar build, npm-only, dist-tag = sanitized branch name) — for handing a build to a downstream (agent-os) or external project. **Preview-publish is for previews ONLY; never cut a release with it.** Caveats: WASM-bearing packages (`@secure-exec/core`, `@agentos-software/*`) publish MANUALLY (see Publishing), and the crates.io job is skipped on preview — a *crate* change only reaches consumers locally (path dep / `[patch]`) or via a real release. - -### Testing a local build from an external project (same machine) - -- **npm:** `pnpm -r build`, then `pnpm pack` the package and `npm install ./secure-exec-core-*.tgz` in the external project (or a `link:`/`file:` override). `@secure-exec/core` needs its WASM commands vendored first (`make -C registry/native wasm`; its `prepack` fails loud if absent). -- **cargo:** add a path dep or `[patch.crates-io]` override in the external Cargo project, e.g. `[patch.crates-io] secure-exec-sidecar = { path = "/abs/path/secure-exec/crates/sidecar" }`. A fresh checkout needs `pnpm install` first (V8 bridge assets — see Project Boundaries). - -## Publishing - -Workflow skills (follow these rather than improvising): -- `.claude/skills/release` — stable release (npm + crates.io lockstep, incl. the manual `@secure-exec/core` wasm publish). -- `.claude/skills/release-preview` — branch preview (`just release-preview `; npm-only, branch dist-tag, registry packages included). -- `.claude/skills/publish-registry` — `@agentos-software/*` registry packages (per-package semver, `dev` tag default, `latest` deliberate). -- agent-os side: its `.claude/skills/{bump-secure-exec,release-preview,release}` cover consuming/releasing against secure-exec. - -- **The `@secure-exec/*` npm packages and the `secure-exec-*` Cargo crates are always published at the same version** (npm and crates stay in sync), so a downstream pins both to one ``. See "Release Tracks" for how this differs from `@agentos-software/*` and agent-os releases. -- CI (`.github/workflows/publish.yaml`) DOES build and vendor the core WASM command set: the "Build and vendor core WASM commands" step runs `make -C registry/native wasm` + `packages/core run copy-commands` before the npm publish, and core's `prepack` fails loud if the commands are absent — so a published `@secure-exec/core` tarball always carries the command set. (`EXCLUDED` in `scripts/publish/src/lib/packages.ts` contains only the private `publish` package.) -- `@agentos-software/*` registry software releases stay MANUAL and per-package (`just registry-publish [tag]`; dist-tag `dev` unless `latest` is passed deliberately); PREVIEWS include them automatically under the branch dist-tag (`PUBLISH_INCLUDE_REGISTRY_PACKAGES`). -- `copy-wasm-commands.mjs` (core's vendoring) is the ONE sanctioned package-local copy script: it vendors the baseline command set into the published `@secure-exec/core` tarball at build/prepack time. Every registry package instead declares commands in `agentos-package.json` and lets `agentos-toolchain stage` populate `bin/`. - -## Website - -- `website/` is `@secure-exec/website`, a unified Astro app serving the public site at **secureexec.dev**: `/` is the React/Tailwind landing page and `/docs/*` is the Starlight documentation. -- External/consumer usage (installing `@secure-exec/core` and using it in your own project) is documented in the website, not in this file. This `CLAUDE.md` is contributor/maintainer-only. -- **Agent OS docs are canonical for agentOS-visible behavior — check them instead of local docs.** Most secure-exec runtime behavior (process lifecycle, limits, permissions, filesystem/network semantics, ACP-adjacent surfaces) reaches users through Agent OS, whose docs live in the agent-os repo (`../agent-os` `website/src/content/docs/`, deployed to `agentos-sdk.dev/docs`), NOT here. When a secure-exec change alters behavior that agentOS consumers can observe, check the agent-os docs for affected pages and keep them up to date in the accompanying agent-os change; the local `website/` documents only the standalone Secure Exec SDK surface. -- Docs are **user-facing, not internals.** Write for a developer *using the SDK*, not for a contributor maintaining the runtime. Every page is framed around how the SDK is used: what you call, what you pass, what you get back, and what behavior to expect. Do not document internal implementation (kernel data structures, isolate plumbing, refactor history); that belongs in code comments or `CLAUDE.md`. When a page must reference a runtime concept (filesystem model, networking, isolation), explain it through the developer-visible API and behavior, show a quick code example, then link out for the deeper reference rather than narrating internals. -- Docs are **bullet-heavy and code-heavy, not prose-heavy.** Default to scannable bullet lists in the `- **Foo**: Bar` form (bolded term, then the one-line explanation) instead of paragraphs. Lead with a code snippet wherever a concept has an API, and link to a runnable example under `examples/docs/*` whenever one exists. Avoid long paragraphs; if you find yourself writing more than two or three sentences in a row, convert it to bullets or a code block. Prose is the exception, used only to connect ideas that genuinely cannot be a list. -- The docs theme matches the Rivet docs (rivet.dev) 1:1: light-only "porcelain" palette, Manrope + JetBrains Mono, dark code blocks. -- Docs prose must not use em dashes (`—`). Rephrase with commas, colons, parentheses, or separate sentences. This applies to all content under `website/src/content/docs`. -- **Docs code blocks MUST embed real example files via `` — never hand-write checked code inline.** All runnable code shown in docs lives as a file under `examples/docs/*` (a real example package, verified end-to-end against the sidecar) and is embedded at build time, so the rendered code is always the exact code we ship, and each block auto-links to its source on GitHub. This **replaces** the old "copy the code verbatim into the page + add a manual `*[See Full Example](…)*` link" convention — `` embeds the source and generates the GitHub link automatically. Authoring: - - Embed a whole file: `` (repo-relative path). `remarkCodeSnippet` (in `@rivet-dev/docs-theme`) inlines the content; the language is inferred from the extension (override with `lang=`), the tab label is the basename (override with `title=`). - - Embed only part of a file with `region="name"`, delimiting it in the source with `// docs:start name` … `// docs:end name` (markers are stripped, the region is dedented). - - `` is the ONLY embed API. A bare ```` ```ts file="server.ts" ```` fence (no slash) is just a CodeGroup tab label, not an embed. - - Paths resolve from the repo root (override via `DOCS_EMBED_ROOT`). If the referenced code doesn't exist yet, add it as a proper runnable example under `examples/docs/*` rather than inlining unchecked code. - - Non-runnable snippets (shell commands, config fragments, illustrative pseudo-code) may stay inline — the rule is about code a reader could copy and run. - - This convention is owned by the shared `@rivet-dev/docs-theme` and applies to every site built on it (secure-exec AND agent-os). -- Docs styling is owned by the shared **`@rivet-dev/docs-theme`** repo (`github.com/rivet-dev/docs-theme`), consumed via `github:rivet-dev/docs-theme#` and wired in via `...docsTheme(starlight, siteConfig)` in `astro.config.mjs`. **To change any docs styling** (header, sidebar, code blocks, fonts, palette), edit that repo and follow its CLAUDE.md release workflow — never restyle docs in `website/src`. When iterating on theme styling locally, add a `pnpm.overrides` `link:` to the local docs-theme checkout (kept through local commits while iterating), but **remove it before pushing** — a pushed consumer must pin `github:rivet-dev/docs-theme#`, never a path. To change *this site's* identity/nav/sidebar/landing, edit `website/docs.config.mjs` (sidebar icons via each item's `attrs['data-icon']`). Re-test with `pnpm --dir website build`. - -- The proper product title is **"Secure Exec"** (two words, capitalized); use it in docs PROSE. Use the lowercase "secure-exec" only for code identifiers, package names (`@secure-exec/*`), the repo, and URLs. - -## Version Control (jj) - -- This checkout is jj colocated (jj over git). Prefer `jj` for commits/branches; avoid `git commit`/`git checkout`, which fight jj's working-copy commit. -- Large pyodide/sandbox assets exceed jj's default snapshot size limit. Commit them with `jj --config snapshot.max-new-file-size=16777216 ...`, or gitignore them. -- **Commit titles and PR titles are pure conventional commits** (`feat`, `fix`, `chore`, `docs`, `refactor`, etc.) with an optional scope, e.g. `fix(sidecar): handle empty ack batch`. Never indicate that a change was written by a coding agent: no model name, no agent name, no `[SLOP(...)]` prefix, and no `Co-Authored-By:` or `Generated with` trailer. The title must read exactly as a human-authored conventional commit. jj descriptions stay single-line. -- **PR descriptions are a simple, high-level bullet list of what changed.** One bullet per meaningful change in plain language. No per-file or line-by-line detail, no implementation narration, and no mention of an agent. - -## CLAUDE.md Convention - -- Every directory with `CLAUDE.md` must also have `AGENTS.md` as a symlink to `CLAUDE.md`. -- Keep CLAUDE entries concise and limited to design constraints, invariants, and non-obvious rules. +This repository is a generated compatibility mirror. Make runtime changes in the AgentOS repository and regenerate the shims. diff --git a/Cargo.lock b/Cargo.lock index 81bf31e35..2dab938aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,6 +49,210 @@ dependencies = [ "subtle", ] +[[package]] +name = "agentos-bridge" +version = "0.0.1" +dependencies = [ + "serde", + "serde_json", + "tracing", +] + +[[package]] +name = "agentos-build-support" +version = "0.0.1" + +[[package]] +name = "agentos-execution" +version = "0.0.1" +dependencies = [ + "agentos-bridge", + "agentos-build-support", + "agentos-v8-runtime", + "base64 0.22.1", + "ciborium", + "getrandom 0.2.17", + "nix", + "serde", + "serde_json", + "tokio", + "tracing", +] + +[[package]] +name = "agentos-kernel" +version = "0.0.1" +dependencies = [ + "agentos-bridge", + "agentos-vfs-core", + "base64 0.22.1", + "getrandom 0.2.17", + "hickory-proto", + "hickory-resolver", + "serde", + "serde_json", + "tokio", + "web-time", +] + +[[package]] +name = "agentos-native-sidecar" +version = "0.0.1" +dependencies = [ + "aes", + "aes-gcm", + "agentos-bridge", + "agentos-execution", + "agentos-kernel", + "agentos-native-sidecar-core", + "agentos-sidecar-protocol", + "agentos-vfs", + "agentos-vfs-core", + "agentos-vm-config", + "async-trait", + "aws-config", + "aws-credential-types", + "aws-sdk-s3", + "base64 0.22.1", + "blake3", + "bytes", + "cap-std", + "ctr", + "filetime", + "h2 0.4.13", + "hickory-resolver", + "hmac", + "http 1.4.0", + "jsonwebtoken", + "log", + "md-5", + "nix", + "openssl", + "pbkdf2", + "rusqlite", + "rustls 0.23.37", + "rustls-native-certs", + "rustls-pemfile", + "scrypt", + "serde", + "serde_json", + "sha1", + "sha2", + "socket2 0.6.3", + "tokio", + "tokio-rustls 0.26.4", + "tracing", + "tracing-subscriber", + "ureq", + "url", +] + +[[package]] +name = "agentos-native-sidecar-browser" +version = "0.0.1" +dependencies = [ + "agentos-bridge", + "agentos-kernel", + "agentos-native-sidecar-core", + "agentos-sidecar-protocol", + "agentos-vm-config", + "base64 0.22.1", + "getrandom 0.2.17", + "js-sys", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "agentos-native-sidecar-core" +version = "0.0.1" +dependencies = [ + "agentos-bridge", + "agentos-kernel", + "agentos-sidecar-protocol", + "agentos-vfs-core", + "agentos-vm-config", + "base64 0.22.1", + "serde_json", +] + +[[package]] +name = "agentos-sidecar-client" +version = "0.0.1" +dependencies = [ + "agentos-sidecar-protocol", + "futures", + "parking_lot", + "scc", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "agentos-sidecar-protocol" +version = "0.0.1" +dependencies = [ + "agentos-vm-config", + "rivet-vbare-compiler", + "serde", + "serde_bare", + "serde_json", + "vbare", +] + +[[package]] +name = "agentos-v8-runtime" +version = "0.0.1" +dependencies = [ + "agentos-bridge", + "agentos-build-support", + "ciborium", + "crossbeam-channel", + "libc", + "serde", + "sha2", + "signal-hook", + "v8", +] + +[[package]] +name = "agentos-vfs" +version = "0.0.1" +dependencies = [ + "agentos-vfs-core", + "async-trait", + "aws-sdk-s3", + "rusqlite", + "serde", + "serde_json", +] + +[[package]] +name = "agentos-vfs-core" +version = "0.0.1" +dependencies = [ + "async-trait", + "base64 0.22.1", + "blake3", + "memmap2", + "serde", + "serde_json", + "tar", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "agentos-vm-config" +version = "0.0.1" +dependencies = [ + "serde", + "serde_json", + "ts-rs", +] + [[package]] name = "ahash" version = "0.8.12" @@ -2197,10 +2401,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "native-baseline" -version = "0.0.1" - [[package]] name = "ndk-context" version = "0.1.1" @@ -2982,214 +3182,91 @@ dependencies = [ name = "secure-exec-bridge" version = "0.0.1" dependencies = [ - "serde", - "serde_json", - "tracing", + "agentos-bridge", ] [[package]] name = "secure-exec-build-support" version = "0.0.1" +dependencies = [ + "agentos-build-support", +] [[package]] name = "secure-exec-client" version = "0.0.1" dependencies = [ - "futures", - "parking_lot", - "scc", - "secure-exec-sidecar-protocol", - "thiserror", - "tokio", - "tracing", + "agentos-sidecar-client", ] [[package]] name = "secure-exec-execution" version = "0.0.1" dependencies = [ - "base64 0.22.1", - "ciborium", - "getrandom 0.2.17", - "nix", - "secure-exec-bridge", - "secure-exec-build-support", - "secure-exec-v8-runtime", - "serde", - "serde_json", - "tempfile", - "tokio", - "tracing", - "wat", + "agentos-execution", ] [[package]] name = "secure-exec-kernel" version = "0.0.1" dependencies = [ - "base64 0.22.1", - "getrandom 0.2.17", - "hickory-proto", - "hickory-resolver", - "secure-exec-bridge", - "secure-exec-vfs-core", - "serde", - "serde_json", - "tokio", - "web-time", + "agentos-kernel", ] [[package]] name = "secure-exec-sidecar" version = "0.0.1" dependencies = [ - "aes", - "aes-gcm", - "async-trait", - "aws-config", - "aws-credential-types", - "aws-sdk-s3", - "base64 0.22.1", - "blake3", - "bytes", - "cap-std", - "ctr", - "filetime", - "h2 0.4.13", - "hickory-resolver", - "hmac", - "http 1.4.0", - "jsonwebtoken", - "log", - "md-5", - "nix", - "openssl", - "pbkdf2", - "rusqlite", - "rustls 0.23.37", - "rustls-native-certs", - "rustls-pemfile", - "scrypt", - "secure-exec-bridge", - "secure-exec-execution", - "secure-exec-kernel", - "secure-exec-sidecar-core", - "secure-exec-sidecar-protocol", - "secure-exec-vfs", - "secure-exec-vfs-core", - "secure-exec-vm-config", - "serde", - "serde_bare", - "serde_json", - "sha1", - "sha2", - "socket2 0.6.3", - "tar", - "tokio", - "tokio-rustls 0.26.4", - "tracing", - "tracing-subscriber", - "ureq", - "url", - "v8", - "wat", + "agentos-native-sidecar", ] [[package]] name = "secure-exec-sidecar-browser" version = "0.0.1" dependencies = [ - "base64 0.22.1", - "getrandom 0.2.17", - "js-sys", - "secure-exec-bridge", - "secure-exec-kernel", - "secure-exec-sidecar-core", - "secure-exec-sidecar-protocol", - "secure-exec-vm-config", - "serde_json", - "wasm-bindgen", + "agentos-native-sidecar-browser", ] [[package]] name = "secure-exec-sidecar-core" version = "0.0.1" dependencies = [ - "base64 0.22.1", - "secure-exec-bridge", - "secure-exec-kernel", - "secure-exec-sidecar-protocol", - "secure-exec-vfs-core", - "secure-exec-vm-config", - "serde_json", + "agentos-native-sidecar-core", ] [[package]] name = "secure-exec-sidecar-protocol" version = "0.0.1" dependencies = [ - "rivet-vbare-compiler", - "secure-exec-vm-config", - "serde", - "serde_bare", - "serde_json", - "vbare", + "agentos-sidecar-protocol", ] [[package]] name = "secure-exec-v8-runtime" version = "0.0.1" dependencies = [ - "ciborium", - "crossbeam-channel", - "libc", - "secure-exec-bridge", - "secure-exec-build-support", - "serde", - "sha2", - "signal-hook", - "v8", + "agentos-v8-runtime", ] [[package]] name = "secure-exec-vfs" version = "0.0.1" dependencies = [ - "async-trait", - "aws-config", - "aws-credential-types", - "aws-sdk-s3", - "rusqlite", - "secure-exec-vfs-core", - "serde", - "serde_json", - "tempfile", - "tokio", + "agentos-vfs", ] [[package]] name = "secure-exec-vfs-core" version = "0.0.1" dependencies = [ - "async-trait", - "base64 0.22.1", - "blake3", - "memmap2", - "serde", - "serde_json", - "tar", - "tokio", - "tracing", - "web-time", + "agentos-vfs-core", ] [[package]] name = "secure-exec-vm-config" version = "0.0.1" dependencies = [ - "serde", - "serde_json", - "ts-rs", + "agentos-vm-config", ] [[package]] @@ -3500,19 +3577,6 @@ dependencies = [ "xattr", ] -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.2", - "once_cell", - "rustix 1.1.4", - "windows-sys 0.61.2", -] - [[package]] name = "termcolor" version = "1.4.1" @@ -3793,12 +3857,6 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - [[package]] name = "unicode-xid" version = "0.2.6" @@ -4025,17 +4083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" dependencies = [ "leb128fmt", - "wasmparser 0.244.0", -] - -[[package]] -name = "wasm-encoder" -version = "0.246.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e1929aad146499e47362c876fcbcbb0363f730951d93438f511178626e999a8" -dependencies = [ - "leb128fmt", - "wasmparser 0.246.1", + "wasmparser", ] [[package]] @@ -4046,8 +4094,8 @@ checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", "indexmap", - "wasm-encoder 0.244.0", - "wasmparser 0.244.0", + "wasm-encoder", + "wasmparser", ] [[package]] @@ -4062,39 +4110,6 @@ dependencies = [ "semver", ] -[[package]] -name = "wasmparser" -version = "0.246.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d991c35d79bf8336dc1cd632ed4aacf0dc5fac4bc466c670625b037b972bb9c" -dependencies = [ - "bitflags", - "indexmap", - "semver", -] - -[[package]] -name = "wast" -version = "246.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96cf2d50bc7478dcca61d00df4dadf922ef46c5924db20a97e6daaf09fe1cb09" -dependencies = [ - "bumpalo", - "leb128fmt", - "memchr", - "unicode-width", - "wasm-encoder 0.246.1", -] - -[[package]] -name = "wat" -version = "1.246.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723f2473b47f738c12fc11c8e0bb8b27ce7cf9c78cf1a29dadbc2d34a2513292" -dependencies = [ - "wast", -] - [[package]] name = "web-sys" version = "0.3.94" @@ -4379,9 +4394,9 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.244.0", + "wasm-encoder", "wasm-metadata", - "wasmparser 0.244.0", + "wasmparser", "wit-parser", ] @@ -4400,7 +4415,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.244.0", + "wasmparser", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 919bdf45f..3eafba16e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,20 +1,19 @@ [workspace] resolver = "2" members = [ - "crates/bridge", - "crates/kernel", - "crates/vfs", - "crates/secure-exec-vfs", - "crates/build-support", - "crates/sidecar-protocol", + "crates/sidecar-browser", "crates/sidecar-core", - "crates/execution", - "crates/secure-exec-client", + "crates/sidecar-protocol", "crates/sidecar", - "crates/sidecar-browser", - "crates/vm-config", + "crates/client", + "crates/build-support", "crates/v8-runtime", - "crates/native-baseline", + "crates/vm-config", + "crates/execution", + "crates/kernel", + "crates/bridge", + "crates/vfs-core", + "crates/vfs", ] [workspace.package] @@ -22,19 +21,3 @@ version = "0.0.1" edition = "2021" license = "Apache-2.0" repository = "https://github.com/rivet-dev/secure-exec" - -[workspace.dependencies] -secure-exec-bridge = { path = "crates/bridge", version = "0.0.1" } -secure-exec-build-support = { path = "crates/build-support", version = "0.0.1" } -secure-exec-kernel = { path = "crates/kernel", version = "0.0.1" } -secure-exec-sidecar-protocol = { path = "crates/sidecar-protocol", version = "0.0.1" } -secure-exec-sidecar-core = { path = "crates/sidecar-core", version = "0.0.1" } -secure-exec-execution = { path = "crates/execution", version = "0.0.1" } -secure-exec-vm-config = { path = "crates/vm-config", version = "0.0.1" } -secure-exec-v8-runtime = { path = "crates/v8-runtime", version = "0.0.1" } -secure-exec-client = { path = "crates/secure-exec-client", version = "0.0.1" } -secure-exec-sidecar = { path = "crates/sidecar", version = "0.0.1" } -secure-exec-vfs = { path = "crates/secure-exec-vfs", version = "0.0.1" } -vfs = { package = "secure-exec-vfs-core", path = "crates/vfs", version = "0.0.1" } -vbare = "0.0.4" -vbare-compiler = { package = "rivet-vbare-compiler", version = "0.0.5" } diff --git a/README.md b/README.md index 093f629b1..c1e3112c1 100644 --- a/README.md +++ b/README.md @@ -1,297 +1,3 @@ -

- Secure Exec -

+# secure-exec -

Secure Node.js Execution Without a Sandbox

- -

- A lightweight library for secure Node.js execution.
- No containers, no VMs — just npm-compatible sandboxing out of the box.
- Powered by the same tech as Cloudflare Workers. -

- -

- DocumentationSDK OverviewDiscord -

- -``` -npm install secure-exec -``` - -## Why Secure Exec - -Give your AI agent the ability to write and run code safely. - -- **No infrastructure required** — No Docker daemon, no hypervisor, no orchestrator. Runs anywhere Node.js, Bun, or an HTML5 browser runs. Deploy to Lambda, a VPS, or a static site — your existing deployment works. -- **Node.js & npm compatibility** — fs, child_process, http, dns, process, os — bridged to real host capabilities, not stubbed. Run Express, Hono, Next.js, and any npm package. -- **Built for AI agents** — Give your AI agent the ability to write and run code safely. Works with the Vercel AI SDK, LangChain, and any tool-use framework. -- **Deny-by-default permissions** — Filesystem, network, child processes, and env vars are all blocked unless explicitly allowed. Permissions are composable functions — grant read but not write, allow fetch but block spawn. -- **Configurable resource limits** — CPU time budgets and memory caps. Runaway code is terminated deterministically — no OOM crashes, no infinite loops, no host exhaustion. -- **Powered by V8 isolates** — The same isolation primitive behind Cloudflare Workers for Platforms and every browser tab. Battle-tested at scale by the infrastructure you already trust. - -## Features - -- **[TypeScript](https://secureexec.dev/docs/features/typescript)** — Compile and type-check TypeScript inside the sandbox. -- **[Permissions](https://secureexec.dev/docs/features/permissions)** — Control what sandboxed code can access on the host. -- **[Filesystem & Mounts](https://secureexec.dev/docs/features/filesystem)** — Filesystem backends for sandboxed code. -- **[Virtual Filesystem](https://secureexec.dev/docs/features/virtual-filesystem)** — A fully virtual filesystem inside the kernel, isolated from the host disk. -- **[Networking](https://secureexec.dev/docs/features/networking)** — Network access for sandboxed code. -- **[NPM & Module Loading](https://secureexec.dev/docs/features/module-loading)** — How sandboxed code resolves and loads modules. -- **[Runtime & Platform](https://secureexec.dev/docs/features/runtime-platform)** — The host environment guest code sees, plus the platform ladder. -- **[Output Capture](https://secureexec.dev/docs/features/output-capture)** — Capture console output from sandboxed code. -- **[Resource Limits](https://secureexec.dev/docs/features/resource-limits)** — Bound and cancel guest execution with timeouts, memory, and CPU-time limits. -- **[Child Processes](https://secureexec.dev/docs/features/child-processes)** — Spawn child processes from sandboxed code. - -## Quickstart - -**1. Install** - -```bash -npm install secure-exec -``` - -**2. Create a runtime** - -`NodeRuntime.create()` boots a fully virtualized VM behind the native sidecar. Guest code runs inside the kernel isolation boundary with no host escapes. All options are optional: `cwd` defaults to `/workspace`, and permissions default to a secure policy that denies network access (see step 4). - -```ts -import { NodeRuntime } from "secure-exec"; - -const runtime = await NodeRuntime.create(); -``` - -**3. Run code** - -Use `run()` when you want a JSON value back; the guest calls `globalThis.__return(value)` to set it. Use `exec()` when you care about side effects and want to capture `stdout`/`stderr`/`exitCode`. Guest code runs as an ES module, so `import` and top-level `await` both work. - -```ts -import { NodeRuntime } from "secure-exec"; - -// Boot a fully virtualized runtime. Guest code runs inside the kernel -// isolation boundary - no host escapes. -const runtime = await NodeRuntime.create(); - -try { - // run() executes guest JavaScript as an ES module and returns the value the - // guest passes to globalThis.__return(). stdout/stderr are captured too. - const result = await runtime.run<{ message: string; sum: number }>(` - console.log("hello from secure-exec"); - __return({ message: "hello from secure-exec", sum: 1 + 2 }); - `); - - console.log("stdout:", JSON.stringify(result.stdout.trim())); - console.log("value:", result.value); - console.log("exitCode:", result.exitCode); -} finally { - // Tear down the VM and release the sidecar. - await runtime.dispose(); -} -``` - -**4. Configure permissions (optional)** - -Guest code is **deny-by-default**: the sandbox has no network access until you opt in (the filesystem and processes are fully virtualized and never touch the host). Pass a `permissions` policy to `NodeRuntime.create()` to open up capabilities. It merges over the secure default, so you only specify what you want to change. - -```ts -const runtime = await NodeRuntime.create({ - permissions: { - // Virtualized and enabled by default (these never touch the host): - fs: "allow", // the in-VM filesystem - childProcess: "allow", // spawning processes inside the VM - process: "allow", // process info (pid, cwd, ...) - env: "allow", // environment variables - // Denied by default - opt in explicitly: - network: "allow", // outbound network access - tool: "allow", // host callbacks - }, -}); -``` - -Set any scope to `"deny"` to lock it down. See [Permissions](https://secureexec.dev/docs/features/permissions) to learn more. - -*[See the full quickstart →](https://secureexec.dev/docs/quickstart)* - - - -## Secure Exec vs. Sandboxes - -Not every workload needs a full OS. Secure Exec gives you V8-level isolation for code execution — no container required. - -- **Secure Exec** — Run untrusted code (Node.js, Python) inside your backend process -- **Sandboxes** — Spin up a full OS with root access, system packages, and persistent disk - -| | Secure Exec | Sandbox | -|----------------------|------------------------------------------|------------------------------| -| **Performance** | ✅ Native V8 | ✅ Native container | -| **Permissions** | ✅ Granular deny-by-default | ❌ Coarse-grained | -| **Setup** | ✅ Just `npm install` — no vendor account | ❌ Vendor account required | -| **Infrastructure** | ✅ Run on any cloud or hardware | ❌ Hardware lock-in | -| **Egress** | ✅ No egress fees | ❌ Per-GB egress fees | -| **API keys** | ✅ None | ❌ Required | - -[**Full comparison guide →**](https://secureexec.dev/docs/comparison/sandbox) - -> **Need a full sandboxed operating system? We've got that too.**
-> -> The [Sandbox Agent SDK](https://sandboxagent.dev/) lets you run coding agents in sandboxes and control them over HTTP. Supports Claude Code, Codex, OpenCode, Amp, and Pi. Works with E2B, Daytona, Vercel, Docker, and Cloudflare. - -## FAQ - -
-How does it work? - -Secure Exec runs untrusted code inside [V8 isolates](https://v8.dev/docs/embed) — the same isolation primitive that powers every Chromium tab and Cloudflare Workers. Each execution gets its own heap, its own globals, and a deny-by-default permission boundary. There is no container, no VM, and no Docker daemon — just fast, lightweight isolation using battle-tested web technology. [Architecture →](https://secureexec.dev/docs/sdk-overview) -
- -
-Does this require Docker, nested virtualization, or a hypervisor? - -No. Secure Exec is a pure npm package — `npm install secure-exec` is all you need. It has zero infrastructure dependencies: no Docker daemon, no hypervisor, no orchestrator, no sidecar. It runs anywhere Node.js or Bun runs. -
- -
-Can it run in serverless environments? - -We are actively validating serverless platforms, but Secure Exec should work everywhere that provides a standard Node.js-like runtime. This includes Vercel Fluid Compute, AWS Lambda, and Google Cloud Run. Cloudflare Workers is not supported because it does not expose the V8 APIs that Secure Exec relies on. -
- -
-When should I use a sandbox vs. Secure Exec? - -Use **Secure Exec** when you need fast, lightweight code execution — AI tool calls, code evaluation, user-submitted scripts — without provisioning infrastructure. Use a **sandbox** (e2b, Modal, Daytona) when you need a full operating-system environment with persistent disk, root access, or GPU passthrough. [Full comparison →](https://secureexec.dev/docs/comparison/sandbox) -
- -
-Can I run npm install in Secure Exec to dynamically install modules? - -Yes. Secure Exec supports dynamic module installation via npm inside the execution environment. -
- -
-Can I use it to run dev servers like Express, Hono, or Next.js? - -Yes. Secure Exec bridges Node.js APIs including http, net, and child_process, so frameworks like Express, Hono, and Next.js work out of the box. For production deployments, pair Secure Exec with [Rivet Actors](https://rivet.dev/docs/actors) to get built-in routing, scaling, and lifecycle management for each server instance. -
- -
-Can it be used for long-running tasks? - -Yes. For orchestrating stateful, long-running tasks, we recommend pairing Secure Exec with [Rivet Actors](https://rivet.dev/docs/actors). Rivet Actors provide durable state, automatic persistence, and fault-tolerant orchestration — so each long-running task survives restarts and can be monitored, paused, or resumed without you building that infrastructure yourself. -
- -
-What are common use cases? - -- [AI agent code execution and tool use](https://secureexec.dev/docs/use-cases/ai-agent-code-exec) -- [User-facing dev servers (Express, Hono, Next.js)](https://secureexec.dev/docs/use-cases/dev-servers) -- MCP tool-code execution -- [Sandboxed plugin / extension systems](https://secureexec.dev/docs/use-cases/plugin-systems) -- Interactive coding playgrounds -
- -
-Does this have Node.js compatibility? - -Yes. Most Node.js core modules work — including fs, child_process, http, dns, process, and os. These are bridged to real host capabilities, not stubbed. -
- -
-Does this have access to a full operating system? - -Yes. Secure Exec includes a virtual kernel with a system bridge that supports a granular permission model. Filesystem, network, child processes, and environment variables are all available — gated behind deny-by-default permissions. -
- -
-Does Secure Exec support JIT compilation? - -Yes. Secure Exec runs on native V8 isolates, so your code is JIT-compiled by V8's TurboFan optimizing compiler — the same pipeline that powers Chrome and Node.js. This means full optimization tiers, inline caching, and speculative optimization out of the box. -
- -
-How does Secure Exec compare to WASM-based JavaScript runtimes like QuickJS? - -WASM-based runtimes like [QuickJS](https://bellard.org/quickjs/) (via quickjs-emscripten) compile a separate JS engine to WebAssembly, which means your code runs through an interpreter inside WASM — not native V8. Secure Exec uses native V8 isolates directly, so you get the same JIT-compiled performance as JavaScript running on the host. No interpretation overhead, no WASM translation layer, and full Node.js API compatibility. -
- -## Links - -- [Documentation](https://secureexec.dev/docs) -- [Changelog](https://github.com/rivet-dev/secure-exec/releases) -- [Discord](https://rivet.dev/discord) -- [GitHub](https://github.com/rivet-dev/secure-exec) - -## License - -Apache-2.0 +Compatibility mirror. Active runtime development moved to the AgentOS runtime packages and crates. diff --git a/crates/bridge/Cargo.toml b/crates/bridge/Cargo.toml index 1df86d1fe..8dbbeedb7 100644 --- a/crates/bridge/Cargo.toml +++ b/crates/bridge/Cargo.toml @@ -4,9 +4,10 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Shared bridge contracts between the secure-exec kernel and execution planes" +description = "secure-exec-bridge compatibility shim for agentos-bridge" + +[lib] +name = "secure_exec_bridge" [dependencies] -serde = { version = "1.0", features = ["derive"] } -serde_json = "1" -tracing = "0.1" +agentos_bridge = { package = "agentos-bridge", path = "../../../agentos/crates/bridge", version = "0.0.1" } diff --git a/crates/bridge/bridge-contract.json b/crates/bridge/bridge-contract.json deleted file mode 100644 index 12c3e6876..000000000 --- a/crates/bridge/bridge-contract.json +++ /dev/null @@ -1,1089 +0,0 @@ -{ - "version": 1, - "groups": [ - { - "convention": "sync", - "argumentTypes": [ - "message: string" - ], - "returnType": "void", - "names": [ - "_log", - "_error" - ] - }, - { - "convention": "sync", - "argumentTypes": [ - "...args: unknown[]" - ], - "returnType": "unknown", - "names": [ - "_benchNoop", - "_benchNetTcpMetricsResetRaw", - "_benchNetTcpMetricsSnapshotRaw" - ] - }, - { - "convention": "syncPromise", - "argumentTypes": [ - "request: string" - ], - "returnType": "string | null", - "names": [ - "_loadPolyfill" - ] - }, - { - "convention": "syncPromise", - "argumentTypes": [ - "specifier: string", - "fromDir: string", - "mode?: \"require\" | \"import\"" - ], - "returnType": "string | null", - "names": [ - "_resolveModule", - "_resolveModuleSync" - ] - }, - { - "convention": "syncPromise", - "argumentTypes": [ - "path: string" - ], - "returnType": "string | null", - "names": [ - "_loadFile", - "_loadFileSync" - ] - }, - { - "convention": "syncPromise", - "argumentTypes": [ - "filename: string" - ], - "returnType": "\"module\" | \"commonjs\" | \"json\" | null", - "names": [ - "_moduleFormat" - ] - }, - { - "convention": "syncPromise", - "argumentTypes": [ - "requests: Array<[string, string]>" - ], - "returnType": "Array<{ resolved: string; source: string } | null>", - "names": [ - "_batchResolveModules" - ] - }, - { - "convention": "sync", - "argumentTypes": [ - "...args: unknown[]" - ], - "returnType": "unknown", - "names": [ - "_cryptoRandomFill", - "_cryptoRandomUUID", - "_cryptoHashDigest", - "_cryptoHmacDigest", - "_cryptoPbkdf2", - "_cryptoScrypt", - "_cryptoCipheriv", - "_cryptoDecipheriv", - "_cryptoCipherivCreate", - "_cryptoCipherivUpdate", - "_cryptoCipherivFinal", - "_cryptoSign", - "_cryptoVerify", - "_cryptoAsymmetricOp", - "_cryptoCreateKeyObject", - "_cryptoGenerateKeyPairSync", - "_cryptoGenerateKeySync", - "_cryptoGeneratePrimeSync", - "_cryptoDiffieHellman", - "_cryptoDiffieHellmanGroup", - "_cryptoDiffieHellmanSessionCreate", - "_cryptoDiffieHellmanSessionCall", - "_cryptoDiffieHellmanSessionDestroy", - "_cryptoSubtle" - ] - }, - { - "convention": "sync", - "argumentTypes": [ - "...args: unknown[]" - ], - "returnType": "unknown", - "names": [ - "_fsReadFile", - "_fsWriteFile", - "_fsReadFileBinary", - "_fsWriteFileBinary", - "_fsWriteFileBinaryRaw", - "_fsReadDir", - "_fsMkdir", - "_fsRmdir", - "_fsExists", - "_fsStat", - "_fsUnlink", - "_fsRename", - "_fsChmod", - "_fsChown", - "_fsLink", - "_fsSymlink", - "_fsReadlink", - "_fsLstat", - "_fsTruncate", - "_fsUtimes", - "_fsLutimes", - "fs.openSync", - "fs.closeSync", - "fs.readSync", - "_fsReadRaw", - "fs.writeSync", - "_fsWriteRaw", - "_fsWritevRaw", - "fs.fstatSync", - "fs.futimesSync" - ] - }, - { - "convention": "async", - "argumentTypes": [ - "...args: unknown[]" - ], - "returnType": "unknown", - "names": [ - "_fsReadFileAsync", - "_fsWriteFileAsync", - "_fsReadFileBinaryAsync", - "_fsWriteFileBinaryAsync", - "_fsReadDirAsync", - "_fsMkdirAsync", - "_fsRmdirAsync", - "_fsAccessAsync", - "_fsStatAsync", - "_fsUnlinkAsync", - "_fsRenameAsync", - "_fsChmodAsync", - "_fsChownAsync", - "_fsLinkAsync", - "_fsSymlinkAsync", - "_fsReadlinkAsync", - "_fsLstatAsync", - "_fsTruncateAsync", - "_fsUtimesAsync", - "_fsLutimesAsync" - ] - }, - { - "convention": "sync", - "argumentTypes": [ - "...args: unknown[]" - ], - "returnType": "unknown", - "names": [ - "_childProcessSpawnStart", - "_childProcessPoll", - "_childProcessStdinWrite", - "_childProcessStdinClose", - "_childProcessKill", - "_processKill", - "_processSignalState" - ] - }, - { - "convention": "syncPromise", - "argumentTypes": [ - "...args: unknown[]" - ], - "returnType": "unknown", - "names": [ - "_childProcessSpawnSync" - ] - }, - { - "convention": "sync", - "argumentTypes": [ - "...args: unknown[]" - ], - "returnType": "unknown", - "names": [ - "process.cpuUsage", - "process.memoryUsage", - "process.resourceUsage", - "process.versions", - "_vmCreateContext", - "_vmRunInContext", - "_vmRunInThisContext", - "_networkHttp2ServerListenRaw", - "_networkHttp2SessionConnectRaw", - "_networkHttp2SessionRequestRaw", - "_networkHttp2SessionSettingsRaw", - "_networkHttp2SessionSetLocalWindowSizeRaw", - "_networkHttp2SessionGoawayRaw", - "_networkHttp2SessionCloseRaw", - "_networkHttp2SessionDestroyRaw", - "_networkHttp2ServerPollRaw", - "_networkHttp2SessionPollRaw", - "_networkHttp2StreamRespondRaw", - "_networkHttp2StreamPushStreamRaw", - "_networkHttp2StreamWriteRaw", - "_networkHttp2StreamEndRaw", - "_networkHttp2StreamCloseRaw", - "_networkHttp2StreamPauseRaw", - "_networkHttp2StreamResumeRaw", - "_networkHttp2StreamRespondWithFileRaw", - "_networkHttp2ServerRespondRaw", - "_networkHttpServerRespondRaw", - "_networkHttpServerRequestRaw", - "_upgradeSocketWriteRaw", - "_upgradeSocketEndRaw", - "_upgradeSocketDestroyRaw", - "_networkDnsLookupSyncRaw", - "_netSocketConnectRaw", - "_netSocketPollRaw", - "_netSocketReadRaw", - "_netSocketSetNoDelayRaw", - "_netSocketSetKeepAliveRaw", - "_netSocketWriteRaw", - "_netSocketEndRaw", - "_netSocketDestroyRaw", - "_netSocketUpgradeTlsRaw", - "_netSocketGetTlsClientHelloRaw", - "_netSocketTlsQueryRaw", - "_tlsGetCiphersRaw", - "_netReserveTcpPortRaw", - "_netReleaseTcpPortRaw", - "_netServerListenRaw", - "_netServerAcceptRaw", - "_dgramSocketCreateRaw", - "_dgramSocketBindRaw", - "_dgramSocketRecvRaw", - "_dgramSocketSendRaw", - "_dgramSocketCloseRaw", - "_dgramSocketAddressRaw", - "_dgramSocketSetBufferSizeRaw", - "_dgramSocketGetBufferSizeRaw", - "_sqliteConstantsRaw", - "_sqliteDatabaseOpenRaw", - "_sqliteDatabaseCloseRaw", - "_sqliteDatabaseExecRaw", - "_sqliteDatabaseQueryRaw", - "_sqliteDatabasePrepareRaw", - "_sqliteDatabaseLocationRaw", - "_sqliteDatabaseCheckpointRaw", - "_sqliteStatementRunRaw", - "_sqliteStatementGetRaw", - "_sqliteStatementAllRaw", - "_sqliteStatementColumnsRaw", - "_sqliteStatementSetReturnArraysRaw", - "_sqliteStatementSetReadBigIntsRaw", - "_sqliteStatementSetAllowBareNamedParametersRaw", - "_sqliteStatementSetAllowUnknownNamedParametersRaw", - "_sqliteStatementFinalizeRaw", - "_kernelStdioWriteRaw", - "_kernelPollRaw", - "_kernelIsattyRaw", - "_kernelTtySizeRaw", - "_ptySetRawMode" - ] - }, - { - "convention": "async", - "argumentTypes": [ - "specifier: string", - "referrer: string" - ], - "returnType": "Record | null", - "names": [ - "_dynamicImport" - ] - }, - { - "convention": "async", - "argumentTypes": [ - "delayMs: number" - ], - "returnType": "void", - "names": [ - "_scheduleTimer" - ] - }, - { - "convention": "sync", - "argumentTypes": [ - "request: unknown" - ], - "returnType": "unknown", - "names": [ - "_pythonRpc" - ] - }, - { - "convention": "sync", - "argumentTypes": [ - "maxBytes: number", - "timeoutMs: number" - ], - "returnType": "string | null", - "names": [ - "_pythonStdinRead" - ] - }, - { - "convention": "sync", - "argumentTypes": [ - "...args: unknown[]" - ], - "returnType": "unknown", - "names": [ - "_kernelStdinReadRaw" - ] - }, - { - "convention": "async", - "argumentTypes": [], - "returnType": "{ done: boolean; dataBase64?: string }", - "names": [ - "_kernelStdinRead" - ] - }, - { - "convention": "async", - "argumentTypes": [ - "...args: unknown[]" - ], - "returnType": "unknown", - "names": [ - "_networkDnsLookupRaw", - "_networkDnsResolveRaw", - "_networkHttpServerListenRaw", - "_networkHttpServerCloseRaw", - "_networkHttpServerWaitRaw", - "_networkHttp2ServerCloseRaw", - "_networkHttp2ServerWaitRaw", - "_networkHttp2SessionWaitRaw", - "_netSocketWaitConnectRaw", - "_netServerCloseRaw" - ] - } - ], - "dispatch": { - "_batchResolveModules": { - "method": "__batch_resolve_modules", - "translateArgs": false - }, - "_benchNetTcpMetricsResetRaw": { - "method": "__bench.net_tcp_metrics_reset", - "translateArgs": false - }, - "_benchNetTcpMetricsSnapshotRaw": { - "method": "__bench.net_tcp_metrics_snapshot", - "translateArgs": false - }, - "_benchNoop": { - "method": "__bench.noop", - "translateArgs": false - }, - "_childProcessKill": { - "method": "child_process.kill", - "translateArgs": false - }, - "_childProcessPoll": { - "method": "child_process.poll", - "translateArgs": false - }, - "_childProcessSpawnStart": { - "method": "child_process.spawn", - "translateArgs": false - }, - "_childProcessSpawnSync": { - "method": "child_process.spawn_sync", - "translateArgs": false - }, - "_childProcessStdinClose": { - "method": "child_process.close_stdin", - "translateArgs": false - }, - "_childProcessStdinWrite": { - "method": "child_process.write_stdin", - "translateArgs": false - }, - "_cryptoAsymmetricOp": { - "method": "crypto.asymmetricOp", - "translateArgs": false - }, - "_cryptoCipheriv": { - "method": "crypto.cipheriv", - "translateArgs": false - }, - "_cryptoCipherivCreate": { - "method": "crypto.cipherivCreate", - "translateArgs": false - }, - "_cryptoCipherivFinal": { - "method": "crypto.cipherivFinal", - "translateArgs": false - }, - "_cryptoCipherivUpdate": { - "method": "crypto.cipherivUpdate", - "translateArgs": false - }, - "_cryptoCreateKeyObject": { - "method": "crypto.createKeyObject", - "translateArgs": false - }, - "_cryptoDecipheriv": { - "method": "crypto.decipheriv", - "translateArgs": false - }, - "_cryptoDiffieHellman": { - "method": "crypto.diffieHellman", - "translateArgs": false - }, - "_cryptoDiffieHellmanGroup": { - "method": "crypto.diffieHellmanGroup", - "translateArgs": false - }, - "_cryptoDiffieHellmanSessionCall": { - "method": "crypto.diffieHellmanSessionCall", - "translateArgs": false - }, - "_cryptoDiffieHellmanSessionCreate": { - "method": "crypto.diffieHellmanSessionCreate", - "translateArgs": false - }, - "_cryptoDiffieHellmanSessionDestroy": { - "method": "crypto.diffieHellmanSessionDestroy", - "translateArgs": false - }, - "_cryptoGenerateKeyPairSync": { - "method": "crypto.generateKeyPairSync", - "translateArgs": false - }, - "_cryptoGenerateKeySync": { - "method": "crypto.generateKeySync", - "translateArgs": false - }, - "_cryptoGeneratePrimeSync": { - "method": "crypto.generatePrimeSync", - "translateArgs": false - }, - "_cryptoHashDigest": { - "method": "crypto.hashDigest", - "translateArgs": false - }, - "_cryptoHmacDigest": { - "method": "crypto.hmacDigest", - "translateArgs": false - }, - "_cryptoPbkdf2": { - "method": "crypto.pbkdf2", - "translateArgs": false - }, - "_cryptoRandomFill": { - "method": "crypto.randomFill", - "translateArgs": false - }, - "_cryptoRandomUUID": { - "method": "crypto.randomUUID", - "translateArgs": false - }, - "_cryptoScrypt": { - "method": "crypto.scrypt", - "translateArgs": false - }, - "_cryptoSign": { - "method": "crypto.sign", - "translateArgs": false - }, - "_cryptoSubtle": { - "method": "crypto.subtle", - "translateArgs": false - }, - "_cryptoVerify": { - "method": "crypto.verify", - "translateArgs": false - }, - "_dgramSocketAddressRaw": { - "method": "dgram.address", - "translateArgs": false - }, - "_dgramSocketBindRaw": { - "method": "dgram.bind", - "translateArgs": false - }, - "_dgramSocketCloseRaw": { - "method": "dgram.close", - "translateArgs": false - }, - "_dgramSocketCreateRaw": { - "method": "dgram.createSocket", - "translateArgs": false - }, - "_dgramSocketGetBufferSizeRaw": { - "method": "dgram.getBufferSize", - "translateArgs": false - }, - "_dgramSocketRecvRaw": { - "method": "dgram.poll", - "translateArgs": false - }, - "_dgramSocketSendRaw": { - "method": "dgram.send", - "translateArgs": false - }, - "_dgramSocketSetBufferSizeRaw": { - "method": "dgram.setBufferSize", - "translateArgs": false - }, - "_error": { - "method": "__log", - "translateArgs": false - }, - "_fsAccessAsync": { - "method": "fs.promises.access", - "translateArgs": false - }, - "_fsChmod": { - "method": "fs.chmodSync", - "translateArgs": false - }, - "_fsChmodAsync": { - "method": "fs.promises.chmod", - "translateArgs": false - }, - "_fsChown": { - "method": "fs.chownSync", - "translateArgs": false - }, - "_fsChownAsync": { - "method": "fs.promises.chown", - "translateArgs": false - }, - "_fsExists": { - "method": "fs.existsSync", - "translateArgs": false - }, - "_fsLink": { - "method": "fs.linkSync", - "translateArgs": false - }, - "_fsLinkAsync": { - "method": "fs.promises.link", - "translateArgs": false - }, - "_fsLstat": { - "method": "fs.lstatSync", - "translateArgs": false - }, - "_fsLstatAsync": { - "method": "fs.promises.lstat", - "translateArgs": false - }, - "_fsLutimes": { - "method": "fs.lutimesSync", - "translateArgs": false - }, - "_fsLutimesAsync": { - "method": "fs.promises.lutimes", - "translateArgs": false - }, - "_fsMkdir": { - "method": "fs.mkdirSync", - "translateArgs": false - }, - "_fsMkdirAsync": { - "method": "fs.promises.mkdir", - "translateArgs": false - }, - "_fsReadDir": { - "method": "fs.readdirSync", - "translateArgs": false - }, - "_fsReadDirAsync": { - "method": "fs.promises.readdir", - "translateArgs": false - }, - "_fsReadFile": { - "method": "fs.readFileSync", - "translateArgs": false - }, - "_fsReadFileAsync": { - "method": "fs.promises.readFile", - "translateArgs": false - }, - "_fsReadFileBinary": { - "method": "fs.readFileSync", - "translateArgs": true - }, - "_fsReadFileBinaryAsync": { - "method": "fs.promises.readFile", - "translateArgs": true - }, - "_fsReadlink": { - "method": "fs.readlinkSync", - "translateArgs": false - }, - "_fsReadlinkAsync": { - "method": "fs.promises.readlink", - "translateArgs": false - }, - "_fsRename": { - "method": "fs.renameSync", - "translateArgs": false - }, - "_fsRenameAsync": { - "method": "fs.promises.rename", - "translateArgs": false - }, - "_fsRmdir": { - "method": "fs.rmdirSync", - "translateArgs": false - }, - "_fsRmdirAsync": { - "method": "fs.promises.rmdir", - "translateArgs": false - }, - "_fsStat": { - "method": "fs.statSync", - "translateArgs": false - }, - "_fsStatAsync": { - "method": "fs.promises.stat", - "translateArgs": false - }, - "_fsSymlink": { - "method": "fs.symlinkSync", - "translateArgs": false - }, - "_fsSymlinkAsync": { - "method": "fs.promises.symlink", - "translateArgs": false - }, - "_fsTruncate": { - "method": "fs.truncateSync", - "translateArgs": false - }, - "_fsTruncateAsync": { - "method": "fs.promises.truncate", - "translateArgs": false - }, - "_fsUnlink": { - "method": "fs.unlinkSync", - "translateArgs": false - }, - "_fsUnlinkAsync": { - "method": "fs.promises.unlink", - "translateArgs": false - }, - "_fsUtimes": { - "method": "fs.utimesSync", - "translateArgs": false - }, - "_fsUtimesAsync": { - "method": "fs.promises.utimes", - "translateArgs": false - }, - "_fsWriteFile": { - "method": "fs.writeFileSync", - "translateArgs": false - }, - "_fsWriteFileAsync": { - "method": "fs.promises.writeFile", - "translateArgs": false - }, - "_fsWriteFileBinary": { - "method": "fs.writeFileSync", - "translateArgs": true - }, - "_fsWriteFileBinaryRaw": { - "method": "fs.writeFileSync", - "translateArgs": false - }, - "_fsWriteFileBinaryAsync": { - "method": "fs.promises.writeFile", - "translateArgs": true - }, - "_kernelIsattyRaw": { - "method": "__kernel_isatty", - "translateArgs": false - }, - "_kernelPollRaw": { - "method": "__kernel_poll", - "translateArgs": false - }, - "_kernelStdinRead": { - "method": "__kernel_stdin_read", - "translateArgs": false - }, - "_kernelStdinReadRaw": { - "method": "__kernel_stdin_read", - "translateArgs": false - }, - "_kernelStdioWriteRaw": { - "method": "__kernel_stdio_write", - "translateArgs": false - }, - "_kernelTtySizeRaw": { - "method": "__kernel_tty_size", - "translateArgs": false - }, - "_loadFile": { - "method": "__load_file", - "translateArgs": false - }, - "_loadFileSync": { - "method": "__load_file", - "translateArgs": false - }, - "_loadPolyfill": { - "method": "__load_polyfill", - "translateArgs": false - }, - "_log": { - "method": "__log", - "translateArgs": false - }, - "_moduleFormat": { - "method": "__module_format", - "translateArgs": false - }, - "_netReleaseTcpPortRaw": { - "method": "net.release_tcp_port", - "translateArgs": false - }, - "_netReserveTcpPortRaw": { - "method": "net.reserve_tcp_port", - "translateArgs": false - }, - "_netServerAcceptRaw": { - "method": "net.server_accept", - "translateArgs": false - }, - "_netServerCloseRaw": { - "method": "net.server_close", - "translateArgs": false - }, - "_netServerListenRaw": { - "method": "net.listen", - "translateArgs": false - }, - "_netSocketConnectRaw": { - "method": "net.connect", - "translateArgs": false - }, - "_netSocketDestroyRaw": { - "method": "net.destroy", - "translateArgs": false - }, - "_netSocketEndRaw": { - "method": "net.shutdown", - "translateArgs": false - }, - "_netSocketGetTlsClientHelloRaw": { - "method": "net.socket_get_tls_client_hello", - "translateArgs": false - }, - "_netSocketPollRaw": { - "method": "net.poll", - "translateArgs": false - }, - "_netSocketReadRaw": { - "method": "net.socket_read", - "translateArgs": false - }, - "_netSocketSetKeepAliveRaw": { - "method": "net.socket_set_keep_alive", - "translateArgs": false - }, - "_netSocketSetNoDelayRaw": { - "method": "net.socket_set_no_delay", - "translateArgs": false - }, - "_netSocketTlsQueryRaw": { - "method": "net.socket_tls_query", - "translateArgs": false - }, - "_netSocketUpgradeTlsRaw": { - "method": "net.socket_upgrade_tls", - "translateArgs": false - }, - "_netSocketWaitConnectRaw": { - "method": "net.socket_wait_connect", - "translateArgs": false - }, - "_netSocketWriteRaw": { - "method": "net.write", - "translateArgs": false - }, - "_networkDnsLookupRaw": { - "method": "dns.lookup", - "translateArgs": false - }, - "_networkDnsLookupSyncRaw": { - "method": "dns.lookup", - "translateArgs": false - }, - "_networkDnsResolveRaw": { - "method": "dns.resolve", - "translateArgs": false - }, - "_networkHttp2ServerCloseRaw": { - "method": "net.http2_server_close", - "translateArgs": false - }, - "_networkHttp2ServerListenRaw": { - "method": "net.http2_server_listen", - "translateArgs": false - }, - "_networkHttp2ServerPollRaw": { - "method": "net.http2_server_poll", - "translateArgs": false - }, - "_networkHttp2ServerRespondRaw": { - "method": "net.http2_server_respond", - "translateArgs": false - }, - "_networkHttp2ServerWaitRaw": { - "method": "net.http2_server_wait", - "translateArgs": false - }, - "_networkHttp2SessionCloseRaw": { - "method": "net.http2_session_close", - "translateArgs": false - }, - "_networkHttp2SessionConnectRaw": { - "method": "net.http2_session_connect", - "translateArgs": false - }, - "_networkHttp2SessionDestroyRaw": { - "method": "net.http2_session_destroy", - "translateArgs": false - }, - "_networkHttp2SessionGoawayRaw": { - "method": "net.http2_session_goaway", - "translateArgs": false - }, - "_networkHttp2SessionPollRaw": { - "method": "net.http2_session_poll", - "translateArgs": false - }, - "_networkHttp2SessionRequestRaw": { - "method": "net.http2_session_request", - "translateArgs": false - }, - "_networkHttp2SessionSetLocalWindowSizeRaw": { - "method": "net.http2_session_set_local_window_size", - "translateArgs": false - }, - "_networkHttp2SessionSettingsRaw": { - "method": "net.http2_session_settings", - "translateArgs": false - }, - "_networkHttp2SessionWaitRaw": { - "method": "net.http2_session_wait", - "translateArgs": false - }, - "_networkHttp2StreamCloseRaw": { - "method": "net.http2_stream_close", - "translateArgs": false - }, - "_networkHttp2StreamEndRaw": { - "method": "net.http2_stream_end", - "translateArgs": false - }, - "_networkHttp2StreamPauseRaw": { - "method": "net.http2_stream_pause", - "translateArgs": false - }, - "_networkHttp2StreamPushStreamRaw": { - "method": "net.http2_stream_push_stream", - "translateArgs": false - }, - "_networkHttp2StreamRespondRaw": { - "method": "net.http2_stream_respond", - "translateArgs": false - }, - "_networkHttp2StreamRespondWithFileRaw": { - "method": "net.http2_stream_respond_with_file", - "translateArgs": false - }, - "_networkHttp2StreamResumeRaw": { - "method": "net.http2_stream_resume", - "translateArgs": false - }, - "_networkHttp2StreamWriteRaw": { - "method": "net.http2_stream_write", - "translateArgs": false - }, - "_networkHttpServerCloseRaw": { - "method": "net.http_close", - "translateArgs": false - }, - "_networkHttpServerListenRaw": { - "method": "net.http_listen", - "translateArgs": false - }, - "_networkHttpServerRequestRaw": { - "method": "net.http_request", - "translateArgs": false - }, - "_networkHttpServerRespondRaw": { - "method": "net.http_respond", - "translateArgs": false - }, - "_networkHttpServerWaitRaw": { - "method": "net.http_wait", - "translateArgs": false - }, - "_processKill": { - "method": "process.kill", - "translateArgs": false - }, - "_processSignalState": { - "method": "process.signal_state", - "translateArgs": false - }, - "_ptySetRawMode": { - "method": "__pty_set_raw_mode", - "translateArgs": false - }, - "_resolveModule": { - "method": "__resolve_module", - "translateArgs": false - }, - "_resolveModuleSync": { - "method": "__resolve_module", - "translateArgs": false - }, - "_scheduleTimer": { - "method": "__schedule_timer", - "translateArgs": false - }, - "_sqliteConstantsRaw": { - "method": "sqlite.constants", - "translateArgs": false - }, - "_sqliteDatabaseCheckpointRaw": { - "method": "sqlite.checkpoint", - "translateArgs": false - }, - "_sqliteDatabaseCloseRaw": { - "method": "sqlite.close", - "translateArgs": false - }, - "_sqliteDatabaseExecRaw": { - "method": "sqlite.exec", - "translateArgs": false - }, - "_sqliteDatabaseLocationRaw": { - "method": "sqlite.location", - "translateArgs": false - }, - "_sqliteDatabaseOpenRaw": { - "method": "sqlite.open", - "translateArgs": false - }, - "_sqliteDatabasePrepareRaw": { - "method": "sqlite.prepare", - "translateArgs": false - }, - "_sqliteDatabaseQueryRaw": { - "method": "sqlite.query", - "translateArgs": false - }, - "_sqliteStatementAllRaw": { - "method": "sqlite.statement.all", - "translateArgs": false - }, - "_sqliteStatementColumnsRaw": { - "method": "sqlite.statement.columns", - "translateArgs": false - }, - "_sqliteStatementFinalizeRaw": { - "method": "sqlite.statement.finalize", - "translateArgs": false - }, - "_sqliteStatementGetRaw": { - "method": "sqlite.statement.get", - "translateArgs": false - }, - "_sqliteStatementRunRaw": { - "method": "sqlite.statement.run", - "translateArgs": false - }, - "_sqliteStatementSetAllowBareNamedParametersRaw": { - "method": "sqlite.statement.setAllowBareNamedParameters", - "translateArgs": false - }, - "_sqliteStatementSetAllowUnknownNamedParametersRaw": { - "method": "sqlite.statement.setAllowUnknownNamedParameters", - "translateArgs": false - }, - "_sqliteStatementSetReadBigIntsRaw": { - "method": "sqlite.statement.setReadBigInts", - "translateArgs": false - }, - "_sqliteStatementSetReturnArraysRaw": { - "method": "sqlite.statement.setReturnArrays", - "translateArgs": false - }, - "_tlsGetCiphersRaw": { - "method": "tls.get_ciphers", - "translateArgs": false - }, - "_upgradeSocketDestroyRaw": { - "method": "net.upgrade_socket_destroy", - "translateArgs": false - }, - "_upgradeSocketEndRaw": { - "method": "net.upgrade_socket_end", - "translateArgs": false - }, - "_upgradeSocketWriteRaw": { - "method": "net.upgrade_socket_write", - "translateArgs": false - }, - "fs.closeSync": { - "method": "fs.closeSync", - "translateArgs": false - }, - "fs.fstatSync": { - "method": "fs.fstatSync", - "translateArgs": false - }, - "fs.futimesSync": { - "method": "fs.futimesSync", - "translateArgs": false - }, - "fs.openSync": { - "method": "fs.openSync", - "translateArgs": false - }, - "fs.readSync": { - "method": "fs.readSync", - "translateArgs": false - }, - "_fsReadRaw": { - "method": "fs.readSync", - "translateArgs": false - }, - "fs.writeSync": { - "method": "fs.writeSync", - "translateArgs": false - }, - "_fsWriteRaw": { - "method": "fs.writeSync", - "translateArgs": false - }, - "_fsWritevRaw": { - "method": "fs.writevSync", - "translateArgs": false - } - } -} diff --git a/crates/bridge/src/lib.rs b/crates/bridge/src/lib.rs index ef3502c79..11727c2a2 100644 --- a/crates/bridge/src/lib.rs +++ b/crates/bridge/src/lib.rs @@ -1,705 +1,3 @@ -#![forbid(unsafe_code)] +//! Compatibility shim for `agentos-bridge`. -//! Shared bridge contracts between the secure-exec kernel and execution planes. - -pub mod queue_tracker; - -use std::collections::BTreeMap; -use std::sync::OnceLock; -use std::time::{Duration, SystemTime}; - -use serde::Deserialize; - -/// Shared associated types for bridge implementations. -pub trait BridgeTypes { - type Error; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FileKind { - File, - Directory, - SymbolicLink, - Other, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FileMetadata { - pub mode: u32, - pub size: u64, - pub kind: FileKind, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DirectoryEntry { - pub name: String, - pub kind: FileKind, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PathRequest { - pub vm_id: String, - pub path: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ReadFileRequest { - pub vm_id: String, - pub path: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WriteFileRequest { - pub vm_id: String, - pub path: String, - pub contents: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ReadDirRequest { - pub vm_id: String, - pub path: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CreateDirRequest { - pub vm_id: String, - pub path: String, - pub recursive: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RenameRequest { - pub vm_id: String, - pub from_path: String, - pub to_path: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SymlinkRequest { - pub vm_id: String, - pub target_path: String, - pub link_path: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ChmodRequest { - pub vm_id: String, - pub path: String, - pub mode: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TruncateRequest { - pub vm_id: String, - pub path: String, - pub len: u64, -} - -pub trait FilesystemBridge: BridgeTypes { - fn read_file(&mut self, request: ReadFileRequest) -> Result, Self::Error>; - fn write_file(&mut self, request: WriteFileRequest) -> Result<(), Self::Error>; - fn stat(&mut self, request: PathRequest) -> Result; - fn lstat(&mut self, request: PathRequest) -> Result; - fn read_dir(&mut self, request: ReadDirRequest) -> Result, Self::Error>; - fn create_dir(&mut self, request: CreateDirRequest) -> Result<(), Self::Error>; - fn remove_file(&mut self, request: PathRequest) -> Result<(), Self::Error>; - fn remove_dir(&mut self, request: PathRequest) -> Result<(), Self::Error>; - fn rename(&mut self, request: RenameRequest) -> Result<(), Self::Error>; - fn symlink(&mut self, request: SymlinkRequest) -> Result<(), Self::Error>; - fn read_link(&mut self, request: PathRequest) -> Result; - fn chmod(&mut self, request: ChmodRequest) -> Result<(), Self::Error>; - fn truncate(&mut self, request: TruncateRequest) -> Result<(), Self::Error>; - fn exists(&mut self, request: PathRequest) -> Result; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PermissionVerdict { - Allow, - Deny, - Prompt, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PermissionDecision { - pub verdict: PermissionVerdict, - pub reason: Option, -} - -impl PermissionDecision { - pub fn allow() -> Self { - Self { - verdict: PermissionVerdict::Allow, - reason: None, - } - } - - pub fn deny(reason: impl Into) -> Self { - Self { - verdict: PermissionVerdict::Deny, - reason: Some(reason.into()), - } - } - - pub fn prompt(reason: impl Into) -> Self { - Self { - verdict: PermissionVerdict::Prompt, - reason: Some(reason.into()), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FilesystemAccess { - Read, - Write, - Stat, - ReadDir, - CreateDir, - Remove, - Rename, - Symlink, - ReadLink, - Chmod, - Truncate, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FilesystemPermissionRequest { - pub vm_id: String, - pub path: String, - pub access: FilesystemAccess, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum NetworkAccess { - Fetch, - Http, - Dns, - Listen, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct NetworkPermissionRequest { - pub vm_id: String, - pub access: NetworkAccess, - pub resource: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CommandPermissionRequest { - pub vm_id: String, - pub command: String, - pub args: Vec, - pub cwd: Option, - pub env: BTreeMap, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum EnvironmentAccess { - Read, - Write, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnvironmentPermissionRequest { - pub vm_id: String, - pub access: EnvironmentAccess, - pub key: String, - pub value: Option, -} - -pub trait PermissionBridge: BridgeTypes { - fn check_filesystem_access( - &mut self, - request: FilesystemPermissionRequest, - ) -> Result; - fn check_network_access( - &mut self, - request: NetworkPermissionRequest, - ) -> Result; - fn check_command_execution( - &mut self, - request: CommandPermissionRequest, - ) -> Result; - fn check_environment_access( - &mut self, - request: EnvironmentPermissionRequest, - ) -> Result; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FilesystemSnapshot { - pub format: String, - pub bytes: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct LoadFilesystemStateRequest { - pub vm_id: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FlushFilesystemStateRequest { - pub vm_id: String, - pub snapshot: FilesystemSnapshot, -} - -pub trait PersistenceBridge: BridgeTypes { - fn load_filesystem_state( - &mut self, - request: LoadFilesystemStateRequest, - ) -> Result, Self::Error>; - fn flush_filesystem_state( - &mut self, - request: FlushFilesystemStateRequest, - ) -> Result<(), Self::Error>; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ClockRequest { - pub vm_id: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ScheduleTimerRequest { - pub vm_id: String, - pub delay: Duration, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ScheduledTimer { - pub timer_id: String, - pub delay: Duration, -} - -pub trait ClockBridge: BridgeTypes { - fn wall_clock(&mut self, request: ClockRequest) -> Result; - fn monotonic_clock(&mut self, request: ClockRequest) -> Result; - fn schedule_timer( - &mut self, - request: ScheduleTimerRequest, - ) -> Result; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RandomBytesRequest { - pub vm_id: String, - pub len: usize, -} - -pub trait RandomBridge: BridgeTypes { - fn fill_random_bytes(&mut self, request: RandomBytesRequest) -> Result, Self::Error>; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LogLevel { - Trace, - Debug, - Info, - Warn, - Error, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct LogRecord { - pub vm_id: String, - pub level: LogLevel, - pub message: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DiagnosticRecord { - pub vm_id: String, - pub message: String, - pub fields: BTreeMap, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StructuredEventRecord { - pub vm_id: String, - pub name: String, - pub fields: BTreeMap, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LifecycleState { - Starting, - Ready, - Busy, - Terminated, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct LifecycleEventRecord { - pub vm_id: String, - pub state: LifecycleState, - pub detail: Option, -} - -pub trait EventBridge: BridgeTypes { - fn emit_structured_event(&mut self, event: StructuredEventRecord) -> Result<(), Self::Error>; - fn emit_diagnostic(&mut self, event: DiagnosticRecord) -> Result<(), Self::Error>; - fn emit_log(&mut self, event: LogRecord) -> Result<(), Self::Error>; - fn emit_lifecycle(&mut self, event: LifecycleEventRecord) -> Result<(), Self::Error>; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum GuestRuntime { - JavaScript, - WebAssembly, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CreateJavascriptContextRequest { - pub vm_id: String, - pub bootstrap_module: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CreateWasmContextRequest { - pub vm_id: String, - pub module_path: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct GuestContextHandle { - pub context_id: String, - pub runtime: GuestRuntime, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StartExecutionRequest { - pub vm_id: String, - pub context_id: String, - pub argv: Vec, - pub env: BTreeMap, - pub cwd: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StartedExecution { - pub execution_id: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExecutionHandleRequest { - pub vm_id: String, - pub execution_id: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WriteExecutionStdinRequest { - pub vm_id: String, - pub execution_id: String, - pub chunk: Vec, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ExecutionSignal { - Terminate, - Interrupt, - Kill, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct KillExecutionRequest { - pub vm_id: String, - pub execution_id: String, - pub signal: ExecutionSignal, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PollExecutionEventRequest { - pub vm_id: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct OutputChunk { - pub vm_id: String, - pub execution_id: String, - pub chunk: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExecutionExited { - pub vm_id: String, - pub execution_id: String, - pub exit_code: i32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct GuestKernelCall { - pub vm_id: String, - pub execution_id: String, - pub operation: String, - pub payload: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum SignalDispositionAction { - Default, - Ignore, - User, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SignalHandlerRegistration { - pub action: SignalDispositionAction, - pub mask: Vec, - pub flags: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExecutionSignalState { - pub vm_id: String, - pub execution_id: String, - pub signal: u32, - pub registration: SignalHandlerRegistration, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ExecutionEvent { - Stdout(OutputChunk), - Stderr(OutputChunk), - Exited(ExecutionExited), - GuestRequest(GuestKernelCall), - SignalState(ExecutionSignalState), -} - -pub trait ExecutionBridge: BridgeTypes { - fn create_javascript_context( - &mut self, - request: CreateJavascriptContextRequest, - ) -> Result; - fn create_wasm_context( - &mut self, - request: CreateWasmContextRequest, - ) -> Result; - fn start_execution( - &mut self, - request: StartExecutionRequest, - ) -> Result; - fn write_stdin(&mut self, request: WriteExecutionStdinRequest) -> Result<(), Self::Error>; - fn close_stdin(&mut self, request: ExecutionHandleRequest) -> Result<(), Self::Error>; - fn kill_execution(&mut self, request: KillExecutionRequest) -> Result<(), Self::Error>; - fn poll_execution_event( - &mut self, - request: PollExecutionEventRequest, - ) -> Result, Self::Error>; -} - -pub trait HostBridge: - FilesystemBridge - + PermissionBridge - + PersistenceBridge - + ClockBridge - + RandomBridge - + EventBridge - + ExecutionBridge -{ -} - -impl HostBridge for T where - T: FilesystemBridge - + PermissionBridge - + PersistenceBridge - + ClockBridge - + RandomBridge - + EventBridge - + ExecutionBridge -{ -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum BridgeCallConvention { - Sync, - Async, - SyncPromise, -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BridgeContractGroup { - pub convention: BridgeCallConvention, - #[serde(default)] - pub argument_types: Vec, - pub return_type: String, - pub names: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BridgeDispatchTarget { - pub method: String, - #[serde(default)] - pub translate_args: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BridgeContract { - pub version: u32, - pub groups: Vec, - #[serde(default)] - pub dispatch: BTreeMap, -} - -static BRIDGE_CONTRACT: OnceLock = OnceLock::new(); - -pub fn bridge_contract() -> &'static BridgeContract { - BRIDGE_CONTRACT.get_or_init(|| { - serde_json::from_str(include_str!("../bridge-contract.json")) - .expect("bridge-contract.json must be valid") - }) -} - -#[cfg(test)] -mod tests { - use super::{bridge_contract, BridgeCallConvention}; - - #[test] - fn bridge_contract_has_version_and_unique_method_names() { - let contract = bridge_contract(); - assert!( - contract.version > 0, - "bridge contract version must be positive" - ); - - let mut seen = std::collections::BTreeSet::new(); - for group in &contract.groups { - assert!( - !group.names.is_empty(), - "every bridge contract group must list at least one method" - ); - for name in &group.names { - assert!( - seen.insert(name.clone()), - "duplicate bridge contract method: {name}" - ); - } - } - } - - #[test] - fn bridge_contract_dispatch_targets_are_declared_methods() { - let contract = bridge_contract(); - let names: std::collections::BTreeSet<_> = contract - .groups - .iter() - .flat_map(|group| group.names.iter()) - .collect(); - - for name in contract.dispatch.keys() { - assert!( - names.contains(name), - "bridge dispatch target {name} must be listed in bridge contract names" - ); - } - - for required in [ - "_fsReadFile", - "_fsReadFileBinary", - "_fsLutimes", - "_fsLutimesAsync", - "fs.futimesSync", - "_cryptoHashDigest", - "_cryptoDiffieHellmanSessionDestroy", - "_netSocketConnectRaw", - "_kernelStdioWriteRaw", - "_ptySetRawMode", - ] { - assert!( - contract.dispatch.contains_key(required), - "bridge dispatch metadata missing for {required}" - ); - } - } - - #[test] - fn bridge_contract_lists_each_convention() { - let contract = bridge_contract(); - for convention in [ - BridgeCallConvention::Sync, - BridgeCallConvention::Async, - BridgeCallConvention::SyncPromise, - ] { - assert!( - contract - .groups - .iter() - .any(|group| group.convention == convention), - "missing bridge contract group for {convention:?}" - ); - } - } - - #[test] - fn bridge_contract_module_loading_signatures_match_runtime_calls() { - let contract = bridge_contract(); - - let find_group = |method: &str| { - contract - .groups - .iter() - .find(|group| group.names.iter().any(|name| name == method)) - .unwrap_or_else(|| panic!("missing bridge contract method {method}")) - }; - - let resolve_group = find_group("_resolveModule"); - assert_eq!(resolve_group.convention, BridgeCallConvention::SyncPromise); - assert_eq!( - resolve_group.argument_types, - vec![ - "specifier: string", - "fromDir: string", - "mode?: \"require\" | \"import\"" - ] - ); - assert_eq!( - resolve_group.names, - vec!["_resolveModule", "_resolveModuleSync"] - ); - - let load_group = find_group("_loadFile"); - assert_eq!(load_group.convention, BridgeCallConvention::SyncPromise); - assert_eq!(load_group.argument_types, vec!["path: string"]); - assert_eq!(load_group.names, vec!["_loadFile", "_loadFileSync"]); - - let format_group = find_group("_moduleFormat"); - assert_eq!(format_group.convention, BridgeCallConvention::SyncPromise); - assert_eq!(format_group.argument_types, vec!["filename: string"]); - assert_eq!( - format_group.return_type, - "\"module\" | \"commonjs\" | \"json\" | null" - ); - assert_eq!(format_group.names, vec!["_moduleFormat"]); - } - - #[test] - fn bridge_contract_includes_diffie_hellman_session_lifecycle_callbacks() { - let contract = bridge_contract(); - let crypto_group = contract - .groups - .iter() - .find(|group| { - group - .names - .iter() - .any(|name| name == "_cryptoDiffieHellmanSessionCreate") - }) - .expect("crypto bridge group"); - - for method in [ - "_cryptoDiffieHellmanSessionCreate", - "_cryptoDiffieHellmanSessionCall", - "_cryptoDiffieHellmanSessionDestroy", - ] { - assert!( - crypto_group.names.iter().any(|name| name == method), - "missing Diffie-Hellman session bridge callback {method}" - ); - } - } -} +pub use agentos_bridge::*; diff --git a/crates/bridge/src/queue_tracker.rs b/crates/bridge/src/queue_tracker.rs deleted file mode 100644 index f85d0dfd1..000000000 --- a/crates/bridge/src/queue_tracker.rs +++ /dev/null @@ -1,679 +0,0 @@ -//! Centralized bounded-queue usage tracker. -//! -//! secure-exec streams guest output through a *chain* of bounded queues: the -//! V8 -> host event channel, the sidecar stdout/stdin frame queues, and so on. -//! Each queue applies backpressure when full (it parks the producer until the -//! consumer drains) rather than crashing, but backpressure is invisible: a slow -//! host consumer silently stalls a session with nothing in the logs. -//! -//! This module gives that whole chain a single, inspectable home: -//! -//! * Every bounded queue registers a [`QueueGauge`] (with a stable name and its -//! capacity) in a process-global [`QueueRegistry`]. -//! * Producers report depth as they enqueue (either by an exact count for -//! manually-tracked queues via [`TrackedSyncSender`], or by sampling the live -//! depth of a Tokio channel via [`QueueGauge::observe_depth`]). -//! * When a queue crosses [`WARN_FILL_PERCENT`] of capacity the gauge emits a -//! single `warn!`, so "the consumer is falling behind" shows up *before* the -//! queue saturates and backpressure stalls the session. It re-arms once the -//! queue drains back below [`REARM_FILL_PERCENT`]. -//! * [`queue_snapshot`] returns the live depth / high-water / capacity of every -//! registered queue for debugging or a status endpoint. - -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::mpsc::{Receiver, RecvError, SendError, SyncSender, TrySendError}; -use std::sync::{Arc, Mutex, OnceLock, Weak}; - -/// Fill fraction (percent of capacity) at or above which a queue is considered -/// "near full" and emits a warning. Edge-triggered so a steadily-full queue logs -/// once, not on every enqueue. -pub const WARN_FILL_PERCENT: usize = 80; - -/// Fill fraction a near-full queue must drain back below before it will warn -/// again. The gap to [`WARN_FILL_PERCENT`] provides hysteresis so a queue -/// hovering at the threshold does not flap. -pub const REARM_FILL_PERCENT: usize = 50; - -/// What class of bounded resource a gauge tracks. Lets a snapshot / a host hook -/// group and reason about limits beyond just queues. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LimitCategory { - /// A bounded channel/buffer with enqueue/dequeue flow (the default). - Queue, - /// A saturating resource counter (fds, processes, sockets, bytes in use). - Resource, - /// A memory/heap envelope. - Memory, - /// A CPU or wall-clock execution budget. - Cpu, -} - -impl LimitCategory { - /// Stable lowercase tag for logs and snapshots. - pub fn as_str(self) -> &'static str { - match self { - LimitCategory::Queue => "queue", - LimitCategory::Resource => "resource", - LimitCategory::Memory => "memory", - LimitCategory::Cpu => "cpu", - } - } -} - -/// Stable catalog of tracked limits that may emit near-capacity or exhaustion -/// warnings. Keep `website/src/content/docs/docs/features/resource-limits.mdx` -/// in sync when adding, removing, or renaming variants so host-visible warning -/// names and the documented constants do not drift. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum TrackedLimit { - JavascriptEventChannel, - V8SessionFrames, - SidecarStdinFrames, - SidecarStdoutFrames, - CompletedSidecarResponses, - PendingProcessEvents, - PendingSidecarResponses, - OutboundSidecarRequests, - VmProcesses, - VmOpenFds, - VmPipes, - VmPtys, - VmSockets, - VmConnections, - VmSocketBufferedBytes, - VmSocketDatagramQueueLen, - VmFilesystemBytes, - VmInodes, - VmRecursiveFsDepth, - VmRecursiveFsEntries, - V8HeapBytes, - V8CpuTimeMs, - V8WallClockMs, - WasmFuelMs, - WasmMemoryBytes, -} - -impl TrackedLimit { - /// Stable lowercase tag emitted in logs, snapshots, and host - /// `limit_warning` events. - pub fn as_str(self) -> &'static str { - match self { - TrackedLimit::JavascriptEventChannel => "javascript_event_channel", - TrackedLimit::V8SessionFrames => "v8_session_frames", - TrackedLimit::SidecarStdinFrames => "sidecar_stdin_frames", - TrackedLimit::SidecarStdoutFrames => "sidecar_stdout_frames", - TrackedLimit::CompletedSidecarResponses => "completed_sidecar_responses", - TrackedLimit::PendingProcessEvents => "pending_process_events", - TrackedLimit::PendingSidecarResponses => "pending_sidecar_responses", - TrackedLimit::OutboundSidecarRequests => "outbound_sidecar_requests", - TrackedLimit::VmProcesses => "vm_processes", - TrackedLimit::VmOpenFds => "vm_open_fds", - TrackedLimit::VmPipes => "vm_pipes", - TrackedLimit::VmPtys => "vm_ptys", - TrackedLimit::VmSockets => "vm_sockets", - TrackedLimit::VmConnections => "vm_connections", - TrackedLimit::VmSocketBufferedBytes => "vm_socket_buffered_bytes", - TrackedLimit::VmSocketDatagramQueueLen => "vm_socket_datagram_queue_len", - TrackedLimit::VmFilesystemBytes => "vm_filesystem_bytes", - TrackedLimit::VmInodes => "vm_inodes", - TrackedLimit::VmRecursiveFsDepth => "vm_recursive_fs_depth", - TrackedLimit::VmRecursiveFsEntries => "vm_recursive_fs_entries", - TrackedLimit::V8HeapBytes => "v8_heap_bytes", - TrackedLimit::V8CpuTimeMs => "v8_cpu_time_ms", - TrackedLimit::V8WallClockMs => "v8_wall_clock_ms", - TrackedLimit::WasmFuelMs => "wasm_fuel_ms", - TrackedLimit::WasmMemoryBytes => "wasm_memory_bytes", - } - } - - pub fn category(self) -> LimitCategory { - match self { - TrackedLimit::JavascriptEventChannel - | TrackedLimit::V8SessionFrames - | TrackedLimit::SidecarStdinFrames - | TrackedLimit::SidecarStdoutFrames - | TrackedLimit::CompletedSidecarResponses - | TrackedLimit::PendingProcessEvents - | TrackedLimit::PendingSidecarResponses - | TrackedLimit::OutboundSidecarRequests => LimitCategory::Queue, - TrackedLimit::VmProcesses - | TrackedLimit::VmOpenFds - | TrackedLimit::VmPipes - | TrackedLimit::VmPtys - | TrackedLimit::VmSockets - | TrackedLimit::VmConnections - | TrackedLimit::VmSocketBufferedBytes - | TrackedLimit::VmSocketDatagramQueueLen - | TrackedLimit::VmFilesystemBytes - | TrackedLimit::VmInodes - | TrackedLimit::VmRecursiveFsDepth - | TrackedLimit::VmRecursiveFsEntries => LimitCategory::Resource, - TrackedLimit::V8HeapBytes | TrackedLimit::WasmMemoryBytes => LimitCategory::Memory, - TrackedLimit::V8CpuTimeMs | TrackedLimit::V8WallClockMs | TrackedLimit::WasmFuelMs => { - LimitCategory::Cpu - } - } - } -} - -/// A near-capacity event for one limit, delivered to the global warning sink at -/// the same edge as the `tracing::warn!`. This is the structured payload a host -/// hook (e.g. agentOS `onLimitWarning`) is built from. -#[derive(Debug, Clone)] -pub struct LimitWarning { - pub name: TrackedLimit, - pub category: LimitCategory, - pub observed: usize, - pub capacity: usize, - pub fill_percent: usize, -} - -type LimitWarningHandler = Arc; - -fn warning_handler_slot() -> &'static Mutex> { - static HANDLER: OnceLock>> = OnceLock::new(); - HANDLER.get_or_init(|| Mutex::new(None)) -} - -/// Install a process-global sink that is invoked on the same edge-triggered, -/// hysteresis-gated boundary as the `tracing::warn!` whenever a tracked limit -/// crosses [`WARN_FILL_PERCENT`]. The sidecar uses this to forward limit warnings -/// to the host as structured events (the `onLimitWarning` hook). The handler must -/// be cheap and non-blocking; it runs on the producer's thread. -pub fn set_limit_warning_handler(handler: Box) { - if let Ok(mut slot) = warning_handler_slot().lock() { - *slot = Some(Arc::from(handler)); - } -} - -fn dispatch_warning(warning: &LimitWarning) { - // Clone the handler Arc out and DROP the registry mutex before invoking it, - // so the handler never runs while we hold the global lock. The sink can be - // reached while a kernel lock is held (e.g. fd_tables -> warning_mutex -> - // handler); keeping the invocation outside the mutex avoids a lock-order - // hazard if the handler ever does non-trivial work. - let handler = match warning_handler_slot().lock() { - Ok(slot) => slot.as_ref().cloned(), - Err(_) => None, - }; - if let Some(handler) = handler { - handler(warning); - } -} - -/// Emit a structured/logged warning for a limit that has already been exhausted. -/// Use this for runtime caps such as CPU or heap exhaustion where there is no -/// continuously sampled queue depth to observe before the terminal edge. -pub fn warn_limit_exhausted(name: TrackedLimit, observed: usize, capacity: usize) { - let fill_percent = observed - .saturating_mul(100) - .checked_div(capacity) - .unwrap_or(0); - let category = name.category(); - tracing::warn!( - limit = name.as_str(), - category = category.as_str(), - observed, - capacity, - fill_percent, - "bounded limit exhausted" - ); - dispatch_warning(&LimitWarning { - name, - category, - observed, - capacity, - fill_percent, - }); -} - -/// Live usage gauge for a single bounded queue. -/// -/// Cloneable handles share one gauge through an [`Arc`]; the registry keeps a -/// [`Weak`] so a gauge is auto-pruned from snapshots once its queue is dropped. -#[derive(Debug)] -pub struct QueueGauge { - name: TrackedLimit, - category: LimitCategory, - capacity: usize, - depth: AtomicUsize, - high_water: AtomicUsize, - warned: AtomicBool, -} - -impl QueueGauge { - fn new(name: TrackedLimit, capacity: usize, category: LimitCategory) -> Self { - Self { - name, - category, - capacity, - depth: AtomicUsize::new(0), - high_water: AtomicUsize::new(0), - warned: AtomicBool::new(false), - } - } - - /// Stable limit name (used in logs and snapshots). - pub fn name(&self) -> TrackedLimit { - self.name - } - - /// The class of bounded resource this gauge tracks. - pub fn category(&self) -> LimitCategory { - self.category - } - - /// Configured queue capacity (slots). `0` means unbounded / untracked. - pub fn capacity(&self) -> usize { - self.capacity - } - - /// Current observed depth. - pub fn depth(&self) -> usize { - self.depth.load(Ordering::Acquire) - } - - /// Highest depth observed over the gauge's lifetime. - pub fn high_water(&self) -> usize { - self.high_water.load(Ordering::Acquire) - } - - /// Fill fraction (0–100) at the given depth. Saturates rather than dividing - /// by zero for untracked (capacity 0) queues. - fn fill_percent(&self, depth: usize) -> usize { - depth - .saturating_mul(100) - .checked_div(self.capacity) - .unwrap_or(0) - } - - /// Record a new depth: refresh the high-water mark and emit an edge-triggered - /// near-capacity warning (or recovery debug line). - fn evaluate(&self, depth: usize) { - self.high_water.fetch_max(depth, Ordering::AcqRel); - if self.capacity == 0 { - return; - } - let percent = self.fill_percent(depth); - if percent >= WARN_FILL_PERCENT { - if !self.warned.swap(true, Ordering::AcqRel) { - tracing::warn!( - limit = self.name.as_str(), - category = self.category.as_str(), - observed = depth, - capacity = self.capacity, - fill_percent = percent, - "bounded limit near capacity" - ); - // Same edge as the log: notify the structured warning sink so the - // host can surface it (e.g. an onLimitWarning hook). Edge-triggered - // + hysteresis keep this from firing more than once per crossing. - dispatch_warning(&LimitWarning { - name: self.name, - category: self.category, - observed: depth, - capacity: self.capacity, - fill_percent: percent, - }); - } - } else if percent <= REARM_FILL_PERCENT && self.warned.swap(false, Ordering::AcqRel) { - tracing::debug!( - limit = self.name.as_str(), - category = self.category.as_str(), - depth, - capacity = self.capacity, - fill_percent = percent, - "bounded limit drained back below threshold" - ); - } - } - - /// Report the queue's exact current depth (for queues whose backing channel - /// exposes its live length, e.g. a Tokio mpsc via `max_capacity - capacity`). - pub fn observe_depth(&self, depth: usize) { - self.depth.store(depth, Ordering::Release); - self.evaluate(depth); - } - - /// Account for one item entering the queue (for manually-tracked queues). - pub fn record_enqueue(&self) { - let depth = self.depth.fetch_add(1, Ordering::AcqRel) + 1; - self.evaluate(depth); - } - - /// Account for one item leaving the queue. Saturates at zero so a stray - /// dequeue can never underflow the depth counter. Re-evaluates so a gauge - /// that latched "warned" while full re-arms once the queue drains back below - /// the re-arm threshold, even if the producer has since gone idle. - pub fn record_dequeue(&self) { - let mut current = self.depth.load(Ordering::Acquire); - loop { - if current == 0 { - return; - } - match self.depth.compare_exchange_weak( - current, - current - 1, - Ordering::AcqRel, - Ordering::Acquire, - ) { - Ok(_) => { - self.evaluate(current - 1); - break; - } - Err(actual) => current = actual, - } - } - } -} - -/// Immutable view of a tracked limit's usage, returned by [`queue_snapshot`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct QueueSnapshot { - pub name: TrackedLimit, - pub category: LimitCategory, - pub depth: usize, - pub high_water: usize, - pub capacity: usize, - pub fill_percent: usize, -} - -/// Process-global registry of every live [`QueueGauge`]. -#[derive(Default)] -pub struct QueueRegistry { - gauges: Mutex>>, -} - -impl QueueRegistry { - /// The shared registry. All `secure-exec` bounded queues register here so - /// their usage can be inspected from one place. - pub fn global() -> &'static QueueRegistry { - static REGISTRY: OnceLock = OnceLock::new(); - REGISTRY.get_or_init(QueueRegistry::default) - } - - /// Register a new bounded limit and return its gauge. Dropping the returned - /// `Arc` (and all clones) removes the limit from future snapshots. - pub fn register(&self, name: TrackedLimit, capacity: usize) -> Arc { - let category = name.category(); - let gauge = Arc::new(QueueGauge::new(name, capacity, category)); - let mut gauges = self.gauges.lock().expect("queue registry mutex poisoned"); - gauges.retain(|weak| weak.strong_count() > 0); - gauges.push(Arc::downgrade(&gauge)); - gauge - } - - /// Snapshot the live usage of every registered queue, pruning dead entries. - pub fn snapshot(&self) -> Vec { - let mut gauges = self.gauges.lock().expect("queue registry mutex poisoned"); - gauges.retain(|weak| weak.strong_count() > 0); - gauges - .iter() - .filter_map(Weak::upgrade) - .map(|gauge| { - let depth = gauge.depth(); - QueueSnapshot { - name: gauge.name(), - category: gauge.category(), - depth, - high_water: gauge.high_water(), - capacity: gauge.capacity(), - fill_percent: gauge.fill_percent(depth), - } - }) - .collect() - } -} - -/// Register a bounded queue (the [`LimitCategory::Queue`] case) with the global -/// registry. Convenience over [`QueueRegistry::global`] + [`QueueRegistry::register`]. -pub fn register_queue(name: TrackedLimit, capacity: usize) -> Arc { - debug_assert_eq!(name.category(), LimitCategory::Queue); - QueueRegistry::global().register(name, capacity) -} - -/// Register a non-queue bounded limit (a saturating resource or memory envelope) -/// with the global registry, so it shares the same approach-warning + snapshot -/// machinery as queues. Observe usage with [`QueueGauge::observe_depth`]. -pub fn register_limit(name: TrackedLimit, capacity: usize) -> Arc { - QueueRegistry::global().register(name, capacity) -} - -/// Snapshot every registered queue from the global registry. -pub fn queue_snapshot() -> Vec { - QueueRegistry::global().snapshot() -} - -/// Emit a `debug!` line for every registered queue. Useful for an on-demand dump -/// of the queue chain when diagnosing a stall. -pub fn log_queue_snapshot() { - for stat in queue_snapshot() { - tracing::debug!( - limit = stat.name.as_str(), - category = stat.category.as_str(), - depth = stat.depth, - high_water = stat.high_water, - capacity = stat.capacity, - fill_percent = stat.fill_percent, - "limit usage" - ); - } -} - -/// A `std::sync::mpsc::SyncSender` that feeds a [`QueueGauge`] as items flow -/// through it, so a queue whose backing channel cannot report its own length -/// still participates in the centralized tracker. -/// -/// `send` keeps the underlying blocking-backpressure semantics; it just records -/// the enqueue first so near-capacity warnings fire as the queue fills. -#[derive(Debug)] -pub struct TrackedSyncSender { - inner: SyncSender, - gauge: Arc, -} - -impl Clone for TrackedSyncSender { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - gauge: Arc::clone(&self.gauge), - } - } -} - -impl TrackedSyncSender { - /// Blocking send: record the enqueue, then hand off to the bounded channel - /// (which parks the caller until a slot is free: clean backpressure). - pub fn send(&self, value: T) -> Result<(), SendError> { - self.gauge.record_enqueue(); - self.inner.send(value) - } - - /// Non-blocking send: record the enqueue only on success. Lets a caller with - /// its own deadline poll instead of parking indefinitely on a full queue. - pub fn try_send(&self, value: T) -> Result<(), TrySendError> { - match self.inner.try_send(value) { - Ok(()) => { - self.gauge.record_enqueue(); - Ok(()) - } - Err(error) => Err(error), - } - } - - /// The gauge backing this sender. - pub fn gauge(&self) -> &Arc { - &self.gauge - } -} - -/// Receiver half of a [`tracked_sync_channel`]; records a dequeue for every -/// item it yields so the gauge depth tracks the real backlog. -#[derive(Debug)] -pub struct TrackedReceiver { - inner: Receiver, - gauge: Arc, -} - -impl TrackedReceiver { - /// Blocking receive that decrements the gauge for the item it returns. - pub fn recv(&self) -> Result { - let value = self.inner.recv()?; - self.gauge.record_dequeue(); - Ok(value) - } -} - -/// Create a bounded `std::sync::mpsc` sync-channel whose depth is tracked by a -/// registered [`QueueGauge`]. Drop-in for `std::sync::mpsc::sync_channel` plus -/// centralized usage tracking + near-capacity warnings. -pub fn tracked_sync_channel( - name: TrackedLimit, - capacity: usize, -) -> (TrackedSyncSender, TrackedReceiver) { - let (tx, rx) = std::sync::mpsc::sync_channel(capacity); - let gauge = register_queue(name, capacity); - ( - TrackedSyncSender { - inner: tx, - gauge: Arc::clone(&gauge), - }, - TrackedReceiver { inner: rx, gauge }, - ) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn gauge_tracks_depth_and_high_water() { - let gauge = QueueGauge::new( - TrackedLimit::JavascriptEventChannel, - 10, - LimitCategory::Queue, - ); - assert_eq!(gauge.depth(), 0); - gauge.record_enqueue(); - gauge.record_enqueue(); - assert_eq!(gauge.depth(), 2); - assert_eq!(gauge.high_water(), 2); - gauge.record_dequeue(); - assert_eq!(gauge.depth(), 1); - // High-water never regresses. - assert_eq!(gauge.high_water(), 2); - // Dequeue never underflows below zero. - gauge.record_dequeue(); - gauge.record_dequeue(); - assert_eq!(gauge.depth(), 0); - } - - #[test] - fn gauge_warn_flag_is_edge_triggered_with_hysteresis() { - let gauge = QueueGauge::new(TrackedLimit::V8SessionFrames, 10, LimitCategory::Queue); - // Below 80%: not warned. - gauge.observe_depth(7); - assert!(!gauge.warned.load(Ordering::Acquire)); - // Cross 80%: warned. - gauge.observe_depth(8); - assert!(gauge.warned.load(Ordering::Acquire)); - // Still near full: stays armed (single warning, not re-fired). - gauge.observe_depth(9); - assert!(gauge.warned.load(Ordering::Acquire)); - // Drain to <=50%: re-arms. - gauge.observe_depth(5); - assert!(!gauge.warned.load(Ordering::Acquire)); - } - - #[test] - fn gauge_rearms_on_dequeue_drain() { - // record_enqueue/record_dequeue gauges (TrackedSyncSender/Receiver) must - // also re-arm as they drain, not only stay latched after the producer idles. - let gauge = QueueGauge::new(TrackedLimit::SidecarStdoutFrames, 10, LimitCategory::Queue); - for _ in 0..9 { - gauge.record_enqueue(); // climbs to 90% -> warned - } - assert_eq!(gauge.depth(), 9); - assert!(gauge.warned.load(Ordering::Acquire)); - for _ in 0..6 { - gauge.record_dequeue(); // drains to 30% (<=50%) -> re-arm on dequeue - } - assert_eq!(gauge.depth(), 3); - assert!(!gauge.warned.load(Ordering::Acquire)); - } - - #[test] - fn tracked_channel_reports_usage_through_registry() { - let (tx, rx) = tracked_sync_channel::(TrackedLimit::SidecarStdoutFrames, 4); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - - let snapshot = queue_snapshot(); - let entry = snapshot - .iter() - .find(|stat| stat.name == TrackedLimit::SidecarStdoutFrames) - .expect("registered queue should appear in snapshot"); - assert_eq!(entry.depth, 2); - assert_eq!(entry.capacity, 4); - assert_eq!(entry.high_water, 2); - assert_eq!(entry.fill_percent, 50); - assert_eq!(entry.category, LimitCategory::Queue); - - assert_eq!(rx.recv().unwrap(), 1); - assert_eq!(tx.gauge().depth(), 1); - - // Dropping the channel removes it from later snapshots. - drop(tx); - drop(rx); - assert!(queue_snapshot() - .iter() - .all(|stat| stat.name != TrackedLimit::SidecarStdoutFrames)); - } - - #[test] - fn warning_sink_fires_once_per_crossing() { - let captured: Arc>> = Arc::new(Mutex::new(Vec::new())); - let sink = Arc::clone(&captured); - // The handler is global; filter by our unique name so a gauge from a - // concurrently-running test can never pollute this assertion. - set_limit_warning_handler(Box::new(move |warning| { - if warning.name == TrackedLimit::VmPipes { - sink.lock().expect("sink mutex").push(warning.clone()); - } - })); - - let gauge = register_limit(TrackedLimit::VmPipes, 10); - gauge.observe_depth(7); // below 80%: no warning - assert!(captured.lock().unwrap().is_empty()); - gauge.observe_depth(9); // crosses 80%: fires once - gauge.observe_depth(10); // still near full: must NOT re-fire (edge-triggered) - - let warnings = captured.lock().unwrap(); - assert_eq!( - warnings.len(), - 1, - "warning sink must fire once per crossing" - ); - assert_eq!(warnings[0].category, LimitCategory::Resource); - assert_eq!(warnings[0].capacity, 10); - assert!(warnings[0].fill_percent >= WARN_FILL_PERCENT); - } - - #[test] - fn exhausted_warning_sink_fires_immediately() { - let captured: Arc>> = Arc::new(Mutex::new(Vec::new())); - let sink = Arc::clone(&captured); - set_limit_warning_handler(Box::new(move |warning| { - if warning.name == TrackedLimit::V8CpuTimeMs { - sink.lock().expect("sink mutex").push(warning.clone()); - } - })); - - warn_limit_exhausted(TrackedLimit::V8CpuTimeMs, 30_000, 30_000); - - let warnings = captured.lock().unwrap(); - assert_eq!(warnings.len(), 1); - assert_eq!(warnings[0].category, LimitCategory::Cpu); - assert_eq!(warnings[0].fill_percent, 100); - } -} diff --git a/crates/bridge/tests/bridge.rs b/crates/bridge/tests/bridge.rs deleted file mode 100644 index 4c17d21a3..000000000 --- a/crates/bridge/tests/bridge.rs +++ /dev/null @@ -1,339 +0,0 @@ -mod support; - -use secure_exec_bridge::{ - BridgeTypes, ClockRequest, CommandPermissionRequest, CreateDirRequest, - CreateJavascriptContextRequest, CreateWasmContextRequest, DiagnosticRecord, DirectoryEntry, - EnvironmentAccess, EnvironmentPermissionRequest, ExecutionEvent, ExecutionHandleRequest, - ExecutionSignal, FileKind, FilesystemAccess, FilesystemPermissionRequest, FilesystemSnapshot, - FlushFilesystemStateRequest, GuestKernelCall, GuestRuntime, HostBridge, LifecycleEventRecord, - LifecycleState, LoadFilesystemStateRequest, LogLevel, LogRecord, NetworkAccess, - NetworkPermissionRequest, PathRequest, PermissionDecision, PollExecutionEventRequest, - RandomBytesRequest, ReadDirRequest, ReadFileRequest, RenameRequest, ScheduleTimerRequest, - StartExecutionRequest, StructuredEventRecord, SymlinkRequest, TruncateRequest, - WriteExecutionStdinRequest, WriteFileRequest, -}; -use std::collections::BTreeMap; -use std::fmt::Debug; -use std::time::{Duration, SystemTime}; -use support::RecordingBridge; - -fn assert_host_bridge(bridge: &mut B) -where - B: HostBridge, - ::Error: Debug, -{ - let contents = bridge - .read_file(ReadFileRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - }) - .expect("read file"); - assert_eq!(contents, b"hello".to_vec()); - - bridge - .write_file(WriteFileRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/output.txt"), - contents: b"world".to_vec(), - }) - .expect("write file"); - assert!(bridge - .exists(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/output.txt"), - }) - .expect("exists after write")); - - let directory = bridge - .read_dir(ReadDirRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace"), - }) - .expect("read dir"); - assert_eq!(directory.len(), 1); - - let metadata = bridge - .stat(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - }) - .expect("stat"); - assert_eq!(metadata.kind, FileKind::File); - assert_eq!(metadata.size, 5); - - bridge - .create_dir(CreateDirRequest { - vm_id: String::from("vm-1"), - path: String::from("/tmp"), - recursive: true, - }) - .expect("create dir"); - bridge - .rename(RenameRequest { - vm_id: String::from("vm-1"), - from_path: String::from("/workspace/output.txt"), - to_path: String::from("/workspace/output-renamed.txt"), - }) - .expect("rename"); - bridge - .symlink(SymlinkRequest { - vm_id: String::from("vm-1"), - target_path: String::from("/workspace/input.txt"), - link_path: String::from("/workspace/input-link.txt"), - }) - .expect("symlink"); - assert_eq!( - bridge - .read_link(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input-link.txt"), - }) - .expect("readlink"), - "/workspace/input.txt" - ); - bridge - .truncate(TruncateRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - len: 2, - }) - .expect("truncate"); - assert_eq!( - bridge - .read_file(ReadFileRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - }) - .expect("read after truncate"), - b"he".to_vec() - ); - - assert_eq!( - bridge - .check_filesystem_access(FilesystemPermissionRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - access: FilesystemAccess::Read, - }) - .expect("filesystem permission"), - PermissionDecision::allow() - ); - assert_eq!( - bridge - .check_network_access(NetworkPermissionRequest { - vm_id: String::from("vm-1"), - access: NetworkAccess::Fetch, - resource: String::from("https://example.test"), - }) - .expect("network permission"), - PermissionDecision::allow() - ); - assert_eq!( - bridge - .check_command_execution(CommandPermissionRequest { - vm_id: String::from("vm-1"), - command: String::from("node"), - args: vec![String::from("--version")], - cwd: Some(String::from("/workspace")), - env: BTreeMap::new(), - }) - .expect("command permission"), - PermissionDecision::allow() - ); - assert_eq!( - bridge - .check_environment_access(EnvironmentPermissionRequest { - vm_id: String::from("vm-1"), - access: EnvironmentAccess::Read, - key: String::from("PATH"), - value: None, - }) - .expect("env permission"), - PermissionDecision::allow() - ); - - assert_eq!( - bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: String::from("vm-1"), - }) - .expect("load snapshot") - .expect("snapshot present") - .format, - "tar" - ); - bridge - .flush_filesystem_state(FlushFilesystemStateRequest { - vm_id: String::from("vm-2"), - snapshot: FilesystemSnapshot { - format: String::from("tar"), - bytes: vec![9, 9, 9], - }, - }) - .expect("flush snapshot"); - assert_eq!( - bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: String::from("vm-2"), - }) - .expect("load flushed snapshot") - .expect("flushed snapshot present") - .bytes, - vec![9, 9, 9] - ); - - assert_eq!( - bridge - .wall_clock(ClockRequest { - vm_id: String::from("vm-1"), - }) - .expect("wall clock"), - SystemTime::UNIX_EPOCH + Duration::from_secs(1_710_000_000) - ); - assert_eq!( - bridge - .monotonic_clock(ClockRequest { - vm_id: String::from("vm-1"), - }) - .expect("monotonic clock"), - Duration::from_millis(42) - ); - assert_eq!( - bridge - .schedule_timer(ScheduleTimerRequest { - vm_id: String::from("vm-1"), - delay: Duration::from_millis(5), - }) - .expect("schedule timer") - .timer_id, - "timer-1" - ); - assert_eq!( - bridge - .fill_random_bytes(RandomBytesRequest { - vm_id: String::from("vm-1"), - len: 4, - }) - .expect("random bytes"), - vec![0xA5; 4] - ); - - bridge - .emit_log(LogRecord { - vm_id: String::from("vm-1"), - level: LogLevel::Info, - message: String::from("started"), - }) - .expect("emit log"); - bridge - .emit_diagnostic(DiagnosticRecord { - vm_id: String::from("vm-1"), - message: String::from("healthy"), - fields: BTreeMap::from([(String::from("uptime_ms"), String::from("10"))]), - }) - .expect("emit diagnostic"); - bridge - .emit_structured_event(StructuredEventRecord { - vm_id: String::from("vm-1"), - name: String::from("process.stdout"), - fields: BTreeMap::from([(String::from("fd"), String::from("1"))]), - }) - .expect("emit structured event"); - bridge - .emit_lifecycle(LifecycleEventRecord { - vm_id: String::from("vm-1"), - state: LifecycleState::Ready, - detail: Some(String::from("booted")), - }) - .expect("emit lifecycle"); - - let js_context = bridge - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-1"), - bootstrap_module: Some(String::from("@secure-exec/bootstrap")), - }) - .expect("create js context"); - assert_eq!(js_context.runtime, GuestRuntime::JavaScript); - - let wasm_context = bridge - .create_wasm_context(CreateWasmContextRequest { - vm_id: String::from("vm-1"), - module_path: Some(String::from("/workspace/module.wasm")), - }) - .expect("create wasm context"); - assert_eq!(wasm_context.runtime, GuestRuntime::WebAssembly); - - let execution = bridge - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-1"), - context_id: js_context.context_id, - argv: vec![String::from("index.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start execution"); - assert_eq!(execution.execution_id, "exec-1"); - - bridge - .write_stdin(WriteExecutionStdinRequest { - vm_id: String::from("vm-1"), - execution_id: execution.execution_id.clone(), - chunk: b"input".to_vec(), - }) - .expect("write stdin"); - bridge - .close_stdin(ExecutionHandleRequest { - vm_id: String::from("vm-1"), - execution_id: execution.execution_id.clone(), - }) - .expect("close stdin"); - bridge - .kill_execution(secure_exec_bridge::KillExecutionRequest { - vm_id: String::from("vm-1"), - execution_id: execution.execution_id, - signal: ExecutionSignal::Terminate, - }) - .expect("kill execution"); - - match bridge - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-1"), - }) - .expect("poll execution event") - { - Some(ExecutionEvent::GuestRequest(event)) => { - assert_eq!(event.operation, "fs.read"); - } - other => panic!("unexpected execution event: {other:?}"), - } - - let _ = wasm_context; -} - -#[test] -fn host_bridge_traits_are_method_oriented_and_composable() { - let mut bridge = RecordingBridge::default(); - bridge.seed_file("/workspace/input.txt", b"hello".to_vec()); - bridge.seed_directory( - "/workspace", - vec![DirectoryEntry { - name: String::from("input.txt"), - kind: FileKind::File, - }], - ); - bridge.seed_snapshot( - "vm-1", - FilesystemSnapshot { - format: String::from("tar"), - bytes: vec![1, 2, 3], - }, - ); - bridge.push_execution_event(ExecutionEvent::GuestRequest(GuestKernelCall { - vm_id: String::from("vm-1"), - execution_id: String::from("exec-seeded"), - operation: String::from("fs.read"), - payload: b"{}".to_vec(), - })); - - assert_host_bridge(&mut bridge); -} diff --git a/crates/bridge/tests/support.rs b/crates/bridge/tests/support.rs deleted file mode 100644 index 75199c8e5..000000000 --- a/crates/bridge/tests/support.rs +++ /dev/null @@ -1,493 +0,0 @@ -use secure_exec_bridge::{ - BridgeTypes, ChmodRequest, ClockBridge, ClockRequest, CommandPermissionRequest, - CreateDirRequest, CreateJavascriptContextRequest, CreateWasmContextRequest, DiagnosticRecord, - DirectoryEntry, EnvironmentPermissionRequest, EventBridge, ExecutionBridge, ExecutionEvent, - ExecutionHandleRequest, FileKind, FileMetadata, FilesystemBridge, FilesystemPermissionRequest, - FilesystemSnapshot, FlushFilesystemStateRequest, GuestContextHandle, GuestRuntime, - KillExecutionRequest, LifecycleEventRecord, LoadFilesystemStateRequest, LogRecord, - NetworkPermissionRequest, PathRequest, PermissionBridge, PermissionDecision, PersistenceBridge, - PollExecutionEventRequest, RandomBridge, RandomBytesRequest, ReadDirRequest, ReadFileRequest, - RenameRequest, ScheduleTimerRequest, ScheduledTimer, StartExecutionRequest, StartedExecution, - StructuredEventRecord, SymlinkRequest, TruncateRequest, WriteExecutionStdinRequest, - WriteFileRequest, -}; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::time::{Duration, SystemTime}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StubError { - message: String, -} - -impl StubError { - pub fn new(message: impl Into) -> Self { - Self { - message: message.into(), - } - } - - fn missing(kind: &'static str, key: &str) -> Self { - Self { - message: format!("missing {kind}: {key}"), - } - } - - fn invalid(kind: &'static str, key: &str) -> Self { - Self { - message: format!("invalid {kind}: {key}"), - } - } -} - -#[derive(Debug)] -pub struct RecordingBridge { - next_context_id: usize, - next_execution_id: usize, - next_timer_id: usize, - files: BTreeMap>, - directories: BTreeMap>, - symlinks: BTreeMap, - snapshots: BTreeMap, - execution_events: VecDeque, - permission_responses: VecDeque>, - worker_create_errors: VecDeque, - execution_start_errors: VecDeque, - pub filesystem_permission_requests: Vec, - pub permission_checks: Vec, - pub log_events: Vec, - pub diagnostic_events: Vec, - pub structured_events: Vec, - pub lifecycle_events: Vec, - pub scheduled_timers: Vec, - pub stdin_writes: Vec, - pub closed_executions: Vec, - pub killed_executions: Vec, - #[allow(dead_code)] - pub browser_worker_spawns: Vec>, - #[allow(dead_code)] - pub terminated_workers: Vec<(String, String, String)>, -} - -impl Default for RecordingBridge { - fn default() -> Self { - let mut directories = BTreeMap::new(); - directories.insert(String::from("/"), Vec::new()); - - Self { - next_context_id: 1, - next_execution_id: 1, - next_timer_id: 1, - files: BTreeMap::new(), - directories, - symlinks: BTreeMap::new(), - snapshots: BTreeMap::new(), - execution_events: VecDeque::new(), - permission_responses: VecDeque::new(), - worker_create_errors: VecDeque::new(), - execution_start_errors: VecDeque::new(), - filesystem_permission_requests: Vec::new(), - permission_checks: Vec::new(), - log_events: Vec::new(), - diagnostic_events: Vec::new(), - structured_events: Vec::new(), - lifecycle_events: Vec::new(), - scheduled_timers: Vec::new(), - stdin_writes: Vec::new(), - closed_executions: Vec::new(), - killed_executions: Vec::new(), - browser_worker_spawns: Vec::new(), - terminated_workers: Vec::new(), - } - } -} - -#[allow(dead_code)] -impl RecordingBridge { - pub fn seed_file(&mut self, path: impl Into, contents: impl Into>) { - self.files.insert(path.into(), contents.into()); - } - - pub fn seed_directory(&mut self, path: impl Into, entries: Vec) { - self.directories.insert(path.into(), entries); - } - - pub fn seed_snapshot(&mut self, vm_id: impl Into, snapshot: FilesystemSnapshot) { - self.snapshots.insert(vm_id.into(), snapshot); - } - - pub fn push_execution_event(&mut self, event: ExecutionEvent) { - self.execution_events.push_back(event); - } - - pub fn push_permission_decision(&mut self, decision: PermissionDecision) { - self.permission_responses.push_back(Ok(decision)); - } - - pub fn push_permission_error(&mut self, message: impl Into) { - self.permission_responses - .push_back(Err(StubError::new(message))); - } - - pub fn push_worker_create_error(&mut self, message: impl Into) { - self.worker_create_errors.push_back(StubError::new(message)); - } - - pub fn push_execution_start_error(&mut self, message: impl Into) { - self.execution_start_errors - .push_back(StubError::new(message)); - } - - pub fn next_worker_create_error(&mut self) -> Option { - self.worker_create_errors.pop_front() - } - - fn next_permission_response(&mut self) -> Result { - self.permission_responses - .pop_front() - .unwrap_or_else(|| Ok(PermissionDecision::allow())) - } - - fn metadata_for_path(&self, path: &str, follow_links: bool) -> Result { - let mut current_path = path.to_owned(); - let mut seen_links = BTreeSet::new(); - - if follow_links { - while let Some(target) = self.symlinks.get(¤t_path) { - if !seen_links.insert(current_path.clone()) { - return Err(StubError::invalid("symlink cycle", ¤t_path)); - } - current_path = target.clone(); - } - } else if self.symlinks.contains_key(¤t_path) { - return Ok(FileMetadata { - mode: 0o777, - size: 0, - kind: FileKind::SymbolicLink, - }); - } - - if let Some(bytes) = self.files.get(¤t_path) { - return Ok(FileMetadata { - mode: 0o644, - size: bytes.len() as u64, - kind: FileKind::File, - }); - } - - if let Some(entries) = self.directories.get(¤t_path) { - return Ok(FileMetadata { - mode: 0o755, - size: entries.len() as u64, - kind: FileKind::Directory, - }); - } - - Err(StubError::missing("path", ¤t_path)) - } -} - -impl BridgeTypes for RecordingBridge { - type Error = StubError; -} - -impl FilesystemBridge for RecordingBridge { - fn read_file(&mut self, request: ReadFileRequest) -> Result, Self::Error> { - self.files - .get(&request.path) - .cloned() - .ok_or_else(|| StubError::missing("file", &request.path)) - } - - fn write_file(&mut self, request: WriteFileRequest) -> Result<(), Self::Error> { - self.files.insert(request.path, request.contents); - Ok(()) - } - - fn stat(&mut self, request: PathRequest) -> Result { - self.metadata_for_path(&request.path, true) - } - - fn lstat(&mut self, request: PathRequest) -> Result { - self.metadata_for_path(&request.path, false) - } - - fn read_dir(&mut self, request: ReadDirRequest) -> Result, Self::Error> { - Ok(self - .directories - .get(&request.path) - .cloned() - .unwrap_or_default()) - } - - fn create_dir(&mut self, request: CreateDirRequest) -> Result<(), Self::Error> { - self.directories.entry(request.path).or_default(); - Ok(()) - } - - fn remove_file(&mut self, request: PathRequest) -> Result<(), Self::Error> { - self.files.remove(&request.path); - Ok(()) - } - - fn remove_dir(&mut self, request: PathRequest) -> Result<(), Self::Error> { - self.directories.remove(&request.path); - Ok(()) - } - - fn rename(&mut self, request: RenameRequest) -> Result<(), Self::Error> { - if let Some(bytes) = self.files.remove(&request.from_path) { - self.files.insert(request.to_path, bytes); - return Ok(()); - } - - if let Some(target) = self.symlinks.remove(&request.from_path) { - self.symlinks.insert(request.to_path, target); - return Ok(()); - } - - if let Some(entries) = self.directories.remove(&request.from_path) { - self.directories.insert(request.to_path, entries); - return Ok(()); - } - - Err(StubError::missing("rename source", &request.from_path)) - } - - fn symlink(&mut self, request: SymlinkRequest) -> Result<(), Self::Error> { - self.symlinks.insert(request.link_path, request.target_path); - Ok(()) - } - - fn read_link(&mut self, request: PathRequest) -> Result { - self.symlinks - .get(&request.path) - .cloned() - .ok_or_else(|| StubError::missing("symlink", &request.path)) - } - - fn chmod(&mut self, _request: ChmodRequest) -> Result<(), Self::Error> { - Ok(()) - } - - fn truncate(&mut self, request: TruncateRequest) -> Result<(), Self::Error> { - let Some(bytes) = self.files.get_mut(&request.path) else { - return Err(StubError::missing("file", &request.path)); - }; - - bytes.resize(request.len as usize, 0); - Ok(()) - } - - fn exists(&mut self, request: PathRequest) -> Result { - Ok(self.files.contains_key(&request.path) - || self.directories.contains_key(&request.path) - || self.symlinks.contains_key(&request.path)) - } -} - -impl PermissionBridge for RecordingBridge { - fn check_filesystem_access( - &mut self, - request: FilesystemPermissionRequest, - ) -> Result { - self.filesystem_permission_requests.push(request.clone()); - self.permission_checks - .push(format!("fs:{}:{}", request.vm_id, request.path)); - self.next_permission_response() - } - - fn check_network_access( - &mut self, - request: NetworkPermissionRequest, - ) -> Result { - self.permission_checks - .push(format!("net:{}:{}", request.vm_id, request.resource)); - self.next_permission_response() - } - - fn check_command_execution( - &mut self, - request: CommandPermissionRequest, - ) -> Result { - self.permission_checks - .push(format!("cmd:{}:{}", request.vm_id, request.command)); - self.next_permission_response() - } - - fn check_environment_access( - &mut self, - request: EnvironmentPermissionRequest, - ) -> Result { - self.permission_checks - .push(format!("env:{}:{}", request.vm_id, request.key)); - self.next_permission_response() - } -} - -impl PersistenceBridge for RecordingBridge { - fn load_filesystem_state( - &mut self, - request: LoadFilesystemStateRequest, - ) -> Result, Self::Error> { - Ok(self.snapshots.get(&request.vm_id).cloned()) - } - - fn flush_filesystem_state( - &mut self, - request: FlushFilesystemStateRequest, - ) -> Result<(), Self::Error> { - self.snapshots.insert(request.vm_id, request.snapshot); - Ok(()) - } -} - -impl ClockBridge for RecordingBridge { - fn wall_clock(&mut self, _request: ClockRequest) -> Result { - Ok(SystemTime::UNIX_EPOCH + Duration::from_secs(1_710_000_000)) - } - - fn monotonic_clock(&mut self, _request: ClockRequest) -> Result { - Ok(Duration::from_millis(42)) - } - - fn schedule_timer( - &mut self, - request: ScheduleTimerRequest, - ) -> Result { - self.scheduled_timers.push(request.clone()); - - let timer = ScheduledTimer { - timer_id: format!("timer-{}", self.next_timer_id), - delay: request.delay, - }; - self.next_timer_id += 1; - - Ok(timer) - } -} - -impl RandomBridge for RecordingBridge { - fn fill_random_bytes(&mut self, request: RandomBytesRequest) -> Result, Self::Error> { - Ok(vec![0xA5; request.len]) - } -} - -impl EventBridge for RecordingBridge { - fn emit_structured_event(&mut self, event: StructuredEventRecord) -> Result<(), Self::Error> { - self.structured_events.push(event); - Ok(()) - } - - fn emit_diagnostic(&mut self, event: DiagnosticRecord) -> Result<(), Self::Error> { - self.diagnostic_events.push(event); - Ok(()) - } - - fn emit_log(&mut self, event: LogRecord) -> Result<(), Self::Error> { - self.log_events.push(event); - Ok(()) - } - - fn emit_lifecycle(&mut self, event: LifecycleEventRecord) -> Result<(), Self::Error> { - self.lifecycle_events.push(event); - Ok(()) - } -} - -impl ExecutionBridge for RecordingBridge { - fn create_javascript_context( - &mut self, - _request: CreateJavascriptContextRequest, - ) -> Result { - let handle = GuestContextHandle { - context_id: format!("js-context-{}", self.next_context_id), - runtime: GuestRuntime::JavaScript, - }; - self.next_context_id += 1; - Ok(handle) - } - - fn create_wasm_context( - &mut self, - _request: CreateWasmContextRequest, - ) -> Result { - let handle = GuestContextHandle { - context_id: format!("wasm-context-{}", self.next_context_id), - runtime: GuestRuntime::WebAssembly, - }; - self.next_context_id += 1; - Ok(handle) - } - - fn start_execution( - &mut self, - _request: StartExecutionRequest, - ) -> Result { - if let Some(error) = self.execution_start_errors.pop_front() { - return Err(error); - } - - let execution = StartedExecution { - execution_id: format!("exec-{}", self.next_execution_id), - }; - self.next_execution_id += 1; - Ok(execution) - } - - fn write_stdin(&mut self, request: WriteExecutionStdinRequest) -> Result<(), Self::Error> { - self.stdin_writes.push(request); - Ok(()) - } - - fn close_stdin(&mut self, request: ExecutionHandleRequest) -> Result<(), Self::Error> { - self.closed_executions.push(request); - Ok(()) - } - - fn kill_execution(&mut self, request: KillExecutionRequest) -> Result<(), Self::Error> { - self.killed_executions.push(request); - Ok(()) - } - - fn poll_execution_event( - &mut self, - _request: PollExecutionEventRequest, - ) -> Result, Self::Error> { - Ok(self.execution_events.pop_front()) - } -} - -#[test] -fn recording_bridge_rejects_symlink_cycles_when_following_metadata() { - let mut bridge = RecordingBridge::default(); - bridge - .symlink(SymlinkRequest { - vm_id: String::from("vm-1"), - target_path: String::from("/b"), - link_path: String::from("/a"), - }) - .expect("create first symlink"); - bridge - .symlink(SymlinkRequest { - vm_id: String::from("vm-1"), - target_path: String::from("/a"), - link_path: String::from("/b"), - }) - .expect("create second symlink"); - - let error = bridge - .stat(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/a"), - }) - .expect_err("cycle should be rejected"); - assert!(error.message.contains("symlink cycle")); - - let metadata = bridge - .lstat(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/a"), - }) - .expect("lstat should not follow symlink"); - assert_eq!(metadata.kind, FileKind::SymbolicLink); -} diff --git a/crates/build-support/Cargo.toml b/crates/build-support/Cargo.toml index b06cdc94f..f97131ac9 100644 --- a/crates/build-support/Cargo.toml +++ b/crates/build-support/Cargo.toml @@ -4,7 +4,10 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Build script helpers for secure-exec crates" +description = "secure-exec-build-support compatibility shim for agentos-build-support" [lib] -path = "v8_bridge_build.rs" +name = "secure_exec_build_support" + +[dependencies] +agentos_build_support = { package = "agentos-build-support", path = "../../../agentos/crates/build-support", version = "0.0.1" } diff --git a/crates/build-support/src/lib.rs b/crates/build-support/src/lib.rs new file mode 100644 index 000000000..44fc0bcfe --- /dev/null +++ b/crates/build-support/src/lib.rs @@ -0,0 +1,3 @@ +//! Compatibility shim for `agentos-build-support`. + +pub use agentos_build_support::*; diff --git a/crates/build-support/v8_bridge_build.rs b/crates/build-support/v8_bridge_build.rs deleted file mode 100644 index 3e3d58221..000000000 --- a/crates/build-support/v8_bridge_build.rs +++ /dev/null @@ -1,315 +0,0 @@ -use std::env; -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; -use std::process::Command; - -const ENV_NODE: &str = "SECURE_EXEC_NODE"; -const LEGACY_ENV_NODE: &str = "AGENTOS_NODE"; -const ENV_BUILD_SCRIPT: &str = "SECURE_EXEC_V8_BRIDGE_BUILD_SCRIPT"; -const LEGACY_ENV_BUILD_SCRIPT: &str = "AGENTOS_V8_BRIDGE_BUILD_SCRIPT"; -const ENV_DEBUG: &str = "SECURE_EXEC_GENERATED_ASSET_DEBUG"; -const LEGACY_ENV_DEBUG: &str = "AGENTOS_GENERATED_ASSET_DEBUG"; -const DEFAULT_BUILD_SCRIPTS: &[&str] = &[ - "packages/build-tools/scripts/build-v8-bridge.mjs", - "packages/secure-exec-core/scripts/build-v8-bridge.mjs", - "packages/core/scripts/build-v8-bridge.mjs", -]; -const BUILD_SCRIPT_CANDIDATES: &str = "packages/build-tools/scripts/build-v8-bridge.mjs, packages/secure-exec-core/scripts/build-v8-bridge.mjs, or packages/core/scripts/build-v8-bridge.mjs"; - -pub fn build_v8_bridge(crate_manifest_dir: &Path, out_dir: &Path) { - let bridge_output = out_dir.join("v8-bridge.js"); - let zlib_output = out_dir.join("v8-bridge-zlib.js"); - - println!("cargo:rerun-if-env-changed={ENV_NODE}"); - println!("cargo:rerun-if-env-changed={LEGACY_ENV_NODE}"); - println!("cargo:rerun-if-env-changed={ENV_BUILD_SCRIPT}"); - println!("cargo:rerun-if-env-changed={LEGACY_ENV_BUILD_SCRIPT}"); - println!("cargo:rerun-if-env-changed={ENV_DEBUG}"); - println!("cargo:rerun-if-env-changed={LEGACY_ENV_DEBUG}"); - - if let Some(repo_root) = monorepo_root(crate_manifest_dir) { - build_from_monorepo(&repo_root, out_dir); - } else { - copy_vendored_bundle(crate_manifest_dir, &bridge_output, &zlib_output); - } - - if !bridge_output.exists() || !zlib_output.exists() { - panic!( - "V8 bridge build completed but expected outputs are missing: {}, {}", - bridge_output.display(), - zlib_output.display() - ); - } -} - -/// Resolve the monorepo root when the in-tree build toolchain is available. -/// Returns `None` when building the published crate so the caller falls back -/// to the vendored prebuilt bundle. -fn monorepo_root(crate_manifest_dir: &Path) -> Option { - if env_var_os(ENV_BUILD_SCRIPT, LEGACY_ENV_BUILD_SCRIPT).is_some() { - // An explicit override always implies an in-tree build. - return crate_manifest_dir - .parent() - .and_then(Path::parent) - .map(Path::to_path_buf); - } - - let repo_root = crate_manifest_dir.parent().and_then(Path::parent)?; - if DEFAULT_BUILD_SCRIPTS - .iter() - .any(|script| repo_root.join(script).exists()) - { - Some(repo_root.to_path_buf()) - } else { - None - } -} - -fn copy_vendored_bundle(crate_manifest_dir: &Path, bridge_output: &Path, zlib_output: &Path) { - let vendored_dir = crate_manifest_dir.join("assets/generated"); - let vendored_bridge = vendored_dir.join("v8-bridge.js"); - let vendored_zlib = vendored_dir.join("v8-bridge-zlib.js"); - - println!("cargo:rerun-if-changed={}", vendored_bridge.display()); - println!("cargo:rerun-if-changed={}", vendored_zlib.display()); - - if !vendored_bridge.exists() || !vendored_zlib.exists() { - panic!( - "the V8 bridge build toolchain ({BUILD_SCRIPT_CANDIDATES}) was not \ - found and no vendored bundle exists at {}. Published crates must ship the prebuilt \ - bundle; run the release tooling to stage it.", - vendored_dir.display() - ); - } - - fs::copy(&vendored_bridge, bridge_output).unwrap_or_else(|error| { - panic!( - "failed to copy vendored V8 bridge bundle from {} to {}: {}", - vendored_bridge.display(), - bridge_output.display(), - error - ) - }); - fs::copy(&vendored_zlib, zlib_output).unwrap_or_else(|error| { - panic!( - "failed to copy vendored V8 bridge zlib bundle from {} to {}: {}", - vendored_zlib.display(), - zlib_output.display(), - error - ) - }); -} - -fn build_from_monorepo(repo_root: &Path, out_dir: &Path) { - let script_path = resolve_build_script(repo_root); - let package_root = script_path - .parent() - .and_then(Path::parent) - .unwrap_or_else(|| { - panic!( - "failed to resolve package root from V8 bridge build script path {}", - script_path.display() - ) - }); - let node_modules = package_root.join("node_modules"); - let node = env_var_os(ENV_NODE, LEGACY_ENV_NODE).unwrap_or_else(|| "node".into()); - let node_path = PathBuf::from(node); - let debug = env_var_os(ENV_DEBUG, LEGACY_ENV_DEBUG).is_some(); - - emit_rerun_inputs(repo_root, &script_path, package_root); - - if !node_modules.exists() { - panic!( - "missing Node dependencies at {}. Run `pnpm install` from {} before building V8 bridge assets.", - node_modules.display(), - repo_root.display() - ); - } - - require_pnpm(repo_root, debug); - - if debug { - println!( - "cargo:warning=building V8 bridge with node={} script={} out_dir={}", - node_path.display(), - script_path.display(), - out_dir.display() - ); - } - - let output = Command::new(&node_path) - .arg(&script_path) - .arg("--out-dir") - .arg(out_dir) - .current_dir(repo_root) - .output() - .unwrap_or_else(|error| match error.kind() { - io::ErrorKind::NotFound => panic!( - "failed to build V8 bridge assets because `{}` was not found. Install Node.js or set {ENV_NODE} to the Node binary.", - node_path.display() - ), - _ => panic!( - "failed to spawn V8 bridge build with `{}`: {}", - node_path.display(), - error - ), - }); - - if !output.status.success() { - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - let dependency_hint = if stderr.contains("ERR_MODULE_NOT_FOUND") - || stderr.contains("Cannot find package") - || stderr.contains("Cannot find module") - { - "\nNode dependencies appear to be missing or incomplete. Run `pnpm install` from the repo root." - } else { - "" - }; - - panic!( - "failed to build V8 bridge assets with `{}` (status: {}).{}\nstdout:\n{}\nstderr:\n{}", - node_path.display(), - output.status, - dependency_hint, - stdout.trim(), - stderr.trim() - ); - } -} - -fn resolve_build_script(repo_root: &Path) -> PathBuf { - match env_var_os(ENV_BUILD_SCRIPT, LEGACY_ENV_BUILD_SCRIPT) { - Some(path) => { - let path = PathBuf::from(path); - if path.is_absolute() { - path - } else { - repo_root.join(path) - } - } - None => DEFAULT_BUILD_SCRIPTS - .iter() - .map(|script| repo_root.join(script)) - .find(|script| script.exists()) - .unwrap_or_else(|| repo_root.join(DEFAULT_BUILD_SCRIPTS[0])), - } -} - -fn env_var_os(primary: &str, legacy: &str) -> Option { - env::var_os(primary).or_else(|| env::var_os(legacy)) -} - -fn require_pnpm(repo_root: &Path, debug: bool) { - let output = Command::new("pnpm") - .arg("--version") - .current_dir(repo_root) - .output() - .unwrap_or_else(|error| match error.kind() { - io::ErrorKind::NotFound => { - panic!( - "failed to build V8 bridge assets because `pnpm` was not found. Install pnpm and run `pnpm install` from {}.", - repo_root.display() - ) - } - _ => panic!("failed to check pnpm availability: {}", error), - }); - - if !output.status.success() { - panic!( - "failed to build V8 bridge assets because `pnpm --version` failed with status {}. Run `pnpm install` from {} after fixing pnpm.", - output.status, - repo_root.display() - ); - } - - if debug { - println!( - "cargo:warning=pnpm version {}", - String::from_utf8_lossy(&output.stdout).trim() - ); - } -} - -fn emit_rerun_inputs(repo_root: &Path, script_path: &Path, package_root: &Path) { - let inputs = [ - repo_root.join("crates/build-support/v8_bridge_build.rs"), - script_path.to_path_buf(), - package_root.join("package.json"), - repo_root.join("pnpm-lock.yaml"), - ]; - - for input in inputs { - println!("cargo:rerun-if-changed={}", input.display()); - } - - let bridge_src_dir = repo_root.join("packages/build-tools/bridge-src"); - emit_rerun_dir(&bridge_src_dir).unwrap_or_else(|error| { - panic!( - "failed to enumerate V8 bridge source inputs under {}: {}", - bridge_src_dir.display(), - error - ) - }); - - let shim_dir = repo_root.join("crates/execution/assets/undici-shims"); - emit_rerun_dir(&shim_dir).unwrap_or_else(|error| { - panic!( - "failed to enumerate V8 bridge shim inputs under {}: {}", - shim_dir.display(), - error - ) - }); -} - -fn emit_rerun_dir(dir: &Path) -> io::Result<()> { - let mut entries = fs::read_dir(dir)?.collect::, _>>()?; - entries.sort_by_key(|entry| entry.path()); - - for entry in entries { - let path = entry.path(); - let file_type = entry.file_type()?; - if file_type.is_dir() { - emit_rerun_dir(&path)?; - } else { - println!("cargo:rerun-if-changed={}", path.display()); - } - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::emit_rerun_dir; - use std::fs; - use std::io; - use std::path::PathBuf; - - fn temp_test_dir(name: &str) -> io::Result { - let mut path = std::env::temp_dir(); - path.push(format!( - "secure-exec-v8-bridge-build-{name}-{}", - std::process::id() - )); - let _ = fs::remove_dir_all(&path); - fs::create_dir(&path)?; - Ok(path) - } - - #[cfg(unix)] - #[test] - fn emit_rerun_dir_does_not_follow_directory_symlinks() -> io::Result<()> { - let dir = temp_test_dir("symlink-cycle")?; - fs::write(dir.join("shim.js"), b"export {};")?; - std::os::unix::fs::symlink(&dir, dir.join("self"))?; - - let result = emit_rerun_dir(&dir); - let cleanup = fs::remove_dir_all(&dir); - - result?; - cleanup?; - Ok(()) - } -} diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml new file mode 100644 index 000000000..faa4d2722 --- /dev/null +++ b/crates/client/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "secure-exec-client" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +description = "secure-exec-client compatibility shim for agentos-sidecar-client" + +[lib] +name = "secure_exec_client" + +[dependencies] +agentos_sidecar_client = { package = "agentos-sidecar-client", path = "../../../agentos/crates/sidecar-client", version = "0.0.1" } diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs new file mode 100644 index 000000000..ef2436dc3 --- /dev/null +++ b/crates/client/src/lib.rs @@ -0,0 +1,3 @@ +//! Compatibility shim for `agentos-sidecar-client`. + +pub use agentos_sidecar_client::*; diff --git a/crates/execution/AGENTS.md b/crates/execution/AGENTS.md deleted file mode 120000 index 681311eb9..000000000 --- a/crates/execution/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/crates/execution/CLAUDE.md b/crates/execution/CLAUDE.md deleted file mode 100644 index 473423dce..000000000 --- a/crates/execution/CLAUDE.md +++ /dev/null @@ -1,233 +0,0 @@ -# Execution Engines - -Runtime execution for Node.js (JavaScript/TypeScript) and Python (Pyodide) guest code. - -`crates/execution` is the native execution implementation crate. It is not the browser/native portability seam. Cross-environment contracts belong in `crates/bridge/` (`ExecutionBridge`, `HostBridge`), and browser-side execution should continue to target those shared bridge surfaces rather than depending on `crates/execution`. - -When simplifying native V8 embedding, prefer concrete native types over new traits unless there is a real need for multiple interchangeable native V8 backends. Do not introduce a native-internal `V8Runtime` abstraction and then treat it like a second portability layer. - -**⚠️ ABSOLUTE RULE — NO EXCEPTIONS, NO FALLBACKS, NO "TEMPORARY" WORKAROUNDS:** - -**ALL guest code MUST execute inside V8 isolates with kernel-backed polyfills. NEVER spawn real host Node.js processes for guest code. NEVER use `Command::new("node")` for guest execution. NEVER add a "legacy node mode", "host execution fallback", or "execution mode flag" that routes guest code through real host processes. There is exactly ONE execution path for guest JavaScript: V8 isolates managed by `crates/v8-runtime/` with polyfills that route through the kernel. Any code path where guest code reaches the real host — even as a "temporary" measure, even behind a flag, even for "compatibility" — is a critical security violation and MUST NOT be merged.** - -If tests fail because they were written for the old `Command::new("node")` path, **fix or delete the tests** — do NOT restore host execution to make them pass. - -## Node.js Isolation Model - -**Desired state:** Guest JS/TS runs inside isolated V8 contexts managed by the execution engine. All Node.js builtins (`fs`, `net`, `child_process`, `dns`, `http`, `os`, etc.) are kernel-backed polyfills that route through the kernel VFS, socket table, and process table. Module loading is fully intercepted — guest code never touches real host APIs. The execution engine previously had this working via `@secure-exec/core` + `@secure-exec/nodejs` with full kernel-backed polyfills for all builtins. - -**Current state (⚠️ STILL INCOMPLETE -- see `~/.agents/todo/node-isolation-gaps.md`):** - -Guest JavaScript entrypoints in `javascript.rs` now run only through the shared V8 runtime. The remaining gaps are polyfill completeness and builtin isolation parity: some builtins still need deeper kernel-backed implementations or broader conformance coverage, but restoring a host-Node guest execution fallback is not allowed. - -- Keep any real-host Node helpers isolated to clearly host-only modules used by benchmarks or import-cache tests. Guest JS/WASM/Python runtime code should depend only on neutral shared helpers (for example signal metadata or path resolution), not on files that also own host launch behavior. -- Guest-side WebAssembly inside the V8 isolate must stay enabled on both fresh isolates and snapshot restores. Real npm packages rely on `WebAssembly.Module`, `WebAssembly.Instance`, and `WebAssembly.instantiate*`, and allowing those APIs does not violate the kernel-isolation boundary because compilation stays inside the isolate. Do not reintroduce an embedder callback that blocks WASM; rely on V8's own implementation limits instead. - -**Recovery reference:** The complete working polyfill + V8 isolate code from the original `@secure-exec/core` + `@secure-exec/nodejs` + `@secure-exec/v8` packages has been recovered to `~/.agents/recovery/secure-exec/`. Key files to port: -- `nodejs/src/bridge/fs.ts` (3,974 lines) -- full kernel-backed `fs`/`fs/promises` polyfill -- `nodejs/src/bridge/network.ts` (11,149 lines) -- full `net`/`dgram`/`dns` polyfill via kernel socket table -- `nodejs/src/bridge/child-process.ts` (1,058 lines) -- `child_process` polyfill via kernel process table -- `nodejs/src/bridge/process.ts` (2,251 lines) -- virtualized `process` global (env, cwd, pid, signals) -- `nodejs/src/bridge/polyfills.ts` (914 lines) -- polyfill registration and module hijacking -- `nodejs/src/bridge-handlers.ts` (6,405 lines) -- host-side bridge handlers for all kernel syscalls -- `nodejs/src/execution-driver.ts` (1,693 lines) -- V8 isolate session lifecycle + bridge setup -- `kernel/` -- the JS kernel (VFS, process table, socket table, PTY, pipes) -- `v8/` -- V8 runtime process manager, IPC binary protocol - -The original source repo is at `/home/nathan/secure-exec-1/` (tagged `v0.2.1`). - -**Prior art -- the original JS kernel had full polyfills:** - -Before the Rust sidecar (commit `5a43882`), the JS kernel (`@secure-exec/core` + `@secure-exec/nodejs` + `packages/posix/`) had complete kernel-backed polyfills for all builtins. The pattern was: -- **Kernel socket table** -- `kernel.socketTable.create/connect/send/recv` managed all TCP/UDP. Loopback stayed in-kernel; external connections went through a `HostNetworkAdapter`. -- **Kernel VFS** -- All `fs` operations routed through the kernel VFS via syscall RPC. -- **Kernel process table** -- `child_process.spawn` routed through `kernel.spawn()`. -- **SharedArrayBuffer RPC** -- Synchronous syscalls from worker threads used `Atomics.wait` + shared memory buffers (same pattern the Pyodide VFS bridge uses today). -- **Module hijacking** -- `require('net')` returned the kernel-backed socket implementation, not real `node:net`. - -The Rust sidecar kernel already has the VFS, process table, pipe manager, PTY manager, and permission system. What's missing is porting the **polyfill layer**. This is a port of proven patterns, not a greenfield design. - -### Current reality vs required state - -| Builtin | Required | Current | Gap | -|---------|----------|---------|-----| -| `fs` / `fs/promises` | Kernel VFS polyfill | Path-translating wrapper over real `node:fs` | Port: route through kernel VFS via RPC | -| `child_process` | Kernel process table polyfill | Path-translating wrapper over real `node:child_process` | Port: route through kernel process table | -| `net` | Kernel socket table polyfill | **No wrapper -- falls through to real `node:net`** | Port: kernel socket table polyfill | -| `dgram` | Kernel socket table polyfill | **No wrapper -- falls through to real `node:dgram`** | Port: kernel socket table polyfill | -| `dns` | Kernel DNS resolver polyfill | **No wrapper -- falls through to real `node:dns`** | Port: kernel DNS resolver polyfill | -| `http` / `https` / `http2` | Built on kernel `net` polyfill | **No wrapper -- falls through to real module** | Port: builds on `net` polyfill | -| `tls` | Kernel TLS polyfill | Guest-owned polyfill in `node_import_cache.rs` wraps the existing guest `net` transport with host TLS state | Keep client/server entrypoints on guest sockets and avoid direct host `node:tls` listeners/connections | -| `os` | Kernel-provided values | Guest-owned polyfill in `node_import_cache.rs` virtualizes hostname, CPU, memory, loopback networking, home, and user info | Keep future `os` additions aligned with VM defaults | -| `vm` | Guest-owned compatibility shim for package loading | Guest-owned compatibility builtin for `Script`, `createContext`, `isContext`, `runInNewContext`, `runInThisContext` | Keep it limited to the compatibility surface; do not fall through to host `node:vm` | -| `worker_threads` | Guest-owned compatibility shim for package loading | Guest-owned compatibility builtin exposing `isMainThread` plus inert ports; `Worker` construction stays unavailable | Keep it importable for feature detection, but never spawn real threads | -| `inspector` | Must be denied | **No wrapper -- falls through to real module** | Must stay denied | -| `v8` | Guest-owned compatibility shim for package loading | Guest-owned compatibility builtin for safe inspection/serialization helpers | Keep it limited to the compatibility surface; do not fall through to host `node:v8` | - -### Loader interception (`node_import_cache.rs`) - -ESM loader hooks (`loader.mjs`) and CJS `Module._load` patches (`runner.mjs`) are generated from Rust string templates. Every `import`/`require` is intercepted: -1. `resolveBuiltinAsset()` -- checks `BUILTIN_ASSETS` list. Redirects to a kernel-backed polyfill file. -2. `resolveDeniedBuiltin()` -- checks `DENIED_BUILTINS` set. Redirects to a stub that throws `ERR_ACCESS_DENIED`. A builtin is in `DENIED_BUILTINS` only if it is NOT in `ALLOWED_BUILTINS`. -3. **Fall through to `nextResolve()`** -- Node.js default resolution. Returns the real host module. **This must never happen for any builtin that guest code can import.** - -`AGENTOS_ALLOWED_NODE_BUILTINS` (JSON string array env var) controls which builtins the host-node loader removes from the deny list. The default list `DEFAULT_ALLOWED_NODE_BUILTINS` lives in `crates/sidecar/src/execution.rs`. Note the live shared-V8 path enforces builtin denial at the Rust resolver (`LocalBridgeState::resolve_module` in `crates/execution/src/javascript.rs`, gated by `AGENTOS_JS_BUILTIN_ALLOWLIST`), not via this env var — see the `jsRuntime` config. - -- CommonJS `require` wrappers in `packages/build-tools/bridge-src/` must expose Node-compatible metadata on every per-module require function, not just on `Module.createRequire(...)`. Real packages call `delete require.cache[__filename]`, inspect `require.extensions`, and expect `require.main` to exist while running inside nested CommonJS modules. -- The builtin `buffer` module wrapper must re-export `Blob` and `File` alongside `Buffer` constants. Next.js bundles `undici` through `require("buffer")`, and missing `buffer.Blob` / `buffer.File` breaks `fetch` support even when global `Blob` / `File` exist. -- Keep the custom `events.EventEmitter` implementation function-constructible rather than a strict ES class. Legacy npm packages still use `util.inherits(..., EventEmitter)` plus `EventEmitter.call(this)`, and that pattern must stay compatible. -- Local bridge module resolution must accept `file:` specifiers by converting them back to guest paths before package/path resolution. Next.js and other ESM loaders use `import(pathToFileURL(path).href)` for config and plugin loading. - -### Additional hardening layers (defense-in-depth, NOT primary isolation) - -1. **`globalThis.fetch` hardening** -- Replaced with `restrictedFetch` (loopback-only on exempt ports). Does NOT cover `http.request()`, `net.connect()`, or `dgram.createSocket()`. -2. **Node.js `--permission` flag** -- OS-level backstop for filesystem and child_process only. No network restrictions. This is a safety net, not the isolation boundary. -3. **Guest env stripping** -- `NODE_OPTIONS`, `LD_PRELOAD`, `DYLD_INSERT_LIBRARIES`, `LD_LIBRARY_PATH` stripped before spawn. -4. **Permissioned Pyodide host launches still need `--allow-worker`.** `python.rs` bootstraps through Node's internal ESM loader worker, so the host process must keep `--allow-worker` enabled even though the guest `node:worker_threads` surface is limited to a compatibility shim and does not permit real worker creation. - -## Guest `fs` and `fs/promises` Polyfill Rules - -- Guest Node `fs` and `fs/promises` polyfills share the JavaScript sync-RPC transport between `node_import_cache.rs` and `crates/sidecar/src/service.rs`. -- Node-facing `readdir` results must filter `.`/`..`. -- Async methods should dispatch under `fs.promises.*`. -- `fs.promises` methods that need real concurrency must use dedicated async bridge globals in `packages/build-tools/bridge-src/`; wrapping `fs.*Sync` inside `async` functions still serializes `Promise.all(...)` behind the first sidecar response. -- When adding WASI guest imports in `registry/native/crates/wasi-ext`, mirror the required module/object in `crates/execution/src/node_import_cache.rs`'s inline `NODE_WASM_RUNNER_SOURCE`; missing modules fail at `WebAssembly.instantiate()` before guest `main()` runs. -- Keep the embedded WASI shim in `crates/execution/src/wasm.rs` aligned with the patched wasi-libc surface used by the C command suite; overrides like `fcntl(F_SETFL)` now depend on `fd_fdstat_set_flags`, and missing imports fail at instantiation time before the guest command can do real work. -- The shared-V8 WASM runner now resolves its own module loads plus internal guest `fs.openSync` / `fs.readSync` / `fs.writeSync` / `fs.closeSync` traffic inside `crates/execution/src/wasm.rs`; if the embedded runner gains more internal file syscalls, extend that internal sync-RPC handling there instead of surfacing those requests to callers or reintroducing a host-Node runtime path. -- fd-based APIs (`open`, `read`, `write`, `close`, `fstat`) plus `createReadStream`/`createWriteStream` should ride the same bridge. -- Creation-oriented V8 `fs` helpers must preserve the guest `mode` option and resolve it against the current guest `process.umask()` before dispatching kernel-backed RPCs; dropping the `mode` field or relying on host defaults breaks Node parity for `fs.openSync`, `fs.mkdirSync`, and stream constructors that create paths. -- Guest `fs.watch` / `fs.watchFile` currently stay guest-owned polling wrappers over `fs.statSync`; keep them in `bridge-src` unless the kernel grows a real notification API. -- Runner-internal pipe/control writes must keep snapped host `node:fs` bindings because `syncBuiltinModuleExports(...)` mutates the builtin module for guests. - -## JavaScript Sync RPC - -- Timeouts and slow-reader backpressure should be enforced in `javascript.rs`, not in the generated runner. -- Track the pending request ID on the host, auto-emit `ERR_AGENTOS_NODE_SYNC_RPC_TIMEOUT` after the configured wait. -- Queue replies through a bounded async writer so slow guest reads cannot block the sidecar thread. -- Have `crates/sidecar/src/service.rs` ignore stale `sync RPC request ... is no longer pending` races after the timeout fires. -- Guest V8 timers have two host paths in `javascript.rs`: `_scheduleTimer` is an async bridge call that resolves its pending Promise later, while `kernelTimerCreate`/`kernelTimerArm`/`kernelTimerClear` are local `_loadPolyfill` dispatches that must emit `"timer"` stream events back into the V8 session so `setTimeout`/`setInterval` callbacks fire. -- In `packages/build-tools/bridge-src/`, keep Node's 1ms minimum-delay clamp on `setTimeout(0)` / `setInterval(0)` separate from `setImmediate()`. If `setImmediate()` is implemented via the timeout helper, it will accidentally inherit the clamp and drift from Node ordering/parity. -- Live guest stdin also has two delivery paths: `SECURE_EXEC_KEEP_STDIN_OPEN` uses `"stdin"` / `"stdin_end"` stream events, while TTY-style reads use `_kernelStdinRead` and must stay forwarded to the sidecar-backed kernel fd `0` pipe so timeout and EOF remain distinguishable. -- Guest `stdin.setRawMode()` should follow the same bridge pattern as `_kernelStdinRead`: leave `_ptySetRawMode` unhandled in `LocalBridgeState`, map it to sidecar `__pty_set_raw_mode`, and have the sidecar toggle kernel PTY discipline on the guest process's fd `0` instead of keeping a local execution-only stub. -- The current V8 sync-RPC bridge effectively supports one in-flight request at a time. Do not leave long-lived network waits such as HTTP server close listeners parked on a pending sync-RPC Promise; use stream events plus short-lived follow-up RPCs so later bridge calls cannot deadlock behind the wait. - -## Runner Script Assets - -- Execution-host runner scripts materialized by `NodeImportCache` should live as checked-in assets under `crates/execution/assets/runners/` and be loaded via `include_str!`. -- The stdlib-backed V8 bridge bundle is generated from `packages/build-tools/bridge-src/` into Cargo `OUT_DIR`; `pnpm --dir packages/secure-exec-core build:v8-bridge` is only for manual debugging. Keep the heavier assert/util/zlib payload in `v8-bridge-zlib.js` so the main `v8-bridge.js` stays below the 500KB cap. -- Guest `os` virtualization has two env surfaces: public `process.env` is intentionally scrubbed of `AGENTOS_*`, while the real per-execution values live in the hidden runtime env (`globalThis.__agentOSProcessConfigEnv` in `javascript.rs`, mirrored from the sidecar's `prepare_guest_runtime_env(...)`). If `bridge-src` needs VM-scoped CPU/memory/home metadata, read that hidden env path or `_processConfig.env` rather than the sanitized public env, and keep it aligned with `node_import_cache.rs`. -- When `build:v8-bridge` pulls deeper undici API modules (for example `undici/lib/api/*`), keep `packages/build-tools/scripts/build-v8-bridge.mjs` aliasing any extra Node builtins they require to standalone shim files under `crates/execution/assets/undici-shims/`; those imports execute while the bundle is still bootstrapping, so they cannot depend on later `exposeCustomGlobal(...)` wiring like `_asyncHooksModule`. -- Keep `http` and `https` default agents scoped to their own module instances inside `packages/build-tools/bridge-src/`; sharing a single global default agent makes `http.request()` inherit HTTPS TLS behavior. Guest-local loopback TLS upgrades must also short-circuit inside the bridge instead of calling `net.socket_upgrade_tls`, because loopback fast-path sockets never have a kernel socket id. -- Guest HTTP client readiness in `packages/build-tools/bridge-src/` must not treat a failed kernel `net.connect()` as request-ready just because `connecting === false`; kernel-backed sockets are only ready once `_connected === true` (or they are loopback/custom preconnected sockets), otherwise denied egress can hang in `http.request()` instead of surfacing `EACCES`. -- Keep both `ServerResponse` socket-compatibility surfaces in sync inside `packages/build-tools/bridge-src/`: the main `ServerResponseBridge.socket` stub and the exported `http.ServerResponse` constructor's fake socket. If only one forwards or throws on `socket.write()`, direct `res.socket.write(...)` calls silently drop bytes on the other path. -- For guest listener-leak warnings in `packages/build-tools/bridge-src/`, route `EventEmitter` warnings through `process.emitWarning(...)` so `process.on("warning")` sees real warning objects, and lazily initialize `_maxListenersWarned` in helper paths because some inline bridge emitters (for example stream and child-process variants) do not always pass through the canonical constructor first. -- If you change generated builtin asset source in `crates/execution/src/node_import_cache.rs`, bump `NODE_IMPORT_CACHE_ASSET_VERSION` in the same file or stale materialized assets under `/tmp/agentos-node-import-cache-*` will keep serving the old code. -- The embedded WASM runner's `buildPreopens()` map must mirror `AGENTOS_GUEST_PATH_MAPPINGS`, not just `.` / `/workspace`; otherwise kernel-visible host-dir mounts like `/etc/agentos` or `/hostmnt` can succeed through `vm.readFile()` while the same path fails under `vm.exec("cat ...")`. -- Treat `crates/bridge/bridge-contract.json` as the canonical inventory for host bridge globals and calling conventions, and treat `crates/execution/assets/polyfill-registry.json` as the canonical inventory for guest `_loadPolyfill` module names. When adding or renaming a bridge global, update those files together with `crates/v8-runtime/src/session.rs`, and when exposing a new runtime-loadable builtin, update the polyfill registry together with the `_loadPolyfill` handler in `crates/execution/src/javascript.rs`. -- Guest builtin availability must stay aligned across `polyfill-registry.json`, `normalize_builtin_specifier()` in `crates/execution/src/javascript.rs`, `Module.builtinModules` plus `loadBuiltinModule()` in `packages/build-tools/bridge-src/`, and the host-node import-cache assets in `crates/execution/src/node_import_cache.rs`; if one surface still treats a denied builtin as unknown, guests will see `MODULE_NOT_FOUND` or host fallthrough instead of the intended `ERR_ACCESS_DENIED` or compatibility stub. -- The `node:vm` compatibility shim in `packages/build-tools/bridge-src/` must tag sandboxes inside `vm.createContext()` and have `vm.isContext()` check only that hidden tag; treating every object-shaped value as a context breaks libraries like jsdom that probe `isContext()` before deciding whether to re-contextify. -- `node:vm` compatibility now spans three layers: the native local bridge methods in `crates/v8-runtime/src/bridge.rs`, the stdlib-backed guest module in `packages/build-tools/bridge-src/`, and the inline shared-runtime fallback in `crates/execution/src/javascript.rs`. Keep all three aligned when changing `Script`, context isolation, or timeout semantics or sidecar builtin-conformance and execution tests will diverge. -- In `packages/build-tools/bridge-src/`, `Readable.on("data")` may auto-switch to flowing mode only from the initial `readableFlowing === null` state; if guest code already called `pause()` and set `readableFlowing === false`, preserve that explicit pause until `resume()` so packages like `tar` and `node-stream-zip` do not drain early. -- The shared-runtime `node:stream` compatibility surface for sidecar/builtin-conformance tests currently comes from the inline mini-stream module in `crates/execution/src/javascript.rs`, not the stdlib-backed `packages/build-tools/bridge-src/` path. Stream iterator/parity fixes for guest `require("stream")` need to land in that inline module and should be covered in `crates/sidecar/tests/builtin_conformance.rs`. -- The shared-runtime `node:readline` compatibility surface exercised by sidecar/builtin-conformance tests also comes from the inline module in `crates/execution/src/javascript.rs`, not only from `packages/build-tools/bridge-src/`. `question()`/async-iterator fixes need to land in that inline module and should be verified in `crates/sidecar/tests/builtin_conformance.rs`. -- Bootstrap globals injected by `packages/build-tools/scripts/build-v8-bridge.mjs` exist only to let the bundle initialize during snapshot creation. If that bootstrap layer defines `URL` or `URLSearchParams`, mark them as bootstrap stubs and have `bridge-src` ignore or replace them once the stdlib polyfills load, or the runtime can silently keep the incomplete bootstrap implementation. -- Keep `globalThis.structuredClone` guest-owned inside `packages/build-tools/bridge-src/`; falling back to the native host `structuredClone` leaks host-realm typed arrays, `Map`s, and `Date`s that fail guest `instanceof` checks even when the cloned data looks correct. -- If guest `fetch()` is powered by bundled undici, the aliased `node:stream` helpers in `crates/execution/assets/undici-shims/stream.js` must understand the bundled web-streams ponyfill too; undici's fetch path calls `finished()`, `isReadable()`, `isErrored()`, and `isDisturbed()` on `ReadableStream` response bodies, not just Node event-emitter streams. -- When testing import-cache temp-root cleanup, use a dedicated `NodeImportCache::new_in(...)` base dir so the one-time sweep stays isolated to that root. -- Active JavaScript/Python/WASM executions must hold a `NodeImportCache` cleanup guard until the child exits; otherwise dropping the engine can delete `timing-bootstrap.mjs` and related assets while the host runtime is still importing them. -- JavaScript guest validation should live in `crates/execution/tests/javascript_v8.rs`. Do not reintroduce a feature-gated host-Node guest path or a parallel host-Node compatibility suite for guest JavaScript behavior. -- Add new V8-backed JavaScript regressions to `crates/execution/tests/javascript_v8.rs` as helper functions invoked from the single top-level `javascript_v8_suite()` test, not as separate `#[test]` cases; the shared embedded runtime still trips teardown/init crashes when libtest runs those guest cases independently. -- Shared-V8 JavaScript tests should assert `uses_shared_v8_runtime()` and the absence of host guest-node launches, not `child_pid() == 0`; shared isolates still report the host runtime PID so the sidecar can manage lifecycle signals. - -## Guest Path Scrubbing - -- Guest path scrubbing in `node_import_cache.rs` should treat the real `HOST_CWD` as an implicit runtime-only mapping to the virtual guest cwd (for example `/root`) so entrypoint imports and stack traces stay usable without leaking the host path. -- Reserve `/unknown` for absolute host paths outside visible mappings or the internal cache roots. - -## CommonJS Module Isolation - -- `node_import_cache.rs` has to patch `Module._resolveFilename` and the guest-facing `Module._cache` / `require.cache` view together; wrapping only `createGuestRequire()` does not constrain local `require()` inside already-loaded `.cjs` modules. -- The V8 bridge's guest-side CommonJS helpers in `packages/build-tools/bridge-src/` must pass an explicit `"require"` mode into `_resolveModule`; omitting it falls back to import resolution and picks the wrong conditional export branch for dual packages. -- Keep `require.resolve()` parity between both CommonJS entrypoints in `packages/build-tools/bridge-src/`: `createRequire()` and the per-module `require` created in `_compile()`. If one gains `resolve.paths()` or builtin handling changes without the other, guest packages behave differently depending on how they obtained `require`. -- Eval entrypoints (`node -e` / `--eval`) must build the guest `require` from a synthetic file under the guest cwd, not from the literal `-e` token. Relative CommonJS loads in eval mode are supposed to resolve from `process.cwd()`, and using `createRequire("-e")` makes positive cases like `require('./config.json')` resolve from `"."` instead. -- Inline `node -e` / `--eval` module-mode detection in `crates/execution/src/javascript.rs` must strip comments plus string/template raw text before scanning syntax markers, and positive CommonJS signals (`module.exports`, `exports.*`, `require(...)`) should win ties over ESM markers; line-prefix heuristics misclassify bundle banners and literal text. -- For builtins that guest CommonJS should `require("node:...")`, update `createRequire()` builtin guards plus both `Module.builtinModules` and `loadBuiltinModule()` in `packages/build-tools/bridge-src/`; changing only one surface leaves `require()` behavior out of sync with `_requireFrom()` and can degrade into `ERR_ACCESS_DENIED`, `MODULE_NOT_FOUND`, or host-fallthrough mismatches. -- `crates/v8-runtime/src/execution.rs` should fall back to runtime CJS export enumeration (`Object.keys(module.exports)`) only when static extraction finds zero names or the source contains a dynamic re-export pattern static scanning cannot resolve (`__exportStar(require(...), exports)`, `Object.assign(exports, ...)`); eagerly requiring every CJS module during shim generation adds avoidable work and can trigger module side effects earlier than intended. The dynamic-re-export case is required because tsc-compiled barrels like `@sinclair/typebox/compiler` surface named exports (e.g. `TypeCompiler`) at runtime via `__exportStar`, which `extract_cjs_export_names()` cannot see. -- Inline builtin wrappers in `crates/execution/src/javascript.rs` must not call `_requireFrom()` on the same builtin subpath they implement. Subpath wrappers like `node:fs/promises` should be built from the parent builtin (`node:fs`) or a direct object, not `_requireFrom("node:fs/promises")`. -- Resolver-only coverage for `javascript.rs` should use `javascript::ModuleResolutionTestHarness` with a temp-dir fixture instead of booting a V8 isolate; mapping `/root` plus `/root/node_modules` is enough to exercise exports/imports and pnpm `.pnpm` layouts. -- `crates/execution/tests/cjs_esm_interop.rs` is the desired-behavior matrix for CJS/ESM/runtime edge cases. If an interop gap is deferred to a follow-up story, keep the strong assertion in place and mark that test `#[ignore = "US-055: ..."]` instead of weakening it to match current behavior. - -## Guest `process` Hardening - -- Guest-visible `process` hardening in `node_import_cache.rs` should harden properties on the real host `process` before swapping in the guest proxy. -- The proxy fallback must resolve via the proxy receiver (`Reflect.get(..., proxy)`) so accessors inherit the virtualized surface instead of the raw host object. -- Per-process filesystem state such as `umask` belongs in `ProcessContext` / `ProcessTable`. Kernel create/write entrypoints should read it there, and any guest Node exposure must be threaded through the JavaScript sync-RPC bridge instead of inheriting host `process` behavior. - -## Guest `child_process` Isolation - -- Strip all `AGENTOS_*` keys from the RPC `options.env` payload in `node_import_cache.rs`. -- Carry only the Node runtime bootstrap allowlist in `options.internalBootstrapEnv`. -- Re-inject that allowlisted map only when `crates/sidecar/src/service.rs` starts a nested JavaScript runtime. -- Treat string-valued `child_process` `options.shell` values as shell-enabled in both `packages/build-tools/bridge-src/` and `crates/execution/src/node_import_cache.rs`; packages like OpenCode and `cross-spawn` pass concrete shell paths such as `"/bin/sh"`, and collapsing those to `false` makes redirected commands execute as literal program names. -- Keep sync child-process stdin wired through the bridge too: `packages/build-tools/bridge-src/` `spawnSync` / `execSync` must serialize `options.input`, and the sidecar sync handlers need to write that payload to child stdin and close stdin before polling or commands like `spawnSync("/bin/cat", { input })` will diverge from host Node or hang waiting for EOF. -- Detached guest `child_process` bootstrap in `packages/build-tools/bridge-src/` must be driven by synchronous/immediate `child_process.poll` drains plus pre-`exit` completion, not a retry timer in `unref()`. Timer-based completion can race listener teardown and make long-lived detached daemons disappear when the parent exits. -- Guest `child_process.kill(signal)` in `packages/build-tools/bridge-src/` should canonicalize numeric and alias inputs through the full 1..31 POSIX table before calling the sidecar, and it should leave `child.signalCode === null` until the exit/close path runs. Node exposes the canonical signal name only after the child actually exits. -- JavaScript child-process launches in `crates/sidecar/src/execution.rs` must call `prepare_javascript_runtime_env(...)` and set `AGENTOS_SANDBOX_ROOT` just like top-level `execute()` does. If child V8 executions miss those runtime env entries, stack traces fall back to `/unknown/...`, bare-package ESM imports like `undici` stop resolving, and spawned JS CLIs (including `pi-acp` -> `pi --mode rpc`) silently diverge from top-level behavior. -- The V8 `node:async_hooks` shim in `packages/build-tools/bridge-src/` must preserve `AsyncLocalStorage` state across `Promise.then`, `queueMicrotask`, `process.nextTick`, timers, and `AsyncResource.runInAsyncScope`; OpenCode's Effect instance context depends on that propagation during streamed tool execution. -- In `crates/execution/src/node_import_cache.rs`, WASM child-process stdio can target delegate-managed guest fds rather than real host OS fds. Keep synthetic-pipe routing aligned with `delegateManagedFdWrite`/`delegateManagedFdClose`, retain those delegate fds for the child lifetime, and only release the final close after child exit; writing streamed stdout/stderr with raw host `writeSync(fd, ...)` breaks redirected shell output. -- In that same WASM host-process bridge, `child_process.poll` returning `ECHILD` after an `exit` event's trailing-drain pass is terminal, not a new fault. The sidecar can remove the child as soon as it reports exit, so post-exit drain loops must stop on `ECHILD` instead of converting a successful pipeline into `WASI_ERRNO_FAULT`. -- For sidecar-managed WASM guests, `fd_write` on fd 1 / fd 2 must go through the kernel stdio bridge (`__kernel_stdio_write`) rather than guest `process.stdout` / `process.stderr`. Falling back to the host stream inside the shared sidecar process breaks VM output isolation, bypasses PTYs and `/dev/stdout` redirection, and can make tests pass by snooping host stdout instead of the kernel-routed output path; keep any execution-only fallback scoped to non-sidecar harnesses that are not running inside a VM. -- In the standalone WASI runner path, only opt into `__kernel_stdio_write` / `__kernel_stdin_read` when the process is sidecar-managed or `AGENTOS_WASI_STDIO_SYNC_RPC=1` is set. Helper-style Rust tests still expect bootstrap stdout/stderr to surface as queued `WasmExecutionEvent::{Stdout,Stderr}` events, so internal `fs.writeSync(1|2, ...)` sync RPCs must be translated inside `crates/execution/src/wasm.rs` instead of leaking out as raw sync-RPC traffic. -- Mirror guest-stdin fixes across both WASI host shims: `crates/execution/src/wasm.rs` and `crates/execution/src/node_import_cache.rs` must special-case guest fd `0` before passthrough-handle delegation, or sidecar-managed stdin silently falls back to host `fs.readSync(...)` and pipe-heavy shell commands hang behind the wrong read path. -- When the standalone WASI runner still uses in-band `__AGENTOS_WASM_SIGNAL_STATE__:` lines, parse stdout/stderr as line-oriented byte streams inside `crates/execution/src/wasm.rs` and treat the marker only when it occupies its own newline-terminated line; preserve every other byte verbatim and reassemble markers that arrive split across chunks. -- In the same WASM host-process path, synthetic pipes must initialize both `producers` and `consumers`, and consumer registration must flush any chunks buffered before the child attached. Shell builtins can write into a pipe before a spawned child like `wc` registers its stdin consumer, so registration also needs to close child stdin immediately when no writers or producers remain. -- In that synthetic-pipe path, keep pipe FD mappings alive while a registered producer or consumer is still attached, even if the guest shell closes its local duplicate of the pipe endpoint. Pipeline writers/readers outlive the shell's bookkeeping FDs, and queued bytes should treat registered consumers as active readers even after `readHandleCount` drops to zero. -- The WASM runner's read-only `path_open` guard in `crates/execution/src/node_import_cache.rs` must allow non-mutating open flags such as `O_DIRECTORY`; only create/truncate/exclusive flags and write rights should return `EACCES`, or read-only traversal commands like `find`, `fd`, and `ls ` will fail to enumerate directories. -- Keep the WASM preopen rights metadata aligned between `buildPreopens()` in `crates/execution/src/node_import_cache.rs` and the inline WASI shim in `crates/execution/src/wasm.rs`: `fd_fdstat_get` and `path_open` must read the same per-preopen `rightsBase` / `rightsInheriting` values, or read-only tiers silently regain write access through the default "all rights" fallback. -- WASM execution tests that poll `WasmExecution::poll_event_blocking()` need to handle `WasmExecutionEvent::SyncRpcRequest(_)` explicitly unless the test is asserting that control-plane behavior; the runtime includes sync RPC traffic in the same event stream as stdout/stderr/signal/exit events. `WasmExecution::wait()` only auto-services kernel stdio writes (`__kernel_stdio_write`) so simple callers still collect stdout/stderr, and it should fail fast on any other unexpected pending sync RPC instead of silently hanging. -- The host WASI runner's full-permission preopens must include both `'.'` and `'/workspace'` mapped to `process.cwd()`. Child commands that receive `cwd: "/workspace"` from the sidecar still resolve relative paths through the WASI `.` preopen, so omitting it makes `cat note.txt`/redirects fail even when the guest cwd is otherwise correct. -- In the inline WASI shim in `crates/execution/src/wasm.rs`, `path_open` must resolve the target beneath the specific descriptor's `hostPath`, not by bouncing through the global guest-path mapping table; otherwise `../` segments can escape one preopen and land in sibling mounts or host paths like `/etc/passwd`. -- WASM child-process launches should keep the guest command name in `ResolvedChildProcessExecution.process_args[0]` / WASI `argv[0]`; `execution_args` is the suffix after that command name. PATH-resolution tests for mounted commands should assert the full argv vector, not just the trailing args. -- Projected native binaries that hit the WASM path must fail with the explicit sidecar-facing code `ERR_NATIVE_BINARY_NOT_SUPPORTED` based on their magic bytes (`ELF`, `Mach-O`, `PE/COFF`) before any `WebAssembly.compile()` attempt; do not broaden regressions to accept fallback `CompileError: WebAssembly.Module()` output. - -## Guest Networking Rules - -- Guest Node `net` Unix-socket support follows the same split as TCP: resolve guest socket paths against `host_dir` mounts when possible, otherwise map them under the VM sandbox root on the host, keep active Unix listeners/sockets in `crates/sidecar/src/service.rs`, and mirror non-mounted listener paths into the kernel VFS so guest `fs` APIs can see the socket file. -- When proving guest `http.request()` uses the kernel socket path instead of the legacy loopback shortcut, point it at a guest `net.createServer()` that speaks raw HTTP. `http.createServer()` can still succeed through the deprecated `net.http_request` loopback dispatch, so a plain TCP listener is the reliable regression target. -- Guest `http.request()` / `http.get()` calls targeting a guest loopback `http.createServer()` must stay on the bridge's raw-socket HTTP path. Do not send `socket._loopbackServer` sockets through the undici dispatcher; the sidecar-managed loopback transport already speaks raw HTTP bytes and the undici path can hang waiting on semantics that never arrive. -- When a guest Node networking port stops using real host listeners, mirror that state in `crates/sidecar/src/service.rs` `ActiveProcess` tracking and consult it from `find_listener`/socket snapshot queries before falling back to `/proc/[pid]/net/*`; procfs only sees host-owned sockets, not sidecar-managed polyfill listeners. -- Sidecar-managed loopback `net.listen` / `dgram.bind` listeners now use guest-port to host-port translation in `crates/sidecar/src/service.rs`: preserve guest-visible loopback addresses/ports in RPC responses and socket snapshots, but use the hidden host-bound port for external host-side probes and test clients. -- V8 `node:dgram` support in `packages/build-tools/bridge-src/` depends on both `loadBuiltinModule("dgram")` and `"dgram"` appearing in `Module.builtinModules`; keep those lists aligned, and keep the generated bridge payloads aligned with the current sidecar RPC contract (`createSocket` object payload, `send` bytes plus `{ address, port }`, `poll` object-or-null responses). -- Sidecar JavaScript networking policy should read internal bootstrap env like `AGENTOS_LOOPBACK_EXEMPT_PORTS` from `VmState.metadata` / `env.*`, not `vm.guest_env`; `guest_env` is permission-filtered and may be empty even when sidecar-only policy still needs the value. -- When adding a new raw V8 bridge method used by WASM host shims, keep `crates/execution/src/wasm.rs`, `crates/execution/src/v8_runtime.rs`, `crates/v8-runtime/src/session.rs`, `crates/bridge/bridge-contract.json`, and `packages/build-tools/bridge-src/` aligned, then rebuild `cargo build -p secure-exec-v8-runtime`; otherwise the method can compile cleanly while still being unavailable at runtime. -- When the embedded V8 runtime is shared across the whole process, V8 session ids must stay globally unique and `JavascriptExecution` teardown must terminate then destroy the session; reusing ids or abruptly dropping a live session can leak state into later tests even when isolated cases pass. -- The direct embedded-runtime path should stay at the `shared_embedded_runtime()` / `EmbeddedV8SessionHandle` boundary in `crates/execution/src/v8_host.rs`; keep `crates/execution`'s local `v8_ipc::BinaryFrame` conversions at that boundary and do not reintroduce a local `UnixStream`/reader-thread transport inside the process. - -## Guest `tls` - -- Guest Node `tls` should stay layered on the guest `net` polyfill rather than importing host `node:tls` directly. -- Client connections must pass a preconnected guest socket into `tls.connect({ socket })`. -- Server handshakes should wrap accepted guest sockets with `new TLSSocket(..., { isServer: true })` and emit `secureConnection` from the wrapped socket's `secure` event. - -## Guest `dns` - -- When a newly allowed Node builtin still has bypass-capable host-owned helpers or constructors (for example `dns.Resolver` / `dns.promises.Resolver`), replace those entrypoints with guest-owned shims or explicit unsupported stubs before adding the builtin to `DEFAULT_ALLOWED_NODE_BUILTINS`; inheriting the host module is only safe for exports that cannot escape the kernel-backed port. -- When adding a Node builtin subpath such as `node:dns/promises`, keep every guest-module surface in sync: `normalize_builtin_specifier()` and `builtin_named_exports()` in `javascript.rs`, `Module.builtinModules` plus `loadBuiltinModule()` in `bridge-src`, the import-cache builtin assets and rewrite table in `node_import_cache.rs`, and the esbuild alias shims under `crates/execution/assets/undici-shims/`. -- Socket-like compatibility shims in `bridge-src` need both `_readableState.endEmitted` and `_readableState.ended`, and they must flip those fields together on EOF and destroy paths; packages like `ssh2`, `ssh2-sftp-client`, and `ws` inspect those internals directly instead of waiting for public stream events. -- `fs.mkdtempSync()` in `bridge-src` should keep Node's six-character alphanumeric suffix shape while sourcing entropy from six random bytes, and it must create the directory without `recursive: true` so existing-path collisions surface as `EEXIST` instead of silently reusing a directory. - -## Python Execution - -- Python execution in `python.rs` should keep `poll_event()` blocked until a real guest-visible event arrives or the caller timeout expires; filtered stderr/control messages are internal noise. -- `wait(None)` should still enforce the per-run `AGENTOS_PYTHON_EXECUTION_TIMEOUT_MS` cap. -- `wait()` should bound accumulated stdout/stderr via the hidden `AGENTOS_PYTHON_OUTPUT_BUFFER_MAX_BYTES` env knob rather than growing buffers without limit. -- Node heap caps from `AGENTOS_PYTHON_MAX_OLD_SPACE_MB` need to apply to both prewarm and execution launches without leaking those control vars into guest `process.env`. -- Warmup marker fingerprints for guest assets must include mutation data (`size` plus `mtime`/`mtime_nsec`), not just inode identity; in-place rewrites of Pyodide or WASM assets can preserve the inode and still need to invalidate prewarm stamps. -- Pyodide bootstrap hardening in `node_import_cache.rs` must stay staged: `globalThis` guards can go in before `loadPyodide()`, but mutating `process` before `loadPyodide()` breaks the bundled Pyodide runtime under Node `--permission`. -- Python RPC shims in `crates/execution/assets/runners/python-runner.mjs` should translate JS bridge failures into Python-native exceptions (`PermissionError`, `FileNotFoundError`, `OSError`) instead of leaking `JsException`, and Python `subprocess.run()` should inherit the VM cwd from sidecar process state rather than Pyodide's internal `/home/pyodide` working directory. -- Treat bundled Pyodide package loading and user-configured `AGENTOS_PYODIDE_PACKAGE_BASE_URL` as separate phases in `python-runner.mjs`: keep `loadPyodide(... packageBaseUrl)` plus the initial `pyodide.loadPackage("micropip")`/bundled preload path pinned to `/__agentos_pyodide`, then switch `pyodide._api.config.packageBaseUrl` afterward for user `micropip.install(...)` URLs. When guest Python needs HTTP wheels, patch `pyodide.http.pyfetch` through the Python `httpRequestSync` bridge so `micropip` obeys sidecar network policy and loopback exemptions instead of bypassing them. -- Guest runtime identity defaults must stay aligned across JS, WASM, and Python: keep `HOME` bound to the kernel user's homedir, keep `PWD` bound to the execution cwd, feed those values into the Pyodide bootstrap env, and make sure Python `execute()` requests still pass through `prepare_guest_runtime_env(...)` instead of bypassing the shared runtime-env assembly. -- The shared runtime env contract also includes a stable guest `PATH` plus internal-env filtering: `prepare_guest_runtime_env(...)` should supply the canonical guest search path, `python-runner.mjs` should expose that `PATH` inside `os.environ`, and the WASM `AGENTOS_GUEST_ENV` payload must strip internal control vars like `AGENTOS_*` / `NODE_SYNC_RPC_*` before they reach guest-visible WASI env. -- Pyodide `micropip` support must keep guest `js` / `pyodide_js` imports blocked for user Python code while exposing only a narrow internal compat surface to `micropip` and `pyodide.http`; widening that exception re-opens host escape hatches. -- `python-runner.mjs` must suppress `loadPyodide()`/micropip progress banners such as `Loading ...` and `Loaded ...` from guest stdout; sidecar callers and tests often parse stdout as program output or JSON, so those bootstrap logs have to stay internal. -- When `python-runner.mjs` or other bundled execution assets change, bump `NODE_IMPORT_CACHE_ASSET_VERSION` in `node_import_cache.rs` if the temp materialization needs to refresh immediately; otherwise stale `/tmp/agentos-node-import-cache-*` contents can mask the update during local test runs. diff --git a/crates/execution/Cargo.toml b/crates/execution/Cargo.toml index fa4c03d3e..347aa1ca2 100644 --- a/crates/execution/Cargo.toml +++ b/crates/execution/Cargo.toml @@ -4,38 +4,10 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Native execution plane scaffold for secure-exec" -build = "build.rs" -# Large Pyodide runtime assets are staged at build time (copied from the -# in-tree assets directory during workspace builds, or downloaded from the -# release CDN when building the published crate) so the packaged crate stays -# under the registry size limit. See build.rs. -exclude = [ - "assets/pyodide/pyodide.asm.wasm", - "assets/pyodide/pyodide.asm.js", - "assets/pyodide/python_stdlib.zip", - "assets/pyodide/numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl", - "assets/pyodide/pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl", -] +description = "secure-exec-execution compatibility shim for agentos-execution" [lib] -doctest = false +name = "secure_exec_execution" [dependencies] -secure-exec-bridge = { workspace = true } -secure-exec-v8-runtime = { workspace = true } -base64 = "0.22" -ciborium = "0.2" -getrandom = "0.2" -nix = { version = "0.29", features = ["fs"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1" -tokio = { version = "1", features = ["rt", "sync", "time"] } -tracing = "0.1" - -[dev-dependencies] -tempfile = "3" -wat = "1" - -[build-dependencies] -secure-exec-build-support = { workspace = true } +agentos_execution = { package = "agentos-execution", path = "../../../agentos/crates/execution", version = "0.0.1" } diff --git a/crates/execution/assets/generated/v8-bridge-zlib.js b/crates/execution/assets/generated/v8-bridge-zlib.js deleted file mode 100644 index 3e6357646..000000000 --- a/crates/execution/assets/generated/v8-bridge-zlib.js +++ /dev/null @@ -1,91 +0,0 @@ -if(typeof globalThis.global==="undefined"){globalThis.global=globalThis;}if(typeof globalThis.process==="undefined"){globalThis.process={env:{},argv:["node"],browser:false,version:"v22.0.0",versions:{node:"22.0.0"},nextTick(callback,...args){return Promise.resolve().then(()=>callback(...args));}};}if(typeof globalThis.TextEncoder==="undefined"){globalThis.TextEncoder=class{encode(value=""){const input=String(value??"");const encoded=unescape(encodeURIComponent(input));const out=new Uint8Array(encoded.length);for(let i=0;isum+(item?.length??0),0);const out=new __SecureExecEarlyBuffer(length);let offset=0;for(const item of list){const chunk=item instanceof Uint8Array?item:__SecureExecEarlyBuffer.from(item);out.set(chunk,offset);offset+=chunk.length;}return out;}static isBuffer(value){return value instanceof Uint8Array;}static byteLength(value,encoding="utf8"){return __SecureExecEarlyBuffer.from(value,encoding).byteLength;}toString(encoding="utf8"){if(encoding==="base64"&&typeof btoa==="function"){let binary="";for(const byte of this){binary+=String.fromCharCode(byte);}return btoa(binary);}if(encoding==="binary"||encoding==="latin1"){let binary="";for(const byte of this){binary+=String.fromCharCode(byte);}return binary;}if(__secureExecTd){return __secureExecTd.decode(this);}return Array.from(this,byte=>String.fromCharCode(byte)).join("");}}globalThis.Buffer=__SecureExecEarlyBuffer;}if(typeof globalThis.performance==="undefined"){const __secureExecPerformanceStart=Date.now();globalThis.performance={now(){return Date.now()-__secureExecPerformanceStart;}};}if(typeof globalThis.performance.markResourceTiming!=="function"){globalThis.performance.markResourceTiming=()=>{};}if(typeof TextEncoder==="undefined"&&typeof globalThis.TextEncoder!=="undefined"){var TextEncoder=globalThis.TextEncoder;}if(typeof TextDecoder==="undefined"&&typeof globalThis.TextDecoder!=="undefined"){var TextDecoder=globalThis.TextDecoder;}if(typeof Buffer==="undefined"&&typeof globalThis.Buffer!=="undefined"){var Buffer=globalThis.Buffer;} -(()=>{var Gd=Object.create;var nn=Object.defineProperty;var $d=Object.getOwnPropertyDescriptor;var Vd=Object.getOwnPropertyNames;var Yd=Object.getPrototypeOf,Kd=Object.prototype.hasOwnProperty;var Xd=(e,r)=>()=>(e&&(r=e(e=0)),r);var y=(e,r)=>()=>(r||e((r={exports:{}}).exports,r),r.exports),Jd=(e,r)=>{for(var t in r)nn(e,t,{get:r[t],enumerable:!0})},tn=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of Vd(r))!Kd.call(e,i)&&i!==t&&nn(e,i,{get:()=>r[i],enumerable:!(n=$d(r,i))||n.enumerable});return e},re=(e,r,t)=>(tn(e,r,"default"),t&&tn(t,r,"default")),ft=(e,r,t)=>(t=e!=null?Gd(Yd(e)):{},tn(r||!e||!e.__esModule?nn(t,"default",{value:e,enumerable:!0}):t,e)),Qd=e=>tn(nn({},"__esModule",{value:!0}),e);var an=y((Um,of)=>{"use strict";of.exports=function(){if(typeof Symbol!="function"||typeof Object.getOwnPropertySymbols!="function")return!1;if(typeof Symbol.iterator=="symbol")return!0;var r={},t=Symbol("test"),n=Object(t);if(typeof t=="string"||Object.prototype.toString.call(t)!=="[object Symbol]"||Object.prototype.toString.call(n)!=="[object Symbol]")return!1;var i=42;r[t]=i;for(var a in r)return!1;if(typeof Object.keys=="function"&&Object.keys(r).length!==0||typeof Object.getOwnPropertyNames=="function"&&Object.getOwnPropertyNames(r).length!==0)return!1;var o=Object.getOwnPropertySymbols(r);if(o.length!==1||o[0]!==t||!Object.prototype.propertyIsEnumerable.call(r,t))return!1;if(typeof Object.getOwnPropertyDescriptor=="function"){var f=Object.getOwnPropertyDescriptor(r,t);if(f.value!==i||f.enumerable!==!0)return!1}return!0}});var ut=y((Cm,ff)=>{"use strict";var ey=an();ff.exports=function(){return ey()&&!!Symbol.toStringTag}});var on=y((zm,uf)=>{"use strict";uf.exports=Object});var sf=y((Zm,lf)=>{"use strict";lf.exports=Error});var hf=y((Wm,cf)=>{"use strict";cf.exports=EvalError});var df=y((Hm,pf)=>{"use strict";pf.exports=RangeError});var vf=y((Gm,yf)=>{"use strict";yf.exports=ReferenceError});var Ci=y(($m,_f)=>{"use strict";_f.exports=SyntaxError});var kr=y((Vm,gf)=>{"use strict";gf.exports=TypeError});var wf=y((Ym,bf)=>{"use strict";bf.exports=URIError});var mf=y((Km,Ef)=>{"use strict";Ef.exports=Math.abs});var xf=y((Xm,Sf)=>{"use strict";Sf.exports=Math.floor});var Rf=y((Jm,Af)=>{"use strict";Af.exports=Math.max});var Tf=y((Qm,Of)=>{"use strict";Of.exports=Math.min});var Nf=y((e1,If)=>{"use strict";If.exports=Math.pow});var Ff=y((r1,Lf)=>{"use strict";Lf.exports=Math.round});var Pf=y((t1,kf)=>{"use strict";kf.exports=Number.isNaN||function(r){return r!==r}});var Mf=y((n1,Df)=>{"use strict";var ry=Pf();Df.exports=function(r){return ry(r)||r===0?r:r<0?-1:1}});var Bf=y((i1,jf)=>{"use strict";jf.exports=Object.getOwnPropertyDescriptor});var rr=y((a1,qf)=>{"use strict";var fn=Bf();if(fn)try{fn([],"length")}catch{fn=null}qf.exports=fn});var lt=y((o1,Uf)=>{"use strict";var un=Object.defineProperty||!1;if(un)try{un({},"a",{value:1})}catch{un=!1}Uf.exports=un});var Zf=y((f1,zf)=>{"use strict";var Cf=typeof Symbol<"u"&&Symbol,ty=an();zf.exports=function(){return typeof Cf!="function"||typeof Symbol!="function"||typeof Cf("foo")!="symbol"||typeof Symbol("bar")!="symbol"?!1:ty()}});var zi=y((u1,Wf)=>{"use strict";Wf.exports=typeof Reflect<"u"&&Reflect.getPrototypeOf||null});var Zi=y((l1,Hf)=>{"use strict";var ny=on();Hf.exports=ny.getPrototypeOf||null});var Vf=y((s1,$f)=>{"use strict";var iy="Function.prototype.bind called on incompatible ",ay=Object.prototype.toString,oy=Math.max,fy="[object Function]",Gf=function(r,t){for(var n=[],i=0;i{"use strict";var sy=Vf();Yf.exports=Function.prototype.bind||sy});var ln=y((h1,Kf)=>{"use strict";Kf.exports=Function.prototype.call});var sn=y((p1,Xf)=>{"use strict";Xf.exports=Function.prototype.apply});var Qf=y((d1,Jf)=>{"use strict";Jf.exports=typeof Reflect<"u"&&Reflect&&Reflect.apply});var Wi=y((y1,eu)=>{"use strict";var cy=Pr(),hy=sn(),py=ln(),dy=Qf();eu.exports=dy||cy.call(py,hy)});var cn=y((v1,ru)=>{"use strict";var yy=Pr(),vy=kr(),_y=ln(),gy=Wi();ru.exports=function(r){if(r.length<1||typeof r[0]!="function")throw new vy("a function is required");return gy(yy,_y,r)}});var fu=y((_1,ou)=>{"use strict";var by=cn(),tu=rr(),iu;try{iu=[].__proto__===Array.prototype}catch(e){if(!e||typeof e!="object"||!("code"in e)||e.code!=="ERR_PROTO_ACCESS")throw e}var Hi=!!iu&&tu&&tu(Object.prototype,"__proto__"),au=Object,nu=au.getPrototypeOf;ou.exports=Hi&&typeof Hi.get=="function"?by([Hi.get]):typeof nu=="function"?function(r){return nu(r==null?r:au(r))}:!1});var hn=y((g1,cu)=>{"use strict";var uu=zi(),lu=Zi(),su=fu();cu.exports=uu?function(r){return uu(r)}:lu?function(r){if(!r||typeof r!="object"&&typeof r!="function")throw new TypeError("getProto: not an object");return lu(r)}:su?function(r){return su(r)}:null});var Gi=y((b1,hu)=>{"use strict";var wy=Function.prototype.call,Ey=Object.prototype.hasOwnProperty,my=Pr();hu.exports=my.call(wy,Ey)});var yn=y((w1,gu)=>{"use strict";var F,Sy=on(),xy=sf(),Ay=hf(),Ry=df(),Oy=vf(),Br=Ci(),jr=kr(),Ty=wf(),Iy=mf(),Ny=xf(),Ly=Rf(),Fy=Tf(),ky=Nf(),Py=Ff(),Dy=Mf(),vu=Function,$i=function(e){try{return vu('"use strict"; return ('+e+").constructor;")()}catch{}},st=rr(),My=lt(),Vi=function(){throw new jr},jy=st?(function(){try{return arguments.callee,Vi}catch{try{return st(arguments,"callee").get}catch{return Vi}}})():Vi,Dr=Zf()(),G=hn(),By=Zi(),qy=zi(),_u=sn(),ct=ln(),Mr={},Uy=typeof Uint8Array>"u"||!G?F:G(Uint8Array),tr={__proto__:null,"%AggregateError%":typeof AggregateError>"u"?F:AggregateError,"%Array%":Array,"%ArrayBuffer%":typeof ArrayBuffer>"u"?F:ArrayBuffer,"%ArrayIteratorPrototype%":Dr&&G?G([][Symbol.iterator]()):F,"%AsyncFromSyncIteratorPrototype%":F,"%AsyncFunction%":Mr,"%AsyncGenerator%":Mr,"%AsyncGeneratorFunction%":Mr,"%AsyncIteratorPrototype%":Mr,"%Atomics%":typeof Atomics>"u"?F:Atomics,"%BigInt%":typeof BigInt>"u"?F:BigInt,"%BigInt64Array%":typeof BigInt64Array>"u"?F:BigInt64Array,"%BigUint64Array%":typeof BigUint64Array>"u"?F:BigUint64Array,"%Boolean%":Boolean,"%DataView%":typeof DataView>"u"?F:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":xy,"%eval%":eval,"%EvalError%":Ay,"%Float16Array%":typeof Float16Array>"u"?F:Float16Array,"%Float32Array%":typeof Float32Array>"u"?F:Float32Array,"%Float64Array%":typeof Float64Array>"u"?F:Float64Array,"%FinalizationRegistry%":typeof FinalizationRegistry>"u"?F:FinalizationRegistry,"%Function%":vu,"%GeneratorFunction%":Mr,"%Int8Array%":typeof Int8Array>"u"?F:Int8Array,"%Int16Array%":typeof Int16Array>"u"?F:Int16Array,"%Int32Array%":typeof Int32Array>"u"?F:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":Dr&&G?G(G([][Symbol.iterator]())):F,"%JSON%":typeof JSON=="object"?JSON:F,"%Map%":typeof Map>"u"?F:Map,"%MapIteratorPrototype%":typeof Map>"u"||!Dr||!G?F:G(new Map()[Symbol.iterator]()),"%Math%":Math,"%Number%":Number,"%Object%":Sy,"%Object.getOwnPropertyDescriptor%":st,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":typeof Promise>"u"?F:Promise,"%Proxy%":typeof Proxy>"u"?F:Proxy,"%RangeError%":Ry,"%ReferenceError%":Oy,"%Reflect%":typeof Reflect>"u"?F:Reflect,"%RegExp%":RegExp,"%Set%":typeof Set>"u"?F:Set,"%SetIteratorPrototype%":typeof Set>"u"||!Dr||!G?F:G(new Set()[Symbol.iterator]()),"%SharedArrayBuffer%":typeof SharedArrayBuffer>"u"?F:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":Dr&&G?G(""[Symbol.iterator]()):F,"%Symbol%":Dr?Symbol:F,"%SyntaxError%":Br,"%ThrowTypeError%":jy,"%TypedArray%":Uy,"%TypeError%":jr,"%Uint8Array%":typeof Uint8Array>"u"?F:Uint8Array,"%Uint8ClampedArray%":typeof Uint8ClampedArray>"u"?F:Uint8ClampedArray,"%Uint16Array%":typeof Uint16Array>"u"?F:Uint16Array,"%Uint32Array%":typeof Uint32Array>"u"?F:Uint32Array,"%URIError%":Ty,"%WeakMap%":typeof WeakMap>"u"?F:WeakMap,"%WeakRef%":typeof WeakRef>"u"?F:WeakRef,"%WeakSet%":typeof WeakSet>"u"?F:WeakSet,"%Function.prototype.call%":ct,"%Function.prototype.apply%":_u,"%Object.defineProperty%":My,"%Object.getPrototypeOf%":By,"%Math.abs%":Iy,"%Math.floor%":Ny,"%Math.max%":Ly,"%Math.min%":Fy,"%Math.pow%":ky,"%Math.round%":Py,"%Math.sign%":Dy,"%Reflect.getPrototypeOf%":qy};if(G)try{null.error}catch(e){pu=G(G(e)),tr["%Error.prototype%"]=pu}var pu,Cy=function e(r){var t;if(r==="%AsyncFunction%")t=$i("async function () {}");else if(r==="%GeneratorFunction%")t=$i("function* () {}");else if(r==="%AsyncGeneratorFunction%")t=$i("async function* () {}");else if(r==="%AsyncGenerator%"){var n=e("%AsyncGeneratorFunction%");n&&(t=n.prototype)}else if(r==="%AsyncIteratorPrototype%"){var i=e("%AsyncGenerator%");i&&G&&(t=G(i.prototype))}return tr[r]=t,t},du={__proto__:null,"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},ht=Pr(),pn=Gi(),zy=ht.call(ct,Array.prototype.concat),Zy=ht.call(_u,Array.prototype.splice),yu=ht.call(ct,String.prototype.replace),dn=ht.call(ct,String.prototype.slice),Wy=ht.call(ct,RegExp.prototype.exec),Hy=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,Gy=/\\(\\)?/g,$y=function(r){var t=dn(r,0,1),n=dn(r,-1);if(t==="%"&&n!=="%")throw new Br("invalid intrinsic syntax, expected closing `%`");if(n==="%"&&t!=="%")throw new Br("invalid intrinsic syntax, expected opening `%`");var i=[];return yu(r,Hy,function(a,o,f,s){i[i.length]=f?yu(s,Gy,"$1"):o||a}),i},Vy=function(r,t){var n=r,i;if(pn(du,n)&&(i=du[n],n="%"+i[0]+"%"),pn(tr,n)){var a=tr[n];if(a===Mr&&(a=Cy(n)),typeof a>"u"&&!t)throw new jr("intrinsic "+r+" exists, but is not available. Please file an issue!");return{alias:i,name:n,value:a}}throw new Br("intrinsic "+r+" does not exist!")};gu.exports=function(r,t){if(typeof r!="string"||r.length===0)throw new jr("intrinsic name must be a non-empty string");if(arguments.length>1&&typeof t!="boolean")throw new jr('"allowMissing" argument must be a boolean');if(Wy(/^%?[^%]*%?$/,r)===null)throw new Br("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var n=$y(r),i=n.length>0?n[0]:"",a=Vy("%"+i+"%",t),o=a.name,f=a.value,s=!1,u=a.alias;u&&(i=u[0],Zy(n,zy([0,1],u)));for(var l=1,c=!0;l=n.length){var _=st(f,p);c=!!_,c&&"get"in _&&!("originalValue"in _.get)?f=_.get:f=f[p]}else c=pn(f,p),f=f[p];c&&!s&&(tr[o]=f)}}return f}});var nr=y((E1,Eu)=>{"use strict";var bu=yn(),wu=cn(),Yy=wu([bu("%String.prototype.indexOf%")]);Eu.exports=function(r,t){var n=bu(r,!!t);return typeof n=="function"&&Yy(r,".prototype.")>-1?wu([n]):n}});var xu=y((m1,Su)=>{"use strict";var Ky=ut()(),Xy=nr(),Yi=Xy("Object.prototype.toString"),vn=function(r){return Ky&&r&&typeof r=="object"&&Symbol.toStringTag in r?!1:Yi(r)==="[object Arguments]"},mu=function(r){return vn(r)?!0:r!==null&&typeof r=="object"&&"length"in r&&typeof r.length=="number"&&r.length>=0&&Yi(r)!=="[object Array]"&&"callee"in r&&Yi(r.callee)==="[object Function]"},Jy=(function(){return vn(arguments)})();vn.isLegacyArguments=mu;Su.exports=Jy?vn:mu});var Nu=y((S1,Iu)=>{"use strict";var Au=nr(),Qy=ut()(),e0=Gi(),r0=rr(),Ji;Qy?(Ru=Au("RegExp.prototype.exec"),Ki={},_n=function(){throw Ki},Xi={toString:_n,valueOf:_n},typeof Symbol.toPrimitive=="symbol"&&(Xi[Symbol.toPrimitive]=_n),Ji=function(r){if(!r||typeof r!="object")return!1;var t=r0(r,"lastIndex"),n=t&&e0(t,"value");if(!n)return!1;try{Ru(r,Xi)}catch(i){return i===Ki}}):(Ou=Au("Object.prototype.toString"),Tu="[object RegExp]",Ji=function(r){return!r||typeof r!="object"&&typeof r!="function"?!1:Ou(r)===Tu});var Ru,Ki,_n,Xi,Ou,Tu;Iu.exports=Ji});var Fu=y((x1,Lu)=>{"use strict";var t0=nr(),n0=Nu(),i0=t0("RegExp.prototype.exec"),a0=kr();Lu.exports=function(r){if(!n0(r))throw new a0("`regex` must be a RegExp");return function(n){return i0(r,n)!==null}}});var Pu=y((A1,ku)=>{"use strict";var o0=function*(){}.constructor;ku.exports=()=>o0});var Bu=y((R1,ju)=>{"use strict";var Mu=nr(),f0=Fu(),u0=f0(/^\s*(?:function)?\*/),l0=ut()(),Du=hn(),s0=Mu("Object.prototype.toString"),c0=Mu("Function.prototype.toString"),h0=Pu();ju.exports=function(r){if(typeof r!="function")return!1;if(u0(c0(r)))return!0;if(!l0){var t=s0(r);return t==="[object GeneratorFunction]"}if(!Du)return!1;var n=h0();return n&&Du(r)===n.prototype}});var zu=y((O1,Cu)=>{"use strict";var Uu=Function.prototype.toString,qr=typeof Reflect=="object"&&Reflect!==null&&Reflect.apply,ea,gn;if(typeof qr=="function"&&typeof Object.defineProperty=="function")try{ea=Object.defineProperty({},"length",{get:function(){throw gn}}),gn={},qr(function(){throw 42},null,ea)}catch(e){e!==gn&&(qr=null)}else qr=null;var p0=/^\s*class\b/,ra=function(r){try{var t=Uu.call(r);return p0.test(t)}catch{return!1}},Qi=function(r){try{return ra(r)?!1:(Uu.call(r),!0)}catch{return!1}},bn=Object.prototype.toString,d0="[object Object]",y0="[object Function]",v0="[object GeneratorFunction]",_0="[object HTMLAllCollection]",g0="[object HTML document.all class]",b0="[object HTMLCollection]",w0=typeof Symbol=="function"&&!!Symbol.toStringTag,E0=!(0 in[,]),ta=function(){return!1};typeof document=="object"&&(qu=document.all,bn.call(qu)===bn.call(document.all)&&(ta=function(r){if((E0||!r)&&(typeof r>"u"||typeof r=="object"))try{var t=bn.call(r);return(t===_0||t===g0||t===b0||t===d0)&&r("")==null}catch{}return!1}));var qu;Cu.exports=qr?function(r){if(ta(r))return!0;if(!r||typeof r!="function"&&typeof r!="object")return!1;try{qr(r,null,ea)}catch(t){if(t!==gn)return!1}return!ra(r)&&Qi(r)}:function(r){if(ta(r))return!0;if(!r||typeof r!="function"&&typeof r!="object")return!1;if(w0)return Qi(r);if(ra(r))return!1;var t=bn.call(r);return t!==y0&&t!==v0&&!/^\[object HTML/.test(t)?!1:Qi(r)}});var Hu=y((T1,Wu)=>{"use strict";var m0=zu(),S0=Object.prototype.toString,Zu=Object.prototype.hasOwnProperty,x0=function(r,t,n){for(var i=0,a=r.length;i=3&&(i=n),O0(r)?x0(r,t,i):typeof r=="string"?A0(r,t,i):R0(r,t,i)}});var $u=y((I1,Gu)=>{"use strict";Gu.exports=["Float16Array","Float32Array","Float64Array","Int8Array","Int16Array","Int32Array","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array"]});var Yu=y((N1,Vu)=>{"use strict";var na=$u(),T0=globalThis;Vu.exports=function(){for(var r=[],t=0;t{"use strict";var Ku=lt(),I0=Ci(),Ur=kr(),Xu=rr();Ju.exports=function(r,t,n){if(!r||typeof r!="object"&&typeof r!="function")throw new Ur("`obj` must be an object or a function`");if(typeof t!="string"&&typeof t!="symbol")throw new Ur("`property` must be a string or a symbol`");if(arguments.length>3&&typeof arguments[3]!="boolean"&&arguments[3]!==null)throw new Ur("`nonEnumerable`, if provided, must be a boolean or null");if(arguments.length>4&&typeof arguments[4]!="boolean"&&arguments[4]!==null)throw new Ur("`nonWritable`, if provided, must be a boolean or null");if(arguments.length>5&&typeof arguments[5]!="boolean"&&arguments[5]!==null)throw new Ur("`nonConfigurable`, if provided, must be a boolean or null");if(arguments.length>6&&typeof arguments[6]!="boolean")throw new Ur("`loose`, if provided, must be a boolean");var i=arguments.length>3?arguments[3]:null,a=arguments.length>4?arguments[4]:null,o=arguments.length>5?arguments[5]:null,f=arguments.length>6?arguments[6]:!1,s=!!Xu&&Xu(r,t);if(Ku)Ku(r,t,{configurable:o===null&&s?s.configurable:!o,enumerable:i===null&&s?s.enumerable:!i,value:n,writable:a===null&&s?s.writable:!a});else if(f||!i&&!a&&!o)r[t]=n;else throw new I0("This environment does not support defining a property as non-configurable, non-writable, or non-enumerable.")}});var oa=y((F1,el)=>{"use strict";var aa=lt(),Qu=function(){return!!aa};Qu.hasArrayLengthDefineBug=function(){if(!aa)return null;try{return aa([],"length",{value:1}).length!==1}catch{return!0}};el.exports=Qu});var al=y((k1,il)=>{"use strict";var N0=yn(),rl=ia(),L0=oa()(),tl=rr(),nl=kr(),F0=N0("%Math.floor%");il.exports=function(r,t){if(typeof r!="function")throw new nl("`fn` is not a function");if(typeof t!="number"||t<0||t>4294967295||F0(t)!==t)throw new nl("`length` must be a positive 32-bit integer");var n=arguments.length>2&&!!arguments[2],i=!0,a=!0;if("length"in r&&tl){var o=tl(r,"length");o&&!o.configurable&&(i=!1),o&&!o.writable&&(a=!1)}return(i||a||!n)&&(L0?rl(r,"length",t,!0,!0):rl(r,"length",t)),r}});var fl=y((P1,ol)=>{"use strict";var k0=Pr(),P0=sn(),D0=Wi();ol.exports=function(){return D0(k0,P0,arguments)}});var pt=y((D1,wn)=>{"use strict";var M0=al(),ul=lt(),j0=cn(),ll=fl();wn.exports=function(r){var t=j0(arguments),n=r.length-(arguments.length-1);return M0(t,1+(n>0?n:0),!0)};ul?ul(wn.exports,"apply",{value:ll}):wn.exports.apply=ll});var sa=y((M1,pl)=>{"use strict";var Sn=Hu(),B0=Yu(),sl=pt(),ua=nr(),mn=rr(),En=hn(),q0=ua("Object.prototype.toString"),hl=ut()(),cl=globalThis,fa=B0(),la=ua("String.prototype.slice"),U0=ua("Array.prototype.indexOf",!0)||function(r,t){for(var n=0;n-1?t:t!=="Object"?!1:z0(r)}return mn?C0(r):null}});var yl=y((j1,dl)=>{"use strict";var Z0=sa();dl.exports=function(r){return!!Z0(r)}});var Il=y(k=>{"use strict";var W0=xu(),H0=Bu(),_e=sa(),vl=yl();function Cr(e){return e.call.bind(e)}var _l=typeof BigInt<"u",gl=typeof Symbol<"u",fe=Cr(Object.prototype.toString),G0=Cr(Number.prototype.valueOf),$0=Cr(String.prototype.valueOf),V0=Cr(Boolean.prototype.valueOf);_l&&(bl=Cr(BigInt.prototype.valueOf));var bl;gl&&(wl=Cr(Symbol.prototype.valueOf));var wl;function yt(e,r){if(typeof e!="object")return!1;try{return r(e),!0}catch{return!1}}k.isArgumentsObject=W0;k.isGeneratorFunction=H0;k.isTypedArray=vl;function Y0(e){return typeof Promise<"u"&&e instanceof Promise||e!==null&&typeof e=="object"&&typeof e.then=="function"&&typeof e.catch=="function"}k.isPromise=Y0;function K0(e){return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?ArrayBuffer.isView(e):vl(e)||ml(e)}k.isArrayBufferView=K0;function X0(e){return _e(e)==="Uint8Array"}k.isUint8Array=X0;function J0(e){return _e(e)==="Uint8ClampedArray"}k.isUint8ClampedArray=J0;function Q0(e){return _e(e)==="Uint16Array"}k.isUint16Array=Q0;function ev(e){return _e(e)==="Uint32Array"}k.isUint32Array=ev;function rv(e){return _e(e)==="Int8Array"}k.isInt8Array=rv;function tv(e){return _e(e)==="Int16Array"}k.isInt16Array=tv;function nv(e){return _e(e)==="Int32Array"}k.isInt32Array=nv;function iv(e){return _e(e)==="Float32Array"}k.isFloat32Array=iv;function av(e){return _e(e)==="Float64Array"}k.isFloat64Array=av;function ov(e){return _e(e)==="BigInt64Array"}k.isBigInt64Array=ov;function fv(e){return _e(e)==="BigUint64Array"}k.isBigUint64Array=fv;function An(e){return fe(e)==="[object Map]"}An.working=typeof Map<"u"&&An(new Map);function uv(e){return typeof Map>"u"?!1:An.working?An(e):e instanceof Map}k.isMap=uv;function Rn(e){return fe(e)==="[object Set]"}Rn.working=typeof Set<"u"&&Rn(new Set);function lv(e){return typeof Set>"u"?!1:Rn.working?Rn(e):e instanceof Set}k.isSet=lv;function On(e){return fe(e)==="[object WeakMap]"}On.working=typeof WeakMap<"u"&&On(new WeakMap);function sv(e){return typeof WeakMap>"u"?!1:On.working?On(e):e instanceof WeakMap}k.isWeakMap=sv;function ha(e){return fe(e)==="[object WeakSet]"}ha.working=typeof WeakSet<"u"&&ha(new WeakSet);function cv(e){return ha(e)}k.isWeakSet=cv;function Tn(e){return fe(e)==="[object ArrayBuffer]"}Tn.working=typeof ArrayBuffer<"u"&&Tn(new ArrayBuffer);function El(e){return typeof ArrayBuffer>"u"?!1:Tn.working?Tn(e):e instanceof ArrayBuffer}k.isArrayBuffer=El;function In(e){return fe(e)==="[object DataView]"}In.working=typeof ArrayBuffer<"u"&&typeof DataView<"u"&&In(new DataView(new ArrayBuffer(1),0,1));function ml(e){return typeof DataView>"u"?!1:In.working?In(e):e instanceof DataView}k.isDataView=ml;var ca=typeof SharedArrayBuffer<"u"?SharedArrayBuffer:void 0;function dt(e){return fe(e)==="[object SharedArrayBuffer]"}function Sl(e){return typeof ca>"u"?!1:(typeof dt.working>"u"&&(dt.working=dt(new ca)),dt.working?dt(e):e instanceof ca)}k.isSharedArrayBuffer=Sl;function hv(e){return fe(e)==="[object AsyncFunction]"}k.isAsyncFunction=hv;function pv(e){return fe(e)==="[object Map Iterator]"}k.isMapIterator=pv;function dv(e){return fe(e)==="[object Set Iterator]"}k.isSetIterator=dv;function yv(e){return fe(e)==="[object Generator]"}k.isGeneratorObject=yv;function vv(e){return fe(e)==="[object WebAssembly.Module]"}k.isWebAssemblyCompiledModule=vv;function xl(e){return yt(e,G0)}k.isNumberObject=xl;function Al(e){return yt(e,$0)}k.isStringObject=Al;function Rl(e){return yt(e,V0)}k.isBooleanObject=Rl;function Ol(e){return _l&&yt(e,bl)}k.isBigIntObject=Ol;function Tl(e){return gl&&yt(e,wl)}k.isSymbolObject=Tl;function _v(e){return xl(e)||Al(e)||Rl(e)||Ol(e)||Tl(e)}k.isBoxedPrimitive=_v;function gv(e){return typeof Uint8Array<"u"&&(El(e)||Sl(e))}k.isAnyArrayBuffer=gv;["isProxy","isExternal","isModuleNamespaceObject"].forEach(function(e){Object.defineProperty(k,e,{enumerable:!1,value:function(){return!1}})})});var Ll=y((q1,Nl)=>{Nl.exports=function(r){return r&&typeof r=="object"&&typeof r.copy=="function"&&typeof r.fill=="function"&&typeof r.readUInt8=="function"}});var Be=y((U1,pa)=>{typeof Object.create=="function"?pa.exports=function(r,t){t&&(r.super_=t,r.prototype=Object.create(t.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}))}:pa.exports=function(r,t){if(t){r.super_=t;var n=function(){};n.prototype=t.prototype,r.prototype=new n,r.prototype.constructor=r}}});var Se=y(P=>{var Fl=Object.getOwnPropertyDescriptors||function(r){for(var t=Object.keys(r),n={},i=0;i=i)return f;switch(f){case"%s":return String(n[t++]);case"%d":return Number(n[t++]);case"%j":try{return JSON.stringify(n[t++])}catch{return"[Circular]"}default:return f}}),o=n[t];t"u")return function(){return P.deprecate(e,r).apply(this,arguments)};var t=!1;function n(){if(!t){if(process.throwDeprecation)throw new Error(r);process.traceDeprecation?console.trace(r):console.error(r),t=!0}return e.apply(this,arguments)}return n};var Nn={},kl=/^$/;process.env.NODE_DEBUG&&(Ln=process.env.NODE_DEBUG,Ln=Ln.replace(/[|\\{}()[\]^$+?.]/g,"\\$&").replace(/\*/g,".*").replace(/,/g,"$|^").toUpperCase(),kl=new RegExp("^"+Ln+"$","i"));var Ln;P.debuglog=function(e){if(e=e.toUpperCase(),!Nn[e])if(kl.test(e)){var r=process.pid;Nn[e]=function(){var t=P.format.apply(P,arguments);console.error("%s %d: %s",e,r,t)}}else Nn[e]=function(){};return Nn[e]};function qe(e,r){var t={seen:[],stylize:Ev};return arguments.length>=3&&(t.depth=arguments[2]),arguments.length>=4&&(t.colors=arguments[3]),_a(r)?t.showHidden=r:r&&P._extend(t,r),ar(t.showHidden)&&(t.showHidden=!1),ar(t.depth)&&(t.depth=2),ar(t.colors)&&(t.colors=!1),ar(t.customInspect)&&(t.customInspect=!0),t.colors&&(t.stylize=wv),kn(t,e,t.depth)}P.inspect=qe;qe.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]};qe.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"};function wv(e,r){var t=qe.styles[r];return t?"\x1B["+qe.colors[t][0]+"m"+e+"\x1B["+qe.colors[t][1]+"m":e}function Ev(e,r){return e}function mv(e){var r={};return e.forEach(function(t,n){r[t]=!0}),r}function kn(e,r,t){if(e.customInspect&&r&&Fn(r.inspect)&&r.inspect!==P.inspect&&!(r.constructor&&r.constructor.prototype===r)){var n=r.inspect(t,e);return Mn(n)||(n=kn(e,n,t)),n}var i=Sv(e,r);if(i)return i;var a=Object.keys(r),o=mv(a);if(e.showHidden&&(a=Object.getOwnPropertyNames(r)),_t(r)&&(a.indexOf("message")>=0||a.indexOf("description")>=0))return da(r);if(a.length===0){if(Fn(r)){var f=r.name?": "+r.name:"";return e.stylize("[Function"+f+"]","special")}if(vt(r))return e.stylize(RegExp.prototype.toString.call(r),"regexp");if(Pn(r))return e.stylize(Date.prototype.toString.call(r),"date");if(_t(r))return da(r)}var s="",u=!1,l=["{","}"];if(Pl(r)&&(u=!0,l=["[","]"]),Fn(r)){var c=r.name?": "+r.name:"";s=" [Function"+c+"]"}if(vt(r)&&(s=" "+RegExp.prototype.toString.call(r)),Pn(r)&&(s=" "+Date.prototype.toUTCString.call(r)),_t(r)&&(s=" "+da(r)),a.length===0&&(!u||r.length==0))return l[0]+s+l[1];if(t<0)return vt(r)?e.stylize(RegExp.prototype.toString.call(r),"regexp"):e.stylize("[Object]","special");e.seen.push(r);var p;return u?p=xv(e,r,t,o,a):p=a.map(function(h){return va(e,r,t,o,h,u)}),e.seen.pop(),Av(p,s,l)}function Sv(e,r){if(ar(r))return e.stylize("undefined","undefined");if(Mn(r)){var t="'"+JSON.stringify(r).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(t,"string")}if(Dl(r))return e.stylize(""+r,"number");if(_a(r))return e.stylize(""+r,"boolean");if(Dn(r))return e.stylize("null","null")}function da(e){return"["+Error.prototype.toString.call(e)+"]"}function xv(e,r,t,n,i){for(var a=[],o=0,f=r.length;o-1&&(a?f=f.split(` -`).map(function(u){return" "+u}).join(` -`).slice(2):f=` -`+f.split(` -`).map(function(u){return" "+u}).join(` -`))):f=e.stylize("[Circular]","special")),ar(o)){if(a&&i.match(/^\d+$/))return f;o=JSON.stringify(""+i),o.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(o=o.slice(1,-1),o=e.stylize(o,"name")):(o=o.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),o=e.stylize(o,"string"))}return o+": "+f}function Av(e,r,t){var n=0,i=e.reduce(function(a,o){return n++,o.indexOf(` -`)>=0&&n++,a+o.replace(/\u001b\[\d\d?m/g,"").length+1},0);return i>60?t[0]+(r===""?"":r+` - `)+" "+e.join(`, - `)+" "+t[1]:t[0]+r+" "+e.join(", ")+" "+t[1]}P.types=Il();function Pl(e){return Array.isArray(e)}P.isArray=Pl;function _a(e){return typeof e=="boolean"}P.isBoolean=_a;function Dn(e){return e===null}P.isNull=Dn;function Rv(e){return e==null}P.isNullOrUndefined=Rv;function Dl(e){return typeof e=="number"}P.isNumber=Dl;function Mn(e){return typeof e=="string"}P.isString=Mn;function Ov(e){return typeof e=="symbol"}P.isSymbol=Ov;function ar(e){return e===void 0}P.isUndefined=ar;function vt(e){return zr(e)&&ga(e)==="[object RegExp]"}P.isRegExp=vt;P.types.isRegExp=vt;function zr(e){return typeof e=="object"&&e!==null}P.isObject=zr;function Pn(e){return zr(e)&&ga(e)==="[object Date]"}P.isDate=Pn;P.types.isDate=Pn;function _t(e){return zr(e)&&(ga(e)==="[object Error]"||e instanceof Error)}P.isError=_t;P.types.isNativeError=_t;function Fn(e){return typeof e=="function"}P.isFunction=Fn;function Tv(e){return e===null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"||typeof e=="symbol"||typeof e>"u"}P.isPrimitive=Tv;P.isBuffer=Ll();function ga(e){return Object.prototype.toString.call(e)}function ya(e){return e<10?"0"+e.toString(10):e.toString(10)}var Iv=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function Nv(){var e=new Date,r=[ya(e.getHours()),ya(e.getMinutes()),ya(e.getSeconds())].join(":");return[e.getDate(),Iv[e.getMonth()],r].join(" ")}P.log=function(){console.log("%s - %s",Nv(),P.format.apply(P,arguments))};P.inherits=Be();P._extend=function(e,r){if(!r||!zr(r))return e;for(var t=Object.keys(r),n=t.length;n--;)e[t[n]]=r[t[n]];return e};function Ml(e,r){return Object.prototype.hasOwnProperty.call(e,r)}var ir=typeof Symbol<"u"?Symbol("util.promisify.custom"):void 0;P.promisify=function(r){if(typeof r!="function")throw new TypeError('The "original" argument must be of type Function');if(ir&&r[ir]){var t=r[ir];if(typeof t!="function")throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(t,ir,{value:t,enumerable:!1,writable:!1,configurable:!0}),t}function t(){for(var n,i,a=new Promise(function(s,u){n=s,i=u}),o=[],f=0;f{"use strict";function Ue(e){"@babel/helpers - typeof";return Ue=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(r){return typeof r}:function(r){return r&&typeof Symbol=="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},Ue(e)}function jl(e,r){for(var t=0;t"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function jn(e){return jn=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},jn(e)}var ql={},Zr,ba;function gt(e,r,t){t||(t=Error);function n(a,o,f){return typeof r=="string"?r:r(a,o,f)}var i=(function(a){jv(f,a);var o=Bv(f);function f(s,u,l){var c;return Mv(this,f),c=o.call(this,n(s,u,l)),c.code=e,c}return kv(f)})(t);ql[e]=i}function Bl(e,r){if(Array.isArray(e)){var t=e.length;return e=e.map(function(n){return String(n)}),t>2?"one of ".concat(r," ").concat(e.slice(0,t-1).join(", "),", or ")+e[t-1]:t===2?"one of ".concat(r," ").concat(e[0]," or ").concat(e[1]):"of ".concat(r," ").concat(e[0])}else return"of ".concat(r," ").concat(String(e))}function zv(e,r,t){return e.substr(!t||t<0?0:+t,r.length)===r}function Zv(e,r,t){return(t===void 0||t>e.length)&&(t=e.length),e.substring(t-r.length,t)===r}function Wv(e,r,t){return typeof t!="number"&&(t=0),t+r.length>e.length?!1:e.indexOf(r,t)!==-1}gt("ERR_AMBIGUOUS_ARGUMENT",'The "%s" argument is ambiguous. %s',TypeError);gt("ERR_INVALID_ARG_TYPE",function(e,r,t){Zr===void 0&&(Zr=Wr()),Zr(typeof e=="string","'name' must be a string");var n;typeof r=="string"&&zv(r,"not ")?(n="must not be",r=r.replace(/^not /,"")):n="must be";var i;if(Zv(e," argument"))i="The ".concat(e," ").concat(n," ").concat(Bl(r,"type"));else{var a=Wv(e,".")?"property":"argument";i='The "'.concat(e,'" ').concat(a," ").concat(n," ").concat(Bl(r,"type"))}return i+=". Received type ".concat(Ue(t)),i},TypeError);gt("ERR_INVALID_ARG_VALUE",function(e,r){var t=arguments.length>2&&arguments[2]!==void 0?arguments[2]:"is invalid";ba===void 0&&(ba=Se());var n=ba.inspect(r);return n.length>128&&(n="".concat(n.slice(0,128),"...")),"The argument '".concat(e,"' ").concat(t,". Received ").concat(n)},TypeError,RangeError);gt("ERR_INVALID_RETURN_VALUE",function(e,r,t){var n;return t&&t.constructor&&t.constructor.name?n="instance of ".concat(t.constructor.name):n="type ".concat(Ue(t)),"Expected ".concat(e,' to be returned from the "').concat(r,'"')+" function but got ".concat(n,".")},TypeError);gt("ERR_MISSING_ARGS",function(){for(var e=arguments.length,r=new Array(e),t=0;t0,"At least one arg needs to be specified");var n="The ",i=r.length;switch(r=r.map(function(a){return'"'.concat(a,'"')}),i){case 1:n+="".concat(r[0]," argument");break;case 2:n+="".concat(r[0]," and ").concat(r[1]," arguments");break;default:n+=r.slice(0,i-1).join(", "),n+=", and ".concat(r[i-1]," arguments");break}return"".concat(n," must be specified")},TypeError);Ul.exports.codes=ql});var Kl=y((Z1,Yl)=>{"use strict";function Cl(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),t.push.apply(t,n)}return t}function zl(e){for(var r=1;r"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function Xv(e){return Function.toString.call(e).indexOf("[native code]")!==-1}function mt(e,r){return mt=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(n,i){return n.__proto__=i,n},mt(e,r)}function St(e){return St=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},St(e)}function te(e){"@babel/helpers - typeof";return te=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(r){return typeof r}:function(r){return r&&typeof Symbol=="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},te(e)}var Jv=Se(),xa=Jv.inspect,Qv=Ea(),e_=Qv.codes.ERR_INVALID_ARG_TYPE;function Wl(e,r,t){return(t===void 0||t>e.length)&&(t=e.length),e.substring(t-r.length,t)===r}function r_(e,r){if(r=Math.floor(r),e.length==0||r==0)return"";var t=e.length*r;for(r=Math.floor(Math.log(r)/Math.log(2));r;)e+=e,r--;return e+=e.substring(0,t-e.length),e}var ge="",bt="",wt="",V="",or={deepStrictEqual:"Expected values to be strictly deep-equal:",strictEqual:"Expected values to be strictly equal:",strictEqualObject:'Expected "actual" to be reference-equal to "expected":',deepEqual:"Expected values to be loosely deep-equal:",equal:"Expected values to be loosely equal:",notDeepStrictEqual:'Expected "actual" not to be strictly deep-equal to:',notStrictEqual:'Expected "actual" to be strictly unequal to:',notStrictEqualObject:'Expected "actual" not to be reference-equal to "expected":',notDeepEqual:'Expected "actual" not to be loosely deep-equal to:',notEqual:'Expected "actual" to be loosely unequal to:',notIdentical:"Values identical but not reference-equal:"},t_=10;function Hl(e){var r=Object.keys(e),t=Object.create(Object.getPrototypeOf(e));return r.forEach(function(n){t[n]=e[n]}),Object.defineProperty(t,"message",{value:e.message}),t}function Et(e){return xa(e,{compact:!1,customInspect:!1,depth:1e3,maxArrayLength:1/0,showHidden:!1,breakLength:1/0,showProxy:!1,sorted:!0,getters:!0})}function n_(e,r,t){var n="",i="",a=0,o="",f=!1,s=Et(e),u=s.split(` -`),l=Et(r).split(` -`),c=0,p="";if(t==="strictEqual"&&te(e)==="object"&&te(r)==="object"&&e!==null&&r!==null&&(t="strictEqualObject"),u.length===1&&l.length===1&&u[0]!==l[0]){var h=u[0].length+l[0].length;if(h<=t_){if((te(e)!=="object"||e===null)&&(te(r)!=="object"||r===null)&&(e!==0||r!==0))return"".concat(or[t],` - -`)+"".concat(u[0]," !== ").concat(l[0],` -`)}else if(t!=="strictEqualObject"){var v=process.stderr&&process.stderr.isTTY?process.stderr.columns:80;if(h2&&(p=` - `.concat(r_(" ",c),"^"),c=0)}}}for(var _=u[u.length-1],m=l[l.length-1];_===m&&(c++<2?o=` - `.concat(_).concat(o):n=_,u.pop(),l.pop(),!(u.length===0||l.length===0));)_=u[u.length-1],m=l[l.length-1];var w=Math.max(u.length,l.length);if(w===0){var L=s.split(` -`);if(L.length>30)for(L[26]="".concat(ge,"...").concat(V);L.length>27;)L.pop();return"".concat(or.notIdentical,` - -`).concat(L.join(` -`),` -`)}c>3&&(o=` -`.concat(ge,"...").concat(V).concat(o),f=!0),n!==""&&(o=` - `.concat(n).concat(o),n="");var A=0,T=or[t]+` -`.concat(bt,"+ actual").concat(V," ").concat(wt,"- expected").concat(V),b=" ".concat(ge,"...").concat(V," Lines skipped");for(c=0;c1&&c>2&&(R>4?(i+=` -`.concat(ge,"...").concat(V),f=!0):R>3&&(i+=` - `.concat(l[c-2]),A++),i+=` - `.concat(l[c-1]),A++),a=c,n+=` -`.concat(wt,"-").concat(V," ").concat(l[c]),A++;else if(l.length1&&c>2&&(R>4?(i+=` -`.concat(ge,"...").concat(V),f=!0):R>3&&(i+=` - `.concat(u[c-2]),A++),i+=` - `.concat(u[c-1]),A++),a=c,i+=` -`.concat(bt,"+").concat(V," ").concat(u[c]),A++;else{var I=l[c],S=u[c],D=S!==I&&(!Wl(S,",")||S.slice(0,-1)!==I);D&&Wl(I,",")&&I.slice(0,-1)===S&&(D=!1,S+=","),D?(R>1&&c>2&&(R>4?(i+=` -`.concat(ge,"...").concat(V),f=!0):R>3&&(i+=` - `.concat(u[c-2]),A++),i+=` - `.concat(u[c-1]),A++),a=c,i+=` -`.concat(bt,"+").concat(V," ").concat(S),n+=` -`.concat(wt,"-").concat(V," ").concat(I),A+=2):(i+=n,n="",(R===1||c===0)&&(i+=` - `.concat(S),A++))}if(A>20&&c30)for(h[26]="".concat(ge,"...").concat(V);h.length>27;)h.pop();h.length===1?a=t.call(this,"".concat(p," ").concat(h[0])):a=t.call(this,"".concat(p,` - -`).concat(h.join(` -`),` -`))}else{var v=Et(u),_="",m=or[f];f==="notDeepEqual"||f==="notEqual"?(v="".concat(or[f],` - -`).concat(v),v.length>1024&&(v="".concat(v.slice(0,1021),"..."))):(_="".concat(Et(l)),v.length>512&&(v="".concat(v.slice(0,509),"...")),_.length>512&&(_="".concat(_.slice(0,509),"...")),f==="deepEqual"||f==="equal"?v="".concat(m,` - -`).concat(v,` - -should equal - -`):_=" ".concat(f," ").concat(_)),a=t.call(this,"".concat(v).concat(_))}return Error.stackTraceLimit=c,a.generatedMessage=!o,Object.defineProperty(ma(a),"name",{value:"AssertionError [ERR_ASSERTION]",enumerable:!1,writable:!0,configurable:!0}),a.code="ERR_ASSERTION",a.actual=u,a.expected=l,a.operator=f,Error.captureStackTrace&&Error.captureStackTrace(ma(a),s),a.stack,a.name="AssertionError",$l(a)}return $v(n,[{key:"toString",value:function(){return"".concat(this.name," [").concat(this.code,"]: ").concat(this.message)}},{key:r,value:function(a,o){return xa(this,zl(zl({},o),{},{customInspect:!1,depth:0}))}}]),n})(Sa(Error),xa.custom);Yl.exports=i_});var Aa=y((W1,Jl)=>{"use strict";var Xl=Object.prototype.toString;Jl.exports=function(r){var t=Xl.call(r),n=t==="[object Arguments]";return n||(n=t!=="[object Array]"&&r!==null&&typeof r=="object"&&typeof r.length=="number"&&r.length>=0&&Xl.call(r.callee)==="[object Function]"),n}});var fs=y((H1,os)=>{"use strict";var as;Object.keys||(xt=Object.prototype.hasOwnProperty,Ra=Object.prototype.toString,Ql=Aa(),Oa=Object.prototype.propertyIsEnumerable,es=!Oa.call({toString:null},"toString"),rs=Oa.call(function(){},"prototype"),At=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],qn=function(e){var r=e.constructor;return r&&r.prototype===e},ts={$applicationCache:!0,$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$onmozfullscreenchange:!0,$onmozfullscreenerror:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},ns=(function(){if(typeof window>"u")return!1;for(var e in window)try{if(!ts["$"+e]&&xt.call(window,e)&&window[e]!==null&&typeof window[e]=="object")try{qn(window[e])}catch{return!0}}catch{return!0}return!1})(),is=function(e){if(typeof window>"u"||!ns)return qn(e);try{return qn(e)}catch{return!1}},as=function(r){var t=r!==null&&typeof r=="object",n=Ra.call(r)==="[object Function]",i=Ql(r),a=t&&Ra.call(r)==="[object String]",o=[];if(!t&&!n&&!i)throw new TypeError("Object.keys called on a non-object");var f=rs&&n;if(a&&r.length>0&&!xt.call(r,0))for(var s=0;s0)for(var u=0;u{"use strict";var a_=Array.prototype.slice,o_=Aa(),us=Object.keys,Un=us?function(r){return us(r)}:fs(),ls=Object.keys;Un.shim=function(){if(Object.keys){var r=(function(){var t=Object.keys(arguments);return t&&t.length===arguments.length})(1,2);r||(Object.keys=function(n){return o_(n)?ls(a_.call(n)):ls(n)})}else Object.keys=Un;return Object.keys||Un};ss.exports=Un});var ys=y(($1,ds)=>{"use strict";var f_=Ta(),hs=an()(),ps=nr(),Cn=on(),u_=ps("Array.prototype.push"),cs=ps("Object.prototype.propertyIsEnumerable"),l_=hs?Cn.getOwnPropertySymbols:null;ds.exports=function(r,t){if(r==null)throw new TypeError("target must be an object");var n=Cn(r);if(arguments.length===1)return n;for(var i=1;i{"use strict";var Ia=ys(),s_=function(){if(!Object.assign)return!1;for(var e="abcdefghijklmnopqrst",r=e.split(""),t={},n=0;n{"use strict";var gs=function(e){return e!==e};bs.exports=function(r,t){return r===0&&t===0?1/r===1/t:!!(r===t||gs(r)&&gs(t))}});var zn=y((K1,ws)=>{"use strict";var h_=Na();ws.exports=function(){return typeof Object.is=="function"?Object.is:h_}});var xs=y((X1,Ss)=>{"use strict";var Es=yn(),ms=pt(),p_=ms(Es("String.prototype.indexOf"));Ss.exports=function(r,t){var n=Es(r,!!t);return typeof n=="function"&&p_(r,".prototype.")>-1?ms(n):n}});var Rt=y((J1,Ts)=>{"use strict";var d_=Ta(),y_=typeof Symbol=="function"&&typeof Symbol("foo")=="symbol",v_=Object.prototype.toString,__=Array.prototype.concat,As=ia(),g_=function(e){return typeof e=="function"&&v_.call(e)==="[object Function]"},Rs=oa()(),b_=function(e,r,t,n){if(r in e){if(n===!0){if(e[r]===t)return}else if(!g_(n)||!n())return}Rs?As(e,r,t,!0):As(e,r,t)},Os=function(e,r){var t=arguments.length>2?arguments[2]:{},n=d_(r);y_&&(n=__.call(n,Object.getOwnPropertySymbols(r)));for(var i=0;i{"use strict";var w_=zn(),E_=Rt();Is.exports=function(){var r=w_();return E_(Object,{is:r},{is:function(){return Object.is!==r}}),r}});var Ps=y((eS,ks)=>{"use strict";var m_=Rt(),S_=pt(),x_=Na(),Ls=zn(),A_=Ns(),Fs=S_(Ls(),Object);m_(Fs,{getPolyfill:Ls,implementation:x_,shim:A_});ks.exports=Fs});var La=y((rS,Ds)=>{"use strict";Ds.exports=function(r){return r!==r}});var Fa=y((tS,Ms)=>{"use strict";var R_=La();Ms.exports=function(){return Number.isNaN&&Number.isNaN(NaN)&&!Number.isNaN("a")?Number.isNaN:R_}});var Bs=y((nS,js)=>{"use strict";var O_=Rt(),T_=Fa();js.exports=function(){var r=T_();return O_(Number,{isNaN:r},{isNaN:function(){return Number.isNaN!==r}}),r}});var zs=y((iS,Cs)=>{"use strict";var I_=pt(),N_=Rt(),L_=La(),qs=Fa(),F_=Bs(),Us=I_(qs(),Number);N_(Us,{getPolyfill:qs,implementation:L_,shim:F_});Cs.exports=Us});var uc=y((aS,fc)=>{"use strict";function Zs(e,r){return M_(e)||D_(e,r)||P_(e,r)||k_()}function k_(){throw new TypeError(`Invalid attempt to destructure non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function P_(e,r){if(e){if(typeof e=="string")return Ws(e,r);var t=Object.prototype.toString.call(e).slice(8,-1);if(t==="Object"&&e.constructor&&(t=e.constructor.name),t==="Map"||t==="Set")return Array.from(e);if(t==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t))return Ws(e,r)}}function Ws(e,r){(r==null||r>e.length)&&(r=e.length);for(var t=0,n=new Array(r);t10)return!0;for(var r=0;r57)return!0}return e.length===10&&e>=Math.pow(2,32)}function Hn(e){return Object.keys(e).filter(H_).concat($n(e).filter(Object.prototype.propertyIsEnumerable.bind(e)))}function nc(e,r){if(e===r)return 0;for(var t=e.length,n=r.length,i=0,a=Math.min(t,n);i{"use strict";function be(e){"@babel/helpers - typeof";return be=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(r){return typeof r}:function(r){return r&&typeof Symbol=="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},be(e)}function lc(e,r){for(var t=0;t1?t-1:0),i=1;i1?t-1:0),i=1;i1?t-1:0),i=1;i1?t-1:0),i=1;i{"use strict";ri.byteLength=gg;ri.toByteArray=wg;ri.fromByteArray=Sg;var xe=[],se=[],_g=typeof Uint8Array<"u"?Uint8Array:Array,Ba="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(fr=0,Oc=Ba.length;fr0)throw new Error("Invalid string. Length must be a multiple of 4");var t=e.indexOf("=");t===-1&&(t=r);var n=t===r?0:4-t%4;return[t,n]}function gg(e){var r=Tc(e),t=r[0],n=r[1];return(t+n)*3/4-n}function bg(e,r,t){return(r+t)*3/4-t}function wg(e){var r,t=Tc(e),n=t[0],i=t[1],a=new _g(bg(e,n,i)),o=0,f=i>0?n-4:n,s;for(s=0;s>16&255,a[o++]=r>>8&255,a[o++]=r&255;return i===2&&(r=se[e.charCodeAt(s)]<<2|se[e.charCodeAt(s+1)]>>4,a[o++]=r&255),i===1&&(r=se[e.charCodeAt(s)]<<10|se[e.charCodeAt(s+1)]<<4|se[e.charCodeAt(s+2)]>>2,a[o++]=r>>8&255,a[o++]=r&255),a}function Eg(e){return xe[e>>18&63]+xe[e>>12&63]+xe[e>>6&63]+xe[e&63]}function mg(e,r,t){for(var n,i=[],a=r;af?f:o+a));return n===1?(r=e[t-1],i.push(xe[r>>2]+xe[r<<4&63]+"==")):n===2&&(r=(e[t-2]<<8)+e[t-1],i.push(xe[r>>10]+xe[r>>4&63]+xe[r<<2&63]+"=")),i.join("")}});var Nc=y(qa=>{qa.read=function(e,r,t,n,i){var a,o,f=i*8-n-1,s=(1<>1,l=-7,c=t?i-1:0,p=t?-1:1,h=e[r+c];for(c+=p,a=h&(1<<-l)-1,h>>=-l,l+=f;l>0;a=a*256+e[r+c],c+=p,l-=8);for(o=a&(1<<-l)-1,a>>=-l,l+=n;l>0;o=o*256+e[r+c],c+=p,l-=8);if(a===0)a=1-u;else{if(a===s)return o?NaN:(h?-1:1)*(1/0);o=o+Math.pow(2,n),a=a-u}return(h?-1:1)*o*Math.pow(2,a-n)};qa.write=function(e,r,t,n,i,a){var o,f,s,u=a*8-i-1,l=(1<>1,p=i===23?Math.pow(2,-24)-Math.pow(2,-77):0,h=n?0:a-1,v=n?1:-1,_=r<0||r===0&&1/r<0?1:0;for(r=Math.abs(r),isNaN(r)||r===1/0?(f=isNaN(r)?1:0,o=l):(o=Math.floor(Math.log(r)/Math.LN2),r*(s=Math.pow(2,-o))<1&&(o--,s*=2),o+c>=1?r+=p/s:r+=p*Math.pow(2,1-c),r*s>=2&&(o++,s/=2),o+c>=l?(f=0,o=l):o+c>=1?(f=(r*s-1)*Math.pow(2,i),o=o+c):(f=r*Math.pow(2,c-1)*Math.pow(2,i),o=0));i>=8;e[t+h]=f&255,h+=v,f/=256,i-=8);for(o=o<0;e[t+h]=o&255,h+=v,o/=256,u-=8);e[t+h-v]|=_*128}});var lr=y($r=>{"use strict";var Ua=Ic(),Gr=Nc(),Lc=typeof Symbol=="function"&&typeof Symbol.for=="function"?Symbol.for("nodejs.util.inspect.custom"):null;$r.Buffer=d;$r.SlowBuffer=Ig;$r.INSPECT_MAX_BYTES=50;var ti=2147483647;$r.kMaxLength=ti;d.TYPED_ARRAY_SUPPORT=xg();!d.TYPED_ARRAY_SUPPORT&&typeof console<"u"&&typeof console.error=="function"&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function xg(){try{var e=new Uint8Array(1),r={foo:function(){return 42}};return Object.setPrototypeOf(r,Uint8Array.prototype),Object.setPrototypeOf(e,r),e.foo()===42}catch{return!1}}Object.defineProperty(d.prototype,"parent",{enumerable:!0,get:function(){if(d.isBuffer(this))return this.buffer}});Object.defineProperty(d.prototype,"offset",{enumerable:!0,get:function(){if(d.isBuffer(this))return this.byteOffset}});function Pe(e){if(e>ti)throw new RangeError('The value "'+e+'" is invalid for option "size"');var r=new Uint8Array(e);return Object.setPrototypeOf(r,d.prototype),r}function d(e,r,t){if(typeof e=="number"){if(typeof r=="string")throw new TypeError('The "string" argument must be of type string. Received type number');return Wa(e)}return Pc(e,r,t)}d.poolSize=8192;function Pc(e,r,t){if(typeof e=="string")return Rg(e,r);if(ArrayBuffer.isView(e))return Og(e);if(e==null)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(Ae(e,ArrayBuffer)||e&&Ae(e.buffer,ArrayBuffer)||typeof SharedArrayBuffer<"u"&&(Ae(e,SharedArrayBuffer)||e&&Ae(e.buffer,SharedArrayBuffer)))return za(e,r,t);if(typeof e=="number")throw new TypeError('The "value" argument must not be of type number. Received type number');var n=e.valueOf&&e.valueOf();if(n!=null&&n!==e)return d.from(n,r,t);var i=Tg(e);if(i)return i;if(typeof Symbol<"u"&&Symbol.toPrimitive!=null&&typeof e[Symbol.toPrimitive]=="function")return d.from(e[Symbol.toPrimitive]("string"),r,t);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}d.from=function(e,r,t){return Pc(e,r,t)};Object.setPrototypeOf(d.prototype,Uint8Array.prototype);Object.setPrototypeOf(d,Uint8Array);function Dc(e){if(typeof e!="number")throw new TypeError('"size" argument must be of type number');if(e<0)throw new RangeError('The value "'+e+'" is invalid for option "size"')}function Ag(e,r,t){return Dc(e),e<=0?Pe(e):r!==void 0?typeof t=="string"?Pe(e).fill(r,t):Pe(e).fill(r):Pe(e)}d.alloc=function(e,r,t){return Ag(e,r,t)};function Wa(e){return Dc(e),Pe(e<0?0:Ha(e)|0)}d.allocUnsafe=function(e){return Wa(e)};d.allocUnsafeSlow=function(e){return Wa(e)};function Rg(e,r){if((typeof r!="string"||r==="")&&(r="utf8"),!d.isEncoding(r))throw new TypeError("Unknown encoding: "+r);var t=Mc(e,r)|0,n=Pe(t),i=n.write(e,r);return i!==t&&(n=n.slice(0,i)),n}function Ca(e){for(var r=e.length<0?0:Ha(e.length)|0,t=Pe(r),n=0;n=ti)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+ti.toString(16)+" bytes");return e|0}function Ig(e){return+e!=e&&(e=0),d.alloc(+e)}d.isBuffer=function(r){return r!=null&&r._isBuffer===!0&&r!==d.prototype};d.compare=function(r,t){if(Ae(r,Uint8Array)&&(r=d.from(r,r.offset,r.byteLength)),Ae(t,Uint8Array)&&(t=d.from(t,t.offset,t.byteLength)),!d.isBuffer(r)||!d.isBuffer(t))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(r===t)return 0;for(var n=r.length,i=t.length,a=0,o=Math.min(n,i);ai.length?d.from(o).copy(i,a):Uint8Array.prototype.set.call(i,o,a);else if(d.isBuffer(o))o.copy(i,a);else throw new TypeError('"list" argument must be an Array of Buffers');a+=o.length}return i};function Mc(e,r){if(d.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||Ae(e,ArrayBuffer))return e.byteLength;if(typeof e!="string")throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof e);var t=e.length,n=arguments.length>2&&arguments[2]===!0;if(!n&&t===0)return 0;for(var i=!1;;)switch(r){case"ascii":case"latin1":case"binary":return t;case"utf8":case"utf-8":return Za(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return t*2;case"hex":return t>>>1;case"base64":return zc(e).length;default:if(i)return n?-1:Za(e).length;r=(""+r).toLowerCase(),i=!0}}d.byteLength=Mc;function Ng(e,r,t){var n=!1;if((r===void 0||r<0)&&(r=0),r>this.length||((t===void 0||t>this.length)&&(t=this.length),t<=0)||(t>>>=0,r>>>=0,t<=r))return"";for(e||(e="utf8");;)switch(e){case"hex":return Ug(this,r,t);case"utf8":case"utf-8":return Bc(this,r,t);case"ascii":return Bg(this,r,t);case"latin1":case"binary":return qg(this,r,t);case"base64":return Mg(this,r,t);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Cg(this,r,t);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}d.prototype._isBuffer=!0;function ur(e,r,t){var n=e[r];e[r]=e[t],e[t]=n}d.prototype.swap16=function(){var r=this.length;if(r%2!==0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(var t=0;tt&&(r+=" ... "),""};Lc&&(d.prototype[Lc]=d.prototype.inspect);d.prototype.compare=function(r,t,n,i,a){if(Ae(r,Uint8Array)&&(r=d.from(r,r.offset,r.byteLength)),!d.isBuffer(r))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof r);if(t===void 0&&(t=0),n===void 0&&(n=r?r.length:0),i===void 0&&(i=0),a===void 0&&(a=this.length),t<0||n>r.length||i<0||a>this.length)throw new RangeError("out of range index");if(i>=a&&t>=n)return 0;if(i>=a)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,i>>>=0,a>>>=0,this===r)return 0;for(var o=a-i,f=n-t,s=Math.min(o,f),u=this.slice(i,a),l=r.slice(t,n),c=0;c2147483647?t=2147483647:t<-2147483648&&(t=-2147483648),t=+t,Ga(t)&&(t=i?0:e.length-1),t<0&&(t=e.length+t),t>=e.length){if(i)return-1;t=e.length-1}else if(t<0)if(i)t=0;else return-1;if(typeof r=="string"&&(r=d.from(r,n)),d.isBuffer(r))return r.length===0?-1:Fc(e,r,t,n,i);if(typeof r=="number")return r=r&255,typeof Uint8Array.prototype.indexOf=="function"?i?Uint8Array.prototype.indexOf.call(e,r,t):Uint8Array.prototype.lastIndexOf.call(e,r,t):Fc(e,[r],t,n,i);throw new TypeError("val must be string, number or Buffer")}function Fc(e,r,t,n,i){var a=1,o=e.length,f=r.length;if(n!==void 0&&(n=String(n).toLowerCase(),n==="ucs2"||n==="ucs-2"||n==="utf16le"||n==="utf-16le")){if(e.length<2||r.length<2)return-1;a=2,o/=2,f/=2,t/=2}function s(h,v){return a===1?h[v]:h.readUInt16BE(v*a)}var u;if(i){var l=-1;for(u=t;uo&&(t=o-f),u=t;u>=0;u--){for(var c=!0,p=0;pi&&(n=i)):n=i;var a=r.length;n>a/2&&(n=a/2);for(var o=0;o>>0,isFinite(n)?(n=n>>>0,i===void 0&&(i="utf8")):(i=n,n=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");var a=this.length-t;if((n===void 0||n>a)&&(n=a),r.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");i||(i="utf8");for(var o=!1;;)switch(i){case"hex":return Lg(this,r,t,n);case"utf8":case"utf-8":return Fg(this,r,t,n);case"ascii":case"latin1":case"binary":return kg(this,r,t,n);case"base64":return Pg(this,r,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Dg(this,r,t,n);default:if(o)throw new TypeError("Unknown encoding: "+i);i=(""+i).toLowerCase(),o=!0}};d.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function Mg(e,r,t){return r===0&&t===e.length?Ua.fromByteArray(e):Ua.fromByteArray(e.slice(r,t))}function Bc(e,r,t){t=Math.min(e.length,t);for(var n=[],i=r;i239?4:a>223?3:a>191?2:1;if(i+f<=t){var s,u,l,c;switch(f){case 1:a<128&&(o=a);break;case 2:s=e[i+1],(s&192)===128&&(c=(a&31)<<6|s&63,c>127&&(o=c));break;case 3:s=e[i+1],u=e[i+2],(s&192)===128&&(u&192)===128&&(c=(a&15)<<12|(s&63)<<6|u&63,c>2047&&(c<55296||c>57343)&&(o=c));break;case 4:s=e[i+1],u=e[i+2],l=e[i+3],(s&192)===128&&(u&192)===128&&(l&192)===128&&(c=(a&15)<<18|(s&63)<<12|(u&63)<<6|l&63,c>65535&&c<1114112&&(o=c))}}o===null?(o=65533,f=1):o>65535&&(o-=65536,n.push(o>>>10&1023|55296),o=56320|o&1023),n.push(o),i+=f}return jg(n)}var kc=4096;function jg(e){var r=e.length;if(r<=kc)return String.fromCharCode.apply(String,e);for(var t="",n=0;nn)&&(t=n);for(var i="",a=r;an&&(r=n),t<0?(t+=n,t<0&&(t=0)):t>n&&(t=n),tt)throw new RangeError("Trying to access beyond buffer length")}d.prototype.readUintLE=d.prototype.readUIntLE=function(r,t,n){r=r>>>0,t=t>>>0,n||$(r,t,this.length);for(var i=this[r],a=1,o=0;++o>>0,t=t>>>0,n||$(r,t,this.length);for(var i=this[r+--t],a=1;t>0&&(a*=256);)i+=this[r+--t]*a;return i};d.prototype.readUint8=d.prototype.readUInt8=function(r,t){return r=r>>>0,t||$(r,1,this.length),this[r]};d.prototype.readUint16LE=d.prototype.readUInt16LE=function(r,t){return r=r>>>0,t||$(r,2,this.length),this[r]|this[r+1]<<8};d.prototype.readUint16BE=d.prototype.readUInt16BE=function(r,t){return r=r>>>0,t||$(r,2,this.length),this[r]<<8|this[r+1]};d.prototype.readUint32LE=d.prototype.readUInt32LE=function(r,t){return r=r>>>0,t||$(r,4,this.length),(this[r]|this[r+1]<<8|this[r+2]<<16)+this[r+3]*16777216};d.prototype.readUint32BE=d.prototype.readUInt32BE=function(r,t){return r=r>>>0,t||$(r,4,this.length),this[r]*16777216+(this[r+1]<<16|this[r+2]<<8|this[r+3])};d.prototype.readIntLE=function(r,t,n){r=r>>>0,t=t>>>0,n||$(r,t,this.length);for(var i=this[r],a=1,o=0;++o=a&&(i-=Math.pow(2,8*t)),i};d.prototype.readIntBE=function(r,t,n){r=r>>>0,t=t>>>0,n||$(r,t,this.length);for(var i=t,a=1,o=this[r+--i];i>0&&(a*=256);)o+=this[r+--i]*a;return a*=128,o>=a&&(o-=Math.pow(2,8*t)),o};d.prototype.readInt8=function(r,t){return r=r>>>0,t||$(r,1,this.length),this[r]&128?(255-this[r]+1)*-1:this[r]};d.prototype.readInt16LE=function(r,t){r=r>>>0,t||$(r,2,this.length);var n=this[r]|this[r+1]<<8;return n&32768?n|4294901760:n};d.prototype.readInt16BE=function(r,t){r=r>>>0,t||$(r,2,this.length);var n=this[r+1]|this[r]<<8;return n&32768?n|4294901760:n};d.prototype.readInt32LE=function(r,t){return r=r>>>0,t||$(r,4,this.length),this[r]|this[r+1]<<8|this[r+2]<<16|this[r+3]<<24};d.prototype.readInt32BE=function(r,t){return r=r>>>0,t||$(r,4,this.length),this[r]<<24|this[r+1]<<16|this[r+2]<<8|this[r+3]};d.prototype.readFloatLE=function(r,t){return r=r>>>0,t||$(r,4,this.length),Gr.read(this,r,!0,23,4)};d.prototype.readFloatBE=function(r,t){return r=r>>>0,t||$(r,4,this.length),Gr.read(this,r,!1,23,4)};d.prototype.readDoubleLE=function(r,t){return r=r>>>0,t||$(r,8,this.length),Gr.read(this,r,!0,52,8)};d.prototype.readDoubleBE=function(r,t){return r=r>>>0,t||$(r,8,this.length),Gr.read(this,r,!1,52,8)};function ne(e,r,t,n,i,a){if(!d.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(r>i||re.length)throw new RangeError("Index out of range")}d.prototype.writeUintLE=d.prototype.writeUIntLE=function(r,t,n,i){if(r=+r,t=t>>>0,n=n>>>0,!i){var a=Math.pow(2,8*n)-1;ne(this,r,t,n,a,0)}var o=1,f=0;for(this[t]=r&255;++f>>0,n=n>>>0,!i){var a=Math.pow(2,8*n)-1;ne(this,r,t,n,a,0)}var o=n-1,f=1;for(this[t+o]=r&255;--o>=0&&(f*=256);)this[t+o]=r/f&255;return t+n};d.prototype.writeUint8=d.prototype.writeUInt8=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,1,255,0),this[t]=r&255,t+1};d.prototype.writeUint16LE=d.prototype.writeUInt16LE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,2,65535,0),this[t]=r&255,this[t+1]=r>>>8,t+2};d.prototype.writeUint16BE=d.prototype.writeUInt16BE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,2,65535,0),this[t]=r>>>8,this[t+1]=r&255,t+2};d.prototype.writeUint32LE=d.prototype.writeUInt32LE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,4,4294967295,0),this[t+3]=r>>>24,this[t+2]=r>>>16,this[t+1]=r>>>8,this[t]=r&255,t+4};d.prototype.writeUint32BE=d.prototype.writeUInt32BE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,4,4294967295,0),this[t]=r>>>24,this[t+1]=r>>>16,this[t+2]=r>>>8,this[t+3]=r&255,t+4};d.prototype.writeIntLE=function(r,t,n,i){if(r=+r,t=t>>>0,!i){var a=Math.pow(2,8*n-1);ne(this,r,t,n,a-1,-a)}var o=0,f=1,s=0;for(this[t]=r&255;++o>0)-s&255;return t+n};d.prototype.writeIntBE=function(r,t,n,i){if(r=+r,t=t>>>0,!i){var a=Math.pow(2,8*n-1);ne(this,r,t,n,a-1,-a)}var o=n-1,f=1,s=0;for(this[t+o]=r&255;--o>=0&&(f*=256);)r<0&&s===0&&this[t+o+1]!==0&&(s=1),this[t+o]=(r/f>>0)-s&255;return t+n};d.prototype.writeInt8=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,1,127,-128),r<0&&(r=255+r+1),this[t]=r&255,t+1};d.prototype.writeInt16LE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,2,32767,-32768),this[t]=r&255,this[t+1]=r>>>8,t+2};d.prototype.writeInt16BE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,2,32767,-32768),this[t]=r>>>8,this[t+1]=r&255,t+2};d.prototype.writeInt32LE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,4,2147483647,-2147483648),this[t]=r&255,this[t+1]=r>>>8,this[t+2]=r>>>16,this[t+3]=r>>>24,t+4};d.prototype.writeInt32BE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,4,2147483647,-2147483648),r<0&&(r=4294967295+r+1),this[t]=r>>>24,this[t+1]=r>>>16,this[t+2]=r>>>8,this[t+3]=r&255,t+4};function qc(e,r,t,n,i,a){if(t+n>e.length)throw new RangeError("Index out of range");if(t<0)throw new RangeError("Index out of range")}function Uc(e,r,t,n,i){return r=+r,t=t>>>0,i||qc(e,r,t,4,34028234663852886e22,-34028234663852886e22),Gr.write(e,r,t,n,23,4),t+4}d.prototype.writeFloatLE=function(r,t,n){return Uc(this,r,t,!0,n)};d.prototype.writeFloatBE=function(r,t,n){return Uc(this,r,t,!1,n)};function Cc(e,r,t,n,i){return r=+r,t=t>>>0,i||qc(e,r,t,8,17976931348623157e292,-17976931348623157e292),Gr.write(e,r,t,n,52,8),t+8}d.prototype.writeDoubleLE=function(r,t,n){return Cc(this,r,t,!0,n)};d.prototype.writeDoubleBE=function(r,t,n){return Cc(this,r,t,!1,n)};d.prototype.copy=function(r,t,n,i){if(!d.isBuffer(r))throw new TypeError("argument should be a Buffer");if(n||(n=0),!i&&i!==0&&(i=this.length),t>=r.length&&(t=r.length),t||(t=0),i>0&&i=this.length)throw new RangeError("Index out of range");if(i<0)throw new RangeError("sourceEnd out of bounds");i>this.length&&(i=this.length),r.length-t>>0,n=n===void 0?this.length:n>>>0,r||(r=0);var o;if(typeof r=="number")for(o=t;o55295&&t<57344){if(!i){if(t>56319){(r-=3)>-1&&a.push(239,191,189);continue}else if(o+1===n){(r-=3)>-1&&a.push(239,191,189);continue}i=t;continue}if(t<56320){(r-=3)>-1&&a.push(239,191,189),i=t;continue}t=(i-55296<<10|t-56320)+65536}else i&&(r-=3)>-1&&a.push(239,191,189);if(i=null,t<128){if((r-=1)<0)break;a.push(t)}else if(t<2048){if((r-=2)<0)break;a.push(t>>6|192,t&63|128)}else if(t<65536){if((r-=3)<0)break;a.push(t>>12|224,t>>6&63|128,t&63|128)}else if(t<1114112){if((r-=4)<0)break;a.push(t>>18|240,t>>12&63|128,t>>6&63|128,t&63|128)}else throw new Error("Invalid code point")}return a}function Wg(e){for(var r=[],t=0;t>8,i=t%256,a.push(i),a.push(n);return a}function zc(e){return Ua.toByteArray(Zg(e))}function ni(e,r,t,n){for(var i=0;i=r.length||i>=e.length);++i)r[i+t]=e[i];return i}function Ae(e,r){return e instanceof r||e!=null&&e.constructor!=null&&e.constructor.name!=null&&e.constructor.name===r.name}function Ga(e){return e!==e}var Gg=(function(){for(var e="0123456789abcdef",r=new Array(256),t=0;t<16;++t)for(var n=t*16,i=0;i<16;++i)r[n+i]=e[t]+e[i];return r})()});var oi=y((sS,$a)=>{"use strict";var Vr=typeof Reflect=="object"?Reflect:null,Zc=Vr&&typeof Vr.apply=="function"?Vr.apply:function(r,t,n){return Function.prototype.apply.call(r,t,n)},ii;Vr&&typeof Vr.ownKeys=="function"?ii=Vr.ownKeys:Object.getOwnPropertySymbols?ii=function(r){return Object.getOwnPropertyNames(r).concat(Object.getOwnPropertySymbols(r))}:ii=function(r){return Object.getOwnPropertyNames(r)};function $g(e){console&&console.warn&&console.warn(e)}var Hc=Number.isNaN||function(r){return r!==r};function q(){q.init.call(this)}$a.exports=q;$a.exports.once=Xg;q.EventEmitter=q;q.prototype._events=void 0;q.prototype._eventsCount=0;q.prototype._maxListeners=void 0;var Wc=10;function ai(e){if(typeof e!="function")throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}Object.defineProperty(q,"defaultMaxListeners",{enumerable:!0,get:function(){return Wc},set:function(e){if(typeof e!="number"||e<0||Hc(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");Wc=e}});q.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0};q.prototype.setMaxListeners=function(r){if(typeof r!="number"||r<0||Hc(r))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+r+".");return this._maxListeners=r,this};function Gc(e){return e._maxListeners===void 0?q.defaultMaxListeners:e._maxListeners}q.prototype.getMaxListeners=function(){return Gc(this)};q.prototype.emit=function(r){for(var t=[],n=1;n0&&(o=t[0]),o instanceof Error)throw o;var f=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw f.context=o,f}var s=a[r];if(s===void 0)return!1;if(typeof s=="function")Zc(s,this,t);else for(var u=s.length,l=Xc(s,u),n=0;n0&&o.length>i&&!o.warned){o.warned=!0;var f=new Error("Possible EventEmitter memory leak detected. "+o.length+" "+String(r)+" listeners added. Use emitter.setMaxListeners() to increase limit");f.name="MaxListenersExceededWarning",f.emitter=e,f.type=r,f.count=o.length,$g(f)}return e}q.prototype.addListener=function(r,t){return $c(this,r,t,!1)};q.prototype.on=q.prototype.addListener;q.prototype.prependListener=function(r,t){return $c(this,r,t,!0)};function Vg(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length===0?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function Vc(e,r,t){var n={fired:!1,wrapFn:void 0,target:e,type:r,listener:t},i=Vg.bind(n);return i.listener=t,n.wrapFn=i,i}q.prototype.once=function(r,t){return ai(t),this.on(r,Vc(this,r,t)),this};q.prototype.prependOnceListener=function(r,t){return ai(t),this.prependListener(r,Vc(this,r,t)),this};q.prototype.removeListener=function(r,t){var n,i,a,o,f;if(ai(t),i=this._events,i===void 0)return this;if(n=i[r],n===void 0)return this;if(n===t||n.listener===t)--this._eventsCount===0?this._events=Object.create(null):(delete i[r],i.removeListener&&this.emit("removeListener",r,n.listener||t));else if(typeof n!="function"){for(a=-1,o=n.length-1;o>=0;o--)if(n[o]===t||n[o].listener===t){f=n[o].listener,a=o;break}if(a<0)return this;a===0?n.shift():Yg(n,a),n.length===1&&(i[r]=n[0]),i.removeListener!==void 0&&this.emit("removeListener",r,f||t)}return this};q.prototype.off=q.prototype.removeListener;q.prototype.removeAllListeners=function(r){var t,n,i;if(n=this._events,n===void 0)return this;if(n.removeListener===void 0)return arguments.length===0?(this._events=Object.create(null),this._eventsCount=0):n[r]!==void 0&&(--this._eventsCount===0?this._events=Object.create(null):delete n[r]),this;if(arguments.length===0){var a=Object.keys(n),o;for(i=0;i=0;i--)this.removeListener(r,t[i]);return this};function Yc(e,r,t){var n=e._events;if(n===void 0)return[];var i=n[r];return i===void 0?[]:typeof i=="function"?t?[i.listener||i]:[i]:t?Kg(i):Xc(i,i.length)}q.prototype.listeners=function(r){return Yc(this,r,!0)};q.prototype.rawListeners=function(r){return Yc(this,r,!1)};q.listenerCount=function(e,r){return typeof e.listenerCount=="function"?e.listenerCount(r):Kc.call(e,r)};q.prototype.listenerCount=Kc;function Kc(e){var r=this._events;if(r!==void 0){var t=r[e];if(typeof t=="function")return 1;if(t!==void 0)return t.length}return 0}q.prototype.eventNames=function(){return this._eventsCount>0?ii(this._events):[]};function Xc(e,r){for(var t=new Array(r),n=0;n{Qc.exports=oi().EventEmitter});var ah=y((hS,ih)=>{"use strict";function eh(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),t.push.apply(t,n)}return t}function rh(e){for(var r=1;r0?this.tail.next=n:this.head=n,this.tail=n,++this.length}},{key:"unshift",value:function(t){var n={data:t,next:this.head};this.length===0&&(this.tail=n),this.head=n,++this.length}},{key:"shift",value:function(){if(this.length!==0){var t=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,t}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(t){if(this.length===0)return"";for(var n=this.head,i=""+n.data;n=n.next;)i+=t+n.data;return i}},{key:"concat",value:function(t){if(this.length===0)return fi.alloc(0);for(var n=fi.allocUnsafe(t>>>0),i=this.head,a=0;i;)ob(i.data,n,a),a+=i.data.length,i=i.next;return n}},{key:"consume",value:function(t,n){var i;return to.length?o.length:t;if(f===o.length?a+=o:a+=o.slice(0,t),t-=f,t===0){f===o.length?(++i,n.next?this.head=n.next:this.head=this.tail=null):(this.head=n,n.data=o.slice(f));break}++i}return this.length-=i,a}},{key:"_getBuffer",value:function(t){var n=fi.allocUnsafe(t),i=this.head,a=1;for(i.data.copy(n),t-=i.data.length;i=i.next;){var o=i.data,f=t>o.length?o.length:t;if(o.copy(n,n.length-t,0,f),t-=f,t===0){f===o.length?(++a,i.next?this.head=i.next:this.head=this.tail=null):(this.head=i,i.data=o.slice(f));break}++a}return this.length-=a,n}},{key:ab,value:function(t,n){return Ya(this,rh(rh({},n),{},{depth:0,customInspect:!1}))}}]),e})()});var Xa=y((pS,fh)=>{"use strict";function fb(e,r){var t=this,n=this._readableState&&this._readableState.destroyed,i=this._writableState&&this._writableState.destroyed;return n||i?(r?r(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(Ka,this,e)):process.nextTick(Ka,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(a){!r&&a?t._writableState?t._writableState.errorEmitted?process.nextTick(ui,t):(t._writableState.errorEmitted=!0,process.nextTick(oh,t,a)):process.nextTick(oh,t,a):r?(process.nextTick(ui,t),r(a)):process.nextTick(ui,t)}),this)}function oh(e,r){Ka(e,r),ui(e)}function ui(e){e._writableState&&!e._writableState.emitClose||e._readableState&&!e._readableState.emitClose||e.emit("close")}function ub(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function Ka(e,r){e.emit("error",r)}function lb(e,r){var t=e._readableState,n=e._writableState;t&&t.autoDestroy||n&&n.autoDestroy?e.destroy(r):e.emit("error",r)}fh.exports={destroy:fb,undestroy:ub,errorOrDestroy:lb}});var sr=y((dS,sh)=>{"use strict";function sb(e,r){e.prototype=Object.create(r.prototype),e.prototype.constructor=e,e.__proto__=r}var lh={};function ce(e,r,t){t||(t=Error);function n(a,o,f){return typeof r=="string"?r:r(a,o,f)}var i=(function(a){sb(o,a);function o(f,s,u){return a.call(this,n(f,s,u))||this}return o})(t);i.prototype.name=t.name,i.prototype.code=e,lh[e]=i}function uh(e,r){if(Array.isArray(e)){var t=e.length;return e=e.map(function(n){return String(n)}),t>2?"one of ".concat(r," ").concat(e.slice(0,t-1).join(", "),", or ")+e[t-1]:t===2?"one of ".concat(r," ").concat(e[0]," or ").concat(e[1]):"of ".concat(r," ").concat(e[0])}else return"of ".concat(r," ").concat(String(e))}function cb(e,r,t){return e.substr(!t||t<0?0:+t,r.length)===r}function hb(e,r,t){return(t===void 0||t>e.length)&&(t=e.length),e.substring(t-r.length,t)===r}function pb(e,r,t){return typeof t!="number"&&(t=0),t+r.length>e.length?!1:e.indexOf(r,t)!==-1}ce("ERR_INVALID_OPT_VALUE",function(e,r){return'The value "'+r+'" is invalid for option "'+e+'"'},TypeError);ce("ERR_INVALID_ARG_TYPE",function(e,r,t){var n;typeof r=="string"&&cb(r,"not ")?(n="must not be",r=r.replace(/^not /,"")):n="must be";var i;if(hb(e," argument"))i="The ".concat(e," ").concat(n," ").concat(uh(r,"type"));else{var a=pb(e,".")?"property":"argument";i='The "'.concat(e,'" ').concat(a," ").concat(n," ").concat(uh(r,"type"))}return i+=". Received type ".concat(typeof t),i},TypeError);ce("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF");ce("ERR_METHOD_NOT_IMPLEMENTED",function(e){return"The "+e+" method is not implemented"});ce("ERR_STREAM_PREMATURE_CLOSE","Premature close");ce("ERR_STREAM_DESTROYED",function(e){return"Cannot call "+e+" after a stream was destroyed"});ce("ERR_MULTIPLE_CALLBACK","Callback called multiple times");ce("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable");ce("ERR_STREAM_WRITE_AFTER_END","write after end");ce("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError);ce("ERR_UNKNOWN_ENCODING",function(e){return"Unknown encoding: "+e},TypeError);ce("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event");sh.exports.codes=lh});var Ja=y((yS,ch)=>{"use strict";var db=sr().codes.ERR_INVALID_OPT_VALUE;function yb(e,r,t){return e.highWaterMark!=null?e.highWaterMark:r?e[t]:null}function vb(e,r,t,n){var i=yb(r,n,t);if(i!=null){if(!(isFinite(i)&&Math.floor(i)===i)||i<0){var a=n?t:"highWaterMark";throw new db(a,i)}return Math.floor(i)}return e.objectMode?16:16*1024}ch.exports={getHighWaterMark:vb}});var ph=y((vS,hh)=>{hh.exports=_b;function _b(e,r){if(Qa("noDeprecation"))return e;var t=!1;function n(){if(!t){if(Qa("throwDeprecation"))throw new Error(r);Qa("traceDeprecation")?console.trace(r):console.warn(r),t=!0}return e.apply(this,arguments)}return n}function Qa(e){try{if(!globalThis.localStorage)return!1}catch{return!1}var r=globalThis.localStorage[e];return r==null?!1:String(r).toLowerCase()==="true"}});var to=y((_S,bh)=>{"use strict";bh.exports=z;function yh(e){var r=this;this.next=null,this.entry=null,this.finish=function(){Wb(r,e)}}var Yr;z.WritableState=Ft;var gb={deprecate:ph()},vh=Va(),si=lr().Buffer,bb=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function wb(e){return si.from(e)}function Eb(e){return si.isBuffer(e)||e instanceof bb}var ro=Xa(),mb=Ja(),Sb=mb.getHighWaterMark,We=sr().codes,xb=We.ERR_INVALID_ARG_TYPE,Ab=We.ERR_METHOD_NOT_IMPLEMENTED,Rb=We.ERR_MULTIPLE_CALLBACK,Ob=We.ERR_STREAM_CANNOT_PIPE,Tb=We.ERR_STREAM_DESTROYED,Ib=We.ERR_STREAM_NULL_VALUES,Nb=We.ERR_STREAM_WRITE_AFTER_END,Lb=We.ERR_UNKNOWN_ENCODING,Kr=ro.errorOrDestroy;Be()(z,vh);function Fb(){}function Ft(e,r,t){Yr=Yr||cr(),e=e||{},typeof t!="boolean"&&(t=r instanceof Yr),this.objectMode=!!e.objectMode,t&&(this.objectMode=this.objectMode||!!e.writableObjectMode),this.highWaterMark=Sb(this,e,"writableHighWaterMark",t),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var n=e.decodeStrings===!1;this.decodeStrings=!n,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(i){qb(r,i)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new yh(this)}Ft.prototype.getBuffer=function(){for(var r=this.bufferedRequest,t=[];r;)t.push(r),r=r.next;return t};(function(){try{Object.defineProperty(Ft.prototype,"buffer",{get:gb.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch{}})();var li;typeof Symbol=="function"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]=="function"?(li=Function.prototype[Symbol.hasInstance],Object.defineProperty(z,Symbol.hasInstance,{value:function(r){return li.call(this,r)?!0:this!==z?!1:r&&r._writableState instanceof Ft}})):li=function(r){return r instanceof this};function z(e){Yr=Yr||cr();var r=this instanceof Yr;if(!r&&!li.call(z,this))return new z(e);this._writableState=new Ft(e,this,r),this.writable=!0,e&&(typeof e.write=="function"&&(this._write=e.write),typeof e.writev=="function"&&(this._writev=e.writev),typeof e.destroy=="function"&&(this._destroy=e.destroy),typeof e.final=="function"&&(this._final=e.final)),vh.call(this)}z.prototype.pipe=function(){Kr(this,new Ob)};function kb(e,r){var t=new Nb;Kr(e,t),process.nextTick(r,t)}function Pb(e,r,t,n){var i;return t===null?i=new Ib:typeof t!="string"&&!r.objectMode&&(i=new xb("chunk",["string","Buffer"],t)),i?(Kr(e,i),process.nextTick(n,i),!1):!0}z.prototype.write=function(e,r,t){var n=this._writableState,i=!1,a=!n.objectMode&&Eb(e);return a&&!si.isBuffer(e)&&(e=wb(e)),typeof r=="function"&&(t=r,r=null),a?r="buffer":r||(r=n.defaultEncoding),typeof t!="function"&&(t=Fb),n.ending?kb(this,t):(a||Pb(this,n,e,t))&&(n.pendingcb++,i=Mb(this,n,a,e,r,t)),i};z.prototype.cork=function(){this._writableState.corked++};z.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&_h(this,e))};z.prototype.setDefaultEncoding=function(r){if(typeof r=="string"&&(r=r.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((r+"").toLowerCase())>-1))throw new Lb(r);return this._writableState.defaultEncoding=r,this};Object.defineProperty(z.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function Db(e,r,t){return!e.objectMode&&e.decodeStrings!==!1&&typeof r=="string"&&(r=si.from(r,t)),r}Object.defineProperty(z.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function Mb(e,r,t,n,i,a){if(!t){var o=Db(r,n,i);n!==o&&(t=!0,i="buffer",n=o)}var f=r.objectMode?1:n.length;r.length+=f;var s=r.length{"use strict";var Hb=Object.keys||function(e){var r=[];for(var t in e)r.push(t);return r};Eh.exports=Re;var wh=ao(),io=to();Be()(Re,wh);for(no=Hb(io.prototype),ci=0;ci{var pi=lr(),Oe=pi.Buffer;function mh(e,r){for(var t in e)r[t]=e[t]}Oe.from&&Oe.alloc&&Oe.allocUnsafe&&Oe.allocUnsafeSlow?Sh.exports=pi:(mh(pi,oo),oo.Buffer=hr);function hr(e,r,t){return Oe(e,r,t)}hr.prototype=Object.create(Oe.prototype);mh(Oe,hr);hr.from=function(e,r,t){if(typeof e=="number")throw new TypeError("Argument must not be a number");return Oe(e,r,t)};hr.alloc=function(e,r,t){if(typeof e!="number")throw new TypeError("Argument must be a number");var n=Oe(e);return r!==void 0?typeof t=="string"?n.fill(r,t):n.fill(r):n.fill(0),n};hr.allocUnsafe=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return Oe(e)};hr.allocUnsafeSlow=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return pi.SlowBuffer(e)}});var lo=y(Rh=>{"use strict";var uo=xh().Buffer,Ah=uo.isEncoding||function(e){switch(e=""+e,e&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function Vb(e){if(!e)return"utf8";for(var r;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(r)return;e=(""+e).toLowerCase(),r=!0}}function Yb(e){var r=Vb(e);if(typeof r!="string"&&(uo.isEncoding===Ah||!Ah(e)))throw new Error("Unknown encoding: "+e);return r||e}Rh.StringDecoder=kt;function kt(e){this.encoding=Yb(e);var r;switch(this.encoding){case"utf16le":this.text=rw,this.end=tw,r=4;break;case"utf8":this.fillLast=Jb,r=4;break;case"base64":this.text=nw,this.end=iw,r=3;break;default:this.write=aw,this.end=ow;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=uo.allocUnsafe(r)}kt.prototype.write=function(e){if(e.length===0)return"";var r,t;if(this.lastNeed){if(r=this.fillLast(e),r===void 0)return"";t=this.lastNeed,this.lastNeed=0}else t=0;return t>5===6?2:e>>4===14?3:e>>3===30?4:e>>6===2?-1:-2}function Kb(e,r,t){var n=r.length-1;if(n=0?(i>0&&(e.lastNeed=i-1),i):--n=0?(i>0&&(e.lastNeed=i-2),i):--n=0?(i>0&&(i===2?i=0:e.lastNeed=i-3),i):0))}function Xb(e,r,t){if((r[0]&192)!==128)return e.lastNeed=0,"\uFFFD";if(e.lastNeed>1&&r.length>1){if((r[1]&192)!==128)return e.lastNeed=1,"\uFFFD";if(e.lastNeed>2&&r.length>2&&(r[2]&192)!==128)return e.lastNeed=2,"\uFFFD"}}function Jb(e){var r=this.lastTotal-this.lastNeed,t=Xb(this,e,r);if(t!==void 0)return t;if(this.lastNeed<=e.length)return e.copy(this.lastChar,r,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,r,0,e.length),this.lastNeed-=e.length}function Qb(e,r){var t=Kb(this,e,r);if(!this.lastNeed)return e.toString("utf8",r);this.lastTotal=t;var n=e.length-(t-this.lastNeed);return e.copy(this.lastChar,0,n),e.toString("utf8",r,n)}function ew(e){var r=e&&e.length?this.write(e):"";return this.lastNeed?r+"\uFFFD":r}function rw(e,r){if((e.length-r)%2===0){var t=e.toString("utf16le",r);if(t){var n=t.charCodeAt(t.length-1);if(n>=55296&&n<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],t.slice(0,-1)}return t}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",r,e.length-1)}function tw(e){var r=e&&e.length?this.write(e):"";if(this.lastNeed){var t=this.lastTotal-this.lastNeed;return r+this.lastChar.toString("utf16le",0,t)}return r}function nw(e,r){var t=(e.length-r)%3;return t===0?e.toString("base64",r):(this.lastNeed=3-t,this.lastTotal=3,t===1?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",r,e.length-t))}function iw(e){var r=e&&e.length?this.write(e):"";return this.lastNeed?r+this.lastChar.toString("base64",0,3-this.lastNeed):r}function aw(e){return e.toString(this.encoding)}function ow(e){return e&&e.length?this.write(e):""}});var di=y((wS,Ih)=>{"use strict";var Oh=sr().codes.ERR_STREAM_PREMATURE_CLOSE;function fw(e){var r=!1;return function(){if(!r){r=!0;for(var t=arguments.length,n=new Array(t),i=0;i{"use strict";var yi;function He(e,r,t){return r=sw(r),r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function sw(e){var r=cw(e,"string");return typeof r=="symbol"?r:String(r)}function cw(e,r){if(typeof e!="object"||e===null)return e;var t=e[Symbol.toPrimitive];if(t!==void 0){var n=t.call(e,r||"default");if(typeof n!="object")return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return(r==="string"?String:Number)(e)}var hw=di(),Ge=Symbol("lastResolve"),pr=Symbol("lastReject"),Pt=Symbol("error"),vi=Symbol("ended"),dr=Symbol("lastPromise"),so=Symbol("handlePromise"),yr=Symbol("stream");function $e(e,r){return{value:e,done:r}}function pw(e){var r=e[Ge];if(r!==null){var t=e[yr].read();t!==null&&(e[dr]=null,e[Ge]=null,e[pr]=null,r($e(t,!1)))}}function dw(e){process.nextTick(pw,e)}function yw(e,r){return function(t,n){e.then(function(){if(r[vi]){t($e(void 0,!0));return}r[so](t,n)},n)}}var vw=Object.getPrototypeOf(function(){}),_w=Object.setPrototypeOf((yi={get stream(){return this[yr]},next:function(){var r=this,t=this[Pt];if(t!==null)return Promise.reject(t);if(this[vi])return Promise.resolve($e(void 0,!0));if(this[yr].destroyed)return new Promise(function(o,f){process.nextTick(function(){r[Pt]?f(r[Pt]):o($e(void 0,!0))})});var n=this[dr],i;if(n)i=new Promise(yw(n,this));else{var a=this[yr].read();if(a!==null)return Promise.resolve($e(a,!1));i=new Promise(this[so])}return this[dr]=i,i}},He(yi,Symbol.asyncIterator,function(){return this}),He(yi,"return",function(){var r=this;return new Promise(function(t,n){r[yr].destroy(null,function(i){if(i){n(i);return}t($e(void 0,!0))})})}),yi),vw),gw=function(r){var t,n=Object.create(_w,(t={},He(t,yr,{value:r,writable:!0}),He(t,Ge,{value:null,writable:!0}),He(t,pr,{value:null,writable:!0}),He(t,Pt,{value:null,writable:!0}),He(t,vi,{value:r._readableState.endEmitted,writable:!0}),He(t,so,{value:function(a,o){var f=n[yr].read();f?(n[dr]=null,n[Ge]=null,n[pr]=null,a($e(f,!1))):(n[Ge]=a,n[pr]=o)},writable:!0}),t));return n[dr]=null,hw(r,function(i){if(i&&i.code!=="ERR_STREAM_PREMATURE_CLOSE"){var a=n[pr];a!==null&&(n[dr]=null,n[Ge]=null,n[pr]=null,a(i)),n[Pt]=i;return}var o=n[Ge];o!==null&&(n[dr]=null,n[Ge]=null,n[pr]=null,o($e(void 0,!0))),n[vi]=!0}),r.on("readable",dw.bind(null,n)),n};Nh.exports=gw});var kh=y((mS,Fh)=>{Fh.exports=function(){throw new Error("Readable.from is not available in the browser")}});var ao=y((xS,Zh)=>{"use strict";Zh.exports=j;var Xr;j.ReadableState=jh;var SS=oi().EventEmitter,Mh=function(r,t){return r.listeners(t).length},Mt=Va(),_i=lr().Buffer,bw=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function ww(e){return _i.from(e)}function Ew(e){return _i.isBuffer(e)||e instanceof bw}var co=Se(),N;co&&co.debuglog?N=co.debuglog("stream"):N=function(){};var mw=ah(),bo=Xa(),Sw=Ja(),xw=Sw.getHighWaterMark,gi=sr().codes,Aw=gi.ERR_INVALID_ARG_TYPE,Rw=gi.ERR_STREAM_PUSH_AFTER_EOF,Ow=gi.ERR_METHOD_NOT_IMPLEMENTED,Tw=gi.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,Jr,ho,po;Be()(j,Mt);var Dt=bo.errorOrDestroy,yo=["error","close","destroy","pause","resume"];function Iw(e,r,t){if(typeof e.prependListener=="function")return e.prependListener(r,t);!e._events||!e._events[r]?e.on(r,t):Array.isArray(e._events[r])?e._events[r].unshift(t):e._events[r]=[t,e._events[r]]}function jh(e,r,t){Xr=Xr||cr(),e=e||{},typeof t!="boolean"&&(t=r instanceof Xr),this.objectMode=!!e.objectMode,t&&(this.objectMode=this.objectMode||!!e.readableObjectMode),this.highWaterMark=xw(this,e,"readableHighWaterMark",t),this.buffer=new mw,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(Jr||(Jr=lo().StringDecoder),this.decoder=new Jr(e.encoding),this.encoding=e.encoding)}function j(e){if(Xr=Xr||cr(),!(this instanceof j))return new j(e);var r=this instanceof Xr;this._readableState=new jh(e,this,r),this.readable=!0,e&&(typeof e.read=="function"&&(this._read=e.read),typeof e.destroy=="function"&&(this._destroy=e.destroy)),Mt.call(this)}Object.defineProperty(j.prototype,"destroyed",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(r){this._readableState&&(this._readableState.destroyed=r)}});j.prototype.destroy=bo.destroy;j.prototype._undestroy=bo.undestroy;j.prototype._destroy=function(e,r){r(e)};j.prototype.push=function(e,r){var t=this._readableState,n;return t.objectMode?n=!0:typeof e=="string"&&(r=r||t.defaultEncoding,r!==t.encoding&&(e=_i.from(e,r),r=""),n=!0),Bh(this,e,r,!1,n)};j.prototype.unshift=function(e){return Bh(this,e,null,!0,!1)};function Bh(e,r,t,n,i){N("readableAddChunk",r);var a=e._readableState;if(r===null)a.reading=!1,Fw(e,a);else{var o;if(i||(o=Nw(a,r)),o)Dt(e,o);else if(a.objectMode||r&&r.length>0)if(typeof r!="string"&&!a.objectMode&&Object.getPrototypeOf(r)!==_i.prototype&&(r=ww(r)),n)a.endEmitted?Dt(e,new Tw):vo(e,a,r,!0);else if(a.ended)Dt(e,new Rw);else{if(a.destroyed)return!1;a.reading=!1,a.decoder&&!t?(r=a.decoder.write(r),a.objectMode||r.length!==0?vo(e,a,r,!1):go(e,a)):vo(e,a,r,!1)}else n||(a.reading=!1,go(e,a))}return!a.ended&&(a.length=Ph?e=Ph:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function Dh(e,r){return e<=0||r.length===0&&r.ended?0:r.objectMode?1:e!==e?r.flowing&&r.length?r.buffer.head.data.length:r.length:(e>r.highWaterMark&&(r.highWaterMark=Lw(e)),e<=r.length?e:r.ended?r.length:(r.needReadable=!0,0))}j.prototype.read=function(e){N("read",e),e=parseInt(e,10);var r=this._readableState,t=e;if(e!==0&&(r.emittedReadable=!1),e===0&&r.needReadable&&((r.highWaterMark!==0?r.length>=r.highWaterMark:r.length>0)||r.ended))return N("read: emitReadable",r.length,r.ended),r.length===0&&r.ended?_o(this):bi(this),null;if(e=Dh(e,r),e===0&&r.ended)return r.length===0&&_o(this),null;var n=r.needReadable;N("need readable",n),(r.length===0||r.length-e0?i=Ch(e,r):i=null,i===null?(r.needReadable=r.length<=r.highWaterMark,e=0):(r.length-=e,r.awaitDrain=0),r.length===0&&(r.ended||(r.needReadable=!0),t!==e&&r.ended&&_o(this)),i!==null&&this.emit("data",i),i};function Fw(e,r){if(N("onEofChunk"),!r.ended){if(r.decoder){var t=r.decoder.end();t&&t.length&&(r.buffer.push(t),r.length+=r.objectMode?1:t.length)}r.ended=!0,r.sync?bi(e):(r.needReadable=!1,r.emittedReadable||(r.emittedReadable=!0,qh(e)))}}function bi(e){var r=e._readableState;N("emitReadable",r.needReadable,r.emittedReadable),r.needReadable=!1,r.emittedReadable||(N("emitReadable",r.flowing),r.emittedReadable=!0,process.nextTick(qh,e))}function qh(e){var r=e._readableState;N("emitReadable_",r.destroyed,r.length,r.ended),!r.destroyed&&(r.length||r.ended)&&(e.emit("readable"),r.emittedReadable=!1),r.needReadable=!r.flowing&&!r.ended&&r.length<=r.highWaterMark,wo(e)}function go(e,r){r.readingMore||(r.readingMore=!0,process.nextTick(kw,e,r))}function kw(e,r){for(;!r.reading&&!r.ended&&(r.length1&&zh(n.pipes,e)!==-1)&&!u&&(N("false write response, pause",n.awaitDrain),n.awaitDrain++),t.pause())}function p(m){N("onerror",m),_(),e.removeListener("error",p),Mh(e,"error")===0&&Dt(e,m)}Iw(e,"error",p);function h(){e.removeListener("finish",v),_()}e.once("close",h);function v(){N("onfinish"),e.removeListener("close",h),_()}e.once("finish",v);function _(){N("unpipe"),t.unpipe(e)}return e.emit("pipe",t),n.flowing||(N("pipe resume"),t.resume()),e};function Pw(e){return function(){var t=e._readableState;N("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,t.awaitDrain===0&&Mh(e,"data")&&(t.flowing=!0,wo(e))}}j.prototype.unpipe=function(e){var r=this._readableState,t={hasUnpiped:!1};if(r.pipesCount===0)return this;if(r.pipesCount===1)return e&&e!==r.pipes?this:(e||(e=r.pipes),r.pipes=null,r.pipesCount=0,r.flowing=!1,e&&e.emit("unpipe",this,t),this);if(!e){var n=r.pipes,i=r.pipesCount;r.pipes=null,r.pipesCount=0,r.flowing=!1;for(var a=0;a0,n.flowing!==!1&&this.resume()):e==="readable"&&!n.endEmitted&&!n.readableListening&&(n.readableListening=n.needReadable=!0,n.flowing=!1,n.emittedReadable=!1,N("on readable",n.length,n.reading),n.length?bi(this):n.reading||process.nextTick(Dw,this)),t};j.prototype.addListener=j.prototype.on;j.prototype.removeListener=function(e,r){var t=Mt.prototype.removeListener.call(this,e,r);return e==="readable"&&process.nextTick(Uh,this),t};j.prototype.removeAllListeners=function(e){var r=Mt.prototype.removeAllListeners.apply(this,arguments);return(e==="readable"||e===void 0)&&process.nextTick(Uh,this),r};function Uh(e){var r=e._readableState;r.readableListening=e.listenerCount("readable")>0,r.resumeScheduled&&!r.paused?r.flowing=!0:e.listenerCount("data")>0&&e.resume()}function Dw(e){N("readable nexttick read 0"),e.read(0)}j.prototype.resume=function(){var e=this._readableState;return e.flowing||(N("resume"),e.flowing=!e.readableListening,Mw(this,e)),e.paused=!1,this};function Mw(e,r){r.resumeScheduled||(r.resumeScheduled=!0,process.nextTick(jw,e,r))}function jw(e,r){N("resume",r.reading),r.reading||e.read(0),r.resumeScheduled=!1,e.emit("resume"),wo(e),r.flowing&&!r.reading&&e.read(0)}j.prototype.pause=function(){return N("call pause flowing=%j",this._readableState.flowing),this._readableState.flowing!==!1&&(N("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this};function wo(e){var r=e._readableState;for(N("flow",r.flowing);r.flowing&&e.read()!==null;);}j.prototype.wrap=function(e){var r=this,t=this._readableState,n=!1;e.on("end",function(){if(N("wrapped end"),t.decoder&&!t.ended){var o=t.decoder.end();o&&o.length&&r.push(o)}r.push(null)}),e.on("data",function(o){if(N("wrapped data"),t.decoder&&(o=t.decoder.write(o)),!(t.objectMode&&o==null)&&!(!t.objectMode&&(!o||!o.length))){var f=r.push(o);f||(n=!0,e.pause())}});for(var i in e)this[i]===void 0&&typeof e[i]=="function"&&(this[i]=(function(f){return function(){return e[f].apply(e,arguments)}})(i));for(var a=0;a=r.length?(r.decoder?t=r.buffer.join(""):r.buffer.length===1?t=r.buffer.first():t=r.buffer.concat(r.length),r.buffer.clear()):t=r.buffer.consume(e,r.decoder),t}function _o(e){var r=e._readableState;N("endReadable",r.endEmitted),r.endEmitted||(r.ended=!0,process.nextTick(Bw,r,e))}function Bw(e,r){if(N("endReadableNT",e.endEmitted,e.length),!e.endEmitted&&e.length===0&&(e.endEmitted=!0,r.readable=!1,r.emit("end"),e.autoDestroy)){var t=r._writableState;(!t||t.autoDestroy&&t.finished)&&r.destroy()}}typeof Symbol=="function"&&(j.from=function(e,r){return po===void 0&&(po=kh()),po(j,e,r)});function zh(e,r){for(var t=0,n=e.length;t{"use strict";Hh.exports=De;var wi=sr().codes,qw=wi.ERR_METHOD_NOT_IMPLEMENTED,Uw=wi.ERR_MULTIPLE_CALLBACK,Cw=wi.ERR_TRANSFORM_ALREADY_TRANSFORMING,zw=wi.ERR_TRANSFORM_WITH_LENGTH_0,Ei=cr();Be()(De,Ei);function Zw(e,r){var t=this._transformState;t.transforming=!1;var n=t.writecb;if(n===null)return this.emit("error",new Uw);t.writechunk=null,t.writecb=null,r!=null&&this.push(r),n(e);var i=this._readableState;i.reading=!1,(i.needReadable||i.length{"use strict";$h.exports=jt;var Gh=Eo();Be()(jt,Gh);function jt(e){if(!(this instanceof jt))return new jt(e);Gh.call(this,e)}jt.prototype._transform=function(e,r,t){t(null,e)}});var Qh=y((OS,Jh)=>{"use strict";var mo;function Hw(e){var r=!1;return function(){r||(r=!0,e.apply(void 0,arguments))}}var Xh=sr().codes,Gw=Xh.ERR_MISSING_ARGS,$w=Xh.ERR_STREAM_DESTROYED;function Yh(e){if(e)throw e}function Vw(e){return e.setHeader&&typeof e.abort=="function"}function Yw(e,r,t,n){n=Hw(n);var i=!1;e.on("close",function(){i=!0}),mo===void 0&&(mo=di()),mo(e,{readable:r,writable:t},function(o){if(o)return n(o);i=!0,n()});var a=!1;return function(o){if(!i&&!a){if(a=!0,Vw(e))return e.abort();if(typeof e.destroy=="function")return e.destroy();n(o||new $w("pipe"))}}}function Kh(e){e()}function Kw(e,r){return e.pipe(r)}function Xw(e){return!e.length||typeof e[e.length-1]!="function"?Yh:e.pop()}function Jw(){for(var e=arguments.length,r=new Array(e),t=0;t0;return Yw(o,s,u,function(l){i||(i=l),l&&a.forEach(Kh),!s&&(a.forEach(Kh),n(i))})});return r.reduce(Kw)}Jh.exports=Jw});var xo=y((TS,ep)=>{ep.exports=he;var So=oi().EventEmitter,Qw=Be();Qw(he,So);he.Readable=ao();he.Writable=to();he.Duplex=cr();he.Transform=Eo();he.PassThrough=Vh();he.finished=di();he.pipeline=Qh();he.Stream=he;function he(){So.call(this)}he.prototype.pipe=function(e,r){var t=this;function n(l){e.writable&&e.write(l)===!1&&t.pause&&t.pause()}t.on("data",n);function i(){t.readable&&t.resume&&t.resume()}e.on("drain",i),!e._isStdio&&(!r||r.end!==!1)&&(t.on("end",o),t.on("close",f));var a=!1;function o(){a||(a=!0,e.end())}function f(){a||(a=!0,typeof e.destroy=="function"&&e.destroy())}function s(l){if(u(),So.listenerCount(this,"error")===0)throw l}t.on("error",s),e.on("error",s);function u(){t.removeListener("data",n),e.removeListener("drain",i),t.removeListener("end",o),t.removeListener("close",f),t.removeListener("error",s),e.removeListener("error",s),t.removeListener("end",u),t.removeListener("close",u),e.removeListener("close",u)}return t.on("end",u),t.on("close",u),e.on("close",u),e.emit("pipe",t),e}});var K={};Jd(K,{default:()=>rE,finished:()=>np,isDisturbed:()=>op,isErrored:()=>ap,isReadable:()=>ip});var Qr,tp,rp,mi,Ao,eE,np,ip,ap,op,rE,fp=Xd(()=>{"use strict";Qr=ft(xo());re(K,ft(xo()));tp=Qr.default??Qr.default??{},rp=Qr.finished??tp.finished,mi=e=>!!e&&typeof e.getReader=="function"&&typeof e.cancel=="function",Ao=e=>!!e&&typeof e.getWriter=="function"&&typeof e.abort=="function",eE=e=>e instanceof Error?e:e==null?new Error("stream errored"):new Error(String(e)),np=(e,r,t)=>{let n=r,i=t;if(typeof n=="function"&&(i=n,n={}),!mi(e)&&!Ao(e)&&typeof rp=="function")return rp(e,n,i);let a=typeof i=="function"?i:()=>{},o=n?.readable!==!1,f=n?.writable!==!1,s=!1,u=null,l=()=>{s=!0,u!==null&&(clearTimeout(u),u=null)},c=(h=void 0)=>{s||(l(),queueMicrotask(()=>a(h)))},p=()=>{if(s)return;let h=e?._state;if(h==="errored"){c(eE(e?._storedError));return}if(h==="closed"||mi(e)&&!o||Ao(e)&&!f){c();return}u=setTimeout(p,0)};return p(),l},ip=e=>mi(e)?e._state==="readable":!!e&&e.readable!==!1&&e.destroyed!==!0,ap=e=>mi(e)||Ao(e)?e?._state==="errored":e?.errored!=null,op=e=>!!(e?.locked||e?.disturbed===!0||e?._disturbed===!0||e?.readableDidRead===!0),rE={...tp,finished:np,isReadable:ip,isErrored:ap,isDisturbed:op}});var lp=y((NS,up)=>{"use strict";function tE(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}up.exports=tE});var Bt=y(Q=>{"use strict";var nE=typeof Uint8Array<"u"&&typeof Uint16Array<"u"&&typeof Int32Array<"u";function iE(e,r){return Object.prototype.hasOwnProperty.call(e,r)}Q.assign=function(e){for(var r=Array.prototype.slice.call(arguments,1);r.length;){var t=r.shift();if(t){if(typeof t!="object")throw new TypeError(t+"must be non-object");for(var n in t)iE(t,n)&&(e[n]=t[n])}}return e};Q.shrinkBuf=function(e,r){return e.length===r?e:e.subarray?e.subarray(0,r):(e.length=r,e)};var aE={arraySet:function(e,r,t,n,i){if(r.subarray&&e.subarray){e.set(r.subarray(t,t+n),i);return}for(var a=0;a{"use strict";var fE=Bt(),uE=4,sp=0,cp=1,lE=2;function rt(e){for(var r=e.length;--r>=0;)e[r]=0}var sE=0,_p=1,cE=2,hE=3,pE=258,Fo=29,Wt=256,Ut=Wt+1+Fo,et=30,ko=19,gp=2*Ut+1,vr=15,Ro=16,dE=7,Po=256,bp=16,wp=17,Ep=18,No=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],Si=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],yE=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],mp=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],vE=512,Me=new Array((Ut+2)*2);rt(Me);var qt=new Array(et*2);rt(qt);var Ct=new Array(vE);rt(Ct);var zt=new Array(pE-hE+1);rt(zt);var Do=new Array(Fo);rt(Do);var xi=new Array(et);rt(xi);function Oo(e,r,t,n,i){this.static_tree=e,this.extra_bits=r,this.extra_base=t,this.elems=n,this.max_length=i,this.has_stree=e&&e.length}var Sp,xp,Ap;function To(e,r){this.dyn_tree=e,this.max_code=0,this.stat_desc=r}function Rp(e){return e<256?Ct[e]:Ct[256+(e>>>7)]}function Zt(e,r){e.pending_buf[e.pending++]=r&255,e.pending_buf[e.pending++]=r>>>8&255}function ie(e,r,t){e.bi_valid>Ro-t?(e.bi_buf|=r<>Ro-e.bi_valid,e.bi_valid+=t-Ro):(e.bi_buf|=r<>>=1,t<<=1;while(--r>0);return t>>>1}function _E(e){e.bi_valid===16?(Zt(e,e.bi_buf),e.bi_buf=0,e.bi_valid=0):e.bi_valid>=8&&(e.pending_buf[e.pending++]=e.bi_buf&255,e.bi_buf>>=8,e.bi_valid-=8)}function gE(e,r){var t=r.dyn_tree,n=r.max_code,i=r.stat_desc.static_tree,a=r.stat_desc.has_stree,o=r.stat_desc.extra_bits,f=r.stat_desc.extra_base,s=r.stat_desc.max_length,u,l,c,p,h,v,_=0;for(p=0;p<=vr;p++)e.bl_count[p]=0;for(t[e.heap[e.heap_max]*2+1]=0,u=e.heap_max+1;us&&(p=s,_++),t[l*2+1]=p,!(l>n)&&(e.bl_count[p]++,h=0,l>=f&&(h=o[l-f]),v=t[l*2],e.opt_len+=v*(p+h),a&&(e.static_len+=v*(i[l*2+1]+h)));if(_!==0){do{for(p=s-1;e.bl_count[p]===0;)p--;e.bl_count[p]--,e.bl_count[p+1]+=2,e.bl_count[s]--,_-=2}while(_>0);for(p=s;p!==0;p--)for(l=e.bl_count[p];l!==0;)c=e.heap[--u],!(c>n)&&(t[c*2+1]!==p&&(e.opt_len+=(p-t[c*2+1])*t[c*2],t[c*2+1]=p),l--)}}function Tp(e,r,t){var n=new Array(vr+1),i=0,a,o;for(a=1;a<=vr;a++)n[a]=i=i+t[a-1]<<1;for(o=0;o<=r;o++){var f=e[o*2+1];f!==0&&(e[o*2]=Op(n[f]++,f))}}function bE(){var e,r,t,n,i,a=new Array(vr+1);for(t=0,n=0;n>=7;n8?Zt(e,e.bi_buf):e.bi_valid>0&&(e.pending_buf[e.pending++]=e.bi_buf),e.bi_buf=0,e.bi_valid=0}function wE(e,r,t,n){Np(e),n&&(Zt(e,t),Zt(e,~t)),fE.arraySet(e.pending_buf,e.window,r,t,e.pending),e.pending+=t}function hp(e,r,t,n){var i=r*2,a=t*2;return e[i]>1;o>=1;o--)Io(e,t,o);u=a;do o=e.heap[1],e.heap[1]=e.heap[e.heap_len--],Io(e,t,1),f=e.heap[1],e.heap[--e.heap_max]=o,e.heap[--e.heap_max]=f,t[u*2]=t[o*2]+t[f*2],e.depth[u]=(e.depth[o]>=e.depth[f]?e.depth[o]:e.depth[f])+1,t[o*2+1]=t[f*2+1]=u,e.heap[1]=u++,Io(e,t,1);while(e.heap_len>=2);e.heap[--e.heap_max]=e.heap[1],gE(e,r),Tp(t,s,e.bl_count)}function dp(e,r,t){var n,i=-1,a,o=r[1],f=0,s=7,u=4;for(o===0&&(s=138,u=3),r[(t+1)*2+1]=65535,n=0;n<=t;n++)a=o,o=r[(n+1)*2+1],!(++f=3&&e.bl_tree[mp[r]*2+1]===0;r--);return e.opt_len+=3*(r+1)+5+5+4,r}function mE(e,r,t,n){var i;for(ie(e,r-257,5),ie(e,t-1,5),ie(e,n-4,4),i=0;i>>=1)if(r&1&&e.dyn_ltree[t*2]!==0)return sp;if(e.dyn_ltree[18]!==0||e.dyn_ltree[20]!==0||e.dyn_ltree[26]!==0)return cp;for(t=32;t0?(e.strm.data_type===lE&&(e.strm.data_type=SE(e)),Lo(e,e.l_desc),Lo(e,e.d_desc),o=EE(e),i=e.opt_len+3+7>>>3,a=e.static_len+3+7>>>3,a<=i&&(i=a)):i=a=t+5,t+4<=i&&r!==-1?Lp(e,r,t,n):e.strategy===uE||a===i?(ie(e,(_p<<1)+(n?1:0),3),pp(e,Me,qt)):(ie(e,(cE<<1)+(n?1:0),3),mE(e,e.l_desc.max_code+1,e.d_desc.max_code+1,o+1),pp(e,e.dyn_ltree,e.dyn_dtree)),Ip(e),n&&Np(e)}function OE(e,r,t){return e.pending_buf[e.d_buf+e.last_lit*2]=r>>>8&255,e.pending_buf[e.d_buf+e.last_lit*2+1]=r&255,e.pending_buf[e.l_buf+e.last_lit]=t&255,e.last_lit++,r===0?e.dyn_ltree[t*2]++:(e.matches++,r--,e.dyn_ltree[(zt[t]+Wt+1)*2]++,e.dyn_dtree[Rp(r)*2]++),e.last_lit===e.lit_bufsize-1}tt._tr_init=xE;tt._tr_stored_block=Lp;tt._tr_flush_block=RE;tt._tr_tally=OE;tt._tr_align=AE});var Mo=y((kS,kp)=>{"use strict";function TE(e,r,t,n){for(var i=e&65535|0,a=e>>>16&65535|0,o=0;t!==0;){o=t>2e3?2e3:t,t-=o;do i=i+r[n++]|0,a=a+i|0;while(--o);i%=65521,a%=65521}return i|a<<16|0}kp.exports=TE});var jo=y((PS,Pp)=>{"use strict";function IE(){for(var e,r=[],t=0;t<256;t++){e=t;for(var n=0;n<8;n++)e=e&1?3988292384^e>>>1:e>>>1;r[t]=e}return r}var NE=IE();function LE(e,r,t,n){var i=NE,a=n+t;e^=-1;for(var o=n;o>>8^i[(e^r[o])&255];return e^-1}Pp.exports=LE});var Mp=y((DS,Dp)=>{"use strict";Dp.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}});var Hp=y(Le=>{"use strict";var ee=Bt(),pe=Fp(),Up=Mo(),Ve=jo(),FE=Mp(),wr=0,kE=1,PE=3,Qe=4,jp=5,Ne=0,Bp=1,de=-2,DE=-3,Bo=-5,ME=-1,jE=1,Ai=2,BE=3,qE=4,UE=0,CE=2,Ii=8,zE=9,ZE=15,WE=8,HE=29,GE=256,Uo=GE+1+HE,$E=30,VE=19,YE=2*Uo+1,KE=15,M=3,Xe=258,Ee=Xe+M+1,XE=32,Ni=42,Co=69,Ri=73,Oi=91,Ti=103,_r=113,Gt=666,H=1,$t=2,gr=3,at=4,JE=3;function Je(e,r){return e.msg=FE[r],r}function qp(e){return(e<<1)-(e>4?9:0)}function Ke(e){for(var r=e.length;--r>=0;)e[r]=0}function Ye(e){var r=e.state,t=r.pending;t>e.avail_out&&(t=e.avail_out),t!==0&&(ee.arraySet(e.output,r.pending_buf,r.pending_out,t,e.next_out),e.next_out+=t,r.pending_out+=t,e.total_out+=t,e.avail_out-=t,r.pending-=t,r.pending===0&&(r.pending_out=0))}function Y(e,r){pe._tr_flush_block(e,e.block_start>=0?e.block_start:-1,e.strstart-e.block_start,r),e.block_start=e.strstart,Ye(e.strm)}function B(e,r){e.pending_buf[e.pending++]=r}function Ht(e,r){e.pending_buf[e.pending++]=r>>>8&255,e.pending_buf[e.pending++]=r&255}function QE(e,r,t,n){var i=e.avail_in;return i>n&&(i=n),i===0?0:(e.avail_in-=i,ee.arraySet(r,e.input,e.next_in,i,t),e.state.wrap===1?e.adler=Up(e.adler,r,i,t):e.state.wrap===2&&(e.adler=Ve(e.adler,r,i,t)),e.next_in+=i,e.total_in+=i,i)}function Cp(e,r){var t=e.max_chain_length,n=e.strstart,i,a,o=e.prev_length,f=e.nice_match,s=e.strstart>e.w_size-Ee?e.strstart-(e.w_size-Ee):0,u=e.window,l=e.w_mask,c=e.prev,p=e.strstart+Xe,h=u[n+o-1],v=u[n+o];e.prev_length>=e.good_match&&(t>>=2),f>e.lookahead&&(f=e.lookahead);do if(i=r,!(u[i+o]!==v||u[i+o-1]!==h||u[i]!==u[n]||u[++i]!==u[n+1])){n+=2,i++;do;while(u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&no){if(e.match_start=r,o=a,a>=f)break;h=u[n+o-1],v=u[n+o]}}while((r=c[r&l])>s&&--t!==0);return o<=e.lookahead?o:e.lookahead}function br(e){var r=e.w_size,t,n,i,a,o;do{if(a=e.window_size-e.lookahead-e.strstart,e.strstart>=r+(r-Ee)){ee.arraySet(e.window,e.window,r,r,0),e.match_start-=r,e.strstart-=r,e.block_start-=r,n=e.hash_size,t=n;do i=e.head[--t],e.head[t]=i>=r?i-r:0;while(--n);n=r,t=n;do i=e.prev[--t],e.prev[t]=i>=r?i-r:0;while(--n);a+=r}if(e.strm.avail_in===0)break;if(n=QE(e.strm,e.window,e.strstart+e.lookahead,a),e.lookahead+=n,e.lookahead+e.insert>=M)for(o=e.strstart-e.insert,e.ins_h=e.window[o],e.ins_h=(e.ins_h<e.pending_buf_size-5&&(t=e.pending_buf_size-5);;){if(e.lookahead<=1){if(br(e),e.lookahead===0&&r===wr)return H;if(e.lookahead===0)break}e.strstart+=e.lookahead,e.lookahead=0;var n=e.block_start+t;if((e.strstart===0||e.strstart>=n)&&(e.lookahead=e.strstart-n,e.strstart=n,Y(e,!1),e.strm.avail_out===0)||e.strstart-e.block_start>=e.w_size-Ee&&(Y(e,!1),e.strm.avail_out===0))return H}return e.insert=0,r===Qe?(Y(e,!0),e.strm.avail_out===0?gr:at):(e.strstart>e.block_start&&(Y(e,!1),e.strm.avail_out===0),H)}function qo(e,r){for(var t,n;;){if(e.lookahead=M&&(e.ins_h=(e.ins_h<=M)if(n=pe._tr_tally(e,e.strstart-e.match_start,e.match_length-M),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=M){e.match_length--;do e.strstart++,e.ins_h=(e.ins_h<=M&&(e.ins_h=(e.ins_h<4096)&&(e.match_length=M-1)),e.prev_length>=M&&e.match_length<=e.prev_length){i=e.strstart+e.lookahead-M,n=pe._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-M),e.lookahead-=e.prev_length-1,e.prev_length-=2;do++e.strstart<=i&&(e.ins_h=(e.ins_h<=M&&e.strstart>0&&(i=e.strstart-1,n=o[i],n===o[++i]&&n===o[++i]&&n===o[++i])){a=e.strstart+Xe;do;while(n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&ie.lookahead&&(e.match_length=e.lookahead)}if(e.match_length>=M?(t=pe._tr_tally(e,1,e.match_length-M),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(t=pe._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),t&&(Y(e,!1),e.strm.avail_out===0))return H}return e.insert=0,r===Qe?(Y(e,!0),e.strm.avail_out===0?gr:at):e.last_lit&&(Y(e,!1),e.strm.avail_out===0)?H:$t}function tm(e,r){for(var t;;){if(e.lookahead===0&&(br(e),e.lookahead===0)){if(r===wr)return H;break}if(e.match_length=0,t=pe._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,t&&(Y(e,!1),e.strm.avail_out===0))return H}return e.insert=0,r===Qe?(Y(e,!0),e.strm.avail_out===0?gr:at):e.last_lit&&(Y(e,!1),e.strm.avail_out===0)?H:$t}function Ie(e,r,t,n,i){this.good_length=e,this.max_lazy=r,this.nice_length=t,this.max_chain=n,this.func=i}var it;it=[new Ie(0,0,0,0,em),new Ie(4,4,8,4,qo),new Ie(4,5,16,8,qo),new Ie(4,6,32,32,qo),new Ie(4,4,16,16,nt),new Ie(8,16,32,32,nt),new Ie(8,16,128,128,nt),new Ie(8,32,128,256,nt),new Ie(32,128,258,1024,nt),new Ie(32,258,258,4096,nt)];function nm(e){e.window_size=2*e.w_size,Ke(e.head),e.max_lazy_match=it[e.level].max_lazy,e.good_match=it[e.level].good_length,e.nice_match=it[e.level].nice_length,e.max_chain_length=it[e.level].max_chain,e.strstart=0,e.block_start=0,e.lookahead=0,e.insert=0,e.match_length=e.prev_length=M-1,e.match_available=0,e.ins_h=0}function im(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=Ii,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new ee.Buf16(YE*2),this.dyn_dtree=new ee.Buf16((2*$E+1)*2),this.bl_tree=new ee.Buf16((2*VE+1)*2),Ke(this.dyn_ltree),Ke(this.dyn_dtree),Ke(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new ee.Buf16(KE+1),this.heap=new ee.Buf16(2*Uo+1),Ke(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new ee.Buf16(2*Uo+1),Ke(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function zp(e){var r;return!e||!e.state?Je(e,de):(e.total_in=e.total_out=0,e.data_type=CE,r=e.state,r.pending=0,r.pending_out=0,r.wrap<0&&(r.wrap=-r.wrap),r.status=r.wrap?Ni:_r,e.adler=r.wrap===2?0:1,r.last_flush=wr,pe._tr_init(r),Ne)}function Zp(e){var r=zp(e);return r===Ne&&nm(e.state),r}function am(e,r){return!e||!e.state||e.state.wrap!==2?de:(e.state.gzhead=r,Ne)}function Wp(e,r,t,n,i,a){if(!e)return de;var o=1;if(r===ME&&(r=6),n<0?(o=0,n=-n):n>15&&(o=2,n-=16),i<1||i>zE||t!==Ii||n<8||n>15||r<0||r>9||a<0||a>qE)return Je(e,de);n===8&&(n=9);var f=new im;return e.state=f,f.strm=e,f.wrap=o,f.gzhead=null,f.w_bits=n,f.w_size=1<jp||r<0)return e?Je(e,de):de;if(n=e.state,!e.output||!e.input&&e.avail_in!==0||n.status===Gt&&r!==Qe)return Je(e,e.avail_out===0?Bo:de);if(n.strm=e,t=n.last_flush,n.last_flush=r,n.status===Ni)if(n.wrap===2)e.adler=0,B(n,31),B(n,139),B(n,8),n.gzhead?(B(n,(n.gzhead.text?1:0)+(n.gzhead.hcrc?2:0)+(n.gzhead.extra?4:0)+(n.gzhead.name?8:0)+(n.gzhead.comment?16:0)),B(n,n.gzhead.time&255),B(n,n.gzhead.time>>8&255),B(n,n.gzhead.time>>16&255),B(n,n.gzhead.time>>24&255),B(n,n.level===9?2:n.strategy>=Ai||n.level<2?4:0),B(n,n.gzhead.os&255),n.gzhead.extra&&n.gzhead.extra.length&&(B(n,n.gzhead.extra.length&255),B(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=Ve(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=Co):(B(n,0),B(n,0),B(n,0),B(n,0),B(n,0),B(n,n.level===9?2:n.strategy>=Ai||n.level<2?4:0),B(n,JE),n.status=_r);else{var o=Ii+(n.w_bits-8<<4)<<8,f=-1;n.strategy>=Ai||n.level<2?f=0:n.level<6?f=1:n.level===6?f=2:f=3,o|=f<<6,n.strstart!==0&&(o|=XE),o+=31-o%31,n.status=_r,Ht(n,o),n.strstart!==0&&(Ht(n,e.adler>>>16),Ht(n,e.adler&65535)),e.adler=1}if(n.status===Co)if(n.gzhead.extra){for(i=n.pending;n.gzindex<(n.gzhead.extra.length&65535)&&!(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),Ye(e),i=n.pending,n.pending===n.pending_buf_size));)B(n,n.gzhead.extra[n.gzindex]&255),n.gzindex++;n.gzhead.hcrc&&n.pending>i&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=Ri)}else n.status=Ri;if(n.status===Ri)if(n.gzhead.name){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),Ye(e),i=n.pending,n.pending===n.pending_buf_size)){a=1;break}n.gzindexi&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),a===0&&(n.gzindex=0,n.status=Oi)}else n.status=Oi;if(n.status===Oi)if(n.gzhead.comment){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),Ye(e),i=n.pending,n.pending===n.pending_buf_size)){a=1;break}n.gzindexi&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),a===0&&(n.status=Ti)}else n.status=Ti;if(n.status===Ti&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&Ye(e),n.pending+2<=n.pending_buf_size&&(B(n,e.adler&255),B(n,e.adler>>8&255),e.adler=0,n.status=_r)):n.status=_r),n.pending!==0){if(Ye(e),e.avail_out===0)return n.last_flush=-1,Ne}else if(e.avail_in===0&&qp(r)<=qp(t)&&r!==Qe)return Je(e,Bo);if(n.status===Gt&&e.avail_in!==0)return Je(e,Bo);if(e.avail_in!==0||n.lookahead!==0||r!==wr&&n.status!==Gt){var s=n.strategy===Ai?tm(n,r):n.strategy===BE?rm(n,r):it[n.level].func(n,r);if((s===gr||s===at)&&(n.status=Gt),s===H||s===gr)return e.avail_out===0&&(n.last_flush=-1),Ne;if(s===$t&&(r===kE?pe._tr_align(n):r!==jp&&(pe._tr_stored_block(n,0,0,!1),r===PE&&(Ke(n.head),n.lookahead===0&&(n.strstart=0,n.block_start=0,n.insert=0))),Ye(e),e.avail_out===0))return n.last_flush=-1,Ne}return r!==Qe?Ne:n.wrap<=0?Bp:(n.wrap===2?(B(n,e.adler&255),B(n,e.adler>>8&255),B(n,e.adler>>16&255),B(n,e.adler>>24&255),B(n,e.total_in&255),B(n,e.total_in>>8&255),B(n,e.total_in>>16&255),B(n,e.total_in>>24&255)):(Ht(n,e.adler>>>16),Ht(n,e.adler&65535)),Ye(e),n.wrap>0&&(n.wrap=-n.wrap),n.pending!==0?Ne:Bp)}function um(e){var r;return!e||!e.state?de:(r=e.state.status,r!==Ni&&r!==Co&&r!==Ri&&r!==Oi&&r!==Ti&&r!==_r&&r!==Gt?Je(e,de):(e.state=null,r===_r?Je(e,DE):Ne))}function lm(e,r){var t=r.length,n,i,a,o,f,s,u,l;if(!e||!e.state||(n=e.state,o=n.wrap,o===2||o===1&&n.status!==Ni||n.lookahead))return de;for(o===1&&(e.adler=Up(e.adler,r,t,0)),n.wrap=0,t>=n.w_size&&(o===0&&(Ke(n.head),n.strstart=0,n.block_start=0,n.insert=0),l=new ee.Buf8(n.w_size),ee.arraySet(l,r,t-n.w_size,n.w_size,0),r=l,t=n.w_size),f=e.avail_in,s=e.next_in,u=e.input,e.avail_in=t,e.next_in=0,e.input=r,br(n);n.lookahead>=M;){i=n.strstart,a=n.lookahead-(M-1);do n.ins_h=(n.ins_h<{"use strict";var Li=30,sm=12;Gp.exports=function(r,t){var n,i,a,o,f,s,u,l,c,p,h,v,_,m,w,L,A,T,b,R,I,S,D,W,O;n=r.state,i=r.next_in,W=r.input,a=i+(r.avail_in-5),o=r.next_out,O=r.output,f=o-(t-r.avail_out),s=o+(r.avail_out-257),u=n.dmax,l=n.wsize,c=n.whave,p=n.wnext,h=n.window,v=n.hold,_=n.bits,m=n.lencode,w=n.distcode,L=(1<>>24,v>>>=b,_-=b,b=T>>>16&255,b===0)O[o++]=T&65535;else if(b&16){R=T&65535,b&=15,b&&(_>>=b,_-=b),_<15&&(v+=W[i++]<<_,_+=8,v+=W[i++]<<_,_+=8),T=w[v&A];t:for(;;){if(b=T>>>24,v>>>=b,_-=b,b=T>>>16&255,b&16){if(I=T&65535,b&=15,_u){r.msg="invalid distance too far back",n.mode=Li;break e}if(v>>>=b,_-=b,b=o-f,I>b){if(b=I-b,b>c&&n.sane){r.msg="invalid distance too far back",n.mode=Li;break e}if(S=0,D=h,p===0){if(S+=l-b,b2;)O[o++]=D[S++],O[o++]=D[S++],O[o++]=D[S++],R-=3;R&&(O[o++]=D[S++],R>1&&(O[o++]=D[S++]))}else{S=o-I;do O[o++]=O[S++],O[o++]=O[S++],O[o++]=O[S++],R-=3;while(R>2);R&&(O[o++]=O[S++],R>1&&(O[o++]=O[S++]))}}else if((b&64)===0){T=w[(T&65535)+(v&(1<>3,i-=R,_-=R<<3,v&=(1<<_)-1,r.next_in=i,r.next_out=o,r.avail_in=i{"use strict";var Vp=Bt(),ot=15,Yp=852,Kp=592,Xp=0,zo=1,Jp=2,cm=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],hm=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,72,78],pm=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],dm=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];Qp.exports=function(r,t,n,i,a,o,f,s){var u=s.bits,l=0,c=0,p=0,h=0,v=0,_=0,m=0,w=0,L=0,A=0,T,b,R,I,S,D=null,W=0,O,ve=new Vp.Buf16(ot+1),Jt=new Vp.Buf16(ot+1),Qt=null,nf=0,af,en,rn;for(l=0;l<=ot;l++)ve[l]=0;for(c=0;c=1&&ve[h]===0;h--);if(v>h&&(v=h),h===0)return a[o++]=1<<24|64<<16|0,a[o++]=1<<24|64<<16|0,s.bits=1,0;for(p=1;p0&&(r===Xp||h!==1))return-1;for(Jt[1]=0,l=1;lYp||r===Jp&&L>Kp)return 1;for(;;){af=l-m,f[c]O?(en=Qt[nf+f[c]],rn=D[W+f[c]]):(en=96,rn=0),T=1<>m)+b]=af<<24|en<<16|rn|0;while(b!==0);for(T=1<>=1;if(T!==0?(A&=T-1,A+=T):A=0,c++,--ve[l]===0){if(l===h)break;l=t[n+f[c]]}if(l>v&&(A&I)!==R){for(m===0&&(m=v),S+=p,_=l-m,w=1<<_;_+mYp||r===Jp&&L>Kp)return 1;R=A&I,a[R]=v<<24|_<<16|S-o|0}}return A!==0&&(a[S+A]=l-m<<24|64<<16|0),s.bits=v,0}});var Dd=y(me=>{"use strict";var ae=Bt(),Vo=Mo(),Fe=jo(),ym=$p(),Vt=ed(),vm=0,Rd=1,Od=2,rd=4,_m=5,Fi=6,Er=0,gm=1,bm=2,ye=-2,Td=-3,Yo=-4,wm=-5,td=8,Id=1,nd=2,id=3,ad=4,od=5,fd=6,ud=7,ld=8,sd=9,cd=10,Di=11,je=12,Zo=13,hd=14,Wo=15,pd=16,dd=17,yd=18,vd=19,ki=20,Pi=21,_d=22,gd=23,bd=24,wd=25,Ed=26,Ho=27,md=28,Sd=29,C=30,Ko=31,Em=32,mm=852,Sm=592,xm=15,Am=xm;function xd(e){return(e>>>24&255)+(e>>>8&65280)+((e&65280)<<8)+((e&255)<<24)}function Rm(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new ae.Buf16(320),this.work=new ae.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function Nd(e){var r;return!e||!e.state?ye:(r=e.state,e.total_in=e.total_out=r.total=0,e.msg="",r.wrap&&(e.adler=r.wrap&1),r.mode=Id,r.last=0,r.havedict=0,r.dmax=32768,r.head=null,r.hold=0,r.bits=0,r.lencode=r.lendyn=new ae.Buf32(mm),r.distcode=r.distdyn=new ae.Buf32(Sm),r.sane=1,r.back=-1,Er)}function Ld(e){var r;return!e||!e.state?ye:(r=e.state,r.wsize=0,r.whave=0,r.wnext=0,Nd(e))}function Fd(e,r){var t,n;return!e||!e.state||(n=e.state,r<0?(t=0,r=-r):(t=(r>>4)+1,r<48&&(r&=15)),r&&(r<8||r>15))?ye:(n.window!==null&&n.wbits!==r&&(n.window=null),n.wrap=t,n.wbits=r,Ld(e))}function kd(e,r){var t,n;return e?(n=new Rm,e.state=n,n.window=null,t=Fd(e,r),t!==Er&&(e.state=null),t):ye}function Om(e){return kd(e,Am)}var Ad=!0,Go,$o;function Tm(e){if(Ad){var r;for(Go=new ae.Buf32(512),$o=new ae.Buf32(32),r=0;r<144;)e.lens[r++]=8;for(;r<256;)e.lens[r++]=9;for(;r<280;)e.lens[r++]=7;for(;r<288;)e.lens[r++]=8;for(Vt(Rd,e.lens,0,288,Go,0,e.work,{bits:9}),r=0;r<32;)e.lens[r++]=5;Vt(Od,e.lens,0,32,$o,0,e.work,{bits:5}),Ad=!1}e.lencode=Go,e.lenbits=9,e.distcode=$o,e.distbits=5}function Pd(e,r,t,n){var i,a=e.state;return a.window===null&&(a.wsize=1<=a.wsize?(ae.arraySet(a.window,r,t-a.wsize,a.wsize,0),a.wnext=0,a.whave=a.wsize):(i=a.wsize-a.wnext,i>n&&(i=n),ae.arraySet(a.window,r,t-n,i,a.wnext),n-=i,n?(ae.arraySet(a.window,r,t-n,n,0),a.wnext=n,a.whave=a.wsize):(a.wnext+=i,a.wnext===a.wsize&&(a.wnext=0),a.whave>>8&255,t.check=Fe(t.check,D,2,0),u=0,l=0,t.mode=nd;break}if(t.flags=0,t.head&&(t.head.done=!1),!(t.wrap&1)||(((u&255)<<8)+(u>>8))%31){e.msg="incorrect header check",t.mode=C;break}if((u&15)!==td){e.msg="unknown compression method",t.mode=C;break}if(u>>>=4,l-=4,I=(u&15)+8,t.wbits===0)t.wbits=I;else if(I>t.wbits){e.msg="invalid window size",t.mode=C;break}t.dmax=1<>8&1),t.flags&512&&(D[0]=u&255,D[1]=u>>>8&255,t.check=Fe(t.check,D,2,0)),u=0,l=0,t.mode=id;case id:for(;l<32;){if(f===0)break e;f--,u+=n[a++]<>>8&255,D[2]=u>>>16&255,D[3]=u>>>24&255,t.check=Fe(t.check,D,4,0)),u=0,l=0,t.mode=ad;case ad:for(;l<16;){if(f===0)break e;f--,u+=n[a++]<>8),t.flags&512&&(D[0]=u&255,D[1]=u>>>8&255,t.check=Fe(t.check,D,2,0)),u=0,l=0,t.mode=od;case od:if(t.flags&1024){for(;l<16;){if(f===0)break e;f--,u+=n[a++]<>>8&255,t.check=Fe(t.check,D,2,0)),u=0,l=0}else t.head&&(t.head.extra=null);t.mode=fd;case fd:if(t.flags&1024&&(h=t.length,h>f&&(h=f),h&&(t.head&&(I=t.head.extra_len-t.length,t.head.extra||(t.head.extra=new Array(t.head.extra_len)),ae.arraySet(t.head.extra,n,a,h,I)),t.flags&512&&(t.check=Fe(t.check,n,h,a)),f-=h,a+=h,t.length-=h),t.length))break e;t.length=0,t.mode=ud;case ud:if(t.flags&2048){if(f===0)break e;h=0;do I=n[a+h++],t.head&&I&&t.length<65536&&(t.head.name+=String.fromCharCode(I));while(I&&h>9&1,t.head.done=!0),e.adler=t.check=0,t.mode=je;break;case cd:for(;l<32;){if(f===0)break e;f--,u+=n[a++]<>>=l&7,l-=l&7,t.mode=Ho;break}for(;l<3;){if(f===0)break e;f--,u+=n[a++]<>>=1,l-=1,u&3){case 0:t.mode=hd;break;case 1:if(Tm(t),t.mode=ki,r===Fi){u>>>=2,l-=2;break e}break;case 2:t.mode=dd;break;case 3:e.msg="invalid block type",t.mode=C}u>>>=2,l-=2;break;case hd:for(u>>>=l&7,l-=l&7;l<32;){if(f===0)break e;f--,u+=n[a++]<>>16^65535)){e.msg="invalid stored block lengths",t.mode=C;break}if(t.length=u&65535,u=0,l=0,t.mode=Wo,r===Fi)break e;case Wo:t.mode=pd;case pd:if(h=t.length,h){if(h>f&&(h=f),h>s&&(h=s),h===0)break e;ae.arraySet(i,n,a,h,o),f-=h,a+=h,s-=h,o+=h,t.length-=h;break}t.mode=je;break;case dd:for(;l<14;){if(f===0)break e;f--,u+=n[a++]<>>=5,l-=5,t.ndist=(u&31)+1,u>>>=5,l-=5,t.ncode=(u&15)+4,u>>>=4,l-=4,t.nlen>286||t.ndist>30){e.msg="too many length or distance symbols",t.mode=C;break}t.have=0,t.mode=yd;case yd:for(;t.have>>=3,l-=3}for(;t.have<19;)t.lens[ve[t.have++]]=0;if(t.lencode=t.lendyn,t.lenbits=7,W={bits:t.lenbits},S=Vt(vm,t.lens,0,19,t.lencode,0,t.work,W),t.lenbits=W.bits,S){e.msg="invalid code lengths set",t.mode=C;break}t.have=0,t.mode=vd;case vd:for(;t.have>>24,L=m>>>16&255,A=m&65535,!(w<=l);){if(f===0)break e;f--,u+=n[a++]<>>=w,l-=w,t.lens[t.have++]=A;else{if(A===16){for(O=w+2;l>>=w,l-=w,t.have===0){e.msg="invalid bit length repeat",t.mode=C;break}I=t.lens[t.have-1],h=3+(u&3),u>>>=2,l-=2}else if(A===17){for(O=w+3;l>>=w,l-=w,I=0,h=3+(u&7),u>>>=3,l-=3}else{for(O=w+7;l>>=w,l-=w,I=0,h=11+(u&127),u>>>=7,l-=7}if(t.have+h>t.nlen+t.ndist){e.msg="invalid bit length repeat",t.mode=C;break}for(;h--;)t.lens[t.have++]=I}}if(t.mode===C)break;if(t.lens[256]===0){e.msg="invalid code -- missing end-of-block",t.mode=C;break}if(t.lenbits=9,W={bits:t.lenbits},S=Vt(Rd,t.lens,0,t.nlen,t.lencode,0,t.work,W),t.lenbits=W.bits,S){e.msg="invalid literal/lengths set",t.mode=C;break}if(t.distbits=6,t.distcode=t.distdyn,W={bits:t.distbits},S=Vt(Od,t.lens,t.nlen,t.ndist,t.distcode,0,t.work,W),t.distbits=W.bits,S){e.msg="invalid distances set",t.mode=C;break}if(t.mode=ki,r===Fi)break e;case ki:t.mode=Pi;case Pi:if(f>=6&&s>=258){e.next_out=o,e.avail_out=s,e.next_in=a,e.avail_in=f,t.hold=u,t.bits=l,ym(e,p),o=e.next_out,i=e.output,s=e.avail_out,a=e.next_in,n=e.input,f=e.avail_in,u=t.hold,l=t.bits,t.mode===je&&(t.back=-1);break}for(t.back=0;m=t.lencode[u&(1<>>24,L=m>>>16&255,A=m&65535,!(w<=l);){if(f===0)break e;f--,u+=n[a++]<>T)],w=m>>>24,L=m>>>16&255,A=m&65535,!(T+w<=l);){if(f===0)break e;f--,u+=n[a++]<>>=T,l-=T,t.back+=T}if(u>>>=w,l-=w,t.back+=w,t.length=A,L===0){t.mode=Ed;break}if(L&32){t.back=-1,t.mode=je;break}if(L&64){e.msg="invalid literal/length code",t.mode=C;break}t.extra=L&15,t.mode=_d;case _d:if(t.extra){for(O=t.extra;l>>=t.extra,l-=t.extra,t.back+=t.extra}t.was=t.length,t.mode=gd;case gd:for(;m=t.distcode[u&(1<>>24,L=m>>>16&255,A=m&65535,!(w<=l);){if(f===0)break e;f--,u+=n[a++]<>T)],w=m>>>24,L=m>>>16&255,A=m&65535,!(T+w<=l);){if(f===0)break e;f--,u+=n[a++]<>>=T,l-=T,t.back+=T}if(u>>>=w,l-=w,t.back+=w,L&64){e.msg="invalid distance code",t.mode=C;break}t.offset=A,t.extra=L&15,t.mode=bd;case bd:if(t.extra){for(O=t.extra;l>>=t.extra,l-=t.extra,t.back+=t.extra}if(t.offset>t.dmax){e.msg="invalid distance too far back",t.mode=C;break}t.mode=wd;case wd:if(s===0)break e;if(h=p-s,t.offset>h){if(h=t.offset-h,h>t.whave&&t.sane){e.msg="invalid distance too far back",t.mode=C;break}h>t.wnext?(h-=t.wnext,v=t.wsize-h):v=t.wnext-h,h>t.length&&(h=t.length),_=t.window}else _=i,v=o-t.offset,h=t.length;h>s&&(h=s),s-=h,t.length-=h;do i[o++]=_[v++];while(--h);t.length===0&&(t.mode=Pi);break;case Ed:if(s===0)break e;i[o++]=t.length,s--,t.mode=Pi;break;case Ho:if(t.wrap){for(;l<32;){if(f===0)break e;f--,u|=n[a++]<{"use strict";Md.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}});var qd=y(g=>{"use strict";var oe=Wr(),km=lp(),Yt=Hp(),mr=Dd(),Bd=jd();for(Xo in Bd)g[Xo]=Bd[Xo];var Xo;g.NONE=0;g.DEFLATE=1;g.INFLATE=2;g.GZIP=3;g.GUNZIP=4;g.DEFLATERAW=5;g.INFLATERAW=6;g.UNZIP=7;var Pm=31,Dm=139;function X(e){if(typeof e!="number"||eg.UNZIP)throw new TypeError("Bad argument");this.dictionary=null,this.err=0,this.flush=0,this.init_done=!1,this.level=0,this.memLevel=0,this.mode=e,this.strategy=0,this.windowBits=0,this.write_in_progress=!1,this.pending_close=!1,this.gzip_id_bytes_read=0}X.prototype.close=function(){if(this.write_in_progress){this.pending_close=!0;return}this.pending_close=!1,oe(this.init_done,"close before init"),oe(this.mode<=g.UNZIP),this.mode===g.DEFLATE||this.mode===g.GZIP||this.mode===g.DEFLATERAW?Yt.deflateEnd(this.strm):(this.mode===g.INFLATE||this.mode===g.GUNZIP||this.mode===g.INFLATERAW||this.mode===g.UNZIP)&&mr.inflateEnd(this.strm),this.mode=g.NONE,this.dictionary=null};X.prototype.write=function(e,r,t,n,i,a,o){return this._write(!0,e,r,t,n,i,a,o)};X.prototype.writeSync=function(e,r,t,n,i,a,o){return this._write(!1,e,r,t,n,i,a,o)};X.prototype._write=function(e,r,t,n,i,a,o,f){if(oe.equal(arguments.length,8),oe(this.init_done,"write before init"),oe(this.mode!==g.NONE,"already finalized"),oe.equal(!1,this.write_in_progress,"write already in progress"),oe.equal(!1,this.pending_close,"close is pending"),this.write_in_progress=!0,oe.equal(!1,r===void 0,"must provide flush value"),this.write_in_progress=!0,r!==g.Z_NO_FLUSH&&r!==g.Z_PARTIAL_FLUSH&&r!==g.Z_SYNC_FLUSH&&r!==g.Z_FULL_FLUSH&&r!==g.Z_FINISH&&r!==g.Z_BLOCK)throw new Error("Invalid flush value");if(t==null&&(t=Buffer.alloc(0),i=0,n=0),this.strm.avail_in=i,this.strm.input=t,this.strm.next_in=n,this.strm.avail_out=f,this.strm.output=a,this.strm.next_out=o,this.flush=r,!e)return this._process(),this._checkError()?this._afterSync():void 0;var s=this;return process.nextTick(function(){s._process(),s._after()}),this};X.prototype._afterSync=function(){var e=this.strm.avail_out,r=this.strm.avail_in;return this.write_in_progress=!1,[r,e]};X.prototype._process=function(){var e=null;switch(this.mode){case g.DEFLATE:case g.GZIP:case g.DEFLATERAW:this.err=Yt.deflate(this.strm,this.flush);break;case g.UNZIP:switch(this.strm.avail_in>0&&(e=this.strm.next_in),this.gzip_id_bytes_read){case 0:if(e===null)break;if(this.strm.input[e]===Pm){if(this.gzip_id_bytes_read=1,e++,this.strm.avail_in===1)break}else{this.mode=g.INFLATE;break}case 1:if(e===null)break;this.strm.input[e]===Dm?(this.gzip_id_bytes_read=2,this.mode=g.GUNZIP):this.mode=g.INFLATE;break;default:throw new Error("invalid number of gzip magic number bytes read")}case g.INFLATE:case g.GUNZIP:case g.INFLATERAW:for(this.err=mr.inflate(this.strm,this.flush),this.err===g.Z_NEED_DICT&&this.dictionary&&(this.err=mr.inflateSetDictionary(this.strm,this.dictionary),this.err===g.Z_OK?this.err=mr.inflate(this.strm,this.flush):this.err===g.Z_DATA_ERROR&&(this.err=g.Z_NEED_DICT));this.strm.avail_in>0&&this.mode===g.GUNZIP&&this.err===g.Z_STREAM_END&&this.strm.next_in[0]!==0;)this.reset(),this.err=mr.inflate(this.strm,this.flush);break;default:throw new Error("Unknown mode "+this.mode)}};X.prototype._checkError=function(){switch(this.err){case g.Z_OK:case g.Z_BUF_ERROR:if(this.strm.avail_out!==0&&this.flush===g.Z_FINISH)return this._error("unexpected end of file"),!1;break;case g.Z_STREAM_END:break;case g.Z_NEED_DICT:return this.dictionary==null?this._error("Missing dictionary"):this._error("Bad dictionary"),!1;default:return this._error("Zlib error"),!1}return!0};X.prototype._after=function(){if(this._checkError()){var e=this.strm.avail_out,r=this.strm.avail_in;this.write_in_progress=!1,this.callback(r,e),this.pending_close&&this.close()}};X.prototype._error=function(e){this.strm.msg&&(e=this.strm.msg),this.onerror(e,this.err),this.write_in_progress=!1,this.pending_close&&this.close()};X.prototype.init=function(e,r,t,n,i){oe(arguments.length===4||arguments.length===5,"init(windowBits, level, memLevel, strategy, [dictionary])"),oe(e>=8&&e<=15,"invalid windowBits"),oe(r>=-1&&r<=9,"invalid compression level"),oe(t>=1&&t<=9,"invalid memlevel"),oe(n===g.Z_FILTERED||n===g.Z_HUFFMAN_ONLY||n===g.Z_RLE||n===g.Z_FIXED||n===g.Z_DEFAULT_STRATEGY,"invalid strategy"),this._init(r,e,t,n,i),this._setDictionary()};X.prototype.params=function(){throw new Error("deflateParams Not supported")};X.prototype.reset=function(){this._reset(),this._setDictionary()};X.prototype._init=function(e,r,t,n,i){switch(this.level=e,this.windowBits=r,this.memLevel=t,this.strategy=n,this.flush=g.Z_NO_FLUSH,this.err=g.Z_OK,(this.mode===g.GZIP||this.mode===g.GUNZIP)&&(this.windowBits+=16),this.mode===g.UNZIP&&(this.windowBits+=32),(this.mode===g.DEFLATERAW||this.mode===g.INFLATERAW)&&(this.windowBits=-1*this.windowBits),this.strm=new km,this.mode){case g.DEFLATE:case g.GZIP:case g.DEFLATERAW:this.err=Yt.deflateInit2(this.strm,this.level,g.Z_DEFLATED,this.windowBits,this.memLevel,this.strategy);break;case g.INFLATE:case g.GUNZIP:case g.INFLATERAW:case g.UNZIP:this.err=mr.inflateInit2(this.strm,this.windowBits);break;default:throw new Error("Unknown mode "+this.mode)}this.err!==g.Z_OK&&this._error("Init error"),this.dictionary=i,this.write_in_progress=!1,this.init_done=!0};X.prototype._setDictionary=function(){if(this.dictionary!=null){switch(this.err=g.Z_OK,this.mode){case g.DEFLATE:case g.DEFLATERAW:this.err=Yt.deflateSetDictionary(this.strm,this.dictionary);break;default:break}this.err!==g.Z_OK&&this._error("Failed to set dictionary")}};X.prototype._reset=function(){switch(this.err=g.Z_OK,this.mode){case g.DEFLATE:case g.DEFLATERAW:case g.GZIP:this.err=Yt.deflateReset(this.strm);break;case g.INFLATE:case g.INFLATERAW:case g.GUNZIP:this.err=mr.inflateReset(this.strm);break;default:break}this.err!==g.Z_OK&&this._error("Failed to reset stream")};g.Zlib=X});var Hd=y(E=>{"use strict";var ke=lr().Buffer,Zd=(fp(),Qd(K)).Transform,x=qd(),er=Se(),Kt=Wr().ok,Qo=lr().kMaxLength,Wd="Cannot create final Buffer. It would be larger than 0x"+Qo.toString(16)+" bytes";x.Z_MIN_WINDOWBITS=8;x.Z_MAX_WINDOWBITS=15;x.Z_DEFAULT_WINDOWBITS=15;x.Z_MIN_CHUNK=64;x.Z_MAX_CHUNK=1/0;x.Z_DEFAULT_CHUNK=16*1024;x.Z_MIN_MEMLEVEL=1;x.Z_MAX_MEMLEVEL=9;x.Z_DEFAULT_MEMLEVEL=8;x.Z_MIN_LEVEL=-1;x.Z_MAX_LEVEL=9;x.Z_DEFAULT_LEVEL=x.Z_DEFAULT_COMPRESSION;var Ud=Object.keys(x);for(Mi=0;Mi=Qo?u=new RangeError(Wd):s=ke.concat(n,i),n=[],e.close(),t(u,s)}}function Lr(e,r){if(typeof r=="string"&&(r=ke.from(r)),!ke.isBuffer(r))throw new TypeError("Not a string or buffer");var t=e._finishFlushFlag;return e._processChunk(r,t)}function Sr(e){if(!(this instanceof Sr))return new Sr(e);Z.call(this,e,x.DEFLATE)}function xr(e){if(!(this instanceof xr))return new xr(e);Z.call(this,e,x.INFLATE)}function Ar(e){if(!(this instanceof Ar))return new Ar(e);Z.call(this,e,x.GZIP)}function Rr(e){if(!(this instanceof Rr))return new Rr(e);Z.call(this,e,x.GUNZIP)}function Or(e){if(!(this instanceof Or))return new Or(e);Z.call(this,e,x.DEFLATERAW)}function Tr(e){if(!(this instanceof Tr))return new Tr(e);Z.call(this,e,x.INFLATERAW)}function Ir(e){if(!(this instanceof Ir))return new Ir(e);Z.call(this,e,x.UNZIP)}function zd(e){return e===x.Z_NO_FLUSH||e===x.Z_PARTIAL_FLUSH||e===x.Z_SYNC_FLUSH||e===x.Z_FULL_FLUSH||e===x.Z_FINISH||e===x.Z_BLOCK}function Z(e,r){var t=this;if(this._opts=e=e||{},this._chunkSize=e.chunkSize||E.Z_DEFAULT_CHUNK,Zd.call(this,e),e.flush&&!zd(e.flush))throw new Error("Invalid flush flag: "+e.flush);if(e.finishFlush&&!zd(e.finishFlush))throw new Error("Invalid flush flag: "+e.finishFlush);if(this._flushFlag=e.flush||x.Z_NO_FLUSH,this._finishFlushFlag=typeof e.finishFlush<"u"?e.finishFlush:x.Z_FINISH,e.chunkSize&&(e.chunkSizeE.Z_MAX_CHUNK))throw new Error("Invalid chunk size: "+e.chunkSize);if(e.windowBits&&(e.windowBitsE.Z_MAX_WINDOWBITS))throw new Error("Invalid windowBits: "+e.windowBits);if(e.level&&(e.levelE.Z_MAX_LEVEL))throw new Error("Invalid compression level: "+e.level);if(e.memLevel&&(e.memLevelE.Z_MAX_MEMLEVEL))throw new Error("Invalid memLevel: "+e.memLevel);if(e.strategy&&e.strategy!=E.Z_FILTERED&&e.strategy!=E.Z_HUFFMAN_ONLY&&e.strategy!=E.Z_RLE&&e.strategy!=E.Z_FIXED&&e.strategy!=E.Z_DEFAULT_STRATEGY)throw new Error("Invalid strategy: "+e.strategy);if(e.dictionary&&!ke.isBuffer(e.dictionary))throw new Error("Invalid dictionary: it should be a Buffer instance");this._handle=new x.Zlib(r);var n=this;this._hadError=!1,this._handle.onerror=function(o,f){Ui(n),n._hadError=!0;var s=new Error(o);s.errno=f,s.code=E.codes[f],n.emit("error",s)};var i=E.Z_DEFAULT_COMPRESSION;typeof e.level=="number"&&(i=e.level);var a=E.Z_DEFAULT_STRATEGY;typeof e.strategy=="number"&&(a=e.strategy),this._handle.init(e.windowBits||E.Z_DEFAULT_WINDOWBITS,i,e.memLevel||E.Z_DEFAULT_MEMLEVEL,a,e.dictionary),this._buffer=ke.allocUnsafe(this._chunkSize),this._offset=0,this._level=i,this._strategy=a,this.once("end",this.close),Object.defineProperty(this,"_closed",{get:function(){return!t._handle},configurable:!0,enumerable:!0})}er.inherits(Z,Zd);Z.prototype.params=function(e,r,t){if(eE.Z_MAX_LEVEL)throw new RangeError("Invalid compression level: "+e);if(r!=E.Z_FILTERED&&r!=E.Z_HUFFMAN_ONLY&&r!=E.Z_RLE&&r!=E.Z_FIXED&&r!=E.Z_DEFAULT_STRATEGY)throw new TypeError("Invalid strategy: "+r);if(this._level!==e||this._strategy!==r){var n=this;this.flush(x.Z_SYNC_FLUSH,function(){Kt(n._handle,"zlib binding closed"),n._handle.params(e,r),n._hadError||(n._level=e,n._strategy=r,t&&t())})}else process.nextTick(t)};Z.prototype.reset=function(){return Kt(this._handle,"zlib binding closed"),this._handle.reset()};Z.prototype._flush=function(e){this._transform(ke.alloc(0),"",e)};Z.prototype.flush=function(e,r){var t=this,n=this._writableState;(typeof e=="function"||e===void 0&&!r)&&(r=e,e=x.Z_FULL_FLUSH),n.ended?r&&process.nextTick(r):n.ending?r&&this.once("end",r):n.needDrain?r&&this.once("drain",function(){return t.flush(e,r)}):(this._flushFlag=e,this.write(ke.alloc(0),"",r))};Z.prototype.close=function(e){Ui(this,e),process.nextTick(Mm,this)};function Ui(e,r){r&&process.nextTick(r),e._handle&&(e._handle.close(),e._handle=null)}function Mm(e){e.emit("close")}Z.prototype._transform=function(e,r,t){var n,i=this._writableState,a=i.ending||i.ended,o=a&&(!e||i.length===e.length);if(e!==null&&!ke.isBuffer(e))return t(new Error("invalid input"));if(!this._handle)return t(new Error("zlib binding closed"));o?n=this._finishFlushFlag:(n=this._flushFlag,e.length>=i.length&&(this._flushFlag=this._opts.flush||x.Z_NO_FLUSH)),this._processChunk(e,n,t)};Z.prototype._processChunk=function(e,r,t){var n=e&&e.length,i=this._chunkSize-this._offset,a=0,o=this,f=typeof t=="function";if(!f){var s=[],u=0,l;this.on("error",function(_){l=_}),Kt(this._handle,"zlib binding closed");do var c=this._handle.writeSync(r,e,a,n,this._buffer,this._offset,i);while(!this._hadError&&v(c[0],c[1]));if(this._hadError)throw l;if(u>=Qo)throw Ui(this),new RangeError(Wd);var p=ke.concat(s,u);return Ui(this),p}Kt(this._handle,"zlib binding closed");var h=this._handle.write(r,e,a,n,this._buffer,this._offset,i);h.buffer=e,h.callback=v;function v(_,m){if(this&&(this.buffer=null,this.callback=null),!o._hadError){var w=i-m;if(Kt(w>=0,"have should not go down"),w>0){var L=o._buffer.slice(o._offset,o._offset+w);o._offset+=w,f?o.push(L):(s.push(L),u+=L.length)}if((m===0||o._offset>=o._chunkSize)&&(i=o._chunkSize,o._offset=0,o._buffer=ke.allocUnsafe(o._chunkSize)),m===0){if(a+=n-_,n=_,!f)return!0;var A=o._handle.write(r,e,a,n,o._buffer,o._offset,o._chunkSize);A.callback=v,A.buffer=e;return}if(!f)return!1;t()}}};er.inherits(Sr,Z);er.inherits(xr,Z);er.inherits(Ar,Z);er.inherits(Rr,Z);er.inherits(Or,Z);er.inherits(Tr,Z);er.inherits(Ir,Z)});var ef=ft(Wr()),rf=ft(Se()),tf=ft(Hd()),jm=ef.default??ef,Xt=rf.default??rf,Fr=tf.default??tf,Bm=typeof Fr.constants=="object"&&Fr.constants!==null?Fr.constants:Object.fromEntries(Object.entries(Fr).filter(([e,r])=>/^[A-Z0-9_]+$/.test(e)&&typeof r=="number"));typeof Fr.constants>"u"&&(Fr.constants=Bm);typeof Xt.TextEncoder>"u"&&typeof globalThis.TextEncoder=="function"&&(Xt.TextEncoder=globalThis.TextEncoder);typeof Xt.TextDecoder>"u"&&typeof globalThis.TextDecoder=="function"&&(Xt.TextDecoder=globalThis.TextDecoder);globalThis.__secureExecBuiltinAssertModule=jm;globalThis.__secureExecBuiltinUtilModule=Xt;globalThis.__secureExecBuiltinZlibModule=Fr;})(); -/*! Bundled license information: - -assert/build/internal/util/comparisons.js: - (*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) - -ieee754/index.js: - (*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh *) - -buffer/index.js: - (*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) - -safe-buffer/index.js: - (*! safe-buffer. MIT License. Feross Aboukhadijeh *) -*/ diff --git a/crates/execution/assets/generated/v8-bridge.js b/crates/execution/assets/generated/v8-bridge.js deleted file mode 100644 index dc58f74d7..000000000 --- a/crates/execution/assets/generated/v8-bridge.js +++ /dev/null @@ -1,229 +0,0 @@ -if(typeof globalThis.global==="undefined"){globalThis.global=globalThis;}if(typeof globalThis.process==="undefined"){globalThis.process={env:{},argv:["node"],browser:false,version:"v22.0.0",versions:{node:"22.0.0"},nextTick(callback,...args){return Promise.resolve().then(()=>callback(...args));}};} -(()=>{var Ca=Object.create;var lr=Object.defineProperty;var Ta=Object.getOwnPropertyDescriptor;var Pa=Object.getOwnPropertyNames;var va=Object.getPrototypeOf,Ea=Object.prototype.hasOwnProperty;var qa=(b,s,l)=>s in b?lr(b,s,{enumerable:!0,configurable:!0,writable:!0,value:l}):b[s]=l;var Wa=(b,s)=>()=>(s||b((s={exports:{}}).exports,s),s.exports);var Aa=(b,s,l,g)=>{if(s&&typeof s=="object"||typeof s=="function")for(let c of Pa(s))!Ea.call(b,c)&&c!==l&&lr(b,c,{get:()=>s[c],enumerable:!(g=Ta(s,c))||g.enumerable});return b};var ka=(b,s,l)=>(l=b!=null?Ca(va(b)):{},Aa(s||!b||!b.__esModule?lr(l,"default",{value:b,enumerable:!0}):l,b));var L=(b,s,l)=>qa(b,typeof s!="symbol"?s+"":s,l);var kn=Wa((St,An)=>{(function(b,s){typeof St=="object"&&typeof An<"u"?s(St):typeof define=="function"&&define.amd?define(["exports"],s):(b=typeof globalThis<"u"?globalThis:b||self,s(b.WebStreamsPolyfill={}))})(St,(function(b){"use strict";function s(){}function l(e){return typeof e=="object"&&e!==null||typeof e=="function"}let g=s;function c(e,t){try{Object.defineProperty(e,"name",{value:t,configurable:!0})}catch{}}let pe=Promise,ur=Promise.prototype.then,ie=Promise.reject.bind(pe);function R(e){return new pe(e)}function p(e){return R(t=>t(e))}function d(e){return ie(e)}function I(e,t,r){return ur.call(e,t,r)}function T(e,t,r){I(I(e,t,r),void 0,g)}function Be(e,t){T(e,t)}function gt(e,t){T(e,void 0,t)}function M(e,t,r){return I(e,t,r)}function ye(e){I(e,void 0,g)}let se=e=>{if(typeof queueMicrotask=="function")se=queueMicrotask;else{let t=p(void 0);se=r=>I(t,r)}return se(e)};function le(e,t,r){if(typeof e!="function")throw new TypeError("Argument is not a function");return Function.prototype.apply.call(e,t,r)}function Z(e,t,r){try{return p(le(e,t,r))}catch(n){return d(n)}}let dr=16384;class W{constructor(){this._cursor=0,this._size=0,this._front={_elements:[],_next:void 0},this._back=this._front,this._cursor=0,this._size=0}get length(){return this._size}push(t){let r=this._back,n=r;r._elements.length===dr-1&&(n={_elements:[],_next:void 0}),r._elements.push(t),n!==r&&(this._back=n,r._next=n),++this._size}shift(){let t=this._front,r=t,n=this._cursor,o=n+1,a=t._elements,i=a[n];return o===dr&&(r=t._next,o=0),--this._size,this._cursor=o,t!==r&&(this._front=r),a[n]=void 0,i}forEach(t){let r=this._cursor,n=this._front,o=n._elements;for(;(r!==o.length||n._next!==void 0)&&!(r===o.length&&(n=n._next,o=n._elements,r=0,o.length===0));)t(o[r]),++r}peek(){let t=this._front,r=this._cursor;return t._elements[r]}}let fr=Symbol("[[AbortSteps]]"),cr=Symbol("[[ErrorSteps]]"),Rt=Symbol("[[CancelSteps]]"),wt=Symbol("[[PullSteps]]"),Ct=Symbol("[[ReleaseSteps]]");function hr(e,t){e._ownerReadableStream=t,t._reader=e,t._state==="readable"?Pt(e):t._state==="closed"?Bn(e):br(e,t._storedError)}function Tt(e,t){let r=e._ownerReadableStream;return j(r,t)}function $(e){let t=e._ownerReadableStream;t._state==="readable"?vt(e,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")):In(e,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")),t._readableStreamController[Ct](),t._reader=void 0,e._ownerReadableStream=void 0}function Qe(e){return new TypeError("Cannot "+e+" a stream using a released reader")}function Pt(e){e._closedPromise=R((t,r)=>{e._closedPromise_resolve=t,e._closedPromise_reject=r})}function br(e,t){Pt(e),vt(e,t)}function Bn(e){Pt(e),mr(e)}function vt(e,t){e._closedPromise_reject!==void 0&&(ye(e._closedPromise),e._closedPromise_reject(t),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0)}function In(e,t){br(e,t)}function mr(e){e._closedPromise_resolve!==void 0&&(e._closedPromise_resolve(void 0),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0)}let _r=Number.isFinite||function(e){return typeof e=="number"&&isFinite(e)},On=Math.trunc||function(e){return e<0?Math.ceil(e):Math.floor(e)};function jn(e){return typeof e=="object"||typeof e=="function"}function F(e,t){if(e!==void 0&&!jn(e))throw new TypeError(`${t} is not an object.`)}function A(e,t){if(typeof e!="function")throw new TypeError(`${t} is not a function.`)}function zn(e){return typeof e=="object"&&e!==null||typeof e=="function"}function pr(e,t){if(!zn(e))throw new TypeError(`${t} is not an object.`)}function U(e,t,r){if(e===void 0)throw new TypeError(`Parameter ${t} is required in '${r}'.`)}function Et(e,t,r){if(e===void 0)throw new TypeError(`${t} is required in '${r}'.`)}function qt(e){return Number(e)}function yr(e){return e===0?0:e}function Fn(e){return yr(On(e))}function Wt(e,t){let n=Number.MAX_SAFE_INTEGER,o=Number(e);if(o=yr(o),!_r(o))throw new TypeError(`${t} is not a finite number`);if(o=Fn(o),o<0||o>n)throw new TypeError(`${t} is outside the accepted range of 0 to ${n}, inclusive`);return!_r(o)||o===0?0:o}function At(e,t){if(!re(e))throw new TypeError(`${t} is not a ReadableStream.`)}function Se(e){return new X(e)}function Sr(e,t){e._reader._readRequests.push(t)}function kt(e,t,r){let o=e._reader._readRequests.shift();r?o._closeSteps():o._chunkSteps(t)}function Ne(e){return e._reader._readRequests.length}function gr(e){let t=e._reader;return!(t===void 0||!J(t))}class X{constructor(t){if(U(t,1,"ReadableStreamDefaultReader"),At(t,"First parameter"),ne(t))throw new TypeError("This stream has already been locked for exclusive reading by another reader");hr(this,t),this._readRequests=new W}get closed(){return J(this)?this._closedPromise:d(Ye("closed"))}cancel(t=void 0){return J(this)?this._ownerReadableStream===void 0?d(Qe("cancel")):Tt(this,t):d(Ye("cancel"))}read(){if(!J(this))return d(Ye("read"));if(this._ownerReadableStream===void 0)return d(Qe("read from"));let t,r,n=R((a,i)=>{t=a,r=i});return Ie(this,{_chunkSteps:a=>t({value:a,done:!1}),_closeSteps:()=>t({value:void 0,done:!0}),_errorSteps:a=>r(a)}),n}releaseLock(){if(!J(this))throw Ye("releaseLock");this._ownerReadableStream!==void 0&&Dn(this)}}Object.defineProperties(X.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),c(X.prototype.cancel,"cancel"),c(X.prototype.read,"read"),c(X.prototype.releaseLock,"releaseLock"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(X.prototype,Symbol.toStringTag,{value:"ReadableStreamDefaultReader",configurable:!0});function J(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_readRequests")?!1:e instanceof X}function Ie(e,t){let r=e._ownerReadableStream;r._disturbed=!0,r._state==="closed"?t._closeSteps():r._state==="errored"?t._errorSteps(r._storedError):r._readableStreamController[wt](t)}function Dn(e){$(e);let t=new TypeError("Reader was released");Rr(e,t)}function Rr(e,t){let r=e._readRequests;e._readRequests=new W,r.forEach(n=>{n._errorSteps(t)})}function Ye(e){return new TypeError(`ReadableStreamDefaultReader.prototype.${e} can only be used on a ReadableStreamDefaultReader`)}let Ln=Object.getPrototypeOf(Object.getPrototypeOf(async function*(){}).prototype);class wr{constructor(t,r){this._ongoingPromise=void 0,this._isFinished=!1,this._reader=t,this._preventCancel=r}next(){let t=()=>this._nextSteps();return this._ongoingPromise=this._ongoingPromise?M(this._ongoingPromise,t,t):t(),this._ongoingPromise}return(t){let r=()=>this._returnSteps(t);return this._ongoingPromise?M(this._ongoingPromise,r,r):r()}_nextSteps(){if(this._isFinished)return Promise.resolve({value:void 0,done:!0});let t=this._reader,r,n,o=R((i,u)=>{r=i,n=u});return Ie(t,{_chunkSteps:i=>{this._ongoingPromise=void 0,se(()=>r({value:i,done:!1}))},_closeSteps:()=>{this._ongoingPromise=void 0,this._isFinished=!0,$(t),r({value:void 0,done:!0})},_errorSteps:i=>{this._ongoingPromise=void 0,this._isFinished=!0,$(t),n(i)}}),o}_returnSteps(t){if(this._isFinished)return Promise.resolve({value:t,done:!0});this._isFinished=!0;let r=this._reader;if(!this._preventCancel){let n=Tt(r,t);return $(r),M(n,()=>({value:t,done:!0}))}return $(r),p({value:t,done:!0})}}let Cr={next(){return Tr(this)?this._asyncIteratorImpl.next():d(Pr("next"))},return(e){return Tr(this)?this._asyncIteratorImpl.return(e):d(Pr("return"))}};Object.setPrototypeOf(Cr,Ln);function Mn(e,t){let r=Se(e),n=new wr(r,t),o=Object.create(Cr);return o._asyncIteratorImpl=n,o}function Tr(e){if(!l(e)||!Object.prototype.hasOwnProperty.call(e,"_asyncIteratorImpl"))return!1;try{return e._asyncIteratorImpl instanceof wr}catch{return!1}}function Pr(e){return new TypeError(`ReadableStreamAsyncIterator.${e} can only be used on a ReadableSteamAsyncIterator`)}let vr=Number.isNaN||function(e){return e!==e};var Bt,It,Ot;function Oe(e){return e.slice()}function Er(e,t,r,n,o){new Uint8Array(e).set(new Uint8Array(r,n,o),t)}let Q=e=>(typeof e.transfer=="function"?Q=t=>t.transfer():typeof structuredClone=="function"?Q=t=>structuredClone(t,{transfer:[t]}):Q=t=>t,Q(e)),K=e=>(typeof e.detached=="boolean"?K=t=>t.detached:K=t=>t.byteLength===0,K(e));function qr(e,t,r){if(e.slice)return e.slice(t,r);let n=r-t,o=new ArrayBuffer(n);return Er(o,0,e,t,n),o}function Ve(e,t){let r=e[t];if(r!=null){if(typeof r!="function")throw new TypeError(`${String(t)} is not a function`);return r}}function $n(e){let t={[Symbol.iterator]:()=>e.iterator},r=(async function*(){return yield*t})(),n=r.next;return{iterator:r,nextMethod:n,done:!1}}let jt=(Ot=(Bt=Symbol.asyncIterator)!==null&&Bt!==void 0?Bt:(It=Symbol.for)===null||It===void 0?void 0:It.call(Symbol,"Symbol.asyncIterator"))!==null&&Ot!==void 0?Ot:"@@asyncIterator";function Wr(e,t="sync",r){if(r===void 0)if(t==="async"){if(r=Ve(e,jt),r===void 0){let a=Ve(e,Symbol.iterator),i=Wr(e,"sync",a);return $n(i)}}else r=Ve(e,Symbol.iterator);if(r===void 0)throw new TypeError("The object is not iterable");let n=le(r,e,[]);if(!l(n))throw new TypeError("The iterator method must return an object");let o=n.next;return{iterator:n,nextMethod:o,done:!1}}function Un(e){let t=le(e.nextMethod,e.iterator,[]);if(!l(t))throw new TypeError("The iterator.next() method must return an object");return t}function Qn(e){return!!e.done}function Nn(e){return e.value}function Yn(e){return!(typeof e!="number"||vr(e)||e<0)}function Ar(e){let t=qr(e.buffer,e.byteOffset,e.byteOffset+e.byteLength);return new Uint8Array(t)}function zt(e){let t=e._queue.shift();return e._queueTotalSize-=t.size,e._queueTotalSize<0&&(e._queueTotalSize=0),t.value}function Ft(e,t,r){if(!Yn(r)||r===1/0)throw new RangeError("Size must be a finite, non-NaN, non-negative number.");e._queue.push({value:t,size:r}),e._queueTotalSize+=r}function Vn(e){return e._queue.peek().value}function x(e){e._queue=new W,e._queueTotalSize=0}function kr(e){return e===DataView}function Hn(e){return kr(e.constructor)}function Gn(e){return kr(e)?1:e.BYTES_PER_ELEMENT}class ue{constructor(){throw new TypeError("Illegal constructor")}get view(){if(!Dt(this))throw Qt("view");return this._view}respond(t){if(!Dt(this))throw Qt("respond");if(U(t,1,"respond"),t=Wt(t,"First parameter"),this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(K(this._view.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be used as a response");Xe(this._associatedReadableByteStreamController,t)}respondWithNewView(t){if(!Dt(this))throw Qt("respondWithNewView");if(U(t,1,"respondWithNewView"),!ArrayBuffer.isView(t))throw new TypeError("You can only respond with array buffer views");if(this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(K(t.buffer))throw new TypeError("The given view's buffer has been detached and so cannot be used as a response");Je(this._associatedReadableByteStreamController,t)}}Object.defineProperties(ue.prototype,{respond:{enumerable:!0},respondWithNewView:{enumerable:!0},view:{enumerable:!0}}),c(ue.prototype.respond,"respond"),c(ue.prototype.respondWithNewView,"respondWithNewView"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ue.prototype,Symbol.toStringTag,{value:"ReadableStreamBYOBRequest",configurable:!0});class N{constructor(){throw new TypeError("Illegal constructor")}get byobRequest(){if(!de(this))throw ze("byobRequest");return Ut(this)}get desiredSize(){if(!de(this))throw ze("desiredSize");return $r(this)}close(){if(!de(this))throw ze("close");if(this._closeRequested)throw new TypeError("The stream has already been closed; do not close it again!");let t=this._controlledReadableByteStream._state;if(t!=="readable")throw new TypeError(`The stream (in ${t} state) is not in the readable state and cannot be closed`);je(this)}enqueue(t){if(!de(this))throw ze("enqueue");if(U(t,1,"enqueue"),!ArrayBuffer.isView(t))throw new TypeError("chunk must be an array buffer view");if(t.byteLength===0)throw new TypeError("chunk must have non-zero byteLength");if(t.buffer.byteLength===0)throw new TypeError("chunk's buffer must have non-zero byteLength");if(this._closeRequested)throw new TypeError("stream is closed or draining");let r=this._controlledReadableByteStream._state;if(r!=="readable")throw new TypeError(`The stream (in ${r} state) is not in the readable state and cannot be enqueued to`);Ze(this,t)}error(t=void 0){if(!de(this))throw ze("error");k(this,t)}[Rt](t){Br(this),x(this);let r=this._cancelAlgorithm(t);return Ge(this),r}[wt](t){let r=this._controlledReadableByteStream;if(this._queueTotalSize>0){Mr(this,t);return}let n=this._autoAllocateChunkSize;if(n!==void 0){let o;try{o=new ArrayBuffer(n)}catch(i){t._errorSteps(i);return}let a={buffer:o,bufferByteLength:n,byteOffset:0,byteLength:n,bytesFilled:0,minimumFill:1,elementSize:1,viewConstructor:Uint8Array,readerType:"default"};this._pendingPullIntos.push(a)}Sr(r,t),fe(this)}[Ct](){if(this._pendingPullIntos.length>0){let t=this._pendingPullIntos.peek();t.readerType="none",this._pendingPullIntos=new W,this._pendingPullIntos.push(t)}}}Object.defineProperties(N.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},byobRequest:{enumerable:!0},desiredSize:{enumerable:!0}}),c(N.prototype.close,"close"),c(N.prototype.enqueue,"enqueue"),c(N.prototype.error,"error"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(N.prototype,Symbol.toStringTag,{value:"ReadableByteStreamController",configurable:!0});function de(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledReadableByteStream")?!1:e instanceof N}function Dt(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_associatedReadableByteStreamController")?!1:e instanceof ue}function fe(e){if(!xn(e))return;if(e._pulling){e._pullAgain=!0;return}e._pulling=!0;let r=e._pullAlgorithm();T(r,()=>(e._pulling=!1,e._pullAgain&&(e._pullAgain=!1,fe(e)),null),n=>(k(e,n),null))}function Br(e){Mt(e),e._pendingPullIntos=new W}function Lt(e,t){let r=!1;e._state==="closed"&&(r=!0);let n=Ir(t);t.readerType==="default"?kt(e,n,r):ao(e,n,r)}function Ir(e){let t=e.bytesFilled,r=e.elementSize;return new e.viewConstructor(e.buffer,e.byteOffset,t/r)}function He(e,t,r,n){e._queue.push({buffer:t,byteOffset:r,byteLength:n}),e._queueTotalSize+=n}function Or(e,t,r,n){let o;try{o=qr(t,r,r+n)}catch(a){throw k(e,a),a}He(e,o,0,n)}function jr(e,t){t.bytesFilled>0&&Or(e,t.buffer,t.byteOffset,t.bytesFilled),ge(e)}function zr(e,t){let r=Math.min(e._queueTotalSize,t.byteLength-t.bytesFilled),n=t.bytesFilled+r,o=r,a=!1,i=n%t.elementSize,u=n-i;u>=t.minimumFill&&(o=u-t.bytesFilled,a=!0);let m=e._queue;for(;o>0;){let f=m.peek(),_=Math.min(o,f.byteLength),y=t.byteOffset+t.bytesFilled;Er(t.buffer,y,f.buffer,f.byteOffset,_),f.byteLength===_?m.shift():(f.byteOffset+=_,f.byteLength-=_),e._queueTotalSize-=_,Fr(e,_,t),o-=_}return a}function Fr(e,t,r){r.bytesFilled+=t}function Dr(e){e._queueTotalSize===0&&e._closeRequested?(Ge(e),Ue(e._controlledReadableByteStream)):fe(e)}function Mt(e){e._byobRequest!==null&&(e._byobRequest._associatedReadableByteStreamController=void 0,e._byobRequest._view=null,e._byobRequest=null)}function $t(e){for(;e._pendingPullIntos.length>0;){if(e._queueTotalSize===0)return;let t=e._pendingPullIntos.peek();zr(e,t)&&(ge(e),Lt(e._controlledReadableByteStream,t))}}function Zn(e){let t=e._controlledReadableByteStream._reader;for(;t._readRequests.length>0;){if(e._queueTotalSize===0)return;let r=t._readRequests.shift();Mr(e,r)}}function Xn(e,t,r,n){let o=e._controlledReadableByteStream,a=t.constructor,i=Gn(a),{byteOffset:u,byteLength:m}=t,f=r*i,_;try{_=Q(t.buffer)}catch(w){n._errorSteps(w);return}let y={buffer:_,bufferByteLength:_.byteLength,byteOffset:u,byteLength:m,bytesFilled:0,minimumFill:f,elementSize:i,viewConstructor:a,readerType:"byob"};if(e._pendingPullIntos.length>0){e._pendingPullIntos.push(y),Nr(o,n);return}if(o._state==="closed"){let w=new a(y.buffer,y.byteOffset,0);n._closeSteps(w);return}if(e._queueTotalSize>0){if(zr(e,y)){let w=Ir(y);Dr(e),n._chunkSteps(w);return}if(e._closeRequested){let w=new TypeError("Insufficient bytes to fill elements in the given buffer");k(e,w),n._errorSteps(w);return}}e._pendingPullIntos.push(y),Nr(o,n),fe(e)}function Jn(e,t){t.readerType==="none"&&ge(e);let r=e._controlledReadableByteStream;if(Nt(r))for(;Yr(r)>0;){let n=ge(e);Lt(r,n)}}function Kn(e,t,r){if(Fr(e,t,r),r.readerType==="none"){jr(e,r),$t(e);return}if(r.bytesFilled0){let o=r.byteOffset+r.bytesFilled;Or(e,r.buffer,o-n,n)}r.bytesFilled-=n,Lt(e._controlledReadableByteStream,r),$t(e)}function Lr(e,t){let r=e._pendingPullIntos.peek();Mt(e),e._controlledReadableByteStream._state==="closed"?Jn(e,r):Kn(e,t,r),fe(e)}function ge(e){return e._pendingPullIntos.shift()}function xn(e){let t=e._controlledReadableByteStream;return t._state!=="readable"||e._closeRequested||!e._started?!1:!!(gr(t)&&Ne(t)>0||Nt(t)&&Yr(t)>0||$r(e)>0)}function Ge(e){e._pullAlgorithm=void 0,e._cancelAlgorithm=void 0}function je(e){let t=e._controlledReadableByteStream;if(!(e._closeRequested||t._state!=="readable")){if(e._queueTotalSize>0){e._closeRequested=!0;return}if(e._pendingPullIntos.length>0){let r=e._pendingPullIntos.peek();if(r.bytesFilled%r.elementSize!==0){let n=new TypeError("Insufficient bytes to fill elements in the given buffer");throw k(e,n),n}}Ge(e),Ue(t)}}function Ze(e,t){let r=e._controlledReadableByteStream;if(e._closeRequested||r._state!=="readable")return;let{buffer:n,byteOffset:o,byteLength:a}=t;if(K(n))throw new TypeError("chunk's buffer is detached and so cannot be enqueued");let i=Q(n);if(e._pendingPullIntos.length>0){let u=e._pendingPullIntos.peek();if(K(u.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk");Mt(e),u.buffer=Q(u.buffer),u.readerType==="none"&&jr(e,u)}if(gr(r))if(Zn(e),Ne(r)===0)He(e,i,o,a);else{e._pendingPullIntos.length>0&&ge(e);let u=new Uint8Array(i,o,a);kt(r,u,!1)}else Nt(r)?(He(e,i,o,a),$t(e)):He(e,i,o,a);fe(e)}function k(e,t){let r=e._controlledReadableByteStream;r._state==="readable"&&(Br(e),x(e),Ge(e),_n(r,t))}function Mr(e,t){let r=e._queue.shift();e._queueTotalSize-=r.byteLength,Dr(e);let n=new Uint8Array(r.buffer,r.byteOffset,r.byteLength);t._chunkSteps(n)}function Ut(e){if(e._byobRequest===null&&e._pendingPullIntos.length>0){let t=e._pendingPullIntos.peek(),r=new Uint8Array(t.buffer,t.byteOffset+t.bytesFilled,t.byteLength-t.bytesFilled),n=Object.create(ue.prototype);to(n,e,r),e._byobRequest=n}return e._byobRequest}function $r(e){let t=e._controlledReadableByteStream._state;return t==="errored"?null:t==="closed"?0:e._strategyHWM-e._queueTotalSize}function Xe(e,t){let r=e._pendingPullIntos.peek();if(e._controlledReadableByteStream._state==="closed"){if(t!==0)throw new TypeError("bytesWritten must be 0 when calling respond() on a closed stream")}else{if(t===0)throw new TypeError("bytesWritten must be greater than 0 when calling respond() on a readable stream");if(r.bytesFilled+t>r.byteLength)throw new RangeError("bytesWritten out of range")}r.buffer=Q(r.buffer),Lr(e,t)}function Je(e,t){let r=e._pendingPullIntos.peek();if(e._controlledReadableByteStream._state==="closed"){if(t.byteLength!==0)throw new TypeError("The view's length must be 0 when calling respondWithNewView() on a closed stream")}else if(t.byteLength===0)throw new TypeError("The view's length must be greater than 0 when calling respondWithNewView() on a readable stream");if(r.byteOffset+r.bytesFilled!==t.byteOffset)throw new RangeError("The region specified by view does not match byobRequest");if(r.bufferByteLength!==t.buffer.byteLength)throw new RangeError("The buffer of view has different capacity than byobRequest");if(r.bytesFilled+t.byteLength>r.byteLength)throw new RangeError("The region specified by view is larger than byobRequest");let o=t.byteLength;r.buffer=Q(t.buffer),Lr(e,o)}function Ur(e,t,r,n,o,a,i){t._controlledReadableByteStream=e,t._pullAgain=!1,t._pulling=!1,t._byobRequest=null,t._queue=t._queueTotalSize=void 0,x(t),t._closeRequested=!1,t._started=!1,t._strategyHWM=a,t._pullAlgorithm=n,t._cancelAlgorithm=o,t._autoAllocateChunkSize=i,t._pendingPullIntos=new W,e._readableStreamController=t;let u=r();T(p(u),()=>(t._started=!0,fe(t),null),m=>(k(t,m),null))}function eo(e,t,r){let n=Object.create(N.prototype),o,a,i;t.start!==void 0?o=()=>t.start(n):o=()=>{},t.pull!==void 0?a=()=>t.pull(n):a=()=>p(void 0),t.cancel!==void 0?i=m=>t.cancel(m):i=()=>p(void 0);let u=t.autoAllocateChunkSize;if(u===0)throw new TypeError("autoAllocateChunkSize must be greater than 0");Ur(e,n,o,a,i,r,u)}function to(e,t,r){e._associatedReadableByteStreamController=t,e._view=r}function Qt(e){return new TypeError(`ReadableStreamBYOBRequest.prototype.${e} can only be used on a ReadableStreamBYOBRequest`)}function ze(e){return new TypeError(`ReadableByteStreamController.prototype.${e} can only be used on a ReadableByteStreamController`)}function ro(e,t){F(e,t);let r=e?.mode;return{mode:r===void 0?void 0:no(r,`${t} has member 'mode' that`)}}function no(e,t){if(e=`${e}`,e!=="byob")throw new TypeError(`${t} '${e}' is not a valid enumeration value for ReadableStreamReaderMode`);return e}function oo(e,t){var r;F(e,t);let n=(r=e?.min)!==null&&r!==void 0?r:1;return{min:Wt(n,`${t} has member 'min' that`)}}function Qr(e){return new ee(e)}function Nr(e,t){e._reader._readIntoRequests.push(t)}function ao(e,t,r){let o=e._reader._readIntoRequests.shift();r?o._closeSteps(t):o._chunkSteps(t)}function Yr(e){return e._reader._readIntoRequests.length}function Nt(e){let t=e._reader;return!(t===void 0||!ce(t))}class ee{constructor(t){if(U(t,1,"ReadableStreamBYOBReader"),At(t,"First parameter"),ne(t))throw new TypeError("This stream has already been locked for exclusive reading by another reader");if(!de(t._readableStreamController))throw new TypeError("Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte source");hr(this,t),this._readIntoRequests=new W}get closed(){return ce(this)?this._closedPromise:d(Ke("closed"))}cancel(t=void 0){return ce(this)?this._ownerReadableStream===void 0?d(Qe("cancel")):Tt(this,t):d(Ke("cancel"))}read(t,r={}){if(!ce(this))return d(Ke("read"));if(!ArrayBuffer.isView(t))return d(new TypeError("view must be an array buffer view"));if(t.byteLength===0)return d(new TypeError("view must have non-zero byteLength"));if(t.buffer.byteLength===0)return d(new TypeError("view's buffer must have non-zero byteLength"));if(K(t.buffer))return d(new TypeError("view's buffer has been detached"));let n;try{n=oo(r,"options")}catch(f){return d(f)}let o=n.min;if(o===0)return d(new TypeError("options.min must be greater than 0"));if(Hn(t)){if(o>t.byteLength)return d(new RangeError("options.min must be less than or equal to view's byteLength"))}else if(o>t.length)return d(new RangeError("options.min must be less than or equal to view's length"));if(this._ownerReadableStream===void 0)return d(Qe("read from"));let a,i,u=R((f,_)=>{a=f,i=_});return Vr(this,t,o,{_chunkSteps:f=>a({value:f,done:!1}),_closeSteps:f=>a({value:f,done:!0}),_errorSteps:f=>i(f)}),u}releaseLock(){if(!ce(this))throw Ke("releaseLock");this._ownerReadableStream!==void 0&&io(this)}}Object.defineProperties(ee.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),c(ee.prototype.cancel,"cancel"),c(ee.prototype.read,"read"),c(ee.prototype.releaseLock,"releaseLock"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ee.prototype,Symbol.toStringTag,{value:"ReadableStreamBYOBReader",configurable:!0});function ce(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_readIntoRequests")?!1:e instanceof ee}function Vr(e,t,r,n){let o=e._ownerReadableStream;o._disturbed=!0,o._state==="errored"?n._errorSteps(o._storedError):Xn(o._readableStreamController,t,r,n)}function io(e){$(e);let t=new TypeError("Reader was released");Hr(e,t)}function Hr(e,t){let r=e._readIntoRequests;e._readIntoRequests=new W,r.forEach(n=>{n._errorSteps(t)})}function Ke(e){return new TypeError(`ReadableStreamBYOBReader.prototype.${e} can only be used on a ReadableStreamBYOBReader`)}function Fe(e,t){let{highWaterMark:r}=e;if(r===void 0)return t;if(vr(r)||r<0)throw new RangeError("Invalid highWaterMark");return r}function xe(e){let{size:t}=e;return t||(()=>1)}function et(e,t){F(e,t);let r=e?.highWaterMark,n=e?.size;return{highWaterMark:r===void 0?void 0:qt(r),size:n===void 0?void 0:so(n,`${t} has member 'size' that`)}}function so(e,t){return A(e,t),r=>qt(e(r))}function lo(e,t){F(e,t);let r=e?.abort,n=e?.close,o=e?.start,a=e?.type,i=e?.write;return{abort:r===void 0?void 0:uo(r,e,`${t} has member 'abort' that`),close:n===void 0?void 0:fo(n,e,`${t} has member 'close' that`),start:o===void 0?void 0:co(o,e,`${t} has member 'start' that`),write:i===void 0?void 0:ho(i,e,`${t} has member 'write' that`),type:a}}function uo(e,t,r){return A(e,r),n=>Z(e,t,[n])}function fo(e,t,r){return A(e,r),()=>Z(e,t,[])}function co(e,t,r){return A(e,r),n=>le(e,t,[n])}function ho(e,t,r){return A(e,r),(n,o)=>Z(e,t,[n,o])}function Gr(e,t){if(!Re(e))throw new TypeError(`${t} is not a WritableStream.`)}function bo(e){if(typeof e!="object"||e===null)return!1;try{return typeof e.aborted=="boolean"}catch{return!1}}let mo=typeof AbortController=="function";function _o(){if(mo)return new AbortController}class te{constructor(t={},r={}){t===void 0?t=null:pr(t,"First parameter");let n=et(r,"Second parameter"),o=lo(t,"First parameter");if(Xr(this),o.type!==void 0)throw new RangeError("Invalid type is specified");let i=xe(n),u=Fe(n,1);Ao(this,o,u,i)}get locked(){if(!Re(this))throw at("locked");return we(this)}abort(t=void 0){return Re(this)?we(this)?d(new TypeError("Cannot abort a stream that already has a writer")):tt(this,t):d(at("abort"))}close(){return Re(this)?we(this)?d(new TypeError("Cannot close a stream that already has a writer")):D(this)?d(new TypeError("Cannot close an already-closing stream")):Jr(this):d(at("close"))}getWriter(){if(!Re(this))throw at("getWriter");return Zr(this)}}Object.defineProperties(te.prototype,{abort:{enumerable:!0},close:{enumerable:!0},getWriter:{enumerable:!0},locked:{enumerable:!0}}),c(te.prototype.abort,"abort"),c(te.prototype.close,"close"),c(te.prototype.getWriter,"getWriter"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(te.prototype,Symbol.toStringTag,{value:"WritableStream",configurable:!0});function Zr(e){return new Y(e)}function po(e,t,r,n,o=1,a=()=>1){let i=Object.create(te.prototype);Xr(i);let u=Object.create(Ce.prototype);return nn(i,u,e,t,r,n,o,a),i}function Xr(e){e._state="writable",e._storedError=void 0,e._writer=void 0,e._writableStreamController=void 0,e._writeRequests=new W,e._inFlightWriteRequest=void 0,e._closeRequest=void 0,e._inFlightCloseRequest=void 0,e._pendingAbortRequest=void 0,e._backpressure=!1}function Re(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_writableStreamController")?!1:e instanceof te}function we(e){return e._writer!==void 0}function tt(e,t){var r;if(e._state==="closed"||e._state==="errored")return p(void 0);e._writableStreamController._abortReason=t,(r=e._writableStreamController._abortController)===null||r===void 0||r.abort(t);let n=e._state;if(n==="closed"||n==="errored")return p(void 0);if(e._pendingAbortRequest!==void 0)return e._pendingAbortRequest._promise;let o=!1;n==="erroring"&&(o=!0,t=void 0);let a=R((i,u)=>{e._pendingAbortRequest={_promise:void 0,_resolve:i,_reject:u,_reason:t,_wasAlreadyErroring:o}});return e._pendingAbortRequest._promise=a,o||Vt(e,t),a}function Jr(e){let t=e._state;if(t==="closed"||t==="errored")return d(new TypeError(`The stream (in ${t} state) is not in the writable state and cannot be closed`));let r=R((o,a)=>{let i={_resolve:o,_reject:a};e._closeRequest=i}),n=e._writer;return n!==void 0&&e._backpressure&&t==="writable"&&er(n),ko(e._writableStreamController),r}function yo(e){return R((r,n)=>{let o={_resolve:r,_reject:n};e._writeRequests.push(o)})}function Yt(e,t){if(e._state==="writable"){Vt(e,t);return}Ht(e)}function Vt(e,t){let r=e._writableStreamController;e._state="erroring",e._storedError=t;let n=e._writer;n!==void 0&&xr(n,t),!Co(e)&&r._started&&Ht(e)}function Ht(e){e._state="errored",e._writableStreamController[cr]();let t=e._storedError;if(e._writeRequests.forEach(o=>{o._reject(t)}),e._writeRequests=new W,e._pendingAbortRequest===void 0){rt(e);return}let r=e._pendingAbortRequest;if(e._pendingAbortRequest=void 0,r._wasAlreadyErroring){r._reject(t),rt(e);return}let n=e._writableStreamController[fr](r._reason);T(n,()=>(r._resolve(),rt(e),null),o=>(r._reject(o),rt(e),null))}function So(e){e._inFlightWriteRequest._resolve(void 0),e._inFlightWriteRequest=void 0}function go(e,t){e._inFlightWriteRequest._reject(t),e._inFlightWriteRequest=void 0,Yt(e,t)}function Ro(e){e._inFlightCloseRequest._resolve(void 0),e._inFlightCloseRequest=void 0,e._state==="erroring"&&(e._storedError=void 0,e._pendingAbortRequest!==void 0&&(e._pendingAbortRequest._resolve(),e._pendingAbortRequest=void 0)),e._state="closed";let r=e._writer;r!==void 0&&ln(r)}function wo(e,t){e._inFlightCloseRequest._reject(t),e._inFlightCloseRequest=void 0,e._pendingAbortRequest!==void 0&&(e._pendingAbortRequest._reject(t),e._pendingAbortRequest=void 0),Yt(e,t)}function D(e){return!(e._closeRequest===void 0&&e._inFlightCloseRequest===void 0)}function Co(e){return!(e._inFlightWriteRequest===void 0&&e._inFlightCloseRequest===void 0)}function To(e){e._inFlightCloseRequest=e._closeRequest,e._closeRequest=void 0}function Po(e){e._inFlightWriteRequest=e._writeRequests.shift()}function rt(e){e._closeRequest!==void 0&&(e._closeRequest._reject(e._storedError),e._closeRequest=void 0);let t=e._writer;t!==void 0&&Kt(t,e._storedError)}function Gt(e,t){let r=e._writer;r!==void 0&&t!==e._backpressure&&(t?Do(r):er(r)),e._backpressure=t}class Y{constructor(t){if(U(t,1,"WritableStreamDefaultWriter"),Gr(t,"First parameter"),we(t))throw new TypeError("This stream has already been locked for exclusive writing by another writer");this._ownerWritableStream=t,t._writer=this;let r=t._state;if(r==="writable")!D(t)&&t._backpressure?st(this):un(this),it(this);else if(r==="erroring")xt(this,t._storedError),it(this);else if(r==="closed")un(this),zo(this);else{let n=t._storedError;xt(this,n),sn(this,n)}}get closed(){return he(this)?this._closedPromise:d(be("closed"))}get desiredSize(){if(!he(this))throw be("desiredSize");if(this._ownerWritableStream===void 0)throw Le("desiredSize");return Wo(this)}get ready(){return he(this)?this._readyPromise:d(be("ready"))}abort(t=void 0){return he(this)?this._ownerWritableStream===void 0?d(Le("abort")):vo(this,t):d(be("abort"))}close(){if(!he(this))return d(be("close"));let t=this._ownerWritableStream;return t===void 0?d(Le("close")):D(t)?d(new TypeError("Cannot close an already-closing stream")):Kr(this)}releaseLock(){if(!he(this))throw be("releaseLock");this._ownerWritableStream!==void 0&&en(this)}write(t=void 0){return he(this)?this._ownerWritableStream===void 0?d(Le("write to")):tn(this,t):d(be("write"))}}Object.defineProperties(Y.prototype,{abort:{enumerable:!0},close:{enumerable:!0},releaseLock:{enumerable:!0},write:{enumerable:!0},closed:{enumerable:!0},desiredSize:{enumerable:!0},ready:{enumerable:!0}}),c(Y.prototype.abort,"abort"),c(Y.prototype.close,"close"),c(Y.prototype.releaseLock,"releaseLock"),c(Y.prototype.write,"write"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Y.prototype,Symbol.toStringTag,{value:"WritableStreamDefaultWriter",configurable:!0});function he(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_ownerWritableStream")?!1:e instanceof Y}function vo(e,t){let r=e._ownerWritableStream;return tt(r,t)}function Kr(e){let t=e._ownerWritableStream;return Jr(t)}function Eo(e){let t=e._ownerWritableStream,r=t._state;return D(t)||r==="closed"?p(void 0):r==="errored"?d(t._storedError):Kr(e)}function qo(e,t){e._closedPromiseState==="pending"?Kt(e,t):Fo(e,t)}function xr(e,t){e._readyPromiseState==="pending"?dn(e,t):Lo(e,t)}function Wo(e){let t=e._ownerWritableStream,r=t._state;return r==="errored"||r==="erroring"?null:r==="closed"?0:on(t._writableStreamController)}function en(e){let t=e._ownerWritableStream,r=new TypeError("Writer was released and can no longer be used to monitor the stream's closedness");xr(e,r),qo(e,r),t._writer=void 0,e._ownerWritableStream=void 0}function tn(e,t){let r=e._ownerWritableStream,n=r._writableStreamController,o=Bo(n,t);if(r!==e._ownerWritableStream)return d(Le("write to"));let a=r._state;if(a==="errored")return d(r._storedError);if(D(r)||a==="closed")return d(new TypeError("The stream is closing or closed and cannot be written to"));if(a==="erroring")return d(r._storedError);let i=yo(r);return Io(n,t,o),i}let rn={};class Ce{constructor(){throw new TypeError("Illegal constructor")}get abortReason(){if(!Zt(this))throw Jt("abortReason");return this._abortReason}get signal(){if(!Zt(this))throw Jt("signal");if(this._abortController===void 0)throw new TypeError("WritableStreamDefaultController.prototype.signal is not supported");return this._abortController.signal}error(t=void 0){if(!Zt(this))throw Jt("error");this._controlledWritableStream._state==="writable"&&an(this,t)}[fr](t){let r=this._abortAlgorithm(t);return nt(this),r}[cr](){x(this)}}Object.defineProperties(Ce.prototype,{abortReason:{enumerable:!0},signal:{enumerable:!0},error:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Ce.prototype,Symbol.toStringTag,{value:"WritableStreamDefaultController",configurable:!0});function Zt(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledWritableStream")?!1:e instanceof Ce}function nn(e,t,r,n,o,a,i,u){t._controlledWritableStream=e,e._writableStreamController=t,t._queue=void 0,t._queueTotalSize=void 0,x(t),t._abortReason=void 0,t._abortController=_o(),t._started=!1,t._strategySizeAlgorithm=u,t._strategyHWM=i,t._writeAlgorithm=n,t._closeAlgorithm=o,t._abortAlgorithm=a;let m=Xt(t);Gt(e,m);let f=r(),_=p(f);T(_,()=>(t._started=!0,ot(t),null),y=>(t._started=!0,Yt(e,y),null))}function Ao(e,t,r,n){let o=Object.create(Ce.prototype),a,i,u,m;t.start!==void 0?a=()=>t.start(o):a=()=>{},t.write!==void 0?i=f=>t.write(f,o):i=()=>p(void 0),t.close!==void 0?u=()=>t.close():u=()=>p(void 0),t.abort!==void 0?m=f=>t.abort(f):m=()=>p(void 0),nn(e,o,a,i,u,m,r,n)}function nt(e){e._writeAlgorithm=void 0,e._closeAlgorithm=void 0,e._abortAlgorithm=void 0,e._strategySizeAlgorithm=void 0}function ko(e){Ft(e,rn,0),ot(e)}function Bo(e,t){try{return e._strategySizeAlgorithm(t)}catch(r){return De(e,r),1}}function on(e){return e._strategyHWM-e._queueTotalSize}function Io(e,t,r){try{Ft(e,t,r)}catch(o){De(e,o);return}let n=e._controlledWritableStream;if(!D(n)&&n._state==="writable"){let o=Xt(e);Gt(n,o)}ot(e)}function ot(e){let t=e._controlledWritableStream;if(!e._started||t._inFlightWriteRequest!==void 0)return;if(t._state==="erroring"){Ht(t);return}if(e._queue.length===0)return;let n=Vn(e);n===rn?Oo(e):jo(e,n)}function De(e,t){e._controlledWritableStream._state==="writable"&&an(e,t)}function Oo(e){let t=e._controlledWritableStream;To(t),zt(e);let r=e._closeAlgorithm();nt(e),T(r,()=>(Ro(t),null),n=>(wo(t,n),null))}function jo(e,t){let r=e._controlledWritableStream;Po(r);let n=e._writeAlgorithm(t);T(n,()=>{So(r);let o=r._state;if(zt(e),!D(r)&&o==="writable"){let a=Xt(e);Gt(r,a)}return ot(e),null},o=>(r._state==="writable"&&nt(e),go(r,o),null))}function Xt(e){return on(e)<=0}function an(e,t){let r=e._controlledWritableStream;nt(e),Vt(r,t)}function at(e){return new TypeError(`WritableStream.prototype.${e} can only be used on a WritableStream`)}function Jt(e){return new TypeError(`WritableStreamDefaultController.prototype.${e} can only be used on a WritableStreamDefaultController`)}function be(e){return new TypeError(`WritableStreamDefaultWriter.prototype.${e} can only be used on a WritableStreamDefaultWriter`)}function Le(e){return new TypeError("Cannot "+e+" a stream using a released writer")}function it(e){e._closedPromise=R((t,r)=>{e._closedPromise_resolve=t,e._closedPromise_reject=r,e._closedPromiseState="pending"})}function sn(e,t){it(e),Kt(e,t)}function zo(e){it(e),ln(e)}function Kt(e,t){e._closedPromise_reject!==void 0&&(ye(e._closedPromise),e._closedPromise_reject(t),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0,e._closedPromiseState="rejected")}function Fo(e,t){sn(e,t)}function ln(e){e._closedPromise_resolve!==void 0&&(e._closedPromise_resolve(void 0),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0,e._closedPromiseState="resolved")}function st(e){e._readyPromise=R((t,r)=>{e._readyPromise_resolve=t,e._readyPromise_reject=r}),e._readyPromiseState="pending"}function xt(e,t){st(e),dn(e,t)}function un(e){st(e),er(e)}function dn(e,t){e._readyPromise_reject!==void 0&&(ye(e._readyPromise),e._readyPromise_reject(t),e._readyPromise_resolve=void 0,e._readyPromise_reject=void 0,e._readyPromiseState="rejected")}function Do(e){st(e)}function Lo(e,t){xt(e,t)}function er(e){e._readyPromise_resolve!==void 0&&(e._readyPromise_resolve(void 0),e._readyPromise_resolve=void 0,e._readyPromise_reject=void 0,e._readyPromiseState="fulfilled")}function Mo(){if(typeof globalThis<"u")return globalThis;if(typeof self<"u")return self;if(typeof globalThis<"u")return globalThis}let tr=Mo();function $o(e){if(!(typeof e=="function"||typeof e=="object")||e.name!=="DOMException")return!1;try{return new e,!0}catch{return!1}}function Uo(){let e=tr?.DOMException;return $o(e)?e:void 0}function Qo(){let e=function(r,n){this.message=r||"",this.name=n||"Error",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)};return c(e,"DOMException"),e.prototype=Object.create(Error.prototype),Object.defineProperty(e.prototype,"constructor",{value:e,writable:!0,configurable:!0}),e}let No=Uo()||Qo();function fn(e,t,r,n,o,a){let i=Se(e),u=Zr(t);e._disturbed=!0;let m=!1,f=p(void 0);return R((_,y)=>{let w;if(a!==void 0){if(w=()=>{let h=a.reason!==void 0?a.reason:new No("Aborted","AbortError"),S=[];n||S.push(()=>t._state==="writable"?tt(t,h):p(void 0)),o||S.push(()=>e._state==="readable"?j(e,h):p(void 0)),E(()=>Promise.all(S.map(C=>C())),!0,h)},a.aborted){w();return}a.addEventListener("abort",w)}function z(){return R((h,S)=>{function C(q){q?h():I(Ee(),C,S)}C(!1)})}function Ee(){return m?p(!0):I(u._readyPromise,()=>R((h,S)=>{Ie(i,{_chunkSteps:C=>{f=I(tn(u,C),void 0,s),h(!1)},_closeSteps:()=>h(!0),_errorSteps:S})}))}if(H(e,i._closedPromise,h=>(n?B(!0,h):E(()=>tt(t,h),!0,h),null)),H(t,u._closedPromise,h=>(o?B(!0,h):E(()=>j(e,h),!0,h),null)),v(e,i._closedPromise,()=>(r?B():E(()=>Eo(u)),null)),D(t)||t._state==="closed"){let h=new TypeError("the destination writable stream closed before all data could be piped to it");o?B(!0,h):E(()=>j(e,h),!0,h)}ye(z());function ae(){let h=f;return I(f,()=>h!==f?ae():void 0)}function H(h,S,C){h._state==="errored"?C(h._storedError):gt(S,C)}function v(h,S,C){h._state==="closed"?C():Be(S,C)}function E(h,S,C){if(m)return;m=!0,t._state==="writable"&&!D(t)?Be(ae(),q):q();function q(){return T(h(),()=>G(S,C),qe=>G(!0,qe)),null}}function B(h,S){m||(m=!0,t._state==="writable"&&!D(t)?Be(ae(),()=>G(h,S)):G(h,S))}function G(h,S){return en(u),$(i),a!==void 0&&a.removeEventListener("abort",w),h?y(S):_(void 0),null}})}class V{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!lt(this))throw dt("desiredSize");return rr(this)}close(){if(!lt(this))throw dt("close");if(!Pe(this))throw new TypeError("The stream is not in a state that permits close");me(this)}enqueue(t=void 0){if(!lt(this))throw dt("enqueue");if(!Pe(this))throw new TypeError("The stream is not in a state that permits enqueue");return Te(this,t)}error(t=void 0){if(!lt(this))throw dt("error");O(this,t)}[Rt](t){x(this);let r=this._cancelAlgorithm(t);return ut(this),r}[wt](t){let r=this._controlledReadableStream;if(this._queue.length>0){let n=zt(this);this._closeRequested&&this._queue.length===0?(ut(this),Ue(r)):Me(this),t._chunkSteps(n)}else Sr(r,t),Me(this)}[Ct](){}}Object.defineProperties(V.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},desiredSize:{enumerable:!0}}),c(V.prototype.close,"close"),c(V.prototype.enqueue,"enqueue"),c(V.prototype.error,"error"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(V.prototype,Symbol.toStringTag,{value:"ReadableStreamDefaultController",configurable:!0});function lt(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledReadableStream")?!1:e instanceof V}function Me(e){if(!cn(e))return;if(e._pulling){e._pullAgain=!0;return}e._pulling=!0;let r=e._pullAlgorithm();T(r,()=>(e._pulling=!1,e._pullAgain&&(e._pullAgain=!1,Me(e)),null),n=>(O(e,n),null))}function cn(e){let t=e._controlledReadableStream;return!Pe(e)||!e._started?!1:!!(ne(t)&&Ne(t)>0||rr(e)>0)}function ut(e){e._pullAlgorithm=void 0,e._cancelAlgorithm=void 0,e._strategySizeAlgorithm=void 0}function me(e){if(!Pe(e))return;let t=e._controlledReadableStream;e._closeRequested=!0,e._queue.length===0&&(ut(e),Ue(t))}function Te(e,t){if(!Pe(e))return;let r=e._controlledReadableStream;if(ne(r)&&Ne(r)>0)kt(r,t,!1);else{let n;try{n=e._strategySizeAlgorithm(t)}catch(o){throw O(e,o),o}try{Ft(e,t,n)}catch(o){throw O(e,o),o}}Me(e)}function O(e,t){let r=e._controlledReadableStream;r._state==="readable"&&(x(e),ut(e),_n(r,t))}function rr(e){let t=e._controlledReadableStream._state;return t==="errored"?null:t==="closed"?0:e._strategyHWM-e._queueTotalSize}function Yo(e){return!cn(e)}function Pe(e){let t=e._controlledReadableStream._state;return!e._closeRequested&&t==="readable"}function hn(e,t,r,n,o,a,i){t._controlledReadableStream=e,t._queue=void 0,t._queueTotalSize=void 0,x(t),t._started=!1,t._closeRequested=!1,t._pullAgain=!1,t._pulling=!1,t._strategySizeAlgorithm=i,t._strategyHWM=a,t._pullAlgorithm=n,t._cancelAlgorithm=o,e._readableStreamController=t;let u=r();T(p(u),()=>(t._started=!0,Me(t),null),m=>(O(t,m),null))}function Vo(e,t,r,n){let o=Object.create(V.prototype),a,i,u;t.start!==void 0?a=()=>t.start(o):a=()=>{},t.pull!==void 0?i=()=>t.pull(o):i=()=>p(void 0),t.cancel!==void 0?u=m=>t.cancel(m):u=()=>p(void 0),hn(e,o,a,i,u,r,n)}function dt(e){return new TypeError(`ReadableStreamDefaultController.prototype.${e} can only be used on a ReadableStreamDefaultController`)}function Ho(e,t){return de(e._readableStreamController)?Zo(e):Go(e)}function Go(e,t){let r=Se(e),n=!1,o=!1,a=!1,i=!1,u,m,f,_,y,w=R(v=>{y=v});function z(){return n?(o=!0,p(void 0)):(n=!0,Ie(r,{_chunkSteps:E=>{se(()=>{o=!1;let B=E,G=E;a||Te(f._readableStreamController,B),i||Te(_._readableStreamController,G),n=!1,o&&z()})},_closeSteps:()=>{n=!1,a||me(f._readableStreamController),i||me(_._readableStreamController),(!a||!i)&&y(void 0)},_errorSteps:()=>{n=!1}}),p(void 0))}function Ee(v){if(a=!0,u=v,i){let E=Oe([u,m]),B=j(e,E);y(B)}return w}function ae(v){if(i=!0,m=v,a){let E=Oe([u,m]),B=j(e,E);y(B)}return w}function H(){}return f=$e(H,z,Ee),_=$e(H,z,ae),gt(r._closedPromise,v=>(O(f._readableStreamController,v),O(_._readableStreamController,v),(!a||!i)&&y(void 0),null)),[f,_]}function Zo(e){let t=Se(e),r=!1,n=!1,o=!1,a=!1,i=!1,u,m,f,_,y,w=R(h=>{y=h});function z(h){gt(h._closedPromise,S=>(h!==t||(k(f._readableStreamController,S),k(_._readableStreamController,S),(!a||!i)&&y(void 0)),null))}function Ee(){ce(t)&&($(t),t=Se(e),z(t)),Ie(t,{_chunkSteps:S=>{se(()=>{n=!1,o=!1;let C=S,q=S;if(!a&&!i)try{q=Ar(S)}catch(qe){k(f._readableStreamController,qe),k(_._readableStreamController,qe),y(j(e,qe));return}a||Ze(f._readableStreamController,C),i||Ze(_._readableStreamController,q),r=!1,n?H():o&&v()})},_closeSteps:()=>{r=!1,a||je(f._readableStreamController),i||je(_._readableStreamController),f._readableStreamController._pendingPullIntos.length>0&&Xe(f._readableStreamController,0),_._readableStreamController._pendingPullIntos.length>0&&Xe(_._readableStreamController,0),(!a||!i)&&y(void 0)},_errorSteps:()=>{r=!1}})}function ae(h,S){J(t)&&($(t),t=Qr(e),z(t));let C=S?_:f,q=S?f:_;Vr(t,h,1,{_chunkSteps:We=>{se(()=>{n=!1,o=!1;let Ae=S?i:a;if(S?a:i)Ae||Je(C._readableStreamController,We);else{let Wn;try{Wn=Ar(We)}catch(sr){k(C._readableStreamController,sr),k(q._readableStreamController,sr),y(j(e,sr));return}Ae||Je(C._readableStreamController,We),Ze(q._readableStreamController,Wn)}r=!1,n?H():o&&v()})},_closeSteps:We=>{r=!1;let Ae=S?i:a,yt=S?a:i;Ae||je(C._readableStreamController),yt||je(q._readableStreamController),We!==void 0&&(Ae||Je(C._readableStreamController,We),!yt&&q._readableStreamController._pendingPullIntos.length>0&&Xe(q._readableStreamController,0)),(!Ae||!yt)&&y(void 0)},_errorSteps:()=>{r=!1}})}function H(){if(r)return n=!0,p(void 0);r=!0;let h=Ut(f._readableStreamController);return h===null?Ee():ae(h._view,!1),p(void 0)}function v(){if(r)return o=!0,p(void 0);r=!0;let h=Ut(_._readableStreamController);return h===null?Ee():ae(h._view,!0),p(void 0)}function E(h){if(a=!0,u=h,i){let S=Oe([u,m]),C=j(e,S);y(C)}return w}function B(h){if(i=!0,m=h,a){let S=Oe([u,m]),C=j(e,S);y(C)}return w}function G(){}return f=mn(G,H,E),_=mn(G,v,B),z(t),[f,_]}function Xo(e){return l(e)&&typeof e.getReader<"u"}function Jo(e){return Xo(e)?xo(e.getReader()):Ko(e)}function Ko(e){let t,r=Wr(e,"async"),n=s;function o(){let i;try{i=Un(r)}catch(m){return d(m)}let u=p(i);return M(u,m=>{if(!l(m))throw new TypeError("The promise returned by the iterator.next() method must fulfill with an object");if(Qn(m))me(t._readableStreamController);else{let _=Nn(m);Te(t._readableStreamController,_)}})}function a(i){let u=r.iterator,m;try{m=Ve(u,"return")}catch(y){return d(y)}if(m===void 0)return p(void 0);let f;try{f=le(m,u,[i])}catch(y){return d(y)}let _=p(f);return M(_,y=>{if(!l(y))throw new TypeError("The promise returned by the iterator.return() method must fulfill with an object")})}return t=$e(n,o,a,0),t}function xo(e){let t,r=s;function n(){let a;try{a=e.read()}catch(i){return d(i)}return M(a,i=>{if(!l(i))throw new TypeError("The promise returned by the reader.read() method must fulfill with an object");if(i.done)me(t._readableStreamController);else{let u=i.value;Te(t._readableStreamController,u)}})}function o(a){try{return p(e.cancel(a))}catch(i){return d(i)}}return t=$e(r,n,o,0),t}function ea(e,t){F(e,t);let r=e,n=r?.autoAllocateChunkSize,o=r?.cancel,a=r?.pull,i=r?.start,u=r?.type;return{autoAllocateChunkSize:n===void 0?void 0:Wt(n,`${t} has member 'autoAllocateChunkSize' that`),cancel:o===void 0?void 0:ta(o,r,`${t} has member 'cancel' that`),pull:a===void 0?void 0:ra(a,r,`${t} has member 'pull' that`),start:i===void 0?void 0:na(i,r,`${t} has member 'start' that`),type:u===void 0?void 0:oa(u,`${t} has member 'type' that`)}}function ta(e,t,r){return A(e,r),n=>Z(e,t,[n])}function ra(e,t,r){return A(e,r),n=>Z(e,t,[n])}function na(e,t,r){return A(e,r),n=>le(e,t,[n])}function oa(e,t){if(e=`${e}`,e!=="bytes")throw new TypeError(`${t} '${e}' is not a valid enumeration value for ReadableStreamType`);return e}function aa(e,t){return F(e,t),{preventCancel:!!e?.preventCancel}}function bn(e,t){F(e,t);let r=e?.preventAbort,n=e?.preventCancel,o=e?.preventClose,a=e?.signal;return a!==void 0&&ia(a,`${t} has member 'signal' that`),{preventAbort:!!r,preventCancel:!!n,preventClose:!!o,signal:a}}function ia(e,t){if(!bo(e))throw new TypeError(`${t} is not an AbortSignal.`)}function sa(e,t){F(e,t);let r=e?.readable;Et(r,"readable","ReadableWritablePair"),At(r,`${t} has member 'readable' that`);let n=e?.writable;return Et(n,"writable","ReadableWritablePair"),Gr(n,`${t} has member 'writable' that`),{readable:r,writable:n}}class P{constructor(t={},r={}){t===void 0?t=null:pr(t,"First parameter");let n=et(r,"Second parameter"),o=ea(t,"First parameter");if(nr(this),o.type==="bytes"){if(n.size!==void 0)throw new RangeError("The strategy for a byte stream cannot have a size function");let a=Fe(n,0);eo(this,o,a)}else{let a=xe(n),i=Fe(n,1);Vo(this,o,i,a)}}get locked(){if(!re(this))throw _e("locked");return ne(this)}cancel(t=void 0){return re(this)?ne(this)?d(new TypeError("Cannot cancel a stream that already has a reader")):j(this,t):d(_e("cancel"))}getReader(t=void 0){if(!re(this))throw _e("getReader");return ro(t,"First parameter").mode===void 0?Se(this):Qr(this)}pipeThrough(t,r={}){if(!re(this))throw _e("pipeThrough");U(t,1,"pipeThrough");let n=sa(t,"First parameter"),o=bn(r,"Second parameter");if(ne(this))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked ReadableStream");if(we(n.writable))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked WritableStream");let a=fn(this,n.writable,o.preventClose,o.preventAbort,o.preventCancel,o.signal);return ye(a),n.readable}pipeTo(t,r={}){if(!re(this))return d(_e("pipeTo"));if(t===void 0)return d("Parameter 1 is required in 'pipeTo'.");if(!Re(t))return d(new TypeError("ReadableStream.prototype.pipeTo's first argument must be a WritableStream"));let n;try{n=bn(r,"Second parameter")}catch(o){return d(o)}return ne(this)?d(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream")):we(t)?d(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream")):fn(this,t,n.preventClose,n.preventAbort,n.preventCancel,n.signal)}tee(){if(!re(this))throw _e("tee");let t=Ho(this);return Oe(t)}values(t=void 0){if(!re(this))throw _e("values");let r=aa(t,"First parameter");return Mn(this,r.preventCancel)}[jt](t){return this.values(t)}static from(t){return Jo(t)}}Object.defineProperties(P,{from:{enumerable:!0}}),Object.defineProperties(P.prototype,{cancel:{enumerable:!0},getReader:{enumerable:!0},pipeThrough:{enumerable:!0},pipeTo:{enumerable:!0},tee:{enumerable:!0},values:{enumerable:!0},locked:{enumerable:!0}}),c(P.from,"from"),c(P.prototype.cancel,"cancel"),c(P.prototype.getReader,"getReader"),c(P.prototype.pipeThrough,"pipeThrough"),c(P.prototype.pipeTo,"pipeTo"),c(P.prototype.tee,"tee"),c(P.prototype.values,"values"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(P.prototype,Symbol.toStringTag,{value:"ReadableStream",configurable:!0}),Object.defineProperty(P.prototype,jt,{value:P.prototype.values,writable:!0,configurable:!0});function $e(e,t,r,n=1,o=()=>1){let a=Object.create(P.prototype);nr(a);let i=Object.create(V.prototype);return hn(a,i,e,t,r,n,o),a}function mn(e,t,r){let n=Object.create(P.prototype);nr(n);let o=Object.create(N.prototype);return Ur(n,o,e,t,r,0,void 0),n}function nr(e){e._state="readable",e._reader=void 0,e._storedError=void 0,e._disturbed=!1}function re(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_readableStreamController")?!1:e instanceof P}function ne(e){return e._reader!==void 0}function j(e,t){if(e._disturbed=!0,e._state==="closed")return p(void 0);if(e._state==="errored")return d(e._storedError);Ue(e);let r=e._reader;if(r!==void 0&&ce(r)){let o=r._readIntoRequests;r._readIntoRequests=new W,o.forEach(a=>{a._closeSteps(void 0)})}let n=e._readableStreamController[Rt](t);return M(n,s)}function Ue(e){e._state="closed";let t=e._reader;if(t!==void 0&&(mr(t),J(t))){let r=t._readRequests;t._readRequests=new W,r.forEach(n=>{n._closeSteps()})}}function _n(e,t){e._state="errored",e._storedError=t;let r=e._reader;r!==void 0&&(vt(r,t),J(r)?Rr(r,t):Hr(r,t))}function _e(e){return new TypeError(`ReadableStream.prototype.${e} can only be used on a ReadableStream`)}function pn(e,t){F(e,t);let r=e?.highWaterMark;return Et(r,"highWaterMark","QueuingStrategyInit"),{highWaterMark:qt(r)}}let yn=e=>e.byteLength;c(yn,"size");class ft{constructor(t){U(t,1,"ByteLengthQueuingStrategy"),t=pn(t,"First parameter"),this._byteLengthQueuingStrategyHighWaterMark=t.highWaterMark}get highWaterMark(){if(!gn(this))throw Sn("highWaterMark");return this._byteLengthQueuingStrategyHighWaterMark}get size(){if(!gn(this))throw Sn("size");return yn}}Object.defineProperties(ft.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ft.prototype,Symbol.toStringTag,{value:"ByteLengthQueuingStrategy",configurable:!0});function Sn(e){return new TypeError(`ByteLengthQueuingStrategy.prototype.${e} can only be used on a ByteLengthQueuingStrategy`)}function gn(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_byteLengthQueuingStrategyHighWaterMark")?!1:e instanceof ft}let Rn=()=>1;c(Rn,"size");class ct{constructor(t){U(t,1,"CountQueuingStrategy"),t=pn(t,"First parameter"),this._countQueuingStrategyHighWaterMark=t.highWaterMark}get highWaterMark(){if(!Cn(this))throw wn("highWaterMark");return this._countQueuingStrategyHighWaterMark}get size(){if(!Cn(this))throw wn("size");return Rn}}Object.defineProperties(ct.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ct.prototype,Symbol.toStringTag,{value:"CountQueuingStrategy",configurable:!0});function wn(e){return new TypeError(`CountQueuingStrategy.prototype.${e} can only be used on a CountQueuingStrategy`)}function Cn(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_countQueuingStrategyHighWaterMark")?!1:e instanceof ct}function la(e,t){F(e,t);let r=e?.cancel,n=e?.flush,o=e?.readableType,a=e?.start,i=e?.transform,u=e?.writableType;return{cancel:r===void 0?void 0:ca(r,e,`${t} has member 'cancel' that`),flush:n===void 0?void 0:ua(n,e,`${t} has member 'flush' that`),readableType:o,start:a===void 0?void 0:da(a,e,`${t} has member 'start' that`),transform:i===void 0?void 0:fa(i,e,`${t} has member 'transform' that`),writableType:u}}function ua(e,t,r){return A(e,r),n=>Z(e,t,[n])}function da(e,t,r){return A(e,r),n=>le(e,t,[n])}function fa(e,t,r){return A(e,r),(n,o)=>Z(e,t,[n,o])}function ca(e,t,r){return A(e,r),n=>Z(e,t,[n])}class ht{constructor(t={},r={},n={}){t===void 0&&(t=null);let o=et(r,"Second parameter"),a=et(n,"Third parameter"),i=la(t,"First parameter");if(i.readableType!==void 0)throw new RangeError("Invalid readableType specified");if(i.writableType!==void 0)throw new RangeError("Invalid writableType specified");let u=Fe(a,0),m=xe(a),f=Fe(o,1),_=xe(o),y,w=R(z=>{y=z});ha(this,w,f,_,u,m),ma(this,i),i.start!==void 0?y(i.start(this._transformStreamController)):y(void 0)}get readable(){if(!Tn(this))throw qn("readable");return this._readable}get writable(){if(!Tn(this))throw qn("writable");return this._writable}}Object.defineProperties(ht.prototype,{readable:{enumerable:!0},writable:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ht.prototype,Symbol.toStringTag,{value:"TransformStream",configurable:!0});function ha(e,t,r,n,o,a){function i(){return t}function u(w){return ya(e,w)}function m(w){return Sa(e,w)}function f(){return ga(e)}e._writable=po(i,u,f,m,r,n);function _(){return Ra(e)}function y(w){return wa(e,w)}e._readable=$e(i,_,y,o,a),e._backpressure=void 0,e._backpressureChangePromise=void 0,e._backpressureChangePromise_resolve=void 0,bt(e,!0),e._transformStreamController=void 0}function Tn(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_transformStreamController")?!1:e instanceof ht}function Pn(e,t){O(e._readable._readableStreamController,t),or(e,t)}function or(e,t){_t(e._transformStreamController),De(e._writable._writableStreamController,t),ar(e)}function ar(e){e._backpressure&&bt(e,!1)}function bt(e,t){e._backpressureChangePromise!==void 0&&e._backpressureChangePromise_resolve(),e._backpressureChangePromise=R(r=>{e._backpressureChangePromise_resolve=r}),e._backpressure=t}class oe{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!mt(this))throw pt("desiredSize");let t=this._controlledTransformStream._readable._readableStreamController;return rr(t)}enqueue(t=void 0){if(!mt(this))throw pt("enqueue");vn(this,t)}error(t=void 0){if(!mt(this))throw pt("error");_a(this,t)}terminate(){if(!mt(this))throw pt("terminate");pa(this)}}Object.defineProperties(oe.prototype,{enqueue:{enumerable:!0},error:{enumerable:!0},terminate:{enumerable:!0},desiredSize:{enumerable:!0}}),c(oe.prototype.enqueue,"enqueue"),c(oe.prototype.error,"error"),c(oe.prototype.terminate,"terminate"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(oe.prototype,Symbol.toStringTag,{value:"TransformStreamDefaultController",configurable:!0});function mt(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledTransformStream")?!1:e instanceof oe}function ba(e,t,r,n,o){t._controlledTransformStream=e,e._transformStreamController=t,t._transformAlgorithm=r,t._flushAlgorithm=n,t._cancelAlgorithm=o,t._finishPromise=void 0,t._finishPromise_resolve=void 0,t._finishPromise_reject=void 0}function ma(e,t){let r=Object.create(oe.prototype),n,o,a;t.transform!==void 0?n=i=>t.transform(i,r):n=i=>{try{return vn(r,i),p(void 0)}catch(u){return d(u)}},t.flush!==void 0?o=()=>t.flush(r):o=()=>p(void 0),t.cancel!==void 0?a=i=>t.cancel(i):a=()=>p(void 0),ba(e,r,n,o,a)}function _t(e){e._transformAlgorithm=void 0,e._flushAlgorithm=void 0,e._cancelAlgorithm=void 0}function vn(e,t){let r=e._controlledTransformStream,n=r._readable._readableStreamController;if(!Pe(n))throw new TypeError("Readable side is not in a state that permits enqueue");try{Te(n,t)}catch(a){throw or(r,a),r._readable._storedError}Yo(n)!==r._backpressure&&bt(r,!0)}function _a(e,t){Pn(e._controlledTransformStream,t)}function En(e,t){let r=e._transformAlgorithm(t);return M(r,void 0,n=>{throw Pn(e._controlledTransformStream,n),n})}function pa(e){let t=e._controlledTransformStream,r=t._readable._readableStreamController;me(r);let n=new TypeError("TransformStream terminated");or(t,n)}function ya(e,t){let r=e._transformStreamController;if(e._backpressure){let n=e._backpressureChangePromise;return M(n,()=>{let o=e._writable;if(o._state==="erroring")throw o._storedError;return En(r,t)})}return En(r,t)}function Sa(e,t){let r=e._transformStreamController;if(r._finishPromise!==void 0)return r._finishPromise;let n=e._readable;r._finishPromise=R((a,i)=>{r._finishPromise_resolve=a,r._finishPromise_reject=i});let o=r._cancelAlgorithm(t);return _t(r),T(o,()=>(n._state==="errored"?ve(r,n._storedError):(O(n._readableStreamController,t),ir(r)),null),a=>(O(n._readableStreamController,a),ve(r,a),null)),r._finishPromise}function ga(e){let t=e._transformStreamController;if(t._finishPromise!==void 0)return t._finishPromise;let r=e._readable;t._finishPromise=R((o,a)=>{t._finishPromise_resolve=o,t._finishPromise_reject=a});let n=t._flushAlgorithm();return _t(t),T(n,()=>(r._state==="errored"?ve(t,r._storedError):(me(r._readableStreamController),ir(t)),null),o=>(O(r._readableStreamController,o),ve(t,o),null)),t._finishPromise}function Ra(e){return bt(e,!1),e._backpressureChangePromise}function wa(e,t){let r=e._transformStreamController;if(r._finishPromise!==void 0)return r._finishPromise;let n=e._writable;r._finishPromise=R((a,i)=>{r._finishPromise_resolve=a,r._finishPromise_reject=i});let o=r._cancelAlgorithm(t);return _t(r),T(o,()=>(n._state==="errored"?ve(r,n._storedError):(De(n._writableStreamController,t),ar(e),ir(r)),null),a=>(De(n._writableStreamController,a),ar(e),ve(r,a),null)),r._finishPromise}function pt(e){return new TypeError(`TransformStreamDefaultController.prototype.${e} can only be used on a TransformStreamDefaultController`)}function ir(e){e._finishPromise_resolve!==void 0&&(e._finishPromise_resolve(),e._finishPromise_resolve=void 0,e._finishPromise_reject=void 0)}function ve(e,t){e._finishPromise_reject!==void 0&&(ye(e._finishPromise),e._finishPromise_reject(t),e._finishPromise_resolve=void 0,e._finishPromise_reject=void 0)}function qn(e){return new TypeError(`TransformStream.prototype.${e} can only be used on a TransformStream`)}b.ByteLengthQueuingStrategy=ft,b.CountQueuingStrategy=ct,b.ReadableByteStreamController=N,b.ReadableStream=P,b.ReadableStreamBYOBReader=ee,b.ReadableStreamBYOBRequest=ue,b.ReadableStreamDefaultController=V,b.ReadableStreamDefaultReader=X,b.TransformStream=ht,b.TransformStreamDefaultController=oe,b.WritableStream=te,b.WritableStreamDefaultController=Ce,b.WritableStreamDefaultWriter=Y}))});var ke=ka(kn());typeof globalThis.ReadableStream>"u"&&(globalThis.ReadableStream=ke.ReadableStream);typeof globalThis.WritableStream>"u"&&(globalThis.WritableStream=ke.WritableStream);typeof globalThis.TransformStream>"u"&&(globalThis.TransformStream=ke.TransformStream);typeof globalThis.URLSearchParams>"u"&&(globalThis.URLSearchParams=class{constructor(s=void 0){L(this,"_entries",[]);if(typeof s=="string"){let l=s.startsWith("?")?s.slice(1):s;if(l.length>0)for(let g of l.split("&")){if(!g)continue;let[c,pe=""]=g.split("=");this.append(decodeURIComponent(c),decodeURIComponent(pe))}}else if(Array.isArray(s))for(let[l,g]of s)this.append(l,g);else if(s&&typeof s=="object")for(let[l,g]of Object.entries(s))this.append(l,g)}append(s,l){this._entries.push([String(s),String(l)])}delete(s){let l=String(s);this._entries=this._entries.filter(([g])=>g!==l)}get(s){let l=String(s),g=this._entries.find(([c])=>c===l);return g?g[1]:null}getAll(s){let l=String(s);return this._entries.filter(([g])=>g===l).map(([,g])=>g)}has(s){let l=String(s);return this._entries.some(([g])=>g===l)}set(s,l){this.delete(s),this.append(s,l)}entries(){return this._entries[Symbol.iterator]()}keys(){return this._entries.map(([s])=>s)[Symbol.iterator]()}values(){return this._entries.map(([,s])=>s)[Symbol.iterator]()}forEach(s,l=void 0){for(let[g,c]of this._entries)s.call(l,c,g,this)}toString(){return this._entries.map(([s,l])=>`${encodeURIComponent(s)}=${encodeURIComponent(l)}`).join("&")}[Symbol.iterator](){return this.entries()}},globalThis.URLSearchParams.__secureExecBootstrapStub=!0);typeof globalThis.URL>"u"&&(globalThis.URL=class{constructor(s,l=void 0){let g=String(s??""),c=/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(g),pe=c||typeof l>"u"?"":String(new globalThis.URL(l).href),ie=(c?g:pe.replace(/\/[^/]*$/,"/")+g).match(/^(\w+:)\/\/([^/:?#]+)(:\d+)?(.*)$/);if(!ie)throw new TypeError(`Invalid URL: ${g}`);this.protocol=ie[1],this.hostname=ie[2],this.port=(ie[3]||"").slice(1);let R=ie[4]||"/",p=R.indexOf("?"),d=R.indexOf("#"),I=[p,d].filter(T=>T>=0).sort((T,Be)=>T-Be)[0]??R.length;this.pathname=R.slice(0,I)||"/",this.search=p>=0?R.slice(p,d>=0&&d>p?d:R.length):"",this.hash=d>=0?R.slice(d):"",this.host=this.hostname+(this.port?`:${this.port}`:""),this.origin=`${this.protocol}//${this.host}`,this.href=`${this.origin}${this.pathname}${this.search}${this.hash}`,this.searchParams=new globalThis.URLSearchParams(this.search)}toString(){return this.href}toJSON(){return this.href}},globalThis.URL.__secureExecBootstrapStub=!0);typeof globalThis.Blob>"u"&&(globalThis.Blob=class{});typeof globalThis.AbortSignal>"u"&&(globalThis.AbortSignal=class{constructor(){L(this,"aborted",!1);L(this,"reason");L(this,"_listeners",new Set)}addEventListener(s,l){s!=="abort"||typeof l!="function"||this._listeners.add(l)}removeEventListener(s,l){s==="abort"&&this._listeners.delete(l)}dispatchEvent(s){for(let l of this._listeners)l.call(this,s);return!0}throwIfAborted(){if(this.aborted)throw this.reason instanceof Error?this.reason:new Error(String(this.reason??"AbortError"))}});typeof globalThis.AbortController>"u"&&(globalThis.AbortController=class{constructor(){this.signal=new globalThis.AbortSignal}abort(s=void 0){this.signal.aborted||(this.signal.aborted=!0,this.signal.reason=s,this.signal.dispatchEvent({type:"abort"}))}});typeof globalThis.File>"u"&&(globalThis.File=class extends Blob{constructor(l=[],g="",c={}){super(l,c);L(this,"name");L(this,"lastModified");L(this,"webkitRelativePath");this.name=String(g),this.lastModified=typeof c.lastModified=="number"?c.lastModified:Date.now(),this.webkitRelativePath=""}});typeof globalThis.FormData>"u"&&(globalThis.FormData=class{constructor(){L(this,"_entries",[])}append(s,l){this._entries.push([s,l])}get(s){let l=this._entries.find(([g])=>g===s);return l?l[1]:null}getAll(s){return this._entries.filter(([l])=>l===s).map(([,l])=>l)}has(s){return this._entries.some(([l])=>l===s)}delete(s){this._entries=this._entries.filter(([l])=>l!==s)}entries(){return this._entries[Symbol.iterator]()}[Symbol.iterator](){return this.entries()}});typeof globalThis.MessagePort>"u"&&(globalThis.MessagePort=class{constructor(){L(this,"onmessage",null)}postMessage(s){}start(){}close(){}addEventListener(){}removeEventListener(){}});typeof globalThis.MessageChannel>"u"&&(globalThis.MessageChannel=class{constructor(){this.port1=new globalThis.MessagePort,this.port2=new globalThis.MessagePort}});if(typeof globalThis.performance>"u"){let b=Date.now();globalThis.performance={now(){return Date.now()-b}}}typeof globalThis.performance.markResourceTiming!="function"&&(globalThis.performance.markResourceTiming=()=>{});})(); -/*! Bundled license information: - -web-streams-polyfill/dist/ponyfill.es2018.js: - (** - * @license - * web-streams-polyfill v3.3.3 - * Copyright 2024 Mattias Buelens, Diwank Singh Tomer and other contributors. - * This code is released under the MIT license. - * SPDX-License-Identifier: MIT - *) -*/ - -if(typeof globalThis.global==="undefined"){globalThis.global=globalThis;}if(typeof globalThis.process==="undefined"){globalThis.process={env:{},argv:["node"],browser:false,version:"v22.0.0",versions:{node:"22.0.0"},nextTick(callback,...args){return Promise.resolve().then(()=>callback(...args));}};}if(typeof globalThis.TextEncoder==="undefined"){globalThis.TextEncoder=class{encode(value=""){const input=String(value??"");const encoded=unescape(encodeURIComponent(input));const out=new Uint8Array(encoded.length);for(let i=0;isum+(item?.length??0),0);const out=new __SecureExecEarlyBuffer(length);let offset=0;for(const item of list){const chunk=item instanceof Uint8Array?item:__SecureExecEarlyBuffer.from(item);out.set(chunk,offset);offset+=chunk.length;}return out;}static isBuffer(value){return value instanceof Uint8Array;}static byteLength(value,encoding="utf8"){return __SecureExecEarlyBuffer.from(value,encoding).byteLength;}toString(encoding="utf8"){if(encoding==="base64"&&typeof btoa==="function"){let binary="";for(const byte of this){binary+=String.fromCharCode(byte);}return btoa(binary);}if(encoding==="binary"||encoding==="latin1"){let binary="";for(const byte of this){binary+=String.fromCharCode(byte);}return binary;}if(__secureExecTd){return __secureExecTd.decode(this);}return Array.from(this,byte=>String.fromCharCode(byte)).join("");}}globalThis.Buffer=__SecureExecEarlyBuffer;}if(typeof globalThis.performance==="undefined"){const __secureExecPerformanceStart=Date.now();globalThis.performance={now(){return Date.now()-__secureExecPerformanceStart;}};}if(typeof globalThis.performance.markResourceTiming!=="function"){globalThis.performance.markResourceTiming=()=>{};}if(typeof TextEncoder==="undefined"&&typeof globalThis.TextEncoder!=="undefined"){var TextEncoder=globalThis.TextEncoder;}if(typeof TextDecoder==="undefined"&&typeof globalThis.TextDecoder!=="undefined"){var TextDecoder=globalThis.TextDecoder;}if(typeof Buffer==="undefined"&&typeof globalThis.Buffer!=="undefined"){var Buffer=globalThis.Buffer;} -(()=>{var sj=Object.create;var eh=Object.defineProperty;var oj=Object.getOwnPropertyDescriptor;var aj=Object.getOwnPropertyNames;var Aj=Object.getPrototypeOf,fj=Object.prototype.hasOwnProperty;var pI=e=>{throw TypeError(e)};var uj=(e,t,r)=>t in e?eh(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var uD=(e,t)=>()=>(e&&(t=e(e=0)),t);var U=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),EI=(e,t)=>{for(var r in t)eh(e,r,{get:t[r],enumerable:!0})},v0=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of aj(t))!fj.call(e,i)&&i!==r&&eh(e,i,{get:()=>t[i],enumerable:!(n=oj(t,i))||n.enumerable});return e},_n=(e,t,r)=>(v0(e,t,"default"),r&&v0(r,t,"default")),hr=(e,t,r)=>(r=e!=null?sj(Aj(e)):{},v0(t||!e||!e.__esModule?eh(r,"default",{value:e,enumerable:!0}):r,e)),Os=e=>v0(eh({},"__esModule",{value:!0}),e);var y=(e,t,r)=>uj(e,typeof t!="symbol"?t+"":t,r),yI=(e,t,r)=>t.has(e)||pI("Cannot "+r),cD=(e,t)=>Object(t)!==t?pI('Cannot use the "in" operator on this value'):e.has(t),ee=(e,t,r)=>(yI(e,t,"read from private field"),r?r.call(e):t.get(e)),wt=(e,t,r)=>t.has(e)?pI("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,r),ft=(e,t,r,n)=>(yI(e,t,"write to private field"),n?n.call(e,r):t.set(e,r),r),lD=(e,t,r)=>(yI(e,t,"access private method"),r);var gD=U(R0=>{"use strict";R0.byteLength=lj;R0.toByteArray=dj;R0.fromByteArray=Ej;var Hs=[],ci=[],cj=typeof Uint8Array<"u"?Uint8Array:Array,mI="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(zA=0,hD=mI.length;zA0)throw new Error("Invalid string. Length must be a multiple of 4");var r=e.indexOf("=");r===-1&&(r=t);var n=r===t?0:4-r%4;return[r,n]}function lj(e){var t=dD(e),r=t[0],n=t[1];return(r+n)*3/4-n}function hj(e,t,r){return(t+r)*3/4-r}function dj(e){var t,r=dD(e),n=r[0],i=r[1],s=new cj(hj(e,n,i)),o=0,a=i>0?n-4:n,A;for(A=0;A>16&255,s[o++]=t>>8&255,s[o++]=t&255;return i===2&&(t=ci[e.charCodeAt(A)]<<2|ci[e.charCodeAt(A+1)]>>4,s[o++]=t&255),i===1&&(t=ci[e.charCodeAt(A)]<<10|ci[e.charCodeAt(A+1)]<<4|ci[e.charCodeAt(A+2)]>>2,s[o++]=t>>8&255,s[o++]=t&255),s}function gj(e){return Hs[e>>18&63]+Hs[e>>12&63]+Hs[e>>6&63]+Hs[e&63]}function pj(e,t,r){for(var n,i=[],s=t;sa?a:o+s));return n===1?(t=e[r-1],i.push(Hs[t>>2]+Hs[t<<4&63]+"==")):n===2&&(t=(e[r-2]<<8)+e[r-1],i.push(Hs[t>>10]+Hs[t>>4&63]+Hs[t<<2&63]+"=")),i.join("")}});var pD=U(BI=>{BI.read=function(e,t,r,n,i){var s,o,a=i*8-n-1,A=(1<>1,l=-7,p=r?i-1:0,I=r?-1:1,S=e[t+p];for(p+=I,s=S&(1<<-l)-1,S>>=-l,l+=a;l>0;s=s*256+e[t+p],p+=I,l-=8);for(o=s&(1<<-l)-1,s>>=-l,l+=n;l>0;o=o*256+e[t+p],p+=I,l-=8);if(s===0)s=1-f;else{if(s===A)return o?NaN:(S?-1:1)*(1/0);o=o+Math.pow(2,n),s=s-f}return(S?-1:1)*o*Math.pow(2,s-n)};BI.write=function(e,t,r,n,i,s){var o,a,A,f=s*8-i-1,l=(1<>1,I=i===23?Math.pow(2,-24)-Math.pow(2,-77):0,S=n?0:s-1,_=n?1:-1,N=t<0||t===0&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(a=isNaN(t)?1:0,o=l):(o=Math.floor(Math.log(t)/Math.LN2),t*(A=Math.pow(2,-o))<1&&(o--,A*=2),o+p>=1?t+=I/A:t+=I*Math.pow(2,1-p),t*A>=2&&(o++,A/=2),o+p>=l?(a=0,o=l):o+p>=1?(a=(t*A-1)*Math.pow(2,i),o=o+p):(a=t*Math.pow(2,p-1)*Math.pow(2,i),o=0));i>=8;e[r+S]=a&255,S+=_,a/=256,i-=8);for(o=o<0;e[r+S]=o&255,S+=_,o/=256,f-=8);e[r+S-_]|=N*128}});var Gr=U(qu=>{"use strict";var II=gD(),Hu=pD(),ED=typeof Symbol=="function"&&typeof Symbol.for=="function"?Symbol.for("nodejs.util.inspect.custom"):null;qu.Buffer=fe;qu.SlowBuffer=Cj;qu.INSPECT_MAX_BYTES=50;var D0=2147483647;qu.kMaxLength=D0;fe.TYPED_ARRAY_SUPPORT=yj();!fe.TYPED_ARRAY_SUPPORT&&typeof console<"u"&&typeof console.error=="function"&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function yj(){try{var e=new Uint8Array(1),t={foo:function(){return 42}};return Object.setPrototypeOf(t,Uint8Array.prototype),Object.setPrototypeOf(e,t),e.foo()===42}catch{return!1}}Object.defineProperty(fe.prototype,"parent",{enumerable:!0,get:function(){if(fe.isBuffer(this))return this.buffer}});Object.defineProperty(fe.prototype,"offset",{enumerable:!0,get:function(){if(fe.isBuffer(this))return this.byteOffset}});function Yo(e){if(e>D0)throw new RangeError('The value "'+e+'" is invalid for option "size"');var t=new Uint8Array(e);return Object.setPrototypeOf(t,fe.prototype),t}function fe(e,t,r){if(typeof e=="number"){if(typeof t=="string")throw new TypeError('The "string" argument must be of type string. Received type number');return wI(e)}return BD(e,t,r)}fe.poolSize=8192;function BD(e,t,r){if(typeof e=="string")return Bj(e,t);if(ArrayBuffer.isView(e))return Ij(e);if(e==null)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(qs(e,ArrayBuffer)||e&&qs(e.buffer,ArrayBuffer)||typeof SharedArrayBuffer<"u"&&(qs(e,SharedArrayBuffer)||e&&qs(e.buffer,SharedArrayBuffer)))return CI(e,t,r);if(typeof e=="number")throw new TypeError('The "value" argument must not be of type number. Received type number');var n=e.valueOf&&e.valueOf();if(n!=null&&n!==e)return fe.from(n,t,r);var i=bj(e);if(i)return i;if(typeof Symbol<"u"&&Symbol.toPrimitive!=null&&typeof e[Symbol.toPrimitive]=="function")return fe.from(e[Symbol.toPrimitive]("string"),t,r);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}fe.from=function(e,t,r){return BD(e,t,r)};Object.setPrototypeOf(fe.prototype,Uint8Array.prototype);Object.setPrototypeOf(fe,Uint8Array);function ID(e){if(typeof e!="number")throw new TypeError('"size" argument must be of type number');if(e<0)throw new RangeError('The value "'+e+'" is invalid for option "size"')}function mj(e,t,r){return ID(e),e<=0?Yo(e):t!==void 0?typeof r=="string"?Yo(e).fill(t,r):Yo(e).fill(t):Yo(e)}fe.alloc=function(e,t,r){return mj(e,t,r)};function wI(e){return ID(e),Yo(e<0?0:SI(e)|0)}fe.allocUnsafe=function(e){return wI(e)};fe.allocUnsafeSlow=function(e){return wI(e)};function Bj(e,t){if((typeof t!="string"||t==="")&&(t="utf8"),!fe.isEncoding(t))throw new TypeError("Unknown encoding: "+t);var r=bD(e,t)|0,n=Yo(r),i=n.write(e,t);return i!==r&&(n=n.slice(0,i)),n}function bI(e){for(var t=e.length<0?0:SI(e.length)|0,r=Yo(t),n=0;n=D0)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+D0.toString(16)+" bytes");return e|0}function Cj(e){return+e!=e&&(e=0),fe.alloc(+e)}fe.isBuffer=function(t){return t!=null&&t._isBuffer===!0&&t!==fe.prototype};fe.compare=function(t,r){if(qs(t,Uint8Array)&&(t=fe.from(t,t.offset,t.byteLength)),qs(r,Uint8Array)&&(r=fe.from(r,r.offset,r.byteLength)),!fe.isBuffer(t)||!fe.isBuffer(r))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(t===r)return 0;for(var n=t.length,i=r.length,s=0,o=Math.min(n,i);si.length?fe.from(o).copy(i,s):Uint8Array.prototype.set.call(i,o,s);else if(fe.isBuffer(o))o.copy(i,s);else throw new TypeError('"list" argument must be an Array of Buffers');s+=o.length}return i};function bD(e,t){if(fe.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||qs(e,ArrayBuffer))return e.byteLength;if(typeof e!="string")throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof e);var r=e.length,n=arguments.length>2&&arguments[2]===!0;if(!n&&r===0)return 0;for(var i=!1;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":return QI(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return r*2;case"hex":return r>>>1;case"base64":return vD(e).length;default:if(i)return n?-1:QI(e).length;t=(""+t).toLowerCase(),i=!0}}fe.byteLength=bD;function Qj(e,t,r){var n=!1;if((t===void 0||t<0)&&(t=0),t>this.length||((r===void 0||r>this.length)&&(r=this.length),r<=0)||(r>>>=0,t>>>=0,r<=t))return"";for(e||(e="utf8");;)switch(e){case"hex":return Fj(this,t,r);case"utf8":case"utf-8":return QD(this,t,r);case"ascii":return Nj(this,t,r);case"latin1":case"binary":return Mj(this,t,r);case"base64":return Dj(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return kj(this,t,r);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}fe.prototype._isBuffer=!0;function KA(e,t,r){var n=e[t];e[t]=e[r],e[r]=n}fe.prototype.swap16=function(){var t=this.length;if(t%2!==0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(var r=0;rr&&(t+=" ... "),""};ED&&(fe.prototype[ED]=fe.prototype.inspect);fe.prototype.compare=function(t,r,n,i,s){if(qs(t,Uint8Array)&&(t=fe.from(t,t.offset,t.byteLength)),!fe.isBuffer(t))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof t);if(r===void 0&&(r=0),n===void 0&&(n=t?t.length:0),i===void 0&&(i=0),s===void 0&&(s=this.length),r<0||n>t.length||i<0||s>this.length)throw new RangeError("out of range index");if(i>=s&&r>=n)return 0;if(i>=s)return-1;if(r>=n)return 1;if(r>>>=0,n>>>=0,i>>>=0,s>>>=0,this===t)return 0;for(var o=s-i,a=n-r,A=Math.min(o,a),f=this.slice(i,s),l=t.slice(r,n),p=0;p2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,_I(r)&&(r=i?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(i)return-1;r=e.length-1}else if(r<0)if(i)r=0;else return-1;if(typeof t=="string"&&(t=fe.from(t,n)),fe.isBuffer(t))return t.length===0?-1:yD(e,t,r,n,i);if(typeof t=="number")return t=t&255,typeof Uint8Array.prototype.indexOf=="function"?i?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):yD(e,[t],r,n,i);throw new TypeError("val must be string, number or Buffer")}function yD(e,t,r,n,i){var s=1,o=e.length,a=t.length;if(n!==void 0&&(n=String(n).toLowerCase(),n==="ucs2"||n==="ucs-2"||n==="utf16le"||n==="utf-16le")){if(e.length<2||t.length<2)return-1;s=2,o/=2,a/=2,r/=2}function A(S,_){return s===1?S[_]:S.readUInt16BE(_*s)}var f;if(i){var l=-1;for(f=r;fo&&(r=o-a),f=r;f>=0;f--){for(var p=!0,I=0;Ii&&(n=i)):n=i;var s=t.length;n>s/2&&(n=s/2);for(var o=0;o>>0,isFinite(n)?(n=n>>>0,i===void 0&&(i="utf8")):(i=n,n=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");var s=this.length-r;if((n===void 0||n>s)&&(n=s),t.length>0&&(n<0||r<0)||r>this.length)throw new RangeError("Attempt to write outside buffer bounds");i||(i="utf8");for(var o=!1;;)switch(i){case"hex":return wj(this,t,r,n);case"utf8":case"utf-8":return Sj(this,t,r,n);case"ascii":case"latin1":case"binary":return _j(this,t,r,n);case"base64":return vj(this,t,r,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Rj(this,t,r,n);default:if(o)throw new TypeError("Unknown encoding: "+i);i=(""+i).toLowerCase(),o=!0}};fe.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function Dj(e,t,r){return t===0&&r===e.length?II.fromByteArray(e):II.fromByteArray(e.slice(t,r))}function QD(e,t,r){r=Math.min(e.length,r);for(var n=[],i=t;i239?4:s>223?3:s>191?2:1;if(i+a<=r){var A,f,l,p;switch(a){case 1:s<128&&(o=s);break;case 2:A=e[i+1],(A&192)===128&&(p=(s&31)<<6|A&63,p>127&&(o=p));break;case 3:A=e[i+1],f=e[i+2],(A&192)===128&&(f&192)===128&&(p=(s&15)<<12|(A&63)<<6|f&63,p>2047&&(p<55296||p>57343)&&(o=p));break;case 4:A=e[i+1],f=e[i+2],l=e[i+3],(A&192)===128&&(f&192)===128&&(l&192)===128&&(p=(s&15)<<18|(A&63)<<12|(f&63)<<6|l&63,p>65535&&p<1114112&&(o=p))}}o===null?(o=65533,a=1):o>65535&&(o-=65536,n.push(o>>>10&1023|55296),o=56320|o&1023),n.push(o),i+=a}return Tj(n)}var mD=4096;function Tj(e){var t=e.length;if(t<=mD)return String.fromCharCode.apply(String,e);for(var r="",n=0;nn)&&(r=n);for(var i="",s=t;sn&&(t=n),r<0?(r+=n,r<0&&(r=0)):r>n&&(r=n),rr)throw new RangeError("Trying to access beyond buffer length")}fe.prototype.readUintLE=fe.prototype.readUIntLE=function(t,r,n){t=t>>>0,r=r>>>0,n||Dr(t,r,this.length);for(var i=this[t],s=1,o=0;++o>>0,r=r>>>0,n||Dr(t,r,this.length);for(var i=this[t+--r],s=1;r>0&&(s*=256);)i+=this[t+--r]*s;return i};fe.prototype.readUint8=fe.prototype.readUInt8=function(t,r){return t=t>>>0,r||Dr(t,1,this.length),this[t]};fe.prototype.readUint16LE=fe.prototype.readUInt16LE=function(t,r){return t=t>>>0,r||Dr(t,2,this.length),this[t]|this[t+1]<<8};fe.prototype.readUint16BE=fe.prototype.readUInt16BE=function(t,r){return t=t>>>0,r||Dr(t,2,this.length),this[t]<<8|this[t+1]};fe.prototype.readUint32LE=fe.prototype.readUInt32LE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+this[t+3]*16777216};fe.prototype.readUint32BE=fe.prototype.readUInt32BE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),this[t]*16777216+(this[t+1]<<16|this[t+2]<<8|this[t+3])};fe.prototype.readIntLE=function(t,r,n){t=t>>>0,r=r>>>0,n||Dr(t,r,this.length);for(var i=this[t],s=1,o=0;++o=s&&(i-=Math.pow(2,8*r)),i};fe.prototype.readIntBE=function(t,r,n){t=t>>>0,r=r>>>0,n||Dr(t,r,this.length);for(var i=r,s=1,o=this[t+--i];i>0&&(s*=256);)o+=this[t+--i]*s;return s*=128,o>=s&&(o-=Math.pow(2,8*r)),o};fe.prototype.readInt8=function(t,r){return t=t>>>0,r||Dr(t,1,this.length),this[t]&128?(255-this[t]+1)*-1:this[t]};fe.prototype.readInt16LE=function(t,r){t=t>>>0,r||Dr(t,2,this.length);var n=this[t]|this[t+1]<<8;return n&32768?n|4294901760:n};fe.prototype.readInt16BE=function(t,r){t=t>>>0,r||Dr(t,2,this.length);var n=this[t+1]|this[t]<<8;return n&32768?n|4294901760:n};fe.prototype.readInt32LE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24};fe.prototype.readInt32BE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]};fe.prototype.readFloatLE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),Hu.read(this,t,!0,23,4)};fe.prototype.readFloatBE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),Hu.read(this,t,!1,23,4)};fe.prototype.readDoubleLE=function(t,r){return t=t>>>0,r||Dr(t,8,this.length),Hu.read(this,t,!0,52,8)};fe.prototype.readDoubleBE=function(t,r){return t=t>>>0,r||Dr(t,8,this.length),Hu.read(this,t,!1,52,8)};function vn(e,t,r,n,i,s){if(!fe.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw new RangeError("Index out of range")}fe.prototype.writeUintLE=fe.prototype.writeUIntLE=function(t,r,n,i){if(t=+t,r=r>>>0,n=n>>>0,!i){var s=Math.pow(2,8*n)-1;vn(this,t,r,n,s,0)}var o=1,a=0;for(this[r]=t&255;++a>>0,n=n>>>0,!i){var s=Math.pow(2,8*n)-1;vn(this,t,r,n,s,0)}var o=n-1,a=1;for(this[r+o]=t&255;--o>=0&&(a*=256);)this[r+o]=t/a&255;return r+n};fe.prototype.writeUint8=fe.prototype.writeUInt8=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,1,255,0),this[r]=t&255,r+1};fe.prototype.writeUint16LE=fe.prototype.writeUInt16LE=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,2,65535,0),this[r]=t&255,this[r+1]=t>>>8,r+2};fe.prototype.writeUint16BE=fe.prototype.writeUInt16BE=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,2,65535,0),this[r]=t>>>8,this[r+1]=t&255,r+2};fe.prototype.writeUint32LE=fe.prototype.writeUInt32LE=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,4,4294967295,0),this[r+3]=t>>>24,this[r+2]=t>>>16,this[r+1]=t>>>8,this[r]=t&255,r+4};fe.prototype.writeUint32BE=fe.prototype.writeUInt32BE=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,4,4294967295,0),this[r]=t>>>24,this[r+1]=t>>>16,this[r+2]=t>>>8,this[r+3]=t&255,r+4};fe.prototype.writeIntLE=function(t,r,n,i){if(t=+t,r=r>>>0,!i){var s=Math.pow(2,8*n-1);vn(this,t,r,n,s-1,-s)}var o=0,a=1,A=0;for(this[r]=t&255;++o>0)-A&255;return r+n};fe.prototype.writeIntBE=function(t,r,n,i){if(t=+t,r=r>>>0,!i){var s=Math.pow(2,8*n-1);vn(this,t,r,n,s-1,-s)}var o=n-1,a=1,A=0;for(this[r+o]=t&255;--o>=0&&(a*=256);)t<0&&A===0&&this[r+o+1]!==0&&(A=1),this[r+o]=(t/a>>0)-A&255;return r+n};fe.prototype.writeInt8=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,1,127,-128),t<0&&(t=255+t+1),this[r]=t&255,r+1};fe.prototype.writeInt16LE=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,2,32767,-32768),this[r]=t&255,this[r+1]=t>>>8,r+2};fe.prototype.writeInt16BE=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,2,32767,-32768),this[r]=t>>>8,this[r+1]=t&255,r+2};fe.prototype.writeInt32LE=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,4,2147483647,-2147483648),this[r]=t&255,this[r+1]=t>>>8,this[r+2]=t>>>16,this[r+3]=t>>>24,r+4};fe.prototype.writeInt32BE=function(t,r,n){return t=+t,r=r>>>0,n||vn(this,t,r,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),this[r]=t>>>24,this[r+1]=t>>>16,this[r+2]=t>>>8,this[r+3]=t&255,r+4};function wD(e,t,r,n,i,s){if(r+n>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function SD(e,t,r,n,i){return t=+t,r=r>>>0,i||wD(e,t,r,4,34028234663852886e22,-34028234663852886e22),Hu.write(e,t,r,n,23,4),r+4}fe.prototype.writeFloatLE=function(t,r,n){return SD(this,t,r,!0,n)};fe.prototype.writeFloatBE=function(t,r,n){return SD(this,t,r,!1,n)};function _D(e,t,r,n,i){return t=+t,r=r>>>0,i||wD(e,t,r,8,17976931348623157e292,-17976931348623157e292),Hu.write(e,t,r,n,52,8),r+8}fe.prototype.writeDoubleLE=function(t,r,n){return _D(this,t,r,!0,n)};fe.prototype.writeDoubleBE=function(t,r,n){return _D(this,t,r,!1,n)};fe.prototype.copy=function(t,r,n,i){if(!fe.isBuffer(t))throw new TypeError("argument should be a Buffer");if(n||(n=0),!i&&i!==0&&(i=this.length),r>=t.length&&(r=t.length),r||(r=0),i>0&&i=this.length)throw new RangeError("Index out of range");if(i<0)throw new RangeError("sourceEnd out of bounds");i>this.length&&(i=this.length),t.length-r>>0,n=n===void 0?this.length:n>>>0,t||(t=0);var o;if(typeof t=="number")for(o=r;o55295&&r<57344){if(!i){if(r>56319){(t-=3)>-1&&s.push(239,191,189);continue}else if(o+1===n){(t-=3)>-1&&s.push(239,191,189);continue}i=r;continue}if(r<56320){(t-=3)>-1&&s.push(239,191,189),i=r;continue}r=(i-55296<<10|r-56320)+65536}else i&&(t-=3)>-1&&s.push(239,191,189);if(i=null,r<128){if((t-=1)<0)break;s.push(r)}else if(r<2048){if((t-=2)<0)break;s.push(r>>6|192,r&63|128)}else if(r<65536){if((t-=3)<0)break;s.push(r>>12|224,r>>6&63|128,r&63|128)}else if(r<1114112){if((t-=4)<0)break;s.push(r>>18|240,r>>12&63|128,r>>6&63|128,r&63|128)}else throw new Error("Invalid code point")}return s}function Lj(e){for(var t=[],r=0;r>8,i=r%256,s.push(i),s.push(n);return s}function vD(e){return II.toByteArray(xj(e))}function T0(e,t,r,n){for(var i=0;i=t.length||i>=e.length);++i)t[i+r]=e[i];return i}function qs(e,t){return e instanceof t||e!=null&&e.constructor!=null&&e.constructor.name!=null&&e.constructor.name===t.name}function _I(e){return e!==e}var Oj=(function(){for(var e="0123456789abcdef",t=new Array(256),r=0;r<16;++r)for(var n=r*16,i=0;i<16;++i)t[n+i]=e[r]+e[i];return t})()});var Zi=U((_2e,RI)=>{"use strict";var Gu=typeof Reflect=="object"?Reflect:null,RD=Gu&&typeof Gu.apply=="function"?Gu.apply:function(t,r,n){return Function.prototype.apply.call(t,r,n)},N0;Gu&&typeof Gu.ownKeys=="function"?N0=Gu.ownKeys:Object.getOwnPropertySymbols?N0=function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:N0=function(t){return Object.getOwnPropertyNames(t)};function MZ(e){console&&console.warn&&console.warn(e)}var TD=Number.isNaN||function(t){return t!==t};function kt(){kt.init.call(this)}RI.exports=kt;RI.exports.once=xZ;kt.EventEmitter=kt;kt.prototype._events=void 0;kt.prototype._eventsCount=0;kt.prototype._maxListeners=void 0;var DD=10;function M0(e){if(typeof e!="function")throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}Object.defineProperty(kt,"defaultMaxListeners",{enumerable:!0,get:function(){return DD},set:function(e){if(typeof e!="number"||e<0||TD(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");DD=e}});kt.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0};kt.prototype.setMaxListeners=function(t){if(typeof t!="number"||t<0||TD(t))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+t+".");return this._maxListeners=t,this};function ND(e){return e._maxListeners===void 0?kt.defaultMaxListeners:e._maxListeners}kt.prototype.getMaxListeners=function(){return ND(this)};kt.prototype.emit=function(t){for(var r=[],n=1;n0&&(o=r[0]),o instanceof Error)throw o;var a=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw a.context=o,a}var A=s[t];if(A===void 0)return!1;if(typeof A=="function")RD(A,this,r);else for(var f=A.length,l=xD(A,f),n=0;n0&&o.length>i&&!o.warned){o.warned=!0;var a=new Error("Possible EventEmitter memory leak detected. "+o.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");a.name="MaxListenersExceededWarning",a.emitter=e,a.type=t,a.count=o.length,MZ(a)}return e}kt.prototype.addListener=function(t,r){return MD(this,t,r,!1)};kt.prototype.on=kt.prototype.addListener;kt.prototype.prependListener=function(t,r){return MD(this,t,r,!0)};function FZ(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length===0?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function FD(e,t,r){var n={fired:!1,wrapFn:void 0,target:e,type:t,listener:r},i=FZ.bind(n);return i.listener=r,n.wrapFn=i,i}kt.prototype.once=function(t,r){return M0(r),this.on(t,FD(this,t,r)),this};kt.prototype.prependOnceListener=function(t,r){return M0(r),this.prependListener(t,FD(this,t,r)),this};kt.prototype.removeListener=function(t,r){var n,i,s,o,a;if(M0(r),i=this._events,i===void 0)return this;if(n=i[t],n===void 0)return this;if(n===r||n.listener===r)--this._eventsCount===0?this._events=Object.create(null):(delete i[t],i.removeListener&&this.emit("removeListener",t,n.listener||r));else if(typeof n!="function"){for(s=-1,o=n.length-1;o>=0;o--)if(n[o]===r||n[o].listener===r){a=n[o].listener,s=o;break}if(s<0)return this;s===0?n.shift():kZ(n,s),n.length===1&&(i[t]=n[0]),i.removeListener!==void 0&&this.emit("removeListener",t,a||r)}return this};kt.prototype.off=kt.prototype.removeListener;kt.prototype.removeAllListeners=function(t){var r,n,i;if(n=this._events,n===void 0)return this;if(n.removeListener===void 0)return arguments.length===0?(this._events=Object.create(null),this._eventsCount=0):n[t]!==void 0&&(--this._eventsCount===0?this._events=Object.create(null):delete n[t]),this;if(arguments.length===0){var s=Object.keys(n),o;for(i=0;i=0;i--)this.removeListener(t,r[i]);return this};function kD(e,t,r){var n=e._events;if(n===void 0)return[];var i=n[t];return i===void 0?[]:typeof i=="function"?r?[i.listener||i]:[i]:r?UZ(i):xD(i,i.length)}kt.prototype.listeners=function(t){return kD(this,t,!0)};kt.prototype.rawListeners=function(t){return kD(this,t,!1)};kt.listenerCount=function(e,t){return typeof e.listenerCount=="function"?e.listenerCount(t):UD.call(e,t)};kt.prototype.listenerCount=UD;function UD(e){var t=this._events;if(t!==void 0){var r=t[e];if(typeof r=="function")return 1;if(r!==void 0)return r.length}return 0}kt.prototype.eventNames=function(){return this._eventsCount>0?N0(this._events):[]};function xD(e,t){for(var r=new Array(t),n=0;n{"use strict";function Gs(e){if(typeof e!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}function PD(e,t){for(var r="",n=0,i=-1,s=0,o,a=0;a<=e.length;++a){if(a2){var A=r.lastIndexOf("/");if(A!==r.length-1){A===-1?(r="",n=0):(r=r.slice(0,A),n=r.length-1-r.lastIndexOf("/")),i=a,s=0;continue}}else if(r.length===2||r.length===1){r="",n=0,i=a,s=0;continue}}t&&(r.length>0?r+="/..":r="..",n=2)}else r.length>0?r+="/"+e.slice(i+1,a):r=e.slice(i+1,a),n=a-i-1;i=a,s=0}else o===46&&s!==-1?++s:s=-1}return r}function PZ(e,t){var r=t.dir||t.root,n=t.base||(t.name||"")+(t.ext||"");return r?r===t.root?r+n:r+e+n:n}var Yu={resolve:function(){for(var t="",r=!1,n,i=arguments.length-1;i>=-1&&!r;i--){var s;i>=0?s=arguments[i]:(n===void 0&&(n=process.cwd()),s=n),Gs(s),s.length!==0&&(t=s+"/"+t,r=s.charCodeAt(0)===47)}return t=PD(t,!r),r?t.length>0?"/"+t:"/":t.length>0?t:"."},normalize:function(t){if(Gs(t),t.length===0)return".";var r=t.charCodeAt(0)===47,n=t.charCodeAt(t.length-1)===47;return t=PD(t,!r),t.length===0&&!r&&(t="."),t.length>0&&n&&(t+="/"),r?"/"+t:t},isAbsolute:function(t){return Gs(t),t.length>0&&t.charCodeAt(0)===47},join:function(){if(arguments.length===0)return".";for(var t,r=0;r0&&(t===void 0?t=n:t+="/"+n)}return t===void 0?".":Yu.normalize(t)},relative:function(t,r){if(Gs(t),Gs(r),t===r||(t=Yu.resolve(t),r=Yu.resolve(r),t===r))return"";for(var n=1;nf){if(r.charCodeAt(o+p)===47)return r.slice(o+p+1);if(p===0)return r.slice(o+p)}else s>f&&(t.charCodeAt(n+p)===47?l=p:p===0&&(l=0));break}var I=t.charCodeAt(n+p),S=r.charCodeAt(o+p);if(I!==S)break;I===47&&(l=p)}var _="";for(p=n+l+1;p<=i;++p)(p===i||t.charCodeAt(p)===47)&&(_.length===0?_+="..":_+="/..");return _.length>0?_+r.slice(o+l):(o+=l,r.charCodeAt(o)===47&&++o,r.slice(o))},_makeLong:function(t){return t},dirname:function(t){if(Gs(t),t.length===0)return".";for(var r=t.charCodeAt(0),n=r===47,i=-1,s=!0,o=t.length-1;o>=1;--o)if(r=t.charCodeAt(o),r===47){if(!s){i=o;break}}else s=!1;return i===-1?n?"/":".":n&&i===1?"//":t.slice(0,i)},basename:function(t,r){if(r!==void 0&&typeof r!="string")throw new TypeError('"ext" argument must be a string');Gs(t);var n=0,i=-1,s=!0,o;if(r!==void 0&&r.length>0&&r.length<=t.length){if(r.length===t.length&&r===t)return"";var a=r.length-1,A=-1;for(o=t.length-1;o>=0;--o){var f=t.charCodeAt(o);if(f===47){if(!s){n=o+1;break}}else A===-1&&(s=!1,A=o+1),a>=0&&(f===r.charCodeAt(a)?--a===-1&&(i=o):(a=-1,i=A))}return n===i?i=A:i===-1&&(i=t.length),t.slice(n,i)}else{for(o=t.length-1;o>=0;--o)if(t.charCodeAt(o)===47){if(!s){n=o+1;break}}else i===-1&&(s=!1,i=o+1);return i===-1?"":t.slice(n,i)}},extname:function(t){Gs(t);for(var r=-1,n=0,i=-1,s=!0,o=0,a=t.length-1;a>=0;--a){var A=t.charCodeAt(a);if(A===47){if(!s){n=a+1;break}continue}i===-1&&(s=!1,i=a+1),A===46?r===-1?r=a:o!==1&&(o=1):r!==-1&&(o=-1)}return r===-1||i===-1||o===0||o===1&&r===i-1&&r===n+1?"":t.slice(r,i)},format:function(t){if(t===null||typeof t!="object")throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof t);return PZ("/",t)},parse:function(t){Gs(t);var r={root:"",dir:"",base:"",ext:"",name:""};if(t.length===0)return r;var n=t.charCodeAt(0),i=n===47,s;i?(r.root="/",s=1):s=0;for(var o=-1,a=0,A=-1,f=!0,l=t.length-1,p=0;l>=s;--l){if(n=t.charCodeAt(l),n===47){if(!f){a=l+1;break}continue}A===-1&&(f=!1,A=l+1),n===46?o===-1?o=l:p!==1&&(p=1):o!==-1&&(p=-1)}return o===-1||A===-1||p===0||p===1&&o===A-1&&o===a+1?A!==-1&&(a===0&&i?r.base=r.name=t.slice(1,A):r.base=r.name=t.slice(a,A)):(a===0&&i?(r.name=t.slice(1,o),r.base=t.slice(1,A)):(r.name=t.slice(a,o),r.base=t.slice(a,A)),r.ext=t.slice(o,A)),a>0?r.dir=t.slice(0,a-1):i&&(r.dir="/"),r},sep:"/",delimiter:":",win32:null,posix:null};Yu.posix=Yu;OD.exports=Yu});var DI=U((Wu,Vu)=>{(function(e){var t=typeof Wu=="object"&&Wu&&!Wu.nodeType&&Wu,r=typeof Vu=="object"&&Vu&&!Vu.nodeType&&Vu,n=typeof globalThis=="object"&&globalThis;(n.global===n||n.window===n||n.self===n)&&(e=n);var i,s=2147483647,o=36,a=1,A=26,f=38,l=700,p=72,I=128,S="-",_=/^xn--/,N=/[^\x20-\x7E]/,O=/[\x2E\u3002\uFF0E\uFF61]/g,x={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},G=o-a,Y=Math.floor,X=String.fromCharCode,Z;function j(C){throw new RangeError(x[C])}function se(C,h){for(var D=C.length,M=[];D--;)M[D]=h(C[D]);return M}function ie(C,h){var D=C.split("@"),M="";D.length>1&&(M=D[0]+"@",C=D[1]),C=C.replace(O,".");var B=C.split("."),k=se(B,h).join(".");return M+k}function ce(C){for(var h=[],D=0,M=C.length,B,k;D=55296&&B<=56319&&D65535&&(h-=65536,D+=X(h>>>10&1023|55296),h=56320|h&1023),D+=X(h),D}).join("")}function E(C){return C-48<10?C-22:C-65<26?C-65:C-97<26?C-97:o}function v(C,h){return C+22+75*(C<26)-((h!=0)<<5)}function b(C,h,D){var M=0;for(C=D?Y(C/l):C>>1,C+=Y(C/h);C>G*A>>1;M+=o)C=Y(C/G);return Y(M+(G+1)*C/(C+f))}function c(C){var h=[],D=C.length,M,B=0,k=I,ne=p,Ae,ue,pe,he,de,Qt,Ie,be,yr;for(Ae=C.lastIndexOf(S),Ae<0&&(Ae=0),ue=0;ue=128&&j("not-basic"),h.push(C.charCodeAt(ue));for(pe=Ae>0?Ae+1:0;pe=D&&j("invalid-input"),Ie=E(C.charCodeAt(pe++)),(Ie>=o||Ie>Y((s-B)/de))&&j("overflow"),B+=Ie*de,be=Qt<=ne?a:Qt>=ne+A?A:Qt-ne,!(IeY(s/yr)&&j("overflow"),de*=yr;M=h.length+1,ne=b(B-he,M,he==0),Y(B/M)>s-k&&j("overflow"),k+=Y(B/M),B%=M,h.splice(B++,0,k)}return H(h)}function g(C){var h,D,M,B,k,ne,Ae,ue,pe,he,de,Qt=[],Ie,be,yr,Qe;for(C=ce(C),Ie=C.length,h=I,D=0,k=p,ne=0;ne=h&&deY((s-D)/be)&&j("overflow"),D+=(Ae-h)*be,h=Ae,ne=0;nes&&j("overflow"),de==h){for(ue=D,pe=o;he=pe<=k?a:pe>=k+A?A:pe-k,!(ue{"use strict";function OZ(e,t){return Object.prototype.hasOwnProperty.call(e,t)}qD.exports=function(e,t,r,n){t=t||"&",r=r||"=";var i={};if(typeof e!="string"||e.length===0)return i;var s=/\+/g;e=e.split(t);var o=1e3;n&&typeof n.maxKeys=="number"&&(o=n.maxKeys);var a=e.length;o>0&&a>o&&(a=o);for(var A=0;A=0?(p=f.substr(0,l),I=f.substr(l+1)):(p=f,I=""),S=decodeURIComponent(p),_=decodeURIComponent(I),OZ(i,S)?HZ(i[S])?i[S].push(_):i[S]=[i[S],_]:i[S]=_}return i};var HZ=Array.isArray||function(e){return Object.prototype.toString.call(e)==="[object Array]"}});var VD=U((D2e,WD)=>{"use strict";var th=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};WD.exports=function(e,t,r,n){return t=t||"&",r=r||"=",e===null&&(e=void 0),typeof e=="object"?YD(GZ(e),function(i){var s=encodeURIComponent(th(i))+r;return qZ(e[i])?YD(e[i],function(o){return s+encodeURIComponent(th(o))}).join(t):s+encodeURIComponent(th(e[i]))}).join(t):n?encodeURIComponent(th(n))+r+encodeURIComponent(th(e)):""};var qZ=Array.isArray||function(e){return Object.prototype.toString.call(e)==="[object Array]"};function YD(e,t){if(e.map)return e.map(t);for(var r=[],n=0;n{"use strict";rh.decode=rh.parse=GD();rh.encode=rh.stringify=VD()});var F0={};EI(F0,{decode:()=>Va.decode,default:()=>YZ,encode:()=>Va.encode,escape:()=>JD,parse:()=>Va.parse,stringify:()=>Va.stringify,unescape:()=>jD});function JD(e){return encodeURIComponent(e)}function jD(e){return decodeURIComponent(e)}var Wa,Va,YZ,NI=uD(()=>{Wa=hr(TI(),1),Va=hr(TI(),1);YZ={decode:Wa.decode,encode:Wa.encode,parse:Wa.parse,stringify:Wa.stringify,escape:JD,unescape:jD}});var je=U((N2e,MI)=>{typeof Object.create=="function"?MI.exports=function(t,r){r&&(t.super_=r,t.prototype=Object.create(r.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}))}:MI.exports=function(t,r){if(r){t.super_=r;var n=function(){};n.prototype=r.prototype,t.prototype=new n,t.prototype.constructor=t}}});var FI=U((M2e,zD)=>{zD.exports=Zi().EventEmitter});var k0=U((F2e,KD)=>{"use strict";KD.exports=function(){if(typeof Symbol!="function"||typeof Object.getOwnPropertySymbols!="function")return!1;if(typeof Symbol.iterator=="symbol")return!0;var t={},r=Symbol("test"),n=Object(r);if(typeof r=="string"||Object.prototype.toString.call(r)!=="[object Symbol]"||Object.prototype.toString.call(n)!=="[object Symbol]")return!1;var i=42;t[r]=i;for(var s in t)return!1;if(typeof Object.keys=="function"&&Object.keys(t).length!==0||typeof Object.getOwnPropertyNames=="function"&&Object.getOwnPropertyNames(t).length!==0)return!1;var o=Object.getOwnPropertySymbols(t);if(o.length!==1||o[0]!==r||!Object.prototype.propertyIsEnumerable.call(t,r))return!1;if(typeof Object.getOwnPropertyDescriptor=="function"){var a=Object.getOwnPropertyDescriptor(t,r);if(a.value!==i||a.enumerable!==!0)return!1}return!0}});var nh=U((k2e,XD)=>{"use strict";var WZ=k0();XD.exports=function(){return WZ()&&!!Symbol.toStringTag}});var U0=U((U2e,ZD)=>{"use strict";ZD.exports=Object});var eT=U((x2e,$D)=>{"use strict";$D.exports=Error});var rT=U((L2e,tT)=>{"use strict";tT.exports=EvalError});var iT=U((P2e,nT)=>{"use strict";nT.exports=RangeError});var oT=U((O2e,sT)=>{"use strict";sT.exports=ReferenceError});var kI=U((H2e,aT)=>{"use strict";aT.exports=SyntaxError});var $i=U((q2e,AT)=>{"use strict";AT.exports=TypeError});var uT=U((G2e,fT)=>{"use strict";fT.exports=URIError});var lT=U((Y2e,cT)=>{"use strict";cT.exports=Math.abs});var dT=U((W2e,hT)=>{"use strict";hT.exports=Math.floor});var pT=U((V2e,gT)=>{"use strict";gT.exports=Math.max});var yT=U((J2e,ET)=>{"use strict";ET.exports=Math.min});var BT=U((j2e,mT)=>{"use strict";mT.exports=Math.pow});var bT=U((z2e,IT)=>{"use strict";IT.exports=Math.round});var QT=U((K2e,CT)=>{"use strict";CT.exports=Number.isNaN||function(t){return t!==t}});var ST=U((X2e,wT)=>{"use strict";var VZ=QT();wT.exports=function(t){return VZ(t)||t===0?t:t<0?-1:1}});var vT=U((Z2e,_T)=>{"use strict";_T.exports=Object.getOwnPropertyDescriptor});var XA=U(($2e,RT)=>{"use strict";var x0=vT();if(x0)try{x0([],"length")}catch{x0=null}RT.exports=x0});var ih=U((eRe,DT)=>{"use strict";var L0=Object.defineProperty||!1;if(L0)try{L0({},"a",{value:1})}catch{L0=!1}DT.exports=L0});var MT=U((tRe,NT)=>{"use strict";var TT=typeof Symbol<"u"&&Symbol,JZ=k0();NT.exports=function(){return typeof TT!="function"||typeof Symbol!="function"||typeof TT("foo")!="symbol"||typeof Symbol("bar")!="symbol"?!1:JZ()}});var UI=U((rRe,FT)=>{"use strict";FT.exports=typeof Reflect<"u"&&Reflect.getPrototypeOf||null});var xI=U((nRe,kT)=>{"use strict";var jZ=U0();kT.exports=jZ.getPrototypeOf||null});var LT=U((iRe,xT)=>{"use strict";var zZ="Function.prototype.bind called on incompatible ",KZ=Object.prototype.toString,XZ=Math.max,ZZ="[object Function]",UT=function(t,r){for(var n=[],i=0;i{"use strict";var t$=LT();PT.exports=Function.prototype.bind||t$});var P0=U((oRe,OT)=>{"use strict";OT.exports=Function.prototype.call});var O0=U((aRe,HT)=>{"use strict";HT.exports=Function.prototype.apply});var GT=U((ARe,qT)=>{"use strict";qT.exports=typeof Reflect<"u"&&Reflect&&Reflect.apply});var LI=U((fRe,YT)=>{"use strict";var r$=Ju(),n$=O0(),i$=P0(),s$=GT();YT.exports=s$||r$.call(i$,n$)});var H0=U((uRe,WT)=>{"use strict";var o$=Ju(),a$=$i(),A$=P0(),f$=LI();WT.exports=function(t){if(t.length<1||typeof t[0]!="function")throw new a$("a function is required");return f$(o$,A$,t)}});var XT=U((cRe,KT)=>{"use strict";var u$=H0(),VT=XA(),jT;try{jT=[].__proto__===Array.prototype}catch(e){if(!e||typeof e!="object"||!("code"in e)||e.code!=="ERR_PROTO_ACCESS")throw e}var PI=!!jT&&VT&&VT(Object.prototype,"__proto__"),zT=Object,JT=zT.getPrototypeOf;KT.exports=PI&&typeof PI.get=="function"?u$([PI.get]):typeof JT=="function"?function(t){return JT(t==null?t:zT(t))}:!1});var q0=U((lRe,tN)=>{"use strict";var ZT=UI(),$T=xI(),eN=XT();tN.exports=ZT?function(t){return ZT(t)}:$T?function(t){if(!t||typeof t!="object"&&typeof t!="function")throw new TypeError("getProto: not an object");return $T(t)}:eN?function(t){return eN(t)}:null});var OI=U((hRe,rN)=>{"use strict";var c$=Function.prototype.call,l$=Object.prototype.hasOwnProperty,h$=Ju();rN.exports=h$.call(c$,l$)});var Zu=U((dRe,AN)=>{"use strict";var gt,d$=U0(),g$=eT(),p$=rT(),E$=iT(),y$=oT(),Xu=kI(),Ku=$i(),m$=uT(),B$=lT(),I$=dT(),b$=pT(),C$=yT(),Q$=BT(),w$=bT(),S$=ST(),oN=Function,HI=function(e){try{return oN('"use strict"; return ('+e+").constructor;")()}catch{}},sh=XA(),_$=ih(),qI=function(){throw new Ku},v$=sh?(function(){try{return arguments.callee,qI}catch{try{return sh(arguments,"callee").get}catch{return qI}}})():qI,ju=MT()(),Tr=q0(),R$=xI(),D$=UI(),aN=O0(),oh=P0(),zu={},T$=typeof Uint8Array>"u"||!Tr?gt:Tr(Uint8Array),ZA={__proto__:null,"%AggregateError%":typeof AggregateError>"u"?gt:AggregateError,"%Array%":Array,"%ArrayBuffer%":typeof ArrayBuffer>"u"?gt:ArrayBuffer,"%ArrayIteratorPrototype%":ju&&Tr?Tr([][Symbol.iterator]()):gt,"%AsyncFromSyncIteratorPrototype%":gt,"%AsyncFunction%":zu,"%AsyncGenerator%":zu,"%AsyncGeneratorFunction%":zu,"%AsyncIteratorPrototype%":zu,"%Atomics%":typeof Atomics>"u"?gt:Atomics,"%BigInt%":typeof BigInt>"u"?gt:BigInt,"%BigInt64Array%":typeof BigInt64Array>"u"?gt:BigInt64Array,"%BigUint64Array%":typeof BigUint64Array>"u"?gt:BigUint64Array,"%Boolean%":Boolean,"%DataView%":typeof DataView>"u"?gt:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":g$,"%eval%":eval,"%EvalError%":p$,"%Float16Array%":typeof Float16Array>"u"?gt:Float16Array,"%Float32Array%":typeof Float32Array>"u"?gt:Float32Array,"%Float64Array%":typeof Float64Array>"u"?gt:Float64Array,"%FinalizationRegistry%":typeof FinalizationRegistry>"u"?gt:FinalizationRegistry,"%Function%":oN,"%GeneratorFunction%":zu,"%Int8Array%":typeof Int8Array>"u"?gt:Int8Array,"%Int16Array%":typeof Int16Array>"u"?gt:Int16Array,"%Int32Array%":typeof Int32Array>"u"?gt:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":ju&&Tr?Tr(Tr([][Symbol.iterator]())):gt,"%JSON%":typeof JSON=="object"?JSON:gt,"%Map%":typeof Map>"u"?gt:Map,"%MapIteratorPrototype%":typeof Map>"u"||!ju||!Tr?gt:Tr(new Map()[Symbol.iterator]()),"%Math%":Math,"%Number%":Number,"%Object%":d$,"%Object.getOwnPropertyDescriptor%":sh,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":typeof Promise>"u"?gt:Promise,"%Proxy%":typeof Proxy>"u"?gt:Proxy,"%RangeError%":E$,"%ReferenceError%":y$,"%Reflect%":typeof Reflect>"u"?gt:Reflect,"%RegExp%":RegExp,"%Set%":typeof Set>"u"?gt:Set,"%SetIteratorPrototype%":typeof Set>"u"||!ju||!Tr?gt:Tr(new Set()[Symbol.iterator]()),"%SharedArrayBuffer%":typeof SharedArrayBuffer>"u"?gt:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":ju&&Tr?Tr(""[Symbol.iterator]()):gt,"%Symbol%":ju?Symbol:gt,"%SyntaxError%":Xu,"%ThrowTypeError%":v$,"%TypedArray%":T$,"%TypeError%":Ku,"%Uint8Array%":typeof Uint8Array>"u"?gt:Uint8Array,"%Uint8ClampedArray%":typeof Uint8ClampedArray>"u"?gt:Uint8ClampedArray,"%Uint16Array%":typeof Uint16Array>"u"?gt:Uint16Array,"%Uint32Array%":typeof Uint32Array>"u"?gt:Uint32Array,"%URIError%":m$,"%WeakMap%":typeof WeakMap>"u"?gt:WeakMap,"%WeakRef%":typeof WeakRef>"u"?gt:WeakRef,"%WeakSet%":typeof WeakSet>"u"?gt:WeakSet,"%Function.prototype.call%":oh,"%Function.prototype.apply%":aN,"%Object.defineProperty%":_$,"%Object.getPrototypeOf%":R$,"%Math.abs%":B$,"%Math.floor%":I$,"%Math.max%":b$,"%Math.min%":C$,"%Math.pow%":Q$,"%Math.round%":w$,"%Math.sign%":S$,"%Reflect.getPrototypeOf%":D$};if(Tr)try{null.error}catch(e){nN=Tr(Tr(e)),ZA["%Error.prototype%"]=nN}var nN,N$=function e(t){var r;if(t==="%AsyncFunction%")r=HI("async function () {}");else if(t==="%GeneratorFunction%")r=HI("function* () {}");else if(t==="%AsyncGeneratorFunction%")r=HI("async function* () {}");else if(t==="%AsyncGenerator%"){var n=e("%AsyncGeneratorFunction%");n&&(r=n.prototype)}else if(t==="%AsyncIteratorPrototype%"){var i=e("%AsyncGenerator%");i&&Tr&&(r=Tr(i.prototype))}return ZA[t]=r,r},iN={__proto__:null,"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},ah=Ju(),G0=OI(),M$=ah.call(oh,Array.prototype.concat),F$=ah.call(aN,Array.prototype.splice),sN=ah.call(oh,String.prototype.replace),Y0=ah.call(oh,String.prototype.slice),k$=ah.call(oh,RegExp.prototype.exec),U$=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,x$=/\\(\\)?/g,L$=function(t){var r=Y0(t,0,1),n=Y0(t,-1);if(r==="%"&&n!=="%")throw new Xu("invalid intrinsic syntax, expected closing `%`");if(n==="%"&&r!=="%")throw new Xu("invalid intrinsic syntax, expected opening `%`");var i=[];return sN(t,U$,function(s,o,a,A){i[i.length]=a?sN(A,x$,"$1"):o||s}),i},P$=function(t,r){var n=t,i;if(G0(iN,n)&&(i=iN[n],n="%"+i[0]+"%"),G0(ZA,n)){var s=ZA[n];if(s===zu&&(s=N$(n)),typeof s>"u"&&!r)throw new Ku("intrinsic "+t+" exists, but is not available. Please file an issue!");return{alias:i,name:n,value:s}}throw new Xu("intrinsic "+t+" does not exist!")};AN.exports=function(t,r){if(typeof t!="string"||t.length===0)throw new Ku("intrinsic name must be a non-empty string");if(arguments.length>1&&typeof r!="boolean")throw new Ku('"allowMissing" argument must be a boolean');if(k$(/^%?[^%]*%?$/,t)===null)throw new Xu("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var n=L$(t),i=n.length>0?n[0]:"",s=P$("%"+i+"%",r),o=s.name,a=s.value,A=!1,f=s.alias;f&&(i=f[0],F$(n,M$([0,1],f)));for(var l=1,p=!0;l=n.length){var N=sh(a,I);p=!!N,p&&"get"in N&&!("originalValue"in N.get)?a=N.get:a=a[I]}else p=G0(a,I),a=a[I];p&&!A&&(ZA[o]=a)}}return a}});var Ys=U((gRe,cN)=>{"use strict";var fN=Zu(),uN=H0(),O$=uN([fN("%String.prototype.indexOf%")]);cN.exports=function(t,r){var n=fN(t,!!r);return typeof n=="function"&&O$(t,".prototype.")>-1?uN([n]):n}});var dN=U((pRe,hN)=>{"use strict";var H$=nh()(),q$=Ys(),GI=q$("Object.prototype.toString"),W0=function(t){return H$&&t&&typeof t=="object"&&Symbol.toStringTag in t?!1:GI(t)==="[object Arguments]"},lN=function(t){return W0(t)?!0:t!==null&&typeof t=="object"&&"length"in t&&typeof t.length=="number"&&t.length>=0&&GI(t)!=="[object Array]"&&"callee"in t&&GI(t.callee)==="[object Function]"},G$=(function(){return W0(arguments)})();W0.isLegacyArguments=lN;hN.exports=G$?W0:lN});var BN=U((ERe,mN)=>{"use strict";var gN=Ys(),Y$=nh()(),W$=OI(),V$=XA(),VI;Y$?(pN=gN("RegExp.prototype.exec"),YI={},V0=function(){throw YI},WI={toString:V0,valueOf:V0},typeof Symbol.toPrimitive=="symbol"&&(WI[Symbol.toPrimitive]=V0),VI=function(t){if(!t||typeof t!="object")return!1;var r=V$(t,"lastIndex"),n=r&&W$(r,"value");if(!n)return!1;try{pN(t,WI)}catch(i){return i===YI}}):(EN=gN("Object.prototype.toString"),yN="[object RegExp]",VI=function(t){return!t||typeof t!="object"&&typeof t!="function"?!1:EN(t)===yN});var pN,YI,V0,WI,EN,yN;mN.exports=VI});var bN=U((yRe,IN)=>{"use strict";var J$=Ys(),j$=BN(),z$=J$("RegExp.prototype.exec"),K$=$i();IN.exports=function(t){if(!j$(t))throw new K$("`regex` must be a RegExp");return function(n){return z$(t,n)!==null}}});var QN=U((mRe,CN)=>{"use strict";var X$=function*(){}.constructor;CN.exports=()=>X$});var vN=U((BRe,_N)=>{"use strict";var SN=Ys(),Z$=bN(),$$=Z$(/^\s*(?:function)?\*/),eee=nh()(),wN=q0(),tee=SN("Object.prototype.toString"),ree=SN("Function.prototype.toString"),nee=QN();_N.exports=function(t){if(typeof t!="function")return!1;if($$(ree(t)))return!0;if(!eee){var r=tee(t);return r==="[object GeneratorFunction]"}if(!wN)return!1;var n=nee();return n&&wN(t)===n.prototype}});var NN=U((IRe,TN)=>{"use strict";var DN=Function.prototype.toString,$u=typeof Reflect=="object"&&Reflect!==null&&Reflect.apply,jI,J0;if(typeof $u=="function"&&typeof Object.defineProperty=="function")try{jI=Object.defineProperty({},"length",{get:function(){throw J0}}),J0={},$u(function(){throw 42},null,jI)}catch(e){e!==J0&&($u=null)}else $u=null;var iee=/^\s*class\b/,zI=function(t){try{var r=DN.call(t);return iee.test(r)}catch{return!1}},JI=function(t){try{return zI(t)?!1:(DN.call(t),!0)}catch{return!1}},j0=Object.prototype.toString,see="[object Object]",oee="[object Function]",aee="[object GeneratorFunction]",Aee="[object HTMLAllCollection]",fee="[object HTML document.all class]",uee="[object HTMLCollection]",cee=typeof Symbol=="function"&&!!Symbol.toStringTag,lee=!(0 in[,]),KI=function(){return!1};typeof document=="object"&&(RN=document.all,j0.call(RN)===j0.call(document.all)&&(KI=function(t){if((lee||!t)&&(typeof t>"u"||typeof t=="object"))try{var r=j0.call(t);return(r===Aee||r===fee||r===uee||r===see)&&t("")==null}catch{}return!1}));var RN;TN.exports=$u?function(t){if(KI(t))return!0;if(!t||typeof t!="function"&&typeof t!="object")return!1;try{$u(t,null,jI)}catch(r){if(r!==J0)return!1}return!zI(t)&&JI(t)}:function(t){if(KI(t))return!0;if(!t||typeof t!="function"&&typeof t!="object")return!1;if(cee)return JI(t);if(zI(t))return!1;var r=j0.call(t);return r!==oee&&r!==aee&&!/^\[object HTML/.test(r)?!1:JI(t)}});var kN=U((bRe,FN)=>{"use strict";var hee=NN(),dee=Object.prototype.toString,MN=Object.prototype.hasOwnProperty,gee=function(t,r,n){for(var i=0,s=t.length;i=3&&(i=n),yee(t)?gee(t,r,i):typeof t=="string"?pee(t,r,i):Eee(t,r,i)}});var xN=U((CRe,UN)=>{"use strict";UN.exports=["Float16Array","Float32Array","Float64Array","Int8Array","Int16Array","Int32Array","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array"]});var PN=U((QRe,LN)=>{"use strict";var XI=xN(),mee=globalThis;LN.exports=function(){for(var t=[],r=0;r{"use strict";var ON=ih(),Bee=kI(),ec=$i(),HN=XA();qN.exports=function(t,r,n){if(!t||typeof t!="object"&&typeof t!="function")throw new ec("`obj` must be an object or a function`");if(typeof r!="string"&&typeof r!="symbol")throw new ec("`property` must be a string or a symbol`");if(arguments.length>3&&typeof arguments[3]!="boolean"&&arguments[3]!==null)throw new ec("`nonEnumerable`, if provided, must be a boolean or null");if(arguments.length>4&&typeof arguments[4]!="boolean"&&arguments[4]!==null)throw new ec("`nonWritable`, if provided, must be a boolean or null");if(arguments.length>5&&typeof arguments[5]!="boolean"&&arguments[5]!==null)throw new ec("`nonConfigurable`, if provided, must be a boolean or null");if(arguments.length>6&&typeof arguments[6]!="boolean")throw new ec("`loose`, if provided, must be a boolean");var i=arguments.length>3?arguments[3]:null,s=arguments.length>4?arguments[4]:null,o=arguments.length>5?arguments[5]:null,a=arguments.length>6?arguments[6]:!1,A=!!HN&&HN(t,r);if(ON)ON(t,r,{configurable:o===null&&A?A.configurable:!o,enumerable:i===null&&A?A.enumerable:!i,value:n,writable:s===null&&A?A.writable:!s});else if(a||!i&&!s&&!o)t[r]=n;else throw new Bee("This environment does not support defining a property as non-configurable, non-writable, or non-enumerable.")}});var eb=U((SRe,YN)=>{"use strict";var $I=ih(),GN=function(){return!!$I};GN.hasArrayLengthDefineBug=function(){if(!$I)return null;try{return $I([],"length",{value:1}).length!==1}catch{return!0}};YN.exports=GN});var zN=U((_Re,jN)=>{"use strict";var Iee=Zu(),WN=ZI(),bee=eb()(),VN=XA(),JN=$i(),Cee=Iee("%Math.floor%");jN.exports=function(t,r){if(typeof t!="function")throw new JN("`fn` is not a function");if(typeof r!="number"||r<0||r>4294967295||Cee(r)!==r)throw new JN("`length` must be a positive 32-bit integer");var n=arguments.length>2&&!!arguments[2],i=!0,s=!0;if("length"in t&&VN){var o=VN(t,"length");o&&!o.configurable&&(i=!1),o&&!o.writable&&(s=!1)}return(i||s||!n)&&(bee?WN(t,"length",r,!0,!0):WN(t,"length",r)),t}});var XN=U((vRe,KN)=>{"use strict";var Qee=Ju(),wee=O0(),See=LI();KN.exports=function(){return See(Qee,wee,arguments)}});var Ah=U((RRe,z0)=>{"use strict";var _ee=zN(),ZN=ih(),vee=H0(),$N=XN();z0.exports=function(t){var r=vee(arguments),n=t.length-(arguments.length-1);return _ee(r,1+(n>0?n:0),!0)};ZN?ZN(z0.exports,"apply",{value:$N}):z0.exports.apply=$N});var ib=U((DRe,nM)=>{"use strict";var Z0=kN(),Ree=PN(),eM=Ah(),rb=Ys(),X0=XA(),K0=q0(),Dee=rb("Object.prototype.toString"),rM=nh()(),tM=globalThis,tb=Ree(),nb=rb("String.prototype.slice"),Tee=rb("Array.prototype.indexOf",!0)||function(t,r){for(var n=0;n-1?r:r!=="Object"?!1:Mee(t)}return X0?Nee(t):null}});var sb=U((TRe,iM)=>{"use strict";var Fee=ib();iM.exports=function(t){return!!Fee(t)}});var yM=U(pt=>{"use strict";var kee=dN(),Uee=vN(),es=ib(),sM=sb();function tc(e){return e.call.bind(e)}var oM=typeof BigInt<"u",aM=typeof Symbol<"u",li=tc(Object.prototype.toString),xee=tc(Number.prototype.valueOf),Lee=tc(String.prototype.valueOf),Pee=tc(Boolean.prototype.valueOf);oM&&(AM=tc(BigInt.prototype.valueOf));var AM;aM&&(fM=tc(Symbol.prototype.valueOf));var fM;function uh(e,t){if(typeof e!="object")return!1;try{return t(e),!0}catch{return!1}}pt.isArgumentsObject=kee;pt.isGeneratorFunction=Uee;pt.isTypedArray=sM;function Oee(e){return typeof Promise<"u"&&e instanceof Promise||e!==null&&typeof e=="object"&&typeof e.then=="function"&&typeof e.catch=="function"}pt.isPromise=Oee;function Hee(e){return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?ArrayBuffer.isView(e):sM(e)||cM(e)}pt.isArrayBufferView=Hee;function qee(e){return es(e)==="Uint8Array"}pt.isUint8Array=qee;function Gee(e){return es(e)==="Uint8ClampedArray"}pt.isUint8ClampedArray=Gee;function Yee(e){return es(e)==="Uint16Array"}pt.isUint16Array=Yee;function Wee(e){return es(e)==="Uint32Array"}pt.isUint32Array=Wee;function Vee(e){return es(e)==="Int8Array"}pt.isInt8Array=Vee;function Jee(e){return es(e)==="Int16Array"}pt.isInt16Array=Jee;function jee(e){return es(e)==="Int32Array"}pt.isInt32Array=jee;function zee(e){return es(e)==="Float32Array"}pt.isFloat32Array=zee;function Kee(e){return es(e)==="Float64Array"}pt.isFloat64Array=Kee;function Xee(e){return es(e)==="BigInt64Array"}pt.isBigInt64Array=Xee;function Zee(e){return es(e)==="BigUint64Array"}pt.isBigUint64Array=Zee;function ep(e){return li(e)==="[object Map]"}ep.working=typeof Map<"u"&&ep(new Map);function $ee(e){return typeof Map>"u"?!1:ep.working?ep(e):e instanceof Map}pt.isMap=$ee;function tp(e){return li(e)==="[object Set]"}tp.working=typeof Set<"u"&&tp(new Set);function ete(e){return typeof Set>"u"?!1:tp.working?tp(e):e instanceof Set}pt.isSet=ete;function rp(e){return li(e)==="[object WeakMap]"}rp.working=typeof WeakMap<"u"&&rp(new WeakMap);function tte(e){return typeof WeakMap>"u"?!1:rp.working?rp(e):e instanceof WeakMap}pt.isWeakMap=tte;function ab(e){return li(e)==="[object WeakSet]"}ab.working=typeof WeakSet<"u"&&ab(new WeakSet);function rte(e){return ab(e)}pt.isWeakSet=rte;function np(e){return li(e)==="[object ArrayBuffer]"}np.working=typeof ArrayBuffer<"u"&&np(new ArrayBuffer);function uM(e){return typeof ArrayBuffer>"u"?!1:np.working?np(e):e instanceof ArrayBuffer}pt.isArrayBuffer=uM;function ip(e){return li(e)==="[object DataView]"}ip.working=typeof ArrayBuffer<"u"&&typeof DataView<"u"&&ip(new DataView(new ArrayBuffer(1),0,1));function cM(e){return typeof DataView>"u"?!1:ip.working?ip(e):e instanceof DataView}pt.isDataView=cM;var ob=typeof SharedArrayBuffer<"u"?SharedArrayBuffer:void 0;function fh(e){return li(e)==="[object SharedArrayBuffer]"}function lM(e){return typeof ob>"u"?!1:(typeof fh.working>"u"&&(fh.working=fh(new ob)),fh.working?fh(e):e instanceof ob)}pt.isSharedArrayBuffer=lM;function nte(e){return li(e)==="[object AsyncFunction]"}pt.isAsyncFunction=nte;function ite(e){return li(e)==="[object Map Iterator]"}pt.isMapIterator=ite;function ste(e){return li(e)==="[object Set Iterator]"}pt.isSetIterator=ste;function ote(e){return li(e)==="[object Generator]"}pt.isGeneratorObject=ote;function ate(e){return li(e)==="[object WebAssembly.Module]"}pt.isWebAssemblyCompiledModule=ate;function hM(e){return uh(e,xee)}pt.isNumberObject=hM;function dM(e){return uh(e,Lee)}pt.isStringObject=dM;function gM(e){return uh(e,Pee)}pt.isBooleanObject=gM;function pM(e){return oM&&uh(e,AM)}pt.isBigIntObject=pM;function EM(e){return aM&&uh(e,fM)}pt.isSymbolObject=EM;function Ate(e){return hM(e)||dM(e)||gM(e)||pM(e)||EM(e)}pt.isBoxedPrimitive=Ate;function fte(e){return typeof Uint8Array<"u"&&(uM(e)||lM(e))}pt.isAnyArrayBuffer=fte;["isProxy","isExternal","isModuleNamespaceObject"].forEach(function(e){Object.defineProperty(pt,e,{enumerable:!1,value:function(){return!1}})})});var BM=U((MRe,mM)=>{mM.exports=function(t){return t&&typeof t=="object"&&typeof t.copy=="function"&&typeof t.fill=="function"&&typeof t.readUInt8=="function"}});var Yr=U(Et=>{var IM=Object.getOwnPropertyDescriptors||function(t){for(var r=Object.keys(t),n={},i=0;i=i)return a;switch(a){case"%s":return String(n[r++]);case"%d":return Number(n[r++]);case"%j":try{return JSON.stringify(n[r++])}catch{return"[Circular]"}default:return a}}),o=n[r];r"u")return function(){return Et.deprecate(e,t).apply(this,arguments)};var r=!1;function n(){if(!r){if(process.throwDeprecation)throw new Error(t);process.traceDeprecation?console.trace(t):console.error(t),r=!0}return e.apply(this,arguments)}return n};var sp={},bM=/^$/;process.env.NODE_DEBUG&&(op=process.env.NODE_DEBUG,op=op.replace(/[|\\{}()[\]^$+?.]/g,"\\$&").replace(/\*/g,".*").replace(/,/g,"$|^").toUpperCase(),bM=new RegExp("^"+op+"$","i"));var op;Et.debuglog=function(e){if(e=e.toUpperCase(),!sp[e])if(bM.test(e)){var t=process.pid;sp[e]=function(){var r=Et.format.apply(Et,arguments);console.error("%s %d: %s",e,t,r)}}else sp[e]=function(){};return sp[e]};function Ja(e,t){var r={seen:[],stylize:lte};return arguments.length>=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),cb(t)?r.showHidden=t:t&&Et._extend(r,t),ef(r.showHidden)&&(r.showHidden=!1),ef(r.depth)&&(r.depth=2),ef(r.colors)&&(r.colors=!1),ef(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=cte),Ap(r,e,r.depth)}Et.inspect=Ja;Ja.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]};Ja.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"};function cte(e,t){var r=Ja.styles[t];return r?"\x1B["+Ja.colors[r][0]+"m"+e+"\x1B["+Ja.colors[r][1]+"m":e}function lte(e,t){return e}function hte(e){var t={};return e.forEach(function(r,n){t[r]=!0}),t}function Ap(e,t,r){if(e.customInspect&&t&&ap(t.inspect)&&t.inspect!==Et.inspect&&!(t.constructor&&t.constructor.prototype===t)){var n=t.inspect(r,e);return cp(n)||(n=Ap(e,n,r)),n}var i=dte(e,t);if(i)return i;var s=Object.keys(t),o=hte(s);if(e.showHidden&&(s=Object.getOwnPropertyNames(t)),lh(t)&&(s.indexOf("message")>=0||s.indexOf("description")>=0))return Ab(t);if(s.length===0){if(ap(t)){var a=t.name?": "+t.name:"";return e.stylize("[Function"+a+"]","special")}if(ch(t))return e.stylize(RegExp.prototype.toString.call(t),"regexp");if(fp(t))return e.stylize(Date.prototype.toString.call(t),"date");if(lh(t))return Ab(t)}var A="",f=!1,l=["{","}"];if(CM(t)&&(f=!0,l=["[","]"]),ap(t)){var p=t.name?": "+t.name:"";A=" [Function"+p+"]"}if(ch(t)&&(A=" "+RegExp.prototype.toString.call(t)),fp(t)&&(A=" "+Date.prototype.toUTCString.call(t)),lh(t)&&(A=" "+Ab(t)),s.length===0&&(!f||t.length==0))return l[0]+A+l[1];if(r<0)return ch(t)?e.stylize(RegExp.prototype.toString.call(t),"regexp"):e.stylize("[Object]","special");e.seen.push(t);var I;return f?I=gte(e,t,r,o,s):I=s.map(function(S){return ub(e,t,r,o,S,f)}),e.seen.pop(),pte(I,A,l)}function dte(e,t){if(ef(t))return e.stylize("undefined","undefined");if(cp(t)){var r="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(r,"string")}if(QM(t))return e.stylize(""+t,"number");if(cb(t))return e.stylize(""+t,"boolean");if(up(t))return e.stylize("null","null")}function Ab(e){return"["+Error.prototype.toString.call(e)+"]"}function gte(e,t,r,n,i){for(var s=[],o=0,a=t.length;o-1&&(s?a=a.split(` -`).map(function(f){return" "+f}).join(` -`).slice(2):a=` -`+a.split(` -`).map(function(f){return" "+f}).join(` -`))):a=e.stylize("[Circular]","special")),ef(o)){if(s&&i.match(/^\d+$/))return a;o=JSON.stringify(""+i),o.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(o=o.slice(1,-1),o=e.stylize(o,"name")):(o=o.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),o=e.stylize(o,"string"))}return o+": "+a}function pte(e,t,r){var n=0,i=e.reduce(function(s,o){return n++,o.indexOf(` -`)>=0&&n++,s+o.replace(/\u001b\[\d\d?m/g,"").length+1},0);return i>60?r[0]+(t===""?"":t+` - `)+" "+e.join(`, - `)+" "+r[1]:r[0]+t+" "+e.join(", ")+" "+r[1]}Et.types=yM();function CM(e){return Array.isArray(e)}Et.isArray=CM;function cb(e){return typeof e=="boolean"}Et.isBoolean=cb;function up(e){return e===null}Et.isNull=up;function Ete(e){return e==null}Et.isNullOrUndefined=Ete;function QM(e){return typeof e=="number"}Et.isNumber=QM;function cp(e){return typeof e=="string"}Et.isString=cp;function yte(e){return typeof e=="symbol"}Et.isSymbol=yte;function ef(e){return e===void 0}Et.isUndefined=ef;function ch(e){return rc(e)&&lb(e)==="[object RegExp]"}Et.isRegExp=ch;Et.types.isRegExp=ch;function rc(e){return typeof e=="object"&&e!==null}Et.isObject=rc;function fp(e){return rc(e)&&lb(e)==="[object Date]"}Et.isDate=fp;Et.types.isDate=fp;function lh(e){return rc(e)&&(lb(e)==="[object Error]"||e instanceof Error)}Et.isError=lh;Et.types.isNativeError=lh;function ap(e){return typeof e=="function"}Et.isFunction=ap;function mte(e){return e===null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"||typeof e=="symbol"||typeof e>"u"}Et.isPrimitive=mte;Et.isBuffer=BM();function lb(e){return Object.prototype.toString.call(e)}function fb(e){return e<10?"0"+e.toString(10):e.toString(10)}var Bte=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function Ite(){var e=new Date,t=[fb(e.getHours()),fb(e.getMinutes()),fb(e.getSeconds())].join(":");return[e.getDate(),Bte[e.getMonth()],t].join(" ")}Et.log=function(){console.log("%s - %s",Ite(),Et.format.apply(Et,arguments))};Et.inherits=je();Et._extend=function(e,t){if(!t||!rc(t))return e;for(var r=Object.keys(t),n=r.length;n--;)e[r[n]]=t[r[n]];return e};function wM(e,t){return Object.prototype.hasOwnProperty.call(e,t)}var $A=typeof Symbol<"u"?Symbol("util.promisify.custom"):void 0;Et.promisify=function(t){if(typeof t!="function")throw new TypeError('The "original" argument must be of type Function');if($A&&t[$A]){var r=t[$A];if(typeof r!="function")throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(r,$A,{value:r,enumerable:!1,writable:!1,configurable:!0}),r}function r(){for(var n,i,s=new Promise(function(A,f){n=A,i=f}),o=[],a=0;a{"use strict";function SM(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),r.push.apply(r,n)}return r}function _M(e){for(var t=1;t0?this.tail.next=n:this.head=n,this.tail=n,++this.length}},{key:"unshift",value:function(r){var n={data:r,next:this.head};this.length===0&&(this.tail=n),this.head=n,++this.length}},{key:"shift",value:function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(r){if(this.length===0)return"";for(var n=this.head,i=""+n.data;n=n.next;)i+=r+n.data;return i}},{key:"concat",value:function(r){if(this.length===0)return lp.alloc(0);for(var n=lp.allocUnsafe(r>>>0),i=this.head,s=0;i;)Tte(i.data,n,s),s+=i.data.length,i=i.next;return n}},{key:"consume",value:function(r,n){var i;return ro.length?o.length:r;if(a===o.length?s+=o:s+=o.slice(0,r),r-=a,r===0){a===o.length?(++i,n.next?this.head=n.next:this.head=this.tail=null):(this.head=n,n.data=o.slice(a));break}++i}return this.length-=i,s}},{key:"_getBuffer",value:function(r){var n=lp.allocUnsafe(r),i=this.head,s=1;for(i.data.copy(n),r-=i.data.length;i=i.next;){var o=i.data,a=r>o.length?o.length:r;if(o.copy(n,n.length-r,0,a),r-=a,r===0){a===o.length?(++s,i.next?this.head=i.next:this.head=this.tail=null):(this.head=i,i.data=o.slice(a));break}++s}return this.length-=s,n}},{key:Dte,value:function(r,n){return hb(this,_M(_M({},n),{},{depth:0,customInspect:!1}))}}]),e})()});var gb=U((URe,MM)=>{"use strict";function Nte(e,t){var r=this,n=this._readableState&&this._readableState.destroyed,i=this._writableState&&this._writableState.destroyed;return n||i?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(db,this,e)):process.nextTick(db,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(s){!t&&s?r._writableState?r._writableState.errorEmitted?process.nextTick(hp,r):(r._writableState.errorEmitted=!0,process.nextTick(NM,r,s)):process.nextTick(NM,r,s):t?(process.nextTick(hp,r),t(s)):process.nextTick(hp,r)}),this)}function NM(e,t){db(e,t),hp(e)}function hp(e){e._writableState&&!e._writableState.emitClose||e._readableState&&!e._readableState.emitClose||e.emit("close")}function Mte(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function db(e,t){e.emit("error",t)}function Fte(e,t){var r=e._readableState,n=e._writableState;r&&r.autoDestroy||n&&n.autoDestroy?e.destroy(t):e.emit("error",t)}MM.exports={destroy:Nte,undestroy:Mte,errorOrDestroy:Fte}});var tf=U((xRe,UM)=>{"use strict";function kte(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}var kM={};function hi(e,t,r){r||(r=Error);function n(s,o,a){return typeof t=="string"?t:t(s,o,a)}var i=(function(s){kte(o,s);function o(a,A,f){return s.call(this,n(a,A,f))||this}return o})(r);i.prototype.name=r.name,i.prototype.code=e,kM[e]=i}function FM(e,t){if(Array.isArray(e)){var r=e.length;return e=e.map(function(n){return String(n)}),r>2?"one of ".concat(t," ").concat(e.slice(0,r-1).join(", "),", or ")+e[r-1]:r===2?"one of ".concat(t," ").concat(e[0]," or ").concat(e[1]):"of ".concat(t," ").concat(e[0])}else return"of ".concat(t," ").concat(String(e))}function Ute(e,t,r){return e.substr(!r||r<0?0:+r,t.length)===t}function xte(e,t,r){return(r===void 0||r>e.length)&&(r=e.length),e.substring(r-t.length,r)===t}function Lte(e,t,r){return typeof r!="number"&&(r=0),r+t.length>e.length?!1:e.indexOf(t,r)!==-1}hi("ERR_INVALID_OPT_VALUE",function(e,t){return'The value "'+t+'" is invalid for option "'+e+'"'},TypeError);hi("ERR_INVALID_ARG_TYPE",function(e,t,r){var n;typeof t=="string"&&Ute(t,"not ")?(n="must not be",t=t.replace(/^not /,"")):n="must be";var i;if(xte(e," argument"))i="The ".concat(e," ").concat(n," ").concat(FM(t,"type"));else{var s=Lte(e,".")?"property":"argument";i='The "'.concat(e,'" ').concat(s," ").concat(n," ").concat(FM(t,"type"))}return i+=". Received type ".concat(typeof r),i},TypeError);hi("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF");hi("ERR_METHOD_NOT_IMPLEMENTED",function(e){return"The "+e+" method is not implemented"});hi("ERR_STREAM_PREMATURE_CLOSE","Premature close");hi("ERR_STREAM_DESTROYED",function(e){return"Cannot call "+e+" after a stream was destroyed"});hi("ERR_MULTIPLE_CALLBACK","Callback called multiple times");hi("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable");hi("ERR_STREAM_WRITE_AFTER_END","write after end");hi("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError);hi("ERR_UNKNOWN_ENCODING",function(e){return"Unknown encoding: "+e},TypeError);hi("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event");UM.exports.codes=kM});var pb=U((LRe,xM)=>{"use strict";var Pte=tf().codes.ERR_INVALID_OPT_VALUE;function Ote(e,t,r){return e.highWaterMark!=null?e.highWaterMark:t?e[r]:null}function Hte(e,t,r,n){var i=Ote(t,n,r);if(i!=null){if(!(isFinite(i)&&Math.floor(i)===i)||i<0){var s=n?r:"highWaterMark";throw new Pte(s,i)}return Math.floor(i)}return e.objectMode?16:16*1024}xM.exports={getHighWaterMark:Hte}});var yb=U((PRe,LM)=>{LM.exports=qte;function qte(e,t){if(Eb("noDeprecation"))return e;var r=!1;function n(){if(!r){if(Eb("throwDeprecation"))throw new Error(t);Eb("traceDeprecation")?console.trace(t):console.warn(t),r=!0}return e.apply(this,arguments)}return n}function Eb(e){try{if(!globalThis.localStorage)return!1}catch{return!1}var t=globalThis.localStorage[e];return t==null?!1:String(t).toLowerCase()==="true"}});var Ib=U((ORe,YM)=>{"use strict";YM.exports=Ar;function OM(e){var t=this;this.next=null,this.entry=null,this.finish=function(){gre(t,e)}}var nc;Ar.WritableState=dh;var Gte={deprecate:yb()},HM=FI(),gp=Gr().Buffer,Yte=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function Wte(e){return gp.from(e)}function Vte(e){return gp.isBuffer(e)||e instanceof Yte}var Bb=gb(),Jte=pb(),jte=Jte.getHighWaterMark,ja=tf().codes,zte=ja.ERR_INVALID_ARG_TYPE,Kte=ja.ERR_METHOD_NOT_IMPLEMENTED,Xte=ja.ERR_MULTIPLE_CALLBACK,Zte=ja.ERR_STREAM_CANNOT_PIPE,$te=ja.ERR_STREAM_DESTROYED,ere=ja.ERR_STREAM_NULL_VALUES,tre=ja.ERR_STREAM_WRITE_AFTER_END,rre=ja.ERR_UNKNOWN_ENCODING,ic=Bb.errorOrDestroy;je()(Ar,HM);function nre(){}function dh(e,t,r){nc=nc||rf(),e=e||{},typeof r!="boolean"&&(r=t instanceof nc),this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode),this.highWaterMark=jte(this,e,"writableHighWaterMark",r),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var n=e.decodeStrings===!1;this.decodeStrings=!n,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(i){ure(t,i)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new OM(this)}dh.prototype.getBuffer=function(){for(var t=this.bufferedRequest,r=[];t;)r.push(t),t=t.next;return r};(function(){try{Object.defineProperty(dh.prototype,"buffer",{get:Gte.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch{}})();var dp;typeof Symbol=="function"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]=="function"?(dp=Function.prototype[Symbol.hasInstance],Object.defineProperty(Ar,Symbol.hasInstance,{value:function(t){return dp.call(this,t)?!0:this!==Ar?!1:t&&t._writableState instanceof dh}})):dp=function(t){return t instanceof this};function Ar(e){nc=nc||rf();var t=this instanceof nc;if(!t&&!dp.call(Ar,this))return new Ar(e);this._writableState=new dh(e,this,t),this.writable=!0,e&&(typeof e.write=="function"&&(this._write=e.write),typeof e.writev=="function"&&(this._writev=e.writev),typeof e.destroy=="function"&&(this._destroy=e.destroy),typeof e.final=="function"&&(this._final=e.final)),HM.call(this)}Ar.prototype.pipe=function(){ic(this,new Zte)};function ire(e,t){var r=new tre;ic(e,r),process.nextTick(t,r)}function sre(e,t,r,n){var i;return r===null?i=new ere:typeof r!="string"&&!t.objectMode&&(i=new zte("chunk",["string","Buffer"],r)),i?(ic(e,i),process.nextTick(n,i),!1):!0}Ar.prototype.write=function(e,t,r){var n=this._writableState,i=!1,s=!n.objectMode&&Vte(e);return s&&!gp.isBuffer(e)&&(e=Wte(e)),typeof t=="function"&&(r=t,t=null),s?t="buffer":t||(t=n.defaultEncoding),typeof r!="function"&&(r=nre),n.ending?ire(this,r):(s||sre(this,n,e,r))&&(n.pendingcb++,i=are(this,n,s,e,t,r)),i};Ar.prototype.cork=function(){this._writableState.corked++};Ar.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&qM(this,e))};Ar.prototype.setDefaultEncoding=function(t){if(typeof t=="string"&&(t=t.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((t+"").toLowerCase())>-1))throw new rre(t);return this._writableState.defaultEncoding=t,this};Object.defineProperty(Ar.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function ore(e,t,r){return!e.objectMode&&e.decodeStrings!==!1&&typeof t=="string"&&(t=gp.from(t,r)),t}Object.defineProperty(Ar.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function are(e,t,r,n,i,s){if(!r){var o=ore(t,n,i);n!==o&&(r=!0,i="buffer",n=o)}var a=t.objectMode?1:n.length;t.length+=a;var A=t.length{"use strict";var pre=Object.keys||function(e){var t=[];for(var r in e)t.push(r);return t};VM.exports=Ws;var WM=Qb(),Cb=Ib();je()(Ws,WM);for(bb=pre(Cb.prototype),pp=0;pp{var yp=Gr(),Vs=yp.Buffer;function JM(e,t){for(var r in e)t[r]=e[r]}Vs.from&&Vs.alloc&&Vs.allocUnsafe&&Vs.allocUnsafeSlow?jM.exports=yp:(JM(yp,wb),wb.Buffer=nf);function nf(e,t,r){return Vs(e,t,r)}nf.prototype=Object.create(Vs.prototype);JM(Vs,nf);nf.from=function(e,t,r){if(typeof e=="number")throw new TypeError("Argument must not be a number");return Vs(e,t,r)};nf.alloc=function(e,t,r){if(typeof e!="number")throw new TypeError("Argument must be a number");var n=Vs(e);return t!==void 0?typeof r=="string"?n.fill(t,r):n.fill(t):n.fill(0),n};nf.allocUnsafe=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return Vs(e)};nf.allocUnsafeSlow=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return yp.SlowBuffer(e)}});var sf=U(KM=>{"use strict";var _b=at().Buffer,zM=_b.isEncoding||function(e){switch(e=""+e,e&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function mre(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}function Bre(e){var t=mre(e);if(typeof t!="string"&&(_b.isEncoding===zM||!zM(e)))throw new Error("Unknown encoding: "+e);return t||e}KM.StringDecoder=gh;function gh(e){this.encoding=Bre(e);var t;switch(this.encoding){case"utf16le":this.text=Sre,this.end=_re,t=4;break;case"utf8":this.fillLast=Cre,t=4;break;case"base64":this.text=vre,this.end=Rre,t=3;break;default:this.write=Dre,this.end=Tre;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=_b.allocUnsafe(t)}gh.prototype.write=function(e){if(e.length===0)return"";var t,r;if(this.lastNeed){if(t=this.fillLast(e),t===void 0)return"";r=this.lastNeed,this.lastNeed=0}else r=0;return r>5===6?2:e>>4===14?3:e>>3===30?4:e>>6===2?-1:-2}function Ire(e,t,r){var n=t.length-1;if(n=0?(i>0&&(e.lastNeed=i-1),i):--n=0?(i>0&&(e.lastNeed=i-2),i):--n=0?(i>0&&(i===2?i=0:e.lastNeed=i-3),i):0))}function bre(e,t,r){if((t[0]&192)!==128)return e.lastNeed=0,"\uFFFD";if(e.lastNeed>1&&t.length>1){if((t[1]&192)!==128)return e.lastNeed=1,"\uFFFD";if(e.lastNeed>2&&t.length>2&&(t[2]&192)!==128)return e.lastNeed=2,"\uFFFD"}}function Cre(e){var t=this.lastTotal-this.lastNeed,r=bre(this,e,t);if(r!==void 0)return r;if(this.lastNeed<=e.length)return e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length}function Qre(e,t){var r=Ire(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=r;var n=e.length-(r-this.lastNeed);return e.copy(this.lastChar,0,n),e.toString("utf8",t,n)}function wre(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"\uFFFD":t}function Sre(e,t){if((e.length-t)%2===0){var r=e.toString("utf16le",t);if(r){var n=r.charCodeAt(r.length-1);if(n>=55296&&n<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function _re(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,r)}return t}function vre(e,t){var r=(e.length-t)%3;return r===0?e.toString("base64",t):(this.lastNeed=3-r,this.lastTotal=3,r===1?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-r))}function Rre(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function Dre(e){return e.toString(this.encoding)}function Tre(e){return e&&e.length?this.write(e):""}});var mp=U((GRe,$M)=>{"use strict";var XM=tf().codes.ERR_STREAM_PREMATURE_CLOSE;function Nre(e){var t=!1;return function(){if(!t){t=!0;for(var r=arguments.length,n=new Array(r),i=0;i{"use strict";var Bp;function za(e,t,r){return t=kre(t),t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function kre(e){var t=Ure(e,"string");return typeof t=="symbol"?t:String(t)}function Ure(e,t){if(typeof e!="object"||e===null)return e;var r=e[Symbol.toPrimitive];if(r!==void 0){var n=r.call(e,t||"default");if(typeof n!="object")return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(e)}var xre=mp(),Ka=Symbol("lastResolve"),of=Symbol("lastReject"),ph=Symbol("error"),Ip=Symbol("ended"),af=Symbol("lastPromise"),vb=Symbol("handlePromise"),Af=Symbol("stream");function Xa(e,t){return{value:e,done:t}}function Lre(e){var t=e[Ka];if(t!==null){var r=e[Af].read();r!==null&&(e[af]=null,e[Ka]=null,e[of]=null,t(Xa(r,!1)))}}function Pre(e){process.nextTick(Lre,e)}function Ore(e,t){return function(r,n){e.then(function(){if(t[Ip]){r(Xa(void 0,!0));return}t[vb](r,n)},n)}}var Hre=Object.getPrototypeOf(function(){}),qre=Object.setPrototypeOf((Bp={get stream(){return this[Af]},next:function(){var t=this,r=this[ph];if(r!==null)return Promise.reject(r);if(this[Ip])return Promise.resolve(Xa(void 0,!0));if(this[Af].destroyed)return new Promise(function(o,a){process.nextTick(function(){t[ph]?a(t[ph]):o(Xa(void 0,!0))})});var n=this[af],i;if(n)i=new Promise(Ore(n,this));else{var s=this[Af].read();if(s!==null)return Promise.resolve(Xa(s,!1));i=new Promise(this[vb])}return this[af]=i,i}},za(Bp,Symbol.asyncIterator,function(){return this}),za(Bp,"return",function(){var t=this;return new Promise(function(r,n){t[Af].destroy(null,function(i){if(i){n(i);return}r(Xa(void 0,!0))})})}),Bp),Hre),Gre=function(t){var r,n=Object.create(qre,(r={},za(r,Af,{value:t,writable:!0}),za(r,Ka,{value:null,writable:!0}),za(r,of,{value:null,writable:!0}),za(r,ph,{value:null,writable:!0}),za(r,Ip,{value:t._readableState.endEmitted,writable:!0}),za(r,vb,{value:function(s,o){var a=n[Af].read();a?(n[af]=null,n[Ka]=null,n[of]=null,s(Xa(a,!1))):(n[Ka]=s,n[of]=o)},writable:!0}),r));return n[af]=null,xre(t,function(i){if(i&&i.code!=="ERR_STREAM_PREMATURE_CLOSE"){var s=n[of];s!==null&&(n[af]=null,n[Ka]=null,n[of]=null,s(i)),n[ph]=i;return}var o=n[Ka];o!==null&&(n[af]=null,n[Ka]=null,n[of]=null,o(Xa(void 0,!0))),n[Ip]=!0}),t.on("readable",Pre.bind(null,n)),n};eF.exports=Gre});var nF=U((WRe,rF)=>{rF.exports=function(){throw new Error("Readable.from is not available in the browser")}});var Qb=U((JRe,hF)=>{"use strict";hF.exports=Ct;var sc;Ct.ReadableState=aF;var VRe=Zi().EventEmitter,oF=function(t,r){return t.listeners(r).length},yh=FI(),bp=Gr().Buffer,Yre=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function Wre(e){return bp.from(e)}function Vre(e){return bp.isBuffer(e)||e instanceof Yre}var Rb=Yr(),dt;Rb&&Rb.debuglog?dt=Rb.debuglog("stream"):dt=function(){};var Jre=TM(),Ub=gb(),jre=pb(),zre=jre.getHighWaterMark,Cp=tf().codes,Kre=Cp.ERR_INVALID_ARG_TYPE,Xre=Cp.ERR_STREAM_PUSH_AFTER_EOF,Zre=Cp.ERR_METHOD_NOT_IMPLEMENTED,$re=Cp.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,oc,Db,Tb;je()(Ct,yh);var Eh=Ub.errorOrDestroy,Nb=["error","close","destroy","pause","resume"];function ene(e,t,r){if(typeof e.prependListener=="function")return e.prependListener(t,r);!e._events||!e._events[t]?e.on(t,r):Array.isArray(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]}function aF(e,t,r){sc=sc||rf(),e=e||{},typeof r!="boolean"&&(r=t instanceof sc),this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.readableObjectMode),this.highWaterMark=zre(this,e,"readableHighWaterMark",r),this.buffer=new Jre,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(oc||(oc=sf().StringDecoder),this.decoder=new oc(e.encoding),this.encoding=e.encoding)}function Ct(e){if(sc=sc||rf(),!(this instanceof Ct))return new Ct(e);var t=this instanceof sc;this._readableState=new aF(e,this,t),this.readable=!0,e&&(typeof e.read=="function"&&(this._read=e.read),typeof e.destroy=="function"&&(this._destroy=e.destroy)),yh.call(this)}Object.defineProperty(Ct.prototype,"destroyed",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(t){this._readableState&&(this._readableState.destroyed=t)}});Ct.prototype.destroy=Ub.destroy;Ct.prototype._undestroy=Ub.undestroy;Ct.prototype._destroy=function(e,t){t(e)};Ct.prototype.push=function(e,t){var r=this._readableState,n;return r.objectMode?n=!0:typeof e=="string"&&(t=t||r.defaultEncoding,t!==r.encoding&&(e=bp.from(e,t),t=""),n=!0),AF(this,e,t,!1,n)};Ct.prototype.unshift=function(e){return AF(this,e,null,!0,!1)};function AF(e,t,r,n,i){dt("readableAddChunk",t);var s=e._readableState;if(t===null)s.reading=!1,nne(e,s);else{var o;if(i||(o=tne(s,t)),o)Eh(e,o);else if(s.objectMode||t&&t.length>0)if(typeof t!="string"&&!s.objectMode&&Object.getPrototypeOf(t)!==bp.prototype&&(t=Wre(t)),n)s.endEmitted?Eh(e,new $re):Mb(e,s,t,!0);else if(s.ended)Eh(e,new Xre);else{if(s.destroyed)return!1;s.reading=!1,s.decoder&&!r?(t=s.decoder.write(t),s.objectMode||t.length!==0?Mb(e,s,t,!1):kb(e,s)):Mb(e,s,t,!1)}else n||(s.reading=!1,kb(e,s))}return!s.ended&&(s.length=iF?e=iF:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function sF(e,t){return e<=0||t.length===0&&t.ended?0:t.objectMode?1:e!==e?t.flowing&&t.length?t.buffer.head.data.length:t.length:(e>t.highWaterMark&&(t.highWaterMark=rne(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}Ct.prototype.read=function(e){dt("read",e),e=parseInt(e,10);var t=this._readableState,r=e;if(e!==0&&(t.emittedReadable=!1),e===0&&t.needReadable&&((t.highWaterMark!==0?t.length>=t.highWaterMark:t.length>0)||t.ended))return dt("read: emitReadable",t.length,t.ended),t.length===0&&t.ended?Fb(this):Qp(this),null;if(e=sF(e,t),e===0&&t.ended)return t.length===0&&Fb(this),null;var n=t.needReadable;dt("need readable",n),(t.length===0||t.length-e0?i=cF(e,t):i=null,i===null?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.awaitDrain=0),t.length===0&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&Fb(this)),i!==null&&this.emit("data",i),i};function nne(e,t){if(dt("onEofChunk"),!t.ended){if(t.decoder){var r=t.decoder.end();r&&r.length&&(t.buffer.push(r),t.length+=t.objectMode?1:r.length)}t.ended=!0,t.sync?Qp(e):(t.needReadable=!1,t.emittedReadable||(t.emittedReadable=!0,fF(e)))}}function Qp(e){var t=e._readableState;dt("emitReadable",t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(dt("emitReadable",t.flowing),t.emittedReadable=!0,process.nextTick(fF,e))}function fF(e){var t=e._readableState;dt("emitReadable_",t.destroyed,t.length,t.ended),!t.destroyed&&(t.length||t.ended)&&(e.emit("readable"),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,xb(e)}function kb(e,t){t.readingMore||(t.readingMore=!0,process.nextTick(ine,e,t))}function ine(e,t){for(;!t.reading&&!t.ended&&(t.length1&&lF(n.pipes,e)!==-1)&&!f&&(dt("false write response, pause",n.awaitDrain),n.awaitDrain++),r.pause())}function I(O){dt("onerror",O),N(),e.removeListener("error",I),oF(e,"error")===0&&Eh(e,O)}ene(e,"error",I);function S(){e.removeListener("finish",_),N()}e.once("close",S);function _(){dt("onfinish"),e.removeListener("close",S),N()}e.once("finish",_);function N(){dt("unpipe"),r.unpipe(e)}return e.emit("pipe",r),n.flowing||(dt("pipe resume"),r.resume()),e};function sne(e){return function(){var r=e._readableState;dt("pipeOnDrain",r.awaitDrain),r.awaitDrain&&r.awaitDrain--,r.awaitDrain===0&&oF(e,"data")&&(r.flowing=!0,xb(e))}}Ct.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(t.pipesCount===0)return this;if(t.pipesCount===1)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r),this);if(!e){var n=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var s=0;s0,n.flowing!==!1&&this.resume()):e==="readable"&&!n.endEmitted&&!n.readableListening&&(n.readableListening=n.needReadable=!0,n.flowing=!1,n.emittedReadable=!1,dt("on readable",n.length,n.reading),n.length?Qp(this):n.reading||process.nextTick(one,this)),r};Ct.prototype.addListener=Ct.prototype.on;Ct.prototype.removeListener=function(e,t){var r=yh.prototype.removeListener.call(this,e,t);return e==="readable"&&process.nextTick(uF,this),r};Ct.prototype.removeAllListeners=function(e){var t=yh.prototype.removeAllListeners.apply(this,arguments);return(e==="readable"||e===void 0)&&process.nextTick(uF,this),t};function uF(e){var t=e._readableState;t.readableListening=e.listenerCount("readable")>0,t.resumeScheduled&&!t.paused?t.flowing=!0:e.listenerCount("data")>0&&e.resume()}function one(e){dt("readable nexttick read 0"),e.read(0)}Ct.prototype.resume=function(){var e=this._readableState;return e.flowing||(dt("resume"),e.flowing=!e.readableListening,ane(this,e)),e.paused=!1,this};function ane(e,t){t.resumeScheduled||(t.resumeScheduled=!0,process.nextTick(Ane,e,t))}function Ane(e,t){dt("resume",t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit("resume"),xb(e),t.flowing&&!t.reading&&e.read(0)}Ct.prototype.pause=function(){return dt("call pause flowing=%j",this._readableState.flowing),this._readableState.flowing!==!1&&(dt("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this};function xb(e){var t=e._readableState;for(dt("flow",t.flowing);t.flowing&&e.read()!==null;);}Ct.prototype.wrap=function(e){var t=this,r=this._readableState,n=!1;e.on("end",function(){if(dt("wrapped end"),r.decoder&&!r.ended){var o=r.decoder.end();o&&o.length&&t.push(o)}t.push(null)}),e.on("data",function(o){if(dt("wrapped data"),r.decoder&&(o=r.decoder.write(o)),!(r.objectMode&&o==null)&&!(!r.objectMode&&(!o||!o.length))){var a=t.push(o);a||(n=!0,e.pause())}});for(var i in e)this[i]===void 0&&typeof e[i]=="function"&&(this[i]=(function(a){return function(){return e[a].apply(e,arguments)}})(i));for(var s=0;s=t.length?(t.decoder?r=t.buffer.join(""):t.buffer.length===1?r=t.buffer.first():r=t.buffer.concat(t.length),t.buffer.clear()):r=t.buffer.consume(e,t.decoder),r}function Fb(e){var t=e._readableState;dt("endReadable",t.endEmitted),t.endEmitted||(t.ended=!0,process.nextTick(fne,t,e))}function fne(e,t){if(dt("endReadableNT",e.endEmitted,e.length),!e.endEmitted&&e.length===0&&(e.endEmitted=!0,t.readable=!1,t.emit("end"),e.autoDestroy)){var r=t._writableState;(!r||r.autoDestroy&&r.finished)&&t.destroy()}}typeof Symbol=="function"&&(Ct.from=function(e,t){return Tb===void 0&&(Tb=nF()),Tb(Ct,e,t)});function lF(e,t){for(var r=0,n=e.length;r{"use strict";gF.exports=Wo;var wp=tf().codes,une=wp.ERR_METHOD_NOT_IMPLEMENTED,cne=wp.ERR_MULTIPLE_CALLBACK,lne=wp.ERR_TRANSFORM_ALREADY_TRANSFORMING,hne=wp.ERR_TRANSFORM_WITH_LENGTH_0,Sp=rf();je()(Wo,Sp);function dne(e,t){var r=this._transformState;r.transforming=!1;var n=r.writecb;if(n===null)return this.emit("error",new cne);r.writechunk=null,r.writecb=null,t!=null&&this.push(t),n(e);var i=this._readableState;i.reading=!1,(i.needReadable||i.length{"use strict";EF.exports=mh;var pF=Lb();je()(mh,pF);function mh(e){if(!(this instanceof mh))return new mh(e);pF.call(this,e)}mh.prototype._transform=function(e,t,r){r(null,e)}});var CF=U((KRe,bF)=>{"use strict";var Pb;function pne(e){var t=!1;return function(){t||(t=!0,e.apply(void 0,arguments))}}var IF=tf().codes,Ene=IF.ERR_MISSING_ARGS,yne=IF.ERR_STREAM_DESTROYED;function mF(e){if(e)throw e}function mne(e){return e.setHeader&&typeof e.abort=="function"}function Bne(e,t,r,n){n=pne(n);var i=!1;e.on("close",function(){i=!0}),Pb===void 0&&(Pb=mp()),Pb(e,{readable:t,writable:r},function(o){if(o)return n(o);i=!0,n()});var s=!1;return function(o){if(!i&&!s){if(s=!0,mne(e))return e.abort();if(typeof e.destroy=="function")return e.destroy();n(o||new yne("pipe"))}}}function BF(e){e()}function Ine(e,t){return e.pipe(t)}function bne(e){return!e.length||typeof e[e.length-1]!="function"?mF:e.pop()}function Cne(){for(var e=arguments.length,t=new Array(e),r=0;r0;return Bne(o,A,f,function(l){i||(i=l),l&&s.forEach(BF),!A&&(s.forEach(BF),n(i))})});return t.reduce(Ine)}bF.exports=Cne});var Hb=U((XRe,QF)=>{QF.exports=di;var Ob=Zi().EventEmitter,Qne=je();Qne(di,Ob);di.Readable=Qb();di.Writable=Ib();di.Duplex=rf();di.Transform=Lb();di.PassThrough=yF();di.finished=mp();di.pipeline=CF();di.Stream=di;function di(){Ob.call(this)}di.prototype.pipe=function(e,t){var r=this;function n(l){e.writable&&e.write(l)===!1&&r.pause&&r.pause()}r.on("data",n);function i(){r.readable&&r.resume&&r.resume()}e.on("drain",i),!e._isStdio&&(!t||t.end!==!1)&&(r.on("end",o),r.on("close",a));var s=!1;function o(){s||(s=!0,e.end())}function a(){s||(s=!0,typeof e.destroy=="function"&&e.destroy())}function A(l){if(f(),Ob.listenerCount(this,"error")===0)throw l}r.on("error",A),e.on("error",A);function f(){r.removeListener("data",n),e.removeListener("drain",i),r.removeListener("end",o),r.removeListener("close",a),r.removeListener("error",A),e.removeListener("error",A),r.removeListener("end",f),r.removeListener("close",f),e.removeListener("close",f)}return r.on("end",f),r.on("close",f),e.on("close",f),e.emit("pipe",r),e}});var qt={};EI(qt,{default:()=>Sne,finished:()=>_F,isDisturbed:()=>DF,isErrored:()=>RF,isReadable:()=>vF});var ac,SF,wF,_p,qb,wne,_F,vF,RF,DF,Sne,ts=uD(()=>{"use strict";ac=hr(Hb());_n(qt,hr(Hb()));SF=ac.default??ac.default??{},wF=ac.finished??SF.finished,_p=e=>!!e&&typeof e.getReader=="function"&&typeof e.cancel=="function",qb=e=>!!e&&typeof e.getWriter=="function"&&typeof e.abort=="function",wne=e=>e instanceof Error?e:e==null?new Error("stream errored"):new Error(String(e)),_F=(e,t,r)=>{let n=t,i=r;if(typeof n=="function"&&(i=n,n={}),!_p(e)&&!qb(e)&&typeof wF=="function")return wF(e,n,i);let s=typeof i=="function"?i:()=>{},o=n?.readable!==!1,a=n?.writable!==!1,A=!1,f=null,l=()=>{A=!0,f!==null&&(clearTimeout(f),f=null)},p=(S=void 0)=>{A||(l(),queueMicrotask(()=>s(S)))},I=()=>{if(A)return;let S=e?._state;if(S==="errored"){p(wne(e?._storedError));return}if(S==="closed"||_p(e)&&!o||qb(e)&&!a){p();return}f=setTimeout(I,0)};return I(),l},vF=e=>_p(e)?e._state==="readable":!!e&&e.readable!==!1&&e.destroyed!==!0,RF=e=>_p(e)||qb(e)?e?._state==="errored":e?.errored!=null,DF=e=>!!(e?.locked||e?.disturbed===!0||e?._disturbed===!0||e?.readableDidRead===!0),Sne={...SF,finished:_F,isReadable:vF,isErrored:RF,isDisturbed:DF}});var TF=U(()=>{});var Qh=U((tDe,XF)=>{var Zb=typeof Map=="function"&&Map.prototype,Gb=Object.getOwnPropertyDescriptor&&Zb?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,Rp=Zb&&Gb&&typeof Gb.get=="function"?Gb.get:null,NF=Zb&&Map.prototype.forEach,$b=typeof Set=="function"&&Set.prototype,Yb=Object.getOwnPropertyDescriptor&&$b?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,Dp=$b&&Yb&&typeof Yb.get=="function"?Yb.get:null,MF=$b&&Set.prototype.forEach,_ne=typeof WeakMap=="function"&&WeakMap.prototype,Ih=_ne?WeakMap.prototype.has:null,vne=typeof WeakSet=="function"&&WeakSet.prototype,bh=vne?WeakSet.prototype.has:null,Rne=typeof WeakRef=="function"&&WeakRef.prototype,FF=Rne?WeakRef.prototype.deref:null,Dne=Boolean.prototype.valueOf,Tne=Object.prototype.toString,Nne=Function.prototype.toString,Mne=String.prototype.match,eC=String.prototype.slice,Za=String.prototype.replace,Fne=String.prototype.toUpperCase,kF=String.prototype.toLowerCase,YF=RegExp.prototype.test,UF=Array.prototype.concat,Js=Array.prototype.join,kne=Array.prototype.slice,xF=Math.floor,Jb=typeof BigInt=="function"?BigInt.prototype.valueOf:null,Wb=Object.getOwnPropertySymbols,jb=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Symbol.prototype.toString:null,Ac=typeof Symbol=="function"&&typeof Symbol.iterator=="object",Ch=typeof Symbol=="function"&&Symbol.toStringTag&&(typeof Symbol.toStringTag===Ac||!0)?Symbol.toStringTag:null,WF=Object.prototype.propertyIsEnumerable,LF=(typeof Reflect=="function"?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(e){return e.__proto__}:null);function PF(e,t){if(e===1/0||e===-1/0||e!==e||e&&e>-1e3&&e<1e3||YF.call(/e/,t))return t;var r=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if(typeof e=="number"){var n=e<0?-xF(-e):xF(e);if(n!==e){var i=String(n),s=eC.call(t,i.length+1);return Za.call(i,r,"$&_")+"."+Za.call(Za.call(s,/([0-9]{3})/g,"$&_"),/_$/,"")}}return Za.call(t,r,"$&_")}var zb=TF(),OF=zb.custom,HF=jF(OF)?OF:null,VF={__proto__:null,double:'"',single:"'"},Une={__proto__:null,double:/(["\\])/g,single:/(['\\])/g};XF.exports=function e(t,r,n,i){var s=r||{};if(Vo(s,"quoteStyle")&&!Vo(VF,s.quoteStyle))throw new TypeError('option "quoteStyle" must be "single" or "double"');if(Vo(s,"maxStringLength")&&(typeof s.maxStringLength=="number"?s.maxStringLength<0&&s.maxStringLength!==1/0:s.maxStringLength!==null))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var o=Vo(s,"customInspect")?s.customInspect:!0;if(typeof o!="boolean"&&o!=="symbol")throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(Vo(s,"indent")&&s.indent!==null&&s.indent!==" "&&!(parseInt(s.indent,10)===s.indent&&s.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(Vo(s,"numericSeparator")&&typeof s.numericSeparator!="boolean")throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var a=s.numericSeparator;if(typeof t>"u")return"undefined";if(t===null)return"null";if(typeof t=="boolean")return t?"true":"false";if(typeof t=="string")return KF(t,s);if(typeof t=="number"){if(t===0)return 1/0/t>0?"0":"-0";var A=String(t);return a?PF(t,A):A}if(typeof t=="bigint"){var f=String(t)+"n";return a?PF(t,f):f}var l=typeof s.depth>"u"?5:s.depth;if(typeof n>"u"&&(n=0),n>=l&&l>0&&typeof t=="object")return Kb(t)?"[Array]":"[Object]";var p=eie(s,n);if(typeof i>"u")i=[];else if(zF(i,t)>=0)return"[Circular]";function I(b,c,g){if(c&&(i=kne.call(i),i.push(c)),g){var w={depth:s.depth};return Vo(s,"quoteStyle")&&(w.quoteStyle=s.quoteStyle),e(b,w,n+1,i)}return e(b,s,n+1,i)}if(typeof t=="function"&&!qF(t)){var S=Wne(t),_=vp(t,I);return"[Function"+(S?": "+S:" (anonymous)")+"]"+(_.length>0?" { "+Js.call(_,", ")+" }":"")}if(jF(t)){var N=Ac?Za.call(String(t),/^(Symbol\(.*\))_[^)]*$/,"$1"):jb.call(t);return typeof t=="object"&&!Ac?Bh(N):N}if(Xne(t)){for(var O="<"+kF.call(String(t.nodeName)),x=t.attributes||[],G=0;G",O}if(Kb(t)){if(t.length===0)return"[]";var Y=vp(t,I);return p&&!$ne(Y)?"["+Xb(Y,p)+"]":"[ "+Js.call(Y,", ")+" ]"}if(Pne(t)){var X=vp(t,I);return!("cause"in Error.prototype)&&"cause"in t&&!WF.call(t,"cause")?"{ ["+String(t)+"] "+Js.call(UF.call("[cause]: "+I(t.cause),X),", ")+" }":X.length===0?"["+String(t)+"]":"{ ["+String(t)+"] "+Js.call(X,", ")+" }"}if(typeof t=="object"&&o){if(HF&&typeof t[HF]=="function"&&zb)return zb(t,{depth:l-n});if(o!=="symbol"&&typeof t.inspect=="function")return t.inspect()}if(Vne(t)){var Z=[];return NF&&NF.call(t,function(b,c){Z.push(I(c,t,!0)+" => "+I(b,t))}),GF("Map",Rp.call(t),Z,p)}if(zne(t)){var j=[];return MF&&MF.call(t,function(b){j.push(I(b,t))}),GF("Set",Dp.call(t),j,p)}if(Jne(t))return Vb("WeakMap");if(Kne(t))return Vb("WeakSet");if(jne(t))return Vb("WeakRef");if(Hne(t))return Bh(I(Number(t)));if(Gne(t))return Bh(I(Jb.call(t)));if(qne(t))return Bh(Dne.call(t));if(One(t))return Bh(I(String(t)));if(typeof window<"u"&&t===window)return"{ [object Window] }";if(typeof globalThis<"u"&&t===globalThis||typeof globalThis<"u"&&t===globalThis)return"{ [object globalThis] }";if(!Lne(t)&&!qF(t)){var se=vp(t,I),ie=LF?LF(t)===Object.prototype:t instanceof Object||t.constructor===Object,ce=t instanceof Object?"":"null prototype",H=!ie&&Ch&&Object(t)===t&&Ch in t?eC.call($a(t),8,-1):ce?"Object":"",E=ie||typeof t.constructor!="function"?"":t.constructor.name?t.constructor.name+" ":"",v=E+(H||ce?"["+Js.call(UF.call([],H||[],ce||[]),": ")+"] ":"");return se.length===0?v+"{}":p?v+"{"+Xb(se,p)+"}":v+"{ "+Js.call(se,", ")+" }"}return String(t)};function JF(e,t,r){var n=r.quoteStyle||t,i=VF[n];return i+e+i}function xne(e){return Za.call(String(e),/"/g,""")}function ff(e){return!Ch||!(typeof e=="object"&&(Ch in e||typeof e[Ch]<"u"))}function Kb(e){return $a(e)==="[object Array]"&&ff(e)}function Lne(e){return $a(e)==="[object Date]"&&ff(e)}function qF(e){return $a(e)==="[object RegExp]"&&ff(e)}function Pne(e){return $a(e)==="[object Error]"&&ff(e)}function One(e){return $a(e)==="[object String]"&&ff(e)}function Hne(e){return $a(e)==="[object Number]"&&ff(e)}function qne(e){return $a(e)==="[object Boolean]"&&ff(e)}function jF(e){if(Ac)return e&&typeof e=="object"&&e instanceof Symbol;if(typeof e=="symbol")return!0;if(!e||typeof e!="object"||!jb)return!1;try{return jb.call(e),!0}catch{}return!1}function Gne(e){if(!e||typeof e!="object"||!Jb)return!1;try{return Jb.call(e),!0}catch{}return!1}var Yne=Object.prototype.hasOwnProperty||function(e){return e in this};function Vo(e,t){return Yne.call(e,t)}function $a(e){return Tne.call(e)}function Wne(e){if(e.name)return e.name;var t=Mne.call(Nne.call(e),/^function\s*([\w$]+)/);return t?t[1]:null}function zF(e,t){if(e.indexOf)return e.indexOf(t);for(var r=0,n=e.length;rt.maxStringLength){var r=e.length-t.maxStringLength,n="... "+r+" more character"+(r>1?"s":"");return KF(eC.call(e,0,t.maxStringLength),t)+n}var i=Une[t.quoteStyle||"single"];i.lastIndex=0;var s=Za.call(Za.call(e,i,"\\$1"),/[\x00-\x1f]/g,Zne);return JF(s,"single",t)}function Zne(e){var t=e.charCodeAt(0),r={8:"b",9:"t",10:"n",12:"f",13:"r"}[t];return r?"\\"+r:"\\x"+(t<16?"0":"")+Fne.call(t.toString(16))}function Bh(e){return"Object("+e+")"}function Vb(e){return e+" { ? }"}function GF(e,t,r,n){var i=n?Xb(r,n):Js.call(r,", ");return e+" ("+t+") {"+i+"}"}function $ne(e){for(var t=0;t=0)return!1;return!0}function eie(e,t){var r;if(e.indent===" ")r=" ";else if(typeof e.indent=="number"&&e.indent>0)r=Js.call(Array(e.indent+1)," ");else return null;return{base:r,prev:Js.call(Array(t+1),r)}}function Xb(e,t){if(e.length===0)return"";var r=` -`+t.prev+t.base;return r+Js.call(e,","+r)+` -`+t.prev}function vp(e,t){var r=Kb(e),n=[];if(r){n.length=e.length;for(var i=0;i{"use strict";var tie=Qh(),rie=$i(),Tp=function(e,t,r){for(var n=e,i;(i=n.next)!=null;n=i)if(i.key===t)return n.next=i.next,r||(i.next=e.next,e.next=i),i},nie=function(e,t){if(e){var r=Tp(e,t);return r&&r.value}},iie=function(e,t,r){var n=Tp(e,t);n?n.value=r:e.next={key:t,next:e.next,value:r}},sie=function(e,t){return e?!!Tp(e,t):!1},oie=function(e,t){if(e)return Tp(e,t,!0)};ZF.exports=function(){var t,r={assert:function(n){if(!r.has(n))throw new rie("Side channel does not contain "+tie(n))},delete:function(n){var i=t&&t.next,s=oie(t,n);return s&&i&&i===s&&(t=void 0),!!s},get:function(n){return nie(t,n)},has:function(n){return sie(t,n)},set:function(n,i){t||(t={next:void 0}),iie(t,n,i)}};return r}});var tC=U((nDe,t4)=>{"use strict";var aie=Zu(),wh=Ys(),Aie=Qh(),fie=$i(),e4=aie("%Map%",!0),uie=wh("Map.prototype.get",!0),cie=wh("Map.prototype.set",!0),lie=wh("Map.prototype.has",!0),hie=wh("Map.prototype.delete",!0),die=wh("Map.prototype.size",!0);t4.exports=!!e4&&function(){var t,r={assert:function(n){if(!r.has(n))throw new fie("Side channel does not contain "+Aie(n))},delete:function(n){if(t){var i=hie(t,n);return die(t)===0&&(t=void 0),i}return!1},get:function(n){if(t)return uie(t,n)},has:function(n){return t?lie(t,n):!1},set:function(n,i){t||(t=new e4),cie(t,n,i)}};return r}});var n4=U((iDe,r4)=>{"use strict";var gie=Zu(),Mp=Ys(),pie=Qh(),Np=tC(),Eie=$i(),fc=gie("%WeakMap%",!0),yie=Mp("WeakMap.prototype.get",!0),mie=Mp("WeakMap.prototype.set",!0),Bie=Mp("WeakMap.prototype.has",!0),Iie=Mp("WeakMap.prototype.delete",!0);r4.exports=fc?function(){var t,r,n={assert:function(i){if(!n.has(i))throw new Eie("Side channel does not contain "+pie(i))},delete:function(i){if(fc&&i&&(typeof i=="object"||typeof i=="function")){if(t)return Iie(t,i)}else if(Np&&r)return r.delete(i);return!1},get:function(i){return fc&&i&&(typeof i=="object"||typeof i=="function")&&t?yie(t,i):r&&r.get(i)},has:function(i){return fc&&i&&(typeof i=="object"||typeof i=="function")&&t?Bie(t,i):!!r&&r.has(i)},set:function(i,s){fc&&i&&(typeof i=="object"||typeof i=="function")?(t||(t=new fc),mie(t,i,s)):Np&&(r||(r=Np()),r.set(i,s))}};return n}:Np});var rC=U((sDe,i4)=>{"use strict";var bie=$i(),Cie=Qh(),Qie=$F(),wie=tC(),Sie=n4(),_ie=Sie||wie||Qie;i4.exports=function(){var t,r={assert:function(n){if(!r.has(n))throw new bie("Side channel does not contain "+Cie(n))},delete:function(n){return!!t&&t.delete(n)},get:function(n){return t&&t.get(n)},has:function(n){return!!t&&t.has(n)},set:function(n,i){t||(t=_ie()),t.set(n,i)}};return r}});var Fp=U((oDe,s4)=>{"use strict";var vie=String.prototype.replace,Rie=/%20/g,nC={RFC1738:"RFC1738",RFC3986:"RFC3986"};s4.exports={default:nC.RFC3986,formatters:{RFC1738:function(e){return vie.call(e,Rie,"+")},RFC3986:function(e){return String(e)}},RFC1738:nC.RFC1738,RFC3986:nC.RFC3986}});var aC=U((aDe,o4)=>{"use strict";var Die=Fp(),Tie=rC(),iC=Object.prototype.hasOwnProperty,uf=Array.isArray,kp=Tie(),uc=function(t,r){return kp.set(t,r),t},cf=function(t){return kp.has(t)},Sh=function(t){return kp.get(t)},oC=function(t,r){kp.set(t,r)},js=(function(){for(var e=[],t=0;t<256;++t)e[e.length]="%"+((t<16?"0":"")+t.toString(16)).toUpperCase();return e})(),Nie=function(t){for(;t.length>1;){var r=t.pop(),n=r.obj[r.prop];if(uf(n)){for(var i=[],s=0;sn.arrayLimit)return uc(_h(t.concat(r),n),i);t[i]=r}else if(t&&typeof t=="object")if(cf(t)){var s=Sh(t)+1;t[s]=r,oC(t,s)}else{if(n&&n.strictMerge)return[t,r];(n&&(n.plainObjects||n.allowPrototypes)||!iC.call(Object.prototype,r))&&(t[r]=!0)}else return[t,r];return t}if(!t||typeof t!="object"){if(cf(r)){for(var o=Object.keys(r),a=n&&n.plainObjects?{__proto__:null,0:t}:{0:t},A=0;An.arrayLimit?uc(_h(l,n),l.length-1):l}var p=t;return uf(t)&&!uf(r)&&(p=_h(t,n)),uf(t)&&uf(r)?(r.forEach(function(I,S){if(iC.call(t,S)){var _=t[S];_&&typeof _=="object"&&I&&typeof I=="object"?t[S]=e(_,I,n):t[t.length]=I}else t[S]=I}),t):Object.keys(r).reduce(function(I,S){var _=r[S];if(iC.call(I,S)?I[S]=e(I[S],_,n):I[S]=_,cf(r)&&!cf(I)&&uc(I,Sh(r)),cf(I)){var N=parseInt(S,10);String(N)===S&&N>=0&&N>Sh(I)&&oC(I,N)}return I},p)},Fie=function(t,r){return Object.keys(r).reduce(function(n,i){return n[i]=r[i],n},t)},kie=function(e,t,r){var n=e.replace(/\+/g," ");if(r==="iso-8859-1")return n.replace(/%[0-9a-f]{2}/gi,unescape);try{return decodeURIComponent(n)}catch{return n}},sC=1024,Uie=function(t,r,n,i,s){if(t.length===0)return t;var o=t;if(typeof t=="symbol"?o=Symbol.prototype.toString.call(t):typeof t!="string"&&(o=String(t)),n==="iso-8859-1")return escape(o).replace(/%u[0-9a-f]{4}/gi,function(S){return"%26%23"+parseInt(S.slice(2),16)+"%3B"});for(var a="",A=0;A=sC?o.slice(A,A+sC):o,l=[],p=0;p=48&&I<=57||I>=65&&I<=90||I>=97&&I<=122||s===Die.RFC1738&&(I===40||I===41)){l[l.length]=f.charAt(p);continue}if(I<128){l[l.length]=js[I];continue}if(I<2048){l[l.length]=js[192|I>>6]+js[128|I&63];continue}if(I<55296||I>=57344){l[l.length]=js[224|I>>12]+js[128|I>>6&63]+js[128|I&63];continue}p+=1,I=65536+((I&1023)<<10|f.charCodeAt(p)&1023),l[l.length]=js[240|I>>18]+js[128|I>>12&63]+js[128|I>>6&63]+js[128|I&63]}a+=l.join("")}return a},xie=function(t){for(var r=[{obj:{o:t},prop:"o"}],n=[],i=0;in?uc(_h(o,{plainObjects:i}),o.length-1):o},Hie=function(t,r){if(uf(t)){for(var n=[],i=0;i{"use strict";var A4=rC(),Up=aC(),vh=Fp(),qie=Object.prototype.hasOwnProperty,f4={brackets:function(t){return t+"[]"},comma:"comma",indices:function(t,r){return t+"["+r+"]"},repeat:function(t){return t}},zs=Array.isArray,Gie=Array.prototype.push,u4=function(e,t){Gie.apply(e,zs(t)?t:[t])},Yie=Date.prototype.toISOString,a4=vh.default,Sr={addQueryPrefix:!1,allowDots:!1,allowEmptyArrays:!1,arrayFormat:"indices",charset:"utf-8",charsetSentinel:!1,commaRoundTrip:!1,delimiter:"&",encode:!0,encodeDotInKeys:!1,encoder:Up.encode,encodeValuesOnly:!1,filter:void 0,format:a4,formatter:vh.formatters[a4],indices:!1,serializeDate:function(t){return Yie.call(t)},skipNulls:!1,strictNullHandling:!1},Wie=function(t){return typeof t=="string"||typeof t=="number"||typeof t=="boolean"||typeof t=="symbol"||typeof t=="bigint"},AC={},Vie=function e(t,r,n,i,s,o,a,A,f,l,p,I,S,_,N,O,x,G){for(var Y=t,X=G,Z=0,j=!1;(X=X.get(AC))!==void 0&&!j;){var se=X.get(t);if(Z+=1,typeof se<"u"){if(se===Z)throw new RangeError("Cyclic object value");j=!0}typeof X.get(AC)>"u"&&(Z=0)}if(typeof l=="function"?Y=l(r,Y):Y instanceof Date?Y=S(Y):n==="comma"&&zs(Y)&&(Y=Up.maybeMap(Y,function(D){return D instanceof Date?S(D):D})),Y===null){if(o)return f&&!O?f(r,Sr.encoder,x,"key",_):r;Y=""}if(Wie(Y)||Up.isBuffer(Y)){if(f){var ie=O?r:f(r,Sr.encoder,x,"key",_);return[N(ie)+"="+N(f(Y,Sr.encoder,x,"value",_))]}return[N(r)+"="+N(String(Y))]}var ce=[];if(typeof Y>"u")return ce;var H;if(n==="comma"&&zs(Y))O&&f&&(Y=Up.maybeMap(Y,f)),H=[{value:Y.length>0?Y.join(",")||null:void 0}];else if(zs(l))H=l;else{var E=Object.keys(Y);H=p?E.sort(p):E}var v=A?String(r).replace(/\./g,"%2E"):String(r),b=i&&zs(Y)&&Y.length===1?v+"[]":v;if(s&&zs(Y)&&Y.length===0)return b+"[]";for(var c=0;c"u"?t.encodeDotInKeys===!0?!0:Sr.allowDots:!!t.allowDots;return{addQueryPrefix:typeof t.addQueryPrefix=="boolean"?t.addQueryPrefix:Sr.addQueryPrefix,allowDots:a,allowEmptyArrays:typeof t.allowEmptyArrays=="boolean"?!!t.allowEmptyArrays:Sr.allowEmptyArrays,arrayFormat:o,charset:r,charsetSentinel:typeof t.charsetSentinel=="boolean"?t.charsetSentinel:Sr.charsetSentinel,commaRoundTrip:!!t.commaRoundTrip,delimiter:typeof t.delimiter>"u"?Sr.delimiter:t.delimiter,encode:typeof t.encode=="boolean"?t.encode:Sr.encode,encodeDotInKeys:typeof t.encodeDotInKeys=="boolean"?t.encodeDotInKeys:Sr.encodeDotInKeys,encoder:typeof t.encoder=="function"?t.encoder:Sr.encoder,encodeValuesOnly:typeof t.encodeValuesOnly=="boolean"?t.encodeValuesOnly:Sr.encodeValuesOnly,filter:s,format:n,formatter:i,serializeDate:typeof t.serializeDate=="function"?t.serializeDate:Sr.serializeDate,skipNulls:typeof t.skipNulls=="boolean"?t.skipNulls:Sr.skipNulls,sort:typeof t.sort=="function"?t.sort:null,strictNullHandling:typeof t.strictNullHandling=="boolean"?t.strictNullHandling:Sr.strictNullHandling}};c4.exports=function(e,t){var r=e,n=Jie(t),i,s;typeof n.filter=="function"?(s=n.filter,r=s("",r)):zs(n.filter)&&(s=n.filter,i=s);var o=[];if(typeof r!="object"||r===null)return"";var a=f4[n.arrayFormat],A=a==="comma"&&n.commaRoundTrip;i||(i=Object.keys(r)),n.sort&&i.sort(n.sort);for(var f=A4(),l=0;l0?_+S:""}});var g4=U((fDe,d4)=>{"use strict";var Ks=aC(),xp=Object.prototype.hasOwnProperty,fC=Array.isArray,sr={allowDots:!1,allowEmptyArrays:!1,allowPrototypes:!1,allowSparse:!1,arrayLimit:20,charset:"utf-8",charsetSentinel:!1,comma:!1,decodeDotInKeys:!1,decoder:Ks.decode,delimiter:"&",depth:5,duplicates:"combine",ignoreQueryPrefix:!1,interpretNumericEntities:!1,parameterLimit:1e3,parseArrays:!0,plainObjects:!1,strictDepth:!1,strictMerge:!0,strictNullHandling:!1,throwOnLimitExceeded:!1},jie=function(e){return e.replace(/&#(\d+);/g,function(t,r){return String.fromCharCode(parseInt(r,10))})},h4=function(e,t,r){if(e&&typeof e=="string"&&t.comma&&e.indexOf(",")>-1)return e.split(",");if(t.throwOnLimitExceeded&&r>=t.arrayLimit)throw new RangeError("Array limit exceeded. Only "+t.arrayLimit+" element"+(t.arrayLimit===1?"":"s")+" allowed in an array.");return e},zie="utf8=%26%2310003%3B",Kie="utf8=%E2%9C%93",Xie=function(t,r){var n={__proto__:null},i=r.ignoreQueryPrefix?t.replace(/^\?/,""):t;i=i.replace(/%5B/gi,"[").replace(/%5D/gi,"]");var s=r.parameterLimit===1/0?void 0:r.parameterLimit,o=i.split(r.delimiter,r.throwOnLimitExceeded?s+1:s);if(r.throwOnLimitExceeded&&o.length>s)throw new RangeError("Parameter limit exceeded. Only "+s+" parameter"+(s===1?"":"s")+" allowed.");var a=-1,A,f=r.charset;if(r.charsetSentinel)for(A=0;A-1&&(_=fC(_)?[_]:_),r.comma&&fC(_)&&_.length>r.arrayLimit){if(r.throwOnLimitExceeded)throw new RangeError("Array limit exceeded. Only "+r.arrayLimit+" element"+(r.arrayLimit===1?"":"s")+" allowed in an array.");_=Ks.combine([],_,r.arrayLimit,r.plainObjects)}if(S!==null){var N=xp.call(n,S);N&&(r.duplicates==="combine"||l.indexOf("[]=")>-1)?n[S]=Ks.combine(n[S],_,r.arrayLimit,r.plainObjects):(!N||r.duplicates==="last")&&(n[S]=_)}}return n},Zie=function(e,t,r,n){var i=0;if(e.length>0&&e[e.length-1]==="[]"){var s=e.slice(0,-1).join("");i=Array.isArray(t)&&t[s]?t[s].length:0}for(var o=n?t:h4(t,r,i),a=e.length-1;a>=0;--a){var A,f=e[a];if(f==="[]"&&r.parseArrays)Ks.isOverflow(o)?A=o:A=r.allowEmptyArrays&&(o===""||r.strictNullHandling&&o===null)?[]:Ks.combine([],o,r.arrayLimit,r.plainObjects);else{A=r.plainObjects?{__proto__:null}:{};var l=f.charAt(0)==="["&&f.charAt(f.length-1)==="]"?f.slice(1,-1):f,p=r.decodeDotInKeys?l.replace(/%2E/g,"."):l,I=parseInt(p,10),S=!isNaN(I)&&f!==p&&String(I)===p&&I>=0&&r.parseArrays;if(!r.parseArrays&&p==="")A={0:o};else if(S&&I"u"?sr.charset:t.charset,n=typeof t.duplicates>"u"?sr.duplicates:t.duplicates;if(n!=="combine"&&n!=="first"&&n!=="last")throw new TypeError("The duplicates option must be either combine, first, or last");var i=typeof t.allowDots>"u"?t.decodeDotInKeys===!0?!0:sr.allowDots:!!t.allowDots;return{allowDots:i,allowEmptyArrays:typeof t.allowEmptyArrays=="boolean"?!!t.allowEmptyArrays:sr.allowEmptyArrays,allowPrototypes:typeof t.allowPrototypes=="boolean"?t.allowPrototypes:sr.allowPrototypes,allowSparse:typeof t.allowSparse=="boolean"?t.allowSparse:sr.allowSparse,arrayLimit:typeof t.arrayLimit=="number"?t.arrayLimit:sr.arrayLimit,charset:r,charsetSentinel:typeof t.charsetSentinel=="boolean"?t.charsetSentinel:sr.charsetSentinel,comma:typeof t.comma=="boolean"?t.comma:sr.comma,decodeDotInKeys:typeof t.decodeDotInKeys=="boolean"?t.decodeDotInKeys:sr.decodeDotInKeys,decoder:typeof t.decoder=="function"?t.decoder:sr.decoder,delimiter:typeof t.delimiter=="string"||Ks.isRegExp(t.delimiter)?t.delimiter:sr.delimiter,depth:typeof t.depth=="number"||t.depth===!1?+t.depth:sr.depth,duplicates:n,ignoreQueryPrefix:t.ignoreQueryPrefix===!0,interpretNumericEntities:typeof t.interpretNumericEntities=="boolean"?t.interpretNumericEntities:sr.interpretNumericEntities,parameterLimit:typeof t.parameterLimit=="number"?t.parameterLimit:sr.parameterLimit,parseArrays:t.parseArrays!==!1,plainObjects:typeof t.plainObjects=="boolean"?t.plainObjects:sr.plainObjects,strictDepth:typeof t.strictDepth=="boolean"?!!t.strictDepth:sr.strictDepth,strictMerge:typeof t.strictMerge=="boolean"?!!t.strictMerge:sr.strictMerge,strictNullHandling:typeof t.strictNullHandling=="boolean"?t.strictNullHandling:sr.strictNullHandling,throwOnLimitExceeded:typeof t.throwOnLimitExceeded=="boolean"?t.throwOnLimitExceeded:!1}};d4.exports=function(e,t){var r=tse(t);if(e===""||e===null||typeof e>"u")return r.plainObjects?{__proto__:null}:{};for(var n=typeof e=="string"?Xie(e,r):e,i=r.plainObjects?{__proto__:null}:{},s=Object.keys(n),o=0;o{"use strict";var rse=l4(),nse=g4(),ise=Fp();p4.exports={formats:ise,parse:nse,stringify:rse}});var I4=U(lc=>{"use strict";var sse=DI();function gi(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}var ose=/^([a-z0-9.+-]+:)/i,ase=/:[0-9]*$/,Ase=/^(\/\/?(?!\/)[^?\s]*)(\?[^\s]*)?$/,fse=["<",">",'"',"`"," ","\r",` -`," "],use=["{","}","|","\\","^","`"].concat(fse),uC=["'"].concat(use),y4=["%","/","?",";","#"].concat(uC),m4=["/","?","#"],cse=255,B4=/^[+a-z0-9A-Z_-]{0,63}$/,lse=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,hse={javascript:!0,"javascript:":!0},cC={javascript:!0,"javascript:":!0},cc={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},lC=E4();function Rh(e,t,r){if(e&&typeof e=="object"&&e instanceof gi)return e;var n=new gi;return n.parse(e,t,r),n}gi.prototype.parse=function(e,t,r){if(typeof e!="string")throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var n=e.indexOf("?"),i=n!==-1&&n127?Z+="x":Z+=X[j];if(!Z.match(B4)){var ie=G.slice(0,S),ce=G.slice(S+1),H=X.match(lse);H&&(ie.push(H[1]),ce.unshift(H[2])),ce.length&&(a="/"+ce.join(".")+a),this.hostname=ie.join(".");break}}}this.hostname.length>cse?this.hostname="":this.hostname=this.hostname.toLowerCase(),x||(this.hostname=sse.toASCII(this.hostname));var E=this.port?":"+this.port:"",v=this.hostname||"";this.host=v+E,this.href+=this.host,x&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),a[0]!=="/"&&(a="/"+a))}if(!hse[l])for(var S=0,Y=uC.length;S0?r.host.split("@"):!1;Z&&(r.auth=Z.shift(),r.hostname=Z.shift(),r.host=r.hostname)}return r.search=e.search,r.query=e.query,(r.pathname!==null||r.search!==null)&&(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.href=r.format(),r}if(!G.length)return r.pathname=null,r.search?r.path="/"+r.search:r.path=null,r.href=r.format(),r;for(var j=G.slice(-1)[0],se=(r.host||e.host||G.length>1)&&(j==="."||j==="..")||j==="",ie=0,ce=G.length;ce>=0;ce--)j=G[ce],j==="."?G.splice(ce,1):j===".."?(G.splice(ce,1),ie++):ie&&(G.splice(ce,1),ie--);if(!O&&!x)for(;ie--;ie)G.unshift("..");O&&G[0]!==""&&(!G[0]||G[0].charAt(0)!=="/")&&G.unshift(""),se&&G.join("/").substr(-1)!=="/"&&G.push("");var H=G[0]===""||G[0]&&G[0].charAt(0)==="/";if(X){r.hostname=H?"":G.length?G.shift():"",r.host=r.hostname;var Z=r.host&&r.host.indexOf("@")>0?r.host.split("@"):!1;Z&&(r.auth=Z.shift(),r.hostname=Z.shift(),r.host=r.hostname)}return O=O||r.host&&G.length,O&&!H&&G.unshift(""),G.length>0?r.pathname=G.join("/"):(r.pathname=null,r.path=null),(r.pathname!==null||r.search!==null)&&(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.auth=e.auth||r.auth,r.slashes=r.slashes||e.slashes,r.href=r.format(),r};gi.prototype.parseHost=function(){var e=this.host,t=ase.exec(e);t&&(t=t[0],t!==":"&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)};lc.parse=Rh;lc.resolve=gse;lc.resolveObject=pse;lc.format=dse;lc.Url=gi});var C4=U((Lp,b4)=>{(function(e,t){typeof Lp=="object"&&typeof b4<"u"?t(Lp):typeof define=="function"&&define.amd?define(["exports"],t):(e=typeof globalThis<"u"?globalThis:e||self,t(e.WebStreamsPolyfill={}))})(Lp,(function(e){"use strict";function t(){}function r(u){return typeof u=="object"&&u!==null||typeof u=="function"}let n=t;function i(u,d){try{Object.defineProperty(u,"name",{value:d,configurable:!0})}catch{}}let s=Promise,o=Promise.prototype.then,a=Promise.reject.bind(s);function A(u){return new s(u)}function f(u){return A(d=>d(u))}function l(u){return a(u)}function p(u,d,T){return o.call(u,d,T)}function I(u,d,T){p(p(u,d,T),void 0,n)}function S(u,d){I(u,d)}function _(u,d){I(u,void 0,d)}function N(u,d,T){return p(u,d,T)}function O(u){p(u,void 0,n)}let x=u=>{if(typeof queueMicrotask=="function")x=queueMicrotask;else{let d=f(void 0);x=T=>p(d,T)}return x(u)};function G(u,d,T){if(typeof u!="function")throw new TypeError("Argument is not a function");return Function.prototype.apply.call(u,d,T)}function Y(u,d,T){try{return f(G(u,d,T))}catch(P){return l(P)}}let X=16384;class Z{constructor(){this._cursor=0,this._size=0,this._front={_elements:[],_next:void 0},this._back=this._front,this._cursor=0,this._size=0}get length(){return this._size}push(d){let T=this._back,P=T;T._elements.length===X-1&&(P={_elements:[],_next:void 0}),T._elements.push(d),P!==T&&(this._back=P,T._next=P),++this._size}shift(){let d=this._front,T=d,P=this._cursor,J=P+1,te=d._elements,oe=te[P];return J===X&&(T=d._next,J=0),--this._size,this._cursor=J,d!==T&&(this._front=T),te[P]=void 0,oe}forEach(d){let T=this._cursor,P=this._front,J=P._elements;for(;(T!==J.length||P._next!==void 0)&&!(T===J.length&&(P=P._next,J=P._elements,T=0,J.length===0));)d(J[T]),++T}peek(){let d=this._front,T=this._cursor;return d._elements[T]}}let j=Symbol("[[AbortSteps]]"),se=Symbol("[[ErrorSteps]]"),ie=Symbol("[[CancelSteps]]"),ce=Symbol("[[PullSteps]]"),H=Symbol("[[ReleaseSteps]]");function E(u,d){u._ownerReadableStream=d,d._reader=u,d._state==="readable"?g(u):d._state==="closed"?R(u):w(u,d._storedError)}function v(u,d){let T=u._ownerReadableStream;return Ki(T,d)}function b(u){let d=u._ownerReadableStream;d._state==="readable"?C(u,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")):h(u,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")),d._readableStreamController[H](),d._reader=void 0,u._ownerReadableStream=void 0}function c(u){return new TypeError("Cannot "+u+" a stream using a released reader")}function g(u){u._closedPromise=A((d,T)=>{u._closedPromise_resolve=d,u._closedPromise_reject=T})}function w(u,d){g(u),C(u,d)}function R(u){g(u),D(u)}function C(u,d){u._closedPromise_reject!==void 0&&(O(u._closedPromise),u._closedPromise_reject(d),u._closedPromise_resolve=void 0,u._closedPromise_reject=void 0)}function h(u,d){w(u,d)}function D(u){u._closedPromise_resolve!==void 0&&(u._closedPromise_resolve(void 0),u._closedPromise_resolve=void 0,u._closedPromise_reject=void 0)}let M=Number.isFinite||function(u){return typeof u=="number"&&isFinite(u)},B=Math.trunc||function(u){return u<0?Math.ceil(u):Math.floor(u)};function k(u){return typeof u=="object"||typeof u=="function"}function ne(u,d){if(u!==void 0&&!k(u))throw new TypeError(`${d} is not an object.`)}function Ae(u,d){if(typeof u!="function")throw new TypeError(`${d} is not a function.`)}function ue(u){return typeof u=="object"&&u!==null||typeof u=="function"}function pe(u,d){if(!ue(u))throw new TypeError(`${d} is not an object.`)}function he(u,d,T){if(u===void 0)throw new TypeError(`Parameter ${d} is required in '${T}'.`)}function de(u,d,T){if(u===void 0)throw new TypeError(`${d} is required in '${T}'.`)}function Qt(u){return Number(u)}function Ie(u){return u===0?0:u}function be(u){return Ie(B(u))}function yr(u,d){let P=Number.MAX_SAFE_INTEGER,J=Number(u);if(J=Ie(J),!M(J))throw new TypeError(`${d} is not a finite number`);if(J=be(J),J<0||J>P)throw new TypeError(`${d} is outside the accepted range of 0 to ${P}, inclusive`);return!M(J)||J===0?0:J}function Qe(u,d){if(!Ha(u))throw new TypeError(`${d} is not a ReadableStream.`)}function _e(u){return new Te(u)}function Ds(u,d){u._reader._readRequests.push(d)}function Ge(u,d,T){let J=u._reader._readRequests.shift();T?J._closeSteps():J._chunkSteps(d)}function Ue(u){return u._reader._readRequests.length}function Ts(u){let d=u._reader;return!(d===void 0||!De(d))}class Te{constructor(d){if(he(d,1,"ReadableStreamDefaultReader"),Qe(d,"First parameter"),qa(d))throw new TypeError("This stream has already been locked for exclusive reading by another reader");E(this,d),this._readRequests=new Z}get closed(){return De(this)?this._closedPromise:l(ai("closed"))}cancel(d=void 0){return De(this)?this._ownerReadableStream===void 0?l(c("cancel")):v(this,d):l(ai("cancel"))}read(){if(!De(this))return l(ai("read"));if(this._ownerReadableStream===void 0)return l(c("read from"));let d,T,P=A((te,oe)=>{d=te,T=oe});return en(this,{_chunkSteps:te=>d({value:te,done:!1}),_closeSteps:()=>d({value:void 0,done:!0}),_errorSteps:te=>T(te)}),P}releaseLock(){if(!De(this))throw ai("releaseLock");this._ownerReadableStream!==void 0&&ve(this)}}Object.defineProperties(Te.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),i(Te.prototype.cancel,"cancel"),i(Te.prototype.read,"read"),i(Te.prototype.releaseLock,"releaseLock"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Te.prototype,Symbol.toStringTag,{value:"ReadableStreamDefaultReader",configurable:!0});function De(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_readRequests")?!1:u instanceof Te}function en(u,d){let T=u._ownerReadableStream;T._disturbed=!0,T._state==="closed"?d._closeSteps():T._state==="errored"?d._errorSteps(T._storedError):T._readableStreamController[ce](d)}function ve(u){b(u);let d=new TypeError("Reader was released");He(u,d)}function He(u,d){let T=u._readRequests;u._readRequests=new Z,T.forEach(P=>{P._errorSteps(d)})}function ai(u){return new TypeError(`ReadableStreamDefaultReader.prototype.${u} can only be used on a ReadableStreamDefaultReader`)}let Ne=Object.getPrototypeOf(Object.getPrototypeOf(async function*(){}).prototype);class Ve{constructor(d,T){this._ongoingPromise=void 0,this._isFinished=!1,this._reader=d,this._preventCancel=T}next(){let d=()=>this._nextSteps();return this._ongoingPromise=this._ongoingPromise?N(this._ongoingPromise,d,d):d(),this._ongoingPromise}return(d){let T=()=>this._returnSteps(d);return this._ongoingPromise?N(this._ongoingPromise,T,T):T()}_nextSteps(){if(this._isFinished)return Promise.resolve({value:void 0,done:!0});let d=this._reader,T,P,J=A((oe,me)=>{T=oe,P=me});return en(d,{_chunkSteps:oe=>{this._ongoingPromise=void 0,x(()=>T({value:oe,done:!1}))},_closeSteps:()=>{this._ongoingPromise=void 0,this._isFinished=!0,b(d),T({value:void 0,done:!0})},_errorSteps:oe=>{this._ongoingPromise=void 0,this._isFinished=!0,b(d),P(oe)}}),J}_returnSteps(d){if(this._isFinished)return Promise.resolve({value:d,done:!0});this._isFinished=!0;let T=this._reader;if(!this._preventCancel){let P=v(T,d);return b(T),N(P,()=>({value:d,done:!0}))}return b(T),f({value:d,done:!0})}}let F={next(){return Q(this)?this._asyncIteratorImpl.next():l(L("next"))},return(u){return Q(this)?this._asyncIteratorImpl.return(u):l(L("return"))}};Object.setPrototypeOf(F,Ne);function m(u,d){let T=_e(u),P=new Ve(T,d),J=Object.create(F);return J._asyncIteratorImpl=P,J}function Q(u){if(!r(u)||!Object.prototype.hasOwnProperty.call(u,"_asyncIteratorImpl"))return!1;try{return u._asyncIteratorImpl instanceof Ve}catch{return!1}}function L(u){return new TypeError(`ReadableStreamAsyncIterator.${u} can only be used on a ReadableSteamAsyncIterator`)}let W=Number.isNaN||function(u){return u!==u};var z,ae,le;function ye(u){return u.slice()}function bt(u,d,T,P,J){new Uint8Array(u).set(new Uint8Array(T,P,J),d)}let Ee=u=>(typeof u.transfer=="function"?Ee=d=>d.transfer():typeof structuredClone=="function"?Ee=d=>structuredClone(d,{transfer:[d]}):Ee=d=>d,Ee(u)),ge=u=>(typeof u.detached=="boolean"?ge=d=>d.detached:ge=d=>d.byteLength===0,ge(u));function ka(u,d,T){if(u.slice)return u.slice(d,T);let P=T-d,J=new ArrayBuffer(P);return bt(J,0,u,d,P),J}function Je(u,d){let T=u[d];if(T!=null){if(typeof T!="function")throw new TypeError(`${String(d)} is not a function`);return T}}function tt(u){let d={[Symbol.iterator]:()=>u.iterator},T=(async function*(){return yield*d})(),P=T.next;return{iterator:T,nextMethod:P,done:!1}}let Mo=(le=(z=Symbol.asyncIterator)!==null&&z!==void 0?z:(ae=Symbol.for)===null||ae===void 0?void 0:ae.call(Symbol,"Symbol.asyncIterator"))!==null&&le!==void 0?le:"@@asyncIterator";function Ze(u,d="sync",T){if(T===void 0)if(d==="async"){if(T=Je(u,Mo),T===void 0){let te=Je(u,Symbol.iterator),oe=Ze(u,"sync",te);return tt(oe)}}else T=Je(u,Symbol.iterator);if(T===void 0)throw new TypeError("The object is not iterable");let P=G(T,u,[]);if(!r(P))throw new TypeError("The iterator method must return an object");let J=P.next;return{iterator:P,nextMethod:J,done:!1}}function rt(u){let d=G(u.nextMethod,u.iterator,[]);if(!r(d))throw new TypeError("The iterator.next() method must return an object");return d}function HA(u){return!!u.done}function nt(u){return u.value}function it(u){return!(typeof u!="number"||W(u)||u<0)}function Ua(u){let d=ka(u.buffer,u.byteOffset,u.byteOffset+u.byteLength);return new Uint8Array(d)}function ze(u){let d=u._queue.shift();return u._queueTotalSize-=d.size,u._queueTotalSize<0&&(u._queueTotalSize=0),d.value}function Ke(u,d,T){if(!it(T)||T===1/0)throw new RangeError("Size must be a finite, non-NaN, non-negative number.");u._queue.push({value:d,size:T}),u._queueTotalSize+=T}function qA(u){return u._queue.peek().value}function xe(u){u._queue=new Z,u._queueTotalSize=0}function $e(u){return u===DataView}function GA(u){return $e(u.constructor)}function st(u){return $e(u)?1:u.BYTES_PER_ELEMENT}class Le{constructor(){throw new TypeError("Illegal constructor")}get view(){if(!Xe(this))throw XB("view");return this._view}respond(d){if(!Xe(this))throw XB("respond");if(he(d,1,"respond"),d=yr(d,"First parameter"),this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(ge(this._view.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be used as a response");s0(this._associatedReadableByteStreamController,d)}respondWithNewView(d){if(!Xe(this))throw XB("respondWithNewView");if(he(d,1,"respondWithNewView"),!ArrayBuffer.isView(d))throw new TypeError("You can only respond with array buffer views");if(this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(ge(d.buffer))throw new TypeError("The given view's buffer has been detached and so cannot be used as a response");o0(this._associatedReadableByteStreamController,d)}}Object.defineProperties(Le.prototype,{respond:{enumerable:!0},respondWithNewView:{enumerable:!0},view:{enumerable:!0}}),i(Le.prototype.respond,"respond"),i(Le.prototype.respondWithNewView,"respondWithNewView"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Le.prototype,Symbol.toStringTag,{value:"ReadableStreamBYOBRequest",configurable:!0});class hn{constructor(){throw new TypeError("Illegal constructor")}get byobRequest(){if(!Pe(this))throw Jl("byobRequest");return KB(this)}get desiredSize(){if(!Pe(this))throw Jl("desiredSize");return bR(this)}close(){if(!Pe(this))throw Jl("close");if(this._closeRequested)throw new TypeError("The stream has already been closed; do not close it again!");let d=this._controlledReadableByteStream._state;if(d!=="readable")throw new TypeError(`The stream (in ${d} state) is not in the readable state and cannot be closed`);Po(this)}enqueue(d){if(!Pe(this))throw Jl("enqueue");if(he(d,1,"enqueue"),!ArrayBuffer.isView(d))throw new TypeError("chunk must be an array buffer view");if(d.byteLength===0)throw new TypeError("chunk must have non-zero byteLength");if(d.buffer.byteLength===0)throw new TypeError("chunk's buffer must have non-zero byteLength");if(this._closeRequested)throw new TypeError("stream is closed or draining");let T=this._controlledReadableByteStream._state;if(T!=="readable")throw new TypeError(`The stream (in ${T} state) is not in the readable state and cannot be enqueued to`);La(this,d)}error(d=void 0){if(!Pe(this))throw Jl("error");fi(this,d)}[ie](d){xt(this),xe(this);let T=this._cancelAlgorithm(d);return xa(this),T}[ce](d){let T=this._controlledReadableByteStream;if(this._queueTotalSize>0){IR(this,d);return}let P=this._autoAllocateChunkSize;if(P!==void 0){let J;try{J=new ArrayBuffer(P)}catch(oe){d._errorSteps(oe);return}let te={buffer:J,bufferByteLength:P,byteOffset:0,byteLength:P,bytesFilled:0,minimumFill:1,elementSize:1,viewConstructor:Uint8Array,readerType:"default"};this._pendingPullIntos.push(te)}Ds(T,d),Qn(this)}[H](){if(this._pendingPullIntos.length>0){let d=this._pendingPullIntos.peek();d.readerType="none",this._pendingPullIntos=new Z,this._pendingPullIntos.push(d)}}}Object.defineProperties(hn.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},byobRequest:{enumerable:!0},desiredSize:{enumerable:!0}}),i(hn.prototype.close,"close"),i(hn.prototype.enqueue,"enqueue"),i(hn.prototype.error,"error"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(hn.prototype,Symbol.toStringTag,{value:"ReadableByteStreamController",configurable:!0});function Pe(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_controlledReadableByteStream")?!1:u instanceof hn}function Xe(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_associatedReadableByteStreamController")?!1:u instanceof Le}function Qn(u){if(!Lo(u))return;if(u._pulling){u._pullAgain=!0;return}u._pulling=!0;let T=u._pullAlgorithm();I(T,()=>(u._pulling=!1,u._pullAgain&&(u._pullAgain=!1,Qn(u)),null),P=>(fi(u,P),null))}function xt(u){Ji(u),u._pendingPullIntos=new Z}function Ft(u,d){let T=!1;u._state==="closed"&&(T=!0);let P=Ns(d);d.readerType==="default"?Ge(u,P,T):qV(u,P,T)}function Ns(u){let d=u.bytesFilled,T=u.elementSize;return new u.viewConstructor(u.buffer,u.byteOffset,d/T)}function Ai(u,d,T,P){u._queue.push({buffer:d,byteOffset:T,byteLength:P}),u._queueTotalSize+=P}function Ms(u,d,T,P){let J;try{J=ka(d,T,T+P)}catch(te){throw fi(u,te),te}Ai(u,J,0,P)}function Fs(u,d){d.bytesFilled>0&&Ms(u,d.buffer,d.byteOffset,d.bytesFilled),wn(u)}function ks(u,d){let T=Math.min(u._queueTotalSize,d.byteLength-d.bytesFilled),P=d.bytesFilled+T,J=T,te=!1,oe=P%d.elementSize,me=P-oe;me>=d.minimumFill&&(J=me-d.bytesFilled,te=!0);let Ye=u._queue;for(;J>0;){let we=Ye.peek(),ot=Math.min(J,we.byteLength),lt=d.byteOffset+d.bytesFilled;bt(d.buffer,lt,we.buffer,we.byteOffset,ot),we.byteLength===ot?Ye.shift():(we.byteOffset+=ot,we.byteLength-=ot),u._queueTotalSize-=ot,Us(u,ot,d),J-=ot}return te}function Us(u,d,T){T.bytesFilled+=d}function xs(u){u._queueTotalSize===0&&u._closeRequested?(xa(u),$l(u._controlledReadableByteStream)):Qn(u)}function Ji(u){u._byobRequest!==null&&(u._byobRequest._associatedReadableByteStreamController=void 0,u._byobRequest._view=null,u._byobRequest=null)}function ji(u){for(;u._pendingPullIntos.length>0;){if(u._queueTotalSize===0)return;let d=u._pendingPullIntos.peek();ks(u,d)&&(wn(u),Ft(u._controlledReadableByteStream,d))}}function Fo(u){let d=u._controlledReadableByteStream._reader;for(;d._readRequests.length>0;){if(u._queueTotalSize===0)return;let T=d._readRequests.shift();IR(u,T)}}function ko(u,d,T,P){let J=u._controlledReadableByteStream,te=d.constructor,oe=st(te),{byteOffset:me,byteLength:Ye}=d,we=T*oe,ot;try{ot=Ee(d.buffer)}catch(Lt){P._errorSteps(Lt);return}let lt={buffer:ot,bufferByteLength:ot.byteLength,byteOffset:me,byteLength:Ye,bytesFilled:0,minimumFill:we,elementSize:oe,viewConstructor:te,readerType:"byob"};if(u._pendingPullIntos.length>0){u._pendingPullIntos.push(lt),wR(J,P);return}if(J._state==="closed"){let Lt=new te(lt.buffer,lt.byteOffset,0);P._closeSteps(Lt);return}if(u._queueTotalSize>0){if(ks(u,lt)){let Lt=Ns(lt);xs(u),P._chunkSteps(Lt);return}if(u._closeRequested){let Lt=new TypeError("Insufficient bytes to fill elements in the given buffer");fi(u,Lt),P._errorSteps(Lt);return}}u._pendingPullIntos.push(lt),wR(J,P),Qn(u)}function Uo(u,d){d.readerType==="none"&&wn(u);let T=u._controlledReadableByteStream;if(ZB(T))for(;SR(T)>0;){let P=wn(u);Ft(T,P)}}function xo(u,d,T){if(Us(u,d,T),T.readerType==="none"){Fs(u,T),ji(u);return}if(T.bytesFilled0){let J=T.byteOffset+T.bytesFilled;Ms(u,T.buffer,J-P,P)}T.bytesFilled-=P,Ft(u._controlledReadableByteStream,T),ji(u)}function Ls(u,d){let T=u._pendingPullIntos.peek();Ji(u),u._controlledReadableByteStream._state==="closed"?Uo(u,T):xo(u,d,T),Qn(u)}function wn(u){return u._pendingPullIntos.shift()}function Lo(u){let d=u._controlledReadableByteStream;return d._state!=="readable"||u._closeRequested||!u._started?!1:!!(Ts(d)&&Ue(d)>0||ZB(d)&&SR(d)>0||bR(u)>0)}function xa(u){u._pullAlgorithm=void 0,u._cancelAlgorithm=void 0}function Po(u){let d=u._controlledReadableByteStream;if(!(u._closeRequested||d._state!=="readable")){if(u._queueTotalSize>0){u._closeRequested=!0;return}if(u._pendingPullIntos.length>0){let T=u._pendingPullIntos.peek();if(T.bytesFilled%T.elementSize!==0){let P=new TypeError("Insufficient bytes to fill elements in the given buffer");throw fi(u,P),P}}xa(u),$l(d)}}function La(u,d){let T=u._controlledReadableByteStream;if(u._closeRequested||T._state!=="readable")return;let{buffer:P,byteOffset:J,byteLength:te}=d;if(ge(P))throw new TypeError("chunk's buffer is detached and so cannot be enqueued");let oe=Ee(P);if(u._pendingPullIntos.length>0){let me=u._pendingPullIntos.peek();if(ge(me.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk");Ji(u),me.buffer=Ee(me.buffer),me.readerType==="none"&&Fs(u,me)}if(Ts(T))if(Fo(u),Ue(T)===0)Ai(u,oe,J,te);else{u._pendingPullIntos.length>0&&wn(u);let me=new Uint8Array(oe,J,te);Ge(T,me,!1)}else ZB(T)?(Ai(u,oe,J,te),ji(u)):Ai(u,oe,J,te);Qn(u)}function fi(u,d){let T=u._controlledReadableByteStream;T._state==="readable"&&(xt(u),xe(u),xa(u),KR(T,d))}function IR(u,d){let T=u._queue.shift();u._queueTotalSize-=T.byteLength,xs(u);let P=new Uint8Array(T.buffer,T.byteOffset,T.byteLength);d._chunkSteps(P)}function KB(u){if(u._byobRequest===null&&u._pendingPullIntos.length>0){let d=u._pendingPullIntos.peek(),T=new Uint8Array(d.buffer,d.byteOffset+d.bytesFilled,d.byteLength-d.bytesFilled),P=Object.create(Le.prototype);LV(P,u,T),u._byobRequest=P}return u._byobRequest}function bR(u){let d=u._controlledReadableByteStream._state;return d==="errored"?null:d==="closed"?0:u._strategyHWM-u._queueTotalSize}function s0(u,d){let T=u._pendingPullIntos.peek();if(u._controlledReadableByteStream._state==="closed"){if(d!==0)throw new TypeError("bytesWritten must be 0 when calling respond() on a closed stream")}else{if(d===0)throw new TypeError("bytesWritten must be greater than 0 when calling respond() on a readable stream");if(T.bytesFilled+d>T.byteLength)throw new RangeError("bytesWritten out of range")}T.buffer=Ee(T.buffer),Ls(u,d)}function o0(u,d){let T=u._pendingPullIntos.peek();if(u._controlledReadableByteStream._state==="closed"){if(d.byteLength!==0)throw new TypeError("The view's length must be 0 when calling respondWithNewView() on a closed stream")}else if(d.byteLength===0)throw new TypeError("The view's length must be greater than 0 when calling respondWithNewView() on a readable stream");if(T.byteOffset+T.bytesFilled!==d.byteOffset)throw new RangeError("The region specified by view does not match byobRequest");if(T.bufferByteLength!==d.buffer.byteLength)throw new RangeError("The buffer of view has different capacity than byobRequest");if(T.bytesFilled+d.byteLength>T.byteLength)throw new RangeError("The region specified by view is larger than byobRequest");let J=d.byteLength;T.buffer=Ee(d.buffer),Ls(u,J)}function CR(u,d,T,P,J,te,oe){d._controlledReadableByteStream=u,d._pullAgain=!1,d._pulling=!1,d._byobRequest=null,d._queue=d._queueTotalSize=void 0,xe(d),d._closeRequested=!1,d._started=!1,d._strategyHWM=te,d._pullAlgorithm=P,d._cancelAlgorithm=J,d._autoAllocateChunkSize=oe,d._pendingPullIntos=new Z,u._readableStreamController=d;let me=T();I(f(me),()=>(d._started=!0,Qn(d),null),Ye=>(fi(d,Ye),null))}function xV(u,d,T){let P=Object.create(hn.prototype),J,te,oe;d.start!==void 0?J=()=>d.start(P):J=()=>{},d.pull!==void 0?te=()=>d.pull(P):te=()=>f(void 0),d.cancel!==void 0?oe=Ye=>d.cancel(Ye):oe=()=>f(void 0);let me=d.autoAllocateChunkSize;if(me===0)throw new TypeError("autoAllocateChunkSize must be greater than 0");CR(u,P,J,te,oe,T,me)}function LV(u,d,T){u._associatedReadableByteStreamController=d,u._view=T}function XB(u){return new TypeError(`ReadableStreamBYOBRequest.prototype.${u} can only be used on a ReadableStreamBYOBRequest`)}function Jl(u){return new TypeError(`ReadableByteStreamController.prototype.${u} can only be used on a ReadableByteStreamController`)}function PV(u,d){ne(u,d);let T=u?.mode;return{mode:T===void 0?void 0:OV(T,`${d} has member 'mode' that`)}}function OV(u,d){if(u=`${u}`,u!=="byob")throw new TypeError(`${d} '${u}' is not a valid enumeration value for ReadableStreamReaderMode`);return u}function HV(u,d){var T;ne(u,d);let P=(T=u?.min)!==null&&T!==void 0?T:1;return{min:yr(P,`${d} has member 'min' that`)}}function QR(u){return new Pa(u)}function wR(u,d){u._reader._readIntoRequests.push(d)}function qV(u,d,T){let J=u._reader._readIntoRequests.shift();T?J._closeSteps(d):J._chunkSteps(d)}function SR(u){return u._reader._readIntoRequests.length}function ZB(u){let d=u._reader;return!(d===void 0||!YA(d))}class Pa{constructor(d){if(he(d,1,"ReadableStreamBYOBReader"),Qe(d,"First parameter"),qa(d))throw new TypeError("This stream has already been locked for exclusive reading by another reader");if(!Pe(d._readableStreamController))throw new TypeError("Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte source");E(this,d),this._readIntoRequests=new Z}get closed(){return YA(this)?this._closedPromise:l(a0("closed"))}cancel(d=void 0){return YA(this)?this._ownerReadableStream===void 0?l(c("cancel")):v(this,d):l(a0("cancel"))}read(d,T={}){if(!YA(this))return l(a0("read"));if(!ArrayBuffer.isView(d))return l(new TypeError("view must be an array buffer view"));if(d.byteLength===0)return l(new TypeError("view must have non-zero byteLength"));if(d.buffer.byteLength===0)return l(new TypeError("view's buffer must have non-zero byteLength"));if(ge(d.buffer))return l(new TypeError("view's buffer has been detached"));let P;try{P=HV(T,"options")}catch(we){return l(we)}let J=P.min;if(J===0)return l(new TypeError("options.min must be greater than 0"));if(GA(d)){if(J>d.byteLength)return l(new RangeError("options.min must be less than or equal to view's byteLength"))}else if(J>d.length)return l(new RangeError("options.min must be less than or equal to view's length"));if(this._ownerReadableStream===void 0)return l(c("read from"));let te,oe,me=A((we,ot)=>{te=we,oe=ot});return _R(this,d,J,{_chunkSteps:we=>te({value:we,done:!1}),_closeSteps:we=>te({value:we,done:!0}),_errorSteps:we=>oe(we)}),me}releaseLock(){if(!YA(this))throw a0("releaseLock");this._ownerReadableStream!==void 0&&GV(this)}}Object.defineProperties(Pa.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),i(Pa.prototype.cancel,"cancel"),i(Pa.prototype.read,"read"),i(Pa.prototype.releaseLock,"releaseLock"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Pa.prototype,Symbol.toStringTag,{value:"ReadableStreamBYOBReader",configurable:!0});function YA(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_readIntoRequests")?!1:u instanceof Pa}function _R(u,d,T,P){let J=u._ownerReadableStream;J._disturbed=!0,J._state==="errored"?P._errorSteps(J._storedError):ko(J._readableStreamController,d,T,P)}function GV(u){b(u);let d=new TypeError("Reader was released");vR(u,d)}function vR(u,d){let T=u._readIntoRequests;u._readIntoRequests=new Z,T.forEach(P=>{P._errorSteps(d)})}function a0(u){return new TypeError(`ReadableStreamBYOBReader.prototype.${u} can only be used on a ReadableStreamBYOBReader`)}function jl(u,d){let{highWaterMark:T}=u;if(T===void 0)return d;if(W(T)||T<0)throw new RangeError("Invalid highWaterMark");return T}function A0(u){let{size:d}=u;return d||(()=>1)}function f0(u,d){ne(u,d);let T=u?.highWaterMark,P=u?.size;return{highWaterMark:T===void 0?void 0:Qt(T),size:P===void 0?void 0:YV(P,`${d} has member 'size' that`)}}function YV(u,d){return Ae(u,d),T=>Qt(u(T))}function WV(u,d){ne(u,d);let T=u?.abort,P=u?.close,J=u?.start,te=u?.type,oe=u?.write;return{abort:T===void 0?void 0:VV(T,u,`${d} has member 'abort' that`),close:P===void 0?void 0:JV(P,u,`${d} has member 'close' that`),start:J===void 0?void 0:jV(J,u,`${d} has member 'start' that`),write:oe===void 0?void 0:zV(oe,u,`${d} has member 'write' that`),type:te}}function VV(u,d,T){return Ae(u,T),P=>Y(u,d,[P])}function JV(u,d,T){return Ae(u,T),()=>Y(u,d,[])}function jV(u,d,T){return Ae(u,T),P=>G(u,d,[P])}function zV(u,d,T){return Ae(u,T),(P,J)=>Y(u,d,[P,J])}function RR(u,d){if(!Tu(u))throw new TypeError(`${d} is not a WritableStream.`)}function KV(u){if(typeof u!="object"||u===null)return!1;try{return typeof u.aborted=="boolean"}catch{return!1}}let XV=typeof AbortController=="function";function ZV(){if(XV)return new AbortController}class Oa{constructor(d={},T={}){d===void 0?d=null:pe(d,"First parameter");let P=f0(T,"Second parameter"),J=WV(d,"First parameter");if(TR(this),J.type!==void 0)throw new RangeError("Invalid type is specified");let oe=A0(P),me=jl(P,1);lJ(this,J,me,oe)}get locked(){if(!Tu(this))throw d0("locked");return Nu(this)}abort(d=void 0){return Tu(this)?Nu(this)?l(new TypeError("Cannot abort a stream that already has a writer")):u0(this,d):l(d0("abort"))}close(){return Tu(this)?Nu(this)?l(new TypeError("Cannot close a stream that already has a writer")):Ps(this)?l(new TypeError("Cannot close an already-closing stream")):NR(this):l(d0("close"))}getWriter(){if(!Tu(this))throw d0("getWriter");return DR(this)}}Object.defineProperties(Oa.prototype,{abort:{enumerable:!0},close:{enumerable:!0},getWriter:{enumerable:!0},locked:{enumerable:!0}}),i(Oa.prototype.abort,"abort"),i(Oa.prototype.close,"close"),i(Oa.prototype.getWriter,"getWriter"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Oa.prototype,Symbol.toStringTag,{value:"WritableStream",configurable:!0});function DR(u){return new Oo(u)}function $V(u,d,T,P,J=1,te=()=>1){let oe=Object.create(Oa.prototype);TR(oe);let me=Object.create(Mu.prototype);return LR(oe,me,u,d,T,P,J,te),oe}function TR(u){u._state="writable",u._storedError=void 0,u._writer=void 0,u._writableStreamController=void 0,u._writeRequests=new Z,u._inFlightWriteRequest=void 0,u._closeRequest=void 0,u._inFlightCloseRequest=void 0,u._pendingAbortRequest=void 0,u._backpressure=!1}function Tu(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_writableStreamController")?!1:u instanceof Oa}function Nu(u){return u._writer!==void 0}function u0(u,d){var T;if(u._state==="closed"||u._state==="errored")return f(void 0);u._writableStreamController._abortReason=d,(T=u._writableStreamController._abortController)===null||T===void 0||T.abort(d);let P=u._state;if(P==="closed"||P==="errored")return f(void 0);if(u._pendingAbortRequest!==void 0)return u._pendingAbortRequest._promise;let J=!1;P==="erroring"&&(J=!0,d=void 0);let te=A((oe,me)=>{u._pendingAbortRequest={_promise:void 0,_resolve:oe,_reject:me,_reason:d,_wasAlreadyErroring:J}});return u._pendingAbortRequest._promise=te,J||eI(u,d),te}function NR(u){let d=u._state;if(d==="closed"||d==="errored")return l(new TypeError(`The stream (in ${d} state) is not in the writable state and cannot be closed`));let T=A((J,te)=>{let oe={_resolve:J,_reject:te};u._closeRequest=oe}),P=u._writer;return P!==void 0&&u._backpressure&&d==="writable"&&AI(P),hJ(u._writableStreamController),T}function eJ(u){return A((T,P)=>{let J={_resolve:T,_reject:P};u._writeRequests.push(J)})}function $B(u,d){if(u._state==="writable"){eI(u,d);return}tI(u)}function eI(u,d){let T=u._writableStreamController;u._state="erroring",u._storedError=d;let P=u._writer;P!==void 0&&FR(P,d),!sJ(u)&&T._started&&tI(u)}function tI(u){u._state="errored",u._writableStreamController[se]();let d=u._storedError;if(u._writeRequests.forEach(J=>{J._reject(d)}),u._writeRequests=new Z,u._pendingAbortRequest===void 0){c0(u);return}let T=u._pendingAbortRequest;if(u._pendingAbortRequest=void 0,T._wasAlreadyErroring){T._reject(d),c0(u);return}let P=u._writableStreamController[j](T._reason);I(P,()=>(T._resolve(),c0(u),null),J=>(T._reject(J),c0(u),null))}function tJ(u){u._inFlightWriteRequest._resolve(void 0),u._inFlightWriteRequest=void 0}function rJ(u,d){u._inFlightWriteRequest._reject(d),u._inFlightWriteRequest=void 0,$B(u,d)}function nJ(u){u._inFlightCloseRequest._resolve(void 0),u._inFlightCloseRequest=void 0,u._state==="erroring"&&(u._storedError=void 0,u._pendingAbortRequest!==void 0&&(u._pendingAbortRequest._resolve(),u._pendingAbortRequest=void 0)),u._state="closed";let T=u._writer;T!==void 0&&qR(T)}function iJ(u,d){u._inFlightCloseRequest._reject(d),u._inFlightCloseRequest=void 0,u._pendingAbortRequest!==void 0&&(u._pendingAbortRequest._reject(d),u._pendingAbortRequest=void 0),$B(u,d)}function Ps(u){return!(u._closeRequest===void 0&&u._inFlightCloseRequest===void 0)}function sJ(u){return!(u._inFlightWriteRequest===void 0&&u._inFlightCloseRequest===void 0)}function oJ(u){u._inFlightCloseRequest=u._closeRequest,u._closeRequest=void 0}function aJ(u){u._inFlightWriteRequest=u._writeRequests.shift()}function c0(u){u._closeRequest!==void 0&&(u._closeRequest._reject(u._storedError),u._closeRequest=void 0);let d=u._writer;d!==void 0&&oI(d,u._storedError)}function rI(u,d){let T=u._writer;T!==void 0&&d!==u._backpressure&&(d?BJ(T):AI(T)),u._backpressure=d}class Oo{constructor(d){if(he(d,1,"WritableStreamDefaultWriter"),RR(d,"First parameter"),Nu(d))throw new TypeError("This stream has already been locked for exclusive writing by another writer");this._ownerWritableStream=d,d._writer=this;let T=d._state;if(T==="writable")!Ps(d)&&d._backpressure?p0(this):GR(this),g0(this);else if(T==="erroring")aI(this,d._storedError),g0(this);else if(T==="closed")GR(this),yJ(this);else{let P=d._storedError;aI(this,P),HR(this,P)}}get closed(){return WA(this)?this._closedPromise:l(VA("closed"))}get desiredSize(){if(!WA(this))throw VA("desiredSize");if(this._ownerWritableStream===void 0)throw Kl("desiredSize");return cJ(this)}get ready(){return WA(this)?this._readyPromise:l(VA("ready"))}abort(d=void 0){return WA(this)?this._ownerWritableStream===void 0?l(Kl("abort")):AJ(this,d):l(VA("abort"))}close(){if(!WA(this))return l(VA("close"));let d=this._ownerWritableStream;return d===void 0?l(Kl("close")):Ps(d)?l(new TypeError("Cannot close an already-closing stream")):MR(this)}releaseLock(){if(!WA(this))throw VA("releaseLock");this._ownerWritableStream!==void 0&&kR(this)}write(d=void 0){return WA(this)?this._ownerWritableStream===void 0?l(Kl("write to")):UR(this,d):l(VA("write"))}}Object.defineProperties(Oo.prototype,{abort:{enumerable:!0},close:{enumerable:!0},releaseLock:{enumerable:!0},write:{enumerable:!0},closed:{enumerable:!0},desiredSize:{enumerable:!0},ready:{enumerable:!0}}),i(Oo.prototype.abort,"abort"),i(Oo.prototype.close,"close"),i(Oo.prototype.releaseLock,"releaseLock"),i(Oo.prototype.write,"write"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Oo.prototype,Symbol.toStringTag,{value:"WritableStreamDefaultWriter",configurable:!0});function WA(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_ownerWritableStream")?!1:u instanceof Oo}function AJ(u,d){let T=u._ownerWritableStream;return u0(T,d)}function MR(u){let d=u._ownerWritableStream;return NR(d)}function fJ(u){let d=u._ownerWritableStream,T=d._state;return Ps(d)||T==="closed"?f(void 0):T==="errored"?l(d._storedError):MR(u)}function uJ(u,d){u._closedPromiseState==="pending"?oI(u,d):mJ(u,d)}function FR(u,d){u._readyPromiseState==="pending"?YR(u,d):IJ(u,d)}function cJ(u){let d=u._ownerWritableStream,T=d._state;return T==="errored"||T==="erroring"?null:T==="closed"?0:PR(d._writableStreamController)}function kR(u){let d=u._ownerWritableStream,T=new TypeError("Writer was released and can no longer be used to monitor the stream's closedness");FR(u,T),uJ(u,T),d._writer=void 0,u._ownerWritableStream=void 0}function UR(u,d){let T=u._ownerWritableStream,P=T._writableStreamController,J=dJ(P,d);if(T!==u._ownerWritableStream)return l(Kl("write to"));let te=T._state;if(te==="errored")return l(T._storedError);if(Ps(T)||te==="closed")return l(new TypeError("The stream is closing or closed and cannot be written to"));if(te==="erroring")return l(T._storedError);let oe=eJ(T);return gJ(P,d,J),oe}let xR={};class Mu{constructor(){throw new TypeError("Illegal constructor")}get abortReason(){if(!nI(this))throw sI("abortReason");return this._abortReason}get signal(){if(!nI(this))throw sI("signal");if(this._abortController===void 0)throw new TypeError("WritableStreamDefaultController.prototype.signal is not supported");return this._abortController.signal}error(d=void 0){if(!nI(this))throw sI("error");this._controlledWritableStream._state==="writable"&&OR(this,d)}[j](d){let T=this._abortAlgorithm(d);return l0(this),T}[se](){xe(this)}}Object.defineProperties(Mu.prototype,{abortReason:{enumerable:!0},signal:{enumerable:!0},error:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Mu.prototype,Symbol.toStringTag,{value:"WritableStreamDefaultController",configurable:!0});function nI(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_controlledWritableStream")?!1:u instanceof Mu}function LR(u,d,T,P,J,te,oe,me){d._controlledWritableStream=u,u._writableStreamController=d,d._queue=void 0,d._queueTotalSize=void 0,xe(d),d._abortReason=void 0,d._abortController=ZV(),d._started=!1,d._strategySizeAlgorithm=me,d._strategyHWM=oe,d._writeAlgorithm=P,d._closeAlgorithm=J,d._abortAlgorithm=te;let Ye=iI(d);rI(u,Ye);let we=T(),ot=f(we);I(ot,()=>(d._started=!0,h0(d),null),lt=>(d._started=!0,$B(u,lt),null))}function lJ(u,d,T,P){let J=Object.create(Mu.prototype),te,oe,me,Ye;d.start!==void 0?te=()=>d.start(J):te=()=>{},d.write!==void 0?oe=we=>d.write(we,J):oe=()=>f(void 0),d.close!==void 0?me=()=>d.close():me=()=>f(void 0),d.abort!==void 0?Ye=we=>d.abort(we):Ye=()=>f(void 0),LR(u,J,te,oe,me,Ye,T,P)}function l0(u){u._writeAlgorithm=void 0,u._closeAlgorithm=void 0,u._abortAlgorithm=void 0,u._strategySizeAlgorithm=void 0}function hJ(u){Ke(u,xR,0),h0(u)}function dJ(u,d){try{return u._strategySizeAlgorithm(d)}catch(T){return zl(u,T),1}}function PR(u){return u._strategyHWM-u._queueTotalSize}function gJ(u,d,T){try{Ke(u,d,T)}catch(J){zl(u,J);return}let P=u._controlledWritableStream;if(!Ps(P)&&P._state==="writable"){let J=iI(u);rI(P,J)}h0(u)}function h0(u){let d=u._controlledWritableStream;if(!u._started||d._inFlightWriteRequest!==void 0)return;if(d._state==="erroring"){tI(d);return}if(u._queue.length===0)return;let P=qA(u);P===xR?pJ(u):EJ(u,P)}function zl(u,d){u._controlledWritableStream._state==="writable"&&OR(u,d)}function pJ(u){let d=u._controlledWritableStream;oJ(d),ze(u);let T=u._closeAlgorithm();l0(u),I(T,()=>(nJ(d),null),P=>(iJ(d,P),null))}function EJ(u,d){let T=u._controlledWritableStream;aJ(T);let P=u._writeAlgorithm(d);I(P,()=>{tJ(T);let J=T._state;if(ze(u),!Ps(T)&&J==="writable"){let te=iI(u);rI(T,te)}return h0(u),null},J=>(T._state==="writable"&&l0(u),rJ(T,J),null))}function iI(u){return PR(u)<=0}function OR(u,d){let T=u._controlledWritableStream;l0(u),eI(T,d)}function d0(u){return new TypeError(`WritableStream.prototype.${u} can only be used on a WritableStream`)}function sI(u){return new TypeError(`WritableStreamDefaultController.prototype.${u} can only be used on a WritableStreamDefaultController`)}function VA(u){return new TypeError(`WritableStreamDefaultWriter.prototype.${u} can only be used on a WritableStreamDefaultWriter`)}function Kl(u){return new TypeError("Cannot "+u+" a stream using a released writer")}function g0(u){u._closedPromise=A((d,T)=>{u._closedPromise_resolve=d,u._closedPromise_reject=T,u._closedPromiseState="pending"})}function HR(u,d){g0(u),oI(u,d)}function yJ(u){g0(u),qR(u)}function oI(u,d){u._closedPromise_reject!==void 0&&(O(u._closedPromise),u._closedPromise_reject(d),u._closedPromise_resolve=void 0,u._closedPromise_reject=void 0,u._closedPromiseState="rejected")}function mJ(u,d){HR(u,d)}function qR(u){u._closedPromise_resolve!==void 0&&(u._closedPromise_resolve(void 0),u._closedPromise_resolve=void 0,u._closedPromise_reject=void 0,u._closedPromiseState="resolved")}function p0(u){u._readyPromise=A((d,T)=>{u._readyPromise_resolve=d,u._readyPromise_reject=T}),u._readyPromiseState="pending"}function aI(u,d){p0(u),YR(u,d)}function GR(u){p0(u),AI(u)}function YR(u,d){u._readyPromise_reject!==void 0&&(O(u._readyPromise),u._readyPromise_reject(d),u._readyPromise_resolve=void 0,u._readyPromise_reject=void 0,u._readyPromiseState="rejected")}function BJ(u){p0(u)}function IJ(u,d){aI(u,d)}function AI(u){u._readyPromise_resolve!==void 0&&(u._readyPromise_resolve(void 0),u._readyPromise_resolve=void 0,u._readyPromise_reject=void 0,u._readyPromiseState="fulfilled")}function bJ(){if(typeof globalThis<"u")return globalThis;if(typeof self<"u")return self;if(typeof globalThis<"u")return globalThis}let fI=bJ();function CJ(u){if(!(typeof u=="function"||typeof u=="object")||u.name!=="DOMException")return!1;try{return new u,!0}catch{return!1}}function QJ(){let u=fI?.DOMException;return CJ(u)?u:void 0}function wJ(){let u=function(T,P){this.message=T||"",this.name=P||"Error",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)};return i(u,"DOMException"),u.prototype=Object.create(Error.prototype),Object.defineProperty(u.prototype,"constructor",{value:u,writable:!0,configurable:!0}),u}let SJ=QJ()||wJ();function WR(u,d,T,P,J,te){let oe=_e(u),me=DR(d);u._disturbed=!0;let Ye=!1,we=f(void 0);return A((ot,lt)=>{let Lt;if(te!==void 0){if(Lt=()=>{let Me=te.reason!==void 0?te.reason:new SJ("Aborted","AbortError"),mt=[];P||mt.push(()=>d._state==="writable"?u0(d,Me):f(void 0)),J||mt.push(()=>u._state==="readable"?Ki(u,Me):f(void 0)),Sn(()=>Promise.all(mt.map(Ht=>Ht())),!0,Me)},te.aborted){Lt();return}te.addEventListener("abort",Lt)}function Xi(){return A((Me,mt)=>{function Ht(Wn){Wn?Me():p(xu(),Ht,mt)}Ht(!1)})}function xu(){return Ye?f(!0):p(me._readyPromise,()=>A((Me,mt)=>{en(oe,{_chunkSteps:Ht=>{we=p(UR(me,Ht),void 0,t),Me(!1)},_closeSteps:()=>Me(!0),_errorSteps:mt})}))}if(qo(u,oe._closedPromise,Me=>(P?ui(!0,Me):Sn(()=>u0(d,Me),!0,Me),null)),qo(d,me._closedPromise,Me=>(J?ui(!0,Me):Sn(()=>Ki(u,Me),!0,Me),null)),dn(u,oe._closedPromise,()=>(T?ui():Sn(()=>fJ(me)),null)),Ps(d)||d._state==="closed"){let Me=new TypeError("the destination writable stream closed before all data could be piped to it");J?ui(!0,Me):Sn(()=>Ki(u,Me),!0,Me)}O(Xi());function Ya(){let Me=we;return p(we,()=>Me!==we?Ya():void 0)}function qo(Me,mt,Ht){Me._state==="errored"?Ht(Me._storedError):_(mt,Ht)}function dn(Me,mt,Ht){Me._state==="closed"?Ht():S(mt,Ht)}function Sn(Me,mt,Ht){if(Ye)return;Ye=!0,d._state==="writable"&&!Ps(d)?S(Ya(),Wn):Wn();function Wn(){return I(Me(),()=>Go(mt,Ht),Lu=>Go(!0,Lu)),null}}function ui(Me,mt){Ye||(Ye=!0,d._state==="writable"&&!Ps(d)?S(Ya(),()=>Go(Me,mt)):Go(Me,mt))}function Go(Me,mt){return kR(me),b(oe),te!==void 0&&te.removeEventListener("abort",Lt),Me?lt(mt):ot(void 0),null}})}class Ho{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!E0(this))throw m0("desiredSize");return uI(this)}close(){if(!E0(this))throw m0("close");if(!ku(this))throw new TypeError("The stream is not in a state that permits close");JA(this)}enqueue(d=void 0){if(!E0(this))throw m0("enqueue");if(!ku(this))throw new TypeError("The stream is not in a state that permits enqueue");return Fu(this,d)}error(d=void 0){if(!E0(this))throw m0("error");zi(this,d)}[ie](d){xe(this);let T=this._cancelAlgorithm(d);return y0(this),T}[ce](d){let T=this._controlledReadableStream;if(this._queue.length>0){let P=ze(this);this._closeRequested&&this._queue.length===0?(y0(this),$l(T)):Xl(this),d._chunkSteps(P)}else Ds(T,d),Xl(this)}[H](){}}Object.defineProperties(Ho.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},desiredSize:{enumerable:!0}}),i(Ho.prototype.close,"close"),i(Ho.prototype.enqueue,"enqueue"),i(Ho.prototype.error,"error"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Ho.prototype,Symbol.toStringTag,{value:"ReadableStreamDefaultController",configurable:!0});function E0(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_controlledReadableStream")?!1:u instanceof Ho}function Xl(u){if(!VR(u))return;if(u._pulling){u._pullAgain=!0;return}u._pulling=!0;let T=u._pullAlgorithm();I(T,()=>(u._pulling=!1,u._pullAgain&&(u._pullAgain=!1,Xl(u)),null),P=>(zi(u,P),null))}function VR(u){let d=u._controlledReadableStream;return!ku(u)||!u._started?!1:!!(qa(d)&&Ue(d)>0||uI(u)>0)}function y0(u){u._pullAlgorithm=void 0,u._cancelAlgorithm=void 0,u._strategySizeAlgorithm=void 0}function JA(u){if(!ku(u))return;let d=u._controlledReadableStream;u._closeRequested=!0,u._queue.length===0&&(y0(u),$l(d))}function Fu(u,d){if(!ku(u))return;let T=u._controlledReadableStream;if(qa(T)&&Ue(T)>0)Ge(T,d,!1);else{let P;try{P=u._strategySizeAlgorithm(d)}catch(J){throw zi(u,J),J}try{Ke(u,d,P)}catch(J){throw zi(u,J),J}}Xl(u)}function zi(u,d){let T=u._controlledReadableStream;T._state==="readable"&&(xe(u),y0(u),KR(T,d))}function uI(u){let d=u._controlledReadableStream._state;return d==="errored"?null:d==="closed"?0:u._strategyHWM-u._queueTotalSize}function _J(u){return!VR(u)}function ku(u){let d=u._controlledReadableStream._state;return!u._closeRequested&&d==="readable"}function JR(u,d,T,P,J,te,oe){d._controlledReadableStream=u,d._queue=void 0,d._queueTotalSize=void 0,xe(d),d._started=!1,d._closeRequested=!1,d._pullAgain=!1,d._pulling=!1,d._strategySizeAlgorithm=oe,d._strategyHWM=te,d._pullAlgorithm=P,d._cancelAlgorithm=J,u._readableStreamController=d;let me=T();I(f(me),()=>(d._started=!0,Xl(d),null),Ye=>(zi(d,Ye),null))}function vJ(u,d,T,P){let J=Object.create(Ho.prototype),te,oe,me;d.start!==void 0?te=()=>d.start(J):te=()=>{},d.pull!==void 0?oe=()=>d.pull(J):oe=()=>f(void 0),d.cancel!==void 0?me=Ye=>d.cancel(Ye):me=()=>f(void 0),JR(u,J,te,oe,me,T,P)}function m0(u){return new TypeError(`ReadableStreamDefaultController.prototype.${u} can only be used on a ReadableStreamDefaultController`)}function RJ(u,d){return Pe(u._readableStreamController)?TJ(u):DJ(u)}function DJ(u,d){let T=_e(u),P=!1,J=!1,te=!1,oe=!1,me,Ye,we,ot,lt,Lt=A(dn=>{lt=dn});function Xi(){return P?(J=!0,f(void 0)):(P=!0,en(T,{_chunkSteps:Sn=>{x(()=>{J=!1;let ui=Sn,Go=Sn;te||Fu(we._readableStreamController,ui),oe||Fu(ot._readableStreamController,Go),P=!1,J&&Xi()})},_closeSteps:()=>{P=!1,te||JA(we._readableStreamController),oe||JA(ot._readableStreamController),(!te||!oe)&<(void 0)},_errorSteps:()=>{P=!1}}),f(void 0))}function xu(dn){if(te=!0,me=dn,oe){let Sn=ye([me,Ye]),ui=Ki(u,Sn);lt(ui)}return Lt}function Ya(dn){if(oe=!0,Ye=dn,te){let Sn=ye([me,Ye]),ui=Ki(u,Sn);lt(ui)}return Lt}function qo(){}return we=Zl(qo,Xi,xu),ot=Zl(qo,Xi,Ya),_(T._closedPromise,dn=>(zi(we._readableStreamController,dn),zi(ot._readableStreamController,dn),(!te||!oe)&<(void 0),null)),[we,ot]}function TJ(u){let d=_e(u),T=!1,P=!1,J=!1,te=!1,oe=!1,me,Ye,we,ot,lt,Lt=A(Me=>{lt=Me});function Xi(Me){_(Me._closedPromise,mt=>(Me!==d||(fi(we._readableStreamController,mt),fi(ot._readableStreamController,mt),(!te||!oe)&<(void 0)),null))}function xu(){YA(d)&&(b(d),d=_e(u),Xi(d)),en(d,{_chunkSteps:mt=>{x(()=>{P=!1,J=!1;let Ht=mt,Wn=mt;if(!te&&!oe)try{Wn=Ua(mt)}catch(Lu){fi(we._readableStreamController,Lu),fi(ot._readableStreamController,Lu),lt(Ki(u,Lu));return}te||La(we._readableStreamController,Ht),oe||La(ot._readableStreamController,Wn),T=!1,P?qo():J&&dn()})},_closeSteps:()=>{T=!1,te||Po(we._readableStreamController),oe||Po(ot._readableStreamController),we._readableStreamController._pendingPullIntos.length>0&&s0(we._readableStreamController,0),ot._readableStreamController._pendingPullIntos.length>0&&s0(ot._readableStreamController,0),(!te||!oe)&<(void 0)},_errorSteps:()=>{T=!1}})}function Ya(Me,mt){De(d)&&(b(d),d=QR(u),Xi(d));let Ht=mt?ot:we,Wn=mt?we:ot;_R(d,Me,1,{_chunkSteps:Pu=>{x(()=>{P=!1,J=!1;let Ou=mt?oe:te;if(mt?te:oe)Ou||o0(Ht._readableStreamController,Pu);else{let fD;try{fD=Ua(Pu)}catch(gI){fi(Ht._readableStreamController,gI),fi(Wn._readableStreamController,gI),lt(Ki(u,gI));return}Ou||o0(Ht._readableStreamController,Pu),La(Wn._readableStreamController,fD)}T=!1,P?qo():J&&dn()})},_closeSteps:Pu=>{T=!1;let Ou=mt?oe:te,_0=mt?te:oe;Ou||Po(Ht._readableStreamController),_0||Po(Wn._readableStreamController),Pu!==void 0&&(Ou||o0(Ht._readableStreamController,Pu),!_0&&Wn._readableStreamController._pendingPullIntos.length>0&&s0(Wn._readableStreamController,0)),(!Ou||!_0)&<(void 0)},_errorSteps:()=>{T=!1}})}function qo(){if(T)return P=!0,f(void 0);T=!0;let Me=KB(we._readableStreamController);return Me===null?xu():Ya(Me._view,!1),f(void 0)}function dn(){if(T)return J=!0,f(void 0);T=!0;let Me=KB(ot._readableStreamController);return Me===null?xu():Ya(Me._view,!0),f(void 0)}function Sn(Me){if(te=!0,me=Me,oe){let mt=ye([me,Ye]),Ht=Ki(u,mt);lt(Ht)}return Lt}function ui(Me){if(oe=!0,Ye=Me,te){let mt=ye([me,Ye]),Ht=Ki(u,mt);lt(Ht)}return Lt}function Go(){}return we=zR(Go,qo,Sn),ot=zR(Go,dn,ui),Xi(d),[we,ot]}function NJ(u){return r(u)&&typeof u.getReader<"u"}function MJ(u){return NJ(u)?kJ(u.getReader()):FJ(u)}function FJ(u){let d,T=Ze(u,"async"),P=t;function J(){let oe;try{oe=rt(T)}catch(Ye){return l(Ye)}let me=f(oe);return N(me,Ye=>{if(!r(Ye))throw new TypeError("The promise returned by the iterator.next() method must fulfill with an object");if(HA(Ye))JA(d._readableStreamController);else{let ot=nt(Ye);Fu(d._readableStreamController,ot)}})}function te(oe){let me=T.iterator,Ye;try{Ye=Je(me,"return")}catch(lt){return l(lt)}if(Ye===void 0)return f(void 0);let we;try{we=G(Ye,me,[oe])}catch(lt){return l(lt)}let ot=f(we);return N(ot,lt=>{if(!r(lt))throw new TypeError("The promise returned by the iterator.return() method must fulfill with an object")})}return d=Zl(P,J,te,0),d}function kJ(u){let d,T=t;function P(){let te;try{te=u.read()}catch(oe){return l(oe)}return N(te,oe=>{if(!r(oe))throw new TypeError("The promise returned by the reader.read() method must fulfill with an object");if(oe.done)JA(d._readableStreamController);else{let me=oe.value;Fu(d._readableStreamController,me)}})}function J(te){try{return f(u.cancel(te))}catch(oe){return l(oe)}}return d=Zl(T,P,J,0),d}function UJ(u,d){ne(u,d);let T=u,P=T?.autoAllocateChunkSize,J=T?.cancel,te=T?.pull,oe=T?.start,me=T?.type;return{autoAllocateChunkSize:P===void 0?void 0:yr(P,`${d} has member 'autoAllocateChunkSize' that`),cancel:J===void 0?void 0:xJ(J,T,`${d} has member 'cancel' that`),pull:te===void 0?void 0:LJ(te,T,`${d} has member 'pull' that`),start:oe===void 0?void 0:PJ(oe,T,`${d} has member 'start' that`),type:me===void 0?void 0:OJ(me,`${d} has member 'type' that`)}}function xJ(u,d,T){return Ae(u,T),P=>Y(u,d,[P])}function LJ(u,d,T){return Ae(u,T),P=>Y(u,d,[P])}function PJ(u,d,T){return Ae(u,T),P=>G(u,d,[P])}function OJ(u,d){if(u=`${u}`,u!=="bytes")throw new TypeError(`${d} '${u}' is not a valid enumeration value for ReadableStreamType`);return u}function HJ(u,d){return ne(u,d),{preventCancel:!!u?.preventCancel}}function jR(u,d){ne(u,d);let T=u?.preventAbort,P=u?.preventCancel,J=u?.preventClose,te=u?.signal;return te!==void 0&&qJ(te,`${d} has member 'signal' that`),{preventAbort:!!T,preventCancel:!!P,preventClose:!!J,signal:te}}function qJ(u,d){if(!KV(u))throw new TypeError(`${d} is not an AbortSignal.`)}function GJ(u,d){ne(u,d);let T=u?.readable;de(T,"readable","ReadableWritablePair"),Qe(T,`${d} has member 'readable' that`);let P=u?.writable;return de(P,"writable","ReadableWritablePair"),RR(P,`${d} has member 'writable' that`),{readable:T,writable:P}}class tn{constructor(d={},T={}){d===void 0?d=null:pe(d,"First parameter");let P=f0(T,"Second parameter"),J=UJ(d,"First parameter");if(cI(this),J.type==="bytes"){if(P.size!==void 0)throw new RangeError("The strategy for a byte stream cannot have a size function");let te=jl(P,0);xV(this,J,te)}else{let te=A0(P),oe=jl(P,1);vJ(this,J,oe,te)}}get locked(){if(!Ha(this))throw jA("locked");return qa(this)}cancel(d=void 0){return Ha(this)?qa(this)?l(new TypeError("Cannot cancel a stream that already has a reader")):Ki(this,d):l(jA("cancel"))}getReader(d=void 0){if(!Ha(this))throw jA("getReader");return PV(d,"First parameter").mode===void 0?_e(this):QR(this)}pipeThrough(d,T={}){if(!Ha(this))throw jA("pipeThrough");he(d,1,"pipeThrough");let P=GJ(d,"First parameter"),J=jR(T,"Second parameter");if(qa(this))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked ReadableStream");if(Nu(P.writable))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked WritableStream");let te=WR(this,P.writable,J.preventClose,J.preventAbort,J.preventCancel,J.signal);return O(te),P.readable}pipeTo(d,T={}){if(!Ha(this))return l(jA("pipeTo"));if(d===void 0)return l("Parameter 1 is required in 'pipeTo'.");if(!Tu(d))return l(new TypeError("ReadableStream.prototype.pipeTo's first argument must be a WritableStream"));let P;try{P=jR(T,"Second parameter")}catch(J){return l(J)}return qa(this)?l(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream")):Nu(d)?l(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream")):WR(this,d,P.preventClose,P.preventAbort,P.preventCancel,P.signal)}tee(){if(!Ha(this))throw jA("tee");let d=RJ(this);return ye(d)}values(d=void 0){if(!Ha(this))throw jA("values");let T=HJ(d,"First parameter");return m(this,T.preventCancel)}[Mo](d){return this.values(d)}static from(d){return MJ(d)}}Object.defineProperties(tn,{from:{enumerable:!0}}),Object.defineProperties(tn.prototype,{cancel:{enumerable:!0},getReader:{enumerable:!0},pipeThrough:{enumerable:!0},pipeTo:{enumerable:!0},tee:{enumerable:!0},values:{enumerable:!0},locked:{enumerable:!0}}),i(tn.from,"from"),i(tn.prototype.cancel,"cancel"),i(tn.prototype.getReader,"getReader"),i(tn.prototype.pipeThrough,"pipeThrough"),i(tn.prototype.pipeTo,"pipeTo"),i(tn.prototype.tee,"tee"),i(tn.prototype.values,"values"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(tn.prototype,Symbol.toStringTag,{value:"ReadableStream",configurable:!0}),Object.defineProperty(tn.prototype,Mo,{value:tn.prototype.values,writable:!0,configurable:!0});function Zl(u,d,T,P=1,J=()=>1){let te=Object.create(tn.prototype);cI(te);let oe=Object.create(Ho.prototype);return JR(te,oe,u,d,T,P,J),te}function zR(u,d,T){let P=Object.create(tn.prototype);cI(P);let J=Object.create(hn.prototype);return CR(P,J,u,d,T,0,void 0),P}function cI(u){u._state="readable",u._reader=void 0,u._storedError=void 0,u._disturbed=!1}function Ha(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_readableStreamController")?!1:u instanceof tn}function qa(u){return u._reader!==void 0}function Ki(u,d){if(u._disturbed=!0,u._state==="closed")return f(void 0);if(u._state==="errored")return l(u._storedError);$l(u);let T=u._reader;if(T!==void 0&&YA(T)){let J=T._readIntoRequests;T._readIntoRequests=new Z,J.forEach(te=>{te._closeSteps(void 0)})}let P=u._readableStreamController[ie](d);return N(P,t)}function $l(u){u._state="closed";let d=u._reader;if(d!==void 0&&(D(d),De(d))){let T=d._readRequests;d._readRequests=new Z,T.forEach(P=>{P._closeSteps()})}}function KR(u,d){u._state="errored",u._storedError=d;let T=u._reader;T!==void 0&&(C(T,d),De(T)?He(T,d):vR(T,d))}function jA(u){return new TypeError(`ReadableStream.prototype.${u} can only be used on a ReadableStream`)}function XR(u,d){ne(u,d);let T=u?.highWaterMark;return de(T,"highWaterMark","QueuingStrategyInit"),{highWaterMark:Qt(T)}}let ZR=u=>u.byteLength;i(ZR,"size");class B0{constructor(d){he(d,1,"ByteLengthQueuingStrategy"),d=XR(d,"First parameter"),this._byteLengthQueuingStrategyHighWaterMark=d.highWaterMark}get highWaterMark(){if(!eD(this))throw $R("highWaterMark");return this._byteLengthQueuingStrategyHighWaterMark}get size(){if(!eD(this))throw $R("size");return ZR}}Object.defineProperties(B0.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(B0.prototype,Symbol.toStringTag,{value:"ByteLengthQueuingStrategy",configurable:!0});function $R(u){return new TypeError(`ByteLengthQueuingStrategy.prototype.${u} can only be used on a ByteLengthQueuingStrategy`)}function eD(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_byteLengthQueuingStrategyHighWaterMark")?!1:u instanceof B0}let tD=()=>1;i(tD,"size");class I0{constructor(d){he(d,1,"CountQueuingStrategy"),d=XR(d,"First parameter"),this._countQueuingStrategyHighWaterMark=d.highWaterMark}get highWaterMark(){if(!nD(this))throw rD("highWaterMark");return this._countQueuingStrategyHighWaterMark}get size(){if(!nD(this))throw rD("size");return tD}}Object.defineProperties(I0.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(I0.prototype,Symbol.toStringTag,{value:"CountQueuingStrategy",configurable:!0});function rD(u){return new TypeError(`CountQueuingStrategy.prototype.${u} can only be used on a CountQueuingStrategy`)}function nD(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_countQueuingStrategyHighWaterMark")?!1:u instanceof I0}function YJ(u,d){ne(u,d);let T=u?.cancel,P=u?.flush,J=u?.readableType,te=u?.start,oe=u?.transform,me=u?.writableType;return{cancel:T===void 0?void 0:jJ(T,u,`${d} has member 'cancel' that`),flush:P===void 0?void 0:WJ(P,u,`${d} has member 'flush' that`),readableType:J,start:te===void 0?void 0:VJ(te,u,`${d} has member 'start' that`),transform:oe===void 0?void 0:JJ(oe,u,`${d} has member 'transform' that`),writableType:me}}function WJ(u,d,T){return Ae(u,T),P=>Y(u,d,[P])}function VJ(u,d,T){return Ae(u,T),P=>G(u,d,[P])}function JJ(u,d,T){return Ae(u,T),(P,J)=>Y(u,d,[P,J])}function jJ(u,d,T){return Ae(u,T),P=>Y(u,d,[P])}class b0{constructor(d={},T={},P={}){d===void 0&&(d=null);let J=f0(T,"Second parameter"),te=f0(P,"Third parameter"),oe=YJ(d,"First parameter");if(oe.readableType!==void 0)throw new RangeError("Invalid readableType specified");if(oe.writableType!==void 0)throw new RangeError("Invalid writableType specified");let me=jl(te,0),Ye=A0(te),we=jl(J,1),ot=A0(J),lt,Lt=A(Xi=>{lt=Xi});zJ(this,Lt,we,ot,me,Ye),XJ(this,oe),oe.start!==void 0?lt(oe.start(this._transformStreamController)):lt(void 0)}get readable(){if(!iD(this))throw AD("readable");return this._readable}get writable(){if(!iD(this))throw AD("writable");return this._writable}}Object.defineProperties(b0.prototype,{readable:{enumerable:!0},writable:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(b0.prototype,Symbol.toStringTag,{value:"TransformStream",configurable:!0});function zJ(u,d,T,P,J,te){function oe(){return d}function me(Lt){return ej(u,Lt)}function Ye(Lt){return tj(u,Lt)}function we(){return rj(u)}u._writable=$V(oe,me,we,Ye,T,P);function ot(){return nj(u)}function lt(Lt){return ij(u,Lt)}u._readable=Zl(oe,ot,lt,J,te),u._backpressure=void 0,u._backpressureChangePromise=void 0,u._backpressureChangePromise_resolve=void 0,C0(u,!0),u._transformStreamController=void 0}function iD(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_transformStreamController")?!1:u instanceof b0}function sD(u,d){zi(u._readable._readableStreamController,d),lI(u,d)}function lI(u,d){w0(u._transformStreamController),zl(u._writable._writableStreamController,d),hI(u)}function hI(u){u._backpressure&&C0(u,!1)}function C0(u,d){u._backpressureChangePromise!==void 0&&u._backpressureChangePromise_resolve(),u._backpressureChangePromise=A(T=>{u._backpressureChangePromise_resolve=T}),u._backpressure=d}class Ga{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!Q0(this))throw S0("desiredSize");let d=this._controlledTransformStream._readable._readableStreamController;return uI(d)}enqueue(d=void 0){if(!Q0(this))throw S0("enqueue");oD(this,d)}error(d=void 0){if(!Q0(this))throw S0("error");ZJ(this,d)}terminate(){if(!Q0(this))throw S0("terminate");$J(this)}}Object.defineProperties(Ga.prototype,{enqueue:{enumerable:!0},error:{enumerable:!0},terminate:{enumerable:!0},desiredSize:{enumerable:!0}}),i(Ga.prototype.enqueue,"enqueue"),i(Ga.prototype.error,"error"),i(Ga.prototype.terminate,"terminate"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Ga.prototype,Symbol.toStringTag,{value:"TransformStreamDefaultController",configurable:!0});function Q0(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_controlledTransformStream")?!1:u instanceof Ga}function KJ(u,d,T,P,J){d._controlledTransformStream=u,u._transformStreamController=d,d._transformAlgorithm=T,d._flushAlgorithm=P,d._cancelAlgorithm=J,d._finishPromise=void 0,d._finishPromise_resolve=void 0,d._finishPromise_reject=void 0}function XJ(u,d){let T=Object.create(Ga.prototype),P,J,te;d.transform!==void 0?P=oe=>d.transform(oe,T):P=oe=>{try{return oD(T,oe),f(void 0)}catch(me){return l(me)}},d.flush!==void 0?J=()=>d.flush(T):J=()=>f(void 0),d.cancel!==void 0?te=oe=>d.cancel(oe):te=()=>f(void 0),KJ(u,T,P,J,te)}function w0(u){u._transformAlgorithm=void 0,u._flushAlgorithm=void 0,u._cancelAlgorithm=void 0}function oD(u,d){let T=u._controlledTransformStream,P=T._readable._readableStreamController;if(!ku(P))throw new TypeError("Readable side is not in a state that permits enqueue");try{Fu(P,d)}catch(te){throw lI(T,te),T._readable._storedError}_J(P)!==T._backpressure&&C0(T,!0)}function ZJ(u,d){sD(u._controlledTransformStream,d)}function aD(u,d){let T=u._transformAlgorithm(d);return N(T,void 0,P=>{throw sD(u._controlledTransformStream,P),P})}function $J(u){let d=u._controlledTransformStream,T=d._readable._readableStreamController;JA(T);let P=new TypeError("TransformStream terminated");lI(d,P)}function ej(u,d){let T=u._transformStreamController;if(u._backpressure){let P=u._backpressureChangePromise;return N(P,()=>{let J=u._writable;if(J._state==="erroring")throw J._storedError;return aD(T,d)})}return aD(T,d)}function tj(u,d){let T=u._transformStreamController;if(T._finishPromise!==void 0)return T._finishPromise;let P=u._readable;T._finishPromise=A((te,oe)=>{T._finishPromise_resolve=te,T._finishPromise_reject=oe});let J=T._cancelAlgorithm(d);return w0(T),I(J,()=>(P._state==="errored"?Uu(T,P._storedError):(zi(P._readableStreamController,d),dI(T)),null),te=>(zi(P._readableStreamController,te),Uu(T,te),null)),T._finishPromise}function rj(u){let d=u._transformStreamController;if(d._finishPromise!==void 0)return d._finishPromise;let T=u._readable;d._finishPromise=A((J,te)=>{d._finishPromise_resolve=J,d._finishPromise_reject=te});let P=d._flushAlgorithm();return w0(d),I(P,()=>(T._state==="errored"?Uu(d,T._storedError):(JA(T._readableStreamController),dI(d)),null),J=>(zi(T._readableStreamController,J),Uu(d,J),null)),d._finishPromise}function nj(u){return C0(u,!1),u._backpressureChangePromise}function ij(u,d){let T=u._transformStreamController;if(T._finishPromise!==void 0)return T._finishPromise;let P=u._writable;T._finishPromise=A((te,oe)=>{T._finishPromise_resolve=te,T._finishPromise_reject=oe});let J=T._cancelAlgorithm(d);return w0(T),I(J,()=>(P._state==="errored"?Uu(T,P._storedError):(zl(P._writableStreamController,d),hI(u),dI(T)),null),te=>(zl(P._writableStreamController,te),hI(u),Uu(T,te),null)),T._finishPromise}function S0(u){return new TypeError(`TransformStreamDefaultController.prototype.${u} can only be used on a TransformStreamDefaultController`)}function dI(u){u._finishPromise_resolve!==void 0&&(u._finishPromise_resolve(),u._finishPromise_resolve=void 0,u._finishPromise_reject=void 0)}function Uu(u,d){u._finishPromise_reject!==void 0&&(O(u._finishPromise),u._finishPromise_reject(d),u._finishPromise_resolve=void 0,u._finishPromise_reject=void 0)}function AD(u){return new TypeError(`TransformStream.prototype.${u} can only be used on a TransformStream`)}e.ByteLengthQueuingStrategy=B0,e.CountQueuingStrategy=I0,e.ReadableByteStreamController=hn,e.ReadableStream=tn,e.ReadableStreamBYOBReader=Pa,e.ReadableStreamBYOBRequest=Le,e.ReadableStreamDefaultController=Ho,e.ReadableStreamDefaultReader=Te,e.TransformStream=b0,e.TransformStreamDefaultController=Ga,e.WritableStream=Oa,e.WritableStreamDefaultController=Mu,e.WritableStreamDefaultWriter=Oo}))});var EC=U((hDe,_4)=>{"use strict";function eA(e){"@babel/helpers - typeof";return eA=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},eA(e)}function Q4(e,t){for(var r=0;r"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function Hp(e){return Hp=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(r){return r.__proto__||Object.getPrototypeOf(r)},Hp(e)}var S4={},hc,gC;function Dh(e,t,r){r||(r=Error);function n(s,o,a){return typeof t=="string"?t:t(s,o,a)}var i=(function(s){Ise(a,s);var o=bse(a);function a(A,f,l){var p;return Bse(this,a),p=o.call(this,n(A,f,l)),p.code=e,p}return Ese(a)})(r);S4[e]=i}function w4(e,t){if(Array.isArray(e)){var r=e.length;return e=e.map(function(n){return String(n)}),r>2?"one of ".concat(t," ").concat(e.slice(0,r-1).join(", "),", or ")+e[r-1]:r===2?"one of ".concat(t," ").concat(e[0]," or ").concat(e[1]):"of ".concat(t," ").concat(e[0])}else return"of ".concat(t," ").concat(String(e))}function Sse(e,t,r){return e.substr(!r||r<0?0:+r,t.length)===t}function _se(e,t,r){return(r===void 0||r>e.length)&&(r=e.length),e.substring(r-t.length,r)===t}function vse(e,t,r){return typeof r!="number"&&(r=0),r+t.length>e.length?!1:e.indexOf(t,r)!==-1}Dh("ERR_AMBIGUOUS_ARGUMENT",'The "%s" argument is ambiguous. %s',TypeError);Dh("ERR_INVALID_ARG_TYPE",function(e,t,r){hc===void 0&&(hc=Gt()),hc(typeof e=="string","'name' must be a string");var n;typeof t=="string"&&Sse(t,"not ")?(n="must not be",t=t.replace(/^not /,"")):n="must be";var i;if(_se(e," argument"))i="The ".concat(e," ").concat(n," ").concat(w4(t,"type"));else{var s=vse(e,".")?"property":"argument";i='The "'.concat(e,'" ').concat(s," ").concat(n," ").concat(w4(t,"type"))}return i+=". Received type ".concat(eA(r)),i},TypeError);Dh("ERR_INVALID_ARG_VALUE",function(e,t){var r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:"is invalid";gC===void 0&&(gC=Yr());var n=gC.inspect(t);return n.length>128&&(n="".concat(n.slice(0,128),"...")),"The argument '".concat(e,"' ").concat(r,". Received ").concat(n)},TypeError,RangeError);Dh("ERR_INVALID_RETURN_VALUE",function(e,t,r){var n;return r&&r.constructor&&r.constructor.name?n="instance of ".concat(r.constructor.name):n="type ".concat(eA(r)),"Expected ".concat(e,' to be returned from the "').concat(t,'"')+" function but got ".concat(n,".")},TypeError);Dh("ERR_MISSING_ARGS",function(){for(var e=arguments.length,t=new Array(e),r=0;r0,"At least one arg needs to be specified");var n="The ",i=t.length;switch(t=t.map(function(s){return'"'.concat(s,'"')}),i){case 1:n+="".concat(t[0]," argument");break;case 2:n+="".concat(t[0]," and ").concat(t[1]," arguments");break;default:n+=t.slice(0,i-1).join(", "),n+=", and ".concat(t[i-1]," arguments");break}return"".concat(n," must be specified")},TypeError);_4.exports.codes=S4});var x4=U((dDe,U4)=>{"use strict";function v4(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),r.push.apply(r,n)}return r}function R4(e){for(var t=1;t"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function kse(e){return Function.toString.call(e).indexOf("[native code]")!==-1}function Fh(e,t){return Fh=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(n,i){return n.__proto__=i,n},Fh(e,t)}function kh(e){return kh=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(r){return r.__proto__||Object.getPrototypeOf(r)},kh(e)}function Rn(e){"@babel/helpers - typeof";return Rn=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Rn(e)}var Use=Yr(),BC=Use.inspect,xse=EC(),Lse=xse.codes.ERR_INVALID_ARG_TYPE;function T4(e,t,r){return(r===void 0||r>e.length)&&(r=e.length),e.substring(r-t.length,r)===t}function Pse(e,t){if(t=Math.floor(t),e.length==0||t==0)return"";var r=e.length*t;for(t=Math.floor(Math.log(t)/Math.log(2));t;)e+=e,t--;return e+=e.substring(0,r-e.length),e}var rs="",Th="",Nh="",Vr="",lf={deepStrictEqual:"Expected values to be strictly deep-equal:",strictEqual:"Expected values to be strictly equal:",strictEqualObject:'Expected "actual" to be reference-equal to "expected":',deepEqual:"Expected values to be loosely deep-equal:",equal:"Expected values to be loosely equal:",notDeepStrictEqual:'Expected "actual" not to be strictly deep-equal to:',notStrictEqual:'Expected "actual" to be strictly unequal to:',notStrictEqualObject:'Expected "actual" not to be reference-equal to "expected":',notDeepEqual:'Expected "actual" not to be loosely deep-equal to:',notEqual:'Expected "actual" to be loosely unequal to:',notIdentical:"Values identical but not reference-equal:"},Ose=10;function N4(e){var t=Object.keys(e),r=Object.create(Object.getPrototypeOf(e));return t.forEach(function(n){r[n]=e[n]}),Object.defineProperty(r,"message",{value:e.message}),r}function Mh(e){return BC(e,{compact:!1,customInspect:!1,depth:1e3,maxArrayLength:1/0,showHidden:!1,breakLength:1/0,showProxy:!1,sorted:!0,getters:!0})}function Hse(e,t,r){var n="",i="",s=0,o="",a=!1,A=Mh(e),f=A.split(` -`),l=Mh(t).split(` -`),p=0,I="";if(r==="strictEqual"&&Rn(e)==="object"&&Rn(t)==="object"&&e!==null&&t!==null&&(r="strictEqualObject"),f.length===1&&l.length===1&&f[0]!==l[0]){var S=f[0].length+l[0].length;if(S<=Ose){if((Rn(e)!=="object"||e===null)&&(Rn(t)!=="object"||t===null)&&(e!==0||t!==0))return"".concat(lf[r],` - -`)+"".concat(f[0]," !== ").concat(l[0],` -`)}else if(r!=="strictEqualObject"){var _=process.stderr&&process.stderr.isTTY?process.stderr.columns:80;if(S<_){for(;f[0][p]===l[0][p];)p++;p>2&&(I=` - `.concat(Pse(" ",p),"^"),p=0)}}}for(var N=f[f.length-1],O=l[l.length-1];N===O&&(p++<2?o=` - `.concat(N).concat(o):n=N,f.pop(),l.pop(),!(f.length===0||l.length===0));)N=f[f.length-1],O=l[l.length-1];var x=Math.max(f.length,l.length);if(x===0){var G=A.split(` -`);if(G.length>30)for(G[26]="".concat(rs,"...").concat(Vr);G.length>27;)G.pop();return"".concat(lf.notIdentical,` - -`).concat(G.join(` -`),` -`)}p>3&&(o=` -`.concat(rs,"...").concat(Vr).concat(o),a=!0),n!==""&&(o=` - `.concat(n).concat(o),n="");var Y=0,X=lf[r]+` -`.concat(Th,"+ actual").concat(Vr," ").concat(Nh,"- expected").concat(Vr),Z=" ".concat(rs,"...").concat(Vr," Lines skipped");for(p=0;p1&&p>2&&(j>4?(i+=` -`.concat(rs,"...").concat(Vr),a=!0):j>3&&(i+=` - `.concat(l[p-2]),Y++),i+=` - `.concat(l[p-1]),Y++),s=p,n+=` -`.concat(Nh,"-").concat(Vr," ").concat(l[p]),Y++;else if(l.length1&&p>2&&(j>4?(i+=` -`.concat(rs,"...").concat(Vr),a=!0):j>3&&(i+=` - `.concat(f[p-2]),Y++),i+=` - `.concat(f[p-1]),Y++),s=p,i+=` -`.concat(Th,"+").concat(Vr," ").concat(f[p]),Y++;else{var se=l[p],ie=f[p],ce=ie!==se&&(!T4(ie,",")||ie.slice(0,-1)!==se);ce&&T4(se,",")&&se.slice(0,-1)===ie&&(ce=!1,ie+=","),ce?(j>1&&p>2&&(j>4?(i+=` -`.concat(rs,"...").concat(Vr),a=!0):j>3&&(i+=` - `.concat(f[p-2]),Y++),i+=` - `.concat(f[p-1]),Y++),s=p,i+=` -`.concat(Th,"+").concat(Vr," ").concat(ie),n+=` -`.concat(Nh,"-").concat(Vr," ").concat(se),Y+=2):(i+=n,n="",(j===1||p===0)&&(i+=` - `.concat(ie),Y++))}if(Y>20&&p30)for(S[26]="".concat(rs,"...").concat(Vr);S.length>27;)S.pop();S.length===1?s=r.call(this,"".concat(I," ").concat(S[0])):s=r.call(this,"".concat(I,` - -`).concat(S.join(` -`),` -`))}else{var _=Mh(f),N="",O=lf[a];a==="notDeepEqual"||a==="notEqual"?(_="".concat(lf[a],` - -`).concat(_),_.length>1024&&(_="".concat(_.slice(0,1021),"..."))):(N="".concat(Mh(l)),_.length>512&&(_="".concat(_.slice(0,509),"...")),N.length>512&&(N="".concat(N.slice(0,509),"...")),a==="deepEqual"||a==="equal"?_="".concat(O,` - -`).concat(_,` - -should equal - -`):N=" ".concat(a," ").concat(N)),s=r.call(this,"".concat(_).concat(N))}return Error.stackTraceLimit=p,s.generatedMessage=!o,Object.defineProperty(yC(s),"name",{value:"AssertionError [ERR_ASSERTION]",enumerable:!1,writable:!0,configurable:!0}),s.code="ERR_ASSERTION",s.actual=f,s.expected=l,s.operator=a,Error.captureStackTrace&&Error.captureStackTrace(yC(s),A),s.stack,s.name="AssertionError",F4(s)}return Tse(n,[{key:"toString",value:function(){return"".concat(this.name," [").concat(this.code,"]: ").concat(this.message)}},{key:t,value:function(s,o){return BC(this,R4(R4({},o),{},{customInspect:!1,depth:0}))}}]),n})(mC(Error),BC.custom);U4.exports=qse});var IC=U((gDe,P4)=>{"use strict";var L4=Object.prototype.toString;P4.exports=function(t){var r=L4.call(t),n=r==="[object Arguments]";return n||(n=r!=="[object Array]"&&t!==null&&typeof t=="object"&&typeof t.length=="number"&&t.length>=0&&L4.call(t.callee)==="[object Function]"),n}});var j4=U((pDe,J4)=>{"use strict";var V4;Object.keys||(Uh=Object.prototype.hasOwnProperty,bC=Object.prototype.toString,O4=IC(),CC=Object.prototype.propertyIsEnumerable,H4=!CC.call({toString:null},"toString"),q4=CC.call(function(){},"prototype"),xh=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],Gp=function(e){var t=e.constructor;return t&&t.prototype===e},G4={$applicationCache:!0,$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$onmozfullscreenchange:!0,$onmozfullscreenerror:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},Y4=(function(){if(typeof window>"u")return!1;for(var e in window)try{if(!G4["$"+e]&&Uh.call(window,e)&&window[e]!==null&&typeof window[e]=="object")try{Gp(window[e])}catch{return!0}}catch{return!0}return!1})(),W4=function(e){if(typeof window>"u"||!Y4)return Gp(e);try{return Gp(e)}catch{return!1}},V4=function(t){var r=t!==null&&typeof t=="object",n=bC.call(t)==="[object Function]",i=O4(t),s=r&&bC.call(t)==="[object String]",o=[];if(!r&&!n&&!i)throw new TypeError("Object.keys called on a non-object");var a=q4&&n;if(s&&t.length>0&&!Uh.call(t,0))for(var A=0;A0)for(var f=0;f{"use strict";var Gse=Array.prototype.slice,Yse=IC(),z4=Object.keys,Yp=z4?function(t){return z4(t)}:j4(),K4=Object.keys;Yp.shim=function(){if(Object.keys){var t=(function(){var r=Object.keys(arguments);return r&&r.length===arguments.length})(1,2);t||(Object.keys=function(n){return Yse(n)?K4(Gse.call(n)):K4(n)})}else Object.keys=Yp;return Object.keys||Yp};X4.exports=Yp});var rk=U((yDe,tk)=>{"use strict";var Wse=QC(),$4=k0()(),ek=Ys(),Wp=U0(),Vse=ek("Array.prototype.push"),Z4=ek("Object.prototype.propertyIsEnumerable"),Jse=$4?Wp.getOwnPropertySymbols:null;tk.exports=function(t,r){if(t==null)throw new TypeError("target must be an object");var n=Wp(t);if(arguments.length===1)return n;for(var i=1;i{"use strict";var wC=rk(),jse=function(){if(!Object.assign)return!1;for(var e="abcdefghijklmnopqrst",t=e.split(""),r={},n=0;n{"use strict";var sk=function(e){return e!==e};ok.exports=function(t,r){return t===0&&r===0?1/t===1/r:!!(t===r||sk(t)&&sk(r))}});var Vp=U((IDe,ak)=>{"use strict";var Kse=SC();ak.exports=function(){return typeof Object.is=="function"?Object.is:Kse}});var ck=U((bDe,uk)=>{"use strict";var Ak=Zu(),fk=Ah(),Xse=fk(Ak("String.prototype.indexOf"));uk.exports=function(t,r){var n=Ak(t,!!r);return typeof n=="function"&&Xse(t,".prototype.")>-1?fk(n):n}});var Lh=U((CDe,gk)=>{"use strict";var Zse=QC(),$se=typeof Symbol=="function"&&typeof Symbol("foo")=="symbol",eoe=Object.prototype.toString,toe=Array.prototype.concat,lk=ZI(),roe=function(e){return typeof e=="function"&&eoe.call(e)==="[object Function]"},hk=eb()(),noe=function(e,t,r,n){if(t in e){if(n===!0){if(e[t]===r)return}else if(!roe(n)||!n())return}hk?lk(e,t,r,!0):lk(e,t,r)},dk=function(e,t){var r=arguments.length>2?arguments[2]:{},n=Zse(t);$se&&(n=toe.call(n,Object.getOwnPropertySymbols(t)));for(var i=0;i{"use strict";var ioe=Vp(),soe=Lh();pk.exports=function(){var t=ioe();return soe(Object,{is:t},{is:function(){return Object.is!==t}}),t}});var Ik=U((wDe,Bk)=>{"use strict";var ooe=Lh(),aoe=Ah(),Aoe=SC(),yk=Vp(),foe=Ek(),mk=aoe(yk(),Object);ooe(mk,{getPolyfill:yk,implementation:Aoe,shim:foe});Bk.exports=mk});var _C=U((SDe,bk)=>{"use strict";bk.exports=function(t){return t!==t}});var vC=U((_De,Ck)=>{"use strict";var uoe=_C();Ck.exports=function(){return Number.isNaN&&Number.isNaN(NaN)&&!Number.isNaN("a")?Number.isNaN:uoe}});var wk=U((vDe,Qk)=>{"use strict";var coe=Lh(),loe=vC();Qk.exports=function(){var t=loe();return coe(Number,{isNaN:t},{isNaN:function(){return Number.isNaN!==t}}),t}});var Rk=U((RDe,vk)=>{"use strict";var hoe=Ah(),doe=Lh(),goe=_C(),Sk=vC(),poe=wk(),_k=hoe(Sk(),Number);doe(_k,{getPolyfill:Sk,implementation:goe,shim:poe});vk.exports=_k});var zk=U((DDe,jk)=>{"use strict";function Dk(e,t){return Boe(e)||moe(e,t)||yoe(e,t)||Eoe()}function Eoe(){throw new TypeError(`Invalid attempt to destructure non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function yoe(e,t){if(e){if(typeof e=="string")return Tk(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);if(r==="Object"&&e.constructor&&(r=e.constructor.name),r==="Map"||r==="Set")return Array.from(e);if(r==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Tk(e,t)}}function Tk(e,t){(t==null||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r10)return!0;for(var t=0;t57)return!0}return e.length===10&&e>=Math.pow(2,32)}function zp(e){return Object.keys(e).filter(Roe).concat(Xp(e).filter(Object.prototype.propertyIsEnumerable.bind(e)))}function Yk(e,t){if(e===t)return 0;for(var r=e.length,n=t.length,i=0,s=Math.min(r,n);i{"use strict";function ns(e){"@babel/helpers - typeof";return ns=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},ns(e)}function Kk(e,t){for(var r=0;r1?r-1:0),i=1;i1?r-1:0),i=1;i1?r-1:0),i=1;i1?r-1:0),i=1;i{"use strict";var FC=class{constructor(){this._enabled=!1,this._store=void 0}disable(){this._enabled=!1,this._store=void 0}enterWith(t){this._enabled=!0,this._store=t}exit(t,...r){let n=this._enabled,i=this._store;this._enabled=!1,this._store=void 0;try{return t(...r)}finally{this._enabled=n,this._store=i}}getStore(){return this._enabled?this._store:void 0}run(t,r,...n){let i=this._enabled,s=this._store;this._enabled=!0,this._store=t;try{return r(...n)}finally{this._enabled=i,this._store=s}}},kC=class{constructor(t="SecureExecAsyncResource"){this.type=t}bind(t,r=void 0){return typeof t!="function"?t:(...n)=>this.runInAsyncScope(t,r??this,...n)}emitDestroy(){}runInAsyncScope(t,r,...n){return t.apply(r,n)}};function tae(){return{enable(){return this},disable(){return this}}}function rae(){return 0}function nae(){return 0}dU.exports={AsyncLocalStorage:FC,AsyncResource:kC,createHook:tae,executionAsyncId:rae,triggerAsyncId:nae}});var mr=U((MDe,PU)=>{"use strict";var gU=Symbol.for("undici.error.UND_ERR"),Xt=class extends Error{constructor(t,r){super(t,r),this.name="UndiciError",this.code="UND_ERR"}static[Symbol.hasInstance](t){return t&&t[gU]===!0}get[gU](){return!0}},pU=Symbol.for("undici.error.UND_ERR_CONNECT_TIMEOUT"),UC=class extends Xt{constructor(t){super(t),this.name="ConnectTimeoutError",this.message=t||"Connect Timeout Error",this.code="UND_ERR_CONNECT_TIMEOUT"}static[Symbol.hasInstance](t){return t&&t[pU]===!0}get[pU](){return!0}},EU=Symbol.for("undici.error.UND_ERR_HEADERS_TIMEOUT"),xC=class extends Xt{constructor(t){super(t),this.name="HeadersTimeoutError",this.message=t||"Headers Timeout Error",this.code="UND_ERR_HEADERS_TIMEOUT"}static[Symbol.hasInstance](t){return t&&t[EU]===!0}get[EU](){return!0}},yU=Symbol.for("undici.error.UND_ERR_HEADERS_OVERFLOW"),LC=class extends Xt{constructor(t){super(t),this.name="HeadersOverflowError",this.message=t||"Headers Overflow Error",this.code="UND_ERR_HEADERS_OVERFLOW"}static[Symbol.hasInstance](t){return t&&t[yU]===!0}get[yU](){return!0}},mU=Symbol.for("undici.error.UND_ERR_BODY_TIMEOUT"),PC=class extends Xt{constructor(t){super(t),this.name="BodyTimeoutError",this.message=t||"Body Timeout Error",this.code="UND_ERR_BODY_TIMEOUT"}static[Symbol.hasInstance](t){return t&&t[mU]===!0}get[mU](){return!0}},BU=Symbol.for("undici.error.UND_ERR_INVALID_ARG"),OC=class extends Xt{constructor(t){super(t),this.name="InvalidArgumentError",this.message=t||"Invalid Argument Error",this.code="UND_ERR_INVALID_ARG"}static[Symbol.hasInstance](t){return t&&t[BU]===!0}get[BU](){return!0}},IU=Symbol.for("undici.error.UND_ERR_INVALID_RETURN_VALUE"),HC=class extends Xt{constructor(t){super(t),this.name="InvalidReturnValueError",this.message=t||"Invalid Return Value Error",this.code="UND_ERR_INVALID_RETURN_VALUE"}static[Symbol.hasInstance](t){return t&&t[IU]===!0}get[IU](){return!0}},bU=Symbol.for("undici.error.UND_ERR_ABORT"),sE=class extends Xt{constructor(t){super(t),this.name="AbortError",this.message=t||"The operation was aborted",this.code="UND_ERR_ABORT"}static[Symbol.hasInstance](t){return t&&t[bU]===!0}get[bU](){return!0}},CU=Symbol.for("undici.error.UND_ERR_ABORTED"),qC=class extends sE{constructor(t){super(t),this.name="AbortError",this.message=t||"Request aborted",this.code="UND_ERR_ABORTED"}static[Symbol.hasInstance](t){return t&&t[CU]===!0}get[CU](){return!0}},QU=Symbol.for("undici.error.UND_ERR_INFO"),GC=class extends Xt{constructor(t){super(t),this.name="InformationalError",this.message=t||"Request information",this.code="UND_ERR_INFO"}static[Symbol.hasInstance](t){return t&&t[QU]===!0}get[QU](){return!0}},wU=Symbol.for("undici.error.UND_ERR_REQ_CONTENT_LENGTH_MISMATCH"),YC=class extends Xt{constructor(t){super(t),this.name="RequestContentLengthMismatchError",this.message=t||"Request body length does not match content-length header",this.code="UND_ERR_REQ_CONTENT_LENGTH_MISMATCH"}static[Symbol.hasInstance](t){return t&&t[wU]===!0}get[wU](){return!0}},SU=Symbol.for("undici.error.UND_ERR_RES_CONTENT_LENGTH_MISMATCH"),WC=class extends Xt{constructor(t){super(t),this.name="ResponseContentLengthMismatchError",this.message=t||"Response body length does not match content-length header",this.code="UND_ERR_RES_CONTENT_LENGTH_MISMATCH"}static[Symbol.hasInstance](t){return t&&t[SU]===!0}get[SU](){return!0}},_U=Symbol.for("undici.error.UND_ERR_DESTROYED"),VC=class extends Xt{constructor(t){super(t),this.name="ClientDestroyedError",this.message=t||"The client is destroyed",this.code="UND_ERR_DESTROYED"}static[Symbol.hasInstance](t){return t&&t[_U]===!0}get[_U](){return!0}},vU=Symbol.for("undici.error.UND_ERR_CLOSED"),JC=class extends Xt{constructor(t){super(t),this.name="ClientClosedError",this.message=t||"The client is closed",this.code="UND_ERR_CLOSED"}static[Symbol.hasInstance](t){return t&&t[vU]===!0}get[vU](){return!0}},RU=Symbol.for("undici.error.UND_ERR_SOCKET"),jC=class extends Xt{constructor(t,r){super(t),this.name="SocketError",this.message=t||"Socket error",this.code="UND_ERR_SOCKET",this.socket=r}static[Symbol.hasInstance](t){return t&&t[RU]===!0}get[RU](){return!0}},DU=Symbol.for("undici.error.UND_ERR_NOT_SUPPORTED"),zC=class extends Xt{constructor(t){super(t),this.name="NotSupportedError",this.message=t||"Not supported error",this.code="UND_ERR_NOT_SUPPORTED"}static[Symbol.hasInstance](t){return t&&t[DU]===!0}get[DU](){return!0}},TU=Symbol.for("undici.error.UND_ERR_BPL_MISSING_UPSTREAM"),KC=class extends Xt{constructor(t){super(t),this.name="MissingUpstreamError",this.message=t||"No upstream has been added to the BalancedPool",this.code="UND_ERR_BPL_MISSING_UPSTREAM"}static[Symbol.hasInstance](t){return t&&t[TU]===!0}get[TU](){return!0}},NU=Symbol.for("undici.error.UND_ERR_HTTP_PARSER"),XC=class extends Error{constructor(t,r,n){super(t),this.name="HTTPParserError",this.code=r?`HPE_${r}`:void 0,this.data=n?n.toString():void 0}static[Symbol.hasInstance](t){return t&&t[NU]===!0}get[NU](){return!0}},MU=Symbol.for("undici.error.UND_ERR_RES_EXCEEDED_MAX_SIZE"),ZC=class extends Xt{constructor(t){super(t),this.name="ResponseExceededMaxSizeError",this.message=t||"Response content exceeded max size",this.code="UND_ERR_RES_EXCEEDED_MAX_SIZE"}static[Symbol.hasInstance](t){return t&&t[MU]===!0}get[MU](){return!0}},FU=Symbol.for("undici.error.UND_ERR_REQ_RETRY"),$C=class extends Xt{constructor(t,r,{headers:n,data:i}){super(t),this.name="RequestRetryError",this.message=t||"Request retry error",this.code="UND_ERR_REQ_RETRY",this.statusCode=r,this.data=i,this.headers=n}static[Symbol.hasInstance](t){return t&&t[FU]===!0}get[FU](){return!0}},kU=Symbol.for("undici.error.UND_ERR_RESPONSE"),eQ=class extends Xt{constructor(t,r,{headers:n,body:i}){super(t),this.name="ResponseError",this.message=t||"Response error",this.code="UND_ERR_RESPONSE",this.statusCode=r,this.body=i,this.headers=n}static[Symbol.hasInstance](t){return t&&t[kU]===!0}get[kU](){return!0}},UU=Symbol.for("undici.error.UND_ERR_PRX_TLS"),tQ=class extends Xt{constructor(t,r,n={}){super(r,{cause:t,...n}),this.name="SecureProxyConnectionError",this.message=r||"Secure Proxy Connection failed",this.code="UND_ERR_PRX_TLS",this.cause=t}static[Symbol.hasInstance](t){return t&&t[UU]===!0}get[UU](){return!0}},xU=Symbol.for("undici.error.UND_ERR_MAX_ORIGINS_REACHED"),rQ=class extends Xt{constructor(t){super(t),this.name="MaxOriginsReachedError",this.message=t||"Maximum allowed origins reached",this.code="UND_ERR_MAX_ORIGINS_REACHED"}static[Symbol.hasInstance](t){return t&&t[xU]===!0}get[xU](){return!0}},nQ=class extends Xt{constructor(t,r){super(t),this.name="Socks5ProxyError",this.message=t||"SOCKS5 proxy error",this.code=r||"UND_ERR_SOCKS5"}},LU=Symbol.for("undici.error.UND_ERR_WS_MESSAGE_SIZE_EXCEEDED"),iQ=class extends Xt{constructor(t){super(t),this.name="MessageSizeExceededError",this.message=t||"Max decompressed message size exceeded",this.code="UND_ERR_WS_MESSAGE_SIZE_EXCEEDED"}static[Symbol.hasInstance](t){return t&&t[LU]===!0}get[LU](){return!0}};PU.exports={AbortError:sE,HTTPParserError:XC,UndiciError:Xt,HeadersTimeoutError:xC,HeadersOverflowError:LC,BodyTimeoutError:PC,RequestContentLengthMismatchError:YC,ConnectTimeoutError:UC,InvalidArgumentError:OC,InvalidReturnValueError:HC,RequestAbortedError:qC,ClientDestroyedError:VC,ClientClosedError:JC,InformationalError:GC,SocketError:jC,NotSupportedError:zC,ResponseContentLengthMismatchError:WC,BalancedPoolMissingUpstreamError:KC,ResponseExceededMaxSizeError:ZC,RequestRetryError:$C,ResponseError:eQ,SecureProxyConnectionError:tQ,MaxOriginsReachedError:rQ,Socks5ProxyError:nQ,MessageSizeExceededError:iQ}});var Dn=U((FDe,OU)=>{"use strict";OU.exports={kClose:Symbol("close"),kDestroy:Symbol("destroy"),kDispatch:Symbol("dispatch"),kUrl:Symbol("url"),kWriting:Symbol("writing"),kResuming:Symbol("resuming"),kQueue:Symbol("queue"),kConnect:Symbol("connect"),kConnecting:Symbol("connecting"),kKeepAliveDefaultTimeout:Symbol("default keep alive timeout"),kKeepAliveMaxTimeout:Symbol("max keep alive timeout"),kKeepAliveTimeoutThreshold:Symbol("keep alive timeout threshold"),kKeepAliveTimeoutValue:Symbol("keep alive timeout"),kKeepAlive:Symbol("keep alive"),kHeadersTimeout:Symbol("headers timeout"),kBodyTimeout:Symbol("body timeout"),kServerName:Symbol("server name"),kLocalAddress:Symbol("local address"),kHost:Symbol("host"),kNoRef:Symbol("no ref"),kBodyUsed:Symbol("used"),kBody:Symbol("abstracted request body"),kRunning:Symbol("running"),kBlocking:Symbol("blocking"),kPending:Symbol("pending"),kSize:Symbol("size"),kBusy:Symbol("busy"),kQueued:Symbol("queued"),kFree:Symbol("free"),kConnected:Symbol("connected"),kClosed:Symbol("closed"),kNeedDrain:Symbol("need drain"),kReset:Symbol("reset"),kDestroyed:Symbol.for("nodejs.stream.destroyed"),kResume:Symbol("resume"),kOnError:Symbol("on error"),kMaxHeadersSize:Symbol("max headers size"),kRunningIdx:Symbol("running index"),kPendingIdx:Symbol("pending index"),kError:Symbol("error"),kClients:Symbol("clients"),kClient:Symbol("client"),kParser:Symbol("parser"),kOnDestroyed:Symbol("destroy callbacks"),kPipelining:Symbol("pipelining"),kSocket:Symbol("socket"),kHostHeader:Symbol("host header"),kConnector:Symbol("connector"),kStrictContentLength:Symbol("strict content length"),kMaxRedirections:Symbol("maxRedirections"),kMaxRequests:Symbol("maxRequestsPerClient"),kProxy:Symbol("proxy agent options"),kCounter:Symbol("socket request counter"),kMaxResponseSize:Symbol("max response size"),kHTTP2Session:Symbol("http2Session"),kHTTP2SessionState:Symbol("http2Session state"),kRetryHandlerDefaultRetry:Symbol("retry agent default retry"),kConstruct:Symbol("constructable"),kListeners:Symbol("listeners"),kHTTPContext:Symbol("http context"),kMaxConcurrentStreams:Symbol("max concurrent streams"),kHTTP2InitialWindowSize:Symbol("http2 initial window size"),kHTTP2ConnectionWindowSize:Symbol("http2 connection window size"),kEnableConnectProtocol:Symbol("http2session connect protocol"),kRemoteSettings:Symbol("http2session remote settings"),kHTTP2Stream:Symbol("http2session client stream"),kPingInterval:Symbol("ping interval"),kNoProxyAgent:Symbol("no proxy agent"),kHttpProxyAgent:Symbol("http proxy agent"),kHttpsProxyAgent:Symbol("https proxy agent"),kSocks5ProxyAgent:Symbol("socks5 proxy agent")}});var aE=U((kDe,HU)=>{"use strict";function hf(){if(!globalThis._httpModule)throw new Error("node:http bridge module is not available");return globalThis._httpModule}var oE=class{},sQ=class{},oQ=class{},aQ=class{},AQ=class{},iae=["CHECKOUT","CONNECT","COPY","DELETE","GET","HEAD","LOCK","M-SEARCH","MERGE","MKACTIVITY","MKCOL","MOVE","NOTIFY","OPTIONS","PATCH","POST","PROPFIND","PROPPATCH","PURGE","PUT","REPORT","SEARCH","SUBSCRIBE","TRACE","UNLOCK","UNSUBSCRIBE"];HU.exports={Agent:oE,ClientRequest:sQ,IncomingMessage:oQ,METHODS:iae,STATUS_CODES:{},Server:aQ,ServerResponse:AQ,_checkInvalidHeaderChar(e){return hf()._checkInvalidHeaderChar(e)},_checkIsHttpToken(e){return hf()._checkIsHttpToken(e)},createServer(...e){return hf().createServer(...e)},get(...e){return hf().get(...e)},globalAgent:new oE,maxHeaderSize:65535,request(...e){return hf().request(...e)},validateHeaderName(e,t){return hf().validateHeaderName(e,t)},validateHeaderValue(e,t){return hf().validateHeaderValue(e,t)}}});var AE=U((UDe,GU)=>{"use strict";function sae(){let e=globalThis._netModule;if(!e)throw new Error("node:net bridge module is not available");return e}var qU={};for(let e of["BlockList","Socket","SocketAddress","Server","Stream","connect","createConnection","createServer","getDefaultAutoSelectFamily","getDefaultAutoSelectFamilyAttemptTimeout","isIP","isIPv4","isIPv6","setDefaultAutoSelectFamily","setDefaultAutoSelectFamilyAttemptTimeout"])Object.defineProperty(qU,e,{enumerable:!0,get(){return sae()[e]}});GU.exports=qU});var gQ=U((xDe,jU)=>{"use strict";var pc=0,fQ=1e3,uQ=(fQ>>1)-1,iA,cQ=Symbol("kFastTimer"),Jo=[],lQ=-2,hQ=-1,VU=0,YU=1;function dQ(){pc+=uQ;let e=0,t=Jo.length;for(;e=r._idleStart+r._idleTimeout&&(r._state=hQ,r._idleStart=-1,r._onTimeout(r._timerArg)),r._state===hQ?(r._state=lQ,--t!==0&&(Jo[e]=Jo[t])):++e}Jo.length=t,Jo.length!==0&&JU()}function JU(){iA?.refresh?iA.refresh():(clearTimeout(iA),iA=setTimeout(dQ,uQ),iA?.unref())}var WU;WU=cQ;var fE=class{constructor(t,r,n){y(this,WU,!0);y(this,"_state",lQ);y(this,"_idleTimeout",-1);y(this,"_idleStart",-1);y(this,"_onTimeout");y(this,"_timerArg");this._onTimeout=t,this._idleTimeout=r,this._timerArg=n,this.refresh()}refresh(){this._state===lQ&&Jo.push(this),(!iA||Jo.length===1)&&JU(),this._state=VU}clear(){this._state=hQ,this._idleStart=-1}};jU.exports={setTimeout(e,t,r){return t<=fQ?setTimeout(e,t,r):new fE(e,t,r)},clearTimeout(e){e[cQ]?e.clear():clearTimeout(e)},setFastTimeout(e,t,r){return new fE(e,t,r)},clearFastTimeout(e){e.clear()},now(){return pc},tick(e=0){pc+=e-fQ+1,dQ(),dQ()},reset(){pc=0,Jo.length=0,clearTimeout(iA),iA=null},kFastTimer:cQ}});var cE=U((PDe,KU)=>{"use strict";var pQ=["Accept","Accept-Encoding","Accept-Language","Accept-Ranges","Access-Control-Allow-Credentials","Access-Control-Allow-Headers","Access-Control-Allow-Methods","Access-Control-Allow-Origin","Access-Control-Expose-Headers","Access-Control-Max-Age","Access-Control-Request-Headers","Access-Control-Request-Method","Age","Allow","Alt-Svc","Alt-Used","Authorization","Cache-Control","Clear-Site-Data","Connection","Content-Disposition","Content-Encoding","Content-Language","Content-Length","Content-Location","Content-Range","Content-Security-Policy","Content-Security-Policy-Report-Only","Content-Type","Cookie","Cross-Origin-Embedder-Policy","Cross-Origin-Opener-Policy","Cross-Origin-Resource-Policy","Date","Device-Memory","Downlink","ECT","ETag","Expect","Expect-CT","Expires","Forwarded","From","Host","If-Match","If-Modified-Since","If-None-Match","If-Range","If-Unmodified-Since","Keep-Alive","Last-Modified","Link","Location","Max-Forwards","Origin","Permissions-Policy","Pragma","Proxy-Authenticate","Proxy-Authorization","RTT","Range","Referer","Referrer-Policy","Refresh","Retry-After","Sec-WebSocket-Accept","Sec-WebSocket-Extensions","Sec-WebSocket-Key","Sec-WebSocket-Protocol","Sec-WebSocket-Version","Server","Server-Timing","Service-Worker-Allowed","Service-Worker-Navigation-Preload","Set-Cookie","SourceMap","Strict-Transport-Security","Supports-Loading-Mode","TE","Timing-Allow-Origin","Trailer","Transfer-Encoding","Upgrade","Upgrade-Insecure-Requests","User-Agent","Vary","Via","WWW-Authenticate","X-Content-Type-Options","X-DNS-Prefetch-Control","X-Frame-Options","X-Permitted-Cross-Domain-Policies","X-Powered-By","X-Requested-With","X-XSS-Protection"],uE={};Object.setPrototypeOf(uE,null);var zU={};Object.setPrototypeOf(zU,null);function oae(e){let t=zU[e];return t===void 0&&(t=Buffer.from(e)),t}for(let e=0;e{"use strict";var{wellknownHeaderNames:XU,headerNameLowerCasedRecord:aae}=cE(),EQ=class e{constructor(t,r,n){y(this,"value",null);y(this,"left",null);y(this,"middle",null);y(this,"right",null);y(this,"code");if(n===void 0||n>=t.length)throw new TypeError("Unreachable");if((this.code=t.charCodeAt(n))>127)throw new TypeError("key must be ascii string");t.length!==++n?this.middle=new e(t,r,n):this.value=r}add(t,r){let n=t.length;if(n===0)throw new TypeError("Unreachable");let i=0,s=this;for(;;){let o=t.charCodeAt(i);if(o>127)throw new TypeError("key must be ascii string");if(s.code===o)if(n===++i){s.value=r;break}else if(s.middle!==null)s=s.middle;else{s.middle=new e(t,r,i);break}else if(s.code=65&&(s|=32);i!==null;){if(s===i.code){if(r===++n)return i;i=i.middle;break}i=i.code{"use strict";var Gh=Gt(),{kDestroyed:ix,kBodyUsed:Ec,kListeners:yc,kBody:tx}=Dn(),{IncomingMessage:Aae}=aE(),sx=(ts(),Os(qt)),fae=AE(),{stringify:uae}=(NI(),Os(F0)),{EventEmitter:cae}=Zi(),hE=gQ(),{InvalidArgumentError:Nr,ConnectTimeoutError:lae}=mr(),{headerNameLowerCasedRecord:hae}=cE(),{tree:ox}=ex(),[dae,gae]=process.versions.node.split(".",2).map(e=>Number(e)),gE=class{constructor(t){this[tx]=t,this[Ec]=!1}async*[Symbol.asyncIterator](){Gh(!this[Ec],"disturbed"),this[Ec]=!0,yield*this[tx]}};function rx(){}function pae(e){return pE(e)?(lx(e)===0&&e.on("data",function(){Gh(!1)}),typeof e.readableDidRead!="boolean"&&(e[Ec]=!1,cae.prototype.on.call(e,"data",function(){this[Ec]=!0})),e):e&&typeof e.pipeTo=="function"?new gE(e):e&&Ex(e)?e:e&&typeof e!="string"&&!ArrayBuffer.isView(e)&&cx(e)?new gE(e):e}function pE(e){return e&&typeof e=="object"&&typeof e.pipe=="function"&&typeof e.on=="function"}function ax(e){if(e===null)return!1;if(e instanceof Blob)return!0;if(typeof e!="object")return!1;{let t=e[Symbol.toStringTag];return(t==="Blob"||t==="File")&&("stream"in e&&typeof e.stream=="function"||"arrayBuffer"in e&&typeof e.arrayBuffer=="function")}}function Ax(e){return e.includes("?")||e.includes("#")}function Eae(e,t){if(Ax(e))throw new Error('Query params cannot be passed when url already contains "?" or "#".');let r=uae(t);return r&&(e+="?"+r),e}function fx(e){let t=parseInt(e,10);return t===Number(e)&&t>=0&&t<=65535}function dE(e){return e!=null&&e[0]==="h"&&e[1]==="t"&&e[2]==="t"&&e[3]==="p"&&(e[4]===":"||e[4]==="s"&&e[5]===":")}function ux(e){if(typeof e=="string"){if(e=new URL(e),!dE(e.origin||e.protocol))throw new Nr("Invalid URL protocol: the URL must start with `http:` or `https:`.");return e}if(!e||typeof e!="object")throw new Nr("Invalid URL: The URL argument must be a non-null object.");if(!(e instanceof URL)){if(e.port!=null&&e.port!==""&&fx(e.port)===!1)throw new Nr("Invalid URL: port must be a valid integer or a string representation of an integer.");if(e.path!=null&&typeof e.path!="string")throw new Nr("Invalid URL path: the path must be a string or null/undefined.");if(e.pathname!=null&&typeof e.pathname!="string")throw new Nr("Invalid URL pathname: the pathname must be a string or null/undefined.");if(e.hostname!=null&&typeof e.hostname!="string")throw new Nr("Invalid URL hostname: the hostname must be a string or null/undefined.");if(e.origin!=null&&typeof e.origin!="string")throw new Nr("Invalid URL origin: the origin must be a string or null/undefined.");if(!dE(e.origin||e.protocol))throw new Nr("Invalid URL protocol: the URL must start with `http:` or `https:`.");let t=e.port!=null?e.port:e.protocol==="https:"?443:80,r=e.origin!=null?e.origin:`${e.protocol||""}//${e.hostname||""}:${t}`,n=e.path!=null?e.path:`${e.pathname||""}${e.search||""}`;return r[r.length-1]==="/"&&(r=r.slice(0,r.length-1)),n&&n[0]!=="/"&&(n=`/${n}`),new URL(`${r}${n}`)}if(!dE(e.origin||e.protocol))throw new Nr("Invalid URL protocol: the URL must start with `http:` or `https:`.");return e}function yae(e){if(e=ux(e),e.pathname!=="/"||e.search||e.hash)throw new Nr("invalid url");return e}function mae(e){if(e[0]==="["){let r=e.indexOf("]");return Gh(r!==-1),e.substring(1,r)}let t=e.indexOf(":");return t===-1?e:e.substring(0,t)}function Bae(e){if(!e)return null;Gh(typeof e=="string");let t=mae(e);return fae.isIP(t)?"":t}function Iae(e){return JSON.parse(JSON.stringify(e))}function bae(e){return e!=null&&typeof e[Symbol.asyncIterator]=="function"}function cx(e){return e!=null&&(typeof e[Symbol.iterator]=="function"||typeof e[Symbol.asyncIterator]=="function")}function Cae(e){let t=Object.getPrototypeOf(e);return Object.prototype.hasOwnProperty.call(e,Symbol.iterator)||t!=null&&t!==Object.prototype&&typeof e[Symbol.iterator]=="function"}function lx(e){if(e==null)return 0;if(pE(e)){let t=e._readableState;return t&&t.objectMode===!1&&t.ended===!0&&Number.isFinite(t.length)?t.length:null}else{if(ax(e))return e.size!=null?e.size:null;if(px(e))return e.byteLength}return null}function hx(e){return e&&!!(e.destroyed||e[ix]||sx.isDestroyed?.(e))}function dx(e,t){e==null||!pE(e)||hx(e)||(typeof e.destroy=="function"?(Object.getPrototypeOf(e).constructor===Aae&&(e.socket=null),e.destroy(t)):t&&queueMicrotask(()=>{e.emit("error",t)}),e.destroyed!==!0&&(e[ix]=!0))}var Qae=/timeout=(\d+)/;function wae(e){let t=e.match(Qae);return t?parseInt(t[1],10)*1e3:null}function gx(e){return typeof e=="string"?hae[e]??e.toLowerCase():ox.lookup(e)??e.toString("latin1").toLowerCase()}function Sae(e){return ox.lookup(e)??e.toString("latin1").toLowerCase()}function _ae(e,t){t===void 0&&(t={});for(let r=0;ro.toString("latin1")):e[r+1].toString("latin1");n==="__proto__"?Object.defineProperty(t,n,{value:s,enumerable:!0,configurable:!0,writable:!0}):t[n]=s}else{let s=typeof e[r+1]=="string"?e[r+1]:Array.isArray(e[r+1])?e[r+1].map(o=>o.toString("latin1")):e[r+1].toString("latin1");t[n]=s}}return t}function vae(e){let t=e.length,r=new Array(t),n,i;for(let s=0;sBuffer.from(t))}function px(e){return e instanceof Uint8Array||Buffer.isBuffer(e)}function Dae(e,t,r){if(!e||typeof e!="object")throw new Nr("handler must be an object");if(typeof e.onRequestStart!="function"){if(typeof e.onConnect!="function")throw new Nr("invalid onConnect method");if(typeof e.onError!="function")throw new Nr("invalid onError method");if(typeof e.onBodySent!="function"&&e.onBodySent!==void 0)throw new Nr("invalid onBodySent method");if(r||t==="CONNECT"){if(typeof e.onUpgrade!="function")throw new Nr("invalid onUpgrade method")}else{if(typeof e.onHeaders!="function")throw new Nr("invalid onHeaders method");if(typeof e.onData!="function")throw new Nr("invalid onData method");if(typeof e.onComplete!="function")throw new Nr("invalid onComplete method")}}}function Tae(e){return!!(e&&(sx.isDisturbed(e)||e[Ec]))}function Nae(e){return{localAddress:e.localAddress,localPort:e.localPort,remoteAddress:e.remoteAddress,remotePort:e.remotePort,remoteFamily:e.remoteFamily,timeout:e.timeout,bytesWritten:e.bytesWritten,bytesRead:e.bytesRead}}function Mae(e){let t;return new ReadableStream({start(){t=e[Symbol.asyncIterator]()},pull(r){return t.next().then(({done:n,value:i})=>{if(n)return queueMicrotask(()=>{r.close(),r.byobRequest?.respond(0)});{let s=Buffer.isBuffer(i)?i:Buffer.from(i);return s.byteLength?r.enqueue(new Uint8Array(s)):this.pull(r)}})},cancel(){return t.return()},type:"bytes"})}function Ex(e){return e&&typeof e=="object"&&typeof e.append=="function"&&typeof e.delete=="function"&&typeof e.get=="function"&&typeof e.getAll=="function"&&typeof e.has=="function"&&typeof e.set=="function"&&e[Symbol.toStringTag]==="FormData"}function Fae(e,t){return"addEventListener"in e?(e.addEventListener("abort",t,{once:!0}),()=>e.removeEventListener("abort",t)):(e.once("abort",t),()=>e.removeListener("abort",t))}var yx=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);function kae(e){return yx[e]===1}var Uae=/^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;function xae(e){if(e.length>=12)return Uae.test(e);if(e.length===0)return!1;for(let t=0;t{if(!t.timeout)return rx;let r=null,n=null,i=hE.setFastTimeout(()=>{r=setImmediate(()=>{n=setImmediate(()=>nx(e.deref(),t))})},t.timeout);return()=>{hE.clearFastTimeout(i),clearImmediate(r),clearImmediate(n)}}:(e,t)=>{if(!t.timeout)return rx;let r=null,n=hE.setFastTimeout(()=>{r=setImmediate(()=>{nx(e.deref(),t)})},t.timeout);return()=>{hE.clearFastTimeout(n),clearImmediate(r)}};function nx(e,t){if(e==null)return;let r="Connect Timeout Error";Array.isArray(e.autoSelectFamilyAttemptedAddresses)?r+=` (attempted addresses: ${e.autoSelectFamilyAttemptedAddresses.join(", ")},`:r+=` (attempted address: ${t.hostname}:${t.port},`,r+=` timeout: ${t.timeout}ms)`,dx(e,new lae(r))}function Vae(e){if(e[0]==="h"&&e[1]==="t"&&e[2]==="t"&&e[3]==="p")switch(e[4]){case":":return"http:";case"s":if(e[5]===":")return"https:"}return e.slice(0,e.indexOf(":")+1)}var mx=Object.create(null);mx.enumerable=!0;var yQ={delete:"DELETE",DELETE:"DELETE",get:"GET",GET:"GET",head:"HEAD",HEAD:"HEAD",options:"OPTIONS",OPTIONS:"OPTIONS",post:"POST",POST:"POST",put:"PUT",PUT:"PUT"},Bx={...yQ,patch:"patch",PATCH:"PATCH"};Object.setPrototypeOf(yQ,null);Object.setPrototypeOf(Bx,null);Ix.exports={kEnumerableProperty:mx,isDisturbed:Tae,isBlobLike:ax,parseOrigin:yae,parseURL:ux,getServerName:Bae,isStream:pE,isIterable:cx,hasSafeIterator:Cae,isAsyncIterable:bae,isDestroyed:hx,headerNameToString:gx,bufferToLowerCasedHeaderName:Sae,addListener:qae,removeAllListeners:Gae,errorRequest:Yae,parseRawHeaders:vae,encodeRawHeaders:Rae,parseHeaders:_ae,parseKeepAliveTimeout:wae,destroy:dx,bodyLength:lx,deepClone:Iae,ReadableStreamFrom:Mae,isBuffer:px,assertRequestHandler:Dae,getSocketInfo:Nae,isFormDataLike:Ex,pathHasQueryOrFragment:Ax,serializePathWithQuery:Eae,addAbortListener:Fae,isValidHTTPToken:xae,isValidHeaderValue:Pae,isTokenCharCode:kae,parseRangeHeader:Hae,normalizedMethodRecordsBase:yQ,normalizedMethodRecords:Bx,isValidPort:fx,isHttpOrHttpsPrefixed:dE,nodeMajor:dae,nodeMinor:gae,safeHTTPMethods:Object.freeze(["GET","HEAD","OPTIONS","TRACE"]),wrapRequestBody:pae,setupConnectTimeout:Wae,getProtocolFromUrlString:Vae}});var Dx=U((GDe,Rx)=>{"use strict";var wx=Gt(),{Readable:Jae}=(ts(),Os(qt)),{RequestAbortedError:Sx,NotSupportedError:jae,InvalidArgumentError:zae,AbortError:EE}=mr(),_x=Zt(),{ReadableStreamFrom:Kae}=Zt(),Vn=Symbol("kConsume"),yE=Symbol("kReading"),df=Symbol("kBody"),bx=Symbol("kAbort"),vx=Symbol("kContentType"),mQ=Symbol("kContentLength"),BQ=Symbol("kUsed"),mE=Symbol("kBytesRead"),Xae=()=>{},IQ=class extends Jae{constructor({resume:t,abort:r,contentType:n="",contentLength:i,highWaterMark:s=64*1024}){super({autoDestroy:!0,read:t,highWaterMark:s}),this._readableState.dataEmitted=!1,this[bx]=r,this[Vn]=null,this[mE]=0,this[df]=null,this[BQ]=!1,this[vx]=n,this[mQ]=Number.isFinite(i)?i:null,this[yE]=!1}_destroy(t,r){!t&&!this._readableState.endEmitted&&(t=new Sx),t&&this[bx](),this[BQ]?r(t):setImmediate(r,t)}on(t,r){return(t==="data"||t==="readable")&&(this[yE]=!0,this[BQ]=!0),super.on(t,r)}addListener(t,r){return this.on(t,r)}off(t,r){let n=super.off(t,r);return(t==="data"||t==="readable")&&(this[yE]=this.listenerCount("data")>0||this.listenerCount("readable")>0),n}removeListener(t,r){return this.off(t,r)}push(t){return t&&(this[mE]+=t.length,this[Vn])?(CQ(this[Vn],t),this[yE]?super.push(t):!0):super.push(t)}text(){return Yh(this,"text")}json(){return Yh(this,"json")}blob(){return Yh(this,"blob")}bytes(){return Yh(this,"bytes")}arrayBuffer(){return Yh(this,"arrayBuffer")}async formData(){throw new jae}get bodyUsed(){return _x.isDisturbed(this)}get body(){return this[df]||(this[df]=Kae(this),this[Vn]&&(this[df].getReader(),wx(this[df].locked))),this[df]}dump(t){let r=t?.signal;if(r!=null&&(typeof r!="object"||!("aborted"in r)))return Promise.reject(new zae("signal must be an AbortSignal"));let n=t?.limit&&Number.isFinite(t.limit)?t.limit:128*1024;return r?.aborted?Promise.reject(r.reason??new EE):this._readableState.closeEmitted?Promise.resolve(null):new Promise((i,s)=>{if((this[mQ]&&this[mQ]>n||this[mE]>n)&&this.destroy(new EE),r){let o=()=>{this.destroy(r.reason??new EE)};r.addEventListener("abort",o),this.on("close",function(){r.removeEventListener("abort",o),r.aborted?s(r.reason??new EE):i(null)})}else this.on("close",i);this.on("error",Xae).on("data",()=>{this[mE]>n&&this.destroy()}).resume()})}setEncoding(t){return Buffer.isEncoding(t)&&(this._readableState.encoding=t),this}};function Zae(e){return e[df]?.locked===!0||e[Vn]!==null}function $ae(e){return _x.isDisturbed(e)||Zae(e)}function Yh(e,t){return wx(!e[Vn]),new Promise((r,n)=>{if($ae(e)){let i=e._readableState;i.destroyed&&i.closeEmitted===!1?e.on("error",n).on("close",()=>{n(new TypeError("unusable"))}):n(i.errored??new TypeError("unusable"))}else queueMicrotask(()=>{e[Vn]={type:t,stream:e,resolve:r,reject:n,length:0,body:[]},e.on("error",function(i){QQ(this[Vn],i)}).on("close",function(){this[Vn].body!==null&&QQ(this[Vn],new Sx)}),eAe(e[Vn])})})}function eAe(e){if(e.body===null)return;let{_readableState:t}=e.stream;if(t.bufferIndex){let r=t.bufferIndex,n=t.buffer.length;for(let i=r;i2&&n[0]===239&&n[1]===187&&n[2]===191?3:0;return!r||r==="utf8"||r==="utf-8"?n.utf8Slice(s,i):n.subarray(s,i).toString(r)}function Cx(e,t){if(e.length===0||t===0)return new Uint8Array(0);if(e.length===1)return new Uint8Array(e[0]);let r=new Uint8Array(Buffer.allocUnsafeSlow(t).buffer),n=0;for(let i=0;i{"use strict";var tAe=Gt(),{AsyncResource:rAe}=gc(),{Readable:nAe}=Dx(),{InvalidArgumentError:mc,RequestAbortedError:Tx}=mr(),yi=Zt();function Wh(){}var BE=class extends rAe{constructor(t,r){if(!t||typeof t!="object")throw new mc("invalid opts");let{signal:n,method:i,opaque:s,body:o,onInfo:a,responseHeaders:A,highWaterMark:f}=t;try{if(typeof r!="function")throw new mc("invalid callback");if(f&&(typeof f!="number"||f<0))throw new mc("invalid highWaterMark");if(n&&typeof n.on!="function"&&typeof n.addEventListener!="function")throw new mc("signal must be an EventEmitter or EventTarget");if(i==="CONNECT")throw new mc("invalid method");if(a&&typeof a!="function")throw new mc("invalid onInfo callback");super("UNDICI_REQUEST")}catch(l){throw yi.isStream(o)&&yi.destroy(o.on("error",Wh),l),l}this.method=i,this.responseHeaders=A||null,this.opaque=s||null,this.callback=r,this.res=null,this.abort=null,this.body=o,this.trailers={},this.context=null,this.onInfo=a||null,this.highWaterMark=f,this.reason=null,this.removeAbortListener=null,n?.aborted?this.reason=n.reason??new Tx:n&&(this.removeAbortListener=yi.addAbortListener(n,()=>{this.reason=n.reason??new Tx,this.res?yi.destroy(this.res.on("error",Wh),this.reason):this.abort&&this.abort(this.reason)}))}onConnect(t,r){if(this.reason){t(this.reason);return}tAe(this.callback),this.abort=t,this.context=r}onHeaders(t,r,n,i){let{callback:s,opaque:o,abort:a,context:A,responseHeaders:f,highWaterMark:l}=this,p=f==="raw"?yi.parseRawHeaders(r):yi.parseHeaders(r);if(t<200){this.onInfo&&this.onInfo({statusCode:t,headers:p});return}let I=f==="raw"?yi.parseHeaders(r):p,S=I["content-type"],_=I["content-length"],N=new nAe({resume:n,abort:a,contentType:S,contentLength:this.method!=="HEAD"&&_?Number(_):null,highWaterMark:l});if(this.removeAbortListener&&(N.on("close",this.removeAbortListener),this.removeAbortListener=null),this.callback=null,this.res=N,s!==null)try{this.runInAsyncScope(s,null,null,{statusCode:t,statusText:i,headers:p,trailers:this.trailers,opaque:o,body:N,context:A})}catch(O){this.res=null,yi.destroy(N.on("error",Wh),O),queueMicrotask(()=>{throw O})}}onData(t){return this.res.push(t)}onComplete(t){yi.parseHeaders(t,this.trailers),this.res.push(null)}onError(t){let{res:r,callback:n,body:i,opaque:s}=this;n&&(this.callback=null,queueMicrotask(()=>{this.runInAsyncScope(n,null,t,{opaque:s})})),r&&(this.res=null,queueMicrotask(()=>{yi.destroy(r.on("error",Wh),t)})),i&&(this.body=null,yi.isStream(i)&&(i.on("error",Wh),yi.destroy(i,t))),this.removeAbortListener&&(this.removeAbortListener(),this.removeAbortListener=null)}};function Nx(e,t){if(t===void 0)return new Promise((r,n)=>{Nx.call(this,e,(i,s)=>i?n(i):r(s))});try{let r=new BE(e,t);this.dispatch(e,r)}catch(r){if(typeof t!="function")throw r;let n=e?.opaque;queueMicrotask(()=>t(r,{opaque:n}))}}wQ.exports=Nx;wQ.exports.RequestHandler=BE});var Vh=U((WDe,Ux)=>{"use strict";var{addAbortListener:iAe}=Zt(),{RequestAbortedError:sAe}=mr(),Bc=Symbol("kListener"),Xs=Symbol("kSignal");function Fx(e){e.abort?e.abort(e[Xs]?.reason):e.reason=e[Xs]?.reason??new sAe,kx(e)}function oAe(e,t){if(e.reason=null,e[Xs]=null,e[Bc]=null,!!t){if(t.aborted){Fx(e);return}e[Xs]=t,e[Bc]=()=>{Fx(e)},iAe(e[Xs],e[Bc])}}function kx(e){e[Xs]&&("removeEventListener"in e[Xs]?e[Xs].removeEventListener("abort",e[Bc]):e[Xs].removeListener("abort",e[Bc]),e[Xs]=null,e[Bc]=null)}Ux.exports={addSignal:oAe,removeSignal:kx}});var Ox=U((VDe,Px)=>{"use strict";var aAe=Gt(),{finished:AAe}=(ts(),Os(qt)),{AsyncResource:fAe}=gc(),{InvalidArgumentError:Ic,InvalidReturnValueError:uAe}=mr(),jo=Zt(),{addSignal:cAe,removeSignal:xx}=Vh();function lAe(){}var SQ=class extends fAe{constructor(t,r,n){if(!t||typeof t!="object")throw new Ic("invalid opts");let{signal:i,method:s,opaque:o,body:a,onInfo:A,responseHeaders:f}=t;try{if(typeof n!="function")throw new Ic("invalid callback");if(typeof r!="function")throw new Ic("invalid factory");if(i&&typeof i.on!="function"&&typeof i.addEventListener!="function")throw new Ic("signal must be an EventEmitter or EventTarget");if(s==="CONNECT")throw new Ic("invalid method");if(A&&typeof A!="function")throw new Ic("invalid onInfo callback");super("UNDICI_STREAM")}catch(l){throw jo.isStream(a)&&jo.destroy(a.on("error",lAe),l),l}this.responseHeaders=f||null,this.opaque=o||null,this.factory=r,this.callback=n,this.res=null,this.abort=null,this.context=null,this.trailers=null,this.body=a,this.onInfo=A||null,jo.isStream(a)&&a.on("error",l=>{this.onError(l)}),cAe(this,i)}onConnect(t,r){if(this.reason){t(this.reason);return}aAe(this.callback),this.abort=t,this.context=r}onHeaders(t,r,n,i){let{factory:s,opaque:o,context:a,responseHeaders:A}=this,f=A==="raw"?jo.parseRawHeaders(r):jo.parseHeaders(r);if(t<200){this.onInfo&&this.onInfo({statusCode:t,headers:f});return}if(this.factory=null,s===null)return;let l=this.runInAsyncScope(s,null,{statusCode:t,headers:f,opaque:o,context:a});if(!l||typeof l.write!="function"||typeof l.end!="function"||typeof l.on!="function")throw new uAe("expected Writable");return AAe(l,{readable:!1},I=>{let{callback:S,res:_,opaque:N,trailers:O,abort:x}=this;this.res=null,(I||!_?.readable)&&jo.destroy(_,I),this.callback=null,this.runInAsyncScope(S,null,I||null,{opaque:N,trailers:O}),I&&x()}),l.on("drain",n),this.res=l,(l.writableNeedDrain!==void 0?l.writableNeedDrain:l._writableState?.needDrain)!==!0}onData(t){let{res:r}=this;return r?r.write(t):!0}onComplete(t){let{res:r}=this;xx(this),r&&(this.trailers=jo.parseHeaders(t),r.end())}onError(t){let{res:r,callback:n,opaque:i,body:s}=this;xx(this),this.factory=null,r?(this.res=null,jo.destroy(r,t)):n&&(this.callback=null,queueMicrotask(()=>{this.runInAsyncScope(n,null,t,{opaque:i})})),s&&(this.body=null,jo.destroy(s,t))}};function Lx(e,t,r){if(r===void 0)return new Promise((n,i)=>{Lx.call(this,e,t,(s,o)=>s?i(s):n(o))});try{let n=new SQ(e,t,r);this.dispatch(e,n)}catch(n){if(typeof r!="function")throw n;let i=e?.opaque;queueMicrotask(()=>r(n,{opaque:i}))}}Px.exports=Lx});var Yx=U((JDe,Gx)=>{"use strict";var{Readable:qx,Duplex:hAe,PassThrough:dAe}=(ts(),Os(qt)),gAe=Gt(),{AsyncResource:pAe}=gc(),{InvalidArgumentError:Jh,InvalidReturnValueError:EAe,RequestAbortedError:_Q}=mr(),Zs=Zt(),{addSignal:yAe,removeSignal:mAe}=Vh();function Hx(){}var bc=Symbol("resume"),vQ=class extends qx{constructor(){super({autoDestroy:!0}),this[bc]=null}_read(){let{[bc]:t}=this;t&&(this[bc]=null,t())}_destroy(t,r){this._read(),r(t)}},RQ=class extends qx{constructor(t){super({autoDestroy:!0}),this[bc]=t}_read(){this[bc]()}_destroy(t,r){!t&&!this._readableState.endEmitted&&(t=new _Q),r(t)}},DQ=class extends pAe{constructor(t,r){if(!t||typeof t!="object")throw new Jh("invalid opts");if(typeof r!="function")throw new Jh("invalid handler");let{signal:n,method:i,opaque:s,onInfo:o,responseHeaders:a}=t;if(n&&typeof n.on!="function"&&typeof n.addEventListener!="function")throw new Jh("signal must be an EventEmitter or EventTarget");if(i==="CONNECT")throw new Jh("invalid method");if(o&&typeof o!="function")throw new Jh("invalid onInfo callback");super("UNDICI_PIPELINE"),this.opaque=s||null,this.responseHeaders=a||null,this.handler=r,this.abort=null,this.context=null,this.onInfo=o||null,this.req=new vQ().on("error",Hx),this.ret=new hAe({readableObjectMode:t.objectMode,autoDestroy:!0,read:()=>{let{body:A}=this;A?.resume&&A.resume()},write:(A,f,l)=>{let{req:p}=this;p.push(A,f)||p._readableState.destroyed?l():p[bc]=l},destroy:(A,f)=>{let{body:l,req:p,res:I,ret:S,abort:_}=this;!A&&!S._readableState.endEmitted&&(A=new _Q),_&&A&&_(),Zs.destroy(l,A),Zs.destroy(p,A),Zs.destroy(I,A),mAe(this),f(A)}}).on("prefinish",()=>{let{req:A}=this;A.push(null)}),this.res=null,yAe(this,n)}onConnect(t,r){let{res:n}=this;if(this.reason){t(this.reason);return}gAe(!n,"pipeline cannot be retried"),this.abort=t,this.context=r}onHeaders(t,r,n){let{opaque:i,handler:s,context:o}=this;if(t<200){if(this.onInfo){let A=this.responseHeaders==="raw"?Zs.parseRawHeaders(r):Zs.parseHeaders(r);this.onInfo({statusCode:t,headers:A})}return}this.res=new RQ(n);let a;try{this.handler=null;let A=this.responseHeaders==="raw"?Zs.parseRawHeaders(r):Zs.parseHeaders(r);a=this.runInAsyncScope(s,null,{statusCode:t,headers:A,opaque:i,body:this.res,context:o})}catch(A){throw this.res.on("error",Hx),A}if(!a||typeof a.on!="function")throw new EAe("expected Readable");a.on("data",A=>{let{ret:f,body:l}=this;!f.push(A)&&l.pause&&l.pause()}).on("error",A=>{let{ret:f}=this;Zs.destroy(f,A)}).on("end",()=>{let{ret:A}=this;A.push(null)}).on("close",()=>{let{ret:A}=this;A._readableState.ended||Zs.destroy(A,new _Q)}),this.body=a}onData(t){let{res:r}=this;return r.push(t)}onComplete(t){let{res:r}=this;r.push(null)}onError(t){let{ret:r}=this;this.handler=null,Zs.destroy(r,t)}};function BAe(e,t){try{let r=new DQ(e,t);return this.dispatch({...e,body:r.req},r),r.ret}catch(r){return new dAe().destroy(r)}}Gx.exports=BAe});var Kx=U((jDe,zx)=>{"use strict";var{InvalidArgumentError:TQ,SocketError:IAe}=mr(),{AsyncResource:bAe}=gc(),Wx=Gt(),Vx=Zt(),{kHTTP2Stream:CAe}=Dn(),{addSignal:QAe,removeSignal:Jx}=Vh(),NQ=class extends bAe{constructor(t,r){if(!t||typeof t!="object")throw new TQ("invalid opts");if(typeof r!="function")throw new TQ("invalid callback");let{signal:n,opaque:i,responseHeaders:s}=t;if(n&&typeof n.on!="function"&&typeof n.addEventListener!="function")throw new TQ("signal must be an EventEmitter or EventTarget");super("UNDICI_UPGRADE"),this.responseHeaders=s||null,this.opaque=i||null,this.callback=r,this.abort=null,this.context=null,QAe(this,n)}onConnect(t,r){if(this.reason){t(this.reason);return}Wx(this.callback),this.abort=t,this.context=null}onHeaders(){throw new IAe("bad upgrade",null)}onUpgrade(t,r,n){Wx(n[CAe]===!0?t===200:t===101);let{callback:i,opaque:s,context:o}=this;Jx(this),this.callback=null;let a=this.responseHeaders==="raw"?Vx.parseRawHeaders(r):Vx.parseHeaders(r);this.runInAsyncScope(i,null,null,{headers:a,socket:n,opaque:s,context:o})}onError(t){let{callback:r,opaque:n}=this;Jx(this),r&&(this.callback=null,queueMicrotask(()=>{this.runInAsyncScope(r,null,t,{opaque:n})}))}};function jx(e,t){if(t===void 0)return new Promise((r,n)=>{jx.call(this,e,(i,s)=>i?n(i):r(s))});try{let r=new NQ(e,t),n={...e,method:e.method||"GET",upgrade:e.protocol||"Websocket"};this.dispatch(n,r)}catch(r){if(typeof t!="function")throw r;let n=e?.opaque;queueMicrotask(()=>t(r,{opaque:n}))}}zx.exports=jx});var t6=U((zDe,e6)=>{"use strict";var wAe=Gt(),{AsyncResource:SAe}=gc(),{InvalidArgumentError:MQ,SocketError:_Ae}=mr(),Xx=Zt(),{addSignal:vAe,removeSignal:Zx}=Vh(),FQ=class extends SAe{constructor(t,r){if(!t||typeof t!="object")throw new MQ("invalid opts");if(typeof r!="function")throw new MQ("invalid callback");let{signal:n,opaque:i,responseHeaders:s}=t;if(n&&typeof n.on!="function"&&typeof n.addEventListener!="function")throw new MQ("signal must be an EventEmitter or EventTarget");super("UNDICI_CONNECT"),this.opaque=i||null,this.responseHeaders=s||null,this.callback=r,this.abort=null,vAe(this,n)}onConnect(t,r){if(this.reason){t(this.reason);return}wAe(this.callback),this.abort=t,this.context=r}onHeaders(){throw new _Ae("bad connect",null)}onUpgrade(t,r,n){let{callback:i,opaque:s,context:o}=this;Zx(this),this.callback=null;let a=r;a!=null&&(a=this.responseHeaders==="raw"?Xx.parseRawHeaders(r):Xx.parseHeaders(r)),this.runInAsyncScope(i,null,null,{statusCode:t,headers:a,socket:n,opaque:s,context:o})}onError(t){let{callback:r,opaque:n}=this;Zx(this),r&&(this.callback=null,queueMicrotask(()=>{this.runInAsyncScope(r,null,t,{opaque:n})}))}};function $x(e,t){if(t===void 0)return new Promise((r,n)=>{$x.call(this,e,(i,s)=>i?n(i):r(s))});try{let r=new FQ(e,t),n={...e,method:"CONNECT"};this.dispatch(n,r)}catch(r){if(typeof t!="function")throw r;let n=e?.opaque;queueMicrotask(()=>t(r,{opaque:n}))}}e6.exports=$x});var r6=U((KDe,Cc)=>{"use strict";Cc.exports.request=Mx();Cc.exports.stream=Ox();Cc.exports.pipeline=Yx();Cc.exports.upgrade=Kx();Cc.exports.connect=t6()});var i6=U((XDe,n6)=>{"use strict";var{InvalidArgumentError:RAe}=mr(),_r,Qc;n6.exports=(Qc=class{constructor(t){wt(this,_r);ft(this,_r,t)}static wrap(t){return t.onRequestStart?t:new Qc(t)}onConnect(t,r){return ee(this,_r).onConnect?.(t,r)}onResponseStarted(){return ee(this,_r).onResponseStarted?.()}onHeaders(t,r,n,i){return ee(this,_r).onHeaders?.(t,r,n,i)}onUpgrade(t,r,n){return ee(this,_r).onUpgrade?.(t,r,n)}onData(t){return ee(this,_r).onData?.(t)}onComplete(t){return ee(this,_r).onComplete?.(t)}onError(t){if(!ee(this,_r).onError)throw t;return ee(this,_r).onError?.(t)}onRequestStart(t,r){ee(this,_r).onConnect?.(n=>t.abort(n),r)}onRequestUpgrade(t,r,n,i){let s=[];for(let[o,a]of Object.entries(n))s.push(Buffer.from(o,"latin1"),kQ(a));ee(this,_r).onUpgrade?.(r,s,i)}onResponseStart(t,r,n,i){let s=[];for(let[o,a]of Object.entries(n))s.push(Buffer.from(o,"latin1"),kQ(a));ee(this,_r).onHeaders?.(r,s,()=>t.resume(),i)===!1&&t.pause()}onResponseData(t,r){ee(this,_r).onData?.(r)===!1&&t.pause()}onResponseEnd(t,r){let n=[];for(let[i,s]of Object.entries(r))n.push(Buffer.from(i,"latin1"),kQ(s));ee(this,_r).onComplete?.(n)}onResponseError(t,r){if(!ee(this,_r).onError)throw new RAe("invalid onError method");ee(this,_r).onError?.(r)}},_r=new WeakMap,Qc);function kQ(e){return Array.isArray(e)?e.map(t=>Buffer.from(t,"latin1")):Buffer.from(e,"latin1")}});var o6=U(($De,s6)=>{"use strict";var DAe=Zi(),TAe=i6(),NAe=e=>(t,r)=>e(t,TAe.wrap(r)),UQ=class extends DAe{dispatch(){throw new Error("not implemented")}close(){throw new Error("not implemented")}destroy(){throw new Error("not implemented")}compose(...t){let r=Array.isArray(t[0])?t[0]:t,n=this.dispatch.bind(this);for(let i of r)if(i!=null){if(typeof i!="function")throw new TypeError(`invalid interceptor, expected function received ${typeof i}`);if(n=i(n),n=NAe(n),n==null||typeof n!="function"||n.length!==2)throw new TypeError("invalid interceptor")}return new Proxy(this,{get:(i,s)=>s==="dispatch"?n:i[s]})}};s6.exports=UQ});var f6=U((eTe,A6)=>{"use strict";var{parseHeaders:xQ}=Zt(),{InvalidArgumentError:MAe}=mr(),LQ=Symbol("resume"),a6,gf,jh,wc,zh;a6=LQ;var PQ=class{constructor(t){wt(this,gf,!1);wt(this,jh,null);wt(this,wc,!1);wt(this,zh);y(this,a6,null);ft(this,zh,t)}pause(){ft(this,gf,!0)}resume(){ee(this,gf)&&(ft(this,gf,!1),this[LQ]?.())}abort(t){ee(this,wc)||(ft(this,wc,!0),ft(this,jh,t),ee(this,zh).call(this,t))}get aborted(){return ee(this,wc)}get reason(){return ee(this,jh)}get paused(){return ee(this,gf)}};gf=new WeakMap,jh=new WeakMap,wc=new WeakMap,zh=new WeakMap;var mi,Jn,Sc;A6.exports=(Sc=class{constructor(t){wt(this,mi);wt(this,Jn);ft(this,mi,t)}static unwrap(t){return t.onRequestStart?new Sc(t):t}onConnect(t,r){ft(this,Jn,new PQ(t)),ee(this,mi).onRequestStart?.(ee(this,Jn),r)}onResponseStarted(){return ee(this,mi).onResponseStarted?.()}onUpgrade(t,r,n){ee(this,mi).onRequestUpgrade?.(ee(this,Jn),t,xQ(r),n)}onHeaders(t,r,n,i){return ee(this,Jn)[LQ]=n,ee(this,mi).onResponseStart?.(ee(this,Jn),t,xQ(r),i),!ee(this,Jn).paused}onData(t){return ee(this,mi).onResponseData?.(ee(this,Jn),t),!ee(this,Jn).paused}onComplete(t){ee(this,mi).onResponseEnd?.(ee(this,Jn),xQ(t))}onError(t){if(!ee(this,mi).onResponseError)throw new MAe("invalid onError method");ee(this,mi).onResponseError?.(ee(this,Jn),t)}},mi=new WeakMap,Jn=new WeakMap,Sc)});var bE=U((rTe,g6)=>{"use strict";var FAe=o6(),kAe=f6(),{ClientDestroyedError:OQ,ClientClosedError:UAe,InvalidArgumentError:IE}=mr(),{kDestroy:xAe,kClose:LAe,kClosed:Kh,kDestroyed:_c,kDispatch:PAe}=Dn(),$s=Symbol("onDestroyed"),zo=Symbol("onClosed"),u6,c6,l6,h6,d6,HQ=class extends(d6=FAe,h6=_c,l6=$s,c6=Kh,u6=zo,d6){constructor(){super(...arguments);y(this,h6,!1);y(this,l6,null);y(this,c6,!1);y(this,u6,null)}get destroyed(){return this[_c]}get closed(){return this[Kh]}close(r){if(r===void 0)return new Promise((i,s)=>{this.close((o,a)=>o?s(o):i(a))});if(typeof r!="function")throw new IE("invalid callback");if(this[_c]){let i=new OQ;queueMicrotask(()=>r(i,null));return}if(this[Kh]){this[zo]?this[zo].push(r):queueMicrotask(()=>r(null,null));return}this[Kh]=!0,this[zo]??(this[zo]=[]),this[zo].push(r);let n=()=>{let i=this[zo];this[zo]=null;for(let s=0;sthis.destroy()).then(()=>queueMicrotask(n))}destroy(r,n){if(typeof r=="function"&&(n=r,r=null),n===void 0)return new Promise((s,o)=>{this.destroy(r,(a,A)=>a?o(a):s(A))});if(typeof n!="function")throw new IE("invalid callback");if(this[_c]){this[$s]?this[$s].push(n):queueMicrotask(()=>n(null,null));return}r||(r=new OQ),this[_c]=!0,this[$s]??(this[$s]=[]),this[$s].push(n);let i=()=>{let s=this[$s];this[$s]=null;for(let o=0;oqueueMicrotask(i))}dispatch(r,n){if(!n||typeof n!="object")throw new IE("handler must be an object");n=kAe.unwrap(n);try{if(!r||typeof r!="object")throw new IE("opts must be an object.");if(this[_c]||this[$s])throw new OQ;if(this[Kh])throw new UAe;return this[PAe](r,n)}catch(i){if(typeof n.onError!="function")throw i;return n.onError(i),!1}}};g6.exports=HQ});var YQ=U((iTe,B6)=>{"use strict";var{kConnected:p6,kPending:E6,kRunning:y6,kSize:m6,kFree:OAe,kQueued:HAe}=Dn(),qQ=class{constructor(t){this.connected=t[p6],this.pending=t[E6],this.running=t[y6],this.size=t[m6]}},GQ=class{constructor(t){this.connected=t[p6],this.free=t[OAe],this.pending=t[E6],this.queued=t[HAe],this.running=t[y6],this.size=t[m6]}};B6.exports={ClientStats:qQ,PoolStats:GQ}});var b6=U((oTe,I6)=>{"use strict";var CE=class{constructor(){y(this,"bottom",0);y(this,"top",0);y(this,"list",new Array(2048).fill(void 0));y(this,"next",null)}isEmpty(){return this.top===this.bottom}isFull(){return(this.top+1&2047)===this.bottom}push(t){this.list[this.top]=t,this.top=this.top+1&2047}shift(){let t=this.list[this.bottom];return t===void 0?null:(this.list[this.bottom]=void 0,this.bottom=this.bottom+1&2047,t)}};I6.exports=class{constructor(){this.head=this.tail=new CE}isEmpty(){return this.head.isEmpty()}push(t){this.head.isFull()&&(this.head=this.head.next=new CE),this.head.push(t)}shift(){let t=this.tail,r=t.shift();return t.isEmpty()&&t.next!==null&&(this.tail=t.next,t.next=null),r}}});var P6=U((ATe,L6)=>{"use strict";var{PoolStats:qAe}=YQ(),GAe=bE(),YAe=b6(),{kConnected:WQ,kSize:C6,kRunning:Q6,kPending:w6,kQueued:Xh,kBusy:WAe,kFree:VAe,kUrl:JAe,kClose:jAe,kDestroy:zAe,kDispatch:KAe}=Dn(),Mr=Symbol("clients"),pn=Symbol("needDrain"),Zh=Symbol("queue"),VQ=Symbol("closed resolve"),JQ=Symbol("onDrain"),S6=Symbol("onConnect"),_6=Symbol("onDisconnect"),v6=Symbol("onConnectionError"),jQ=Symbol("get dispatcher"),U6=Symbol("add client"),x6=Symbol("remove client"),R6,D6,T6,N6,M6,F6,k6,zQ=class extends GAe{constructor(){super(...arguments);y(this,k6,new YAe);y(this,F6,0);y(this,M6,[]);y(this,N6,!1);y(this,T6,(r,n)=>{this.emit("connect",r,[this,...n])});y(this,D6,(r,n,i)=>{this.emit("disconnect",r,[this,...n],i)});y(this,R6,(r,n,i)=>{this.emit("connectionError",r,[this,...n],i)})}[(k6=Zh,F6=Xh,M6=Mr,N6=pn,JQ)](r,n,i){let s=this[Zh],o=!1;for(;!o;){let a=s.shift();if(!a)break;this[Xh]--,o=!r.dispatch(a.opts,a.handler)}if(r[pn]=o,!o&&this[pn]&&(this[pn]=!1,this.emit("drain",n,[this,...i])),this[VQ]&&s.isEmpty()){let a=[];for(let A=0;A{this[VQ]=r})}[zAe](r){for(;;){let i=this[Zh].shift();if(!i)break;i.handler.onError(r)}let n=new Array(this[Mr].length);for(let i=0;i{this[pn]&&this[JQ](r,r[JAe],[r,this])}),this}[x6](r){r.close(()=>{let n=this[Mr].indexOf(r);n!==-1&&this[Mr].splice(n,1)}),this[pn]=this[Mr].some(n=>!n[pn]&&n.closed!==!0&&n.destroyed!==!0)}};L6.exports={PoolBase:zQ,kClients:Mr,kNeedDrain:pn,kAddClient:U6,kRemoveClient:x6,kGetDispatcher:jQ}});var q6=U((uTe,H6)=>{"use strict";var O6=new Map,KQ=new Map;function QE(e){let t=O6.get(e);return t||(t=new Set,O6.set(e,t)),t}function XAe(e){return{name:e,get hasSubscribers(){return QE(e).size>0},publish(t){for(let r of QE(e))r(t,e)},subscribe(t){return QE(e).add(t),this},unsubscribe(t){return QE(e).delete(t),this}}}function wE(e){return KQ.has(e)||KQ.set(e,XAe(e)),KQ.get(e)}function ZAe(e,t){wE(e).subscribe(t)}function $Ae(e,t){wE(e).unsubscribe(t)}H6.exports={channel:wE,hasSubscribers(e){return wE(e).hasSubscribers},subscribe:ZAe,unsubscribe:$Ae}});var ed=U((cTe,Y6)=>{"use strict";var Mt=q6(),ew=Yr(),pf=ew.debuglog("undici"),$h=ew.debuglog("fetch"),SE=ew.debuglog("websocket"),jn={beforeConnect:Mt.channel("undici:client:beforeConnect"),connected:Mt.channel("undici:client:connected"),connectError:Mt.channel("undici:client:connectError"),sendHeaders:Mt.channel("undici:client:sendHeaders"),create:Mt.channel("undici:request:create"),bodySent:Mt.channel("undici:request:bodySent"),bodyChunkSent:Mt.channel("undici:request:bodyChunkSent"),bodyChunkReceived:Mt.channel("undici:request:bodyChunkReceived"),headers:Mt.channel("undici:request:headers"),trailers:Mt.channel("undici:request:trailers"),error:Mt.channel("undici:request:error"),open:Mt.channel("undici:websocket:open"),close:Mt.channel("undici:websocket:close"),socketError:Mt.channel("undici:websocket:socket_error"),ping:Mt.channel("undici:websocket:ping"),pong:Mt.channel("undici:websocket:pong"),proxyConnected:Mt.channel("undici:proxy:connected")},XQ=!1;function G6(e=pf){if(!XQ){if(jn.beforeConnect.hasSubscribers||jn.connected.hasSubscribers||jn.connectError.hasSubscribers||jn.sendHeaders.hasSubscribers){XQ=!0;return}XQ=!0,Mt.subscribe("undici:client:beforeConnect",t=>{let{connectParams:{version:r,protocol:n,port:i,host:s}}=t;e("connecting to %s%s using %s%s",s,i?`:${i}`:"",n,r)}),Mt.subscribe("undici:client:connected",t=>{let{connectParams:{version:r,protocol:n,port:i,host:s}}=t;e("connected to %s%s using %s%s",s,i?`:${i}`:"",n,r)}),Mt.subscribe("undici:client:connectError",t=>{let{connectParams:{version:r,protocol:n,port:i,host:s},error:o}=t;e("connection to %s%s using %s%s errored - %s",s,i?`:${i}`:"",n,r,o.message)}),Mt.subscribe("undici:client:sendHeaders",t=>{let{request:{method:r,path:n,origin:i}}=t;e("sending request to %s %s%s",r,i,n)})}}var ZQ=!1;function efe(e=pf){if(!ZQ){if(jn.headers.hasSubscribers||jn.trailers.hasSubscribers||jn.error.hasSubscribers){ZQ=!0;return}ZQ=!0,Mt.subscribe("undici:request:headers",t=>{let{request:{method:r,path:n,origin:i},response:{statusCode:s}}=t;e("received response to %s %s%s - HTTP %d",r,i,n,s)}),Mt.subscribe("undici:request:trailers",t=>{let{request:{method:r,path:n,origin:i}}=t;e("trailers received from %s %s%s",r,i,n)}),Mt.subscribe("undici:request:error",t=>{let{request:{method:r,path:n,origin:i},error:s}=t;e("request to %s %s%s errored - %s",r,i,n,s.message)})}}var $Q=!1;function tfe(e=SE){if(!$Q){if(jn.open.hasSubscribers||jn.close.hasSubscribers||jn.socketError.hasSubscribers||jn.ping.hasSubscribers||jn.pong.hasSubscribers){$Q=!0;return}$Q=!0,Mt.subscribe("undici:websocket:open",t=>{if(t.address!=null){let{address:r,port:n}=t.address;e("connection opened %s%s",r,n?`:${n}`:"")}else e("connection opened")}),Mt.subscribe("undici:websocket:close",t=>{let{websocket:r,code:n,reason:i}=t;e("closed connection to %s - %s %s",r.url,n,i)}),Mt.subscribe("undici:websocket:socket_error",t=>{e("connection errored - %s",t.message)}),Mt.subscribe("undici:websocket:ping",t=>{e("ping received")}),Mt.subscribe("undici:websocket:pong",t=>{e("pong received")})}}(pf.enabled||$h.enabled)&&(G6($h.enabled?$h:pf),efe($h.enabled?$h:pf));SE.enabled&&(G6(pf.enabled?pf:SE),tfe(SE));Y6.exports={channels:jn}});var J6=U((lTe,V6)=>{"use strict";var{InvalidArgumentError:Tt,NotSupportedError:rfe}=mr(),eo=Gt(),{isValidHTTPToken:tw,isValidHeaderValue:rw,isStream:nfe,destroy:ife,isBuffer:sfe,isFormDataLike:ofe,isIterable:afe,hasSafeIterator:Afe,isBlobLike:ffe,serializePathWithQuery:ufe,assertRequestHandler:cfe,getServerName:lfe,normalizedMethodRecords:hfe,getProtocolFromUrlString:dfe}=Zt(),{channels:Tn}=ed(),{headerNameLowerCasedRecord:W6}=cE(),gfe=/[^\u0021-\u00ff]/,Bi=Symbol("handler"),nw=class{constructor(t,{path:r,method:n,body:i,headers:s,query:o,idempotent:a,blocking:A,upgrade:f,headersTimeout:l,bodyTimeout:p,reset:I,expectContinue:S,servername:_,throwOnError:N,maxRedirections:O,typeOfService:x},G){if(typeof r!="string")throw new Tt("path must be a string");if(r[0]!=="/"&&!(r.startsWith("http://")||r.startsWith("https://"))&&n!=="CONNECT")throw new Tt("path must be an absolute URL or start with a slash");if(gfe.test(r))throw new Tt("invalid request path");if(typeof n!="string")throw new Tt("method must be a string");if(hfe[n]===void 0&&!tw(n))throw new Tt("invalid request method");if(f&&typeof f!="string")throw new Tt("upgrade must be a string");if(f&&!rw(f))throw new Tt("invalid upgrade header");if(l!=null&&(!Number.isFinite(l)||l<0))throw new Tt("invalid headersTimeout");if(p!=null&&(!Number.isFinite(p)||p<0))throw new Tt("invalid bodyTimeout");if(I!=null&&typeof I!="boolean")throw new Tt("invalid reset");if(S!=null&&typeof S!="boolean")throw new Tt("invalid expectContinue");if(N!=null)throw new Tt("invalid throwOnError");if(O!=null&&O!==0)throw new Tt("maxRedirections is not supported, use the redirect interceptor");if(x!=null&&(!Number.isInteger(x)||x<0||x>255))throw new Tt("typeOfService must be an integer between 0 and 255");if(this.headersTimeout=l,this.bodyTimeout=p,this.method=n,this.typeOfService=x??0,this.abort=null,i==null)this.body=null;else if(nfe(i)){this.body=i;let Y=this.body._readableState;(!Y||!Y.autoDestroy)&&(this.endHandler=function(){ife(this)},this.body.on("end",this.endHandler)),this.errorHandler=X=>{this.abort?this.abort(X):this.error=X},this.body.on("error",this.errorHandler)}else if(sfe(i))this.body=i.byteLength?i:null;else if(ArrayBuffer.isView(i))this.body=i.buffer.byteLength?Buffer.from(i.buffer,i.byteOffset,i.byteLength):null;else if(i instanceof ArrayBuffer)this.body=i.byteLength?Buffer.from(i):null;else if(typeof i=="string")this.body=i.length?Buffer.from(i):null;else if(ofe(i)||afe(i)||ffe(i))this.body=i;else throw new Tt("body must be a string, a Buffer, a Readable stream, an iterable, or an async iterable");if(this.completed=!1,this.aborted=!1,this.upgrade=f||null,this.path=o?ufe(r,o):r,this.origin=t,this.protocol=dfe(t),this.idempotent=a??(n==="HEAD"||n==="GET"),this.blocking=A??this.method!=="HEAD",this.reset=I??null,this.host=null,this.contentLength=null,this.contentType=null,this.headers=[],this.expectContinue=S??!1,Array.isArray(s)){if(s.length%2!==0)throw new Tt("headers array must be even");for(let Y=0;Y{"use strict";function pfe(){let e=globalThis._tlsModule;if(!e)throw new Error("node:tls bridge module is not available");return e}var j6={};for(let e of["connect","createServer","createSecureContext","TLSSocket","Server","checkServerIdentity","getCiphers","rootCertificates"])Object.defineProperty(j6,e,{enumerable:!0,get(){return pfe()[e]}});z6.exports=j6});var sw=U((gTe,$6)=>{"use strict";var Efe=AE(),X6=Gt(),Z6=Zt(),{InvalidArgumentError:yfe}=mr(),iw,mfe=class{constructor(t){this._maxCachedSessions=t,this._sessionCache=new Map,this._sessionRegistry=new FinalizationRegistry(r=>{if(this._sessionCache.size{"use strict";Object.defineProperty(ow,"__esModule",{value:!0});ow.enumToMap=Ife;function Ife(e,t=[],r=[]){let n=(t?.length??0)===0,i=(r?.length??0)===0;return Object.fromEntries(Object.entries(e).filter(([,s])=>typeof s=="number"&&(n||t.includes(s))&&(i||!r.includes(s))))}});var t3=U(q=>{"use strict";Object.defineProperty(q,"__esModule",{value:!0});q.SPECIAL_HEADERS=q.MINOR=q.MAJOR=q.HTAB_SP_VCHAR_OBS_TEXT=q.QUOTED_STRING=q.CONNECTION_TOKEN_CHARS=q.HEADER_CHARS=q.TOKEN=q.HEX=q.URL_CHAR=q.USERINFO_CHARS=q.MARK=q.ALPHANUM=q.NUM=q.HEX_MAP=q.NUM_MAP=q.ALPHA=q.STATUSES_HTTP=q.H_METHOD_MAP=q.METHOD_MAP=q.METHODS_RTSP=q.METHODS_ICE=q.METHODS_HTTP=q.HEADER_STATE=q.FINISH=q.STATUSES=q.METHODS=q.LENIENT_FLAGS=q.FLAGS=q.TYPE=q.ERROR=void 0;var bfe=e3();q.ERROR={OK:0,INTERNAL:1,STRICT:2,CR_EXPECTED:25,LF_EXPECTED:3,UNEXPECTED_CONTENT_LENGTH:4,UNEXPECTED_SPACE:30,CLOSED_CONNECTION:5,INVALID_METHOD:6,INVALID_URL:7,INVALID_CONSTANT:8,INVALID_VERSION:9,INVALID_HEADER_TOKEN:10,INVALID_CONTENT_LENGTH:11,INVALID_CHUNK_SIZE:12,INVALID_STATUS:13,INVALID_EOF_STATE:14,INVALID_TRANSFER_ENCODING:15,CB_MESSAGE_BEGIN:16,CB_HEADERS_COMPLETE:17,CB_MESSAGE_COMPLETE:18,CB_CHUNK_HEADER:19,CB_CHUNK_COMPLETE:20,PAUSED:21,PAUSED_UPGRADE:22,PAUSED_H2_UPGRADE:23,USER:24,CB_URL_COMPLETE:26,CB_STATUS_COMPLETE:27,CB_METHOD_COMPLETE:32,CB_VERSION_COMPLETE:33,CB_HEADER_FIELD_COMPLETE:28,CB_HEADER_VALUE_COMPLETE:29,CB_CHUNK_EXTENSION_NAME_COMPLETE:34,CB_CHUNK_EXTENSION_VALUE_COMPLETE:35,CB_RESET:31,CB_PROTOCOL_COMPLETE:38};q.TYPE={BOTH:0,REQUEST:1,RESPONSE:2};q.FLAGS={CONNECTION_KEEP_ALIVE:1,CONNECTION_CLOSE:2,CONNECTION_UPGRADE:4,CHUNKED:8,UPGRADE:16,CONTENT_LENGTH:32,SKIPBODY:64,TRAILING:128,TRANSFER_ENCODING:512};q.LENIENT_FLAGS={HEADERS:1,CHUNKED_LENGTH:2,KEEP_ALIVE:4,TRANSFER_ENCODING:8,VERSION:16,DATA_AFTER_CLOSE:32,OPTIONAL_LF_AFTER_CR:64,OPTIONAL_CRLF_AFTER_CHUNK:128,OPTIONAL_CR_BEFORE_LF:256,SPACES_AFTER_CHUNK_SIZE:512};q.METHODS={DELETE:0,GET:1,HEAD:2,POST:3,PUT:4,CONNECT:5,OPTIONS:6,TRACE:7,COPY:8,LOCK:9,MKCOL:10,MOVE:11,PROPFIND:12,PROPPATCH:13,SEARCH:14,UNLOCK:15,BIND:16,REBIND:17,UNBIND:18,ACL:19,REPORT:20,MKACTIVITY:21,CHECKOUT:22,MERGE:23,"M-SEARCH":24,NOTIFY:25,SUBSCRIBE:26,UNSUBSCRIBE:27,PATCH:28,PURGE:29,MKCALENDAR:30,LINK:31,UNLINK:32,SOURCE:33,PRI:34,DESCRIBE:35,ANNOUNCE:36,SETUP:37,PLAY:38,PAUSE:39,TEARDOWN:40,GET_PARAMETER:41,SET_PARAMETER:42,REDIRECT:43,RECORD:44,FLUSH:45,QUERY:46};q.STATUSES={CONTINUE:100,SWITCHING_PROTOCOLS:101,PROCESSING:102,EARLY_HINTS:103,RESPONSE_IS_STALE:110,REVALIDATION_FAILED:111,DISCONNECTED_OPERATION:112,HEURISTIC_EXPIRATION:113,MISCELLANEOUS_WARNING:199,OK:200,CREATED:201,ACCEPTED:202,NON_AUTHORITATIVE_INFORMATION:203,NO_CONTENT:204,RESET_CONTENT:205,PARTIAL_CONTENT:206,MULTI_STATUS:207,ALREADY_REPORTED:208,TRANSFORMATION_APPLIED:214,IM_USED:226,MISCELLANEOUS_PERSISTENT_WARNING:299,MULTIPLE_CHOICES:300,MOVED_PERMANENTLY:301,FOUND:302,SEE_OTHER:303,NOT_MODIFIED:304,USE_PROXY:305,SWITCH_PROXY:306,TEMPORARY_REDIRECT:307,PERMANENT_REDIRECT:308,BAD_REQUEST:400,UNAUTHORIZED:401,PAYMENT_REQUIRED:402,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_ALLOWED:405,NOT_ACCEPTABLE:406,PROXY_AUTHENTICATION_REQUIRED:407,REQUEST_TIMEOUT:408,CONFLICT:409,GONE:410,LENGTH_REQUIRED:411,PRECONDITION_FAILED:412,PAYLOAD_TOO_LARGE:413,URI_TOO_LONG:414,UNSUPPORTED_MEDIA_TYPE:415,RANGE_NOT_SATISFIABLE:416,EXPECTATION_FAILED:417,IM_A_TEAPOT:418,PAGE_EXPIRED:419,ENHANCE_YOUR_CALM:420,MISDIRECTED_REQUEST:421,UNPROCESSABLE_ENTITY:422,LOCKED:423,FAILED_DEPENDENCY:424,TOO_EARLY:425,UPGRADE_REQUIRED:426,PRECONDITION_REQUIRED:428,TOO_MANY_REQUESTS:429,REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL:430,REQUEST_HEADER_FIELDS_TOO_LARGE:431,LOGIN_TIMEOUT:440,NO_RESPONSE:444,RETRY_WITH:449,BLOCKED_BY_PARENTAL_CONTROL:450,UNAVAILABLE_FOR_LEGAL_REASONS:451,CLIENT_CLOSED_LOAD_BALANCED_REQUEST:460,INVALID_X_FORWARDED_FOR:463,REQUEST_HEADER_TOO_LARGE:494,SSL_CERTIFICATE_ERROR:495,SSL_CERTIFICATE_REQUIRED:496,HTTP_REQUEST_SENT_TO_HTTPS_PORT:497,INVALID_TOKEN:498,CLIENT_CLOSED_REQUEST:499,INTERNAL_SERVER_ERROR:500,NOT_IMPLEMENTED:501,BAD_GATEWAY:502,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504,HTTP_VERSION_NOT_SUPPORTED:505,VARIANT_ALSO_NEGOTIATES:506,INSUFFICIENT_STORAGE:507,LOOP_DETECTED:508,BANDWIDTH_LIMIT_EXCEEDED:509,NOT_EXTENDED:510,NETWORK_AUTHENTICATION_REQUIRED:511,WEB_SERVER_UNKNOWN_ERROR:520,WEB_SERVER_IS_DOWN:521,CONNECTION_TIMEOUT:522,ORIGIN_IS_UNREACHABLE:523,TIMEOUT_OCCURED:524,SSL_HANDSHAKE_FAILED:525,INVALID_SSL_CERTIFICATE:526,RAILGUN_ERROR:527,SITE_IS_OVERLOADED:529,SITE_IS_FROZEN:530,IDENTITY_PROVIDER_AUTHENTICATION_ERROR:561,NETWORK_READ_TIMEOUT:598,NETWORK_CONNECT_TIMEOUT:599};q.FINISH={SAFE:0,SAFE_WITH_CB:1,UNSAFE:2};q.HEADER_STATE={GENERAL:0,CONNECTION:1,CONTENT_LENGTH:2,TRANSFER_ENCODING:3,UPGRADE:4,CONNECTION_KEEP_ALIVE:5,CONNECTION_CLOSE:6,CONNECTION_UPGRADE:7,TRANSFER_ENCODING_CHUNKED:8};q.METHODS_HTTP=[q.METHODS.DELETE,q.METHODS.GET,q.METHODS.HEAD,q.METHODS.POST,q.METHODS.PUT,q.METHODS.CONNECT,q.METHODS.OPTIONS,q.METHODS.TRACE,q.METHODS.COPY,q.METHODS.LOCK,q.METHODS.MKCOL,q.METHODS.MOVE,q.METHODS.PROPFIND,q.METHODS.PROPPATCH,q.METHODS.SEARCH,q.METHODS.UNLOCK,q.METHODS.BIND,q.METHODS.REBIND,q.METHODS.UNBIND,q.METHODS.ACL,q.METHODS.REPORT,q.METHODS.MKACTIVITY,q.METHODS.CHECKOUT,q.METHODS.MERGE,q.METHODS["M-SEARCH"],q.METHODS.NOTIFY,q.METHODS.SUBSCRIBE,q.METHODS.UNSUBSCRIBE,q.METHODS.PATCH,q.METHODS.PURGE,q.METHODS.MKCALENDAR,q.METHODS.LINK,q.METHODS.UNLINK,q.METHODS.PRI,q.METHODS.SOURCE,q.METHODS.QUERY];q.METHODS_ICE=[q.METHODS.SOURCE];q.METHODS_RTSP=[q.METHODS.OPTIONS,q.METHODS.DESCRIBE,q.METHODS.ANNOUNCE,q.METHODS.SETUP,q.METHODS.PLAY,q.METHODS.PAUSE,q.METHODS.TEARDOWN,q.METHODS.GET_PARAMETER,q.METHODS.SET_PARAMETER,q.METHODS.REDIRECT,q.METHODS.RECORD,q.METHODS.FLUSH,q.METHODS.GET,q.METHODS.POST];q.METHOD_MAP=(0,bfe.enumToMap)(q.METHODS);q.H_METHOD_MAP=Object.fromEntries(Object.entries(q.METHODS).filter(([e])=>e.startsWith("H")));q.STATUSES_HTTP=[q.STATUSES.CONTINUE,q.STATUSES.SWITCHING_PROTOCOLS,q.STATUSES.PROCESSING,q.STATUSES.EARLY_HINTS,q.STATUSES.RESPONSE_IS_STALE,q.STATUSES.REVALIDATION_FAILED,q.STATUSES.DISCONNECTED_OPERATION,q.STATUSES.HEURISTIC_EXPIRATION,q.STATUSES.MISCELLANEOUS_WARNING,q.STATUSES.OK,q.STATUSES.CREATED,q.STATUSES.ACCEPTED,q.STATUSES.NON_AUTHORITATIVE_INFORMATION,q.STATUSES.NO_CONTENT,q.STATUSES.RESET_CONTENT,q.STATUSES.PARTIAL_CONTENT,q.STATUSES.MULTI_STATUS,q.STATUSES.ALREADY_REPORTED,q.STATUSES.TRANSFORMATION_APPLIED,q.STATUSES.IM_USED,q.STATUSES.MISCELLANEOUS_PERSISTENT_WARNING,q.STATUSES.MULTIPLE_CHOICES,q.STATUSES.MOVED_PERMANENTLY,q.STATUSES.FOUND,q.STATUSES.SEE_OTHER,q.STATUSES.NOT_MODIFIED,q.STATUSES.USE_PROXY,q.STATUSES.SWITCH_PROXY,q.STATUSES.TEMPORARY_REDIRECT,q.STATUSES.PERMANENT_REDIRECT,q.STATUSES.BAD_REQUEST,q.STATUSES.UNAUTHORIZED,q.STATUSES.PAYMENT_REQUIRED,q.STATUSES.FORBIDDEN,q.STATUSES.NOT_FOUND,q.STATUSES.METHOD_NOT_ALLOWED,q.STATUSES.NOT_ACCEPTABLE,q.STATUSES.PROXY_AUTHENTICATION_REQUIRED,q.STATUSES.REQUEST_TIMEOUT,q.STATUSES.CONFLICT,q.STATUSES.GONE,q.STATUSES.LENGTH_REQUIRED,q.STATUSES.PRECONDITION_FAILED,q.STATUSES.PAYLOAD_TOO_LARGE,q.STATUSES.URI_TOO_LONG,q.STATUSES.UNSUPPORTED_MEDIA_TYPE,q.STATUSES.RANGE_NOT_SATISFIABLE,q.STATUSES.EXPECTATION_FAILED,q.STATUSES.IM_A_TEAPOT,q.STATUSES.PAGE_EXPIRED,q.STATUSES.ENHANCE_YOUR_CALM,q.STATUSES.MISDIRECTED_REQUEST,q.STATUSES.UNPROCESSABLE_ENTITY,q.STATUSES.LOCKED,q.STATUSES.FAILED_DEPENDENCY,q.STATUSES.TOO_EARLY,q.STATUSES.UPGRADE_REQUIRED,q.STATUSES.PRECONDITION_REQUIRED,q.STATUSES.TOO_MANY_REQUESTS,q.STATUSES.REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL,q.STATUSES.REQUEST_HEADER_FIELDS_TOO_LARGE,q.STATUSES.LOGIN_TIMEOUT,q.STATUSES.NO_RESPONSE,q.STATUSES.RETRY_WITH,q.STATUSES.BLOCKED_BY_PARENTAL_CONTROL,q.STATUSES.UNAVAILABLE_FOR_LEGAL_REASONS,q.STATUSES.CLIENT_CLOSED_LOAD_BALANCED_REQUEST,q.STATUSES.INVALID_X_FORWARDED_FOR,q.STATUSES.REQUEST_HEADER_TOO_LARGE,q.STATUSES.SSL_CERTIFICATE_ERROR,q.STATUSES.SSL_CERTIFICATE_REQUIRED,q.STATUSES.HTTP_REQUEST_SENT_TO_HTTPS_PORT,q.STATUSES.INVALID_TOKEN,q.STATUSES.CLIENT_CLOSED_REQUEST,q.STATUSES.INTERNAL_SERVER_ERROR,q.STATUSES.NOT_IMPLEMENTED,q.STATUSES.BAD_GATEWAY,q.STATUSES.SERVICE_UNAVAILABLE,q.STATUSES.GATEWAY_TIMEOUT,q.STATUSES.HTTP_VERSION_NOT_SUPPORTED,q.STATUSES.VARIANT_ALSO_NEGOTIATES,q.STATUSES.INSUFFICIENT_STORAGE,q.STATUSES.LOOP_DETECTED,q.STATUSES.BANDWIDTH_LIMIT_EXCEEDED,q.STATUSES.NOT_EXTENDED,q.STATUSES.NETWORK_AUTHENTICATION_REQUIRED,q.STATUSES.WEB_SERVER_UNKNOWN_ERROR,q.STATUSES.WEB_SERVER_IS_DOWN,q.STATUSES.CONNECTION_TIMEOUT,q.STATUSES.ORIGIN_IS_UNREACHABLE,q.STATUSES.TIMEOUT_OCCURED,q.STATUSES.SSL_HANDSHAKE_FAILED,q.STATUSES.INVALID_SSL_CERTIFICATE,q.STATUSES.RAILGUN_ERROR,q.STATUSES.SITE_IS_OVERLOADED,q.STATUSES.SITE_IS_FROZEN,q.STATUSES.IDENTITY_PROVIDER_AUTHENTICATION_ERROR,q.STATUSES.NETWORK_READ_TIMEOUT,q.STATUSES.NETWORK_CONNECT_TIMEOUT];q.ALPHA=[];for(let e=65;e<=90;e++)q.ALPHA.push(String.fromCharCode(e)),q.ALPHA.push(String.fromCharCode(e+32));q.NUM_MAP={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9};q.HEX_MAP={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15};q.NUM=["0","1","2","3","4","5","6","7","8","9"];q.ALPHANUM=q.ALPHA.concat(q.NUM);q.MARK=["-","_",".","!","~","*","'","(",")"];q.USERINFO_CHARS=q.ALPHANUM.concat(q.MARK).concat(["%",";",":","&","=","+","$",","]);q.URL_CHAR=["!",'"',"$","%","&","'","(",")","*","+",",","-",".","/",":",";","<","=",">","@","[","\\","]","^","_","`","{","|","}","~"].concat(q.ALPHANUM);q.HEX=q.NUM.concat(["a","b","c","d","e","f","A","B","C","D","E","F"]);q.TOKEN=["!","#","$","%","&","'","*","+","-",".","^","_","`","|","~"].concat(q.ALPHANUM);q.HEADER_CHARS=[" "];for(let e=32;e<=255;e++)e!==127&&q.HEADER_CHARS.push(e);q.CONNECTION_TOKEN_CHARS=q.HEADER_CHARS.filter(e=>e!==44);q.QUOTED_STRING=[" "," "];for(let e=33;e<=255;e++)e!==34&&e!==92&&q.QUOTED_STRING.push(e);q.HTAB_SP_VCHAR_OBS_TEXT=[" "," "];for(let e=33;e<=126;e++)q.HTAB_SP_VCHAR_OBS_TEXT.push(e);for(let e=128;e<=255;e++)q.HTAB_SP_VCHAR_OBS_TEXT.push(e);q.MAJOR=q.NUM_MAP;q.MINOR=q.MAJOR;q.SPECIAL_HEADERS={connection:q.HEADER_STATE.CONNECTION,"content-length":q.HEADER_STATE.CONTENT_LENGTH,"proxy-connection":q.HEADER_STATE.CONNECTION,"transfer-encoding":q.HEADER_STATE.TRANSFER_ENCODING,upgrade:q.HEADER_STATE.UPGRADE};q.default={ERROR:q.ERROR,TYPE:q.TYPE,FLAGS:q.FLAGS,LENIENT_FLAGS:q.LENIENT_FLAGS,METHODS:q.METHODS,STATUSES:q.STATUSES,FINISH:q.FINISH,HEADER_STATE:q.HEADER_STATE,ALPHA:q.ALPHA,NUM_MAP:q.NUM_MAP,HEX_MAP:q.HEX_MAP,NUM:q.NUM,ALPHANUM:q.ALPHANUM,MARK:q.MARK,USERINFO_CHARS:q.USERINFO_CHARS,URL_CHAR:q.URL_CHAR,HEX:q.HEX,TOKEN:q.TOKEN,HEADER_CHARS:q.HEADER_CHARS,CONNECTION_TOKEN_CHARS:q.CONNECTION_TOKEN_CHARS,QUOTED_STRING:q.QUOTED_STRING,HTAB_SP_VCHAR_OBS_TEXT:q.HTAB_SP_VCHAR_OBS_TEXT,MAJOR:q.MAJOR,MINOR:q.MINOR,SPECIAL_HEADERS:q.SPECIAL_HEADERS,METHODS_HTTP:q.METHODS_HTTP,METHODS_ICE:q.METHODS_ICE,METHODS_RTSP:q.METHODS_RTSP,METHOD_MAP:q.METHOD_MAP,H_METHOD_MAP:q.H_METHOD_MAP,STATUSES_HTTP:q.STATUSES_HTTP}});var Aw=U((yTe,r3)=>{"use strict";var{Buffer:Cfe}=Gr(),Qfe="AGFzbQEAAAABJwdgAX8Bf2ADf39/AX9gAn9/AGABfwBgBH9/f38Bf2AAAGADf39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQAEA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAAzU0BQYAAAMAAAAAAAADAQMAAwMDAAACAAAAAAICAgICAgICAgIBAQEBAQEBAQEBAwAAAwAAAAQFAXABExMFAwEAAgYIAX8BQcDZBAsHxQcoBm1lbW9yeQIAC19pbml0aWFsaXplAAgZX19pbmRpcmVjdF9mdW5jdGlvbl90YWJsZQEAC2xsaHR0cF9pbml0AAkYbGxodHRwX3Nob3VsZF9rZWVwX2FsaXZlADcMbGxodHRwX2FsbG9jAAsGbWFsbG9jADkLbGxodHRwX2ZyZWUADARmcmVlAAwPbGxodHRwX2dldF90eXBlAA0VbGxodHRwX2dldF9odHRwX21ham9yAA4VbGxodHRwX2dldF9odHRwX21pbm9yAA8RbGxodHRwX2dldF9tZXRob2QAEBZsbGh0dHBfZ2V0X3N0YXR1c19jb2RlABESbGxodHRwX2dldF91cGdyYWRlABIMbGxodHRwX3Jlc2V0ABMObGxodHRwX2V4ZWN1dGUAFBRsbGh0dHBfc2V0dGluZ3NfaW5pdAAVDWxsaHR0cF9maW5pc2gAFgxsbGh0dHBfcGF1c2UAFw1sbGh0dHBfcmVzdW1lABgbbGxodHRwX3Jlc3VtZV9hZnRlcl91cGdyYWRlABkQbGxodHRwX2dldF9lcnJubwAaF2xsaHR0cF9nZXRfZXJyb3JfcmVhc29uABsXbGxodHRwX3NldF9lcnJvcl9yZWFzb24AHBRsbGh0dHBfZ2V0X2Vycm9yX3BvcwAdEWxsaHR0cF9lcnJub19uYW1lAB4SbGxodHRwX21ldGhvZF9uYW1lAB8SbGxodHRwX3N0YXR1c19uYW1lACAabGxodHRwX3NldF9sZW5pZW50X2hlYWRlcnMAISFsbGh0dHBfc2V0X2xlbmllbnRfY2h1bmtlZF9sZW5ndGgAIh1sbGh0dHBfc2V0X2xlbmllbnRfa2VlcF9hbGl2ZQAjJGxsaHR0cF9zZXRfbGVuaWVudF90cmFuc2Zlcl9lbmNvZGluZwAkGmxsaHR0cF9zZXRfbGVuaWVudF92ZXJzaW9uACUjbGxodHRwX3NldF9sZW5pZW50X2RhdGFfYWZ0ZXJfY2xvc2UAJidsbGh0dHBfc2V0X2xlbmllbnRfb3B0aW9uYWxfbGZfYWZ0ZXJfY3IAJyxsbGh0dHBfc2V0X2xlbmllbnRfb3B0aW9uYWxfY3JsZl9hZnRlcl9jaHVuawAoKGxsaHR0cF9zZXRfbGVuaWVudF9vcHRpb25hbF9jcl9iZWZvcmVfbGYAKSpsbGh0dHBfc2V0X2xlbmllbnRfc3BhY2VzX2FmdGVyX2NodW5rX3NpemUAKhhsbGh0dHBfbWVzc2FnZV9uZWVkc19lb2YANgkYAQBBAQsSAQIDBAUKBgcyNDMuKy8tLDAxCq/ZAjQWAEHA1QAoAgAEQAALQcDVAEEBNgIACxQAIAAQOCAAIAI2AjggACABOgAoCxQAIAAgAC8BNCAALQAwIAAQNxAACx4BAX9BwAAQOiIBEDggAUGACDYCOCABIAA6ACggAQuPDAEHfwJAIABFDQAgAEEIayIBIABBBGsoAgAiAEF4cSIEaiEFAkAgAEEBcQ0AIABBA3FFDQEgASABKAIAIgBrIgFB1NUAKAIASQ0BIAAgBGohBAJAAkBB2NUAKAIAIAFHBEAgAEH/AU0EQCAAQQN2IQMgASgCCCIAIAEoAgwiAkYEQEHE1QBBxNUAKAIAQX4gA3dxNgIADAULIAIgADYCCCAAIAI2AgwMBAsgASgCGCEGIAEgASgCDCIARwRAIAAgASgCCCICNgIIIAIgADYCDAwDCyABQRRqIgMoAgAiAkUEQCABKAIQIgJFDQIgAUEQaiEDCwNAIAMhByACIgBBFGoiAygCACICDQAgAEEQaiEDIAAoAhAiAg0ACyAHQQA2AgAMAgsgBSgCBCIAQQNxQQNHDQIgBSAAQX5xNgIEQczVACAENgIAIAUgBDYCACABIARBAXI2AgQMAwtBACEACyAGRQ0AAkAgASgCHCICQQJ0QfTXAGoiAygCACABRgRAIAMgADYCACAADQFByNUAQcjVACgCAEF+IAJ3cTYCAAwCCyAGQRBBFCAGKAIQIAFGG2ogADYCACAARQ0BCyAAIAY2AhggASgCECICBEAgACACNgIQIAIgADYCGAsgAUEUaigCACICRQ0AIABBFGogAjYCACACIAA2AhgLIAEgBU8NACAFKAIEIgBBAXFFDQACQAJAAkACQCAAQQJxRQRAQdzVACgCACAFRgRAQdzVACABNgIAQdDVAEHQ1QAoAgAgBGoiADYCACABIABBAXI2AgQgAUHY1QAoAgBHDQZBzNUAQQA2AgBB2NUAQQA2AgAMBgtB2NUAKAIAIAVGBEBB2NUAIAE2AgBBzNUAQczVACgCACAEaiIANgIAIAEgAEEBcjYCBCAAIAFqIAA2AgAMBgsgAEF4cSAEaiEEIABB/wFNBEAgAEEDdiEDIAUoAggiACAFKAIMIgJGBEBBxNUAQcTVACgCAEF+IAN3cTYCAAwFCyACIAA2AgggACACNgIMDAQLIAUoAhghBiAFIAUoAgwiAEcEQEHU1QAoAgAaIAAgBSgCCCICNgIIIAIgADYCDAwDCyAFQRRqIgMoAgAiAkUEQCAFKAIQIgJFDQIgBUEQaiEDCwNAIAMhByACIgBBFGoiAygCACICDQAgAEEQaiEDIAAoAhAiAg0ACyAHQQA2AgAMAgsgBSAAQX5xNgIEIAEgBGogBDYCACABIARBAXI2AgQMAwtBACEACyAGRQ0AAkAgBSgCHCICQQJ0QfTXAGoiAygCACAFRgRAIAMgADYCACAADQFByNUAQcjVACgCAEF+IAJ3cTYCAAwCCyAGQRBBFCAGKAIQIAVGG2ogADYCACAARQ0BCyAAIAY2AhggBSgCECICBEAgACACNgIQIAIgADYCGAsgBUEUaigCACICRQ0AIABBFGogAjYCACACIAA2AhgLIAEgBGogBDYCACABIARBAXI2AgQgAUHY1QAoAgBHDQBBzNUAIAQ2AgAMAQsgBEH/AU0EQCAEQXhxQezVAGohAAJ/QcTVACgCACICQQEgBEEDdnQiA3FFBEBBxNUAIAIgA3I2AgAgAAwBCyAAKAIICyICIAE2AgwgACABNgIIIAEgADYCDCABIAI2AggMAQtBHyECIARB////B00EQCAEQSYgBEEIdmciAGt2QQFxIABBAXRrQT5qIQILIAEgAjYCHCABQgA3AhAgAkECdEH01wBqIQACQEHI1QAoAgAiA0EBIAJ0IgdxRQRAIAAgATYCAEHI1QAgAyAHcjYCACABIAA2AhggASABNgIIIAEgATYCDAwBCyAEQRkgAkEBdmtBACACQR9HG3QhAiAAKAIAIQACQANAIAAiAygCBEF4cSAERg0BIAJBHXYhACACQQF0IQIgAyAAQQRxakEQaiIHKAIAIgANAAsgByABNgIAIAEgAzYCGCABIAE2AgwgASABNgIIDAELIAMoAggiACABNgIMIAMgATYCCCABQQA2AhggASADNgIMIAEgADYCCAtB5NUAQeTVACgCAEEBayIAQX8gABs2AgALCwcAIAAtACgLBwAgAC0AKgsHACAALQArCwcAIAAtACkLBwAgAC8BNAsHACAALQAwC0ABBH8gACgCGCEBIAAvAS4hAiAALQAoIQMgACgCOCEEIAAQOCAAIAQ2AjggACADOgAoIAAgAjsBLiAAIAE2AhgL5YUCAgd/A34gASACaiEEAkAgACIDKAIMIgANACADKAIEBEAgAyABNgIECyMAQRBrIgkkAAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAygCHCICQQJrDvwBAfkBAgMEBQYHCAkKCwwNDg8QERL4ARP3ARQV9gEWF/UBGBkaGxwdHh8g/QH7ASH0ASIjJCUmJygpKivzASwtLi8wMTLyAfEBMzTwAe8BNTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5P+gFQUVJT7gHtAVTsAVXrAVZXWFla6gFbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHpAegBzwHnAdAB5gHRAdIB0wHUAeUB1QHWAdcB2AHZAdoB2wHcAd0B3gHfAeAB4QHiAeMBAPwBC0EADOMBC0EODOIBC0ENDOEBC0EPDOABC0EQDN8BC0ETDN4BC0EUDN0BC0EVDNwBC0EWDNsBC0EXDNoBC0EYDNkBC0EZDNgBC0EaDNcBC0EbDNYBC0EcDNUBC0EdDNQBC0EeDNMBC0EfDNIBC0EgDNEBC0EhDNABC0EIDM8BC0EiDM4BC0EkDM0BC0EjDMwBC0EHDMsBC0ElDMoBC0EmDMkBC0EnDMgBC0EoDMcBC0ESDMYBC0ERDMUBC0EpDMQBC0EqDMMBC0ErDMIBC0EsDMEBC0HeAQzAAQtBLgy/AQtBLwy+AQtBMAy9AQtBMQy8AQtBMgy7AQtBMwy6AQtBNAy5AQtB3wEMuAELQTUMtwELQTkMtgELQQwMtQELQTYMtAELQTcMswELQTgMsgELQT4MsQELQToMsAELQeABDK8BC0ELDK4BC0E/DK0BC0E7DKwBC0EKDKsBC0E8DKoBC0E9DKkBC0HhAQyoAQtBwQAMpwELQcAADKYBC0HCAAylAQtBCQykAQtBLQyjAQtBwwAMogELQcQADKEBC0HFAAygAQtBxgAMnwELQccADJ4BC0HIAAydAQtByQAMnAELQcoADJsBC0HLAAyaAQtBzAAMmQELQc0ADJgBC0HOAAyXAQtBzwAMlgELQdAADJUBC0HRAAyUAQtB0gAMkwELQdMADJIBC0HVAAyRAQtB1AAMkAELQdYADI8BC0HXAAyOAQtB2AAMjQELQdkADIwBC0HaAAyLAQtB2wAMigELQdwADIkBC0HdAAyIAQtB3gAMhwELQd8ADIYBC0HgAAyFAQtB4QAMhAELQeIADIMBC0HjAAyCAQtB5AAMgQELQeUADIABC0HiAQx/C0HmAAx+C0HnAAx9C0EGDHwLQegADHsLQQUMegtB6QAMeQtBBAx4C0HqAAx3C0HrAAx2C0HsAAx1C0HtAAx0C0EDDHMLQe4ADHILQe8ADHELQfAADHALQfIADG8LQfEADG4LQfMADG0LQfQADGwLQfUADGsLQfYADGoLQQIMaQtB9wAMaAtB+AAMZwtB+QAMZgtB+gAMZQtB+wAMZAtB/AAMYwtB/QAMYgtB/gAMYQtB/wAMYAtBgAEMXwtBgQEMXgtBggEMXQtBgwEMXAtBhAEMWwtBhQEMWgtBhgEMWQtBhwEMWAtBiAEMVwtBiQEMVgtBigEMVQtBiwEMVAtBjAEMUwtBjQEMUgtBjgEMUQtBjwEMUAtBkAEMTwtBkQEMTgtBkgEMTQtBkwEMTAtBlAEMSwtBlQEMSgtBlgEMSQtBlwEMSAtBmAEMRwtBmQEMRgtBmgEMRQtBmwEMRAtBnAEMQwtBnQEMQgtBngEMQQtBnwEMQAtBoAEMPwtBoQEMPgtBogEMPQtBowEMPAtBpAEMOwtBpQEMOgtBpgEMOQtBpwEMOAtBqAEMNwtBqQEMNgtBqgEMNQtBqwEMNAtBrAEMMwtBrQEMMgtBrgEMMQtBrwEMMAtBsAEMLwtBsQEMLgtBsgEMLQtBswEMLAtBtAEMKwtBtQEMKgtBtgEMKQtBtwEMKAtBuAEMJwtBuQEMJgtBugEMJQtBuwEMJAtBvAEMIwtBvQEMIgtBvgEMIQtBvwEMIAtBwAEMHwtBwQEMHgtBwgEMHQtBAQwcC0HDAQwbC0HEAQwaC0HFAQwZC0HGAQwYC0HHAQwXC0HIAQwWC0HJAQwVC0HKAQwUC0HLAQwTC0HMAQwSC0HNAQwRC0HOAQwQC0HPAQwPC0HQAQwOC0HRAQwNC0HSAQwMC0HTAQwLC0HUAQwKC0HVAQwJC0HWAQwIC0HjAQwHC0HXAQwGC0HYAQwFC0HZAQwEC0HaAQwDC0HbAQwCC0HdAQwBC0HcAQshAgNAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAn8CQAJAAkACQAJAAkACQAJ/AkACQAJAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAMCfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAg7jAQABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEjJCUnKCmeA5sDmgORA4oDgwOAA/0C+wL4AvIC8QLvAu0C6ALnAuYC5QLkAtwC2wLaAtkC2ALXAtYC1QLPAs4CzALLAsoCyQLIAscCxgLEAsMCvgK8AroCuQK4ArcCtgK1ArQCswKyArECsAKuAq0CqQKoAqcCpgKlAqQCowKiAqECoAKfApgCkAKMAosCigKBAv4B/QH8AfsB+gH5AfgB9wH1AfMB8AHrAekB6AHnAeYB5QHkAeMB4gHhAeAB3wHeAd0B3AHaAdkB2AHXAdYB1QHUAdMB0gHRAdABzwHOAc0BzAHLAcoByQHIAccBxgHFAcQBwwHCAcEBwAG/Ab4BvQG8AbsBugG5AbgBtwG2AbUBtAGzAbIBsQGwAa8BrgGtAawBqwGqAakBqAGnAaYBpQGkAaMBogGfAZ4BmQGYAZcBlgGVAZQBkwGSAZEBkAGPAY0BjAGHAYYBhQGEAYMBggF9fHt6eXZ1dFBRUlNUVQsgASAERw1yQf0BIQIMvgMLIAEgBEcNmAFB2wEhAgy9AwsgASAERw3xAUGOASECDLwDCyABIARHDfwBQYQBIQIMuwMLIAEgBEcNigJB/wAhAgy6AwsgASAERw2RAkH9ACECDLkDCyABIARHDZQCQfsAIQIMuAMLIAEgBEcNHkEeIQIMtwMLIAEgBEcNGUEYIQIMtgMLIAEgBEcNygJBzQAhAgy1AwsgASAERw3VAkHGACECDLQDCyABIARHDdYCQcMAIQIMswMLIAEgBEcN3AJBOCECDLIDCyADLQAwQQFGDa0DDIkDC0EAIQACQAJAAkAgAy0AKkUNACADLQArRQ0AIAMvATIiAkECcUUNAQwCCyADLwEyIgJBAXFFDQELQQEhACADLQAoQQFGDQAgAy8BNCIGQeQAa0HkAEkNACAGQcwBRg0AIAZBsAJGDQAgAkHAAHENAEEAIQAgAkGIBHFBgARGDQAgAkEocUEARyEACyADQQA7ATIgA0EAOgAxAkAgAEUEQCADQQA6ADEgAy0ALkEEcQ0BDLEDCyADQgA3AyALIANBADoAMSADQQE6ADYMSAtBACEAAkAgAygCOCICRQ0AIAIoAjAiAkUNACADIAIRAAAhAAsgAEUNSCAAQRVHDWIgA0EENgIcIAMgATYCFCADQdIbNgIQIANBFTYCDEEAIQIMrwMLIAEgBEYEQEEGIQIMrwMLIAEtAABBCkcNGSABQQFqIQEMGgsgA0IANwMgQRIhAgyUAwsgASAERw2KA0EjIQIMrAMLIAEgBEYEQEEHIQIMrAMLAkACQCABLQAAQQprDgQBGBgAGAsgAUEBaiEBQRAhAgyTAwsgAUEBaiEBIANBL2otAABBAXENF0EAIQIgA0EANgIcIAMgATYCFCADQZkgNgIQIANBGTYCDAyrAwsgAyADKQMgIgwgBCABa60iCn0iC0IAIAsgDFgbNwMgIAogDFoNGEEIIQIMqgMLIAEgBEcEQCADQQk2AgggAyABNgIEQRQhAgyRAwtBCSECDKkDCyADKQMgUA2uAgxDCyABIARGBEBBCyECDKgDCyABLQAAQQpHDRYgAUEBaiEBDBcLIANBL2otAABBAXFFDRkMJgtBACEAAkAgAygCOCICRQ0AIAIoAlAiAkUNACADIAIRAAAhAAsgAA0ZDEILQQAhAAJAIAMoAjgiAkUNACACKAJQIgJFDQAgAyACEQAAIQALIAANGgwkC0EAIQACQCADKAI4IgJFDQAgAigCUCICRQ0AIAMgAhEAACEACyAADRsMMgsgA0Evai0AAEEBcUUNHAwiC0EAIQACQCADKAI4IgJFDQAgAigCVCICRQ0AIAMgAhEAACEACyAADRwMQgtBACEAAkAgAygCOCICRQ0AIAIoAlQiAkUNACADIAIRAAAhAAsgAA0dDCALIAEgBEYEQEETIQIMoAMLAkAgAS0AACIAQQprDgQfIyMAIgsgAUEBaiEBDB8LQQAhAAJAIAMoAjgiAkUNACACKAJUIgJFDQAgAyACEQAAIQALIAANIgxCCyABIARGBEBBFiECDJ4DCyABLQAAQcDBAGotAABBAUcNIwyDAwsCQANAIAEtAABBsDtqLQAAIgBBAUcEQAJAIABBAmsOAgMAJwsgAUEBaiEBQSEhAgyGAwsgBCABQQFqIgFHDQALQRghAgydAwsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAFBAWoiARA0IgANIQxBC0EAIQACQCADKAI4IgJFDQAgAigCVCICRQ0AIAMgAhEAACEACyAADSMMKgsgASAERgRAQRwhAgybAwsgA0EKNgIIIAMgATYCBEEAIQACQCADKAI4IgJFDQAgAigCUCICRQ0AIAMgAhEAACEACyAADSVBJCECDIEDCyABIARHBEADQCABLQAAQbA9ai0AACIAQQNHBEAgAEEBaw4FGBomggMlJgsgBCABQQFqIgFHDQALQRshAgyaAwtBGyECDJkDCwNAIAEtAABBsD9qLQAAIgBBA0cEQCAAQQFrDgUPEScTJicLIAQgAUEBaiIBRw0AC0EeIQIMmAMLIAEgBEcEQCADQQs2AgggAyABNgIEQQchAgz/AgtBHyECDJcDCyABIARGBEBBICECDJcDCwJAIAEtAABBDWsOFC4/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8APwtBACECIANBADYCHCADQb8LNgIQIANBAjYCDCADIAFBAWo2AhQMlgMLIANBL2ohAgNAIAEgBEYEQEEhIQIMlwMLAkACQAJAIAEtAAAiAEEJaw4YAgApKQEpKSkpKSkpKSkpKSkpKSkpKSkCJwsgAUEBaiEBIANBL2otAABBAXFFDQoMGAsgAUEBaiEBDBcLIAFBAWohASACLQAAQQJxDQALQQAhAiADQQA2AhwgAyABNgIUIANBnxU2AhAgA0EMNgIMDJUDCyADLQAuQYABcUUNAQtBACEAAkAgAygCOCICRQ0AIAIoAlwiAkUNACADIAIRAAAhAAsgAEUN5gIgAEEVRgRAIANBJDYCHCADIAE2AhQgA0GbGzYCECADQRU2AgxBACECDJQDC0EAIQIgA0EANgIcIAMgATYCFCADQZAONgIQIANBFDYCDAyTAwtBACECIANBADYCHCADIAE2AhQgA0G+IDYCECADQQI2AgwMkgMLIAMoAgQhAEEAIQIgA0EANgIEIAMgACABIAynaiIBEDIiAEUNKyADQQc2AhwgAyABNgIUIAMgADYCDAyRAwsgAy0ALkHAAHFFDQELQQAhAAJAIAMoAjgiAkUNACACKAJYIgJFDQAgAyACEQAAIQALIABFDSsgAEEVRgRAIANBCjYCHCADIAE2AhQgA0HrGTYCECADQRU2AgxBACECDJADC0EAIQIgA0EANgIcIAMgATYCFCADQZMMNgIQIANBEzYCDAyPAwtBACECIANBADYCHCADIAE2AhQgA0GCFTYCECADQQI2AgwMjgMLQQAhAiADQQA2AhwgAyABNgIUIANB3RQ2AhAgA0EZNgIMDI0DC0EAIQIgA0EANgIcIAMgATYCFCADQeYdNgIQIANBGTYCDAyMAwsgAEEVRg09QQAhAiADQQA2AhwgAyABNgIUIANB0A82AhAgA0EiNgIMDIsDCyADKAIEIQBBACECIANBADYCBCADIAAgARAzIgBFDSggA0ENNgIcIAMgATYCFCADIAA2AgwMigMLIABBFUYNOkEAIQIgA0EANgIcIAMgATYCFCADQdAPNgIQIANBIjYCDAyJAwsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQMyIARQRAIAFBAWohAQwoCyADQQ42AhwgAyAANgIMIAMgAUEBajYCFAyIAwsgAEEVRg03QQAhAiADQQA2AhwgAyABNgIUIANB0A82AhAgA0EiNgIMDIcDCyADKAIEIQBBACECIANBADYCBCADIAAgARAzIgBFBEAgAUEBaiEBDCcLIANBDzYCHCADIAA2AgwgAyABQQFqNgIUDIYDC0EAIQIgA0EANgIcIAMgATYCFCADQeIXNgIQIANBGTYCDAyFAwsgAEEVRg0zQQAhAiADQQA2AhwgAyABNgIUIANB1gw2AhAgA0EjNgIMDIQDCyADKAIEIQBBACECIANBADYCBCADIAAgARA0IgBFDSUgA0ERNgIcIAMgATYCFCADIAA2AgwMgwMLIABBFUYNMEEAIQIgA0EANgIcIAMgATYCFCADQdYMNgIQIANBIzYCDAyCAwsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQwlCyADQRI2AhwgAyAANgIMIAMgAUEBajYCFAyBAwsgA0Evai0AAEEBcUUNAQtBFyECDOYCC0EAIQIgA0EANgIcIAMgATYCFCADQeIXNgIQIANBGTYCDAz+AgsgAEE7Rw0AIAFBAWohAQwMC0EAIQIgA0EANgIcIAMgATYCFCADQZIYNgIQIANBAjYCDAz8AgsgAEEVRg0oQQAhAiADQQA2AhwgAyABNgIUIANB1gw2AhAgA0EjNgIMDPsCCyADQRQ2AhwgAyABNgIUIAMgADYCDAz6AgsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQz1AgsgA0EVNgIcIAMgADYCDCADIAFBAWo2AhQM+QILIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDQiAEUEQCABQQFqIQEM8wILIANBFzYCHCADIAA2AgwgAyABQQFqNgIUDPgCCyAAQRVGDSNBACECIANBADYCHCADIAE2AhQgA0HWDDYCECADQSM2AgwM9wILIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDQiAEUEQCABQQFqIQEMHQsgA0EZNgIcIAMgADYCDCADIAFBAWo2AhQM9gILIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDQiAEUEQCABQQFqIQEM7wILIANBGjYCHCADIAA2AgwgAyABQQFqNgIUDPUCCyAAQRVGDR9BACECIANBADYCHCADIAE2AhQgA0HQDzYCECADQSI2AgwM9AILIAMoAgQhACADQQA2AgQgAyAAIAEQMyIARQRAIAFBAWohAQwbCyADQRw2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIM8wILIAMoAgQhACADQQA2AgQgAyAAIAEQMyIARQRAIAFBAWohAQzrAgsgA0EdNgIcIAMgADYCDCADIAFBAWo2AhRBACECDPICCyAAQTtHDQEgAUEBaiEBC0EmIQIM1wILQQAhAiADQQA2AhwgAyABNgIUIANBnxU2AhAgA0EMNgIMDO8CCyABIARHBEADQCABLQAAQSBHDYQCIAQgAUEBaiIBRw0AC0EsIQIM7wILQSwhAgzuAgsgASAERgRAQTQhAgzuAgsCQAJAA0ACQCABLQAAQQprDgQCAAADAAsgBCABQQFqIgFHDQALQTQhAgzvAgsgAygCBCEAIANBADYCBCADIAAgARAxIgBFDZ8CIANBMjYCHCADIAE2AhQgAyAANgIMQQAhAgzuAgsgAygCBCEAIANBADYCBCADIAAgARAxIgBFBEAgAUEBaiEBDJ8CCyADQTI2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIM7QILIAEgBEcEQAJAA0AgAS0AAEEwayIAQf8BcUEKTwRAQTohAgzXAgsgAykDICILQpmz5syZs+bMGVYNASADIAtCCn4iCjcDICAKIACtQv8BgyILQn+FVg0BIAMgCiALfDcDICAEIAFBAWoiAUcNAAtBwAAhAgzuAgsgAygCBCEAIANBADYCBCADIAAgAUEBaiIBEDEiAA0XDOICC0HAACECDOwCCyABIARGBEBByQAhAgzsAgsCQANAAkAgAS0AAEEJaw4YAAKiAqICqQKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogIAogILIAQgAUEBaiIBRw0AC0HJACECDOwCCyABQQFqIQEgA0Evai0AAEEBcQ2lAiADQQA2AhwgAyABNgIUIANBlxA2AhAgA0EKNgIMQQAhAgzrAgsgASAERwRAA0AgAS0AAEEgRw0VIAQgAUEBaiIBRw0AC0H4ACECDOsCC0H4ACECDOoCCyADQQI6ACgMOAtBACECIANBADYCHCADQb8LNgIQIANBAjYCDCADIAFBAWo2AhQM6AILQQAhAgzOAgtBDSECDM0CC0ETIQIMzAILQRUhAgzLAgtBFiECDMoCC0EYIQIMyQILQRkhAgzIAgtBGiECDMcCC0EbIQIMxgILQRwhAgzFAgtBHSECDMQCC0EeIQIMwwILQR8hAgzCAgtBICECDMECC0EiIQIMwAILQSMhAgy/AgtBJSECDL4CC0HlACECDL0CCyADQT02AhwgAyABNgIUIAMgADYCDEEAIQIM1QILIANBGzYCHCADIAE2AhQgA0GkHDYCECADQRU2AgxBACECDNQCCyADQSA2AhwgAyABNgIUIANBmBo2AhAgA0EVNgIMQQAhAgzTAgsgA0ETNgIcIAMgATYCFCADQZgaNgIQIANBFTYCDEEAIQIM0gILIANBCzYCHCADIAE2AhQgA0GYGjYCECADQRU2AgxBACECDNECCyADQRA2AhwgAyABNgIUIANBmBo2AhAgA0EVNgIMQQAhAgzQAgsgA0EgNgIcIAMgATYCFCADQaQcNgIQIANBFTYCDEEAIQIMzwILIANBCzYCHCADIAE2AhQgA0GkHDYCECADQRU2AgxBACECDM4CCyADQQw2AhwgAyABNgIUIANBpBw2AhAgA0EVNgIMQQAhAgzNAgtBACECIANBADYCHCADIAE2AhQgA0HdDjYCECADQRI2AgwMzAILAkADQAJAIAEtAABBCmsOBAACAgACCyAEIAFBAWoiAUcNAAtB/QEhAgzMAgsCQAJAIAMtADZBAUcNAEEAIQACQCADKAI4IgJFDQAgAigCYCICRQ0AIAMgAhEAACEACyAARQ0AIABBFUcNASADQfwBNgIcIAMgATYCFCADQdwZNgIQIANBFTYCDEEAIQIMzQILQdwBIQIMswILIANBADYCHCADIAE2AhQgA0H5CzYCECADQR82AgxBACECDMsCCwJAAkAgAy0AKEEBaw4CBAEAC0HbASECDLICC0HUASECDLECCyADQQI6ADFBACEAAkAgAygCOCICRQ0AIAIoAgAiAkUNACADIAIRAAAhAAsgAEUEQEHdASECDLECCyAAQRVHBEAgA0EANgIcIAMgATYCFCADQbQMNgIQIANBEDYCDEEAIQIMygILIANB+wE2AhwgAyABNgIUIANBgRo2AhAgA0EVNgIMQQAhAgzJAgsgASAERgRAQfoBIQIMyQILIAEtAABByABGDQEgA0EBOgAoC0HAASECDK4CC0HaASECDK0CCyABIARHBEAgA0EMNgIIIAMgATYCBEHZASECDK0CC0H5ASECDMUCCyABIARGBEBB+AEhAgzFAgsgAS0AAEHIAEcNBCABQQFqIQFB2AEhAgyrAgsgASAERgRAQfcBIQIMxAILAkACQCABLQAAQcUAaw4QAAUFBQUFBQUFBQUFBQUFAQULIAFBAWohAUHWASECDKsCCyABQQFqIQFB1wEhAgyqAgtB9gEhAiABIARGDcICIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQbrVAGotAABHDQMgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADMMCCyADKAIEIQAgA0IANwMAIAMgACAGQQFqIgEQLiIARQRAQeMBIQIMqgILIANB9QE2AhwgAyABNgIUIAMgADYCDEEAIQIMwgILQfQBIQIgASAERg3BAiADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEG41QBqLQAARw0CIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzCAgsgA0GBBDsBKCADKAIEIQAgA0IANwMAIAMgACAGQQFqIgEQLiIADQMMAgsgA0EANgIAC0EAIQIgA0EANgIcIAMgATYCFCADQeUfNgIQIANBCDYCDAy/AgtB1QEhAgylAgsgA0HzATYCHCADIAE2AhQgAyAANgIMQQAhAgy9AgtBACEAAkAgAygCOCICRQ0AIAIoAkAiAkUNACADIAIRAAAhAAsgAEUNbiAAQRVHBEAgA0EANgIcIAMgATYCFCADQYIPNgIQIANBIDYCDEEAIQIMvQILIANBjwE2AhwgAyABNgIUIANB7Bs2AhAgA0EVNgIMQQAhAgy8AgsgASAERwRAIANBDTYCCCADIAE2AgRB0wEhAgyjAgtB8gEhAgy7AgsgASAERgRAQfEBIQIMuwILAkACQAJAIAEtAABByABrDgsAAQgICAgICAgIAggLIAFBAWohAUHQASECDKMCCyABQQFqIQFB0QEhAgyiAgsgAUEBaiEBQdIBIQIMoQILQfABIQIgASAERg25AiADKAIAIgAgBCABa2ohBiABIABrQQJqIQUDQCABLQAAIABBtdUAai0AAEcNBCAAQQJGDQMgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAY2AgAMuQILQe8BIQIgASAERg24AiADKAIAIgAgBCABa2ohBiABIABrQQFqIQUDQCABLQAAIABBs9UAai0AAEcNAyAAQQFGDQIgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAY2AgAMuAILQe4BIQIgASAERg23AiADKAIAIgAgBCABa2ohBiABIABrQQJqIQUDQCABLQAAIABBsNUAai0AAEcNAiAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAY2AgAMtwILIAMoAgQhACADQgA3AwAgAyAAIAVBAWoiARArIgBFDQIgA0HsATYCHCADIAE2AhQgAyAANgIMQQAhAgy2AgsgA0EANgIACyADKAIEIQAgA0EANgIEIAMgACABECsiAEUNnAIgA0HtATYCHCADIAE2AhQgAyAANgIMQQAhAgy0AgtBzwEhAgyaAgtBACEAAkAgAygCOCICRQ0AIAIoAjQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0HqDTYCECADQSY2AgxBACECDLQCC0HOASECDJoCCyADQesBNgIcIAMgATYCFCADQYAbNgIQIANBFTYCDEEAIQIMsgILIAEgBEYEQEHrASECDLICCyABLQAAQS9GBEAgAUEBaiEBDAELIANBADYCHCADIAE2AhQgA0GyODYCECADQQg2AgxBACECDLECC0HNASECDJcCCyABIARHBEAgA0EONgIIIAMgATYCBEHMASECDJcCC0HqASECDK8CCyABIARGBEBB6QEhAgyvAgsgAS0AAEEwayIAQf8BcUEKSQRAIAMgADoAKiABQQFqIQFBywEhAgyWAgsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDZcCIANB6AE2AhwgAyABNgIUIAMgADYCDEEAIQIMrgILIAEgBEYEQEHnASECDK4CCwJAIAEtAABBLkYEQCABQQFqIQEMAQsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDZgCIANB5gE2AhwgAyABNgIUIAMgADYCDEEAIQIMrgILQcoBIQIMlAILIAEgBEYEQEHlASECDK0CC0EAIQBBASEFQQEhB0EAIQICQAJAAkACQAJAAn8CQAJAAkACQAJAAkACQCABLQAAQTBrDgoKCQABAgMEBQYICwtBAgwGC0EDDAULQQQMBAtBBQwDC0EGDAILQQcMAQtBCAshAkEAIQVBACEHDAILQQkhAkEBIQBBACEFQQAhBwwBC0EAIQVBASECCyADIAI6ACsgAUEBaiEBAkACQCADLQAuQRBxDQACQAJAAkAgAy0AKg4DAQACBAsgB0UNAwwCCyAADQEMAgsgBUUNAQsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDQIgA0HiATYCHCADIAE2AhQgAyAANgIMQQAhAgyvAgsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDZoCIANB4wE2AhwgAyABNgIUIAMgADYCDEEAIQIMrgILIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ2YAiADQeQBNgIcIAMgATYCFCADIAA2AgwMrQILQckBIQIMkwILQQAhAAJAIAMoAjgiAkUNACACKAJEIgJFDQAgAyACEQAAIQALAkAgAARAIABBFUYNASADQQA2AhwgAyABNgIUIANBpA02AhAgA0EhNgIMQQAhAgytAgtByAEhAgyTAgsgA0HhATYCHCADIAE2AhQgA0HQGjYCECADQRU2AgxBACECDKsCCyABIARGBEBB4QEhAgyrAgsCQCABLQAAQSBGBEAgA0EAOwE0IAFBAWohAQwBCyADQQA2AhwgAyABNgIUIANBmRE2AhAgA0EJNgIMQQAhAgyrAgtBxwEhAgyRAgsgASAERgRAQeABIQIMqgILAkAgAS0AAEEwa0H/AXEiAkEKSQRAIAFBAWohAQJAIAMvATQiAEGZM0sNACADIABBCmwiADsBNCAAQf7/A3EgAkH//wNzSw0AIAMgACACajsBNAwCC0EAIQIgA0EANgIcIAMgATYCFCADQZUeNgIQIANBDTYCDAyrAgsgA0EANgIcIAMgATYCFCADQZUeNgIQIANBDTYCDEEAIQIMqgILQcYBIQIMkAILIAEgBEYEQEHfASECDKkCCwJAIAEtAABBMGtB/wFxIgJBCkkEQCABQQFqIQECQCADLwE0IgBBmTNLDQAgAyAAQQpsIgA7ATQgAEH+/wNxIAJB//8Dc0sNACADIAAgAmo7ATQMAgtBACECIANBADYCHCADIAE2AhQgA0GVHjYCECADQQ02AgwMqgILIANBADYCHCADIAE2AhQgA0GVHjYCECADQQ02AgxBACECDKkCC0HFASECDI8CCyABIARGBEBB3gEhAgyoAgsCQCABLQAAQTBrQf8BcSICQQpJBEAgAUEBaiEBAkAgAy8BNCIAQZkzSw0AIAMgAEEKbCIAOwE0IABB/v8DcSACQf//A3NLDQAgAyAAIAJqOwE0DAILQQAhAiADQQA2AhwgAyABNgIUIANBlR42AhAgA0ENNgIMDKkCCyADQQA2AhwgAyABNgIUIANBlR42AhAgA0ENNgIMQQAhAgyoAgtBxAEhAgyOAgsgASAERgRAQd0BIQIMpwILAkACQAJAAkAgAS0AAEEKaw4XAgMDAAMDAwMDAwMDAwMDAwMDAwMDAwEDCyABQQFqDAULIAFBAWohAUHDASECDI8CCyABQQFqIQEgA0Evai0AAEEBcQ0IIANBADYCHCADIAE2AhQgA0GNCzYCECADQQ02AgxBACECDKcCCyADQQA2AhwgAyABNgIUIANBjQs2AhAgA0ENNgIMQQAhAgymAgsgASAERwRAIANBDzYCCCADIAE2AgRBASECDI0CC0HcASECDKUCCwJAAkADQAJAIAEtAABBCmsOBAIAAAMACyAEIAFBAWoiAUcNAAtB2wEhAgymAgsgAygCBCEAIANBADYCBCADIAAgARAtIgBFBEAgAUEBaiEBDAQLIANB2gE2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMpQILIAMoAgQhACADQQA2AgQgAyAAIAEQLSIADQEgAUEBagshAUHBASECDIoCCyADQdkBNgIcIAMgADYCDCADIAFBAWo2AhRBACECDKICC0HCASECDIgCCyADQS9qLQAAQQFxDQEgA0EANgIcIAMgATYCFCADQeQcNgIQIANBGTYCDEEAIQIMoAILIAEgBEYEQEHZASECDKACCwJAAkACQCABLQAAQQprDgQBAgIAAgsgAUEBaiEBDAILIAFBAWohAQwBCyADLQAuQcAAcUUNAQtBACEAAkAgAygCOCICRQ0AIAIoAjwiAkUNACADIAIRAAAhAAsgAEUNoAEgAEEVRgRAIANB2QA2AhwgAyABNgIUIANBtxo2AhAgA0EVNgIMQQAhAgyfAgsgA0EANgIcIAMgATYCFCADQYANNgIQIANBGzYCDEEAIQIMngILIANBADYCHCADIAE2AhQgA0HcKDYCECADQQI2AgxBACECDJ0CCyABIARHBEAgA0EMNgIIIAMgATYCBEG/ASECDIQCC0HYASECDJwCCyABIARGBEBB1wEhAgycAgsCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAEtAABBwQBrDhUAAQIDWgQFBlpaWgcICQoLDA0ODxBaCyABQQFqIQFB+wAhAgySAgsgAUEBaiEBQfwAIQIMkQILIAFBAWohAUGBASECDJACCyABQQFqIQFBhQEhAgyPAgsgAUEBaiEBQYYBIQIMjgILIAFBAWohAUGJASECDI0CCyABQQFqIQFBigEhAgyMAgsgAUEBaiEBQY0BIQIMiwILIAFBAWohAUGWASECDIoCCyABQQFqIQFBlwEhAgyJAgsgAUEBaiEBQZgBIQIMiAILIAFBAWohAUGlASECDIcCCyABQQFqIQFBpgEhAgyGAgsgAUEBaiEBQawBIQIMhQILIAFBAWohAUG0ASECDIQCCyABQQFqIQFBtwEhAgyDAgsgAUEBaiEBQb4BIQIMggILIAEgBEYEQEHWASECDJsCCyABLQAAQc4ARw1IIAFBAWohAUG9ASECDIECCyABIARGBEBB1QEhAgyaAgsCQAJAAkAgAS0AAEHCAGsOEgBKSkpKSkpKSkoBSkpKSkpKAkoLIAFBAWohAUG4ASECDIICCyABQQFqIQFBuwEhAgyBAgsgAUEBaiEBQbwBIQIMgAILQdQBIQIgASAERg2YAiADKAIAIgAgBCABa2ohBSABIABrQQdqIQYCQANAIAEtAAAgAEGo1QBqLQAARw1FIABBB0YNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyZAgsgA0EANgIAIAZBAWohAUEbDEULIAEgBEYEQEHTASECDJgCCwJAAkAgAS0AAEHJAGsOBwBHR0dHRwFHCyABQQFqIQFBuQEhAgz/AQsgAUEBaiEBQboBIQIM/gELQdIBIQIgASAERg2WAiADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGm1QBqLQAARw1DIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyXAgsgA0EANgIAIAZBAWohAUEPDEMLQdEBIQIgASAERg2VAiADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGk1QBqLQAARw1CIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyWAgsgA0EANgIAIAZBAWohAUEgDEILQdABIQIgASAERg2UAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGh1QBqLQAARw1BIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyVAgsgA0EANgIAIAZBAWohAUESDEELIAEgBEYEQEHPASECDJQCCwJAAkAgAS0AAEHFAGsODgBDQ0NDQ0NDQ0NDQ0MBQwsgAUEBaiEBQbUBIQIM+wELIAFBAWohAUG2ASECDPoBC0HOASECIAEgBEYNkgIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBntUAai0AAEcNPyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMkwILIANBADYCACAGQQFqIQFBBww/C0HNASECIAEgBEYNkQIgAygCACIAIAQgAWtqIQUgASAAa0EFaiEGAkADQCABLQAAIABBmNUAai0AAEcNPiAAQQVGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMkgILIANBADYCACAGQQFqIQFBKAw+CyABIARGBEBBzAEhAgyRAgsCQAJAAkAgAS0AAEHFAGsOEQBBQUFBQUFBQUEBQUFBQUECQQsgAUEBaiEBQbEBIQIM+QELIAFBAWohAUGyASECDPgBCyABQQFqIQFBswEhAgz3AQtBywEhAiABIARGDY8CIAMoAgAiACAEIAFraiEFIAEgAGtBBmohBgJAA0AgAS0AACAAQZHVAGotAABHDTwgAEEGRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJACCyADQQA2AgAgBkEBaiEBQRoMPAtBygEhAiABIARGDY4CIAMoAgAiACAEIAFraiEFIAEgAGtBA2ohBgJAA0AgAS0AACAAQY3VAGotAABHDTsgAEEDRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADI8CCyADQQA2AgAgBkEBaiEBQSEMOwsgASAERgRAQckBIQIMjgILAkACQCABLQAAQcEAaw4UAD09PT09PT09PT09PT09PT09PQE9CyABQQFqIQFBrQEhAgz1AQsgAUEBaiEBQbABIQIM9AELIAEgBEYEQEHIASECDI0CCwJAAkAgAS0AAEHVAGsOCwA8PDw8PDw8PDwBPAsgAUEBaiEBQa4BIQIM9AELIAFBAWohAUGvASECDPMBC0HHASECIAEgBEYNiwIgAygCACIAIAQgAWtqIQUgASAAa0EIaiEGAkADQCABLQAAIABBhNUAai0AAEcNOCAAQQhGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMjAILIANBADYCACAGQQFqIQFBKgw4CyABIARGBEBBxgEhAgyLAgsgAS0AAEHQAEcNOCABQQFqIQFBJQw3C0HFASECIAEgBEYNiQIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBgdUAai0AAEcNNiAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMigILIANBADYCACAGQQFqIQFBDgw2CyABIARGBEBBxAEhAgyJAgsgAS0AAEHFAEcNNiABQQFqIQFBqwEhAgzvAQsgASAERgRAQcMBIQIMiAILAkACQAJAAkAgAS0AAEHCAGsODwABAjk5OTk5OTk5OTk5AzkLIAFBAWohAUGnASECDPEBCyABQQFqIQFBqAEhAgzwAQsgAUEBaiEBQakBIQIM7wELIAFBAWohAUGqASECDO4BC0HCASECIAEgBEYNhgIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABB/tQAai0AAEcNMyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMhwILIANBADYCACAGQQFqIQFBFAwzC0HBASECIAEgBEYNhQIgAygCACIAIAQgAWtqIQUgASAAa0EEaiEGAkADQCABLQAAIABB+dQAai0AAEcNMiAAQQRGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMhgILIANBADYCACAGQQFqIQFBKwwyC0HAASECIAEgBEYNhAIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABB9tQAai0AAEcNMSAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMhQILIANBADYCACAGQQFqIQFBLAwxC0G/ASECIAEgBEYNgwIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBodUAai0AAEcNMCAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMhAILIANBADYCACAGQQFqIQFBEQwwC0G+ASECIAEgBEYNggIgAygCACIAIAQgAWtqIQUgASAAa0EDaiEGAkADQCABLQAAIABB8tQAai0AAEcNLyAAQQNGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMgwILIANBADYCACAGQQFqIQFBLgwvCyABIARGBEBBvQEhAgyCAgsCQAJAAkACQAJAIAEtAABBwQBrDhUANDQ0NDQ0NDQ0NAE0NAI0NAM0NAQ0CyABQQFqIQFBmwEhAgzsAQsgAUEBaiEBQZwBIQIM6wELIAFBAWohAUGdASECDOoBCyABQQFqIQFBogEhAgzpAQsgAUEBaiEBQaQBIQIM6AELIAEgBEYEQEG8ASECDIECCwJAAkAgAS0AAEHSAGsOAwAwATALIAFBAWohAUGjASECDOgBCyABQQFqIQFBBAwtC0G7ASECIAEgBEYN/wEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABB8NQAai0AAEcNLCAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMgAILIANBADYCACAGQQFqIQFBHQwsCyABIARGBEBBugEhAgz/AQsCQAJAIAEtAABByQBrDgcBLi4uLi4ALgsgAUEBaiEBQaEBIQIM5gELIAFBAWohAUEiDCsLIAEgBEYEQEG5ASECDP4BCyABLQAAQdAARw0rIAFBAWohAUGgASECDOQBCyABIARGBEBBuAEhAgz9AQsCQAJAIAEtAABBxgBrDgsALCwsLCwsLCwsASwLIAFBAWohAUGeASECDOQBCyABQQFqIQFBnwEhAgzjAQtBtwEhAiABIARGDfsBIAMoAgAiACAEIAFraiEFIAEgAGtBA2ohBgJAA0AgAS0AACAAQezUAGotAABHDSggAEEDRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPwBCyADQQA2AgAgBkEBaiEBQQ0MKAtBtgEhAiABIARGDfoBIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQaHVAGotAABHDScgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPsBCyADQQA2AgAgBkEBaiEBQQwMJwtBtQEhAiABIARGDfkBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQerUAGotAABHDSYgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPoBCyADQQA2AgAgBkEBaiEBQQMMJgtBtAEhAiABIARGDfgBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQejUAGotAABHDSUgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPkBCyADQQA2AgAgBkEBaiEBQSYMJQsgASAERgRAQbMBIQIM+AELAkACQCABLQAAQdQAaw4CAAEnCyABQQFqIQFBmQEhAgzfAQsgAUEBaiEBQZoBIQIM3gELQbIBIQIgASAERg32ASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHm1ABqLQAARw0jIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAz3AQsgA0EANgIAIAZBAWohAUEnDCMLQbEBIQIgASAERg31ASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHk1ABqLQAARw0iIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAz2AQsgA0EANgIAIAZBAWohAUEcDCILQbABIQIgASAERg30ASADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEHe1ABqLQAARw0hIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAz1AQsgA0EANgIAIAZBAWohAUEGDCELQa8BIQIgASAERg3zASADKAIAIgAgBCABa2ohBSABIABrQQRqIQYCQANAIAEtAAAgAEHZ1ABqLQAARw0gIABBBEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAz0AQsgA0EANgIAIAZBAWohAUEZDCALIAEgBEYEQEGuASECDPMBCwJAAkACQAJAIAEtAABBLWsOIwAkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJAEkJCQkJAIkJCQDJAsgAUEBaiEBQY4BIQIM3AELIAFBAWohAUGPASECDNsBCyABQQFqIQFBlAEhAgzaAQsgAUEBaiEBQZUBIQIM2QELQa0BIQIgASAERg3xASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHX1ABqLQAARw0eIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzyAQsgA0EANgIAIAZBAWohAUELDB4LIAEgBEYEQEGsASECDPEBCwJAAkAgAS0AAEHBAGsOAwAgASALIAFBAWohAUGQASECDNgBCyABQQFqIQFBkwEhAgzXAQsgASAERgRAQasBIQIM8AELAkACQCABLQAAQcEAaw4PAB8fHx8fHx8fHx8fHx8BHwsgAUEBaiEBQZEBIQIM1wELIAFBAWohAUGSASECDNYBCyABIARGBEBBqgEhAgzvAQsgAS0AAEHMAEcNHCABQQFqIQFBCgwbC0GpASECIAEgBEYN7QEgAygCACIAIAQgAWtqIQUgASAAa0EFaiEGAkADQCABLQAAIABB0dQAai0AAEcNGiAAQQVGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM7gELIANBADYCACAGQQFqIQFBHgwaC0GoASECIAEgBEYN7AEgAygCACIAIAQgAWtqIQUgASAAa0EGaiEGAkADQCABLQAAIABBytQAai0AAEcNGSAAQQZGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM7QELIANBADYCACAGQQFqIQFBFQwZC0GnASECIAEgBEYN6wEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBx9QAai0AAEcNGCAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM7AELIANBADYCACAGQQFqIQFBFwwYC0GmASECIAEgBEYN6gEgAygCACIAIAQgAWtqIQUgASAAa0EFaiEGAkADQCABLQAAIABBwdQAai0AAEcNFyAAQQVGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM6wELIANBADYCACAGQQFqIQFBGAwXCyABIARGBEBBpQEhAgzqAQsCQAJAIAEtAABByQBrDgcAGRkZGRkBGQsgAUEBaiEBQYsBIQIM0QELIAFBAWohAUGMASECDNABC0GkASECIAEgBEYN6AEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABBptUAai0AAEcNFSAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM6QELIANBADYCACAGQQFqIQFBCQwVC0GjASECIAEgBEYN5wEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABBpNUAai0AAEcNFCAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM6AELIANBADYCACAGQQFqIQFBHwwUC0GiASECIAEgBEYN5gEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBvtQAai0AAEcNEyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM5wELIANBADYCACAGQQFqIQFBAgwTC0GhASECIAEgBEYN5QEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGA0AgAS0AACAAQbzUAGotAABHDREgAEEBRg0CIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADOUBCyABIARGBEBBoAEhAgzlAQtBASABLQAAQd8ARw0RGiABQQFqIQFBhwEhAgzLAQsgA0EANgIAIAZBAWohAUGIASECDMoBC0GfASECIAEgBEYN4gEgAygCACIAIAQgAWtqIQUgASAAa0EIaiEGAkADQCABLQAAIABBhNUAai0AAEcNDyAAQQhGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM4wELIANBADYCACAGQQFqIQFBKQwPC0GeASECIAEgBEYN4QEgAygCACIAIAQgAWtqIQUgASAAa0EDaiEGAkADQCABLQAAIABBuNQAai0AAEcNDiAAQQNGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM4gELIANBADYCACAGQQFqIQFBLQwOCyABIARGBEBBnQEhAgzhAQsgAS0AAEHFAEcNDiABQQFqIQFBhAEhAgzHAQsgASAERgRAQZwBIQIM4AELAkACQCABLQAAQcwAaw4IAA8PDw8PDwEPCyABQQFqIQFBggEhAgzHAQsgAUEBaiEBQYMBIQIMxgELQZsBIQIgASAERg3eASADKAIAIgAgBCABa2ohBSABIABrQQRqIQYCQANAIAEtAAAgAEGz1ABqLQAARw0LIABBBEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzfAQsgA0EANgIAIAZBAWohAUEjDAsLQZoBIQIgASAERg3dASADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGw1ABqLQAARw0KIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzeAQsgA0EANgIAIAZBAWohAUEADAoLIAEgBEYEQEGZASECDN0BCwJAAkAgAS0AAEHIAGsOCAAMDAwMDAwBDAsgAUEBaiEBQf0AIQIMxAELIAFBAWohAUGAASECDMMBCyABIARGBEBBmAEhAgzcAQsCQAJAIAEtAABBzgBrDgMACwELCyABQQFqIQFB/gAhAgzDAQsgAUEBaiEBQf8AIQIMwgELIAEgBEYEQEGXASECDNsBCyABLQAAQdkARw0IIAFBAWohAUEIDAcLQZYBIQIgASAERg3ZASADKAIAIgAgBCABa2ohBSABIABrQQNqIQYCQANAIAEtAAAgAEGs1ABqLQAARw0GIABBA0YNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzaAQsgA0EANgIAIAZBAWohAUEFDAYLQZUBIQIgASAERg3YASADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEGm1ABqLQAARw0FIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzZAQsgA0EANgIAIAZBAWohAUEWDAULQZQBIQIgASAERg3XASADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGh1QBqLQAARw0EIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzYAQsgA0EANgIAIAZBAWohAUEQDAQLIAEgBEYEQEGTASECDNcBCwJAAkAgAS0AAEHDAGsODAAGBgYGBgYGBgYGAQYLIAFBAWohAUH5ACECDL4BCyABQQFqIQFB+gAhAgy9AQtBkgEhAiABIARGDdUBIAMoAgAiACAEIAFraiEFIAEgAGtBBWohBgJAA0AgAS0AACAAQaDUAGotAABHDQIgAEEFRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADNYBCyADQQA2AgAgBkEBaiEBQSQMAgsgA0EANgIADAILIAEgBEYEQEGRASECDNQBCyABLQAAQcwARw0BIAFBAWohAUETCzoAKSADKAIEIQAgA0EANgIEIAMgACABEC4iAA0CDAELQQAhAiADQQA2AhwgAyABNgIUIANB/h82AhAgA0EGNgIMDNEBC0H4ACECDLcBCyADQZABNgIcIAMgATYCFCADIAA2AgxBACECDM8BC0EAIQACQCADKAI4IgJFDQAgAigCQCICRQ0AIAMgAhEAACEACyAARQ0AIABBFUYNASADQQA2AhwgAyABNgIUIANBgg82AhAgA0EgNgIMQQAhAgzOAQtB9wAhAgy0AQsgA0GPATYCHCADIAE2AhQgA0HsGzYCECADQRU2AgxBACECDMwBCyABIARGBEBBjwEhAgzMAQsCQCABLQAAQSBGBEAgAUEBaiEBDAELIANBADYCHCADIAE2AhQgA0GbHzYCECADQQY2AgxBACECDMwBC0ECIQIMsgELA0AgAS0AAEEgRw0CIAQgAUEBaiIBRw0AC0GOASECDMoBCyABIARGBEBBjQEhAgzKAQsCQCABLQAAQQlrDgRKAABKAAtB9QAhAgywAQsgAy0AKUEFRgRAQfYAIQIMsAELQfQAIQIMrwELIAEgBEYEQEGMASECDMgBCyADQRA2AgggAyABNgIEDAoLIAEgBEYEQEGLASECDMcBCwJAIAEtAABBCWsOBEcAAEcAC0HzACECDK0BCyABIARHBEAgA0EQNgIIIAMgATYCBEHxACECDK0BC0GKASECDMUBCwJAIAEgBEcEQANAIAEtAABBoNAAai0AACIAQQNHBEACQCAAQQFrDgJJAAQLQfAAIQIMrwELIAQgAUEBaiIBRw0AC0GIASECDMYBC0GIASECDMUBCyADQQA2AhwgAyABNgIUIANB2yA2AhAgA0EHNgIMQQAhAgzEAQsgASAERgRAQYkBIQIMxAELAkACQAJAIAEtAABBoNIAai0AAEEBaw4DRgIAAQtB8gAhAgysAQsgA0EANgIcIAMgATYCFCADQbQSNgIQIANBBzYCDEEAIQIMxAELQeoAIQIMqgELIAEgBEcEQCABQQFqIQFB7wAhAgyqAQtBhwEhAgzCAQsgBCABIgBGBEBBhgEhAgzCAQsgAC0AACIBQS9GBEAgAEEBaiEBQe4AIQIMqQELIAFBCWsiAkEXSw0BIAAhAUEBIAJ0QZuAgARxDUEMAQsgBCABIgBGBEBBhQEhAgzBAQsgAC0AAEEvRw0AIABBAWohAQwDC0EAIQIgA0EANgIcIAMgADYCFCADQdsgNgIQIANBBzYCDAy/AQsCQAJAAkACQAJAA0AgAS0AAEGgzgBqLQAAIgBBBUcEQAJAAkAgAEEBaw4IRwUGBwgABAEIC0HrACECDK0BCyABQQFqIQFB7QAhAgysAQsgBCABQQFqIgFHDQALQYQBIQIMwwELIAFBAWoMFAsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDR4gA0HbADYCHCADIAE2AhQgAyAANgIMQQAhAgzBAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDR4gA0HdADYCHCADIAE2AhQgAyAANgIMQQAhAgzAAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDR4gA0H6ADYCHCADIAE2AhQgAyAANgIMQQAhAgy/AQsgA0EANgIcIAMgATYCFCADQfkPNgIQIANBBzYCDEEAIQIMvgELIAEgBEYEQEGDASECDL4BCwJAIAEtAABBoM4Aai0AAEEBaw4IPgQFBgAIAgMHCyABQQFqIQELQQMhAgyjAQsgAUEBagwNC0EAIQIgA0EANgIcIANB0RI2AhAgA0EHNgIMIAMgAUEBajYCFAy6AQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDRYgA0HbADYCHCADIAE2AhQgAyAANgIMQQAhAgy5AQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDRYgA0HdADYCHCADIAE2AhQgAyAANgIMQQAhAgy4AQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDRYgA0H6ADYCHCADIAE2AhQgAyAANgIMQQAhAgy3AQsgA0EANgIcIAMgATYCFCADQfkPNgIQIANBBzYCDEEAIQIMtgELQewAIQIMnAELIAEgBEYEQEGCASECDLUBCyABQQFqDAILIAEgBEYEQEGBASECDLQBCyABQQFqDAELIAEgBEYNASABQQFqCyEBQQQhAgyYAQtBgAEhAgywAQsDQCABLQAAQaDMAGotAAAiAEECRwRAIABBAUcEQEHpACECDJkBCwwxCyAEIAFBAWoiAUcNAAtB/wAhAgyvAQsgASAERgRAQf4AIQIMrwELAkAgAS0AAEEJaw43LwMGLwQGBgYGBgYGBgYGBgYGBgYGBgYFBgYCBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGAAYLIAFBAWoLIQFBBSECDJQBCyABQQFqDAYLIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0IIANB2wA2AhwgAyABNgIUIAMgADYCDEEAIQIMqwELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0IIANB3QA2AhwgAyABNgIUIAMgADYCDEEAIQIMqgELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0IIANB+gA2AhwgAyABNgIUIAMgADYCDEEAIQIMqQELIANBADYCHCADIAE2AhQgA0GNFDYCECADQQc2AgxBACECDKgBCwJAAkACQAJAA0AgAS0AAEGgygBqLQAAIgBBBUcEQAJAIABBAWsOBi4DBAUGAAYLQegAIQIMlAELIAQgAUEBaiIBRw0AC0H9ACECDKsBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNByADQdsANgIcIAMgATYCFCADIAA2AgxBACECDKoBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNByADQd0ANgIcIAMgATYCFCADIAA2AgxBACECDKkBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNByADQfoANgIcIAMgATYCFCADIAA2AgxBACECDKgBCyADQQA2AhwgAyABNgIUIANB5Ag2AhAgA0EHNgIMQQAhAgynAQsgASAERg0BIAFBAWoLIQFBBiECDIwBC0H8ACECDKQBCwJAAkACQAJAA0AgAS0AAEGgyABqLQAAIgBBBUcEQCAAQQFrDgQpAgMEBQsgBCABQQFqIgFHDQALQfsAIQIMpwELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0DIANB2wA2AhwgAyABNgIUIAMgADYCDEEAIQIMpgELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0DIANB3QA2AhwgAyABNgIUIAMgADYCDEEAIQIMpQELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0DIANB+gA2AhwgAyABNgIUIAMgADYCDEEAIQIMpAELIANBADYCHCADIAE2AhQgA0G8CjYCECADQQc2AgxBACECDKMBC0HPACECDIkBC0HRACECDIgBC0HnACECDIcBCyABIARGBEBB+gAhAgygAQsCQCABLQAAQQlrDgQgAAAgAAsgAUEBaiEBQeYAIQIMhgELIAEgBEYEQEH5ACECDJ8BCwJAIAEtAABBCWsOBB8AAB8AC0EAIQACQCADKAI4IgJFDQAgAigCOCICRQ0AIAMgAhEAACEACyAARQRAQeIBIQIMhgELIABBFUcEQCADQQA2AhwgAyABNgIUIANByQ02AhAgA0EaNgIMQQAhAgyfAQsgA0H4ADYCHCADIAE2AhQgA0HqGjYCECADQRU2AgxBACECDJ4BCyABIARHBEAgA0ENNgIIIAMgATYCBEHkACECDIUBC0H3ACECDJ0BCyABIARGBEBB9gAhAgydAQsCQAJAAkAgAS0AAEHIAGsOCwABCwsLCwsLCwsCCwsgAUEBaiEBQd0AIQIMhQELIAFBAWohAUHgACECDIQBCyABQQFqIQFB4wAhAgyDAQtB9QAhAiABIARGDZsBIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQbXVAGotAABHDQggAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJwBCyADKAIEIQAgA0IANwMAIAMgACAGQQFqIgEQKyIABEAgA0H0ADYCHCADIAE2AhQgAyAANgIMQQAhAgycAQtB4gAhAgyCAQtBACEAAkAgAygCOCICRQ0AIAIoAjQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0HqDTYCECADQSY2AgxBACECDJwBC0HhACECDIIBCyADQfMANgIcIAMgATYCFCADQYAbNgIQIANBFTYCDEEAIQIMmgELIAMtACkiAEEja0ELSQ0JAkAgAEEGSw0AQQEgAHRBygBxRQ0ADAoLQQAhAiADQQA2AhwgAyABNgIUIANB7Qk2AhAgA0EINgIMDJkBC0HyACECIAEgBEYNmAEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABBs9UAai0AAEcNBSAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMmQELIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARArIgAEQCADQfEANgIcIAMgATYCFCADIAA2AgxBACECDJkBC0HfACECDH8LQQAhAAJAIAMoAjgiAkUNACACKAI0IgJFDQAgAyACEQAAIQALAkAgAARAIABBFUYNASADQQA2AhwgAyABNgIUIANB6g02AhAgA0EmNgIMQQAhAgyZAQtB3gAhAgx/CyADQfAANgIcIAMgATYCFCADQYAbNgIQIANBFTYCDEEAIQIMlwELIAMtAClBIUYNBiADQQA2AhwgAyABNgIUIANBkQo2AhAgA0EINgIMQQAhAgyWAQtB7wAhAiABIARGDZUBIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQbDVAGotAABHDQIgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJYBCyADKAIEIQAgA0IANwMAIAMgACAGQQFqIgEQKyIARQ0CIANB7QA2AhwgAyABNgIUIAMgADYCDEEAIQIMlQELIANBADYCAAsgAygCBCEAIANBADYCBCADIAAgARArIgBFDYABIANB7gA2AhwgAyABNgIUIAMgADYCDEEAIQIMkwELQdwAIQIMeQtBACEAAkAgAygCOCICRQ0AIAIoAjQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0HqDTYCECADQSY2AgxBACECDJMBC0HbACECDHkLIANB7AA2AhwgAyABNgIUIANBgBs2AhAgA0EVNgIMQQAhAgyRAQsgAy0AKSIAQSNJDQAgAEEuRg0AIANBADYCHCADIAE2AhQgA0HJCTYCECADQQg2AgxBACECDJABC0HaACECDHYLIAEgBEYEQEHrACECDI8BCwJAIAEtAABBL0YEQCABQQFqIQEMAQsgA0EANgIcIAMgATYCFCADQbI4NgIQIANBCDYCDEEAIQIMjwELQdkAIQIMdQsgASAERwRAIANBDjYCCCADIAE2AgRB2AAhAgx1C0HqACECDI0BCyABIARGBEBB6QAhAgyNAQsgAS0AAEEwayIAQf8BcUEKSQRAIAMgADoAKiABQQFqIQFB1wAhAgx0CyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNeiADQegANgIcIAMgATYCFCADIAA2AgxBACECDIwBCyABIARGBEBB5wAhAgyMAQsCQCABLQAAQS5GBEAgAUEBaiEBDAELIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ17IANB5gA2AhwgAyABNgIUIAMgADYCDEEAIQIMjAELQdYAIQIMcgsgASAERgRAQeUAIQIMiwELQQAhAEEBIQVBASEHQQAhAgJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAIAEtAABBMGsOCgoJAAECAwQFBggLC0ECDAYLQQMMBQtBBAwEC0EFDAMLQQYMAgtBBwwBC0EICyECQQAhBUEAIQcMAgtBCSECQQEhAEEAIQVBACEHDAELQQAhBUEBIQILIAMgAjoAKyABQQFqIQECQAJAIAMtAC5BEHENAAJAAkACQCADLQAqDgMBAAIECyAHRQ0DDAILIAANAQwCCyAFRQ0BCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNAiADQeIANgIcIAMgATYCFCADIAA2AgxBACECDI0BCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNfSADQeMANgIcIAMgATYCFCADIAA2AgxBACECDIwBCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNeyADQeQANgIcIAMgATYCFCADIAA2AgwMiwELQdQAIQIMcQsgAy0AKUEiRg2GAUHTACECDHALQQAhAAJAIAMoAjgiAkUNACACKAJEIgJFDQAgAyACEQAAIQALIABFBEBB1QAhAgxwCyAAQRVHBEAgA0EANgIcIAMgATYCFCADQaQNNgIQIANBITYCDEEAIQIMiQELIANB4QA2AhwgAyABNgIUIANB0Bo2AhAgA0EVNgIMQQAhAgyIAQsgASAERgRAQeAAIQIMiAELAkACQAJAAkACQCABLQAAQQprDgQBBAQABAsgAUEBaiEBDAELIAFBAWohASADQS9qLQAAQQFxRQ0BC0HSACECDHALIANBADYCHCADIAE2AhQgA0G2ETYCECADQQk2AgxBACECDIgBCyADQQA2AhwgAyABNgIUIANBthE2AhAgA0EJNgIMQQAhAgyHAQsgASAERgRAQd8AIQIMhwELIAEtAABBCkYEQCABQQFqIQEMCQsgAy0ALkHAAHENCCADQQA2AhwgAyABNgIUIANBthE2AhAgA0ECNgIMQQAhAgyGAQsgASAERgRAQd0AIQIMhgELIAEtAAAiAkENRgRAIAFBAWohAUHQACECDG0LIAEhACACQQlrDgQFAQEFAQsgBCABIgBGBEBB3AAhAgyFAQsgAC0AAEEKRw0AIABBAWoMAgtBACECIANBADYCHCADIAA2AhQgA0HKLTYCECADQQc2AgwMgwELIAEgBEYEQEHbACECDIMBCwJAIAEtAABBCWsOBAMAAAMACyABQQFqCyEBQc4AIQIMaAsgASAERgRAQdoAIQIMgQELIAEtAABBCWsOBAABAQABC0EAIQIgA0EANgIcIANBmhI2AhAgA0EHNgIMIAMgAUEBajYCFAx/CyADQYASOwEqQQAhAAJAIAMoAjgiAkUNACACKAI4IgJFDQAgAyACEQAAIQALIABFDQAgAEEVRw0BIANB2QA2AhwgAyABNgIUIANB6ho2AhAgA0EVNgIMQQAhAgx+C0HNACECDGQLIANBADYCHCADIAE2AhQgA0HJDTYCECADQRo2AgxBACECDHwLIAEgBEYEQEHZACECDHwLIAEtAABBIEcNPSABQQFqIQEgAy0ALkEBcQ09IANBADYCHCADIAE2AhQgA0HCHDYCECADQR42AgxBACECDHsLIAEgBEYEQEHYACECDHsLAkACQAJAAkACQCABLQAAIgBBCmsOBAIDAwABCyABQQFqIQFBLCECDGULIABBOkcNASADQQA2AhwgAyABNgIUIANB5xE2AhAgA0EKNgIMQQAhAgx9CyABQQFqIQEgA0Evai0AAEEBcUUNcyADLQAyQYABcUUEQCADQTJqIQIgAxA1QQAhAAJAIAMoAjgiBkUNACAGKAIoIgZFDQAgAyAGEQAAIQALAkACQCAADhZNTEsBAQEBAQEBAQEBAQEBAQEBAQEAAQsgA0EpNgIcIAMgATYCFCADQawZNgIQIANBFTYCDEEAIQIMfgsgA0EANgIcIAMgATYCFCADQeULNgIQIANBETYCDEEAIQIMfQtBACEAAkAgAygCOCICRQ0AIAIoAlwiAkUNACADIAIRAAAhAAsgAEUNWSAAQRVHDQEgA0EFNgIcIAMgATYCFCADQZsbNgIQIANBFTYCDEEAIQIMfAtBywAhAgxiC0EAIQIgA0EANgIcIAMgATYCFCADQZAONgIQIANBFDYCDAx6CyADIAMvATJBgAFyOwEyDDsLIAEgBEcEQCADQRE2AgggAyABNgIEQcoAIQIMYAtB1wAhAgx4CyABIARGBEBB1gAhAgx4CwJAAkACQAJAIAEtAAAiAEEgciAAIABBwQBrQf8BcUEaSRtB/wFxQeMAaw4TAEBAQEBAQEBAQEBAQAFAQEACA0ALIAFBAWohAUHGACECDGELIAFBAWohAUHHACECDGALIAFBAWohAUHIACECDF8LIAFBAWohAUHJACECDF4LQdUAIQIgBCABIgBGDXYgBCABayADKAIAIgFqIQYgACABa0EFaiEHA0AgAUGQyABqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0IQQQgAUEFRg0KGiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAx2C0HUACECIAQgASIARg11IAQgAWsgAygCACIBaiEGIAAgAWtBD2ohBwNAIAFBgMgAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNB0EDIAFBD0YNCRogAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMdQtB0wAhAiAEIAEiAEYNdCAEIAFrIAMoAgAiAWohBiAAIAFrQQ5qIQcDQCABQeLHAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQYgAUEORg0HIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADHQLQdIAIQIgBCABIgBGDXMgBCABayADKAIAIgFqIQUgACABa0EBaiEGA0AgAUHgxwBqLQAAIAAtAAAiB0EgciAHIAdBwQBrQf8BcUEaSRtB/wFxRw0FIAFBAUYNAiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBTYCAAxzCyABIARGBEBB0QAhAgxzCwJAAkAgAS0AACIAQSByIAAgAEHBAGtB/wFxQRpJG0H/AXFB7gBrDgcAOTk5OTkBOQsgAUEBaiEBQcMAIQIMWgsgAUEBaiEBQcQAIQIMWQsgA0EANgIAIAZBAWohAUHFACECDFgLQdAAIQIgBCABIgBGDXAgBCABayADKAIAIgFqIQYgACABa0EJaiEHA0AgAUHWxwBqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0CQQIgAUEJRg0EGiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAxwC0HPACECIAQgASIARg1vIAQgAWsgAygCACIBaiEGIAAgAWtBBWohBwNAIAFB0McAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNASABQQVGDQIgAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMbwsgACEBIANBADYCAAwzC0EBCzoALCADQQA2AgAgB0EBaiEBC0EtIQIMUgsCQANAIAEtAABB0MUAai0AAEEBRw0BIAQgAUEBaiIBRw0AC0HNACECDGsLQcIAIQIMUQsgASAERgRAQcwAIQIMagsgAS0AAEE6RgRAIAMoAgQhACADQQA2AgQgAyAAIAEQMCIARQ0zIANBywA2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMagsgA0EANgIcIAMgATYCFCADQecRNgIQIANBCjYCDEEAIQIMaQsCQAJAIAMtACxBAmsOAgABJwsgA0Ezai0AAEECcUUNJiADLQAuQQJxDSYgA0EANgIcIAMgATYCFCADQaYUNgIQIANBCzYCDEEAIQIMaQsgAy0AMkEgcUUNJSADLQAuQQJxDSUgA0EANgIcIAMgATYCFCADQb0TNgIQIANBDzYCDEEAIQIMaAtBACEAAkAgAygCOCICRQ0AIAIoAkgiAkUNACADIAIRAAAhAAsgAEUEQEHBACECDE8LIABBFUcEQCADQQA2AhwgAyABNgIUIANBpg82AhAgA0EcNgIMQQAhAgxoCyADQcoANgIcIAMgATYCFCADQYUcNgIQIANBFTYCDEEAIQIMZwsgASAERwRAA0AgAS0AAEHAwQBqLQAAQQFHDRcgBCABQQFqIgFHDQALQcQAIQIMZwtBxAAhAgxmCyABIARHBEADQAJAIAEtAAAiAEEgciAAIABBwQBrQf8BcUEaSRtB/wFxIgBBCUYNACAAQSBGDQACQAJAAkACQCAAQeMAaw4TAAMDAwMDAwMBAwMDAwMDAwMDAgMLIAFBAWohAUE2IQIMUgsgAUEBaiEBQTchAgxRCyABQQFqIQFBOCECDFALDBULIAQgAUEBaiIBRw0AC0E8IQIMZgtBPCECDGULIAEgBEYEQEHIACECDGULIANBEjYCCCADIAE2AgQCQAJAAkACQAJAIAMtACxBAWsOBBQAAQIJCyADLQAyQSBxDQNB4AEhAgxPCwJAIAMvATIiAEEIcUUNACADLQAoQQFHDQAgAy0ALkEIcUUNAgsgAyAAQff7A3FBgARyOwEyDAsLIAMgAy8BMkEQcjsBMgwECyADQQA2AgQgAyABIAEQMSIABEAgA0HBADYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgxmCyABQQFqIQEMWAsgA0EANgIcIAMgATYCFCADQfQTNgIQIANBBDYCDEEAIQIMZAtBxwAhAiABIARGDWMgAygCACIAIAQgAWtqIQUgASAAa0EGaiEGAkADQCAAQcDFAGotAAAgAS0AAEEgckcNASAAQQZGDUogAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMZAsgA0EANgIADAULAkAgASAERwRAA0AgAS0AAEHAwwBqLQAAIgBBAUcEQCAAQQJHDQMgAUEBaiEBDAULIAQgAUEBaiIBRw0AC0HFACECDGQLQcUAIQIMYwsLIANBADoALAwBC0ELIQIMRwtBPyECDEYLAkACQANAIAEtAAAiAEEgRwRAAkAgAEEKaw4EAwUFAwALIABBLEYNAwwECyAEIAFBAWoiAUcNAAtBxgAhAgxgCyADQQg6ACwMDgsgAy0AKEEBRw0CIAMtAC5BCHENAiADKAIEIQAgA0EANgIEIAMgACABEDEiAARAIANBwgA2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMXwsgAUEBaiEBDFALQTshAgxECwJAA0AgAS0AACIAQSBHIABBCUdxDQEgBCABQQFqIgFHDQALQcMAIQIMXQsLQTwhAgxCCwJAAkAgASAERwRAA0AgAS0AACIAQSBHBEAgAEEKaw4EAwQEAwQLIAQgAUEBaiIBRw0AC0E/IQIMXQtBPyECDFwLIAMgAy8BMkEgcjsBMgwKCyADKAIEIQAgA0EANgIEIAMgACABEDEiAEUNTiADQT42AhwgAyABNgIUIAMgADYCDEEAIQIMWgsCQCABIARHBEADQCABLQAAQcDDAGotAAAiAEEBRwRAIABBAkYNAwwMCyAEIAFBAWoiAUcNAAtBNyECDFsLQTchAgxaCyABQQFqIQEMBAtBOyECIAQgASIARg1YIAQgAWsgAygCACIBaiEGIAAgAWtBBWohBwJAA0AgAUGQyABqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0BIAFBBUYEQEEHIQEMPwsgAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMWQsgA0EANgIAIAAhAQwFC0E6IQIgBCABIgBGDVcgBCABayADKAIAIgFqIQYgACABa0EIaiEHAkADQCABQbTBAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQEgAUEIRgRAQQUhAQw+CyABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAxYCyADQQA2AgAgACEBDAQLQTkhAiAEIAEiAEYNViAEIAFrIAMoAgAiAWohBiAAIAFrQQNqIQcCQANAIAFBsMEAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNASABQQNGBEBBBiEBDD0LIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADFcLIANBADYCACAAIQEMAwsCQANAIAEtAAAiAEEgRwRAIABBCmsOBAcEBAcCCyAEIAFBAWoiAUcNAAtBOCECDFYLIABBLEcNASABQQFqIQBBASEBAkACQAJAAkACQCADLQAsQQVrDgQDAQIEAAsgACEBDAQLQQIhAQwBC0EEIQELIANBAToALCADIAMvATIgAXI7ATIgACEBDAELIAMgAy8BMkEIcjsBMiAAIQELQT4hAgw7CyADQQA6ACwLQTkhAgw5CyABIARGBEBBNiECDFILAkACQAJAAkACQCABLQAAQQprDgQAAgIBAgsgAygCBCEAIANBADYCBCADIAAgARAxIgBFDQIgA0EzNgIcIAMgATYCFCADIAA2AgxBACECDFULIAMoAgQhACADQQA2AgQgAyAAIAEQMSIARQRAIAFBAWohAQwGCyADQTI2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMVAsgAy0ALkEBcQRAQd8BIQIMOwsgAygCBCEAIANBADYCBCADIAAgARAxIgANAQxJC0E0IQIMOQsgA0E1NgIcIAMgATYCFCADIAA2AgxBACECDFELQTUhAgw3CyADQS9qLQAAQQFxDQAgA0EANgIcIAMgATYCFCADQesWNgIQIANBGTYCDEEAIQIMTwtBMyECDDULIAEgBEYEQEEyIQIMTgsCQCABLQAAQQpGBEAgAUEBaiEBDAELIANBADYCHCADIAE2AhQgA0GSFzYCECADQQM2AgxBACECDE4LQTIhAgw0CyABIARGBEBBMSECDE0LAkAgAS0AACIAQQlGDQAgAEEgRg0AQQEhAgJAIAMtACxBBWsOBAYEBQANCyADIAMvATJBCHI7ATIMDAsgAy0ALkEBcUUNASADLQAsQQhHDQAgA0EAOgAsC0E9IQIMMgsgA0EANgIcIAMgATYCFCADQcIWNgIQIANBCjYCDEEAIQIMSgtBAiECDAELQQQhAgsgA0EBOgAsIAMgAy8BMiACcjsBMgwGCyABIARGBEBBMCECDEcLIAEtAABBCkYEQCABQQFqIQEMAQsgAy0ALkEBcQ0AIANBADYCHCADIAE2AhQgA0HcKDYCECADQQI2AgxBACECDEYLQTAhAgwsCyABQQFqIQFBMSECDCsLIAEgBEYEQEEvIQIMRAsgAS0AACIAQQlHIABBIEdxRQRAIAFBAWohASADLQAuQQFxDQEgA0EANgIcIAMgATYCFCADQZcQNgIQIANBCjYCDEEAIQIMRAtBASECAkACQAJAAkACQAJAIAMtACxBAmsOBwUEBAMBAgAECyADIAMvATJBCHI7ATIMAwtBAiECDAELQQQhAgsgA0EBOgAsIAMgAy8BMiACcjsBMgtBLyECDCsLIANBADYCHCADIAE2AhQgA0GEEzYCECADQQs2AgxBACECDEMLQeEBIQIMKQsgASAERgRAQS4hAgxCCyADQQA2AgQgA0ESNgIIIAMgASABEDEiAA0BC0EuIQIMJwsgA0EtNgIcIAMgATYCFCADIAA2AgxBACECDD8LQQAhAAJAIAMoAjgiAkUNACACKAJMIgJFDQAgAyACEQAAIQALIABFDQAgAEEVRw0BIANB2AA2AhwgAyABNgIUIANBsxs2AhAgA0EVNgIMQQAhAgw+C0HMACECDCQLIANBADYCHCADIAE2AhQgA0GzDjYCECADQR02AgxBACECDDwLIAEgBEYEQEHOACECDDwLIAEtAAAiAEEgRg0CIABBOkYNAQsgA0EAOgAsQQkhAgwhCyADKAIEIQAgA0EANgIEIAMgACABEDAiAA0BDAILIAMtAC5BAXEEQEHeASECDCALIAMoAgQhACADQQA2AgQgAyAAIAEQMCIARQ0CIANBKjYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgw4CyADQcsANgIcIAMgADYCDCADIAFBAWo2AhRBACECDDcLIAFBAWohAUHAACECDB0LIAFBAWohAQwsCyABIARGBEBBKyECDDULAkAgAS0AAEEKRgRAIAFBAWohAQwBCyADLQAuQcAAcUUNBgsgAy0AMkGAAXEEQEEAIQACQCADKAI4IgJFDQAgAigCXCICRQ0AIAMgAhEAACEACyAARQ0SIABBFUYEQCADQQU2AhwgAyABNgIUIANBmxs2AhAgA0EVNgIMQQAhAgw2CyADQQA2AhwgAyABNgIUIANBkA42AhAgA0EUNgIMQQAhAgw1CyADQTJqIQIgAxA1QQAhAAJAIAMoAjgiBkUNACAGKAIoIgZFDQAgAyAGEQAAIQALIAAOFgIBAAQEBAQEBAQEBAQEBAQEBAQEBAMECyADQQE6ADALIAIgAi8BAEHAAHI7AQALQSshAgwYCyADQSk2AhwgAyABNgIUIANBrBk2AhAgA0EVNgIMQQAhAgwwCyADQQA2AhwgAyABNgIUIANB5Qs2AhAgA0ERNgIMQQAhAgwvCyADQQA2AhwgAyABNgIUIANBpQs2AhAgA0ECNgIMQQAhAgwuC0EBIQcgAy8BMiIFQQhxRQRAIAMpAyBCAFIhBwsCQCADLQAwBEBBASEAIAMtAClBBUYNASAFQcAAcUUgB3FFDQELAkAgAy0AKCICQQJGBEBBASEAIAMvATQiBkHlAEYNAkEAIQAgBUHAAHENAiAGQeQARg0CIAZB5gBrQQJJDQIgBkHMAUYNAiAGQbACRg0CDAELQQAhACAFQcAAcQ0BC0ECIQAgBUEIcQ0AIAVBgARxBEACQCACQQFHDQAgAy0ALkEKcQ0AQQUhAAwCC0EEIQAMAQsgBUEgcUUEQCADEDZBAEdBAnQhAAwBC0EAQQMgAykDIFAbIQALIABBAWsOBQIABwEDBAtBESECDBMLIANBAToAMQwpC0EAIQICQCADKAI4IgBFDQAgACgCMCIARQ0AIAMgABEAACECCyACRQ0mIAJBFUYEQCADQQM2AhwgAyABNgIUIANB0hs2AhAgA0EVNgIMQQAhAgwrC0EAIQIgA0EANgIcIAMgATYCFCADQd0ONgIQIANBEjYCDAwqCyADQQA2AhwgAyABNgIUIANB+SA2AhAgA0EPNgIMQQAhAgwpC0EAIQACQCADKAI4IgJFDQAgAigCMCICRQ0AIAMgAhEAACEACyAADQELQQ4hAgwOCyAAQRVGBEAgA0ECNgIcIAMgATYCFCADQdIbNgIQIANBFTYCDEEAIQIMJwsgA0EANgIcIAMgATYCFCADQd0ONgIQIANBEjYCDEEAIQIMJgtBKiECDAwLIAEgBEcEQCADQQk2AgggAyABNgIEQSkhAgwMC0EmIQIMJAsgAyADKQMgIgwgBCABa60iCn0iC0IAIAsgDFgbNwMgIAogDFQEQEElIQIMJAsgAygCBCEAIANBADYCBCADIAAgASAMp2oiARAyIgBFDQAgA0EFNgIcIAMgATYCFCADIAA2AgxBACECDCMLQQ8hAgwJC0IAIQoCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAS0AAEEwaw43FxYAAQIDBAUGBxQUFBQUFBQICQoLDA0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFA4PEBESExQLQgIhCgwWC0IDIQoMFQtCBCEKDBQLQgUhCgwTC0IGIQoMEgtCByEKDBELQgghCgwQC0IJIQoMDwtCCiEKDA4LQgshCgwNC0IMIQoMDAtCDSEKDAsLQg4hCgwKC0IPIQoMCQtCCiEKDAgLQgshCgwHC0IMIQoMBgtCDSEKDAULQg4hCgwEC0IPIQoMAwsgA0EANgIcIAMgATYCFCADQZ8VNgIQIANBDDYCDEEAIQIMIQsgASAERgRAQSIhAgwhC0IAIQoCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAEtAABBMGsONxUUAAECAwQFBgcWFhYWFhYWCAkKCwwNFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYODxAREhMWC0ICIQoMFAtCAyEKDBMLQgQhCgwSC0IFIQoMEQtCBiEKDBALQgchCgwPC0IIIQoMDgtCCSEKDA0LQgohCgwMC0ILIQoMCwtCDCEKDAoLQg0hCgwJC0IOIQoMCAtCDyEKDAcLQgohCgwGC0ILIQoMBQtCDCEKDAQLQg0hCgwDC0IOIQoMAgtCDyEKDAELQgEhCgsgAUEBaiEBIAMpAyAiC0L//////////w9YBEAgAyALQgSGIAqENwMgDAILIANBADYCHCADIAE2AhQgA0G1CTYCECADQQw2AgxBACECDB4LQSchAgwEC0EoIQIMAwsgAyABOgAsIANBADYCACAHQQFqIQFBDCECDAILIANBADYCACAGQQFqIQFBCiECDAELIAFBAWohAUEIIQIMAAsAC0EAIQIgA0EANgIcIAMgATYCFCADQbI4NgIQIANBCDYCDAwXC0EAIQIgA0EANgIcIAMgATYCFCADQYMRNgIQIANBCTYCDAwWC0EAIQIgA0EANgIcIAMgATYCFCADQd8KNgIQIANBCTYCDAwVC0EAIQIgA0EANgIcIAMgATYCFCADQe0QNgIQIANBCTYCDAwUC0EAIQIgA0EANgIcIAMgATYCFCADQdIRNgIQIANBCTYCDAwTC0EAIQIgA0EANgIcIAMgATYCFCADQbI4NgIQIANBCDYCDAwSC0EAIQIgA0EANgIcIAMgATYCFCADQYMRNgIQIANBCTYCDAwRC0EAIQIgA0EANgIcIAMgATYCFCADQd8KNgIQIANBCTYCDAwQC0EAIQIgA0EANgIcIAMgATYCFCADQe0QNgIQIANBCTYCDAwPC0EAIQIgA0EANgIcIAMgATYCFCADQdIRNgIQIANBCTYCDAwOC0EAIQIgA0EANgIcIAMgATYCFCADQbkXNgIQIANBDzYCDAwNC0EAIQIgA0EANgIcIAMgATYCFCADQbkXNgIQIANBDzYCDAwMC0EAIQIgA0EANgIcIAMgATYCFCADQZkTNgIQIANBCzYCDAwLC0EAIQIgA0EANgIcIAMgATYCFCADQZ0JNgIQIANBCzYCDAwKC0EAIQIgA0EANgIcIAMgATYCFCADQZcQNgIQIANBCjYCDAwJC0EAIQIgA0EANgIcIAMgATYCFCADQbEQNgIQIANBCjYCDAwIC0EAIQIgA0EANgIcIAMgATYCFCADQbsdNgIQIANBAjYCDAwHC0EAIQIgA0EANgIcIAMgATYCFCADQZYWNgIQIANBAjYCDAwGC0EAIQIgA0EANgIcIAMgATYCFCADQfkYNgIQIANBAjYCDAwFC0EAIQIgA0EANgIcIAMgATYCFCADQcQYNgIQIANBAjYCDAwECyADQQI2AhwgAyABNgIUIANBqR42AhAgA0EWNgIMQQAhAgwDC0HeACECIAEgBEYNAiAJQQhqIQcgAygCACEFAkACQCABIARHBEAgBUGWyABqIQggBCAFaiABayEGIAVBf3NBCmoiBSABaiEAA0AgAS0AACAILQAARwRAQQIhCAwDCyAFRQRAQQAhCCAAIQEMAwsgBUEBayEFIAhBAWohCCAEIAFBAWoiAUcNAAsgBiEFIAQhAQsgB0EBNgIAIAMgBTYCAAwBCyADQQA2AgAgByAINgIACyAHIAE2AgQgCSgCDCEAAkACQCAJKAIIQQFrDgIEAQALIANBADYCHCADQcIeNgIQIANBFzYCDCADIABBAWo2AhRBACECDAMLIANBADYCHCADIAA2AhQgA0HXHjYCECADQQk2AgxBACECDAILIAEgBEYEQEEoIQIMAgsgA0EJNgIIIAMgATYCBEEnIQIMAQsgASAERgRAQQEhAgwBCwNAAkACQAJAIAEtAABBCmsOBAABAQABCyABQQFqIQEMAQsgAUEBaiEBIAMtAC5BIHENAEEAIQIgA0EANgIcIAMgATYCFCADQaEhNgIQIANBBTYCDAwCC0EBIQIgASAERw0ACwsgCUEQaiQAIAJFBEAgAygCDCEADAELIAMgAjYCHEEAIQAgAygCBCIBRQ0AIAMgASAEIAMoAggRAQAiAUUNACADIAQ2AhQgAyABNgIMIAEhAAsgAAu+AgECfyAAQQA6AAAgAEHkAGoiAUEBa0EAOgAAIABBADoAAiAAQQA6AAEgAUEDa0EAOgAAIAFBAmtBADoAACAAQQA6AAMgAUEEa0EAOgAAQQAgAGtBA3EiASAAaiIAQQA2AgBB5AAgAWtBfHEiAiAAaiIBQQRrQQA2AgACQCACQQlJDQAgAEEANgIIIABBADYCBCABQQhrQQA2AgAgAUEMa0EANgIAIAJBGUkNACAAQQA2AhggAEEANgIUIABBADYCECAAQQA2AgwgAUEQa0EANgIAIAFBFGtBADYCACABQRhrQQA2AgAgAUEca0EANgIAIAIgAEEEcUEYciICayIBQSBJDQAgACACaiEAA0AgAEIANwMYIABCADcDECAAQgA3AwggAEIANwMAIABBIGohACABQSBrIgFBH0sNAAsLC1YBAX8CQCAAKAIMDQACQAJAAkACQCAALQAxDgMBAAMCCyAAKAI4IgFFDQAgASgCMCIBRQ0AIAAgAREAACIBDQMLQQAPCwALIABByhk2AhBBDiEBCyABCxoAIAAoAgxFBEAgAEHeHzYCECAAQRU2AgwLCxQAIAAoAgxBFUYEQCAAQQA2AgwLCxQAIAAoAgxBFkYEQCAAQQA2AgwLCwcAIAAoAgwLBwAgACgCEAsJACAAIAE2AhALBwAgACgCFAsrAAJAIABBJ08NAEL//////wkgAK2IQgGDUA0AIABBAnRB0DhqKAIADwsACxcAIABBL08EQAALIABBAnRB7DlqKAIAC78JAQF/QfQtIQECQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAQeQAaw70A2NiAAFhYWFhYWECAwQFYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQYHCAkKCwwNDg9hYWFhYRBhYWFhYWFhYWFhYRFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWESExQVFhcYGRobYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYRwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1NmE3ODk6YWFhYWFhYWE7YWFhPGFhYWE9Pj9hYWFhYWFhYUBhYUFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFCQ0RFRkdISUpLTE1OT1BRUlNhYWFhYWFhYVRVVldYWVpbYVxdYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhXmFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYV9gYQtB6iwPC0GYJg8LQe0xDwtBoDcPC0HJKQ8LQbQpDwtBli0PC0HrKw8LQaI1DwtB2zQPC0HgKQ8LQeMkDwtB1SQPC0HuJA8LQeYlDwtByjQPC0HQNw8LQao1DwtB9SwPC0H2Jg8LQYIiDwtB8jMPC0G+KA8LQec3DwtBzSEPC0HAIQ8LQbglDwtByyUPC0GWJA8LQY80DwtBzTUPC0HdKg8LQe4zDwtBnDQPC0GeMQ8LQfQ1DwtB5SIPC0GvJQ8LQZkxDwtBsjYPC0H5Ng8LQcQyDwtB3SwPC0GCMQ8LQcExDwtBjTcPC0HJJA8LQew2DwtB5yoPC0HIIw8LQeIhDwtByTcPC0GlIg8LQZQiDwtB2zYPC0HeNQ8LQYYmDwtBvCsPC0GLMg8LQaAjDwtB9jAPC0GALA8LQYkrDwtBpCYPC0HyIw8LQYEoDwtBqzIPC0HrJw8LQcI2DwtBoiQPC0HPKg8LQdwjDwtBhycPC0HkNA8LQbciDwtBrTEPC0HVIg8LQa80DwtB3iYPC0HWMg8LQfQ0DwtBgTgPC0H0Nw8LQZI2DwtBnScPC0GCKQ8LQY0jDwtB1zEPC0G9NQ8LQbQ3DwtB2DAPC0G2Jw8LQZo4DwtBpyoPC0HEJw8LQa4jDwtB9SIPCwALQcomIQELIAELFwAgACAALwEuQf7/A3EgAUEAR3I7AS4LGgAgACAALwEuQf3/A3EgAUEAR0EBdHI7AS4LGgAgACAALwEuQfv/A3EgAUEAR0ECdHI7AS4LGgAgACAALwEuQff/A3EgAUEAR0EDdHI7AS4LGgAgACAALwEuQe//A3EgAUEAR0EEdHI7AS4LGgAgACAALwEuQd//A3EgAUEAR0EFdHI7AS4LGgAgACAALwEuQb//A3EgAUEAR0EGdHI7AS4LGgAgACAALwEuQf/+A3EgAUEAR0EHdHI7AS4LGgAgACAALwEuQf/9A3EgAUEAR0EIdHI7AS4LGgAgACAALwEuQf/7A3EgAUEAR0EJdHI7AS4LPgECfwJAIAAoAjgiA0UNACADKAIEIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEHhEjYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIIIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEH8ETYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIMIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEHsCjYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIQIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEH6HjYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIUIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEHLEDYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIYIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEG3HzYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIcIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEG/FTYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIsIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEH+CDYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIgIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEGMHTYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIkIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEHmFTYCEEEYIQQLIAQLOAAgAAJ/IAAvATJBFHFBFEYEQEEBIAAtAChBAUYNARogAC8BNEHlAEYMAQsgAC0AKUEFRgs6ADALWQECfwJAIAAtAChBAUYNACAALwE0IgFB5ABrQeQASQ0AIAFBzAFGDQAgAUGwAkYNACAALwEyIgBBwABxDQBBASECIABBiARxQYAERg0AIABBKHFFIQILIAILjAEBAn8CQAJAAkAgAC0AKkUNACAALQArRQ0AIAAvATIiAUECcUUNAQwCCyAALwEyIgFBAXFFDQELQQEhAiAALQAoQQFGDQAgAC8BNCIAQeQAa0HkAEkNACAAQcwBRg0AIABBsAJGDQAgAUHAAHENAEEAIQIgAUGIBHFBgARGDQAgAUEocUEARyECCyACC1cAIABBGGpCADcDACAAQgA3AwAgAEE4akIANwMAIABBMGpCADcDACAAQShqQgA3AwAgAEEgakIANwMAIABBEGpCADcDACAAQQhqQgA3AwAgAEH9ATYCHAsGACAAEDoLmi0BC38jAEEQayIKJABB3NUAKAIAIglFBEBBnNkAKAIAIgVFBEBBqNkAQn83AgBBoNkAQoCAhICAgMAANwIAQZzZACAKQQhqQXBxQdiq1aoFcyIFNgIAQbDZAEEANgIAQYDZAEEANgIAC0GE2QBBwNkENgIAQdTVAEHA2QQ2AgBB6NUAIAU2AgBB5NUAQX82AgBBiNkAQcCmAzYCAANAIAFBgNYAaiABQfTVAGoiAjYCACACIAFB7NUAaiIDNgIAIAFB+NUAaiADNgIAIAFBiNYAaiABQfzVAGoiAzYCACADIAI2AgAgAUGQ1gBqIAFBhNYAaiICNgIAIAIgAzYCACABQYzWAGogAjYCACABQSBqIgFBgAJHDQALQczZBEGBpgM2AgBB4NUAQazZACgCADYCAEHQ1QBBgKYDNgIAQdzVAEHI2QQ2AgBBzP8HQTg2AgBByNkEIQkLAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAEHsAU0EQEHE1QAoAgAiBkEQIABBE2pBcHEgAEELSRsiBEEDdiIAdiIBQQNxBEACQCABQQFxIAByQQFzIgJBA3QiAEHs1QBqIgEgAEH01QBqKAIAIgAoAggiA0YEQEHE1QAgBkF+IAJ3cTYCAAwBCyABIAM2AgggAyABNgIMCyAAQQhqIQEgACACQQN0IgJBA3I2AgQgACACaiIAIAAoAgRBAXI2AgQMEQtBzNUAKAIAIgggBE8NASABBEACQEECIAB0IgJBACACa3IgASAAdHFoIgBBA3QiAkHs1QBqIgEgAkH01QBqKAIAIgIoAggiA0YEQEHE1QAgBkF+IAB3cSIGNgIADAELIAEgAzYCCCADIAE2AgwLIAIgBEEDcjYCBCAAQQN0IgAgBGshBSAAIAJqIAU2AgAgAiAEaiIEIAVBAXI2AgQgCARAIAhBeHFB7NUAaiEAQdjVACgCACEDAn9BASAIQQN2dCIBIAZxRQRAQcTVACABIAZyNgIAIAAMAQsgACgCCAsiASADNgIMIAAgAzYCCCADIAA2AgwgAyABNgIICyACQQhqIQFB2NUAIAQ2AgBBzNUAIAU2AgAMEQtByNUAKAIAIgtFDQEgC2hBAnRB9NcAaigCACIAKAIEQXhxIARrIQUgACECA0ACQCACKAIQIgFFBEAgAkEUaigCACIBRQ0BCyABKAIEQXhxIARrIgMgBUkhAiADIAUgAhshBSABIAAgAhshACABIQIMAQsLIAAoAhghCSAAKAIMIgMgAEcEQEHU1QAoAgAaIAMgACgCCCIBNgIIIAEgAzYCDAwQCyAAQRRqIgIoAgAiAUUEQCAAKAIQIgFFDQMgAEEQaiECCwNAIAIhByABIgNBFGoiAigCACIBDQAgA0EQaiECIAMoAhAiAQ0ACyAHQQA2AgAMDwtBfyEEIABBv39LDQAgAEETaiIBQXBxIQRByNUAKAIAIghFDQBBACAEayEFAkACQAJAAn9BACAEQYACSQ0AGkEfIARB////B0sNABogBEEmIAFBCHZnIgBrdkEBcSAAQQF0a0E+agsiBkECdEH01wBqKAIAIgJFBEBBACEBQQAhAwwBC0EAIQEgBEEZIAZBAXZrQQAgBkEfRxt0IQBBACEDA0ACQCACKAIEQXhxIARrIgcgBU8NACACIQMgByIFDQBBACEFIAIhAQwDCyABIAJBFGooAgAiByAHIAIgAEEddkEEcWpBEGooAgAiAkYbIAEgBxshASAAQQF0IQAgAg0ACwsgASADckUEQEEAIQNBAiAGdCIAQQAgAGtyIAhxIgBFDQMgAGhBAnRB9NcAaigCACEBCyABRQ0BCwNAIAEoAgRBeHEgBGsiAiAFSSEAIAIgBSAAGyEFIAEgAyAAGyEDIAEoAhAiAAR/IAAFIAFBFGooAgALIgENAAsLIANFDQAgBUHM1QAoAgAgBGtPDQAgAygCGCEHIAMgAygCDCIARwRAQdTVACgCABogACADKAIIIgE2AgggASAANgIMDA4LIANBFGoiAigCACIBRQRAIAMoAhAiAUUNAyADQRBqIQILA0AgAiEGIAEiAEEUaiICKAIAIgENACAAQRBqIQIgACgCECIBDQALIAZBADYCAAwNC0HM1QAoAgAiAyAETwRAQdjVACgCACEBAkAgAyAEayICQRBPBEAgASAEaiIAIAJBAXI2AgQgASADaiACNgIAIAEgBEEDcjYCBAwBCyABIANBA3I2AgQgASADaiIAIAAoAgRBAXI2AgRBACEAQQAhAgtBzNUAIAI2AgBB2NUAIAA2AgAgAUEIaiEBDA8LQdDVACgCACIDIARLBEAgBCAJaiIAIAMgBGsiAUEBcjYCBEHc1QAgADYCAEHQ1QAgATYCACAJIARBA3I2AgQgCUEIaiEBDA8LQQAhASAEAn9BnNkAKAIABEBBpNkAKAIADAELQajZAEJ/NwIAQaDZAEKAgISAgIDAADcCAEGc2QAgCkEMakFwcUHYqtWqBXM2AgBBsNkAQQA2AgBBgNkAQQA2AgBBgIAECyIAIARBxwBqIgVqIgZBACAAayIHcSICTwRAQbTZAEEwNgIADA8LAkBB/NgAKAIAIgFFDQBB9NgAKAIAIgggAmohACAAIAFNIAAgCEtxDQBBACEBQbTZAEEwNgIADA8LQYDZAC0AAEEEcQ0EAkACQCAJBEBBhNkAIQEDQCABKAIAIgAgCU0EQCAAIAEoAgRqIAlLDQMLIAEoAggiAQ0ACwtBABA7IgBBf0YNBSACIQZBoNkAKAIAIgFBAWsiAyAAcQRAIAIgAGsgACADakEAIAFrcWohBgsgBCAGTw0FIAZB/v///wdLDQVB/NgAKAIAIgMEQEH02AAoAgAiByAGaiEBIAEgB00NBiABIANLDQYLIAYQOyIBIABHDQEMBwsgBiADayAHcSIGQf7///8HSw0EIAYQOyEAIAAgASgCACABKAIEakYNAyAAIQELAkAgBiAEQcgAak8NACABQX9GDQBBpNkAKAIAIgAgBSAGa2pBACAAa3EiAEH+////B0sEQCABIQAMBwsgABA7QX9HBEAgACAGaiEGIAEhAAwHC0EAIAZrEDsaDAQLIAEiAEF/Rw0FDAMLQQAhAwwMC0EAIQAMCgsgAEF/Rw0CC0GA2QBBgNkAKAIAQQRyNgIACyACQf7///8HSw0BIAIQOyEAQQAQOyEBIABBf0YNASABQX9GDQEgACABTw0BIAEgAGsiBiAEQThqTQ0BC0H02ABB9NgAKAIAIAZqIgE2AgBB+NgAKAIAIAFJBEBB+NgAIAE2AgALAkACQAJAQdzVACgCACICBEBBhNkAIQEDQCAAIAEoAgAiAyABKAIEIgVqRg0CIAEoAggiAQ0ACwwCC0HU1QAoAgAiAUEARyAAIAFPcUUEQEHU1QAgADYCAAtBACEBQYjZACAGNgIAQYTZACAANgIAQeTVAEF/NgIAQejVAEGc2QAoAgA2AgBBkNkAQQA2AgADQCABQYDWAGogAUH01QBqIgI2AgAgAiABQezVAGoiAzYCACABQfjVAGogAzYCACABQYjWAGogAUH81QBqIgM2AgAgAyACNgIAIAFBkNYAaiABQYTWAGoiAjYCACACIAM2AgAgAUGM1gBqIAI2AgAgAUEgaiIBQYACRw0AC0F4IABrQQ9xIgEgAGoiAiAGQThrIgMgAWsiAUEBcjYCBEHg1QBBrNkAKAIANgIAQdDVACABNgIAQdzVACACNgIAIAAgA2pBODYCBAwCCyAAIAJNDQAgAiADSQ0AIAEoAgxBCHENAEF4IAJrQQ9xIgAgAmoiA0HQ1QAoAgAgBmoiByAAayIAQQFyNgIEIAEgBSAGajYCBEHg1QBBrNkAKAIANgIAQdDVACAANgIAQdzVACADNgIAIAIgB2pBODYCBAwBCyAAQdTVACgCAEkEQEHU1QAgADYCAAsgACAGaiEDQYTZACEBAkACQAJAA0AgAyABKAIARwRAIAEoAggiAQ0BDAILCyABLQAMQQhxRQ0BC0GE2QAhAQNAIAEoAgAiAyACTQRAIAMgASgCBGoiBSACSw0DCyABKAIIIQEMAAsACyABIAA2AgAgASABKAIEIAZqNgIEIABBeCAAa0EPcWoiCSAEQQNyNgIEIANBeCADa0EPcWoiBiAEIAlqIgRrIQEgAiAGRgRAQdzVACAENgIAQdDVAEHQ1QAoAgAgAWoiADYCACAEIABBAXI2AgQMCAtB2NUAKAIAIAZGBEBB2NUAIAQ2AgBBzNUAQczVACgCACABaiIANgIAIAQgAEEBcjYCBCAAIARqIAA2AgAMCAsgBigCBCIFQQNxQQFHDQYgBUF4cSEIIAVB/wFNBEAgBUEDdiEDIAYoAggiACAGKAIMIgJGBEBBxNUAQcTVACgCAEF+IAN3cTYCAAwHCyACIAA2AgggACACNgIMDAYLIAYoAhghByAGIAYoAgwiAEcEQCAAIAYoAggiAjYCCCACIAA2AgwMBQsgBkEUaiICKAIAIgVFBEAgBigCECIFRQ0EIAZBEGohAgsDQCACIQMgBSIAQRRqIgIoAgAiBQ0AIABBEGohAiAAKAIQIgUNAAsgA0EANgIADAQLQXggAGtBD3EiASAAaiIHIAZBOGsiAyABayIBQQFyNgIEIAAgA2pBODYCBCACIAVBNyAFa0EPcWpBP2siAyADIAJBEGpJGyIDQSM2AgRB4NUAQazZACgCADYCAEHQ1QAgATYCAEHc1QAgBzYCACADQRBqQYzZACkCADcCACADQYTZACkCADcCCEGM2QAgA0EIajYCAEGI2QAgBjYCAEGE2QAgADYCAEGQ2QBBADYCACADQSRqIQEDQCABQQc2AgAgBSABQQRqIgFLDQALIAIgA0YNACADIAMoAgRBfnE2AgQgAyADIAJrIgU2AgAgAiAFQQFyNgIEIAVB/wFNBEAgBUF4cUHs1QBqIQACf0HE1QAoAgAiAUEBIAVBA3Z0IgNxRQRAQcTVACABIANyNgIAIAAMAQsgACgCCAsiASACNgIMIAAgAjYCCCACIAA2AgwgAiABNgIIDAELQR8hASAFQf///wdNBEAgBUEmIAVBCHZnIgBrdkEBcSAAQQF0a0E+aiEBCyACIAE2AhwgAkIANwIQIAFBAnRB9NcAaiEAQcjVACgCACIDQQEgAXQiBnFFBEAgACACNgIAQcjVACADIAZyNgIAIAIgADYCGCACIAI2AgggAiACNgIMDAELIAVBGSABQQF2a0EAIAFBH0cbdCEBIAAoAgAhAwJAA0AgAyIAKAIEQXhxIAVGDQEgAUEddiEDIAFBAXQhASAAIANBBHFqQRBqIgYoAgAiAw0ACyAGIAI2AgAgAiAANgIYIAIgAjYCDCACIAI2AggMAQsgACgCCCIBIAI2AgwgACACNgIIIAJBADYCGCACIAA2AgwgAiABNgIIC0HQ1QAoAgAiASAETQ0AQdzVACgCACIAIARqIgIgASAEayIBQQFyNgIEQdDVACABNgIAQdzVACACNgIAIAAgBEEDcjYCBCAAQQhqIQEMCAtBACEBQbTZAEEwNgIADAcLQQAhAAsgB0UNAAJAIAYoAhwiAkECdEH01wBqIgMoAgAgBkYEQCADIAA2AgAgAA0BQcjVAEHI1QAoAgBBfiACd3E2AgAMAgsgB0EQQRQgBygCECAGRhtqIAA2AgAgAEUNAQsgACAHNgIYIAYoAhAiAgRAIAAgAjYCECACIAA2AhgLIAZBFGooAgAiAkUNACAAQRRqIAI2AgAgAiAANgIYCyABIAhqIQEgBiAIaiIGKAIEIQULIAYgBUF+cTYCBCABIARqIAE2AgAgBCABQQFyNgIEIAFB/wFNBEAgAUF4cUHs1QBqIQACf0HE1QAoAgAiAkEBIAFBA3Z0IgFxRQRAQcTVACABIAJyNgIAIAAMAQsgACgCCAsiASAENgIMIAAgBDYCCCAEIAA2AgwgBCABNgIIDAELQR8hBSABQf///wdNBEAgAUEmIAFBCHZnIgBrdkEBcSAAQQF0a0E+aiEFCyAEIAU2AhwgBEIANwIQIAVBAnRB9NcAaiEAQcjVACgCACICQQEgBXQiA3FFBEAgACAENgIAQcjVACACIANyNgIAIAQgADYCGCAEIAQ2AgggBCAENgIMDAELIAFBGSAFQQF2a0EAIAVBH0cbdCEFIAAoAgAhAAJAA0AgACICKAIEQXhxIAFGDQEgBUEddiEAIAVBAXQhBSACIABBBHFqQRBqIgMoAgAiAA0ACyADIAQ2AgAgBCACNgIYIAQgBDYCDCAEIAQ2AggMAQsgAigCCCIAIAQ2AgwgAiAENgIIIARBADYCGCAEIAI2AgwgBCAANgIICyAJQQhqIQEMAgsCQCAHRQ0AAkAgAygCHCIBQQJ0QfTXAGoiAigCACADRgRAIAIgADYCACAADQFByNUAIAhBfiABd3EiCDYCAAwCCyAHQRBBFCAHKAIQIANGG2ogADYCACAARQ0BCyAAIAc2AhggAygCECIBBEAgACABNgIQIAEgADYCGAsgA0EUaigCACIBRQ0AIABBFGogATYCACABIAA2AhgLAkAgBUEPTQRAIAMgBCAFaiIAQQNyNgIEIAAgA2oiACAAKAIEQQFyNgIEDAELIAMgBGoiAiAFQQFyNgIEIAMgBEEDcjYCBCACIAVqIAU2AgAgBUH/AU0EQCAFQXhxQezVAGohAAJ/QcTVACgCACIBQQEgBUEDdnQiBXFFBEBBxNUAIAEgBXI2AgAgAAwBCyAAKAIICyIBIAI2AgwgACACNgIIIAIgADYCDCACIAE2AggMAQtBHyEBIAVB////B00EQCAFQSYgBUEIdmciAGt2QQFxIABBAXRrQT5qIQELIAIgATYCHCACQgA3AhAgAUECdEH01wBqIQBBASABdCIEIAhxRQRAIAAgAjYCAEHI1QAgBCAIcjYCACACIAA2AhggAiACNgIIIAIgAjYCDAwBCyAFQRkgAUEBdmtBACABQR9HG3QhASAAKAIAIQQCQANAIAQiACgCBEF4cSAFRg0BIAFBHXYhBCABQQF0IQEgACAEQQRxakEQaiIGKAIAIgQNAAsgBiACNgIAIAIgADYCGCACIAI2AgwgAiACNgIIDAELIAAoAggiASACNgIMIAAgAjYCCCACQQA2AhggAiAANgIMIAIgATYCCAsgA0EIaiEBDAELAkAgCUUNAAJAIAAoAhwiAUECdEH01wBqIgIoAgAgAEYEQCACIAM2AgAgAw0BQcjVACALQX4gAXdxNgIADAILIAlBEEEUIAkoAhAgAEYbaiADNgIAIANFDQELIAMgCTYCGCAAKAIQIgEEQCADIAE2AhAgASADNgIYCyAAQRRqKAIAIgFFDQAgA0EUaiABNgIAIAEgAzYCGAsCQCAFQQ9NBEAgACAEIAVqIgFBA3I2AgQgACABaiIBIAEoAgRBAXI2AgQMAQsgACAEaiIHIAVBAXI2AgQgACAEQQNyNgIEIAUgB2ogBTYCACAIBEAgCEF4cUHs1QBqIQFB2NUAKAIAIQMCf0EBIAhBA3Z0IgIgBnFFBEBBxNUAIAIgBnI2AgAgAQwBCyABKAIICyICIAM2AgwgASADNgIIIAMgATYCDCADIAI2AggLQdjVACAHNgIAQczVACAFNgIACyAAQQhqIQELIApBEGokACABC0MAIABFBEA/AEEQdA8LAkAgAEH//wNxDQAgAEEASA0AIABBEHZAACIAQX9GBEBBtNkAQTA2AgBBfw8LIABBEHQPCwALC5lCIgBBgAgLDQEAAAAAAAAAAgAAAAMAQZgICwUEAAAABQBBqAgLCQYAAAAHAAAACABB5AgLwjJJbnZhbGlkIGNoYXIgaW4gdXJsIHF1ZXJ5AFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fYm9keQBDb250ZW50LUxlbmd0aCBvdmVyZmxvdwBDaHVuayBzaXplIG92ZXJmbG93AEludmFsaWQgbWV0aG9kIGZvciBIVFRQL3gueCByZXF1ZXN0AEludmFsaWQgbWV0aG9kIGZvciBSVFNQL3gueCByZXF1ZXN0AEV4cGVjdGVkIFNPVVJDRSBtZXRob2QgZm9yIElDRS94LnggcmVxdWVzdABJbnZhbGlkIGNoYXIgaW4gdXJsIGZyYWdtZW50IHN0YXJ0AEV4cGVjdGVkIGRvdABTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3N0YXR1cwBJbnZhbGlkIHJlc3BvbnNlIHN0YXR1cwBFeHBlY3RlZCBMRiBhZnRlciBoZWFkZXJzAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMAVXNlciBjYWxsYmFjayBlcnJvcgBgb25fcmVzZXRgIGNhbGxiYWNrIGVycm9yAGBvbl9jaHVua19oZWFkZXJgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2JlZ2luYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlYCBjYWxsYmFjayBlcnJvcgBgb25fc3RhdHVzX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdmVyc2lvbl9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3VybF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3Byb3RvY29sX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWV0aG9kX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX25hbWVgIGNhbGxiYWNrIGVycm9yAFVuZXhwZWN0ZWQgY2hhciBpbiB1cmwgc2VydmVyAEludmFsaWQgaGVhZGVyIHZhbHVlIGNoYXIASW52YWxpZCBoZWFkZXIgZmllbGQgY2hhcgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3ZlcnNpb24ASW52YWxpZCBtaW5vciB2ZXJzaW9uAEludmFsaWQgbWFqb3IgdmVyc2lvbgBFeHBlY3RlZCBzcGFjZSBhZnRlciB2ZXJzaW9uAEV4cGVjdGVkIENSTEYgYWZ0ZXIgdmVyc2lvbgBJbnZhbGlkIEhUVFAgdmVyc2lvbgBJbnZhbGlkIGhlYWRlciB0b2tlbgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3VybABJbnZhbGlkIGNoYXJhY3RlcnMgaW4gdXJsAFVuZXhwZWN0ZWQgc3RhcnQgY2hhciBpbiB1cmwARG91YmxlIEAgaW4gdXJsAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fcHJvdG9jb2wARW1wdHkgQ29udGVudC1MZW5ndGgASW52YWxpZCBjaGFyYWN0ZXIgaW4gQ29udGVudC1MZW5ndGgAVHJhbnNmZXItRW5jb2RpbmcgY2FuJ3QgYmUgcHJlc2VudCB3aXRoIENvbnRlbnQtTGVuZ3RoAER1cGxpY2F0ZSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXIgaW4gdXJsIHBhdGgAQ29udGVudC1MZW5ndGggY2FuJ3QgYmUgcHJlc2VudCB3aXRoIFRyYW5zZmVyLUVuY29kaW5nAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgY2h1bmsgc2l6ZQBFeHBlY3RlZCBMRiBhZnRlciBjaHVuayBzaXplAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIHNpemUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfdmFsdWUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyB2YWx1ZQBVbmV4cGVjdGVkIHdoaXRlc3BhY2UgYWZ0ZXIgaGVhZGVyIHZhbHVlAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgaGVhZGVyIHZhbHVlAE1pc3NpbmcgZXhwZWN0ZWQgTEYgYWZ0ZXIgaGVhZGVyIHZhbHVlAEludmFsaWQgYFRyYW5zZmVyLUVuY29kaW5nYCBoZWFkZXIgdmFsdWUATWlzc2luZyBleHBlY3RlZCBDUiBhZnRlciBjaHVuayBleHRlbnNpb24gdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBxdW90ZSB2YWx1ZQBJbnZhbGlkIHF1b3RlZC1wYWlyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAFBhdXNlZCBieSBvbl9oZWFkZXJzX2NvbXBsZXRlAEludmFsaWQgRU9GIHN0YXRlAG9uX3Jlc2V0IHBhdXNlAG9uX2NodW5rX2hlYWRlciBwYXVzZQBvbl9tZXNzYWdlX2JlZ2luIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl92YWx1ZSBwYXVzZQBvbl9zdGF0dXNfY29tcGxldGUgcGF1c2UAb25fdmVyc2lvbl9jb21wbGV0ZSBwYXVzZQBvbl91cmxfY29tcGxldGUgcGF1c2UAb25fcHJvdG9jb2xfY29tcGxldGUgcGF1c2UAb25fY2h1bmtfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX3ZhbHVlX2NvbXBsZXRlIHBhdXNlAG9uX21lc3NhZ2VfY29tcGxldGUgcGF1c2UAb25fbWV0aG9kX2NvbXBsZXRlIHBhdXNlAG9uX2hlYWRlcl9maWVsZF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19leHRlbnNpb25fbmFtZSBwYXVzZQBVbmV4cGVjdGVkIHNwYWNlIGFmdGVyIHN0YXJ0IGxpbmUATWlzc2luZyBleHBlY3RlZCBDUiBhZnRlciByZXNwb25zZSBsaW5lAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fY2h1bmtfZXh0ZW5zaW9uX25hbWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBuYW1lAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgY2h1bmsgZXh0ZW5zaW9uIG5hbWUASW52YWxpZCBzdGF0dXMgY29kZQBQYXVzZSBvbiBDT05ORUNUL1VwZ3JhZGUAUGF1c2Ugb24gUFJJL1VwZ3JhZGUARXhwZWN0ZWQgSFRUUC8yIENvbm5lY3Rpb24gUHJlZmFjZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX21ldGhvZABFeHBlY3RlZCBzcGFjZSBhZnRlciBtZXRob2QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfZmllbGQAUGF1c2VkAEludmFsaWQgd29yZCBlbmNvdW50ZXJlZABJbnZhbGlkIG1ldGhvZCBlbmNvdW50ZXJlZABNaXNzaW5nIGV4cGVjdGVkIENSIGFmdGVyIGNodW5rIGRhdGEARXhwZWN0ZWQgTEYgYWZ0ZXIgY2h1bmsgZGF0YQBVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNjaGVtYQBSZXF1ZXN0IGhhcyBpbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AARGF0YSBhZnRlciBgQ29ubmVjdGlvbjogY2xvc2VgAFNXSVRDSF9QUk9YWQBVU0VfUFJPWFkATUtBQ1RJVklUWQBVTlBST0NFU1NBQkxFX0VOVElUWQBRVUVSWQBDT1BZAE1PVkVEX1BFUk1BTkVOVExZAFRPT19FQVJMWQBOT1RJRlkARkFJTEVEX0RFUEVOREVOQ1kAQkFEX0dBVEVXQVkAUExBWQBQVVQAQ0hFQ0tPVVQAR0FURVdBWV9USU1FT1VUAFJFUVVFU1RfVElNRU9VVABORVRXT1JLX0NPTk5FQ1RfVElNRU9VVABDT05ORUNUSU9OX1RJTUVPVVQATE9HSU5fVElNRU9VVABORVRXT1JLX1JFQURfVElNRU9VVABQT1NUAE1JU0RJUkVDVEVEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9SRVFVRVNUAENMSUVOVF9DTE9TRURfTE9BRF9CQUxBTkNFRF9SRVFVRVNUAEJBRF9SRVFVRVNUAEhUVFBfUkVRVUVTVF9TRU5UX1RPX0hUVFBTX1BPUlQAUkVQT1JUAElNX0FfVEVBUE9UAFJFU0VUX0NPTlRFTlQATk9fQ09OVEVOVABQQVJUSUFMX0NPTlRFTlQASFBFX0lOVkFMSURfQ09OU1RBTlQASFBFX0NCX1JFU0VUAEdFVABIUEVfU1RSSUNUAENPTkZMSUNUAFRFTVBPUkFSWV9SRURJUkVDVABQRVJNQU5FTlRfUkVESVJFQ1QAQ09OTkVDVABNVUxUSV9TVEFUVVMASFBFX0lOVkFMSURfU1RBVFVTAFRPT19NQU5ZX1JFUVVFU1RTAEVBUkxZX0hJTlRTAFVOQVZBSUxBQkxFX0ZPUl9MRUdBTF9SRUFTT05TAE9QVElPTlMAU1dJVENISU5HX1BST1RPQ09MUwBWQVJJQU5UX0FMU09fTkVHT1RJQVRFUwBNVUxUSVBMRV9DSE9JQ0VTAElOVEVSTkFMX1NFUlZFUl9FUlJPUgBXRUJfU0VSVkVSX1VOS05PV05fRVJST1IAUkFJTEdVTl9FUlJPUgBJREVOVElUWV9QUk9WSURFUl9BVVRIRU5USUNBVElPTl9FUlJPUgBTU0xfQ0VSVElGSUNBVEVfRVJST1IASU5WQUxJRF9YX0ZPUldBUkRFRF9GT1IAU0VUX1BBUkFNRVRFUgBHRVRfUEFSQU1FVEVSAEhQRV9VU0VSAFNFRV9PVEhFUgBIUEVfQ0JfQ0hVTktfSEVBREVSAEV4cGVjdGVkIExGIGFmdGVyIENSAE1LQ0FMRU5EQVIAU0VUVVAAV0VCX1NFUlZFUl9JU19ET1dOAFRFQVJET1dOAEhQRV9DTE9TRURfQ09OTkVDVElPTgBIRVVSSVNUSUNfRVhQSVJBVElPTgBESVNDT05ORUNURURfT1BFUkFUSU9OAE5PTl9BVVRIT1JJVEFUSVZFX0lORk9STUFUSU9OAEhQRV9JTlZBTElEX1ZFUlNJT04ASFBFX0NCX01FU1NBR0VfQkVHSU4AU0lURV9JU19GUk9aRU4ASFBFX0lOVkFMSURfSEVBREVSX1RPS0VOAElOVkFMSURfVE9LRU4ARk9SQklEREVOAEVOSEFOQ0VfWU9VUl9DQUxNAEhQRV9JTlZBTElEX1VSTABCTE9DS0VEX0JZX1BBUkVOVEFMX0NPTlRST0wATUtDT0wAQUNMAEhQRV9JTlRFUk5BTABSRVFVRVNUX0hFQURFUl9GSUVMRFNfVE9PX0xBUkdFX1VOT0ZGSUNJQUwASFBFX09LAFVOTElOSwBVTkxPQ0sAUFJJAFJFVFJZX1dJVEgASFBFX0lOVkFMSURfQ09OVEVOVF9MRU5HVEgASFBFX1VORVhQRUNURURfQ09OVEVOVF9MRU5HVEgARkxVU0gAUFJPUFBBVENIAE0tU0VBUkNIAFVSSV9UT09fTE9ORwBQUk9DRVNTSU5HAE1JU0NFTExBTkVPVVNfUEVSU0lTVEVOVF9XQVJOSU5HAE1JU0NFTExBTkVPVVNfV0FSTklORwBIUEVfSU5WQUxJRF9UUkFOU0ZFUl9FTkNPRElORwBFeHBlY3RlZCBDUkxGAEhQRV9JTlZBTElEX0NIVU5LX1NJWkUATU9WRQBDT05USU5VRQBIUEVfQ0JfU1RBVFVTX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJTX0NPTVBMRVRFAEhQRV9DQl9WRVJTSU9OX0NPTVBMRVRFAEhQRV9DQl9VUkxfQ09NUExFVEUASFBFX0NCX1BST1RPQ09MX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19DT01QTEVURQBIUEVfQ0JfSEVBREVSX1ZBTFVFX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19FWFRFTlNJT05fVkFMVUVfQ09NUExFVEUASFBFX0NCX0NIVU5LX0VYVEVOU0lPTl9OQU1FX0NPTVBMRVRFAEhQRV9DQl9NRVNTQUdFX0NPTVBMRVRFAEhQRV9DQl9NRVRIT0RfQ09NUExFVEUASFBFX0NCX0hFQURFUl9GSUVMRF9DT01QTEVURQBERUxFVEUASFBFX0lOVkFMSURfRU9GX1NUQVRFAElOVkFMSURfU1NMX0NFUlRJRklDQVRFAFBBVVNFAE5PX1JFU1BPTlNFAFVOU1VQUE9SVEVEX01FRElBX1RZUEUAR09ORQBOT1RfQUNDRVBUQUJMRQBTRVJWSUNFX1VOQVZBSUxBQkxFAFJBTkdFX05PVF9TQVRJU0ZJQUJMRQBPUklHSU5fSVNfVU5SRUFDSEFCTEUAUkVTUE9OU0VfSVNfU1RBTEUAUFVSR0UATUVSR0UAUkVRVUVTVF9IRUFERVJfRklFTERTX1RPT19MQVJHRQBSRVFVRVNUX0hFQURFUl9UT09fTEFSR0UAUEFZTE9BRF9UT09fTEFSR0UASU5TVUZGSUNJRU5UX1NUT1JBR0UASFBFX1BBVVNFRF9VUEdSQURFAEhQRV9QQVVTRURfSDJfVVBHUkFERQBTT1VSQ0UAQU5OT1VOQ0UAVFJBQ0UASFBFX1VORVhQRUNURURfU1BBQ0UAREVTQ1JJQkUAVU5TVUJTQ1JJQkUAUkVDT1JEAEhQRV9JTlZBTElEX01FVEhPRABOT1RfRk9VTkQAUFJPUEZJTkQAVU5CSU5EAFJFQklORABVTkFVVEhPUklaRUQATUVUSE9EX05PVF9BTExPV0VEAEhUVFBfVkVSU0lPTl9OT1RfU1VQUE9SVEVEAEFMUkVBRFlfUkVQT1JURUQAQUNDRVBURUQATk9UX0lNUExFTUVOVEVEAExPT1BfREVURUNURUQASFBFX0NSX0VYUEVDVEVEAEhQRV9MRl9FWFBFQ1RFRABDUkVBVEVEAElNX1VTRUQASFBFX1BBVVNFRABUSU1FT1VUX09DQ1VSRUQAUEFZTUVOVF9SRVFVSVJFRABQUkVDT05ESVRJT05fUkVRVUlSRUQAUFJPWFlfQVVUSEVOVElDQVRJT05fUkVRVUlSRUQATkVUV09SS19BVVRIRU5USUNBVElPTl9SRVFVSVJFRABMRU5HVEhfUkVRVUlSRUQAU1NMX0NFUlRJRklDQVRFX1JFUVVJUkVEAFVQR1JBREVfUkVRVUlSRUQAUEFHRV9FWFBJUkVEAFBSRUNPTkRJVElPTl9GQUlMRUQARVhQRUNUQVRJT05fRkFJTEVEAFJFVkFMSURBVElPTl9GQUlMRUQAU1NMX0hBTkRTSEFLRV9GQUlMRUQATE9DS0VEAFRSQU5TRk9STUFUSU9OX0FQUExJRUQATk9UX01PRElGSUVEAE5PVF9FWFRFTkRFRABCQU5EV0lEVEhfTElNSVRfRVhDRUVERUQAU0lURV9JU19PVkVSTE9BREVEAEhFQUQARXhwZWN0ZWQgSFRUUC8sIFJUU1AvIG9yIElDRS8A5xUAAK8VAACkEgAAkhoAACYWAACeFAAA2xkAAHkVAAB+EgAA/hQAADYVAAALFgAA2BYAAPMSAABCGAAArBYAABIVAAAUFwAA7xcAAEgUAABxFwAAshoAAGsZAAB+GQAANRQAAIIaAABEFwAA/RYAAB4YAACHFwAAqhkAAJMSAAAHGAAALBcAAMoXAACkFwAA5xUAAOcVAABYFwAAOxgAAKASAAAtHAAAwxEAAEgRAADeEgAAQhMAAKQZAAD9EAAA9xUAAKUVAADvFgAA+BkAAEoWAABWFgAA9RUAAAoaAAAIGgAAARoAAKsVAABCEgAA1xAAAEwRAAAFGQAAVBYAAB4RAADKGQAAyBkAAE4WAAD/GAAAcRQAAPAVAADuFQAAlBkAAPwVAAC/GQAAmxkAAHwUAABDEQAAcBgAAJUUAAAnFAAAGRQAANUSAADUGQAARBYAAPcQAEG5OwsBAQBB0DsL4AEBAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBuj0LBAEAAAIAQdE9C14DBAMDAwMDAAADAwADAwADAwMDAwMDAwMDAAUAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAwADAEG6PwsEAQAAAgBB0T8LXgMAAwMDAwMAAAMDAAMDAAMDAwMDAwMDAwMABAAFAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwADAAMAQbDBAAsNbG9zZWVlcC1hbGl2ZQBBycEACwEBAEHgwQAL4AEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBycMACwEBAEHgwwAL5wEBAQEBAQEBAQEBAQECAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAWNodW5rZWQAQfHFAAteAQABAQEBAQAAAQEAAQEAAQEBAQEBAQEBAQAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQBB0McACyFlY3Rpb25lbnQtbGVuZ3Rob25yb3h5LWNvbm5lY3Rpb24AQYDIAAsgcmFuc2Zlci1lbmNvZGluZ3BncmFkZQ0KDQpTTQ0KDQoAQanIAAsFAQIAAQMAQcDIAAtfBAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAQanKAAsFAQIAAQMAQcDKAAtfBAUFBgUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAQanMAAsEAQAAAQBBwcwAC14CAgACAgICAgICAgICAgICAgICAgICAgICAgICAgIAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAEGpzgALBQECAAEDAEHAzgALXwQFAAAFBQUFBQUFBQUFBQYFBQUFBQUFBQUFBQUABQAHCAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQAFAAUABQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAAAAFAEGp0AALBQEBAAEBAEHA0AALAQEAQdrQAAtBAgAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQanSAAsFAQEAAQEAQcDSAAsBAQBBytIACwYCAAAAAAIAQeHSAAs6AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBBoNQAC50BTk9VTkNFRUNLT1VUTkVDVEVURUNSSUJFTFVTSEVURUFEU0VBUkNIUkdFQ1RJVklUWUxFTkRBUlZFT1RJRllQVElPTlNDSFNFQVlTVEFUQ0hHRVVFUllPUkRJUkVDVE9SVFJDSFBBUkFNRVRFUlVSQ0VCU0NSSUJFQVJET1dOQUNFSU5ETktDS1VCU0NSSUJFVFRQQ0VUU1BBRFRQLw==",aw;Object.defineProperty(r3,"exports",{get:()=>aw||(aw=Cfe.from(Qfe,"base64"))})});var i3=U((mTe,n3)=>{"use strict";var{Buffer:wfe}=Gr(),Sfe="AGFzbQEAAAABJwdgAX8Bf2ADf39/AX9gAn9/AGABfwBgBH9/f38Bf2AAAGADf39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQAEA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAAzU0BQYAAAMAAAAAAAADAQMAAwMDAAACAAAAAAICAgICAgICAgIBAQEBAQEBAQEBAwAAAwAAAAQFAXABExMFAwEAAgYIAX8BQcDZBAsHxQcoBm1lbW9yeQIAC19pbml0aWFsaXplAAgZX19pbmRpcmVjdF9mdW5jdGlvbl90YWJsZQEAC2xsaHR0cF9pbml0AAkYbGxodHRwX3Nob3VsZF9rZWVwX2FsaXZlADcMbGxodHRwX2FsbG9jAAsGbWFsbG9jADkLbGxodHRwX2ZyZWUADARmcmVlAAwPbGxodHRwX2dldF90eXBlAA0VbGxodHRwX2dldF9odHRwX21ham9yAA4VbGxodHRwX2dldF9odHRwX21pbm9yAA8RbGxodHRwX2dldF9tZXRob2QAEBZsbGh0dHBfZ2V0X3N0YXR1c19jb2RlABESbGxodHRwX2dldF91cGdyYWRlABIMbGxodHRwX3Jlc2V0ABMObGxodHRwX2V4ZWN1dGUAFBRsbGh0dHBfc2V0dGluZ3NfaW5pdAAVDWxsaHR0cF9maW5pc2gAFgxsbGh0dHBfcGF1c2UAFw1sbGh0dHBfcmVzdW1lABgbbGxodHRwX3Jlc3VtZV9hZnRlcl91cGdyYWRlABkQbGxodHRwX2dldF9lcnJubwAaF2xsaHR0cF9nZXRfZXJyb3JfcmVhc29uABsXbGxodHRwX3NldF9lcnJvcl9yZWFzb24AHBRsbGh0dHBfZ2V0X2Vycm9yX3BvcwAdEWxsaHR0cF9lcnJub19uYW1lAB4SbGxodHRwX21ldGhvZF9uYW1lAB8SbGxodHRwX3N0YXR1c19uYW1lACAabGxodHRwX3NldF9sZW5pZW50X2hlYWRlcnMAISFsbGh0dHBfc2V0X2xlbmllbnRfY2h1bmtlZF9sZW5ndGgAIh1sbGh0dHBfc2V0X2xlbmllbnRfa2VlcF9hbGl2ZQAjJGxsaHR0cF9zZXRfbGVuaWVudF90cmFuc2Zlcl9lbmNvZGluZwAkGmxsaHR0cF9zZXRfbGVuaWVudF92ZXJzaW9uACUjbGxodHRwX3NldF9sZW5pZW50X2RhdGFfYWZ0ZXJfY2xvc2UAJidsbGh0dHBfc2V0X2xlbmllbnRfb3B0aW9uYWxfbGZfYWZ0ZXJfY3IAJyxsbGh0dHBfc2V0X2xlbmllbnRfb3B0aW9uYWxfY3JsZl9hZnRlcl9jaHVuawAoKGxsaHR0cF9zZXRfbGVuaWVudF9vcHRpb25hbF9jcl9iZWZvcmVfbGYAKSpsbGh0dHBfc2V0X2xlbmllbnRfc3BhY2VzX2FmdGVyX2NodW5rX3NpemUAKhhsbGh0dHBfbWVzc2FnZV9uZWVkc19lb2YANgkYAQBBAQsSAQIDBAUKBgcyNDMuKy8tLDAxCuzaAjQWAEHA1QAoAgAEQAALQcDVAEEBNgIACxQAIAAQOCAAIAI2AjggACABOgAoCxQAIAAgAC8BNCAALQAwIAAQNxAACx4BAX9BwAAQOiIBEDggAUGACDYCOCABIAA6ACggAQuPDAEHfwJAIABFDQAgAEEIayIBIABBBGsoAgAiAEF4cSIEaiEFAkAgAEEBcQ0AIABBA3FFDQEgASABKAIAIgBrIgFB1NUAKAIASQ0BIAAgBGohBAJAAkBB2NUAKAIAIAFHBEAgAEH/AU0EQCAAQQN2IQMgASgCCCIAIAEoAgwiAkYEQEHE1QBBxNUAKAIAQX4gA3dxNgIADAULIAIgADYCCCAAIAI2AgwMBAsgASgCGCEGIAEgASgCDCIARwRAIAAgASgCCCICNgIIIAIgADYCDAwDCyABQRRqIgMoAgAiAkUEQCABKAIQIgJFDQIgAUEQaiEDCwNAIAMhByACIgBBFGoiAygCACICDQAgAEEQaiEDIAAoAhAiAg0ACyAHQQA2AgAMAgsgBSgCBCIAQQNxQQNHDQIgBSAAQX5xNgIEQczVACAENgIAIAUgBDYCACABIARBAXI2AgQMAwtBACEACyAGRQ0AAkAgASgCHCICQQJ0QfTXAGoiAygCACABRgRAIAMgADYCACAADQFByNUAQcjVACgCAEF+IAJ3cTYCAAwCCyAGQRBBFCAGKAIQIAFGG2ogADYCACAARQ0BCyAAIAY2AhggASgCECICBEAgACACNgIQIAIgADYCGAsgAUEUaigCACICRQ0AIABBFGogAjYCACACIAA2AhgLIAEgBU8NACAFKAIEIgBBAXFFDQACQAJAAkACQCAAQQJxRQRAQdzVACgCACAFRgRAQdzVACABNgIAQdDVAEHQ1QAoAgAgBGoiADYCACABIABBAXI2AgQgAUHY1QAoAgBHDQZBzNUAQQA2AgBB2NUAQQA2AgAMBgtB2NUAKAIAIAVGBEBB2NUAIAE2AgBBzNUAQczVACgCACAEaiIANgIAIAEgAEEBcjYCBCAAIAFqIAA2AgAMBgsgAEF4cSAEaiEEIABB/wFNBEAgAEEDdiEDIAUoAggiACAFKAIMIgJGBEBBxNUAQcTVACgCAEF+IAN3cTYCAAwFCyACIAA2AgggACACNgIMDAQLIAUoAhghBiAFIAUoAgwiAEcEQEHU1QAoAgAaIAAgBSgCCCICNgIIIAIgADYCDAwDCyAFQRRqIgMoAgAiAkUEQCAFKAIQIgJFDQIgBUEQaiEDCwNAIAMhByACIgBBFGoiAygCACICDQAgAEEQaiEDIAAoAhAiAg0ACyAHQQA2AgAMAgsgBSAAQX5xNgIEIAEgBGogBDYCACABIARBAXI2AgQMAwtBACEACyAGRQ0AAkAgBSgCHCICQQJ0QfTXAGoiAygCACAFRgRAIAMgADYCACAADQFByNUAQcjVACgCAEF+IAJ3cTYCAAwCCyAGQRBBFCAGKAIQIAVGG2ogADYCACAARQ0BCyAAIAY2AhggBSgCECICBEAgACACNgIQIAIgADYCGAsgBUEUaigCACICRQ0AIABBFGogAjYCACACIAA2AhgLIAEgBGogBDYCACABIARBAXI2AgQgAUHY1QAoAgBHDQBBzNUAIAQ2AgAMAQsgBEH/AU0EQCAEQXhxQezVAGohAAJ/QcTVACgCACICQQEgBEEDdnQiA3FFBEBBxNUAIAIgA3I2AgAgAAwBCyAAKAIICyICIAE2AgwgACABNgIIIAEgADYCDCABIAI2AggMAQtBHyECIARB////B00EQCAEQSYgBEEIdmciAGt2QQFxIABBAXRrQT5qIQILIAEgAjYCHCABQgA3AhAgAkECdEH01wBqIQACQEHI1QAoAgAiA0EBIAJ0IgdxRQRAIAAgATYCAEHI1QAgAyAHcjYCACABIAA2AhggASABNgIIIAEgATYCDAwBCyAEQRkgAkEBdmtBACACQR9HG3QhAiAAKAIAIQACQANAIAAiAygCBEF4cSAERg0BIAJBHXYhACACQQF0IQIgAyAAQQRxakEQaiIHKAIAIgANAAsgByABNgIAIAEgAzYCGCABIAE2AgwgASABNgIIDAELIAMoAggiACABNgIMIAMgATYCCCABQQA2AhggASADNgIMIAEgADYCCAtB5NUAQeTVACgCAEEBayIAQX8gABs2AgALCwcAIAAtACgLBwAgAC0AKgsHACAALQArCwcAIAAtACkLBwAgAC8BNAsHACAALQAwC0ABBH8gACgCGCEBIAAvAS4hAiAALQAoIQMgACgCOCEEIAAQOCAAIAQ2AjggACADOgAoIAAgAjsBLiAAIAE2AhgLhocCAwd/A34BeyABIAJqIQQCQCAAIgMoAgwiAA0AIAMoAgQEQCADIAE2AgQLIwBBEGsiCSQAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADKAIcIgJBAmsO/AEB+QECAwQFBgcICQoLDA0ODxAREvgBE/cBFBX2ARYX9QEYGRobHB0eHyD9AfsBIfQBIiMkJSYnKCkqK/MBLC0uLzAxMvIB8QEzNPAB7wE1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk/6AVBRUlPuAe0BVOwBVesBVldYWVrqAVtcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AAYEBggGDAYQBhQGGAYcBiAGJAYoBiwGMAY0BjgGPAZABkQGSAZMBlAGVAZYBlwGYAZkBmgGbAZwBnQGeAZ8BoAGhAaIBowGkAaUBpgGnAagBqQGqAasBrAGtAa4BrwGwAbEBsgGzAbQBtQG2AbcBuAG5AboBuwG8Ab0BvgG/AcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQHOAekB6AHPAecB0AHmAdEB0gHTAdQB5QHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wEA/AELQQAM4wELQQ4M4gELQQ0M4QELQQ8M4AELQRAM3wELQRMM3gELQRQM3QELQRUM3AELQRYM2wELQRcM2gELQRgM2QELQRkM2AELQRoM1wELQRsM1gELQRwM1QELQR0M1AELQR4M0wELQR8M0gELQSAM0QELQSEM0AELQQgMzwELQSIMzgELQSQMzQELQSMMzAELQQcMywELQSUMygELQSYMyQELQScMyAELQSgMxwELQRIMxgELQREMxQELQSkMxAELQSoMwwELQSsMwgELQSwMwQELQd4BDMABC0EuDL8BC0EvDL4BC0EwDL0BC0ExDLwBC0EyDLsBC0EzDLoBC0E0DLkBC0HfAQy4AQtBNQy3AQtBOQy2AQtBDAy1AQtBNgy0AQtBNwyzAQtBOAyyAQtBPgyxAQtBOgywAQtB4AEMrwELQQsMrgELQT8MrQELQTsMrAELQQoMqwELQTwMqgELQT0MqQELQeEBDKgBC0HBAAynAQtBwAAMpgELQcIADKUBC0EJDKQBC0EtDKMBC0HDAAyiAQtBxAAMoQELQcUADKABC0HGAAyfAQtBxwAMngELQcgADJ0BC0HJAAycAQtBygAMmwELQcsADJoBC0HMAAyZAQtBzQAMmAELQc4ADJcBC0HPAAyWAQtB0AAMlQELQdEADJQBC0HSAAyTAQtB0wAMkgELQdUADJEBC0HUAAyQAQtB1gAMjwELQdcADI4BC0HYAAyNAQtB2QAMjAELQdoADIsBC0HbAAyKAQtB3AAMiQELQd0ADIgBC0HeAAyHAQtB3wAMhgELQeAADIUBC0HhAAyEAQtB4gAMgwELQeMADIIBC0HkAAyBAQtB5QAMgAELQeIBDH8LQeYADH4LQecADH0LQQYMfAtB6AAMewtBBQx6C0HpAAx5C0EEDHgLQeoADHcLQesADHYLQewADHULQe0ADHQLQQMMcwtB7gAMcgtB7wAMcQtB8AAMcAtB8gAMbwtB8QAMbgtB8wAMbQtB9AAMbAtB9QAMawtB9gAMagtBAgxpC0H3AAxoC0H4AAxnC0H5AAxmC0H6AAxlC0H7AAxkC0H8AAxjC0H9AAxiC0H+AAxhC0H/AAxgC0GAAQxfC0GBAQxeC0GCAQxdC0GDAQxcC0GEAQxbC0GFAQxaC0GGAQxZC0GHAQxYC0GIAQxXC0GJAQxWC0GKAQxVC0GLAQxUC0GMAQxTC0GNAQxSC0GOAQxRC0GPAQxQC0GQAQxPC0GRAQxOC0GSAQxNC0GTAQxMC0GUAQxLC0GVAQxKC0GWAQxJC0GXAQxIC0GYAQxHC0GZAQxGC0GaAQxFC0GbAQxEC0GcAQxDC0GdAQxCC0GeAQxBC0GfAQxAC0GgAQw/C0GhAQw+C0GiAQw9C0GjAQw8C0GkAQw7C0GlAQw6C0GmAQw5C0GnAQw4C0GoAQw3C0GpAQw2C0GqAQw1C0GrAQw0C0GsAQwzC0GtAQwyC0GuAQwxC0GvAQwwC0GwAQwvC0GxAQwuC0GyAQwtC0GzAQwsC0G0AQwrC0G1AQwqC0G2AQwpC0G3AQwoC0G4AQwnC0G5AQwmC0G6AQwlC0G7AQwkC0G8AQwjC0G9AQwiC0G+AQwhC0G/AQwgC0HAAQwfC0HBAQweC0HCAQwdC0EBDBwLQcMBDBsLQcQBDBoLQcUBDBkLQcYBDBgLQccBDBcLQcgBDBYLQckBDBULQcoBDBQLQcsBDBMLQcwBDBILQc0BDBELQc4BDBALQc8BDA8LQdABDA4LQdEBDA0LQdIBDAwLQdMBDAsLQdQBDAoLQdUBDAkLQdYBDAgLQeMBDAcLQdcBDAYLQdgBDAULQdkBDAQLQdoBDAMLQdsBDAILQd0BDAELQdwBCyECA0ACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAMCfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAAn8CQAJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAwJ/AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJ/AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCACDuMBAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISMkJScoKZ4DmwOaA5EDigODA4AD/QL7AvgC8gLxAu8C7QLoAucC5gLlAuQC3ALbAtoC2QLYAtcC1gLVAs8CzgLMAssCygLJAsgCxwLGAsQCwwK+ArwCugK5ArgCtwK2ArUCtAKzArICsQKwAq4CrQKpAqgCpwKmAqUCpAKjAqICoQKgAp8CmAKQAowCiwKKAoEC/gH9AfwB+wH6AfkB+AH3AfUB8wHwAesB6QHoAecB5gHlAeQB4wHiAeEB4AHfAd4B3QHcAdoB2QHYAdcB1gHVAdQB0wHSAdEB0AHPAc4BzQHMAcsBygHJAcgBxwHGAcUBxAHDAcIBwQHAAb8BvgG9AbwBuwG6AbkBuAG3AbYBtQG0AbMBsgGxAbABrwGuAa0BrAGrAaoBqQGoAacBpgGlAaQBowGiAZ8BngGZAZgBlwGWAZUBlAGTAZIBkQGQAY8BjQGMAYcBhgGFAYQBgwGCAX18e3p5dnV0UFFSU1RVCyABIARHDXJB/QEhAgy+AwsgASAERw2YAUHbASECDL0DCyABIARHDfEBQY4BIQIMvAMLIAEgBEcN/AFBhAEhAgy7AwsgASAERw2KAkH/ACECDLoDCyABIARHDZECQf0AIQIMuQMLIAEgBEcNlAJB+wAhAgy4AwsgASAERw0eQR4hAgy3AwsgASAERw0ZQRghAgy2AwsgASAERw3KAkHNACECDLUDCyABIARHDdUCQcYAIQIMtAMLIAEgBEcN1gJBwwAhAgyzAwsgASAERw3cAkE4IQIMsgMLIAMtADBBAUYNrQMMiQMLQQAhAAJAAkACQCADLQAqRQ0AIAMtACtFDQAgAy8BMiICQQJxRQ0BDAILIAMvATIiAkEBcUUNAQtBASEAIAMtAChBAUYNACADLwE0IgZB5ABrQeQASQ0AIAZBzAFGDQAgBkGwAkYNACACQcAAcQ0AQQAhACACQYgEcUGABEYNACACQShxQQBHIQALIANBADsBMiADQQA6ADECQCAARQRAIANBADoAMSADLQAuQQRxDQEMsQMLIANCADcDIAsgA0EAOgAxIANBAToANgxIC0EAIQACQCADKAI4IgJFDQAgAigCMCICRQ0AIAMgAhEAACEACyAARQ1IIABBFUcNYiADQQQ2AhwgAyABNgIUIANB0hs2AhAgA0EVNgIMQQAhAgyvAwsgASAERgRAQQYhAgyvAwsgAS0AAEEKRw0ZIAFBAWohAQwaCyADQgA3AyBBEiECDJQDCyABIARHDYoDQSMhAgysAwsgASAERgRAQQchAgysAwsCQAJAIAEtAABBCmsOBAEYGAAYCyABQQFqIQFBECECDJMDCyABQQFqIQEgA0Evai0AAEEBcQ0XQQAhAiADQQA2AhwgAyABNgIUIANBmSA2AhAgA0EZNgIMDKsDCyADIAMpAyAiDCAEIAFrrSIKfSILQgAgCyAMWBs3AyAgCiAMWg0YQQghAgyqAwsgASAERwRAIANBCTYCCCADIAE2AgRBFCECDJEDC0EJIQIMqQMLIAMpAyBQDa4CDEMLIAEgBEYEQEELIQIMqAMLIAEtAABBCkcNFiABQQFqIQEMFwsgA0Evai0AAEEBcUUNGQwmC0EAIQACQCADKAI4IgJFDQAgAigCUCICRQ0AIAMgAhEAACEACyAADRkMQgtBACEAAkAgAygCOCICRQ0AIAIoAlAiAkUNACADIAIRAAAhAAsgAA0aDCQLQQAhAAJAIAMoAjgiAkUNACACKAJQIgJFDQAgAyACEQAAIQALIAANGwwyCyADQS9qLQAAQQFxRQ0cDCILQQAhAAJAIAMoAjgiAkUNACACKAJUIgJFDQAgAyACEQAAIQALIAANHAxCC0EAIQACQCADKAI4IgJFDQAgAigCVCICRQ0AIAMgAhEAACEACyAADR0MIAsgASAERgRAQRMhAgygAwsCQCABLQAAIgBBCmsOBB8jIwAiCyABQQFqIQEMHwtBACEAAkAgAygCOCICRQ0AIAIoAlQiAkUNACADIAIRAAAhAAsgAA0iDEILIAEgBEYEQEEWIQIMngMLIAEtAABBwMEAai0AAEEBRw0jDIMDCwJAA0AgAS0AAEGwO2otAAAiAEEBRwRAAkAgAEECaw4CAwAnCyABQQFqIQFBISECDIYDCyAEIAFBAWoiAUcNAAtBGCECDJ0DCyADKAIEIQBBACECIANBADYCBCADIAAgAUEBaiIBEDQiAA0hDEELQQAhAAJAIAMoAjgiAkUNACACKAJUIgJFDQAgAyACEQAAIQALIAANIwwqCyABIARGBEBBHCECDJsDCyADQQo2AgggAyABNgIEQQAhAAJAIAMoAjgiAkUNACACKAJQIgJFDQAgAyACEQAAIQALIAANJUEkIQIMgQMLIAEgBEcEQANAIAEtAABBsD1qLQAAIgBBA0cEQCAAQQFrDgUYGiaCAyUmCyAEIAFBAWoiAUcNAAtBGyECDJoDC0EbIQIMmQMLA0AgAS0AAEGwP2otAAAiAEEDRwRAIABBAWsOBQ8RJxMmJwsgBCABQQFqIgFHDQALQR4hAgyYAwsgASAERwRAIANBCzYCCCADIAE2AgRBByECDP8CC0EfIQIMlwMLIAEgBEYEQEEgIQIMlwMLAkAgAS0AAEENaw4ULj8/Pz8/Pz8/Pz8/Pz8/Pz8/PwA/C0EAIQIgA0EANgIcIANBvws2AhAgA0ECNgIMIAMgAUEBajYCFAyWAwsgA0EvaiECA0AgASAERgRAQSEhAgyXAwsCQAJAAkAgAS0AACIAQQlrDhgCACkpASkpKSkpKSkpKSkpKSkpKSkpKQInCyABQQFqIQEgA0Evai0AAEEBcUUNCgwYCyABQQFqIQEMFwsgAUEBaiEBIAItAABBAnENAAtBACECIANBADYCHCADIAE2AhQgA0GfFTYCECADQQw2AgwMlQMLIAMtAC5BgAFxRQ0BC0EAIQACQCADKAI4IgJFDQAgAigCXCICRQ0AIAMgAhEAACEACyAARQ3mAiAAQRVGBEAgA0EkNgIcIAMgATYCFCADQZsbNgIQIANBFTYCDEEAIQIMlAMLQQAhAiADQQA2AhwgAyABNgIUIANBkA42AhAgA0EUNgIMDJMDC0EAIQIgA0EANgIcIAMgATYCFCADQb4gNgIQIANBAjYCDAySAwsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEgDKdqIgEQMiIARQ0rIANBBzYCHCADIAE2AhQgAyAANgIMDJEDCyADLQAuQcAAcUUNAQtBACEAAkAgAygCOCICRQ0AIAIoAlgiAkUNACADIAIRAAAhAAsgAEUNKyAAQRVGBEAgA0EKNgIcIAMgATYCFCADQesZNgIQIANBFTYCDEEAIQIMkAMLQQAhAiADQQA2AhwgAyABNgIUIANBkww2AhAgA0ETNgIMDI8DC0EAIQIgA0EANgIcIAMgATYCFCADQYIVNgIQIANBAjYCDAyOAwtBACECIANBADYCHCADIAE2AhQgA0HdFDYCECADQRk2AgwMjQMLQQAhAiADQQA2AhwgAyABNgIUIANB5h02AhAgA0EZNgIMDIwDCyAAQRVGDT1BACECIANBADYCHCADIAE2AhQgA0HQDzYCECADQSI2AgwMiwMLIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDMiAEUNKCADQQ02AhwgAyABNgIUIAMgADYCDAyKAwsgAEEVRg06QQAhAiADQQA2AhwgAyABNgIUIANB0A82AhAgA0EiNgIMDIkDCyADKAIEIQBBACECIANBADYCBCADIAAgARAzIgBFBEAgAUEBaiEBDCgLIANBDjYCHCADIAA2AgwgAyABQQFqNgIUDIgDCyAAQRVGDTdBACECIANBADYCHCADIAE2AhQgA0HQDzYCECADQSI2AgwMhwMLIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDMiAEUEQCABQQFqIQEMJwsgA0EPNgIcIAMgADYCDCADIAFBAWo2AhQMhgMLQQAhAiADQQA2AhwgAyABNgIUIANB4hc2AhAgA0EZNgIMDIUDCyAAQRVGDTNBACECIANBADYCHCADIAE2AhQgA0HWDDYCECADQSM2AgwMhAMLIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDQiAEUNJSADQRE2AhwgAyABNgIUIAMgADYCDAyDAwsgAEEVRg0wQQAhAiADQQA2AhwgAyABNgIUIANB1gw2AhAgA0EjNgIMDIIDCyADKAIEIQBBACECIANBADYCBCADIAAgARA0IgBFBEAgAUEBaiEBDCULIANBEjYCHCADIAA2AgwgAyABQQFqNgIUDIEDCyADQS9qLQAAQQFxRQ0BC0EXIQIM5gILQQAhAiADQQA2AhwgAyABNgIUIANB4hc2AhAgA0EZNgIMDP4CCyAAQTtHDQAgAUEBaiEBDAwLQQAhAiADQQA2AhwgAyABNgIUIANBkhg2AhAgA0ECNgIMDPwCCyAAQRVGDShBACECIANBADYCHCADIAE2AhQgA0HWDDYCECADQSM2AgwM+wILIANBFDYCHCADIAE2AhQgAyAANgIMDPoCCyADKAIEIQBBACECIANBADYCBCADIAAgARA0IgBFBEAgAUEBaiEBDPUCCyADQRU2AhwgAyAANgIMIAMgAUEBajYCFAz5AgsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQzzAgsgA0EXNgIcIAMgADYCDCADIAFBAWo2AhQM+AILIABBFUYNI0EAIQIgA0EANgIcIAMgATYCFCADQdYMNgIQIANBIzYCDAz3AgsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQwdCyADQRk2AhwgAyAANgIMIAMgAUEBajYCFAz2AgsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQzvAgsgA0EaNgIcIAMgADYCDCADIAFBAWo2AhQM9QILIABBFUYNH0EAIQIgA0EANgIcIAMgATYCFCADQdAPNgIQIANBIjYCDAz0AgsgAygCBCEAIANBADYCBCADIAAgARAzIgBFBEAgAUEBaiEBDBsLIANBHDYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgzzAgsgAygCBCEAIANBADYCBCADIAAgARAzIgBFBEAgAUEBaiEBDOsCCyADQR02AhwgAyAANgIMIAMgAUEBajYCFEEAIQIM8gILIABBO0cNASABQQFqIQELQSYhAgzXAgtBACECIANBADYCHCADIAE2AhQgA0GfFTYCECADQQw2AgwM7wILIAEgBEcEQANAIAEtAABBIEcNhAIgBCABQQFqIgFHDQALQSwhAgzvAgtBLCECDO4CCyABIARGBEBBNCECDO4CCwJAAkADQAJAIAEtAABBCmsOBAIAAAMACyAEIAFBAWoiAUcNAAtBNCECDO8CCyADKAIEIQAgA0EANgIEIAMgACABEDEiAEUNnwIgA0EyNgIcIAMgATYCFCADIAA2AgxBACECDO4CCyADKAIEIQAgA0EANgIEIAMgACABEDEiAEUEQCABQQFqIQEMnwILIANBMjYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgztAgsgASAERwRAAkADQCABLQAAQTBrIgBB/wFxQQpPBEBBOiECDNcCCyADKQMgIgtCmbPmzJmz5swZVg0BIAMgC0IKfiIKNwMgIAogAK1C/wGDIgtCf4VWDQEgAyAKIAt8NwMgIAQgAUEBaiIBRw0AC0HAACECDO4CCyADKAIEIQAgA0EANgIEIAMgACABQQFqIgEQMSIADRcM4gILQcAAIQIM7AILIAEgBEYEQEHJACECDOwCCwJAA0ACQCABLQAAQQlrDhgAAqICogKpAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAgCiAgsgBCABQQFqIgFHDQALQckAIQIM7AILIAFBAWohASADQS9qLQAAQQFxDaUCIANBADYCHCADIAE2AhQgA0GXEDYCECADQQo2AgxBACECDOsCCyABIARHBEADQCABLQAAQSBHDRUgBCABQQFqIgFHDQALQfgAIQIM6wILQfgAIQIM6gILIANBAjoAKAw4C0EAIQIgA0EANgIcIANBvws2AhAgA0ECNgIMIAMgAUEBajYCFAzoAgtBACECDM4CC0ENIQIMzQILQRMhAgzMAgtBFSECDMsCC0EWIQIMygILQRghAgzJAgtBGSECDMgCC0EaIQIMxwILQRshAgzGAgtBHCECDMUCC0EdIQIMxAILQR4hAgzDAgtBHyECDMICC0EgIQIMwQILQSIhAgzAAgtBIyECDL8CC0ElIQIMvgILQeUAIQIMvQILIANBPTYCHCADIAE2AhQgAyAANgIMQQAhAgzVAgsgA0EbNgIcIAMgATYCFCADQaQcNgIQIANBFTYCDEEAIQIM1AILIANBIDYCHCADIAE2AhQgA0GYGjYCECADQRU2AgxBACECDNMCCyADQRM2AhwgAyABNgIUIANBmBo2AhAgA0EVNgIMQQAhAgzSAgsgA0ELNgIcIAMgATYCFCADQZgaNgIQIANBFTYCDEEAIQIM0QILIANBEDYCHCADIAE2AhQgA0GYGjYCECADQRU2AgxBACECDNACCyADQSA2AhwgAyABNgIUIANBpBw2AhAgA0EVNgIMQQAhAgzPAgsgA0ELNgIcIAMgATYCFCADQaQcNgIQIANBFTYCDEEAIQIMzgILIANBDDYCHCADIAE2AhQgA0GkHDYCECADQRU2AgxBACECDM0CC0EAIQIgA0EANgIcIAMgATYCFCADQd0ONgIQIANBEjYCDAzMAgsCQANAAkAgAS0AAEEKaw4EAAICAAILIAQgAUEBaiIBRw0AC0H9ASECDMwCCwJAAkAgAy0ANkEBRw0AQQAhAAJAIAMoAjgiAkUNACACKAJgIgJFDQAgAyACEQAAIQALIABFDQAgAEEVRw0BIANB/AE2AhwgAyABNgIUIANB3Bk2AhAgA0EVNgIMQQAhAgzNAgtB3AEhAgyzAgsgA0EANgIcIAMgATYCFCADQfkLNgIQIANBHzYCDEEAIQIMywILAkACQCADLQAoQQFrDgIEAQALQdsBIQIMsgILQdQBIQIMsQILIANBAjoAMUEAIQACQCADKAI4IgJFDQAgAigCACICRQ0AIAMgAhEAACEACyAARQRAQd0BIQIMsQILIABBFUcEQCADQQA2AhwgAyABNgIUIANBtAw2AhAgA0EQNgIMQQAhAgzKAgsgA0H7ATYCHCADIAE2AhQgA0GBGjYCECADQRU2AgxBACECDMkCCyABIARGBEBB+gEhAgzJAgsgAS0AAEHIAEYNASADQQE6ACgLQcABIQIMrgILQdoBIQIMrQILIAEgBEcEQCADQQw2AgggAyABNgIEQdkBIQIMrQILQfkBIQIMxQILIAEgBEYEQEH4ASECDMUCCyABLQAAQcgARw0EIAFBAWohAUHYASECDKsCCyABIARGBEBB9wEhAgzEAgsCQAJAIAEtAABBxQBrDhAABQUFBQUFBQUFBQUFBQUBBQsgAUEBaiEBQdYBIQIMqwILIAFBAWohAUHXASECDKoCC0H2ASECIAEgBEYNwgIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABButUAai0AAEcNAyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMwwILIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARAuIgBFBEBB4wEhAgyqAgsgA0H1ATYCHCADIAE2AhQgAyAANgIMQQAhAgzCAgtB9AEhAiABIARGDcECIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQbjVAGotAABHDQIgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADMICCyADQYEEOwEoIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARAuIgANAwwCCyADQQA2AgALQQAhAiADQQA2AhwgAyABNgIUIANB5R82AhAgA0EINgIMDL8CC0HVASECDKUCCyADQfMBNgIcIAMgATYCFCADIAA2AgxBACECDL0CC0EAIQACQCADKAI4IgJFDQAgAigCQCICRQ0AIAMgAhEAACEACyAARQ1uIABBFUcEQCADQQA2AhwgAyABNgIUIANBgg82AhAgA0EgNgIMQQAhAgy9AgsgA0GPATYCHCADIAE2AhQgA0HsGzYCECADQRU2AgxBACECDLwCCyABIARHBEAgA0ENNgIIIAMgATYCBEHTASECDKMCC0HyASECDLsCCyABIARGBEBB8QEhAgy7AgsCQAJAAkAgAS0AAEHIAGsOCwABCAgICAgICAgCCAsgAUEBaiEBQdABIQIMowILIAFBAWohAUHRASECDKICCyABQQFqIQFB0gEhAgyhAgtB8AEhAiABIARGDbkCIAMoAgAiACAEIAFraiEGIAEgAGtBAmohBQNAIAEtAAAgAEG11QBqLQAARw0EIABBAkYNAyAAQQFqIQAgBCABQQFqIgFHDQALIAMgBjYCAAy5AgtB7wEhAiABIARGDbgCIAMoAgAiACAEIAFraiEGIAEgAGtBAWohBQNAIAEtAAAgAEGz1QBqLQAARw0DIABBAUYNAiAAQQFqIQAgBCABQQFqIgFHDQALIAMgBjYCAAy4AgtB7gEhAiABIARGDbcCIAMoAgAiACAEIAFraiEGIAEgAGtBAmohBQNAIAEtAAAgAEGw1QBqLQAARw0CIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBjYCAAy3AgsgAygCBCEAIANCADcDACADIAAgBUEBaiIBECsiAEUNAiADQewBNgIcIAMgATYCFCADIAA2AgxBACECDLYCCyADQQA2AgALIAMoAgQhACADQQA2AgQgAyAAIAEQKyIARQ2cAiADQe0BNgIcIAMgATYCFCADIAA2AgxBACECDLQCC0HPASECDJoCC0EAIQACQCADKAI4IgJFDQAgAigCNCICRQ0AIAMgAhEAACEACwJAIAAEQCAAQRVGDQEgA0EANgIcIAMgATYCFCADQeoNNgIQIANBJjYCDEEAIQIMtAILQc4BIQIMmgILIANB6wE2AhwgAyABNgIUIANBgBs2AhAgA0EVNgIMQQAhAgyyAgsgASAERgRAQesBIQIMsgILIAEtAABBL0YEQCABQQFqIQEMAQsgA0EANgIcIAMgATYCFCADQbI4NgIQIANBCDYCDEEAIQIMsQILQc0BIQIMlwILIAEgBEcEQCADQQ42AgggAyABNgIEQcwBIQIMlwILQeoBIQIMrwILIAEgBEYEQEHpASECDK8CCyABLQAAQTBrIgBB/wFxQQpJBEAgAyAAOgAqIAFBAWohAUHLASECDJYCCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNlwIgA0HoATYCHCADIAE2AhQgAyAANgIMQQAhAgyuAgsgASAERgRAQecBIQIMrgILAkAgAS0AAEEuRgRAIAFBAWohAQwBCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNmAIgA0HmATYCHCADIAE2AhQgAyAANgIMQQAhAgyuAgtBygEhAgyUAgsgASAERgRAQeUBIQIMrQILQQAhAEEBIQVBASEHQQAhAgJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAIAEtAABBMGsOCgoJAAECAwQFBggLC0ECDAYLQQMMBQtBBAwEC0EFDAMLQQYMAgtBBwwBC0EICyECQQAhBUEAIQcMAgtBCSECQQEhAEEAIQVBACEHDAELQQAhBUEBIQILIAMgAjoAKyABQQFqIQECQAJAIAMtAC5BEHENAAJAAkACQCADLQAqDgMBAAIECyAHRQ0DDAILIAANAQwCCyAFRQ0BCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNAiADQeIBNgIcIAMgATYCFCADIAA2AgxBACECDK8CCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNmgIgA0HjATYCHCADIAE2AhQgAyAANgIMQQAhAgyuAgsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDZgCIANB5AE2AhwgAyABNgIUIAMgADYCDAytAgtByQEhAgyTAgtBACEAAkAgAygCOCICRQ0AIAIoAkQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0GkDTYCECADQSE2AgxBACECDK0CC0HIASECDJMCCyADQeEBNgIcIAMgATYCFCADQdAaNgIQIANBFTYCDEEAIQIMqwILIAEgBEYEQEHhASECDKsCCwJAIAEtAABBIEYEQCADQQA7ATQgAUEBaiEBDAELIANBADYCHCADIAE2AhQgA0GZETYCECADQQk2AgxBACECDKsCC0HHASECDJECCyABIARGBEBB4AEhAgyqAgsCQCABLQAAQTBrQf8BcSICQQpJBEAgAUEBaiEBAkAgAy8BNCIAQZkzSw0AIAMgAEEKbCIAOwE0IABB/v8DcSACQf//A3NLDQAgAyAAIAJqOwE0DAILQQAhAiADQQA2AhwgAyABNgIUIANBlR42AhAgA0ENNgIMDKsCCyADQQA2AhwgAyABNgIUIANBlR42AhAgA0ENNgIMQQAhAgyqAgtBxgEhAgyQAgsgASAERgRAQd8BIQIMqQILAkAgAS0AAEEwa0H/AXEiAkEKSQRAIAFBAWohAQJAIAMvATQiAEGZM0sNACADIABBCmwiADsBNCAAQf7/A3EgAkH//wNzSw0AIAMgACACajsBNAwCC0EAIQIgA0EANgIcIAMgATYCFCADQZUeNgIQIANBDTYCDAyqAgsgA0EANgIcIAMgATYCFCADQZUeNgIQIANBDTYCDEEAIQIMqQILQcUBIQIMjwILIAEgBEYEQEHeASECDKgCCwJAIAEtAABBMGtB/wFxIgJBCkkEQCABQQFqIQECQCADLwE0IgBBmTNLDQAgAyAAQQpsIgA7ATQgAEH+/wNxIAJB//8Dc0sNACADIAAgAmo7ATQMAgtBACECIANBADYCHCADIAE2AhQgA0GVHjYCECADQQ02AgwMqQILIANBADYCHCADIAE2AhQgA0GVHjYCECADQQ02AgxBACECDKgCC0HEASECDI4CCyABIARGBEBB3QEhAgynAgsCQAJAAkACQCABLQAAQQprDhcCAwMAAwMDAwMDAwMDAwMDAwMDAwMDAQMLIAFBAWoMBQsgAUEBaiEBQcMBIQIMjwILIAFBAWohASADQS9qLQAAQQFxDQggA0EANgIcIAMgATYCFCADQY0LNgIQIANBDTYCDEEAIQIMpwILIANBADYCHCADIAE2AhQgA0GNCzYCECADQQ02AgxBACECDKYCCyABIARHBEAgA0EPNgIIIAMgATYCBEEBIQIMjQILQdwBIQIMpQILAkACQANAAkAgAS0AAEEKaw4EAgAAAwALIAQgAUEBaiIBRw0AC0HbASECDKYCCyADKAIEIQAgA0EANgIEIAMgACABEC0iAEUEQCABQQFqIQEMBAsgA0HaATYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgylAgsgAygCBCEAIANBADYCBCADIAAgARAtIgANASABQQFqCyEBQcEBIQIMigILIANB2QE2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMogILQcIBIQIMiAILIANBL2otAABBAXENASADQQA2AhwgAyABNgIUIANB5Bw2AhAgA0EZNgIMQQAhAgygAgsgASAERgRAQdkBIQIMoAILAkACQAJAIAEtAABBCmsOBAECAgACCyABQQFqIQEMAgsgAUEBaiEBDAELIAMtAC5BwABxRQ0BC0EAIQACQCADKAI4IgJFDQAgAigCPCICRQ0AIAMgAhEAACEACyAARQ2gASAAQRVGBEAgA0HZADYCHCADIAE2AhQgA0G3GjYCECADQRU2AgxBACECDJ8CCyADQQA2AhwgAyABNgIUIANBgA02AhAgA0EbNgIMQQAhAgyeAgsgA0EANgIcIAMgATYCFCADQdwoNgIQIANBAjYCDEEAIQIMnQILIAEgBEcEQCADQQw2AgggAyABNgIEQb8BIQIMhAILQdgBIQIMnAILIAEgBEYEQEHXASECDJwCCwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAS0AAEHBAGsOFQABAgNaBAUGWlpaBwgJCgsMDQ4PEFoLIAFBAWohAUH7ACECDJICCyABQQFqIQFB/AAhAgyRAgsgAUEBaiEBQYEBIQIMkAILIAFBAWohAUGFASECDI8CCyABQQFqIQFBhgEhAgyOAgsgAUEBaiEBQYkBIQIMjQILIAFBAWohAUGKASECDIwCCyABQQFqIQFBjQEhAgyLAgsgAUEBaiEBQZYBIQIMigILIAFBAWohAUGXASECDIkCCyABQQFqIQFBmAEhAgyIAgsgAUEBaiEBQaUBIQIMhwILIAFBAWohAUGmASECDIYCCyABQQFqIQFBrAEhAgyFAgsgAUEBaiEBQbQBIQIMhAILIAFBAWohAUG3ASECDIMCCyABQQFqIQFBvgEhAgyCAgsgASAERgRAQdYBIQIMmwILIAEtAABBzgBHDUggAUEBaiEBQb0BIQIMgQILIAEgBEYEQEHVASECDJoCCwJAAkACQCABLQAAQcIAaw4SAEpKSkpKSkpKSgFKSkpKSkoCSgsgAUEBaiEBQbgBIQIMggILIAFBAWohAUG7ASECDIECCyABQQFqIQFBvAEhAgyAAgtB1AEhAiABIARGDZgCIAMoAgAiACAEIAFraiEFIAEgAGtBB2ohBgJAA0AgAS0AACAAQajVAGotAABHDUUgAEEHRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJkCCyADQQA2AgAgBkEBaiEBQRsMRQsgASAERgRAQdMBIQIMmAILAkACQCABLQAAQckAaw4HAEdHR0dHAUcLIAFBAWohAUG5ASECDP8BCyABQQFqIQFBugEhAgz+AQtB0gEhAiABIARGDZYCIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQabVAGotAABHDUMgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJcCCyADQQA2AgAgBkEBaiEBQQ8MQwtB0QEhAiABIARGDZUCIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQaTVAGotAABHDUIgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJYCCyADQQA2AgAgBkEBaiEBQSAMQgtB0AEhAiABIARGDZQCIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQaHVAGotAABHDUEgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJUCCyADQQA2AgAgBkEBaiEBQRIMQQsgASAERgRAQc8BIQIMlAILAkACQCABLQAAQcUAaw4OAENDQ0NDQ0NDQ0NDQwFDCyABQQFqIQFBtQEhAgz7AQsgAUEBaiEBQbYBIQIM+gELQc4BIQIgASAERg2SAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGe1QBqLQAARw0/IABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyTAgsgA0EANgIAIAZBAWohAUEHDD8LQc0BIQIgASAERg2RAiADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEGY1QBqLQAARw0+IABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAySAgsgA0EANgIAIAZBAWohAUEoDD4LIAEgBEYEQEHMASECDJECCwJAAkACQCABLQAAQcUAaw4RAEFBQUFBQUFBQQFBQUFBQQJBCyABQQFqIQFBsQEhAgz5AQsgAUEBaiEBQbIBIQIM+AELIAFBAWohAUGzASECDPcBC0HLASECIAEgBEYNjwIgAygCACIAIAQgAWtqIQUgASAAa0EGaiEGAkADQCABLQAAIABBkdUAai0AAEcNPCAAQQZGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMkAILIANBADYCACAGQQFqIQFBGgw8C0HKASECIAEgBEYNjgIgAygCACIAIAQgAWtqIQUgASAAa0EDaiEGAkADQCABLQAAIABBjdUAai0AAEcNOyAAQQNGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMjwILIANBADYCACAGQQFqIQFBIQw7CyABIARGBEBByQEhAgyOAgsCQAJAIAEtAABBwQBrDhQAPT09PT09PT09PT09PT09PT09AT0LIAFBAWohAUGtASECDPUBCyABQQFqIQFBsAEhAgz0AQsgASAERgRAQcgBIQIMjQILAkACQCABLQAAQdUAaw4LADw8PDw8PDw8PAE8CyABQQFqIQFBrgEhAgz0AQsgAUEBaiEBQa8BIQIM8wELQccBIQIgASAERg2LAiADKAIAIgAgBCABa2ohBSABIABrQQhqIQYCQANAIAEtAAAgAEGE1QBqLQAARw04IABBCEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyMAgsgA0EANgIAIAZBAWohAUEqDDgLIAEgBEYEQEHGASECDIsCCyABLQAAQdAARw04IAFBAWohAUElDDcLQcUBIQIgASAERg2JAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGB1QBqLQAARw02IABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyKAgsgA0EANgIAIAZBAWohAUEODDYLIAEgBEYEQEHEASECDIkCCyABLQAAQcUARw02IAFBAWohAUGrASECDO8BCyABIARGBEBBwwEhAgyIAgsCQAJAAkACQCABLQAAQcIAaw4PAAECOTk5OTk5OTk5OTkDOQsgAUEBaiEBQacBIQIM8QELIAFBAWohAUGoASECDPABCyABQQFqIQFBqQEhAgzvAQsgAUEBaiEBQaoBIQIM7gELQcIBIQIgASAERg2GAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEH+1ABqLQAARw0zIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyHAgsgA0EANgIAIAZBAWohAUEUDDMLQcEBIQIgASAERg2FAiADKAIAIgAgBCABa2ohBSABIABrQQRqIQYCQANAIAEtAAAgAEH51ABqLQAARw0yIABBBEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyGAgsgA0EANgIAIAZBAWohAUErDDILQcABIQIgASAERg2EAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEH21ABqLQAARw0xIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyFAgsgA0EANgIAIAZBAWohAUEsDDELQb8BIQIgASAERg2DAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGh1QBqLQAARw0wIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyEAgsgA0EANgIAIAZBAWohAUERDDALQb4BIQIgASAERg2CAiADKAIAIgAgBCABa2ohBSABIABrQQNqIQYCQANAIAEtAAAgAEHy1ABqLQAARw0vIABBA0YNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyDAgsgA0EANgIAIAZBAWohAUEuDC8LIAEgBEYEQEG9ASECDIICCwJAAkACQAJAAkAgAS0AAEHBAGsOFQA0NDQ0NDQ0NDQ0ATQ0AjQ0AzQ0BDQLIAFBAWohAUGbASECDOwBCyABQQFqIQFBnAEhAgzrAQsgAUEBaiEBQZ0BIQIM6gELIAFBAWohAUGiASECDOkBCyABQQFqIQFBpAEhAgzoAQsgASAERgRAQbwBIQIMgQILAkACQCABLQAAQdIAaw4DADABMAsgAUEBaiEBQaMBIQIM6AELIAFBAWohAUEEDC0LQbsBIQIgASAERg3/ASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHw1ABqLQAARw0sIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyAAgsgA0EANgIAIAZBAWohAUEdDCwLIAEgBEYEQEG6ASECDP8BCwJAAkAgAS0AAEHJAGsOBwEuLi4uLgAuCyABQQFqIQFBoQEhAgzmAQsgAUEBaiEBQSIMKwsgASAERgRAQbkBIQIM/gELIAEtAABB0ABHDSsgAUEBaiEBQaABIQIM5AELIAEgBEYEQEG4ASECDP0BCwJAAkAgAS0AAEHGAGsOCwAsLCwsLCwsLCwBLAsgAUEBaiEBQZ4BIQIM5AELIAFBAWohAUGfASECDOMBC0G3ASECIAEgBEYN+wEgAygCACIAIAQgAWtqIQUgASAAa0EDaiEGAkADQCABLQAAIABB7NQAai0AAEcNKCAAQQNGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM/AELIANBADYCACAGQQFqIQFBDQwoC0G2ASECIAEgBEYN+gEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBodUAai0AAEcNJyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM+wELIANBADYCACAGQQFqIQFBDAwnC0G1ASECIAEgBEYN+QEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABB6tQAai0AAEcNJiAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM+gELIANBADYCACAGQQFqIQFBAwwmC0G0ASECIAEgBEYN+AEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABB6NQAai0AAEcNJSAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM+QELIANBADYCACAGQQFqIQFBJgwlCyABIARGBEBBswEhAgz4AQsCQAJAIAEtAABB1ABrDgIAAScLIAFBAWohAUGZASECDN8BCyABQQFqIQFBmgEhAgzeAQtBsgEhAiABIARGDfYBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQebUAGotAABHDSMgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPcBCyADQQA2AgAgBkEBaiEBQScMIwtBsQEhAiABIARGDfUBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQeTUAGotAABHDSIgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPYBCyADQQA2AgAgBkEBaiEBQRwMIgtBsAEhAiABIARGDfQBIAMoAgAiACAEIAFraiEFIAEgAGtBBWohBgJAA0AgAS0AACAAQd7UAGotAABHDSEgAEEFRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPUBCyADQQA2AgAgBkEBaiEBQQYMIQtBrwEhAiABIARGDfMBIAMoAgAiACAEIAFraiEFIAEgAGtBBGohBgJAA0AgAS0AACAAQdnUAGotAABHDSAgAEEERg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPQBCyADQQA2AgAgBkEBaiEBQRkMIAsgASAERgRAQa4BIQIM8wELAkACQAJAAkAgAS0AAEEtaw4jACQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkASQkJCQkAiQkJAMkCyABQQFqIQFBjgEhAgzcAQsgAUEBaiEBQY8BIQIM2wELIAFBAWohAUGUASECDNoBCyABQQFqIQFBlQEhAgzZAQtBrQEhAiABIARGDfEBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQdfUAGotAABHDR4gAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPIBCyADQQA2AgAgBkEBaiEBQQsMHgsgASAERgRAQawBIQIM8QELAkACQCABLQAAQcEAaw4DACABIAsgAUEBaiEBQZABIQIM2AELIAFBAWohAUGTASECDNcBCyABIARGBEBBqwEhAgzwAQsCQAJAIAEtAABBwQBrDg8AHx8fHx8fHx8fHx8fHwEfCyABQQFqIQFBkQEhAgzXAQsgAUEBaiEBQZIBIQIM1gELIAEgBEYEQEGqASECDO8BCyABLQAAQcwARw0cIAFBAWohAUEKDBsLQakBIQIgASAERg3tASADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEHR1ABqLQAARw0aIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzuAQsgA0EANgIAIAZBAWohAUEeDBoLQagBIQIgASAERg3sASADKAIAIgAgBCABa2ohBSABIABrQQZqIQYCQANAIAEtAAAgAEHK1ABqLQAARw0ZIABBBkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAztAQsgA0EANgIAIAZBAWohAUEVDBkLQacBIQIgASAERg3rASADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEHH1ABqLQAARw0YIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzsAQsgA0EANgIAIAZBAWohAUEXDBgLQaYBIQIgASAERg3qASADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEHB1ABqLQAARw0XIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzrAQsgA0EANgIAIAZBAWohAUEYDBcLIAEgBEYEQEGlASECDOoBCwJAAkAgAS0AAEHJAGsOBwAZGRkZGQEZCyABQQFqIQFBiwEhAgzRAQsgAUEBaiEBQYwBIQIM0AELQaQBIQIgASAERg3oASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGm1QBqLQAARw0VIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzpAQsgA0EANgIAIAZBAWohAUEJDBULQaMBIQIgASAERg3nASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGk1QBqLQAARw0UIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzoAQsgA0EANgIAIAZBAWohAUEfDBQLQaIBIQIgASAERg3mASADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEG+1ABqLQAARw0TIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAznAQsgA0EANgIAIAZBAWohAUECDBMLQaEBIQIgASAERg3lASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYDQCABLQAAIABBvNQAai0AAEcNESAAQQFGDQIgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM5QELIAEgBEYEQEGgASECDOUBC0EBIAEtAABB3wBHDREaIAFBAWohAUGHASECDMsBCyADQQA2AgAgBkEBaiEBQYgBIQIMygELQZ8BIQIgASAERg3iASADKAIAIgAgBCABa2ohBSABIABrQQhqIQYCQANAIAEtAAAgAEGE1QBqLQAARw0PIABBCEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzjAQsgA0EANgIAIAZBAWohAUEpDA8LQZ4BIQIgASAERg3hASADKAIAIgAgBCABa2ohBSABIABrQQNqIQYCQANAIAEtAAAgAEG41ABqLQAARw0OIABBA0YNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAziAQsgA0EANgIAIAZBAWohAUEtDA4LIAEgBEYEQEGdASECDOEBCyABLQAAQcUARw0OIAFBAWohAUGEASECDMcBCyABIARGBEBBnAEhAgzgAQsCQAJAIAEtAABBzABrDggADw8PDw8PAQ8LIAFBAWohAUGCASECDMcBCyABQQFqIQFBgwEhAgzGAQtBmwEhAiABIARGDd4BIAMoAgAiACAEIAFraiEFIAEgAGtBBGohBgJAA0AgAS0AACAAQbPUAGotAABHDQsgAEEERg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADN8BCyADQQA2AgAgBkEBaiEBQSMMCwtBmgEhAiABIARGDd0BIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQbDUAGotAABHDQogAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADN4BCyADQQA2AgAgBkEBaiEBQQAMCgsgASAERgRAQZkBIQIM3QELAkACQCABLQAAQcgAaw4IAAwMDAwMDAEMCyABQQFqIQFB/QAhAgzEAQsgAUEBaiEBQYABIQIMwwELIAEgBEYEQEGYASECDNwBCwJAAkAgAS0AAEHOAGsOAwALAQsLIAFBAWohAUH+ACECDMMBCyABQQFqIQFB/wAhAgzCAQsgASAERgRAQZcBIQIM2wELIAEtAABB2QBHDQggAUEBaiEBQQgMBwtBlgEhAiABIARGDdkBIAMoAgAiACAEIAFraiEFIAEgAGtBA2ohBgJAA0AgAS0AACAAQazUAGotAABHDQYgAEEDRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADNoBCyADQQA2AgAgBkEBaiEBQQUMBgtBlQEhAiABIARGDdgBIAMoAgAiACAEIAFraiEFIAEgAGtBBWohBgJAA0AgAS0AACAAQabUAGotAABHDQUgAEEFRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADNkBCyADQQA2AgAgBkEBaiEBQRYMBQtBlAEhAiABIARGDdcBIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQaHVAGotAABHDQQgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADNgBCyADQQA2AgAgBkEBaiEBQRAMBAsgASAERgRAQZMBIQIM1wELAkACQCABLQAAQcMAaw4MAAYGBgYGBgYGBgYBBgsgAUEBaiEBQfkAIQIMvgELIAFBAWohAUH6ACECDL0BC0GSASECIAEgBEYN1QEgAygCACIAIAQgAWtqIQUgASAAa0EFaiEGAkADQCABLQAAIABBoNQAai0AAEcNAiAAQQVGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM1gELIANBADYCACAGQQFqIQFBJAwCCyADQQA2AgAMAgsgASAERgRAQZEBIQIM1AELIAEtAABBzABHDQEgAUEBaiEBQRMLOgApIAMoAgQhACADQQA2AgQgAyAAIAEQLiIADQIMAQtBACECIANBADYCHCADIAE2AhQgA0H+HzYCECADQQY2AgwM0QELQfgAIQIMtwELIANBkAE2AhwgAyABNgIUIAMgADYCDEEAIQIMzwELQQAhAAJAIAMoAjgiAkUNACACKAJAIgJFDQAgAyACEQAAIQALIABFDQAgAEEVRg0BIANBADYCHCADIAE2AhQgA0GCDzYCECADQSA2AgxBACECDM4BC0H3ACECDLQBCyADQY8BNgIcIAMgATYCFCADQewbNgIQIANBFTYCDEEAIQIMzAELIAEgBEYEQEGPASECDMwBCwJAIAEtAABBIEYEQCABQQFqIQEMAQsgA0EANgIcIAMgATYCFCADQZsfNgIQIANBBjYCDEEAIQIMzAELQQIhAgyyAQsDQCABLQAAQSBHDQIgBCABQQFqIgFHDQALQY4BIQIMygELIAEgBEYEQEGNASECDMoBCwJAIAEtAABBCWsOBEoAAEoAC0H1ACECDLABCyADLQApQQVGBEBB9gAhAgywAQtB9AAhAgyvAQsgASAERgRAQYwBIQIMyAELIANBEDYCCCADIAE2AgQMCgsgASAERgRAQYsBIQIMxwELAkAgAS0AAEEJaw4ERwAARwALQfMAIQIMrQELIAEgBEcEQCADQRA2AgggAyABNgIEQfEAIQIMrQELQYoBIQIMxQELAkAgASAERwRAA0AgAS0AAEGg0ABqLQAAIgBBA0cEQAJAIABBAWsOAkkABAtB8AAhAgyvAQsgBCABQQFqIgFHDQALQYgBIQIMxgELQYgBIQIMxQELIANBADYCHCADIAE2AhQgA0HbIDYCECADQQc2AgxBACECDMQBCyABIARGBEBBiQEhAgzEAQsCQAJAAkAgAS0AAEGg0gBqLQAAQQFrDgNGAgABC0HyACECDKwBCyADQQA2AhwgAyABNgIUIANBtBI2AhAgA0EHNgIMQQAhAgzEAQtB6gAhAgyqAQsgASAERwRAIAFBAWohAUHvACECDKoBC0GHASECDMIBCyAEIAEiAEYEQEGGASECDMIBCyAALQAAIgFBL0YEQCAAQQFqIQFB7gAhAgypAQsgAUEJayICQRdLDQEgACEBQQEgAnRBm4CABHENQQwBCyAEIAEiAEYEQEGFASECDMEBCyAALQAAQS9HDQAgAEEBaiEBDAMLQQAhAiADQQA2AhwgAyAANgIUIANB2yA2AhAgA0EHNgIMDL8BCwJAAkACQAJAAkADQCABLQAAQaDOAGotAAAiAEEFRwRAAkACQCAAQQFrDghHBQYHCAAEAQgLQesAIQIMrQELIAFBAWohAUHtACECDKwBCyAEIAFBAWoiAUcNAAtBhAEhAgzDAQsgAUEBagwUCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNHiADQdsANgIcIAMgATYCFCADIAA2AgxBACECDMEBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNHiADQd0ANgIcIAMgATYCFCADIAA2AgxBACECDMABCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNHiADQfoANgIcIAMgATYCFCADIAA2AgxBACECDL8BCyADQQA2AhwgAyABNgIUIANB+Q82AhAgA0EHNgIMQQAhAgy+AQsgASAERgRAQYMBIQIMvgELAkAgAS0AAEGgzgBqLQAAQQFrDgg+BAUGAAgCAwcLIAFBAWohAQtBAyECDKMBCyABQQFqDA0LQQAhAiADQQA2AhwgA0HREjYCECADQQc2AgwgAyABQQFqNgIUDLoBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNFiADQdsANgIcIAMgATYCFCADIAA2AgxBACECDLkBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNFiADQd0ANgIcIAMgATYCFCADIAA2AgxBACECDLgBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNFiADQfoANgIcIAMgATYCFCADIAA2AgxBACECDLcBCyADQQA2AhwgAyABNgIUIANB+Q82AhAgA0EHNgIMQQAhAgy2AQtB7AAhAgycAQsgASAERgRAQYIBIQIMtQELIAFBAWoMAgsgASAERgRAQYEBIQIMtAELIAFBAWoMAQsgASAERg0BIAFBAWoLIQFBBCECDJgBC0GAASECDLABCwNAIAEtAABBoMwAai0AACIAQQJHBEAgAEEBRwRAQekAIQIMmQELDDELIAQgAUEBaiIBRw0AC0H/ACECDK8BCyABIARGBEBB/gAhAgyvAQsCQCABLQAAQQlrDjcvAwYvBAYGBgYGBgYGBgYGBgYGBgYGBgUGBgIGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYABgsgAUEBagshAUEFIQIMlAELIAFBAWoMBgsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQggA0HbADYCHCADIAE2AhQgAyAANgIMQQAhAgyrAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQggA0HdADYCHCADIAE2AhQgAyAANgIMQQAhAgyqAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQggA0H6ADYCHCADIAE2AhQgAyAANgIMQQAhAgypAQsgA0EANgIcIAMgATYCFCADQY0UNgIQIANBBzYCDEEAIQIMqAELAkACQAJAAkADQCABLQAAQaDKAGotAAAiAEEFRwRAAkAgAEEBaw4GLgMEBQYABgtB6AAhAgyUAQsgBCABQQFqIgFHDQALQf0AIQIMqwELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0HIANB2wA2AhwgAyABNgIUIAMgADYCDEEAIQIMqgELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0HIANB3QA2AhwgAyABNgIUIAMgADYCDEEAIQIMqQELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0HIANB+gA2AhwgAyABNgIUIAMgADYCDEEAIQIMqAELIANBADYCHCADIAE2AhQgA0HkCDYCECADQQc2AgxBACECDKcBCyABIARGDQEgAUEBagshAUEGIQIMjAELQfwAIQIMpAELAkACQAJAAkADQCABLQAAQaDIAGotAAAiAEEFRwRAIABBAWsOBCkCAwQFCyAEIAFBAWoiAUcNAAtB+wAhAgynAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQMgA0HbADYCHCADIAE2AhQgAyAANgIMQQAhAgymAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQMgA0HdADYCHCADIAE2AhQgAyAANgIMQQAhAgylAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQMgA0H6ADYCHCADIAE2AhQgAyAANgIMQQAhAgykAQsgA0EANgIcIAMgATYCFCADQbwKNgIQIANBBzYCDEEAIQIMowELQc8AIQIMiQELQdEAIQIMiAELQecAIQIMhwELIAEgBEYEQEH6ACECDKABCwJAIAEtAABBCWsOBCAAACAACyABQQFqIQFB5gAhAgyGAQsgASAERgRAQfkAIQIMnwELAkAgAS0AAEEJaw4EHwAAHwALQQAhAAJAIAMoAjgiAkUNACACKAI4IgJFDQAgAyACEQAAIQALIABFBEBB4gEhAgyGAQsgAEEVRwRAIANBADYCHCADIAE2AhQgA0HJDTYCECADQRo2AgxBACECDJ8BCyADQfgANgIcIAMgATYCFCADQeoaNgIQIANBFTYCDEEAIQIMngELIAEgBEcEQCADQQ02AgggAyABNgIEQeQAIQIMhQELQfcAIQIMnQELIAEgBEYEQEH2ACECDJ0BCwJAAkACQCABLQAAQcgAaw4LAAELCwsLCwsLCwILCyABQQFqIQFB3QAhAgyFAQsgAUEBaiEBQeAAIQIMhAELIAFBAWohAUHjACECDIMBC0H1ACECIAEgBEYNmwEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBtdUAai0AAEcNCCAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMnAELIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARArIgAEQCADQfQANgIcIAMgATYCFCADIAA2AgxBACECDJwBC0HiACECDIIBC0EAIQACQCADKAI4IgJFDQAgAigCNCICRQ0AIAMgAhEAACEACwJAIAAEQCAAQRVGDQEgA0EANgIcIAMgATYCFCADQeoNNgIQIANBJjYCDEEAIQIMnAELQeEAIQIMggELIANB8wA2AhwgAyABNgIUIANBgBs2AhAgA0EVNgIMQQAhAgyaAQsgAy0AKSIAQSNrQQtJDQkCQCAAQQZLDQBBASAAdEHKAHFFDQAMCgtBACECIANBADYCHCADIAE2AhQgA0HtCTYCECADQQg2AgwMmQELQfIAIQIgASAERg2YASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGz1QBqLQAARw0FIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyZAQsgAygCBCEAIANCADcDACADIAAgBkEBaiIBECsiAARAIANB8QA2AhwgAyABNgIUIAMgADYCDEEAIQIMmQELQd8AIQIMfwtBACEAAkAgAygCOCICRQ0AIAIoAjQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0HqDTYCECADQSY2AgxBACECDJkBC0HeACECDH8LIANB8AA2AhwgAyABNgIUIANBgBs2AhAgA0EVNgIMQQAhAgyXAQsgAy0AKUEhRg0GIANBADYCHCADIAE2AhQgA0GRCjYCECADQQg2AgxBACECDJYBC0HvACECIAEgBEYNlQEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBsNUAai0AAEcNAiAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMlgELIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARArIgBFDQIgA0HtADYCHCADIAE2AhQgAyAANgIMQQAhAgyVAQsgA0EANgIACyADKAIEIQAgA0EANgIEIAMgACABECsiAEUNgAEgA0HuADYCHCADIAE2AhQgAyAANgIMQQAhAgyTAQtB3AAhAgx5C0EAIQACQCADKAI4IgJFDQAgAigCNCICRQ0AIAMgAhEAACEACwJAIAAEQCAAQRVGDQEgA0EANgIcIAMgATYCFCADQeoNNgIQIANBJjYCDEEAIQIMkwELQdsAIQIMeQsgA0HsADYCHCADIAE2AhQgA0GAGzYCECADQRU2AgxBACECDJEBCyADLQApIgBBI0kNACAAQS5GDQAgA0EANgIcIAMgATYCFCADQckJNgIQIANBCDYCDEEAIQIMkAELQdoAIQIMdgsgASAERgRAQesAIQIMjwELAkAgAS0AAEEvRgRAIAFBAWohAQwBCyADQQA2AhwgAyABNgIUIANBsjg2AhAgA0EINgIMQQAhAgyPAQtB2QAhAgx1CyABIARHBEAgA0EONgIIIAMgATYCBEHYACECDHULQeoAIQIMjQELIAEgBEYEQEHpACECDI0BCyABLQAAQTBrIgBB/wFxQQpJBEAgAyAAOgAqIAFBAWohAUHXACECDHQLIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ16IANB6AA2AhwgAyABNgIUIAMgADYCDEEAIQIMjAELIAEgBEYEQEHnACECDIwBCwJAIAEtAABBLkYEQCABQQFqIQEMAQsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDXsgA0HmADYCHCADIAE2AhQgAyAANgIMQQAhAgyMAQtB1gAhAgxyCyABIARGBEBB5QAhAgyLAQtBACEAQQEhBUEBIQdBACECAkACQAJAAkACQAJ/AkACQAJAAkACQAJAAkAgAS0AAEEwaw4KCgkAAQIDBAUGCAsLQQIMBgtBAwwFC0EEDAQLQQUMAwtBBgwCC0EHDAELQQgLIQJBACEFQQAhBwwCC0EJIQJBASEAQQAhBUEAIQcMAQtBACEFQQEhAgsgAyACOgArIAFBAWohAQJAAkAgAy0ALkEQcQ0AAkACQAJAIAMtACoOAwEAAgQLIAdFDQMMAgsgAA0BDAILIAVFDQELIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ0CIANB4gA2AhwgAyABNgIUIAMgADYCDEEAIQIMjQELIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ19IANB4wA2AhwgAyABNgIUIAMgADYCDEEAIQIMjAELIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ17IANB5AA2AhwgAyABNgIUIAMgADYCDAyLAQtB1AAhAgxxCyADLQApQSJGDYYBQdMAIQIMcAtBACEAAkAgAygCOCICRQ0AIAIoAkQiAkUNACADIAIRAAAhAAsgAEUEQEHVACECDHALIABBFUcEQCADQQA2AhwgAyABNgIUIANBpA02AhAgA0EhNgIMQQAhAgyJAQsgA0HhADYCHCADIAE2AhQgA0HQGjYCECADQRU2AgxBACECDIgBCyABIARGBEBB4AAhAgyIAQsCQAJAAkACQAJAIAEtAABBCmsOBAEEBAAECyABQQFqIQEMAQsgAUEBaiEBIANBL2otAABBAXFFDQELQdIAIQIMcAsgA0EANgIcIAMgATYCFCADQbYRNgIQIANBCTYCDEEAIQIMiAELIANBADYCHCADIAE2AhQgA0G2ETYCECADQQk2AgxBACECDIcBCyABIARGBEBB3wAhAgyHAQsgAS0AAEEKRgRAIAFBAWohAQwJCyADLQAuQcAAcQ0IIANBADYCHCADIAE2AhQgA0G2ETYCECADQQI2AgxBACECDIYBCyABIARGBEBB3QAhAgyGAQsgAS0AACICQQ1GBEAgAUEBaiEBQdAAIQIMbQsgASEAIAJBCWsOBAUBAQUBCyAEIAEiAEYEQEHcACECDIUBCyAALQAAQQpHDQAgAEEBagwCC0EAIQIgA0EANgIcIAMgADYCFCADQcotNgIQIANBBzYCDAyDAQsgASAERgRAQdsAIQIMgwELAkAgAS0AAEEJaw4EAwAAAwALIAFBAWoLIQFBzgAhAgxoCyABIARGBEBB2gAhAgyBAQsgAS0AAEEJaw4EAAEBAAELQQAhAiADQQA2AhwgA0GaEjYCECADQQc2AgwgAyABQQFqNgIUDH8LIANBgBI7ASpBACEAAkAgAygCOCICRQ0AIAIoAjgiAkUNACADIAIRAAAhAAsgAEUNACAAQRVHDQEgA0HZADYCHCADIAE2AhQgA0HqGjYCECADQRU2AgxBACECDH4LQc0AIQIMZAsgA0EANgIcIAMgATYCFCADQckNNgIQIANBGjYCDEEAIQIMfAsgASAERgRAQdkAIQIMfAsgAS0AAEEgRw09IAFBAWohASADLQAuQQFxDT0gA0EANgIcIAMgATYCFCADQcIcNgIQIANBHjYCDEEAIQIMewsgASAERgRAQdgAIQIMewsCQAJAAkACQAJAIAEtAAAiAEEKaw4EAgMDAAELIAFBAWohAUEsIQIMZQsgAEE6Rw0BIANBADYCHCADIAE2AhQgA0HnETYCECADQQo2AgxBACECDH0LIAFBAWohASADQS9qLQAAQQFxRQ1zIAMtADJBgAFxRQRAIANBMmohAiADEDVBACEAAkAgAygCOCIGRQ0AIAYoAigiBkUNACADIAYRAAAhAAsCQAJAIAAOFk1MSwEBAQEBAQEBAQEBAQEBAQEBAQABCyADQSk2AhwgAyABNgIUIANBrBk2AhAgA0EVNgIMQQAhAgx+CyADQQA2AhwgAyABNgIUIANB5Qs2AhAgA0ERNgIMQQAhAgx9C0EAIQACQCADKAI4IgJFDQAgAigCXCICRQ0AIAMgAhEAACEACyAARQ1ZIABBFUcNASADQQU2AhwgAyABNgIUIANBmxs2AhAgA0EVNgIMQQAhAgx8C0HLACECDGILQQAhAiADQQA2AhwgAyABNgIUIANBkA42AhAgA0EUNgIMDHoLIAMgAy8BMkGAAXI7ATIMOwsgASAERwRAIANBETYCCCADIAE2AgRBygAhAgxgC0HXACECDHgLIAEgBEYEQEHWACECDHgLAkACQAJAAkAgAS0AACIAQSByIAAgAEHBAGtB/wFxQRpJG0H/AXFB4wBrDhMAQEBAQEBAQEBAQEBAAUBAQAIDQAsgAUEBaiEBQcYAIQIMYQsgAUEBaiEBQccAIQIMYAsgAUEBaiEBQcgAIQIMXwsgAUEBaiEBQckAIQIMXgtB1QAhAiAEIAEiAEYNdiAEIAFrIAMoAgAiAWohBiAAIAFrQQVqIQcDQCABQZDIAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQhBBCABQQVGDQoaIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADHYLQdQAIQIgBCABIgBGDXUgBCABayADKAIAIgFqIQYgACABa0EPaiEHA0AgAUGAyABqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0HQQMgAUEPRg0JGiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAx1C0HTACECIAQgASIARg10IAQgAWsgAygCACIBaiEGIAAgAWtBDmohBwNAIAFB4scAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNBiABQQ5GDQcgAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMdAtB0gAhAiAEIAEiAEYNcyAEIAFrIAMoAgAiAWohBSAAIAFrQQFqIQYDQCABQeDHAGotAAAgAC0AACIHQSByIAcgB0HBAGtB/wFxQRpJG0H/AXFHDQUgAUEBRg0CIAFBAWohASAEIABBAWoiAEcNAAsgAyAFNgIADHMLIAEgBEYEQEHRACECDHMLAkACQCABLQAAIgBBIHIgACAAQcEAa0H/AXFBGkkbQf8BcUHuAGsOBwA5OTk5OQE5CyABQQFqIQFBwwAhAgxaCyABQQFqIQFBxAAhAgxZCyADQQA2AgAgBkEBaiEBQcUAIQIMWAtB0AAhAiAEIAEiAEYNcCAEIAFrIAMoAgAiAWohBiAAIAFrQQlqIQcDQCABQdbHAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQJBAiABQQlGDQQaIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADHALQc8AIQIgBCABIgBGDW8gBCABayADKAIAIgFqIQYgACABa0EFaiEHA0AgAUHQxwBqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0BIAFBBUYNAiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAxvCyAAIQEgA0EANgIADDMLQQELOgAsIANBADYCACAHQQFqIQELQS0hAgxSCwJAA0AgAS0AAEHQxQBqLQAAQQFHDQEgBCABQQFqIgFHDQALQc0AIQIMawtBwgAhAgxRCyABIARGBEBBzAAhAgxqCyABLQAAQTpGBEAgAygCBCEAIANBADYCBCADIAAgARAwIgBFDTMgA0HLADYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgxqCyADQQA2AhwgAyABNgIUIANB5xE2AhAgA0EKNgIMQQAhAgxpCwJAAkAgAy0ALEECaw4CAAEnCyADQTNqLQAAQQJxRQ0mIAMtAC5BAnENJiADQQA2AhwgAyABNgIUIANBphQ2AhAgA0ELNgIMQQAhAgxpCyADLQAyQSBxRQ0lIAMtAC5BAnENJSADQQA2AhwgAyABNgIUIANBvRM2AhAgA0EPNgIMQQAhAgxoC0EAIQACQCADKAI4IgJFDQAgAigCSCICRQ0AIAMgAhEAACEACyAARQRAQcEAIQIMTwsgAEEVRwRAIANBADYCHCADIAE2AhQgA0GmDzYCECADQRw2AgxBACECDGgLIANBygA2AhwgAyABNgIUIANBhRw2AhAgA0EVNgIMQQAhAgxnCyABIARHBEAgASECA0AgBCACIgFrQRBOBEAgAUEQaiEC/Qz/////////////////////IAH9AAAAIg1BB/1sIA39DODg4ODg4ODg4ODg4ODg4OD9bv0MX19fX19fX19fX19fX19fX/0mIA39DAkJCQkJCQkJCQkJCQkJCQn9I/1Q/VL9ZEF/c2giAEEQRg0BIAAgAWohAQwYCyABIARGBEBBxAAhAgxpCyABLQAAQcDBAGotAABBAUcNFyAEIAFBAWoiAkcNAAtBxAAhAgxnC0HEACECDGYLIAEgBEcEQANAAkAgAS0AACIAQSByIAAgAEHBAGtB/wFxQRpJG0H/AXEiAEEJRg0AIABBIEYNAAJAAkACQAJAIABB4wBrDhMAAwMDAwMDAwEDAwMDAwMDAwMCAwsgAUEBaiEBQTYhAgxSCyABQQFqIQFBNyECDFELIAFBAWohAUE4IQIMUAsMFQsgBCABQQFqIgFHDQALQTwhAgxmC0E8IQIMZQsgASAERgRAQcgAIQIMZQsgA0ESNgIIIAMgATYCBAJAAkACQAJAAkAgAy0ALEEBaw4EFAABAgkLIAMtADJBIHENA0HgASECDE8LAkAgAy8BMiIAQQhxRQ0AIAMtAChBAUcNACADLQAuQQhxRQ0CCyADIABB9/sDcUGABHI7ATIMCwsgAyADLwEyQRByOwEyDAQLIANBADYCBCADIAEgARAxIgAEQCADQcEANgIcIAMgADYCDCADIAFBAWo2AhRBACECDGYLIAFBAWohAQxYCyADQQA2AhwgAyABNgIUIANB9BM2AhAgA0EENgIMQQAhAgxkC0HHACECIAEgBEYNYyADKAIAIgAgBCABa2ohBSABIABrQQZqIQYCQANAIABBwMUAai0AACABLQAAQSByRw0BIABBBkYNSiAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAxkCyADQQA2AgAMBQsCQCABIARHBEADQCABLQAAQcDDAGotAAAiAEEBRwRAIABBAkcNAyABQQFqIQEMBQsgBCABQQFqIgFHDQALQcUAIQIMZAtBxQAhAgxjCwsgA0EAOgAsDAELQQshAgxHC0E/IQIMRgsCQAJAA0AgAS0AACIAQSBHBEACQCAAQQprDgQDBQUDAAsgAEEsRg0DDAQLIAQgAUEBaiIBRw0AC0HGACECDGALIANBCDoALAwOCyADLQAoQQFHDQIgAy0ALkEIcQ0CIAMoAgQhACADQQA2AgQgAyAAIAEQMSIABEAgA0HCADYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgxfCyABQQFqIQEMUAtBOyECDEQLAkADQCABLQAAIgBBIEcgAEEJR3ENASAEIAFBAWoiAUcNAAtBwwAhAgxdCwtBPCECDEILAkACQCABIARHBEADQCABLQAAIgBBIEcEQCAAQQprDgQDBAQDBAsgBCABQQFqIgFHDQALQT8hAgxdC0E/IQIMXAsgAyADLwEyQSByOwEyDAoLIAMoAgQhACADQQA2AgQgAyAAIAEQMSIARQ1OIANBPjYCHCADIAE2AhQgAyAANgIMQQAhAgxaCwJAIAEgBEcEQANAIAEtAABBwMMAai0AACIAQQFHBEAgAEECRg0DDAwLIAQgAUEBaiIBRw0AC0E3IQIMWwtBNyECDFoLIAFBAWohAQwEC0E7IQIgBCABIgBGDVggBCABayADKAIAIgFqIQYgACABa0EFaiEHAkADQCABQZDIAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQEgAUEFRgRAQQchAQw/CyABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAxZCyADQQA2AgAgACEBDAULQTohAiAEIAEiAEYNVyAEIAFrIAMoAgAiAWohBiAAIAFrQQhqIQcCQANAIAFBtMEAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNASABQQhGBEBBBSEBDD4LIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADFgLIANBADYCACAAIQEMBAtBOSECIAQgASIARg1WIAQgAWsgAygCACIBaiEGIAAgAWtBA2ohBwJAA0AgAUGwwQBqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0BIAFBA0YEQEEGIQEMPQsgAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMVwsgA0EANgIAIAAhAQwDCwJAA0AgAS0AACIAQSBHBEAgAEEKaw4EBwQEBwILIAQgAUEBaiIBRw0AC0E4IQIMVgsgAEEsRw0BIAFBAWohAEEBIQECQAJAAkACQAJAIAMtACxBBWsOBAMBAgQACyAAIQEMBAtBAiEBDAELQQQhAQsgA0EBOgAsIAMgAy8BMiABcjsBMiAAIQEMAQsgAyADLwEyQQhyOwEyIAAhAQtBPiECDDsLIANBADoALAtBOSECDDkLIAEgBEYEQEE2IQIMUgsCQAJAAkACQAJAIAEtAABBCmsOBAACAgECCyADKAIEIQAgA0EANgIEIAMgACABEDEiAEUNAiADQTM2AhwgAyABNgIUIAMgADYCDEEAIQIMVQsgAygCBCEAIANBADYCBCADIAAgARAxIgBFBEAgAUEBaiEBDAYLIANBMjYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgxUCyADLQAuQQFxBEBB3wEhAgw7CyADKAIEIQAgA0EANgIEIAMgACABEDEiAA0BDEkLQTQhAgw5CyADQTU2AhwgAyABNgIUIAMgADYCDEEAIQIMUQtBNSECDDcLIANBL2otAABBAXENACADQQA2AhwgAyABNgIUIANB6xY2AhAgA0EZNgIMQQAhAgxPC0EzIQIMNQsgASAERgRAQTIhAgxOCwJAIAEtAABBCkYEQCABQQFqIQEMAQsgA0EANgIcIAMgATYCFCADQZIXNgIQIANBAzYCDEEAIQIMTgtBMiECDDQLIAEgBEYEQEExIQIMTQsCQCABLQAAIgBBCUYNACAAQSBGDQBBASECAkAgAy0ALEEFaw4EBgQFAA0LIAMgAy8BMkEIcjsBMgwMCyADLQAuQQFxRQ0BIAMtACxBCEcNACADQQA6ACwLQT0hAgwyCyADQQA2AhwgAyABNgIUIANBwhY2AhAgA0EKNgIMQQAhAgxKC0ECIQIMAQtBBCECCyADQQE6ACwgAyADLwEyIAJyOwEyDAYLIAEgBEYEQEEwIQIMRwsgAS0AAEEKRgRAIAFBAWohAQwBCyADLQAuQQFxDQAgA0EANgIcIAMgATYCFCADQdwoNgIQIANBAjYCDEEAIQIMRgtBMCECDCwLIAFBAWohAUExIQIMKwsgASAERgRAQS8hAgxECyABLQAAIgBBCUcgAEEgR3FFBEAgAUEBaiEBIAMtAC5BAXENASADQQA2AhwgAyABNgIUIANBlxA2AhAgA0EKNgIMQQAhAgxEC0EBIQICQAJAAkACQAJAAkAgAy0ALEECaw4HBQQEAwECAAQLIAMgAy8BMkEIcjsBMgwDC0ECIQIMAQtBBCECCyADQQE6ACwgAyADLwEyIAJyOwEyC0EvIQIMKwsgA0EANgIcIAMgATYCFCADQYQTNgIQIANBCzYCDEEAIQIMQwtB4QEhAgwpCyABIARGBEBBLiECDEILIANBADYCBCADQRI2AgggAyABIAEQMSIADQELQS4hAgwnCyADQS02AhwgAyABNgIUIAMgADYCDEEAIQIMPwtBACEAAkAgAygCOCICRQ0AIAIoAkwiAkUNACADIAIRAAAhAAsgAEUNACAAQRVHDQEgA0HYADYCHCADIAE2AhQgA0GzGzYCECADQRU2AgxBACECDD4LQcwAIQIMJAsgA0EANgIcIAMgATYCFCADQbMONgIQIANBHTYCDEEAIQIMPAsgASAERgRAQc4AIQIMPAsgAS0AACIAQSBGDQIgAEE6Rg0BCyADQQA6ACxBCSECDCELIAMoAgQhACADQQA2AgQgAyAAIAEQMCIADQEMAgsgAy0ALkEBcQRAQd4BIQIMIAsgAygCBCEAIANBADYCBCADIAAgARAwIgBFDQIgA0EqNgIcIAMgADYCDCADIAFBAWo2AhRBACECDDgLIANBywA2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMNwsgAUEBaiEBQcAAIQIMHQsgAUEBaiEBDCwLIAEgBEYEQEErIQIMNQsCQCABLQAAQQpGBEAgAUEBaiEBDAELIAMtAC5BwABxRQ0GCyADLQAyQYABcQRAQQAhAAJAIAMoAjgiAkUNACACKAJcIgJFDQAgAyACEQAAIQALIABFDRIgAEEVRgRAIANBBTYCHCADIAE2AhQgA0GbGzYCECADQRU2AgxBACECDDYLIANBADYCHCADIAE2AhQgA0GQDjYCECADQRQ2AgxBACECDDULIANBMmohAiADEDVBACEAAkAgAygCOCIGRQ0AIAYoAigiBkUNACADIAYRAAAhAAsgAA4WAgEABAQEBAQEBAQEBAQEBAQEBAQEAwQLIANBAToAMAsgAiACLwEAQcAAcjsBAAtBKyECDBgLIANBKTYCHCADIAE2AhQgA0GsGTYCECADQRU2AgxBACECDDALIANBADYCHCADIAE2AhQgA0HlCzYCECADQRE2AgxBACECDC8LIANBADYCHCADIAE2AhQgA0GlCzYCECADQQI2AgxBACECDC4LQQEhByADLwEyIgVBCHFFBEAgAykDIEIAUiEHCwJAIAMtADAEQEEBIQAgAy0AKUEFRg0BIAVBwABxRSAHcUUNAQsCQCADLQAoIgJBAkYEQEEBIQAgAy8BNCIGQeUARg0CQQAhACAFQcAAcQ0CIAZB5ABGDQIgBkHmAGtBAkkNAiAGQcwBRg0CIAZBsAJGDQIMAQtBACEAIAVBwABxDQELQQIhACAFQQhxDQAgBUGABHEEQAJAIAJBAUcNACADLQAuQQpxDQBBBSEADAILQQQhAAwBCyAFQSBxRQRAIAMQNkEAR0ECdCEADAELQQBBAyADKQMgUBshAAsgAEEBaw4FAgAHAQMEC0ERIQIMEwsgA0EBOgAxDCkLQQAhAgJAIAMoAjgiAEUNACAAKAIwIgBFDQAgAyAAEQAAIQILIAJFDSYgAkEVRgRAIANBAzYCHCADIAE2AhQgA0HSGzYCECADQRU2AgxBACECDCsLQQAhAiADQQA2AhwgAyABNgIUIANB3Q42AhAgA0ESNgIMDCoLIANBADYCHCADIAE2AhQgA0H5IDYCECADQQ82AgxBACECDCkLQQAhAAJAIAMoAjgiAkUNACACKAIwIgJFDQAgAyACEQAAIQALIAANAQtBDiECDA4LIABBFUYEQCADQQI2AhwgAyABNgIUIANB0hs2AhAgA0EVNgIMQQAhAgwnCyADQQA2AhwgAyABNgIUIANB3Q42AhAgA0ESNgIMQQAhAgwmC0EqIQIMDAsgASAERwRAIANBCTYCCCADIAE2AgRBKSECDAwLQSYhAgwkCyADIAMpAyAiDCAEIAFrrSIKfSILQgAgCyAMWBs3AyAgCiAMVARAQSUhAgwkCyADKAIEIQAgA0EANgIEIAMgACABIAynaiIBEDIiAEUNACADQQU2AhwgAyABNgIUIAMgADYCDEEAIQIMIwtBDyECDAkLQgAhCgJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCABLQAAQTBrDjcXFgABAgMEBQYHFBQUFBQUFAgJCgsMDRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUDg8QERITFAtCAiEKDBYLQgMhCgwVC0IEIQoMFAtCBSEKDBMLQgYhCgwSC0IHIQoMEQtCCCEKDBALQgkhCgwPC0IKIQoMDgtCCyEKDA0LQgwhCgwMC0INIQoMCwtCDiEKDAoLQg8hCgwJC0IKIQoMCAtCCyEKDAcLQgwhCgwGC0INIQoMBQtCDiEKDAQLQg8hCgwDCyADQQA2AhwgAyABNgIUIANBnxU2AhAgA0EMNgIMQQAhAgwhCyABIARGBEBBIiECDCELQgAhCgJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAS0AAEEwaw43FRQAAQIDBAUGBxYWFhYWFhYICQoLDA0WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFg4PEBESExYLQgIhCgwUC0IDIQoMEwtCBCEKDBILQgUhCgwRC0IGIQoMEAtCByEKDA8LQgghCgwOC0IJIQoMDQtCCiEKDAwLQgshCgwLC0IMIQoMCgtCDSEKDAkLQg4hCgwIC0IPIQoMBwtCCiEKDAYLQgshCgwFC0IMIQoMBAtCDSEKDAMLQg4hCgwCC0IPIQoMAQtCASEKCyABQQFqIQEgAykDICILQv//////////D1gEQCADIAtCBIYgCoQ3AyAMAgsgA0EANgIcIAMgATYCFCADQbUJNgIQIANBDDYCDEEAIQIMHgtBJyECDAQLQSghAgwDCyADIAE6ACwgA0EANgIAIAdBAWohAUEMIQIMAgsgA0EANgIAIAZBAWohAUEKIQIMAQsgAUEBaiEBQQghAgwACwALQQAhAiADQQA2AhwgAyABNgIUIANBsjg2AhAgA0EINgIMDBcLQQAhAiADQQA2AhwgAyABNgIUIANBgxE2AhAgA0EJNgIMDBYLQQAhAiADQQA2AhwgAyABNgIUIANB3wo2AhAgA0EJNgIMDBULQQAhAiADQQA2AhwgAyABNgIUIANB7RA2AhAgA0EJNgIMDBQLQQAhAiADQQA2AhwgAyABNgIUIANB0hE2AhAgA0EJNgIMDBMLQQAhAiADQQA2AhwgAyABNgIUIANBsjg2AhAgA0EINgIMDBILQQAhAiADQQA2AhwgAyABNgIUIANBgxE2AhAgA0EJNgIMDBELQQAhAiADQQA2AhwgAyABNgIUIANB3wo2AhAgA0EJNgIMDBALQQAhAiADQQA2AhwgAyABNgIUIANB7RA2AhAgA0EJNgIMDA8LQQAhAiADQQA2AhwgAyABNgIUIANB0hE2AhAgA0EJNgIMDA4LQQAhAiADQQA2AhwgAyABNgIUIANBuRc2AhAgA0EPNgIMDA0LQQAhAiADQQA2AhwgAyABNgIUIANBuRc2AhAgA0EPNgIMDAwLQQAhAiADQQA2AhwgAyABNgIUIANBmRM2AhAgA0ELNgIMDAsLQQAhAiADQQA2AhwgAyABNgIUIANBnQk2AhAgA0ELNgIMDAoLQQAhAiADQQA2AhwgAyABNgIUIANBlxA2AhAgA0EKNgIMDAkLQQAhAiADQQA2AhwgAyABNgIUIANBsRA2AhAgA0EKNgIMDAgLQQAhAiADQQA2AhwgAyABNgIUIANBux02AhAgA0ECNgIMDAcLQQAhAiADQQA2AhwgAyABNgIUIANBlhY2AhAgA0ECNgIMDAYLQQAhAiADQQA2AhwgAyABNgIUIANB+Rg2AhAgA0ECNgIMDAULQQAhAiADQQA2AhwgAyABNgIUIANBxBg2AhAgA0ECNgIMDAQLIANBAjYCHCADIAE2AhQgA0GpHjYCECADQRY2AgxBACECDAMLQd4AIQIgASAERg0CIAlBCGohByADKAIAIQUCQAJAIAEgBEcEQCAFQZbIAGohCCAEIAVqIAFrIQYgBUF/c0EKaiIFIAFqIQADQCABLQAAIAgtAABHBEBBAiEIDAMLIAVFBEBBACEIIAAhAQwDCyAFQQFrIQUgCEEBaiEIIAQgAUEBaiIBRw0ACyAGIQUgBCEBCyAHQQE2AgAgAyAFNgIADAELIANBADYCACAHIAg2AgALIAcgATYCBCAJKAIMIQACQAJAIAkoAghBAWsOAgQBAAsgA0EANgIcIANBwh42AhAgA0EXNgIMIAMgAEEBajYCFEEAIQIMAwsgA0EANgIcIAMgADYCFCADQdceNgIQIANBCTYCDEEAIQIMAgsgASAERgRAQSghAgwCCyADQQk2AgggAyABNgIEQSchAgwBCyABIARGBEBBASECDAELA0ACQAJAAkAgAS0AAEEKaw4EAAEBAAELIAFBAWohAQwBCyABQQFqIQEgAy0ALkEgcQ0AQQAhAiADQQA2AhwgAyABNgIUIANBoSE2AhAgA0EFNgIMDAILQQEhAiABIARHDQALCyAJQRBqJAAgAkUEQCADKAIMIQAMAQsgAyACNgIcQQAhACADKAIEIgFFDQAgAyABIAQgAygCCBEBACIBRQ0AIAMgBDYCFCADIAE2AgwgASEACyAAC74CAQJ/IABBADoAACAAQeQAaiIBQQFrQQA6AAAgAEEAOgACIABBADoAASABQQNrQQA6AAAgAUECa0EAOgAAIABBADoAAyABQQRrQQA6AABBACAAa0EDcSIBIABqIgBBADYCAEHkACABa0F8cSICIABqIgFBBGtBADYCAAJAIAJBCUkNACAAQQA2AgggAEEANgIEIAFBCGtBADYCACABQQxrQQA2AgAgAkEZSQ0AIABBADYCGCAAQQA2AhQgAEEANgIQIABBADYCDCABQRBrQQA2AgAgAUEUa0EANgIAIAFBGGtBADYCACABQRxrQQA2AgAgAiAAQQRxQRhyIgJrIgFBIEkNACAAIAJqIQADQCAAQgA3AxggAEIANwMQIABCADcDCCAAQgA3AwAgAEEgaiEAIAFBIGsiAUEfSw0ACwsLVgEBfwJAIAAoAgwNAAJAAkACQAJAIAAtADEOAwEAAwILIAAoAjgiAUUNACABKAIwIgFFDQAgACABEQAAIgENAwtBAA8LAAsgAEHKGTYCEEEOIQELIAELGgAgACgCDEUEQCAAQd4fNgIQIABBFTYCDAsLFAAgACgCDEEVRgRAIABBADYCDAsLFAAgACgCDEEWRgRAIABBADYCDAsLBwAgACgCDAsHACAAKAIQCwkAIAAgATYCEAsHACAAKAIUCysAAkAgAEEnTw0AQv//////CSAArYhCAYNQDQAgAEECdEHQOGooAgAPCwALFwAgAEEvTwRAAAsgAEECdEHsOWooAgALvwkBAX9B9C0hAQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIABB5ABrDvQDY2IAAWFhYWFhYQIDBAVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhBgcICQoLDA0OD2FhYWFhEGFhYWFhYWFhYWFhEWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYRITFBUWFxgZGhthYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2YTc4OTphYWFhYWFhYTthYWE8YWFhYT0+P2FhYWFhYWFhQGFhQWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYUJDREVGR0hJSktMTU5PUFFSU2FhYWFhYWFhVFVWV1hZWlthXF1hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFeYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhX2BhC0HqLA8LQZgmDwtB7TEPC0GgNw8LQckpDwtBtCkPC0GWLQ8LQesrDwtBojUPC0HbNA8LQeApDwtB4yQPC0HVJA8LQe4kDwtB5iUPC0HKNA8LQdA3DwtBqjUPC0H1LA8LQfYmDwtBgiIPC0HyMw8LQb4oDwtB5zcPC0HNIQ8LQcAhDwtBuCUPC0HLJQ8LQZYkDwtBjzQPC0HNNQ8LQd0qDwtB7jMPC0GcNA8LQZ4xDwtB9DUPC0HlIg8LQa8lDwtBmTEPC0GyNg8LQfk2DwtBxDIPC0HdLA8LQYIxDwtBwTEPC0GNNw8LQckkDwtB7DYPC0HnKg8LQcgjDwtB4iEPC0HJNw8LQaUiDwtBlCIPC0HbNg8LQd41DwtBhiYPC0G8Kw8LQYsyDwtBoCMPC0H2MA8LQYAsDwtBiSsPC0GkJg8LQfIjDwtBgSgPC0GrMg8LQesnDwtBwjYPC0GiJA8LQc8qDwtB3CMPC0GHJw8LQeQ0DwtBtyIPC0GtMQ8LQdUiDwtBrzQPC0HeJg8LQdYyDwtB9DQPC0GBOA8LQfQ3DwtBkjYPC0GdJw8LQYIpDwtBjSMPC0HXMQ8LQb01DwtBtDcPC0HYMA8LQbYnDwtBmjgPC0GnKg8LQcQnDwtBriMPC0H1Ig8LAAtByiYhAQsgAQsXACAAIAAvAS5B/v8DcSABQQBHcjsBLgsaACAAIAAvAS5B/f8DcSABQQBHQQF0cjsBLgsaACAAIAAvAS5B+/8DcSABQQBHQQJ0cjsBLgsaACAAIAAvAS5B9/8DcSABQQBHQQN0cjsBLgsaACAAIAAvAS5B7/8DcSABQQBHQQR0cjsBLgsaACAAIAAvAS5B3/8DcSABQQBHQQV0cjsBLgsaACAAIAAvAS5Bv/8DcSABQQBHQQZ0cjsBLgsaACAAIAAvAS5B//4DcSABQQBHQQd0cjsBLgsaACAAIAAvAS5B//0DcSABQQBHQQh0cjsBLgsaACAAIAAvAS5B//sDcSABQQBHQQl0cjsBLgs+AQJ/AkAgACgCOCIDRQ0AIAMoAgQiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQeESNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAggiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQfwRNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAgwiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQewKNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAhAiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQfoeNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAhQiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQcsQNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAhgiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQbcfNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAhwiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQb8VNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAiwiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQf4INgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAiAiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQYwdNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAiQiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQeYVNgIQQRghBAsgBAs4ACAAAn8gAC8BMkEUcUEURgRAQQEgAC0AKEEBRg0BGiAALwE0QeUARgwBCyAALQApQQVGCzoAMAtZAQJ/AkAgAC0AKEEBRg0AIAAvATQiAUHkAGtB5ABJDQAgAUHMAUYNACABQbACRg0AIAAvATIiAEHAAHENAEEBIQIgAEGIBHFBgARGDQAgAEEocUUhAgsgAguMAQECfwJAAkACQCAALQAqRQ0AIAAtACtFDQAgAC8BMiIBQQJxRQ0BDAILIAAvATIiAUEBcUUNAQtBASECIAAtAChBAUYNACAALwE0IgBB5ABrQeQASQ0AIABBzAFGDQAgAEGwAkYNACABQcAAcQ0AQQAhAiABQYgEcUGABEYNACABQShxQQBHIQILIAILcwAgAEEQav0MAAAAAAAAAAAAAAAAAAAAAP0LAwAgAP0MAAAAAAAAAAAAAAAAAAAAAP0LAwAgAEEwav0MAAAAAAAAAAAAAAAAAAAAAP0LAwAgAEEgav0MAAAAAAAAAAAAAAAAAAAAAP0LAwAgAEH9ATYCHAsGACAAEDoLmi0BC38jAEEQayIKJABB3NUAKAIAIglFBEBBnNkAKAIAIgVFBEBBqNkAQn83AgBBoNkAQoCAhICAgMAANwIAQZzZACAKQQhqQXBxQdiq1aoFcyIFNgIAQbDZAEEANgIAQYDZAEEANgIAC0GE2QBBwNkENgIAQdTVAEHA2QQ2AgBB6NUAIAU2AgBB5NUAQX82AgBBiNkAQcCmAzYCAANAIAFBgNYAaiABQfTVAGoiAjYCACACIAFB7NUAaiIDNgIAIAFB+NUAaiADNgIAIAFBiNYAaiABQfzVAGoiAzYCACADIAI2AgAgAUGQ1gBqIAFBhNYAaiICNgIAIAIgAzYCACABQYzWAGogAjYCACABQSBqIgFBgAJHDQALQczZBEGBpgM2AgBB4NUAQazZACgCADYCAEHQ1QBBgKYDNgIAQdzVAEHI2QQ2AgBBzP8HQTg2AgBByNkEIQkLAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAEHsAU0EQEHE1QAoAgAiBkEQIABBE2pBcHEgAEELSRsiBEEDdiIAdiIBQQNxBEACQCABQQFxIAByQQFzIgJBA3QiAEHs1QBqIgEgAEH01QBqKAIAIgAoAggiA0YEQEHE1QAgBkF+IAJ3cTYCAAwBCyABIAM2AgggAyABNgIMCyAAQQhqIQEgACACQQN0IgJBA3I2AgQgACACaiIAIAAoAgRBAXI2AgQMEQtBzNUAKAIAIgggBE8NASABBEACQEECIAB0IgJBACACa3IgASAAdHFoIgBBA3QiAkHs1QBqIgEgAkH01QBqKAIAIgIoAggiA0YEQEHE1QAgBkF+IAB3cSIGNgIADAELIAEgAzYCCCADIAE2AgwLIAIgBEEDcjYCBCAAQQN0IgAgBGshBSAAIAJqIAU2AgAgAiAEaiIEIAVBAXI2AgQgCARAIAhBeHFB7NUAaiEAQdjVACgCACEDAn9BASAIQQN2dCIBIAZxRQRAQcTVACABIAZyNgIAIAAMAQsgACgCCAsiASADNgIMIAAgAzYCCCADIAA2AgwgAyABNgIICyACQQhqIQFB2NUAIAQ2AgBBzNUAIAU2AgAMEQtByNUAKAIAIgtFDQEgC2hBAnRB9NcAaigCACIAKAIEQXhxIARrIQUgACECA0ACQCACKAIQIgFFBEAgAkEUaigCACIBRQ0BCyABKAIEQXhxIARrIgMgBUkhAiADIAUgAhshBSABIAAgAhshACABIQIMAQsLIAAoAhghCSAAKAIMIgMgAEcEQEHU1QAoAgAaIAMgACgCCCIBNgIIIAEgAzYCDAwQCyAAQRRqIgIoAgAiAUUEQCAAKAIQIgFFDQMgAEEQaiECCwNAIAIhByABIgNBFGoiAigCACIBDQAgA0EQaiECIAMoAhAiAQ0ACyAHQQA2AgAMDwtBfyEEIABBv39LDQAgAEETaiIBQXBxIQRByNUAKAIAIghFDQBBACAEayEFAkACQAJAAn9BACAEQYACSQ0AGkEfIARB////B0sNABogBEEmIAFBCHZnIgBrdkEBcSAAQQF0a0E+agsiBkECdEH01wBqKAIAIgJFBEBBACEBQQAhAwwBC0EAIQEgBEEZIAZBAXZrQQAgBkEfRxt0IQBBACEDA0ACQCACKAIEQXhxIARrIgcgBU8NACACIQMgByIFDQBBACEFIAIhAQwDCyABIAJBFGooAgAiByAHIAIgAEEddkEEcWpBEGooAgAiAkYbIAEgBxshASAAQQF0IQAgAg0ACwsgASADckUEQEEAIQNBAiAGdCIAQQAgAGtyIAhxIgBFDQMgAGhBAnRB9NcAaigCACEBCyABRQ0BCwNAIAEoAgRBeHEgBGsiAiAFSSEAIAIgBSAAGyEFIAEgAyAAGyEDIAEoAhAiAAR/IAAFIAFBFGooAgALIgENAAsLIANFDQAgBUHM1QAoAgAgBGtPDQAgAygCGCEHIAMgAygCDCIARwRAQdTVACgCABogACADKAIIIgE2AgggASAANgIMDA4LIANBFGoiAigCACIBRQRAIAMoAhAiAUUNAyADQRBqIQILA0AgAiEGIAEiAEEUaiICKAIAIgENACAAQRBqIQIgACgCECIBDQALIAZBADYCAAwNC0HM1QAoAgAiAyAETwRAQdjVACgCACEBAkAgAyAEayICQRBPBEAgASAEaiIAIAJBAXI2AgQgASADaiACNgIAIAEgBEEDcjYCBAwBCyABIANBA3I2AgQgASADaiIAIAAoAgRBAXI2AgRBACEAQQAhAgtBzNUAIAI2AgBB2NUAIAA2AgAgAUEIaiEBDA8LQdDVACgCACIDIARLBEAgBCAJaiIAIAMgBGsiAUEBcjYCBEHc1QAgADYCAEHQ1QAgATYCACAJIARBA3I2AgQgCUEIaiEBDA8LQQAhASAEAn9BnNkAKAIABEBBpNkAKAIADAELQajZAEJ/NwIAQaDZAEKAgISAgIDAADcCAEGc2QAgCkEMakFwcUHYqtWqBXM2AgBBsNkAQQA2AgBBgNkAQQA2AgBBgIAECyIAIARBxwBqIgVqIgZBACAAayIHcSICTwRAQbTZAEEwNgIADA8LAkBB/NgAKAIAIgFFDQBB9NgAKAIAIgggAmohACAAIAFNIAAgCEtxDQBBACEBQbTZAEEwNgIADA8LQYDZAC0AAEEEcQ0EAkACQCAJBEBBhNkAIQEDQCABKAIAIgAgCU0EQCAAIAEoAgRqIAlLDQMLIAEoAggiAQ0ACwtBABA7IgBBf0YNBSACIQZBoNkAKAIAIgFBAWsiAyAAcQRAIAIgAGsgACADakEAIAFrcWohBgsgBCAGTw0FIAZB/v///wdLDQVB/NgAKAIAIgMEQEH02AAoAgAiByAGaiEBIAEgB00NBiABIANLDQYLIAYQOyIBIABHDQEMBwsgBiADayAHcSIGQf7///8HSw0EIAYQOyEAIAAgASgCACABKAIEakYNAyAAIQELAkAgBiAEQcgAak8NACABQX9GDQBBpNkAKAIAIgAgBSAGa2pBACAAa3EiAEH+////B0sEQCABIQAMBwsgABA7QX9HBEAgACAGaiEGIAEhAAwHC0EAIAZrEDsaDAQLIAEiAEF/Rw0FDAMLQQAhAwwMC0EAIQAMCgsgAEF/Rw0CC0GA2QBBgNkAKAIAQQRyNgIACyACQf7///8HSw0BIAIQOyEAQQAQOyEBIABBf0YNASABQX9GDQEgACABTw0BIAEgAGsiBiAEQThqTQ0BC0H02ABB9NgAKAIAIAZqIgE2AgBB+NgAKAIAIAFJBEBB+NgAIAE2AgALAkACQAJAQdzVACgCACICBEBBhNkAIQEDQCAAIAEoAgAiAyABKAIEIgVqRg0CIAEoAggiAQ0ACwwCC0HU1QAoAgAiAUEARyAAIAFPcUUEQEHU1QAgADYCAAtBACEBQYjZACAGNgIAQYTZACAANgIAQeTVAEF/NgIAQejVAEGc2QAoAgA2AgBBkNkAQQA2AgADQCABQYDWAGogAUH01QBqIgI2AgAgAiABQezVAGoiAzYCACABQfjVAGogAzYCACABQYjWAGogAUH81QBqIgM2AgAgAyACNgIAIAFBkNYAaiABQYTWAGoiAjYCACACIAM2AgAgAUGM1gBqIAI2AgAgAUEgaiIBQYACRw0AC0F4IABrQQ9xIgEgAGoiAiAGQThrIgMgAWsiAUEBcjYCBEHg1QBBrNkAKAIANgIAQdDVACABNgIAQdzVACACNgIAIAAgA2pBODYCBAwCCyAAIAJNDQAgAiADSQ0AIAEoAgxBCHENAEF4IAJrQQ9xIgAgAmoiA0HQ1QAoAgAgBmoiByAAayIAQQFyNgIEIAEgBSAGajYCBEHg1QBBrNkAKAIANgIAQdDVACAANgIAQdzVACADNgIAIAIgB2pBODYCBAwBCyAAQdTVACgCAEkEQEHU1QAgADYCAAsgACAGaiEDQYTZACEBAkACQAJAA0AgAyABKAIARwRAIAEoAggiAQ0BDAILCyABLQAMQQhxRQ0BC0GE2QAhAQNAIAEoAgAiAyACTQRAIAMgASgCBGoiBSACSw0DCyABKAIIIQEMAAsACyABIAA2AgAgASABKAIEIAZqNgIEIABBeCAAa0EPcWoiCSAEQQNyNgIEIANBeCADa0EPcWoiBiAEIAlqIgRrIQEgAiAGRgRAQdzVACAENgIAQdDVAEHQ1QAoAgAgAWoiADYCACAEIABBAXI2AgQMCAtB2NUAKAIAIAZGBEBB2NUAIAQ2AgBBzNUAQczVACgCACABaiIANgIAIAQgAEEBcjYCBCAAIARqIAA2AgAMCAsgBigCBCIFQQNxQQFHDQYgBUF4cSEIIAVB/wFNBEAgBUEDdiEDIAYoAggiACAGKAIMIgJGBEBBxNUAQcTVACgCAEF+IAN3cTYCAAwHCyACIAA2AgggACACNgIMDAYLIAYoAhghByAGIAYoAgwiAEcEQCAAIAYoAggiAjYCCCACIAA2AgwMBQsgBkEUaiICKAIAIgVFBEAgBigCECIFRQ0EIAZBEGohAgsDQCACIQMgBSIAQRRqIgIoAgAiBQ0AIABBEGohAiAAKAIQIgUNAAsgA0EANgIADAQLQXggAGtBD3EiASAAaiIHIAZBOGsiAyABayIBQQFyNgIEIAAgA2pBODYCBCACIAVBNyAFa0EPcWpBP2siAyADIAJBEGpJGyIDQSM2AgRB4NUAQazZACgCADYCAEHQ1QAgATYCAEHc1QAgBzYCACADQRBqQYzZACkCADcCACADQYTZACkCADcCCEGM2QAgA0EIajYCAEGI2QAgBjYCAEGE2QAgADYCAEGQ2QBBADYCACADQSRqIQEDQCABQQc2AgAgBSABQQRqIgFLDQALIAIgA0YNACADIAMoAgRBfnE2AgQgAyADIAJrIgU2AgAgAiAFQQFyNgIEIAVB/wFNBEAgBUF4cUHs1QBqIQACf0HE1QAoAgAiAUEBIAVBA3Z0IgNxRQRAQcTVACABIANyNgIAIAAMAQsgACgCCAsiASACNgIMIAAgAjYCCCACIAA2AgwgAiABNgIIDAELQR8hASAFQf///wdNBEAgBUEmIAVBCHZnIgBrdkEBcSAAQQF0a0E+aiEBCyACIAE2AhwgAkIANwIQIAFBAnRB9NcAaiEAQcjVACgCACIDQQEgAXQiBnFFBEAgACACNgIAQcjVACADIAZyNgIAIAIgADYCGCACIAI2AgggAiACNgIMDAELIAVBGSABQQF2a0EAIAFBH0cbdCEBIAAoAgAhAwJAA0AgAyIAKAIEQXhxIAVGDQEgAUEddiEDIAFBAXQhASAAIANBBHFqQRBqIgYoAgAiAw0ACyAGIAI2AgAgAiAANgIYIAIgAjYCDCACIAI2AggMAQsgACgCCCIBIAI2AgwgACACNgIIIAJBADYCGCACIAA2AgwgAiABNgIIC0HQ1QAoAgAiASAETQ0AQdzVACgCACIAIARqIgIgASAEayIBQQFyNgIEQdDVACABNgIAQdzVACACNgIAIAAgBEEDcjYCBCAAQQhqIQEMCAtBACEBQbTZAEEwNgIADAcLQQAhAAsgB0UNAAJAIAYoAhwiAkECdEH01wBqIgMoAgAgBkYEQCADIAA2AgAgAA0BQcjVAEHI1QAoAgBBfiACd3E2AgAMAgsgB0EQQRQgBygCECAGRhtqIAA2AgAgAEUNAQsgACAHNgIYIAYoAhAiAgRAIAAgAjYCECACIAA2AhgLIAZBFGooAgAiAkUNACAAQRRqIAI2AgAgAiAANgIYCyABIAhqIQEgBiAIaiIGKAIEIQULIAYgBUF+cTYCBCABIARqIAE2AgAgBCABQQFyNgIEIAFB/wFNBEAgAUF4cUHs1QBqIQACf0HE1QAoAgAiAkEBIAFBA3Z0IgFxRQRAQcTVACABIAJyNgIAIAAMAQsgACgCCAsiASAENgIMIAAgBDYCCCAEIAA2AgwgBCABNgIIDAELQR8hBSABQf///wdNBEAgAUEmIAFBCHZnIgBrdkEBcSAAQQF0a0E+aiEFCyAEIAU2AhwgBEIANwIQIAVBAnRB9NcAaiEAQcjVACgCACICQQEgBXQiA3FFBEAgACAENgIAQcjVACACIANyNgIAIAQgADYCGCAEIAQ2AgggBCAENgIMDAELIAFBGSAFQQF2a0EAIAVBH0cbdCEFIAAoAgAhAAJAA0AgACICKAIEQXhxIAFGDQEgBUEddiEAIAVBAXQhBSACIABBBHFqQRBqIgMoAgAiAA0ACyADIAQ2AgAgBCACNgIYIAQgBDYCDCAEIAQ2AggMAQsgAigCCCIAIAQ2AgwgAiAENgIIIARBADYCGCAEIAI2AgwgBCAANgIICyAJQQhqIQEMAgsCQCAHRQ0AAkAgAygCHCIBQQJ0QfTXAGoiAigCACADRgRAIAIgADYCACAADQFByNUAIAhBfiABd3EiCDYCAAwCCyAHQRBBFCAHKAIQIANGG2ogADYCACAARQ0BCyAAIAc2AhggAygCECIBBEAgACABNgIQIAEgADYCGAsgA0EUaigCACIBRQ0AIABBFGogATYCACABIAA2AhgLAkAgBUEPTQRAIAMgBCAFaiIAQQNyNgIEIAAgA2oiACAAKAIEQQFyNgIEDAELIAMgBGoiAiAFQQFyNgIEIAMgBEEDcjYCBCACIAVqIAU2AgAgBUH/AU0EQCAFQXhxQezVAGohAAJ/QcTVACgCACIBQQEgBUEDdnQiBXFFBEBBxNUAIAEgBXI2AgAgAAwBCyAAKAIICyIBIAI2AgwgACACNgIIIAIgADYCDCACIAE2AggMAQtBHyEBIAVB////B00EQCAFQSYgBUEIdmciAGt2QQFxIABBAXRrQT5qIQELIAIgATYCHCACQgA3AhAgAUECdEH01wBqIQBBASABdCIEIAhxRQRAIAAgAjYCAEHI1QAgBCAIcjYCACACIAA2AhggAiACNgIIIAIgAjYCDAwBCyAFQRkgAUEBdmtBACABQR9HG3QhASAAKAIAIQQCQANAIAQiACgCBEF4cSAFRg0BIAFBHXYhBCABQQF0IQEgACAEQQRxakEQaiIGKAIAIgQNAAsgBiACNgIAIAIgADYCGCACIAI2AgwgAiACNgIIDAELIAAoAggiASACNgIMIAAgAjYCCCACQQA2AhggAiAANgIMIAIgATYCCAsgA0EIaiEBDAELAkAgCUUNAAJAIAAoAhwiAUECdEH01wBqIgIoAgAgAEYEQCACIAM2AgAgAw0BQcjVACALQX4gAXdxNgIADAILIAlBEEEUIAkoAhAgAEYbaiADNgIAIANFDQELIAMgCTYCGCAAKAIQIgEEQCADIAE2AhAgASADNgIYCyAAQRRqKAIAIgFFDQAgA0EUaiABNgIAIAEgAzYCGAsCQCAFQQ9NBEAgACAEIAVqIgFBA3I2AgQgACABaiIBIAEoAgRBAXI2AgQMAQsgACAEaiIHIAVBAXI2AgQgACAEQQNyNgIEIAUgB2ogBTYCACAIBEAgCEF4cUHs1QBqIQFB2NUAKAIAIQMCf0EBIAhBA3Z0IgIgBnFFBEBBxNUAIAIgBnI2AgAgAQwBCyABKAIICyICIAM2AgwgASADNgIIIAMgATYCDCADIAI2AggLQdjVACAHNgIAQczVACAFNgIACyAAQQhqIQELIApBEGokACABC0MAIABFBEA/AEEQdA8LAkAgAEH//wNxDQAgAEEASA0AIABBEHZAACIAQX9GBEBBtNkAQTA2AgBBfw8LIABBEHQPCwALC5lCIgBBgAgLDQEAAAAAAAAAAgAAAAMAQZgICwUEAAAABQBBqAgLCQYAAAAHAAAACABB5AgLwjJJbnZhbGlkIGNoYXIgaW4gdXJsIHF1ZXJ5AFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fYm9keQBDb250ZW50LUxlbmd0aCBvdmVyZmxvdwBDaHVuayBzaXplIG92ZXJmbG93AEludmFsaWQgbWV0aG9kIGZvciBIVFRQL3gueCByZXF1ZXN0AEludmFsaWQgbWV0aG9kIGZvciBSVFNQL3gueCByZXF1ZXN0AEV4cGVjdGVkIFNPVVJDRSBtZXRob2QgZm9yIElDRS94LnggcmVxdWVzdABJbnZhbGlkIGNoYXIgaW4gdXJsIGZyYWdtZW50IHN0YXJ0AEV4cGVjdGVkIGRvdABTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3N0YXR1cwBJbnZhbGlkIHJlc3BvbnNlIHN0YXR1cwBFeHBlY3RlZCBMRiBhZnRlciBoZWFkZXJzAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMAVXNlciBjYWxsYmFjayBlcnJvcgBgb25fcmVzZXRgIGNhbGxiYWNrIGVycm9yAGBvbl9jaHVua19oZWFkZXJgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2JlZ2luYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlYCBjYWxsYmFjayBlcnJvcgBgb25fc3RhdHVzX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdmVyc2lvbl9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3VybF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3Byb3RvY29sX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWV0aG9kX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX25hbWVgIGNhbGxiYWNrIGVycm9yAFVuZXhwZWN0ZWQgY2hhciBpbiB1cmwgc2VydmVyAEludmFsaWQgaGVhZGVyIHZhbHVlIGNoYXIASW52YWxpZCBoZWFkZXIgZmllbGQgY2hhcgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3ZlcnNpb24ASW52YWxpZCBtaW5vciB2ZXJzaW9uAEludmFsaWQgbWFqb3IgdmVyc2lvbgBFeHBlY3RlZCBzcGFjZSBhZnRlciB2ZXJzaW9uAEV4cGVjdGVkIENSTEYgYWZ0ZXIgdmVyc2lvbgBJbnZhbGlkIEhUVFAgdmVyc2lvbgBJbnZhbGlkIGhlYWRlciB0b2tlbgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3VybABJbnZhbGlkIGNoYXJhY3RlcnMgaW4gdXJsAFVuZXhwZWN0ZWQgc3RhcnQgY2hhciBpbiB1cmwARG91YmxlIEAgaW4gdXJsAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fcHJvdG9jb2wARW1wdHkgQ29udGVudC1MZW5ndGgASW52YWxpZCBjaGFyYWN0ZXIgaW4gQ29udGVudC1MZW5ndGgAVHJhbnNmZXItRW5jb2RpbmcgY2FuJ3QgYmUgcHJlc2VudCB3aXRoIENvbnRlbnQtTGVuZ3RoAER1cGxpY2F0ZSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXIgaW4gdXJsIHBhdGgAQ29udGVudC1MZW5ndGggY2FuJ3QgYmUgcHJlc2VudCB3aXRoIFRyYW5zZmVyLUVuY29kaW5nAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgY2h1bmsgc2l6ZQBFeHBlY3RlZCBMRiBhZnRlciBjaHVuayBzaXplAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIHNpemUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfdmFsdWUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyB2YWx1ZQBVbmV4cGVjdGVkIHdoaXRlc3BhY2UgYWZ0ZXIgaGVhZGVyIHZhbHVlAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgaGVhZGVyIHZhbHVlAE1pc3NpbmcgZXhwZWN0ZWQgTEYgYWZ0ZXIgaGVhZGVyIHZhbHVlAEludmFsaWQgYFRyYW5zZmVyLUVuY29kaW5nYCBoZWFkZXIgdmFsdWUATWlzc2luZyBleHBlY3RlZCBDUiBhZnRlciBjaHVuayBleHRlbnNpb24gdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBxdW90ZSB2YWx1ZQBJbnZhbGlkIHF1b3RlZC1wYWlyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAFBhdXNlZCBieSBvbl9oZWFkZXJzX2NvbXBsZXRlAEludmFsaWQgRU9GIHN0YXRlAG9uX3Jlc2V0IHBhdXNlAG9uX2NodW5rX2hlYWRlciBwYXVzZQBvbl9tZXNzYWdlX2JlZ2luIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl92YWx1ZSBwYXVzZQBvbl9zdGF0dXNfY29tcGxldGUgcGF1c2UAb25fdmVyc2lvbl9jb21wbGV0ZSBwYXVzZQBvbl91cmxfY29tcGxldGUgcGF1c2UAb25fcHJvdG9jb2xfY29tcGxldGUgcGF1c2UAb25fY2h1bmtfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX3ZhbHVlX2NvbXBsZXRlIHBhdXNlAG9uX21lc3NhZ2VfY29tcGxldGUgcGF1c2UAb25fbWV0aG9kX2NvbXBsZXRlIHBhdXNlAG9uX2hlYWRlcl9maWVsZF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19leHRlbnNpb25fbmFtZSBwYXVzZQBVbmV4cGVjdGVkIHNwYWNlIGFmdGVyIHN0YXJ0IGxpbmUATWlzc2luZyBleHBlY3RlZCBDUiBhZnRlciByZXNwb25zZSBsaW5lAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fY2h1bmtfZXh0ZW5zaW9uX25hbWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBuYW1lAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgY2h1bmsgZXh0ZW5zaW9uIG5hbWUASW52YWxpZCBzdGF0dXMgY29kZQBQYXVzZSBvbiBDT05ORUNUL1VwZ3JhZGUAUGF1c2Ugb24gUFJJL1VwZ3JhZGUARXhwZWN0ZWQgSFRUUC8yIENvbm5lY3Rpb24gUHJlZmFjZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX21ldGhvZABFeHBlY3RlZCBzcGFjZSBhZnRlciBtZXRob2QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfZmllbGQAUGF1c2VkAEludmFsaWQgd29yZCBlbmNvdW50ZXJlZABJbnZhbGlkIG1ldGhvZCBlbmNvdW50ZXJlZABNaXNzaW5nIGV4cGVjdGVkIENSIGFmdGVyIGNodW5rIGRhdGEARXhwZWN0ZWQgTEYgYWZ0ZXIgY2h1bmsgZGF0YQBVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNjaGVtYQBSZXF1ZXN0IGhhcyBpbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AARGF0YSBhZnRlciBgQ29ubmVjdGlvbjogY2xvc2VgAFNXSVRDSF9QUk9YWQBVU0VfUFJPWFkATUtBQ1RJVklUWQBVTlBST0NFU1NBQkxFX0VOVElUWQBRVUVSWQBDT1BZAE1PVkVEX1BFUk1BTkVOVExZAFRPT19FQVJMWQBOT1RJRlkARkFJTEVEX0RFUEVOREVOQ1kAQkFEX0dBVEVXQVkAUExBWQBQVVQAQ0hFQ0tPVVQAR0FURVdBWV9USU1FT1VUAFJFUVVFU1RfVElNRU9VVABORVRXT1JLX0NPTk5FQ1RfVElNRU9VVABDT05ORUNUSU9OX1RJTUVPVVQATE9HSU5fVElNRU9VVABORVRXT1JLX1JFQURfVElNRU9VVABQT1NUAE1JU0RJUkVDVEVEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9SRVFVRVNUAENMSUVOVF9DTE9TRURfTE9BRF9CQUxBTkNFRF9SRVFVRVNUAEJBRF9SRVFVRVNUAEhUVFBfUkVRVUVTVF9TRU5UX1RPX0hUVFBTX1BPUlQAUkVQT1JUAElNX0FfVEVBUE9UAFJFU0VUX0NPTlRFTlQATk9fQ09OVEVOVABQQVJUSUFMX0NPTlRFTlQASFBFX0lOVkFMSURfQ09OU1RBTlQASFBFX0NCX1JFU0VUAEdFVABIUEVfU1RSSUNUAENPTkZMSUNUAFRFTVBPUkFSWV9SRURJUkVDVABQRVJNQU5FTlRfUkVESVJFQ1QAQ09OTkVDVABNVUxUSV9TVEFUVVMASFBFX0lOVkFMSURfU1RBVFVTAFRPT19NQU5ZX1JFUVVFU1RTAEVBUkxZX0hJTlRTAFVOQVZBSUxBQkxFX0ZPUl9MRUdBTF9SRUFTT05TAE9QVElPTlMAU1dJVENISU5HX1BST1RPQ09MUwBWQVJJQU5UX0FMU09fTkVHT1RJQVRFUwBNVUxUSVBMRV9DSE9JQ0VTAElOVEVSTkFMX1NFUlZFUl9FUlJPUgBXRUJfU0VSVkVSX1VOS05PV05fRVJST1IAUkFJTEdVTl9FUlJPUgBJREVOVElUWV9QUk9WSURFUl9BVVRIRU5USUNBVElPTl9FUlJPUgBTU0xfQ0VSVElGSUNBVEVfRVJST1IASU5WQUxJRF9YX0ZPUldBUkRFRF9GT1IAU0VUX1BBUkFNRVRFUgBHRVRfUEFSQU1FVEVSAEhQRV9VU0VSAFNFRV9PVEhFUgBIUEVfQ0JfQ0hVTktfSEVBREVSAEV4cGVjdGVkIExGIGFmdGVyIENSAE1LQ0FMRU5EQVIAU0VUVVAAV0VCX1NFUlZFUl9JU19ET1dOAFRFQVJET1dOAEhQRV9DTE9TRURfQ09OTkVDVElPTgBIRVVSSVNUSUNfRVhQSVJBVElPTgBESVNDT05ORUNURURfT1BFUkFUSU9OAE5PTl9BVVRIT1JJVEFUSVZFX0lORk9STUFUSU9OAEhQRV9JTlZBTElEX1ZFUlNJT04ASFBFX0NCX01FU1NBR0VfQkVHSU4AU0lURV9JU19GUk9aRU4ASFBFX0lOVkFMSURfSEVBREVSX1RPS0VOAElOVkFMSURfVE9LRU4ARk9SQklEREVOAEVOSEFOQ0VfWU9VUl9DQUxNAEhQRV9JTlZBTElEX1VSTABCTE9DS0VEX0JZX1BBUkVOVEFMX0NPTlRST0wATUtDT0wAQUNMAEhQRV9JTlRFUk5BTABSRVFVRVNUX0hFQURFUl9GSUVMRFNfVE9PX0xBUkdFX1VOT0ZGSUNJQUwASFBFX09LAFVOTElOSwBVTkxPQ0sAUFJJAFJFVFJZX1dJVEgASFBFX0lOVkFMSURfQ09OVEVOVF9MRU5HVEgASFBFX1VORVhQRUNURURfQ09OVEVOVF9MRU5HVEgARkxVU0gAUFJPUFBBVENIAE0tU0VBUkNIAFVSSV9UT09fTE9ORwBQUk9DRVNTSU5HAE1JU0NFTExBTkVPVVNfUEVSU0lTVEVOVF9XQVJOSU5HAE1JU0NFTExBTkVPVVNfV0FSTklORwBIUEVfSU5WQUxJRF9UUkFOU0ZFUl9FTkNPRElORwBFeHBlY3RlZCBDUkxGAEhQRV9JTlZBTElEX0NIVU5LX1NJWkUATU9WRQBDT05USU5VRQBIUEVfQ0JfU1RBVFVTX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJTX0NPTVBMRVRFAEhQRV9DQl9WRVJTSU9OX0NPTVBMRVRFAEhQRV9DQl9VUkxfQ09NUExFVEUASFBFX0NCX1BST1RPQ09MX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19DT01QTEVURQBIUEVfQ0JfSEVBREVSX1ZBTFVFX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19FWFRFTlNJT05fVkFMVUVfQ09NUExFVEUASFBFX0NCX0NIVU5LX0VYVEVOU0lPTl9OQU1FX0NPTVBMRVRFAEhQRV9DQl9NRVNTQUdFX0NPTVBMRVRFAEhQRV9DQl9NRVRIT0RfQ09NUExFVEUASFBFX0NCX0hFQURFUl9GSUVMRF9DT01QTEVURQBERUxFVEUASFBFX0lOVkFMSURfRU9GX1NUQVRFAElOVkFMSURfU1NMX0NFUlRJRklDQVRFAFBBVVNFAE5PX1JFU1BPTlNFAFVOU1VQUE9SVEVEX01FRElBX1RZUEUAR09ORQBOT1RfQUNDRVBUQUJMRQBTRVJWSUNFX1VOQVZBSUxBQkxFAFJBTkdFX05PVF9TQVRJU0ZJQUJMRQBPUklHSU5fSVNfVU5SRUFDSEFCTEUAUkVTUE9OU0VfSVNfU1RBTEUAUFVSR0UATUVSR0UAUkVRVUVTVF9IRUFERVJfRklFTERTX1RPT19MQVJHRQBSRVFVRVNUX0hFQURFUl9UT09fTEFSR0UAUEFZTE9BRF9UT09fTEFSR0UASU5TVUZGSUNJRU5UX1NUT1JBR0UASFBFX1BBVVNFRF9VUEdSQURFAEhQRV9QQVVTRURfSDJfVVBHUkFERQBTT1VSQ0UAQU5OT1VOQ0UAVFJBQ0UASFBFX1VORVhQRUNURURfU1BBQ0UAREVTQ1JJQkUAVU5TVUJTQ1JJQkUAUkVDT1JEAEhQRV9JTlZBTElEX01FVEhPRABOT1RfRk9VTkQAUFJPUEZJTkQAVU5CSU5EAFJFQklORABVTkFVVEhPUklaRUQATUVUSE9EX05PVF9BTExPV0VEAEhUVFBfVkVSU0lPTl9OT1RfU1VQUE9SVEVEAEFMUkVBRFlfUkVQT1JURUQAQUNDRVBURUQATk9UX0lNUExFTUVOVEVEAExPT1BfREVURUNURUQASFBFX0NSX0VYUEVDVEVEAEhQRV9MRl9FWFBFQ1RFRABDUkVBVEVEAElNX1VTRUQASFBFX1BBVVNFRABUSU1FT1VUX09DQ1VSRUQAUEFZTUVOVF9SRVFVSVJFRABQUkVDT05ESVRJT05fUkVRVUlSRUQAUFJPWFlfQVVUSEVOVElDQVRJT05fUkVRVUlSRUQATkVUV09SS19BVVRIRU5USUNBVElPTl9SRVFVSVJFRABMRU5HVEhfUkVRVUlSRUQAU1NMX0NFUlRJRklDQVRFX1JFUVVJUkVEAFVQR1JBREVfUkVRVUlSRUQAUEFHRV9FWFBJUkVEAFBSRUNPTkRJVElPTl9GQUlMRUQARVhQRUNUQVRJT05fRkFJTEVEAFJFVkFMSURBVElPTl9GQUlMRUQAU1NMX0hBTkRTSEFLRV9GQUlMRUQATE9DS0VEAFRSQU5TRk9STUFUSU9OX0FQUExJRUQATk9UX01PRElGSUVEAE5PVF9FWFRFTkRFRABCQU5EV0lEVEhfTElNSVRfRVhDRUVERUQAU0lURV9JU19PVkVSTE9BREVEAEhFQUQARXhwZWN0ZWQgSFRUUC8sIFJUU1AvIG9yIElDRS8A5xUAAK8VAACkEgAAkhoAACYWAACeFAAA2xkAAHkVAAB+EgAA/hQAADYVAAALFgAA2BYAAPMSAABCGAAArBYAABIVAAAUFwAA7xcAAEgUAABxFwAAshoAAGsZAAB+GQAANRQAAIIaAABEFwAA/RYAAB4YAACHFwAAqhkAAJMSAAAHGAAALBcAAMoXAACkFwAA5xUAAOcVAABYFwAAOxgAAKASAAAtHAAAwxEAAEgRAADeEgAAQhMAAKQZAAD9EAAA9xUAAKUVAADvFgAA+BkAAEoWAABWFgAA9RUAAAoaAAAIGgAAARoAAKsVAABCEgAA1xAAAEwRAAAFGQAAVBYAAB4RAADKGQAAyBkAAE4WAAD/GAAAcRQAAPAVAADuFQAAlBkAAPwVAAC/GQAAmxkAAHwUAABDEQAAcBgAAJUUAAAnFAAAGRQAANUSAADUGQAARBYAAPcQAEG5OwsBAQBB0DsL4AEBAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBuj0LBAEAAAIAQdE9C14DBAMDAwMDAAADAwADAwADAwMDAwMDAwMDAAUAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAwADAEG6PwsEAQAAAgBB0T8LXgMAAwMDAwMAAAMDAAMDAAMDAwMDAwMDAwMABAAFAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwADAAMAQbDBAAsNbG9zZWVlcC1hbGl2ZQBBycEACwEBAEHgwQAL4AEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBycMACwEBAEHgwwAL5wEBAQEBAQEBAQEBAQECAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAWNodW5rZWQAQfHFAAteAQABAQEBAQAAAQEAAQEAAQEBAQEBAQEBAQAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQBB0McACyFlY3Rpb25lbnQtbGVuZ3Rob25yb3h5LWNvbm5lY3Rpb24AQYDIAAsgcmFuc2Zlci1lbmNvZGluZ3BncmFkZQ0KDQpTTQ0KDQoAQanIAAsFAQIAAQMAQcDIAAtfBAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAQanKAAsFAQIAAQMAQcDKAAtfBAUFBgUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAQanMAAsEAQAAAQBBwcwAC14CAgACAgICAgICAgICAgICAgICAgICAgICAgICAgIAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAEGpzgALBQECAAEDAEHAzgALXwQFAAAFBQUFBQUFBQUFBQYFBQUFBQUFBQUFBQUABQAHCAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQAFAAUABQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAAAAFAEGp0AALBQEBAAEBAEHA0AALAQEAQdrQAAtBAgAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQanSAAsFAQEAAQEAQcDSAAsBAQBBytIACwYCAAAAAAIAQeHSAAs6AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBBoNQAC50BTk9VTkNFRUNLT1VUTkVDVEVURUNSSUJFTFVTSEVURUFEU0VBUkNIUkdFQ1RJVklUWUxFTkRBUlZFT1RJRllQVElPTlNDSFNFQVlTVEFUQ0hHRVVFUllPUkRJUkVDVE9SVFJDSFBBUkFNRVRFUlVSQ0VCU0NSSUJFQVJET1dOQUNFSU5ETktDS1VCU0NSSUJFVFRQQ0VUU1BBRFRQLw==",fw;Object.defineProperty(n3,"exports",{get:()=>fw||(fw=wfe.from(Sfe,"base64"))})});var RE=U((BTe,s3)=>{"use strict";function vE(){let e=globalThis.__secureExecBuiltinZlibModule;if(!e)throw new Error("node:zlib bridge module is not available");return e}s3.exports=new Proxy({},{get(e,t){return vE()[t]},has(e,t){return t in vE()},ownKeys(){return Reflect.ownKeys(vE())},getOwnPropertyDescriptor(e,t){let r=Object.getOwnPropertyDescriptor(vE(),t);return r||{configurable:!0,enumerable:!0,value:void 0,writable:!1}}})});var td=U((ITe,h3)=>{"use strict";var o3=["GET","HEAD","POST"],_fe=new Set(o3),vfe=[101,204,205,304],a3=[301,302,303,307,308],Rfe=new Set(a3),A3=["1","7","9","11","13","15","17","19","20","21","22","23","25","37","42","43","53","69","77","79","87","95","101","102","103","104","109","110","111","113","115","117","119","123","135","137","139","143","161","179","389","427","465","512","513","514","515","526","530","531","532","540","548","554","556","563","587","601","636","989","990","993","995","1719","1720","1723","2049","3659","4045","4190","5060","5061","6000","6566","6665","6666","6667","6668","6669","6679","6697","10080"],Dfe=new Set(A3),f3=["no-referrer","no-referrer-when-downgrade","same-origin","origin","strict-origin","origin-when-cross-origin","strict-origin-when-cross-origin","unsafe-url"],Tfe=["",...f3],Nfe=new Set(f3),Mfe=["follow","manual","error"],u3=["GET","HEAD","OPTIONS","TRACE"],Ffe=new Set(u3),kfe=["navigate","same-origin","no-cors","cors"],Ufe=["omit","same-origin","include"],xfe=["default","no-store","reload","no-cache","force-cache","only-if-cached"],Lfe=["content-encoding","content-language","content-location","content-type","content-length"],Pfe=["half"],c3=["CONNECT","TRACE","TRACK"],Ofe=new Set(c3),l3=["audio","audioworklet","font","image","manifest","paintworklet","script","style","track","video","xslt",""],Hfe=new Set(l3);h3.exports={subresource:l3,forbiddenMethods:c3,requestBodyHeader:Lfe,referrerPolicy:Tfe,requestRedirect:Mfe,requestMode:kfe,requestCredentials:Ufe,requestCache:xfe,redirectStatus:a3,corsSafeListedMethods:o3,nullBodyStatus:vfe,safeMethods:u3,badPorts:A3,requestDuplex:Pfe,subresourceSet:Hfe,badPortsSet:Dfe,redirectStatusSet:Rfe,corsSafeListedMethodsSet:_fe,safeMethodsSet:Ffe,forbiddenMethodsSet:Ofe,referrerPolicyTokens:Nfe}});var g3=U((bTe,d3)=>{"use strict";var uw=Symbol.for("undici.globalOrigin.1");function qfe(){return globalThis[uw]}function Gfe(e){if(e===void 0){Object.defineProperty(globalThis,uw,{value:void 0,writable:!0,enumerable:!1,configurable:!1});return}let t=new URL(e);if(t.protocol!=="http:"&&t.protocol!=="https:")throw new TypeError(`Only http & https urls are allowed, received ${t.protocol}`);Object.defineProperty(globalThis,uw,{value:t,writable:!0,enumerable:!1,configurable:!1})}d3.exports={getGlobalOrigin:qfe,setGlobalOrigin:Gfe}});var cw=U((CTe,p3)=>{"use strict";var Yfe=new TextDecoder;function Wfe(e){return e.length===0?"":(e[0]===239&&e[1]===187&&e[2]===191&&(e=e.subarray(3)),Yfe.decode(e))}p3.exports={utf8DecodeBytes:Wfe}});var Ef=U((QTe,B3)=>{"use strict";var E3=Gt(),{utf8DecodeBytes:Vfe}=cw();function Jfe(e,t,r){let n="";for(;r.positiont)return String.fromCharCode.apply(null,e);let r="",n=0,i=65535;for(;nt&&(i=t-n),r+=String.fromCharCode.apply(null,e.subarray(n,n+=i));return r}var Zfe=/[^\x00-\xFF]/;function $fe(e){return E3(!Zfe.test(e)),e}function eue(e){return JSON.parse(Vfe(e))}function tue(e,t=!0,r=!0){return m3(e,t,r,y3)}function m3(e,t,r,n){let i=0,s=e.length-1;if(t)for(;i0&&n(e.charCodeAt(s));)s--;return i===0&&s===e.length-1?e:e.slice(i,s+1)}function rue(e){let t=JSON.stringify(e);if(t===void 0)throw new TypeError("Value is not JSON serializable");return E3(typeof t=="string"),t}B3.exports={collectASequenceOfCodePoints:Jfe,collectASequenceOfCodePointsFast:jfe,forgivingBase64:Kfe,isASCIIWhitespace:y3,isomorphicDecode:Xfe,isomorphicEncode:$fe,parseJSONFromBytes:eue,removeASCIIWhitespace:tue,removeChars:m3,serializeJavascriptValueToJSONString:rue}});var yf=U((wTe,S3)=>{"use strict";var TE=Gt(),{forgivingBase64:nue,collectASequenceOfCodePoints:lw,collectASequenceOfCodePointsFast:rd,isomorphicDecode:iue,removeASCIIWhitespace:sue,removeChars:oue}=Ef(),aue=new TextEncoder,nd=/^[-!#$%&'*+.^_|~A-Za-z0-9]+$/u,Aue=/[\u000A\u000D\u0009\u0020]/u,fue=/^[\u0009\u0020-\u007E\u0080-\u00FF]+$/u;function uue(e){TE(e.protocol==="data:");let t=C3(e,!0);t=t.slice(5);let r={position:0},n=rd(",",t,r),i=n.length;if(n=sue(n,!0,!0),r.position>=t.length)return"failure";r.position++;let s=t.slice(i+1),o=Q3(s);if(/;(?:\u0020*)base64$/ui.test(n)){let A=iue(o);if(o=nue(A),o==="failure")return"failure";n=n.slice(0,-6),n=n.replace(/(\u0020+)$/u,""),n=n.slice(0,-1)}n.startsWith(";")&&(n="text/plain"+n);let a=hw(n);return a==="failure"&&(a=hw("text/plain;charset=US-ASCII")),{mimeType:a,body:o}}function C3(e,t=!1){if(!t)return e.href;let r=e.href,n=e.hash.length,i=n===0?r:r.substring(0,r.length-n);return!n&&r.endsWith("#")?i.slice(0,-1):i}function Q3(e){let t=aue.encode(e);return cue(t)}function I3(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}function b3(e){return e>=48&&e<=57?e-48:(e&223)-55}function cue(e){let t=e.length,r=new Uint8Array(t),n=0,i=0;for(;i=e.length)return"failure";t.position++;let n=rd(";",e,t);if(n=DE(n,!1,!0),n.length===0||!nd.test(n))return"failure";let i=r.toLowerCase(),s=n.toLowerCase(),o={type:i,subtype:s,parameters:new Map,essence:`${i}/${s}`};for(;t.positionAue.test(f),e,t);let a=lw(f=>f!==";"&&f!=="=",e,t);if(a=a.toLowerCase(),t.position=e.length)break;let A=null;if(e[t.position]==='"')A=w3(e,t,!0),rd(";",e,t);else if(A=rd(";",e,t),A=DE(A,!1,!0),A.length===0)continue;a.length!==0&&nd.test(a)&&(A.length===0||fue.test(A))&&!o.parameters.has(a)&&o.parameters.set(a,A)}return o}function w3(e,t,r=!1){let n=t.position,i="";for(TE(e[t.position]==='"'),t.position++;i+=lw(o=>o!=='"'&&o!=="\\",e,t),!(t.position>=e.length);){let s=e[t.position];if(t.position++,s==="\\"){if(t.position>=e.length){i+="\\";break}i+=e[t.position],t.position++}else{TE(s==='"');break}}return r?i:e.slice(n,t.position)}function lue(e){TE(e!=="failure");let{parameters:t,essence:r}=e,n=r;for(let[i,s]of t.entries())n+=";",n+=i,n+="=",nd.test(s)||(s=s.replace(/[\\"]/ug,"\\$&"),s='"'+s,s+='"'),n+=s;return n}function hue(e){return e===13||e===10||e===9||e===32}function DE(e,t=!0,r=!0){return oue(e,t,r,hue)}function due(e){switch(e.essence){case"application/ecmascript":case"application/javascript":case"application/x-ecmascript":case"application/x-javascript":case"text/ecmascript":case"text/javascript":case"text/javascript1.0":case"text/javascript1.1":case"text/javascript1.2":case"text/javascript1.3":case"text/javascript1.4":case"text/javascript1.5":case"text/jscript":case"text/livescript":case"text/x-ecmascript":case"text/x-javascript":return"text/javascript";case"application/json":case"text/json":return"application/json";case"image/svg+xml":return"image/svg+xml";case"text/xml":case"application/xml":return"application/xml"}return e.subtype.endsWith("+json")?"application/json":e.subtype.endsWith("+xml")?"application/xml":""}S3.exports={dataURLProcessor:uue,URLSerializer:C3,stringPercentDecode:Q3,parseMIMEType:hw,collectAnHTTPQuotedString:w3,serializeAMimeType:lue,removeHTTPWhitespace:DE,minimizeSupportedMimeType:due,HTTP_TOKEN_CODEPOINTS:nd}});var v3=U((STe,_3)=>{"use strict";var gue=globalThis.performance??{now(){return Date.now()},timeOrigin:Date.now()};_3.exports={performance:gue}});var dw=U((_Te,R3)=>{"use strict";function pue(e){return e instanceof ArrayBuffer}function Eue(e){return ArrayBuffer.isView(e)}function yue(e){return e instanceof Uint8Array}function mue(e){return!1}R3.exports={isArrayBuffer:pue,isArrayBufferView:Eue,isProxy:mue,isUint8Array:yue}});var mf=U((vTe,pw)=>{"use strict";var gw=65536,Bue=4294967295;function Iue(){throw new Error(`Secure random number generation is not supported by this browser. -Use Chrome, Firefox or Internet Explorer 11`)}var bue=at().Buffer,NE=globalThis.crypto||globalThis.msCrypto;NE&&NE.getRandomValues?pw.exports=Cue:pw.exports=Iue;function Cue(e,t){if(e>Bue)throw new RangeError("requested too many random bytes");var r=bue.allocUnsafe(e);if(e>0)if(e>gw)for(var n=0;n{var Que={}.toString;D3.exports=Array.isArray||function(e){return Que.call(e)=="[object Array]"}});var M3=U((DTe,N3)=>{"use strict";var wue=$i(),Sue=Ys(),_ue=Sue("TypedArray.prototype.buffer",!0),vue=sb();N3.exports=_ue||function(t){if(!vue(t))throw new wue("Not a Typed Array");return t.buffer}});var id=U((TTe,k3)=>{"use strict";var ss=at().Buffer,Rue=T3(),Due=M3(),Tue=ArrayBuffer.isView||function(t){try{return Due(t),!0}catch{return!1}},Nue=typeof Uint8Array<"u",F3=typeof ArrayBuffer<"u"&&typeof Uint8Array<"u",Mue=F3&&(ss.prototype instanceof Uint8Array||ss.TYPED_ARRAY_SUPPORT);k3.exports=function(t,r){if(ss.isBuffer(t))return t.constructor&&!("isBuffer"in t)?ss.from(t):t;if(typeof t=="string")return ss.from(t,r);if(F3&&Tue(t)){if(t.byteLength===0)return ss.alloc(0);if(Mue){var n=ss.from(t.buffer,t.byteOffset,t.byteLength);if(n.byteLength===t.byteLength)return n}var i=t instanceof Uint8Array?t:new Uint8Array(t.buffer,t.byteOffset,t.byteLength),s=ss.from(i);if(s.length===t.byteLength)return s}if(Nue&&t instanceof Uint8Array)return ss.from(t);var o=Rue(t);if(o)for(var a=0;a255||~~A!==A)throw new RangeError("Array items must be numbers in the range 0-255.")}if(o||ss.isBuffer(t)&&t.constructor&&typeof t.constructor.isBuffer=="function"&&t.constructor.isBuffer(t))return ss.from(t);throw new TypeError('The "data" argument must be a string, an Array, a Buffer, a Uint8Array, or a DataView.')}});var P3=U((NTe,L3)=>{"use strict";var Fue=at().Buffer,kue=id(),x3=typeof Uint8Array<"u",Uue=x3&&typeof ArrayBuffer<"u",U3=Uue&&ArrayBuffer.isView;L3.exports=function(e,t){if(typeof e=="string"||Fue.isBuffer(e)||x3&&e instanceof Uint8Array||U3&&U3(e))return kue(e,t);throw new TypeError('The "data" argument must be a string, a Buffer, a Uint8Array, or a DataView')}});var sd=U((MTe,Ew)=>{"use strict";typeof process>"u"||!process.version||process.version.indexOf("v0.")===0||process.version.indexOf("v1.")===0&&process.version.indexOf("v1.8.")!==0?Ew.exports={nextTick:xue}:Ew.exports=process;function xue(e,t,r,n){if(typeof e!="function")throw new TypeError('"callback" argument must be a function');var i=arguments.length,s,o;switch(i){case 0:case 1:return process.nextTick(e);case 2:return process.nextTick(function(){e.call(null,t)});case 3:return process.nextTick(function(){e.call(null,t,r)});case 4:return process.nextTick(function(){e.call(null,t,r,n)});default:for(s=new Array(i-1),o=0;o{var Lue={}.toString;O3.exports=Array.isArray||function(e){return Lue.call(e)=="[object Array]"}});var yw=U((kTe,q3)=>{q3.exports=Zi().EventEmitter});var FE=U((mw,Y3)=>{var ME=Gr(),Ko=ME.Buffer;function G3(e,t){for(var r in e)t[r]=e[r]}Ko.from&&Ko.alloc&&Ko.allocUnsafe&&Ko.allocUnsafeSlow?Y3.exports=ME:(G3(ME,mw),mw.Buffer=vc);function vc(e,t,r){return Ko(e,t,r)}G3(Ko,vc);vc.from=function(e,t,r){if(typeof e=="number")throw new TypeError("Argument must not be a number");return Ko(e,t,r)};vc.alloc=function(e,t,r){if(typeof e!="number")throw new TypeError("Argument must be a number");var n=Ko(e);return t!==void 0?typeof r=="string"?n.fill(t,r):n.fill(t):n.fill(0),n};vc.allocUnsafe=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return Ko(e)};vc.allocUnsafeSlow=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return ME.SlowBuffer(e)}});var Rc=U(rn=>{function Pue(e){return Array.isArray?Array.isArray(e):kE(e)==="[object Array]"}rn.isArray=Pue;function Oue(e){return typeof e=="boolean"}rn.isBoolean=Oue;function Hue(e){return e===null}rn.isNull=Hue;function que(e){return e==null}rn.isNullOrUndefined=que;function Gue(e){return typeof e=="number"}rn.isNumber=Gue;function Yue(e){return typeof e=="string"}rn.isString=Yue;function Wue(e){return typeof e=="symbol"}rn.isSymbol=Wue;function Vue(e){return e===void 0}rn.isUndefined=Vue;function Jue(e){return kE(e)==="[object RegExp]"}rn.isRegExp=Jue;function jue(e){return typeof e=="object"&&e!==null}rn.isObject=jue;function zue(e){return kE(e)==="[object Date]"}rn.isDate=zue;function Kue(e){return kE(e)==="[object Error]"||e instanceof Error}rn.isError=Kue;function Xue(e){return typeof e=="function"}rn.isFunction=Xue;function Zue(e){return e===null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"||typeof e=="symbol"||typeof e>"u"}rn.isPrimitive=Zue;rn.isBuffer=Gr().Buffer.isBuffer;function kE(e){return Object.prototype.toString.call(e)}});var V3=U((xTe,Bw)=>{"use strict";function $ue(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var W3=FE().Buffer,od=Yr();function ece(e,t,r){e.copy(t,r)}Bw.exports=(function(){function e(){$ue(this,e),this.head=null,this.tail=null,this.length=0}return e.prototype.push=function(r){var n={data:r,next:null};this.length>0?this.tail.next=n:this.head=n,this.tail=n,++this.length},e.prototype.unshift=function(r){var n={data:r,next:this.head};this.length===0&&(this.tail=n),this.head=n,++this.length},e.prototype.shift=function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}},e.prototype.clear=function(){this.head=this.tail=null,this.length=0},e.prototype.join=function(r){if(this.length===0)return"";for(var n=this.head,i=""+n.data;n=n.next;)i+=r+n.data;return i},e.prototype.concat=function(r){if(this.length===0)return W3.alloc(0);for(var n=W3.allocUnsafe(r>>>0),i=this.head,s=0;i;)ece(i.data,n,s),s+=i.data.length,i=i.next;return n},e})();od&&od.inspect&&od.inspect.custom&&(Bw.exports.prototype[od.inspect.custom]=function(){var e=od.inspect({length:this.length});return this.constructor.name+" "+e})});var Iw=U((LTe,J3)=>{"use strict";var UE=sd();function tce(e,t){var r=this,n=this._readableState&&this._readableState.destroyed,i=this._writableState&&this._writableState.destroyed;return n||i?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,UE.nextTick(xE,this,e)):UE.nextTick(xE,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(s){!t&&s?r._writableState?r._writableState.errorEmitted||(r._writableState.errorEmitted=!0,UE.nextTick(xE,r,s)):UE.nextTick(xE,r,s):t&&t(s)}),this)}function rce(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function xE(e,t){e.emit("error",t)}J3.exports={destroy:tce,undestroy:rce}});var Cw=U((PTe,tL)=>{"use strict";var Bf=sd();tL.exports=Br;function z3(e){var t=this;this.next=null,this.entry=null,this.finish=function(){Bce(t,e)}}var nce=!process.browser&&["v0.10","v0.9."].indexOf(process.version.slice(0,5))>-1?setImmediate:Bf.nextTick,Dc;Br.WritableState=Ad;var K3=Object.create(Rc());K3.inherits=je();var ice={deprecate:yb()},X3=yw(),PE=FE().Buffer,sce=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function oce(e){return PE.from(e)}function ace(e){return PE.isBuffer(e)||e instanceof sce}var Z3=Iw();K3.inherits(Br,X3);function Ace(){}function Ad(e,t){Dc=Dc||If(),e=e||{};var r=t instanceof Dc;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var n=e.highWaterMark,i=e.writableHighWaterMark,s=this.objectMode?16:16*1024;n||n===0?this.highWaterMark=n:r&&(i||i===0)?this.highWaterMark=i:this.highWaterMark=s,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var o=e.decodeStrings===!1;this.decodeStrings=!o,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(a){gce(t,a)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new z3(this)}Ad.prototype.getBuffer=function(){for(var t=this.bufferedRequest,r=[];t;)r.push(t),t=t.next;return r};(function(){try{Object.defineProperty(Ad.prototype,"buffer",{get:ice.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch{}})();var LE;typeof Symbol=="function"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]=="function"?(LE=Function.prototype[Symbol.hasInstance],Object.defineProperty(Br,Symbol.hasInstance,{value:function(e){return LE.call(this,e)?!0:this!==Br?!1:e&&e._writableState instanceof Ad}})):LE=function(e){return e instanceof this};function Br(e){if(Dc=Dc||If(),!LE.call(Br,this)&&!(this instanceof Dc))return new Br(e);this._writableState=new Ad(e,this),this.writable=!0,e&&(typeof e.write=="function"&&(this._write=e.write),typeof e.writev=="function"&&(this._writev=e.writev),typeof e.destroy=="function"&&(this._destroy=e.destroy),typeof e.final=="function"&&(this._final=e.final)),X3.call(this)}Br.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))};function fce(e,t){var r=new Error("write after end");e.emit("error",r),Bf.nextTick(t,r)}function uce(e,t,r,n){var i=!0,s=!1;return r===null?s=new TypeError("May not write null values to stream"):typeof r!="string"&&r!==void 0&&!t.objectMode&&(s=new TypeError("Invalid non-string/buffer chunk")),s&&(e.emit("error",s),Bf.nextTick(n,s),i=!1),i}Br.prototype.write=function(e,t,r){var n=this._writableState,i=!1,s=!n.objectMode&&ace(e);return s&&!PE.isBuffer(e)&&(e=oce(e)),typeof t=="function"&&(r=t,t=null),s?t="buffer":t||(t=n.defaultEncoding),typeof r!="function"&&(r=Ace),n.ended?fce(this,r):(s||uce(this,n,e,r))&&(n.pendingcb++,i=lce(this,n,s,e,t,r)),i};Br.prototype.cork=function(){var e=this._writableState;e.corked++};Br.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&$3(this,e))};Br.prototype.setDefaultEncoding=function(t){if(typeof t=="string"&&(t=t.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((t+"").toLowerCase())>-1))throw new TypeError("Unknown encoding: "+t);return this._writableState.defaultEncoding=t,this};function cce(e,t,r){return!e.objectMode&&e.decodeStrings!==!1&&typeof t=="string"&&(t=PE.from(t,r)),t}Object.defineProperty(Br.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function lce(e,t,r,n,i,s){if(!r){var o=cce(t,n,i);n!==o&&(r=!0,i="buffer",n=o)}var a=t.objectMode?1:n.length;t.length+=a;var A=t.length{"use strict";var rL=sd(),Ice=Object.keys||function(e){var t=[];for(var r in e)t.push(r);return t};sL.exports=Xo;var nL=Object.create(Rc());nL.inherits=je();var iL=Sw(),ww=Cw();nL.inherits(Xo,iL);for(Qw=Ice(ww.prototype),OE=0;OE{"use strict";var Nc=sd();EL.exports=$t;var Qce=H3(),fd;$t.ReadableState=lL;var HTe=Zi().EventEmitter,fL=function(e,t){return e.listeners(t).length},Tw=yw(),ud=FE().Buffer,wce=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function Sce(e){return ud.from(e)}function _ce(e){return ud.isBuffer(e)||e instanceof wce}var uL=Object.create(Rc());uL.inherits=je();var _w=Yr(),St=void 0;_w&&_w.debuglog?St=_w.debuglog("stream"):St=function(){};var vce=V3(),cL=Iw(),Tc;uL.inherits($t,Tw);var vw=["error","close","destroy","pause","resume"];function Rce(e,t,r){if(typeof e.prependListener=="function")return e.prependListener(t,r);!e._events||!e._events[t]?e.on(t,r):Qce(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]}function lL(e,t){fd=fd||If(),e=e||{};var r=t instanceof fd;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.readableObjectMode);var n=e.highWaterMark,i=e.readableHighWaterMark,s=this.objectMode?16:16*1024;n||n===0?this.highWaterMark=n:r&&(i||i===0)?this.highWaterMark=i:this.highWaterMark=s,this.highWaterMark=Math.floor(this.highWaterMark),this.buffer=new vce,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(Tc||(Tc=sf().StringDecoder),this.decoder=new Tc(e.encoding),this.encoding=e.encoding)}function $t(e){if(fd=fd||If(),!(this instanceof $t))return new $t(e);this._readableState=new lL(e,this),this.readable=!0,e&&(typeof e.read=="function"&&(this._read=e.read),typeof e.destroy=="function"&&(this._destroy=e.destroy)),Tw.call(this)}Object.defineProperty($t.prototype,"destroyed",{get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){this._readableState&&(this._readableState.destroyed=e)}});$t.prototype.destroy=cL.destroy;$t.prototype._undestroy=cL.undestroy;$t.prototype._destroy=function(e,t){this.push(null),t(e)};$t.prototype.push=function(e,t){var r=this._readableState,n;return r.objectMode?n=!0:typeof e=="string"&&(t=t||r.defaultEncoding,t!==r.encoding&&(e=ud.from(e,t),t=""),n=!0),hL(this,e,t,!1,n)};$t.prototype.unshift=function(e){return hL(this,e,null,!0,!1)};function hL(e,t,r,n,i){var s=e._readableState;if(t===null)s.reading=!1,Mce(e,s);else{var o;i||(o=Dce(s,t)),o?e.emit("error",o):s.objectMode||t&&t.length>0?(typeof t!="string"&&!s.objectMode&&Object.getPrototypeOf(t)!==ud.prototype&&(t=Sce(t)),n?s.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):Rw(e,s,t,!0):s.ended?e.emit("error",new Error("stream.push() after EOF")):(s.reading=!1,s.decoder&&!r?(t=s.decoder.write(t),s.objectMode||t.length!==0?Rw(e,s,t,!1):dL(e,s)):Rw(e,s,t,!1))):n||(s.reading=!1)}return Tce(s)}function Rw(e,t,r,n){t.flowing&&t.length===0&&!t.sync?(e.emit("data",r),e.read(0)):(t.length+=t.objectMode?1:r.length,n?t.buffer.unshift(r):t.buffer.push(r),t.needReadable&&qE(e)),dL(e,t)}function Dce(e,t){var r;return!_ce(t)&&typeof t!="string"&&t!==void 0&&!e.objectMode&&(r=new TypeError("Invalid non-string/buffer chunk")),r}function Tce(e){return!e.ended&&(e.needReadable||e.length=oL?e=oL:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function aL(e,t){return e<=0||t.length===0&&t.ended?0:t.objectMode?1:e!==e?t.flowing&&t.length?t.buffer.head.data.length:t.length:(e>t.highWaterMark&&(t.highWaterMark=Nce(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}$t.prototype.read=function(e){St("read",e),e=parseInt(e,10);var t=this._readableState,r=e;if(e!==0&&(t.emittedReadable=!1),e===0&&t.needReadable&&(t.length>=t.highWaterMark||t.ended))return St("read: emitReadable",t.length,t.ended),t.length===0&&t.ended?Dw(this):qE(this),null;if(e=aL(e,t),e===0&&t.ended)return t.length===0&&Dw(this),null;var n=t.needReadable;St("need readable",n),(t.length===0||t.length-e0?i=gL(e,t):i=null,i===null?(t.needReadable=!0,e=0):t.length-=e,t.length===0&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&Dw(this)),i!==null&&this.emit("data",i),i};function Mce(e,t){if(!t.ended){if(t.decoder){var r=t.decoder.end();r&&r.length&&(t.buffer.push(r),t.length+=t.objectMode?1:r.length)}t.ended=!0,qE(e)}}function qE(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(St("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?Nc.nextTick(AL,e):AL(e))}function AL(e){St("emit readable"),e.emit("readable"),Nw(e)}function dL(e,t){t.readingMore||(t.readingMore=!0,Nc.nextTick(Fce,e,t))}function Fce(e,t){for(var r=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length1&&pL(n.pipes,e)!==-1)&&!f&&(St("false write response, pause",n.awaitDrain),n.awaitDrain++,p=!0),r.pause())}function S(x){St("onerror",x),O(),e.removeListener("error",S),fL(e,"error")===0&&e.emit("error",x)}Rce(e,"error",S);function _(){e.removeListener("finish",N),O()}e.once("close",_);function N(){St("onfinish"),e.removeListener("close",_),O()}e.once("finish",N);function O(){St("unpipe"),r.unpipe(e)}return e.emit("pipe",r),n.flowing||(St("pipe resume"),r.resume()),e};function kce(e){return function(){var t=e._readableState;St("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,t.awaitDrain===0&&fL(e,"data")&&(t.flowing=!0,Nw(e))}}$t.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(t.pipesCount===0)return this;if(t.pipesCount===1)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r),this);if(!e){var n=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var s=0;s=t.length?(t.decoder?r=t.buffer.join(""):t.buffer.length===1?r=t.buffer.head.data:r=t.buffer.concat(t.length),t.buffer.clear()):r=Pce(e,t.buffer,t.decoder),r}function Pce(e,t,r){var n;return es.length?s.length:e;if(o===s.length?i+=s:i+=s.slice(0,e),e-=o,e===0){o===s.length?(++n,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=s.slice(o));break}++n}return t.length-=n,i}function Hce(e,t){var r=ud.allocUnsafe(e),n=t.head,i=1;for(n.data.copy(r),e-=n.data.length;n=n.next;){var s=n.data,o=e>s.length?s.length:e;if(s.copy(r,r.length-e,0,o),e-=o,e===0){o===s.length?(++i,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=s.slice(o));break}++i}return t.length-=i,r}function Dw(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,Nc.nextTick(qce,t,e))}function qce(e,t){!e.endEmitted&&e.length===0&&(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function pL(e,t){for(var r=0,n=e.length;r{"use strict";BL.exports=Zo;var GE=If(),mL=Object.create(Rc());mL.inherits=je();mL.inherits(Zo,GE);function Gce(e,t){var r=this._transformState;r.transforming=!1;var n=r.writecb;if(!n)return this.emit("error",new Error("write callback called multiple times"));r.writechunk=null,r.writecb=null,t!=null&&this.push(t),n(e);var i=this._readableState;i.reading=!1,(i.needReadable||i.length{"use strict";CL.exports=cd;var IL=Mw(),bL=Object.create(Rc());bL.inherits=je();bL.inherits(cd,IL);function cd(e){if(!(this instanceof cd))return new cd(e);IL.call(this,e)}cd.prototype._transform=function(e,t,r){r(null,e)}});var Fw=U((to,wL)=>{to=wL.exports=Sw();to.Stream=to;to.Readable=to;to.Writable=Cw();to.Duplex=If();to.Transform=Mw();to.PassThrough=QL()});var kw=U((WTe,_L)=>{"use strict";var Wce=at().Buffer,Vce=P3(),SL=Fw().Transform,Jce=je();function sA(e){SL.call(this),this._block=Wce.allocUnsafe(e),this._blockSize=e,this._blockOffset=0,this._length=[0,0,0,0],this._finalized=!1}Jce(sA,SL);sA.prototype._transform=function(e,t,r){var n=null;try{this.update(e,t)}catch(i){n=i}r(n)};sA.prototype._flush=function(e){var t=null;try{this.push(this.digest())}catch(r){t=r}e(t)};sA.prototype.update=function(e,t){if(this._finalized)throw new Error("Digest already called");for(var r=Vce(e,t),n=this._block,i=0;this._blockOffset+r.length-i>=this._blockSize;){for(var s=this._blockOffset;s0;++o)this._length[o]+=a,a=this._length[o]/4294967296|0,a>0&&(this._length[o]-=4294967296*a);return this};sA.prototype._update=function(){throw new Error("_update is not implemented")};sA.prototype.digest=function(e){if(this._finalized)throw new Error("Digest already called");this._finalized=!0;var t=this._digest();e!==void 0&&(t=t.toString(e)),this._block.fill(0),this._blockOffset=0;for(var r=0;r<4;++r)this._length[r]=0;return t};sA.prototype._digest=function(){throw new Error("_digest is not implemented")};_L.exports=sA});var VE=U((VTe,RL)=>{"use strict";var jce=je(),vL=kw(),zce=at().Buffer,Kce=new Array(16);function YE(){vL.call(this,64),this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878}jce(YE,vL);YE.prototype._update=function(){for(var e=Kce,t=0;t<16;++t)e[t]=this._block.readInt32LE(t*4);var r=this._a,n=this._b,i=this._c,s=this._d;r=nn(r,n,i,s,e[0],3614090360,7),s=nn(s,r,n,i,e[1],3905402710,12),i=nn(i,s,r,n,e[2],606105819,17),n=nn(n,i,s,r,e[3],3250441966,22),r=nn(r,n,i,s,e[4],4118548399,7),s=nn(s,r,n,i,e[5],1200080426,12),i=nn(i,s,r,n,e[6],2821735955,17),n=nn(n,i,s,r,e[7],4249261313,22),r=nn(r,n,i,s,e[8],1770035416,7),s=nn(s,r,n,i,e[9],2336552879,12),i=nn(i,s,r,n,e[10],4294925233,17),n=nn(n,i,s,r,e[11],2304563134,22),r=nn(r,n,i,s,e[12],1804603682,7),s=nn(s,r,n,i,e[13],4254626195,12),i=nn(i,s,r,n,e[14],2792965006,17),n=nn(n,i,s,r,e[15],1236535329,22),r=sn(r,n,i,s,e[1],4129170786,5),s=sn(s,r,n,i,e[6],3225465664,9),i=sn(i,s,r,n,e[11],643717713,14),n=sn(n,i,s,r,e[0],3921069994,20),r=sn(r,n,i,s,e[5],3593408605,5),s=sn(s,r,n,i,e[10],38016083,9),i=sn(i,s,r,n,e[15],3634488961,14),n=sn(n,i,s,r,e[4],3889429448,20),r=sn(r,n,i,s,e[9],568446438,5),s=sn(s,r,n,i,e[14],3275163606,9),i=sn(i,s,r,n,e[3],4107603335,14),n=sn(n,i,s,r,e[8],1163531501,20),r=sn(r,n,i,s,e[13],2850285829,5),s=sn(s,r,n,i,e[2],4243563512,9),i=sn(i,s,r,n,e[7],1735328473,14),n=sn(n,i,s,r,e[12],2368359562,20),r=on(r,n,i,s,e[5],4294588738,4),s=on(s,r,n,i,e[8],2272392833,11),i=on(i,s,r,n,e[11],1839030562,16),n=on(n,i,s,r,e[14],4259657740,23),r=on(r,n,i,s,e[1],2763975236,4),s=on(s,r,n,i,e[4],1272893353,11),i=on(i,s,r,n,e[7],4139469664,16),n=on(n,i,s,r,e[10],3200236656,23),r=on(r,n,i,s,e[13],681279174,4),s=on(s,r,n,i,e[0],3936430074,11),i=on(i,s,r,n,e[3],3572445317,16),n=on(n,i,s,r,e[6],76029189,23),r=on(r,n,i,s,e[9],3654602809,4),s=on(s,r,n,i,e[12],3873151461,11),i=on(i,s,r,n,e[15],530742520,16),n=on(n,i,s,r,e[2],3299628645,23),r=an(r,n,i,s,e[0],4096336452,6),s=an(s,r,n,i,e[7],1126891415,10),i=an(i,s,r,n,e[14],2878612391,15),n=an(n,i,s,r,e[5],4237533241,21),r=an(r,n,i,s,e[12],1700485571,6),s=an(s,r,n,i,e[3],2399980690,10),i=an(i,s,r,n,e[10],4293915773,15),n=an(n,i,s,r,e[1],2240044497,21),r=an(r,n,i,s,e[8],1873313359,6),s=an(s,r,n,i,e[15],4264355552,10),i=an(i,s,r,n,e[6],2734768916,15),n=an(n,i,s,r,e[13],1309151649,21),r=an(r,n,i,s,e[4],4149444226,6),s=an(s,r,n,i,e[11],3174756917,10),i=an(i,s,r,n,e[2],718787259,15),n=an(n,i,s,r,e[9],3951481745,21),this._a=this._a+r|0,this._b=this._b+n|0,this._c=this._c+i|0,this._d=this._d+s|0};YE.prototype._digest=function(){this._block[this._blockOffset++]=128,this._blockOffset>56&&(this._block.fill(0,this._blockOffset,64),this._update(),this._blockOffset=0),this._block.fill(0,this._blockOffset,56),this._block.writeUInt32LE(this._length[0],56),this._block.writeUInt32LE(this._length[1],60),this._update();var e=zce.allocUnsafe(16);return e.writeInt32LE(this._a,0),e.writeInt32LE(this._b,4),e.writeInt32LE(this._c,8),e.writeInt32LE(this._d,12),e};function WE(e,t){return e<>>32-t}function nn(e,t,r,n,i,s,o){return WE(e+(t&r|~t&n)+i+s|0,o)+t|0}function sn(e,t,r,n,i,s,o){return WE(e+(t&n|r&~n)+i+s|0,o)+t|0}function on(e,t,r,n,i,s,o){return WE(e+(t^r^n)+i+s|0,o)+t|0}function an(e,t,r,n,i,s,o){return WE(e+(r^(t|~n))+i+s|0,o)+t|0}RL.exports=YE});var jE=U((JTe,UL)=>{"use strict";var Uw=Gr().Buffer,Xce=je(),kL=kw(),Zce=new Array(16),ld=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13],hd=[5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11],dd=[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6],gd=[8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11],pd=[0,1518500249,1859775393,2400959708,2840853838],Ed=[1352829926,1548603684,1836072691,2053994217,0];function bf(e,t){return e<>>32-t}function DL(e,t,r,n,i,s,o,a){return bf(e+(t^r^n)+s+o|0,a)+i|0}function TL(e,t,r,n,i,s,o,a){return bf(e+(t&r|~t&n)+s+o|0,a)+i|0}function NL(e,t,r,n,i,s,o,a){return bf(e+((t|~r)^n)+s+o|0,a)+i|0}function ML(e,t,r,n,i,s,o,a){return bf(e+(t&n|r&~n)+s+o|0,a)+i|0}function FL(e,t,r,n,i,s,o,a){return bf(e+(t^(r|~n))+s+o|0,a)+i|0}function JE(){kL.call(this,64),this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520}Xce(JE,kL);JE.prototype._update=function(){for(var e=Zce,t=0;t<16;++t)e[t]=this._block.readInt32LE(t*4);for(var r=this._a|0,n=this._b|0,i=this._c|0,s=this._d|0,o=this._e|0,a=this._a|0,A=this._b|0,f=this._c|0,l=this._d|0,p=this._e|0,I=0;I<80;I+=1){var S,_;I<16?(S=DL(r,n,i,s,o,e[ld[I]],pd[0],dd[I]),_=FL(a,A,f,l,p,e[hd[I]],Ed[0],gd[I])):I<32?(S=TL(r,n,i,s,o,e[ld[I]],pd[1],dd[I]),_=ML(a,A,f,l,p,e[hd[I]],Ed[1],gd[I])):I<48?(S=NL(r,n,i,s,o,e[ld[I]],pd[2],dd[I]),_=NL(a,A,f,l,p,e[hd[I]],Ed[2],gd[I])):I<64?(S=ML(r,n,i,s,o,e[ld[I]],pd[3],dd[I]),_=TL(a,A,f,l,p,e[hd[I]],Ed[3],gd[I])):(S=FL(r,n,i,s,o,e[ld[I]],pd[4],dd[I]),_=DL(a,A,f,l,p,e[hd[I]],Ed[4],gd[I])),r=o,o=s,s=bf(i,10),i=n,n=S,a=p,p=l,l=bf(f,10),f=A,A=_}var N=this._b+i+l|0;this._b=this._c+s+p|0,this._c=this._d+o+a|0,this._d=this._e+r+A|0,this._e=this._a+n+f|0,this._a=N};JE.prototype._digest=function(){this._block[this._blockOffset]=128,this._blockOffset+=1,this._blockOffset>56&&(this._block.fill(0,this._blockOffset,64),this._update(),this._blockOffset=0),this._block.fill(0,this._blockOffset,56),this._block.writeUInt32LE(this._length[0],56),this._block.writeUInt32LE(this._length[1],60),this._update();var e=Uw.alloc?Uw.alloc(20):new Uw(20);return e.writeInt32LE(this._a,0),e.writeInt32LE(this._b,4),e.writeInt32LE(this._c,8),e.writeInt32LE(this._d,12),e.writeInt32LE(this._e,16),e};UL.exports=JE});var Cf=U((jTe,xL)=>{"use strict";var $ce=at().Buffer,ele=id();function zE(e,t){this._block=$ce.alloc(e),this._finalSize=t,this._blockSize=e,this._len=0}zE.prototype.update=function(e,t){e=ele(e,t||"utf8");for(var r=this._block,n=this._blockSize,i=e.length,s=this._len,o=0;o=this._finalSize&&(this._update(this._block),this._block.fill(0));var r=this._len*8;if(r<=4294967295)this._block.writeUInt32BE(r,this._blockSize-4);else{var n=(r&4294967295)>>>0,i=(r-n)/4294967296;this._block.writeUInt32BE(i,this._blockSize-8),this._block.writeUInt32BE(n,this._blockSize-4)}this._update(this._block);var s=this._hash();return e?s.toString(e):s};zE.prototype._update=function(){throw new Error("_update must be implemented by subclass")};xL.exports=zE});var OL=U((zTe,PL)=>{"use strict";var tle=je(),LL=Cf(),rle=at().Buffer,nle=[1518500249,1859775393,-1894007588,-899497514],ile=new Array(80);function yd(){this.init(),this._w=ile,LL.call(this,64,56)}tle(yd,LL);yd.prototype.init=function(){return this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520,this};function sle(e){return e<<5|e>>>27}function ole(e){return e<<30|e>>>2}function ale(e,t,r,n){return e===0?t&r|~t&n:e===2?t&r|t&n|r&n:t^r^n}yd.prototype._update=function(e){for(var t=this._w,r=this._a|0,n=this._b|0,i=this._c|0,s=this._d|0,o=this._e|0,a=0;a<16;++a)t[a]=e.readInt32BE(a*4);for(;a<80;++a)t[a]=t[a-3]^t[a-8]^t[a-14]^t[a-16];for(var A=0;A<80;++A){var f=~~(A/20),l=sle(r)+ale(f,n,i,s)+o+t[A]+nle[f]|0;o=s,s=i,i=ole(n),n=r,r=l}this._a=r+this._a|0,this._b=n+this._b|0,this._c=i+this._c|0,this._d=s+this._d|0,this._e=o+this._e|0};yd.prototype._hash=function(){var e=rle.allocUnsafe(20);return e.writeInt32BE(this._a|0,0),e.writeInt32BE(this._b|0,4),e.writeInt32BE(this._c|0,8),e.writeInt32BE(this._d|0,12),e.writeInt32BE(this._e|0,16),e};PL.exports=yd});var GL=U((KTe,qL)=>{"use strict";var Ale=je(),HL=Cf(),fle=at().Buffer,ule=[1518500249,1859775393,-1894007588,-899497514],cle=new Array(80);function md(){this.init(),this._w=cle,HL.call(this,64,56)}Ale(md,HL);md.prototype.init=function(){return this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520,this};function lle(e){return e<<1|e>>>31}function hle(e){return e<<5|e>>>27}function dle(e){return e<<30|e>>>2}function gle(e,t,r,n){return e===0?t&r|~t&n:e===2?t&r|t&n|r&n:t^r^n}md.prototype._update=function(e){for(var t=this._w,r=this._a|0,n=this._b|0,i=this._c|0,s=this._d|0,o=this._e|0,a=0;a<16;++a)t[a]=e.readInt32BE(a*4);for(;a<80;++a)t[a]=lle(t[a-3]^t[a-8]^t[a-14]^t[a-16]);for(var A=0;A<80;++A){var f=~~(A/20),l=hle(r)+gle(f,n,i,s)+o+t[A]+ule[f]|0;o=s,s=i,i=dle(n),n=r,r=l}this._a=r+this._a|0,this._b=n+this._b|0,this._c=i+this._c|0,this._d=s+this._d|0,this._e=o+this._e|0};md.prototype._hash=function(){var e=fle.allocUnsafe(20);return e.writeInt32BE(this._a|0,0),e.writeInt32BE(this._b|0,4),e.writeInt32BE(this._c|0,8),e.writeInt32BE(this._d|0,12),e.writeInt32BE(this._e|0,16),e};qL.exports=md});var xw=U((XTe,WL)=>{"use strict";var ple=je(),YL=Cf(),Ele=at().Buffer,yle=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],mle=new Array(64);function Bd(){this.init(),this._w=mle,YL.call(this,64,56)}ple(Bd,YL);Bd.prototype.init=function(){return this._a=1779033703,this._b=3144134277,this._c=1013904242,this._d=2773480762,this._e=1359893119,this._f=2600822924,this._g=528734635,this._h=1541459225,this};function Ble(e,t,r){return r^e&(t^r)}function Ile(e,t,r){return e&t|r&(e|t)}function ble(e){return(e>>>2|e<<30)^(e>>>13|e<<19)^(e>>>22|e<<10)}function Cle(e){return(e>>>6|e<<26)^(e>>>11|e<<21)^(e>>>25|e<<7)}function Qle(e){return(e>>>7|e<<25)^(e>>>18|e<<14)^e>>>3}function wle(e){return(e>>>17|e<<15)^(e>>>19|e<<13)^e>>>10}Bd.prototype._update=function(e){for(var t=this._w,r=this._a|0,n=this._b|0,i=this._c|0,s=this._d|0,o=this._e|0,a=this._f|0,A=this._g|0,f=this._h|0,l=0;l<16;++l)t[l]=e.readInt32BE(l*4);for(;l<64;++l)t[l]=wle(t[l-2])+t[l-7]+Qle(t[l-15])+t[l-16]|0;for(var p=0;p<64;++p){var I=f+Cle(o)+Ble(o,a,A)+yle[p]+t[p]|0,S=ble(r)+Ile(r,n,i)|0;f=A,A=a,a=o,o=s+I|0,s=i,i=n,n=r,r=I+S|0}this._a=r+this._a|0,this._b=n+this._b|0,this._c=i+this._c|0,this._d=s+this._d|0,this._e=o+this._e|0,this._f=a+this._f|0,this._g=A+this._g|0,this._h=f+this._h|0};Bd.prototype._hash=function(){var e=Ele.allocUnsafe(32);return e.writeInt32BE(this._a,0),e.writeInt32BE(this._b,4),e.writeInt32BE(this._c,8),e.writeInt32BE(this._d,12),e.writeInt32BE(this._e,16),e.writeInt32BE(this._f,20),e.writeInt32BE(this._g,24),e.writeInt32BE(this._h,28),e};WL.exports=Bd});var JL=U((ZTe,VL)=>{"use strict";var Sle=je(),_le=xw(),vle=Cf(),Rle=at().Buffer,Dle=new Array(64);function KE(){this.init(),this._w=Dle,vle.call(this,64,56)}Sle(KE,_le);KE.prototype.init=function(){return this._a=3238371032,this._b=914150663,this._c=812702999,this._d=4144912697,this._e=4290775857,this._f=1750603025,this._g=1694076839,this._h=3204075428,this};KE.prototype._hash=function(){var e=Rle.allocUnsafe(28);return e.writeInt32BE(this._a,0),e.writeInt32BE(this._b,4),e.writeInt32BE(this._c,8),e.writeInt32BE(this._d,12),e.writeInt32BE(this._e,16),e.writeInt32BE(this._f,20),e.writeInt32BE(this._g,24),e};VL.exports=KE});var Lw=U(($Te,e8)=>{"use strict";var Tle=je(),$L=Cf(),Nle=at().Buffer,jL=[1116352408,3609767458,1899447441,602891725,3049323471,3964484399,3921009573,2173295548,961987163,4081628472,1508970993,3053834265,2453635748,2937671579,2870763221,3664609560,3624381080,2734883394,310598401,1164996542,607225278,1323610764,1426881987,3590304994,1925078388,4068182383,2162078206,991336113,2614888103,633803317,3248222580,3479774868,3835390401,2666613458,4022224774,944711139,264347078,2341262773,604807628,2007800933,770255983,1495990901,1249150122,1856431235,1555081692,3175218132,1996064986,2198950837,2554220882,3999719339,2821834349,766784016,2952996808,2566594879,3210313671,3203337956,3336571891,1034457026,3584528711,2466948901,113926993,3758326383,338241895,168717936,666307205,1188179964,773529912,1546045734,1294757372,1522805485,1396182291,2643833823,1695183700,2343527390,1986661051,1014477480,2177026350,1206759142,2456956037,344077627,2730485921,1290863460,2820302411,3158454273,3259730800,3505952657,3345764771,106217008,3516065817,3606008344,3600352804,1432725776,4094571909,1467031594,275423344,851169720,430227734,3100823752,506948616,1363258195,659060556,3750685593,883997877,3785050280,958139571,3318307427,1322822218,3812723403,1537002063,2003034995,1747873779,3602036899,1955562222,1575990012,2024104815,1125592928,2227730452,2716904306,2361852424,442776044,2428436474,593698344,2756734187,3733110249,3204031479,2999351573,3329325298,3815920427,3391569614,3928383900,3515267271,566280711,3940187606,3454069534,4118630271,4000239992,116418474,1914138554,174292421,2731055270,289380356,3203993006,460393269,320620315,685471733,587496836,852142971,1086792851,1017036298,365543100,1126000580,2618297676,1288033470,3409855158,1501505948,4234509866,1607167915,987167468,1816402316,1246189591],Mle=new Array(160);function Id(){this.init(),this._w=Mle,$L.call(this,128,112)}Tle(Id,$L);Id.prototype.init=function(){return this._ah=1779033703,this._bh=3144134277,this._ch=1013904242,this._dh=2773480762,this._eh=1359893119,this._fh=2600822924,this._gh=528734635,this._hh=1541459225,this._al=4089235720,this._bl=2227873595,this._cl=4271175723,this._dl=1595750129,this._el=2917565137,this._fl=725511199,this._gl=4215389547,this._hl=327033209,this};function zL(e,t,r){return r^e&(t^r)}function KL(e,t,r){return e&t|r&(e|t)}function XL(e,t){return(e>>>28|t<<4)^(t>>>2|e<<30)^(t>>>7|e<<25)}function ZL(e,t){return(e>>>14|t<<18)^(e>>>18|t<<14)^(t>>>9|e<<23)}function Fle(e,t){return(e>>>1|t<<31)^(e>>>8|t<<24)^e>>>7}function kle(e,t){return(e>>>1|t<<31)^(e>>>8|t<<24)^(e>>>7|t<<25)}function Ule(e,t){return(e>>>19|t<<13)^(t>>>29|e<<3)^e>>>6}function xle(e,t){return(e>>>19|t<<13)^(t>>>29|e<<3)^(e>>>6|t<<26)}function Fr(e,t){return e>>>0>>0?1:0}Id.prototype._update=function(e){for(var t=this._w,r=this._ah|0,n=this._bh|0,i=this._ch|0,s=this._dh|0,o=this._eh|0,a=this._fh|0,A=this._gh|0,f=this._hh|0,l=this._al|0,p=this._bl|0,I=this._cl|0,S=this._dl|0,_=this._el|0,N=this._fl|0,O=this._gl|0,x=this._hl|0,G=0;G<32;G+=2)t[G]=e.readInt32BE(G*4),t[G+1]=e.readInt32BE(G*4+4);for(;G<160;G+=2){var Y=t[G-30],X=t[G-30+1],Z=Fle(Y,X),j=kle(X,Y);Y=t[G-4],X=t[G-4+1];var se=Ule(Y,X),ie=xle(X,Y),ce=t[G-14],H=t[G-14+1],E=t[G-32],v=t[G-32+1],b=j+H|0,c=Z+ce+Fr(b,j)|0;b=b+ie|0,c=c+se+Fr(b,ie)|0,b=b+v|0,c=c+E+Fr(b,v)|0,t[G]=c,t[G+1]=b}for(var g=0;g<160;g+=2){c=t[g],b=t[g+1];var w=KL(r,n,i),R=KL(l,p,I),C=XL(r,l),h=XL(l,r),D=ZL(o,_),M=ZL(_,o),B=jL[g],k=jL[g+1],ne=zL(o,a,A),Ae=zL(_,N,O),ue=x+M|0,pe=f+D+Fr(ue,x)|0;ue=ue+Ae|0,pe=pe+ne+Fr(ue,Ae)|0,ue=ue+k|0,pe=pe+B+Fr(ue,k)|0,ue=ue+b|0,pe=pe+c+Fr(ue,b)|0;var he=h+R|0,de=C+w+Fr(he,h)|0;f=A,x=O,A=a,O=N,a=o,N=_,_=S+ue|0,o=s+pe+Fr(_,S)|0,s=i,S=I,i=n,I=p,n=r,p=l,l=ue+he|0,r=pe+de+Fr(l,ue)|0}this._al=this._al+l|0,this._bl=this._bl+p|0,this._cl=this._cl+I|0,this._dl=this._dl+S|0,this._el=this._el+_|0,this._fl=this._fl+N|0,this._gl=this._gl+O|0,this._hl=this._hl+x|0,this._ah=this._ah+r+Fr(this._al,l)|0,this._bh=this._bh+n+Fr(this._bl,p)|0,this._ch=this._ch+i+Fr(this._cl,I)|0,this._dh=this._dh+s+Fr(this._dl,S)|0,this._eh=this._eh+o+Fr(this._el,_)|0,this._fh=this._fh+a+Fr(this._fl,N)|0,this._gh=this._gh+A+Fr(this._gl,O)|0,this._hh=this._hh+f+Fr(this._hl,x)|0};Id.prototype._hash=function(){var e=Nle.allocUnsafe(64);function t(r,n,i){e.writeInt32BE(r,i),e.writeInt32BE(n,i+4)}return t(this._ah,this._al,0),t(this._bh,this._bl,8),t(this._ch,this._cl,16),t(this._dh,this._dl,24),t(this._eh,this._el,32),t(this._fh,this._fl,40),t(this._gh,this._gl,48),t(this._hh,this._hl,56),e};e8.exports=Id});var r8=U((eNe,t8)=>{"use strict";var Lle=je(),Ple=Lw(),Ole=Cf(),Hle=at().Buffer,qle=new Array(160);function XE(){this.init(),this._w=qle,Ole.call(this,128,112)}Lle(XE,Ple);XE.prototype.init=function(){return this._ah=3418070365,this._bh=1654270250,this._ch=2438529370,this._dh=355462360,this._eh=1731405415,this._fh=2394180231,this._gh=3675008525,this._hh=1203062813,this._al=3238371032,this._bl=914150663,this._cl=812702999,this._dl=4144912697,this._el=4290775857,this._fl=1750603025,this._gl=1694076839,this._hl=3204075428,this};XE.prototype._hash=function(){var e=Hle.allocUnsafe(48);function t(r,n,i){e.writeInt32BE(r,i),e.writeInt32BE(n,i+4)}return t(this._ah,this._al,0),t(this._bh,this._bl,8),t(this._ch,this._cl,16),t(this._dh,this._dl,24),t(this._eh,this._el,32),t(this._fh,this._fl,40),e};t8.exports=XE});var ZE=U((tNe,$o)=>{"use strict";$o.exports=function(t){var r=t.toLowerCase(),n=$o.exports[r];if(!n)throw new Error(r+" is not supported (we accept pull requests)");return new n};$o.exports.sha=OL();$o.exports.sha1=GL();$o.exports.sha224=JL();$o.exports.sha256=xw();$o.exports.sha384=r8();$o.exports.sha512=Lw()});var ea=U((rNe,i8)=>{"use strict";var Gle=at().Buffer,n8=(ts(),Os(qt)).Transform,Yle=sf().StringDecoder,Wle=je(),Vle=id();function os(e){n8.call(this),this.hashMode=typeof e=="string",this.hashMode?this[e]=this._finalOrDigest:this.final=this._finalOrDigest,this._final&&(this.__final=this._final,this._final=null),this._decoder=null,this._encoding=null}Wle(os,n8);os.prototype.update=function(e,t,r){var n=Vle(e,t),i=this._update(n);return this.hashMode?this:(r&&(i=this._toString(i,r)),i)};os.prototype.setAutoPadding=function(){};os.prototype.getAuthTag=function(){throw new Error("trying to get auth tag in unsupported state")};os.prototype.setAuthTag=function(){throw new Error("trying to set auth tag in unsupported state")};os.prototype.setAAD=function(){throw new Error("trying to set aad in unsupported state")};os.prototype._transform=function(e,t,r){var n;try{this.hashMode?this._update(e):this.push(this._update(e))}catch(i){n=i}finally{r(n)}};os.prototype._flush=function(e){var t;try{this.push(this.__final())}catch(r){t=r}e(t)};os.prototype._finalOrDigest=function(e){var t=this.__final()||Gle.alloc(0);return e&&(t=this._toString(t,e,!0)),t};os.prototype._toString=function(e,t,r){if(this._decoder||(this._decoder=new Yle(t),this._encoding=t),this._encoding!==t)throw new Error("can\u2019t switch encodings");var n=this._decoder.write(e);return r&&(n+=this._decoder.end()),n};i8.exports=os});var Mc=U((nNe,o8)=>{"use strict";var Jle=je(),jle=VE(),zle=jE(),Kle=ZE(),s8=ea();function $E(e){s8.call(this,"digest"),this._hash=e}Jle($E,s8);$E.prototype._update=function(e){this._hash.update(e)};$E.prototype._final=function(){return this._hash.digest()};o8.exports=function(t){return t=t.toLowerCase(),t==="md5"?new jle:t==="rmd160"||t==="ripemd160"?new zle:new $E(Kle(t))}});var f8=U((iNe,A8)=>{"use strict";var Xle=je(),Qf=at().Buffer,a8=ea(),Zle=Qf.alloc(128),Fc=64;function ey(e,t){a8.call(this,"digest"),typeof t=="string"&&(t=Qf.from(t)),this._alg=e,this._key=t,t.length>Fc?t=e(t):t.length{var $le=VE();u8.exports=function(e){return new $le().update(e).digest()}});var qw=U((oNe,l8)=>{"use strict";var ehe=je(),the=f8(),c8=ea(),bd=at().Buffer,rhe=Pw(),Ow=jE(),Hw=ZE(),nhe=bd.alloc(128);function Cd(e,t){c8.call(this,"digest"),typeof t=="string"&&(t=bd.from(t));var r=e==="sha512"||e==="sha384"?128:64;if(this._alg=e,this._key=t,t.length>r){var n=e==="rmd160"?new Ow:Hw(e);t=n.update(t).digest()}else t.length{ihe.exports={sha224WithRSAEncryption:{sign:"rsa",hash:"sha224",id:"302d300d06096086480165030402040500041c"},"RSA-SHA224":{sign:"ecdsa/rsa",hash:"sha224",id:"302d300d06096086480165030402040500041c"},sha256WithRSAEncryption:{sign:"rsa",hash:"sha256",id:"3031300d060960864801650304020105000420"},"RSA-SHA256":{sign:"ecdsa/rsa",hash:"sha256",id:"3031300d060960864801650304020105000420"},sha384WithRSAEncryption:{sign:"rsa",hash:"sha384",id:"3041300d060960864801650304020205000430"},"RSA-SHA384":{sign:"ecdsa/rsa",hash:"sha384",id:"3041300d060960864801650304020205000430"},sha512WithRSAEncryption:{sign:"rsa",hash:"sha512",id:"3051300d060960864801650304020305000440"},"RSA-SHA512":{sign:"ecdsa/rsa",hash:"sha512",id:"3051300d060960864801650304020305000440"},"RSA-SHA1":{sign:"rsa",hash:"sha1",id:"3021300906052b0e03021a05000414"},"ecdsa-with-SHA1":{sign:"ecdsa",hash:"sha1",id:""},sha256:{sign:"ecdsa",hash:"sha256",id:""},sha224:{sign:"ecdsa",hash:"sha224",id:""},sha384:{sign:"ecdsa",hash:"sha384",id:""},sha512:{sign:"ecdsa",hash:"sha512",id:""},"DSA-SHA":{sign:"dsa",hash:"sha1",id:""},"DSA-SHA1":{sign:"dsa",hash:"sha1",id:""},DSA:{sign:"dsa",hash:"sha1",id:""},"DSA-WITH-SHA224":{sign:"dsa",hash:"sha224",id:""},"DSA-SHA224":{sign:"dsa",hash:"sha224",id:""},"DSA-WITH-SHA256":{sign:"dsa",hash:"sha256",id:""},"DSA-SHA256":{sign:"dsa",hash:"sha256",id:""},"DSA-WITH-SHA384":{sign:"dsa",hash:"sha384",id:""},"DSA-SHA384":{sign:"dsa",hash:"sha384",id:""},"DSA-WITH-SHA512":{sign:"dsa",hash:"sha512",id:""},"DSA-SHA512":{sign:"dsa",hash:"sha512",id:""},"DSA-RIPEMD160":{sign:"dsa",hash:"rmd160",id:""},ripemd160WithRSA:{sign:"rsa",hash:"rmd160",id:"3021300906052b2403020105000414"},"RSA-RIPEMD160":{sign:"rsa",hash:"rmd160",id:"3021300906052b2403020105000414"},md5WithRSAEncryption:{sign:"rsa",hash:"md5",id:"3020300c06082a864886f70d020505000410"},"RSA-MD5":{sign:"rsa",hash:"md5",id:"3020300c06082a864886f70d020505000410"}}});var d8=U((ANe,h8)=>{"use strict";h8.exports=Gw()});var Yw=U((fNe,g8)=>{"use strict";var she=isFinite,ohe=Math.pow(2,30)-1;g8.exports=function(e,t){if(typeof e!="number")throw new TypeError("Iterations not a number");if(e<0||!she(e))throw new TypeError("Bad iterations");if(typeof t!="number")throw new TypeError("Key length not a number");if(t<0||t>ohe||t!==t)throw new TypeError("Bad key length")}});var Ww=U((uNe,E8)=>{"use strict";var ty;globalThis.process&&globalThis.process.browser?ty="utf-8":globalThis.process&&globalThis.process.version?(p8=parseInt(process.version.split(".")[0].slice(1),10),ty=p8>=6?"utf-8":"binary"):ty="utf-8";var p8;E8.exports=ty});var Vw=U((cNe,B8)=>{"use strict";var ahe=at().Buffer,Ahe=id(),m8=typeof Uint8Array<"u",fhe=m8&&typeof ArrayBuffer<"u",y8=fhe&&ArrayBuffer.isView;B8.exports=function(e,t,r){if(typeof e=="string"||ahe.isBuffer(e)||m8&&e instanceof Uint8Array||y8&&y8(e))return Ahe(e,t);throw new TypeError(r+" must be a string, a Buffer, a Uint8Array, or a DataView")}});var Jw=U((lNe,Q8)=>{"use strict";var uhe=Pw(),che=jE(),lhe=ZE(),wf=at().Buffer,hhe=Yw(),I8=Ww(),b8=Vw(),dhe=wf.alloc(128),ry={__proto__:null,md5:16,sha1:20,sha224:28,sha256:32,sha384:48,sha512:64,"sha512-256":32,ripemd160:20,rmd160:20},ghe={__proto__:null,"sha-1":"sha1","sha-224":"sha224","sha-256":"sha256","sha-384":"sha384","sha-512":"sha512","ripemd-160":"ripemd160"};function phe(e){return new che().update(e).digest()}function Ehe(e){function t(r){return lhe(e).update(r).digest()}return e==="rmd160"||e==="ripemd160"?phe:e==="md5"?uhe:t}function C8(e,t,r){var n=Ehe(e),i=e==="sha512"||e==="sha384"?128:64;t.length>i?t=n(t):t.length{"use strict";var v8=at().Buffer,mhe=Yw(),w8=Ww(),S8=Jw(),_8=Vw(),ny,Qd=globalThis.crypto&&globalThis.crypto.subtle,Bhe={sha:"SHA-1","sha-1":"SHA-1",sha1:"SHA-1",sha256:"SHA-256","sha-256":"SHA-256",sha384:"SHA-384","sha-384":"SHA-384","sha-512":"SHA-512",sha512:"SHA-512"},jw=[],Sf;function zw(){return Sf||(globalThis.process&&globalThis.process.nextTick?Sf=globalThis.process.nextTick:globalThis.queueMicrotask?Sf=globalThis.queueMicrotask:globalThis.setImmediate?Sf=globalThis.setImmediate:Sf=globalThis.setTimeout,Sf)}function R8(e,t,r,n,i){return Qd.importKey("raw",e,{name:"PBKDF2"},!1,["deriveBits"]).then(function(s){return Qd.deriveBits({name:"PBKDF2",salt:t,iterations:r,hash:{name:i}},s,n<<3)}).then(function(s){return v8.from(s)})}function Ihe(e){if(globalThis.process&&!globalThis.process.browser||!Qd||!Qd.importKey||!Qd.deriveBits)return Promise.resolve(!1);if(jw[e]!==void 0)return jw[e];ny=ny||v8.alloc(8);var t=R8(ny,ny,10,128,e).then(function(){return!0},function(){return!1});return jw[e]=t,t}function bhe(e,t){e.then(function(r){zw()(function(){t(null,r)})},function(r){zw()(function(){t(r)})})}D8.exports=function(e,t,r,n,i,s){if(typeof i=="function"&&(s=i,i=void 0),mhe(r,n),e=_8(e,w8,"Password"),t=_8(t,w8,"Salt"),typeof s!="function")throw new Error("No callback provided to pbkdf2");i=i||"sha1";var o=Bhe[i.toLowerCase()];if(!o||typeof globalThis.Promise!="function"){zw()(function(){var a;try{a=S8(e,t,r,n,i)}catch(A){s(A);return}s(null,a)});return}bhe(Ihe(o).then(function(a){return a?R8(e,t,r,n,o):S8(e,t,r,n,i)}),s)}});var Xw=U(Kw=>{"use strict";Kw.pbkdf2=T8();Kw.pbkdf2Sync=Jw()});var Zw=U(Ii=>{"use strict";Ii.readUInt32BE=function(t,r){var n=t[0+r]<<24|t[1+r]<<16|t[2+r]<<8|t[3+r];return n>>>0};Ii.writeUInt32BE=function(t,r,n){t[0+n]=r>>>24,t[1+n]=r>>>16&255,t[2+n]=r>>>8&255,t[3+n]=r&255};Ii.ip=function(t,r,n,i){for(var s=0,o=0,a=6;a>=0;a-=2){for(var A=0;A<=24;A+=8)s<<=1,s|=r>>>A+a&1;for(var A=0;A<=24;A+=8)s<<=1,s|=t>>>A+a&1}for(var a=6;a>=0;a-=2){for(var A=1;A<=25;A+=8)o<<=1,o|=r>>>A+a&1;for(var A=1;A<=25;A+=8)o<<=1,o|=t>>>A+a&1}n[i+0]=s>>>0,n[i+1]=o>>>0};Ii.rip=function(t,r,n,i){for(var s=0,o=0,a=0;a<4;a++)for(var A=24;A>=0;A-=8)s<<=1,s|=r>>>A+a&1,s<<=1,s|=t>>>A+a&1;for(var a=4;a<8;a++)for(var A=24;A>=0;A-=8)o<<=1,o|=r>>>A+a&1,o<<=1,o|=t>>>A+a&1;n[i+0]=s>>>0,n[i+1]=o>>>0};Ii.pc1=function(t,r,n,i){for(var s=0,o=0,a=7;a>=5;a--){for(var A=0;A<=24;A+=8)s<<=1,s|=r>>A+a&1;for(var A=0;A<=24;A+=8)s<<=1,s|=t>>A+a&1}for(var A=0;A<=24;A+=8)s<<=1,s|=r>>A+a&1;for(var a=1;a<=3;a++){for(var A=0;A<=24;A+=8)o<<=1,o|=r>>A+a&1;for(var A=0;A<=24;A+=8)o<<=1,o|=t>>A+a&1}for(var A=0;A<=24;A+=8)o<<=1,o|=t>>A+a&1;n[i+0]=s>>>0,n[i+1]=o>>>0};Ii.r28shl=function(t,r){return t<>>28-r};var iy=[14,11,17,4,27,23,25,0,13,22,7,18,5,9,16,24,2,20,12,21,1,8,15,26,15,4,25,19,9,1,26,16,5,11,23,8,12,7,17,0,22,3,10,14,6,20,27,24];Ii.pc2=function(t,r,n,i){for(var s=0,o=0,a=iy.length>>>1,A=0;A>>iy[A]&1;for(var A=a;A>>iy[A]&1;n[i+0]=s>>>0,n[i+1]=o>>>0};Ii.expand=function(t,r,n){var i=0,s=0;i=(t&1)<<5|t>>>27;for(var o=23;o>=15;o-=4)i<<=6,i|=t>>>o&63;for(var o=11;o>=3;o-=4)s|=t>>>o&63,s<<=6;s|=(t&31)<<1|t>>>31,r[n+0]=i>>>0,r[n+1]=s>>>0};var N8=[14,0,4,15,13,7,1,4,2,14,15,2,11,13,8,1,3,10,10,6,6,12,12,11,5,9,9,5,0,3,7,8,4,15,1,12,14,8,8,2,13,4,6,9,2,1,11,7,15,5,12,11,9,3,7,14,3,10,10,0,5,6,0,13,15,3,1,13,8,4,14,7,6,15,11,2,3,8,4,14,9,12,7,0,2,1,13,10,12,6,0,9,5,11,10,5,0,13,14,8,7,10,11,1,10,3,4,15,13,4,1,2,5,11,8,6,12,7,6,12,9,0,3,5,2,14,15,9,10,13,0,7,9,0,14,9,6,3,3,4,15,6,5,10,1,2,13,8,12,5,7,14,11,12,4,11,2,15,8,1,13,1,6,10,4,13,9,0,8,6,15,9,3,8,0,7,11,4,1,15,2,14,12,3,5,11,10,5,14,2,7,12,7,13,13,8,14,11,3,5,0,6,6,15,9,0,10,3,1,4,2,7,8,2,5,12,11,1,12,10,4,14,15,9,10,3,6,15,9,0,0,6,12,10,11,1,7,13,13,8,15,9,1,4,3,5,14,11,5,12,2,7,8,2,4,14,2,14,12,11,4,2,1,12,7,4,10,7,11,13,6,1,8,5,5,0,3,15,15,10,13,3,0,9,14,8,9,6,4,11,2,8,1,12,11,7,10,1,13,14,7,2,8,13,15,6,9,15,12,0,5,9,6,10,3,4,0,5,14,3,12,10,1,15,10,4,15,2,9,7,2,12,6,9,8,5,0,6,13,1,3,13,4,14,14,0,7,11,5,3,11,8,9,4,14,3,15,2,5,12,2,9,8,5,12,15,3,10,7,11,0,14,4,1,10,7,1,6,13,0,11,8,6,13,4,13,11,0,2,11,14,7,15,4,0,9,8,1,13,10,3,14,12,3,9,5,7,12,5,2,10,15,6,8,1,6,1,6,4,11,11,13,13,8,12,1,3,4,7,10,14,7,10,9,15,5,6,0,8,15,0,14,5,2,9,3,2,12,13,1,2,15,8,13,4,8,6,10,15,3,11,7,1,4,10,12,9,5,3,6,14,11,5,0,0,14,12,9,7,2,7,2,11,1,4,14,1,7,9,4,12,10,14,8,2,13,0,15,6,12,10,9,13,0,15,3,3,5,5,6,8,11];Ii.substitute=function(t,r){for(var n=0,i=0;i<4;i++){var s=t>>>18-i*6&63,o=N8[i*64+s];n<<=4,n|=o}for(var i=0;i<4;i++){var s=r>>>18-i*6&63,o=N8[256+i*64+s];n<<=4,n|=o}return n>>>0};var M8=[16,25,12,11,3,20,4,15,31,17,9,6,27,14,1,22,30,24,8,18,0,5,29,23,13,19,2,26,10,21,28,7];Ii.permute=function(t){for(var r=0,n=0;n>>M8[n]&1;return r>>>0};Ii.padSplit=function(t,r,n){for(var i=t.toString(2);i.length{k8.exports=F8;function F8(e,t){if(!e)throw new Error(t||"Assertion failed")}F8.equal=function(t,r,n){if(t!=r)throw new Error(n||"Assertion failed: "+t+" != "+r)}});var sy=U((ENe,U8)=>{"use strict";var Che=zn();function bi(e){this.options=e,this.type=this.options.type,this.blockSize=8,this._init(),this.buffer=new Array(this.blockSize),this.bufferOff=0,this.padding=e.padding!==!1}U8.exports=bi;bi.prototype._init=function(){};bi.prototype.update=function(t){return t.length===0?[]:this.type==="decrypt"?this._updateDecrypt(t):this._updateEncrypt(t)};bi.prototype._buffer=function(t,r){for(var n=Math.min(this.buffer.length-this.bufferOff,t.length-r),i=0;i0;i--)r+=this._buffer(t,r),n+=this._flushBuffer(s,n);return r+=this._buffer(t,r),s};bi.prototype.final=function(t){var r;t&&(r=this.update(t));var n;return this.type==="encrypt"?n=this._finalEncrypt():n=this._finalDecrypt(),r?r.concat(n):n};bi.prototype._pad=function(t,r){if(r===0)return!1;for(;r{"use strict";var x8=zn(),Qhe=je(),vr=Zw(),L8=sy();function whe(){this.tmp=new Array(2),this.keys=null}function ro(e){L8.call(this,e);var t=new whe;this._desState=t,this.deriveKeys(t,e.key)}Qhe(ro,L8);P8.exports=ro;ro.create=function(t){return new ro(t)};var She=[1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1];ro.prototype.deriveKeys=function(t,r){t.keys=new Array(32),x8.equal(r.length,this.blockSize,"Invalid key length");var n=vr.readUInt32BE(r,0),i=vr.readUInt32BE(r,4);vr.pc1(n,i,t.tmp,0),n=t.tmp[0],i=t.tmp[1];for(var s=0;s>>1];n=vr.r28shl(n,o),i=vr.r28shl(i,o),vr.pc2(n,i,t.keys,s)}};ro.prototype._update=function(t,r,n,i){var s=this._desState,o=vr.readUInt32BE(t,r),a=vr.readUInt32BE(t,r+4);vr.ip(o,a,s.tmp,0),o=s.tmp[0],a=s.tmp[1],this.type==="encrypt"?this._encrypt(s,o,a,s.tmp,0):this._decrypt(s,o,a,s.tmp,0),o=s.tmp[0],a=s.tmp[1],vr.writeUInt32BE(n,o,i),vr.writeUInt32BE(n,a,i+4)};ro.prototype._pad=function(t,r){if(this.padding===!1)return!1;for(var n=t.length-r,i=r;i>>0,o=S}vr.rip(a,o,i,s)};ro.prototype._decrypt=function(t,r,n,i,s){for(var o=n,a=r,A=t.keys.length-2;A>=0;A-=2){var f=t.keys[A],l=t.keys[A+1];vr.expand(o,t.tmp,0),f^=t.tmp[0],l^=t.tmp[1];var p=vr.substitute(f,l),I=vr.permute(p),S=o;o=(a^I)>>>0,a=S}vr.rip(o,a,i,s)}});var H8=U(O8=>{"use strict";var _he=zn(),vhe=je(),oy={};function Rhe(e){_he.equal(e.length,8,"Invalid IV length"),this.iv=new Array(8);for(var t=0;t{"use strict";var The=zn(),Nhe=je(),q8=sy(),oA=$w();function Mhe(e,t){The.equal(t.length,24,"Invalid key length");var r=t.slice(0,8),n=t.slice(8,16),i=t.slice(16,24);e==="encrypt"?this.ciphers=[oA.create({type:"encrypt",key:r}),oA.create({type:"decrypt",key:n}),oA.create({type:"encrypt",key:i})]:this.ciphers=[oA.create({type:"decrypt",key:i}),oA.create({type:"encrypt",key:n}),oA.create({type:"decrypt",key:r})]}function _f(e){q8.call(this,e);var t=new Mhe(this.type,this.options.key);this._edeState=t}Nhe(_f,q8);G8.exports=_f;_f.create=function(t){return new _f(t)};_f.prototype._update=function(t,r,n,i){var s=this._edeState;s.ciphers[0]._update(t,r,n,i),s.ciphers[1]._update(n,i,n,i),s.ciphers[2]._update(n,i,n,i)};_f.prototype._pad=oA.prototype._pad;_f.prototype._unpad=oA.prototype._unpad});var W8=U(kc=>{"use strict";kc.utils=Zw();kc.Cipher=sy();kc.DES=$w();kc.CBC=H8();kc.EDE=Y8()});var j8=U((bNe,J8)=>{var V8=ea(),ta=W8(),Fhe=je(),vf=at().Buffer,wd={"des-ede3-cbc":ta.CBC.instantiate(ta.EDE),"des-ede3":ta.EDE,"des-ede-cbc":ta.CBC.instantiate(ta.EDE),"des-ede":ta.EDE,"des-cbc":ta.CBC.instantiate(ta.DES),"des-ecb":ta.DES};wd.des=wd["des-cbc"];wd.des3=wd["des-ede3-cbc"];J8.exports=ay;Fhe(ay,V8);function ay(e){V8.call(this);var t=e.mode.toLowerCase(),r=wd[t],n;e.decrypt?n="decrypt":n="encrypt";var i=e.key;vf.isBuffer(i)||(i=vf.from(i)),(t==="des-ede"||t==="des-ede-cbc")&&(i=vf.concat([i,i.slice(0,8)]));var s=e.iv;vf.isBuffer(s)||(s=vf.from(s)),this._des=r.create({key:i,iv:s,type:n})}ay.prototype._update=function(e){return vf.from(this._des.update(e))};ay.prototype._final=function(){return vf.from(this._des.final())}});var z8=U(eS=>{eS.encrypt=function(e,t){return e._cipher.encryptBlock(t)};eS.decrypt=function(e,t){return e._cipher.decryptBlock(t)}});var Uc=U((QNe,K8)=>{K8.exports=function(t,r){for(var n=Math.min(t.length,r.length),i=new Buffer(n),s=0;s{var X8=Uc();tS.encrypt=function(e,t){var r=X8(t,e._prev);return e._prev=e._cipher.encryptBlock(r),e._prev};tS.decrypt=function(e,t){var r=e._prev;e._prev=t;var n=e._cipher.decryptBlock(t);return X8(n,r)}});var t5=U(e5=>{var Sd=at().Buffer,khe=Uc();function $8(e,t,r){var n=t.length,i=khe(t,e._cache);return e._cache=e._cache.slice(n),e._prev=Sd.concat([e._prev,r?t:i]),i}e5.encrypt=function(e,t,r){for(var n=Sd.allocUnsafe(0),i;t.length;)if(e._cache.length===0&&(e._cache=e._cipher.encryptBlock(e._prev),e._prev=Sd.allocUnsafe(0)),e._cache.length<=t.length)i=e._cache.length,n=Sd.concat([n,$8(e,t.slice(0,i),r)]),t=t.slice(i);else{n=Sd.concat([n,$8(e,t,r)]);break}return n}});var n5=U(r5=>{var rS=at().Buffer;function Uhe(e,t,r){var n=e._cipher.encryptBlock(e._prev),i=n[0]^t;return e._prev=rS.concat([e._prev.slice(1),rS.from([r?t:i])]),i}r5.encrypt=function(e,t,r){for(var n=t.length,i=rS.allocUnsafe(n),s=-1;++s{var Ay=at().Buffer;function xhe(e,t,r){for(var n,i=-1,s=8,o=0,a,A;++i>i%8,e._prev=Lhe(e._prev,r?a:A);return o}function Lhe(e,t){var r=e.length,n=-1,i=Ay.allocUnsafe(e.length);for(e=Ay.concat([e,Ay.from([t])]);++n>7;return i}i5.encrypt=function(e,t,r){for(var n=t.length,i=Ay.allocUnsafe(n),s=-1;++s{var Phe=Uc();function Ohe(e){return e._prev=e._cipher.encryptBlock(e._prev),e._prev}o5.encrypt=function(e,t){for(;e._cache.length{function Hhe(e){for(var t=e.length,r;t--;)if(r=e.readUInt8(t),r===255)e.writeUInt8(0,t);else{r++,e.writeUInt8(r,t);break}}A5.exports=Hhe});var sS=U(u5=>{var qhe=Uc(),f5=at().Buffer,Ghe=nS();function Yhe(e){var t=e._cipher.encryptBlockRaw(e._prev);return Ghe(e._prev),t}var iS=16;u5.encrypt=function(e,t){var r=Math.ceil(t.length/iS),n=e._cache.length;e._cache=f5.concat([e._cache,f5.allocUnsafe(r*iS)]);for(var i=0;i{Whe.exports={"aes-128-ecb":{cipher:"AES",key:128,iv:0,mode:"ECB",type:"block"},"aes-192-ecb":{cipher:"AES",key:192,iv:0,mode:"ECB",type:"block"},"aes-256-ecb":{cipher:"AES",key:256,iv:0,mode:"ECB",type:"block"},"aes-128-cbc":{cipher:"AES",key:128,iv:16,mode:"CBC",type:"block"},"aes-192-cbc":{cipher:"AES",key:192,iv:16,mode:"CBC",type:"block"},"aes-256-cbc":{cipher:"AES",key:256,iv:16,mode:"CBC",type:"block"},aes128:{cipher:"AES",key:128,iv:16,mode:"CBC",type:"block"},aes192:{cipher:"AES",key:192,iv:16,mode:"CBC",type:"block"},aes256:{cipher:"AES",key:256,iv:16,mode:"CBC",type:"block"},"aes-128-cfb":{cipher:"AES",key:128,iv:16,mode:"CFB",type:"stream"},"aes-192-cfb":{cipher:"AES",key:192,iv:16,mode:"CFB",type:"stream"},"aes-256-cfb":{cipher:"AES",key:256,iv:16,mode:"CFB",type:"stream"},"aes-128-cfb8":{cipher:"AES",key:128,iv:16,mode:"CFB8",type:"stream"},"aes-192-cfb8":{cipher:"AES",key:192,iv:16,mode:"CFB8",type:"stream"},"aes-256-cfb8":{cipher:"AES",key:256,iv:16,mode:"CFB8",type:"stream"},"aes-128-cfb1":{cipher:"AES",key:128,iv:16,mode:"CFB1",type:"stream"},"aes-192-cfb1":{cipher:"AES",key:192,iv:16,mode:"CFB1",type:"stream"},"aes-256-cfb1":{cipher:"AES",key:256,iv:16,mode:"CFB1",type:"stream"},"aes-128-ofb":{cipher:"AES",key:128,iv:16,mode:"OFB",type:"stream"},"aes-192-ofb":{cipher:"AES",key:192,iv:16,mode:"OFB",type:"stream"},"aes-256-ofb":{cipher:"AES",key:256,iv:16,mode:"OFB",type:"stream"},"aes-128-ctr":{cipher:"AES",key:128,iv:16,mode:"CTR",type:"stream"},"aes-192-ctr":{cipher:"AES",key:192,iv:16,mode:"CTR",type:"stream"},"aes-256-ctr":{cipher:"AES",key:256,iv:16,mode:"CTR",type:"stream"},"aes-128-gcm":{cipher:"AES",key:128,iv:12,mode:"GCM",type:"auth"},"aes-192-gcm":{cipher:"AES",key:192,iv:12,mode:"GCM",type:"auth"},"aes-256-gcm":{cipher:"AES",key:256,iv:12,mode:"GCM",type:"auth"}}});var uy=U((MNe,c5)=>{var Vhe={ECB:z8(),CBC:Z8(),CFB:t5(),CFB8:n5(),CFB1:s5(),OFB:a5(),CTR:sS(),GCM:sS()},fy=oS();for(aS in fy)fy[aS].module=Vhe[fy[aS].mode];var aS;c5.exports=fy});var _d=U((FNe,h5)=>{var cy=at().Buffer;function fS(e){cy.isBuffer(e)||(e=cy.from(e));for(var t=e.length/4|0,r=new Array(t),n=0;n>>24]^o[l>>>16&255]^a[p>>>8&255]^A[I&255]^t[x++],_=s[l>>>24]^o[p>>>16&255]^a[I>>>8&255]^A[f&255]^t[x++],N=s[p>>>24]^o[I>>>16&255]^a[f>>>8&255]^A[l&255]^t[x++],O=s[I>>>24]^o[f>>>16&255]^a[l>>>8&255]^A[p&255]^t[x++],f=S,l=_,p=N,I=O;return S=(n[f>>>24]<<24|n[l>>>16&255]<<16|n[p>>>8&255]<<8|n[I&255])^t[x++],_=(n[l>>>24]<<24|n[p>>>16&255]<<16|n[I>>>8&255]<<8|n[f&255])^t[x++],N=(n[p>>>24]<<24|n[I>>>16&255]<<16|n[f>>>8&255]<<8|n[l&255])^t[x++],O=(n[I>>>24]<<24|n[f>>>16&255]<<16|n[l>>>8&255]<<8|n[p&255])^t[x++],S=S>>>0,_=_>>>0,N=N>>>0,O=O>>>0,[S,_,N,O]}var Jhe=[0,1,2,4,8,16,32,64,128,27,54],Ir=(function(){for(var e=new Array(256),t=0;t<256;t++)t<128?e[t]=t<<1:e[t]=t<<1^283;for(var r=[],n=[],i=[[],[],[],[]],s=[[],[],[],[]],o=0,a=0,A=0;A<256;++A){var f=a^a<<1^a<<2^a<<3^a<<4;f=f>>>8^f&255^99,r[o]=f,n[f]=o;var l=e[o],p=e[l],I=e[p],S=e[f]*257^f*16843008;i[0][o]=S<<24|S>>>8,i[1][o]=S<<16|S>>>16,i[2][o]=S<<8|S>>>24,i[3][o]=S,S=I*16843009^p*65537^l*257^o*16843008,s[0][f]=S<<24|S>>>8,s[1][f]=S<<16|S>>>16,s[2][f]=S<<8|S>>>24,s[3][f]=S,o===0?o=a=1:(o=l^e[e[e[I^l]]],a^=e[e[a]])}return{SBOX:r,INV_SBOX:n,SUB_MIX:i,INV_SUB_MIX:s}})();function Ci(e){this._key=fS(e),this._reset()}Ci.blockSize=16;Ci.keySize=256/8;Ci.prototype.blockSize=Ci.blockSize;Ci.prototype.keySize=Ci.keySize;Ci.prototype._reset=function(){for(var e=this._key,t=e.length,r=t+6,n=(r+1)*4,i=[],s=0;s>>24,o=Ir.SBOX[o>>>24]<<24|Ir.SBOX[o>>>16&255]<<16|Ir.SBOX[o>>>8&255]<<8|Ir.SBOX[o&255],o^=Jhe[s/t|0]<<24):t>6&&s%t===4&&(o=Ir.SBOX[o>>>24]<<24|Ir.SBOX[o>>>16&255]<<16|Ir.SBOX[o>>>8&255]<<8|Ir.SBOX[o&255]),i[s]=i[s-t]^o}for(var a=[],A=0;A>>24]]^Ir.INV_SUB_MIX[1][Ir.SBOX[l>>>16&255]]^Ir.INV_SUB_MIX[2][Ir.SBOX[l>>>8&255]]^Ir.INV_SUB_MIX[3][Ir.SBOX[l&255]]}this._nRounds=r,this._keySchedule=i,this._invKeySchedule=a};Ci.prototype.encryptBlockRaw=function(e){return e=fS(e),l5(e,this._keySchedule,Ir.SUB_MIX,Ir.SBOX,this._nRounds)};Ci.prototype.encryptBlock=function(e){var t=this.encryptBlockRaw(e),r=cy.allocUnsafe(16);return r.writeUInt32BE(t[0],0),r.writeUInt32BE(t[1],4),r.writeUInt32BE(t[2],8),r.writeUInt32BE(t[3],12),r};Ci.prototype.decryptBlock=function(e){e=fS(e);var t=e[1];e[1]=e[3],e[3]=t;var r=l5(e,this._invKeySchedule,Ir.INV_SUB_MIX,Ir.INV_SBOX,this._nRounds),n=cy.allocUnsafe(16);return n.writeUInt32BE(r[0],0),n.writeUInt32BE(r[3],4),n.writeUInt32BE(r[2],8),n.writeUInt32BE(r[1],12),n};Ci.prototype.scrub=function(){AS(this._keySchedule),AS(this._invKeySchedule),AS(this._key)};h5.exports.AES=Ci});var p5=U((kNe,g5)=>{var xc=at().Buffer,jhe=xc.alloc(16,0);function zhe(e){return[e.readUInt32BE(0),e.readUInt32BE(4),e.readUInt32BE(8),e.readUInt32BE(12)]}function d5(e){var t=xc.allocUnsafe(16);return t.writeUInt32BE(e[0]>>>0,0),t.writeUInt32BE(e[1]>>>0,4),t.writeUInt32BE(e[2]>>>0,8),t.writeUInt32BE(e[3]>>>0,12),t}function vd(e){this.h=e,this.state=xc.alloc(16,0),this.cache=xc.allocUnsafe(0)}vd.prototype.ghash=function(e){for(var t=-1;++t0;r--)e[r]=e[r]>>>1|(e[r-1]&1)<<31;e[0]=e[0]>>>1,i&&(e[0]=e[0]^225<<24)}this.state=d5(t)};vd.prototype.update=function(e){this.cache=xc.concat([this.cache,e]);for(var t;this.cache.length>=16;)t=this.cache.slice(0,16),this.cache=this.cache.slice(16),this.ghash(t)};vd.prototype.final=function(e,t){return this.cache.length&&this.ghash(xc.concat([this.cache,jhe],16)),this.ghash(d5([0,e,0,t])),this.state};g5.exports=vd});var uS=U((UNe,m5)=>{var Khe=_d(),Nn=at().Buffer,E5=ea(),Xhe=je(),y5=p5(),Zhe=Uc(),$he=nS();function ede(e,t){var r=0;e.length!==t.length&&r++;for(var n=Math.min(e.length,t.length),i=0;i{var rde=_d(),cS=at().Buffer,B5=ea(),nde=je();function ly(e,t,r,n){B5.call(this),this._cipher=new rde.AES(t),this._prev=cS.from(r),this._cache=cS.allocUnsafe(0),this._secCache=cS.allocUnsafe(0),this._decrypt=n,this._mode=e}nde(ly,B5);ly.prototype._update=function(e){return this._mode.encrypt(this,e,this._decrypt)};ly.prototype._final=function(){this._cipher.scrub()};I5.exports=ly});var Rd=U((LNe,b5)=>{var Df=at().Buffer,ide=VE();function sde(e,t,r,n){if(Df.isBuffer(e)||(e=Df.from(e,"binary")),t&&(Df.isBuffer(t)||(t=Df.from(t,"binary")),t.length!==8))throw new RangeError("salt should be Buffer with 8 byte length");for(var i=r/8,s=Df.alloc(i),o=Df.alloc(n||0),a=Df.alloc(0);i>0||n>0;){var A=new ide;A.update(a),A.update(e),t&&A.update(t),a=A.digest();var f=0;if(i>0){var l=s.length-i;f=Math.min(i,a.length),a.copy(s,l,0,f),i-=f}if(f0){var p=o.length-n,I=Math.min(n,a.length-f);a.copy(o,p,f,f+I),n-=I}}return a.fill(0),{key:s,iv:o}}b5.exports=sde});var S5=U(hS=>{var C5=uy(),ode=uS(),ra=at().Buffer,ade=lS(),Q5=ea(),Ade=_d(),fde=Rd(),ude=je();function Dd(e,t,r){Q5.call(this),this._cache=new hy,this._cipher=new Ade.AES(t),this._prev=ra.from(r),this._mode=e,this._autopadding=!0}ude(Dd,Q5);Dd.prototype._update=function(e){this._cache.add(e);for(var t,r,n=[];t=this._cache.get();)r=this._mode.encrypt(this,t),n.push(r);return ra.concat(n)};var cde=ra.alloc(16,16);Dd.prototype._final=function(){var e=this._cache.flush();if(this._autopadding)return e=this._mode.encrypt(this,e),this._cipher.scrub(),e;if(!e.equals(cde))throw this._cipher.scrub(),new Error("data not multiple of block length")};Dd.prototype.setAutoPadding=function(e){return this._autopadding=!!e,this};function hy(){this.cache=ra.allocUnsafe(0)}hy.prototype.add=function(e){this.cache=ra.concat([this.cache,e])};hy.prototype.get=function(){if(this.cache.length>15){var e=this.cache.slice(0,16);return this.cache=this.cache.slice(16),e}return null};hy.prototype.flush=function(){for(var e=16-this.cache.length,t=ra.allocUnsafe(e),r=-1;++r{var hde=uS(),Lc=at().Buffer,_5=uy(),dde=lS(),v5=ea(),gde=_d(),pde=Rd(),Ede=je();function Td(e,t,r){v5.call(this),this._cache=new dy,this._last=void 0,this._cipher=new gde.AES(t),this._prev=Lc.from(r),this._mode=e,this._autopadding=!0}Ede(Td,v5);Td.prototype._update=function(e){this._cache.add(e);for(var t,r,n=[];t=this._cache.get(this._autopadding);)r=this._mode.decrypt(this,t),n.push(r);return Lc.concat(n)};Td.prototype._final=function(){var e=this._cache.flush();if(this._autopadding)return yde(this._mode.decrypt(this,e));if(e)throw new Error("data not multiple of block length")};Td.prototype.setAutoPadding=function(e){return this._autopadding=!!e,this};function dy(){this.cache=Lc.allocUnsafe(0)}dy.prototype.add=function(e){this.cache=Lc.concat([this.cache,e])};dy.prototype.get=function(e){var t;if(e){if(this.cache.length>16)return t=this.cache.slice(0,16),this.cache=this.cache.slice(16),t}else if(this.cache.length>=16)return t=this.cache.slice(0,16),this.cache=this.cache.slice(16),t;return null};dy.prototype.flush=function(){if(this.cache.length)return this.cache};function yde(e){var t=e[15];if(t<1||t>16)throw new Error("unable to decrypt data");for(var r=-1;++r{var T5=S5(),N5=D5(),Bde=oS();function Ide(){return Object.keys(Bde)}as.createCipher=as.Cipher=T5.createCipher;as.createCipheriv=as.Cipheriv=T5.createCipheriv;as.createDecipher=as.Decipher=N5.createDecipher;as.createDecipheriv=as.Decipheriv=N5.createDecipheriv;as.listCiphers=as.getCiphers=Ide});var M5=U(na=>{na["des-ecb"]={key:8,iv:0};na["des-cbc"]=na.des={key:8,iv:8};na["des-ede3-cbc"]=na.des3={key:24,iv:8};na["des-ede3"]={key:24,iv:0};na["des-ede-cbc"]={key:16,iv:8};na["des-ede"]={key:16,iv:0}});var L5=U(As=>{var F5=j8(),gS=gy(),aA=uy(),ia=M5(),k5=Rd();function bde(e,t){e=e.toLowerCase();var r,n;if(aA[e])r=aA[e].key,n=aA[e].iv;else if(ia[e])r=ia[e].key*8,n=ia[e].iv;else throw new TypeError("invalid suite type");var i=k5(t,!1,r,n);return U5(e,i.key,i.iv)}function Cde(e,t){e=e.toLowerCase();var r,n;if(aA[e])r=aA[e].key,n=aA[e].iv;else if(ia[e])r=ia[e].key*8,n=ia[e].iv;else throw new TypeError("invalid suite type");var i=k5(t,!1,r,n);return x5(e,i.key,i.iv)}function U5(e,t,r){if(e=e.toLowerCase(),aA[e])return gS.createCipheriv(e,t,r);if(ia[e])return new F5({key:t,iv:r,mode:e});throw new TypeError("invalid suite type")}function x5(e,t,r){if(e=e.toLowerCase(),aA[e])return gS.createDecipheriv(e,t,r);if(ia[e])return new F5({key:t,iv:r,mode:e,decrypt:!0});throw new TypeError("invalid suite type")}function Qde(){return Object.keys(ia).concat(gS.getCiphers())}As.createCipher=As.Cipher=bde;As.createCipheriv=As.Cipheriv=U5;As.createDecipher=As.Decipher=Cde;As.createDecipheriv=As.Decipheriv=x5;As.listCiphers=As.getCiphers=Qde});var kr=U((P5,pS)=>{(function(e,t){"use strict";function r(H,E){if(!H)throw new Error(E||"Assertion failed")}function n(H,E){H.super_=E;var v=function(){};v.prototype=E.prototype,H.prototype=new v,H.prototype.constructor=H}function i(H,E,v){if(i.isBN(H))return H;this.negative=0,this.words=null,this.length=0,this.red=null,H!==null&&((E==="le"||E==="be")&&(v=E,E=10),this._init(H||0,E||10,v||"be"))}typeof e=="object"?e.exports=i:t.BN=i,i.BN=i,i.wordSize=26;var s;try{typeof window<"u"&&typeof window.Buffer<"u"?s=window.Buffer:s=Gr().Buffer}catch{}i.isBN=function(E){return E instanceof i?!0:E!==null&&typeof E=="object"&&E.constructor.wordSize===i.wordSize&&Array.isArray(E.words)},i.max=function(E,v){return E.cmp(v)>0?E:v},i.min=function(E,v){return E.cmp(v)<0?E:v},i.prototype._init=function(E,v,b){if(typeof E=="number")return this._initNumber(E,v,b);if(typeof E=="object")return this._initArray(E,v,b);v==="hex"&&(v=16),r(v===(v|0)&&v>=2&&v<=36),E=E.toString().replace(/\s+/g,"");var c=0;E[0]==="-"&&(c++,this.negative=1),c=0;c-=3)w=E[c]|E[c-1]<<8|E[c-2]<<16,this.words[g]|=w<>>26-R&67108863,R+=24,R>=26&&(R-=26,g++);else if(b==="le")for(c=0,g=0;c>>26-R&67108863,R+=24,R>=26&&(R-=26,g++);return this.strip()};function o(H,E){var v=H.charCodeAt(E);return v>=65&&v<=70?v-55:v>=97&&v<=102?v-87:v-48&15}function a(H,E,v){var b=o(H,v);return v-1>=E&&(b|=o(H,v-1)<<4),b}i.prototype._parseHex=function(E,v,b){this.length=Math.ceil((E.length-v)/6),this.words=new Array(this.length);for(var c=0;c=v;c-=2)R=a(E,v,c)<=18?(g-=18,w+=1,this.words[w]|=R>>>26):g+=8;else{var C=E.length-v;for(c=C%2===0?v+1:v;c=18?(g-=18,w+=1,this.words[w]|=R>>>26):g+=8}this.strip()};function A(H,E,v,b){for(var c=0,g=Math.min(H.length,v),w=E;w=49?c+=R-49+10:R>=17?c+=R-17+10:c+=R}return c}i.prototype._parseBase=function(E,v,b){this.words=[0],this.length=1;for(var c=0,g=1;g<=67108863;g*=v)c++;c--,g=g/v|0;for(var w=E.length-b,R=w%c,C=Math.min(w,w-R)+b,h=0,D=b;D1&&this.words[this.length-1]===0;)this.length--;return this._normSign()},i.prototype._normSign=function(){return this.length===1&&this.words[0]===0&&(this.negative=0),this},i.prototype.inspect=function(){return(this.red?""};var f=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],p=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];i.prototype.toString=function(E,v){E=E||10,v=v|0||1;var b;if(E===16||E==="hex"){b="";for(var c=0,g=0,w=0;w>>24-c&16777215,c+=2,c>=26&&(c-=26,w--),g!==0||w!==this.length-1?b=f[6-C.length]+C+b:b=C+b}for(g!==0&&(b=g.toString(16)+b);b.length%v!==0;)b="0"+b;return this.negative!==0&&(b="-"+b),b}if(E===(E|0)&&E>=2&&E<=36){var h=l[E],D=p[E];b="";var M=this.clone();for(M.negative=0;!M.isZero();){var B=M.modn(D).toString(E);M=M.idivn(D),M.isZero()?b=B+b:b=f[h-B.length]+B+b}for(this.isZero()&&(b="0"+b);b.length%v!==0;)b="0"+b;return this.negative!==0&&(b="-"+b),b}r(!1,"Base should be between 2 and 36")},i.prototype.toNumber=function(){var E=this.words[0];return this.length===2?E+=this.words[1]*67108864:this.length===3&&this.words[2]===1?E+=4503599627370496+this.words[1]*67108864:this.length>2&&r(!1,"Number can only safely store up to 53 bits"),this.negative!==0?-E:E},i.prototype.toJSON=function(){return this.toString(16)},i.prototype.toBuffer=function(E,v){return r(typeof s<"u"),this.toArrayLike(s,E,v)},i.prototype.toArray=function(E,v){return this.toArrayLike(Array,E,v)},i.prototype.toArrayLike=function(E,v,b){var c=this.byteLength(),g=b||Math.max(1,c);r(c<=g,"byte array longer than desired length"),r(g>0,"Requested array length <= 0"),this.strip();var w=v==="le",R=new E(g),C,h,D=this.clone();if(w){for(h=0;!D.isZero();h++)C=D.andln(255),D.iushrn(8),R[h]=C;for(;h=4096&&(b+=13,v>>>=13),v>=64&&(b+=7,v>>>=7),v>=8&&(b+=4,v>>>=4),v>=2&&(b+=2,v>>>=2),b+v},i.prototype._zeroBits=function(E){if(E===0)return 26;var v=E,b=0;return(v&8191)===0&&(b+=13,v>>>=13),(v&127)===0&&(b+=7,v>>>=7),(v&15)===0&&(b+=4,v>>>=4),(v&3)===0&&(b+=2,v>>>=2),(v&1)===0&&b++,b},i.prototype.bitLength=function(){var E=this.words[this.length-1],v=this._countBits(E);return(this.length-1)*26+v};function I(H){for(var E=new Array(H.bitLength()),v=0;v>>c}return E}i.prototype.zeroBits=function(){if(this.isZero())return 0;for(var E=0,v=0;vE.length?this.clone().ior(E):E.clone().ior(this)},i.prototype.uor=function(E){return this.length>E.length?this.clone().iuor(E):E.clone().iuor(this)},i.prototype.iuand=function(E){var v;this.length>E.length?v=E:v=this;for(var b=0;bE.length?this.clone().iand(E):E.clone().iand(this)},i.prototype.uand=function(E){return this.length>E.length?this.clone().iuand(E):E.clone().iuand(this)},i.prototype.iuxor=function(E){var v,b;this.length>E.length?(v=this,b=E):(v=E,b=this);for(var c=0;cE.length?this.clone().ixor(E):E.clone().ixor(this)},i.prototype.uxor=function(E){return this.length>E.length?this.clone().iuxor(E):E.clone().iuxor(this)},i.prototype.inotn=function(E){r(typeof E=="number"&&E>=0);var v=Math.ceil(E/26)|0,b=E%26;this._expand(v),b>0&&v--;for(var c=0;c0&&(this.words[c]=~this.words[c]&67108863>>26-b),this.strip()},i.prototype.notn=function(E){return this.clone().inotn(E)},i.prototype.setn=function(E,v){r(typeof E=="number"&&E>=0);var b=E/26|0,c=E%26;return this._expand(b+1),v?this.words[b]=this.words[b]|1<E.length?(b=this,c=E):(b=E,c=this);for(var g=0,w=0;w>>26;for(;g!==0&&w>>26;if(this.length=b.length,g!==0)this.words[this.length]=g,this.length++;else if(b!==this)for(;wE.length?this.clone().iadd(E):E.clone().iadd(this)},i.prototype.isub=function(E){if(E.negative!==0){E.negative=0;var v=this.iadd(E);return E.negative=1,v._normSign()}else if(this.negative!==0)return this.negative=0,this.iadd(E),this.negative=1,this._normSign();var b=this.cmp(E);if(b===0)return this.negative=0,this.length=1,this.words[0]=0,this;var c,g;b>0?(c=this,g=E):(c=E,g=this);for(var w=0,R=0;R>26,this.words[R]=v&67108863;for(;w!==0&&R>26,this.words[R]=v&67108863;if(w===0&&R>>26,M=C&67108863,B=Math.min(h,E.length-1),k=Math.max(0,h-H.length+1);k<=B;k++){var ne=h-k|0;c=H.words[ne]|0,g=E.words[k]|0,w=c*g+M,D+=w/67108864|0,M=w&67108863}v.words[h]=M|0,C=D|0}return C!==0?v.words[h]=C|0:v.length--,v.strip()}var _=function(E,v,b){var c=E.words,g=v.words,w=b.words,R=0,C,h,D,M=c[0]|0,B=M&8191,k=M>>>13,ne=c[1]|0,Ae=ne&8191,ue=ne>>>13,pe=c[2]|0,he=pe&8191,de=pe>>>13,Qt=c[3]|0,Ie=Qt&8191,be=Qt>>>13,yr=c[4]|0,Qe=yr&8191,_e=yr>>>13,Ds=c[5]|0,Ge=Ds&8191,Ue=Ds>>>13,Ts=c[6]|0,Te=Ts&8191,De=Ts>>>13,en=c[7]|0,ve=en&8191,He=en>>>13,ai=c[8]|0,Ne=ai&8191,Ve=ai>>>13,F=c[9]|0,m=F&8191,Q=F>>>13,L=g[0]|0,W=L&8191,z=L>>>13,ae=g[1]|0,le=ae&8191,ye=ae>>>13,bt=g[2]|0,Ee=bt&8191,ge=bt>>>13,ka=g[3]|0,Je=ka&8191,tt=ka>>>13,Mo=g[4]|0,Ze=Mo&8191,rt=Mo>>>13,HA=g[5]|0,nt=HA&8191,it=HA>>>13,Ua=g[6]|0,ze=Ua&8191,Ke=Ua>>>13,qA=g[7]|0,xe=qA&8191,$e=qA>>>13,GA=g[8]|0,st=GA&8191,Le=GA>>>13,hn=g[9]|0,Pe=hn&8191,Xe=hn>>>13;b.negative=E.negative^v.negative,b.length=19,C=Math.imul(B,W),h=Math.imul(B,z),h=h+Math.imul(k,W)|0,D=Math.imul(k,z);var Qn=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Qn>>>26)|0,Qn&=67108863,C=Math.imul(Ae,W),h=Math.imul(Ae,z),h=h+Math.imul(ue,W)|0,D=Math.imul(ue,z),C=C+Math.imul(B,le)|0,h=h+Math.imul(B,ye)|0,h=h+Math.imul(k,le)|0,D=D+Math.imul(k,ye)|0;var xt=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(xt>>>26)|0,xt&=67108863,C=Math.imul(he,W),h=Math.imul(he,z),h=h+Math.imul(de,W)|0,D=Math.imul(de,z),C=C+Math.imul(Ae,le)|0,h=h+Math.imul(Ae,ye)|0,h=h+Math.imul(ue,le)|0,D=D+Math.imul(ue,ye)|0,C=C+Math.imul(B,Ee)|0,h=h+Math.imul(B,ge)|0,h=h+Math.imul(k,Ee)|0,D=D+Math.imul(k,ge)|0;var Ft=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ft>>>26)|0,Ft&=67108863,C=Math.imul(Ie,W),h=Math.imul(Ie,z),h=h+Math.imul(be,W)|0,D=Math.imul(be,z),C=C+Math.imul(he,le)|0,h=h+Math.imul(he,ye)|0,h=h+Math.imul(de,le)|0,D=D+Math.imul(de,ye)|0,C=C+Math.imul(Ae,Ee)|0,h=h+Math.imul(Ae,ge)|0,h=h+Math.imul(ue,Ee)|0,D=D+Math.imul(ue,ge)|0,C=C+Math.imul(B,Je)|0,h=h+Math.imul(B,tt)|0,h=h+Math.imul(k,Je)|0,D=D+Math.imul(k,tt)|0;var Ns=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ns>>>26)|0,Ns&=67108863,C=Math.imul(Qe,W),h=Math.imul(Qe,z),h=h+Math.imul(_e,W)|0,D=Math.imul(_e,z),C=C+Math.imul(Ie,le)|0,h=h+Math.imul(Ie,ye)|0,h=h+Math.imul(be,le)|0,D=D+Math.imul(be,ye)|0,C=C+Math.imul(he,Ee)|0,h=h+Math.imul(he,ge)|0,h=h+Math.imul(de,Ee)|0,D=D+Math.imul(de,ge)|0,C=C+Math.imul(Ae,Je)|0,h=h+Math.imul(Ae,tt)|0,h=h+Math.imul(ue,Je)|0,D=D+Math.imul(ue,tt)|0,C=C+Math.imul(B,Ze)|0,h=h+Math.imul(B,rt)|0,h=h+Math.imul(k,Ze)|0,D=D+Math.imul(k,rt)|0;var Ai=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ai>>>26)|0,Ai&=67108863,C=Math.imul(Ge,W),h=Math.imul(Ge,z),h=h+Math.imul(Ue,W)|0,D=Math.imul(Ue,z),C=C+Math.imul(Qe,le)|0,h=h+Math.imul(Qe,ye)|0,h=h+Math.imul(_e,le)|0,D=D+Math.imul(_e,ye)|0,C=C+Math.imul(Ie,Ee)|0,h=h+Math.imul(Ie,ge)|0,h=h+Math.imul(be,Ee)|0,D=D+Math.imul(be,ge)|0,C=C+Math.imul(he,Je)|0,h=h+Math.imul(he,tt)|0,h=h+Math.imul(de,Je)|0,D=D+Math.imul(de,tt)|0,C=C+Math.imul(Ae,Ze)|0,h=h+Math.imul(Ae,rt)|0,h=h+Math.imul(ue,Ze)|0,D=D+Math.imul(ue,rt)|0,C=C+Math.imul(B,nt)|0,h=h+Math.imul(B,it)|0,h=h+Math.imul(k,nt)|0,D=D+Math.imul(k,it)|0;var Ms=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ms>>>26)|0,Ms&=67108863,C=Math.imul(Te,W),h=Math.imul(Te,z),h=h+Math.imul(De,W)|0,D=Math.imul(De,z),C=C+Math.imul(Ge,le)|0,h=h+Math.imul(Ge,ye)|0,h=h+Math.imul(Ue,le)|0,D=D+Math.imul(Ue,ye)|0,C=C+Math.imul(Qe,Ee)|0,h=h+Math.imul(Qe,ge)|0,h=h+Math.imul(_e,Ee)|0,D=D+Math.imul(_e,ge)|0,C=C+Math.imul(Ie,Je)|0,h=h+Math.imul(Ie,tt)|0,h=h+Math.imul(be,Je)|0,D=D+Math.imul(be,tt)|0,C=C+Math.imul(he,Ze)|0,h=h+Math.imul(he,rt)|0,h=h+Math.imul(de,Ze)|0,D=D+Math.imul(de,rt)|0,C=C+Math.imul(Ae,nt)|0,h=h+Math.imul(Ae,it)|0,h=h+Math.imul(ue,nt)|0,D=D+Math.imul(ue,it)|0,C=C+Math.imul(B,ze)|0,h=h+Math.imul(B,Ke)|0,h=h+Math.imul(k,ze)|0,D=D+Math.imul(k,Ke)|0;var Fs=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Fs>>>26)|0,Fs&=67108863,C=Math.imul(ve,W),h=Math.imul(ve,z),h=h+Math.imul(He,W)|0,D=Math.imul(He,z),C=C+Math.imul(Te,le)|0,h=h+Math.imul(Te,ye)|0,h=h+Math.imul(De,le)|0,D=D+Math.imul(De,ye)|0,C=C+Math.imul(Ge,Ee)|0,h=h+Math.imul(Ge,ge)|0,h=h+Math.imul(Ue,Ee)|0,D=D+Math.imul(Ue,ge)|0,C=C+Math.imul(Qe,Je)|0,h=h+Math.imul(Qe,tt)|0,h=h+Math.imul(_e,Je)|0,D=D+Math.imul(_e,tt)|0,C=C+Math.imul(Ie,Ze)|0,h=h+Math.imul(Ie,rt)|0,h=h+Math.imul(be,Ze)|0,D=D+Math.imul(be,rt)|0,C=C+Math.imul(he,nt)|0,h=h+Math.imul(he,it)|0,h=h+Math.imul(de,nt)|0,D=D+Math.imul(de,it)|0,C=C+Math.imul(Ae,ze)|0,h=h+Math.imul(Ae,Ke)|0,h=h+Math.imul(ue,ze)|0,D=D+Math.imul(ue,Ke)|0,C=C+Math.imul(B,xe)|0,h=h+Math.imul(B,$e)|0,h=h+Math.imul(k,xe)|0,D=D+Math.imul(k,$e)|0;var ks=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(ks>>>26)|0,ks&=67108863,C=Math.imul(Ne,W),h=Math.imul(Ne,z),h=h+Math.imul(Ve,W)|0,D=Math.imul(Ve,z),C=C+Math.imul(ve,le)|0,h=h+Math.imul(ve,ye)|0,h=h+Math.imul(He,le)|0,D=D+Math.imul(He,ye)|0,C=C+Math.imul(Te,Ee)|0,h=h+Math.imul(Te,ge)|0,h=h+Math.imul(De,Ee)|0,D=D+Math.imul(De,ge)|0,C=C+Math.imul(Ge,Je)|0,h=h+Math.imul(Ge,tt)|0,h=h+Math.imul(Ue,Je)|0,D=D+Math.imul(Ue,tt)|0,C=C+Math.imul(Qe,Ze)|0,h=h+Math.imul(Qe,rt)|0,h=h+Math.imul(_e,Ze)|0,D=D+Math.imul(_e,rt)|0,C=C+Math.imul(Ie,nt)|0,h=h+Math.imul(Ie,it)|0,h=h+Math.imul(be,nt)|0,D=D+Math.imul(be,it)|0,C=C+Math.imul(he,ze)|0,h=h+Math.imul(he,Ke)|0,h=h+Math.imul(de,ze)|0,D=D+Math.imul(de,Ke)|0,C=C+Math.imul(Ae,xe)|0,h=h+Math.imul(Ae,$e)|0,h=h+Math.imul(ue,xe)|0,D=D+Math.imul(ue,$e)|0,C=C+Math.imul(B,st)|0,h=h+Math.imul(B,Le)|0,h=h+Math.imul(k,st)|0,D=D+Math.imul(k,Le)|0;var Us=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Us>>>26)|0,Us&=67108863,C=Math.imul(m,W),h=Math.imul(m,z),h=h+Math.imul(Q,W)|0,D=Math.imul(Q,z),C=C+Math.imul(Ne,le)|0,h=h+Math.imul(Ne,ye)|0,h=h+Math.imul(Ve,le)|0,D=D+Math.imul(Ve,ye)|0,C=C+Math.imul(ve,Ee)|0,h=h+Math.imul(ve,ge)|0,h=h+Math.imul(He,Ee)|0,D=D+Math.imul(He,ge)|0,C=C+Math.imul(Te,Je)|0,h=h+Math.imul(Te,tt)|0,h=h+Math.imul(De,Je)|0,D=D+Math.imul(De,tt)|0,C=C+Math.imul(Ge,Ze)|0,h=h+Math.imul(Ge,rt)|0,h=h+Math.imul(Ue,Ze)|0,D=D+Math.imul(Ue,rt)|0,C=C+Math.imul(Qe,nt)|0,h=h+Math.imul(Qe,it)|0,h=h+Math.imul(_e,nt)|0,D=D+Math.imul(_e,it)|0,C=C+Math.imul(Ie,ze)|0,h=h+Math.imul(Ie,Ke)|0,h=h+Math.imul(be,ze)|0,D=D+Math.imul(be,Ke)|0,C=C+Math.imul(he,xe)|0,h=h+Math.imul(he,$e)|0,h=h+Math.imul(de,xe)|0,D=D+Math.imul(de,$e)|0,C=C+Math.imul(Ae,st)|0,h=h+Math.imul(Ae,Le)|0,h=h+Math.imul(ue,st)|0,D=D+Math.imul(ue,Le)|0,C=C+Math.imul(B,Pe)|0,h=h+Math.imul(B,Xe)|0,h=h+Math.imul(k,Pe)|0,D=D+Math.imul(k,Xe)|0;var xs=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(xs>>>26)|0,xs&=67108863,C=Math.imul(m,le),h=Math.imul(m,ye),h=h+Math.imul(Q,le)|0,D=Math.imul(Q,ye),C=C+Math.imul(Ne,Ee)|0,h=h+Math.imul(Ne,ge)|0,h=h+Math.imul(Ve,Ee)|0,D=D+Math.imul(Ve,ge)|0,C=C+Math.imul(ve,Je)|0,h=h+Math.imul(ve,tt)|0,h=h+Math.imul(He,Je)|0,D=D+Math.imul(He,tt)|0,C=C+Math.imul(Te,Ze)|0,h=h+Math.imul(Te,rt)|0,h=h+Math.imul(De,Ze)|0,D=D+Math.imul(De,rt)|0,C=C+Math.imul(Ge,nt)|0,h=h+Math.imul(Ge,it)|0,h=h+Math.imul(Ue,nt)|0,D=D+Math.imul(Ue,it)|0,C=C+Math.imul(Qe,ze)|0,h=h+Math.imul(Qe,Ke)|0,h=h+Math.imul(_e,ze)|0,D=D+Math.imul(_e,Ke)|0,C=C+Math.imul(Ie,xe)|0,h=h+Math.imul(Ie,$e)|0,h=h+Math.imul(be,xe)|0,D=D+Math.imul(be,$e)|0,C=C+Math.imul(he,st)|0,h=h+Math.imul(he,Le)|0,h=h+Math.imul(de,st)|0,D=D+Math.imul(de,Le)|0,C=C+Math.imul(Ae,Pe)|0,h=h+Math.imul(Ae,Xe)|0,h=h+Math.imul(ue,Pe)|0,D=D+Math.imul(ue,Xe)|0;var Ji=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ji>>>26)|0,Ji&=67108863,C=Math.imul(m,Ee),h=Math.imul(m,ge),h=h+Math.imul(Q,Ee)|0,D=Math.imul(Q,ge),C=C+Math.imul(Ne,Je)|0,h=h+Math.imul(Ne,tt)|0,h=h+Math.imul(Ve,Je)|0,D=D+Math.imul(Ve,tt)|0,C=C+Math.imul(ve,Ze)|0,h=h+Math.imul(ve,rt)|0,h=h+Math.imul(He,Ze)|0,D=D+Math.imul(He,rt)|0,C=C+Math.imul(Te,nt)|0,h=h+Math.imul(Te,it)|0,h=h+Math.imul(De,nt)|0,D=D+Math.imul(De,it)|0,C=C+Math.imul(Ge,ze)|0,h=h+Math.imul(Ge,Ke)|0,h=h+Math.imul(Ue,ze)|0,D=D+Math.imul(Ue,Ke)|0,C=C+Math.imul(Qe,xe)|0,h=h+Math.imul(Qe,$e)|0,h=h+Math.imul(_e,xe)|0,D=D+Math.imul(_e,$e)|0,C=C+Math.imul(Ie,st)|0,h=h+Math.imul(Ie,Le)|0,h=h+Math.imul(be,st)|0,D=D+Math.imul(be,Le)|0,C=C+Math.imul(he,Pe)|0,h=h+Math.imul(he,Xe)|0,h=h+Math.imul(de,Pe)|0,D=D+Math.imul(de,Xe)|0;var ji=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(ji>>>26)|0,ji&=67108863,C=Math.imul(m,Je),h=Math.imul(m,tt),h=h+Math.imul(Q,Je)|0,D=Math.imul(Q,tt),C=C+Math.imul(Ne,Ze)|0,h=h+Math.imul(Ne,rt)|0,h=h+Math.imul(Ve,Ze)|0,D=D+Math.imul(Ve,rt)|0,C=C+Math.imul(ve,nt)|0,h=h+Math.imul(ve,it)|0,h=h+Math.imul(He,nt)|0,D=D+Math.imul(He,it)|0,C=C+Math.imul(Te,ze)|0,h=h+Math.imul(Te,Ke)|0,h=h+Math.imul(De,ze)|0,D=D+Math.imul(De,Ke)|0,C=C+Math.imul(Ge,xe)|0,h=h+Math.imul(Ge,$e)|0,h=h+Math.imul(Ue,xe)|0,D=D+Math.imul(Ue,$e)|0,C=C+Math.imul(Qe,st)|0,h=h+Math.imul(Qe,Le)|0,h=h+Math.imul(_e,st)|0,D=D+Math.imul(_e,Le)|0,C=C+Math.imul(Ie,Pe)|0,h=h+Math.imul(Ie,Xe)|0,h=h+Math.imul(be,Pe)|0,D=D+Math.imul(be,Xe)|0;var Fo=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Fo>>>26)|0,Fo&=67108863,C=Math.imul(m,Ze),h=Math.imul(m,rt),h=h+Math.imul(Q,Ze)|0,D=Math.imul(Q,rt),C=C+Math.imul(Ne,nt)|0,h=h+Math.imul(Ne,it)|0,h=h+Math.imul(Ve,nt)|0,D=D+Math.imul(Ve,it)|0,C=C+Math.imul(ve,ze)|0,h=h+Math.imul(ve,Ke)|0,h=h+Math.imul(He,ze)|0,D=D+Math.imul(He,Ke)|0,C=C+Math.imul(Te,xe)|0,h=h+Math.imul(Te,$e)|0,h=h+Math.imul(De,xe)|0,D=D+Math.imul(De,$e)|0,C=C+Math.imul(Ge,st)|0,h=h+Math.imul(Ge,Le)|0,h=h+Math.imul(Ue,st)|0,D=D+Math.imul(Ue,Le)|0,C=C+Math.imul(Qe,Pe)|0,h=h+Math.imul(Qe,Xe)|0,h=h+Math.imul(_e,Pe)|0,D=D+Math.imul(_e,Xe)|0;var ko=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(ko>>>26)|0,ko&=67108863,C=Math.imul(m,nt),h=Math.imul(m,it),h=h+Math.imul(Q,nt)|0,D=Math.imul(Q,it),C=C+Math.imul(Ne,ze)|0,h=h+Math.imul(Ne,Ke)|0,h=h+Math.imul(Ve,ze)|0,D=D+Math.imul(Ve,Ke)|0,C=C+Math.imul(ve,xe)|0,h=h+Math.imul(ve,$e)|0,h=h+Math.imul(He,xe)|0,D=D+Math.imul(He,$e)|0,C=C+Math.imul(Te,st)|0,h=h+Math.imul(Te,Le)|0,h=h+Math.imul(De,st)|0,D=D+Math.imul(De,Le)|0,C=C+Math.imul(Ge,Pe)|0,h=h+Math.imul(Ge,Xe)|0,h=h+Math.imul(Ue,Pe)|0,D=D+Math.imul(Ue,Xe)|0;var Uo=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Uo>>>26)|0,Uo&=67108863,C=Math.imul(m,ze),h=Math.imul(m,Ke),h=h+Math.imul(Q,ze)|0,D=Math.imul(Q,Ke),C=C+Math.imul(Ne,xe)|0,h=h+Math.imul(Ne,$e)|0,h=h+Math.imul(Ve,xe)|0,D=D+Math.imul(Ve,$e)|0,C=C+Math.imul(ve,st)|0,h=h+Math.imul(ve,Le)|0,h=h+Math.imul(He,st)|0,D=D+Math.imul(He,Le)|0,C=C+Math.imul(Te,Pe)|0,h=h+Math.imul(Te,Xe)|0,h=h+Math.imul(De,Pe)|0,D=D+Math.imul(De,Xe)|0;var xo=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(xo>>>26)|0,xo&=67108863,C=Math.imul(m,xe),h=Math.imul(m,$e),h=h+Math.imul(Q,xe)|0,D=Math.imul(Q,$e),C=C+Math.imul(Ne,st)|0,h=h+Math.imul(Ne,Le)|0,h=h+Math.imul(Ve,st)|0,D=D+Math.imul(Ve,Le)|0,C=C+Math.imul(ve,Pe)|0,h=h+Math.imul(ve,Xe)|0,h=h+Math.imul(He,Pe)|0,D=D+Math.imul(He,Xe)|0;var Ls=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ls>>>26)|0,Ls&=67108863,C=Math.imul(m,st),h=Math.imul(m,Le),h=h+Math.imul(Q,st)|0,D=Math.imul(Q,Le),C=C+Math.imul(Ne,Pe)|0,h=h+Math.imul(Ne,Xe)|0,h=h+Math.imul(Ve,Pe)|0,D=D+Math.imul(Ve,Xe)|0;var wn=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(wn>>>26)|0,wn&=67108863,C=Math.imul(m,Pe),h=Math.imul(m,Xe),h=h+Math.imul(Q,Pe)|0,D=Math.imul(Q,Xe);var Lo=(R+C|0)+((h&8191)<<13)|0;return R=(D+(h>>>13)|0)+(Lo>>>26)|0,Lo&=67108863,w[0]=Qn,w[1]=xt,w[2]=Ft,w[3]=Ns,w[4]=Ai,w[5]=Ms,w[6]=Fs,w[7]=ks,w[8]=Us,w[9]=xs,w[10]=Ji,w[11]=ji,w[12]=Fo,w[13]=ko,w[14]=Uo,w[15]=xo,w[16]=Ls,w[17]=wn,w[18]=Lo,R!==0&&(w[19]=R,b.length++),b};Math.imul||(_=S);function N(H,E,v){v.negative=E.negative^H.negative,v.length=H.length+E.length;for(var b=0,c=0,g=0;g>>26)|0,c+=w>>>26,w&=67108863}v.words[g]=R,b=w,w=c}return b!==0?v.words[g]=b:v.length--,v.strip()}function O(H,E,v){var b=new x;return b.mulp(H,E,v)}i.prototype.mulTo=function(E,v){var b,c=this.length+E.length;return this.length===10&&E.length===10?b=_(this,E,v):c<63?b=S(this,E,v):c<1024?b=N(this,E,v):b=O(this,E,v),b};function x(H,E){this.x=H,this.y=E}x.prototype.makeRBT=function(E){for(var v=new Array(E),b=i.prototype._countBits(E)-1,c=0;c>=1;return c},x.prototype.permute=function(E,v,b,c,g,w){for(var R=0;R>>1)g++;return 1<>>13,b[2*w+1]=g&8191,g=g>>>13;for(w=2*v;w>=26,v+=c/67108864|0,v+=g>>>26,this.words[b]=g&67108863}return v!==0&&(this.words[b]=v,this.length++),this.length=E===0?1:this.length,this},i.prototype.muln=function(E){return this.clone().imuln(E)},i.prototype.sqr=function(){return this.mul(this)},i.prototype.isqr=function(){return this.imul(this.clone())},i.prototype.pow=function(E){var v=I(E);if(v.length===0)return new i(1);for(var b=this,c=0;c=0);var v=E%26,b=(E-v)/26,c=67108863>>>26-v<<26-v,g;if(v!==0){var w=0;for(g=0;g>>26-v}w&&(this.words[g]=w,this.length++)}if(b!==0){for(g=this.length-1;g>=0;g--)this.words[g+b]=this.words[g];for(g=0;g=0);var c;v?c=(v-v%26)/26:c=0;var g=E%26,w=Math.min((E-g)/26,this.length),R=67108863^67108863>>>g<w)for(this.length-=w,h=0;h=0&&(D!==0||h>=c);h--){var M=this.words[h]|0;this.words[h]=D<<26-g|M>>>g,D=M&R}return C&&D!==0&&(C.words[C.length++]=D),this.length===0&&(this.words[0]=0,this.length=1),this.strip()},i.prototype.ishrn=function(E,v,b){return r(this.negative===0),this.iushrn(E,v,b)},i.prototype.shln=function(E){return this.clone().ishln(E)},i.prototype.ushln=function(E){return this.clone().iushln(E)},i.prototype.shrn=function(E){return this.clone().ishrn(E)},i.prototype.ushrn=function(E){return this.clone().iushrn(E)},i.prototype.testn=function(E){r(typeof E=="number"&&E>=0);var v=E%26,b=(E-v)/26,c=1<=0);var v=E%26,b=(E-v)/26;if(r(this.negative===0,"imaskn works only with positive numbers"),this.length<=b)return this;if(v!==0&&b++,this.length=Math.min(b,this.length),v!==0){var c=67108863^67108863>>>v<=67108864;v++)this.words[v]-=67108864,v===this.length-1?this.words[v+1]=1:this.words[v+1]++;return this.length=Math.max(this.length,v+1),this},i.prototype.isubn=function(E){if(r(typeof E=="number"),r(E<67108864),E<0)return this.iaddn(-E);if(this.negative!==0)return this.negative=0,this.iaddn(E),this.negative=1,this;if(this.words[0]-=E,this.length===1&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var v=0;v>26)-(C/67108864|0),this.words[g+b]=w&67108863}for(;g>26,this.words[g+b]=w&67108863;if(R===0)return this.strip();for(r(R===-1),R=0,g=0;g>26,this.words[g]=w&67108863;return this.negative=1,this.strip()},i.prototype._wordDiv=function(E,v){var b=this.length-E.length,c=this.clone(),g=E,w=g.words[g.length-1]|0,R=this._countBits(w);b=26-R,b!==0&&(g=g.ushln(b),c.iushln(b),w=g.words[g.length-1]|0);var C=c.length-g.length,h;if(v!=="mod"){h=new i(null),h.length=C+1,h.words=new Array(h.length);for(var D=0;D=0;B--){var k=(c.words[g.length+B]|0)*67108864+(c.words[g.length+B-1]|0);for(k=Math.min(k/w|0,67108863),c._ishlnsubmul(g,k,B);c.negative!==0;)k--,c.negative=0,c._ishlnsubmul(g,1,B),c.isZero()||(c.negative^=1);h&&(h.words[B]=k)}return h&&h.strip(),c.strip(),v!=="div"&&b!==0&&c.iushrn(b),{div:h||null,mod:c}},i.prototype.divmod=function(E,v,b){if(r(!E.isZero()),this.isZero())return{div:new i(0),mod:new i(0)};var c,g,w;return this.negative!==0&&E.negative===0?(w=this.neg().divmod(E,v),v!=="mod"&&(c=w.div.neg()),v!=="div"&&(g=w.mod.neg(),b&&g.negative!==0&&g.iadd(E)),{div:c,mod:g}):this.negative===0&&E.negative!==0?(w=this.divmod(E.neg(),v),v!=="mod"&&(c=w.div.neg()),{div:c,mod:w.mod}):(this.negative&E.negative)!==0?(w=this.neg().divmod(E.neg(),v),v!=="div"&&(g=w.mod.neg(),b&&g.negative!==0&&g.isub(E)),{div:w.div,mod:g}):E.length>this.length||this.cmp(E)<0?{div:new i(0),mod:this}:E.length===1?v==="div"?{div:this.divn(E.words[0]),mod:null}:v==="mod"?{div:null,mod:new i(this.modn(E.words[0]))}:{div:this.divn(E.words[0]),mod:new i(this.modn(E.words[0]))}:this._wordDiv(E,v)},i.prototype.div=function(E){return this.divmod(E,"div",!1).div},i.prototype.mod=function(E){return this.divmod(E,"mod",!1).mod},i.prototype.umod=function(E){return this.divmod(E,"mod",!0).mod},i.prototype.divRound=function(E){var v=this.divmod(E);if(v.mod.isZero())return v.div;var b=v.div.negative!==0?v.mod.isub(E):v.mod,c=E.ushrn(1),g=E.andln(1),w=b.cmp(c);return w<0||g===1&&w===0?v.div:v.div.negative!==0?v.div.isubn(1):v.div.iaddn(1)},i.prototype.modn=function(E){r(E<=67108863);for(var v=(1<<26)%E,b=0,c=this.length-1;c>=0;c--)b=(v*b+(this.words[c]|0))%E;return b},i.prototype.idivn=function(E){r(E<=67108863);for(var v=0,b=this.length-1;b>=0;b--){var c=(this.words[b]|0)+v*67108864;this.words[b]=c/E|0,v=c%E}return this.strip()},i.prototype.divn=function(E){return this.clone().idivn(E)},i.prototype.egcd=function(E){r(E.negative===0),r(!E.isZero());var v=this,b=E.clone();v.negative!==0?v=v.umod(E):v=v.clone();for(var c=new i(1),g=new i(0),w=new i(0),R=new i(1),C=0;v.isEven()&&b.isEven();)v.iushrn(1),b.iushrn(1),++C;for(var h=b.clone(),D=v.clone();!v.isZero();){for(var M=0,B=1;(v.words[0]&B)===0&&M<26;++M,B<<=1);if(M>0)for(v.iushrn(M);M-- >0;)(c.isOdd()||g.isOdd())&&(c.iadd(h),g.isub(D)),c.iushrn(1),g.iushrn(1);for(var k=0,ne=1;(b.words[0]&ne)===0&&k<26;++k,ne<<=1);if(k>0)for(b.iushrn(k);k-- >0;)(w.isOdd()||R.isOdd())&&(w.iadd(h),R.isub(D)),w.iushrn(1),R.iushrn(1);v.cmp(b)>=0?(v.isub(b),c.isub(w),g.isub(R)):(b.isub(v),w.isub(c),R.isub(g))}return{a:w,b:R,gcd:b.iushln(C)}},i.prototype._invmp=function(E){r(E.negative===0),r(!E.isZero());var v=this,b=E.clone();v.negative!==0?v=v.umod(E):v=v.clone();for(var c=new i(1),g=new i(0),w=b.clone();v.cmpn(1)>0&&b.cmpn(1)>0;){for(var R=0,C=1;(v.words[0]&C)===0&&R<26;++R,C<<=1);if(R>0)for(v.iushrn(R);R-- >0;)c.isOdd()&&c.iadd(w),c.iushrn(1);for(var h=0,D=1;(b.words[0]&D)===0&&h<26;++h,D<<=1);if(h>0)for(b.iushrn(h);h-- >0;)g.isOdd()&&g.iadd(w),g.iushrn(1);v.cmp(b)>=0?(v.isub(b),c.isub(g)):(b.isub(v),g.isub(c))}var M;return v.cmpn(1)===0?M=c:M=g,M.cmpn(0)<0&&M.iadd(E),M},i.prototype.gcd=function(E){if(this.isZero())return E.abs();if(E.isZero())return this.abs();var v=this.clone(),b=E.clone();v.negative=0,b.negative=0;for(var c=0;v.isEven()&&b.isEven();c++)v.iushrn(1),b.iushrn(1);do{for(;v.isEven();)v.iushrn(1);for(;b.isEven();)b.iushrn(1);var g=v.cmp(b);if(g<0){var w=v;v=b,b=w}else if(g===0||b.cmpn(1)===0)break;v.isub(b)}while(!0);return b.iushln(c)},i.prototype.invm=function(E){return this.egcd(E).a.umod(E)},i.prototype.isEven=function(){return(this.words[0]&1)===0},i.prototype.isOdd=function(){return(this.words[0]&1)===1},i.prototype.andln=function(E){return this.words[0]&E},i.prototype.bincn=function(E){r(typeof E=="number");var v=E%26,b=(E-v)/26,c=1<>>26,R&=67108863,this.words[w]=R}return g!==0&&(this.words[w]=g,this.length++),this},i.prototype.isZero=function(){return this.length===1&&this.words[0]===0},i.prototype.cmpn=function(E){var v=E<0;if(this.negative!==0&&!v)return-1;if(this.negative===0&&v)return 1;this.strip();var b;if(this.length>1)b=1;else{v&&(E=-E),r(E<=67108863,"Number is too big");var c=this.words[0]|0;b=c===E?0:cE.length)return 1;if(this.length=0;b--){var c=this.words[b]|0,g=E.words[b]|0;if(c!==g){cg&&(v=1);break}}return v},i.prototype.gtn=function(E){return this.cmpn(E)===1},i.prototype.gt=function(E){return this.cmp(E)===1},i.prototype.gten=function(E){return this.cmpn(E)>=0},i.prototype.gte=function(E){return this.cmp(E)>=0},i.prototype.ltn=function(E){return this.cmpn(E)===-1},i.prototype.lt=function(E){return this.cmp(E)===-1},i.prototype.lten=function(E){return this.cmpn(E)<=0},i.prototype.lte=function(E){return this.cmp(E)<=0},i.prototype.eqn=function(E){return this.cmpn(E)===0},i.prototype.eq=function(E){return this.cmp(E)===0},i.red=function(E){return new ie(E)},i.prototype.toRed=function(E){return r(!this.red,"Already a number in reduction context"),r(this.negative===0,"red works only with positives"),E.convertTo(this)._forceRed(E)},i.prototype.fromRed=function(){return r(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},i.prototype._forceRed=function(E){return this.red=E,this},i.prototype.forceRed=function(E){return r(!this.red,"Already a number in reduction context"),this._forceRed(E)},i.prototype.redAdd=function(E){return r(this.red,"redAdd works only with red numbers"),this.red.add(this,E)},i.prototype.redIAdd=function(E){return r(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,E)},i.prototype.redSub=function(E){return r(this.red,"redSub works only with red numbers"),this.red.sub(this,E)},i.prototype.redISub=function(E){return r(this.red,"redISub works only with red numbers"),this.red.isub(this,E)},i.prototype.redShl=function(E){return r(this.red,"redShl works only with red numbers"),this.red.shl(this,E)},i.prototype.redMul=function(E){return r(this.red,"redMul works only with red numbers"),this.red._verify2(this,E),this.red.mul(this,E)},i.prototype.redIMul=function(E){return r(this.red,"redMul works only with red numbers"),this.red._verify2(this,E),this.red.imul(this,E)},i.prototype.redSqr=function(){return r(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},i.prototype.redISqr=function(){return r(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},i.prototype.redSqrt=function(){return r(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},i.prototype.redInvm=function(){return r(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},i.prototype.redNeg=function(){return r(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},i.prototype.redPow=function(E){return r(this.red&&!E.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,E)};var G={k256:null,p224:null,p192:null,p25519:null};function Y(H,E){this.name=H,this.p=new i(E,16),this.n=this.p.bitLength(),this.k=new i(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}Y.prototype._tmp=function(){var E=new i(null);return E.words=new Array(Math.ceil(this.n/13)),E},Y.prototype.ireduce=function(E){var v=E,b;do this.split(v,this.tmp),v=this.imulK(v),v=v.iadd(this.tmp),b=v.bitLength();while(b>this.n);var c=b0?v.isub(this.p):v.strip!==void 0?v.strip():v._strip(),v},Y.prototype.split=function(E,v){E.iushrn(this.n,0,v)},Y.prototype.imulK=function(E){return E.imul(this.k)};function X(){Y.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}n(X,Y),X.prototype.split=function(E,v){for(var b=4194303,c=Math.min(E.length,9),g=0;g>>22,w=R}w>>>=22,E.words[g-10]=w,w===0&&E.length>10?E.length-=10:E.length-=9},X.prototype.imulK=function(E){E.words[E.length]=0,E.words[E.length+1]=0,E.length+=2;for(var v=0,b=0;b>>=26,E.words[b]=g,v=c}return v!==0&&(E.words[E.length++]=v),E},i._prime=function(E){if(G[E])return G[E];var v;if(E==="k256")v=new X;else if(E==="p224")v=new Z;else if(E==="p192")v=new j;else if(E==="p25519")v=new se;else throw new Error("Unknown prime "+E);return G[E]=v,v};function ie(H){if(typeof H=="string"){var E=i._prime(H);this.m=E.p,this.prime=E}else r(H.gtn(1),"modulus must be greater than 1"),this.m=H,this.prime=null}ie.prototype._verify1=function(E){r(E.negative===0,"red works only with positives"),r(E.red,"red works only with red numbers")},ie.prototype._verify2=function(E,v){r((E.negative|v.negative)===0,"red works only with positives"),r(E.red&&E.red===v.red,"red works only with red numbers")},ie.prototype.imod=function(E){return this.prime?this.prime.ireduce(E)._forceRed(this):E.umod(this.m)._forceRed(this)},ie.prototype.neg=function(E){return E.isZero()?E.clone():this.m.sub(E)._forceRed(this)},ie.prototype.add=function(E,v){this._verify2(E,v);var b=E.add(v);return b.cmp(this.m)>=0&&b.isub(this.m),b._forceRed(this)},ie.prototype.iadd=function(E,v){this._verify2(E,v);var b=E.iadd(v);return b.cmp(this.m)>=0&&b.isub(this.m),b},ie.prototype.sub=function(E,v){this._verify2(E,v);var b=E.sub(v);return b.cmpn(0)<0&&b.iadd(this.m),b._forceRed(this)},ie.prototype.isub=function(E,v){this._verify2(E,v);var b=E.isub(v);return b.cmpn(0)<0&&b.iadd(this.m),b},ie.prototype.shl=function(E,v){return this._verify1(E),this.imod(E.ushln(v))},ie.prototype.imul=function(E,v){return this._verify2(E,v),this.imod(E.imul(v))},ie.prototype.mul=function(E,v){return this._verify2(E,v),this.imod(E.mul(v))},ie.prototype.isqr=function(E){return this.imul(E,E.clone())},ie.prototype.sqr=function(E){return this.mul(E,E)},ie.prototype.sqrt=function(E){if(E.isZero())return E.clone();var v=this.m.andln(3);if(r(v%2===1),v===3){var b=this.m.add(new i(1)).iushrn(2);return this.pow(E,b)}for(var c=this.m.subn(1),g=0;!c.isZero()&&c.andln(1)===0;)g++,c.iushrn(1);r(!c.isZero());var w=new i(1).toRed(this),R=w.redNeg(),C=this.m.subn(1).iushrn(1),h=this.m.bitLength();for(h=new i(2*h*h).toRed(this);this.pow(h,C).cmp(R)!==0;)h.redIAdd(R);for(var D=this.pow(h,c),M=this.pow(E,c.addn(1).iushrn(1)),B=this.pow(E,c),k=g;B.cmp(w)!==0;){for(var ne=B,Ae=0;ne.cmp(w)!==0;Ae++)ne=ne.redSqr();r(Ae=0;g--){for(var D=v.words[g],M=h-1;M>=0;M--){var B=D>>M&1;if(w!==c[0]&&(w=this.sqr(w)),B===0&&R===0){C=0;continue}R<<=1,R|=B,C++,!(C!==b&&(g!==0||M!==0))&&(w=this.mul(w,c[R]),C=0,R=0)}h=26}return w},ie.prototype.convertTo=function(E){var v=E.umod(this.m);return v===E?v.clone():v},ie.prototype.convertFrom=function(E){var v=E.clone();return v.red=null,v},i.mont=function(E){return new ce(E)};function ce(H){ie.call(this,H),this.shift=this.m.bitLength(),this.shift%26!==0&&(this.shift+=26-this.shift%26),this.r=new i(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}n(ce,ie),ce.prototype.convertTo=function(E){return this.imod(E.ushln(this.shift))},ce.prototype.convertFrom=function(E){var v=this.imod(E.mul(this.rinv));return v.red=null,v},ce.prototype.imul=function(E,v){if(E.isZero()||v.isZero())return E.words[0]=0,E.length=1,E;var b=E.imul(v),c=b.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),g=b.isub(c).iushrn(this.shift),w=g;return g.cmp(this.m)>=0?w=g.isub(this.m):g.cmpn(0)<0&&(w=g.iadd(this.m)),w._forceRed(this)},ce.prototype.mul=function(E,v){if(E.isZero()||v.isZero())return new i(0)._forceRed(this);var b=E.mul(v),c=b.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),g=b.isub(c).iushrn(this.shift),w=g;return g.cmp(this.m)>=0?w=g.isub(this.m):g.cmpn(0)<0&&(w=g.iadd(this.m)),w._forceRed(this)},ce.prototype.invm=function(E){var v=this.imod(E._invmp(this.m).mul(this.r2));return v._forceRed(this)}})(typeof pS>"u"||pS,P5)});var py=U((YNe,mS)=>{var ES;mS.exports=function(t){return ES||(ES=new AA(null)),ES.generate(t)};function AA(e){this.rand=e}mS.exports.Rand=AA;AA.prototype.generate=function(t){return this._rand(t)};AA.prototype._rand=function(t){if(this.rand.getBytes)return this.rand.getBytes(t);for(var r=new Uint8Array(t),n=0;n{var Tf=kr(),wde=py();function Nf(e){this.rand=e||new wde.Rand}O5.exports=Nf;Nf.create=function(t){return new Nf(t)};Nf.prototype._randbelow=function(t){var r=t.bitLength(),n=Math.ceil(r/8);do var i=new Tf(this.rand.generate(n));while(i.cmp(t)>=0);return i};Nf.prototype._randrange=function(t,r){var n=r.sub(t);return t.add(this._randbelow(n))};Nf.prototype.test=function(t,r,n){var i=t.bitLength(),s=Tf.mont(t),o=new Tf(1).toRed(s);r||(r=Math.max(1,i/48|0));for(var a=t.subn(1),A=0;!a.testn(A);A++);for(var f=t.shrn(A),l=a.toRed(s),p=!0;r>0;r--){var I=this._randrange(new Tf(2),a);n&&n(I);var S=I.toRed(s).redPow(f);if(!(S.cmp(o)===0||S.cmp(l)===0)){for(var _=1;_0;r--){var l=this._randrange(new Tf(2),o),p=t.gcd(l);if(p.cmpn(1)!==0)return p;var I=l.toRed(i).redPow(A);if(!(I.cmp(s)===0||I.cmp(f)===0)){for(var S=1;S{var Sde=mf();G5.exports=wS;wS.simpleSieve=CS;wS.fermatTest=QS;var Jr=kr(),_de=new Jr(24),vde=BS(),H5=new vde,Rde=new Jr(1),bS=new Jr(2),Dde=new Jr(5),VNe=new Jr(16),JNe=new Jr(8),Tde=new Jr(10),Nde=new Jr(3),jNe=new Jr(7),Mde=new Jr(11),q5=new Jr(4),zNe=new Jr(12),IS=null;function Fde(){if(IS!==null)return IS;var e=1048576,t=[];t[0]=2;for(var r=1,n=3;ne;)r.ishrn(1);if(r.isEven()&&r.iadd(Rde),r.testn(1)||r.iadd(bS),t.cmp(bS)){if(!t.cmp(Dde))for(;r.mod(Tde).cmp(Nde);)r.iadd(q5)}else for(;r.mod(_de).cmp(Mde);)r.iadd(q5);if(n=r.shrn(1),CS(n)&&CS(r)&&QS(n)&&QS(r)&&H5.test(n)&&H5.test(r))return r}}});var Y5=U((XNe,kde)=>{kde.exports={modp1:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff"},modp2:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff"},modp5:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff"},modp14:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff"},modp15:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff"},modp16:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff"},modp17:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff"},modp18:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff"}}});var j5=U((ZNe,J5)=>{var Qi=kr(),Ude=BS(),W5=new Ude,xde=new Qi(24),Lde=new Qi(11),Pde=new Qi(10),Ode=new Qi(3),Hde=new Qi(7),V5=SS(),qde=mf();J5.exports=sa;function Gde(e,t){return t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t)),this._pub=new Qi(e),this}function Yde(e,t){return t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t)),this._priv=new Qi(e),this}var Ey={};function Wde(e,t){var r=t.toString("hex"),n=[r,e.toString(16)].join("_");if(n in Ey)return Ey[n];var i=0;if(e.isEven()||!V5.simpleSieve||!V5.fermatTest(e)||!W5.test(e))return i+=1,r==="02"||r==="05"?i+=8:i+=4,Ey[n]=i,i;W5.test(e.shrn(1))||(i+=2);var s;switch(r){case"02":e.mod(xde).cmp(Lde)&&(i+=8);break;case"05":s=e.mod(Pde),s.cmp(Ode)&&s.cmp(Hde)&&(i+=8);break;default:i+=4}return Ey[n]=i,i}function sa(e,t,r){this.setGenerator(t),this.__prime=new Qi(e),this._prime=Qi.mont(this.__prime),this._primeLen=e.length,this._pub=void 0,this._priv=void 0,this._primeCode=void 0,r?(this.setPublicKey=Gde,this.setPrivateKey=Yde):this._primeCode=8}Object.defineProperty(sa.prototype,"verifyError",{enumerable:!0,get:function(){return typeof this._primeCode!="number"&&(this._primeCode=Wde(this.__prime,this.__gen)),this._primeCode}});sa.prototype.generateKeys=function(){return this._priv||(this._priv=new Qi(qde(this._primeLen))),this._pub=this._gen.toRed(this._prime).redPow(this._priv).fromRed(),this.getPublicKey()};sa.prototype.computeSecret=function(e){e=new Qi(e),e=e.toRed(this._prime);var t=e.redPow(this._priv).fromRed(),r=new Buffer(t.toArray()),n=this.getPrime();if(r.length{var Vde=SS(),z5=Y5(),_S=j5();function Jde(e){var t=new Buffer(z5[e].prime,"hex"),r=new Buffer(z5[e].gen,"hex");return new _S(t,r)}var jde={binary:!0,hex:!0,base64:!0};function K5(e,t,r,n){return Buffer.isBuffer(t)||jde[t]===void 0?K5(e,"binary",t,r):(t=t||"binary",n=n||"binary",r=r||new Buffer([2]),Buffer.isBuffer(r)||(r=new Buffer(r,n)),typeof e=="number"?new _S(Vde(e,r),r,!0):(Buffer.isBuffer(e)||(e=new Buffer(e,t)),new _S(e,r,!0)))}Pc.DiffieHellmanGroup=Pc.createDiffieHellmanGroup=Pc.getDiffieHellman=Jde;Pc.createDiffieHellman=Pc.DiffieHellman=K5});var my=U((Z5,vS)=>{(function(e,t){"use strict";function r(b,c){if(!b)throw new Error(c||"Assertion failed")}function n(b,c){b.super_=c;var g=function(){};g.prototype=c.prototype,b.prototype=new g,b.prototype.constructor=b}function i(b,c,g){if(i.isBN(b))return b;this.negative=0,this.words=null,this.length=0,this.red=null,b!==null&&((c==="le"||c==="be")&&(g=c,c=10),this._init(b||0,c||10,g||"be"))}typeof e=="object"?e.exports=i:t.BN=i,i.BN=i,i.wordSize=26;var s;try{typeof window<"u"&&typeof window.Buffer<"u"?s=window.Buffer:s=Gr().Buffer}catch{}i.isBN=function(c){return c instanceof i?!0:c!==null&&typeof c=="object"&&c.constructor.wordSize===i.wordSize&&Array.isArray(c.words)},i.max=function(c,g){return c.cmp(g)>0?c:g},i.min=function(c,g){return c.cmp(g)<0?c:g},i.prototype._init=function(c,g,w){if(typeof c=="number")return this._initNumber(c,g,w);if(typeof c=="object")return this._initArray(c,g,w);g==="hex"&&(g=16),r(g===(g|0)&&g>=2&&g<=36),c=c.toString().replace(/\s+/g,"");var R=0;c[0]==="-"&&(R++,this.negative=1),R=0;R-=3)h=c[R]|c[R-1]<<8|c[R-2]<<16,this.words[C]|=h<>>26-D&67108863,D+=24,D>=26&&(D-=26,C++);else if(w==="le")for(R=0,C=0;R>>26-D&67108863,D+=24,D>=26&&(D-=26,C++);return this._strip()};function o(b,c){var g=b.charCodeAt(c);if(g>=48&&g<=57)return g-48;if(g>=65&&g<=70)return g-55;if(g>=97&&g<=102)return g-87;r(!1,"Invalid character in "+b)}function a(b,c,g){var w=o(b,g);return g-1>=c&&(w|=o(b,g-1)<<4),w}i.prototype._parseHex=function(c,g,w){this.length=Math.ceil((c.length-g)/6),this.words=new Array(this.length);for(var R=0;R=g;R-=2)D=a(c,g,R)<=18?(C-=18,h+=1,this.words[h]|=D>>>26):C+=8;else{var M=c.length-g;for(R=M%2===0?g+1:g;R=18?(C-=18,h+=1,this.words[h]|=D>>>26):C+=8}this._strip()};function A(b,c,g,w){for(var R=0,C=0,h=Math.min(b.length,g),D=c;D=49?C=M-49+10:M>=17?C=M-17+10:C=M,r(M>=0&&C1&&this.words[this.length-1]===0;)this.length--;return this._normSign()},i.prototype._normSign=function(){return this.length===1&&this.words[0]===0&&(this.negative=0),this},typeof Symbol<"u"&&typeof Symbol.for=="function")try{i.prototype[Symbol.for("nodejs.util.inspect.custom")]=l}catch{i.prototype.inspect=l}else i.prototype.inspect=l;function l(){return(this.red?""}var p=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],I=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],S=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];i.prototype.toString=function(c,g){c=c||10,g=g|0||1;var w;if(c===16||c==="hex"){w="";for(var R=0,C=0,h=0;h>>24-R&16777215,R+=2,R>=26&&(R-=26,h--),C!==0||h!==this.length-1?w=p[6-M.length]+M+w:w=M+w}for(C!==0&&(w=C.toString(16)+w);w.length%g!==0;)w="0"+w;return this.negative!==0&&(w="-"+w),w}if(c===(c|0)&&c>=2&&c<=36){var B=I[c],k=S[c];w="";var ne=this.clone();for(ne.negative=0;!ne.isZero();){var Ae=ne.modrn(k).toString(c);ne=ne.idivn(k),ne.isZero()?w=Ae+w:w=p[B-Ae.length]+Ae+w}for(this.isZero()&&(w="0"+w);w.length%g!==0;)w="0"+w;return this.negative!==0&&(w="-"+w),w}r(!1,"Base should be between 2 and 36")},i.prototype.toNumber=function(){var c=this.words[0];return this.length===2?c+=this.words[1]*67108864:this.length===3&&this.words[2]===1?c+=4503599627370496+this.words[1]*67108864:this.length>2&&r(!1,"Number can only safely store up to 53 bits"),this.negative!==0?-c:c},i.prototype.toJSON=function(){return this.toString(16,2)},s&&(i.prototype.toBuffer=function(c,g){return this.toArrayLike(s,c,g)}),i.prototype.toArray=function(c,g){return this.toArrayLike(Array,c,g)};var _=function(c,g){return c.allocUnsafe?c.allocUnsafe(g):new c(g)};i.prototype.toArrayLike=function(c,g,w){this._strip();var R=this.byteLength(),C=w||Math.max(1,R);r(R<=C,"byte array longer than desired length"),r(C>0,"Requested array length <= 0");var h=_(c,C),D=g==="le"?"LE":"BE";return this["_toArrayLike"+D](h,R),h},i.prototype._toArrayLikeLE=function(c,g){for(var w=0,R=0,C=0,h=0;C>8&255),w>16&255),h===6?(w>24&255),R=0,h=0):(R=D>>>24,h+=2)}if(w=0&&(c[w--]=D>>8&255),w>=0&&(c[w--]=D>>16&255),h===6?(w>=0&&(c[w--]=D>>24&255),R=0,h=0):(R=D>>>24,h+=2)}if(w>=0)for(c[w--]=R;w>=0;)c[w--]=0},Math.clz32?i.prototype._countBits=function(c){return 32-Math.clz32(c)}:i.prototype._countBits=function(c){var g=c,w=0;return g>=4096&&(w+=13,g>>>=13),g>=64&&(w+=7,g>>>=7),g>=8&&(w+=4,g>>>=4),g>=2&&(w+=2,g>>>=2),w+g},i.prototype._zeroBits=function(c){if(c===0)return 26;var g=c,w=0;return(g&8191)===0&&(w+=13,g>>>=13),(g&127)===0&&(w+=7,g>>>=7),(g&15)===0&&(w+=4,g>>>=4),(g&3)===0&&(w+=2,g>>>=2),(g&1)===0&&w++,w},i.prototype.bitLength=function(){var c=this.words[this.length-1],g=this._countBits(c);return(this.length-1)*26+g};function N(b){for(var c=new Array(b.bitLength()),g=0;g>>R&1}return c}i.prototype.zeroBits=function(){if(this.isZero())return 0;for(var c=0,g=0;gc.length?this.clone().ior(c):c.clone().ior(this)},i.prototype.uor=function(c){return this.length>c.length?this.clone().iuor(c):c.clone().iuor(this)},i.prototype.iuand=function(c){var g;this.length>c.length?g=c:g=this;for(var w=0;wc.length?this.clone().iand(c):c.clone().iand(this)},i.prototype.uand=function(c){return this.length>c.length?this.clone().iuand(c):c.clone().iuand(this)},i.prototype.iuxor=function(c){var g,w;this.length>c.length?(g=this,w=c):(g=c,w=this);for(var R=0;Rc.length?this.clone().ixor(c):c.clone().ixor(this)},i.prototype.uxor=function(c){return this.length>c.length?this.clone().iuxor(c):c.clone().iuxor(this)},i.prototype.inotn=function(c){r(typeof c=="number"&&c>=0);var g=Math.ceil(c/26)|0,w=c%26;this._expand(g),w>0&&g--;for(var R=0;R0&&(this.words[R]=~this.words[R]&67108863>>26-w),this._strip()},i.prototype.notn=function(c){return this.clone().inotn(c)},i.prototype.setn=function(c,g){r(typeof c=="number"&&c>=0);var w=c/26|0,R=c%26;return this._expand(w+1),g?this.words[w]=this.words[w]|1<c.length?(w=this,R=c):(w=c,R=this);for(var C=0,h=0;h>>26;for(;C!==0&&h>>26;if(this.length=w.length,C!==0)this.words[this.length]=C,this.length++;else if(w!==this)for(;hc.length?this.clone().iadd(c):c.clone().iadd(this)},i.prototype.isub=function(c){if(c.negative!==0){c.negative=0;var g=this.iadd(c);return c.negative=1,g._normSign()}else if(this.negative!==0)return this.negative=0,this.iadd(c),this.negative=1,this._normSign();var w=this.cmp(c);if(w===0)return this.negative=0,this.length=1,this.words[0]=0,this;var R,C;w>0?(R=this,C=c):(R=c,C=this);for(var h=0,D=0;D>26,this.words[D]=g&67108863;for(;h!==0&&D>26,this.words[D]=g&67108863;if(h===0&&D>>26,ne=M&67108863,Ae=Math.min(B,c.length-1),ue=Math.max(0,B-b.length+1);ue<=Ae;ue++){var pe=B-ue|0;R=b.words[pe]|0,C=c.words[ue]|0,h=R*C+ne,k+=h/67108864|0,ne=h&67108863}g.words[B]=ne|0,M=k|0}return M!==0?g.words[B]=M|0:g.length--,g._strip()}var x=function(c,g,w){var R=c.words,C=g.words,h=w.words,D=0,M,B,k,ne=R[0]|0,Ae=ne&8191,ue=ne>>>13,pe=R[1]|0,he=pe&8191,de=pe>>>13,Qt=R[2]|0,Ie=Qt&8191,be=Qt>>>13,yr=R[3]|0,Qe=yr&8191,_e=yr>>>13,Ds=R[4]|0,Ge=Ds&8191,Ue=Ds>>>13,Ts=R[5]|0,Te=Ts&8191,De=Ts>>>13,en=R[6]|0,ve=en&8191,He=en>>>13,ai=R[7]|0,Ne=ai&8191,Ve=ai>>>13,F=R[8]|0,m=F&8191,Q=F>>>13,L=R[9]|0,W=L&8191,z=L>>>13,ae=C[0]|0,le=ae&8191,ye=ae>>>13,bt=C[1]|0,Ee=bt&8191,ge=bt>>>13,ka=C[2]|0,Je=ka&8191,tt=ka>>>13,Mo=C[3]|0,Ze=Mo&8191,rt=Mo>>>13,HA=C[4]|0,nt=HA&8191,it=HA>>>13,Ua=C[5]|0,ze=Ua&8191,Ke=Ua>>>13,qA=C[6]|0,xe=qA&8191,$e=qA>>>13,GA=C[7]|0,st=GA&8191,Le=GA>>>13,hn=C[8]|0,Pe=hn&8191,Xe=hn>>>13,Qn=C[9]|0,xt=Qn&8191,Ft=Qn>>>13;w.negative=c.negative^g.negative,w.length=19,M=Math.imul(Ae,le),B=Math.imul(Ae,ye),B=B+Math.imul(ue,le)|0,k=Math.imul(ue,ye);var Ns=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Ns>>>26)|0,Ns&=67108863,M=Math.imul(he,le),B=Math.imul(he,ye),B=B+Math.imul(de,le)|0,k=Math.imul(de,ye),M=M+Math.imul(Ae,Ee)|0,B=B+Math.imul(Ae,ge)|0,B=B+Math.imul(ue,Ee)|0,k=k+Math.imul(ue,ge)|0;var Ai=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Ai>>>26)|0,Ai&=67108863,M=Math.imul(Ie,le),B=Math.imul(Ie,ye),B=B+Math.imul(be,le)|0,k=Math.imul(be,ye),M=M+Math.imul(he,Ee)|0,B=B+Math.imul(he,ge)|0,B=B+Math.imul(de,Ee)|0,k=k+Math.imul(de,ge)|0,M=M+Math.imul(Ae,Je)|0,B=B+Math.imul(Ae,tt)|0,B=B+Math.imul(ue,Je)|0,k=k+Math.imul(ue,tt)|0;var Ms=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Ms>>>26)|0,Ms&=67108863,M=Math.imul(Qe,le),B=Math.imul(Qe,ye),B=B+Math.imul(_e,le)|0,k=Math.imul(_e,ye),M=M+Math.imul(Ie,Ee)|0,B=B+Math.imul(Ie,ge)|0,B=B+Math.imul(be,Ee)|0,k=k+Math.imul(be,ge)|0,M=M+Math.imul(he,Je)|0,B=B+Math.imul(he,tt)|0,B=B+Math.imul(de,Je)|0,k=k+Math.imul(de,tt)|0,M=M+Math.imul(Ae,Ze)|0,B=B+Math.imul(Ae,rt)|0,B=B+Math.imul(ue,Ze)|0,k=k+Math.imul(ue,rt)|0;var Fs=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Fs>>>26)|0,Fs&=67108863,M=Math.imul(Ge,le),B=Math.imul(Ge,ye),B=B+Math.imul(Ue,le)|0,k=Math.imul(Ue,ye),M=M+Math.imul(Qe,Ee)|0,B=B+Math.imul(Qe,ge)|0,B=B+Math.imul(_e,Ee)|0,k=k+Math.imul(_e,ge)|0,M=M+Math.imul(Ie,Je)|0,B=B+Math.imul(Ie,tt)|0,B=B+Math.imul(be,Je)|0,k=k+Math.imul(be,tt)|0,M=M+Math.imul(he,Ze)|0,B=B+Math.imul(he,rt)|0,B=B+Math.imul(de,Ze)|0,k=k+Math.imul(de,rt)|0,M=M+Math.imul(Ae,nt)|0,B=B+Math.imul(Ae,it)|0,B=B+Math.imul(ue,nt)|0,k=k+Math.imul(ue,it)|0;var ks=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(ks>>>26)|0,ks&=67108863,M=Math.imul(Te,le),B=Math.imul(Te,ye),B=B+Math.imul(De,le)|0,k=Math.imul(De,ye),M=M+Math.imul(Ge,Ee)|0,B=B+Math.imul(Ge,ge)|0,B=B+Math.imul(Ue,Ee)|0,k=k+Math.imul(Ue,ge)|0,M=M+Math.imul(Qe,Je)|0,B=B+Math.imul(Qe,tt)|0,B=B+Math.imul(_e,Je)|0,k=k+Math.imul(_e,tt)|0,M=M+Math.imul(Ie,Ze)|0,B=B+Math.imul(Ie,rt)|0,B=B+Math.imul(be,Ze)|0,k=k+Math.imul(be,rt)|0,M=M+Math.imul(he,nt)|0,B=B+Math.imul(he,it)|0,B=B+Math.imul(de,nt)|0,k=k+Math.imul(de,it)|0,M=M+Math.imul(Ae,ze)|0,B=B+Math.imul(Ae,Ke)|0,B=B+Math.imul(ue,ze)|0,k=k+Math.imul(ue,Ke)|0;var Us=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Us>>>26)|0,Us&=67108863,M=Math.imul(ve,le),B=Math.imul(ve,ye),B=B+Math.imul(He,le)|0,k=Math.imul(He,ye),M=M+Math.imul(Te,Ee)|0,B=B+Math.imul(Te,ge)|0,B=B+Math.imul(De,Ee)|0,k=k+Math.imul(De,ge)|0,M=M+Math.imul(Ge,Je)|0,B=B+Math.imul(Ge,tt)|0,B=B+Math.imul(Ue,Je)|0,k=k+Math.imul(Ue,tt)|0,M=M+Math.imul(Qe,Ze)|0,B=B+Math.imul(Qe,rt)|0,B=B+Math.imul(_e,Ze)|0,k=k+Math.imul(_e,rt)|0,M=M+Math.imul(Ie,nt)|0,B=B+Math.imul(Ie,it)|0,B=B+Math.imul(be,nt)|0,k=k+Math.imul(be,it)|0,M=M+Math.imul(he,ze)|0,B=B+Math.imul(he,Ke)|0,B=B+Math.imul(de,ze)|0,k=k+Math.imul(de,Ke)|0,M=M+Math.imul(Ae,xe)|0,B=B+Math.imul(Ae,$e)|0,B=B+Math.imul(ue,xe)|0,k=k+Math.imul(ue,$e)|0;var xs=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(xs>>>26)|0,xs&=67108863,M=Math.imul(Ne,le),B=Math.imul(Ne,ye),B=B+Math.imul(Ve,le)|0,k=Math.imul(Ve,ye),M=M+Math.imul(ve,Ee)|0,B=B+Math.imul(ve,ge)|0,B=B+Math.imul(He,Ee)|0,k=k+Math.imul(He,ge)|0,M=M+Math.imul(Te,Je)|0,B=B+Math.imul(Te,tt)|0,B=B+Math.imul(De,Je)|0,k=k+Math.imul(De,tt)|0,M=M+Math.imul(Ge,Ze)|0,B=B+Math.imul(Ge,rt)|0,B=B+Math.imul(Ue,Ze)|0,k=k+Math.imul(Ue,rt)|0,M=M+Math.imul(Qe,nt)|0,B=B+Math.imul(Qe,it)|0,B=B+Math.imul(_e,nt)|0,k=k+Math.imul(_e,it)|0,M=M+Math.imul(Ie,ze)|0,B=B+Math.imul(Ie,Ke)|0,B=B+Math.imul(be,ze)|0,k=k+Math.imul(be,Ke)|0,M=M+Math.imul(he,xe)|0,B=B+Math.imul(he,$e)|0,B=B+Math.imul(de,xe)|0,k=k+Math.imul(de,$e)|0,M=M+Math.imul(Ae,st)|0,B=B+Math.imul(Ae,Le)|0,B=B+Math.imul(ue,st)|0,k=k+Math.imul(ue,Le)|0;var Ji=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Ji>>>26)|0,Ji&=67108863,M=Math.imul(m,le),B=Math.imul(m,ye),B=B+Math.imul(Q,le)|0,k=Math.imul(Q,ye),M=M+Math.imul(Ne,Ee)|0,B=B+Math.imul(Ne,ge)|0,B=B+Math.imul(Ve,Ee)|0,k=k+Math.imul(Ve,ge)|0,M=M+Math.imul(ve,Je)|0,B=B+Math.imul(ve,tt)|0,B=B+Math.imul(He,Je)|0,k=k+Math.imul(He,tt)|0,M=M+Math.imul(Te,Ze)|0,B=B+Math.imul(Te,rt)|0,B=B+Math.imul(De,Ze)|0,k=k+Math.imul(De,rt)|0,M=M+Math.imul(Ge,nt)|0,B=B+Math.imul(Ge,it)|0,B=B+Math.imul(Ue,nt)|0,k=k+Math.imul(Ue,it)|0,M=M+Math.imul(Qe,ze)|0,B=B+Math.imul(Qe,Ke)|0,B=B+Math.imul(_e,ze)|0,k=k+Math.imul(_e,Ke)|0,M=M+Math.imul(Ie,xe)|0,B=B+Math.imul(Ie,$e)|0,B=B+Math.imul(be,xe)|0,k=k+Math.imul(be,$e)|0,M=M+Math.imul(he,st)|0,B=B+Math.imul(he,Le)|0,B=B+Math.imul(de,st)|0,k=k+Math.imul(de,Le)|0,M=M+Math.imul(Ae,Pe)|0,B=B+Math.imul(Ae,Xe)|0,B=B+Math.imul(ue,Pe)|0,k=k+Math.imul(ue,Xe)|0;var ji=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(ji>>>26)|0,ji&=67108863,M=Math.imul(W,le),B=Math.imul(W,ye),B=B+Math.imul(z,le)|0,k=Math.imul(z,ye),M=M+Math.imul(m,Ee)|0,B=B+Math.imul(m,ge)|0,B=B+Math.imul(Q,Ee)|0,k=k+Math.imul(Q,ge)|0,M=M+Math.imul(Ne,Je)|0,B=B+Math.imul(Ne,tt)|0,B=B+Math.imul(Ve,Je)|0,k=k+Math.imul(Ve,tt)|0,M=M+Math.imul(ve,Ze)|0,B=B+Math.imul(ve,rt)|0,B=B+Math.imul(He,Ze)|0,k=k+Math.imul(He,rt)|0,M=M+Math.imul(Te,nt)|0,B=B+Math.imul(Te,it)|0,B=B+Math.imul(De,nt)|0,k=k+Math.imul(De,it)|0,M=M+Math.imul(Ge,ze)|0,B=B+Math.imul(Ge,Ke)|0,B=B+Math.imul(Ue,ze)|0,k=k+Math.imul(Ue,Ke)|0,M=M+Math.imul(Qe,xe)|0,B=B+Math.imul(Qe,$e)|0,B=B+Math.imul(_e,xe)|0,k=k+Math.imul(_e,$e)|0,M=M+Math.imul(Ie,st)|0,B=B+Math.imul(Ie,Le)|0,B=B+Math.imul(be,st)|0,k=k+Math.imul(be,Le)|0,M=M+Math.imul(he,Pe)|0,B=B+Math.imul(he,Xe)|0,B=B+Math.imul(de,Pe)|0,k=k+Math.imul(de,Xe)|0,M=M+Math.imul(Ae,xt)|0,B=B+Math.imul(Ae,Ft)|0,B=B+Math.imul(ue,xt)|0,k=k+Math.imul(ue,Ft)|0;var Fo=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Fo>>>26)|0,Fo&=67108863,M=Math.imul(W,Ee),B=Math.imul(W,ge),B=B+Math.imul(z,Ee)|0,k=Math.imul(z,ge),M=M+Math.imul(m,Je)|0,B=B+Math.imul(m,tt)|0,B=B+Math.imul(Q,Je)|0,k=k+Math.imul(Q,tt)|0,M=M+Math.imul(Ne,Ze)|0,B=B+Math.imul(Ne,rt)|0,B=B+Math.imul(Ve,Ze)|0,k=k+Math.imul(Ve,rt)|0,M=M+Math.imul(ve,nt)|0,B=B+Math.imul(ve,it)|0,B=B+Math.imul(He,nt)|0,k=k+Math.imul(He,it)|0,M=M+Math.imul(Te,ze)|0,B=B+Math.imul(Te,Ke)|0,B=B+Math.imul(De,ze)|0,k=k+Math.imul(De,Ke)|0,M=M+Math.imul(Ge,xe)|0,B=B+Math.imul(Ge,$e)|0,B=B+Math.imul(Ue,xe)|0,k=k+Math.imul(Ue,$e)|0,M=M+Math.imul(Qe,st)|0,B=B+Math.imul(Qe,Le)|0,B=B+Math.imul(_e,st)|0,k=k+Math.imul(_e,Le)|0,M=M+Math.imul(Ie,Pe)|0,B=B+Math.imul(Ie,Xe)|0,B=B+Math.imul(be,Pe)|0,k=k+Math.imul(be,Xe)|0,M=M+Math.imul(he,xt)|0,B=B+Math.imul(he,Ft)|0,B=B+Math.imul(de,xt)|0,k=k+Math.imul(de,Ft)|0;var ko=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(ko>>>26)|0,ko&=67108863,M=Math.imul(W,Je),B=Math.imul(W,tt),B=B+Math.imul(z,Je)|0,k=Math.imul(z,tt),M=M+Math.imul(m,Ze)|0,B=B+Math.imul(m,rt)|0,B=B+Math.imul(Q,Ze)|0,k=k+Math.imul(Q,rt)|0,M=M+Math.imul(Ne,nt)|0,B=B+Math.imul(Ne,it)|0,B=B+Math.imul(Ve,nt)|0,k=k+Math.imul(Ve,it)|0,M=M+Math.imul(ve,ze)|0,B=B+Math.imul(ve,Ke)|0,B=B+Math.imul(He,ze)|0,k=k+Math.imul(He,Ke)|0,M=M+Math.imul(Te,xe)|0,B=B+Math.imul(Te,$e)|0,B=B+Math.imul(De,xe)|0,k=k+Math.imul(De,$e)|0,M=M+Math.imul(Ge,st)|0,B=B+Math.imul(Ge,Le)|0,B=B+Math.imul(Ue,st)|0,k=k+Math.imul(Ue,Le)|0,M=M+Math.imul(Qe,Pe)|0,B=B+Math.imul(Qe,Xe)|0,B=B+Math.imul(_e,Pe)|0,k=k+Math.imul(_e,Xe)|0,M=M+Math.imul(Ie,xt)|0,B=B+Math.imul(Ie,Ft)|0,B=B+Math.imul(be,xt)|0,k=k+Math.imul(be,Ft)|0;var Uo=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Uo>>>26)|0,Uo&=67108863,M=Math.imul(W,Ze),B=Math.imul(W,rt),B=B+Math.imul(z,Ze)|0,k=Math.imul(z,rt),M=M+Math.imul(m,nt)|0,B=B+Math.imul(m,it)|0,B=B+Math.imul(Q,nt)|0,k=k+Math.imul(Q,it)|0,M=M+Math.imul(Ne,ze)|0,B=B+Math.imul(Ne,Ke)|0,B=B+Math.imul(Ve,ze)|0,k=k+Math.imul(Ve,Ke)|0,M=M+Math.imul(ve,xe)|0,B=B+Math.imul(ve,$e)|0,B=B+Math.imul(He,xe)|0,k=k+Math.imul(He,$e)|0,M=M+Math.imul(Te,st)|0,B=B+Math.imul(Te,Le)|0,B=B+Math.imul(De,st)|0,k=k+Math.imul(De,Le)|0,M=M+Math.imul(Ge,Pe)|0,B=B+Math.imul(Ge,Xe)|0,B=B+Math.imul(Ue,Pe)|0,k=k+Math.imul(Ue,Xe)|0,M=M+Math.imul(Qe,xt)|0,B=B+Math.imul(Qe,Ft)|0,B=B+Math.imul(_e,xt)|0,k=k+Math.imul(_e,Ft)|0;var xo=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(xo>>>26)|0,xo&=67108863,M=Math.imul(W,nt),B=Math.imul(W,it),B=B+Math.imul(z,nt)|0,k=Math.imul(z,it),M=M+Math.imul(m,ze)|0,B=B+Math.imul(m,Ke)|0,B=B+Math.imul(Q,ze)|0,k=k+Math.imul(Q,Ke)|0,M=M+Math.imul(Ne,xe)|0,B=B+Math.imul(Ne,$e)|0,B=B+Math.imul(Ve,xe)|0,k=k+Math.imul(Ve,$e)|0,M=M+Math.imul(ve,st)|0,B=B+Math.imul(ve,Le)|0,B=B+Math.imul(He,st)|0,k=k+Math.imul(He,Le)|0,M=M+Math.imul(Te,Pe)|0,B=B+Math.imul(Te,Xe)|0,B=B+Math.imul(De,Pe)|0,k=k+Math.imul(De,Xe)|0,M=M+Math.imul(Ge,xt)|0,B=B+Math.imul(Ge,Ft)|0,B=B+Math.imul(Ue,xt)|0,k=k+Math.imul(Ue,Ft)|0;var Ls=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Ls>>>26)|0,Ls&=67108863,M=Math.imul(W,ze),B=Math.imul(W,Ke),B=B+Math.imul(z,ze)|0,k=Math.imul(z,Ke),M=M+Math.imul(m,xe)|0,B=B+Math.imul(m,$e)|0,B=B+Math.imul(Q,xe)|0,k=k+Math.imul(Q,$e)|0,M=M+Math.imul(Ne,st)|0,B=B+Math.imul(Ne,Le)|0,B=B+Math.imul(Ve,st)|0,k=k+Math.imul(Ve,Le)|0,M=M+Math.imul(ve,Pe)|0,B=B+Math.imul(ve,Xe)|0,B=B+Math.imul(He,Pe)|0,k=k+Math.imul(He,Xe)|0,M=M+Math.imul(Te,xt)|0,B=B+Math.imul(Te,Ft)|0,B=B+Math.imul(De,xt)|0,k=k+Math.imul(De,Ft)|0;var wn=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(wn>>>26)|0,wn&=67108863,M=Math.imul(W,xe),B=Math.imul(W,$e),B=B+Math.imul(z,xe)|0,k=Math.imul(z,$e),M=M+Math.imul(m,st)|0,B=B+Math.imul(m,Le)|0,B=B+Math.imul(Q,st)|0,k=k+Math.imul(Q,Le)|0,M=M+Math.imul(Ne,Pe)|0,B=B+Math.imul(Ne,Xe)|0,B=B+Math.imul(Ve,Pe)|0,k=k+Math.imul(Ve,Xe)|0,M=M+Math.imul(ve,xt)|0,B=B+Math.imul(ve,Ft)|0,B=B+Math.imul(He,xt)|0,k=k+Math.imul(He,Ft)|0;var Lo=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Lo>>>26)|0,Lo&=67108863,M=Math.imul(W,st),B=Math.imul(W,Le),B=B+Math.imul(z,st)|0,k=Math.imul(z,Le),M=M+Math.imul(m,Pe)|0,B=B+Math.imul(m,Xe)|0,B=B+Math.imul(Q,Pe)|0,k=k+Math.imul(Q,Xe)|0,M=M+Math.imul(Ne,xt)|0,B=B+Math.imul(Ne,Ft)|0,B=B+Math.imul(Ve,xt)|0,k=k+Math.imul(Ve,Ft)|0;var xa=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(xa>>>26)|0,xa&=67108863,M=Math.imul(W,Pe),B=Math.imul(W,Xe),B=B+Math.imul(z,Pe)|0,k=Math.imul(z,Xe),M=M+Math.imul(m,xt)|0,B=B+Math.imul(m,Ft)|0,B=B+Math.imul(Q,xt)|0,k=k+Math.imul(Q,Ft)|0;var Po=(D+M|0)+((B&8191)<<13)|0;D=(k+(B>>>13)|0)+(Po>>>26)|0,Po&=67108863,M=Math.imul(W,xt),B=Math.imul(W,Ft),B=B+Math.imul(z,xt)|0,k=Math.imul(z,Ft);var La=(D+M|0)+((B&8191)<<13)|0;return D=(k+(B>>>13)|0)+(La>>>26)|0,La&=67108863,h[0]=Ns,h[1]=Ai,h[2]=Ms,h[3]=Fs,h[4]=ks,h[5]=Us,h[6]=xs,h[7]=Ji,h[8]=ji,h[9]=Fo,h[10]=ko,h[11]=Uo,h[12]=xo,h[13]=Ls,h[14]=wn,h[15]=Lo,h[16]=xa,h[17]=Po,h[18]=La,D!==0&&(h[19]=D,w.length++),w};Math.imul||(x=O);function G(b,c,g){g.negative=c.negative^b.negative,g.length=b.length+c.length;for(var w=0,R=0,C=0;C>>26)|0,R+=h>>>26,h&=67108863}g.words[C]=D,w=h,h=R}return w!==0?g.words[C]=w:g.length--,g._strip()}function Y(b,c,g){return G(b,c,g)}i.prototype.mulTo=function(c,g){var w,R=this.length+c.length;return this.length===10&&c.length===10?w=x(this,c,g):R<63?w=O(this,c,g):R<1024?w=G(this,c,g):w=Y(this,c,g),w};function X(b,c){this.x=b,this.y=c}X.prototype.makeRBT=function(c){for(var g=new Array(c),w=i.prototype._countBits(c)-1,R=0;R>=1;return R},X.prototype.permute=function(c,g,w,R,C,h){for(var D=0;D>>1)C++;return 1<>>13,w[2*h+1]=C&8191,C=C>>>13;for(h=2*g;h>=26,w+=C/67108864|0,w+=h>>>26,this.words[R]=h&67108863}return w!==0&&(this.words[R]=w,this.length++),this.length=c===0?1:this.length,g?this.ineg():this},i.prototype.muln=function(c){return this.clone().imuln(c)},i.prototype.sqr=function(){return this.mul(this)},i.prototype.isqr=function(){return this.imul(this.clone())},i.prototype.pow=function(c){var g=N(c);if(g.length===0)return new i(1);for(var w=this,R=0;R=0);var g=c%26,w=(c-g)/26,R=67108863>>>26-g<<26-g,C;if(g!==0){var h=0;for(C=0;C>>26-g}h&&(this.words[C]=h,this.length++)}if(w!==0){for(C=this.length-1;C>=0;C--)this.words[C+w]=this.words[C];for(C=0;C=0);var R;g?R=(g-g%26)/26:R=0;var C=c%26,h=Math.min((c-C)/26,this.length),D=67108863^67108863>>>C<h)for(this.length-=h,B=0;B=0&&(k!==0||B>=R);B--){var ne=this.words[B]|0;this.words[B]=k<<26-C|ne>>>C,k=ne&D}return M&&k!==0&&(M.words[M.length++]=k),this.length===0&&(this.words[0]=0,this.length=1),this._strip()},i.prototype.ishrn=function(c,g,w){return r(this.negative===0),this.iushrn(c,g,w)},i.prototype.shln=function(c){return this.clone().ishln(c)},i.prototype.ushln=function(c){return this.clone().iushln(c)},i.prototype.shrn=function(c){return this.clone().ishrn(c)},i.prototype.ushrn=function(c){return this.clone().iushrn(c)},i.prototype.testn=function(c){r(typeof c=="number"&&c>=0);var g=c%26,w=(c-g)/26,R=1<=0);var g=c%26,w=(c-g)/26;if(r(this.negative===0,"imaskn works only with positive numbers"),this.length<=w)return this;if(g!==0&&w++,this.length=Math.min(w,this.length),g!==0){var R=67108863^67108863>>>g<=67108864;g++)this.words[g]-=67108864,g===this.length-1?this.words[g+1]=1:this.words[g+1]++;return this.length=Math.max(this.length,g+1),this},i.prototype.isubn=function(c){if(r(typeof c=="number"),r(c<67108864),c<0)return this.iaddn(-c);if(this.negative!==0)return this.negative=0,this.iaddn(c),this.negative=1,this;if(this.words[0]-=c,this.length===1&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var g=0;g>26)-(M/67108864|0),this.words[C+w]=h&67108863}for(;C>26,this.words[C+w]=h&67108863;if(D===0)return this._strip();for(r(D===-1),D=0,C=0;C>26,this.words[C]=h&67108863;return this.negative=1,this._strip()},i.prototype._wordDiv=function(c,g){var w=this.length-c.length,R=this.clone(),C=c,h=C.words[C.length-1]|0,D=this._countBits(h);w=26-D,w!==0&&(C=C.ushln(w),R.iushln(w),h=C.words[C.length-1]|0);var M=R.length-C.length,B;if(g!=="mod"){B=new i(null),B.length=M+1,B.words=new Array(B.length);for(var k=0;k=0;Ae--){var ue=(R.words[C.length+Ae]|0)*67108864+(R.words[C.length+Ae-1]|0);for(ue=Math.min(ue/h|0,67108863),R._ishlnsubmul(C,ue,Ae);R.negative!==0;)ue--,R.negative=0,R._ishlnsubmul(C,1,Ae),R.isZero()||(R.negative^=1);B&&(B.words[Ae]=ue)}return B&&B._strip(),R._strip(),g!=="div"&&w!==0&&R.iushrn(w),{div:B||null,mod:R}},i.prototype.divmod=function(c,g,w){if(r(!c.isZero()),this.isZero())return{div:new i(0),mod:new i(0)};var R,C,h;return this.negative!==0&&c.negative===0?(h=this.neg().divmod(c,g),g!=="mod"&&(R=h.div.neg()),g!=="div"&&(C=h.mod.neg(),w&&C.negative!==0&&C.iadd(c)),{div:R,mod:C}):this.negative===0&&c.negative!==0?(h=this.divmod(c.neg(),g),g!=="mod"&&(R=h.div.neg()),{div:R,mod:h.mod}):(this.negative&c.negative)!==0?(h=this.neg().divmod(c.neg(),g),g!=="div"&&(C=h.mod.neg(),w&&C.negative!==0&&C.isub(c)),{div:h.div,mod:C}):c.length>this.length||this.cmp(c)<0?{div:new i(0),mod:this}:c.length===1?g==="div"?{div:this.divn(c.words[0]),mod:null}:g==="mod"?{div:null,mod:new i(this.modrn(c.words[0]))}:{div:this.divn(c.words[0]),mod:new i(this.modrn(c.words[0]))}:this._wordDiv(c,g)},i.prototype.div=function(c){return this.divmod(c,"div",!1).div},i.prototype.mod=function(c){return this.divmod(c,"mod",!1).mod},i.prototype.umod=function(c){return this.divmod(c,"mod",!0).mod},i.prototype.divRound=function(c){var g=this.divmod(c);if(g.mod.isZero())return g.div;var w=g.div.negative!==0?g.mod.isub(c):g.mod,R=c.ushrn(1),C=c.andln(1),h=w.cmp(R);return h<0||C===1&&h===0?g.div:g.div.negative!==0?g.div.isubn(1):g.div.iaddn(1)},i.prototype.modrn=function(c){var g=c<0;g&&(c=-c),r(c<=67108863);for(var w=(1<<26)%c,R=0,C=this.length-1;C>=0;C--)R=(w*R+(this.words[C]|0))%c;return g?-R:R},i.prototype.modn=function(c){return this.modrn(c)},i.prototype.idivn=function(c){var g=c<0;g&&(c=-c),r(c<=67108863);for(var w=0,R=this.length-1;R>=0;R--){var C=(this.words[R]|0)+w*67108864;this.words[R]=C/c|0,w=C%c}return this._strip(),g?this.ineg():this},i.prototype.divn=function(c){return this.clone().idivn(c)},i.prototype.egcd=function(c){r(c.negative===0),r(!c.isZero());var g=this,w=c.clone();g.negative!==0?g=g.umod(c):g=g.clone();for(var R=new i(1),C=new i(0),h=new i(0),D=new i(1),M=0;g.isEven()&&w.isEven();)g.iushrn(1),w.iushrn(1),++M;for(var B=w.clone(),k=g.clone();!g.isZero();){for(var ne=0,Ae=1;(g.words[0]&Ae)===0&&ne<26;++ne,Ae<<=1);if(ne>0)for(g.iushrn(ne);ne-- >0;)(R.isOdd()||C.isOdd())&&(R.iadd(B),C.isub(k)),R.iushrn(1),C.iushrn(1);for(var ue=0,pe=1;(w.words[0]&pe)===0&&ue<26;++ue,pe<<=1);if(ue>0)for(w.iushrn(ue);ue-- >0;)(h.isOdd()||D.isOdd())&&(h.iadd(B),D.isub(k)),h.iushrn(1),D.iushrn(1);g.cmp(w)>=0?(g.isub(w),R.isub(h),C.isub(D)):(w.isub(g),h.isub(R),D.isub(C))}return{a:h,b:D,gcd:w.iushln(M)}},i.prototype._invmp=function(c){r(c.negative===0),r(!c.isZero());var g=this,w=c.clone();g.negative!==0?g=g.umod(c):g=g.clone();for(var R=new i(1),C=new i(0),h=w.clone();g.cmpn(1)>0&&w.cmpn(1)>0;){for(var D=0,M=1;(g.words[0]&M)===0&&D<26;++D,M<<=1);if(D>0)for(g.iushrn(D);D-- >0;)R.isOdd()&&R.iadd(h),R.iushrn(1);for(var B=0,k=1;(w.words[0]&k)===0&&B<26;++B,k<<=1);if(B>0)for(w.iushrn(B);B-- >0;)C.isOdd()&&C.iadd(h),C.iushrn(1);g.cmp(w)>=0?(g.isub(w),R.isub(C)):(w.isub(g),C.isub(R))}var ne;return g.cmpn(1)===0?ne=R:ne=C,ne.cmpn(0)<0&&ne.iadd(c),ne},i.prototype.gcd=function(c){if(this.isZero())return c.abs();if(c.isZero())return this.abs();var g=this.clone(),w=c.clone();g.negative=0,w.negative=0;for(var R=0;g.isEven()&&w.isEven();R++)g.iushrn(1),w.iushrn(1);do{for(;g.isEven();)g.iushrn(1);for(;w.isEven();)w.iushrn(1);var C=g.cmp(w);if(C<0){var h=g;g=w,w=h}else if(C===0||w.cmpn(1)===0)break;g.isub(w)}while(!0);return w.iushln(R)},i.prototype.invm=function(c){return this.egcd(c).a.umod(c)},i.prototype.isEven=function(){return(this.words[0]&1)===0},i.prototype.isOdd=function(){return(this.words[0]&1)===1},i.prototype.andln=function(c){return this.words[0]&c},i.prototype.bincn=function(c){r(typeof c=="number");var g=c%26,w=(c-g)/26,R=1<>>26,D&=67108863,this.words[h]=D}return C!==0&&(this.words[h]=C,this.length++),this},i.prototype.isZero=function(){return this.length===1&&this.words[0]===0},i.prototype.cmpn=function(c){var g=c<0;if(this.negative!==0&&!g)return-1;if(this.negative===0&&g)return 1;this._strip();var w;if(this.length>1)w=1;else{g&&(c=-c),r(c<=67108863,"Number is too big");var R=this.words[0]|0;w=R===c?0:Rc.length)return 1;if(this.length=0;w--){var R=this.words[w]|0,C=c.words[w]|0;if(R!==C){RC&&(g=1);break}}return g},i.prototype.gtn=function(c){return this.cmpn(c)===1},i.prototype.gt=function(c){return this.cmp(c)===1},i.prototype.gten=function(c){return this.cmpn(c)>=0},i.prototype.gte=function(c){return this.cmp(c)>=0},i.prototype.ltn=function(c){return this.cmpn(c)===-1},i.prototype.lt=function(c){return this.cmp(c)===-1},i.prototype.lten=function(c){return this.cmpn(c)<=0},i.prototype.lte=function(c){return this.cmp(c)<=0},i.prototype.eqn=function(c){return this.cmpn(c)===0},i.prototype.eq=function(c){return this.cmp(c)===0},i.red=function(c){return new E(c)},i.prototype.toRed=function(c){return r(!this.red,"Already a number in reduction context"),r(this.negative===0,"red works only with positives"),c.convertTo(this)._forceRed(c)},i.prototype.fromRed=function(){return r(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},i.prototype._forceRed=function(c){return this.red=c,this},i.prototype.forceRed=function(c){return r(!this.red,"Already a number in reduction context"),this._forceRed(c)},i.prototype.redAdd=function(c){return r(this.red,"redAdd works only with red numbers"),this.red.add(this,c)},i.prototype.redIAdd=function(c){return r(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,c)},i.prototype.redSub=function(c){return r(this.red,"redSub works only with red numbers"),this.red.sub(this,c)},i.prototype.redISub=function(c){return r(this.red,"redISub works only with red numbers"),this.red.isub(this,c)},i.prototype.redShl=function(c){return r(this.red,"redShl works only with red numbers"),this.red.shl(this,c)},i.prototype.redMul=function(c){return r(this.red,"redMul works only with red numbers"),this.red._verify2(this,c),this.red.mul(this,c)},i.prototype.redIMul=function(c){return r(this.red,"redMul works only with red numbers"),this.red._verify2(this,c),this.red.imul(this,c)},i.prototype.redSqr=function(){return r(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},i.prototype.redISqr=function(){return r(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},i.prototype.redSqrt=function(){return r(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},i.prototype.redInvm=function(){return r(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},i.prototype.redNeg=function(){return r(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},i.prototype.redPow=function(c){return r(this.red&&!c.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,c)};var Z={k256:null,p224:null,p192:null,p25519:null};function j(b,c){this.name=b,this.p=new i(c,16),this.n=this.p.bitLength(),this.k=new i(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}j.prototype._tmp=function(){var c=new i(null);return c.words=new Array(Math.ceil(this.n/13)),c},j.prototype.ireduce=function(c){var g=c,w;do this.split(g,this.tmp),g=this.imulK(g),g=g.iadd(this.tmp),w=g.bitLength();while(w>this.n);var R=w0?g.isub(this.p):g.strip!==void 0?g.strip():g._strip(),g},j.prototype.split=function(c,g){c.iushrn(this.n,0,g)},j.prototype.imulK=function(c){return c.imul(this.k)};function se(){j.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}n(se,j),se.prototype.split=function(c,g){for(var w=4194303,R=Math.min(c.length,9),C=0;C>>22,h=D}h>>>=22,c.words[C-10]=h,h===0&&c.length>10?c.length-=10:c.length-=9},se.prototype.imulK=function(c){c.words[c.length]=0,c.words[c.length+1]=0,c.length+=2;for(var g=0,w=0;w>>=26,c.words[w]=C,g=R}return g!==0&&(c.words[c.length++]=g),c},i._prime=function(c){if(Z[c])return Z[c];var g;if(c==="k256")g=new se;else if(c==="p224")g=new ie;else if(c==="p192")g=new ce;else if(c==="p25519")g=new H;else throw new Error("Unknown prime "+c);return Z[c]=g,g};function E(b){if(typeof b=="string"){var c=i._prime(b);this.m=c.p,this.prime=c}else r(b.gtn(1),"modulus must be greater than 1"),this.m=b,this.prime=null}E.prototype._verify1=function(c){r(c.negative===0,"red works only with positives"),r(c.red,"red works only with red numbers")},E.prototype._verify2=function(c,g){r((c.negative|g.negative)===0,"red works only with positives"),r(c.red&&c.red===g.red,"red works only with red numbers")},E.prototype.imod=function(c){return this.prime?this.prime.ireduce(c)._forceRed(this):(f(c,c.umod(this.m)._forceRed(this)),c)},E.prototype.neg=function(c){return c.isZero()?c.clone():this.m.sub(c)._forceRed(this)},E.prototype.add=function(c,g){this._verify2(c,g);var w=c.add(g);return w.cmp(this.m)>=0&&w.isub(this.m),w._forceRed(this)},E.prototype.iadd=function(c,g){this._verify2(c,g);var w=c.iadd(g);return w.cmp(this.m)>=0&&w.isub(this.m),w},E.prototype.sub=function(c,g){this._verify2(c,g);var w=c.sub(g);return w.cmpn(0)<0&&w.iadd(this.m),w._forceRed(this)},E.prototype.isub=function(c,g){this._verify2(c,g);var w=c.isub(g);return w.cmpn(0)<0&&w.iadd(this.m),w},E.prototype.shl=function(c,g){return this._verify1(c),this.imod(c.ushln(g))},E.prototype.imul=function(c,g){return this._verify2(c,g),this.imod(c.imul(g))},E.prototype.mul=function(c,g){return this._verify2(c,g),this.imod(c.mul(g))},E.prototype.isqr=function(c){return this.imul(c,c.clone())},E.prototype.sqr=function(c){return this.mul(c,c)},E.prototype.sqrt=function(c){if(c.isZero())return c.clone();var g=this.m.andln(3);if(r(g%2===1),g===3){var w=this.m.add(new i(1)).iushrn(2);return this.pow(c,w)}for(var R=this.m.subn(1),C=0;!R.isZero()&&R.andln(1)===0;)C++,R.iushrn(1);r(!R.isZero());var h=new i(1).toRed(this),D=h.redNeg(),M=this.m.subn(1).iushrn(1),B=this.m.bitLength();for(B=new i(2*B*B).toRed(this);this.pow(B,M).cmp(D)!==0;)B.redIAdd(D);for(var k=this.pow(B,R),ne=this.pow(c,R.addn(1).iushrn(1)),Ae=this.pow(c,R),ue=C;Ae.cmp(h)!==0;){for(var pe=Ae,he=0;pe.cmp(h)!==0;he++)pe=pe.redSqr();r(he=0;C--){for(var k=g.words[C],ne=B-1;ne>=0;ne--){var Ae=k>>ne&1;if(h!==R[0]&&(h=this.sqr(h)),Ae===0&&D===0){M=0;continue}D<<=1,D|=Ae,M++,!(M!==w&&(C!==0||ne!==0))&&(h=this.mul(h,R[D]),M=0,D=0)}B=26}return h},E.prototype.convertTo=function(c){var g=c.umod(this.m);return g===c?g.clone():g},E.prototype.convertFrom=function(c){var g=c.clone();return g.red=null,g},i.mont=function(c){return new v(c)};function v(b){E.call(this,b),this.shift=this.m.bitLength(),this.shift%26!==0&&(this.shift+=26-this.shift%26),this.r=new i(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}n(v,E),v.prototype.convertTo=function(c){return this.imod(c.ushln(this.shift))},v.prototype.convertFrom=function(c){var g=this.imod(c.mul(this.rinv));return g.red=null,g},v.prototype.imul=function(c,g){if(c.isZero()||g.isZero())return c.words[0]=0,c.length=1,c;var w=c.imul(g),R=w.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),C=w.isub(R).iushrn(this.shift),h=C;return C.cmp(this.m)>=0?h=C.isub(this.m):C.cmpn(0)<0&&(h=C.iadd(this.m)),h._forceRed(this)},v.prototype.mul=function(c,g){if(c.isZero()||g.isZero())return new i(0)._forceRed(this);var w=c.mul(g),R=w.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),C=w.isub(R).iushrn(this.shift),h=C;return C.cmp(this.m)>=0?h=C.isub(this.m):C.cmpn(0)<0&&(h=C.iadd(this.m)),h._forceRed(this)},v.prototype.invm=function(c){var g=this.imod(c._invmp(this.m).mul(this.r2));return g._forceRed(this)}})(typeof vS>"u"||vS,Z5)});var By=U((eMe,t9)=>{"use strict";var Oc=my(),zde=mf(),Kde=at().Buffer;function $5(e){var t=e.modulus.byteLength(),r;do r=new Oc(zde(t));while(r.cmp(e.modulus)>=0||!r.umod(e.prime1)||!r.umod(e.prime2));return r}function Xde(e){var t=$5(e),r=t.toRed(Oc.mont(e.modulus)).redPow(new Oc(e.publicExponent)).fromRed();return{blinder:r,unblinder:t.invm(e.modulus)}}function e9(e,t){var r=Xde(t),n=t.modulus.byteLength(),i=new Oc(e).mul(r.blinder).umod(t.modulus),s=i.toRed(Oc.mont(t.prime1)),o=i.toRed(Oc.mont(t.prime2)),a=t.coefficient,A=t.prime1,f=t.prime2,l=s.redPow(t.exponent1).fromRed(),p=o.redPow(t.exponent2).fromRed(),I=l.isub(p).imul(a).umod(A).imul(f);return p.iadd(I).imul(r.unblinder).umod(t.modulus).toArrayLike(Kde,"be",n)}e9.getr=$5;t9.exports=e9});var r9=U((tMe,Zde)=>{Zde.exports={name:"elliptic",version:"6.6.1",description:"EC cryptography",main:"lib/elliptic.js",files:["lib"],scripts:{lint:"eslint lib test","lint:fix":"npm run lint -- --fix",unit:"istanbul test _mocha --reporter=spec test/index.js",test:"npm run lint && npm run unit",version:"grunt dist && git add dist/"},repository:{type:"git",url:"git@github.com:indutny/elliptic"},keywords:["EC","Elliptic","curve","Cryptography"],author:"Fedor Indutny ",license:"MIT",bugs:{url:"https://github.com/indutny/elliptic/issues"},homepage:"https://github.com/indutny/elliptic",devDependencies:{brfs:"^2.0.2",coveralls:"^3.1.0",eslint:"^7.6.0",grunt:"^1.2.1","grunt-browserify":"^5.3.0","grunt-cli":"^1.3.2","grunt-contrib-connect":"^3.0.0","grunt-contrib-copy":"^1.0.0","grunt-contrib-uglify":"^5.0.0","grunt-mocha-istanbul":"^5.0.2","grunt-saucelabs":"^9.0.1",istanbul:"^0.4.5",mocha:"^8.0.1"},dependencies:{"bn.js":"^4.11.9",brorand:"^1.1.0","hash.js":"^1.0.0","hmac-drbg":"^1.0.1",inherits:"^2.0.4","minimalistic-assert":"^1.0.1","minimalistic-crypto-utils":"^1.0.1"}}});var RS=U(s9=>{"use strict";var Iy=s9;function $de(e,t){if(Array.isArray(e))return e.slice();if(!e)return[];var r=[];if(typeof e!="string"){for(var n=0;n>8,o=i&255;s?r.push(s,o):r.push(o)}return r}Iy.toArray=$de;function n9(e){return e.length===1?"0"+e:e}Iy.zero2=n9;function i9(e){for(var t="",r=0;r{"use strict";var fs=o9,ege=kr(),tge=zn(),by=RS();fs.assert=tge;fs.toArray=by.toArray;fs.zero2=by.zero2;fs.toHex=by.toHex;fs.encode=by.encode;function rge(e,t,r){var n=new Array(Math.max(e.bitLength(),r)+1),i;for(i=0;i(s>>1)-1?a=(s>>1)-A:a=A,o.isubn(a)):a=0,n[i]=a,o.iushrn(1)}return n}fs.getNAF=rge;function nge(e,t){var r=[[],[]];e=e.clone(),t=t.clone();for(var n=0,i=0,s;e.cmpn(-n)>0||t.cmpn(-i)>0;){var o=e.andln(3)+n&3,a=t.andln(3)+i&3;o===3&&(o=-1),a===3&&(a=-1);var A;(o&1)===0?A=0:(s=e.andln(7)+n&7,(s===3||s===5)&&a===2?A=-o:A=o),r[0].push(A);var f;(a&1)===0?f=0:(s=t.andln(7)+i&7,(s===3||s===5)&&o===2?f=-a:f=a),r[1].push(f),2*n===A+1&&(n=1-n),2*i===f+1&&(i=1-i),e.iushrn(1),t.iushrn(1)}return r}fs.getJSF=nge;function ige(e,t,r){var n="_"+t;e.prototype[t]=function(){return this[n]!==void 0?this[n]:this[n]=r.call(this)}}fs.cachedProperty=ige;function sge(e){return typeof e=="string"?fs.toArray(e,"hex"):e}fs.parseBytes=sge;function oge(e){return new ege(e,"hex","le")}fs.intFromLE=oge});var Fd=U((iMe,a9)=>{"use strict";var Mf=kr(),Md=Kn(),Cy=Md.getNAF,age=Md.getJSF,Qy=Md.assert;function fA(e,t){this.type=e,this.p=new Mf(t.p,16),this.red=t.prime?Mf.red(t.prime):Mf.mont(this.p),this.zero=new Mf(0).toRed(this.red),this.one=new Mf(1).toRed(this.red),this.two=new Mf(2).toRed(this.red),this.n=t.n&&new Mf(t.n,16),this.g=t.g&&this.pointFromJSON(t.g,t.gRed),this._wnafT1=new Array(4),this._wnafT2=new Array(4),this._wnafT3=new Array(4),this._wnafT4=new Array(4),this._bitLength=this.n?this.n.bitLength():0;var r=this.n&&this.p.div(this.n);!r||r.cmpn(100)>0?this.redN=null:(this._maxwellTrick=!0,this.redN=this.n.toRed(this.red))}a9.exports=fA;fA.prototype.point=function(){throw new Error("Not implemented")};fA.prototype.validate=function(){throw new Error("Not implemented")};fA.prototype._fixedNafMul=function(t,r){Qy(t.precomputed);var n=t._getDoubles(),i=Cy(r,1,this._bitLength),s=(1<=a;f--)A=(A<<1)+i[f];o.push(A)}for(var l=this.jpoint(null,null,null),p=this.jpoint(null,null,null),I=s;I>0;I--){for(a=0;a=0;A--){for(var f=0;A>=0&&o[A]===0;A--)f++;if(A>=0&&f++,a=a.dblp(f),A<0)break;var l=o[A];Qy(l!==0),t.type==="affine"?l>0?a=a.mixedAdd(s[l-1>>1]):a=a.mixedAdd(s[-l-1>>1].neg()):l>0?a=a.add(s[l-1>>1]):a=a.add(s[-l-1>>1].neg())}return t.type==="affine"?a.toP():a};fA.prototype._wnafMulAdd=function(t,r,n,i,s){var o=this._wnafT1,a=this._wnafT2,A=this._wnafT3,f=0,l,p,I;for(l=0;l=1;l-=2){var _=l-1,N=l;if(o[_]!==1||o[N]!==1){A[_]=Cy(n[_],o[_],this._bitLength),A[N]=Cy(n[N],o[N],this._bitLength),f=Math.max(A[_].length,f),f=Math.max(A[N].length,f);continue}var O=[r[_],null,null,r[N]];r[_].y.cmp(r[N].y)===0?(O[1]=r[_].add(r[N]),O[2]=r[_].toJ().mixedAdd(r[N].neg())):r[_].y.cmp(r[N].y.redNeg())===0?(O[1]=r[_].toJ().mixedAdd(r[N]),O[2]=r[_].add(r[N].neg())):(O[1]=r[_].toJ().mixedAdd(r[N]),O[2]=r[_].toJ().mixedAdd(r[N].neg()));var x=[-3,-1,-5,-7,0,7,5,1,3],G=age(n[_],n[N]);for(f=Math.max(G[0].length,f),A[_]=new Array(f),A[N]=new Array(f),p=0;p=0;l--){for(var se=0;l>=0;){var ie=!0;for(p=0;p=0&&se++,Z=Z.dblp(se),l<0)break;for(p=0;p0?I=a[p][ce-1>>1]:ce<0&&(I=a[p][-ce-1>>1].neg()),I.type==="affine"?Z=Z.mixedAdd(I):Z=Z.add(I))}}for(l=0;l=Math.ceil((t.bitLength()+1)/r.step):!1};wi.prototype._getDoubles=function(t,r){if(this.precomputed&&this.precomputed.doubles)return this.precomputed.doubles;for(var n=[this],i=this,s=0;s{"use strict";var Age=Kn(),fr=kr(),DS=je(),Hc=Fd(),fge=Age.assert;function Si(e){Hc.call(this,"short",e),this.a=new fr(e.a,16).toRed(this.red),this.b=new fr(e.b,16).toRed(this.red),this.tinv=this.two.redInvm(),this.zeroA=this.a.fromRed().cmpn(0)===0,this.threeA=this.a.fromRed().sub(this.p).cmpn(-3)===0,this.endo=this._getEndomorphism(e),this._endoWnafT1=new Array(4),this._endoWnafT2=new Array(4)}DS(Si,Hc);A9.exports=Si;Si.prototype._getEndomorphism=function(t){if(!(!this.zeroA||!this.g||!this.n||this.p.modn(3)!==1)){var r,n;if(t.beta)r=new fr(t.beta,16).toRed(this.red);else{var i=this._getEndoRoots(this.p);r=i[0].cmp(i[1])<0?i[0]:i[1],r=r.toRed(this.red)}if(t.lambda)n=new fr(t.lambda,16);else{var s=this._getEndoRoots(this.n);this.g.mul(s[0]).x.cmp(this.g.x.redMul(r))===0?n=s[0]:(n=s[1],fge(this.g.mul(n).x.cmp(this.g.x.redMul(r))===0))}var o;return t.basis?o=t.basis.map(function(a){return{a:new fr(a.a,16),b:new fr(a.b,16)}}):o=this._getEndoBasis(n),{beta:r,lambda:n,basis:o}}};Si.prototype._getEndoRoots=function(t){var r=t===this.p?this.red:fr.mont(t),n=new fr(2).toRed(r).redInvm(),i=n.redNeg(),s=new fr(3).toRed(r).redNeg().redSqrt().redMul(n),o=i.redAdd(s).fromRed(),a=i.redSub(s).fromRed();return[o,a]};Si.prototype._getEndoBasis=function(t){for(var r=this.n.ushrn(Math.floor(this.n.bitLength()/2)),n=t,i=this.n.clone(),s=new fr(1),o=new fr(0),a=new fr(0),A=new fr(1),f,l,p,I,S,_,N,O=0,x,G;n.cmpn(0)!==0;){var Y=i.div(n);x=i.sub(Y.mul(n)),G=a.sub(Y.mul(s));var X=A.sub(Y.mul(o));if(!p&&x.cmp(r)<0)f=N.neg(),l=s,p=x.neg(),I=G;else if(p&&++O===2)break;N=x,i=n,n=x,a=s,s=G,A=o,o=X}S=x.neg(),_=G;var Z=p.sqr().add(I.sqr()),j=S.sqr().add(_.sqr());return j.cmp(Z)>=0&&(S=f,_=l),p.negative&&(p=p.neg(),I=I.neg()),S.negative&&(S=S.neg(),_=_.neg()),[{a:p,b:I},{a:S,b:_}]};Si.prototype._endoSplit=function(t){var r=this.endo.basis,n=r[0],i=r[1],s=i.b.mul(t).divRound(this.n),o=n.b.neg().mul(t).divRound(this.n),a=s.mul(n.a),A=o.mul(i.a),f=s.mul(n.b),l=o.mul(i.b),p=t.sub(a).sub(A),I=f.add(l).neg();return{k1:p,k2:I}};Si.prototype.pointFromX=function(t,r){t=new fr(t,16),t.red||(t=t.toRed(this.red));var n=t.redSqr().redMul(t).redIAdd(t.redMul(this.a)).redIAdd(this.b),i=n.redSqrt();if(i.redSqr().redSub(n).cmp(this.zero)!==0)throw new Error("invalid point");var s=i.fromRed().isOdd();return(r&&!s||!r&&s)&&(i=i.redNeg()),this.point(t,i)};Si.prototype.validate=function(t){if(t.inf)return!0;var r=t.x,n=t.y,i=this.a.redMul(r),s=r.redSqr().redMul(r).redIAdd(i).redIAdd(this.b);return n.redSqr().redISub(s).cmpn(0)===0};Si.prototype._endoWnafMulAdd=function(t,r,n){for(var i=this._endoWnafT1,s=this._endoWnafT2,o=0;o":""};Ur.prototype.isInfinity=function(){return this.inf};Ur.prototype.add=function(t){if(this.inf)return t;if(t.inf)return this;if(this.eq(t))return this.dbl();if(this.neg().eq(t))return this.curve.point(null,null);if(this.x.cmp(t.x)===0)return this.curve.point(null,null);var r=this.y.redSub(t.y);r.cmpn(0)!==0&&(r=r.redMul(this.x.redSub(t.x).redInvm()));var n=r.redSqr().redISub(this.x).redISub(t.x),i=r.redMul(this.x.redSub(n)).redISub(this.y);return this.curve.point(n,i)};Ur.prototype.dbl=function(){if(this.inf)return this;var t=this.y.redAdd(this.y);if(t.cmpn(0)===0)return this.curve.point(null,null);var r=this.curve.a,n=this.x.redSqr(),i=t.redInvm(),s=n.redAdd(n).redIAdd(n).redIAdd(r).redMul(i),o=s.redSqr().redISub(this.x.redAdd(this.x)),a=s.redMul(this.x.redSub(o)).redISub(this.y);return this.curve.point(o,a)};Ur.prototype.getX=function(){return this.x.fromRed()};Ur.prototype.getY=function(){return this.y.fromRed()};Ur.prototype.mul=function(t){return t=new fr(t,16),this.isInfinity()?this:this._hasDoubles(t)?this.curve._fixedNafMul(this,t):this.curve.endo?this.curve._endoWnafMulAdd([this],[t]):this.curve._wnafMul(this,t)};Ur.prototype.mulAdd=function(t,r,n){var i=[this,r],s=[t,n];return this.curve.endo?this.curve._endoWnafMulAdd(i,s):this.curve._wnafMulAdd(1,i,s,2)};Ur.prototype.jmulAdd=function(t,r,n){var i=[this,r],s=[t,n];return this.curve.endo?this.curve._endoWnafMulAdd(i,s,!0):this.curve._wnafMulAdd(1,i,s,2,!0)};Ur.prototype.eq=function(t){return this===t||this.inf===t.inf&&(this.inf||this.x.cmp(t.x)===0&&this.y.cmp(t.y)===0)};Ur.prototype.neg=function(t){if(this.inf)return this;var r=this.curve.point(this.x,this.y.redNeg());if(t&&this.precomputed){var n=this.precomputed,i=function(s){return s.neg()};r.precomputed={naf:n.naf&&{wnd:n.naf.wnd,points:n.naf.points.map(i)},doubles:n.doubles&&{step:n.doubles.step,points:n.doubles.points.map(i)}}}return r};Ur.prototype.toJ=function(){if(this.inf)return this.curve.jpoint(null,null,null);var t=this.curve.jpoint(this.x,this.y,this.curve.one);return t};function jr(e,t,r,n){Hc.BasePoint.call(this,e,"jacobian"),t===null&&r===null&&n===null?(this.x=this.curve.one,this.y=this.curve.one,this.z=new fr(0)):(this.x=new fr(t,16),this.y=new fr(r,16),this.z=new fr(n,16)),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)),this.zOne=this.z===this.curve.one}DS(jr,Hc.BasePoint);Si.prototype.jpoint=function(t,r,n){return new jr(this,t,r,n)};jr.prototype.toP=function(){if(this.isInfinity())return this.curve.point(null,null);var t=this.z.redInvm(),r=t.redSqr(),n=this.x.redMul(r),i=this.y.redMul(r).redMul(t);return this.curve.point(n,i)};jr.prototype.neg=function(){return this.curve.jpoint(this.x,this.y.redNeg(),this.z)};jr.prototype.add=function(t){if(this.isInfinity())return t;if(t.isInfinity())return this;var r=t.z.redSqr(),n=this.z.redSqr(),i=this.x.redMul(r),s=t.x.redMul(n),o=this.y.redMul(r.redMul(t.z)),a=t.y.redMul(n.redMul(this.z)),A=i.redSub(s),f=o.redSub(a);if(A.cmpn(0)===0)return f.cmpn(0)!==0?this.curve.jpoint(null,null,null):this.dbl();var l=A.redSqr(),p=l.redMul(A),I=i.redMul(l),S=f.redSqr().redIAdd(p).redISub(I).redISub(I),_=f.redMul(I.redISub(S)).redISub(o.redMul(p)),N=this.z.redMul(t.z).redMul(A);return this.curve.jpoint(S,_,N)};jr.prototype.mixedAdd=function(t){if(this.isInfinity())return t.toJ();if(t.isInfinity())return this;var r=this.z.redSqr(),n=this.x,i=t.x.redMul(r),s=this.y,o=t.y.redMul(r).redMul(this.z),a=n.redSub(i),A=s.redSub(o);if(a.cmpn(0)===0)return A.cmpn(0)!==0?this.curve.jpoint(null,null,null):this.dbl();var f=a.redSqr(),l=f.redMul(a),p=n.redMul(f),I=A.redSqr().redIAdd(l).redISub(p).redISub(p),S=A.redMul(p.redISub(I)).redISub(s.redMul(l)),_=this.z.redMul(a);return this.curve.jpoint(I,S,_)};jr.prototype.dblp=function(t){if(t===0)return this;if(this.isInfinity())return this;if(!t)return this.dbl();var r;if(this.curve.zeroA||this.curve.threeA){var n=this;for(r=0;r=0)return!1;if(n.redIAdd(s),this.x.cmp(n)===0)return!0}};jr.prototype.inspect=function(){return this.isInfinity()?"":""};jr.prototype.isInfinity=function(){return this.z.cmpn(0)===0}});var l9=U((oMe,c9)=>{"use strict";var qc=kr(),u9=je(),wy=Fd(),uge=Kn();function Gc(e){wy.call(this,"mont",e),this.a=new qc(e.a,16).toRed(this.red),this.b=new qc(e.b,16).toRed(this.red),this.i4=new qc(4).toRed(this.red).redInvm(),this.two=new qc(2).toRed(this.red),this.a24=this.i4.redMul(this.a.redAdd(this.two))}u9(Gc,wy);c9.exports=Gc;Gc.prototype.validate=function(t){var r=t.normalize().x,n=r.redSqr(),i=n.redMul(r).redAdd(n.redMul(this.a)).redAdd(r),s=i.redSqrt();return s.redSqr().cmp(i)===0};function xr(e,t,r){wy.BasePoint.call(this,e,"projective"),t===null&&r===null?(this.x=this.curve.one,this.z=this.curve.zero):(this.x=new qc(t,16),this.z=new qc(r,16),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)))}u9(xr,wy.BasePoint);Gc.prototype.decodePoint=function(t,r){return this.point(uge.toArray(t,r),1)};Gc.prototype.point=function(t,r){return new xr(this,t,r)};Gc.prototype.pointFromJSON=function(t){return xr.fromJSON(this,t)};xr.prototype.precompute=function(){};xr.prototype._encode=function(){return this.getX().toArray("be",this.curve.p.byteLength())};xr.fromJSON=function(t,r){return new xr(t,r[0],r[1]||t.one)};xr.prototype.inspect=function(){return this.isInfinity()?"":""};xr.prototype.isInfinity=function(){return this.z.cmpn(0)===0};xr.prototype.dbl=function(){var t=this.x.redAdd(this.z),r=t.redSqr(),n=this.x.redSub(this.z),i=n.redSqr(),s=r.redSub(i),o=r.redMul(i),a=s.redMul(i.redAdd(this.curve.a24.redMul(s)));return this.curve.point(o,a)};xr.prototype.add=function(){throw new Error("Not supported on Montgomery curve")};xr.prototype.diffAdd=function(t,r){var n=this.x.redAdd(this.z),i=this.x.redSub(this.z),s=t.x.redAdd(t.z),o=t.x.redSub(t.z),a=o.redMul(n),A=s.redMul(i),f=r.z.redMul(a.redAdd(A).redSqr()),l=r.x.redMul(a.redISub(A).redSqr());return this.curve.point(f,l)};xr.prototype.mul=function(t){for(var r=t.clone(),n=this,i=this.curve.point(null,null),s=this,o=[];r.cmpn(0)!==0;r.iushrn(1))o.push(r.andln(1));for(var a=o.length-1;a>=0;a--)o[a]===0?(n=n.diffAdd(i,s),i=i.dbl()):(i=n.diffAdd(i,s),n=n.dbl());return i};xr.prototype.mulAdd=function(){throw new Error("Not supported on Montgomery curve")};xr.prototype.jumlAdd=function(){throw new Error("Not supported on Montgomery curve")};xr.prototype.eq=function(t){return this.getX().cmp(t.getX())===0};xr.prototype.normalize=function(){return this.x=this.x.redMul(this.z.redInvm()),this.z=this.curve.one,this};xr.prototype.getX=function(){return this.normalize(),this.x.fromRed()}});var g9=U((aMe,d9)=>{"use strict";var cge=Kn(),oa=kr(),h9=je(),Sy=Fd(),lge=cge.assert;function no(e){this.twisted=(e.a|0)!==1,this.mOneA=this.twisted&&(e.a|0)===-1,this.extended=this.mOneA,Sy.call(this,"edwards",e),this.a=new oa(e.a,16).umod(this.red.m),this.a=this.a.toRed(this.red),this.c=new oa(e.c,16).toRed(this.red),this.c2=this.c.redSqr(),this.d=new oa(e.d,16).toRed(this.red),this.dd=this.d.redAdd(this.d),lge(!this.twisted||this.c.fromRed().cmpn(1)===0),this.oneC=(e.c|0)===1}h9(no,Sy);d9.exports=no;no.prototype._mulA=function(t){return this.mOneA?t.redNeg():this.a.redMul(t)};no.prototype._mulC=function(t){return this.oneC?t:this.c.redMul(t)};no.prototype.jpoint=function(t,r,n,i){return this.point(t,r,n,i)};no.prototype.pointFromX=function(t,r){t=new oa(t,16),t.red||(t=t.toRed(this.red));var n=t.redSqr(),i=this.c2.redSub(this.a.redMul(n)),s=this.one.redSub(this.c2.redMul(this.d).redMul(n)),o=i.redMul(s.redInvm()),a=o.redSqrt();if(a.redSqr().redSub(o).cmp(this.zero)!==0)throw new Error("invalid point");var A=a.fromRed().isOdd();return(r&&!A||!r&&A)&&(a=a.redNeg()),this.point(t,a)};no.prototype.pointFromY=function(t,r){t=new oa(t,16),t.red||(t=t.toRed(this.red));var n=t.redSqr(),i=n.redSub(this.c2),s=n.redMul(this.d).redMul(this.c2).redSub(this.a),o=i.redMul(s.redInvm());if(o.cmp(this.zero)===0){if(r)throw new Error("invalid point");return this.point(this.zero,t)}var a=o.redSqrt();if(a.redSqr().redSub(o).cmp(this.zero)!==0)throw new Error("invalid point");return a.fromRed().isOdd()!==r&&(a=a.redNeg()),this.point(a,t)};no.prototype.validate=function(t){if(t.isInfinity())return!0;t.normalize();var r=t.x.redSqr(),n=t.y.redSqr(),i=r.redMul(this.a).redAdd(n),s=this.c2.redMul(this.one.redAdd(this.d.redMul(r).redMul(n)));return i.cmp(s)===0};function Wt(e,t,r,n,i){Sy.BasePoint.call(this,e,"projective"),t===null&&r===null&&n===null?(this.x=this.curve.zero,this.y=this.curve.one,this.z=this.curve.one,this.t=this.curve.zero,this.zOne=!0):(this.x=new oa(t,16),this.y=new oa(r,16),this.z=n?new oa(n,16):this.curve.one,this.t=i&&new oa(i,16),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)),this.t&&!this.t.red&&(this.t=this.t.toRed(this.curve.red)),this.zOne=this.z===this.curve.one,this.curve.extended&&!this.t&&(this.t=this.x.redMul(this.y),this.zOne||(this.t=this.t.redMul(this.z.redInvm()))))}h9(Wt,Sy.BasePoint);no.prototype.pointFromJSON=function(t){return Wt.fromJSON(this,t)};no.prototype.point=function(t,r,n,i){return new Wt(this,t,r,n,i)};Wt.fromJSON=function(t,r){return new Wt(t,r[0],r[1],r[2])};Wt.prototype.inspect=function(){return this.isInfinity()?"":""};Wt.prototype.isInfinity=function(){return this.x.cmpn(0)===0&&(this.y.cmp(this.z)===0||this.zOne&&this.y.cmp(this.curve.c)===0)};Wt.prototype._extDbl=function(){var t=this.x.redSqr(),r=this.y.redSqr(),n=this.z.redSqr();n=n.redIAdd(n);var i=this.curve._mulA(t),s=this.x.redAdd(this.y).redSqr().redISub(t).redISub(r),o=i.redAdd(r),a=o.redSub(n),A=i.redSub(r),f=s.redMul(a),l=o.redMul(A),p=s.redMul(A),I=a.redMul(o);return this.curve.point(f,l,I,p)};Wt.prototype._projDbl=function(){var t=this.x.redAdd(this.y).redSqr(),r=this.x.redSqr(),n=this.y.redSqr(),i,s,o,a,A,f;if(this.curve.twisted){a=this.curve._mulA(r);var l=a.redAdd(n);this.zOne?(i=t.redSub(r).redSub(n).redMul(l.redSub(this.curve.two)),s=l.redMul(a.redSub(n)),o=l.redSqr().redSub(l).redSub(l)):(A=this.z.redSqr(),f=l.redSub(A).redISub(A),i=t.redSub(r).redISub(n).redMul(f),s=l.redMul(a.redSub(n)),o=l.redMul(f))}else a=r.redAdd(n),A=this.curve._mulC(this.z).redSqr(),f=a.redSub(A).redSub(A),i=this.curve._mulC(t.redISub(a)).redMul(f),s=this.curve._mulC(a).redMul(r.redISub(n)),o=a.redMul(f);return this.curve.point(i,s,o)};Wt.prototype.dbl=function(){return this.isInfinity()?this:this.curve.extended?this._extDbl():this._projDbl()};Wt.prototype._extAdd=function(t){var r=this.y.redSub(this.x).redMul(t.y.redSub(t.x)),n=this.y.redAdd(this.x).redMul(t.y.redAdd(t.x)),i=this.t.redMul(this.curve.dd).redMul(t.t),s=this.z.redMul(t.z.redAdd(t.z)),o=n.redSub(r),a=s.redSub(i),A=s.redAdd(i),f=n.redAdd(r),l=o.redMul(a),p=A.redMul(f),I=o.redMul(f),S=a.redMul(A);return this.curve.point(l,p,S,I)};Wt.prototype._projAdd=function(t){var r=this.z.redMul(t.z),n=r.redSqr(),i=this.x.redMul(t.x),s=this.y.redMul(t.y),o=this.curve.d.redMul(i).redMul(s),a=n.redSub(o),A=n.redAdd(o),f=this.x.redAdd(this.y).redMul(t.x.redAdd(t.y)).redISub(i).redISub(s),l=r.redMul(a).redMul(f),p,I;return this.curve.twisted?(p=r.redMul(A).redMul(s.redSub(this.curve._mulA(i))),I=a.redMul(A)):(p=r.redMul(A).redMul(s.redSub(i)),I=this.curve._mulC(a).redMul(A)),this.curve.point(l,p,I)};Wt.prototype.add=function(t){return this.isInfinity()?t:t.isInfinity()?this:this.curve.extended?this._extAdd(t):this._projAdd(t)};Wt.prototype.mul=function(t){return this._hasDoubles(t)?this.curve._fixedNafMul(this,t):this.curve._wnafMul(this,t)};Wt.prototype.mulAdd=function(t,r,n){return this.curve._wnafMulAdd(1,[this,r],[t,n],2,!1)};Wt.prototype.jmulAdd=function(t,r,n){return this.curve._wnafMulAdd(1,[this,r],[t,n],2,!0)};Wt.prototype.normalize=function(){if(this.zOne)return this;var t=this.z.redInvm();return this.x=this.x.redMul(t),this.y=this.y.redMul(t),this.t&&(this.t=this.t.redMul(t)),this.z=this.curve.one,this.zOne=!0,this};Wt.prototype.neg=function(){return this.curve.point(this.x.redNeg(),this.y,this.z,this.t&&this.t.redNeg())};Wt.prototype.getX=function(){return this.normalize(),this.x.fromRed()};Wt.prototype.getY=function(){return this.normalize(),this.y.fromRed()};Wt.prototype.eq=function(t){return this===t||this.getX().cmp(t.getX())===0&&this.getY().cmp(t.getY())===0};Wt.prototype.eqXToP=function(t){var r=t.toRed(this.curve.red).redMul(this.z);if(this.x.cmp(r)===0)return!0;for(var n=t.clone(),i=this.curve.redN.redMul(this.z);;){if(n.iadd(this.curve.n),n.cmp(this.curve.p)>=0)return!1;if(r.redIAdd(i),this.x.cmp(r)===0)return!0}};Wt.prototype.toP=Wt.prototype.normalize;Wt.prototype.mixedAdd=Wt.prototype.add});var TS=U(p9=>{"use strict";var _y=p9;_y.base=Fd();_y.short=f9();_y.mont=l9();_y.edwards=g9()});var us=U(Pt=>{"use strict";var hge=zn(),dge=je();Pt.inherits=dge;function gge(e,t){return(e.charCodeAt(t)&64512)!==55296||t<0||t+1>=e.length?!1:(e.charCodeAt(t+1)&64512)===56320}function pge(e,t){if(Array.isArray(e))return e.slice();if(!e)return[];var r=[];if(typeof e=="string")if(t){if(t==="hex")for(e=e.replace(/[^a-z0-9]+/ig,""),e.length%2!==0&&(e="0"+e),i=0;i>6|192,r[n++]=s&63|128):gge(e,i)?(s=65536+((s&1023)<<10)+(e.charCodeAt(++i)&1023),r[n++]=s>>18|240,r[n++]=s>>12&63|128,r[n++]=s>>6&63|128,r[n++]=s&63|128):(r[n++]=s>>12|224,r[n++]=s>>6&63|128,r[n++]=s&63|128)}else for(i=0;i>>24|e>>>8&65280|e<<8&16711680|(e&255)<<24;return t>>>0}Pt.htonl=E9;function yge(e,t){for(var r="",n=0;n>>0}return s}Pt.join32=mge;function Bge(e,t){for(var r=new Array(e.length*4),n=0,i=0;n>>24,r[i+1]=s>>>16&255,r[i+2]=s>>>8&255,r[i+3]=s&255):(r[i+3]=s>>>24,r[i+2]=s>>>16&255,r[i+1]=s>>>8&255,r[i]=s&255)}return r}Pt.split32=Bge;function Ige(e,t){return e>>>t|e<<32-t}Pt.rotr32=Ige;function bge(e,t){return e<>>32-t}Pt.rotl32=bge;function Cge(e,t){return e+t>>>0}Pt.sum32=Cge;function Qge(e,t,r){return e+t+r>>>0}Pt.sum32_3=Qge;function wge(e,t,r,n){return e+t+r+n>>>0}Pt.sum32_4=wge;function Sge(e,t,r,n,i){return e+t+r+n+i>>>0}Pt.sum32_5=Sge;function _ge(e,t,r,n){var i=e[t],s=e[t+1],o=n+s>>>0,a=(o>>0,e[t+1]=o}Pt.sum64=_ge;function vge(e,t,r,n){var i=t+n>>>0,s=(i>>0}Pt.sum64_hi=vge;function Rge(e,t,r,n){var i=t+n;return i>>>0}Pt.sum64_lo=Rge;function Dge(e,t,r,n,i,s,o,a){var A=0,f=t;f=f+n>>>0,A+=f>>0,A+=f>>0,A+=f>>0}Pt.sum64_4_hi=Dge;function Tge(e,t,r,n,i,s,o,a){var A=t+n+s+a;return A>>>0}Pt.sum64_4_lo=Tge;function Nge(e,t,r,n,i,s,o,a,A,f){var l=0,p=t;p=p+n>>>0,l+=p>>0,l+=p>>0,l+=p>>0,l+=p>>0}Pt.sum64_5_hi=Nge;function Mge(e,t,r,n,i,s,o,a,A,f){var l=t+n+s+a+f;return l>>>0}Pt.sum64_5_lo=Mge;function Fge(e,t,r){var n=t<<32-r|e>>>r;return n>>>0}Pt.rotr64_hi=Fge;function kge(e,t,r){var n=e<<32-r|t>>>r;return n>>>0}Pt.rotr64_lo=kge;function Uge(e,t,r){return e>>>r}Pt.shr64_hi=Uge;function xge(e,t,r){var n=e<<32-r|t>>>r;return n>>>0}Pt.shr64_lo=xge});var Yc=U(I9=>{"use strict";var B9=us(),Lge=zn();function vy(){this.pending=null,this.pendingTotal=0,this.blockSize=this.constructor.blockSize,this.outSize=this.constructor.outSize,this.hmacStrength=this.constructor.hmacStrength,this.padLength=this.constructor.padLength/8,this.endian="big",this._delta8=this.blockSize/8,this._delta32=this.blockSize/32}I9.BlockHash=vy;vy.prototype.update=function(t,r){if(t=B9.toArray(t,r),this.pending?this.pending=this.pending.concat(t):this.pending=t,this.pendingTotal+=t.length,this.pending.length>=this._delta8){t=this.pending;var n=t.length%this._delta8;this.pending=t.slice(t.length-n,t.length),this.pending.length===0&&(this.pending=null),t=B9.join32(t,0,t.length-n,this.endian);for(var i=0;i>>24&255,i[s++]=t>>>16&255,i[s++]=t>>>8&255,i[s++]=t&255}else for(i[s++]=t&255,i[s++]=t>>>8&255,i[s++]=t>>>16&255,i[s++]=t>>>24&255,i[s++]=0,i[s++]=0,i[s++]=0,i[s++]=0,o=8;o{"use strict";var Pge=us(),io=Pge.rotr32;function Oge(e,t,r,n){if(e===0)return b9(t,r,n);if(e===1||e===3)return Q9(t,r,n);if(e===2)return C9(t,r,n)}aa.ft_1=Oge;function b9(e,t,r){return e&t^~e&r}aa.ch32=b9;function C9(e,t,r){return e&t^e&r^t&r}aa.maj32=C9;function Q9(e,t,r){return e^t^r}aa.p32=Q9;function Hge(e){return io(e,2)^io(e,13)^io(e,22)}aa.s0_256=Hge;function qge(e){return io(e,6)^io(e,11)^io(e,25)}aa.s1_256=qge;function Gge(e){return io(e,7)^io(e,18)^e>>>3}aa.g0_256=Gge;function Yge(e){return io(e,17)^io(e,19)^e>>>10}aa.g1_256=Yge});var _9=U((lMe,S9)=>{"use strict";var Wc=us(),Wge=Yc(),Vge=NS(),MS=Wc.rotl32,kd=Wc.sum32,Jge=Wc.sum32_5,jge=Vge.ft_1,w9=Wge.BlockHash,zge=[1518500249,1859775393,2400959708,3395469782];function so(){if(!(this instanceof so))return new so;w9.call(this),this.h=[1732584193,4023233417,2562383102,271733878,3285377520],this.W=new Array(80)}Wc.inherits(so,w9);S9.exports=so;so.blockSize=512;so.outSize=160;so.hmacStrength=80;so.padLength=64;so.prototype._update=function(t,r){for(var n=this.W,i=0;i<16;i++)n[i]=t[r+i];for(;i{"use strict";var Vc=us(),Kge=Yc(),Jc=NS(),Xge=zn(),cs=Vc.sum32,Zge=Vc.sum32_4,$ge=Vc.sum32_5,e0e=Jc.ch32,t0e=Jc.maj32,r0e=Jc.s0_256,n0e=Jc.s1_256,i0e=Jc.g0_256,s0e=Jc.g1_256,v9=Kge.BlockHash,o0e=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function oo(){if(!(this instanceof oo))return new oo;v9.call(this),this.h=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],this.k=o0e,this.W=new Array(64)}Vc.inherits(oo,v9);R9.exports=oo;oo.blockSize=512;oo.outSize=256;oo.hmacStrength=192;oo.padLength=64;oo.prototype._update=function(t,r){for(var n=this.W,i=0;i<16;i++)n[i]=t[r+i];for(;i{"use strict";var kS=us(),D9=FS();function Aa(){if(!(this instanceof Aa))return new Aa;D9.call(this),this.h=[3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428]}kS.inherits(Aa,D9);T9.exports=Aa;Aa.blockSize=512;Aa.outSize=224;Aa.hmacStrength=192;Aa.padLength=64;Aa.prototype._digest=function(t){return t==="hex"?kS.toHex32(this.h.slice(0,7),"big"):kS.split32(this.h.slice(0,7),"big")}});var LS=U((gMe,U9)=>{"use strict";var Mn=us(),a0e=Yc(),A0e=zn(),ao=Mn.rotr64_hi,Ao=Mn.rotr64_lo,M9=Mn.shr64_hi,F9=Mn.shr64_lo,uA=Mn.sum64,US=Mn.sum64_hi,xS=Mn.sum64_lo,f0e=Mn.sum64_4_hi,u0e=Mn.sum64_4_lo,c0e=Mn.sum64_5_hi,l0e=Mn.sum64_5_lo,k9=a0e.BlockHash,h0e=[1116352408,3609767458,1899447441,602891725,3049323471,3964484399,3921009573,2173295548,961987163,4081628472,1508970993,3053834265,2453635748,2937671579,2870763221,3664609560,3624381080,2734883394,310598401,1164996542,607225278,1323610764,1426881987,3590304994,1925078388,4068182383,2162078206,991336113,2614888103,633803317,3248222580,3479774868,3835390401,2666613458,4022224774,944711139,264347078,2341262773,604807628,2007800933,770255983,1495990901,1249150122,1856431235,1555081692,3175218132,1996064986,2198950837,2554220882,3999719339,2821834349,766784016,2952996808,2566594879,3210313671,3203337956,3336571891,1034457026,3584528711,2466948901,113926993,3758326383,338241895,168717936,666307205,1188179964,773529912,1546045734,1294757372,1522805485,1396182291,2643833823,1695183700,2343527390,1986661051,1014477480,2177026350,1206759142,2456956037,344077627,2730485921,1290863460,2820302411,3158454273,3259730800,3505952657,3345764771,106217008,3516065817,3606008344,3600352804,1432725776,4094571909,1467031594,275423344,851169720,430227734,3100823752,506948616,1363258195,659060556,3750685593,883997877,3785050280,958139571,3318307427,1322822218,3812723403,1537002063,2003034995,1747873779,3602036899,1955562222,1575990012,2024104815,1125592928,2227730452,2716904306,2361852424,442776044,2428436474,593698344,2756734187,3733110249,3204031479,2999351573,3329325298,3815920427,3391569614,3928383900,3515267271,566280711,3940187606,3454069534,4118630271,4000239992,116418474,1914138554,174292421,2731055270,289380356,3203993006,460393269,320620315,685471733,587496836,852142971,1086792851,1017036298,365543100,1126000580,2618297676,1288033470,3409855158,1501505948,4234509866,1607167915,987167468,1816402316,1246189591];function ls(){if(!(this instanceof ls))return new ls;k9.call(this),this.h=[1779033703,4089235720,3144134277,2227873595,1013904242,4271175723,2773480762,1595750129,1359893119,2917565137,2600822924,725511199,528734635,4215389547,1541459225,327033209],this.k=h0e,this.W=new Array(160)}Mn.inherits(ls,k9);U9.exports=ls;ls.blockSize=1024;ls.outSize=512;ls.hmacStrength=192;ls.padLength=128;ls.prototype._prepareBlock=function(t,r){for(var n=this.W,i=0;i<32;i++)n[i]=t[r+i];for(;i{"use strict";var PS=us(),x9=LS();function fa(){if(!(this instanceof fa))return new fa;x9.call(this),this.h=[3418070365,3238371032,1654270250,914150663,2438529370,812702999,355462360,4144912697,1731405415,4290775857,2394180231,1750603025,3675008525,1694076839,1203062813,3204075428]}PS.inherits(fa,x9);L9.exports=fa;fa.blockSize=1024;fa.outSize=384;fa.hmacStrength=192;fa.padLength=128;fa.prototype._digest=function(t){return t==="hex"?PS.toHex32(this.h.slice(0,12),"big"):PS.split32(this.h.slice(0,12),"big")}});var O9=U(jc=>{"use strict";jc.sha1=_9();jc.sha224=N9();jc.sha256=FS();jc.sha384=P9();jc.sha512=LS()});var V9=U(W9=>{"use strict";var Ff=us(),S0e=Yc(),Ry=Ff.rotl32,H9=Ff.sum32,Ud=Ff.sum32_3,q9=Ff.sum32_4,Y9=S0e.BlockHash;function fo(){if(!(this instanceof fo))return new fo;Y9.call(this),this.h=[1732584193,4023233417,2562383102,271733878,3285377520],this.endian="little"}Ff.inherits(fo,Y9);W9.ripemd160=fo;fo.blockSize=512;fo.outSize=160;fo.hmacStrength=192;fo.padLength=64;fo.prototype._update=function(t,r){for(var n=this.h[0],i=this.h[1],s=this.h[2],o=this.h[3],a=this.h[4],A=n,f=i,l=s,p=o,I=a,S=0;S<80;S++){var _=H9(Ry(q9(n,G9(S,i,s,o),t[R0e[S]+r],_0e(S)),T0e[S]),a);n=a,a=o,o=Ry(s,10),s=i,i=_,_=H9(Ry(q9(A,G9(79-S,f,l,p),t[D0e[S]+r],v0e(S)),N0e[S]),I),A=I,I=p,p=Ry(l,10),l=f,f=_}_=Ud(this.h[1],s,p),this.h[1]=Ud(this.h[2],o,I),this.h[2]=Ud(this.h[3],a,A),this.h[3]=Ud(this.h[4],n,f),this.h[4]=Ud(this.h[0],i,l),this.h[0]=_};fo.prototype._digest=function(t){return t==="hex"?Ff.toHex32(this.h,"little"):Ff.split32(this.h,"little")};function G9(e,t,r,n){return e<=15?t^r^n:e<=31?t&r|~t&n:e<=47?(t|~r)^n:e<=63?t&n|r&~n:t^(r|~n)}function _0e(e){return e<=15?0:e<=31?1518500249:e<=47?1859775393:e<=63?2400959708:2840853838}function v0e(e){return e<=15?1352829926:e<=31?1548603684:e<=47?1836072691:e<=63?2053994217:0}var R0e=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13],D0e=[5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11],T0e=[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6],N0e=[8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]});var j9=U((mMe,J9)=>{"use strict";var M0e=us(),F0e=zn();function zc(e,t,r){if(!(this instanceof zc))return new zc(e,t,r);this.Hash=e,this.blockSize=e.blockSize/8,this.outSize=e.outSize/8,this.inner=null,this.outer=null,this._init(M0e.toArray(t,r))}J9.exports=zc;zc.prototype._init=function(t){t.length>this.blockSize&&(t=new this.Hash().update(t).digest()),F0e(t.length<=this.blockSize);for(var r=t.length;r{var zr=z9;zr.utils=us();zr.common=Yc();zr.sha=O9();zr.ripemd=V9();zr.hmac=j9();zr.sha1=zr.sha.sha1;zr.sha256=zr.sha.sha256;zr.sha224=zr.sha.sha224;zr.sha384=zr.sha.sha384;zr.sha512=zr.sha.sha512;zr.ripemd160=zr.ripemd.ripemd160});var X9=U((IMe,K9)=>{K9.exports={doubles:{step:4,points:[["e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a","f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821"],["8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508","11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf"],["175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739","d3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695"],["363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640","4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9"],["8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c","4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36"],["723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda","96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f"],["eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa","5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999"],["100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0","cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09"],["e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d","9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d"],["feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d","e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088"],["da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1","9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d"],["53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0","5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8"],["8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047","10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a"],["385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862","283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453"],["6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7","7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160"],["3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd","56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0"],["85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83","7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6"],["948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a","53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589"],["6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8","bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17"],["e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d","4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda"],["e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725","7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd"],["213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754","4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2"],["4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c","17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6"],["fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6","6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f"],["76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39","c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01"],["c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891","893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3"],["d895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b","febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f"],["b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03","2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7"],["e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d","eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78"],["a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070","7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1"],["90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4","e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150"],["8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da","662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82"],["e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11","1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc"],["8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e","efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b"],["e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41","2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51"],["b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef","67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45"],["d68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8","db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120"],["324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d","648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84"],["4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96","35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d"],["9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd","ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d"],["6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5","9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8"],["a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266","40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8"],["7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71","34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac"],["928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac","c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f"],["85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751","1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962"],["ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e","493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907"],["827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241","c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec"],["eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3","be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d"],["e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f","4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414"],["1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19","aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd"],["146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be","b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0"],["fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9","6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811"],["da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2","8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1"],["a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13","7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c"],["174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c","ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73"],["959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba","2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd"],["d2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151","e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405"],["64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073","d99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589"],["8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458","38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e"],["13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b","69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27"],["bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366","d3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1"],["8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa","40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482"],["8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0","620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945"],["dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787","7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573"],["f710d79d9eb962297e4f6232b40e8f7feb2bc63814614d692c12de752408221e","ea98e67232d3b3295d3b535532115ccac8612c721851617526ae47a9c77bfc82"]]},naf:{wnd:7,points:[["f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9","388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672"],["2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4","d8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6"],["5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc","6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da"],["acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe","cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37"],["774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb","d984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b"],["f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8","ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81"],["d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e","581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58"],["defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34","4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77"],["2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c","85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a"],["352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5","321eb4075348f534d59c18259dda3e1f4a1b3b2e71b1039c67bd3d8bcf81998c"],["2fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f","2de1068295dd865b64569335bd5dd80181d70ecfc882648423ba76b532b7d67"],["9248279b09b4d68dab21a9b066edda83263c3d84e09572e269ca0cd7f5453714","73016f7bf234aade5d1aa71bdea2b1ff3fc0de2a887912ffe54a32ce97cb3402"],["daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729","a69dce4a7d6c98e8d4a1aca87ef8d7003f83c230f3afa726ab40e52290be1c55"],["c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db","2119a460ce326cdc76c45926c982fdac0e106e861edf61c5a039063f0e0e6482"],["6a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4","e022cf42c2bd4a708b3f5126f16a24ad8b33ba48d0423b6efd5e6348100d8a82"],["1697ffa6fd9de627c077e3d2fe541084ce13300b0bec1146f95ae57f0d0bd6a5","b9c398f186806f5d27561506e4557433a2cf15009e498ae7adee9d63d01b2396"],["605bdb019981718b986d0f07e834cb0d9deb8360ffb7f61df982345ef27a7479","2972d2de4f8d20681a78d93ec96fe23c26bfae84fb14db43b01e1e9056b8c49"],["62d14dab4150bf497402fdc45a215e10dcb01c354959b10cfe31c7e9d87ff33d","80fc06bd8cc5b01098088a1950eed0db01aa132967ab472235f5642483b25eaf"],["80c60ad0040f27dade5b4b06c408e56b2c50e9f56b9b8b425e555c2f86308b6f","1c38303f1cc5c30f26e66bad7fe72f70a65eed4cbe7024eb1aa01f56430bd57a"],["7a9375ad6167ad54aa74c6348cc54d344cc5dc9487d847049d5eabb0fa03c8fb","d0e3fa9eca8726909559e0d79269046bdc59ea10c70ce2b02d499ec224dc7f7"],["d528ecd9b696b54c907a9ed045447a79bb408ec39b68df504bb51f459bc3ffc9","eecf41253136e5f99966f21881fd656ebc4345405c520dbc063465b521409933"],["49370a4b5f43412ea25f514e8ecdad05266115e4a7ecb1387231808f8b45963","758f3f41afd6ed428b3081b0512fd62a54c3f3afbb5b6764b653052a12949c9a"],["77f230936ee88cbbd73df930d64702ef881d811e0e1498e2f1c13eb1fc345d74","958ef42a7886b6400a08266e9ba1b37896c95330d97077cbbe8eb3c7671c60d6"],["f2dac991cc4ce4b9ea44887e5c7c0bce58c80074ab9d4dbaeb28531b7739f530","e0dedc9b3b2f8dad4da1f32dec2531df9eb5fbeb0598e4fd1a117dba703a3c37"],["463b3d9f662621fb1b4be8fbbe2520125a216cdfc9dae3debcba4850c690d45b","5ed430d78c296c3543114306dd8622d7c622e27c970a1de31cb377b01af7307e"],["f16f804244e46e2a09232d4aff3b59976b98fac14328a2d1a32496b49998f247","cedabd9b82203f7e13d206fcdf4e33d92a6c53c26e5cce26d6579962c4e31df6"],["caf754272dc84563b0352b7a14311af55d245315ace27c65369e15f7151d41d1","cb474660ef35f5f2a41b643fa5e460575f4fa9b7962232a5c32f908318a04476"],["2600ca4b282cb986f85d0f1709979d8b44a09c07cb86d7c124497bc86f082120","4119b88753c15bd6a693b03fcddbb45d5ac6be74ab5f0ef44b0be9475a7e4b40"],["7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435","91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61"],["754e3239f325570cdbbf4a87deee8a66b7f2b33479d468fbc1a50743bf56cc18","673fb86e5bda30fb3cd0ed304ea49a023ee33d0197a695d0c5d98093c536683"],["e3e6bd1071a1e96aff57859c82d570f0330800661d1c952f9fe2694691d9b9e8","59c9e0bba394e76f40c0aa58379a3cb6a5a2283993e90c4167002af4920e37f5"],["186b483d056a033826ae73d88f732985c4ccb1f32ba35f4b4cc47fdcf04aa6eb","3b952d32c67cf77e2e17446e204180ab21fb8090895138b4a4a797f86e80888b"],["df9d70a6b9876ce544c98561f4be4f725442e6d2b737d9c91a8321724ce0963f","55eb2dafd84d6ccd5f862b785dc39d4ab157222720ef9da217b8c45cf2ba2417"],["5edd5cc23c51e87a497ca815d5dce0f8ab52554f849ed8995de64c5f34ce7143","efae9c8dbc14130661e8cec030c89ad0c13c66c0d17a2905cdc706ab7399a868"],["290798c2b6476830da12fe02287e9e777aa3fba1c355b17a722d362f84614fba","e38da76dcd440621988d00bcf79af25d5b29c094db2a23146d003afd41943e7a"],["af3c423a95d9f5b3054754efa150ac39cd29552fe360257362dfdecef4053b45","f98a3fd831eb2b749a93b0e6f35cfb40c8cd5aa667a15581bc2feded498fd9c6"],["766dbb24d134e745cccaa28c99bf274906bb66b26dcf98df8d2fed50d884249a","744b1152eacbe5e38dcc887980da38b897584a65fa06cedd2c924f97cbac5996"],["59dbf46f8c94759ba21277c33784f41645f7b44f6c596a58ce92e666191abe3e","c534ad44175fbc300f4ea6ce648309a042ce739a7919798cd85e216c4a307f6e"],["f13ada95103c4537305e691e74e9a4a8dd647e711a95e73cb62dc6018cfd87b8","e13817b44ee14de663bf4bc808341f326949e21a6a75c2570778419bdaf5733d"],["7754b4fa0e8aced06d4167a2c59cca4cda1869c06ebadfb6488550015a88522c","30e93e864e669d82224b967c3020b8fa8d1e4e350b6cbcc537a48b57841163a2"],["948dcadf5990e048aa3874d46abef9d701858f95de8041d2a6828c99e2262519","e491a42537f6e597d5d28a3224b1bc25df9154efbd2ef1d2cbba2cae5347d57e"],["7962414450c76c1689c7b48f8202ec37fb224cf5ac0bfa1570328a8a3d7c77ab","100b610ec4ffb4760d5c1fc133ef6f6b12507a051f04ac5760afa5b29db83437"],["3514087834964b54b15b160644d915485a16977225b8847bb0dd085137ec47ca","ef0afbb2056205448e1652c48e8127fc6039e77c15c2378b7e7d15a0de293311"],["d3cc30ad6b483e4bc79ce2c9dd8bc54993e947eb8df787b442943d3f7b527eaf","8b378a22d827278d89c5e9be8f9508ae3c2ad46290358630afb34db04eede0a4"],["1624d84780732860ce1c78fcbfefe08b2b29823db913f6493975ba0ff4847610","68651cf9b6da903e0914448c6cd9d4ca896878f5282be4c8cc06e2a404078575"],["733ce80da955a8a26902c95633e62a985192474b5af207da6df7b4fd5fc61cd4","f5435a2bd2badf7d485a4d8b8db9fcce3e1ef8e0201e4578c54673bc1dc5ea1d"],["15d9441254945064cf1a1c33bbd3b49f8966c5092171e699ef258dfab81c045c","d56eb30b69463e7234f5137b73b84177434800bacebfc685fc37bbe9efe4070d"],["a1d0fcf2ec9de675b612136e5ce70d271c21417c9d2b8aaaac138599d0717940","edd77f50bcb5a3cab2e90737309667f2641462a54070f3d519212d39c197a629"],["e22fbe15c0af8ccc5780c0735f84dbe9a790badee8245c06c7ca37331cb36980","a855babad5cd60c88b430a69f53a1a7a38289154964799be43d06d77d31da06"],["311091dd9860e8e20ee13473c1155f5f69635e394704eaa74009452246cfa9b3","66db656f87d1f04fffd1f04788c06830871ec5a64feee685bd80f0b1286d8374"],["34c1fd04d301be89b31c0442d3e6ac24883928b45a9340781867d4232ec2dbdf","9414685e97b1b5954bd46f730174136d57f1ceeb487443dc5321857ba73abee"],["f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63","4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1"],["d7b8740f74a8fbaab1f683db8f45de26543a5490bca627087236912469a0b448","fa77968128d9c92ee1010f337ad4717eff15db5ed3c049b3411e0315eaa4593b"],["32d31c222f8f6f0ef86f7c98d3a3335ead5bcd32abdd94289fe4d3091aa824bf","5f3032f5892156e39ccd3d7915b9e1da2e6dac9e6f26e961118d14b8462e1661"],["7461f371914ab32671045a155d9831ea8793d77cd59592c4340f86cbc18347b5","8ec0ba238b96bec0cbdddcae0aa442542eee1ff50c986ea6b39847b3cc092ff6"],["ee079adb1df1860074356a25aa38206a6d716b2c3e67453d287698bad7b2b2d6","8dc2412aafe3be5c4c5f37e0ecc5f9f6a446989af04c4e25ebaac479ec1c8c1e"],["16ec93e447ec83f0467b18302ee620f7e65de331874c9dc72bfd8616ba9da6b5","5e4631150e62fb40d0e8c2a7ca5804a39d58186a50e497139626778e25b0674d"],["eaa5f980c245f6f038978290afa70b6bd8855897f98b6aa485b96065d537bd99","f65f5d3e292c2e0819a528391c994624d784869d7e6ea67fb18041024edc07dc"],["78c9407544ac132692ee1910a02439958ae04877151342ea96c4b6b35a49f51","f3e0319169eb9b85d5404795539a5e68fa1fbd583c064d2462b675f194a3ddb4"],["494f4be219a1a77016dcd838431aea0001cdc8ae7a6fc688726578d9702857a5","42242a969283a5f339ba7f075e36ba2af925ce30d767ed6e55f4b031880d562c"],["a598a8030da6d86c6bc7f2f5144ea549d28211ea58faa70ebf4c1e665c1fe9b5","204b5d6f84822c307e4b4a7140737aec23fc63b65b35f86a10026dbd2d864e6b"],["c41916365abb2b5d09192f5f2dbeafec208f020f12570a184dbadc3e58595997","4f14351d0087efa49d245b328984989d5caf9450f34bfc0ed16e96b58fa9913"],["841d6063a586fa475a724604da03bc5b92a2e0d2e0a36acfe4c73a5514742881","73867f59c0659e81904f9a1c7543698e62562d6744c169ce7a36de01a8d6154"],["5e95bb399a6971d376026947f89bde2f282b33810928be4ded112ac4d70e20d5","39f23f366809085beebfc71181313775a99c9aed7d8ba38b161384c746012865"],["36e4641a53948fd476c39f8a99fd974e5ec07564b5315d8bf99471bca0ef2f66","d2424b1b1abe4eb8164227b085c9aa9456ea13493fd563e06fd51cf5694c78fc"],["336581ea7bfbbb290c191a2f507a41cf5643842170e914faeab27c2c579f726","ead12168595fe1be99252129b6e56b3391f7ab1410cd1e0ef3dcdcabd2fda224"],["8ab89816dadfd6b6a1f2634fcf00ec8403781025ed6890c4849742706bd43ede","6fdcef09f2f6d0a044e654aef624136f503d459c3e89845858a47a9129cdd24e"],["1e33f1a746c9c5778133344d9299fcaa20b0938e8acff2544bb40284b8c5fb94","60660257dd11b3aa9c8ed618d24edff2306d320f1d03010e33a7d2057f3b3b6"],["85b7c1dcb3cec1b7ee7f30ded79dd20a0ed1f4cc18cbcfcfa410361fd8f08f31","3d98a9cdd026dd43f39048f25a8847f4fcafad1895d7a633c6fed3c35e999511"],["29df9fbd8d9e46509275f4b125d6d45d7fbe9a3b878a7af872a2800661ac5f51","b4c4fe99c775a606e2d8862179139ffda61dc861c019e55cd2876eb2a27d84b"],["a0b1cae06b0a847a3fea6e671aaf8adfdfe58ca2f768105c8082b2e449fce252","ae434102edde0958ec4b19d917a6a28e6b72da1834aff0e650f049503a296cf2"],["4e8ceafb9b3e9a136dc7ff67e840295b499dfb3b2133e4ba113f2e4c0e121e5","cf2174118c8b6d7a4b48f6d534ce5c79422c086a63460502b827ce62a326683c"],["d24a44e047e19b6f5afb81c7ca2f69080a5076689a010919f42725c2b789a33b","6fb8d5591b466f8fc63db50f1c0f1c69013f996887b8244d2cdec417afea8fa3"],["ea01606a7a6c9cdd249fdfcfacb99584001edd28abbab77b5104e98e8e3b35d4","322af4908c7312b0cfbfe369f7a7b3cdb7d4494bc2823700cfd652188a3ea98d"],["af8addbf2b661c8a6c6328655eb96651252007d8c5ea31be4ad196de8ce2131f","6749e67c029b85f52a034eafd096836b2520818680e26ac8f3dfbcdb71749700"],["e3ae1974566ca06cc516d47e0fb165a674a3dabcfca15e722f0e3450f45889","2aeabe7e4531510116217f07bf4d07300de97e4874f81f533420a72eeb0bd6a4"],["591ee355313d99721cf6993ffed1e3e301993ff3ed258802075ea8ced397e246","b0ea558a113c30bea60fc4775460c7901ff0b053d25ca2bdeee98f1a4be5d196"],["11396d55fda54c49f19aa97318d8da61fa8584e47b084945077cf03255b52984","998c74a8cd45ac01289d5833a7beb4744ff536b01b257be4c5767bea93ea57a4"],["3c5d2a1ba39c5a1790000738c9e0c40b8dcdfd5468754b6405540157e017aa7a","b2284279995a34e2f9d4de7396fc18b80f9b8b9fdd270f6661f79ca4c81bd257"],["cc8704b8a60a0defa3a99a7299f2e9c3fbc395afb04ac078425ef8a1793cc030","bdd46039feed17881d1e0862db347f8cf395b74fc4bcdc4e940b74e3ac1f1b13"],["c533e4f7ea8555aacd9777ac5cad29b97dd4defccc53ee7ea204119b2889b197","6f0a256bc5efdf429a2fb6242f1a43a2d9b925bb4a4b3a26bb8e0f45eb596096"],["c14f8f2ccb27d6f109f6d08d03cc96a69ba8c34eec07bbcf566d48e33da6593","c359d6923bb398f7fd4473e16fe1c28475b740dd098075e6c0e8649113dc3a38"],["a6cbc3046bc6a450bac24789fa17115a4c9739ed75f8f21ce441f72e0b90e6ef","21ae7f4680e889bb130619e2c0f95a360ceb573c70603139862afd617fa9b9f"],["347d6d9a02c48927ebfb86c1359b1caf130a3c0267d11ce6344b39f99d43cc38","60ea7f61a353524d1c987f6ecec92f086d565ab687870cb12689ff1e31c74448"],["da6545d2181db8d983f7dcb375ef5866d47c67b1bf31c8cf855ef7437b72656a","49b96715ab6878a79e78f07ce5680c5d6673051b4935bd897fea824b77dc208a"],["c40747cc9d012cb1a13b8148309c6de7ec25d6945d657146b9d5994b8feb1111","5ca560753be2a12fc6de6caf2cb489565db936156b9514e1bb5e83037e0fa2d4"],["4e42c8ec82c99798ccf3a610be870e78338c7f713348bd34c8203ef4037f3502","7571d74ee5e0fb92a7a8b33a07783341a5492144cc54bcc40a94473693606437"],["3775ab7089bc6af823aba2e1af70b236d251cadb0c86743287522a1b3b0dedea","be52d107bcfa09d8bcb9736a828cfa7fac8db17bf7a76a2c42ad961409018cf7"],["cee31cbf7e34ec379d94fb814d3d775ad954595d1314ba8846959e3e82f74e26","8fd64a14c06b589c26b947ae2bcf6bfa0149ef0be14ed4d80f448a01c43b1c6d"],["b4f9eaea09b6917619f6ea6a4eb5464efddb58fd45b1ebefcdc1a01d08b47986","39e5c9925b5a54b07433a4f18c61726f8bb131c012ca542eb24a8ac07200682a"],["d4263dfc3d2df923a0179a48966d30ce84e2515afc3dccc1b77907792ebcc60e","62dfaf07a0f78feb30e30d6295853ce189e127760ad6cf7fae164e122a208d54"],["48457524820fa65a4f8d35eb6930857c0032acc0a4a2de422233eeda897612c4","25a748ab367979d98733c38a1fa1c2e7dc6cc07db2d60a9ae7a76aaa49bd0f77"],["dfeeef1881101f2cb11644f3a2afdfc2045e19919152923f367a1767c11cceda","ecfb7056cf1de042f9420bab396793c0c390bde74b4bbdff16a83ae09a9a7517"],["6d7ef6b17543f8373c573f44e1f389835d89bcbc6062ced36c82df83b8fae859","cd450ec335438986dfefa10c57fea9bcc521a0959b2d80bbf74b190dca712d10"],["e75605d59102a5a2684500d3b991f2e3f3c88b93225547035af25af66e04541f","f5c54754a8f71ee540b9b48728473e314f729ac5308b06938360990e2bfad125"],["eb98660f4c4dfaa06a2be453d5020bc99a0c2e60abe388457dd43fefb1ed620c","6cb9a8876d9cb8520609af3add26cd20a0a7cd8a9411131ce85f44100099223e"],["13e87b027d8514d35939f2e6892b19922154596941888336dc3563e3b8dba942","fef5a3c68059a6dec5d624114bf1e91aac2b9da568d6abeb2570d55646b8adf1"],["ee163026e9fd6fe017c38f06a5be6fc125424b371ce2708e7bf4491691e5764a","1acb250f255dd61c43d94ccc670d0f58f49ae3fa15b96623e5430da0ad6c62b2"],["b268f5ef9ad51e4d78de3a750c2dc89b1e626d43505867999932e5db33af3d80","5f310d4b3c99b9ebb19f77d41c1dee018cf0d34fd4191614003e945a1216e423"],["ff07f3118a9df035e9fad85eb6c7bfe42b02f01ca99ceea3bf7ffdba93c4750d","438136d603e858a3a5c440c38eccbaddc1d2942114e2eddd4740d098ced1f0d8"],["8d8b9855c7c052a34146fd20ffb658bea4b9f69e0d825ebec16e8c3ce2b526a1","cdb559eedc2d79f926baf44fb84ea4d44bcf50fee51d7ceb30e2e7f463036758"],["52db0b5384dfbf05bfa9d472d7ae26dfe4b851ceca91b1eba54263180da32b63","c3b997d050ee5d423ebaf66a6db9f57b3180c902875679de924b69d84a7b375"],["e62f9490d3d51da6395efd24e80919cc7d0f29c3f3fa48c6fff543becbd43352","6d89ad7ba4876b0b22c2ca280c682862f342c8591f1daf5170e07bfd9ccafa7d"],["7f30ea2476b399b4957509c88f77d0191afa2ff5cb7b14fd6d8e7d65aaab1193","ca5ef7d4b231c94c3b15389a5f6311e9daff7bb67b103e9880ef4bff637acaec"],["5098ff1e1d9f14fb46a210fada6c903fef0fb7b4a1dd1d9ac60a0361800b7a00","9731141d81fc8f8084d37c6e7542006b3ee1b40d60dfe5362a5b132fd17ddc0"],["32b78c7de9ee512a72895be6b9cbefa6e2f3c4ccce445c96b9f2c81e2778ad58","ee1849f513df71e32efc3896ee28260c73bb80547ae2275ba497237794c8753c"],["e2cb74fddc8e9fbcd076eef2a7c72b0ce37d50f08269dfc074b581550547a4f7","d3aa2ed71c9dd2247a62df062736eb0baddea9e36122d2be8641abcb005cc4a4"],["8438447566d4d7bedadc299496ab357426009a35f235cb141be0d99cd10ae3a8","c4e1020916980a4da5d01ac5e6ad330734ef0d7906631c4f2390426b2edd791f"],["4162d488b89402039b584c6fc6c308870587d9c46f660b878ab65c82c711d67e","67163e903236289f776f22c25fb8a3afc1732f2b84b4e95dbda47ae5a0852649"],["3fad3fa84caf0f34f0f89bfd2dcf54fc175d767aec3e50684f3ba4a4bf5f683d","cd1bc7cb6cc407bb2f0ca647c718a730cf71872e7d0d2a53fa20efcdfe61826"],["674f2600a3007a00568c1a7ce05d0816c1fb84bf1370798f1c69532faeb1a86b","299d21f9413f33b3edf43b257004580b70db57da0b182259e09eecc69e0d38a5"],["d32f4da54ade74abb81b815ad1fb3b263d82d6c692714bcff87d29bd5ee9f08f","f9429e738b8e53b968e99016c059707782e14f4535359d582fc416910b3eea87"],["30e4e670435385556e593657135845d36fbb6931f72b08cb1ed954f1e3ce3ff6","462f9bce619898638499350113bbc9b10a878d35da70740dc695a559eb88db7b"],["be2062003c51cc3004682904330e4dee7f3dcd10b01e580bf1971b04d4cad297","62188bc49d61e5428573d48a74e1c655b1c61090905682a0d5558ed72dccb9bc"],["93144423ace3451ed29e0fb9ac2af211cb6e84a601df5993c419859fff5df04a","7c10dfb164c3425f5c71a3f9d7992038f1065224f72bb9d1d902a6d13037b47c"],["b015f8044f5fcbdcf21ca26d6c34fb8197829205c7b7d2a7cb66418c157b112c","ab8c1e086d04e813744a655b2df8d5f83b3cdc6faa3088c1d3aea1454e3a1d5f"],["d5e9e1da649d97d89e4868117a465a3a4f8a18de57a140d36b3f2af341a21b52","4cb04437f391ed73111a13cc1d4dd0db1693465c2240480d8955e8592f27447a"],["d3ae41047dd7ca065dbf8ed77b992439983005cd72e16d6f996a5316d36966bb","bd1aeb21ad22ebb22a10f0303417c6d964f8cdd7df0aca614b10dc14d125ac46"],["463e2763d885f958fc66cdd22800f0a487197d0a82e377b49f80af87c897b065","bfefacdb0e5d0fd7df3a311a94de062b26b80c61fbc97508b79992671ef7ca7f"],["7985fdfd127c0567c6f53ec1bb63ec3158e597c40bfe747c83cddfc910641917","603c12daf3d9862ef2b25fe1de289aed24ed291e0ec6708703a5bd567f32ed03"],["74a1ad6b5f76e39db2dd249410eac7f99e74c59cb83d2d0ed5ff1543da7703e9","cc6157ef18c9c63cd6193d83631bbea0093e0968942e8c33d5737fd790e0db08"],["30682a50703375f602d416664ba19b7fc9bab42c72747463a71d0896b22f6da3","553e04f6b018b4fa6c8f39e7f311d3176290d0e0f19ca73f17714d9977a22ff8"],["9e2158f0d7c0d5f26c3791efefa79597654e7a2b2464f52b1ee6c1347769ef57","712fcdd1b9053f09003a3481fa7762e9ffd7c8ef35a38509e2fbf2629008373"],["176e26989a43c9cfeba4029c202538c28172e566e3c4fce7322857f3be327d66","ed8cc9d04b29eb877d270b4878dc43c19aefd31f4eee09ee7b47834c1fa4b1c3"],["75d46efea3771e6e68abb89a13ad747ecf1892393dfc4f1b7004788c50374da8","9852390a99507679fd0b86fd2b39a868d7efc22151346e1a3ca4726586a6bed8"],["809a20c67d64900ffb698c4c825f6d5f2310fb0451c869345b7319f645605721","9e994980d9917e22b76b061927fa04143d096ccc54963e6a5ebfa5f3f8e286c1"],["1b38903a43f7f114ed4500b4eac7083fdefece1cf29c63528d563446f972c180","4036edc931a60ae889353f77fd53de4a2708b26b6f5da72ad3394119daf408f9"]]}}});var Ty=U(eP=>{"use strict";var HS=eP,cA=Dy(),OS=TS(),k0e=Kn(),Z9=k0e.assert;function $9(e){e.type==="short"?this.curve=new OS.short(e):e.type==="edwards"?this.curve=new OS.edwards(e):this.curve=new OS.mont(e),this.g=this.curve.g,this.n=this.curve.n,this.hash=e.hash,Z9(this.g.validate(),"Invalid curve"),Z9(this.g.mul(this.n).isInfinity(),"Invalid curve, G*N != O")}HS.PresetCurve=$9;function lA(e,t){Object.defineProperty(HS,e,{configurable:!0,enumerable:!0,get:function(){var r=new $9(t);return Object.defineProperty(HS,e,{configurable:!0,enumerable:!0,value:r}),r}})}lA("p192",{type:"short",prime:"p192",p:"ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff",a:"ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc",b:"64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1",n:"ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831",hash:cA.sha256,gRed:!1,g:["188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012","07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811"]});lA("p224",{type:"short",prime:"p224",p:"ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001",a:"ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe",b:"b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4",n:"ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d",hash:cA.sha256,gRed:!1,g:["b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21","bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34"]});lA("p256",{type:"short",prime:null,p:"ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff",a:"ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc",b:"5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b",n:"ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551",hash:cA.sha256,gRed:!1,g:["6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296","4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5"]});lA("p384",{type:"short",prime:null,p:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe ffffffff 00000000 00000000 ffffffff",a:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe ffffffff 00000000 00000000 fffffffc",b:"b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef",n:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 f4372ddf 581a0db2 48b0a77a ecec196a ccc52973",hash:cA.sha384,gRed:!1,g:["aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7","3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f"]});lA("p521",{type:"short",prime:null,p:"000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff",a:"000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffc",b:"00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b 99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd 3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00",n:"000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409",hash:cA.sha512,gRed:!1,g:["000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66","00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 3fad0761 353c7086 a272c240 88be9476 9fd16650"]});lA("curve25519",{type:"mont",prime:"p25519",p:"7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed",a:"76d06",b:"1",n:"1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed",hash:cA.sha256,gRed:!1,g:["9"]});lA("ed25519",{type:"edwards",prime:"p25519",p:"7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed",a:"-1",c:"1",d:"52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3",n:"1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed",hash:cA.sha256,gRed:!1,g:["216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a","6666666666666666666666666666666666666666666666666666666666666658"]});var qS;try{qS=X9()}catch{qS=void 0}lA("secp256k1",{type:"short",prime:"k256",p:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f",a:"0",b:"7",n:"ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141",h:"1",hash:cA.sha256,beta:"7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee",lambda:"5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72",basis:[{a:"3086d221a7d46bcde86c90e49284eb15",b:"-e4437ed6010e88286f547fa90abfe4c3"},{a:"114ca50f7a8e2f3f657c1108d9d44cfd8",b:"3086d221a7d46bcde86c90e49284eb15"}],gRed:!1,g:["79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",qS]})});var nP=U((CMe,rP)=>{"use strict";var U0e=Dy(),kf=RS(),tP=zn();function hA(e){if(!(this instanceof hA))return new hA(e);this.hash=e.hash,this.predResist=!!e.predResist,this.outLen=this.hash.outSize,this.minEntropy=e.minEntropy||this.hash.hmacStrength,this._reseed=null,this.reseedInterval=null,this.K=null,this.V=null;var t=kf.toArray(e.entropy,e.entropyEnc||"hex"),r=kf.toArray(e.nonce,e.nonceEnc||"hex"),n=kf.toArray(e.pers,e.persEnc||"hex");tP(t.length>=this.minEntropy/8,"Not enough entropy. Minimum is: "+this.minEntropy+" bits"),this._init(t,r,n)}rP.exports=hA;hA.prototype._init=function(t,r,n){var i=t.concat(r).concat(n);this.K=new Array(this.outLen/8),this.V=new Array(this.outLen/8);for(var s=0;s=this.minEntropy/8,"Not enough entropy. Minimum is: "+this.minEntropy+" bits"),this._update(t.concat(n||[])),this._reseed=1};hA.prototype.generate=function(t,r,n,i){if(this._reseed>this.reseedInterval)throw new Error("Reseed is required");typeof r!="string"&&(i=n,n=r,r=null),n&&(n=kf.toArray(n,i||"hex"),this._update(n));for(var s=[];s.length{"use strict";var x0e=kr(),L0e=Kn(),GS=L0e.assert;function An(e,t){this.ec=e,this.priv=null,this.pub=null,t.priv&&this._importPrivate(t.priv,t.privEnc),t.pub&&this._importPublic(t.pub,t.pubEnc)}iP.exports=An;An.fromPublic=function(t,r,n){return r instanceof An?r:new An(t,{pub:r,pubEnc:n})};An.fromPrivate=function(t,r,n){return r instanceof An?r:new An(t,{priv:r,privEnc:n})};An.prototype.validate=function(){var t=this.getPublic();return t.isInfinity()?{result:!1,reason:"Invalid public key"}:t.validate()?t.mul(this.ec.curve.n).isInfinity()?{result:!0,reason:null}:{result:!1,reason:"Public key * N != O"}:{result:!1,reason:"Public key is not a point"}};An.prototype.getPublic=function(t,r){return typeof t=="string"&&(r=t,t=null),this.pub||(this.pub=this.ec.g.mul(this.priv)),r?this.pub.encode(r,t):this.pub};An.prototype.getPrivate=function(t){return t==="hex"?this.priv.toString(16,2):this.priv};An.prototype._importPrivate=function(t,r){this.priv=new x0e(t,r||16),this.priv=this.priv.umod(this.ec.curve.n)};An.prototype._importPublic=function(t,r){if(t.x||t.y){this.ec.curve.type==="mont"?GS(t.x,"Need x coordinate"):(this.ec.curve.type==="short"||this.ec.curve.type==="edwards")&&GS(t.x&&t.y,"Need both x and y coordinate"),this.pub=this.ec.curve.point(t.x,t.y);return}this.pub=this.ec.curve.decodePoint(t,r)};An.prototype.derive=function(t){return t.validate()||GS(t.validate(),"public point not validated"),t.mul(this.priv).getX()};An.prototype.sign=function(t,r,n){return this.ec.sign(t,this,r,n)};An.prototype.verify=function(t,r,n){return this.ec.verify(t,r,this,void 0,n)};An.prototype.inspect=function(){return""}});var AP=U((wMe,aP)=>{"use strict";var Ny=kr(),VS=Kn(),P0e=VS.assert;function My(e,t){if(e instanceof My)return e;this._importDER(e,t)||(P0e(e.r&&e.s,"Signature without r or s"),this.r=new Ny(e.r,16),this.s=new Ny(e.s,16),e.recoveryParam===void 0?this.recoveryParam=null:this.recoveryParam=e.recoveryParam)}aP.exports=My;function O0e(){this.place=0}function YS(e,t){var r=e[t.place++];if(!(r&128))return r;var n=r&15;if(n===0||n>4||e[t.place]===0)return!1;for(var i=0,s=0,o=t.place;s>>=0;return i<=127?!1:(t.place=o,i)}function oP(e){for(var t=0,r=e.length-1;!e[t]&&!(e[t+1]&128)&&t>>3);for(e.push(r|128);--r;)e.push(t>>>(r<<3)&255);e.push(t)}My.prototype.toDER=function(t){var r=this.r.toArray(),n=this.s.toArray();for(r[0]&128&&(r=[0].concat(r)),n[0]&128&&(n=[0].concat(n)),r=oP(r),n=oP(n);!n[0]&&!(n[1]&128);)n=n.slice(1);var i=[2];WS(i,r.length),i=i.concat(r),i.push(2),WS(i,n.length);var s=i.concat(n),o=[48];return WS(o,s.length),o=o.concat(s),VS.encode(o,t)}});var cP=U((SMe,uP)=>{"use strict";var hs=kr(),fP=nP(),H0e=Kn(),JS=Ty(),q0e=py(),Uf=H0e.assert,jS=sP(),Fy=AP();function _i(e){if(!(this instanceof _i))return new _i(e);typeof e=="string"&&(Uf(Object.prototype.hasOwnProperty.call(JS,e),"Unknown curve "+e),e=JS[e]),e instanceof JS.PresetCurve&&(e={curve:e}),this.curve=e.curve.curve,this.n=this.curve.n,this.nh=this.n.ushrn(1),this.g=this.curve.g,this.g=e.curve.g,this.g.precompute(e.curve.n.bitLength()+1),this.hash=e.hash||e.curve.hash}uP.exports=_i;_i.prototype.keyPair=function(t){return new jS(this,t)};_i.prototype.keyFromPrivate=function(t,r){return jS.fromPrivate(this,t,r)};_i.prototype.keyFromPublic=function(t,r){return jS.fromPublic(this,t,r)};_i.prototype.genKeyPair=function(t){t||(t={});for(var r=new fP({hash:this.hash,pers:t.pers,persEnc:t.persEnc||"utf8",entropy:t.entropy||q0e(this.hash.hmacStrength),entropyEnc:t.entropy&&t.entropyEnc||"utf8",nonce:this.n.toArray()}),n=this.n.byteLength(),i=this.n.sub(new hs(2));;){var s=new hs(r.generate(n));if(!(s.cmp(i)>0))return s.iaddn(1),this.keyFromPrivate(s)}};_i.prototype._truncateToN=function(t,r,n){var i;if(hs.isBN(t)||typeof t=="number")t=new hs(t,16),i=t.byteLength();else if(typeof t=="object")i=t.length,t=new hs(t,16);else{var s=t.toString();i=s.length+1>>>1,t=new hs(s,16)}typeof n!="number"&&(n=i*8);var o=n-this.n.bitLength();return o>0&&(t=t.ushrn(o)),!r&&t.cmp(this.n)>=0?t.sub(this.n):t};_i.prototype.sign=function(t,r,n,i){if(typeof n=="object"&&(i=n,n=null),i||(i={}),typeof t!="string"&&typeof t!="number"&&!hs.isBN(t)){Uf(typeof t=="object"&&t&&typeof t.length=="number","Expected message to be an array-like, a hex string, or a BN instance"),Uf(t.length>>>0===t.length);for(var s=0;s=0)){var S=this.g.mul(I);if(!S.isInfinity()){var _=S.getX(),N=_.umod(this.n);if(N.cmpn(0)!==0){var O=I.invm(this.n).mul(N.mul(r.getPrivate()).iadd(t));if(O=O.umod(this.n),O.cmpn(0)!==0){var x=(S.getY().isOdd()?1:0)|(_.cmp(N)!==0?2:0);return i.canonical&&O.cmp(this.nh)>0&&(O=this.n.sub(O),x^=1),new Fy({r:N,s:O,recoveryParam:x})}}}}}};_i.prototype.verify=function(t,r,n,i,s){s||(s={}),t=this._truncateToN(t,!1,s.msgBitLength),n=this.keyFromPublic(n,i),r=new Fy(r,"hex");var o=r.r,a=r.s;if(o.cmpn(1)<0||o.cmp(this.n)>=0||a.cmpn(1)<0||a.cmp(this.n)>=0)return!1;var A=a.invm(this.n),f=A.mul(t).umod(this.n),l=A.mul(o).umod(this.n),p;return this.curve._maxwellTrick?(p=this.g.jmulAdd(f,n.getPublic(),l),p.isInfinity()?!1:p.eqXToP(o)):(p=this.g.mulAdd(f,n.getPublic(),l),p.isInfinity()?!1:p.getX().umod(this.n).cmp(o)===0)};_i.prototype.recoverPubKey=function(e,t,r,n){Uf((3&r)===r,"The recovery param is more than two bits"),t=new Fy(t,n);var i=this.n,s=new hs(e),o=t.r,a=t.s,A=r&1,f=r>>1;if(o.cmp(this.curve.p.umod(this.curve.n))>=0&&f)throw new Error("Unable to find sencond key candinate");f?o=this.curve.pointFromX(o.add(this.curve.n),A):o=this.curve.pointFromX(o,A);var l=t.r.invm(i),p=i.sub(s).mul(l).umod(i),I=a.mul(l).umod(i);return this.g.mulAdd(p,o,I)};_i.prototype.getKeyRecoveryParam=function(e,t,r,n){if(t=new Fy(t,n),t.recoveryParam!==null)return t.recoveryParam;for(var i=0;i<4;i++){var s;try{s=this.recoverPubKey(e,t,i)}catch{continue}if(s.eq(r))return i}throw new Error("Unable to find valid recovery factor")}});var gP=U((_Me,dP)=>{"use strict";var xd=Kn(),hP=xd.assert,lP=xd.parseBytes,Kc=xd.cachedProperty;function Lr(e,t){this.eddsa=e,this._secret=lP(t.secret),e.isPoint(t.pub)?this._pub=t.pub:this._pubBytes=lP(t.pub)}Lr.fromPublic=function(t,r){return r instanceof Lr?r:new Lr(t,{pub:r})};Lr.fromSecret=function(t,r){return r instanceof Lr?r:new Lr(t,{secret:r})};Lr.prototype.secret=function(){return this._secret};Kc(Lr,"pubBytes",function(){return this.eddsa.encodePoint(this.pub())});Kc(Lr,"pub",function(){return this._pubBytes?this.eddsa.decodePoint(this._pubBytes):this.eddsa.g.mul(this.priv())});Kc(Lr,"privBytes",function(){var t=this.eddsa,r=this.hash(),n=t.encodingLength-1,i=r.slice(0,t.encodingLength);return i[0]&=248,i[n]&=127,i[n]|=64,i});Kc(Lr,"priv",function(){return this.eddsa.decodeInt(this.privBytes())});Kc(Lr,"hash",function(){return this.eddsa.hash().update(this.secret()).digest()});Kc(Lr,"messagePrefix",function(){return this.hash().slice(this.eddsa.encodingLength)});Lr.prototype.sign=function(t){return hP(this._secret,"KeyPair can only verify"),this.eddsa.sign(t,this)};Lr.prototype.verify=function(t,r){return this.eddsa.verify(t,r,this)};Lr.prototype.getSecret=function(t){return hP(this._secret,"KeyPair is public only"),xd.encode(this.secret(),t)};Lr.prototype.getPublic=function(t){return xd.encode(this.pubBytes(),t)};dP.exports=Lr});var yP=U((vMe,EP)=>{"use strict";var G0e=kr(),ky=Kn(),pP=ky.assert,Uy=ky.cachedProperty,Y0e=ky.parseBytes;function xf(e,t){this.eddsa=e,typeof t!="object"&&(t=Y0e(t)),Array.isArray(t)&&(pP(t.length===e.encodingLength*2,"Signature has invalid size"),t={R:t.slice(0,e.encodingLength),S:t.slice(e.encodingLength)}),pP(t.R&&t.S,"Signature without R or S"),e.isPoint(t.R)&&(this._R=t.R),t.S instanceof G0e&&(this._S=t.S),this._Rencoded=Array.isArray(t.R)?t.R:t.Rencoded,this._Sencoded=Array.isArray(t.S)?t.S:t.Sencoded}Uy(xf,"S",function(){return this.eddsa.decodeInt(this.Sencoded())});Uy(xf,"R",function(){return this.eddsa.decodePoint(this.Rencoded())});Uy(xf,"Rencoded",function(){return this.eddsa.encodePoint(this.R())});Uy(xf,"Sencoded",function(){return this.eddsa.encodeInt(this.S())});xf.prototype.toBytes=function(){return this.Rencoded().concat(this.Sencoded())};xf.prototype.toHex=function(){return ky.encode(this.toBytes(),"hex").toUpperCase()};EP.exports=xf});var CP=U((RMe,bP)=>{"use strict";var W0e=Dy(),V0e=Ty(),Xc=Kn(),J0e=Xc.assert,BP=Xc.parseBytes,IP=gP(),mP=yP();function Fn(e){if(J0e(e==="ed25519","only tested with ed25519 so far"),!(this instanceof Fn))return new Fn(e);e=V0e[e].curve,this.curve=e,this.g=e.g,this.g.precompute(e.n.bitLength()+1),this.pointClass=e.point().constructor,this.encodingLength=Math.ceil(e.n.bitLength()/8),this.hash=W0e.sha512}bP.exports=Fn;Fn.prototype.sign=function(t,r){t=BP(t);var n=this.keyFromSecret(r),i=this.hashInt(n.messagePrefix(),t),s=this.g.mul(i),o=this.encodePoint(s),a=this.hashInt(o,n.pubBytes(),t).mul(n.priv()),A=i.add(a).umod(this.curve.n);return this.makeSignature({R:s,S:A,Rencoded:o})};Fn.prototype.verify=function(t,r,n){if(t=BP(t),r=this.makeSignature(r),r.S().gte(r.eddsa.curve.n)||r.S().isNeg())return!1;var i=this.keyFromPublic(n),s=this.hashInt(r.Rencoded(),i.pubBytes(),t),o=this.g.mul(r.S()),a=r.R().add(i.pub().mul(s));return a.eq(o)};Fn.prototype.hashInt=function(){for(var t=this.hash(),r=0;r{"use strict";var Lf=QP;Lf.version=r9().version;Lf.utils=Kn();Lf.rand=py();Lf.curve=TS();Lf.curves=Ty();Lf.ec=cP();Lf.eddsa=CP()});var wP=U((exports,module)=>{var indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var r=0;r{var SP=$c(),j0e=je(),z0e=_P;z0e.define=function(t,r){return new Zc(t,r)};function Zc(e,t){this.name=e,this.body=t,this.decoders={},this.encoders={}}Zc.prototype._createNamed=function(t){var r;try{r=wP().runInThisContext("(function "+this.name+`(entity) { - this._initNamed(entity); -})`)}catch{r=function(i){this._initNamed(i)}}return j0e(r,t),r.prototype._initNamed=function(i){t.call(this,i)},new r(this)};Zc.prototype._getDecoder=function(t){return t=t||"der",this.decoders.hasOwnProperty(t)||(this.decoders[t]=this._createNamed(SP.decoders[t])),this.decoders[t]};Zc.prototype.decode=function(t,r,n){return this._getDecoder(r).decode(t,n)};Zc.prototype._getEncoder=function(t){return t=t||"der",this.encoders.hasOwnProperty(t)||(this.encoders[t]=this._createNamed(SP.encoders[t])),this.encoders[t]};Zc.prototype.encode=function(t,r,n){return this._getEncoder(r).encode(t,n)}});var DP=U(RP=>{var K0e=je();function vi(e){this._reporterState={obj:null,path:[],options:e||{},errors:[]}}RP.Reporter=vi;vi.prototype.isError=function(t){return t instanceof el};vi.prototype.save=function(){var t=this._reporterState;return{obj:t.obj,pathLen:t.path.length}};vi.prototype.restore=function(t){var r=this._reporterState;r.obj=t.obj,r.path=r.path.slice(0,t.pathLen)};vi.prototype.enterKey=function(t){return this._reporterState.path.push(t)};vi.prototype.exitKey=function(t){var r=this._reporterState;r.path=r.path.slice(0,t-1)};vi.prototype.leaveKey=function(t,r,n){var i=this._reporterState;this.exitKey(t),i.obj!==null&&(i.obj[r]=n)};vi.prototype.path=function(){return this._reporterState.path.join("/")};vi.prototype.enterObject=function(){var t=this._reporterState,r=t.obj;return t.obj={},r};vi.prototype.leaveObject=function(t){var r=this._reporterState,n=r.obj;return r.obj=t,n};vi.prototype.error=function(t){var r,n=this._reporterState,i=t instanceof el;if(i?r=t:r=new el(n.path.map(function(s){return"["+JSON.stringify(s)+"]"}).join(""),t.message||t,t.stack),!n.options.partial)throw r;return i||n.errors.push(r),r};vi.prototype.wrapResult=function(t){var r=this._reporterState;return r.options.partial?{result:this.isError(t)?null:t,errors:r.errors}:t};function el(e,t){this.path=e,this.rethrow(t)}K0e(el,Error);el.prototype.rethrow=function(t){if(this.message=t+" at: "+(this.path||"(shallow)"),Error.captureStackTrace&&Error.captureStackTrace(this,el),!this.stack)try{throw new Error(this.message)}catch(r){this.stack=r.stack}return this}});var KS=U(zS=>{var X0e=je(),Py=tl().Reporter,Ld=Gr().Buffer;function uo(e,t){if(Py.call(this,t),!Ld.isBuffer(e)){this.error("Input not Buffer");return}this.base=e,this.offset=0,this.length=e.length}X0e(uo,Py);zS.DecoderBuffer=uo;uo.prototype.save=function(){return{offset:this.offset,reporter:Py.prototype.save.call(this)}};uo.prototype.restore=function(t){var r=new uo(this.base);return r.offset=t.offset,r.length=this.offset,this.offset=t.offset,Py.prototype.restore.call(this,t.reporter),r};uo.prototype.isEmpty=function(){return this.offset===this.length};uo.prototype.readUInt8=function(t){return this.offset+1<=this.length?this.base.readUInt8(this.offset++,!0):this.error(t||"DecoderBuffer overrun")};uo.prototype.skip=function(t,r){if(!(this.offset+t<=this.length))return this.error(r||"DecoderBuffer overrun");var n=new uo(this.base);return n._reporterState=this._reporterState,n.offset=this.offset,n.length=this.offset+t,this.offset+=t,n};uo.prototype.raw=function(t){return this.base.slice(t?t.offset:this.offset,this.length)};function Ly(e,t){if(Array.isArray(e))this.length=0,this.value=e.map(function(r){return r instanceof Ly||(r=new Ly(r,t)),this.length+=r.length,r},this);else if(typeof e=="number"){if(!(0<=e&&e<=255))return t.error("non-byte EncoderBuffer value");this.value=e,this.length=1}else if(typeof e=="string")this.value=e,this.length=Ld.byteLength(e);else if(Ld.isBuffer(e))this.value=e,this.length=e.length;else return t.error("Unsupported type: "+typeof e)}zS.EncoderBuffer=Ly;Ly.prototype.join=function(t,r){return t||(t=new Ld(this.length)),r||(r=0),this.length===0||(Array.isArray(this.value)?this.value.forEach(function(n){n.join(t,r),r+=n.length}):(typeof this.value=="number"?t[r]=this.value:typeof this.value=="string"?t.write(this.value,r):Ld.isBuffer(this.value)&&this.value.copy(t,r),r+=this.length)),t}});var MP=U((FMe,NP)=>{var Z0e=tl().Reporter,$0e=tl().EncoderBuffer,epe=tl().DecoderBuffer,En=zn(),TP=["seq","seqof","set","setof","objid","bool","gentime","utctime","null_","enum","int","objDesc","bitstr","bmpstr","charstr","genstr","graphstr","ia5str","iso646str","numstr","octstr","printstr","t61str","unistr","utf8str","videostr"],tpe=["key","obj","use","optional","explicit","implicit","def","choice","any","contains"].concat(TP),rpe=["_peekTag","_decodeTag","_use","_decodeStr","_decodeObjid","_decodeTime","_decodeNull","_decodeInt","_decodeBool","_decodeList","_encodeComposite","_encodeStr","_encodeObjid","_encodeTime","_encodeNull","_encodeInt","_encodeBool"];function Ut(e,t){var r={};this._baseState=r,r.enc=e,r.parent=t||null,r.children=null,r.tag=null,r.args=null,r.reverseArgs=null,r.choice=null,r.optional=!1,r.any=!1,r.obj=!1,r.use=null,r.useDecoder=null,r.key=null,r.default=null,r.explicit=null,r.implicit=null,r.contains=null,r.parent||(r.children=[],this._wrap())}NP.exports=Ut;var npe=["enc","parent","children","tag","args","reverseArgs","choice","optional","any","obj","use","alteredUse","key","default","explicit","implicit","contains"];Ut.prototype.clone=function(){var t=this._baseState,r={};npe.forEach(function(i){r[i]=t[i]});var n=new this.constructor(r.parent);return n._baseState=r,n};Ut.prototype._wrap=function(){var t=this._baseState;tpe.forEach(function(r){this[r]=function(){var i=new this.constructor(this);return t.children.push(i),i[r].apply(i,arguments)}},this)};Ut.prototype._init=function(t){var r=this._baseState;En(r.parent===null),t.call(this),r.children=r.children.filter(function(n){return n._baseState.parent===this},this),En.equal(r.children.length,1,"Root node can have only one child")};Ut.prototype._useArgs=function(t){var r=this._baseState,n=t.filter(function(i){return i instanceof this.constructor},this);t=t.filter(function(i){return!(i instanceof this.constructor)},this),n.length!==0&&(En(r.children===null),r.children=n,n.forEach(function(i){i._baseState.parent=this},this)),t.length!==0&&(En(r.args===null),r.args=t,r.reverseArgs=t.map(function(i){if(typeof i!="object"||i.constructor!==Object)return i;var s={};return Object.keys(i).forEach(function(o){o==(o|0)&&(o|=0);var a=i[o];s[a]=o}),s}))};rpe.forEach(function(e){Ut.prototype[e]=function(){var r=this._baseState;throw new Error(e+" not implemented for encoding: "+r.enc)}});TP.forEach(function(e){Ut.prototype[e]=function(){var r=this._baseState,n=Array.prototype.slice.call(arguments);return En(r.tag===null),r.tag=e,this._useArgs(n),this}});Ut.prototype.use=function(t){En(t);var r=this._baseState;return En(r.use===null),r.use=t,this};Ut.prototype.optional=function(){var t=this._baseState;return t.optional=!0,this};Ut.prototype.def=function(t){var r=this._baseState;return En(r.default===null),r.default=t,r.optional=!0,this};Ut.prototype.explicit=function(t){var r=this._baseState;return En(r.explicit===null&&r.implicit===null),r.explicit=t,this};Ut.prototype.implicit=function(t){var r=this._baseState;return En(r.explicit===null&&r.implicit===null),r.implicit=t,this};Ut.prototype.obj=function(){var t=this._baseState,r=Array.prototype.slice.call(arguments);return t.obj=!0,r.length!==0&&this._useArgs(r),this};Ut.prototype.key=function(t){var r=this._baseState;return En(r.key===null),r.key=t,this};Ut.prototype.any=function(){var t=this._baseState;return t.any=!0,this};Ut.prototype.choice=function(t){var r=this._baseState;return En(r.choice===null),r.choice=t,this._useArgs(Object.keys(t).map(function(n){return t[n]})),this};Ut.prototype.contains=function(t){var r=this._baseState;return En(r.use===null),r.contains=t,this};Ut.prototype._decode=function(t,r){var n=this._baseState;if(n.parent===null)return t.wrapResult(n.children[0]._decode(t,r));var i=n.default,s=!0,o=null;if(n.key!==null&&(o=t.enterKey(n.key)),n.optional){var a=null;if(n.explicit!==null?a=n.explicit:n.implicit!==null?a=n.implicit:n.tag!==null&&(a=n.tag),a===null&&!n.any){var A=t.save();try{n.choice===null?this._decodeGeneric(n.tag,t,r):this._decodeChoice(t,r),s=!0}catch{s=!1}t.restore(A)}else if(s=this._peekTag(t,a,n.any),t.isError(s))return s}var f;if(n.obj&&s&&(f=t.enterObject()),s){if(n.explicit!==null){var l=this._decodeTag(t,n.explicit);if(t.isError(l))return l;t=l}var p=t.offset;if(n.use===null&&n.choice===null){if(n.any)var A=t.save();var I=this._decodeTag(t,n.implicit!==null?n.implicit:n.tag,n.any);if(t.isError(I))return I;n.any?i=t.raw(A):t=I}if(r&&r.track&&n.tag!==null&&r.track(t.path(),p,t.length,"tagged"),r&&r.track&&n.tag!==null&&r.track(t.path(),t.offset,t.length,"content"),n.any?i=i:n.choice===null?i=this._decodeGeneric(n.tag,t,r):i=this._decodeChoice(t,r),t.isError(i))return i;if(!n.any&&n.choice===null&&n.children!==null&&n.children.forEach(function(N){N._decode(t,r)}),n.contains&&(n.tag==="octstr"||n.tag==="bitstr")){var S=new epe(i);i=this._getUse(n.contains,t._reporterState.obj)._decode(S,r)}}return n.obj&&s&&(i=t.leaveObject(f)),n.key!==null&&(i!==null||s===!0)?t.leaveKey(o,n.key,i):o!==null&&t.exitKey(o),i};Ut.prototype._decodeGeneric=function(t,r,n){var i=this._baseState;return t==="seq"||t==="set"?null:t==="seqof"||t==="setof"?this._decodeList(r,t,i.args[0],n):/str$/.test(t)?this._decodeStr(r,t,n):t==="objid"&&i.args?this._decodeObjid(r,i.args[0],i.args[1],n):t==="objid"?this._decodeObjid(r,null,null,n):t==="gentime"||t==="utctime"?this._decodeTime(r,t,n):t==="null_"?this._decodeNull(r,n):t==="bool"?this._decodeBool(r,n):t==="objDesc"?this._decodeStr(r,t,n):t==="int"||t==="enum"?this._decodeInt(r,i.args&&i.args[0],n):i.use!==null?this._getUse(i.use,r._reporterState.obj)._decode(r,n):r.error("unknown tag: "+t)};Ut.prototype._getUse=function(t,r){var n=this._baseState;return n.useDecoder=this._use(t,r),En(n.useDecoder._baseState.parent===null),n.useDecoder=n.useDecoder._baseState.children[0],n.implicit!==n.useDecoder._baseState.implicit&&(n.useDecoder=n.useDecoder.clone(),n.useDecoder._baseState.implicit=n.implicit),n.useDecoder};Ut.prototype._decodeChoice=function(t,r){var n=this._baseState,i=null,s=!1;return Object.keys(n.choice).some(function(o){var a=t.save(),A=n.choice[o];try{var f=A._decode(t,r);if(t.isError(f))return!1;i={type:o,value:f},s=!0}catch{return t.restore(a),!1}return!0},this),s?i:t.error("Choice not matched")};Ut.prototype._createEncoderBuffer=function(t){return new $0e(t,this.reporter)};Ut.prototype._encode=function(t,r,n){var i=this._baseState;if(!(i.default!==null&&i.default===t)){var s=this._encodeValue(t,r,n);if(s!==void 0&&!this._skipDefault(s,r,n))return s}};Ut.prototype._encodeValue=function(t,r,n){var i=this._baseState;if(i.parent===null)return i.children[0]._encode(t,r||new Z0e);var A=null;if(this.reporter=r,i.optional&&t===void 0)if(i.default!==null)t=i.default;else return;var s=null,o=!1;if(i.any)A=this._createEncoderBuffer(t);else if(i.choice)A=this._encodeChoice(t,r);else if(i.contains)s=this._getUse(i.contains,n)._encode(t,r),o=!0;else if(i.children)s=i.children.map(function(p){if(p._baseState.tag==="null_")return p._encode(null,r,t);if(p._baseState.key===null)return r.error("Child should have a key");var I=r.enterKey(p._baseState.key);if(typeof t!="object")return r.error("Child expected, but input is not object");var S=p._encode(t[p._baseState.key],r,t);return r.leaveKey(I),S},this).filter(function(p){return p}),s=this._createEncoderBuffer(s);else if(i.tag==="seqof"||i.tag==="setof"){if(!(i.args&&i.args.length===1))return r.error("Too many args for : "+i.tag);if(!Array.isArray(t))return r.error("seqof/setof, but data is not Array");var a=this.clone();a._baseState.implicit=null,s=this._createEncoderBuffer(t.map(function(p){var I=this._baseState;return this._getUse(I.args[0],t)._encode(p,r)},a))}else i.use!==null?A=this._getUse(i.use,n)._encode(t,r):(s=this._encodePrimitive(i.tag,t),o=!0);var A;if(!i.any&&i.choice===null){var f=i.implicit!==null?i.implicit:i.tag,l=i.implicit===null?"universal":"context";f===null?i.use===null&&r.error("Tag could be omitted only for .use()"):i.use===null&&(A=this._encodeComposite(f,o,l,s))}return i.explicit!==null&&(A=this._encodeComposite(i.explicit,!1,"context",A)),A};Ut.prototype._encodeChoice=function(t,r){var n=this._baseState,i=n.choice[t.type];return i||En(!1,t.type+" not found in "+JSON.stringify(Object.keys(n.choice))),i._encode(t.value,r)};Ut.prototype._encodePrimitive=function(t,r){var n=this._baseState;if(/str$/.test(t))return this._encodeStr(r,t);if(t==="objid"&&n.args)return this._encodeObjid(r,n.reverseArgs[0],n.args[1]);if(t==="objid")return this._encodeObjid(r,null,null);if(t==="gentime"||t==="utctime")return this._encodeTime(r,t);if(t==="null_")return this._encodeNull();if(t==="int"||t==="enum")return this._encodeInt(r,n.args&&n.reverseArgs[0]);if(t==="bool")return this._encodeBool(r);if(t==="objDesc")return this._encodeStr(r,t);throw new Error("Unsupported tag: "+t)};Ut.prototype._isNumstr=function(t){return/^[0-9 ]*$/.test(t)};Ut.prototype._isPrintstr=function(t){return/^[A-Za-z0-9 '\(\)\+,\-\.\/:=\?]*$/.test(t)}});var tl=U(FP=>{var Oy=FP;Oy.Reporter=DP().Reporter;Oy.DecoderBuffer=KS().DecoderBuffer;Oy.EncoderBuffer=KS().EncoderBuffer;Oy.Node=MP()});var UP=U(Pf=>{var kP=XS();Pf.tagClass={0:"universal",1:"application",2:"context",3:"private"};Pf.tagClassByName=kP._reverse(Pf.tagClass);Pf.tag={0:"end",1:"bool",2:"int",3:"bitstr",4:"octstr",5:"null_",6:"objid",7:"objDesc",8:"external",9:"real",10:"enum",11:"embed",12:"utf8str",13:"relativeOid",16:"seq",17:"set",18:"numstr",19:"printstr",20:"t61str",21:"videostr",22:"ia5str",23:"utctime",24:"gentime",25:"graphstr",26:"iso646str",27:"genstr",28:"unistr",29:"charstr",30:"bmpstr"};Pf.tagByName=kP._reverse(Pf.tag)});var XS=U(LP=>{var xP=LP;xP._reverse=function(t){var r={};return Object.keys(t).forEach(function(n){(n|0)==n&&(n=n|0);var i=t[n];r[i]=n}),r};xP.der=UP()});var e_=U((LMe,qP)=>{var ipe=je(),ZS=$c(),Hy=ZS.base,spe=ZS.bignum,PP=ZS.constants.der;function OP(e){this.enc="der",this.name=e.name,this.entity=e,this.tree=new Xn,this.tree._init(e.body)}qP.exports=OP;OP.prototype.decode=function(t,r){return t instanceof Hy.DecoderBuffer||(t=new Hy.DecoderBuffer(t,r)),this.tree._decode(t,r)};function Xn(e){Hy.Node.call(this,"der",e)}ipe(Xn,Hy.Node);Xn.prototype._peekTag=function(t,r,n){if(t.isEmpty())return!1;var i=t.save(),s=$S(t,'Failed to peek tag: "'+r+'"');return t.isError(s)?s:(t.restore(i),s.tag===r||s.tagStr===r||s.tagStr+"of"===r||n)};Xn.prototype._decodeTag=function(t,r,n){var i=$S(t,'Failed to decode tag of "'+r+'"');if(t.isError(i))return i;var s=HP(t,i.primitive,'Failed to get length of "'+r+'"');if(t.isError(s))return s;if(!n&&i.tag!==r&&i.tagStr!==r&&i.tagStr+"of"!==r)return t.error('Failed to match tag: "'+r+'"');if(i.primitive||s!==null)return t.skip(s,'Failed to match body of: "'+r+'"');var o=t.save(),a=this._skipUntilEnd(t,'Failed to skip indefinite length body: "'+this.tag+'"');return t.isError(a)?a:(s=t.offset-o.offset,t.restore(o),t.skip(s,'Failed to match body of: "'+r+'"'))};Xn.prototype._skipUntilEnd=function(t,r){for(;;){var n=$S(t,r);if(t.isError(n))return n;var i=HP(t,n.primitive,r);if(t.isError(i))return i;var s;if(n.primitive||i!==null?s=t.skip(i):s=this._skipUntilEnd(t,r),t.isError(s))return s;if(n.tagStr==="end")break}};Xn.prototype._decodeList=function(t,r,n,i){for(var s=[];!t.isEmpty();){var o=this._peekTag(t,"end");if(t.isError(o))return o;var a=n.decode(t,"der",i);if(t.isError(a)&&o)break;s.push(a)}return s};Xn.prototype._decodeStr=function(t,r){if(r==="bitstr"){var n=t.readUInt8();return t.isError(n)?n:{unused:n,data:t.raw()}}else if(r==="bmpstr"){var i=t.raw();if(i.length%2===1)return t.error("Decoding of string type: bmpstr length mismatch");for(var s="",o=0;o>6],i=(r&32)===0;if((r&31)===31){var s=r;for(r=0;(s&128)===128;){if(s=e.readUInt8(t),e.isError(s))return s;r<<=7,r|=s&127}}else r&=31;var o=PP.tag[r];return{cls:n,primitive:i,tag:r,tagStr:o}}function HP(e,t,r){var n=e.readUInt8(r);if(e.isError(n))return n;if(!t&&n===128)return null;if((n&128)===0)return n;var i=n&127;if(i>4)return e.error("length octect is too long");n=0;for(var s=0;s{var ope=je(),ape=Gr().Buffer,t_=e_();function r_(e){t_.call(this,e),this.enc="pem"}ope(r_,t_);GP.exports=r_;r_.prototype.decode=function(t,r){for(var n=t.toString().split(/[\r\n]+/g),i=r.label.toUpperCase(),s=/^-----(BEGIN|END) ([^-]+)-----$/,o=-1,a=-1,A=0;A{var WP=VP;WP.der=e_();WP.pem=YP()});var i_=U((HMe,XP)=>{var Ape=je(),ua=Gr().Buffer,jP=$c(),zP=jP.base,n_=jP.constants.der;function KP(e){this.enc="der",this.name=e.name,this.entity=e,this.tree=new ds,this.tree._init(e.body)}XP.exports=KP;KP.prototype.encode=function(t,r){return this.tree._encode(t,r).join()};function ds(e){zP.Node.call(this,"der",e)}Ape(ds,zP.Node);ds.prototype._encodeComposite=function(t,r,n,i){var s=fpe(t,r,n,this.reporter);if(i.length<128){var A=new ua(2);return A[0]=s,A[1]=i.length,this._createEncoderBuffer([A,i])}for(var o=1,a=i.length;a>=256;a>>=8)o++;var A=new ua(2+o);A[0]=s,A[1]=128|o;for(var a=1+o,f=i.length;f>0;a--,f>>=8)A[a]=f&255;return this._createEncoderBuffer([A,i])};ds.prototype._encodeStr=function(t,r){if(r==="bitstr")return this._createEncoderBuffer([t.unused|0,t.data]);if(r==="bmpstr"){for(var n=new ua(t.length*2),i=0;i=40)return this.reporter.error("Second objid identifier OOB");t.splice(0,2,t[0]*40+t[1])}for(var s=0,i=0;i=128;o>>=7)s++}for(var a=new ua(s),A=a.length-1,i=t.length-1;i>=0;i--){var o=t[i];for(a[A--]=o&127;(o>>=7)>0;)a[A--]=128|o&127}return this._createEncoderBuffer(a)};function Ri(e){return e<10?"0"+e:e}ds.prototype._encodeTime=function(t,r){var n,i=new Date(t);return r==="gentime"?n=[Ri(i.getFullYear()),Ri(i.getUTCMonth()+1),Ri(i.getUTCDate()),Ri(i.getUTCHours()),Ri(i.getUTCMinutes()),Ri(i.getUTCSeconds()),"Z"].join(""):r==="utctime"?n=[Ri(i.getFullYear()%100),Ri(i.getUTCMonth()+1),Ri(i.getUTCDate()),Ri(i.getUTCHours()),Ri(i.getUTCMinutes()),Ri(i.getUTCSeconds()),"Z"].join(""):this.reporter.error("Encoding "+r+" time is not supported yet"),this._encodeStr(n,"octstr")};ds.prototype._encodeNull=function(){return this._createEncoderBuffer("")};ds.prototype._encodeInt=function(t,r){if(typeof t=="string"){if(!r)return this.reporter.error("String int or enum given, but no values map");if(!r.hasOwnProperty(t))return this.reporter.error("Values map doesn't contain: "+JSON.stringify(t));t=r[t]}if(typeof t!="number"&&!ua.isBuffer(t)){var n=t.toArray();!t.sign&&n[0]&128&&n.unshift(0),t=new ua(n)}if(ua.isBuffer(t)){var i=t.length;t.length===0&&i++;var o=new ua(i);return t.copy(o),t.length===0&&(o[0]=0),this._createEncoderBuffer(o)}if(t<128)return this._createEncoderBuffer(t);if(t<256)return this._createEncoderBuffer([0,t]);for(var i=1,s=t;s>=256;s>>=8)i++;for(var o=new Array(i),s=o.length-1;s>=0;s--)o[s]=t&255,t>>=8;return o[0]&128&&o.unshift(0),this._createEncoderBuffer(new ua(o))};ds.prototype._encodeBool=function(t){return this._createEncoderBuffer(t?255:0)};ds.prototype._use=function(t,r){return typeof t=="function"&&(t=t(r)),t._getEncoder("der").tree};ds.prototype._skipDefault=function(t,r,n){var i=this._baseState,s;if(i.default===null)return!1;var o=t.join();if(i.defaultBuffer===void 0&&(i.defaultBuffer=this._encodeValue(i.default,r,n).join()),o.length!==i.defaultBuffer.length)return!1;for(s=0;s=31?n.error("Multi-octet tag encoding unsupported"):(t||(i|=32),i|=n_.tagClassByName[r||"universal"]<<6,i)}});var $P=U((qMe,ZP)=>{var upe=je(),s_=i_();function o_(e){s_.call(this,e),this.enc="pem"}upe(o_,s_);ZP.exports=o_;o_.prototype.encode=function(t,r){for(var n=s_.prototype.encode.call(this,t),i=n.toString("base64"),s=["-----BEGIN "+r.label+"-----"],o=0;o{var eO=tO;eO.der=i_();eO.pem=$P()});var $c=U(nO=>{var rl=nO;rl.bignum=kr();rl.define=vP().define;rl.base=tl();rl.constants=XS();rl.decoders=JP();rl.encoders=rO()});var aO=U((WMe,oO)=>{"use strict";var gs=$c(),iO=gs.define("Time",function(){this.choice({utcTime:this.utctime(),generalTime:this.gentime()})}),cpe=gs.define("AttributeTypeValue",function(){this.seq().obj(this.key("type").objid(),this.key("value").any())}),a_=gs.define("AlgorithmIdentifier",function(){this.seq().obj(this.key("algorithm").objid(),this.key("parameters").optional(),this.key("curve").objid().optional())}),lpe=gs.define("SubjectPublicKeyInfo",function(){this.seq().obj(this.key("algorithm").use(a_),this.key("subjectPublicKey").bitstr())}),hpe=gs.define("RelativeDistinguishedName",function(){this.setof(cpe)}),dpe=gs.define("RDNSequence",function(){this.seqof(hpe)}),sO=gs.define("Name",function(){this.choice({rdnSequence:this.use(dpe)})}),gpe=gs.define("Validity",function(){this.seq().obj(this.key("notBefore").use(iO),this.key("notAfter").use(iO))}),ppe=gs.define("Extension",function(){this.seq().obj(this.key("extnID").objid(),this.key("critical").bool().def(!1),this.key("extnValue").octstr())}),Epe=gs.define("TBSCertificate",function(){this.seq().obj(this.key("version").explicit(0).int().optional(),this.key("serialNumber").int(),this.key("signature").use(a_),this.key("issuer").use(sO),this.key("validity").use(gpe),this.key("subject").use(sO),this.key("subjectPublicKeyInfo").use(lpe),this.key("issuerUniqueID").implicit(1).bitstr().optional(),this.key("subjectUniqueID").implicit(2).bitstr().optional(),this.key("extensions").explicit(3).seqof(ppe).optional())}),ype=gs.define("X509Certificate",function(){this.seq().obj(this.key("tbsCertificate").use(Epe),this.key("signatureAlgorithm").use(a_),this.key("signatureValue").bitstr())});oO.exports=ype});var fO=U(Es=>{"use strict";var ps=$c();Es.certificate=aO();var mpe=ps.define("RSAPrivateKey",function(){this.seq().obj(this.key("version").int(),this.key("modulus").int(),this.key("publicExponent").int(),this.key("privateExponent").int(),this.key("prime1").int(),this.key("prime2").int(),this.key("exponent1").int(),this.key("exponent2").int(),this.key("coefficient").int())});Es.RSAPrivateKey=mpe;var Bpe=ps.define("RSAPublicKey",function(){this.seq().obj(this.key("modulus").int(),this.key("publicExponent").int())});Es.RSAPublicKey=Bpe;var AO=ps.define("AlgorithmIdentifier",function(){this.seq().obj(this.key("algorithm").objid(),this.key("none").null_().optional(),this.key("curve").objid().optional(),this.key("params").seq().obj(this.key("p").int(),this.key("q").int(),this.key("g").int()).optional())}),Ipe=ps.define("SubjectPublicKeyInfo",function(){this.seq().obj(this.key("algorithm").use(AO),this.key("subjectPublicKey").bitstr())});Es.PublicKey=Ipe;var bpe=ps.define("PrivateKeyInfo",function(){this.seq().obj(this.key("version").int(),this.key("algorithm").use(AO),this.key("subjectPrivateKey").octstr())});Es.PrivateKey=bpe;var Cpe=ps.define("EncryptedPrivateKeyInfo",function(){this.seq().obj(this.key("algorithm").seq().obj(this.key("id").objid(),this.key("decrypt").seq().obj(this.key("kde").seq().obj(this.key("id").objid(),this.key("kdeparams").seq().obj(this.key("salt").octstr(),this.key("iters").int())),this.key("cipher").seq().obj(this.key("algo").objid(),this.key("iv").octstr()))),this.key("subjectPrivateKey").octstr())});Es.EncryptedPrivateKey=Cpe;var Qpe=ps.define("DSAPrivateKey",function(){this.seq().obj(this.key("version").int(),this.key("p").int(),this.key("q").int(),this.key("g").int(),this.key("pub_key").int(),this.key("priv_key").int())});Es.DSAPrivateKey=Qpe;Es.DSAparam=ps.define("DSAparam",function(){this.int()});var wpe=ps.define("ECParameters",function(){this.choice({namedCurve:this.objid()})}),Spe=ps.define("ECPrivateKey",function(){this.seq().obj(this.key("version").int(),this.key("privateKey").octstr(),this.key("parameters").optional().explicit(0).use(wpe),this.key("publicKey").optional().explicit(1).bitstr())});Es.ECPrivateKey=Spe;Es.signature=ps.define("signature",function(){this.seq().obj(this.key("r").int(),this.key("s").int())})});var uO=U((JMe,_pe)=>{_pe.exports={"2.16.840.1.101.3.4.1.1":"aes-128-ecb","2.16.840.1.101.3.4.1.2":"aes-128-cbc","2.16.840.1.101.3.4.1.3":"aes-128-ofb","2.16.840.1.101.3.4.1.4":"aes-128-cfb","2.16.840.1.101.3.4.1.21":"aes-192-ecb","2.16.840.1.101.3.4.1.22":"aes-192-cbc","2.16.840.1.101.3.4.1.23":"aes-192-ofb","2.16.840.1.101.3.4.1.24":"aes-192-cfb","2.16.840.1.101.3.4.1.41":"aes-256-ecb","2.16.840.1.101.3.4.1.42":"aes-256-cbc","2.16.840.1.101.3.4.1.43":"aes-256-ofb","2.16.840.1.101.3.4.1.44":"aes-256-cfb"}});var lO=U((jMe,cO)=>{"use strict";var vpe=/Proc-Type: 4,ENCRYPTED[\n\r]+DEK-Info: AES-((?:128)|(?:192)|(?:256))-CBC,([0-9A-H]+)[\n\r]+([0-9A-z\n\r+/=]+)[\n\r]+/m,Rpe=/^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----/m,Dpe=/^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----([0-9A-z\n\r+/=]+)-----END \1-----$/m,Tpe=Rd(),Npe=gy(),qy=at().Buffer;cO.exports=function(e,t){var r=e.toString(),n=r.match(vpe),i;if(n){var o="aes"+n[1],a=qy.from(n[2],"hex"),A=qy.from(n[3].replace(/[\r\n]/g,""),"base64"),f=Tpe(t,a.slice(0,8),parseInt(n[1],10)).key,l=[],p=Npe.createDecipheriv(o,f,a);l.push(p.update(A)),l.push(p.final()),i=qy.concat(l)}else{var s=r.match(Dpe);i=qy.from(s[2].replace(/[\r\n]/g,""),"base64")}var I=r.match(Rpe)[1];return{tag:I,data:i}}});var Pd=U((zMe,dO)=>{"use strict";var kn=fO(),Mpe=uO(),Fpe=lO(),kpe=gy(),Upe=Xw().pbkdf2Sync,A_=at().Buffer;function xpe(e,t){var r=e.algorithm.decrypt.kde.kdeparams.salt,n=parseInt(e.algorithm.decrypt.kde.kdeparams.iters.toString(),10),i=Mpe[e.algorithm.decrypt.cipher.algo.join(".")],s=e.algorithm.decrypt.cipher.iv,o=e.subjectPrivateKey,a=parseInt(i.split("-")[1],10)/8,A=Upe(t,r,n,a,"sha1"),f=kpe.createDecipheriv(i,A,s),l=[];return l.push(f.update(o)),l.push(f.final()),A_.concat(l)}function hO(e){var t;typeof e=="object"&&!A_.isBuffer(e)&&(t=e.passphrase,e=e.key),typeof e=="string"&&(e=A_.from(e));var r=Fpe(e,t),n=r.tag,i=r.data,s,o;switch(n){case"CERTIFICATE":o=kn.certificate.decode(i,"der").tbsCertificate.subjectPublicKeyInfo;case"PUBLIC KEY":switch(o||(o=kn.PublicKey.decode(i,"der")),s=o.algorithm.algorithm.join("."),s){case"1.2.840.113549.1.1.1":return kn.RSAPublicKey.decode(o.subjectPublicKey.data,"der");case"1.2.840.10045.2.1":return o.subjectPrivateKey=o.subjectPublicKey,{type:"ec",data:o};case"1.2.840.10040.4.1":return o.algorithm.params.pub_key=kn.DSAparam.decode(o.subjectPublicKey.data,"der"),{type:"dsa",data:o.algorithm.params};default:throw new Error("unknown key id "+s)}case"ENCRYPTED PRIVATE KEY":i=kn.EncryptedPrivateKey.decode(i,"der"),i=xpe(i,t);case"PRIVATE KEY":switch(o=kn.PrivateKey.decode(i,"der"),s=o.algorithm.algorithm.join("."),s){case"1.2.840.113549.1.1.1":return kn.RSAPrivateKey.decode(o.subjectPrivateKey,"der");case"1.2.840.10045.2.1":return{curve:o.algorithm.curve,privateKey:kn.ECPrivateKey.decode(o.subjectPrivateKey,"der").privateKey};case"1.2.840.10040.4.1":return o.algorithm.params.priv_key=kn.DSAparam.decode(o.subjectPrivateKey,"der"),{type:"dsa",params:o.algorithm.params};default:throw new Error("unknown key id "+s)}case"RSA PUBLIC KEY":return kn.RSAPublicKey.decode(i,"der");case"RSA PRIVATE KEY":return kn.RSAPrivateKey.decode(i,"der");case"DSA PRIVATE KEY":return{type:"dsa",params:kn.DSAPrivateKey.decode(i,"der")};case"EC PRIVATE KEY":return i=kn.ECPrivateKey.decode(i,"der"),{curve:i.parameters.value,privateKey:i.privateKey};default:throw new Error("unknown key type "+n)}}hO.signature=kn.signature;dO.exports=hO});var f_=U((KMe,Lpe)=>{Lpe.exports={"1.3.132.0.10":"secp256k1","1.3.132.0.33":"p224","1.2.840.10045.3.1.1":"p192","1.2.840.10045.3.1.7":"p256","1.3.132.0.34":"p384","1.3.132.0.35":"p521"}});var EO=U((XMe,Yy)=>{"use strict";var fn=at().Buffer,Of=qw(),Ppe=By(),Ope=xy().ec,Gy=my(),Hpe=Pd(),qpe=f_(),Gpe=1;function Ype(e,t,r,n,i){var s=Hpe(t);if(s.curve){if(n!=="ecdsa"&&n!=="ecdsa/rsa")throw new Error("wrong private key type");return Wpe(e,s)}else if(s.type==="dsa"){if(n!=="dsa")throw new Error("wrong private key type");return Vpe(e,s,r)}if(n!=="rsa"&&n!=="ecdsa/rsa")throw new Error("wrong private key type");if(t.padding!==void 0&&t.padding!==Gpe)throw new Error("illegal or unsupported padding mode");e=fn.concat([i,e]);for(var o=s.modulus.byteLength(),a=[0,1];e.length+a.length+10&&r.ishrn(n),r}function jpe(e,t){e=u_(e,t),e=e.mod(t);var r=fn.from(e.toArray());if(r.length{"use strict";var c_=at().Buffer,Od=my(),Kpe=xy().ec,mO=Pd(),Xpe=f_();function Zpe(e,t,r,n,i){var s=mO(r);if(s.type==="ec"){if(n!=="ecdsa"&&n!=="ecdsa/rsa")throw new Error("wrong public key type");return $pe(e,t,s)}else if(s.type==="dsa"){if(n!=="dsa")throw new Error("wrong public key type");return eEe(e,t,s)}if(n!=="rsa"&&n!=="ecdsa/rsa")throw new Error("wrong public key type");t=c_.concat([i,t]);for(var o=s.modulus.byteLength(),a=[1],A=0;t.length+a.length+2=0)throw new Error("invalid sig")}BO.exports=Zpe});var _O=U(($Me,SO)=>{"use strict";var Wy=at().Buffer,QO=Mc(),Vy=Fw(),wO=je(),tEe=EO(),rEe=IO(),Hf=Gw();Object.keys(Hf).forEach(function(e){Hf[e].id=Wy.from(Hf[e].id,"hex"),Hf[e.toLowerCase()]=Hf[e]});function Hd(e){Vy.Writable.call(this);var t=Hf[e];if(!t)throw new Error("Unknown message digest");this._hashType=t.hash,this._hash=QO(t.hash),this._tag=t.id,this._signType=t.sign}wO(Hd,Vy.Writable);Hd.prototype._write=function(t,r,n){this._hash.update(t),n()};Hd.prototype.update=function(t,r){return this._hash.update(typeof t=="string"?Wy.from(t,r):t),this};Hd.prototype.sign=function(t,r){this.end();var n=this._hash.digest(),i=tEe(n,t,this._hashType,this._signType,this._tag);return r?i.toString(r):i};function qd(e){Vy.Writable.call(this);var t=Hf[e];if(!t)throw new Error("Unknown message digest");this._hash=QO(t.hash),this._tag=t.id,this._signType=t.sign}wO(qd,Vy.Writable);qd.prototype._write=function(t,r,n){this._hash.update(t),n()};qd.prototype.update=function(t,r){return this._hash.update(typeof t=="string"?Wy.from(t,r):t),this};qd.prototype.verify=function(t,r,n){var i=typeof r=="string"?Wy.from(r,n):r;this.end();var s=this._hash.digest();return rEe(i,s,t,this._signType,this._tag)};function bO(e){return new Hd(e)}function CO(e){return new qd(e)}SO.exports={Sign:bO,Verify:CO,createSign:bO,createVerify:CO}});var RO=U((eFe,vO)=>{var nEe=xy(),iEe=kr();vO.exports=function(t){return new qf(t)};var Zn={secp256k1:{name:"secp256k1",byteLength:32},secp224r1:{name:"p224",byteLength:28},prime256v1:{name:"p256",byteLength:32},prime192v1:{name:"p192",byteLength:24},ed25519:{name:"ed25519",byteLength:32},secp384r1:{name:"p384",byteLength:48},secp521r1:{name:"p521",byteLength:66}};Zn.p224=Zn.secp224r1;Zn.p256=Zn.secp256r1=Zn.prime256v1;Zn.p192=Zn.secp192r1=Zn.prime192v1;Zn.p384=Zn.secp384r1;Zn.p521=Zn.secp521r1;function qf(e){this.curveType=Zn[e],this.curveType||(this.curveType={name:e}),this.curve=new nEe.ec(this.curveType.name),this.keys=void 0}qf.prototype.generateKeys=function(e,t){return this.keys=this.curve.genKeyPair(),this.getPublicKey(e,t)};qf.prototype.computeSecret=function(e,t,r){t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t));var n=this.curve.keyFromPublic(e).getPublic(),i=n.mul(this.keys.getPrivate()).getX();return l_(i,r,this.curveType.byteLength)};qf.prototype.getPublicKey=function(e,t){var r=this.keys.getPublic(t==="compressed",!0);return t==="hybrid"&&(r[r.length-1]%2?r[0]=7:r[0]=6),l_(r,e)};qf.prototype.getPrivateKey=function(e){return l_(this.keys.getPrivate(),e)};qf.prototype.setPublicKey=function(e,t){return t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t)),this.keys._importPublic(e),this};qf.prototype.setPrivateKey=function(e,t){t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t));var r=new iEe(e);return r=r.toString(16),this.keys=this.curve.genKeyPair(),this.keys._importPrivate(r),this};function l_(e,t,r){Array.isArray(e)||(e=e.toArray());var n=new Buffer(e);if(r&&n.length{var sEe=Mc(),h_=at().Buffer;DO.exports=function(e,t){for(var r=h_.alloc(0),n=0,i;r.length{TO.exports=function(t,r){for(var n=t.length,i=-1;++i{var NO=kr(),aEe=at().Buffer;function AEe(e,t){return aEe.from(e.toRed(NO.mont(t.modulus)).redPow(new NO(t.publicExponent)).fromRed().toArray())}MO.exports=AEe});var xO=U((iFe,UO)=>{var fEe=Pd(),E_=mf(),uEe=Mc(),FO=d_(),kO=g_(),y_=kr(),cEe=p_(),lEe=By(),ys=at().Buffer;UO.exports=function(t,r,n){var i;t.padding?i=t.padding:n?i=1:i=4;var s=fEe(t),o;if(i===4)o=hEe(s,r);else if(i===1)o=dEe(s,r,n);else if(i===3){if(o=new y_(r),o.cmp(s.modulus)>=0)throw new Error("data too long for modulus")}else throw new Error("unknown padding");return n?lEe(o,s):cEe(o,s)};function hEe(e,t){var r=e.modulus.byteLength(),n=t.length,i=uEe("sha1").update(ys.alloc(0)).digest(),s=i.length,o=2*s;if(n>r-o-2)throw new Error("message too long");var a=ys.alloc(r-n-o-2),A=r-s-1,f=E_(s),l=kO(ys.concat([i,a,ys.alloc(1,1),t],A),FO(f,A)),p=kO(f,FO(l,s));return new y_(ys.concat([ys.alloc(1),p,l],r))}function dEe(e,t,r){var n=t.length,i=e.modulus.byteLength();if(n>i-11)throw new Error("message too long");var s;return r?s=ys.alloc(i-n-3,255):s=gEe(i-n-3),new y_(ys.concat([ys.from([0,r?1:2]),s,ys.alloc(1),t],i))}function gEe(e){for(var t=ys.allocUnsafe(e),r=0,n=E_(e*2),i=0,s;r{var pEe=Pd(),LO=d_(),PO=g_(),OO=kr(),EEe=By(),yEe=Mc(),mEe=p_(),Gd=at().Buffer;HO.exports=function(t,r,n){var i;t.padding?i=t.padding:n?i=1:i=4;var s=pEe(t),o=s.modulus.byteLength();if(r.length>o||new OO(r).cmp(s.modulus)>=0)throw new Error("decryption error");var a;n?a=mEe(new OO(r),s):a=EEe(r,s);var A=Gd.alloc(o-a.length);if(a=Gd.concat([A,a],o),i===4)return BEe(s,a);if(i===1)return IEe(s,a,n);if(i===3)return a;throw new Error("unknown padding")};function BEe(e,t){var r=e.modulus.byteLength(),n=yEe("sha1").update(Gd.alloc(0)).digest(),i=n.length;if(t[0]!==0)throw new Error("decryption error");var s=t.slice(1,i+1),o=t.slice(i+1),a=PO(s,LO(o,i)),A=PO(o,LO(a,r-i-1));if(bEe(n,A.slice(0,i)))throw new Error("decryption error");for(var f=i;A[f]===0;)f++;if(A[f++]!==1)throw new Error("decryption error");return A.slice(f)}function IEe(e,t,r){for(var n=t.slice(0,2),i=2,s=0;t[i++]!==0;)if(i>=t.length){s++;break}var o=t.slice(2,i-1);if((n.toString("hex")!=="0002"&&!r||n.toString("hex")!=="0001"&&r)&&s++,o.length<8&&s++,s)throw new Error("decryption error");return t.slice(i)}function bEe(e,t){e=Gd.from(e),t=Gd.from(t);var r=0,n=e.length;e.length!==t.length&&(r++,n=Math.min(e.length,t.length));for(var i=-1;++i{Gf.publicEncrypt=xO();Gf.privateDecrypt=qO();Gf.privateEncrypt=function(t,r){return Gf.publicEncrypt(t,r,!0)};Gf.publicDecrypt=function(t,r){return Gf.privateDecrypt(t,r,!0)}});var $O=U(Yd=>{"use strict";function YO(){throw new Error(`secure random number generation not supported by this browser -use chrome, FireFox or Internet Explorer 11`)}var VO=at(),WO=mf(),JO=VO.Buffer,jO=VO.kMaxLength,m_=globalThis.crypto||globalThis.msCrypto,zO=Math.pow(2,32)-1;function KO(e,t){if(typeof e!="number"||e!==e)throw new TypeError("offset must be a number");if(e>zO||e<0)throw new TypeError("offset must be a uint32");if(e>jO||e>t)throw new RangeError("offset out of range")}function XO(e,t,r){if(typeof e!="number"||e!==e)throw new TypeError("size must be a number");if(e>zO||e<0)throw new TypeError("size must be a uint32");if(e+t>r||e>jO)throw new RangeError("buffer too small")}m_&&m_.getRandomValues||!process.browser?(Yd.randomFill=CEe,Yd.randomFillSync=QEe):(Yd.randomFill=YO,Yd.randomFillSync=YO);function CEe(e,t,r,n){if(!JO.isBuffer(e)&&!(e instanceof globalThis.Uint8Array))throw new TypeError('"buf" argument must be a Buffer or Uint8Array');if(typeof t=="function")n=t,t=0,r=e.length;else if(typeof r=="function")n=r,r=e.length-t;else if(typeof n!="function")throw new TypeError('"cb" argument must be a function');return KO(t,e.length),XO(r,t,e.length),ZO(e,t,r,n)}function ZO(e,t,r,n){if(process.browser){var i=e.buffer,s=new Uint8Array(i,t,r);if(m_.getRandomValues(s),n){process.nextTick(function(){n(null,e)});return}return e}if(n){WO(r,function(a,A){if(a)return n(a);A.copy(e,t),n(null,e)});return}var o=WO(r);return o.copy(e,t),e}function QEe(e,t,r){if(typeof t>"u"&&(t=0),!JO.isBuffer(e)&&!(e instanceof globalThis.Uint8Array))throw new TypeError('"buf" argument must be a Buffer or Uint8Array');return KO(t,e.length),r===void 0&&(r=e.length-t),XO(r,t,e.length),ZO(e,t,r)}});var Nd=U(ut=>{"use strict";ut.randomBytes=ut.rng=ut.pseudoRandomBytes=ut.prng=mf();ut.createHash=ut.Hash=Mc();ut.createHmac=ut.Hmac=qw();var wEe=d8(),SEe=Object.keys(wEe),_Ee=["sha1","sha224","sha256","sha384","sha512","md5","rmd160"].concat(SEe);ut.getHashes=function(){return _Ee};var eH=Xw();ut.pbkdf2=eH.pbkdf2;ut.pbkdf2Sync=eH.pbkdf2Sync;var co=L5();ut.Cipher=co.Cipher;ut.createCipher=co.createCipher;ut.Cipheriv=co.Cipheriv;ut.createCipheriv=co.createCipheriv;ut.Decipher=co.Decipher;ut.createDecipher=co.createDecipher;ut.Decipheriv=co.Decipheriv;ut.createDecipheriv=co.createDecipheriv;ut.getCiphers=co.getCiphers;ut.listCiphers=co.listCiphers;var Wd=X5();ut.DiffieHellmanGroup=Wd.DiffieHellmanGroup;ut.createDiffieHellmanGroup=Wd.createDiffieHellmanGroup;ut.getDiffieHellman=Wd.getDiffieHellman;ut.createDiffieHellman=Wd.createDiffieHellman;ut.DiffieHellman=Wd.DiffieHellman;var Jy=_O();ut.createSign=Jy.createSign;ut.Sign=Jy.Sign;ut.createVerify=Jy.createVerify;ut.Verify=Jy.Verify;ut.createECDH=RO();var jy=GO();ut.publicEncrypt=jy.publicEncrypt;ut.privateEncrypt=jy.privateEncrypt;ut.publicDecrypt=jy.publicDecrypt;ut.privateDecrypt=jy.privateDecrypt;var tH=$O();ut.randomFill=tH.randomFill;ut.randomFillSync=tH.randomFillSync;ut.createCredentials=function(){throw new Error(`sorry, createCredentials is not implemented yet -we accept pull requests -https://github.com/browserify/crypto-browserify`)};ut.constants={DH_CHECK_P_NOT_SAFE_PRIME:2,DH_CHECK_P_NOT_PRIME:1,DH_UNABLE_TO_CHECK_GENERATOR:4,DH_NOT_SUITABLE_GENERATOR:8,NPN_ENABLED:1,ALPN_ENABLED:1,RSA_PKCS1_PADDING:1,RSA_SSLV23_PADDING:2,RSA_NO_PADDING:3,RSA_PKCS1_OAEP_PADDING:4,RSA_X931_PADDING:5,RSA_PKCS1_PSS_PADDING:6,POINT_CONVERSION_COMPRESSED:2,POINT_CONVERSION_UNCOMPRESSED:4,POINT_CONVERSION_HYBRID:6}});var nH=U(()=>{"use strict";var rH=new Error("No such built-in module: node:sqlite");rH.code="ERR_UNKNOWN_BUILTIN_MODULE";throw rH});var B_=U((cFe,iH)=>{"use strict";iH.exports={isMainThread:!0,parentPort:null,workerData:null}});var C_=U((_,b_)=>{"use strict";var e=new Set(["crypto","sqlite","markAsUncloneable","zstd"]),t=new Map([["crypto",!0],["sqlite",!1],["markAsUncloneable",!1],["zstd",!1]]),r={clear(){t.clear()},has(n){if(!e.has(n))throw new TypeError(`unknown feature: ${n}`);return t.get(n)??!1},set(n,i){if(!e.has(n))throw new TypeError(`unknown feature: ${n}`);t.set(n,!!i)}};b_.exports.runtimeFeatures=r;b_.exports.default=r});var lo=U((dFe,cH)=>{"use strict";var MEe=Gt(),{types:ur,inspect:FEe}=Yr(),{runtimeFeatures:kEe}=C_(),Q_=1,w_=2,Ky=3,Xy=4,S_=5,Zy=6,__=7,$n=8,uH=Function.call.bind(Function.prototype[Symbol.hasInstance]),K={converters:{},util:{},errors:{},is:{}};K.errors.exception=function(e){return new TypeError(`${e.header}: ${e.message}`)};K.errors.conversionFailed=function(e){let t=e.types.length===1?"":" one of",r=`${e.argument} could not be converted to${t}: ${e.types.join(", ")}.`;return K.errors.exception({header:e.prefix,message:r})};K.errors.invalidArgument=function(e){return K.errors.exception({header:e.prefix,message:`"${e.value}" is an invalid ${e.type}.`})};K.brandCheck=function(e,t){if(!uH(t,e)){let r=new TypeError("Illegal invocation");throw r.code="ERR_INVALID_THIS",r}};K.brandCheckMultiple=function(e){let t=e.map(r=>K.util.MakeTypeAssertion(r));return r=>{if(t.every(n=>!n(r))){let n=new TypeError("Illegal invocation");throw n.code="ERR_INVALID_THIS",n}}};K.argumentLengthCheck=function({length:e},t,r){if(euH(e,t)};K.util.Type=function(e){switch(typeof e){case"undefined":return Q_;case"boolean":return w_;case"string":return Ky;case"symbol":return Xy;case"number":return S_;case"bigint":return Zy;case"function":case"object":return e===null?__:$n}};K.util.Types={UNDEFINED:Q_,BOOLEAN:w_,STRING:Ky,SYMBOL:Xy,NUMBER:S_,BIGINT:Zy,NULL:__,OBJECT:$n};K.util.TypeValueToString=function(e){switch(K.util.Type(e)){case Q_:return"Undefined";case w_:return"Boolean";case Ky:return"String";case Xy:return"Symbol";case S_:return"Number";case Zy:return"BigInt";case __:return"Null";case $n:return"Object"}};K.util.markAsUncloneable=kEe.has("markAsUncloneable")?B_().markAsUncloneable:()=>{};K.util.ConvertToInt=function(e,t,r,n){let i,s;t===64?(i=Math.pow(2,53)-1,r==="unsigned"?s=0:s=Math.pow(-2,53)+1):r==="unsigned"?(s=0,i=Math.pow(2,t)-1):(s=Math.pow(-2,t)-1,i=Math.pow(2,t-1)-1);let o=Number(e);if(o===0&&(o=0),K.util.HasFlag(n,K.attributes.EnforceRange)){if(Number.isNaN(o)||o===Number.POSITIVE_INFINITY||o===Number.NEGATIVE_INFINITY)throw K.errors.exception({header:"Integer conversion",message:`Could not convert ${K.util.Stringify(e)} to an integer.`});if(o=K.util.IntegerPart(o),oi)throw K.errors.exception({header:"Integer conversion",message:`Value must be between ${s}-${i}, got ${o}.`});return o}return!Number.isNaN(o)&&K.util.HasFlag(n,K.attributes.Clamp)?(o=Math.min(Math.max(o,s),i),Math.floor(o)%2===0?o=Math.floor(o):o=Math.ceil(o),o):Number.isNaN(o)||o===0&&Object.is(0,o)||o===Number.POSITIVE_INFINITY||o===Number.NEGATIVE_INFINITY?0:(o=K.util.IntegerPart(o),o=o%Math.pow(2,t),r==="signed"&&o>=Math.pow(2,t)-1?o-Math.pow(2,t):o)};K.util.IntegerPart=function(e){let t=Math.floor(Math.abs(e));return e<0?-1*t:t};K.util.Stringify=function(e){switch(K.util.Type(e)){case Xy:return`Symbol(${e.description})`;case $n:return FEe(e);case Ky:return`"${e}"`;case Zy:return`${e}n`;default:return`${e}`}};K.util.IsResizableArrayBuffer=function(e){if(ur.isArrayBuffer(e))return e.resizable;if(ur.isSharedArrayBuffer(e))return e.growable;throw K.errors.exception({header:"IsResizableArrayBuffer",message:`"${K.util.Stringify(e)}" is not an array buffer.`})};K.util.HasFlag=function(e,t){return typeof e=="number"&&(e&t)===t};K.sequenceConverter=function(e){return(t,r,n,i)=>{if(K.util.Type(t)!==$n)throw K.errors.exception({header:r,message:`${n} (${K.util.Stringify(t)}) is not iterable.`});let s=typeof i=="function"?i():t?.[Symbol.iterator]?.(),o=[],a=0;if(s===void 0||typeof s.next!="function")throw K.errors.exception({header:r,message:`${n} is not iterable.`});for(;;){let{done:A,value:f}=s.next();if(A)break;o.push(e(f,r,`${n}[${a++}]`))}return o}};K.recordConverter=function(e,t){return(r,n,i)=>{if(K.util.Type(r)!==$n)throw K.errors.exception({header:n,message:`${i} ("${K.util.TypeValueToString(r)}") is not an Object.`});let s={};if(!ur.isProxy(r)){let a=[...Object.getOwnPropertyNames(r),...Object.getOwnPropertySymbols(r)];for(let A of a){let f=K.util.Stringify(A),l=e(A,n,`Key ${f} in ${i}`),p=t(r[A],n,`${i}[${f}]`);s[l]=p}return s}let o=Reflect.ownKeys(r);for(let a of o)if(Reflect.getOwnPropertyDescriptor(r,a)?.enumerable){let f=e(a,n,i),l=t(r[a],n,i);s[f]=l}return s}};K.interfaceConverter=function(e,t){return(r,n,i)=>{if(!e(r))throw K.errors.exception({header:n,message:`Expected ${i} ("${K.util.Stringify(r)}") to be an instance of ${t}.`});return r}};K.dictionaryConverter=function(e){return e.sort((t,r)=>(t.key>r.key)-(t.key{let i={};if(t!=null&&K.util.Type(t)!==$n)throw K.errors.exception({header:r,message:`Expected ${t} to be one of: Null, Undefined, Object.`});for(let s of e){let{key:o,defaultValue:a,required:A,converter:f}=s;if(A===!0&&(t==null||!Object.hasOwn(t,o)))throw K.errors.exception({header:r,message:`Missing required key "${o}".`});let l=t?.[o],p=a!==void 0;if(p&&l===void 0&&(l=a()),A||p||l!==void 0){if(l=f(l,r,`${n}.${o}`),s.allowedValues&&!s.allowedValues.includes(l))throw K.errors.exception({header:r,message:`${l} is not an accepted type. Expected one of ${s.allowedValues.join(", ")}.`});i[o]=l}}return i}};K.nullableConverter=function(e){return(t,r,n)=>t===null?t:e(t,r,n)};K.is.USVString=function(e){return typeof e=="string"&&e.isWellFormed()};K.is.ReadableStream=K.util.MakeTypeAssertion(ReadableStream);K.is.Blob=K.util.MakeTypeAssertion(Blob);K.is.URLSearchParams=K.util.MakeTypeAssertion(URLSearchParams);K.is.File=K.util.MakeTypeAssertion(File);K.is.URL=K.util.MakeTypeAssertion(URL);K.is.AbortSignal=K.util.MakeTypeAssertion(AbortSignal);K.is.MessagePort=K.util.MakeTypeAssertion(MessagePort);K.is.BufferSource=function(e){return ur.isArrayBuffer(e)||ArrayBuffer.isView(e)&&ur.isArrayBuffer(e.buffer)};K.util.getCopyOfBytesHeldByBufferSource=function(e){let t=e,r=t,n=0,i=0;if(ur.isTypedArray(t)||ur.isDataView(t)?(r=t.buffer,n=t.byteOffset,i=t.byteLength):(MEe(ur.isAnyArrayBuffer(t)),i=t.byteLength),r.detached)return new Uint8Array(0);let s=new Uint8Array(i),o=new Uint8Array(r,n,i);return s.set(o),s};K.converters.DOMString=function(e,t,r,n){if(e===null&&K.util.HasFlag(n,K.attributes.LegacyNullToEmptyString))return"";if(typeof e=="symbol")throw K.errors.exception({header:t,message:`${r} is a symbol, which cannot be converted to a DOMString.`});return String(e)};K.converters.ByteString=function(e,t,r){if(typeof e=="symbol")throw K.errors.exception({header:t,message:`${r} is a symbol, which cannot be converted to a ByteString.`});let n=String(e);for(let i=0;i255)throw new TypeError(`Cannot convert argument to a ByteString because the character at index ${i} has a value of ${n.charCodeAt(i)} which is greater than 255.`);return n};K.converters.USVString=function(e){return typeof e=="string"?e.toWellFormed():`${e}`.toWellFormed()};K.converters.boolean=function(e){return!!e};K.converters.any=function(e){return e};K.converters["long long"]=function(e,t,r){return K.util.ConvertToInt(e,64,"signed",0,t,r)};K.converters["unsigned long long"]=function(e,t,r){return K.util.ConvertToInt(e,64,"unsigned",0,t,r)};K.converters["unsigned long"]=function(e,t,r){return K.util.ConvertToInt(e,32,"unsigned",0,t,r)};K.converters["unsigned short"]=function(e,t,r,n){return K.util.ConvertToInt(e,16,"unsigned",n,t,r)};K.converters.ArrayBuffer=function(e,t,r,n){if(K.util.Type(e)!==$n||!ur.isArrayBuffer(e))throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["ArrayBuffer"]});if(!K.util.HasFlag(n,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e))throw K.errors.exception({header:t,message:`${r} cannot be a resizable ArrayBuffer.`});return e};K.converters.SharedArrayBuffer=function(e,t,r,n){if(K.util.Type(e)!==$n||!ur.isSharedArrayBuffer(e))throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["SharedArrayBuffer"]});if(!K.util.HasFlag(n,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e))throw K.errors.exception({header:t,message:`${r} cannot be a resizable SharedArrayBuffer.`});return e};K.converters.TypedArray=function(e,t,r,n,i){if(K.util.Type(e)!==$n||!ur.isTypedArray(e)||e.constructor.name!==t.name)throw K.errors.conversionFailed({prefix:r,argument:`${n} ("${K.util.Stringify(e)}")`,types:[t.name]});if(!K.util.HasFlag(i,K.attributes.AllowShared)&&ur.isSharedArrayBuffer(e.buffer))throw K.errors.exception({header:r,message:`${n} cannot be a view on a shared array buffer.`});if(!K.util.HasFlag(i,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e.buffer))throw K.errors.exception({header:r,message:`${n} cannot be a view on a resizable array buffer.`});return e};K.converters.DataView=function(e,t,r,n){if(K.util.Type(e)!==$n||!ur.isDataView(e))throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["DataView"]});if(!K.util.HasFlag(n,K.attributes.AllowShared)&&ur.isSharedArrayBuffer(e.buffer))throw K.errors.exception({header:t,message:`${r} cannot be a view on a shared array buffer.`});if(!K.util.HasFlag(n,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e.buffer))throw K.errors.exception({header:t,message:`${r} cannot be a view on a resizable array buffer.`});return e};K.converters.ArrayBufferView=function(e,t,r,n){if(K.util.Type(e)!==$n||!ur.isArrayBufferView(e))throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["ArrayBufferView"]});if(!K.util.HasFlag(n,K.attributes.AllowShared)&&ur.isSharedArrayBuffer(e.buffer))throw K.errors.exception({header:t,message:`${r} cannot be a view on a shared array buffer.`});if(!K.util.HasFlag(n,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e.buffer))throw K.errors.exception({header:t,message:`${r} cannot be a view on a resizable array buffer.`});return e};K.converters.BufferSource=function(e,t,r,n){if(ur.isArrayBuffer(e))return K.converters.ArrayBuffer(e,t,r,n);if(ur.isArrayBufferView(e))return n&=~K.attributes.AllowShared,K.converters.ArrayBufferView(e,t,r,n);throw ur.isSharedArrayBuffer(e)?K.errors.exception({header:t,message:`${r} cannot be a SharedArrayBuffer.`}):K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["ArrayBuffer","ArrayBufferView"]})};K.converters.AllowSharedBufferSource=function(e,t,r,n){if(ur.isArrayBuffer(e))return K.converters.ArrayBuffer(e,t,r,n);if(ur.isSharedArrayBuffer(e))return K.converters.SharedArrayBuffer(e,t,r,n);if(ur.isArrayBufferView(e))return n|=K.attributes.AllowShared,K.converters.ArrayBufferView(e,t,r,n);throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["ArrayBuffer","SharedArrayBuffer","ArrayBufferView"]})};K.converters["sequence"]=K.sequenceConverter(K.converters.ByteString);K.converters["sequence>"]=K.sequenceConverter(K.converters["sequence"]);K.converters["record"]=K.recordConverter(K.converters.ByteString,K.converters.ByteString);K.converters.Blob=K.interfaceConverter(K.is.Blob,"Blob");K.converters.AbortSignal=K.interfaceConverter(K.is.AbortSignal,"AbortSignal");K.converters.EventHandlerNonNull=function(e){return K.util.Type(e)!==$n?null:typeof e=="function"?e:()=>{}};K.attributes={Clamp:1,EnforceRange:2,AllowShared:4,AllowResizable:8,LegacyNullToEmptyString:16};cH.exports={webidl:K}});var jf=U((gFe,wH)=>{"use strict";var{Transform:UEe}=(ts(),Os(qt)),lH=RE(),{redirectStatusSet:xEe,referrerPolicyTokens:LEe,badPortsSet:PEe}=td(),{getGlobalOrigin:hH}=g3(),{collectAnHTTPQuotedString:OEe,parseMIMEType:HEe}=yf(),{performance:qEe}=v3(),{ReadableStreamFrom:GEe,isValidHTTPToken:dH,normalizedMethodRecordsBase:YEe}=Zt(),Jd=Gt(),{isUint8Array:WEe}=dw(),{webidl:dA}=lo(),{isomorphicEncode:v_,collectASequenceOfCodePoints:Wf,removeChars:VEe}=Ef();function gH(e){let t=e.urlList,r=t.length;return r===0?null:t[r-1].toString()}function JEe(e,t){if(!xEe.has(e.status))return null;let r=e.headersList.get("location",!0);return r!==null&&EH(r)&&(pH(r)||(r=jEe(r)),r=new URL(r,gH(e))),r&&!r.hash&&(r.hash=t),r}function pH(e){for(let t=0;t126||r<32)return!1}return!0}function jEe(e){return Buffer.from(e,"binary").toString("utf8")}function Jf(e){return e.urlList[e.urlList.length-1]}function zEe(e){let t=Jf(e);return CH(t)&&PEe.has(t.port)?"blocked":"allowed"}function KEe(e){return e instanceof Error||e?.constructor?.name==="Error"||e?.constructor?.name==="DOMException"}function XEe(e){for(let t=0;t=32&&r<=126||r>=128&&r<=255))return!1}return!0}var ZEe=dH;function EH(e){return(e[0]===" "||e[0]===" "||e[e.length-1]===" "||e[e.length-1]===" "||e.includes(` -`)||e.includes("\r")||e.includes("\0"))===!1}function $Ee(e){let t=(e.headersList.get("referrer-policy",!0)??"").split(","),r="";if(t.length)for(let n=t.length;n!==0;n--){let i=t[n-1].trim();if(LEe.has(i)){r=i;break}}return r}function eye(e,t){let r=$Ee(t);r!==""&&(e.referrerPolicy=r)}function tye(){return"allowed"}function rye(){return"success"}function nye(){return"success"}function iye(e){let t=null;t=e.mode,e.headersList.set("sec-fetch-mode",t,!0)}function sye(e){let t=e.origin;if(!(t==="client"||t===void 0)){if(e.responseTainting==="cors"||e.mode==="websocket")e.headersList.append("origin",t,!0);else if(e.method!=="GET"&&e.method!=="HEAD"){switch(e.referrerPolicy){case"no-referrer":t=null;break;case"no-referrer-when-downgrade":case"strict-origin":case"strict-origin-when-cross-origin":e.origin&&D_(e.origin)&&!D_(Jf(e))&&(t=null);break;case"same-origin":Vd(e,Jf(e))||(t=null);break;default:}e.headersList.append("origin",t,!0)}}}function nl(e,t){return e}function oye(e,t,r){return!e?.startTime||e.startTime4096&&(n=i),t){case"no-referrer":return"no-referrer";case"origin":return i??R_(r,!0);case"unsafe-url":return n;case"strict-origin":{let s=Jf(e);return Vf(n)&&!Vf(s)?"no-referrer":i}case"strict-origin-when-cross-origin":{let s=Jf(e);return Vd(n,s)?n:Vf(n)&&!Vf(s)?"no-referrer":i}case"same-origin":return Vd(e,n)?n:"no-referrer";case"origin-when-cross-origin":return Vd(e,n)?n:i;case"no-referrer-when-downgrade":{let s=Jf(e);return Vf(n)&&!Vf(s)?"no-referrer":n}}}function R_(e,t=!1){return Jd(dA.is.URL(e)),e=new URL(e),bH(e)?"no-referrer":(e.username="",e.password="",e.hash="",t===!0&&(e.pathname="",e.search=""),e)}var cye=RegExp.prototype.test.bind(/^127\.(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){2}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)$/),lye=RegExp.prototype.test.bind(/^(?:(?:0{1,4}:){7}|(?:0{1,4}:){1,6}:|::)0{0,3}1$/);function mH(e){return e.includes(":")?(e[0]==="["&&e[e.length-1]==="]"&&(e=e.slice(1,-1)),lye(e)):cye(e)}function hye(e){return e==null||e==="null"?!1:(e=new URL(e),!!(e.protocol==="https:"||e.protocol==="wss:"||mH(e.hostname)||e.hostname==="localhost"||e.hostname==="localhost."||e.hostname.endsWith(".localhost")||e.hostname.endsWith(".localhost.")||e.protocol==="file:"))}function Vf(e){return dA.is.URL(e)?e.href==="about:blank"||e.href==="about:srcdoc"||e.protocol==="data:"||e.protocol==="blob:"?!0:hye(e.origin):!1}function dye(e){}function Vd(e,t){return e.origin===t.origin&&e.origin==="null"||e.protocol===t.protocol&&e.hostname===t.hostname&&e.port===t.port}function gye(e){return e.controller.state==="aborted"}function pye(e){return e.controller.state==="aborted"||e.controller.state==="terminated"}function Eye(e){return YEe[e.toLowerCase()]??e}var yye=Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));function BH(e,t,r=0,n=1){var s,o,a;class i{constructor(f,l){wt(this,s);wt(this,o);wt(this,a);ft(this,s,f),ft(this,o,l),ft(this,a,0)}next(){if(typeof this!="object"||this===null||!cD(s,this))throw new TypeError(`'next' called on an object that does not implement interface ${e} Iterator.`);let f=ee(this,a),l=t(ee(this,s)),p=l.length;if(f>=p)return{value:void 0,done:!0};let{[r]:I,[n]:S}=l[f];ft(this,a,f+1);let _;switch(ee(this,o)){case"key":_=I;break;case"value":_=S;break;case"key+value":_=[I,S];break}return{value:_,done:!1}}}return s=new WeakMap,o=new WeakMap,a=new WeakMap,delete i.prototype.constructor,Object.setPrototypeOf(i.prototype,yye),Object.defineProperties(i.prototype,{[Symbol.toStringTag]:{writable:!1,enumerable:!1,configurable:!0,value:`${e} Iterator`},next:{writable:!0,enumerable:!0,configurable:!0}}),function(A,f){return new i(A,f)}}function mye(e,t,r,n=0,i=1){let s=BH(e,r,n,i),o={keys:{writable:!0,enumerable:!0,configurable:!0,value:function(){return dA.brandCheck(this,t),s(this,"key")}},values:{writable:!0,enumerable:!0,configurable:!0,value:function(){return dA.brandCheck(this,t),s(this,"value")}},entries:{writable:!0,enumerable:!0,configurable:!0,value:function(){return dA.brandCheck(this,t),s(this,"key+value")}},forEach:{writable:!0,enumerable:!0,configurable:!0,value:function(A,f=globalThis){if(dA.brandCheck(this,t),dA.argumentLengthCheck(arguments,1,`${e}.forEach`),typeof A!="function")throw new TypeError(`Failed to execute 'forEach' on '${e}': parameter 1 is not of type 'Function'.`);for(let{0:l,1:p}of s(this,"key+value"))A.call(f,p,l,this)}}};return Object.defineProperties(t.prototype,{...o,[Symbol.iterator]:{writable:!0,enumerable:!1,configurable:!0,value:o.entries.value}})}function Bye(e,t,r){let n=t,i=r;try{let s=e.stream.getReader();IH(s,n,i)}catch(s){i(s)}}function Iye(e){try{e.close(),e.byobRequest?.respond(0)}catch(t){if(!t.message.includes("Controller is already closed")&&!t.message.includes("ReadableStream is already closed"))throw t}}async function IH(e,t,r){try{let n=[],i=0;do{let{done:s,value:o}=await e.read();if(s){t(Buffer.concat(n,i));return}if(!WEe(o)){r(new TypeError("Received non-Uint8Array chunk"));return}n.push(o),i+=o.length}while(!0)}catch(n){r(n)}}function bH(e){Jd("protocol"in e);let t=e.protocol;return t==="about:"||t==="blob:"||t==="data:"}function D_(e){return typeof e=="string"&&e[5]===":"&&e[0]==="h"&&e[1]==="t"&&e[2]==="t"&&e[3]==="p"&&e[4]==="s"||e.protocol==="https:"}function CH(e){Jd("protocol"in e);let t=e.protocol;return t==="http:"||t==="https:"}function bye(e,t){let r=e;if(!r.startsWith("bytes"))return"failure";let n={position:5};if(t&&Wf(A=>A===" "||A===" ",r,n),r.charCodeAt(n.position)!==61)return"failure";n.position++,t&&Wf(A=>A===" "||A===" ",r,n);let i=Wf(A=>{let f=A.charCodeAt(0);return f>=48&&f<=57},r,n),s=i.length?Number(i):null;if(t&&Wf(A=>A===" "||A===" ",r,n),r.charCodeAt(n.position)!==45)return"failure";n.position++,t&&Wf(A=>A===" "||A===" ",r,n);let o=Wf(A=>{let f=A.charCodeAt(0);return f>=48&&f<=57},r,n),a=o.length?Number(o):null;return n.positiona?"failure":{rangeStartValue:s,rangeEndValue:a}}function Cye(e,t,r){let n="bytes ";return n+=v_(`${e}`),n+="-",n+=v_(`${t}`),n+="/",n+=v_(`${r}`),n}var il,T_=class extends UEe{constructor(r){super();wt(this,il);ft(this,il,r)}_transform(r,n,i){if(!this._inflateStream){if(r.length===0){i();return}this._inflateStream=(r[0]&15)===8?lH.createInflate(ee(this,il)):lH.createInflateRaw(ee(this,il)),this._inflateStream.on("data",this.push.bind(this)),this._inflateStream.on("end",()=>this.push(null)),this._inflateStream.on("error",s=>this.destroy(s))}this._inflateStream.write(r,n,i)}_final(r){this._inflateStream&&(this._inflateStream.end(),this._inflateStream=null),r()}};il=new WeakMap;function Qye(e){return new T_(e)}function wye(e){let t=null,r=null,n=null,i=QH("content-type",e);if(i===null)return"failure";for(let s of i){let o=HEe(s);o==="failure"||o.essence==="*/*"||(n=o,n.essence!==r?(t=null,n.parameters.has("charset")&&(t=n.parameters.get("charset")),r=n.essence):!n.parameters.has("charset")&&t!==null&&n.parameters.set("charset",t))}return n??"failure"}function Sye(e){let t=e,r={position:0},n=[],i="";for(;r.positions!=='"'&&s!==",",t,r),r.positions===9||s===32),n.push(i),i=""}return n}function QH(e,t){let r=t.get(e,!0);return r===null?null:Sye(r)}function _ye(e){return!1}function vye(e){return!!(e.username||e.password)}function Rye(e){return!0}var N_=class{constructor(){y(this,"policyContainer",yH())}get baseUrl(){return hH()}get origin(){return this.baseUrl?.origin}},M_=class{constructor(){y(this,"settingsObject",new N_)}},Dye=new M_;wH.exports={isAborted:gye,isCancelled:pye,isValidEncodedURL:pH,ReadableStreamFrom:GEe,tryUpgradeRequestToAPotentiallyTrustworthyURL:dye,clampAndCoarsenConnectionTimingInfo:oye,coarsenedSharedCurrentTime:aye,determineRequestsReferrer:uye,makePolicyContainer:yH,clonePolicyContainer:fye,appendFetchMetadata:iye,appendRequestOriginHeader:sye,TAOCheck:nye,corsCheck:rye,crossOriginResourcePolicyCheck:tye,createOpaqueTimingInfo:Aye,setRequestReferrerPolicyOnRedirect:eye,isValidHTTPToken:dH,requestBadPort:zEe,requestCurrentURL:Jf,responseURL:gH,responseLocationURL:JEe,isURLPotentiallyTrustworthy:Vf,isValidReasonPhrase:XEe,sameOrigin:Vd,normalizeMethod:Eye,iteratorMixin:mye,createIterator:BH,isValidHeaderName:ZEe,isValidHeaderValue:EH,isErrorLike:KEe,fullyReadBody:Bye,readableStreamClose:Iye,urlIsLocal:bH,urlHasHttpsScheme:D_,urlIsHttpHttpsScheme:CH,readAllBytes:IH,simpleRangeHeaderValue:bye,buildContentRange:Cye,createInflate:Qye,extractMimeType:wye,getDecodeSplit:QH,environmentSettingsObject:Dye,isOriginIPPotentiallyTrustworthy:mH,hasAuthenticationEntry:_ye,includesCredentials:vye,isTraversableNavigable:Rye}});var k_=U((EFe,_H)=>{"use strict";var{iteratorMixin:Tye}=jf(),{kEnumerableProperty:sl}=Zt(),{webidl:_t}=lo(),SH=Yr(),Pr,gA=class gA{constructor(t=void 0){wt(this,Pr,[]);if(_t.util.markAsUncloneable(this),t!==void 0)throw _t.errors.conversionFailed({prefix:"FormData constructor",argument:"Argument 1",types:["undefined"]})}append(t,r,n=void 0){_t.brandCheck(this,gA);let i="FormData.append";_t.argumentLengthCheck(arguments,2,i),t=_t.converters.USVString(t),arguments.length===3||_t.is.Blob(r)?(r=_t.converters.Blob(r,i,"value"),n!==void 0&&(n=_t.converters.USVString(n))):r=_t.converters.USVString(r);let s=F_(t,r,n);ee(this,Pr).push(s)}delete(t){_t.brandCheck(this,gA),_t.argumentLengthCheck(arguments,1,"FormData.delete"),t=_t.converters.USVString(t),ft(this,Pr,ee(this,Pr).filter(n=>n.name!==t))}get(t){_t.brandCheck(this,gA),_t.argumentLengthCheck(arguments,1,"FormData.get"),t=_t.converters.USVString(t);let n=ee(this,Pr).findIndex(i=>i.name===t);return n===-1?null:ee(this,Pr)[n].value}getAll(t){return _t.brandCheck(this,gA),_t.argumentLengthCheck(arguments,1,"FormData.getAll"),t=_t.converters.USVString(t),ee(this,Pr).filter(n=>n.name===t).map(n=>n.value)}has(t){return _t.brandCheck(this,gA),_t.argumentLengthCheck(arguments,1,"FormData.has"),t=_t.converters.USVString(t),ee(this,Pr).findIndex(n=>n.name===t)!==-1}set(t,r,n=void 0){_t.brandCheck(this,gA);let i="FormData.set";_t.argumentLengthCheck(arguments,2,i),t=_t.converters.USVString(t),arguments.length===3||_t.is.Blob(r)?(r=_t.converters.Blob(r,i,"value"),n!==void 0&&(n=_t.converters.USVString(n))):r=_t.converters.USVString(r);let s=F_(t,r,n),o=ee(this,Pr).findIndex(a=>a.name===t);o!==-1?ft(this,Pr,[...ee(this,Pr).slice(0,o),s,...ee(this,Pr).slice(o+1).filter(a=>a.name!==t)]):ee(this,Pr).push(s)}[SH.inspect.custom](t,r){let n=ee(this,Pr).reduce((s,o)=>(s[o.name]?Array.isArray(s[o.name])?s[o.name].push(o.value):s[o.name]=[s[o.name],o.value]:s[o.name]=o.value,s),{__proto__:null});r.depth??(r.depth=t),r.colors??(r.colors=!0);let i=SH.formatWithOptions(r,n);return`FormData ${i.slice(i.indexOf("]")+2)}`}static getFormDataState(t){return ee(t,Pr)}static setFormDataState(t,r){ft(t,Pr,r)}};Pr=new WeakMap;var ca=gA,{getFormDataState:Nye,setFormDataState:Mye}=ca;Reflect.deleteProperty(ca,"getFormDataState");Reflect.deleteProperty(ca,"setFormDataState");Tye("FormData",ca,Nye,"name","value");Object.defineProperties(ca.prototype,{append:sl,delete:sl,get:sl,getAll:sl,has:sl,set:sl,[Symbol.toStringTag]:{value:"FormData",configurable:!0}});function F_(e,t,r){if(typeof t!="string"){if(_t.is.File(t)||(t=new File([t],"blob",{type:t.type})),r!==void 0){let n={type:t.type,lastModified:t.lastModified};t=new File([t],r,n)}}return{name:e,value:t}}_t.is.FormData=_t.util.MakeTypeAssertion(ca);_H.exports={FormData:ca,makeEntry:F_,setFormDataState:Mye}});var DH=U((mFe,RH)=>{"use strict";var{bufferToLowerCasedHeaderName:Fye}=Zt(),{HTTP_TOKEN_CODEPOINTS:kye}=yf(),{makeEntry:Uye}=k_(),{webidl:U_}=lo(),x_=Gt(),{isomorphicDecode:vH}=Ef(),xye=Buffer.from("--"),L_=new TextDecoder,Lye=new TextDecoder("utf-8",{ignoreBOM:!0});function Pye(e){for(let t=0;t70)return!1;for(let r=0;r=48&&n<=57||n>=65&&n<=90||n>=97&&n<=122||n===39||n===45||n===95))return!1}return!0}function Hye(e,t){x_(t!=="failure"&&t.essence==="multipart/form-data");let r=t.parameters.get("boundary");if(r===void 0)throw Un("missing boundary in content-type header");let n=Buffer.from(`--${r}`,"utf8"),i=[],s={position:0},o=e.indexOf(n);if(o===-1)throw Un("no boundary found in multipart body");for(s.position=o;;){if(e.subarray(s.position,s.position+n.length).equals(n))s.position+=n.length;else throw Un("expected a value starting with -- and the boundary");if(Yye(e,xye,s))return i;if(e[s.position]!==13||e[s.position+1]!==10)throw Un("expected CRLF");s.position+=2;let a=Gye(e,s),{name:A,filename:f,contentType:l,encoding:p}=a;s.position+=2;let I;{let _=e.indexOf(n.subarray(2),s.position);if(_===-1)throw Un("expected boundary after body");I=e.subarray(s.position,_-4),s.position+=I.length,p==="base64"&&(I=Buffer.from(I.toString(),"base64"))}if(e[s.position]!==13||e[s.position+1]!==10)throw Un("expected CRLF");s.position+=2;let S;f!==null?(l??(l="text/plain"),Pye(l)||(l=""),S=new File([I],f,{type:l})):S=Lye.decode(Buffer.from(I)),x_(U_.is.USVString(A)),x_(typeof S=="string"&&U_.is.USVString(S)||U_.is.File(S)),i.push(Uye(A,S,f))}}function qye(e,t){e[t.position]===59&&t.position++,Di(o=>o===32||o===9,e,t);let r=Di(o=>O_(o)&&o!==61&&o!==42,e,t);if(r.length===0)return null;let n=r.toString("ascii").toLowerCase(),i=e[t.position]===42;if(i&&t.position++,e[t.position]!==61)return null;t.position++,Di(o=>o===32||o===9,e,t);let s;if(i){let o=Di(a=>a!==32&&a!==13&&a!==10&&a!==59,e,t);if(o[0]!==117&&o[0]!==85||o[1]!==116&&o[1]!==84||o[2]!==102&&o[2]!==70||o[3]!==45||o[4]!==56)throw Un("unknown encoding, expected utf-8''");s=decodeURIComponent(L_.decode(o.subarray(7)))}else if(e[t.position]===34){t.position++;let o=Di(a=>a!==10&&a!==13&&a!==34,e,t);if(e[t.position]!==34)throw Un("Closing quote not found");t.position++,s=L_.decode(o).replace(/%0A/ig,` -`).replace(/%0D/ig,"\r").replace(/%22/g,'"')}else{let o=Di(a=>O_(a)&&a!==59,e,t);s=L_.decode(o)}return{name:n,value:s}}function Gye(e,t){let r=null,n=null,i=null,s=null;for(;;){if(e[t.position]===13&&e[t.position+1]===10){if(r===null)throw Un("header name is null");return{name:r,filename:n,contentType:i,encoding:s}}let o=Di(a=>a!==10&&a!==13&&a!==58,e,t);if(o=P_(o,!0,!0,a=>a===9||a===32),!kye.test(o.toString()))throw Un("header name does not match the field-name token production");if(e[t.position]!==58)throw Un("expected :");switch(t.position++,Di(a=>a===32||a===9,e,t),Fye(o)){case"content-disposition":{if(r=n=null,Di(A=>O_(A),e,t).toString("ascii").toLowerCase()!=="form-data")throw Un("expected form-data for content-disposition header");for(;t.positionA!==10&&A!==13,e,t);a=P_(a,!1,!0,A=>A===9||A===32),i=vH(a);break}case"content-transfer-encoding":{let a=Di(A=>A!==10&&A!==13,e,t);a=P_(a,!1,!0,A=>A===9||A===32),s=vH(a);break}default:Di(a=>a!==10&&a!==13,e,t)}if(e[t.position]!==13&&e[t.position+1]!==10)throw Un("expected CRLF");t.position+=2}}function Di(e,t,r){let n=r.position;for(;n0&&n(e[s]);)s--;return i===0&&s===e.length-1?e:e.subarray(i,s+1)}function Yye(e,t,r){if(e.length{"use strict";function Jye(){let e,t;return{promise:new Promise((n,i)=>{e=n,t=i}),resolve:e,reject:t}}TH.exports={createDeferredPromise:Jye}});var G_=U((IFe,FH)=>{"use strict";var NH=new Set(["crypto","sqlite","markAsUncloneable","zstd"]),ol,q_=class{constructor(){wt(this,ol,new Map([["crypto",!0],["sqlite",!1],["markAsUncloneable",!1],["zstd",!1]]))}clear(){ee(this,ol).clear()}has(t){if(!NH.has(t))throw new TypeError(`unknown feature: ${t}`);return ee(this,ol).get(t)??!1}set(t,r){if(!NH.has(t))throw new TypeError(`unknown feature: ${t}`);ee(this,ol).set(t,!!r)}};ol=new WeakMap;var MH=new q_;FH.exports={runtimeFeatures:MH,default:MH}});var Al=U((CFe,PH)=>{"use strict";var V_=Zt(),{ReadableStreamFrom:jye,readableStreamClose:zye,fullyReadBody:Kye,extractMimeType:Xye}=jf(),{FormData:kH,setFormDataState:Zye}=k_(),{webidl:ms}=lo(),Y_=Gt(),{isErrored:W_,isDisturbed:$ye}=(ts(),Os(qt)),{isUint8Array:eme}=dw(),{serializeAMimeType:tme}=yf(),{multipartFormDataParser:rme}=DH(),{createDeferredPromise:nme}=H_(),{parseJSONFromBytes:ime}=Ef(),{utf8DecodeBytes:sme}=cw(),{runtimeFeatures:ome}=G_(),ame=ome.has("crypto")?Nd().randomInt:e=>Math.floor(Math.random()*e),$y=new TextEncoder;function Ame(){}var fme=new FinalizationRegistry(e=>{let t=e.deref();t&&!t.locked&&!$ye(t)&&!W_(t)&&t.cancel("Response object has been garbage collected").catch(Ame)});function xH(e,t=!1){let r=null,n=null;ms.is.ReadableStream(e)?r=e:ms.is.Blob(e)?r=e.stream():r=new ReadableStream({pull(){},start(f){n=f},cancel(){},type:"bytes"}),Y_(ms.is.ReadableStream(r));let i=null,s=null,o=null,a=null;if(typeof e=="string")s=e,a="text/plain;charset=UTF-8";else if(ms.is.URLSearchParams(e))s=e.toString(),a="application/x-www-form-urlencoded;charset=UTF-8";else if(ms.is.BufferSource(e))s=ms.util.getCopyOfBytesHeldByBufferSource(e);else if(ms.is.FormData(e)){let f=`----formdata-undici-0${`${ame(1e11)}`.padStart(11,"0")}`,l=`--${f}\r -Content-Disposition: form-data`;let p=x=>x.replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/"/g,"%22"),I=x=>x.replace(/\r?\n|\r/g,`\r -`),S=[],_=new Uint8Array([13,10]);o=0;let N=!1;for(let[x,G]of e)if(typeof G=="string"){let Y=$y.encode(l+`; name="${p(I(x))}"\r -\r -${I(G)}\r -`);S.push(Y),o+=Y.byteLength}else{let Y=$y.encode(`${l}; name="${p(I(x))}"`+(G.name?`; filename="${p(G.name)}"`:"")+`\r -Content-Type: ${G.type||"application/octet-stream"}\r -\r -`);S.push(Y,G,_),typeof G.size=="number"?o+=Y.byteLength+G.size+_.byteLength:N=!0}let O=$y.encode(`--${f}--\r -`);S.push(O),o+=O.byteLength,N&&(o=null),s=e,i=async function*(){for(let x of S)x.stream?yield*x.stream():yield x},a=`multipart/form-data; boundary=${f}`}else if(ms.is.Blob(e))s=e,o=e.size,e.type&&(a=e.type);else if(typeof e[Symbol.asyncIterator]=="function"){if(t)throw new TypeError("keepalive");if(V_.isDisturbed(e)||e.locked)throw new TypeError("Response body object should not be disturbed or locked");r=ms.is.ReadableStream(e)?e:jye(e)}return(typeof s=="string"||eme(s))&&(i=()=>(o=typeof s=="string"?Buffer.byteLength(s):s.length,s)),i!=null&&(async()=>{let f=i(),l=f?.[Symbol.asyncIterator]?.();if(l)for await(let p of l){if(W_(r))break;p.length&&n.enqueue(new Uint8Array(p))}else f?.length&&!W_(r)&&n.enqueue(typeof f=="string"?$y.encode(f):new Uint8Array(f));queueMicrotask(()=>zye(n))})(),[{stream:r,source:s,length:o},a]}function ume(e,t=!1){return ms.is.ReadableStream(e)&&(Y_(!V_.isDisturbed(e),"The body has already been consumed."),Y_(!e.locked,"The stream is locked.")),xH(e,t)}function cme(e){let{0:t,1:r}=e.stream.tee();return e.stream=t,{stream:r,length:e.length,source:e.source}}function lme(e,t){return{blob(){return al(this,n=>{let i=UH(t(this));return i===null?i="":i&&(i=tme(i)),new Blob([n],{type:i})},e,t)},arrayBuffer(){return al(this,n=>new Uint8Array(n).buffer,e,t)},text(){return al(this,sme,e,t)},json(){return al(this,ime,e,t)},formData(){return al(this,n=>{let i=UH(t(this));if(i!==null)switch(i.essence){case"multipart/form-data":{let s=rme(n,i),o=new kH;return Zye(o,s),o}case"application/x-www-form-urlencoded":{let s=new URLSearchParams(n.toString()),o=new kH;for(let[a,A]of s)o.append(a,A);return o}}throw new TypeError('Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".')},e,t)},bytes(){return al(this,n=>new Uint8Array(n),e,t)}}}function hme(e,t){Object.assign(e.prototype,lme(e,t))}function al(e,t,r,n){try{ms.brandCheck(e,r)}catch(a){return Promise.reject(a)}if(e=n(e),LH(e))return Promise.reject(new TypeError("Body is unusable: Body has already been read"));let i=nme(),s=i.reject,o=a=>{try{i.resolve(t(a))}catch(A){s(A)}};return e.body==null?(o(Buffer.allocUnsafe(0)),i.promise):(Kye(e.body,o,s),i.promise)}function LH(e){let t=e.body;return t!=null&&(t.stream.locked||V_.isDisturbed(t.stream))}function UH(e){let t=e.headersList,r=Xye(t);return r==="failure"?null:r}PH.exports={extractBody:xH,safelyExtractBody:ume,cloneBody:cme,mixinBody:hme,streamRegistry:fme,bodyUnusable:LH}});var KH=U((QFe,zH)=>{"use strict";var Oe=Gt(),qe=Zt(),{channels:OH}=ed(),J_=gQ(),{RequestContentLengthMismatchError:zf,ResponseContentLengthMismatchError:dme,RequestAbortedError:VH,HeadersTimeoutError:gme,HeadersOverflowError:pme,SocketError:Kd,InformationalError:fl,BodyTimeoutError:Eme,HTTPParserError:yme,ResponseExceededMaxSizeError:mme}=mr(),{kUrl:JH,kReset:xn,kClient:ev,kParser:cr,kBlocking:Xd,kRunning:un,kPending:Bme,kSize:HH,kWriting:EA,kQueue:Bs,kNoRef:jd,kKeepAliveDefaultTimeout:Ime,kHostHeader:bme,kPendingIdx:Cme,kRunningIdx:Ti,kError:Ni,kPipelining:rm,kSocket:ul,kKeepAliveTimeoutValue:im,kMaxHeadersSize:Qme,kKeepAliveMaxTimeout:wme,kKeepAliveTimeoutThreshold:Sme,kHeadersTimeout:_me,kBodyTimeout:vme,kStrictContentLength:K_,kMaxRequests:qH,kCounter:Rme,kMaxResponseSize:Dme,kOnError:Tme,kResume:pA,kHTTPContext:jH,kClosed:X_}=Dn(),ho=t3(),Nme=Buffer.alloc(0),em=Buffer[Symbol.species],Mme=qe.removeAllListeners,j_;function Fme(){let e=process.env.JEST_WORKER_ID?Aw():void 0,t,r=process.arch!=="ppc64";if(process.env.UNDICI_NO_WASM_SIMD==="1"?r=!0:process.env.UNDICI_NO_WASM_SIMD==="0"&&(r=!1),r)try{t=new WebAssembly.Module(i3())}catch{}return t||(t=new WebAssembly.Module(e||Aw())),new WebAssembly.Instance(t,{env:{wasm_on_url:(n,i,s)=>0,wasm_on_status:(n,i,s)=>{Oe(Rr.ptr===n);let o=i-po+go.byteOffset;return Rr.onStatus(new em(go.buffer,o,s))},wasm_on_message_begin:n=>(Oe(Rr.ptr===n),Rr.onMessageBegin()),wasm_on_header_field:(n,i,s)=>{Oe(Rr.ptr===n);let o=i-po+go.byteOffset;return Rr.onHeaderField(new em(go.buffer,o,s))},wasm_on_header_value:(n,i,s)=>{Oe(Rr.ptr===n);let o=i-po+go.byteOffset;return Rr.onHeaderValue(new em(go.buffer,o,s))},wasm_on_headers_complete:(n,i,s,o)=>(Oe(Rr.ptr===n),Rr.onHeadersComplete(i,s===1,o===1)),wasm_on_body:(n,i,s)=>{Oe(Rr.ptr===n);let o=i-po+go.byteOffset;return Rr.onBody(new em(go.buffer,o,s))},wasm_on_message_complete:n=>(Oe(Rr.ptr===n),Rr.onMessageComplete())}})}var z_=null,Rr=null,go=null,tm=0,po=null,kme=0,zd=1,cl=2|zd,nm=4|zd,Z_=8|kme,$_=class{constructor(t,r,{exports:n}){this.llhttp=n,this.ptr=this.llhttp.llhttp_alloc(ho.TYPE.RESPONSE),this.client=t,this.socket=r,this.timeout=null,this.timeoutValue=null,this.timeoutType=null,this.statusCode=0,this.statusText="",this.upgrade=!1,this.headers=[],this.headersSize=0,this.headersMaxSize=t[Qme],this.shouldKeepAlive=!1,this.paused=!1,this.resume=this.resume.bind(this),this.bytesRead=0,this.keepAlive="",this.contentLength="",this.connection="",this.maxResponseSize=t[Dme]}setTimeout(t,r){t!==this.timeoutValue||r&zd^this.timeoutType&zd?(this.timeout&&(J_.clearTimeout(this.timeout),this.timeout=null),t&&(r&zd?this.timeout=J_.setFastTimeout(GH,t,new WeakRef(this)):(this.timeout=setTimeout(GH,t,new WeakRef(this)),this.timeout?.unref())),this.timeoutValue=t):this.timeout&&this.timeout.refresh&&this.timeout.refresh(),this.timeoutType=r}resume(){this.socket.destroyed||!this.paused||(Oe(this.ptr!=null),Oe(Rr===null),this.llhttp.llhttp_resume(this.ptr),Oe(this.timeoutType===nm),this.timeout&&this.timeout.refresh&&this.timeout.refresh(),this.paused=!1,this.execute(this.socket.read()||Nme),this.readMore())}readMore(){for(;!this.paused&&this.ptr;){let t=this.socket.read();if(t===null)break;this.execute(t)}}execute(t){Oe(Rr===null),Oe(this.ptr!=null),Oe(!this.paused);let{socket:r,llhttp:n}=this;t.length>tm&&(po&&n.free(po),tm=Math.ceil(t.length/4096)*4096,po=n.malloc(tm)),new Uint8Array(n.memory.buffer,po,tm).set(t);try{let i;try{go=t,Rr=this,i=n.llhttp_execute(this.ptr,po,t.length)}finally{Rr=null,go=null}if(i!==ho.ERROR.OK){let s=t.subarray(n.llhttp_get_error_pos(this.ptr)-po);if(i===ho.ERROR.PAUSED_UPGRADE)this.onUpgrade(s);else if(i===ho.ERROR.PAUSED)this.paused=!0,r.unshift(s);else{let o=n.llhttp_get_error_reason(this.ptr),a="";if(o){let A=new Uint8Array(n.memory.buffer,o).indexOf(0);a="Response does not match the HTTP/1.1 protocol ("+Buffer.from(n.memory.buffer,o,A).toString()+")"}throw new yme(a,ho.ERROR[i],s)}}}catch(i){qe.destroy(r,i)}}destroy(){Oe(Rr===null),Oe(this.ptr!=null),this.llhttp.llhttp_free(this.ptr),this.ptr=null,this.timeout&&J_.clearTimeout(this.timeout),this.timeout=null,this.timeoutValue=null,this.timeoutType=null,this.paused=!1}onStatus(t){return this.statusText=t.toString(),0}onMessageBegin(){let{socket:t,client:r}=this;if(t.destroyed)return-1;let n=r[Bs][r[Ti]];return n?(n.onResponseStarted(),0):-1}onHeaderField(t){let r=this.headers.length;return(r&1)===0?this.headers.push(t):this.headers[r-1]=Buffer.concat([this.headers[r-1],t]),this.trackHeader(t.length),0}onHeaderValue(t){let r=this.headers.length;(r&1)===1?(this.headers.push(t),r+=1):this.headers[r-1]=Buffer.concat([this.headers[r-1],t]);let n=this.headers[r-2];if(n.length===10){let i=qe.bufferToLowerCasedHeaderName(n);i==="keep-alive"?this.keepAlive+=t.toString():i==="connection"&&(this.connection+=t.toString())}else n.length===14&&qe.bufferToLowerCasedHeaderName(n)==="content-length"&&(this.contentLength+=t.toString());return this.trackHeader(t.length),0}trackHeader(t){this.headersSize+=t,this.headersSize>=this.headersMaxSize&&qe.destroy(this.socket,new pme)}onUpgrade(t){let{upgrade:r,client:n,socket:i,headers:s,statusCode:o}=this;Oe(r),Oe(n[ul]===i),Oe(!i.destroyed),Oe(!this.paused),Oe((s.length&1)===0);let a=n[Bs][n[Ti]];Oe(a),Oe(a.upgrade||a.method==="CONNECT"),this.statusCode=0,this.statusText="",this.shouldKeepAlive=!1,this.headers=[],this.headersSize=0,i.unshift(t),i[cr].destroy(),i[cr]=null,i[ev]=null,i[Ni]=null,Mme(i),n[ul]=null,n[jH]=null,n[Bs][n[Ti]++]=null,n.emit("disconnect",n[JH],[n],new fl("upgrade"));try{a.onUpgrade(o,s,i)}catch(A){qe.destroy(i,A)}n[pA]()}onHeadersComplete(t,r,n){let{client:i,socket:s,headers:o,statusText:a}=this;if(s.destroyed)return-1;let A=i[Bs][i[Ti]];if(!A)return-1;if(Oe(!this.upgrade),Oe(this.statusCode<200),t===100)return qe.destroy(s,new Kd("bad response",qe.getSocketInfo(s))),-1;if(r&&!A.upgrade)return qe.destroy(s,new Kd("bad upgrade",qe.getSocketInfo(s))),-1;if(Oe(this.timeoutType===cl),this.statusCode=t,this.shouldKeepAlive=n||A.method==="HEAD"&&!s[xn]&&this.connection.toLowerCase()==="keep-alive",this.statusCode>=200){let l=A.bodyTimeout!=null?A.bodyTimeout:i[vme];this.setTimeout(l,nm)}else this.timeout&&this.timeout.refresh&&this.timeout.refresh();if(A.method==="CONNECT")return Oe(i[un]===1),this.upgrade=!0,2;if(r)return Oe(i[un]===1),this.upgrade=!0,2;if(Oe((this.headers.length&1)===0),this.headers=[],this.headersSize=0,this.shouldKeepAlive&&i[rm]){let l=this.keepAlive?qe.parseKeepAliveTimeout(this.keepAlive):null;if(l!=null){let p=Math.min(l-i[Sme],i[wme]);p<=0?s[xn]=!0:i[im]=p}else i[im]=i[Ime]}else s[xn]=!0;let f=A.onHeaders(t,o,this.resume,a)===!1;return A.aborted?-1:A.method==="HEAD"||t<200?1:(s[Xd]&&(s[Xd]=!1,i[pA]()),f?ho.ERROR.PAUSED:0)}onBody(t){let{client:r,socket:n,statusCode:i,maxResponseSize:s}=this;if(n.destroyed)return-1;let o=r[Bs][r[Ti]];return Oe(o),Oe(this.timeoutType===nm),this.timeout&&this.timeout.refresh&&this.timeout.refresh(),Oe(i>=200),s>-1&&this.bytesRead+t.length>s?(qe.destroy(n,new mme),-1):(this.bytesRead+=t.length,o.onData(t)===!1?ho.ERROR.PAUSED:0)}onMessageComplete(){let{client:t,socket:r,statusCode:n,upgrade:i,headers:s,contentLength:o,bytesRead:a,shouldKeepAlive:A}=this;if(r.destroyed&&(!n||A))return-1;if(i)return 0;Oe(n>=100),Oe((this.headers.length&1)===0);let f=t[Bs][t[Ti]];if(Oe(f),this.statusCode=0,this.statusText="",this.bytesRead=0,this.contentLength="",this.keepAlive="",this.connection="",this.headers=[],this.headersSize=0,n<200)return 0;if(f.method!=="HEAD"&&o&&a!==parseInt(o,10))return qe.destroy(r,new dme),-1;if(f.onComplete(s),t[Bs][t[Ti]++]=null,r[EA])return Oe(t[un]===0),qe.destroy(r,new fl("reset")),ho.ERROR.PAUSED;if(A){if(r[xn]&&t[un]===0)return qe.destroy(r,new fl("reset")),ho.ERROR.PAUSED;t[rm]==null||t[rm]===1?setImmediate(t[pA]):t[pA]()}else return qe.destroy(r,new fl("reset")),ho.ERROR.PAUSED;return 0}};function GH(e){let t=e.deref();if(!t)return;let{socket:r,timeoutType:n,client:i,paused:s}=t;n===cl?(!r[EA]||r.writableNeedDrain||i[un]>1)&&(Oe(!s,"cannot be paused while waiting for headers"),qe.destroy(r,new gme)):n===nm?s||qe.destroy(r,new Eme):n===Z_&&(Oe(i[un]===0&&i[im]),qe.destroy(r,new fl("socket idle timeout")))}function Ume(e,t){if(e[ul]=t,z_||(z_=Fme()),t.errored)throw t.errored;if(t.destroyed)throw new Kd("destroyed");return t[jd]=!1,t[EA]=!1,t[xn]=!1,t[Xd]=!1,t[cr]=new $_(e,t,z_),qe.addListener(t,"error",xme),qe.addListener(t,"readable",Lme),qe.addListener(t,"end",Pme),qe.addListener(t,"close",Ome),t[X_]=!1,t.on("close",Hme),{version:"h1",defaultPipelining:1,write(r){return Yme(e,r)},resume(){qme(e)},destroy(r,n){t[X_]?queueMicrotask(n):(t.on("close",n),t.destroy(r))},get destroyed(){return t.destroyed},busy(r){return!!(t[EA]||t[xn]||t[Xd]||r&&(e[un]>0&&!r.idempotent||e[un]>0&&(r.upgrade||r.method==="CONNECT")||e[un]>0&&qe.bodyLength(r.body)!==0&&(qe.isStream(r.body)||qe.isAsyncIterable(r.body)||qe.isFormDataLike(r.body))))}}}function xme(e){Oe(e.code!=="ERR_TLS_CERT_ALTNAME_INVALID");let t=this[cr];if(e.code==="ECONNRESET"&&t.statusCode&&!t.shouldKeepAlive){t.onMessageComplete();return}this[Ni]=e,this[ev][Tme](e)}function Lme(){this[cr]?.readMore()}function Pme(){let e=this[cr];if(e.statusCode&&!e.shouldKeepAlive){e.onMessageComplete();return}qe.destroy(this,new Kd("other side closed",qe.getSocketInfo(this)))}function Ome(){let e=this[cr];e&&(!this[Ni]&&e.statusCode&&!e.shouldKeepAlive&&e.onMessageComplete(),this[cr].destroy(),this[cr]=null);let t=this[Ni]||new Kd("closed",qe.getSocketInfo(this)),r=this[ev];if(r[ul]=null,r[jH]=null,r.destroyed){Oe(r[Bme]===0);let n=r[Bs].splice(r[Ti]);for(let i=0;i0&&t.code!=="UND_ERR_INFO"){let n=r[Bs][r[Ti]];r[Bs][r[Ti]++]=null,qe.errorRequest(r,n,t)}r[Cme]=r[Ti],Oe(r[un]===0),r.emit("disconnect",r[JH],[r],t),r[pA]()}function Hme(){this[X_]=!0}function qme(e){let t=e[ul];if(t&&!t.destroyed){if(e[HH]===0?!t[jd]&&t.unref&&(t.unref(),t[jd]=!0):t[jd]&&t.ref&&(t.ref(),t[jd]=!1),e[HH]===0)t[cr].timeoutType!==Z_&&t[cr].setTimeout(e[im],Z_);else if(e[un]>0&&t[cr].statusCode<200&&t[cr].timeoutType!==cl){let r=e[Bs][e[Ti]],n=r.headersTimeout!=null?r.headersTimeout:e[_me];t[cr].setTimeout(n,cl)}}}function Gme(e){return e!=="GET"&&e!=="HEAD"&&e!=="OPTIONS"&&e!=="TRACE"&&e!=="CONNECT"}function Yme(e,t){let{method:r,path:n,host:i,upgrade:s,blocking:o,reset:a}=t,{body:A,headers:f,contentLength:l}=t,p=r==="PUT"||r==="POST"||r==="PATCH"||r==="QUERY"||r==="PROPFIND"||r==="PROPPATCH";if(qe.isFormDataLike(A)){j_||(j_=Al().extractBody);let[O,x]=j_(A);t.contentType==null&&f.push("content-type",x),A=O.stream,l=O.length}else qe.isBlobLike(A)&&t.contentType==null&&A.type&&f.push("content-type",A.type);A&&typeof A.read=="function"&&A.read(0);let I=qe.bodyLength(A);if(l=I??l,l===null&&(l=t.contentLength),l===0&&!p&&(l=null),Gme(r)&&l>0&&t.contentLength!==null&&t.contentLength!==l){if(e[K_])return qe.errorRequest(e,t,new zf),!1;process.emitWarning(new zf)}let S=e[ul],_=O=>{t.aborted||t.completed||(qe.errorRequest(e,t,O||new VH),qe.destroy(A),qe.destroy(S,new fl("aborted")))};try{t.onConnect(_)}catch(O){qe.errorRequest(e,t,O)}if(t.aborted)return!1;r==="HEAD"&&(S[xn]=!0),(s||r==="CONNECT")&&(S[xn]=!0),a!=null&&(S[xn]=a),e[qH]&&S[Rme]++>=e[qH]&&(S[xn]=!0),o&&(S[Xd]=!0),S.setTypeOfService&&S.setTypeOfService(t.typeOfService);let N=`${r} ${n} HTTP/1.1\r -`;if(typeof i=="string"?N+=`host: ${i}\r -`:N+=e[bme],s?N+=`connection: upgrade\r -upgrade: ${s}\r -`:e[rm]&&!S[xn]?N+=`connection: keep-alive\r -`:N+=`connection: close\r -`,Array.isArray(f))for(let O=0;O{t.removeListener("error",S)}),!A){let _=new VH;queueMicrotask(()=>S(_))}},S=function(_){if(!A){if(A=!0,Oe(i.destroyed||i[EA]&&r[un]<=1),i.off("drain",p).off("error",S),t.removeListener("data",l).removeListener("end",S).removeListener("close",I),!_)try{f.end()}catch(N){_=N}f.destroy(_),_&&(_.code!=="UND_ERR_INFO"||_.message!=="reset")?qe.destroy(t,_):qe.destroy(t)}};t.on("data",l).on("end",S).on("error",S).on("close",I),t.resume&&t.resume(),i.on("drain",p).on("error",S),t.errorEmitted??t.errored?setImmediate(S,t.errored):(t.endEmitted??t.readableEnded)&&setImmediate(S,null),(t.closeEmitted??t.closed)&&setImmediate(I)}function YH(e,t,r,n,i,s,o,a){try{t?qe.isBuffer(t)&&(Oe(s===t.byteLength,"buffer body must have content length"),i.cork(),i.write(`${o}content-length: ${s}\r -\r -`,"latin1"),i.write(t),i.uncork(),n.onBodySent(t),!a&&n.reset!==!1&&(i[xn]=!0)):s===0?i.write(`${o}content-length: 0\r -\r -`,"latin1"):(Oe(s===null,"no body must not have content length"),i.write(`${o}\r -`,"latin1")),n.onRequestSent(),r[pA]()}catch(A){e(A)}}async function Vme(e,t,r,n,i,s,o,a){Oe(s===t.size,"blob body must have content length");try{if(s!=null&&s!==t.size)throw new zf;let A=Buffer.from(await t.arrayBuffer());i.cork(),i.write(`${o}content-length: ${s}\r -\r -`,"latin1"),i.write(A),i.uncork(),n.onBodySent(A),n.onRequestSent(),!a&&n.reset!==!1&&(i[xn]=!0),r[pA]()}catch(A){e(A)}}async function WH(e,t,r,n,i,s,o,a){Oe(s!==0||r[un]===0,"iterator body cannot be pipelined");let A=null;function f(){if(A){let I=A;A=null,I()}}let l=()=>new Promise((I,S)=>{Oe(A===null),i[Ni]?S(i[Ni]):A=I});i.on("close",f).on("drain",f);let p=new sm({abort:e,socket:i,request:n,contentLength:s,client:r,expectsPayload:a,header:o});try{for await(let I of t){if(i[Ni])throw i[Ni];p.write(I)||await l()}p.end()}catch(I){p.destroy(I)}finally{i.off("close",f).off("drain",f)}}var sm=class{constructor({abort:t,socket:r,request:n,contentLength:i,client:s,expectsPayload:o,header:a}){this.socket=r,this.request=n,this.contentLength=i,this.client=s,this.bytesWritten=0,this.expectsPayload=o,this.header=a,this.abort=t,r[EA]=!0}write(t){let{socket:r,request:n,contentLength:i,client:s,bytesWritten:o,expectsPayload:a,header:A}=this;if(r[Ni])throw r[Ni];if(r.destroyed)return!1;let f=Buffer.byteLength(t);if(!f)return!0;if(i!==null&&o+f>i){if(s[K_])throw new zf;process.emitWarning(new zf)}r.cork(),o===0&&(!a&&n.reset!==!1&&(r[xn]=!0),i===null?r.write(`${A}transfer-encoding: chunked\r -`,"latin1"):r.write(`${A}content-length: ${i}\r -\r -`,"latin1")),i===null&&r.write(`\r -${f.toString(16)}\r -`,"latin1"),this.bytesWritten+=f;let l=r.write(t);return r.uncork(),n.onBodySent(t),l||r[cr].timeout&&r[cr].timeoutType===cl&&r[cr].timeout.refresh&&r[cr].timeout.refresh(),l}end(){let{socket:t,contentLength:r,client:n,bytesWritten:i,expectsPayload:s,header:o,request:a}=this;if(a.onRequestSent(),t[EA]=!1,t[Ni])throw t[Ni];if(!t.destroyed){if(i===0?s?t.write(`${o}content-length: 0\r -\r -`,"latin1"):t.write(`${o}\r -`,"latin1"):r===null&&t.write(`\r -0\r -\r -`,"latin1"),r!==null&&i!==r){if(n[K_])throw new zf;process.emitWarning(new zf)}t[cr].timeout&&t[cr].timeoutType===cl&&t[cr].timeout.refresh&&t[cr].timeout.refresh(),n[pA]()}}destroy(t){let{socket:r,client:n,abort:i}=this;r[EA]=!1,t&&(Oe(n[un]<=1,"pipeline should only contain this request"),i(t))}};zH.exports=Ume});var $H=U((wFe,ZH)=>{"use strict";var XH={HTTP2_HEADER_METHOD:":method",HTTP2_HEADER_PATH:":path",HTTP2_HEADER_SCHEME:":scheme",HTTP2_HEADER_AUTHORITY:":authority",HTTP2_HEADER_STATUS:":status",HTTP2_HEADER_CONTENT_TYPE:"content-type",HTTP2_HEADER_CONTENT_LENGTH:"content-length",HTTP2_HEADER_LAST_MODIFIED:"last-modified",HTTP2_HEADER_ACCEPT:"accept",HTTP2_HEADER_ACCEPT_ENCODING:"accept-encoding",HTTP2_METHOD_GET:"GET",HTTP2_METHOD_POST:"POST",HTTP2_METHOD_PUT:"PUT",HTTP2_METHOD_DELETE:"DELETE",DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE:65535};function tv(e){let t=new Error(`node:http2 ${e} is not available in the secure-exec bridge bootstrap`);throw t.code="ERR_NOT_IMPLEMENTED",t}function Jme(){tv("connect")}function jme(){tv("createServer")}function zme(){tv("createSecureServer")}function Kme(){return{maxHeaderListSize:XH.DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE}}ZH.exports={constants:XH,connect:Jme,createServer:jme,createSecureServer:zme,getDefaultSettings:Kme}});var A7=U((SFe,a7)=>{"use strict";var Fi=Gt(),{pipeline:Xme}=(ts(),Os(qt)),ct=Zt(),{RequestContentLengthMismatchError:sv,RequestAbortedError:Zme,SocketError:tg,InformationalError:yA,InvalidArgumentError:$me}=mr(),{kUrl:eg,kReset:fm,kClient:ei,kRunning:rg,kPending:eBe,kQueue:mA,kPendingIdx:av,kRunningIdx:Is,kError:ti,kSocket:or,kStrictContentLength:tBe,kOnError:ll,kMaxConcurrentStreams:am,kPingInterval:e7,kHTTP2Session:la,kHTTP2InitialWindowSize:rBe,kHTTP2ConnectionWindowSize:nBe,kResume:Eo,kSize:iBe,kHTTPContext:Av,kClosed:ov,kBodyTimeout:sBe,kEnableConnectProtocol:Zd,kRemoteSettings:$d,kHTTP2Stream:om,kHTTP2SessionState:fv}=Dn(),{channels:t7}=ed(),Mi=Symbol("open streams"),r7,Am;try{Am=$H()}catch{Am={constants:{}}}var{constants:{HTTP2_HEADER_AUTHORITY:oBe,HTTP2_HEADER_METHOD:n7,HTTP2_HEADER_PATH:i7,HTTP2_HEADER_SCHEME:rv,HTTP2_HEADER_CONTENT_LENGTH:aBe,HTTP2_HEADER_EXPECT:ABe,HTTP2_HEADER_STATUS:nv,HTTP2_HEADER_PROTOCOL:fBe,NGHTTP2_REFUSED_STREAM:uBe,NGHTTP2_CANCEL:cBe}}=Am;function iv(e){let t=[];for(let[r,n]of Object.entries(e))if(Array.isArray(n))for(let i of n)t.push(Buffer.from(r),Buffer.from(i));else t.push(Buffer.from(r),Buffer.from(n));return t}function lBe(e,t){e[or]=t;let r=e[rBe],n=e[nBe],i=Am.connect(e[eg],{createConnection:()=>t,peerMaxConcurrentStreams:e[am],settings:{enablePush:!1,...r!=null?{initialWindowSize:r}:null}});return e[or]=t,i[Mi]=0,i[ei]=e,i[or]=t,i[fv]={ping:{interval:e[e7]===0?null:setInterval(pBe,e[e7],i).unref()}},i[Zd]=!1,i[$d]=!1,n&&ct.addListener(i,"connect",dBe.bind(i,n)),ct.addListener(i,"error",EBe),ct.addListener(i,"frameError",yBe),ct.addListener(i,"end",mBe),ct.addListener(i,"goaway",BBe),ct.addListener(i,"close",IBe),ct.addListener(i,"remoteSettings",gBe),i.unref(),e[la]=i,t[la]=i,ct.addListener(t,"error",CBe),ct.addListener(t,"end",QBe),ct.addListener(t,"close",bBe),t[ov]=!1,t.on("close",wBe),{version:"h2",defaultPipelining:1/0,write(s){return _Be(e,s)},resume(){hBe(e)},destroy(s,o){t[ov]?queueMicrotask(o):t.destroy(s).on("close",o)},get destroyed(){return t.destroyed},busy(s){if(s!=null)if(e[rg]>0){if(s.idempotent===!1||(s.upgrade==="websocket"||s.method==="CONNECT")&&i[$d]===!1||ct.bodyLength(s.body)!==0&&(ct.isStream(s.body)||ct.isAsyncIterable(s.body)||ct.isFormDataLike(s.body)))return!0}else return(s.upgrade==="websocket"||s.method==="CONNECT")&&i[$d]===!1;return!1}}}function hBe(e){let t=e[or];t?.destroyed===!1&&(e[iBe]===0||e[am]===0?(t.unref(),e[la].unref()):(t.ref(),e[la].ref()))}function dBe(e){try{typeof this.setLocalWindowSize=="function"&&this.setLocalWindowSize(e)}catch{}}function gBe(e){if(this[ei][am]=e.maxConcurrentStreams??this[ei][am],this[$d]===!0&&this[Zd]===!0&&e.enableConnectProtocol===!1){let t=new yA("HTTP/2: Server disabled extended CONNECT protocol against RFC-8441");this[or][ti]=t,this[ei][ll](t);return}this[Zd]=e.enableConnectProtocol??this[Zd],this[$d]=!0,this[ei][Eo]()}function pBe(e){let t=e[fv];if((e.closed||e.destroyed)&&t.ping.interval!=null){clearInterval(t.ping.interval),t.ping.interval=null;return}e.ping(r.bind(e));function r(n,i){let s=this[ei],o=this[ei];if(n!=null){let a=new yA(`HTTP/2: "PING" errored - type ${n.message}`);o[ti]=a,s[ll](a)}else s.emit("ping",i)}}function EBe(e){Fi(e.code!=="ERR_TLS_CERT_ALTNAME_INVALID"),this[or][ti]=e,this[ei][ll](e)}function yBe(e,t,r){if(r===0){let n=new yA(`HTTP/2: "frameError" received - type ${e}, code ${t}`);this[or][ti]=n,this[ei][ll](n)}}function mBe(){let e=new tg("other side closed",ct.getSocketInfo(this[or]));this.destroy(e),ct.destroy(this[or],e)}function BBe(e){let t=this[ti]||new tg(`HTTP/2: "GOAWAY" frame received with code ${e}`,ct.getSocketInfo(this[or])),r=this[ei];if(r[or]=null,r[Av]=null,this.close(),this[la]=null,ct.destroy(this[or],t),r[Is]{t.aborted||t.completed||(se=se||new Zme,ct.errorRequest(e,t,se),_!=null&&(_.removeAllListeners("data"),_.close(),e[ll](se),e[Eo]()),ct.destroy(I,se))};try{t.onConnect(x)}catch(se){ct.errorRequest(e,t,se)}if(t.aborted)return!1;if(a||i==="CONNECT")return n.ref(),a==="websocket"?n[Zd]===!1?(ct.errorRequest(e,t,new yA("HTTP/2: Extended CONNECT protocol not supported by server")),n.unref(),!1):(S[n7]="CONNECT",S[fBe]="websocket",S[i7]=s,l==="ws:"||l==="wss:"?S[rv]=l==="ws:"?"http":"https":S[rv]=l==="http:"?"http":"https",_=n.request(S,{endStream:!1,signal:f}),_[om]=!0,_.once("response",(se,ie)=>{let{[nv]:ce,...H}=se;t.onUpgrade(ce,iv(H),_),++n[Mi],e[mA][e[Is]++]=null}),_.on("error",()=>{(_.rstCode===uBe||_.rstCode===cBe)&&x(new yA(`HTTP/2: "stream error" received - code ${_.rstCode}`))}),_.once("close",()=>{n[Mi]-=1,n[Mi]===0&&n.unref()}),_.setTimeout(r),!0):(_=n.request(S,{endStream:!1,signal:f}),_[om]=!0,_.on("response",se=>{let{[nv]:ie,...ce}=se;t.onUpgrade(ie,iv(ce),_),++n[Mi],e[mA][e[Is]++]=null}),_.once("close",()=>{n[Mi]-=1,n[Mi]===0&&n.unref()}),_.setTimeout(r),!0);S[i7]=s,S[rv]=l==="http:"?"http":"https";let G=i==="PUT"||i==="POST"||i==="PATCH";I&&typeof I.read=="function"&&I.read(0);let Y=ct.bodyLength(I);if(ct.isFormDataLike(I)){r7??(r7=Al().extractBody);let[se,ie]=r7(I);S["content-type"]=ie,I=se.stream,Y=se.length}if(Y==null&&(Y=t.contentLength),G||(Y=null),SBe(i)&&Y>0&&t.contentLength!=null&&t.contentLength!==Y){if(e[tBe])return ct.errorRequest(e,t,new sv),!1;process.emitWarning(new sv)}if(Y!=null&&(Fi(I||Y===0,"no body must not have content length"),S[aBe]=`${Y}`),n.ref(),t7.sendHeaders.hasSubscribers){let se="";for(let ie in S)se+=`${ie}: ${S[ie]}\r -`;t7.sendHeaders.publish({request:t,headers:se,socket:n[or]})}let X=i==="GET"||i==="HEAD"||I===null;A?(S[ABe]="100-continue",_=n.request(S,{endStream:X,signal:f}),_[om]=!0,_.once("continue",j)):(_=n.request(S,{endStream:X,signal:f}),_[om]=!0,j()),++n[Mi],_.setTimeout(r);let Z=!1;return _.once("response",se=>{let{[nv]:ie,...ce}=se;if(t.onResponseStarted(),Z=!0,t.aborted){_.removeAllListeners("data");return}t.onHeaders(Number(ie),iv(ce),_.resume.bind(_),"")===!1&&_.pause(),_.on("data",H=>{t.aborted||t.completed||t.onData(H)===!1&&_.pause()})}),_.once("end",()=>{_.removeAllListeners("data"),Z?(!t.aborted&&!t.completed&&t.onComplete({}),e[mA][e[Is]++]=null,e[Eo]()):(x(new yA("HTTP/2: stream half-closed (remote)")),e[mA][e[Is]++]=null,e[av]=e[Is],e[Eo]())}),_.once("close",()=>{_.removeAllListeners("data"),n[Mi]-=1,n[Mi]===0&&n.unref()}),_.once("error",function(se){_.removeAllListeners("data"),x(se)}),_.once("frameError",(se,ie)=>{_.removeAllListeners("data"),x(new yA(`HTTP/2: "frameError" received - type ${se}, code ${ie}`))}),_.on("aborted",()=>{_.removeAllListeners("data")}),_.on("timeout",()=>{let se=new yA(`HTTP/2: "stream timeout after ${r}"`);_.removeAllListeners("data"),n[Mi]-=1,n[Mi]===0&&n.unref(),x(se)}),_.once("trailers",se=>{t.aborted||t.completed||(_.removeAllListeners("data"),t.onComplete(se))}),!0;function j(){!I||Y===0?s7(x,_,null,e,t,e[or],Y,G):ct.isBuffer(I)?s7(x,_,I,e,t,e[or],Y,G):ct.isBlobLike(I)?typeof I.stream=="function"?o7(x,_,I.stream(),e,t,e[or],Y,G):RBe(x,_,I,e,t,e[or],Y,G):ct.isStream(I)?vBe(x,e[or],G,_,I,e,t,Y):ct.isIterable(I)?o7(x,_,I,e,t,e[or],Y,G):Fi(!1)}}function s7(e,t,r,n,i,s,o,a){try{r!=null&&ct.isBuffer(r)&&(Fi(o===r.byteLength,"buffer body must have content length"),t.cork(),t.write(r),t.uncork(),t.end(),i.onBodySent(r)),a||(s[fm]=!0),i.onRequestSent(),n[Eo]()}catch(A){e(A)}}function vBe(e,t,r,n,i,s,o,a){Fi(a!==0||s[rg]===0,"stream body cannot be pipelined");let A=Xme(i,n,l=>{l?(ct.destroy(A,l),e(l)):(ct.removeAllListeners(A),o.onRequestSent(),r||(t[fm]=!0),s[Eo]())});ct.addListener(A,"data",f);function f(l){o.onBodySent(l)}}async function RBe(e,t,r,n,i,s,o,a){Fi(o===r.size,"blob body must have content length");try{if(o!=null&&o!==r.size)throw new sv;let A=Buffer.from(await r.arrayBuffer());t.cork(),t.write(A),t.uncork(),t.end(),i.onBodySent(A),i.onRequestSent(),a||(s[fm]=!0),n[Eo]()}catch(A){e(A)}}async function o7(e,t,r,n,i,s,o,a){Fi(o!==0||n[rg]===0,"iterator body cannot be pipelined");let A=null;function f(){if(A){let p=A;A=null,p()}}let l=()=>new Promise((p,I)=>{Fi(A===null),s[ti]?I(s[ti]):A=p});t.on("close",f).on("drain",f);try{for await(let p of r){if(s[ti])throw s[ti];let I=t.write(p);i.onBodySent(p),I||await l()}t.end(),i.onRequestSent(),a||(s[fm]=!0),n[Eo]()}catch(p){e(p)}finally{t.off("close",f).off("drain",f)}}a7.exports=lBe});var cm=U((_Fe,p7)=>{"use strict";var ha=Gt(),l7=AE(),ng=aE(),Kf=Zt(),{ClientStats:DBe}=YQ(),{channels:hl}=ed(),TBe=J6(),NBe=bE(),{InvalidArgumentError:er,InformationalError:MBe,ClientDestroyedError:FBe}=mr(),kBe=sw(),{kUrl:yo,kServerName:bA,kClient:UBe,kBusy:cv,kConnect:xBe,kResuming:Xf,kRunning:ag,kPending:Ag,kSize:ig,kQueue:bs,kConnected:LBe,kConnecting:dl,kNeedDrain:IA,kKeepAliveDefaultTimeout:f7,kHostHeader:PBe,kPendingIdx:Cs,kRunningIdx:ga,kError:OBe,kPipelining:um,kKeepAliveTimeoutValue:HBe,kMaxHeadersSize:qBe,kKeepAliveMaxTimeout:GBe,kKeepAliveTimeoutThreshold:YBe,kHeadersTimeout:WBe,kBodyTimeout:VBe,kStrictContentLength:JBe,kConnector:sg,kMaxRequests:lv,kCounter:jBe,kClose:zBe,kDestroy:KBe,kDispatch:XBe,kLocalAddress:og,kMaxResponseSize:ZBe,kOnError:$Be,kHTTPContext:dr,kMaxConcurrentStreams:eIe,kHTTP2InitialWindowSize:tIe,kHTTP2ConnectionWindowSize:rIe,kResume:da,kPingInterval:nIe}=Dn(),iIe=KH(),sIe=A7(),BA=Symbol("kClosedResolve"),oIe=ng&&ng.maxHeaderSize&&Number.isInteger(ng.maxHeaderSize)&&ng.maxHeaderSize>0?()=>ng.maxHeaderSize:()=>{throw new er("http module not available or http.maxHeaderSize invalid")},u7=()=>{};function h7(e){return e[um]??e[dr]?.defaultPipelining??1}var hv=class extends NBe{constructor(t,{maxHeaderSize:r,headersTimeout:n,socketTimeout:i,requestTimeout:s,connectTimeout:o,bodyTimeout:a,idleTimeout:A,keepAlive:f,keepAliveTimeout:l,maxKeepAliveTimeout:p,keepAliveMaxTimeout:I,keepAliveTimeoutThreshold:S,socketPath:_,pipelining:N,tls:O,strictContentLength:x,maxCachedSessions:G,connect:Y,maxRequestsPerClient:X,localAddress:Z,maxResponseSize:j,autoSelectFamily:se,autoSelectFamilyAttemptTimeout:ie,maxConcurrentStreams:ce,allowH2:H,useH2c:E,initialWindowSize:v,connectionWindowSize:b,pingInterval:c}={}){if(f!==void 0)throw new er("unsupported keepAlive, use pipelining=0 instead");if(i!==void 0)throw new er("unsupported socketTimeout, use headersTimeout & bodyTimeout instead");if(s!==void 0)throw new er("unsupported requestTimeout, use headersTimeout & bodyTimeout instead");if(A!==void 0)throw new er("unsupported idleTimeout, use keepAliveTimeout instead");if(p!==void 0)throw new er("unsupported maxKeepAliveTimeout, use keepAliveMaxTimeout instead");if(r!=null){if(!Number.isInteger(r)||r<1)throw new er("invalid maxHeaderSize")}else r=oIe();if(_!=null&&typeof _!="string")throw new er("invalid socketPath");if(o!=null&&(!Number.isFinite(o)||o<0))throw new er("invalid connectTimeout");if(l!=null&&(!Number.isFinite(l)||l<=0))throw new er("invalid keepAliveTimeout");if(I!=null&&(!Number.isFinite(I)||I<=0))throw new er("invalid keepAliveMaxTimeout");if(S!=null&&!Number.isFinite(S))throw new er("invalid keepAliveTimeoutThreshold");if(n!=null&&(!Number.isInteger(n)||n<0))throw new er("headersTimeout must be a positive integer or zero");if(a!=null&&(!Number.isInteger(a)||a<0))throw new er("bodyTimeout must be a positive integer or zero");if(Y!=null&&typeof Y!="function"&&typeof Y!="object")throw new er("connect must be a function or an object");if(X!=null&&(!Number.isInteger(X)||X<0))throw new er("maxRequestsPerClient must be a positive number");if(Z!=null&&(typeof Z!="string"||l7.isIP(Z)===0))throw new er("localAddress must be valid string IP address");if(j!=null&&(!Number.isInteger(j)||j<-1))throw new er("maxResponseSize must be a positive number");if(ie!=null&&(!Number.isInteger(ie)||ie<-1))throw new er("autoSelectFamilyAttemptTimeout must be a positive number");if(H!=null&&typeof H!="boolean")throw new er("allowH2 must be a valid boolean value");if(ce!=null&&(typeof ce!="number"||ce<1))throw new er("maxConcurrentStreams must be a positive integer, greater than 0");if(E!=null&&typeof E!="boolean")throw new er("useH2c must be a valid boolean value");if(v!=null&&(!Number.isInteger(v)||v<1))throw new er("initialWindowSize must be a positive integer, greater than 0");if(b!=null&&(!Number.isInteger(b)||b<1))throw new er("connectionWindowSize must be a positive integer, greater than 0");if(c!=null&&(typeof c!="number"||!Number.isInteger(c)||c<0))throw new er("pingInterval must be a positive integer, greater or equal to 0");if(super(),typeof Y!="function")Y=kBe({...O,maxCachedSessions:G,allowH2:H,useH2c:E,socketPath:_,timeout:o,...typeof se=="boolean"?{autoSelectFamily:se,autoSelectFamilyAttemptTimeout:ie}:void 0,...Y});else if(_!=null){let g=Y;Y=(w,R)=>g({...w,socketPath:_},R)}this[yo]=Kf.parseOrigin(t),this[sg]=Y,this[um]=N??1,this[qBe]=r,this[f7]=l??4e3,this[GBe]=I??6e5,this[YBe]=S??2e3,this[HBe]=this[f7],this[bA]=null,this[og]=Z??null,this[Xf]=0,this[IA]=0,this[PBe]=`host: ${this[yo].hostname}${this[yo].port?`:${this[yo].port}`:""}\r -`,this[VBe]=a??3e5,this[WBe]=n??3e5,this[JBe]=x??!0,this[lv]=X,this[BA]=null,this[ZBe]=j>-1?j:-1,this[dr]=null,this[eIe]=ce??100,this[tIe]=v??262144,this[rIe]=b??524288,this[nIe]=c??6e4,this[bs]=[],this[ga]=0,this[Cs]=0,this[da]=g=>dv(this,g),this[$Be]=g=>d7(this,g)}get pipelining(){return this[um]}set pipelining(t){this[um]=t,this[da](!0)}get stats(){return new DBe(this)}get[Ag](){return this[bs].length-this[Cs]}get[ag](){return this[Cs]-this[ga]}get[ig](){return this[bs].length-this[ga]}get[LBe](){return!!this[dr]&&!this[dl]&&!this[dr].destroyed}get[cv](){return!!(this[dr]?.busy(null)||this[ig]>=(h7(this)||1)||this[Ag]>0)}[xBe](t){g7(this),this.once("connect",t)}[XBe](t,r){let n=new TBe(this[yo].origin,t,r);return this[bs].push(n),this[Xf]||(Kf.bodyLength(n.body)==null&&Kf.isIterable(n.body)?(this[Xf]=1,queueMicrotask(()=>dv(this))):this[da](!0)),this[Xf]&&this[IA]!==2&&this[cv]&&(this[IA]=2),this[IA]<2}[zBe](){return new Promise(t=>{this[ig]?this[BA]=t:t(null)})}[KBe](t){return new Promise(r=>{let n=this[bs].splice(this[Cs]);for(let s=0;s{this[BA]&&(this[BA](),this[BA]=null),r(null)};this[dr]?(this[dr].destroy(t,i),this[dr]=null):queueMicrotask(i),this[da]()})}};function d7(e,t){if(e[ag]===0&&t.code!=="UND_ERR_INFO"&&t.code!=="UND_ERR_SOCKET"){ha(e[Cs]===e[ga]);let r=e[bs].splice(e[ga]);for(let n=0;n{if(s){uv(e,s,{host:t,hostname:r,protocol:n,port:i}),e[da]();return}if(e.destroyed){Kf.destroy(o.on("error",u7),new FBe),e[da]();return}ha(o);try{e[dr]=o.alpnProtocol==="h2"?sIe(e,o):iIe(e,o)}catch(a){o.destroy().on("error",u7),uv(e,a,{host:t,hostname:r,protocol:n,port:i}),e[da]();return}e[dl]=!1,o[jBe]=0,o[lv]=e[lv],o[UBe]=e,o[OBe]=null,hl.connected.hasSubscribers&&hl.connected.publish({connectParams:{host:t,hostname:r,protocol:n,port:i,version:e[dr]?.version,servername:e[bA],localAddress:e[og]},connector:e[sg],socket:o}),e.emit("connect",e[yo],[e]),e[da]()})}catch(s){uv(e,s,{host:t,hostname:r,protocol:n,port:i}),e[da]()}}function uv(e,t,{host:r,hostname:n,protocol:i,port:s}){if(!e.destroyed){if(e[dl]=!1,hl.connectError.hasSubscribers&&hl.connectError.publish({connectParams:{host:r,hostname:n,protocol:i,port:s,version:e[dr]?.version,servername:e[bA],localAddress:e[og]},connector:e[sg],error:t}),t.code==="ERR_TLS_CERT_ALTNAME_INVALID")for(ha(e[ag]===0);e[Ag]>0&&e[bs][e[Cs]].servername===e[bA];){let o=e[bs][e[Cs]++];Kf.errorRequest(e,o,t)}else d7(e,t);e.emit("connectionError",e[yo],[e],t)}}function c7(e){e[IA]=0,e.emit("drain",e[yo],[e])}function dv(e,t){e[Xf]!==2&&(e[Xf]=2,aIe(e,t),e[Xf]=0,e[ga]>256&&(e[bs].splice(0,e[ga]),e[Cs]-=e[ga],e[ga]=0))}function aIe(e,t){for(;;){if(e.destroyed){ha(e[Ag]===0);return}if(e[BA]&&!e[ig]){e[BA](),e[BA]=null;return}if(e[dr]&&e[dr].resume(),e[cv])e[IA]=2;else if(e[IA]===2){t?(e[IA]=1,queueMicrotask(()=>c7(e))):c7(e);continue}if(e[Ag]===0||e[ag]>=(h7(e)||1))return;let r=e[bs][e[Cs]];if(r===null)return;if(e[yo].protocol==="https:"&&e[bA]!==r.servername){if(e[ag]>0)return;e[bA]=r.servername,e[dr]?.destroy(new MBe("servername changed"),()=>{e[dr]=null,dv(e)})}if(e[dl])return;if(!e[dr]){g7(e);return}if(e[dr].destroyed||e[dr].busy(r))return;!r.aborted&&e[dr].write(r)?e[Cs]++:e[bs].splice(e[Cs],1)}}p7.exports=hv});var I7=U((vFe,B7)=>{"use strict";var{PoolBase:AIe,kClients:lm,kNeedDrain:fIe,kAddClient:uIe,kGetDispatcher:cIe,kRemoveClient:lIe}=P6(),hIe=cm(),{InvalidArgumentError:gv}=mr(),E7=Zt(),{kUrl:y7}=Dn(),dIe=sw(),hm=Symbol("options"),pv=Symbol("connections"),m7=Symbol("factory");function gIe(e,t){return new hIe(e,t)}var Ev=class extends AIe{constructor(t,{connections:r,factory:n=gIe,connect:i,connectTimeout:s,tls:o,maxCachedSessions:a,socketPath:A,autoSelectFamily:f,autoSelectFamilyAttemptTimeout:l,allowH2:p,clientTtl:I,...S}={}){if(r!=null&&(!Number.isFinite(r)||r<0))throw new gv("invalid connections");if(typeof n!="function")throw new gv("factory must be a function.");if(i!=null&&typeof i!="function"&&typeof i!="object")throw new gv("connect must be a function or an object");typeof i!="function"&&(i=dIe({...o,maxCachedSessions:a,allowH2:p,socketPath:A,timeout:s,...typeof f=="boolean"?{autoSelectFamily:f,autoSelectFamilyAttemptTimeout:l}:void 0,...i})),super(),this[pv]=r||null,this[y7]=E7.parseOrigin(t),this[hm]={...E7.deepClone(S),connect:i,allowH2:p,clientTtl:I,socketPath:A},this[hm].interceptors=S.interceptors?{...S.interceptors}:void 0,this[m7]=n,this.on("connect",(_,N)=>{if(I!=null&&I>0)for(let O of N)Object.assign(O,{ttl:Date.now()})}),this.on("connectionError",(_,N,O)=>{for(let x of N){let G=this[lm].indexOf(x);G!==-1&&this[lm].splice(G,1)}})}[cIe](){let t=this[hm].clientTtl;for(let r of this[lm])if(t!=null&&t>0&&r.ttl&&Date.now()-r.ttl>t)this[lIe](r);else if(!r[fIe])return r;if(!this[pv]||this[lm].length{"use strict";var{InvalidArgumentError:dm,MaxOriginsReachedError:pIe}=mr(),{kClients:ki,kRunning:b7,kClose:EIe,kDestroy:yIe,kDispatch:mIe,kUrl:BIe}=Dn(),IIe=bE(),bIe=I7(),CIe=cm(),QIe=Zt(),C7=Symbol("onConnect"),Q7=Symbol("onDisconnect"),w7=Symbol("onConnectionError"),S7=Symbol("onDrain"),_7=Symbol("factory"),yv=Symbol("options"),fg=Symbol("origins");function wIe(e,t){return t&&t.connections===1?new CIe(e,t):new bIe(e,t)}var mv=class extends IIe{constructor({factory:t=wIe,maxOrigins:r=1/0,connect:n,...i}={}){if(typeof t!="function")throw new dm("factory must be a function.");if(n!=null&&typeof n!="function"&&typeof n!="object")throw new dm("connect must be a function or an object");if(typeof r!="number"||Number.isNaN(r)||r<=0)throw new dm("maxOrigins must be a number greater than 0");super(),n&&typeof n!="function"&&(n={...n}),this[yv]={...QIe.deepClone(i),maxOrigins:r,connect:n},this[_7]=t,this[ki]=new Map,this[fg]=new Set,this[S7]=(s,o)=>{this.emit("drain",s,[this,...o])},this[C7]=(s,o)=>{this.emit("connect",s,[this,...o])},this[Q7]=(s,o,a)=>{this.emit("disconnect",s,[this,...o],a)},this[w7]=(s,o,a)=>{this.emit("connectionError",s,[this,...o],a)}}get[b7](){let t=0;for(let{dispatcher:r}of this[ki].values())t+=r[b7];return t}[mIe](t,r){let n;if(t.origin&&(typeof t.origin=="string"||t.origin instanceof URL))n=String(t.origin);else throw new dm("opts.origin must be a non-empty string or URL.");if(this[fg].size>=this[yv].maxOrigins&&!this[fg].has(n))throw new pIe;let i=this[ki].get(n),s=i&&i.dispatcher;if(!s){let o=a=>{let A=this[ki].get(n);A&&(a&&(A.count-=1),A.count<=0&&(this[ki].delete(n),A.dispatcher.destroyed||A.dispatcher.close()),this[fg].delete(n))};s=this[_7](t.origin,this[yv]).on("drain",this[S7]).on("connect",(a,A)=>{let f=this[ki].get(n);f&&(f.count+=1),this[C7](a,A)}).on("disconnect",(a,A,f)=>{o(!0),this[Q7](a,A,f)}).on("connectionError",(a,A,f)=>{o(!1),this[w7](a,A,f)}),this[ki].set(n,{count:0,dispatcher:s}),this[fg].add(n)}return s.dispatch(t,r)}[EIe](){let t=[];for(let{dispatcher:r}of this[ki].values())t.push(r.close());return this[ki].clear(),Promise.all(t)}[yIe](t){let r=[];for(let{dispatcher:n}of this[ki].values())r.push(n.destroy(t));return this[ki].clear(),Promise.all(r)}get stats(){let t={};for(let{dispatcher:r}of this[ki].values())r.stats&&(t[r[BIe].origin]=r.stats);return t}};v7.exports=mv});var cg=U((DFe,k7)=>{"use strict";var{kConstruct:SIe}=Dn(),{kEnumerableProperty:gl}=Zt(),{iteratorMixin:_Ie,isValidHeaderName:ug,isValidHeaderValue:D7}=jf(),{webidl:Bt}=lo(),Iv=Gt(),gm=Yr();function R7(e){return e===10||e===13||e===9||e===32}function T7(e){let t=0,r=e.length;for(;r>t&&R7(e.charCodeAt(r-1));)--r;for(;r>t&&R7(e.charCodeAt(t));)++t;return t===0&&r===e.length?e:e.substring(t,r)}function N7(e,t){if(Array.isArray(t))for(let r=0;r>","record"]})}function bv(e,t,r){if(r=T7(r),ug(t)){if(!D7(r))throw Bt.errors.invalidArgument({prefix:"Headers.append",value:r,type:"header value"})}else throw Bt.errors.invalidArgument({prefix:"Headers.append",value:t,type:"header name"});if(F7(e)==="immutable")throw new TypeError("immutable");return Em(e).append(t,r,!1)}function vIe(e){let t=Em(e);if(!t)return[];if(t.sortedMap)return t.sortedMap;let r=[],n=t.toSortedArray(),i=t.cookies;if(i===null||i.length===1)return t.sortedMap=n;for(let s=0;s>1),r[f][0]<=l[0]?A=f+1:a=f;if(s!==f){for(o=s;o>A;)r[o]=r[--o];r[A]=l}}if(!n.next().done)throw new TypeError("Unreachable");return r}else{let n=0;for(let{0:i,1:{value:s}}of this.headersMap)r[n++]=[i,s],Iv(s!==null);return r.sort(M7)}}},QA,ri,CA=class CA{constructor(t=void 0){wt(this,QA);wt(this,ri);Bt.util.markAsUncloneable(this),t!==SIe&&(ft(this,ri,new pm),ft(this,QA,"none"),t!==void 0&&(t=Bt.converters.HeadersInit(t,"Headers constructor","init"),N7(this,t)))}append(t,r){Bt.brandCheck(this,CA),Bt.argumentLengthCheck(arguments,2,"Headers.append");let n="Headers.append";return t=Bt.converters.ByteString(t,n,"name"),r=Bt.converters.ByteString(r,n,"value"),bv(this,t,r)}delete(t){if(Bt.brandCheck(this,CA),Bt.argumentLengthCheck(arguments,1,"Headers.delete"),t=Bt.converters.ByteString(t,"Headers.delete","name"),!ug(t))throw Bt.errors.invalidArgument({prefix:"Headers.delete",value:t,type:"header name"});if(ee(this,QA)==="immutable")throw new TypeError("immutable");ee(this,ri).contains(t,!1)&&ee(this,ri).delete(t,!1)}get(t){Bt.brandCheck(this,CA),Bt.argumentLengthCheck(arguments,1,"Headers.get");let r="Headers.get";if(t=Bt.converters.ByteString(t,r,"name"),!ug(t))throw Bt.errors.invalidArgument({prefix:r,value:t,type:"header name"});return ee(this,ri).get(t,!1)}has(t){Bt.brandCheck(this,CA),Bt.argumentLengthCheck(arguments,1,"Headers.has");let r="Headers.has";if(t=Bt.converters.ByteString(t,r,"name"),!ug(t))throw Bt.errors.invalidArgument({prefix:r,value:t,type:"header name"});return ee(this,ri).contains(t,!1)}set(t,r){Bt.brandCheck(this,CA),Bt.argumentLengthCheck(arguments,2,"Headers.set");let n="Headers.set";if(t=Bt.converters.ByteString(t,n,"name"),r=Bt.converters.ByteString(r,n,"value"),r=T7(r),ug(t)){if(!D7(r))throw Bt.errors.invalidArgument({prefix:n,value:r,type:"header value"})}else throw Bt.errors.invalidArgument({prefix:n,value:t,type:"header name"});if(ee(this,QA)==="immutable")throw new TypeError("immutable");ee(this,ri).set(t,r,!1)}getSetCookie(){Bt.brandCheck(this,CA);let t=ee(this,ri).cookies;return t?[...t]:[]}[gm.inspect.custom](t,r){return r.depth??(r.depth=t),`Headers ${gm.formatWithOptions(r,ee(this,ri).entries)}`}static getHeadersGuard(t){return ee(t,QA)}static setHeadersGuard(t,r){ft(t,QA,r)}static getHeadersList(t){return ee(t,ri)}static setHeadersList(t,r){ft(t,ri,r)}};QA=new WeakMap,ri=new WeakMap;var Qs=CA,{getHeadersGuard:F7,setHeadersGuard:RIe,getHeadersList:Em,setHeadersList:DIe}=Qs;Reflect.deleteProperty(Qs,"getHeadersGuard");Reflect.deleteProperty(Qs,"setHeadersGuard");Reflect.deleteProperty(Qs,"getHeadersList");Reflect.deleteProperty(Qs,"setHeadersList");_Ie("Headers",Qs,vIe,0,1);Object.defineProperties(Qs.prototype,{append:gl,delete:gl,get:gl,has:gl,set:gl,getSetCookie:gl,[Symbol.toStringTag]:{value:"Headers",configurable:!0},[gm.inspect.custom]:{enumerable:!1}});Bt.converters.HeadersInit=function(e,t,r){if(Bt.util.Type(e)===Bt.util.Types.OBJECT){let n=Reflect.get(e,Symbol.iterator);if(!gm.types.isProxy(e)&&n===Qs.prototype.entries)try{return Em(e).entriesList}catch{}return typeof n=="function"?Bt.converters["sequence>"](e,t,r,n.bind(e)):Bt.converters["record"](e,t,r)}throw Bt.errors.conversionFailed({prefix:"Headers constructor",argument:"Argument 1",types:["sequence>","record"]})};k7.exports={fill:N7,compareHeaderName:M7,Headers:Qs,HeadersList:pm,getHeadersGuard:F7,setHeadersGuard:RIe,setHeadersList:DIe,getHeadersList:Em}});var wv=U((NFe,J7)=>{"use strict";var{Headers:H7,HeadersList:U7,fill:TIe,getHeadersGuard:NIe,setHeadersGuard:q7,setHeadersList:G7}=cg(),{extractBody:x7,cloneBody:MIe,mixinBody:FIe,streamRegistry:Y7,bodyUnusable:kIe}=Al(),W7=Zt(),L7=Yr(),{kEnumerableProperty:ni}=W7,{isValidReasonPhrase:UIe,isCancelled:xIe,isAborted:LIe,isErrorLike:PIe,environmentSettingsObject:OIe}=jf(),{redirectStatusSet:HIe,nullBodyStatus:qIe}=td(),{webidl:yt}=lo(),{URLSerializer:P7}=yf(),{kConstruct:mm}=Dn(),Cv=Gt(),{isomorphicEncode:GIe,serializeJavascriptValueToJSONString:YIe}=Ef(),WIe=new TextEncoder("utf-8"),mo,tr,Ui=class Ui{constructor(t=null,r=void 0){wt(this,mo);wt(this,tr);if(yt.util.markAsUncloneable(this),t===mm)return;t!==null&&(t=yt.converters.BodyInit(t,"Response","body")),r=yt.converters.ResponseInit(r),ft(this,tr,pl({})),ft(this,mo,new H7(mm)),q7(ee(this,mo),"response"),G7(ee(this,mo),ee(this,tr).headersList);let n=null;if(t!=null){let[i,s]=x7(t);n={body:i,type:s}}O7(this,r,n)}static error(){return lg(Bm(),"immutable")}static json(t,r=void 0){yt.argumentLengthCheck(arguments,1,"Response.json"),r!==null&&(r=yt.converters.ResponseInit(r));let n=WIe.encode(YIe(t)),i=x7(n),s=lg(pl({}),"response");return O7(s,r,{body:i[0],type:"application/json"}),s}static redirect(t,r=302){yt.argumentLengthCheck(arguments,1,"Response.redirect"),t=yt.converters.USVString(t),r=yt.converters["unsigned short"](r);let n;try{n=new URL(t,OIe.settingsObject.baseUrl)}catch(o){throw new TypeError(`Failed to parse URL from ${t}`,{cause:o})}if(!HIe.has(r))throw new RangeError(`Invalid status code ${r}`);let i=lg(pl({}),"immutable");ee(i,tr).status=r;let s=GIe(P7(n));return ee(i,tr).headersList.append("location",s,!0),i}get type(){return yt.brandCheck(this,Ui),ee(this,tr).type}get url(){yt.brandCheck(this,Ui);let t=ee(this,tr).urlList,r=t[t.length-1]??null;return r===null?"":P7(r,!0)}get redirected(){return yt.brandCheck(this,Ui),ee(this,tr).urlList.length>1}get status(){return yt.brandCheck(this,Ui),ee(this,tr).status}get ok(){return yt.brandCheck(this,Ui),ee(this,tr).status>=200&&ee(this,tr).status<=299}get statusText(){return yt.brandCheck(this,Ui),ee(this,tr).statusText}get headers(){return yt.brandCheck(this,Ui),ee(this,mo)}get body(){return yt.brandCheck(this,Ui),ee(this,tr).body?ee(this,tr).body.stream:null}get bodyUsed(){return yt.brandCheck(this,Ui),!!ee(this,tr).body&&W7.isDisturbed(ee(this,tr).body.stream)}clone(){if(yt.brandCheck(this,Ui),kIe(ee(this,tr)))throw yt.errors.exception({header:"Response.clone",message:"Body has already been consumed."});let t=Qv(ee(this,tr));return ee(this,tr).urlList.length!==0&&ee(this,tr).body?.stream&&Y7.register(this,new WeakRef(ee(this,tr).body.stream)),lg(t,NIe(ee(this,mo)))}[L7.inspect.custom](t,r){r.depth===null&&(r.depth=2),r.colors??(r.colors=!0);let n={status:this.status,statusText:this.statusText,headers:this.headers,body:this.body,bodyUsed:this.bodyUsed,ok:this.ok,redirected:this.redirected,type:this.type,url:this.url};return`Response ${L7.formatWithOptions(r,n)}`}static getResponseHeaders(t){return ee(t,mo)}static setResponseHeaders(t,r){ft(t,mo,r)}static getResponseState(t){return ee(t,tr)}static setResponseState(t,r){ft(t,tr,r)}};mo=new WeakMap,tr=new WeakMap;var ii=Ui,{getResponseHeaders:VIe,setResponseHeaders:JIe,getResponseState:Zf,setResponseState:jIe}=ii;Reflect.deleteProperty(ii,"getResponseHeaders");Reflect.deleteProperty(ii,"setResponseHeaders");Reflect.deleteProperty(ii,"getResponseState");Reflect.deleteProperty(ii,"setResponseState");FIe(ii,Zf);Object.defineProperties(ii.prototype,{type:ni,url:ni,status:ni,ok:ni,redirected:ni,statusText:ni,headers:ni,clone:ni,body:ni,bodyUsed:ni,[Symbol.toStringTag]:{value:"Response",configurable:!0}});Object.defineProperties(ii,{json:ni,redirect:ni,error:ni});function Qv(e){if(e.internalResponse)return V7(Qv(e.internalResponse),e.type);let t=pl({...e,body:null});return e.body!=null&&(t.body=MIe(e.body)),t}function pl(e){return{aborted:!1,rangeRequested:!1,timingAllowPassed:!1,requestIncludesCredentials:!1,type:"default",status:200,timingInfo:null,cacheState:"",statusText:"",...e,headersList:e?.headersList?new U7(e?.headersList):new U7,urlList:e?.urlList?[...e.urlList]:[]}}function Bm(e){let t=PIe(e);return pl({type:"error",status:0,error:t?e:new Error(e&&String(e)),aborted:e&&e.name==="AbortError"})}function zIe(e){return e.type==="error"&&e.status===0}function ym(e,t){return t={internalResponse:e,...t},new Proxy(e,{get(r,n){return n in t?t[n]:r[n]},set(r,n,i){return Cv(!(n in t)),r[n]=i,!0}})}function V7(e,t){if(t==="basic")return ym(e,{type:"basic",headersList:e.headersList});if(t==="cors")return ym(e,{type:"cors",headersList:e.headersList});if(t==="opaque")return ym(e,{type:"opaque",urlList:[],status:0,statusText:"",body:null});if(t==="opaqueredirect")return ym(e,{type:"opaqueredirect",status:0,statusText:"",headersList:[],body:null});Cv(!1)}function KIe(e,t=null){return Cv(xIe(e)),LIe(e)?Bm(Object.assign(new DOMException("The operation was aborted.","AbortError"),{cause:t})):Bm(Object.assign(new DOMException("Request was cancelled."),{cause:t}))}function O7(e,t,r){if(t.status!==null&&(t.status<200||t.status>599))throw new RangeError('init["status"] must be in the range of 200 to 599, inclusive.');if("statusText"in t&&t.statusText!=null&&!UIe(String(t.statusText)))throw new TypeError("Invalid statusText");if("status"in t&&t.status!=null&&(Zf(e).status=t.status),"statusText"in t&&t.statusText!=null&&(Zf(e).statusText=t.statusText),"headers"in t&&t.headers!=null&&TIe(VIe(e),t.headers),r){if(qIe.includes(e.status))throw yt.errors.exception({header:"Response constructor",message:`Invalid response status code ${e.status}`});Zf(e).body=r.body,r.type!=null&&!Zf(e).headersList.contains("content-type",!0)&&Zf(e).headersList.append("content-type",r.type,!0)}}function lg(e,t){let r=new ii(mm);jIe(r,e);let n=new H7(mm);return JIe(r,n),G7(n,e.headersList),q7(n,t),e.urlList.length!==0&&e.body?.stream&&Y7.register(r,new WeakRef(e.body.stream)),r}yt.converters.XMLHttpRequestBodyInit=function(e,t,r){return typeof e=="string"?yt.converters.USVString(e,t,r):yt.is.Blob(e)||yt.is.BufferSource(e)||yt.is.FormData(e)||yt.is.URLSearchParams(e)?e:yt.converters.DOMString(e,t,r)};yt.converters.BodyInit=function(e,t,r){return yt.is.ReadableStream(e)||e?.[Symbol.asyncIterator]?e:yt.converters.XMLHttpRequestBodyInit(e,t,r)};yt.converters.ResponseInit=yt.dictionaryConverter([{key:"status",converter:yt.converters["unsigned short"],defaultValue:()=>200},{key:"statusText",converter:yt.converters.ByteString,defaultValue:()=>""},{key:"headers",converter:yt.converters.HeadersInit}]);yt.is.Response=yt.util.MakeTypeAssertion(ii);J7.exports={isNetworkError:zIe,makeNetworkError:Bm,makeResponse:pl,makeAppropriateNetworkError:KIe,filterResponse:V7,Response:ii,cloneResponse:Qv,fromInnerResponse:lg,getResponseState:Zf}});var vv=U((FFe,aq)=>{"use strict";var{extractBody:XIe,mixinBody:ZIe,cloneBody:$Ie,bodyUnusable:j7}=Al(),{Headers:eq,fill:ebe,HeadersList:Cm,setHeadersGuard:Sv,getHeadersGuard:tbe,setHeadersList:tq,getHeadersList:z7}=cg(),bm=Zt(),K7=Yr(),{isValidHTTPToken:rbe,sameOrigin:X7,environmentSettingsObject:Im}=jf(),{forbiddenMethodsSet:nbe,corsSafeListedMethodsSet:ibe,referrerPolicy:sbe,requestRedirect:obe,requestMode:abe,requestCredentials:Abe,requestCache:fbe,requestDuplex:ube}=td(),{kEnumerableProperty:br,normalizedMethodRecordsBase:cbe,normalizedMethodRecords:lbe}=bm,{webidl:Fe}=lo(),{URLSerializer:hbe}=yf(),{kConstruct:Qm}=Dn(),dbe=Gt(),{getMaxListeners:rq,setMaxListeners:gbe,defaultMaxListeners:pbe}=Zi(),Ebe=Symbol("abortController"),nq=new FinalizationRegistry(({signal:e,abort:t})=>{e.removeEventListener("abort",t)}),wm=new WeakMap,_v;try{_v=rq(new AbortController().signal)>0}catch{_v=!1}function Z7(e){return t;function t(){let r=e.deref();if(r!==void 0){nq.unregister(t),this.removeEventListener("abort",t),r.abort(this.reason);let n=wm.get(r.signal);if(n!==void 0){if(n.size!==0){for(let i of n){let s=i.deref();s!==void 0&&s.abort(this.reason)}n.clear()}wm.delete(r.signal)}}}}var $7=!1,$f,pa,Ln,vt,gr=class gr{constructor(t,r=void 0){wt(this,$f);wt(this,pa);wt(this,Ln);wt(this,vt);if(Fe.util.markAsUncloneable(this),t===Qm)return;Fe.argumentLengthCheck(arguments,1,"Request constructor"),t=Fe.converters.RequestInfo(t),r=Fe.converters.RequestInit(r);let i=null,s=null,o=Im.settingsObject.baseUrl,a=null;if(typeof t=="string"){ft(this,pa,r.dispatcher);let x;try{x=new URL(t,o)}catch(G){throw new TypeError("Failed to parse URL from "+t,{cause:G})}if(x.username||x.password)throw new TypeError("Request cannot be constructed from a URL that includes credentials: "+t);i=Sm({urlList:[x]}),s="cors"}else dbe(Fe.is.Request(t)),i=ee(t,vt),a=ee(t,$f),ft(this,pa,r.dispatcher||ee(t,pa));let A=Im.settingsObject.origin,f="client";if(i.window?.constructor?.name==="EnvironmentSettingsObject"&&X7(i.window,A)&&(f=i.window),r.window!=null)throw new TypeError(`'window' option '${f}' must be null`);"window"in r&&(f="no-window"),i=Sm({method:i.method,headersList:i.headersList,unsafeRequest:i.unsafeRequest,client:Im.settingsObject,window:f,priority:i.priority,origin:i.origin,referrer:i.referrer,referrerPolicy:i.referrerPolicy,mode:i.mode,credentials:i.credentials,cache:i.cache,redirect:i.redirect,integrity:i.integrity,keepalive:i.keepalive,reloadNavigation:i.reloadNavigation,historyNavigation:i.historyNavigation,urlList:[...i.urlList]});let l=Object.keys(r).length!==0;if(l&&(i.mode==="navigate"&&(i.mode="same-origin"),i.reloadNavigation=!1,i.historyNavigation=!1,i.origin="client",i.referrer="client",i.referrerPolicy="",i.url=i.urlList[i.urlList.length-1],i.urlList=[i.url]),r.referrer!==void 0){let x=r.referrer;if(x==="")i.referrer="no-referrer";else{let G;try{G=new URL(x,o)}catch(Y){throw new TypeError(`Referrer "${x}" is not a valid URL.`,{cause:Y})}G.protocol==="about:"&&G.hostname==="client"||A&&!X7(G,Im.settingsObject.baseUrl)?i.referrer="client":i.referrer=G}}r.referrerPolicy!==void 0&&(i.referrerPolicy=r.referrerPolicy);let p;if(r.mode!==void 0?p=r.mode:p=s,p==="navigate")throw Fe.errors.exception({header:"Request constructor",message:"invalid request mode navigate."});if(p!=null&&(i.mode=p),r.credentials!==void 0&&(i.credentials=r.credentials),r.cache!==void 0&&(i.cache=r.cache),i.cache==="only-if-cached"&&i.mode!=="same-origin")throw new TypeError("'only-if-cached' can be set only with 'same-origin' mode");if(r.redirect!==void 0&&(i.redirect=r.redirect),r.integrity!=null&&(i.integrity=String(r.integrity)),r.keepalive!==void 0&&(i.keepalive=!!r.keepalive),r.method!==void 0){let x=r.method,G=lbe[x];if(G!==void 0)i.method=G;else{if(!rbe(x))throw new TypeError(`'${x}' is not a valid HTTP method.`);let Y=x.toUpperCase();if(nbe.has(Y))throw new TypeError(`'${x}' HTTP method is unsupported.`);x=cbe[Y]??x,i.method=x}!$7&&i.method==="patch"&&(process.emitWarning("Using `patch` is highly likely to result in a `405 Method Not Allowed`. `PATCH` is much more likely to succeed.",{code:"UNDICI-FETCH-patch"}),$7=!0)}r.signal!==void 0&&(a=r.signal),ft(this,vt,i);let I=new AbortController;if(ft(this,$f,I.signal),a!=null)if(a.aborted)I.abort(a.reason);else{this[Ebe]=I;let x=new WeakRef(I),G=Z7(x);_v&&rq(a)===pbe&&gbe(1500,a),bm.addAbortListener(a,G),nq.register(I,{signal:a,abort:G},G)}if(ft(this,Ln,new eq(Qm)),tq(ee(this,Ln),i.headersList),Sv(ee(this,Ln),"request"),p==="no-cors"){if(!ibe.has(i.method))throw new TypeError(`'${i.method} is unsupported in no-cors mode.`);Sv(ee(this,Ln),"request-no-cors")}if(l){let x=z7(ee(this,Ln)),G=r.headers!==void 0?r.headers:new Cm(x);if(x.clear(),G instanceof Cm){for(let{name:Y,value:X}of G.rawValues())x.append(Y,X,!1);x.cookies=G.cookies}else ebe(ee(this,Ln),G)}let S=Fe.is.Request(t)?ee(t,vt).body:null;if((r.body!=null||S!=null)&&(i.method==="GET"||i.method==="HEAD"))throw new TypeError("Request with GET/HEAD method cannot have body.");let _=null;if(r.body!=null){let[x,G]=XIe(r.body,i.keepalive);_=x,G&&!z7(ee(this,Ln)).contains("content-type",!0)&&ee(this,Ln).append("content-type",G,!0)}let N=_??S;if(N!=null&&N.source==null){if(_!=null&&r.duplex==null)throw new TypeError("RequestInit: duplex option is required when sending a body.");if(i.mode!=="same-origin"&&i.mode!=="cors")throw new TypeError('If request is made from ReadableStream, mode should be "same-origin" or "cors"');i.useCORSPreflightFlag=!0}let O=N;if(_==null&&S!=null){if(j7(ee(t,vt)))throw new TypeError("Cannot construct a Request with a Request object that has already been used.");let x=new TransformStream;S.stream.pipeThrough(x),O={source:S.source,length:S.length,stream:x.readable}}ee(this,vt).body=O}get method(){return Fe.brandCheck(this,gr),ee(this,vt).method}get url(){return Fe.brandCheck(this,gr),hbe(ee(this,vt).url)}get headers(){return Fe.brandCheck(this,gr),ee(this,Ln)}get destination(){return Fe.brandCheck(this,gr),ee(this,vt).destination}get referrer(){return Fe.brandCheck(this,gr),ee(this,vt).referrer==="no-referrer"?"":ee(this,vt).referrer==="client"?"about:client":ee(this,vt).referrer.toString()}get referrerPolicy(){return Fe.brandCheck(this,gr),ee(this,vt).referrerPolicy}get mode(){return Fe.brandCheck(this,gr),ee(this,vt).mode}get credentials(){return Fe.brandCheck(this,gr),ee(this,vt).credentials}get cache(){return Fe.brandCheck(this,gr),ee(this,vt).cache}get redirect(){return Fe.brandCheck(this,gr),ee(this,vt).redirect}get integrity(){return Fe.brandCheck(this,gr),ee(this,vt).integrity}get keepalive(){return Fe.brandCheck(this,gr),ee(this,vt).keepalive}get isReloadNavigation(){return Fe.brandCheck(this,gr),ee(this,vt).reloadNavigation}get isHistoryNavigation(){return Fe.brandCheck(this,gr),ee(this,vt).historyNavigation}get signal(){return Fe.brandCheck(this,gr),ee(this,$f)}get body(){return Fe.brandCheck(this,gr),ee(this,vt).body?ee(this,vt).body.stream:null}get bodyUsed(){return Fe.brandCheck(this,gr),!!ee(this,vt).body&&bm.isDisturbed(ee(this,vt).body.stream)}get duplex(){return Fe.brandCheck(this,gr),"half"}clone(){if(Fe.brandCheck(this,gr),j7(ee(this,vt)))throw new TypeError("unusable");let t=sq(ee(this,vt)),r=new AbortController;if(this.signal.aborted)r.abort(this.signal.reason);else{let n=wm.get(this.signal);n===void 0&&(n=new Set,wm.set(this.signal,n));let i=new WeakRef(r);n.add(i),bm.addAbortListener(r.signal,Z7(i))}return oq(t,ee(this,pa),r.signal,tbe(ee(this,Ln)))}[K7.inspect.custom](t,r){r.depth===null&&(r.depth=2),r.colors??(r.colors=!0);let n={method:this.method,url:this.url,headers:this.headers,destination:this.destination,referrer:this.referrer,referrerPolicy:this.referrerPolicy,mode:this.mode,credentials:this.credentials,cache:this.cache,redirect:this.redirect,integrity:this.integrity,keepalive:this.keepalive,isReloadNavigation:this.isReloadNavigation,isHistoryNavigation:this.isHistoryNavigation,signal:this.signal};return`Request ${K7.formatWithOptions(r,n)}`}static setRequestSignal(t,r){return ft(t,$f,r),t}static getRequestDispatcher(t){return ee(t,pa)}static setRequestDispatcher(t,r){ft(t,pa,r)}static setRequestHeaders(t,r){ft(t,Ln,r)}static getRequestState(t){return ee(t,vt)}static setRequestState(t,r){ft(t,vt,r)}};$f=new WeakMap,pa=new WeakMap,Ln=new WeakMap,vt=new WeakMap;var Pn=gr,{setRequestSignal:ybe,getRequestDispatcher:mbe,setRequestDispatcher:Bbe,setRequestHeaders:Ibe,getRequestState:iq,setRequestState:bbe}=Pn;Reflect.deleteProperty(Pn,"setRequestSignal");Reflect.deleteProperty(Pn,"getRequestDispatcher");Reflect.deleteProperty(Pn,"setRequestDispatcher");Reflect.deleteProperty(Pn,"setRequestHeaders");Reflect.deleteProperty(Pn,"getRequestState");Reflect.deleteProperty(Pn,"setRequestState");ZIe(Pn,iq);function Sm(e){return{method:e.method??"GET",localURLsOnly:e.localURLsOnly??!1,unsafeRequest:e.unsafeRequest??!1,body:e.body??null,client:e.client??null,reservedClient:e.reservedClient??null,replacesClientId:e.replacesClientId??"",window:e.window??"client",keepalive:e.keepalive??!1,serviceWorkers:e.serviceWorkers??"all",initiator:e.initiator??"",destination:e.destination??"",priority:e.priority??null,origin:e.origin??"client",policyContainer:e.policyContainer??"client",referrer:e.referrer??"client",referrerPolicy:e.referrerPolicy??"",mode:e.mode??"no-cors",useCORSPreflightFlag:e.useCORSPreflightFlag??!1,credentials:e.credentials??"same-origin",useCredentials:e.useCredentials??!1,cache:e.cache??"default",redirect:e.redirect??"follow",integrity:e.integrity??"",cryptoGraphicsNonceMetadata:e.cryptoGraphicsNonceMetadata??"",parserMetadata:e.parserMetadata??"",reloadNavigation:e.reloadNavigation??!1,historyNavigation:e.historyNavigation??!1,userActivation:e.userActivation??!1,taintedOrigin:e.taintedOrigin??!1,redirectCount:e.redirectCount??0,responseTainting:e.responseTainting??"basic",preventNoCacheCacheControlHeaderModification:e.preventNoCacheCacheControlHeaderModification??!1,done:e.done??!1,timingAllowFailed:e.timingAllowFailed??!1,useURLCredentials:e.useURLCredentials??void 0,traversableForUserPrompts:e.traversableForUserPrompts??"client",urlList:e.urlList,url:e.urlList[0],headersList:e.headersList?new Cm(e.headersList):new Cm}}function sq(e){let t=Sm({...e,body:null});return e.body!=null&&(t.body=$Ie(e.body)),t}function oq(e,t,r,n){let i=new Pn(Qm);bbe(i,e),Bbe(i,t),ybe(i,r);let s=new eq(Qm);return Ibe(i,s),tq(s,e.headersList),Sv(s,n),i}Object.defineProperties(Pn.prototype,{method:br,url:br,headers:br,redirect:br,clone:br,signal:br,duplex:br,destination:br,body:br,bodyUsed:br,isHistoryNavigation:br,isReloadNavigation:br,keepalive:br,integrity:br,cache:br,credentials:br,attribute:br,referrerPolicy:br,referrer:br,mode:br,[Symbol.toStringTag]:{value:"Request",configurable:!0}});Fe.is.Request=Fe.util.MakeTypeAssertion(Pn);Fe.converters.RequestInfo=function(e){return typeof e=="string"?Fe.converters.USVString(e):Fe.is.Request(e)?e:Fe.converters.USVString(e)};Fe.converters.RequestInit=Fe.dictionaryConverter([{key:"method",converter:Fe.converters.ByteString},{key:"headers",converter:Fe.converters.HeadersInit},{key:"body",converter:Fe.nullableConverter(Fe.converters.BodyInit)},{key:"referrer",converter:Fe.converters.USVString},{key:"referrerPolicy",converter:Fe.converters.DOMString,allowedValues:sbe},{key:"mode",converter:Fe.converters.DOMString,allowedValues:abe},{key:"credentials",converter:Fe.converters.DOMString,allowedValues:Abe},{key:"cache",converter:Fe.converters.DOMString,allowedValues:fbe},{key:"redirect",converter:Fe.converters.DOMString,allowedValues:obe},{key:"integrity",converter:Fe.converters.DOMString},{key:"keepalive",converter:Fe.converters.boolean},{key:"signal",converter:Fe.nullableConverter(e=>Fe.converters.AbortSignal(e,"RequestInit","signal"))},{key:"window",converter:Fe.converters.any},{key:"duplex",converter:Fe.converters.DOMString,allowedValues:ube},{key:"dispatcher",converter:Fe.converters.any},{key:"priority",converter:Fe.converters.DOMString,allowedValues:["high","low","auto"],defaultValue:()=>"auto"}]);aq.exports={Request:Pn,makeRequest:Sm,fromInnerRequest:oq,cloneRequest:sq,getRequestDispatcher:mbe,getRequestState:iq}});var Rv=U((UFe,cq)=>{"use strict";var Aq=Symbol.for("undici.globalDispatcher.1"),{InvalidArgumentError:Cbe}=mr(),Qbe=Bv();uq()===void 0&&fq(new Qbe);function fq(e){if(!e||typeof e.dispatch!="function")throw new Cbe("Argument agent must implement Agent");Object.defineProperty(globalThis,Aq,{value:e,writable:!0,enumerable:!1,configurable:!1})}function uq(){return globalThis[Aq]}var wbe=["fetch","Headers","Response","Request","FormData","WebSocket","CloseEvent","ErrorEvent","MessageEvent","EventSource"];cq.exports={setGlobalDispatcher:fq,getGlobalDispatcher:uq,installedExports:wbe}});var mq=U((xFe,yq)=>{"use strict";var Sbe=Gt(),{runtimeFeatures:hq}=G_(),eu=new Map([["sha256",0],["sha384",1],["sha512",2]]),Dv;if(hq.has("crypto")){Dv=Nd();let e=Dv.getHashes();e.length===0&&eu.clear();for(let t of eu.keys())e.includes(t)===!1&&eu.delete(t)}else eu.clear();var lq=Map.prototype.get.bind(eu),Tv=Map.prototype.has.bind(eu),_be=hq.has("crypto")===!1||eu.size===0?()=>!0:(e,t)=>{let r=gq(t);if(r.length===0)return!0;let n=dq(r);for(let i of n){let s=i.alg,o=i.val,a=pq(s,e);if(Eq(a,o))return!0}return!1};function dq(e){let t=[],r=null;for(let n of e){if(Sbe(Tv(n.alg),"Invalid SRI hash algorithm token"),t.length===0){t.push(n),r=n;continue}let i=r.alg,s=lq(i),o=n.alg,a=lq(o);as?(r=n,t[0]=n,t.length=1):t.push(n))}return t}function gq(e){let t=[];for(let r of e.split(" ")){let i=r.split("?",1)[0],s="",o=[i.slice(0,6),i.slice(7)],a=o[0];if(!Tv(a))continue;o[1]&&(s=o[1]);let A={alg:a,val:s};t.push(A)}return t}var pq=(e,t)=>Dv.hash(e,t,"base64");function Eq(e,t){let r=e.length;r!==0&&e[r-1]==="="&&(r-=1),r!==0&&e[r-1]==="="&&(r-=1);let n=t.length;if(n!==0&&t[n-1]==="="&&(n-=1),n!==0&&t[n-1]==="="&&(n-=1),r!==n)return!1;for(let i=0;i{"use strict";var{makeNetworkError:Nt,makeAppropriateNetworkError:hg,filterResponse:Nv,makeResponse:_m,fromInnerResponse:vbe,getResponseState:Rbe}=wv(),{HeadersList:Mv}=cg(),{Request:Dbe,cloneRequest:Tbe,getRequestDispatcher:Nbe,getRequestState:Mbe}=vv(),ws=RE(),{makePolicyContainer:Fbe,clonePolicyContainer:kbe,requestBadPort:Ube,TAOCheck:xbe,appendRequestOriginHeader:Lbe,responseLocationURL:Pbe,requestCurrentURL:si,setRequestReferrerPolicyOnRedirect:Obe,tryUpgradeRequestToAPotentiallyTrustworthyURL:Hbe,createOpaqueTimingInfo:Pv,appendFetchMetadata:qbe,corsCheck:Gbe,crossOriginResourcePolicyCheck:Ybe,determineRequestsReferrer:Wbe,coarsenedSharedCurrentTime:dg,sameOrigin:xv,isCancelled:wA,isAborted:Bq,isErrorLike:Vbe,fullyReadBody:Jbe,readableStreamClose:jbe,urlIsLocal:zbe,urlIsHttpHttpsScheme:Tm,urlHasHttpsScheme:Kbe,clampAndCoarsenConnectionTimingInfo:Xbe,simpleRangeHeaderValue:Zbe,buildContentRange:$be,createInflate:eCe,extractMimeType:tCe,hasAuthenticationEntry:rCe,includesCredentials:Iq,isTraversableNavigable:nCe}=jf(),tu=Gt(),{safelyExtractBody:Nm,extractBody:bq}=Al(),{redirectStatusSet:Sq,nullBodyStatus:_q,safeMethodsSet:iCe,requestBodyHeader:sCe,subresourceSet:oCe}=td(),aCe=Zi(),{Readable:ACe,pipeline:fCe,finished:uCe,isErrored:cCe,isReadable:vm}=(ts(),Os(qt)),{addAbortListener:lCe,bufferToLowerCasedHeaderName:Cq}=Zt(),{dataURLProcessor:hCe,serializeAMimeType:dCe,minimizeSupportedMimeType:gCe}=yf(),{getGlobalDispatcher:pCe}=Rv(),{webidl:Ov}=lo(),{STATUS_CODES:Qq}=aE(),{bytesMatch:ECe}=mq(),{createDeferredPromise:yCe}=H_(),{isomorphicEncode:Rm}=Ef(),{runtimeFeatures:mCe}=C_(),BCe=mCe.has("zstd"),ICe=["GET","HEAD"],bCe=typeof __UNDICI_IS_NODE__<"u"||typeof esbuildDetection<"u"?"node":"undici",Fv,Dm=class extends aCe{constructor(t){super(),this.dispatcher=t,this.connection=null,this.dump=!1,this.state="ongoing"}terminate(t){this.state==="ongoing"&&(this.state="terminated",this.connection?.destroy(t),this.emit("terminated",t))}abort(t){this.state==="ongoing"&&(this.state="aborted",t||(t=new DOMException("The operation was aborted.","AbortError")),this.serializedAbortReason=t,this.connection?.destroy(t),this.emit("terminated",t))}};function CCe(e){vq(e,"fetch")}function QCe(e,t=void 0){Ov.argumentLengthCheck(arguments,1,"globalThis.fetch");let r=yCe(),n;try{n=new Dbe(e,t)}catch(l){return r.reject(l),r.promise}let i=Mbe(n);if(n.signal.aborted)return kv(r,i,null,n.signal.reason,null),r.promise;i.client.globalObject?.constructor?.name==="ServiceWorkerGlobalScope"&&(i.serviceWorkers="none");let o=null,a=!1,A=null;return lCe(n.signal,()=>{a=!0,tu(A!=null),A.abort(n.signal.reason);let l=o?.deref();kv(r,i,l,n.signal.reason,A.controller)}),A=Dq({request:i,processResponseEndOfBody:CCe,processResponse:l=>{if(!a){if(l.aborted){kv(r,i,o,A.serializedAbortReason,A.controller);return}if(l.type==="error"){r.reject(new TypeError("fetch failed",{cause:l.error}));return}o=new WeakRef(vbe(l,"immutable")),r.resolve(o.deref()),r=null}},dispatcher:Nbe(n),requestObject:n}),r.promise}function vq(e,t="other"){if(e.type==="error"&&e.aborted||!e.urlList?.length)return;let r=e.urlList[0],n=e.timingInfo,i=e.cacheState;Tm(r)&&n!==null&&(e.timingAllowPassed||(n=Pv({startTime:n.startTime}),i=""),n.endTime=dg(),e.timingInfo=n,Rq(n,r.href,t,globalThis,i,"",e.status))}var Rq=performance.markResourceTiming;function kv(e,t,r,n,i){if(e&&e.reject(n),t.body?.stream!=null&&vm(t.body.stream)&&t.body.stream.cancel(n).catch(o=>{if(o.code!=="ERR_INVALID_STATE")throw o}),r==null)return;let s=Rbe(r);s.body?.stream!=null&&vm(s.body.stream)&&i.error(n)}function Dq({request:e,processRequestBodyChunkLength:t,processRequestEndOfBody:r,processResponse:n,processResponseEndOfBody:i,processResponseConsumeBody:s,useParallelQueue:o=!1,dispatcher:a=pCe(),requestObject:A=null}){tu(a);let f=null,l=!1;e.client!=null&&(f=e.client.globalObject,l=e.client.crossOriginIsolatedCapability);let p=dg(l),I=Pv({startTime:p}),S={controller:new Dm(a),request:e,timingInfo:I,processRequestBodyChunkLength:t,processRequestEndOfBody:r,processResponse:n,processResponseConsumeBody:s,processResponseEndOfBody:i,taskDestination:f,crossOriginIsolatedCapability:l,requestObject:A};return tu(!e.body||e.body.stream),e.window==="client"&&(e.window=e.client?.globalObject?.constructor?.name==="Window"?e.client:"no-window"),e.origin==="client"&&(e.origin=e.client.origin),e.policyContainer==="client"&&(e.client!=null?e.policyContainer=kbe(e.client.policyContainer):e.policyContainer=Fbe()),e.headersList.contains("accept",!0)||e.headersList.append("accept","*/*",!0),e.headersList.contains("accept-language",!0)||e.headersList.append("accept-language","*",!0),e.priority,oCe.has(e.destination),Tq(S,!1),S.controller}async function Tq(e,t){try{let r=e.request,n=null;if(r.localURLsOnly&&!zbe(si(r))&&(n=Nt("local URLs only")),Hbe(r),Ube(r)==="blocked"&&(n=Nt("bad port")),r.referrerPolicy===""&&(r.referrerPolicy=r.policyContainer.referrerPolicy),r.referrer!=="no-referrer"&&(r.referrer=Wbe(r)),n===null){let s=si(r);xv(s,r.url)&&r.responseTainting==="basic"||s.protocol==="data:"||r.mode==="navigate"||r.mode==="websocket"?(r.responseTainting="basic",n=await wq(e)):r.mode==="same-origin"?n=Nt('request mode cannot be "same-origin"'):r.mode==="no-cors"?r.redirect!=="follow"?n=Nt('redirect mode cannot be "follow" for "no-cors" request'):(r.responseTainting="opaque",n=await wq(e)):Tm(si(r))?(r.responseTainting="cors",n=await Nq(e)):n=Nt("URL scheme must be a HTTP(S) scheme")}if(t)return n;n.status!==0&&!n.internalResponse&&(r.responseTainting,r.responseTainting==="basic"?n=Nv(n,"basic"):r.responseTainting==="cors"?n=Nv(n,"cors"):r.responseTainting==="opaque"?n=Nv(n,"opaque"):tu(!1));let i=n.status===0?n:n.internalResponse;if(i.urlList.length===0&&i.urlList.push(...r.urlList),r.timingAllowFailed||(n.timingAllowPassed=!0),n.type==="opaque"&&i.status===206&&i.rangeRequested&&!r.headers.contains("range",!0)&&(n=i=Nt()),n.status!==0&&(r.method==="HEAD"||r.method==="CONNECT"||_q.includes(i.status))&&(i.body=null,e.controller.dump=!0),r.integrity){let s=a=>Uv(e,Nt(a));if(r.responseTainting==="opaque"||n.body==null){s(n.error);return}let o=a=>{if(!ECe(a,r.integrity)){s("integrity mismatch");return}n.body=Nm(a)[0],Uv(e,n)};Jbe(n.body,o,s)}else Uv(e,n)}catch(r){e.controller.terminate(r)}}function wq(e){if(wA(e)&&e.request.redirectCount===0)return Promise.resolve(hg(e));let{request:t}=e,{protocol:r}=si(t);switch(r){case"about:":return Promise.resolve(Nt("about scheme is not supported"));case"blob:":{Fv||(Fv=Gr().resolveObjectURL);let n=si(t);if(n.search.length!==0)return Promise.resolve(Nt("NetworkError when attempting to fetch resource."));let i=Fv(n.toString());if(t.method!=="GET"||!Ov.is.Blob(i))return Promise.resolve(Nt("invalid method"));let s=_m(),o=i.size,a=Rm(`${o}`),A=i.type;if(t.headersList.contains("range",!0)){s.rangeRequested=!0;let f=t.headersList.get("range",!0),l=Zbe(f,!0);if(l==="failure")return Promise.resolve(Nt("failed to fetch the data URL"));let{rangeStartValue:p,rangeEndValue:I}=l;if(p===null)p=o-I,I=p+I-1;else{if(p>=o)return Promise.resolve(Nt("Range start is greater than the blob's size."));(I===null||I>=o)&&(I=o-1)}let S=i.slice(p,I+1,A),_=bq(S);s.body=_[0];let N=Rm(`${S.size}`),O=$be(p,I,o);s.status=206,s.statusText="Partial Content",s.headersList.set("content-length",N,!0),s.headersList.set("content-type",A,!0),s.headersList.set("content-range",O,!0)}else{let f=bq(i);s.statusText="OK",s.body=f[0],s.headersList.set("content-length",a,!0),s.headersList.set("content-type",A,!0)}return Promise.resolve(s)}case"data:":{let n=si(t),i=hCe(n);if(i==="failure")return Promise.resolve(Nt("failed to fetch the data URL"));let s=dCe(i.mimeType);return Promise.resolve(_m({statusText:"OK",headersList:[["content-type",{name:"Content-Type",value:s}]],body:Nm(i.body)[0]}))}case"file:":return Promise.resolve(Nt("not implemented... yet..."));case"http:":case"https:":return Nq(e).catch(n=>Nt(n));default:return Promise.resolve(Nt("unknown scheme"))}}function wCe(e,t){e.request.done=!0,e.processResponseDone!=null&&queueMicrotask(()=>e.processResponseDone(t))}function Uv(e,t){let r=e.timingInfo,n=()=>{let s=Date.now();e.request.destination==="document"&&(e.controller.fullTimingInfo=r),e.controller.reportTimingSteps=()=>{if(!Tm(e.request.url))return;r.endTime=s;let a=t.cacheState,A=t.bodyInfo;t.timingAllowPassed||(r=Pv(r),a="");let f=0;if(e.request.mode!=="navigator"||!t.hasCrossOriginRedirects){f=t.status;let l=tCe(t.headersList);l!=="failure"&&(A.contentType=gCe(l))}e.request.initiatorType!=null&&Rq(r,e.request.url.href,e.request.initiatorType,globalThis,a,A,f)};let o=()=>{e.request.done=!0,e.processResponseEndOfBody!=null&&queueMicrotask(()=>e.processResponseEndOfBody(t)),e.request.initiatorType!=null&&e.controller.reportTimingSteps()};queueMicrotask(()=>o())};e.processResponse!=null&&queueMicrotask(()=>{e.processResponse(t),e.processResponse=null});let i=t.type==="error"?t:t.internalResponse??t;i.body==null?n():uCe(i.body.stream,()=>{n()})}async function Nq(e){let t=e.request,r=null,n=null,i=e.timingInfo;if(t.serviceWorkers,r===null){if(t.redirect==="follow"&&(t.serviceWorkers="none"),n=r=await Lv(e),t.responseTainting==="cors"&&Gbe(t,r)==="failure")return Nt("cors failure");xbe(t,r)==="failure"&&(t.timingAllowFailed=!0)}return(t.responseTainting==="opaque"||r.type==="opaque")&&Ybe(t.origin,t.client,t.destination,n)==="blocked"?Nt("blocked"):(Sq.has(n.status)&&(t.redirect!=="manual"&&e.controller.connection.destroy(void 0,!1),t.redirect==="error"?r=Nt("unexpected redirect"):t.redirect==="manual"?r=n:t.redirect==="follow"?r=await SCe(e,r):tu(!1)),r.timingInfo=i,r)}function SCe(e,t){let r=e.request,n=t.internalResponse?t.internalResponse:t,i;try{if(i=Pbe(n,si(r).hash),i==null)return t}catch(o){return Promise.resolve(Nt(o))}if(!Tm(i))return Promise.resolve(Nt("URL scheme must be a HTTP(S) scheme"));if(r.redirectCount===20)return Promise.resolve(Nt("redirect count exceeded"));if(r.redirectCount+=1,r.mode==="cors"&&(i.username||i.password)&&!xv(r,i))return Promise.resolve(Nt('cross origin not allowed for request mode "cors"'));if(r.responseTainting==="cors"&&(i.username||i.password))return Promise.resolve(Nt('URL cannot contain credentials for request mode "cors"'));if(n.status!==303&&r.body!=null&&r.body.source==null)return Promise.resolve(Nt());if([301,302].includes(n.status)&&r.method==="POST"||n.status===303&&!ICe.includes(r.method)){r.method="GET",r.body=null;for(let o of sCe)r.headersList.delete(o)}xv(si(r),i)||(r.headersList.delete("authorization",!0),r.headersList.delete("proxy-authorization",!0),r.headersList.delete("cookie",!0),r.headersList.delete("host",!0)),r.body!=null&&(tu(r.body.source!=null),r.body=Nm(r.body.source)[0]);let s=e.timingInfo;return s.redirectEndTime=s.postRedirectStartTime=dg(e.crossOriginIsolatedCapability),s.redirectStartTime===0&&(s.redirectStartTime=s.startTime),r.urlList.push(i),Obe(r,n),Tq(e,!0)}async function Lv(e,t=!1,r=!1){let n=e.request,i=null,s=null,o=null,a=null,A=!1;n.window==="no-window"&&n.redirect==="error"?(i=e,s=n):(s=Tbe(n),i={...e},i.request=s);let f=n.credentials==="include"||n.credentials==="same-origin"&&n.responseTainting==="basic",l=s.body?s.body.length:null,p=null;if(s.body==null&&["POST","PUT"].includes(s.method)&&(p="0"),l!=null&&(p=Rm(`${l}`)),p!=null&&s.headersList.append("content-length",p,!0),l!=null&&s.keepalive,Ov.is.URL(s.referrer)&&s.headersList.append("referer",Rm(s.referrer.href),!0),Lbe(s),qbe(s),s.headersList.contains("user-agent",!0)||s.headersList.append("user-agent",bCe,!0),s.cache==="default"&&(s.headersList.contains("if-modified-since",!0)||s.headersList.contains("if-none-match",!0)||s.headersList.contains("if-unmodified-since",!0)||s.headersList.contains("if-match",!0)||s.headersList.contains("if-range",!0))&&(s.cache="no-store"),s.cache==="no-cache"&&!s.preventNoCacheCacheControlHeaderModification&&!s.headersList.contains("cache-control",!0)&&s.headersList.append("cache-control","max-age=0",!0),(s.cache==="no-store"||s.cache==="reload")&&(s.headersList.contains("pragma",!0)||s.headersList.append("pragma","no-cache",!0),s.headersList.contains("cache-control",!0)||s.headersList.append("cache-control","no-cache",!0)),s.headersList.contains("range",!0)&&s.headersList.append("accept-encoding","identity",!0),s.headersList.contains("accept-encoding",!0)||(Kbe(si(s))?s.headersList.append("accept-encoding","br, gzip, deflate",!0):s.headersList.append("accept-encoding","gzip, deflate",!0)),s.headersList.delete("host",!0),f&&!s.headersList.contains("authorization",!0)){let I=null;if(!(rCe(s)&&(s.useURLCredentials===void 0||!Iq(si(s))))){if(Iq(si(s))&&t){let{username:S,password:_}=si(s);I=`Basic ${Buffer.from(`${S}:${_}`).toString("base64")}`}}I!==null&&s.headersList.append("Authorization",I,!1)}if(a==null&&(s.cache="no-store"),s.cache!=="no-store"&&s.cache,o==null){if(s.cache==="only-if-cached")return Nt("only if cached");let I=await _Ce(i,f,r);!iCe.has(s.method)&&I.status>=200&&I.status<=399,A&&I.status,o==null&&(o=I)}if(o.urlList=[...s.urlList],s.headersList.contains("range",!0)&&(o.rangeRequested=!0),o.requestIncludesCredentials=f,o.status===401&&s.responseTainting!=="cors"&&f&&nCe(n.traversableForUserPrompts)){if(n.body!=null){if(n.body.source==null)return Nt("expected non-null body source");n.body=Nm(n.body.source)[0]}if(n.useURLCredentials===void 0||t)return wA(e)?hg(e):o;e.controller.connection.destroy(),o=await Lv(e,!0)}if(o.status===407)return n.window==="no-window"?Nt():wA(e)?hg(e):Nt("proxy authentication required");if(o.status===421&&!r&&(n.body==null||n.body.source!=null)){if(wA(e))return hg(e);e.controller.connection.destroy(),o=await Lv(e,t,!0)}return o}async function _Ce(e,t=!1,r=!1){tu(!e.controller.connection||e.controller.connection.destroyed),e.controller.connection={abort:null,destroyed:!1,destroy(_,N=!0){this.destroyed||(this.destroyed=!0,N&&this.abort?.(_??new DOMException("The operation was aborted.","AbortError")))}};let n=e.request,i=null,s=e.timingInfo;null==null&&(n.cache="no-store");let a=r?"yes":"no";n.mode;let A=null;if(n.body==null&&e.processRequestEndOfBody)queueMicrotask(()=>e.processRequestEndOfBody());else if(n.body!=null){let _=async function*(x){wA(e)||(yield x,e.processRequestBodyChunkLength?.(x.byteLength))},N=()=>{wA(e)||e.processRequestEndOfBody&&e.processRequestEndOfBody()},O=x=>{wA(e)||(x.name==="AbortError"?e.controller.abort():e.controller.terminate(x))};A=(async function*(){try{for await(let x of n.body.stream)yield*_(x);N()}catch(x){O(x)}})()}try{let{body:_,status:N,statusText:O,headersList:x,socket:G}=await S({body:A});if(G)i=_m({status:N,statusText:O,headersList:x,socket:G});else{let Y=_[Symbol.asyncIterator]();e.controller.next=()=>Y.next(),i=_m({status:N,statusText:O,headersList:x})}}catch(_){return _.name==="AbortError"?(e.controller.connection.destroy(),hg(e,_)):Nt(_)}let f=()=>e.controller.resume(),l=_=>{wA(e)||e.controller.abort(_)},p=new ReadableStream({start(_){e.controller.controller=_},pull:f,cancel:l,type:"bytes"});i.body={stream:p,source:null,length:null},e.controller.resume||e.controller.on("terminated",I),e.controller.resume=async()=>{for(;;){let _,N;try{let{done:x,value:G}=await e.controller.next();if(Bq(e))break;_=x?void 0:G}catch(x){e.controller.ended&&!s.encodedBodySize?_=void 0:(_=x,N=!0)}if(_===void 0){jbe(e.controller.controller),wCe(e,i);return}if(s.decodedBodySize+=_?.byteLength??0,N){e.controller.terminate(_);return}let O=new Uint8Array(_);if(O.byteLength&&e.controller.controller.enqueue(O),cCe(p)){e.controller.terminate();return}if(e.controller.controller.desiredSize<=0)return}};function I(_){Bq(e)?(i.aborted=!0,vm(p)&&e.controller.controller.error(e.controller.serializedAbortReason)):vm(p)&&e.controller.controller.error(new TypeError("terminated",{cause:Vbe(_)?_:void 0})),e.controller.connection.destroy()}return i;function S({body:_}){let N=si(n),O=e.controller.dispatcher,x=N.pathname+N.search,G=N.search.length===0&&N.href[N.href.length-N.hash.length-1]==="?";return new Promise((Y,X)=>O.dispatch({path:G?`${x}?`:x,origin:N.origin,method:n.method,body:O.isMockActive?n.body&&(n.body.source||n.body.stream):_,headers:n.headersList.entries,maxRedirections:0,upgrade:n.mode==="websocket"?"websocket":void 0},{body:null,abort:null,onConnect(Z){let{connection:j}=e.controller;s.finalConnectionTimingInfo=Xbe(void 0,s.postRedirectStartTime,e.crossOriginIsolatedCapability),j.destroyed?Z(new DOMException("The operation was aborted.","AbortError")):(e.controller.on("terminated",Z),this.abort=j.abort=Z),s.finalNetworkRequestStartTime=dg(e.crossOriginIsolatedCapability)},onResponseStarted(){s.finalNetworkResponseStartTime=dg(e.crossOriginIsolatedCapability)},onHeaders(Z,j,se,ie){if(Z<200)return!1;let ce=new Mv;for(let c=0;cw)return X(new Error(`too many content-encodings in response: ${g.length}, maximum allowed is ${w}`)),!0;for(let R=g.length-1;R>=0;--R){let C=g[R].trim();if(C==="x-gzip"||C==="gzip")v.push(ws.createGunzip({flush:ws.constants.Z_SYNC_FLUSH,finishFlush:ws.constants.Z_SYNC_FLUSH}));else if(C==="deflate")v.push(eCe({flush:ws.constants.Z_SYNC_FLUSH,finishFlush:ws.constants.Z_SYNC_FLUSH}));else if(C==="br")v.push(ws.createBrotliDecompress({flush:ws.constants.BROTLI_OPERATION_FLUSH,finishFlush:ws.constants.BROTLI_OPERATION_FLUSH}));else if(C==="zstd"&&BCe)v.push(ws.createZstdDecompress({flush:ws.constants.ZSTD_e_continue,finishFlush:ws.constants.ZSTD_e_end}));else{v.length=0;break}}}let b=this.onError.bind(this);return Y({status:Z,statusText:ie,headersList:ce,body:v.length?fCe(this.body,...v,c=>{c&&this.onError(c)}).on("error",b):this.body.on("error",b)}),!0},onData(Z){if(e.controller.dump)return;let j=Z;return s.encodedBodySize+=j.byteLength,this.body.push(j)},onComplete(){this.abort&&e.controller.off("terminated",this.abort),e.controller.ended=!0,this.body.push(null)},onError(Z){this.abort&&e.controller.off("terminated",this.abort),this.body?.destroy(Z),e.controller.terminate(Z),X(Z)},onRequestUpgrade(Z,j,se,ie){if(ie.session!=null&&j!==200||ie.session==null&&j!==101)return!1;let ce=new Mv;for(let[H,E]of Object.entries(se)){if(E==null)continue;let v=H.toLowerCase();if(Array.isArray(E))for(let b of E)ce.append(v,String(b),!0);else ce.append(v,String(E),!0)}return Y({status:j,statusText:Qq[j],headersList:ce,socket:ie}),!0},onUpgrade(Z,j,se){if(se.session!=null&&Z!==200||se.session==null&&Z!==101)return!1;let ie=new Mv;for(let ce=0;cedZ,DH_CHECK_P_NOT_SAFE_PRIME:()=>hZ,DH_NOT_SUITABLE_GENERATOR:()=>pZ,DH_UNABLE_TO_CHECK_GENERATOR:()=>gZ,E2BIG:()=>Bz,EACCES:()=>Iz,EADDRINUSE:()=>bz,EADDRNOTAVAIL:()=>Cz,EAFNOSUPPORT:()=>Qz,EAGAIN:()=>wz,EALREADY:()=>Sz,EBADF:()=>_z,EBADMSG:()=>vz,EBUSY:()=>Rz,ECANCELED:()=>Dz,ECHILD:()=>Tz,ECONNABORTED:()=>Nz,ECONNREFUSED:()=>Mz,ECONNRESET:()=>Fz,EDEADLK:()=>kz,EDESTADDRREQ:()=>Uz,EDOM:()=>xz,EDQUOT:()=>Lz,EEXIST:()=>Pz,EFAULT:()=>Oz,EFBIG:()=>Hz,EHOSTUNREACH:()=>qz,EIDRM:()=>Gz,EILSEQ:()=>Yz,EINPROGRESS:()=>Wz,EINTR:()=>Vz,EINVAL:()=>Jz,EIO:()=>jz,EISCONN:()=>zz,EISDIR:()=>Kz,ELOOP:()=>Xz,EMFILE:()=>Zz,EMLINK:()=>$z,EMSGSIZE:()=>eK,EMULTIHOP:()=>tK,ENAMETOOLONG:()=>rK,ENETDOWN:()=>nK,ENETRESET:()=>iK,ENETUNREACH:()=>sK,ENFILE:()=>oK,ENGINE_METHOD_ALL:()=>cZ,ENGINE_METHOD_CIPHERS:()=>oZ,ENGINE_METHOD_DH:()=>rZ,ENGINE_METHOD_DIGESTS:()=>aZ,ENGINE_METHOD_DSA:()=>tZ,ENGINE_METHOD_ECDH:()=>iZ,ENGINE_METHOD_ECDSA:()=>sZ,ENGINE_METHOD_NONE:()=>lZ,ENGINE_METHOD_PKEY_ASN1_METHS:()=>uZ,ENGINE_METHOD_PKEY_METHS:()=>fZ,ENGINE_METHOD_RAND:()=>nZ,ENGINE_METHOD_STORE:()=>AZ,ENOBUFS:()=>aK,ENODATA:()=>AK,ENODEV:()=>fK,ENOENT:()=>uK,ENOEXEC:()=>cK,ENOLCK:()=>lK,ENOLINK:()=>hK,ENOMEM:()=>dK,ENOMSG:()=>gK,ENOPROTOOPT:()=>pK,ENOSPC:()=>EK,ENOSR:()=>yK,ENOSTR:()=>mK,ENOSYS:()=>BK,ENOTCONN:()=>IK,ENOTDIR:()=>bK,ENOTEMPTY:()=>CK,ENOTSOCK:()=>QK,ENOTSUP:()=>wK,ENOTTY:()=>SK,ENXIO:()=>_K,EOPNOTSUPP:()=>vK,EOVERFLOW:()=>RK,EPERM:()=>DK,EPIPE:()=>TK,EPROTO:()=>NK,EPROTONOSUPPORT:()=>MK,EPROTOTYPE:()=>FK,ERANGE:()=>kK,EROFS:()=>UK,ESPIPE:()=>xK,ESRCH:()=>LK,ESTALE:()=>PK,ETIME:()=>OK,ETIMEDOUT:()=>HK,ETXTBSY:()=>qK,EWOULDBLOCK:()=>GK,EXDEV:()=>YK,F_OK:()=>_Z,NPN_ENABLED:()=>EZ,O_APPEND:()=>rz,O_CREAT:()=>Zj,O_DIRECTORY:()=>nz,O_EXCL:()=>$j,O_NOCTTY:()=>ez,O_NOFOLLOW:()=>iz,O_NONBLOCK:()=>az,O_RDONLY:()=>Hj,O_RDWR:()=>Gj,O_SYMLINK:()=>oz,O_SYNC:()=>sz,O_TRUNC:()=>tz,O_WRONLY:()=>qj,POINT_CONVERSION_COMPRESSED:()=>QZ,POINT_CONVERSION_HYBRID:()=>SZ,POINT_CONVERSION_UNCOMPRESSED:()=>wZ,RSA_NO_PADDING:()=>BZ,RSA_PKCS1_OAEP_PADDING:()=>IZ,RSA_PKCS1_PADDING:()=>yZ,RSA_PKCS1_PSS_PADDING:()=>CZ,RSA_SSLV23_PADDING:()=>mZ,RSA_X931_PADDING:()=>bZ,R_OK:()=>vZ,SIGABRT:()=>KK,SIGALRM:()=>sX,SIGBUS:()=>ZK,SIGCHLD:()=>aX,SIGCONT:()=>AX,SIGFPE:()=>$K,SIGHUP:()=>WK,SIGILL:()=>jK,SIGINT:()=>VK,SIGIO:()=>mX,SIGIOT:()=>XK,SIGKILL:()=>eX,SIGPIPE:()=>iX,SIGPROF:()=>EX,SIGQUIT:()=>JK,SIGSEGV:()=>rX,SIGSTOP:()=>fX,SIGSYS:()=>BX,SIGTERM:()=>oX,SIGTRAP:()=>zK,SIGTSTP:()=>uX,SIGTTIN:()=>cX,SIGTTOU:()=>lX,SIGURG:()=>hX,SIGUSR1:()=>tX,SIGUSR2:()=>nX,SIGVTALRM:()=>pX,SIGWINCH:()=>yX,SIGXCPU:()=>dX,SIGXFSZ:()=>gX,SSL_OP_ALL:()=>IX,SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION:()=>bX,SSL_OP_CIPHER_SERVER_PREFERENCE:()=>CX,SSL_OP_CISCO_ANYCONNECT:()=>QX,SSL_OP_COOKIE_EXCHANGE:()=>wX,SSL_OP_CRYPTOPRO_TLSEXT_BUG:()=>SX,SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:()=>_X,SSL_OP_EPHEMERAL_RSA:()=>vX,SSL_OP_LEGACY_SERVER_CONNECT:()=>RX,SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER:()=>DX,SSL_OP_MICROSOFT_SESS_ID_BUG:()=>TX,SSL_OP_MSIE_SSLV2_RSA_PADDING:()=>NX,SSL_OP_NETSCAPE_CA_DN_BUG:()=>MX,SSL_OP_NETSCAPE_CHALLENGE_BUG:()=>FX,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG:()=>kX,SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG:()=>UX,SSL_OP_NO_COMPRESSION:()=>xX,SSL_OP_NO_QUERY_MTU:()=>LX,SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION:()=>PX,SSL_OP_NO_SSLv2:()=>OX,SSL_OP_NO_SSLv3:()=>HX,SSL_OP_NO_TICKET:()=>qX,SSL_OP_NO_TLSv1:()=>GX,SSL_OP_NO_TLSv1_1:()=>YX,SSL_OP_NO_TLSv1_2:()=>WX,SSL_OP_PKCS1_CHECK_1:()=>VX,SSL_OP_PKCS1_CHECK_2:()=>JX,SSL_OP_SINGLE_DH_USE:()=>jX,SSL_OP_SINGLE_ECDH_USE:()=>zX,SSL_OP_SSLEAY_080_CLIENT_DH_BUG:()=>KX,SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG:()=>XX,SSL_OP_TLS_BLOCK_PADDING_BUG:()=>ZX,SSL_OP_TLS_D5_BUG:()=>$X,SSL_OP_TLS_ROLLBACK_BUG:()=>eZ,S_IFBLK:()=>jj,S_IFCHR:()=>Jj,S_IFDIR:()=>Vj,S_IFIFO:()=>zj,S_IFLNK:()=>Kj,S_IFMT:()=>Yj,S_IFREG:()=>Wj,S_IFSOCK:()=>Xj,S_IRGRP:()=>hz,S_IROTH:()=>Ez,S_IRUSR:()=>fz,S_IRWXG:()=>lz,S_IRWXO:()=>pz,S_IRWXU:()=>Az,S_IWGRP:()=>dz,S_IWOTH:()=>yz,S_IWUSR:()=>uz,S_IXGRP:()=>gz,S_IXOTH:()=>mz,S_IXUSR:()=>cz,UV_UDP_REUSEADDR:()=>TZ,W_OK:()=>RZ,X_OK:()=>DZ,default:()=>NZ});var Hj=0,qj=1,Gj=2,Yj=61440,Wj=32768,Vj=16384,Jj=8192,jj=24576,zj=4096,Kj=40960,Xj=49152,Zj=512,$j=2048,ez=131072,tz=1024,rz=8,nz=1048576,iz=256,sz=128,oz=2097152,az=4,Az=448,fz=256,uz=128,cz=64,lz=56,hz=32,dz=16,gz=8,pz=7,Ez=4,yz=2,mz=1,Bz=7,Iz=13,bz=48,Cz=49,Qz=47,wz=35,Sz=37,_z=9,vz=94,Rz=16,Dz=89,Tz=10,Nz=53,Mz=61,Fz=54,kz=11,Uz=39,xz=33,Lz=69,Pz=17,Oz=14,Hz=27,qz=65,Gz=90,Yz=92,Wz=36,Vz=4,Jz=22,jz=5,zz=56,Kz=21,Xz=62,Zz=24,$z=31,eK=40,tK=95,rK=63,nK=50,iK=52,sK=51,oK=23,aK=55,AK=96,fK=19,uK=2,cK=8,lK=77,hK=97,dK=12,gK=91,pK=42,EK=28,yK=98,mK=99,BK=78,IK=57,bK=20,CK=66,QK=38,wK=45,SK=25,_K=6,vK=102,RK=84,DK=1,TK=32,NK=100,MK=43,FK=41,kK=34,UK=30,xK=29,LK=3,PK=70,OK=101,HK=60,qK=26,GK=35,YK=18,WK=1,VK=2,JK=3,jK=4,zK=5,KK=6,XK=6,ZK=10,$K=8,eX=9,tX=30,rX=11,nX=31,iX=13,sX=14,oX=15,aX=20,AX=19,fX=17,uX=18,cX=21,lX=22,hX=16,dX=24,gX=25,pX=26,EX=27,yX=28,mX=23,BX=12,IX=2147486719,bX=262144,CX=4194304,QX=32768,wX=8192,SX=2147483648,_X=2048,vX=0,RX=4,DX=32,TX=1,NX=0,MX=536870912,FX=2,kX=1073741824,UX=8,xX=131072,LX=4096,PX=65536,OX=16777216,HX=33554432,qX=16384,GX=67108864,YX=268435456,WX=134217728,VX=0,JX=0,jX=1048576,zX=524288,KX=128,XX=0,ZX=512,$X=256,eZ=8388608,tZ=2,rZ=4,nZ=8,iZ=16,sZ=32,oZ=64,aZ=128,AZ=256,fZ=512,uZ=1024,cZ=65535,lZ=0,hZ=2,dZ=1,gZ=4,pZ=8,EZ=1,yZ=1,mZ=2,BZ=3,IZ=4,bZ=5,CZ=6,QZ=2,wZ=4,SZ=6,_Z=0,vZ=4,RZ=2,DZ=1,TZ=4,NZ={O_RDONLY:Hj,O_WRONLY:qj,O_RDWR:Gj,S_IFMT:Yj,S_IFREG:Wj,S_IFDIR:Vj,S_IFCHR:Jj,S_IFBLK:jj,S_IFIFO:zj,S_IFLNK:Kj,S_IFSOCK:Xj,O_CREAT:Zj,O_EXCL:$j,O_NOCTTY:ez,O_TRUNC:tz,O_APPEND:rz,O_DIRECTORY:nz,O_NOFOLLOW:iz,O_SYNC:sz,O_SYMLINK:oz,O_NONBLOCK:az,S_IRWXU:Az,S_IRUSR:fz,S_IWUSR:uz,S_IXUSR:cz,S_IRWXG:lz,S_IRGRP:hz,S_IWGRP:dz,S_IXGRP:gz,S_IRWXO:pz,S_IROTH:Ez,S_IWOTH:yz,S_IXOTH:mz,E2BIG:Bz,EACCES:Iz,EADDRINUSE:bz,EADDRNOTAVAIL:Cz,EAFNOSUPPORT:Qz,EAGAIN:wz,EALREADY:Sz,EBADF:_z,EBADMSG:vz,EBUSY:Rz,ECANCELED:Dz,ECHILD:Tz,ECONNABORTED:Nz,ECONNREFUSED:Mz,ECONNRESET:Fz,EDEADLK:kz,EDESTADDRREQ:Uz,EDOM:xz,EDQUOT:Lz,EEXIST:Pz,EFAULT:Oz,EFBIG:Hz,EHOSTUNREACH:qz,EIDRM:Gz,EILSEQ:Yz,EINPROGRESS:Wz,EINTR:Vz,EINVAL:Jz,EIO:jz,EISCONN:zz,EISDIR:Kz,ELOOP:Xz,EMFILE:Zz,EMLINK:$z,EMSGSIZE:eK,EMULTIHOP:tK,ENAMETOOLONG:rK,ENETDOWN:nK,ENETRESET:iK,ENETUNREACH:sK,ENFILE:oK,ENOBUFS:aK,ENODATA:AK,ENODEV:fK,ENOENT:uK,ENOEXEC:cK,ENOLCK:lK,ENOLINK:hK,ENOMEM:dK,ENOMSG:gK,ENOPROTOOPT:pK,ENOSPC:EK,ENOSR:yK,ENOSTR:mK,ENOSYS:BK,ENOTCONN:IK,ENOTDIR:bK,ENOTEMPTY:CK,ENOTSOCK:QK,ENOTSUP:wK,ENOTTY:SK,ENXIO:_K,EOPNOTSUPP:vK,EOVERFLOW:RK,EPERM:DK,EPIPE:TK,EPROTO:NK,EPROTONOSUPPORT:MK,EPROTOTYPE:FK,ERANGE:kK,EROFS:UK,ESPIPE:xK,ESRCH:LK,ESTALE:PK,ETIME:OK,ETIMEDOUT:HK,ETXTBSY:qK,EWOULDBLOCK:GK,EXDEV:YK,SIGHUP:WK,SIGINT:VK,SIGQUIT:JK,SIGILL:jK,SIGTRAP:zK,SIGABRT:KK,SIGIOT:XK,SIGBUS:ZK,SIGFPE:$K,SIGKILL:eX,SIGUSR1:tX,SIGSEGV:rX,SIGUSR2:nX,SIGPIPE:iX,SIGALRM:sX,SIGTERM:oX,SIGCHLD:aX,SIGCONT:AX,SIGSTOP:fX,SIGTSTP:uX,SIGTTIN:cX,SIGTTOU:lX,SIGURG:hX,SIGXCPU:dX,SIGXFSZ:gX,SIGVTALRM:pX,SIGPROF:EX,SIGWINCH:yX,SIGIO:mX,SIGSYS:BX,SSL_OP_ALL:IX,SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION:bX,SSL_OP_CIPHER_SERVER_PREFERENCE:CX,SSL_OP_CISCO_ANYCONNECT:QX,SSL_OP_COOKIE_EXCHANGE:wX,SSL_OP_CRYPTOPRO_TLSEXT_BUG:SX,SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:_X,SSL_OP_EPHEMERAL_RSA:vX,SSL_OP_LEGACY_SERVER_CONNECT:RX,SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER:DX,SSL_OP_MICROSOFT_SESS_ID_BUG:TX,SSL_OP_MSIE_SSLV2_RSA_PADDING:NX,SSL_OP_NETSCAPE_CA_DN_BUG:MX,SSL_OP_NETSCAPE_CHALLENGE_BUG:FX,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG:kX,SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG:UX,SSL_OP_NO_COMPRESSION:xX,SSL_OP_NO_QUERY_MTU:LX,SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION:PX,SSL_OP_NO_SSLv2:OX,SSL_OP_NO_SSLv3:HX,SSL_OP_NO_TICKET:qX,SSL_OP_NO_TLSv1:GX,SSL_OP_NO_TLSv1_1:YX,SSL_OP_NO_TLSv1_2:WX,SSL_OP_PKCS1_CHECK_1:VX,SSL_OP_PKCS1_CHECK_2:JX,SSL_OP_SINGLE_DH_USE:jX,SSL_OP_SINGLE_ECDH_USE:zX,SSL_OP_SSLEAY_080_CLIENT_DH_BUG:KX,SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG:XX,SSL_OP_TLS_BLOCK_PADDING_BUG:ZX,SSL_OP_TLS_D5_BUG:$X,SSL_OP_TLS_ROLLBACK_BUG:eZ,ENGINE_METHOD_DSA:tZ,ENGINE_METHOD_DH:rZ,ENGINE_METHOD_RAND:nZ,ENGINE_METHOD_ECDH:iZ,ENGINE_METHOD_ECDSA:sZ,ENGINE_METHOD_CIPHERS:oZ,ENGINE_METHOD_DIGESTS:aZ,ENGINE_METHOD_STORE:AZ,ENGINE_METHOD_PKEY_METHS:fZ,ENGINE_METHOD_PKEY_ASN1_METHS:uZ,ENGINE_METHOD_ALL:cZ,ENGINE_METHOD_NONE:lZ,DH_CHECK_P_NOT_SAFE_PRIME:hZ,DH_CHECK_P_NOT_PRIME:dZ,DH_UNABLE_TO_CHECK_GENERATOR:gZ,DH_NOT_SUITABLE_GENERATOR:pZ,NPN_ENABLED:EZ,RSA_PKCS1_PADDING:yZ,RSA_SSLV23_PADDING:mZ,RSA_NO_PADDING:BZ,RSA_PKCS1_OAEP_PADDING:IZ,RSA_X931_PADDING:bZ,RSA_PKCS1_PSS_PADDING:CZ,POINT_CONVERSION_COMPRESSED:QZ,POINT_CONVERSION_UNCOMPRESSED:wZ,POINT_CONVERSION_HYBRID:SZ,F_OK:_Z,R_OK:vZ,W_OK:RZ,X_OK:DZ,UV_UDP_REUSEADDR:TZ};var vCe=hr(Zi()),Ug=hr(HD()),RCe=hr(DI());NI();ts();var DCe=hr(sf()),Cu=hr(I4()),NB=hr(Yr());var Wr=hr(C4()),hC=class{constructor(){let t=new globalThis.TextEncoder,r=new Wr.TransformStream({transform(n,i){i.enqueue(t.encode(n))}});this.encoding="utf-8",this.readable=r.readable,this.writable=r.writable}},dC=class{constructor(t="utf-8",r=void 0){let n=new globalThis.TextDecoder(t,r),i=new Wr.TransformStream({transform(s,o){let a=n.decode(s,{stream:!0});a.length>0&&o.enqueue(a)},flush(s){let o=n.decode();o.length>0&&s.enqueue(o)}});this.encoding=n.encoding,this.fatal=n.fatal,this.ignoreBOM=n.ignoreBOM,this.readable=i.readable,this.writable=i.writable}},Pp=typeof globalThis.TextEncoderStream=="function"?globalThis.TextEncoderStream:hC,Op=typeof globalThis.TextDecoderStream=="function"?globalThis.TextDecoderStream:dC;typeof globalThis.ReadableStream>"u"&&(globalThis.ReadableStream=Wr.ReadableStream);typeof globalThis.WritableStream>"u"&&(globalThis.WritableStream=Wr.WritableStream);typeof globalThis.TransformStream>"u"&&(globalThis.TransformStream=Wr.TransformStream);typeof globalThis.TextEncoderStream>"u"&&(globalThis.TextEncoderStream=Pp);typeof globalThis.TextDecoderStream>"u"&&(globalThis.TextDecoderStream=Op);var Cg=hr(r6()),m1=hr(Bv()),B1=hr(cm()),Vm=hr(Fq()),B2=hr(Rv()),Eu=hr(cg()),yu=hr(vv()),mu=hr(wv()),I1=hr(lo());var sY=e=>{throw TypeError(e)},oY=(e,t,r)=>t.has(e)||sY("Cannot "+r),Vt=(e,t,r)=>(oY(e,t,"read from private field"),r?r.call(e):t.get(e)),kq=(e,t,r)=>t.has(e)?sY("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,r),Uq=(e,t,r,n)=>(oY(e,t,"write to private field"),n?n.call(e,r):t.set(e,r),r),xq=globalThis.AbortController,Lq=globalThis.AbortSignal,b1=Fl.Buffer??Fl.default?.Buffer??Fl.default;function Mm(e){return typeof e=="string"&&e.toLowerCase()==="base64url"?"base64":e}function TCe(e){return String(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function NCe(e){if(typeof e!="function"||e.__agentOSBase64UrlPatched)return;let t=typeof e.isEncoding=="function"?e.isEncoding.bind(e):null,r=typeof e.byteLength=="function"?e.byteLength.bind(e):null,n=typeof e.prototype?.toString=="function"?e.prototype.toString:null,i=typeof e.prototype?.write=="function"?e.prototype.write:null;e.isEncoding=function(o){return typeof o=="string"&&o.toLowerCase()==="base64url"||t?.(o)===!0},r&&(e.byteLength=function(o,a,...A){return r(o,Mm(a),...A)}),n&&(e.prototype.toString=function(o,...a){return typeof o=="string"&&o.toLowerCase()==="base64url"?TCe(n.call(this,"base64",...a)):n.call(this,o,...a)}),i&&(e.prototype.write=function(o,a,A,f){return typeof a=="string"?a=Mm(a):typeof A=="string"?A=Mm(A):typeof f=="string"&&(f=Mm(f)),i.call(this,o,a,A,f)}),e.__agentOSBase64UrlPatched=!0}NCe(b1);typeof b1=="function"&&(globalThis.Buffer=b1);var El=NB.types??NB.default?.types,MCe=new Map([["[object Int8Array]",Int8Array],["[object Uint8Array]",Uint8Array],["[object Uint8ClampedArray]",Uint8ClampedArray],["[object Int16Array]",Int16Array],["[object Uint16Array]",Uint16Array],["[object Int32Array]",Int32Array],["[object Uint32Array]",Uint32Array],["[object Float32Array]",Float32Array],["[object Float64Array]",Float64Array],["[object BigInt64Array]",BigInt64Array],["[object BigUint64Array]",BigUint64Array]]);function Pq(e="The object could not be cloned."){if(typeof globalThis.DOMException=="function")return new globalThis.DOMException(e,"DataCloneError");let t=new Error(e);return t.name="DataCloneError",t.code=25,t}function FCe(e){let t=new ArrayBuffer(e.byteLength);return new Uint8Array(t).set(new Uint8Array(e)),t}function _A(e,t){if(e===null)return e;let r=typeof e;if(r==="function"||r==="symbol")throw Pq();if(r!=="object")return e;let n=t.get(e);if(n!==void 0)return n;let i=Object.prototype.toString.call(e),s=MCe.get(i);if(s){let o=_A(e.buffer,t),a=new s(o,e.byteOffset,e.length);return t.set(e,a),a}if(i==="[object ArrayBuffer]"){let o=FCe(e);return t.set(e,o),o}if(i==="[object DataView]"){let o=_A(e.buffer,t),a=new DataView(o,e.byteOffset,e.byteLength);return t.set(e,a),a}if(i==="[object Date]"){let o=new Date(e.getTime());return t.set(e,o),o}if(i==="[object RegExp]"){let o=new RegExp(e.source,e.flags);return o.lastIndex=e.lastIndex,t.set(e,o),o}if(i==="[object Map]"){let o=new Map;t.set(e,o);for(let[a,A]of e.entries())o.set(_A(a,t),_A(A,t));return o}if(i==="[object Set]"){let o=new Set;t.set(e,o);for(let a of e.values())o.add(_A(a,t));return o}if(i==="[object Array]"){let o=new Array(e.length);t.set(e,o);for(let a of Object.keys(e))o[a]=_A(e[a],t);return o}if(i==="[object Object]"){let o=Object.getPrototypeOf(e)===null?Object.create(null):{};t.set(e,o);for(let a of Object.keys(e))o[a]=_A(e[a],t);return o}throw Pq()}function kCe(e,t=void 0){return t!=null&&typeof t=="object"&&"transfer"in t&&t.transfer,_A(e,new Map)}if(El&&typeof El.isProxy!="function")El.isProxy=()=>!1;else if(El)try{El.isProxy({})}catch{El.isProxy=()=>!1}function UCe(e){if(typeof e=="boolean")return{capture:e,once:!1,passive:!1};if(e==null)return{capture:!1,once:!1,passive:!1};let t=Object(e);return{capture:!!t.capture,once:!!t.once,passive:!!t.passive,signal:t.signal}}function xCe(e){return typeof e=="boolean"?e:e==null?!1:!!Object(e).capture}function LCe(e){return typeof e=="object"&&e!==null&&"aborted"in e&&typeof e.addEventListener=="function"&&typeof e.removeEventListener=="function"}var Cl,aY=(Cl=class{constructor(e,t){y(this,"type");y(this,"bubbles");y(this,"cancelable");y(this,"composed");y(this,"detail",null);y(this,"defaultPrevented",!1);y(this,"target",null);y(this,"currentTarget",null);y(this,"eventPhase",0);y(this,"returnValue",!0);y(this,"cancelBubble",!1);y(this,"timeStamp",Date.now());y(this,"isTrusted",!1);y(this,"srcElement",null);y(this,"inPassiveListener",!1);y(this,"propagationStopped",!1);y(this,"immediatePropagationStopped",!1);if(arguments.length===0)throw new TypeError("The event type must be provided");let r=t==null?{}:Object(t);this.type=String(e),this.bubbles=!!r.bubbles,this.cancelable=!!r.cancelable,this.composed=!!r.composed}get[Symbol.toStringTag](){return"Event"}preventDefault(){this.cancelable&&!this.inPassiveListener&&(this.defaultPrevented=!0,this.returnValue=!1)}stopPropagation(){this.propagationStopped=!0,this.cancelBubble=!0}stopImmediatePropagation(){this.propagationStopped=!0,this.immediatePropagationStopped=!0,this.cancelBubble=!0}composedPath(){return this.target?[this.target]:[]}_setPassive(e){this.inPassiveListener=e}_isPropagationStopped(){return this.propagationStopped}_isImmediatePropagationStopped(){return this.immediatePropagationStopped}},y(Cl,"NONE",0),y(Cl,"CAPTURING_PHASE",1),y(Cl,"AT_TARGET",2),y(Cl,"BUBBLING_PHASE",3),Cl),PCe=class extends aY{constructor(e,t){super(e,t);let r=t==null?null:Object(t);this.detail=r&&"detail"in r?r.detail:null}get[Symbol.toStringTag](){return"CustomEvent"}},OCe=class{constructor(){y(this,"listeners",new Map)}addEventListener(e,t,r){let n=UCe(r);if(n.signal!==void 0&&!LCe(n.signal))throw new TypeError('The "signal" option must be an instance of AbortSignal.');if(t==null||typeof t!="function"&&(typeof t!="object"||t===null)||n.signal?.aborted)return;let i=this.listeners.get(e)??[];if(i.find(a=>a.listener===t&&a.capture===n.capture))return;let o={listener:t,capture:n.capture,once:n.once,passive:n.passive,kind:typeof t=="function"?"function":"object",signal:n.signal};n.signal&&(o.abortListener=()=>{this.removeEventListener(e,t,n.capture)},n.signal.addEventListener("abort",o.abortListener,{once:!0})),i.push(o),this.listeners.set(e,i)}removeEventListener(e,t,r){if(t==null)return;let n=xCe(r),i=this.listeners.get(e);if(!i)return;let s=i.filter(o=>{let a=o.listener===t&&o.capture===n;return a&&o.signal&&o.abortListener&&o.signal.removeEventListener("abort",o.abortListener),!a});if(s.length===0){this.listeners.delete(e);return}this.listeners.set(e,s)}dispatchEvent(e){if(typeof e!="object"||e===null||typeof e.type!="string")throw new TypeError("Argument 1 must be an Event");let t=e,r=(this.listeners.get(t.type)??[]).slice();t.target=this,t.currentTarget=this,t.eventPhase=2;for(let n of r)if(this.listeners.get(t.type)?.includes(n)){if(n.once&&this.removeEventListener(t.type,n.listener,n.capture),t._setPassive(n.passive),n.kind==="function")n.listener.call(this,t);else{let s=n.listener.handleEvent;typeof s=="function"&&s.call(n.listener,t)}if(t._setPassive(!1),t._isImmediatePropagationStopped()||t._isPropagationStopped())break}return t.currentTarget=null,t.eventPhase=0,!t.defaultPrevented}},kl=aY,I2=PCe,MB=OCe,Ro=typeof Lq=="function"?Lq:class extends MB{constructor(){super(),this.aborted=!1,this.reason=void 0}throwIfAborted(){if(this.aborted)throw this.reason instanceof Error?this.reason:new Error(String(this.reason??"AbortError"))}},Su=typeof xq=="function"?xq:class{constructor(){this.signal=new Ro}abort(e){this.signal.aborted||(this.signal.aborted=!0,this.signal.reason=e,this.signal.dispatchEvent(new kl("abort")))}};function b2(e,t){if(typeof e=="function")try{e.name!==t&&Object.defineProperty(e,"name",{configurable:!0,value:t})}catch{}}b2(Ro,"AbortSignal");b2(Su,"AbortController");try{let e=Object.getPrototypeOf(new Su().signal)?.constructor;b2(e,"AbortSignal")}catch{}try{globalThis.AbortSignal=Ro}catch{}try{globalThis.AbortController=Su}catch{}function AY(e){if(e!==void 0)return e;if(typeof globalThis.DOMException=="function")return new globalThis.DOMException("This operation was aborted","AbortError");let t=new Error("This operation was aborted");return t.name="AbortError",t}function HCe(e){let t=new Su;return t.abort(AY(e)),t.signal}function qCe(e){if(typeof e!="number")throw new TypeError(`The "delay" argument must be of type number. Received ${typeof e}`);if(!Number.isFinite(e)||e<0)throw new RangeError(`The value of "delay" is out of range. It must be >= 0. Received ${String(e)}`);return Math.trunc(e)}typeof Ro.abort!="function"&&Object.defineProperty(Ro,"abort",{configurable:!0,writable:!0,value(e=void 0){return HCe(e)}});typeof Ro.timeout!="function"&&Object.defineProperty(Ro,"timeout",{configurable:!0,writable:!0,value(e){let t=qCe(e),r=new Su,n=setTimeout(()=>{r.abort(AY())},t);return typeof n?.unref=="function"&&n.unref(),r.signal.addEventListener("abort",()=>{clearTimeout(n)},{once:!0}),r.signal}});typeof Ro.any!="function"&&Object.defineProperty(Ro,"any",{configurable:!0,writable:!0,value(e){if(!e||typeof e[Symbol.iterator]!="function")throw new TypeError('The "signals" argument must be an iterable');let t=Array.from(e),r=new Su;if(t.length===0)return r.signal;let n=[],i=s=>{for(;n.length>0;){let[o,a]=n.pop();o.removeEventListener?.("abort",a)}r.abort(s.reason)};for(let s of t){if(!s||typeof s.aborted!="boolean"||typeof s.addEventListener!="function")throw new TypeError('The "signals" argument must contain AbortSignal instances');if(s.aborted)return i(s),r.signal;let o=()=>i(s);n.push([s,o]),s.addEventListener("abort",o,{once:!0})}return r.signal}});var GCe=class{constructor(e={}){this._sink=e}getWriter(){let e=this._sink;return{write(t){return Promise.resolve(typeof e.write=="function"?e.write(t):void 0)},close(){return Promise.resolve(typeof e.close=="function"?e.close():void 0)},releaseLock(){}}}},YCe=class{constructor(e={}){this._queue=[],this._pending=[],this._closed=!1,this._error=null;let t=()=>{for(;this._pending.length>0;){let n=this._pending.shift();if(this._error){n.reject(this._error);continue}if(this._queue.length>0){n.resolve({value:this._queue.shift(),done:!1});continue}if(this._closed){n.resolve({value:void 0,done:!0});continue}this._pending.unshift(n);break}},r={enqueue:n=>{this._closed||this._error||(this._queue.push(n),t())},close:()=>{this._closed||this._error||(this._closed=!0,t())},error:n=>{this._closed||this._error||(this._error=n instanceof Error?n:new Error(String(n)),t())}};typeof e.start=="function"&&Promise.resolve().then(()=>e.start(r)).catch(n=>r.error(n))}getReader(){return{read:()=>this._error?Promise.reject(this._error):this._queue.length>0?Promise.resolve({value:this._queue.shift(),done:!1}):this._closed?Promise.resolve({value:void 0,done:!0}):new Promise((e,t)=>{this._pending.push({resolve:e,reject:t})}),releaseLock(){}}}};function C2(e,t){return e.code=t,e}function WCe(e){return C2(new RangeError(`The "${e}" encoding is not supported`),"ERR_ENCODING_NOT_SUPPORTED")}function qi(e){return C2(new TypeError(`The encoded data was not valid for encoding ${e}`),"ERR_ENCODING_INVALID_ENCODED_DATA")}function VCe(){return C2(new TypeError('The "input" argument must be an instance of ArrayBuffer, SharedArrayBuffer, or ArrayBufferView.'),"ERR_INVALID_ARG_TYPE")}function JCe(e){return e.replace(/^[\t\n\f\r ]+|[\t\n\f\r ]+$/g,"")}function jCe(e){let t=JCe(e===void 0?"utf-8":String(e)).toLowerCase();switch(t){case"utf-8":case"utf8":case"unicode-1-1-utf-8":case"unicode11utf8":case"unicode20utf8":case"x-unicode20utf8":return"utf-8";case"utf-16":case"utf-16le":case"ucs-2":case"ucs2":case"csunicode":case"iso-10646-ucs-2":case"unicode":case"unicodefeff":return"utf-16le";case"utf-16be":case"unicodefffe":return"utf-16be";default:throw WCe(t)}}function zCe(e){if(e===void 0)return new Uint8Array(0);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);if(e instanceof ArrayBuffer)return new Uint8Array(e);if(typeof SharedArrayBuffer<"u"&&e instanceof SharedArrayBuffer)return new Uint8Array(e);throw VCe()}function Fm(e,t){if(e<=127){t.push(e);return}if(e<=2047){t.push(192|e>>6,128|e&63);return}if(e<=65535){t.push(224|e>>12,128|e>>6&63,128|e&63);return}t.push(240|e>>18,128|e>>12&63,128|e>>6&63,128|e&63)}function Oq(e=""){let t=String(e),r=[];for(let n=0;n=55296&&i<=56319){let s=n+1;if(s=56320&&o<=57343){let a=65536+(i-55296<<10)+(o-56320);Fm(a,r),n=s;continue}}Fm(65533,r);continue}if(i>=56320&&i<=57343){Fm(65533,r);continue}Fm(i,r)}return new Uint8Array(r)}function fY(e,t){if(t<=65535){e.push(String.fromCharCode(t));return}let r=t-65536;e.push(String.fromCharCode(55296+(r>>10)),String.fromCharCode(56320+(r&1023)))}function Hv(e){return e>=128&&e<=191}function KCe(e,t,r,n){let i=[];for(let s=0;s=194&&o<=223)a=1,A=o&31;else if(o>=224&&o<=239)a=2,A=o&15;else if(o>=240&&o<=244)a=3,A=o&7;else{if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}if(s+a>=e.length){if(r)return{text:i.join(""),pending:Array.from(e.slice(s))};if(t)throw qi(n);i.push("\uFFFD");break}let f=e[s+1];if(!Hv(f)){if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}if(o===224&&f<160||o===237&&f>159||o===240&&f<144||o===244&&f>143){if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}if(A=A<<6|f&63,a>=2){let l=e[s+2];if(!Hv(l)){if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}A=A<<6|l&63}if(a===3){let l=e[s+3];if(!Hv(l)){if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}A=A<<6|l&63}if(A>=55296&&A<=57343){if(t)throw qi(n);i.push("\uFFFD"),s+=a+1;continue}fY(i,A),s+=a+1}return{text:i.join(""),pending:[]}}function XCe(e,t,r,n,i){let s=[],o=t==="utf-16be"?"be":"le";!i&&t==="utf-16le"&&e.length>=2&&e[0]===254&&e[1]===255&&(o="be");for(let a=0;a=e.length){if(n)return{text:s.join(""),pending:Array.from(e.slice(a))};if(r)throw qi(t);s.push("\uFFFD");break}let A=e[a],f=e[a+1],l=o==="le"?A|f<<8:A<<8|f;if(a+=2,l>=55296&&l<=56319){if(a+1>=e.length){if(n)return{text:s.join(""),pending:Array.from(e.slice(a-2))};if(r)throw qi(t);s.push("\uFFFD");continue}let p=e[a],I=e[a+1],S=o==="le"?p|I<<8:p<<8|I;if(S>=56320&&S<=57343){let _=65536+(l-55296<<10)+(S-56320);fY(s,_),a+=2;continue}if(r)throw qi(t);s.push("\uFFFD");continue}if(l>=56320&&l<=57343){if(r)throw qi(t);s.push("\uFFFD");continue}s.push(String.fromCharCode(l))}return{text:s.join(""),pending:[]}}var ZCe=class{encode(e=""){return Oq(e)}encodeInto(e,t){let r=String(e),n=0,i=0;for(let s=0;s=55296&&o<=56319&&s+1=56320&&f<=57343&&(a=r.slice(s,s+2))}a===""&&(a=r[s]??"");let A=Oq(a);if(i+A.length>t.length)break;t.set(A,i),i+=A.length,n+=a.length,a.length===2&&(s+=1)}return{read:n,written:i}}get encoding(){return"utf-8"}get[Symbol.toStringTag](){return"TextEncoder"}},$Ce=class{constructor(e,t){y(this,"normalizedEncoding");y(this,"fatalFlag");y(this,"ignoreBOMFlag");y(this,"pendingBytes",[]);y(this,"bomSeen",!1);let r=t==null?{}:Object(t);this.normalizedEncoding=jCe(e),this.fatalFlag=!!r.fatal,this.ignoreBOMFlag=!!r.ignoreBOM}get encoding(){return this.normalizedEncoding}get fatal(){return this.fatalFlag}get ignoreBOM(){return this.ignoreBOMFlag}get[Symbol.toStringTag](){return"TextDecoder"}decode(e,t){let n=!!(t==null?{}:Object(t)).stream,i=zCe(e),s=new Uint8Array(this.pendingBytes.length+i.length);s.set(this.pendingBytes,0),s.set(i,this.pendingBytes.length);let o=this.normalizedEncoding==="utf-8"?KCe(s,this.fatalFlag,n,this.normalizedEncoding):XCe(s,this.normalizedEncoding,this.fatalFlag,n,this.bomSeen);this.pendingBytes=o.pending;let a=o.text;if(!this.bomSeen&&a.length>0&&(!this.ignoreBOMFlag&&a.charCodeAt(0)===65279&&(a=a.slice(1)),this.bomSeen=!0),!n&&this.pendingBytes.length>0){let A=this.pendingBytes;if(this.pendingBytes=[],this.fatalFlag)throw qi(this.normalizedEncoding);return a+"\uFFFD".repeat(Math.ceil(A.length/2))}return a}},Q2=ZCe,_u=$Ce;function ln(e,t){globalThis[e]=t}typeof globalThis.global>"u"&&ln("global",globalThis);if(typeof globalThis.RegExp=="function"&&!("__secureExecRgiEmojiCompat"in globalThis.RegExp)){let e=globalThis.RegExp,t="^\\p{RGI_Emoji}$",r="[\\u{00A9}\\u{00AE}\\u{203C}\\u{2049}\\u{2122}\\u{2139}\\u{2194}-\\u{21AA}\\u{231A}-\\u{23FF}\\u{24C2}\\u{25AA}-\\u{27BF}\\u{2934}-\\u{2935}\\u{2B05}-\\u{2B55}\\u{3030}\\u{303D}\\u{3297}\\u{3299}\\u{1F000}-\\u{1FAFF}]",n="[#*0-9]\\uFE0F?\\u20E3",i="^(?:"+n+"|\\p{Regional_Indicator}{2}|"+r+"(?:\\uFE0F|\\u200D(?:"+n+"|"+r+")|[\\u{1F3FB}-\\u{1F3FF}])*)$";try{new e(t,"v")}catch(s){if(String(s?.message??s).includes("RGI_Emoji")){let o=function(A,f){let l=A instanceof e&&f===void 0?A.source:String(A),p=f===void 0?A instanceof e?A.flags:"":String(f);try{return new e(A,f)}catch(I){if(l===t&&p==="v")return new e(i,"u");throw I}};Object.setPrototypeOf(o,e),o.prototype=e.prototype,Object.defineProperty(o.prototype,"constructor",{value:o,writable:!0,configurable:!0}),ln("RegExp",Object.assign(o,{__secureExecRgiEmojiCompat:!0}))}}}ln("TextEncoder",Q2);ln("TextDecoder",_u);ln("Event",kl);ln("CustomEvent",I2);ln("EventTarget",MB);ln("AbortSignal",Ro);ln("AbortController",Su);ln("structuredClone",kCe);globalThis.WebAssembly&&typeof globalThis.WebAssembly.instantiateStreaming!="function"&&(globalThis.WebAssembly.instantiateStreaming=async function(t,r){let n=await t;if(n==null||typeof n.arrayBuffer!="function")throw new TypeError("WebAssembly.instantiateStreaming requires a Response or promise for one");let i=new Uint8Array(await n.arrayBuffer());return globalThis.WebAssembly.instantiate(i,r)});ln("ReadableStream",typeof Wr.ReadableStream=="function"?Wr.ReadableStream:YCe);ln("WritableStream",typeof Wr.WritableStream=="function"?Wr.WritableStream:GCe);typeof Wr.TransformStream=="function"&&ln("TransformStream",Wr.TransformStream);typeof Pp=="function"&&ln("TextEncoderStream",Pp);typeof Op=="function"&&ln("TextDecoderStream",Op);var uu=I1.default?.webidl??I1.default;uu?.is&&(uu.is.ReadableStream=e=>e!=null&&(e instanceof globalThis.ReadableStream||typeof e.getReader=="function"),uu.is.AbortSignal=e=>e!=null&&(e instanceof globalThis.AbortSignal||typeof e.aborted=="boolean"&&typeof e.addEventListener=="function"));uu?.converters?.AbortSignal&&(uu.converters.AbortSignal=(e,...t)=>e!=null&&(e instanceof globalThis.AbortSignal||typeof e.aborted=="boolean"&&typeof e.addEventListener=="function")?e:uu.interfaceConverter(uu.is.AbortSignal,"AbortSignal")(e,...t));var uY=[{name:"_processConfig",c:"h"},{name:"process.cpuUsage",c:"h"},{name:"process.memoryUsage",c:"h"},{name:"process.resourceUsage",c:"h"},{name:"process.versions",c:"h"},{name:"_processKill",c:"h"},{name:"_processSignalState",c:"h"},{name:"_osConfig",c:"h"},{name:"bridge",c:"h"},{name:"_registerHandle",c:"h"},{name:"_unregisterHandle",c:"h"},{name:"_waitForActiveHandles",c:"h"},{name:"_getActiveHandles",c:"h"},{name:"_childProcessDispatch",c:"h"},{name:"_childProcessModule",c:"h"},{name:"_osModule",c:"h"},{name:"_moduleModule",c:"h"},{name:"_httpModule",c:"h"},{name:"_httpsModule",c:"h"},{name:"_http2Module",c:"h"},{name:"_dnsModule",c:"h"},{name:"_dgramModule",c:"h"},{name:"_netModule",c:"h"},{name:"_tlsModule",c:"h"},{name:"_vmCreateContext",c:"h"},{name:"_vmRunInContext",c:"h"},{name:"_vmRunInThisContext",c:"h"},{name:"_netSocketDispatch",c:"h"},{name:"_httpServerDispatch",c:"h"},{name:"_httpServerUpgradeDispatch",c:"h"},{name:"_httpServerConnectDispatch",c:"h"},{name:"_http2Dispatch",c:"h"},{name:"_timerDispatch",c:"h"},{name:"_upgradeSocketData",c:"h"},{name:"_upgradeSocketEnd",c:"h"},{name:"ProcessExitError",c:"h"},{name:"_log",c:"h"},{name:"_error",c:"h"},{name:"_pythonRpc",c:"h"},{name:"_pythonStdinRead",c:"h"},{name:"_loadPolyfill",c:"h"},{name:"_resolveModule",c:"h"},{name:"_loadFile",c:"h"},{name:"_resolveModuleSync",c:"h"},{name:"_loadFileSync",c:"h"},{name:"_moduleFormat",c:"h"},{name:"_scheduleTimer",c:"h"},{name:"_cryptoRandomFill",c:"h"},{name:"_cryptoRandomUUID",c:"h"},{name:"_cryptoHashDigest",c:"h"},{name:"_cryptoHmacDigest",c:"h"},{name:"_cryptoPbkdf2",c:"h"},{name:"_cryptoScrypt",c:"h"},{name:"_cryptoCipheriv",c:"h"},{name:"_cryptoDecipheriv",c:"h"},{name:"_cryptoCipherivCreate",c:"h"},{name:"_cryptoCipherivUpdate",c:"h"},{name:"_cryptoCipherivFinal",c:"h"},{name:"_cryptoSign",c:"h"},{name:"_cryptoVerify",c:"h"},{name:"_cryptoAsymmetricOp",c:"h"},{name:"_cryptoCreateKeyObject",c:"h"},{name:"_cryptoGenerateKeyPairSync",c:"h"},{name:"_cryptoGenerateKeySync",c:"h"},{name:"_cryptoGeneratePrimeSync",c:"h"},{name:"_cryptoDiffieHellman",c:"h"},{name:"_cryptoDiffieHellmanGroup",c:"h"},{name:"_cryptoDiffieHellmanSessionCreate",c:"h"},{name:"_cryptoDiffieHellmanSessionCall",c:"h"},{name:"_cryptoDiffieHellmanSessionDestroy",c:"h"},{name:"_cryptoSubtle",c:"h"},{name:"_benchNoop",c:"h"},{name:"_fsReadFile",c:"h"},{name:"_fsReadFileAsync",c:"h"},{name:"_fsWriteFile",c:"h"},{name:"_fsWriteFileAsync",c:"h"},{name:"_fsReadFileBinary",c:"h"},{name:"_fsReadFileBinaryAsync",c:"h"},{name:"_fsWriteFileBinary",c:"h"},{name:"_fsWriteFileBinaryAsync",c:"h"},{name:"_fsReadDir",c:"h"},{name:"_fsReadDirAsync",c:"h"},{name:"_fsMkdir",c:"h"},{name:"_fsMkdirAsync",c:"h"},{name:"_fsRmdir",c:"h"},{name:"_fsRmdirAsync",c:"h"},{name:"_fsExists",c:"h"},{name:"_fsAccessAsync",c:"h"},{name:"_fsStat",c:"h"},{name:"_fsStatAsync",c:"h"},{name:"_fsUnlink",c:"h"},{name:"_fsUnlinkAsync",c:"h"},{name:"_fsRename",c:"h"},{name:"_fsRenameAsync",c:"h"},{name:"_fsChmod",c:"h"},{name:"_fsChmodAsync",c:"h"},{name:"_fsChown",c:"h"},{name:"_fsChownAsync",c:"h"},{name:"_fsLink",c:"h"},{name:"_fsLinkAsync",c:"h"},{name:"_fsSymlink",c:"h"},{name:"_fsSymlinkAsync",c:"h"},{name:"_fsReadlink",c:"h"},{name:"_fsReadlinkAsync",c:"h"},{name:"_fsLstat",c:"h"},{name:"_fsLstatAsync",c:"h"},{name:"_fsTruncate",c:"h"},{name:"_fsTruncateAsync",c:"h"},{name:"_fsUtimes",c:"h"},{name:"_fsLutimes",c:"h"},{name:"_fsUtimesAsync",c:"h"},{name:"_fsLutimesAsync",c:"h"},{name:"fs.futimesSync",c:"h"},{name:"fs.openSync",c:"h"},{name:"fs.closeSync",c:"h"},{name:"fs.readSync",c:"h"},{name:"fs.writeSync",c:"h"},{name:"fs.fstatSync",c:"h"},{name:"_fs",c:"h"},{name:"_childProcessSpawnStart",c:"h"},{name:"_childProcessPoll",c:"h"},{name:"_childProcessStdinWrite",c:"h"},{name:"_childProcessStdinClose",c:"h"},{name:"_childProcessKill",c:"h"},{name:"_childProcessSpawnSync",c:"h"},{name:"_benchNetTcpMetricsResetRaw",c:"h"},{name:"_benchNetTcpMetricsSnapshotRaw",c:"h"},{name:"_networkDnsLookupRaw",c:"h"},{name:"_networkDnsLookupSyncRaw",c:"h"},{name:"_networkDnsResolveRaw",c:"h"},{name:"_networkHttpServerListenRaw",c:"h"},{name:"_networkHttpServerCloseRaw",c:"h"},{name:"_networkHttpServerRespondRaw",c:"h"},{name:"_networkHttpServerRequestRaw",c:"h"},{name:"_networkHttpServerWaitRaw",c:"h"},{name:"_networkHttp2ServerListenRaw",c:"h"},{name:"_networkHttp2ServerCloseRaw",c:"h"},{name:"_networkHttp2ServerWaitRaw",c:"h"},{name:"_networkHttp2SessionConnectRaw",c:"h"},{name:"_networkHttp2SessionRequestRaw",c:"h"},{name:"_networkHttp2SessionSettingsRaw",c:"h"},{name:"_networkHttp2SessionSetLocalWindowSizeRaw",c:"h"},{name:"_networkHttp2SessionGoawayRaw",c:"h"},{name:"_networkHttp2SessionCloseRaw",c:"h"},{name:"_networkHttp2SessionDestroyRaw",c:"h"},{name:"_networkHttp2SessionWaitRaw",c:"h"},{name:"_networkHttp2ServerPollRaw",c:"h"},{name:"_networkHttp2SessionPollRaw",c:"h"},{name:"_networkHttp2StreamRespondRaw",c:"h"},{name:"_networkHttp2StreamPushStreamRaw",c:"h"},{name:"_networkHttp2StreamWriteRaw",c:"h"},{name:"_networkHttp2StreamEndRaw",c:"h"},{name:"_networkHttp2StreamCloseRaw",c:"h"},{name:"_networkHttp2StreamPauseRaw",c:"h"},{name:"_networkHttp2StreamResumeRaw",c:"h"},{name:"_networkHttp2StreamRespondWithFileRaw",c:"h"},{name:"_networkHttp2ServerRespondRaw",c:"h"},{name:"_upgradeSocketWriteRaw",c:"h"},{name:"_upgradeSocketEndRaw",c:"h"},{name:"_upgradeSocketDestroyRaw",c:"h"},{name:"_netSocketConnectRaw",c:"h"},{name:"_netSocketPollRaw",c:"h"},{name:"_netSocketWaitConnectRaw",c:"h"},{name:"_netSocketReadRaw",c:"h"},{name:"_netSocketSetNoDelayRaw",c:"h"},{name:"_netSocketSetKeepAliveRaw",c:"h"},{name:"_netSocketWriteRaw",c:"h"},{name:"_netSocketEndRaw",c:"h"},{name:"_netSocketDestroyRaw",c:"h"},{name:"_netSocketUpgradeTlsRaw",c:"h"},{name:"_netSocketGetTlsClientHelloRaw",c:"h"},{name:"_netSocketTlsQueryRaw",c:"h"},{name:"_tlsGetCiphersRaw",c:"h"},{name:"_netReserveTcpPortRaw",c:"h"},{name:"_netReleaseTcpPortRaw",c:"h"},{name:"_netServerListenRaw",c:"h"},{name:"_netServerAcceptRaw",c:"h"},{name:"_netServerCloseRaw",c:"h"},{name:"_dgramSocketCreateRaw",c:"h"},{name:"_dgramSocketBindRaw",c:"h"},{name:"_dgramSocketRecvRaw",c:"h"},{name:"_dgramSocketSendRaw",c:"h"},{name:"_dgramSocketCloseRaw",c:"h"},{name:"_dgramSocketAddressRaw",c:"h"},{name:"_dgramSocketSetBufferSizeRaw",c:"h"},{name:"_dgramSocketGetBufferSizeRaw",c:"h"},{name:"_sqliteConstantsRaw",c:"h"},{name:"_sqliteDatabaseOpenRaw",c:"h"},{name:"_sqliteDatabaseCloseRaw",c:"h"},{name:"_sqliteDatabaseExecRaw",c:"h"},{name:"_sqliteDatabaseQueryRaw",c:"h"},{name:"_sqliteDatabasePrepareRaw",c:"h"},{name:"_sqliteDatabaseLocationRaw",c:"h"},{name:"_sqliteDatabaseCheckpointRaw",c:"h"},{name:"_sqliteStatementRunRaw",c:"h"},{name:"_sqliteStatementGetRaw",c:"h"},{name:"_sqliteStatementAllRaw",c:"h"},{name:"_sqliteStatementColumnsRaw",c:"h"},{name:"_sqliteStatementSetReturnArraysRaw",c:"h"},{name:"_sqliteStatementSetReadBigIntsRaw",c:"h"},{name:"_sqliteStatementSetAllowBareNamedParametersRaw",c:"h"},{name:"_sqliteStatementSetAllowUnknownNamedParametersRaw",c:"h"},{name:"_sqliteStatementFinalizeRaw",c:"h"},{name:"_batchResolveModules",c:"h"},{name:"_kernelPollRaw",c:"h"},{name:"_kernelIsattyRaw",c:"h"},{name:"_kernelTtySizeRaw",c:"h"},{name:"_kernelStdioWriteRaw",c:"h"},{name:"_kernelStdinReadRaw",c:"h"},{name:"_kernelStdinRead",c:"h"},{name:"_ptySetRawMode",c:"h"},{name:"require",c:"h"},{name:"_requireFrom",c:"h"},{name:"_dynamicImport",c:"h"},{name:"__dynamicImport",c:"h"},{name:"_moduleCache",c:"h"},{name:"_pendingModules",c:"m"},{name:"_currentModule",c:"m"},{name:"_stdinData",c:"m"},{name:"_stdinPosition",c:"m"},{name:"_stdinEnded",c:"m"},{name:"_stdinFlowMode",c:"m"},{name:"module",c:"m"},{name:"exports",c:"m"},{name:"__filename",c:"m"},{name:"__dirname",c:"m"},{name:"fetch",c:"h"},{name:"Headers",c:"h"},{name:"Request",c:"h"},{name:"Response",c:"h"},{name:"DOMException",c:"h"},{name:"__importMetaResolve",c:"h"},{name:"Blob",c:"h"},{name:"File",c:"h"},{name:"FormData",c:"h"}],OFe=uY.filter(e=>e.c==="h").map(e=>e.name),HFe=uY.filter(e=>e.c==="m").map(e=>e.name);function cY(e,t,r,n={}){let i=n.mutable===!0,s=n.enumerable!==!1;Object.defineProperty(e,t,{value:r,writable:i,configurable:!0,enumerable:s})}function et(e,t){cY(globalThis,e,t)}function vu(e,t){cY(globalThis,e,t,{mutable:!0})}function eQe(e){return JSON.stringify(e,(t,r)=>r===void 0?{__secureExecDispatchType:"undefined"}:r)}function tQe(e,t){return`__bd:${e}:${eQe(t)}`}function rQe(e){if(e===null)return;let t=JSON.parse(e);if(t.__bd_error){let r=new Error(t.__bd_error.message);throw r.name=t.__bd_error.name??"Error",t.__bd_error.code!==void 0&&(r.code=t.__bd_error.code),t.__bd_error.stack&&(r.stack=t.__bd_error.stack),r}return t.__bd_result}function nQe(){if(!_loadPolyfill)throw new Error("_loadPolyfill is not available in sandbox");return _loadPolyfill}function zg(e,...t){let r=nQe();return rQe(r.applySyncPromise(void 0,[tQe(e,t)]))}var iQe=Object.create,w2=Object.defineProperty,sQe=Object.getOwnPropertyDescriptor,lY=Object.getOwnPropertyNames,oQe=Object.getPrototypeOf,aQe=Object.prototype.hasOwnProperty,S2=(e,t)=>function(){return t||(0,e[lY(e)[0]])((t={exports:{}}).exports,t),t.exports},_2=(e,t)=>{for(var r in t)w2(e,r,{get:t[r],enumerable:!0})},AQe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of lY(t))!aQe.call(e,i)&&i!==r&&w2(e,i,{get:()=>t[i],enumerable:!(n=sQe(t,i))||n.enumerable});return e},v2=(e,t,r)=>(r=e!=null?iQe(oQe(e)):{},AQe(t||!e||!e.__esModule?w2(r,"default",{value:e,enumerable:!0}):r,e));var hY=S2({"../../../tmp/buffer-build/node_modules/base64-js/index.js"(e){"use strict";e.byteLength=A,e.toByteArray=l,e.fromByteArray=S;var t=[],r=[],n=typeof Uint8Array<"u"?Uint8Array:Array,i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(s=0,o=i.length;s0)throw new Error("Invalid string. Length must be a multiple of 4");var O=_.indexOf("=");O===-1&&(O=N);var x=O===N?0:4-O%4;return[O,x]}function A(_){var N=a(_),O=N[0],x=N[1];return(O+x)*3/4-x}function f(_,N,O){return(N+O)*3/4-O}function l(_){var N,O=a(_),x=O[0],G=O[1],Y=new n(f(_,x,G)),X=0,Z=G>0?x-4:x,j;for(j=0;j>16&255,Y[X++]=N>>8&255,Y[X++]=N&255;return G===2&&(N=r[_.charCodeAt(j)]<<2|r[_.charCodeAt(j+1)]>>4,Y[X++]=N&255),G===1&&(N=r[_.charCodeAt(j)]<<10|r[_.charCodeAt(j+1)]<<4|r[_.charCodeAt(j+2)]>>2,Y[X++]=N>>8&255,Y[X++]=N&255),Y}function p(_){return t[_>>18&63]+t[_>>12&63]+t[_>>6&63]+t[_&63]}function I(_,N,O){for(var x,G=[],Y=N;YZ?Z:X+Y));return x===1?(N=_[O-1],G.push(t[N>>2]+t[N<<4&63]+"==")):x===2&&(N=(_[O-2]<<8)+_[O-1],G.push(t[N>>10]+t[N>>4&63]+t[N<<2&63]+"=")),G.join("")}}}),fQe=S2({"../../../tmp/buffer-build/node_modules/ieee754/index.js"(e){e.read=function(t,r,n,i,s){var o,a,A=s*8-i-1,f=(1<>1,p=-7,I=n?s-1:0,S=n?-1:1,_=t[r+I];for(I+=S,o=_&(1<<-p)-1,_>>=-p,p+=A;p>0;o=o*256+t[r+I],I+=S,p-=8);for(a=o&(1<<-p)-1,o>>=-p,p+=i;p>0;a=a*256+t[r+I],I+=S,p-=8);if(o===0)o=1-l;else{if(o===f)return a?NaN:(_?-1:1)*(1/0);a=a+Math.pow(2,i),o=o-l}return(_?-1:1)*a*Math.pow(2,o-i)},e.write=function(t,r,n,i,s,o){var a,A,f,l=o*8-s-1,p=(1<>1,S=s===23?Math.pow(2,-24)-Math.pow(2,-77):0,_=i?0:o-1,N=i?1:-1,O=r<0||r===0&&1/r<0?1:0;for(r=Math.abs(r),isNaN(r)||r===1/0?(A=isNaN(r)?1:0,a=p):(a=Math.floor(Math.log(r)/Math.LN2),r*(f=Math.pow(2,-a))<1&&(a--,f*=2),a+I>=1?r+=S/f:r+=S*Math.pow(2,1-I),r*f>=2&&(a++,f/=2),a+I>=p?(A=0,a=p):a+I>=1?(A=(r*f-1)*Math.pow(2,s),a=a+I):(A=r*Math.pow(2,I-1)*Math.pow(2,s),a=0));s>=8;t[n+_]=A&255,_+=N,A/=256,s-=8);for(a=a<0;t[n+_]=a&255,_+=N,a/=256,l-=8);t[n+_-N]|=O*128}}}),R2=S2({"../../../tmp/buffer-build/node_modules/buffer/index.js"(e){"use strict";var t=hY(),r=fQe(),n=typeof Symbol=="function"&&typeof Symbol.for=="function"?Symbol.for("nodejs.util.inspect.custom"):null;e.Buffer=a,e.SlowBuffer=G,e.INSPECT_MAX_BYTES=50;var i=2147483647;e.kMaxLength=i,a.TYPED_ARRAY_SUPPORT=s(),!a.TYPED_ARRAY_SUPPORT&&typeof console<"u"&&typeof console.error=="function"&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function s(){try{let F=new Uint8Array(1),m={foo:function(){return 42}};return Object.setPrototypeOf(m,Uint8Array.prototype),Object.setPrototypeOf(F,m),F.foo()===42}catch{return!1}}Object.defineProperty(a.prototype,"parent",{enumerable:!0,get:function(){if(a.isBuffer(this))return this.buffer}}),Object.defineProperty(a.prototype,"offset",{enumerable:!0,get:function(){if(a.isBuffer(this))return this.byteOffset}});function o(F){if(F>i)throw new RangeError('The value "'+F+'" is invalid for option "size"');let m=new Uint8Array(F);return Object.setPrototypeOf(m,a.prototype),m}function a(F,m,Q){if(typeof F=="number"){if(typeof m=="string")throw new TypeError('The "string" argument must be of type string. Received type number');return p(F)}return A(F,m,Q)}a.poolSize=8192;function A(F,m,Q){if(typeof F=="string")return I(F,m);if(ArrayBuffer.isView(F))return _(F);if(F==null)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof F);if(ve(F,ArrayBuffer)||F&&ve(F.buffer,ArrayBuffer)||typeof SharedArrayBuffer<"u"&&(ve(F,SharedArrayBuffer)||F&&ve(F.buffer,SharedArrayBuffer)))return N(F,m,Q);if(typeof F=="number")throw new TypeError('The "value" argument must not be of type number. Received type number');let L=F.valueOf&&F.valueOf();if(L!=null&&L!==F)return a.from(L,m,Q);let W=O(F);if(W)return W;if(typeof Symbol<"u"&&Symbol.toPrimitive!=null&&typeof F[Symbol.toPrimitive]=="function")return a.from(F[Symbol.toPrimitive]("string"),m,Q);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof F)}a.from=function(F,m,Q){return A(F,m,Q)},Object.setPrototypeOf(a.prototype,Uint8Array.prototype),Object.setPrototypeOf(a,Uint8Array);function f(F){if(typeof F!="number")throw new TypeError('"size" argument must be of type number');if(F<0)throw new RangeError('The value "'+F+'" is invalid for option "size"')}function l(F,m,Q){return f(F),F<=0?o(F):m!==void 0?typeof Q=="string"?o(F).fill(m,Q):o(F).fill(m):o(F)}a.alloc=function(F,m,Q){return l(F,m,Q)};function p(F){return f(F),o(F<0?0:x(F)|0)}a.allocUnsafe=function(F){return p(F)},a.allocUnsafeSlow=function(F){return p(F)};function I(F,m){if((typeof m!="string"||m==="")&&(m="utf8"),!a.isEncoding(m))throw new TypeError("Unknown encoding: "+m);let Q=Y(F,m)|0,L=o(Q),W=L.write(F,m);return W!==Q&&(L=L.slice(0,W)),L}function S(F){let m=F.length<0?0:x(F.length)|0,Q=o(m);for(let L=0;L=i)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+i.toString(16)+" bytes");return F|0}function G(F){return+F!=F&&(F=0),a.alloc(+F)}a.isBuffer=function(m){return m!=null&&m._isBuffer===!0&&m!==a.prototype},a.compare=function(m,Q){if(ve(m,Uint8Array)&&(m=a.from(m,m.offset,m.byteLength)),ve(Q,Uint8Array)&&(Q=a.from(Q,Q.offset,Q.byteLength)),!a.isBuffer(m)||!a.isBuffer(Q))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(m===Q)return 0;let L=m.length,W=Q.length;for(let z=0,ae=Math.min(L,W);z=W.length)break;let le=W.length-z,ye=ae.length>le?le:ae.length;Uint8Array.prototype.set.call(W,ae.subarray(0,ye),z),z+=ye}return W};function Y(F,m){if(a.isBuffer(F))return F.length;if(ArrayBuffer.isView(F)||ve(F,ArrayBuffer))return F.byteLength;if(typeof F!="string")throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof F);let Q=F.length,L=arguments.length>2&&arguments[2]===!0;if(!L&&Q===0)return 0;let W=!1;for(;;)switch(m){case"ascii":case"latin1":case"binary":return Q;case"utf8":case"utf-8":return Ue(F).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Q*2;case"hex":return Q>>>1;case"base64":case"base64url":return De(F).length;default:if(W)return L?-1:Ue(F).length;m=(""+m).toLowerCase(),W=!0}}a.byteLength=Y;function X(F,m,Q){let L=!1;if((m===void 0||m<0)&&(m=0),m>this.length||((Q===void 0||Q>this.length)&&(Q=this.length),Q<=0)||(Q>>>=0,m>>>=0,Q<=m))return"";for(F||(F="utf8");;)switch(F){case"hex":return D(this,m,Q);case"utf8":case"utf-8":return g(this,m,Q);case"ascii":return C(this,m,Q);case"latin1":case"binary":return h(this,m,Q);case"base64":return b(this,m,Q);case"base64url":return c(this,m,Q);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return M(this,m,Q);default:if(L)throw new TypeError("Unknown encoding: "+F);F=(F+"").toLowerCase(),L=!0}}a.prototype._isBuffer=!0;function Z(F,m,Q){let L=F[m];F[m]=F[Q],F[Q]=L}a.prototype.swap16=function(){let m=this.length;if(m%2!==0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let Q=0;QQ&&(m+=" ... "),""},n&&(a.prototype[n]=a.prototype.inspect),a.prototype.compare=function(m,Q,L,W,z){if(ve(m,Uint8Array)&&(m=a.from(m,m.offset,m.byteLength)),!a.isBuffer(m))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof m);if(Q===void 0&&(Q=0),L===void 0&&(L=m?m.length:0),W===void 0&&(W=0),z===void 0&&(z=this.length),Q<0||L>m.length||W<0||z>this.length)throw new RangeError("out of range index");if(W>=z&&Q>=L)return 0;if(W>=z)return-1;if(Q>=L)return 1;if(Q>>>=0,L>>>=0,W>>>=0,z>>>=0,this===m)return 0;let ae=z-W,le=L-Q,ye=Math.min(ae,le),bt=this.slice(W,z),Ee=m.slice(Q,L);for(let ge=0;ge2147483647?Q=2147483647:Q<-2147483648&&(Q=-2147483648),Q=+Q,He(Q)&&(Q=W?0:F.length-1),Q<0&&(Q=F.length+Q),Q>=F.length){if(W)return-1;Q=F.length-1}else if(Q<0)if(W)Q=0;else return-1;if(typeof m=="string"&&(m=a.from(m,L)),a.isBuffer(m))return m.length===0?-1:se(F,m,Q,L,W);if(typeof m=="number")return m=m&255,typeof Uint8Array.prototype.indexOf=="function"?W?Uint8Array.prototype.indexOf.call(F,m,Q):Uint8Array.prototype.lastIndexOf.call(F,m,Q):se(F,[m],Q,L,W);throw new TypeError("val must be string, number or Buffer")}function se(F,m,Q,L,W){let z=1,ae=F.length,le=m.length;if(L!==void 0&&(L=String(L).toLowerCase(),L==="ucs2"||L==="ucs-2"||L==="utf16le"||L==="utf-16le")){if(F.length<2||m.length<2)return-1;z=2,ae/=2,le/=2,Q/=2}function ye(Ee,ge){return z===1?Ee[ge]:Ee.readUInt16BE(ge*z)}let bt;if(W){let Ee=-1;for(bt=Q;btae&&(Q=ae-le),bt=Q;bt>=0;bt--){let Ee=!0;for(let ge=0;geW&&(L=W)):L=W;let z=m.length;L>z/2&&(L=z/2);let ae;for(ae=0;ae>>0,isFinite(L)?(L=L>>>0,W===void 0&&(W="utf8")):(W=L,L=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");let z=this.length-Q;if((L===void 0||L>z)&&(L=z),m.length>0&&(L<0||Q<0)||Q>this.length)throw new RangeError("Attempt to write outside buffer bounds");W||(W="utf8");let ae=!1;for(;;)switch(W){case"hex":return ie(this,m,Q,L);case"utf8":case"utf-8":return ce(this,m,Q,L);case"ascii":case"latin1":case"binary":return H(this,m,Q,L);case"base64":case"base64url":return E(this,m,Q,L);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return v(this,m,Q,L);default:if(ae)throw new TypeError("Unknown encoding: "+W);W=(""+W).toLowerCase(),ae=!0}},a.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function b(F,m,Q){return m===0&&Q===F.length?t.fromByteArray(F):t.fromByteArray(F.slice(m,Q))}function c(F,m,Q){return b(F,m,Q).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function g(F,m,Q){Q=Math.min(F.length,Q);let L=[],W=m;for(;W239?4:z>223?3:z>191?2:1;if(W+le<=Q){let ye,bt,Ee,ge;switch(le){case 1:z<128&&(ae=z);break;case 2:ye=F[W+1],(ye&192)===128&&(ge=(z&31)<<6|ye&63,ge>127&&(ae=ge));break;case 3:ye=F[W+1],bt=F[W+2],(ye&192)===128&&(bt&192)===128&&(ge=(z&15)<<12|(ye&63)<<6|bt&63,ge>2047&&(ge<55296||ge>57343)&&(ae=ge));break;case 4:ye=F[W+1],bt=F[W+2],Ee=F[W+3],(ye&192)===128&&(bt&192)===128&&(Ee&192)===128&&(ge=(z&15)<<18|(ye&63)<<12|(bt&63)<<6|Ee&63,ge>65535&&ge<1114112&&(ae=ge))}}ae===null?(ae=65533,le=1):ae>65535&&(ae-=65536,L.push(ae>>>10&1023|55296),ae=56320|ae&1023),L.push(ae),W+=le}return R(L)}var w=4096;function R(F){let m=F.length;if(m<=w)return String.fromCharCode.apply(String,F);let Q="",L=0;for(;LL)&&(Q=L);let W="";for(let z=m;zL&&(m=L),Q<0?(Q+=L,Q<0&&(Q=0)):Q>L&&(Q=L),QQ)throw new RangeError("Trying to access beyond buffer length")}a.prototype.readUintLE=a.prototype.readUIntLE=function(m,Q,L){m=m>>>0,Q=Q>>>0,L||B(m,Q,this.length);let W=this[m],z=1,ae=0;for(;++ae>>0,Q=Q>>>0,L||B(m,Q,this.length);let W=this[m+--Q],z=1;for(;Q>0&&(z*=256);)W+=this[m+--Q]*z;return W},a.prototype.readUint8=a.prototype.readUInt8=function(m,Q){return m=m>>>0,Q||B(m,1,this.length),this[m]},a.prototype.readUint16LE=a.prototype.readUInt16LE=function(m,Q){return m=m>>>0,Q||B(m,2,this.length),this[m]|this[m+1]<<8},a.prototype.readUint16BE=a.prototype.readUInt16BE=function(m,Q){return m=m>>>0,Q||B(m,2,this.length),this[m]<<8|this[m+1]},a.prototype.readUint32LE=a.prototype.readUInt32LE=function(m,Q){return m=m>>>0,Q||B(m,4,this.length),(this[m]|this[m+1]<<8|this[m+2]<<16)+this[m+3]*16777216},a.prototype.readUint32BE=a.prototype.readUInt32BE=function(m,Q){return m=m>>>0,Q||B(m,4,this.length),this[m]*16777216+(this[m+1]<<16|this[m+2]<<8|this[m+3])},a.prototype.readBigUInt64LE=Ne(function(m){m=m>>>0,Qe(m,"offset");let Q=this[m],L=this[m+7];(Q===void 0||L===void 0)&&_e(m,this.length-8);let W=Q+this[++m]*2**8+this[++m]*2**16+this[++m]*2**24,z=this[++m]+this[++m]*2**8+this[++m]*2**16+L*2**24;return BigInt(W)+(BigInt(z)<>>0,Qe(m,"offset");let Q=this[m],L=this[m+7];(Q===void 0||L===void 0)&&_e(m,this.length-8);let W=Q*2**24+this[++m]*2**16+this[++m]*2**8+this[++m],z=this[++m]*2**24+this[++m]*2**16+this[++m]*2**8+L;return(BigInt(W)<>>0,Q=Q>>>0,L||B(m,Q,this.length);let W=this[m],z=1,ae=0;for(;++ae=z&&(W-=Math.pow(2,8*Q)),W},a.prototype.readIntBE=function(m,Q,L){m=m>>>0,Q=Q>>>0,L||B(m,Q,this.length);let W=Q,z=1,ae=this[m+--W];for(;W>0&&(z*=256);)ae+=this[m+--W]*z;return z*=128,ae>=z&&(ae-=Math.pow(2,8*Q)),ae},a.prototype.readInt8=function(m,Q){return m=m>>>0,Q||B(m,1,this.length),this[m]&128?(255-this[m]+1)*-1:this[m]},a.prototype.readInt16LE=function(m,Q){m=m>>>0,Q||B(m,2,this.length);let L=this[m]|this[m+1]<<8;return L&32768?L|4294901760:L},a.prototype.readInt16BE=function(m,Q){m=m>>>0,Q||B(m,2,this.length);let L=this[m+1]|this[m]<<8;return L&32768?L|4294901760:L},a.prototype.readInt32LE=function(m,Q){return m=m>>>0,Q||B(m,4,this.length),this[m]|this[m+1]<<8|this[m+2]<<16|this[m+3]<<24},a.prototype.readInt32BE=function(m,Q){return m=m>>>0,Q||B(m,4,this.length),this[m]<<24|this[m+1]<<16|this[m+2]<<8|this[m+3]},a.prototype.readBigInt64LE=Ne(function(m){m=m>>>0,Qe(m,"offset");let Q=this[m],L=this[m+7];(Q===void 0||L===void 0)&&_e(m,this.length-8);let W=this[m+4]+this[m+5]*2**8+this[m+6]*2**16+(L<<24);return(BigInt(W)<>>0,Qe(m,"offset");let Q=this[m],L=this[m+7];(Q===void 0||L===void 0)&&_e(m,this.length-8);let W=(Q<<24)+this[++m]*2**16+this[++m]*2**8+this[++m];return(BigInt(W)<>>0,Q||B(m,4,this.length),r.read(this,m,!0,23,4)},a.prototype.readFloatBE=function(m,Q){return m=m>>>0,Q||B(m,4,this.length),r.read(this,m,!1,23,4)},a.prototype.readDoubleLE=function(m,Q){return m=m>>>0,Q||B(m,8,this.length),r.read(this,m,!0,52,8)},a.prototype.readDoubleBE=function(m,Q){return m=m>>>0,Q||B(m,8,this.length),r.read(this,m,!1,52,8)};function k(F,m,Q,L,W,z){if(!a.isBuffer(F))throw new TypeError('"buffer" argument must be a Buffer instance');if(m>W||mF.length)throw new RangeError("Index out of range")}a.prototype.writeUintLE=a.prototype.writeUIntLE=function(m,Q,L,W){if(m=+m,Q=Q>>>0,L=L>>>0,!W){let le=Math.pow(2,8*L)-1;k(this,m,Q,L,le,0)}let z=1,ae=0;for(this[Q]=m&255;++ae>>0,L=L>>>0,!W){let le=Math.pow(2,8*L)-1;k(this,m,Q,L,le,0)}let z=L-1,ae=1;for(this[Q+z]=m&255;--z>=0&&(ae*=256);)this[Q+z]=m/ae&255;return Q+L},a.prototype.writeUint8=a.prototype.writeUInt8=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,1,255,0),this[Q]=m&255,Q+1},a.prototype.writeUint16LE=a.prototype.writeUInt16LE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,2,65535,0),this[Q]=m&255,this[Q+1]=m>>>8,Q+2},a.prototype.writeUint16BE=a.prototype.writeUInt16BE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,2,65535,0),this[Q]=m>>>8,this[Q+1]=m&255,Q+2},a.prototype.writeUint32LE=a.prototype.writeUInt32LE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,4,4294967295,0),this[Q+3]=m>>>24,this[Q+2]=m>>>16,this[Q+1]=m>>>8,this[Q]=m&255,Q+4},a.prototype.writeUint32BE=a.prototype.writeUInt32BE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,4,4294967295,0),this[Q]=m>>>24,this[Q+1]=m>>>16,this[Q+2]=m>>>8,this[Q+3]=m&255,Q+4};function ne(F,m,Q,L,W){yr(m,L,W,F,Q,7);let z=Number(m&BigInt(4294967295));F[Q++]=z,z=z>>8,F[Q++]=z,z=z>>8,F[Q++]=z,z=z>>8,F[Q++]=z;let ae=Number(m>>BigInt(32)&BigInt(4294967295));return F[Q++]=ae,ae=ae>>8,F[Q++]=ae,ae=ae>>8,F[Q++]=ae,ae=ae>>8,F[Q++]=ae,Q}function Ae(F,m,Q,L,W){yr(m,L,W,F,Q,7);let z=Number(m&BigInt(4294967295));F[Q+7]=z,z=z>>8,F[Q+6]=z,z=z>>8,F[Q+5]=z,z=z>>8,F[Q+4]=z;let ae=Number(m>>BigInt(32)&BigInt(4294967295));return F[Q+3]=ae,ae=ae>>8,F[Q+2]=ae,ae=ae>>8,F[Q+1]=ae,ae=ae>>8,F[Q]=ae,Q+8}a.prototype.writeBigUInt64LE=Ne(function(m,Q=0){return ne(this,m,Q,BigInt(0),BigInt("0xffffffffffffffff"))}),a.prototype.writeBigUInt64BE=Ne(function(m,Q=0){return Ae(this,m,Q,BigInt(0),BigInt("0xffffffffffffffff"))}),a.prototype.writeIntLE=function(m,Q,L,W){if(m=+m,Q=Q>>>0,!W){let ye=Math.pow(2,8*L-1);k(this,m,Q,L,ye-1,-ye)}let z=0,ae=1,le=0;for(this[Q]=m&255;++z>0)-le&255;return Q+L},a.prototype.writeIntBE=function(m,Q,L,W){if(m=+m,Q=Q>>>0,!W){let ye=Math.pow(2,8*L-1);k(this,m,Q,L,ye-1,-ye)}let z=L-1,ae=1,le=0;for(this[Q+z]=m&255;--z>=0&&(ae*=256);)m<0&&le===0&&this[Q+z+1]!==0&&(le=1),this[Q+z]=(m/ae>>0)-le&255;return Q+L},a.prototype.writeInt8=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,1,127,-128),m<0&&(m=255+m+1),this[Q]=m&255,Q+1},a.prototype.writeInt16LE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,2,32767,-32768),this[Q]=m&255,this[Q+1]=m>>>8,Q+2},a.prototype.writeInt16BE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,2,32767,-32768),this[Q]=m>>>8,this[Q+1]=m&255,Q+2},a.prototype.writeInt32LE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,4,2147483647,-2147483648),this[Q]=m&255,this[Q+1]=m>>>8,this[Q+2]=m>>>16,this[Q+3]=m>>>24,Q+4},a.prototype.writeInt32BE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,4,2147483647,-2147483648),m<0&&(m=4294967295+m+1),this[Q]=m>>>24,this[Q+1]=m>>>16,this[Q+2]=m>>>8,this[Q+3]=m&255,Q+4},a.prototype.writeBigInt64LE=Ne(function(m,Q=0){return ne(this,m,Q,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))}),a.prototype.writeBigInt64BE=Ne(function(m,Q=0){return Ae(this,m,Q,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))});function ue(F,m,Q,L,W,z){if(Q+L>F.length)throw new RangeError("Index out of range");if(Q<0)throw new RangeError("Index out of range")}function pe(F,m,Q,L,W){return m=+m,Q=Q>>>0,W||ue(F,m,Q,4,34028234663852886e22,-34028234663852886e22),r.write(F,m,Q,L,23,4),Q+4}a.prototype.writeFloatLE=function(m,Q,L){return pe(this,m,Q,!0,L)},a.prototype.writeFloatBE=function(m,Q,L){return pe(this,m,Q,!1,L)};function he(F,m,Q,L,W){return m=+m,Q=Q>>>0,W||ue(F,m,Q,8,17976931348623157e292,-17976931348623157e292),r.write(F,m,Q,L,52,8),Q+8}a.prototype.writeDoubleLE=function(m,Q,L){return he(this,m,Q,!0,L)},a.prototype.writeDoubleBE=function(m,Q,L){return he(this,m,Q,!1,L)},a.prototype.copy=function(m,Q,L,W){if(!a.isBuffer(m))throw new TypeError("argument should be a Buffer");if(L||(L=0),!W&&W!==0&&(W=this.length),Q>=m.length&&(Q=m.length),Q||(Q=0),W>0&&W=this.length)throw new RangeError("Index out of range");if(W<0)throw new RangeError("sourceEnd out of bounds");W>this.length&&(W=this.length),m.length-Q>>0,L=L===void 0?this.length:L>>>0,m||(m=0);let z;if(typeof m=="number")for(z=Q;z2**32?W=Ie(String(Q)):typeof Q=="bigint"&&(W=String(Q),(Q>BigInt(2)**BigInt(32)||Q<-(BigInt(2)**BigInt(32)))&&(W=Ie(W)),W+="n"),L+=` It must be ${m}. Received ${W}`,L},RangeError);function Ie(F){let m="",Q=F.length,L=F[0]==="-"?1:0;for(;Q>=L+4;Q-=3)m=`_${F.slice(Q-3,Q)}${m}`;return`${F.slice(0,Q)}${m}`}function be(F,m,Q){Qe(m,"offset"),(F[m]===void 0||F[m+Q]===void 0)&&_e(m,F.length-(Q+1))}function yr(F,m,Q,L,W,z){if(F>Q||F3?m===0||m===BigInt(0)?le=`>= 0${ae} and < 2${ae} ** ${(z+1)*8}${ae}`:le=`>= -(2${ae} ** ${(z+1)*8-1}${ae}) and < 2 ** ${(z+1)*8-1}${ae}`:le=`>= ${m}${ae} and <= ${Q}${ae}`,new de.ERR_OUT_OF_RANGE("value",le,F)}be(L,W,z)}function Qe(F,m){if(typeof F!="number")throw new de.ERR_INVALID_ARG_TYPE(m,"number",F)}function _e(F,m,Q){throw Math.floor(F)!==F?(Qe(F,Q),new de.ERR_OUT_OF_RANGE(Q||"offset","an integer",F)):m<0?new de.ERR_BUFFER_OUT_OF_BOUNDS:new de.ERR_OUT_OF_RANGE(Q||"offset",`>= ${Q?1:0} and <= ${m}`,F)}var Ds=/[^+/0-9A-Za-z-_]/g;function Ge(F){if(F=F.split("=")[0],F=F.trim().replace(Ds,""),F.length<2)return"";for(;F.length%4!==0;)F=F+"=";return F}function Ue(F,m){m=m||1/0;let Q,L=F.length,W=null,z=[];for(let ae=0;ae55295&&Q<57344){if(!W){if(Q>56319){(m-=3)>-1&&z.push(239,191,189);continue}else if(ae+1===L){(m-=3)>-1&&z.push(239,191,189);continue}W=Q;continue}if(Q<56320){(m-=3)>-1&&z.push(239,191,189),W=Q;continue}Q=(W-55296<<10|Q-56320)+65536}else W&&(m-=3)>-1&&z.push(239,191,189);if(W=null,Q<128){if((m-=1)<0)break;z.push(Q)}else if(Q<2048){if((m-=2)<0)break;z.push(Q>>6|192,Q&63|128)}else if(Q<65536){if((m-=3)<0)break;z.push(Q>>12|224,Q>>6&63|128,Q&63|128)}else if(Q<1114112){if((m-=4)<0)break;z.push(Q>>18|240,Q>>12&63|128,Q>>6&63|128,Q&63|128)}else throw new Error("Invalid code point")}return z}function Ts(F){let m=[];for(let Q=0;Q>8,W=Q%256,z.push(W),z.push(L);return z}function De(F){return t.toByteArray(Ge(F))}function en(F,m,Q,L){let W;for(W=0;W=m.length||W>=F.length);++W)m[W+Q]=F[W];return W}function ve(F,m){return F instanceof m||F!=null&&F.constructor!=null&&F.constructor.name!=null&&F.constructor.name===m.name}function He(F){return F!==F}var ai=(function(){let F="0123456789abcdef",m=new Array(256);for(let Q=0;Q<16;++Q){let L=Q*16;for(let W=0;W<16;++W)m[L+W]=F[Q]+F[W]}return m})();function Ne(F){return typeof BigInt>"u"?Ve:F}function Ve(){throw new Error("BigInt not supported")}}}),uB=v2(R2(),1),ql=typeof uB.Buffer.kMaxLength=="number"?uB.Buffer.kMaxLength:2147483647,Kg=typeof uB.Buffer.kStringMaxLength=="number"?uB.Buffer.kStringMaxLength:536870888,dY=Object.freeze({MAX_LENGTH:ql,MAX_STRING_LENGTH:Kg}),gY=Symbol("events.errorMonitor"),UA=10;function Xg(e,t,r){return t==="newListener"&&r[0]==="newListener"||t==="removeListener"&&r[0]==="removeListener"?!1:C1(e,t,r)}function Zg(e,t){PA(e);let r=e._events[t];return Array.isArray(r)?r.slice():[]}function $g(e,t,r,n=!1){PA(e);let i=e._events[t];if(!Array.isArray(i)||i.length===0)return e;let s=null,o=i.slice();for(let a=o.length-1;a>=0;a-=1){let A=o[a];if(!(A.listener!==r&&A.rawListener!==r)&&!(n&&!A.once)){s=A,o.splice(a,1);break}}return s===null||(o.length===0?delete e._events[t]:e._events[t]=o,Xg(e,"removeListener",[t,s.listener])),e}function Hq(e,t){let r=String(t),n=Zg(e,r);for(let i=n.length-1;i>=0;i-=1)$g(e,r,n[i].listener);return e}function C1(e,t,r){let n=Zg(e,t);if(n.length===0)return!1;for(let i of n){i.once&&$g(e,t,i.listener,!0);try{i.listener.apply(e,r)}catch(s){let o=i0(s);if(!o.handled&&o.rethrow!==null)throw o.rethrow;return!0}}return!0}function D2(e,t){return Zg(e,t).length}function T2(e,t){return Zg(e,t).map(r=>r.listener)}function uQe(e,t){return Zg(e,t).map(r=>r.rawListener??r.listener)}function pY(e,t,r){function n(...i){return $g(e,t,n,!0),r.apply(e,i)}return Object.defineProperty(n,"listener",{value:r,configurable:!0,enumerable:!1,writable:!1}),n}function EY(e){return e&&typeof e.getMaxListeners=="function"?e.getMaxListeners():UA}function yY(e,...t){for(let r of t)r&&typeof r.setMaxListeners=="function"&&r.setMaxListeners(e)}function cQe(e,t){if(!e||typeof e.addEventListener!="function")throw new TypeError("AbortSignal is required");let r=()=>t();return e.aborted?(queueMicrotask(r),{dispose(){}}):(e.addEventListener("abort",r,{once:!0}),{dispose(){e.removeEventListener("abort",r)}})}function mY(e,t){return new Promise((r,n)=>{let i=(...o)=>{typeof e.removeListener=="function"&&e.removeListener("error",s),r(o)},s=o=>{typeof e.removeListener=="function"&&e.removeListener(t,i),n(o)};e.once(t,i),t!=="error"&&typeof e.once=="function"&&e.once("error",s)})}function BY(e){e._events=Object.create(null),e._maxListeners=UA,e._maxListenersWarned=new Set}function PA(e){if(!(!e||typeof e!="object"&&typeof e!="function")){if(typeof e._events>"u"){BY(e);return}e._maxListenersWarned instanceof Set||(e._maxListenersWarned=new Set),typeof e._maxListeners!="number"&&(e._maxListeners=UA)}}function lQe(e,t,r){let n=Number.isFinite(e._maxListeners)?e._maxListeners:UA,i=new Error(`Possible EventEmitter memory leak detected. ${r} ${t} listeners added to [EventEmitter]. MaxListeners is ${n}. Use emitter.setMaxListeners() to increase limit`);return i.name="MaxListenersExceededWarning",i.emitter=e,i.type=t,i.count=r,i}function hQe(e,t,r){if(PA(e),e._maxListenersWarned instanceof Set||(e._maxListenersWarned=new Set),e._maxListeners<=0||e._maxListenersWarned.has(t)||r<=e._maxListeners)return;e._maxListenersWarned.add(t);let n=lQe(e,t,r);if(Ce&&typeof Ce.emitWarning=="function"){Ce.emitWarning(n);return}typeof _error<"u"&&_error.applySync(void 0,[`${n.name}: ${n.message}`])}function FB(e,t,r,n=!1){PA(e);let i=e._events[t]??[];n?i.unshift(r):i.push(r),e._events[t]=i,hQe(e,t,i.length)}function Kt(){if(!this||typeof this!="object"&&typeof this!="function")return new Kt;BY(this)}Kt.prototype.addListener=function(e,t){return this.on(e,t)};Kt.prototype.on=function(e,t){if(typeof t!="function")throw new TypeError("listener must be a function");let r=String(e);return Xg(this,"newListener",[r,t]),FB(this,r,{listener:t,once:!1}),this};Kt.prototype.once=function(e,t){if(typeof t!="function")throw new TypeError("listener must be a function");let r=String(e);return Xg(this,"newListener",[r,t]),FB(this,r,{listener:t,rawListener:pY(this,r,t),once:!0}),this};Kt.prototype.prependListener=function(e,t){if(typeof t!="function")throw new TypeError("listener must be a function");let r=String(e);return Xg(this,"newListener",[r,t]),FB(this,r,{listener:t,once:!1},!0),this};Kt.prototype.prependOnceListener=function(e,t){if(typeof t!="function")throw new TypeError("listener must be a function");let r=String(e);return Xg(this,"newListener",[r,t]),FB(this,r,{listener:t,rawListener:pY(this,r,t),once:!0},!0),this};Kt.prototype.removeListener=function(e,t){return $g(this,String(e),t)};Kt.prototype.off=function(e,t){return $g(this,String(e),t)};Kt.prototype.removeAllListeners=function(e){if(PA(this),typeof e>"u"){for(let t of Object.keys(this._events))t!=="removeListener"&&Hq(this,t);delete this._events.removeListener}else Hq(this,String(e));return this};Kt.prototype.emit=function(e,...t){let r=String(e);if(r==="error"&&D2(this,r)===0)throw t[0]instanceof Error?t[0]:new Error(String(t[0]??"Unhandled error event"));let n=C1(this,r,t);return r==="error"&&(n=C1(this,String(gY),t)||n),n};Kt.prototype.listeners=function(e){return T2(this,String(e))};Kt.prototype.rawListeners=function(e){return uQe(this,String(e))};Kt.prototype.listenerCount=function(e){return D2(this,String(e))};Kt.prototype.eventNames=function(){return PA(this),Object.keys(this._events)};Kt.prototype.setMaxListeners=function(e){return PA(this),this._maxListeners=Number(e),this};Kt.prototype.getMaxListeners=function(){return PA(this),Number.isFinite(this._maxListeners)?this._maxListeners:UA};Kt.once=mY;Kt.on=function(t,r,n){let i=n&&n.signal;if(i&&i.aborted)throw i.reason??new Error("The operation was aborted");let s=(N,O)=>(t.off??t.removeListener).call(t,N,O),o=[],a=[],A=null,f=!1,l=()=>{s(r,I),s("error",S),i&&i.removeEventListener&&i.removeEventListener("abort",_)},p={next(){let N=o.shift();if(N!==void 0)return Promise.resolve({value:N,done:!1});if(A){let O=A;return A=null,l(),Promise.reject(O)}return f?Promise.resolve({value:void 0,done:!0}):new Promise((O,x)=>a.push({resolve:O,reject:x}))},return(){f=!0,l();for(let N of a)N.resolve({value:void 0,done:!0});return a.length=0,Promise.resolve({value:void 0,done:!0})},throw(N){return A=N,l(),Promise.reject(N)},[Symbol.asyncIterator](){return this}};function I(...N){let O=a.shift();O?O.resolve({value:N,done:!1}):o.push(N)}function S(N){let O=a.shift();O?(l(),O.reject(N)):A=N}function _(){p.return()}return t.on(r,I),t.on("error",S),i&&i.addEventListener&&i.addEventListener("abort",_,{once:!0}),p};Kt.addAbortListener=function(t,r){return t&&t.aborted?queueMicrotask(()=>r(typeof kl=="function"?new kl("abort"):{type:"abort"})):t&&t.addEventListener&&t.addEventListener("abort",r,{once:!0}),{[Symbol.dispose](){t&&t.removeEventListener&&t.removeEventListener("abort",r)}}};Kt.getEventListeners=T2;Kt.getMaxListeners=EY;Kt.setMaxListeners=yY;Object.defineProperty(Kt,"defaultMaxListeners",{get(){return UA},set(e){UA=Number(e)}});var Ql={addAbortListener:cQe,defaultMaxListeners:UA,errorMonitor:gY,EventEmitter:Kt,getEventListeners:T2,getMaxListeners:EY,listenerCount:D2,once:mY,setMaxListeners:yY};et("_eventsModule",Ql);var Se=v2(R2(),1),Bu=Se.Buffer;typeof Bu.kMaxLength!="number"&&(Bu.kMaxLength=ql);typeof Bu.kStringMaxLength!="number"&&(Bu.kStringMaxLength=Kg);(typeof Bu.constants!="object"||Bu.constants===null)&&(Bu.constants={MAX_LENGTH:ql,MAX_STRING_LENGTH:Kg});var gg=Se.Buffer.prototype;if(typeof gg.utf8Slice!="function"){let e=["utf8","latin1","ascii","hex","base64","ucs2","utf16le"];for(let t of e)typeof gg[t+"Slice"]!="function"&&(gg[t+"Slice"]=function(r,n){return this.toString(t,r,n)}),typeof gg[t+"Write"]!="function"&&(gg[t+"Write"]=function(r,n,i){return this.write(r,n??0,i??this.length-(n??0),t)})}var pg=Se.Buffer;if(typeof pg.allocUnsafe=="function"&&!pg.allocUnsafe._secureExecPatched){let e=pg.allocUnsafe;pg.allocUnsafe=function(r){try{return e.call(this,r)}catch(n){throw n instanceof RangeError&&typeof r=="number"&&r>ql?new Error("Array buffer allocation failed"):n}},pg.allocUnsafe._secureExecPatched=!0}var IY=Se.Buffer,Jm={scheduler:{wait(e=0,t=void 0){return Jm.setTimeout(e,void 0,t)},yield(){return Jm.setImmediate()}},setImmediate(e=void 0,t=void 0){return t?.signal?.aborted?Promise.reject(t.signal.reason??new Error("The operation was aborted")):new Promise((r,n)=>{let i=()=>n(t.signal.reason??new Error("The operation was aborted"));t?.signal?.addEventListener?.("abort",i,{once:!0}),globalThis.setImmediate?.(()=>{t?.signal?.removeEventListener?.("abort",i),r(e)})??globalThis.setTimeout?.(()=>{t?.signal?.removeEventListener?.("abort",i),r(e)},0)})},setInterval(e=1,t=void 0,r=void 0){let n=!0,i=r?.signal;return i?.aborted&&(n=!1),{[Symbol.asyncIterator](){return this},async next(){if(!n)return{done:!0,value:void 0};try{let s=await Jm.setTimeout(e,t,{signal:i});return n?{done:!1,value:s}:{done:!0,value:void 0}}catch(s){throw n=!1,s}},async return(){return n=!1,{done:!0,value:void 0}}}},setTimeout(e=1,t=void 0,r=void 0){return r?.signal?.aborted?Promise.reject(r.signal.reason??new Error("The operation was aborted")):new Promise((n,i)=>{let s=globalThis.setTimeout?.(()=>{r?.signal?.removeEventListener?.("abort",o),n(t)},e??0),o=()=>{typeof globalThis.clearTimeout=="function"&&globalThis.clearTimeout(s),i(r.signal.reason??new Error("The operation was aborted"))};r?.signal?.addEventListener?.("abort",o,{once:!0})})}},bY=new Set;function Fa(){return Array.from(bY,e=>({storage:e,hasStore:e._hasStore===!0,store:e._store}))}function qq(e){for(let t of e)t.storage._hasStore=t.hasStore,t.storage._store=t.store}function kB(e,t,r,n){if(typeof t!="function")return t;let i=Fa();qq(e);try{return t.apply(r,n)}finally{qq(i)}}function Ul(e,t){return typeof e!="function"?e:function(...r){try{return kB(t,e,this,r)}catch(n){throw jB(n),n}}}var CY={AsyncLocalStorage:class{constructor(){this._hasStore=!1,this._store=void 0,bY.add(this)}disable(){this._hasStore=!1,this._store=void 0}enterWith(e){this._hasStore=!0,this._store=e}exit(e,...t){let r={hasStore:this._hasStore,store:this._store};this._hasStore=!1,this._store=void 0;let n=!0;try{let i=e(...t);return i&&typeof i.then=="function"?(n=!1,Promise.resolve(i).finally(()=>{this._hasStore=r.hasStore,this._store=r.store})):i}finally{n&&(this._hasStore=r.hasStore,this._store=r.store)}}getStore(){return this._hasStore?this._store:void 0}run(e,t,...r){let n={hasStore:this._hasStore,store:this._store};this._hasStore=!0,this._store=e;let i=!0;try{let s=t(...r);return s&&typeof s.then=="function"?(i=!1,Promise.resolve(s).finally(()=>{this._hasStore=n.hasStore,this._store=n.store})):s}finally{i&&(this._hasStore=n.hasStore,this._store=n.store)}}},AsyncResource:class{constructor(e="SecureExecAsyncResource"){this.type=e,this._asyncLocalStorageSnapshot=Fa()}emitBefore(){}emitAfter(){}emitDestroy(){}asyncId(){return 0}triggerAsyncId(){return 0}runInAsyncScope(e,t,...r){return kB(this._asyncLocalStorageSnapshot,e,t,r)}},createHook(){return{enable(){return this},disable(){return this}}},executionAsyncId(){return 0},triggerAsyncId(){return 0}};if(!Promise.prototype.__agentOSAsyncLocalStoragePatched){let e=Promise.prototype.then;Promise.prototype.then=function(t,r){let n=Fa(),i=typeof r=="function"?s=>{if(jB(s))throw s;return r(s)}:r;return e.call(this,Ul(t,n),Ul(i,n))},Object.defineProperty(Promise.prototype,"__agentOSAsyncLocalStoragePatched",{value:!0,configurable:!0})}var N2={create:"kernelTimerCreate",arm:"kernelTimerArm",clear:"kernelTimerClear"};et("_asyncHooksModule",CY);var Sa=typeof queueMicrotask=="function"?queueMicrotask:function(e){Promise.resolve().then(e)};function QY(e){let t=Number(e??0);return!Number.isFinite(t)||t<=0?0:Math.floor(t)}function dQe(e){if(e&&typeof e=="object"&&e._id!==void 0)return e._id;if(typeof e=="number")return e}function M2(e,t){try{return zg(N2.create,e,t)}catch(r){throw r instanceof Error&&r.message.includes("EAGAIN")?new Error("ERR_RESOURCE_BUDGET_EXCEEDED: maximum number of timers exceeded"):r}}function e0(e){zg(N2.arm,e)}var F2=class{constructor(e){y(this,"_id");y(this,"_destroyed");y(this,"_refed");this._id=e,this._destroyed=!1,this._refed=!0}ref(){return this._refed=!0,this}unref(){return this._refed=!1,this}hasRef(){return this._refed}refresh(){return!this._destroyed&&_o.has(this._id)&&e0(this._id),this}[Symbol.toPrimitive](){return this._id}},_o=new Map,jm=[];function k2(){if(typeof wu<"u"&&wu)return 0;let e=0;for(let t of _o.values())t.handle?.hasRef?.()!==!1&&(e+=1);return e}function cB(){if(k2()===0&&jm.length>0){let e=jm;jm=[],e.forEach(t=>t())}}function gQe(){return k2()}function pQe(){return k2()===0?Promise.resolve():new Promise(e=>{jm.push(e),cB()})}var zm=[],Q1=!1;function EQe(){for(Q1=!1;zm.length>0;){let e=zm.shift();if(!e)break;try{e.callback(...e.args)}catch(t){let r=i0(t);!r.handled&&r.rethrow!==null&&(zm.length=0,IV(r.rethrow));return}}}function yQe(){if(Q1)return;Q1=!0;let e=Fa();Sa(()=>kB(e,EQe,globalThis,[]))}function mQe(e,t){let r=typeof t=="number"?t:Number(t?.timerId);if(!Number.isFinite(r))return;let n=_o.get(r);if(n){n.repeat||(n.handle._destroyed=!0,_o.delete(r));try{n.callback(...n.args)}catch(i){let s=i0(i);if(!s.handled&&s.rethrow!==null)throw s.rethrow;return}if(typeof wu<"u"&&wu){cB();return}n.repeat&&_o.has(r)&&e0(r),cB()}}function U2(e,t,...r){let n=Math.max(1,QY(t)),i=M2(n,!1),s=new F2(i),o=Fa();return _o.set(i,{handle:s,callback:Ul(e,o),args:r,repeat:!1}),e0(i),s}function UB(e){let t=dQe(e);if(t===void 0)return;let r=_o.get(t);r&&(r.handle._destroyed=!0,_o.delete(t)),zg(N2.clear,t),cB()}function x2(e,t,...r){let n=Math.max(1,QY(t)),i=M2(n,!0),s=new F2(i),o=Fa();return _o.set(i,{handle:s,callback:Ul(e,o),args:r,repeat:!0}),e0(i),s}function L2(e){UB(e)}et("_timerDispatch",mQe);et("_getPendingTimerCount",gQe);et("_waitForTimerDrain",pQe);function lB(e,...t){let r=M2(0,!1),n=new F2(r),i=Fa();return _o.set(r,{handle:n,callback:Ul(e,i),args:t,repeat:!1}),e0(r),n}function wY(e){UB(e)}var BQe={stdinIsTTY:!1,stdoutIsTTY:!1,stderrIsTTY:!1,cols:80,rows:24},Bo;function qv(e){if(typeof _kernelIsattyRaw>"u")throw new Error("_kernelIsattyRaw is unavailable");return _kernelIsattyRaw.applySync(void 0,[e])===!0}function IQe(e){if(typeof _kernelTtySizeRaw>"u")throw new Error("_kernelTtySizeRaw is unavailable");let t=_kernelTtySizeRaw.applySync(void 0,[e]);if(!t||typeof t.cols!="number"||typeof t.rows!="number")throw new Error("_kernelTtySizeRaw returned an invalid size");return t}function xg(){if(Bo)return Bo;if(typeof __runtimeTtyConfig<"u")return Bo=__runtimeTtyConfig,Bo;try{Bo={stdinIsTTY:qv(0),stdoutIsTTY:qv(1),stderrIsTTY:qv(2),cols:80,rows:24}}catch{return Bo=BQe,Bo}for(let e of[1,0])try{let t=IQe(e);Bo.cols=t.cols,Bo.rows=t.rows;break}catch{}return Bo}function bQe(){return xg().stdoutIsTTY}function CQe(){return xg().stderrIsTTY}function QQe(e,t){if(typeof e=="function")return e;if(typeof t=="function")return t}function km(e,t,r,n){let i=e[r]?e[r].slice():[],s=t[r]?t[r].slice():[];s.length>0&&(t[r]=[]);for(let o of i)o(...n);for(let o of s)o(...n);return i.length+s.length>0}function SY(e){let t={},r={},n=(s,o)=>{if(t[s]){let a=t[s].indexOf(o);a!==-1&&t[s].splice(a,1)}if(r[s]){let a=r[s].indexOf(o);a!==-1&&r[s].splice(a,1)}},i={write(s,o,a){s instanceof Uint8Array||typeof Se.Buffer<"u"&&Se.Buffer.isBuffer(s)?e.write(s):e.write(String(s));let A=QQe(o,a);return A&&Sa(()=>A(null)),!0},end(s,o,a){return typeof s=="function"?(a=s,s=void 0):typeof o=="function"&&(a=o),s!=null&&i.write(s),i.writableEnded=!0,typeof a=="function"&&Sa(()=>a()),Sa(()=>km(t,r,"finish",[])),i},destroyed:!1,destroy(s){return i.destroyed||(i.destroyed=!0,s&&Sa(()=>km(t,r,"error",[s])),Sa(()=>km(t,r,"close",[]))),i},cork(){},uncork(){},setDefaultEncoding(){return i},on(s,o){return t[s]||(t[s]=[]),t[s].push(o),i},once(s,o){return r[s]||(r[s]=[]),r[s].push(o),i},off(s,o){return n(s,o),i},removeListener(s,o){return n(s,o),i},addListener(s,o){return i.on(s,o)},emit(s,...o){return km(t,r,s,o)},writable:!0,get isTTY(){return e.isTTY()},get columns(){return xg().cols},get rows(){return xg().rows}};return i}var P2=SY({write(e){typeof _log<"u"&&_log.applySync(void 0,[e])},isTTY:bQe}),O2=SY({write(e){typeof _error<"u"&&_error.applySync(void 0,[e])},isTTY:CQe});function wQe(e){if(typeof e=="string")return e;if(typeof e=="bigint")return`${e}n`;if(e instanceof Error)return e.stack||e.message||String(e);if(typeof e=="object"&&e!==null)try{return JSON.stringify(e)}catch{}return String(e)}function w1(e){return typeof builtinUtilModule<"u"&&typeof builtinUtilModule?.formatWithOptions=="function"?builtinUtilModule.formatWithOptions({colors:!1},...e):e.map(t=>wQe(t)).join(" ")}function yl(e){return`${w1(e)} -`}var H2=class{constructor(e=P2,t=O2){this._stdout=e,this._stderr=t,this._counts=new Map,this._times=new Map;for(let r of["assert","clear","count","countReset","debug","dir","dirxml","error","group","groupCollapsed","groupEnd","info","log","table","time","timeEnd","timeLog","trace","warn"])this[r]=this[r].bind(this)}log(...e){this._stdout.write(yl(e))}info(...e){this._stdout.write(yl(e))}debug(...e){this._stdout.write(yl(e))}warn(...e){this._stderr.write(yl(e))}error(...e){this._stderr.write(yl(e))}dir(e){this._stdout.write(yl([e]))}dirxml(...e){this.log(...e)}trace(...e){let t=w1(e),r=new Error(t);this._stderr.write(`${r.stack||t} -`)}assert(e,...t){if(!e){let r=t.length>0?w1(t):"Assertion failed";this._stderr.write(`${r} -`)}}clear(){}count(e="default"){let t=(this._counts.get(e)??0)+1;this._counts.set(e,t),this.log(`${e}: ${t}`)}countReset(e="default"){this._counts.delete(e)}group(...e){e.length>0&&this.log(...e)}groupCollapsed(...e){e.length>0&&this.log(...e)}groupEnd(){}table(e){this.log(e)}time(e="default"){this._times.set(e,Date.now())}timeEnd(e="default"){if(!this._times.has(e))return;let t=this._times.get(e);this._times.delete(e),this.log(`${e}: ${Date.now()-t}ms`)}timeLog(e="default",...t){if(!this._times.has(e))return;let r=this._times.get(e);this.log(`${e}: ${Date.now()-r}ms`,...t)}},ht=new H2;globalThis.console=ht;function SQe(){return{run(e,...t){return typeof e=="function"?e(...t):void 0}}}function _Qe(e=P2,t=O2){return new H2(e,t)}var vQe={Console:H2,assert:ht.assert.bind(ht),clear:ht.clear.bind(ht),context:_Qe,count:ht.count.bind(ht),countReset:ht.countReset.bind(ht),createTask:SQe,debug:ht.debug.bind(ht),dir:ht.dir.bind(ht),dirxml:ht.dirxml.bind(ht),error:ht.error.bind(ht),group:ht.group.bind(ht),groupCollapsed:ht.groupCollapsed.bind(ht),groupEnd:ht.groupEnd.bind(ht),info:ht.info.bind(ht),log:ht.log.bind(ht),profile:void 0,profileEnd:void 0,table:ht.table.bind(ht),time:ht.time.bind(ht),timeEnd:ht.timeEnd.bind(ht),timeLog:ht.timeLog.bind(ht),timeStamp:void 0,trace:ht.trace.bind(ht),warn:ht.warn.bind(ht)};function Km(e){return!e||typeof e.formatWithOptions=="function"||(e.formatWithOptions=function(r,n,...i){let s=f=>{if(typeof e.inspect=="function")return e.inspect(f,r);try{return JSON.stringify(f)}catch{return String(f)}},o=f=>typeof f=="string"?f:s(f);if(typeof n!="string")return[n,...i].map(o).join(" ");let a=0,A=n.replace(/%[sdifjoO%]/g,f=>{if(f==="%%")return"%";if(a>=i.length)return f;let l=i[a++];switch(f){case"%s":return String(l);case"%d":return Number(l).toString();case"%i":return Number.parseInt(l,10).toString();case"%f":return Number.parseFloat(l).toString();case"%j":try{return JSON.stringify(l)}catch{return"[Circular]"}case"%o":case"%O":return s(l);default:return f}});return a>=i.length?A:[A,...i.slice(a).map(o)].join(" ")}),e}function S1(e){let t=new Error(`node:worker_threads ${e} is not available in the secure-exec guest runtime`);return t.code="ERR_NOT_IMPLEMENTED",t}var _1=class extends Kt{postMessage(){}start(){}close(){this.emit("close")}unref(){return this}ref(){return this}},RQe=class{constructor(){this.port1=new _1,this.port2=new _1}},DQe=class extends Kt{constructor(){throw super(),S1("Worker")}},TQe={BroadcastChannel:globalThis.BroadcastChannel,MessageChannel:globalThis.MessageChannel??RQe,MessagePort:globalThis.MessagePort??_1,SHARE_ENV:Symbol.for("secure-exec.worker_threads.SHARE_ENV"),Worker:DQe,getEnvironmentData(){},isMainThread:!0,markAsUncloneable(){},markAsUntransferable(){},moveMessagePortToContext(){throw S1("moveMessagePortToContext")},parentPort:null,postMessageToThread(){throw S1("postMessageToThread")},receiveMessageOnPort(){},resourceLimits:{},setEnvironmentData(){},threadId:0,workerData:null};function NQe(e){return e===0?!!Ce.stdin?.isTTY:e===1?!!Ce.stdout?.isTTY:e===2?!!Ce.stderr?.isTTY:!1}function MQe(e){return e===0?Ce.stdin:void 0}function FQe(e){if(e===1)return Ce.stdout;if(e===2)return Ce.stderr}var kQe={ReadStream:class{constructor(t){return MQe(t)}},WriteStream:class{constructor(t){return FQe(t)}},isatty:NQe};async function Gq(e){let t=_Y(e);if(t){let r=[];for await(let n of t)r.push(Buffer.isBuffer(n)?n:Buffer.from(n??[]));return r}if(e&&typeof e[Symbol.asyncIterator]=="function"){let r=[];for await(let n of e)r.push(Buffer.isBuffer(n)?n:Buffer.from(n??[]));return r}if(e&&typeof e.getReader=="function"){let r=e.getReader(),n=[];try{for(;;){let{value:i,done:s}=await r.read();if(s)break;n.push(Buffer.from(i??[]))}}finally{r.releaseLock?.()}return n}throw new TypeError("expected an async iterable or WHATWG ReadableStream")}function UQe(e,t=""){return{size:e.byteLength,type:t,async arrayBuffer(){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)},stream(){return new ReadableStream({start(r){r.enqueue(e),r.close()}})},async text(){return e.toString("utf8")}}}var Xm={async arrayBuffer(e){let t=await Gq(e),r=Buffer.concat(t);return r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength)},async blob(e){return UQe(await Xm.buffer(e))},async buffer(e){return Buffer.concat(await Gq(e))},async json(e){return JSON.parse(await Xm.text(e))},async text(e){return(await Xm.buffer(e)).toString("utf8")}};function _Y(e){return!e||typeof e.on!="function"||typeof e.read!="function"&&typeof e.pipe!="function"&&typeof e.resume!="function"?null:{async*[Symbol.asyncIterator](){let t=[],r=[],n=!1,i=null,s=[],o=typeof e.off=="function"?e.off.bind(e):typeof e.removeListener=="function"?e.removeListener.bind(e):null,a=()=>{for(;r.length>0;){if(i){r.shift()?.(Promise.reject(i));continue}if(t.length>0){r.shift()?.(Promise.resolve({done:!1,value:t.shift()}));continue}if(n){r.shift()?.(Promise.resolve({done:!0,value:void 0}));continue}break}},A=(I,S)=>{e.on(I,S),s.push(()=>o?.(I,S))},f=I=>{t.push(I),a()},l=()=>{n=!0,a()},p=I=>{i=I,n=!0,a()};A("data",f),A("end",l),A("close",l),A("error",p),e.resume?.();try{for(;;){if(i)throw i;if(t.length>0){yield t.shift();continue}if(n)return;let I=await new Promise(S=>{r.push(S)});if(I.done)return;yield I.value}}finally{for(;s.length>0;)s.pop()?.()}}}}var vY={finished(e){return new Promise((t,r)=>{if(!e||typeof e!="object"){r(new TypeError("finished() expects a stream"));return}let n=[],i=(o,a)=>{e?.once?.(o,a),n.push(()=>e?.off?.(o,a))},s=o=>a=>{for(;n.length>0;)n.pop()?.();o(a)};i("finish",s(t)),i("end",s(t)),i("close",s(t)),i("error",s(r))})},async pipeline(e,t){let r=_Y(e)??(e&&typeof e[Symbol.asyncIterator]=="function"?e:e&&typeof e.getReader=="function"?{async*[Symbol.asyncIterator](){let i=e.getReader();try{for(;;){let{value:s,done:o}=await i.read();if(o)break;yield Buffer.from(s??[])}}finally{i.releaseLock?.()}}}:null);if(r==null)throw new TypeError("pipeline source must be async iterable or a WHATWG ReadableStream");if(!t||typeof t.write!="function")throw new TypeError("pipeline destination must provide write()");for await(let i of r)await new Promise((s,o)=>{try{t.write(i,a=>a?o(a):s())}catch(a){o(a)}});let n=vY.finished(t);return typeof t.end=="function"&&await new Promise((i,s)=>{try{t.end(o=>o?s(o):i())}catch(o){s(o)}}),await n,t}};function iu(e){let t=String(e).replace(/^node:/,""),r=new Error(`node:${t} is not available in the secure-exec guest runtime`);return r.code="ERR_ACCESS_DENIED",r}var RY=class{constructor(e=""){this.name=String(e),this._subscribers=new Set}get hasSubscribers(){return this._subscribers.size>0}publish(e){for(let t of Array.from(this._subscribers))t(e,this.name)}subscribe(e){typeof e=="function"&&this._subscribers.add(e)}unsubscribe(e){return this._subscribers.delete(e)}runStores(e,t,r,...n){return typeof t!="function"?t:t.apply(r,n)}},Yq=new Map;function _a(e=""){let t=String(e),r=Yq.get(t);return r||(r=new RY(t),Yq.set(t,r)),r}function xQe(e=""){let t=String(e),r={start:_a(`tracing:${t}:start`),end:_a(`tracing:${t}:end`),asyncStart:_a(`tracing:${t}:asyncStart`),asyncEnd:_a(`tracing:${t}:asyncEnd`),error:_a(`tracing:${t}:error`),subscribe(){},unsubscribe(){return!0},traceSync(n,i,s,...o){return typeof n!="function"?n:n.apply(s,o)},tracePromise(n,i,s,...o){return typeof n!="function"?Promise.resolve(n):Promise.resolve(n.apply(s,o))},traceCallback(n,i,s,o,...a){return typeof n!="function"?n:n.apply(o,a)}};return Object.defineProperty(r,"hasSubscribers",{get(){return r.start.hasSubscribers||r.end.hasSubscribers||r.asyncStart.hasSubscribers||r.asyncEnd.hasSubscribers||r.error.hasSubscribers},enumerable:!1,configurable:!0}),r}var LQe={Channel:RY,channel:_a,hasSubscribers(e=""){return _a(e).hasSubscribers},subscribe(e="",t){return _a(e).subscribe(t)},tracingChannel:xQe,unsubscribe(e="",t){return _a(e).unsubscribe(t)}};function ml(e,t=2){return String(Math.trunc(e)).padStart(t,"0")}function PQe(e){let t=e instanceof Date?e:new Date(e??Date.now());if(Number.isNaN(t.getTime()))throw new RangeError("Invalid time value");return t}function OQe(e,t={}){let r=PQe(e),n=t&&typeof t=="object"?t:{},i=ml(r.getUTCFullYear(),4),s=ml(r.getUTCMonth()+1),o=ml(r.getUTCDate()),a=ml(r.getUTCHours()),A=ml(r.getUTCMinutes()),f=ml(r.getUTCSeconds()),l=`${i}-${s}-${o}`,p=`${a}:${A}:${f}`,I=n.dateStyle||n.year||n.month||n.day||!n.timeStyle&&!n.hour&&!n.minute&&!n.second,S=n.timeStyle||n.hour||n.minute||n.second;return I&&S?`${l}, ${p}`:S?p:l}var HQe=class{constructor(e="en-US",t={}){this.locales=e,this.options=t&&typeof t=="object"?{...t}:{},this.format=this.format.bind(this)}format(e=Date.now()){return OQe(e,this.options)}formatToParts(e=Date.now()){return[{type:"literal",value:this.format(e)}]}formatRange(e,t){return`${this.format(e)} \u2013 ${this.format(t)}`}formatRangeToParts(e,t){return[{type:"literal",value:this.formatRange(e,t),source:"shared"}]}resolvedOptions(){return{locale:Array.isArray(this.locales)?this.locales.find(t=>typeof t=="string")||"en-US":typeof this.locales=="string"?this.locales:"en-US",calendar:"gregory",numberingSystem:"latn",timeZone:"UTC",...this.options}}static supportedLocalesOf(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):typeof e=="string"?[e]:[]}};function Um(e,t){let r=Number(e);return Number.isFinite(r)?Math.min(20,Math.max(0,Math.trunc(r))):t}function qQe(e){let[t,r]=e.split("."),n=t.startsWith("-")?"-":"",s=(n?t.slice(1):t).replace(/\B(?=(\d{3})+(?!\d))/g,",");return r===void 0?`${n}${s}`:`${n}${s}.${r}`}var GQe=class{constructor(e="en-US",t={}){this.locales=e,this.options=t&&typeof t=="object"?{...t}:{},this.format=this.format.bind(this)}format(e){let t=Number(e);if(Number.isNaN(t))return"NaN";if(t===1/0)return"\u221E";if(t===-1/0)return"-\u221E";let r=Um(this.options.minimumFractionDigits,0),n=Math.max(r,Um(this.options.maximumFractionDigits,Math.max(r,3))),i=t.toFixed(n);if(n>r){i=i.replace(/(\.\d*?)0+$/,"$1").replace(/\.$/,"");let s=i.includes(".")?i.length-i.indexOf(".")-1:0;stypeof t=="string")||"en-US":typeof this.locales=="string"?this.locales:"en-US",numberingSystem:"latn",style:"decimal",minimumFractionDigits:Um(this.options.minimumFractionDigits,0),maximumFractionDigits:Um(this.options.maximumFractionDigits,3),useGrouping:this.options.useGrouping!==!1,...this.options}}static supportedLocalesOf(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):typeof e=="string"?[e]:[]}};function YQe(e){let t=e.Intl&&typeof e.Intl=="object"?e.Intl:{};t.DateTimeFormat=HQe,t.NumberFormat=GQe,e.Intl=t,Date.prototype.toLocaleString=function(r,n){return new e.Intl.DateTimeFormat(r,n).format(this)},Date.prototype.toLocaleDateString=function(r,n){return new e.Intl.DateTimeFormat(r,{...n||{},hour:void 0,minute:void 0,second:void 0}).format(this)},Date.prototype.toLocaleTimeString=function(r,n){return new e.Intl.DateTimeFormat(r,{hour:"2-digit",minute:"2-digit",second:"2-digit",...n||{}}).format(this)},Number.prototype.toLocaleString=function(r,n){return new e.Intl.NumberFormat(r,n).format(this.valueOf())}}function Gv(e,t,r){let n=new RangeError(`The value of "${e}" is out of range. It must be ${t}. Received ${String(r)}`);return n.code="ERR_OUT_OF_RANGE",n}function DY(e){return{name:String(e?.name??""),entryType:String(e?.entryType??""),startTime:Number(e?.startTime??0),duration:Number(e?.duration??0)}}function TY(e){return{getEntries(){return e.slice()},getEntriesByName(t,r=void 0){let n=String(t??""),i=e.filter(s=>s.name===n);return typeof r=="string"?i.filter(s=>s.entryType===r):i},getEntriesByType(t){let r=String(t??"");return e.filter(n=>n.entryType===r)}}}function WQe(){let e=[];return{percentile(t){let r=Number(t);if(!Number.isFinite(r)||r<=0||r>100)throw Gv("percentile","> 0 && <= 100",t);if(e.length===0)return 0;let n=e.slice().sort((s,o)=>s-o),i=Math.min(n.length-1,Math.max(0,Math.ceil(r/100*n.length)-1));return n[i]},record(t){let r=Number(t);if(!Number.isInteger(r))throw Gv("val","an integer",t);if(r<1||r>Number.MAX_SAFE_INTEGER)throw Gv("val",`>= 1 && <= ${Number.MAX_SAFE_INTEGER}`,t);e.push(r)}}}var xm=(()=>{let e=new Map,t=[],r=new Set,n=typeof performance<"u"&&performance&&typeof performance.now=="function"?performance:{now(){return Hl()},timeOrigin:Date.now()-Hl()};typeof n.mark!="function"&&(n.mark=function(A){let f={name:String(A??""),entryType:"mark",startTime:n.now(),duration:0},l=e.get(f.name)??[];return l.push(f),e.set(f.name,l),f}),typeof n.measure!="function"&&(n.measure=function(A,f,l){let p=String(A??""),I=0,S=n.now();if(typeof f=="string"){let N=e.get(f);if(N?.length&&(I=N[N.length-1].startTime),typeof l=="string"){let O=e.get(l);O?.length&&(S=O[O.length-1].startTime)}}else if(f&&typeof f=="object"){if(typeof f.start=="number")I=f.start;else if(typeof f.startMark=="string"){let N=e.get(f.startMark);N?.length&&(I=N[N.length-1].startTime)}if(typeof f.end=="number")S=f.end;else if(typeof f.endMark=="string"){let N=e.get(f.endMark);N?.length&&(S=N[N.length-1].startTime)}}let _={name:p,entryType:"measure",startTime:I,duration:Math.max(0,S-I)};return t.push(_),_}),typeof n.getEntriesByName!="function"&&(n.getEntriesByName=function(A,f=void 0){let l=String(A??""),I=[...e.get(l)??[],...t.filter(S=>S.name===l)];return typeof f=="string"?I.filter(S=>S.entryType===f):I}),typeof n.getEntries!="function"&&(n.getEntries=function(){return[...e.values()].flatMap(A=>[...A]).concat(t)}),typeof n.getEntriesByType!="function"&&(n.getEntriesByType=function(A){let f=String(A??"");return n.getEntries().filter(l=>l.entryType===f)}),typeof n.clearMarks!="function"&&(n.clearMarks=function(A=void 0){if(typeof A>"u"){e.clear();return}e.delete(String(A))}),typeof n.clearMeasures!="function"&&(n.clearMeasures=function(A=void 0){if(typeof A>"u"){t.length=0;return}let f=String(A);for(let l=t.length-1;l>=0;l-=1)t[l]?.name===f&&t.splice(l,1)});let i=A=>{A._deliveryQueued||(A._deliveryQueued=!0,Sa(()=>{if(A._deliveryQueued=!1,!A._connected)return;let f=A.takeRecords();A._callback(TY(f),A)}))},s=A=>{let f=DY(A);for(let l of r)l._entryTypes.has(f.entryType)&&(l._records.push(f),i(l))},o=n.mark.bind(n);n.mark=function(...A){let f=o(...A);return s(f),f};let a=n.measure.bind(n);return n.measure=function(...A){let f=a(...A);return s(f),f},n.__agentOSObservers=r,n})(),VQe={PerformanceObserver:class{constructor(e){if(typeof e!="function")throw new TypeError("PerformanceObserver callback must be a function");this._callback=e,this._connected=!1,this._deliveryQueued=!1,this._entryTypes=new Set,this._records=[]}static get supportedEntryTypes(){return["mark","measure"]}observe(e={}){let t=Array.isArray(e?.entryTypes)?e.entryTypes.map(r=>String(r)):typeof e?.type=="string"?[String(e.type)]:[];if(t.length===0)throw new TypeError("PerformanceObserver.observe() requires an entryTypes array or type string");if(this.disconnect(),this._entryTypes=new Set(t),this._connected=!0,xm.__agentOSObservers.add(this),e?.buffered){for(let r of this._entryTypes)for(let n of xm.getEntriesByType(r))this._records.push(DY(n));this._records.length>0&&(this._deliveryQueued=!0,Sa(()=>{if(this._deliveryQueued=!1,!this._connected)return;let r=this.takeRecords();this._callback(TY(r),this)}))}}disconnect(){this._connected=!1,xm.__agentOSObservers.delete(this)}takeRecords(){let e=this._records.slice();return this._records.length=0,e}},constants:{},createHistogram(){return WQe()},performance:xm};function NY(e){let t=JSON.stringify(e??null);return Buffer.from(t,"utf8")}function MY(e){let t=Buffer.isBuffer(e)?e:Buffer.from(e??[]);return JSON.parse(t.toString("utf8"))}var Wq=class{constructor(){this._value=null}writeHeader(){}writeValue(e){this._value=e}releaseBuffer(){return NY(this._value)}transferArrayBuffer(){}},Vq=class{constructor(e){this._buffer=e}readHeader(){}readValue(){return MY(this._buffer)}transferArrayBuffer(){}};function JQe(){let e=Number(globalThis.__agentOSV8HeapLimitBytes);return Number.isFinite(e)&&e>0?e:128*1024*1024}function jQe(){let e=JQe();return{total_heap_size:Math.max(64*1024*1024,Math.floor(e/2)),total_heap_size_executable:1024*1024,total_physical_size:Math.max(64*1024*1024,Math.floor(e/2)),total_available_size:Math.max(0,e-64*1024*1024),used_heap_size:Math.max(0,Math.min(e,Math.floor(e*.4))),heap_size_limit:e,malloced_memory:8192,peak_malloced_memory:16384,does_zap_garbage:0,number_of_native_contexts:1,number_of_detached_contexts:0,total_global_handles_size:16384,used_global_handles_size:8192,external_memory:0}}function zQe(){return[]}function KQe(){return{code_and_metadata_size:0,bytecode_and_metadata_size:0,external_script_source_size:0,cpu_profiler_metadata_size:0}}function XQe(){return{committed_size_bytes:0,resident_size_bytes:0,used_size_bytes:0,space_statistics:[]}}function ZQe(){return Readable.fromWeb(new ReadableStream({start(e){e.enqueue(Buffer.from("{}")),e.close()}}))}var $Qe={cachedDataVersionTag(){return 0},DefaultDeserializer:Vq,DefaultSerializer:Wq,Deserializer:Vq,GCProfiler:class{start(){}stop(){return[]}},Serializer:Wq,deserialize:MY,getCppHeapStatistics:XQe,getHeapCodeStatistics:KQe,getHeapSnapshot:ZQe,getHeapSpaceStatistics:zQe,getHeapStatistics:jQe,isStringOneByteRepresentation(e){return typeof e=="string"&&!/[^\x00-\xff]/.test(e)},promiseHooks:{},queryObjects(){return[]},serialize:NY,setFlagsFromString(){},setHeapSnapshotNearHeapLimit(){return[]},startCpuProfile(){return{stop(){return{}}}},startupSnapshot:{},stopCoverage(){return[]},takeCoverage(){return[]},writeHeapSnapshot(){return""}},v1=typeof Symbol=="function"?Symbol.for("secure-exec.vm.context"):"__secure_exec_vm_context__",hB=typeof Symbol=="function"?Symbol.for("secure-exec.vm.context.id"):"__secure_exec_vm_context_id__";function Jq(e){let t=new Error(`node:vm ${e} is not implemented in the secure-exec guest runtime`);return t.code="ERR_NOT_IMPLEMENTED",t}function q2(e){return e!==null&&(typeof e=="object"||typeof e=="function")}function Lg(e=void 0){if(typeof e=="string")return{filename:e};if(!e||typeof e!="object")return{};let t={};return typeof e.filename=="string"&&(t.filename=e.filename),Number.isInteger(e.lineOffset)&&(t.lineOffset=e.lineOffset),Number.isInteger(e.columnOffset)&&(t.columnOffset=e.columnOffset),Number.isInteger(e.timeout)&&e.timeout>0&&(t.timeout=e.timeout),e.cachedData!==void 0&&(t.cachedData=e.cachedData),e.produceCachedData===!0&&(t.produceCachedData=!0),t}function Yv(e,t){let r=Lg(e),n=Lg(t);return{...r,...n}}function FY(e={}){if(!q2(e))throw new TypeError('The "object" argument must be of type object.');if(e[v1]===!0&&Number.isInteger(e[hB]))return e;let t=_vmCreateContext(e);return Object.defineProperty(e,v1,{value:!0,configurable:!0,enumerable:!1,writable:!1}),Object.defineProperty(e,hB,{value:t,configurable:!1,enumerable:!1,writable:!1}),e}function kY(e){return q2(e)&&e[v1]===!0&&Number.isInteger(e[hB])}function ewe(e){if(!kY(e))throw new TypeError('The "contextifiedObject" argument must be a vm context.');return e}function UY(e,t=void 0){return _vmRunInThisContext(String(e),Lg(t))}function G2(e,t,r=void 0){let n=ewe(t);return _vmRunInContext(n[hB],String(e),Lg(r),n)}function xY(e,t={},r=void 0){let n=q2(t),i=n?t:{},s=n?r:t;return G2(e,FY(i),s)}var twe=class{constructor(e,t=void 0){this.code=String(e),this.options=Lg(t),this.filename=this.options.filename??"evalmachine.",this.lineOffset=this.options.lineOffset??0,this.columnOffset=this.options.columnOffset??0,this.cachedData=this.options.cachedData,this.cachedDataProduced=!1,this.cachedDataRejected=!1}createCachedData(){return typeof Buffer=="function"?Buffer.alloc(0):new Uint8Array(0)}runInThisContext(e=void 0){return UY(this.code,Yv(this.options,e))}runInContext(e,t=void 0){return G2(this.code,e,Yv(this.options,t))}runInNewContext(e={},t=void 0){return xY(this.code,e,Yv(this.options,t))}},rwe={Script:twe,compileFunction(){throw Jq("compileFunction")},createContext:FY,isContext:kY,measureMemory(){throw Jq("measureMemory")},runInContext:G2,runInNewContext:xY,runInThisContext:UY},LY=m1.default?.default??m1.default,jq=B1.default?.default??B1.default,PY=Cg.default?.request??Cg.default?.default?.request??Cg.default?.default??Cg.default,zq=Vm.default?.fetch??Vm.default?.default??Vm.default,nwe=Eu.default?.Headers??Eu.default?.default??Eu.default,iwe=yu.default?.Request??yu.default?.default??yu.default,swe=mu.default?.Response??mu.default?.default??mu.default,Kq=B2.default?.setGlobalDispatcher,Xq=B2.default?.getGlobalDispatcher,Wv=null;function owe(){return new LY({connections:6,connect(e,t){try{let r=e?.protocol==="https:"||e?.protocol==="https"?"https:":"http:",n=e?.hostname||e?.host||e?.servername||"localhost",i=e?.port;if(e?.origin){let p=new URL(String(e.origin));r=p.protocol==="https:"?"https:":"http:",n=p.hostname||n,i=p.port||i}typeof n=="string"&&n.startsWith("[")&&n.endsWith("]")&&(n=n.slice(1,-1));let s=LB({protocol:r,hostname:n,host:n,port:i?Number(i):r==="https:"?443:80,servername:e?.servername||n,rejectUnauthorized:e?.rejectUnauthorized}),o=Z2(r),a=!1,A=()=>{s.off?.(o,f),s.removeListener?.(o,f),s.off?.("error",l),s.removeListener?.("error",l)},f=()=>{a||(a=!0,A(),t(null,s))},l=p=>{a||(a=!0,A(),t(p instanceof Error?p:new Error(String(p))))};return s.once(o,f),s.once("error",l),s}catch(r){return t(r instanceof Error?r:new Error(String(r))),null}}})}function R1(){return Wv||(Wv=owe()),Wv}typeof Kq=="function"&&typeof LY=="function"&&(typeof Xq=="function"?Xq():null)==null&&Kq(R1());var Y2="__secureExecNetSocket:",awe="net-server:",W2=new Map,dB=new Map;function Awe(e){return globalThis[`${Y2}${e}`]}function Zq(e,t){globalThis[`${Y2}${e}`]=t,W2.set(e,t)}function fwe(e){delete globalThis[`${Y2}${e}`],W2.delete(e)}function uwe(e){let t=e?._address?.port;typeof t=="number"&&dB.set(t,e)}function cwe(e){let t=e?._address?.port;typeof t=="number"&&dB.get(t)===e&&dB.delete(t)}function lwe(e){if(re("readWakeAttempts"),!e||e.destroyed||e._socketId===0||e._loopbackServer||e._loopbackHttpTarget){re("readWakeInvalidTargets");return}if(e._bridgeReadLoopRunning&&re("readWakeAlreadyRunning"),!e._bridgeReadPollTimer){re("readWakeNoTimer"),re(e._bridgeReadPumpStarted?"readWakeNoTimerAfterFirstPump":"readWakeNoTimerBeforeFirstPump"),e._connected&&re("readWakeNoTimerConnected"),e.connecting&&re("readWakeNoTimerConnecting"),re(e._refed?"readWakeNoTimerRefed":"readWakeNoTimerUnrefed");let t=(e._listeners?.data?.length??0)>0,r=(e._listeners?.readable?.length??0)>0;if(t&&re("readWakeNoTimerHasDataListener"),r&&re("readWakeNoTimerHasReadableListener"),e._bridgeWriteFlushScheduled&&(re("readWakeNoTimerPendingWriteFlush"),re("readWakeNoTimerPendingWriteBytes",e._pendingBridgeWriteBytes)),!e._bridgeReadPumpStarted&&e._firstReadNoTimerWakeAtUs===0&&ir()&&(e._firstReadNoTimerWakeAtUs=At()),ir()&&!e._bridgeReadPumpStarted&&e._connected&&e._refed&&(t||r))if(re("readFirstPumpScheduleCandidates"),e._bridgeReadFirstPumpBenchmarkScheduled)re("readFirstPumpScheduleAlreadyScheduled");else{re("readFirstPumpScheduleQueued"),e._bridgeReadFirstPumpBenchmarkScheduled=!0;let n=At();queueMicrotask(()=>{re("readFirstPumpScheduleRuns");let i=At(),s=Math.max(0,i-n);if(re("readFirstPumpScheduleQueuedToRunUs",s),Qr("readFirstPumpScheduleQueuedToRunMaxUs",s),e._bridgeReadFirstPumpBenchmarkScheduled=!1,e.destroyed){re("readFirstPumpScheduleSkipDestroyed");return}if(e._tlsUpgrading){re("readFirstPumpScheduleSkipTlsUpgrading");return}if(e._bridgeReadPumpStarted){re("readFirstPumpScheduleSkipPumpStarted");return}if(e._bridgeReadLoopRunning){re("readFirstPumpScheduleSkipLoopRunning");return}if(e._socketId===0){re("readFirstPumpScheduleSkipSocketClosed");return}re("readFirstPumpSchedulePumpCalls"),e._nextReadPumpOrigin="eventWake",e._readFirstPumpScheduleActive=!0,e._readFirstPumpScheduleQueuedAtUs=n,e._pumpBridgeReads()})}return}clearTimeout(e._bridgeReadPollTimer),e._bridgeReadPollTimer=null,re("readEventWakeups"),ir()&&(e._readWakeQueuedAtUs=At()),queueMicrotask(()=>{e.destroyed||(e._nextReadPumpOrigin="eventWake",e._pumpBridgeReads())})}function hwe(e){if(re("peerWakeScans"),!e||e._socketId===0||e.remotePort===void 0||e.localPort===void 0){re("peerWakeInvalidTargets");return}for(let t of W2.values())if(!(t===e||t.destroyed)&&t.localPort===e.remotePort&&t.remotePort===e.localPort){re("peerWakeFound"),lwe(t);return}re("peerWakeMiss")}function dwe(e){if(re("acceptWakeAttempts"),!e||!e.listening||e._serverId===0||!e._acceptPollTimer){if(!e||!e.listening||e._serverId===0)re("acceptWakeInvalidTargets");else{re("acceptWakeNoTimer"),re(e._acceptPumpStarted?"acceptWakeNoTimerAfterFirstPump":"acceptWakeNoTimerBeforeFirstPump"),e._acceptLoopRunning&&re("acceptWakeNoTimerLoopRunning"),e._acceptLoopActive&&re("acceptWakeNoTimerLoopActive"),re(e._refed?"acceptWakeNoTimerRefed":"acceptWakeNoTimerUnrefed");let t=e._connections?.size??0;re("acceptWakeNoTimerConnections",t),Qr("acceptWakeNoTimerConnectionsMax",t),!e._acceptPumpStarted&&e._firstAcceptNoTimerWakeAtUs===0&&ir()&&(e._firstAcceptNoTimerWakeAtUs=At())}return}e._acceptLoopRunning&&re("acceptWakeAlreadyRunning"),clearTimeout(e._acceptPollTimer),e._acceptPollTimer=null,re("acceptEventWakeups"),ir()&&(e._acceptWakeQueuedAtUs=At()),queueMicrotask(()=>{e.listening&&e._serverId!==0&&(e._nextAcceptPumpOrigin="eventWake",e._pumpAccepts())})}function gwe(e){re("acceptWakeSocketScans");let t=e?.remotePort;if(typeof t!="number"){re("acceptWakeSocketInvalidTargets");return}let r=dB.get(t);re(r?"acceptWakeSocketFound":"acceptWakeSocketMiss"),dwe(r)}function $q(e){return e===void 0?!0:!!e}function gB(e){return typeof e!="number"||!Number.isFinite(e)?0:Math.max(0,Math.floor(e/1e3))}function pwe(e,t){return lr(`The "${e}" argument must be of type number. Received ${Yn(t)}`,"ERR_INVALID_ARG_TYPE")}function xl(e,t){return lr(`The "${e}" argument must be of type function. Received ${Yn(t)}`,"ERR_INVALID_ARG_TYPE")}function Ewe(e){let t=new RangeError(`The value of "timeout" is out of range. It must be a non-negative finite number. Received ${String(e)}`);return t.code="ERR_OUT_OF_RANGE",t}function wl(e){return lr(e,"ERR_INVALID_ARG_VALUE")}function D1(e){let t=new RangeError(`options.port should be >= 0 and < 65536. Received ${Yn(e)}.`);return t.code="ERR_SOCKET_BAD_PORT",t}function T1(e){return Number.isInteger(e)&&e>=0&&e<65536}function OY(e){return/^[0-9]+$/.test(e)}function eG(e){if(e==null)return 0;if(typeof e=="string"&&e.length>0){let t=Number(e);if(T1(t))return t;throw D1(e)}if(typeof e=="number"){if(T1(e))return e;throw D1(e)}throw wl(`The argument 'options' is invalid. Received ${String(e)}`)}function HY(e,t,r,n){let i={port:0,host:"127.0.0.1",backlog:511,readableAll:!1,writableAll:!1};if(typeof e=="function")return{...i,callback:e};if(e!==null&&typeof e=="object"){let s=e,o=Object.prototype.hasOwnProperty.call(s,"port"),a=Object.prototype.hasOwnProperty.call(s,"path");if(!o&&!a)throw wl(`The argument 'options' must have the property "port" or "path". Received ${String(e)}`);if(o&&a)throw wl(`The argument 'options' is invalid. Received ${String(e)}`);if(o&&s.port!==void 0&&s.port!==null&&typeof s.port!="number"&&typeof s.port!="string")throw wl(`The argument 'options' is invalid. Received ${String(e)}`);if(a){if(typeof s.path!="string"||s.path.length===0)throw wl(`The argument 'options' is invalid. Received ${String(e)}`);return{path:s.path,backlog:typeof s.backlog=="number"&&Number.isFinite(s.backlog)?s.backlog:i.backlog,readableAll:s.readableAll===!0,writableAll:s.writableAll===!0,callback:typeof t=="function"?t:typeof r=="function"?r:n}}return{port:eG(s.port),host:typeof s.host=="string"&&s.host.length>0?s.host:i.host,backlog:typeof s.backlog=="number"&&Number.isFinite(s.backlog)?s.backlog:i.backlog,readableAll:!1,writableAll:!1,callback:typeof t=="function"?t:typeof r=="function"?r:n}}if(e!=null&&typeof e!="number"&&typeof e!="string")throw wl(`The argument 'options' is invalid. Received ${String(e)}`);return typeof e=="string"&&e.length>0&&!OY(e)?{path:e,backlog:i.backlog,readableAll:!1,writableAll:!1,callback:typeof t=="function"?t:typeof r=="function"?r:n}:{port:eG(e),host:typeof t=="string"?t:i.host,backlog:typeof r=="number"?r:i.backlog,readableAll:!1,writableAll:!1,callback:typeof t=="function"?t:typeof r=="function"?r:n}}function ywe(e,t,r){if(e!==null&&typeof e=="object"){let n=typeof e.port=="string"?Number(e.port):e.port;return{host:typeof e.host=="string"&&e.host.length>0?e.host:void 0,port:n,path:typeof e.path=="string"&&e.path.length>0?e.path:void 0,keepAlive:e.keepAlive,keepAliveInitialDelay:e.keepAliveInitialDelay,callback:typeof t=="function"?t:r}}return typeof e=="string"&&!OY(e)?{path:e,callback:typeof t=="function"?t:r}:{port:typeof e=="number"?e:Number(e),host:typeof t=="string"?t:"127.0.0.1",callback:typeof t=="function"?t:r}}function mwe(e){if(!/^[0-9]{1,3}$/.test(e)||e.length>1&&e.startsWith("0"))return!1;let t=Number(e);return Number.isInteger(t)&&t>=0&&t<=255}function t0(e){let t=e.split(".");return t.length===4&&t.every(r=>mwe(r))}function Bwe(e){return e.length>0&&/^[0-9A-Za-z_.-]+$/.test(e)}function Vv(e){if(e.length===0)return 0;let t=e.split(":"),r=0;for(let n of t){if(n.length===0)return null;if(n.includes(".")){if(n!==t[t.length-1]||!t0(n))return null;r+=2;continue}if(!/^[0-9A-Fa-f]{1,4}$/.test(n))return null;r+=1}return r}function xB(e){if(e.length===0)return!1;let t=e,r=t.indexOf("%");if(r!==-1){if(t.indexOf("%",r+1)!==-1)return!1;let s=t.slice(r+1);if(!Bwe(s))return!1;t=t.slice(0,r)}let n=t.indexOf("::");if(n!==-1){if(t.indexOf("::",n+2)!==-1)return!1;let[s,o]=t.split("::");if(s.includes("."))return!1;let a=Vv(s),A=Vv(o);return a===null||A===null?!1:a+A<8}return Vv(t)===8}function Iwe(e){return e==null?"":String(e)}function Tl(e){let t=Iwe(e);return t0(t)?4:xB(t)?6:0}function Sl(e,t){if(t==="ipv4"||t===4)return"ipv4";if(t==="ipv6"||t===6)return"ipv6";let r=Tl(e);if(r===4)return"ipv4";if(r===6)return"ipv6";throw new TypeError(`Invalid IP address: ${e}`)}function qY(e){return e.split(".").reduce((t,r)=>(t<<8n)+BigInt(Number(r)),0n)}function bwe(e){let t=String(e),r=t.indexOf("%");if(r!==-1&&(t=t.slice(0,r)),t.includes(".")){let l=t.lastIndexOf(":"),p=t.slice(l+1),I=qY(p),S=Number(I>>16n&65535n).toString(16),_=Number(I&65535n).toString(16);t=`${t.slice(0,l)}:${S}:${_}`}let n=t.includes("::"),[i,s]=n?t.split("::"):[t,""],o=i.length>0?i.split(":"):[],a=s.length>0?s.split(":"):[],A=n?Math.max(0,8-(o.length+a.length)):0,f=[...o,...new Array(A).fill("0"),...a];if(f.length!==8)throw new TypeError(`Invalid IPv6 address: ${e}`);return f.map(l=>l.length===0?"0":l)}function Cwe(e){return bwe(e).reduce((t,r)=>(t<<16n)+BigInt(parseInt(r,16)),0n)}function Eg(e,t){return t==="ipv4"?qY(e):Cwe(e)}function Qwe(e){return e.type==="address"?`Address: ${e.family==="ipv4"?"IPv4":"IPv6"} ${e.address}`:e.type==="range"?`Range: ${e.family==="ipv4"?"IPv4":"IPv6"} ${e.start}-${e.end}`:`Subnet: ${e.family==="ipv4"?"IPv4":"IPv6"} ${e.network}/${e.prefix}`}var wwe=class{constructor(){y(this,"_rules",[])}addAddress(e,t){let r=Sl(e,t);return this._rules.push({type:"address",family:r,address:String(e)}),this}addRange(e,t,r){let n=Sl(e,r);if(Sl(t,n)!==n)throw new TypeError("BlockList range family mismatch");return this._rules.push({type:"range",family:n,start:String(e),end:String(t)}),this}addSubnet(e,t,r){let n=Sl(e,r),i=Number(t),s=n==="ipv4"?32:128;if(!Number.isInteger(i)||i<0||i>s)throw new RangeError(`Invalid subnet prefix: ${t}`);return this._rules.push({type:"subnet",family:n,network:String(e),prefix:i}),this}check(e,t){let r=Sl(e,t),n=Eg(String(e),r);for(let i of this._rules)if(i.family===r){if(i.type==="address"&&n===Eg(i.address,r))return!0;if(i.type==="range"){let s=Eg(i.start,r),o=Eg(i.end,r);if(n>=s&&n<=o)return!0}if(i.type==="subnet"){let s=r==="ipv4"?32n:128n,o=BigInt(i.prefix),a=s-o,A=o===0n?0n:(1n<({...e}))}fromJSON(e){if(!Array.isArray(e))throw new TypeError("BlockList JSON must be an array");return this._rules=e.map(t=>({...t})),this}get rules(){return this._rules.map(e=>Qwe(e))}},tG=!0,rG=250,Swe=class Qg{constructor(t={}){let r=String(t.address??""),n=Sl(r,t.family),i=Number(t.port??0),s=Number(t.flowlabel??0);if(!Number.isInteger(i)||i<0||i>65535)throw new RangeError(`Invalid port: ${t.port}`);if(!Number.isInteger(s)||s<0)throw new RangeError(`Invalid flowlabel: ${t.flowlabel}`);this.address=r,this.port=i,this.family=n,this.flowlabel=s}toJSON(){return{address:this.address,port:this.port,family:this.family,flowlabel:this.flowlabel}}static isSocketAddress(t){return t instanceof Qg}static parse(t){let r=String(t);if(r.startsWith("[")){let i=r.indexOf("]");if(i===-1)return;let s=r.slice(1,i),o=r[i+1]===":"?Number(r.slice(i+2)):0;return new Qg({address:s,family:"ipv6",port:o})}let n=r.lastIndexOf(":");if(n!==-1&&r.indexOf(":")===n){let i=r.slice(0,n),s=Number(r.slice(n+1));if(Tl(i)!==0&&Number.isInteger(s))return new Qg({address:i,port:s})}if(Tl(r)!==0)return new Qg({address:r})}};function GY(e){if(typeof e!="number")throw pwe("timeout",e);if(!Number.isFinite(e)||e<0)throw Ewe(e);return e}function YY(e){if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}function _we(e){if(!e)throw new Error("net.connect bridge returned an empty socket handle");if(typeof e=="string")return{socketId:e};if(typeof e=="object"&&(typeof e.socketId=="string"||typeof e.socketId=="number")||typeof e=="object"&&e.loopbackHttpTarget)return e;throw new Error("net.connect bridge returned an invalid socket handle")}function Zm(e){if(e!=null){if(Array.isArray(e)){let t=e.map(r=>Zm(r)).flatMap(r=>Array.isArray(r)?r:r?[r]:[]);return t.length>0?t:void 0}if(typeof e=="string")return{kind:"string",data:e};if(Buffer.isBuffer(e)||e instanceof Uint8Array)return{kind:"buffer",data:Buffer.from(e).toString("base64")}}}function N1(e){return!!e&&typeof e=="object"&&"__secureExecTlsContext"in e}function Gl(e,t){let n={...(N1(e?.secureContext)?e.secureContext.__secureExecTlsContext:void 0)??{},...t},i=Zm(e?.key),s=Zm(e?.cert),o=Zm(e?.ca);if(i!==void 0&&(n.key=i),s!==void 0&&(n.cert=s),o!==void 0&&(n.ca=o),typeof e?.passphrase=="string"&&(n.passphrase=e.passphrase),typeof e?.ciphers=="string"&&(n.ciphers=e.ciphers),(Buffer.isBuffer(e?.session)||e?.session instanceof Uint8Array)&&(n.session=Buffer.from(e.session).toString("base64")),Array.isArray(e?.ALPNProtocols)){let a=e.ALPNProtocols.filter(A=>typeof A=="string");a.length>0&&(n.ALPNProtocols=a)}return typeof e?.minVersion=="string"&&(n.minVersion=e.minVersion),typeof e?.maxVersion=="string"&&(n.maxVersion=e.maxVersion),typeof e?.servername=="string"&&(n.servername=e.servername),typeof e?.rejectUnauthorized=="boolean"&&(n.rejectUnauthorized=e.rejectUnauthorized),typeof e?.requestCert=="boolean"&&(n.requestCert=e.requestCert),n}function vwe(e){if(!e)return null;try{return JSON.parse(e)}catch{return null}}function Rwe(e){if(!e)return null;try{return JSON.parse(e)}catch{return null}}function Dwe(e){if(!e)return new Error("socket error");try{let t=JSON.parse(e),r=new Error(t.message);return t.name&&(r.name=t.name),t.code&&(r.code=t.code),t.stack&&(r.stack=t.stack),r}catch{return new Error(e)}}function M1(e,t=new Map){if(e===null||typeof e=="boolean"||typeof e=="number"||typeof e=="string")return e;if(e.type==="undefined")return;if(e.type==="buffer")return Buffer.from(e.data,"base64");if(e.type==="array")return e.value.map(n=>M1(n,t));if(e.type==="ref")return t.get(e.id);let r={};t.set(e.id,r);for(let[n,i]of Object.entries(e.value))r[n]=M1(i,t);return r}function Ia(e,t,r){if(typeof _netSocketTlsQueryRaw>"u")return;let n=_netSocketTlsQueryRaw.applySync(void 0,r===void 0?[e,t]:[e,t,r]);return M1(JSON.parse(n))}function F1(e,t="secureConnect"){if(e._tlsUpgrading=!1,e.encrypted=!0,e.authorized=e.authorizationError==null,typeof e._socketId=="string"&&e._socketId.length>0){let r=Ia(e._socketId,"getProtocol");(typeof r=="string"||r===null)&&(e._tlsProtocol=r);let n=Ia(e._socketId,"getCipher");n!==void 0&&(e._tlsCipher=n);let i=Ia(e._socketId,"isSessionReused");typeof i=="boolean"&&(e._tlsSessionReused=i)}e._touchTimeout(),e._emitNet(t),t!=="secure"&&e._emitNet("secure"),!e.destroyed&&!e._bridgeReadLoopRunning&&(e._nextReadPumpOrigin="tls",e._pumpBridgeReads())}function nG(e){return{socketId:e,setNoDelay(t){return _netSocketSetNoDelayRaw?.applySync(void 0,[e,t!==!1]),this},setKeepAlive(t,r){return _netSocketSetKeepAliveRaw?.applySync(void 0,[e,t!==!1,gB(r)]),this},ref(){return this},unref(){return this}}}function Twe(e,t){return{socketId:e,info:t,setNoDelay(r){return _netSocketSetNoDelayRaw?.applySync(void 0,[e,r!==!1]),this},setKeepAlive(r,n){return _netSocketSetKeepAliveRaw?.applySync(void 0,[e,r!==!1,gB(n)]),this},ref(){return this},unref(){return this}}}var V2="__secure_exec_net_timeout__",pB=10,k1=null;function Nwe(){return(typeof process<"u"?process.env:globalThis.__agentOSProcessConfigEnv)?.AGENTOS_NET_BRIDGE_TRACE==="1"}function Mwe(e){let t=Number(e);return!Number.isFinite(t)||t<0?pB:Math.trunc(t)}function J2(){return k1??pB}function Fwe(){let e=typeof process<"u"?process.env:void 0,t=globalThis.__agentOSProcessConfigEnv;return e?.AGENTOS_NET_RETAIN_OWNED_WRITE_BUFFER!=="0"&&t?.AGENTOS_NET_RETAIN_OWNED_WRITE_BUFFER!=="0"}function WY(){return{userWriteCalls:0,userWriteBytes:0,queuedWriteChunks:0,queuedWriteBytes:0,queuedWriteCopiedChunks:0,queuedWriteCopiedBytes:0,queuedWriteRetainedChunks:0,queuedWriteRetainedBytes:0,flushCalls:0,flushChunks:0,flushBytes:0,writeBufferedBytesMax:0,writeBufferedChunksMax:0,writeBase64EncodeCalls:0,writeBase64EncodeBytes:0,writeBase64EncodeUs:0,writeRawCalls:0,writeRawBytes:0,writeRawElapsedUs:0,readRawCalls:0,readRawElapsedUs:0,readPumpRuns:0,readTimeoutSentinels:0,readPollTimersScheduled:0,readPollTimerFires:0,readPollTimerFireLagUs:0,readPollTimerFireLagMaxUs:0,readDataEvents:0,readBytes:0,readBase64DecodeCalls:0,readBase64DecodeBytes:0,readBase64DecodeChars:0,readBase64DecodeUs:0,readPayloadMaterializeCalls:0,readPayloadMaterializeBytes:0,readPayloadMaterializeUs:0,readEndEvents:0,readMacrotaskYields:0,readMacrotaskYieldElapsedUs:0,readMacrotaskYieldMaxUs:0,queueReadablePayloads:0,queueReadablePayloadElapsedUs:0,queueReadablePayloadMaxUs:0,queueReadableBytes:0,queueReadableBytesMax:0,queueReadableImmediateReadCalls:0,queueReadableImmediateReadUs:0,queueReadableImmediateReadMaxUs:0,socketReadableEmits:0,socketReadableEmitUs:0,socketReadableEmitMaxUs:0,socketDataEmits:0,socketDataEmitUs:0,socketDataEmitMaxUs:0,readPostDeliveryProbeCalls:0,readPostDeliveryProbeTimeoutSentinels:0,readPostDeliveryProbeDataEvents:0,readPostDeliveryNextRawCalls:0,readPostDeliveryNextRawTimeoutSentinels:0,readPostDeliveryNextRawDataEvents:0,readPostDeliveryToProbeStartUs:0,readPostDeliveryProbeElapsedUs:0,readPostDeliveryProbeMaxUs:0,readPostDeliveryPendingWriteFlushes:0,readPostDeliveryPendingWriteBytes:0,userWriteDuringDataEmitCalls:0,dataEmitStartToUserWriteUs:0,dataEmitEndToUserWriteUs:0,writeQueuedToFlushStartUs:0,writeQueuedToFlushStartMaxUs:0,writeFlushQueuedToRawUs:0,writeFlushQueuedToRawMaxUs:0,readWakeQueuedToPumpStartUs:0,readWakeQueuedToPumpStartMaxUs:0,acceptWakeQueuedToPumpStartUs:0,acceptWakeQueuedToPumpStartMaxUs:0,socketEndEmits:0,socketCloseEmits:0,socketConnectEmits:0,acceptRawCalls:0,acceptRawElapsedUs:0,acceptPumpRuns:0,acceptLoopAlreadyRunning:0,acceptTimeoutSentinels:0,acceptPollTimersScheduled:0,acceptPollTimerFires:0,acceptPollTimerFireLagUs:0,acceptPollTimerFireLagMaxUs:0,acceptConnections:0,acceptJsonParseUs:0,acceptOnConnectionUs:0,connectionEmits:0,readEventWakeups:0,readWakeAttempts:0,readWakeInvalidTargets:0,readWakeAlreadyRunning:0,readWakeNoTimer:0,readWakeNoTimerBeforeFirstPump:0,readWakeNoTimerAfterFirstPump:0,readWakeNoTimerConnected:0,readWakeNoTimerConnecting:0,readWakeNoTimerRefed:0,readWakeNoTimerUnrefed:0,readWakeNoTimerHasDataListener:0,readWakeNoTimerHasReadableListener:0,readWakeNoTimerPendingWriteFlush:0,readWakeNoTimerPendingWriteBytes:0,readFirstPumpAfterNoTimerWakeCalls:0,readFirstPumpAfterNoTimerWakeUs:0,readFirstPumpAfterNoTimerWakeMaxUs:0,readFirstPumpOriginConnectWait:0,readFirstPumpOriginAcceptedHandle:0,readFirstPumpOriginEventWake:0,readFirstPumpOriginTimer:0,readFirstPumpOriginRef:0,readFirstPumpOriginTls:0,readFirstPumpOriginUnknown:0,readFirstPumpResultData:0,readFirstPumpResultEnd:0,readFirstPumpResultTimeout:0,readFirstPumpScheduleCandidates:0,readFirstPumpScheduleQueued:0,readFirstPumpScheduleAlreadyScheduled:0,readFirstPumpScheduleRuns:0,readFirstPumpSchedulePumpCalls:0,readFirstPumpScheduleSkipDestroyed:0,readFirstPumpScheduleSkipTlsUpgrading:0,readFirstPumpScheduleSkipPumpStarted:0,readFirstPumpScheduleSkipLoopRunning:0,readFirstPumpScheduleSkipSocketClosed:0,readFirstPumpScheduleQueuedToRunUs:0,readFirstPumpScheduleQueuedToRunMaxUs:0,readFirstPumpScheduleQueuedToPumpStartUs:0,readFirstPumpScheduleQueuedToPumpStartMaxUs:0,readFirstPumpScheduleResultData:0,readFirstPumpScheduleResultTimeout:0,readFirstPumpScheduleResultEnd:0,peerWakeScans:0,peerWakeInvalidTargets:0,peerWakeFound:0,peerWakeMiss:0,acceptEventWakeups:0,acceptWakeAttempts:0,acceptWakeInvalidTargets:0,acceptWakeNoTimer:0,acceptWakeNoTimerBeforeFirstPump:0,acceptWakeNoTimerAfterFirstPump:0,acceptWakeNoTimerLoopRunning:0,acceptWakeNoTimerLoopActive:0,acceptWakeNoTimerRefed:0,acceptWakeNoTimerUnrefed:0,acceptWakeNoTimerConnections:0,acceptWakeNoTimerConnectionsMax:0,acceptFirstPumpAfterNoTimerWakeCalls:0,acceptFirstPumpAfterNoTimerWakeUs:0,acceptFirstPumpAfterNoTimerWakeMaxUs:0,acceptFirstPumpOriginListen:0,acceptFirstPumpOriginEventWake:0,acceptFirstPumpOriginTimer:0,acceptFirstPumpOriginRef:0,acceptFirstPumpOriginUnknown:0,acceptFirstPumpResultConnection:0,acceptFirstPumpResultTimeout:0,acceptFirstPumpResultEmpty:0,acceptWakeAlreadyRunning:0,acceptWakeSocketScans:0,acceptWakeSocketInvalidTargets:0,acceptWakeSocketFound:0,acceptWakeSocketMiss:0}}var U1=!1,Ll=WY();function ir(){return U1||Nwe()}function At(){return typeof performance<"u"&&typeof performance.now=="function"?Math.round(performance.now()*1e3):Date.now()*1e3}function re(e,t=1){ir()&&(Ll[e]=(Ll[e]??0)+t)}function Qr(e,t){if(!ir())return;let r=Number(t);Number.isFinite(r)&&(Ll[e]=Math.max(Ll[e]??0,r))}function kwe(e){switch(e){case"connectWait":re("readFirstPumpOriginConnectWait");break;case"acceptedHandle":re("readFirstPumpOriginAcceptedHandle");break;case"eventWake":re("readFirstPumpOriginEventWake");break;case"timer":re("readFirstPumpOriginTimer");break;case"ref":re("readFirstPumpOriginRef");break;case"tls":re("readFirstPumpOriginTls");break;default:re("readFirstPumpOriginUnknown");break}}function Uwe(e){switch(e){case"listen":re("acceptFirstPumpOriginListen");break;case"eventWake":re("acceptFirstPumpOriginEventWake");break;case"timer":re("acceptFirstPumpOriginTimer");break;case"ref":re("acceptFirstPumpOriginRef");break;default:re("acceptFirstPumpOriginUnknown");break}}et("__agentOSNetBridgeMetrics",{get enabled(){return ir()},enable(){U1=!0},disable(){U1=!1},setPollDelayMs(e){k1=Mwe(e)},resetPollDelayMs(){k1=null},pollDelayMs(){return J2()},reset(){Ll=WY(),typeof _benchNetTcpMetricsResetRaw<"u"&&_benchNetTcpMetricsResetRaw.applySync(void 0,[])},snapshot(){let e;return typeof _benchNetTcpMetricsSnapshotRaw<"u"&&(e=_benchNetTcpMetricsSnapshotRaw.applySync(void 0,[])),{...Ll,...e?{sidecarNetTrace:e}:{}}}});function xwe(){return new Promise(e=>{typeof lB=="function"?lB(e):setTimeout(e,0)})}function Lwe(e,t,r){if(e===0&&t.startsWith("http2:")){rr("http2 dispatch via netSocket",t);try{let i=r?JSON.parse(r):{};sW(t.slice(6),Number(i.id??0),i.data,i.extra,i.extraNumber,i.extraHeaders,i.flags)}catch{}return}let n=Awe(e);if(n)switch(t){case"connect":{n._applySocketInfo(YY(r)),n._connected=!0,n.connecting=!1,n._touchTimeout(),n._emitNet("connect"),n._emitNet("ready");break}case"secureConnect":case"secure":{let i=vwe(r);i&&(n.authorized=i.authorized===!0,n.authorizationError=i.authorizationError,n.alpnProtocol=i.alpnProtocol??!1,n.servername=i.servername??n.servername,n._tlsProtocol=i.protocol??null,n._tlsSessionReused=i.sessionReused===!0,n._tlsCipher=i.cipher??null),F1(n,t);break}case"data":{let i=typeof Buffer<"u"?Buffer.from(r,"base64"):new Uint8Array(0);n._touchTimeout(),n._emitNet("data",i);break}case"end":n._handleRemoteReadableEnd();break;case"session":{let i=typeof Buffer<"u"?Buffer.from(r??"","base64"):new Uint8Array(0);n._tlsSession=Buffer.from(i),n._emitNet("session",i);break}case"error":if(r)try{let i=JSON.parse(r);n.authorized=i.authorized===!0,n.authorizationError=i.authorizationError}catch{}n._emitNet("error",Dwe(r));break;case"close":n._emitSocketClose(!1);break}}et("_netSocketDispatch",Lwe);var Lm=256*1024,Do=class VY{constructor(t){y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_socketId",0);y(this,"_loopbackServer",null);y(this,"_loopbackBuffer",Buffer.alloc(0));y(this,"_loopbackDispatchRunning",!1);y(this,"_loopbackDispatchPending",!1);y(this,"_loopbackReadableEnded",!1);y(this,"_loopbackUpgradeSocket",null);y(this,"_loopbackEventQueue",Promise.resolve());y(this,"_encoding");y(this,"_noDelayState",!1);y(this,"_keepAliveState",!1);y(this,"_keepAliveDelaySeconds",0);y(this,"_refed",!0);y(this,"_bridgeReadLoopRunning",!1);y(this,"_bridgeReadPollTimer",null);y(this,"_bridgeReadPumpStarted",!1);y(this,"_bridgeReadFirstPumpBenchmarkScheduled",!1);y(this,"_readFirstPumpScheduleActive",!1);y(this,"_readFirstPumpScheduleQueuedAtUs",0);y(this,"_nextReadPumpOrigin",null);y(this,"_firstReadNoTimerWakeAtUs",0);y(this,"_timeoutMs",0);y(this,"_timeoutTimer",null);y(this,"_pendingBridgeWriteChunks",null);y(this,"_pendingBridgeWriteCallbacks",null);y(this,"_pendingBridgeWriteBytes",0);y(this,"_bridgeWriteFlushScheduled",!1);y(this,"_bridgeWriteFlushQueuedAtUs",0);y(this,"_lastReadDeliveryEndUs",0);y(this,"_currentDataEmitStartUs",0);y(this,"_lastDataEmitEndUs",0);y(this,"_readWakeQueuedAtUs",0);y(this,"_tlsUpgrading",!1);y(this,"_remoteEnded",!1);y(this,"_writableEnded",!1);y(this,"_closeEmitted",!1);y(this,"_connected",!1);y(this,"connecting",!1);y(this,"destroyed",!1);y(this,"writable",!0);y(this,"readable",!0);y(this,"readyState","open");y(this,"readableLength",0);y(this,"writableLength",0);y(this,"remoteAddress");y(this,"remotePort");y(this,"remoteFamily");y(this,"localAddress","0.0.0.0");y(this,"localPort",0);y(this,"localFamily","IPv4");y(this,"localPath");y(this,"remotePath");y(this,"bytesRead",0);y(this,"bytesWritten",0);y(this,"bufferSize",0);y(this,"pending",!0);y(this,"allowHalfOpen",!1);y(this,"encrypted",!1);y(this,"authorized",!1);y(this,"authorizationError");y(this,"servername");y(this,"alpnProtocol",!1);y(this,"writableHighWaterMark",16*1024);y(this,"server");y(this,"_tlsCipher",null);y(this,"_tlsProtocol",null);y(this,"_tlsSession",null);y(this,"_tlsSessionReused",!1);y(this,"_readableState",{endEmitted:!1,ended:!1});y(this,"_readQueue",[]);y(this,"_handle",null);t?.allowHalfOpen&&(this.allowHalfOpen=!0),t?.handle&&(this._handle=t.handle)}connect(t,r,n){if(typeof _netSocketConnectRaw>"u")throw new Error("net.Socket is not supported in sandbox (bridge not available)");let{host:i="127.0.0.1",port:s=0,path:o,keepAlive:a,keepAliveInitialDelay:A,callback:f}=ywe(t,r,n);f&&this.once("connect",f),this.connecting=!0,this.remoteAddress=o??i,this.remotePort=o?void 0:s,this.remotePath=o,this.pending=!1;let l;try{l=_we(_netSocketConnectRaw.applySync(void 0,[o?{path:o}:{host:i,port:s}]))}catch(p){return this.connecting=!1,this.pending=!1,queueMicrotask(()=>{this.destroyed||this.destroy(p)}),this}return l.loopbackHttpTarget?(this._loopbackHttpTarget=l.loopbackHttpTarget,this._applySocketInfo(l),this._connected=!0,this.connecting=!1,queueMicrotask(()=>{this._touchTimeout(),this._emitNet("connect"),this._emitNet("ready")}),this):(rr("socket connect",l.socketId,i,s,o??null),this._socketId=l.socketId,this._handle=nG(this._socketId),this._applySocketInfo(l),Zq(this._socketId,this),gwe(this),this._waitForConnect(),a&&this.once("connect",()=>{this.setKeepAlive(!0,A)}),this)}write(t,r,n){let i,s=!1;if(Buffer.isBuffer(t))i=t;else if(typeof t=="string"){let a=typeof r=="string"?r:"utf-8";i=Buffer.from(t,a),s=Fwe()}else i=Buffer.from(t);if(this._loopbackServer||this._loopbackHttpTarget){if(rr("socket write loopback",this._socketId,i.length),this.bytesWritten+=i.length,this._loopbackUpgradeSocket){this._touchTimeout(),this._loopbackUpgradeSocket._pushData(i);let A=typeof r=="function"?r:n;return A&&A(),!0}this._loopbackBuffer=Buffer.concat([this._loopbackBuffer,i]),this._touchTimeout(),this._dispatchLoopbackHttpRequest();let a=typeof r=="function"?r:n;return a&&a(),!0}if(typeof _netSocketWriteRaw>"u"||this.destroyed||!this._socketId)return!1;if(re("userWriteCalls"),re("userWriteBytes",i.length),ir()){let a=At();this._currentDataEmitStartUs>0?(re("userWriteDuringDataEmitCalls"),re("dataEmitStartToUserWriteUs",a-this._currentDataEmitStartUs)):this._lastDataEmitEndUs>0&&re("dataEmitEndToUserWriteUs",a-this._lastDataEmitEndUs)}this.bytesWritten+=i.length;let o=typeof r=="function"?r:n;return this._queueBridgeWrite(i,o,s),!0}end(t,r,n){return typeof t=="function"?this.once("finish",t):t!=null&&this.write(t,r,n),this._writableEnded||this.destroyed?this:(this._writableEnded=!0,this.writable=!1,queueMicrotask(()=>{this.destroyed||(this._emitNet("finish"),this._remoteEnded&&this._emitSocketClose(!1))}),this._loopbackServer||this._loopbackHttpTarget?(this._loopbackUpgradeSocket?queueMicrotask(()=>{this._loopbackUpgradeSocket?._pushEnd()}):this._loopbackReadableEnded||queueMicrotask(()=>{this._closeLoopbackReadable()}),this):(typeof _netSocketEndRaw<"u"&&this._socketId&&!this.destroyed&&(this._flushBridgeWrites(),rr("socket end",this._socketId),_netSocketEndRaw.applySync(void 0,[this._socketId]),this._touchTimeout()),this))}destroy(t){return this.destroyed?this:(rr("socket destroy",this._socketId,t?.message??null),this.destroyed=!0,this._writableEnded=!0,this.writable=!1,this.readable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._clearTimeoutTimer(),this._bridgeReadPollTimer&&(clearTimeout(this._bridgeReadPollTimer),this._bridgeReadPollTimer=null),this._loopbackServer||this._loopbackHttpTarget?(this._loopbackUpgradeSocket?.destroy(t),this._loopbackUpgradeSocket=null,this._loopbackServer=null,this._loopbackHttpTarget=null,t&&this._emitNet("error",t),this._emitSocketClose(!!t),this):(typeof _netSocketDestroyRaw<"u"&&this._socketId&&_netSocketDestroyRaw.applySync(void 0,[this._socketId]),t&&this._emitNet("error",t),this._emitSocketClose(!!t),this))}_queueBridgeWrite(t,r,n=!1){this._pendingBridgeWriteChunks||(this._pendingBridgeWriteChunks=[],this._pendingBridgeWriteCallbacks=[]);let i=n?t:Buffer.from(t);this._pendingBridgeWriteChunks.push(i),this._pendingBridgeWriteBytes+=i.length,re("queuedWriteChunks"),re("queuedWriteBytes",i.length),n?(re("queuedWriteRetainedChunks"),re("queuedWriteRetainedBytes",i.length)):(re("queuedWriteCopiedChunks"),re("queuedWriteCopiedBytes",i.length)),Qr("writeBufferedBytesMax",this._pendingBridgeWriteBytes),Qr("writeBufferedChunksMax",this._pendingBridgeWriteChunks.length),r&&this._pendingBridgeWriteCallbacks.push(r),this._bridgeWriteFlushScheduled||(this._bridgeWriteFlushScheduled=!0,ir()&&(this._bridgeWriteFlushQueuedAtUs=At()),queueMicrotask(()=>{this._flushBridgeWrites()}))}_flushBridgeWrites(){let t=this._pendingBridgeWriteChunks;if(!t||t.length===0){this._bridgeWriteFlushScheduled=!1,this._bridgeWriteFlushQueuedAtUs=0;return}let r=this._pendingBridgeWriteCallbacks??[],n=this._pendingBridgeWriteBytes;if(this._pendingBridgeWriteChunks=null,this._pendingBridgeWriteCallbacks=null,this._pendingBridgeWriteBytes=0,this._bridgeWriteFlushScheduled=!1,this.destroyed||!this._socketId||typeof _netSocketWriteRaw>"u")return;let i=ir();if(i&&this._bridgeWriteFlushQueuedAtUs>0){let f=Math.max(0,At()-this._bridgeWriteFlushQueuedAtUs);re("writeQueuedToFlushStartUs",f),Qr("writeQueuedToFlushStartMaxUs",f),re("writeFlushQueuedToRawUs",f),Qr("writeFlushQueuedToRawMaxUs",f),this._bridgeWriteFlushQueuedAtUs=0}rr("socket write",this._socketId,n,t.length),re("flushCalls"),re("flushChunks",t.length),re("flushBytes",n);let s=i?At():0,o=[],a=0,A=()=>{if(a===0)return;let f=o.length===1?o[0]:Buffer.concat(o,a);re("writeRawCalls"),re("writeRawBytes",f.length),_netSocketWriteRaw.applySync(void 0,[this._socketId,f]),o=[],a=0};for(let f of t)for(let l=0;l0&&a+p.length>Lm&&A(),o.push(p),a+=p.length,a>=Lm&&A()}A(),i&&re("writeRawElapsedUs",At()-s),hwe(this),this._touchTimeout();for(let f of r)f()}_emitSocketClose(t=!1){this._closeEmitted||(this._closeEmitted=!0,this._connected=!1,this.connecting=!1,this.pending=!1,this.readable=!1,this.writable=!1,this._clearTimeoutTimer(),this._socketId&&fwe(this._socketId),this._emitNet("close",t))}_handleRemoteReadableEnd(){this.destroyed||this._remoteEnded||(rr("socket remote end",this._socketId),this._remoteEnded=!0,this.readable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,queueMicrotask(()=>{if(!this.destroyed&&(this._emitNet("end"),!this.destroyed)){if(!this.allowHalfOpen&&!this._writableEnded){this.end();return}this._writableEnded&&this._emitSocketClose(!1)}}))}_applySocketInfo(t){t&&(this.localAddress=t.localAddress,this.localPort=t.localPort,this.localFamily=t.localFamily,this.localPath=t.localPath,this.remoteAddress=t.remoteAddress??this.remoteAddress,this.remotePort=t.remotePort??this.remotePort,this.remoteFamily=t.remoteFamily??this.remoteFamily,this.remotePath=t.remotePath??this.remotePath)}_applyAcceptedKeepAlive(t){this._keepAliveState=!0,this._keepAliveDelaySeconds=gB(t)}static fromAcceptedHandle(t,r){let n=new VY({allowHalfOpen:r?.allowHalfOpen});return n._socketId=t.socketId,n._handle=nG(t.socketId),n._applySocketInfo(t.info),n._connected=!0,n.connecting=!1,n.pending=!1,Zq(t.socketId,n),queueMicrotask(()=>{!n.destroyed&&!n._tlsUpgrading&&(n._nextReadPumpOrigin="acceptedHandle",n._pumpBridgeReads())}),n}setKeepAlive(t,r){let n=$q(t),i=gB(r);return n===this._keepAliveState&&(!n||i===this._keepAliveDelaySeconds)?this:(this._keepAliveState=n,this._keepAliveDelaySeconds=n?i:0,rr("socket setKeepAlive",this._socketId,n,i),this._handle?.setKeepAlive?.(n,i),this)}setNoDelay(t){let r=$q(t);return r===this._noDelayState?this:(this._noDelayState=r,rr("socket setNoDelay",this._socketId,r),this._handle?.setNoDelay?.(r),this)}setTimeout(t,r){let n=GY(t);if(r!==void 0&&typeof r!="function")throw xl("callback",r);return r&&this.once("timeout",r),this._timeoutMs=n,n===0?(this._clearTimeoutTimer(),this):(this._touchTimeout(),this)}ref(){return this._refed=!0,this._handle?.ref?.(),this._timeoutTimer&&typeof this._timeoutTimer.ref=="function"&&this._timeoutTimer.ref(),!this.destroyed&&this._connected&&!this._loopbackServer&&!this._loopbackHttpTarget&&!this._bridgeReadLoopRunning&&(this._nextReadPumpOrigin="ref",this._pumpBridgeReads()),this}unref(){return this._refed=!1,this._handle?.unref?.(),this._timeoutTimer&&typeof this._timeoutTimer.unref=="function"&&this._timeoutTimer.unref(),this._bridgeReadPollTimer&&(clearTimeout(this._bridgeReadPollTimer),this._bridgeReadPollTimer=null),this}pause(){return this}resume(){return this}read(t){if(this._readQueue.length===0)return null;if(t==null||t<=0){let i=this._readQueue.shift()??null;return i&&(this.readableLength=Math.max(0,this.readableLength-i.length)),i}let r=this._readQueue[0];if(!r)return null;if(r.length<=t)return this._readQueue.shift(),this.readableLength=Math.max(0,this.readableLength-r.length),r;let n=r.subarray(0,t);return this._readQueue[0]=r.subarray(t),this.readableLength=Math.max(0,this.readableLength-n.length),n}unshift(t){let r=Buffer.isBuffer(t)?t:Buffer.from(t);return r.length===0?this:(this._readQueue.unshift(r),this.readableLength+=r.length,this)}cork(){}uncork(){}address(){return{port:this.localPort,family:this.localFamily,address:this.localAddress}}getCipher(){return Ia(this._socketId,"getCipher")??this._tlsCipher}getSession(){let t=Ia(this._socketId,"getSession");return Buffer.isBuffer(t)?(this._tlsSession=Buffer.from(t),Buffer.from(t)):this._tlsSession?Buffer.from(this._tlsSession):null}isSessionReused(){let t=Ia(this._socketId,"isSessionReused");return typeof t=="boolean"?t:this._tlsSessionReused}getPeerCertificate(t){let r=Ia(this._socketId,"getPeerCertificate",t===!0);return r&&typeof r=="object"?r:{}}getCertificate(){let t=Ia(this._socketId,"getCertificate");return t&&typeof t=="object"?t:{}}getProtocol(){let t=Ia(this._socketId,"getProtocol");return typeof t=="string"?t:this._tlsProtocol}setEncoding(t){return this._encoding=t,this}pipe(t){return t}on(t,r){return this._listeners[t]||(this._listeners[t]=[]),this._listeners[t].push(r),this}addListener(t,r){return this.on(t,r)}once(t,r){return this._onceListeners[t]||(this._onceListeners[t]=[]),this._onceListeners[t].push(r),this}removeListener(t,r){let n=this._listeners[t];if(n){let s=n.indexOf(r);s>=0&&n.splice(s,1)}let i=this._onceListeners[t];if(i){let s=i.indexOf(r);s>=0&&i.splice(s,1)}return this}off(t,r){return this.removeListener(t,r)}removeAllListeners(t){return t?(delete this._listeners[t],delete this._onceListeners[t]):(this._listeners={},this._onceListeners={}),this}listeners(t){return[...this._listeners[t]??[],...this._onceListeners[t]??[]]}listenerCount(t){return(this._listeners[t]?.length??0)+(this._onceListeners[t]?.length??0)}setMaxListeners(t){return this}getMaxListeners(){return 10}prependListener(t,r){return this._listeners[t]||(this._listeners[t]=[]),this._listeners[t].unshift(r),this}prependOnceListener(t,r){return this._onceListeners[t]||(this._onceListeners[t]=[]),this._onceListeners[t].unshift(r),this}eventNames(){return[...new Set([...Object.keys(this._listeners),...Object.keys(this._onceListeners)])]}rawListeners(t){return this.listeners(t)}emit(t,...r){return this._emitNet(t,...r)}_emitNet(t,...r){let n=ir()&&(t==="readable"||t==="data"),i=n?At():0;n&&t==="data"&&(this._currentDataEmitStartUs=i),t==="readable"?re("socketReadableEmits"):t==="data"?re("socketDataEmits"):t==="end"?re("socketEndEmits"):t==="close"?re("socketCloseEmits"):t==="connect"&&re("socketConnectEmits"),t==="data"&&this._encoding&&r[0]&&Buffer.isBuffer(r[0])&&(r[0]=r[0].toString(this._encoding));let s=!1;try{let o=this._listeners[t];if(o)for(let A of[...o])A.call(this,...r),s=!0;let a=this._onceListeners[t];if(a){let A=[...a];this._onceListeners[t]=[];for(let f of A)f.call(this,...r),s=!0}}finally{if(n){let o=At()-i;t==="readable"?(re("socketReadableEmitUs",o),Qr("socketReadableEmitMaxUs",o)):t==="data"&&(re("socketDataEmitUs",o),Qr("socketDataEmitMaxUs",o),this._lastDataEmitEndUs=At(),this._currentDataEmitStartUs=0)}}return s}_queueReadablePayload(t){if(!t||t.length===0)return;let r=ir(),n=r?At():0;try{if(this._readQueue.push(t),this.readableLength+=t.length,re("queueReadablePayloads"),re("queueReadableBytes",t.length),Qr("queueReadableBytesMax",this.readableLength),this._emitNet("readable"),this.listenerCount("data")>0){let i=r?At():0,s=this.read();if(r){let o=At()-i;re("queueReadableImmediateReadCalls"),re("queueReadableImmediateReadUs",o),Qr("queueReadableImmediateReadMaxUs",o)}s!==null&&this._emitNet("data",s)}}finally{if(r){let i=At()-n;re("queueReadablePayloadElapsedUs",i),Qr("queueReadablePayloadMaxUs",i)}}}async _waitForConnect(){if(!(typeof _netSocketWaitConnectRaw>"u"||this._socketId===0))try{let t=await _netSocketWaitConnectRaw.apply(void 0,[this._socketId],{result:{promise:!0}});if(this.destroyed)return;this._applySocketInfo(YY(t)),this._connected=!0,this.connecting=!1,rr("socket connected",this._socketId,this.localAddress,this.localPort,this.remoteAddress,this.remotePort),this._touchTimeout(),rr("socket emit connect",this._socketId,this.listenerCount("connect")),this._emitNet("connect"),rr("socket emit ready",this._socketId,this.listenerCount("ready")),this._emitNet("ready"),this._tlsUpgrading||(this._nextReadPumpOrigin="connectWait",await this._pumpBridgeReads())}catch(t){if(this.destroyed)return;let r=t instanceof Error?t:new Error(String(t));rr("socket connect error",this._socketId,r.message,r.stack??null),this._emitNet("error",r),this.destroy()}}async _pumpBridgeReads(){if(this._bridgeReadLoopRunning||typeof _netSocketReadRaw>"u"||this._socketId===0)return;re("readPumpRuns");let t=!this._bridgeReadPumpStarted,r=this._readFirstPumpScheduleActive===!0;if(t){if(kwe(this._nextReadPumpOrigin),this._firstReadNoTimerWakeAtUs>0&&ir()){let s=Math.max(0,At()-this._firstReadNoTimerWakeAtUs);re("readFirstPumpAfterNoTimerWakeCalls"),re("readFirstPumpAfterNoTimerWakeUs",s),Qr("readFirstPumpAfterNoTimerWakeMaxUs",s)}if(r&&this._readFirstPumpScheduleQueuedAtUs>0&&ir()){let s=Math.max(0,At()-this._readFirstPumpScheduleQueuedAtUs);re("readFirstPumpScheduleQueuedToPumpStartUs",s),Qr("readFirstPumpScheduleQueuedToPumpStartMaxUs",s)}}this._readFirstPumpScheduleActive=!1,this._readFirstPumpScheduleQueuedAtUs=0,this._nextReadPumpOrigin=null,this._bridgeReadPumpStarted=!0;let n=!1,i=!1;if(ir()&&this._readWakeQueuedAtUs>0){let s=Math.max(0,At()-this._readWakeQueuedAtUs);re("readWakeQueuedToPumpStartUs",s),Qr("readWakeQueuedToPumpStartMaxUs",s),this._readWakeQueuedAtUs=0}this._bridgeReadLoopRunning=!0;try{for(;!this.destroyed;){re("readRawCalls");let s=ir(),o=s&&this._lastReadDeliveryEndUs>0?At():0;o>0&&(re("readPostDeliveryProbeCalls"),re("readPostDeliveryNextRawCalls"),re("readPostDeliveryToProbeStartUs",o-this._lastReadDeliveryEndUs),this._bridgeWriteFlushScheduled&&(re("readPostDeliveryPendingWriteFlushes"),re("readPostDeliveryPendingWriteBytes",this._pendingBridgeWriteBytes)),this._lastReadDeliveryEndUs=0);let a=s?At():0,A=_netSocketReadRaw.applySync(void 0,[this._socketId]);if(s){let p=At()-a;re("readRawElapsedUs",p),o>0&&(re("readPostDeliveryProbeElapsedUs",p),Qr("readPostDeliveryProbeMaxUs",p))}if(this.destroyed)return;if(A===V2){if(t&&!n&&(n=!0,re("readFirstPumpResultTimeout")),r&&!i&&(i=!0,re("readFirstPumpScheduleResultTimeout")),re("readTimeoutSentinels"),o>0&&(re("readPostDeliveryProbeTimeoutSentinels"),re("readPostDeliveryNextRawTimeoutSentinels")),!this._refed)return;re("readPollTimersScheduled");let p=J2(),I=ir()?At():0;this._bridgeReadPollTimer=setTimeout(()=>{if(ir()){let S=Math.max(0,At()-I-p*1e3);re("readPollTimerFires"),re("readPollTimerFireLagUs",S),Qr("readPollTimerFireLagMaxUs",S)}this._bridgeReadPollTimer=null,this._nextReadPumpOrigin="timer",this._pumpBridgeReads()},p);return}if(A===null){t&&!n&&(n=!0,re("readFirstPumpResultEnd")),r&&!i&&(i=!0,re("readFirstPumpScheduleResultEnd")),re("readEndEvents"),this._handleRemoteReadableEnd();return}o>0&&(re("readPostDeliveryProbeDataEvents"),re("readPostDeliveryNextRawDataEvents")),t&&!n&&(n=!0,re("readFirstPumpResultData")),r&&!i&&(i=!0,re("readFirstPumpScheduleResultData"));let f;if(typeof A=="string"){let p=s?At():0;f=Buffer.from(A,"base64"),s&&(re("readBase64DecodeCalls"),re("readBase64DecodeBytes",f.length),re("readBase64DecodeChars",A.length),re("readBase64DecodeUs",At()-p))}else{let p=s?At():0;f=Buffer.from(A),s&&(re("readPayloadMaterializeCalls"),re("readPayloadMaterializeBytes",f.length),re("readPayloadMaterializeUs",At()-p))}rr("socket data",this._socketId,f.length),re("readDataEvents"),re("readBytes",f.length),this.bytesRead+=f.length,this._touchTimeout(),re("readMacrotaskYields");let l=s?At():0;if(await xwe(),s){let p=At()-l;re("readMacrotaskYieldElapsedUs",p),Qr("readMacrotaskYieldMaxUs",p)}if(this.destroyed)return;this._queueReadablePayload(f),s&&(this._lastReadDeliveryEndUs=At())}}finally{this._bridgeReadLoopRunning=!1}}_dispatchLoopbackHttpRequest(){if(!(!this._loopbackServer&&!this._loopbackHttpTarget||this.destroyed)){if(this._loopbackDispatchRunning){this._loopbackDispatchPending=!0;return}this._loopbackDispatchRunning=!0,this._processLoopbackHttpRequests().finally(()=>{this._loopbackDispatchRunning=!1,this._loopbackDispatchPending&&this._loopbackBuffer.length>0?(this._loopbackDispatchPending=!1,this._dispatchLoopbackHttpRequest()):this._loopbackDispatchPending=!1})}}async _processLoopbackHttpRequests(){let t=!1;for(;(this._loopbackServer||this._loopbackHttpTarget)&&!this.destroyed;){let r=this._loopbackServer??{listenerCount:()=>0},n=pW(this._loopbackBuffer,r);if(n.kind==="incomplete"){t&&this._closeLoopbackReadable();return}if(n.kind==="bad-request"){this._pushLoopbackData(V1()),n.closeConnection&&this._closeLoopbackReadable(),this._loopbackBuffer=Buffer.alloc(0);return}if(this._loopbackBuffer=this._loopbackBuffer.subarray(n.bytesConsumed),n.upgradeHead){this._dispatchLoopbackUpgrade(n.request,n.upgradeHead);return}let i;if(this._loopbackHttpTarget){if(typeof _networkHttpServerRequestRaw>"u")throw new Error("HTTP loopback bridge is not available");i=_networkHttpServerRequestRaw.applySync(void 0,[{...this._loopbackHttpTarget,request:JSON.stringify(n.request)}])}else({responseJson:i}=await YSe(this._loopbackServer,n.request));let s=JSON.parse(i),o=eR(s,n.request,n.closeConnection);if(!t&&o.payload.length>0&&this._pushLoopbackData(o.payload),o.closeConnection&&(t=!0,this._loopbackBuffer.length===0)){this._closeLoopbackReadable();return}}}_pushLoopbackData(t){if(t.length===0||this._loopbackReadableEnded)return;let r=Buffer.from(t);this._queueLoopbackEvent(()=>{this.destroyed||(this.bytesRead+=r.length,this._touchTimeout(),this._queueReadablePayload(r))})}_closeLoopbackReadable(){this._loopbackReadableEnded||(this._loopbackReadableEnded=!0,this.readable=!1,this.writable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._clearTimeoutTimer(),this._queueLoopbackEvent(()=>{this._emitNet("end"),this._emitNet("close")}))}_queueLoopbackEvent(t){this._loopbackEventQueue=this._loopbackEventQueue.then(()=>new Promise(r=>{queueMicrotask(()=>{try{t()}finally{r()}})}))}_dispatchLoopbackUpgrade(t,r){if(this._loopbackServer)try{let n=new CSe({host:this.remoteAddress,port:this.remotePort});n._attachPeer({_pushData:i=>this._pushLoopbackData(i),_pushEnd:()=>this._closeLoopbackReadable()}),this._loopbackUpgradeSocket=n,this._loopbackServer._emit("upgrade",new Du(t),n,r)}catch(n){let i=n instanceof Error?n:new Error(String(n)),s=!1,o=null;if(typeof process<"u"&&typeof process.emit=="function"){let a=process;try{s=a.emit("uncaughtException",i,"uncaughtException")}catch(A){if(A&&typeof A=="object"&&A.name==="ProcessExitError"){s=!0;let f=Number(A.code);o=Number.isFinite(f)?f:0}else throw A}}if(s){o!==null&&(process.exitCode=o),this._loopbackServer?.close(),this.destroy();return}throw i}}_upgradeTls(t){if(typeof _netSocketUpgradeTlsRaw>"u")throw new Error("tls.connect is not supported in sandbox (bridge not available)");if(this._tlsUpgrading=!0,this._loopbackServer&&(typeof this._socketId!="string"||this._socketId.length===0)){queueMicrotask(()=>{this.destroyed||F1(this)});return}_netSocketUpgradeTlsRaw.applySync(void 0,[this._socketId,JSON.stringify(t??{})]),queueMicrotask(()=>{this.destroyed||F1(this)})}_touchTimeout(){this._timeoutMs===0||this.destroyed||(this._clearTimeoutTimer(),this._timeoutTimer=setTimeout(()=>{this._timeoutTimer=null,!this.destroyed&&this._emitNet("timeout")},this._timeoutMs),!this._refed&&typeof this._timeoutTimer.unref=="function"&&this._timeoutTimer.unref())}_clearTimeoutTimer(){this._timeoutTimer&&(clearTimeout(this._timeoutTimer),this._timeoutTimer=null)}};function x1(e,t,r){let n=new Do;return n.connect(e,t,r),n}var Pg=class{constructor(e,t){y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_serverId",0);y(this,"_address",null);y(this,"_acceptLoopActive",!1);y(this,"_acceptLoopRunning",!1);y(this,"_acceptPollTimer",null);y(this,"_acceptPumpStarted",!1);y(this,"_nextAcceptPumpOrigin",null);y(this,"_firstAcceptNoTimerWakeAtUs",0);y(this,"_acceptWakeQueuedAtUs",0);y(this,"_handleRefId",null);y(this,"_connections",new Set);y(this,"_refed",!0);y(this,"listening",!1);y(this,"keepAlive",!1);y(this,"keepAliveInitialDelay",0);y(this,"allowHalfOpen",!1);y(this,"maxConnections");y(this,"_handle");typeof e=="function"?this.on("connection",e):(this.allowHalfOpen=e?.allowHalfOpen===!0,this.keepAlive=e?.keepAlive===!0,this.keepAliveInitialDelay=e?.keepAliveInitialDelay??0,t&&this.on("connection",t)),this._handle={onconnection:(r,n)=>{if(r){this._emit("error",r);return}if(!n)return;if(typeof this.maxConnections=="number"&&this.maxConnections>=0&&this._connections.size>=this.maxConnections){this._emit("drop",{localAddress:n.info.localAddress,localPort:n.info.localPort,localFamily:n.info.localFamily,remoteAddress:n.info.remoteAddress,remotePort:n.info.remotePort,remoteFamily:n.info.remoteFamily}),_netSocketDestroyRaw?.applySync(void 0,[n.socketId]);return}this.keepAlive&&n.setKeepAlive?.(!0,this.keepAliveInitialDelay);let i=Do.fromAcceptedHandle(n,{allowHalfOpen:this.allowHalfOpen});i.server=this,this._connections.add(i),i.once("close",()=>{this._connections.delete(i)}),this.keepAlive&&i._applyAcceptedKeepAlive(this.keepAliveInitialDelay),re("connectionEmits"),this._emit("connection",i)}}}listen(e,t,r,n){if(typeof _netServerListenRaw>"u"||typeof _netServerAcceptRaw>"u")throw new Error("net.createServer is not supported in sandbox");let{port:i,host:s,path:o,backlog:a,readableAll:A,writableAll:f,callback:l}=HY(e,t,r,n);l&&this.once("listening",l);try{let p=_netServerListenRaw.applySyncPromise(void 0,[{port:i,host:s,path:o,backlog:a,readableAll:A,writableAll:f}]),I=typeof p=="string"?JSON.parse(p):p,S=I.address??I;this._serverId=I.serverId,this._address=S.localPath?S.localPath:{address:S.localAddress,family:S.localFamily??S.family,port:S.localPort},this.listening=!0,uwe(this),this._syncHandleRef(),this._acceptLoopActive=!0,queueMicrotask(()=>{!this.listening||this._serverId===0||(this._emit("listening"),this._nextAcceptPumpOrigin="listen",this._pumpAccepts())})}catch(p){queueMicrotask(()=>{this._emit("error",p)})}return this}close(e){if(e&&this.once("close",e),!this.listening||typeof _netServerCloseRaw>"u")return queueMicrotask(()=>{this._emit("close")}),this;this.listening=!1,this._acceptLoopActive=!1,cwe(this),this._acceptPollTimer&&(clearTimeout(this._acceptPollTimer),this._acceptPollTimer=null),this._syncHandleRef();let t=this._serverId;return this._serverId=0,(async()=>{try{await _netServerCloseRaw.apply(void 0,[t],{result:{promise:!0}})}finally{this._address=null,this._emit("close")}})(),this}address(){return this._address}getConnections(e){if(typeof e!="function")throw xl("callback",e);return queueMicrotask(()=>{e(null,this._connections.size)}),this}ref(){return this._refed=!0,this._syncHandleRef(),this.listening&&this._acceptLoopActive&&!this._acceptLoopRunning&&(this._nextAcceptPumpOrigin="ref",this._pumpAccepts()),this}unref(){return this._refed=!1,this._acceptPollTimer&&(clearTimeout(this._acceptPollTimer),this._acceptPollTimer=null),this._syncHandleRef(),this}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this}emit(e,...t){return this._emit(e,...t)}_emit(e,...t){let r=!1,n=this._listeners[e];if(n)for(let s of[...n])s.call(this,...t),r=!0;let i=this._onceListeners[e];if(i){this._onceListeners[e]=[];for(let s of[...i])s.call(this,...t),r=!0}return r}_syncHandleRef(){if(!this.listening||this._serverId===0||!this._refed){this._handleRefId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleRefId),this._handleRefId=null;return}let e=`${awe}${this._serverId}`;this._handleRefId!==e&&(this._handleRefId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleRefId),this._handleRefId=e,typeof _registerHandle=="function"&&_registerHandle(this._handleRefId,"net server"))}async _pumpAccepts(){if(typeof _netServerAcceptRaw>"u"||this._acceptLoopRunning){this._acceptLoopRunning&&re("acceptLoopAlreadyRunning");return}re("acceptPumpRuns");let e=!this._acceptPumpStarted;if(e&&(Uwe(this._nextAcceptPumpOrigin),this._firstAcceptNoTimerWakeAtUs>0&&ir())){let r=Math.max(0,At()-this._firstAcceptNoTimerWakeAtUs);re("acceptFirstPumpAfterNoTimerWakeCalls"),re("acceptFirstPumpAfterNoTimerWakeUs",r),Qr("acceptFirstPumpAfterNoTimerWakeMaxUs",r)}this._nextAcceptPumpOrigin=null,this._acceptPumpStarted=!0;let t=!1;if(ir()&&this._acceptWakeQueuedAtUs>0){let r=Math.max(0,At()-this._acceptWakeQueuedAtUs);re("acceptWakeQueuedToPumpStartUs",r),Qr("acceptWakeQueuedToPumpStartMaxUs",r),this._acceptWakeQueuedAtUs=0}this._acceptLoopRunning=!0;try{for(;this._acceptLoopActive&&this._serverId!==0;){re("acceptRawCalls");let r=ir(),n=r?At():0,i=_netServerAcceptRaw.applySync(void 0,[this._serverId]);if(r&&re("acceptRawElapsedUs",At()-n),i===V2){if(e&&!t&&(t=!0,re("acceptFirstPumpResultTimeout")),re("acceptTimeoutSentinels"),!this._refed)return;re("acceptPollTimersScheduled");let s=J2(),o=ir()?At():0;this._acceptPollTimer=setTimeout(()=>{if(ir()){let a=Math.max(0,At()-o-s*1e3);re("acceptPollTimerFires"),re("acceptPollTimerFireLagUs",a),Qr("acceptPollTimerFireLagMaxUs",a)}this._acceptPollTimer=null,this._nextAcceptPumpOrigin="timer",this._pumpAccepts()},s);return}if(!i){e&&!t&&(t=!0,re("acceptFirstPumpResultEmpty"));return}try{let s=r?At():0,o=JSON.parse(i);r&&re("acceptJsonParseUs",At()-s),re("acceptConnections"),e&&!t&&(t=!0,re("acceptFirstPumpResultConnection"));let a=Twe(o.socketId,o.info),A=r?At():0;this._handle.onconnection(null,a),r&&re("acceptOnConnectionUs",At()-A)}catch(s){this._emit("error",s)}}}finally{this._acceptLoopRunning=!1}}};function Pwe(e,t){return new Pg(e,t)}var JY={BlockList:wwe,Socket:Do,SocketAddress:Swe,Server:Pwe,Stream:Do,connect:x1,createConnection:x1,createServer(e,t){return new Pg(e,t)},getDefaultAutoSelectFamily(){return tG},getDefaultAutoSelectFamilyAttemptTimeout(){return rG},isIP(e){return Tl(e)},isIPv4(e){return Tl(e)===4},isIPv6(e){return Tl(e)===6},setDefaultAutoSelectFamily(e){tG=e!==!1},setDefaultAutoSelectFamilyAttemptTimeout(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw new RangeError(`Invalid auto-select family attempt timeout: ${e}`);rG=Math.trunc(t)}},Owe=Symbol.for("secure-exec.http2.kSocket"),iG=Symbol("options"),Io=new Map,qn=new Map,In=new Map,EB=new Map,Jv=new Set,L1=[],P1=new Map,jv=!1,Hwe=1,Ru=class{constructor(){y(this,"_listeners",{});y(this,"_onceListeners",{})}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}addListener(e,t){return this.on(e,t)}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this}removeListener(e,t){let r=n=>{if(!n)return;let i=n.indexOf(t);i!==-1&&n.splice(i,1)};return r(this._listeners[e]),r(this._onceListeners[e]),this}off(e,t){return this.removeListener(e,t)}listenerCount(e){return(this._listeners[e]?.length??0)+(this._onceListeners[e]?.length??0)}setMaxListeners(e){return this}emit(e,...t){let r=!1,n=this._listeners[e];if(n)for(let s of[...n])s.call(this,...t),r=!0;let i=this._onceListeners[e];if(i){this._onceListeners[e]=[];for(let s of[...i])s.call(this,...t),r=!0}return r}},O1=class extends Ru{constructor(t,r){super();y(this,"allowHalfOpen",!1);y(this,"encrypted",!1);y(this,"localAddress","127.0.0.1");y(this,"localPort",0);y(this,"localFamily","IPv4");y(this,"remoteAddress","127.0.0.1");y(this,"remotePort",0);y(this,"remoteFamily","IPv4");y(this,"servername");y(this,"alpnProtocol",!1);y(this,"readable",!0);y(this,"writable",!0);y(this,"destroyed",!1);y(this,"_bridgeReadPollTimer",null);y(this,"_loopbackServer",null);y(this,"_onDestroy");y(this,"_destroyCallbackInvoked",!1);this._onDestroy=r,this._applyState(t)}_applyState(t){t&&(this.allowHalfOpen=t.allowHalfOpen===!0,this.encrypted=t.encrypted===!0,this.localAddress=t.localAddress??this.localAddress,this.localPort=t.localPort??this.localPort,this.localFamily=t.localFamily??this.localFamily,this.remoteAddress=t.remoteAddress??this.remoteAddress,this.remotePort=t.remotePort??this.remotePort,this.remoteFamily=t.remoteFamily??this.remoteFamily,this.servername=t.servername,this.alpnProtocol=t.alpnProtocol??this.alpnProtocol)}_clearTimeoutTimer(){}_emitNet(t,r){if(t==="error"&&r){this.emit("error",r);return}t==="close"&&(this._destroyCallbackInvoked||(this._destroyCallbackInvoked=!0,queueMicrotask(()=>{this._onDestroy?.()})),this.emit("close"))}end(){return this.destroyed=!0,this.readable=!1,this.writable=!1,this.emit("close"),this}destroy(){return this.destroyed?this:(this.destroyed=!0,this.readable=!1,this.writable=!1,this._emitNet("close"),this)}};function Pl(e,t,r){return lr(`The "${e}" argument must be of type ${t}. Received ${Yn(r)}`,"ERR_INVALID_ARG_TYPE")}function bo(e,t){return IB(t,e)}function wg(e,t){let r=new RangeError(`Invalid value for setting "${e}": ${String(t)}`);return r.code="ERR_HTTP2_INVALID_SETTING_VALUE",r}function qwe(e,t){let r=new TypeError(`Invalid value for setting "${e}": ${String(t)}`);return r.code="ERR_HTTP2_INVALID_SETTING_VALUE",r}var Qo={NGHTTP2_NO_ERROR:0,NGHTTP2_PROTOCOL_ERROR:1,NGHTTP2_INTERNAL_ERROR:2,NGHTTP2_FLOW_CONTROL_ERROR:3,NGHTTP2_SETTINGS_TIMEOUT:4,NGHTTP2_STREAM_CLOSED:5,NGHTTP2_FRAME_SIZE_ERROR:6,NGHTTP2_REFUSED_STREAM:7,NGHTTP2_CANCEL:8,NGHTTP2_COMPRESSION_ERROR:9,NGHTTP2_CONNECT_ERROR:10,NGHTTP2_ENHANCE_YOUR_CALM:11,NGHTTP2_INADEQUATE_SECURITY:12,NGHTTP2_HTTP_1_1_REQUIRED:13,NGHTTP2_NV_FLAG_NONE:0,NGHTTP2_NV_FLAG_NO_INDEX:1,NGHTTP2_ERR_DEFERRED:-508,NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE:-509,NGHTTP2_ERR_STREAM_CLOSED:-510,NGHTTP2_ERR_INVALID_ARGUMENT:-501,NGHTTP2_ERR_FRAME_SIZE_ERROR:-522,NGHTTP2_ERR_NOMEM:-901,NGHTTP2_FLAG_NONE:0,NGHTTP2_FLAG_END_STREAM:1,NGHTTP2_FLAG_END_HEADERS:4,NGHTTP2_FLAG_ACK:1,NGHTTP2_FLAG_PADDED:8,NGHTTP2_FLAG_PRIORITY:32,NGHTTP2_DEFAULT_WEIGHT:16,NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:1,NGHTTP2_SETTINGS_ENABLE_PUSH:2,NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:3,NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:4,NGHTTP2_SETTINGS_MAX_FRAME_SIZE:5,NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:6,NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:8},Gwe={[Qo.NGHTTP2_ERR_DEFERRED]:"Data deferred",[Qo.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE]:"Stream ID is not available",[Qo.NGHTTP2_ERR_STREAM_CLOSED]:"Stream was already closed or invalid",[Qo.NGHTTP2_ERR_INVALID_ARGUMENT]:"Invalid argument",[Qo.NGHTTP2_ERR_FRAME_SIZE_ERROR]:"Frame size error",[Qo.NGHTTP2_ERR_NOMEM]:"Out of memory"},jY=class extends Error{constructor(t){super(t);y(this,"code","ERR_HTTP2_ERROR");this.name="Error"}};function zY(e){return Gwe[e]??`HTTP/2 error (${String(e)})`}function zv(e,t){return lr(`The property 'options.${e}' is invalid. Received ${Ywe(t)}`,"ERR_INVALID_ARG_VALUE")}function Ywe(e){return typeof e=="function"?`[Function${e.name?`: ${e.name}`:": function"}]`:typeof e=="symbol"?e.toString():Array.isArray(e)?"[]":e===null?"null":typeof e=="object"?"{}":String(e)}function Wwe(e){return bo("ERR_HTTP2_PAYLOAD_FORBIDDEN",`Responses with ${String(e)} status must not have a payload`)}var Vwe=61440,Jwe=16384,jwe=32768,zwe=4096,Kwe=49152,Xwe=40960;function Zwe(e){let t=e.atimeMs??0,r=e.mtimeMs??t,n=e.ctimeMs??r,i=e.birthtimeMs??n,s=e.mode&Vwe;return{size:e.size,mode:e.mode,atimeMs:t,mtimeMs:r,ctimeMs:n,birthtimeMs:i,atime:new Date(t),mtime:new Date(r),ctime:new Date(n),birthtime:new Date(i),isFile:()=>s===jwe,isDirectory:()=>s===Jwe,isFIFO:()=>s===zwe,isSocket:()=>s===Kwe,isSymbolicLink:()=>s===Xwe}}function $we(e){let t=e??{},r=t.offset;if(r!==void 0&&(typeof r!="number"||!Number.isFinite(r)))throw zv("offset",r);let n=t.length;if(n!==void 0&&(typeof n!="number"||!Number.isFinite(n)))throw zv("length",n);let i=t.statCheck;if(i!==void 0&&typeof i!="function")throw zv("statCheck",i);let s=t.onError;return{offset:r===void 0?0:Math.max(0,Math.trunc(r)),length:typeof n=="number"?Math.trunc(n):void 0,statCheck:typeof i=="function"?i:void 0,onError:typeof s=="function"?s:void 0}}function eSe(e,t,r){let n=Math.max(0,Math.min(t,e.length));return r===void 0||r<0?e.subarray(n):e.subarray(n,Math.min(e.length,n+r))}var KY=class{constructor(e){y(this,"_streamId");this._streamId=e}respond(e){if(typeof _networkHttp2StreamRespondRaw>"u")throw new Error("http2 server stream respond bridge is not available");return _networkHttp2StreamRespondRaw.applySync(void 0,[this._streamId,j2(e)]),0}},H1={headerTableSize:4096,enablePush:!0,initialWindowSize:65535,maxFrameSize:16384,maxConcurrentStreams:4294967295,maxHeaderListSize:65535,maxHeaderSize:65535,enableConnectProtocol:!1},XY={effectiveLocalWindowSize:65535,localWindowSize:65535,remoteWindowSize:65535,nextStreamID:1,outboundQueueSize:1,deflateDynamicTableSize:0,inflateDynamicTableSize:0};function Wi(e){let t={};for(let[r,n]of Object.entries(e??{})){if(r==="customSettings"&&n&&typeof n=="object"){let i={};for(let[s,o]of Object.entries(n))i[Number(s)]=Number(o);t.customSettings=i;continue}t[r]=n}return t}function sG(e){return{...XY,...e??{}}}function tSe(e){if(!e||typeof e!="object")return;let t=e,r={},n=["effectiveLocalWindowSize","localWindowSize","remoteWindowSize","nextStreamID","outboundQueueSize","deflateDynamicTableSize","inflateDynamicTableSize"];for(let i of n)typeof t[i]=="number"&&(r[i]=t[i]);return r}function ZY(e,t="settings"){if(!e||typeof e!="object"||Array.isArray(e))throw Pl(t,"object",e);let r=e,n={},i={headerTableSize:[0,4294967295],initialWindowSize:[0,4294967295],maxFrameSize:[16384,16777215],maxConcurrentStreams:[0,4294967295],maxHeaderListSize:[0,4294967295],maxHeaderSize:[0,4294967295]};for(let[s,o]of Object.entries(r))if(o!==void 0){if(s==="enablePush"||s==="enableConnectProtocol"){if(typeof o!="boolean")throw qwe(s,o);n[s]=o;continue}if(s==="customSettings"){if(!o||typeof o!="object"||Array.isArray(o))throw wg(s,o);let a={};for(let[A,f]of Object.entries(o)){let l=Number(A);if(!Number.isInteger(l)||l<0||l>65535||typeof f!="number"||!Number.isInteger(f)||f<0||f>4294967295)throw wg(s,o);a[l]=f}n.customSettings=a;continue}if(s in i){let[a,A]=i[s];if(typeof o!="number"||!Number.isInteger(o)||oA)throw wg(s,o);n[s]=o;continue}n[s]=o}return n}function j2(e){return JSON.stringify(e??{})}function NA(e){if(!e)return{};try{let t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}function Dg(e){if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}function oG(e){if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}function yB(e){if(!e)return new Error("Unknown HTTP/2 bridge error");try{let t=JSON.parse(e),r=new Error(t.message??"Unknown HTTP/2 bridge error");return t.name&&(r.name=t.name),t.code&&(r.code=t.code),r}catch{return new Error(e)}}function $Y(e){let t={};if(!e||typeof e!="object")return t;for(let[r,n]of Object.entries(e))t[String(r)]=n;return t}function rSe(e){if(!e)return;let t={endStream:"boolean",weight:"number",parent:"number",exclusive:"boolean",silent:"boolean"};for(let[r,n]of Object.entries(t)){if(!(r in e)||e[r]===void 0)continue;let i=e[r];if(n==="boolean"&&typeof i!="boolean")throw Pl(r,"boolean",i);if(n==="number"&&typeof i!="number")throw Pl(r,"number",i)}}function nSe(e){if(!e||!e.settings||typeof e.settings!="object")return;let t=e.settings;if("maxFrameSize"in t){let r=t.maxFrameSize;if(typeof r!="number"||!Number.isInteger(r)||r<16384||r>16777215)throw wg("maxFrameSize",r)}}function z2(e,t){t&&(e.encrypted=t.encrypted===!0,e.alpnProtocol=t.alpnProtocol??(e.encrypted?"h2":"h2c"),e.originSet=Array.isArray(t.originSet)&&t.originSet.length>0?[...t.originSet]:e.encrypted?[]:void 0,t.localSettings&&typeof t.localSettings=="object"&&(e.localSettings=Wi(t.localSettings)),t.remoteSettings&&typeof t.remoteSettings=="object"&&(e.remoteSettings=Wi(t.remoteSettings)),t.state&&typeof t.state=="object"&&e._applyRuntimeState(tSe(t.state)),e.socket._applyState(t.socket))}function iSe(e,t){if(e instanceof URL)return e;if(typeof e=="string")return new URL(e);if(e&&typeof e=="object"){let r=e,n=typeof(t?.protocol??r.protocol)=="string"?String(t?.protocol??r.protocol):"http:",i=typeof(t?.host??r.host??t?.hostname??r.hostname)=="string"?String(t?.host??r.host??t?.hostname??r.hostname):"localhost",s=t?.port??r.port,o=s===void 0?"":String(s);return new URL(`${n}//${i}${o?`:${o}`:""}`)}return new URL("http://localhost")}function sSe(e,t,r){let n=typeof t=="function"?t:typeof r=="function"?r:void 0,i=typeof t=="function"?{}:t??{};return{authority:iSe(e,i),options:i,listener:n}}function oSe(e){if(!e||typeof e!="object")return;let t=e._socketId;return typeof t=="number"&&Number.isFinite(t)?t:void 0}var eW=class extends Ru{constructor(t,r,n=!1){super();y(this,"_streamId");y(this,"_encoding");y(this,"_utf8Remainder");y(this,"_isPushStream");y(this,"_session");y(this,"_receivedResponse",!1);y(this,"_needsDrain",!1);y(this,"_pendingWritableBytes",0);y(this,"_drainScheduled",!1);y(this,"_writableHighWaterMark",16*1024);y(this,"rstCode",0);y(this,"readable",!0);y(this,"writable",!0);y(this,"writableEnded",!1);y(this,"writableFinished",!1);y(this,"destroyed",!1);y(this,"_writableState",{ended:!1,finished:!1,objectMode:!1,corked:0,length:0});this._streamId=t,this._session=r,this._isPushStream=n,n||queueMicrotask(()=>{this.emit("ready")})}setEncoding(t){return this._encoding=t,this._utf8Remainder=this._encoding==="utf8"||this._encoding==="utf-8"?Buffer.alloc(0):void 0,this}close(){return this.end(),this}destroy(t){return this.destroyed?this:(this.destroyed=!0,t&&this.emit("error",t),this.end(),this)}_scheduleDrain(){!this._needsDrain||this._drainScheduled||(this._drainScheduled=!0,queueMicrotask(()=>{this._drainScheduled=!1,this._needsDrain&&(this._needsDrain=!1,this._pendingWritableBytes=0,this.emit("drain"))}))}write(t,r,n){if(typeof _networkHttp2StreamWriteRaw>"u")throw new Error("http2 session stream write bridge is not available");let i=Buffer.isBuffer(t)?t:typeof t=="string"?Buffer.from(t,typeof r=="string"?r:"utf8"):Buffer.from(t),s=_networkHttp2StreamWriteRaw.applySync(void 0,[this._streamId,i.toString("base64")]);this._pendingWritableBytes+=i.byteLength;let o=s===!1||this._pendingWritableBytes>=this._writableHighWaterMark;return o&&(this._needsDrain=!0),(typeof r=="function"?r:n)?.(),!o}end(t){if(typeof _networkHttp2StreamEndRaw>"u")throw new Error("http2 session stream end bridge is not available");let r=null;return t!==void 0&&(r=(Buffer.isBuffer(t)?t:Buffer.from(t)).toString("base64")),_networkHttp2StreamEndRaw.applySync(void 0,[this._streamId,r]),this.writableEnded=!0,this._writableState.ended=!0,queueMicrotask(()=>{this.writable=!1,this.writableFinished=!0,this._writableState.finished=!0,this.emit("finish")}),this}resume(){return this}_emitPush(t,r){process.env.SECURE_EXEC_DEBUG_HTTP2_BRIDGE==="1"&&console.error("[secure-exec http2 isolate] push",this._streamId),this.emit("push",t,r??0)}_hasReceivedResponse(){return this._receivedResponse}_belongsTo(t){return this._session===t}_emitResponseHeaders(t){this._receivedResponse=!0,process.env.SECURE_EXEC_DEBUG_HTTP2_BRIDGE==="1"&&console.error("[secure-exec http2 isolate] response headers",this._streamId,this._isPushStream),this._isPushStream||this.emit("response",t)}_emitDataChunk(t){if(!t)return;let r=Buffer.from(t,"base64");if(this._utf8Remainder!==void 0){let n=this._utf8Remainder.length>0?Buffer.concat([this._utf8Remainder,r]):r,i=aSe(n),s=n.subarray(0,i).toString("utf8");this._utf8Remainder=i0&&this.emit("data",s)}else this._encoding?this.emit("data",r.toString(this._encoding)):this.emit("data",r);this._scheduleDrain()}_emitEnd(){if(this._utf8Remainder&&this._utf8Remainder.length>0){let t=this._utf8Remainder.toString("utf8");this._utf8Remainder=Buffer.alloc(0),t.length>0&&this.emit("data",t)}this.readable=!1,this.emit("end"),this._scheduleDrain()}_emitClose(t){typeof t=="number"&&(this.rstCode=t),this.destroyed=!0,this.readable=!1,this.writable=!1,this._scheduleDrain(),this.emit("close")}};function aSe(e){if(e.length===0)return 0;let t=0;for(let r=e.length-1;r>=0&&t<3;r-=1){if((e[r]&192)!==128){let n=e.length-r,i=e[r],s=(i&128)===0?1:(i&224)===192?2:(i&240)===224?3:(i&248)===240?4:1;return n0?e.length-t:e.length}var ASe=class tW extends Ru{constructor(r,n,i,s=!1){super();y(this,"_streamId");y(this,"_binding");y(this,"_responded",!1);y(this,"_endQueued",!1);y(this,"_pendingSyntheticErrorSuppressions",0);y(this,"_requestHeaders");y(this,"_isPushStream");y(this,"session");y(this,"rstCode",0);y(this,"readable",!0);y(this,"writable",!0);y(this,"destroyed",!1);y(this,"_readableState");y(this,"_writableState");this._streamId=r,this._binding=new KY(r),this.session=n,this._requestHeaders=i,this._isPushStream=s,this._readableState={flowing:null,ended:!1,highWaterMark:16*1024},this._writableState={ended:i?.[":method"]==="HEAD"}}_closeWithCode(r){this.rstCode=r,_networkHttp2StreamCloseRaw?.applySync(void 0,[this._streamId,r])}_markSyntheticClose(){this.destroyed=!0,this.readable=!1,this.writable=!1}_shouldSuppressHostError(){return this._pendingSyntheticErrorSuppressions<=0?!1:(this._pendingSyntheticErrorSuppressions-=1,!0)}_emitNghttp2Error(r){let n=new jY(zY(r));this._pendingSyntheticErrorSuppressions+=1,this._markSyntheticClose(),this.emit("error",n),this._closeWithCode(Qo.NGHTTP2_INTERNAL_ERROR)}_emitInternalStreamError(){let r=bo("ERR_HTTP2_STREAM_ERROR","Stream closed with error code NGHTTP2_INTERNAL_ERROR");this._pendingSyntheticErrorSuppressions+=1,this._markSyntheticClose(),this.emit("error",r),this._closeWithCode(Qo.NGHTTP2_INTERNAL_ERROR)}_submitResponse(r){this._responded=!0;let n=this._binding.respond(r);return typeof n=="number"&&n!==0?(this._emitNghttp2Error(n),!1):!0}respond(r){if(this.destroyed)throw bo("ERR_HTTP2_INVALID_STREAM","The stream has been destroyed");if(this._responded)throw bo("ERR_HTTP2_HEADERS_SENT","Response has already been initiated.");this._submitResponse(r)}pushStream(r,n,i){if(this._isPushStream)throw bo("ERR_HTTP2_NESTED_PUSH","A push stream cannot initiate another push stream.");let s=typeof n=="function"?n:i;if(typeof s!="function")throw Pl("callback","function",s);if(typeof _networkHttp2StreamPushStreamRaw>"u")throw new Error("http2 server stream push bridge is not available");let o=n&&typeof n=="object"&&!Array.isArray(n)?n:{},a=_networkHttp2StreamPushStreamRaw.applySync(void 0,[this._streamId,j2($Y(r)),JSON.stringify(o??{})]),A=JSON.parse(a);if(A.error){s(yB(A.error));return}let f=new tW(Number(A.streamId),this.session,NA(A.headers),!0);In.set(Number(A.streamId),f),s(null,f,NA(A.headers))}write(r){if(this._writableState.ended)return queueMicrotask(()=>{this.emit("error",bo("ERR_STREAM_WRITE_AFTER_END","write after end"))}),!1;if(typeof _networkHttp2StreamWriteRaw>"u")throw new Error("http2 server stream write bridge is not available");let n=Buffer.isBuffer(r)?r:Buffer.from(r);return _networkHttp2StreamWriteRaw.applySync(void 0,[this._streamId,n.toString("base64")])}end(r){if(!this._responded&&!this._submitResponse({":status":200})||this._endQueued)return;if(typeof _networkHttp2StreamEndRaw>"u")throw new Error("http2 server stream end bridge is not available");this._writableState.ended=!0;let n=null;r!==void 0&&(n=(Buffer.isBuffer(r)?r:Buffer.from(r)).toString("base64")),this._endQueued=!0,queueMicrotask(()=>{!this._endQueued||this.destroyed||(this._endQueued=!1,_networkHttp2StreamEndRaw.applySync(void 0,[this._streamId,n]))})}pause(){return this._readableState.flowing=!1,_networkHttp2StreamPauseRaw?.applySync(void 0,[this._streamId]),this}resume(){return this._readableState.flowing=!0,_networkHttp2StreamResumeRaw?.applySync(void 0,[this._streamId]),this}respondWithFile(r,n,i){if(this.destroyed)throw bo("ERR_HTTP2_INVALID_STREAM","The stream has been destroyed");if(this._responded)throw bo("ERR_HTTP2_HEADERS_SENT","Response has already been initiated.");let s=$we(i),o={...n??{}},a=o[":status"];if(a===204||a===205||a===304)throw Wwe(Number(a));try{let A=Jt.stat.applySyncPromise(void 0,[r]),f=Jt.readFileBinary.applySyncPromise(void 0,[r]),l=Zwe(Ta(A)),p={offset:s.offset,length:s.length??Math.max(0,l.size-s.offset)};s.statCheck?.(l,o,p);let I=Buffer.from(f,"base64"),S=eSe(I,s.offset,s.length);if(o["content-length"]===void 0&&(o["content-length"]=S.byteLength),!this._submitResponse({":status":200,...o}))return;this.end(S);return}catch{}if(typeof _networkHttp2StreamRespondWithFileRaw>"u")throw new Error("http2 server stream respondWithFile bridge is not available");this._responded=!0,_networkHttp2StreamRespondWithFileRaw.applySync(void 0,[this._streamId,r,JSON.stringify(n??{}),JSON.stringify(i??{})])}respondWithFD(r,n,i){let s=typeof r=="number"?r:typeof r?.fd=="number"?r.fd:NaN,o=Number.isFinite(s)?FA.applySync(void 0,[s]):null;if(!o){this._emitInternalStreamError();return}this.respondWithFile(o,n,i)}destroy(r){return this.destroyed?this:(this.destroyed=!0,r&&this.emit("error",r),this._closeWithCode(Qo.NGHTTP2_CANCEL),this)}_emitData(r){r&&this.emit("data",Buffer.from(r,"base64"))}_emitEnd(){this._readableState.ended=!0,this.emit("end")}_emitDrain(){this.emit("drain")}_emitClose(r){typeof r=="number"&&(this.rstCode=r),this.destroyed=!0,this.emit("close")}},rW=class extends Ru{constructor(t,r,n){super();y(this,"headers");y(this,"method");y(this,"url");y(this,"connection");y(this,"socket");y(this,"stream");y(this,"destroyed",!1);y(this,"readable",!0);y(this,"_readableState",{flowing:null,length:0,ended:!1,objectMode:!1});this.headers=t,this.method=typeof t[":method"]=="string"?String(t[":method"]):"GET",this.url=typeof t[":path"]=="string"?String(t[":path"]):"/",this.connection=r,this.socket=r,this.stream=n}on(t,r){return super.on(t,r),t==="data"&&this._readableState.flowing!==!1&&this.resume(),this}once(t,r){return super.once(t,r),t==="data"&&this._readableState.flowing!==!1&&this.resume(),this}resume(){return this._readableState.flowing=!0,this.stream.resume(),this}pause(){return this._readableState.flowing=!1,this.stream.pause(),this}pipe(t){return this.on("data",r=>{t.write(r)===!1&&typeof t.once=="function"&&(this.pause(),t.once("drain",()=>this.resume()))}),this.on("end",()=>t.end()),this.resume(),t}unpipe(){return this}read(){return null}isPaused(){return this._readableState.flowing===!1}setEncoding(){return this}_emitData(t){this._readableState.length+=t.byteLength,this.emit("data",t)}_emitEnd(){this._readableState.ended=!0,this.emit("end"),this.emit("close")}_emitError(t){this.emit("error",t)}destroy(t){return this.destroyed=!0,t&&this.emit("error",t),this.emit("close"),this}},nW=class extends Ru{constructor(t){super();y(this,"_stream");y(this,"_headers",{});y(this,"_statusCode",200);y(this,"headersSent",!1);y(this,"writable",!0);y(this,"writableEnded",!1);y(this,"writableFinished",!1);y(this,"socket");y(this,"connection");y(this,"stream");y(this,"_writableState",{ended:!1,finished:!1,objectMode:!1,corked:0,length:0});this._stream=t,this.stream=t,this.socket=t.session.socket,this.connection=this.socket}writeHead(t,r){return this._statusCode=t,this._headers={...this._headers,...r??{},":status":t},this._stream.respond(this._headers),this.headersSent=!0,this}setHeader(t,r){return this._headers[t]=r,this}getHeader(t){return this._headers[t]}hasHeader(t){return Object.prototype.hasOwnProperty.call(this._headers,t)}removeHeader(t){delete this._headers[t]}write(t,r,n){":status"in this._headers||(this._headers[":status"]=this._statusCode,this._stream.respond(this._headers),this.headersSent=!0);let i=this._stream.write(typeof t=="string"&&typeof r=="string"?Buffer.from(t,r):t);return(typeof r=="function"?r:n)?.(),i}end(t){return":status"in this._headers||(this._headers[":status"]=this._statusCode,this._stream.respond(this._headers),this.headersSent=!0),this.writableEnded=!0,this._writableState.ended=!0,this._stream.end(t),queueMicrotask(()=>{this.writable=!1,this.writableFinished=!0,this._writableState.finished=!0,this.emit("finish"),this.emit("close")}),this}destroy(t){return t&&this.emit("error",t),this.writable=!1,this.writableEnded=!0,this.writableFinished=!0,this.emit("close"),this}},iW=class extends Ru{constructor(t,r){super();y(this,"encrypted",!1);y(this,"alpnProtocol",!1);y(this,"originSet");y(this,"localSettings",Wi(H1));y(this,"remoteSettings",Wi(H1));y(this,"pendingSettingsAck",!1);y(this,"socket");y(this,"state",sG(XY));y(this,"_sessionId");y(this,"_waitStarted",!1);y(this,"_pendingSettingsAckCount",0);y(this,"_awaitingInitialSettingsAck",!1);y(this,"_settingsCallbacks",[]);this._sessionId=t,this.socket=new O1(r,()=>{setTimeout(()=>{this.destroy()},0)}),this[Owe]=this.socket}_retain(){this._waitStarted||typeof _networkHttp2SessionWaitRaw>"u"||(this._waitStarted=!0,_networkHttp2SessionWaitRaw.apply(void 0,[this._sessionId],{result:{promise:!0}}).catch(t=>{this.emit("error",t instanceof Error?t:new Error(String(t)))}))}_release(){this._waitStarted=!1}_beginInitialSettingsAck(){this._awaitingInitialSettingsAck=!0,this._pendingSettingsAckCount+=1,this.pendingSettingsAck=!0}_applyLocalSettings(t){this.localSettings=Wi(t),this._awaitingInitialSettingsAck&&(this._awaitingInitialSettingsAck=!1,this._pendingSettingsAckCount=Math.max(0,this._pendingSettingsAckCount-1),this.pendingSettingsAck=this._pendingSettingsAckCount>0),this.emit("localSettings",this.localSettings)}_applyRemoteSettings(t){this.remoteSettings=Wi(t),this.emit("remoteSettings",this.remoteSettings)}_applyRuntimeState(t){this.state=sG(t)}_ackSettings(){this._pendingSettingsAckCount=Math.max(0,this._pendingSettingsAckCount-1),this.pendingSettingsAck=this._pendingSettingsAckCount>0,this._settingsCallbacks.shift()?.()}request(t,r){if(typeof _networkHttp2SessionRequestRaw>"u")throw new Error("http2 session request bridge is not available");rSe(r);let n=_networkHttp2SessionRequestRaw.applySync(void 0,[this._sessionId,j2($Y(t)),JSON.stringify(r??{})]),i=new eW(n,this);return In.set(n,i),i}settings(t,r){if(r!==void 0&&typeof r!="function")throw Pl("callback","function",r);if(typeof _networkHttp2SessionSettingsRaw>"u")throw new Error("http2 session settings bridge is not available");let n=ZY(t);_networkHttp2SessionSettingsRaw.applySync(void 0,[this._sessionId,JSON.stringify(n)]),this._pendingSettingsAckCount+=1,this.pendingSettingsAck=!0,r&&this._settingsCallbacks.push(r)}setLocalWindowSize(t){if(typeof t!="number"||Number.isNaN(t))throw Pl("windowSize","number",t);if(!Number.isInteger(t)||t<0||t>2147483647){let n=new RangeError(`The value of "windowSize" is out of range. It must be >= 0 && <= 2147483647. Received ${t}`);throw n.code="ERR_OUT_OF_RANGE",n}if(typeof _networkHttp2SessionSetLocalWindowSizeRaw>"u")throw new Error("http2 session setLocalWindowSize bridge is not available");let r=_networkHttp2SessionSetLocalWindowSizeRaw.applySync(void 0,[this._sessionId,t]);this._applyRuntimeState(Dg(r)?.state)}goaway(t=0,r=0,n){let i=n===void 0?null:Buffer.isBuffer(n)?n.toString("base64"):Buffer.from(n).toString("base64");_networkHttp2SessionGoawayRaw?.applySync(void 0,[this._sessionId,t,r,i])}close(){let t=Array.from(In.entries()).filter(([,r])=>typeof r._belongsTo=="function"&&r._belongsTo(this)&&!r._hasReceivedResponse());if(t.length>0){let r=bo("ERR_HTTP2_GOAWAY_SESSION","The HTTP/2 session is closing before the stream could be established.");if(queueMicrotask(()=>{for(let[n,i]of t)In.get(n)===i&&(i.emit("error",r),i.emit("close"),In.delete(n))}),typeof _networkHttp2SessionDestroyRaw<"u"){_networkHttp2SessionDestroyRaw.applySync(void 0,[this._sessionId]);return}}_networkHttp2SessionCloseRaw?.applySync(void 0,[this._sessionId]),setTimeout(()=>{qn.has(this._sessionId)&&(this._release(),this.emit("close"),qn.delete(this._sessionId),_unregisterHandle?.(`http2:session:${this._sessionId}`))},50)}destroy(){if(typeof _networkHttp2SessionDestroyRaw<"u"){_networkHttp2SessionDestroyRaw.applySync(void 0,[this._sessionId]);return}this.close()}},fSe=class extends Ru{constructor(t,r,n){super();y(this,"allowHalfOpen");y(this,"allowHTTP1");y(this,"encrypted");y(this,"_serverId");y(this,"listening",!1);y(this,"_address",null);y(this,"_options");y(this,"_timeoutMs",0);y(this,"_waitStarted",!1);this.allowHalfOpen=t?.allowHalfOpen===!0,this.allowHTTP1=t?.allowHTTP1===!0,this.encrypted=n;let i=t?.settings&&typeof t.settings=="object"&&!Array.isArray(t.settings)?Wi(t.settings):{};this._options={...t??{},settings:i},this._serverId=Hwe++,this[iG]={settings:Wi(i),unknownProtocolTimeout:1e4,...n?{ALPNProtocols:["h2"]}:{}},r&&this.on("request",r),Io.set(this._serverId,this)}address(){return this._address}_retain(){this._waitStarted||typeof _networkHttp2ServerWaitRaw>"u"||(this._waitStarted=!0,_networkHttp2ServerWaitRaw.apply(void 0,[this._serverId],{result:{promise:!0}}).catch(t=>{this.emit("error",t instanceof Error?t:new Error(String(t)))}))}_release(){this._waitStarted=!1}setTimeout(t,r){return this._timeoutMs=GY(t),r&&this.on("timeout",r),this}updateSettings(t){let r=ZY(t),n={...Wi(this._options.settings),...Wi(r)};this._options={...this._options,settings:n};let i=this[iG];return i.settings=Wi(n),this}listen(t,r,n,i){if(typeof _networkHttp2ServerListenRaw>"u")throw new Error(`http2.${this.encrypted?"createSecureServer":"createServer"} is not supported in sandbox`);let s=HY(t,r,n,i);s.callback&&this.once("listening",s.callback);let o={serverId:this._serverId,secure:this.encrypted,port:s.port,host:s.host,backlog:s.backlog,allowHalfOpen:this.allowHalfOpen,allowHTTP1:this._options.allowHTTP1===!0,timeout:this._timeoutMs,settings:this._options.settings,remoteCustomSettings:this._options.remoteCustomSettings,tls:this.encrypted?Gl({...this._options,...t&&typeof t=="object"?t:{}},{isServer:!0}):void 0},a=JSON.parse(_networkHttp2ServerListenRaw.applySyncPromise(void 0,[JSON.stringify(o)]));return this._address=a.address??null,this.listening=!0,this._retain(),_registerHandle?.(`http2:server:${this._serverId}`,"http2 server"),this.emit("listening"),this}close(t){return t&&this.once("close",t),this.listening?(_networkHttp2ServerCloseRaw?.apply(void 0,[this._serverId],{result:{promise:!0}}),setTimeout(()=>{this.listening&&(this.listening=!1,this._release(),this.emit("close"),Io.delete(this._serverId),_unregisterHandle?.(`http2:server:${this._serverId}`))},50),this):(this._release(),queueMicrotask(()=>this.emit("close")),this)}};function aG(e,t,r){let n=typeof t=="function"?t:r,i=t&&typeof t=="object"&&!Array.isArray(t)?t:void 0;return new fSe(i,n,e)}function uSe(e,t,r){if(typeof _networkHttp2SessionConnectRaw>"u")throw new Error("http2.connect is not supported in sandbox");let{authority:n,options:i,listener:s}=sSe(e,t,r);if(n.protocol!=="http:"&&n.protocol!=="https:")throw bo("ERR_HTTP2_UNSUPPORTED_PROTOCOL",`protocol "${n.protocol}" is unsupported.`);nSe(i);let o=i.createConnection?oSe(i.createConnection()):void 0,a=i.port??n.port,A=a===""||a===void 0||a===null?void 0:Number(a),f=JSON.parse(_networkHttp2SessionConnectRaw.applySyncPromise(void 0,[JSON.stringify({authority:n.toString(),protocol:n.protocol,host:i.host??i.hostname??n.hostname,port:A,localAddress:i.localAddress,family:i.family,socketId:o,settings:i.settings,remoteCustomSettings:i.remoteCustomSettings,tls:n.protocol==="https:"?Gl(i,{servername:typeof i.servername=="string"?i.servername:n.hostname}):void 0})])),l=Dg(f.state),p=new iW(f.sessionId,l?.socket??void 0);return z2(p,l),p._beginInitialSettingsAck(),p._retain(),s&&p.once("connect",()=>s(p)),qn.set(f.sessionId,p),_registerHandle?.(`http2:session:${f.sessionId}`,"http2 session"),n.protocol==="https:"&&p.socket.once("secureConnect",()=>{}),p}function AG(e,t){let r=qn.get(e);return r||(r=new iW(e,t?.socket??void 0),qn.set(e,r)),z2(r,t),r}function Bl(e,t){let r=EB.get(e)??[];r.push(t),EB.set(e,r)}function ru(e){if(Jv.has(e))return;Jv.add(e);let t=()=>{Jv.delete(e),cSe(e)},r=globalThis.setImmediate;if(typeof r=="function"){r(t);return}setTimeout(t,0)}function cSe(e){let t=In.get(e);if(!t||typeof t._emitResponseHeaders!="function")return;let r=EB.get(e);if(!(!r||r.length===0)){EB.delete(e);for(let n of r){if(n.kind==="push"){t._emitPush(NA(n.data),n.extraNumber);continue}if(n.kind==="responseHeaders"){t._emitResponseHeaders(NA(n.data));continue}if(n.kind==="data"){t._emitDataChunk(n.data);continue}if(n.kind==="end"){t._emitEnd();continue}if(n.kind==="error"){t.emit("error",yB(n.data));continue}typeof t._emitClose=="function"?t._emitClose(n.extraNumber):t.emit("close"),In.delete(e)}}}function sW(e,t,r,n,i,s,o){if(e==="sessionConnect"){let a=qn.get(t);if(!a)return;let A=Dg(r);z2(a,A),a.encrypted&&a.socket.emit("secureConnect"),a.emit("connect");return}if(e==="sessionClose"){let a=qn.get(t);if(!a)return;a._release(),a.emit("close"),qn.delete(t),_unregisterHandle?.(`http2:session:${t}`);return}if(e==="sessionError"){let a=qn.get(t);if(!a)return;a.emit("error",yB(r));return}if(e==="sessionLocalSettings"){let a=qn.get(t);if(!a)return;a._applyLocalSettings(NA(r));return}if(e==="sessionRemoteSettings"){let a=qn.get(t);if(!a)return;a._applyRemoteSettings(NA(r));return}if(e==="sessionSettingsAck"){let a=qn.get(t);if(!a)return;a._ackSettings();return}if(e==="sessionGoaway"){let a=qn.get(t);if(!a)return;a.emit("goaway",Number(i??0),Number(o??0),r?Buffer.from(r,"base64"):Buffer.alloc(0));return}if(e==="clientPushStream"){let a=qn.get(t);if(!a)return;let A=Number(r),f=new eW(A,a,!0);In.set(A,f),a.emit("stream",f,NA(s),Number(o??0)),ru(A);return}if(e==="clientPushHeaders"){Bl(t,{kind:"push",data:r,extraNumber:Number(i??0)}),ru(t);return}if(e==="clientResponseHeaders"){Bl(t,{kind:"responseHeaders",data:r}),ru(t);return}if(e==="clientData"){Bl(t,{kind:"data",data:r}),ru(t);return}if(e==="clientEnd"){Bl(t,{kind:"end"}),ru(t);return}if(e==="clientClose"){Bl(t,{kind:"close",extraNumber:Number(i??0)}),ru(t);return}if(e==="clientError"){Bl(t,{kind:"error",data:r}),ru(t);return}if(e==="serverStream"){let a=Io.get(t);if(!a)return;let A=Dg(n),f=Number(i),l=AG(f,A),p=Number(r),I=NA(s),S=Number(o??0),_=new ASe(p,l,I);if(In.set(p,_),a.emit("stream",_,I,S),a.listenerCount("request")>0){let N=new rW(I,l.socket,_),O=new nW(_);_.on("data",x=>{N._emitData(x)}),_.on("end",()=>{N._emitEnd()}),_.on("error",x=>{N._emitError(x)}),_.on("drain",()=>{O.emit("drain")}),a.emit("request",N,O)}return}if(e==="serverStreamData"){let a=In.get(t);if(!a||typeof a._emitData!="function")return;a._emitData(r);return}if(e==="serverStreamEnd"){let a=In.get(t);if(!a||typeof a._emitEnd!="function")return;a._emitEnd();return}if(e==="serverStreamDrain"){let a=In.get(t);if(!a||typeof a._emitDrain!="function")return;a._emitDrain();return}if(e==="serverStreamError"){let a=In.get(t);if(!a||typeof a._shouldSuppressHostError=="function"&&a._shouldSuppressHostError())return;a.emit("error",yB(r));return}if(e==="serverStreamClose"){let a=In.get(t);if(!a||typeof a._emitClose!="function")return;a._emitClose(Number(i??0)),In.delete(t);return}if(e==="serverSession"){let a=Io.get(t);if(!a)return;let A=Number(i),f=AG(A,Dg(r));a.emit("session",f);return}if(e==="serverTimeout"){Io.get(t)?.emit("timeout");return}if(e==="serverConnection"){Io.get(t)?.emit("connection",new O1(oG(r)??void 0));return}if(e==="serverSecureConnection"){Io.get(t)?.emit("secureConnection",new O1(oG(r)??void 0));return}if(e==="serverClose"){let a=Io.get(t);if(!a)return;a.listening=!1,a._release(),a.emit("close"),Io.delete(t),_unregisterHandle?.(`http2:server:${t}`);return}e==="serverCompatRequest"&&(P1.set(Number(i),{serverId:t,requestJson:r??"{}"}),GSe(t,Number(i)))}function lSe(){if(jv)return;jv=!0,queueMicrotask(()=>{for(jv=!1;L1.length>0;){let t=L1.shift();t&&sW(t.kind,t.id,t.data,t.extra,t.extraNumber,t.extraHeaders,t.flags)}})}function hSe(e,t){if(!t||typeof t!="object")return;let r=t;if(typeof r.kind!="string"||typeof r.id!="number")return;process.env.SECURE_EXEC_DEBUG_HTTP2_BRIDGE==="1"&&console.error("[secure-exec http2 isolate dispatch]",r.kind,r.id);let n=r.kind,i=r.id,s=typeof r.data=="string"?r.data:void 0,o=typeof r.extra=="string"?r.extra:void 0,a=typeof r.extraNumber=="string"||typeof r.extraNumber=="number"?r.extraNumber:void 0,A=typeof r.extraHeaders=="string"?r.extraHeaders:void 0,f=typeof r.flags=="string"||typeof r.flags=="number"?r.flags:void 0;L1.push({kind:n,id:i,data:s,extra:o,extraNumber:a,extraHeaders:A,flags:f}),lSe()}var K2={Http2ServerRequest:rW,Http2ServerResponse:nW,Http2Stream:KY,NghttpError:jY,nghttp2ErrorString:zY,constants:{HTTP2_HEADER_METHOD:":method",HTTP2_HEADER_PATH:":path",HTTP2_HEADER_SCHEME:":scheme",HTTP2_HEADER_AUTHORITY:":authority",HTTP2_HEADER_STATUS:":status",HTTP2_HEADER_CONTENT_TYPE:"content-type",HTTP2_HEADER_CONTENT_LENGTH:"content-length",HTTP2_HEADER_LAST_MODIFIED:"last-modified",HTTP2_HEADER_ACCEPT:"accept",HTTP2_HEADER_ACCEPT_ENCODING:"accept-encoding",HTTP2_METHOD_GET:"GET",HTTP2_METHOD_POST:"POST",HTTP2_METHOD_PUT:"PUT",HTTP2_METHOD_DELETE:"DELETE",...Qo,DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE:65535},getDefaultSettings(){return Wi(H1)},connect:uSe,createServer:aG.bind(void 0,!1),createSecureServer:aG.bind(void 0,!0)};function dSe(e,t,r){let n={},i=r;if(typeof t=="function")i=t;else if(typeof t=="number")n={family:t};else if(t==null)n={};else if(typeof t=="object")n={...t};else throw new TypeError("dns.lookup options must be a number, object, or callback");let s=n.family===4||n.family===6?n.family:void 0;return{callback:i,options:{hostname:String(e),family:s,all:n.all===!0}}}function $m(e){let t=new Error(`${e} is not supported by the secure-exec dns polyfill`);return t.code="ERR_NOT_IMPLEMENTED",t}function gSe(e,t,r,n){let i=r,s=n;typeof r=="function"&&(s=r,i=void 0);let o=String(i??"A").toUpperCase();if(!["A","AAAA","MX","TXT","SRV","CNAME","PTR","NS","SOA","NAPTR","CAA","ANY"].includes(o))throw $m(`${e}(${o})`);return{callback:s,options:{hostname:String(t),rrtype:o}}}function pSe(e){let t=e;return typeof t=="string"&&(t=JSON.parse(t)),t&&typeof t=="object"&&Array.isArray(t.records)?t=t.records:t&&typeof t=="object"&&typeof t.address=="string"&&(t=[t]),Array.isArray(t)?t.filter(r=>r&&typeof r.address=="string").map(r=>({address:r.address,family:r.family===6?6:4})):[]}function ESe(e){let t=e;return typeof t=="string"&&(t=JSON.parse(t)),t}function fG(e){let t=new TypeError(`${e} expects an array of non-empty server strings`);return t.code="ERR_INVALID_ARG_TYPE",t}function oW(e,t){if(!Array.isArray(t))throw fG(e);return t.map(r=>{if(typeof r!="string"||r.length===0)throw fG(e);return r})}function mB(e,t,r){let n=dSe(e,t,r);return _networkDnsLookupRaw.apply(void 0,[n.options],{result:{promise:!0}}).then(i=>{let s=pSe(i);if(typeof n.callback=="function")if(n.options.all)n.callback(null,s);else{let o=s[0]??{address:null,family:n.options.family??0};n.callback(null,o.address,o.family)}return n.options.all?s:s[0]??{address:"",family:n.options.family??0}})}function ke(e,t,r,n){let i=gSe(e,t,r,n);return _networkDnsResolveRaw.apply(void 0,[i.options],{result:{promise:!0}}).then(s=>{let o=ESe(s);return typeof i.callback=="function"&&queueMicrotask(()=>i.callback(null,o)),o}).catch(s=>{throw typeof i.callback=="function"&&queueMicrotask(()=>i.callback(s)),s})}var ySe=class{constructor(){this._servers=[]}cancel(){}getServers(){return this._servers.slice()}lookup(e,t,r){return mB(e,t,r)}resolve(e,t,r){return ke("dns.resolve",e,t,r)}resolve4(e,t){return ke("dns.resolve4",e,"A",t)}resolve6(e,t){return ke("dns.resolve6",e,"AAAA",t)}resolveAny(e,t){return ke("dns.resolveAny",e,"ANY",t)}resolveMx(e,t){return ke("dns.resolveMx",e,"MX",t)}resolveTxt(e,t){return ke("dns.resolveTxt",e,"TXT",t)}resolveSrv(e,t){return ke("dns.resolveSrv",e,"SRV",t)}resolveCname(e,t){return ke("dns.resolveCname",e,"CNAME",t)}resolvePtr(e,t){return ke("dns.resolvePtr",e,"PTR",t)}resolveNs(e,t){return ke("dns.resolveNs",e,"NS",t)}resolveSoa(e,t){return ke("dns.resolveSoa",e,"SOA",t)}resolveNaptr(e,t){return ke("dns.resolveNaptr",e,"NAPTR",t)}resolveCaa(e,t){return ke("dns.resolveCaa",e,"CAA",t)}setServers(e){this._servers=oW("dns.Resolver.setServers",e)}},mSe=class{constructor(){this._servers=[]}cancel(){}getServers(){return this._servers.slice()}lookup(e,t){return mB(e,t)}resolve(e,t){return ke("dns.resolve",e,t)}resolve4(e){return ke("dns.resolve4",e,"A")}resolve6(e){return ke("dns.resolve6",e,"AAAA")}resolveAny(e){return ke("dns.resolveAny",e,"ANY")}resolveMx(e){return ke("dns.resolveMx",e,"MX")}resolveTxt(e){return ke("dns.resolveTxt",e,"TXT")}resolveSrv(e){return ke("dns.resolveSrv",e,"SRV")}resolveCname(e){return ke("dns.resolveCname",e,"CNAME")}resolvePtr(e){return ke("dns.resolvePtr",e,"PTR")}resolveNs(e){return ke("dns.resolveNs",e,"NS")}resolveSoa(e){return ke("dns.resolveSoa",e,"SOA")}resolveNaptr(e){return ke("dns.resolveNaptr",e,"NAPTR")}resolveCaa(e){return ke("dns.resolveCaa",e,"CAA")}setServers(e){this._servers=oW("dns.promises.Resolver.setServers",e)}},X2={lookup(e,t,r){mB(e,t,r).catch(n=>{(typeof t=="function"?t:r)?.(n)})},resolve(e,t,r){ke("dns.resolve",e,t,r).catch(()=>{})},resolve4(e,t){ke("dns.resolve4",e,"A",t).catch(()=>{})},resolve6(e,t){ke("dns.resolve6",e,"AAAA",t).catch(()=>{})},resolveAny(e,t){ke("dns.resolveAny",e,"ANY",t).catch(()=>{})},resolveMx(e,t){ke("dns.resolveMx",e,"MX",t).catch(()=>{})},resolveTxt(e,t){ke("dns.resolveTxt",e,"TXT",t).catch(()=>{})},resolveSrv(e,t){ke("dns.resolveSrv",e,"SRV",t).catch(()=>{})},resolveCname(e,t){ke("dns.resolveCname",e,"CNAME",t).catch(()=>{})},resolvePtr(e,t){ke("dns.resolvePtr",e,"PTR",t).catch(()=>{})},resolveNs(e,t){ke("dns.resolveNs",e,"NS",t).catch(()=>{})},resolveSoa(e,t){ke("dns.resolveSoa",e,"SOA",t).catch(()=>{})},resolveNaptr(e,t){ke("dns.resolveNaptr",e,"NAPTR",t).catch(()=>{})},resolveCaa(e,t){ke("dns.resolveCaa",e,"CAA",t).catch(()=>{})},promises:{Resolver:mSe,lookup(e,t){return mB(e,t)},resolve(e,t){return ke("dns.resolve",e,t||"A")},resolve4(e){return ke("dns.resolve4",e,"A")},resolve6(e){return ke("dns.resolve6",e,"AAAA")},resolveAny(e){return ke("dns.resolveAny",e,"ANY")},resolveMx(e){return ke("dns.resolveMx",e,"MX")},resolveTxt(e){return ke("dns.resolveTxt",e,"TXT")},resolveSrv(e){return ke("dns.resolveSrv",e,"SRV")},resolveCname(e){return ke("dns.resolveCname",e,"CNAME")},resolvePtr(e){return ke("dns.resolvePtr",e,"PTR")},resolveNs(e){return ke("dns.resolveNs",e,"NS")},resolveSoa(e){return ke("dns.resolveSoa",e,"SOA")},resolveNaptr(e){return ke("dns.resolveNaptr",e,"NAPTR")},resolveCaa(e){return ke("dns.resolveCaa",e,"CAA")}},Resolver:ySe,getServers(){return[]},lookupService(){throw $m("dns.lookupService")},reverse(){throw $m("dns.reverse")},setServers(){throw $m("dns.setServers")}};et("_http2Module",K2);function q1(e){return{__secureExecTlsContext:Gl(e),context:{}}}function BSe(e,t){if(!(e instanceof Do))throw new TypeError("tls.TLSSocket requires a net.Socket instance");let r=t&&typeof t=="object"?{...t}:{};Object.setPrototypeOf(e,aW.prototype);let n=Gl(r,{isServer:r.isServer===!0,servername:r.servername??e.servername??e.remoteAddress??"127.0.0.1"});return n.isServer||(e.servername=n.servername),e._connected?e._upgradeTls(n):e.once("connect",()=>{e._upgradeTls(n)}),e}var aW=class extends Do{constructor(e,t){if(e instanceof Do)return super({allowHalfOpen:e.allowHalfOpen===!0}),BSe(e,t);super(e&&typeof e=="object"?e:t)}};function AW(...e){let t,r,n=[...e],i=typeof n[n.length-1]=="function"?n.pop():void 0;if(n[0]!=null&&typeof n[0]=="object")r={...n[0]},r.socket?t=r.socket:(t=new Do,t.connect({host:r.host??"127.0.0.1",port:r.port}));else{let o={};n.length>0&&(o.port=n.shift()),typeof n[0]=="string"&&(o.host=n.shift()),r={...n[0]!=null&&typeof n[0]=="object"?{...n[0]}:{},...o},t=new Do,t.connect({host:r.host??"127.0.0.1",port:r.port})}i&&t.once("secureConnect",i);let s=Gl(r,{isServer:!1,servername:r.servername??r.host??"127.0.0.1"});return t.servername=s.servername,t._connected?t._upgradeTls(s):t.once("connect",()=>{t._upgradeTls(s)}),t}function ISe(e,t){if(!e.startsWith("*."))return e===t;let r=e.slice(1);if(!t.endsWith(r))return!1;let n=t.slice(0,-r.length);return n.length>0&&!n.includes(".")}var fW=class{constructor(e,t){y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_server");y(this,"_tlsOptions");y(this,"_sniCallback");y(this,"_alpnCallback");y(this,"_contexts",[]);let r=typeof e=="function"||e===void 0?void 0:e,n=typeof e=="function"?e:t;if(r?.ALPNCallback&&r?.ALPNProtocols){let i=new Error("The ALPNCallback and ALPNProtocols TLS options are mutually exclusive");throw i.code="ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS",i}this._tlsOptions=Gl(r,{isServer:!0}),this._sniCallback=r?.SNICallback,this._alpnCallback=r?.ALPNCallback,this._server=new Pg(r?{allowHalfOpen:r.allowHalfOpen,keepAlive:r.keepAlive,keepAliveInitialDelay:r.keepAliveInitialDelay}:void 0,(i=>{let s=i;s.server=this,this._handleSecureSocket(s)})),n&&this.on("secureConnection",n),this._server.on("listening",(...i)=>this._emit("listening",...i)),this._server.on("close",(...i)=>this._emit("close",...i)),this._server.on("error",(...i)=>this._emit("error",...i)),this._server.on("drop",(...i)=>this._emit("drop",...i))}listen(e,t,r,n){return this._server.listen(e,t,r,n),this}close(e){return e&&this.once("close",e),this._server.close(),this}address(){return this._server.address()}getConnections(e){return this._server.getConnections(e),this}ref(){return this._server.ref(),this}unref(){return this._server.unref(),this}addContext(e,t){let r=N1(t)?t:q1(t&&typeof t=="object"?t:void 0);return this._contexts.push({servername:e,context:r}),this}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this}emit(e,...t){return this._emit(e,...t)}_emit(e,...t){let r=!1,n=this._listeners[e];if(n)for(let s of[...n])s.call(this,...t),r=!0;let i=this._onceListeners[e];if(i){this._onceListeners[e]=[];for(let s of[...i])s.call(this,...t),r=!0}return r}async _handleSecureSocket(e){let t=this._getClientHello(e),r=t?.servername;r&&(e.servername=r);try{let n=await this._resolveTlsOptions(r,t?.ALPNProtocols??[]);if(!n){this._emitTlsClientError(e,"Invalid SNI context");return}e._upgradeTls(n),e.once("secure",()=>{this._emit("secureConnection",e),this._emit("connection",e)}),e.on("error",i=>{this._emit("tlsClientError",i,e)})}catch(n){let i=n instanceof Error?n:new Error(String(n));this._emitTlsClientError(e,i.message,i),i.uncaught&&process.emit?.("uncaughtException",i,"uncaughtException")}}_getClientHello(e){if(typeof _netSocketGetTlsClientHelloRaw>"u")return null;let t=e._socketId;return typeof t!="number"||t===0?null:Rwe(_netSocketGetTlsClientHelloRaw.applySync(void 0,[t]))}async _resolveTlsOptions(e,t){let r=null,n=!1;if(e&&this._sniCallback){if(r=await new Promise((s,o)=>{this._sniCallback?.(e,(a,A)=>{if(a){o(a);return}if(A==null){s(null);return}if(N1(A)){s(A);return}if(A&&typeof A=="object"&&Object.keys(A).length>0){s(q1(A));return}n=!0,s(null)})}),n)return null}else e&&(r=this._findContext(e));let i={...this._tlsOptions,...r?.__secureExecTlsContext??{},isServer:!0};if(this._alpnCallback){let s=this._alpnCallback({servername:e,protocols:t});if(s===void 0){let o=new Error("ALPN callback rejected the client protocol list");throw o.code="ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL",o}if(!t.includes(s)){let o=new Error("The ALPNCallback callback returned an invalid protocol");throw o.code="ERR_TLS_ALPN_CALLBACK_INVALID_RESULT",o.uncaught=!0,o}i.ALPNProtocols=[s]}return i}_findContext(e){for(let t=this._contexts.length-1;t>=0;t-=1){let r=this._contexts[t];if(ISe(r.servername,e))return r.context}return null}_emitTlsClientError(e,t,r){let n=r??new Error(t);e.servername??(e.servername=this._getClientHello(e)?.servername),this._emit("tlsClientError",n,e),e.destroy()}};function bSe(e,t){return new fW(e,t)}var uW={connect:AW,TLSSocket:aW,Server:bSe,createServer(e,t){return new fW(e,t)},createSecureContext(e){return q1(e)},getCiphers(){if(typeof _tlsGetCiphersRaw>"u")throw new Error("tls.getCiphers is not supported in sandbox");try{return JSON.parse(_tlsGetCiphersRaw.applySync(void 0,[]))}catch{return[]}},DEFAULT_MIN_VERSION:"TLSv1.2",DEFAULT_MAX_VERSION:"TLSv1.3"};et("_netModule",JY);function Da(e="socket hang up"){let t=new Error(e);return t.code="ECONNRESET",t}function uG(){let e=new Error("The operation was aborted");return e.name="AbortError",e.code="ABORT_ERR",e}var cu=class{constructor(e){y(this,"headers");y(this,"rawHeaders");y(this,"trailers");y(this,"rawTrailers");y(this,"httpVersion");y(this,"httpVersionMajor");y(this,"httpVersionMinor");y(this,"method");y(this,"url");y(this,"statusCode");y(this,"statusMessage");y(this,"_body");y(this,"_isBinary");y(this,"_listeners");y(this,"complete");y(this,"aborted");y(this,"socket");y(this,"_bodyConsumed");y(this,"_ended");y(this,"_flowing");y(this,"readable");y(this,"readableEnded");y(this,"readableFlowing");y(this,"destroyed");y(this,"_encoding");y(this,"_closeEmitted");let t={};if(Array.isArray(e?.headers)?e.headers.forEach(([i,s])=>{vo(t,i.toLowerCase(),s)}):e?.headers&&Object.entries(e.headers).forEach(([i,s])=>{t[i]=Array.isArray(s)?[...s]:s}),this.rawHeaders=Array.isArray(e?.rawHeaders)?[...e.rawHeaders]:[],this.rawHeaders.length>0){this.headers={};for(let i=0;i{if(Array.isArray(s)){s.forEach(o=>{this.rawHeaders.push(i,o)});return}this.rawHeaders.push(i,s)}),e?.trailers&&typeof e.trailers=="object"?(this.trailers=e.trailers,this.rawTrailers=[],Object.entries(e.trailers).forEach(([i,s])=>{this.rawTrailers.push(i,s)})):(this.trailers={},this.rawTrailers=[]),this.httpVersion="1.1",this.httpVersionMajor=1,this.httpVersionMinor=1,this.method=null,this.url=e?.url||"",this.statusCode=e?.status,this.statusMessage=e?.statusText;let r=this.headers["x-body-encoding"];(e?.bodyEncoding||(Array.isArray(r)?r[0]:r))==="base64"&&e?.body&&typeof Buffer<"u"?(this._body=Buffer.from(e.body,"base64").toString("binary"),this._isBinary=!0):(this._body=e?.body||"",this._isBinary=!1),this._listeners={},this.complete=!1,this.aborted=!1,this.socket=null,this._bodyConsumed=!1,this._ended=!1,this._flowing=!1,this.readable=!0,this.readableEnded=!1,this.readableFlowing=null,this.destroyed=!1,this._closeEmitted=!1}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),e==="data"&&!this._bodyConsumed&&(this._flowing=!0,this.readableFlowing=!0,Promise.resolve().then(()=>{if(!this._bodyConsumed){if(this._bodyConsumed=!0,this._body&&this._body.length>0){let r;typeof Buffer<"u"?r=this._isBinary?Buffer.from(this._body,"binary"):Buffer.from(this._body):r=this._body,this.emit("data",r)}Promise.resolve().then(()=>{this._ended||(this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,this.emit("end"))})}})),e==="end"&&this._bodyConsumed&&!this._ended&&Promise.resolve().then(()=>{this._ended||(this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,t())}),this}once(e,t){let r=(...n)=>{this.off(e,r),t(...n)};return r._originalListener=t,this.on(e,r)}off(e,t){if(this._listeners[e]){let r=this._listeners[e].findIndex(n=>n===t||n._originalListener===t);r!==-1&&this._listeners[e].splice(r,1)}return this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e?delete this._listeners[e]:this._listeners={},this}emit(e,...t){return Vl(this,this._listeners[e],t)}setEncoding(e){return this._encoding=e,this}read(e){if(this._bodyConsumed)return null;this._bodyConsumed=!0;let t;return typeof Buffer<"u"?t=this._isBinary?Buffer.from(this._body,"binary"):Buffer.from(this._body):t=this._body,Promise.resolve().then(()=>{this._ended||(this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,this.emit("end"))}),t}pipe(e){let t;return typeof Buffer<"u"?t=this._isBinary?Buffer.from(this._body||"","binary"):Buffer.from(this._body||""):t=this._body||"",typeof e.write=="function"&&t.length>0&&e.write(t),typeof e.end=="function"&&Promise.resolve().then(()=>e.end()),this._bodyConsumed=!0,this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,e}pause(){return this._flowing=!1,this.readableFlowing=!1,this}resume(){return this._flowing=!0,this.readableFlowing=!0,this._bodyConsumed||Promise.resolve().then(()=>{if(!this._bodyConsumed){if(this._bodyConsumed=!0,this._body){let e;typeof Buffer<"u"?e=this._isBinary?Buffer.from(this._body,"binary"):Buffer.from(this._body):e=this._body,this.emit("data",e)}Promise.resolve().then(()=>{this._ended||(this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,this.emit("end"))})}}),this}unpipe(e){return this}destroy(e){return this.destroyed=!0,this.readable=!1,e&&this.emit("error",e),this._emitClose(),this}_abort(e=Da("aborted")){this.aborted||(this.aborted=!0,this.complete=!1,this.destroyed=!0,this.readable=!1,this.readableEnded=!0,this.emit("aborted"),e&&this.emit("error",e),this._emitClose())}_emitClose(){this._closeEmitted||(this._closeEmitted=!0,this.emit("close"))}[Symbol.asyncIterator](){let e=this,t=!1,r=!1;return{async next(){if(r||e._ended)return{done:!0,value:void 0};if(!t&&!e._bodyConsumed){t=!0,e._bodyConsumed=!0;let n;return typeof Buffer<"u"?n=e._isBinary?Buffer.from(e._body||"","binary"):Buffer.from(e._body||""):n=e._body||"",{done:!1,value:n}}return r=!0,e._ended=!0,e.complete=!0,e.readable=!1,e.readableEnded=!0,{done:!0,value:void 0}},return(){return r=!0,Promise.resolve({done:!0,value:void 0})},throw(n){return r=!0,e.emit("error",n),Promise.resolve({done:!0,value:void 0})}}}},Tg=class{constructor(e,t){y(this,"_options");y(this,"_callback");y(this,"_listeners",{});y(this,"_headers",{});y(this,"_rawHeaderNames",new Map);y(this,"_body","");y(this,"_bodyBytes",0);y(this,"_ended",!1);y(this,"_agent");y(this,"_hostKey");y(this,"_socketEndListener",null);y(this,"_socketCloseListener",null);y(this,"_loopbackAbort");y(this,"_response",null);y(this,"_closeEmitted",!1);y(this,"_abortEmitted",!1);y(this,"_signalAbortHandler");y(this,"_signalPollTimer",null);y(this,"_skipExecute",!1);y(this,"_destroyError");y(this,"_errorEmitted",!1);y(this,"socket");y(this,"finished",!1);y(this,"aborted",!1);y(this,"destroyed",!1);y(this,"path");y(this,"method");y(this,"reusedSocket",!1);y(this,"timeoutCb");let r=RSe(e.method);this._options={...e,method:r,path:DSe(e.path)},this._callback=t,this._validateTimeoutOption(),this._setOutgoingHeaders(e.headers),this._headers.host||this._setHeaderValue("Host",TSe(this._options)),this.path=String(this._options.path||"/"),this.method=String(this._options.method||"GET").toUpperCase();let n=this._options.agent;n===!1?this._agent=null:n instanceof BB?this._agent=n:this._options._agentOSDefaultAgent instanceof BB?this._agent=this._options._agentOSDefaultAgent:this._agent=null,this._hostKey=this._agent?this._agent._getHostKey(this._options):"",this._bindAbortSignal(),typeof this._options.timeout=="number"&&this.setTimeout(this._options.timeout),Promise.resolve().then(()=>this._execute())}_assignSocket(e,t){this.socket=e,this.reusedSocket=t;let r=e;if(r._agentPermanentListenersInstalled||(r._agentPermanentListenersInstalled=!0,e.on("error",()=>{}),e.on("end",()=>{})),this._socketEndListener=()=>{},e.on("end",this._socketEndListener),this._socketCloseListener=()=>{this.destroyed=!0,this._clearTimeout(),this._emitClose()},e.on("close",this._socketCloseListener),this._applyTimeoutToSocket(e),this._emit("socket",e),this.destroyed){this._destroyError&&!this._errorEmitted&&(this._errorEmitted=!0,queueMicrotask(()=>{this._emit("error",this._destroyError)})),e.destroy();return}this._dispatchWithSocket(e)}_handleSocketError(e){this._emit("error",e)}_finalizeSocket(e,t){this._socketEndListener&&(e.off?.("end",this._socketEndListener),e.removeListener?.("end",this._socketEndListener),this._socketEndListener=null),this._socketCloseListener&&(e.off?.("close",this._socketCloseListener),e.removeListener?.("close",this._socketCloseListener),this._socketCloseListener=null),this._agent?this._agent._releaseSocket(this._hostKey,e,this._options,t):e.destroyed||e.destroy()}async _dispatchWithSocket(e){try{let t=NSe(this._options.headers),r=String(this._options.method||"GET").toUpperCase();e instanceof Do||typeof e?._socketId=="string"&&e._socketId.length>0||typeof e?._socketId=="number"&&e._socketId>0||e?._loopbackServer||MSe(r,t)||this._options.socketPath||this._agent?.keepAlive===!0?await this._dispatchRawSocketRequest(e,r,t):await this._dispatchUndiciRequest(e,r)}catch(t){this._clearTimeout(),this._emit("error",t),this._finalizeSocket(e,!1)}}async _dispatchUndiciRequest(e,t){await lG(e,this._options.protocol||"http:");let r=USe(e,this._options),n=this._body?Buffer.from(this._body):Buffer.alloc(0),i=hG(this._headers,this._rawHeaderNames);n.length>0&&!this._headers["content-length"]&&!this._headers["transfer-encoding"]&&i.push(["Content-Length",String(n.length)]);let s=await new Promise((A,f)=>{try{PY.call(r,{path:this._options.path||"/",method:t,headers:xSe(i),body:n.length>0?n:null,signal:this._options.signal,responseHeaders:"raw"},(l,p)=>{if(l){f(l);return}A(p)})}catch(l){f(l)}}),o=await PSe(s?.body);await new Promise(A=>{queueMicrotask(A)}),this.finished=!0,this._clearTimeout();let a=new cu({status:s?.statusCode,statusText:s?.statusText,headers:Array.isArray(s?.headers)?s.headers:[],rawHeaders:Array.isArray(s?.headers)?s.headers:[],trailers:s?.trailers&&typeof s.trailers=="object"?s.trailers:{},body:o.length>0?o.toString("base64"):"",bodyEncoding:"base64",url:this._buildUrl()});this._response=a,a.socket=e,a.once("end",()=>{process.nextTick(()=>{this._finalizeSocket(e,this._agent?.keepAlive===!0&&!this.aborted)})}),this._callback&&this._callback(a),this._emit("response",a),!this._callback&&this._listenerCount("response")===0&&queueMicrotask(()=>{a.resume()})}async _dispatchRawSocketRequest(e,t,r){let n=this._options.protocol||"http:";await lG(e,n);let i=this._body?Buffer.from(this._body):Buffer.alloc(0),s=hG(this._headers,this._rawHeaderNames);i.length>0&&!r["content-length"]&&!r["transfer-encoding"]&&s.push(["Content-Length",String(i.length)]);let o=LSe(t,this._options.path||"/",s,i),a=typeof this._options.timeout=="number"&&this._options.timeout>0?this._options.timeout:3e4,A=HSe(e,t,a);e.write(o);let f=await A;if(this.finished=!0,this._clearTimeout(),f.status===101){let p=new cu({status:f.status,statusText:f.statusText,headers:f.headers,rawHeaders:f.rawHeaders,body:"",bodyEncoding:"base64",url:this._buildUrl()});this._response=p,p.socket=e;let I=f.head??Buffer.alloc(0);if(this._listenerCount("upgrade")===0){e.destroy();return}this._emit("upgrade",p,e,I);return}if(t==="CONNECT"){let p=new cu({status:f.status,statusText:f.statusText,headers:f.headers,rawHeaders:f.rawHeaders,body:"",bodyEncoding:"base64",url:this._buildUrl()});this._response=p,p.socket=e;let I=f.head??Buffer.alloc(0);this._emit("connect",p,e,I);return}let l=new cu({status:f.status,statusText:f.statusText,headers:f.headers,rawHeaders:f.rawHeaders,body:f.body&&f.body.length>0?f.body.toString("base64"):"",bodyEncoding:"base64",url:this._buildUrl()});this._response=l,l.socket=e,l.once("end",()=>{process.nextTick(()=>{this._finalizeSocket(e,this._agent?.keepAlive===!0&&!this.aborted)})}),this._callback&&this._callback(l),this._emit("response",l),!this._callback&&this._listenerCount("response")===0&&queueMicrotask(()=>{l.resume()})}_execute(){if(this._skipExecute)return;if(this._agent){this._agent.addRequest(this,this._options);return}let e=r=>{if(!r){this._handleSocketError(new Error("Failed to create socket")),this._emitClose();return}this._assignSocket(r,!1)},t=this._options.createConnection;if(typeof t=="function"){let r=t(this._options,(n,i)=>{e(i)});e(r);return}e(LB(this._options))}_buildUrl(){let e=this._options,t=e.protocol||(e.port===443?"https:":"http:"),r=e.hostname||e.host||"localhost",n=e.port?":"+e.port:"",i=e.path||"/";return t+"//"+r+n+i}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}addListener(e,t){return this.on(e,t)}once(e,t){let r=(...n)=>{this.off(e,r),t(...n)};return r.listener=t,this.on(e,r)}off(e,t){if(this._listeners[e]){let r=this._listeners[e].findIndex(n=>n===t||n.listener===t);r!==-1&&this._listeners[e].splice(r,1)}return this}removeListener(e,t){return this.off(e,t)}getHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");return this._headers[e.toLowerCase()]}getHeaders(){let e=Object.create(null);for(let[t,r]of Object.entries(this._headers))e[t]=Array.isArray(r)?[...r]:r;return e}getHeaderNames(){return Object.keys(this._headers)}getRawHeaderNames(){return Object.keys(this._headers).map(e=>this._rawHeaderNames.get(e)||e)}hasHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");return Object.prototype.hasOwnProperty.call(this._headers,e.toLowerCase())}removeHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");let t=e.toLowerCase();delete this._headers[t],this._rawHeaderNames.delete(t),this._options.headers={...this._headers}}_emit(e,...t){Vl(this,this._listeners[e],t)}_listenerCount(e){return this._listeners[e]?.length||0}_setOutgoingHeaders(e){if(this._headers={},this._rawHeaderNames=new Map,!e){this._options.headers={};return}if(Array.isArray(e)){for(let t=0;t{r!==void 0&&this._setHeaderValue(t,r)})}_setHeaderValue(e,t){let r=Gi(e).toLowerCase();Yi(r,t),this._headers[r]=Array.isArray(t)?t.map(n=>String(n)):String(t),this._rawHeaderNames.has(r)||this._rawHeaderNames.set(r,e),this._options.headers={...this._headers}}write(e){let t=typeof Buffer<"u"?Buffer.byteLength(e):e.length;if(this._bodyBytes+t>Ol)throw new Error("ERR_HTTP_BODY_TOO_LARGE: request body exceeds "+Ol+" byte limit");return this._body+=e,this._bodyBytes+=t,!0}end(e){return e&&this.write(e),this._ended=!0,this}abort(){this.aborted||(this.aborted=!0,this._abortEmitted||(this._abortEmitted=!0,queueMicrotask(()=>{this._emit("abort")})),this._loopbackAbort?.(),this.destroy())}destroy(e){if(this.destroyed)return this;this.destroyed=!0,this._clearTimeout(),this._unbindAbortSignal(),this._loopbackAbort?.(),this._loopbackAbort=void 0,!this.socket&&e&&e.code==="ABORT_ERR"&&(this._skipExecute=!0);let t=this._response!=null,r=e??(!this.aborted&&!t?Da():void 0);return this._destroyError=r,this._response&&!this._response.complete&&!this._response.aborted&&this._response._abort(r??Da("aborted")),this.socket&&!this.socket.destroyed?(r&&!this._errorEmitted&&(this._errorEmitted=!0,queueMicrotask(()=>{this._emit("error",r)})),this.socket.destroy(r)):(r&&(this._errorEmitted=!0,queueMicrotask(()=>{this._emit("error",r)})),queueMicrotask(()=>{this._emitClose()})),this}setTimeout(e,t){if(t&&this.once("timeout",t),this.timeoutCb=()=>{this._emit("timeout")},this._clearTimeout(),e===0)return this;if(!Number.isFinite(e)||e<0)throw new TypeError(`The "timeout" argument must be of type number. Received ${String(e)}`);return this._options.timeout=e,this.socket&&this._applyTimeoutToSocket(this.socket),this}setNoDelay(){return this}setSocketKeepAlive(){return this}flushHeaders(){}_emitClose(){this._closeEmitted||(this._closeEmitted=!0,this._emit("close"))}_applyTimeoutToSocket(e){let t=this._options.timeout;typeof t!="number"||t===0||(this.timeoutCb||(this.timeoutCb=()=>{this._emit("timeout")}),e.off?.("timeout",this.timeoutCb),e.removeListener?.("timeout",this.timeoutCb),e.setTimeout?.(t,this.timeoutCb))}_validateTimeoutOption(){let e=this._options.timeout;if(e!==void 0&&typeof e!="number"){let t=e===null?"null":typeof e=="string"?`type string ('${e}')`:`type ${typeof e} (${JSON.stringify(e)})`,r=new TypeError(`The "timeout" argument must be of type number. Received ${t}`);throw r.code="ERR_INVALID_ARG_TYPE",r}}_bindAbortSignal(){let e=this._options.signal;if(!e)return;if(this._signalAbortHandler=()=>{this.destroy(uG())},e.aborted){this.destroyed=!0,this._skipExecute=!0,queueMicrotask(()=>{this._emit("error",uG()),this._emitClose()});return}if(typeof e.addEventListener=="function"){e.addEventListener("abort",this._signalAbortHandler,{once:!0});return}let t=e;t.__secureExecPrevOnAbort__=t.onabort??null,t.onabort=(r=>{t.__secureExecPrevOnAbort__?.call(e,r),this._signalAbortHandler?.()}),this._startAbortSignalPoll(e)}_unbindAbortSignal(){let e=this._options.signal;if(!e||!this._signalAbortHandler)return;if(this._signalPollTimer&&(clearTimeout(this._signalPollTimer),this._signalPollTimer=null),typeof e.removeEventListener=="function"){e.removeEventListener("abort",this._signalAbortHandler),this._signalAbortHandler=void 0;return}let t=e;(t.onabort===this._signalAbortHandler||t.__secureExecPrevOnAbort__!==void 0)&&(t.onabort=t.__secureExecPrevOnAbort__??null),delete t.__secureExecPrevOnAbort__,this._signalAbortHandler=void 0}_startAbortSignalPoll(e){let t=()=>{if(this.destroyed){this._signalPollTimer=null;return}if(e.aborted){this._signalPollTimer=null,this._signalAbortHandler?.();return}this._signalPollTimer=setTimeout(t,5)};this._signalPollTimer||(this._signalPollTimer=setTimeout(t,5))}_clearTimeout(){this.socket&&this.timeoutCb&&(this.socket.off?.("timeout",this.timeoutCb),this.socket.removeListener?.("timeout",this.timeoutCb)),this.socket?.setTimeout&&this.socket.setTimeout(0)}};var CSe=class{constructor(e){y(this,"remoteAddress");y(this,"remotePort");y(this,"localAddress","127.0.0.1");y(this,"localPort",0);y(this,"connecting",!1);y(this,"destroyed",!1);y(this,"writable",!0);y(this,"readable",!0);y(this,"readyState","open");y(this,"bytesWritten",0);y(this,"_listeners",{});y(this,"_encoding");y(this,"_peer",null);y(this,"_readableState",{endEmitted:!1,ended:!1});y(this,"_writableState",{finished:!1,errorEmitted:!1});this.remoteAddress=e?.host||"127.0.0.1",this.remotePort=e?.port||80}_attachPeer(e){this._peer=e}setTimeout(e,t){return this}setNoDelay(e){return this}setKeepAlive(e,t){return this}setEncoding(e){return this._encoding=e,this}ref(){return this}unref(){return this}cork(){}uncork(){}pause(){return this}resume(){return this}address(){return{address:this.localAddress,family:"IPv4",port:this.localPort}}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){let r=(...n)=>{this.off(e,r),t.call(this,...n)};return this.on(e,r)}off(e,t){let r=this._listeners[e];if(!r)return this;let n=r.indexOf(t);return n!==-1&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e?delete this._listeners[e]:this._listeners={},this}emit(e,...t){let r=this._listeners[e];return Vl(this,r,t)}listenerCount(e){return this._listeners[e]?.length||0}write(e,t,r){if(this.destroyed||!this._peer)return!1;let n=typeof t=="function"?t:r,i=QSe(e);return this.bytesWritten+=i.length,queueMicrotask(()=>{this._peer?._pushData(i)}),n?.(),!0}end(e){return e!==void 0&&this.write(e),this.writable=!1,this._writableState.finished=!0,queueMicrotask(()=>{this._peer?._pushEnd()}),this.emit("finish"),this}destroy(e){return this.destroyed?this:(this.destroyed=!0,this.readable=!1,this.writable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._writableState.finished=!0,e&&this.emit("error",e),queueMicrotask(()=>{this._peer?._pushEnd()}),this.emit("close",!1),this)}_pushData(e){!this.readable||this.destroyed||this.emit("data",this._encoding?e.toString(this._encoding):e)}_pushEnd(){this.destroyed||(this.readable=!1,this.writable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._writableState.finished=!0,this.emit("end"),this.emit("close",!1))}};function QSe(e){return typeof Buffer<"u"&&Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):Buffer.from(String(e))}var pu,BB=(pu=class{constructor(t){y(this,"options");y(this,"maxSockets");y(this,"maxTotalSockets");y(this,"maxFreeSockets");y(this,"keepAlive");y(this,"keepAliveMsecs");y(this,"timeout");y(this,"requests");y(this,"sockets");y(this,"freeSockets");y(this,"totalSocketCount");y(this,"_listeners",{});this.options={...t},this._validateSocketCountOption("maxSockets",t?.maxSockets),this._validateSocketCountOption("maxFreeSockets",t?.maxFreeSockets),this._validateSocketCountOption("maxTotalSockets",t?.maxTotalSockets),this.keepAlive=t?.keepAlive??!1,this.keepAliveMsecs=t?.keepAliveMsecs??1e3,this.maxSockets=t?.maxSockets??pu.defaultMaxSockets,this.maxTotalSockets=t?.maxTotalSockets??1/0,this.maxFreeSockets=t?.maxFreeSockets??256,this.timeout=t?.timeout??-1,this.requests={},this.sockets={},this.freeSockets={},this.totalSocketCount=0}_validateSocketCountOption(t,r){if(r!==void 0){if(typeof r!="number"){let n=typeof r=="string"?`type string ('${r}')`:`type ${typeof r} (${JSON.stringify(r)})`,i=new TypeError(`The "${t}" argument must be of type number. Received ${n}`);throw i.code="ERR_INVALID_ARG_TYPE",i}if(Number.isNaN(r)||r<=0){let n=new RangeError(`The value of "${t}" is out of range. It must be > 0. Received ${String(r)}`);throw n.code="ERR_OUT_OF_RANGE",n}}}getName(t){let r=t?.hostname||t?.host||"localhost",n=t?.port??"",i=t?.localAddress??"",s="";return t?.socketPath?s=`:${t.socketPath}`:(t?.family===4||t?.family===6)&&(s=`:${t.family}`),`${r}:${n}:${i}${s}`}_getHostKey(t){return this.getName(t)}on(t,r){return this._listeners[t]||(this._listeners[t]=[]),this._listeners[t].push(r),this}once(t,r){let n=(...i)=>{this.off(t,n),r(...i)};return this.on(t,n)}off(t,r){let n=this._listeners[t];if(!n)return this;let i=n.indexOf(r);return i!==-1&&n.splice(i,1),this}removeListener(t,r){return this.off(t,r)}emit(t,...r){let n=this._listeners[t];return Vl(this,n,r)}createConnection(t,r){let n=typeof t.createConnection=="function"?t.createConnection:typeof this.options.createConnection=="function"?this.options.createConnection:null;return n?n(t,r??(()=>{})):LB(t,r)}addRequest(t,r){let n=this.getName(r),i=this._takeFreeSocket(n);if(i){this._activateSocket(n,i),t._assignSocket(i,!0);return}if(this._canCreateSocket(n)){this._createSocketForRequest(n,t,r);return}this.requests[n]||(this.requests[n]=[]),this.requests[n].push({request:t,options:r})}_releaseSocket(t,r,n,i){let s=this._removeSocket(this.sockets,t,r);if(i&&!r.destroyed){let o=this.freeSockets[t]??(this.freeSockets[t]=[]);o.length0&&(r._freeTimer=setTimeout(()=>{r._freeTimer=null,r.destroy()},this.timeout)),r.emit("free"),this.emit("free",r,n)):(s&&(this.totalSocketCount=Math.max(0,this.totalSocketCount-1)),r.destroy())}else r.destroyed||(s&&(this.totalSocketCount=Math.max(0,this.totalSocketCount-1)),r.destroy());Promise.resolve().then(()=>this._processPendingRequests())}_removeSocketCompletely(t,r){r._freeTimer&&(clearTimeout(r._freeTimer),r._freeTimer=null),(this._removeSocket(this.sockets,t,r)||this._removeSocket(this.freeSockets,t,r))&&(this.totalSocketCount=Math.max(0,this.totalSocketCount-1),Promise.resolve().then(()=>this._processPendingRequests()))}_canCreateSocket(t){return(this.sockets[t]?.length??0)>=this.maxSockets?!1:this.totalSocketCount0;){let n=r.shift();if(!n.destroyed)return n._freeTimer&&(clearTimeout(n._freeTimer),n._freeTimer=null),r.length===0&&delete this.freeSockets[t],n;this.totalSocketCount=Math.max(0,this.totalSocketCount-1)}return r&&r.length===0&&delete this.freeSockets[t],null}_activateSocket(t,r){(this.sockets[t]??(this.sockets[t]=[])).push(r)}_createSocketForRequest(t,r,n){let i=!1,s=(a,A)=>{if(!i){if(i=!0,a||!A){r._handleSocketError(a??new Error("Failed to create socket")),this._processPendingRequests();return}if(r.destroyed){this.totalSocketCount+=1,this._activateSocket(t,A),A.once("close",()=>{this._removeSocketCompletely(t,A)}),r._assignSocket(A,!1);return}this.totalSocketCount+=1,this._activateSocket(t,A),A.once("close",()=>{this._removeSocketCompletely(t,A)}),r._assignSocket(A,!1)}},o={...n,keepAlive:this.keepAlive,keepAliveInitialDelay:this.keepAliveMsecs};try{let a=this.createConnection(o,(A,f)=>{s(A,f)});a&&s(null,a)}catch(a){s(a instanceof Error?a:new Error(String(a)))}}_processPendingRequests(){for(let t of Object.keys(this.requests)){let r=this.requests[t];for(;r&&r.length>0;){let n=this._takeFreeSocket(t);if(n){let s=r.shift();if(s.request.destroyed){this._activateSocket(t,n),this._releaseSocket(t,n,s.options,!0);continue}this._activateSocket(t,n),s.request._assignSocket(n,!0);continue}if(!this._canCreateSocket(t))break;let i=r.shift();i.request.destroyed||this._createSocketForRequest(t,i.request,i.options)}(!r||r.length===0)&&delete this.requests[t]}}_removeSocket(t,r,n){let i=t[r];if(!i)return!1;let s=i.indexOf(n);return s===-1?!1:(i.splice(s,1),i.length===0&&delete t[r],!0)}_evictFreeSocket(t){let r=Object.keys(this.freeSockets),n=r.includes(t)?[...r.filter(i=>i!==t),t]:r;for(let i of n){let s=this.freeSockets[i]?.[0];if(s){s.destroy();return}}}destroy(){for(let t of Object.values(this.sockets).flat())t.destroy();for(let t of Object.values(this.freeSockets).flat())t.destroy();this.requests={},this.sockets={},this.freeSockets={},this.totalSocketCount=0}},y(pu,"defaultMaxSockets",1/0),pu);function rr(...e){process.env.SECURE_EXEC_DEBUG_HTTP_BRIDGE==="1"&&console.error("[secure-exec bridge network]",...e)}var wSe=1,Og=new Map,SSe=["ACL","BIND","CHECKOUT","CONNECT","COPY","DELETE","GET","HEAD","LINK","LOCK","M-SEARCH","MERGE","MKACTIVITY","MKCALENDAR","MKCOL","MOVE","NOTIFY","OPTIONS","PATCH","POST","PROPFIND","PROPPATCH","PURGE","PUT","QUERY","REBIND","REPORT","SEARCH","SOURCE","SUBSCRIBE","TRACE","UNBIND","UNLINK","UNLOCK","UNSUBSCRIBE"],_Se=/[^\u0021-\u00ff]/,vSe=new Set(["!","#","$","%","&","'","*","+","-",".","^","_","`","|","~"]);function lr(e,t){let r=new TypeError(e);return r.code=t,r}function IB(e,t){let r=new Error(e);return r.code=t,r}function Yn(e){if(e===null)return"null";if(Array.isArray(e))return"an instance of Array";let t=typeof e;return t==="function"?`function ${typeof e.name=="string"&&e.name.length>0?e.name:"anonymous"}`:t==="object"?`an instance of ${e&&typeof e=="object"&&typeof e.constructor?.name=="string"?e.constructor.name:"Object"}`:t==="string"?`type string ('${String(e)}')`:t==="symbol"?`type symbol (${String(e)})`:`type ${t} (${String(e)})`}function G1(e,t,r){return lr(`The "${e}" property must be of type ${t}. Received ${Yn(r)}`,"ERR_INVALID_ARG_TYPE")}function cW(e){if(e.length===0)return!1;for(let t=0;t=48&&n<=57||n>=65&&n<=90||n>=97&&n<=122)&&!vSe.has(r))return!1}return!0}function lW(e){for(let t=0;t255))return!0}return!1}function Gi(e,t="Header name"){let r=String(e);if(!cW(r))throw lr(`${t} must be a valid HTTP token [${JSON.stringify(r)}]`,"ERR_INVALID_HTTP_TOKEN");return r}function Yi(e,t){if(t===void 0)throw lr(`Invalid value "undefined" for header "${e}"`,"ERR_HTTP_INVALID_HEADER_VALUE");if(Array.isArray(t)){for(let r of t)Yi(e,r);return}if(lW(String(t)))throw lr(`Invalid character in header content [${JSON.stringify(e)}]`,"ERR_INVALID_CHAR")}function Il(e){return Array.isArray(e)?e.map(t=>String(t)):String(e)}function Qu(e){return Array.isArray(e)?e.join(", "):e}function cG(e){return Array.isArray(e)?[...e]:e}function vo(e,t,r){if(t==="set-cookie"){let i=e[t];i===void 0?e[t]=[r]:Array.isArray(i)?i.push(r):e[t]=[i,r];return}let n=e[t];e[t]=n===void 0?r:`${Qu(n)}, ${r}`}function RSe(e){if(!(e==null||e==="")){if(typeof e!="string")throw G1("options.method","string",e);return Gi(e,"Method")}}function DSe(e){let t=e==null||e===""?"/":String(e);if(_Se.test(t))throw lr("Request path contains unescaped characters","ERR_UNESCAPED_CHARACTERS");return t}function TSe(e){let t=String(e.hostname||e.host||"localhost"),r=e.protocol==="https:"||Number(e.port)===443?443:80,n=e.port!=null?Number(e.port):r;return n===r?t:`${t}:${n}`}function Y1(e){return Array.isArray(e)&&(e.length===0||typeof e[0]=="string")}function NSe(e){if(!e)return{};if(Array.isArray(e)){let r={};for(let n=0;n{if(n===void 0)return;let i=Gi(r).toLowerCase();if(Yi(i,n),Array.isArray(n)){n.forEach(s=>vo(t,i,String(s)));return}vo(t,i,String(n))}),t}function hW(e){return Qu(e.connection||"").toLowerCase().includes("upgrade")&&!!e.upgrade}function MSe(e,t){return String(e||"GET").toUpperCase()==="CONNECT"?!0:hW(t)}function Z2(e){return e==="https:"?"secureConnect":"connect"}function FSe(e,t){return!e||e.destroyed===!0?!1:t==="https:"?e.encrypted===!0&&e._tlsUpgrading!==!0:e._connected===!0||e._loopbackServer?!0:typeof e._socketId=="number"?!1:e.connecting===!1}function lG(e,t){return FSe(e,t)?Promise.resolve():new Promise((r,n)=>{let i=Z2(t),s=()=>{A(),r()},o=f=>{A(),n(f instanceof Error?f:new Error(String(f)))},a=()=>{A(),n(Da("socket closed before request was ready"))},A=()=>{e.off?.(i,s),e.removeListener?.(i,s),e.off?.("error",o),e.removeListener?.("error",o),e.off?.("close",a),e.removeListener?.("close",a)};e.once(i,s),e.once("error",o),e.once("close",a)})}function kSe(e){let t=e?.protocol==="https:"?"https:":"http:",r=String(e?.hostname||e?.host||"localhost"),n=t==="https:"?443:80,i=Number(e?.port)||n,s=new URL(`${t}//${r}`);return i!==n&&(s.port=String(i)),s.origin}function USe(e,t){if(typeof jq!="function"||typeof PY!="function")throw new Error("Undici request transport is not available");let r=kSe(t);if(e._agentOSUndiciClient&&e._agentOSUndiciOrigin===r&&e._agentOSUndiciClient.destroyed!==!0)return e._agentOSUndiciClient;let n=new jq(r,{pipelining:1,connect(s,o){return o(null,e),e}}),i=()=>{e._agentOSUndiciClient===n&&(e._agentOSUndiciClient=null,e._agentOSUndiciOrigin=null)};return e.once?.("close",i),e._agentOSUndiciClient=n,e._agentOSUndiciOrigin=r,n}function LB(e,t){let r=e?.protocol==="https:"?"https:":"http:",n=String(e?.hostname||e?.host||"localhost"),i=Number(e?.port)||(r==="https:"?443:80),s=r==="https:"?AW({host:n,port:i,servername:e?.servername||n,rejectUnauthorized:e?.rejectUnauthorized,socket:e?.socket}):x1({host:n,port:i,path:e?.socketPath,keepAlive:e?.keepAlive,keepAliveInitialDelay:e?.keepAliveInitialDelay});if(t){let o=Z2(r),a=()=>{f(),t(null,s)},A=l=>{f(),t(l instanceof Error?l:new Error(String(l)))},f=()=>{s.off?.(o,a),s.removeListener?.(o,a),s.off?.("error",A),s.removeListener?.("error",A)};s.once(o,a),s.once("error",A)}return s}function xSe(e){let t=[];for(let[r,n]of e)t.push(r,n);return t}function hG(e,t){let r=[];return Object.entries(e).forEach(([n,i])=>{let s=t.get(n)||n;if(Array.isArray(i)){i.forEach(o=>{r.push([s,String(o)])});return}r.push([s,String(i)])}),r}function LSe(e,t,r,n){let i=[`${e} ${t} HTTP/1.1`];r.forEach(([o,a])=>{i.push(`${o}: ${a}`)}),i.push("","");let s=Buffer.from(i.join(`\r -`),"latin1");return!n||n.length===0?s:Buffer.concat([s,n])}async function PSe(e){if(!e)return Buffer.alloc(0);let t=[];for await(let r of e)typeof Buffer<"u"&&Buffer.isBuffer(r)?t.push(r):r instanceof Uint8Array?t.push(Buffer.from(r)):t.push(Buffer.from(String(r)));return t.length===0?Buffer.alloc(0):t.length===1?t[0]:Buffer.concat(t)}function OSe(e){let t=e.indexOf(`\r -\r -`);if(t===-1)return null;let n=e.subarray(0,t).toString("latin1").split(`\r -`),i=n.shift()||"",s=/^HTTP\/(\d)\.(\d)\s+(\d{3})(?:\s+(.*))?$/.exec(i);if(!s)throw new Error(`Invalid HTTP response status line: ${i}`);let o={},a=[],A=null;for(let f of n){if(!f)continue;if((f.startsWith(" ")||f.startsWith(" "))&&a.length>=2&&A){let S=f.trim();a[a.length-1]+=` ${S}`,o[A]=Qu(o[A])+` ${S}`;continue}let l=f.indexOf(":");if(l===-1)throw new Error(`Invalid HTTP response header line: ${f}`);let p=f.slice(0,l),I=f.slice(l+1).trim();A=p.toLowerCase(),a.push(p,I),vo(o,A,I)}return{status:Number(s[3]),statusText:s[4]||"",headers:o,rawHeaders:a,head:e.subarray(t+4)}}function HSe(e,t,r){return new Promise((n,i)=>{let s=null,o=Buffer.alloc(0),a=null,A=!1,f=!1,l=!1,p=(X,Z)=>{if(!l){if(l=!0,I(),X){i(X);return}n(Z)}},I=()=>{clearTimeout(Y),e.off?.("data",N),e.removeListener?.("data",N),e.off?.("error",O),e.removeListener?.("error",O),e.off?.("end",x),e.removeListener?.("end",x),e.off?.("close",G),e.removeListener?.("close",G)},S=()=>{if(!s)return!1;if(!W1(s.status,t))return p(null,{...s,body:Buffer.alloc(0)}),!0;if(A){let X=gW(o);return X===null?(p(new Error("Invalid chunked HTTP response body")),!0):X.complete?(p(null,{...s,body:X.body}),!0):!1}return a!==null?o.length{if(!s||!W1(s.status,t))return;let X=s.headers["transfer-encoding"],Z=s.headers["content-length"];if(X!==void 0){let j=$2(Qu(X)),se=j.filter(H=>H==="chunked").length,ie=se>0,ce=ie&&j[j.length-1]==="chunked";if(!ie||se!==1||!ce||Z!==void 0)throw new Error("Unsupported transfer-encoding in HTTP response");A=!0;return}if(Z!==void 0){let j=dW(Z);if(j===null)throw new Error("Invalid content-length in HTTP response");a=j;return}f=!0},N=X=>{let Z=Buffer.isBuffer(X)?X:Buffer.from(X);if(!s){o=Buffer.concat([o,Z]);try{let j=OSe(o);if(!j)return;s=j,o=Buffer.from(j.head),_(),S()}catch(j){p(j instanceof Error?j:new Error(String(j)))}return}o=Buffer.concat([o,Z]);try{S()}catch(j){p(j instanceof Error?j:new Error(String(j)))}},O=X=>{p(X instanceof Error?X:new Error(String(X)))},x=()=>{if(!s){p(Da("socket ended before receiving HTTP response head"));return}if(f){p(null,{...s,body:o});return}S()||p(Da("socket ended before receiving complete HTTP response body"))},G=()=>{if(!s){p(Da("socket closed before receiving HTTP response head"));return}if(f){p(null,{...s,body:o});return}S()||p(Da("socket closed before receiving complete HTTP response body"))},Y=setTimeout(()=>{p(new Error(`Timed out waiting for HTTP response after ${r}ms`))},r);e.on("data",N),e.once("error",O),e.once("end",x),e.once("close",G)})}function W1(e,t){return!(t==="HEAD"||e>=100&&e<200||e===204||e===304)}function $2(e){return e.split(",").map(t=>t.trim().toLowerCase()).filter(t=>t.length>0)}function dW(e){if(e===void 0)return 0;let t=Array.isArray(e)?e:[e],r=null;for(let n of t){if(!/^\d+$/.test(n))return null;let i=Number(n);if(!Number.isSafeInteger(i)||i<0||r!==null&&r!==i)return null;r=i}return r??0}function gW(e,t=Ol){let r=0,n=0,i=[];for(;;){let s=e.indexOf(`\r -`,r);if(s===-1)return{complete:!1};let o=e.subarray(r,s).toString("latin1");if(o.length===0||/[\r\n]/.test(o))return null;let[a,A]=o.split(";",2);if(!/^[0-9A-Fa-f]+$/.test(a)||A!==void 0&&/[\r\n]/.test(A))return null;let f=Number.parseInt(a,16);if(!Number.isSafeInteger(f)||f<0||n+f>t)return null;let l=s+2,p=l+f,I=p+2;if(I>e.length)return{complete:!1};if(e[p]!==13||e[p+1]!==10)return null;if(f>0){n+=f,i.push(e.subarray(l,p)),r=I;continue}let S=e.indexOf(`\r -\r -`,l);if(S===-1)return{complete:!1};let _=e.subarray(l,S).toString("latin1");if(_.length>0){for(let N of _.split(`\r -`))if(N.length!==0&&(N.startsWith(" ")||N.startsWith(" ")||N.indexOf(":")===-1))return null}return{complete:!0,bytesConsumed:S+4,body:i.length>0?Buffer.concat(i):Buffer.alloc(0)}}}function pW(e,t){let r=0;for(;r+1dG?{kind:"bad-request",closeConnection:!0}:{kind:"incomplete"};if(n-r>dG)return{kind:"bad-request",closeConnection:!0};let i=e.subarray(r,n).toString("latin1"),[s,...o]=i.split(`\r -`);if(o.length>$Se)return{kind:"bad-request",closeConnection:!0};let a=/^([A-Z]+)\s+(\S+)\s+HTTP\/(1)\.(0|1)$/.exec(s);if(!a)return{kind:"bad-request",closeConnection:!0};let A={},f=[],l=null;try{for(let X of o){if(X.length===0)continue;if(X.startsWith(" ")||X.startsWith(" "))return{kind:"bad-request",closeConnection:!0};let Z=X.indexOf(":");if(Z===-1)return{kind:"bad-request",closeConnection:!0};let j=X.slice(0,Z).trim(),se=X.slice(Z+1).trim(),ie=Gi(j).toLowerCase();Yi(ie,se),vo(A,ie,se),f.push(j,se),l=ie}}catch{return{kind:"bad-request",closeConnection:!0}}let p=a[1],I=a[2],S=Number(a[4]),_=Qu(A.connection||"").toLowerCase(),N=S===0?!_.includes("keep-alive"):_.includes("close");if(hW(A)&&t.listenerCount("upgrade")>0)return{kind:"request",bytesConsumed:e.length,closeConnection:!1,request:{method:p,url:I,headers:A,rawHeaders:f,bodyBase64:n+4ce==="chunked").length,j=Z>0,se=j&&X[X.length-1]==="chunked";if(!j||Z!==1||!se||x!==void 0)return{kind:"bad-request",closeConnection:!0};let ie=gW(e.subarray(n+4));if(ie===null)return{kind:"bad-request",closeConnection:!0};if(!ie.complete)return{kind:"incomplete"};G=ie.body,Y=n+4+ie.bytesConsumed}else if(x!==void 0){let X=dW(x);if(X===null||X>Ol)return{kind:"bad-request",closeConnection:!0};let Z=n+4+X;if(Z>e.length)return{kind:"incomplete"};G=e.subarray(n+4,Z),Y=Z}return{kind:"request",bytesConsumed:Y,closeConnection:N,request:{method:p,url:I,headers:A,rawHeaders:f,bodyBase64:G.length>0?G.toString("base64"):void 0}}}function yg(e,t){let r={},n=new Map,i=[];if(Array.isArray(e)&&e.length>0){for(let s=0;s`${Z}: ${j}\r -`).join("");N.push(Buffer.from(`HTTP/1.1 ${G.status} ${G.statusText||Hg[G.status]||""}\r -${X}\r -`,"latin1"))}let x=Kv(s,o,a).map(([G,Y])=>`${G}: ${Y}\r -`).join("");if(N.push(Buffer.from(`HTTP/1.1 ${n} ${i}\r -${x}\r -`,"latin1")),l)if(I){if(f.length>0&&(N.push(Buffer.from(f.length.toString(16)+`\r -`,"latin1")),N.push(f),N.push(Buffer.from(`\r -`,"latin1"))),N.push(Buffer.from(`0\r -`,"latin1")),Object.keys(A.headers).length>0){let G=Kv(A.headers,A.rawNameMap,A.order);for(let[Y,X]of G)N.push(Buffer.from(`${Y}: ${X}\r -`,"latin1"))}N.push(Buffer.from(`\r -`,"latin1"))}else f.length>0&&N.push(f);return{payload:N.length===1?N[0]:Buffer.concat(N),closeConnection:_}}var Hg={100:"Continue",101:"Switching Protocols",102:"Processing",103:"Early Hints",200:"OK",201:"Created",204:"No Content",301:"Moved Permanently",302:"Found",304:"Not Modified",400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"};var Du=class{constructor(e){y(this,"headers");y(this,"rawHeaders");y(this,"method");y(this,"url");y(this,"socket");y(this,"connection");y(this,"rawBody");y(this,"destroyed",!1);y(this,"errored");y(this,"readable",!0);y(this,"httpVersion","1.1");y(this,"httpVersionMajor",1);y(this,"httpVersionMinor",1);y(this,"complete",!0);y(this,"aborted",!1);y(this,"_readableState",{flowing:null,length:0,ended:!1,objectMode:!1});y(this,"_listeners",{});this.headers=e.headers||{},this.rawHeaders=e.rawHeaders||[],(!Array.isArray(this.rawHeaders)||this.rawHeaders.length%2!==0)&&(this.rawHeaders=[]),this.method=e.method||"GET",this.url=e.url||"/";let t={encrypted:!1,remoteAddress:"127.0.0.1",remotePort:0,writable:!0,on(){return t},once(){return t},removeListener(){return t},destroy(){},end(){}};this.socket=t,this.connection=t;let r=this.headers.host;typeof r=="string"&&r.includes(",")&&(this.headers.host=r.split(",")[0].trim()),this.headers.host||(this.headers.host="127.0.0.1"),this.rawHeaders.length===0&&Object.entries(this.headers).forEach(([n,i])=>{if(Array.isArray(i)){i.forEach(s=>{this.rawHeaders.push(n,s)});return}this.rawHeaders.push(n,i)}),e.bodyBase64&&typeof Buffer<"u"&&(this.rawBody=Buffer.from(e.bodyBase64,"base64"))}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){let r=(...n)=>{this.off(e,r),t.call(this,...n)};return this.on(e,r)}off(e,t){let r=this._listeners[e];if(!r)return this;let n=r.indexOf(t);return n!==-1&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}emit(e,...t){let r=this._listeners[e];return Vl(this,r,t)}unpipe(){return this}pause(){return this}resume(){return this}read(){return null}pipe(e){return e}isPaused(){return!1}setEncoding(){return this}destroy(e){return this.destroyed=!0,this.errored=e,e&&this.emit("error",e),this.emit("close"),this}_abort(){if(this.aborted)return;this.aborted=!0;let e=Da("aborted");this.emit("aborted"),this.emit("error",e),this.emit("close")}},r0=class{constructor(){y(this,"statusCode",200);y(this,"statusMessage","OK");y(this,"headersSent",!1);y(this,"writable",!0);y(this,"writableFinished",!1);y(this,"outputSize",0);y(this,"_headers",new Map);y(this,"_trailers",new Map);y(this,"_chunks",[]);y(this,"_chunksBytes",0);y(this,"_streamed",!1);y(this,"_listeners",{});y(this,"_closedPromise");y(this,"_resolveClosed",null);y(this,"_connectionEnded",!1);y(this,"_connectionReset",!1);y(this,"_rawHeaderNames",new Map);y(this,"_rawTrailerNames",new Map);y(this,"_informational",[]);y(this,"_pendingRawInfoBuffer","");y(this,"_streamSocket",null);y(this,"_streamRequest",null);y(this,"_streamedDirectly",!1);y(this,"_streamCloseConnection",!1);y(this,"_writableState",{length:0,ended:!1,finished:!1,objectMode:!1,corked:0});y(this,"socket",{writable:!0,writableCorked:0,writableHighWaterMark:16*1024,on:()=>this.socket,once:()=>this.socket,removeListener:()=>this.socket,destroy:()=>{this._connectionReset=!0,this._finalize()},end:()=>{this._connectionEnded=!0},cork:()=>{this._writableState.corked+=1,this.socket.writableCorked=this._writableState.corked},uncork:()=>{this._writableState.corked=Math.max(0,this._writableState.corked-1),this.socket.writableCorked=this._writableState.corked},write:(e,t,r)=>this.write(e,t,r)});y(this,"connection",this.socket);this._closedPromise=new Promise(e=>{this._resolveClosed=e})}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){let r=(...n)=>{this.off(e,r),t.call(this,...n)};return this.on(e,r)}off(e,t){let r=this._listeners[e];if(!r)return this;let n=r.indexOf(t);return n!==-1&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}emit(e,...t){let r=this._listeners[e];return!r||r.length===0?!1:(r.slice().forEach(n=>n.call(this,...t)),!0)}_emit(e,...t){this.emit(e,...t)}writeHead(e,t){if(e>=100&&e<200&&e!==101){let r=new Map,n=new Map;if(t)if(Y1(t))for(let o=0;o{let A=Gi(o).toLowerCase();Yi(A,a),r.set(A,String(a)),n.has(A)||n.set(A,o)}):Object.entries(t).forEach(([o,a])=>{let A=Gi(o).toLowerCase();Yi(A,a),r.set(A,String(a)),n.has(A)||n.set(A,o)});let i=Array.from(r.entries()).flatMap(([o,a])=>{let A=Il(a);return Array.isArray(A)?A.map(f=>[o,f]):[[o,A]]}),s=Array.from(r.entries()).flatMap(([o,a])=>{let A=n.get(o)||o,f=Il(a);return Array.isArray(f)?f.flatMap(l=>[A,l]):[A,f]});return this._informational.push({status:e,statusText:Hg[e],headers:i,rawHeaders:s}),this}if(this.statusCode=e,t)if(Y1(t))for(let r=0;rthis.setHeader(r,n)):Object.entries(t).forEach(([r,n])=>this.setHeader(r,n));return this.headersSent=!0,this.outputSize+=64,this}setHeader(e,t){if(this.headersSent)throw IB("Cannot set headers after they are sent to the client","ERR_HTTP_HEADERS_SENT");let r=Gi(e).toLowerCase();Yi(r,t);let n=Array.isArray(t)?Array.from(t):t;return this._headers.set(r,n),this._rawHeaderNames.has(r)||this._rawHeaderNames.set(r,e),this}setHeaders(e){if(this.headersSent)throw IB("Cannot set headers after they are sent to the client","ERR_HTTP_HEADERS_SENT");if(!(e instanceof xA)&&!(e instanceof Map))throw lr(`The "headers" argument must be an instance of Headers or Map. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");if(e instanceof xA){let t=Object.create(null);return e.forEach((r,n)=>{vo(t,n.toLowerCase(),r)}),Object.entries(t).forEach(([r,n])=>{this.setHeader(r,n)}),this}return e.forEach((t,r)=>{this.setHeader(r,t)}),this}getHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");let t=this._headers.get(e.toLowerCase());return t===void 0?void 0:cG(t)}hasHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");return this._headers.has(e.toLowerCase())}removeHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");let t=e.toLowerCase();this._headers.delete(t),this._rawHeaderNames.delete(t)}_appendChunk(e,t,r){if(e==null)return!0;let n=typeof e=="string"?Buffer.from(e,typeof t=="string"?t:void 0):e;if(this._chunksBytes+n.byteLength>Ol)throw new Error("ERR_HTTP_BODY_TOO_LARGE: response body exceeds "+Ol+" byte limit");return this._chunks.push(n),this._chunksBytes+=n.byteLength,this._streamed||(this._streamed=r),this.headersSent=!0,this.outputSize+=n.byteLength,!0}write(e,t,r){this._appendChunk(e,typeof t=="string"?t:void 0,!0);let n=typeof t=="function"?t:r;return typeof n=="function"&&queueMicrotask(n),!0}end(e,t,r){let n,i;if(typeof e=="function"?i=e:(n=e,i=typeof t=="function"?t:r),this._streamSocket&&this._chunks.length===0&&!this.writableFinished&&!this._streamedDirectly){let s=typeof t=="string"?t:void 0;return this._streamEndBody(n,s),typeof i=="function"&&queueMicrotask(i),this}return n!=null&&(typeof n=="string"&&typeof t=="string"?this._appendChunk(n,t,!1):this._appendChunk(n,void 0,!1)),this._finalize(),typeof i=="function"&&queueMicrotask(i),this}_streamEndBody(e,t){let r=typeof e=="string",n=256*1024,i=0;if(e!=null)if(r)for(let a=0;a0&&this._streamSocket.write(o.payload),e!=null&&i>0)if(r)for(let a=0;athis._rawHeaderNames.get(e)||e)}getHeaders(){let e=Object.create(null);for(let[t,r]of this._headers)e[t]=cG(r);return e}assignSocket(){}detachSocket(){}writeContinue(){this.writeHead(100)}writeProcessing(){this.writeHead(102)}addTrailers(e){if(Array.isArray(e)){for(let t=0;t{let n=Gi(t).toLowerCase();Yi(n,r),this._trailers.set(n,String(r)),this._rawTrailerNames.has(n)||this._rawTrailerNames.set(n,t)})}cork(){this.socket.cork()}uncork(){this.socket.uncork()}setTimeout(e){return this}get writableCorked(){return Number(this.socket.writableCorked||0)}flushHeaders(){this.headersSent=!0}destroy(e){this._connectionReset=!0,e&&this._emit("error",e),this._finalize()}async waitForClose(){await this._closedPromise}serialize(){let e=this._chunks.length>0?Buffer.concat(this._chunks):Buffer.alloc(0),t=Array.from(this._headers.entries()).flatMap(([s,o])=>{let a=Il(o);return Array.isArray(a)?s==="set-cookie"?a.map(A=>[s,A]):[[s,a.join(", ")]]:[[s,a]]}),r=Array.from(this._headers.entries()).flatMap(([s,o])=>{let a=this._rawHeaderNames.get(s)||s,A=Il(o);return Array.isArray(A)?s==="set-cookie"?A.flatMap(f=>[a,f]):[a,A.join(", ")]:[a,A]}),n=Array.from(this._trailers.entries()).flatMap(([s,o])=>{let a=Il(o);return Array.isArray(a)?a.map(A=>[s,A]):[[s,a]]}),i=Array.from(this._trailers.entries()).flatMap(([s,o])=>{let a=this._rawTrailerNames.get(s)||s,A=Il(o);return Array.isArray(A)?A.flatMap(f=>[a,f]):[a,A]});return{status:this.statusCode,headers:t,rawHeaders:r,informational:this._informational.length>0?[...this._informational]:void 0,body:e.toString("base64"),bodyEncoding:"base64",trailers:n.length>0?n:void 0,rawTrailers:i.length>0?i:void 0,connectionEnded:this._connectionEnded,connectionReset:this._connectionReset,streamed:this._streamed}}_writeRaw(e,t){return this._pendingRawInfoBuffer+=String(e),this._flushPendingRawInformational(),typeof t=="function"&&queueMicrotask(t),!0}_finalize(){this.writableFinished||(this.writableFinished=!0,this.writable=!1,this._writableState.ended=!0,this._writableState.finished=!0,this._emit("finish"),this._emit("close"),this._resolveClosed?.(),this._resolveClosed=null)}_flushPendingRawInformational(){let e=this._pendingRawInfoBuffer.indexOf(`\r -\r -`);for(;e!==-1;){let t=this._pendingRawInfoBuffer.slice(0,e);this._pendingRawInfoBuffer=this._pendingRawInfoBuffer.slice(e+4);let[r,...n]=t.split(`\r -`),i=/^HTTP\/1\.[01]\s+(\d{3})(?:\s+(.*))?$/.exec(r);if(!i){e=this._pendingRawInfoBuffer.indexOf(`\r -\r -`);continue}let s=Number(i[1]);if(s>=100&&s<200&&s!==101){let o=[],a=[];for(let A of n){let f=A.indexOf(":");if(f===-1)continue;let l=A.slice(0,f).trim(),p=A.slice(f+1).trim();o.push([l.toLowerCase(),p]),a.push(l,p)}this._informational.push({status:s,statusText:i[2]||Hg[s]||void 0,headers:o,rawHeaders:a})}e=this._pendingRawInfoBuffer.indexOf(`\r -\r -`)}}},tR=class{constructor(e){y(this,"listening",!1);y(this,"_listeners",{});y(this,"_serverId");y(this,"_netServer",null);y(this,"_listenPromise",null);y(this,"_address",null);y(this,"_handleId",null);y(this,"_hostCloseWaitStarted",!1);y(this,"_activeRequestDispatches",0);y(this,"_closePending",!1);y(this,"_closeRunning",!1);y(this,"_closeCallbacks",[]);y(this,"_requestListener");y(this,"keepAliveTimeout",5e3);y(this,"requestTimeout",3e5);y(this,"headersTimeout",6e4);y(this,"timeout",0);y(this,"maxRequestsPerSocket",0);this._serverId=wSe++,this._requestListener=e??(()=>{}),Og.set(this._serverId,this)}get _bridgeServerId(){return this._serverId}_emit(e,...t){let r=this._listeners[e];!r||r.length===0||r.slice().forEach(n=>n.call(this,...t))}_finishStart(e){let t=JSON.parse(e);this._address=t.address,this.listening=!0,this._handleId=`http-server:${this._serverId}`,rr("server listening",this._serverId,this._address),typeof _registerHandle=="function"&&_registerHandle(this._handleId,"http server"),this._startHostCloseWait()}_completeClose(){this.listening=!1,this._address=null,Og.delete(this._serverId),this._handleId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleId),this._handleId=null}_beginRequestDispatch(){this._activeRequestDispatches+=1}_endRequestDispatch(){this._activeRequestDispatches=Math.max(0,this._activeRequestDispatches-1),this._closePending&&this._activeRequestDispatches===0&&(this._closePending=!1,queueMicrotask(()=>{this._startClose()}))}_startHostCloseWait(){this._hostCloseWaitStarted=!0}async _start(e,t){if(typeof Pg>"u")throw new Error("http.createServer requires kernel-backed network bridge support");rr("server listen start",this._serverId,e,t);let r=new Pg({allowHalfOpen:!0});this._netServer=r,r.on("connection",n=>{this._emit("connection",n),VSe(this,n)}),r.on("error",n=>{this._emit("error",n)}),await new Promise((n,i)=>{let s=!1,o=()=>{r.removeListener?.("listening",a),r.removeListener?.("error",A)},a=()=>{s||(s=!0,o(),n())},A=f=>{s||(s=!0,o(),i(f instanceof Error?f:new Error(String(f))))};r.once("listening",a),r.once("error",A),r.listen(e??0,t)}),this._address=r.address(),this.listening=!0,this._startHostCloseWait(),rr("server listening",this._serverId,this._address)}listen(e,t,r){let n=typeof e=="number"?e:void 0,i=typeof t=="string"?t:void 0,s=typeof r=="function"?r:typeof t=="function"?t:typeof e=="function"?e:void 0;return this._listenPromise||(this._listenPromise=this._start(n,i).then(()=>{this._emit("listening"),s?.call(this)}).catch(o=>{this._emit("error",o)})),this}close(e){return rr("server close requested",this._serverId,this.listening),e&&this._closeCallbacks.push(e),this._activeRequestDispatches>0?(this._closePending=!0,this):(queueMicrotask(()=>{this._startClose()}),this)}_startClose(){if(this._closeRunning)return;this._closeRunning=!0,(async()=>{try{this._listenPromise&&await this._listenPromise;let t=this._netServer;this.listening&&t&&(rr("server close net server",this._serverId),await new Promise((n,i)=>{t.close(s=>{s?i(s):n()})})),this._netServer=null,this._completeClose(),rr("server close complete",this._serverId),this._closeCallbacks.splice(0).forEach(n=>n()),this._emit("close")}catch(t){let r=t instanceof Error?t:new Error(String(t));rr("server close error",this._serverId,r.message),this._closeCallbacks.splice(0).forEach(i=>i(r)),this._emit("error",r)}finally{this._closeRunning=!1}})()}address(){return this._address}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){let r=(...n)=>{this.off(e,r),t.call(this,...n)};return this.on(e,r)}off(e,t){let r=this._listeners[e];if(!r)return this;let n=r.indexOf(t);return n!==-1&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e?delete this._listeners[e]:this._listeners={},this}listenerCount(e){return this._listeners[e]?.length||0}setTimeout(e,t){return typeof e=="number"&&(this.timeout=e),this}ref(){return this}unref(){return this}};function EW(e){return new tR(e)}EW.prototype=tR.prototype;async function qSe(e,t){let r=Og.get(e);if(!r)throw new Error(`Unknown HTTP server: ${e}`);let n=r._requestListener;r._beginRequestDispatch();let i=JSON.parse(t),s=new Du(i),o=new r0;s.socket=o.socket,s.connection=o.socket;let a=[],A=[],f=new Map,l=0,p=0;try{try{let I=globalThis.setImmediate,S=globalThis.setTimeout,_=globalThis.clearTimeout;typeof I=="function"&&(globalThis.setImmediate=((N,...O)=>{let x=new Promise(G=>{queueMicrotask(()=>{try{N(...O)}finally{G()}})});return a.push(x),0})),typeof S=="function"&&(globalThis.setTimeout=((N,O,...x)=>{if(typeof N!="function")return S(N,O,...x);let G=typeof O=="number"&&Number.isFinite(O)?Math.max(0,O):0;if(G>1e3)return S(N,G,...x);let Y,X=new Promise(j=>{Y=j}),Z;return Z=S(()=>{f.delete(Z);try{N(...x)}finally{Y()}},G),f.set(Z,Y),A.push(X),Z})),typeof _=="function"&&(globalThis.clearTimeout=(N=>{if(N!=null){let O=f.get(N);O&&(f.delete(N),O())}return _(N)}));try{let N=n(s,o);for(s.rawBody&&s.rawBody.length>0&&s.emit("data",s.rawBody),s.emit("end"),await Promise.resolve(N);l"u")return;P1.delete(t);let n=Io.get(e);if(!n){_networkHttp2ServerRespondRaw.applySync(void 0,[e,t,JSON.stringify({status:500,headers:[["content-type","text/plain"]],body:"Unknown HTTP/2 server",bodyEncoding:"utf8"})]);return}let i=JSON.parse(r.requestJson),s=new Du(i),o=new r0;s.socket=o.socket,s.connection=o.socket;try{n.emit("request",s,o),s.rawBody&&s.rawBody.length>0&&s.emit("data",s.rawBody),s.emit("end"),o.writableFinished||o.end(),await o.waitForClose(),_networkHttp2ServerRespondRaw.applySync(void 0,[e,t,JSON.stringify(o.serialize())])}catch(a){let A=a instanceof Error?a.message:String(a);_networkHttp2ServerRespondRaw.applySync(void 0,[e,t,JSON.stringify({status:500,headers:[["content-type","text/plain"]],body:`Error: ${A}`,bodyEncoding:"utf8"})])}}async function YSe(e,t){let r=typeof e=="number"?Og.get(e):e;if(!r)throw new Error(`Unknown HTTP server: ${typeof e=="number"?e:""}`);let n=typeof t=="string"?JSON.parse(t):t,i=new Du(n),s=new r0;i.socket=s.socket,i.connection=s.socket;let o=[],a=[],A=new Map,f=0,l=0;r._beginRequestDispatch();try{try{let I=globalThis.setImmediate,S=globalThis.setTimeout,_=globalThis.clearTimeout;typeof I=="function"&&(globalThis.setImmediate=((N,...O)=>{let x=new Promise(G=>{queueMicrotask(()=>{try{N(...O)}finally{G()}})});return o.push(x),0})),typeof S=="function"&&(globalThis.setTimeout=((N,O,...x)=>{if(typeof N!="function")return S(N,O,...x);let G=typeof O=="number"&&Number.isFinite(O)?Math.max(0,O):0;if(G>1e3)return S(N,G,...x);let Y,X=new Promise(j=>{Y=j}),Z;return Z=S(()=>{A.delete(Z);try{N(...x)}finally{Y()}},G),A.set(Z,Y),a.push(X),Z})),typeof _=="function"&&(globalThis.clearTimeout=(N=>{if(N!=null){let O=A.get(N);O&&(A.delete(N),O())}return _(N)}));try{let N=r._requestListener(i,s);for(i.rawBody&&i.rawBody.length>0&&i.emit("data",i.rawBody),i.emit("end"),await Promise.resolve(N);f{p||(p=!0,i._abort())}}}finally{r._endRequestDispatch()}}async function WSe(e,t,r){let n=typeof t=="string"?JSON.parse(t):t,i=new Du(n),s=new r0;i.socket=s.socket,i.connection=s.socket,r&&(s._streamSocket=r,s._streamRequest=n),e._beginRequestDispatch();try{try{let A=e._requestListener(i,s);i.rawBody&&i.rawBody.length>0&&i.emit("data",i.rawBody),i.emit("end"),await Promise.resolve(A)}catch(A){s.statusCode=500;try{s.end(A instanceof Error?`Error: ${A.message}`:"Error")}catch{s.writableFinished||s.end()}}s.writableFinished||s.end(),await s.waitForClose();let o=!1,a=()=>{o||(o=!0,i._abort())};return s._streamedDirectly?{streamedDirectly:!0,closeConnection:s._streamCloseConnection,abortRequest:a}:{responseJson:JSON.stringify(s.serialize()),abortRequest:a}}finally{e._endRequestDispatch()}}function VSe(e,t){let r=Buffer.alloc(0),n=!1,i=!1,s=!1,o=!1,a=()=>{o||(o=!0,t.off?.("data",l),t.removeListener?.("data",l),t.off?.("end",p),t.removeListener?.("end",p),t.off?.("close",I),t.removeListener?.("close",I),t.off?.("error",S),t.removeListener?.("error",S))},A=()=>{if(n){i=!0;return}n=!0,_().finally(()=>{n=!1,i&&!o?(i=!1,A()):i=!1})},f=()=>{a(),!t.destroyed&&!t._writableEnded&&t.end()},l=N=>{let O=Buffer.isBuffer(N)?N:Buffer.from(N);r=r.length===0?O:Buffer.concat([r,O]),A()},p=()=>{if(s=!0,r.length===0){a();return}A()},I=()=>{a()},S=()=>{a()};async function _(){let N=!1;for(;!o&&!t.destroyed;){let O=pW(r,e);if(O.kind==="incomplete"){s&&r.length>0&&(t.write(V1()),f());return}if(O.kind==="bad-request"){t.write(V1()),f(),r=Buffer.alloc(0);return}if(r=r.subarray(O.bytesConsumed),O.upgradeHead){a();let Y=new Du(O.request);Y.socket=t,Y.connection=t,e._emit("upgrade",Y,t,O.upgradeHead);return}let x=await WSe(e,O.request,t);if(o||t.destroyed)return;let G;if(x.streamedDirectly)G=x.closeConnection;else{let Y=JSON.parse(x.responseJson),X=eR(Y,O.request,!0);!N&&X.payload.length>0&&t.write(X.payload),G=X.closeConnection}if(G&&(N=!0,r.length===0)){f();return}}}t.on("data",l),t.once("end",p),t.once("close",I),t.once("error",S)}function yW(e,t,r,n,i){let s=Og.get(t);if(!s)throw new Error(`Unknown HTTP server for ${e}: ${t}`);let o=JSON.parse(r),a=new Du(o),A=typeof Buffer<"u"?Buffer.from(n,"base64"):new Uint8Array(0),f=a.headers.host,l=new JSe(i,{host:(Array.isArray(f)?f[0]:f)?.split(":")[0]||"127.0.0.1"});qg.set(i,l),s._emit(e,a,l,A)}var qg=new Map,JSe=class{constructor(e,t){y(this,"remoteAddress");y(this,"remotePort");y(this,"localAddress","127.0.0.1");y(this,"localPort",0);y(this,"connecting",!1);y(this,"destroyed",!1);y(this,"writable",!0);y(this,"readable",!0);y(this,"readyState","open");y(this,"bytesWritten",0);y(this,"_listeners",{});y(this,"_socketId");y(this,"_readableState",{endEmitted:!1,ended:!1});y(this,"_writableState",{finished:!1,errorEmitted:!1});this._socketId=e,this.remoteAddress=t?.host||"127.0.0.1",this.remotePort=t?.port||80}setTimeout(e,t){return this}setNoDelay(e){return this}setKeepAlive(e,t){return this}ref(){return this}unref(){return this}cork(){}uncork(){}pause(){return this}resume(){return this}address(){return{address:this.localAddress,family:"IPv4",port:this.localPort}}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}addListener(e,t){return this.on(e,t)}once(e,t){let r=(...n)=>{this.off(e,r),t(...n)};return this.on(e,r)}off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}return this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e?delete this._listeners[e]:this._listeners={},this}emit(e,...t){let r=this._listeners[e];return Vl(this,r,t)}listenerCount(e){return this._listeners[e]?.length||0}write(e,t,r){if(this.destroyed)return!1;let n=typeof t=="function"?t:r;if(typeof _upgradeSocketWriteRaw<"u"){let i;typeof Buffer<"u"&&Buffer.isBuffer(e)?i=e.toString("base64"):typeof e=="string"?i=typeof Buffer<"u"?Buffer.from(e).toString("base64"):btoa(e):e instanceof Uint8Array?i=typeof Buffer<"u"?Buffer.from(e).toString("base64"):btoa(String.fromCharCode(...e)):i=typeof Buffer<"u"?Buffer.from(String(e)).toString("base64"):btoa(String(e)),this.bytesWritten+=i.length,_upgradeSocketWriteRaw.applySync(void 0,[this._socketId,i])}return n&&n(),!0}end(e){return e&&this.write(e),typeof _upgradeSocketEndRaw<"u"&&!this.destroyed&&_upgradeSocketEndRaw.applySync(void 0,[this._socketId]),this.writable=!1,this.emit("finish"),this}destroy(e){return this.destroyed?this:(this.destroyed=!0,this.writable=!1,this.readable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._writableState.finished=!0,typeof _upgradeSocketDestroyRaw<"u"&&_upgradeSocketDestroyRaw.applySync(void 0,[this._socketId]),qg.delete(this._socketId),e&&this.emit("error",e),this.emit("close",!1),this)}_pushData(e){this.emit("data",e)}_pushEnd(){this.readable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._writableState.finished=!0,this.emit("end"),this.emit("close",!1),qg.delete(this._socketId)}};function jSe(e,t,r,n){yW("upgrade",e,t,r,n)}function zSe(e,t,r,n){yW("connect",e,t,r,n)}function KSe(e,t){let r=qg.get(e);if(r){let n=typeof Buffer<"u"?Buffer.from(t,"base64"):new Uint8Array(0);r._pushData(n)}}function XSe(e){let t=qg.get(e);t&&t._pushEnd()}function J1(){this.statusCode=200,this.statusMessage="OK",this.headersSent=!1,this.writable=!0,this.writableFinished=!1,this.outputSize=0,this._headers=new Map,this._trailers=new Map,this._rawHeaderNames=new Map,this._rawTrailerNames=new Map,this._informational=[],this._pendingRawInfoBuffer="",this._chunks=[],this._chunksBytes=0,this._listeners={},this._closedPromise=new Promise(t=>{this._resolveClosed=t}),this._connectionEnded=!1,this._connectionReset=!1,this._writableState={length:0,ended:!1,finished:!1,objectMode:!1,corked:0};let e={writable:!0,writableCorked:0,writableHighWaterMark:16*1024,on(){return e},once(){return e},removeListener(){return e},destroy(){},end(){},cork(){},uncork(){},write:(t,r,n)=>this.write(t,r,n)};this.socket=e,this.connection=e}J1.prototype=Object.create(r0.prototype,{constructor:{value:J1,writable:!0,configurable:!0}});function mW(e){let t=e==="https"?"https:":"http:",r=new BB({keepAlive:!1,createConnection(s,o){return LB({...s,protocol:t},o)}});function n(s){return s.protocol?s:{...s,protocol:t}}function i(s){return s.agent!==void 0?s:{...s,_agentOSDefaultAgent:r}}return{request(s,o,a){let A,f=typeof o=="function"?o:a;if(typeof s=="string"){let l=new URL(s);A={protocol:l.protocol,hostname:l.hostname,port:l.port,path:l.pathname+l.search,...typeof o=="object"&&o?o:{}}}else s instanceof URL?A={protocol:s.protocol,hostname:s.hostname,port:s.port,path:s.pathname+s.search,...typeof o=="object"&&o?o:{}}:A={...s,...typeof o=="object"&&o?o:{}};return new Tg(i(n(A)),f)},get(s,o,a){let A,f=typeof o=="function"?o:a;if(typeof s=="string"){let p=new URL(s);A={protocol:p.protocol,hostname:p.hostname,port:p.port,path:p.pathname+p.search,method:"GET",...typeof o=="object"&&o?o:{}}}else s instanceof URL?A={protocol:s.protocol,hostname:s.hostname,port:s.port,path:s.pathname+s.search,method:"GET",...typeof o=="object"&&o?o:{}}:A={...s,...typeof o=="object"&&o?o:{},method:"GET"};let l=new Tg(i(n(A)),f);return l.end(),l},createServer(s,o){let a=typeof s=="function"?s:o;return new tR(a)},Agent:BB,globalAgent:r,Server:EW,ServerResponse:J1,IncomingMessage:cu,ClientRequest:Tg,validateHeaderName:Gi,validateHeaderValue:Yi,_checkIsHttpToken:cW,_checkInvalidHeaderChar:lW,maxHeaderSize:65535,METHODS:[...SSe],STATUS_CODES:Hg}}var rR=mW("http");et("_httpModule",rR);et("_dnsModule",X2);function ZSe(e,t){if(rr("http stream event",e,t),e==="http_request"&&!(!t||t.serverId===void 0||t.requestId===void 0||typeof t.request!="string")){if(typeof _networkHttpServerRespondRaw>"u"){rr("http stream missing respond bridge");return}qSe(t.serverId,t.request).then(r=>{rr("http stream response",t.serverId,t.requestId),_networkHttpServerRespondRaw.applySync(void 0,[t.serverId,t.requestId,r])}).catch(r=>{let n=r instanceof Error?r.message:String(r);rr("http stream error",t.serverId,t.requestId,n),_networkHttpServerRespondRaw.applySync(void 0,[t.serverId,t.requestId,JSON.stringify({status:500,headers:[["content-type","text/plain"]],body:`Error: ${n}`,bodyEncoding:"utf8"})])})}}et("_httpServerDispatch",ZSe);et("_httpServerUpgradeDispatch",jSe);et("_httpServerConnectDispatch",zSe);et("_http2Dispatch",hSe);et("_upgradeSocketData",KSe);var nR=mW("https");et("_httpsModule",nR);var Ol=50*1024*1024,dG=64*1024,$Se=2e3,e_e=0,j1=Eu.default?.Headers??Eu.default?.default??Eu.default,t_e=yu.default?.Request??yu.default?.default??yu.default,r_e=mu.default?.Response??mu.default?.default??mu.default;function PB(e){if(!e)return{};if(e instanceof xA||typeof j1=="function"&&e instanceof j1)return Object.fromEntries(e.entries());if(Y1(e)){let t={};for(let r=0;rn.toLowerCase()==="accept-encoding")||(t["accept-encoding"]="gzip, deflate"),{...e||{},headers:t}}async function OB(e,t={}){if(typeof zq!="function")throw new Error("fetch requires undici to be configured");let r=e,n=t;e instanceof iR&&(r=e.url,n={method:e.method,headers:PB(e.headers),body:e.body,...t}),n=i_e(n),n=s_e(n);let i=typeof r=="string"?r:r?.url?String(r.url):String(r),s=typeof _registerHandle=="function"?`fetch:${++e_e}`:null;s&&_registerHandle?.(s,`fetch ${i}`);let o=n.dispatcher==null&&typeof R1=="function"?R1():null;try{return await zq(r,o?{...n,dispatcher:o}:n)}finally{s&&_unregisterHandle?.(s)}}var xA=class BW{constructor(t){y(this,"_headers",{});t&&t!==null&&(t instanceof BW?this._headers={...t._headers}:Array.isArray(t)?t.forEach(([r,n])=>{this._headers[r.toLowerCase()]=n}):typeof t=="object"&&Object.entries(t).forEach(([r,n])=>{this._headers[r.toLowerCase()]=n}))}get(t){return this._headers[t.toLowerCase()]||null}set(t,r){this._headers[t.toLowerCase()]=r}has(t){return t.toLowerCase()in this._headers}delete(t){delete this._headers[t.toLowerCase()]}entries(){return Object.entries(this._headers)[Symbol.iterator]()}[Symbol.iterator](){return this.entries()}keys(){return Object.keys(this._headers)[Symbol.iterator]()}values(){return Object.values(this._headers)[Symbol.iterator]()}append(t,r){let n=t.toLowerCase();n in this._headers?this._headers[n]=this._headers[n]+", "+r:this._headers[n]=r}forEach(t){Object.entries(this._headers).forEach(([r,n])=>t(n,r,this))}},iR=class IW{constructor(t,r={}){y(this,"url");y(this,"method");y(this,"headers");y(this,"body");y(this,"mode");y(this,"credentials");y(this,"cache");y(this,"redirect");y(this,"referrer");y(this,"integrity");this.url=typeof t=="string"?t:t.url,this.method=r.method||(typeof t!="string"?t.method:void 0)||"GET",this.headers=n_e(r.headers||(typeof t!="string"?t.headers:void 0)),this.body=r.body||null,this.mode=r.mode||"cors",this.credentials=r.credentials||"same-origin",this.cache=r.cache||"default",this.redirect=r.redirect||"follow",this.referrer=r.referrer||"about:client",this.integrity=r.integrity||""}clone(){return new IW(this.url,this)}},bW=class eB{constructor(t,r={}){y(this,"_body");y(this,"status");y(this,"statusText");y(this,"headers");y(this,"ok");y(this,"type");y(this,"url");y(this,"redirected");this._body=t||null,this.status=r.status||200,this.statusText=r.statusText||"OK",this.headers=new xA(r.headers),this.ok=this.status>=200&&this.status<300,this.type="default",this.url="",this.redirected=!1}async text(){return String(this._body||"")}async json(){return JSON.parse(this._body||"{}")}get body(){let t=this._body;return t===null?null:{getReader(){let r=!1;return{async read(){return r?{done:!0}:(r=!0,{done:!1,value:new TextEncoder().encode(t)})}}}}}clone(){return new eB(this._body,{status:this.status,statusText:this.statusText})}static error(){return new eB(null,{status:0,statusText:""})}static redirect(t,r=302){return new eB(null,{status:r,headers:{Location:t}})}};et("_upgradeSocketEnd",XSe);et("fetch",OB);et("Headers",j1);et("Request",t_e);et("Response",r_e);var Nl=globalThis.Blob;typeof Nl>"u"&&(Nl=class{},et("Blob",Nl));var Xv=globalThis.File;typeof Xv>"u"&&(Xv=class extends Nl{constructor(r=[],n="",i={}){super(r,i);y(this,"name");y(this,"lastModified");y(this,"webkitRelativePath");this.name=String(n),this.lastModified=typeof i.lastModified=="number"?i.lastModified:Date.now(),this.webkitRelativePath=""}},et("File",Xv));if(typeof globalThis.FormData>"u"){class e{constructor(){y(this,"_entries",[])}append(r,n){this._entries.push([r,n])}get(r){let n=this._entries.find(([i])=>i===r);return n?n[1]:null}getAll(r){return this._entries.filter(([n])=>n===r).map(([,n])=>n)}has(r){return this._entries.some(([n])=>n===r)}delete(r){this._entries=this._entries.filter(([n])=>n!==r)}entries(){return this._entries[Symbol.iterator]()}[Symbol.iterator](){return this.entries()}}et("FormData",e)}var o_e="dgram-socket:";function CW(){return lr("Bad socket type specified. Valid types are: udp4, udp6","ERR_SOCKET_BAD_TYPE")}function a_e(){let e=new Error("Socket is already bound");return e.code="ERR_SOCKET_ALREADY_BOUND",e}function gG(){return new Error("getsockname EBADF")}function Bn(e,t,r){return lr(`The "${e}" argument must be of type ${t}. Received ${Yn(r)}`,"ERR_INVALID_ARG_TYPE")}function pG(e){return lr(`The "${e}" argument must be specified`,"ERR_MISSING_ARGS")}function mg(){return IB("Not running","ERR_SOCKET_DGRAM_NOT_RUNNING")}function A_e(e){switch(e){case"EBADF":return-9;case"EINVAL":return-22;case"EADDRNOTAVAIL":return-99;case"ENOPROTOOPT":return-92}}function ba(e,t){let r=new Error(`${e} ${t}`);return r.code=t,r.errno=A_e(t),r.syscall=e,r}function f_e(e){return lr(`The "ttl" argument must be of type number. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE")}function u_e(){return lr("Buffer size must be a positive integer","ERR_SOCKET_BAD_BUFFER_SIZE")}function Zv(e,t){let r=`uv_${e}_buffer_size`,n={errno:t==="EBADF"?-9:-22,code:t,message:t==="EBADF"?"bad file descriptor":"invalid argument",syscall:r},i=new Error(`Could not get or set buffer size: ${r} returned ${t} (${n.message})`);i.name="SystemError [ERR_SOCKET_BUFFER_SIZE]",i.code="ERR_SOCKET_BUFFER_SIZE",i.info=n;let s=n.errno,o=r;return Object.defineProperty(i,"errno",{enumerable:!0,configurable:!0,get(){return s},set(a){s=a}}),Object.defineProperty(i,"syscall",{enumerable:!0,configurable:!0,get(){return o},set(a){o=a}}),i}function EG(e){return e<=0?e:process.platform==="linux"?e*2:e}function yG(e,t){if(typeof e!="number")throw f_e(e);if(!Number.isInteger(e)||e<=0||e>=256)throw ba(t,"EINVAL");return e}function QW(e){if(!t0(e))return!1;let t=Number(e.split(".")[0]);return t>=224&&t<=239}function wW(e){return t0(e)&&!QW(e)&&e!=="255.255.255.255"}function SW(e){let t=e.indexOf("%"),r=t===-1?e:e.slice(0,t);return xB(e)&&r.toLowerCase().startsWith("ff")}function Pm(e,t,r){if(typeof r!="string")throw Bn(t==="addSourceSpecificMembership"||t==="dropSourceSpecificMembership"?"groupAddress":"multicastAddress","string",r);if(!(e==="udp6"?SW(r):QW(r)))throw ba(t,"EINVAL");return r}function mG(e,t,r){if(typeof r!="string")throw Bn("sourceAddress","string",r);if(!(e==="udp6"?xB(r)&&!SW(r):wW(r)))throw ba(t,"EINVAL");return r}function BG(e){if(e==="udp4"||e==="udp6")return e;throw CW()}function c_e(e){if(typeof e=="string")return{type:BG(e)};if(!e||typeof e!="object"||Array.isArray(e))throw CW();let t=e,r={type:BG(t.type)};if(t.recvBufferSize!==void 0){if(typeof t.recvBufferSize!="number")throw G1("options.recvBufferSize","number",t.recvBufferSize);r.recvBufferSize=t.recvBufferSize}if(t.sendBufferSize!==void 0){if(typeof t.sendBufferSize!="number")throw G1("options.sendBufferSize","number",t.sendBufferSize);r.sendBufferSize=t.sendBufferSize}return r}function z1(e,t,r){if(e==null||e==="")return r;if(typeof e!="string")throw Bn("address","string",e);return e==="localhost"?t==="udp6"?"::1":"127.0.0.1":e}function K1(e){if(typeof e!="number")throw Bn("port","number",e);if(!T1(e))throw D1(e);return e}function X1(e){if(typeof e=="string"||Buffer.isBuffer(e))return Buffer.from(e);if(ArrayBuffer.isView(e))return Buffer.from(e.buffer,e.byteOffset,e.byteLength);throw Bn("msg","string or Buffer or Uint8Array or DataView",e)}function l_e(e){return Array.isArray(e)?Buffer.concat(e.map(t=>X1(t))):X1(e)}function Bg(e){if(typeof e!="string")return e;try{return JSON.parse(e)}catch{return e}}function h_e(e){if(Buffer.isBuffer(e)||e instanceof Uint8Array)return Buffer.from(e);if(typeof e=="string")return Buffer.from(e,"base64");if(e&&typeof e=="object"){if(e.__type==="Buffer"&&typeof e.data=="string")return Buffer.from(e.data,"base64");if(e.__agentOSType==="bytes"&&typeof e.base64=="string")return Buffer.from(e.base64,"base64")}return Buffer.alloc(0)}function d_e(e,t){let r,n,i;if(typeof e[0]=="function")i=e[0];else if(e[0]&&typeof e[0]=="object"&&!Array.isArray(e[0])){let s=e[0];r=s.port,n=s.address,i=e[1]}else r=e[0],typeof e[1]=="function"?i=e[1]:(n=e[1],i=e[2]);if(i!==void 0&&typeof i!="function")throw xl("callback",i);return{port:r===void 0?0:K1(r),address:z1(n,t,t==="udp6"?"::":"0.0.0.0"),callback:i}}function g_e(e,t){if(e.length===0)throw Bn("msg","string or Buffer or Uint8Array or DataView",void 0);let r=e[0];if(typeof e[1]=="number"&&typeof e[2]=="number"&&e.length>=4){let s=X1(r),o=e[1],a=e[2],A=typeof e[4]=="function"?e[4]:e[5];if(A!==void 0&&typeof A!="function")throw xl("callback",A);return{data:Buffer.from(s.subarray(o,o+a)),port:K1(e[3]),address:z1(typeof e[4]=="function"?void 0:e[4],t,t==="udp6"?"::1":"127.0.0.1"),callback:A}}let i=typeof e[2]=="function"?e[2]:e[3];if(i!==void 0&&typeof i!="function")throw xl("callback",i);return{data:l_e(r),port:K1(e[1]),address:z1(typeof e[2]=="function"?void 0:e[2],t,t==="udp6"?"::1":"127.0.0.1"),callback:i}}var IG=class{constructor(e,t){y(this,"_type");y(this,"_socketId");y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_bindPromise",null);y(this,"_receiveLoopRunning",!1);y(this,"_receivePollTimer",null);y(this,"_refed",!0);y(this,"_closed",!1);y(this,"_bound",!1);y(this,"_handleRefId",null);y(this,"_recvBufferSize");y(this,"_sendBufferSize");y(this,"_memberships",new Set);y(this,"_multicastInterface");y(this,"_broadcast",!1);y(this,"_multicastLoopback",1);y(this,"_multicastTtl",1);y(this,"_ttl",64);if(typeof _dgramSocketCreateRaw>"u")throw new Error("dgram.createSocket is not supported in sandbox");let r=c_e(e);this._type=r.type;let n=Bg(_dgramSocketCreateRaw.applySync(void 0,[{type:this._type}]));this._socketId=String(n?.socketId??n),t&&this.on("message",t),r.recvBufferSize!==void 0&&this._setBufferSize("recv",r.recvBufferSize,!1),r.sendBufferSize!==void 0&&this._setBufferSize("send",r.sendBufferSize,!1)}bind(...e){let{port:t,address:r,callback:n}=d_e(e,this._type);return this._bindInternal(t,r,n),this}send(...e){let{data:t,port:r,address:n,callback:i}=g_e(e,this._type);this._sendInternal(t,r,n,i)}sendto(...e){this.send(...e)}address(){if(typeof _dgramSocketAddressRaw>"u")throw gG();try{return Bg(_dgramSocketAddressRaw.applySync(void 0,[this._socketId]))}catch{throw gG()}}close(e){if(e!==void 0&&typeof e!="function")throw xl("callback",e);if(e&&this.once("close",e),this._closed)return this;if(this._closed=!0,this._bound=!1,this._clearReceivePollTimer(),this._syncHandleRef(),typeof _dgramSocketCloseRaw>"u")return queueMicrotask(()=>{this._emit("close")}),this;try{_dgramSocketCloseRaw.applySyncPromise(void 0,[this._socketId])}finally{queueMicrotask(()=>{this._emit("close")})}return this}ref(){return this._refed=!0,this._syncHandleRef(),this._receivePollTimer&&typeof this._receivePollTimer.ref=="function"&&this._receivePollTimer.ref(),this._bound&&!this._closed&&!this._receiveLoopRunning&&this._pumpMessages(),this}unref(){return this._refed=!1,this._syncHandleRef(),this._receivePollTimer&&typeof this._receivePollTimer.unref=="function"&&this._receivePollTimer.unref(),this}setRecvBufferSize(e){this._setBufferSize("recv",e)}setSendBufferSize(e){this._setBufferSize("send",e)}getRecvBufferSize(){return this._getBufferSize("recv")}getSendBufferSize(){return this._getBufferSize("send")}setBroadcast(e){this._ensureBoundForSocketOption("setBroadcast"),this._broadcast=!!e}setTTL(e){return this._ensureBoundForSocketOption("setTTL"),this._ttl=yG(e,"setTTL"),this._ttl}setMulticastTTL(e){return this._ensureBoundForSocketOption("setMulticastTTL"),this._multicastTtl=yG(e,"setMulticastTTL"),this._multicastTtl}setMulticastLoopback(e){return this._ensureBoundForSocketOption("setMulticastLoopback"),this._multicastLoopback=Number(e),this._multicastLoopback}addMembership(e,t){if(e===void 0)throw pG("multicastAddress");if(this._closed)throw mg();let r=Pm(this._type,"addMembership",e);if(t!==void 0&&typeof t!="string")throw Bn("multicastInterface","string",t);this._memberships.add(`${r}|${t??""}`)}dropMembership(e,t){if(e===void 0)throw pG("multicastAddress");if(this._closed)throw mg();let r=Pm(this._type,"dropMembership",e);if(t!==void 0&&typeof t!="string")throw Bn("multicastInterface","string",t);let n=`${r}|${t??""}`;if(!this._memberships.has(n))throw ba("dropMembership","EADDRNOTAVAIL");this._memberships.delete(n)}addSourceSpecificMembership(e,t,r){if(this._closed)throw mg();if(typeof e!="string")throw Bn("sourceAddress","string",e);if(typeof t!="string")throw Bn("groupAddress","string",t);let n=mG(this._type,"addSourceSpecificMembership",e),i=Pm(this._type,"addSourceSpecificMembership",t);if(r!==void 0&&typeof r!="string")throw Bn("multicastInterface","string",r);this._memberships.add(`${n}>${i}|${r??""}`)}dropSourceSpecificMembership(e,t,r){if(this._closed)throw mg();if(typeof e!="string")throw Bn("sourceAddress","string",e);if(typeof t!="string")throw Bn("groupAddress","string",t);let n=mG(this._type,"dropSourceSpecificMembership",e),i=Pm(this._type,"dropSourceSpecificMembership",t);if(r!==void 0&&typeof r!="string")throw Bn("multicastInterface","string",r);let s=`${n}>${i}|${r??""}`;if(!this._memberships.has(s))throw ba("dropSourceSpecificMembership","EADDRNOTAVAIL");this._memberships.delete(s)}setMulticastInterface(e){if(typeof e!="string")throw Bn("interfaceAddress","string",e);if(this._closed)throw mg();if(this._ensureBoundForSocketOption("setMulticastInterface"),this._type==="udp4"){if(e==="0.0.0.0"){this._multicastInterface=e;return}if(!t0(e))throw ba("setMulticastInterface","ENOPROTOOPT");if(!wW(e))throw ba("setMulticastInterface","EADDRNOTAVAIL");this._multicastInterface=e;return}if(e===""||e==="undefined"||!xB(e))throw ba("setMulticastInterface","EINVAL");this._multicastInterface=e}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}addListener(e,t){return this.on(e,t)}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this}removeListener(e,t){let r=this._listeners[e];if(r){let i=r.indexOf(t);i>=0&&r.splice(i,1)}let n=this._onceListeners[e];if(n){let i=n.indexOf(t);i>=0&&n.splice(i,1)}return this}off(e,t){return this.removeListener(e,t)}emit(e,...t){return this._emit(e,...t)}async _bindInternal(e,t,r){if(!this._closed){if(this._bound||this._bindPromise)throw a_e();if(typeof _dgramSocketBindRaw>"u")throw new Error("dgram.bind is not supported in sandbox");return this._bindPromise=(async()=>{try{Bg(_dgramSocketBindRaw.applySyncPromise(void 0,[this._socketId,{port:e,address:t}])),this._bound=!0,this._applyInitialBufferSizes(),this._syncHandleRef(),queueMicrotask(()=>{this._closed||(this._emit("listening"),r?.call(this),this._pumpMessages())})}catch(n){throw queueMicrotask(()=>{this._emit("error",n)}),n}finally{this._bindPromise=null}})(),this._bindPromise}}async _ensureBound(){if(!this._bound){if(this._bindPromise){await this._bindPromise;return}await this._bindInternal(0,this._type==="udp6"?"::":"0.0.0.0")}}async _sendInternal(e,t,r,n){try{if(await this._ensureBound(),this._closed||typeof _dgramSocketSendRaw>"u")return;let i=Bg(_dgramSocketSendRaw.applySyncPromise(void 0,[this._socketId,e,{port:t,address:r}]));n&&queueMicrotask(()=>{n(null,typeof i?.bytes=="number"?i.bytes:e.length)})}catch(i){if(n){queueMicrotask(()=>{n(i)});return}queueMicrotask(()=>{this._emit("error",i)})}}async _pumpMessages(){if(!(this._receiveLoopRunning||this._closed||!this._bound)&&!(typeof _dgramSocketRecvRaw>"u")){this._receiveLoopRunning=!0;try{for(;!this._closed&&this._bound;){let e=Bg(_dgramSocketRecvRaw.applySync(void 0,[this._socketId,pB]));if(e===V2||!e){this._receivePollTimer=setTimeout(()=>{this._receivePollTimer=null,this._pumpMessages()},pB),!this._refed&&typeof this._receivePollTimer.unref=="function"&&this._receivePollTimer.unref();return}if(e.type==="message"){let t=h_e(e.data);this._emit("message",t,{address:e.remoteAddress,family:e.remoteFamily??socketFamilyForAddress(e.remoteAddress),port:e.remotePort,size:t.length});continue}if(e.type==="error"){let t=new Error(typeof e.message=="string"?e.message:"secure-exec dgram socket error");typeof e.code=="string"&&e.code.length>0&&(t.code=e.code),this._emit("error",t)}}}catch(e){this._emit("error",e)}finally{this._receiveLoopRunning=!1}}}_clearReceivePollTimer(){this._receivePollTimer&&(clearTimeout(this._receivePollTimer),this._receivePollTimer=null)}_ensureBoundForSocketOption(e){if(!this._bound||this._closed)throw ba(e,"EBADF")}_setBufferSize(e,t,r=!0){if(!Number.isInteger(t)||t<=0||!Number.isFinite(t))throw u_e();if(t>2147483647)throw Zv(e,"EINVAL");if(r&&(!this._bound||this._closed))throw Zv(e,"EBADF");if(typeof _dgramSocketSetBufferSizeRaw<"u"&&this._bound&&!this._closed&&_dgramSocketSetBufferSizeRaw.applySync(void 0,[this._socketId,e,t]),e==="recv"){this._recvBufferSize=t;return}this._sendBufferSize=t}_getBufferSize(e){if(!this._bound||this._closed)throw Zv(e,"EBADF");let t=e==="recv"?this._recvBufferSize??0:this._sendBufferSize??0;if(typeof _dgramSocketGetBufferSizeRaw>"u")return EG(t);let r=_dgramSocketGetBufferSizeRaw.applySync(void 0,[this._socketId,e]);return EG(r>0?r:t)}_applyInitialBufferSizes(){this._recvBufferSize!==void 0&&this._setBufferSize("recv",this._recvBufferSize),this._sendBufferSize!==void 0&&this._setBufferSize("send",this._sendBufferSize)}_syncHandleRef(){if(!this._bound||this._closed||!this._refed){this._handleRefId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleRefId),this._handleRefId=null;return}let e=`${o_e}${this._socketId}`;this._handleRefId!==e&&(this._handleRefId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleRefId),this._handleRefId=e,typeof _registerHandle=="function"&&_registerHandle(this._handleRefId,"dgram socket"))}_emit(e,...t){let r=!1,n=this._listeners[e];if(n)for(let s of[...n])s(...t),r=!0;let i=this._onceListeners[e];if(i){this._onceListeners[e]=[];for(let s of[...i])s(...t),r=!0}return r}},_W={Socket:IG,createSocket(e,t){return new IG(e,t)}};et("_tlsModule",uW);function p_e(e){if(!e||typeof e!="object"||Array.isArray(e)||Buffer.isBuffer(e)||e instanceof Uint8Array)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function bB(e){return e==null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"?e??null:typeof e=="bigint"?{__agentosSqliteType:"bigint",value:e.toString()}:Buffer.isBuffer(e)||e instanceof Uint8Array?{__agentosSqliteType:"uint8array",value:Buffer.from(e).toString("base64")}:Array.isArray(e)?e.map(t=>bB(t)):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([t,r])=>[t,bB(r)])):null}function Ng(e){return e==null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"?e??null:Array.isArray(e)?e.map(t=>Ng(t)):e&&typeof e=="object"?e.__agentosSqliteType==="bigint"&&typeof e.value=="string"?BigInt(e.value):e.__agentosSqliteType==="uint8array"&&typeof e.value=="string"?Buffer.from(e.value,"base64"):Object.fromEntries(Object.entries(e).map(([t,r])=>[t,Ng(r)])):e}function tB(e){return!Array.isArray(e)||e.length===0?null:e.length===1&&p_e(e[0])?bB(e[0]):e.map(t=>bB(t))}function Zr(e,t,r){if(typeof e=="function")return Ng(e(...t));if(!e)throw new Error(`sqlite bridge is not available for ${r}`);if(typeof e.applySync=="function")return Ng(e.applySync(void 0,t));if(typeof e.applySyncPromise=="function")return Ng(e.applySyncPromise(void 0,t));throw new Error(`sqlite bridge is not available for ${r}`)}var E_e=Re("_sqliteConstantsRaw"),y_e=Re("_sqliteDatabaseOpenRaw"),m_e=Re("_sqliteDatabaseCloseRaw"),B_e=Re("_sqliteDatabaseExecRaw"),I_e=Re("_sqliteDatabaseQueryRaw"),b_e=Re("_sqliteDatabasePrepareRaw"),C_e=Re("_sqliteDatabaseLocationRaw"),Q_e=Re("_sqliteDatabaseCheckpointRaw"),w_e=Re("_sqliteStatementRunRaw"),S_e=Re("_sqliteStatementGetRaw"),__e=Re("_sqliteStatementAllRaw"),v_e=Re("_sqliteStatementColumnsRaw"),R_e=Re("_sqliteStatementSetReturnArraysRaw"),D_e=Re("_sqliteStatementSetReadBigIntsRaw"),T_e=Re("_sqliteStatementSetAllowBareNamedParametersRaw"),N_e=Re("_sqliteStatementSetAllowUnknownNamedParametersRaw"),M_e=Re("_sqliteStatementFinalizeRaw"),CB=class{constructor(e,t){this._database=e,this._statementId=t,this._finalized=!1}_assertOpen(){if(this._database._assertOpen(),this._finalized)throw new Error("SQLite statement is already finalized")}run(...e){return this._assertOpen(),Zr(w_e,[this._statementId,tB(e)],"statement.run")}get(...e){return this._assertOpen(),Zr(S_e,[this._statementId,tB(e)],"statement.get")}all(...e){return this._assertOpen(),Zr(__e,[this._statementId,tB(e)],"statement.all")}iterate(...e){return this.all(...e)[Symbol.iterator]()}columns(){return this._assertOpen(),Zr(v_e,[this._statementId],"statement.columns")}setReturnArrays(e){this._assertOpen(),Zr(R_e,[this._statementId,!!e],"statement.setReturnArrays")}setReadBigInts(e){this._assertOpen(),Zr(D_e,[this._statementId,!!e],"statement.setReadBigInts")}setAllowBareNamedParameters(e){this._assertOpen(),Zr(T_e,[this._statementId,!!e],"statement.setAllowBareNamedParameters")}setAllowUnknownNamedParameters(e){this._assertOpen(),Zr(N_e,[this._statementId,!!e],"statement.setAllowUnknownNamedParameters")}finalize(){return this._finalized||(this._database._assertOpen(),Zr(M_e,[this._statementId],"statement.finalize"),this._finalized=!0),null}},Z1=class{constructor(e=":memory:",t=void 0){this._closed=!1,this._databaseId=Zr(y_e,[typeof e=="string"?e:":memory:",t??null],"database.open")}_assertOpen(){if(this._closed)throw new Error("SQLite database is already closed")}close(){return this._closed||(Zr(m_e,[this._databaseId],"database.close"),this._closed=!0),null}exec(e){return this._assertOpen(),Zr(B_e,[this._databaseId,String(e??"")],"database.exec")}query(e,t=null,r=null){this._assertOpen();let n=t===null?null:tB(Array.isArray(t)?t:[t]);return Zr(I_e,[this._databaseId,String(e??""),n,r??null],"database.query")}prepare(e){this._assertOpen();let t=Zr(b_e,[this._databaseId,String(e??"")],"database.prepare");return new CB(this,t)}location(){return this._assertOpen(),Zr(C_e,[this._databaseId],"database.location")}checkpoint(){return this._assertOpen(),Zr(Q_e,[this._databaseId],"database.checkpoint")}};Z1.prototype[Symbol.dispose]=Z1.prototype.close;CB.prototype[Symbol.dispose]=CB.prototype.finalize;var $v;function F_e(){return $v===void 0&&($v=Object.freeze(Zr(E_e,[],"constants")??{})),$v}var k_e={DatabaseSync:Z1,StatementSync:CB,get constants(){return F_e()}};et("_dgramModule",_W);et("_sqliteModule",k_e);var vW={};_2(vW,{ClientRequest:()=>Tg,Headers:()=>xA,IncomingMessage:()=>cu,Request:()=>iR,Response:()=>bW,default:()=>U_e,dns:()=>X2,fetch:()=>OB,http:()=>rR,http2:()=>K2,https:()=>nR});var U_e={fetch:OB,Headers:xA,Request:iR,Response:bW,dns:X2,http:rR,https:nR,http2:K2,IncomingMessage:cu,ClientRequest:Tg,net:JY,tls:uW,dgram:_W},Ot,Ig,Ea,To=Symbol.for("nodejs.util.inspect.custom"),Ma=Symbol.toStringTag,sR="ERR_INVALID_THIS",x_e="ERR_MISSING_ARGS",L_e="ERR_INVALID_URL",P_e="ERR_ARG_NOT_ITERABLE",O_e="ERR_INVALID_TUPLE",H_e="URLSearchParams",QB=Symbol("secureExecLinkedURLSearchParams"),bG=Symbol.for("secureExec.blobUrlStore"),e1=Symbol.for("secureExec.blobUrlCounter"),q_e=["append","delete","get","getAll","has"],G_e=["append","set"],Y_e={"http:":0,"https:":2,"ws:":4,"wss:":5,"file:":6,"ftp:":8},RW=new WeakSet,$1=new WeakMap,DW=new WeakSet,t1=new WeakMap;function OA(e,t){let r=new TypeError(e);return r.code=t,r}function W_e(){let e=new TypeError("Invalid URL");return e.code=L_e,e}function Om(){return new TypeError("Receiver must be an instance of class URL")}function Ca(e){return OA(e,x_e)}function V_e(){return OA("Query pairs must be iterable",P_e)}function r1(){return OA("Each query pair must be an iterable [name, value] tuple",O_e)}function J_e(){return new TypeError("Cannot convert a Symbol value to a string")}function j_e(e){if(typeof e=="symbol")throw J_e();return String(e)}function z_e(e){let t="";for(let r=0;r=55296&&n<=56319){let i=r+1;if(i=56320&&s<=57343){t+=e[r]+e[i],r=i;continue}}t+="\uFFFD";continue}if(n>=56320&&n<=57343){t+="\uFFFD";continue}t+=e[r]}return t}function zt(e){return z_e(j_e(e))}function yn(e){if(!RW.has(e))throw OA('Value of "this" must be of type URLSearchParams',sR)}function rB(e){if(!DW.has(e))throw OA('Value of "this" must be of type URLSearchParamsIterator',sR)}function On(e){let t=$1.get(e);if(!t)throw OA('Value of "this" must be of type URLSearchParams',sR);return t.getImpl()}function K_e(e){let t=0;for(let r of e)t++;return t}function CG(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}function QG(e){return e>=48&&e<=57?e-48:e>=65&&e<=70?e-55:e-87}function X_e(e,t){if(t<=127){e.push(t);return}if(t<=2047){e.push(192|t>>6,128|t&63);return}if(t<=65535){e.push(224|t>>12,128|t>>6&63,128|t&63);return}e.push(240|t>>18,128|t>>12&63,128|t>>6&63,128|t&63)}function wG(e){let t=String(e).replace(/\+/g," "),r="";for(let n=0;n0){r+=new _u().decode(Uint8Array.from(s)),n=o-1;continue}}let i=t.codePointAt(n);r+=String.fromCodePoint(i),i>65535&&(n+=1)}return r}function SG(e){let t=String(e),r=[];for(let i=0;i65535&&(i+=1)}let n="";for(let i of r){if(i===32){n+="+";continue}if(i>=48&&i<=57||i>=65&&i<=90||i>=97&&i<=122||i===42||i===45||i===46||i===95){n+=String.fromCharCode(i);continue}n+=`%${i.toString(16).toUpperCase().padStart(2,"0")}`}return n}function Z_e(e,t){let r=Math.min(e.length,t.length);for(let n=0;nn!==r)}get(t){let r=String(t),n=this._pairs.find(([i])=>i===r);return n?n[1]:null}getAll(t){let r=String(t);return this._pairs.filter(([n])=>n===r).map(([,n])=>n)}has(t){let r=String(t);return this._pairs.some(([n])=>n===r)}set(t,r){let n=String(t),i=String(r),s=[],o=!1;for(let[a,A]of this._pairs){if(a!==n){s.push([a,A]);continue}o||(o=!0,s.push([n,i]))}o||s.push([n,i]),this._pairs=s}sort(){this._pairs=this._pairs.map((t,r)=>({pair:t,index:r})).sort((t,r)=>{let n=Z_e(t.pair[0],r.pair[0]);return n!==0?n:t.index-r.index}).map(({pair:t})=>t)}entries(){return this._pairs[Symbol.iterator]()}keys(){return this._pairs.map(([t])=>t)[Symbol.iterator]()}values(){return this._pairs.map(([,t])=>t)[Symbol.iterator]()}[Symbol.iterator](){return this.entries()}toString(){return this._pairs.map(([t,r])=>`${SG(t)}=${SG(r)}`).join("&")}};function eve(e){return typeof e=="string"?new n1(e):e===void 0?new n1:new n1(e)}function TW(e,t,r){if(e.length===0)return r;let n=`{ ${e.join(", ")} }`,i=t?.breakLength??1/0;return n.length<=i?n:`{ -${e.join(`, - `)} }`}function tve(e){let t=e.href,r=t.indexOf(":")+1,n=t.indexOf("@"),i=t.indexOf("/",r+2),s=t.indexOf("?"),o=t.indexOf("#"),a=e.username.length>0?t.indexOf(":",r+2):r+2,A=n===-1?r+2:n,f=i===-1?t.length:i-(e.port.length>0?e.port.length+1:0),l=e.port.length>0?Number(e.port):null;return{href:t,protocol_end:r,username_end:a,host_start:A,host_end:f,pathname_start:i===-1?t.length:i,search_start:s===-1?t.length:s,hash_start:o===-1?t.length:o,port:l,scheme_type:Y_e[e.protocol]??1,hasPort:e.port.length>0,hasSearch:e.search.length>0,hasHash:e.hash.length>0}}function rve(e,t,r){let n=tve(e),i=typeof t=="function"?o=>t(o,r):o=>JSON.stringify(o),s=n.port===null?"null":String(n.port);return["URLContext {",` href: ${i(n.href)},`,` protocol_end: ${n.protocol_end},`,` username_end: ${n.username_end},`,` host_start: ${n.host_start},`,` host_end: ${n.host_end},`,` pathname_start: ${n.pathname_start},`,` search_start: ${n.search_start},`,` hash_start: ${n.hash_start},`,` port: ${s},`,` scheme_type: ${n.scheme_type},`," [hasPort]: [Getter],"," [hasSearch]: [Getter],"," [hasHash]: [Getter]"," }"].join(` -`)}function _G(){let e=globalThis,t=e[bG];if(t instanceof Map)return t;let r=new Map;return e[bG]=r,r}function nve(){let e=globalThis,t=typeof e[e1]=="number"?e[e1]:1;return e[e1]=t+1,t}var MA=class NW{constructor(t){DW.add(this),t1.set(this,{values:t,index:0})}next(){rB(this);let t=t1.get(this);if(t.index>=t.values.length)return{value:void 0,done:!0};let r=t.values[t.index];return t.index+=1,{value:r,done:!1}}[To](t,r,n){if(rB(this),t<0)return"[Object]";let i=t1.get(this),s=typeof n=="function"?a=>n(a,r):a=>JSON.stringify(a),o=i.values.slice(i.index).map(a=>s(a));return`URLSearchParams Iterator ${TW(o,r,"{ }")}`}get[Ma](){return this!==NW.prototype&&rB(this),"URLSearchParams Iterator"}};Object.defineProperties(MA.prototype,{next:{value:MA.prototype.next,writable:!0,configurable:!0,enumerable:!0},[Symbol.iterator]:{value:function(){return rB(this),this},writable:!0,configurable:!0,enumerable:!1},[To]:{value:MA.prototype[To],writable:!0,configurable:!0,enumerable:!1},[Ma]:{get:Object.getOwnPropertyDescriptor(MA.prototype,Ma)?.get,configurable:!0,enumerable:!1}});Object.defineProperty(Object.getOwnPropertyDescriptor(MA.prototype,Symbol.iterator)?.value,"name",{value:"entries",configurable:!0});var Hr=class MW{constructor(t){RW.add(this);let r=$_e(t);if(r&&typeof r=="object"&&QB in r){$1.set(this,{getImpl:r[QB]});return}let n=eve(r);$1.set(this,{getImpl:()=>n})}append(t,r){if(yn(this),arguments.length<2)throw Ca('The "name" and "value" arguments must be specified');On(this).append(zt(t),zt(r))}delete(t){if(yn(this),arguments.length<1)throw Ca('The "name" argument must be specified');On(this).delete(zt(t))}get(t){if(yn(this),arguments.length<1)throw Ca('The "name" argument must be specified');return On(this).get(zt(t))}getAll(t){if(yn(this),arguments.length<1)throw Ca('The "name" argument must be specified');return On(this).getAll(zt(t))}has(t){if(yn(this),arguments.length<1)throw Ca('The "name" argument must be specified');return On(this).has(zt(t))}set(t,r){if(yn(this),arguments.length<2)throw Ca('The "name" and "value" arguments must be specified');On(this).set(zt(t),zt(r))}sort(){yn(this),On(this).sort()}entries(){return yn(this),new MA(Array.from(On(this)))}keys(){return yn(this),new MA(Array.from(On(this).keys()))}values(){return yn(this),new MA(Array.from(On(this).values()))}forEach(t,r){if(yn(this),typeof t!="function")throw OA('The "callback" argument must be of type function. Received '+(t===void 0?"undefined":typeof t),"ERR_INVALID_ARG_TYPE");for(let[n,i]of On(this))t.call(r,i,n,this)}toString(){return yn(this),On(this).toString()}get size(){return yn(this),K_e(On(this))}[To](t,r,n){if(yn(this),t<0)return"[Object]";let i=typeof n=="function"?o=>n(o,r):o=>JSON.stringify(o),s=Array.from(On(this)).map(([o,a])=>`${i(o)} => ${i(a)}`);return`URLSearchParams ${TW(s,r,"{}")}`}get[Ma](){return this!==MW.prototype&&yn(this),H_e}};for(let e of q_e)Object.defineProperty(Hr.prototype,e,{value:Hr.prototype[e],writable:!0,configurable:!0,enumerable:!0});for(let e of G_e)Object.defineProperty(Hr.prototype,e,{value:Hr.prototype[e],writable:!0,configurable:!0,enumerable:!0});for(let e of["sort","entries","forEach","keys","values","toString"])Object.defineProperty(Hr.prototype,e,{value:Hr.prototype[e],writable:!0,configurable:!0,enumerable:!0});Object.defineProperties(Hr.prototype,{size:{get:Object.getOwnPropertyDescriptor(Hr.prototype,"size")?.get,configurable:!0,enumerable:!0},[Symbol.iterator]:{value:Hr.prototype.entries,writable:!0,configurable:!0,enumerable:!1},[To]:{value:Hr.prototype[To],writable:!0,configurable:!0,enumerable:!1},[Ma]:{get:Object.getOwnPropertyDescriptor(Hr.prototype,Ma)?.get,configurable:!0,enumerable:!1}});function ive(e){if(typeof e!="function"||e.__secureExecBootstrapStub===!0)return!1;try{return String(new e("./child.mjs","file:///root/base/entry.mjs").href)==="file:///root/base/child.mjs"}catch{return!1}}function sve(e){return e.endsWith("/")?e:`${e}/`}function ove(e,t){let r=String(e??"");if(!r.startsWith("file:"))return{input:r,base:t};let n=/^file:(\.\.?(?:\/[^?#]*)?)([?#].*)?$/.exec(r);if(!n)return{input:r,base:t};let i=n[1],s=n[2]??"",o=typeof t>"u"?"file:///":String(t);try{let a=new globalThis.URL(o);if(a.protocol!=="file:")return{input:r,base:t};let A=a.pathname||"/";A.startsWith("/")||(A=`/${A}`);let f=A.endsWith("/")?A:qr.posix.dirname(A),l=qr.posix.resolve(f,i);return{input:`file://${i==="."||i===".."||i.endsWith("/")?sve(l):l}${s}`,base:void 0}}catch{return{input:r,base:t}}}var vG=typeof Cu?.URL=="function"?Cu.URL:typeof Cu?.default?.URL=="function"?Cu.default.URL:globalThis.URL,RG=ive(vG)?vG:class FW{constructor(t,r){let n=String(t??""),i=/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(n);if(!i&&typeof r>"u")throw new TypeError(`Invalid URL: ${n}`);let s=n;if(!i){let N=new FW(r);if(N.protocol==="file:"){let O=n.indexOf("?"),x=n.indexOf("#"),G=O===-1?n.length:O,Y=x===-1?n.length:x,X=Math.min(G,Y),Z=n.slice(0,X),j=n.slice(X),se=N.pathname||"/";se.startsWith("/")||(se=`/${se}`);let ie=se.endsWith("/")?se:qr.posix.dirname(se),ce=qr.posix.resolve(ie,Z);(Z.endsWith("/")||/(^|\/)\.\.?$/.test(Z))&&!ce.endsWith("/")&&(ce+="/"),s=`file://${ce}${j}`}else s=String(N.href).replace(/\/[^/]*$/,"/")+n}let o=s.indexOf("?"),a=s.indexOf("#"),A=o===-1?s.length:o,f=a===-1?s.length:a,l=Math.min(A,f),p=o===-1?"":s.slice(o,f),I=a===-1?"":s.slice(a);if(s.startsWith("file:")){let N=s.slice(5,l);N.startsWith("//")&&(N=/^\/\/[^/]*(.*)$/.exec(N)?.[1]||"/"),N.startsWith("/")||(N=`/${N}`),this.protocol="file:",this.hostname="",this.port="",this.pathname=N||"/",this.search=p,this.hash=I,this.host="",this.href=`file://${this.pathname}${this.search}${this.hash}`,this.origin="null",this.searchParams=new Hr(this.search);let O=()=>{let x=this.searchParams.toString();this.search=x?`?${x}`:"",this.href=`file://${this.pathname}${this.search}${this.hash}`};for(let x of["append","delete","set","sort"]){let G=this.searchParams[x]?.bind(this.searchParams);G&&(this.searchParams[x]=(...Y)=>{let X=G(...Y);return O(),X})}return}let S=s.match(/^(\w+:)\/\/([^/:?#]+)(:\d+)?(.*)$/);this.protocol=S?.[1]||"",this.hostname=S?.[2]||"",this.port=(S?.[3]||"").slice(1),this.pathname=(S?.[4]||"/").split("?")[0].split("#")[0]||"/",this.search=s.includes("?")?"?"+s.split("?")[1].split("#")[0]:"",this.hash=s.includes("#")?"#"+s.split("#")[1]:"",this.host=this.hostname+(this.port?":"+this.port:""),this.href=this.protocol+"//"+this.host+this.pathname+this.search+this.hash,this.origin=this.protocol+"//"+this.host,this.searchParams=new Hr(this.search);let _=()=>{let N=this.searchParams.toString();this.search=N?`?${N}`:"",this.href=this.protocol+"//"+this.host+this.pathname+this.search+this.hash};for(let N of["append","delete","set","sort"]){let O=this.searchParams[N]?.bind(this.searchParams);O&&(this.searchParams[N]=(...x)=>{let G=O(...x);return _(),G})}}toString(){return this.href}},Cn=(Ea=class{constructor(e,t){if(kq(this,Ot),kq(this,Ig),arguments.length<1)throw Ca('The "url" argument must be specified');let r=ove(zt(e),arguments.length>=2?zt(t):void 0);try{Uq(this,Ot,r.base!==void 0?new RG(r.input,r.base):new RG(r.input))}catch{throw W_e()}}static canParse(e,t){if(arguments.length<1)throw Ca('The "url" argument must be specified');try{return arguments.length>=2?new Ea(e,t):new Ea(e),!0}catch{return!1}}static createObjectURL(e){if(typeof Nl>"u"||!(e instanceof Nl))throw OA('The "obj" argument must be an instance of Blob. Received '+(e===null?"null":typeof e),"ERR_INVALID_ARG_TYPE");let t=`blob:nodedata:${nve()}`;return _G().set(t,e),t}static revokeObjectURL(e){if(arguments.length<1)throw Ca('The "url" argument must be specified');typeof e=="string"&&_G().delete(e)}get href(){if(!(this instanceof Ea))throw Om();return Vt(this,Ot).href}set href(e){Vt(this,Ot).href=zt(e)}get origin(){return Vt(this,Ot).origin}get protocol(){return Vt(this,Ot).protocol}set protocol(e){Vt(this,Ot).protocol=zt(e)}get username(){return Vt(this,Ot).username}set username(e){Vt(this,Ot).username=zt(e)}get password(){return Vt(this,Ot).password}set password(e){Vt(this,Ot).password=zt(e)}get host(){return Vt(this,Ot).host}set host(e){Vt(this,Ot).host=zt(e)}get hostname(){return Vt(this,Ot).hostname}set hostname(e){Vt(this,Ot).hostname=zt(e)}get port(){return Vt(this,Ot).port}set port(e){Vt(this,Ot).port=zt(e)}get pathname(){return Vt(this,Ot).pathname}set pathname(e){Vt(this,Ot).pathname=zt(e)}get search(){if(!(this instanceof Ea))throw Om();return Vt(this,Ot).search}set search(e){Vt(this,Ot).search=zt(e)}get searchParams(){return Vt(this,Ig)||Uq(this,Ig,new Hr({[QB]:()=>Vt(this,Ot).searchParams})),Vt(this,Ig)}get hash(){return Vt(this,Ot).hash}set hash(e){Vt(this,Ot).hash=zt(e)}toString(){if(!(this instanceof Ea))throw Om();return Vt(this,Ot).href}toJSON(){if(!(this instanceof Ea))throw Om();return Vt(this,Ot).href}[To](e,t,r){let n=this.constructor===Ea?"URL":this.constructor.name;if(e<0)return`${n} {}`;let i=typeof r=="function"?o=>r(o,t):o=>JSON.stringify(o),s=[`${n} {`,` href: ${i(this.href)},`,` origin: ${i(this.origin)},`,` protocol: ${i(this.protocol)},`,` username: ${i(this.username)},`,` password: ${i(this.password)},`,` host: ${i(this.host)},`,` hostname: ${i(this.hostname)},`,` port: ${i(this.port)},`,` pathname: ${i(this.pathname)},`,` search: ${i(this.search)},`,` searchParams: ${this.searchParams[To](e-1,void 0,r)},`,` hash: ${i(this.hash)}`];return t?.showHidden&&(s[s.length-1]+=",",s.push(` [Symbol(context)]: ${rve(this,r,t)}`)),s.push("}"),s.join(` -`)}get[Ma](){return"URL"}},Ot=new WeakMap,Ig=new WeakMap,Ea);for(let e of["toString","toJSON"])Object.defineProperty(Cn.prototype,e,{value:Cn.prototype[e],writable:!0,configurable:!0,enumerable:!0});for(let e of["href","protocol","username","password","host","hostname","port","pathname","search","hash","origin","searchParams"]){let t=Object.getOwnPropertyDescriptor(Cn.prototype,e);t&&(t.enumerable=!0,Object.defineProperty(Cn.prototype,e,t))}Object.defineProperties(Cn.prototype,{[To]:{value:Cn.prototype[To],writable:!0,configurable:!0,enumerable:!1},[Ma]:{get:Object.getOwnPropertyDescriptor(Cn.prototype,Ma)?.get,configurable:!0,enumerable:!1}});for(let e of["canParse","createObjectURL","revokeObjectURL"])Object.defineProperty(Cn,e,{value:Cn[e],writable:!0,configurable:!0,enumerable:!0});function ave(e=globalThis){Object.defineProperty(e,"URL",{value:Cn,writable:!0,configurable:!0,enumerable:!1}),Object.defineProperty(e,"URLSearchParams",{value:Hr,writable:!0,configurable:!0,enumerable:!1})}var y1,Ave=(y1=class{},y(y1,"builtinModules",["assert","async_hooks","buffer","child_process","console","cluster","constants","crypto","dgram","diagnostics_channel","domain","dns","dns/promises","events","fs","fs/promises","http","http2","https","inspector","module","net","os","path","path/posix","path/win32","perf_hooks","process","punycode","querystring","readline","repl","sqlite","stream","stream/consumers","stream/promises","stream/web","string_decoder","sys","timers","timers/promises","trace_events","tls","tty","url","util","util/types","v8","wasi","worker_threads","zlib","vm"]),y1),fve=Ave.builtinModules,uve={clearImmediate:globalThis.clearImmediate??function(){},clearInterval:globalThis.clearInterval??function(){},clearTimeout:globalThis.clearTimeout??function(){},setImmediate:globalThis.setImmediate??function(e,...t){return globalThis.setTimeout?.(()=>e(...t),0)},setInterval:globalThis.setInterval??function(e,t,...r){return globalThis.setTimeout?.(()=>e(...r),t??0)},setTimeout:globalThis.setTimeout??function(){}};function cve(e){return e&&typeof e=="object"&&e.default!=null?e.default:e}function Rs(e){let t=cve(e);return t==null||typeof t=="function"?t:typeof t=="object"?{...t}:t}function No(e,t,r){e!=null&&typeof e[t]>"u"&&(e[t]=r)}function lve(e){return typeof e=="string"&&e.length>1&&e.endsWith("/")?e.slice(0,-1):e}var kA=Rs(Fl);No(kA,"constants",dY);No(kA,"kMaxLength",ql);No(kA,"kStringMaxLength",Kg);No(kA,"Blob",globalThis.Blob);No(kA,"File",globalThis.File);var kW=Rs(vI),Ss=Rs(vCe),i1=null,DG=!1;function hve(){return DG||(DG=!0,i1=typeof Ss=="function"?Ss:Ss?.EventEmitter,typeof i1=="function"?(Object.assign(i1.prototype,Ql.EventEmitter.prototype),Object.assign(Ql.EventEmitter,Ss,Ql),Ss=Ql.EventEmitter,Ss.EventEmitter=Ss):Ss={...Ss,...Ql}),Ss}var qr=Rs(Ug);qr?.posix||(qr.posix=Rs(Ug?.posix??Ug?.default?.posix)??qr);qr?.win32||(qr.win32=Rs(Ug?.win32??Ug?.default?.win32)??qr);if(qr?.normalize){let e=qr.normalize.bind(qr);qr.normalize=function(t){return lve(e(t))}}var dve=Rs(RCe),gve=Rs(F0),jt=Rs(qt);typeof jt?.Stream=="function"&&(Object.assign(jt.Stream,jt),jt=jt.Stream,jt.Stream=jt,Object.defineProperty(jt,Symbol.hasInstance,{configurable:!0,value:t=>!t||typeof t!="object"&&typeof t!="function"?!1:typeof jt.Readable=="function"&&t instanceof jt.Readable||typeof jt.Writable=="function"&&t instanceof jt.Writable||typeof jt.Duplex=="function"&&t instanceof jt.Duplex||typeof jt.Transform=="function"&&t instanceof jt.Transform||typeof jt.PassThrough=="function"&&t instanceof jt.PassThrough}));function HB(e){!e||typeof e[Symbol.asyncIterator]=="function"||Object.defineProperty(e,Symbol.asyncIterator,{configurable:!0,value:function(){let t=this,r=[],n=[],i=!1,s=null,o=()=>{for(;n.length>0;){if(s){n.shift()(Promise.reject(s));continue}if(r.length>0){n.shift()(Promise.resolve({done:!1,value:r.shift()}));continue}if(i){n.shift()(Promise.resolve({done:!0,value:void 0}));continue}break}},a=l=>{r.push(l),o()},A=()=>{i=!0,o()},f=l=>{s=l,i=!0,o()};return t.on?.("data",a),t.on?.("end",A),t.on?.("close",A),t.on?.("error",f),t.resume?.(),{next(){return s?Promise.reject(s):r.length>0?Promise.resolve({done:!1,value:r.shift()}):i?Promise.resolve({done:!0,value:void 0}):new Promise(l=>{n.push(l)})},return(){return i=!0,t.off?.("data",a),t.off?.("end",A),t.off?.("close",A),t.off?.("error",f),o(),Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}}}})}HB(jt?.Readable?.prototype);HB(jt?.PassThrough?.prototype);HB(jt?.Transform?.prototype);HB(jt?.Duplex?.prototype);No(jt,"isReadable",e=>!!e&&e.readable!==!1&&e.destroyed!==!0);No(jt,"isErrored",e=>e?.errored!=null);No(jt,"isDisturbed",e=>!!(e?.locked||e?.disturbed===!0||e?.readableDidRead===!0));var pve=Rs(DCe),xi=Rs(Cu),TG=!1;function Eve(){return TG||(TG=!0,xi.URL=Cn,xi.URLSearchParams=Hr,xi.fileURLToPath=rY,xi.pathToFileURL=tY,xi?.default&&typeof xi.default=="object"&&(xi.default.URL=Cn,xi.default.URLSearchParams=Hr,xi.default.fileURLToPath=rY,xi.default.pathToFileURL=tY)),xi}function yve(e){return String(e).replace(/^node:/,"")}var UW=null;function xW(e){let t=yve(e),r=UW;if(Array.isArray(r)){let n=String(t??e).replace(/^node:/,"").split("/")[0];if(!r.includes(n))throw iu(e)}return t}et("__agentOSInitJsRuntime",function(e){UW=Array.isArray(e)?e.map(t=>String(t).replace(/^node:/,"").split("/")[0]):null});function mve(e){switch(xW(e)){case"assert":return globalThis.__secureExecBuiltinAssertModule;case"async_hooks":return CY;case"buffer":return No(kA,"Blob",globalThis.Blob),No(kA,"File",globalThis.File),kA;case"cluster":throw iu(e);case"crypto":return va;case"diagnostics_channel":return LQe;case"domain":throw iu(e);case"http":return _httpModule;case"http2":return _http2Module;case"events":return hve();case"fs":return _fsModule;case"fs/promises":return _fsModule.promises;case"os":return _osModule;case"path":return qr;case"path/posix":return qr.posix;case"path/win32":return qr.win32;case"perf_hooks":return VQe;case"process":return wV;case"punycode":return dve;case"querystring":return gve;case"readline":return{createInterface(r={}){let n=r.input??null,i=r.output??null,s=new Map,o=!1,a=!1,A="",f=[],l=null,p=[],I=new _u,S=(j,...se)=>{let ie=s.get(j)??[];for(let ce of[...ie])ce(...se)},_=j=>{if(p.length>0){p.shift()(j);return}if(l){let se=l;l=null,se({done:!1,value:j});return}f.push(j)},N=j=>{S("line",j),_(j)},O=()=>{let j=A.indexOf(` -`);for(;j!==-1;){let se=A.slice(0,j);se.endsWith("\r")&&(se=se.slice(0,-1)),A=A.slice(j+1),N(se),j=A.indexOf(` -`)}},x=()=>{!n||typeof n.off!="function"||(n.off("data",G),n.off("end",Y))},G=j=>{o||(typeof j=="string"?A+=j:j instanceof Uint8Array?A+=I.decode(j,{stream:!0}):j!=null&&(A+=String(j)),O())},Y=()=>{if(a)return;a=!0;let j=I.decode();j&&(A+=j),O(),A.length>0&&(N(A),A=""),Z.close()};n&&typeof n.on=="function"&&(n.on("data",G),n.on("end",Y),typeof n.resume=="function"&&n.resume());let X={next(){return f.length>0?Promise.resolve({done:!1,value:f.shift()}):o||a?Promise.resolve({done:!0,value:void 0}):new Promise(j=>{l=j})},return(){return Z.close(),Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}},Z={addListener(j,se){return this.on(j,se)},on(j,se){let ie=s.get(j)??[];return ie.push(se),s.set(j,ie),this},once(j,se){let ie=(...ce)=>{this.off(j,ie),se(...ce)};return this.on(j,ie)},off(j,se){let ie=s.get(j)??[];return s.set(j,ie.filter(ce=>ce!==se)),this},removeListener(j,se){return this.off(j,se)},close(){if(!o){for(o=!0,x();p.length>0;)p.shift()("");if(l){let j=l;l=null,j({done:!0,value:void 0})}S("close")}},question(j,se){i&&typeof i.write=="function"&&j&&i.write(String(j));let ie=()=>f.length>0?Promise.resolve(f.shift()):o||a?Promise.resolve(""):new Promise(ce=>{p.push(ce)});if(typeof se=="function"){ie().then(ce=>{se(ce)});return}return ie()},[Symbol.asyncIterator](){return X}};return Z}};case"repl":throw iu(e);case"stream":return jt;case"stream/consumers":return Xm;case"stream/promises":return vY;case"string_decoder":return pve;case"stream/web":return{ReadableStream:globalThis.ReadableStream,WritableStream:globalThis.WritableStream,TransformStream:globalThis.TransformStream,TextEncoderStream:globalThis.TextEncoderStream,TextDecoderStream:globalThis.TextDecoderStream,CompressionStream:globalThis.CompressionStream,DecompressionStream:globalThis.DecompressionStream};case"timers":return uve;case"timers/promises":return Jm;case"trace_events":throw iu(e);case"url":return Eve();case"sys":return Km(globalThis.__secureExecBuiltinUtilModule);case"util":return Km(globalThis.__secureExecBuiltinUtilModule);case"util/types":return Km(globalThis.__secureExecBuiltinUtilModule).types;case"child_process":return _childProcessModule;case"console":return vQe;case"constants":return kW;case"dns":return _dnsModule;case"dns/promises":return _dnsModule.promises;case"net":return _netModule;case"tls":return _tlsModule;case"tty":return kQe;case"dgram":return _dgramModule;case"sqlite":return _sqliteModule;case"https":return _httpsModule;case"inspector":throw iu(e);case"module":return _moduleModule;case"wasi":throw iu(e);case"zlib":return globalThis.__secureExecBuiltinZlibModule;case"v8":return $Qe;case"vm":return rwe;case"worker_threads":return TQe;default:{let r=new Error(`Cannot find module '${e}'`);throw r.code="MODULE_NOT_FOUND",r}}}function oR(e){let t=new Error(`${e} is not supported in sandbox`);return t.code="ERR_NOT_IMPLEMENTED",t}function lu(e){throw oR(`crypto.${e}`)}var Mg=Symbol("secureExecCryptoKey"),aR=Symbol("secureExecCrypto"),AR=Symbol("secureExecSubtle"),LW="ERR_INVALID_THIS",qB="ERR_ILLEGAL_CONSTRUCTOR";function Yl(e,t){let r=new TypeError(e);return r.code=t,r}var Bve=class extends Error{constructor(e="",t="Error"){super(e),this.name=String(t),this.code=0}};function NG(e,t,r){let n=new Error(r);return n.name=e,n.code=t,n}function s1(e){if(!(e instanceof uR)||e._token!==aR)throw Yl('Value of "this" must be of type Crypto',LW)}function Li(e){if(!(e instanceof fR)||e._token!==AR)throw Yl('Value of "this" must be of type SubtleCrypto',LW)}function Ive(e){return!ArrayBuffer.isView(e)||e instanceof DataView?!1:e instanceof Int8Array||e instanceof Int16Array||e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint16Array||e instanceof Uint32Array||e instanceof Uint8ClampedArray||e instanceof BigInt64Array||e instanceof BigUint64Array||Se.Buffer.isBuffer(e)}function Gn(e){return typeof e=="string"?Se.Buffer.from(e).toString("base64"):e instanceof ArrayBuffer?Se.Buffer.from(new Uint8Array(e)).toString("base64"):ArrayBuffer.isView(e)?Se.Buffer.from(new Uint8Array(e.buffer,e.byteOffset,e.byteLength)).toString("base64"):Se.Buffer.from(e).toString("base64")}function nu(e){let t=Se.Buffer.from(e,"base64");return t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength)}function e2(e){return typeof e=="string"?{name:e}:e??{}}function Pi(e){let t={...e2(e)},r=t.hash,n=t.publicExponent,i=t.iv,s=t.additionalData,o=t.salt,a=t.info,A=t.context,f=t.label,l=t.public;return r&&(t.hash=e2(r)),n&&ArrayBuffer.isView(n)&&(t.publicExponent=Se.Buffer.from(new Uint8Array(n.buffer,n.byteOffset,n.byteLength)).toString("base64")),i&&(t.iv=Gn(i)),s&&(t.additionalData=Gn(s)),o&&(t.salt=Gn(o)),a&&(t.info=Gn(a)),A&&(t.context=Gn(A)),f&&(t.label=Gn(f)),l&&typeof l=="object"&&"_keyData"in l&&(t.public=l._keyData),t}var nY,Gg=(nY=Mg,class{constructor(e,t){y(this,"type");y(this,"extractable");y(this,"algorithm");y(this,"usages");y(this,"_keyData");y(this,"_pem");y(this,"_jwk");y(this,"_raw");y(this,"_sourceKeyObjectData");y(this,nY);if(t!==Mg||!e)throw Yl("Illegal constructor",qB);this.type=e.type,this.extractable=e.extractable,this.algorithm=e.algorithm,this.usages=e.usages,this._keyData=e,this._pem=e._pem,this._jwk=e._jwk,this._raw=e._raw,this._sourceKeyObjectData=e._sourceKeyObjectData,this[Mg]=!0}});Object.defineProperty(Gg.prototype,Symbol.toStringTag,{value:"CryptoKey",configurable:!0});Object.defineProperty(Gg,Symbol.hasInstance,{value(e){return!!(e&&typeof e=="object"&&(e[Mg]===!0||"_keyData"in e&&e[Symbol.toStringTag]==="CryptoKey"))},configurable:!0});function bl(e){let t=globalThis.CryptoKey;if(typeof t=="function"&&t.prototype&&t.prototype!==Gg.prototype){let r=Object.create(t.prototype);return r.type=e.type,r.extractable=e.extractable,r.algorithm=e.algorithm,r.usages=e.usages,r._keyData=e,r._pem=e._pem,r._jwk=e._jwk,r._raw=e._raw,r._sourceKeyObjectData=e._sourceKeyObjectData,r}return new Gg(e,Mg)}function Oi(e){if(typeof _cryptoSubtle>"u")throw new Error("crypto.subtle is not supported in sandbox");return _cryptoSubtle.applySync(void 0,[JSON.stringify(e)])}var fR=class{constructor(e){y(this,"_token");if(e!==AR)throw Yl("Illegal constructor",qB);this._token=e}digest(e,t){return Li(this),Promise.resolve().then(()=>{let r=JSON.parse(Oi({op:"digest",algorithm:e2(e).name,data:Gn(t)}));return nu(r.data)})}generateKey(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"generateKey",algorithm:Pi(e),extractable:t,usages:Array.from(r)}));return"publicKey"in n&&"privateKey"in n?{publicKey:bl(n.publicKey),privateKey:bl(n.privateKey)}:bl(n.key)})}importKey(e,t,r,n,i){return Li(this),Promise.resolve().then(()=>{let s=JSON.parse(Oi({op:"importKey",format:e,keyData:e==="jwk"?t:Gn(t),algorithm:Pi(r),extractable:n,usages:Array.from(i)}));return bl(s.key)})}exportKey(e,t){return Li(this),Promise.resolve().then(()=>{let r=JSON.parse(Oi({op:"exportKey",format:e,key:t._keyData}));return e==="jwk"?r.jwk:nu(r.data??"")})}encrypt(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"encrypt",algorithm:Pi(e),key:t._keyData,data:Gn(r)}));return nu(n.data)})}decrypt(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"decrypt",algorithm:Pi(e),key:t._keyData,data:Gn(r)}));return nu(n.data)})}sign(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"sign",algorithm:Pi(e),key:t._keyData,data:Gn(r)}));return nu(n.data)})}verify(e,t,r,n){return Li(this),Promise.resolve().then(()=>JSON.parse(Oi({op:"verify",algorithm:Pi(e),key:t._keyData,signature:Gn(r),data:Gn(n)})).result)}deriveBits(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"deriveBits",algorithm:Pi(e),baseKey:t._keyData,length:r}));return nu(n.data)})}deriveKey(e,t,r,n,i){return Li(this),Promise.resolve().then(()=>{let s=JSON.parse(Oi({op:"deriveKey",algorithm:Pi(e),baseKey:t._keyData,derivedKeyAlgorithm:Pi(r),extractable:n,usages:Array.from(i)}));return bl(s.key)})}wrapKey(e,t,r,n){return Li(this),Promise.resolve().then(()=>{let i=JSON.parse(Oi({op:"wrapKey",format:e,key:t._keyData,wrappingKey:r._keyData,wrapAlgorithm:Pi(n)}));return nu(i.data)})}unwrapKey(e,t,r,n,i,s,o){return Li(this),Promise.resolve().then(()=>{let a=JSON.parse(Oi({op:"unwrapKey",format:e,wrappedKey:Gn(t),unwrappingKey:r._keyData,unwrapAlgorithm:Pi(n),unwrappedKeyAlgorithm:Pi(i),extractable:s,usages:Array.from(o)}));return bl(a.key)})}},PW=new fR(AR),uR=class{constructor(e){y(this,"_token");if(e!==aR)throw Yl("Illegal constructor",qB);this._token=e}get subtle(){return s1(this),PW}getRandomValues(e){if(s1(this),!Ive(e))throw NG("TypeMismatchError",17,"The data argument must be an integer-type TypedArray");if(typeof _cryptoRandomFill>"u"&&lu("getRandomValues"),e.byteLength>65536)throw NG("QuotaExceededError",22,`The ArrayBufferView's byte length (${e.byteLength}) exceeds the number of bytes of entropy available via this API (65536)`);let t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);try{let r=_cryptoRandomFill.applySync(void 0,[t.byteLength]),n=Se.Buffer.from(r,"base64");if(n.byteLength!==t.byteLength)throw new Error("invalid host entropy size");return t.set(n),e}catch{lu("getRandomValues")}}randomUUID(){s1(this),typeof _cryptoRandomUUID>"u"&&lu("randomUUID");try{let e=_cryptoRandomUUID.applySync(void 0,[]);if(typeof e!="string")throw new Error("invalid host uuid");return e}catch{lu("randomUUID")}}},bve=new uR(aR),_l=bve;function Cve(e){let t=[];return{update(r,n){let i=typeof r=="string"?Se.Buffer.from(r,n||"utf8"):Se.Buffer.from(r);return t.push(i),this},digest(r){typeof _cryptoHashDigest>"u"&&lu("createHash");let n=t.length===1?t[0]:Se.Buffer.concat(t),i=_cryptoHashDigest.applySync(void 0,[String(e),n.toString("base64")]),s=Se.Buffer.from(String(i||""),"base64");return r?s.toString(r):s}}}function OW(e){if(Wl(e)){if(e.type!=="secret")throw new TypeError("Symmetric crypto operations require a secret KeyObject");return Se.Buffer.from(String(e._serialized.raw||""),"base64")}return e&&typeof e=="object"&&e[Symbol.toStringTag]==="CryptoKey"&&typeof e._raw=="string"?Se.Buffer.from(String(e._raw||""),"base64"):typeof e=="string"?Se.Buffer.from(e):Rt(e)}function Qve(e,t){let r=[],n=OW(t);return{update(i,s){let o=typeof i=="string"?Se.Buffer.from(i,s||"utf8"):Se.Buffer.from(i);return r.push(o),this},digest(i){typeof _cryptoHmacDigest>"u"&&lu("createHmac");let s=r.length===1?r[0]:Se.Buffer.concat(r),o=_cryptoHmacDigest.applySync(void 0,[String(e),n.toString("base64"),s.toString("base64")]),a=Se.Buffer.from(String(o||""),"base64");return i?a.toString(i):a}}}var Fg=Symbol("secureExecBuiltinKeyObject");function t2(e){return Se.Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function Rt(e,t=void 0){return Se.Buffer.isBuffer(e)?Se.Buffer.from(e):typeof e=="string"?Se.Buffer.from(e,t||"utf8"):e instanceof ArrayBuffer?Se.Buffer.from(new Uint8Array(e)):ArrayBuffer.isView(e)?Se.Buffer.from(new Uint8Array(e.buffer,e.byteOffset,e.byteLength)):Se.Buffer.from(e??[])}function Qa(e,t=void 0){return t?e.toString(t):e}function Wl(e){return!!(e&&typeof e=="object"&&(e[Fg]===!0||e[Symbol.toStringTag]==="KeyObject"&&"_serialized"in e))}function vs(e){if(Wl(e))return e._serialized;if(e&&typeof e=="object"&&e[Symbol.toStringTag]==="CryptoKey"&&"_keyData"in e)return e._keyData;if(typeof e=="bigint")return{__type:"bigint",value:e.toString()};if(t2(e))return{__type:"buffer",value:Rt(e).toString("base64")};if(Array.isArray(e))return e.map(t=>vs(t));if(e&&typeof e=="object"){let t={};for(let[r,n]of Object.entries(e))n!==void 0&&(t[r]=vs(n));return t}return e}function Yg(e){if(Array.isArray(e))return e.map(r=>Yg(r));if(!e||typeof e!="object")return e;if(e.__type==="buffer")return Se.Buffer.from(String(e.value||""),"base64");if(e.__type==="bigint")return BigInt(String(e.value||"0"));if(e.__type==="keyObject")return Rl(e.value);let t={};for(let[r,n]of Object.entries(e))t[r]=Yg(n);return t}function HW(e){if(Wl(e))return e._serialized;if(e&&typeof e=="object"&&e[Symbol.toStringTag]==="CryptoKey"&&"_keyData"in e)return e._keyData;if(e&&typeof e=="object"&&!Array.isArray(e)&&"key"in e){let{key:t,...r}=e,n=HW(t);return n&&typeof n=="object"&&!Array.isArray(n)&&"type"in n&&("pem"in n||"raw"in n)?{...n,...Object.fromEntries(Object.entries(r).map(([i,s])=>[i,vs(s)]))}:{...Object.fromEntries(Object.entries(r).map(([i,s])=>[i,vs(s)])),key:vs(t)}}return vs(e)}function RA(e){return JSON.stringify(HW(e))}function o1(e){return JSON.stringify({hasOptions:e!==void 0,options:e===void 0?null:vs(e)})}function qW(e){return e==null?null:typeof e=="string"?e:typeof e=="object"&&e&&typeof e.name=="string"?e.name:String(e)}function pr(e,t,r){return typeof e>"u"&&lu(t),e.applySync(void 0,r)}function MG(e){return e&&typeof e=="object"&&e.kind==="buffer"?Se.Buffer.from(String(e.value||""),"base64"):e&&typeof e=="object"&&e.kind==="string"?String(e.value||""):Rl(e)}var iY,GB=(iY=Fg,class{constructor(e,t){y(this,"type");y(this,"asymmetricKeyType");y(this,"asymmetricKeyDetails");y(this,"symmetricKeySize");y(this,"_serialized");y(this,iY);if(t!==Fg||!e||typeof e!="object")throw Yl("Illegal constructor",qB);this.type=e.type,this.asymmetricKeyType=e.asymmetricKeyType,this.asymmetricKeyDetails=e.asymmetricKeyDetails,this.symmetricKeySize=e.raw?Se.Buffer.from(String(e.raw),"base64").length:void 0,this._serialized=e,this[Fg]=!0}export(e=void 0){if(this.type==="secret")return e&&e.format==="jwk"&&this._serialized.jwk?{...this._serialized.jwk}:Se.Buffer.from(String(this._serialized.raw||""),"base64");if(e==null||typeof e!="object"){let t=new TypeError('The "options" argument must be of type object. Received undefined');throw t.code="ERR_INVALID_ARG_TYPE",t}if(e.format==="jwk"&&this._serialized.jwk)return{...this._serialized.jwk};if(e.format&&e.format!=="pem")throw oR(`crypto.KeyObject.export(${e.format})`);return String(this._serialized.pem||"")}equals(e){return Wl(e)&&JSON.stringify(this._serialized)===JSON.stringify(e._serialized)}});Object.defineProperty(GB.prototype,Symbol.toStringTag,{value:"KeyObject",configurable:!0});Object.defineProperty(GB,Symbol.hasInstance,{value(e){return Wl(e)},configurable:!0});function Rl(e){return Wl(e)?e:new GB(e,Fg)}function wve(e){if(!e||typeof e!="object")return{};let t={};return"aad"in e&&e.aad!=null&&(t.aad=Rt(e.aad).toString("base64")),"authTag"in e&&e.authTag!=null&&(t.authTag=Rt(e.authTag).toString("base64")),"authTagLength"in e&&e.authTagLength!=null&&(t.authTagLength=Number(e.authTagLength)),"autoPadding"in e&&(t.autoPadding=!!e.autoPadding),t}var FG=class{constructor(e,t,r,n,i=void 0){y(this,"_mode");y(this,"_algorithm");y(this,"_key");y(this,"_iv");y(this,"_options");y(this,"_sessionId");y(this,"_authTag");this._mode=e,this._algorithm=String(t),this._key=OW(r),this._iv=n==null?null:Rt(n),this._options=wve(i),this._sessionId=null,this._authTag=null}_ensureSession(){return this._sessionId!=null?this._sessionId:(this._sessionId=Number(pr(_cryptoCipherivCreate,this._mode==="cipher"?"createCipheriv":"createDecipheriv",[this._mode,this._algorithm,this._key.toString("base64"),this._iv?this._iv.toString("base64"):null,Object.keys(this._options).length>0?JSON.stringify(this._options):null])),this._sessionId)}_assertMutable(e){if(this._sessionId!=null)throw oR(`crypto.${e} after update()`)}update(e,t=void 0,r=void 0){let n=Rt(e,t),i=pr(_cryptoCipherivUpdate,this._mode==="cipher"?"createCipheriv":"createDecipheriv",[this._ensureSession(),n.toString("base64")]);return Qa(Se.Buffer.from(String(i||""),"base64"),r)}final(e=void 0){let t=JSON.parse(String(pr(_cryptoCipherivFinal,this._mode==="cipher"?"createCipheriv":"createDecipheriv",[this._ensureSession()])||"{}"));return t.authTag&&(this._authTag=Se.Buffer.from(String(t.authTag),"base64")),Qa(Se.Buffer.from(String(t.data||""),"base64"),e)}setAAD(e,t=void 0){return this._assertMutable(this._mode==="cipher"?"createCipheriv":"createDecipheriv"),this._options.aad=Rt(e).toString("base64"),t&&typeof t=="object"&&t.authTagLength!=null&&(this._options.authTagLength=Number(t.authTagLength)),this}setAuthTag(e){return this._assertMutable("createDecipheriv"),this._authTag=Rt(e),this._options.authTag=this._authTag.toString("base64"),this}getAuthTag(){if(!this._authTag)throw new Error("Invalid state for operation getAuthTag");return Se.Buffer.from(this._authTag)}setAutoPadding(e=!0){return this._assertMutable(this._mode==="cipher"?"createCipheriv":"createDecipheriv"),this._options.autoPadding=!!e,this}},r2=class{constructor(e){y(this,"_algorithm");y(this,"_chunks");this._algorithm=e,this._chunks=[]}update(e,t=void 0){return this._chunks.push(Rt(e,t)),this}write(e,t=void 0){return this.update(e,t),!0}end(e=void 0,t=void 0){return e!==void 0&&this.update(e,t),this}_inputBuffer(){return this._chunks.length===0?Se.Buffer.alloc(0):this._chunks.length===1?this._chunks[0]:Se.Buffer.concat(this._chunks)}sign(e,t=void 0){let r=pr(_cryptoSign,"sign",[qW(this._algorithm),this._inputBuffer().toString("base64"),RA(e)]);return Qa(Se.Buffer.from(String(r||""),"base64"),t)}},kG=class extends r2{verify(e,t,r=void 0){let n=Rt(t,r);return!!pr(_cryptoVerify,"verify",[qW(this._algorithm),this._inputBuffer().toString("base64"),RA(e),n.toString("base64")])}};function Sve(e,t=void 0,r=void 0,n=void 0){let i=[];return typeof e=="string"?(i.push(Rt(e,typeof t=="string"?t:void 0)),r!==void 0?i.push(typeof r=="string"?Rt(r,typeof n=="string"?n:void 0):r):(typeof t=="number"||t2(t))&&i.push(t),i):(i.push(e),r!==void 0?i.push(r):(typeof t=="number"||t2(t))&&i.push(t),i)}var UG=typeof FinalizationRegistry=="function"?new FinalizationRegistry(e=>{try{pr(_cryptoDiffieHellmanSessionDestroy,"createDiffieHellman",[e])}catch{}}):null,bg=class{constructor(e){y(this,"_sessionId");this._sessionId=Number(pr(_cryptoDiffieHellmanSessionCreate,"createDiffieHellman",[JSON.stringify({type:e.type,name:e.name,args:(e.args||[]).map(t=>vs(t))})])),UG?.register(this,this._sessionId,this)}_destroySession(){if(this._sessionId==null)return;let e=this._sessionId;this._sessionId=null,UG?.unregister(this),pr(_cryptoDiffieHellmanSessionDestroy,"createDiffieHellman",[e])}dispose(){this._destroySession()}[Symbol.dispose||Symbol.for("Symbol.dispose")](){this._destroySession()}_call(e,t=[]){if(this._sessionId==null)throw new Error("Diffie-Hellman session has been destroyed");let r=JSON.parse(String(pr(_cryptoDiffieHellmanSessionCall,"createDiffieHellman",[this._sessionId,JSON.stringify({method:e,args:t.map(n=>vs(n))})])||"{}"));return r.hasResult?Yg(r.result):void 0}get verifyError(){let e=this._call("verifyError");return e==null?0:Number(e)}generateKeys(e=void 0){return Qa(Rt(this._call("generateKeys")),e)}computeSecret(e,t=void 0,r=void 0){let n=this._call("computeSecret",[Rt(e,t)]);return Qa(Rt(n),r)}getPrime(e=void 0){return Qa(Rt(this._call("getPrime")),e)}getGenerator(e=void 0){return Qa(Rt(this._call("getGenerator")),e)}getPublicKey(e=void 0){return Qa(Rt(this._call("getPublicKey")),e)}getPrivateKey(e=void 0){return Qa(Rt(this._call("getPrivateKey")),e)}setPrivateKey(e,t=void 0){this._call("setPrivateKey",[Rt(e,t)])}setPublicKey(e,t=void 0){this._call("setPublicKey",[Rt(e,t)])}},va={KeyObject:GB,DiffieHellman:bg,ECDH:bg,randomFillSync(e,t=0,r=void 0){let n=e instanceof ArrayBuffer?new Uint8Array(e):e;if(!ArrayBuffer.isView(n))throw new TypeError('The "buffer" argument must be an instance of ArrayBuffer, Buffer, TypedArray, or DataView');let i=Number(t)||0;if(!Number.isInteger(i)||i<0||i>n.byteLength)throw new RangeError('The value of "offset" is out of range');let s=r===void 0?n.byteLength-i:Number(r);if(!Number.isInteger(s)||s<0||i+s>n.byteLength)throw new RangeError('The value of "size" is out of range');let o=new Uint8Array(n.buffer,n.byteOffset+i,s);return _l.getRandomValues(o),e},randomFill(e,t,r,n){let i=t,s=r,o=n;if(typeof i=="function"?(o=i,i=0,s=void 0):typeof s=="function"&&(o=s,s=void 0),typeof o!="function")throw new TypeError('The "callback" argument must be of type function');try{let a=va.randomFillSync(e,i,s);queueMicrotask(()=>o(null,a))}catch(a){queueMicrotask(()=>o(a))}},createHash(e){return Cve(e)},createHmac(e,t){return Qve(e,t)},createCipheriv(e,t,r,n=void 0){return new FG("cipher",e,t,r,n)},createDecipheriv(e,t,r,n=void 0){return new FG("decipher",e,t,r,n)},createSign(e){return new r2(e)},createVerify(e){return new kG(e)},sign(e,t,r){let n=new r2(e);return n.update(t),n.sign(r)},verify(e,t,r,n){let i=new kG(e);return i.update(t),i.verify(r,n)},createPrivateKey(e){let t=pr(_cryptoCreateKeyObject,"createPrivateKey",["createPrivateKey",RA(e)]);return Rl(JSON.parse(String(t||"{}")))},createPublicKey(e){let t=pr(_cryptoCreateKeyObject,"createPublicKey",["createPublicKey",RA(e)]);return Rl(JSON.parse(String(t||"{}")))},createSecretKey(e){return Rl({type:"secret",raw:Rt(e).toString("base64")})},publicEncrypt(e,t){let r=pr(_cryptoAsymmetricOp,"publicEncrypt",["publicEncrypt",RA(e),Rt(t).toString("base64")]);return Se.Buffer.from(String(r||""),"base64")},publicDecrypt(e,t){let r=pr(_cryptoAsymmetricOp,"publicDecrypt",["publicDecrypt",RA(e),Rt(t).toString("base64")]);return Se.Buffer.from(String(r||""),"base64")},privateEncrypt(e,t){let r=pr(_cryptoAsymmetricOp,"privateEncrypt",["privateEncrypt",RA(e),Rt(t).toString("base64")]);return Se.Buffer.from(String(r||""),"base64")},privateDecrypt(e,t){let r=pr(_cryptoAsymmetricOp,"privateDecrypt",["privateDecrypt",RA(e),Rt(t).toString("base64")]);return Se.Buffer.from(String(r||""),"base64")},pbkdf2Sync(e,t,r,n,i){let s=pr(_cryptoPbkdf2,"pbkdf2Sync",[Rt(e).toString("base64"),Rt(t).toString("base64"),Number(r),Number(n),String(i)]);return Se.Buffer.from(String(s||""),"base64")},pbkdf2(e,t,r,n,i,s){let o=i,a=s;if(typeof o=="function"&&(a=o,o="sha1"),typeof a!="function")throw new TypeError('The "callback" argument must be of type function');queueMicrotask(()=>{try{a(null,va.pbkdf2Sync(e,t,r,n,o))}catch(A){a(A)}})},scryptSync(e,t,r,n=void 0){let i=pr(_cryptoScrypt,"scryptSync",[Rt(e).toString("base64"),Rt(t).toString("base64"),Number(r),JSON.stringify(vs(n||{}))]);return Se.Buffer.from(String(i||""),"base64")},scrypt(e,t,r,n,i){let s=n,o=i;if(typeof s=="function"&&(o=s,s=void 0),typeof o!="function")throw new TypeError('The "callback" argument must be of type function');queueMicrotask(()=>{try{o(null,va.scryptSync(e,t,r,s))}catch(a){o(a)}})},generateKeyPairSync(e,t=void 0){let r=JSON.parse(String(pr(_cryptoGenerateKeyPairSync,"generateKeyPairSync",[String(e),o1(t)])||"{}"));return{publicKey:MG(r.publicKey),privateKey:MG(r.privateKey)}},generateKeyPair(e,t,r){let n=t,i=r;if(typeof n=="function"&&(i=n,n=void 0),typeof i!="function")throw new TypeError('The "callback" argument must be of type function');queueMicrotask(()=>{try{let s=va.generateKeyPairSync(e,n);i(null,s.publicKey,s.privateKey)}catch(s){i(s)}})},generateKeySync(e,t=void 0){let r=JSON.parse(String(pr(_cryptoGenerateKeySync,"generateKeySync",[String(e),o1(t)])||"{}"));return Rl(r)},generatePrimeSync(e,t=void 0){let r=JSON.parse(String(pr(_cryptoGeneratePrimeSync,"generatePrimeSync",[Number(e),o1(t)])||"null"));return Yg(r)},generatePrime(e,t,r){let n=t,i=r;if(typeof n=="function"&&(i=n,n=void 0),typeof i!="function")throw new TypeError('The "callback" argument must be of type function');queueMicrotask(()=>{try{i(null,va.generatePrimeSync(e,n))}catch(s){i(s)}})},diffieHellman(e){let t=JSON.parse(String(pr(_cryptoDiffieHellman,"diffieHellman",[JSON.stringify(vs(e))])||"null"));return Rt(Yg(t))},getDiffieHellman(e){return new bg({type:"group",name:String(e)})},createDiffieHellman(e,t=void 0,r=void 0,n=void 0){return new bg({type:"dh",args:Sve(e,t,r,n)})},createECDH(e){return new bg({type:"ecdh",name:String(e)})},getFips(){return 0},getHashes(){return["md5","sha1","sha224","sha256","sha384","sha512"]},getCiphers(){return["aes-128-cbc","aes-128-ctr","aes-128-gcm","aes-192-cbc","aes-192-ctr","aes-192-gcm","aes-256-cbc","aes-256-ctr","aes-256-gcm","aes128","aes192","aes256"]},getCurves(){return["prime256v1","secp256k1","secp384r1","secp521r1"]},getRandomValues(e){return _l.getRandomValues(e)},randomBytes(e){let t=Math.max(0,Number(e)||0),r=new Uint8Array(t);return _l.getRandomValues(r),Se.Buffer.from(r)},randomUUID(){return _l.randomUUID()},get constants(){return kW},subtle:PW,webcrypto:_l},Dt=v2(R2(),1),n2=0,su=1,ya=2,Hn=64,ma=128,ou=512,au=1024,hu=class{constructor(e){y(this,"dev");y(this,"ino");y(this,"mode");y(this,"nlink");y(this,"uid");y(this,"gid");y(this,"rdev");y(this,"size");y(this,"blksize");y(this,"blocks");y(this,"atimeMs");y(this,"mtimeMs");y(this,"ctimeMs");y(this,"birthtimeMs");y(this,"atime");y(this,"mtime");y(this,"ctime");y(this,"birthtime");this.dev=e.dev??0,this.ino=e.ino??0,this.mode=e.mode,this.nlink=e.nlink??1,this.uid=e.uid??0,this.gid=e.gid??0,this.rdev=e.rdev??0,this.size=e.size,this.blksize=e.blksize??4096,this.blocks=e.blocks??Math.ceil(e.size/512);let t=e.atimeMs??Date.now(),r=e.mtimeMs??Date.now(),n=e.ctimeMs??Date.now();this.atimeMs=t+(e.atimeNsec??0)%1e6/1e6,this.mtimeMs=r+(e.mtimeNsec??0)%1e6/1e6,this.ctimeMs=n+(e.ctimeNsec??0)%1e6/1e6,this.birthtimeMs=e.birthtimeMs??Date.now(),this.atime=new Date(this.atimeMs),this.mtime=new Date(this.mtimeMs),this.ctime=new Date(this.ctimeMs),this.birthtime=new Date(this.birthtimeMs)}isFile(){return(this.mode&61440)===32768}isDirectory(){return(this.mode&61440)===16384}isSymbolicLink(){return(this.mode&61440)===40960}isBlockDevice(){return!1}isCharacterDevice(){return!1}isFIFO(){return!1}isSocket(){return!1}},i2=class{constructor(e,t,r=""){y(this,"name");y(this,"parentPath");y(this,"path");y(this,"_isDir");this.name=e,this._isDir=t,this.parentPath=r,this.path=r}isFile(){return!this._isDir}isDirectory(){return this._isDir}isSymbolicLink(){return!1}isBlockDevice(){return!1}isCharacterDevice(){return!1}isFIFO(){return!1}isSocket(){return!1}},xG=class{constructor(e){y(this,"path");y(this,"_entries",null);y(this,"_index",0);y(this,"_closed",!1);this.path=e}_load(){return this._entries===null&&(this._entries=$.readdirSync(this.path,{withFileTypes:!0})),this._entries}readSync(){if(this._closed)throw new Error("Directory handle was closed");let e=this._load();return this._index>=e.length?null:e[this._index++]}async read(){return this.readSync()}closeSync(){this._closed=!0}async close(){this.closeSync()}async*[Symbol.asyncIterator](){let e=this._load();for(let t of e){if(this._closed)return;yield t}this._closed=!0}},s2=64*1024,_ve=16*1024,LG=2**31-1;function GW(e){let t=new Error("The operation was aborted");return t.name="AbortError",t.code="ABORT_ERR",e!==void 0&&(t.cause=e),t}function o2(e){if(e!==void 0){if(e===null||typeof e!="object"||typeof e.aborted!="boolean"||typeof e.addEventListener!="function"||typeof e.removeEventListener!="function"){let t=new TypeError('The "signal" argument must be an instance of AbortSignal');throw t.code="ERR_INVALID_ARG_TYPE",t}return e}}function Sg(e){if(e?.aborted)throw GW(e.reason)}function Hm(){return new Promise(e=>process.nextTick(e))}function vve(e){let t=new Error(e);return t.code="ERR_INTERNAL_ASSERTION",t}function Na(e,t,r){let n=new RangeError(`The value of "${e}" is out of range. It must be ${t}. Received ${String(r)}`);return n.code="ERR_OUT_OF_RANGE",n}function YW(e){if(e===null)return"Received null";if(e===void 0)return"Received undefined";if(typeof e=="string")return`Received type string ('${e}')`;if(typeof e=="number")return`Received type number (${String(e)})`;if(typeof e=="boolean")return`Received type boolean (${String(e)})`;if(typeof e=="bigint")return`Received type bigint (${e.toString()}n)`;if(typeof e=="symbol")return`Received type symbol (${String(e)})`;if(typeof e=="function")return e.name?`Received function ${e.name}`:"Received function";if(Array.isArray(e))return"Received an instance of Array";if(e&&typeof e=="object"){let t=e.constructor?.name;if(t)return`Received an instance of ${t}`}return`Received type ${typeof e} (${String(e)})`}function It(e,t,r){let n=new TypeError(`The "${e}" argument must be ${t}. ${YW(r)}`);return n.code="ERR_INVALID_ARG_TYPE",n}function WW(e,t){let r=new TypeError(`The argument '${e}' ${t}`);return r.code="ERR_INVALID_ARG_VALUE",r}function Rve(e){let t=typeof e=="string"?`'${e}'`:e===void 0?"undefined":e===null?"null":String(e),r=new TypeError(`The argument 'encoding' is invalid encoding. Received ${t}`);return r.code="ERR_INVALID_ARG_VALUE",r}function a1(e,t){if(typeof e=="string")return Dt.Buffer.from(e,t??"utf8");if(Dt.Buffer.isBuffer(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);if(e instanceof Uint8Array)return e;if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);throw It("data","a string, Buffer, TypedArray, or DataView",e)}async function*Dve(e,t){if(typeof e=="string"||ArrayBuffer.isView(e)){yield a1(e,t);return}if(e&&typeof e[Symbol.asyncIterator]=="function"){for await(let r of e)yield a1(r,t);return}if(e&&typeof e[Symbol.iterator]=="function"){for(let r of e)yield a1(r,t);return}throw It("data","a string, Buffer, TypedArray, DataView, or Iterable",e)}var du=class mn{constructor(t){y(this,"_fd");y(this,"_closing",!1);y(this,"_closed",!1);y(this,"_listeners",new Map);this._fd=t}static _assertHandle(t){if(!(t instanceof mn))throw vve("handle must be an instance of FileHandle");return t}_emitCloseOnce(){if(this._closed){this._fd=-1,this.emit("close");return}this._closed=!0,this._fd=-1,this.emit("close")}_resolvePath(){return this._fd<0?null:FA.applySync(void 0,[this._fd])}get fd(){return this._fd}get closed(){return this._closed}on(t,r){let n=this._listeners.get(t)??[];return n.push(r),this._listeners.set(t,n),this}once(t,r){let n=(...i)=>{this.off(t,n),r(...i)};return n._originalListener=r,this.on(t,n)}off(t,r){let n=this._listeners.get(t);if(!n)return this;let i=n.findIndex(s=>s===r||s._originalListener===r);return i!==-1&&n.splice(i,1),this}removeListener(t,r){return this.off(t,r)}emit(t,...r){let n=this._listeners.get(t);if(!n||n.length===0)return!1;for(let i of n.slice())i(...r);return!0}async close(){let t=mn._assertHandle(this);if((t._closing||t._closed)&&t._fd<0)throw We("EBADF","EBADF: bad file descriptor, close","close");t._closing=!0;try{$.closeSync(t._fd),t._emitCloseOnce()}finally{t._closing=!1}}async stat(){let t=mn._assertHandle(this);return $.fstatSync(t.fd)}async sync(){let t=mn._assertHandle(this);$.fsyncSync(t.fd)}async datasync(){return this.sync()}async truncate(t){let r=mn._assertHandle(this);$.ftruncateSync(r.fd,t)}async chmod(t){let n=mn._assertHandle(this)._resolvePath();if(!n)throw We("EBADF","EBADF: bad file descriptor","chmod");$.chmodSync(n,t)}async chown(t,r){let i=mn._assertHandle(this)._resolvePath();if(!i)throw We("EBADF","EBADF: bad file descriptor","chown");$.chownSync(i,t,r)}async utimes(t,r){let n=mn._assertHandle(this);$.futimesSync(n.fd,t,r)}async read(t,r,n,i){let s=mn._assertHandle(this),o=t,a=r,A=n,f=i;if(o!==null&&typeof o=="object"&&!ArrayBuffer.isView(o)&&(a=o.offset,A=o.length,f=o.position,o=o.buffer??null),o===null&&(o=Dt.Buffer.alloc(_ve)),!ArrayBuffer.isView(o))throw It("buffer","an instance of ArrayBufferView",o);let l=a??0,p=A??o.byteLength-l;return{bytesRead:$.readSync(s.fd,o,l,p,f??null),buffer:o}}async write(t,r,n,i){let s=mn._assertHandle(this);if(typeof t=="string"){let f=typeof n=="string"?n:"utf8";if(f==="hex"&&t.length%2!==0)throw WW("encoding",`is invalid for data of length ${t.length}`);return{bytesWritten:$.writeSync(s.fd,Dt.Buffer.from(t,f),0,void 0,r??null),buffer:t}}if(!ArrayBuffer.isView(t))throw It("buffer","a string, Buffer, TypedArray, or DataView",t);let o=r??0,a=typeof n=="number"?n:void 0;return{bytesWritten:$.writeSync(s.fd,t,o,a,i??null),buffer:t}}async readFile(t){let r=mn._assertHandle(this),n=typeof t=="string"?{encoding:t}:t??void 0,i=o2(n?.signal),s=n?.encoding??void 0;if((await r.stat()).size>LG){let l=new RangeError("File size is greater than 2 GiB");throw l.code="ERR_FS_FILE_TOO_LARGE",l}await Hm(),Sg(i);let a=[],A=0;for(;;){Sg(i);let l=Dt.Buffer.alloc(s2),{bytesRead:p}=await r.read(l,0,l.byteLength,null);if(p===0)break;if(a.push(l.subarray(0,p)),A+=p,A>LG){let I=new RangeError("File size is greater than 2 GiB");throw I.code="ERR_FS_FILE_TOO_LARGE",I}await Hm()}let f=Dt.Buffer.concat(a,A);return s?f.toString(s):f}async writeFile(t,r){let n=mn._assertHandle(this),i=typeof r=="string"?{encoding:r}:r??void 0,s=o2(i?.signal),o=i?.encoding??void 0;await Hm(),Sg(s);for await(let a of Dve(t,o))Sg(s),await n.write(a,0,a.byteLength,void 0),await Hm()}async appendFile(t,r){return this.writeFile(t,r)}createReadStream(t){return mn._assertHandle(this),new WB(null,{...t??{},fd:this})}createWriteStream(t){return mn._assertHandle(this),new VB(null,{...t??{},fd:this})}};function YB(e){return ArrayBuffer.isView(e)}function Tve(e,t){let r;t===null?r="Received null":typeof t=="string"?r=`Received type string ('${t}')`:r=`Received type ${typeof t} (${String(t)})`;let n=new TypeError(`The "${e}" property must be of type function. ${r}`);return n.code="ERR_INVALID_ARG_TYPE",n}function SA(e,t="cb"){if(typeof e!="function")throw It(t,"of type function",e)}function a2(e){if(e!=null&&(typeof e!="string"||!Dt.Buffer.isEncoding(e)))throw Rve(e)}function nr(e){if(typeof e=="string"){a2(e);return}e&&typeof e=="object"&&"encoding"in e&&a2(e.encoding)}function Be(e,t="path"){if(typeof e=="string")return e;if(Dt.Buffer.isBuffer(e))return e.toString("utf8");if(e instanceof URL){if(e.protocol==="file:")return e.pathname;throw It(t,"of type string or an instance of Buffer or URL",e)}throw It(t,"of type string or an instance of Buffer or URL",e)}function PG(e){try{return Be(e)}catch{return null}}function Kr(e,t,r={}){let{min:n=0,max:i=2147483647,allowNegativeOne:s=!1}=r;if(typeof t!="number")throw It(e,"of type number",t);if(!Number.isFinite(t)||!Number.isInteger(t))throw Na(e,"an integer",t);if(s&&t===-1||t>=n&&t<=i)return t;throw Na(e,`>= ${n} && <= ${i}`,t)}function wa(e,t="mode"){if(typeof e=="string"){if(!/^[0-7]+$/.test(e))throw WW(t,"must be a 32-bit unsigned integer or an octal string. Received '"+e+"'");return parseInt(e,8)}return Kr(t,e,{min:0,max:4294967295})}function OG(e){if(e!=null)return wa(e)}function A1(e){return e&-512|e&511&~(aB&511)}function VW(e){if(e?.start!==void 0){if(typeof e.start!="number")throw It("start","of type number",e.start);if(!Number.isFinite(e.start)||!Number.isInteger(e.start)||e.start<0)throw Na("start",">= 0",e.start)}}function wB(e,t){if(t!==void 0){if(typeof t!="boolean")throw It(e,"of type boolean",t);return t}}function Nve(e,t){if(t!==void 0){if(t===null||typeof t!="object"||typeof t.aborted!="boolean"||typeof t.addEventListener!="function"||typeof t.removeEventListener!="function"){let r=new TypeError(`The "${e}" property must be an instance of AbortSignal. ${YW(t)}`);throw r.code="ERR_INVALID_ARG_TYPE",r}return t}}function Mve(e,t){let r;if(e==null)r={};else if(typeof e=="string"){if(!t)throw It("options","of type object",e);a2(e),r={encoding:e}}else if(typeof e=="object")r=e;else throw It("options",t?"one of type string or object":"of type object",e);wB("options.persistent",r.persistent),wB("options.recursive",r.recursive),nr(r);let n=Nve("options.signal",r.signal);return{persistent:r.persistent,recursive:r.recursive,encoding:r.encoding,signal:n}}function Fve(e,t,r){let n=Be(e),i=t,s=r;if(typeof t=="function"&&(i=void 0,s=t),s!==void 0&&typeof s!="function")throw It("listener","of type function",s);return{path:n,listener:s,options:Mve(i,!0)}}function kve(e,t,r){let n=Be(e),i={},s=r;if(typeof t=="function")s=t;else if(t==null)i={};else if(typeof t=="object")i=t;else throw It("listener","of type function",t);if(typeof s!="function")throw It("listener","of type function",s);if(wB("persistent",i.persistent),wB("bigint",i.bigint),i.interval!==void 0&&typeof i.interval!="number")throw It("interval","of type number",i.interval);return{path:n,listener:s,options:{persistent:i.persistent,bigint:i.bigint,interval:i.interval}}}function Uve(){return new hu({mode:0,size:0,dev:0,ino:0,nlink:0,uid:0,gid:0,rdev:0,blksize:0,blocks:0,atimeMs:0,mtimeMs:0,ctimeMs:0,birthtimeMs:0})}function HG(e){try{let t=$.statSync(e);return{exists:!0,stats:t,signature:JSON.stringify({dev:t.dev,ino:t.ino,mode:t.mode,nlink:t.nlink,uid:t.uid,gid:t.gid,rdev:t.rdev,size:t.size,atimeMs:t.atimeMs,mtimeMs:t.mtimeMs,ctimeMs:t.ctimeMs,birthtimeMs:t.birthtimeMs})}}catch(t){if(t?.code==="ENOENT"||t?.code==="ENOTDIR")return{exists:!1,stats:Uve(),signature:"missing"};throw t}}function xve(e,t){let r=e==="/"?"":e.split("/").filter(Boolean).pop()??"";return t==="buffer"?Dt.Buffer.from(r):r}function Lve(e,t){return e.exists!==t.exists?"rename":"change"}var Pve=50,Ove=5007,Wg=new Map,JW=class{constructor(e,t){y(this,"_path");y(this,"_intervalMs");y(this,"_onChange");y(this,"_onClose");y(this,"_listeners");y(this,"_timer");y(this,"_closed");y(this,"_signal");y(this,"_handleAbort");y(this,"_snapshot");y(this,"_poll");this._path=e,this._intervalMs=t.interval,this._onChange=t.onChange,this._onClose=t.onClose,this._listeners=new Map,this._closed=!1,this._signal=t.signal,this._snapshot=HG(e),this._poll=()=>{if(this._closed)return;let r;try{r=HG(this._path)}catch(i){this.emit("error",i);return}if(r.signature===this._snapshot.signature)return;let n=this._snapshot;this._snapshot=r,this._onChange(r,n)},this._handleAbort=()=>{this.close()},this._timer=x2(this._poll,this._intervalMs),t.persistent===!1&&this._timer?.unref?.(),this._signal&&(this._signal.aborted?queueMicrotask(()=>this.close()):this._signal.addEventListener("abort",this._handleAbort,{once:!0}))}on(e,t){let r=this._listeners.get(e)??[];return r.push(t),this._listeners.set(e,r),this}addListener(e,t){return this.on(e,t)}once(e,t){let r=(...n)=>{this.removeListener(e,r),t(...n)};return r._originalListener=t,this.on(e,r)}off(e,t){return this.removeListener(e,t)}removeListener(e,t){let r=this._listeners.get(e);if(!r)return this;let n=r.findIndex(i=>i===t||i._originalListener===t);return n>=0&&r.splice(n,1),r.length===0&&this._listeners.delete(e),this}removeAllListeners(e){return e===void 0?this._listeners.clear():this._listeners.delete(e),this}emit(e,...t){let r=this._listeners.get(e);return r?.length?(r.slice().forEach(n=>n(...t)),!0):!1}ref(){return this._timer?.ref?.(),this}unref(){return this._timer?.unref?.(),this}close(){this._closed||(this._closed=!0,this._timer!==void 0&&(L2(this._timer),this._timer=void 0),this._signal&&this._signal.removeEventListener("abort",this._handleAbort),this._onClose?.(),this.emit("close"))}};function Hve(e,t){let r=Wg.get(e)??new Set;r.add(t),Wg.set(e,r)}function qve(e,t){let r=Wg.get(e);r&&(r.delete(t),r.size===0&&Wg.delete(e))}function Gve(e,t){let r=xve(e,t.encoding),n=new JW(e,{interval:Pve,persistent:t.persistent,signal:t.signal,onChange(i,s){n.emit("change",Lve(s,i),r)}});return n}function Yve(e,t,r){let n=new JW(e,{interval:t.interval??Ove,persistent:t.persistent,onChange(i,s){n.emit("change",i.stats,s.stats)},onClose(){qve(e,n)}});return n.on("change",r),Hve(e,n),n}async function*Wve(e,t){let r=[],n=null,i=!1,s=null,o=$.watch(e,t,(a,A)=>{r.push({eventType:a,filename:A}),n?.(),n=null});o.on("close",()=>{i=!0,n?.(),n=null}),o.on("error",a=>{s=a,n?.(),n=null});try{for(;;){if(r.length>0){yield r.shift();continue}if(s)throw s;if(i)return;await new Promise(a=>{n=a})}}finally{o.close()}}function A2(e){return e==null||typeof e=="object"&&!Array.isArray(e)}function So(e){if(e==null||e===-1)return null;if(typeof e=="bigint")return Number(e);if(typeof e!="number"||!Number.isInteger(e))throw It("position","an integer",e);return e}function SB(e,t,r){let n=t??0;if(typeof n!="number"||!Number.isInteger(n))throw It("offset","an integer",n);if(n<0||n>e)throw Na("offset",`>= 0 && <= ${e}`,n);let i=e-n,s=r??i;if(typeof s!="number"||!Number.isInteger(s))throw It("length","an integer",s);if(s<0||s>2147483647)throw Na("length",">= 0 && <= 2147483647",s);if(n+s>e)throw Na("length",`>= 0 && <= ${e-n}`,s);return{offset:n,length:s}}function Vve(e,t,r,n){if(!YB(e))throw It("buffer","an instance of Buffer, TypedArray, or DataView",e);if(r===void 0&&n===void 0&&A2(t)){let o=t??{},{offset:a,length:A}=SB(e.byteLength,o.offset,o.length);return{buffer:e,offset:a,length:A,position:So(o.position)}}let{offset:i,length:s}=SB(e.byteLength,t,r);return{buffer:e,offset:i,length:s,position:So(n)}}function qG(e,t,r,n){if(typeof e=="string"){if(r===void 0&&n===void 0&&A2(t)){let o=t??{},a=typeof o.encoding=="string"?o.encoding:void 0;return{buffer:e,offset:0,length:Dt.Buffer.byteLength(e,a),position:So(o.position),encoding:a}}if(t!=null&&typeof t!="number")throw It("position","an integer",t);return{buffer:e,offset:0,length:Dt.Buffer.byteLength(e,typeof r=="string"?r:void 0),position:So(t),encoding:typeof r=="string"?r:void 0}}if(!YB(e))throw It("buffer","a string, Buffer, TypedArray, or DataView",e);if(r===void 0&&n===void 0&&A2(t)){let o=t??{},{offset:a,length:A}=SB(e.byteLength,o.offset,o.length);return{buffer:e,offset:a,length:A,position:So(o.position)}}let{offset:i,length:s}=SB(e.byteLength,t,typeof r=="number"?r:void 0);return{buffer:e,offset:i,length:s,position:So(n)}}function ar(e){return Kr("fd",e)}function qm(e){if(!Array.isArray(e))throw It("buffers","an ArrayBufferView[]",e);for(let t of e)if(!YB(t))throw It("buffers","an ArrayBufferView[]",e);return e}function f2(e,t){if(e===void 0)return;if(e===null||typeof e!="object")throw It("options.fs","an object",e);let r=e;for(let n of t)if(typeof r[n]!="function")throw Tve(`options.fs.${String(n)}`,r[n]);return r}function _B(e){if(e!==void 0)return e instanceof du?e:Kr("fd",e)}function GG(e,t){if(e===null){if(t===void 0)throw It("path","of type string or an instance of Buffer or URL",e);return null}if(typeof e=="string"||Dt.Buffer.isBuffer(e))return e;if(e instanceof URL){if(e.protocol==="file:")return e.pathname;throw It("path","of type string or an instance of Buffer or URL",e)}throw It("path","of type string or an instance of Buffer or URL",e)}function Jve(e){let t=e?.start,r=e?.end;if(t!==void 0&&typeof t!="number")throw It("start","of type number",t);if(r!==void 0&&typeof r!="number")throw It("end","of type number",r);let n=t,i=r;if(n!==void 0&&(!Number.isFinite(n)||n<0))throw Na("start",">= 0",t);if(i!==void 0&&(!Number.isFinite(i)||i<0))throw Na("end",">= 0",r);if(n!==void 0&&i!==void 0&&n>i)throw Na("start",`<= "end" (here: ${i})`,n);let s=e?.highWaterMark??e?.bufferSize,o=typeof s=="number"&&Number.isFinite(s)&&s>0?Math.floor(s):65536;return{start:n,end:i,highWaterMark:o,autoClose:e?.autoClose!==!1}}var WB=class{constructor(e,t){y(this,"_options");y(this,"bytesRead",0);y(this,"path");y(this,"pending",!0);y(this,"readable",!0);y(this,"readableAborted",!1);y(this,"readableDidRead",!1);y(this,"readableEncoding",null);y(this,"readableEnded",!1);y(this,"readableFlowing",null);y(this,"readableHighWaterMark",65536);y(this,"readableLength",0);y(this,"readableObjectMode",!1);y(this,"destroyed",!1);y(this,"closed",!1);y(this,"errored",null);y(this,"fd",null);y(this,"autoClose",!0);y(this,"start");y(this,"end");y(this,"_listeners",new Map);y(this,"_started",!1);y(this,"_reading",!1);y(this,"_readScheduled",!1);y(this,"_opening",!1);y(this,"_remaining",null);y(this,"_position",null);y(this,"_fileHandle",null);y(this,"_streamFs");y(this,"_signal");y(this,"_handleCloseListener");this._options=t;let r=_B(t?.fd),i=Jve(t??{});if(this.path=e,this.start=i.start,this.end=i.end,this.autoClose=i.autoClose,this.readableHighWaterMark=i.highWaterMark,this.readableEncoding=t?.encoding??null,this._position=this.start??null,this._remaining=this.end!==void 0?this.end-(this.start??0)+1:null,this._signal=o2(t?.signal),r instanceof du){if(t?.fs!==void 0){let s=new Error("The FileHandle with fs method is not implemented");throw s.code="ERR_METHOD_NOT_IMPLEMENTED",s}this._fileHandle=r,this.fd=r.fd,this.pending=!1,this._handleCloseListener=()=>{this.closed||(this.closed=!0,this.destroyed=!0,this.readable=!1,this.emit("close"))},this._fileHandle.on("close",this._handleCloseListener)}else this._streamFs=f2(t?.fs,["open","read","close"]),typeof r=="number"&&(this.fd=r,this.pending=!1);this._signal&&(this._signal.aborted?queueMicrotask(()=>{this._abort(this._signal?.reason)}):this._signal.addEventListener("abort",()=>{this._abort(this._signal?.reason)})),this.fd===null&&queueMicrotask(()=>{this._openIfNeeded()})}_emitOpen(e){this.fd=e,this.pending=!1,this.emit("open",e),(this._started||this.readableFlowing)&&this._scheduleRead()}async _openIfNeeded(){if(this.fd!==null||this._opening||this.destroyed||this.closed)return;let e=typeof this.path=="string"?this.path:this.path instanceof Dt.Buffer?this.path.toString():null;if(!e){this._handleStreamError(We("EBADF","EBADF: bad file descriptor","read"));return}this._opening=!0,(this._streamFs?.open??$.open).bind(this._streamFs??$)(e,"r",438,(r,n)=>{if(this._opening=!1,r||typeof n!="number"){this._handleStreamError(r??We("EBADF","EBADF: bad file descriptor","open"));return}this._emitOpen(n)})}async _closeUnderlying(){if(this._fileHandle){this._fileHandle.closed||await this._fileHandle.close();return}if(this.fd!==null&&this.fd>=0){let e=this.fd,t=(this._streamFs?.close??$.close).bind(this._streamFs??$);await new Promise(r=>{t(e,()=>r())}),this.fd=-1}}_scheduleRead(){this._readScheduled||this._reading||this.readableFlowing===!1||this.destroyed||this.closed||(this._readScheduled=!0,queueMicrotask(()=>{this._readScheduled=!1,this._readNextChunk()}))}async _readNextChunk(){if(this._reading||this.destroyed||this.closed||this.readableFlowing===!1)return;if(Sg(this._signal),this.fd===null){await this._openIfNeeded();return}if(this._remaining===0){await this._finishReadable();return}let e=this._remaining===null?this.readableHighWaterMark:Math.min(this.readableHighWaterMark,this._remaining),t=Dt.Buffer.alloc(e);this._reading=!0;let r=async(i,s=0)=>{if(this._reading=!1,i){this._handleStreamError(i);return}if(s===0){await this._finishReadable();return}this.bytesRead+=s,this.readableDidRead=!0,typeof this._position=="number"&&(this._position+=s),this._remaining!==null&&(this._remaining-=s);let o=t.subarray(0,s);if(this.emit("data",this.readableEncoding?o.toString(this.readableEncoding):Dt.Buffer.from(o)),this._remaining===0){await this._finishReadable();return}this._scheduleRead()};if(this._fileHandle){try{let i=await this._fileHandle.read(t,0,e,this._position);await r(null,i.bytesRead)}catch(i){await r(i)}return}(this._streamFs?.read??$.read).bind(this._streamFs??$)(this.fd,t,0,e,this._position,(i,s)=>{r(i,s??0)})}async _finishReadable(){this.readableEnded||(this.readable=!1,this.readableEnded=!0,this.emit("end"),this.autoClose&&this.destroy())}_handleStreamError(e){this.closed||(this.errored=e,this.emit("error",e),this.autoClose?this.destroy():this.readable=!1)}async _abort(e){if(!(this.closed||this.destroyed)){if(this.readableAborted=!0,this.errored=GW(e),this.emit("error",this.errored),this._fileHandle){this.destroyed=!0,this.readable=!1,this.closed=!0,this.emit("close");return}if(this.autoClose){this.destroy();return}this.closed=!0,this.emit("close")}}async _readAllContent(){let e=[],t=0,r=this.readableFlowing;for(this.readableFlowing=!1;this._remaining!==0&&(this.fd===null&&await this._openIfNeeded(),this.fd!==null);){let n=this._remaining===null?s2:Math.min(s2,this._remaining),i=Dt.Buffer.alloc(n),s=0;if(this._fileHandle?s=(await this._fileHandle.read(i,0,n,this._position)).bytesRead:s=$.readSync(this.fd,i,0,n,this._position),s===0)break;let o=i.subarray(0,s);e.push(o),t+=s,typeof this._position=="number"&&(this._position+=s),this._remaining!==null&&(this._remaining-=s)}return this.readableFlowing=r,Dt.Buffer.concat(e,t)}on(e,t){let r=this._listeners.get(e)??[];return r.push(t),this._listeners.set(e,r),e==="data"&&(this._started=!0,this.readableFlowing!==!1&&(this.readableFlowing=!0,this._scheduleRead())),this}once(e,t){let r=(...n)=>{this.off(e,r),t(...n)};return r._originalListener=t,this.on(e,r)}off(e,t){let r=this._listeners.get(e);if(!r)return this;let n=r.findIndex(i=>i===t||i._originalListener===t);return n>=0&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e===void 0?this._listeners.clear():this._listeners.delete(e),this}emit(e,...t){let r=this._listeners.get(e);return r?.length?(r.slice().forEach(n=>n(...t)),!0):!1}read(){return null}pipe(e,t){return this.on("data",r=>{e.write(r)}),this.on("end",()=>{e.end?.()}),this.resume(),e}unpipe(e){return this}pause(){return this.readableFlowing=!1,this}resume(){return this._started=!0,this.readableFlowing=!0,this._scheduleRead(),this}setEncoding(e){return this.readableEncoding=e,this}destroy(e){return this.destroyed?this:(this.destroyed=!0,this.readable=!1,e&&(this.errored=e,this.emit("error",e)),queueMicrotask(()=>{this._closeUnderlying().then(()=>{this.closed||(this.closed=!0,this.emit("close"))})}),this)}close(e){this.destroy(),e&&queueMicrotask(()=>e(null))}async*[Symbol.asyncIterator](){let e=await this._readAllContent();yield this.readableEncoding?e.toString(this.readableEncoding):e}},YG=16*1024*1024,VB=class{constructor(e,t){y(this,"_options");y(this,"bytesWritten",0);y(this,"path");y(this,"pending",!1);y(this,"writable",!0);y(this,"writableAborted",!1);y(this,"writableEnded",!1);y(this,"writableFinished",!1);y(this,"writableHighWaterMark",16384);y(this,"writableLength",0);y(this,"writableObjectMode",!1);y(this,"writableCorked",0);y(this,"destroyed",!1);y(this,"closed",!1);y(this,"errored",null);y(this,"writableNeedDrain",!1);y(this,"fd",null);y(this,"autoClose",!0);y(this,"_chunks",[]);y(this,"_listeners",new Map);y(this,"_fileHandle",null);y(this,"_streamFs");y(this,"_position",null);this._options=t;let r=_B(t?.fd),n=t?.start,i=t?.highWaterMark??t?.bufferSize,s=t?.flags??"w";if(this.path=e,this.autoClose=t?.autoClose!==!1,this.writableHighWaterMark=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):16384,this._position=typeof n=="number"?n:null,this._streamFs=f2(t?.fs,["open","close","write"]),t?.fs!==void 0&&f2(t?.fs,["writev"]),r instanceof du){this._fileHandle=r,this.fd=r.fd;return}if(typeof r=="number"){this.fd=r;return}let o=typeof this.path=="string"?this.path:this.path instanceof Dt.Buffer?this.path.toString():null;if(!o)throw We("EBADF","EBADF: bad file descriptor","write");this.fd=$.openSync(o,s,t?.mode),queueMicrotask(()=>{this.fd!==null&&this.fd>=0&&this.emit("open",this.fd)})}async _closeUnderlying(){if(this._fileHandle){this._fileHandle.closed||await this._fileHandle.close();return}if(this.fd!==null&&this.fd>=0){let e=this.fd,t=(this._streamFs?.close??$.close).bind(this._streamFs??$);await new Promise(r=>{t(e,()=>r())}),this.fd=-1}}close(e){queueMicrotask(()=>{this._closeUnderlying().then(()=>{this.closed||(this.closed=!0,this.writable=!1,this.emit("close")),e?.(null)})})}write(e,t,r){if(this.writableEnded||this.destroyed){let s=new Error("write after end"),o=typeof t=="function"?t:r;return queueMicrotask(()=>o?.(s)),!1}let n;if(typeof e=="string")n=Dt.Buffer.from(e,typeof t=="string"?t:"utf8");else if(YB(e))n=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);else throw It("chunk","a string, Buffer, TypedArray, or DataView",e);if(this.writableLength+n.length>YG){let s=new Error(`WriteStream buffer exceeded ${YG} bytes`);this.errored=s,this.destroyed=!0,this.writable=!1;let o=typeof t=="function"?t:r;return queueMicrotask(()=>{o?.(s),this.emit("error",s)}),!1}this._chunks.push(n),this.bytesWritten+=n.length,this.writableLength+=n.length;let i=typeof t=="function"?t:r;return queueMicrotask(()=>i?.(null)),!0}end(e,t,r){if(this.writableEnded)return this;let n;return typeof e=="function"?n=e:typeof t=="function"?(n=t,e!=null&&this.write(e)):(n=r,e!=null&&this.write(e,t)),this.writableEnded=!0,this.writable=!1,this.writableFinished=!0,this.writableLength=0,queueMicrotask(()=>{(async()=>{try{if(this._fileHandle){for(let i of this._chunks){let s=await this._fileHandle.write(i,0,i.byteLength,this._position);typeof this._position=="number"&&(this._position+=s?.bytesWritten??i.byteLength)}this.autoClose&&!this._fileHandle.closed&&await this._fileHandle.close()}else{let i=typeof this.path=="string"?this.path:this.path instanceof Dt.Buffer?this.path.toString():null;if(i){let s=this._chunks.map(o=>Dt.Buffer.from(o));if(typeof this._position=="number"){let o=$.readFileSync(i),a=Math.max(o.length,this._position+s.reduce((l,p)=>l+p.length,0)),A=Dt.Buffer.alloc(a);o.copy(A);let f=this._position;for(let l of s)l.copy(A,f),f+=l.length;$.writeFileSync(i,A.toString(this._options?.encoding??"utf8"))}else $.writeFileSync(i,Dt.Buffer.concat(s).toString(this._options?.encoding??"utf8"));this.autoClose&&this.fd!==null&&this.fd>=0&&await this._closeUnderlying()}else if(this.fd!==null&&this.fd>=0){for(let s of this._chunks){let o=$.writeSync(this.fd,s,0,s.byteLength,this._position);typeof this._position=="number"&&(this._position+=o)}this.autoClose&&await this._closeUnderlying()}else throw We("EBADF","EBADF: bad file descriptor","write")}this.emit("finish"),this.autoClose&&!this.closed&&(this.closed=!0,this.emit("close")),n?.()}catch(i){this.errored=i,this.emit("error",i)}})()}),this}setDefaultEncoding(e){return this}cork(){this.writableCorked++}uncork(){this.writableCorked>0&&this.writableCorked--}destroy(e){return this.destroyed?this:(this.destroyed=!0,this.writable=!1,e&&(this.errored=e,this.emit("error",e)),queueMicrotask(()=>{this._closeUnderlying().then(()=>{this.closed||(this.closed=!0,this.emit("close"))})}),this)}addListener(e,t){return this.on(e,t)}on(e,t){let r=this._listeners.get(e)??[];return r.push(t),this._listeners.set(e,r),this}once(e,t){let r=(...n)=>{this.removeListener(e,r),t(...n)};return this.on(e,r)}removeListener(e,t){let r=this._listeners.get(e);if(!r)return this;let n=r.indexOf(t);return n>=0&&r.splice(n,1),this}off(e,t){return this.removeListener(e,t)}removeAllListeners(e){return e===void 0?this._listeners.clear():this._listeners.delete(e),this}emit(e,...t){let r=this._listeners.get(e);return r?.length?(r.slice().forEach(n=>n(...t)),!0):!1}pipe(e,t){return e}unpipe(e){return this}[Symbol.asyncDispose](){return Promise.resolve()}},jve=WB,zve=VB,jW=function(t,r){return nr(r),new jve(t,r)};jW.prototype=WB.prototype;var zW=function(t,r){return nr(r),VW(r??{}),new zve(t,r)};zW.prototype=VB.prototype;function Kve(e){if(typeof e=="number")return e;let t={r:n2,"r+":ya,rs:n2,"rs+":ya,w:su|Hn|ou,"w+":ya|Hn|ou,a:su|au|Hn,"a+":ya|au|Hn,wx:su|Hn|ou|ma,xw:su|Hn|ou|ma,"wx+":ya|Hn|ou|ma,"xw+":ya|Hn|ou|ma,ax:su|au|Hn|ma,xa:su|au|Hn|ma,"ax+":ya|au|Hn|ma,"xa+":ya|au|Hn|ma};if(e in t)return t[e];throw new Error("Unknown file flag: "+e)}var WG={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENAMETOOLONG:36,ENOSYS:38,ENOTEMPTY:39,ELOOP:40,EOVERFLOW:75,ENOTSOCK:88,EDESTADDRREQ:89,EMSGSIZE:90,EPROTOTYPE:91,ENOPROTOOPT:92,EPROTONOSUPPORT:93,ENOTSUP:95,EOPNOTSUPP:95,EAFNOSUPPORT:97,EADDRINUSE:98,EADDRNOTAVAIL:99,ENETDOWN:100,ENETUNREACH:101,ECONNABORTED:103,ECONNRESET:104,ENOBUFS:105,EISCONN:106,ENOTCONN:107,ETIMEDOUT:110,ECONNREFUSED:111,EHOSTUNREACH:113,EALREADY:114,EINPROGRESS:115};function Xve(e){return Object.prototype.hasOwnProperty.call(WG,e)?-WG[e]:-1}function We(e,t,r,n){let i=new Error(t);return i.code=e,i.errno=Xve(e),i.syscall=r,n&&(i.path=n),i}function Zve(e){return String(e?.message??e??"")}function Vi(e){let t=Zve(e);return t.includes("ENOENT")||t.includes("entry not found")||t.includes("no such file or directory")||t.includes("not found")?"ENOENT":t.includes("EROFS")||t.includes("read-only file system")?"EROFS":t.includes("ERR_ACCESS_DENIED")?"ERR_ACCESS_DENIED":t.includes("EACCES")||t.includes("permission denied")?"EACCES":t.includes("EEXIST")||t.includes("file already exists")?"EEXIST":t.includes("EINVAL")||t.includes("invalid argument")?"EINVAL":t.includes("EXDEV")||t.includes("cross-device link")?"EXDEV":typeof e?.code=="string"&&e.code.length>0?e.code:null}function Hi(e,t,r){try{return e()}catch(n){let i=Vi(n);throw i==="ENOENT"?We("ENOENT",`ENOENT: no such file or directory, ${t} '${r}'`,t,r):i==="EACCES"?We("EACCES",`EACCES: permission denied, ${t} '${r}'`,t,r):i==="EEXIST"?We("EEXIST",`EEXIST: file already exists, ${t} '${r}'`,t,r):i==="EINVAL"?We("EINVAL",`EINVAL: invalid argument, ${t} '${r}'`,t,r):i==="EXDEV"?We("EXDEV",`EXDEV: cross-device link not permitted, ${t} '${r}'`,t,r):n}}function $ve(e){let t="",r=0;for(;ro.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,"[^/]*")).join("|")+")",r=i+1}else t+="\\{",r++}else if(n==="["){let i=e.indexOf("]",r);i!==-1?(t+=e.slice(r,i+1),r=i+1):(t+="\\[",r++)}else".+^${}()|[]\\".includes(n)?(t+="\\"+n,r++):(t+=n,r++)}return new RegExp("^"+t+"$")}function e1e(e){let t=e.split("/"),r=[];for(let n of t){if(/[*?{}\[\]]/.test(n))break;r.push(n)}return r.join("/")||"/"}var t1e=100;function r1e(e,t){let r=$ve(e),n=e1e(e),i=(s,o)=>{if(o>t1e)return;let a;try{a=KW(s)}catch{return}for(let A of a){let f=s==="/"?"/"+A:s+"/"+A;r.test(f)&&t.push(f);try{u2(f).isDirectory()&&i(f,o+1)}catch{}}};try{if(r.test(n)&&!u2(n).isDirectory()){t.push(n);return}i(n,0)}catch{}}var KW,u2;function f1(e){return Be(e)}function c2(e){return typeof globalThis<"u"?globalThis[e]:void 0}function Re(e){return{applySync(t,r){let n=c2(e);if(typeof n=="function")return n(...r||[]);if(n&&typeof n.applySync=="function")return n.applySync(t,r)},applySyncPromise(t,r){let n=c2(e);if(typeof n=="function")return n(...r||[]);if(n&&typeof n.applySync=="function")return n.applySync(t,r);if(n&&typeof n.applySyncPromise=="function")return n.applySyncPromise(t,r)}}}function Cr(e){return{apply(t,r){let n=c2(e);return typeof n=="function"?n(...r||[]):n&&typeof n.apply=="function"?n.apply(t,r):Promise.resolve(void 0)}}}var Jt={readFile:Re("_fsReadFile"),writeFile:Re("_fsWriteFile"),readFileBinary:Re("_fsReadFileBinary"),writeFileBinary:Re("_fsWriteFileBinary"),readDir:Re("_fsReadDir"),mkdir:Re("_fsMkdir"),rmdir:Re("_fsRmdir"),exists:Re("_fsExists"),stat:Re("_fsStat"),unlink:Re("_fsUnlink"),rename:Re("_fsRename"),chmod:Re("_fsChmod"),chown:Re("_fsChown"),link:Re("_fsLink"),symlink:Re("_fsSymlink"),readlink:Re("_fsReadlink"),lstat:Re("_fsLstat"),truncate:Re("_fsTruncate"),utimes:Re("_fsUtimes"),lutimes:Re("_fsLutimes")},Er={readFile:Cr("_fsReadFileAsync"),writeFile:Cr("_fsWriteFileAsync"),readFileBinary:Cr("_fsReadFileBinaryAsync"),writeFileBinary:Cr("_fsWriteFileBinaryAsync"),readDir:Cr("_fsReadDirAsync"),mkdir:Cr("_fsMkdirAsync"),rmdir:Cr("_fsRmdirAsync"),stat:Cr("_fsStatAsync"),unlink:Cr("_fsUnlinkAsync"),rename:Cr("_fsRenameAsync"),chmod:Cr("_fsChmodAsync"),chown:Cr("_fsChownAsync"),link:Cr("_fsLinkAsync"),symlink:Cr("_fsSymlinkAsync"),readlink:Cr("_fsReadlinkAsync"),lstat:Cr("_fsLstatAsync"),truncate:Cr("_fsTruncateAsync"),utimes:Cr("_fsUtimesAsync"),lutimes:Cr("_fsLutimesAsync"),access:Cr("_fsAccessAsync")},n1e=Re("fs.openSync"),XW=Re("fs.closeSync"),i1e=Re("fs.readSync"),u1=Re("fs.writeSync"),s1e=Re("fs.fstatSync"),o1e=Re("fs.ftruncateSync"),VG=Re("fs.fsyncSync"),a1e=Re("fs.futimesSync"),FA=Re("fs._getPathSync"),A1e=Re("process.umask"),f1e=Re("process.memoryUsage"),u1e=Re("process.cpuUsage"),c1e=Re("process.resourceUsage"),l1e=Re("process.versions"),zFe=Re("_kernelPollRaw"),KFe=Re("_kernelIsattyRaw"),XFe=Re("_kernelTtySizeRaw");function Ta(e){return typeof e=="string"?JSON.parse(e):e}function gu(e){return{__agentOSType:"bytes",base64:Dt.Buffer.from(e).toString("base64")}}function nB(e,t,r){let n=Vi(e);if(n==="ENOENT")throw We("ENOENT",`ENOENT: no such file or directory, ${t} '${r}'`,t,r);if(n==="EROFS")throw We("EROFS",`EROFS: read-only file system, ${t} '${r}'`,t,r);if(n==="ERR_ACCESS_DENIED"){let i=We("ERR_ACCESS_DENIED",`ERR_ACCESS_DENIED: permission denied, ${t} '${r}'`,t,r);throw i.code="ERR_ACCESS_DENIED",i}throw n==="EACCES"?We("EACCES",`EACCES: permission denied, ${t} '${r}'`,t,r):e}function h1e(e,t){return e==="/"?`/${t}`:e.endsWith("/")?`${e}${t}`:`${e}/${t}`}function ZW(e,t,r){return Array.isArray(e)?r?e.map(n=>{if(typeof n=="string"){let i=$.statSync(h1e(t,n));return new i2(n,i.isDirectory(),t)}return new i2(n.name,n.isDirectory,t)}):e.map(n=>typeof n=="string"?n:n?.name):[]}async function c1(e,t){nr(t);let r=typeof e=="number"?FA.applySync(void 0,[ar(e)]):Be(e);if(!r)throw We("EBADF","EBADF: bad file descriptor","read");let n=r,i=typeof t=="string"?t:t?.encoding;try{if(i)return await Er.readFile.apply(void 0,[n,i]);let s=await Er.readFileBinary.apply(void 0,[n]);return Dt.Buffer.from(s,"base64")}catch(s){throw Vi(s)==="ENOENT"?We("ENOENT",`ENOENT: no such file or directory, open '${r}'`,"open",r):Vi(s)==="EACCES"?We("EACCES",`EACCES: permission denied, open '${r}'`,"open",r):s}}async function l1(e,t,r){nr(r);let n=typeof e=="number"?FA.applySync(void 0,[ar(e)]):Be(e);if(!n)throw We("EBADF","EBADF: bad file descriptor","write");let i=n;try{if(typeof t=="string")return await Er.writeFile.apply(void 0,[i,t]);if(ArrayBuffer.isView(t)){let s=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return await Er.writeFileBinary.apply(void 0,[i,gu(s)])}return await Er.writeFile.apply(void 0,[i,String(t)])}catch(s){nB(s,"write",n)}}async function d1e(e,t){nr(t);let r=Be(e);try{let n=await Er.readDir.apply(void 0,[r]);return ZW(Ta(n),r,t?.withFileTypes)}catch(n){throw Vi(n)==="ENOENT"?We("ENOENT",`ENOENT: no such file or directory, scandir '${r}'`,"scandir",r):n}}async function g1e(e,t){let r=Be(e),n=typeof t=="object"?t?.recursive??!1:!1;return await Er.mkdir.apply(void 0,[r,n]),n?r:void 0}async function p1e(e){let t=Be(e);await Er.rmdir.apply(void 0,[t])}async function E1e(e){let t=Be(e);try{let r=await Er.stat.apply(void 0,[t]);return new hu(Ta(r))}catch(r){throw Vi(r)==="ENOENT"?We("ENOENT",`ENOENT: no such file or directory, stat '${t}'`,"stat",t):r}}async function y1e(e){let t=Be(e),r=await Er.lstat.apply(void 0,[t]);return new hu(Ta(r))}async function m1e(e){let t=Be(e);await Er.unlink.apply(void 0,[t])}async function B1e(e,t){let r=Be(e,"oldPath"),n=Be(t,"newPath");await Er.rename.apply(void 0,[r,n])}async function I1e(e){let t=Be(e);try{await Er.access.apply(void 0,[t])}catch(r){throw Vi(r)==="ENOENT"?We("ENOENT",`ENOENT: no such file or directory, access '${t}'`,"access",t):r}}async function b1e(e,t){let r=Be(e),n=wa(t,"mode");await Er.chmod.apply(void 0,[r,n])}async function C1e(e,t,r){let n=Be(e),i=Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),s=Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});await Er.chown.apply(void 0,[n,i,s])}async function Q1e(e,t){let r=Be(e,"existingPath"),n=Be(t,"newPath");await Er.link.apply(void 0,[r,n])}async function w1e(e,t){let r=Be(e,"target"),n=Be(t);await Er.symlink.apply(void 0,[r,n])}async function S1e(e){let t=Be(e);return await Er.readlink.apply(void 0,[t])}async function _1e(e,t){let r=Be(e);await Er.truncate.apply(void 0,[r,t??0])}function wo(e,t){if(e&&typeof e=="object"&&!(e instanceof Date)){let o=typeof e.kind=="string"?e.kind:null;if(o==="now"||o==="UTIME_NOW")return{kind:"now"};if(o==="omit"||o==="UTIME_OMIT")return{kind:"omit"};if("nsec"in e){if(e.nsec===$.constants.UTIME_NOW||e.nsec==="UTIME_NOW")return{kind:"now"};if(e.nsec===$.constants.UTIME_OMIT||e.nsec==="UTIME_OMIT")return{kind:"omit"}}let a=Number(e.sec),A=Number(e.nsec??0);if(!Number.isInteger(a))throw It(t,"an integer sec field",e);if(!Number.isInteger(A)||A<0||A>=1e9)throw createRangeError(`${t}.nsec must be an integer between 0 and 999999999`);return{sec:a,nsec:A}}let r=typeof e=="number"?e:new Date(e).getTime()/1e3;if(!Number.isFinite(r))throw createRangeError(`${t} must be a finite timestamp`);let n=Math.floor(r),i=n,s=Math.round((r-n)*1e9);return s>=1e9&&(i+=1,s-=1e9),{sec:i,nsec:s}}async function v1e(e,t,r){let n=Be(e);await Er.utimes.apply(void 0,[n,wo(t,"atime"),wo(r,"mtime")])}async function R1e(e,t,r){let n=Be(e);await Er.lutimes.apply(void 0,[n,wo(t,"atime"),wo(r,"mtime")])}var $={constants:{F_OK:0,R_OK:4,W_OK:2,X_OK:1,COPYFILE_EXCL:1,COPYFILE_FICLONE:2,COPYFILE_FICLONE_FORCE:4,O_RDONLY:n2,O_WRONLY:su,O_RDWR:ya,O_CREAT:Hn,O_EXCL:ma,O_NOCTTY:256,O_TRUNC:ou,O_APPEND:au,O_DIRECTORY:65536,O_NOATIME:262144,O_NOFOLLOW:131072,O_SYNC:1052672,O_DSYNC:4096,O_SYMLINK:2097152,O_DIRECT:16384,O_NONBLOCK:2048,UTIME_NOW:1073741823,UTIME_OMIT:1073741822,S_IFMT:61440,S_IFREG:32768,S_IFDIR:16384,S_IFCHR:8192,S_IFBLK:24576,S_IFIFO:4096,S_IFLNK:40960,S_IFSOCK:49152,S_IRWXU:448,S_IRUSR:256,S_IWUSR:128,S_IXUSR:64,S_IRWXG:56,S_IRGRP:32,S_IWGRP:16,S_IXGRP:8,S_IRWXO:7,S_IROTH:4,S_IWOTH:2,S_IXOTH:1,UV_FS_O_FILEMAP:536870912},Stats:hu,Dirent:i2,Dir:xG,readFileSync(e,t){nr(t);let r=typeof e=="number"?FA.applySync(void 0,[ar(e)]):Be(e);if(!r)throw We("EBADF","EBADF: bad file descriptor","read");let n=r,i=typeof t=="string"?t:t?.encoding;try{if(i)return Jt.readFile.applySyncPromise(void 0,[n,i]);{let s=Jt.readFileBinary.applySyncPromise(void 0,[n]);return Dt.Buffer.from(s,"base64")}}catch(s){throw Vi(s)==="ENOENT"?We("ENOENT",`ENOENT: no such file or directory, open '${r}'`,"open",r):Vi(s)==="EACCES"?We("EACCES",`EACCES: permission denied, open '${r}'`,"open",r):s}},writeFileSync(e,t,r){nr(r);let n=typeof e=="number"?FA.applySync(void 0,[ar(e)]):Be(e);if(!n)throw We("EBADF","EBADF: bad file descriptor","write");let i=n;try{if(typeof t=="string")return Jt.writeFile.applySyncPromise(void 0,[i,t]);if(ArrayBuffer.isView(t)){let s=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return Jt.writeFileBinary.applySyncPromise(void 0,[i,gu(s)])}else return Jt.writeFile.applySyncPromise(void 0,[i,String(t)])}catch(s){nB(s,"write",n)}},appendFileSync(e,t,r){nr(r);let n=Be(e),i="";try{i=$.existsSync(e)?$.readFileSync(e,"utf8"):""}catch(o){nB(o,"open",n)}let s=typeof t=="string"?t:String(t);try{$.writeFileSync(e,i+s,r)}catch(o){if(!o?.code)throw We("EACCES",`EACCES: permission denied, write '${n}'`,"write",n);nB(o,"write",n)}},readdirSync(e,t){nr(t);let r=Be(e),n=r,i;try{i=Jt.readDir.applySyncPromise(void 0,[n])}catch(o){throw Vi(o)==="ENOENT"?We("ENOENT",`ENOENT: no such file or directory, scandir '${r}'`,"scandir",r):o}let s=Ta(i);return ZW(s,r,t?.withFileTypes)},mkdirSync(e,t){let r=Be(e),n=r,i=typeof t=="object"?t?.recursive??!1:!1,s=typeof t=="object"?t?.mode:t,o=s===void 0?void 0:wa(s);return Jt.mkdir.applySyncPromise(void 0,[n,{recursive:i,mode:A1(o??511)}]),i?r:void 0},rmdirSync(e,t){let r=Be(e);Jt.rmdir.applySyncPromise(void 0,[r])},rmSync(e,t){let r=f1(e),n=t||{};try{if($.statSync(r).isDirectory())if(n.recursive){let s=$.readdirSync(r);for(let o of s){let a=r.endsWith("/")?r+o:r+"/"+o;$.statSync(a).isDirectory()?$.rmSync(a,{recursive:!0}):$.unlinkSync(a)}$.rmdirSync(r)}else $.rmdirSync(r);else $.unlinkSync(r)}catch(i){if(n.force&&i.code==="ENOENT")return;throw i}},existsSync(e){let t=PG(e);return t?t==="/dev/null"||t==="/dev/zero"||t==="/dev/urandom"||t==="/dev/stdin"||t==="/dev/stdout"||t==="/dev/stderr"?!0:Jt.exists.applySyncPromise(void 0,[t]):!1},statSync(e,t){let r=Be(e),n=r,i;try{i=Jt.stat.applySyncPromise(void 0,[n])}catch(o){throw Vi(o)==="ENOENT"?We("ENOENT",`ENOENT: no such file or directory, stat '${r}'`,"stat",r):o}let s=Ta(i);return new hu(s)},lstatSync(e,t){let r=Be(e),n=Hi(()=>Jt.lstat.applySyncPromise(void 0,[r]),"lstat",r),i=Ta(n);return new hu(i)},unlinkSync(e){let t=Be(e);Jt.unlink.applySyncPromise(void 0,[t])},renameSync(e,t){let r=Be(e,"oldPath"),n=Be(t,"newPath");Jt.rename.applySyncPromise(void 0,[r,n])},copyFileSync(e,t,r){let n=$.readFileSync(e);$.writeFileSync(t,n)},cpSync(e,t,r){let n=f1(e),i=f1(t),s=r||{};if($.statSync(n).isDirectory()){if(!s.recursive)throw We("ERR_FS_EISDIR",`Path is a directory: cp '${n}'`,"cp",n);try{$.mkdirSync(i,{recursive:!0})}catch{}let a=$.readdirSync(n);for(let A of a){let f=n.endsWith("/")?n+A:n+"/"+A,l=i.endsWith("/")?i+A:i+"/"+A;$.cpSync(f,l,s)}}else{if(s.errorOnExist&&$.existsSync(i))throw We("EEXIST",`EEXIST: file already exists, cp '${n}' -> '${i}'`,"cp",i);if(!s.force&&s.force!==void 0&&$.existsSync(i))return;$.copyFileSync(n,i)}},mkdtempSync(e,t){nr(t);let r=Be(e,"prefix"),n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let i=0;i<10;i+=1){let s=va.randomBytes(6),o="";for(let A of s)o+=n[A%n.length];let a=r+o;try{return Hi(()=>Jt.mkdir.applySyncPromise(void 0,[a,{recursive:!1,mode:A1(511)}]),"mkdir",a),a}catch(A){if(i<9&&(A?.code==="EEXIST"||Vi(A)==="EEXIST"))continue;throw A}}throw We("EEXIST",`EEXIST: file already exists, mkdtemp '${r}'`,"mkdtemp",r)},opendirSync(e,t){let r=Be(e);if(!$.statSync(r).isDirectory())throw We("ENOTDIR",`ENOTDIR: not a directory, opendir '${r}'`,"opendir",r);return new xG(r)},openSync(e,t,r){let n=Be(e),i=Kve(t??"r"),s=OG(r),o=i&Hn?A1(s??438):s;try{return n1e.applySyncPromise(void 0,[n,i,o])}catch(a){let A=a?.message??String(a);throw A.includes("ENOENT")?We("ENOENT",A,"open",n):A.includes("EMFILE")?We("EMFILE",A,"open",n):a}},closeSync(e){if(ar(e),!L1e(e))try{XW.applySyncPromise(void 0,[e])}catch(t){throw(t?.message??String(t)).includes("EBADF")?We("EBADF","EBADF: bad file descriptor, close","close"):t}},readSync(e,t,r,n,i){let s=Vve(t,r,n,i),o;try{o=i1e.applySyncPromise(void 0,[e,s.length,s.position??null])}catch(f){let l=f?.message??String(f);throw l.includes("EBADF")?We("EBADF",l,"read"):f}let a=Dt.Buffer.from(o,"base64"),A=new Uint8Array(s.buffer.buffer,s.buffer.byteOffset,s.buffer.byteLength);for(let f=0;fJt.chmod.applySyncPromise(void 0,[r,n]),"chmod",r)},chownSync(e,t,r){let n=Be(e),i=Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),s=Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});Hi(()=>Jt.chown.applySyncPromise(void 0,[n,i,s]),"chown",n)},fchmodSync(e,t){let r=ar(e),n=FA.applySync(void 0,[r]);if(!n)throw We("EBADF","EBADF: bad file descriptor","chmod");$.chmodSync(n,wa(t))},fchownSync(e,t,r){let n=ar(e),i=FA.applySync(void 0,[n]);if(!i)throw We("EBADF","EBADF: bad file descriptor","chown");$.chownSync(i,t,r)},lchownSync(e,t,r){let n=Be(e),i=Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),s=Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});Hi(()=>Jt.chown.applySyncPromise(void 0,[n,i,s]),"chown",n)},linkSync(e,t){let r=Be(e,"existingPath"),n=Be(t,"newPath");Hi(()=>Jt.link.applySyncPromise(void 0,[r,n]),"link",n)},symlinkSync(e,t,r){let n=Be(e,"target"),i=Be(t);Hi(()=>Jt.symlink.applySyncPromise(void 0,[n,i]),"symlink",i)},readlinkSync(e,t){nr(t);let r=Be(e);return Hi(()=>Jt.readlink.applySyncPromise(void 0,[r]),"readlink",r)},truncateSync(e,t){let r=Be(e);Hi(()=>Jt.truncate.applySyncPromise(void 0,[r,t??0]),"truncate",r)},utimesSync(e,t,r){let n=Be(e);Hi(()=>Jt.utimes.applySyncPromise(void 0,[n,wo(t,"atime"),wo(r,"mtime")]),"utimes",n)},lutimesSync(e,t,r){let n=Be(e);Hi(()=>Jt.lutimes.applySyncPromise(void 0,[n,wo(t,"atime"),wo(r,"mtime")]),"lutimes",n)},futimesSync(e,t,r){let n=ar(e);Hi(()=>a1e.applySyncPromise(void 0,[n,wo(t,"atime"),wo(r,"mtime")]),"futimes")},readFile(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r){Be(e),nr(t);try{r(null,$.readFileSync(e,t))}catch(n){r(n)}}else return Promise.resolve($.readFileSync(e,t))},writeFile(e,t,r,n){if(typeof r=="function"&&(n=r,r=void 0),n){Be(e),nr(r);try{$.writeFileSync(e,t,r),n(null)}catch(i){n(i)}}else return Promise.resolve($.writeFileSync(e,t,r))},appendFile(e,t,r,n){if(typeof r=="function"&&(n=r,r=void 0),n){Be(e),nr(r);try{$.appendFileSync(e,t,r),n(null)}catch(i){n(i)}}else return Promise.resolve($.appendFileSync(e,t,r))},readdir(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r){Be(e),nr(t);try{r(null,$.readdirSync(e,t))}catch(n){r(n)}}else return Promise.resolve($.readdirSync(e,t))},mkdir(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r){Be(e);try{$.mkdirSync(e,t),r(null)}catch(n){r(n)}}else return $.mkdirSync(e,t),Promise.resolve()},rmdir(e,t){if(t){Be(e);let r=t;try{$.rmdirSync(e),queueMicrotask(()=>r(null))}catch(n){queueMicrotask(()=>r(n))}}else return Promise.resolve($.rmdirSync(e))},rm(e,t,r){let n={},i;typeof t=="function"?i=t:(t&&(n=t),i=r);let s=()=>{try{if($.statSync(e).isDirectory())if(n.recursive){let a=$.readdirSync(e);for(let A of a){let f=e.endsWith("/")?e+A:e+"/"+A;$.statSync(f).isDirectory()?$.rmSync(f,{recursive:!0}):$.unlinkSync(f)}$.rmdirSync(e)}else $.rmdirSync(e);else $.unlinkSync(e)}catch(o){if(n.force&&o.code==="ENOENT")return;throw o}};if(i)try{s(),queueMicrotask(()=>i(null))}catch(o){queueMicrotask(()=>i(o))}else return s(),Promise.resolve()},exists(e,t){if(SA(t,"cb"),e===void 0)throw It("path","of type string or an instance of Buffer or URL",e);queueMicrotask(()=>t(!!(PG(e)&&$.existsSync(e))))},stat(e,t){SA(t,"cb"),Be(e);let r=t;try{let n=$.statSync(e);queueMicrotask(()=>r(null,n))}catch(n){queueMicrotask(()=>r(n))}},lstat(e,t){if(t){let r=t;try{let n=$.lstatSync(e);queueMicrotask(()=>r(null,n))}catch(n){queueMicrotask(()=>r(n))}}else return Promise.resolve($.lstatSync(e))},unlink(e,t){if(t){Be(e);let r=t;try{$.unlinkSync(e),queueMicrotask(()=>r(null))}catch(n){queueMicrotask(()=>r(n))}}else return Promise.resolve($.unlinkSync(e))},rename(e,t,r){if(r){Be(e,"oldPath"),Be(t,"newPath");let n=r;try{$.renameSync(e,t),queueMicrotask(()=>n(null))}catch(i){queueMicrotask(()=>n(i))}}else return Promise.resolve($.renameSync(e,t))},copyFile(e,t,r){if(r)try{$.copyFileSync(e,t),r(null)}catch(n){r(n)}else return Promise.resolve($.copyFileSync(e,t))},cp(e,t,r,n){if(typeof r=="function"&&(n=r,r=void 0),n)try{$.cpSync(e,t,r),n(null)}catch(i){n(i)}else return Promise.resolve($.cpSync(e,t,r))},mkdtemp(e,t,r){typeof t=="function"&&(r=t,t=void 0),SA(r,"cb"),nr(t);try{r(null,$.mkdtempSync(e,t))}catch(n){r(n)}},opendir(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r)try{r(null,$.opendirSync(e,t))}catch(n){r(n)}else return Promise.resolve($.opendirSync(e,t))},open(e,t,r,n){let i="r",s=r;typeof t=="function"?(n=t,s=void 0):i=t??"r",typeof r=="function"&&(n=r,s=void 0),SA(n,"cb"),Be(e),OG(s);let o=n;try{let a=$.openSync(e,i,s);queueMicrotask(()=>o(null,a))}catch(a){queueMicrotask(()=>o(a))}},close(e,t){ar(e),SA(t,"cb");let r=t;try{$.closeSync(e),queueMicrotask(()=>r(null))}catch(n){queueMicrotask(()=>r(n))}},read(e,t,r,n,i,s){if(s){let o=s;if(e===0&&i==null&&typeof _kernelStdinRead<"u"){let A=new Uint8Array(t.buffer,t.byteOffset+r,n),f=()=>{_kernelStdinRead.apply(void 0,[n,100],{result:{promise:!0}}).then(l=>{if(l==null){setTimeout(f,1);return}if(l?.done){queueMicrotask(()=>o(null,0,t));return}let p=String(l?.dataBase64??"");if(!p){setTimeout(f,1);return}let I=Dt.Buffer.from(p,"base64"),S=Math.min(n,I.length);A.set(I.subarray(0,S),0),queueMicrotask(()=>o(null,S,t))},l=>{queueMicrotask(()=>o(l))})};f();return}let a=()=>{try{let A=$.readSync(e,t,r,n,i);queueMicrotask(()=>o(null,A,t))}catch(A){if((A?.message??String(A)).includes("EAGAIN")){setTimeout(a,1);return}queueMicrotask(()=>o(A))}};a()}else return Promise.resolve($.readSync(e,t,r,n,i))},write(e,t,r,n,i,s){if(typeof r=="function"?(s=r,r=void 0,n=void 0,i=void 0):typeof n=="function"?(s=n,n=void 0,i=void 0):typeof i=="function"&&(s=i,i=void 0),s){let o=qG(t,r,n,i),a=s;try{let A=typeof o.buffer=="string"?u1.applySyncPromise(void 0,[e,gu(Dt.Buffer.from(o.buffer,o.encoding)),o.position??null]):u1.applySyncPromise(void 0,[e,gu(Dt.Buffer.from(new Uint8Array(o.buffer.buffer,o.buffer.byteOffset+o.offset,o.length))),o.position??null]);queueMicrotask(()=>a(null,A))}catch(A){queueMicrotask(()=>a(A))}}else return Promise.resolve($.writeSync(e,t,r,n,i))},writev(e,t,r,n){typeof r=="function"&&(n=r,r=null);let i=ar(e),s=qm(t),o=So(r);if(n)try{let a=$.writevSync(i,s,o);queueMicrotask(()=>n(null,a,s))}catch(a){queueMicrotask(()=>n(a))}},writevSync(e,t,r){let n=ar(e),i=qm(t),s=So(r),o=0;for(let a of i){let A=a instanceof Uint8Array?a:new Uint8Array(a.buffer,a.byteOffset,a.byteLength);o+=$.writeSync(n,A,0,A.length,s),s!==null&&(s+=A.length)}return o},fstat(e,t){if(t)try{t(null,$.fstatSync(e))}catch(r){t(r)}else return Promise.resolve($.fstatSync(e))},fsync(e,t){ar(e),SA(t,"cb");try{$.fsyncSync(e),t(null)}catch(r){t(r)}},fdatasync(e,t){ar(e),SA(t,"cb");try{$.fdatasyncSync(e),t(null)}catch(r){t(r)}},readv(e,t,r,n){typeof r=="function"&&(n=r,r=null);let i=ar(e),s=qm(t),o=So(r);if(n)try{let a=$.readvSync(i,s,o);queueMicrotask(()=>n(null,a,s))}catch(a){queueMicrotask(()=>n(a))}},statfs(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r)try{r(null,$.statfsSync(e,t))}catch(n){r(n)}else return Promise.resolve($.statfsSync(e,t))},glob(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r)try{r(null,$.globSync(e,t))}catch(n){r(n)}},promises:{async readFile(e,t){return e instanceof du?e.readFile(t):c1(e,t)},async writeFile(e,t,r){return e instanceof du?e.writeFile(t,r):l1(e,t,r)},async appendFile(e,t,r){if(e instanceof du)return e.appendFile(t,r);let n=await c1(e,"utf8").catch(s=>s?.code==="ENOENT"?"":Promise.reject(s)),i=typeof t=="string"?t:String(t);await l1(e,n+i,r)},async readdir(e,t){return d1e(e,t)},async mkdir(e,t){return g1e(e,t)},async rmdir(e){return p1e(e)},async stat(e){return E1e(e)},async lstat(e){return y1e(e)},async unlink(e){return m1e(e)},async rename(e,t){return B1e(e,t)},async copyFile(e,t){let r=await c1(e);await l1(t,r)},async cp(e,t,r){return $.cpSync(e,t,r)},async mkdtemp(e,t){return $.mkdtempSync(e,t)},async opendir(e,t){return $.opendirSync(e,t)},async open(e,t,r){return new du($.openSync(e,t??"r",r))},async statfs(e,t){return $.statfsSync(e,t)},async glob(e,t){return $.globSync(e,t)},async access(e){return I1e(e)},async rm(e,t){return $.rmSync(e,t)},async chmod(e,t){return b1e(e,t)},async chown(e,t,r){return C1e(e,t,r)},async lchown(e,t,r){return $.lchownSync(e,t,r)},async lutimes(e,t,r){return R1e(e,t,r)},async link(e,t){return Q1e(e,t)},async symlink(e,t){return w1e(e,t)},async readlink(e){return S1e(e)},async realpath(e,t){return $.realpathSync(e,t)},async truncate(e,t){return _1e(e,t)},async utimes(e,t,r){return v1e(e,t,r)},watch(e,t){return Wve(e,t)}},accessSync(e){if(!$.existsSync(e))throw We("ENOENT",`ENOENT: no such file or directory, access '${e}'`,"access",e)},access(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r)try{$.accessSync(e),r(null)}catch(n){r(n)}else return $.promises.access(e)},realpathSync:Object.assign(function(t,r){nr(r);let n=40,i=0,s=Be(t),o=[];for(let A of s.split("/"))!A||A==="."||(A===".."?o.length>0&&o.pop():o.push(A));let a=[];for(;o.length>0;){let A=o.shift();if(A===".")continue;if(A===".."){a.length>0&&a.pop();continue}a.push(A);let f="/"+a.join("/");try{if($.lstatSync(f).isSymbolicLink()){if(++i>n){let S=new Error(`ELOOP: too many levels of symbolic links, realpath '${s}'`);throw S.code="ELOOP",S.syscall="realpath",S.path=s,S}let p=$.readlinkSync(f),I=p.split("/").filter(Boolean);p.startsWith("/")?a.length=0:a.pop(),o.unshift(...I)}}catch(l){let p=l;if(p.code==="ELOOP")throw l;if(p.code==="ENOENT"||p.code==="ENOTDIR"){let I=new Error(`ENOENT: no such file or directory, realpath '${s}'`);throw I.code="ENOENT",I.syscall="realpath",I.path=s,I}break}}return"/"+a.join("/")||"/"},{native(e,t){return nr(t),$.realpathSync(e)}}),realpath:Object.assign(function(t,r,n){let i;if(typeof r=="function"?n=r:i=r,n)nr(i),n(null,$.realpathSync(t,i));else return Promise.resolve($.realpathSync(t,i))},{native(e,t,r){let n;if(typeof t=="function"?r=t:n=t,r)nr(n),r(null,$.realpathSync.native(e,n));else return Promise.resolve($.realpathSync.native(e,n))}}),ReadStream:jW,WriteStream:zW,createReadStream:function(t,r){let n=typeof r=="string"?{encoding:r}:r;nr(n);let i=_B(n?.fd),s=GG(t,i);return new WB(s,n)},createWriteStream:function(t,r){let n=typeof r=="string"?{encoding:r}:r;nr(n),VW(n??{});let i=_B(n?.fd),s=GG(t,i);return new VB(s,n)},watch(...e){let{path:t,listener:r,options:n}=Fve(e[0],e[1],e[2]),i=Gve(t,n);return r&&i.on("change",r),i},watchFile(...e){let{path:t,listener:r,options:n}=kve(e[0],e[1],e[2]);return Yve(t,n,r)},unwatchFile(...e){let t=Be(e[0]),r=e[1];if(r!==void 0&&typeof r!="function")throw It("listener","of type function",r);let n=Wg.get(t);if(n)for(let i of[...n]){let s=i._listeners.get("change")??[];(r===void 0||s.some(o=>o===r||o._originalListener===r))&&i.close()}},chmod(e,t,r){if(r){Be(e),wa(t);try{$.chmodSync(e,t),r(null)}catch(n){r(n)}}else return Promise.resolve($.chmodSync(e,t))},chown(e,t,r,n){if(n){Be(e),Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});try{$.chownSync(e,t,r),n(null)}catch(i){n(i)}}else return Promise.resolve($.chownSync(e,t,r))},fchmod(e,t,r){if(r){ar(e),wa(t);try{$.fchmodSync(e,t),r(null)}catch(n){r(n)}}else return ar(e),wa(t),Promise.resolve($.fchmodSync(e,t))},fchown(e,t,r,n){if(n){ar(e),Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});try{$.fchownSync(e,t,r),n(null)}catch(i){n(i)}}else return ar(e),Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0}),Promise.resolve($.fchownSync(e,t,r))},lchown(e,t,r,n){if(arguments.length>=4){SA(n,"cb"),Be(e),Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});try{$.lchownSync(e,t,r),n(null)}catch(i){n(i)}}else return Promise.resolve($.lchownSync(e,t,r))},link(e,t,r){if(r){Be(e,"existingPath"),Be(t,"newPath");try{$.linkSync(e,t),r(null)}catch(n){r(n)}}else return Promise.resolve($.linkSync(e,t))},symlink(e,t,r,n){if(typeof r=="function"&&(n=r),n)try{$.symlinkSync(e,t),n(null)}catch(i){n(i)}else return Promise.resolve($.symlinkSync(e,t))},readlink(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r){Be(e),nr(t);try{r(null,$.readlinkSync(e,t))}catch(n){r(n)}}else return Promise.resolve($.readlinkSync(e,t))},truncate(e,t,r){if(typeof t=="function"&&(r=t,t=0),r)try{$.truncateSync(e,t),r(null)}catch(n){r(n)}else return Promise.resolve($.truncateSync(e,t))},utimes(e,t,r,n){if(n)try{$.utimesSync(e,t,r),n(null)}catch(i){n(i)}else return Promise.resolve($.utimesSync(e,t,r))},lutimes(e,t,r,n){if(n)try{$.lutimesSync(e,t,r),n(null)}catch(i){n(i)}else return Promise.resolve($.lutimesSync(e,t,r))},futimes(e,t,r,n){if(n)try{$.futimesSync(e,t,r),n(null)}catch(i){n(i)}else return Promise.resolve($.futimesSync(e,t,r))}};KW=e=>$.readdirSync(e);u2=e=>$.statSync(e);var cR=$;et("_fsModule",cR);var Ba={platform:typeof _osConfig<"u"&&_osConfig.platform||"linux",arch:typeof _osConfig<"u"&&_osConfig.arch||"x64",type:typeof _osConfig<"u"&&_osConfig.type||"Linux",release:typeof _osConfig<"u"&&_osConfig.release||"6.8.0-secure-exec",version:typeof _osConfig<"u"&&_osConfig.version||"#1 SMP PREEMPT_DYNAMIC secure-exec",homedir:typeof _osConfig<"u"&&_osConfig.homedir||"/home/user",tmpdir:typeof _osConfig<"u"&&_osConfig.tmpdir||"/tmp",hostname:typeof _osConfig<"u"&&_osConfig.hostname||"secure-exec",machine:typeof _osConfig<"u"&&_osConfig.machine||"x86_64"};function JG(){return _s("homedir",globalThis.process?.env?.HOME||Ba.homedir)}function D1e(){return _s("tmpdir",globalThis.process?.env?.TMPDIR||Ba.tmpdir)}function T1e(){return _s("user",globalThis.process?.env?.USER||globalThis.process?.env?.LOGNAME||"user")}function N1e(){return _s("shell",globalThis.process?.env?.SHELL||"/bin/sh")}function l2(){let e=globalThis.process?.uid;return Number.isFinite(e)?e:0}function iB(){let e=globalThis.process?.gid;return Number.isFinite(e)?e:0}function $W(){return globalThis.__agentOSVirtualOs||{}}function _s(e,t){let r=$W()[e];return typeof r=="string"&&r.length>0?r:t}function lR(e,t){let r=Number($W()[e]);return Number.isSafeInteger(r)&&r>0?r:t}function jG(){return lR("cpuCount",1)}function eV(){return lR("totalmem",1073741824)}function M1e(){return Math.min(lR("freemem",536870912),eV())}var tV={SIGHUP:1,SIGINT:2,SIGQUIT:3,SIGILL:4,SIGTRAP:5,SIGABRT:6,SIGIOT:6,SIGBUS:7,SIGFPE:8,SIGKILL:9,SIGUSR1:10,SIGSEGV:11,SIGUSR2:12,SIGPIPE:13,SIGALRM:14,SIGTERM:15,SIGSTKFLT:16,SIGCHLD:17,SIGCONT:18,SIGSTOP:19,SIGTSTP:20,SIGTTIN:21,SIGTTOU:22,SIGURG:23,SIGXCPU:24,SIGXFSZ:25,SIGVTALRM:26,SIGPROF:27,SIGWINCH:28,SIGIO:29,SIGPOLL:29,SIGPWR:30,SIGSYS:31},zG={1:"SIGHUP",2:"SIGINT",3:"SIGQUIT",4:"SIGILL",5:"SIGTRAP",6:"SIGABRT",7:"SIGBUS",8:"SIGFPE",9:"SIGKILL",10:"SIGUSR1",11:"SIGSEGV",12:"SIGUSR2",13:"SIGPIPE",14:"SIGALRM",15:"SIGTERM",16:"SIGSTKFLT",17:"SIGCHLD",18:"SIGCONT",19:"SIGSTOP",20:"SIGTSTP",21:"SIGTTIN",22:"SIGTTOU",23:"SIGURG",24:"SIGXCPU",25:"SIGXFSZ",26:"SIGVTALRM",27:"SIGPROF",28:"SIGWINCH",29:"SIGIO",30:"SIGPWR",31:"SIGSYS"};function hR(e){if(e==null)return{bridgeSignal:"SIGTERM",signalCode:"SIGTERM"};if(e===0||e==="0")return{bridgeSignal:"0",signalCode:null};if(typeof e=="number"){let t=zG[e];if(t)return{bridgeSignal:t,signalCode:t};throw new Error("Unknown signal: "+e)}if(typeof e=="string"){let t=tV[e];if(t!==void 0){let r=zG[t]??e;return{bridgeSignal:r,signalCode:r}}}throw new Error("Unknown signal: "+e)}var F1e={E2BIG:7,EACCES:13,EADDRINUSE:98,EADDRNOTAVAIL:99,EAFNOSUPPORT:97,EAGAIN:11,EALREADY:114,EBADF:9,EBADMSG:74,EBUSY:16,ECANCELED:125,ECHILD:10,ECONNABORTED:103,ECONNREFUSED:111,ECONNRESET:104,EDEADLK:35,EDESTADDRREQ:89,EDOM:33,EDQUOT:122,EEXIST:17,EFAULT:14,EFBIG:27,EHOSTUNREACH:113,EIDRM:43,EILSEQ:84,EINPROGRESS:115,EINTR:4,EINVAL:22,EIO:5,EISCONN:106,EISDIR:21,ELOOP:40,EMFILE:24,EMLINK:31,EMSGSIZE:90,EMULTIHOP:72,ENAMETOOLONG:36,ENETDOWN:100,ENETRESET:102,ENETUNREACH:101,ENFILE:23,ENOBUFS:105,ENODATA:61,ENODEV:19,ENOENT:2,ENOEXEC:8,ENOLCK:37,ENOLINK:67,ENOMEM:12,ENOMSG:42,ENOPROTOOPT:92,ENOSPC:28,ENOSR:63,ENOSTR:60,ENOSYS:38,ENOTCONN:107,ENOTDIR:20,ENOTEMPTY:39,ENOTSOCK:88,ENOTSUP:95,ENOTTY:25,ENXIO:6,EOPNOTSUPP:95,EOVERFLOW:75,EPERM:1,EPIPE:32,EPROTO:71,EPROTONOSUPPORT:93,EPROTOTYPE:91,ERANGE:34,EROFS:30,ESPIPE:29,ESRCH:3,ESTALE:116,ETIME:62,ETIMEDOUT:110,ETXTBSY:26,EWOULDBLOCK:11,EXDEV:18},k1e={PRIORITY_LOW:19,PRIORITY_BELOW_NORMAL:10,PRIORITY_NORMAL:0,PRIORITY_ABOVE_NORMAL:-7,PRIORITY_HIGH:-14,PRIORITY_HIGHEST:-20},rV={platform(){return _s("platform",Ba.platform)},arch(){return _s("arch",Ba.arch)},type(){return _s("type",Ba.type)},release(){return _s("release",Ba.release)},version(){return _s("version",Ba.version)},homedir(){return JG()},tmpdir(){return D1e()},hostname(){return _s("hostname",Ba.hostname)},userInfo(e){return{username:T1e(),uid:l2(),gid:iB(),shell:N1e(),homedir:JG()}},cpus(){return Array.from({length:jG()},()=>({model:"Virtual CPU",speed:2e3,times:{user:1e5,nice:0,sys:5e4,idle:8e5,irq:0}}))},totalmem(){return eV()},freemem(){return M1e()},loadavg(){return[.1,.1,.1]},uptime(){return 3600},networkInterfaces(){return{}},endianness(){return"LE"},EOL:` -`,devNull:"/dev/null",machine(){return _s("machine",Ba.machine)},constants:{signals:tV,errno:F1e,priority:k1e,dlopen:{RTLD_LAZY:1,RTLD_NOW:2,RTLD_GLOBAL:256,RTLD_LOCAL:0},UV_UDP_REUSEADDR:4},getPriority(e){return 0},setPriority(e,t){},availableParallelism(){return jG()}};et("_osModule",rV);var U1e=rV,nV={};_2(nV,{ChildProcess:()=>gR,default:()=>V1e,exec:()=>fV,execFile:()=>cV,execFileSync:()=>lV,execSync:()=>uV,fork:()=>hV,spawn:()=>n0,spawnSync:()=>pR});var Iu=new Map,Vg=new Map;function x1e(e){if(typeof e!="number")return;let t=Vg.get(e);t?t.holders+=1:Vg.set(e,{holders:1,closePending:!1})}function L1e(e){let t=Vg.get(e);return t?(t.closePending=!0,!0):!1}function P1e(e){let t=Vg.get(e);if(t&&(t.holders-=1,!(t.holders>0)&&(Vg.delete(e),t.closePending)))try{XW.applySyncPromise(void 0,[e])}catch{}}var O1e=200,H1e=25;function q1e(e){return!e||typeof e!="object"?null:typeof e.sessionId=="string"&&e.sessionId.length>0||typeof e.sessionId=="number"&&Number.isFinite(e.sessionId)?e.sessionId:null}function dR(e){if(e&&typeof e=="object")return e;if(typeof e=="string")try{let t=JSON.parse(e);return t&&typeof t=="object"?t:e}catch{}return e}var h2="AGENTOS_IPC:";function iV(e){let t=JSON.stringify(e),r=typeof Buffer<"u"?Buffer.from(t,"utf8").toString("base64"):btoa(t);return`${h2}${r} -`}function G1e(e){let t=typeof Buffer<"u"?Buffer.from(e,"base64").toString("utf8"):atob(e);return JSON.parse(t)}function sV(e,t){let r=`${e}${typeof Buffer<"u"?Buffer.from(t).toString("utf8"):String(t)}`,n=[],i=[],s=0;for(;;){let o=r.indexOf(h2,s);if(o===-1)return i.push(r.slice(s)),{buffer:"",messages:n,output:i.join("")};i.push(r.slice(s,o));let a=o+h2.length,A=r.indexOf(` -`,a);if(A===-1)return{buffer:r.slice(o),messages:n,output:i.join("")};try{n.push(G1e(r.slice(a,A)))}catch{i.push(r.slice(o,A+1))}s=A+1}}function oV(e,t){if(!t||typeof t!="object")return!1;if(t.type==="stdout"||t.type==="stderr"){let r={sessionId:e};return typeof t.data=="string"?r.data=t.data:typeof Buffer<"u"&&Buffer.isBuffer(t.data)?r.dataBase64=t.data.toString("base64"):t.data instanceof Uint8Array||ArrayBuffer.isView(t.data)?r.dataBase64=Buffer.from(t.data.buffer,t.data.byteOffset,t.data.byteLength).toString("base64"):t.data?.__agentOSType==="bytes"&&typeof t.data.base64=="string"&&(r.dataBase64=t.data.base64),d2(`child_${t.type}`,r),!0}return t.type==="exit"?(d2("child_exit",{sessionId:e,code:t.exitCode,signal:t.signal??null}),!0):!1}function aV(e){e?._detachedBootstrapPending&&(e._detachedBootstrapPending=!1,e._detachedBootstrapPollsRemaining=0,e._detachedBootstrapTimer!=null&&(clearTimeout(e._detachedBootstrapTimer),e._detachedBootstrapTimer=null),e._pollRefed||(e._pollTimer?.unref?.(),e._handleRefed&&e._handleId&&typeof _unregisterHandle=="function"&&(_unregisterHandle(e._handleId),e._handleRefed=!1)))}function AV(e){e?._detachedBootstrapPending&&(e._detachedBootstrapPollsRemaining>0&&(e._detachedBootstrapPollsRemaining-=1),e._detachedBootstrapPollsRemaining===0&&aV(e))}function Y1e(e,t=H1e){if(!e?.detached||e._sessionId==null||typeof _childProcessPoll>"u")return!1;if(!e._detachedBootstrapPending)return!0;for(let r=0;r{if(typeof e=="number"){d1(e,t,r);return}let n=(()=>{if(t&&typeof t=="object")return t;if(typeof t=="string")try{return JSON.parse(t)}catch{return null}return null})(),i=q1e(n);if(i!=null){if(e==="child_stdout"||e==="child_stderr"){let s=n?.data,o;if(typeof Buffer<"u"&&Buffer.isBuffer(s))o=Buffer.from(s);else if(s instanceof Uint8Array)o=typeof Buffer<"u"?Buffer.from(s.buffer,s.byteOffset,s.byteLength):s;else if(ArrayBuffer.isView(s))o=typeof Buffer<"u"?Buffer.from(s.buffer,s.byteOffset,s.byteLength):new Uint8Array(s.buffer,s.byteOffset,s.byteLength);else{let a=typeof n?.dataBase64=="string"?n.dataBase64:typeof s=="string"?s:s?.__agentOSType==="bytes"&&typeof s?.base64=="string"?s.base64:"";o=typeof Buffer<"u"?Buffer.from(a,"base64"):new Uint8Array(atob(a).split("").map(A=>A.charCodeAt(0)))}d1(i,e==="child_stdout"?"stdout":"stderr",o);return}if(e==="child_exit"){let s=typeof n?.code=="number"?n.code:Number(n?.code??1),o=typeof n?.signal=="string"?n.signal:null;d1(i,"exit",{code:s,signal:o})}}};et("_childProcessDispatch",d2);var W1e=64;function g2(e,t=0){let r=Iu.get(e);if(!r||typeof _childProcessPoll>"u"||r._pollScheduled)return;r._pollScheduled=!0;let n=setTimeout(()=>{if(r._pollTimer=null,r._pollScheduled=!1,!Iu.has(e))return;let i=0;for(;i0||(e._onceListeners[t]?.length??0)>0}function KG(e,t){let r=e._readableEncoding;return!r||typeof t=="string"?t:typeof Buffer<"u"&&Buffer.isBuffer(t)?t.toString(r):t instanceof Uint8Array?typeof Buffer<"u"?Buffer.from(t).toString(r):String(t):t}function _g(e){e._flushScheduled||(e._flushScheduled=!0,queueMicrotask(()=>{if(e._flushScheduled=!1,e._bufferedChunks.length>0&&Dl(e,"data")){let t=e._bufferedChunks.splice(0,e._bufferedChunks.length);for(let r of t)e.emit("data",r)}e._ended&&e._bufferedChunks.length===0&&Dl(e,"end")&&e.emit("end")}))}function Gm(e,t){if(e._maxListenersWarned instanceof Set||(e._maxListenersWarned=new Set),e._maxListeners>0&&!e._maxListenersWarned.has(t)){let r=(e._listeners[t]?.length??0)+(e._onceListeners[t]?.length??0);if(r>e._maxListeners){e._maxListenersWarned.add(t);let n=`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${r} ${t} listeners added. MaxListeners is ${e._maxListeners}. Use emitter.setMaxListeners() to increase limit`;typeof console<"u"&&console.error&&console.error(n)}}}function XG(e){let t=[],r=[],n=[],i=!1,s=()=>{for(;n.length>0;){let f=n.shift();if(r.length>0){f(Promise.reject(r.shift()));continue}if(t.length>0){f(Promise.resolve({done:!1,value:t.shift()}));continue}if(i){f(Promise.resolve({done:!0,value:void 0}));continue}n.unshift(f);break}},o=f=>{t.push(f),s()},a=()=>{i=!0,s()},A=f=>{r.push(f),i=!0,s()};return e.on("data",o),e.on("end",a),e.on("close",a),e.on("error",A),_g(e),{next(){return r.length>0?Promise.reject(r.shift()):t.length>0?Promise.resolve({done:!1,value:t.shift()}):i?Promise.resolve({done:!0,value:void 0}):new Promise(f=>{n.push(f)})},return(){return e.off("data",o),e.off("end",a),e.off("close",a),e.off("error",A),i=!0,s(),Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}}}var vl=1e3,gR=class{constructor(){y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_maxListeners",10);y(this,"_maxListenersWarned",new Set);y(this,"pid",vl++);y(this,"killed",!1);y(this,"exitCode",null);y(this,"signalCode",null);y(this,"_pendingSignalCode",null);y(this,"connected",!1);y(this,"_pollScheduled",!1);y(this,"_pollRefed",!0);y(this,"_pollTimer",null);y(this,"_detachedBootstrapPending",!1);y(this,"_detachedBootstrapPollsRemaining",0);y(this,"_detachedBootstrapTimer",null);y(this,"_sessionId",null);y(this,"_handleId",null);y(this,"_handleDescription","");y(this,"_handleRefed",!1);y(this,"_ipcEnabled",!1);y(this,"_ipcStdoutBuffer","");y(this,"_ipcQueuedMessages",[]);y(this,"spawnfile","");y(this,"spawnargs",[]);y(this,"stdin");y(this,"stdout");y(this,"stderr");y(this,"stdio");this.stdin={writable:!0,destroyed:!1,_listeners:{},_onceListeners:{},write(e,t,r){let n=typeof t=="function"?t:r;return n&&queueMicrotask(()=>n(null)),!0},end(e,t,r){let n=typeof e=="function"?e:typeof t=="function"?t:r;this.writable=!1,n&&queueMicrotask(()=>n())},destroy(){return this.writable=!1,this.destroyed=!0,this.emit("close"),this},on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this},once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this},off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}if(this._onceListeners[e]){let r=this._onceListeners[e].indexOf(t);r!==-1&&this._onceListeners[e].splice(r,1)}return this},removeListener(e,t){return this.off(e,t)},emit(e,...t){let r=!1;return this._listeners[e]&&this._listeners[e].forEach(n=>{n(...t),r=!0}),this._onceListeners[e]&&(this._onceListeners[e].forEach(n=>{n(...t),r=!0}),this._onceListeners[e]=[]),r}},this.stdout={readable:!0,isTTY:!1,destroyed:!1,_listeners:{},_onceListeners:{},_bufferedChunks:[],_ended:!1,_flushScheduled:!1,_maxListeners:10,_maxListenersWarned:new Set,on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),Gm(this,e),(e==="data"||e==="end")&&_g(this),this},once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),Gm(this,e),(e==="data"||e==="end")&&_g(this),this},off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}if(this._onceListeners[e]){let r=this._onceListeners[e].indexOf(t);r!==-1&&this._onceListeners[e].splice(r,1)}return this},removeListener(e,t){return this.off(e,t)},emit(e,...t){return e==="data"&&(t[0]=KG(this,t[0]),!Dl(this,"data"))?(this._bufferedChunks.push(t[0]),!1):e==="end"&&(this._ended=!0,!Dl(this,"end"))?!1:(this._listeners[e]&&this._listeners[e].forEach(r=>r(...t)),this._onceListeners[e]&&(this._onceListeners[e].forEach(r=>r(...t)),this._onceListeners[e]=[]),!0)},read(){return null},setEncoding(e){return this._readableEncoding=e==null||e==="buffer"?null:String(e),this},setMaxListeners(e){return this._maxListeners=e,this},getMaxListeners(){return this._maxListeners},pipe(e){return e},pause(){return this},resume(){return this},destroy(){return this.readable=!1,this._ended=!0,this.destroyed=!0,this.emit("close"),this},[Symbol.asyncIterator](){return XG(this)}},this.stderr={readable:!0,isTTY:!1,destroyed:!1,_listeners:{},_onceListeners:{},_bufferedChunks:[],_ended:!1,_flushScheduled:!1,_maxListeners:10,_maxListenersWarned:new Set,on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),Gm(this,e),(e==="data"||e==="end")&&_g(this),this},once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),Gm(this,e),(e==="data"||e==="end")&&_g(this),this},off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}if(this._onceListeners[e]){let r=this._onceListeners[e].indexOf(t);r!==-1&&this._onceListeners[e].splice(r,1)}return this},removeListener(e,t){return this.off(e,t)},emit(e,...t){return e==="data"&&(t[0]=KG(this,t[0]),!Dl(this,"data"))?(this._bufferedChunks.push(t[0]),!1):e==="end"&&(this._ended=!0,!Dl(this,"end"))?!1:(this._listeners[e]&&this._listeners[e].forEach(r=>r(...t)),this._onceListeners[e]&&(this._onceListeners[e].forEach(r=>r(...t)),this._onceListeners[e]=[]),!0)},read(){return null},setEncoding(e){return this._readableEncoding=e==null||e==="buffer"?null:String(e),this},setMaxListeners(e){return this._maxListeners=e,this},getMaxListeners(){return this._maxListeners},pipe(e){return e},pause(){return this},resume(){return this},destroy(){return this.readable=!1,this._ended=!0,this.destroyed=!0,this.emit("close"),this},[Symbol.asyncIterator](){return XG(this)}},this.stdio=[this.stdin,this.stdout,this.stderr]}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this._checkMaxListeners(e),e==="message"&&this._flushQueuedIpcMessages(),this}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this._checkMaxListeners(e),e==="message"&&this._flushQueuedIpcMessages(),this}off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}return this}removeListener(e,t){return this.off(e,t)}setMaxListeners(e){return this._maxListeners=e,this}getMaxListeners(){return this._maxListeners}_checkMaxListeners(e){if(this._maxListenersWarned instanceof Set||(this._maxListenersWarned=new Set),this._maxListeners>0&&!this._maxListenersWarned.has(e)){let t=(this._listeners[e]?.length??0)+(this._onceListeners[e]?.length??0);if(t>this._maxListeners){this._maxListenersWarned.add(e);let r=`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${t} ${e} listeners added to [ChildProcess]. MaxListeners is ${this._maxListeners}. Use emitter.setMaxListeners() to increase limit`;typeof console<"u"&&console.error&&console.error(r)}}}_hasIpcMessageListeners(){return(this._listeners.message?.length??0)>0||(this._onceListeners.message?.length??0)>0}_emitOrQueueIpcMessage(e){return this._hasIpcMessageListeners()?this.emit("message",e,void 0):(this._ipcQueuedMessages.push(e),!1)}_flushQueuedIpcMessages(){this._ipcQueuedMessages.length!==0&&queueMicrotask(()=>{for(;this._ipcQueuedMessages.length>0&&this._hasIpcMessageListeners();)this.emit("message",this._ipcQueuedMessages.shift(),void 0)})}emit(e,...t){let r=!1;return this._listeners[e]&&this._listeners[e].forEach(n=>{n(...t),r=!0}),this._onceListeners[e]&&(this._onceListeners[e].forEach(n=>{n(...t),r=!0}),this._onceListeners[e]=[]),r}kill(e){let t=hR(e);return this.killed=!0,this._pendingSignalCode=t.signalCode,!0}ref(){return this._pollRefed=!0,this._pollTimer?.ref?.(),!this._handleRefed&&this._handleId&&typeof _registerHandle=="function"&&(_registerHandle(this._handleId,this._handleDescription),this._handleRefed=!0),this}unref(){return this._pollRefed=!1,this._detachedBootstrapPending&&Y1e(this),this._detachedBootstrapPending||this._pollTimer?.unref?.(),!this._detachedBootstrapPending&&this._handleRefed&&this._handleId&&typeof _unregisterHandle=="function"&&(_unregisterHandle(this._handleId),this._handleRefed=!1),this}disconnect(){this.connected=!1,this.emit("disconnect")}send(e,t,r,n){if(!this.connected||!this._ipcEnabled||this._sessionId==null)return!1;let i=typeof t=="function"?t:typeof r=="function"?r:n;try{let s=iV(e);return this.stdin.write(s,"utf8",i),!0}catch(s){return i?(queueMicrotask(()=>i(s)),!1):(this.emit("error",s),!1)}}_complete(e,t,r){let n=this._pendingSignalCode??this.signalCode;if(this._pendingSignalCode=null,this.signalCode=n??null,this.exitCode=n==null?r:null,e){let i=typeof Buffer<"u"?Buffer.from(e):e;this.stdout.emit("data",i)}if(t){let i=typeof Buffer<"u"?Buffer.from(t):t;this.stderr.emit("data",i)}this.stdout.emit("end"),this.stderr.emit("end"),this.emit("close",this.exitCode,this.signalCode),this.emit("exit",this.exitCode,this.signalCode)}};function fV(e,t,r){typeof t=="function"&&(r=t,t={});let n=n0(e,[],{...t,shell:!0});n.spawnargs=[e],n.spawnfile=e;let i=t?.maxBuffer??1024*1024,s="",o="",a=0,A=0,f=!1,l=!1,p=null,I=S=>{!r||l||(l=!0,r(S,s,o))};return n.stdout.on("data",S=>{if(f)return;let _=String(S);s+=_,a+=_.length,a>i&&(f=!0,n.kill("SIGTERM"))}),n.stderr.on("data",S=>{if(f)return;let _=String(S);o+=_,A+=_.length,A>i&&(f=!0,n.kill("SIGTERM"))}),n.on("close",(...S)=>{let _=S[0];if(r)if(f){let N=new Error("stdout maxBuffer length exceeded");N.code="ERR_CHILD_PROCESS_STDIO_MAXBUFFER",N.killed=!0,N.cmd=e,N.stdout=s,N.stderr=o,I(N)}else if(_!==0&&p==null){let N=new Error("Command failed: "+e);N.code=_,N.killed=!1,N.signal=null,N.cmd=e,N.stdout=s,N.stderr=o,I(N)}else I(null)}),n.on("error",S=>{if(r){let _=S instanceof Error?S:new Error(String(S));p=_,_.cmd=e,_.stdout=s,_.stderr=o,I(_)}}),n}function uV(e,t){let r=t||{};if(typeof _childProcessSpawnSync>"u")throw new Error("child_process.execSync requires CommandExecutor to be configured");let n=r.cwd??(typeof process<"u"?process.cwd():"/"),i=r.maxBuffer??1024*1024,s=_childProcessSpawnSync.applySyncPromise(void 0,[e,JSON.stringify([]),JSON.stringify({cwd:n,env:r.env,input:r.input==null?null:gu(r.input),maxBuffer:i,shell:!0})]),o=typeof s=="string"?JSON.parse(s):s,a=Array.isArray(r.stdio)?r.stdio:r.stdio==="inherit"?["inherit","inherit","inherit"]:[];if(vB(a[1],o.stdout)&&(o.stdout=typeof o.stdout=="string"?"":Buffer.from("")),vB(a[2],o.stderr),o.maxBufferExceeded){let A=new Error("stdout maxBuffer length exceeded");throw A.code="ERR_CHILD_PROCESS_STDIO_MAXBUFFER",A.stdout=o.stdout,A.stderr=o.stderr,A}if(o.code!==0){let A=new Error("Command failed: "+e);throw A.status=o.code,A.stdout=o.stdout,A.stderr=o.stderr,A.output=[null,o.stdout,o.stderr],A}return(r.encoding==="buffer"||!r.encoding)&&typeof Buffer<"u"?Buffer.from(o.stdout):o.stdout}function n0(e,t,r){let n=[],i={};Array.isArray(t)?(n=t,i=r||{}):i=t||{};let s=new gR;s.spawnfile=e,s.spawnargs=[e,...n],s.detached=i.detached===!0,s._detachedBootstrapPending=s.detached,s._detachedBootstrapPollsRemaining=s.detached?O1e:0;let o=Array.isArray(i.stdio)?i.stdio:i.stdio==="inherit"?["inherit","inherit","inherit"]:[];s._stdoutFd=typeof o[1]=="number"?o[1]:null,s._stderrFd=typeof o[2]=="number"?o[2]:null,s._inheritedFds=[];for(let A of[s._stdoutFd,s._stderrFd])typeof A=="number"&&(x1e(A),s._inheritedFds.push(A));if(typeof _childProcessSpawnStart<"u"){let A;try{let l=i.cwd??(typeof process<"u"?process.cwd():"/");A=dR(_childProcessSpawnStart.applySync(void 0,[e,JSON.stringify(n),JSON.stringify({cwd:l,env:i.env,shell:i.shell===!0||typeof i.shell=="string",detached:i.detached===!0})]))}catch(l){let p=l instanceof Error?l:new Error(String(l));return p.code==null&&/command not found:/i.test(String(p.message||""))?p.code="ENOENT":p.code==null&&/ERR_NATIVE_BINARY_NOT_SUPPORTED\b/i.test(String(p.message||""))&&(p.code="ERR_NATIVE_BINARY_NOT_SUPPORTED"),queueMicrotask(()=>{s.emit("error",p)}),s}let f=typeof A=="object"&&A!==null?A.childId:A;return Iu.set(f,s),s._sessionId=f,typeof _registerHandle=="function"&&(s._handleId=`child:${f}`,s._handleDescription=`child_process: ${e} ${n.join(" ")}`,_registerHandle(s._handleId,s._handleDescription),s._handleRefed=!0),s.stdin.write=(l,p,I)=>{let S=typeof p=="function"?p:I;if(typeof _childProcessStdinWrite>"u")return!1;let _=typeof l=="string"?new TextEncoder().encode(l):l;try{_childProcessStdinWrite.applySync(void 0,[f,_])}catch(N){return S?(queueMicrotask(()=>S(N)),!1):(s.stdin.emit("error",N),!1)}return S&&queueMicrotask(()=>S(null)),!0},s.stdin.end=(l,p,I)=>{let S=typeof l=="function"?l:typeof p=="function"?p:I;if(l!=null&&typeof l!="function"&&s.stdin.write(l,typeof p=="string"?p:void 0),typeof _childProcessStdinClose<"u")try{_childProcessStdinClose.applySync(void 0,[f])}catch(_){if(S){queueMicrotask(()=>S(_));return}s.stdin.emit("error",_);return}s.stdin.writable=!1,S&&queueMicrotask(()=>S())},s.stdin.destroy=()=>(s.stdin.end(),s.stdin.destroyed=!0,s.stdin.emit("close"),s.stdin),s.kill=l=>{if(typeof _childProcessKill>"u")return!1;let p=hR(l);return _childProcessKill.applySync(void 0,[f,p.bridgeSignal]),s.killed=!0,s._pendingSignalCode=p.signalCode,!0},s.pid=typeof A=="object"&&A!==null?Number(A.pid)||-1:Number(f)||-1,(o[1]==="inherit"||o[1]===1)&&s.stdout.on("data",l=>process.stdout.write(l)),(o[2]==="inherit"||o[2]===2)&&s.stderr.on("data",l=>process.stderr.write(l)),setTimeout(()=>s.emit("spawn"),0),g2(f,0),s}let a=new Error("child_process.spawn requires CommandExecutor to be configured");return setTimeout(()=>{s.emit("error",a),s._complete("",a.message,1)},0),s}function pR(e,t,r){let n=[],i={};if(Array.isArray(t)?(n=t,i=r||{}):i=t||{},typeof _childProcessSpawnSync>"u")return{pid:vl++,output:[null,"","child_process.spawnSync requires CommandExecutor to be configured"],stdout:"",stderr:"child_process.spawnSync requires CommandExecutor to be configured",status:1,signal:null,error:new Error("child_process.spawnSync requires CommandExecutor to be configured")};try{let s=i.cwd??(typeof process<"u"?process.cwd():"/"),o=i.maxBuffer,a=i.encoding==null||i.encoding==="buffer",A=Number.isInteger(i.timeout)&&i.timeout>0?i.timeout:null,f=hR(i.killSignal).signalCode??"SIGTERM",l=_childProcessSpawnSync.applySyncPromise(void 0,[e,JSON.stringify(n),JSON.stringify({cwd:s,env:i.env,input:i.input==null?null:gu(i.input),maxBuffer:o,shell:i.shell===!0||typeof i.shell=="string",timeout:A,killSignal:f})]),p=typeof l=="string"?JSON.parse(l):l,I=Array.isArray(i.stdio)?i.stdio:i.stdio==="inherit"?["inherit","inherit","inherit"]:[],S=a&&typeof Buffer<"u"?Buffer.from(p.stdout):p.stdout,_=a&&typeof Buffer<"u"?Buffer.from(p.stderr):p.stderr;if(vB(I[1],S)&&(S=a&&typeof Buffer<"u"?Buffer.from(""):""),vB(I[2],_)&&(_=a&&typeof Buffer<"u"?Buffer.from(""):""),p.timedOut){let N=new Error(`spawnSync ${e} ETIMEDOUT`);return N.code="ETIMEDOUT",{pid:vl++,output:[null,S,_],stdout:S,stderr:_,status:null,signal:p.signal??f,error:N}}if(p.maxBufferExceeded){let N=new Error("stdout maxBuffer length exceeded");return N.code="ERR_CHILD_PROCESS_STDIO_MAXBUFFER",{pid:vl++,output:[null,S,_],stdout:S,stderr:_,status:p.code,signal:null,error:N}}return{pid:vl++,output:[null,S,_],stdout:S,stderr:_,status:p.code,signal:null,error:void 0}}catch(s){s&&typeof s=="object"&&s.code==null&&/ERR_NATIVE_BINARY_NOT_SUPPORTED\b/i.test(String(s.message||s))&&(s.code="ERR_NATIVE_BINARY_NOT_SUPPORTED");let o=s instanceof Error?s.message:String(s),a=i.encoding==null||i.encoding==="buffer",A=a&&typeof Buffer<"u"?Buffer.from(""):"",f=a&&typeof Buffer<"u"?Buffer.from(o):o;return{pid:vl++,output:[null,A,f],stdout:A,stderr:f,status:1,signal:null,error:s instanceof Error?s:new Error(String(s))}}}function cV(e,t,r,n){let i=[],s={},o;typeof t=="function"?o=t:typeof r=="function"?(i=t.slice(),o=r):(i=Array.isArray(t)?t:[],s=r||{},o=n);let a=s.maxBuffer??1024*1024,A=n0(e,i,s),f="",l="",p=0,I=0,S=!1;return A.stdout.on("data",_=>{let N=String(_);f+=N,p+=N.length,p>a&&!S&&(S=!0,A.kill("SIGTERM"))}),A.stderr.on("data",_=>{let N=String(_);l+=N,I+=N.length,I>a&&!S&&(S=!0,A.kill("SIGTERM"))}),A.on("close",(..._)=>{let N=_[0];if(o)if(S){let O=new Error("stdout maxBuffer length exceeded");O.code="ERR_CHILD_PROCESS_STDIO_MAXBUFFER",O.killed=!0,O.stdout=f,O.stderr=l,o(O,f,l)}else if(N!==0){let O=new Error("Command failed: "+e);O.code=N,O.stdout=f,O.stderr=l,o(O,f,l)}else o(null,f,l)}),A.on("error",_=>{o&&o(_,f,l)}),A}function lV(e,t,r){let n=[],i={};Array.isArray(t)?(n=t,i=r||{}):i=t||{};let s=i.maxBuffer??1024*1024,o=pR(e,n,{...i,maxBuffer:s});if(o.error&&String(o.error.code)==="ERR_CHILD_PROCESS_STDIO_MAXBUFFER")throw o.error;if(o.status!==0){let a=new Error("Command failed: "+e);throw a.status=o.status??void 0,a.stdout=String(o.stdout),a.stderr=String(o.stderr),a}return i.encoding==="buffer"||!i.encoding||typeof o.stdout=="string"?o.stdout:o.stdout.toString(i.encoding)}function hV(e,t,r){if(typeof e!="string"||e.length===0)throw new TypeError('The "modulePath" argument must be of type string');let n=[],i={};Array.isArray(t)?(n=t.slice(),i=r||{}):i=t||{};let s=i.cwd??(typeof process<"u"?process.cwd():"/"),o=Array.isArray(i.execArgv)?i.execArgv:typeof process<"u"&&Array.isArray(process.execArgv)?process.execArgv:[],a={...typeof process<"u"?process.env:{},...i.env||{},AGENTOS_NODE_IPC:"1"},A=n0(i.execPath||(typeof process<"u"?process.execPath:"node"),[...o,e,...n],{...i,cwd:s,env:a,shell:!1});return A._ipcEnabled=!0,A.connected=!0,A}var dV={ChildProcess:gR,exec:fV,execSync:uV,spawn:n0,spawnSync:pR,execFile:cV,execFileSync:lV,fork:hV};et("_childProcessModule",dV);var V1e=dV,oi={},bn={},p2=new _u,ZG="process.stdin",Or="",E2=!1,Ym=!1,sB=!1,oB=!1;vu("_stdinData",typeof _processConfig<"u"&&_processConfig.stdin||"");vu("_stdinPosition",0);vu("_stdinEnded",!1);vu("_stdinFlowMode",!1);function Ra(){return globalThis._stdinData}function J1e(e){globalThis._stdinData=e}function Au(){return globalThis._stdinPosition}function ER(e){globalThis._stdinPosition=e}function LA(){return globalThis._stdinEnded}function yR(e){globalThis._stdinEnded=e}function RB(){return globalThis._stdinFlowMode}function vg(e){globalThis._stdinFlowMode=e}function j1e(e){Or="",E2=!1,p2=e,sB=!1,oB=!1}function g1(){if(!(LA()||!Ra())&&RB()&&Au()0}function jg(e){if(e){if(!Ym&&typeof _registerHandle=="function")try{_registerHandle(ZG,"process.stdin"),Ym=!0}catch{}return}if(Ym&&typeof _unregisterHandle=="function"){try{_unregisterHandle(ZG)}catch{}Ym=!1}}function JB(){if(!RB()||Or.length===0)return;let e=Or;Or="";let t=DA.encoding?e:Se.Buffer.from(e);Jg("data",t),bu()}function bu(){!LA()||oB||Or.length>0||sB||(sB=!0,queueMicrotask(()=>{sB=!1,!(!LA()||oB||Or.length>0)&&(oB=!0,Jg("end"),Jg("close"),jg(!1))}))}function gV(){LA()||(yR(!0),JB(),bu())}function fu(){return typeof __runtimeStreamStdin<"u"&&!!__runtimeStreamStdin}function p1(){E2||!vA()&&!fu()||(E2=!0,jg(!DA.paused),!fu()&&(typeof _kernelStdinRead>"u"||(async()=>{try{for(;!LA()&&!(typeof _kernelStdinRead>"u");){let e=await _kernelStdinRead.apply(void 0,[65536,100],{result:{promise:!0}});if(e?.done)break;let t=String(e?.dataBase64??"");t&&(Or+=p2.decode(Se.Buffer.from(t,"base64"),{stream:!0}),JB())}}catch{}Or+=p2.decode(),gV()})()))}function z1e(e,t){if(e==="stdin_end"){gV();return}if(e!=="stdin"||LA())return;let r,n=!1;if(t&&typeof t=="object"&&typeof t.dataBase64=="string"){let i=Se.Buffer.from(t.dataBase64,"base64");if(i.length===0)return;if(!DA.encoding&&RB()){Jg("data",i),bu();return}r=DA.encoding?i.toString(DA.encoding):i.toString("latin1"),n=!DA.encoding}else r=typeof t=="string"?t:t==null?"":Se.Buffer.from(t).toString("utf8");if(r){if(Or+=r,n&&!DA.encoding&&RB()){let i=Or;Or="",Jg("data",Se.Buffer.from(i,"latin1")),bu();return}JB()}}var DA={readable:!0,paused:!0,encoding:null,isRaw:!1,read(e){if(Or.length>0){if(!e||e>=Or.length){let n=Or;return Or="",n}let r=Or.slice(0,e);return Or=Or.slice(e),r}if(Au()>=Ra().length)return null;let t=e?Ra().slice(Au(),Au()+e):Ra().slice(Au());return ER(Au()+t.length),t},on(e,t){return oi[e]||(oi[e]=[]),oi[e].push(t),(vA()||fu())&&(e==="data"||e==="end"||e==="close")&&p1(),e==="data"&&this.paused&&this.resume(),(e==="end"||e==="close")&&(vA()||fu())&&bu(),e==="end"&&Ra()&&!LA()&&(vg(!0),g1()),this},once(e,t){return bn[e]||(bn[e]=[]),bn[e].push(t),(vA()||fu())&&(e==="data"||e==="end"||e==="close")&&p1(),e==="data"&&this.paused&&this.resume(),(e==="end"||e==="close")&&(vA()||fu())&&bu(),e==="end"&&Ra()&&!LA()&&(vg(!0),g1()),this},off(e,t){if(oi[e]){let r=oi[e].indexOf(t);r!==-1&&oi[e].splice(r,1)}return this},removeListener(e,t){return this.off(e,t)},emit(e,...t){let r=[...oi[e]||[],...bn[e]||[]];bn[e]=[];for(let n of r)n(t[0]);return r.length>0},pause(){return this.paused=!0,vg(!1),jg(!1),this},resume(){return(vA()||fu())&&(p1(),jg(!0)),this.paused=!1,vg(!0),JB(),g1(),bu(),this},setEncoding(e){return this.encoding=e,this},setRawMode(e){if(!vA())throw new Error("setRawMode is not supported when stdin is not a TTY");return typeof _ptySetRawMode<"u"&&_ptySetRawMode.applySync(void 0,[e]),this.isRaw=e,this},get isTTY(){return vA()},[Symbol.asyncIterator]:function(){let e=this,t=[],r=[],n=!1,i=null,s=()=>{for(;r.length>0;){if(i){r.shift()(Promise.reject(i));continue}if(t.length>0){r.shift()(Promise.resolve({done:!1,value:t.shift()}));continue}if(n){r.shift()(Promise.resolve({done:!0,value:void 0}));continue}break}},o=f=>{t.push(f),s()},a=()=>{n=!0,s()},A=f=>{i=f,n=!0,s()};return e.on("end",a),e.on("close",a),e.on("error",A),e.on("data",o),e.resume(),{next(){return i?Promise.reject(i):t.length>0?Promise.resolve({done:!1,value:t.shift()}):n?Promise.resolve({done:!0,value:void 0}):new Promise(f=>{r.push(f)})},return(){return n=!0,e.off?.("data",o),e.off?.("end",a),e.off?.("close",a),e.off?.("error",A),s(),Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}}}};function pV(){return{platform:typeof _processConfig<"u"&&_processConfig.platform||"linux",arch:typeof _processConfig<"u"&&_processConfig.arch||"x64",version:typeof _processConfig<"u"&&_processConfig.version||"v22.0.0",cwd:typeof _processConfig<"u"&&_processConfig.cwd||"/root",env:typeof _processConfig<"u"&&_processConfig.env||{},argv:typeof _processConfig<"u"&&_processConfig.argv||["node","script.js"],execPath:typeof _processConfig<"u"&&_processConfig.execPath||"/usr/bin/node",pid:typeof _processConfig<"u"&&_processConfig.pid||1,ppid:typeof _processConfig<"u"&&_processConfig.ppid||0,uid:typeof _processConfig<"u"&&_processConfig.uid||0,gid:typeof _processConfig<"u"&&_processConfig.gid||0,stdin:typeof _processConfig<"u"?_processConfig.stdin:void 0,timingMitigation:typeof _processConfig<"u"&&_processConfig.timingMitigation||"off",frozenTimeMs:typeof _processConfig<"u"?_processConfig.frozenTimeMs:void 0}}var wr=pV(),K1e=typeof performance<"u"&&performance&&typeof performance.now=="function"?performance.now.bind(performance):Date.now;function Hl(){return wr.timingMitigation==="freeze"&&typeof wr.frozenTimeMs=="number"?wr.frozenTimeMs:K1e()}var X1e=Hl(),Wm=void 0,wu=!1,mR=class extends Error{constructor(t){super("process.exit("+t+")");y(this,"code");y(this,"_isProcessExit");this.name="ProcessExitError",this.code=t,this._isProcessExit=!0}};et("ProcessExitError",mR);var BR={SIGHUP:1,SIGINT:2,SIGQUIT:3,SIGILL:4,SIGTRAP:5,SIGABRT:6,SIGBUS:7,SIGFPE:8,SIGKILL:9,SIGUSR1:10,SIGSEGV:11,SIGUSR2:12,SIGPIPE:13,SIGALRM:14,SIGTERM:15,SIGCHLD:17,SIGCONT:18,SIGSTOP:19,SIGTSTP:20,SIGTTIN:21,SIGTTOU:22,SIGURG:23,SIGXCPU:24,SIGXFSZ:25,SIGVTALRM:26,SIGPROF:27,SIGWINCH:28,SIGIO:29,SIGPWR:30,SIGSYS:31},EV=Object.fromEntries(Object.entries(BR).map(([e,t])=>[t,e])),Z1e=new Set(["SIGWINCH","SIGCHLD","SIGCONT","SIGURG"]),yV=new Set(["SIGHUP","SIGINT","SIGTERM","SIGWINCH","SIGCHLD"]);function mV(e){if(e==null)return 15;if(typeof e=="number")return e;let t=BR[e];if(t!==void 0)return t;throw new Error("Unknown signal: "+e)}function $1e(e){return typeof e=="string"&&yV.has(e)}var $G={ESRCH:3,EPERM:1,EINVAL:22};function e2e(e){let t=String(e&&e.message||e||""),r=null;if(e&&typeof e.code=="string"&&Object.prototype.hasOwnProperty.call($G,e.code)?r=e.code:/\bESRCH\b/.test(t)?r="ESRCH":/\bEINVAL\b/.test(t)?r="EINVAL":(/\bEPERM\b/.test(t)||/permission denied/i.test(t))&&(r="EPERM"),r===null)return e instanceof Error?e:new Error(t);let n=new Error(`kill ${r}`);return n.code=r,n.errno=-$G[r],n.syscall="kill",n}var cn={},$r={},kg=10,eY=new Set;function BV(e){return(cn[e]||[]).length+($r[e]||[]).length}function Ml(e){if(!$1e(e)||typeof _processSignalState>"u")return;let t=BR[e];if(typeof t!="number")return;let r=BV(e)>0?"user":"default";try{_processSignalState.applySyncPromise(void 0,[t,r,JSON.stringify([]),0])}catch{}}function t2e(){for(let e of yV)Ml(e)}function y2(e,t="default"){let r=mV(e);if(r===0)return!0;let n=EV[r]??`SIG${r}`;return t==="ignore"||TA(n,n)||Z1e.has(n)?!0:Ce.exit(128+r)}function r2e(e,t){if(e!=="signal"||t===null||typeof t!="object")return;let r=t.signal??t.number,n=typeof t.action=="string"?t.action:"default";y2(r,n)}function E1(e,t,r=!1){let n=r?$r:cn;if(n[e]||(n[e]=[]),n[e].push(t),kg>0&&!eY.has(e)){let i=(cn[e]?.length??0)+($r[e]?.length??0);if(i>kg){eY.add(e);let s=`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${i} ${e} listeners added to [process]. MaxListeners is ${kg}. Use emitter.setMaxListeners() to increase limit`;typeof _error<"u"&&_error.applySync(void 0,[s])}}return Ml(e),Ce}function n2e(e,t){if(cn[e]){let r=cn[e].indexOf(t);r!==-1&&cn[e].splice(r,1)}if($r[e]){let r=$r[e].indexOf(t);r!==-1&&$r[e].splice(r,1)}return Ml(e),Ce}function TA(e,...t){let r=!1;if(cn[e])for(let n of cn[e])n.call(Ce,...t),r=!0;if($r[e]){let n=$r[e].slice();$r[e]=[];for(let i of n)i.call(Ce,...t),r=!0}return r}function jB(e){return!!(e&&typeof e=="object"&&(e._isProcessExit===!0||e.name==="ProcessExitError"))}function i2e(e){return e instanceof Error?e:new Error(String(e))}function i0(e){if(jB(e))return{handled:!1,rethrow:e};let t=i2e(e);try{if(TA("uncaughtException",t,"uncaughtException"))return{handled:!0,rethrow:null}}catch(r){return{handled:!1,rethrow:r}}return{handled:!1,rethrow:t}}function IV(e){U2(()=>{throw e},0)}function Vl(e,t,r){if(!t||t.length===0)return!1;for(let n of t.slice())try{n.call(e,...r)}catch(i){let s=i0(i);if(!s.handled&&s.rethrow!==null)throw s.rethrow;return!0}return!0}function vA(){return xg().stdinIsTTY}et("_stdinDispatch",z1e);et("_signalDispatch",r2e);function bV(e){let t=Hl(),r=Math.floor(t/1e3),n=Math.floor(t%1e3*1e6);if(e){let i=r-e[0],s=n-e[1];return s<0&&(i-=1,s+=1e9),[i,s]}return[r,n]}bV.bigint=function(){let e=Hl();return BigInt(Math.floor(e*1e6))};var m2=wr.cwd,aB=18,Rg={node:wr.version.replace(/^v/,""),v8:"11.3.244.8",uv:"1.44.2",zlib:"1.2.13",brotli:"1.0.9",ares:"1.19.0",modules:"108",nghttp2:"1.52.0",napi:"8",llhttp:"8.1.0",openssl:"3.0.8",cldr:"42.0",icu:"72.1",tz:"2022g",unicode:"15.0"};function s2e(){return{rss:50*1024*1024,heapTotal:20*1024*1024,heapUsed:10*1024*1024,external:1*1024*1024,arrayBuffers:500*1024}}function CV(){let e=s2e(),t=f1e.applySyncPromise(void 0,[]);return!t||typeof t!="object"?e:{rss:Number.isFinite(t.rss)?Number(t.rss):e.rss,heapTotal:Number.isFinite(t.heapTotal)?Number(t.heapTotal):e.heapTotal,heapUsed:Number.isFinite(t.heapUsed)?Number(t.heapUsed):e.heapUsed,external:Number.isFinite(t.external)?Number(t.external):e.external,arrayBuffers:Number.isFinite(t.arrayBuffers)?Number(t.arrayBuffers):e.arrayBuffers}}function o2e(e){let t=u1e.applySyncPromise(void 0,[e??null]);if(t&&typeof t=="object")return{user:Number.isFinite(t.user)?Number(t.user):1e6,system:Number.isFinite(t.system)?Number(t.system):5e5};let r={user:1e6,system:5e5};return e&&typeof e=="object"?{user:r.user-Number(e.user||0),system:r.system-Number(e.system||0)}:r}function a2e(){return{userCPUTime:1e6,systemCPUTime:5e5,maxRSS:50*1024,sharedMemorySize:0,unsharedDataSize:0,unsharedStackSize:0,minorPageFault:0,majorPageFault:0,swappedOut:0,fsRead:0,fsWrite:0,ipcSent:0,ipcReceived:0,signalsCount:0,voluntaryContextSwitches:0,involuntaryContextSwitches:0}}function A2e(){let e=a2e(),t=c1e.applySyncPromise(void 0,[]);return!t||typeof t!="object"?e:{userCPUTime:Number.isFinite(t.userCPUTime)?Number(t.userCPUTime):e.userCPUTime,systemCPUTime:Number.isFinite(t.systemCPUTime)?Number(t.systemCPUTime):e.systemCPUTime,maxRSS:Number.isFinite(t.maxRSS)?Number(t.maxRSS):e.maxRSS,sharedMemorySize:Number.isFinite(t.sharedMemorySize)?Number(t.sharedMemorySize):e.sharedMemorySize,unsharedDataSize:Number.isFinite(t.unsharedDataSize)?Number(t.unsharedDataSize):e.unsharedDataSize,unsharedStackSize:Number.isFinite(t.unsharedStackSize)?Number(t.unsharedStackSize):e.unsharedStackSize,minorPageFault:Number.isFinite(t.minorPageFault)?Number(t.minorPageFault):e.minorPageFault,majorPageFault:Number.isFinite(t.majorPageFault)?Number(t.majorPageFault):e.majorPageFault,swappedOut:Number.isFinite(t.swappedOut)?Number(t.swappedOut):e.swappedOut,fsRead:Number.isFinite(t.fsRead)?Number(t.fsRead):e.fsRead,fsWrite:Number.isFinite(t.fsWrite)?Number(t.fsWrite):e.fsWrite,ipcSent:Number.isFinite(t.ipcSent)?Number(t.ipcSent):e.ipcSent,ipcReceived:Number.isFinite(t.ipcReceived)?Number(t.ipcReceived):e.ipcReceived,signalsCount:Number.isFinite(t.signalsCount)?Number(t.signalsCount):e.signalsCount,voluntaryContextSwitches:Number.isFinite(t.voluntaryContextSwitches)?Number(t.voluntaryContextSwitches):e.voluntaryContextSwitches,involuntaryContextSwitches:Number.isFinite(t.involuntaryContextSwitches)?Number(t.involuntaryContextSwitches):e.involuntaryContextSwitches}}function f2e(){Rg.node=wr.version.replace(/^v/,"");let e=l1e.applySyncPromise(void 0,[]);return e&&typeof e=="object"&&(Object.assign(Rg,e),Rg.node=wr.version.replace(/^v/,"")),Rg}var Ce={platform:wr.platform,arch:wr.arch,version:wr.version,get versions(){return f2e()},pid:wr.pid,ppid:wr.ppid,execPath:wr.execPath,execArgv:[],argv:wr.argv,argv0:wr.argv[0]||"node",title:"node",env:wr.env,config:{target_defaults:{cflags:[],default_configuration:"Release",defines:[],include_dirs:[],libraries:[]},variables:{node_prefix:"/usr",node_shared_libuv:!1}},release:{name:"node",sourceUrl:"https://nodejs.org/download/release/v20.0.0/node-v20.0.0.tar.gz",headersUrl:"https://nodejs.org/download/release/v20.0.0/node-v20.0.0-headers.tar.gz"},features:{inspector:!1,debug:!1,uv:!0,ipv6:!0,tls_alpn:!0,tls_sni:!0,tls_ocsp:!0,tls:!0},cwd(){return m2},chdir(e){let t;try{t=Jt.stat.applySyncPromise(void 0,[e])}catch{let n=new Error(`ENOENT: no such file or directory, chdir '${e}'`);throw n.code="ENOENT",n.errno=-2,n.syscall="chdir",n.path=e,n}if(!Ta(t).isDirectory){let n=new Error(`ENOTDIR: not a directory, chdir '${e}'`);throw n.code="ENOTDIR",n.errno=-20,n.syscall="chdir",n.path=e,n}m2=e},get exitCode(){return Wm},set exitCode(e){Wm=e??void 0},exit(e){let t=e!==void 0?e:Wm??0;Wm=t,wu=!0;try{TA("exit",t)}catch{}throw new mR(t)},abort(){return Ce.kill(Ce.pid,"SIGABRT")},nextTick(e,...t){let r=Fa();zm.push({callback:Ul(e,r),args:t}),yQe()},hrtime:bV,getuid(){return l2()},getgid(){return iB()},geteuid(){let e=globalThis.process?.euid;return Number.isFinite(e)?e:l2()},getegid(){let e=globalThis.process?.egid;return Number.isFinite(e)?e:iB()},getgroups(){return Array.isArray(globalThis.process?.groups)&&globalThis.process.groups.length>0?[...globalThis.process.groups]:[iB()]},setuid(){},setgid(){},seteuid(){},setegid(){},setgroups(){},umask(e){let t=e===void 0?void 0:wa(e,"mask"),r=Number(A1e.applySyncPromise(void 0,[t??null]));if(Number.isFinite(r))return aB=t??r,r;let n=aB;return t!==void 0&&(aB=t),n},uptime(){return(Hl()-X1e)/1e3},memoryUsage(){return CV()},cpuUsage(e){return o2e(e)},resourceUsage(){return A2e()},kill(e,t){if(typeof e!="number"||!Number.isFinite(e)||!Number.isInteger(e))throw new TypeError(`The "pid" argument must be an integer. Received ${String(e)}`);let r=mV(t),n=EV[r]??`SIG${r}`;if(typeof _processKill<"u"){let i;try{i=_processKill.applySyncPromise(void 0,[e,n])}catch(o){throw e2e(o)}let s=i;if(typeof s=="string")try{s=JSON.parse(s)}catch{s=null}if(s&&typeof s=="object"&&s.self===!0){let o=typeof s.action=="string"?s.action:"default";return y2(r,o)}return!0}if(e!==Ce.pid){let i=new Error("Operation not permitted");throw i.code="EPERM",i.errno=-1,i.syscall="kill",i}return y2(r,"default")},on(e,t){return E1(e,t)},once(e,t){return E1(e,t,!0)},removeListener(e,t){return n2e(e,t)},off:null,removeAllListeners(e){return e?(delete cn[e],delete $r[e],Ml(e)):(Object.keys(cn).forEach(t=>delete cn[t]),Object.keys($r).forEach(t=>delete $r[t]),t2e()),Ce},addListener(e,t){return E1(e,t)},emit(e,...t){return TA(e,...t)},listeners(e){return[...cn[e]||[],...$r[e]||[]]},listenerCount(e){return BV(e)},prependListener(e,t){return cn[e]||(cn[e]=[]),cn[e].unshift(t),Ml(e),Ce},prependOnceListener(e,t){return $r[e]||($r[e]=[]),$r[e].unshift(t),Ml(e),Ce},eventNames(){return[...new Set([...Object.keys(cn),...Object.keys($r)])]},setMaxListeners(e){return kg=e,Ce},getMaxListeners(){return kg},rawListeners(e){return Ce.listeners(e)},stdout:P2,stderr:O2,stdin:DA,connected:wr.env?.AGENTOS_NODE_IPC==="1",mainModule:void 0,emitWarning(e){if(e&&typeof e=="object"){typeof e.message!="string"&&(e.message=String(e.message??"")),(typeof e.name!="string"||e.name.length===0)&&(e.name="Warning"),TA("warning",e);return}TA("warning",{message:String(e??""),name:"Warning"})},binding(e){let t=new Error("process.binding is not supported in sandbox");throw t.code="ERR_ACCESS_DENIED",t},_linkedBinding(e){let t=new Error("process._linkedBinding is not supported in sandbox");throw t.code="ERR_ACCESS_DENIED",t},dlopen(){throw new Error("process.dlopen is not supported")},hasUncaughtExceptionCaptureCallback(){return!1},setUncaughtExceptionCaptureCallback(){},send(e,t,r,n){let i=typeof t=="function"?t:typeof r=="function"?r:n;if(!Ce.connected)return!1;try{return Ce.stdout.write(iV(e)),i&&queueMicrotask(()=>i(null)),!0}catch(s){if(i)return queueMicrotask(()=>i(s)),!1;throw s}},disconnect(){Ce.connected&&(Ce.connected=!1,Ce._agentOSIpcHandleId&&typeof _unregisterHandle=="function"&&(_unregisterHandle(Ce._agentOSIpcHandleId),Ce._agentOSIpcHandleId=null),TA("disconnect"))},report:{directory:"",filename:"",compact:!1,signal:"SIGUSR2",reportOnFatalError:!1,reportOnSignal:!1,reportOnUncaughtException:!1,getReport(){return{}},writeReport(){return""}},debugPort:9229,_cwd:wr.cwd,_umask:18};function QV(){if(!(wr.env?.AGENTOS_NODE_IPC==="1"||globalThis.__agentOSProcessConfigEnv?.AGENTOS_NODE_IPC==="1")||Ce._agentOSIpcInstalled)return;Ce._agentOSIpcInstalled=!0,Ce.connected=!0,!Ce._agentOSIpcHandleId&&typeof _registerHandle=="function"&&(Ce._agentOSIpcHandleId=`process-ipc:${Ce.pid}`,_registerHandle(Ce._agentOSIpcHandleId,"child_process IPC channel"));let t="";Ce.stdin.on("data",r=>{let n=sV(t,r);t=n.buffer;for(let i of n.messages)TA("message",i,void 0)})}function u2e(e){jg(!1),j1e(new _u);for(let t of Object.keys(oi))oi[t]=[];for(let t of Object.keys(bn))bn[t]=[];J1e(e.stdin??""),ER(0),yR(!1),vg(!1),wr=e,m2=e.cwd,Ce.platform=e.platform,Ce.arch=e.arch,Ce.version=e.version,Ce.pid=e.pid,Ce.ppid=e.ppid,Ce.execPath=e.execPath,Ce.argv=e.argv,Ce.argv0=e.argv[0]||"node",Ce.env=e.env,Ce.connected=e.env?.AGENTOS_NODE_IPC==="1",Ce._cwd=e.cwd,Ce.stdin.paused=!0,Ce.stdin.encoding=null,Ce.stdin.isRaw=!1,Rg.node=e.version.replace(/^v/,"")}et("__runtimeRefreshProcessConfig",()=>{u2e(pV())});Ce.off=Ce.removeListener;et("__runtimeInstallProcessIpcBridge",QV);QV();Ce.memoryUsage.rss=function(){return CV().rss};Object.defineProperty(Ce,Symbol.toStringTag,{value:"process",writable:!1,configurable:!0,enumerable:!1});var wV=Ce;function c2e(e){return encodeURIComponent(String(e)).replace(/%2F/g,"/")}function tY(e){let t=qr.posix.resolve(String(e||"/")),r=c2e(t);return new Cn(`file://${r.startsWith("/")?r:`/${r}`}`)}function rY(e){let t=e instanceof Cn?e.href:String(e??"");if(!t.startsWith("file:"))throw new TypeError("The URL must be of scheme file");let r=t.slice(5);return r.startsWith("//")&&(r=/^\/\/[^/]*(.*)$/.exec(r)?.[1]||"/"),r=r.split(/[?#]/,1)[0]||"/",r=decodeURIComponent(r),r.startsWith("/")||(r=`/${r}`),r}function SV(){let e=globalThis;e.process=Ce,e.setTimeout=U2,e.clearTimeout=UB,e.setInterval=x2,e.clearInterval=L2,e.setImmediate=lB,e.clearImmediate=wY;let t=typeof e.queueMicrotask=="function"?e.queueMicrotask.bind(e):Sa;e.queueMicrotask=i=>{let s=Fa();return t(()=>kB(s,i,e,[]))},ave(e),e.TextEncoder=Q2,e.TextDecoder=_u,e.Event=kl,e.CustomEvent=I2,e.EventTarget=MB,typeof e.Buffer>"u"&&(e.Buffer=IY);let r=e.Buffer;typeof r.kMaxLength!="number"&&(r.kMaxLength=ql),typeof r.kStringMaxLength!="number"&&(r.kStringMaxLength=Kg),(typeof r.constants!="object"||r.constants===null)&&(r.constants=dY);let n=globalThis.__secureExecBuiltinUtilModule;if(n?.types&&(n.types.isProxy=()=>!1),Km(n),typeof e.atob>"u"||typeof e.btoa>"u"){let i=hY();typeof e.atob>"u"&&(e.atob=s=>{let o=i.toByteArray(String(s)),a="";for(let A of o)a+=String.fromCharCode(A);return a}),typeof e.btoa>"u"&&(e.btoa=s=>{let o=String(s),a=new Uint8Array(o.length);for(let A=0;A255)throw new TypeError("Invalid character");a[A]=f}return i.fromByteArray(a)})}if(typeof e.Crypto>"u"&&(e.Crypto=uR),typeof e.SubtleCrypto>"u"&&(e.SubtleCrypto=fR),typeof e.CryptoKey>"u"&&(e.CryptoKey=Gg),typeof e.DOMException>"u"&&(e.DOMException=Bve),typeof e.crypto>"u")e.crypto=va;else{let i=e.crypto;for(let[s,o]of Object.entries(va))typeof i[s]>"u"&&(i[s]=o)}e.fetch=OB,e.Headers=nwe,e.Request=iwe,e.Response=swe,YQe(e)}var _V={register:"kernelHandleRegister",unregister:"kernelHandleUnregister",list:"kernelHandleList"},DB=new Map,AB=[];function vV(e,t){try{zg(_V.register,e,t)}catch(r){throw r instanceof Error&&r.message.includes("EAGAIN")?new Error("ERR_RESOURCE_BUDGET_EXCEEDED: maximum active handles exceeded"):r}DB.set(e,t)}function RV(e){DB.delete(e);let t=DB.size;try{zg(_V.unregister,e)}catch{}if(t===0&&AB.length>0){let r=AB;AB=[],r.forEach(n=>n())}}function DV(){if(typeof wu<"u"&&wu)return Promise.resolve();let e=globalThis._getPendingTimerCount,t=globalThis._waitForTimerDrain,r=TB().length>0,n=typeof e=="function"&&e()>0;if(!r&&!n)return Promise.resolve();let i=[];return r&&i.push(new Promise(s=>{let o=!1,a=()=>{o||(o=!0,s())};AB.push(a),TB().length===0&&a()})),n&&typeof t=="function"&&i.push(t()),Promise.all(i).then(()=>{})}function TB(){return Array.from(DB.values())}et("_registerHandle",vV);et("_unregisterHandle",RV);et("_waitForActiveHandles",DV);et("_getActiveHandles",TB);var l2e={},h2e={},d2e={id:"/.js",filename:"/.js",dirname:"/",exports:{},loaded:!1};vu("_moduleCache",l2e);vu("_pendingModules",h2e);vu("_currentModule",d2e);function fB(e){let t=e.lastIndexOf("/");return t===-1?".":t===0?"/":e.slice(0,t)}function g2e(e){if(e.startsWith("file://")){let t=e.slice(7);return t.startsWith("/")?t:"/"+t}return e}function p2e(e,t){return Xr.isBuiltin(t)?null:t.startsWith("./")||t.startsWith("../")||t.startsWith("/")?[e]:Xr._nodeModulePaths(e)}function TV(e){let t=function(r,n){let i=_resolveModule.applySyncPromise(void 0,[r,e,"require"]);if(i===null){let s=new Error("Cannot find module '"+r+"'");throw s.code="MODULE_NOT_FOUND",s}return i};return t.paths=function(r){return p2e(e,r)},t}var NV={".js":function(e,t){},".json":function(e,t){},".node":function(e,t){throw new Error(".node extensions are not supported in sandbox")}};function MV(e){return e.cache=_moduleCache,e.main=globalThis.process?.mainModule,e.extensions=NV,e}function E2e(e){let t=new Error(`require() of ES Module ${e} is not supported.`);return t.code="ERR_REQUIRE_ESM",t}function y2e(e){let t=new Error(`secure-exec module format bridge is not registered; cannot require ${e}.`);return t.code="ERR_AGENTOS_MODULE_FORMAT_BRIDGE_MISSING",t}function FV(e){if(typeof _moduleFormat>"u"||typeof _moduleFormat.applySyncPromise!="function")throw y2e(e);if(_moduleFormat.applySyncPromise(void 0,[e])==="module")throw E2e(e)}function zB(e){if(typeof e!="string"&&!(e instanceof URL))throw new TypeError("filename must be a string or URL");let t=g2e(String(e)),r=fB(t),n=TV(r),i=function(o){},s=function(o){return i(o),_requireFrom(o,r)};return s.resolve=n,MV(s)}ln("__secureExecGuestCreateRequire",zB);var Co,Xr=(Co=class{constructor(t,r){y(this,"id");y(this,"path");y(this,"exports");y(this,"filename");y(this,"loaded");y(this,"children");y(this,"paths");y(this,"parent");y(this,"isPreloading");this.id=t,this.path=fB(t),this.exports={},this.filename=t,this.loaded=!1,this.children=[],this.paths=[],this.parent=r,this.isPreloading=!1;let n=this.path;for(;n!=="/";)this.paths.push(n+"/node_modules"),n=fB(n);this.paths.push("/node_modules")}require(t){return _requireFrom(t,this.path)}_compile(t,r){let n=String(t)+` -//# sourceURL=`+String(r),i=new Function("exports","require","module","__filename","__dirname",n),s=a=>(xW(a),_requireFrom(a,this.path));s.resolve=TV(this.path),MV(s);let o=globalThis._currentModule;globalThis._currentModule=this;try{return i(this.exports,s,this,r,this.path),this.loaded=!0,this.exports}finally{globalThis._currentModule=o}}static _resolveFilename(t,r,n,i){let s=r&&r.path?r.path:"/",o=_resolveModule.applySyncPromise(void 0,[t,s,"require"]);if(o===null){let a=new Error("Cannot find module '"+t+"'");throw a.code="MODULE_NOT_FOUND",a}return o}static wrap(t){return"(function (exports, require, module, __filename, __dirname) { "+t+` -});`}static isBuiltin(t){let r=t.replace(/^node:/,"");return Co.builtinModules.includes(r)}static syncBuiltinESMExports(){}static findSourceMap(t){}static _nodeModulePaths(t){let r=[],n=t;for(;n!=="/"&&(r.push(n+"/node_modules"),n=fB(n),n!=="."););return r.push("/node_modules"),r}static _load(t,r,n){let i=r&&r.path?r.path:"/";return _requireFrom(t,i)}static runMain(){}},y(Co,"_extensions",{...NV,".js":function(t,r){FV(r);let n=typeof _loadFile<"u"?_loadFile.applySyncPromise(void 0,[r]):_requireFrom("fs","/").readFileSync(r,"utf8");t._compile(n,r)},".json":function(t,r){let n=typeof _loadFile<"u"?_loadFile.applySyncPromise(void 0,[r]):_requireFrom("fs","/").readFileSync(r,"utf8");t.exports=JSON.parse(n)}}),y(Co,"_cache",typeof _moduleCache<"u"?_moduleCache:{}),y(Co,"builtinModules",fve),y(Co,"createRequire",zB),Co),kV=class{constructor(e){throw new Error("SourceMap is not implemented in sandbox")}get payload(){throw new Error("SourceMap is not implemented in sandbox")}set payload(e){throw new Error("SourceMap is not implemented in sandbox")}findEntry(e,t){throw new Error("SourceMap is not implemented in sandbox")}},UV=Object.assign(Xr,{Module:Xr,createRequire:zB,_extensions:Xr._extensions,_cache:Xr._cache,builtinModules:Xr.builtinModules,isBuiltin:Xr.isBuiltin,_resolveFilename:Xr._resolveFilename,wrap:Xr.wrap,syncBuiltinESMExports:Xr.syncBuiltinESMExports,findSourceMap:Xr.findSourceMap,SourceMap:kV});et("_moduleModule",UV);function m2e(e,t){let r=typeof t=="string"?t:"/";if(Xr.isBuiltin(e))try{return mve(e)}catch(s){if(s?.code!=="MODULE_NOT_FOUND")throw s}let n=_resolveModule.applySyncPromise(void 0,[e,r,"require"]);if(n===null){let s=new Error(`Cannot find module '${e}'`);throw s.code="MODULE_NOT_FOUND",s}if(Object.prototype.hasOwnProperty.call(_moduleCache,n))return _moduleCache[n].exports;FV(n);let i=new Xr(n,{path:r});_moduleCache[n]=i;try{let s=n.endsWith(".json")?".json":n.endsWith(".node")?".node":".js";return(Xr._extensions[s]??Xr._extensions[".js"])(i,n),i.loaded=!0,i.exports}catch(s){throw delete _moduleCache[n],s}}et("_requireFrom",m2e);var B2e=UV,I2e={};_2(I2e,{Buffer:()=>IY,CustomEvent:()=>I2,Event:()=>kl,EventTarget:()=>MB,Module:()=>Xr,ProcessExitError:()=>mR,SourceMap:()=>kV,TextDecoder:()=>_u,TextEncoder:()=>Q2,URL:()=>Cn,URLSearchParams:()=>Hr,_getActiveHandles:()=>TB,_registerHandle:()=>vV,_unregisterHandle:()=>RV,_waitForActiveHandles:()=>DV,childProcess:()=>nV,clearImmediate:()=>wY,clearInterval:()=>L2,clearTimeout:()=>UB,createRequire:()=>zB,cryptoPolyfill:()=>_l,default:()=>b2e,fs:()=>cR,module:()=>B2e,network:()=>vW,os:()=>U1e,process:()=>wV,setImmediate:()=>lB,setInterval:()=>x2,setTimeout:()=>U2,setupGlobals:()=>SV});var b2e=cR;SV();})(); -/*! Bundled license information: - -ieee754/index.js: -(*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh *) - -buffer/index.js: -(*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) -*/ -/*! Bundled license information: - -ieee754/index.js: - (*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh *) - -buffer/index.js: - (*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) - -punycode/punycode.js: - (*! https://mths.be/punycode v1.4.1 by @mathias *) - -safe-buffer/index.js: - (*! safe-buffer. MIT License. Feross Aboukhadijeh *) - -web-streams-polyfill/dist/ponyfill.es2018.js: - (** - * @license - * web-streams-polyfill v3.3.3 - * Copyright 2024 Mattias Buelens, Diwank Singh Tomer and other contributors. - * This code is released under the MIT license. - * SPDX-License-Identifier: MIT - *) - -assert/build/internal/util/comparisons.js: - (*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) - -undici/lib/web/fetch/body.js: - (*! formdata-polyfill. MIT License. Jimmy Wärting *) -*/ diff --git a/crates/execution/assets/polyfill-registry.json b/crates/execution/assets/polyfill-registry.json deleted file mode 100644 index 3286cc434..000000000 --- a/crates/execution/assets/polyfill-registry.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "version": 1, - "groups": [ - { - "source": "node-stdlib-browser", - "names": [ - "assert", - "buffer", - "constants", - "console", - "events", - "path", - "path/posix", - "path/win32", - "punycode", - "querystring", - "sys", - "stream", - "string_decoder", - "timers", - "url", - "util", - "util/types", - "zlib" - ] - }, - { - "source": "custom-bridge", - "names": [ - "async_hooks", - "child_process", - "crypto", - "dgram", - "diagnostics_channel", - "dns", - "dns/promises", - "fs", - "fs/promises", - "http", - "http2", - "https", - "module", - "net", - "os", - "perf_hooks", - "process", - "readline", - "sqlite", - "stream/consumers", - "stream/promises", - "stream/web", - "timers/promises", - "tls", - "tty", - "v8", - "vm", - "worker_threads" - ] - }, - { - "source": "denied", - "errorCode": "ERR_ACCESS_DENIED", - "names": [ - "cluster", - "domain", - "inspector", - "repl", - "trace_events", - "wasi" - ] - } - ] -} diff --git a/crates/execution/assets/pyodide/README.md b/crates/execution/assets/pyodide/README.md deleted file mode 100644 index 5a5990046..000000000 --- a/crates/execution/assets/pyodide/README.md +++ /dev/null @@ -1,38 +0,0 @@ -Pyodide runtime bundle for the secure-exec Python sidecar. - -Bundled runtime files: -- `pyodide.mjs` -- `pyodide.asm.js` -- `pyodide.asm.wasm` -- `pyodide-lock.json` -- `python_stdlib.zip` - -Bundled offline package wheels: -- `click-8.3.1-py3-none-any.whl` -- `micropip-0.11.0-py3-none-any.whl` -- `numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl` -- `pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl` -- `python_dateutil-2.9.0.post0-py2.py3-none-any.whl` -- `pytz-2025.2-py2.py3-none-any.whl` -- `six-1.17.0-py2.py3-none-any.whl` - -Bundle size as vendored in this directory: -- Core Pyodide runtime: 12,283,621 bytes -- Offline package wheels: 8,347,517 bytes -- Total: 20,631,138 bytes (19.68 MiB) - -`python-runner.mjs` points `indexURL` at this local directory and defaults `packageBaseUrl` to the same bundled asset root so `pyodide.loadPackage()` and the built-in `micropip` bootstrap stay offline. - -Dynamic package installs: -- `AGENTOS_PYODIDE_PACKAGE_BASE_URL` can override the package base used by Pyodide package resolution when a Python execution needs to install additional wheels from a network-visible host. -- The bundled `micropip` wheel is still loaded from the local asset directory first so package-manager bootstrap does not depend on external network access. -- `await micropip.install("https://.../package.whl")` goes through the Python runner's bridge-backed fetch path, which means network permissions are enforced by the secure-exec kernel rather than bypassing it. - -Debug timing output: -- Set `AGENTOS_PYTHON_WARMUP_DEBUG=1` on a Python execution request to emit `__AGENTOS_PYTHON_WARMUP_METRICS__:` JSON lines on stderr. -- The Rust execution engine emits a `phase:"prewarm"` line that reports whether warmup executed or reused the cached compile-cache path, plus the measured warmup duration in milliseconds. -- `python-runner.mjs` emits a `phase:"startup"` line just before guest code runs, including total startup time, `loadPyodide()` time, package-load time, package count, and whether the source was inline code, a file, or prewarm-only. - -Startup targets: -- Cold start target: first request in a fresh cache should keep the combined prewarm plus startup path under `3000ms` on commodity hardware. -- Warm start target: cached follow-up requests should keep the `phase:"startup"` time under `500ms`. diff --git a/crates/execution/assets/pyodide/click-8.3.1-py3-none-any.whl b/crates/execution/assets/pyodide/click-8.3.1-py3-none-any.whl deleted file mode 100644 index f2513adc0..000000000 Binary files a/crates/execution/assets/pyodide/click-8.3.1-py3-none-any.whl and /dev/null differ diff --git a/crates/execution/assets/pyodide/micropip-0.11.0-py3-none-any.whl b/crates/execution/assets/pyodide/micropip-0.11.0-py3-none-any.whl deleted file mode 100644 index c9953bfed..000000000 Binary files a/crates/execution/assets/pyodide/micropip-0.11.0-py3-none-any.whl and /dev/null differ diff --git a/crates/execution/assets/pyodide/numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl b/crates/execution/assets/pyodide/numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl deleted file mode 100644 index 516bd5103..000000000 Binary files a/crates/execution/assets/pyodide/numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl and /dev/null differ diff --git a/crates/execution/assets/pyodide/pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl b/crates/execution/assets/pyodide/pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl deleted file mode 100644 index 9e01899dd..000000000 Binary files a/crates/execution/assets/pyodide/pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl and /dev/null differ diff --git a/crates/execution/assets/pyodide/pyodide-lock.json b/crates/execution/assets/pyodide/pyodide-lock.json deleted file mode 100644 index e71db1eea..000000000 --- a/crates/execution/assets/pyodide/pyodide-lock.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {"abi_version": "2025_0", "arch": "wasm32", "platform": "emscripten_4_0_9", "python": "3.13.2", "version": "0.28.0.dev0"}, "packages": {"affine": {"depends": [], "file_name": "affine-2.4.0-py3-none-any.whl", "imports": ["affine"], "install_dir": "site", "name": "affine", "package_type": "package", "sha256": "131be00552026a0f9fa9ccf741bdeee5fcbd1b7532761bc0816b39735140e2b0", "unvendored_tests": true, "version": "2.4.0"}, "affine-tests": {"depends": ["affine"], "file_name": "affine-tests.tar", "imports": [], "install_dir": "site", "name": "affine-tests", "package_type": "package", "sha256": "550c271105cc6b33a8b9d29bd95bb13c2667b4286463d124eff1c8f77ecddf0e", "unvendored_tests": false, "version": "2.4.0"}, "aiohappyeyeballs": {"depends": [], "file_name": "aiohappyeyeballs-2.6.1-py3-none-any.whl", "imports": ["aiohappyeyeballs"], "install_dir": "site", "name": "aiohappyeyeballs", "package_type": "package", "sha256": "b8c78c6d23dea9d258b995363f70eaa03840def2c027ca42bda4875e8de657ef", "unvendored_tests": false, "version": "2.6.1"}, "aiohttp": {"depends": ["aiohappyeyeballs", "aiosignal", "async-timeout", "attrs", "charset-normalizer", "frozenlist", "multidict", "yarl"], "file_name": "aiohttp-3.11.13-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["aiohttp"], "install_dir": "site", "name": "aiohttp", "package_type": "package", "sha256": "1c62fa8fe9763120a2423b5c077327b999513ce5b80e1cbb0728d466bb18de08", "unvendored_tests": true, "version": "3.11.13"}, "aiohttp-tests": {"depends": ["aiohttp"], "file_name": "aiohttp-tests.tar", "imports": [], "install_dir": "site", "name": "aiohttp-tests", "package_type": "package", "sha256": "1ea4437cf425330444632b0612072c5edcd959984c5aaa7ceb982075124feb5a", "unvendored_tests": false, "version": "3.11.13"}, "aiosignal": {"depends": ["frozenlist"], "file_name": "aiosignal-1.3.2-py2.py3-none-any.whl", "imports": ["aiosignal"], "install_dir": "site", "name": "aiosignal", "package_type": "package", "sha256": "f6cf8e632efd670870c2ba7e477d7fc09c4e0890d5f62cae2168b67b1a6e9d8a", "unvendored_tests": false, "version": "1.3.2"}, "altair": {"depends": ["typing-extensions", "jinja2", "jsonschema", "packaging", "narwhals"], "file_name": "altair-6.0.0-py3-none-any.whl", "imports": ["altair"], "install_dir": "site", "name": "altair", "package_type": "package", "sha256": "352b116baddc402f86f71b823cf3dd0a7289d7ac381238dd75982d0fc1cacd78", "unvendored_tests": false, "version": "6.0.0"}, "annotated-types": {"depends": [], "file_name": "annotated_types-0.7.0-py3-none-any.whl", "imports": ["annotated_types"], "install_dir": "site", "name": "annotated-types", "package_type": "package", "sha256": "107c6d0a31af3ce347cad1990976cca76373de2ef51dfbffff84fe10cb7b2c19", "unvendored_tests": true, "version": "0.7.0"}, "annotated-types-tests": {"depends": ["annotated-types"], "file_name": "annotated-types-tests.tar", "imports": [], "install_dir": "site", "name": "annotated-types-tests", "package_type": "package", "sha256": "cae22ded0e13e7ad4207c2e30218a5cf58f9e9af5b02e90f711ecb62c9059892", "unvendored_tests": false, "version": "0.7.0"}, "anyio": {"depends": ["ssl", "sniffio", "typing-extensions"], "file_name": "anyio-4.9.0-py3-none-any.whl", "imports": ["anyio"], "install_dir": "site", "name": "anyio", "package_type": "package", "sha256": "9dee49af7541d8bf0b334adcf910aaeb878132648633fc3b91d1604ecb6b1c34", "unvendored_tests": false, "version": "4.9.0"}, "apsw": {"depends": [], "file_name": "apsw-3.50.4.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["apsw"], "install_dir": "site", "name": "apsw", "package_type": "package", "sha256": "7ac926974bcc51dbc93ff5e3ca0034ba109b6a652c9e54a1bd72f2eb05b3f130", "unvendored_tests": true, "version": "3.50.4.0"}, "apsw-tests": {"depends": ["apsw"], "file_name": "apsw-tests.tar", "imports": [], "install_dir": "site", "name": "apsw-tests", "package_type": "package", "sha256": "ebbc200492e1342d346aeba256550a38b1c8d489621f3811a528f46242e10c0e", "unvendored_tests": false, "version": "3.50.4.0"}, "argon2-cffi": {"depends": ["argon2-cffi-bindings"], "file_name": "argon2_cffi-23.1.0-py3-none-any.whl", "imports": ["argon2"], "install_dir": "site", "name": "argon2-cffi", "package_type": "package", "sha256": "09d9151a362d4766bc102fe9b4c1f130544ac55c3f7f7053252a493c602f4330", "unvendored_tests": false, "version": "23.1.0"}, "argon2-cffi-bindings": {"depends": ["cffi"], "file_name": "argon2_cffi_bindings-21.2.0-cp313-abi3-pyodide_2025_0_wasm32.whl", "imports": ["_argon2_cffi_bindings"], "install_dir": "site", "name": "argon2-cffi-bindings", "package_type": "package", "sha256": "5e0122b770d6105cf0f4faabdb6c44b33eb7a7a76583af8fbb94d68de48cfdfa", "unvendored_tests": false, "version": "21.2.0"}, "asciitree": {"depends": [], "file_name": "asciitree-0.3.3-py3-none-any.whl", "imports": ["asciitree"], "install_dir": "site", "name": "asciitree", "package_type": "package", "sha256": "d0f15820c8f1a4470cd7c9932ea9e8989bfe93cc837aa65ac5aa278d4c34b45e", "unvendored_tests": false, "version": "0.3.3"}, "astropy": {"depends": ["packaging", "numpy", "pyerfa", "pyyaml", "astropy_iers_data"], "file_name": "astropy-7.0.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["astropy"], "install_dir": "site", "name": "astropy", "package_type": "package", "sha256": "998c0e4d15f7baa007f1358b1806f46c37a23967387e3e8b426048819994fbca", "unvendored_tests": false, "version": "7.0.1"}, "astropy-iers-data": {"depends": [], "file_name": "astropy_iers_data-0.2025.3.10.0.29.26-py3-none-any.whl", "imports": ["astropy_iers_data"], "install_dir": "site", "name": "astropy_iers_data", "package_type": "package", "sha256": "cfa8d1ce15ccc2ba30c8c373c61a4ffcf1ca2116990150a735c4b1a55a4ccdb0", "unvendored_tests": true, "version": "0.2025.3.10.0.29.26"}, "astropy-iers-data-tests": {"depends": ["astropy_iers_data"], "file_name": "astropy-iers-data-tests.tar", "imports": [], "install_dir": "site", "name": "astropy_iers_data-tests", "package_type": "package", "sha256": "d996c6e07035b5909e04c2b9ccf8dc542b5db5176ddd109b8a51b3ae21291f41", "unvendored_tests": false, "version": "0.2025.3.10.0.29.26"}, "asttokens": {"depends": ["six"], "file_name": "asttokens-3.0.0-py3-none-any.whl", "imports": ["asttokens"], "install_dir": "site", "name": "asttokens", "package_type": "package", "sha256": "c43876aec4679221a3d063796a858278d88a4e3a036c192f0fd3e473a25a9410", "unvendored_tests": false, "version": "3.0.0"}, "async-timeout": {"depends": [], "file_name": "async_timeout-5.0.1-py3-none-any.whl", "imports": ["async_timeout"], "install_dir": "site", "name": "async-timeout", "package_type": "package", "sha256": "48f4163ed3a8b6ff000d3e334e8b4899ac9962e96236fa3156fc3a52dec4bf7a", "unvendored_tests": false, "version": "5.0.1"}, "atomicwrites": {"depends": [], "file_name": "atomicwrites-1.4.1-py2.py3-none-any.whl", "imports": ["atomicwrites"], "install_dir": "site", "name": "atomicwrites", "package_type": "package", "sha256": "3ff3c35fe0cb90741632773d53200125b666fb2c875ac67c016479bb8a52ca0d", "unvendored_tests": false, "version": "1.4.1"}, "attrs": {"depends": ["six"], "file_name": "attrs-25.2.0-py3-none-any.whl", "imports": ["attr", "attrs"], "install_dir": "site", "name": "attrs", "package_type": "package", "sha256": "0ca0ca2b0dbc02f198a7134fb09c26598dc50390439b318d6dfb63adaee97b25", "unvendored_tests": false, "version": "25.2.0"}, "audioop-lts": {"depends": [], "file_name": "audioop_lts-0.2.1-cp313-abi3-pyodide_2025_0_wasm32.whl", "imports": ["audioop"], "install_dir": "site", "name": "audioop-lts", "package_type": "package", "sha256": "9e6bfa4751f5fff5db006c808eb13acbd723f6776e1e7a83cacf3d4779a43975", "unvendored_tests": false, "version": "0.2.1"}, "autograd": {"depends": ["numpy", "future"], "file_name": "autograd-1.7.0-py3-none-any.whl", "imports": ["autograd"], "install_dir": "site", "name": "autograd", "package_type": "package", "sha256": "70300de9264d5c6e89164cab4de39749406a38dde1db1b70f25dda5c901b0990", "unvendored_tests": true, "version": "1.7.0"}, "autograd-tests": {"depends": ["autograd"], "file_name": "autograd-tests.tar", "imports": [], "install_dir": "site", "name": "autograd-tests", "package_type": "package", "sha256": "2e8b8c0119d4ea2d1d93ce4f04d5fe6413021a627df0bd2768943f994d35e1cf", "unvendored_tests": false, "version": "1.7.0"}, "awkward-cpp": {"depends": ["numpy"], "file_name": "awkward_cpp-47-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["awkward_cpp"], "install_dir": "site", "name": "awkward-cpp", "package_type": "package", "sha256": "25794edf577714c842893efdb3e23d0518c53ebbebe3f9da444b0813a7ab6063", "unvendored_tests": false, "version": "47"}, "b2d": {"depends": ["numpy", "pydantic", "setuptools", "annotated-types"], "file_name": "b2d-0.7.4-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["b2d"], "install_dir": "site", "name": "b2d", "package_type": "package", "sha256": "47709ef215b1ae596bbda3e2905a4182ddc95469daa78bfe1d362c8f3adef894", "unvendored_tests": false, "version": "0.7.4"}, "bcrypt": {"depends": [], "file_name": "bcrypt-4.3.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["bcrypt"], "install_dir": "site", "name": "bcrypt", "package_type": "package", "sha256": "dc7912bcfa6e66a1ecf93a51180cbff8ccce095ac742e2abad0684eb5b84b6a1", "unvendored_tests": false, "version": "4.3.0"}, "beautifulsoup4": {"depends": ["soupsieve", "typing-extensions"], "file_name": "beautifulsoup4-4.13.3-py3-none-any.whl", "imports": ["bs4"], "install_dir": "site", "name": "beautifulsoup4", "package_type": "package", "sha256": "3b401669e1cf50a15a6fc5de272009f581f8a16180a7e5596dbdafec97472b88", "unvendored_tests": true, "version": "4.13.3"}, "beautifulsoup4-tests": {"depends": ["beautifulsoup4"], "file_name": "beautifulsoup4-tests.tar", "imports": [], "install_dir": "site", "name": "beautifulsoup4-tests", "package_type": "package", "sha256": "d285c75aefab4bb8472c8baf3b66b6e06c185a3f25790b565fcd25b55e697e9d", "unvendored_tests": false, "version": "4.13.3"}, "bilby-cython": {"depends": ["numpy"], "file_name": "bilby_cython-0.5.3-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["bilby_cython"], "install_dir": "site", "name": "bilby.cython", "package_type": "package", "sha256": "1eeeec68f4fc30c67088496c0caac658145ba3a239f497b9affe21a6d5fb769f", "unvendored_tests": true, "version": "0.5.3"}, "bilby-cython-tests": {"depends": ["bilby.cython"], "file_name": "bilby-cython-tests.tar", "imports": [], "install_dir": "site", "name": "bilby.cython-tests", "package_type": "package", "sha256": "acbc16454028227bc9092a58920b863a92c72063d4f6b4d8429fbfdae4cb7f91", "unvendored_tests": false, "version": "0.5.3"}, "biopython": {"depends": ["numpy"], "file_name": "biopython-1.85-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["Bio", "BioSQL"], "install_dir": "site", "name": "biopython", "package_type": "package", "sha256": "a3826362af0a9382e3adb450ff633b3c0807bc77ddbe4bf55b1477d19bf46499", "unvendored_tests": false, "version": "1.85"}, "bitarray": {"depends": [], "file_name": "bitarray-3.8.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["bitarray"], "install_dir": "site", "name": "bitarray", "package_type": "package", "sha256": "8a8ae1f58878fc1ac0704e1688b1d24580eb3f7dfd6e442b29c3d10d9511c971", "unvendored_tests": true, "version": "3.8.0"}, "bitarray-tests": {"depends": ["bitarray"], "file_name": "bitarray-tests.tar", "imports": [], "install_dir": "site", "name": "bitarray-tests", "package_type": "package", "sha256": "a18fea12f1a946e0912c8fa3dd792f9e1f4ac36fb7826694db84791eb2875fd5", "unvendored_tests": false, "version": "3.8.0"}, "bitstring": {"depends": ["bitarray"], "file_name": "bitstring-4.3.1-py3-none-any.whl", "imports": ["bitstring"], "install_dir": "site", "name": "bitstring", "package_type": "package", "sha256": "428f9b321ba97820700d45548046ae922b110eede5cd7ae045863b9ded64d364", "unvendored_tests": false, "version": "4.3.1"}, "bleach": {"depends": ["webencodings", "packaging", "six"], "file_name": "bleach-6.2.0-py3-none-any.whl", "imports": ["bleach"], "install_dir": "site", "name": "bleach", "package_type": "package", "sha256": "f9fdb8ec80fb553ecd97f95bd86d7109694a06ac0182cfc0fd70707de2de7326", "unvendored_tests": false, "version": "6.2.0"}, "blosc2": {"depends": ["numpy", "msgpack", "requests", "ndindex", "platformdirs"], "file_name": "blosc2-3.5.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["blosc2"], "install_dir": "site", "name": "blosc2", "package_type": "package", "sha256": "c59b3a727ee6aadafc6c76b973e0e66a85a3403f1067de7b2082dc8c68a7b170", "unvendored_tests": false, "version": "3.5.1"}, "bokeh": {"depends": ["contourpy", "numpy", "jinja2", "pandas", "pillow", "python-dateutil", "six", "typing-extensions", "pyyaml", "xyzservices"], "file_name": "bokeh-3.6.3-py3-none-any.whl", "imports": ["bokeh"], "install_dir": "site", "name": "bokeh", "package_type": "package", "sha256": "bf281877079625b7fac7b9bb5113bcc8728dc78da2201b9e4c1da9adbdd9dbde", "unvendored_tests": false, "version": "3.6.3"}, "boost-histogram": {"depends": ["numpy"], "file_name": "boost_histogram-1.6.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["boost_histogram"], "install_dir": "site", "name": "boost-histogram", "package_type": "package", "sha256": "5baed26887645ad8f23fd92a698fdf6e821250c57bbb87343340a9a2e8fa804b", "unvendored_tests": false, "version": "1.6.1"}, "bottleneck": {"depends": ["numpy"], "file_name": "bottleneck-1.6.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["bottleneck"], "install_dir": "site", "name": "Bottleneck", "package_type": "package", "sha256": "4387e8bb7cf8f26b2c5c41bb0635fb05c87c65770d99f9a6ab1cb56cf4498fcb", "unvendored_tests": false, "version": "1.6.0"}, "brotli": {"depends": [], "file_name": "brotli-1.2.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["brotli"], "install_dir": "site", "name": "brotli", "package_type": "package", "sha256": "5ab0f27efecb1504448bed4e78bc617fe61bdb8d7eac33dcf611e3712324161c", "unvendored_tests": false, "version": "1.2.0"}, "cachetools": {"depends": [], "file_name": "cachetools-5.5.2-py3-none-any.whl", "imports": ["cachetools"], "install_dir": "site", "name": "cachetools", "package_type": "package", "sha256": "3bcb173d17fd7a7fb18ed5ad495f15aa9c29a44a4ccab69e1a6fb816991bb9ae", "unvendored_tests": false, "version": "5.5.2"}, "cartopy": {"depends": ["shapely", "pyshp", "pyproj", "libgeos", "matplotlib", "scipy"], "file_name": "cartopy-0.25.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cartopy"], "install_dir": "site", "name": "Cartopy", "package_type": "package", "sha256": "ce3942e2ca66a40afcea2631d4da0f5c3a56ef02bbad4c02bf5873689b041a01", "unvendored_tests": true, "version": "0.25.0"}, "cartopy-tests": {"depends": ["Cartopy"], "file_name": "cartopy-tests.tar", "imports": [], "install_dir": "site", "name": "Cartopy-tests", "package_type": "package", "sha256": "bcea2c24e4f38555f8eddfcab8589249fc34c6660cbc56cb7bca065b8e269f20", "unvendored_tests": false, "version": "0.25.0"}, "casadi": {"depends": ["numpy"], "file_name": "casadi-3.7.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["casadi"], "install_dir": "site", "name": "casadi", "package_type": "package", "sha256": "d3df1dc9a41eb7b6854e9901fba2dee9f03ff38c3d820ad174c0410c780f5ad5", "unvendored_tests": false, "version": "3.7.0"}, "cbor-diag": {"depends": [], "file_name": "cbor_diag-1.0.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cbor_diag"], "install_dir": "site", "name": "cbor-diag", "package_type": "package", "sha256": "bd3425bfa559ba2d37df1be401782f227fc2d5f66021eb0e7ecfbaa6bf55a405", "unvendored_tests": false, "version": "1.0.1"}, "certifi": {"depends": [], "file_name": "certifi-2026.1.4-py3-none-any.whl", "imports": ["certifi"], "install_dir": "site", "name": "certifi", "package_type": "package", "sha256": "f4a28d9afc3e7f15bed4437710794d5c439d7f3aab1310767eea26eae3be534d", "unvendored_tests": false, "version": "2026.1.4"}, "cffi": {"depends": ["pycparser"], "file_name": "cffi-1.17.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cffi"], "install_dir": "site", "name": "cffi", "package_type": "package", "sha256": "a91747e5e4d982e7e7b2f158f2d06302c4205198ccec688e34b9c310e4417da7", "unvendored_tests": false, "version": "1.17.1"}, "cffi-example": {"depends": ["cffi"], "file_name": "cffi_example-0.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cffi_example"], "install_dir": "site", "name": "cffi_example", "package_type": "package", "sha256": "41af9bb3bd71bfb466e1955a5d61ab20613b8940da70a84acb7069b20bd259c6", "unvendored_tests": false, "version": "0.1"}, "cftime": {"depends": ["numpy"], "file_name": "cftime-1.6.4.post1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cftime"], "install_dir": "site", "name": "cftime", "package_type": "package", "sha256": "7f829cd958bb0451722e8ac1ec20cfe4094727dac1aa663dc906fb21d1f08fbe", "unvendored_tests": false, "version": "1.6.4.post1"}, "charset-normalizer": {"depends": [], "file_name": "charset_normalizer-3.4.4-py3-none-any.whl", "imports": ["charset_normalizer"], "install_dir": "site", "name": "charset-normalizer", "package_type": "package", "sha256": "3ad3f0d6ba052549bf375d0137b3a218bcf2914e8f08db7fa5436561404f3a36", "unvendored_tests": false, "version": "3.4.4"}, "clarabel": {"depends": ["numpy", "scipy"], "file_name": "clarabel-0.11.0-cp39-abi3-pyodide_2025_0_wasm32.whl", "imports": ["clarabel"], "install_dir": "site", "name": "clarabel", "package_type": "package", "sha256": "556e80e526244d1259c2fb7d7302bc758836a31f6b85d7c6960bb052d2b77489", "unvendored_tests": false, "version": "0.11.0"}, "click": {"depends": [], "file_name": "click-8.3.1-py3-none-any.whl", "imports": ["click"], "install_dir": "site", "name": "click", "package_type": "package", "sha256": "d3a6a60612e8940fc1396f5095d823520f14d65621adb5d8739b9b3f300276ae", "unvendored_tests": false, "version": "8.3.1"}, "cligj": {"depends": ["click"], "file_name": "cligj-0.7.2-py3-none-any.whl", "imports": ["cligj"], "install_dir": "site", "name": "cligj", "package_type": "package", "sha256": "8ee9b744c58c6c7d3fb57b645ad383ca991fdfa035d6b5367764835b4718f4cb", "unvendored_tests": false, "version": "0.7.2"}, "clingo": {"depends": ["cffi"], "file_name": "clingo-5.8.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["clingo"], "install_dir": "site", "name": "clingo", "package_type": "package", "sha256": "bebb57cec75510c9f0574e7a4c30d1211ac1504dd3fe88eb898b49f11c1e7764", "unvendored_tests": false, "version": "5.8.0"}, "cloudpickle": {"depends": [], "file_name": "cloudpickle-3.1.1-py3-none-any.whl", "imports": ["cloudpickle"], "install_dir": "site", "name": "cloudpickle", "package_type": "package", "sha256": "1713954092c0c77c38518705b822ac2a48055749b1131a8bc0c6bb8daddd5f83", "unvendored_tests": false, "version": "3.1.1"}, "cmyt": {"depends": ["colorspacious", "matplotlib", "more-itertools", "numpy"], "file_name": "cmyt-2.0.2-py3-none-any.whl", "imports": ["cmyt"], "install_dir": "site", "name": "cmyt", "package_type": "package", "sha256": "4e34b39e175f32ed104f7c31076a43bbc1f755da601be61c548d9bf9ccb162ff", "unvendored_tests": false, "version": "2.0.2"}, "cobs": {"depends": [], "file_name": "cobs-1.2.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cobs"], "install_dir": "site", "name": "cobs", "package_type": "package", "sha256": "3fc5bb2065f467bf6ebe8781ba2d65e255157efd57ca17e2231a6bc78e62e3f5", "unvendored_tests": false, "version": "1.2.1"}, "colorspacious": {"depends": ["numpy"], "file_name": "colorspacious-1.1.2-py2.py3-none-any.whl", "imports": ["colorspacious"], "install_dir": "site", "name": "colorspacious", "package_type": "package", "sha256": "a4ffb391e744d4ee5a278da853f659462f5b7af554e1d3668cddcde5fbd178d2", "unvendored_tests": false, "version": "1.1.2"}, "contourpy": {"depends": ["numpy"], "file_name": "contourpy-1.3.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["contourpy"], "install_dir": "site", "name": "contourpy", "package_type": "package", "sha256": "bfb8aebbd6fe129eb04b9339eacc593f3ff31c9f3fe6067d48c59bf579269a94", "unvendored_tests": false, "version": "1.3.1"}, "coolprop": {"depends": ["numpy", "matplotlib"], "file_name": "coolprop-7.2.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["CoolProp"], "install_dir": "site", "name": "coolprop", "package_type": "package", "sha256": "5db234d62efeff77429f0341b380be7781a984ca791b92f0aa6c821a4721ea1f", "unvendored_tests": true, "version": "7.2.0"}, "coolprop-tests": {"depends": ["coolprop"], "file_name": "coolprop-tests.tar", "imports": [], "install_dir": "site", "name": "coolprop-tests", "package_type": "package", "sha256": "fd85ea7b15f11987b66296922060c1a58a49b4fd9772c5d8394a95e2ebd44c95", "unvendored_tests": false, "version": "7.2.0"}, "coverage": {"depends": ["sqlite3"], "file_name": "coverage-7.6.12-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["coverage"], "install_dir": "site", "name": "coverage", "package_type": "package", "sha256": "f7177cc62824e11cb856dcb8b24d18f34fef616601bdb3c260cfb61e38625ebd", "unvendored_tests": false, "version": "7.6.12"}, "cramjam": {"depends": [], "file_name": "cramjam-2.10.0rc1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cramjam"], "install_dir": "site", "name": "cramjam", "package_type": "package", "sha256": "6a771bba3165b2233a2b7e3b597513e6bf54053f57bc1df54d8bc565910e0797", "unvendored_tests": false, "version": "2.10.0rc1"}, "crc32c": {"depends": [], "file_name": "crc32c-2.7.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["crc32c"], "install_dir": "site", "name": "crc32c", "package_type": "package", "sha256": "2b2d2aa5c35772fc993405aec61cbea8cfd08f734358ee4bbd13c4ed30589c5f", "unvendored_tests": false, "version": "2.7.1"}, "cryptography": {"depends": ["libopenssl", "six", "cffi"], "file_name": "cryptography-46.0.3-cp313-abi3-pyodide_2025_0_wasm32.whl", "imports": ["cryptography"], "install_dir": "site", "name": "cryptography", "package_type": "package", "sha256": "8dcec3549f85ea9df0941f75339fa5539d3b4a87ea0a47ab1957fd30c3878419", "unvendored_tests": false, "version": "46.0.3"}, "css-inline": {"depends": [], "file_name": "css_inline-0.16.0-cp39-abi3-pyodide_2025_0_wasm32.whl", "imports": ["css_inline"], "install_dir": "site", "name": "css-inline", "package_type": "package", "sha256": "3dbb7ce8fcb79c0e2efbb8cd2f46513e0cf55715896d0cc781783f44262f101a", "unvendored_tests": false, "version": "0.16.0"}, "cssselect": {"depends": [], "file_name": "cssselect-1.3.0-py3-none-any.whl", "imports": ["cssselect"], "install_dir": "site", "name": "cssselect", "package_type": "package", "sha256": "964d7b801271db5a87ff4e4d15a759907d21c2171512a0c465fa479c9304f29b", "unvendored_tests": false, "version": "1.3.0"}, "cvxpy-base": {"depends": ["numpy", "scipy", "clarabel"], "file_name": "cvxpy_base-1.6.3-py3-none-any.whl", "imports": ["cvxpy"], "install_dir": "site", "name": "cvxpy-base", "package_type": "package", "sha256": "1af1f7116765a3f58b07435051f7b22472629f7ce0914bed40290e04dad13c48", "unvendored_tests": true, "version": "1.6.3"}, "cvxpy-base-tests": {"depends": ["cvxpy-base"], "file_name": "cvxpy-base-tests.tar", "imports": [], "install_dir": "site", "name": "cvxpy-base-tests", "package_type": "package", "sha256": "d8ee8b62799cc27f03f1db48667850094adad7ab73f2e7170018efdf2d5803ee", "unvendored_tests": false, "version": "1.6.3"}, "cycler": {"depends": ["six"], "file_name": "cycler-0.12.1-py3-none-any.whl", "imports": ["cycler"], "install_dir": "site", "name": "cycler", "package_type": "package", "sha256": "a140384709bfc674001fbd3b1e32a3bf8b531c0413d02f98badbd2d8ecc924c1", "unvendored_tests": false, "version": "0.12.1"}, "cysignals": {"depends": [], "file_name": "cysignals-1.12.3-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cysignals"], "install_dir": "site", "name": "cysignals", "package_type": "package", "sha256": "d23517d622583a2229ab97eb6cdfb8da76a07aa015da194794623a3d080467b3", "unvendored_tests": false, "version": "1.12.3"}, "cytoolz": {"depends": ["toolz"], "file_name": "cytoolz-1.0.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cytoolz"], "install_dir": "site", "name": "cytoolz", "package_type": "package", "sha256": "dd3fa44718db38cdc637763c68f07e7e49953b6a85d8452afdd5f0b78be643f1", "unvendored_tests": true, "version": "1.0.1"}, "cytoolz-tests": {"depends": ["cytoolz"], "file_name": "cytoolz-tests.tar", "imports": [], "install_dir": "site", "name": "cytoolz-tests", "package_type": "package", "sha256": "7ad1424b1544a1f5a6fe188fae7f30022552f76ae1e8665d17d1fe9fd5d81dac", "unvendored_tests": false, "version": "1.0.1"}, "decorator": {"depends": [], "file_name": "decorator-5.2.1-py3-none-any.whl", "imports": ["decorator"], "install_dir": "site", "name": "decorator", "package_type": "package", "sha256": "875c482c775a71a793ed4392891abba2b762c0dfe951dccc6d2165bb5b422658", "unvendored_tests": false, "version": "5.2.1"}, "demes": {"depends": ["attrs", "ruamel.yaml"], "file_name": "demes-0.2.3-py3-none-any.whl", "imports": ["demes"], "install_dir": "site", "name": "demes", "package_type": "package", "sha256": "01d91bf39f3ead93e0131886865caf669dae1c14b0723ce55932982b528cbfba", "unvendored_tests": false, "version": "0.2.3"}, "deprecation": {"depends": ["packaging"], "file_name": "deprecation-2.1.0-py2.py3-none-any.whl", "imports": ["deprecation"], "install_dir": "site", "name": "deprecation", "package_type": "package", "sha256": "9352a446bcf40cb483d89dbee7f85dc67bb7707653706f8bd180366fe024f862", "unvendored_tests": false, "version": "2.1.0"}, "diskcache": {"depends": ["sqlite3"], "file_name": "diskcache-5.6.3-py3-none-any.whl", "imports": ["diskcache"], "install_dir": "site", "name": "diskcache", "package_type": "package", "sha256": "d4bcdb7580a6dc5370eb5f810c89232972f2a79ad8557ec15b12d2148078a401", "unvendored_tests": false, "version": "5.6.3"}, "distlib": {"depends": [], "file_name": "distlib-0.3.9-py2.py3-none-any.whl", "imports": ["distlib"], "install_dir": "site", "name": "distlib", "package_type": "package", "sha256": "8599aff281d7dd46ac4eb31a98107318281cacabcd83303b51c19ca4a2da3eb5", "unvendored_tests": false, "version": "0.3.9"}, "distro": {"depends": [], "file_name": "distro-1.9.0-py3-none-any.whl", "imports": ["distro"], "install_dir": "site", "name": "distro", "package_type": "package", "sha256": "997da1bf8f9ce720daa3c06cea7e1439a8a0407379293e01144e5a2da01bc3c6", "unvendored_tests": false, "version": "1.9.0"}, "docutils": {"depends": [], "file_name": "docutils-0.21.2-py3-none-any.whl", "imports": ["docutils"], "install_dir": "site", "name": "docutils", "package_type": "package", "sha256": "55e71ee1f74328917ab97904fd879960197db736e2e1ac44686cf1df781b13bd", "unvendored_tests": false, "version": "0.21.2"}, "donfig": {"depends": ["pyyaml"], "file_name": "donfig-0.8.1.post1-py3-none-any.whl", "imports": ["donfig"], "install_dir": "site", "name": "donfig", "package_type": "package", "sha256": "36064dc40199a88bfa3ea79f279cc4f66b850f6a5c2f1e6ebbf9569648e15884", "unvendored_tests": true, "version": "0.8.1.post1"}, "donfig-tests": {"depends": ["donfig"], "file_name": "donfig-tests.tar", "imports": [], "install_dir": "site", "name": "donfig-tests", "package_type": "package", "sha256": "27980fd72de84aaf45682097106445fe801a69180c5c7d1066f7b8dfb1742940", "unvendored_tests": false, "version": "0.8.1.post1"}, "ewah-bool-utils": {"depends": ["numpy"], "file_name": "ewah_bool_utils-1.2.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["ewah_bool_utils"], "install_dir": "site", "name": "ewah_bool_utils", "package_type": "package", "sha256": "baa25345e54e978361653ced58224ec5e66533df54fa25e765523892afc804f9", "unvendored_tests": true, "version": "1.2.2"}, "ewah-bool-utils-tests": {"depends": ["ewah_bool_utils"], "file_name": "ewah-bool-utils-tests.tar", "imports": [], "install_dir": "site", "name": "ewah_bool_utils-tests", "package_type": "package", "sha256": "c5723fbb16afbb37fd805ebff71173c0200e3ae300afc725e54a88f8a6371ac7", "unvendored_tests": false, "version": "1.2.2"}, "exceptiongroup": {"depends": [], "file_name": "exceptiongroup-1.2.2-py3-none-any.whl", "imports": ["exceptiongroup"], "install_dir": "site", "name": "exceptiongroup", "package_type": "package", "sha256": "1e53eb509a0ec39aec35fd93ee2190899745967d7758de005318f3145e8b5b0d", "unvendored_tests": false, "version": "1.2.2"}, "executing": {"depends": [], "file_name": "executing-2.2.0-py2.py3-none-any.whl", "imports": ["executing"], "install_dir": "site", "name": "executing", "package_type": "package", "sha256": "c8e573008eea36616bd1821285b8f13b44ec77c35aa732bbe6d689a1b3932458", "unvendored_tests": false, "version": "2.2.0"}, "fastapi": {"depends": ["httpx", "jinja2", "pydantic", "starlette", "anyio"], "file_name": "fastapi-0.116.1-py3-none-any.whl", "imports": ["fastapi"], "install_dir": "site", "name": "fastapi", "package_type": "package", "sha256": "57b58f74bc39b4b10828cffe45d59eebfa18f30d5656f35c002f2f5f651c305f", "unvendored_tests": false, "version": "0.116.1"}, "fastcan": {"depends": ["scikit-learn"], "file_name": "fastcan-0.5.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["fastcan"], "install_dir": "site", "name": "fastcan", "package_type": "package", "sha256": "42911731bed3165fcb977bfa88c06db94eb0c5e6d0bcfb28504342476b4bd3f4", "unvendored_tests": true, "version": "0.5.0"}, "fastcan-tests": {"depends": ["fastcan"], "file_name": "fastcan-tests.tar", "imports": [], "install_dir": "site", "name": "fastcan-tests", "package_type": "package", "sha256": "c9dabf71fb41f66f38cdabd850adf8a1ed2c2ac880be96e0650de85e3208e7ee", "unvendored_tests": false, "version": "0.5.0"}, "fastparquet": {"depends": ["numpy", "cramjam", "pandas", "fsspec", "packaging"], "file_name": "fastparquet-2024.11.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["fastparquet"], "install_dir": "site", "name": "fastparquet", "package_type": "package", "sha256": "97e54ff7436c2b661f92fb2c648d5346cb94c6a14a90d96c08151b185a82e1b1", "unvendored_tests": false, "version": "2024.11.0"}, "fiona": {"depends": ["attrs", "certifi", "setuptools", "six", "click", "cligj"], "file_name": "fiona-1.9.5-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["fiona"], "install_dir": "site", "name": "fiona", "package_type": "package", "sha256": "e3c4b0f342b9d14f8f49474e18b2faeda31d2515eaff0f2a122afb9cef562876", "unvendored_tests": false, "version": "1.9.5"}, "fonttools": {"depends": [], "file_name": "fonttools-4.56.0-py3-none-any.whl", "imports": ["fontTools"], "install_dir": "site", "name": "fonttools", "package_type": "package", "sha256": "9d6518c8ad4d88019bc72045108eca154301014215222408aa047cf4955c726d", "unvendored_tests": false, "version": "4.56.0"}, "freesasa": {"depends": [], "file_name": "freesasa-2.2.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["freesasa"], "install_dir": "site", "name": "freesasa", "package_type": "package", "sha256": "2d4158326beecd9958af7bc6a121cc7cae0d4a577a942a1f2d58f6d9931cb942", "unvendored_tests": false, "version": "2.2.1"}, "frozenlist": {"depends": [], "file_name": "frozenlist-1.6.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["frozenlist"], "install_dir": "site", "name": "frozenlist", "package_type": "package", "sha256": "8586c579bec9bea1be39e9814ffa65280b1f6aaf1bde4332eeedc5ba6fb6c59d", "unvendored_tests": false, "version": "1.6.0"}, "fsspec": {"depends": [], "file_name": "fsspec-2025.3.2-py3-none-any.whl", "imports": ["fsspec"], "install_dir": "site", "name": "fsspec", "package_type": "package", "sha256": "33f1825db178ed9df3bbf056f431ce0dc29f57489b8e265133d704d44f8d7deb", "unvendored_tests": true, "version": "2025.3.2"}, "fsspec-tests": {"depends": ["fsspec"], "file_name": "fsspec-tests.tar", "imports": [], "install_dir": "site", "name": "fsspec-tests", "package_type": "package", "sha256": "d8bca1f84b04961ddecd8410705e71c4475febf4f7c894acb2d0b34442a61821", "unvendored_tests": false, "version": "2025.3.2"}, "future": {"depends": [], "file_name": "future-1.0.0-py3-none-any.whl", "imports": ["future"], "install_dir": "site", "name": "future", "package_type": "package", "sha256": "00fb5bff96057f6cc8bf891d68b45c5c4a1e8f4ab6ed366651cfa7d8292d651a", "unvendored_tests": true, "version": "1.0.0"}, "future-tests": {"depends": ["future"], "file_name": "future-tests.tar", "imports": [], "install_dir": "site", "name": "future-tests", "package_type": "package", "sha256": "be42b72dd88321133f53666012cfee4fb22acc66a0e93d52f3bbaabc21edecca", "unvendored_tests": false, "version": "1.0.0"}, "galpy": {"depends": ["numpy", "scipy", "matplotlib", "astropy", "future", "setuptools"], "file_name": "galpy-1.10.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["galpy"], "install_dir": "site", "name": "galpy", "package_type": "package", "sha256": "ab453044b69f8161b518fd86c76f494e4d5876b936668e464db63cf2922ba6fc", "unvendored_tests": false, "version": "1.10.2"}, "geopandas": {"depends": ["shapely", "fiona", "pyproj", "packaging", "pandas"], "file_name": "geopandas-1.1.1-py3-none-any.whl", "imports": ["geopandas"], "install_dir": "site", "name": "geopandas", "package_type": "package", "sha256": "37a35570d7fa540595c490bb84b89ad83848b67d9c55eeb0442c7578197db6fc", "unvendored_tests": true, "version": "1.1.1"}, "geopandas-tests": {"depends": ["geopandas"], "file_name": "geopandas-tests.tar", "imports": [], "install_dir": "site", "name": "geopandas-tests", "package_type": "package", "sha256": "a4233e1555cd0a84d6712fc6934e8ec35c0c8740b9770f44ca927001e9ee4aeb", "unvendored_tests": false, "version": "1.1.1"}, "gmpy2": {"depends": [], "file_name": "gmpy2-2.1.5-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["gmpy2"], "install_dir": "site", "name": "gmpy2", "package_type": "package", "sha256": "0f4168b108079567f211ac6b3d3a22e500c29a2c620fbb7a3035d6a193f002da", "unvendored_tests": false, "version": "2.1.5"}, "google-crc32c": {"depends": [], "file_name": "google_crc32c-1.8.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["google_crc32c"], "install_dir": "site", "name": "google-crc32c", "package_type": "package", "sha256": "c469bebdea71acf327c5e35177dde836186649e50f08489898d167ffb3de3090", "unvendored_tests": false, "version": "1.8.0"}, "gsw": {"depends": ["numpy"], "file_name": "gsw-3.6.19-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["gsw"], "install_dir": "site", "name": "gsw", "package_type": "package", "sha256": "d57a2ba51ad05510862d315343eb9049143005e475f3b5093765d5e9dba7e7a2", "unvendored_tests": true, "version": "3.6.19"}, "gsw-tests": {"depends": ["gsw"], "file_name": "gsw-tests.tar", "imports": [], "install_dir": "site", "name": "gsw-tests", "package_type": "package", "sha256": "ebbecf095de3e2a21b221b1b858390de986587a1f1959be3702f25f0bbc36d32", "unvendored_tests": false, "version": "3.6.19"}, "h11": {"depends": [], "file_name": "h11-0.14.0-py3-none-any.whl", "imports": ["h11"], "install_dir": "site", "name": "h11", "package_type": "package", "sha256": "c1163b48048f27994e804188a4f2c9726d4e945eb181c2637d9ee78c379a226b", "unvendored_tests": true, "version": "0.14.0"}, "h11-tests": {"depends": ["h11"], "file_name": "h11-tests.tar", "imports": [], "install_dir": "site", "name": "h11-tests", "package_type": "package", "sha256": "2eb365f7d4bb226b3a2ac452047cafbb7682651c4f8d6ad583f840d21aacdf98", "unvendored_tests": false, "version": "0.14.0"}, "h3": {"depends": [], "file_name": "h3-4.2.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["h3"], "install_dir": "site", "name": "h3", "package_type": "package", "sha256": "1c0209c3e265140dd9716d58b242c606530a960538aefa02b00487269e82295e", "unvendored_tests": false, "version": "4.2.2"}, "h5py": {"depends": ["numpy", "pkgconfig", "libhdf5"], "file_name": "h5py-3.13.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["h5py"], "install_dir": "site", "name": "h5py", "package_type": "package", "sha256": "b8b01774b2a5bfa4fee0313a0fe51b689af065ccdb53feac87e0112c0b555a81", "unvendored_tests": true, "version": "3.13.0"}, "h5py-tests": {"depends": ["h5py"], "file_name": "h5py-tests.tar", "imports": [], "install_dir": "site", "name": "h5py-tests", "package_type": "package", "sha256": "6b4143ff0eb8ea781bed7cd73b969ff4f6cdee8e77b7b5117b9b9620cf4a1ab9", "unvendored_tests": false, "version": "3.13.0"}, "hashlib": {"depends": ["libopenssl"], "file_name": "hashlib-1.0.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["_hashlib"], "install_dir": "site", "name": "hashlib", "package_type": "cpython_module", "sha256": "206442f20d96c131210dfdbad25d5da877b795c873d6b6689a58a46031ed9aab", "unvendored_tests": false, "version": "1.0.0"}, "healpy": {"depends": ["numpy", "astropy"], "file_name": "healpy-1.19.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["healpy"], "install_dir": "site", "name": "healpy", "package_type": "package", "sha256": "f2f16fe5aa15d70c88b3bcddcddb40bb450a85f7f51c7fdc6a7aea281b63d413", "unvendored_tests": true, "version": "1.19.0"}, "healpy-tests": {"depends": ["healpy"], "file_name": "healpy-tests.tar", "imports": [], "install_dir": "site", "name": "healpy-tests", "package_type": "package", "sha256": "41852502e5cf88f1e25d885d3fcf48d4d623b31aa92f939c7b5fa25ff863fa95", "unvendored_tests": false, "version": "1.19.0"}, "highspy": {"depends": ["numpy"], "file_name": "highspy-1.11.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["highspy"], "install_dir": "site", "name": "highspy", "package_type": "package", "sha256": "9e0c64abc044e6cdf4d07d68b982f6e7e4b3bb1aec3596ce5e81f3798f207664", "unvendored_tests": false, "version": "1.11.0"}, "html5lib": {"depends": ["webencodings", "six"], "file_name": "html5lib-1.1-py2.py3-none-any.whl", "imports": ["html5lib"], "install_dir": "site", "name": "html5lib", "package_type": "package", "sha256": "0140d9b5d8c2cdec07bb3a513f99ea1082d169803a61dc388f7ab2de4104d948", "unvendored_tests": false, "version": "1.1"}, "httpcore": {"depends": ["certifi", "h11", "ssl"], "file_name": "httpcore-1.0.7-py3-none-any.whl", "imports": ["httpcore"], "install_dir": "site", "name": "httpcore", "package_type": "package", "sha256": "59660a6db0443006290fe5bf1eaae7c047ed2c7c13520ba0b3329fbbf8a6aa45", "unvendored_tests": false, "version": "1.0.7"}, "httpx": {"depends": [], "file_name": "httpx-0.28.1-py3-none-any.whl", "imports": ["httpx"], "install_dir": "site", "name": "httpx", "package_type": "package", "sha256": "3123bf6c7e7623667b39d31f8b2bf4eac925b49ea79dfdf520560db2e1cf87a9", "unvendored_tests": false, "version": "0.28.1"}, "idna": {"depends": [], "file_name": "idna-3.10-py3-none-any.whl", "imports": ["idna"], "install_dir": "site", "name": "idna", "package_type": "package", "sha256": "72da788d7a6d3e363535aba1be2658fd21bda5038f2eb0976ce6cb5186942bd6", "unvendored_tests": false, "version": "3.10"}, "igraph": {"depends": ["texttable"], "file_name": "igraph-0.11.8-cp39-abi3-pyodide_2025_0_wasm32.whl", "imports": ["igraph"], "install_dir": "site", "name": "igraph", "package_type": "package", "sha256": "06fcc32420c64dfd3349c172b6b1460f36487e3b47e937ee5e8da0cc1ffa7c86", "unvendored_tests": false, "version": "0.11.8"}, "imageio": {"depends": ["numpy", "pillow"], "file_name": "imageio-2.37.0-py3-none-any.whl", "imports": ["imageio"], "install_dir": "site", "name": "imageio", "package_type": "package", "sha256": "f9af831a6e7d9b55adbd9f1c2aa40667550ed09265ca1dc2636236ee53f945e0", "unvendored_tests": false, "version": "2.37.0"}, "imgui-bundle": {"depends": ["pydantic", "munch", "numpy"], "file_name": "imgui_bundle-1.92.4-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["imgui_bundle"], "install_dir": "site", "name": "imgui-bundle", "package_type": "package", "sha256": "2ac186d7a0f22b093c766bc5fba6e9e299d99fab8c290c4963181bea1a03ffe5", "unvendored_tests": true, "version": "1.92.4"}, "imgui-bundle-tests": {"depends": ["imgui-bundle"], "file_name": "imgui-bundle-tests.tar", "imports": [], "install_dir": "site", "name": "imgui-bundle-tests", "package_type": "package", "sha256": "18654d836f70b906a516f7e116f6c4789adf1e61a9d763ca8a59bafe149a544a", "unvendored_tests": false, "version": "1.92.4"}, "iminuit": {"depends": ["numpy"], "file_name": "iminuit-2.30.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["iminuit"], "install_dir": "site", "name": "iminuit", "package_type": "package", "sha256": "62b3b007d1cf6dbbecd5c054f8bef8562c224a4f127733d6fa571fa27957a243", "unvendored_tests": false, "version": "2.30.1"}, "iniconfig": {"depends": [], "file_name": "iniconfig-2.1.0-py3-none-any.whl", "imports": ["iniconfig"], "install_dir": "site", "name": "iniconfig", "package_type": "package", "sha256": "141afb191b247fa924232a589108b3391113d80e8b53902730e6d3efedac30cf", "unvendored_tests": false, "version": "2.1.0"}, "inspice": {"depends": ["numpy", "matplotlib", "pyyaml", "cffi", "diskcache", "h5py", "ply", "libngspice"], "file_name": "inspice-1.6.4.1-py3-none-any.whl", "imports": ["InSpice"], "install_dir": "site", "name": "inspice", "package_type": "package", "sha256": "c7cd694127cfe87b20cff5d29449745fd242fe7388f3ad6aa2705f3075349d9a", "unvendored_tests": false, "version": "1.6.4.1"}, "ipython": {"depends": ["asttokens", "decorator", "executing", "matplotlib-inline", "prompt_toolkit", "pure-eval", "pygments", "six", "stack-data", "traitlets", "sqlite3", "wcwidth"], "file_name": "ipython-9.0.2-py3-none-any.whl", "imports": ["IPython"], "install_dir": "site", "name": "ipython", "package_type": "package", "sha256": "1cd4500bf130562204ea0a029e2f98fc386ab79629c42f608429590d886c83d5", "unvendored_tests": true, "version": "9.0.2"}, "ipython-tests": {"depends": ["ipython"], "file_name": "ipython-tests.tar", "imports": [], "install_dir": "site", "name": "ipython-tests", "package_type": "package", "sha256": "27d4cd74a4711e6a84368b4e829714679a8884f3790f6b54bfe0446b5ae378fe", "unvendored_tests": false, "version": "9.0.2"}, "jedi": {"depends": ["parso"], "file_name": "jedi-0.19.2-py2.py3-none-any.whl", "imports": ["jedi"], "install_dir": "site", "name": "jedi", "package_type": "package", "sha256": "63f137a6c965e08cc4221acdf5170ef24d34e7572d8a1109846da93b3ab33d65", "unvendored_tests": true, "version": "0.19.2"}, "jedi-tests": {"depends": ["jedi"], "file_name": "jedi-tests.tar", "imports": [], "install_dir": "site", "name": "jedi-tests", "package_type": "package", "sha256": "83220d4411c3f9353d9c01f4bddff48acb2daf1f9a5cbe86e9bc005932aed841", "unvendored_tests": false, "version": "0.19.2"}, "jinja2": {"depends": ["markupsafe"], "file_name": "jinja2-3.1.6-py3-none-any.whl", "imports": ["jinja2"], "install_dir": "site", "name": "Jinja2", "package_type": "package", "sha256": "56b8a136e2140cb9ce2e2e7c8ed138a795ec1f6ea97fdd4319d46ed9193ab9d2", "unvendored_tests": false, "version": "3.1.6"}, "jiter": {"depends": [], "file_name": "jiter-0.9.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["jiter"], "install_dir": "site", "name": "jiter", "package_type": "package", "sha256": "69fc995fab57b81727062c7cfdd6922658ae8c320e29af3d3a4b8f227b984b4d", "unvendored_tests": false, "version": "0.9.0"}, "joblib": {"depends": [], "file_name": "joblib-1.4.2-py3-none-any.whl", "imports": ["joblib"], "install_dir": "site", "name": "joblib", "package_type": "package", "sha256": "f6cd3ff44cc58faa3216f8778048b37792822183fd5ece300bd9a5d7f1be72ba", "unvendored_tests": true, "version": "1.4.2"}, "joblib-tests": {"depends": ["joblib"], "file_name": "joblib-tests.tar", "imports": [], "install_dir": "site", "name": "joblib-tests", "package_type": "package", "sha256": "f99c9730662d553fb7c71d9905796b9a36bc18b753008f885bf614fd23a8a343", "unvendored_tests": false, "version": "1.4.2"}, "jsonpatch": {"depends": ["jsonpointer"], "file_name": "jsonpatch-1.33-py2.py3-none-any.whl", "imports": ["jsonpatch"], "install_dir": "site", "name": "jsonpatch", "package_type": "package", "sha256": "932997e42e9468342b8c8d359c8da92ee71eb82d3612c46a4793c67758ba1c31", "unvendored_tests": false, "version": "1.33"}, "jsonpointer": {"depends": [], "file_name": "jsonpointer-3.0.0-py2.py3-none-any.whl", "imports": ["jsonpointer"], "install_dir": "site", "name": "jsonpointer", "package_type": "package", "sha256": "0697364e01aac2f708c64f29c214105e21ea239c9a7e32ea71e4b37d192cee90", "unvendored_tests": false, "version": "3.0.0"}, "jsonschema": {"depends": ["attrs", "pyrsistent", "referencing", "jsonschema_specifications"], "file_name": "jsonschema-4.23.0-py3-none-any.whl", "imports": ["jsonschema"], "install_dir": "site", "name": "jsonschema", "package_type": "package", "sha256": "5178a630760e05b5ce4392fb885e0bdd24a9bc5939006b5a88a0a63d402f0b60", "unvendored_tests": true, "version": "4.23.0"}, "jsonschema-specifications": {"depends": ["referencing"], "file_name": "jsonschema_specifications-2024.10.1-py3-none-any.whl", "imports": ["jsonschema_specifications"], "install_dir": "site", "name": "jsonschema_specifications", "package_type": "package", "sha256": "40a4885255fc56c2fb671eb656a3be0501b1185a59aad6e67dde3cee0d2d916d", "unvendored_tests": true, "version": "2024.10.1"}, "jsonschema-specifications-tests": {"depends": ["jsonschema_specifications"], "file_name": "jsonschema-specifications-tests.tar", "imports": [], "install_dir": "site", "name": "jsonschema_specifications-tests", "package_type": "package", "sha256": "c46b7d5a07f445aed287f5a806bdf3cc030ed94c149581a353aacc213b1809bb", "unvendored_tests": false, "version": "2024.10.1"}, "jsonschema-tests": {"depends": ["jsonschema"], "file_name": "jsonschema-tests.tar", "imports": [], "install_dir": "site", "name": "jsonschema-tests", "package_type": "package", "sha256": "5558631e5cd8c27c5997349ed0ad5df44bd6d30b33b15397cef8a2a243cddb2d", "unvendored_tests": false, "version": "4.23.0"}, "kiwisolver": {"depends": [], "file_name": "kiwisolver-1.4.8-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["kiwisolver"], "install_dir": "site", "name": "kiwisolver", "package_type": "package", "sha256": "74fef16f229c3280f386ace367f36ac5ad8597ebabef45c6cf8bc2fa8aa3be70", "unvendored_tests": false, "version": "1.4.8"}, "lakers-python": {"depends": [], "file_name": "lakers_python-0.6.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["lakers"], "install_dir": "site", "name": "lakers-python", "package_type": "package", "sha256": "60239e9e85ee953e9a9edb13a8810e89659c9d532444e4d55d32ed047170792e", "unvendored_tests": false, "version": "0.6.0"}, "lazy-loader": {"depends": [], "file_name": "lazy_loader-0.4-py3-none-any.whl", "imports": ["lazy_loader"], "install_dir": "site", "name": "lazy_loader", "package_type": "package", "sha256": "b46b6d7f9124873396e5e8ca0656adb11c8edf59934e93be8699d293a5ba9e7b", "unvendored_tests": true, "version": "0.4"}, "lazy-loader-tests": {"depends": ["lazy_loader"], "file_name": "lazy-loader-tests.tar", "imports": [], "install_dir": "site", "name": "lazy_loader-tests", "package_type": "package", "sha256": "4de49164cb79121e4c0701cf72ca50dfa70a1c25c226647be5d934acc6396653", "unvendored_tests": false, "version": "0.4"}, "lazy-object-proxy": {"depends": [], "file_name": "lazy_object_proxy-1.10.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["lazy_object_proxy"], "install_dir": "site", "name": "lazy-object-proxy", "package_type": "package", "sha256": "f78136e4bf7e17b01537752b392597bebf2b01807f79696421173e7f609225df", "unvendored_tests": false, "version": "1.10.0"}, "libcrc32c": {"depends": [], "file_name": "libcrc32c-1.1.0.zip", "imports": [], "install_dir": "dynlib", "name": "libcrc32c", "package_type": "shared_library", "sha256": "dd59006ba799fff18f02829338fedfe5d8eeba51bbd9ad9e712551ec93d5cc50", "unvendored_tests": false, "version": "1.1.0"}, "libcst": {"depends": ["pyyaml"], "file_name": "libcst-1.6.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["libcst"], "install_dir": "site", "name": "libcst", "package_type": "package", "sha256": "8ed555b5850c35e6c072f0965c5615df06e13a23a0dd60f192406080704ffe55", "unvendored_tests": true, "version": "1.6.0"}, "libcst-tests": {"depends": ["libcst"], "file_name": "libcst-tests.tar", "imports": [], "install_dir": "site", "name": "libcst-tests", "package_type": "package", "sha256": "bae8e946ce84316132a3e997c11d11336552371e897e885a683e06ec25ee8c11", "unvendored_tests": false, "version": "1.6.0"}, "libgdal": {"depends": ["libgeos"], "file_name": "libgdal-3.8.3.zip", "imports": [], "install_dir": "dynlib", "name": "libgdal", "package_type": "shared_library", "sha256": "c2e47d21f9ae47a12177c9f7d4aeaa8b7528fbf87a88d77778a159f910af459c", "unvendored_tests": false, "version": "3.8.3"}, "libgeos": {"depends": [], "file_name": "libgeos-3.12.1.zip", "imports": [], "install_dir": "dynlib", "name": "libgeos", "package_type": "shared_library", "sha256": "92899a5b7734ecef7dcf0f3f84cf73dbd48847f67c29d59555b6dc609940816b", "unvendored_tests": false, "version": "3.12.1"}, "libhdf5": {"depends": [], "file_name": "libhdf5-1.12.1.zip", "imports": [], "install_dir": "dynlib", "name": "libhdf5", "package_type": "shared_library", "sha256": "ea36748b4e800267ee2f237ebb1db8880a3a15344ee18333487befc936935fc5", "unvendored_tests": false, "version": "1.12.1"}, "libheif": {"depends": [], "file_name": "libheif-1.12.0.zip", "imports": [], "install_dir": "dynlib", "name": "libheif", "package_type": "shared_library", "sha256": "3bd6978820e070d61f5acc48cdc9fcf8e601477597117e7946d46de390bd283d", "unvendored_tests": false, "version": "1.12.0"}, "libmagic": {"depends": [], "file_name": "libmagic-5.42.zip", "imports": [], "install_dir": "dynlib", "name": "libmagic", "package_type": "shared_library", "sha256": "cae7434e74f870e730cd3584f94352adb2a61d6a0c6cfa2b97365a51b3978021", "unvendored_tests": false, "version": "5.42"}, "libngspice": {"depends": [], "file_name": "libngspice-44.2.zip", "imports": [], "install_dir": "dynlib", "name": "libngspice", "package_type": "shared_library", "sha256": "d6a0fe29032d30653f44b24553b4efdff65efee13cfd732ea47fb09525768d3f", "unvendored_tests": false, "version": "44.2"}, "libopenblas": {"depends": [], "file_name": "libopenblas-0.3.26.zip", "imports": [], "install_dir": "dynlib", "name": "libopenblas", "package_type": "shared_library", "sha256": "f8f5db65c9367ed7f057d0ee853d94ddb3c007968aa8138253461dad42537fa2", "unvendored_tests": false, "version": "0.3.26"}, "libopenssl": {"depends": [], "file_name": "libopenssl-1.1.1w.zip", "imports": [], "install_dir": "dynlib", "name": "libopenssl", "package_type": "shared_library", "sha256": "eaec7126f466a33ea4121fd230211bb01e9ad1c5748f3cd0b4b1c8677b4ac90a", "unvendored_tests": false, "version": "1.1.1w"}, "libproj": {"depends": [], "file_name": "libproj-9.6.2.zip", "imports": [], "install_dir": "dynlib", "name": "libproj", "package_type": "shared_library", "sha256": "8739c76e681f900923b900c9df0ef75cf421d39cabb54650c4b9ad19b6a76d85", "unvendored_tests": false, "version": "9.6.2"}, "libsuitesparse": {"depends": ["libopenblas"], "file_name": "libsuitesparse-5.11.0.zip", "imports": [], "install_dir": "dynlib", "name": "libsuitesparse", "package_type": "shared_library", "sha256": "8883746009a4fc5aa2b83cf109c37e5fb0c6e9db270b0ca4b4f87c762d831db9", "unvendored_tests": false, "version": "5.11.0"}, "libtaglib": {"depends": [], "file_name": "libtaglib-2.1.1.zip", "imports": [], "install_dir": "dynlib", "name": "libtaglib", "package_type": "shared_library", "sha256": "9783f638d2f124f9546a902b85186fc92b1b99b05e5e1853d938975df95bd075", "unvendored_tests": false, "version": "2.1.1"}, "lightgbm": {"depends": ["numpy", "scipy", "scikit-learn"], "file_name": "lightgbm-4.6.0-py3-none-pyodide_2025_0_wasm32.whl", "imports": ["lightgbm"], "install_dir": "site", "name": "lightgbm", "package_type": "package", "sha256": "75bb0670f69b252c19b3a546433c1fdd6ddb0a6234e2575b35bc655dec0f620b", "unvendored_tests": false, "version": "4.6.0"}, "logbook": {"depends": ["ssl"], "file_name": "logbook-1.8.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["logbook"], "install_dir": "site", "name": "logbook", "package_type": "package", "sha256": "2cb7f2954a26095d7217079692a39ec2754565945ab75e1ce0adfd5dbc1c37d2", "unvendored_tests": false, "version": "1.8.0"}, "lxml": {"depends": [], "file_name": "lxml-6.0.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["lxml"], "install_dir": "site", "name": "lxml", "package_type": "package", "sha256": "99b959a55eaeb41a2997fa022859892880c2b708af01ff336c34c7b125c80916", "unvendored_tests": false, "version": "6.0.2"}, "lz4": {"depends": [], "file_name": "lz4-4.4.5-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["lz4"], "install_dir": "site", "name": "lz4", "package_type": "package", "sha256": "2f3d8c272bc379a0722201073ba9912770d504bc6a2a576047b0b2d57bf69574", "unvendored_tests": false, "version": "4.4.5"}, "lzma": {"depends": [], "file_name": "lzma-1.0.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["lzma", "_lzma"], "install_dir": "site", "name": "lzma", "package_type": "cpython_module", "sha256": "2489604bcd9446eb1a40be1fcd8a989d0985499a0cb350fc6593aa626b27a05e", "unvendored_tests": false, "version": "1.0.0"}, "markupsafe": {"depends": [], "file_name": "markupsafe-3.0.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["markupsafe"], "install_dir": "site", "name": "MarkupSafe", "package_type": "package", "sha256": "2b480f742c99c45c9e0f7402ae6d0fa531284a3aa34da4b8982c37809c9b4d07", "unvendored_tests": false, "version": "3.0.2"}, "matplotlib": {"depends": ["contourpy", "cycler", "fonttools", "kiwisolver", "numpy", "packaging", "pillow", "pyparsing", "python-dateutil", "pytz"], "file_name": "matplotlib-3.8.4-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pylab", "mpl_toolkits", "matplotlib"], "install_dir": "site", "name": "matplotlib", "package_type": "package", "sha256": "65f657efbb717a6aa7ccd10c0729a0e6993c1da757bd68601d97a2905362e8d4", "unvendored_tests": true, "version": "3.8.4"}, "matplotlib-inline": {"depends": ["traitlets"], "file_name": "matplotlib_inline-0.2.1-py3-none-any.whl", "imports": ["matplotlib-inline"], "install_dir": "site", "name": "matplotlib-inline", "package_type": "package", "sha256": "aaeaba20ce1cb410ea322be58363ea043ce72e303bbb21126e0ca2de26f4d22d", "unvendored_tests": false, "version": "0.2.1"}, "matplotlib-tests": {"depends": ["matplotlib"], "file_name": "matplotlib-tests.tar", "imports": [], "install_dir": "site", "name": "matplotlib-tests", "package_type": "package", "sha256": "e369fa872c6634fb47cdd8c7529eaea15525d1b23e3fcfd5b94feec42184f10b", "unvendored_tests": false, "version": "3.8.4"}, "memory-allocator": {"depends": [], "file_name": "memory_allocator-0.1.4-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["memory_allocator"], "install_dir": "site", "name": "memory-allocator", "package_type": "package", "sha256": "04a7a7cec09e3410f9934f37de2e944adfc2af0a0d96ce4c87bcae42dcc225e8", "unvendored_tests": false, "version": "0.1.4"}, "micropip": {"depends": [], "file_name": "micropip-0.11.0-py3-none-any.whl", "imports": ["micropip"], "install_dir": "site", "name": "micropip", "package_type": "package", "sha256": "0ae422514e45d068b8159eb8ec3b2c3f4cbce2e664e26cb81735dbe4af2377a1", "unvendored_tests": false, "version": "0.11.0"}, "ml-dtypes": {"depends": ["numpy"], "file_name": "ml_dtypes-0.5.4-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["ml_dtypes"], "install_dir": "site", "name": "ml_dtypes", "package_type": "package", "sha256": "6f700837e66c1ba13199ebab7d8096472db10571e5b34a11343a2d636bcb696d", "unvendored_tests": false, "version": "0.5.4"}, "mmh3": {"depends": [], "file_name": "mmh3-5.1.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["mmh3"], "install_dir": "site", "name": "mmh3", "package_type": "package", "sha256": "9a2a114fee30ef9a762648472b81a3a982e491c1836b616c9bfbaeb5f47ec638", "unvendored_tests": false, "version": "5.1.0"}, "more-itertools": {"depends": [], "file_name": "more_itertools-10.6.0-py3-none-any.whl", "imports": ["more_itertools"], "install_dir": "site", "name": "more-itertools", "package_type": "package", "sha256": "14de567c4b1ec60c7a0a066ddfd72088f0b0da1f828f6d1f6d79015f3b9ad87a", "unvendored_tests": false, "version": "10.6.0"}, "mpmath": {"depends": [], "file_name": "mpmath-1.3.0-py3-none-any.whl", "imports": ["mpmath"], "install_dir": "site", "name": "mpmath", "package_type": "package", "sha256": "75c33edefd4b92311926ddbfa7aac6731a61b3b5ac0562bc8f8d420e23328d46", "unvendored_tests": true, "version": "1.3.0"}, "mpmath-tests": {"depends": ["mpmath"], "file_name": "mpmath-tests.tar", "imports": [], "install_dir": "site", "name": "mpmath-tests", "package_type": "package", "sha256": "d8e5d23684f5f4b95da9804737329f431550a8f9c4da4691b25b5846b57726f9", "unvendored_tests": false, "version": "1.3.0"}, "msgpack": {"depends": [], "file_name": "msgpack-1.1.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["msgpack"], "install_dir": "site", "name": "msgpack", "package_type": "package", "sha256": "802f05c8e529672806576596d6c37f49a58656d316c32ca1c1f96f6bb70b00a3", "unvendored_tests": false, "version": "1.1.2"}, "msgspec": {"depends": [], "file_name": "msgspec-0.19.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["msgspec"], "install_dir": "site", "name": "msgspec", "package_type": "package", "sha256": "d7fffe4d004646d47c875dd3b5489d25c14591ee02594bf9e69a5186499e421a", "unvendored_tests": false, "version": "0.19.0"}, "msprime": {"depends": ["numpy", "newick", "tskit", "demes", "rpds-py"], "file_name": "msprime-1.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["msprime"], "install_dir": "site", "name": "msprime", "package_type": "package", "sha256": "6cc9d1702506a0ec23c0edf602c3f516c9f7c5c2056859cef8423d65024363e9", "unvendored_tests": false, "version": "1.3.3"}, "multidict": {"depends": [], "file_name": "multidict-6.7.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["multidict"], "install_dir": "site", "name": "multidict", "package_type": "package", "sha256": "c7db3ee26fddee527406fef580d21aadb79adde44b61bc14ddac4977d31ea393", "unvendored_tests": false, "version": "6.7.0"}, "munch": {"depends": ["setuptools", "six"], "file_name": "munch-4.0.0-py2.py3-none-any.whl", "imports": ["munch"], "install_dir": "site", "name": "munch", "package_type": "package", "sha256": "a52d9ba576b9e0ce29b711c4451bfd7040a8e5d33f41819c98b03ae555e5839f", "unvendored_tests": false, "version": "4.0.0"}, "mypy": {"depends": [], "file_name": "mypy-1.15.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["mypyc", "mypy"], "install_dir": "site", "name": "mypy", "package_type": "package", "sha256": "4fd93f836f74be201f5c783d4d54b8957cfe6ac422cbcdb8b35cdb6d60f096a4", "unvendored_tests": true, "version": "1.15.0"}, "mypy-tests": {"depends": ["mypy"], "file_name": "mypy-tests.tar", "imports": [], "install_dir": "site", "name": "mypy-tests", "package_type": "package", "sha256": "5de2ddc2a3b5b64aaf92d76c0222121793cf886526a23c881561d9dbc5ff18b1", "unvendored_tests": false, "version": "1.15.0"}, "narwhals": {"depends": [], "file_name": "narwhals-2.15.0-py3-none-any.whl", "imports": ["narwhals"], "install_dir": "site", "name": "narwhals", "package_type": "package", "sha256": "bef7de68cf772cbac41808a772e12e68468e4736d7d03ca6103d5833361fac8d", "unvendored_tests": false, "version": "2.15.0"}, "ndindex": {"depends": [], "file_name": "ndindex-1.9.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["ndindex"], "install_dir": "site", "name": "ndindex", "package_type": "package", "sha256": "35d5fd03c16827a337006eb391cae62250360e60f815d104ce6f44392d3bb508", "unvendored_tests": true, "version": "1.9.2"}, "ndindex-tests": {"depends": ["ndindex"], "file_name": "ndindex-tests.tar", "imports": [], "install_dir": "site", "name": "ndindex-tests", "package_type": "package", "sha256": "d549d918c71f2491dae952f15f26c5770dbe6e35598a31effc8c7faa2f67e6c7", "unvendored_tests": false, "version": "1.9.2"}, "netcdf4": {"depends": ["numpy", "packaging", "h5py", "cftime", "certifi", "libhdf5"], "file_name": "netcdf4-1.7.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["netCDF4"], "install_dir": "site", "name": "netcdf4", "package_type": "package", "sha256": "dc1a17b676477265f95bf219a056dd44faddce49efa23c53e631d33e1db684a7", "unvendored_tests": false, "version": "1.7.2"}, "networkx": {"depends": ["decorator", "setuptools", "matplotlib", "numpy"], "file_name": "networkx-3.4.2-py3-none-any.whl", "imports": ["networkx"], "install_dir": "site", "name": "networkx", "package_type": "package", "sha256": "a29f3036b00fa0fe1562a31feac086848f55f3c0a36e9bf76e89201be939e3ac", "unvendored_tests": true, "version": "3.4.2"}, "networkx-tests": {"depends": ["networkx"], "file_name": "networkx-tests.tar", "imports": [], "install_dir": "site", "name": "networkx-tests", "package_type": "package", "sha256": "fb9faecf96ece9717bb9292edfd3b574c71a22c7426dc0754118ba669db0a3e2", "unvendored_tests": false, "version": "3.4.2"}, "newick": {"depends": [], "file_name": "newick-1.9.0-py2.py3-none-any.whl", "imports": ["newick"], "install_dir": "site", "name": "newick", "package_type": "package", "sha256": "ab63c8d58dfb570b30db2f89eeffb08078472be0cf879ff204ba3bdd33842c46", "unvendored_tests": false, "version": "1.9.0"}, "nh3": {"depends": [], "file_name": "nh3-0.2.21-cp38-abi3-pyodide_2025_0_wasm32.whl", "imports": ["nh3"], "install_dir": "site", "name": "nh3", "package_type": "package", "sha256": "db3a9a2828e109400ce361c8e9f2deeb8f49b41d870cae19377a9c5ed1a19d88", "unvendored_tests": false, "version": "0.2.21"}, "nlopt": {"depends": ["numpy"], "file_name": "nlopt-2.9.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["nlopt"], "install_dir": "site", "name": "nlopt", "package_type": "package", "sha256": "f8bf68dc26a2a97975e2d93fde03f97e808d7c90f131e0b1bfd0d8ffec2fa4e7", "unvendored_tests": false, "version": "2.9.1"}, "nltk": {"depends": ["regex", "sqlite3"], "file_name": "nltk-3.9.1-py3-none-any.whl", "imports": ["nltk"], "install_dir": "site", "name": "nltk", "package_type": "package", "sha256": "17ed6948bd75a0cba27a7a99f08c9f348dbb376ae069022e8c3cec622904102a", "unvendored_tests": true, "version": "3.9.1"}, "nltk-tests": {"depends": ["nltk"], "file_name": "nltk-tests.tar", "imports": [], "install_dir": "site", "name": "nltk-tests", "package_type": "package", "sha256": "2e22290acde6cbceef7a0a6ed3728b627559ee768799fbb334b5831d8489cfc6", "unvendored_tests": false, "version": "3.9.1"}, "numcodecs": {"depends": ["numpy", "msgpack"], "file_name": "numcodecs-0.13.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["numcodecs"], "install_dir": "site", "name": "numcodecs", "package_type": "package", "sha256": "da29b4c22dad035a96f0edb9a4f49d92eb3d760112865947ac791e98bc7ddb82", "unvendored_tests": true, "version": "0.13.1"}, "numcodecs-tests": {"depends": ["numcodecs"], "file_name": "numcodecs-tests.tar", "imports": [], "install_dir": "site", "name": "numcodecs-tests", "package_type": "package", "sha256": "dedcd6ca0cd61b5bb0df95673ddbc91710623f83be7c918c7910b7c9959d01cd", "unvendored_tests": false, "version": "0.13.1"}, "numpy": {"depends": [], "file_name": "numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["numpy"], "install_dir": "site", "name": "numpy", "package_type": "package", "sha256": "6eaab6a7bb658d71ebe702911a3deab715323642462eb41b65565ca6a7cc23f1", "unvendored_tests": false, "version": "2.2.5"}, "numpy-tests": {"depends": [], "file_name": "numpy_tests-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["numpy-tests"], "install_dir": "site", "name": "numpy-tests", "package_type": "package", "sha256": "9162518247787fb647890f2a4bc4af7b6b5c720aab43c9f8c20c5fad3b9fcc36", "unvendored_tests": false, "version": "2.2.5"}, "openai": {"depends": ["httpx", "pydantic", "typing-extensions", "distro", "anyio", "jiter"], "file_name": "openai-1.68.2-py3-none-any.whl", "imports": ["openai"], "install_dir": "site", "name": "openai", "package_type": "package", "sha256": "55485cde95b81742b2e3ae57f6a2f02dc51696e6fba0989299a6eabc7003c8da", "unvendored_tests": false, "version": "1.68.2"}, "opencv-python": {"depends": ["numpy"], "file_name": "opencv_python-4.11.0.86-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["cv2"], "install_dir": "site", "name": "opencv-python", "package_type": "package", "sha256": "a8b116def8c74b3ccf389b856b3ccb5cec5a2efc295ec17a15ea9cda1f88aa1e", "unvendored_tests": false, "version": "4.11.0.86"}, "optlang": {"depends": ["sympy", "six", "swiglpk"], "file_name": "optlang-1.8.3-py2.py3-none-any.whl", "imports": ["optlang"], "install_dir": "site", "name": "optlang", "package_type": "package", "sha256": "0efd4f2474919e5834f707540db8e0ba4cae9d7aa9a3bd6bb778092c1ad423f2", "unvendored_tests": true, "version": "1.8.3"}, "optlang-tests": {"depends": ["optlang"], "file_name": "optlang-tests.tar", "imports": [], "install_dir": "site", "name": "optlang-tests", "package_type": "package", "sha256": "0dae9b248d5c81bd590ee3ffad6d8b6d021b39cbbac7b5cb74541e1bebda4391", "unvendored_tests": false, "version": "1.8.3"}, "orjson": {"depends": [], "file_name": "orjson-3.10.16-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["orjson"], "install_dir": "site", "name": "orjson", "package_type": "package", "sha256": "4b815ae28eef5332e898e220ec3f7de4d0cb5067aa895db589bb05989bb2608b", "unvendored_tests": false, "version": "3.10.16"}, "packaging": {"depends": [], "file_name": "packaging-24.2-py3-none-any.whl", "imports": ["packaging"], "install_dir": "site", "name": "packaging", "package_type": "package", "sha256": "c18cde5592cc3d1823e9cc3a9a4fb436b02c15e3f8d7f5f69962f77b1b109da1", "unvendored_tests": false, "version": "24.2"}, "pandas": {"depends": ["numpy", "python-dateutil", "pytz"], "file_name": "pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pandas"], "install_dir": "site", "name": "pandas", "package_type": "package", "sha256": "5b1c0acfc8555be16057e8609e9eb7f279037c2469032bcc23e2a691380a50ae", "unvendored_tests": true, "version": "2.3.3"}, "pandas-tests": {"depends": ["pandas"], "file_name": "pandas-tests.tar", "imports": [], "install_dir": "site", "name": "pandas-tests", "package_type": "package", "sha256": "d5f994d07ff84875b87f135ff944fc0e970dd7e599b315c48642afeeba7e6731", "unvendored_tests": false, "version": "2.3.3"}, "parso": {"depends": [], "file_name": "parso-0.8.4-py2.py3-none-any.whl", "imports": ["parso"], "install_dir": "site", "name": "parso", "package_type": "package", "sha256": "3a5faf5729dd290ffc178674515912f0b79fec5ac02d261699daddfbeb847d3a", "unvendored_tests": false, "version": "0.8.4"}, "patsy": {"depends": ["numpy", "six"], "file_name": "patsy-1.0.1-py2.py3-none-any.whl", "imports": ["patsy"], "install_dir": "site", "name": "patsy", "package_type": "package", "sha256": "34d2156b3db04a1c565dad7072d3cff22e02c22b72a531e1d3ee3a9442e7f4e7", "unvendored_tests": true, "version": "1.0.1"}, "patsy-tests": {"depends": ["patsy"], "file_name": "patsy-tests.tar", "imports": [], "install_dir": "site", "name": "patsy-tests", "package_type": "package", "sha256": "b31f9b8a7d2212239c2a6b52547bc57af570586e785399e7de048c7f754a9a23", "unvendored_tests": false, "version": "1.0.1"}, "pcodec": {"depends": ["numpy"], "file_name": "pcodec-0.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pcodec"], "install_dir": "site", "name": "pcodec", "package_type": "package", "sha256": "a0e34ad928aacb5eec9204573725835efa1191c9995bb1b690e6d15b0100edf4", "unvendored_tests": false, "version": "0.3.3"}, "peewee": {"depends": ["sqlite3", "cffi"], "file_name": "peewee-3.17.9-py3-none-any.whl", "imports": ["peewee"], "install_dir": "site", "name": "peewee", "package_type": "package", "sha256": "540439a57875866a9880818f2ed5982d67220c11b94e154b18da736262ad49a9", "unvendored_tests": true, "version": "3.17.9"}, "peewee-tests": {"depends": ["peewee"], "file_name": "peewee-tests.tar", "imports": [], "install_dir": "site", "name": "peewee-tests", "package_type": "package", "sha256": "eded3f39bec30ef6a171068b23429c7967fdeacf36fcf758aaed8030068ed920", "unvendored_tests": false, "version": "3.17.9"}, "pi-heif": {"depends": ["cffi", "pillow", "libheif"], "file_name": "pi_heif-0.21.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pi_heif"], "install_dir": "site", "name": "pi-heif", "package_type": "package", "sha256": "6929ba48c15bbb914c2b52c76d7d8e6d909114dbef49fad7dc3fffa8def2549a", "unvendored_tests": false, "version": "0.21.0"}, "pillow": {"depends": [], "file_name": "pillow-11.3.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["PIL"], "install_dir": "site", "name": "Pillow", "package_type": "package", "sha256": "7e1168616481f685f277d7fad1d197f3a625540542a2cd292cdc8958ab083d6e", "unvendored_tests": false, "version": "11.3.0"}, "pillow-heif": {"depends": ["cffi", "pillow", "libheif"], "file_name": "pillow_heif-1.1.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pillow_heif"], "install_dir": "site", "name": "pillow-heif", "package_type": "package", "sha256": "3304a87c7ca9371c43725f67e070a7a143493d9cbdbb4c5203b6641a2c223ad6", "unvendored_tests": false, "version": "1.1.1"}, "pkgconfig": {"depends": [], "file_name": "pkgconfig-1.5.5-py3-none-any.whl", "imports": ["pkgconfig"], "install_dir": "site", "name": "pkgconfig", "package_type": "package", "sha256": "48f41d6739ec0941055e25efea42881b6970416fca506caf4b047eecde189e91", "unvendored_tests": false, "version": "1.5.5"}, "platformdirs": {"depends": [], "file_name": "platformdirs-4.3.6-py3-none-any.whl", "imports": ["platformdirs"], "install_dir": "site", "name": "platformdirs", "package_type": "package", "sha256": "909ec75bf144b5641ece53173061f820f8df7daf754cd4016d2c17c93018c118", "unvendored_tests": false, "version": "4.3.6"}, "pluggy": {"depends": [], "file_name": "pluggy-1.5.0-py3-none-any.whl", "imports": ["pluggy"], "install_dir": "site", "name": "pluggy", "package_type": "package", "sha256": "a5526e777aac76c926e884d8c5f8104a909e1243a2f3ecc6b9bb1b52fa46f7bd", "unvendored_tests": false, "version": "1.5.0"}, "ply": {"depends": [], "file_name": "ply-3.11-py2.py3-none-any.whl", "imports": ["ply"], "install_dir": "site", "name": "ply", "package_type": "package", "sha256": "00278ab037f4e6068af477e5fc3553f78e2c824aad9595160061058aa77a954f", "unvendored_tests": false, "version": "3.11"}, "pplpy": {"depends": ["gmpy2", "cysignals"], "file_name": "pplpy-0.8.10-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["ppl"], "install_dir": "site", "name": "pplpy", "package_type": "package", "sha256": "a400cd911dcaf95161588d31ff2eba7b7e73de92f9842b27b290918280a68216", "unvendored_tests": false, "version": "0.8.10"}, "primecountpy": {"depends": ["cysignals"], "file_name": "primecountpy-0.1.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["primecountpy"], "install_dir": "site", "name": "primecountpy", "package_type": "package", "sha256": "b1a52c5537f1e8162bf2cd2b8974aea86f2420890c2bd5b8fef2bfc3fc468f54", "unvendored_tests": false, "version": "0.1.1"}, "prompt-toolkit": {"depends": ["wcwidth"], "file_name": "prompt_toolkit-3.0.50-py3-none-any.whl", "imports": ["prompt_toolkit"], "install_dir": "site", "name": "prompt_toolkit", "package_type": "package", "sha256": "c850b8c5f71eeda05fc0237ec2ca75ce74d96baf398ec0f3af7b7b582b5eb4eb", "unvendored_tests": false, "version": "3.0.50"}, "propcache": {"depends": [], "file_name": "propcache-0.3.0-py3-none-any.whl", "imports": ["propcache"], "install_dir": "site", "name": "propcache", "package_type": "package", "sha256": "b6676a4e95b3e2e43515b4606c48c1f6f907c7e552caaea17140948c94817f1c", "unvendored_tests": false, "version": "0.3.0"}, "protobuf": {"depends": [], "file_name": "protobuf-6.31.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["google"], "install_dir": "site", "name": "protobuf", "package_type": "package", "sha256": "c37921bc1631dfac55b654563a45df630eb963c720e1092ffe6cd8a388f9ae5b", "unvendored_tests": false, "version": "6.31.1"}, "pure-eval": {"depends": [], "file_name": "pure_eval-0.2.3-py3-none-any.whl", "imports": ["pure_eval"], "install_dir": "site", "name": "pure-eval", "package_type": "package", "sha256": "4e68524914448c8b2d74da68820e3270789745dab658c25cf1e011203e51ee58", "unvendored_tests": false, "version": "0.2.3"}, "py": {"depends": [], "file_name": "py-1.11.0-py2.py3-none-any.whl", "imports": ["py"], "install_dir": "site", "name": "py", "package_type": "package", "sha256": "425c7054bd6b8ee8efb556b04c88889bf64e0e4a5a7c210b14adbffc26fc0783", "unvendored_tests": false, "version": "1.11.0"}, "pyarrow": {"depends": ["numpy", "pandas", "pyodide-unix-timezones"], "file_name": "pyarrow-22.0.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pyarrow"], "install_dir": "site", "name": "pyarrow", "package_type": "package", "sha256": "b5c6b7b7aa72627071f414bc19ff762012e1052ee0634a30cd7f2c57dd6d84ba", "unvendored_tests": false, "version": "22.0.0"}, "pycdfpp": {"depends": ["numpy", "pyyaml"], "file_name": "pycdfpp-0.8.5-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pycdfpp"], "install_dir": "site", "name": "pycdfpp", "package_type": "package", "sha256": "07ab0a2dd561fd99edf24b8a131fbac590ca7ba978345d33921917fcb341cfca", "unvendored_tests": false, "version": "0.8.5"}, "pyclipper": {"depends": [], "file_name": "pyclipper-1.3.0.post6-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pyclipper"], "install_dir": "site", "name": "pyclipper", "package_type": "package", "sha256": "7d7af1b80ac33383a87e21df5839bd9caf33500ea69cdaab50fa462e208b831b", "unvendored_tests": false, "version": "1.3.0.post6"}, "pycparser": {"depends": [], "file_name": "pycparser-2.22-py3-none-any.whl", "imports": ["pycparser"], "install_dir": "site", "name": "pycparser", "package_type": "package", "sha256": "778a41679914eee8499ce3d37a8d15d808d8972e70aa02eef13ac59649559aaa", "unvendored_tests": false, "version": "2.22"}, "pycryptodome": {"depends": [], "file_name": "pycryptodome-3.21.0-cp36-abi3-pyodide_2025_0_wasm32.whl", "imports": ["Crypto"], "install_dir": "site", "name": "pycryptodome", "package_type": "package", "sha256": "2d3bdd009cf49ec43e09ac3217b9fffd128a7d32dd3d2d112602b2d34e40174a", "unvendored_tests": true, "version": "3.21.0"}, "pycryptodome-tests": {"depends": ["pycryptodome"], "file_name": "pycryptodome-tests.tar", "imports": [], "install_dir": "site", "name": "pycryptodome-tests", "package_type": "package", "sha256": "61f21439f6956bbe2e339e6d4b437021b9250da64e04ba7ebaee0372fd534f94", "unvendored_tests": false, "version": "3.21.0"}, "pydantic": {"depends": ["typing-extensions", "pydantic_core", "annotated-types", "typing-inspection"], "file_name": "pydantic-2.12.5-py3-none-any.whl", "imports": ["pydantic"], "install_dir": "site", "name": "pydantic", "package_type": "package", "sha256": "a56b56d0a0942fbd5cf24a9c9195eb5bdfeceea17ddb3e1cd174db43be4e88dc", "unvendored_tests": false, "version": "2.12.5"}, "pydantic-core": {"depends": ["typing-extensions"], "file_name": "pydantic_core-2.41.5-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pydantic_core"], "install_dir": "site", "name": "pydantic_core", "package_type": "package", "sha256": "dd259177c9159a866334e2ac040aca973b8205cc884b3297cb5b2dc6bef8d629", "unvendored_tests": false, "version": "2.41.5"}, "pydecimal": {"depends": [], "file_name": "pydecimal-1.0.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["_pydecimal"], "install_dir": "site", "name": "pydecimal", "package_type": "cpython_module", "sha256": "de2ad05e281819096c73008eb8816b1ad5e7bc64a5539eabf2b131927a0e483a", "unvendored_tests": false, "version": "1.0.0"}, "pydoc-data": {"depends": [], "file_name": "pydoc_data-1.0.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pydoc_data"], "install_dir": "site", "name": "pydoc_data", "package_type": "cpython_module", "sha256": "d288a116e5592b16788b20dde1d75351129bbeeace4cf4c50b798df7fe535ef8", "unvendored_tests": false, "version": "1.0.0"}, "pyerfa": {"depends": ["numpy"], "file_name": "pyerfa-2.0.1.5-cp39-abi3-pyodide_2025_0_wasm32.whl", "imports": ["erfa"], "install_dir": "site", "name": "pyerfa", "package_type": "package", "sha256": "063e4a534e3ef00014683e8e5d896a3ebeb273d3a5cdd9f7a8c2ea6c30fca7c3", "unvendored_tests": true, "version": "2.0.1.5"}, "pyerfa-tests": {"depends": ["pyerfa"], "file_name": "pyerfa-tests.tar", "imports": [], "install_dir": "site", "name": "pyerfa-tests", "package_type": "package", "sha256": "8e9388e6240dadbb3493c9e238ae856413a4d0f79bb0747a4e2007ec0e805992", "unvendored_tests": false, "version": "2.0.1.5"}, "pygame-ce": {"depends": [], "file_name": "pygame_ce-2.5.6.dev2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pygame"], "install_dir": "site", "name": "pygame-ce", "package_type": "package", "sha256": "d7c52caf092288b6f813d8cf4c07edd98b47cc67385bc377147a8e5e12310872", "unvendored_tests": false, "version": "2.5.6.dev2"}, "pygments": {"depends": [], "file_name": "pygments-2.19.1-py3-none-any.whl", "imports": ["pygments"], "install_dir": "site", "name": "Pygments", "package_type": "package", "sha256": "1557c19a71c6c60b814ba3a921583ab97a15722fb21ba3ab73f2d6f477b49213", "unvendored_tests": false, "version": "2.19.1"}, "pyheif": {"depends": ["cffi"], "file_name": "pyheif-0.8.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pyheif"], "install_dir": "site", "name": "pyheif", "package_type": "package", "sha256": "a90413a3bcebf7c73a4a5a1317c6d8ca1b5e553936d2a15e04280f4303ea4d2c", "unvendored_tests": false, "version": "0.8.0"}, "pyiceberg": {"depends": ["click", "cachetools", "fsspec", "mmh3", "pydantic", "pyparsing", "requests", "rich", "sortedcontainers", "sqlalchemy", "strictyaml"], "file_name": "pyiceberg-0.10.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pyiceberg"], "install_dir": "site", "name": "pyiceberg", "package_type": "package", "sha256": "5f14f73c3cb98e1883931eea53e5de57609ed668f85382eb0b50b4a26aadbfdf", "unvendored_tests": false, "version": "0.10.0"}, "pyinstrument": {"depends": [], "file_name": "pyinstrument-5.0.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pyinstrument"], "install_dir": "site", "name": "pyinstrument", "package_type": "package", "sha256": "266504251136dd4c960e66c61f071d56abdbb363e3d91e68be26044356fd5185", "unvendored_tests": false, "version": "5.0.1"}, "pylimer-tools": {"depends": ["numpy"], "file_name": "pylimer_tools-0.3.13-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pylimer_tools"], "install_dir": "site", "name": "pylimer-tools", "package_type": "package", "sha256": "bf2eedb0103e6f958d7da4e666e25c396fc0ef588e3623d3a7c9fe07b5296216", "unvendored_tests": false, "version": "0.3.13"}, "pymupdf": {"depends": [], "file_name": "pymupdf-1.26.3-cp313-none-pyodide_2025_0_wasm32.whl", "imports": ["pymupdf", "fitz"], "install_dir": "site", "name": "PyMuPDF", "package_type": "package", "sha256": "271f7fb3c20b0ddd6f6618b01460ce207ce5370d5549c407837954f24a0ef8ec", "unvendored_tests": false, "version": "1.26.3"}, "pynacl": {"depends": ["cffi"], "file_name": "pynacl-1.5.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["nacl"], "install_dir": "site", "name": "pynacl", "package_type": "package", "sha256": "fb2518a6fee4b24c86b71f110387d3be534cdfce1682a8c3f2e91aa5f03ae7b7", "unvendored_tests": false, "version": "1.5.0"}, "pyodide-http": {"depends": [], "file_name": "pyodide_http-0.2.2-py3-none-any.whl", "imports": ["pyodide_http"], "install_dir": "site", "name": "pyodide-http", "package_type": "package", "sha256": "0cc0d07f3151e5deac22bbdbbf114642da983739ee394a3d31db5c7762c4c146", "unvendored_tests": false, "version": "0.2.2"}, "pyodide-unix-timezones": {"depends": [], "file_name": "pyodide_unix_timezones-1.0.0-py3-none-any.whl", "imports": ["unix_timezones"], "install_dir": "site", "name": "pyodide-unix-timezones", "package_type": "package", "sha256": "49469bacdf058914c325d8e49d1020c2803dd921d6c2d7a71a29ceea952fd438", "unvendored_tests": false, "version": "1.0.0"}, "pyparsing": {"depends": [], "file_name": "pyparsing-3.2.1-py3-none-any.whl", "imports": ["pyparsing"], "install_dir": "site", "name": "pyparsing", "package_type": "package", "sha256": "8f314b856e7e87cb3a426ce4db341308199157f6a757256e215e4d418e216d86", "unvendored_tests": false, "version": "3.2.1"}, "pyproj": {"depends": ["certifi"], "file_name": "pyproj-3.7.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pyproj"], "install_dir": "site", "name": "pyproj", "package_type": "package", "sha256": "fd7af196bfb8d88c095293fa241498982cb39d7af15a3fc133ae533185d6d710", "unvendored_tests": false, "version": "3.7.2"}, "pyrodigal": {"depends": [], "file_name": "pyrodigal-3.7.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pyrodigal"], "install_dir": "site", "name": "pyrodigal", "package_type": "package", "sha256": "4c8351cc959cb64962bcbdd0de60de928ea8ff9c973f969e461e908d43784467", "unvendored_tests": true, "version": "3.7.0"}, "pyrodigal-tests": {"depends": ["pyrodigal"], "file_name": "pyrodigal-tests.tar", "imports": [], "install_dir": "site", "name": "pyrodigal-tests", "package_type": "package", "sha256": "38d1bac466a4a9a63a98d19470abe83c8c403285e2b5fa7d04f491d2746f3846", "unvendored_tests": false, "version": "3.7.0"}, "pyrsistent": {"depends": [], "file_name": "pyrsistent-0.20.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["_pyrsistent_version", "pyrsistent"], "install_dir": "site", "name": "pyrsistent", "package_type": "package", "sha256": "ea59641657ac5f69b04484e646eecdf3d09e4759163e2cdee876e18ae711ed4c", "unvendored_tests": false, "version": "0.20.0"}, "pysam": {"depends": [], "file_name": "pysam-0.23.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pysam"], "install_dir": "site", "name": "pysam", "package_type": "package", "sha256": "792be11ba2580824612c766f5ff973f21e1cd99a483d1d9fb749521cd2ceb214", "unvendored_tests": false, "version": "0.23.0"}, "pyshp": {"depends": [], "file_name": "pyshp-2.3.1-py2.py3-none-any.whl", "imports": ["shapefile"], "install_dir": "site", "name": "pyshp", "package_type": "package", "sha256": "36946c1f1fc24ddf6774182619192a3da96ec3bcb1245b62c7270b9c45099d31", "unvendored_tests": false, "version": "2.3.1"}, "pytaglib": {"depends": ["libtaglib"], "file_name": "pytaglib-3.0.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["taglib"], "install_dir": "site", "name": "pytaglib", "package_type": "package", "sha256": "cd1d71c16bf40edd342e7917060559451b57ddfd76317dadf3dc31e4e4c25098", "unvendored_tests": false, "version": "3.0.1"}, "pytest": {"depends": ["atomicwrites", "attrs", "more-itertools", "pluggy", "py", "setuptools", "six", "iniconfig", "exceptiongroup"], "file_name": "pytest-8.3.5-py3-none-any.whl", "imports": ["_pytest", "pytest"], "install_dir": "site", "name": "pytest", "package_type": "package", "sha256": "f648e340ac21fd1a19361d4083690f759533e3579a7d02645f31ca91c1b45d9b", "unvendored_tests": false, "version": "8.3.5"}, "pytest-asyncio": {"depends": ["pytest"], "file_name": "pytest_asyncio-0.25.3-py3-none-any.whl", "imports": ["pytest_asyncio"], "install_dir": "site", "name": "pytest-asyncio", "package_type": "package", "sha256": "12bb1ef200b7a8f6296f1c137a7639c588060c0afbeea4e236c827b75fd4b271", "unvendored_tests": false, "version": "0.25.3"}, "pytest-benchmark": {"depends": [], "file_name": "pytest_benchmark-4.0.0-py3-none-any.whl", "imports": ["pytest_benchmark"], "install_dir": "site", "name": "pytest-benchmark", "package_type": "package", "sha256": "6ddd836283cc63bb56de20e93e3f7326288cc9bc677f8f3f4b02fcad6216994f", "unvendored_tests": false, "version": "4.0.0"}, "pytest-httpx": {"depends": ["httpx", "pytest", "httpcore"], "file_name": "pytest_httpx-0.30.0-py3-none-any.whl", "imports": ["pytest_httpx"], "install_dir": "site", "name": "pytest_httpx", "package_type": "package", "sha256": "e4e50630f19692cb862c8e0a44fa4f806cb7cca86a57e65a1a4d05e4c0e9395f", "unvendored_tests": false, "version": "0.30.0"}, "python-calamine": {"depends": ["packaging"], "file_name": "python_calamine-0.5.3-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["python_calamine"], "install_dir": "site", "name": "python-calamine", "package_type": "package", "sha256": "5a1722bbac59c7a62250511267ac0709160145cb6b37af7352d6b1148d291b64", "unvendored_tests": false, "version": "0.5.3"}, "python-dateutil": {"depends": ["six"], "file_name": "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", "imports": ["dateutil"], "install_dir": "site", "name": "python-dateutil", "package_type": "package", "sha256": "ddca13fc1046572701872b9517622b57f847c77eea4bf9fdc995256e6c82beaf", "unvendored_tests": false, "version": "2.9.0.post0"}, "python-flint": {"depends": [], "file_name": "python_flint-0.8.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["flint"], "install_dir": "site", "name": "python-flint", "package_type": "package", "sha256": "2615968edf0985813ff377a368d7f58a1be7d8ade2327c8914f4c1a193ce7bcf", "unvendored_tests": false, "version": "0.8.0"}, "python-magic": {"depends": ["libmagic"], "file_name": "python_magic-0.4.27-py2.py3-none-any.whl", "imports": ["magic"], "install_dir": "site", "name": "python-magic", "package_type": "package", "sha256": "40caa90926fe5249bc6d6ccf1c8d026d2366d384395650756eeb3223cffbcf82", "unvendored_tests": false, "version": "0.4.27"}, "python-sat": {"depends": ["six"], "file_name": "python_sat-1.8.dev26-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pysat"], "install_dir": "site", "name": "python-sat", "package_type": "package", "sha256": "6ba3b64402341ec89825f760f9f462c21bd1a69b38b052b6a1c0262f924df122", "unvendored_tests": false, "version": "1.8.dev26"}, "python-solvespace": {"depends": [], "file_name": "python_solvespace-3.0.8-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["python_solvespace"], "install_dir": "site", "name": "python-solvespace", "package_type": "package", "sha256": "a6d0c80bdc9aff71ef7a36fb88a15a72fc04ab589ff12eb997b2ad56738da21c", "unvendored_tests": false, "version": "3.0.8"}, "pytz": {"depends": [], "file_name": "pytz-2025.2-py2.py3-none-any.whl", "imports": ["pytz"], "install_dir": "site", "name": "pytz", "package_type": "package", "sha256": "5a9c9286f6c03a4d16ee4ced15d511097568e1e41329d3499b597ecd7f1d317e", "unvendored_tests": false, "version": "2025.2"}, "pywavelets": {"depends": ["numpy"], "file_name": "pywavelets-1.8.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pywt"], "install_dir": "site", "name": "pywavelets", "package_type": "package", "sha256": "4e3df040f2927cd2ead32678cf40f323424519f084b9d5c4cf3ea1851e7bd2ba", "unvendored_tests": true, "version": "1.8.0"}, "pywavelets-tests": {"depends": ["pywavelets"], "file_name": "pywavelets-tests.tar", "imports": [], "install_dir": "site", "name": "pywavelets-tests", "package_type": "package", "sha256": "ac735e687c282003e049a48ba16b6ffb48a23ac3c45f04860f8d4eeecd7ecaa9", "unvendored_tests": false, "version": "1.8.0"}, "pyxel": {"depends": [], "file_name": "pyxel-1.9.10-cp37-abi3-pyodide_2025_0_wasm32.whl", "imports": ["pyxel"], "install_dir": "site", "name": "pyxel", "package_type": "package", "sha256": "a10c723c40f0f893f3da75fb230134af15150b818097e11d438d548d5ea2fd44", "unvendored_tests": false, "version": "1.9.10"}, "pyxirr": {"depends": [], "file_name": "pyxirr-0.10.6-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["pyxirr"], "install_dir": "site", "name": "pyxirr", "package_type": "package", "sha256": "0948e9ce6b751811d4b410f29ace3292bdf0db066acd9277645e9752ebca7935", "unvendored_tests": false, "version": "0.10.6"}, "pyyaml": {"depends": [], "file_name": "pyyaml-6.0.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["_yaml", "yaml"], "install_dir": "site", "name": "pyyaml", "package_type": "package", "sha256": "d0b3d100f3ebe90c0ea62f04d9ac2d3c38ca0023be5d240ef92c77b94c9495f8", "unvendored_tests": false, "version": "6.0.2"}, "rasterio": {"depends": ["numpy", "affine", "attrs", "certifi", "click", "cligj"], "file_name": "rasterio-1.4.3-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["rasterio"], "install_dir": "site", "name": "rasterio", "package_type": "package", "sha256": "3fa33927cc7a1ea9187aecebace9a82d0e91641e80886687d610fcdef563e310", "unvendored_tests": false, "version": "1.4.3"}, "rateslib": {"depends": ["numpy", "pandas", "matplotlib"], "file_name": "rateslib-2.5.1-cp310-abi3-pyodide_2025_0_wasm32.whl", "imports": ["rateslib"], "install_dir": "site", "name": "rateslib", "package_type": "package", "sha256": "bddc87fee2fecfcf1719d2183110d72c7523c1bd021780a82a54c44e6a1bfe87", "unvendored_tests": false, "version": "2.5.1"}, "rebound": {"depends": ["numpy"], "file_name": "rebound-4.4.7-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["rebound"], "install_dir": "site", "name": "rebound", "package_type": "package", "sha256": "6baac26fcc18f1f9fc3efc10282196e2413135392902e48d1edbaff0c464559c", "unvendored_tests": false, "version": "4.4.7"}, "reboundx": {"depends": ["rebound", "numpy"], "file_name": "reboundx-4.4.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["reboundx"], "install_dir": "site", "name": "reboundx", "package_type": "package", "sha256": "8e8542dbc7bc630a469d890601af41f923e8b4ab8b804368ee20eef32cad9b8c", "unvendored_tests": false, "version": "4.4.1"}, "referencing": {"depends": ["attrs", "rpds-py", "typing-extensions"], "file_name": "referencing-0.36.2-py3-none-any.whl", "imports": ["referencing"], "install_dir": "site", "name": "referencing", "package_type": "package", "sha256": "9fd72557776e4d4e1eb6f0d906c41c0dd71a8e6bce8d791e93a1ea6aba0602fc", "unvendored_tests": true, "version": "0.36.2"}, "referencing-tests": {"depends": ["referencing"], "file_name": "referencing-tests.tar", "imports": [], "install_dir": "site", "name": "referencing-tests", "package_type": "package", "sha256": "f34c6e81fb7dea8f9f731c965c6d2888aeb39c0c4a4ad59817966aba389b0887", "unvendored_tests": false, "version": "0.36.2"}, "regex": {"depends": [], "file_name": "regex-2024.11.6-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["regex"], "install_dir": "site", "name": "regex", "package_type": "package", "sha256": "0400d660e4f9f6359b7a98077bdc46b34b705b38f0f6c96a3053c8b5703caeed", "unvendored_tests": true, "version": "2024.11.6"}, "regex-tests": {"depends": ["regex"], "file_name": "regex-tests.tar", "imports": [], "install_dir": "site", "name": "regex-tests", "package_type": "package", "sha256": "1974108c86e92577fceac91ed1ef782a070d9b8243012446e97b193f79df1166", "unvendored_tests": false, "version": "2024.11.6"}, "requests": {"depends": ["charset-normalizer", "idna", "urllib3", "certifi"], "file_name": "requests-2.32.4-py3-none-any.whl", "imports": ["requests"], "install_dir": "site", "name": "requests", "package_type": "package", "sha256": "1e5c14010785e00a8d8bbb1874fd9382b2de21d6b81cbe07588c49f7a39393ef", "unvendored_tests": false, "version": "2.32.4"}, "retrying": {"depends": ["six"], "file_name": "retrying-1.3.4-py3-none-any.whl", "imports": ["retrying"], "install_dir": "site", "name": "retrying", "package_type": "package", "sha256": "6dcfceefc2f1f66713031db3c49737e742e9f3fe2becbb9de2d67c94d6c0dbc8", "unvendored_tests": false, "version": "1.3.4"}, "rich": {"depends": [], "file_name": "rich-13.9.4-py3-none-any.whl", "imports": ["rich"], "install_dir": "site", "name": "rich", "package_type": "package", "sha256": "d996f3db62e16f85134b3c3f433ca1c9d30b16d9ae67ec5b4e190c21ed45becd", "unvendored_tests": false, "version": "13.9.4"}, "river": {"depends": ["numpy", "pandas", "scipy"], "file_name": "river-0.22.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["river"], "install_dir": "site", "name": "river", "package_type": "package", "sha256": "5cc5e34dbfe552936d05ce6b2c2895548d3e0a0ddc4f81c3411d565ee814ba1d", "unvendored_tests": true, "version": "0.22.0"}, "river-tests": {"depends": ["river"], "file_name": "river-tests.tar", "imports": [], "install_dir": "site", "name": "river-tests", "package_type": "package", "sha256": "5a8ed77f166bf3cc734357e7a46d62734b4a4f32ba1fff3b5bcd8b3b3be3d40e", "unvendored_tests": false, "version": "0.22.0"}, "robotraconteur": {"depends": ["numpy"], "file_name": "robotraconteur-1.2.7-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["RobotRaconteur"], "install_dir": "site", "name": "RobotRaconteur", "package_type": "package", "sha256": "c5db05398decbe001a3925aece63caebcc52f98ab9e01cc5da6dbe3c102f64a7", "unvendored_tests": false, "version": "1.2.7"}, "rpds-py": {"depends": [], "file_name": "rpds_py-0.30.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["rpds"], "install_dir": "site", "name": "rpds-py", "package_type": "package", "sha256": "8e7918c617cc077fcb0d110f9d9d6511466958f9c095810be1f72760a63bfc2f", "unvendored_tests": false, "version": "0.30.0"}, "ruamel-yaml": {"depends": [], "file_name": "ruamel.yaml-0.18.10-py3-none-any.whl", "imports": ["ruamel"], "install_dir": "site", "name": "ruamel.yaml", "package_type": "package", "sha256": "d998c5c7ebae7eec165a0611f587e4789a7d8b00e1440b569c0abf7613208bda", "unvendored_tests": false, "version": "0.18.10"}, "rustworkx": {"depends": [], "file_name": "rustworkx-0.17.1-cp39-abi3-pyodide_2025_0_wasm32.whl", "imports": ["rustworkx"], "install_dir": "site", "name": "rustworkx", "package_type": "package", "sha256": "78b2e4036cc324f834b556d1e68091dda66e7304adc924b484be76778cac71ac", "unvendored_tests": false, "version": "0.17.1"}, "scikit-image": {"depends": ["packaging", "numpy", "scipy", "networkx", "pillow", "imageio", "pywavelets", "lazy_loader"], "file_name": "scikit_image-0.25.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["skimage"], "install_dir": "site", "name": "scikit-image", "package_type": "package", "sha256": "351b08daac16153c6c9a4ae5c03ee57e622e426685f3aad27b7e3bd8731e5795", "unvendored_tests": true, "version": "0.25.2"}, "scikit-image-tests": {"depends": ["scikit-image"], "file_name": "scikit-image-tests.tar", "imports": [], "install_dir": "site", "name": "scikit-image-tests", "package_type": "package", "sha256": "faf95457c2f1eb47a7ff4027f0ba9fe0c93a4fa386797c956d9f432d6ad69aad", "unvendored_tests": false, "version": "0.25.2"}, "scikit-learn": {"depends": ["scipy", "joblib", "threadpoolctl"], "file_name": "scikit_learn-1.7.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["sklearn"], "install_dir": "site", "name": "scikit-learn", "package_type": "package", "sha256": "267a184f7d3c2cd236a17d729b0f62993c581337b40ee7f99f00e0598dfdb5c2", "unvendored_tests": true, "version": "1.7.0"}, "scikit-learn-tests": {"depends": ["scikit-learn"], "file_name": "scikit-learn-tests.tar", "imports": [], "install_dir": "site", "name": "scikit-learn-tests", "package_type": "package", "sha256": "fdc657b4da1d4d1001a1f4fe6bdcf89552fa3c13a29d66dc766e208cdec3f89f", "unvendored_tests": false, "version": "1.7.0"}, "scipy": {"depends": ["numpy", "libopenblas"], "file_name": "scipy-1.14.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["scipy"], "install_dir": "site", "name": "scipy", "package_type": "package", "sha256": "96fbc718e81cf54ac7df7d8a2c24e370fa3c45086e917c3d58752207d85d21af", "unvendored_tests": true, "version": "1.14.1"}, "scipy-tests": {"depends": ["scipy"], "file_name": "scipy-tests.tar", "imports": [], "install_dir": "site", "name": "scipy-tests", "package_type": "package", "sha256": "0a079ec3481ab936db3e1e243ed4c68e08b797e31e46b76e112f72ef9ae2966a", "unvendored_tests": false, "version": "1.14.1"}, "screed": {"depends": [], "file_name": "screed-1.1.3-py2.py3-none-any.whl", "imports": ["bigtests", "screed"], "install_dir": "site", "name": "screed", "package_type": "package", "sha256": "3d1988cc70a893999774f244a17bfebca33ea7ec5fc4b7297147d36d4b9accca", "unvendored_tests": true, "version": "1.1.3"}, "screed-tests": {"depends": ["screed"], "file_name": "screed-tests.tar", "imports": [], "install_dir": "site", "name": "screed-tests", "package_type": "package", "sha256": "328b604d4feb15aa7470eaa32743cdc83f4f9b7f290fff9e1a8d54535e650685", "unvendored_tests": false, "version": "1.1.3"}, "setuptools": {"depends": ["pyparsing"], "file_name": "setuptools-76.0.0-py3-none-any.whl", "imports": ["_distutils_hack", "pkg_resources", "setuptools"], "install_dir": "site", "name": "setuptools", "package_type": "package", "sha256": "0ffe3d7fd6b219b68fd0c67a450a44e3a19e2d2d9e751e4333430af27c6d89e5", "unvendored_tests": true, "version": "76.0.0"}, "setuptools-tests": {"depends": ["setuptools"], "file_name": "setuptools-tests.tar", "imports": [], "install_dir": "site", "name": "setuptools-tests", "package_type": "package", "sha256": "7ab7cdf90ac2479ccbb79c44ec7fd7d5bd3957fa3ba23835db8ee36236937d15", "unvendored_tests": false, "version": "76.0.0"}, "shapely": {"depends": ["numpy"], "file_name": "shapely-2.0.7-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["shapely"], "install_dir": "site", "name": "shapely", "package_type": "package", "sha256": "3c14600713a254d407c92bccd2d8c679b23296ac1aacb69556cf1d5352d71f6c", "unvendored_tests": true, "version": "2.0.7"}, "shapely-tests": {"depends": ["shapely"], "file_name": "shapely-tests.tar", "imports": [], "install_dir": "site", "name": "shapely-tests", "package_type": "package", "sha256": "afab739c87044873a38c6f97b82389c21f8f12e2f02689dab750e107aaf9a441", "unvendored_tests": false, "version": "2.0.7"}, "simplejson": {"depends": [], "file_name": "simplejson-3.20.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["simplejson"], "install_dir": "site", "name": "simplejson", "package_type": "package", "sha256": "8e3741f95687da2574ca9c48e088035b1d52ff00cfb2956e30672993ecb8aeb6", "unvendored_tests": true, "version": "3.20.1"}, "simplejson-tests": {"depends": ["simplejson"], "file_name": "simplejson-tests.tar", "imports": [], "install_dir": "site", "name": "simplejson-tests", "package_type": "package", "sha256": "ecc18b83ce5779a6f33699ecd1fa3b1c7f336a5aab7d4bb6983cfc945c442f57", "unvendored_tests": false, "version": "3.20.1"}, "sisl": {"depends": ["pyparsing", "numpy", "scipy", "tqdm", "xarray", "pandas", "matplotlib"], "file_name": "sisl-0.16.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["sisl_toolbox", "sisl"], "install_dir": "site", "name": "sisl", "package_type": "package", "sha256": "b284861007e8912e67ed650789e50bb9585a335b0cbe183ee26dfb9c80a3b2fa", "unvendored_tests": true, "version": "0.16.2"}, "sisl-tests": {"depends": ["sisl"], "file_name": "sisl-tests.tar", "imports": [], "install_dir": "site", "name": "sisl-tests", "package_type": "package", "sha256": "4d31452b286130d79c0a81848136ed10f503497275f9b6822d711fb0f04ced5e", "unvendored_tests": false, "version": "0.16.2"}, "six": {"depends": [], "file_name": "six-1.17.0-py2.py3-none-any.whl", "imports": ["six"], "install_dir": "site", "name": "six", "package_type": "package", "sha256": "1f715fc699e802b31e53290ead6c16a4d6a8da462a225d2e06097fce45ab70b9", "unvendored_tests": false, "version": "1.17.0"}, "smart-open": {"depends": ["wrapt"], "file_name": "smart_open-7.1.0-py3-none-any.whl", "imports": ["smart_open"], "install_dir": "site", "name": "smart-open", "package_type": "package", "sha256": "dc5beecb15b4857d05e4fab6382349e0545ed156df6cc255c3b785459ca77af3", "unvendored_tests": false, "version": "7.1.0"}, "sniffio": {"depends": [], "file_name": "sniffio-1.3.1-py3-none-any.whl", "imports": ["sniffio"], "install_dir": "site", "name": "sniffio", "package_type": "package", "sha256": "0077e1685d430cd50f6413af1ed209bb03c95da589ef4f1b8426d67c6b02cb4a", "unvendored_tests": true, "version": "1.3.1"}, "sniffio-tests": {"depends": ["sniffio"], "file_name": "sniffio-tests.tar", "imports": [], "install_dir": "site", "name": "sniffio-tests", "package_type": "package", "sha256": "240d53b95a77a72c309d4279c31f93a5be3ce0a15cb7c92a8f2ac1b9df346bfb", "unvendored_tests": false, "version": "1.3.1"}, "sortedcontainers": {"depends": [], "file_name": "sortedcontainers-2.4.0-py2.py3-none-any.whl", "imports": ["sortedcontainers"], "install_dir": "site", "name": "sortedcontainers", "package_type": "package", "sha256": "8f9018394f1e1c1c98c8744b94d224c990f5090747e2a4c42ac2ca13ae9435ac", "unvendored_tests": false, "version": "2.4.0"}, "soundfile": {"depends": ["cffi", "numpy"], "file_name": "soundfile-0.12.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["soundfile"], "install_dir": "site", "name": "soundfile", "package_type": "package", "sha256": "abe68fea5610c352dc5fb635f5f1af379f9a6c15bb7c0ede5dfe9c1313c65764", "unvendored_tests": false, "version": "0.12.1"}, "soupsieve": {"depends": [], "file_name": "soupsieve-2.6-py3-none-any.whl", "imports": ["soupsieve"], "install_dir": "site", "name": "soupsieve", "package_type": "package", "sha256": "7e7e36183777bcbc525ee458fa8c39853615b7a94d80c38b944e5824bdaf5a78", "unvendored_tests": false, "version": "2.6"}, "sourmash": {"depends": ["screed", "cffi", "deprecation", "cachetools", "numpy", "matplotlib", "scipy", "sqlite3", "bitstring"], "file_name": "sourmash-4.8.14-py3-none-pyodide_2025_0_wasm32.whl", "imports": ["sourmash"], "install_dir": "site", "name": "sourmash", "package_type": "package", "sha256": "72dab96fd65d0afa9137be9255f00804def5cdf2ce89fd0d04a01cc157cb91dc", "unvendored_tests": false, "version": "4.8.14"}, "soxr": {"depends": ["numpy"], "file_name": "soxr-0.5.0.post1-cp312-abi3-pyodide_2025_0_wasm32.whl", "imports": ["soxr"], "install_dir": "site", "name": "soxr", "package_type": "package", "sha256": "54ecac0c40457de53cf5683d47cddaa8aab607f14c5df7b64b8399d20a4b6470", "unvendored_tests": false, "version": "0.5.0.post1"}, "sparseqr": {"depends": ["pycparser", "cffi", "numpy", "scipy", "libsuitesparse"], "file_name": "sparseqr-1.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["sparseqr"], "install_dir": "site", "name": "sparseqr", "package_type": "package", "sha256": "6f89e5c0d9593244e7a08573f19173f370687135f983e2d7abc9ee7d52e1142e", "unvendored_tests": false, "version": "1.2"}, "sqlalchemy": {"depends": ["sqlite3", "typing-extensions"], "file_name": "sqlalchemy-2.0.39-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["sqlalchemy"], "install_dir": "site", "name": "sqlalchemy", "package_type": "package", "sha256": "165fe298a753acdaa860c8167ef39bf31ab590423d91f634d58181b2abcd85af", "unvendored_tests": true, "version": "2.0.39"}, "sqlalchemy-tests": {"depends": ["sqlalchemy"], "file_name": "sqlalchemy-tests.tar", "imports": [], "install_dir": "site", "name": "sqlalchemy-tests", "package_type": "package", "sha256": "31df12d9cc2a92e803a92320e1b27aa65cc56c8d4a59f66cf0fd70fe5a2be6c1", "unvendored_tests": false, "version": "2.0.39"}, "sqlite3": {"depends": [], "file_name": "sqlite3-1.0.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["sqlite3", "_sqlite3"], "install_dir": "site", "name": "sqlite3", "package_type": "cpython_module", "sha256": "aab7214b987a3803fca283a8221e4b9d3274abc05d0cf506ea1a2ae7e09e3bf0", "unvendored_tests": false, "version": "1.0.0"}, "ssl": {"depends": ["libopenssl"], "file_name": "ssl-1.0.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["ssl", "_ssl"], "install_dir": "site", "name": "ssl", "package_type": "cpython_module", "sha256": "23a3fe862983d6798a51a0a63ac55356891751084927a7bde979dc4d6d52e0b5", "unvendored_tests": false, "version": "1.0.0"}, "stack-data": {"depends": ["executing", "asttokens", "pure-eval"], "file_name": "stack_data-0.6.3-py3-none-any.whl", "imports": ["stack_data"], "install_dir": "site", "name": "stack-data", "package_type": "package", "sha256": "b31a4062c2fed35479587fad00b74a23e105acc51a42d68e76a9ab6ed134ac25", "unvendored_tests": false, "version": "0.6.3"}, "starlette": {"depends": [], "file_name": "starlette-0.47.2-py3-none-any.whl", "imports": ["starlette"], "install_dir": "site", "name": "starlette", "package_type": "package", "sha256": "8ae10ca3b4f3e2f58593bd18a8f58df0193aac10f1922dd6c8a0d4b7a95db470", "unvendored_tests": false, "version": "0.47.2"}, "statsmodels": {"depends": ["numpy", "scipy", "pandas", "patsy", "packaging"], "file_name": "statsmodels-0.14.4-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["statsmodels"], "install_dir": "site", "name": "statsmodels", "package_type": "package", "sha256": "0a6387e6e2b0774dc76abd05c3f9a17e0f45233574a9c9e5f0dbeaca3e5a1df6", "unvendored_tests": false, "version": "0.14.4"}, "strictyaml": {"depends": ["python-dateutil"], "file_name": "strictyaml-1.7.3-py3-none-any.whl", "imports": ["strictyaml"], "install_dir": "site", "name": "strictyaml", "package_type": "package", "sha256": "567ddc1f5cecbec407bd01e97e4fbc3a973e1fbf32fb80f83f25741184cbaa6a", "unvendored_tests": false, "version": "1.7.3"}, "svgwrite": {"depends": [], "file_name": "svgwrite-1.4.3-py3-none-any.whl", "imports": ["svgwrite"], "install_dir": "site", "name": "svgwrite", "package_type": "package", "sha256": "92cd1c63bb36ced6abb09edadcde53276cce95b9a8c65b2d7e5e45fb7a4cf79c", "unvendored_tests": false, "version": "1.4.3"}, "swiglpk": {"depends": [], "file_name": "swiglpk-5.0.12-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["swiglpk"], "install_dir": "site", "name": "swiglpk", "package_type": "package", "sha256": "3e4fef0f9ba61ecdea0f46ab70d191fc12537303a5526fbb1717c368d1bcca24", "unvendored_tests": false, "version": "5.0.12"}, "sympy": {"depends": ["mpmath"], "file_name": "sympy-1.13.3-py3-none-any.whl", "imports": ["isympy", "sympy"], "install_dir": "site", "name": "sympy", "package_type": "package", "sha256": "56d438f823c08b2a08231400dcf1f640374192d7b1df0f55c4171bd708227b5f", "unvendored_tests": true, "version": "1.13.3"}, "sympy-tests": {"depends": ["sympy"], "file_name": "sympy-tests.tar", "imports": [], "install_dir": "site", "name": "sympy-tests", "package_type": "package", "sha256": "4d596bf4fdfe9badeea05c0a6f2baa6d5a5f903b32988834d7654e4e88f9bc68", "unvendored_tests": false, "version": "1.13.3"}, "tblib": {"depends": [], "file_name": "tblib-3.0.0-py3-none-any.whl", "imports": ["tblib"], "install_dir": "site", "name": "tblib", "package_type": "package", "sha256": "1d575165bedd73188f1ba98acaadff02cc3b1631406373130596b00ba00013dd", "unvendored_tests": false, "version": "3.0.0"}, "termcolor": {"depends": [], "file_name": "termcolor-2.5.0-py3-none-any.whl", "imports": ["termcolor"], "install_dir": "site", "name": "termcolor", "package_type": "package", "sha256": "fd0dbfea276e782e04fcc39c1a2352ab49d59a0533edd4b9ef248d68d4b6a0c6", "unvendored_tests": false, "version": "2.5.0"}, "test": {"depends": [], "file_name": "test-1.0.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["test"], "install_dir": "site", "name": "test", "package_type": "cpython_module", "sha256": "a12dc1785efa8f2ec03fbc0388f76e066f2dfa78f1ffcce1d31167619a1c94c5", "unvendored_tests": false, "version": "1.0.0"}, "texttable": {"depends": [], "file_name": "texttable-1.7.0-py2.py3-none-any.whl", "imports": ["texttable"], "install_dir": "site", "name": "texttable", "package_type": "package", "sha256": "044ee958dd8ba0c7863f17af1d888f6296d69dc1248230becf8b016ca208fa31", "unvendored_tests": false, "version": "1.7.0"}, "texture2ddecoder": {"depends": [], "file_name": "texture2ddecoder-1.0.5-cp37-abi3-pyodide_2025_0_wasm32.whl", "imports": ["texture2ddecoder"], "install_dir": "site", "name": "texture2ddecoder", "package_type": "package", "sha256": "faf296ba14ffc078255809ecbc67592f40f8fff8d2a9bc0209e72da138d6ad88", "unvendored_tests": false, "version": "1.0.5"}, "threadpoolctl": {"depends": [], "file_name": "threadpoolctl-3.5.0-py3-none-any.whl", "imports": ["threadpoolctl"], "install_dir": "site", "name": "threadpoolctl", "package_type": "package", "sha256": "a6c097ecbc46c97610e6fdf44e270d6cdc07fa5291b24db0e3d2427ee15c3478", "unvendored_tests": false, "version": "3.5.0"}, "tiktoken": {"depends": ["regex", "requests"], "file_name": "tiktoken-0.9.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["tiktoken", "tiktoken_ext"], "install_dir": "site", "name": "tiktoken", "package_type": "package", "sha256": "5d634abc439080560224fdf27d5fd94a5c4c0b8b7c9084fa1fb4305bc68aed4d", "unvendored_tests": false, "version": "0.9.0"}, "tomli": {"depends": [], "file_name": "tomli-2.2.1-py3-none-any.whl", "imports": ["tomli"], "install_dir": "site", "name": "tomli", "package_type": "package", "sha256": "6c3495c050cb288e13416c75511cb81aed241f5ebd40e637bd7ab02ede8069d4", "unvendored_tests": false, "version": "2.2.1"}, "tomli-w": {"depends": [], "file_name": "tomli_w-1.2.0-py3-none-any.whl", "imports": ["tomli_w"], "install_dir": "site", "name": "tomli-w", "package_type": "package", "sha256": "c68058a9596e616e6bbc2b8e6540b66973975b224f8d741d0b9ab170ce2ed23b", "unvendored_tests": false, "version": "1.2.0"}, "toolz": {"depends": [], "file_name": "toolz-1.0.0-py3-none-any.whl", "imports": ["tlz", "toolz"], "install_dir": "site", "name": "toolz", "package_type": "package", "sha256": "967d0d799a872dd03bc3247fa2e2da1e6451a5237f0d68963cc03e644c348e3e", "unvendored_tests": true, "version": "1.0.0"}, "toolz-tests": {"depends": ["toolz"], "file_name": "toolz-tests.tar", "imports": [], "install_dir": "site", "name": "toolz-tests", "package_type": "package", "sha256": "ed4e7ee95cda60c212d3db55dc531a0ec46aa6786fca9f56b777551666f053f6", "unvendored_tests": false, "version": "1.0.0"}, "tqdm": {"depends": [], "file_name": "tqdm-4.67.1-py3-none-any.whl", "imports": ["tqdm"], "install_dir": "site", "name": "tqdm", "package_type": "package", "sha256": "006b436ee31e705b222d855b36a78b3760adfb31d0be1fc75da70c8f4f0834e7", "unvendored_tests": false, "version": "4.67.1"}, "traitlets": {"depends": [], "file_name": "traitlets-5.14.3-py3-none-any.whl", "imports": ["traitlets"], "install_dir": "site", "name": "traitlets", "package_type": "package", "sha256": "81d9fb14245aedf572b78b15c33480c67e7c4070f9cfd7732bb85d702a875629", "unvendored_tests": true, "version": "5.14.3"}, "traitlets-tests": {"depends": ["traitlets"], "file_name": "traitlets-tests.tar", "imports": [], "install_dir": "site", "name": "traitlets-tests", "package_type": "package", "sha256": "a3197b5e3dfc8db00b0529032cdbf4e627a43a8f93560366062b11e0d8117f0c", "unvendored_tests": false, "version": "5.14.3"}, "traits": {"depends": [], "file_name": "traits-7.0.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["traits"], "install_dir": "site", "name": "traits", "package_type": "package", "sha256": "018e5d5a728367b6b00d3b8ec75721de8dde7ff34cc6c1ba004e5b55bce26315", "unvendored_tests": true, "version": "7.0.2"}, "traits-tests": {"depends": ["traits"], "file_name": "traits-tests.tar", "imports": [], "install_dir": "site", "name": "traits-tests", "package_type": "package", "sha256": "c6df8d68fb079caa60b654338fdf43e2f5aadcd351e811a1c81616e7ac26c4e8", "unvendored_tests": false, "version": "7.0.2"}, "tree-sitter": {"depends": [], "file_name": "tree_sitter-0.23.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["tree_sitter"], "install_dir": "site", "name": "tree-sitter", "package_type": "package", "sha256": "bfc7f18af606c82dbc48ad4e027df691c0093cb147c6147535a6c2c625cb1f65", "unvendored_tests": false, "version": "0.23.2"}, "tree-sitter-go": {"depends": ["tree-sitter"], "file_name": "tree_sitter_go-0.23.3-cp39-abi3-pyodide_2025_0_wasm32.whl", "imports": ["tree_sitter_go"], "install_dir": "site", "name": "tree-sitter-go", "package_type": "package", "sha256": "efd2b3c3e2e91520d7f901c5848ec3be9c31f2ed30aa0ec93a6434e906b6ce6f", "unvendored_tests": false, "version": "0.23.3"}, "tree-sitter-java": {"depends": ["tree-sitter"], "file_name": "tree_sitter_java-0.23.4-cp39-abi3-pyodide_2025_0_wasm32.whl", "imports": ["tree_sitter_java"], "install_dir": "site", "name": "tree-sitter-java", "package_type": "package", "sha256": "3cb99f96ef340f9b62d84f54dd087a47df357528bf18c99f58f6cc25ba3c5342", "unvendored_tests": false, "version": "0.23.4"}, "tree-sitter-python": {"depends": ["tree-sitter"], "file_name": "tree_sitter_python-0.23.4-cp39-abi3-pyodide_2025_0_wasm32.whl", "imports": ["tree_sitter_python"], "install_dir": "site", "name": "tree-sitter-python", "package_type": "package", "sha256": "4a92f239f1e83121f18908ec5f8d4047cfec71a6d828813fe6a9b7c1bcd735b0", "unvendored_tests": false, "version": "0.23.4"}, "tskit": {"depends": ["numpy", "jsonschema", "rpds-py"], "file_name": "tskit-1.0.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["tskit"], "install_dir": "site", "name": "tskit", "package_type": "package", "sha256": "f7e8a5c0b5171018bc7172e6b53f4184139afde97fa12350e580a42f7a544e3d", "unvendored_tests": false, "version": "1.0.0"}, "typing-extensions": {"depends": [], "file_name": "typing_extensions-4.15.0-py3-none-any.whl", "imports": ["typing_extensions"], "install_dir": "site", "name": "typing-extensions", "package_type": "package", "sha256": "b57583f623dd3df72e6ace8a4061c3e4f0683755165ef73b4cd44ac3df92ddb9", "unvendored_tests": false, "version": "4.15.0"}, "typing-inspection": {"depends": [], "file_name": "typing_inspection-0.4.2-py3-none-any.whl", "imports": ["typing_inspection"], "install_dir": "site", "name": "typing-inspection", "package_type": "package", "sha256": "5c4d0bade04cec6ac0d03c227c8bdb7c59218e4c6d759b5ac0cea5c34f6a72aa", "unvendored_tests": false, "version": "0.4.2"}, "tzdata": {"depends": [], "file_name": "tzdata-2025.3-py2.py3-none-any.whl", "imports": ["tzdata"], "install_dir": "site", "name": "tzdata", "package_type": "package", "sha256": "39db9ad12044be29b71e3ab24b905956fca75ae6fb25f9bc2062043c293d0f50", "unvendored_tests": false, "version": "2025.3"}, "ujson": {"depends": [], "file_name": "ujson-5.11.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["ujson"], "install_dir": "site", "name": "ujson", "package_type": "package", "sha256": "e9e8e11ebb2f314db428661fe635fe44af8bb9740f44847f3c60510e21b7b0c0", "unvendored_tests": false, "version": "5.11.0"}, "uncertainties": {"depends": ["future"], "file_name": "uncertainties-3.2.2-py3-none-any.whl", "imports": ["uncertainties"], "install_dir": "site", "name": "uncertainties", "package_type": "package", "sha256": "0abeeb1832fb157815a5c11b6b1fc83ed29304044df77959873fe621d3ffd6ed", "unvendored_tests": false, "version": "3.2.2"}, "unyt": {"depends": ["numpy", "packaging", "sympy"], "file_name": "unyt-3.0.3-py3-none-any.whl", "imports": ["unyt"], "install_dir": "site", "name": "unyt", "package_type": "package", "sha256": "ecf3b23f3cec33e7edd09477b267862274b06c7044341b2ae62c83422dad49e7", "unvendored_tests": true, "version": "3.0.3"}, "unyt-tests": {"depends": ["unyt"], "file_name": "unyt-tests.tar", "imports": [], "install_dir": "site", "name": "unyt-tests", "package_type": "package", "sha256": "8ab10030c32bd8f159dd871d290d0e41203197392cf25f5e98ba0e2b0e5d9d64", "unvendored_tests": false, "version": "3.0.3"}, "urllib3": {"depends": [], "file_name": "urllib3-2.5.0-py3-none-any.whl", "imports": ["urllib3"], "install_dir": "site", "name": "urllib3", "package_type": "package", "sha256": "ae930887b25087f9ba80e06d57b22c7c047c0d5db3fca3df6e932cdebbb77ad6", "unvendored_tests": false, "version": "2.5.0"}, "vega-datasets": {"depends": ["pandas"], "file_name": "vega_datasets-0.9.0-py3-none-any.whl", "imports": ["vega_datasets"], "install_dir": "site", "name": "vega-datasets", "package_type": "package", "sha256": "f6c66410b3fe2b8b65ad62c99ea7251eba29b352fd84c1aceec86c511a325f3c", "unvendored_tests": true, "version": "0.9.0"}, "vega-datasets-tests": {"depends": ["vega-datasets"], "file_name": "vega-datasets-tests.tar", "imports": [], "install_dir": "site", "name": "vega-datasets-tests", "package_type": "package", "sha256": "2d4c7ecccbb7bbb037a02da795d5c9a6ad9f0e655f2fce63d34b2c928c72b63d", "unvendored_tests": false, "version": "0.9.0"}, "vrplib": {"depends": ["numpy"], "file_name": "vrplib-2.0.1-py3-none-any.whl", "imports": ["vrplib"], "install_dir": "site", "name": "vrplib", "package_type": "package", "sha256": "1cbe88b6ffc6d7f25b4a7b1ed3bc363126cef615498dd4a1e689e89ebacd16b0", "unvendored_tests": false, "version": "2.0.1"}, "wcwidth": {"depends": [], "file_name": "wcwidth-0.2.13-py2.py3-none-any.whl", "imports": ["wcwidth"], "install_dir": "site", "name": "wcwidth", "package_type": "package", "sha256": "5aea2ced9398448b2807b68a484586aeb5c91cac95a634acf39e2300ad9847c8", "unvendored_tests": false, "version": "0.2.13"}, "webencodings": {"depends": [], "file_name": "webencodings-0.5.1-py2.py3-none-any.whl", "imports": ["webencodings"], "install_dir": "site", "name": "webencodings", "package_type": "package", "sha256": "a0a893e9e174cf99d91b2750287735a5273678c0bdb9acf9708b567207a5c14a", "unvendored_tests": false, "version": "0.5.1"}, "wordcloud": {"depends": ["matplotlib"], "file_name": "wordcloud-1.9.4-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["wordcloud"], "install_dir": "site", "name": "wordcloud", "package_type": "package", "sha256": "35b1a40bf00e29e8b14fa9a43047f4fbea82dabeddfa3cb0b517c1833b4f0836", "unvendored_tests": false, "version": "1.9.4"}, "wrapt": {"depends": [], "file_name": "wrapt-1.17.2-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["wrapt"], "install_dir": "site", "name": "wrapt", "package_type": "package", "sha256": "00dc226b5b1af067344049c90e4ac1805dc7dd8fb4bea71940a8e801b7f18706", "unvendored_tests": false, "version": "1.17.2"}, "xarray": {"depends": ["numpy", "packaging", "pandas"], "file_name": "xarray-2025.12.0-py3-none-any.whl", "imports": ["xarray"], "install_dir": "site", "name": "xarray", "package_type": "package", "sha256": "c2cfc5a4c2f4761799048730b953b12417c4ed5d112c71c0e8918636713c4b5b", "unvendored_tests": true, "version": "2025.12.0"}, "xarray-tests": {"depends": ["xarray"], "file_name": "xarray-tests.tar", "imports": [], "install_dir": "site", "name": "xarray-tests", "package_type": "package", "sha256": "d88594de4f27ca72812cdb4f237ff769b091d40481ef45d2f044050d04972bc3", "unvendored_tests": false, "version": "2025.12.0"}, "xgboost": {"depends": ["numpy", "scipy", "setuptools"], "file_name": "xgboost-2.1.4-py3-none-pyodide_2025_0_wasm32.whl", "imports": ["xgboost"], "install_dir": "site", "name": "xgboost", "package_type": "package", "sha256": "35e2a5898b84ee763b93144fc7906c7fe72c2a45b28833f57d0ae5a27742c93f", "unvendored_tests": false, "version": "2.1.4"}, "xlrd": {"depends": [], "file_name": "xlrd-2.0.1-py2.py3-none-any.whl", "imports": ["xlrd"], "install_dir": "site", "name": "xlrd", "package_type": "package", "sha256": "2872cbcef5a5df3a5cc547aaebdd0ffe5256c3e79d817f3be69574350faf1090", "unvendored_tests": false, "version": "2.0.1"}, "xxhash": {"depends": [], "file_name": "xxhash-3.5.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["xxhash"], "install_dir": "site", "name": "xxhash", "package_type": "package", "sha256": "2ce8ffb702fb7d67520de4c81c111a3475b2615cab0614969f44dd6aade3878a", "unvendored_tests": false, "version": "3.5.0"}, "xyzservices": {"depends": [], "file_name": "xyzservices-2025.1.0-py3-none-any.whl", "imports": ["xyzservices"], "install_dir": "site", "name": "xyzservices", "package_type": "package", "sha256": "26daed3f653ba211516d70b3634e74be7a86e801bee481840ebc6d4fa841cd0d", "unvendored_tests": true, "version": "2025.1.0"}, "xyzservices-tests": {"depends": ["xyzservices"], "file_name": "xyzservices-tests.tar", "imports": [], "install_dir": "site", "name": "xyzservices-tests", "package_type": "package", "sha256": "660c4cc829acd35aecab7aaa293e76fa0d8cb8ac9fdcb7c548a5ae44a1a26fd1", "unvendored_tests": false, "version": "2025.1.0"}, "yarl": {"depends": ["multidict", "idna", "propcache"], "file_name": "yarl-1.18.3-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["yarl"], "install_dir": "site", "name": "yarl", "package_type": "package", "sha256": "0ede8d5eb487bae5b75729d78829bd3d86ff08efa30c020fe71a3213e9df25ec", "unvendored_tests": false, "version": "1.18.3"}, "yt": {"depends": ["ewah_bool_utils", "numpy", "matplotlib", "sympy", "setuptools", "packaging", "unyt", "cmyt", "colorspacious", "tqdm", "tomli", "tomli-w"], "file_name": "yt-4.4.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["yt"], "install_dir": "site", "name": "yt", "package_type": "package", "sha256": "f9537bb9b17b74eb53bf97f4e9e7fa7a808d71ec3d45403e96c447eb623b6eef", "unvendored_tests": false, "version": "4.4.0"}, "zengl": {"depends": [], "file_name": "zengl-2.7.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["zengl", "_zengl"], "install_dir": "site", "name": "zengl", "package_type": "package", "sha256": "1ea96005955b706cc28057be6df05e3ef00e78e4a2683595cdfac56a68ebbe5e", "unvendored_tests": false, "version": "2.7.1"}, "zfpy": {"depends": ["numpy"], "file_name": "zfpy-1.0.1-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["zfpy"], "install_dir": "site", "name": "zfpy", "package_type": "package", "sha256": "a402cd384e7c32bb78c486fb7201a990a3b550b5fe57ab440b3fd8fc721249f1", "unvendored_tests": false, "version": "1.0.1"}, "zstandard": {"depends": ["cffi"], "file_name": "zstandard-0.23.0-cp313-cp313-pyodide_2025_0_wasm32.whl", "imports": ["zstandard"], "install_dir": "site", "name": "zstandard", "package_type": "package", "sha256": "c365a307b01175281bd2d0d56d0092c4f0c97cdc8273e029d01dc4cabbc77fa1", "unvendored_tests": false, "version": "0.23.0"}}} \ No newline at end of file diff --git a/crates/execution/assets/pyodide/pyodide.asm.js b/crates/execution/assets/pyodide/pyodide.asm.js deleted file mode 100644 index 1ff17f7ba..000000000 --- a/crates/execution/assets/pyodide/pyodide.asm.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -var _createPyodideModule = (() => { - var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; - return ( -async function(moduleArg = {}) { - var moduleRtn; - -var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof WorkerGlobalScope!="undefined";var ENVIRONMENT_IS_NODE=typeof process=="object"&&process.versions?.node&&process.type!="renderer";var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){}var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};if(typeof __filename!="undefined"){_scriptName=__filename}else if(ENVIRONMENT_IS_WORKER){_scriptName=self.location.href}var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_SHELL){readBinary=f=>{if(typeof readbuffer=="function"){return new Uint8Array(readbuffer(f))}let data=read(f,"binary");assert(typeof data=="object");return data};readAsync=async f=>readBinary(f);globalThis.clearTimeout??=id=>{};globalThis.setTimeout??=f=>f();arguments_=globalThis.arguments||globalThis.scriptArgs;if(typeof quit=="function"){quit_=(status,toThrow)=>{setTimeout(()=>{if(!(toThrow instanceof ExitStatus)){let toLog=toThrow;if(toThrow&&typeof toThrow=="object"&&toThrow.stack){toLog=[toThrow,toThrow.stack]}err(`exiting due to exception: ${toLog}`)}quit(status)});throw toThrow}}if(typeof print!="undefined"){globalThis.console??={};console.log=print;console.warn=console.error=globalThis.printErr??print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{if(isFileURI(url)){return new Promise((resolve,reject)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){resolve(xhr.response);return}reject(xhr.status)};xhr.onerror=reject;xhr.send(null)})}var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var dynamicLibraries=[];var wasmBinary;var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var HEAP,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAP64,HEAPU64,HEAPF64;var runtimeInitialized=false;var runtimeExited=false;var isFileURI=filename=>filename.startsWith("file://");function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b);Module["HEAP64"]=HEAP64=new BigInt64Array(b);Module["HEAPU64"]=HEAPU64=new BigUint64Array(b)}function initMemory(){if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||20971520;wasmMemory=new WebAssembly.Memory({initial:INITIAL_MEMORY/65536,maximum:65536})}updateMemoryViews()}var __RELOC_FUNCS__=[];function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__RELOC_FUNCS__);callRuntimeCallbacks(onInits);if(!Module["noFSInit"]&&!FS.initialized)FS.init();TTY.init();SOCKFS.root=FS.mount(SOCKFS,{},null);PIPEFS.root=FS.mount(PIPEFS,{},null);wasmExports["__wasm_call_ctors"]();callRuntimeCallbacks(onPostCtors);FS.ignorePermissions=false}function preMain(){callRuntimeCallbacks(onMains)}function exitRuntime(){___funcs_on_exit();callRuntimeCallbacks(onExits);FS.quit();TTY.shutdown();IDBFS.quit();runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(onPostRuns)}var runDependencies=0;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";if(runtimeInitialized){___trap()}var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var wasmBinaryFile;function findWasmBinary(){return locateFile("pyodide.asm.wasm")}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_SHELL){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){return{env:wasmImports,wasi_snapshot_preview1:wasmImports,"GOT.mem":new Proxy(wasmImports,GOTHandler),"GOT.func":new Proxy(wasmImports,GOTHandler)}}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=relocateExports(wasmExports,1024);var metadata=getDylinkMetadata(module);if(metadata.neededDynlibs){dynamicLibraries=metadata.neededDynlibs.concat(dynamicLibraries)}mergeLibSymbols(wasmExports,"main");LDSO.init();loadDylibs();wasmExports=applySignatureConversions(wasmExports);__RELOC_FUNCS__.push(wasmExports["__wasm_apply_data_relocs"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){return receiveInstance(result["instance"],result["module"])}var info=getWasmImports();if(Module["instantiateWasm"]){return new Promise((resolve,reject)=>{Module["instantiateWasm"](info,(mod,inst)=>{resolve(receiveInstance(mod,inst))})})}wasmBinaryFile??=findWasmBinary();try{var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}catch(e){readyPromiseReject(e);return Promise.reject(e)}}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var GOT={};var currentModuleWeakSymbols=new Set([]);var GOTHandler={get(obj,symName){var rtn=GOT[symName];if(!rtn){rtn=GOT[symName]=new WebAssembly.Global({value:"i32",mutable:true})}if(!currentModuleWeakSymbols.has(symName)){rtn.required=true}return rtn}};var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var addOnPostRun=cb=>onPostRuns.push(cb);var onPreRuns=[];var addOnPreRun=cb=>onPreRuns.push(cb);var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead=NaN)=>{idx>>>=0;var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var getDylinkMetadata=binary=>{var offset=0;var end=0;function getU8(){return binary[offset++]}function getLEB(){var ret=0;var mul=1;while(1){var byte=binary[offset++];ret+=(byte&127)*mul;mul*=128;if(!(byte&128))break}return ret}function getString(){var len=getLEB();offset+=len;return UTF8ArrayToString(binary,offset-len,len)}function getStringList(){var count=getLEB();var rtn=[];while(count--)rtn.push(getString());return rtn}function failIf(condition,message){if(condition)throw new Error(message)}if(binary instanceof WebAssembly.Module){var dylinkSection=WebAssembly.Module.customSections(binary,"dylink.0");failIf(dylinkSection.length===0,"need dylink section");binary=new Uint8Array(dylinkSection[0]);end=binary.length}else{var int32View=new Uint32Array(new Uint8Array(binary.subarray(0,24)).buffer);var magicNumberFound=int32View[0]==1836278016;failIf(!magicNumberFound,"need to see wasm magic number");failIf(binary[8]!==0,"need the dylink section to be first");offset=9;var section_size=getLEB();end=offset+section_size;var name=getString();failIf(name!=="dylink.0")}var customSection={neededDynlibs:[],tlsExports:new Set,weakImports:new Set,runtimePaths:[]};var WASM_DYLINK_MEM_INFO=1;var WASM_DYLINK_NEEDED=2;var WASM_DYLINK_EXPORT_INFO=3;var WASM_DYLINK_IMPORT_INFO=4;var WASM_DYLINK_RUNTIME_PATH=5;var WASM_SYMBOL_TLS=256;var WASM_SYMBOL_BINDING_MASK=3;var WASM_SYMBOL_BINDING_WEAK=1;while(offset>>0];case"i8":return HEAP8[ptr>>>0];case"i16":return HEAP16[ptr>>>1>>>0];case"i32":return HEAP32[ptr>>>2>>>0];case"i64":return HEAP64[ptr>>>3>>>0];case"float":return HEAPF32[ptr>>>2>>>0];case"double":return HEAPF64[ptr>>>3>>>0];case"*":return HEAPU32[ptr>>>2>>>0];default:abort(`invalid type for getValue: ${type}`)}}var newDSO=(name,handle,syms)=>{var dso={refcount:Infinity,name,exports:syms,global:true};LDSO.loadedLibsByName[name]=dso;if(handle!=undefined){LDSO.loadedLibsByHandle[handle]=dso}return dso};var LDSO={loadedLibsByName:{},loadedLibsByHandle:{},init(){newDSO("__main__",0,wasmImports)}};var ___heap_base=8810528;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var getMemory=size=>{if(runtimeInitialized){return _calloc(size,1)}var ret=___heap_base;var end=ret+alignMemory(size,16);___heap_base=end;GOT["__heap_base"].value=end;return ret};var isInternalSym=symName=>["__cpp_exception","__c_longjmp","__wasm_apply_data_relocs","__dso_handle","__tls_size","__tls_align","__set_stack_limits","_emscripten_tls_init","__wasm_init_tls","__wasm_call_ctors","__start_em_asm","__stop_em_asm","__start_em_js","__stop_em_js"].includes(symName)||symName.startsWith("__em_js__");var uleb128Encode=(n,target)=>{if(n<128){target.push(n)}else{target.push(n%128|128,n>>7)}};var sigToWasmTypes=sig=>{var typeNames={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",p:"i32"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i{var sigRet=sig.slice(0,1);var sigParam=sig.slice(1);var typeCodes={i:127,p:127,j:126,f:125,d:124,e:111};target.push(96);uleb128Encode(sigParam.length,target);for(var paramType of sigParam){target.push(typeCodes[paramType])}if(sigRet=="v"){target.push(0)}else{target.push(1,typeCodes[sigRet])}};var convertJsFunctionToWasm=(func,sig)=>{if(typeof WebAssembly.Function=="function"){return new WebAssembly.Function(sigToWasmTypes(sig),func)}var typeSectionBody=[1];generateFuncType(sig,typeSectionBody);var bytes=[0,97,115,109,1,0,0,0,1];uleb128Encode(typeSectionBody.length,bytes);bytes.push(...typeSectionBody);bytes.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);var module=new WebAssembly.Module(new Uint8Array(bytes));var instance=new WebAssembly.Instance(module,{e:{f:func}});var wrappedFunc=instance.exports["f"];return wrappedFunc};var wasmTableMirror=[];var wasmTable=new WebAssembly.Table({initial:6076,element:"anyfunc"});var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};var updateTableMap=(offset,count)=>{if(functionsInTableMap){for(var i=offset;i{if(!functionsInTableMap){functionsInTableMap=new WeakMap;updateTableMap(0,wasmTable.length)}return functionsInTableMap.get(func)||0};var freeTableIndexes=[];var getEmptyTableSlot=()=>{if(freeTableIndexes.length){return freeTableIndexes.pop()}try{wasmTable.grow(1)}catch(err){if(!(err instanceof RangeError)){throw err}throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH."}return wasmTable.length-1};var setWasmTableEntry=(idx,func)=>{wasmTable.set(idx,func);wasmTableMirror[idx]=wasmTable.get(idx)};var addFunction=(func,sig)=>{var rtn=getFunctionAddress(func);if(rtn){return rtn}var ret=getEmptyTableSlot();try{setWasmTableEntry(ret,func)}catch(err){if(!(err instanceof TypeError)){throw err}var wrapped=convertJsFunctionToWasm(func,sig);setWasmTableEntry(ret,wrapped)}functionsInTableMap.set(func,ret);return ret};var updateGOT=(exports,replace)=>{for(var symName in exports){if(isInternalSym(symName)){continue}var value=exports[symName];GOT[symName]||=new WebAssembly.Global({value:"i32",mutable:true});if(replace||GOT[symName].value==0){if(typeof value=="function"){GOT[symName].value=addFunction(value)}else if(typeof value=="number"){GOT[symName].value=value}else{err(`unhandled export type for '${symName}': ${typeof value}`)}}}};var relocateExports=(exports,memoryBase,replace)=>{var relocated={};for(var e in exports){var value=exports[e];if(typeof value=="object"){value=value.value}if(typeof value=="number"){value+=memoryBase}relocated[e]=value}updateGOT(relocated,replace);return relocated};var isSymbolDefined=symName=>{var existing=wasmImports[symName];if(!existing||existing.stub){return false}return true};var resolveGlobalSymbol=(symName,direct=false)=>{var sym;if(isSymbolDefined(symName)){sym=wasmImports[symName]}return{sym,name:symName}};var onPostCtors=[];var addOnPostCtor=cb=>onPostCtors.push(cb);var UTF8ToString=(ptr,maxBytesToRead)=>{ptr>>>=0;return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""};var loadWebAssemblyModule=(binary,flags,libName,localScope,handle)=>{var metadata=getDylinkMetadata(binary);currentModuleWeakSymbols=metadata.weakImports;function loadModule(){var memAlign=Math.pow(2,metadata.memoryAlign);var memoryBase=metadata.memorySize?alignMemory(getMemory(metadata.memorySize+memAlign),memAlign):0;var tableBase=metadata.tableSize?wasmTable.length:0;if(handle){HEAP8[handle+8>>>0]=1;HEAPU32[handle+12>>>2>>>0]=memoryBase;HEAP32[handle+16>>>2>>>0]=metadata.memorySize;HEAPU32[handle+20>>>2>>>0]=tableBase;HEAP32[handle+24>>>2>>>0]=metadata.tableSize}if(metadata.tableSize){wasmTable.grow(metadata.tableSize)}var moduleExports;function resolveSymbol(sym){var resolved=resolveGlobalSymbol(sym).sym;if(!resolved&&localScope){resolved=localScope[sym]}if(!resolved){resolved=moduleExports[sym]}return resolved}var proxyHandler={get(stubs,prop){switch(prop){case"__memory_base":return memoryBase;case"__table_base":return tableBase}if(prop in wasmImports&&!wasmImports[prop].stub){var res=wasmImports[prop];return res}if(!(prop in stubs)){var resolved;stubs[prop]=(...args)=>{resolved||=resolveSymbol(prop);if(!resolved){throw new Error(`Dynamic linking error: cannot resolve symbol ${prop}`)}return resolved(...args)}}return stubs[prop]}};var proxy=new Proxy({},proxyHandler);var info={"GOT.mem":new Proxy({},GOTHandler),"GOT.func":new Proxy({},GOTHandler),env:proxy,wasi_snapshot_preview1:proxy};function postInstantiation(module,instance){updateTableMap(tableBase,metadata.tableSize);moduleExports=relocateExports(instance.exports,memoryBase);if(!flags.allowUndefined){reportUndefinedSymbols()}function addEmAsm(addr,body){var args=[];var arity=0;for(;arity<16;arity++){if(body.indexOf("$"+arity)!=-1){args.push("$"+arity)}else{break}}args=args.join(",");var func=`(${args}) => { ${body} };`;ASM_CONSTS[start]=eval(func)}if("__start_em_asm"in moduleExports){var start=moduleExports["__start_em_asm"];var stop=moduleExports["__stop_em_asm"];while(start ${body};`;moduleExports[name]=eval(func)}for(var name in moduleExports){if(name.startsWith("__em_js__")){var start=moduleExports[name];var jsString=UTF8ToString(start);var parts=jsString.split("<::>");addEmJs(name.replace("__em_js__",""),parts[0],parts[1]);delete moduleExports[name]}}var applyRelocs=moduleExports["__wasm_apply_data_relocs"];if(applyRelocs){if(runtimeInitialized){applyRelocs()}else{__RELOC_FUNCS__.push(applyRelocs)}}var init=moduleExports["__wasm_call_ctors"];if(init){if(runtimeInitialized){init()}else{addOnPostCtor(init)}}return moduleExports}if(flags.loadAsync){return(async()=>{var instance;if(binary instanceof WebAssembly.Module){instance=new WebAssembly.Instance(binary,info)}else{({module:binary,instance}=await WebAssembly.instantiate(binary,info))}return postInstantiation(binary,instance)})()}var module=binary instanceof WebAssembly.Module?binary:new WebAssembly.Module(binary);var instance=new WebAssembly.Instance(module,info);return postInstantiation(module,instance)}flags={...flags,rpath:{parentLibPath:libName,paths:metadata.runtimePaths}};if(flags.loadAsync){return metadata.neededDynlibs.reduce((chain,needed)=>chain.then(()=>{needed=findLibraryFS(needed,flags.rpath)??needed;return loadDynamicLibrary(needed,flags,localScope)}),Promise.resolve()).then(loadModule)}metadata.neededDynlibs.forEach(needed=>{needed=findLibraryFS(needed,flags.rpath)??needed;return loadDynamicLibrary(needed,flags,localScope)});return loadModule()};var mergeLibSymbols=(exports,libName)=>{for(var[sym,exp]of Object.entries(exports)){const setImport=target=>{if(!isSymbolDefined(target)){wasmImports[target]=exp}};setImport(sym);const main_alias="__main_argc_argv";if(sym=="main"){setImport(main_alias)}if(sym==main_alias){setImport("main")}}};var asyncLoad=async url=>{var arrayBuffer=await readAsync(url);return new Uint8Array(arrayBuffer)};var preloadPlugins=[];var registerWasmPlugin=()=>{var wasmPlugin={promiseChainEnd:Promise.resolve(),canHandle:name=>!Module["noWasmDecoding"]&&name.endsWith(".so"),handle:(byteArray,name,onload,onerror)=>{wasmPlugin["promiseChainEnd"]=wasmPlugin["promiseChainEnd"].then(()=>loadWebAssemblyModule(byteArray,{loadAsync:true,nodelete:true},name,{})).then(exports=>{preloadedWasm[name]=exports;onload(byteArray)},error=>{err(`failed to instantiate wasm: ${name}: ${error}`);onerror()})}};preloadPlugins.push(wasmPlugin)};var preloadedWasm={};var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.slice(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.slice(0,-1)}return root+dir},basename:path=>path&&path.match(/([^\/]+|\/)\/*$/)[1],join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var replaceORIGIN=(parentLibName,rpath)=>{if(rpath.startsWith("$ORIGIN")){var origin=PATH.dirname(parentLibName);return rpath.replace("$ORIGIN",origin)}return rpath};var stackSave=()=>_emscripten_stack_get_current();var stackRestore=val=>__emscripten_stack_restore(val);var withStackSave=f=>{var stack=stackSave();var ret=f();stackRestore(stack);return ret};var stackAlloc=sz=>__emscripten_stack_alloc(sz);var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{outIdx>>>=0;if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++>>>0]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++>>>0]=192|u>>6;heap[outIdx++>>>0]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++>>>0]=224|u>>12;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++>>>0]=240|u>>18;heap[outIdx++>>>0]=128|u>>12&63;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}}heap[outIdx>>>0]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var base64Decode=b64=>{if(ENVIRONMENT_IS_NODE){var buf=Buffer.from(b64,"base64");return new Uint8Array(buf.buffer,buf.byteOffset,buf.length)}var b1,b2,i=0,j=0,bLength=b64.length;var output=new Uint8Array((bLength*3>>2)-(b64[bLength-2]=="=")-(b64[bLength-1]=="="));for(;i>4;output[j+1]=b1<<4|b2>>2;output[j+2]=b2<<6|base64ReverseLookup[b64.charCodeAt(i+3)]}return output};var initRandomFill=()=>{if(ENVIRONMENT_IS_NODE){var nodeCrypto=require("crypto");return view=>nodeCrypto.randomFillSync(view)}if(ENVIRONMENT_IS_SHELL){return view=>{if(!os.system){throw new Error("randomFill not supported on d8 unless --enable-os-system is passed")}const b64=os.system("sh",["-c",`head -c${view.byteLength} /dev/urandom | base64 --wrap=0`]);view.set(base64Decode(b64))}}return view=>crypto.getRandomValues(view)};var randomFill=view=>{(randomFill=initRandomFill())(view)};var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).slice(1);to=PATH_FS.resolve(to).slice(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array};var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf,0,BUFSIZE)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output?.length>0){err(UTF8ArrayToString(tty.output));tty.output=[]}}}};var zeroMemory=(ptr,size)=>HEAPU8.fill(0,ptr,ptr+size);var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(ptr)zeroMemory(ptr,size);return ptr};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16895,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.atime=node.mtime=node.ctime=Date.now();if(parent){parent.contents[name]=node;parent.atime=parent.mtime=parent.ctime=node.atime}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.atime);attr.mtime=new Date(node.mtime);attr.ctime=new Date(node.ctime);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){for(const key of["mode","atime","mtime","ctime"]){if(attr[key]!=null){node[key]=attr[key]}}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw MEMFS.doesNotExistError},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){if(FS.isDir(old_node.mode)){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}FS.hashRemoveNode(new_node)}delete old_node.parent.contents[old_node.name];new_dir.contents[new_name]=old_node;old_node.name=new_name;new_dir.ctime=new_dir.mtime=old_node.parent.ctime=old_node.parent.mtime=Date.now()},unlink(parent,name){delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},readdir(node){return[".","..",...Object.keys(node.contents)]},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length>>0)}}return{ptr,allocated}},msync(stream,buffer,offset,length,mmapFlags){MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};var FS_createDataFile=(...args)=>FS.createDataFile(...args);var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url).then(processData,onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var IDBFS={dbs:{},indexedDB:()=>{if(typeof indexedDB!="undefined")return indexedDB;var ret=null;if(typeof window=="object")ret=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;return ret},DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",queuePersist:mount=>{function onPersistComplete(){if(mount.idbPersistState==="again")startPersist();else mount.idbPersistState=0}function startPersist(){mount.idbPersistState="idb";IDBFS.syncfs(mount,false,onPersistComplete)}if(!mount.idbPersistState){mount.idbPersistState=setTimeout(startPersist,0)}else if(mount.idbPersistState==="idb"){mount.idbPersistState="again"}},mount:mount=>{var mnt=MEMFS.mount(mount);if(mount?.opts?.autoPersist){mnt.idbPersistState=0;var memfs_node_ops=mnt.node_ops;mnt.node_ops={...mnt.node_ops};mnt.node_ops.mknod=(parent,name,mode,dev)=>{var node=memfs_node_ops.mknod(parent,name,mode,dev);node.node_ops=mnt.node_ops;node.idbfs_mount=mnt.mount;node.memfs_stream_ops=node.stream_ops;node.stream_ops={...node.stream_ops};node.stream_ops.write=(stream,buffer,offset,length,position,canOwn)=>{stream.node.isModified=true;return node.memfs_stream_ops.write(stream,buffer,offset,length,position,canOwn)};node.stream_ops.close=stream=>{var n=stream.node;if(n.isModified){IDBFS.queuePersist(n.idbfs_mount);n.isModified=false}if(n.memfs_stream_ops.close)return n.memfs_stream_ops.close(stream)};return node};mnt.node_ops.mkdir=(...args)=>(IDBFS.queuePersist(mnt.mount),memfs_node_ops.mkdir(...args));mnt.node_ops.rmdir=(...args)=>(IDBFS.queuePersist(mnt.mount),memfs_node_ops.rmdir(...args));mnt.node_ops.symlink=(...args)=>(IDBFS.queuePersist(mnt.mount),memfs_node_ops.symlink(...args));mnt.node_ops.unlink=(...args)=>(IDBFS.queuePersist(mnt.mount),memfs_node_ops.unlink(...args));mnt.node_ops.rename=(...args)=>(IDBFS.queuePersist(mnt.mount),memfs_node_ops.rename(...args))}return mnt},syncfs:(mount,populate,callback)=>{IDBFS.getLocalSet(mount,(err,local)=>{if(err)return callback(err);IDBFS.getRemoteSet(mount,(err,remote)=>{if(err)return callback(err);var src=populate?remote:local;var dst=populate?local:remote;IDBFS.reconcile(src,dst,callback)})})},quit:()=>{Object.values(IDBFS.dbs).forEach(value=>value.close());IDBFS.dbs={}},getDB:(name,callback)=>{var db=IDBFS.dbs[name];if(db){return callback(null,db)}var req;try{req=IDBFS.indexedDB().open(name,IDBFS.DB_VERSION)}catch(e){return callback(e)}if(!req){return callback("Unable to connect to IndexedDB")}req.onupgradeneeded=e=>{var db=e.target.result;var transaction=e.target.transaction;var fileStore;if(db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)){fileStore=transaction.objectStore(IDBFS.DB_STORE_NAME)}else{fileStore=db.createObjectStore(IDBFS.DB_STORE_NAME)}if(!fileStore.indexNames.contains("timestamp")){fileStore.createIndex("timestamp","timestamp",{unique:false})}};req.onsuccess=()=>{db=req.result;IDBFS.dbs[name]=db;callback(null,db)};req.onerror=e=>{callback(e.target.error);e.preventDefault()}},getLocalSet:(mount,callback)=>{var entries={};function isRealDir(p){return p!=="."&&p!==".."}function toAbsolute(root){return p=>PATH.join2(root,p)}var check=FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));while(check.length){var path=check.pop();var stat;try{stat=FS.stat(path)}catch(e){return callback(e)}if(FS.isDir(stat.mode)){check.push(...FS.readdir(path).filter(isRealDir).map(toAbsolute(path)))}entries[path]={timestamp:stat.mtime}}return callback(null,{type:"local",entries})},getRemoteSet:(mount,callback)=>{var entries={};IDBFS.getDB(mount.mountpoint,(err,db)=>{if(err)return callback(err);try{var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readonly");transaction.onerror=e=>{callback(e.target.error);e.preventDefault()};var store=transaction.objectStore(IDBFS.DB_STORE_NAME);var index=store.index("timestamp");index.openKeyCursor().onsuccess=event=>{var cursor=event.target.result;if(!cursor){return callback(null,{type:"remote",db,entries})}entries[cursor.primaryKey]={timestamp:cursor.key};cursor.continue()}}catch(e){return callback(e)}})},loadLocalEntry:(path,callback)=>{var stat,node;try{var lookup=FS.lookupPath(path);node=lookup.node;stat=FS.stat(path)}catch(e){return callback(e)}if(FS.isDir(stat.mode)){return callback(null,{timestamp:stat.mtime,mode:stat.mode})}else if(FS.isFile(stat.mode)){node.contents=MEMFS.getFileDataAsTypedArray(node);return callback(null,{timestamp:stat.mtime,mode:stat.mode,contents:node.contents})}else{return callback(new Error("node type not supported"))}},storeLocalEntry:(path,entry,callback)=>{try{if(FS.isDir(entry["mode"])){FS.mkdirTree(path,entry["mode"])}else if(FS.isFile(entry["mode"])){FS.writeFile(path,entry["contents"],{canOwn:true})}else{return callback(new Error("node type not supported"))}FS.chmod(path,entry["mode"]);FS.utime(path,entry["timestamp"],entry["timestamp"])}catch(e){return callback(e)}callback(null)},removeLocalEntry:(path,callback)=>{try{var stat=FS.stat(path);if(FS.isDir(stat.mode)){FS.rmdir(path)}else if(FS.isFile(stat.mode)){FS.unlink(path)}}catch(e){return callback(e)}callback(null)},loadRemoteEntry:(store,path,callback)=>{var req=store.get(path);req.onsuccess=event=>callback(null,event.target.result);req.onerror=e=>{callback(e.target.error);e.preventDefault()}},storeRemoteEntry:(store,path,entry,callback)=>{try{var req=store.put(entry,path)}catch(e){callback(e);return}req.onsuccess=event=>callback();req.onerror=e=>{callback(e.target.error);e.preventDefault()}},removeRemoteEntry:(store,path,callback)=>{var req=store.delete(path);req.onsuccess=event=>callback();req.onerror=e=>{callback(e.target.error);e.preventDefault()}},reconcile:(src,dst,callback)=>{var total=0;var create=[];Object.keys(src.entries).forEach(key=>{var e=src.entries[key];var e2=dst.entries[key];if(!e2||e["timestamp"].getTime()!=e2["timestamp"].getTime()){create.push(key);total++}});var remove=[];Object.keys(dst.entries).forEach(key=>{if(!src.entries[key]){remove.push(key);total++}});if(!total){return callback(null)}var errored=false;var db=src.type==="remote"?src.db:dst.db;var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readwrite");var store=transaction.objectStore(IDBFS.DB_STORE_NAME);function done(err){if(err&&!errored){errored=true;return callback(err)}}transaction.onerror=transaction.onabort=e=>{done(e.target.error);e.preventDefault()};transaction.oncomplete=e=>{if(!errored){callback(null)}};create.sort().forEach(path=>{if(dst.type==="local"){IDBFS.loadRemoteEntry(store,path,(err,entry)=>{if(err)return done(err);IDBFS.storeLocalEntry(path,entry,done)})}else{IDBFS.loadLocalEntry(path,(err,entry)=>{if(err)return done(err);IDBFS.storeRemoteEntry(store,path,entry,done)})}});remove.sort().reverse().forEach(path=>{if(dst.type==="local"){IDBFS.removeLocalEntry(path,done)}else{IDBFS.removeRemoteEntry(store,path,done)}})}};var ERRNO_CODES={EPERM:63,ENOENT:44,ESRCH:71,EINTR:27,EIO:29,ENXIO:60,E2BIG:1,ENOEXEC:45,EBADF:8,ECHILD:12,EAGAIN:6,EWOULDBLOCK:6,ENOMEM:48,EACCES:2,EFAULT:21,ENOTBLK:105,EBUSY:10,EEXIST:20,EXDEV:75,ENODEV:43,ENOTDIR:54,EISDIR:31,EINVAL:28,ENFILE:41,EMFILE:33,ENOTTY:59,ETXTBSY:74,EFBIG:22,ENOSPC:51,ESPIPE:70,EROFS:69,EMLINK:34,EPIPE:64,EDOM:18,ERANGE:68,ENOMSG:49,EIDRM:24,ECHRNG:106,EL2NSYNC:156,EL3HLT:107,EL3RST:108,ELNRNG:109,EUNATCH:110,ENOCSI:111,EL2HLT:112,EDEADLK:16,ENOLCK:46,EBADE:113,EBADR:114,EXFULL:115,ENOANO:104,EBADRQC:103,EBADSLT:102,EDEADLOCK:16,EBFONT:101,ENOSTR:100,ENODATA:116,ETIME:117,ENOSR:118,ENONET:119,ENOPKG:120,EREMOTE:121,ENOLINK:47,EADV:122,ESRMNT:123,ECOMM:124,EPROTO:65,EMULTIHOP:36,EDOTDOT:125,EBADMSG:9,ENOTUNIQ:126,EBADFD:127,EREMCHG:128,ELIBACC:129,ELIBBAD:130,ELIBSCN:131,ELIBMAX:132,ELIBEXEC:133,ENOSYS:52,ENOTEMPTY:55,ENAMETOOLONG:37,ELOOP:32,EOPNOTSUPP:138,EPFNOSUPPORT:139,ECONNRESET:15,ENOBUFS:42,EAFNOSUPPORT:5,EPROTOTYPE:67,ENOTSOCK:57,ENOPROTOOPT:50,ESHUTDOWN:140,ECONNREFUSED:14,EADDRINUSE:3,ECONNABORTED:13,ENETUNREACH:40,ENETDOWN:38,ETIMEDOUT:73,EHOSTDOWN:142,EHOSTUNREACH:23,EINPROGRESS:26,EALREADY:7,EDESTADDRREQ:17,EMSGSIZE:35,EPROTONOSUPPORT:66,ESOCKTNOSUPPORT:137,EADDRNOTAVAIL:4,ENETRESET:39,EISCONN:30,ENOTCONN:53,ETOOMANYREFS:141,EUSERS:136,EDQUOT:19,ESTALE:72,ENOTSUP:138,ENOMEDIUM:148,EILSEQ:25,EOVERFLOW:61,ECANCELED:11,ENOTRECOVERABLE:56,EOWNERDEAD:62,ESTRPIPE:135};var NODEFS={isWindows:false,staticInit(){NODEFS.isWindows=!!process.platform.match(/^win/);var flags=process.binding("constants")["fs"];NODEFS.flagsForNodeMap={1024:flags["O_APPEND"],64:flags["O_CREAT"],128:flags["O_EXCL"],256:flags["O_NOCTTY"],0:flags["O_RDONLY"],2:flags["O_RDWR"],4096:flags["O_SYNC"],512:flags["O_TRUNC"],1:flags["O_WRONLY"],131072:flags["O_NOFOLLOW"]}},convertNodeCode(e){var code=e.code;return ERRNO_CODES[code]},tryFSOperation(f){try{return f()}catch(e){if(!e.code)throw e;if(e.code==="UNKNOWN")throw new FS.ErrnoError(28);throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},mount(mount){return NODEFS.createNode(null,"/",NODEFS.getMode(mount.opts.root),0)},createNode(parent,name,mode,dev){if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(28)}var node=FS.createNode(parent,name,mode);node.node_ops=NODEFS.node_ops;node.stream_ops=NODEFS.stream_ops;return node},getMode(path){return NODEFS.tryFSOperation(()=>{var mode=fs.lstatSync(path).mode;if(NODEFS.isWindows){mode|=(mode&292)>>2}return mode})},realPath(node){var parts=[];while(node.parent!==node){parts.push(node.name);node=node.parent}parts.push(node.mount.opts.root);parts.reverse();return PATH.join(...parts)},flagsForNode(flags){flags&=~2097152;flags&=~2048;flags&=~32768;flags&=~524288;flags&=~65536;var newFlags=0;for(var k in NODEFS.flagsForNodeMap){if(flags&k){newFlags|=NODEFS.flagsForNodeMap[k];flags^=k}}if(flags){throw new FS.ErrnoError(28)}return newFlags},getattr(func,node){var stat=NODEFS.tryFSOperation(func);if(NODEFS.isWindows){if(!stat.blksize){stat.blksize=4096}if(!stat.blocks){stat.blocks=(stat.size+stat.blksize-1)/stat.blksize|0}stat.mode|=(stat.mode&292)>>2}return{dev:stat.dev,ino:node.id,mode:stat.mode,nlink:stat.nlink,uid:stat.uid,gid:stat.gid,rdev:stat.rdev,size:stat.size,atime:stat.atime,mtime:stat.mtime,ctime:stat.ctime,blksize:stat.blksize,blocks:stat.blocks}},setattr(arg,node,attr,chmod,utimes,truncate,stat){NODEFS.tryFSOperation(()=>{if(attr.mode!==undefined){var mode=attr.mode;if(NODEFS.isWindows){mode&=384}chmod(arg,mode);node.mode=attr.mode}if(typeof(attr.atime??attr.mtime)==="number"){var atime=new Date(attr.atime??stat(arg).atime);var mtime=new Date(attr.mtime??stat(arg).mtime);utimes(arg,atime,mtime)}if(attr.size!==undefined){truncate(arg,attr.size)}})},node_ops:{getattr(node){var path=NODEFS.realPath(node);return NODEFS.getattr(()=>fs.lstatSync(path),node)},setattr(node,attr){var path=NODEFS.realPath(node);if(attr.mode!=null&&attr.dontFollow){throw new FS.ErrnoError(52)}NODEFS.setattr(path,node,attr,fs.chmodSync,fs.utimesSync,fs.truncateSync,fs.lstatSync)},lookup(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);var mode=NODEFS.getMode(path);return NODEFS.createNode(parent,name,mode)},mknod(parent,name,mode,dev){var node=NODEFS.createNode(parent,name,mode,dev);var path=NODEFS.realPath(node);NODEFS.tryFSOperation(()=>{if(FS.isDir(node.mode)){fs.mkdirSync(path,node.mode)}else{fs.writeFileSync(path,"",{mode:node.mode})}});return node},rename(oldNode,newDir,newName){var oldPath=NODEFS.realPath(oldNode);var newPath=PATH.join2(NODEFS.realPath(newDir),newName);try{FS.unlink(newPath)}catch(e){}NODEFS.tryFSOperation(()=>fs.renameSync(oldPath,newPath));oldNode.name=newName},unlink(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);NODEFS.tryFSOperation(()=>fs.unlinkSync(path))},rmdir(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);NODEFS.tryFSOperation(()=>fs.rmdirSync(path))},readdir(node){var path=NODEFS.realPath(node);return NODEFS.tryFSOperation(()=>fs.readdirSync(path))},symlink(parent,newName,oldPath){var newPath=PATH.join2(NODEFS.realPath(parent),newName);NODEFS.tryFSOperation(()=>fs.symlinkSync(oldPath,newPath))},readlink(node){var path=NODEFS.realPath(node);return NODEFS.tryFSOperation(()=>fs.readlinkSync(path))},statfs(path){var stats=NODEFS.tryFSOperation(()=>fs.statfsSync(path));stats.frsize=stats.bsize;return stats}},stream_ops:{getattr(stream){return NODEFS.getattr(()=>fs.fstatSync(stream.nfd),stream.node)},setattr(stream,attr){NODEFS.setattr(stream.nfd,stream.node,attr,fs.fchmodSync,fs.futimesSync,fs.ftruncateSync,fs.fstatSync)},open(stream){var path=NODEFS.realPath(stream.node);NODEFS.tryFSOperation(()=>{stream.shared.refcount=1;stream.nfd=fs.openSync(path,NODEFS.flagsForNode(stream.flags))})},close(stream){NODEFS.tryFSOperation(()=>{if(stream.nfd&&--stream.shared.refcount===0){fs.closeSync(stream.nfd)}})},dup(stream){stream.shared.refcount++},read(stream,buffer,offset,length,position){return NODEFS.tryFSOperation(()=>fs.readSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),0,length,position))},write(stream,buffer,offset,length,position){return NODEFS.tryFSOperation(()=>fs.writeSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),0,length,position))},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){NODEFS.tryFSOperation(()=>{var stat=fs.fstatSync(stream.nfd);position+=stat.size})}}if(position<0){throw new FS.ErrnoError(28)}return position},mmap(stream,length,position,prot,flags){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr=mmapAlloc(length);NODEFS.stream_ops.read(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}},msync(stream,buffer,offset,length,mmapFlags){NODEFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};var WORKERFS={DIR_MODE:16895,FILE_MODE:33279,reader:null,mount(mount){assert(ENVIRONMENT_IS_WORKER);WORKERFS.reader??=new FileReaderSync;var root=WORKERFS.createNode(null,"/",WORKERFS.DIR_MODE,0);var createdParents={};function ensureParent(path){var parts=path.split("/");var parent=root;for(var i=0;i{WORKERFS.createNode(ensureParent(obj["name"]),base(obj["name"]),WORKERFS.FILE_MODE,0,obj["data"])});(mount.opts["packages"]||[]).forEach(pack=>{pack["metadata"].files.forEach(file=>{var name=file.filename.slice(1);WORKERFS.createNode(ensureParent(name),base(name),WORKERFS.FILE_MODE,0,pack["blob"].slice(file.start,file.end))})});return root},createNode(parent,name,mode,dev,contents,mtime){var node=FS.createNode(parent,name,mode);node.mode=mode;node.node_ops=WORKERFS.node_ops;node.stream_ops=WORKERFS.stream_ops;node.atime=node.mtime=node.ctime=(mtime||new Date).getTime();assert(WORKERFS.FILE_MODE!==WORKERFS.DIR_MODE);if(mode===WORKERFS.FILE_MODE){node.size=contents.size;node.contents=contents}else{node.size=4096;node.contents={}}if(parent){parent.contents[name]=node}return node},node_ops:{getattr(node){return{dev:1,ino:node.id,mode:node.mode,nlink:1,uid:0,gid:0,rdev:0,size:node.size,atime:new Date(node.atime),mtime:new Date(node.mtime),ctime:new Date(node.ctime),blksize:4096,blocks:Math.ceil(node.size/4096)}},setattr(node,attr){for(const key of["mode","atime","mtime","ctime"]){if(attr[key]!=null){node[key]=attr[key]}}},lookup(parent,name){throw new FS.ErrnoError(44)},mknod(parent,name,mode,dev){throw new FS.ErrnoError(63)},rename(oldNode,newDir,newName){throw new FS.ErrnoError(63)},unlink(parent,name){throw new FS.ErrnoError(63)},rmdir(parent,name){throw new FS.ErrnoError(63)},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},symlink(parent,newName,oldPath){throw new FS.ErrnoError(63)}},stream_ops:{read(stream,buffer,offset,length,position){if(position>=stream.node.size)return 0;var chunk=stream.node.contents.slice(position,position+length);var ab=WORKERFS.reader.readAsArrayBuffer(chunk);buffer.set(new Uint8Array(ab),offset);return chunk.size},write(stream,buffer,offset,length,position){throw new FS.ErrnoError(29)},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){position+=stream.node.size}}if(position<0){throw new FS.ErrnoError(28)}return position}}};var PROXYFS={mount(mount){return PROXYFS.createNode(null,"/",mount.opts.fs.lstat(mount.opts.root).mode,0)},createNode(parent,name,mode,dev){if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(ERRNO_CODES.EINVAL)}var node=FS.createNode(parent,name,mode);node.node_ops=PROXYFS.node_ops;node.stream_ops=PROXYFS.stream_ops;return node},realPath(node){var parts=[];while(node.parent!==node){parts.push(node.name);node=node.parent}parts.push(node.mount.opts.root);parts.reverse();return PATH.join(...parts)},node_ops:{getattr(node){var path=PROXYFS.realPath(node);var stat;try{stat=node.mount.opts.fs.lstat(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}return{dev:stat.dev,ino:stat.ino,mode:stat.mode,nlink:stat.nlink,uid:stat.uid,gid:stat.gid,rdev:stat.rdev,size:stat.size,atime:stat.atime,mtime:stat.mtime,ctime:stat.ctime,blksize:stat.blksize,blocks:stat.blocks}},setattr(node,attr){var path=PROXYFS.realPath(node);try{if(attr.mode!==undefined){node.mount.opts.fs.chmod(path,attr.mode);node.mode=attr.mode}if(attr.atime||attr.mtime){var atime=new Date(attr.atime||attr.mtime);var mtime=new Date(attr.mtime||attr.atime);node.mount.opts.fs.utime(path,atime,mtime)}if(attr.size!==undefined){node.mount.opts.fs.truncate(path,attr.size)}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},lookup(parent,name){try{var path=PATH.join2(PROXYFS.realPath(parent),name);var mode=parent.mount.opts.fs.lstat(path).mode;var node=PROXYFS.createNode(parent,name,mode);return node}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},mknod(parent,name,mode,dev){var node=PROXYFS.createNode(parent,name,mode,dev);var path=PROXYFS.realPath(node);try{if(FS.isDir(node.mode)){node.mount.opts.fs.mkdir(path,node.mode)}else{node.mount.opts.fs.writeFile(path,"",{mode:node.mode})}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}return node},rename(oldNode,newDir,newName){var oldPath=PROXYFS.realPath(oldNode);var newPath=PATH.join2(PROXYFS.realPath(newDir),newName);try{oldNode.mount.opts.fs.rename(oldPath,newPath);oldNode.name=newName}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},unlink(parent,name){var path=PATH.join2(PROXYFS.realPath(parent),name);try{parent.mount.opts.fs.unlink(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},rmdir(parent,name){var path=PATH.join2(PROXYFS.realPath(parent),name);try{parent.mount.opts.fs.rmdir(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},readdir(node){var path=PROXYFS.realPath(node);try{return node.mount.opts.fs.readdir(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},symlink(parent,newName,oldPath){var newPath=PATH.join2(PROXYFS.realPath(parent),newName);try{parent.mount.opts.fs.symlink(oldPath,newPath)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},readlink(node){var path=PROXYFS.realPath(node);try{return node.mount.opts.fs.readlink(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}}},stream_ops:{open(stream){var path=PROXYFS.realPath(stream.node);try{stream.nfd=stream.node.mount.opts.fs.open(path,stream.flags)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},close(stream){try{stream.node.mount.opts.fs.close(stream.nfd)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},read(stream,buffer,offset,length,position){try{return stream.node.mount.opts.fs.read(stream.nfd,buffer,offset,length,position)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},write(stream,buffer,offset,length,position){try{return stream.node.mount.opts.fs.write(stream.nfd,buffer,offset,length,position)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){try{var stat=stream.node.node_ops.getattr(stream.node);position+=stat.size}catch(e){throw new FS.ErrnoError(ERRNO_CODES[e.code])}}}if(position<0){throw new FS.ErrnoError(ERRNO_CODES.EINVAL)}return position}}};var LZ4={DIR_MODE:16895,FILE_MODE:33279,CHUNK_SIZE:-1,codec:null,init(){if(LZ4.codec)return;LZ4.codec=(()=>{var MiniLZ4=function(){var exports={};exports.uncompress=function(input,output,sIdx,eIdx){sIdx=sIdx||0;eIdx=eIdx||input.length-sIdx;for(var i=sIdx,n=eIdx,j=0;i>4;if(literals_length>0){var l=literals_length+240;while(l===255){l=input[i++];literals_length+=l}var end=i+literals_length;while(ij)return-(i-2);var match_length=token&15;var l=match_length+240;while(l===255){l=input[i++];match_length+=l}var pos=j-offset;var end=j+match_length+4;while(jmaxInputSize?0:isize+isize/255+16|0};exports.compress=function(src,dst,sIdx,eIdx){hashTable.set(empty);return compressBlock(src,dst,0,sIdx||0,eIdx||dst.length)};function compressBlock(src,dst,pos,sIdx,eIdx){var dpos=sIdx;var dlen=eIdx-sIdx;var anchor=0;if(src.length>=maxInputSize)throw new Error("input too large");if(src.length>mfLimit){var n=exports.compressBound(src.length);if(dlen>>hashShift;var ref=hashTable[hash]-1;hashTable[hash]=pos+1;if(ref<0||pos-ref>>>16>0||((src[ref+3]<<8|src[ref+2])!=sequenceHighBits||(src[ref+1]<<8|src[ref])!=sequenceLowBits)){step=findMatchAttempts++>>skipStrength;pos+=step;continue}findMatchAttempts=(1<=runMask){dst[dpos++]=(runMask<254;len-=255){dst[dpos++]=255}dst[dpos++]=len}else{dst[dpos++]=(literals_length<>8;if(match_length>=mlMask){match_length-=mlMask;while(match_length>=255){match_length-=255;dst[dpos++]=255}dst[dpos++]=match_length}anchor=pos}}if(anchor==0)return 0;literals_length=src.length-anchor;if(literals_length>=runMask){dst[dpos++]=runMask<254;ln-=255){dst[dpos++]=255}dst[dpos++]=ln}else{dst[dpos++]=literals_length<0){assert(compressedSize<=bound);compressed=compressed.subarray(0,compressedSize);compressedChunks.push(compressed);total+=compressedSize;successes.push(1);if(verify){var back=exports.uncompress(compressed,temp);assert(back===chunk.length,[back,chunk.length]);for(var i=0;i{var dir=PATH.dirname(file.filename);var name=PATH.basename(file.filename);FS.createPath("",dir,true,true);var parent=FS.analyzePath(dir).object;LZ4.createNode(parent,name,LZ4.FILE_MODE,0,{compressedData,start:file.start,end:file.end})});if(preloadPlugin){Browser.init();pack["metadata"].files.forEach(file=>{var handled=false;var fullname=file.filename;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){var dep=getUniqueRunDependency("fp "+fullname);addRunDependency(dep);var finish=()=>removeRunDependency(dep);var byteArray=FS.readFile(fullname);plugin["handle"](byteArray,fullname,finish,finish);handled=true}})})}},createNode(parent,name,mode,dev,contents,mtime){var node=FS.createNode(parent,name,mode);node.mode=mode;node.node_ops=LZ4.node_ops;node.stream_ops=LZ4.stream_ops;this.atime=this.mtime=this.ctime=(mtime||new Date).getTime();assert(LZ4.FILE_MODE!==LZ4.DIR_MODE);if(mode===LZ4.FILE_MODE){node.size=contents.end-contents.start;node.contents=contents}else{node.size=4096;node.contents={}}if(parent){parent.contents[name]=node}return node},node_ops:{getattr(node){return{dev:1,ino:node.id,mode:node.mode,nlink:1,uid:0,gid:0,rdev:0,size:node.size,atime:new Date(node.atime),mtime:new Date(node.mtime),ctime:new Date(node.ctime),blksize:4096,blocks:Math.ceil(node.size/4096)}},setattr(node,attr){for(const key of["mode","atime","mtime","ctime"]){if(attr[key]){node[key]=attr[key]}}},lookup(parent,name){throw new FS.ErrnoError(44)},mknod(parent,name,mode,dev){throw new FS.ErrnoError(63)},rename(oldNode,newDir,newName){throw new FS.ErrnoError(63)},unlink(parent,name){throw new FS.ErrnoError(63)},rmdir(parent,name){throw new FS.ErrnoError(63)},readdir(node){throw new FS.ErrnoError(63)},symlink(parent,newName,oldPath){throw new FS.ErrnoError(63)}},stream_ops:{read(stream,buffer,offset,length,position){length=Math.min(length,stream.node.size-position);if(length<=0)return 0;var contents=stream.node.contents;var compressedData=contents.compressedData;var written=0;while(written=0){currChunk=compressedData["cachedChunks"][found]}else{compressedData["cachedIndexes"].pop();compressedData["cachedIndexes"].unshift(chunkIndex);currChunk=compressedData["cachedChunks"].pop();compressedData["cachedChunks"].unshift(currChunk);if(compressedData["debug"]){out("decompressing chunk "+chunkIndex);Module["decompressedChunks"]=(Module["decompressedChunks"]||0)+1}var compressed=compressedData["data"].subarray(compressedStart,compressedStart+compressedSize);var originalSize=LZ4.codec.uncompress(compressed,currChunk);if(chunkIndex!!p);var current=FS.root;var current_path="/";for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){if(!FS.isDir(dir.mode)){return 54}try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&(512|64)){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},checkOpExists(op,err){if(!op){throw new FS.ErrnoError(err)}return op},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},doSetAttr(stream,node,attr){var setattr=stream?.stream_ops.setattr;var arg=setattr?stream:node;setattr??=node.node_ops.setattr;FS.checkOpExists(setattr,63);setattr(arg,attr)},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name){throw new FS.ErrnoError(28)}if(name==="."||name===".."){throw new FS.ErrnoError(20)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},statfs(path){return FS.statfsNode(FS.lookupPath(path,{follow:true}).node)},statfsStream(stream){return FS.statfsNode(stream.node)},statfsNode(node){var rtn={bsize:4096,frsize:4096,blocks:1e6,bfree:5e5,bavail:5e5,files:FS.nextInode,ffree:FS.nextInode-1,fsid:42,flags:2,namelen:255};if(node.node_ops.statfs){Object.assign(rtn,node.node_ops.statfs(node.mount.opts.root))}return rtn},create(path,mode=438){mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode=511){mode&=511|512;mode|=16384;if(FS.trackingDelegate["onMakeDirectory"]){FS.trackingDelegate["onMakeDirectory"](path,mode)}return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var dir of dirs){if(!dir)continue;if(d||PATH.isAbs(path))d+="/";d+=dir;try{FS.mkdir(d,mode)}catch(e){if(e.errno!=20)throw e}}},mkdev(path,mode,dev){if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink(oldpath,newpath){if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}if(FS.trackingDelegate["onMakeSymlink"]){FS.trackingDelegate["onMakeSymlink"](oldpath,newpath)}return parent.node_ops.symlink(parent,newname,oldpath)},rename(old_path,new_path){var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}if(FS.trackingDelegate["willMovePath"]){FS.trackingDelegate["willMovePath"](old_path,new_path)}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name);old_node.parent=new_dir}catch(e){throw e}finally{FS.hashAddNode(old_node)}if(FS.trackingDelegate["onMovePath"]){FS.trackingDelegate["onMovePath"](old_path,new_path)}},rmdir(path){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(FS.trackingDelegate["willDeletePath"]){FS.trackingDelegate["willDeletePath"](path)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node);if(FS.trackingDelegate["onDeletePath"]){FS.trackingDelegate["onDeletePath"](path)}},readdir(path){var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;var readdir=FS.checkOpExists(node.node_ops.readdir,54);return readdir(node)},unlink(path){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(FS.trackingDelegate["willDeletePath"]){FS.trackingDelegate["willDeletePath"](path)}parent.node_ops.unlink(parent,name);FS.destroyNode(node);if(FS.trackingDelegate["onDeletePath"]){FS.trackingDelegate["onDeletePath"](path)}},readlink(path){var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return link.node_ops.readlink(link)},stat(path,dontFollow){var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;var getattr=FS.checkOpExists(node.node_ops.getattr,63);return getattr(node)},fstat(fd){var stream=FS.getStreamChecked(fd);var node=stream.node;var getattr=stream.stream_ops.getattr;var arg=getattr?stream:node;getattr??=node.node_ops.getattr;FS.checkOpExists(getattr,63);return getattr(arg)},lstat(path){return FS.stat(path,true)},doChmod(stream,node,mode,dontFollow){FS.doSetAttr(stream,node,{mode:mode&4095|node.mode&~4095,ctime:Date.now(),dontFollow})},chmod(path,mode,dontFollow){var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}FS.doChmod(null,node,mode,dontFollow)},lchmod(path,mode){FS.chmod(path,mode,true)},fchmod(fd,mode){var stream=FS.getStreamChecked(fd);FS.doChmod(stream,stream.node,mode,false)},doChown(stream,node,dontFollow){FS.doSetAttr(stream,node,{timestamp:Date.now(),dontFollow})},chown(path,uid,gid,dontFollow){var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}FS.doChown(null,node,dontFollow)},lchown(path,uid,gid){FS.chown(path,uid,gid,true)},fchown(fd,uid,gid){var stream=FS.getStreamChecked(fd);FS.doChown(stream,stream.node,false)},doTruncate(stream,node,len){if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}FS.doSetAttr(stream,node,{size:len,timestamp:Date.now()})},truncate(path,len){if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}FS.doTruncate(null,node,len)},ftruncate(fd,len){var stream=FS.getStreamChecked(fd);if(len<0||(stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.doTruncate(stream,stream.node,len)},utime(path,atime,mtime){var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;var setattr=FS.checkOpExists(node.node_ops.setattr,63);setattr(node,{atime,mtime})},open(path,flags,mode=438){if(path===""){throw new FS.ErrnoError(44)}flags=typeof flags=="string"?FS_modeStringToFlags(flags):flags;if(flags&64){mode=mode&4095|32768}else{mode=0}var node;var isDirPath;if(typeof path=="object"){node=path}else{isDirPath=path.endsWith("/");var lookup=FS.lookupPath(path,{follow:!(flags&131072),noent_okay:true});node=lookup.node;path=lookup.path}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else if(isDirPath){throw new FS.ErrnoError(31)}else{node=FS.mknod(path,mode|511,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}var trackingFlags=flags;flags&=~(128|512|131072);var stream=FS.createStream({node,path:FS.getPath(node),flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(created){FS.chmod(node,mode&511)}if(Module["logReadFiles"]&&!(flags&1)){if(!(path in FS.readFiles)){FS.readFiles[path]=1;dbg(`FS.trackingDelegate error on read file: ${path}`)}}if(FS.trackingDelegate["onOpenFile"]){FS.trackingDelegate["onOpenFile"](path,trackingFlags)}return stream},close(stream){if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null;if(stream.path&&FS.trackingDelegate["onCloseFile"]){FS.trackingDelegate["onCloseFile"](stream.path)}},isClosed(stream){return stream.fd===null},llseek(stream,offset,whence){if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];if(stream.path&&FS.trackingDelegate["onSeekFile"]){FS.trackingDelegate["onSeekFile"](stream.path,stream.position,whence)}return stream.position},read(stream,buffer,offset,length,position){if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;if(stream.path&&FS.trackingDelegate["onReadFile"]){FS.trackingDelegate["onReadFile"](stream.path,bytesRead)}return bytesRead},write(stream,buffer,offset,length,position,canOwn){if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;if(stream.path&&FS.trackingDelegate["onWriteToFile"]){FS.trackingDelegate["onWriteToFile"](stream.path,bytesWritten)}return bytesWritten},mmap(stream,length,position,prot,flags){if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}if(!length){throw new FS.ErrnoError(28)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync(stream,buffer,offset,length,mmapFlags){if(!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},ioctl(stream,cmd,arg){if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile(path,opts={}){opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile(path,data,opts={}){opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomFill(randomBuffer);randomLeft=randomBuffer.byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16895,73);node.stream_ops={llseek:MEMFS.stream_ops.llseek};node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path},id:fd+1};ret.parent=ret;return ret},readdir(){return Array.from(FS.streams.entries()).filter(([k,v])=>v).map(([k,v])=>k.toString())}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS,IDBFS,NODEFS,WORKERFS,PROXYFS}},init(input,output,error){FS.initialized=true;input??=Module["stdin"];output??=Module["stdout"];error??=Module["stderr"];FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;_fflush(0);for(var stream of FS.streams){if(stream){FS.close(stream)}}},findObject(path,dontResolveLastLink){var ret=FS.analyzePath(path,dontResolveLastLink);if(!ret.exists){return null}return ret.object},analyzePath(path,dontResolveLastLink){try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath(parent,path,canRead,canWrite){parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){if(e.errno!=20)throw e}parent=current}return current},createFile(parent,name,properties,canRead,canWrite){var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile(parent,name,data,canRead,canWrite,canOwn){var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS_getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){if(typeof data=="string"){var arr=new Array(data.length);for(var i=0,len=data.length;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var findLibraryFS=(libName,rpath)=>{if(!runtimeInitialized){return undefined}if(PATH.isAbs(libName)){try{FS.lookupPath(libName);return libName}catch(e){return undefined}}var rpathResolved=(rpath?.paths||[]).map(p=>replaceORIGIN(rpath?.parentLibPath,p));return withStackSave(()=>{var bufSize=2*255+2;var buf=stackAlloc(bufSize);var rpathC=stringToUTF8OnStack(rpathResolved.join(":"));var libNameC=stringToUTF8OnStack(libName);var resLibNameC=__emscripten_find_dylib(buf,rpathC,libNameC,bufSize);return resLibNameC?UTF8ToString(resLibNameC):undefined})};function loadDynamicLibrary(libName,flags={global:true,nodelete:true},localScope,handle){var dso=LDSO.loadedLibsByName[libName];if(dso){if(!flags.global){if(localScope){Object.assign(localScope,dso.exports)}}else if(!dso.global){dso.global=true;mergeLibSymbols(dso.exports,libName)}if(flags.nodelete&&dso.refcount!==Infinity){dso.refcount=Infinity}dso.refcount++;if(handle){LDSO.loadedLibsByHandle[handle]=dso}return flags.loadAsync?Promise.resolve(true):true}dso=newDSO(libName,handle,"loading");dso.refcount=flags.nodelete?Infinity:1;dso.global=flags.global;function loadLibData(){if(handle){var data=HEAPU32[handle+28>>>2>>>0];var dataSize=HEAPU32[handle+32>>>2>>>0];if(data&&dataSize){var libData=HEAP8.slice(data,data+dataSize);return flags.loadAsync?Promise.resolve(libData):libData}}var f=findLibraryFS(libName,flags.rpath);if(f){var libData=FS.readFile(f,{encoding:"binary"});return flags.loadAsync?Promise.resolve(libData):libData}var libFile=locateFile(libName);if(flags.loadAsync){return asyncLoad(libFile)}if(!readBinary){throw new Error(`${libFile}: file not found, and synchronous loading of external files is not available`)}return readBinary(libFile)}function getExports(){var preloaded=preloadedWasm[libName];if(preloaded){return flags.loadAsync?Promise.resolve(preloaded):preloaded}if(flags.loadAsync){return loadLibData().then(libData=>loadWebAssemblyModule(libData,flags,libName,localScope,handle))}return loadWebAssemblyModule(loadLibData(),flags,libName,localScope,handle)}function moduleLoaded(exports){if(dso.global){mergeLibSymbols(exports,libName)}else if(localScope){Object.assign(localScope,exports)}dso.exports=exports}if(flags.loadAsync){return getExports().then(exports=>{moduleLoaded(exports);return true})}moduleLoaded(getExports());return true}var reportUndefinedSymbols=()=>{for(var[symName,entry]of Object.entries(GOT)){if(entry.value==0){var value=resolveGlobalSymbol(symName,true).sym;if(!value&&!entry.required){continue}if(typeof value=="function"){entry.value=addFunction(value,value.sig)}else if(typeof value=="number"){entry.value=value}else{throw new Error(`bad export type for '${symName}': ${typeof value}`)}}}};var loadDylibs=()=>{if(!dynamicLibraries.length){reportUndefinedSymbols();return}addRunDependency("loadDylibs");dynamicLibraries.reduce((chain,lib)=>chain.then(()=>loadDynamicLibrary(lib,{loadAsync:true,global:true,nodelete:true,allowUndefined:true})),Promise.resolve()).then(()=>{reportUndefinedSymbols();removeRunDependency("loadDylibs")})};var noExitRuntime=false;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr>>>0]=value;break;case"i8":HEAP8[ptr>>>0]=value;break;case"i16":HEAP16[ptr>>>1>>>0]=value;break;case"i32":HEAP32[ptr>>>2>>>0]=value;break;case"i64":HEAP64[ptr>>>3>>>0]=BigInt(value);break;case"float":HEAPF32[ptr>>>2>>>0]=value;break;case"double":HEAPF64[ptr>>>3>>>0]=value;break;case"*":HEAPU32[ptr>>>2>>>0]=value;break;default:abort(`invalid type for setValue: ${type}`)}}var INT53_MAX=9007199254740992;var INT53_MIN=-9007199254740992;var bigintToI53Checked=num=>numINT53_MAX?NaN:Number(num);function ___assert_fail(condition,filename,line,func){condition>>>=0;filename>>>=0;func>>>=0;return abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}___assert_fail.sig="vppip";var ___c_longjmp=new WebAssembly.Tag({parameters:["i32"]});function ___call_sighandler(fp,sig){fp>>>=0;return getWasmTableEntry(fp)(sig)}___call_sighandler.sig="vpi";var ___cpp_exception=new WebAssembly.Tag({parameters:["i32"]});var ___memory_base=new WebAssembly.Global({value:"i32",mutable:false},1024);var ___stack_high=8810528;var ___stack_low=3567648;var ___stack_pointer=new WebAssembly.Global({value:"i32",mutable:true},8810528);var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return dir+"/"+path},writeStat(buf,stat){HEAP32[buf>>>2>>>0]=stat.dev;HEAP32[buf+4>>>2>>>0]=stat.mode;HEAPU32[buf+8>>>2>>>0]=stat.nlink;HEAP32[buf+12>>>2>>>0]=stat.uid;HEAP32[buf+16>>>2>>>0]=stat.gid;HEAP32[buf+20>>>2>>>0]=stat.rdev;HEAP64[buf+24>>>3>>>0]=BigInt(stat.size);HEAP32[buf+32>>>2>>>0]=4096;HEAP32[buf+36>>>2>>>0]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();HEAP64[buf+40>>>3>>>0]=BigInt(Math.floor(atime/1e3));HEAPU32[buf+48>>>2>>>0]=atime%1e3*1e3*1e3;HEAP64[buf+56>>>3>>>0]=BigInt(Math.floor(mtime/1e3));HEAPU32[buf+64>>>2>>>0]=mtime%1e3*1e3*1e3;HEAP64[buf+72>>>3>>>0]=BigInt(Math.floor(ctime/1e3));HEAPU32[buf+80>>>2>>>0]=ctime%1e3*1e3*1e3;HEAP64[buf+88>>>3>>>0]=BigInt(stat.ino);return 0},writeStatFs(buf,stats){HEAP32[buf+4>>>2>>>0]=stats.bsize;HEAP32[buf+40>>>2>>>0]=stats.bsize;HEAP32[buf+8>>>2>>>0]=stats.blocks;HEAP32[buf+12>>>2>>>0]=stats.bfree;HEAP32[buf+16>>>2>>>0]=stats.bavail;HEAP32[buf+20>>>2>>>0]=stats.files;HEAP32[buf+24>>>2>>>0]=stats.ffree;HEAP32[buf+28>>>2>>>0]=stats.fsid;HEAP32[buf+44>>>2>>>0]=stats.flags;HEAP32[buf+36>>>2>>>0]=stats.namelen},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};var ___syscall__newselect=function(nfds,readfds,writefds,exceptfds,timeout){readfds>>>=0;writefds>>>=0;exceptfds>>>=0;timeout>>>=0;try{var total=0;var srcReadLow=readfds?HEAP32[readfds>>>2>>>0]:0,srcReadHigh=readfds?HEAP32[readfds+4>>>2>>>0]:0;var srcWriteLow=writefds?HEAP32[writefds>>>2>>>0]:0,srcWriteHigh=writefds?HEAP32[writefds+4>>>2>>>0]:0;var srcExceptLow=exceptfds?HEAP32[exceptfds>>>2>>>0]:0,srcExceptHigh=exceptfds?HEAP32[exceptfds+4>>>2>>>0]:0;var dstReadLow=0,dstReadHigh=0;var dstWriteLow=0,dstWriteHigh=0;var dstExceptLow=0,dstExceptHigh=0;var allLow=(readfds?HEAP32[readfds>>>2>>>0]:0)|(writefds?HEAP32[writefds>>>2>>>0]:0)|(exceptfds?HEAP32[exceptfds>>>2>>>0]:0);var allHigh=(readfds?HEAP32[readfds+4>>>2>>>0]:0)|(writefds?HEAP32[writefds+4>>>2>>>0]:0)|(exceptfds?HEAP32[exceptfds+4>>>2>>>0]:0);var check=(fd,low,high,val)=>fd<32?low&val:high&val;for(var fd=0;fd>>2>>>0]:0,tv_usec=readfds?HEAP32[timeout+4>>>2>>>0]:0;timeoutInMillis=(tv_sec+tv_usec/1e6)*1e3}flags=stream.stream_ops.poll(stream,timeoutInMillis)}if(flags&1&&check(fd,srcReadLow,srcReadHigh,mask)){fd<32?dstReadLow=dstReadLow|mask:dstReadHigh=dstReadHigh|mask;total++}if(flags&4&&check(fd,srcWriteLow,srcWriteHigh,mask)){fd<32?dstWriteLow=dstWriteLow|mask:dstWriteHigh=dstWriteHigh|mask;total++}if(flags&2&&check(fd,srcExceptLow,srcExceptHigh,mask)){fd<32?dstExceptLow=dstExceptLow|mask:dstExceptHigh=dstExceptHigh|mask;total++}}if(readfds){HEAP32[readfds>>>2>>>0]=dstReadLow;HEAP32[readfds+4>>>2>>>0]=dstReadHigh}if(writefds){HEAP32[writefds>>>2>>>0]=dstWriteLow;HEAP32[writefds+4>>>2>>>0]=dstWriteHigh}if(exceptfds){HEAP32[exceptfds>>>2>>>0]=dstExceptLow;HEAP32[exceptfds+4>>>2>>>0]=dstExceptHigh}return total}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}};___syscall__newselect.sig="iipppp";var SOCKFS={websocketArgs:{},callbacks:{},on(event,callback){SOCKFS.callbacks[event]=callback},emit(event,param){SOCKFS.callbacks[event]?.(param)},mount(mount){SOCKFS.websocketArgs=Module["websocket"]||{};(Module["websocket"]??={})["on"]=SOCKFS.on;return FS.createNode(null,"/",16895,0)},createSocket(family,type,protocol){type&=~526336;var streaming=type==1;if(streaming&&protocol&&protocol!=6){throw new FS.ErrnoError(66)}var sock={family,type,protocol,server:null,error:null,peers:{},pending:[],recv_queue:[],sock_ops:SOCKFS.websocket_sock_ops};var name=SOCKFS.nextname();var node=FS.createNode(SOCKFS.root,name,49152,0);node.sock=sock;var stream=FS.createStream({path:name,node,flags:2,seekable:false,stream_ops:SOCKFS.stream_ops});sock.stream=stream;return sock},getSocket(fd){var stream=FS.getStream(fd);if(!stream||!FS.isSocket(stream.node.mode)){return null}return stream.node.sock},stream_ops:{poll(stream){var sock=stream.node.sock;return sock.sock_ops.poll(sock)},ioctl(stream,request,varargs){var sock=stream.node.sock;return sock.sock_ops.ioctl(sock,request,varargs)},read(stream,buffer,offset,length,position){var sock=stream.node.sock;var msg=sock.sock_ops.recvmsg(sock,length);if(!msg){return 0}buffer.set(msg.buffer,offset);return msg.buffer.length},write(stream,buffer,offset,length,position){var sock=stream.node.sock;return sock.sock_ops.sendmsg(sock,buffer,offset,length)},close(stream){var sock=stream.node.sock;sock.sock_ops.close(sock)}},nextname(){if(!SOCKFS.nextname.current){SOCKFS.nextname.current=0}return`socket[${SOCKFS.nextname.current++}]`},websocket_sock_ops:{createPeer(sock,addr,port){var ws;if(typeof addr=="object"){ws=addr;addr=null;port=null}if(ws){if(ws._socket){addr=ws._socket.remoteAddress;port=ws._socket.remotePort}else{var result=/ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);if(!result){throw new Error("WebSocket URL must be in the format ws(s)://address:port")}addr=result[1];port=parseInt(result[2],10)}}else{try{var url="ws://".replace("#","//");var subProtocols="binary";var opts=undefined;if(SOCKFS.websocketArgs["url"]){url=SOCKFS.websocketArgs["url"]}if(SOCKFS.websocketArgs["subprotocol"]){subProtocols=SOCKFS.websocketArgs["subprotocol"]}else if(SOCKFS.websocketArgs["subprotocol"]===null){subProtocols="null"}if(url==="ws://"||url==="wss://"){var parts=addr.split("/");url=url+parts[0]+":"+port+"/"+parts.slice(1).join("/")}if(subProtocols!=="null"){subProtocols=subProtocols.replace(/^ +| +$/g,"").split(/ *, */);opts=subProtocols}var WebSocketConstructor;if(ENVIRONMENT_IS_NODE){WebSocketConstructor=require("ws")}else{WebSocketConstructor=WebSocket}ws=new WebSocketConstructor(url,opts);ws.binaryType="arraybuffer"}catch(e){throw new FS.ErrnoError(23)}}var peer={addr,port,socket:ws,msg_send_queue:[]};SOCKFS.websocket_sock_ops.addPeer(sock,peer);SOCKFS.websocket_sock_ops.handlePeerEvents(sock,peer);if(sock.type===2&&typeof sock.sport!="undefined"){peer.msg_send_queue.push(new Uint8Array([255,255,255,255,"p".charCodeAt(0),"o".charCodeAt(0),"r".charCodeAt(0),"t".charCodeAt(0),(sock.sport&65280)>>8,sock.sport&255]))}return peer},getPeer(sock,addr,port){return sock.peers[addr+":"+port]},addPeer(sock,peer){sock.peers[peer.addr+":"+peer.port]=peer},removePeer(sock,peer){delete sock.peers[peer.addr+":"+peer.port]},handlePeerEvents(sock,peer){var first=true;var handleOpen=function(){sock.connecting=false;SOCKFS.emit("open",sock.stream.fd);try{var queued=peer.msg_send_queue.shift();while(queued){peer.socket.send(queued);queued=peer.msg_send_queue.shift()}}catch(e){peer.socket.close()}};function handleMessage(data){if(typeof data=="string"){var encoder=new TextEncoder;data=encoder.encode(data)}else{assert(data.byteLength!==undefined);if(data.byteLength==0){return}data=new Uint8Array(data)}var wasfirst=first;first=false;if(wasfirst&&data.length===10&&data[0]===255&&data[1]===255&&data[2]===255&&data[3]===255&&data[4]==="p".charCodeAt(0)&&data[5]==="o".charCodeAt(0)&&data[6]==="r".charCodeAt(0)&&data[7]==="t".charCodeAt(0)){var newport=data[8]<<8|data[9];SOCKFS.websocket_sock_ops.removePeer(sock,peer);peer.port=newport;SOCKFS.websocket_sock_ops.addPeer(sock,peer);return}sock.recv_queue.push({addr:peer.addr,port:peer.port,data});SOCKFS.emit("message",sock.stream.fd)}if(ENVIRONMENT_IS_NODE){peer.socket.on("open",handleOpen);peer.socket.on("message",function(data,isBinary){if(!isBinary){return}handleMessage(new Uint8Array(data).buffer)});peer.socket.on("close",function(){SOCKFS.emit("close",sock.stream.fd)});peer.socket.on("error",function(error){sock.error=14;SOCKFS.emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])})}else{peer.socket.onopen=handleOpen;peer.socket.onclose=function(){SOCKFS.emit("close",sock.stream.fd)};peer.socket.onmessage=function peer_socket_onmessage(event){handleMessage(event.data)};peer.socket.onerror=function(error){sock.error=14;SOCKFS.emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])}}},poll(sock){if(sock.type===1&&sock.server){return sock.pending.length?64|1:0}var mask=0;var dest=sock.type===1?SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport):null;if(sock.recv_queue.length||!dest||dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=64|1}if(!dest||dest&&dest.socket.readyState===dest.socket.OPEN){mask|=4}if(dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){if(sock.connecting){mask|=4}else{mask|=16}}return mask},ioctl(sock,request,arg){switch(request){case 21531:var bytes=0;if(sock.recv_queue.length){bytes=sock.recv_queue[0].data.length}HEAP32[arg>>>2>>>0]=bytes;return 0;default:return 28}},close(sock){if(sock.server){try{sock.server.close()}catch(e){}sock.server=null}for(var peer of Object.values(sock.peers)){try{peer.socket.close()}catch(e){}SOCKFS.websocket_sock_ops.removePeer(sock,peer)}return 0},bind(sock,addr,port){if(typeof sock.saddr!="undefined"||typeof sock.sport!="undefined"){throw new FS.ErrnoError(28)}sock.saddr=addr;sock.sport=port;if(sock.type===2){if(sock.server){sock.server.close();sock.server=null}try{sock.sock_ops.listen(sock,0)}catch(e){if(!(e.name==="ErrnoError"))throw e;if(e.errno!==138)throw e}}},connect(sock,addr,port){if(sock.server){throw new FS.ErrnoError(138)}if(typeof sock.daddr!="undefined"&&typeof sock.dport!="undefined"){var dest=SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport);if(dest){if(dest.socket.readyState===dest.socket.CONNECTING){throw new FS.ErrnoError(7)}else{throw new FS.ErrnoError(30)}}}var peer=SOCKFS.websocket_sock_ops.createPeer(sock,addr,port);sock.daddr=peer.addr;sock.dport=peer.port;sock.connecting=true},listen(sock,backlog){if(!ENVIRONMENT_IS_NODE){throw new FS.ErrnoError(138)}if(sock.server){throw new FS.ErrnoError(28)}var WebSocketServer=require("ws").Server;var host=sock.saddr;sock.server=new WebSocketServer({host,port:sock.sport});SOCKFS.emit("listen",sock.stream.fd);sock.server.on("connection",function(ws){if(sock.type===1){var newsock=SOCKFS.createSocket(sock.family,sock.type,sock.protocol);var peer=SOCKFS.websocket_sock_ops.createPeer(newsock,ws);newsock.daddr=peer.addr;newsock.dport=peer.port;sock.pending.push(newsock);SOCKFS.emit("connection",newsock.stream.fd)}else{SOCKFS.websocket_sock_ops.createPeer(sock,ws);SOCKFS.emit("connection",sock.stream.fd)}});sock.server.on("close",function(){SOCKFS.emit("close",sock.stream.fd);sock.server=null});sock.server.on("error",function(error){sock.error=23;SOCKFS.emit("error",[sock.stream.fd,sock.error,"EHOSTUNREACH: Host is unreachable"])})},accept(listensock){if(!listensock.server||!listensock.pending.length){throw new FS.ErrnoError(28)}var newsock=listensock.pending.shift();newsock.stream.flags=listensock.stream.flags;return newsock},getname(sock,peer){var addr,port;if(peer){if(sock.daddr===undefined||sock.dport===undefined){throw new FS.ErrnoError(53)}addr=sock.daddr;port=sock.dport}else{addr=sock.saddr||0;port=sock.sport||0}return{addr,port}},sendmsg(sock,buffer,offset,length,addr,port){if(sock.type===2){if(addr===undefined||port===undefined){addr=sock.daddr;port=sock.dport}if(addr===undefined||port===undefined){throw new FS.ErrnoError(17)}}else{addr=sock.daddr;port=sock.dport}var dest=SOCKFS.websocket_sock_ops.getPeer(sock,addr,port);if(sock.type===1){if(!dest||dest.socket.readyState===dest.socket.CLOSING||dest.socket.readyState===dest.socket.CLOSED){throw new FS.ErrnoError(53)}}if(ArrayBuffer.isView(buffer)){offset+=buffer.byteOffset;buffer=buffer.buffer}var data=buffer.slice(offset,offset+length);if(!dest||dest.socket.readyState!==dest.socket.OPEN){if(sock.type===2){if(!dest||dest.socket.readyState===dest.socket.CLOSING||dest.socket.readyState===dest.socket.CLOSED){dest=SOCKFS.websocket_sock_ops.createPeer(sock,addr,port)}}dest.msg_send_queue.push(data);return length}try{dest.socket.send(data);return length}catch(e){throw new FS.ErrnoError(28)}},recvmsg(sock,length){if(sock.type===1&&sock.server){throw new FS.ErrnoError(53)}var queued=sock.recv_queue.shift();if(!queued){if(sock.type===1){var dest=SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport);if(!dest){throw new FS.ErrnoError(53)}if(dest.socket.readyState===dest.socket.CLOSING||dest.socket.readyState===dest.socket.CLOSED){return null}throw new FS.ErrnoError(6)}throw new FS.ErrnoError(6)}var queuedLength=queued.data.byteLength||queued.data.length;var queuedOffset=queued.data.byteOffset||0;var queuedBuffer=queued.data.buffer||queued.data;var bytesRead=Math.min(length,queuedLength);var res={buffer:new Uint8Array(queuedBuffer,queuedOffset,bytesRead),addr:queued.addr,port:queued.port};if(sock.type===1&&bytesRead{var socket=SOCKFS.getSocket(fd);if(!socket)throw new FS.ErrnoError(8);return socket};var inetPton4=str=>{var b=str.split(".");for(var i=0;i<4;i++){var tmp=Number(b[i]);if(isNaN(tmp))return null;b[i]=tmp}return(b[0]|b[1]<<8|b[2]<<16|b[3]<<24)>>>0};var inetPton6=str=>{var words;var w,offset,z,i;var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;var parts=[];if(!valid6regx.test(str)){return null}if(str==="::"){return[0,0,0,0,0,0,0,0]}if(str.startsWith("::")){str=str.replace("::","Z:")}else{str=str.replace("::",":Z:")}if(str.indexOf(".")>0){str=str.replace(new RegExp("[.]","g"),":");words=str.split(":");words[words.length-4]=Number(words[words.length-4])+Number(words[words.length-3])*256;words[words.length-3]=Number(words[words.length-2])+Number(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w{switch(family){case 2:addr=inetPton4(addr);zeroMemory(sa,16);if(addrlen){HEAP32[addrlen>>>2>>>0]=16}HEAP16[sa>>>1>>>0]=family;HEAP32[sa+4>>>2>>>0]=addr;HEAP16[sa+2>>>1>>>0]=_htons(port);break;case 10:addr=inetPton6(addr);zeroMemory(sa,28);if(addrlen){HEAP32[addrlen>>>2>>>0]=28}HEAP32[sa>>>2>>>0]=family;HEAP32[sa+8>>>2>>>0]=addr[0];HEAP32[sa+12>>>2>>>0]=addr[1];HEAP32[sa+16>>>2>>>0]=addr[2];HEAP32[sa+20>>>2>>>0]=addr[3];HEAP16[sa+2>>>1>>>0]=_htons(port);break;default:return 5}return 0};var DNS={address_map:{id:1,addrs:{},names:{}},lookup_name(name){var res=inetPton4(name);if(res!==null){return name}res=inetPton6(name);if(res!==null){return name}var addr;if(DNS.address_map.addrs[name]){addr=DNS.address_map.addrs[name]}else{var id=DNS.address_map.id++;assert(id<65535,"exceeded max address mappings of 65535");addr="172.29."+(id&255)+"."+(id&65280);DNS.address_map.names[addr]=name;DNS.address_map.addrs[name]=addr}return addr},lookup_addr(addr){if(DNS.address_map.names[addr]){return DNS.address_map.names[addr]}return null}};function ___syscall_accept4(fd,addr,addrlen,flags,d1,d2){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var newsock=sock.sock_ops.accept(sock);if(addr){var errno=writeSockaddr(addr,newsock.family,DNS.lookup_name(newsock.daddr),newsock.dport,addrlen)}return newsock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_accept4.sig="iippiii";var inetNtop4=addr=>(addr&255)+"."+(addr>>8&255)+"."+(addr>>16&255)+"."+(addr>>24&255);var inetNtop6=ints=>{var str="";var word=0;var longest=0;var lastzero=0;var zstart=0;var len=0;var i=0;var parts=[ints[0]&65535,ints[0]>>16,ints[1]&65535,ints[1]>>16,ints[2]&65535,ints[2]>>16,ints[3]&65535,ints[3]>>16];var hasipv4=true;var v4part="";for(i=0;i<5;i++){if(parts[i]!==0){hasipv4=false;break}}if(hasipv4){v4part=inetNtop4(parts[6]|parts[7]<<16);if(parts[5]===-1){str="::ffff:";str+=v4part;return str}if(parts[5]===0){str="::";if(v4part==="0.0.0.0")v4part="";if(v4part==="0.0.0.1")v4part="1";str+=v4part;return str}}for(word=0;word<8;word++){if(parts[word]===0){if(word-lastzero>1){len=0}lastzero=word;len++}if(len>longest){longest=len;zstart=word-longest+1}}for(word=0;word<8;word++){if(longest>1){if(parts[word]===0&&word>=zstart&&word{var family=HEAP16[sa>>>1>>>0];var port=_ntohs(HEAPU16[sa+2>>>1>>>0]);var addr;switch(family){case 2:if(salen!==16){return{errno:28}}addr=HEAP32[sa+4>>>2>>>0];addr=inetNtop4(addr);break;case 10:if(salen!==28){return{errno:28}}addr=[HEAP32[sa+8>>>2>>>0],HEAP32[sa+12>>>2>>>0],HEAP32[sa+16>>>2>>>0],HEAP32[sa+20>>>2>>>0]];addr=inetNtop6(addr);break;default:return{errno:5}}return{family,addr,port}};var getSocketAddress=(addrp,addrlen)=>{var info=readSockaddr(addrp,addrlen);if(info.errno)throw new FS.ErrnoError(info.errno);info.addr=DNS.lookup_addr(info.addr)||info.addr;return info};function ___syscall_bind(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.bind(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_bind.sig="iippiii";function ___syscall_chdir(path){path>>>=0;try{path=SYSCALLS.getStr(path);FS.chdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_chdir.sig="ip";function ___syscall_chmod(path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_chmod.sig="ipi";function ___syscall_connect(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.connect(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_connect.sig="iippiii";function ___syscall_dup(fd){try{var old=SYSCALLS.getStreamFromFD(fd);return FS.dupStream(old).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_dup.sig="ii";function ___syscall_dup3(fd,newfd,flags){try{var old=SYSCALLS.getStreamFromFD(fd);if(old.fd===newfd)return-28;if(newfd<0||newfd>=FS.MAX_OPEN_FDS)return-8;var existing=FS.getStream(newfd);if(existing)FS.close(existing);return FS.dupStream(old,newfd).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_dup3.sig="iiii";function ___syscall_faccessat(dirfd,path,amode,flags){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_faccessat.sig="iipii";var ___syscall_fadvise64=(fd,offset,len,advice)=>0;___syscall_fadvise64.sig="iijji";function ___syscall_fallocate(fd,mode,offset,len){offset=bigintToI53Checked(offset);len=bigintToI53Checked(len);try{if(isNaN(offset)||isNaN(len))return-61;if(mode!=0){return-138}if(offset<0||len<0){return-28}var oldSize=FS.fstat(fd).size;var newSize=offset+len;if(newSize>oldSize){FS.ftruncate(fd,newSize)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fallocate.sig="iiijj";function ___syscall_fchdir(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.chdir(stream.path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fchdir.sig="ii";function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fchmod.sig="iii";function ___syscall_fchmodat2(dirfd,path,mode,flags){path>>>=0;try{var nofollow=flags&256;path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);FS.chmod(path,mode,nofollow);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fchmodat2.sig="iipii";function ___syscall_fchown32(fd,owner,group){try{FS.fchown(fd,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fchown32.sig="iiii";function ___syscall_fchownat(dirfd,path,owner,group,flags){path>>>=0;try{path=SYSCALLS.getStr(path);var nofollow=flags&256;flags=flags&~256;path=SYSCALLS.calculateAt(dirfd,path);(nofollow?FS.lchown:FS.chown)(path,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fchownat.sig="iipiii";var syscallGetVarargI=()=>{var ret=HEAP32[+SYSCALLS.varargs>>>2>>>0];SYSCALLS.varargs+=4;return ret};var syscallGetVarargP=syscallGetVarargI;function ___syscall_fcntl64(fd,cmd,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>>1>>>0]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fcntl64.sig="iiip";function ___syscall_fdatasync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fdatasync.sig="ii";function ___syscall_fstat64(fd,buf){buf>>>=0;try{return SYSCALLS.writeStat(buf,FS.fstat(fd))}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fstat64.sig="iip";function ___syscall_fstatfs64(fd,size,buf){size>>>=0;buf>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);SYSCALLS.writeStatFs(buf,FS.statfsStream(stream));return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_fstatfs64.sig="iipp";function ___syscall_ftruncate64(fd,length){length=bigintToI53Checked(length);try{if(isNaN(length))return-61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_ftruncate64.sig="iij";function ___syscall_getcwd(buf,size){buf>>>=0;size>>>=0;try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(size>>=0;count>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);stream.getdents||=FS.readdir(stream.path);var struct_size=280;var pos=0;var off=FS.llseek(stream,0,1);var startIdx=Math.floor(off/struct_size);var endIdx=Math.min(stream.getdents.length,startIdx+Math.floor(count/struct_size));for(var idx=startIdx;idx>>3>>>0]=BigInt(id);HEAP64[dirp+pos+8>>>3>>>0]=BigInt((idx+1)*struct_size);HEAP16[dirp+pos+16>>>1>>>0]=280;HEAP8[dirp+pos+18>>>0]=type;stringToUTF8(name,dirp+pos+19,256);pos+=struct_size}FS.llseek(stream,idx*struct_size,0);return pos}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_getdents64.sig="iipp";function ___syscall_getpeername(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);if(!sock.daddr){return-53}var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.daddr),sock.dport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_getpeername.sig="iippiii";function ___syscall_getsockname(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.saddr||"0.0.0.0"),sock.sport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_getsockname.sig="iippiii";function ___syscall_getsockopt(fd,level,optname,optval,optlen,d1){optval>>>=0;optlen>>>=0;try{var sock=getSocketFromFD(fd);if(level===1){if(optname===4){HEAP32[optval>>>2>>>0]=sock.error;HEAP32[optlen>>>2>>>0]=4;sock.error=null;return 0}}return-50}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_getsockopt.sig="iiiippi";function ___syscall_ioctl(fd,op,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=termios.c_iflag||0;HEAP32[argp+4>>>2>>>0]=termios.c_oflag||0;HEAP32[argp+8>>>2>>>0]=termios.c_cflag||0;HEAP32[argp+12>>>2>>>0]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17>>>0]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>>2>>>0];var c_oflag=HEAP32[argp+4>>>2>>>0];var c_cflag=HEAP32[argp+8>>>2>>>0];var c_lflag=HEAP32[argp+12>>>2>>>0];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17>>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag,c_oflag,c_cflag,c_lflag,c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>>1>>>0]=winsize[0];HEAP16[argp+2>>>1>>>0]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_ioctl.sig="iiip";function ___syscall_listen(fd,backlog){try{var sock=getSocketFromFD(fd);sock.sock_ops.listen(sock,backlog);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_listen.sig="iiiiiii";function ___syscall_lstat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.writeStat(buf,FS.lstat(path))}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_lstat64.sig="ipp";function ___syscall_mkdirat(dirfd,path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);FS.mkdir(path,mode,0);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_mkdirat.sig="iipi";function ___syscall_mknodat(dirfd,path,mode,dev){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_mknodat.sig="iipii";function ___syscall_newfstatat(dirfd,path,buf,flags){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.writeStat(buf,nofollow?FS.lstat(path):FS.stat(path))}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_newfstatat.sig="iippi";function ___syscall_openat(dirfd,path,flags,varargs){path>>>=0;varargs>>>=0;SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_openat.sig="iipip";var PIPEFS={BUCKET_BUFFER_SIZE:8192,mount(mount){return FS.createNode(null,"/",16384|511,0)},createPipe(){var pipe={buckets:[],refcnt:2,timestamp:new Date};pipe.buckets.push({buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:0,roffset:0});var rName=PIPEFS.nextname();var wName=PIPEFS.nextname();var rNode=FS.createNode(PIPEFS.root,rName,4096,0);var wNode=FS.createNode(PIPEFS.root,wName,4096,0);rNode.pipe=pipe;wNode.pipe=pipe;var readableStream=FS.createStream({path:rName,node:rNode,flags:0,seekable:false,stream_ops:PIPEFS.stream_ops});rNode.stream=readableStream;var writableStream=FS.createStream({path:wName,node:wNode,flags:1,seekable:false,stream_ops:PIPEFS.stream_ops});wNode.stream=writableStream;return{readable_fd:readableStream.fd,writable_fd:writableStream.fd}},stream_ops:{getattr(stream){var node=stream.node;var timestamp=node.pipe.timestamp;return{dev:14,ino:node.id,mode:4480,nlink:1,uid:0,gid:0,rdev:0,size:0,atime:timestamp,mtime:timestamp,ctime:timestamp,blksize:4096,blocks:0}},poll(stream){var pipe=stream.node.pipe;if((stream.flags&2097155)===1){return 256|4}for(var bucket of pipe.buckets){if(bucket.offset-bucket.roffset>0){return 64|1}}return 0},dup(stream){stream.node.pipe.refcnt++},ioctl(stream,request,varargs){return 28},fsync(stream){return 28},read(stream,buffer,offset,length,position){var pipe=stream.node.pipe;var currentLength=0;for(var bucket of pipe.buckets){currentLength+=bucket.offset-bucket.roffset}var data=buffer.subarray(offset,offset+length);if(length<=0){return 0}if(currentLength==0){throw new FS.ErrnoError(6)}var toRead=Math.min(currentLength,length);var totalRead=toRead;var toRemove=0;for(var bucket of pipe.buckets){var bucketSize=bucket.offset-bucket.roffset;if(toRead<=bucketSize){var tmpSlice=bucket.buffer.subarray(bucket.roffset,bucket.offset);if(toRead=dataLen){currBucket.buffer.set(data,currBucket.offset);currBucket.offset+=dataLen;return dataLen}else if(freeBytesInCurrBuffer>0){currBucket.buffer.set(data.subarray(0,freeBytesInCurrBuffer),currBucket.offset);currBucket.offset+=freeBytesInCurrBuffer;data=data.subarray(freeBytesInCurrBuffer,data.byteLength)}var numBuckets=data.byteLength/PIPEFS.BUCKET_BUFFER_SIZE|0;var remElements=data.byteLength%PIPEFS.BUCKET_BUFFER_SIZE;for(var i=0;i0){var newBucket={buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:data.byteLength,roffset:0};pipe.buckets.push(newBucket);newBucket.buffer.set(data)}return dataLen},close(stream){var pipe=stream.node.pipe;pipe.refcnt--;if(pipe.refcnt===0){pipe.buckets=null}}},nextname(){if(!PIPEFS.nextname.current){PIPEFS.nextname.current=0}return"pipe["+PIPEFS.nextname.current+++"]"}};function ___syscall_pipe(fdPtr){fdPtr>>>=0;try{if(fdPtr==0){throw new FS.ErrnoError(21)}var res=PIPEFS.createPipe();HEAP32[fdPtr>>>2>>>0]=res.readable_fd;HEAP32[fdPtr+4>>>2>>>0]=res.writable_fd;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_pipe.sig="ip";function ___syscall_poll(fds,nfds,timeout){fds>>>=0;try{var nonzero=0;for(var i=0;i>>2>>>0];var events=HEAP16[pollfd+4>>>1>>>0];var mask=32;var stream=FS.getStream(fd);if(stream){mask=SYSCALLS.DEFAULT_POLLMASK;if(stream.stream_ops.poll){mask=stream.stream_ops.poll(stream,-1)}}mask&=events|8|16;if(mask)nonzero++;HEAP16[pollfd+6>>>1>>>0]=mask}return nonzero}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_poll.sig="ipii";function ___syscall_readlinkat(dirfd,path,buf,bufsize){path>>>=0;buf>>>=0;bufsize>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len>>>0];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len>>>0]=endChar;return len}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_readlinkat.sig="iippp";function ___syscall_recvfrom(fd,buf,len,flags,addr,addrlen){buf>>>=0;len>>>=0;addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var msg=sock.sock_ops.recvmsg(sock,len);if(!msg)return 0;if(addr){var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(msg.addr),msg.port,addrlen)}HEAPU8.set(msg.buffer,buf>>>0);return msg.buffer.byteLength}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_recvfrom.sig="iippipp";function ___syscall_recvmsg(fd,message,flags,d1,d2,d3){message>>>=0;try{var sock=getSocketFromFD(fd);var iov=HEAPU32[message+8>>>2>>>0];var num=HEAP32[message+12>>>2>>>0];var total=0;for(var i=0;i>>2>>>0]}var msg=sock.sock_ops.recvmsg(sock,total);if(!msg)return 0;var name=HEAPU32[message>>>2>>>0];if(name){var errno=writeSockaddr(name,sock.family,DNS.lookup_name(msg.addr),msg.port)}var bytesRead=0;var bytesRemaining=msg.buffer.byteLength;for(var i=0;bytesRemaining>0&&i>>2>>>0];var iovlen=HEAP32[iov+(8*i+4)>>>2>>>0];if(!iovlen){continue}var length=Math.min(iovlen,bytesRemaining);var buf=msg.buffer.subarray(bytesRead,bytesRead+length);HEAPU8.set(buf,iovbase+bytesRead>>>0);bytesRead+=length;bytesRemaining-=length}return bytesRead}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_recvmsg.sig="iipiiii";function ___syscall_renameat(olddirfd,oldpath,newdirfd,newpath){oldpath>>>=0;newpath>>>=0;try{oldpath=SYSCALLS.getStr(oldpath);newpath=SYSCALLS.getStr(newpath);oldpath=SYSCALLS.calculateAt(olddirfd,oldpath);newpath=SYSCALLS.calculateAt(newdirfd,newpath);FS.rename(oldpath,newpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_renameat.sig="iipip";function ___syscall_rmdir(path){path>>>=0;try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_rmdir.sig="ip";function ___syscall_sendmsg(fd,message,flags,d1,d2,d3){message>>>=0;d1>>>=0;d2>>>=0;try{var sock=getSocketFromFD(fd);var iov=HEAPU32[message+8>>>2>>>0];var num=HEAP32[message+12>>>2>>>0];var addr,port;var name=HEAPU32[message>>>2>>>0];var namelen=HEAP32[message+4>>>2>>>0];if(name){var info=getSocketAddress(name,namelen);port=info.port;addr=info.addr}var total=0;for(var i=0;i>>2>>>0]}var view=new Uint8Array(total);var offset=0;for(var i=0;i>>2>>>0];var iovlen=HEAP32[iov+(8*i+4)>>>2>>>0];for(var j=0;j>>0]}}return sock.sock_ops.sendmsg(sock,view,0,total,addr,port)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_sendmsg.sig="iipippi";function ___syscall_sendto(fd,message,length,flags,addr,addr_len){message>>>=0;length>>>=0;addr>>>=0;addr_len>>>=0;try{var sock=getSocketFromFD(fd);if(!addr){return FS.write(sock.stream,HEAP8,message,length)}var dest=getSocketAddress(addr,addr_len);return sock.sock_ops.sendmsg(sock,HEAP8,message,length,dest.addr,dest.port)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_sendto.sig="iippipp";function ___syscall_socket(domain,type,protocol){try{var sock=SOCKFS.createSocket(domain,type,protocol);return sock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_socket.sig="iiiiiii";function ___syscall_stat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.writeStat(buf,FS.stat(path))}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_stat64.sig="ipp";function ___syscall_statfs64(path,size,buf){path>>>=0;size>>>=0;buf>>>=0;try{SYSCALLS.writeStatFs(buf,FS.statfs(SYSCALLS.getStr(path)));return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_statfs64.sig="ippp";function ___syscall_symlinkat(target,dirfd,linkpath){target>>>=0;linkpath>>>=0;try{target=SYSCALLS.getStr(target);linkpath=SYSCALLS.getStr(linkpath);linkpath=SYSCALLS.calculateAt(dirfd,linkpath);FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_symlinkat.sig="ipip";function ___syscall_truncate64(path,length){path>>>=0;length=bigintToI53Checked(length);try{if(isNaN(length))return-61;path=SYSCALLS.getStr(path);FS.truncate(path,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_truncate64.sig="ipj";function ___syscall_unlinkat(dirfd,path,flags){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(!flags){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{return-28}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_unlinkat.sig="iipi";var readI53FromI64=ptr=>HEAPU32[ptr>>>2>>>0]+HEAP32[ptr+4>>>2>>>0]*4294967296;function ___syscall_utimensat(dirfd,path,times,flags){path>>>=0;times>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);var now=Date.now(),atime,mtime;if(!times){atime=now;mtime=now}else{var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>>2>>>0];if(nanoseconds==1073741823){atime=now}else if(nanoseconds==1073741822){atime=null}else{atime=seconds*1e3+nanoseconds/(1e3*1e3)}times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>>2>>>0];if(nanoseconds==1073741823){mtime=now}else if(nanoseconds==1073741822){mtime=null}else{mtime=seconds*1e3+nanoseconds/(1e3*1e3)}}if((mtime??atime)!==null){FS.utime(path,atime,mtime)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}___syscall_utimensat.sig="iippi";var ___table_base=new WebAssembly.Global({value:"i32",mutable:false},1);var __abort_js=()=>abort("");__abort_js.sig="v";var dlSetError=msg=>{var sp=stackSave();var cmsg=stringToUTF8OnStack(msg);___dl_seterr(cmsg,0);stackRestore(sp)};var dlopenInternal=(handle,jsflags)=>{var filename=UTF8ToString(handle+36);var flags=HEAP32[handle+4>>>2>>>0];filename=PATH.normalize(filename);var searchpaths=[];var global=Boolean(flags&256);var localScope=global?null:{};var combinedFlags={global,nodelete:Boolean(flags&4096),loadAsync:jsflags.loadAsync};if(jsflags.loadAsync){return loadDynamicLibrary(filename,combinedFlags,localScope,handle)}try{return loadDynamicLibrary(filename,combinedFlags,localScope,handle)}catch(e){dlSetError(`Could not load dynamic lib: ${filename}\n${e}`);return 0}};function __dlopen_js(handle){handle>>>=0;return dlopenInternal(handle,{loadAsync:false})}__dlopen_js.sig="pp";function __dlsym_js(handle,symbol,symbolIndex){handle>>>=0;symbol>>>=0;symbolIndex>>>=0;symbol=UTF8ToString(symbol);var result;var newSymIndex;var lib=LDSO.loadedLibsByHandle[handle];if(!lib.exports.hasOwnProperty(symbol)||lib.exports[symbol].stub){dlSetError(`Tried to lookup unknown symbol "${symbol}" in dynamic lib: ${lib.name}`);return 0}newSymIndex=Object.keys(lib.exports).indexOf(symbol);result=lib.exports[symbol];if(typeof result=="function"){var addr=getFunctionAddress(result);if(addr){result=addr}else{result=addFunction(result,result.sig);HEAPU32[symbolIndex>>>2>>>0]=newSymIndex}}return result}__dlsym_js.sig="pppp";var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};_proc_exit.sig="vi";var exitJS=(status,implicit)=>{EXITSTATUS=status;if(!keepRuntimeAlive()){exitRuntime()}_proc_exit(status)};var _exit=exitJS;_exit.sig="vi";var maybeExit=()=>{if(runtimeExited){return}if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(runtimeExited||ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var runtimeKeepalivePush=()=>{runtimeKeepaliveCounter+=1};runtimeKeepalivePush.sig="v";var runtimeKeepalivePop=()=>{runtimeKeepaliveCounter-=1};runtimeKeepalivePop.sig="v";function __emscripten_dlopen_js(handle,onsuccess,onerror,user_data){handle>>>=0;onsuccess>>>=0;onerror>>>=0;user_data>>>=0;function errorCallback(e){var filename=UTF8ToString(handle+36);dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`);runtimeKeepalivePop();callUserCallback(()=>getWasmTableEntry(onerror)(handle,user_data))}function successCallback(){runtimeKeepalivePop();callUserCallback(()=>getWasmTableEntry(onsuccess)(handle,user_data))}runtimeKeepalivePush();var promise=dlopenInternal(handle,{loadAsync:true});if(promise){promise.then(successCallback,errorCallback)}else{errorCallback()}}__emscripten_dlopen_js.sig="vpppp";var getExecutableName=()=>thisProgram||"./this.program";function __emscripten_get_progname(str,len){str>>>=0;return stringToUTF8(getExecutableName(),str,len)}__emscripten_get_progname.sig="vpi";function __emscripten_lookup_name(name){name>>>=0;var nameString=UTF8ToString(name);return inetPton4(DNS.lookup_name(nameString))}__emscripten_lookup_name.sig="ip";var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};__emscripten_runtime_keepalive_clear.sig="v";function __emscripten_system(command){command>>>=0;if(ENVIRONMENT_IS_NODE){if(!command)return 1;var cmdstr=UTF8ToString(command);if(!cmdstr.length)return 0;var cp=require("child_process");var ret=cp.spawnSync(cmdstr,[],{shell:true,stdio:"inherit"});var _W_EXITCODE=(ret,sig)=>ret<<8|sig;if(ret.status===null){var signalToNumber=sig=>{switch(sig){case"SIGHUP":return 1;case"SIGQUIT":return 3;case"SIGFPE":return 8;case"SIGKILL":return 9;case"SIGALRM":return 14;case"SIGTERM":return 15;default:return 2}};return _W_EXITCODE(0,signalToNumber(ret.signal))}return _W_EXITCODE(ret.status,0)}if(!command)return 0;return-52}__emscripten_system.sig="ip";function __gmtime_js(time,tmPtr){time=bigintToI53Checked(time);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getUTCSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getUTCMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getUTCHours();HEAP32[tmPtr+12>>>2>>>0]=date.getUTCDate();HEAP32[tmPtr+16>>>2>>>0]=date.getUTCMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>>2>>>0]=yday}__gmtime_js.sig="vjp";var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time,tmPtr){time=bigintToI53Checked(time);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr+36>>>2>>>0]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>>2>>>0]=dst}__localtime_js.sig="vjp";var __mktime_js=function(tmPtr){tmPtr>>>=0;var ret=(()=>{var date=new Date(HEAP32[tmPtr+20>>>2>>>0]+1900,HEAP32[tmPtr+16>>>2>>>0],HEAP32[tmPtr+12>>>2>>>0],HEAP32[tmPtr+8>>>2>>>0],HEAP32[tmPtr+4>>>2>>>0],HEAP32[tmPtr>>>2>>>0],0);var dst=HEAP32[tmPtr+32>>>2>>>0];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>>2>>>0]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getYear();var timeMs=date.getTime();if(isNaN(timeMs)){return-1}return timeMs/1e3})();return BigInt(ret)};__mktime_js.sig="jp";function __mmap_js(len,prot,flags,fd,offset,allocated,addr){len>>>=0;offset=bigintToI53Checked(offset);allocated>>>=0;addr>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>>2>>>0]=res.allocated;HEAPU32[addr>>>2>>>0]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}__mmap_js.sig="ipiiijpp";function __msync_js(addr,len,prot,flags,fd,offset){addr>>>=0;len>>>=0;offset=bigintToI53Checked(offset);try{if(isNaN(offset))return-61;SYSCALLS.doMsync(addr,SYSCALLS.getStreamFromFD(fd),len,flags,offset);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}__msync_js.sig="ippiiij";function __munmap_js(addr,len,prot,flags,fd,offset){addr>>>=0;len>>>=0;offset=bigintToI53Checked(offset);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}__munmap_js.sig="ippiiij";var timers={};var _emscripten_get_now=()=>performance.now();_emscripten_get_now.sig="d";var __setitimer_js=(which,timeout_ms)=>{if(timers[which]){clearTimeout(timers[which].id);delete timers[which]}if(!timeout_ms)return 0;var id=setTimeout(()=>{delete timers[which];callUserCallback(()=>__emscripten_timeout(which,_emscripten_get_now()))},timeout_ms);timers[which]={id,timeout_ms};return 0};__setitimer_js.sig="iid";var __timegm_js=function(tmPtr){tmPtr>>>=0;var ret=(()=>{var time=Date.UTC(HEAP32[tmPtr+20>>>2>>>0]+1900,HEAP32[tmPtr+16>>>2>>>0],HEAP32[tmPtr+12>>>2>>>0],HEAP32[tmPtr+8>>>2>>>0],HEAP32[tmPtr+4>>>2>>>0],HEAP32[tmPtr>>>2>>>0],0);var date=new Date(time);HEAP32[tmPtr+24>>>2>>>0]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;return date.getTime()/1e3})();return BigInt(ret)};__timegm_js.sig="jp";var __tzset_js=function(timezone,daylight,std_name,dst_name){timezone>>>=0;daylight>>>=0;std_name>>>=0;dst_name>>>=0;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>>2>>>0]=stdTimezoneOffset*60;HEAP32[daylight>>>2>>>0]=Number(winterOffset!=summerOffset);var extractZone=timezoneOffset=>{var sign=timezoneOffset>=0?"-":"+";var absOffset=Math.abs(timezoneOffset);var hours=String(Math.floor(absOffset/60)).padStart(2,"0");var minutes=String(absOffset%60).padStart(2,"0");return`UTC${sign}${hours}${minutes}`};var winterName=extractZone(winterOffset);var summerName=extractZone(summerOffset);if(summerOffset{if(ENVIRONMENT_IS_NODE){return 1}return 1e3};_emscripten_get_now_res.sig="d";var nowIsMonotonic=1;var checkWasiClock=clock_id=>clock_id>=0&&clock_id<=3;function _clock_res_get(clk_id,pres){pres>>>=0;if(!checkWasiClock(clk_id)){return 28}var nsec;if(clk_id===0){nsec=1e3*1e3}else if(nowIsMonotonic){nsec=_emscripten_get_now_res()}else{return 52}HEAP64[pres>>>3>>>0]=BigInt(nsec);return 0}_clock_res_get.sig="iip";var _emscripten_date_now=()=>Date.now();_emscripten_date_now.sig="d";function _clock_time_get(clk_id,ignored_precision,ptime){ignored_precision=bigintToI53Checked(ignored_precision);ptime>>>=0;if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=_emscripten_date_now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);HEAP64[ptime>>>3>>>0]=BigInt(nsec);return 0}_clock_time_get.sig="iijp";function _create_sentinel(...args){return wasmImports["create_sentinel"](...args)}_create_sentinel.stub=true;var readEmAsmArgsArray=[];var readEmAsmArgs=(sigPtr,buf)=>{readEmAsmArgsArray.length=0;var ch;while(ch=HEAPU8[sigPtr++>>>0]){var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?HEAPU32[buf>>>2>>>0]:ch==106?HEAP64[buf>>>3>>>0]:ch==105?HEAP32[buf>>>2>>>0]:HEAPF64[buf>>>3>>>0]);buf+=wide?8:4}return readEmAsmArgsArray};var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code](...args)};function _emscripten_asm_const_int(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}_emscripten_asm_const_int.sig="ippp";function _emscripten_console_error(str){str>>>=0;console.error(UTF8ToString(str))}_emscripten_console_error.sig="vp";function _emscripten_console_log(str){str>>>=0;console.log(UTF8ToString(str))}_emscripten_console_log.sig="vp";function _emscripten_console_trace(str){str>>>=0;console.trace(UTF8ToString(str))}_emscripten_console_trace.sig="vp";function _emscripten_console_warn(str){str>>>=0;console.warn(UTF8ToString(str))}_emscripten_console_warn.sig="vp";function _emscripten_err(str){str>>>=0;return err(UTF8ToString(str))}_emscripten_err.sig="vp";var getHeapMax=()=>4294901760;function _emscripten_get_heap_max(){return getHeapMax()}_emscripten_get_heap_max.sig="p";var GLctx;var webgl_enable_ANGLE_instanced_arrays=ctx=>{var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=(index,divisor)=>ext["vertexAttribDivisorANGLE"](index,divisor);ctx["drawArraysInstanced"]=(mode,first,count,primcount)=>ext["drawArraysInstancedANGLE"](mode,first,count,primcount);ctx["drawElementsInstanced"]=(mode,count,type,indices,primcount)=>ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount);return 1}};var webgl_enable_OES_vertex_array_object=ctx=>{var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=()=>ext["createVertexArrayOES"]();ctx["deleteVertexArray"]=vao=>ext["deleteVertexArrayOES"](vao);ctx["bindVertexArray"]=vao=>ext["bindVertexArrayOES"](vao);ctx["isVertexArray"]=vao=>ext["isVertexArrayOES"](vao);return 1}};var webgl_enable_WEBGL_draw_buffers=ctx=>{var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=(n,bufs)=>ext["drawBuffersWEBGL"](n,bufs);return 1}};var webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.dibvbi=ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"));var webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.mdibvbi=ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"));var webgl_enable_EXT_polygon_offset_clamp=ctx=>!!(ctx.extPolygonOffsetClamp=ctx.getExtension("EXT_polygon_offset_clamp"));var webgl_enable_EXT_clip_control=ctx=>!!(ctx.extClipControl=ctx.getExtension("EXT_clip_control"));var webgl_enable_WEBGL_polygon_mode=ctx=>!!(ctx.webglPolygonMode=ctx.getExtension("WEBGL_polygon_mode"));var webgl_enable_WEBGL_multi_draw=ctx=>!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"));var getEmscriptenSupportedExtensions=ctx=>{var supportedExtensions=["ANGLE_instanced_arrays","EXT_blend_minmax","EXT_disjoint_timer_query","EXT_frag_depth","EXT_shader_texture_lod","EXT_sRGB","OES_element_index_uint","OES_fbo_render_mipmap","OES_standard_derivatives","OES_texture_float","OES_texture_half_float","OES_texture_half_float_linear","OES_vertex_array_object","WEBGL_color_buffer_float","WEBGL_depth_texture","WEBGL_draw_buffers","EXT_color_buffer_float","EXT_conservative_depth","EXT_disjoint_timer_query_webgl2","EXT_texture_norm16","NV_shader_noperspective_interpolation","WEBGL_clip_cull_distance","EXT_clip_control","EXT_color_buffer_half_float","EXT_depth_clamp","EXT_float_blend","EXT_polygon_offset_clamp","EXT_texture_compression_bptc","EXT_texture_compression_rgtc","EXT_texture_filter_anisotropic","KHR_parallel_shader_compile","OES_texture_float_linear","WEBGL_blend_func_extended","WEBGL_compressed_texture_astc","WEBGL_compressed_texture_etc","WEBGL_compressed_texture_etc1","WEBGL_compressed_texture_s3tc","WEBGL_compressed_texture_s3tc_srgb","WEBGL_debug_renderer_info","WEBGL_debug_shaders","WEBGL_lose_context","WEBGL_multi_draw","WEBGL_polygon_mode"];return(ctx.getSupportedExtensions()||[]).filter(ext=>supportedExtensions.includes(ext))};var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],stringCache:{},stringiCache:{},unpackAlignment:4,unpackRowLength:0,recordError:errorCode=>{if(!GL.lastError){GL.lastError=errorCode}},getNewId:table=>{var ret=GL.counter++;for(var i=table.length;i{for(var i=0;i>>2>>>0]=id}},getSource:(shader,count,string,length)=>{var source="";for(var i=0;i>>2>>>0]:undefined;source+=UTF8ToString(HEAPU32[string+i*4>>>2>>>0],len)}return source},createContext:(canvas,webGLContextAttributes)=>{var ctx=webGLContextAttributes.majorVersion>1?canvas.getContext("webgl2",webGLContextAttributes):canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:(ctx,webGLContextAttributes)=>{var handle=GL.getNewId(GL.contexts);var context={handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}return handle},makeContextCurrent:contextHandle=>{GL.currentContext=GL.contexts[contextHandle];Module["ctx"]=GLctx=GL.currentContext?.GLctx;return!(contextHandle&&!GLctx)},getContext:contextHandle=>GL.contexts[contextHandle],deleteContext:contextHandle=>{if(GL.currentContext===GL.contexts[contextHandle]){GL.currentContext=null}if(typeof JSEvents=="object"){JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas)}if(GL.contexts[contextHandle]?.GLctx.canvas){GL.contexts[contextHandle].GLctx.canvas.GLctxObject=undefined}GL.contexts[contextHandle]=null},initExtensions:context=>{context||=GL.currentContext;if(context.initExtensionsDone)return;context.initExtensionsDone=true;var GLctx=context.GLctx;webgl_enable_WEBGL_multi_draw(GLctx);webgl_enable_EXT_polygon_offset_clamp(GLctx);webgl_enable_EXT_clip_control(GLctx);webgl_enable_WEBGL_polygon_mode(GLctx);webgl_enable_ANGLE_instanced_arrays(GLctx);webgl_enable_OES_vertex_array_object(GLctx);webgl_enable_WEBGL_draw_buffers(GLctx);webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);if(context.version>=2){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query_webgl2")}if(context.version<2||!GLctx.disjointTimerQueryExt){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}getEmscriptenSupportedExtensions(GLctx).forEach(ext=>{if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};var _glActiveTexture=x0=>GLctx.activeTexture(x0);_glActiveTexture.sig="vi";var _emscripten_glActiveTexture=_glActiveTexture;_emscripten_glActiveTexture.sig="vi";var _glAttachShader=(program,shader)=>{GLctx.attachShader(GL.programs[program],GL.shaders[shader])};_glAttachShader.sig="vii";var _emscripten_glAttachShader=_glAttachShader;_emscripten_glAttachShader.sig="vii";var _glBeginQuery=(target,id)=>{GLctx.beginQuery(target,GL.queries[id])};_glBeginQuery.sig="vii";var _emscripten_glBeginQuery=_glBeginQuery;_emscripten_glBeginQuery.sig="vii";var _glBeginQueryEXT=(target,id)=>{GLctx.disjointTimerQueryExt["beginQueryEXT"](target,GL.queries[id])};_glBeginQueryEXT.sig="vii";var _emscripten_glBeginQueryEXT=_glBeginQueryEXT;var _glBeginTransformFeedback=x0=>GLctx.beginTransformFeedback(x0);_glBeginTransformFeedback.sig="vi";var _emscripten_glBeginTransformFeedback=_glBeginTransformFeedback;_emscripten_glBeginTransformFeedback.sig="vi";function _glBindAttribLocation(program,index,name){name>>>=0;GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}_glBindAttribLocation.sig="viip";var _emscripten_glBindAttribLocation=_glBindAttribLocation;_emscripten_glBindAttribLocation.sig="viip";var _glBindBuffer=(target,buffer)=>{if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])};_glBindBuffer.sig="vii";var _emscripten_glBindBuffer=_glBindBuffer;_emscripten_glBindBuffer.sig="vii";var _glBindBufferBase=(target,index,buffer)=>{GLctx.bindBufferBase(target,index,GL.buffers[buffer])};_glBindBufferBase.sig="viii";var _emscripten_glBindBufferBase=_glBindBufferBase;_emscripten_glBindBufferBase.sig="viii";function _glBindBufferRange(target,index,buffer,offset,ptrsize){offset>>>=0;ptrsize>>>=0;GLctx.bindBufferRange(target,index,GL.buffers[buffer],offset,ptrsize)}_glBindBufferRange.sig="viiipp";var _emscripten_glBindBufferRange=_glBindBufferRange;_emscripten_glBindBufferRange.sig="viiipp";var _glBindFramebuffer=(target,framebuffer)=>{GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])};_glBindFramebuffer.sig="vii";var _emscripten_glBindFramebuffer=_glBindFramebuffer;_emscripten_glBindFramebuffer.sig="vii";var _glBindRenderbuffer=(target,renderbuffer)=>{GLctx.bindRenderbuffer(target,GL.renderbuffers[renderbuffer])};_glBindRenderbuffer.sig="vii";var _emscripten_glBindRenderbuffer=_glBindRenderbuffer;_emscripten_glBindRenderbuffer.sig="vii";var _glBindSampler=(unit,sampler)=>{GLctx.bindSampler(unit,GL.samplers[sampler])};_glBindSampler.sig="vii";var _emscripten_glBindSampler=_glBindSampler;_emscripten_glBindSampler.sig="vii";var _glBindTexture=(target,texture)=>{GLctx.bindTexture(target,GL.textures[texture])};_glBindTexture.sig="vii";var _emscripten_glBindTexture=_glBindTexture;_emscripten_glBindTexture.sig="vii";var _glBindTransformFeedback=(target,id)=>{GLctx.bindTransformFeedback(target,GL.transformFeedbacks[id])};_glBindTransformFeedback.sig="vii";var _emscripten_glBindTransformFeedback=_glBindTransformFeedback;_emscripten_glBindTransformFeedback.sig="vii";var _glBindVertexArray=vao=>{GLctx.bindVertexArray(GL.vaos[vao])};_glBindVertexArray.sig="vi";var _emscripten_glBindVertexArray=_glBindVertexArray;_emscripten_glBindVertexArray.sig="vi";var _glBindVertexArrayOES=_glBindVertexArray;_glBindVertexArrayOES.sig="vi";var _emscripten_glBindVertexArrayOES=_glBindVertexArrayOES;_emscripten_glBindVertexArrayOES.sig="vi";var _glBlendColor=(x0,x1,x2,x3)=>GLctx.blendColor(x0,x1,x2,x3);_glBlendColor.sig="vffff";var _emscripten_glBlendColor=_glBlendColor;_emscripten_glBlendColor.sig="vffff";var _glBlendEquation=x0=>GLctx.blendEquation(x0);_glBlendEquation.sig="vi";var _emscripten_glBlendEquation=_glBlendEquation;_emscripten_glBlendEquation.sig="vi";var _glBlendEquationSeparate=(x0,x1)=>GLctx.blendEquationSeparate(x0,x1);_glBlendEquationSeparate.sig="vii";var _emscripten_glBlendEquationSeparate=_glBlendEquationSeparate;_emscripten_glBlendEquationSeparate.sig="vii";var _glBlendFunc=(x0,x1)=>GLctx.blendFunc(x0,x1);_glBlendFunc.sig="vii";var _emscripten_glBlendFunc=_glBlendFunc;_emscripten_glBlendFunc.sig="vii";var _glBlendFuncSeparate=(x0,x1,x2,x3)=>GLctx.blendFuncSeparate(x0,x1,x2,x3);_glBlendFuncSeparate.sig="viiii";var _emscripten_glBlendFuncSeparate=_glBlendFuncSeparate;_emscripten_glBlendFuncSeparate.sig="viiii";var _glBlitFramebuffer=(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)=>GLctx.blitFramebuffer(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);_glBlitFramebuffer.sig="viiiiiiiiii";var _emscripten_glBlitFramebuffer=_glBlitFramebuffer;_emscripten_glBlitFramebuffer.sig="viiiiiiiiii";function _glBufferData(target,size,data,usage){size>>>=0;data>>>=0;GLctx.bufferData(target,data?HEAPU8.subarray(data>>>0,data+size>>>0):size,usage)}_glBufferData.sig="vippi";var _emscripten_glBufferData=_glBufferData;_emscripten_glBufferData.sig="vippi";function _glBufferSubData(target,offset,size,data){offset>>>=0;size>>>=0;data>>>=0;GLctx.bufferSubData(target,offset,HEAPU8.subarray(data>>>0,data+size>>>0))}_glBufferSubData.sig="vippp";var _emscripten_glBufferSubData=_glBufferSubData;_emscripten_glBufferSubData.sig="vippp";var _glCheckFramebufferStatus=x0=>GLctx.checkFramebufferStatus(x0);_glCheckFramebufferStatus.sig="ii";var _emscripten_glCheckFramebufferStatus=_glCheckFramebufferStatus;_emscripten_glCheckFramebufferStatus.sig="ii";var _glClear=x0=>GLctx.clear(x0);_glClear.sig="vi";var _emscripten_glClear=_glClear;_emscripten_glClear.sig="vi";var _glClearBufferfi=(x0,x1,x2,x3)=>GLctx.clearBufferfi(x0,x1,x2,x3);_glClearBufferfi.sig="viifi";var _emscripten_glClearBufferfi=_glClearBufferfi;_emscripten_glClearBufferfi.sig="viifi";function _glClearBufferfv(buffer,drawbuffer,value){value>>>=0;GLctx.clearBufferfv(buffer,drawbuffer,HEAPF32,value>>>2)}_glClearBufferfv.sig="viip";var _emscripten_glClearBufferfv=_glClearBufferfv;_emscripten_glClearBufferfv.sig="viip";function _glClearBufferiv(buffer,drawbuffer,value){value>>>=0;GLctx.clearBufferiv(buffer,drawbuffer,HEAP32,value>>>2)}_glClearBufferiv.sig="viip";var _emscripten_glClearBufferiv=_glClearBufferiv;_emscripten_glClearBufferiv.sig="viip";function _glClearBufferuiv(buffer,drawbuffer,value){value>>>=0;GLctx.clearBufferuiv(buffer,drawbuffer,HEAPU32,value>>>2)}_glClearBufferuiv.sig="viip";var _emscripten_glClearBufferuiv=_glClearBufferuiv;_emscripten_glClearBufferuiv.sig="viip";var _glClearColor=(x0,x1,x2,x3)=>GLctx.clearColor(x0,x1,x2,x3);_glClearColor.sig="vffff";var _emscripten_glClearColor=_glClearColor;_emscripten_glClearColor.sig="vffff";var _glClearDepthf=x0=>GLctx.clearDepth(x0);_glClearDepthf.sig="vf";var _emscripten_glClearDepthf=_glClearDepthf;_emscripten_glClearDepthf.sig="vf";var _glClearStencil=x0=>GLctx.clearStencil(x0);_glClearStencil.sig="vi";var _emscripten_glClearStencil=_glClearStencil;_emscripten_glClearStencil.sig="vi";function _glClientWaitSync(sync,flags,timeout){sync>>>=0;timeout=Number(timeout);return GLctx.clientWaitSync(GL.syncs[sync],flags,timeout)}_glClientWaitSync.sig="ipij";var _emscripten_glClientWaitSync=_glClientWaitSync;_emscripten_glClientWaitSync.sig="ipij";var _glClipControlEXT=(origin,depth)=>{GLctx.extClipControl["clipControlEXT"](origin,depth)};_glClipControlEXT.sig="vii";var _emscripten_glClipControlEXT=_glClipControlEXT;var _glColorMask=(red,green,blue,alpha)=>{GLctx.colorMask(!!red,!!green,!!blue,!!alpha)};_glColorMask.sig="viiii";var _emscripten_glColorMask=_glColorMask;_emscripten_glColorMask.sig="viiii";var _glCompileShader=shader=>{GLctx.compileShader(GL.shaders[shader])};_glCompileShader.sig="vi";var _emscripten_glCompileShader=_glCompileShader;_emscripten_glCompileShader.sig="vi";function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){data>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data);return}}GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,HEAPU8.subarray(data>>>0,data+imageSize>>>0))}_glCompressedTexImage2D.sig="viiiiiiip";var _emscripten_glCompressedTexImage2D=_glCompressedTexImage2D;_emscripten_glCompressedTexImage2D.sig="viiiiiiip";function _glCompressedTexImage3D(target,level,internalFormat,width,height,depth,border,imageSize,data){data>>>=0;if(GLctx.currentPixelUnpackBufferBinding){GLctx.compressedTexImage3D(target,level,internalFormat,width,height,depth,border,imageSize,data)}else{GLctx.compressedTexImage3D(target,level,internalFormat,width,height,depth,border,HEAPU8,data,imageSize)}}_glCompressedTexImage3D.sig="viiiiiiiip";var _emscripten_glCompressedTexImage3D=_glCompressedTexImage3D;_emscripten_glCompressedTexImage3D.sig="viiiiiiiip";function _glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){data>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx.compressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data);return}}GLctx.compressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,HEAPU8.subarray(data>>>0,data+imageSize>>>0))}_glCompressedTexSubImage2D.sig="viiiiiiiip";var _emscripten_glCompressedTexSubImage2D=_glCompressedTexSubImage2D;_emscripten_glCompressedTexSubImage2D.sig="viiiiiiiip";function _glCompressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data){data>>>=0;if(GLctx.currentPixelUnpackBufferBinding){GLctx.compressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data)}else{GLctx.compressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,HEAPU8,data,imageSize)}}_glCompressedTexSubImage3D.sig="viiiiiiiiiip";var _emscripten_glCompressedTexSubImage3D=_glCompressedTexSubImage3D;_emscripten_glCompressedTexSubImage3D.sig="viiiiiiiiiip";function _glCopyBufferSubData(x0,x1,x2,x3,x4){x2>>>=0;x3>>>=0;x4>>>=0;return GLctx.copyBufferSubData(x0,x1,x2,x3,x4)}_glCopyBufferSubData.sig="viippp";var _emscripten_glCopyBufferSubData=_glCopyBufferSubData;_emscripten_glCopyBufferSubData.sig="viippp";var _glCopyTexImage2D=(x0,x1,x2,x3,x4,x5,x6,x7)=>GLctx.copyTexImage2D(x0,x1,x2,x3,x4,x5,x6,x7);_glCopyTexImage2D.sig="viiiiiiii";var _emscripten_glCopyTexImage2D=_glCopyTexImage2D;_emscripten_glCopyTexImage2D.sig="viiiiiiii";var _glCopyTexSubImage2D=(x0,x1,x2,x3,x4,x5,x6,x7)=>GLctx.copyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7);_glCopyTexSubImage2D.sig="viiiiiiii";var _emscripten_glCopyTexSubImage2D=_glCopyTexSubImage2D;_emscripten_glCopyTexSubImage2D.sig="viiiiiiii";var _glCopyTexSubImage3D=(x0,x1,x2,x3,x4,x5,x6,x7,x8)=>GLctx.copyTexSubImage3D(x0,x1,x2,x3,x4,x5,x6,x7,x8);_glCopyTexSubImage3D.sig="viiiiiiiii";var _emscripten_glCopyTexSubImage3D=_glCopyTexSubImage3D;_emscripten_glCopyTexSubImage3D.sig="viiiiiiiii";var _glCreateProgram=()=>{var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id};_glCreateProgram.sig="i";var _emscripten_glCreateProgram=_glCreateProgram;_emscripten_glCreateProgram.sig="i";var _glCreateShader=shaderType=>{var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id};_glCreateShader.sig="ii";var _emscripten_glCreateShader=_glCreateShader;_emscripten_glCreateShader.sig="ii";var _glCullFace=x0=>GLctx.cullFace(x0);_glCullFace.sig="vi";var _emscripten_glCullFace=_glCullFace;_emscripten_glCullFace.sig="vi";function _glDeleteBuffers(n,buffers){buffers>>>=0;for(var i=0;i>>2>>>0];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}_glDeleteBuffers.sig="vip";var _emscripten_glDeleteBuffers=_glDeleteBuffers;_emscripten_glDeleteBuffers.sig="vip";function _glDeleteFramebuffers(n,framebuffers){framebuffers>>>=0;for(var i=0;i>>2>>>0];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}_glDeleteFramebuffers.sig="vip";var _emscripten_glDeleteFramebuffers=_glDeleteFramebuffers;_emscripten_glDeleteFramebuffers.sig="vip";var _glDeleteProgram=id=>{if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null};_glDeleteProgram.sig="vi";var _emscripten_glDeleteProgram=_glDeleteProgram;_emscripten_glDeleteProgram.sig="vi";function _glDeleteQueries(n,ids){ids>>>=0;for(var i=0;i>>2>>>0];var query=GL.queries[id];if(!query)continue;GLctx.deleteQuery(query);GL.queries[id]=null}}_glDeleteQueries.sig="vip";var _emscripten_glDeleteQueries=_glDeleteQueries;_emscripten_glDeleteQueries.sig="vip";function _glDeleteQueriesEXT(n,ids){ids>>>=0;for(var i=0;i>>2>>>0];var query=GL.queries[id];if(!query)continue;GLctx.disjointTimerQueryExt["deleteQueryEXT"](query);GL.queries[id]=null}}_glDeleteQueriesEXT.sig="vip";var _emscripten_glDeleteQueriesEXT=_glDeleteQueriesEXT;function _glDeleteRenderbuffers(n,renderbuffers){renderbuffers>>>=0;for(var i=0;i>>2>>>0];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}_glDeleteRenderbuffers.sig="vip";var _emscripten_glDeleteRenderbuffers=_glDeleteRenderbuffers;_emscripten_glDeleteRenderbuffers.sig="vip";function _glDeleteSamplers(n,samplers){samplers>>>=0;for(var i=0;i>>2>>>0];var sampler=GL.samplers[id];if(!sampler)continue;GLctx.deleteSampler(sampler);sampler.name=0;GL.samplers[id]=null}}_glDeleteSamplers.sig="vip";var _emscripten_glDeleteSamplers=_glDeleteSamplers;_emscripten_glDeleteSamplers.sig="vip";var _glDeleteShader=id=>{if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null};_glDeleteShader.sig="vi";var _emscripten_glDeleteShader=_glDeleteShader;_emscripten_glDeleteShader.sig="vi";function _glDeleteSync(id){id>>>=0;if(!id)return;var sync=GL.syncs[id];if(!sync){GL.recordError(1281);return}GLctx.deleteSync(sync);sync.name=0;GL.syncs[id]=null}_glDeleteSync.sig="vp";var _emscripten_glDeleteSync=_glDeleteSync;_emscripten_glDeleteSync.sig="vp";function _glDeleteTextures(n,textures){textures>>>=0;for(var i=0;i>>2>>>0];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}_glDeleteTextures.sig="vip";var _emscripten_glDeleteTextures=_glDeleteTextures;_emscripten_glDeleteTextures.sig="vip";function _glDeleteTransformFeedbacks(n,ids){ids>>>=0;for(var i=0;i>>2>>>0];var transformFeedback=GL.transformFeedbacks[id];if(!transformFeedback)continue;GLctx.deleteTransformFeedback(transformFeedback);transformFeedback.name=0;GL.transformFeedbacks[id]=null}}_glDeleteTransformFeedbacks.sig="vip";var _emscripten_glDeleteTransformFeedbacks=_glDeleteTransformFeedbacks;_emscripten_glDeleteTransformFeedbacks.sig="vip";function _glDeleteVertexArrays(n,vaos){vaos>>>=0;for(var i=0;i>>2>>>0];GLctx.deleteVertexArray(GL.vaos[id]);GL.vaos[id]=null}}_glDeleteVertexArrays.sig="vip";var _emscripten_glDeleteVertexArrays=_glDeleteVertexArrays;_emscripten_glDeleteVertexArrays.sig="vip";var _glDeleteVertexArraysOES=_glDeleteVertexArrays;_glDeleteVertexArraysOES.sig="vip";var _emscripten_glDeleteVertexArraysOES=_glDeleteVertexArraysOES;_emscripten_glDeleteVertexArraysOES.sig="vip";var _glDepthFunc=x0=>GLctx.depthFunc(x0);_glDepthFunc.sig="vi";var _emscripten_glDepthFunc=_glDepthFunc;_emscripten_glDepthFunc.sig="vi";var _glDepthMask=flag=>{GLctx.depthMask(!!flag)};_glDepthMask.sig="vi";var _emscripten_glDepthMask=_glDepthMask;_emscripten_glDepthMask.sig="vi";var _glDepthRangef=(x0,x1)=>GLctx.depthRange(x0,x1);_glDepthRangef.sig="vff";var _emscripten_glDepthRangef=_glDepthRangef;_emscripten_glDepthRangef.sig="vff";var _glDetachShader=(program,shader)=>{GLctx.detachShader(GL.programs[program],GL.shaders[shader])};_glDetachShader.sig="vii";var _emscripten_glDetachShader=_glDetachShader;_emscripten_glDetachShader.sig="vii";var _glDisable=x0=>GLctx.disable(x0);_glDisable.sig="vi";var _emscripten_glDisable=_glDisable;_emscripten_glDisable.sig="vi";var _glDisableVertexAttribArray=index=>{GLctx.disableVertexAttribArray(index)};_glDisableVertexAttribArray.sig="vi";var _emscripten_glDisableVertexAttribArray=_glDisableVertexAttribArray;_emscripten_glDisableVertexAttribArray.sig="vi";var _glDrawArrays=(mode,first,count)=>{GLctx.drawArrays(mode,first,count)};_glDrawArrays.sig="viii";var _emscripten_glDrawArrays=_glDrawArrays;_emscripten_glDrawArrays.sig="viii";var _glDrawArraysInstanced=(mode,first,count,primcount)=>{GLctx.drawArraysInstanced(mode,first,count,primcount)};_glDrawArraysInstanced.sig="viiii";var _emscripten_glDrawArraysInstanced=_glDrawArraysInstanced;_emscripten_glDrawArraysInstanced.sig="viiii";var _glDrawArraysInstancedANGLE=_glDrawArraysInstanced;var _emscripten_glDrawArraysInstancedANGLE=_glDrawArraysInstancedANGLE;var _glDrawArraysInstancedARB=_glDrawArraysInstanced;var _emscripten_glDrawArraysInstancedARB=_glDrawArraysInstancedARB;var _glDrawArraysInstancedEXT=_glDrawArraysInstanced;var _emscripten_glDrawArraysInstancedEXT=_glDrawArraysInstancedEXT;var _glDrawArraysInstancedNV=_glDrawArraysInstanced;var _emscripten_glDrawArraysInstancedNV=_glDrawArraysInstancedNV;var tempFixedLengthArray=[];function _glDrawBuffers(n,bufs){bufs>>>=0;var bufArray=tempFixedLengthArray[n];for(var i=0;i>>2>>>0]}GLctx.drawBuffers(bufArray)}_glDrawBuffers.sig="vip";var _emscripten_glDrawBuffers=_glDrawBuffers;_emscripten_glDrawBuffers.sig="vip";var _glDrawBuffersEXT=_glDrawBuffers;var _emscripten_glDrawBuffersEXT=_glDrawBuffersEXT;var _glDrawBuffersWEBGL=_glDrawBuffers;var _emscripten_glDrawBuffersWEBGL=_glDrawBuffersWEBGL;function _glDrawElements(mode,count,type,indices){indices>>>=0;GLctx.drawElements(mode,count,type,indices)}_glDrawElements.sig="viiip";var _emscripten_glDrawElements=_glDrawElements;_emscripten_glDrawElements.sig="viiip";function _glDrawElementsInstanced(mode,count,type,indices,primcount){indices>>>=0;GLctx.drawElementsInstanced(mode,count,type,indices,primcount)}_glDrawElementsInstanced.sig="viiipi";var _emscripten_glDrawElementsInstanced=_glDrawElementsInstanced;_emscripten_glDrawElementsInstanced.sig="viiipi";var _glDrawElementsInstancedANGLE=_glDrawElementsInstanced;var _emscripten_glDrawElementsInstancedANGLE=_glDrawElementsInstancedANGLE;var _glDrawElementsInstancedARB=_glDrawElementsInstanced;var _emscripten_glDrawElementsInstancedARB=_glDrawElementsInstancedARB;var _glDrawElementsInstancedEXT=_glDrawElementsInstanced;var _emscripten_glDrawElementsInstancedEXT=_glDrawElementsInstancedEXT;var _glDrawElementsInstancedNV=_glDrawElementsInstanced;var _emscripten_glDrawElementsInstancedNV=_glDrawElementsInstancedNV;function _glDrawRangeElements(mode,start,end,count,type,indices){indices>>>=0;_glDrawElements(mode,count,type,indices)}_glDrawRangeElements.sig="viiiiip";var _emscripten_glDrawRangeElements=_glDrawRangeElements;_emscripten_glDrawRangeElements.sig="viiiiip";var _glEnable=x0=>GLctx.enable(x0);_glEnable.sig="vi";var _emscripten_glEnable=_glEnable;_emscripten_glEnable.sig="vi";var _glEnableVertexAttribArray=index=>{GLctx.enableVertexAttribArray(index)};_glEnableVertexAttribArray.sig="vi";var _emscripten_glEnableVertexAttribArray=_glEnableVertexAttribArray;_emscripten_glEnableVertexAttribArray.sig="vi";var _glEndQuery=x0=>GLctx.endQuery(x0);_glEndQuery.sig="vi";var _emscripten_glEndQuery=_glEndQuery;_emscripten_glEndQuery.sig="vi";var _glEndQueryEXT=target=>{GLctx.disjointTimerQueryExt["endQueryEXT"](target)};_glEndQueryEXT.sig="vi";var _emscripten_glEndQueryEXT=_glEndQueryEXT;var _glEndTransformFeedback=()=>GLctx.endTransformFeedback();_glEndTransformFeedback.sig="v";var _emscripten_glEndTransformFeedback=_glEndTransformFeedback;_emscripten_glEndTransformFeedback.sig="v";function _glFenceSync(condition,flags){var sync=GLctx.fenceSync(condition,flags);if(sync){var id=GL.getNewId(GL.syncs);sync.name=id;GL.syncs[id]=sync;return id}return 0}_glFenceSync.sig="pii";var _emscripten_glFenceSync=_glFenceSync;_emscripten_glFenceSync.sig="pii";var _glFinish=()=>GLctx.finish();_glFinish.sig="v";var _emscripten_glFinish=_glFinish;_emscripten_glFinish.sig="v";var _glFlush=()=>GLctx.flush();_glFlush.sig="v";var _emscripten_glFlush=_glFlush;_emscripten_glFlush.sig="v";var _glFramebufferRenderbuffer=(target,attachment,renderbuffertarget,renderbuffer)=>{GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])};_glFramebufferRenderbuffer.sig="viiii";var _emscripten_glFramebufferRenderbuffer=_glFramebufferRenderbuffer;_emscripten_glFramebufferRenderbuffer.sig="viiii";var _glFramebufferTexture2D=(target,attachment,textarget,texture,level)=>{GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)};_glFramebufferTexture2D.sig="viiiii";var _emscripten_glFramebufferTexture2D=_glFramebufferTexture2D;_emscripten_glFramebufferTexture2D.sig="viiiii";var _glFramebufferTextureLayer=(target,attachment,texture,level,layer)=>{GLctx.framebufferTextureLayer(target,attachment,GL.textures[texture],level,layer)};_glFramebufferTextureLayer.sig="viiiii";var _emscripten_glFramebufferTextureLayer=_glFramebufferTextureLayer;_emscripten_glFramebufferTextureLayer.sig="viiiii";var _glFrontFace=x0=>GLctx.frontFace(x0);_glFrontFace.sig="vi";var _emscripten_glFrontFace=_glFrontFace;_emscripten_glFrontFace.sig="vi";function _glGenBuffers(n,buffers){buffers>>>=0;GL.genObject(n,buffers,"createBuffer",GL.buffers)}_glGenBuffers.sig="vip";var _emscripten_glGenBuffers=_glGenBuffers;_emscripten_glGenBuffers.sig="vip";function _glGenFramebuffers(n,ids){ids>>>=0;GL.genObject(n,ids,"createFramebuffer",GL.framebuffers)}_glGenFramebuffers.sig="vip";var _emscripten_glGenFramebuffers=_glGenFramebuffers;_emscripten_glGenFramebuffers.sig="vip";function _glGenQueries(n,ids){ids>>>=0;GL.genObject(n,ids,"createQuery",GL.queries)}_glGenQueries.sig="vip";var _emscripten_glGenQueries=_glGenQueries;_emscripten_glGenQueries.sig="vip";function _glGenQueriesEXT(n,ids){ids>>>=0;for(var i=0;i>>2>>>0]=0;return}var id=GL.getNewId(GL.queries);query.name=id;GL.queries[id]=query;HEAP32[ids+i*4>>>2>>>0]=id}}_glGenQueriesEXT.sig="vip";var _emscripten_glGenQueriesEXT=_glGenQueriesEXT;function _glGenRenderbuffers(n,renderbuffers){renderbuffers>>>=0;GL.genObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}_glGenRenderbuffers.sig="vip";var _emscripten_glGenRenderbuffers=_glGenRenderbuffers;_emscripten_glGenRenderbuffers.sig="vip";function _glGenSamplers(n,samplers){samplers>>>=0;GL.genObject(n,samplers,"createSampler",GL.samplers)}_glGenSamplers.sig="vip";var _emscripten_glGenSamplers=_glGenSamplers;_emscripten_glGenSamplers.sig="vip";function _glGenTextures(n,textures){textures>>>=0;GL.genObject(n,textures,"createTexture",GL.textures)}_glGenTextures.sig="vip";var _emscripten_glGenTextures=_glGenTextures;_emscripten_glGenTextures.sig="vip";function _glGenTransformFeedbacks(n,ids){ids>>>=0;GL.genObject(n,ids,"createTransformFeedback",GL.transformFeedbacks)}_glGenTransformFeedbacks.sig="vip";var _emscripten_glGenTransformFeedbacks=_glGenTransformFeedbacks;_emscripten_glGenTransformFeedbacks.sig="vip";function _glGenVertexArrays(n,arrays){arrays>>>=0;GL.genObject(n,arrays,"createVertexArray",GL.vaos)}_glGenVertexArrays.sig="vip";var _emscripten_glGenVertexArrays=_glGenVertexArrays;_emscripten_glGenVertexArrays.sig="vip";var _glGenVertexArraysOES=_glGenVertexArrays;_glGenVertexArraysOES.sig="vip";var _emscripten_glGenVertexArraysOES=_glGenVertexArraysOES;_emscripten_glGenVertexArraysOES.sig="vip";var _glGenerateMipmap=x0=>GLctx.generateMipmap(x0);_glGenerateMipmap.sig="vi";var _emscripten_glGenerateMipmap=_glGenerateMipmap;_emscripten_glGenerateMipmap.sig="vi";var __glGetActiveAttribOrUniform=(funcName,program,index,bufSize,length,size,type,name)=>{program=GL.programs[program];var info=GLctx[funcName](program,index);if(info){var numBytesWrittenExclNull=name&&stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull;if(size)HEAP32[size>>>2>>>0]=info.size;if(type)HEAP32[type>>>2>>>0]=info.type}};function _glGetActiveAttrib(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;return __glGetActiveAttribOrUniform("getActiveAttrib",program,index,bufSize,length,size,type,name)}_glGetActiveAttrib.sig="viiipppp";var _emscripten_glGetActiveAttrib=_glGetActiveAttrib;_emscripten_glGetActiveAttrib.sig="viiipppp";function _glGetActiveUniform(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;return __glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}_glGetActiveUniform.sig="viiipppp";var _emscripten_glGetActiveUniform=_glGetActiveUniform;_emscripten_glGetActiveUniform.sig="viiipppp";function _glGetActiveUniformBlockName(program,uniformBlockIndex,bufSize,length,uniformBlockName){length>>>=0;uniformBlockName>>>=0;program=GL.programs[program];var result=GLctx.getActiveUniformBlockName(program,uniformBlockIndex);if(!result)return;if(uniformBlockName&&bufSize>0){var numBytesWrittenExclNull=stringToUTF8(result,uniformBlockName,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>>2>>>0]=0}}_glGetActiveUniformBlockName.sig="viiipp";var _emscripten_glGetActiveUniformBlockName=_glGetActiveUniformBlockName;_emscripten_glGetActiveUniformBlockName.sig="viiipp";function _glGetActiveUniformBlockiv(program,uniformBlockIndex,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}program=GL.programs[program];if(pname==35393){var name=GLctx.getActiveUniformBlockName(program,uniformBlockIndex);HEAP32[params>>>2>>>0]=name.length+1;return}var result=GLctx.getActiveUniformBlockParameter(program,uniformBlockIndex,pname);if(result===null)return;if(pname==35395){for(var i=0;i>>2>>>0]=result[i]}}else{HEAP32[params>>>2>>>0]=result}}_glGetActiveUniformBlockiv.sig="viiip";var _emscripten_glGetActiveUniformBlockiv=_glGetActiveUniformBlockiv;_emscripten_glGetActiveUniformBlockiv.sig="viiip";function _glGetActiveUniformsiv(program,uniformCount,uniformIndices,pname,params){uniformIndices>>>=0;params>>>=0;if(!params){GL.recordError(1281);return}if(uniformCount>0&&uniformIndices==0){GL.recordError(1281);return}program=GL.programs[program];var ids=[];for(var i=0;i>>2>>>0])}var result=GLctx.getActiveUniforms(program,ids,pname);if(!result)return;var len=result.length;for(var i=0;i>>2>>>0]=result[i]}}_glGetActiveUniformsiv.sig="viipip";var _emscripten_glGetActiveUniformsiv=_glGetActiveUniformsiv;_emscripten_glGetActiveUniformsiv.sig="viipip";function _glGetAttachedShaders(program,maxCount,count,shaders){count>>>=0;shaders>>>=0;var result=GLctx.getAttachedShaders(GL.programs[program]);var len=result.length;if(len>maxCount){len=maxCount}HEAP32[count>>>2>>>0]=len;for(var i=0;i>>2>>>0]=id}}_glGetAttachedShaders.sig="viipp";var _emscripten_glGetAttachedShaders=_glGetAttachedShaders;_emscripten_glGetAttachedShaders.sig="viipp";function _glGetAttribLocation(program,name){name>>>=0;return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}_glGetAttribLocation.sig="iip";var _emscripten_glGetAttribLocation=_glGetAttribLocation;_emscripten_glGetAttribLocation.sig="iip";var writeI53ToI64=(ptr,num)=>{HEAPU32[ptr>>>2>>>0]=num;var lower=HEAPU32[ptr>>>2>>>0];HEAPU32[ptr+4>>>2>>>0]=(num-lower)/4294967296};var webglGetExtensions=()=>{var exts=getEmscriptenSupportedExtensions(GLctx);exts=exts.concat(exts.map(e=>"GL_"+e));return exts};var emscriptenWebGLGet=(name_,p,type)=>{if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 34814:case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break;case 33309:if(GL.currentContext.version<2){GL.recordError(1282);return}ret=webglGetExtensions().length;break;case 33307:case 33308:if(GL.currentContext.version<2){GL.recordError(1280);return}ret=name_==33307?3:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>>2>>>0]=result[i];break;case 2:HEAPF32[p+i*4>>>2>>>0]=result[i];break;case 4:HEAP8[p+i>>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`);return}}break;default:GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof result}!`);return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>>2>>>0]=ret;break;case 2:HEAPF32[p>>>2>>>0]=ret;break;case 4:HEAP8[p>>>0]=ret?1:0;break}};function _glGetBooleanv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,4)}_glGetBooleanv.sig="vip";var _emscripten_glGetBooleanv=_glGetBooleanv;_emscripten_glGetBooleanv.sig="vip";function _glGetBufferParameteri64v(target,value,data){data>>>=0;if(!data){GL.recordError(1281);return}writeI53ToI64(data,GLctx.getBufferParameter(target,value))}_glGetBufferParameteri64v.sig="viip";var _emscripten_glGetBufferParameteri64v=_glGetBufferParameteri64v;_emscripten_glGetBufferParameteri64v.sig="viip";function _glGetBufferParameteriv(target,value,data){data>>>=0;if(!data){GL.recordError(1281);return}HEAP32[data>>>2>>>0]=GLctx.getBufferParameter(target,value)}_glGetBufferParameteriv.sig="viip";var _emscripten_glGetBufferParameteriv=_glGetBufferParameteriv;_emscripten_glGetBufferParameteriv.sig="viip";var _glGetError=()=>{var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error};_glGetError.sig="i";var _emscripten_glGetError=_glGetError;_emscripten_glGetError.sig="i";function _glGetFloatv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,2)}_glGetFloatv.sig="vip";var _emscripten_glGetFloatv=_glGetFloatv;_emscripten_glGetFloatv.sig="vip";function _glGetFragDataLocation(program,name){name>>>=0;return GLctx.getFragDataLocation(GL.programs[program],UTF8ToString(name))}_glGetFragDataLocation.sig="iip";var _emscripten_glGetFragDataLocation=_glGetFragDataLocation;_emscripten_glGetFragDataLocation.sig="iip";function _glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){params>>>=0;var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>>2>>>0]=result}_glGetFramebufferAttachmentParameteriv.sig="viiip";var _emscripten_glGetFramebufferAttachmentParameteriv=_glGetFramebufferAttachmentParameteriv;_emscripten_glGetFramebufferAttachmentParameteriv.sig="viiip";var emscriptenWebGLGetIndexed=(target,index,data,type)=>{if(!data){GL.recordError(1281);return}var result=GLctx.getIndexedParameter(target,index);var ret;switch(typeof result){case"boolean":ret=result?1:0;break;case"number":ret=result;break;case"object":if(result===null){switch(target){case 35983:case 35368:ret=0;break;default:{GL.recordError(1280);return}}}else if(result instanceof WebGLBuffer){ret=result.name|0}else{GL.recordError(1280);return}break;default:GL.recordError(1280);return}switch(type){case 1:writeI53ToI64(data,ret);break;case 0:HEAP32[data>>>2>>>0]=ret;break;case 2:HEAPF32[data>>>2>>>0]=ret;break;case 4:HEAP8[data>>>0]=ret?1:0;break;default:throw"internal emscriptenWebGLGetIndexed() error, bad type: "+type}};function _glGetInteger64i_v(target,index,data){data>>>=0;return emscriptenWebGLGetIndexed(target,index,data,1)}_glGetInteger64i_v.sig="viip";var _emscripten_glGetInteger64i_v=_glGetInteger64i_v;_emscripten_glGetInteger64i_v.sig="viip";function _glGetInteger64v(name_,p){p>>>=0;emscriptenWebGLGet(name_,p,1)}_glGetInteger64v.sig="vip";var _emscripten_glGetInteger64v=_glGetInteger64v;_emscripten_glGetInteger64v.sig="vip";function _glGetIntegeri_v(target,index,data){data>>>=0;return emscriptenWebGLGetIndexed(target,index,data,0)}_glGetIntegeri_v.sig="viip";var _emscripten_glGetIntegeri_v=_glGetIntegeri_v;_emscripten_glGetIntegeri_v.sig="viip";function _glGetIntegerv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,0)}_glGetIntegerv.sig="vip";var _emscripten_glGetIntegerv=_glGetIntegerv;_emscripten_glGetIntegerv.sig="vip";function _glGetInternalformativ(target,internalformat,pname,bufSize,params){params>>>=0;if(bufSize<0){GL.recordError(1281);return}if(!params){GL.recordError(1281);return}var ret=GLctx.getInternalformatParameter(target,internalformat,pname);if(ret===null)return;for(var i=0;i>>2>>>0]=ret[i]}}_glGetInternalformativ.sig="viiiip";var _emscripten_glGetInternalformativ=_glGetInternalformativ;_emscripten_glGetInternalformativ.sig="viiiip";function _glGetProgramBinary(program,bufSize,length,binaryFormat,binary){length>>>=0;binaryFormat>>>=0;binary>>>=0;GL.recordError(1282)}_glGetProgramBinary.sig="viippp";var _emscripten_glGetProgramBinary=_glGetProgramBinary;_emscripten_glGetProgramBinary.sig="viippp";function _glGetProgramInfoLog(program,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}_glGetProgramInfoLog.sig="viipp";var _emscripten_glGetProgramInfoLog=_glGetProgramInfoLog;_emscripten_glGetProgramInfoLog.sig="viipp";function _glGetProgramiv(program,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>>2>>>0]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){var numActiveUniforms=GLctx.getProgramParameter(program,35718);for(var i=0;i>>2>>>0]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){var numActiveAttributes=GLctx.getProgramParameter(program,35721);for(var i=0;i>>2>>>0]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){var numActiveUniformBlocks=GLctx.getProgramParameter(program,35382);for(var i=0;i>>2>>>0]=program.maxUniformBlockNameLength}else{HEAP32[p>>>2>>>0]=GLctx.getProgramParameter(program,pname)}}_glGetProgramiv.sig="viip";var _emscripten_glGetProgramiv=_glGetProgramiv;_emscripten_glGetProgramiv.sig="viip";function _glGetQueryObjecti64vEXT(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param;if(GL.currentContext.version<2){param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname)}else{param=GLctx.getQueryParameter(query,pname)}var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}_glGetQueryObjecti64vEXT.sig="viip";var _emscripten_glGetQueryObjecti64vEXT=_glGetQueryObjecti64vEXT;function _glGetQueryObjectivEXT(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>>2>>>0]=ret}_glGetQueryObjectivEXT.sig="viip";var _emscripten_glGetQueryObjectivEXT=_glGetQueryObjectivEXT;var _glGetQueryObjectui64vEXT=_glGetQueryObjecti64vEXT;var _emscripten_glGetQueryObjectui64vEXT=_glGetQueryObjectui64vEXT;function _glGetQueryObjectuiv(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.getQueryParameter(query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>>2>>>0]=ret}_glGetQueryObjectuiv.sig="viip";var _emscripten_glGetQueryObjectuiv=_glGetQueryObjectuiv;_emscripten_glGetQueryObjectuiv.sig="viip";var _glGetQueryObjectuivEXT=_glGetQueryObjectivEXT;var _emscripten_glGetQueryObjectuivEXT=_glGetQueryObjectuivEXT;function _glGetQueryiv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getQuery(target,pname)}_glGetQueryiv.sig="viip";var _emscripten_glGetQueryiv=_glGetQueryiv;_emscripten_glGetQueryiv.sig="viip";function _glGetQueryivEXT(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.disjointTimerQueryExt["getQueryEXT"](target,pname)}_glGetQueryivEXT.sig="viip";var _emscripten_glGetQueryivEXT=_glGetQueryivEXT;function _glGetRenderbufferParameteriv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getRenderbufferParameter(target,pname)}_glGetRenderbufferParameteriv.sig="viip";var _emscripten_glGetRenderbufferParameteriv=_glGetRenderbufferParameteriv;_emscripten_glGetRenderbufferParameteriv.sig="viip";function _glGetSamplerParameterfv(sampler,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAPF32[params>>>2>>>0]=GLctx.getSamplerParameter(GL.samplers[sampler],pname)}_glGetSamplerParameterfv.sig="viip";var _emscripten_glGetSamplerParameterfv=_glGetSamplerParameterfv;_emscripten_glGetSamplerParameterfv.sig="viip";function _glGetSamplerParameteriv(sampler,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getSamplerParameter(GL.samplers[sampler],pname)}_glGetSamplerParameteriv.sig="viip";var _emscripten_glGetSamplerParameteriv=_glGetSamplerParameteriv;_emscripten_glGetSamplerParameteriv.sig="viip";function _glGetShaderInfoLog(shader,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}_glGetShaderInfoLog.sig="viipp";var _emscripten_glGetShaderInfoLog=_glGetShaderInfoLog;_emscripten_glGetShaderInfoLog.sig="viipp";function _glGetShaderPrecisionFormat(shaderType,precisionType,range,precision){range>>>=0;precision>>>=0;var result=GLctx.getShaderPrecisionFormat(shaderType,precisionType);HEAP32[range>>>2>>>0]=result.rangeMin;HEAP32[range+4>>>2>>>0]=result.rangeMax;HEAP32[precision>>>2>>>0]=result.precision}_glGetShaderPrecisionFormat.sig="viipp";var _emscripten_glGetShaderPrecisionFormat=_glGetShaderPrecisionFormat;_emscripten_glGetShaderPrecisionFormat.sig="viipp";function _glGetShaderSource(shader,bufSize,length,source){length>>>=0;source>>>=0;var result=GLctx.getShaderSource(GL.shaders[shader]);if(!result)return;var numBytesWrittenExclNull=bufSize>0&&source?stringToUTF8(result,source,bufSize):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}_glGetShaderSource.sig="viipp";var _emscripten_glGetShaderSource=_glGetShaderSource;_emscripten_glGetShaderSource.sig="viipp";function _glGetShaderiv(shader,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>>2>>>0]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>>2>>>0]=sourceLength}else{HEAP32[p>>>2>>>0]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}_glGetShaderiv.sig="viip";var _emscripten_glGetShaderiv=_glGetShaderiv;_emscripten_glGetShaderiv.sig="viip";var stringToNewUTF8=str=>{var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret};function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:ret=stringToNewUTF8(webglGetExtensions().join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s?stringToNewUTF8(s):0;break;case 7938:var webGLVersion=GLctx.getParameter(7938);var glVersion=`OpenGL ES 2.0 (${webGLVersion})`;if(GL.currentContext.version>=2)glVersion=`OpenGL ES 3.0 (${webGLVersion})`;ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion=`OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}_glGetString.sig="pi";var _emscripten_glGetString=_glGetString;_emscripten_glGetString.sig="pi";function _glGetStringi(name,index){if(GL.currentContext.version<2){GL.recordError(1282);return 0}var stringiCache=GL.stringiCache[name];if(stringiCache){if(index<0||index>=stringiCache.length){GL.recordError(1281);return 0}return stringiCache[index]}switch(name){case 7939:var exts=webglGetExtensions().map(stringToNewUTF8);stringiCache=GL.stringiCache[name]=exts;if(index<0||index>=stringiCache.length){GL.recordError(1281);return 0}return stringiCache[index];default:GL.recordError(1280);return 0}}_glGetStringi.sig="pii";var _emscripten_glGetStringi=_glGetStringi;_emscripten_glGetStringi.sig="pii";function _glGetSynciv(sync,pname,bufSize,length,values){sync>>>=0;length>>>=0;values>>>=0;if(bufSize<0){GL.recordError(1281);return}if(!values){GL.recordError(1281);return}var ret=GLctx.getSyncParameter(GL.syncs[sync],pname);if(ret!==null){HEAP32[values>>>2>>>0]=ret;if(length)HEAP32[length>>>2>>>0]=1}}_glGetSynciv.sig="vpiipp";var _emscripten_glGetSynciv=_glGetSynciv;_emscripten_glGetSynciv.sig="vpiipp";function _glGetTexParameterfv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAPF32[params>>>2>>>0]=GLctx.getTexParameter(target,pname)}_glGetTexParameterfv.sig="viip";var _emscripten_glGetTexParameterfv=_glGetTexParameterfv;_emscripten_glGetTexParameterfv.sig="viip";function _glGetTexParameteriv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getTexParameter(target,pname)}_glGetTexParameteriv.sig="viip";var _emscripten_glGetTexParameteriv=_glGetTexParameteriv;_emscripten_glGetTexParameteriv.sig="viip";function _glGetTransformFeedbackVarying(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;program=GL.programs[program];var info=GLctx.getTransformFeedbackVarying(program,index);if(!info)return;if(name&&bufSize>0){var numBytesWrittenExclNull=stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>>2>>>0]=0}if(size)HEAP32[size>>>2>>>0]=info.size;if(type)HEAP32[type>>>2>>>0]=info.type}_glGetTransformFeedbackVarying.sig="viiipppp";var _emscripten_glGetTransformFeedbackVarying=_glGetTransformFeedbackVarying;_emscripten_glGetTransformFeedbackVarying.sig="viiipppp";function _glGetUniformBlockIndex(program,uniformBlockName){uniformBlockName>>>=0;return GLctx.getUniformBlockIndex(GL.programs[program],UTF8ToString(uniformBlockName))}_glGetUniformBlockIndex.sig="iip";var _emscripten_glGetUniformBlockIndex=_glGetUniformBlockIndex;_emscripten_glGetUniformBlockIndex.sig="iip";function _glGetUniformIndices(program,uniformCount,uniformNames,uniformIndices){uniformNames>>>=0;uniformIndices>>>=0;if(!uniformIndices){GL.recordError(1281);return}if(uniformCount>0&&(uniformNames==0||uniformIndices==0)){GL.recordError(1281);return}program=GL.programs[program];var names=[];for(var i=0;i>>2>>>0]));var result=GLctx.getUniformIndices(program,names);if(!result)return;var len=result.length;for(var i=0;i>>2>>>0]=result[i]}}_glGetUniformIndices.sig="viipp";var _emscripten_glGetUniformIndices=_glGetUniformIndices;_emscripten_glGetUniformIndices.sig="viipp";var jstoi_q=str=>parseInt(str);var webglGetLeftBracePos=name=>name.slice(-1)=="]"&&name.lastIndexOf("[");var webglPrepareUniformLocationsBeforeFirstUse=program=>{var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};var numActiveUniforms=GLctx.getProgramParameter(program,35718);for(i=0;i0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j>>=0;name=UTF8ToString(name);if(program=GL.programs[program]){webglPrepareUniformLocationsBeforeFirstUse(program);var uniformLocsById=program.uniformLocsById;var arrayIndex=0;var uniformBaseName=name;var leftBrace=webglGetLeftBracePos(name);if(leftBrace>0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex{var p=GLctx.currentProgram;if(p){var webglLoc=p.uniformLocsById[location];if(typeof webglLoc=="number"){p.uniformLocsById[location]=webglLoc=GLctx.getUniformLocation(p,p.uniformArrayNamesById[location]+(webglLoc>0?`[${webglLoc}]`:""))}return webglLoc}else{GL.recordError(1282)}};var emscriptenWebGLGetUniform=(program,location,params,type)=>{if(!params){GL.recordError(1281);return}program=GL.programs[program];webglPrepareUniformLocationsBeforeFirstUse(program);var data=GLctx.getUniform(program,webglGetUniformLocation(location));if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>>2>>>0]=data;break;case 2:HEAPF32[params>>>2>>>0]=data;break}}else{for(var i=0;i>>2>>>0]=data[i];break;case 2:HEAPF32[params+i*4>>>2>>>0]=data[i];break}}}};function _glGetUniformfv(program,location,params){params>>>=0;emscriptenWebGLGetUniform(program,location,params,2)}_glGetUniformfv.sig="viip";var _emscripten_glGetUniformfv=_glGetUniformfv;_emscripten_glGetUniformfv.sig="viip";function _glGetUniformiv(program,location,params){params>>>=0;emscriptenWebGLGetUniform(program,location,params,0)}_glGetUniformiv.sig="viip";var _emscripten_glGetUniformiv=_glGetUniformiv;_emscripten_glGetUniformiv.sig="viip";function _glGetUniformuiv(program,location,params){params>>>=0;return emscriptenWebGLGetUniform(program,location,params,0)}_glGetUniformuiv.sig="viip";var _emscripten_glGetUniformuiv=_glGetUniformuiv;_emscripten_glGetUniformuiv.sig="viip";var emscriptenWebGLGetVertexAttrib=(index,pname,params,type)=>{if(!params){GL.recordError(1281);return}var data=GLctx.getVertexAttrib(index,pname);if(pname==34975){HEAP32[params>>>2>>>0]=data&&data["name"]}else if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>>2>>>0]=data;break;case 2:HEAPF32[params>>>2>>>0]=data;break;case 5:HEAP32[params>>>2>>>0]=Math.fround(data);break}}else{for(var i=0;i>>2>>>0]=data[i];break;case 2:HEAPF32[params+i*4>>>2>>>0]=data[i];break;case 5:HEAP32[params+i*4>>>2>>>0]=Math.fround(data[i]);break}}}};function _glGetVertexAttribIiv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,0)}_glGetVertexAttribIiv.sig="viip";var _emscripten_glGetVertexAttribIiv=_glGetVertexAttribIiv;_emscripten_glGetVertexAttribIiv.sig="viip";var _glGetVertexAttribIuiv=_glGetVertexAttribIiv;_glGetVertexAttribIuiv.sig="viip";var _emscripten_glGetVertexAttribIuiv=_glGetVertexAttribIuiv;_emscripten_glGetVertexAttribIuiv.sig="viip";function _glGetVertexAttribPointerv(index,pname,pointer){pointer>>>=0;if(!pointer){GL.recordError(1281);return}HEAP32[pointer>>>2>>>0]=GLctx.getVertexAttribOffset(index,pname)}_glGetVertexAttribPointerv.sig="viip";var _emscripten_glGetVertexAttribPointerv=_glGetVertexAttribPointerv;_emscripten_glGetVertexAttribPointerv.sig="viip";function _glGetVertexAttribfv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,2)}_glGetVertexAttribfv.sig="viip";var _emscripten_glGetVertexAttribfv=_glGetVertexAttribfv;_emscripten_glGetVertexAttribfv.sig="viip";function _glGetVertexAttribiv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,5)}_glGetVertexAttribiv.sig="viip";var _emscripten_glGetVertexAttribiv=_glGetVertexAttribiv;_emscripten_glGetVertexAttribiv.sig="viip";var _glHint=(x0,x1)=>GLctx.hint(x0,x1);_glHint.sig="vii";var _emscripten_glHint=_glHint;_emscripten_glHint.sig="vii";function _glInvalidateFramebuffer(target,numAttachments,attachments){attachments>>>=0;var list=tempFixedLengthArray[numAttachments];for(var i=0;i>>2>>>0]}GLctx.invalidateFramebuffer(target,list)}_glInvalidateFramebuffer.sig="viip";var _emscripten_glInvalidateFramebuffer=_glInvalidateFramebuffer;_emscripten_glInvalidateFramebuffer.sig="viip";function _glInvalidateSubFramebuffer(target,numAttachments,attachments,x,y,width,height){attachments>>>=0;var list=tempFixedLengthArray[numAttachments];for(var i=0;i>>2>>>0]}GLctx.invalidateSubFramebuffer(target,list,x,y,width,height)}_glInvalidateSubFramebuffer.sig="viipiiii";var _emscripten_glInvalidateSubFramebuffer=_glInvalidateSubFramebuffer;_emscripten_glInvalidateSubFramebuffer.sig="viipiiii";var _glIsBuffer=buffer=>{var b=GL.buffers[buffer];if(!b)return 0;return GLctx.isBuffer(b)};_glIsBuffer.sig="ii";var _emscripten_glIsBuffer=_glIsBuffer;_emscripten_glIsBuffer.sig="ii";var _glIsEnabled=x0=>GLctx.isEnabled(x0);_glIsEnabled.sig="ii";var _emscripten_glIsEnabled=_glIsEnabled;_emscripten_glIsEnabled.sig="ii";var _glIsFramebuffer=framebuffer=>{var fb=GL.framebuffers[framebuffer];if(!fb)return 0;return GLctx.isFramebuffer(fb)};_glIsFramebuffer.sig="ii";var _emscripten_glIsFramebuffer=_glIsFramebuffer;_emscripten_glIsFramebuffer.sig="ii";var _glIsProgram=program=>{program=GL.programs[program];if(!program)return 0;return GLctx.isProgram(program)};_glIsProgram.sig="ii";var _emscripten_glIsProgram=_glIsProgram;_emscripten_glIsProgram.sig="ii";var _glIsQuery=id=>{var query=GL.queries[id];if(!query)return 0;return GLctx.isQuery(query)};_glIsQuery.sig="ii";var _emscripten_glIsQuery=_glIsQuery;_emscripten_glIsQuery.sig="ii";var _glIsQueryEXT=id=>{var query=GL.queries[id];if(!query)return 0;return GLctx.disjointTimerQueryExt["isQueryEXT"](query)};_glIsQueryEXT.sig="ii";var _emscripten_glIsQueryEXT=_glIsQueryEXT;var _glIsRenderbuffer=renderbuffer=>{var rb=GL.renderbuffers[renderbuffer];if(!rb)return 0;return GLctx.isRenderbuffer(rb)};_glIsRenderbuffer.sig="ii";var _emscripten_glIsRenderbuffer=_glIsRenderbuffer;_emscripten_glIsRenderbuffer.sig="ii";var _glIsSampler=id=>{var sampler=GL.samplers[id];if(!sampler)return 0;return GLctx.isSampler(sampler)};_glIsSampler.sig="ii";var _emscripten_glIsSampler=_glIsSampler;_emscripten_glIsSampler.sig="ii";var _glIsShader=shader=>{var s=GL.shaders[shader];if(!s)return 0;return GLctx.isShader(s)};_glIsShader.sig="ii";var _emscripten_glIsShader=_glIsShader;_emscripten_glIsShader.sig="ii";function _glIsSync(sync){sync>>>=0;return GLctx.isSync(GL.syncs[sync])}_glIsSync.sig="ip";var _emscripten_glIsSync=_glIsSync;_emscripten_glIsSync.sig="ip";var _glIsTexture=id=>{var texture=GL.textures[id];if(!texture)return 0;return GLctx.isTexture(texture)};_glIsTexture.sig="ii";var _emscripten_glIsTexture=_glIsTexture;_emscripten_glIsTexture.sig="ii";var _glIsTransformFeedback=id=>GLctx.isTransformFeedback(GL.transformFeedbacks[id]);_glIsTransformFeedback.sig="ii";var _emscripten_glIsTransformFeedback=_glIsTransformFeedback;_emscripten_glIsTransformFeedback.sig="ii";var _glIsVertexArray=array=>{var vao=GL.vaos[array];if(!vao)return 0;return GLctx.isVertexArray(vao)};_glIsVertexArray.sig="ii";var _emscripten_glIsVertexArray=_glIsVertexArray;_emscripten_glIsVertexArray.sig="ii";var _glIsVertexArrayOES=_glIsVertexArray;_glIsVertexArrayOES.sig="ii";var _emscripten_glIsVertexArrayOES=_glIsVertexArrayOES;_emscripten_glIsVertexArrayOES.sig="ii";var _glLineWidth=x0=>GLctx.lineWidth(x0);_glLineWidth.sig="vf";var _emscripten_glLineWidth=_glLineWidth;_emscripten_glLineWidth.sig="vf";var _glLinkProgram=program=>{program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}};_glLinkProgram.sig="vi";var _emscripten_glLinkProgram=_glLinkProgram;_emscripten_glLinkProgram.sig="vi";var _glPauseTransformFeedback=()=>GLctx.pauseTransformFeedback();_glPauseTransformFeedback.sig="v";var _emscripten_glPauseTransformFeedback=_glPauseTransformFeedback;_emscripten_glPauseTransformFeedback.sig="v";var _glPixelStorei=(pname,param)=>{if(pname==3317){GL.unpackAlignment=param}else if(pname==3314){GL.unpackRowLength=param}GLctx.pixelStorei(pname,param)};_glPixelStorei.sig="vii";var _emscripten_glPixelStorei=_glPixelStorei;_emscripten_glPixelStorei.sig="vii";var _glPolygonModeWEBGL=(face,mode)=>{GLctx.webglPolygonMode["polygonModeWEBGL"](face,mode)};_glPolygonModeWEBGL.sig="vii";var _emscripten_glPolygonModeWEBGL=_glPolygonModeWEBGL;var _glPolygonOffset=(x0,x1)=>GLctx.polygonOffset(x0,x1);_glPolygonOffset.sig="vff";var _emscripten_glPolygonOffset=_glPolygonOffset;_emscripten_glPolygonOffset.sig="vff";var _glPolygonOffsetClampEXT=(factor,units,clamp)=>{GLctx.extPolygonOffsetClamp["polygonOffsetClampEXT"](factor,units,clamp)};_glPolygonOffsetClampEXT.sig="vfff";var _emscripten_glPolygonOffsetClampEXT=_glPolygonOffsetClampEXT;function _glProgramBinary(program,binaryFormat,binary,length){binary>>>=0;GL.recordError(1280)}_glProgramBinary.sig="viipi";var _emscripten_glProgramBinary=_glProgramBinary;_emscripten_glProgramBinary.sig="viipi";var _glProgramParameteri=(program,pname,value)=>{GL.recordError(1280)};_glProgramParameteri.sig="viii";var _emscripten_glProgramParameteri=_glProgramParameteri;_emscripten_glProgramParameteri.sig="viii";var _glQueryCounterEXT=(id,target)=>{GLctx.disjointTimerQueryExt["queryCounterEXT"](GL.queries[id],target)};_glQueryCounterEXT.sig="vii";var _emscripten_glQueryCounterEXT=_glQueryCounterEXT;var _glReadBuffer=x0=>GLctx.readBuffer(x0);_glReadBuffer.sig="vi";var _emscripten_glReadBuffer=_glReadBuffer;_emscripten_glReadBuffer.sig="vi";var computeUnpackAlignedImageSize=(width,height,sizePerPixel)=>{function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=(GL.unpackRowLength||width)*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,GL.unpackAlignment);return height*alignedRowSize};var colorChannelsInGlTextureFormat=format=>{var colorChannels={5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4};return colorChannels[format-6402]||1};var heapObjectForWebGLType=type=>{type-=5120;if(type==0)return HEAP8;if(type==1)return HEAPU8;if(type==2)return HEAP16;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922||type==28520||type==30779||type==30782)return HEAPU32;return HEAPU16};var toTypedArrayIndex=(pointer,heap)=>pointer>>>31-Math.clz32(heap.BYTES_PER_ELEMENT);var emscriptenWebGLGetTexPixelData=(type,format,width,height,pixels,internalFormat)=>{var heap=heapObjectForWebGLType(type);var sizePerPixel=colorChannelsInGlTextureFormat(format)*heap.BYTES_PER_ELEMENT;var bytes=computeUnpackAlignedImageSize(width,height,sizePerPixel);return heap.subarray(toTypedArrayIndex(pixels,heap)>>>0,toTypedArrayIndex(pixels+bytes,heap)>>>0)};function _glReadPixels(x,y,width,height,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels);return}}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}_glReadPixels.sig="viiiiiip";var _emscripten_glReadPixels=_glReadPixels;_emscripten_glReadPixels.sig="viiiiiip";var _glReleaseShaderCompiler=()=>{};_glReleaseShaderCompiler.sig="v";var _emscripten_glReleaseShaderCompiler=_glReleaseShaderCompiler;_emscripten_glReleaseShaderCompiler.sig="v";var _glRenderbufferStorage=(x0,x1,x2,x3)=>GLctx.renderbufferStorage(x0,x1,x2,x3);_glRenderbufferStorage.sig="viiii";var _emscripten_glRenderbufferStorage=_glRenderbufferStorage;_emscripten_glRenderbufferStorage.sig="viiii";var _glRenderbufferStorageMultisample=(x0,x1,x2,x3,x4)=>GLctx.renderbufferStorageMultisample(x0,x1,x2,x3,x4);_glRenderbufferStorageMultisample.sig="viiiii";var _emscripten_glRenderbufferStorageMultisample=_glRenderbufferStorageMultisample;_emscripten_glRenderbufferStorageMultisample.sig="viiiii";var _glResumeTransformFeedback=()=>GLctx.resumeTransformFeedback();_glResumeTransformFeedback.sig="v";var _emscripten_glResumeTransformFeedback=_glResumeTransformFeedback;_emscripten_glResumeTransformFeedback.sig="v";var _glSampleCoverage=(value,invert)=>{GLctx.sampleCoverage(value,!!invert)};_glSampleCoverage.sig="vfi";var _emscripten_glSampleCoverage=_glSampleCoverage;_emscripten_glSampleCoverage.sig="vfi";var _glSamplerParameterf=(sampler,pname,param)=>{GLctx.samplerParameterf(GL.samplers[sampler],pname,param)};_glSamplerParameterf.sig="viif";var _emscripten_glSamplerParameterf=_glSamplerParameterf;_emscripten_glSamplerParameterf.sig="viif";function _glSamplerParameterfv(sampler,pname,params){params>>>=0;var param=HEAPF32[params>>>2>>>0];GLctx.samplerParameterf(GL.samplers[sampler],pname,param)}_glSamplerParameterfv.sig="viip";var _emscripten_glSamplerParameterfv=_glSamplerParameterfv;_emscripten_glSamplerParameterfv.sig="viip";var _glSamplerParameteri=(sampler,pname,param)=>{GLctx.samplerParameteri(GL.samplers[sampler],pname,param)};_glSamplerParameteri.sig="viii";var _emscripten_glSamplerParameteri=_glSamplerParameteri;_emscripten_glSamplerParameteri.sig="viii";function _glSamplerParameteriv(sampler,pname,params){params>>>=0;var param=HEAP32[params>>>2>>>0];GLctx.samplerParameteri(GL.samplers[sampler],pname,param)}_glSamplerParameteriv.sig="viip";var _emscripten_glSamplerParameteriv=_glSamplerParameteriv;_emscripten_glSamplerParameteriv.sig="viip";var _glScissor=(x0,x1,x2,x3)=>GLctx.scissor(x0,x1,x2,x3);_glScissor.sig="viiii";var _emscripten_glScissor=_glScissor;_emscripten_glScissor.sig="viiii";function _glShaderBinary(count,shaders,binaryformat,binary,length){shaders>>>=0;binary>>>=0;GL.recordError(1280)}_glShaderBinary.sig="vipipi";var _emscripten_glShaderBinary=_glShaderBinary;_emscripten_glShaderBinary.sig="vipipi";function _glShaderSource(shader,count,string,length){string>>>=0;length>>>=0;var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}_glShaderSource.sig="viipp";var _emscripten_glShaderSource=_glShaderSource;_emscripten_glShaderSource.sig="viipp";var _glStencilFunc=(x0,x1,x2)=>GLctx.stencilFunc(x0,x1,x2);_glStencilFunc.sig="viii";var _emscripten_glStencilFunc=_glStencilFunc;_emscripten_glStencilFunc.sig="viii";var _glStencilFuncSeparate=(x0,x1,x2,x3)=>GLctx.stencilFuncSeparate(x0,x1,x2,x3);_glStencilFuncSeparate.sig="viiii";var _emscripten_glStencilFuncSeparate=_glStencilFuncSeparate;_emscripten_glStencilFuncSeparate.sig="viiii";var _glStencilMask=x0=>GLctx.stencilMask(x0);_glStencilMask.sig="vi";var _emscripten_glStencilMask=_glStencilMask;_emscripten_glStencilMask.sig="vi";var _glStencilMaskSeparate=(x0,x1)=>GLctx.stencilMaskSeparate(x0,x1);_glStencilMaskSeparate.sig="vii";var _emscripten_glStencilMaskSeparate=_glStencilMaskSeparate;_emscripten_glStencilMaskSeparate.sig="vii";var _glStencilOp=(x0,x1,x2)=>GLctx.stencilOp(x0,x1,x2);_glStencilOp.sig="viii";var _emscripten_glStencilOp=_glStencilOp;_emscripten_glStencilOp.sig="viii";var _glStencilOpSeparate=(x0,x1,x2,x3)=>GLctx.stencilOpSeparate(x0,x1,x2,x3);_glStencilOpSeparate.sig="viiii";var _emscripten_glStencilOpSeparate=_glStencilOpSeparate;_emscripten_glStencilOpSeparate.sig="viiii";function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels);return}}var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null;GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixelData)}_glTexImage2D.sig="viiiiiiiip";var _emscripten_glTexImage2D=_glTexImage2D;_emscripten_glTexImage2D.sig="viiiiiiiip";function _glTexImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels){pixels>>>=0;if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height*depth,pixels,internalFormat);GLctx.texImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixelData)}else{GLctx.texImage3D(target,level,internalFormat,width,height,depth,border,format,type,null)}}_glTexImage3D.sig="viiiiiiiiip";var _emscripten_glTexImage3D=_glTexImage3D;_emscripten_glTexImage3D.sig="viiiiiiiiip";var _glTexParameterf=(x0,x1,x2)=>GLctx.texParameterf(x0,x1,x2);_glTexParameterf.sig="viif";var _emscripten_glTexParameterf=_glTexParameterf;_emscripten_glTexParameterf.sig="viif";function _glTexParameterfv(target,pname,params){params>>>=0;var param=HEAPF32[params>>>2>>>0];GLctx.texParameterf(target,pname,param)}_glTexParameterfv.sig="viip";var _emscripten_glTexParameterfv=_glTexParameterfv;_emscripten_glTexParameterfv.sig="viip";var _glTexParameteri=(x0,x1,x2)=>GLctx.texParameteri(x0,x1,x2);_glTexParameteri.sig="viii";var _emscripten_glTexParameteri=_glTexParameteri;_emscripten_glTexParameteri.sig="viii";function _glTexParameteriv(target,pname,params){params>>>=0;var param=HEAP32[params>>>2>>>0];GLctx.texParameteri(target,pname,param)}_glTexParameteriv.sig="viip";var _emscripten_glTexParameteriv=_glTexParameteriv;_emscripten_glTexParameteriv.sig="viip";var _glTexStorage2D=(x0,x1,x2,x3,x4)=>GLctx.texStorage2D(x0,x1,x2,x3,x4);_glTexStorage2D.sig="viiiii";var _emscripten_glTexStorage2D=_glTexStorage2D;_emscripten_glTexStorage2D.sig="viiiii";var _glTexStorage3D=(x0,x1,x2,x3,x4,x5)=>GLctx.texStorage3D(x0,x1,x2,x3,x4,x5);_glTexStorage3D.sig="viiiiii";var _emscripten_glTexStorage3D=_glTexStorage3D;_emscripten_glTexStorage3D.sig="viiiiii";function _glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels);return}}var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0):null;GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}_glTexSubImage2D.sig="viiiiiiiip";var _emscripten_glTexSubImage2D=_glTexSubImage2D;_emscripten_glTexSubImage2D.sig="viiiiiiiip";function _glTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels){pixels>>>=0;if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,heap,toTypedArrayIndex(pixels,heap))}else{GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,null)}}_glTexSubImage3D.sig="viiiiiiiiiip";var _emscripten_glTexSubImage3D=_glTexSubImage3D;_emscripten_glTexSubImage3D.sig="viiiiiiiiiip";function _glTransformFeedbackVaryings(program,count,varyings,bufferMode){varyings>>>=0;program=GL.programs[program];var vars=[];for(var i=0;i>>2>>>0]));GLctx.transformFeedbackVaryings(program,vars,bufferMode)}_glTransformFeedbackVaryings.sig="viipi";var _emscripten_glTransformFeedbackVaryings=_glTransformFeedbackVaryings;_emscripten_glTransformFeedbackVaryings.sig="viipi";var _glUniform1f=(location,v0)=>{GLctx.uniform1f(webglGetUniformLocation(location),v0)};_glUniform1f.sig="vif";var _emscripten_glUniform1f=_glUniform1f;_emscripten_glUniform1f.sig="vif";var miniTempWebGLFloatBuffers=[];function _glUniform1fv(location,count,value){value>>>=0;if(count<=288){var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*4>>>2>>>0)}GLctx.uniform1fv(webglGetUniformLocation(location),view)}_glUniform1fv.sig="viip";var _emscripten_glUniform1fv=_glUniform1fv;_emscripten_glUniform1fv.sig="viip";var _glUniform1i=(location,v0)=>{GLctx.uniform1i(webglGetUniformLocation(location),v0)};_glUniform1i.sig="vii";var _emscripten_glUniform1i=_glUniform1i;_emscripten_glUniform1i.sig="vii";var miniTempWebGLIntBuffers=[];function _glUniform1iv(location,count,value){value>>>=0;if(count<=288){var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*4>>>2>>>0)}GLctx.uniform1iv(webglGetUniformLocation(location),view)}_glUniform1iv.sig="viip";var _emscripten_glUniform1iv=_glUniform1iv;_emscripten_glUniform1iv.sig="viip";var _glUniform1ui=(location,v0)=>{GLctx.uniform1ui(webglGetUniformLocation(location),v0)};_glUniform1ui.sig="vii";var _emscripten_glUniform1ui=_glUniform1ui;_emscripten_glUniform1ui.sig="vii";function _glUniform1uiv(location,count,value){value>>>=0;count&&GLctx.uniform1uiv(webglGetUniformLocation(location),HEAPU32,value>>>2,count)}_glUniform1uiv.sig="viip";var _emscripten_glUniform1uiv=_glUniform1uiv;_emscripten_glUniform1uiv.sig="viip";var _glUniform2f=(location,v0,v1)=>{GLctx.uniform2f(webglGetUniformLocation(location),v0,v1)};_glUniform2f.sig="viff";var _emscripten_glUniform2f=_glUniform2f;_emscripten_glUniform2f.sig="viff";function _glUniform2fv(location,count,value){value>>>=0;if(count<=144){count*=2;var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*8>>>2>>>0)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}_glUniform2fv.sig="viip";var _emscripten_glUniform2fv=_glUniform2fv;_emscripten_glUniform2fv.sig="viip";var _glUniform2i=(location,v0,v1)=>{GLctx.uniform2i(webglGetUniformLocation(location),v0,v1)};_glUniform2i.sig="viii";var _emscripten_glUniform2i=_glUniform2i;_emscripten_glUniform2i.sig="viii";function _glUniform2iv(location,count,value){value>>>=0;if(count<=144){count*=2;var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*8>>>2>>>0)}GLctx.uniform2iv(webglGetUniformLocation(location),view)}_glUniform2iv.sig="viip";var _emscripten_glUniform2iv=_glUniform2iv;_emscripten_glUniform2iv.sig="viip";var _glUniform2ui=(location,v0,v1)=>{GLctx.uniform2ui(webglGetUniformLocation(location),v0,v1)};_glUniform2ui.sig="viii";var _emscripten_glUniform2ui=_glUniform2ui;_emscripten_glUniform2ui.sig="viii";function _glUniform2uiv(location,count,value){value>>>=0;count&&GLctx.uniform2uiv(webglGetUniformLocation(location),HEAPU32,value>>>2,count*2)}_glUniform2uiv.sig="viip";var _emscripten_glUniform2uiv=_glUniform2uiv;_emscripten_glUniform2uiv.sig="viip";var _glUniform3f=(location,v0,v1,v2)=>{GLctx.uniform3f(webglGetUniformLocation(location),v0,v1,v2)};_glUniform3f.sig="vifff";var _emscripten_glUniform3f=_glUniform3f;_emscripten_glUniform3f.sig="vifff";function _glUniform3fv(location,count,value){value>>>=0;if(count<=96){count*=3;var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*12>>>2>>>0)}GLctx.uniform3fv(webglGetUniformLocation(location),view)}_glUniform3fv.sig="viip";var _emscripten_glUniform3fv=_glUniform3fv;_emscripten_glUniform3fv.sig="viip";var _glUniform3i=(location,v0,v1,v2)=>{GLctx.uniform3i(webglGetUniformLocation(location),v0,v1,v2)};_glUniform3i.sig="viiii";var _emscripten_glUniform3i=_glUniform3i;_emscripten_glUniform3i.sig="viiii";function _glUniform3iv(location,count,value){value>>>=0;if(count<=96){count*=3;var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAP32[value+(4*i+8)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*12>>>2>>>0)}GLctx.uniform3iv(webglGetUniformLocation(location),view)}_glUniform3iv.sig="viip";var _emscripten_glUniform3iv=_glUniform3iv;_emscripten_glUniform3iv.sig="viip";var _glUniform3ui=(location,v0,v1,v2)=>{GLctx.uniform3ui(webglGetUniformLocation(location),v0,v1,v2)};_glUniform3ui.sig="viiii";var _emscripten_glUniform3ui=_glUniform3ui;_emscripten_glUniform3ui.sig="viiii";function _glUniform3uiv(location,count,value){value>>>=0;count&&GLctx.uniform3uiv(webglGetUniformLocation(location),HEAPU32,value>>>2,count*3)}_glUniform3uiv.sig="viip";var _emscripten_glUniform3uiv=_glUniform3uiv;_emscripten_glUniform3uiv.sig="viip";var _glUniform4f=(location,v0,v1,v2,v3)=>{GLctx.uniform4f(webglGetUniformLocation(location),v0,v1,v2,v3)};_glUniform4f.sig="viffff";var _emscripten_glUniform4f=_glUniform4f;_emscripten_glUniform4f.sig="viffff";function _glUniform4fv(location,count,value){value>>>=0;if(count<=72){var view=miniTempWebGLFloatBuffers[4*count];var heap=HEAPF32;value=value>>>2;count*=4;for(var i=0;i>>0];view[i+1]=heap[dst+1>>>0];view[i+2]=heap[dst+2>>>0];view[i+3]=heap[dst+3>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}_glUniform4fv.sig="viip";var _emscripten_glUniform4fv=_glUniform4fv;_emscripten_glUniform4fv.sig="viip";var _glUniform4i=(location,v0,v1,v2,v3)=>{GLctx.uniform4i(webglGetUniformLocation(location),v0,v1,v2,v3)};_glUniform4i.sig="viiiii";var _emscripten_glUniform4i=_glUniform4i;_emscripten_glUniform4i.sig="viiiii";function _glUniform4iv(location,count,value){value>>>=0;if(count<=72){count*=4;var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAP32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAP32[value+(4*i+12)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniform4iv(webglGetUniformLocation(location),view)}_glUniform4iv.sig="viip";var _emscripten_glUniform4iv=_glUniform4iv;_emscripten_glUniform4iv.sig="viip";var _glUniform4ui=(location,v0,v1,v2,v3)=>{GLctx.uniform4ui(webglGetUniformLocation(location),v0,v1,v2,v3)};_glUniform4ui.sig="viiiii";var _emscripten_glUniform4ui=_glUniform4ui;_emscripten_glUniform4ui.sig="viiiii";function _glUniform4uiv(location,count,value){value>>>=0;count&&GLctx.uniform4uiv(webglGetUniformLocation(location),HEAPU32,value>>>2,count*4)}_glUniform4uiv.sig="viip";var _emscripten_glUniform4uiv=_glUniform4uiv;_emscripten_glUniform4uiv.sig="viip";var _glUniformBlockBinding=(program,uniformBlockIndex,uniformBlockBinding)=>{program=GL.programs[program];GLctx.uniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding)};_glUniformBlockBinding.sig="viii";var _emscripten_glUniformBlockBinding=_glUniformBlockBinding;_emscripten_glUniformBlockBinding.sig="viii";function _glUniformMatrix2fv(location,count,transpose,value){value>>>=0;if(count<=72){count*=4;var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAPF32[value+(4*i+12)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniformMatrix2fv(webglGetUniformLocation(location),!!transpose,view)}_glUniformMatrix2fv.sig="viiip";var _emscripten_glUniformMatrix2fv=_glUniformMatrix2fv;_emscripten_glUniformMatrix2fv.sig="viiip";function _glUniformMatrix2x3fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix2x3fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*6)}_glUniformMatrix2x3fv.sig="viiip";var _emscripten_glUniformMatrix2x3fv=_glUniformMatrix2x3fv;_emscripten_glUniformMatrix2x3fv.sig="viiip";function _glUniformMatrix2x4fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix2x4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*8)}_glUniformMatrix2x4fv.sig="viiip";var _emscripten_glUniformMatrix2x4fv=_glUniformMatrix2x4fv;_emscripten_glUniformMatrix2x4fv.sig="viiip";function _glUniformMatrix3fv(location,count,transpose,value){value>>>=0;if(count<=32){count*=9;var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAPF32[value+(4*i+12)>>>2>>>0];view[i+4]=HEAPF32[value+(4*i+16)>>>2>>>0];view[i+5]=HEAPF32[value+(4*i+20)>>>2>>>0];view[i+6]=HEAPF32[value+(4*i+24)>>>2>>>0];view[i+7]=HEAPF32[value+(4*i+28)>>>2>>>0];view[i+8]=HEAPF32[value+(4*i+32)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*36>>>2>>>0)}GLctx.uniformMatrix3fv(webglGetUniformLocation(location),!!transpose,view)}_glUniformMatrix3fv.sig="viiip";var _emscripten_glUniformMatrix3fv=_glUniformMatrix3fv;_emscripten_glUniformMatrix3fv.sig="viiip";function _glUniformMatrix3x2fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix3x2fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*6)}_glUniformMatrix3x2fv.sig="viiip";var _emscripten_glUniformMatrix3x2fv=_glUniformMatrix3x2fv;_emscripten_glUniformMatrix3x2fv.sig="viiip";function _glUniformMatrix3x4fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix3x4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*12)}_glUniformMatrix3x4fv.sig="viiip";var _emscripten_glUniformMatrix3x4fv=_glUniformMatrix3x4fv;_emscripten_glUniformMatrix3x4fv.sig="viiip";function _glUniformMatrix4fv(location,count,transpose,value){value>>>=0;if(count<=18){var view=miniTempWebGLFloatBuffers[16*count];var heap=HEAPF32;value=value>>>2;count*=16;for(var i=0;i>>0];view[i+1]=heap[dst+1>>>0];view[i+2]=heap[dst+2>>>0];view[i+3]=heap[dst+3>>>0];view[i+4]=heap[dst+4>>>0];view[i+5]=heap[dst+5>>>0];view[i+6]=heap[dst+6>>>0];view[i+7]=heap[dst+7>>>0];view[i+8]=heap[dst+8>>>0];view[i+9]=heap[dst+9>>>0];view[i+10]=heap[dst+10>>>0];view[i+11]=heap[dst+11>>>0];view[i+12]=heap[dst+12>>>0];view[i+13]=heap[dst+13>>>0];view[i+14]=heap[dst+14>>>0];view[i+15]=heap[dst+15>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*64>>>2>>>0)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}_glUniformMatrix4fv.sig="viiip";var _emscripten_glUniformMatrix4fv=_glUniformMatrix4fv;_emscripten_glUniformMatrix4fv.sig="viiip";function _glUniformMatrix4x2fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix4x2fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*8)}_glUniformMatrix4x2fv.sig="viiip";var _emscripten_glUniformMatrix4x2fv=_glUniformMatrix4x2fv;_emscripten_glUniformMatrix4x2fv.sig="viiip";function _glUniformMatrix4x3fv(location,count,transpose,value){value>>>=0;count&&GLctx.uniformMatrix4x3fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>>2,count*12)}_glUniformMatrix4x3fv.sig="viiip";var _emscripten_glUniformMatrix4x3fv=_glUniformMatrix4x3fv;_emscripten_glUniformMatrix4x3fv.sig="viiip";var _glUseProgram=program=>{program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program};_glUseProgram.sig="vi";var _emscripten_glUseProgram=_glUseProgram;_emscripten_glUseProgram.sig="vi";var _glValidateProgram=program=>{GLctx.validateProgram(GL.programs[program])};_glValidateProgram.sig="vi";var _emscripten_glValidateProgram=_glValidateProgram;_emscripten_glValidateProgram.sig="vi";var _glVertexAttrib1f=(x0,x1)=>GLctx.vertexAttrib1f(x0,x1);_glVertexAttrib1f.sig="vif";var _emscripten_glVertexAttrib1f=_glVertexAttrib1f;_emscripten_glVertexAttrib1f.sig="vif";function _glVertexAttrib1fv(index,v){v>>>=0;GLctx.vertexAttrib1f(index,HEAPF32[v>>>2])}_glVertexAttrib1fv.sig="vip";var _emscripten_glVertexAttrib1fv=_glVertexAttrib1fv;_emscripten_glVertexAttrib1fv.sig="vip";var _glVertexAttrib2f=(x0,x1,x2)=>GLctx.vertexAttrib2f(x0,x1,x2);_glVertexAttrib2f.sig="viff";var _emscripten_glVertexAttrib2f=_glVertexAttrib2f;_emscripten_glVertexAttrib2f.sig="viff";function _glVertexAttrib2fv(index,v){v>>>=0;GLctx.vertexAttrib2f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2])}_glVertexAttrib2fv.sig="vip";var _emscripten_glVertexAttrib2fv=_glVertexAttrib2fv;_emscripten_glVertexAttrib2fv.sig="vip";var _glVertexAttrib3f=(x0,x1,x2,x3)=>GLctx.vertexAttrib3f(x0,x1,x2,x3);_glVertexAttrib3f.sig="vifff";var _emscripten_glVertexAttrib3f=_glVertexAttrib3f;_emscripten_glVertexAttrib3f.sig="vifff";function _glVertexAttrib3fv(index,v){v>>>=0;GLctx.vertexAttrib3f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2],HEAPF32[v+8>>>2])}_glVertexAttrib3fv.sig="vip";var _emscripten_glVertexAttrib3fv=_glVertexAttrib3fv;_emscripten_glVertexAttrib3fv.sig="vip";var _glVertexAttrib4f=(x0,x1,x2,x3,x4)=>GLctx.vertexAttrib4f(x0,x1,x2,x3,x4);_glVertexAttrib4f.sig="viffff";var _emscripten_glVertexAttrib4f=_glVertexAttrib4f;_emscripten_glVertexAttrib4f.sig="viffff";function _glVertexAttrib4fv(index,v){v>>>=0;GLctx.vertexAttrib4f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2],HEAPF32[v+8>>>2],HEAPF32[v+12>>>2])}_glVertexAttrib4fv.sig="vip";var _emscripten_glVertexAttrib4fv=_glVertexAttrib4fv;_emscripten_glVertexAttrib4fv.sig="vip";var _glVertexAttribDivisor=(index,divisor)=>{GLctx.vertexAttribDivisor(index,divisor)};_glVertexAttribDivisor.sig="vii";var _emscripten_glVertexAttribDivisor=_glVertexAttribDivisor;_emscripten_glVertexAttribDivisor.sig="vii";var _glVertexAttribDivisorANGLE=_glVertexAttribDivisor;var _emscripten_glVertexAttribDivisorANGLE=_glVertexAttribDivisorANGLE;var _glVertexAttribDivisorARB=_glVertexAttribDivisor;var _emscripten_glVertexAttribDivisorARB=_glVertexAttribDivisorARB;var _glVertexAttribDivisorEXT=_glVertexAttribDivisor;var _emscripten_glVertexAttribDivisorEXT=_glVertexAttribDivisorEXT;var _glVertexAttribDivisorNV=_glVertexAttribDivisor;var _emscripten_glVertexAttribDivisorNV=_glVertexAttribDivisorNV;var _glVertexAttribI4i=(x0,x1,x2,x3,x4)=>GLctx.vertexAttribI4i(x0,x1,x2,x3,x4);_glVertexAttribI4i.sig="viiiii";var _emscripten_glVertexAttribI4i=_glVertexAttribI4i;_emscripten_glVertexAttribI4i.sig="viiiii";function _glVertexAttribI4iv(index,v){v>>>=0;GLctx.vertexAttribI4i(index,HEAP32[v>>>2],HEAP32[v+4>>>2],HEAP32[v+8>>>2],HEAP32[v+12>>>2])}_glVertexAttribI4iv.sig="vip";var _emscripten_glVertexAttribI4iv=_glVertexAttribI4iv;_emscripten_glVertexAttribI4iv.sig="vip";var _glVertexAttribI4ui=(x0,x1,x2,x3,x4)=>GLctx.vertexAttribI4ui(x0,x1,x2,x3,x4);_glVertexAttribI4ui.sig="viiiii";var _emscripten_glVertexAttribI4ui=_glVertexAttribI4ui;_emscripten_glVertexAttribI4ui.sig="viiiii";function _glVertexAttribI4uiv(index,v){v>>>=0;GLctx.vertexAttribI4ui(index,HEAPU32[v>>>2],HEAPU32[v+4>>>2],HEAPU32[v+8>>>2],HEAPU32[v+12>>>2])}_glVertexAttribI4uiv.sig="vip";var _emscripten_glVertexAttribI4uiv=_glVertexAttribI4uiv;_emscripten_glVertexAttribI4uiv.sig="vip";function _glVertexAttribIPointer(index,size,type,stride,ptr){ptr>>>=0;GLctx.vertexAttribIPointer(index,size,type,stride,ptr)}_glVertexAttribIPointer.sig="viiiip";var _emscripten_glVertexAttribIPointer=_glVertexAttribIPointer;_emscripten_glVertexAttribIPointer.sig="viiiip";function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){ptr>>>=0;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}_glVertexAttribPointer.sig="viiiiip";var _emscripten_glVertexAttribPointer=_glVertexAttribPointer;_emscripten_glVertexAttribPointer.sig="viiiiip";var _glViewport=(x0,x1,x2,x3)=>GLctx.viewport(x0,x1,x2,x3);_glViewport.sig="viiii";var _emscripten_glViewport=_glViewport;_emscripten_glViewport.sig="viiii";function _glWaitSync(sync,flags,timeout){sync>>>=0;timeout=Number(timeout);GLctx.waitSync(GL.syncs[sync],flags,timeout)}_glWaitSync.sig="vpij";var _emscripten_glWaitSync=_glWaitSync;_emscripten_glWaitSync.sig="vpij";function _emscripten_out(str){str>>>=0;return out(UTF8ToString(str))}_emscripten_out.sig="vp";class HandleAllocator{allocated=[undefined];freelist=[];get(id){return this.allocated[id]}has(id){return this.allocated[id]!==undefined}allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id}free(id){this.allocated[id]=undefined;this.freelist.push(id)}}var promiseMap=new HandleAllocator;var makePromise=()=>{var promiseInfo={};promiseInfo.promise=new Promise((resolve,reject)=>{promiseInfo.reject=reject;promiseInfo.resolve=resolve});promiseInfo.id=promiseMap.allocate(promiseInfo);return promiseInfo};function _emscripten_promise_create(){return makePromise().id}_emscripten_promise_create.sig="p";function _emscripten_promise_destroy(id){id>>>=0;promiseMap.free(id)}_emscripten_promise_destroy.sig="vp";var getPromise=id=>promiseMap.get(id).promise;function _emscripten_promise_resolve(id,result,value){id>>>=0;value>>>=0;var info=promiseMap.get(id);switch(result){case 0:info.resolve(value);return;case 1:info.resolve(getPromise(value));return;case 2:info.resolve(getPromise(value));_emscripten_promise_destroy(value);return;case 3:info.reject(value);return}}_emscripten_promise_resolve.sig="vpip";var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};function _emscripten_resize_heap(requestedSize){requestedSize>>>=0;var oldSize=HEAPU8.length;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false}_emscripten_resize_heap.sig="ip";var _emscripten_runtime_keepalive_pop=runtimeKeepalivePop;_emscripten_runtime_keepalive_pop.sig="v";var _emscripten_runtime_keepalive_push=runtimeKeepalivePush;_emscripten_runtime_keepalive_push.sig="v";var ENV={};var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};function _environ_get(__environ,environ_buf){__environ>>>=0;environ_buf>>>=0;var bufSize=0;var envp=0;for(var string of getEnvStrings()){var ptr=environ_buf+bufSize;HEAPU32[__environ+envp>>>2>>>0]=ptr;bufSize+=stringToUTF8(string,ptr,Infinity)+1;envp+=4}return 0}_environ_get.sig="ipp";function _environ_sizes_get(penviron_count,penviron_buf_size){penviron_count>>>=0;penviron_buf_size>>>=0;var strings=getEnvStrings();HEAPU32[penviron_count>>>2>>>0]=strings.length;var bufSize=0;for(var string of strings){bufSize+=lengthBytesUTF8(string)+1}HEAPU32[penviron_buf_size>>>2>>>0]=bufSize;return 0}_environ_sizes_get.sig="ipp";function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}_fd_close.sig="ii";function _fd_fdstat_get(fd,pbuf){pbuf>>>=0;try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4}HEAP8[pbuf>>>0]=type;HEAP16[pbuf+2>>>1>>>0]=flags;HEAP64[pbuf+8>>>3>>>0]=BigInt(rightsBase);HEAP64[pbuf+16>>>3>>>0]=BigInt(rightsInheriting);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}_fd_fdstat_get.sig="iip";var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;offset=bigintToI53Checked(offset);pnum>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt,offset);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}_fd_pread.sig="iippjp";var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;offset=bigintToI53Checked(offset);pnum>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt,offset);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}_fd_pwrite.sig="iippjp";function _fd_read(fd,iov,iovcnt,pnum){iov>>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}_fd_read.sig="iippp";function _fd_seek(fd,offset,whence,newOffset){offset=bigintToI53Checked(offset);newOffset>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);HEAP64[newOffset>>>3>>>0]=BigInt(stream.position);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}_fd_seek.sig="iijip";function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops?.fsync){return stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}_fd_sync.sig="ii";function _fd_write(fd,iov,iovcnt,pnum){iov>>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}_fd_write.sig="iippp";function _getaddrinfo(node,service,hint,out){node>>>=0;service>>>=0;hint>>>=0;out>>>=0;var addrs=[];var canon=null;var addr=0;var port=0;var flags=0;var family=0;var type=0;var proto=0;var ai,last;function allocaddrinfo(family,type,proto,canon,addr,port){var sa,salen,ai;var errno;salen=family===10?28:16;addr=family===10?inetNtop6(addr):inetNtop4(addr);sa=_malloc(salen);errno=writeSockaddr(sa,family,addr,port);assert(!errno);ai=_malloc(32);HEAP32[ai+4>>>2>>>0]=family;HEAP32[ai+8>>>2>>>0]=type;HEAP32[ai+12>>>2>>>0]=proto;HEAPU32[ai+24>>>2>>>0]=canon;HEAPU32[ai+20>>>2>>>0]=sa;if(family===10){HEAP32[ai+16>>>2>>>0]=28}else{HEAP32[ai+16>>>2>>>0]=16}HEAP32[ai+28>>>2>>>0]=0;return ai}if(hint){flags=HEAP32[hint>>>2>>>0];family=HEAP32[hint+4>>>2>>>0];type=HEAP32[hint+8>>>2>>>0];proto=HEAP32[hint+12>>>2>>>0]}if(type&&!proto){proto=type===2?17:6}if(!type&&proto){type=proto===17?2:1}if(proto===0){proto=6}if(type===0){type=1}if(!node&&!service){return-2}if(flags&~(1|2|4|1024|8|16|32)){return-1}if(hint!==0&&HEAP32[hint>>>2>>>0]&2&&!node){return-1}if(flags&32){return-2}if(type!==0&&type!==1&&type!==2){return-7}if(family!==0&&family!==2&&family!==10){return-6}if(service){service=UTF8ToString(service);port=parseInt(service,10);if(isNaN(port)){if(flags&1024){return-2}return-8}}if(!node){if(family===0){family=2}if((flags&1)===0){if(family===2){addr=_htonl(2130706433)}else{addr=[0,0,0,_htonl(1)]}}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}node=UTF8ToString(node);addr=inetPton4(node);if(addr!==null){if(family===0||family===2){family=2}else if(family===10&&flags&8){addr=[0,0,_htonl(65535),addr];family=10}else{return-2}}else{addr=inetPton6(node);if(addr!==null){if(family===0||family===10){family=10}else{return-2}}}if(addr!=null){ai=allocaddrinfo(family,type,proto,node,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}if(flags&4){return-2}node=DNS.lookup_name(node);addr=inetPton4(node);if(family===0){family=2}else if(family===10){addr=[0,0,_htonl(65535),addr]}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}_getaddrinfo.sig="ipppp";function _getnameinfo(sa,salen,node,nodelen,serv,servlen,flags){sa>>>=0;node>>>=0;serv>>>=0;var info=readSockaddr(sa,salen);if(info.errno){return-6}var port=info.port;var addr=info.addr;var overflowed=false;if(node&&nodelen){var lookup;if(flags&1||!(lookup=DNS.lookup_addr(addr))){if(flags&8){return-2}}else{addr=lookup}var numBytesWrittenExclNull=stringToUTF8(addr,node,nodelen);if(numBytesWrittenExclNull+1>=nodelen){overflowed=true}}if(serv&&servlen){port=""+port;var numBytesWrittenExclNull=stringToUTF8(port,serv,servlen);if(numBytesWrittenExclNull+1>=servlen){overflowed=true}}if(overflowed){return-12}return 0}_getnameinfo.sig="ipipipii";var Protocols={list:[],map:{}};var stringToAscii=(str,buffer)=>{for(var i=0;i>>0]=str.charCodeAt(i)}HEAP8[buffer>>>0]=0};var _setprotoent=stayopen=>{function allocprotoent(name,proto,aliases){var nameBuf=_malloc(name.length+1);stringToAscii(name,nameBuf);var j=0;var length=aliases.length;var aliasListBuf=_malloc((length+1)*4);for(var i=0;i>>2>>>0]=aliasBuf}HEAPU32[aliasListBuf+j>>>2>>>0]=0;var pe=_malloc(12);HEAPU32[pe>>>2>>>0]=nameBuf;HEAPU32[pe+4>>>2>>>0]=aliasListBuf;HEAP32[pe+8>>>2>>>0]=proto;return pe}var list=Protocols.list;var map=Protocols.map;if(list.length===0){var entry=allocprotoent("tcp",6,["TCP"]);list.push(entry);map["tcp"]=map["6"]=entry;entry=allocprotoent("udp",17,["UDP"]);list.push(entry);map["udp"]=map["17"]=entry}_setprotoent.index=0};_setprotoent.sig="vi";function _getprotobyname(name){name>>>=0;name=UTF8ToString(name);_setprotoent(true);var result=Protocols.map[name];return result}_getprotobyname.sig="pp";function _is_sentinel(...args){return wasmImports["is_sentinel"](...args)}_is_sentinel.stub=true;function _random_get(buffer,size){buffer>>>=0;size>>>=0;try{randomFill(HEAPU8.subarray(buffer>>>0,buffer+size>>>0));return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}_random_get.sig="ipp";var _stackAlloc=stackAlloc;var _stackRestore=stackSave;var _stackSave=stackSave;var FS_createPath=(...args)=>FS.createPath(...args);var FS_unlink=(...args)=>FS.unlink(...args);var FS_createLazyFile=(...args)=>FS.createLazyFile(...args);var FS_createDevice=(...args)=>FS.createDevice(...args);var writeI53ToI64Clamped=(ptr,num)=>{if(num>0x8000000000000000){HEAPU32[ptr>>>2>>>0]=4294967295;HEAPU32[ptr+4>>>2>>>0]=2147483647}else if(num<-0x8000000000000000){HEAPU32[ptr>>>2>>>0]=0;HEAPU32[ptr+4>>>2>>>0]=2147483648}else{writeI53ToI64(ptr,num)}};var writeI53ToI64Signaling=(ptr,num)=>{if(num>0x8000000000000000||num<-0x8000000000000000){throw`RangeError: ${num}`}writeI53ToI64(ptr,num)};var writeI53ToU64Clamped=(ptr,num)=>{if(num>0x10000000000000000){HEAPU32[ptr>>>2>>>0]=4294967295;HEAPU32[ptr+4>>>2>>>0]=4294967295}else if(num<0){HEAPU32[ptr>>>2>>>0]=0;HEAPU32[ptr+4>>>2>>>0]=0}else{writeI53ToI64(ptr,num)}};var writeI53ToU64Signaling=(ptr,num)=>{if(num<0||num>0x10000000000000000){throw`RangeError: ${num}`}writeI53ToI64(ptr,num)};var readI53FromU64=ptr=>HEAPU32[ptr>>>2>>>0]+HEAPU32[ptr+4>>>2>>>0]*4294967296;var convertI32PairToI53=(lo,hi)=>(lo>>>0)+hi*4294967296;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;var convertU32PairToI53=(lo,hi)=>(lo>>>0)+(hi>>>0)*4294967296;var getTempRet0=val=>__emscripten_tempret_get();var setTempRet0=val=>__emscripten_tempret_set(val);var ptrToString=ptr=>"0x"+ptr.toString(16).padStart(8,"0");function _emscripten_notify_memory_growth(memoryIndex){memoryIndex>>>=0;updateMemoryViews()}_emscripten_notify_memory_growth.sig="vp";var strError=errno=>UTF8ToString(_strerror(errno));var _endprotoent=()=>{};_endprotoent.sig="v";function _getprotoent(number){if(_setprotoent.index===Protocols.list.length){return 0}var result=Protocols.list[_setprotoent.index++];return result}_getprotoent.sig="p";function _getprotobynumber(number){_setprotoent(true);var result=Protocols.map[number];return result}_getprotobynumber.sig="pi";var Sockets={BUFFER_SIZE:10240,MAX_BUFFER_SIZE:10485760,nextFd:1,fds:{},nextport:1,maxport:65535,peer:null,connections:{},portmap:{},localAddr:4261412874,addrPool:[33554442,50331658,67108874,83886090,100663306,117440522,134217738,150994954,167772170,184549386,201326602,218103818,234881034]};function _emscripten_run_script(ptr){ptr>>>=0;eval(UTF8ToString(ptr))}_emscripten_run_script.sig="vp";function _emscripten_run_script_int(ptr){ptr>>>=0;return eval(UTF8ToString(ptr))|0}_emscripten_run_script_int.sig="ip";function _emscripten_run_script_string(ptr){ptr>>>=0;var s=eval(UTF8ToString(ptr));if(s==null){return 0}s+="";var me=_emscripten_run_script_string;var len=lengthBytesUTF8(s);if(!me.bufferSize||me.bufferSizeMath.random();_emscripten_random.sig="f";var _emscripten_performance_now=()=>performance.now();_emscripten_performance_now.sig="d";var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;__emscripten_get_now_is_monotonic.sig="i";var warnOnce=text=>{warnOnce.shown||={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}};var jsStackTrace=()=>(new Error).stack.toString();var getCallstack=flags=>{var callstack=jsStackTrace();var lines=callstack.split("\n");callstack="";var firefoxRe=new RegExp("\\s*(.*?)@(.*?):([0-9]+):([0-9]+)");var chromeRe=new RegExp("\\s*at (.*?) \\((.*):(.*):(.*)\\)");for(var line of lines){var symbolName="";var file="";var lineno=0;var column=0;var parts=chromeRe.exec(line);if(parts?.length==5){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]}else{parts=firefoxRe.exec(line);if(parts?.length>=4){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]|0}else{callstack+=line+"\n";continue}}if(symbolName=="_emscripten_log"||symbolName=="_emscripten_get_callstack"){callstack="";continue}if(flags&24){if(flags&64){file=file.substring(file.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=` at ${symbolName} (${file}:${lineno}:${column})\n`}}callstack=callstack.replace(/\s+$/,"");return callstack};var emscriptenLog=(flags,str)=>{if(flags&24){str=str.replace(/\s+$/,"");str+=(str.length>0?"\n":"")+getCallstack(flags)}if(flags&1){if(flags&4){console.error(str)}else if(flags&2){console.warn(str)}else if(flags&512){console.info(str)}else if(flags&256){console.debug(str)}else{console.log(str)}}else if(flags&6){err(str)}else{out(str)}};var reallyNegative=x=>x<0||x===0&&1/x===-Infinity;var reSign=(value,bits)=>{if(value<=0){return value}var half=bits<=32?Math.abs(1<=half&&(bits<=32||value>half)){value=-2*half+value}return value};var unSign=(value,bits)=>{if(value>=0){return value}return bits<=32?2*Math.abs(1<{var end=ptr;while(HEAPU8[end>>>0])++end;return end-ptr};var formatString=(format,varargs)=>{var textIndex=format;var argIndex=varargs;function prepVararg(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){ptr+=4}}else{}return ptr}function getNextArg(type){var ret;argIndex=prepVararg(argIndex,type);if(type==="double"){ret=HEAPF64[argIndex>>>3>>>0];argIndex+=8}else if(type=="i64"){ret=[HEAP32[argIndex>>>2>>>0],HEAP32[argIndex+4>>>2>>>0]];argIndex+=8}else{type="i32";ret=HEAP32[argIndex>>>2>>>0];argIndex+=4}return ret}var ret=[];var curr,next,currArg;while(1){var startTextIndex=textIndex;curr=HEAP8[textIndex>>>0];if(curr===0)break;next=HEAP8[textIndex+1>>>0];if(curr==37){var flagAlwaysSigned=false;var flagLeftAlign=false;var flagAlternative=false;var flagZeroPad=false;var flagPadSign=false;flagsLoop:while(1){switch(next){case 43:flagAlwaysSigned=true;break;case 45:flagLeftAlign=true;break;case 35:flagAlternative=true;break;case 48:if(flagZeroPad){break flagsLoop}else{flagZeroPad=true;break}case 32:flagPadSign=true;break;default:break flagsLoop}textIndex++;next=HEAP8[textIndex+1>>>0]}var width=0;if(next==42){width=getNextArg("i32");textIndex++;next=HEAP8[textIndex+1>>>0]}else{while(next>=48&&next<=57){width=width*10+(next-48);textIndex++;next=HEAP8[textIndex+1>>>0]}}var precisionSet=false,precision=-1;if(next==46){precision=0;precisionSet=true;textIndex++;next=HEAP8[textIndex+1>>>0];if(next==42){precision=getNextArg("i32");textIndex++}else{while(1){var precisionChr=HEAP8[textIndex+1>>>0];if(precisionChr<48||precisionChr>57)break;precision=precision*10+(precisionChr-48);textIndex++}}next=HEAP8[textIndex+1>>>0]}if(precision<0){precision=6;precisionSet=false}var argSize;switch(String.fromCharCode(next)){case"h":var nextNext=HEAP8[textIndex+2>>>0];if(nextNext==104){textIndex++;argSize=1}else{argSize=2}break;case"l":var nextNext=HEAP8[textIndex+2>>>0];if(nextNext==108){textIndex++;argSize=8}else{argSize=4}break;case"L":case"q":case"j":argSize=8;break;case"z":case"t":case"I":argSize=4;break;default:argSize=null}if(argSize)textIndex++;next=HEAP8[textIndex+1>>>0];switch(String.fromCharCode(next)){case"d":case"i":case"u":case"o":case"x":case"X":case"p":{var signed=next==100||next==105;argSize=argSize||4;currArg=getNextArg("i"+argSize*8);var argText;if(argSize==8){currArg=next==117?convertU32PairToI53(currArg[0],currArg[1]):convertI32PairToI53(currArg[0],currArg[1])}if(argSize<=4){var limit=Math.pow(256,argSize)-1;currArg=(signed?reSign:unSign)(currArg&limit,argSize*8)}var currAbsArg=Math.abs(currArg);var prefix="";if(next==100||next==105){argText=reSign(currArg,8*argSize).toString(10)}else if(next==117){argText=unSign(currArg,8*argSize).toString(10);currArg=Math.abs(currArg)}else if(next==111){argText=(flagAlternative?"0":"")+currAbsArg.toString(8)}else if(next==120||next==88){prefix=flagAlternative&&currArg!=0?"0x":"";if(currArg<0){currArg=-currArg;argText=(currAbsArg-1).toString(16);var buffer=[];for(var i=0;i=0){if(flagAlwaysSigned){prefix="+"+prefix}else if(flagPadSign){prefix=" "+prefix}}if(argText.charAt(0)=="-"){prefix="-"+prefix;argText=argText.slice(1)}while(prefix.length+argText.lengthret.push(chr.charCodeAt(0)));break}case"f":case"F":case"e":case"E":case"g":case"G":{currArg=getNextArg("double");var argText;if(isNaN(currArg)){argText="nan";flagZeroPad=false}else if(!isFinite(currArg)){argText=(currArg<0?"-":"")+"inf";flagZeroPad=false}else{var isGeneral=false;var effectivePrecision=Math.min(precision,20);if(next==103||next==71){isGeneral=true;precision=precision||1;var exponent=parseInt(currArg.toExponential(effectivePrecision).split("e")[1],10);if(precision>exponent&&exponent>=-4){next=(next==103?"f":"F").charCodeAt(0);precision-=exponent+1}else{next=(next==103?"e":"E").charCodeAt(0);precision--}effectivePrecision=Math.min(precision,20)}if(next==101||next==69){argText=currArg.toExponential(effectivePrecision);if(/[eE][-+]\d$/.test(argText)){argText=argText.slice(0,-1)+"0"+argText.slice(-1)}}else if(next==102||next==70){argText=currArg.toFixed(effectivePrecision);if(currArg===0&&reallyNegative(currArg)){argText="-"+argText}}var parts=argText.split("e");if(isGeneral&&!flagAlternative){while(parts[0].length>1&&parts[0].includes(".")&&(parts[0].slice(-1)=="0"||parts[0].slice(-1)==".")){parts[0]=parts[0].slice(0,-1)}}else{if(flagAlternative&&argText.indexOf(".")==-1)parts[0]+=".";while(precision>effectivePrecision++)parts[0]+="0"}argText=parts[0]+(parts.length>1?"e"+parts[1]:"");if(next==69)argText=argText.toUpperCase();if(currArg>=0){if(flagAlwaysSigned){argText="+"+argText}else if(flagPadSign){argText=" "+argText}}}while(argText.lengthret.push(chr.charCodeAt(0)));break}case"s":{var arg=getNextArg("i8*");var argLength=arg?strLen(arg):"(null)".length;if(precisionSet)argLength=Math.min(argLength,precision);if(!flagLeftAlign){while(argLength>>0])}}else{ret=ret.concat(intArrayFromString("(null)".slice(0,argLength),true))}if(flagLeftAlign){while(argLength0){ret.push(32)}if(!flagLeftAlign)ret.push(getNextArg("i8"));break}case"n":{var ptr=getNextArg("i32*");HEAP32[ptr>>>2>>>0]=ret.length;break}case"%":{ret.push(curr);break}default:{for(var i=startTextIndex;i>>0])}}}textIndex+=2}else{ret.push(curr);textIndex+=1}}return ret};function _emscripten_log(flags,format,varargs){format>>>=0;varargs>>>=0;var result=formatString(format,varargs);var str=UTF8ArrayToString(result);emscriptenLog(flags,str)}_emscripten_log.sig="vipp";function _emscripten_get_compiler_setting(name){name>>>=0;throw"You must build with -sRETAIN_COMPILER_SETTINGS for getCompilerSetting or emscripten_get_compiler_setting to work"}_emscripten_get_compiler_setting.sig="pp";var _emscripten_has_asyncify=()=>0;_emscripten_has_asyncify.sig="i";var _emscripten_debugger=()=>{debugger};_emscripten_debugger.sig="v";function _emscripten_print_double(x,to,max){to>>>=0;var str=x+"";if(to)return stringToUTF8(str,to,max);else return lengthBytesUTF8(str)}_emscripten_print_double.sig="idpi";function _emscripten_asm_const_double(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}_emscripten_asm_const_double.sig="dppp";function _emscripten_asm_const_ptr(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}_emscripten_asm_const_ptr.sig="pppp";var runMainThreadEmAsm=(emAsmAddr,sigPtr,argbuf,sync)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[emAsmAddr](...args)};function _emscripten_asm_const_int_sync_on_main_thread(emAsmAddr,sigPtr,argbuf){emAsmAddr>>>=0;sigPtr>>>=0;argbuf>>>=0;return runMainThreadEmAsm(emAsmAddr,sigPtr,argbuf,1)}_emscripten_asm_const_int_sync_on_main_thread.sig="ippp";function _emscripten_asm_const_ptr_sync_on_main_thread(emAsmAddr,sigPtr,argbuf){emAsmAddr>>>=0;sigPtr>>>=0;argbuf>>>=0;return runMainThreadEmAsm(emAsmAddr,sigPtr,argbuf,1)}_emscripten_asm_const_ptr_sync_on_main_thread.sig="pppp";var _emscripten_asm_const_double_sync_on_main_thread=_emscripten_asm_const_int_sync_on_main_thread;_emscripten_asm_const_double_sync_on_main_thread.sig="dppp";function _emscripten_asm_const_async_on_main_thread(emAsmAddr,sigPtr,argbuf){emAsmAddr>>>=0;sigPtr>>>=0;argbuf>>>=0;return runMainThreadEmAsm(emAsmAddr,sigPtr,argbuf,0)}_emscripten_asm_const_async_on_main_thread.sig="vppp";function __Unwind_Backtrace(func,arg){func>>>=0;arg>>>=0;var trace=getCallstack();var parts=trace.split("\n");for(var i=0;i>>=0;ipBefore>>>=0;return abort("Unwind_GetIPInfo")}__Unwind_GetIPInfo.sig="ppp";function __Unwind_FindEnclosingFunction(ip){ip>>>=0;return 0}__Unwind_FindEnclosingFunction.sig="pp";var listenOnce=(object,event,func)=>object.addEventListener(event,func,{once:true});var autoResumeAudioContext=(ctx,elements)=>{if(!elements){elements=[document,document.getElementById("canvas")]}["keydown","mousedown","touchstart"].forEach(event=>{elements.forEach(element=>{if(element){listenOnce(element,event,()=>{if(ctx.state==="suspended")ctx.resume()})}})})};var dynCall=(sig,ptr,args=[],promising=false)=>{var func=getWasmTableEntry(ptr);var rtn=func(...args);function convert(rtn){return sig[0]=="p"?rtn>>>0:rtn}return convert(rtn)};var getDynCaller=(sig,ptr,promising=false)=>(...args)=>dynCall(sig,ptr,args,promising);var _emscripten_exit_with_live_runtime=()=>{runtimeKeepalivePush();throw"unwind"};_emscripten_exit_with_live_runtime.sig="v";var _emscripten_force_exit=status=>{__emscripten_runtime_keepalive_clear();_exit(status)};_emscripten_force_exit.sig="vi";function _emscripten_outn(str,len){str>>>=0;len>>>=0;return out(UTF8ToString(str,len))}_emscripten_outn.sig="vpp";function _emscripten_errn(str,len){str>>>=0;len>>>=0;return err(UTF8ToString(str,len))}_emscripten_errn.sig="vpp";var _emscripten_throw_number=number=>{throw number};_emscripten_throw_number.sig="vd";function _emscripten_throw_string(str){str>>>=0;throw UTF8ToString(str)}_emscripten_throw_string.sig="vp";var _emscripten_runtime_keepalive_check=keepRuntimeAlive;_emscripten_runtime_keepalive_check.sig="i";var asmjsMangle=x=>{if(x=="__main_argc_argv"){x="main"}return x.startsWith("dynCall_")?x:"_"+x};var ___global_base=1024;function __emscripten_fs_load_embedded_files(ptr){ptr>>>=0;do{var name_addr=HEAPU32[ptr>>>2>>>0];ptr+=4;var len=HEAPU32[ptr>>>2>>>0];ptr+=4;var content=HEAPU32[ptr>>>2>>>0];ptr+=4;var name=UTF8ToString(name_addr);FS.createPath("/",PATH.dirname(name),true,true);FS.createDataFile(name,null,HEAP8.subarray(content>>>0,content+len>>>0),true,true,true)}while(HEAPU32[ptr>>>2>>>0])}__emscripten_fs_load_embedded_files.sig="vp";var POINTER_SIZE=4;function getNativeTypeSize(type){switch(type){case"i1":case"i8":case"u8":return 1;case"i16":case"u16":return 2;case"i32":case"u32":return 4;case"i64":case"u64":return 8;case"float":return 4;case"double":return 8;default:{if(type.endsWith("*")){return POINTER_SIZE}if(type[0]==="i"){const bits=Number(type.slice(1));assert(bits%8===0,`getNativeTypeSize invalid bits ${bits}, ${type} type`);return bits/8}return 0}}}var onInits=[];var addOnInit=cb=>onInits.push(cb);var onMains=[];var addOnPreMain=cb=>onMains.push(cb);var onExits=[];var addOnExit=cb=>onExits.push(cb);var STACK_SIZE=5242880;var STACK_ALIGN=16;var ASSERTIONS=0;var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer>>>0)};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};var removeFunction=index=>{functionsInTableMap.delete(getWasmTableEntry(index));setWasmTableEntry(index,null);freeTableIndexes.push(index)};var _emscripten_math_cbrt=Math.cbrt;_emscripten_math_cbrt.sig="dd";var _emscripten_math_pow=Math.pow;_emscripten_math_pow.sig="ddd";var _emscripten_math_random=Math.random;_emscripten_math_random.sig="d";var _emscripten_math_sign=Math.sign;_emscripten_math_sign.sig="dd";var _emscripten_math_sqrt=Math.sqrt;_emscripten_math_sqrt.sig="dd";var _emscripten_math_exp=Math.exp;_emscripten_math_exp.sig="dd";var _emscripten_math_expm1=Math.expm1;_emscripten_math_expm1.sig="dd";var _emscripten_math_fmod=(x,y)=>x%y;_emscripten_math_fmod.sig="ddd";var _emscripten_math_log=Math.log;_emscripten_math_log.sig="dd";var _emscripten_math_log1p=Math.log1p;_emscripten_math_log1p.sig="dd";var _emscripten_math_log10=Math.log10;_emscripten_math_log10.sig="dd";var _emscripten_math_log2=Math.log2;_emscripten_math_log2.sig="dd";var _emscripten_math_round=Math.round;_emscripten_math_round.sig="dd";var _emscripten_math_acos=Math.acos;_emscripten_math_acos.sig="dd";var _emscripten_math_acosh=Math.acosh;_emscripten_math_acosh.sig="dd";var _emscripten_math_asin=Math.asin;_emscripten_math_asin.sig="dd";var _emscripten_math_asinh=Math.asinh;_emscripten_math_asinh.sig="dd";var _emscripten_math_atan=Math.atan;_emscripten_math_atan.sig="dd";var _emscripten_math_atanh=Math.atanh;_emscripten_math_atanh.sig="dd";var _emscripten_math_atan2=Math.atan2;_emscripten_math_atan2.sig="ddd";var _emscripten_math_cos=Math.cos;_emscripten_math_cos.sig="dd";var _emscripten_math_cosh=Math.cosh;_emscripten_math_cosh.sig="dd";function _emscripten_math_hypot(count,varargs){varargs>>>=0;var args=[];for(var i=0;i>>3>>>0])}return Math.hypot(...args)}_emscripten_math_hypot.sig="dip";var _emscripten_math_sin=Math.sin;_emscripten_math_sin.sig="dd";var _emscripten_math_sinh=Math.sinh;_emscripten_math_sinh.sig="dd";var _emscripten_math_tan=Math.tan;_emscripten_math_tan.sig="dd";var _emscripten_math_tanh=Math.tanh;_emscripten_math_tanh.sig="dd";var intArrayToString=array=>{var ret=[];for(var i=0;i255){chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")};var AsciiToString=ptr=>{ptr>>>=0;var str="";while(1){var ch=HEAPU8[ptr++>>>0];if(!ch)return str;str+=String.fromCharCode(ch)}};var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var idx=ptr>>>1;var maxIdx=idx+maxBytesToRead/2;var endIdx=idx;while(!(endIdx>=maxIdx)&&HEAPU16[endIdx>>>0])++endIdx;if(endIdx-idx>16&&UTF16Decoder)return UTF16Decoder.decode(HEAPU16.subarray(idx>>>0,endIdx>>>0));var str="";for(var i=idx;!(i>=maxIdx);++i){var codeUnit=HEAPU16[i>>>0];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>>1>>>0]=codeUnit;outPtr+=2}HEAP16[outPtr>>>1>>>0]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>>2>>>0];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{outPtr>>>=0;maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>>2>>>0]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>>2>>>0]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var JSEvents={memcpy(target,src,size){HEAP8.set(HEAP8.subarray(src>>>0,src+size>>>0),target>>>0)},removeAllEventListeners(){while(JSEvents.eventHandlers.length){JSEvents._removeHandler(JSEvents.eventHandlers.length-1)}JSEvents.deferredCalls=[]},registerRemoveEventListeners(){if(!JSEvents.removeEventListenersRegistered){addOnExit(JSEvents.removeAllEventListeners);JSEvents.removeEventListenersRegistered=true}},inEventHandler:0,deferredCalls:[],deferCall(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var call of JSEvents.deferredCalls){if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction,precedence,argsList});JSEvents.deferredCalls.sort((x,y)=>x.precedencecall.targetFunction!=targetFunction)},canPerformEventHandlerRequests(){if(navigator.userActivation){return navigator.userActivation.isActive}return JSEvents.inEventHandler&&JSEvents.currentEventHandler.allowsDeferredCalls},runDeferredCalls(){if(!JSEvents.canPerformEventHandlerRequests()){return}var deferredCalls=JSEvents.deferredCalls;JSEvents.deferredCalls=[];for(var call of deferredCalls){call.targetFunction(...call.argsList)}},eventHandlers:[],removeAllHandlersOnTarget:(target,eventTypeString)=>{for(var i=0;icString>2?UTF8ToString(cString):cString;var specialHTMLTargets=[0,typeof document!="undefined"?document:0,typeof window!="undefined"?window:0];var findEventTarget=target=>{target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||(typeof document!="undefined"?document.querySelector(target):null);return domElement};var registerKeyEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.keyEvent||=_malloc(160);var keyEventHandlerFunc=e=>{var keyEventData=JSEvents.keyEvent;HEAPF64[keyEventData>>>3>>>0]=e.timeStamp;var idx=keyEventData>>>2;HEAP32[idx+2>>>0]=e.location;HEAP8[keyEventData+12>>>0]=e.ctrlKey;HEAP8[keyEventData+13>>>0]=e.shiftKey;HEAP8[keyEventData+14>>>0]=e.altKey;HEAP8[keyEventData+15>>>0]=e.metaKey;HEAP8[keyEventData+16>>>0]=e.repeat;HEAP32[idx+5>>>0]=e.charCode;HEAP32[idx+6>>>0]=e.keyCode;HEAP32[idx+7>>>0]=e.which;stringToUTF8(e.key||"",keyEventData+32,32);stringToUTF8(e.code||"",keyEventData+64,32);stringToUTF8(e.char||"",keyEventData+96,32);stringToUTF8(e.locale||"",keyEventData+128,32);if(getWasmTableEntry(callbackfunc)(eventTypeId,keyEventData,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString,callbackfunc,handlerFunc:keyEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};var findCanvasEventTarget=findEventTarget;function _emscripten_set_keypress_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,1,"keypress",targetThread)}_emscripten_set_keypress_callback_on_thread.sig="ippipp";function _emscripten_set_keydown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,2,"keydown",targetThread)}_emscripten_set_keydown_callback_on_thread.sig="ippipp";function _emscripten_set_keyup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,3,"keyup",targetThread)}_emscripten_set_keyup_callback_on_thread.sig="ippipp";var getBoundingClientRect=e=>specialHTMLTargets.indexOf(e)<0?e.getBoundingClientRect():{left:0,top:0};var fillMouseEventData=(eventStruct,e,target)=>{HEAPF64[eventStruct>>>3>>>0]=e.timeStamp;var idx=eventStruct>>>2;HEAP32[idx+2>>>0]=e.screenX;HEAP32[idx+3>>>0]=e.screenY;HEAP32[idx+4>>>0]=e.clientX;HEAP32[idx+5>>>0]=e.clientY;HEAP8[eventStruct+24>>>0]=e.ctrlKey;HEAP8[eventStruct+25>>>0]=e.shiftKey;HEAP8[eventStruct+26>>>0]=e.altKey;HEAP8[eventStruct+27>>>0]=e.metaKey;HEAP16[idx*2+14>>>0]=e.button;HEAP16[idx*2+15>>>0]=e.buttons;HEAP32[idx+8>>>0]=e["movementX"];HEAP32[idx+9>>>0]=e["movementY"];var rect=getBoundingClientRect(target);HEAP32[idx+10>>>0]=e.clientX-(rect.left|0);HEAP32[idx+11>>>0]=e.clientY-(rect.top|0)};var registerMouseEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.mouseEvent||=_malloc(64);target=findEventTarget(target);var mouseEventHandlerFunc=(e=event)=>{fillMouseEventData(JSEvents.mouseEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.mouseEvent,userData))e.preventDefault()};var eventHandler={target,allowsDeferredCalls:eventTypeString!="mousemove"&&eventTypeString!="mouseenter"&&eventTypeString!="mouseleave",eventTypeString,callbackfunc,handlerFunc:mouseEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_click_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,4,"click",targetThread)}_emscripten_set_click_callback_on_thread.sig="ippipp";function _emscripten_set_mousedown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,5,"mousedown",targetThread)}_emscripten_set_mousedown_callback_on_thread.sig="ippipp";function _emscripten_set_mouseup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,6,"mouseup",targetThread)}_emscripten_set_mouseup_callback_on_thread.sig="ippipp";function _emscripten_set_dblclick_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,7,"dblclick",targetThread)}_emscripten_set_dblclick_callback_on_thread.sig="ippipp";function _emscripten_set_mousemove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,8,"mousemove",targetThread)}_emscripten_set_mousemove_callback_on_thread.sig="ippipp";function _emscripten_set_mouseenter_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,33,"mouseenter",targetThread)}_emscripten_set_mouseenter_callback_on_thread.sig="ippipp";function _emscripten_set_mouseleave_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,34,"mouseleave",targetThread)}_emscripten_set_mouseleave_callback_on_thread.sig="ippipp";function _emscripten_set_mouseover_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,35,"mouseover",targetThread)}_emscripten_set_mouseover_callback_on_thread.sig="ippipp";function _emscripten_set_mouseout_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,36,"mouseout",targetThread)}_emscripten_set_mouseout_callback_on_thread.sig="ippipp";function _emscripten_get_mouse_status(mouseState){mouseState>>>=0;if(!JSEvents.mouseEvent)return-7;JSEvents.memcpy(mouseState,JSEvents.mouseEvent,64);return 0}_emscripten_get_mouse_status.sig="ip";var registerWheelEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.wheelEvent||=_malloc(96);var wheelHandlerFunc=(e=event)=>{var wheelEvent=JSEvents.wheelEvent;fillMouseEventData(wheelEvent,e,target);HEAPF64[wheelEvent+64>>>3>>>0]=e["deltaX"];HEAPF64[wheelEvent+72>>>3>>>0]=e["deltaY"];HEAPF64[wheelEvent+80>>>3>>>0]=e["deltaZ"];HEAP32[wheelEvent+88>>>2>>>0]=e["deltaMode"];if(getWasmTableEntry(callbackfunc)(eventTypeId,wheelEvent,userData))e.preventDefault()};var eventHandler={target,allowsDeferredCalls:true,eventTypeString,callbackfunc,handlerFunc:wheelHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_wheel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;target=findEventTarget(target);if(!target)return-4;if(typeof target.onwheel!="undefined"){return registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"wheel",targetThread)}else{return-1}}_emscripten_set_wheel_callback_on_thread.sig="ippipp";var registerUiEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.uiEvent||=_malloc(36);target=findEventTarget(target);var uiEventHandlerFunc=(e=event)=>{if(e.target!=target){return}var b=document.body;if(!b){return}var uiEvent=JSEvents.uiEvent;HEAP32[uiEvent>>>2>>>0]=0;HEAP32[uiEvent+4>>>2>>>0]=b.clientWidth;HEAP32[uiEvent+8>>>2>>>0]=b.clientHeight;HEAP32[uiEvent+12>>>2>>>0]=innerWidth;HEAP32[uiEvent+16>>>2>>>0]=innerHeight;HEAP32[uiEvent+20>>>2>>>0]=outerWidth;HEAP32[uiEvent+24>>>2>>>0]=outerHeight;HEAP32[uiEvent+28>>>2>>>0]=pageXOffset|0;HEAP32[uiEvent+32>>>2>>>0]=pageYOffset|0;if(getWasmTableEntry(callbackfunc)(eventTypeId,uiEvent,userData))e.preventDefault()};var eventHandler={target,eventTypeString,callbackfunc,handlerFunc:uiEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_resize_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerUiEventCallback(target,userData,useCapture,callbackfunc,10,"resize",targetThread)}_emscripten_set_resize_callback_on_thread.sig="ippipp";function _emscripten_set_scroll_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerUiEventCallback(target,userData,useCapture,callbackfunc,11,"scroll",targetThread)}_emscripten_set_scroll_callback_on_thread.sig="ippipp";var registerFocusEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.focusEvent||=_malloc(256);var focusEventHandlerFunc=(e=event)=>{var nodeName=JSEvents.getNodeNameForTarget(e.target);var id=e.target.id?e.target.id:"";var focusEvent=JSEvents.focusEvent;stringToUTF8(nodeName,focusEvent+0,128);stringToUTF8(id,focusEvent+128,128);if(getWasmTableEntry(callbackfunc)(eventTypeId,focusEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString,callbackfunc,handlerFunc:focusEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_blur_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,12,"blur",targetThread)}_emscripten_set_blur_callback_on_thread.sig="ippipp";function _emscripten_set_focus_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,13,"focus",targetThread)}_emscripten_set_focus_callback_on_thread.sig="ippipp";function _emscripten_set_focusin_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,14,"focusin",targetThread)}_emscripten_set_focusin_callback_on_thread.sig="ippipp";function _emscripten_set_focusout_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,15,"focusout",targetThread)}_emscripten_set_focusout_callback_on_thread.sig="ippipp";var fillDeviceOrientationEventData=(eventStruct,e,target)=>{HEAPF64[eventStruct>>>3>>>0]=e.alpha;HEAPF64[eventStruct+8>>>3>>>0]=e.beta;HEAPF64[eventStruct+16>>>3>>>0]=e.gamma;HEAP8[eventStruct+24>>>0]=e.absolute};var registerDeviceOrientationEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.deviceOrientationEvent||=_malloc(32);var deviceOrientationEventHandlerFunc=(e=event)=>{fillDeviceOrientationEventData(JSEvents.deviceOrientationEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.deviceOrientationEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString,callbackfunc,handlerFunc:deviceOrientationEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_deviceorientation_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerDeviceOrientationEventCallback(2,userData,useCapture,callbackfunc,16,"deviceorientation",targetThread)}_emscripten_set_deviceorientation_callback_on_thread.sig="ipipp";function _emscripten_get_deviceorientation_status(orientationState){orientationState>>>=0;if(!JSEvents.deviceOrientationEvent)return-7;JSEvents.memcpy(orientationState,JSEvents.deviceOrientationEvent,32);return 0}_emscripten_get_deviceorientation_status.sig="ip";var fillDeviceMotionEventData=(eventStruct,e,target)=>{var supportedFields=0;var a=e["acceleration"];supportedFields|=a&&1;var ag=e["accelerationIncludingGravity"];supportedFields|=ag&&2;var rr=e["rotationRate"];supportedFields|=rr&&4;a=a||{};ag=ag||{};rr=rr||{};HEAPF64[eventStruct>>>3>>>0]=a["x"];HEAPF64[eventStruct+8>>>3>>>0]=a["y"];HEAPF64[eventStruct+16>>>3>>>0]=a["z"];HEAPF64[eventStruct+24>>>3>>>0]=ag["x"];HEAPF64[eventStruct+32>>>3>>>0]=ag["y"];HEAPF64[eventStruct+40>>>3>>>0]=ag["z"];HEAPF64[eventStruct+48>>>3>>>0]=rr["alpha"];HEAPF64[eventStruct+56>>>3>>>0]=rr["beta"];HEAPF64[eventStruct+64>>>3>>>0]=rr["gamma"]};var registerDeviceMotionEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.deviceMotionEvent||=_malloc(80);var deviceMotionEventHandlerFunc=(e=event)=>{fillDeviceMotionEventData(JSEvents.deviceMotionEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.deviceMotionEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString,callbackfunc,handlerFunc:deviceMotionEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_devicemotion_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerDeviceMotionEventCallback(2,userData,useCapture,callbackfunc,17,"devicemotion",targetThread)}_emscripten_set_devicemotion_callback_on_thread.sig="ipipp";function _emscripten_get_devicemotion_status(motionState){motionState>>>=0;if(!JSEvents.deviceMotionEvent)return-7;JSEvents.memcpy(motionState,JSEvents.deviceMotionEvent,80);return 0}_emscripten_get_devicemotion_status.sig="ip";var screenOrientation=()=>{if(!window.screen)return undefined;return screen.orientation||screen["mozOrientation"]||screen["webkitOrientation"]};var fillOrientationChangeEventData=eventStruct=>{var orientationsType1=["portrait-primary","portrait-secondary","landscape-primary","landscape-secondary"];var orientationsType2=["portrait","portrait","landscape","landscape"];var orientationIndex=0;var orientationAngle=0;var screenOrientObj=screenOrientation();if(typeof screenOrientObj==="object"){orientationIndex=orientationsType1.indexOf(screenOrientObj.type);if(orientationIndex<0){orientationIndex=orientationsType2.indexOf(screenOrientObj.type)}if(orientationIndex>=0){orientationIndex=1<>>2>>>0]=orientationIndex;HEAP32[eventStruct+4>>>2>>>0]=orientationAngle};var registerOrientationChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.orientationChangeEvent||=_malloc(8);var orientationChangeEventHandlerFunc=(e=event)=>{var orientationChangeEvent=JSEvents.orientationChangeEvent;fillOrientationChangeEventData(orientationChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,orientationChangeEvent,userData))e.preventDefault()};var eventHandler={target,eventTypeString,callbackfunc,handlerFunc:orientationChangeEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_orientationchange_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!window.screen||!screen.orientation)return-1;return registerOrientationChangeEventCallback(screen.orientation,userData,useCapture,callbackfunc,18,"change",targetThread)}_emscripten_set_orientationchange_callback_on_thread.sig="ipipp";function _emscripten_get_orientation_status(orientationChangeEvent){orientationChangeEvent>>>=0;if(!screenOrientation()&&typeof orientation=="undefined")return-1;fillOrientationChangeEventData(orientationChangeEvent);return 0}_emscripten_get_orientation_status.sig="ip";var _emscripten_lock_orientation=allowedOrientations=>{var orientations=[];if(allowedOrientations&1)orientations.push("portrait-primary");if(allowedOrientations&2)orientations.push("portrait-secondary");if(allowedOrientations&4)orientations.push("landscape-primary");if(allowedOrientations&8)orientations.push("landscape-secondary");var succeeded;if(screen.lockOrientation){succeeded=screen.lockOrientation(orientations)}else if(screen.mozLockOrientation){succeeded=screen.mozLockOrientation(orientations)}else if(screen.webkitLockOrientation){succeeded=screen.webkitLockOrientation(orientations)}else{return-1}if(succeeded){return 0}return-6};_emscripten_lock_orientation.sig="ii";var _emscripten_unlock_orientation=()=>{if(screen.unlockOrientation){screen.unlockOrientation()}else if(screen.mozUnlockOrientation){screen.mozUnlockOrientation()}else if(screen.webkitUnlockOrientation){screen.webkitUnlockOrientation()}else{return-1}return 0};_emscripten_unlock_orientation.sig="i";var fillFullscreenChangeEventData=eventStruct=>{var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;var isFullscreen=!!fullscreenElement;HEAP8[eventStruct>>>0]=isFullscreen;HEAP8[eventStruct+1>>>0]=JSEvents.fullscreenEnabled();var reportedElement=isFullscreen?fullscreenElement:JSEvents.previousFullscreenElement;var nodeName=JSEvents.getNodeNameForTarget(reportedElement);var id=reportedElement?.id||"";stringToUTF8(nodeName,eventStruct+2,128);stringToUTF8(id,eventStruct+130,128);HEAP32[eventStruct+260>>>2>>>0]=reportedElement?reportedElement.clientWidth:0;HEAP32[eventStruct+264>>>2>>>0]=reportedElement?reportedElement.clientHeight:0;HEAP32[eventStruct+268>>>2>>>0]=screen.width;HEAP32[eventStruct+272>>>2>>>0]=screen.height;if(isFullscreen){JSEvents.previousFullscreenElement=fullscreenElement}};var registerFullscreenChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.fullscreenChangeEvent||=_malloc(276);var fullscreenChangeEventhandlerFunc=(e=event)=>{var fullscreenChangeEvent=JSEvents.fullscreenChangeEvent;fillFullscreenChangeEventData(fullscreenChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,fullscreenChangeEvent,userData))e.preventDefault()};var eventHandler={target,eventTypeString,callbackfunc,handlerFunc:fullscreenChangeEventhandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_fullscreenchange_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!JSEvents.fullscreenEnabled())return-1;target=findEventTarget(target);if(!target)return-4;registerFullscreenChangeEventCallback(target,userData,useCapture,callbackfunc,19,"webkitfullscreenchange",targetThread);return registerFullscreenChangeEventCallback(target,userData,useCapture,callbackfunc,19,"fullscreenchange",targetThread)}_emscripten_set_fullscreenchange_callback_on_thread.sig="ippipp";function _emscripten_get_fullscreen_status(fullscreenStatus){fullscreenStatus>>>=0;if(!JSEvents.fullscreenEnabled())return-1;fillFullscreenChangeEventData(fullscreenStatus);return 0}_emscripten_get_fullscreen_status.sig="ip";function _emscripten_get_canvas_element_size(target,width,height){target>>>=0;width>>>=0;height>>>=0;var canvas=findCanvasEventTarget(target);if(!canvas)return-4;HEAP32[width>>>2>>>0]=canvas.width;HEAP32[height>>>2>>>0]=canvas.height}_emscripten_get_canvas_element_size.sig="ippp";var getCanvasElementSize=target=>{var sp=stackSave();var w=stackAlloc(8);var h=w+4;var targetInt=stringToUTF8OnStack(target.id);var ret=_emscripten_get_canvas_element_size(targetInt,w,h);var size=[HEAP32[w>>>2>>>0],HEAP32[h>>>2>>>0]];stackRestore(sp);return size};function _emscripten_set_canvas_element_size(target,width,height){target>>>=0;var canvas=findCanvasEventTarget(target);if(!canvas)return-4;canvas.width=width;canvas.height=height;return 0}_emscripten_set_canvas_element_size.sig="ipii";var setCanvasElementSize=(target,width,height)=>{if(!target.controlTransferredOffscreen){target.width=width;target.height=height}else{var sp=stackSave();var targetInt=stringToUTF8OnStack(target.id);_emscripten_set_canvas_element_size(targetInt,width,height);stackRestore(sp)}};var currentFullscreenStrategy={};var registerRestoreOldStyle=canvas=>{var canvasSize=getCanvasElementSize(canvas);var oldWidth=canvasSize[0];var oldHeight=canvasSize[1];var oldCssWidth=canvas.style.width;var oldCssHeight=canvas.style.height;var oldBackgroundColor=canvas.style.backgroundColor;var oldDocumentBackgroundColor=document.body.style.backgroundColor;var oldPaddingLeft=canvas.style.paddingLeft;var oldPaddingRight=canvas.style.paddingRight;var oldPaddingTop=canvas.style.paddingTop;var oldPaddingBottom=canvas.style.paddingBottom;var oldMarginLeft=canvas.style.marginLeft;var oldMarginRight=canvas.style.marginRight;var oldMarginTop=canvas.style.marginTop;var oldMarginBottom=canvas.style.marginBottom;var oldDocumentBodyMargin=document.body.style.margin;var oldDocumentOverflow=document.documentElement.style.overflow;var oldDocumentScroll=document.body.scroll;var oldImageRendering=canvas.style.imageRendering;function restoreOldStyle(){var fullscreenElement=document.fullscreenElement||document.webkitFullscreenElement;if(!fullscreenElement){document.removeEventListener("fullscreenchange",restoreOldStyle);document.removeEventListener("webkitfullscreenchange",restoreOldStyle);setCanvasElementSize(canvas,oldWidth,oldHeight);canvas.style.width=oldCssWidth;canvas.style.height=oldCssHeight;canvas.style.backgroundColor=oldBackgroundColor;if(!oldDocumentBackgroundColor)document.body.style.backgroundColor="white";document.body.style.backgroundColor=oldDocumentBackgroundColor;canvas.style.paddingLeft=oldPaddingLeft;canvas.style.paddingRight=oldPaddingRight;canvas.style.paddingTop=oldPaddingTop;canvas.style.paddingBottom=oldPaddingBottom;canvas.style.marginLeft=oldMarginLeft;canvas.style.marginRight=oldMarginRight;canvas.style.marginTop=oldMarginTop;canvas.style.marginBottom=oldMarginBottom;document.body.style.margin=oldDocumentBodyMargin;document.documentElement.style.overflow=oldDocumentOverflow;document.body.scroll=oldDocumentScroll;canvas.style.imageRendering=oldImageRendering;if(canvas.GLctxObject)canvas.GLctxObject.GLctx.viewport(0,0,oldWidth,oldHeight);if(currentFullscreenStrategy.canvasResizedCallback){getWasmTableEntry(currentFullscreenStrategy.canvasResizedCallback)(37,0,currentFullscreenStrategy.canvasResizedCallbackUserData)}}}document.addEventListener("fullscreenchange",restoreOldStyle);document.addEventListener("webkitfullscreenchange",restoreOldStyle);return restoreOldStyle};var setLetterbox=(element,topBottom,leftRight)=>{element.style.paddingLeft=element.style.paddingRight=leftRight+"px";element.style.paddingTop=element.style.paddingBottom=topBottom+"px"};var JSEvents_resizeCanvasForFullscreen=(target,strategy)=>{var restoreOldStyle=registerRestoreOldStyle(target);var cssWidth=strategy.softFullscreen?innerWidth:screen.width;var cssHeight=strategy.softFullscreen?innerHeight:screen.height;var rect=getBoundingClientRect(target);var windowedCssWidth=rect.width;var windowedCssHeight=rect.height;var canvasSize=getCanvasElementSize(target);var windowedRttWidth=canvasSize[0];var windowedRttHeight=canvasSize[1];if(strategy.scaleMode==3){setLetterbox(target,(cssHeight-windowedCssHeight)/2,(cssWidth-windowedCssWidth)/2);cssWidth=windowedCssWidth;cssHeight=windowedCssHeight}else if(strategy.scaleMode==2){if(cssWidth*windowedRttHeight{if(strategy.scaleMode!=0||strategy.canvasResolutionScaleMode!=0){JSEvents_resizeCanvasForFullscreen(target,strategy)}if(target.requestFullscreen){target.requestFullscreen()}else if(target.webkitRequestFullscreen){target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}else{return JSEvents.fullscreenEnabled()?-3:-1}currentFullscreenStrategy=strategy;if(strategy.canvasResizedCallback){getWasmTableEntry(strategy.canvasResizedCallback)(37,0,strategy.canvasResizedCallbackUserData)}return 0};var hideEverythingExceptGivenElement=onlyVisibleElement=>{var child=onlyVisibleElement;var parent=child.parentNode;var hiddenElements=[];while(child!=document.body){var children=parent.children;for(var currChild of children){if(currChild!=child){hiddenElements.push({node:currChild,displayState:currChild.style.display});currChild.style.display="none"}}child=parent;parent=parent.parentNode}return hiddenElements};var restoreHiddenElements=hiddenElements=>{for(var elem of hiddenElements){elem.node.style.display=elem.displayState}};var restoreOldWindowedStyle=null;var softFullscreenResizeWebGLRenderTarget=()=>{var dpr=devicePixelRatio;var inHiDPIFullscreenMode=currentFullscreenStrategy.canvasResolutionScaleMode==2;var inAspectRatioFixedFullscreenMode=currentFullscreenStrategy.scaleMode==2;var inPixelPerfectFullscreenMode=currentFullscreenStrategy.canvasResolutionScaleMode!=0;var inCenteredWithoutScalingFullscreenMode=currentFullscreenStrategy.scaleMode==3;var screenWidth=inHiDPIFullscreenMode?Math.round(innerWidth*dpr):innerWidth;var screenHeight=inHiDPIFullscreenMode?Math.round(innerHeight*dpr):innerHeight;var w=screenWidth;var h=screenHeight;var canvas=currentFullscreenStrategy.target;var canvasSize=getCanvasElementSize(canvas);var x=canvasSize[0];var y=canvasSize[1];var topMargin;if(inAspectRatioFixedFullscreenMode){if(w*yx*h)w=h*x/y|0;topMargin=(screenHeight-h)/2|0}if(inPixelPerfectFullscreenMode){setCanvasElementSize(canvas,w,h);if(canvas.GLctxObject)canvas.GLctxObject.GLctx.viewport(0,0,w,h)}if(inHiDPIFullscreenMode){topMargin/=dpr;w/=dpr;h/=dpr;w=Math.round(w*1e4)/1e4;h=Math.round(h*1e4)/1e4;topMargin=Math.round(topMargin*1e4)/1e4}if(inCenteredWithoutScalingFullscreenMode){var t=(innerHeight-jstoi_q(canvas.style.height))/2;var b=(innerWidth-jstoi_q(canvas.style.width))/2;setLetterbox(canvas,t,b)}else{canvas.style.width=w+"px";canvas.style.height=h+"px";var b=(innerWidth-w)/2;setLetterbox(canvas,topMargin,b)}if(!inCenteredWithoutScalingFullscreenMode&¤tFullscreenStrategy.canvasResizedCallback){getWasmTableEntry(currentFullscreenStrategy.canvasResizedCallback)(37,0,currentFullscreenStrategy.canvasResizedCallbackUserData)}};var doRequestFullscreen=(target,strategy)=>{if(!JSEvents.fullscreenEnabled())return-1;target=findEventTarget(target);if(!target)return-4;if(!target.requestFullscreen&&!target.webkitRequestFullscreen){return-3}if(!JSEvents.canPerformEventHandlerRequests()){if(strategy.deferUntilInEventHandler){JSEvents.deferCall(JSEvents_requestFullscreen,1,[target,strategy]);return 1}return-2}return JSEvents_requestFullscreen(target,strategy)};function _emscripten_request_fullscreen(target,deferUntilInEventHandler){target>>>=0;var strategy={scaleMode:0,canvasResolutionScaleMode:0,filteringMode:0,deferUntilInEventHandler,canvasResizedCallbackTargetThread:2};return doRequestFullscreen(target,strategy)}_emscripten_request_fullscreen.sig="ipi";function _emscripten_request_fullscreen_strategy(target,deferUntilInEventHandler,fullscreenStrategy){target>>>=0;fullscreenStrategy>>>=0;var strategy={scaleMode:HEAP32[fullscreenStrategy>>>2>>>0],canvasResolutionScaleMode:HEAP32[fullscreenStrategy+4>>>2>>>0],filteringMode:HEAP32[fullscreenStrategy+8>>>2>>>0],deferUntilInEventHandler,canvasResizedCallback:HEAP32[fullscreenStrategy+12>>>2>>>0],canvasResizedCallbackUserData:HEAP32[fullscreenStrategy+16>>>2>>>0]};return doRequestFullscreen(target,strategy)}_emscripten_request_fullscreen_strategy.sig="ipip";function _emscripten_enter_soft_fullscreen(target,fullscreenStrategy){target>>>=0;fullscreenStrategy>>>=0;target=findEventTarget(target);if(!target)return-4;var strategy={scaleMode:HEAP32[fullscreenStrategy>>>2>>>0],canvasResolutionScaleMode:HEAP32[fullscreenStrategy+4>>>2>>>0],filteringMode:HEAP32[fullscreenStrategy+8>>>2>>>0],canvasResizedCallback:HEAP32[fullscreenStrategy+12>>>2>>>0],canvasResizedCallbackUserData:HEAP32[fullscreenStrategy+16>>>2>>>0],target,softFullscreen:true};var restoreOldStyle=JSEvents_resizeCanvasForFullscreen(target,strategy);document.documentElement.style.overflow="hidden";document.body.scroll="no";document.body.style.margin="0px";var hiddenElements=hideEverythingExceptGivenElement(target);function restoreWindowedState(){restoreOldStyle();restoreHiddenElements(hiddenElements);removeEventListener("resize",softFullscreenResizeWebGLRenderTarget);if(strategy.canvasResizedCallback){getWasmTableEntry(strategy.canvasResizedCallback)(37,0,strategy.canvasResizedCallbackUserData)}currentFullscreenStrategy=0}restoreOldWindowedStyle=restoreWindowedState;currentFullscreenStrategy=strategy;addEventListener("resize",softFullscreenResizeWebGLRenderTarget);if(strategy.canvasResizedCallback){getWasmTableEntry(strategy.canvasResizedCallback)(37,0,strategy.canvasResizedCallbackUserData)}return 0}_emscripten_enter_soft_fullscreen.sig="ipp";var _emscripten_exit_soft_fullscreen=()=>{restoreOldWindowedStyle?.();restoreOldWindowedStyle=null;return 0};_emscripten_exit_soft_fullscreen.sig="i";var _emscripten_exit_fullscreen=()=>{if(!JSEvents.fullscreenEnabled())return-1;JSEvents.removeDeferredCalls(JSEvents_requestFullscreen);var d=specialHTMLTargets[1];if(d.exitFullscreen){d.fullscreenElement&&d.exitFullscreen()}else if(d.webkitExitFullscreen){d.webkitFullscreenElement&&d.webkitExitFullscreen()}else{return-1}return 0};_emscripten_exit_fullscreen.sig="i";var fillPointerlockChangeEventData=eventStruct=>{var pointerLockElement=document.pointerLockElement||document.mozPointerLockElement||document.webkitPointerLockElement||document.msPointerLockElement;var isPointerlocked=!!pointerLockElement;HEAP8[eventStruct>>>0]=isPointerlocked;var nodeName=JSEvents.getNodeNameForTarget(pointerLockElement);var id=pointerLockElement?.id||"";stringToUTF8(nodeName,eventStruct+1,128);stringToUTF8(id,eventStruct+129,128)};var registerPointerlockChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.pointerlockChangeEvent||=_malloc(257);var pointerlockChangeEventHandlerFunc=(e=event)=>{var pointerlockChangeEvent=JSEvents.pointerlockChangeEvent;fillPointerlockChangeEventData(pointerlockChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,pointerlockChangeEvent,userData))e.preventDefault()};var eventHandler={target,eventTypeString,callbackfunc,handlerFunc:pointerlockChangeEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_pointerlockchange_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!document||!document.body||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}target=findEventTarget(target);if(!target)return-4;registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"mozpointerlockchange",targetThread);registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"webkitpointerlockchange",targetThread);registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"mspointerlockchange",targetThread);return registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"pointerlockchange",targetThread)}_emscripten_set_pointerlockchange_callback_on_thread.sig="ippipp";var registerPointerlockErrorEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{var pointerlockErrorEventHandlerFunc=(e=event)=>{if(getWasmTableEntry(callbackfunc)(eventTypeId,0,userData))e.preventDefault()};var eventHandler={target,eventTypeString,callbackfunc,handlerFunc:pointerlockErrorEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_pointerlockerror_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!document||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}target=findEventTarget(target);if(!target)return-4;registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"mozpointerlockerror",targetThread);registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"webkitpointerlockerror",targetThread);registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"mspointerlockerror",targetThread);return registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"pointerlockerror",targetThread)}_emscripten_set_pointerlockerror_callback_on_thread.sig="ippipp";function _emscripten_get_pointerlock_status(pointerlockStatus){pointerlockStatus>>>=0;if(pointerlockStatus)fillPointerlockChangeEventData(pointerlockStatus);if(!document.body||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}return 0}_emscripten_get_pointerlock_status.sig="ip";var requestPointerLock=target=>{if(target.requestPointerLock){target.requestPointerLock()}else{if(document.body.requestPointerLock){return-3}return-1}return 0};function _emscripten_request_pointerlock(target,deferUntilInEventHandler){target>>>=0;target=findEventTarget(target);if(!target)return-4;if(!target.requestPointerLock){return-1}if(!JSEvents.canPerformEventHandlerRequests()){if(deferUntilInEventHandler){JSEvents.deferCall(requestPointerLock,2,[target]);return 1}return-2}return requestPointerLock(target)}_emscripten_request_pointerlock.sig="ipi";var _emscripten_exit_pointerlock=()=>{JSEvents.removeDeferredCalls(requestPointerLock);if(document.exitPointerLock){document.exitPointerLock()}else{return-1}return 0};_emscripten_exit_pointerlock.sig="i";var _emscripten_vibrate=msecs=>{if(!navigator.vibrate)return-1;navigator.vibrate(msecs);return 0};_emscripten_vibrate.sig="ii";function _emscripten_vibrate_pattern(msecsArray,numEntries){msecsArray>>>=0;if(!navigator.vibrate)return-1;var vibrateList=[];for(var i=0;i>>2>>>0];vibrateList.push(msecs)}navigator.vibrate(vibrateList);return 0}_emscripten_vibrate_pattern.sig="ipi";var fillVisibilityChangeEventData=eventStruct=>{var visibilityStates=["hidden","visible","prerender","unloaded"];var visibilityState=visibilityStates.indexOf(document.visibilityState);HEAP8[eventStruct>>>0]=document.hidden;HEAP32[eventStruct+4>>>2>>>0]=visibilityState};var registerVisibilityChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.visibilityChangeEvent||=_malloc(8);var visibilityChangeEventHandlerFunc=(e=event)=>{var visibilityChangeEvent=JSEvents.visibilityChangeEvent;fillVisibilityChangeEventData(visibilityChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,visibilityChangeEvent,userData))e.preventDefault()};var eventHandler={target,eventTypeString,callbackfunc,handlerFunc:visibilityChangeEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_visibilitychange_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!specialHTMLTargets[1]){return-4}return registerVisibilityChangeEventCallback(specialHTMLTargets[1],userData,useCapture,callbackfunc,21,"visibilitychange",targetThread)}_emscripten_set_visibilitychange_callback_on_thread.sig="ipipp";function _emscripten_get_visibility_status(visibilityStatus){visibilityStatus>>>=0;if(typeof document.visibilityState=="undefined"&&typeof document.hidden=="undefined"){return-1}fillVisibilityChangeEventData(visibilityStatus);return 0}_emscripten_get_visibility_status.sig="ip";var registerTouchEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.touchEvent||=_malloc(1552);target=findEventTarget(target);var touchEventHandlerFunc=e=>{var t,touches={},et=e.touches;for(let t of et){t.isChanged=t.onTarget=0;touches[t.identifier]=t}for(let t of e.changedTouches){t.isChanged=1;touches[t.identifier]=t}for(let t of e.targetTouches){touches[t.identifier].onTarget=1}var touchEvent=JSEvents.touchEvent;HEAPF64[touchEvent>>>3>>>0]=e.timeStamp;HEAP8[touchEvent+12>>>0]=e.ctrlKey;HEAP8[touchEvent+13>>>0]=e.shiftKey;HEAP8[touchEvent+14>>>0]=e.altKey;HEAP8[touchEvent+15>>>0]=e.metaKey;var idx=touchEvent+16;var targetRect=getBoundingClientRect(target);var numTouches=0;for(let t of Object.values(touches)){var idx32=idx>>>2;HEAP32[idx32+0>>>0]=t.identifier;HEAP32[idx32+1>>>0]=t.screenX;HEAP32[idx32+2>>>0]=t.screenY;HEAP32[idx32+3>>>0]=t.clientX;HEAP32[idx32+4>>>0]=t.clientY;HEAP32[idx32+5>>>0]=t.pageX;HEAP32[idx32+6>>>0]=t.pageY;HEAP8[idx+28>>>0]=t.isChanged;HEAP8[idx+29>>>0]=t.onTarget;HEAP32[idx32+8>>>0]=t.clientX-(targetRect.left|0);HEAP32[idx32+9>>>0]=t.clientY-(targetRect.top|0);idx+=48;if(++numTouches>31){break}}HEAP32[touchEvent+8>>>2>>>0]=numTouches;if(getWasmTableEntry(callbackfunc)(eventTypeId,touchEvent,userData))e.preventDefault()};var eventHandler={target,allowsDeferredCalls:eventTypeString=="touchstart"||eventTypeString=="touchend",eventTypeString,callbackfunc,handlerFunc:touchEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_touchstart_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,22,"touchstart",targetThread)}_emscripten_set_touchstart_callback_on_thread.sig="ippipp";function _emscripten_set_touchend_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,23,"touchend",targetThread)}_emscripten_set_touchend_callback_on_thread.sig="ippipp";function _emscripten_set_touchmove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,24,"touchmove",targetThread)}_emscripten_set_touchmove_callback_on_thread.sig="ippipp";function _emscripten_set_touchcancel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,25,"touchcancel",targetThread)}_emscripten_set_touchcancel_callback_on_thread.sig="ippipp";var fillGamepadEventData=(eventStruct,e)=>{HEAPF64[eventStruct>>>3>>>0]=e.timestamp;for(var i=0;i>>3>>>0]=e.axes[i]}for(var i=0;i>>3>>>0]=e.buttons[i].value}else{HEAPF64[eventStruct+i*8+528>>>3>>>0]=e.buttons[i]}}for(var i=0;i>>0]=e.buttons[i].pressed}else{HEAP8[eventStruct+i+1040>>>0]=e.buttons[i]==1}}HEAP8[eventStruct+1104>>>0]=e.connected;HEAP32[eventStruct+1108>>>2>>>0]=e.index;HEAP32[eventStruct+8>>>2>>>0]=e.axes.length;HEAP32[eventStruct+12>>>2>>>0]=e.buttons.length;stringToUTF8(e.id,eventStruct+1112,64);stringToUTF8(e.mapping,eventStruct+1176,64)};var registerGamepadEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.gamepadEvent||=_malloc(1240);var gamepadEventHandlerFunc=(e=event)=>{var gamepadEvent=JSEvents.gamepadEvent;fillGamepadEventData(gamepadEvent,e["gamepad"]);if(getWasmTableEntry(callbackfunc)(eventTypeId,gamepadEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),allowsDeferredCalls:true,eventTypeString,callbackfunc,handlerFunc:gamepadEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};var _emscripten_sample_gamepad_data=()=>{try{if(navigator.getGamepads)return(JSEvents.lastGamepadState=navigator.getGamepads())?0:-1}catch(e){navigator.getGamepads=null}return-1};_emscripten_sample_gamepad_data.sig="i";function _emscripten_set_gamepadconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(_emscripten_sample_gamepad_data())return-1;return registerGamepadEventCallback(2,userData,useCapture,callbackfunc,26,"gamepadconnected",targetThread)}_emscripten_set_gamepadconnected_callback_on_thread.sig="ipipp";function _emscripten_set_gamepaddisconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(_emscripten_sample_gamepad_data())return-1;return registerGamepadEventCallback(2,userData,useCapture,callbackfunc,27,"gamepaddisconnected",targetThread)}_emscripten_set_gamepaddisconnected_callback_on_thread.sig="ipipp";var _emscripten_get_num_gamepads=()=>JSEvents.lastGamepadState.length;_emscripten_get_num_gamepads.sig="i";function _emscripten_get_gamepad_status(index,gamepadState){gamepadState>>>=0;if(index<0||index>=JSEvents.lastGamepadState.length)return-5;if(!JSEvents.lastGamepadState[index])return-7;fillGamepadEventData(gamepadState,JSEvents.lastGamepadState[index]);return 0}_emscripten_get_gamepad_status.sig="iip";var registerBeforeUnloadEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString)=>{var beforeUnloadEventHandlerFunc=(e=event)=>{var confirmationMessage=getWasmTableEntry(callbackfunc)(eventTypeId,0,userData);if(confirmationMessage){confirmationMessage=UTF8ToString(confirmationMessage)}if(confirmationMessage){e.preventDefault();e.returnValue=confirmationMessage;return confirmationMessage}};var eventHandler={target:findEventTarget(target),eventTypeString,callbackfunc,handlerFunc:beforeUnloadEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_beforeunload_callback_on_thread(userData,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(typeof onbeforeunload=="undefined")return-1;if(targetThread!==1)return-5;return registerBeforeUnloadEventCallback(2,userData,true,callbackfunc,28,"beforeunload")}_emscripten_set_beforeunload_callback_on_thread.sig="ippp";var fillBatteryEventData=(eventStruct,e)=>{HEAPF64[eventStruct>>>3>>>0]=e.chargingTime;HEAPF64[eventStruct+8>>>3>>>0]=e.dischargingTime;HEAPF64[eventStruct+16>>>3>>>0]=e.level;HEAP8[eventStruct+24>>>0]=e.charging};var battery=()=>navigator.battery||navigator.mozBattery||navigator.webkitBattery;var registerBatteryEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{JSEvents.batteryEvent||=_malloc(32);var batteryEventHandlerFunc=(e=event)=>{var batteryEvent=JSEvents.batteryEvent;fillBatteryEventData(batteryEvent,battery());if(getWasmTableEntry(callbackfunc)(eventTypeId,batteryEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString,callbackfunc,handlerFunc:batteryEventHandlerFunc,useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_batterychargingchange_callback_on_thread(userData,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!battery())return-1;return registerBatteryEventCallback(battery(),userData,true,callbackfunc,29,"chargingchange",targetThread)}_emscripten_set_batterychargingchange_callback_on_thread.sig="ippp";function _emscripten_set_batterylevelchange_callback_on_thread(userData,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!battery())return-1;return registerBatteryEventCallback(battery(),userData,true,callbackfunc,30,"levelchange",targetThread)}_emscripten_set_batterylevelchange_callback_on_thread.sig="ippp";function _emscripten_get_battery_status(batteryState){batteryState>>>=0;if(!battery())return-1;fillBatteryEventData(batteryState,battery());return 0}_emscripten_get_battery_status.sig="ip";function _emscripten_set_element_css_size(target,width,height){target>>>=0;target=findEventTarget(target);if(!target)return-4;target.style.width=width+"px";target.style.height=height+"px";return 0}_emscripten_set_element_css_size.sig="ipdd";function _emscripten_get_element_css_size(target,width,height){target>>>=0;width>>>=0;height>>>=0;target=findEventTarget(target);if(!target)return-4;var rect=getBoundingClientRect(target);HEAPF64[width>>>3>>>0]=rect.width;HEAPF64[height>>>3>>>0]=rect.height;return 0}_emscripten_get_element_css_size.sig="ippp";var _emscripten_html5_remove_all_event_listeners=()=>JSEvents.removeAllEventListeners();_emscripten_html5_remove_all_event_listeners.sig="v";var _emscripten_request_animation_frame=function(cb,userData){cb>>>=0;userData>>>=0;return requestAnimationFrame(timeStamp=>getWasmTableEntry(cb)(timeStamp,userData))};_emscripten_request_animation_frame.sig="ipp";var _emscripten_cancel_animation_frame=id=>cancelAnimationFrame(id);_emscripten_cancel_animation_frame.sig="vi";function _emscripten_request_animation_frame_loop(cb,userData){cb>>>=0;userData>>>=0;function tick(timeStamp){if(getWasmTableEntry(cb)(timeStamp,userData)){requestAnimationFrame(tick)}}return requestAnimationFrame(tick)}_emscripten_request_animation_frame_loop.sig="vpp";var _emscripten_get_device_pixel_ratio=()=>typeof devicePixelRatio=="number"&&devicePixelRatio||1;_emscripten_get_device_pixel_ratio.sig="d";function _emscripten_get_callstack(flags,str,maxbytes){str>>>=0;var callstack=getCallstack(flags);if(!str||maxbytes<=0){return lengthBytesUTF8(callstack)+1}var bytesWrittenExcludingNull=stringToUTF8(callstack,str,maxbytes);return bytesWrittenExcludingNull+1}_emscripten_get_callstack.sig="iipi";var convertFrameToPC=frame=>{abort("Cannot use convertFrameToPC (needed by __builtin_return_address) without -sUSE_OFFSET_CONVERTER");return 0};function _emscripten_return_address(level){var callstack=jsStackTrace().split("\n");if(callstack[0]=="Error"){callstack.shift()}var caller=callstack[level+3];return convertFrameToPC(caller)}_emscripten_return_address.sig="pi";var UNWIND_CACHE={};var saveInUnwindCache=callstack=>{callstack.forEach(frame=>{var pc=convertFrameToPC(frame);if(pc){UNWIND_CACHE[pc]=frame}})};function _emscripten_stack_snapshot(){var callstack=jsStackTrace().split("\n");if(callstack[0]=="Error"){callstack.shift()}saveInUnwindCache(callstack);UNWIND_CACHE.last_addr=convertFrameToPC(callstack[3]);UNWIND_CACHE.last_stack=callstack;return UNWIND_CACHE.last_addr}_emscripten_stack_snapshot.sig="p";function _emscripten_stack_unwind_buffer(addr,buffer,count){addr>>>=0;buffer>>>=0;var stack;if(UNWIND_CACHE.last_addr==addr){stack=UNWIND_CACHE.last_stack}else{stack=jsStackTrace().split("\n");if(stack[0]=="Error"){stack.shift()}saveInUnwindCache(stack)}var offset=3;while(stack[offset]&&convertFrameToPC(stack[offset])!=addr){++offset}for(var i=0;i>>2>>>0]=convertFrameToPC(stack[i+offset])}return i}_emscripten_stack_unwind_buffer.sig="ippi";function _emscripten_pc_get_function(pc){pc>>>=0;abort("Cannot use emscripten_pc_get_function without -sUSE_OFFSET_CONVERTER");return 0}_emscripten_pc_get_function.sig="pp";var convertPCtoSourceLocation=pc=>{if(UNWIND_CACHE.last_get_source_pc==pc)return UNWIND_CACHE.last_source;var match;var source;if(!source){var frame=UNWIND_CACHE[pc];if(!frame)return null;if(match=/\((.*):(\d+):(\d+)\)$/.exec(frame)){source={file:match[1],line:match[2],column:match[3]}}else if(match=/@(.*):(\d+):(\d+)/.exec(frame)){source={file:match[1],line:match[2],column:match[3]}}}UNWIND_CACHE.last_get_source_pc=pc;UNWIND_CACHE.last_source=source;return source};function _emscripten_pc_get_file(pc){pc>>>=0;var result=convertPCtoSourceLocation(pc);if(!result)return 0;if(_emscripten_pc_get_file.ret)_free(_emscripten_pc_get_file.ret);_emscripten_pc_get_file.ret=stringToNewUTF8(result.file);return _emscripten_pc_get_file.ret}_emscripten_pc_get_file.sig="pp";function _emscripten_pc_get_line(pc){pc>>>=0;var result=convertPCtoSourceLocation(pc);return result?result.line:0}_emscripten_pc_get_line.sig="ip";function _emscripten_pc_get_column(pc){pc>>>=0;var result=convertPCtoSourceLocation(pc);return result?result.column||0:0}_emscripten_pc_get_column.sig="ip";var wasiRightsToMuslOFlags=rights=>{if(rights&2&&rights&64){return 2}if(rights&2){return 0}if(rights&64){return 1}throw new FS.ErrnoError(28)};var wasiOFlagsToMuslOFlags=oflags=>{var musl_oflags=0;if(oflags&1){musl_oflags|=64}if(oflags&8){musl_oflags|=512}if(oflags&2){musl_oflags|=65536}if(oflags&4){musl_oflags|=128}return musl_oflags};var _emscripten_unwind_to_js_event_loop=()=>{throw"unwind"};_emscripten_unwind_to_js_event_loop.sig="v";var safeSetTimeout=(func,timeout)=>{runtimeKeepalivePush();return setTimeout(()=>{runtimeKeepalivePop();callUserCallback(func)},timeout)};var setImmediateWrapped=func=>{setImmediateWrapped.mapping||=[];var id=setImmediateWrapped.mapping.length;setImmediateWrapped.mapping[id]=setImmediate(()=>{setImmediateWrapped.mapping[id]=undefined;func()});return id};var _emscripten_set_main_loop_timing=(mode,value)=>{MainLoop.timingMode=mode;MainLoop.timingValue=value;if(!MainLoop.func){return 1}if(!MainLoop.running){runtimeKeepalivePush();MainLoop.running=true}if(mode==0){MainLoop.scheduler=function MainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,MainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(MainLoop.runner,timeUntilNextTick)};MainLoop.method="timeout"}else if(mode==1){MainLoop.scheduler=function MainLoop_scheduler_rAF(){MainLoop.requestAnimationFrame(MainLoop.runner)};MainLoop.method="rAF"}else if(mode==2){if(typeof MainLoop.setImmediate=="undefined"){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var MainLoop_setImmediate_messageHandler=event=>{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",MainLoop_setImmediate_messageHandler,true);MainLoop.setImmediate=func=>{setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){Module["setImmediates"]??=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}else{MainLoop.setImmediate=setImmediate}}MainLoop.scheduler=function MainLoop_scheduler_setImmediate(){MainLoop.setImmediate(MainLoop.runner)};MainLoop.method="immediate"}return 0};_emscripten_set_main_loop_timing.sig="iii";var setMainLoop=(iterFunc,fps,simulateInfiniteLoop,arg,noSetTiming)=>{MainLoop.func=iterFunc;MainLoop.arg=arg;var thisMainLoopId=MainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=MainLoop.queue.shift();blocker.func(blocker.arg);if(MainLoop.remainingBlockers){var remaining=MainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){MainLoop.remainingBlockers=next}else{next=next+.5;MainLoop.remainingBlockers=(8*remaining+next)/9}}MainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(MainLoop.runner,0);return}if(!checkIsRunning())return;MainLoop.currentFrameNumber=MainLoop.currentFrameNumber+1|0;if(MainLoop.timingMode==1&&MainLoop.timingValue>1&&MainLoop.currentFrameNumber%MainLoop.timingValue!=0){MainLoop.scheduler();return}else if(MainLoop.timingMode==0){MainLoop.tickStartTime=_emscripten_get_now()}MainLoop.runIter(iterFunc);if(!checkIsRunning())return;MainLoop.scheduler()};if(!noSetTiming){if(fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}MainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}};var MainLoop={running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],preMainLoop:[],postMainLoop:[],pause(){MainLoop.scheduler=null;MainLoop.currentlyRunningMainloop++},resume(){MainLoop.currentlyRunningMainloop++;var timingMode=MainLoop.timingMode;var timingValue=MainLoop.timingValue;var func=MainLoop.func;MainLoop.func=null;setMainLoop(func,0,false,MainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);MainLoop.scheduler()},updateStatus(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=MainLoop.remainingBlockers??0;var expected=MainLoop.expectedBlockers??0;if(remaining){if(remaining=MainLoop.nextRAF){MainLoop.nextRAF+=1e3/60}}var delay=Math.max(MainLoop.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=MainLoop.fakeRequestAnimationFrame;RAF(func)}};var safeRequestAnimationFrame=func=>{runtimeKeepalivePush();return MainLoop.requestAnimationFrame(()=>{runtimeKeepalivePop();callUserCallback(func)})};var clearImmediateWrapped=id=>{clearImmediate(setImmediateWrapped.mapping[id]);setImmediateWrapped.mapping[id]=undefined};var emClearImmediate;var emSetImmediate;var emClearImmediate_deps=["$emSetImmediate"];var _emscripten_set_immediate=function(cb,userData){cb>>>=0;userData>>>=0;runtimeKeepalivePush();return emSetImmediate(()=>{runtimeKeepalivePop();callUserCallback(()=>getWasmTableEntry(cb)(userData))})};_emscripten_set_immediate.sig="ipp";var _emscripten_clear_immediate=id=>{runtimeKeepalivePop();emClearImmediate(id)};_emscripten_clear_immediate.sig="vi";var _emscripten_set_immediate_loop=function(cb,userData){cb>>>=0;userData>>>=0;function tick(){callUserCallback(()=>{if(getWasmTableEntry(cb)(userData)){emSetImmediate(tick)}else{runtimeKeepalivePop()}})}runtimeKeepalivePush();emSetImmediate(tick)};_emscripten_set_immediate_loop.sig="vpp";var _emscripten_set_timeout=function(cb,msecs,userData){cb>>>=0;userData>>>=0;return safeSetTimeout(()=>getWasmTableEntry(cb)(userData),msecs)};_emscripten_set_timeout.sig="ipdp";var _emscripten_clear_timeout=clearTimeout;_emscripten_clear_timeout.sig="vi";var _emscripten_set_timeout_loop=function(cb,msecs,userData){cb>>>=0;userData>>>=0;function tick(){var t=_emscripten_get_now();var n=t+msecs;runtimeKeepalivePop();callUserCallback(()=>{if(getWasmTableEntry(cb)(t,userData)){runtimeKeepalivePush();var remaining=n-_emscripten_get_now();remaining=Math.max(0,remaining);setTimeout(tick,remaining)}})}runtimeKeepalivePush();return setTimeout(tick,0)};_emscripten_set_timeout_loop.sig="vpdp";var _emscripten_set_interval=function(cb,msecs,userData){cb>>>=0;userData>>>=0;runtimeKeepalivePush();return setInterval(()=>{callUserCallback(()=>getWasmTableEntry(cb)(userData))},msecs)};_emscripten_set_interval.sig="ipdp";var _emscripten_clear_interval=id=>{runtimeKeepalivePop();clearInterval(id)};_emscripten_clear_interval.sig="vi";var _emscripten_async_call=function(func,arg,millis){func>>>=0;arg>>>=0;var wrapper=()=>getWasmTableEntry(func)(arg);if(millis>=0||ENVIRONMENT_IS_NODE){safeSetTimeout(wrapper,millis)}else{safeRequestAnimationFrame(wrapper)}};_emscripten_async_call.sig="vppi";var registerPostMainLoop=f=>{typeof MainLoop!="undefined"&&MainLoop.postMainLoop.push(f)};var registerPreMainLoop=f=>{typeof MainLoop!="undefined"&&MainLoop.preMainLoop.push(f)};function _emscripten_get_main_loop_timing(mode,value){mode>>>=0;value>>>=0;if(mode)HEAP32[mode>>>2>>>0]=MainLoop.timingMode;if(value)HEAP32[value>>>2>>>0]=MainLoop.timingValue}_emscripten_get_main_loop_timing.sig="vpp";function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){func>>>=0;var iterFunc=getWasmTableEntry(func);setMainLoop(iterFunc,fps,simulateInfiniteLoop)}_emscripten_set_main_loop.sig="vpii";var _emscripten_set_main_loop_arg=function(func,arg,fps,simulateInfiniteLoop){func>>>=0;arg>>>=0;var iterFunc=()=>getWasmTableEntry(func)(arg);setMainLoop(iterFunc,fps,simulateInfiniteLoop,arg)};_emscripten_set_main_loop_arg.sig="vppii";var _emscripten_cancel_main_loop=()=>{MainLoop.pause();MainLoop.func=null};_emscripten_cancel_main_loop.sig="v";var _emscripten_pause_main_loop=()=>MainLoop.pause();_emscripten_pause_main_loop.sig="v";var _emscripten_resume_main_loop=()=>MainLoop.resume();_emscripten_resume_main_loop.sig="v";var __emscripten_push_main_loop_blocker=function(func,arg,name){func>>>=0;arg>>>=0;name>>>=0;MainLoop.queue.push({func:()=>{getWasmTableEntry(func)(arg)},name:UTF8ToString(name),counted:true});MainLoop.updateStatus()};__emscripten_push_main_loop_blocker.sig="vppp";var __emscripten_push_uncounted_main_loop_blocker=function(func,arg,name){func>>>=0;arg>>>=0;name>>>=0;MainLoop.queue.push({func:()=>{getWasmTableEntry(func)(arg)},name:UTF8ToString(name),counted:false});MainLoop.updateStatus()};__emscripten_push_uncounted_main_loop_blocker.sig="vppp";var _emscripten_set_main_loop_expected_blockers=num=>{MainLoop.expectedBlockers=num;MainLoop.remainingBlockers=num;MainLoop.updateStatus()};_emscripten_set_main_loop_expected_blockers.sig="vi";var idsToPromises=(idBuf,size)=>{var promises=[];for(var i=0;i>>2>>>0];promises[i]=getPromise(id)}return promises};var makePromiseCallback=(callback,userData)=>value=>{runtimeKeepalivePop();var stack=stackSave();var resultPtr=stackAlloc(POINTER_SIZE);HEAPU32[resultPtr>>>2>>>0]=0;try{var result=getWasmTableEntry(callback)(resultPtr,userData,value);var resultVal=HEAPU32[resultPtr>>>2>>>0]}catch(e){if(typeof e!="number"){throw 0}throw e}finally{stackRestore(stack)}switch(result){case 0:return resultVal;case 1:return getPromise(resultVal);case 2:var ret=getPromise(resultVal);_emscripten_promise_destroy(resultVal);return ret;case 3:throw resultVal}};function _emscripten_promise_then(id,onFulfilled,onRejected,userData){id>>>=0;onFulfilled>>>=0;onRejected>>>=0;userData>>>=0;runtimeKeepalivePush();var promise=getPromise(id);var newId=promiseMap.allocate({promise:promise.then(makePromiseCallback(onFulfilled,userData),makePromiseCallback(onRejected,userData))});return newId}_emscripten_promise_then.sig="ppppp";var _emscripten_promise_all=function(idBuf,resultBuf,size){idBuf>>>=0;resultBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.all(promises).then(results=>{if(resultBuf){for(var i=0;i>>2>>>0]=result}}return resultBuf})});return id};_emscripten_promise_all.sig="pppp";var setPromiseResult=(ptr,fulfill,value)=>{var result=fulfill?0:3;HEAP32[ptr>>>2>>>0]=result;HEAPU32[ptr+4>>>2>>>0]=value};var _emscripten_promise_all_settled=function(idBuf,resultBuf,size){idBuf>>>=0;resultBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.allSettled(promises).then(results=>{if(resultBuf){var offset=resultBuf;for(var i=0;i>>=0;errorBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.any(promises).catch(err=>{if(errorBuf){for(var i=0;i>>2>>>0]=err.errors[i]}}throw errorBuf})});return id};_emscripten_promise_any.sig="pppp";function _emscripten_promise_race(idBuf,size){idBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.race(promises)});return id}_emscripten_promise_race.sig="ppp";function _emscripten_promise_await(returnValuePtr,id){returnValuePtr>>>=0;id>>>=0;abort("emscripten_promise_await is only available with ASYNCIFY")}_emscripten_promise_await.sig="vpp";var getExceptionMessageCommon=ptr=>{var sp=stackSave();var type_addr_addr=stackAlloc(4);var message_addr_addr=stackAlloc(4);___get_exception_message(ptr,type_addr_addr,message_addr_addr);var type_addr=HEAPU32[type_addr_addr>>>2>>>0];var message_addr=HEAPU32[message_addr_addr>>>2>>>0];var type=UTF8ToString(type_addr);_free(type_addr);var message;if(message_addr){message=UTF8ToString(message_addr);_free(message_addr)}stackRestore(sp);return[type,message]};var getCppExceptionTag=()=>___cpp_exception;var getCppExceptionThrownObjectFromWebAssemblyException=ex=>{var unwind_header=ex.getArg(getCppExceptionTag(),0);return ___thrown_object_from_unwind_exception(unwind_header)};var incrementExceptionRefcount=ex=>{var ptr=getCppExceptionThrownObjectFromWebAssemblyException(ex);___cxa_increment_exception_refcount(ptr)};var decrementExceptionRefcount=ex=>{var ptr=getCppExceptionThrownObjectFromWebAssemblyException(ex);___cxa_decrement_exception_refcount(ptr)};var getExceptionMessage=ex=>{var ptr=getCppExceptionThrownObjectFromWebAssemblyException(ex);return getExceptionMessageCommon(ptr)};var Browser={useWebGL:false,isFullscreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],preloadedImages:{},preloadedAudios:{},getCanvas:()=>Module["canvas"],init(){if(Browser.initted)return;Browser.initted=true;var imagePlugin={};imagePlugin["canHandle"]=function imagePlugin_canHandle(name){return!Module["noImageDecoding"]&&/\.(jpg|jpeg|png|bmp|webp)$/i.test(name)};imagePlugin["handle"]=function imagePlugin_handle(byteArray,name,onload,onerror){var b=new Blob([byteArray],{type:Browser.getMimetype(name)});if(b.size!==byteArray.length){b=new Blob([new Uint8Array(byteArray).buffer],{type:Browser.getMimetype(name)})}var url=URL.createObjectURL(b);var img=new Image;img.onload=()=>{var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);Browser.preloadedImages[name]=canvas;URL.revokeObjectURL(url);onload?.(byteArray)};img.onerror=event=>{err(`Image ${url} could not be decoded`);onerror?.()};img.src=url};preloadPlugins.push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module["noAudioDecoding"]&&name.slice(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;Browser.preloadedAudios[name]=audio;onload?.(byteArray)}function fail(){if(done)return;done=true;Browser.preloadedAudios[name]=new Audio;onerror?.()}var b=new Blob([byteArray],{type:Browser.getMimetype(name)});var url=URL.createObjectURL(b);var audio=new Audio;audio.addEventListener("canplaythrough",()=>finish(audio),false);audio.onerror=function audio_onerror(event){if(done)return;err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`);function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.slice(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(()=>{finish(audio)},1e4)};preloadPlugins.push(audioPlugin);function pointerLockChange(){var canvas=Browser.getCanvas();Browser.pointerLock=document["pointerLockElement"]===canvas||document["mozPointerLockElement"]===canvas||document["webkitPointerLockElement"]===canvas||document["msPointerLockElement"]===canvas}var canvas=Browser.getCanvas();if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||(()=>{});canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||(()=>{});canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",ev=>{if(!Browser.pointerLock&&Browser.getCanvas().requestPointerLock){Browser.getCanvas().requestPointerLock();ev.preventDefault()}},false)}}},createContext(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module["ctx"]&&canvas==Browser.getCanvas())return Module["ctx"];var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:typeof WebGL2RenderingContext!="undefined"?2:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){Module["ctx"]=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Browser.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(callback=>callback());Browser.init()}return ctx},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Browser.getCanvas();function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}Module["onFullScreen"]?.(Browser.isFullscreen);Module["onFullscreen"]?.(Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?()=>canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]):null)||(canvasContainer["webkitRequestFullScreen"]?()=>canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]):null);canvasContainer.requestFullscreen()},exitFullscreen(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||(()=>{});CFS.apply(document,[]);return true},safeSetTimeout(func,timeout){return safeSetTimeout(func,timeout)},getMimetype(name){return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",bmp:"image/bmp",ogg:"audio/ogg",wav:"audio/wav",mp3:"audio/mpeg"}[name.slice(name.lastIndexOf(".")+1)]},getUserMedia(func){window.getUserMedia||=navigator["getUserMedia"]||navigator["mozGetUserMedia"];window.getUserMedia(func)},getMovementX(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseCoords(pageX,pageY){var canvas=Browser.getCanvas();var rect=canvas.getBoundingClientRect();var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;var adjustedX=pageX-(scrollX+rect.left);var adjustedY=pageY-(scrollY+rect.top);adjustedX=adjustedX*(canvas.width/rect.width);adjustedY=adjustedY*(canvas.height/rect.height);return{x:adjustedX,y:adjustedY}},setMouseCoords(pageX,pageY){const{x,y}=Browser.calculateMouseCoords(pageX,pageY);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y},calculateMouseEvent(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}else{if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var coords=Browser.calculateMouseCoords(touch.pageX,touch.pageY);if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];last||=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}Browser.setMouseCoords(event.pageX,event.pageY)}},resizeListeners:[],updateResizeListeners(){var canvas=Browser.getCanvas();Browser.resizeListeners.forEach(listener=>listener(canvas.width,canvas.height))},setCanvasSize(width,height,noUpdates){var canvas=Browser.getCanvas();Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags|8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Browser.getCanvas());Browser.updateResizeListeners()},setWindowedCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags&~8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Browser.getCanvas());Browser.updateResizeListeners()},updateCanvasDimensions(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]>0){if(w/h>>=0;onload>>>=0;onerror>>>=0;runtimeKeepalivePush();var _file=UTF8ToString(file);var data=FS.analyzePath(_file);if(!data.exists)return-1;FS.createPreloadedFile(PATH.dirname(_file),PATH.basename(_file),new Uint8Array(data.object.contents),true,true,()=>{runtimeKeepalivePop();if(onload)getWasmTableEntry(onload)(file)},()=>{runtimeKeepalivePop();if(onerror)getWasmTableEntry(onerror)(file)},true);return 0};_emscripten_run_preload_plugins.sig="ippp";var Browser_asyncPrepareDataCounter=0;var _emscripten_run_preload_plugins_data=function(data,size,suffix,arg,onload,onerror){data>>>=0;suffix>>>=0;arg>>>=0;onload>>>=0;onerror>>>=0;runtimeKeepalivePush();var _suffix=UTF8ToString(suffix);var name="prepare_data_"+Browser_asyncPrepareDataCounter+++"."+_suffix;var cname=stringToNewUTF8(name);FS.createPreloadedFile("/",name,HEAPU8.subarray(data>>>0,data+size>>>0),true,true,()=>{runtimeKeepalivePop();if(onload)getWasmTableEntry(onload)(arg,cname)},()=>{runtimeKeepalivePop();if(onerror)getWasmTableEntry(onerror)(arg)},true)};_emscripten_run_preload_plugins_data.sig="vpipppp";var _emscripten_async_run_script=function(script,millis){script>>>=0;safeSetTimeout(()=>_emscripten_run_script(script),millis)};_emscripten_async_run_script.sig="vpi";var _emscripten_async_load_script=async function(url,onload,onerror){url>>>=0;onload>>>=0;onerror>>>=0;url=UTF8ToString(url);runtimeKeepalivePush();var loadDone=()=>{runtimeKeepalivePop();if(onload){var onloadCallback=()=>callUserCallback(getWasmTableEntry(onload));if(runDependencies>0){dependenciesFulfilled=onloadCallback}else{onloadCallback()}}};var loadError=()=>{runtimeKeepalivePop();if(onerror){callUserCallback(getWasmTableEntry(onerror))}};if(ENVIRONMENT_IS_NODE){try{var data=await readAsync(url,false);eval(data);loadDone()}catch(e){err(e);loadError()}return}var script=document.createElement("script");script.onload=loadDone;script.onerror=loadError;script.src=url;document.body.appendChild(script)};_emscripten_async_load_script.sig="vppp";function _emscripten_get_window_title(){var buflen=256;if(!_emscripten_get_window_title.buffer){_emscripten_get_window_title.buffer=_malloc(buflen)}stringToUTF8(document.title,_emscripten_get_window_title.buffer,buflen);return _emscripten_get_window_title.buffer}_emscripten_get_window_title.sig="p";function _emscripten_set_window_title(title){title>>>=0;return document.title=UTF8ToString(title)}_emscripten_set_window_title.sig="vp";function _emscripten_get_screen_size(width,height){width>>>=0;height>>>=0;HEAP32[width>>>2>>>0]=screen.width;HEAP32[height>>>2>>>0]=screen.height}_emscripten_get_screen_size.sig="vpp";var _emscripten_hide_mouse=()=>{var styleSheet=document.styleSheets[0];var rules=styleSheet.cssRules;for(var i=0;iBrowser.setCanvasSize(width,height);_emscripten_set_canvas_size.sig="vii";function _emscripten_get_canvas_size(width,height,isFullscreen){width>>>=0;height>>>=0;isFullscreen>>>=0;var canvas=Browser.getCanvas();HEAP32[width>>>2>>>0]=canvas.width;HEAP32[height>>>2>>>0]=canvas.height;HEAP32[isFullscreen>>>2>>>0]=Browser.isFullscreen?1:0}_emscripten_get_canvas_size.sig="vppp";function _emscripten_create_worker(url){url>>>=0;url=UTF8ToString(url);var id=Browser.workers.length;var info={worker:new Worker(url),callbacks:[],awaited:0,buffer:0,bufferSize:0};info.worker.onmessage=function info_worker_onmessage(msg){if(ABORT)return;var info=Browser.workers[id];if(!info)return;var callbackId=msg.data["callbackId"];var callbackInfo=info.callbacks[callbackId];if(!callbackInfo)return;if(msg.data["finalResponse"]){info.awaited--;info.callbacks[callbackId]=null;runtimeKeepalivePop()}var data=msg.data["data"];if(data){if(!data.byteLength)data=new Uint8Array(data);if(!info.buffer||info.bufferSize>>0);callbackInfo.func(info.buffer,data.length,callbackInfo.arg)}else{callbackInfo.func(0,0,callbackInfo.arg)}};Browser.workers.push(info);return id}_emscripten_create_worker.sig="ip";var _emscripten_destroy_worker=id=>{var info=Browser.workers[id];info.worker.terminate();if(info.buffer)_free(info.buffer);Browser.workers[id]=null};_emscripten_destroy_worker.sig="vi";function _emscripten_call_worker(id,funcName,data,size,callback,arg){funcName>>>=0;data>>>=0;callback>>>=0;arg>>>=0;funcName=UTF8ToString(funcName);var info=Browser.workers[id];var callbackId=-1;if(callback){runtimeKeepalivePush();callbackId=info.callbacks.length;info.callbacks.push({func:getWasmTableEntry(callback),arg});info.awaited++}var transferObject={funcName,callbackId,data:data?new Uint8Array(HEAPU8.subarray(data>>>0,data+size>>>0)):0};if(data){info.worker.postMessage(transferObject,[transferObject.data.buffer])}else{info.worker.postMessage(transferObject)}}_emscripten_call_worker.sig="vippipp";var _emscripten_get_worker_queue_size=id=>{var info=Browser.workers[id];if(!info)return-1;return info.awaited};_emscripten_get_worker_queue_size.sig="ii";var getPreloadedImageData=(path,w,h)=>{path=PATH_FS.resolve(path);var canvas=Browser.preloadedImages[path];if(!canvas)return 0;var ctx=canvas.getContext("2d");var image=ctx.getImageData(0,0,canvas.width,canvas.height);var buf=_malloc(canvas.width*canvas.height*4);HEAPU8.set(image.data,buf>>>0);HEAP32[w>>>2>>>0]=canvas.width;HEAP32[h>>>2>>>0]=canvas.height;return buf};function _emscripten_get_preloaded_image_data(path,w,h){path>>>=0;w>>>=0;h>>>=0;return getPreloadedImageData(UTF8ToString(path),w,h)}_emscripten_get_preloaded_image_data.sig="pppp";var getPreloadedImageData__data=["$PATH_FS","malloc"];function _emscripten_get_preloaded_image_data_from_FILE(file,w,h){file>>>=0;w>>>=0;h>>>=0;var fd=_fileno(file);var stream=FS.getStream(fd);if(stream){return getPreloadedImageData(stream.path,w,h)}return 0}_emscripten_get_preloaded_image_data_from_FILE.sig="pppp";var wget={wgetRequests:{},nextWgetRequestHandle:0,getNextWgetRequestHandle(){var handle=wget.nextWgetRequestHandle;wget.nextWgetRequestHandle++;return handle}};var FS_mkdirTree=(path,mode)=>FS.mkdirTree(path,mode);var _emscripten_async_wget=function(url,file,onload,onerror){url>>>=0;file>>>=0;onload>>>=0;onerror>>>=0;runtimeKeepalivePush();var _url=UTF8ToString(url);var _file=UTF8ToString(file);_file=PATH_FS.resolve(_file);function doCallback(callback){if(callback){runtimeKeepalivePop();callUserCallback(()=>{var sp=stackSave();getWasmTableEntry(callback)(stringToUTF8OnStack(_file));stackRestore(sp)})}}var destinationDirectory=PATH.dirname(_file);FS_createPreloadedFile(destinationDirectory,PATH.basename(_file),_url,true,true,()=>doCallback(onload),()=>doCallback(onerror),false,false,()=>{try{FS_unlink(_file)}catch(e){}FS_mkdirTree(destinationDirectory)})};_emscripten_async_wget.sig="vpppp";var _emscripten_async_wget_data=async function(url,userdata,onload,onerror){url>>>=0;userdata>>>=0;onload>>>=0;onerror>>>=0;runtimeKeepalivePush();try{var byteArray=await asyncLoad(UTF8ToString(url));runtimeKeepalivePop();callUserCallback(()=>{var buffer=_malloc(byteArray.length);HEAPU8.set(byteArray,buffer>>>0);getWasmTableEntry(onload)(userdata,buffer,byteArray.length);_free(buffer)})}catch(e){if(onerror){runtimeKeepalivePop();callUserCallback(()=>{getWasmTableEntry(onerror)(userdata)})}}};_emscripten_async_wget_data.sig="vpppp";var _emscripten_async_wget2=function(url,file,request,param,userdata,onload,onerror,onprogress){url>>>=0;file>>>=0;request>>>=0;param>>>=0;userdata>>>=0;onload>>>=0;onerror>>>=0;onprogress>>>=0;runtimeKeepalivePush();var _url=UTF8ToString(url);var _file=UTF8ToString(file);_file=PATH_FS.resolve(_file);var _request=UTF8ToString(request);var _param=UTF8ToString(param);var index=_file.lastIndexOf("/");var http=new XMLHttpRequest;http.open(_request,_url,true);http.responseType="arraybuffer";var handle=wget.getNextWgetRequestHandle();var destinationDirectory=PATH.dirname(_file);http.onload=e=>{runtimeKeepalivePop();if(http.status>=200&&http.status<300){try{FS.unlink(_file)}catch(e){}FS.mkdirTree(destinationDirectory);FS.createDataFile(_file.slice(0,index),_file.slice(index+1),new Uint8Array(http.response),true,true,false);if(onload){var sp=stackSave();getWasmTableEntry(onload)(handle,userdata,stringToUTF8OnStack(_file));stackRestore(sp)}}else{if(onerror)getWasmTableEntry(onerror)(handle,userdata,http.status)}delete wget.wgetRequests[handle]};http.onerror=e=>{runtimeKeepalivePop();if(onerror)getWasmTableEntry(onerror)(handle,userdata,http.status);delete wget.wgetRequests[handle]};http.onprogress=e=>{if(e.lengthComputable||e.lengthComputable===undefined&&e.total!=0){var percentComplete=e.loaded/e.total*100;if(onprogress)getWasmTableEntry(onprogress)(handle,userdata,percentComplete)}};http.onabort=e=>{runtimeKeepalivePop();delete wget.wgetRequests[handle]};if(_request=="POST"){http.setRequestHeader("Content-type","application/x-www-form-urlencoded");http.send(_param)}else{http.send(null)}wget.wgetRequests[handle]=http;return handle};_emscripten_async_wget2.sig="ipppppppp";function _emscripten_async_wget2_data(url,request,param,userdata,free,onload,onerror,onprogress){url>>>=0;request>>>=0;param>>>=0;userdata>>>=0;onload>>>=0;onerror>>>=0;onprogress>>>=0;var _url=UTF8ToString(url);var _request=UTF8ToString(request);var _param=UTF8ToString(param);var http=new XMLHttpRequest;http.open(_request,_url,true);http.responseType="arraybuffer";var handle=wget.getNextWgetRequestHandle();function onerrorjs(){if(onerror){var sp=stackSave();var statusText=0;if(http.statusText){statusText=stringToUTF8OnStack(http.statusText)}getWasmTableEntry(onerror)(handle,userdata,http.status,statusText);stackRestore(sp)}}http.onload=e=>{if(http.status>=200&&http.status<300||http.status===0&&_url.slice(0,4).toLowerCase()!="http"){var byteArray=new Uint8Array(http.response);var buffer=_malloc(byteArray.length);HEAPU8.set(byteArray,buffer>>>0);if(onload)getWasmTableEntry(onload)(handle,userdata,buffer,byteArray.length);if(free)_free(buffer)}else{onerrorjs()}delete wget.wgetRequests[handle]};http.onerror=e=>{onerrorjs();delete wget.wgetRequests[handle]};http.onprogress=e=>{if(onprogress)getWasmTableEntry(onprogress)(handle,userdata,e.loaded,e.lengthComputable||e.lengthComputable===undefined?e.total:0)};http.onabort=e=>{delete wget.wgetRequests[handle]};if(_request=="POST"){http.setRequestHeader("Content-type","application/x-www-form-urlencoded");http.send(_param)}else{http.send(null)}wget.wgetRequests[handle]=http;return handle}_emscripten_async_wget2_data.sig="ippppippp";var _emscripten_async_wget2_abort=handle=>{var http=wget.wgetRequests[handle];http?.abort()};_emscripten_async_wget2_abort.sig="vi";function ___asctime_r(tmPtr,buf){tmPtr>>>=0;buf>>>=0;var date={tm_sec:HEAP32[tmPtr>>>2>>>0],tm_min:HEAP32[tmPtr+4>>>2>>>0],tm_hour:HEAP32[tmPtr+8>>>2>>>0],tm_mday:HEAP32[tmPtr+12>>>2>>>0],tm_mon:HEAP32[tmPtr+16>>>2>>>0],tm_year:HEAP32[tmPtr+20>>>2>>>0],tm_wday:HEAP32[tmPtr+24>>>2>>>0]};var days=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];var months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];var s=days[date.tm_wday]+" "+months[date.tm_mon]+(date.tm_mday<10?" ":" ")+date.tm_mday+(date.tm_hour<10?" 0":" ")+date.tm_hour+(date.tm_min<10?":0":":")+date.tm_min+(date.tm_sec<10?":0":":")+date.tm_sec+" "+(1900+date.tm_year)+"\n";stringToUTF8(s,buf,26);return buf}___asctime_r.sig="ppp";var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var arraySum=(array,index)=>{var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum};var addDays=(date,days)=>{var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate};function _strptime(buf,format,tm){buf>>>=0;format>>>=0;tm>>>=0;var pattern=UTF8ToString(format);var SPECIAL_CHARS="\\!@#$^&*()+=-[]/{}|:<>?,.";for(var i=0,ii=SPECIAL_CHARS.length;iEQUIVALENT_MATCHERS[c]||m).replace(/%(.)/g,(_,c)=>{let pat=DATE_PATTERNS[c];if(pat){capture.push(c);return`(${pat})`}else{return c}}).replace(/\s+/g,"\\s*");var matches=new RegExp("^"+pattern_out,"i").exec(UTF8ToString(buf));function initDate(){function fixup(value,min,max){return typeof value!="number"||isNaN(value)?min:value>=min?value<=max?value:max:min}return{year:fixup(HEAP32[tm+20>>>2>>>0]+1900,1970,9999),month:fixup(HEAP32[tm+16>>>2>>>0],0,11),day:fixup(HEAP32[tm+12>>>2>>>0],1,31),hour:fixup(HEAP32[tm+8>>>2>>>0],0,23),min:fixup(HEAP32[tm+4>>>2>>>0],0,59),sec:fixup(HEAP32[tm>>>2>>>0],0,59),gmtoff:0}}if(matches){var date=initDate();var value;var getMatch=symbol=>{var pos=capture.indexOf(symbol);if(pos>=0){return matches[pos+1]}return};if(value=getMatch("S")){date.sec=Number(value)}if(value=getMatch("M")){date.min=Number(value)}if(value=getMatch("H")){date.hour=Number(value)}else if(value=getMatch("I")){var hour=Number(value);if(value=getMatch("p")){hour+=value.toUpperCase()[0]==="P"?12:0}date.hour=hour}if(value=getMatch("Y")){date.year=Number(value)}else if(value=getMatch("y")){var year=Number(value);if(value=getMatch("C")){year+=Number(value)*100}else{year+=year<69?2e3:1900}date.year=year}if(value=getMatch("m")){date.month=Number(value)-1}else if(value=getMatch("b")){date.month=MONTH_NUMBERS[value.substring(0,3).toUpperCase()]||0}if(value=getMatch("d")){date.day=Number(value)}else if(value=getMatch("j")){var day=Number(value);var leapYear=isLeapYear(date.year);for(var month=0;month<12;++month){var daysUntilMonth=arraySum(leapYear?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,month-1);if(day<=daysUntilMonth+(leapYear?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[month]){date.day=day-daysUntilMonth}}}else if(value=getMatch("a")){var weekDay=value.substring(0,3).toUpperCase();if(value=getMatch("U")){var weekDayNumber=DAY_NUMBERS_SUN_FIRST[weekDay];var weekNumber=Number(value);var janFirst=new Date(date.year,0,1);var endDate;if(janFirst.getDay()===0){endDate=addDays(janFirst,weekDayNumber+7*(weekNumber-1))}else{endDate=addDays(janFirst,7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1))}date.day=endDate.getDate();date.month=endDate.getMonth()}else if(value=getMatch("W")){var weekDayNumber=DAY_NUMBERS_MON_FIRST[weekDay];var weekNumber=Number(value);var janFirst=new Date(date.year,0,1);var endDate;if(janFirst.getDay()===1){endDate=addDays(janFirst,weekDayNumber+7*(weekNumber-1))}else{endDate=addDays(janFirst,7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1))}date.day=endDate.getDate();date.month=endDate.getMonth()}}if(value=getMatch("z")){if(value.toLowerCase()==="z"){date.gmtoff=0}else{var match=value.match(/^((?:\-|\+)\d\d):?(\d\d)?/);date.gmtoff=match[1]*3600;if(match[2]){date.gmtoff+=date.gmtoff>0?match[2]*60:-match[2]*60}}}var fullDate=new Date(date.year,date.month,date.day,date.hour,date.min,date.sec,0);HEAP32[tm>>>2>>>0]=fullDate.getSeconds();HEAP32[tm+4>>>2>>>0]=fullDate.getMinutes();HEAP32[tm+8>>>2>>>0]=fullDate.getHours();HEAP32[tm+12>>>2>>>0]=fullDate.getDate();HEAP32[tm+16>>>2>>>0]=fullDate.getMonth();HEAP32[tm+20>>>2>>>0]=fullDate.getFullYear()-1900;HEAP32[tm+24>>>2>>>0]=fullDate.getDay();HEAP32[tm+28>>>2>>>0]=arraySum(isLeapYear(fullDate.getFullYear())?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,fullDate.getMonth()-1)+fullDate.getDate()-1;HEAP32[tm+32>>>2>>>0]=0;HEAP32[tm+36>>>2>>>0]=date.gmtoff;return buf+intArrayFromString(matches[0]).length-1}return 0}_strptime.sig="pppp";function _strptime_l(buf,format,tm,locale){buf>>>=0;format>>>=0;tm>>>=0;locale>>>=0;return _strptime(buf,format,tm)}_strptime_l.sig="ppppp";function __dlsym_catchup_js(handle,symbolIndex){handle>>>=0;var lib=LDSO.loadedLibsByHandle[handle];var symDict=lib.exports;var symName=Object.keys(symDict)[symbolIndex];var sym=symDict[symName];var result=addFunction(sym,sym.sig);return result}__dlsym_catchup_js.sig="ppi";var FS_readFile=(...args)=>FS.readFile(...args);var FS_root=(...args)=>FS.root(...args);var FS_mounts=(...args)=>FS.mounts(...args);var FS_devices=(...args)=>FS.devices(...args);var FS_streams=(...args)=>FS.streams(...args);var FS_nextInode=(...args)=>FS.nextInode(...args);var FS_nameTable=(...args)=>FS.nameTable(...args);var FS_currentPath=(...args)=>FS.currentPath(...args);var FS_initialized=(...args)=>FS.initialized(...args);var FS_ignorePermissions=(...args)=>FS.ignorePermissions(...args);var FS_trackingDelegate=(...args)=>FS.trackingDelegate(...args);var FS_filesystems=(...args)=>FS.filesystems(...args);var FS_syncFSRequests=(...args)=>FS.syncFSRequests(...args);var FS_readFiles=(...args)=>FS.readFiles(...args);var FS_lookupPath=(...args)=>FS.lookupPath(...args);var FS_getPath=(...args)=>FS.getPath(...args);var FS_hashName=(...args)=>FS.hashName(...args);var FS_hashAddNode=(...args)=>FS.hashAddNode(...args);var FS_hashRemoveNode=(...args)=>FS.hashRemoveNode(...args);var FS_lookupNode=(...args)=>FS.lookupNode(...args);var FS_createNode=(...args)=>FS.createNode(...args);var FS_destroyNode=(...args)=>FS.destroyNode(...args);var FS_isRoot=(...args)=>FS.isRoot(...args);var FS_isMountpoint=(...args)=>FS.isMountpoint(...args);var FS_isFile=(...args)=>FS.isFile(...args);var FS_isDir=(...args)=>FS.isDir(...args);var FS_isLink=(...args)=>FS.isLink(...args);var FS_isChrdev=(...args)=>FS.isChrdev(...args);var FS_isBlkdev=(...args)=>FS.isBlkdev(...args);var FS_isFIFO=(...args)=>FS.isFIFO(...args);var FS_isSocket=(...args)=>FS.isSocket(...args);var FS_flagsToPermissionString=(...args)=>FS.flagsToPermissionString(...args);var FS_nodePermissions=(...args)=>FS.nodePermissions(...args);var FS_mayLookup=(...args)=>FS.mayLookup(...args);var FS_mayCreate=(...args)=>FS.mayCreate(...args);var FS_mayDelete=(...args)=>FS.mayDelete(...args);var FS_mayOpen=(...args)=>FS.mayOpen(...args);var FS_checkOpExists=(...args)=>FS.checkOpExists(...args);var FS_nextfd=(...args)=>FS.nextfd(...args);var FS_getStreamChecked=(...args)=>FS.getStreamChecked(...args);var FS_getStream=(...args)=>FS.getStream(...args);var FS_createStream=(...args)=>FS.createStream(...args);var FS_closeStream=(...args)=>FS.closeStream(...args);var FS_dupStream=(...args)=>FS.dupStream(...args);var FS_doSetAttr=(...args)=>FS.doSetAttr(...args);var FS_chrdev_stream_ops=(...args)=>FS.chrdev_stream_ops(...args);var FS_major=(...args)=>FS.major(...args);var FS_minor=(...args)=>FS.minor(...args);var FS_makedev=(...args)=>FS.makedev(...args);var FS_registerDevice=(...args)=>FS.registerDevice(...args);var FS_getDevice=(...args)=>FS.getDevice(...args);var FS_getMounts=(...args)=>FS.getMounts(...args);var FS_syncfs=(...args)=>FS.syncfs(...args);var FS_mount=(...args)=>FS.mount(...args);var FS_unmount=(...args)=>FS.unmount(...args);var FS_lookup=(...args)=>FS.lookup(...args);var FS_mknod=(...args)=>FS.mknod(...args);var FS_statfs=(...args)=>FS.statfs(...args);var FS_statfsStream=(...args)=>FS.statfsStream(...args);var FS_statfsNode=(...args)=>FS.statfsNode(...args);var FS_create=(...args)=>FS.create(...args);var FS_mkdir=(...args)=>FS.mkdir(...args);var FS_mkdev=(...args)=>FS.mkdev(...args);var FS_symlink=(...args)=>FS.symlink(...args);var FS_rename=(...args)=>FS.rename(...args);var FS_rmdir=(...args)=>FS.rmdir(...args);var FS_readdir=(...args)=>FS.readdir(...args);var FS_readlink=(...args)=>FS.readlink(...args);var FS_stat=(...args)=>FS.stat(...args);var FS_fstat=(...args)=>FS.fstat(...args);var FS_lstat=(...args)=>FS.lstat(...args);var FS_doChmod=(...args)=>FS.doChmod(...args);var FS_chmod=(...args)=>FS.chmod(...args);var FS_lchmod=(...args)=>FS.lchmod(...args);var FS_fchmod=(...args)=>FS.fchmod(...args);var FS_doChown=(...args)=>FS.doChown(...args);var FS_chown=(...args)=>FS.chown(...args);var FS_lchown=(...args)=>FS.lchown(...args);var FS_fchown=(...args)=>FS.fchown(...args);var FS_doTruncate=(...args)=>FS.doTruncate(...args);var FS_truncate=(...args)=>FS.truncate(...args);var FS_ftruncate=(...args)=>FS.ftruncate(...args);var FS_utime=(...args)=>FS.utime(...args);var FS_open=(...args)=>FS.open(...args);var FS_close=(...args)=>FS.close(...args);var FS_isClosed=(...args)=>FS.isClosed(...args);var FS_llseek=(...args)=>FS.llseek(...args);var FS_read=(...args)=>FS.read(...args);var FS_write=(...args)=>FS.write(...args);var FS_mmap=(...args)=>FS.mmap(...args);var FS_msync=(...args)=>FS.msync(...args);var FS_ioctl=(...args)=>FS.ioctl(...args);var FS_writeFile=(...args)=>FS.writeFile(...args);var FS_cwd=(...args)=>FS.cwd(...args);var FS_chdir=(...args)=>FS.chdir(...args);var FS_createDefaultDirectories=(...args)=>FS.createDefaultDirectories(...args);var FS_createDefaultDevices=(...args)=>FS.createDefaultDevices(...args);var FS_createSpecialDirectories=(...args)=>FS.createSpecialDirectories(...args);var FS_createStandardStreams=(...args)=>FS.createStandardStreams(...args);var FS_staticInit=(...args)=>FS.staticInit(...args);var FS_init=(...args)=>FS.init(...args);var FS_quit=(...args)=>FS.quit(...args);var FS_findObject=(...args)=>FS.findObject(...args);var FS_analyzePath=(...args)=>FS.analyzePath(...args);var FS_createFile=(...args)=>FS.createFile(...args);var FS_forceLoadFile=(...args)=>FS.forceLoadFile(...args);var _setNetworkCallback=(event,userData,callback)=>{function _callback(data){callUserCallback(()=>{if(event==="error"){withStackSave(()=>{var msg=stringToUTF8OnStack(data[2]);getWasmTableEntry(callback)(data[0],data[1],msg,userData)})}else{getWasmTableEntry(callback)(data,userData)}})}runtimeKeepalivePush();SOCKFS.on(event,callback?_callback:null)};function _emscripten_set_socket_error_callback(userData,callback){userData>>>=0;callback>>>=0;return _setNetworkCallback("error",userData,callback)}_emscripten_set_socket_error_callback.sig="vpp";function _emscripten_set_socket_open_callback(userData,callback){userData>>>=0;callback>>>=0;return _setNetworkCallback("open",userData,callback)}_emscripten_set_socket_open_callback.sig="vpp";function _emscripten_set_socket_listen_callback(userData,callback){userData>>>=0;callback>>>=0;return _setNetworkCallback("listen",userData,callback)}_emscripten_set_socket_listen_callback.sig="vpp";function _emscripten_set_socket_connection_callback(userData,callback){userData>>>=0;callback>>>=0;return _setNetworkCallback("connection",userData,callback)}_emscripten_set_socket_connection_callback.sig="vpp";function _emscripten_set_socket_message_callback(userData,callback){userData>>>=0;callback>>>=0;return _setNetworkCallback("message",userData,callback)}_emscripten_set_socket_message_callback.sig="vpp";function _emscripten_set_socket_close_callback(userData,callback){userData>>>=0;callback>>>=0;return _setNetworkCallback("close",userData,callback)}_emscripten_set_socket_close_callback.sig="vpp";function _emscripten_webgl_enable_ANGLE_instanced_arrays(ctx){ctx>>>=0;return webgl_enable_ANGLE_instanced_arrays(GL.contexts[ctx].GLctx)}_emscripten_webgl_enable_ANGLE_instanced_arrays.sig="ip";function _emscripten_webgl_enable_OES_vertex_array_object(ctx){ctx>>>=0;return webgl_enable_OES_vertex_array_object(GL.contexts[ctx].GLctx)}_emscripten_webgl_enable_OES_vertex_array_object.sig="ip";function _emscripten_webgl_enable_WEBGL_draw_buffers(ctx){ctx>>>=0;return webgl_enable_WEBGL_draw_buffers(GL.contexts[ctx].GLctx)}_emscripten_webgl_enable_WEBGL_draw_buffers.sig="ip";function _emscripten_webgl_enable_WEBGL_multi_draw(ctx){ctx>>>=0;return webgl_enable_WEBGL_multi_draw(GL.contexts[ctx].GLctx)}_emscripten_webgl_enable_WEBGL_multi_draw.sig="ip";function _emscripten_webgl_enable_EXT_polygon_offset_clamp(ctx){ctx>>>=0;return webgl_enable_EXT_polygon_offset_clamp(GL.contexts[ctx].GLctx)}_emscripten_webgl_enable_EXT_polygon_offset_clamp.sig="ip";function _emscripten_webgl_enable_EXT_clip_control(ctx){ctx>>>=0;return webgl_enable_EXT_clip_control(GL.contexts[ctx].GLctx)}_emscripten_webgl_enable_EXT_clip_control.sig="ip";function _emscripten_webgl_enable_WEBGL_polygon_mode(ctx){ctx>>>=0;return webgl_enable_WEBGL_polygon_mode(GL.contexts[ctx].GLctx)}_emscripten_webgl_enable_WEBGL_polygon_mode.sig="ip";function _glVertexPointer(size,type,stride,ptr){ptr>>>=0;throw"Legacy GL function (glVertexPointer) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."}_glVertexPointer.sig="viiip";var _glMatrixMode=()=>{throw"Legacy GL function (glMatrixMode) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."};_glMatrixMode.sig="vi";var _glBegin=()=>{throw"Legacy GL function (glBegin) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."};_glBegin.sig="vi";var _glLoadIdentity=()=>{throw"Legacy GL function (glLoadIdentity) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."};_glLoadIdentity.sig="v";function _glMultiDrawArraysWEBGL(mode,firsts,counts,drawcount){firsts>>>=0;counts>>>=0;GLctx.multiDrawWebgl["multiDrawArraysWEBGL"](mode,HEAP32,firsts>>>2,HEAP32,counts>>>2,drawcount)}_glMultiDrawArraysWEBGL.sig="vippi";var _glMultiDrawArrays=_glMultiDrawArraysWEBGL;_glMultiDrawArrays.sig="vippi";var _glMultiDrawArraysANGLE=_glMultiDrawArraysWEBGL;function _glMultiDrawArraysInstancedWEBGL(mode,firsts,counts,instanceCounts,drawcount){firsts>>>=0;counts>>>=0;instanceCounts>>>=0;GLctx.multiDrawWebgl["multiDrawArraysInstancedWEBGL"](mode,HEAP32,firsts>>>2,HEAP32,counts>>>2,HEAP32,instanceCounts>>>2,drawcount)}_glMultiDrawArraysInstancedWEBGL.sig="vipppi";var _glMultiDrawArraysInstancedANGLE=_glMultiDrawArraysInstancedWEBGL;function _glMultiDrawElementsWEBGL(mode,counts,type,offsets,drawcount){counts>>>=0;offsets>>>=0;GLctx.multiDrawWebgl["multiDrawElementsWEBGL"](mode,HEAP32,counts>>>2,type,HEAP32,offsets>>>2,drawcount)}_glMultiDrawElementsWEBGL.sig="vipipi";var _glMultiDrawElements=_glMultiDrawElementsWEBGL;_glMultiDrawElements.sig="vipipi";var _glMultiDrawElementsANGLE=_glMultiDrawElementsWEBGL;function _glMultiDrawElementsInstancedWEBGL(mode,counts,type,offsets,instanceCounts,drawcount){counts>>>=0;offsets>>>=0;instanceCounts>>>=0;GLctx.multiDrawWebgl["multiDrawElementsInstancedWEBGL"](mode,HEAP32,counts>>>2,type,HEAP32,offsets>>>2,HEAP32,instanceCounts>>>2,drawcount)}_glMultiDrawElementsInstancedWEBGL.sig="vipippi";var _glMultiDrawElementsInstancedANGLE=_glMultiDrawElementsInstancedWEBGL;var _glClearDepth=x0=>GLctx.clearDepth(x0);_glClearDepth.sig="vd";var _glDepthRange=(x0,x1)=>GLctx.depthRange(x0,x1);_glDepthRange.sig="vdd";var _emscripten_glVertexPointer=_glVertexPointer;_emscripten_glVertexPointer.sig="viiip";var _emscripten_glMatrixMode=_glMatrixMode;_emscripten_glMatrixMode.sig="vi";var _emscripten_glBegin=_glBegin;_emscripten_glBegin.sig="vi";var _emscripten_glLoadIdentity=_glLoadIdentity;_emscripten_glLoadIdentity.sig="v";var _emscripten_glMultiDrawArrays=_glMultiDrawArrays;_emscripten_glMultiDrawArrays.sig="vippi";var _emscripten_glMultiDrawArraysANGLE=_glMultiDrawArraysANGLE;var _emscripten_glMultiDrawArraysWEBGL=_glMultiDrawArraysWEBGL;var _emscripten_glMultiDrawArraysInstancedANGLE=_glMultiDrawArraysInstancedANGLE;var _emscripten_glMultiDrawArraysInstancedWEBGL=_glMultiDrawArraysInstancedWEBGL;var _emscripten_glMultiDrawElements=_glMultiDrawElements;_emscripten_glMultiDrawElements.sig="vipipi";var _emscripten_glMultiDrawElementsANGLE=_glMultiDrawElementsANGLE;var _emscripten_glMultiDrawElementsWEBGL=_glMultiDrawElementsWEBGL;var _emscripten_glMultiDrawElementsInstancedANGLE=_glMultiDrawElementsInstancedANGLE;var _emscripten_glMultiDrawElementsInstancedWEBGL=_glMultiDrawElementsInstancedWEBGL;var _emscripten_glClearDepth=_glClearDepth;_emscripten_glClearDepth.sig="vd";var _emscripten_glDepthRange=_glDepthRange;_emscripten_glDepthRange.sig="vdd";function _glGetBufferSubData(target,offset,size,data){offset>>>=0;size>>>=0;data>>>=0;if(!data){GL.recordError(1281);return}size&&GLctx.getBufferSubData(target,offset,HEAPU8.subarray(data>>>0,data+size>>>0))}_glGetBufferSubData.sig="vippp";var _glDrawArraysInstancedBaseInstanceWEBGL=(mode,first,count,instanceCount,baseInstance)=>{GLctx.dibvbi["drawArraysInstancedBaseInstanceWEBGL"](mode,first,count,instanceCount,baseInstance)};_glDrawArraysInstancedBaseInstanceWEBGL.sig="viiiii";var _glDrawArraysInstancedBaseInstance=_glDrawArraysInstancedBaseInstanceWEBGL;_glDrawArraysInstancedBaseInstance.sig="viiiii";var _glDrawArraysInstancedBaseInstanceANGLE=_glDrawArraysInstancedBaseInstanceWEBGL;var _glDrawElementsInstancedBaseVertexBaseInstanceWEBGL=(mode,count,type,offset,instanceCount,baseVertex,baseinstance)=>{GLctx.dibvbi["drawElementsInstancedBaseVertexBaseInstanceWEBGL"](mode,count,type,offset,instanceCount,baseVertex,baseinstance)};_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL.sig="viiiiiii";var _glDrawElementsInstancedBaseVertexBaseInstanceANGLE=_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL;function _emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(ctx){ctx>>>=0;return webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx)}_emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance.sig="ip";var _glMultiDrawArraysInstancedBaseInstanceWEBGL=(mode,firsts,counts,instanceCounts,baseInstances,drawCount)=>{GLctx.mdibvbi["multiDrawArraysInstancedBaseInstanceWEBGL"](mode,HEAP32,firsts>>>2,HEAP32,counts>>>2,HEAP32,instanceCounts>>>2,HEAPU32,baseInstances>>>2,drawCount)};_glMultiDrawArraysInstancedBaseInstanceWEBGL.sig="viiiiii";var _glMultiDrawArraysInstancedBaseInstanceANGLE=_glMultiDrawArraysInstancedBaseInstanceWEBGL;var _glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL=(mode,counts,type,offsets,instanceCounts,baseVertices,baseInstances,drawCount)=>{GLctx.mdibvbi["multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL"](mode,HEAP32,counts>>>2,type,HEAP32,offsets>>>2,HEAP32,instanceCounts>>>2,HEAP32,baseVertices>>>2,HEAPU32,baseInstances>>>2,drawCount)};_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL.sig="viiiiiiii";var _glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE=_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL;function _emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(ctx){ctx>>>=0;return webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx)}_emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance.sig="ip";var _emscripten_glGetBufferSubData=_glGetBufferSubData;_emscripten_glGetBufferSubData.sig="vippp";var _emscripten_glDrawArraysInstancedBaseInstanceWEBGL=_glDrawArraysInstancedBaseInstanceWEBGL;var _emscripten_glDrawArraysInstancedBaseInstance=_glDrawArraysInstancedBaseInstance;_emscripten_glDrawArraysInstancedBaseInstance.sig="viiiii";var _emscripten_glDrawArraysInstancedBaseInstanceANGLE=_glDrawArraysInstancedBaseInstanceANGLE;var _emscripten_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL=_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL;var _emscripten_glDrawElementsInstancedBaseVertexBaseInstanceANGLE=_glDrawElementsInstancedBaseVertexBaseInstanceANGLE;var _emscripten_glMultiDrawArraysInstancedBaseInstanceWEBGL=_glMultiDrawArraysInstancedBaseInstanceWEBGL;var _emscripten_glMultiDrawArraysInstancedBaseInstanceANGLE=_glMultiDrawArraysInstancedBaseInstanceANGLE;var _emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL=_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL;var _emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE=_glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE;var ALLOC_NORMAL=0;var ALLOC_STACK=1;var allocate=(slab,allocator)=>{var ret;if(allocator==ALLOC_STACK){ret=stackAlloc(slab.length)}else{ret=_malloc(slab.length)}if(!slab.subarray&&!slab.slice){slab=new Uint8Array(slab)}HEAPU8.set(slab,ret>>>0);return ret};var writeStringToMemory=(string,buffer,dontAddNull)=>{warnOnce("writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!");var lastChar,end;if(dontAddNull){end=buffer+lengthBytesUTF8(string);lastChar=HEAP8[end>>>0]}stringToUTF8(string,buffer,Infinity);if(dontAddNull)HEAP8[end>>>0]=lastChar};var writeAsciiToMemory=(str,buffer,dontAddNull)=>{for(var i=0;i>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>>0]=0};var allocateUTF8=stringToNewUTF8;var allocateUTF8OnStack=stringToUTF8OnStack;var demangle=func=>{demangle.recursionGuard=(demangle.recursionGuard|0)+1;if(demangle.recursionGuard>1)return func;return withStackSave(()=>{try{var s=func;if(s.startsWith("__Z"))s=s.slice(1);var buf=stringToUTF8OnStack(s);var status=stackAlloc(4);var ret=___cxa_demangle(buf,0,0,status);if(HEAP32[status>>>2>>>0]===0&&ret){return UTF8ToString(ret)}}catch(e){}finally{_free(ret);if(demangle.recursionGuard<2)--demangle.recursionGuard}return func})};var stackTrace=()=>{var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return js};var print=out;var printErr=err;var jstoi_s=Number;var _emscripten_is_main_browser_thread=()=>!ENVIRONMENT_IS_WORKER;var webSockets=new HandleAllocator;var WS={socketEvent:null,getSocket(socketId){if(!webSockets.has(socketId)){return 0}return webSockets.get(socketId)},getSocketEvent(socketId){this.socketEvent||=_malloc(520);HEAPU32[this.socketEvent>>>2>>>0]=socketId;return this.socketEvent}};function _emscripten_websocket_get_ready_state(socketId,readyState){readyState>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}HEAP16[readyState>>>1>>>0]=socket.readyState;return 0}_emscripten_websocket_get_ready_state.sig="iip";function _emscripten_websocket_get_buffered_amount(socketId,bufferedAmount){bufferedAmount>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}HEAPU32[bufferedAmount>>>2>>>0]=socket.bufferedAmount;return 0}_emscripten_websocket_get_buffered_amount.sig="iip";function _emscripten_websocket_get_extensions(socketId,extensions,extensionsLength){extensions>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!extensions)return-5;stringToUTF8(socket.extensions,extensions,extensionsLength);return 0}_emscripten_websocket_get_extensions.sig="iipi";function _emscripten_websocket_get_extensions_length(socketId,extensionsLength){extensionsLength>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!extensionsLength)return-5;HEAP32[extensionsLength>>>2>>>0]=lengthBytesUTF8(socket.extensions)+1;return 0}_emscripten_websocket_get_extensions_length.sig="iip";function _emscripten_websocket_get_protocol(socketId,protocol,protocolLength){protocol>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!protocol)return-5;stringToUTF8(socket.protocol,protocol,protocolLength);return 0}_emscripten_websocket_get_protocol.sig="iipi";function _emscripten_websocket_get_protocol_length(socketId,protocolLength){protocolLength>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!protocolLength)return-5;HEAP32[protocolLength>>>2>>>0]=lengthBytesUTF8(socket.protocol)+1;return 0}_emscripten_websocket_get_protocol_length.sig="iip";function _emscripten_websocket_get_url(socketId,url,urlLength){url>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!url)return-5;stringToUTF8(socket.url,url,urlLength);return 0}_emscripten_websocket_get_url.sig="iipi";function _emscripten_websocket_get_url_length(socketId,urlLength){urlLength>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!urlLength)return-5;HEAP32[urlLength>>>2>>>0]=lengthBytesUTF8(socket.url)+1;return 0}_emscripten_websocket_get_url_length.sig="iip";function _emscripten_websocket_set_onopen_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onopen=function(e){var eventPtr=WS.getSocketEvent(socketId);getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}_emscripten_websocket_set_onopen_callback_on_thread.sig="iippp";function _emscripten_websocket_set_onerror_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onerror=function(e){var eventPtr=WS.getSocketEvent(socketId);getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}_emscripten_websocket_set_onerror_callback_on_thread.sig="iippp";function _emscripten_websocket_set_onclose_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onclose=function(e){var eventPtr=WS.getSocketEvent(socketId);HEAP8[eventPtr+4>>>0]=e.wasClean,HEAP16[eventPtr+6>>>1>>>0]=e.code,stringToUTF8(e.reason,eventPtr+8,512);getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}_emscripten_websocket_set_onclose_callback_on_thread.sig="iippp";function _emscripten_websocket_set_onmessage_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onmessage=function(e){var isText=typeof e.data=="string";if(isText){var buf=stringToNewUTF8(e.data);var len=lengthBytesUTF8(e.data)+1}else{var len=e.data.byteLength;var buf=_malloc(len);HEAP8.set(new Uint8Array(e.data),buf>>>0)}var eventPtr=WS.getSocketEvent(socketId);HEAPU32[eventPtr+4>>>2>>>0]=buf,HEAP32[eventPtr+8>>>2>>>0]=len,HEAP8[eventPtr+12>>>0]=isText,getWasmTableEntry(callbackFunc)(0,eventPtr,userData);_free(buf)};return 0}_emscripten_websocket_set_onmessage_callback_on_thread.sig="iippp";function _emscripten_websocket_new(createAttributes){createAttributes>>>=0;if(typeof WebSocket=="undefined"){return-1}if(!createAttributes){return-5}var url=UTF8ToString(HEAPU32[createAttributes>>>2>>>0]);var protocols=HEAPU32[createAttributes+4>>>2>>>0];var socket=protocols?new WebSocket(url,UTF8ToString(protocols).split(",")):new WebSocket(url);socket.binaryType="arraybuffer";var socketId=webSockets.allocate(socket);return socketId}_emscripten_websocket_new.sig="ip";function _emscripten_websocket_send_utf8_text(socketId,textData){textData>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}var str=UTF8ToString(textData);socket.send(str);return 0}_emscripten_websocket_send_utf8_text.sig="iip";function _emscripten_websocket_send_binary(socketId,binaryData,dataLength){binaryData>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.send(HEAPU8.subarray(binaryData>>>0,binaryData+dataLength>>>0));return 0}_emscripten_websocket_send_binary.sig="iipi";function _emscripten_websocket_close(socketId,code,reason){reason>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}var reasonStr=reason?UTF8ToString(reason):undefined;if(reason)socket.close(code||undefined,UTF8ToString(reason));else if(code)socket.close(code);else socket.close();return 0}_emscripten_websocket_close.sig="iiip";var _emscripten_websocket_delete=socketId=>{var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onopen=socket.onerror=socket.onclose=socket.onmessage=null;webSockets.free(socketId);return 0};_emscripten_websocket_delete.sig="ii";var _emscripten_websocket_is_supported=()=>typeof WebSocket!="undefined";_emscripten_websocket_is_supported.sig="i";var _emscripten_websocket_deinitialize=()=>{for(var i in WS.sockets){var socket=WS.sockets[i];if(socket){socket.close();_emscripten_websocket_delete(i)}}WS.sockets=[]};_emscripten_websocket_deinitialize.sig="v";var writeGLArray=(arr,dst,dstLength,heapType)=>{var len=arr.length;var writeLength=dstLength>>2;for(var i=0;i>>0]=arr[i]}return len};var webglPowerPreferences=["default","low-power","high-performance"];function _emscripten_webgl_do_create_context(target,attributes){target>>>=0;attributes>>>=0;var attr32=attributes>>>2;var powerPreference=HEAP32[attr32+(8>>2)>>>0];var contextAttributes={alpha:!!HEAP8[attributes+0>>>0],depth:!!HEAP8[attributes+1>>>0],stencil:!!HEAP8[attributes+2>>>0],antialias:!!HEAP8[attributes+3>>>0],premultipliedAlpha:!!HEAP8[attributes+4>>>0],preserveDrawingBuffer:!!HEAP8[attributes+5>>>0],powerPreference:webglPowerPreferences[powerPreference],failIfMajorPerformanceCaveat:!!HEAP8[attributes+12>>>0],majorVersion:HEAP32[attr32+(16>>2)>>>0],minorVersion:HEAP32[attr32+(20>>2)>>>0],enableExtensionsByDefault:HEAP8[attributes+24>>>0],explicitSwapControl:HEAP8[attributes+25>>>0],proxyContextToMainThread:HEAP32[attr32+(28>>2)>>>0],renderViaOffscreenBackBuffer:HEAP8[attributes+32>>>0]};var canvas=findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}_emscripten_webgl_do_create_context.sig="ppp";var _emscripten_webgl_create_context=_emscripten_webgl_do_create_context;_emscripten_webgl_create_context.sig="ppp";function _emscripten_webgl_do_get_current_context(){return GL.currentContext?GL.currentContext.handle:0}_emscripten_webgl_do_get_current_context.sig="p";var _emscripten_webgl_get_current_context=_emscripten_webgl_do_get_current_context;_emscripten_webgl_get_current_context.sig="p";var _emscripten_webgl_do_commit_frame=()=>{if(!GL.currentContext||!GL.currentContext.GLctx){return-3}if(!GL.currentContext.attributes.explicitSwapControl){return-3}return 0};_emscripten_webgl_do_commit_frame.sig="i";var _emscripten_webgl_commit_frame=_emscripten_webgl_do_commit_frame;_emscripten_webgl_commit_frame.sig="i";function _emscripten_webgl_make_context_current(contextHandle){contextHandle>>>=0;var success=GL.makeContextCurrent(contextHandle);return success?0:-5}_emscripten_webgl_make_context_current.sig="ip";function _emscripten_webgl_get_drawing_buffer_size(contextHandle,width,height){contextHandle>>>=0;width>>>=0;height>>>=0;var GLContext=GL.getContext(contextHandle);if(!GLContext||!GLContext.GLctx||!width||!height){return-5}HEAP32[width>>>2>>>0]=GLContext.GLctx.drawingBufferWidth;HEAP32[height>>>2>>>0]=GLContext.GLctx.drawingBufferHeight;return 0}_emscripten_webgl_get_drawing_buffer_size.sig="ippp";function _emscripten_webgl_get_context_attributes(c,a){c>>>=0;a>>>=0;if(!a)return-5;c=GL.contexts[c];if(!c)return-3;var t=c.GLctx;if(!t)return-3;t=t.getContextAttributes();HEAP8[a>>>0]=t.alpha;HEAP8[a+1>>>0]=t.depth;HEAP8[a+2>>>0]=t.stencil;HEAP8[a+3>>>0]=t.antialias;HEAP8[a+4>>>0]=t.premultipliedAlpha;HEAP8[a+5>>>0]=t.preserveDrawingBuffer;var power=t["powerPreference"]&&webglPowerPreferences.indexOf(t["powerPreference"]);HEAP32[a+8>>>2>>>0]=power;HEAP8[a+12>>>0]=t.failIfMajorPerformanceCaveat;HEAP32[a+16>>>2>>>0]=c.version;HEAP32[a+20>>>2>>>0]=0;HEAP8[a+24>>>0]=c.attributes.enableExtensionsByDefault;return 0}_emscripten_webgl_get_context_attributes.sig="ipp";function _emscripten_webgl_destroy_context(contextHandle){contextHandle>>>=0;if(GL.currentContext==contextHandle)GL.currentContext=0;GL.deleteContext(contextHandle)}_emscripten_webgl_destroy_context.sig="ip";function _emscripten_webgl_enable_extension(contextHandle,extension){contextHandle>>>=0;extension>>>=0;var context=GL.getContext(contextHandle);var extString=UTF8ToString(extension);if(extString.startsWith("GL_"))extString=extString.slice(3);if(extString=="ANGLE_instanced_arrays")webgl_enable_ANGLE_instanced_arrays(GLctx);if(extString=="OES_vertex_array_object")webgl_enable_OES_vertex_array_object(GLctx);if(extString=="WEBGL_draw_buffers")webgl_enable_WEBGL_draw_buffers(GLctx);if(extString=="WEBGL_draw_instanced_base_vertex_base_instance")webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);if(extString=="WEBGL_multi_draw_instanced_base_vertex_base_instance")webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);if(extString=="WEBGL_multi_draw")webgl_enable_WEBGL_multi_draw(GLctx);if(extString=="EXT_polygon_offset_clamp")webgl_enable_EXT_polygon_offset_clamp(GLctx);if(extString=="EXT_clip_control")webgl_enable_EXT_clip_control(GLctx);if(extString=="WEBGL_polygon_mode")webgl_enable_WEBGL_polygon_mode(GLctx);var ext=context.GLctx.getExtension(extString);return!!ext}_emscripten_webgl_enable_extension.sig="ipp";var _emscripten_supports_offscreencanvas=()=>0;_emscripten_supports_offscreencanvas.sig="i";var registerWebGlEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{var webGlEventHandlerFunc=(e=event)=>{if(getWasmTableEntry(callbackfunc)(eventTypeId,0,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString,callbackfunc,handlerFunc:webGlEventHandlerFunc,useCapture};JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_webglcontextlost_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;registerWebGlEventCallback(target,userData,useCapture,callbackfunc,31,"webglcontextlost",targetThread);return 0}_emscripten_set_webglcontextlost_callback_on_thread.sig="ippipp";function _emscripten_set_webglcontextrestored_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;registerWebGlEventCallback(target,userData,useCapture,callbackfunc,32,"webglcontextrestored",targetThread);return 0}_emscripten_set_webglcontextrestored_callback_on_thread.sig="ippipp";function _emscripten_is_webgl_context_lost(contextHandle){contextHandle>>>=0;return!GL.contexts[contextHandle]||GL.contexts[contextHandle].GLctx.isContextLost()}_emscripten_is_webgl_context_lost.sig="ip";function _emscripten_webgl_get_supported_extensions(){return stringToNewUTF8(GLctx.getSupportedExtensions().join(" "))}_emscripten_webgl_get_supported_extensions.sig="p";var _emscripten_webgl_get_program_parameter_d=(program,param)=>GLctx.getProgramParameter(GL.programs[program],param);_emscripten_webgl_get_program_parameter_d.sig="dii";function _emscripten_webgl_get_program_info_log_utf8(program){return stringToNewUTF8(GLctx.getProgramInfoLog(GL.programs[program]))}_emscripten_webgl_get_program_info_log_utf8.sig="pi";var _emscripten_webgl_get_shader_parameter_d=(shader,param)=>GLctx.getShaderParameter(GL.shaders[shader],param);_emscripten_webgl_get_shader_parameter_d.sig="dii";function _emscripten_webgl_get_shader_info_log_utf8(shader){return stringToNewUTF8(GLctx.getShaderInfoLog(GL.shaders[shader]))}_emscripten_webgl_get_shader_info_log_utf8.sig="pi";function _emscripten_webgl_get_shader_source_utf8(shader){return stringToNewUTF8(GLctx.getShaderSource(GL.shaders[shader]))}_emscripten_webgl_get_shader_source_utf8.sig="pi";var _emscripten_webgl_get_vertex_attrib_d=(index,param)=>GLctx.getVertexAttrib(index,param);_emscripten_webgl_get_vertex_attrib_d.sig="dii";var _emscripten_webgl_get_vertex_attrib_o=(index,param)=>{var obj=GLctx.getVertexAttrib(index,param);return obj?.name};_emscripten_webgl_get_vertex_attrib_o.sig="iii";function _emscripten_webgl_get_vertex_attrib_v(index,param,dst,dstLength,dstType){dst>>>=0;return writeGLArray(GLctx.getVertexAttrib(index,param),dst,dstLength,dstType)}_emscripten_webgl_get_vertex_attrib_v.sig="iiipii";var _emscripten_webgl_get_uniform_d=(program,location)=>GLctx.getUniform(GL.programs[program],webglGetUniformLocation(location));_emscripten_webgl_get_uniform_d.sig="dii";function _emscripten_webgl_get_uniform_v(program,location,dst,dstLength,dstType){dst>>>=0;return writeGLArray(GLctx.getUniform(GL.programs[program],webglGetUniformLocation(location)),dst,dstLength,dstType)}_emscripten_webgl_get_uniform_v.sig="iiipii";function _emscripten_webgl_get_parameter_v(param,dst,dstLength,dstType){dst>>>=0;return writeGLArray(GLctx.getParameter(param),dst,dstLength,dstType)}_emscripten_webgl_get_parameter_v.sig="iipii";var _emscripten_webgl_get_parameter_d=param=>GLctx.getParameter(param);_emscripten_webgl_get_parameter_d.sig="di";var _emscripten_webgl_get_parameter_o=param=>{var obj=GLctx.getParameter(param);return obj?.name};_emscripten_webgl_get_parameter_o.sig="ii";function _emscripten_webgl_get_parameter_utf8(param){return stringToNewUTF8(GLctx.getParameter(param))}_emscripten_webgl_get_parameter_utf8.sig="pi";function _emscripten_webgl_get_parameter_i64v(param,dst){dst>>>=0;return writeI53ToI64(dst,GLctx.getParameter(param))}_emscripten_webgl_get_parameter_i64v.sig="vip";var EGL={errorCode:12288,defaultDisplayInitialized:false,currentContext:0,currentReadSurface:0,currentDrawSurface:0,contextAttributes:{alpha:false,depth:false,stencil:false,antialias:false},stringCache:{},setErrorCode(code){EGL.errorCode=code},chooseConfig(display,attribList,config,config_size,numConfigs){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(attribList){for(;;){var param=HEAP32[attribList>>>2>>>0];if(param==12321){var alphaSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.alpha=alphaSize>0}else if(param==12325){var depthSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.depth=depthSize>0}else if(param==12326){var stencilSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.stencil=stencilSize>0}else if(param==12337){var samples=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.antialias=samples>0}else if(param==12338){var samples=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.antialias=samples==1}else if(param==12544){var requestedPriority=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.lowLatency=requestedPriority!=12547}else if(param==12344){break}attribList+=8}}if((!config||!config_size)&&!numConfigs){EGL.setErrorCode(12300);return 0}if(numConfigs){HEAP32[numConfigs>>>2>>>0]=1}if(config&&config_size>0){HEAPU32[config>>>2>>>0]=62002}EGL.setErrorCode(12288);return 1}};function _eglGetDisplay(nativeDisplayType){nativeDisplayType>>>=0;EGL.setErrorCode(12288);if(nativeDisplayType!=0&&nativeDisplayType!=1){return 0}return 62e3}_eglGetDisplay.sig="pp";function _eglInitialize(display,majorVersion,minorVersion){display>>>=0;majorVersion>>>=0;minorVersion>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(majorVersion){HEAP32[majorVersion>>>2>>>0]=1}if(minorVersion){HEAP32[minorVersion>>>2>>>0]=4}EGL.defaultDisplayInitialized=true;EGL.setErrorCode(12288);return 1}_eglInitialize.sig="ippp";function _eglTerminate(display){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.currentContext=0;EGL.currentReadSurface=0;EGL.currentDrawSurface=0;EGL.defaultDisplayInitialized=false;EGL.setErrorCode(12288);return 1}_eglTerminate.sig="ip";function _eglGetConfigs(display,configs,config_size,numConfigs){display>>>=0;configs>>>=0;numConfigs>>>=0;return EGL.chooseConfig(display,0,configs,config_size,numConfigs)}_eglGetConfigs.sig="ippip";function _eglChooseConfig(display,attrib_list,configs,config_size,numConfigs){display>>>=0;attrib_list>>>=0;configs>>>=0;numConfigs>>>=0;return EGL.chooseConfig(display,attrib_list,configs,config_size,numConfigs)}_eglChooseConfig.sig="ipppip";function _eglGetConfigAttrib(display,config,attribute,value){display>>>=0;config>>>=0;value>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12320:HEAP32[value>>>2>>>0]=EGL.contextAttributes.alpha?32:24;return 1;case 12321:HEAP32[value>>>2>>>0]=EGL.contextAttributes.alpha?8:0;return 1;case 12322:HEAP32[value>>>2>>>0]=8;return 1;case 12323:HEAP32[value>>>2>>>0]=8;return 1;case 12324:HEAP32[value>>>2>>>0]=8;return 1;case 12325:HEAP32[value>>>2>>>0]=EGL.contextAttributes.depth?24:0;return 1;case 12326:HEAP32[value>>>2>>>0]=EGL.contextAttributes.stencil?8:0;return 1;case 12327:HEAP32[value>>>2>>>0]=12344;return 1;case 12328:HEAP32[value>>>2>>>0]=62002;return 1;case 12329:HEAP32[value>>>2>>>0]=0;return 1;case 12330:HEAP32[value>>>2>>>0]=4096;return 1;case 12331:HEAP32[value>>>2>>>0]=16777216;return 1;case 12332:HEAP32[value>>>2>>>0]=4096;return 1;case 12333:HEAP32[value>>>2>>>0]=0;return 1;case 12334:HEAP32[value>>>2>>>0]=0;return 1;case 12335:HEAP32[value>>>2>>>0]=12344;return 1;case 12337:HEAP32[value>>>2>>>0]=EGL.contextAttributes.antialias?4:0;return 1;case 12338:HEAP32[value>>>2>>>0]=EGL.contextAttributes.antialias?1:0;return 1;case 12339:HEAP32[value>>>2>>>0]=4;return 1;case 12340:HEAP32[value>>>2>>>0]=12344;return 1;case 12341:case 12342:case 12343:HEAP32[value>>>2>>>0]=-1;return 1;case 12345:case 12346:HEAP32[value>>>2>>>0]=0;return 1;case 12347:HEAP32[value>>>2>>>0]=0;return 1;case 12348:HEAP32[value>>>2>>>0]=1;return 1;case 12349:case 12350:HEAP32[value>>>2>>>0]=0;return 1;case 12351:HEAP32[value>>>2>>>0]=12430;return 1;case 12352:HEAP32[value>>>2>>>0]=4;return 1;case 12354:HEAP32[value>>>2>>>0]=0;return 1;default:EGL.setErrorCode(12292);return 0}}_eglGetConfigAttrib.sig="ippip";function _eglCreateWindowSurface(display,config,win,attrib_list){display>>>=0;config>>>=0;attrib_list>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}EGL.setErrorCode(12288);return 62006}_eglCreateWindowSurface.sig="pppip";function _eglDestroySurface(display,surface){display>>>=0;surface>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(surface!=62006){EGL.setErrorCode(12301);return 1}if(EGL.currentReadSurface==surface){EGL.currentReadSurface=0}if(EGL.currentDrawSurface==surface){EGL.currentDrawSurface=0}EGL.setErrorCode(12288);return 1}_eglDestroySurface.sig="ipp";function _eglCreateContext(display,config,hmm,contextAttribs){display>>>=0;config>>>=0;hmm>>>=0;contextAttribs>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}var glesContextVersion=1;for(;;){var param=HEAP32[contextAttribs>>>2>>>0];if(param==12440){glesContextVersion=HEAP32[contextAttribs+4>>>2>>>0]}else if(param==12344){break}else{EGL.setErrorCode(12292);return 0}contextAttribs+=8}if(glesContextVersion<2||glesContextVersion>3){EGL.setErrorCode(12293);return 0}EGL.contextAttributes.majorVersion=glesContextVersion-1;EGL.contextAttributes.minorVersion=0;EGL.context=GL.createContext(Browser.getCanvas(),EGL.contextAttributes);if(EGL.context!=0){EGL.setErrorCode(12288);GL.makeContextCurrent(EGL.context);Browser.useWebGL=true;Browser.moduleContextCreatedCallbacks.forEach(callback=>callback());GL.makeContextCurrent(null);return 62004}else{EGL.setErrorCode(12297);return 0}}_eglCreateContext.sig="ppppp";function _eglDestroyContext(display,context){display>>>=0;context>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=62004){EGL.setErrorCode(12294);return 0}GL.deleteContext(EGL.context);EGL.setErrorCode(12288);if(EGL.currentContext==context){EGL.currentContext=0}return 1}_eglDestroyContext.sig="ipp";function _eglQuerySurface(display,surface,attribute,value){display>>>=0;surface>>>=0;value>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(surface!=62006){EGL.setErrorCode(12301);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12328:HEAP32[value>>>2>>>0]=62002;return 1;case 12376:return 1;case 12375:HEAP32[value>>>2>>>0]=Browser.getCanvas().width;return 1;case 12374:HEAP32[value>>>2>>>0]=Browser.getCanvas().height;return 1;case 12432:HEAP32[value>>>2>>>0]=-1;return 1;case 12433:HEAP32[value>>>2>>>0]=-1;return 1;case 12434:HEAP32[value>>>2>>>0]=-1;return 1;case 12422:HEAP32[value>>>2>>>0]=12420;return 1;case 12441:HEAP32[value>>>2>>>0]=12442;return 1;case 12435:HEAP32[value>>>2>>>0]=12437;return 1;case 12416:case 12417:case 12418:case 12419:return 1;default:EGL.setErrorCode(12292);return 0}}_eglQuerySurface.sig="ippip";function _eglQueryContext(display,context,attribute,value){display>>>=0;context>>>=0;value>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=62004){EGL.setErrorCode(12294);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12328:HEAP32[value>>>2>>>0]=62002;return 1;case 12439:HEAP32[value>>>2>>>0]=12448;return 1;case 12440:HEAP32[value>>>2>>>0]=EGL.contextAttributes.majorVersion+1;return 1;case 12422:HEAP32[value>>>2>>>0]=12420;return 1;default:EGL.setErrorCode(12292);return 0}}_eglQueryContext.sig="ippip";var _eglGetError=()=>EGL.errorCode;_eglGetError.sig="i";function _eglQueryString(display,name){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.setErrorCode(12288);if(EGL.stringCache[name])return EGL.stringCache[name];var ret;switch(name){case 12371:ret=stringToNewUTF8("Emscripten");break;case 12372:ret=stringToNewUTF8("1.4 Emscripten EGL");break;case 12373:ret=stringToNewUTF8("");break;case 12429:ret=stringToNewUTF8("OpenGL_ES");break;default:EGL.setErrorCode(12300);return 0}EGL.stringCache[name]=ret;return ret}_eglQueryString.sig="ppi";var _eglBindAPI=api=>{if(api==12448){EGL.setErrorCode(12288);return 1}EGL.setErrorCode(12300);return 0};_eglBindAPI.sig="ii";var _eglQueryAPI=()=>{EGL.setErrorCode(12288);return 12448};_eglQueryAPI.sig="i";var _eglWaitClient=()=>{EGL.setErrorCode(12288);return 1};_eglWaitClient.sig="i";var _eglWaitNative=nativeEngineId=>{EGL.setErrorCode(12288);return 1};_eglWaitNative.sig="ii";var _eglWaitGL=_eglWaitClient;_eglWaitGL.sig="i";function _eglSwapInterval(display,interval){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(interval==0)_emscripten_set_main_loop_timing(0,0);else _emscripten_set_main_loop_timing(1,interval);EGL.setErrorCode(12288);return 1}_eglSwapInterval.sig="ipi";function _eglMakeCurrent(display,draw,read,context){display>>>=0;draw>>>=0;read>>>=0;context>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=0&&context!=62004){EGL.setErrorCode(12294);return 0}if(read!=0&&read!=62006||draw!=0&&draw!=62006){EGL.setErrorCode(12301);return 0}GL.makeContextCurrent(context?EGL.context:null);EGL.currentContext=context;EGL.currentDrawSurface=draw;EGL.currentReadSurface=read;EGL.setErrorCode(12288);return 1}_eglMakeCurrent.sig="ipppp";function _eglGetCurrentContext(){return EGL.currentContext}_eglGetCurrentContext.sig="p";function _eglGetCurrentSurface(readdraw){if(readdraw==12378){return EGL.currentReadSurface}else if(readdraw==12377){return EGL.currentDrawSurface}else{EGL.setErrorCode(12300);return 0}}_eglGetCurrentSurface.sig="pi";function _eglGetCurrentDisplay(){return EGL.currentContext?62e3:0}_eglGetCurrentDisplay.sig="p";function _eglSwapBuffers(dpy,surface){dpy>>>=0;surface>>>=0;if(!EGL.defaultDisplayInitialized){EGL.setErrorCode(12289)}else if(!GLctx){EGL.setErrorCode(12290)}else if(GLctx.isContextLost()){EGL.setErrorCode(12302)}else{EGL.setErrorCode(12288);return 1}return 0}_eglSwapBuffers.sig="ipp";var _eglReleaseThread=()=>{EGL.currentContext=0;EGL.currentReadSurface=0;EGL.currentDrawSurface=0;EGL.setErrorCode(12288);return 1};_eglReleaseThread.sig="i";var _SDL_GetTicks=()=>Date.now()-SDL.startTime|0;_SDL_GetTicks.sig="i";function _SDL_LockSurface(surf){surf>>>=0;var surfData=SDL.surfaces[surf];surfData.locked++;if(surfData.locked>1)return 0;if(!surfData.buffer){surfData.buffer=_malloc(surfData.width*surfData.height*4);HEAPU32[surf+20>>>2>>>0]=surfData.buffer}HEAPU32[surf+20>>>2>>>0]=surfData.buffer;if(surf==SDL.screen&&Module.screenIsReadOnly&&surfData.image)return 0;if(SDL.defaults.discardOnLock){if(!surfData.image){surfData.image=surfData.ctx.createImageData(surfData.width,surfData.height)}if(!SDL.defaults.opaqueFrontBuffer)return}else{surfData.image=surfData.ctx.getImageData(0,0,surfData.width,surfData.height)}if(surf==SDL.screen&&SDL.defaults.opaqueFrontBuffer){var data=surfData.image.data;var num=data.length;for(var i=0;i>>0)}}return 0}_SDL_LockSurface.sig="ip";var SDL={defaults:{width:320,height:200,copyOnLock:true,discardOnLock:false,opaqueFrontBuffer:true},version:null,surfaces:{},canvasPool:[],events:[],fonts:[null],audios:[null],rwops:[null],music:{audio:null,volume:1},mixerFrequency:22050,mixerFormat:32784,mixerNumChannels:2,mixerChunkSize:1024,channelMinimumNumber:0,GL:false,glAttributes:{0:3,1:3,2:2,3:0,4:0,5:1,6:16,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0,15:1,16:0,17:0,18:0},keyboardState:null,keyboardMap:{},canRequestFullscreen:false,isRequestingFullscreen:false,textInput:false,unicode:false,ttfContext:null,audio:null,startTime:null,initFlags:0,buttonState:0,modState:0,DOMButtons:[0,0,0],DOMEventToSDLEvent:{},TOUCH_DEFAULT_ID:0,eventHandler:null,eventHandlerContext:null,eventHandlerTemp:0,keyCodes:{16:1249,17:1248,18:1250,20:1081,33:1099,34:1102,35:1101,36:1098,37:1104,38:1106,39:1103,40:1105,44:316,45:1097,46:127,91:1251,93:1125,96:1122,97:1113,98:1114,99:1115,100:1116,101:1117,102:1118,103:1119,104:1120,105:1121,106:1109,107:1111,109:1110,110:1123,111:1108,112:1082,113:1083,114:1084,115:1085,116:1086,117:1087,118:1088,119:1089,120:1090,121:1091,122:1092,123:1093,124:1128,125:1129,126:1130,127:1131,128:1132,129:1133,130:1134,131:1135,132:1136,133:1137,134:1138,135:1139,144:1107,160:94,161:33,162:34,163:35,164:36,165:37,166:38,167:95,168:40,169:41,170:42,171:43,172:124,173:45,174:123,175:125,176:126,181:127,182:129,183:128,188:44,190:46,191:47,192:96,219:91,220:92,221:93,222:39,224:1251},scanCodes:{8:42,9:43,13:40,27:41,32:44,35:204,39:53,44:54,46:55,47:56,48:39,49:30,50:31,51:32,52:33,53:34,54:35,55:36,56:37,57:38,58:203,59:51,61:46,91:47,92:49,93:48,96:52,97:4,98:5,99:6,100:7,101:8,102:9,103:10,104:11,105:12,106:13,107:14,108:15,109:16,110:17,111:18,112:19,113:20,114:21,115:22,116:23,117:24,118:25,119:26,120:27,121:28,122:29,127:76,305:224,308:226,316:70},loadRect(rect){return{x:HEAP32[rect>>>2>>>0],y:HEAP32[rect+4>>>2>>>0],w:HEAP32[rect+8>>>2>>>0],h:HEAP32[rect+12>>>2>>>0]}},updateRect(rect,r){HEAP32[rect>>>2>>>0]=r.x;HEAP32[rect+4>>>2>>>0]=r.y;HEAP32[rect+8>>>2>>>0]=r.w;HEAP32[rect+12>>>2>>>0]=r.h},intersectionOfRects(first,second){var leftX=Math.max(first.x,second.x);var leftY=Math.max(first.y,second.y);var rightX=Math.min(first.x+first.w,second.x+second.w);var rightY=Math.min(first.y+first.h,second.y+second.h);return{x:leftX,y:leftY,w:Math.max(leftX,rightX)-leftX,h:Math.max(leftY,rightY)-leftY}},checkPixelFormat(fmt){},loadColorToCSSRGB(color){var rgba=HEAP32[color>>>2>>>0];return"rgb("+(rgba&255)+","+(rgba>>8&255)+","+(rgba>>16&255)+")"},loadColorToCSSRGBA(color){var rgba=HEAP32[color>>>2>>>0];return"rgba("+(rgba&255)+","+(rgba>>8&255)+","+(rgba>>16&255)+","+(rgba>>24&255)/255+")"},translateColorToCSSRGBA:rgba=>"rgba("+(rgba&255)+","+(rgba>>8&255)+","+(rgba>>16&255)+","+(rgba>>>24)/255+")",translateRGBAToCSSRGBA:(r,g,b,a)=>"rgba("+(r&255)+","+(g&255)+","+(b&255)+","+(a&255)/255+")",translateRGBAToColor:(r,g,b,a)=>r|g<<8|b<<16|a<<24,makeSurface(width,height,flags,usePageCanvas,source,rmask,gmask,bmask,amask){var is_SDL_HWSURFACE=flags&134217729;var is_SDL_HWPALETTE=flags&2097152;var is_SDL_OPENGL=flags&67108864;var surf=_malloc(60);var pixelFormat=_malloc(44);var bpp=is_SDL_HWPALETTE?1:4;var buffer=0;if(!is_SDL_HWSURFACE&&!is_SDL_OPENGL){buffer=_malloc(width*height*4)}HEAP32[surf>>>2>>>0]=flags;HEAPU32[surf+4>>>2>>>0]=pixelFormat;HEAP32[surf+8>>>2>>>0]=width;HEAP32[surf+12>>>2>>>0]=height;HEAP32[surf+16>>>2>>>0]=width*bpp;HEAPU32[surf+20>>>2>>>0]=buffer;var canvas=Browser.getCanvas();HEAP32[surf+36>>>2>>>0]=0;HEAP32[surf+40>>>2>>>0]=0;HEAP32[surf+44>>>2>>>0]=canvas.width;HEAP32[surf+48>>>2>>>0]=canvas.height;HEAP32[surf+56>>>2>>>0]=1;HEAP32[pixelFormat>>>2>>>0]=-2042224636;HEAP32[pixelFormat+4>>>2>>>0]=0;HEAP8[pixelFormat+8>>>0]=bpp*8;HEAP8[pixelFormat+9>>>0]=bpp;HEAP32[pixelFormat+12>>>2>>>0]=rmask||255;HEAP32[pixelFormat+16>>>2>>>0]=gmask||65280;HEAP32[pixelFormat+20>>>2>>>0]=bmask||16711680;HEAP32[pixelFormat+24>>>2>>>0]=amask||4278190080;SDL.GL=SDL.GL||is_SDL_OPENGL;if(!usePageCanvas){if(SDL.canvasPool.length>0){canvas=SDL.canvasPool.pop()}else{canvas=document.createElement("canvas")}canvas.width=width;canvas.height=height}var webGLContextAttributes={antialias:SDL.glAttributes[13]!=0&&SDL.glAttributes[14]>1,depth:SDL.glAttributes[6]>0,stencil:SDL.glAttributes[7]>0,alpha:SDL.glAttributes[3]>0};var ctx=Browser.createContext(canvas,is_SDL_OPENGL,usePageCanvas,webGLContextAttributes);SDL.surfaces[surf]={width,height,canvas,ctx,surf,buffer,pixelFormat,alpha:255,flags,locked:0,usePageCanvas,source,isFlagSet:flag=>flags&flag};return surf},copyIndexedColorData(surfData,rX,rY,rW,rH){if(!surfData.colors){return}var canvas=Browser.getCanvas();var fullWidth=canvas.width;var fullHeight=canvas.height;var startX=rX||0;var startY=rY||0;var endX=(rW||fullWidth-startX)+startX;var endY=(rH||fullHeight-startY)+startY;var buffer=surfData.buffer;if(!surfData.image.data32){surfData.image.data32=new Uint32Array(surfData.image.data.buffer)}var data32=surfData.image.data32;var colors32=surfData.colors32;for(var y=startY;y>>0]]}}},freeSurface(surf){var refcountPointer=surf+56;var refcount=HEAP32[refcountPointer>>>2>>>0];if(refcount>1){HEAP32[refcountPointer>>>2>>>0]=refcount-1;return}var info=SDL.surfaces[surf];if(!info.usePageCanvas&&info.canvas)SDL.canvasPool.push(info.canvas);if(info.buffer)_free(info.buffer);_free(info.pixelFormat);_free(surf);SDL.surfaces[surf]=null;if(surf===SDL.screen){SDL.screen=null}},blitSurface(src,srcrect,dst,dstrect,scale){var srcData=SDL.surfaces[src];var dstData=SDL.surfaces[dst];var sr,dr;if(srcrect){sr=SDL.loadRect(srcrect)}else{sr={x:0,y:0,w:srcData.width,h:srcData.height}}if(dstrect){dr=SDL.loadRect(dstrect)}else{dr={x:0,y:0,w:srcData.width,h:srcData.height}}if(dstData.clipRect){var widthScale=!scale||sr.w===0?1:sr.w/dr.w;var heightScale=!scale||sr.h===0?1:sr.h/dr.h;dr=SDL.intersectionOfRects(dstData.clipRect,dr);sr.w=dr.w*widthScale;sr.h=dr.h*heightScale;if(dstrect){SDL.updateRect(dstrect,dr)}}var blitw,blith;if(scale){blitw=dr.w;blith=dr.h}else{blitw=sr.w;blith=sr.h}if(sr.w===0||sr.h===0||blitw===0||blith===0){return 0}var oldAlpha=dstData.ctx.globalAlpha;dstData.ctx.globalAlpha=srcData.alpha/255;dstData.ctx.drawImage(srcData.canvas,sr.x,sr.y,sr.w,sr.h,dr.x,dr.y,blitw,blith);dstData.ctx.globalAlpha=oldAlpha;if(dst!=SDL.screen){warnOnce("WARNING: copying canvas data to memory for compatibility");_SDL_LockSurface(dst);dstData.locked--}return 0},downFingers:{},savedKeydown:null,receiveEvent(event){function unpressAllPressedKeys(){for(var keyCode of Object.values(SDL.keyboardMap)){SDL.events.push({type:"keyup",keyCode})}}switch(event.type){case"touchstart":case"touchmove":{event.preventDefault();var touches=[];if(event.type==="touchstart"){for(var touch of event.touches){if(SDL.downFingers[touch.identifier]!=true){SDL.downFingers[touch.identifier]=true;touches.push(touch)}}}else{touches=event.touches}var firstTouch=touches[0];if(firstTouch){if(event.type=="touchstart"){SDL.DOMButtons[0]=1}var mouseEventType;switch(event.type){case"touchstart":mouseEventType="mousedown";break;case"touchmove":mouseEventType="mousemove";break}var mouseEvent={type:mouseEventType,button:0,pageX:firstTouch.clientX,pageY:firstTouch.clientY};SDL.events.push(mouseEvent)}for(var touch of touches){SDL.events.push({type:event.type,touch})}break}case"touchend":{event.preventDefault();for(var touch of event.changedTouches){if(SDL.downFingers[touch.identifier]===true){delete SDL.downFingers[touch.identifier]}}var mouseEvent={type:"mouseup",button:0,pageX:event.changedTouches[0].clientX,pageY:event.changedTouches[0].clientY};SDL.DOMButtons[0]=0;SDL.events.push(mouseEvent);for(var touch of event.changedTouches){SDL.events.push({type:"touchend",touch})}break}case"DOMMouseScroll":case"mousewheel":case"wheel":var delta=-Browser.getMouseWheelDelta(event);delta=delta==0?0:delta>0?Math.max(delta,1):Math.min(delta,-1);var button=(delta>0?4:5)-1;SDL.events.push({type:"mousedown",button,pageX:event.pageX,pageY:event.pageY});SDL.events.push({type:"mouseup",button,pageX:event.pageX,pageY:event.pageY});SDL.events.push({type:"wheel",deltaX:0,deltaY:delta});event.preventDefault();break;case"mousemove":if(SDL.DOMButtons[0]===1){SDL.events.push({type:"touchmove",touch:{identifier:0,deviceID:-1,pageX:event.pageX,pageY:event.pageY}})}if(Browser.pointerLock){if("mozMovementX"in event){event["movementX"]=event["mozMovementX"];event["movementY"]=event["mozMovementY"]}if(event["movementX"]==0&&event["movementY"]==0){event.preventDefault();return}}case"keydown":case"keyup":case"keypress":case"mousedown":case"mouseup":if(event.type!=="keydown"||!SDL.unicode&&!SDL.textInput||(event.key=="Backspace"||event.key=="Tab")){event.preventDefault()}if(event.type=="mousedown"){SDL.DOMButtons[event.button]=1;SDL.events.push({type:"touchstart",touch:{identifier:0,deviceID:-1,pageX:event.pageX,pageY:event.pageY}})}else if(event.type=="mouseup"){if(!SDL.DOMButtons[event.button]){return}SDL.events.push({type:"touchend",touch:{identifier:0,deviceID:-1,pageX:event.pageX,pageY:event.pageY}});SDL.DOMButtons[event.button]=0}if(event.type==="keydown"||event.type==="mousedown"){SDL.canRequestFullscreen=true}else if(event.type==="keyup"||event.type==="mouseup"){if(SDL.isRequestingFullscreen){Module["requestFullscreen"](true,true);SDL.isRequestingFullscreen=false}SDL.canRequestFullscreen=false}if(event.type==="keypress"&&SDL.savedKeydown){SDL.savedKeydown.keypressCharCode=event.charCode;SDL.savedKeydown=null}else if(event.type==="keydown"){SDL.savedKeydown=event}if(event.type!=="keypress"||SDL.textInput){SDL.events.push(event)}break;case"mouseout":for(var i=0;i<3;i++){if(SDL.DOMButtons[i]){SDL.events.push({type:"mouseup",button:i,pageX:event.pageX,pageY:event.pageY});SDL.DOMButtons[i]=0}}event.preventDefault();break;case"focus":SDL.events.push(event);event.preventDefault();break;case"blur":SDL.events.push(event);unpressAllPressedKeys();event.preventDefault();break;case"visibilitychange":SDL.events.push({type:"visibilitychange",visible:!document.hidden});unpressAllPressedKeys();event.preventDefault();break;case"unload":if(MainLoop.runner){SDL.events.push(event);MainLoop.runner()}return;case"resize":SDL.events.push(event);if(event.preventDefault){event.preventDefault()}break}if(SDL.events.length>=1e4){err("SDL event queue full, dropping events");SDL.events=SDL.events.slice(0,1e4)}SDL.flushEventsToHandler();return},lookupKeyCodeForEvent(event){var code=event.keyCode;if(code>=65&&code<=90){code+=32}else{code=SDL.keyCodes[code]||(code<128?code:0);if(event.location===2&&code>=(224|1<<10)&&code<=(227|1<<10)){code+=4}}return code},handleEvent(event){if(event.handled)return;event.handled=true;switch(event.type){case"touchstart":case"touchend":case"touchmove":{Browser.calculateMouseEvent(event);break}case"keydown":case"keyup":{var down=event.type==="keydown";var code=SDL.lookupKeyCodeForEvent(event);if(!code)return;HEAP8[SDL.keyboardState+code>>>0]=down;SDL.modState=(HEAP8[SDL.keyboardState+1248>>>0]?64:0)|(HEAP8[SDL.keyboardState+1249>>>0]?1:0)|(HEAP8[SDL.keyboardState+1250>>>0]?256:0)|(HEAP8[SDL.keyboardState+1252>>>0]?128:0)|(HEAP8[SDL.keyboardState+1253>>>0]?2:0)|(HEAP8[SDL.keyboardState+1254>>>0]?512:0);if(down){SDL.keyboardMap[code]=event.keyCode}else{delete SDL.keyboardMap[code]}break}case"mousedown":case"mouseup":if(event.type=="mousedown"){SDL.buttonState|=1<0){if(SDL.makeCEvent(SDL.events.shift(),ptr)!==false)return 1}return 0}return SDL.events.length>0},makeCEvent(event,ptr){if(typeof event=="number"){_memcpy(ptr,event,28);_free(event);return}SDL.handleEvent(event);switch(event.type){case"keydown":case"keyup":{var down=event.type==="keydown";var key=SDL.lookupKeyCodeForEvent(event);if(!key)return false;var scan;if(key>=1024){scan=key-1024}else{scan=SDL.scanCodes[key]||key}HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP8[ptr+8>>>0]=down?1:0;HEAP8[ptr+9>>>0]=0;HEAP32[ptr+12>>>2>>>0]=scan;HEAP32[ptr+16>>>2>>>0]=key;HEAP16[ptr+20>>>1>>>0]=SDL.modState;HEAP32[ptr+24>>>2>>>0]=event.keypressCharCode||key;break}case"keypress":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];var cStr=intArrayFromString(String.fromCharCode(event.charCode));for(var i=0;i>>0]=cStr[i]}break}case"mousedown":case"mouseup":case"mousemove":{if(event.type!="mousemove"){var down=event.type==="mousedown";HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP32[ptr+8>>>2>>>0]=0;HEAP32[ptr+12>>>2>>>0]=0;HEAP8[ptr+16>>>0]=event.button+1;HEAP8[ptr+17>>>0]=down?1:0;HEAP32[ptr+20>>>2>>>0]=Browser.mouseX;HEAP32[ptr+24>>>2>>>0]=Browser.mouseY}else{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP32[ptr+8>>>2>>>0]=0;HEAP32[ptr+12>>>2>>>0]=0;HEAP32[ptr+16>>>2>>>0]=SDL.buttonState;HEAP32[ptr+20>>>2>>>0]=Browser.mouseX;HEAP32[ptr+24>>>2>>>0]=Browser.mouseY;HEAP32[ptr+28>>>2>>>0]=Browser.mouseMovementX;HEAP32[ptr+32>>>2>>>0]=Browser.mouseMovementY}break}case"wheel":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+16>>>2>>>0]=event.deltaX;HEAP32[ptr+20>>>2>>>0]=event.deltaY;break}case"touchstart":case"touchend":case"touchmove":{var touch=event.touch;if(!Browser.touches[touch.identifier])break;var canvas=Browser.getCanvas();var x=Browser.touches[touch.identifier].x/canvas.width;var y=Browser.touches[touch.identifier].y/canvas.height;var lx=Browser.lastTouches[touch.identifier].x/canvas.width;var ly=Browser.lastTouches[touch.identifier].y/canvas.height;var dx=x-lx;var dy=y-ly;if(touch["deviceID"]===undefined)touch.deviceID=SDL.TOUCH_DEFAULT_ID;if(dx===0&&dy===0&&event.type==="touchmove")return false;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=_SDL_GetTicks();HEAP64[ptr+8>>>3>>>0]=BigInt(touch.deviceID);HEAP64[ptr+16>>>3>>>0]=BigInt(touch.identifier);HEAPF32[ptr+24>>>2>>>0]=x;HEAPF32[ptr+28>>>2>>>0]=y;HEAPF32[ptr+32>>>2>>>0]=dx;HEAPF32[ptr+36>>>2>>>0]=dy;if(touch.force!==undefined){HEAPF32[ptr+40>>>2>>>0]=touch.force}else{HEAPF32[ptr+40>>>2>>>0]=event.type=="touchend"?0:1}break}case"unload":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];break}case"resize":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=event.w;HEAP32[ptr+8>>>2>>>0]=event.h;break}case"joystick_button_up":case"joystick_button_down":{var state=event.type==="joystick_button_up"?0:1;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP8[ptr+4>>>0]=event.index;HEAP8[ptr+5>>>0]=event.button;HEAP8[ptr+6>>>0]=state;break}case"joystick_axis_motion":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP8[ptr+4>>>0]=event.index;HEAP8[ptr+5>>>0]=event.axis;HEAP32[ptr+8>>>2>>>0]=SDL.joystickAxisValueConversion(event.value);break}case"focus":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP8[ptr+8>>>0]=12;break}case"blur":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP8[ptr+8>>>0]=13;break}case"visibilitychange":{var visibilityEventID=event.visible?1:2;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP8[ptr+8>>>0]=visibilityEventID;break}default:throw"Unhandled SDL event: "+event.type}},makeFontString(height,fontName){if(fontName.charAt(0)!="'"&&fontName.charAt(0)!='"'){fontName='"'+fontName+'"'}return height+"px "+fontName+", serif"},estimateTextWidth(fontData,text){var h=fontData.size;var fontString=SDL.makeFontString(h,fontData.name);var tempCtx=SDL.ttfContext;tempCtx.font=fontString;var ret=tempCtx.measureText(text).width|0;return ret},allocateChannels(num){if(SDL.numChannels>=num&&num!=0)return;SDL.numChannels=num;SDL.channels=[];for(var i=0;i{if(!audio.paused)SDL.playWebAudio(audio)});return}audio.webAudioNode=SDL.audioContext["createBufferSource"]();audio.webAudioNode["buffer"]=webAudio.decodedBuffer;audio.webAudioNode["loop"]=audio.loop;audio.webAudioNode["onended"]=audio["onended"];audio.webAudioPannerNode=SDL.audioContext["createPanner"]();audio.webAudioPannerNode["setPosition"](0,0,-.5);audio.webAudioPannerNode["panningModel"]="equalpower";audio.webAudioGainNode=SDL.audioContext["createGain"]();audio.webAudioGainNode["gain"]["value"]=audio.volume;audio.webAudioNode["connect"](audio.webAudioPannerNode);audio.webAudioPannerNode["connect"](audio.webAudioGainNode);audio.webAudioGainNode["connect"](SDL.audioContext["destination"]);audio.webAudioNode["start"](0,audio.currentPosition);audio.startTime=SDL.audioContext["currentTime"]-audio.currentPosition}catch(e){err(`playWebAudio failed: ${e}`)}},pauseWebAudio(audio){if(!audio)return;if(audio.webAudioNode){try{audio.currentPosition=(SDL.audioContext["currentTime"]-audio.startTime)%audio.resource.webAudio.decodedBuffer.duration;audio.webAudioNode["onended"]=undefined;audio.webAudioNode.stop(0);audio.webAudioNode=undefined}catch(e){err(`pauseWebAudio failed: ${e}`)}}audio.paused=true},openAudioContext(){if(!SDL.audioContext){if(typeof AudioContext!="undefined"){SDL.audioContext=new AudioContext}else if(typeof webkitAudioContext!="undefined"){SDL.audioContext=new webkitAudioContext}}},webAudioAvailable:()=>!!SDL.audioContext,fillWebAudioBufferFromHeap(heapPtr,sizeSamplesPerChannel,dstAudioBuffer){var audio=SDL.audio;var numChannels=audio.channels;for(var c=0;c>>1>>>0]/32768}}else if(audio.format==8){for(var j=0;j>>0];channelData[j]=(v>=0?v-128:v+128)/128}}else if(audio.format==33056){for(var j=0;j>>2>>>0]}}else{throw"Invalid SDL audio format "+audio.format+"!"}}},joystickEventState:1,lastJoystickState:{},joystickNamePool:{},recordJoystickState(joystick,state){var buttons=[];for(var button of state.buttons){buttons.push(SDL.getJoystickButtonState(button))}SDL.lastJoystickState[joystick]={buttons,axes:state.axes.slice(0),timestamp:state.timestamp,index:state.index,id:state.id}},getJoystickButtonState(button){if(typeof button=="object"){return button["pressed"]}return button>0},queryJoysticks(){for(var joystick in SDL.lastJoystickState){var state=SDL.getGamepad(joystick-1);var prevState=SDL.lastJoystickState[joystick];if(typeof state=="undefined")return;if(state===null)return;if(typeof state.timestamp!="number"||state.timestamp!=prevState.timestamp||!state.timestamp){var i;for(i=0;ideviceIndex&&deviceIndex>=0){return gamepads[deviceIndex]}return null}};function _SDL_Linked_Version(){if(SDL.version===null){SDL.version=_malloc(3);HEAP8[SDL.version>>>0]=1;HEAP8[SDL.version+1>>>0]=3;HEAP8[SDL.version+2>>>0]=0}return SDL.version}_SDL_Linked_Version.sig="p";var _SDL_Init=initFlags=>{SDL.startTime=Date.now();SDL.initFlags=initFlags;if(!Module["doNotCaptureKeyboard"]){var keyboardListeningElement=Module["keyboardListeningElement"]||document;keyboardListeningElement.addEventListener("keydown",SDL.receiveEvent);keyboardListeningElement.addEventListener("keyup",SDL.receiveEvent);keyboardListeningElement.addEventListener("keypress",SDL.receiveEvent);window.addEventListener("focus",SDL.receiveEvent);window.addEventListener("blur",SDL.receiveEvent);document.addEventListener("visibilitychange",SDL.receiveEvent)}window.addEventListener("unload",SDL.receiveEvent);SDL.keyboardState=_calloc(65536,1);SDL.DOMEventToSDLEvent["keydown"]=768;SDL.DOMEventToSDLEvent["keyup"]=769;SDL.DOMEventToSDLEvent["keypress"]=771;SDL.DOMEventToSDLEvent["mousedown"]=1025;SDL.DOMEventToSDLEvent["mouseup"]=1026;SDL.DOMEventToSDLEvent["mousemove"]=1024;SDL.DOMEventToSDLEvent["wheel"]=1027;SDL.DOMEventToSDLEvent["touchstart"]=1792;SDL.DOMEventToSDLEvent["touchend"]=1793;SDL.DOMEventToSDLEvent["touchmove"]=1794;SDL.DOMEventToSDLEvent["unload"]=256;SDL.DOMEventToSDLEvent["resize"]=28673;SDL.DOMEventToSDLEvent["visibilitychange"]=512;SDL.DOMEventToSDLEvent["focus"]=512;SDL.DOMEventToSDLEvent["blur"]=512;SDL.DOMEventToSDLEvent["joystick_axis_motion"]=1536;SDL.DOMEventToSDLEvent["joystick_button_down"]=1539;SDL.DOMEventToSDLEvent["joystick_button_up"]=1540;return 0};_SDL_Init.sig="ii";var _SDL_WasInit=flags=>{if(SDL.startTime===null){_SDL_Init(0)}return 1};_SDL_WasInit.sig="ii";function _SDL_GetVideoInfo(){var ret=_calloc(20,1);var canvas=Browser.getCanvas();HEAP32[ret+12>>>2>>>0]=canvas.width;HEAP32[ret+16>>>2>>>0]=canvas.height;return ret}_SDL_GetVideoInfo.sig="p";function _SDL_ListModes(format,flags){format>>>=0;return-1}_SDL_ListModes.sig="ppi";var _SDL_VideoModeOK=(width,height,depth,flags)=>depth;_SDL_VideoModeOK.sig="iiiii";function _SDL_VideoDriverName(buf,max_size){buf>>>=0;if(SDL.startTime===null){return 0}var driverName=[101,109,115,99,114,105,112,116,101,110,95,115,100,108,95,100,114,105,118,101,114];var index=0;var size=driverName.length;if(max_size<=size){size=max_size-1}while(index>>0]=value;index++}HEAP8[buf+index>>>0]=0;return buf}_SDL_VideoDriverName.sig="ppi";var _SDL_AudioDriverName=_SDL_VideoDriverName;_SDL_AudioDriverName.sig="ppi";var _SDL_SetVideoMode=function(width,height,depth,flags){var canvas=Browser.getCanvas();["touchstart","touchend","touchmove","mousedown","mouseup","mousemove","mousewheel","wheel","mouseout","DOMMouseScroll"].forEach(e=>canvas.addEventListener(e,SDL.receiveEvent,true));if(width==0&&height==0){width=canvas.width;height=canvas.height}if(!SDL.addedResizeListener){SDL.addedResizeListener=true;Browser.resizeListeners.push((w,h)=>{if(!SDL.settingVideoMode){SDL.receiveEvent({type:"resize",w,h})}})}SDL.settingVideoMode=true;Browser.setCanvasSize(width,height);SDL.settingVideoMode=false;if(SDL.screen){SDL.freeSurface(SDL.screen);assert(!SDL.screen)}if(SDL.GL)flags=flags|67108864;SDL.screen=SDL.makeSurface(width,height,flags,true,"screen");return SDL.screen};_SDL_SetVideoMode.sig="piiii";function _SDL_GetVideoSurface(){return SDL.screen}_SDL_GetVideoSurface.sig="p";var _SDL_AudioQuit=()=>{for(var i=0;iout("SDL_VideoQuit called (and ignored)");_SDL_VideoQuit.sig="v";var _SDL_QuitSubSystem=flags=>out("SDL_QuitSubSystem called (and ignored)");_SDL_QuitSubSystem.sig="vi";var _SDL_Quit=()=>{_SDL_AudioQuit();out("SDL_Quit called (and ignored)")};_SDL_Quit.sig="v";function _SDL_UnlockSurface(surf){surf>>>=0;assert(!SDL.GL);var surfData=SDL.surfaces[surf];if(!surfData.locked||--surfData.locked>0){return}if(surfData.isFlagSet(2097152)){SDL.copyIndexedColorData(surfData)}else if(!surfData.colors){var data=surfData.image.data;var buffer=surfData.buffer;assert(buffer%4==0,"Invalid buffer offset: "+buffer);var src=buffer>>>2;var dst=0;var isScreen=surf==SDL.screen;var num;if(typeof CanvasPixelArray!="undefined"&&data instanceof CanvasPixelArray){num=data.length;while(dst>>0];data[dst]=val&255;data[dst+1]=val>>8&255;data[dst+2]=val>>16&255;data[dst+3]=isScreen?255:val>>24&255;src++;dst+=4}}else{var data32=new Uint32Array(data.buffer);if(isScreen&&SDL.defaults.opaqueFrontBuffer){num=data32.length;data32.set(HEAP32.subarray(src>>>0,src+num>>>0));var data8=new Uint8Array(data.buffer);var i=3;var j=i+4*num;if(num%8==0){while(i>>0,src+data32.length>>>0))}}}else{var canvas=Browser.getCanvas();var width=canvas.width;var height=canvas.height;var s=surfData.buffer;var data=surfData.image.data;var colors=surfData.colors;for(var y=0;y>>0]*4;var start=base+x*4;data[start]=colors[val];data[start+1]=colors[val+1];data[start+2]=colors[val+2]}s+=width*3}}surfData.ctx.putImageData(surfData.image,0,0)}_SDL_UnlockSurface.sig="vp";function _SDL_Flip(surf){surf>>>=0}_SDL_Flip.sig="ip";function _SDL_UpdateRect(surf,x,y,w,h){surf>>>=0}_SDL_UpdateRect.sig="vpiiii";function _SDL_UpdateRects(surf,numrects,rects){surf>>>=0;rects>>>=0}_SDL_UpdateRects.sig="vpip";var _SDL_Delay=delay=>{if(!ENVIRONMENT_IS_WORKER)abort("SDL_Delay called on the main thread! Potential infinite loop, quitting. (consider building with async support like ASYNCIFY)");var now=Date.now();while(Date.now()-now>>=0;icon>>>=0;if(title){_emscripten_set_window_title(title)}icon&&=UTF8ToString(icon)}_SDL_WM_SetCaption.sig="vpp";var _SDL_EnableKeyRepeat=(delay,interval)=>{};_SDL_EnableKeyRepeat.sig="iii";function _SDL_GetKeyboardState(numKeys){numKeys>>>=0;if(numKeys){HEAP32[numKeys>>>2>>>0]=65536}return SDL.keyboardState}_SDL_GetKeyboardState.sig="pp";var _SDL_GetKeyState=()=>_SDL_GetKeyboardState(0);function _SDL_GetKeyName(key){var name="";if(key>=97&&key<=122||key>=48&&key<=57){name=String.fromCharCode(key)}var size=lengthBytesUTF8(name)+1;SDL.keyName=_realloc(SDL.keyName,size);stringToUTF8(name,SDL.keyName,size);return SDL.keyName}_SDL_GetKeyName.sig="pi";var _SDL_GetModState=()=>SDL.modState;_SDL_GetModState.sig="i";function _SDL_GetMouseState(x,y){x>>>=0;y>>>=0;if(x)HEAP32[x>>>2>>>0]=Browser.mouseX;if(y)HEAP32[y>>>2>>>0]=Browser.mouseY;return SDL.buttonState}_SDL_GetMouseState.sig="ipp";var _SDL_WarpMouse=(x,y)=>{};_SDL_WarpMouse.sig="vii";var _SDL_ShowCursor=toggle=>{switch(toggle){case 0:if(Browser.isFullscreen){Browser.getCanvas().requestPointerLock();return 0}return 1;case 1:Browser.getCanvas().exitPointerLock();return 1;case-1:return!Browser.pointerLock;default:err(`SDL_ShowCursor called with unknown toggle parameter value: ${toggle}`);break}};_SDL_ShowCursor.sig="ii";function _SDL_GetError(){SDL.errorMessage||=stringToNewUTF8("unknown SDL-emscripten error");return SDL.errorMessage}_SDL_GetError.sig="p";function _SDL_SetError(fmt,varargs){fmt>>>=0;varargs>>>=0}_SDL_SetError.sig="vpp";function _SDL_CreateRGBSurface(flags,width,height,depth,rmask,gmask,bmask,amask){return SDL.makeSurface(width,height,flags,false,"CreateRGBSurface",rmask,gmask,bmask,amask)}_SDL_CreateRGBSurface.sig="piiiiiiii";function _SDL_CreateRGBSurfaceFrom(pixels,width,height,depth,pitch,rmask,gmask,bmask,amask){pixels>>>=0;var surf=SDL.makeSurface(width,height,0,false,"CreateRGBSurfaceFrom",rmask,gmask,bmask,amask);if(depth!==32){err("TODO: Partially unimplemented SDL_CreateRGBSurfaceFrom called!");return surf}var data=SDL.surfaces[surf];var image=data.ctx.createImageData(width,height);var pitchOfDst=width*4;for(var row=0;row>>0]}}data.ctx.putImageData(image,0,0);return surf}_SDL_CreateRGBSurfaceFrom.sig="ppiiiiiiii";function _SDL_ConvertSurface(surf,format,flags){surf>>>=0;format>>>=0;if(format){SDL.checkPixelFormat(format)}var oldData=SDL.surfaces[surf];var ret=SDL.makeSurface(oldData.width,oldData.height,oldData.flags,false,"copy:"+oldData.source);var newData=SDL.surfaces[ret];newData.ctx.globalCompositeOperation="copy";newData.ctx.drawImage(oldData.canvas,0,0);newData.ctx.globalCompositeOperation=oldData.ctx.globalCompositeOperation;return ret}_SDL_ConvertSurface.sig="pppi";function _SDL_DisplayFormat(surf){surf>>>=0;return _SDL_ConvertSurface(surf,0,0)}_SDL_DisplayFormat.sig="pp";function _SDL_DisplayFormatAlpha(surf){surf>>>=0;return _SDL_ConvertSurface(surf,0,0)}_SDL_DisplayFormatAlpha.sig="pp";function _SDL_FreeSurface(surf){surf>>>=0;if(surf)SDL.freeSurface(surf)}_SDL_FreeSurface.sig="vp";function _SDL_UpperBlit(src,srcrect,dst,dstrect){src>>>=0;srcrect>>>=0;dst>>>=0;dstrect>>>=0;return SDL.blitSurface(src,srcrect,dst,dstrect,false)}_SDL_UpperBlit.sig="ipppp";function _SDL_UpperBlitScaled(src,srcrect,dst,dstrect){src>>>=0;srcrect>>>=0;dst>>>=0;dstrect>>>=0;return SDL.blitSurface(src,srcrect,dst,dstrect,true)}_SDL_UpperBlitScaled.sig="ipppp";var _SDL_LowerBlit=_SDL_UpperBlit;_SDL_LowerBlit.sig="ipppp";var _SDL_LowerBlitScaled=_SDL_UpperBlitScaled;_SDL_LowerBlitScaled.sig="ipppp";function _SDL_GetClipRect(surf,rect){surf>>>=0;rect>>>=0;assert(rect);var surfData=SDL.surfaces[surf];var r=surfData.clipRect||{x:0,y:0,w:surfData.width,h:surfData.height};SDL.updateRect(rect,r)}_SDL_GetClipRect.sig="vpp";function _SDL_SetClipRect(surf,rect){surf>>>=0;rect>>>=0;var surfData=SDL.surfaces[surf];if(rect){surfData.clipRect=SDL.intersectionOfRects({x:0,y:0,w:surfData.width,h:surfData.height},SDL.loadRect(rect))}else{delete surfData.clipRect}}_SDL_SetClipRect.sig="ipp";function _SDL_FillRect(surf,rect,color){surf>>>=0;rect>>>=0;var surfData=SDL.surfaces[surf];assert(!surfData.locked);if(surfData.isFlagSet(2097152)){color=surfData.colors32[color]}var r=rect?SDL.loadRect(rect):{x:0,y:0,w:surfData.width,h:surfData.height};if(surfData.clipRect){r=SDL.intersectionOfRects(surfData.clipRect,r);if(rect){SDL.updateRect(rect,r)}}surfData.ctx.save();surfData.ctx.fillStyle=SDL.translateColorToCSSRGBA(color);surfData.ctx.fillRect(r.x,r.y,r.w,r.h);surfData.ctx.restore();return 0}_SDL_FillRect.sig="ippi";function _zoomSurface(src,x,y,smooth){src>>>=0;var srcData=SDL.surfaces[src];var w=srcData.width*x;var h=srcData.height*y;var ret=SDL.makeSurface(Math.abs(w),Math.abs(h),srcData.flags,false,"zoomSurface");var dstData=SDL.surfaces[ret];if(x>=0&&y>=0){dstData.ctx.drawImage(srcData.canvas,0,0,w,h)}else{dstData.ctx.save();dstData.ctx.scale(x<0?-1:1,y<0?-1:1);dstData.ctx.drawImage(srcData.canvas,w<0?w:0,h<0?h:0,Math.abs(w),Math.abs(h));dstData.ctx.restore()}return ret}_zoomSurface.sig="ppddi";function _rotozoomSurface(src,angle,zoom,smooth){src>>>=0;if(angle%360===0){return _zoomSurface(src,zoom,zoom,smooth)}var srcData=SDL.surfaces[src];var w=srcData.width*zoom;var h=srcData.height*zoom;var diagonal=Math.ceil(Math.sqrt(Math.pow(w,2)+Math.pow(h,2)));var ret=SDL.makeSurface(diagonal,diagonal,srcData.flags,false,"rotozoomSurface");var dstData=SDL.surfaces[ret];dstData.ctx.translate(diagonal/2,diagonal/2);dstData.ctx.rotate(-angle*Math.PI/180);dstData.ctx.drawImage(srcData.canvas,-w/2,-h/2,w,h);return ret}_rotozoomSurface.sig="ppddi";function _SDL_SetAlpha(surf,flag,alpha){surf>>>=0;var surfData=SDL.surfaces[surf];surfData.alpha=alpha;if(!(flag&65536)){surfData.alpha=255}}_SDL_SetAlpha.sig="ipii";function _SDL_SetColorKey(surf,flag,key){surf>>>=0;warnOnce("SDL_SetColorKey is a no-op for performance reasons");return 0}_SDL_SetColorKey.sig="ipii";function _SDL_PollEvent(ptr){ptr>>>=0;return SDL.pollEvent(ptr)}_SDL_PollEvent.sig="ip";function _SDL_PushEvent(ptr){ptr>>>=0;var copy=_malloc(28);_memcpy(copy,ptr,28);SDL.events.push(copy);return 0}_SDL_PushEvent.sig="ip";function _SDL_PeepEvents(events,requestedEventCount,action,from,to){events>>>=0;switch(action){case 2:{assert(requestedEventCount==1);var index=0;var retrievedEventCount=0;while(indexSDL.events.forEach(SDL.handleEvent);_SDL_PumpEvents.sig="v";function _emscripten_SDL_SetEventHandler(handler,userdata){handler>>>=0;userdata>>>=0;SDL.eventHandler=handler;SDL.eventHandlerContext=userdata;SDL.eventHandlerTemp||=_malloc(28)}_emscripten_SDL_SetEventHandler.sig="vpp";function _SDL_SetColors(surf,colors,firstColor,nColors){surf>>>=0;colors>>>=0;var surfData=SDL.surfaces[surf];if(!surfData.colors){var buffer=new ArrayBuffer(256*4);surfData.colors=new Uint8Array(buffer);surfData.colors32=new Uint32Array(buffer)}for(var i=0;i>>0];surfData.colors[index+1]=HEAPU8[colors+(i*4+1)>>>0];surfData.colors[index+2]=HEAPU8[colors+(i*4+2)>>>0];surfData.colors[index+3]=255}return 1}_SDL_SetColors.sig="ippii";function _SDL_SetPalette(surf,flags,colors,firstColor,nColors){surf>>>=0;colors>>>=0;return _SDL_SetColors(surf,colors,firstColor,nColors)}_SDL_SetPalette.sig="ipipii";function _SDL_MapRGB(fmt,r,g,b){fmt>>>=0;SDL.checkPixelFormat(fmt);return r&255|(g&255)<<8|(b&255)<<16|4278190080}_SDL_MapRGB.sig="ipiii";function _SDL_MapRGBA(fmt,r,g,b,a){fmt>>>=0;SDL.checkPixelFormat(fmt);return r&255|(g&255)<<8|(b&255)<<16|(a&255)<<24}_SDL_MapRGBA.sig="ipiiii";function _SDL_GetRGB(pixel,fmt,r,g,b){fmt>>>=0;r>>>=0;g>>>=0;b>>>=0;SDL.checkPixelFormat(fmt);if(r){HEAP8[r>>>0]=pixel&255}if(g){HEAP8[g>>>0]=pixel>>8&255}if(b){HEAP8[b>>>0]=pixel>>16&255}}_SDL_GetRGB.sig="vipppp";function _SDL_GetRGBA(pixel,fmt,r,g,b,a){fmt>>>=0;r>>>=0;g>>>=0;b>>>=0;a>>>=0;SDL.checkPixelFormat(fmt);if(r){HEAP8[r>>>0]=pixel&255}if(g){HEAP8[g>>>0]=pixel>>8&255}if(b){HEAP8[b>>>0]=pixel>>16&255}if(a){HEAP8[a>>>0]=pixel>>24&255}}_SDL_GetRGBA.sig="vippppp";var _SDL_GetAppState=()=>{var state=0;if(Browser.pointerLock){state|=1}if(document.hasFocus()){state|=2}state|=4;return state};_SDL_GetAppState.sig="i";var _SDL_WM_GrabInput=()=>{};_SDL_WM_GrabInput.sig="ii";function _SDL_WM_ToggleFullScreen(surf){surf>>>=0;if(Browser.exitFullscreen()){return 1}if(!SDL.canRequestFullscreen){return 0}SDL.isRequestingFullscreen=true;return 1}_SDL_WM_ToggleFullScreen.sig="ip";var _IMG_Init=flags=>flags;_IMG_Init.sig="ii";function _SDL_FreeRW(rwopsID){rwopsID>>>=0;SDL.rwops[rwopsID]=null;while(SDL.rwops.length>0&&SDL.rwops[SDL.rwops.length-1]===null){SDL.rwops.pop()}}_SDL_FreeRW.sig="vp";var _IMG_Load_RW=function(rwopsID,freeSrc){rwopsID>>>=0;var sp=stackSave();try{var cleanup=()=>{stackRestore(sp);if(rwops&&freeSrc)_SDL_FreeRW(rwopsID)};var addCleanup=func=>{var old=cleanup;cleanup=()=>{old();func()}};var callStbImage=(func,params)=>{var x=stackAlloc(4);var y=stackAlloc(4);var comp=stackAlloc(4);var data=Module["_"+func](...params,x,y,comp,0);if(!data)return null;addCleanup(()=>Module["_stbi_image_free"](data));return{rawData:true,data,width:HEAP32[x>>>2>>>0],height:HEAP32[y>>>2>>>0],size:HEAP32[x>>>2>>>0]*HEAP32[y>>>2>>>0]*HEAP32[comp>>>2>>>0],bpp:HEAP32[comp>>>2>>>0]}};var rwops=SDL.rwops[rwopsID];if(rwops===undefined){return 0}var raw;var filename=rwops.filename;if(filename===undefined){warnOnce("Only file names that have been preloaded are supported for IMG_Load_RW. Consider using STB_IMAGE=1 if you want synchronous image decoding (see settings.js), or package files with --use-preload-plugins");return 0}if(!raw){filename=PATH_FS.resolve(filename);raw=Browser.preloadedImages[filename];if(!raw){if(raw===null)err("Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!");warnOnce("Cannot find preloaded image "+filename);warnOnce("Cannot find preloaded image "+filename+". Consider using STB_IMAGE=1 if you want synchronous image decoding (see settings.js), or package files with --use-preload-plugins");return 0}else if(Module["freePreloadedMediaOnUse"]){Browser.preloadedImages[filename]=null}}var surf=SDL.makeSurface(raw.width,raw.height,0,false,"load:"+filename);var surfData=SDL.surfaces[surf];surfData.ctx.globalCompositeOperation="copy";if(!raw.rawData){surfData.ctx.drawImage(raw,0,0,raw.width,raw.height,0,0,raw.width,raw.height)}else{var imageData=surfData.ctx.getImageData(0,0,surfData.width,surfData.height);if(raw.bpp==4){imageData.data.set(HEAPU8.subarray(raw.data>>>0,raw.data+raw.size>>>0))}else if(raw.bpp==3){var pixels=raw.size/3;var data=imageData.data;var sourcePtr=raw.data;var destPtr=0;for(var i=0;i>>0];data[destPtr++]=HEAPU8[sourcePtr++>>>0];data[destPtr++]=HEAPU8[sourcePtr++>>>0];data[destPtr++]=255}}else if(raw.bpp==2){var pixels=raw.size;var data=imageData.data;var sourcePtr=raw.data;var destPtr=0;for(var i=0;i>>0];var alpha=HEAPU8[sourcePtr++>>>0];data[destPtr++]=gray;data[destPtr++]=gray;data[destPtr++]=gray;data[destPtr++]=alpha}}else if(raw.bpp==1){var pixels=raw.size;var data=imageData.data;var sourcePtr=raw.data;var destPtr=0;for(var i=0;i>>0];data[destPtr++]=value;data[destPtr++]=value;data[destPtr++]=value;data[destPtr++]=255}}else{err(`cannot handle bpp ${raw.bpp}`);return 0}surfData.ctx.putImageData(imageData,0,0)}surfData.ctx.globalCompositeOperation="source-over";_SDL_LockSurface(surf);surfData.locked--;if(SDL.GL){surfData.canvas=surfData.ctx=null}return surf}finally{cleanup()}};_IMG_Load_RW.sig="ppi";var _SDL_LoadBMP_RW=_IMG_Load_RW;_SDL_LoadBMP_RW.sig="ppi";function _SDL_RWFromFile(_name,mode){_name>>>=0;mode>>>=0;var id=SDL.rwops.length;var filename=UTF8ToString(_name);SDL.rwops.push({filename,mimetype:Browser.getMimetype(filename)});return id}_SDL_RWFromFile.sig="ppp";function _IMG_Load(filename){filename>>>=0;var rwops=_SDL_RWFromFile(filename,0);var result=_IMG_Load_RW(rwops,1);return result}_IMG_Load.sig="pp";var _IMG_Quit=()=>out("IMG_Quit called (and ignored)");_IMG_Quit.sig="v";function _SDL_OpenAudio(desired,obtained){desired>>>=0;obtained>>>=0;try{SDL.audio={freq:HEAPU32[desired>>>2>>>0],format:HEAPU16[desired+4>>>1>>>0],channels:HEAPU8[desired+6>>>0],samples:HEAPU16[desired+8>>>1>>>0],callback:HEAPU32[desired+16>>>2>>>0],userdata:HEAPU32[desired+20>>>2>>>0],paused:true,timer:null};if(SDL.audio.format==8){SDL.audio.silence=128}else if(SDL.audio.format==32784){SDL.audio.silence=0}else if(SDL.audio.format==33056){SDL.audio.silence=0}else{throw"Invalid SDL audio format "+SDL.audio.format+"!"}if(SDL.audio.freq<=0){throw"Unsupported sound frequency "+SDL.audio.freq+"!"}else if(SDL.audio.freq<=22050){SDL.audio.freq=22050}else if(SDL.audio.freq<=32e3){SDL.audio.freq=32e3}else if(SDL.audio.freq<=44100){SDL.audio.freq=44100}else if(SDL.audio.freq<=48e3){SDL.audio.freq=48e3}else if(SDL.audio.freq<=96e3){SDL.audio.freq=96e3}else{throw`Unsupported sound frequency ${SDL.audio.freq}!`}if(SDL.audio.channels==0){SDL.audio.channels=1}else if(SDL.audio.channels<0||SDL.audio.channels>32){throw`Unsupported number of audio channels for SDL audio: ${SDL.audio.channels}!`}else if(SDL.audio.channels!=1&&SDL.audio.channels!=2){out(`Warning: Using untested number of audio channels ${SDL.audio.channels}`)}if(SDL.audio.samples<128||SDL.audio.samples>524288){throw`Unsupported audio callback buffer size ${SDL.audio.samples}!`}else if((SDL.audio.samples&SDL.audio.samples-1)!=0){throw`Audio callback buffer size ${SDL.audio.samples} must be a power-of-two!`}var totalSamples=SDL.audio.samples*SDL.audio.channels;if(SDL.audio.format==8){SDL.audio.bytesPerSample=1}else if(SDL.audio.format==32784){SDL.audio.bytesPerSample=2}else if(SDL.audio.format==33056){SDL.audio.bytesPerSample=4}else{throw`Invalid SDL audio format ${SDL.audio.format}!`}SDL.audio.bufferSize=totalSamples*SDL.audio.bytesPerSample;SDL.audio.bufferDurationSecs=SDL.audio.bufferSize/SDL.audio.bytesPerSample/SDL.audio.channels/SDL.audio.freq;SDL.audio.bufferingDelay=50/1e3;SDL.audio.buffer=_malloc(SDL.audio.bufferSize);SDL.audio.numSimultaneouslyQueuedBuffers=Module["SDL_numSimultaneouslyQueuedBuffers"]||5;SDL.audio.queueNewAudioData=()=>{if(!SDL.audio)return;for(var i=0;i=SDL.audio.bufferingDelay+SDL.audio.bufferDurationSecs*SDL.audio.numSimultaneouslyQueuedBuffers)return;getWasmTableEntry(SDL.audio.callback)(SDL.audio.userdata,SDL.audio.buffer,SDL.audio.bufferSize);SDL.audio.pushAudio(SDL.audio.buffer,SDL.audio.bufferSize)}};SDL.audio.caller=()=>{if(!SDL.audio)return;--SDL.audio.numAudioTimersPending;SDL.audio.queueNewAudioData();var secsUntilNextPlayStart=SDL.audio.nextPlayTime-SDL.audioContext["currentTime"];var preemptBufferFeedSecs=SDL.audio.bufferDurationSecs/2;if(SDL.audio.numAudioTimersPending{try{if(SDL.audio.paused)return;var sizeSamples=sizeBytes/SDL.audio.bytesPerSample;var sizeSamplesPerChannel=sizeSamples/SDL.audio.channels;if(sizeSamplesPerChannel!=SDL.audio.samples){throw"Received mismatching audio buffer size!"}var source=SDL.audioContext["createBufferSource"]();var soundBuffer=SDL.audioContext["createBuffer"](SDL.audio.channels,sizeSamplesPerChannel,SDL.audio.freq);source["connect"](SDL.audioContext["destination"]);SDL.fillWebAudioBufferFromHeap(ptr,sizeSamplesPerChannel,soundBuffer);source["buffer"]=soundBuffer;var curtime=SDL.audioContext["currentTime"];var playtime=Math.max(curtime+SDL.audio.bufferingDelay,SDL.audio.nextPlayTime);if(typeof source["start"]!="undefined"){source["start"](playtime)}else if(typeof source["noteOn"]!="undefined"){source["noteOn"](playtime)}SDL.audio.nextPlayTime=playtime+SDL.audio.bufferDurationSecs}catch(e){err(`Web Audio API error playing back audio: ${e.toString()}`)}};if(obtained){HEAP32[obtained>>>2>>>0]=SDL.audio.freq;HEAP16[obtained+4>>>1>>>0]=SDL.audio.format;HEAP8[obtained+6>>>0]=SDL.audio.channels;HEAP8[obtained+7>>>0]=SDL.audio.silence;HEAP16[obtained+8>>>1>>>0]=SDL.audio.samples;HEAPU32[obtained+16>>>2>>>0]=SDL.audio.callback;HEAPU32[obtained+20>>>2>>>0]=SDL.audio.userdata}SDL.allocateChannels(32)}catch(e){err(`Initializing SDL audio threw an exception: "${e.toString()}"! Continuing without audio`);SDL.audio=null;SDL.allocateChannels(0);if(obtained){HEAP32[obtained>>>2>>>0]=0;HEAP16[obtained+4>>>1>>>0]=0;HEAP8[obtained+6>>>0]=0;HEAP8[obtained+7>>>0]=0;HEAP16[obtained+8>>>1>>>0]=0;HEAPU32[obtained+16>>>2>>>0]=0;HEAPU32[obtained+20>>>2>>>0]=0}}if(!SDL.audio){return-1}return 0}_SDL_OpenAudio.sig="ipp";var _SDL_PauseAudio=pauseOn=>{if(!SDL.audio){return}if(pauseOn){if(SDL.audio.timer!==undefined){clearTimeout(SDL.audio.timer);SDL.audio.numAudioTimersPending=0;SDL.audio.timer=undefined}}else if(!SDL.audio.timer){SDL.audio.numAudioTimersPending=1;SDL.audio.timer=safeSetTimeout(SDL.audio.caller,1)}SDL.audio.paused=pauseOn};_SDL_PauseAudio.sig="vi";var _SDL_CloseAudio=()=>{if(SDL.audio){if(SDL.audio.callbackRemover){SDL.audio.callbackRemover();SDL.audio.callbackRemover=null}_SDL_PauseAudio(1);_free(SDL.audio.buffer);SDL.audio=null;SDL.allocateChannels(0)}};_SDL_CloseAudio.sig="v";var _SDL_LockAudio=()=>{};_SDL_LockAudio.sig="v";var _SDL_UnlockAudio=()=>{};_SDL_UnlockAudio.sig="v";function _SDL_CreateMutex(){return 0}_SDL_CreateMutex.sig="p";function _SDL_mutexP(mutex){mutex>>>=0;return 0}_SDL_mutexP.sig="ip";function _SDL_mutexV(mutex){mutex>>>=0;return 0}_SDL_mutexV.sig="ip";function _SDL_DestroyMutex(mutex){mutex>>>=0}_SDL_DestroyMutex.sig="vp";function _SDL_CreateCond(){return 0}_SDL_CreateCond.sig="p";function _SDL_CondSignal(cond){cond>>>=0}_SDL_CondSignal.sig="ip";function _SDL_CondWait(cond,mutex){cond>>>=0;mutex>>>=0}_SDL_CondWait.sig="ipp";function _SDL_DestroyCond(cond){cond>>>=0}_SDL_DestroyCond.sig="vp";var _SDL_StartTextInput=()=>{SDL.textInput=true};_SDL_StartTextInput.sig="v";var _SDL_StopTextInput=()=>{SDL.textInput=false};_SDL_StopTextInput.sig="v";var _Mix_Init=flags=>{if(!flags)return 0;return 8};_Mix_Init.sig="ii";var _Mix_Quit=()=>{};_Mix_Quit.sig="v";var _Mix_OpenAudio=(frequency,format,channels,chunksize)=>{SDL.openAudioContext();autoResumeAudioContext(SDL.audioContext);SDL.allocateChannels(32);SDL.mixerFrequency=frequency;SDL.mixerFormat=format;SDL.mixerNumChannels=channels;SDL.mixerChunkSize=chunksize;return 0};_Mix_OpenAudio.sig="iiiii";var _Mix_CloseAudio=_SDL_CloseAudio;_Mix_CloseAudio.sig="v";var _Mix_AllocateChannels=num=>{SDL.allocateChannels(num);return num};_Mix_AllocateChannels.sig="ii";function _Mix_ChannelFinished(func){func>>>=0;SDL.channelFinished=func}_Mix_ChannelFinished.sig="vp";var _Mix_Volume=(channel,volume)=>{if(channel==-1){for(var i=0;i{left/=255;right/=255;SDL.setPannerPosition(SDL.channels[channel],right-left,0,.1);return 1};_Mix_SetPanning.sig="iiii";function _Mix_LoadWAV_RW(rwopsID,freesrc){rwopsID>>>=0;var rwops=SDL.rwops[rwopsID];if(rwops===undefined)return 0;var filename="";var audio;var webAudio;var bytes;if(rwops.filename!==undefined){filename=PATH_FS.resolve(rwops.filename);var raw=Browser.preloadedAudios[filename];if(!raw){if(raw===null)err("Trying to reuse preloaded audio, but freePreloadedMediaOnUse is set!");if(!Module["noAudioDecoding"])warnOnce("Cannot find preloaded audio "+filename);try{bytes=FS.readFile(filename)}catch(e){err(`Couldn't find file for: ${filename}`);return 0}}if(Module["freePreloadedMediaOnUse"]){Browser.preloadedAudios[filename]=null}audio=raw}else if(rwops.bytes!==undefined){if(SDL.webAudioAvailable()){bytes=HEAPU8.buffer.slice(rwops.bytes,rwops.bytes+rwops.count)}else{bytes=HEAPU8.subarray(rwops.bytes>>>0,rwops.bytes+rwops.count>>>0)}}else{return 0}var arrayBuffer=bytes?bytes.buffer||bytes:bytes;var canPlayWithWebAudio=Module["SDL_canPlayWithWebAudio"]===undefined||Module["SDL_canPlayWithWebAudio"](filename,arrayBuffer);if(bytes!==undefined&&SDL.webAudioAvailable()&&canPlayWithWebAudio){audio=undefined;webAudio={onDecodeComplete:[]};SDL.audioContext["decodeAudioData"](arrayBuffer,data=>{webAudio.decodedBuffer=data;webAudio.onDecodeComplete.forEach(e=>e());delete webAudio.onDecodeComplete})}else if(audio===undefined&&bytes){var blob=new Blob([bytes],{type:rwops.mimetype});var url=URL.createObjectURL(blob);audio=new Audio;audio.src=url;audio.mozAudioChannelType="content"}var id=SDL.audios.length;SDL.audios.push({source:filename,audio,webAudio});return id}_Mix_LoadWAV_RW.sig="ppi";function _Mix_LoadWAV(filename){filename>>>=0;var rwops=_SDL_RWFromFile(filename,0);var result=_Mix_LoadWAV_RW(rwops,0);_SDL_FreeRW(rwops);return result}_Mix_LoadWAV.sig="pp";function _Mix_QuickLoad_RAW(mem,len){mem>>>=0;var audio;var webAudio;var numSamples=len>>1;var buffer=new Float32Array(numSamples);for(var i=0;i>>1>>>0]/32768}if(SDL.webAudioAvailable()){webAudio={decodedBuffer:buffer}}else{audio=new Audio;audio.mozAudioChannelType="content";audio.numChannels=SDL.mixerNumChannels;audio.frequency=SDL.mixerFrequency}var id=SDL.audios.length;SDL.audios.push({source:"",audio,webAudio,buffer});return id}_Mix_QuickLoad_RAW.sig="ppi";function _Mix_FreeChunk(id){id>>>=0;SDL.audios[id]=null}_Mix_FreeChunk.sig="vp";var _Mix_ReserveChannels=num=>{SDL.channelMinimumNumber=num};_Mix_ReserveChannels.sig="ii";var _Mix_HaltChannel=channel=>{function halt(channel){var info=SDL.channels[channel];if(info.audio){info.audio.pause();info.audio=null}if(SDL.channelFinished){getWasmTableEntry(SDL.channelFinished)(channel)}}if(channel!=-1){halt(channel)}else{for(var i=0;i>>=0;assert(ticks==-1);var info=SDL.audios[id];if(!info)return-1;if(!info.audio&&!info.webAudio)return-1;if(channel==-1){for(var i=SDL.channelMinimumNumber;i0;_Mix_FadingChannel.sig="ii";var _Mix_HaltMusic=()=>{var audio=SDL.music.audio;if(audio){audio.src=audio.src;audio.currentPosition=0;audio.pause()}SDL.music.audio=null;if(SDL.hookMusicFinished){getWasmTableEntry(SDL.hookMusicFinished)()}return 0};_Mix_HaltMusic.sig="i";function _Mix_HookMusicFinished(func){func>>>=0;SDL.hookMusicFinished=func;if(SDL.music.audio){SDL.music.audio["onended"]=_Mix_HaltMusic}}_Mix_HookMusicFinished.sig="vp";var _Mix_VolumeMusic=volume=>SDL.setGetVolume(SDL.music,volume);_Mix_VolumeMusic.sig="ii";function _Mix_LoadMUS_RW(filename){filename>>>=0;return _Mix_LoadWAV_RW(filename,0)}_Mix_LoadMUS_RW.sig="pp";function _Mix_LoadMUS(filename){filename>>>=0;var rwops=_SDL_RWFromFile(filename,0);var result=_Mix_LoadMUS_RW(rwops);_SDL_FreeRW(rwops);return result}_Mix_LoadMUS.sig="pp";var _Mix_FreeMusic=_Mix_FreeChunk;_Mix_FreeMusic.sig="vp";function _Mix_PlayMusic(id,loops){id>>>=0;if(SDL.music.audio){if(!SDL.music.audio.paused)err(`Music is already playing. ${SDL.music.source}`);SDL.music.audio.pause()}var info=SDL.audios[id];var audio;if(info.webAudio){audio={resource:info,paused:false,currentPosition:0,play(){SDL.playWebAudio(this)},pause(){SDL.pauseWebAudio(this)}}}else if(info.audio){audio=info.audio}audio["onended"]=function(){if(SDL.music.audio===this||SDL.music.audio?.webAudioNode===this){_Mix_HaltMusic()}};audio.loop=loops!=0&&loops!=1;audio.volume=SDL.music.volume;SDL.music.audio=audio;audio.play();return 0}_Mix_PlayMusic.sig="ipi";var _Mix_PauseMusic=()=>{var audio=SDL.music.audio;audio?.pause()};_Mix_PauseMusic.sig="v";var _Mix_ResumeMusic=()=>{var audio=SDL.music.audio;audio?.play()};_Mix_ResumeMusic.sig="v";var _Mix_FadeInMusicPos=_Mix_PlayMusic;_Mix_FadeInMusicPos.sig="ipiid";var _Mix_FadeOutMusic=_Mix_HaltMusic;_Mix_FadeOutMusic.sig="ii";var _Mix_PlayingMusic=()=>SDL.music.audio&&!SDL.music.audio.paused;_Mix_PlayingMusic.sig="i";var _Mix_Playing=channel=>{if(channel===-1){var count=0;for(var i=0;i{if(channel===-1){for(var i=0;i{if(channel===-1){var pausedCount=0;for(var i=0;iSDL.music.audio?.paused?1:0;_Mix_PausedMusic.sig="i";var _Mix_Resume=channel=>{if(channel===-1){for(var i=0;i{try{var offscreenCanvas=new OffscreenCanvas(0,0);SDL.ttfContext=offscreenCanvas.getContext("2d");if(typeof SDL.ttfContext.measureText!="function"){throw"bad context"}}catch(ex){var canvas=document.createElement("canvas");SDL.ttfContext=canvas.getContext("2d")}return 0};_TTF_Init.sig="i";function _TTF_OpenFont(name,size){name>>>=0;name=PATH.normalize(UTF8ToString(name));var id=SDL.fonts.length;SDL.fonts.push({name,size});return id}_TTF_OpenFont.sig="ppi";function _TTF_CloseFont(font){font>>>=0;SDL.fonts[font]=null}_TTF_CloseFont.sig="vp";function _TTF_RenderText_Solid(font,text,color){font>>>=0;text>>>=0;color>>>=0;text=UTF8ToString(text)||" ";var fontData=SDL.fonts[font];var w=SDL.estimateTextWidth(fontData,text);var h=fontData.size;color=SDL.loadColorToCSSRGB(color);var fontString=SDL.makeFontString(h,fontData.name);var surf=SDL.makeSurface(w,h,0,false,"text:"+text);var surfData=SDL.surfaces[surf];surfData.ctx.save();surfData.ctx.fillStyle=color;surfData.ctx.font=fontString;surfData.ctx.textBaseline="bottom";surfData.ctx.fillText(text,0,h|0);surfData.ctx.restore();return surf}_TTF_RenderText_Solid.sig="pppp";var _TTF_RenderText_Blended=_TTF_RenderText_Solid;_TTF_RenderText_Blended.sig="pppp";var _TTF_RenderText_Shaded=_TTF_RenderText_Solid;_TTF_RenderText_Shaded.sig="ppppp";var _TTF_RenderUTF8_Solid=_TTF_RenderText_Solid;_TTF_RenderUTF8_Solid.sig="pppp";function _TTF_SizeText(font,text,w,h){font>>>=0;text>>>=0;w>>>=0;h>>>=0;var fontData=SDL.fonts[font];if(w){HEAP32[w>>>2>>>0]=SDL.estimateTextWidth(fontData,UTF8ToString(text))}if(h){HEAP32[h>>>2>>>0]=fontData.size}return 0}_TTF_SizeText.sig="ipppp";var _TTF_SizeUTF8=_TTF_SizeText;_TTF_SizeUTF8.sig="ipppp";function _TTF_GlyphMetrics(font,ch,minx,maxx,miny,maxy,advance){font>>>=0;minx>>>=0;maxx>>>=0;miny>>>=0;maxy>>>=0;advance>>>=0;var fontData=SDL.fonts[font];var width=SDL.estimateTextWidth(fontData,String.fromCharCode(ch));if(advance){HEAP32[advance>>>2>>>0]=width}if(minx){HEAP32[minx>>>2>>>0]=0}if(maxx){HEAP32[maxx>>>2>>>0]=width}if(miny){HEAP32[miny>>>2>>>0]=0}if(maxy){HEAP32[maxy>>>2>>>0]=fontData.size}}_TTF_GlyphMetrics.sig="ipippppp";function _TTF_FontAscent(font){font>>>=0;var fontData=SDL.fonts[font];return fontData.size*.98|0}_TTF_FontAscent.sig="ip";function _TTF_FontDescent(font){font>>>=0;var fontData=SDL.fonts[font];return fontData.size*.02|0}_TTF_FontDescent.sig="ip";function _TTF_FontHeight(font){font>>>=0;var fontData=SDL.fonts[font];return fontData.size}_TTF_FontHeight.sig="ip";var _TTF_FontLineSkip=_TTF_FontHeight;_TTF_FontLineSkip.sig="ip";var _TTF_Quit=()=>out("TTF_Quit called (and ignored)");_TTF_Quit.sig="v";var SDL_gfx={drawRectangle:(surf,x1,y1,x2,y2,action,cssColor)=>{x1=x1<<16>>16;y1=y1<<16>>16;x2=x2<<16>>16;y2=y2<<16>>16;var surfData=SDL.surfaces[surf];assert(!surfData.locked);var x=x1{x1=x1<<16>>16;y1=y1<<16>>16;x2=x2<<16>>16;y2=y2<<16>>16;var surfData=SDL.surfaces[surf];assert(!surfData.locked);surfData.ctx.save();surfData.ctx.strokeStyle=cssColor;surfData.ctx.beginPath();surfData.ctx.moveTo(x1,y1);surfData.ctx.lineTo(x2,y2);surfData.ctx.stroke();surfData.ctx.restore()},drawEllipse:(surf,x,y,rx,ry,action,cssColor)=>{x=x<<16>>16;y=y<<16>>16;rx=rx<<16>>16;ry=ry<<16>>16;var surfData=SDL.surfaces[surf];assert(!surfData.locked);surfData.ctx.save();surfData.ctx.beginPath();surfData.ctx.translate(x,y);surfData.ctx.scale(rx,ry);surfData.ctx.arc(0,0,1,0,2*Math.PI);surfData.ctx.restore();surfData.ctx.save();surfData.ctx[action+"Style"]=cssColor;surfData.ctx[action]();surfData.ctx.restore()},translateColorToCSSRGBA:rgba=>`rgba(${rgba>>>24},${rgba>>16&255},${rgba>>8&255},${rgba&255})`};function _boxColor(surf,x1,y1,x2,y2,color){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"fill",SDL_gfx.translateColorToCSSRGBA(color))}_boxColor.sig="ipiiiii";function _boxRGBA(surf,x1,y1,x2,y2,r,g,b,a){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"fill",SDL.translateRGBAToCSSRGBA(r,g,b,a))}_boxRGBA.sig="ipiiiiiiii";function _rectangleColor(surf,x1,y1,x2,y2,color){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"stroke",SDL_gfx.translateColorToCSSRGBA(color))}_rectangleColor.sig="ipiiiii";function _rectangleRGBA(surf,x1,y1,x2,y2,r,g,b,a){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"stroke",SDL.translateRGBAToCSSRGBA(r,g,b,a))}_rectangleRGBA.sig="ipiiiiiiii";function _ellipseColor(surf,x,y,rx,ry,color){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"stroke",SDL_gfx.translateColorToCSSRGBA(color))}_ellipseColor.sig="ipiiiii";function _ellipseRGBA(surf,x,y,rx,ry,r,g,b,a){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"stroke",SDL.translateRGBAToCSSRGBA(r,g,b,a))}_ellipseRGBA.sig="ipiiiiiiii";function _filledEllipseColor(surf,x,y,rx,ry,color){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"fill",SDL_gfx.translateColorToCSSRGBA(color))}_filledEllipseColor.sig="ipiiiii";function _filledEllipseRGBA(surf,x,y,rx,ry,r,g,b,a){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"fill",SDL.translateRGBAToCSSRGBA(r,g,b,a))}_filledEllipseRGBA.sig="ipiiiiiiii";function _lineColor(surf,x1,y1,x2,y2,color){surf>>>=0;return SDL_gfx.drawLine(surf,x1,y1,x2,y2,SDL_gfx.translateColorToCSSRGBA(color))}_lineColor.sig="ipiiiii";function _lineRGBA(surf,x1,y1,x2,y2,r,g,b,a){surf>>>=0;return SDL_gfx.drawLine(surf,x1,y1,x2,y2,SDL.translateRGBAToCSSRGBA(r,g,b,a))}_lineRGBA.sig="ipiiiiiiii";function _pixelRGBA(surf,x1,y1,r,g,b,a){surf>>>=0;return _boxRGBA(surf,x1,y1,x1,y1,r,g,b,a)}_pixelRGBA.sig="ipiiiiii";var _SDL_GL_SetAttribute=(attr,value)=>{if(!(attr in SDL.glAttributes)){abort("Unknown SDL GL attribute ("+attr+"). Please check if your SDL version is supported.")}SDL.glAttributes[attr]=value};_SDL_GL_SetAttribute.sig="iii";function _SDL_GL_GetAttribute(attr,value){value>>>=0;if(!(attr in SDL.glAttributes)){abort("Unknown SDL GL attribute ("+attr+"). Please check if your SDL version is supported.")}if(value)HEAP32[value>>>2>>>0]=SDL.glAttributes[attr];return 0}_SDL_GL_GetAttribute.sig="iip";var _SDL_GL_SwapBuffers=()=>Browser.doSwapBuffers?.();_SDL_GL_SwapBuffers.sig="v";function _SDL_GL_ExtensionSupported(extension){extension>>>=0;return GLctx?.getExtension(UTF8ToString(extension))?1:0}_SDL_GL_ExtensionSupported.sig="ip";function _SDL_DestroyWindow(window){window>>>=0}_SDL_DestroyWindow.sig="vp";function _SDL_DestroyRenderer(renderer){renderer>>>=0}_SDL_DestroyRenderer.sig="vp";function _SDL_GetWindowFlags(window){window>>>=0;if(Browser.isFullscreen){return 1}return 0}_SDL_GetWindowFlags.sig="ip";function _SDL_GL_SwapWindow(window){window>>>=0}_SDL_GL_SwapWindow.sig="vp";function _SDL_GL_MakeCurrent(window,context){window>>>=0;context>>>=0}_SDL_GL_MakeCurrent.sig="ipp";function _SDL_GL_DeleteContext(context){context>>>=0}_SDL_GL_DeleteContext.sig="vp";var _SDL_GL_GetSwapInterval=()=>{if(MainLoop.timingMode==1){return MainLoop.timingValue}else{return 0}};_SDL_GL_GetSwapInterval.sig="i";var _SDL_GL_SetSwapInterval=state=>_emscripten_set_main_loop_timing(1,state);_SDL_GL_SetSwapInterval.sig="ii";function _SDL_SetWindowTitle(window,title){window>>>=0;title>>>=0;if(title)document.title=UTF8ToString(title)}_SDL_SetWindowTitle.sig="vpp";function _SDL_GetWindowSize(window,width,height){window>>>=0;width>>>=0;height>>>=0;var canvas=Browser.getCanvas();if(width)HEAP32[width>>>2>>>0]=canvas.width;if(height)HEAP32[height>>>2>>>0]=canvas.height}_SDL_GetWindowSize.sig="vppp";function _SDL_LogSetOutputFunction(callback,userdata){callback>>>=0;userdata>>>=0}_SDL_LogSetOutputFunction.sig="vpp";function _SDL_SetWindowFullscreen(window,fullscreen){window>>>=0;if(Browser.isFullscreen){Browser.getCanvas().exitFullscreen();return 1}return 0}_SDL_SetWindowFullscreen.sig="ipi";var _SDL_ClearError=()=>{};_SDL_ClearError.sig="v";var _SDL_SetGamma=(r,g,b)=>-1;_SDL_SetGamma.sig="ifff";function _SDL_SetGammaRamp(redTable,greenTable,blueTable){redTable>>>=0;greenTable>>>=0;blueTable>>>=0;return-1}_SDL_SetGammaRamp.sig="ippp";var _SDL_NumJoysticks=()=>{var count=0;var gamepads=SDL.getGamepads();for(var gamepad of gamepads){if(gamepad!==undefined)count++}return count};_SDL_NumJoysticks.sig="i";function _SDL_JoystickName(deviceIndex){var gamepad=SDL.getGamepad(deviceIndex);if(gamepad){var name=gamepad.id;if(SDL.joystickNamePool.hasOwnProperty(name)){return SDL.joystickNamePool[name]}return SDL.joystickNamePool[name]=stringToNewUTF8(name)}return 0}_SDL_JoystickName.sig="pi";function _SDL_JoystickOpen(deviceIndex){var gamepad=SDL.getGamepad(deviceIndex);if(gamepad){var joystick=deviceIndex+1;SDL.recordJoystickState(joystick,gamepad);return joystick}return 0}_SDL_JoystickOpen.sig="pi";var _SDL_JoystickOpened=deviceIndex=>SDL.lastJoystickState.hasOwnProperty(deviceIndex+1)?1:0;_SDL_JoystickOpened.sig="ii";function _SDL_JoystickIndex(joystick){joystick>>>=0;return joystick-1}_SDL_JoystickIndex.sig="ip";function _SDL_JoystickNumAxes(joystick){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad){return gamepad.axes.length}return 0}_SDL_JoystickNumAxes.sig="ip";function _SDL_JoystickNumBalls(joystick){joystick>>>=0;return 0}_SDL_JoystickNumBalls.sig="ip";function _SDL_JoystickNumHats(joystick){joystick>>>=0;return 0}_SDL_JoystickNumHats.sig="ip";function _SDL_JoystickNumButtons(joystick){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad){return gamepad.buttons.length}return 0}_SDL_JoystickNumButtons.sig="ip";var _SDL_JoystickUpdate=()=>SDL.queryJoysticks();_SDL_JoystickUpdate.sig="v";var _SDL_JoystickEventState=state=>{if(state<0){return SDL.joystickEventState}return SDL.joystickEventState=state};_SDL_JoystickEventState.sig="ii";function _SDL_JoystickGetAxis(joystick,axis){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad?.axes.length>axis){return SDL.joystickAxisValueConversion(gamepad.axes[axis])}return 0}_SDL_JoystickGetAxis.sig="ipi";function _SDL_JoystickGetHat(joystick,hat){joystick>>>=0;return 0}_SDL_JoystickGetHat.sig="ipi";function _SDL_JoystickGetBall(joystick,ball,dxptr,dyptr){joystick>>>=0;dxptr>>>=0;dyptr>>>=0;return-1}_SDL_JoystickGetBall.sig="ipipp";function _SDL_JoystickGetButton(joystick,button){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad?.buttons.length>button){return SDL.getJoystickButtonState(gamepad.buttons[button])?1:0}return 0}_SDL_JoystickGetButton.sig="ipi";function _SDL_JoystickClose(joystick){joystick>>>=0;delete SDL.lastJoystickState[joystick]}_SDL_JoystickClose.sig="vp";var _SDL_InitSubSystem=flags=>0;_SDL_InitSubSystem.sig="ii";function _SDL_RWFromConstMem(mem,size){mem>>>=0;var id=SDL.rwops.length;SDL.rwops.push({bytes:mem,count:size});return id}_SDL_RWFromConstMem.sig="ppi";var _SDL_RWFromMem=_SDL_RWFromConstMem;_SDL_RWFromMem.sig="ppi";var _SDL_GetNumAudioDrivers=()=>1;_SDL_GetNumAudioDrivers.sig="i";function _SDL_GetCurrentAudioDriver(){return stringToNewUTF8("Emscripten Audio")}_SDL_GetCurrentAudioDriver.sig="p";var _SDL_GetScancodeFromKey=key=>SDL.scanCodes[key];_SDL_GetScancodeFromKey.sig="ii";function _SDL_GetAudioDriver(index){return _SDL_GetCurrentAudioDriver()}_SDL_GetAudioDriver.sig="pi";var _SDL_EnableUNICODE=on=>{var ret=SDL.unicode||0;SDL.unicode=on;return ret};_SDL_EnableUNICODE.sig="ii";var _SDL_AddTimer=function(interval,callback,param){callback>>>=0;param>>>=0;return safeSetTimeout(()=>getWasmTableEntry(callback)(interval,param),interval)};_SDL_AddTimer.sig="iipp";var _SDL_RemoveTimer=id=>{clearTimeout(id);return true};_SDL_RemoveTimer.sig="ii";function _SDL_CreateThread(fs,data,pfnBeginThread,pfnEndThread){fs>>>=0;data>>>=0;throw"SDL threads cannot be supported in the web platform because they assume shared state. See emscripten_create_worker etc. for a message-passing concurrency model that does let you run code in another thread."}_SDL_CreateThread.sig="ppp";function _SDL_WaitThread(thread,status){thread>>>=0;status>>>=0;throw"SDL_WaitThread"}_SDL_WaitThread.sig="vpp";function _SDL_GetThreadID(thread){thread>>>=0;throw"SDL_GetThreadID"}_SDL_GetThreadID.sig="pp";function _SDL_ThreadID(){return 0}_SDL_ThreadID.sig="p";function _SDL_AllocRW(){throw"SDL_AllocRW: TODO"}_SDL_AllocRW.sig="p";function _SDL_CondBroadcast(cond){cond>>>=0;throw"SDL_CondBroadcast: TODO"}_SDL_CondBroadcast.sig="ip";function _SDL_CondWaitTimeout(cond,mutex,ms){cond>>>=0;mutex>>>=0;throw"SDL_CondWaitTimeout: TODO"}_SDL_CondWaitTimeout.sig="ippi";var _SDL_WM_IconifyWindow=()=>{throw"SDL_WM_IconifyWindow TODO"};_SDL_WM_IconifyWindow.sig="i";function _Mix_SetPostMix(func,arg){func>>>=0;arg>>>=0;return warnOnce("Mix_SetPostMix: TODO")}_Mix_SetPostMix.sig="vpp";function _Mix_VolumeChunk(chunk,volume){chunk>>>=0;throw"Mix_VolumeChunk: TODO"}_Mix_VolumeChunk.sig="ipi";var _Mix_SetPosition=(channel,angle,distance)=>{throw"Mix_SetPosition: TODO"};_Mix_SetPosition.sig="iiii";function _Mix_QuerySpec(frequency,format,channels){frequency>>>=0;format>>>=0;channels>>>=0;throw"Mix_QuerySpec: TODO"}_Mix_QuerySpec.sig="ippp";function _Mix_FadeInChannelTimed(channel,chunk,loop,ms,ticks){chunk>>>=0;throw"Mix_FadeInChannelTimed"}_Mix_FadeInChannelTimed.sig="iipiii";var _Mix_FadeOutChannel=()=>{throw"Mix_FadeOutChannel"};_Mix_FadeOutChannel.sig="iii";function _Mix_Linked_Version(){throw"Mix_Linked_Version: TODO"}_Mix_Linked_Version.sig="p";function _SDL_SaveBMP_RW(surface,dst,freedst){surface>>>=0;dst>>>=0;throw"SDL_SaveBMP_RW: TODO"}_SDL_SaveBMP_RW.sig="ippi";function _SDL_WM_SetIcon(icon,mask){icon>>>=0;mask>>>=0}_SDL_WM_SetIcon.sig="vpp";var _SDL_HasRDTSC=()=>0;_SDL_HasRDTSC.sig="i";var _SDL_HasMMX=()=>0;_SDL_HasMMX.sig="i";var _SDL_HasMMXExt=()=>0;_SDL_HasMMXExt.sig="i";var _SDL_Has3DNow=()=>0;_SDL_Has3DNow.sig="i";var _SDL_Has3DNowExt=()=>0;_SDL_Has3DNowExt.sig="i";var _SDL_HasSSE=()=>0;_SDL_HasSSE.sig="i";var _SDL_HasSSE2=()=>0;_SDL_HasSSE2.sig="i";var _SDL_HasAltiVec=()=>0;_SDL_HasAltiVec.sig="i";registerWasmPlugin();FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();for(var base64ReverseLookup=new Uint8Array(123),i=25;i>=0;--i){base64ReverseLookup[48+i]=52+i;base64ReverseLookup[65+i]=i;base64ReverseLookup[97+i]=26+i}base64ReverseLookup[43]=62;base64ReverseLookup[47]=63;MEMFS.doesNotExistError=new FS.ErrnoError(44);MEMFS.doesNotExistError.stack="";if(ENVIRONMENT_IS_NODE){NODEFS.staticInit();}for(let i=0;i<32;++i)tempFixedLengthArray.push(new Array(i));var miniTempWebGLFloatBuffersStorage=new Float32Array(288);for(var i=0;i<=288;++i){miniTempWebGLFloatBuffers[i]=miniTempWebGLFloatBuffersStorage.subarray(0,i)}var miniTempWebGLIntBuffersStorage=new Int32Array(288);for(var i=0;i<=288;++i){miniTempWebGLIntBuffers[i]=miniTempWebGLIntBuffersStorage.subarray(0,i)}Module["requestAnimationFrame"]=MainLoop.requestAnimationFrame;Module["pauseMainLoop"]=MainLoop.pause;Module["resumeMainLoop"]=MainLoop.resume;MainLoop.init();if(typeof setImmediate!="undefined"){emSetImmediate=setImmediateWrapped;emClearImmediate=clearImmediateWrapped}else if(typeof addEventListener=="function"){var __setImmediate_id_counter=0;var __setImmediate_queue=[];var __setImmediate_message_id="_si";var __setImmediate_cb=e=>{if(e.data===__setImmediate_message_id){e.stopPropagation();__setImmediate_queue.shift()();++__setImmediate_id_counter}};addEventListener("message",__setImmediate_cb,true);emSetImmediate=func=>{postMessage(__setImmediate_message_id,"*");return __setImmediate_id_counter+__setImmediate_queue.push(func)-1};emClearImmediate=id=>{var index=id-__setImmediate_id_counter;if(index>=0&&index<__setImmediate_queue.length)__setImmediate_queue[index]=()=>{}}}registerPostMainLoop(()=>SDL.audio?.queueNewAudioData?.());{initMemory();if(Module["preloadPlugins"])preloadPlugins=Module["preloadPlugins"];if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["dynamicLibraries"])dynamicLibraries=Module["dynamicLibraries"];if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"]}Module["addRunDependency"]=addRunDependency;Module["removeRunDependency"]=removeRunDependency;Module["ERRNO_CODES"]=ERRNO_CODES;Module["wasmTable"]=wasmTable;Module["FS_createPreloadedFile"]=FS_createPreloadedFile;Module["FS_unlink"]=FS_unlink;Module["FS_createPath"]=FS_createPath;Module["FS_createDevice"]=FS_createDevice;Module["FS_createDataFile"]=FS_createDataFile;Module["FS_createLazyFile"]=FS_createLazyFile;Module["LZ4"]=LZ4;Module["ExitStatus"]=ExitStatus;Module["GOTHandler"]=GOTHandler;Module["GOT"]=GOT;Module["currentModuleWeakSymbols"]=currentModuleWeakSymbols;Module["addOnPostRun"]=addOnPostRun;Module["onPostRuns"]=onPostRuns;Module["callRuntimeCallbacks"]=callRuntimeCallbacks;Module["addOnPreRun"]=addOnPreRun;Module["onPreRuns"]=onPreRuns;Module["getDylinkMetadata"]=getDylinkMetadata;Module["UTF8ArrayToString"]=UTF8ArrayToString;Module["UTF8Decoder"]=UTF8Decoder;Module["getValue"]=getValue;Module["loadDylibs"]=loadDylibs;Module["loadDynamicLibrary"]=loadDynamicLibrary;Module["LDSO"]=LDSO;Module["newDSO"]=newDSO;Module["loadWebAssemblyModule"]=loadWebAssemblyModule;Module["getMemory"]=getMemory;Module["___heap_base"]=___heap_base;Module["alignMemory"]=alignMemory;Module["relocateExports"]=relocateExports;Module["updateGOT"]=updateGOT;Module["isInternalSym"]=isInternalSym;Module["addFunction"]=addFunction;Module["convertJsFunctionToWasm"]=convertJsFunctionToWasm;Module["uleb128Encode"]=uleb128Encode;Module["sigToWasmTypes"]=sigToWasmTypes;Module["generateFuncType"]=generateFuncType;Module["getFunctionAddress"]=getFunctionAddress;Module["updateTableMap"]=updateTableMap;Module["getWasmTableEntry"]=getWasmTableEntry;Module["wasmTableMirror"]=wasmTableMirror;Module["wasmTable"]=wasmTable;Module["functionsInTableMap"]=functionsInTableMap;Module["getEmptyTableSlot"]=getEmptyTableSlot;Module["freeTableIndexes"]=freeTableIndexes;Module["setWasmTableEntry"]=setWasmTableEntry;Module["resolveGlobalSymbol"]=resolveGlobalSymbol;Module["isSymbolDefined"]=isSymbolDefined;Module["addOnPostCtor"]=addOnPostCtor;Module["onPostCtors"]=onPostCtors;Module["UTF8ToString"]=UTF8ToString;Module["mergeLibSymbols"]=mergeLibSymbols;Module["asyncLoad"]=asyncLoad;Module["preloadedWasm"]=preloadedWasm;Module["registerWasmPlugin"]=registerWasmPlugin;Module["preloadPlugins"]=preloadPlugins;Module["findLibraryFS"]=findLibraryFS;Module["replaceORIGIN"]=replaceORIGIN;Module["PATH"]=PATH;Module["withStackSave"]=withStackSave;Module["stackSave"]=stackSave;Module["stackRestore"]=stackRestore;Module["stackAlloc"]=stackAlloc;Module["lengthBytesUTF8"]=lengthBytesUTF8;Module["stringToUTF8OnStack"]=stringToUTF8OnStack;Module["stringToUTF8"]=stringToUTF8;Module["stringToUTF8Array"]=stringToUTF8Array;Module["FS"]=FS;Module["randomFill"]=randomFill;Module["initRandomFill"]=initRandomFill;Module["base64Decode"]=base64Decode;Module["PATH_FS"]=PATH_FS;Module["TTY"]=TTY;Module["FS_stdin_getChar"]=FS_stdin_getChar;Module["FS_stdin_getChar_buffer"]=FS_stdin_getChar_buffer;Module["intArrayFromString"]=intArrayFromString;Module["MEMFS"]=MEMFS;Module["mmapAlloc"]=mmapAlloc;Module["zeroMemory"]=zeroMemory;Module["FS_createPreloadedFile"]=FS_createPreloadedFile;Module["FS_createDataFile"]=FS_createDataFile;Module["FS_handledByPreloadPlugin"]=FS_handledByPreloadPlugin;Module["FS_modeStringToFlags"]=FS_modeStringToFlags;Module["FS_getMode"]=FS_getMode;Module["IDBFS"]=IDBFS;Module["NODEFS"]=NODEFS;Module["ERRNO_CODES"]=ERRNO_CODES;Module["WORKERFS"]=WORKERFS;Module["PROXYFS"]=PROXYFS;Module["LZ4"]=LZ4;Module["reportUndefinedSymbols"]=reportUndefinedSymbols;Module["noExitRuntime"]=noExitRuntime;Module["setValue"]=setValue;Module["___assert_fail"]=___assert_fail;Module["bigintToI53Checked"]=bigintToI53Checked;Module["INT53_MAX"]=INT53_MAX;Module["INT53_MIN"]=INT53_MIN;Module["___c_longjmp"]=___c_longjmp;Module["___call_sighandler"]=___call_sighandler;Module["___cpp_exception"]=___cpp_exception;Module["___memory_base"]=___memory_base;Module["___stack_high"]=___stack_high;Module["___stack_low"]=___stack_low;Module["___stack_pointer"]=___stack_pointer;Module["___syscall__newselect"]=___syscall__newselect;Module["SYSCALLS"]=SYSCALLS;Module["___syscall_accept4"]=___syscall_accept4;Module["getSocketFromFD"]=getSocketFromFD;Module["SOCKFS"]=SOCKFS;Module["writeSockaddr"]=writeSockaddr;Module["inetPton4"]=inetPton4;Module["inetPton6"]=inetPton6;Module["DNS"]=DNS;Module["___syscall_bind"]=___syscall_bind;Module["getSocketAddress"]=getSocketAddress;Module["readSockaddr"]=readSockaddr;Module["inetNtop4"]=inetNtop4;Module["inetNtop6"]=inetNtop6;Module["___syscall_chdir"]=___syscall_chdir;Module["___syscall_chmod"]=___syscall_chmod;Module["___syscall_connect"]=___syscall_connect;Module["___syscall_dup"]=___syscall_dup;Module["___syscall_dup3"]=___syscall_dup3;Module["___syscall_faccessat"]=___syscall_faccessat;Module["___syscall_fadvise64"]=___syscall_fadvise64;Module["___syscall_fallocate"]=___syscall_fallocate;Module["___syscall_fchdir"]=___syscall_fchdir;Module["___syscall_fchmod"]=___syscall_fchmod;Module["___syscall_fchmodat2"]=___syscall_fchmodat2;Module["___syscall_fchown32"]=___syscall_fchown32;Module["___syscall_fchownat"]=___syscall_fchownat;Module["___syscall_fcntl64"]=___syscall_fcntl64;Module["syscallGetVarargP"]=syscallGetVarargP;Module["syscallGetVarargI"]=syscallGetVarargI;Module["___syscall_fdatasync"]=___syscall_fdatasync;Module["___syscall_fstat64"]=___syscall_fstat64;Module["___syscall_fstatfs64"]=___syscall_fstatfs64;Module["___syscall_ftruncate64"]=___syscall_ftruncate64;Module["___syscall_getcwd"]=___syscall_getcwd;Module["___syscall_getdents64"]=___syscall_getdents64;Module["___syscall_getpeername"]=___syscall_getpeername;Module["___syscall_getsockname"]=___syscall_getsockname;Module["___syscall_getsockopt"]=___syscall_getsockopt;Module["___syscall_ioctl"]=___syscall_ioctl;Module["___syscall_listen"]=___syscall_listen;Module["___syscall_lstat64"]=___syscall_lstat64;Module["___syscall_mkdirat"]=___syscall_mkdirat;Module["___syscall_mknodat"]=___syscall_mknodat;Module["___syscall_newfstatat"]=___syscall_newfstatat;Module["___syscall_openat"]=___syscall_openat;Module["___syscall_pipe"]=___syscall_pipe;Module["PIPEFS"]=PIPEFS;Module["___syscall_poll"]=___syscall_poll;Module["___syscall_readlinkat"]=___syscall_readlinkat;Module["___syscall_recvfrom"]=___syscall_recvfrom;Module["___syscall_recvmsg"]=___syscall_recvmsg;Module["___syscall_renameat"]=___syscall_renameat;Module["___syscall_rmdir"]=___syscall_rmdir;Module["___syscall_sendmsg"]=___syscall_sendmsg;Module["___syscall_sendto"]=___syscall_sendto;Module["___syscall_socket"]=___syscall_socket;Module["___syscall_stat64"]=___syscall_stat64;Module["___syscall_statfs64"]=___syscall_statfs64;Module["___syscall_symlinkat"]=___syscall_symlinkat;Module["___syscall_truncate64"]=___syscall_truncate64;Module["___syscall_unlinkat"]=___syscall_unlinkat;Module["___syscall_utimensat"]=___syscall_utimensat;Module["readI53FromI64"]=readI53FromI64;Module["___table_base"]=___table_base;Module["__abort_js"]=__abort_js;Module["__dlopen_js"]=__dlopen_js;Module["dlopenInternal"]=dlopenInternal;Module["dlSetError"]=dlSetError;Module["__dlsym_js"]=__dlsym_js;Module["__emscripten_dlopen_js"]=__emscripten_dlopen_js;Module["callUserCallback"]=callUserCallback;Module["handleException"]=handleException;Module["maybeExit"]=maybeExit;Module["_exit"]=_exit;Module["exitJS"]=exitJS;Module["_proc_exit"]=_proc_exit;Module["keepRuntimeAlive"]=keepRuntimeAlive;Module["runtimeKeepaliveCounter"]=runtimeKeepaliveCounter;Module["runtimeKeepalivePush"]=runtimeKeepalivePush;Module["runtimeKeepalivePop"]=runtimeKeepalivePop;Module["__emscripten_get_progname"]=__emscripten_get_progname;Module["getExecutableName"]=getExecutableName;Module["__emscripten_lookup_name"]=__emscripten_lookup_name;Module["__emscripten_runtime_keepalive_clear"]=__emscripten_runtime_keepalive_clear;Module["__emscripten_system"]=__emscripten_system;Module["__gmtime_js"]=__gmtime_js;Module["__localtime_js"]=__localtime_js;Module["ydayFromDate"]=ydayFromDate;Module["isLeapYear"]=isLeapYear;Module["MONTH_DAYS_LEAP_CUMULATIVE"]=MONTH_DAYS_LEAP_CUMULATIVE;Module["MONTH_DAYS_REGULAR_CUMULATIVE"]=MONTH_DAYS_REGULAR_CUMULATIVE;Module["__mktime_js"]=__mktime_js;Module["__mmap_js"]=__mmap_js;Module["__msync_js"]=__msync_js;Module["__munmap_js"]=__munmap_js;Module["__setitimer_js"]=__setitimer_js;Module["timers"]=timers;Module["_emscripten_get_now"]=_emscripten_get_now;Module["__timegm_js"]=__timegm_js;Module["__tzset_js"]=__tzset_js;Module["_clock_res_get"]=_clock_res_get;Module["_emscripten_get_now_res"]=_emscripten_get_now_res;Module["nowIsMonotonic"]=nowIsMonotonic;Module["checkWasiClock"]=checkWasiClock;Module["_clock_time_get"]=_clock_time_get;Module["_emscripten_date_now"]=_emscripten_date_now;Module["_create_sentinel"]=_create_sentinel;Module["_emscripten_asm_const_int"]=_emscripten_asm_const_int;Module["runEmAsmFunction"]=runEmAsmFunction;Module["readEmAsmArgs"]=readEmAsmArgs;Module["readEmAsmArgsArray"]=readEmAsmArgsArray;Module["_emscripten_console_error"]=_emscripten_console_error;Module["_emscripten_console_log"]=_emscripten_console_log;Module["_emscripten_console_trace"]=_emscripten_console_trace;Module["_emscripten_console_warn"]=_emscripten_console_warn;Module["_emscripten_err"]=_emscripten_err;Module["_emscripten_get_heap_max"]=_emscripten_get_heap_max;Module["getHeapMax"]=getHeapMax;Module["_emscripten_glActiveTexture"]=_emscripten_glActiveTexture;Module["_glActiveTexture"]=_glActiveTexture;Module["GL"]=GL;Module["GLctx"]=GLctx;Module["webgl_enable_ANGLE_instanced_arrays"]=webgl_enable_ANGLE_instanced_arrays;Module["webgl_enable_OES_vertex_array_object"]=webgl_enable_OES_vertex_array_object;Module["webgl_enable_WEBGL_draw_buffers"]=webgl_enable_WEBGL_draw_buffers;Module["webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance"]=webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance;Module["webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance"]=webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance;Module["webgl_enable_EXT_polygon_offset_clamp"]=webgl_enable_EXT_polygon_offset_clamp;Module["webgl_enable_EXT_clip_control"]=webgl_enable_EXT_clip_control;Module["webgl_enable_WEBGL_polygon_mode"]=webgl_enable_WEBGL_polygon_mode;Module["webgl_enable_WEBGL_multi_draw"]=webgl_enable_WEBGL_multi_draw;Module["getEmscriptenSupportedExtensions"]=getEmscriptenSupportedExtensions;Module["_emscripten_glAttachShader"]=_emscripten_glAttachShader;Module["_glAttachShader"]=_glAttachShader;Module["_emscripten_glBeginQuery"]=_emscripten_glBeginQuery;Module["_glBeginQuery"]=_glBeginQuery;Module["_emscripten_glBeginQueryEXT"]=_emscripten_glBeginQueryEXT;Module["_glBeginQueryEXT"]=_glBeginQueryEXT;Module["_emscripten_glBeginTransformFeedback"]=_emscripten_glBeginTransformFeedback;Module["_glBeginTransformFeedback"]=_glBeginTransformFeedback;Module["_emscripten_glBindAttribLocation"]=_emscripten_glBindAttribLocation;Module["_glBindAttribLocation"]=_glBindAttribLocation;Module["_emscripten_glBindBuffer"]=_emscripten_glBindBuffer;Module["_glBindBuffer"]=_glBindBuffer;Module["_emscripten_glBindBufferBase"]=_emscripten_glBindBufferBase;Module["_glBindBufferBase"]=_glBindBufferBase;Module["_emscripten_glBindBufferRange"]=_emscripten_glBindBufferRange;Module["_glBindBufferRange"]=_glBindBufferRange;Module["_emscripten_glBindFramebuffer"]=_emscripten_glBindFramebuffer;Module["_glBindFramebuffer"]=_glBindFramebuffer;Module["_emscripten_glBindRenderbuffer"]=_emscripten_glBindRenderbuffer;Module["_glBindRenderbuffer"]=_glBindRenderbuffer;Module["_emscripten_glBindSampler"]=_emscripten_glBindSampler;Module["_glBindSampler"]=_glBindSampler;Module["_emscripten_glBindTexture"]=_emscripten_glBindTexture;Module["_glBindTexture"]=_glBindTexture;Module["_emscripten_glBindTransformFeedback"]=_emscripten_glBindTransformFeedback;Module["_glBindTransformFeedback"]=_glBindTransformFeedback;Module["_emscripten_glBindVertexArray"]=_emscripten_glBindVertexArray;Module["_glBindVertexArray"]=_glBindVertexArray;Module["_emscripten_glBindVertexArrayOES"]=_emscripten_glBindVertexArrayOES;Module["_glBindVertexArrayOES"]=_glBindVertexArrayOES;Module["_emscripten_glBlendColor"]=_emscripten_glBlendColor;Module["_glBlendColor"]=_glBlendColor;Module["_emscripten_glBlendEquation"]=_emscripten_glBlendEquation;Module["_glBlendEquation"]=_glBlendEquation;Module["_emscripten_glBlendEquationSeparate"]=_emscripten_glBlendEquationSeparate;Module["_glBlendEquationSeparate"]=_glBlendEquationSeparate;Module["_emscripten_glBlendFunc"]=_emscripten_glBlendFunc;Module["_glBlendFunc"]=_glBlendFunc;Module["_emscripten_glBlendFuncSeparate"]=_emscripten_glBlendFuncSeparate;Module["_glBlendFuncSeparate"]=_glBlendFuncSeparate;Module["_emscripten_glBlitFramebuffer"]=_emscripten_glBlitFramebuffer;Module["_glBlitFramebuffer"]=_glBlitFramebuffer;Module["_emscripten_glBufferData"]=_emscripten_glBufferData;Module["_glBufferData"]=_glBufferData;Module["_emscripten_glBufferSubData"]=_emscripten_glBufferSubData;Module["_glBufferSubData"]=_glBufferSubData;Module["_emscripten_glCheckFramebufferStatus"]=_emscripten_glCheckFramebufferStatus;Module["_glCheckFramebufferStatus"]=_glCheckFramebufferStatus;Module["_emscripten_glClear"]=_emscripten_glClear;Module["_glClear"]=_glClear;Module["_emscripten_glClearBufferfi"]=_emscripten_glClearBufferfi;Module["_glClearBufferfi"]=_glClearBufferfi;Module["_emscripten_glClearBufferfv"]=_emscripten_glClearBufferfv;Module["_glClearBufferfv"]=_glClearBufferfv;Module["_emscripten_glClearBufferiv"]=_emscripten_glClearBufferiv;Module["_glClearBufferiv"]=_glClearBufferiv;Module["_emscripten_glClearBufferuiv"]=_emscripten_glClearBufferuiv;Module["_glClearBufferuiv"]=_glClearBufferuiv;Module["_emscripten_glClearColor"]=_emscripten_glClearColor;Module["_glClearColor"]=_glClearColor;Module["_emscripten_glClearDepthf"]=_emscripten_glClearDepthf;Module["_glClearDepthf"]=_glClearDepthf;Module["_emscripten_glClearStencil"]=_emscripten_glClearStencil;Module["_glClearStencil"]=_glClearStencil;Module["_emscripten_glClientWaitSync"]=_emscripten_glClientWaitSync;Module["_glClientWaitSync"]=_glClientWaitSync;Module["_emscripten_glClipControlEXT"]=_emscripten_glClipControlEXT;Module["_glClipControlEXT"]=_glClipControlEXT;Module["_emscripten_glColorMask"]=_emscripten_glColorMask;Module["_glColorMask"]=_glColorMask;Module["_emscripten_glCompileShader"]=_emscripten_glCompileShader;Module["_glCompileShader"]=_glCompileShader;Module["_emscripten_glCompressedTexImage2D"]=_emscripten_glCompressedTexImage2D;Module["_glCompressedTexImage2D"]=_glCompressedTexImage2D;Module["_emscripten_glCompressedTexImage3D"]=_emscripten_glCompressedTexImage3D;Module["_glCompressedTexImage3D"]=_glCompressedTexImage3D;Module["_emscripten_glCompressedTexSubImage2D"]=_emscripten_glCompressedTexSubImage2D;Module["_glCompressedTexSubImage2D"]=_glCompressedTexSubImage2D;Module["_emscripten_glCompressedTexSubImage3D"]=_emscripten_glCompressedTexSubImage3D;Module["_glCompressedTexSubImage3D"]=_glCompressedTexSubImage3D;Module["_emscripten_glCopyBufferSubData"]=_emscripten_glCopyBufferSubData;Module["_glCopyBufferSubData"]=_glCopyBufferSubData;Module["_emscripten_glCopyTexImage2D"]=_emscripten_glCopyTexImage2D;Module["_glCopyTexImage2D"]=_glCopyTexImage2D;Module["_emscripten_glCopyTexSubImage2D"]=_emscripten_glCopyTexSubImage2D;Module["_glCopyTexSubImage2D"]=_glCopyTexSubImage2D;Module["_emscripten_glCopyTexSubImage3D"]=_emscripten_glCopyTexSubImage3D;Module["_glCopyTexSubImage3D"]=_glCopyTexSubImage3D;Module["_emscripten_glCreateProgram"]=_emscripten_glCreateProgram;Module["_glCreateProgram"]=_glCreateProgram;Module["_emscripten_glCreateShader"]=_emscripten_glCreateShader;Module["_glCreateShader"]=_glCreateShader;Module["_emscripten_glCullFace"]=_emscripten_glCullFace;Module["_glCullFace"]=_glCullFace;Module["_emscripten_glDeleteBuffers"]=_emscripten_glDeleteBuffers;Module["_glDeleteBuffers"]=_glDeleteBuffers;Module["_emscripten_glDeleteFramebuffers"]=_emscripten_glDeleteFramebuffers;Module["_glDeleteFramebuffers"]=_glDeleteFramebuffers;Module["_emscripten_glDeleteProgram"]=_emscripten_glDeleteProgram;Module["_glDeleteProgram"]=_glDeleteProgram;Module["_emscripten_glDeleteQueries"]=_emscripten_glDeleteQueries;Module["_glDeleteQueries"]=_glDeleteQueries;Module["_emscripten_glDeleteQueriesEXT"]=_emscripten_glDeleteQueriesEXT;Module["_glDeleteQueriesEXT"]=_glDeleteQueriesEXT;Module["_emscripten_glDeleteRenderbuffers"]=_emscripten_glDeleteRenderbuffers;Module["_glDeleteRenderbuffers"]=_glDeleteRenderbuffers;Module["_emscripten_glDeleteSamplers"]=_emscripten_glDeleteSamplers;Module["_glDeleteSamplers"]=_glDeleteSamplers;Module["_emscripten_glDeleteShader"]=_emscripten_glDeleteShader;Module["_glDeleteShader"]=_glDeleteShader;Module["_emscripten_glDeleteSync"]=_emscripten_glDeleteSync;Module["_glDeleteSync"]=_glDeleteSync;Module["_emscripten_glDeleteTextures"]=_emscripten_glDeleteTextures;Module["_glDeleteTextures"]=_glDeleteTextures;Module["_emscripten_glDeleteTransformFeedbacks"]=_emscripten_glDeleteTransformFeedbacks;Module["_glDeleteTransformFeedbacks"]=_glDeleteTransformFeedbacks;Module["_emscripten_glDeleteVertexArrays"]=_emscripten_glDeleteVertexArrays;Module["_glDeleteVertexArrays"]=_glDeleteVertexArrays;Module["_emscripten_glDeleteVertexArraysOES"]=_emscripten_glDeleteVertexArraysOES;Module["_glDeleteVertexArraysOES"]=_glDeleteVertexArraysOES;Module["_emscripten_glDepthFunc"]=_emscripten_glDepthFunc;Module["_glDepthFunc"]=_glDepthFunc;Module["_emscripten_glDepthMask"]=_emscripten_glDepthMask;Module["_glDepthMask"]=_glDepthMask;Module["_emscripten_glDepthRangef"]=_emscripten_glDepthRangef;Module["_glDepthRangef"]=_glDepthRangef;Module["_emscripten_glDetachShader"]=_emscripten_glDetachShader;Module["_glDetachShader"]=_glDetachShader;Module["_emscripten_glDisable"]=_emscripten_glDisable;Module["_glDisable"]=_glDisable;Module["_emscripten_glDisableVertexAttribArray"]=_emscripten_glDisableVertexAttribArray;Module["_glDisableVertexAttribArray"]=_glDisableVertexAttribArray;Module["_emscripten_glDrawArrays"]=_emscripten_glDrawArrays;Module["_glDrawArrays"]=_glDrawArrays;Module["_emscripten_glDrawArraysInstanced"]=_emscripten_glDrawArraysInstanced;Module["_glDrawArraysInstanced"]=_glDrawArraysInstanced;Module["_emscripten_glDrawArraysInstancedANGLE"]=_emscripten_glDrawArraysInstancedANGLE;Module["_glDrawArraysInstancedANGLE"]=_glDrawArraysInstancedANGLE;Module["_emscripten_glDrawArraysInstancedARB"]=_emscripten_glDrawArraysInstancedARB;Module["_glDrawArraysInstancedARB"]=_glDrawArraysInstancedARB;Module["_emscripten_glDrawArraysInstancedEXT"]=_emscripten_glDrawArraysInstancedEXT;Module["_glDrawArraysInstancedEXT"]=_glDrawArraysInstancedEXT;Module["_emscripten_glDrawArraysInstancedNV"]=_emscripten_glDrawArraysInstancedNV;Module["_glDrawArraysInstancedNV"]=_glDrawArraysInstancedNV;Module["_emscripten_glDrawBuffers"]=_emscripten_glDrawBuffers;Module["_glDrawBuffers"]=_glDrawBuffers;Module["tempFixedLengthArray"]=tempFixedLengthArray;Module["_emscripten_glDrawBuffersEXT"]=_emscripten_glDrawBuffersEXT;Module["_glDrawBuffersEXT"]=_glDrawBuffersEXT;Module["_emscripten_glDrawBuffersWEBGL"]=_emscripten_glDrawBuffersWEBGL;Module["_glDrawBuffersWEBGL"]=_glDrawBuffersWEBGL;Module["_emscripten_glDrawElements"]=_emscripten_glDrawElements;Module["_glDrawElements"]=_glDrawElements;Module["_emscripten_glDrawElementsInstanced"]=_emscripten_glDrawElementsInstanced;Module["_glDrawElementsInstanced"]=_glDrawElementsInstanced;Module["_emscripten_glDrawElementsInstancedANGLE"]=_emscripten_glDrawElementsInstancedANGLE;Module["_glDrawElementsInstancedANGLE"]=_glDrawElementsInstancedANGLE;Module["_emscripten_glDrawElementsInstancedARB"]=_emscripten_glDrawElementsInstancedARB;Module["_glDrawElementsInstancedARB"]=_glDrawElementsInstancedARB;Module["_emscripten_glDrawElementsInstancedEXT"]=_emscripten_glDrawElementsInstancedEXT;Module["_glDrawElementsInstancedEXT"]=_glDrawElementsInstancedEXT;Module["_emscripten_glDrawElementsInstancedNV"]=_emscripten_glDrawElementsInstancedNV;Module["_glDrawElementsInstancedNV"]=_glDrawElementsInstancedNV;Module["_emscripten_glDrawRangeElements"]=_emscripten_glDrawRangeElements;Module["_glDrawRangeElements"]=_glDrawRangeElements;Module["_emscripten_glEnable"]=_emscripten_glEnable;Module["_glEnable"]=_glEnable;Module["_emscripten_glEnableVertexAttribArray"]=_emscripten_glEnableVertexAttribArray;Module["_glEnableVertexAttribArray"]=_glEnableVertexAttribArray;Module["_emscripten_glEndQuery"]=_emscripten_glEndQuery;Module["_glEndQuery"]=_glEndQuery;Module["_emscripten_glEndQueryEXT"]=_emscripten_glEndQueryEXT;Module["_glEndQueryEXT"]=_glEndQueryEXT;Module["_emscripten_glEndTransformFeedback"]=_emscripten_glEndTransformFeedback;Module["_glEndTransformFeedback"]=_glEndTransformFeedback;Module["_emscripten_glFenceSync"]=_emscripten_glFenceSync;Module["_glFenceSync"]=_glFenceSync;Module["_emscripten_glFinish"]=_emscripten_glFinish;Module["_glFinish"]=_glFinish;Module["_emscripten_glFlush"]=_emscripten_glFlush;Module["_glFlush"]=_glFlush;Module["_emscripten_glFramebufferRenderbuffer"]=_emscripten_glFramebufferRenderbuffer;Module["_glFramebufferRenderbuffer"]=_glFramebufferRenderbuffer;Module["_emscripten_glFramebufferTexture2D"]=_emscripten_glFramebufferTexture2D;Module["_glFramebufferTexture2D"]=_glFramebufferTexture2D;Module["_emscripten_glFramebufferTextureLayer"]=_emscripten_glFramebufferTextureLayer;Module["_glFramebufferTextureLayer"]=_glFramebufferTextureLayer;Module["_emscripten_glFrontFace"]=_emscripten_glFrontFace;Module["_glFrontFace"]=_glFrontFace;Module["_emscripten_glGenBuffers"]=_emscripten_glGenBuffers;Module["_glGenBuffers"]=_glGenBuffers;Module["_emscripten_glGenFramebuffers"]=_emscripten_glGenFramebuffers;Module["_glGenFramebuffers"]=_glGenFramebuffers;Module["_emscripten_glGenQueries"]=_emscripten_glGenQueries;Module["_glGenQueries"]=_glGenQueries;Module["_emscripten_glGenQueriesEXT"]=_emscripten_glGenQueriesEXT;Module["_glGenQueriesEXT"]=_glGenQueriesEXT;Module["_emscripten_glGenRenderbuffers"]=_emscripten_glGenRenderbuffers;Module["_glGenRenderbuffers"]=_glGenRenderbuffers;Module["_emscripten_glGenSamplers"]=_emscripten_glGenSamplers;Module["_glGenSamplers"]=_glGenSamplers;Module["_emscripten_glGenTextures"]=_emscripten_glGenTextures;Module["_glGenTextures"]=_glGenTextures;Module["_emscripten_glGenTransformFeedbacks"]=_emscripten_glGenTransformFeedbacks;Module["_glGenTransformFeedbacks"]=_glGenTransformFeedbacks;Module["_emscripten_glGenVertexArrays"]=_emscripten_glGenVertexArrays;Module["_glGenVertexArrays"]=_glGenVertexArrays;Module["_emscripten_glGenVertexArraysOES"]=_emscripten_glGenVertexArraysOES;Module["_glGenVertexArraysOES"]=_glGenVertexArraysOES;Module["_emscripten_glGenerateMipmap"]=_emscripten_glGenerateMipmap;Module["_glGenerateMipmap"]=_glGenerateMipmap;Module["_emscripten_glGetActiveAttrib"]=_emscripten_glGetActiveAttrib;Module["_glGetActiveAttrib"]=_glGetActiveAttrib;Module["__glGetActiveAttribOrUniform"]=__glGetActiveAttribOrUniform;Module["_emscripten_glGetActiveUniform"]=_emscripten_glGetActiveUniform;Module["_glGetActiveUniform"]=_glGetActiveUniform;Module["_emscripten_glGetActiveUniformBlockName"]=_emscripten_glGetActiveUniformBlockName;Module["_glGetActiveUniformBlockName"]=_glGetActiveUniformBlockName;Module["_emscripten_glGetActiveUniformBlockiv"]=_emscripten_glGetActiveUniformBlockiv;Module["_glGetActiveUniformBlockiv"]=_glGetActiveUniformBlockiv;Module["_emscripten_glGetActiveUniformsiv"]=_emscripten_glGetActiveUniformsiv;Module["_glGetActiveUniformsiv"]=_glGetActiveUniformsiv;Module["_emscripten_glGetAttachedShaders"]=_emscripten_glGetAttachedShaders;Module["_glGetAttachedShaders"]=_glGetAttachedShaders;Module["_emscripten_glGetAttribLocation"]=_emscripten_glGetAttribLocation;Module["_glGetAttribLocation"]=_glGetAttribLocation;Module["_emscripten_glGetBooleanv"]=_emscripten_glGetBooleanv;Module["_glGetBooleanv"]=_glGetBooleanv;Module["emscriptenWebGLGet"]=emscriptenWebGLGet;Module["writeI53ToI64"]=writeI53ToI64;Module["webglGetExtensions"]=webglGetExtensions;Module["_emscripten_glGetBufferParameteri64v"]=_emscripten_glGetBufferParameteri64v;Module["_glGetBufferParameteri64v"]=_glGetBufferParameteri64v;Module["_emscripten_glGetBufferParameteriv"]=_emscripten_glGetBufferParameteriv;Module["_glGetBufferParameteriv"]=_glGetBufferParameteriv;Module["_emscripten_glGetError"]=_emscripten_glGetError;Module["_glGetError"]=_glGetError;Module["_emscripten_glGetFloatv"]=_emscripten_glGetFloatv;Module["_glGetFloatv"]=_glGetFloatv;Module["_emscripten_glGetFragDataLocation"]=_emscripten_glGetFragDataLocation;Module["_glGetFragDataLocation"]=_glGetFragDataLocation;Module["_emscripten_glGetFramebufferAttachmentParameteriv"]=_emscripten_glGetFramebufferAttachmentParameteriv;Module["_glGetFramebufferAttachmentParameteriv"]=_glGetFramebufferAttachmentParameteriv;Module["_emscripten_glGetInteger64i_v"]=_emscripten_glGetInteger64i_v;Module["_glGetInteger64i_v"]=_glGetInteger64i_v;Module["emscriptenWebGLGetIndexed"]=emscriptenWebGLGetIndexed;Module["_emscripten_glGetInteger64v"]=_emscripten_glGetInteger64v;Module["_glGetInteger64v"]=_glGetInteger64v;Module["_emscripten_glGetIntegeri_v"]=_emscripten_glGetIntegeri_v;Module["_glGetIntegeri_v"]=_glGetIntegeri_v;Module["_emscripten_glGetIntegerv"]=_emscripten_glGetIntegerv;Module["_glGetIntegerv"]=_glGetIntegerv;Module["_emscripten_glGetInternalformativ"]=_emscripten_glGetInternalformativ;Module["_glGetInternalformativ"]=_glGetInternalformativ;Module["_emscripten_glGetProgramBinary"]=_emscripten_glGetProgramBinary;Module["_glGetProgramBinary"]=_glGetProgramBinary;Module["_emscripten_glGetProgramInfoLog"]=_emscripten_glGetProgramInfoLog;Module["_glGetProgramInfoLog"]=_glGetProgramInfoLog;Module["_emscripten_glGetProgramiv"]=_emscripten_glGetProgramiv;Module["_glGetProgramiv"]=_glGetProgramiv;Module["_emscripten_glGetQueryObjecti64vEXT"]=_emscripten_glGetQueryObjecti64vEXT;Module["_glGetQueryObjecti64vEXT"]=_glGetQueryObjecti64vEXT;Module["_emscripten_glGetQueryObjectivEXT"]=_emscripten_glGetQueryObjectivEXT;Module["_glGetQueryObjectivEXT"]=_glGetQueryObjectivEXT;Module["_emscripten_glGetQueryObjectui64vEXT"]=_emscripten_glGetQueryObjectui64vEXT;Module["_glGetQueryObjectui64vEXT"]=_glGetQueryObjectui64vEXT;Module["_emscripten_glGetQueryObjectuiv"]=_emscripten_glGetQueryObjectuiv;Module["_glGetQueryObjectuiv"]=_glGetQueryObjectuiv;Module["_emscripten_glGetQueryObjectuivEXT"]=_emscripten_glGetQueryObjectuivEXT;Module["_glGetQueryObjectuivEXT"]=_glGetQueryObjectuivEXT;Module["_emscripten_glGetQueryiv"]=_emscripten_glGetQueryiv;Module["_glGetQueryiv"]=_glGetQueryiv;Module["_emscripten_glGetQueryivEXT"]=_emscripten_glGetQueryivEXT;Module["_glGetQueryivEXT"]=_glGetQueryivEXT;Module["_emscripten_glGetRenderbufferParameteriv"]=_emscripten_glGetRenderbufferParameteriv;Module["_glGetRenderbufferParameteriv"]=_glGetRenderbufferParameteriv;Module["_emscripten_glGetSamplerParameterfv"]=_emscripten_glGetSamplerParameterfv;Module["_glGetSamplerParameterfv"]=_glGetSamplerParameterfv;Module["_emscripten_glGetSamplerParameteriv"]=_emscripten_glGetSamplerParameteriv;Module["_glGetSamplerParameteriv"]=_glGetSamplerParameteriv;Module["_emscripten_glGetShaderInfoLog"]=_emscripten_glGetShaderInfoLog;Module["_glGetShaderInfoLog"]=_glGetShaderInfoLog;Module["_emscripten_glGetShaderPrecisionFormat"]=_emscripten_glGetShaderPrecisionFormat;Module["_glGetShaderPrecisionFormat"]=_glGetShaderPrecisionFormat;Module["_emscripten_glGetShaderSource"]=_emscripten_glGetShaderSource;Module["_glGetShaderSource"]=_glGetShaderSource;Module["_emscripten_glGetShaderiv"]=_emscripten_glGetShaderiv;Module["_glGetShaderiv"]=_glGetShaderiv;Module["_emscripten_glGetString"]=_emscripten_glGetString;Module["_glGetString"]=_glGetString;Module["stringToNewUTF8"]=stringToNewUTF8;Module["_emscripten_glGetStringi"]=_emscripten_glGetStringi;Module["_glGetStringi"]=_glGetStringi;Module["_emscripten_glGetSynciv"]=_emscripten_glGetSynciv;Module["_glGetSynciv"]=_glGetSynciv;Module["_emscripten_glGetTexParameterfv"]=_emscripten_glGetTexParameterfv;Module["_glGetTexParameterfv"]=_glGetTexParameterfv;Module["_emscripten_glGetTexParameteriv"]=_emscripten_glGetTexParameteriv;Module["_glGetTexParameteriv"]=_glGetTexParameteriv;Module["_emscripten_glGetTransformFeedbackVarying"]=_emscripten_glGetTransformFeedbackVarying;Module["_glGetTransformFeedbackVarying"]=_glGetTransformFeedbackVarying;Module["_emscripten_glGetUniformBlockIndex"]=_emscripten_glGetUniformBlockIndex;Module["_glGetUniformBlockIndex"]=_glGetUniformBlockIndex;Module["_emscripten_glGetUniformIndices"]=_emscripten_glGetUniformIndices;Module["_glGetUniformIndices"]=_glGetUniformIndices;Module["_emscripten_glGetUniformLocation"]=_emscripten_glGetUniformLocation;Module["_glGetUniformLocation"]=_glGetUniformLocation;Module["jstoi_q"]=jstoi_q;Module["webglPrepareUniformLocationsBeforeFirstUse"]=webglPrepareUniformLocationsBeforeFirstUse;Module["webglGetLeftBracePos"]=webglGetLeftBracePos;Module["_emscripten_glGetUniformfv"]=_emscripten_glGetUniformfv;Module["_glGetUniformfv"]=_glGetUniformfv;Module["emscriptenWebGLGetUniform"]=emscriptenWebGLGetUniform;Module["webglGetUniformLocation"]=webglGetUniformLocation;Module["_emscripten_glGetUniformiv"]=_emscripten_glGetUniformiv;Module["_glGetUniformiv"]=_glGetUniformiv;Module["_emscripten_glGetUniformuiv"]=_emscripten_glGetUniformuiv;Module["_glGetUniformuiv"]=_glGetUniformuiv;Module["_emscripten_glGetVertexAttribIiv"]=_emscripten_glGetVertexAttribIiv;Module["_glGetVertexAttribIiv"]=_glGetVertexAttribIiv;Module["emscriptenWebGLGetVertexAttrib"]=emscriptenWebGLGetVertexAttrib;Module["_emscripten_glGetVertexAttribIuiv"]=_emscripten_glGetVertexAttribIuiv;Module["_glGetVertexAttribIuiv"]=_glGetVertexAttribIuiv;Module["_emscripten_glGetVertexAttribPointerv"]=_emscripten_glGetVertexAttribPointerv;Module["_glGetVertexAttribPointerv"]=_glGetVertexAttribPointerv;Module["_emscripten_glGetVertexAttribfv"]=_emscripten_glGetVertexAttribfv;Module["_glGetVertexAttribfv"]=_glGetVertexAttribfv;Module["_emscripten_glGetVertexAttribiv"]=_emscripten_glGetVertexAttribiv;Module["_glGetVertexAttribiv"]=_glGetVertexAttribiv;Module["_emscripten_glHint"]=_emscripten_glHint;Module["_glHint"]=_glHint;Module["_emscripten_glInvalidateFramebuffer"]=_emscripten_glInvalidateFramebuffer;Module["_glInvalidateFramebuffer"]=_glInvalidateFramebuffer;Module["_emscripten_glInvalidateSubFramebuffer"]=_emscripten_glInvalidateSubFramebuffer;Module["_glInvalidateSubFramebuffer"]=_glInvalidateSubFramebuffer;Module["_emscripten_glIsBuffer"]=_emscripten_glIsBuffer;Module["_glIsBuffer"]=_glIsBuffer;Module["_emscripten_glIsEnabled"]=_emscripten_glIsEnabled;Module["_glIsEnabled"]=_glIsEnabled;Module["_emscripten_glIsFramebuffer"]=_emscripten_glIsFramebuffer;Module["_glIsFramebuffer"]=_glIsFramebuffer;Module["_emscripten_glIsProgram"]=_emscripten_glIsProgram;Module["_glIsProgram"]=_glIsProgram;Module["_emscripten_glIsQuery"]=_emscripten_glIsQuery;Module["_glIsQuery"]=_glIsQuery;Module["_emscripten_glIsQueryEXT"]=_emscripten_glIsQueryEXT;Module["_glIsQueryEXT"]=_glIsQueryEXT;Module["_emscripten_glIsRenderbuffer"]=_emscripten_glIsRenderbuffer;Module["_glIsRenderbuffer"]=_glIsRenderbuffer;Module["_emscripten_glIsSampler"]=_emscripten_glIsSampler;Module["_glIsSampler"]=_glIsSampler;Module["_emscripten_glIsShader"]=_emscripten_glIsShader;Module["_glIsShader"]=_glIsShader;Module["_emscripten_glIsSync"]=_emscripten_glIsSync;Module["_glIsSync"]=_glIsSync;Module["_emscripten_glIsTexture"]=_emscripten_glIsTexture;Module["_glIsTexture"]=_glIsTexture;Module["_emscripten_glIsTransformFeedback"]=_emscripten_glIsTransformFeedback;Module["_glIsTransformFeedback"]=_glIsTransformFeedback;Module["_emscripten_glIsVertexArray"]=_emscripten_glIsVertexArray;Module["_glIsVertexArray"]=_glIsVertexArray;Module["_emscripten_glIsVertexArrayOES"]=_emscripten_glIsVertexArrayOES;Module["_glIsVertexArrayOES"]=_glIsVertexArrayOES;Module["_emscripten_glLineWidth"]=_emscripten_glLineWidth;Module["_glLineWidth"]=_glLineWidth;Module["_emscripten_glLinkProgram"]=_emscripten_glLinkProgram;Module["_glLinkProgram"]=_glLinkProgram;Module["_emscripten_glPauseTransformFeedback"]=_emscripten_glPauseTransformFeedback;Module["_glPauseTransformFeedback"]=_glPauseTransformFeedback;Module["_emscripten_glPixelStorei"]=_emscripten_glPixelStorei;Module["_glPixelStorei"]=_glPixelStorei;Module["_emscripten_glPolygonModeWEBGL"]=_emscripten_glPolygonModeWEBGL;Module["_glPolygonModeWEBGL"]=_glPolygonModeWEBGL;Module["_emscripten_glPolygonOffset"]=_emscripten_glPolygonOffset;Module["_glPolygonOffset"]=_glPolygonOffset;Module["_emscripten_glPolygonOffsetClampEXT"]=_emscripten_glPolygonOffsetClampEXT;Module["_glPolygonOffsetClampEXT"]=_glPolygonOffsetClampEXT;Module["_emscripten_glProgramBinary"]=_emscripten_glProgramBinary;Module["_glProgramBinary"]=_glProgramBinary;Module["_emscripten_glProgramParameteri"]=_emscripten_glProgramParameteri;Module["_glProgramParameteri"]=_glProgramParameteri;Module["_emscripten_glQueryCounterEXT"]=_emscripten_glQueryCounterEXT;Module["_glQueryCounterEXT"]=_glQueryCounterEXT;Module["_emscripten_glReadBuffer"]=_emscripten_glReadBuffer;Module["_glReadBuffer"]=_glReadBuffer;Module["_emscripten_glReadPixels"]=_emscripten_glReadPixels;Module["_glReadPixels"]=_glReadPixels;Module["emscriptenWebGLGetTexPixelData"]=emscriptenWebGLGetTexPixelData;Module["computeUnpackAlignedImageSize"]=computeUnpackAlignedImageSize;Module["colorChannelsInGlTextureFormat"]=colorChannelsInGlTextureFormat;Module["heapObjectForWebGLType"]=heapObjectForWebGLType;Module["toTypedArrayIndex"]=toTypedArrayIndex;Module["_emscripten_glReleaseShaderCompiler"]=_emscripten_glReleaseShaderCompiler;Module["_glReleaseShaderCompiler"]=_glReleaseShaderCompiler;Module["_emscripten_glRenderbufferStorage"]=_emscripten_glRenderbufferStorage;Module["_glRenderbufferStorage"]=_glRenderbufferStorage;Module["_emscripten_glRenderbufferStorageMultisample"]=_emscripten_glRenderbufferStorageMultisample;Module["_glRenderbufferStorageMultisample"]=_glRenderbufferStorageMultisample;Module["_emscripten_glResumeTransformFeedback"]=_emscripten_glResumeTransformFeedback;Module["_glResumeTransformFeedback"]=_glResumeTransformFeedback;Module["_emscripten_glSampleCoverage"]=_emscripten_glSampleCoverage;Module["_glSampleCoverage"]=_glSampleCoverage;Module["_emscripten_glSamplerParameterf"]=_emscripten_glSamplerParameterf;Module["_glSamplerParameterf"]=_glSamplerParameterf;Module["_emscripten_glSamplerParameterfv"]=_emscripten_glSamplerParameterfv;Module["_glSamplerParameterfv"]=_glSamplerParameterfv;Module["_emscripten_glSamplerParameteri"]=_emscripten_glSamplerParameteri;Module["_glSamplerParameteri"]=_glSamplerParameteri;Module["_emscripten_glSamplerParameteriv"]=_emscripten_glSamplerParameteriv;Module["_glSamplerParameteriv"]=_glSamplerParameteriv;Module["_emscripten_glScissor"]=_emscripten_glScissor;Module["_glScissor"]=_glScissor;Module["_emscripten_glShaderBinary"]=_emscripten_glShaderBinary;Module["_glShaderBinary"]=_glShaderBinary;Module["_emscripten_glShaderSource"]=_emscripten_glShaderSource;Module["_glShaderSource"]=_glShaderSource;Module["_emscripten_glStencilFunc"]=_emscripten_glStencilFunc;Module["_glStencilFunc"]=_glStencilFunc;Module["_emscripten_glStencilFuncSeparate"]=_emscripten_glStencilFuncSeparate;Module["_glStencilFuncSeparate"]=_glStencilFuncSeparate;Module["_emscripten_glStencilMask"]=_emscripten_glStencilMask;Module["_glStencilMask"]=_glStencilMask;Module["_emscripten_glStencilMaskSeparate"]=_emscripten_glStencilMaskSeparate;Module["_glStencilMaskSeparate"]=_glStencilMaskSeparate;Module["_emscripten_glStencilOp"]=_emscripten_glStencilOp;Module["_glStencilOp"]=_glStencilOp;Module["_emscripten_glStencilOpSeparate"]=_emscripten_glStencilOpSeparate;Module["_glStencilOpSeparate"]=_glStencilOpSeparate;Module["_emscripten_glTexImage2D"]=_emscripten_glTexImage2D;Module["_glTexImage2D"]=_glTexImage2D;Module["_emscripten_glTexImage3D"]=_emscripten_glTexImage3D;Module["_glTexImage3D"]=_glTexImage3D;Module["_emscripten_glTexParameterf"]=_emscripten_glTexParameterf;Module["_glTexParameterf"]=_glTexParameterf;Module["_emscripten_glTexParameterfv"]=_emscripten_glTexParameterfv;Module["_glTexParameterfv"]=_glTexParameterfv;Module["_emscripten_glTexParameteri"]=_emscripten_glTexParameteri;Module["_glTexParameteri"]=_glTexParameteri;Module["_emscripten_glTexParameteriv"]=_emscripten_glTexParameteriv;Module["_glTexParameteriv"]=_glTexParameteriv;Module["_emscripten_glTexStorage2D"]=_emscripten_glTexStorage2D;Module["_glTexStorage2D"]=_glTexStorage2D;Module["_emscripten_glTexStorage3D"]=_emscripten_glTexStorage3D;Module["_glTexStorage3D"]=_glTexStorage3D;Module["_emscripten_glTexSubImage2D"]=_emscripten_glTexSubImage2D;Module["_glTexSubImage2D"]=_glTexSubImage2D;Module["_emscripten_glTexSubImage3D"]=_emscripten_glTexSubImage3D;Module["_glTexSubImage3D"]=_glTexSubImage3D;Module["_emscripten_glTransformFeedbackVaryings"]=_emscripten_glTransformFeedbackVaryings;Module["_glTransformFeedbackVaryings"]=_glTransformFeedbackVaryings;Module["_emscripten_glUniform1f"]=_emscripten_glUniform1f;Module["_glUniform1f"]=_glUniform1f;Module["_emscripten_glUniform1fv"]=_emscripten_glUniform1fv;Module["_glUniform1fv"]=_glUniform1fv;Module["miniTempWebGLFloatBuffers"]=miniTempWebGLFloatBuffers;Module["_emscripten_glUniform1i"]=_emscripten_glUniform1i;Module["_glUniform1i"]=_glUniform1i;Module["_emscripten_glUniform1iv"]=_emscripten_glUniform1iv;Module["_glUniform1iv"]=_glUniform1iv;Module["miniTempWebGLIntBuffers"]=miniTempWebGLIntBuffers;Module["_emscripten_glUniform1ui"]=_emscripten_glUniform1ui;Module["_glUniform1ui"]=_glUniform1ui;Module["_emscripten_glUniform1uiv"]=_emscripten_glUniform1uiv;Module["_glUniform1uiv"]=_glUniform1uiv;Module["_emscripten_glUniform2f"]=_emscripten_glUniform2f;Module["_glUniform2f"]=_glUniform2f;Module["_emscripten_glUniform2fv"]=_emscripten_glUniform2fv;Module["_glUniform2fv"]=_glUniform2fv;Module["_emscripten_glUniform2i"]=_emscripten_glUniform2i;Module["_glUniform2i"]=_glUniform2i;Module["_emscripten_glUniform2iv"]=_emscripten_glUniform2iv;Module["_glUniform2iv"]=_glUniform2iv;Module["_emscripten_glUniform2ui"]=_emscripten_glUniform2ui;Module["_glUniform2ui"]=_glUniform2ui;Module["_emscripten_glUniform2uiv"]=_emscripten_glUniform2uiv;Module["_glUniform2uiv"]=_glUniform2uiv;Module["_emscripten_glUniform3f"]=_emscripten_glUniform3f;Module["_glUniform3f"]=_glUniform3f;Module["_emscripten_glUniform3fv"]=_emscripten_glUniform3fv;Module["_glUniform3fv"]=_glUniform3fv;Module["_emscripten_glUniform3i"]=_emscripten_glUniform3i;Module["_glUniform3i"]=_glUniform3i;Module["_emscripten_glUniform3iv"]=_emscripten_glUniform3iv;Module["_glUniform3iv"]=_glUniform3iv;Module["_emscripten_glUniform3ui"]=_emscripten_glUniform3ui;Module["_glUniform3ui"]=_glUniform3ui;Module["_emscripten_glUniform3uiv"]=_emscripten_glUniform3uiv;Module["_glUniform3uiv"]=_glUniform3uiv;Module["_emscripten_glUniform4f"]=_emscripten_glUniform4f;Module["_glUniform4f"]=_glUniform4f;Module["_emscripten_glUniform4fv"]=_emscripten_glUniform4fv;Module["_glUniform4fv"]=_glUniform4fv;Module["_emscripten_glUniform4i"]=_emscripten_glUniform4i;Module["_glUniform4i"]=_glUniform4i;Module["_emscripten_glUniform4iv"]=_emscripten_glUniform4iv;Module["_glUniform4iv"]=_glUniform4iv;Module["_emscripten_glUniform4ui"]=_emscripten_glUniform4ui;Module["_glUniform4ui"]=_glUniform4ui;Module["_emscripten_glUniform4uiv"]=_emscripten_glUniform4uiv;Module["_glUniform4uiv"]=_glUniform4uiv;Module["_emscripten_glUniformBlockBinding"]=_emscripten_glUniformBlockBinding;Module["_glUniformBlockBinding"]=_glUniformBlockBinding;Module["_emscripten_glUniformMatrix2fv"]=_emscripten_glUniformMatrix2fv;Module["_glUniformMatrix2fv"]=_glUniformMatrix2fv;Module["_emscripten_glUniformMatrix2x3fv"]=_emscripten_glUniformMatrix2x3fv;Module["_glUniformMatrix2x3fv"]=_glUniformMatrix2x3fv;Module["_emscripten_glUniformMatrix2x4fv"]=_emscripten_glUniformMatrix2x4fv;Module["_glUniformMatrix2x4fv"]=_glUniformMatrix2x4fv;Module["_emscripten_glUniformMatrix3fv"]=_emscripten_glUniformMatrix3fv;Module["_glUniformMatrix3fv"]=_glUniformMatrix3fv;Module["_emscripten_glUniformMatrix3x2fv"]=_emscripten_glUniformMatrix3x2fv;Module["_glUniformMatrix3x2fv"]=_glUniformMatrix3x2fv;Module["_emscripten_glUniformMatrix3x4fv"]=_emscripten_glUniformMatrix3x4fv;Module["_glUniformMatrix3x4fv"]=_glUniformMatrix3x4fv;Module["_emscripten_glUniformMatrix4fv"]=_emscripten_glUniformMatrix4fv;Module["_glUniformMatrix4fv"]=_glUniformMatrix4fv;Module["_emscripten_glUniformMatrix4x2fv"]=_emscripten_glUniformMatrix4x2fv;Module["_glUniformMatrix4x2fv"]=_glUniformMatrix4x2fv;Module["_emscripten_glUniformMatrix4x3fv"]=_emscripten_glUniformMatrix4x3fv;Module["_glUniformMatrix4x3fv"]=_glUniformMatrix4x3fv;Module["_emscripten_glUseProgram"]=_emscripten_glUseProgram;Module["_glUseProgram"]=_glUseProgram;Module["_emscripten_glValidateProgram"]=_emscripten_glValidateProgram;Module["_glValidateProgram"]=_glValidateProgram;Module["_emscripten_glVertexAttrib1f"]=_emscripten_glVertexAttrib1f;Module["_glVertexAttrib1f"]=_glVertexAttrib1f;Module["_emscripten_glVertexAttrib1fv"]=_emscripten_glVertexAttrib1fv;Module["_glVertexAttrib1fv"]=_glVertexAttrib1fv;Module["_emscripten_glVertexAttrib2f"]=_emscripten_glVertexAttrib2f;Module["_glVertexAttrib2f"]=_glVertexAttrib2f;Module["_emscripten_glVertexAttrib2fv"]=_emscripten_glVertexAttrib2fv;Module["_glVertexAttrib2fv"]=_glVertexAttrib2fv;Module["_emscripten_glVertexAttrib3f"]=_emscripten_glVertexAttrib3f;Module["_glVertexAttrib3f"]=_glVertexAttrib3f;Module["_emscripten_glVertexAttrib3fv"]=_emscripten_glVertexAttrib3fv;Module["_glVertexAttrib3fv"]=_glVertexAttrib3fv;Module["_emscripten_glVertexAttrib4f"]=_emscripten_glVertexAttrib4f;Module["_glVertexAttrib4f"]=_glVertexAttrib4f;Module["_emscripten_glVertexAttrib4fv"]=_emscripten_glVertexAttrib4fv;Module["_glVertexAttrib4fv"]=_glVertexAttrib4fv;Module["_emscripten_glVertexAttribDivisor"]=_emscripten_glVertexAttribDivisor;Module["_glVertexAttribDivisor"]=_glVertexAttribDivisor;Module["_emscripten_glVertexAttribDivisorANGLE"]=_emscripten_glVertexAttribDivisorANGLE;Module["_glVertexAttribDivisorANGLE"]=_glVertexAttribDivisorANGLE;Module["_emscripten_glVertexAttribDivisorARB"]=_emscripten_glVertexAttribDivisorARB;Module["_glVertexAttribDivisorARB"]=_glVertexAttribDivisorARB;Module["_emscripten_glVertexAttribDivisorEXT"]=_emscripten_glVertexAttribDivisorEXT;Module["_glVertexAttribDivisorEXT"]=_glVertexAttribDivisorEXT;Module["_emscripten_glVertexAttribDivisorNV"]=_emscripten_glVertexAttribDivisorNV;Module["_glVertexAttribDivisorNV"]=_glVertexAttribDivisorNV;Module["_emscripten_glVertexAttribI4i"]=_emscripten_glVertexAttribI4i;Module["_glVertexAttribI4i"]=_glVertexAttribI4i;Module["_emscripten_glVertexAttribI4iv"]=_emscripten_glVertexAttribI4iv;Module["_glVertexAttribI4iv"]=_glVertexAttribI4iv;Module["_emscripten_glVertexAttribI4ui"]=_emscripten_glVertexAttribI4ui;Module["_glVertexAttribI4ui"]=_glVertexAttribI4ui;Module["_emscripten_glVertexAttribI4uiv"]=_emscripten_glVertexAttribI4uiv;Module["_glVertexAttribI4uiv"]=_glVertexAttribI4uiv;Module["_emscripten_glVertexAttribIPointer"]=_emscripten_glVertexAttribIPointer;Module["_glVertexAttribIPointer"]=_glVertexAttribIPointer;Module["_emscripten_glVertexAttribPointer"]=_emscripten_glVertexAttribPointer;Module["_glVertexAttribPointer"]=_glVertexAttribPointer;Module["_emscripten_glViewport"]=_emscripten_glViewport;Module["_glViewport"]=_glViewport;Module["_emscripten_glWaitSync"]=_emscripten_glWaitSync;Module["_glWaitSync"]=_glWaitSync;Module["_emscripten_out"]=_emscripten_out;Module["_emscripten_promise_create"]=_emscripten_promise_create;Module["makePromise"]=makePromise;Module["promiseMap"]=promiseMap;Module["HandleAllocator"]=HandleAllocator;Module["_emscripten_promise_destroy"]=_emscripten_promise_destroy;Module["_emscripten_promise_resolve"]=_emscripten_promise_resolve;Module["getPromise"]=getPromise;Module["_emscripten_resize_heap"]=_emscripten_resize_heap;Module["growMemory"]=growMemory;Module["_emscripten_runtime_keepalive_pop"]=_emscripten_runtime_keepalive_pop;Module["_emscripten_runtime_keepalive_push"]=_emscripten_runtime_keepalive_push;Module["_environ_get"]=_environ_get;Module["getEnvStrings"]=getEnvStrings;Module["ENV"]=ENV;Module["_environ_sizes_get"]=_environ_sizes_get;Module["_fd_close"]=_fd_close;Module["_fd_fdstat_get"]=_fd_fdstat_get;Module["_fd_pread"]=_fd_pread;Module["doReadv"]=doReadv;Module["_fd_pwrite"]=_fd_pwrite;Module["doWritev"]=doWritev;Module["_fd_read"]=_fd_read;Module["_fd_seek"]=_fd_seek;Module["_fd_sync"]=_fd_sync;Module["_fd_write"]=_fd_write;Module["_getaddrinfo"]=_getaddrinfo;Module["_getnameinfo"]=_getnameinfo;Module["_getprotobyname"]=_getprotobyname;Module["_setprotoent"]=_setprotoent;Module["Protocols"]=Protocols;Module["stringToAscii"]=stringToAscii;Module["_is_sentinel"]=_is_sentinel;Module["_random_get"]=_random_get;Module["_stackAlloc"]=_stackAlloc;Module["_stackRestore"]=_stackRestore;Module["_stackSave"]=_stackSave;Module["FS_createPath"]=FS_createPath;Module["FS_unlink"]=FS_unlink;Module["FS_createLazyFile"]=FS_createLazyFile;Module["FS_createDevice"]=FS_createDevice;Module["writeI53ToI64Clamped"]=writeI53ToI64Clamped;Module["writeI53ToI64Signaling"]=writeI53ToI64Signaling;Module["writeI53ToU64Clamped"]=writeI53ToU64Clamped;Module["writeI53ToU64Signaling"]=writeI53ToU64Signaling;Module["readI53FromU64"]=readI53FromU64;Module["convertI32PairToI53"]=convertI32PairToI53;Module["convertI32PairToI53Checked"]=convertI32PairToI53Checked;Module["convertU32PairToI53"]=convertU32PairToI53;Module["getTempRet0"]=getTempRet0;Module["setTempRet0"]=setTempRet0;Module["ptrToString"]=ptrToString;Module["_emscripten_notify_memory_growth"]=_emscripten_notify_memory_growth;Module["strError"]=strError;Module["_endprotoent"]=_endprotoent;Module["_getprotoent"]=_getprotoent;Module["_getprotobynumber"]=_getprotobynumber;Module["Sockets"]=Sockets;Module["_emscripten_run_script"]=_emscripten_run_script;Module["_emscripten_run_script_int"]=_emscripten_run_script_int;Module["_emscripten_run_script_string"]=_emscripten_run_script_string;Module["_emscripten_random"]=_emscripten_random;Module["_emscripten_performance_now"]=_emscripten_performance_now;Module["__emscripten_get_now_is_monotonic"]=__emscripten_get_now_is_monotonic;Module["warnOnce"]=warnOnce;Module["emscriptenLog"]=emscriptenLog;Module["getCallstack"]=getCallstack;Module["jsStackTrace"]=jsStackTrace;Module["_emscripten_log"]=_emscripten_log;Module["formatString"]=formatString;Module["reallyNegative"]=reallyNegative;Module["reSign"]=reSign;Module["unSign"]=unSign;Module["strLen"]=strLen;Module["_emscripten_get_compiler_setting"]=_emscripten_get_compiler_setting;Module["_emscripten_has_asyncify"]=_emscripten_has_asyncify;Module["_emscripten_debugger"]=_emscripten_debugger;Module["_emscripten_print_double"]=_emscripten_print_double;Module["_emscripten_asm_const_double"]=_emscripten_asm_const_double;Module["_emscripten_asm_const_ptr"]=_emscripten_asm_const_ptr;Module["runMainThreadEmAsm"]=runMainThreadEmAsm;Module["_emscripten_asm_const_int_sync_on_main_thread"]=_emscripten_asm_const_int_sync_on_main_thread;Module["_emscripten_asm_const_ptr_sync_on_main_thread"]=_emscripten_asm_const_ptr_sync_on_main_thread;Module["_emscripten_asm_const_double_sync_on_main_thread"]=_emscripten_asm_const_double_sync_on_main_thread;Module["_emscripten_asm_const_async_on_main_thread"]=_emscripten_asm_const_async_on_main_thread;Module["__Unwind_Backtrace"]=__Unwind_Backtrace;Module["__Unwind_GetIPInfo"]=__Unwind_GetIPInfo;Module["__Unwind_FindEnclosingFunction"]=__Unwind_FindEnclosingFunction;Module["listenOnce"]=listenOnce;Module["autoResumeAudioContext"]=autoResumeAudioContext;Module["getDynCaller"]=getDynCaller;Module["dynCall"]=dynCall;Module["_emscripten_exit_with_live_runtime"]=_emscripten_exit_with_live_runtime;Module["_emscripten_force_exit"]=_emscripten_force_exit;Module["_emscripten_outn"]=_emscripten_outn;Module["_emscripten_errn"]=_emscripten_errn;Module["_emscripten_throw_number"]=_emscripten_throw_number;Module["_emscripten_throw_string"]=_emscripten_throw_string;Module["_emscripten_runtime_keepalive_check"]=_emscripten_runtime_keepalive_check;Module["asmjsMangle"]=asmjsMangle;Module["___global_base"]=___global_base;Module["__emscripten_fs_load_embedded_files"]=__emscripten_fs_load_embedded_files;Module["getNativeTypeSize"]=getNativeTypeSize;Module["POINTER_SIZE"]=POINTER_SIZE;Module["onInits"]=onInits;Module["addOnInit"]=addOnInit;Module["onMains"]=onMains;Module["addOnPreMain"]=addOnPreMain;Module["onExits"]=onExits;Module["addOnExit"]=addOnExit;Module["STACK_SIZE"]=STACK_SIZE;Module["STACK_ALIGN"]=STACK_ALIGN;Module["ASSERTIONS"]=ASSERTIONS;Module["getCFunc"]=getCFunc;Module["ccall"]=ccall;Module["writeArrayToMemory"]=writeArrayToMemory;Module["cwrap"]=cwrap;Module["removeFunction"]=removeFunction;Module["_emscripten_math_cbrt"]=_emscripten_math_cbrt;Module["_emscripten_math_pow"]=_emscripten_math_pow;Module["_emscripten_math_random"]=_emscripten_math_random;Module["_emscripten_math_sign"]=_emscripten_math_sign;Module["_emscripten_math_sqrt"]=_emscripten_math_sqrt;Module["_emscripten_math_exp"]=_emscripten_math_exp;Module["_emscripten_math_expm1"]=_emscripten_math_expm1;Module["_emscripten_math_fmod"]=_emscripten_math_fmod;Module["_emscripten_math_log"]=_emscripten_math_log;Module["_emscripten_math_log1p"]=_emscripten_math_log1p;Module["_emscripten_math_log10"]=_emscripten_math_log10;Module["_emscripten_math_log2"]=_emscripten_math_log2;Module["_emscripten_math_round"]=_emscripten_math_round;Module["_emscripten_math_acos"]=_emscripten_math_acos;Module["_emscripten_math_acosh"]=_emscripten_math_acosh;Module["_emscripten_math_asin"]=_emscripten_math_asin;Module["_emscripten_math_asinh"]=_emscripten_math_asinh;Module["_emscripten_math_atan"]=_emscripten_math_atan;Module["_emscripten_math_atanh"]=_emscripten_math_atanh;Module["_emscripten_math_atan2"]=_emscripten_math_atan2;Module["_emscripten_math_cos"]=_emscripten_math_cos;Module["_emscripten_math_cosh"]=_emscripten_math_cosh;Module["_emscripten_math_hypot"]=_emscripten_math_hypot;Module["_emscripten_math_sin"]=_emscripten_math_sin;Module["_emscripten_math_sinh"]=_emscripten_math_sinh;Module["_emscripten_math_tan"]=_emscripten_math_tan;Module["_emscripten_math_tanh"]=_emscripten_math_tanh;Module["intArrayToString"]=intArrayToString;Module["AsciiToString"]=AsciiToString;Module["UTF16Decoder"]=UTF16Decoder;Module["UTF16ToString"]=UTF16ToString;Module["stringToUTF16"]=stringToUTF16;Module["lengthBytesUTF16"]=lengthBytesUTF16;Module["UTF32ToString"]=UTF32ToString;Module["stringToUTF32"]=stringToUTF32;Module["lengthBytesUTF32"]=lengthBytesUTF32;Module["JSEvents"]=JSEvents;Module["registerKeyEventCallback"]=registerKeyEventCallback;Module["findEventTarget"]=findEventTarget;Module["maybeCStringToJsString"]=maybeCStringToJsString;Module["specialHTMLTargets"]=specialHTMLTargets;Module["findCanvasEventTarget"]=findCanvasEventTarget;Module["_emscripten_set_keypress_callback_on_thread"]=_emscripten_set_keypress_callback_on_thread;Module["_emscripten_set_keydown_callback_on_thread"]=_emscripten_set_keydown_callback_on_thread;Module["_emscripten_set_keyup_callback_on_thread"]=_emscripten_set_keyup_callback_on_thread;Module["getBoundingClientRect"]=getBoundingClientRect;Module["fillMouseEventData"]=fillMouseEventData;Module["registerMouseEventCallback"]=registerMouseEventCallback;Module["_emscripten_set_click_callback_on_thread"]=_emscripten_set_click_callback_on_thread;Module["_emscripten_set_mousedown_callback_on_thread"]=_emscripten_set_mousedown_callback_on_thread;Module["_emscripten_set_mouseup_callback_on_thread"]=_emscripten_set_mouseup_callback_on_thread;Module["_emscripten_set_dblclick_callback_on_thread"]=_emscripten_set_dblclick_callback_on_thread;Module["_emscripten_set_mousemove_callback_on_thread"]=_emscripten_set_mousemove_callback_on_thread;Module["_emscripten_set_mouseenter_callback_on_thread"]=_emscripten_set_mouseenter_callback_on_thread;Module["_emscripten_set_mouseleave_callback_on_thread"]=_emscripten_set_mouseleave_callback_on_thread;Module["_emscripten_set_mouseover_callback_on_thread"]=_emscripten_set_mouseover_callback_on_thread;Module["_emscripten_set_mouseout_callback_on_thread"]=_emscripten_set_mouseout_callback_on_thread;Module["_emscripten_get_mouse_status"]=_emscripten_get_mouse_status;Module["registerWheelEventCallback"]=registerWheelEventCallback;Module["_emscripten_set_wheel_callback_on_thread"]=_emscripten_set_wheel_callback_on_thread;Module["registerUiEventCallback"]=registerUiEventCallback;Module["_emscripten_set_resize_callback_on_thread"]=_emscripten_set_resize_callback_on_thread;Module["_emscripten_set_scroll_callback_on_thread"]=_emscripten_set_scroll_callback_on_thread;Module["registerFocusEventCallback"]=registerFocusEventCallback;Module["_emscripten_set_blur_callback_on_thread"]=_emscripten_set_blur_callback_on_thread;Module["_emscripten_set_focus_callback_on_thread"]=_emscripten_set_focus_callback_on_thread;Module["_emscripten_set_focusin_callback_on_thread"]=_emscripten_set_focusin_callback_on_thread;Module["_emscripten_set_focusout_callback_on_thread"]=_emscripten_set_focusout_callback_on_thread;Module["fillDeviceOrientationEventData"]=fillDeviceOrientationEventData;Module["registerDeviceOrientationEventCallback"]=registerDeviceOrientationEventCallback;Module["_emscripten_set_deviceorientation_callback_on_thread"]=_emscripten_set_deviceorientation_callback_on_thread;Module["_emscripten_get_deviceorientation_status"]=_emscripten_get_deviceorientation_status;Module["fillDeviceMotionEventData"]=fillDeviceMotionEventData;Module["registerDeviceMotionEventCallback"]=registerDeviceMotionEventCallback;Module["_emscripten_set_devicemotion_callback_on_thread"]=_emscripten_set_devicemotion_callback_on_thread;Module["_emscripten_get_devicemotion_status"]=_emscripten_get_devicemotion_status;Module["screenOrientation"]=screenOrientation;Module["fillOrientationChangeEventData"]=fillOrientationChangeEventData;Module["registerOrientationChangeEventCallback"]=registerOrientationChangeEventCallback;Module["_emscripten_set_orientationchange_callback_on_thread"]=_emscripten_set_orientationchange_callback_on_thread;Module["_emscripten_get_orientation_status"]=_emscripten_get_orientation_status;Module["_emscripten_lock_orientation"]=_emscripten_lock_orientation;Module["_emscripten_unlock_orientation"]=_emscripten_unlock_orientation;Module["fillFullscreenChangeEventData"]=fillFullscreenChangeEventData;Module["registerFullscreenChangeEventCallback"]=registerFullscreenChangeEventCallback;Module["_emscripten_set_fullscreenchange_callback_on_thread"]=_emscripten_set_fullscreenchange_callback_on_thread;Module["_emscripten_get_fullscreen_status"]=_emscripten_get_fullscreen_status;Module["JSEvents_requestFullscreen"]=JSEvents_requestFullscreen;Module["JSEvents_resizeCanvasForFullscreen"]=JSEvents_resizeCanvasForFullscreen;Module["registerRestoreOldStyle"]=registerRestoreOldStyle;Module["getCanvasElementSize"]=getCanvasElementSize;Module["_emscripten_get_canvas_element_size"]=_emscripten_get_canvas_element_size;Module["setCanvasElementSize"]=setCanvasElementSize;Module["_emscripten_set_canvas_element_size"]=_emscripten_set_canvas_element_size;Module["currentFullscreenStrategy"]=currentFullscreenStrategy;Module["setLetterbox"]=setLetterbox;Module["hideEverythingExceptGivenElement"]=hideEverythingExceptGivenElement;Module["restoreHiddenElements"]=restoreHiddenElements;Module["restoreOldWindowedStyle"]=restoreOldWindowedStyle;Module["softFullscreenResizeWebGLRenderTarget"]=softFullscreenResizeWebGLRenderTarget;Module["doRequestFullscreen"]=doRequestFullscreen;Module["_emscripten_request_fullscreen"]=_emscripten_request_fullscreen;Module["_emscripten_request_fullscreen_strategy"]=_emscripten_request_fullscreen_strategy;Module["_emscripten_enter_soft_fullscreen"]=_emscripten_enter_soft_fullscreen;Module["_emscripten_exit_soft_fullscreen"]=_emscripten_exit_soft_fullscreen;Module["_emscripten_exit_fullscreen"]=_emscripten_exit_fullscreen;Module["fillPointerlockChangeEventData"]=fillPointerlockChangeEventData;Module["registerPointerlockChangeEventCallback"]=registerPointerlockChangeEventCallback;Module["_emscripten_set_pointerlockchange_callback_on_thread"]=_emscripten_set_pointerlockchange_callback_on_thread;Module["registerPointerlockErrorEventCallback"]=registerPointerlockErrorEventCallback;Module["_emscripten_set_pointerlockerror_callback_on_thread"]=_emscripten_set_pointerlockerror_callback_on_thread;Module["_emscripten_get_pointerlock_status"]=_emscripten_get_pointerlock_status;Module["requestPointerLock"]=requestPointerLock;Module["_emscripten_request_pointerlock"]=_emscripten_request_pointerlock;Module["_emscripten_exit_pointerlock"]=_emscripten_exit_pointerlock;Module["_emscripten_vibrate"]=_emscripten_vibrate;Module["_emscripten_vibrate_pattern"]=_emscripten_vibrate_pattern;Module["fillVisibilityChangeEventData"]=fillVisibilityChangeEventData;Module["registerVisibilityChangeEventCallback"]=registerVisibilityChangeEventCallback;Module["_emscripten_set_visibilitychange_callback_on_thread"]=_emscripten_set_visibilitychange_callback_on_thread;Module["_emscripten_get_visibility_status"]=_emscripten_get_visibility_status;Module["registerTouchEventCallback"]=registerTouchEventCallback;Module["_emscripten_set_touchstart_callback_on_thread"]=_emscripten_set_touchstart_callback_on_thread;Module["_emscripten_set_touchend_callback_on_thread"]=_emscripten_set_touchend_callback_on_thread;Module["_emscripten_set_touchmove_callback_on_thread"]=_emscripten_set_touchmove_callback_on_thread;Module["_emscripten_set_touchcancel_callback_on_thread"]=_emscripten_set_touchcancel_callback_on_thread;Module["fillGamepadEventData"]=fillGamepadEventData;Module["registerGamepadEventCallback"]=registerGamepadEventCallback;Module["_emscripten_set_gamepadconnected_callback_on_thread"]=_emscripten_set_gamepadconnected_callback_on_thread;Module["_emscripten_sample_gamepad_data"]=_emscripten_sample_gamepad_data;Module["_emscripten_set_gamepaddisconnected_callback_on_thread"]=_emscripten_set_gamepaddisconnected_callback_on_thread;Module["_emscripten_get_num_gamepads"]=_emscripten_get_num_gamepads;Module["_emscripten_get_gamepad_status"]=_emscripten_get_gamepad_status;Module["registerBeforeUnloadEventCallback"]=registerBeforeUnloadEventCallback;Module["_emscripten_set_beforeunload_callback_on_thread"]=_emscripten_set_beforeunload_callback_on_thread;Module["fillBatteryEventData"]=fillBatteryEventData;Module["battery"]=battery;Module["registerBatteryEventCallback"]=registerBatteryEventCallback;Module["_emscripten_set_batterychargingchange_callback_on_thread"]=_emscripten_set_batterychargingchange_callback_on_thread;Module["_emscripten_set_batterylevelchange_callback_on_thread"]=_emscripten_set_batterylevelchange_callback_on_thread;Module["_emscripten_get_battery_status"]=_emscripten_get_battery_status;Module["_emscripten_set_element_css_size"]=_emscripten_set_element_css_size;Module["_emscripten_get_element_css_size"]=_emscripten_get_element_css_size;Module["_emscripten_html5_remove_all_event_listeners"]=_emscripten_html5_remove_all_event_listeners;Module["_emscripten_request_animation_frame"]=_emscripten_request_animation_frame;Module["_emscripten_cancel_animation_frame"]=_emscripten_cancel_animation_frame;Module["_emscripten_request_animation_frame_loop"]=_emscripten_request_animation_frame_loop;Module["_emscripten_get_device_pixel_ratio"]=_emscripten_get_device_pixel_ratio;Module["_emscripten_get_callstack"]=_emscripten_get_callstack;Module["convertFrameToPC"]=convertFrameToPC;Module["_emscripten_return_address"]=_emscripten_return_address;Module["UNWIND_CACHE"]=UNWIND_CACHE;Module["_emscripten_stack_snapshot"]=_emscripten_stack_snapshot;Module["saveInUnwindCache"]=saveInUnwindCache;Module["_emscripten_stack_unwind_buffer"]=_emscripten_stack_unwind_buffer;Module["_emscripten_pc_get_function"]=_emscripten_pc_get_function;Module["convertPCtoSourceLocation"]=convertPCtoSourceLocation;Module["_emscripten_pc_get_file"]=_emscripten_pc_get_file;Module["_emscripten_pc_get_line"]=_emscripten_pc_get_line;Module["_emscripten_pc_get_column"]=_emscripten_pc_get_column;Module["wasiRightsToMuslOFlags"]=wasiRightsToMuslOFlags;Module["wasiOFlagsToMuslOFlags"]=wasiOFlagsToMuslOFlags;Module["_emscripten_unwind_to_js_event_loop"]=_emscripten_unwind_to_js_event_loop;Module["safeSetTimeout"]=safeSetTimeout;Module["setImmediateWrapped"]=setImmediateWrapped;Module["safeRequestAnimationFrame"]=safeRequestAnimationFrame;Module["MainLoop"]=MainLoop;Module["setMainLoop"]=setMainLoop;Module["_emscripten_set_main_loop_timing"]=_emscripten_set_main_loop_timing;Module["clearImmediateWrapped"]=clearImmediateWrapped;Module["emSetImmediate"]=emSetImmediate;Module["emClearImmediate"]=emClearImmediate;Module["emClearImmediate_deps"]=emClearImmediate_deps;Module["_emscripten_set_immediate"]=_emscripten_set_immediate;Module["_emscripten_clear_immediate"]=_emscripten_clear_immediate;Module["_emscripten_set_immediate_loop"]=_emscripten_set_immediate_loop;Module["_emscripten_set_timeout"]=_emscripten_set_timeout;Module["_emscripten_clear_timeout"]=_emscripten_clear_timeout;Module["_emscripten_set_timeout_loop"]=_emscripten_set_timeout_loop;Module["_emscripten_set_interval"]=_emscripten_set_interval;Module["_emscripten_clear_interval"]=_emscripten_clear_interval;Module["_emscripten_async_call"]=_emscripten_async_call;Module["registerPostMainLoop"]=registerPostMainLoop;Module["registerPreMainLoop"]=registerPreMainLoop;Module["_emscripten_get_main_loop_timing"]=_emscripten_get_main_loop_timing;Module["_emscripten_set_main_loop"]=_emscripten_set_main_loop;Module["_emscripten_set_main_loop_arg"]=_emscripten_set_main_loop_arg;Module["_emscripten_cancel_main_loop"]=_emscripten_cancel_main_loop;Module["_emscripten_pause_main_loop"]=_emscripten_pause_main_loop;Module["_emscripten_resume_main_loop"]=_emscripten_resume_main_loop;Module["__emscripten_push_main_loop_blocker"]=__emscripten_push_main_loop_blocker;Module["__emscripten_push_uncounted_main_loop_blocker"]=__emscripten_push_uncounted_main_loop_blocker;Module["_emscripten_set_main_loop_expected_blockers"]=_emscripten_set_main_loop_expected_blockers;Module["idsToPromises"]=idsToPromises;Module["makePromiseCallback"]=makePromiseCallback;Module["_emscripten_promise_then"]=_emscripten_promise_then;Module["_emscripten_promise_all"]=_emscripten_promise_all;Module["setPromiseResult"]=setPromiseResult;Module["_emscripten_promise_all_settled"]=_emscripten_promise_all_settled;Module["_emscripten_promise_any"]=_emscripten_promise_any;Module["_emscripten_promise_race"]=_emscripten_promise_race;Module["_emscripten_promise_await"]=_emscripten_promise_await;Module["getExceptionMessageCommon"]=getExceptionMessageCommon;Module["getCppExceptionTag"]=getCppExceptionTag;Module["getCppExceptionThrownObjectFromWebAssemblyException"]=getCppExceptionThrownObjectFromWebAssemblyException;Module["incrementExceptionRefcount"]=incrementExceptionRefcount;Module["decrementExceptionRefcount"]=decrementExceptionRefcount;Module["getExceptionMessage"]=getExceptionMessage;Module["Browser"]=Browser;Module["requestFullscreen"]=requestFullscreen;Module["setCanvasSize"]=setCanvasSize;Module["getUserMedia"]=getUserMedia;Module["createContext"]=createContext;Module["_emscripten_run_preload_plugins"]=_emscripten_run_preload_plugins;Module["Browser_asyncPrepareDataCounter"]=Browser_asyncPrepareDataCounter;Module["_emscripten_run_preload_plugins_data"]=_emscripten_run_preload_plugins_data;Module["_emscripten_async_run_script"]=_emscripten_async_run_script;Module["_emscripten_async_load_script"]=_emscripten_async_load_script;Module["_emscripten_get_window_title"]=_emscripten_get_window_title;Module["_emscripten_set_window_title"]=_emscripten_set_window_title;Module["_emscripten_get_screen_size"]=_emscripten_get_screen_size;Module["_emscripten_hide_mouse"]=_emscripten_hide_mouse;Module["_emscripten_set_canvas_size"]=_emscripten_set_canvas_size;Module["_emscripten_get_canvas_size"]=_emscripten_get_canvas_size;Module["_emscripten_create_worker"]=_emscripten_create_worker;Module["_emscripten_destroy_worker"]=_emscripten_destroy_worker;Module["_emscripten_call_worker"]=_emscripten_call_worker;Module["_emscripten_get_worker_queue_size"]=_emscripten_get_worker_queue_size;Module["_emscripten_get_preloaded_image_data"]=_emscripten_get_preloaded_image_data;Module["getPreloadedImageData"]=getPreloadedImageData;Module["getPreloadedImageData__data"]=getPreloadedImageData__data;Module["_emscripten_get_preloaded_image_data_from_FILE"]=_emscripten_get_preloaded_image_data_from_FILE;Module["wget"]=wget;Module["_emscripten_async_wget"]=_emscripten_async_wget;Module["FS_mkdirTree"]=FS_mkdirTree;Module["_emscripten_async_wget_data"]=_emscripten_async_wget_data;Module["_emscripten_async_wget2"]=_emscripten_async_wget2;Module["_emscripten_async_wget2_data"]=_emscripten_async_wget2_data;Module["_emscripten_async_wget2_abort"]=_emscripten_async_wget2_abort;Module["___asctime_r"]=___asctime_r;Module["MONTH_DAYS_REGULAR"]=MONTH_DAYS_REGULAR;Module["MONTH_DAYS_LEAP"]=MONTH_DAYS_LEAP;Module["arraySum"]=arraySum;Module["addDays"]=addDays;Module["_strptime"]=_strptime;Module["_strptime_l"]=_strptime_l;Module["__dlsym_catchup_js"]=__dlsym_catchup_js;Module["FS_readFile"]=FS_readFile;Module["FS_root"]=FS_root;Module["FS_mounts"]=FS_mounts;Module["FS_devices"]=FS_devices;Module["FS_streams"]=FS_streams;Module["FS_nextInode"]=FS_nextInode;Module["FS_nameTable"]=FS_nameTable;Module["FS_currentPath"]=FS_currentPath;Module["FS_initialized"]=FS_initialized;Module["FS_ignorePermissions"]=FS_ignorePermissions;Module["FS_trackingDelegate"]=FS_trackingDelegate;Module["FS_filesystems"]=FS_filesystems;Module["FS_syncFSRequests"]=FS_syncFSRequests;Module["FS_readFiles"]=FS_readFiles;Module["FS_lookupPath"]=FS_lookupPath;Module["FS_getPath"]=FS_getPath;Module["FS_hashName"]=FS_hashName;Module["FS_hashAddNode"]=FS_hashAddNode;Module["FS_hashRemoveNode"]=FS_hashRemoveNode;Module["FS_lookupNode"]=FS_lookupNode;Module["FS_createNode"]=FS_createNode;Module["FS_destroyNode"]=FS_destroyNode;Module["FS_isRoot"]=FS_isRoot;Module["FS_isMountpoint"]=FS_isMountpoint;Module["FS_isFile"]=FS_isFile;Module["FS_isDir"]=FS_isDir;Module["FS_isLink"]=FS_isLink;Module["FS_isChrdev"]=FS_isChrdev;Module["FS_isBlkdev"]=FS_isBlkdev;Module["FS_isFIFO"]=FS_isFIFO;Module["FS_isSocket"]=FS_isSocket;Module["FS_flagsToPermissionString"]=FS_flagsToPermissionString;Module["FS_nodePermissions"]=FS_nodePermissions;Module["FS_mayLookup"]=FS_mayLookup;Module["FS_mayCreate"]=FS_mayCreate;Module["FS_mayDelete"]=FS_mayDelete;Module["FS_mayOpen"]=FS_mayOpen;Module["FS_checkOpExists"]=FS_checkOpExists;Module["FS_nextfd"]=FS_nextfd;Module["FS_getStreamChecked"]=FS_getStreamChecked;Module["FS_getStream"]=FS_getStream;Module["FS_createStream"]=FS_createStream;Module["FS_closeStream"]=FS_closeStream;Module["FS_dupStream"]=FS_dupStream;Module["FS_doSetAttr"]=FS_doSetAttr;Module["FS_chrdev_stream_ops"]=FS_chrdev_stream_ops;Module["FS_major"]=FS_major;Module["FS_minor"]=FS_minor;Module["FS_makedev"]=FS_makedev;Module["FS_registerDevice"]=FS_registerDevice;Module["FS_getDevice"]=FS_getDevice;Module["FS_getMounts"]=FS_getMounts;Module["FS_syncfs"]=FS_syncfs;Module["FS_mount"]=FS_mount;Module["FS_unmount"]=FS_unmount;Module["FS_lookup"]=FS_lookup;Module["FS_mknod"]=FS_mknod;Module["FS_statfs"]=FS_statfs;Module["FS_statfsStream"]=FS_statfsStream;Module["FS_statfsNode"]=FS_statfsNode;Module["FS_create"]=FS_create;Module["FS_mkdir"]=FS_mkdir;Module["FS_mkdev"]=FS_mkdev;Module["FS_symlink"]=FS_symlink;Module["FS_rename"]=FS_rename;Module["FS_rmdir"]=FS_rmdir;Module["FS_readdir"]=FS_readdir;Module["FS_readlink"]=FS_readlink;Module["FS_stat"]=FS_stat;Module["FS_fstat"]=FS_fstat;Module["FS_lstat"]=FS_lstat;Module["FS_doChmod"]=FS_doChmod;Module["FS_chmod"]=FS_chmod;Module["FS_lchmod"]=FS_lchmod;Module["FS_fchmod"]=FS_fchmod;Module["FS_doChown"]=FS_doChown;Module["FS_chown"]=FS_chown;Module["FS_lchown"]=FS_lchown;Module["FS_fchown"]=FS_fchown;Module["FS_doTruncate"]=FS_doTruncate;Module["FS_truncate"]=FS_truncate;Module["FS_ftruncate"]=FS_ftruncate;Module["FS_utime"]=FS_utime;Module["FS_open"]=FS_open;Module["FS_close"]=FS_close;Module["FS_isClosed"]=FS_isClosed;Module["FS_llseek"]=FS_llseek;Module["FS_read"]=FS_read;Module["FS_write"]=FS_write;Module["FS_mmap"]=FS_mmap;Module["FS_msync"]=FS_msync;Module["FS_ioctl"]=FS_ioctl;Module["FS_writeFile"]=FS_writeFile;Module["FS_cwd"]=FS_cwd;Module["FS_chdir"]=FS_chdir;Module["FS_createDefaultDirectories"]=FS_createDefaultDirectories;Module["FS_createDefaultDevices"]=FS_createDefaultDevices;Module["FS_createSpecialDirectories"]=FS_createSpecialDirectories;Module["FS_createStandardStreams"]=FS_createStandardStreams;Module["FS_staticInit"]=FS_staticInit;Module["FS_init"]=FS_init;Module["FS_quit"]=FS_quit;Module["FS_findObject"]=FS_findObject;Module["FS_analyzePath"]=FS_analyzePath;Module["FS_createFile"]=FS_createFile;Module["FS_forceLoadFile"]=FS_forceLoadFile;Module["_setNetworkCallback"]=_setNetworkCallback;Module["_emscripten_set_socket_error_callback"]=_emscripten_set_socket_error_callback;Module["_emscripten_set_socket_open_callback"]=_emscripten_set_socket_open_callback;Module["_emscripten_set_socket_listen_callback"]=_emscripten_set_socket_listen_callback;Module["_emscripten_set_socket_connection_callback"]=_emscripten_set_socket_connection_callback;Module["_emscripten_set_socket_message_callback"]=_emscripten_set_socket_message_callback;Module["_emscripten_set_socket_close_callback"]=_emscripten_set_socket_close_callback;Module["_emscripten_webgl_enable_ANGLE_instanced_arrays"]=_emscripten_webgl_enable_ANGLE_instanced_arrays;Module["_emscripten_webgl_enable_OES_vertex_array_object"]=_emscripten_webgl_enable_OES_vertex_array_object;Module["_emscripten_webgl_enable_WEBGL_draw_buffers"]=_emscripten_webgl_enable_WEBGL_draw_buffers;Module["_emscripten_webgl_enable_WEBGL_multi_draw"]=_emscripten_webgl_enable_WEBGL_multi_draw;Module["_emscripten_webgl_enable_EXT_polygon_offset_clamp"]=_emscripten_webgl_enable_EXT_polygon_offset_clamp;Module["_emscripten_webgl_enable_EXT_clip_control"]=_emscripten_webgl_enable_EXT_clip_control;Module["_emscripten_webgl_enable_WEBGL_polygon_mode"]=_emscripten_webgl_enable_WEBGL_polygon_mode;Module["_glVertexPointer"]=_glVertexPointer;Module["_glMatrixMode"]=_glMatrixMode;Module["_glBegin"]=_glBegin;Module["_glLoadIdentity"]=_glLoadIdentity;Module["_glMultiDrawArrays"]=_glMultiDrawArrays;Module["_glMultiDrawArraysWEBGL"]=_glMultiDrawArraysWEBGL;Module["_glMultiDrawArraysANGLE"]=_glMultiDrawArraysANGLE;Module["_glMultiDrawArraysInstancedANGLE"]=_glMultiDrawArraysInstancedANGLE;Module["_glMultiDrawArraysInstancedWEBGL"]=_glMultiDrawArraysInstancedWEBGL;Module["_glMultiDrawElements"]=_glMultiDrawElements;Module["_glMultiDrawElementsWEBGL"]=_glMultiDrawElementsWEBGL;Module["_glMultiDrawElementsANGLE"]=_glMultiDrawElementsANGLE;Module["_glMultiDrawElementsInstancedANGLE"]=_glMultiDrawElementsInstancedANGLE;Module["_glMultiDrawElementsInstancedWEBGL"]=_glMultiDrawElementsInstancedWEBGL;Module["_glClearDepth"]=_glClearDepth;Module["_glDepthRange"]=_glDepthRange;Module["_emscripten_glVertexPointer"]=_emscripten_glVertexPointer;Module["_emscripten_glMatrixMode"]=_emscripten_glMatrixMode;Module["_emscripten_glBegin"]=_emscripten_glBegin;Module["_emscripten_glLoadIdentity"]=_emscripten_glLoadIdentity;Module["_emscripten_glMultiDrawArrays"]=_emscripten_glMultiDrawArrays;Module["_emscripten_glMultiDrawArraysANGLE"]=_emscripten_glMultiDrawArraysANGLE;Module["_emscripten_glMultiDrawArraysWEBGL"]=_emscripten_glMultiDrawArraysWEBGL;Module["_emscripten_glMultiDrawArraysInstancedANGLE"]=_emscripten_glMultiDrawArraysInstancedANGLE;Module["_emscripten_glMultiDrawArraysInstancedWEBGL"]=_emscripten_glMultiDrawArraysInstancedWEBGL;Module["_emscripten_glMultiDrawElements"]=_emscripten_glMultiDrawElements;Module["_emscripten_glMultiDrawElementsANGLE"]=_emscripten_glMultiDrawElementsANGLE;Module["_emscripten_glMultiDrawElementsWEBGL"]=_emscripten_glMultiDrawElementsWEBGL;Module["_emscripten_glMultiDrawElementsInstancedANGLE"]=_emscripten_glMultiDrawElementsInstancedANGLE;Module["_emscripten_glMultiDrawElementsInstancedWEBGL"]=_emscripten_glMultiDrawElementsInstancedWEBGL;Module["_emscripten_glClearDepth"]=_emscripten_glClearDepth;Module["_emscripten_glDepthRange"]=_emscripten_glDepthRange;Module["_glGetBufferSubData"]=_glGetBufferSubData;Module["_glDrawArraysInstancedBaseInstanceWEBGL"]=_glDrawArraysInstancedBaseInstanceWEBGL;Module["_glDrawArraysInstancedBaseInstance"]=_glDrawArraysInstancedBaseInstance;Module["_glDrawArraysInstancedBaseInstanceANGLE"]=_glDrawArraysInstancedBaseInstanceANGLE;Module["_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL"]=_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL;Module["_glDrawElementsInstancedBaseVertexBaseInstanceANGLE"]=_glDrawElementsInstancedBaseVertexBaseInstanceANGLE;Module["_emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance"]=_emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance;Module["_glMultiDrawArraysInstancedBaseInstanceWEBGL"]=_glMultiDrawArraysInstancedBaseInstanceWEBGL;Module["_glMultiDrawArraysInstancedBaseInstanceANGLE"]=_glMultiDrawArraysInstancedBaseInstanceANGLE;Module["_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL"]=_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL;Module["_glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE"]=_glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE;Module["_emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance"]=_emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance;Module["_emscripten_glGetBufferSubData"]=_emscripten_glGetBufferSubData;Module["_emscripten_glDrawArraysInstancedBaseInstanceWEBGL"]=_emscripten_glDrawArraysInstancedBaseInstanceWEBGL;Module["_emscripten_glDrawArraysInstancedBaseInstance"]=_emscripten_glDrawArraysInstancedBaseInstance;Module["_emscripten_glDrawArraysInstancedBaseInstanceANGLE"]=_emscripten_glDrawArraysInstancedBaseInstanceANGLE;Module["_emscripten_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL"]=_emscripten_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL;Module["_emscripten_glDrawElementsInstancedBaseVertexBaseInstanceANGLE"]=_emscripten_glDrawElementsInstancedBaseVertexBaseInstanceANGLE;Module["_emscripten_glMultiDrawArraysInstancedBaseInstanceWEBGL"]=_emscripten_glMultiDrawArraysInstancedBaseInstanceWEBGL;Module["_emscripten_glMultiDrawArraysInstancedBaseInstanceANGLE"]=_emscripten_glMultiDrawArraysInstancedBaseInstanceANGLE;Module["_emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL"]=_emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL;Module["_emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE"]=_emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE;Module["ALLOC_NORMAL"]=ALLOC_NORMAL;Module["ALLOC_STACK"]=ALLOC_STACK;Module["allocate"]=allocate;Module["writeStringToMemory"]=writeStringToMemory;Module["writeAsciiToMemory"]=writeAsciiToMemory;Module["allocateUTF8"]=allocateUTF8;Module["allocateUTF8OnStack"]=allocateUTF8OnStack;Module["demangle"]=demangle;Module["stackTrace"]=stackTrace;Module["print"]=print;Module["printErr"]=printErr;Module["jstoi_s"]=jstoi_s;Module["_emscripten_is_main_browser_thread"]=_emscripten_is_main_browser_thread;Module["webSockets"]=webSockets;Module["WS"]=WS;Module["_emscripten_websocket_get_ready_state"]=_emscripten_websocket_get_ready_state;Module["_emscripten_websocket_get_buffered_amount"]=_emscripten_websocket_get_buffered_amount;Module["_emscripten_websocket_get_extensions"]=_emscripten_websocket_get_extensions;Module["_emscripten_websocket_get_extensions_length"]=_emscripten_websocket_get_extensions_length;Module["_emscripten_websocket_get_protocol"]=_emscripten_websocket_get_protocol;Module["_emscripten_websocket_get_protocol_length"]=_emscripten_websocket_get_protocol_length;Module["_emscripten_websocket_get_url"]=_emscripten_websocket_get_url;Module["_emscripten_websocket_get_url_length"]=_emscripten_websocket_get_url_length;Module["_emscripten_websocket_set_onopen_callback_on_thread"]=_emscripten_websocket_set_onopen_callback_on_thread;Module["_emscripten_websocket_set_onerror_callback_on_thread"]=_emscripten_websocket_set_onerror_callback_on_thread;Module["_emscripten_websocket_set_onclose_callback_on_thread"]=_emscripten_websocket_set_onclose_callback_on_thread;Module["_emscripten_websocket_set_onmessage_callback_on_thread"]=_emscripten_websocket_set_onmessage_callback_on_thread;Module["_emscripten_websocket_new"]=_emscripten_websocket_new;Module["_emscripten_websocket_send_utf8_text"]=_emscripten_websocket_send_utf8_text;Module["_emscripten_websocket_send_binary"]=_emscripten_websocket_send_binary;Module["_emscripten_websocket_close"]=_emscripten_websocket_close;Module["_emscripten_websocket_delete"]=_emscripten_websocket_delete;Module["_emscripten_websocket_is_supported"]=_emscripten_websocket_is_supported;Module["_emscripten_websocket_deinitialize"]=_emscripten_websocket_deinitialize;Module["writeGLArray"]=writeGLArray;Module["webglPowerPreferences"]=webglPowerPreferences;Module["_emscripten_webgl_create_context"]=_emscripten_webgl_create_context;Module["_emscripten_webgl_do_create_context"]=_emscripten_webgl_do_create_context;Module["_emscripten_webgl_get_current_context"]=_emscripten_webgl_get_current_context;Module["_emscripten_webgl_do_get_current_context"]=_emscripten_webgl_do_get_current_context;Module["_emscripten_webgl_commit_frame"]=_emscripten_webgl_commit_frame;Module["_emscripten_webgl_do_commit_frame"]=_emscripten_webgl_do_commit_frame;Module["_emscripten_webgl_make_context_current"]=_emscripten_webgl_make_context_current;Module["_emscripten_webgl_get_drawing_buffer_size"]=_emscripten_webgl_get_drawing_buffer_size;Module["_emscripten_webgl_get_context_attributes"]=_emscripten_webgl_get_context_attributes;Module["_emscripten_webgl_destroy_context"]=_emscripten_webgl_destroy_context;Module["_emscripten_webgl_enable_extension"]=_emscripten_webgl_enable_extension;Module["_emscripten_supports_offscreencanvas"]=_emscripten_supports_offscreencanvas;Module["registerWebGlEventCallback"]=registerWebGlEventCallback;Module["_emscripten_set_webglcontextlost_callback_on_thread"]=_emscripten_set_webglcontextlost_callback_on_thread;Module["_emscripten_set_webglcontextrestored_callback_on_thread"]=_emscripten_set_webglcontextrestored_callback_on_thread;Module["_emscripten_is_webgl_context_lost"]=_emscripten_is_webgl_context_lost;Module["_emscripten_webgl_get_supported_extensions"]=_emscripten_webgl_get_supported_extensions;Module["_emscripten_webgl_get_program_parameter_d"]=_emscripten_webgl_get_program_parameter_d;Module["_emscripten_webgl_get_program_info_log_utf8"]=_emscripten_webgl_get_program_info_log_utf8;Module["_emscripten_webgl_get_shader_parameter_d"]=_emscripten_webgl_get_shader_parameter_d;Module["_emscripten_webgl_get_shader_info_log_utf8"]=_emscripten_webgl_get_shader_info_log_utf8;Module["_emscripten_webgl_get_shader_source_utf8"]=_emscripten_webgl_get_shader_source_utf8;Module["_emscripten_webgl_get_vertex_attrib_d"]=_emscripten_webgl_get_vertex_attrib_d;Module["_emscripten_webgl_get_vertex_attrib_o"]=_emscripten_webgl_get_vertex_attrib_o;Module["_emscripten_webgl_get_vertex_attrib_v"]=_emscripten_webgl_get_vertex_attrib_v;Module["_emscripten_webgl_get_uniform_d"]=_emscripten_webgl_get_uniform_d;Module["_emscripten_webgl_get_uniform_v"]=_emscripten_webgl_get_uniform_v;Module["_emscripten_webgl_get_parameter_v"]=_emscripten_webgl_get_parameter_v;Module["_emscripten_webgl_get_parameter_d"]=_emscripten_webgl_get_parameter_d;Module["_emscripten_webgl_get_parameter_o"]=_emscripten_webgl_get_parameter_o;Module["_emscripten_webgl_get_parameter_utf8"]=_emscripten_webgl_get_parameter_utf8;Module["_emscripten_webgl_get_parameter_i64v"]=_emscripten_webgl_get_parameter_i64v;Module["EGL"]=EGL;Module["_eglGetDisplay"]=_eglGetDisplay;Module["_eglInitialize"]=_eglInitialize;Module["_eglTerminate"]=_eglTerminate;Module["_eglGetConfigs"]=_eglGetConfigs;Module["_eglChooseConfig"]=_eglChooseConfig;Module["_eglGetConfigAttrib"]=_eglGetConfigAttrib;Module["_eglCreateWindowSurface"]=_eglCreateWindowSurface;Module["_eglDestroySurface"]=_eglDestroySurface;Module["_eglCreateContext"]=_eglCreateContext;Module["_eglDestroyContext"]=_eglDestroyContext;Module["_eglQuerySurface"]=_eglQuerySurface;Module["_eglQueryContext"]=_eglQueryContext;Module["_eglGetError"]=_eglGetError;Module["_eglQueryString"]=_eglQueryString;Module["_eglBindAPI"]=_eglBindAPI;Module["_eglQueryAPI"]=_eglQueryAPI;Module["_eglWaitClient"]=_eglWaitClient;Module["_eglWaitNative"]=_eglWaitNative;Module["_eglWaitGL"]=_eglWaitGL;Module["_eglSwapInterval"]=_eglSwapInterval;Module["_eglMakeCurrent"]=_eglMakeCurrent;Module["_eglGetCurrentContext"]=_eglGetCurrentContext;Module["_eglGetCurrentSurface"]=_eglGetCurrentSurface;Module["_eglGetCurrentDisplay"]=_eglGetCurrentDisplay;Module["_eglSwapBuffers"]=_eglSwapBuffers;Module["_eglReleaseThread"]=_eglReleaseThread;Module["SDL"]=SDL;Module["_SDL_GetTicks"]=_SDL_GetTicks;Module["_SDL_LockSurface"]=_SDL_LockSurface;Module["_SDL_Linked_Version"]=_SDL_Linked_Version;Module["_SDL_Init"]=_SDL_Init;Module["_SDL_WasInit"]=_SDL_WasInit;Module["_SDL_GetVideoInfo"]=_SDL_GetVideoInfo;Module["_SDL_ListModes"]=_SDL_ListModes;Module["_SDL_VideoModeOK"]=_SDL_VideoModeOK;Module["_SDL_AudioDriverName"]=_SDL_AudioDriverName;Module["_SDL_VideoDriverName"]=_SDL_VideoDriverName;Module["_SDL_SetVideoMode"]=_SDL_SetVideoMode;Module["_SDL_GetVideoSurface"]=_SDL_GetVideoSurface;Module["_SDL_AudioQuit"]=_SDL_AudioQuit;Module["_SDL_VideoQuit"]=_SDL_VideoQuit;Module["_SDL_QuitSubSystem"]=_SDL_QuitSubSystem;Module["_SDL_Quit"]=_SDL_Quit;Module["_SDL_UnlockSurface"]=_SDL_UnlockSurface;Module["_SDL_Flip"]=_SDL_Flip;Module["_SDL_UpdateRect"]=_SDL_UpdateRect;Module["_SDL_UpdateRects"]=_SDL_UpdateRects;Module["_SDL_Delay"]=_SDL_Delay;Module["_SDL_WM_SetCaption"]=_SDL_WM_SetCaption;Module["_SDL_EnableKeyRepeat"]=_SDL_EnableKeyRepeat;Module["_SDL_GetKeyboardState"]=_SDL_GetKeyboardState;Module["_SDL_GetKeyState"]=_SDL_GetKeyState;Module["_SDL_GetKeyName"]=_SDL_GetKeyName;Module["_SDL_GetModState"]=_SDL_GetModState;Module["_SDL_GetMouseState"]=_SDL_GetMouseState;Module["_SDL_WarpMouse"]=_SDL_WarpMouse;Module["_SDL_ShowCursor"]=_SDL_ShowCursor;Module["_SDL_GetError"]=_SDL_GetError;Module["_SDL_SetError"]=_SDL_SetError;Module["_SDL_CreateRGBSurface"]=_SDL_CreateRGBSurface;Module["_SDL_CreateRGBSurfaceFrom"]=_SDL_CreateRGBSurfaceFrom;Module["_SDL_ConvertSurface"]=_SDL_ConvertSurface;Module["_SDL_DisplayFormat"]=_SDL_DisplayFormat;Module["_SDL_DisplayFormatAlpha"]=_SDL_DisplayFormatAlpha;Module["_SDL_FreeSurface"]=_SDL_FreeSurface;Module["_SDL_UpperBlit"]=_SDL_UpperBlit;Module["_SDL_UpperBlitScaled"]=_SDL_UpperBlitScaled;Module["_SDL_LowerBlit"]=_SDL_LowerBlit;Module["_SDL_LowerBlitScaled"]=_SDL_LowerBlitScaled;Module["_SDL_GetClipRect"]=_SDL_GetClipRect;Module["_SDL_SetClipRect"]=_SDL_SetClipRect;Module["_SDL_FillRect"]=_SDL_FillRect;Module["_zoomSurface"]=_zoomSurface;Module["_rotozoomSurface"]=_rotozoomSurface;Module["_SDL_SetAlpha"]=_SDL_SetAlpha;Module["_SDL_SetColorKey"]=_SDL_SetColorKey;Module["_SDL_PollEvent"]=_SDL_PollEvent;Module["_SDL_PushEvent"]=_SDL_PushEvent;Module["_SDL_PeepEvents"]=_SDL_PeepEvents;Module["_SDL_PumpEvents"]=_SDL_PumpEvents;Module["_emscripten_SDL_SetEventHandler"]=_emscripten_SDL_SetEventHandler;Module["_SDL_SetColors"]=_SDL_SetColors;Module["_SDL_SetPalette"]=_SDL_SetPalette;Module["_SDL_MapRGB"]=_SDL_MapRGB;Module["_SDL_MapRGBA"]=_SDL_MapRGBA;Module["_SDL_GetRGB"]=_SDL_GetRGB;Module["_SDL_GetRGBA"]=_SDL_GetRGBA;Module["_SDL_GetAppState"]=_SDL_GetAppState;Module["_SDL_WM_GrabInput"]=_SDL_WM_GrabInput;Module["_SDL_WM_ToggleFullScreen"]=_SDL_WM_ToggleFullScreen;Module["_IMG_Init"]=_IMG_Init;Module["_IMG_Load_RW"]=_IMG_Load_RW;Module["_SDL_FreeRW"]=_SDL_FreeRW;Module["_SDL_LoadBMP_RW"]=_SDL_LoadBMP_RW;Module["_IMG_Load"]=_IMG_Load;Module["_SDL_RWFromFile"]=_SDL_RWFromFile;Module["_IMG_Quit"]=_IMG_Quit;Module["_SDL_OpenAudio"]=_SDL_OpenAudio;Module["_SDL_PauseAudio"]=_SDL_PauseAudio;Module["_SDL_CloseAudio"]=_SDL_CloseAudio;Module["_SDL_LockAudio"]=_SDL_LockAudio;Module["_SDL_UnlockAudio"]=_SDL_UnlockAudio;Module["_SDL_CreateMutex"]=_SDL_CreateMutex;Module["_SDL_mutexP"]=_SDL_mutexP;Module["_SDL_mutexV"]=_SDL_mutexV;Module["_SDL_DestroyMutex"]=_SDL_DestroyMutex;Module["_SDL_CreateCond"]=_SDL_CreateCond;Module["_SDL_CondSignal"]=_SDL_CondSignal;Module["_SDL_CondWait"]=_SDL_CondWait;Module["_SDL_DestroyCond"]=_SDL_DestroyCond;Module["_SDL_StartTextInput"]=_SDL_StartTextInput;Module["_SDL_StopTextInput"]=_SDL_StopTextInput;Module["_Mix_Init"]=_Mix_Init;Module["_Mix_Quit"]=_Mix_Quit;Module["_Mix_OpenAudio"]=_Mix_OpenAudio;Module["_Mix_CloseAudio"]=_Mix_CloseAudio;Module["_Mix_AllocateChannels"]=_Mix_AllocateChannels;Module["_Mix_ChannelFinished"]=_Mix_ChannelFinished;Module["_Mix_Volume"]=_Mix_Volume;Module["_Mix_SetPanning"]=_Mix_SetPanning;Module["_Mix_LoadWAV_RW"]=_Mix_LoadWAV_RW;Module["_Mix_LoadWAV"]=_Mix_LoadWAV;Module["_Mix_QuickLoad_RAW"]=_Mix_QuickLoad_RAW;Module["_Mix_FreeChunk"]=_Mix_FreeChunk;Module["_Mix_ReserveChannels"]=_Mix_ReserveChannels;Module["_Mix_PlayChannelTimed"]=_Mix_PlayChannelTimed;Module["_Mix_HaltChannel"]=_Mix_HaltChannel;Module["_Mix_FadingChannel"]=_Mix_FadingChannel;Module["_Mix_HookMusicFinished"]=_Mix_HookMusicFinished;Module["_Mix_HaltMusic"]=_Mix_HaltMusic;Module["_Mix_VolumeMusic"]=_Mix_VolumeMusic;Module["_Mix_LoadMUS_RW"]=_Mix_LoadMUS_RW;Module["_Mix_LoadMUS"]=_Mix_LoadMUS;Module["_Mix_FreeMusic"]=_Mix_FreeMusic;Module["_Mix_PlayMusic"]=_Mix_PlayMusic;Module["_Mix_PauseMusic"]=_Mix_PauseMusic;Module["_Mix_ResumeMusic"]=_Mix_ResumeMusic;Module["_Mix_FadeInMusicPos"]=_Mix_FadeInMusicPos;Module["_Mix_FadeOutMusic"]=_Mix_FadeOutMusic;Module["_Mix_PlayingMusic"]=_Mix_PlayingMusic;Module["_Mix_Playing"]=_Mix_Playing;Module["_Mix_Pause"]=_Mix_Pause;Module["_Mix_Paused"]=_Mix_Paused;Module["_Mix_PausedMusic"]=_Mix_PausedMusic;Module["_Mix_Resume"]=_Mix_Resume;Module["_TTF_Init"]=_TTF_Init;Module["_TTF_OpenFont"]=_TTF_OpenFont;Module["_TTF_CloseFont"]=_TTF_CloseFont;Module["_TTF_RenderText_Solid"]=_TTF_RenderText_Solid;Module["_TTF_RenderText_Blended"]=_TTF_RenderText_Blended;Module["_TTF_RenderText_Shaded"]=_TTF_RenderText_Shaded;Module["_TTF_RenderUTF8_Solid"]=_TTF_RenderUTF8_Solid;Module["_TTF_SizeUTF8"]=_TTF_SizeUTF8;Module["_TTF_SizeText"]=_TTF_SizeText;Module["_TTF_GlyphMetrics"]=_TTF_GlyphMetrics;Module["_TTF_FontAscent"]=_TTF_FontAscent;Module["_TTF_FontDescent"]=_TTF_FontDescent;Module["_TTF_FontHeight"]=_TTF_FontHeight;Module["_TTF_FontLineSkip"]=_TTF_FontLineSkip;Module["_TTF_Quit"]=_TTF_Quit;Module["SDL_gfx"]=SDL_gfx;Module["_boxColor"]=_boxColor;Module["_boxRGBA"]=_boxRGBA;Module["_rectangleColor"]=_rectangleColor;Module["_rectangleRGBA"]=_rectangleRGBA;Module["_ellipseColor"]=_ellipseColor;Module["_ellipseRGBA"]=_ellipseRGBA;Module["_filledEllipseColor"]=_filledEllipseColor;Module["_filledEllipseRGBA"]=_filledEllipseRGBA;Module["_lineColor"]=_lineColor;Module["_lineRGBA"]=_lineRGBA;Module["_pixelRGBA"]=_pixelRGBA;Module["_SDL_GL_SetAttribute"]=_SDL_GL_SetAttribute;Module["_SDL_GL_GetAttribute"]=_SDL_GL_GetAttribute;Module["_SDL_GL_SwapBuffers"]=_SDL_GL_SwapBuffers;Module["_SDL_GL_ExtensionSupported"]=_SDL_GL_ExtensionSupported;Module["_SDL_DestroyWindow"]=_SDL_DestroyWindow;Module["_SDL_DestroyRenderer"]=_SDL_DestroyRenderer;Module["_SDL_GetWindowFlags"]=_SDL_GetWindowFlags;Module["_SDL_GL_SwapWindow"]=_SDL_GL_SwapWindow;Module["_SDL_GL_MakeCurrent"]=_SDL_GL_MakeCurrent;Module["_SDL_GL_DeleteContext"]=_SDL_GL_DeleteContext;Module["_SDL_GL_GetSwapInterval"]=_SDL_GL_GetSwapInterval;Module["_SDL_GL_SetSwapInterval"]=_SDL_GL_SetSwapInterval;Module["_SDL_SetWindowTitle"]=_SDL_SetWindowTitle;Module["_SDL_GetWindowSize"]=_SDL_GetWindowSize;Module["_SDL_LogSetOutputFunction"]=_SDL_LogSetOutputFunction;Module["_SDL_SetWindowFullscreen"]=_SDL_SetWindowFullscreen;Module["_SDL_ClearError"]=_SDL_ClearError;Module["_SDL_SetGamma"]=_SDL_SetGamma;Module["_SDL_SetGammaRamp"]=_SDL_SetGammaRamp;Module["_SDL_NumJoysticks"]=_SDL_NumJoysticks;Module["_SDL_JoystickName"]=_SDL_JoystickName;Module["_SDL_JoystickOpen"]=_SDL_JoystickOpen;Module["_SDL_JoystickOpened"]=_SDL_JoystickOpened;Module["_SDL_JoystickIndex"]=_SDL_JoystickIndex;Module["_SDL_JoystickNumAxes"]=_SDL_JoystickNumAxes;Module["_SDL_JoystickNumBalls"]=_SDL_JoystickNumBalls;Module["_SDL_JoystickNumHats"]=_SDL_JoystickNumHats;Module["_SDL_JoystickNumButtons"]=_SDL_JoystickNumButtons;Module["_SDL_JoystickUpdate"]=_SDL_JoystickUpdate;Module["_SDL_JoystickEventState"]=_SDL_JoystickEventState;Module["_SDL_JoystickGetAxis"]=_SDL_JoystickGetAxis;Module["_SDL_JoystickGetHat"]=_SDL_JoystickGetHat;Module["_SDL_JoystickGetBall"]=_SDL_JoystickGetBall;Module["_SDL_JoystickGetButton"]=_SDL_JoystickGetButton;Module["_SDL_JoystickClose"]=_SDL_JoystickClose;Module["_SDL_InitSubSystem"]=_SDL_InitSubSystem;Module["_SDL_RWFromConstMem"]=_SDL_RWFromConstMem;Module["_SDL_RWFromMem"]=_SDL_RWFromMem;Module["_SDL_GetNumAudioDrivers"]=_SDL_GetNumAudioDrivers;Module["_SDL_GetCurrentAudioDriver"]=_SDL_GetCurrentAudioDriver;Module["_SDL_GetScancodeFromKey"]=_SDL_GetScancodeFromKey;Module["_SDL_GetAudioDriver"]=_SDL_GetAudioDriver;Module["_SDL_EnableUNICODE"]=_SDL_EnableUNICODE;Module["_SDL_AddTimer"]=_SDL_AddTimer;Module["_SDL_RemoveTimer"]=_SDL_RemoveTimer;Module["_SDL_CreateThread"]=_SDL_CreateThread;Module["_SDL_WaitThread"]=_SDL_WaitThread;Module["_SDL_GetThreadID"]=_SDL_GetThreadID;Module["_SDL_ThreadID"]=_SDL_ThreadID;Module["_SDL_AllocRW"]=_SDL_AllocRW;Module["_SDL_CondBroadcast"]=_SDL_CondBroadcast;Module["_SDL_CondWaitTimeout"]=_SDL_CondWaitTimeout;Module["_SDL_WM_IconifyWindow"]=_SDL_WM_IconifyWindow;Module["_Mix_SetPostMix"]=_Mix_SetPostMix;Module["_Mix_VolumeChunk"]=_Mix_VolumeChunk;Module["_Mix_SetPosition"]=_Mix_SetPosition;Module["_Mix_QuerySpec"]=_Mix_QuerySpec;Module["_Mix_FadeInChannelTimed"]=_Mix_FadeInChannelTimed;Module["_Mix_FadeOutChannel"]=_Mix_FadeOutChannel;Module["_Mix_Linked_Version"]=_Mix_Linked_Version;Module["_SDL_SaveBMP_RW"]=_SDL_SaveBMP_RW;Module["_SDL_WM_SetIcon"]=_SDL_WM_SetIcon;Module["_SDL_HasRDTSC"]=_SDL_HasRDTSC;Module["_SDL_HasMMX"]=_SDL_HasMMX;Module["_SDL_HasMMXExt"]=_SDL_HasMMXExt;Module["_SDL_Has3DNow"]=_SDL_Has3DNow;Module["_SDL_Has3DNowExt"]=_SDL_Has3DNowExt;Module["_SDL_HasSSE"]=_SDL_HasSSE;Module["_SDL_HasSSE2"]=_SDL_HasSSE2;Module["_SDL_HasAltiVec"]=_SDL_HasAltiVec;var ASM_CONSTS={3473994:()=>{throw new Error("intentionally triggered fatal error!")},3474051:()=>{wasmImports["open64"]=wasmImports["open"]},3474100:()=>jspiSupported};function console_error(msg){let jsmsg=UTF8ToString(msg);console.error(jsmsg)}function console_error_obj(obj){console.error(obj)}function new_error(type,msg,err){return new API.PythonError(UTF8ToString(type),msg,err)}new_error.sig="eiei";function fail_test(){API.fail_test=true}fail_test.sig="v";function capture_stderr(){API.capture_stderr()}capture_stderr.sig="v";function restore_stderr(){return API.restore_stderr()}restore_stderr.sig="e";function raw_call_js(func){func()}raw_call_js.sig="ve";function hiwire_invalid_ref_js(type,ref){API.fail_test=!!1;if(type===1&&!ref){if(_PyErr_Occurred()){const e=_wrap_exception();console.error("Pyodide internal error: Argument to hiwire_get is falsy. This was "+"probably because the Python error indicator was set when get_value was "+"called. The Python error that caused this was:",e);throw e}else{const msg="Pyodide internal error: Argument to hiwire_get is falsy (but error "+"indicator is not set).";console.error(msg);throw new Error(msg)}}const typestr={[1]:"get",[2]:"incref",[3]:"decref"}[type];const msg=`hiwire_${typestr} on invalid reference ${ref}. This is most likely due `+"to use after free. It may also be due to memory corruption.";console.error(msg);throw new Error(msg)}hiwire_invalid_ref_js.sig="vii";function set_pyodide_module(mod){API._pyodide=mod}set_pyodide_module.sig="ve";function js2python_immutable_js(value){try{let result=Module.js2python_convertImmutable(value);if(result!==undefined){return result}return 0}catch(e){Module.handle_js_error(e);return 0}errNoRet()}js2python_immutable_js.sig="ie";function js2python_js(value){try{let result=Module.js2python_convertImmutable(value);if(result!==undefined){return result}return _JsProxy_create(value)}catch(e){Module.handle_js_error(e);return 0}errNoRet()}js2python_js.sig="ie";function js2python_convert(v,depth,defaultConverter){try{return Module.js2python_convert(v,{depth,defaultConverter})}catch(e){Module.handle_js_error(e);return 0}errNoRet()}js2python_convert.sig="ieie";function isReservedWord(word){if(!Module.pythonReservedWords){Module.pythonReservedWords=new Set(["False","await","else","import","pass","None","break","except","in","raise","True","class","finally","is","return","and","continue","for","lambda","try","as","def","from","nonlocal","while","assert","del","global","not","with","async","elif","if","or","yield"])}return Module.pythonReservedWords.has(word)}function normalizeReservedWords(word){const noTrailing_=word.replace(/_*$/,"");if(!isReservedWord(noTrailing_)){return word}if(noTrailing_!==word){return word.slice(0,-1)}return word}function JsProxy_GetAttr_js(jsobj,ptrkey){try{const jskey=normalizeReservedWords(UTF8ToString(ptrkey));const result=jsobj[jskey];if(result===undefined&&!(jskey in jsobj)){return Module.error}return result}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsProxy_GetAttr_js.sig="eei";function JsProxy_SetAttr_js(jsobj,ptrkey,jsval){try{let jskey=normalizeReservedWords(UTF8ToString(ptrkey));jsobj[jskey]=jsval}catch(e){Module.handle_js_error(e);return-1}return 0}JsProxy_SetAttr_js.sig="ieie";function JsProxy_DelAttr_js(jsobj,ptrkey){try{let jskey=normalizeReservedWords(UTF8ToString(ptrkey));delete jsobj[jskey]}catch(e){Module.handle_js_error(e);return-1}return 0}JsProxy_DelAttr_js.sig="iei";function JsProxy_GetIter_js(obj){try{return obj[Symbol.iterator]()}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsProxy_GetIter_js.sig="ee";function handle_next_result_js(res,done,msg){try{let errmsg;if(typeof res!=="object"){errmsg=`Result should have type "object" not "${typeof res}"`}else if(typeof res.done==="undefined"){if(typeof res.then==="function"){errmsg=`Result was a promise, use anext() / asend() / athrow() instead.`}else{errmsg=`Result has no "done" field.`}}if(errmsg){HEAPU32[(msg>>2)+0>>>0]=stringToNewUTF8(errmsg);HEAPU32[(done>>2)+0>>>0]=-1}HEAPU32[(done>>2)+0>>>0]=res.done;return res.value}catch(e){Module.handle_js_error(e);return-1}return 0}handle_next_result_js.sig="eeii";function JsException_new_helper(name_ptr,message_ptr,stack_ptr){try{let name=UTF8ToString(name_ptr);let message=UTF8ToString(message_ptr);let stack=UTF8ToString(stack_ptr);return API.deserializeError(name,message,stack)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsException_new_helper.sig="eiii";function JsProxy_GetAsyncIter_js(obj){try{return obj[Symbol.asyncIterator]()}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsProxy_GetAsyncIter_js.sig="ee";function _agen_handle_result_js(p,msg,set_result,set_exception,closing){try{let errmsg;if(typeof p!=="object"){errmsg=`Result of anext() should be object not ${typeof p}`}else if(typeof p.then!=="function"){if(typeof p.done==="boolean"){errmsg=`Result of anext() was not a promise, use next() instead.`}else{errmsg=`Result of anext() was not a promise.`}}if(errmsg){HEAPU32[(msg>>2)+0>>>0]=stringToNewUTF8(errmsg);return-1}_Py_IncRef(set_result);_Py_IncRef(set_exception);p.then(({done,value})=>{__agen_handle_result_js_c(set_result,set_exception,done,value,closing)},err=>{__agen_handle_result_js_c(set_result,set_exception,-1,err,closing)}).finally(()=>{_Py_DecRef(set_result);_Py_DecRef(set_exception)});return 0}catch(e){Module.handle_js_error(e);return-1}return 0}_agen_handle_result_js.sig="ieiiii";function get_length_helper(val){try{let result;if(typeof val.size==="number"){result=val.size}else if(typeof val.length==="number"){result=val.length}else{return-2}if(result<0){return-3}if(result>2147483647){return-4}return result}catch(e){Module.handle_js_error(e);return-1}return 0}get_length_helper.sig="ie";function get_length_string(val){try{let result;if(typeof val.size==="number"){result=val.size}else if(typeof val.length==="number"){result=val.length}return stringToNewUTF8(" "+result.toString())}catch(e){Module.handle_js_error(e);return 0}errNoRet()}get_length_string.sig="ie";function destroy_jsarray_entries(array){for(let v of array){try{if(typeof v.destroy==="function"){v.destroy()}}catch(e){console.warn("Weird error:",e)}}}destroy_jsarray_entries.sig="ve";function JsArray_repeat_js(o,count){try{return Array.from({length:count},()=>o).flat()}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsArray_repeat_js.sig="eei";function JsArray_inplace_repeat_js(o,count){try{o.splice(0,o.length,...Array.from({length:count},()=>o).flat())}catch(e){Module.handle_js_error(e);return-1}return 0}JsArray_inplace_repeat_js.sig="iei";function JsArray_reversed_iterator(array){return new ReversedIterator(array)}class ReversedIterator{constructor(array){this._array=array;this._i=array.length-1}__length_hint__(){return this._array.length}[Symbol.toStringTag](){return"ReverseIterator"}next(){const i=this._i;const a=this._array;const done=i<0;const value=done?undefined:a[i];this._i--;return{done,value}}}JsArray_reversed_iterator.sig="ee";function JsArray_index_js(o,v,start,stop){try{for(let i=start;i{let c=s.charCodeAt(0);return c<48||c>57}).map(word=>isReservedWord(word.replace(/_*$/,""))?word+"_":word))}while(jsobj=Object.getPrototypeOf(jsobj));return result}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsProxy_Dir_js.sig="ee";function JsProxy_Bool_js(val){try{if(!val){return!!0}if(val.size===0){if(/HTML[A-Za-z]*Element/.test(getTypeTag(val))){return!!1}return!!0}if(val.length===0&&JsvArray_Check(val)){return!!0}if(val.byteLength===0){return!!0}return!!1}catch(e){return!!0}}JsProxy_Bool_js.sig="ie";function JsObjMap_GetIter_js(obj){try{return Module.iterObject(obj)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsObjMap_GetIter_js.sig="ee";function JsObjMap_length_js(obj){try{let length=0;for(let _ of Module.iterObject(obj)){length++}return length}catch(e){Module.handle_js_error(e);return-1}return 0}JsObjMap_length_js.sig="ie";function JsObjMap_subscript_js(obj,key){try{if(!Object.prototype.hasOwnProperty.call(obj,key)){return Module.error}return obj[key]}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsObjMap_subscript_js.sig="eee";function JsObjMap_ass_subscript_js(obj,key,value){try{if(value===Module.error){if(!Object.prototype.hasOwnProperty.call(obj,key)){return-1}delete obj[key]}else{obj[key]=value}return 0}catch(e){Module.handle_js_error(e);return-1}return 0}JsObjMap_ass_subscript_js.sig="ieee";function JsObjMap_contains_js(obj,key){try{return Object.prototype.hasOwnProperty.call(obj,key)}catch(e){Module.handle_js_error(e);return-1}return 0}JsObjMap_contains_js.sig="iee";function JsModule_GetAll_js(o){try{return Object.getOwnPropertyNames(o)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsModule_GetAll_js.sig="ee";function JsBuffer_DecodeString_js(buffer,encoding){try{let encoding_js;if(encoding){encoding_js=UTF8ToString(encoding)}const decoder=new TextDecoder(encoding_js,{fatal:!!1,ignoreBOM:!!1});let res;try{res=decoder.decode(buffer)}catch(e){if(e instanceof TypeError){return Module.error}throw e}return res}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsBuffer_DecodeString_js.sig="eei";function JsBuffer_get_info(jsobj,byteLength_ptr,format_ptr,size_ptr,checked_ptr){const[format_utf8,size,checked]=Module.get_buffer_datatype(jsobj);HEAPU32[(byteLength_ptr>>2)+0>>>0]=jsobj.byteLength;HEAPU32[(format_ptr>>2)+0>>>0]=format_utf8;HEAPU32[(size_ptr>>2)+0>>>0]=size;HEAPU8[checked_ptr+0>>>0]=checked}JsBuffer_get_info.sig="veiiii";function JsDoubleProxy_unwrap_js(id){try{return Module.PyProxy_getPtr(id)}catch(e){Module.handle_js_error(e);return 0}errNoRet()}JsDoubleProxy_unwrap_js.sig="ie";function JsProxy_to_weakref_js(pyproxy){try{return new WeakRef(pyproxy)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsProxy_to_weakref_js.sig="ee";function JsProxy_compute_typeflags(obj,is_py_json){try{let type_flags=0;if(API.isPyProxy(obj)&&!pyproxyIsAlive(obj)){return 0}const typeTag=getTypeTag(obj);function safeBool(cb){try{return cb()}catch(e){return!!0}}const isBufferView=safeBool(()=>ArrayBuffer.isView(obj));const isArray=safeBool(()=>Array.isArray(obj));const constructorName=safeBool(()=>obj.constructor.name)||"";if(typeof obj==="function"){type_flags|=1<<9}if(hasMethod(obj,"then")){type_flags|=1<<7}if(hasMethod(obj,Symbol.iterator)){type_flags|=1<<0}if(hasMethod(obj,Symbol.asyncIterator)){type_flags|=1<<15}if(hasMethod(obj,"next")&&(hasMethod(obj,Symbol.iterator)||!hasMethod(obj,Symbol.asyncIterator))){type_flags|=1<<1}if(hasMethod(obj,"next")&&(!hasMethod(obj,Symbol.iterator)||hasMethod(obj,Symbol.asyncIterator))){type_flags|=1<<18}if(hasProperty(obj,"size")||hasProperty(obj,"length")&&typeof obj!=="function"){type_flags|=1<<2}if(hasMethod(obj,"get")){type_flags|=1<<3}if(hasMethod(obj,"set")){type_flags|=1<<4}if(hasMethod(obj,"has")){type_flags|=1<<5}if(hasMethod(obj,"includes")){type_flags|=1<<6}if((isBufferView||typeTag==="[object ArrayBuffer]")&&!(type_flags&1<<9)){type_flags|=1<<8}if(API.isPyProxy(obj)){type_flags|=1<<13}if(isArray){type_flags|=1<<10}if(typeTag==="[object HTMLCollection]"||typeTag==="[object NodeList]"){type_flags|=1<<11}if(isBufferView&&typeTag!=="[object DataView]"){type_flags|=1<<12}if(typeTag==="[object Generator]"){type_flags|=1<<16}if(typeTag==="[object AsyncGenerator]"){type_flags|=1<<17}if(hasProperty(obj,"name")&&hasProperty(obj,"message")&&(hasProperty(obj,"stack")||constructorName==="DOMException")&&!(type_flags&(1<<9|1<<8))){type_flags|=1<<19}if(is_py_json&&type_flags&(1<<10|1<<11|1<<1)){type_flags|=1<<21}if(is_py_json&&!(type_flags&(1<<10|1<<12|1<<11|1<<8|1<<13|1<<1|1<<9|1<<19))){type_flags|=1<<20}return type_flags}catch(e){Module.handle_js_error(e);return-1}return 0}JsProxy_compute_typeflags.sig="iei";function is_comlink_proxy(obj){try{return!!(API.Comlink&&value[API.Comlink.createEndpoint])}catch(e){return!!0}}is_comlink_proxy.sig="ie";function can_run_sync_js(){return!!validSuspender.value}can_run_sync_js.sig="i";function my_dict_converter(){return Object.fromEntries}my_dict_converter.sig="e";function get_async_js_call_done_callback(proxies){try{return function(result){let msg="This borrowed proxy was automatically destroyed "+"at the end of an asynchronous function call. Try "+"using create_proxy or create_once_callable.";for(let px of proxies){Module.pyproxy_destroy(px,msg,!!0)}if(API.isPyProxy(result)){Module.pyproxy_destroy(result,msg,!!0)}}}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}get_async_js_call_done_callback.sig="ee";function wrap_generator(gen,proxies){try{proxies=new Set(proxies);const msg="This borrowed proxy was automatically destroyed "+"when a generator completed execution. Try "+"using create_proxy or create_once_callable.";function cleanup(){proxies.forEach(px=>Module.pyproxy_destroy(px,msg))}function wrap(funcname){return function(val){if(API.isPyProxy(val)){val=val.copy();proxies.add(val)}let res;try{res=gen[funcname](val)}catch(e){cleanup();throw e}if(res.done){proxies.delete(res.value);cleanup()}return res}}return{get[Symbol.toStringTag](){return"Generator"},[Symbol.iterator](){return this},next:wrap("next"),throw:wrap("throw"),return:wrap("return")}}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}wrap_generator.sig="eee";function wrap_async_generator(gen,proxies){try{proxies=new Set(proxies);const msg="This borrowed proxy was automatically destroyed "+"when an asynchronous generator completed execution. Try "+"using create_proxy or create_once_callable.";function cleanup(){proxies.forEach(px=>Module.pyproxy_destroy(px,msg))}function wrap(funcname){return async function(val){if(API.isPyProxy(val)){val=val.copy();proxies.add(val)}let res;try{res=await gen[funcname](val)}catch(e){cleanup();throw e}if(res.done){proxies.delete(res.value);cleanup()}return res}}return{get[Symbol.toStringTag](){return"AsyncGenerator"},[Symbol.asyncIterator](){return this},next:wrap("next"),throw:wrap("throw"),return:wrap("return")}}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}wrap_async_generator.sig="eee";function throw_no_gil(){throw new API.NoGilError("Attempted to use PyProxy when Python GIL not held")}throw_no_gil.sig="v";function pyproxy_Check(val){return API.isPyProxy(val)}pyproxy_Check.sig="ie";function pyproxy_AsPyObject(val){if(!API.isPyProxy(val)||!pyproxyIsAlive(val)){return 0}return Module.PyProxy_getPtr(val)}pyproxy_AsPyObject.sig="ie";function destroy_proxies(proxies,msg_ptr){let msg=undefined;if(msg_ptr){msg=_JsvString_FromId(msg_ptr)}for(let px of proxies){Module.pyproxy_destroy(px,msg,false)}}destroy_proxies.sig="vei";function gc_register_proxies(proxies){for(let px of proxies){Module.gc_register_proxy(Module.PyProxy_getAttrs(px).shared)}}gc_register_proxies.sig="ve";function destroy_proxy(px,msg_ptr){const{shared,props}=Module.PyProxy_getAttrsQuiet(px);if(!shared.ptr){return}if(props.roundtrip){return}let msg=undefined;if(msg_ptr){msg=_JsvString_FromId(msg_ptr)}Module.pyproxy_destroy(px,msg,false)}destroy_proxy.sig="vei";function proxy_cache_get(proxyCache,descr){const proxy=proxyCache.get(descr);if(!proxy){return Module.error}if(pyproxyIsAlive(proxy)){return proxy}else{proxyCache.delete(descr);return Module.error}}proxy_cache_get.sig="eei";function proxy_cache_set(proxyCache,descr,proxy){proxyCache.set(descr,proxy)}proxy_cache_set.sig="veie";function _pyproxyGen_make_result(done,value){return{done:!!done,value}}_pyproxyGen_make_result.sig="eie";function array_to_js(array,len){return Array.from(HEAP32.subarray(array/4>>>0,array/4+len>>>0))}array_to_js.sig="eii";function _pyproxy_get_buffer_result(start_ptr,smallest_ptr,largest_ptr,readonly,format,itemsize,shape,strides,view,c_contiguous,f_contiguous,sentinel){format=UTF8ToString(format);return{start_ptr,smallest_ptr,largest_ptr,readonly,format,itemsize,shape,strides,view,c_contiguous,f_contiguous}}_pyproxy_get_buffer_result.sig="eiiiiiieeiiii";function pyproxy_new_ex(ptrobj,capture_this,roundtrip,gcRegister,jsonAdaptor){try{return Module.pyproxy_new(ptrobj,{props:{captureThis:!!capture_this,roundtrip:!!roundtrip},gcRegister,jsonAdaptor})}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}pyproxy_new_ex.sig="eiiiii";function pyproxy_new(ptrobj){try{return Module.pyproxy_new(ptrobj)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}pyproxy_new.sig="ei";function create_once_callable(obj,may_syncify){try{_Py_IncRef(obj);let alreadyCalled=!!0;function wrapper(...args){if(alreadyCalled){throw new Error("OnceProxy can only be called once")}try{if(may_syncify){return Module.callPyObjectMaybePromising(obj,args)}else{return Module.callPyObject(obj,args)}}finally{wrapper.destroy()}}wrapper.destroy=function(){if(alreadyCalled){throw new Error("OnceProxy has already been destroyed")}alreadyCalled=!!1;Module.finalizationRegistry.unregister(wrapper);_Py_DecRef(obj)};Module.finalizationRegistry.register(wrapper,[obj,undefined],wrapper);return wrapper}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}create_once_callable.sig="eii";function create_promise_handles(handle_result,handle_exception,done_callback,js2py_converter){try{if(handle_result){_Py_IncRef(handle_result)}if(handle_exception){_Py_IncRef(handle_exception)}if(js2py_converter){_Py_IncRef(js2py_converter)}if(!done_callback){done_callback=x=>{}}let used=!!0;function checkUsed(){if(used){throw new Error("One of the promise handles has already been called.")}}function destroy(){checkUsed();used=!!1;if(handle_result){_Py_DecRef(handle_result)}if(handle_exception){_Py_DecRef(handle_exception)}if(js2py_converter){_Py_DecRef(js2py_converter)}}function onFulfilled(res){checkUsed();try{if(handle_result){return _create_promise_handles_result_helper(handle_result,js2py_converter,res)}}finally{done_callback(res);destroy()}}function onRejected(err){checkUsed();try{if(handle_exception){return Module.callPyObjectMaybePromising(handle_exception,[err])}}finally{done_callback(undefined);destroy()}}onFulfilled.destroy=destroy;onRejected.destroy=destroy;return[onFulfilled,onRejected]}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}create_promise_handles.sig="eiiei";function _python2js_buffer_inner(buf,itemsize,ndim,format,shape,strides,suboffsets){try{let converter=Module.get_converter(format,itemsize);return Module._python2js_buffer_recursive(buf,0,{ndim,format,itemsize,shape,strides,suboffsets,converter})}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}_python2js_buffer_inner.sig="eiiiiiii";function jslib_init_js(){try{HEAP32[_Jsr_undefined/4>>>0]=_hiwire_intern(undefined);HEAP32[_Jsr_true/4>>>0]=_hiwire_intern(true);HEAP32[_Jsr_false/4>>>0]=_hiwire_intern(false);HEAP32[_Jsr_error/4>>>0]=_hiwire_intern(_Jsv_GetNull());HEAP32[_Jsr_novalue/4>>>0]=_hiwire_intern({noValueMarker:1});Module.novalue=_hiwire_get(HEAP32[_Jsr_novalue/4>>>0]);Module.error=_hiwire_get(HEAP32[_Jsr_error/4>>>0]);Hiwire.num_keys=_hiwire_num_refs;return 0}catch(e){Module.handle_js_error(e);return-1}return 0}jslib_init_js.sig="i";function JsvNoValue_Check(v){return v===Module.novalue}JsvNoValue_Check.sig="ie";function JsvNum_fromInt(x){return x}JsvNum_fromInt.sig="ei";function JsvNum_fromDouble(val){return val}JsvNum_fromDouble.sig="ed";function JsvNum_fromDigits(digits,ndigits){let result=BigInt(0);for(let i=0;i>2)+i>>>0])<>2)+ndigits-1>>>0]&2147483648)<=arr.length){return Module.error}return arr.splice(idx,1)[0]}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvArray_Delete.sig="eei";function JsvArray_Push(arr,obj){return arr.push(obj)}JsvArray_Push.sig="iee";function JsvArray_Extend(arr,vals){arr.push(...vals)}JsvArray_Extend.sig="vee";function JsvArray_Insert(arr,idx,value){try{arr.splice(idx,0,value)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvArray_Insert.sig="ieie";function JsvArray_ShallowCopy(arr){try{return"slice"in arr?arr.slice():Array.from(arr)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvArray_ShallowCopy.sig="ee";function JsvArray_slice(obj,length,start,stop,step){try{let result;if(step===1){result=obj.slice(start,stop)}else{result=Array.from({length},(_,i)=>obj[start+i*step])}return result}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvArray_slice.sig="eeiiii";function JsvArray_slice_assign(obj,slicelength,start,stop,step,values_length,values){try{let jsvalues=[];for(let i=0;i>2)+i>>>0]);if(ref===Module.error){return-1}jsvalues.push(ref)}if(step===1){obj.splice(start,slicelength,...jsvalues)}else{if(values!==0){for(let i=0;i=0;i--){obj.splice(start+i*step,1)}}}}catch(e){Module.handle_js_error(e);return-1}return 0}JsvArray_slice_assign.sig="ieiiiiii";function JsvObject_New(){return{}}JsvObject_New.sig="e";function JsvObject_SetAttr(obj,attr,value){try{obj[attr]=value}catch(e){Module.handle_js_error(e);return-1}return 0}JsvObject_SetAttr.sig="ieee";function JsvObject_Entries(obj){try{return Object.entries(obj)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvObject_Entries.sig="ee";function JsvObject_Keys(obj){try{return Object.keys(obj)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvObject_Keys.sig="ee";function JsvObject_Values(obj){try{return Object.values(obj)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvObject_Values.sig="ee";function JsvObject_toString(obj){try{if(hasMethod(obj,"toString")){return obj.toString()}return Object.prototype.toString.call(obj)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvObject_toString.sig="ee";function JsvObject_CallMethod(obj,meth,args){try{return obj[meth](...args)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvObject_CallMethod.sig="eeee";function JsvObject_CallMethod_NoArgs(obj,meth){try{return obj[meth]()}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvObject_CallMethod_NoArgs.sig="eee";function JsvObject_CallMethod_OneArg(obj,meth,arg){try{return obj[meth](arg)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvObject_CallMethod_OneArg.sig="eeee";function JsvObject_CallMethod_TwoArgs(obj,meth,arg1,arg2){try{return obj[meth](arg1,arg2)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvObject_CallMethod_TwoArgs.sig="eeeee";function JsvFunction_Check(obj){try{return typeof obj==="function"}catch(e){return false}}JsvFunction_Check.sig="ie";function JsvFunction_CallBound(func,this_,args){try{return Function.prototype.apply.apply(func,[this_,args])}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvFunction_CallBound.sig="eeee";function JsvFunction_Call_OneArg(func,arg){try{return func(arg)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvFunction_Call_OneArg.sig="eee";function JsvFunction_Construct(func,args){try{return Reflect.construct(func,args)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvFunction_Construct.sig="eee";function JsvPromise_Check(obj){try{return isPromise(obj)}catch(e){return false}}JsvPromise_Check.sig="ie";function JsvPromise_Resolve(obj){try{return Promise.resolve(obj)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvPromise_Resolve.sig="ee";function jslib_init_buffers_js(){try{const dtypes_str=Array.from("bBhHiIqQfd").join(String.fromCharCode(0));const dtypes_ptr=stringToNewUTF8(dtypes_str);const dtypes_map=Object.fromEntries(Object.entries(dtypes_str).map(([idx,val])=>[val,dtypes_ptr+ +idx]));const buffer_datatype_map=new Map([["Int8Array",[dtypes_map["b"],1,true]],["Uint8Array",[dtypes_map["B"],1,true]],["Uint8ClampedArray",[dtypes_map["B"],1,true]],["Int16Array",[dtypes_map["h"],2,true]],["Uint16Array",[dtypes_map["H"],2,true]],["Int32Array",[dtypes_map["i"],4,true]],["Uint32Array",[dtypes_map["I"],4,true]],["Float32Array",[dtypes_map["f"],4,true]],["Float64Array",[dtypes_map["d"],8,true]],["BigInt64Array",[dtypes_map["q"],8,true]],["BigUint64Array",[dtypes_map["Q"],8,true]],["DataView",[dtypes_map["B"],1,false]],["ArrayBuffer",[dtypes_map["B"],1,false]]]);Module.get_buffer_datatype=function(jsobj){return buffer_datatype_map.get(jsobj.constructor.name)||[0,0,false]}}catch(e){Module.handle_js_error(e);return-1}return 0}jslib_init_buffers_js.sig="i";function JsvBuffer_assignToPtr(buf,ptr){try{Module.HEAPU8.set(bufferAsUint8Array(buf),ptr)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_assignToPtr.sig="iei";function JsvBuffer_assignFromPtr(buf,ptr){try{bufferAsUint8Array(buf).set(Module.HEAPU8.subarray(ptr,ptr+buf.byteLength))}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_assignFromPtr.sig="iei";function JsvBuffer_readFromFile(buf,fd){try{let uint8_buf=bufferAsUint8Array(buf);let stream=Module.FS.streams[fd];Module.FS.read(stream,uint8_buf,0,uint8_buf.byteLength)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_readFromFile.sig="iei";function JsvBuffer_writeToFile(buf,fd){try{let uint8_buf=bufferAsUint8Array(buf);let stream=Module.FS.streams[fd];Module.FS.write(stream,uint8_buf,0,uint8_buf.byteLength)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_writeToFile.sig="iei";function JsvBuffer_intoFile(buf,fd){try{let uint8_buf=bufferAsUint8Array(buf);let stream=Module.FS.streams[fd];Module.FS.write(stream,uint8_buf,0,uint8_buf.byteLength,undefined,true)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_intoFile.sig="iei";function JsvGenerator_Check(obj){try{return getTypeTag(obj)==="[object Generator]"}catch(e){return false}}JsvGenerator_Check.sig="ie";function JsvAsyncGenerator_Check(obj){try{return getTypeTag(obj)==="[object AsyncGenerator]"}catch(e){return false}}JsvAsyncGenerator_Check.sig="ie";function JsvError_Throw(e){throw e}JsvError_Throw.sig="ve";function Jsv_less_than(a,b){try{return!!(ab)}catch(e){return false}}Jsv_greater_than.sig="iee";function Jsv_greater_than_equal(a,b){try{return!!(a>=b)}catch(e){return false}}Jsv_greater_than_equal.sig="iee";function JsvMap_New(){try{return new Map}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvMap_New.sig="e";function JsvLiteralMap_New(){try{return new API.LiteralMap}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvLiteralMap_New.sig="e";function JsvMap_Set(map,key,val){try{map.set(key,val)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvMap_Set.sig="ieee";function JsvSet_New(){try{return new Set}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}JsvSet_New.sig="e";function JsvSet_Add(set,val){try{set.add(val)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvSet_Add.sig="iee";function _python2js_addto_postprocess_list(list,parent,key,value){list.push([parent,key,value])}_python2js_addto_postprocess_list.sig="veeei";function _python2js_handle_postprocess_list(list,cache){for(const[parent,key,ptr]of list){let val=cache.get(ptr);if(parent.constructor.name==="LiteralMap"){parent.set(key,val)}else{parent[key]=val}}}_python2js_handle_postprocess_list.sig="vee";function _python2js_ucs1(ptr,len){try{let jsstr="";for(let i=0;i>>0])}return jsstr}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}_python2js_ucs1.sig="eii";function _python2js_ucs2(ptr,len){try{let jsstr="";for(let i=0;i>1)+i>>>0])}return jsstr}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}_python2js_ucs2.sig="eii";function _python2js_ucs4(ptr,len){try{let jsstr="";for(let i=0;i>2)+i>>>0])}return jsstr}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}_python2js_ucs4.sig="eii";function _python2js_add_to_cache(cache,pyparent,jsparent){try{cache.set(pyparent,jsparent)}catch(e){Module.handle_js_error(e);return-1}return 0}_python2js_add_to_cache.sig="ieie";function _python2js_cache_lookup(cache,pyparent){return cache.get(pyparent)||Module.error}_python2js_cache_lookup.sig="eei";function _JsObject_Set_js(obj,key,value){try{if(key in obj){return-2}obj[key]=value}catch(e){Module.handle_js_error(e);return-1}return 0}_JsObject_Set_js.sig="ieee";function _JsArray_PushEntry_helper(array,key,value){try{array.push([key,value])}catch(e){Module.handle_js_error(e);return-1}return 0}_JsArray_PushEntry_helper.sig="ieee";function _JsArray_PostProcess_helper(jscontext,array){try{return jscontext.dict_converter(array)}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}_JsArray_PostProcess_helper.sig="eee";function python2js__default_converter_js(jscontext,object){try{let proxy=Module.pyproxy_new(object);try{return jscontext.default_converter(proxy,jscontext.converter,jscontext.cacheConversion)}finally{proxy.destroy()}}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}python2js__default_converter_js.sig="eei";function python2js__eager_converter_js(jscontext,object){try{if(jscontext.eager_visited.has(object)){return Module.novalue}jscontext.eager_visited.add(object);const proxy=Module.pyproxy_new(object);try{return jscontext.eager_converter(proxy,jscontext.converter,jscontext.cacheConversion)}finally{proxy.destroy()}}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}python2js__eager_converter_js.sig="eei";function python2js_custom__create_jscontext(context,cache,dict_converter,default_converter,eager_converter){try{const jscontext={};if(dict_converter){jscontext.dict_converter=dict_converter}if(default_converter){jscontext.default_converter=default_converter;jscontext.cacheConversion=function(input,output){if(!API.isPyProxy(input)){throw new TypeError("The first argument to cacheConversion must be a PyProxy.")}const input_ptr=Module.PyProxy_getPtr(input);cache.set(input_ptr,output)}}if(eager_converter){jscontext.eager_converter=eager_converter;jscontext.eager_visited=new Set}if(default_converter||eager_converter){jscontext.converter=function(x){if(!API.isPyProxy(x)){return x}const ptr=Module.PyProxy_getPtr(x);let res;try{res=__python2js(context,ptr)}catch(e){API.fatal_error(e)}if(res===Module.error){_pythonexc2js()}return res}}return jscontext}catch(e){Module.handle_js_error(e);return Module.error}errNoRet()}python2js_custom__create_jscontext.sig="eieeee";function destroy_proxies_js(proxies_id){try{for(const proxy of proxies_id){proxy.destroy()}}catch(e){Module.handle_js_error(e);return-1}return 0}destroy_proxies_js.sig="ie";function pyodide_js_init(){"use strict";(()=>{var Dr=Object.create;var ze=Object.defineProperty;var Rr=Object.getOwnPropertyDescriptor;var Lr=Object.getOwnPropertyNames;var $r=Object.getPrototypeOf,Cr=Object.prototype.hasOwnProperty;var a=(t,e)=>ze(t,"name",{value:e,configurable:!0}),b=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var Ur=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Lr(e))!Cr.call(t,o)&&o!==r&&ze(t,o,{get:()=>e[o],enumerable:!(n=Rr(e,o))||n.enumerable});return t};var E=(t,e,r)=>(r=t!=null?Dr($r(t)):{},Ur(e||!t||!t.__esModule?ze(r,"default",{value:t,enumerable:!0}):r,t));function Br(t){return!isNaN(parseFloat(t))&&isFinite(t)}a(Br,"_isNumber");function D(t){return t.charAt(0).toUpperCase()+t.substring(1)}a(D,"_capitalize");function Ge(t){return function(){return this[t]}}a(Ge,"_getter");var $=["isConstructor","isEval","isNative","isToplevel"],C=["columnNumber","lineNumber"],U=["fileName","functionName","source"],Hr=["args"],jr=["evalOrigin"],se=$.concat(C,U,Hr,jr);function v(t){if(t)for(var e=0;e-1&&(i=i.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(,.*$)/g,""));var s=i.replace(/^\s+/,"").replace(/\(eval code/g,"(").replace(/^.*?\s+/,""),l=s.match(/ (\(.+\)$)/);s=l?s.replace(l[0],""):s;var c=this.extractLocation(l?l[1]:s),u=l&&s||void 0,y=["eval",""].indexOf(c[0])>-1?void 0:c[0];return new le({functionName:u,fileName:y,lineNumber:c[1],columnNumber:c[2],source:i})},this)},"ErrorStackParser$$parseV8OrIE"),parseFFOrSafari:a(function(n){var o=n.stack.split(`\n`).filter(function(i){return!i.match(e)},this);return o.map(function(i){if(i.indexOf(" > eval")>-1&&(i=i.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),i.indexOf("@")===-1&&i.indexOf(":")===-1)return new le({functionName:i});var s=/((.*".+"[^@]*)?[^@]*)(?:@)/,l=i.match(s),c=l&&l[1]?l[1]:void 0,u=this.extractLocation(i.replace(s,""));return new le({functionName:c,fileName:u[0],lineNumber:u[1],columnNumber:u[2],source:i})},this)},"ErrorStackParser$$parseFFOrSafari")}}a(Wr,"ErrorStackParser");var zr=new Wr;var Ve=zr;function Mt(t){if(typeof t=="string")t=new Error(t);else if(t&&typeof t=="object"&&t.name==="ExitStatus"){let e=t.status;t=new z(t.message),t.status=e}else if(typeof t!="object"||t===null||typeof t.stack!="string"||typeof t.message!="string"){let e=API.getTypeTag(t),r=`A value of type ${typeof t} with tag ${e} was thrown as an error!`;try{r+=`\nString interpolation of the thrown value gives """${t}""".`}catch{r+=`\nString interpolation of the thrown value fails.`}try{r+=`\nThe thrown value's toString method returns """${t.toString()}""".`}catch{r+=`\nThe thrown value's toString method fails.`}t=new Error(r)}return t}a(Mt,"ensureCaughtObjectIsError");var Ke=class extends Error{static{a(this,"CppException")}constructor(e,r,n){let o=Module.getCppExceptionThrownObjectFromWebAssemblyException(n);r||(r=`The exception is an object of type ${e} at address ${o} which does not inherit from std::exception`),super(r),this.ty=e}get name(){return`${this.constructor.name} ${this.ty}`}},Gr=WebAssembly.Exception,Vr=a(t=>t instanceof Gr,"isWasmException");function Nt(t){let[e,r]=Module.getExceptionMessage(t);return new Ke(e,r,t)}a(Nt,"convertCppException");Tests.convertCppException=Nt;var Et=!1;API.fatal_error=function(t){if(t&&t.pyodide_fatal_error)return;if(Et){console.error("Recursive call to fatal_error. Inner error was:"),console.error(t);return}if(t instanceof G)throw t;typeof t=="number"||Vr(t)?t=Nt(t):t=Mt(t),t.pyodide_fatal_error=!0,Et=!0;let e=t instanceof z;e||(console.error("Pyodide has suffered a fatal error. Please report this to the Pyodide maintainers."),console.error("The cause of the fatal error was:"),API.inTestHoist?(console.error(t.toString()),console.error(t.stack)):console.error(t));try{e||_dump_traceback();let n=`Pyodide already ${e?"exited":"fatally failed"} and can no longer be used.`;for(let o of Reflect.ownKeys(API.public_api))typeof o=="string"&&o.startsWith("_")||o==="version"||Object.defineProperty(API.public_api,o,{enumerable:!0,configurable:!0,get:a(()=>{throw new Error(n)},"get")});API.on_fatal&&API.on_fatal(t)}catch(r){console.error("Another error occurred while handling the fatal error:"),console.error(r)}throw t};API.maybe_fatal_error=function(t){API._skip_unwind_fatal_error&&t==="unwind"||API.fatal_error(t)};var Je=[];API.capture_stderr=function(){Je=[],Module.FS.createDevice("/dev","capture_stderr",null,t=>Je.push(t)),Module.FS.closeStream(2),Module.FS.open("/dev/capture_stderr",1)};API.restore_stderr=function(){return Module.FS.closeStream(2),Module.FS.unlink("/dev/capture_stderr"),Module.FS.open("/dev/stderr",1),UTF8ArrayToString(new Uint8Array(Je))};API.fatal_loading_error=function(...t){let e=t.join(" ");if(_PyErr_Occurred()){API.capture_stderr(),_PyErr_Print();let r=API.restore_stderr();e+=`\n`+r}throw new ce(e)};function qe(t){if(!t)return!1;let e=t.fileName||"";if(e.includes("wasm-function"))return!0;if(!e.includes("pyodide.asm.js"))return!1;let r=t.functionName||"";return r.startsWith("Object.")&&(r=r.slice(7)),API.public_api&&r in API.public_api&&r!=="PythonError"?(t.functionName=r,!1):!0}a(qe,"isPyodideFrame");function kt(t){return qe(t)&&t.functionName==="new_error"}a(kt,"isErrorStart");Module.handle_js_error=function(t){if(t&&t.pyodide_fatal_error)throw t;if(t instanceof w)return;let e=!1;t instanceof R&&(e=_restore_sys_last_exception(t.__error_address));let r,n;try{r=Ve.parse(t)}catch{n=!0}if(n&&(t=Mt(t)),!e){let o=_JsProxy_create(t);_set_error(o),_Py_DecRef(o)}if(!n){if(kt(r[0])||kt(r[1]))for(;qe(r[0]);)r.shift();for(let o of r){if(qe(o))break;let i=stringToNewUTF8(o.functionName||"???"),s=stringToNewUTF8(o.fileName||"???.js");__PyTraceback_Add(i,s,o.lineNumber),_free(i),_free(s)}}};var R=class extends Error{static{a(this,"PythonError")}constructor(e,r,n){let o=Error.stackTraceLimit;Error.stackTraceLimit=1/0,super(r),Error.stackTraceLimit=o,this.type=e,this.__error_address=n}};API.PythonError=R;var w=class extends Error{static{a(this,"_PropagatePythonError")}constructor(){super("If you are seeing this message, an internal Pyodide error has occurred. Please report it to the Pyodide maintainers.")}};Module._PropagatePythonError=w;function Kr(t){Object.defineProperty(t.prototype,"name",{value:t.name})}a(Kr,"setName");var ce=class extends Error{static{a(this,"FatalPyodideError")}},z=class extends Error{static{a(this,"Exit")}},G=class extends Error{static{a(this,"NoGilError")}};[w,ce,z,R,G].forEach(Kr);API.NoGilError=G;API.errorConstructors=new Map([EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError,globalThis.DOMException,globalThis.AssertionError,globalThis.SystemError].filter(t=>t).map(t=>[t.constructor.name,t]));API.deserializeError=function(t,e,r){let n=API.errorConstructors.get(t)||Error,o=new n(e);return API.errorConstructors.has(t)||(o.name=t),o.message=e,o.stack=r,o};function Jr(t){let e=0,r=[];for(let s of t){let l=s.codePointAt(0);r.push(l),e=l>e?l:e}let n=r.length,o=_PyUnicode_New(n,e);if(o===0)throw new w;let i=_PyUnicode_Data(o);if(e>65535)for(let s=0;s>2)+s>>>0]=r[s];else if(e>255)for(let s=0;s>1)+s>>>0]=r[s];else for(let s=0;s>>0]=r[s];return o}a(Jr,"js2python_string");function qr(t){let e=t,r=0;for(t<0&&(t=-t),t<<=BigInt(1);t;)r++,t>>=BigInt(32);let n=stackSave(),o=stackAlloc(r*4);t=e;for(let s=0;s>2)+s>>>0]=Number(t&BigInt(4294967295)),t>>=BigInt(32);let i=__PyLong_FromByteArray(o,r*4,!0,!0);return stackRestore(n),i}a(qr,"js2python_bigint");function V(t){let e=Yr(t);if(e===0)throw new w;return e}a(V,"js2python_convertImmutable");Module.js2python_convertImmutable=V;function Yr(t){let e=typeof t;if(e==="string")return Jr(t);if(e==="number")return Number.isSafeInteger(t)?_PyLong_FromDouble(t):_PyFloat_FromDouble(t);if(e==="bigint")return qr(t);if(t===void 0)return __js2python_none();if(t===null)return __js2python_null();if(t===!0)return __js2python_true();if(t===!1)return __js2python_false();if(API.isPyProxy(t)){let{props:r,shared:n}=Module.PyProxy_getAttrs(t);return r.roundtrip?_JsProxy_create(t):__js2python_pyproxy(n.ptr)}}a(Yr,"js2python_convertImmutableInner");function Qr(t,e){let r=_PyList_New(t.length);if(r===0)return 0;let n=0;try{e.cache.set(t,r);for(let o=0;oModule.pyproxy_new(ue(o,n)),"converter"),cacheConversion(o,i){if(API.isPyProxy(i))n.cache.set(o,Module.PyProxy_getPtr(i));else throw new Error("Second argument should be a PyProxy!")}};return ue(t,n)}a(en,"js2python_convert");Module.js2python_convert=en;Module.processBufferFormatString=function(t,e=""){if(t.length>2)throw new Error(`Expected format string to have length <= 2, got '${t}'.`+e);let r=t.slice(-1),n=t.slice(0,-1),o;switch(n){case"!":case">":o=!0;break;case"<":case"@":case"=":case"":o=!1;break;default:throw new Error(`Unrecognized alignment character ${n}.`+e)}let i;switch(r){case"b":i=Int8Array;break;case"s":case"p":case"c":case"B":case"?":i=Uint8Array;break;case"h":i=Int16Array;break;case"H":i=Uint16Array;break;case"i":case"l":case"n":i=Int32Array;break;case"I":case"L":case"N":case"P":i=Uint32Array;break;case"q":if(globalThis.BigInt64Array===void 0)throw new Error("BigInt64Array is not supported on this browser."+e);i=BigInt64Array;break;case"Q":if(globalThis.BigUint64Array===void 0)throw new Error("BigUint64Array is not supported on this browser."+e);i=BigUint64Array;break;case"f":i=Float32Array;break;case"d":i=Float64Array;break;case"e":throw new Error("Javascript has no Float16 support.");default:throw new Error(`Unrecognized format character '${r}'.`+e)}return[i,o]};Module.python2js_buffer_1d_contiguous=function(t,e,r){let n=e*r;return HEAP8.slice(t,t+n).buffer};Module.python2js_buffer_1d_noncontiguous=function(t,e,r,n,o){let i=o*n,s=new Uint8Array(i);for(let l=0;l=0&&(c=HEAPU32[(c>>2)+0>>>0]+r),s.set(HEAP8.subarray(c>>>0,c+o>>>0),l*o)}return s.buffer};Module._python2js_buffer_recursive=function(t,e,r){let{shape:n,strides:o,ndim:i,converter:s,itemsize:l,suboffsets:c}=r,u=HEAPU32[(n>>2)+e>>>0],y=HEAP32[(o>>2)+e>>>0],_=-1;if(i===0)return s(Module.python2js_buffer_1d_contiguous(t,l,1));if(c!==0&&(_=HEAP32[(c>>2)+e>>>0]),e===i-1){let f;return y===l&&_<0?f=Module.python2js_buffer_1d_contiguous(t,y,u):f=Module.python2js_buffer_1d_noncontiguous(t,y,_,u,l),s(f)}let m=[];for(let f=0;f=0&&(curptr=HEAPU32[(curptr>>2)+0>>>0]+_),m.push(Module._python2js_buffer_recursive(I,e+1,r))}return m};Module.get_converter=function(t,e){let r=UTF8ToString(t),[n,o]=Module.processBufferFormatString(r);switch(r.slice(-1)){case"s":let u=new TextDecoder("utf8",{ignoreBOM:!0});return y=>u.decode(y);case"?":return y=>Array.from(new Uint8Array(y),_=>!!_)}if(!o)return u=>new n(u);let s,l;switch(e){case 2:s="getUint16",l="setUint16";break;case 4:s="getUint32",l="setUint32";break;case 8:s="getFloat64",l="setFloat64";break;default:throw new Error(`Unexpected size ${e}`)}function c(u){let y=new DataView(u),_=y[s].bind(y),m=y[l].bind(y);for(let f=0;fnew n(c(u))};function tn(t){try{return t instanceof g}catch{return!1}}a(tn,"isPyProxy");API.isPyProxy=tn;globalThis.FinalizationRegistry?Module.finalizationRegistry=new FinalizationRegistry(({ptr:t,cache:e})=>{e&&(e.leaked=!0,Bt(e));try{_check_gil();let r=validSuspender.value;validSuspender.value=!1,_Py_DecRef(t),validSuspender.value=r}catch(r){API.fatal_error(r)}}):Module.finalizationRegistry={register(){},unregister(){}};var Ye=new Map;Module.pyproxy_alloc_map=Ye;var ct,ut;Module.enable_pyproxy_allocation_tracing=function(){ct=a(function(t){Ye.set(t,Error().stack)},"trace_pyproxy_alloc"),ut=a(function(t){Ye.delete(t)},"trace_pyproxy_dealloc")};Module.disable_pyproxy_allocation_tracing=function(){ct=a(function(t){},"trace_pyproxy_alloc"),ut=a(function(t){},"trace_pyproxy_dealloc")};Module.disable_pyproxy_allocation_tracing();var $t=Symbol("pyproxy.attrs");function rn(t,e){_check_gil();let r=validSuspender.value;validSuspender.value=!1;try{return _pyproxy_getflags(t,e)}finally{validSuspender.value=r}}a(rn,"pyproxy_getflags");function J(t,{flags:e,cache:r,props:n,shared:o,gcRegister:i,jsonAdaptor:s}={}){i===void 0&&(i=!0);let l=e!==void 0?e:rn(t,!!s);l===-1&&_pythonexc2js();let c=l&8192,u=l&32768,y=l&1<<17,_=Module.getPyProxyClass(l),m;l&256?(m=a(function(){},"target"),Object.setPrototypeOf(m,_.prototype),delete m.length,delete m.name,m.prototype=void 0):m=Object.create(_.prototype);let f=!!o;o||(r||(r={map:new Map,json_adaptor_map:new Map,refcnt:0}),r.refcnt++,o={ptr:t,cache:r,flags:l,promise:void 0,destroyed_msg:void 0,gcRegistered:!1},_Py_IncRef(t)),n=Object.assign({isBound:!1,captureThis:!1,boundArgs:[],roundtrip:!1},n);let I;u?I=M:c?I=fn:y?I=_n:I=P;let oe=new Proxy(m,I);!f&&i&&Ct(o),f||ct(oe);let ae={shared:o,props:n};return m[$t]=ae,oe}a(J,"pyproxy_new");Module.pyproxy_new=J;function Ct(t){let e=Object.assign({},t);t.gcRegistered=!0,Module.finalizationRegistry.register(t,e,t)}a(Ct,"gc_register_proxy");Module.gc_register_proxy=Ct;function Oe(t){return t[$t]}a(Oe,"_getAttrsQuiet");Module.PyProxy_getAttrsQuiet=Oe;function S(t){let e=Oe(t);if(!e.shared.ptr)throw new Error(e.shared.destroyed_msg);return e}a(S,"_getAttrs");Module.PyProxy_getAttrs=S;function p(t){return S(t).shared.ptr}a(p,"_getPtr");function h(t){return Object.getPrototypeOf(t).$$flags}a(h,"_getFlags");function Ut(t){return!!(h(t)&98304)}a(Ut,"isJsonAdaptor");function Ft(t,e,r){let{captureThis:n,boundArgs:o,boundThis:i,isBound:s}=S(t).props;return n?s?[i].concat(o,r):[e].concat(r):s?o.concat(r):r}a(Ft,"_adjustArgs");var Dt=new Map;Module.getPyProxyClass=function(t){let e=[[1,Qe],[2,B],[4,L],[8,k],[16,Ze],[32,tt],[2048,rt],[512,et],[1024,nt],[4096,ot],[64,st],[128,lt],[256,ke],[8192,at],[16384,it]],r=Dt.get(t);if(r)return r;let n={};for(let[l,c]of e)t&l&&Object.assign(n,Object.getOwnPropertyDescriptors(c.prototype));(t&8192||t&2)&&Object.assign(n,Object.getOwnPropertyDescriptors(Xe.prototype)),n.constructor=Object.getOwnPropertyDescriptor(g.prototype,"constructor"),Object.assign(n,Object.getOwnPropertyDescriptors({$$flags:t}));let o=t&256?jt:Ht,i=Object.create(o,n);function s(){}return a(s,"NewPyProxyClass"),s.prototype=i,Dt.set(t,s),s};Module.PyProxy_getPtr=p;var Rt="This borrowed attribute proxy was automatically destroyed in the process of destroying the proxy it was borrowed from. Try using the 'copy' method.";function Bt(t){if(t&&(t.refcnt--,!t.leaked&&t.refcnt===0)){for(let e of t.map.values())Module.pyproxy_destroy(e,Rt,!0);for(let e of t.json_adaptor_map.values())Module.pyproxy_destroy(e,Rt,!0)}}a(Bt,"pyproxy_decref_cache");function nn(t,e){if(e=e||"Object has already been destroyed",API.debug_ffi){let r=t.type,n;try{n=t.toString()}catch(o){if(o.pyodide_fatal_error)throw o}e+=`\nThe object was of type "${r}" and `,n?e+=`had repr "${n}"`:e+="an error was raised when trying to generate its repr"}else e+="\nFor more information about the cause of this error, use `pyodide.setDebug(true)`";return e}a(nn,"generateDestroyedMessage");Module.pyproxy_destroy=function(t,e,r){let{shared:n,props:o}=Oe(t);if(!n.ptr||!r&&o.roundtrip)return;n.destroyed_msg=nn(t,e);let i=n.ptr;n.ptr=0,n.gcRegistered&&Module.finalizationRegistry.unregister(n),Bt(n.cache);try{_check_gil();let s=validSuspender.value;validSuspender.value=!1,_Py_DecRef(i),ut(t),validSuspender.value=s}catch(s){API.fatal_error(s)}};function pe(t,e,r){let n=e.length,o=Object.keys(r),i=Object.values(r),s=o.length;e.push(...i);let l;try{_check_gil();let c=validSuspender.value;validSuspender.value=!1,l=__pyproxy_apply(t,e,n,o,s),validSuspender.value=c}catch(c){API.maybe_fatal_error(c);return}if(l===Module.error&&_pythonexc2js(),l&&l.type==="coroutine"&&l._ensure_future){_check_gil();let c=validSuspender.value;validSuspender.value=!1;let u=__iscoroutinefunction(t);validSuspender.value=c,u&&l._ensure_future()}return l}a(pe,"callPyObjectKwargs");async function de(t,e,r){if(!Module.jspiSupported)throw new Error("WebAssembly stack switching not supported in this JavaScript runtime");let n=e.length,o=Object.keys(r),i=Object.values(r),s=o.length;e.push(...i);let l=stackSave(),c=stackAlloc(4),u;try{_check_gil();let y=validSuspender.value;validSuspender.value=!1,u=await Module.promisingApply(t,e,n,o,s,c),validSuspender.value=y}catch(y){API.fatal_error(y)}if(u=u[0],u===Module.error){_PyErr_SetRaisedException(HEAPU32[c/4>>>0]);try{_pythonexc2js()}finally{stackRestore(l)}}if(u&&u.type==="coroutine"&&u._ensure_future){_check_gil();let y=validSuspender.value;validSuspender.value=!1;let _=__iscoroutinefunction(t);validSuspender.value=y,_&&u._ensure_future()}return u}a(de,"callPyObjectKwargsPromising");Module.callPyObjectMaybePromising=async function(t,e){return Module.jspiSupported?await de(t,e,{}):pe(t,e,{})};Module.callPyObject=function(t,e){return pe(t,e,{})};var g=class t{static{a(this,"PyProxy")}static[Symbol.hasInstance](e){return[t,Wt].some(r=>Function.prototype[Symbol.hasInstance].call(r,e))}constructor(){throw new TypeError("PyProxy is not a constructor")}get[Symbol.toStringTag](){return"PyProxy"}get type(){let e=p(this);return __pyproxy_type(e)}toString(){let e=p(this),r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxy_repr(e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===Module.error&&_pythonexc2js(),r}destroy(e={}){e=Object.assign({message:"",destroyRoundtrip:!0},e);let{message:r,destroyRoundtrip:n}=e;Module.pyproxy_destroy(this,r,n)}copy(){let e=S(this);return J(e.shared.ptr,{flags:h(this),cache:e.shared.cache,props:e.props})}toJs({depth:e=-1,pyproxies:r=void 0,create_pyproxies:n=!0,dict_converter:o=void 0,default_converter:i=void 0,eager_converter:s=void 0}={}){let l=p(this),c,u;n?r?u=r:u=[]:u=Module.error;try{_check_gil();let y=validSuspender.value;validSuspender.value=!1,c=_python2js_custom(l,e,u,o??Module.error,i??Module.error,s??Module.error),validSuspender.value=y}catch(y){API.fatal_error(y)}return c===Module.error&&_pythonexc2js(),c}},Ht=g.prototype;Tests.Function=Function;var jt=Object.create(Function.prototype,Object.getOwnPropertyDescriptors(Ht));function Wt(){}a(Wt,"PyProxyFunction");Wt.prototype=jt;var fe=class extends g{static{a(this,"PyProxyWithLength")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&1)}},Qe=class{static{a(this,"PyLengthMethods")}get length(){let e=p(this),r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=_PyObject_Size(e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===-1&&_pythonexc2js(),r}},ge=class extends g{static{a(this,"PyProxyWithGet")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&2)}},Xe=class{static{a(this,"PyAsJsonAdaptorMethods")}asJsJson(){let{shared:e,props:r}=S(this),n=h(this);return n&8192?n|=65536:n|=32768,J(e.ptr,{shared:e,flags:n,props:r})}},B=class{static{a(this,"PyGetItemMethods")}get(e){let{shared:r}=S(this),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_getitem(r.ptr,e,r.cache.json_adaptor_map,Ut(this)),validSuspender.value=o}catch(o){API.fatal_error(o)}if(n===Module.error)if(_PyErr_Occurred())_pythonexc2js();else return;return n}asJsJson(){throw new Error("Should not happen")}},_e=class extends g{static{a(this,"PyProxyWithSet")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&4)}},L=class{static{a(this,"PySetItemMethods")}set(e,r){let n=p(this),o;try{_check_gil();let i=validSuspender.value;validSuspender.value=!1,o=__pyproxy_setitem(n,e,r),validSuspender.value=i}catch(i){API.fatal_error(i)}o===-1&&_pythonexc2js()}delete(e){let r=p(this),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_delitem(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}n===-1&&_pythonexc2js()}},me=class extends g{static{a(this,"PyProxyWithHas")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&8)}},k=class{static{a(this,"PyContainsMethods")}has(e){let r=p(this),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_contains(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}return n===-1&&_pythonexc2js(),n===1}};function*on(t,e,r,n){let o=[];try{for(;;){_check_gil();let i=validSuspender.value;validSuspender.value=!1;let s=__pyproxy_iter_next(t,r,n);if(validSuspender.value=i,s===Module.error)break;yield s,!n&&API.isPyProxy(s)&&o.push(s)}}catch(i){API.fatal_error(i)}finally{Module.finalizationRegistry.unregister(e),_Py_DecRef(t)}try{o.forEach(i=>Module.pyproxy_destroy(i,"This borrowed proxy was automatically destroyed when an iterator was exhausted."))}catch{}_PyErr_Occurred()&&_pythonexc2js()}a(on,"iter_helper");var he=class extends g{static{a(this,"PyIterable")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&48)}},Ze=class{static{a(this,"PyIterableMethods")}[Symbol.iterator](){let{shared:e}=S(this),r={},n;try{_check_gil();let i=validSuspender.value;validSuspender.value=!1,n=_PyObject_GetIter(e.ptr),validSuspender.value=i}catch(i){API.fatal_error(i)}n===0&&_pythonexc2js();let o=on(n,r,e.cache.json_adaptor_map,Ut(this));return Module.finalizationRegistry.register(o,[n,void 0],r),o}};async function*an(t,e){try{for(;;){let r;try{_check_gil();let n=validSuspender.value;if(validSuspender.value=!1,r=__pyproxy_aiter_next(t),validSuspender.value=n,r===Module.error)break}catch(n){API.fatal_error(n)}try{yield await r}catch(n){if(n&&typeof n=="object"&&n.type==="StopAsyncIteration")return;throw n}finally{r.destroy()}}}finally{Module.finalizationRegistry.unregister(e),_Py_DecRef(t)}_PyErr_Occurred()&&_pythonexc2js()}a(an,"aiter_helper");var Pe=class extends g{static{a(this,"PyAsyncIterable")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&1536)}},et=class{static{a(this,"PyAsyncIterableMethods")}[Symbol.asyncIterator](){let e=p(this),r={},n;try{_check_gil();let i=validSuspender.value;validSuspender.value=!1,n=_PyObject_GetAIter(e),validSuspender.value=i}catch(i){API.fatal_error(i)}n===0&&_pythonexc2js();let o=an(n,r);return Module.finalizationRegistry.register(o,[n,void 0],r),o}},be=class extends g{static{a(this,"PyIterator")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&32)}},tt=class{static{a(this,"PyIteratorMethods")}[Symbol.iterator](){return this}next(e=void 0){let r,n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_Send(p(this),e),validSuspender.value=o}catch(o){API.fatal_error(o)}return r===Module.error&&_pythonexc2js(),r}},ve=class extends g{static{a(this,"PyGenerator")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&2048)}},rt=class{static{a(this,"PyGeneratorMethods")}throw(e){let r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_throw(p(this),e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===Module.error&&_pythonexc2js(),r}return(e){let r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_return(p(this),e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===Module.error&&_pythonexc2js(),r}},xe=class extends g{static{a(this,"PyAsyncIterator")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&1024)}},nt=class{static{a(this,"PyAsyncIteratorMethods")}[Symbol.asyncIterator](){return this}async next(e=void 0){let r;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_asend(p(this),e),validSuspender.value=o}catch(o){API.fatal_error(o)}r===Module.error&&_pythonexc2js();let n;try{n=await r}catch(o){if(o&&typeof o=="object"&&o.type==="StopAsyncIteration")return{done:!0,value:n};throw o}finally{r.destroy()}return{done:!1,value:n}}},we=class extends g{static{a(this,"PyAsyncGenerator")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&4096)}},ot=class{static{a(this,"PyAsyncGeneratorMethods")}async throw(e){let r;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_athrow(p(this),e),validSuspender.value=o}catch(o){API.fatal_error(o)}r===Module.error&&_pythonexc2js();let n;try{n=await r}catch(o){if(o&&typeof o=="object"){if(o.type==="StopAsyncIteration")return{done:!0,value:n};if(o.type==="GeneratorExit")return{done:!0,value:n}}throw o}finally{r.destroy()}return{done:!1,value:n}}async return(e){let r;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_areturn(p(this)),validSuspender.value=o}catch(o){API.fatal_error(o)}r===Module.error&&_pythonexc2js();let n;try{n=await r}catch(o){if(o&&typeof o=="object"){if(o.type==="StopAsyncIteration")return{done:!0,value:n};if(o.type==="GeneratorExit")return{done:!0,value:e}}throw o}finally{r.destroy()}return{done:!1,value:n}}},Se=class extends g{static{a(this,"PySequence")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&8192)}};function sn(t,e){let r=t.toString(),n=e.toString();return r===n?0:r{this.insert(n,r)}),this.length}copyWithin(...e){return Array.prototype.copyWithin.apply(this,e),this}fill(...e){return Array.prototype.fill.apply(this,e),this}};function ln(t,e){let r=p(t),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_hasattr(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}return n===-1&&_pythonexc2js(),n!==0}a(ln,"python_hasattr");function cn(t,e){let{shared:r}=S(t),n=r.cache.map,o;try{_check_gil();let i=validSuspender.value;validSuspender.value=!1,o=__pyproxy_getattr(r.ptr,e,n),validSuspender.value=i}catch(i){API.fatal_error(i)}if(o===Module.error){_PyErr_Occurred()&&_pythonexc2js();return}return o}a(cn,"python_getattr");function un(t,e,r){let n=p(t),o;try{_check_gil();let i=validSuspender.value;validSuspender.value=!1,o=__pyproxy_setattr(n,e,r),validSuspender.value=i}catch(i){API.fatal_error(i)}o===-1&&_pythonexc2js()}a(un,"python_setattr");function yn(t,e){let r=p(t),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_delattr(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}n===-1&&_pythonexc2js()}a(yn,"python_delattr");function dn(t,e,r,n){let o=p(t),i;try{_check_gil();let s=validSuspender.value;validSuspender.value=!1,i=__pyproxy_slice_assign(o,e,r,n),validSuspender.value=s}catch(s){API.fatal_error(s)}return i===Module.error&&_pythonexc2js(),i}a(dn,"python_slice_assign");function Lt(t,e){let r=p(t),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_pop(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}return n===Module.error&&_pythonexc2js(),n}a(Lt,"python_pop");var pn=new Set(["name","length","caller","arguments"]);function ye(t,e,r){return t instanceof Function?e in t&&!(pn.has(e)||r&&e==="prototype"):e in t}a(ye,"filteredHasKey");var P={isExtensible(){return!0},has(t,e){return ye(t,e,!1)?!0:typeof e=="symbol"?!1:(e.startsWith("$")&&(e=e.slice(1)),ln(t,e))},get(t,e){return typeof e=="symbol"||ye(t,e,!0)?Reflect.get(t,e):(e.startsWith("$")&&(e=e.slice(1)),cn(t,e))},set(t,e,r){let n=Object.getOwnPropertyDescriptor(t,e);return n&&!n.writable&&!n.set?!1:typeof e=="symbol"||ye(t,e,!0)?Reflect.set(t,e,r):(e.startsWith("$")&&(e=e.slice(1)),un(t,e,r),!0)},deleteProperty(t,e){let r=Object.getOwnPropertyDescriptor(t,e);return r&&!r.configurable?!1:typeof e=="symbol"||ye(t,e,!0)?Reflect.deleteProperty(t,e):(e.startsWith("$")&&(e=e.slice(1)),yn(t,e),!0)},ownKeys(t){let e=p(t),r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxy_ownKeys(e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===Module.error&&_pythonexc2js(),r.push(...Reflect.ownKeys(t)),r},apply(t,e,r){return t.apply(e,r)}};function K(t){return t&&typeof t=="object"&&t.constructor&&t.constructor.name==="PythonError"}a(K,"isPythonError");var fn={isExtensible(){return!0},has(t,e){return typeof e=="string"&&/^[0-9]+$/.test(e)?Number(e)n.toString())),e.push("length"),e}},gn=new Set(["copy","constructor","$$flags","toString","destroy"]),M={isExtensible(){return!0},has(t,e){return k.prototype.has.call(t,e)?!0:typeof e=="string"&&/^[0-9]+$/.test(e)?k.prototype.has.call(t,Number(e)):!1},get(t,e){if(typeof e=="symbol"||gn.has(e))return Reflect.get(...arguments);let r=B.prototype.get.call(t,e);return r!==void 0||k.prototype.has.call(t,e)?r:typeof e=="string"&&/^[0-9]+$/.test(e)?B.prototype.get.call(t,Number(e)):Reflect.get(...arguments)},set(t,e,r){if(typeof e=="symbol")return!1;!k.prototype.has.call(t,e)&&typeof e=="string"&&/^[0-9]+$/.test(e)&&(e=Number(e));try{return L.prototype.set.call(t,e,r),!0}catch(n){if(K(n)&&n.type==="KeyError")return!1;throw n}},deleteProperty(t,e){if(typeof e=="symbol")return!1;!k.prototype.has.call(t,e)&&typeof e=="string"&&/^[0-9]+$/.test(e)&&(e=Number(e));try{return L.prototype.delete.call(t,e),!0}catch(r){if(K(r)&&r.type==="KeyError")return!1;throw r}},getOwnPropertyDescriptor(t,e){return M.has(t,e)?{configurable:!0,enumerable:!0,value:M.get(t,e),writable:!0}:void 0},ownKeys(t){let e=new Set;return zt(t,e),Array.from(e)}};function zt(t,e){let r=P.get(t,"keys")();for(let n of r)typeof n=="string"?e.add(n):typeof n=="number"&&e.add(n.toString());r.destroy()}a(zt,"dictOwnKeysHelper");var _n={isExtensible(){return!0},has(t,e){return P.has(t,e)?!0:M.has(t,e)},get(t,e){let r=P.get(t,e);return r!==void 0||P.has(t,e)?r:M.get(t,e)},set(t,e,r){return P.has(t,e)?P.set(t,e,r):M.set(t,e,r)},deleteProperty(t,e){return P.has(t,e)?P.deleteProperty(t,e):M.deleteProperty(t,e)},getOwnPropertyDescriptor(t,e){return Reflect.getOwnPropertyDescriptor(t,e)??M.getOwnPropertyDescriptor(t,e)},ownKeys(t){let e=new Set(P.ownKeys(t));return zt(t,e),Array.from(e)}},Ie=class extends g{static{a(this,"PyAwaitable")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&64)}},st=class{static{a(this,"PyAwaitableMethods")}_ensure_future(){let{shared:e}=Oe(this);if(e.promise)return e.promise;let r=e.ptr;r||S(this);let n,o,i=new Promise((l,c)=>{n=l,o=c}),s;try{_check_gil();let l=validSuspender.value;validSuspender.value=!1,s=__pyproxy_ensure_future(r,n,o),validSuspender.value=l}catch(l){API.fatal_error(l)}return s===-1&&_pythonexc2js(),e.promise=i,this.destroy(),i}then(e,r){return this._ensure_future().then(e,r)}catch(e){return this._ensure_future().catch(e)}finally(e){return this._ensure_future().finally(e)}},Ee=class extends g{static{a(this,"PyCallable")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&256)}},ke=class{static{a(this,"PyCallableMethods")}apply(e,r){return r=function(...n){return n}.apply(void 0,r),r=Ft(this,e,r),Module.callPyObject(p(this),r)}call(e,...r){return r=Ft(this,e,r),Module.callPyObject(p(this),r)}callWithOptions({relaxed:e,kwargs:r,promising:n},...o){let i={};if(r){if(o.length===0)throw new TypeError("callWithOptions with 'kwargs: true' requires at least one argument (the key word argument object)");if(i=o.pop(),i.constructor!==void 0&&i.constructor.name!=="Object")throw new TypeError("kwargs argument is not an object")}let s=e?API.pyodide_code.relaxed_call:this;return e&&o.unshift(this),(n?de:pe)(p(s),o,i)}callKwargs(...e){if(e.length===0)throw new TypeError("callKwargs requires at least one argument (the key word argument object)");let r=e.pop();if(r.constructor!==void 0&&r.constructor.name!=="Object")throw new TypeError("kwargs argument is not an object");return pe(p(this),e,r)}callRelaxed(...e){return API.pyodide_code.relaxed_call(this,...e)}callKwargsRelaxed(...e){return API.pyodide_code.relaxed_call.callKwargs(this,...e)}callPromising(...e){return de(p(this),e,{})}callPromisingKwargs(...e){if(e.length===0)throw new TypeError("callKwargs requires at least one argument (the key word argument object)");let r=e.pop();if(r.constructor!==void 0&&r.constructor.name!=="Object")throw new TypeError("kwargs argument is not an object");return de(p(this),e,r)}bind(e,...r){let{shared:n,props:o}=S(this),{boundArgs:i,boundThis:s,isBound:l}=o,c=e;l&&(c=s);let u=i.concat(r);return o=Object.assign({},o,{boundArgs:u,isBound:!0,boundThis:c}),J(n.ptr,{shared:n,flags:h(this),props:o})}captureThis(){let{props:e,shared:r}=S(this);return e=Object.assign({},e,{captureThis:!0}),J(r.ptr,{shared:r,flags:h(this),props:e})}};ke.prototype.prototype=Function.prototype;var mn=new Map([["i8",Int8Array],["u8",Uint8Array],["u8clamped",Uint8ClampedArray],["i16",Int16Array],["u16",Uint16Array],["i32",Int32Array],["u32",Uint32Array],["i32",Int32Array],["u32",Uint32Array],["i64",globalThis.BigInt64Array],["u64",globalThis.BigUint64Array],["f32",Float32Array],["f64",Float64Array],["dataview",DataView]]),Me=class extends g{static{a(this,"PyBuffer")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(h(e)&128)}},lt=class{static{a(this,"PyBufferMethods")}getBuffer(e){let r;if(e&&(r=mn.get(e),r===void 0))throw new Error(`Unknown type ${e}`);let n=p(this),o;try{_check_gil();let A=validSuspender.value;validSuspender.value=!1,o=__pyproxy_get_buffer(n),validSuspender.value=A}catch(A){API.fatal_error(A)}o===Module.error&&_pythonexc2js();let{start_ptr:i,smallest_ptr:s,largest_ptr:l,readonly:c,format:u,itemsize:y,shape:_,strides:m,view:f,c_contiguous:I,f_contiguous:oe}=o,ae=!1;try{let A=!1;r===void 0&&([r,A]=Module.processBufferFormatString(u," In this case, you can pass an explicit type argument."));let N=parseInt(r.name.replace(/[^0-9]/g,""))/8||1;if(A&&N>1)throw new Error("JavaScript has no native support for big endian buffers. In this case, you can pass an explicit type argument. For instance, `getBuffer('dataview')` will return a `DataView`which has native support for reading big endian data. Alternatively, toJs will automatically convert the buffer to little endian.");let ie=l-s;if(ie!==0&&(i%N!==0||s%N!==0||l%N!==0))throw new Error(`Buffer does not have valid alignment for a ${r.name}`);let Or=ie/N,Tr=(i-s)/N,We;ie===0?We=new r:We=new r(HEAPU32.buffer,s,Or);for(let Fr of m.keys())m[Fr]/=N;return ae=!0,Object.create(q.prototype,Object.getOwnPropertyDescriptors({offset:Tr,readonly:c,format:u,itemsize:y,ndim:_.length,nbytes:ie,shape:_,strides:m,data:We,c_contiguous:I,f_contiguous:oe,_view_ptr:f,_released:!1}))}finally{if(!ae)try{_check_gil();let A=validSuspender.value;validSuspender.value=!1,_PyBuffer_Release(f),_PyMem_Free(f),validSuspender.value=A}catch(A){API.fatal_error(A)}}}},Ne=class extends g{static{a(this,"PyDict")}static[Symbol.hasInstance](e){return API.isPyProxy(e)&&e.type==="dict"}},q=class{static{a(this,"PyBufferView")}constructor(){throw new TypeError("PyBufferView is not a constructor")}release(){if(!this._released){try{_check_gil();let e=validSuspender.value;validSuspender.value=!1,_PyBuffer_Release(this._view_ptr),_PyMem_Free(this._view_ptr),validSuspender.value=e}catch(e){API.fatal_error(e)}this._released=!0,this.data=Module.error}}};var Gt={PyProxy:g,PyProxyWithLength:fe,PyProxyWithGet:ge,PyProxyWithSet:_e,PyProxyWithHas:me,PyDict:Ne,PyIterable:he,PyAsyncIterable:Pe,PyIterator:be,PyAsyncIterator:xe,PyGenerator:ve,PyAsyncGenerator:we,PyAwaitable:Ie,PyCallable:Ee,PyBuffer:Me,PyBufferView:q,PythonError:R,PySequence:Se,PyMutableSequence:Ae};function Vt(t){t.id!=="canvas"&&console.warn("If you are using canvas element for SDL library, it should have id 'canvas' to work properly."),Module.canvas=t}a(Vt,"setCanvas2D");function Kt(){return Module.canvas}a(Kt,"getCanvas2D");function hn(t){Vt(t)}a(hn,"setCanvas3D");function Pn(){return Kt()}a(Pn,"getCanvas3D");var Jt={setCanvas2D:Vt,getCanvas2D:Kt,setCanvas3D:hn,getCanvas3D:Pn};var qt=new Map([["INSTALLER","pyodide.unpackArchive"]]);function bn(){if(typeof API<"u"&&API!==globalThis.API)return API.runtimeEnv;let t=typeof Bun<"u",e=typeof Deno<"u",r=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&!process.browser,n=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent.indexOf("Chrome")===-1&&navigator.userAgent.indexOf("Safari")>-1;return vn({IN_BUN:t,IN_DENO:e,IN_NODE:r,IN_SAFARI:n,IN_SHELL:typeof read=="function"&&typeof load=="function"})}a(bn,"getGlobalRuntimeEnv");var d=bn();function vn(t){let e=t.IN_NODE&&typeof module<"u"&&module.exports&&typeof b=="function"&&typeof __dirname=="string",r=t.IN_NODE&&!e,n=!t.IN_NODE&&!t.IN_DENO&&!t.IN_BUN,o=n&&typeof window<"u"&&typeof window.document<"u"&&typeof document.createElement=="function"&&"sessionStorage"in window&&typeof globalThis.importScripts!="function",i=n&&typeof globalThis.WorkerGlobalScope<"u"&&typeof globalThis.self<"u"&&globalThis.self instanceof globalThis.WorkerGlobalScope;return{...t,IN_BROWSER:n,IN_BROWSER_MAIN_THREAD:o,IN_BROWSER_WEB_WORKER:i,IN_NODE_COMMONJS:e,IN_NODE_ESM:r}}a(vn,"calculateDerivedFlags");function yt(){let t=a(()=>{},"_resolve"),e=a(()=>{},"_reject"),r=new Promise((n,o)=>{t=n,e=o});return r.resolve=t,r.reject=e,r}a(yt,"createResolvable");function Te(){let t=Promise.resolve();async function e(){let r=t,n;return t=new Promise(o=>n=o),await r,n}return a(e,"acquireLock"),e}a(Te,"createLock");var xn=/[-_.]+/g;function Yt(t){return t.replace(xn,"-").toLowerCase()}a(Yt,"canonicalizePackageName");var wn=/^.*?([^\/]*)\.whl$/;function Qt(t){let e=wn.exec(t);if(e){let r=e[1].toLowerCase().split("-");return{name:r[0],version:r[1],fileName:r.join("-")+".whl"}}}a(Qt,"uriToPackageData");function Xt(t){return btoa(t.match(/\w{2}/g).map(function(e){return String.fromCharCode(parseInt(e,16))}).join(""))}a(Xt,"base16ToBase64");var Zt,dt,er,Re,H;async function tr(){if(!d.IN_NODE||(Zt=(await import("node:url")).default,Re=await import("node:fs"),H=await import("node:fs/promises"),er=(await import("node:vm")).default,dt=await import("node:path"),nr=dt.sep,typeof b<"u"))return;let t=Re,e=await import("node:crypto"),r=await import("ws"),n=await import("node:child_process"),o={fs:t,crypto:e,ws:r,child_process:n};globalThis.require=function(i){return o[i]}}a(tr,"initNodeModules");function rr(t){return t.includes("://")||t.startsWith("/")}a(rr,"isAbsolute");function Sn(t,e){return dt.resolve(e||".",t)}a(Sn,"node_resolvePath");function An(t,e){return e===void 0&&(e=location),new URL(t,e).toString()}a(An,"browser_resolvePath");var Y;d.IN_NODE?Y=Sn:d.IN_SHELL?Y=a(t=>t,"resolvePath"):Y=An;var nr;d.IN_NODE||(nr="/");function In(t,e){return t.startsWith("file://")&&(t=t.slice(7)),t.includes("://")?{response:fetch(t)}:{binary:H.readFile(t).then(r=>new Uint8Array(r.buffer,r.byteOffset,r.byteLength))}}a(In,"node_getBinaryResponse");function En(t,e){if(t.startsWith("file://")&&(t=t.slice(7)),t.includes("://"))throw new Error("Shell cannot fetch urls");return{binary:Promise.resolve(new Uint8Array(readbuffer(t)))}}a(En,"shell_getBinaryResponse");function kn(t,e){let r=new URL(t,location);return{response:fetch(r,e?{integrity:e}:{})}}a(kn,"browser_getBinaryResponse");var De;d.IN_NODE?De=In:d.IN_SHELL?De=En:De=kn;async function Q(t,e){let{response:r,binary:n}=De(t,e);if(n)return n;let o=await r;if(!o.ok)throw new Error(`Failed to load '${t}': request failed.`);return new Uint8Array(await o.arrayBuffer())}a(Q,"loadBinaryFile");var Fe;if(d.IN_BROWSER_MAIN_THREAD)Fe=a(async t=>await import(t),"loadScript");else if(d.IN_BROWSER_WEB_WORKER)Fe=a(async t=>{try{globalThis.importScripts(t)}catch(e){if(e instanceof TypeError)await import(t);else throw e}},"loadScript");else if(d.IN_NODE)Fe=Mn;else if(d.IN_SHELL)Fe=load;else throw new Error("Cannot determine runtime environment");async function Mn(t){t.startsWith("file://")&&(t=t.slice(7)),t.includes("://")?er.runInThisContext(await(await fetch(t)).text()):await import(Zt.pathToFileURL(t).href)}a(Mn,"nodeLoadScript");async function or(t){if(d.IN_NODE&&t)try{await H.stat(t)}catch{await H.mkdir(t,{recursive:!0})}}a(or,"ensureDirNode");var X=class{constructor(e,r){this._lock=Te();this.#t=e,this.#e=r}static{a(this,"DynlibLoader")}#t;#e;async loadDynlib(e){let r=await this._lock();try{let n=this.#e.stackSave(),o=this.#e.stringToUTF8OnStack(e);try{let i=this.#e._emscripten_dlopen_promise(o,2);this.#e.stackRestore(n);let s=this.#e.getPromise(i);this.#e.promiseMap.free(i),await s}catch(i){let s=this.getDLError();throw new Error(`Failed to load dynamic library ${e}: ${s??i}`)}}catch(n){throw n&&n.message&&n.message.includes("need to see wasm magic number")?new Error(`Failed to load dynamic library ${e} $. We probably just tried to load a linux .so file or something.`):n}finally{r()}}getDLError(){let e=this.#e._dlerror();return e===0?void 0:this.#e.UTF8ToString(e,512).trim()}async loadDynlibsFromPackage(e,r){for(let n of r)await this.loadDynlib(n)}};if(typeof API<"u"&&typeof Module<"u"){let t=new X(API,Module);API.loadDynlib=t.loadDynlib.bind(t)}var Z=class{static{a(this,"Installer")}#t;#e;constructor(e,r){this.#t=e,this.#e=new X(e,r)}async install(e,r,n,o){let i=this.#t.package_loader.unpack_buffer.callKwargs({buffer:e,filename:r,extract_dir:n,metadata:o,calculate_dynlibs:!0});await this.#e.loadDynlibsFromPackage({file_name:r},i)}},ar;if(typeof API<"u"&&typeof Module<"u"){let t=new Z(API,Module);ar=t.install.bind(t),API.install=ar}function Nn(t,e,r){t();let n;try{n=r()}catch(o){throw e(),o}return n instanceof Promise?n.finally(()=>e()):(e(),n)}a(Nn,"withContext");function ir(t,e){return function(r){return function(...n){return Nn(t,e,()=>r.apply(this,n))}}}a(ir,"createContextWrapper");async function On(t){await tr();let e=await t,r=typeof e=="string"?JSON.parse(e):e;if(!r.packages)throw new Error("Loaded pyodide lock file does not contain the expected key 'packages'.");if(r.info.abi_version!==API.abiVersion)throw new Error(`Lock file ABI version doesn't match Pyodide ABI version.\n lockfile version: ${r.info.abi_version}\n pyodide version: ${API.abiVersion}`);API.lockfile=r,API.lockfile_info=r.info,API.lockfile_packages=r.packages,API.lockfile_unvendored_stdlibs_and_test=[],API._import_name_to_package_name=new Map;for(let i of Object.keys(API.lockfile_packages)){let s=API.lockfile_packages[i];for(let l of s.imports)API._import_name_to_package_name.set(l,i);s.package_type==="cpython_module"&&API.lockfile_unvendored_stdlibs_and_test.push(i)}API.lockfile_unvendored_stdlibs=API.lockfile_unvendored_stdlibs_and_test.filter(i=>i!=="test");let n=API.config.packages;API.config.fullStdLib&&(n=[...n,...API.lockfile_unvendored_stdlibs]),await te(n,{messageCallback(){}}),await API.bootstrapFinalizedPromise,API.flushPackageManagerBuffers(),API._pyodide._importhook.register_module_not_found_hook(API._import_name_to_package_name,API.lockfile_unvendored_stdlibs_and_test),API.package_loader.init_loaded_packages()}a(On,"initializePackageIndex");var Tn="default channel",Fn="pyodide.loadPackage",pt=class{constructor(e,r){this.cdnURL="";this.loadedPackages={};this._lock=Te();this.streamReady=!1;this.stdoutBuffer=[];this.stderrBuffer=[];this.defaultChannel=Tn;this.#t=e,this.#e=r,this.#r=new Z(e,r),d.IN_NODE?(this.installBaseUrl=this.#t.config.packageCacheDir??this.#t.config.packageBaseUrl,this.cdnURL=this.#t.config.cdnUrl):this.installBaseUrl=this.#t.config.packageBaseUrl,this.stdout=n=>{if(!this.streamReady){this.stdoutBuffer.push(n);return}let o=this.#e.stackSave();try{let i=this.#e.stringToUTF8OnStack(n);this.#e._print_stdout(i)}finally{this.#e.stackRestore(o)}},this.stderr=n=>{if(!this.streamReady){this.stderrBuffer.push(n);return}let o=this.#e.stackSave();try{let i=this.#e.stringToUTF8OnStack(n);this.#e._print_stderr(i)}finally{this.#e.stackRestore(o)}}}static{a(this,"PackageManager")}#t;#e;#r;async loadPackage(e,r={checkIntegrity:!0}){return this.setCallbacks(r.messageCallback,r.errorCallback)(this.loadPackageInner.bind(this))(e,r)}async loadPackageInner(e,r={checkIntegrity:!0}){let n=new Set,o=Rn(e),i=this.recursiveDependencies(o);for(let[u,{name:y,normalizedName:_,channel:m}]of i){let f=this.getLoadedPackageChannel(y);f&&(i.delete(_),f===m||m===this.defaultChannel?this.logStdout(`${y} already loaded from ${f}`):this.logStderr(`URI mismatch, attempting to load package ${y} from ${m} while it is already loaded from ${f}. To override a dependency, load the custom package first.`))}if(i.size===0)return this.logStdout("No new packages to load"),[];let s=Array.from(i.values(),({name:u})=>u).sort().join(", "),l=new Map,c=await this._lock();try{this.logStdout(`Loading ${s}`);for(let[u,y]of i){if(this.getLoadedPackageChannel(y.name)){i.delete(y.normalizedName);continue}y.installPromise=this.downloadAndInstall(y,i,n,l,r.checkIntegrity)}if(await Promise.all(Array.from(i.values()).map(({installPromise:u})=>u)),n.size>0){let u=Array.from(n,y=>y.name).sort().join(", ");this.logStdout(`Loaded ${u}`)}if(l.size>0){let u=Array.from(l.keys()).sort().join(", ");this.logStdout(`Failed to load ${u}`);for(let[y,_]of l)this.logStderr(`The following error occurred while loading ${y}:`),this.logStderr(_.message)}return await this.#t.bootstrapFinalizedPromise,this.#t.importlib.invalidate_caches(),Array.from(n,Dn)}finally{c()}}addPackageToLoad(e,r){let n=Yt(e);if(r.has(n))return;let o=this.#t.lockfile_packages[n];if(!o)throw new Error(`No known package with name '${e}'`);if(r.set(n,{name:o.name,normalizedName:n,channel:this.defaultChannel,depends:o.depends,installPromise:void 0,done:yt(),packageData:o}),!this.getLoadedPackageChannel(o.name))for(let i of o.depends)this.addPackageToLoad(i,r)}recursiveDependencies(e){let r=new Map;for(let n of e){let o=Qt(n);if(o===void 0){this.addPackageToLoad(n,r);continue}let{name:i,version:s,fileName:l}=o,c=n;if(r.has(i)&&r.get(i).channel!==c){this.logStderr(`Loading same package ${i} from ${c} and ${r.get(i).channel}`);continue}r.set(i,{name:i,normalizedName:i,channel:c,depends:[],installPromise:void 0,done:yt(),packageData:{name:i,version:s,file_name:l,install_dir:"site",sha256:"",package_type:"package",imports:[],depends:[]}})}return r}async downloadPackage(e,r=!0){await or(this.installBaseUrl);let n,o,i;if(e.channel===this.defaultChannel){if(!(e.normalizedName in this.#t.lockfile_packages))throw new Error(`Internal error: no entry for package named ${name}`);let l=this.#t.lockfile_packages[e.normalizedName];if(n=l.file_name,!rr(n)&&!this.installBaseUrl)throw new Error(`Lock file file_name for package "${e.name}" is relative path "${n}" but no packageBaseUrl provided to loadPyodide.`);o=Y(n,this.installBaseUrl),i="sha256-"+Xt(l.sha256)}else o=e.channel,i=void 0;r||(i=void 0);try{return await Q(o,i)}catch(l){if(!d.IN_NODE||e.channel!==this.defaultChannel||!n||n.startsWith("/"))throw l}this.logStdout(`Didn't find package ${n} locally, attempting to load from ${this.cdnURL}`);let s=await Q(this.cdnURL+n);return this.logStdout(`Package ${n} loaded from ${this.cdnURL}, caching the wheel in node_modules for future use.`),await H.writeFile(o,s),s}async installPackage(e,r){let n=this.#t.lockfile_packages[e.normalizedName];n||(n=e.packageData);let o=n.file_name,i=this.#t.package_loader.get_install_dir(n.install_dir);await this.#r.install(r,o,i,new Map([["INSTALLER",Fn],["PYODIDE_SOURCE",e.channel===this.defaultChannel?"pyodide":e.channel]]))}async downloadAndInstall(e,r,n,o,i=!0){if(ee[e.name]===void 0)try{let s=await this.downloadPackage(e,i),l=e.depends.map(c=>r.has(c)?r.get(c).done:Promise.resolve());await this.#t.bootstrapFinalizedPromise,await Promise.all(l),await this.installPackage(e,s),n.add(e.packageData),ee[e.name]=e.channel}catch(s){o.set(e.name,s)}finally{e.done.resolve()}}flushBuffers(){this.streamReady=!0;for(let e of this.stdoutBuffer)this.stdout(e);for(let e of this.stderrBuffer)this.stderr(e);this.stdoutBuffer=[],this.stderrBuffer=[]}getLoadedPackageChannel(e){let r=this.loadedPackages[e];return r===void 0?null:r}setCallbacks(e,r){let n=this.stdout,o=this.stderr;return ir(()=>{this.stdout=e||n,this.stderr=r||o},()=>{this.stdout=n,this.stderr=o})}logStdout(e){this.stdout(e)}logStderr(e){this.stderr(e)}};function Dn({name:t,version:e,file_name:r,package_type:n}){return{name:t,version:e,fileName:r,packageType:n}}a(Dn,"filterPackageData");function Rn(t){return typeof t.toJs=="function"&&(t=t.toJs()),Array.isArray(t)||(t=[t]),t}a(Rn,"toStringArray");var te,ee;if(typeof API<"u"&&typeof Module<"u"){let t=new pt(API,Module);te=t.loadPackage.bind(t),ee=t.loadedPackages,API.flushPackageManagerBuffers=t.flushBuffers.bind(t),API.lockFilePromise&&(API.packageIndexReady=On(API.lockFilePromise)),API.packageManager=t}var sr="0.29.3";var vt=d.IN_NODE?b("node:fs"):void 0,ur=d.IN_NODE?b("node:tty"):void 0;function yr(t){try{vt.fsyncSync(t)}catch(e){if(e?.code==="EINVAL"||(t===0||t===1||t===2)&&(e?.code==="ENOTSUP"||e?.code==="EBADF"||e?.code==="EPERM"))return;throw e}}a(yr,"nodeFsync");var dr=!1,$e={},x={};function gt(t){$e[x.stdin]=t}a(gt,"_setStdinOps");function Ln(t){$e[x.stdout]=t}a(Ln,"_setStdoutOps");function $n(t){$e[x.stderr]=t}a($n,"_setStderrOps");function Cn(t){return t&&typeof t=="object"&&"errno"in t}a(Cn,"isErrnoError");var Un=new Int32Array(new WebAssembly.Memory({shared:!0,initial:1,maximum:1}).buffer);function Bn(t){try{return Atomics.wait(Un,0,0,t),!0}catch{return!1}}a(Bn,"syncSleep");function Hn(t){for(;;)try{return t()}catch(e){if(e&&e.code==="EAGAIN"&&Bn(100))continue;throw e}}a(Hn,"handleEAGAIN");function lr(t,e,r){let n;try{n=Hn(e)}catch(o){throw o&&o.code&&Module.ERRNO_CODES[o.code]?new FS.ErrnoError(Module.ERRNO_CODES[o.code]):Cn(o)?o:(console.error("Error thrown in read:"),console.error(o),new FS.ErrnoError(29))}if(n===void 0)throw console.warn(`${r} returned undefined; a correct implementation must return a number`),new FS.ErrnoError(29);return n!==0&&(t.node.timestamp=Date.now()),n}a(lr,"readWriteHelper");var cr=a((t,e,r)=>API.typedArrayAsUint8Array(t).subarray(e,e+r),"prepareBuffer"),ft={open:a(function(t){let e=$e[t.node.rdev];if(!e)throw new FS.ErrnoError(43);t.devops=e,t.tty=t.devops.isatty?{ops:{}}:void 0,t.seekable=!1},"open"),close:a(function(t){t.stream_ops.fsync(t)},"close"),fsync:a(function(t){let e=t.devops;e.fsync&&e.fsync()},"fsync"),read:a(function(t,e,r,n,o){return e=cr(e,r,n),lr(t,()=>t.devops.read(e),"read")},"read"),write:a(function(t,e,r,n,o){return e=cr(e,r,n),lr(t,()=>t.devops.write(e),"write")},"write")};function Ce(){dr&&(FS.closeStream(0),FS.closeStream(1),FS.closeStream(2),FS.open("/dev/stdin",0),FS.open("/dev/stdout",1),FS.open("/dev/stderr",1))}a(Ce,"refreshStreams");API.initializeStreams=function(t,e,r){let n=FS.createDevice.major++;x.stdin=FS.makedev(n,0),x.stdout=FS.makedev(n,1),x.stderr=FS.makedev(n,2),FS.registerDevice(x.stdin,ft),FS.registerDevice(x.stdout,ft),FS.registerDevice(x.stderr,ft),FS.unlink("/dev/stdin"),FS.unlink("/dev/stdout"),FS.unlink("/dev/stderr"),FS.mkdev("/dev/stdin",x.stdin),FS.mkdev("/dev/stdout",x.stdout),FS.mkdev("/dev/stderr",x.stderr),re({stdin:t}),xt({batched:e}),wt({batched:r}),dr=!0,Ce()};function jn(){d.IN_NODE?re(new mt(process.stdin.fd)):re({stdin:a(()=>prompt(),"stdin")})}a(jn,"setDefaultStdin");function Wn(){gt(new _t),Ce()}a(Wn,"setStdinError");function re(t={}){let{stdin:e,error:r,isatty:n,autoEOF:o,read:i}=t,s=+!!e+ +!!r+ +!!i;if(s>1)throw new TypeError("At most one of stdin, read, and error must be provided.");if(!e&&o!==void 0)throw new TypeError("The 'autoEOF' option can only be used with the 'stdin' option");if(s===0){jn();return}r&&Wn(),e&&(o=o===void 0?!0:o,gt(new ht(e.bind(t),!!n,o))),i&>(t),Ce()}a(re,"setStdin");function pr(t,e,r){let{raw:n,isatty:o,batched:i,write:s}=t,l=+!!n+ +!!i+ +!!s;if(l===0&&(t=r(),({raw:n,isatty:o,batched:i,write:s}=t)),l>1)throw new TypeError("At most one of 'raw', 'batched', and 'write' must be passed");if(!n&&!s&&o)throw new TypeError("Cannot set 'isatty' to true unless 'raw' or 'write' is provided");n&&e(new Pt(n.bind(t),!!o)),i&&e(new bt(i.bind(t))),s&&e(t),Ce()}a(pr,"_setStdwrite");function zn(){return d.IN_NODE?new Le(process.stdout.fd):{batched:a(t=>console.log(t),"batched")}}a(zn,"_getStdoutDefaults");function Gn(){return d.IN_NODE?new Le(process.stderr.fd):{batched:a(t=>console.warn(t),"batched")}}a(Gn,"_getStderrDefaults");function xt(t={}){pr(t,Ln,zn)}a(xt,"setStdout");function wt(t={}){pr(t,$n,Gn)}a(wt,"setStderr");var Vn=globalThis.TextEncoder??function(){},Kn=new Vn,_t=class{static{a(this,"ErrorReader")}read(e){throw new FS.ErrnoError(29)}},mt=class{static{a(this,"NodeReader")}constructor(e){this.fd=e,this.isatty=ur.isatty(e)}read(e){try{return vt.readSync(this.fd,e)}catch(r){if(r.toString().includes("EOF"))return 0;throw r}}fsync(){yr(this.fd)}},ht=class{static{a(this,"LegacyReader")}constructor(e,r,n){this.infunc=e,this.isatty=r,this.autoEOF=n,this.index=0,this.saved=void 0,this.insertEOF=!1}_getInput(){if(this.saved)return this.saved;let e=this.infunc();if(typeof e=="number")return e;if(e!=null){if(ArrayBuffer.isView(e)){if(e.BYTES_PER_ELEMENT!==1)throw console.warn(`Expected BYTES_PER_ELEMENT to be 1, infunc gave ${e.constructor}`),new FS.ErrnoError(29);return e}if(typeof e=="string")return e.endsWith(`\n`)||(e+=`\n`),e;if(Object.prototype.toString.call(e)==="[object ArrayBuffer]")return new Uint8Array(e);throw console.warn("Expected result to be undefined, null, string, array buffer, or array buffer view"),new FS.ErrnoError(29)}}read(e){if(this.insertEOF)return this.insertEOF=!1,0;let r=0;for(;;){let n=this._getInput();if(typeof n=="number"){e[0]=n,e=e.subarray(1),r++;continue}let o;if(n&&n.length>0)if(typeof n=="string"){let{read:i,written:s}=Kn.encodeInto(n,e);this.saved=n.slice(i),r+=s,o=e[s-1],e=e.subarray(s)}else{let i;n.length>e.length?(e.set(n.subarray(0,e.length)),this.saved=n.subarray(e.length),i=e.length):(e.set(n),this.saved=void 0,i=n.length),r+=i,o=e[i-1],e=e.subarray(i)}if(!(n&&n.length>0)||this.autoEOF||e.length===0)return this.insertEOF=r>0&&this.autoEOF&&o!==10,r}}fsync(){}},Pt=class{static{a(this,"CharacterCodeWriter")}constructor(e,r){this.out=e,this.isatty=r}write(e){for(let r of e)this.out(r);return e.length}},bt=class{constructor(e){this.isatty=!1;this.out=e,this.output=[]}static{a(this,"StringWriter")}write(e){for(let r of e)r===10?(this.out(UTF8ArrayToString(new Uint8Array(this.output))),this.output=[]):r!==0&&this.output.push(r);return e.length}fsync(){this.output&&this.output.length>0&&(this.out(UTF8ArrayToString(new Uint8Array(this.output))),this.output=[])}},Le=class{static{a(this,"NodeWriter")}constructor(e){this.fd=e,this.isatty=ur.isatty(e)}write(e){return vt.writeSync(this.fd,e)}fsync(){yr(this.fd)}};var St="sched$"+Math.random().toString(36).slice(2)+"$",W={},fr=0,j=null,At=[],Jn=typeof globalThis.scheduler?.postTask=="function";function qn(){if(!d.IN_BROWSER_MAIN_THREAD)return;let t=a(e=>{if(typeof e.data=="string"&&e.data.indexOf(St)===0){let r=+e.data.slice(St.length),n=W[r];if(!n)return;try{n()}finally{delete W[r]}}},"onGlobalMessage");globalThis.addEventListener("message",t,!1)}a(qn,"installPostMessageHandler");qn();function Yn(){j||d.IN_SAFARI||d.IN_DENO||d.IN_NODE||typeof globalThis.MessageChannel=="function"&&(j=new MessageChannel,j.port1.onmessage=()=>{let t=At.length;for(let e=0;e({value:t,enumerable:!0,writable:!0,configurable:!0}),"getPropertyDescriptor"),_r=Symbol(),gr="prototype",ro={deleteProperty:a((t,e)=>t.has(e)?t.delete(e):delete t[e],"deleteProperty"),get(t,e,r){if(e===_r)return t;let n=t[e];return typeof n=="function"&&e!=="constructor"&&(n=n.bind(t)),n||=t.get(e),n},getOwnPropertyDescriptor(t,e){if(t.has(e))return to(t.get(e));if(e in t)return Zn(t,e)},has:a((t,e)=>t.has(e)||e in t,"has"),ownKeys:a(t=>[...t.keys(),...eo(t)].filter(e=>["string","symbol"].includes(typeof e)),"ownKeys"),set:a((t,e,r)=>(t.set(e,r),!0),"set")},no=new Proxy(class extends Map{static{a(this,"LiteralMap")}constructor(...e){return new Proxy(super(...e),ro)}},{get(t,e,...r){return e!==gr&&e in t[gr]?(n,...o)=>{let i=n[_r],s=i[e];return typeof s=="function"&&(s=s.apply(i,o)),s===i?n:s}:Xn(t,e,...r)}}),mr=no;var Be=new FinalizationRegistry(t=>void t());function oo(t){let e=new AbortController;for(let l of t)if(l.aborted)return e.abort(l.reason),e.signal;let r=new WeakRef(e),n=[],o=t.length;t.forEach(l=>{let c=new WeakRef(l);function u(){r.deref()?.abort(c.deref()?.reason)}a(u,"abort"),l.addEventListener("abort",u),n.push([c,u]),Be.register(l,()=>!--o&&i(),l)});function i(){n.forEach(([l,c])=>{let u=l.deref();u&&(u.removeEventListener("abort",c),Be.unregister(u));let y=r.deref();y&&(Be.unregister(y.signal),delete y.signal.__controller)})}a(i,"clear");let{signal:s}=e;return Be.register(s,i,s),s.addEventListener("abort",i),s.__controller=e,s}a(oo,"abortSignalAny");var hr=oo;API.getExpectedKeys=function(){return[null,API.config.jsglobals,API.public_api,API,Ue,API,{}]};var xr=Symbol("getAccessorList"),Pr=Symbol("getObject");function He(t,e=[]){return new Proxy(t,{get(r,n,o){if(n===xr)return e;if(n===Pr)return r;let i=Reflect.get(...arguments),s=Reflect.getOwnPropertyDescriptor(r,n);return s&&s.writable===!1&&!s.configurable||s&&s.set&&!s.get||!["object","function"].includes(typeof i)?i:He(i,[...e,n])},apply(r,n,o){return n=n?.[Pr]??n,Reflect.apply(r,n,o)},getPrototypeOf(){return He(Reflect.getPrototypeOf(...arguments),[...e,"[getProtoTypeOf]"])}})}a(He,"makeGlobalsProxy");var wr=1886286592,je=48;function ao(t,e){if(e.length!==8)throw new Error("Expected 256 bit buffer");for(let r=0;r<32;r++)e[r]=parseInt(t.slice(r*8,(r+1)*8),16)}a(ao,"encodeBuildId");function io(t){if(t.length!==8)throw new Error("Expected 256 bit buffer");return Array.from(t,e=>e.toString(16).padStart(8,"0")).join("")}a(io,"decodeBuildId");function br(t,e,r){if(e===r)return;if(typeof r=="function"&&typeof e!="function")throw console.warn(r,e),new Error(`Expected function at index ${t}`);let n=!1;try{n=JSON.stringify(e)===JSON.stringify(r)}catch(o){console.warn(o)}if(!n)throw console.warn(r,e),new Error(`Unexpected hiwire entry at index ${t}`)}a(br,"checkEntry");var ne=6;API.serializeHiwireState=function(t,e){e||(e=br);let r=[],n=API.getExpectedKeys();for(let s=0;svr(i,o)),e.hiwireKeys.forEach((o,i)=>{let s;if(!o)s=o;else if("path"in o)s=o.path.reduce((l,c)=>l[c],t)||null;else if("abortSignalAny"in o)s=API.abortSignalAny;else if("API"in o)s=API;else{if(!r)throw new Error("You must pass an appropriate deserializer as _snapshotDeserializer");s=r(o.serialized)}vr(n.length+i,s)}),e.immortalKeys.forEach(o=>Module.__hiwire_immortal_add(o))}a(Ar,"syncUpSnapshotLoad2");async function Ir(t,e){return new Promise((r,n)=>{t.FS.syncfs(e,o=>{o?n(o):r()})})}a(Ir,"syncfs");async function Er(t){return await Ir(t,!1)}a(Er,"syncLocalToRemote");async function kr(t){return await Ir(t,!0)}a(kr,"syncRemoteToLocal");API.loadBinaryFile=Q;API.rawRun=a(function(e){let r=Module.stringToNewUTF8(e);Module.API.capture_stderr();let n=_PyRun_SimpleString(r);_free(r);let o=Module.API.restore_stderr().trim();return[n,o]},"rawRun");API.runPythonInternal=function(t){return API._pyodide._base.eval_code(t,API.runPythonInternal_dict)};API.setPyProxyToStringMethod=function(t){Module.HEAP8[Module._compat_to_string_repr]=+t};API.setCompatToJsLiteralMap=function(t){Module.HEAP8[Module._compat_dict_to_literalmap]=+t};API.setCompatNullToNone=function(t){Module.HEAP8[Module._compat_null_to_none]=+t};API.saveState=()=>API.pyodide_py._state.save_state();API.restoreState=t=>API.pyodide_py._state.restore_state(t);API.scheduleCallback=Ue;typeof AbortSignal<"u"&&AbortSignal.any?API.abortSignalAny=AbortSignal.any:API.abortSignalAny=hr;API.LiteralMap=mr;function Mr(t){Module.FS.mkdirTree(t);let{node:e}=Module.FS.lookupPath(t,{follow_mount:!1});if(Module.FS.isMountpoint(e))throw new Error(`path '${t}' is already a file system mount point`);if(!Module.FS.isDir(e.mode))throw new Error(`path '${t}' points to a file not a directory`);for(let r in e.contents)throw new Error(`directory '${t}' is not empty`)}a(Mr,"ensureMountPathExists");var It=class{static{a(this,"PyodideAPI_")}static{this.version=sr}static{this.loadPackage=te}static{this.loadedPackages=ee}static{this.ffi=Gt}static{this.setStdin=re}static{this.setStdout=xt}static{this.setStderr=wt}static{this.globals={}}static{this.FS={}}static{this.PATH={}}static{this.canvas=Jt}static{this.ERRNO_CODES={}}static{this.pyodide_py={}}static async loadPackagesFromImports(e,r={checkIntegrity:!0}){let n=API.pyodide_code.find_imports(e),o;try{o=n.toJs()}finally{n.destroy()}if(o.length===0)return[];let i=API._import_name_to_package_name,s=new Set;for(let l of o)i.has(l)&&s.add(i.get(l));return s.size?await te(Array.from(s),r):[]}static runPython(e,r={}){return r.globals||(r.globals=API.globals),API.pyodide_code.eval_code.callKwargs(e,r)}static async runPythonAsync(e,r={}){return r.globals||(r.globals=API.globals),await API.pyodide_code.eval_code_async.callKwargs(e,r)}static registerJsModule(e,r){API.pyodide_ffi.register_js_module(e,r)}static unregisterJsModule(e){API.pyodide_ffi.unregister_js_module(e)}static toPy(e,{depth:r,defaultConverter:n}={depth:-1}){switch(typeof e){case"string":case"number":case"boolean":case"bigint":case"undefined":return e}if(!e||API.isPyProxy(e))return e;let o=0,i=0;try{o=Module.js2python_convert(e,{depth:r,defaultConverter:n})}catch(s){throw s instanceof Module._PropagatePythonError&&_pythonexc2js(),s}try{if(_JsProxy_Check(o))return e;i=_python2js(o),i===null&&_pythonexc2js()}finally{_Py_DecRef(o)}return i}static pyimport(e){return API.pyodide_base.pyimport_impl(e)}static unpackArchive(e,r,n={}){if(!ArrayBuffer.isView(e)&&API.getTypeTag(e)!=="[object ArrayBuffer]")throw new TypeError("Expected argument 'buffer' to be an ArrayBuffer or an ArrayBuffer view");API.typedArrayAsUint8Array(e);let o=n.extractDir;API.package_loader.unpack_buffer.callKwargs({buffer:e,format:r,extract_dir:o,metadata:qt})}static async mountNativeFS(e,r){if(r.constructor.name!=="FileSystemDirectoryHandle")throw new TypeError("Expected argument 'fileSystemHandle' to be a FileSystemDirectoryHandle");return Mr(e),Module.FS.mount(Module.FS.filesystems.NATIVEFS_ASYNC,{fileSystemHandle:r},e),await kr(Module),{syncfs:a(async()=>await Er(Module),"syncfs")}}static mountNodeFS(e,r){if(!d.IN_NODE)throw new Error("mountNodeFS only works in Node");Mr(e);let n;try{n=Re.lstatSync(r)}catch{throw new Error(`hostPath '${r}' does not exist`)}if(!n.isDirectory())throw new Error(`hostPath '${r}' is not a directory`);Module.FS.mount(Module.FS.filesystems.NODEFS,{root:r},e)}static registerComlink(e){API._Comlink=e}static setInterruptBuffer(e){Module.HEAP8[Module._Py_EMSCRIPTEN_SIGNAL_HANDLING]=+!!e,Module.Py_EmscriptenSignalBuffer=e}static checkInterrupt(){if(_PyGILState_Check()){__PyErr_CheckSignals()&&_pythonexc2js();return}else{let e=Module.Py_EmscriptenSignalBuffer;if(e&&e[0]===2)throw new Module.FS.ErrnoError(27)}}static setDebug(e){let r=!!API.debug_ffi;return API.debug_ffi=e,r}static makeMemorySnapshot({serializer:e}={}){if(!API.config._makeSnapshot)throw new Error("Can only use pyodide.makeMemorySnapshot if the _makeSnapshot option is passed to loadPyodide");return API.makeSnapshot(e)}static get lockfile(){return API.lockfile}static get lockfileBaseUrl(){return API.config.packageCacheDir??API.config.packageBaseUrl}};function so(){let t=Object.getOwnPropertyDescriptors(It);delete t.prototype;let e=Object.create({},t);return API.public_api=e,e.FS=Module.FS,e.PATH=Module.PATH,e.ERRNO_CODES=Module.ERRNO_CODES,e._module=Module,e._api=API,e}a(so,"makePublicAPI");function lo(t,e){return new Proxy(t,{get(r,n){return n==="get"?o=>{let i=r.get(o);return i===void 0&&(i=e.get(o)),i}:n==="has"?o=>r.has(o)||e.has(o):Reflect.get(r,n)}})}a(lo,"wrapPythonGlobals");var Nr;API.bootstrapFinalizedPromise=new Promise(t=>Nr=t);API.finalizeBootstrap=function(t,e){t&&Sr();let[r,n]=API.rawRun("import _pyodide_core");r&&API.fatal_loading_error(`Failed to import _pyodide_core\n`,n),API.runPythonInternal_dict=API._pyodide._base.eval_code("{}"),API.importlib=API.runPythonInternal("import importlib; importlib");let o=API.importlib.import_module;API.sys=o("sys"),API.os=o("os");let i=API.runPythonInternal("import __main__; __main__.__dict__"),s=API.runPythonInternal("import builtins; builtins.__dict__");API.globals=lo(i,s);let l=API._pyodide._importhook,c=so();API.config._makeSnapshot&&(API.config.jsglobals=He(API.config.jsglobals));let u=API.config.jsglobals;return t?Ar(u,t,e):(l.register_js_finder(),l.register_js_module("js",u),l.register_js_module("pyodide_js",c),l.register_windows_finder()),API.pyodide_py=o("pyodide"),API.pyodide_code=o("pyodide.code"),API.pyodide_ffi=o("pyodide.ffi"),API.package_loader=o("pyodide._package_loader"),API.pyodide_base=o("_pyodide._base"),API.sitepackages=API.package_loader.SITE_PACKAGES.__str__(),API.dsodir=API.package_loader.DSO_DIR.__str__(),API.defaultLdLibraryPath=[API.dsodir,API.sitepackages],API.os.environ.__setitem__("LD_LIBRARY_PATH",API.defaultLdLibraryPath.join(":")),c.pyodide_py=API.pyodide_py,c.globals=API.globals,Nr(),c}})()}var StackSwitching=(()=>{var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var stack_switching_exports={};__export(stack_switching_exports,{StackState:()=>StackState,createPromising:()=>createPromising,jspiSupported:()=>jspiSupported,newJspiSupported:()=>newJspiSupported,oldJspiSupported:()=>oldJspiSupported,promisingApply:()=>promisingApply,promisingRunMain:()=>promisingRunMain,suspenderGlobal:()=>suspenderGlobal,validSuspender:()=>validSuspender});var suspenderGlobal={value:null};var validSuspender={value:false};var promisingApplyHandler;function promisingApply(...args){validSuspender.value=true;Module.stackStop=stackSave();return promisingApplyHandler(...args)}var promisingRunMainHandler;function promisingRunMain(...args){validSuspender.value=true;Module.stackStop=stackSave();return promisingRunMainHandler(...args)}function createPromising(wasm_func){if(Module.newJspiSupported){const promisingFunc=WebAssembly.promising(wasm_func);async function wrapper(...args){const orig=validSuspender.value;validSuspender.value=true;try{return await promisingFunc(null,...args)}finally{validSuspender.value=orig}}return wrapper}const{parameters}=wasmFunctionType(wasm_func);parameters.shift();return new WebAssembly.Function({parameters,results:["externref"]},wasm_func,{promising:"first"})}function initSuspenders(){promisingApplyHandler=createPromising(wasmExports._pyproxy_apply_promising);if(wasmExports.run_main_promising){promisingRunMainHandler=createPromising(wasmExports.run_main_promising)}}var stackStates=[];var StackState=class{constructor(){this.start=stackSave();this.stop=Module.stackStop;this._copy=new Uint8Array(0);if(this.start!==this.stop){stackStates.push(this)}}restore(){let total=0;while(stackStates.length>0&&stackStates[stackStates.length-1].stop>>0,this.start+sz2>>>0);const c=new Uint8Array(sz2);c.set(this._copy);c.set(new_segment,sz1);this._copy=c;return sz2}_save(){return this._save_up_to(this.stop)}};var canConstructWasm=true;try{new WebAssembly.Module(new Uint8Array([0,97,115,109,1,0,0,0]))}catch(e){canConstructWasm=false}var newJspiSupported=canConstructWasm&&"Suspending"in WebAssembly;var oldJspiSupported=canConstructWasm&&"Suspender"in WebAssembly;var jspiSupported=newJspiSupported||oldJspiSupported;Module.newJspiSupported=newJspiSupported;Module.oldJspiSupported=oldJspiSupported;Module.jspiSupported=jspiSupported;if(jspiSupported){Module.preRun.push(initSuspenders)}return __toCommonJS(stack_switching_exports)})();const{StackState,createPromising,jspiSupported,newJspiSupported,oldJspiSupported,promisingApply,promisingRunMain,suspenderGlobal,validSuspender}=StackSwitching;Object.assign(Module,StackSwitching);const API=Module.API;const Hiwire={};const Tests={};API.tests=Tests;API.version="0.29.3";API.abiVersion="2025_0";Module.hiwire=Hiwire;function getTypeTag(x){try{return Object.prototype.toString.call(x)}catch(e){return""}}API.getTypeTag=getTypeTag;function hasProperty(obj,prop){try{while(obj){if(Object.hasOwn(obj,prop)){return true}obj=Object.getPrototypeOf(obj)}}catch(e){}return false}function hasMethod(obj,prop){try{return typeof obj[prop]==="function"}catch(e){return false}}const pyproxyIsAlive=px=>!!Module.PyProxy_getAttrsQuiet(px).shared.ptr;API.pyproxyIsAlive=pyproxyIsAlive;const errNoRet=()=>{throw new Error("Assertion error: control reached end of function without return")};function isPromise(obj){try{return typeof obj?.then==="function"}catch(e){return false}}API.isPromise=isPromise;function bufferAsUint8Array(arg){if(ArrayBuffer.isView(arg)){return new Uint8Array(arg.buffer,arg.byteOffset,arg.byteLength)}else{return new Uint8Array(arg)}}API.typedArrayAsUint8Array=bufferAsUint8Array;Module.iterObject=function*(object){for(let k in object){if(Object.hasOwn(object,k)){yield k}}};function wasmFunctionType(wasm_func){if(!WebAssembly.Function){throw new Error("No type reflection")}if(WebAssembly.Function.type){return WebAssembly.Function.type(wasm_func)}return wasm_func.type()}pyodide_js_init();pyodide_js_init.sig="v";function set_suspender(suspender){suspenderGlobal.value=suspender}set_suspender.sig="ve";function get_suspender(){return suspenderGlobal.value}get_suspender.sig="e";function syncifyHandler(x,y){return Module.error}async function inner(x,y){try{return await(x??y)}catch(e){if(e&&e.pyodide_fatal_error){throw e}Module.syncify_error=e;return Module.error}}if(newJspiSupported){syncifyHandler=new WebAssembly.Suspending(inner)}else if(oldJspiSupported){syncifyHandler=new WebAssembly.Function({parameters:["externref","externref"],results:["externref"]},inner,{suspending:"first"})}syncifyHandler.sig="eee";function JsvPromise_Syncify_handleError(){if(!Module.syncify_error){return}Module.handle_js_error(Module.syncify_error);delete Module.syncify_error}JsvPromise_Syncify_handleError.sig="v";function saveState(){if(!validSuspender.value){return Module.error}const stackState=new StackState;const threadState=_captureThreadState();return{threadState,stackState,suspender:suspenderGlobal.value}}saveState.sig="e";function restoreState(state){state.stackState.restore();_restoreThreadState(state.threadState);suspenderGlobal.value=state.suspender;validSuspender.value=true}restoreState.sig="ve";function _Py_emscripten_runtime(){var info;if(typeof navigator=="object"){info=navigator.userAgent}else if(typeof process=="object"){info="Node.js ".concat(process.version)}else{info="UNKNOWN"}var len=lengthBytesUTF8(info)+1;var res=_malloc(len);if(res)stringToUTF8(info,res,len);return res}_Py_emscripten_runtime.sig="i";function _Py_CheckEmscriptenSignals_Helper(){if(!Module.Py_EmscriptenSignalBuffer){return 0}try{let result=Module.Py_EmscriptenSignalBuffer[0];Module.Py_EmscriptenSignalBuffer[0]=0;return result}catch(e){return 0}}_Py_CheckEmscriptenSignals_Helper.sig="i";function _PyEM_GetCountArgsPtr(){return Module._PyEM_CountArgsPtr}_PyEM_GetCountArgsPtr.sig="i";function _PyEM_InitTrampoline_js(){const ptr=getPyEMCountArgsPtr();Module._PyEM_CountArgsPtr=ptr;const offset=HEAP32[__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET/4>>>0];HEAP32[(__PyRuntime+offset)/4>>>0]=ptr}function getPyEMCountArgsPtr(){let isIOS=globalThis.navigator&&(/iPad|iPhone|iPod/.test(navigator.userAgent)||navigator.platform==="MacIntel"&&typeof navigator.maxTouchPoints!=="undefined"&&navigator.maxTouchPoints>1);if(isIOS){return 0}const code=new Uint8Array([0,97,115,109,1,0,0,0,1,27,5,96,0,1,127,96,1,127,1,127,96,2,127,127,1,127,96,3,127,127,127,1,127,96,1,127,0,2,9,1,1,101,1,116,1,112,0,0,3,2,1,1,7,5,1,1,102,0,0,10,68,1,66,1,1,112,32,0,37,0,34,1,251,20,3,2,4,69,13,0,65,3,15,11,32,1,251,20,2,2,4,69,13,0,65,2,15,11,32,1,251,20,1,2,4,69,13,0,65,1,15,11,32,1,251,20,0,2,4,69,13,0,65,0,15,11,65,127,11]);try{const mod=new WebAssembly.Module(code);const inst=new WebAssembly.Instance(mod,{e:{t:wasmTable}});return addFunction(inst.exports.f)}catch(e){return 0}}_PyEM_InitTrampoline_js.sig="v";function _PyEM_TrampolineCall_JS(func,arg1,arg2,arg3){return wasmTable.get(func)(arg1,arg2,arg3)}_PyEM_TrampolineCall_JS.sig="iiiii";function unbox_small_structs(type_ptr){var type_id=HEAPU16[(type_ptr+6>>1)+0>>>0];while(type_id===13){var elements=HEAPU32[(type_ptr+8>>2)+0>>>0];var first_element=HEAPU32[(elements>>2)+0>>>0];if(first_element===0){type_id=0;break}else if(HEAPU32[(elements>>2)+1>>>0]===0){type_ptr=first_element;type_id=HEAPU16[(first_element+6>>1)+0>>>0]}else{break}}return[type_ptr,type_id]}function ffi_call_js(cif,fn,rvalue,avalue){var abi=HEAPU32[(cif>>2)+0>>>0];var nargs=HEAPU32[(cif>>2)+1>>>0];var nfixedargs=HEAPU32[(cif>>2)+6>>>0];var arg_types_ptr=HEAPU32[(cif>>2)+2>>>0];var rtype_unboxed=unbox_small_structs(HEAPU32[(cif>>2)+3>>>0]);var rtype_ptr=rtype_unboxed[0];var rtype_id=rtype_unboxed[1];var orig_stack_ptr=stackSave();var cur_stack_ptr=orig_stack_ptr;var args=[];var ret_by_arg=!!0;if(rtype_id===15){throw new Error("complex ret marshalling nyi")}if(rtype_id<0||rtype_id>15){throw new Error("Unexpected rtype "+rtype_id)}if(rtype_id===4||rtype_id===13){args.push(rvalue);ret_by_arg=!!1}for(var i=0;i>2)+i>>>0];var arg_unboxed=unbox_small_structs(HEAPU32[(arg_types_ptr>>2)+i>>>0]);var arg_type_ptr=arg_unboxed[0];var arg_type_id=arg_unboxed[1];switch(arg_type_id){case 1:case 10:case 9:case 14:args.push(HEAPU32[(arg_ptr>>2)+0>>>0]);break;case 2:args.push(HEAPF32[(arg_ptr>>2)+0>>>0]);break;case 3:args.push(HEAPF64[(arg_ptr>>3)+0>>>0]);break;case 5:args.push(HEAPU8[arg_ptr+0>>>0]);break;case 6:args.push(HEAP8[arg_ptr+0>>>0]);break;case 7:args.push(HEAPU16[(arg_ptr>>1)+0>>>0]);break;case 8:args.push(HEAP16[(arg_ptr>>1)+0>>>0]);break;case 11:case 12:args.push(HEAPU64[(arg_ptr>>3)+0>>>0]);break;case 4:args.push(HEAPU64[(arg_ptr>>3)+0>>>0]);args.push(HEAPU64[(arg_ptr>>3)+1>>>0]);break;case 13:var size=HEAPU32[(arg_type_ptr>>2)+0>>>0];var align=HEAPU16[(arg_type_ptr+4>>1)+0>>>0];cur_stack_ptr-=size,cur_stack_ptr&=~(align-1);HEAP8.subarray(cur_stack_ptr>>>0,cur_stack_ptr+size>>>0).set(HEAP8.subarray(arg_ptr>>>0,arg_ptr+size>>>0));args.push(cur_stack_ptr);break;case 15:throw new Error("complex marshalling nyi");default:throw new Error("Unexpected type "+arg_type_id)}}if(nfixedargs!=nargs){var struct_arg_info=[];for(var i=nargs-1;i>=nfixedargs;i--){var arg_ptr=HEAPU32[(avalue>>2)+i>>>0];var arg_unboxed=unbox_small_structs(HEAPU32[(arg_types_ptr>>2)+i>>>0]);var arg_type_ptr=arg_unboxed[0];var arg_type_id=arg_unboxed[1];switch(arg_type_id){case 5:case 6:cur_stack_ptr-=1,cur_stack_ptr&=~(1-1);HEAPU8[cur_stack_ptr+0>>>0]=HEAPU8[arg_ptr+0>>>0];break;case 7:case 8:cur_stack_ptr-=2,cur_stack_ptr&=~(2-1);HEAPU16[(cur_stack_ptr>>1)+0>>>0]=HEAPU16[(arg_ptr>>1)+0>>>0];break;case 1:case 9:case 10:case 14:case 2:cur_stack_ptr-=4,cur_stack_ptr&=~(4-1);HEAPU32[(cur_stack_ptr>>2)+0>>>0]=HEAPU32[(arg_ptr>>2)+0>>>0];break;case 3:case 11:case 12:cur_stack_ptr-=8,cur_stack_ptr&=~(8-1);HEAPU32[(cur_stack_ptr>>2)+0>>>0]=HEAPU32[(arg_ptr>>2)+0>>>0];HEAPU32[(cur_stack_ptr>>2)+1>>>0]=HEAPU32[(arg_ptr>>2)+1>>>0];break;case 4:cur_stack_ptr-=16,cur_stack_ptr&=~(8-1);HEAPU32[(cur_stack_ptr>>2)+0>>>0]=HEAPU32[(arg_ptr>>2)+0>>>0];HEAPU32[(cur_stack_ptr>>2)+1>>>0]=HEAPU32[(arg_ptr>>2)+1>>>0];HEAPU32[(cur_stack_ptr>>2)+2>>>0]=HEAPU32[(arg_ptr>>2)+2>>>0];HEAPU32[(cur_stack_ptr>>2)+3>>>0]=HEAPU32[(arg_ptr>>2)+3>>>0];break;case 13:cur_stack_ptr-=4,cur_stack_ptr&=~(4-1);struct_arg_info.push([cur_stack_ptr,arg_ptr,HEAPU32[(arg_type_ptr>>2)+0>>>0],HEAPU16[(arg_type_ptr+4>>1)+0>>>0]]);break;case 15:throw new Error("complex arg marshalling nyi");default:throw new Error("Unexpected argtype "+arg_type_id)}}args.push(cur_stack_ptr);for(var i=0;i>>0,cur_stack_ptr+size>>>0).set(HEAP8.subarray(arg_ptr>>>0,arg_ptr+size>>>0));HEAPU32[(arg_target>>2)+0>>>0]=cur_stack_ptr}}stackRestore(cur_stack_ptr);stackAlloc(0);var result=(0,getWasmTableEntry(fn).apply(null,args));stackRestore(orig_stack_ptr);if(ret_by_arg){return}switch(rtype_id){case 0:break;case 1:case 9:case 10:case 14:HEAPU32[(rvalue>>2)+0>>>0]=result;break;case 2:HEAPF32[(rvalue>>2)+0>>>0]=result;break;case 3:HEAPF64[(rvalue>>3)+0>>>0]=result;break;case 5:case 6:HEAPU8[rvalue+0>>>0]=result;break;case 7:case 8:HEAPU16[(rvalue>>1)+0>>>0]=result;break;case 11:case 12:HEAPU64[(rvalue>>3)+0>>>0]=result;break;case 15:throw new Error("complex ret marshalling nyi");default:throw new Error("Unexpected rtype "+rtype_id)}}ffi_call_js.sig="viiii";function ffi_closure_alloc_js(size,code){var closure=_malloc(size);var index=getEmptyTableSlot();HEAPU32[(code>>2)+0>>>0]=index;HEAPU32[(closure>>2)+0>>>0]=index;return closure}ffi_closure_alloc_js.sig="iii";function ffi_closure_free_js(closure){var index=HEAPU32[(closure>>2)+0>>>0];freeTableIndexes.push(index);_free(closure)}ffi_closure_free_js.sig="vi";function ffi_prep_closure_loc_js(closure,cif,fun,user_data,codeloc){var abi=HEAPU32[(cif>>2)+0>>>0];var nargs=HEAPU32[(cif>>2)+1>>>0];var nfixedargs=HEAPU32[(cif>>2)+6>>>0];var arg_types_ptr=HEAPU32[(cif>>2)+2>>>0];var rtype_unboxed=unbox_small_structs(HEAPU32[(cif>>2)+3>>>0]);var rtype_ptr=rtype_unboxed[0];var rtype_id=rtype_unboxed[1];var sig;var ret_by_arg=!!0;switch(rtype_id){case 0:sig="v";break;case 13:case 4:sig="vi";ret_by_arg=!!1;break;case 1:case 5:case 6:case 7:case 8:case 9:case 10:case 14:sig="i";break;case 2:sig="f";break;case 3:sig="d";break;case 11:case 12:sig="j";break;case 15:throw new Error("complex ret marshalling nyi");default:throw new Error("Unexpected rtype "+rtype_id)}var unboxed_arg_type_id_list=[];var unboxed_arg_type_info_list=[];for(var i=0;i>2)+i>>>0]);var arg_type_ptr=arg_unboxed[0];var arg_type_id=arg_unboxed[1];unboxed_arg_type_id_list.push(arg_type_id);unboxed_arg_type_info_list.push([HEAPU32[(arg_type_ptr>>2)+0>>>0],HEAPU16[(arg_type_ptr+4>>1)+0>>>0]])}for(var i=0;i>2)+carg_idx>>>0]=cur_ptr;HEAPU8[cur_ptr+0>>>0]=cur_arg;break;case 7:case 8:cur_ptr-=2,cur_ptr&=~(4-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU16[(cur_ptr>>1)+0>>>0]=cur_arg;break;case 1:case 9:case 10:case 14:cur_ptr-=4,cur_ptr&=~(4-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU32[(cur_ptr>>2)+0>>>0]=cur_arg;break;case 13:cur_ptr-=arg_size,cur_ptr&=~(arg_align-1);HEAP8.subarray(cur_ptr>>>0,cur_ptr+arg_size>>>0).set(HEAP8.subarray(cur_arg>>>0,cur_arg+arg_size>>>0));HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;break;case 2:cur_ptr-=4,cur_ptr&=~(4-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPF32[(cur_ptr>>2)+0>>>0]=cur_arg;break;case 3:cur_ptr-=8,cur_ptr&=~(8-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPF64[(cur_ptr>>3)+0>>>0]=cur_arg;break;case 11:case 12:cur_ptr-=8,cur_ptr&=~(8-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU64[(cur_ptr>>3)+0>>>0]=cur_arg;break;case 4:cur_ptr-=16,cur_ptr&=~(8-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU64[(cur_ptr>>3)+0>>>0]=cur_arg;cur_arg=args[jsarg_idx++];HEAPU64[(cur_ptr>>3)+1>>>0]=cur_arg;break}}var varargs=args[args.length-1];for(;carg_idx>2)+0>>>0];cur_ptr-=arg_size,cur_ptr&=~(arg_align-1);HEAP8.subarray(cur_ptr>>>0,cur_ptr+arg_size>>>0).set(HEAP8.subarray(struct_ptr>>>0,struct_ptr+arg_size>>>0));HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr}else{HEAPU32[(args_ptr>>2)+carg_idx>>>0]=varargs}varargs+=4}stackRestore(cur_ptr);stackAlloc(0);0;getWasmTableEntry(HEAPU32[(closure>>2)+2>>>0])(HEAPU32[(closure>>2)+1>>>0],ret_ptr,args_ptr,HEAPU32[(closure>>2)+3>>>0]);stackRestore(orig_stack_ptr);if(!ret_by_arg){switch(sig[0]){case"i":return HEAPU32[(ret_ptr>>2)+0>>>0];case"j":return HEAPU64[(ret_ptr>>3)+0>>>0];case"d":return HEAPF64[(ret_ptr>>3)+0>>>0];case"f":return HEAPF32[(ret_ptr>>2)+0>>>0]}}}try{var wasm_trampoline=convertJsFunctionToWasm(trampoline,sig)}catch(e){return 1}setWasmTableEntry(codeloc,wasm_trampoline);HEAPU32[(closure>>2)+1>>>0]=cif;HEAPU32[(closure>>2)+2>>>0]=fun;HEAPU32[(closure>>2)+3>>>0]=user_data;return 0}ffi_prep_closure_loc_js.sig="iiiiii";function __hiwire_deduplicate_new(){return new Map}__hiwire_deduplicate_new.sig="e";function __hiwire_deduplicate_get(map,value){return map.get(value)}__hiwire_deduplicate_get.sig="iee";function __hiwire_deduplicate_set(map,value,ref){map.set(value,ref)}__hiwire_deduplicate_set.sig="veei";function __hiwire_deduplicate_delete(map,value){map.delete(value)}__hiwire_deduplicate_delete.sig="vee";var wasmImports={IMG_Init:_IMG_Init,IMG_Load:_IMG_Load,IMG_Load_RW:_IMG_Load_RW,IMG_Quit:_IMG_Quit,JsArray_count_js,JsArray_index_js,JsArray_inplace_repeat_js,JsArray_repeat_js,JsArray_reverse_js,JsArray_reversed_iterator,JsBuffer_DecodeString_js,JsBuffer_get_info,JsDoubleProxy_unwrap_js,JsException_new_helper,JsMap_GetIter_js,JsMap_clear_js,JsModule_GetAll_js,JsObjMap_GetIter_js,JsObjMap_ass_subscript_js,JsObjMap_contains_js,JsObjMap_length_js,JsObjMap_subscript_js,JsProxy_Bool_js,JsProxy_DelAttr_js,JsProxy_Dir_js,JsProxy_GetAsyncIter_js,JsProxy_GetAttr_js,JsProxy_GetIter_js,JsProxy_SetAttr_js,JsProxy_compute_typeflags,JsProxy_subscript_js,JsProxy_to_weakref_js,JsvArray_Check,JsvArray_Delete,JsvArray_Extend,JsvArray_Get,JsvArray_Insert,JsvArray_New,JsvArray_Push,JsvArray_Set,JsvArray_ShallowCopy,JsvArray_slice,JsvArray_slice_assign,JsvAsyncGenerator_Check,JsvBuffer_assignFromPtr,JsvBuffer_assignToPtr,JsvBuffer_intoFile,JsvBuffer_readFromFile,JsvBuffer_writeToFile,JsvError_Throw,JsvFunction_CallBound,JsvFunction_Call_OneArg,JsvFunction_Check,JsvFunction_Construct,JsvGenerator_Check,JsvLiteralMap_New,JsvMap_New,JsvMap_Set,JsvNoValue_Check,JsvNum_fromDigits,JsvNum_fromDouble,JsvNum_fromInt,JsvObject_CallMethod,JsvObject_CallMethod_NoArgs,JsvObject_CallMethod_OneArg,JsvObject_CallMethod_TwoArgs,JsvObject_Entries,JsvObject_Keys,JsvObject_New,JsvObject_SetAttr,JsvObject_Values,JsvObject_toString,JsvPromise_Check,JsvPromise_Resolve,JsvPromise_Syncify_handleError,JsvSet_Add,JsvSet_New,JsvUTF8ToString,Jsv_constructorName,Jsv_equal,Jsv_greater_than,Jsv_greater_than_equal,Jsv_less_than,Jsv_less_than_equal,Jsv_not_equal,Jsv_to_bool,Jsv_typeof,Mix_AllocateChannels:_Mix_AllocateChannels,Mix_ChannelFinished:_Mix_ChannelFinished,Mix_CloseAudio:_Mix_CloseAudio,Mix_FadeInChannelTimed:_Mix_FadeInChannelTimed,Mix_FadeInMusicPos:_Mix_FadeInMusicPos,Mix_FadeOutChannel:_Mix_FadeOutChannel,Mix_FadeOutMusic:_Mix_FadeOutMusic,Mix_FadingChannel:_Mix_FadingChannel,Mix_FreeChunk:_Mix_FreeChunk,Mix_FreeMusic:_Mix_FreeMusic,Mix_HaltChannel:_Mix_HaltChannel,Mix_HaltMusic:_Mix_HaltMusic,Mix_HookMusicFinished:_Mix_HookMusicFinished,Mix_Init:_Mix_Init,Mix_Linked_Version:_Mix_Linked_Version,Mix_LoadMUS:_Mix_LoadMUS,Mix_LoadMUS_RW:_Mix_LoadMUS_RW,Mix_LoadWAV:_Mix_LoadWAV,Mix_LoadWAV_RW:_Mix_LoadWAV_RW,Mix_OpenAudio:_Mix_OpenAudio,Mix_Pause:_Mix_Pause,Mix_PauseMusic:_Mix_PauseMusic,Mix_Paused:_Mix_Paused,Mix_PausedMusic:_Mix_PausedMusic,Mix_PlayChannelTimed:_Mix_PlayChannelTimed,Mix_PlayMusic:_Mix_PlayMusic,Mix_Playing:_Mix_Playing,Mix_PlayingMusic:_Mix_PlayingMusic,Mix_QuerySpec:_Mix_QuerySpec,Mix_QuickLoad_RAW:_Mix_QuickLoad_RAW,Mix_Quit:_Mix_Quit,Mix_ReserveChannels:_Mix_ReserveChannels,Mix_Resume:_Mix_Resume,Mix_ResumeMusic:_Mix_ResumeMusic,Mix_SetPanning:_Mix_SetPanning,Mix_SetPosition:_Mix_SetPosition,Mix_SetPostMix:_Mix_SetPostMix,Mix_Volume:_Mix_Volume,Mix_VolumeChunk:_Mix_VolumeChunk,Mix_VolumeMusic:_Mix_VolumeMusic,SDL_AddTimer:_SDL_AddTimer,SDL_AllocRW:_SDL_AllocRW,SDL_AudioDriverName:_SDL_AudioDriverName,SDL_AudioQuit:_SDL_AudioQuit,SDL_ClearError:_SDL_ClearError,SDL_CloseAudio:_SDL_CloseAudio,SDL_CondBroadcast:_SDL_CondBroadcast,SDL_CondSignal:_SDL_CondSignal,SDL_CondWait:_SDL_CondWait,SDL_CondWaitTimeout:_SDL_CondWaitTimeout,SDL_ConvertSurface:_SDL_ConvertSurface,SDL_CreateCond:_SDL_CreateCond,SDL_CreateMutex:_SDL_CreateMutex,SDL_CreateRGBSurface:_SDL_CreateRGBSurface,SDL_CreateRGBSurfaceFrom:_SDL_CreateRGBSurfaceFrom,SDL_CreateThread:_SDL_CreateThread,SDL_Delay:_SDL_Delay,SDL_DestroyCond:_SDL_DestroyCond,SDL_DestroyMutex:_SDL_DestroyMutex,SDL_DestroyRenderer:_SDL_DestroyRenderer,SDL_DestroyWindow:_SDL_DestroyWindow,SDL_DisplayFormat:_SDL_DisplayFormat,SDL_DisplayFormatAlpha:_SDL_DisplayFormatAlpha,SDL_EnableKeyRepeat:_SDL_EnableKeyRepeat,SDL_EnableUNICODE:_SDL_EnableUNICODE,SDL_FillRect:_SDL_FillRect,SDL_Flip:_SDL_Flip,SDL_FreeRW:_SDL_FreeRW,SDL_FreeSurface:_SDL_FreeSurface,SDL_GL_DeleteContext:_SDL_GL_DeleteContext,SDL_GL_ExtensionSupported:_SDL_GL_ExtensionSupported,SDL_GL_GetAttribute:_SDL_GL_GetAttribute,SDL_GL_GetSwapInterval:_SDL_GL_GetSwapInterval,SDL_GL_MakeCurrent:_SDL_GL_MakeCurrent,SDL_GL_SetAttribute:_SDL_GL_SetAttribute,SDL_GL_SetSwapInterval:_SDL_GL_SetSwapInterval,SDL_GL_SwapBuffers:_SDL_GL_SwapBuffers,SDL_GL_SwapWindow:_SDL_GL_SwapWindow,SDL_GetAppState:_SDL_GetAppState,SDL_GetAudioDriver:_SDL_GetAudioDriver,SDL_GetClipRect:_SDL_GetClipRect,SDL_GetCurrentAudioDriver:_SDL_GetCurrentAudioDriver,SDL_GetError:_SDL_GetError,SDL_GetKeyName:_SDL_GetKeyName,SDL_GetKeyState:_SDL_GetKeyState,SDL_GetKeyboardState:_SDL_GetKeyboardState,SDL_GetModState:_SDL_GetModState,SDL_GetMouseState:_SDL_GetMouseState,SDL_GetNumAudioDrivers:_SDL_GetNumAudioDrivers,SDL_GetRGB:_SDL_GetRGB,SDL_GetRGBA:_SDL_GetRGBA,SDL_GetScancodeFromKey:_SDL_GetScancodeFromKey,SDL_GetThreadID:_SDL_GetThreadID,SDL_GetTicks:_SDL_GetTicks,SDL_GetVideoInfo:_SDL_GetVideoInfo,SDL_GetVideoSurface:_SDL_GetVideoSurface,SDL_GetWindowFlags:_SDL_GetWindowFlags,SDL_GetWindowSize:_SDL_GetWindowSize,SDL_Has3DNow:_SDL_Has3DNow,SDL_Has3DNowExt:_SDL_Has3DNowExt,SDL_HasAltiVec:_SDL_HasAltiVec,SDL_HasMMX:_SDL_HasMMX,SDL_HasMMXExt:_SDL_HasMMXExt,SDL_HasRDTSC:_SDL_HasRDTSC,SDL_HasSSE:_SDL_HasSSE,SDL_HasSSE2:_SDL_HasSSE2,SDL_Init:_SDL_Init,SDL_InitSubSystem:_SDL_InitSubSystem,SDL_JoystickClose:_SDL_JoystickClose,SDL_JoystickEventState:_SDL_JoystickEventState,SDL_JoystickGetAxis:_SDL_JoystickGetAxis,SDL_JoystickGetBall:_SDL_JoystickGetBall,SDL_JoystickGetButton:_SDL_JoystickGetButton,SDL_JoystickGetHat:_SDL_JoystickGetHat,SDL_JoystickIndex:_SDL_JoystickIndex,SDL_JoystickName:_SDL_JoystickName,SDL_JoystickNumAxes:_SDL_JoystickNumAxes,SDL_JoystickNumBalls:_SDL_JoystickNumBalls,SDL_JoystickNumButtons:_SDL_JoystickNumButtons,SDL_JoystickNumHats:_SDL_JoystickNumHats,SDL_JoystickOpen:_SDL_JoystickOpen,SDL_JoystickOpened:_SDL_JoystickOpened,SDL_JoystickUpdate:_SDL_JoystickUpdate,SDL_Linked_Version:_SDL_Linked_Version,SDL_ListModes:_SDL_ListModes,SDL_LoadBMP_RW:_SDL_LoadBMP_RW,SDL_LockAudio:_SDL_LockAudio,SDL_LockSurface:_SDL_LockSurface,SDL_LogSetOutputFunction:_SDL_LogSetOutputFunction,SDL_LowerBlit:_SDL_LowerBlit,SDL_LowerBlitScaled:_SDL_LowerBlitScaled,SDL_MapRGB:_SDL_MapRGB,SDL_MapRGBA:_SDL_MapRGBA,SDL_NumJoysticks:_SDL_NumJoysticks,SDL_OpenAudio:_SDL_OpenAudio,SDL_PauseAudio:_SDL_PauseAudio,SDL_PeepEvents:_SDL_PeepEvents,SDL_PollEvent:_SDL_PollEvent,SDL_PumpEvents:_SDL_PumpEvents,SDL_PushEvent:_SDL_PushEvent,SDL_Quit:_SDL_Quit,SDL_QuitSubSystem:_SDL_QuitSubSystem,SDL_RWFromConstMem:_SDL_RWFromConstMem,SDL_RWFromFile:_SDL_RWFromFile,SDL_RWFromMem:_SDL_RWFromMem,SDL_RemoveTimer:_SDL_RemoveTimer,SDL_SaveBMP_RW:_SDL_SaveBMP_RW,SDL_SetAlpha:_SDL_SetAlpha,SDL_SetClipRect:_SDL_SetClipRect,SDL_SetColorKey:_SDL_SetColorKey,SDL_SetColors:_SDL_SetColors,SDL_SetError:_SDL_SetError,SDL_SetGamma:_SDL_SetGamma,SDL_SetGammaRamp:_SDL_SetGammaRamp,SDL_SetPalette:_SDL_SetPalette,SDL_SetVideoMode:_SDL_SetVideoMode,SDL_SetWindowFullscreen:_SDL_SetWindowFullscreen,SDL_SetWindowTitle:_SDL_SetWindowTitle,SDL_ShowCursor:_SDL_ShowCursor,SDL_StartTextInput:_SDL_StartTextInput,SDL_StopTextInput:_SDL_StopTextInput,SDL_ThreadID:_SDL_ThreadID,SDL_UnlockAudio:_SDL_UnlockAudio,SDL_UnlockSurface:_SDL_UnlockSurface,SDL_UpdateRect:_SDL_UpdateRect,SDL_UpdateRects:_SDL_UpdateRects,SDL_UpperBlit:_SDL_UpperBlit,SDL_UpperBlitScaled:_SDL_UpperBlitScaled,SDL_VideoDriverName:_SDL_VideoDriverName,SDL_VideoModeOK:_SDL_VideoModeOK,SDL_VideoQuit:_SDL_VideoQuit,SDL_WM_GrabInput:_SDL_WM_GrabInput,SDL_WM_IconifyWindow:_SDL_WM_IconifyWindow,SDL_WM_SetCaption:_SDL_WM_SetCaption,SDL_WM_SetIcon:_SDL_WM_SetIcon,SDL_WM_ToggleFullScreen:_SDL_WM_ToggleFullScreen,SDL_WaitThread:_SDL_WaitThread,SDL_WarpMouse:_SDL_WarpMouse,SDL_WasInit:_SDL_WasInit,SDL_mutexP:_SDL_mutexP,SDL_mutexV:_SDL_mutexV,TTF_CloseFont:_TTF_CloseFont,TTF_FontAscent:_TTF_FontAscent,TTF_FontDescent:_TTF_FontDescent,TTF_FontHeight:_TTF_FontHeight,TTF_FontLineSkip:_TTF_FontLineSkip,TTF_GlyphMetrics:_TTF_GlyphMetrics,TTF_Init:_TTF_Init,TTF_OpenFont:_TTF_OpenFont,TTF_Quit:_TTF_Quit,TTF_RenderText_Blended:_TTF_RenderText_Blended,TTF_RenderText_Shaded:_TTF_RenderText_Shaded,TTF_RenderText_Solid:_TTF_RenderText_Solid,TTF_RenderUTF8_Solid:_TTF_RenderUTF8_Solid,TTF_SizeText:_TTF_SizeText,TTF_SizeUTF8:_TTF_SizeUTF8,_JsArray_PostProcess_helper,_JsArray_PushEntry_helper,_JsObject_Set_js,_PyEM_GetCountArgsPtr,_PyEM_InitTrampoline_js,_PyEM_TrampolineCall_JS,_Py_CheckEmscriptenSignals_Helper,_Py_emscripten_runtime,_Unwind_Backtrace:__Unwind_Backtrace,_Unwind_FindEnclosingFunction:__Unwind_FindEnclosingFunction,_Unwind_GetIPInfo:__Unwind_GetIPInfo,__asctime_r:___asctime_r,__assert_fail:___assert_fail,__c_longjmp:___c_longjmp,__call_sighandler:___call_sighandler,__cpp_exception:___cpp_exception,__global_base:___global_base,__heap_base:___heap_base,__hiwire_deduplicate_delete,__hiwire_deduplicate_get,__hiwire_deduplicate_new,__hiwire_deduplicate_set,__indirect_function_table:wasmTable,__memory_base:___memory_base,__stack_high:___stack_high,__stack_low:___stack_low,__stack_pointer:___stack_pointer,__syscall__newselect:___syscall__newselect,__syscall_accept4:___syscall_accept4,__syscall_bind:___syscall_bind,__syscall_chdir:___syscall_chdir,__syscall_chmod:___syscall_chmod,__syscall_connect:___syscall_connect,__syscall_dup:___syscall_dup,__syscall_dup3:___syscall_dup3,__syscall_faccessat:___syscall_faccessat,__syscall_fadvise64:___syscall_fadvise64,__syscall_fallocate:___syscall_fallocate,__syscall_fchdir:___syscall_fchdir,__syscall_fchmod:___syscall_fchmod,__syscall_fchmodat2:___syscall_fchmodat2,__syscall_fchown32:___syscall_fchown32,__syscall_fchownat:___syscall_fchownat,__syscall_fcntl64:___syscall_fcntl64,__syscall_fdatasync:___syscall_fdatasync,__syscall_fstat64:___syscall_fstat64,__syscall_fstatfs64:___syscall_fstatfs64,__syscall_ftruncate64:___syscall_ftruncate64,__syscall_getcwd:___syscall_getcwd,__syscall_getdents64:___syscall_getdents64,__syscall_getpeername:___syscall_getpeername,__syscall_getsockname:___syscall_getsockname,__syscall_getsockopt:___syscall_getsockopt,__syscall_ioctl:___syscall_ioctl,__syscall_listen:___syscall_listen,__syscall_lstat64:___syscall_lstat64,__syscall_mkdirat:___syscall_mkdirat,__syscall_mknodat:___syscall_mknodat,__syscall_newfstatat:___syscall_newfstatat,__syscall_openat:___syscall_openat,__syscall_pipe:___syscall_pipe,__syscall_poll:___syscall_poll,__syscall_readlinkat:___syscall_readlinkat,__syscall_recvfrom:___syscall_recvfrom,__syscall_recvmsg:___syscall_recvmsg,__syscall_renameat:___syscall_renameat,__syscall_rmdir:___syscall_rmdir,__syscall_sendmsg:___syscall_sendmsg,__syscall_sendto:___syscall_sendto,__syscall_socket:___syscall_socket,__syscall_stat64:___syscall_stat64,__syscall_statfs64:___syscall_statfs64,__syscall_symlinkat:___syscall_symlinkat,__syscall_truncate64:___syscall_truncate64,__syscall_unlinkat:___syscall_unlinkat,__syscall_utimensat:___syscall_utimensat,__table_base:___table_base,_abort_js:__abort_js,_agen_handle_result_js,_dlopen_js:__dlopen_js,_dlsym_catchup_js:__dlsym_catchup_js,_dlsym_js:__dlsym_js,_emscripten_dlopen_js:__emscripten_dlopen_js,_emscripten_fs_load_embedded_files:__emscripten_fs_load_embedded_files,_emscripten_get_now_is_monotonic:__emscripten_get_now_is_monotonic,_emscripten_get_progname:__emscripten_get_progname,_emscripten_lookup_name:__emscripten_lookup_name,_emscripten_push_main_loop_blocker:__emscripten_push_main_loop_blocker,_emscripten_push_uncounted_main_loop_blocker:__emscripten_push_uncounted_main_loop_blocker,_emscripten_runtime_keepalive_clear:__emscripten_runtime_keepalive_clear,_emscripten_system:__emscripten_system,_glGetActiveAttribOrUniform:__glGetActiveAttribOrUniform,_gmtime_js:__gmtime_js,_localtime_js:__localtime_js,_mktime_js:__mktime_js,_mmap_js:__mmap_js,_msync_js:__msync_js,_munmap_js:__munmap_js,_pyproxyGen_make_result,_pyproxy_get_buffer_result,_python2js_add_to_cache,_python2js_addto_postprocess_list,_python2js_buffer_inner,_python2js_cache_lookup,_python2js_handle_postprocess_list,_python2js_ucs1,_python2js_ucs2,_python2js_ucs4,_setitimer_js:__setitimer_js,_timegm_js:__timegm_js,_tzset_js:__tzset_js,array_to_js,boxColor:_boxColor,boxRGBA:_boxRGBA,can_run_sync_js,capture_stderr,clock_res_get:_clock_res_get,clock_time_get:_clock_time_get,create_once_callable,create_promise_handles,create_sentinel:_create_sentinel,destroy_jsarray_entries,destroy_proxies,destroy_proxies_js,destroy_proxy,eglBindAPI:_eglBindAPI,eglChooseConfig:_eglChooseConfig,eglCreateContext:_eglCreateContext,eglCreateWindowSurface:_eglCreateWindowSurface,eglDestroyContext:_eglDestroyContext,eglDestroySurface:_eglDestroySurface,eglGetConfigAttrib:_eglGetConfigAttrib,eglGetConfigs:_eglGetConfigs,eglGetCurrentContext:_eglGetCurrentContext,eglGetCurrentDisplay:_eglGetCurrentDisplay,eglGetCurrentSurface:_eglGetCurrentSurface,eglGetDisplay:_eglGetDisplay,eglGetError:_eglGetError,eglInitialize:_eglInitialize,eglMakeCurrent:_eglMakeCurrent,eglQueryAPI:_eglQueryAPI,eglQueryContext:_eglQueryContext,eglQueryString:_eglQueryString,eglQuerySurface:_eglQuerySurface,eglReleaseThread:_eglReleaseThread,eglSwapBuffers:_eglSwapBuffers,eglSwapInterval:_eglSwapInterval,eglTerminate:_eglTerminate,eglWaitClient:_eglWaitClient,eglWaitGL:_eglWaitGL,eglWaitNative:_eglWaitNative,ellipseColor:_ellipseColor,ellipseRGBA:_ellipseRGBA,emscripten_SDL_SetEventHandler:_emscripten_SDL_SetEventHandler,emscripten_asm_const_async_on_main_thread:_emscripten_asm_const_async_on_main_thread,emscripten_asm_const_double:_emscripten_asm_const_double,emscripten_asm_const_double_sync_on_main_thread:_emscripten_asm_const_double_sync_on_main_thread,emscripten_asm_const_int:_emscripten_asm_const_int,emscripten_asm_const_int_sync_on_main_thread:_emscripten_asm_const_int_sync_on_main_thread,emscripten_asm_const_ptr:_emscripten_asm_const_ptr,emscripten_asm_const_ptr_sync_on_main_thread:_emscripten_asm_const_ptr_sync_on_main_thread,emscripten_async_call:_emscripten_async_call,emscripten_async_load_script:_emscripten_async_load_script,emscripten_async_run_script:_emscripten_async_run_script,emscripten_async_wget:_emscripten_async_wget,emscripten_async_wget2:_emscripten_async_wget2,emscripten_async_wget2_abort:_emscripten_async_wget2_abort,emscripten_async_wget2_data:_emscripten_async_wget2_data,emscripten_async_wget_data:_emscripten_async_wget_data,emscripten_call_worker:_emscripten_call_worker,emscripten_cancel_animation_frame:_emscripten_cancel_animation_frame,emscripten_cancel_main_loop:_emscripten_cancel_main_loop,emscripten_clear_immediate:_emscripten_clear_immediate,emscripten_clear_interval:_emscripten_clear_interval,emscripten_clear_timeout:_emscripten_clear_timeout,emscripten_console_error:_emscripten_console_error,emscripten_console_log:_emscripten_console_log,emscripten_console_trace:_emscripten_console_trace,emscripten_console_warn:_emscripten_console_warn,emscripten_create_worker:_emscripten_create_worker,emscripten_date_now:_emscripten_date_now,emscripten_debugger:_emscripten_debugger,emscripten_destroy_worker:_emscripten_destroy_worker,emscripten_enter_soft_fullscreen:_emscripten_enter_soft_fullscreen,emscripten_err:_emscripten_err,emscripten_errn:_emscripten_errn,emscripten_exit_fullscreen:_emscripten_exit_fullscreen,emscripten_exit_pointerlock:_emscripten_exit_pointerlock,emscripten_exit_soft_fullscreen:_emscripten_exit_soft_fullscreen,emscripten_exit_with_live_runtime:_emscripten_exit_with_live_runtime,emscripten_force_exit:_emscripten_force_exit,emscripten_get_battery_status:_emscripten_get_battery_status,emscripten_get_callstack:_emscripten_get_callstack,emscripten_get_canvas_element_size:_emscripten_get_canvas_element_size,emscripten_get_canvas_size:_emscripten_get_canvas_size,emscripten_get_compiler_setting:_emscripten_get_compiler_setting,emscripten_get_device_pixel_ratio:_emscripten_get_device_pixel_ratio,emscripten_get_devicemotion_status:_emscripten_get_devicemotion_status,emscripten_get_deviceorientation_status:_emscripten_get_deviceorientation_status,emscripten_get_element_css_size:_emscripten_get_element_css_size,emscripten_get_fullscreen_status:_emscripten_get_fullscreen_status,emscripten_get_gamepad_status:_emscripten_get_gamepad_status,emscripten_get_heap_max:_emscripten_get_heap_max,emscripten_get_main_loop_timing:_emscripten_get_main_loop_timing,emscripten_get_mouse_status:_emscripten_get_mouse_status,emscripten_get_now:_emscripten_get_now,emscripten_get_now_res:_emscripten_get_now_res,emscripten_get_num_gamepads:_emscripten_get_num_gamepads,emscripten_get_orientation_status:_emscripten_get_orientation_status,emscripten_get_pointerlock_status:_emscripten_get_pointerlock_status,emscripten_get_preloaded_image_data:_emscripten_get_preloaded_image_data,emscripten_get_preloaded_image_data_from_FILE:_emscripten_get_preloaded_image_data_from_FILE,emscripten_get_screen_size:_emscripten_get_screen_size,emscripten_get_visibility_status:_emscripten_get_visibility_status,emscripten_get_window_title:_emscripten_get_window_title,emscripten_get_worker_queue_size:_emscripten_get_worker_queue_size,emscripten_glActiveTexture:_emscripten_glActiveTexture,emscripten_glAttachShader:_emscripten_glAttachShader,emscripten_glBegin:_emscripten_glBegin,emscripten_glBeginQuery:_emscripten_glBeginQuery,emscripten_glBeginQueryEXT:_emscripten_glBeginQueryEXT,emscripten_glBeginTransformFeedback:_emscripten_glBeginTransformFeedback,emscripten_glBindAttribLocation:_emscripten_glBindAttribLocation,emscripten_glBindBuffer:_emscripten_glBindBuffer,emscripten_glBindBufferBase:_emscripten_glBindBufferBase,emscripten_glBindBufferRange:_emscripten_glBindBufferRange,emscripten_glBindFramebuffer:_emscripten_glBindFramebuffer,emscripten_glBindRenderbuffer:_emscripten_glBindRenderbuffer,emscripten_glBindSampler:_emscripten_glBindSampler,emscripten_glBindTexture:_emscripten_glBindTexture,emscripten_glBindTransformFeedback:_emscripten_glBindTransformFeedback,emscripten_glBindVertexArray:_emscripten_glBindVertexArray,emscripten_glBindVertexArrayOES:_emscripten_glBindVertexArrayOES,emscripten_glBlendColor:_emscripten_glBlendColor,emscripten_glBlendEquation:_emscripten_glBlendEquation,emscripten_glBlendEquationSeparate:_emscripten_glBlendEquationSeparate,emscripten_glBlendFunc:_emscripten_glBlendFunc,emscripten_glBlendFuncSeparate:_emscripten_glBlendFuncSeparate,emscripten_glBlitFramebuffer:_emscripten_glBlitFramebuffer,emscripten_glBufferData:_emscripten_glBufferData,emscripten_glBufferSubData:_emscripten_glBufferSubData,emscripten_glCheckFramebufferStatus:_emscripten_glCheckFramebufferStatus,emscripten_glClear:_emscripten_glClear,emscripten_glClearBufferfi:_emscripten_glClearBufferfi,emscripten_glClearBufferfv:_emscripten_glClearBufferfv,emscripten_glClearBufferiv:_emscripten_glClearBufferiv,emscripten_glClearBufferuiv:_emscripten_glClearBufferuiv,emscripten_glClearColor:_emscripten_glClearColor,emscripten_glClearDepth:_emscripten_glClearDepth,emscripten_glClearDepthf:_emscripten_glClearDepthf,emscripten_glClearStencil:_emscripten_glClearStencil,emscripten_glClientWaitSync:_emscripten_glClientWaitSync,emscripten_glClipControlEXT:_emscripten_glClipControlEXT,emscripten_glColorMask:_emscripten_glColorMask,emscripten_glCompileShader:_emscripten_glCompileShader,emscripten_glCompressedTexImage2D:_emscripten_glCompressedTexImage2D,emscripten_glCompressedTexImage3D:_emscripten_glCompressedTexImage3D,emscripten_glCompressedTexSubImage2D:_emscripten_glCompressedTexSubImage2D,emscripten_glCompressedTexSubImage3D:_emscripten_glCompressedTexSubImage3D,emscripten_glCopyBufferSubData:_emscripten_glCopyBufferSubData,emscripten_glCopyTexImage2D:_emscripten_glCopyTexImage2D,emscripten_glCopyTexSubImage2D:_emscripten_glCopyTexSubImage2D,emscripten_glCopyTexSubImage3D:_emscripten_glCopyTexSubImage3D,emscripten_glCreateProgram:_emscripten_glCreateProgram,emscripten_glCreateShader:_emscripten_glCreateShader,emscripten_glCullFace:_emscripten_glCullFace,emscripten_glDeleteBuffers:_emscripten_glDeleteBuffers,emscripten_glDeleteFramebuffers:_emscripten_glDeleteFramebuffers,emscripten_glDeleteProgram:_emscripten_glDeleteProgram,emscripten_glDeleteQueries:_emscripten_glDeleteQueries,emscripten_glDeleteQueriesEXT:_emscripten_glDeleteQueriesEXT,emscripten_glDeleteRenderbuffers:_emscripten_glDeleteRenderbuffers,emscripten_glDeleteSamplers:_emscripten_glDeleteSamplers,emscripten_glDeleteShader:_emscripten_glDeleteShader,emscripten_glDeleteSync:_emscripten_glDeleteSync,emscripten_glDeleteTextures:_emscripten_glDeleteTextures,emscripten_glDeleteTransformFeedbacks:_emscripten_glDeleteTransformFeedbacks,emscripten_glDeleteVertexArrays:_emscripten_glDeleteVertexArrays,emscripten_glDeleteVertexArraysOES:_emscripten_glDeleteVertexArraysOES,emscripten_glDepthFunc:_emscripten_glDepthFunc,emscripten_glDepthMask:_emscripten_glDepthMask,emscripten_glDepthRange:_emscripten_glDepthRange,emscripten_glDepthRangef:_emscripten_glDepthRangef,emscripten_glDetachShader:_emscripten_glDetachShader,emscripten_glDisable:_emscripten_glDisable,emscripten_glDisableVertexAttribArray:_emscripten_glDisableVertexAttribArray,emscripten_glDrawArrays:_emscripten_glDrawArrays,emscripten_glDrawArraysInstanced:_emscripten_glDrawArraysInstanced,emscripten_glDrawArraysInstancedANGLE:_emscripten_glDrawArraysInstancedANGLE,emscripten_glDrawArraysInstancedARB:_emscripten_glDrawArraysInstancedARB,emscripten_glDrawArraysInstancedBaseInstance:_emscripten_glDrawArraysInstancedBaseInstance,emscripten_glDrawArraysInstancedBaseInstanceANGLE:_emscripten_glDrawArraysInstancedBaseInstanceANGLE,emscripten_glDrawArraysInstancedBaseInstanceWEBGL:_emscripten_glDrawArraysInstancedBaseInstanceWEBGL,emscripten_glDrawArraysInstancedEXT:_emscripten_glDrawArraysInstancedEXT,emscripten_glDrawArraysInstancedNV:_emscripten_glDrawArraysInstancedNV,emscripten_glDrawBuffers:_emscripten_glDrawBuffers,emscripten_glDrawBuffersEXT:_emscripten_glDrawBuffersEXT,emscripten_glDrawBuffersWEBGL:_emscripten_glDrawBuffersWEBGL,emscripten_glDrawElements:_emscripten_glDrawElements,emscripten_glDrawElementsInstanced:_emscripten_glDrawElementsInstanced,emscripten_glDrawElementsInstancedANGLE:_emscripten_glDrawElementsInstancedANGLE,emscripten_glDrawElementsInstancedARB:_emscripten_glDrawElementsInstancedARB,emscripten_glDrawElementsInstancedBaseVertexBaseInstanceANGLE:_emscripten_glDrawElementsInstancedBaseVertexBaseInstanceANGLE,emscripten_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL:_emscripten_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL,emscripten_glDrawElementsInstancedEXT:_emscripten_glDrawElementsInstancedEXT,emscripten_glDrawElementsInstancedNV:_emscripten_glDrawElementsInstancedNV,emscripten_glDrawRangeElements:_emscripten_glDrawRangeElements,emscripten_glEnable:_emscripten_glEnable,emscripten_glEnableVertexAttribArray:_emscripten_glEnableVertexAttribArray,emscripten_glEndQuery:_emscripten_glEndQuery,emscripten_glEndQueryEXT:_emscripten_glEndQueryEXT,emscripten_glEndTransformFeedback:_emscripten_glEndTransformFeedback,emscripten_glFenceSync:_emscripten_glFenceSync,emscripten_glFinish:_emscripten_glFinish,emscripten_glFlush:_emscripten_glFlush,emscripten_glFramebufferRenderbuffer:_emscripten_glFramebufferRenderbuffer,emscripten_glFramebufferTexture2D:_emscripten_glFramebufferTexture2D,emscripten_glFramebufferTextureLayer:_emscripten_glFramebufferTextureLayer,emscripten_glFrontFace:_emscripten_glFrontFace,emscripten_glGenBuffers:_emscripten_glGenBuffers,emscripten_glGenFramebuffers:_emscripten_glGenFramebuffers,emscripten_glGenQueries:_emscripten_glGenQueries,emscripten_glGenQueriesEXT:_emscripten_glGenQueriesEXT,emscripten_glGenRenderbuffers:_emscripten_glGenRenderbuffers,emscripten_glGenSamplers:_emscripten_glGenSamplers,emscripten_glGenTextures:_emscripten_glGenTextures,emscripten_glGenTransformFeedbacks:_emscripten_glGenTransformFeedbacks,emscripten_glGenVertexArrays:_emscripten_glGenVertexArrays,emscripten_glGenVertexArraysOES:_emscripten_glGenVertexArraysOES,emscripten_glGenerateMipmap:_emscripten_glGenerateMipmap,emscripten_glGetActiveAttrib:_emscripten_glGetActiveAttrib,emscripten_glGetActiveUniform:_emscripten_glGetActiveUniform,emscripten_glGetActiveUniformBlockName:_emscripten_glGetActiveUniformBlockName,emscripten_glGetActiveUniformBlockiv:_emscripten_glGetActiveUniformBlockiv,emscripten_glGetActiveUniformsiv:_emscripten_glGetActiveUniformsiv,emscripten_glGetAttachedShaders:_emscripten_glGetAttachedShaders,emscripten_glGetAttribLocation:_emscripten_glGetAttribLocation,emscripten_glGetBooleanv:_emscripten_glGetBooleanv,emscripten_glGetBufferParameteri64v:_emscripten_glGetBufferParameteri64v,emscripten_glGetBufferParameteriv:_emscripten_glGetBufferParameteriv,emscripten_glGetBufferSubData:_emscripten_glGetBufferSubData,emscripten_glGetError:_emscripten_glGetError,emscripten_glGetFloatv:_emscripten_glGetFloatv,emscripten_glGetFragDataLocation:_emscripten_glGetFragDataLocation,emscripten_glGetFramebufferAttachmentParameteriv:_emscripten_glGetFramebufferAttachmentParameteriv,emscripten_glGetInteger64i_v:_emscripten_glGetInteger64i_v,emscripten_glGetInteger64v:_emscripten_glGetInteger64v,emscripten_glGetIntegeri_v:_emscripten_glGetIntegeri_v,emscripten_glGetIntegerv:_emscripten_glGetIntegerv,emscripten_glGetInternalformativ:_emscripten_glGetInternalformativ,emscripten_glGetProgramBinary:_emscripten_glGetProgramBinary,emscripten_glGetProgramInfoLog:_emscripten_glGetProgramInfoLog,emscripten_glGetProgramiv:_emscripten_glGetProgramiv,emscripten_glGetQueryObjecti64vEXT:_emscripten_glGetQueryObjecti64vEXT,emscripten_glGetQueryObjectivEXT:_emscripten_glGetQueryObjectivEXT,emscripten_glGetQueryObjectui64vEXT:_emscripten_glGetQueryObjectui64vEXT,emscripten_glGetQueryObjectuiv:_emscripten_glGetQueryObjectuiv,emscripten_glGetQueryObjectuivEXT:_emscripten_glGetQueryObjectuivEXT,emscripten_glGetQueryiv:_emscripten_glGetQueryiv,emscripten_glGetQueryivEXT:_emscripten_glGetQueryivEXT,emscripten_glGetRenderbufferParameteriv:_emscripten_glGetRenderbufferParameteriv,emscripten_glGetSamplerParameterfv:_emscripten_glGetSamplerParameterfv,emscripten_glGetSamplerParameteriv:_emscripten_glGetSamplerParameteriv,emscripten_glGetShaderInfoLog:_emscripten_glGetShaderInfoLog,emscripten_glGetShaderPrecisionFormat:_emscripten_glGetShaderPrecisionFormat,emscripten_glGetShaderSource:_emscripten_glGetShaderSource,emscripten_glGetShaderiv:_emscripten_glGetShaderiv,emscripten_glGetString:_emscripten_glGetString,emscripten_glGetStringi:_emscripten_glGetStringi,emscripten_glGetSynciv:_emscripten_glGetSynciv,emscripten_glGetTexParameterfv:_emscripten_glGetTexParameterfv,emscripten_glGetTexParameteriv:_emscripten_glGetTexParameteriv,emscripten_glGetTransformFeedbackVarying:_emscripten_glGetTransformFeedbackVarying,emscripten_glGetUniformBlockIndex:_emscripten_glGetUniformBlockIndex,emscripten_glGetUniformIndices:_emscripten_glGetUniformIndices,emscripten_glGetUniformLocation:_emscripten_glGetUniformLocation,emscripten_glGetUniformfv:_emscripten_glGetUniformfv,emscripten_glGetUniformiv:_emscripten_glGetUniformiv,emscripten_glGetUniformuiv:_emscripten_glGetUniformuiv,emscripten_glGetVertexAttribIiv:_emscripten_glGetVertexAttribIiv,emscripten_glGetVertexAttribIuiv:_emscripten_glGetVertexAttribIuiv,emscripten_glGetVertexAttribPointerv:_emscripten_glGetVertexAttribPointerv,emscripten_glGetVertexAttribfv:_emscripten_glGetVertexAttribfv,emscripten_glGetVertexAttribiv:_emscripten_glGetVertexAttribiv,emscripten_glHint:_emscripten_glHint,emscripten_glInvalidateFramebuffer:_emscripten_glInvalidateFramebuffer,emscripten_glInvalidateSubFramebuffer:_emscripten_glInvalidateSubFramebuffer,emscripten_glIsBuffer:_emscripten_glIsBuffer,emscripten_glIsEnabled:_emscripten_glIsEnabled,emscripten_glIsFramebuffer:_emscripten_glIsFramebuffer,emscripten_glIsProgram:_emscripten_glIsProgram,emscripten_glIsQuery:_emscripten_glIsQuery,emscripten_glIsQueryEXT:_emscripten_glIsQueryEXT,emscripten_glIsRenderbuffer:_emscripten_glIsRenderbuffer,emscripten_glIsSampler:_emscripten_glIsSampler,emscripten_glIsShader:_emscripten_glIsShader,emscripten_glIsSync:_emscripten_glIsSync,emscripten_glIsTexture:_emscripten_glIsTexture,emscripten_glIsTransformFeedback:_emscripten_glIsTransformFeedback,emscripten_glIsVertexArray:_emscripten_glIsVertexArray,emscripten_glIsVertexArrayOES:_emscripten_glIsVertexArrayOES,emscripten_glLineWidth:_emscripten_glLineWidth,emscripten_glLinkProgram:_emscripten_glLinkProgram,emscripten_glLoadIdentity:_emscripten_glLoadIdentity,emscripten_glMatrixMode:_emscripten_glMatrixMode,emscripten_glMultiDrawArrays:_emscripten_glMultiDrawArrays,emscripten_glMultiDrawArraysANGLE:_emscripten_glMultiDrawArraysANGLE,emscripten_glMultiDrawArraysInstancedANGLE:_emscripten_glMultiDrawArraysInstancedANGLE,emscripten_glMultiDrawArraysInstancedBaseInstanceANGLE:_emscripten_glMultiDrawArraysInstancedBaseInstanceANGLE,emscripten_glMultiDrawArraysInstancedBaseInstanceWEBGL:_emscripten_glMultiDrawArraysInstancedBaseInstanceWEBGL,emscripten_glMultiDrawArraysInstancedWEBGL:_emscripten_glMultiDrawArraysInstancedWEBGL,emscripten_glMultiDrawArraysWEBGL:_emscripten_glMultiDrawArraysWEBGL,emscripten_glMultiDrawElements:_emscripten_glMultiDrawElements,emscripten_glMultiDrawElementsANGLE:_emscripten_glMultiDrawElementsANGLE,emscripten_glMultiDrawElementsInstancedANGLE:_emscripten_glMultiDrawElementsInstancedANGLE,emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE:_emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE,emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL:_emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL,emscripten_glMultiDrawElementsInstancedWEBGL:_emscripten_glMultiDrawElementsInstancedWEBGL,emscripten_glMultiDrawElementsWEBGL:_emscripten_glMultiDrawElementsWEBGL,emscripten_glPauseTransformFeedback:_emscripten_glPauseTransformFeedback,emscripten_glPixelStorei:_emscripten_glPixelStorei,emscripten_glPolygonModeWEBGL:_emscripten_glPolygonModeWEBGL,emscripten_glPolygonOffset:_emscripten_glPolygonOffset,emscripten_glPolygonOffsetClampEXT:_emscripten_glPolygonOffsetClampEXT,emscripten_glProgramBinary:_emscripten_glProgramBinary,emscripten_glProgramParameteri:_emscripten_glProgramParameteri,emscripten_glQueryCounterEXT:_emscripten_glQueryCounterEXT,emscripten_glReadBuffer:_emscripten_glReadBuffer,emscripten_glReadPixels:_emscripten_glReadPixels,emscripten_glReleaseShaderCompiler:_emscripten_glReleaseShaderCompiler,emscripten_glRenderbufferStorage:_emscripten_glRenderbufferStorage,emscripten_glRenderbufferStorageMultisample:_emscripten_glRenderbufferStorageMultisample,emscripten_glResumeTransformFeedback:_emscripten_glResumeTransformFeedback,emscripten_glSampleCoverage:_emscripten_glSampleCoverage,emscripten_glSamplerParameterf:_emscripten_glSamplerParameterf,emscripten_glSamplerParameterfv:_emscripten_glSamplerParameterfv,emscripten_glSamplerParameteri:_emscripten_glSamplerParameteri,emscripten_glSamplerParameteriv:_emscripten_glSamplerParameteriv,emscripten_glScissor:_emscripten_glScissor,emscripten_glShaderBinary:_emscripten_glShaderBinary,emscripten_glShaderSource:_emscripten_glShaderSource,emscripten_glStencilFunc:_emscripten_glStencilFunc,emscripten_glStencilFuncSeparate:_emscripten_glStencilFuncSeparate,emscripten_glStencilMask:_emscripten_glStencilMask,emscripten_glStencilMaskSeparate:_emscripten_glStencilMaskSeparate,emscripten_glStencilOp:_emscripten_glStencilOp,emscripten_glStencilOpSeparate:_emscripten_glStencilOpSeparate,emscripten_glTexImage2D:_emscripten_glTexImage2D,emscripten_glTexImage3D:_emscripten_glTexImage3D,emscripten_glTexParameterf:_emscripten_glTexParameterf,emscripten_glTexParameterfv:_emscripten_glTexParameterfv,emscripten_glTexParameteri:_emscripten_glTexParameteri,emscripten_glTexParameteriv:_emscripten_glTexParameteriv,emscripten_glTexStorage2D:_emscripten_glTexStorage2D,emscripten_glTexStorage3D:_emscripten_glTexStorage3D,emscripten_glTexSubImage2D:_emscripten_glTexSubImage2D,emscripten_glTexSubImage3D:_emscripten_glTexSubImage3D,emscripten_glTransformFeedbackVaryings:_emscripten_glTransformFeedbackVaryings,emscripten_glUniform1f:_emscripten_glUniform1f,emscripten_glUniform1fv:_emscripten_glUniform1fv,emscripten_glUniform1i:_emscripten_glUniform1i,emscripten_glUniform1iv:_emscripten_glUniform1iv,emscripten_glUniform1ui:_emscripten_glUniform1ui,emscripten_glUniform1uiv:_emscripten_glUniform1uiv,emscripten_glUniform2f:_emscripten_glUniform2f,emscripten_glUniform2fv:_emscripten_glUniform2fv,emscripten_glUniform2i:_emscripten_glUniform2i,emscripten_glUniform2iv:_emscripten_glUniform2iv,emscripten_glUniform2ui:_emscripten_glUniform2ui,emscripten_glUniform2uiv:_emscripten_glUniform2uiv,emscripten_glUniform3f:_emscripten_glUniform3f,emscripten_glUniform3fv:_emscripten_glUniform3fv,emscripten_glUniform3i:_emscripten_glUniform3i,emscripten_glUniform3iv:_emscripten_glUniform3iv,emscripten_glUniform3ui:_emscripten_glUniform3ui,emscripten_glUniform3uiv:_emscripten_glUniform3uiv,emscripten_glUniform4f:_emscripten_glUniform4f,emscripten_glUniform4fv:_emscripten_glUniform4fv,emscripten_glUniform4i:_emscripten_glUniform4i,emscripten_glUniform4iv:_emscripten_glUniform4iv,emscripten_glUniform4ui:_emscripten_glUniform4ui,emscripten_glUniform4uiv:_emscripten_glUniform4uiv,emscripten_glUniformBlockBinding:_emscripten_glUniformBlockBinding,emscripten_glUniformMatrix2fv:_emscripten_glUniformMatrix2fv,emscripten_glUniformMatrix2x3fv:_emscripten_glUniformMatrix2x3fv,emscripten_glUniformMatrix2x4fv:_emscripten_glUniformMatrix2x4fv,emscripten_glUniformMatrix3fv:_emscripten_glUniformMatrix3fv,emscripten_glUniformMatrix3x2fv:_emscripten_glUniformMatrix3x2fv,emscripten_glUniformMatrix3x4fv:_emscripten_glUniformMatrix3x4fv,emscripten_glUniformMatrix4fv:_emscripten_glUniformMatrix4fv,emscripten_glUniformMatrix4x2fv:_emscripten_glUniformMatrix4x2fv,emscripten_glUniformMatrix4x3fv:_emscripten_glUniformMatrix4x3fv,emscripten_glUseProgram:_emscripten_glUseProgram,emscripten_glValidateProgram:_emscripten_glValidateProgram,emscripten_glVertexAttrib1f:_emscripten_glVertexAttrib1f,emscripten_glVertexAttrib1fv:_emscripten_glVertexAttrib1fv,emscripten_glVertexAttrib2f:_emscripten_glVertexAttrib2f,emscripten_glVertexAttrib2fv:_emscripten_glVertexAttrib2fv,emscripten_glVertexAttrib3f:_emscripten_glVertexAttrib3f,emscripten_glVertexAttrib3fv:_emscripten_glVertexAttrib3fv,emscripten_glVertexAttrib4f:_emscripten_glVertexAttrib4f,emscripten_glVertexAttrib4fv:_emscripten_glVertexAttrib4fv,emscripten_glVertexAttribDivisor:_emscripten_glVertexAttribDivisor,emscripten_glVertexAttribDivisorANGLE:_emscripten_glVertexAttribDivisorANGLE,emscripten_glVertexAttribDivisorARB:_emscripten_glVertexAttribDivisorARB,emscripten_glVertexAttribDivisorEXT:_emscripten_glVertexAttribDivisorEXT,emscripten_glVertexAttribDivisorNV:_emscripten_glVertexAttribDivisorNV,emscripten_glVertexAttribI4i:_emscripten_glVertexAttribI4i,emscripten_glVertexAttribI4iv:_emscripten_glVertexAttribI4iv,emscripten_glVertexAttribI4ui:_emscripten_glVertexAttribI4ui,emscripten_glVertexAttribI4uiv:_emscripten_glVertexAttribI4uiv,emscripten_glVertexAttribIPointer:_emscripten_glVertexAttribIPointer,emscripten_glVertexAttribPointer:_emscripten_glVertexAttribPointer,emscripten_glVertexPointer:_emscripten_glVertexPointer,emscripten_glViewport:_emscripten_glViewport,emscripten_glWaitSync:_emscripten_glWaitSync,emscripten_has_asyncify:_emscripten_has_asyncify,emscripten_hide_mouse:_emscripten_hide_mouse,emscripten_html5_remove_all_event_listeners:_emscripten_html5_remove_all_event_listeners,emscripten_is_main_browser_thread:_emscripten_is_main_browser_thread,emscripten_is_webgl_context_lost:_emscripten_is_webgl_context_lost,emscripten_lock_orientation:_emscripten_lock_orientation,emscripten_log:_emscripten_log,emscripten_math_acos:_emscripten_math_acos,emscripten_math_acosh:_emscripten_math_acosh,emscripten_math_asin:_emscripten_math_asin,emscripten_math_asinh:_emscripten_math_asinh,emscripten_math_atan:_emscripten_math_atan,emscripten_math_atan2:_emscripten_math_atan2,emscripten_math_atanh:_emscripten_math_atanh,emscripten_math_cbrt:_emscripten_math_cbrt,emscripten_math_cos:_emscripten_math_cos,emscripten_math_cosh:_emscripten_math_cosh,emscripten_math_exp:_emscripten_math_exp,emscripten_math_expm1:_emscripten_math_expm1,emscripten_math_fmod:_emscripten_math_fmod,emscripten_math_hypot:_emscripten_math_hypot,emscripten_math_log:_emscripten_math_log,emscripten_math_log10:_emscripten_math_log10,emscripten_math_log1p:_emscripten_math_log1p,emscripten_math_log2:_emscripten_math_log2,emscripten_math_pow:_emscripten_math_pow,emscripten_math_random:_emscripten_math_random,emscripten_math_round:_emscripten_math_round,emscripten_math_sign:_emscripten_math_sign,emscripten_math_sin:_emscripten_math_sin,emscripten_math_sinh:_emscripten_math_sinh,emscripten_math_sqrt:_emscripten_math_sqrt,emscripten_math_tan:_emscripten_math_tan,emscripten_math_tanh:_emscripten_math_tanh,emscripten_notify_memory_growth:_emscripten_notify_memory_growth,emscripten_out:_emscripten_out,emscripten_outn:_emscripten_outn,emscripten_pause_main_loop:_emscripten_pause_main_loop,emscripten_pc_get_column:_emscripten_pc_get_column,emscripten_pc_get_file:_emscripten_pc_get_file,emscripten_pc_get_function:_emscripten_pc_get_function,emscripten_pc_get_line:_emscripten_pc_get_line,emscripten_performance_now:_emscripten_performance_now,emscripten_print_double:_emscripten_print_double,emscripten_promise_all:_emscripten_promise_all,emscripten_promise_all_settled:_emscripten_promise_all_settled,emscripten_promise_any:_emscripten_promise_any,emscripten_promise_await:_emscripten_promise_await,emscripten_promise_create:_emscripten_promise_create,emscripten_promise_destroy:_emscripten_promise_destroy,emscripten_promise_race:_emscripten_promise_race,emscripten_promise_resolve:_emscripten_promise_resolve,emscripten_promise_then:_emscripten_promise_then,emscripten_random:_emscripten_random,emscripten_request_animation_frame:_emscripten_request_animation_frame,emscripten_request_animation_frame_loop:_emscripten_request_animation_frame_loop,emscripten_request_fullscreen:_emscripten_request_fullscreen,emscripten_request_fullscreen_strategy:_emscripten_request_fullscreen_strategy,emscripten_request_pointerlock:_emscripten_request_pointerlock,emscripten_resize_heap:_emscripten_resize_heap,emscripten_resume_main_loop:_emscripten_resume_main_loop,emscripten_return_address:_emscripten_return_address,emscripten_run_preload_plugins:_emscripten_run_preload_plugins,emscripten_run_preload_plugins_data:_emscripten_run_preload_plugins_data,emscripten_run_script:_emscripten_run_script,emscripten_run_script_int:_emscripten_run_script_int,emscripten_run_script_string:_emscripten_run_script_string,emscripten_runtime_keepalive_check:_emscripten_runtime_keepalive_check,emscripten_runtime_keepalive_pop:_emscripten_runtime_keepalive_pop,emscripten_runtime_keepalive_push:_emscripten_runtime_keepalive_push,emscripten_sample_gamepad_data:_emscripten_sample_gamepad_data,emscripten_set_batterychargingchange_callback_on_thread:_emscripten_set_batterychargingchange_callback_on_thread,emscripten_set_batterylevelchange_callback_on_thread:_emscripten_set_batterylevelchange_callback_on_thread,emscripten_set_beforeunload_callback_on_thread:_emscripten_set_beforeunload_callback_on_thread,emscripten_set_blur_callback_on_thread:_emscripten_set_blur_callback_on_thread,emscripten_set_canvas_element_size:_emscripten_set_canvas_element_size,emscripten_set_canvas_size:_emscripten_set_canvas_size,emscripten_set_click_callback_on_thread:_emscripten_set_click_callback_on_thread,emscripten_set_dblclick_callback_on_thread:_emscripten_set_dblclick_callback_on_thread,emscripten_set_devicemotion_callback_on_thread:_emscripten_set_devicemotion_callback_on_thread,emscripten_set_deviceorientation_callback_on_thread:_emscripten_set_deviceorientation_callback_on_thread,emscripten_set_element_css_size:_emscripten_set_element_css_size,emscripten_set_focus_callback_on_thread:_emscripten_set_focus_callback_on_thread,emscripten_set_focusin_callback_on_thread:_emscripten_set_focusin_callback_on_thread,emscripten_set_focusout_callback_on_thread:_emscripten_set_focusout_callback_on_thread,emscripten_set_fullscreenchange_callback_on_thread:_emscripten_set_fullscreenchange_callback_on_thread,emscripten_set_gamepadconnected_callback_on_thread:_emscripten_set_gamepadconnected_callback_on_thread,emscripten_set_gamepaddisconnected_callback_on_thread:_emscripten_set_gamepaddisconnected_callback_on_thread,emscripten_set_immediate:_emscripten_set_immediate,emscripten_set_immediate_loop:_emscripten_set_immediate_loop,emscripten_set_interval:_emscripten_set_interval,emscripten_set_keydown_callback_on_thread:_emscripten_set_keydown_callback_on_thread,emscripten_set_keypress_callback_on_thread:_emscripten_set_keypress_callback_on_thread,emscripten_set_keyup_callback_on_thread:_emscripten_set_keyup_callback_on_thread,emscripten_set_main_loop:_emscripten_set_main_loop,emscripten_set_main_loop_arg:_emscripten_set_main_loop_arg,emscripten_set_main_loop_expected_blockers:_emscripten_set_main_loop_expected_blockers,emscripten_set_main_loop_timing:_emscripten_set_main_loop_timing,emscripten_set_mousedown_callback_on_thread:_emscripten_set_mousedown_callback_on_thread,emscripten_set_mouseenter_callback_on_thread:_emscripten_set_mouseenter_callback_on_thread,emscripten_set_mouseleave_callback_on_thread:_emscripten_set_mouseleave_callback_on_thread,emscripten_set_mousemove_callback_on_thread:_emscripten_set_mousemove_callback_on_thread,emscripten_set_mouseout_callback_on_thread:_emscripten_set_mouseout_callback_on_thread,emscripten_set_mouseover_callback_on_thread:_emscripten_set_mouseover_callback_on_thread,emscripten_set_mouseup_callback_on_thread:_emscripten_set_mouseup_callback_on_thread,emscripten_set_orientationchange_callback_on_thread:_emscripten_set_orientationchange_callback_on_thread,emscripten_set_pointerlockchange_callback_on_thread:_emscripten_set_pointerlockchange_callback_on_thread,emscripten_set_pointerlockerror_callback_on_thread:_emscripten_set_pointerlockerror_callback_on_thread,emscripten_set_resize_callback_on_thread:_emscripten_set_resize_callback_on_thread,emscripten_set_scroll_callback_on_thread:_emscripten_set_scroll_callback_on_thread,emscripten_set_socket_close_callback:_emscripten_set_socket_close_callback,emscripten_set_socket_connection_callback:_emscripten_set_socket_connection_callback,emscripten_set_socket_error_callback:_emscripten_set_socket_error_callback,emscripten_set_socket_listen_callback:_emscripten_set_socket_listen_callback,emscripten_set_socket_message_callback:_emscripten_set_socket_message_callback,emscripten_set_socket_open_callback:_emscripten_set_socket_open_callback,emscripten_set_timeout:_emscripten_set_timeout,emscripten_set_timeout_loop:_emscripten_set_timeout_loop,emscripten_set_touchcancel_callback_on_thread:_emscripten_set_touchcancel_callback_on_thread,emscripten_set_touchend_callback_on_thread:_emscripten_set_touchend_callback_on_thread,emscripten_set_touchmove_callback_on_thread:_emscripten_set_touchmove_callback_on_thread,emscripten_set_touchstart_callback_on_thread:_emscripten_set_touchstart_callback_on_thread,emscripten_set_visibilitychange_callback_on_thread:_emscripten_set_visibilitychange_callback_on_thread,emscripten_set_webglcontextlost_callback_on_thread:_emscripten_set_webglcontextlost_callback_on_thread,emscripten_set_webglcontextrestored_callback_on_thread:_emscripten_set_webglcontextrestored_callback_on_thread,emscripten_set_wheel_callback_on_thread:_emscripten_set_wheel_callback_on_thread,emscripten_set_window_title:_emscripten_set_window_title,emscripten_stack_snapshot:_emscripten_stack_snapshot,emscripten_stack_unwind_buffer:_emscripten_stack_unwind_buffer,emscripten_supports_offscreencanvas:_emscripten_supports_offscreencanvas,emscripten_throw_number:_emscripten_throw_number,emscripten_throw_string:_emscripten_throw_string,emscripten_unlock_orientation:_emscripten_unlock_orientation,emscripten_unwind_to_js_event_loop:_emscripten_unwind_to_js_event_loop,emscripten_vibrate:_emscripten_vibrate,emscripten_vibrate_pattern:_emscripten_vibrate_pattern,emscripten_webgl_commit_frame:_emscripten_webgl_commit_frame,emscripten_webgl_create_context:_emscripten_webgl_create_context,emscripten_webgl_destroy_context:_emscripten_webgl_destroy_context,emscripten_webgl_do_commit_frame:_emscripten_webgl_do_commit_frame,emscripten_webgl_do_create_context:_emscripten_webgl_do_create_context,emscripten_webgl_do_get_current_context:_emscripten_webgl_do_get_current_context,emscripten_webgl_enable_ANGLE_instanced_arrays:_emscripten_webgl_enable_ANGLE_instanced_arrays,emscripten_webgl_enable_EXT_clip_control:_emscripten_webgl_enable_EXT_clip_control,emscripten_webgl_enable_EXT_polygon_offset_clamp:_emscripten_webgl_enable_EXT_polygon_offset_clamp,emscripten_webgl_enable_OES_vertex_array_object:_emscripten_webgl_enable_OES_vertex_array_object,emscripten_webgl_enable_WEBGL_draw_buffers:_emscripten_webgl_enable_WEBGL_draw_buffers,emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance:_emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance,emscripten_webgl_enable_WEBGL_multi_draw:_emscripten_webgl_enable_WEBGL_multi_draw,emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance:_emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance,emscripten_webgl_enable_WEBGL_polygon_mode:_emscripten_webgl_enable_WEBGL_polygon_mode,emscripten_webgl_enable_extension:_emscripten_webgl_enable_extension,emscripten_webgl_get_context_attributes:_emscripten_webgl_get_context_attributes,emscripten_webgl_get_current_context:_emscripten_webgl_get_current_context,emscripten_webgl_get_drawing_buffer_size:_emscripten_webgl_get_drawing_buffer_size,emscripten_webgl_get_parameter_d:_emscripten_webgl_get_parameter_d,emscripten_webgl_get_parameter_i64v:_emscripten_webgl_get_parameter_i64v,emscripten_webgl_get_parameter_o:_emscripten_webgl_get_parameter_o,emscripten_webgl_get_parameter_utf8:_emscripten_webgl_get_parameter_utf8,emscripten_webgl_get_parameter_v:_emscripten_webgl_get_parameter_v,emscripten_webgl_get_program_info_log_utf8:_emscripten_webgl_get_program_info_log_utf8,emscripten_webgl_get_program_parameter_d:_emscripten_webgl_get_program_parameter_d,emscripten_webgl_get_shader_info_log_utf8:_emscripten_webgl_get_shader_info_log_utf8,emscripten_webgl_get_shader_parameter_d:_emscripten_webgl_get_shader_parameter_d,emscripten_webgl_get_shader_source_utf8:_emscripten_webgl_get_shader_source_utf8,emscripten_webgl_get_supported_extensions:_emscripten_webgl_get_supported_extensions,emscripten_webgl_get_uniform_d:_emscripten_webgl_get_uniform_d,emscripten_webgl_get_uniform_v:_emscripten_webgl_get_uniform_v,emscripten_webgl_get_vertex_attrib_d:_emscripten_webgl_get_vertex_attrib_d,emscripten_webgl_get_vertex_attrib_o:_emscripten_webgl_get_vertex_attrib_o,emscripten_webgl_get_vertex_attrib_v:_emscripten_webgl_get_vertex_attrib_v,emscripten_webgl_make_context_current:_emscripten_webgl_make_context_current,emscripten_websocket_close:_emscripten_websocket_close,emscripten_websocket_deinitialize:_emscripten_websocket_deinitialize,emscripten_websocket_delete:_emscripten_websocket_delete,emscripten_websocket_get_buffered_amount:_emscripten_websocket_get_buffered_amount,emscripten_websocket_get_extensions:_emscripten_websocket_get_extensions,emscripten_websocket_get_extensions_length:_emscripten_websocket_get_extensions_length,emscripten_websocket_get_protocol:_emscripten_websocket_get_protocol,emscripten_websocket_get_protocol_length:_emscripten_websocket_get_protocol_length,emscripten_websocket_get_ready_state:_emscripten_websocket_get_ready_state,emscripten_websocket_get_url:_emscripten_websocket_get_url,emscripten_websocket_get_url_length:_emscripten_websocket_get_url_length,emscripten_websocket_is_supported:_emscripten_websocket_is_supported,emscripten_websocket_new:_emscripten_websocket_new,emscripten_websocket_send_binary:_emscripten_websocket_send_binary,emscripten_websocket_send_utf8_text:_emscripten_websocket_send_utf8_text,emscripten_websocket_set_onclose_callback_on_thread:_emscripten_websocket_set_onclose_callback_on_thread,emscripten_websocket_set_onerror_callback_on_thread:_emscripten_websocket_set_onerror_callback_on_thread,emscripten_websocket_set_onmessage_callback_on_thread:_emscripten_websocket_set_onmessage_callback_on_thread,emscripten_websocket_set_onopen_callback_on_thread:_emscripten_websocket_set_onopen_callback_on_thread,endprotoent:_endprotoent,environ_get:_environ_get,environ_sizes_get:_environ_sizes_get,exit:_exit,fail_test,fd_close:_fd_close,fd_fdstat_get:_fd_fdstat_get,fd_pread:_fd_pread,fd_pwrite:_fd_pwrite,fd_read:_fd_read,fd_seek:_fd_seek,fd_sync:_fd_sync,fd_write:_fd_write,ffi_call_js,ffi_closure_alloc_js,ffi_closure_free_js,ffi_prep_closure_loc_js,filledEllipseColor:_filledEllipseColor,filledEllipseRGBA:_filledEllipseRGBA,gc_register_proxies,get_async_js_call_done_callback,get_length_helper,get_length_string,get_suspender,getaddrinfo:_getaddrinfo,getnameinfo:_getnameinfo,getprotobyname:_getprotobyname,getprotobynumber:_getprotobynumber,getprotoent:_getprotoent,glActiveTexture:_glActiveTexture,glAttachShader:_glAttachShader,glBegin:_glBegin,glBeginQuery:_glBeginQuery,glBeginQueryEXT:_glBeginQueryEXT,glBeginTransformFeedback:_glBeginTransformFeedback,glBindAttribLocation:_glBindAttribLocation,glBindBuffer:_glBindBuffer,glBindBufferBase:_glBindBufferBase,glBindBufferRange:_glBindBufferRange,glBindFramebuffer:_glBindFramebuffer,glBindRenderbuffer:_glBindRenderbuffer,glBindSampler:_glBindSampler,glBindTexture:_glBindTexture,glBindTransformFeedback:_glBindTransformFeedback,glBindVertexArray:_glBindVertexArray,glBindVertexArrayOES:_glBindVertexArrayOES,glBlendColor:_glBlendColor,glBlendEquation:_glBlendEquation,glBlendEquationSeparate:_glBlendEquationSeparate,glBlendFunc:_glBlendFunc,glBlendFuncSeparate:_glBlendFuncSeparate,glBlitFramebuffer:_glBlitFramebuffer,glBufferData:_glBufferData,glBufferSubData:_glBufferSubData,glCheckFramebufferStatus:_glCheckFramebufferStatus,glClear:_glClear,glClearBufferfi:_glClearBufferfi,glClearBufferfv:_glClearBufferfv,glClearBufferiv:_glClearBufferiv,glClearBufferuiv:_glClearBufferuiv,glClearColor:_glClearColor,glClearDepth:_glClearDepth,glClearDepthf:_glClearDepthf,glClearStencil:_glClearStencil,glClientWaitSync:_glClientWaitSync,glClipControlEXT:_glClipControlEXT,glColorMask:_glColorMask,glCompileShader:_glCompileShader,glCompressedTexImage2D:_glCompressedTexImage2D,glCompressedTexImage3D:_glCompressedTexImage3D,glCompressedTexSubImage2D:_glCompressedTexSubImage2D,glCompressedTexSubImage3D:_glCompressedTexSubImage3D,glCopyBufferSubData:_glCopyBufferSubData,glCopyTexImage2D:_glCopyTexImage2D,glCopyTexSubImage2D:_glCopyTexSubImage2D,glCopyTexSubImage3D:_glCopyTexSubImage3D,glCreateProgram:_glCreateProgram,glCreateShader:_glCreateShader,glCullFace:_glCullFace,glDeleteBuffers:_glDeleteBuffers,glDeleteFramebuffers:_glDeleteFramebuffers,glDeleteProgram:_glDeleteProgram,glDeleteQueries:_glDeleteQueries,glDeleteQueriesEXT:_glDeleteQueriesEXT,glDeleteRenderbuffers:_glDeleteRenderbuffers,glDeleteSamplers:_glDeleteSamplers,glDeleteShader:_glDeleteShader,glDeleteSync:_glDeleteSync,glDeleteTextures:_glDeleteTextures,glDeleteTransformFeedbacks:_glDeleteTransformFeedbacks,glDeleteVertexArrays:_glDeleteVertexArrays,glDeleteVertexArraysOES:_glDeleteVertexArraysOES,glDepthFunc:_glDepthFunc,glDepthMask:_glDepthMask,glDepthRange:_glDepthRange,glDepthRangef:_glDepthRangef,glDetachShader:_glDetachShader,glDisable:_glDisable,glDisableVertexAttribArray:_glDisableVertexAttribArray,glDrawArrays:_glDrawArrays,glDrawArraysInstanced:_glDrawArraysInstanced,glDrawArraysInstancedANGLE:_glDrawArraysInstancedANGLE,glDrawArraysInstancedARB:_glDrawArraysInstancedARB,glDrawArraysInstancedBaseInstance:_glDrawArraysInstancedBaseInstance,glDrawArraysInstancedBaseInstanceANGLE:_glDrawArraysInstancedBaseInstanceANGLE,glDrawArraysInstancedBaseInstanceWEBGL:_glDrawArraysInstancedBaseInstanceWEBGL,glDrawArraysInstancedEXT:_glDrawArraysInstancedEXT,glDrawArraysInstancedNV:_glDrawArraysInstancedNV,glDrawBuffers:_glDrawBuffers,glDrawBuffersEXT:_glDrawBuffersEXT,glDrawBuffersWEBGL:_glDrawBuffersWEBGL,glDrawElements:_glDrawElements,glDrawElementsInstanced:_glDrawElementsInstanced,glDrawElementsInstancedANGLE:_glDrawElementsInstancedANGLE,glDrawElementsInstancedARB:_glDrawElementsInstancedARB,glDrawElementsInstancedBaseVertexBaseInstanceANGLE:_glDrawElementsInstancedBaseVertexBaseInstanceANGLE,glDrawElementsInstancedBaseVertexBaseInstanceWEBGL:_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL,glDrawElementsInstancedEXT:_glDrawElementsInstancedEXT,glDrawElementsInstancedNV:_glDrawElementsInstancedNV,glDrawRangeElements:_glDrawRangeElements,glEnable:_glEnable,glEnableVertexAttribArray:_glEnableVertexAttribArray,glEndQuery:_glEndQuery,glEndQueryEXT:_glEndQueryEXT,glEndTransformFeedback:_glEndTransformFeedback,glFenceSync:_glFenceSync,glFinish:_glFinish,glFlush:_glFlush,glFramebufferRenderbuffer:_glFramebufferRenderbuffer,glFramebufferTexture2D:_glFramebufferTexture2D,glFramebufferTextureLayer:_glFramebufferTextureLayer,glFrontFace:_glFrontFace,glGenBuffers:_glGenBuffers,glGenFramebuffers:_glGenFramebuffers,glGenQueries:_glGenQueries,glGenQueriesEXT:_glGenQueriesEXT,glGenRenderbuffers:_glGenRenderbuffers,glGenSamplers:_glGenSamplers,glGenTextures:_glGenTextures,glGenTransformFeedbacks:_glGenTransformFeedbacks,glGenVertexArrays:_glGenVertexArrays,glGenVertexArraysOES:_glGenVertexArraysOES,glGenerateMipmap:_glGenerateMipmap,glGetActiveAttrib:_glGetActiveAttrib,glGetActiveUniform:_glGetActiveUniform,glGetActiveUniformBlockName:_glGetActiveUniformBlockName,glGetActiveUniformBlockiv:_glGetActiveUniformBlockiv,glGetActiveUniformsiv:_glGetActiveUniformsiv,glGetAttachedShaders:_glGetAttachedShaders,glGetAttribLocation:_glGetAttribLocation,glGetBooleanv:_glGetBooleanv,glGetBufferParameteri64v:_glGetBufferParameteri64v,glGetBufferParameteriv:_glGetBufferParameteriv,glGetBufferSubData:_glGetBufferSubData,glGetError:_glGetError,glGetFloatv:_glGetFloatv,glGetFragDataLocation:_glGetFragDataLocation,glGetFramebufferAttachmentParameteriv:_glGetFramebufferAttachmentParameteriv,glGetInteger64i_v:_glGetInteger64i_v,glGetInteger64v:_glGetInteger64v,glGetIntegeri_v:_glGetIntegeri_v,glGetIntegerv:_glGetIntegerv,glGetInternalformativ:_glGetInternalformativ,glGetProgramBinary:_glGetProgramBinary,glGetProgramInfoLog:_glGetProgramInfoLog,glGetProgramiv:_glGetProgramiv,glGetQueryObjecti64vEXT:_glGetQueryObjecti64vEXT,glGetQueryObjectivEXT:_glGetQueryObjectivEXT,glGetQueryObjectui64vEXT:_glGetQueryObjectui64vEXT,glGetQueryObjectuiv:_glGetQueryObjectuiv,glGetQueryObjectuivEXT:_glGetQueryObjectuivEXT,glGetQueryiv:_glGetQueryiv,glGetQueryivEXT:_glGetQueryivEXT,glGetRenderbufferParameteriv:_glGetRenderbufferParameteriv,glGetSamplerParameterfv:_glGetSamplerParameterfv,glGetSamplerParameteriv:_glGetSamplerParameteriv,glGetShaderInfoLog:_glGetShaderInfoLog,glGetShaderPrecisionFormat:_glGetShaderPrecisionFormat,glGetShaderSource:_glGetShaderSource,glGetShaderiv:_glGetShaderiv,glGetString:_glGetString,glGetStringi:_glGetStringi,glGetSynciv:_glGetSynciv,glGetTexParameterfv:_glGetTexParameterfv,glGetTexParameteriv:_glGetTexParameteriv,glGetTransformFeedbackVarying:_glGetTransformFeedbackVarying,glGetUniformBlockIndex:_glGetUniformBlockIndex,glGetUniformIndices:_glGetUniformIndices,glGetUniformLocation:_glGetUniformLocation,glGetUniformfv:_glGetUniformfv,glGetUniformiv:_glGetUniformiv,glGetUniformuiv:_glGetUniformuiv,glGetVertexAttribIiv:_glGetVertexAttribIiv,glGetVertexAttribIuiv:_glGetVertexAttribIuiv,glGetVertexAttribPointerv:_glGetVertexAttribPointerv,glGetVertexAttribfv:_glGetVertexAttribfv,glGetVertexAttribiv:_glGetVertexAttribiv,glHint:_glHint,glInvalidateFramebuffer:_glInvalidateFramebuffer,glInvalidateSubFramebuffer:_glInvalidateSubFramebuffer,glIsBuffer:_glIsBuffer,glIsEnabled:_glIsEnabled,glIsFramebuffer:_glIsFramebuffer,glIsProgram:_glIsProgram,glIsQuery:_glIsQuery,glIsQueryEXT:_glIsQueryEXT,glIsRenderbuffer:_glIsRenderbuffer,glIsSampler:_glIsSampler,glIsShader:_glIsShader,glIsSync:_glIsSync,glIsTexture:_glIsTexture,glIsTransformFeedback:_glIsTransformFeedback,glIsVertexArray:_glIsVertexArray,glIsVertexArrayOES:_glIsVertexArrayOES,glLineWidth:_glLineWidth,glLinkProgram:_glLinkProgram,glLoadIdentity:_glLoadIdentity,glMatrixMode:_glMatrixMode,glMultiDrawArrays:_glMultiDrawArrays,glMultiDrawArraysANGLE:_glMultiDrawArraysANGLE,glMultiDrawArraysInstancedANGLE:_glMultiDrawArraysInstancedANGLE,glMultiDrawArraysInstancedBaseInstanceANGLE:_glMultiDrawArraysInstancedBaseInstanceANGLE,glMultiDrawArraysInstancedBaseInstanceWEBGL:_glMultiDrawArraysInstancedBaseInstanceWEBGL,glMultiDrawArraysInstancedWEBGL:_glMultiDrawArraysInstancedWEBGL,glMultiDrawArraysWEBGL:_glMultiDrawArraysWEBGL,glMultiDrawElements:_glMultiDrawElements,glMultiDrawElementsANGLE:_glMultiDrawElementsANGLE,glMultiDrawElementsInstancedANGLE:_glMultiDrawElementsInstancedANGLE,glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE:_glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE,glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL:_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL,glMultiDrawElementsInstancedWEBGL:_glMultiDrawElementsInstancedWEBGL,glMultiDrawElementsWEBGL:_glMultiDrawElementsWEBGL,glPauseTransformFeedback:_glPauseTransformFeedback,glPixelStorei:_glPixelStorei,glPolygonModeWEBGL:_glPolygonModeWEBGL,glPolygonOffset:_glPolygonOffset,glPolygonOffsetClampEXT:_glPolygonOffsetClampEXT,glProgramBinary:_glProgramBinary,glProgramParameteri:_glProgramParameteri,glQueryCounterEXT:_glQueryCounterEXT,glReadBuffer:_glReadBuffer,glReadPixels:_glReadPixels,glReleaseShaderCompiler:_glReleaseShaderCompiler,glRenderbufferStorage:_glRenderbufferStorage,glRenderbufferStorageMultisample:_glRenderbufferStorageMultisample,glResumeTransformFeedback:_glResumeTransformFeedback,glSampleCoverage:_glSampleCoverage,glSamplerParameterf:_glSamplerParameterf,glSamplerParameterfv:_glSamplerParameterfv,glSamplerParameteri:_glSamplerParameteri,glSamplerParameteriv:_glSamplerParameteriv,glScissor:_glScissor,glShaderBinary:_glShaderBinary,glShaderSource:_glShaderSource,glStencilFunc:_glStencilFunc,glStencilFuncSeparate:_glStencilFuncSeparate,glStencilMask:_glStencilMask,glStencilMaskSeparate:_glStencilMaskSeparate,glStencilOp:_glStencilOp,glStencilOpSeparate:_glStencilOpSeparate,glTexImage2D:_glTexImage2D,glTexImage3D:_glTexImage3D,glTexParameterf:_glTexParameterf,glTexParameterfv:_glTexParameterfv,glTexParameteri:_glTexParameteri,glTexParameteriv:_glTexParameteriv,glTexStorage2D:_glTexStorage2D,glTexStorage3D:_glTexStorage3D,glTexSubImage2D:_glTexSubImage2D,glTexSubImage3D:_glTexSubImage3D,glTransformFeedbackVaryings:_glTransformFeedbackVaryings,glUniform1f:_glUniform1f,glUniform1fv:_glUniform1fv,glUniform1i:_glUniform1i,glUniform1iv:_glUniform1iv,glUniform1ui:_glUniform1ui,glUniform1uiv:_glUniform1uiv,glUniform2f:_glUniform2f,glUniform2fv:_glUniform2fv,glUniform2i:_glUniform2i,glUniform2iv:_glUniform2iv,glUniform2ui:_glUniform2ui,glUniform2uiv:_glUniform2uiv,glUniform3f:_glUniform3f,glUniform3fv:_glUniform3fv,glUniform3i:_glUniform3i,glUniform3iv:_glUniform3iv,glUniform3ui:_glUniform3ui,glUniform3uiv:_glUniform3uiv,glUniform4f:_glUniform4f,glUniform4fv:_glUniform4fv,glUniform4i:_glUniform4i,glUniform4iv:_glUniform4iv,glUniform4ui:_glUniform4ui,glUniform4uiv:_glUniform4uiv,glUniformBlockBinding:_glUniformBlockBinding,glUniformMatrix2fv:_glUniformMatrix2fv,glUniformMatrix2x3fv:_glUniformMatrix2x3fv,glUniformMatrix2x4fv:_glUniformMatrix2x4fv,glUniformMatrix3fv:_glUniformMatrix3fv,glUniformMatrix3x2fv:_glUniformMatrix3x2fv,glUniformMatrix3x4fv:_glUniformMatrix3x4fv,glUniformMatrix4fv:_glUniformMatrix4fv,glUniformMatrix4x2fv:_glUniformMatrix4x2fv,glUniformMatrix4x3fv:_glUniformMatrix4x3fv,glUseProgram:_glUseProgram,glValidateProgram:_glValidateProgram,glVertexAttrib1f:_glVertexAttrib1f,glVertexAttrib1fv:_glVertexAttrib1fv,glVertexAttrib2f:_glVertexAttrib2f,glVertexAttrib2fv:_glVertexAttrib2fv,glVertexAttrib3f:_glVertexAttrib3f,glVertexAttrib3fv:_glVertexAttrib3fv,glVertexAttrib4f:_glVertexAttrib4f,glVertexAttrib4fv:_glVertexAttrib4fv,glVertexAttribDivisor:_glVertexAttribDivisor,glVertexAttribDivisorANGLE:_glVertexAttribDivisorANGLE,glVertexAttribDivisorARB:_glVertexAttribDivisorARB,glVertexAttribDivisorEXT:_glVertexAttribDivisorEXT,glVertexAttribDivisorNV:_glVertexAttribDivisorNV,glVertexAttribI4i:_glVertexAttribI4i,glVertexAttribI4iv:_glVertexAttribI4iv,glVertexAttribI4ui:_glVertexAttribI4ui,glVertexAttribI4uiv:_glVertexAttribI4uiv,glVertexAttribIPointer:_glVertexAttribIPointer,glVertexAttribPointer:_glVertexAttribPointer,glVertexPointer:_glVertexPointer,glViewport:_glViewport,glWaitSync:_glWaitSync,handle_next_result_js,hiwire_invalid_ref_js,is_comlink_proxy,is_sentinel:_is_sentinel,js2python_convert,js2python_immutable_js,js2python_js,jslib_init_buffers_js,jslib_init_js,lineColor:_lineColor,lineRGBA:_lineRGBA,memory:wasmMemory,my_dict_converter,new_error,pixelRGBA:_pixelRGBA,proc_exit:_proc_exit,proxy_cache_get,proxy_cache_set,pyodide_js_init,pyproxy_AsPyObject,pyproxy_Check,pyproxy_new,pyproxy_new_ex,python2js__default_converter_js,python2js__eager_converter_js,python2js_custom__create_jscontext,random_get:_random_get,raw_call_js,rectangleColor:_rectangleColor,rectangleRGBA:_rectangleRGBA,restoreState,restore_stderr,rotozoomSurface:_rotozoomSurface,saveState,setNetworkCallback:_setNetworkCallback,set_pyodide_module,set_suspender,setprotoent:_setprotoent,stackAlloc:_stackAlloc,stackRestore:_stackRestore,stackSave:_stackSave,strptime:_strptime,strptime_l:_strptime_l,syncifyHandler,throw_no_gil,wrap_async_generator,wrap_generator,zoomSurface:_zoomSurface};var wasmExports=await createWasm();var ___wasm_call_ctors=wasmExports["__wasm_call_ctors"];var _set_method_docstring=Module["_set_method_docstring"]=wasmExports["set_method_docstring"];var _PyObject_GetAttrString=Module["_PyObject_GetAttrString"]=wasmExports["PyObject_GetAttrString"];var __PyUnicode_FromId=Module["__PyUnicode_FromId"]=wasmExports["_PyUnicode_FromId"];var _PyObject_VectorcallMethod=Module["_PyObject_VectorcallMethod"]=wasmExports["PyObject_VectorcallMethod"];var _PyUnicode_AsUTF8AndSize=Module["_PyUnicode_AsUTF8AndSize"]=wasmExports["PyUnicode_AsUTF8AndSize"];var _malloc=wasmExports["malloc"];var __Py_Dealloc=Module["__Py_Dealloc"]=wasmExports["_Py_Dealloc"];var _PyErr_Format=Module["_PyErr_Format"]=wasmExports["PyErr_Format"];var _add_methods_and_set_docstrings=Module["_add_methods_and_set_docstrings"]=wasmExports["add_methods_and_set_docstrings"];var _PyModule_AddFunctions=Module["_PyModule_AddFunctions"]=wasmExports["PyModule_AddFunctions"];var _docstring_init=Module["_docstring_init"]=wasmExports["docstring_init"];var _PyImport_ImportModule=Module["_PyImport_ImportModule"]=wasmExports["PyImport_ImportModule"];var _dump_traceback=Module["_dump_traceback"]=wasmExports["dump_traceback"];var _fileno=wasmExports["fileno"];var _PyGILState_GetThisThreadState=Module["_PyGILState_GetThisThreadState"]=wasmExports["PyGILState_GetThisThreadState"];var _set_error=Module["_set_error"]=wasmExports["set_error"];var _PyErr_SetObject=Module["_PyErr_SetObject"]=wasmExports["PyErr_SetObject"];var _restore_sys_last_exception=Module["_restore_sys_last_exception"]=wasmExports["restore_sys_last_exception"];var _PySys_GetObject=Module["_PySys_GetObject"]=wasmExports["PySys_GetObject"];var _PyErr_SetRaisedException=Module["_PyErr_SetRaisedException"]=wasmExports["PyErr_SetRaisedException"];var _wrap_exception=Module["_wrap_exception"]=wasmExports["wrap_exception"];var _PyErr_GetRaisedException=Module["_PyErr_GetRaisedException"]=wasmExports["PyErr_GetRaisedException"];var _PyErr_GivenExceptionMatches=Module["_PyErr_GivenExceptionMatches"]=wasmExports["PyErr_GivenExceptionMatches"];var _PyErr_Print=Module["_PyErr_Print"]=wasmExports["PyErr_Print"];var __PyObject_GetAttrId=Module["__PyObject_GetAttrId"]=wasmExports["_PyObject_GetAttrId"];var _PyUnicode_AsUTF8=Module["_PyUnicode_AsUTF8"]=wasmExports["PyUnicode_AsUTF8"];var _PySys_WriteStderr=Module["_PySys_WriteStderr"]=wasmExports["PySys_WriteStderr"];var _PyErr_DisplayException=Module["_PyErr_DisplayException"]=wasmExports["PyErr_DisplayException"];var _JsvString_FromId=Module["_JsvString_FromId"]=wasmExports["JsvString_FromId"];var _pythonexc2js=Module["_pythonexc2js"]=wasmExports["pythonexc2js"];var _trigger_fatal_error=Module["_trigger_fatal_error"]=wasmExports["trigger_fatal_error"];var _raw_call=Module["_raw_call"]=wasmExports["raw_call"];var _JsProxy_Val=Module["_JsProxy_Val"]=wasmExports["JsProxy_Val"];var _error_handling_init=Module["_error_handling_init"]=wasmExports["error_handling_init"];var _hiwire_invalid_ref=Module["_hiwire_invalid_ref"]=wasmExports["hiwire_invalid_ref"];var _init_pyodide_proxy=Module["_init_pyodide_proxy"]=wasmExports["init_pyodide_proxy"];var _python2js=Module["_python2js"]=wasmExports["python2js"];var _PyInit__pyodide_core=Module["_PyInit__pyodide_core"]=wasmExports["PyInit__pyodide_core"];var _PyErr_Occurred=Module["_PyErr_Occurred"]=wasmExports["PyErr_Occurred"];var __PyErr_FormatFromCause=Module["__PyErr_FormatFromCause"]=wasmExports["_PyErr_FormatFromCause"];var _PyModule_Create2=Module["_PyModule_Create2"]=wasmExports["PyModule_Create2"];var _PyImport_GetModuleDict=Module["_PyImport_GetModuleDict"]=wasmExports["PyImport_GetModuleDict"];var _PyDict_SetItemString=Module["_PyDict_SetItemString"]=wasmExports["PyDict_SetItemString"];var _jslib_init=Module["_jslib_init"]=wasmExports["jslib_init"];var _python2js_init=Module["_python2js_init"]=wasmExports["python2js_init"];var _jsproxy_init=Module["_jsproxy_init"]=wasmExports["jsproxy_init"];var _jsproxy_call_init=Module["_jsproxy_call_init"]=wasmExports["jsproxy_call_init"];var _pyproxy_init=Module["_pyproxy_init"]=wasmExports["pyproxy_init"];var _jsbind_init=Module["_jsbind_init"]=wasmExports["jsbind_init"];var _pyodide_export=Module["_pyodide_export"]=wasmExports["pyodide_export"];var _PyUnicode_Data=Module["_PyUnicode_Data"]=wasmExports["PyUnicode_Data"];var __js2python_none=Module["__js2python_none"]=wasmExports["_js2python_none"];var __js2python_null=Module["__js2python_null"]=wasmExports["_js2python_null"];var __js2python_true=Module["__js2python_true"]=wasmExports["_js2python_true"];var __js2python_false=Module["__js2python_false"]=wasmExports["_js2python_false"];var __js2python_pyproxy=Module["__js2python_pyproxy"]=wasmExports["_js2python_pyproxy"];var _js2python_immutable=Module["_js2python_immutable"]=wasmExports["js2python_immutable"];var _js2python=Module["_js2python"]=wasmExports["js2python"];var _JsProxy_getflags=Module["_JsProxy_getflags"]=wasmExports["JsProxy_getflags"];var _PyLong_AsLong=Module["_PyLong_AsLong"]=wasmExports["PyLong_AsLong"];var _JsProxy_is_py_json=Module["_JsProxy_is_py_json"]=wasmExports["JsProxy_is_py_json"];var _js2python_as_py_json=Module["_js2python_as_py_json"]=wasmExports["js2python_as_py_json"];var _hiwire_get=Module["_hiwire_get"]=wasmExports["hiwire_get"];var _JsProxy_create_with_type=Module["_JsProxy_create_with_type"]=wasmExports["JsProxy_create_with_type"];var _JsProxy_bind_sig=Module["_JsProxy_bind_sig"]=wasmExports["JsProxy_bind_sig"];var _JsRef_toVal=Module["_JsRef_toVal"]=wasmExports["JsRef_toVal"];var _PyErr_SetString=Module["_PyErr_SetString"]=wasmExports["PyErr_SetString"];var _JsProxy_create_with_this=Module["_JsProxy_create_with_this"]=wasmExports["JsProxy_create_with_this"];var _JsProxy_bind_class=Module["_JsProxy_bind_class"]=wasmExports["JsProxy_bind_class"];var _clear_method_call_singleton=Module["_clear_method_call_singleton"]=wasmExports["clear_method_call_singleton"];var _hiwire_decref=Module["_hiwire_decref"]=wasmExports["hiwire_decref"];var _JsProxy_GetMethod=Module["_JsProxy_GetMethod"]=wasmExports["JsProxy_GetMethod"];var __PyObject_GenericGetAttrWithDict=Module["__PyObject_GenericGetAttrWithDict"]=wasmExports["_PyObject_GenericGetAttrWithDict"];var _strcmp=Module["_strcmp"]=wasmExports["strcmp"];var _PyArg_ParseTuple=Module["_PyArg_ParseTuple"]=wasmExports["PyArg_ParseTuple"];var _Js2PyConverter_convert=Module["_Js2PyConverter_convert"]=wasmExports["Js2PyConverter_convert"];var _hiwire_new=Module["_hiwire_new"]=wasmExports["hiwire_new"];var _hiwire_incref=Module["_hiwire_incref"]=wasmExports["hiwire_incref"];var _JsProxy_GetAttr=Module["_JsProxy_GetAttr"]=wasmExports["JsProxy_GetAttr"];var _handle_next_result=Module["_handle_next_result"]=wasmExports["handle_next_result"];var _free=Module["_free"]=wasmExports["free"];var _JsProxy_create_objmap=Module["_JsProxy_create_objmap"]=wasmExports["JsProxy_create_objmap"];var _JsProxy_am_send=Module["_JsProxy_am_send"]=wasmExports["JsProxy_am_send"];var _python2js_track_proxies=Module["_python2js_track_proxies"]=wasmExports["python2js_track_proxies"];var _JsvObject_CallMethodId_OneArg=Module["_JsvObject_CallMethodId_OneArg"]=wasmExports["JsvObject_CallMethodId_OneArg"];var _JsProxy_IterNext=Module["_JsProxy_IterNext"]=wasmExports["JsProxy_IterNext"];var __PyGen_SetStopIterationValue=Module["__PyGen_SetStopIterationValue"]=wasmExports["_PyGen_SetStopIterationValue"];var _JsGenerator_send=Module["_JsGenerator_send"]=wasmExports["JsGenerator_send"];var _PyErr_SetNone=Module["_PyErr_SetNone"]=wasmExports["PyErr_SetNone"];var _JsException_js_error_getter=Module["_JsException_js_error_getter"]=wasmExports["JsException_js_error_getter"];var _process_throw_args=Module["_process_throw_args"]=wasmExports["process_throw_args"];var _PyErr_NormalizeException=Module["_PyErr_NormalizeException"]=wasmExports["PyErr_NormalizeException"];var _PyException_GetTraceback=Module["_PyException_GetTraceback"]=wasmExports["PyException_GetTraceback"];var _PyException_SetTraceback=Module["_PyException_SetTraceback"]=wasmExports["PyException_SetTraceback"];var _PyErr_Restore=Module["_PyErr_Restore"]=wasmExports["PyErr_Restore"];var _PyErr_ExceptionMatches=Module["_PyErr_ExceptionMatches"]=wasmExports["PyErr_ExceptionMatches"];var _PyErr_Clear=Module["_PyErr_Clear"]=wasmExports["PyErr_Clear"];var _JsvObject_CallMethodId_NoArgs=Module["_JsvObject_CallMethodId_NoArgs"]=wasmExports["JsvObject_CallMethodId_NoArgs"];var _PyErr_Fetch=Module["_PyErr_Fetch"]=wasmExports["PyErr_Fetch"];var __agen_handle_result_js_c=Module["__agen_handle_result_js_c"]=wasmExports["_agen_handle_result_js_c"];var _PyObject_CallOneArg=Module["_PyObject_CallOneArg"]=wasmExports["PyObject_CallOneArg"];var __agen_handle_result=Module["__agen_handle_result"]=wasmExports["_agen_handle_result"];var _JsArray_sq_item=Module["_JsArray_sq_item"]=wasmExports["JsArray_sq_item"];var _JsArray_sq_ass_item=Module["_JsArray_sq_ass_item"]=wasmExports["JsArray_sq_ass_item"];var _JsTypedArray_sq_ass_item=Module["_JsTypedArray_sq_ass_item"]=wasmExports["JsTypedArray_sq_ass_item"];var _JsMap_update=Module["_JsMap_update"]=wasmExports["JsMap_update"];var _wrap_promise=Module["_wrap_promise"]=wasmExports["wrap_promise"];var _PyTuple_GetItem=Module["_PyTuple_GetItem"]=wasmExports["PyTuple_GetItem"];var _JsvObject_CallMethodId=Module["_JsvObject_CallMethodId"]=wasmExports["JsvObject_CallMethodId"];var _JsModule_GetAll=Module["_JsModule_GetAll"]=wasmExports["JsModule_GetAll"];var _PyType_IsSubtype=Module["_PyType_IsSubtype"]=wasmExports["PyType_IsSubtype"];var _JsProxy_Check=Module["_JsProxy_Check"]=wasmExports["JsProxy_Check"];var _JsBuffer_CopyIntoMemoryView=Module["_JsBuffer_CopyIntoMemoryView"]=wasmExports["JsBuffer_CopyIntoMemoryView"];var _PyMem_Malloc=Module["_PyMem_Malloc"]=wasmExports["PyMem_Malloc"];var _PyMemoryView_FromObject=Module["_PyMemoryView_FromObject"]=wasmExports["PyMemoryView_FromObject"];var _JsBuffer_cinit=Module["_JsBuffer_cinit"]=wasmExports["JsBuffer_cinit"];var _hiwire_new_deduplicate=Module["_hiwire_new_deduplicate"]=wasmExports["hiwire_new_deduplicate"];var _JsRef_new=Module["_JsRef_new"]=wasmExports["JsRef_new"];var _PyTuple_Pack=Module["_PyTuple_Pack"]=wasmExports["PyTuple_Pack"];var _PyLong_FromLong=Module["_PyLong_FromLong"]=wasmExports["PyLong_FromLong"];var _PyDict_GetItemWithError=Module["_PyDict_GetItemWithError"]=wasmExports["PyDict_GetItemWithError"];var _PyObject_SelfIter=Module["_PyObject_SelfIter"]=wasmExports["PyObject_SelfIter"];var _PyVectorcall_Call=Module["_PyVectorcall_Call"]=wasmExports["PyVectorcall_Call"];var _PyErr_NoMemory=Module["_PyErr_NoMemory"]=wasmExports["PyErr_NoMemory"];var _PyType_FromSpecWithBases=Module["_PyType_FromSpecWithBases"]=wasmExports["PyType_FromSpecWithBases"];var _PyObject_SetAttr=Module["_PyObject_SetAttr"]=wasmExports["PyObject_SetAttr"];var _PyMem_Free=Module["_PyMem_Free"]=wasmExports["PyMem_Free"];var _PyDict_SetItem=Module["_PyDict_SetItem"]=wasmExports["PyDict_SetItem"];var _JsProxy_create=Module["_JsProxy_create"]=wasmExports["JsProxy_create"];var _JsProxy_init_docstrings=Module["_JsProxy_init_docstrings"]=wasmExports["JsProxy_init_docstrings"];var _run_sync_not_supported=Module["_run_sync_not_supported"]=wasmExports["run_sync_not_supported"];var _run_sync=Module["_run_sync"]=wasmExports["run_sync"];var _py_is_awaitable=Module["_py_is_awaitable"]=wasmExports["py_is_awaitable"];var _JsvPromise_Syncify=Module["_JsvPromise_Syncify"]=wasmExports["JsvPromise_Syncify"];var _can_run_sync=Module["_can_run_sync"]=wasmExports["can_run_sync"];var _PyDict_New=Module["_PyDict_New"]=wasmExports["PyDict_New"];var _PyObject_SetAttrString=Module["_PyObject_SetAttrString"]=wasmExports["PyObject_SetAttrString"];var _PyModule_AddObject=Module["_PyModule_AddObject"]=wasmExports["PyModule_AddObject"];var _PyType_Ready=Module["_PyType_Ready"]=wasmExports["PyType_Ready"];var _JsMethod_Vectorcall_impl=Module["_JsMethod_Vectorcall_impl"]=wasmExports["JsMethod_Vectorcall_impl"];var _JsvObject_CallMethodId_TwoArgs=Module["_JsvObject_CallMethodId_TwoArgs"]=wasmExports["JsvObject_CallMethodId_TwoArgs"];var _PyObject_Repr=Module["_PyObject_Repr"]=wasmExports["PyObject_Repr"];var _PyIndex_Check=Module["_PyIndex_Check"]=wasmExports["PyIndex_Check"];var _PyNumber_AsSsize_t=Module["_PyNumber_AsSsize_t"]=wasmExports["PyNumber_AsSsize_t"];var _PySlice_Unpack=Module["_PySlice_Unpack"]=wasmExports["PySlice_Unpack"];var _PySlice_AdjustIndices=Module["_PySlice_AdjustIndices"]=wasmExports["PySlice_AdjustIndices"];var _PySequence_Fast=Module["_PySequence_Fast"]=wasmExports["PySequence_Fast"];var _PyArg_ParseTupleAndKeywords=Module["_PyArg_ParseTupleAndKeywords"]=wasmExports["PyArg_ParseTupleAndKeywords"];var _PySet_New=Module["_PySet_New"]=wasmExports["PySet_New"];var __PySet_Update=Module["__PySet_Update"]=wasmExports["_PySet_Update"];var _PyUnicode_FromString=Module["_PyUnicode_FromString"]=wasmExports["PyUnicode_FromString"];var _PySet_Discard=Module["_PySet_Discard"]=wasmExports["PySet_Discard"];var _PyList_New=Module["_PyList_New"]=wasmExports["PyList_New"];var _PyList_Extend=Module["_PyList_Extend"]=wasmExports["PyList_Extend"];var _PyList_Sort=Module["_PyList_Sort"]=wasmExports["PyList_Sort"];var __PyArg_ParseStack=Module["__PyArg_ParseStack"]=wasmExports["_PyArg_ParseStack"];var _PyObject_GetIter=Module["_PyObject_GetIter"]=wasmExports["PyObject_GetIter"];var _PyObject_RichCompareBool=Module["_PyObject_RichCompareBool"]=wasmExports["PyObject_RichCompareBool"];var _PyErr_WarnEx=Module["_PyErr_WarnEx"]=wasmExports["PyErr_WarnEx"];var __PyArg_ParseStackAndKeywords=Module["__PyArg_ParseStackAndKeywords"]=wasmExports["_PyArg_ParseStackAndKeywords"];var _hiwire_pop=Module["_hiwire_pop"]=wasmExports["hiwire_pop"];var _puts=Module["_puts"]=wasmExports["puts"];var _PyObject_GenericSetAttr=Module["_PyObject_GenericSetAttr"]=wasmExports["PyObject_GenericSetAttr"];var __Py_HashBytes=Module["__Py_HashBytes"]=wasmExports["_Py_HashBytes"];var _JsMethod_Construct_impl=Module["_JsMethod_Construct_impl"]=wasmExports["JsMethod_Construct_impl"];var __PyArg_CheckPositional=Module["__PyArg_CheckPositional"]=wasmExports["_PyArg_CheckPositional"];var _PyNumber_Index=Module["_PyNumber_Index"]=wasmExports["PyNumber_Index"];var _PyLong_AsSsize_t=Module["_PyLong_AsSsize_t"]=wasmExports["PyLong_AsSsize_t"];var _PyLong_FromSsize_t=Module["_PyLong_FromSsize_t"]=wasmExports["PyLong_FromSsize_t"];var _PyObject_GetItem=Module["_PyObject_GetItem"]=wasmExports["PyObject_GetItem"];var _PyObject_DelItem=Module["_PyObject_DelItem"]=wasmExports["PyObject_DelItem"];var _PyObject_SetItem=Module["_PyObject_SetItem"]=wasmExports["PyObject_SetItem"];var _PyObject_GetBuffer=Module["_PyObject_GetBuffer"]=wasmExports["PyObject_GetBuffer"];var _PyBuffer_Release=Module["_PyBuffer_Release"]=wasmExports["PyBuffer_Release"];var _PyBytes_FromStringAndSize=Module["_PyBytes_FromStringAndSize"]=wasmExports["PyBytes_FromStringAndSize"];var _PyObject_Vectorcall=Module["_PyObject_Vectorcall"]=wasmExports["PyObject_Vectorcall"];var _Py_EnterRecursiveCall=Module["_Py_EnterRecursiveCall"]=wasmExports["Py_EnterRecursiveCall"];var _Py_LeaveRecursiveCall=Module["_Py_LeaveRecursiveCall"]=wasmExports["Py_LeaveRecursiveCall"];var _Py2JsConverter_convert=Module["_Py2JsConverter_convert"]=wasmExports["Py2JsConverter_convert"];var _PyUnicode_FromFormat=Module["_PyUnicode_FromFormat"]=wasmExports["PyUnicode_FromFormat"];var _PyType_GenericNew=Module["_PyType_GenericNew"]=wasmExports["PyType_GenericNew"];var _PyObject_IsInstance=Module["_PyObject_IsInstance"]=wasmExports["PyObject_IsInstance"];var _python2js_inner=Module["_python2js_inner"]=wasmExports["python2js_inner"];var _python2js_custom=Module["_python2js_custom"]=wasmExports["python2js_custom"];var _PyObject_GC_UnTrack=Module["_PyObject_GC_UnTrack"]=wasmExports["PyObject_GC_UnTrack"];var _check_gil=Module["_check_gil"]=wasmExports["check_gil"];var _PyGILState_Check=Module["_PyGILState_Check"]=wasmExports["PyGILState_Check"];var _PyGen_GetCode=Module["_PyGen_GetCode"]=wasmExports["PyGen_GetCode"];var _pyproxy_getflags=Module["_pyproxy_getflags"]=wasmExports["pyproxy_getflags"];var _PyObject_HasAttr=Module["_PyObject_HasAttr"]=wasmExports["PyObject_HasAttr"];var _PyObject_IsSubclass=Module["_PyObject_IsSubclass"]=wasmExports["PyObject_IsSubclass"];var __pyproxy_repr=Module["__pyproxy_repr"]=wasmExports["_pyproxy_repr"];var _PyObject_Str=Module["_PyObject_Str"]=wasmExports["PyObject_Str"];var __pyproxy_type=Module["__pyproxy_type"]=wasmExports["_pyproxy_type"];var __pyproxy_hasattr=Module["__pyproxy_hasattr"]=wasmExports["_pyproxy_hasattr"];var _python2js_json_adaptor=Module["_python2js_json_adaptor"]=wasmExports["python2js_json_adaptor"];var __pyproxy_getattr=Module["__pyproxy_getattr"]=wasmExports["_pyproxy_getattr"];var __PyObject_GetMethod=Module["__PyObject_GetMethod"]=wasmExports["_PyObject_GetMethod"];var __pyproxy_setattr=Module["__pyproxy_setattr"]=wasmExports["_pyproxy_setattr"];var __pyproxy_delattr=Module["__pyproxy_delattr"]=wasmExports["_pyproxy_delattr"];var _PyObject_DelAttr=Module["_PyObject_DelAttr"]=wasmExports["PyObject_DelAttr"];var __pyproxy_getitem=Module["__pyproxy_getitem"]=wasmExports["_pyproxy_getitem"];var __pyproxy_setitem=Module["__pyproxy_setitem"]=wasmExports["_pyproxy_setitem"];var __pyproxy_delitem=Module["__pyproxy_delitem"]=wasmExports["_pyproxy_delitem"];var __pyproxy_slice_assign=Module["__pyproxy_slice_assign"]=wasmExports["_pyproxy_slice_assign"];var _PySequence_Size=Module["_PySequence_Size"]=wasmExports["PySequence_Size"];var _PySequence_GetSlice=Module["_PySequence_GetSlice"]=wasmExports["PySequence_GetSlice"];var _PySequence_SetSlice=Module["_PySequence_SetSlice"]=wasmExports["PySequence_SetSlice"];var _python2js_with_depth=Module["_python2js_with_depth"]=wasmExports["python2js_with_depth"];var __pyproxy_pop=Module["__pyproxy_pop"]=wasmExports["_pyproxy_pop"];var __pyproxy_contains=Module["__pyproxy_contains"]=wasmExports["_pyproxy_contains"];var _PySequence_Contains=Module["_PySequence_Contains"]=wasmExports["PySequence_Contains"];var __pyproxy_ownKeys=Module["__pyproxy_ownKeys"]=wasmExports["_pyproxy_ownKeys"];var _PyObject_Dir=Module["_PyObject_Dir"]=wasmExports["PyObject_Dir"];var _PyList_Size=Module["_PyList_Size"]=wasmExports["PyList_Size"];var _PyList_GetItem=Module["_PyList_GetItem"]=wasmExports["PyList_GetItem"];var __pyproxy_apply=Module["__pyproxy_apply"]=wasmExports["_pyproxy_apply"];var _PyTuple_New=Module["_PyTuple_New"]=wasmExports["PyTuple_New"];var __pyproxy_apply_promising=Module["__pyproxy_apply_promising"]=wasmExports["_pyproxy_apply_promising"];var __iscoroutinefunction=Module["__iscoroutinefunction"]=wasmExports["_iscoroutinefunction"];var __pyproxy_iter_next=Module["__pyproxy_iter_next"]=wasmExports["_pyproxy_iter_next"];var _PyIter_Next=Module["_PyIter_Next"]=wasmExports["PyIter_Next"];var __pyproxyGen_Send=Module["__pyproxyGen_Send"]=wasmExports["_pyproxyGen_Send"];var _PyIter_Send=Module["_PyIter_Send"]=wasmExports["PyIter_Send"];var __pyproxyGen_return=Module["__pyproxyGen_return"]=wasmExports["_pyproxyGen_return"];var __PyGen_FetchStopIterationValue=Module["__PyGen_FetchStopIterationValue"]=wasmExports["_PyGen_FetchStopIterationValue"];var __pyproxyGen_throw=Module["__pyproxyGen_throw"]=wasmExports["_pyproxyGen_throw"];var __pyproxyGen_asend=Module["__pyproxyGen_asend"]=wasmExports["_pyproxyGen_asend"];var __pyproxyGen_areturn=Module["__pyproxyGen_areturn"]=wasmExports["_pyproxyGen_areturn"];var __pyproxyGen_athrow=Module["__pyproxyGen_athrow"]=wasmExports["_pyproxyGen_athrow"];var __pyproxy_aiter_next=Module["__pyproxy_aiter_next"]=wasmExports["_pyproxy_aiter_next"];var _FutureDoneCallback_call_resolve=Module["_FutureDoneCallback_call_resolve"]=wasmExports["FutureDoneCallback_call_resolve"];var _FutureDoneCallback_call_reject=Module["_FutureDoneCallback_call_reject"]=wasmExports["FutureDoneCallback_call_reject"];var _FutureDoneCallback_call=Module["_FutureDoneCallback_call"]=wasmExports["FutureDoneCallback_call"];var _PyArg_UnpackTuple=Module["_PyArg_UnpackTuple"]=wasmExports["PyArg_UnpackTuple"];var __pyproxy_ensure_future=Module["__pyproxy_ensure_future"]=wasmExports["_pyproxy_ensure_future"];var __pyproxy_get_buffer=Module["__pyproxy_get_buffer"]=wasmExports["_pyproxy_get_buffer"];var _PyBuffer_FillContiguousStrides=Module["_PyBuffer_FillContiguousStrides"]=wasmExports["PyBuffer_FillContiguousStrides"];var _PyBuffer_IsContiguous=Module["_PyBuffer_IsContiguous"]=wasmExports["PyBuffer_IsContiguous"];var _create_promise_handles_result_helper=Module["_create_promise_handles_result_helper"]=wasmExports["create_promise_handles_result_helper"];var __python2js_buffer=Module["__python2js_buffer"]=wasmExports["_python2js_buffer"];var _Jsv_GetNull=Module["_Jsv_GetNull"]=wasmExports["Jsv_GetNull"];var _jslib_init_buffers=Module["_jslib_init_buffers"]=wasmExports["jslib_init_buffers"];var _JsRef_pop=Module["_JsRef_pop"]=wasmExports["JsRef_pop"];var _JsrString_FromId=Module["_JsrString_FromId"]=wasmExports["JsrString_FromId"];var _hiwire_intern=Module["_hiwire_intern"]=wasmExports["hiwire_intern"];var __python2js=Module["__python2js"]=wasmExports["_python2js"];var _PySequence_GetItem=Module["_PySequence_GetItem"]=wasmExports["PySequence_GetItem"];var _PyObject_CheckBuffer=Module["_PyObject_CheckBuffer"]=wasmExports["PyObject_CheckBuffer"];var _PyFloat_AsDouble=Module["_PyFloat_AsDouble"]=wasmExports["PyFloat_AsDouble"];var _python2js__default_converter=Module["_python2js__default_converter"]=wasmExports["python2js__default_converter"];var _python2js__eager_converter=Module["_python2js__eager_converter"]=wasmExports["python2js__eager_converter"];var _PyLong_AsLongAndOverflow=Module["_PyLong_AsLongAndOverflow"]=wasmExports["PyLong_AsLongAndOverflow"];var __PyLong_NumBits=Module["__PyLong_NumBits"]=wasmExports["_PyLong_NumBits"];var __PyLong_AsByteArray=Module["__PyLong_AsByteArray"]=wasmExports["_PyLong_AsByteArray"];var _saveAsyncioState=Module["_saveAsyncioState"]=wasmExports["saveAsyncioState"];var _PyObject_Hash=Module["_PyObject_Hash"]=wasmExports["PyObject_Hash"];var __PyDict_GetItem_KnownHash=Module["__PyDict_GetItem_KnownHash"]=wasmExports["_PyDict_GetItem_KnownHash"];var _restoreAsyncioState=Module["_restoreAsyncioState"]=wasmExports["restoreAsyncioState"];var _captureThreadState=Module["_captureThreadState"]=wasmExports["captureThreadState"];var _PyInterpreterState_Get=Module["_PyInterpreterState_Get"]=wasmExports["PyInterpreterState_Get"];var _PyThreadState_New=Module["_PyThreadState_New"]=wasmExports["PyThreadState_New"];var _PyThreadState_Swap=Module["_PyThreadState_Swap"]=wasmExports["PyThreadState_Swap"];var _restoreThreadState=Module["_restoreThreadState"]=wasmExports["restoreThreadState"];var _PyThreadState_Delete=Module["_PyThreadState_Delete"]=wasmExports["PyThreadState_Delete"];var _print_stdout=Module["_print_stdout"]=wasmExports["print_stdout"];var _fiprintf=Module["_fiprintf"]=wasmExports["fiprintf"];var _print_stderr=Module["_print_stderr"]=wasmExports["print_stderr"];var _main=Module["_main"]=wasmExports["__main_argc_argv"];var _PyImport_AppendInittab=Module["_PyImport_AppendInittab"]=wasmExports["PyImport_AppendInittab"];var _PyPreConfig_InitPythonConfig=Module["_PyPreConfig_InitPythonConfig"]=wasmExports["PyPreConfig_InitPythonConfig"];var _Py_PreInitializeFromBytesArgs=Module["_Py_PreInitializeFromBytesArgs"]=wasmExports["Py_PreInitializeFromBytesArgs"];var _PyStatus_Exception=Module["_PyStatus_Exception"]=wasmExports["PyStatus_Exception"];var _PyConfig_InitPythonConfig=Module["_PyConfig_InitPythonConfig"]=wasmExports["PyConfig_InitPythonConfig"];var _PyConfig_SetBytesArgv=Module["_PyConfig_SetBytesArgv"]=wasmExports["PyConfig_SetBytesArgv"];var _PyConfig_SetBytesString=Module["_PyConfig_SetBytesString"]=wasmExports["PyConfig_SetBytesString"];var _Py_InitializeFromConfig=Module["_Py_InitializeFromConfig"]=wasmExports["Py_InitializeFromConfig"];var _PyConfig_Clear=Module["_PyConfig_Clear"]=wasmExports["PyConfig_Clear"];var _Py_ExitStatusException=Module["_Py_ExitStatusException"]=wasmExports["Py_ExitStatusException"];var _run_main=Module["_run_main"]=wasmExports["run_main"];var _run_main_promising=Module["_run_main_promising"]=wasmExports["run_main_promising"];var _Py_GetBuildInfo=Module["_Py_GetBuildInfo"]=wasmExports["Py_GetBuildInfo"];var _PyOS_snprintf=Module["_PyOS_snprintf"]=wasmExports["PyOS_snprintf"];var __PyToken_OneChar=Module["__PyToken_OneChar"]=wasmExports["_PyToken_OneChar"];var __PyToken_TwoChars=Module["__PyToken_TwoChars"]=wasmExports["_PyToken_TwoChars"];var __PyToken_ThreeChars=Module["__PyToken_ThreeChars"]=wasmExports["_PyToken_ThreeChars"];var _strlen=Module["_strlen"]=wasmExports["strlen"];var _PyUnicode_DecodeUTF8=Module["_PyUnicode_DecodeUTF8"]=wasmExports["PyUnicode_DecodeUTF8"];var __PyArena_Malloc=Module["__PyArena_Malloc"]=wasmExports["_PyArena_Malloc"];var _strncpy=Module["_strncpy"]=wasmExports["strncpy"];var _PyMem_Realloc=Module["_PyMem_Realloc"]=wasmExports["PyMem_Realloc"];var _PyMem_Calloc=Module["_PyMem_Calloc"]=wasmExports["PyMem_Calloc"];var _strncmp=Module["_strncmp"]=wasmExports["strncmp"];var __PyArena_AddPyObject=Module["__PyArena_AddPyObject"]=wasmExports["_PyArena_AddPyObject"];var _PyBytes_AsString=Module["_PyBytes_AsString"]=wasmExports["PyBytes_AsString"];var __PyImport_GetModuleAttrString=Module["__PyImport_GetModuleAttrString"]=wasmExports["_PyImport_GetModuleAttrString"];var _PyUnicode_InternFromString=Module["_PyUnicode_InternFromString"]=wasmExports["PyUnicode_InternFromString"];var __PyType_Name=Module["__PyType_Name"]=wasmExports["_PyType_Name"];var __PyUnicode_InternImmortal=Module["__PyUnicode_InternImmortal"]=wasmExports["_PyUnicode_InternImmortal"];var _PyBytes_AsStringAndSize=Module["_PyBytes_AsStringAndSize"]=wasmExports["PyBytes_AsStringAndSize"];var _strchr=Module["_strchr"]=wasmExports["strchr"];var _PyUnicode_CompareWithASCIIString=Module["_PyUnicode_CompareWithASCIIString"]=wasmExports["PyUnicode_CompareWithASCIIString"];var ___errno_location=Module["___errno_location"]=wasmExports["__errno_location"];var _PyOS_strtoul=Module["_PyOS_strtoul"]=wasmExports["PyOS_strtoul"];var _PyLong_FromString=Module["_PyLong_FromString"]=wasmExports["PyLong_FromString"];var _PyOS_strtol=Module["_PyOS_strtol"]=wasmExports["PyOS_strtol"];var _PyOS_string_to_double=Module["_PyOS_string_to_double"]=wasmExports["PyOS_string_to_double"];var _PyComplex_FromCComplex=Module["_PyComplex_FromCComplex"]=wasmExports["PyComplex_FromCComplex"];var _PyFloat_FromDouble=Module["_PyFloat_FromDouble"]=wasmExports["PyFloat_FromDouble"];var _Py_BuildValue=Module["_Py_BuildValue"]=wasmExports["Py_BuildValue"];var _PyUnicode_FromFormatV=Module["_PyUnicode_FromFormatV"]=wasmExports["PyUnicode_FromFormatV"];var __PyErr_ProgramDecodedTextObject=Module["__PyErr_ProgramDecodedTextObject"]=wasmExports["_PyErr_ProgramDecodedTextObject"];var _PyUnicode_FromStringAndSize=Module["_PyUnicode_FromStringAndSize"]=wasmExports["PyUnicode_FromStringAndSize"];var _PyBytes_FromString=Module["_PyBytes_FromString"]=wasmExports["PyBytes_FromString"];var _PyBytes_Concat=Module["_PyBytes_Concat"]=wasmExports["PyBytes_Concat"];var __PyUnicodeWriter_Init=Module["__PyUnicodeWriter_Init"]=wasmExports["_PyUnicodeWriter_Init"];var __PyUnicodeWriter_WriteStr=Module["__PyUnicodeWriter_WriteStr"]=wasmExports["_PyUnicodeWriter_WriteStr"];var __PyUnicodeWriter_Dealloc=Module["__PyUnicodeWriter_Dealloc"]=wasmExports["_PyUnicodeWriter_Dealloc"];var __PyUnicodeWriter_Finish=Module["__PyUnicodeWriter_Finish"]=wasmExports["_PyUnicodeWriter_Finish"];var _strpbrk=Module["_strpbrk"]=wasmExports["strpbrk"];var _PyUnicode_DecodeUTF8Stateful=Module["_PyUnicode_DecodeUTF8Stateful"]=wasmExports["PyUnicode_DecodeUTF8Stateful"];var _siprintf=Module["_siprintf"]=wasmExports["siprintf"];var __PyUnicode_DecodeUnicodeEscapeInternal=Module["__PyUnicode_DecodeUnicodeEscapeInternal"]=wasmExports["_PyUnicode_DecodeUnicodeEscapeInternal"];var __PyErr_BadInternalCall=Module["__PyErr_BadInternalCall"]=wasmExports["_PyErr_BadInternalCall"];var __PyBytes_DecodeEscape=Module["__PyBytes_DecodeEscape"]=wasmExports["_PyBytes_DecodeEscape"];var _PyErr_WarnExplicitObject=Module["_PyErr_WarnExplicitObject"]=wasmExports["PyErr_WarnExplicitObject"];var _PySys_Audit=Module["_PySys_Audit"]=wasmExports["PySys_Audit"];var _memchr=Module["_memchr"]=wasmExports["memchr"];var __Py_FatalErrorFunc=Module["__Py_FatalErrorFunc"]=wasmExports["_Py_FatalErrorFunc"];var _memcmp=Module["_memcmp"]=wasmExports["memcmp"];var __PyUnicode_ScanIdentifier=Module["__PyUnicode_ScanIdentifier"]=wasmExports["_PyUnicode_ScanIdentifier"];var _PyUnicode_Substring=Module["_PyUnicode_Substring"]=wasmExports["PyUnicode_Substring"];var _PyUnicode_AsUTF8String=Module["_PyUnicode_AsUTF8String"]=wasmExports["PyUnicode_AsUTF8String"];var __PyUnicode_IsPrintable=Module["__PyUnicode_IsPrintable"]=wasmExports["_PyUnicode_IsPrintable"];var _PyOS_Readline=Module["_PyOS_Readline"]=wasmExports["PyOS_Readline"];var _strcpy=Module["_strcpy"]=wasmExports["strcpy"];var _PyObject_CallNoArgs=Module["_PyObject_CallNoArgs"]=wasmExports["PyObject_CallNoArgs"];var __Py_UniversalNewlineFgetsWithSize=Module["__Py_UniversalNewlineFgetsWithSize"]=wasmExports["_Py_UniversalNewlineFgetsWithSize"];var _fopencookie=Module["_fopencookie"]=wasmExports["fopencookie"];var _fclose=Module["_fclose"]=wasmExports["fclose"];var _getc=Module["_getc"]=wasmExports["getc"];var _ungetc=Module["_ungetc"]=wasmExports["ungetc"];var _ftell=Module["_ftell"]=wasmExports["ftell"];var _lseek=Module["_lseek"]=wasmExports["lseek"];var _PyErr_SetFromErrnoWithFilename=Module["_PyErr_SetFromErrnoWithFilename"]=wasmExports["PyErr_SetFromErrnoWithFilename"];var _PyObject_CallFunction=Module["_PyObject_CallFunction"]=wasmExports["PyObject_CallFunction"];var _PyObject_GetAttr=Module["_PyObject_GetAttr"]=wasmExports["PyObject_GetAttr"];var __PyObject_MakeTpCall=Module["__PyObject_MakeTpCall"]=wasmExports["_PyObject_MakeTpCall"];var __Py_CheckFunctionResult=Module["__Py_CheckFunctionResult"]=wasmExports["_Py_CheckFunctionResult"];var _read=Module["_read"]=wasmExports["read"];var _PyUnicode_Decode=Module["_PyUnicode_Decode"]=wasmExports["PyUnicode_Decode"];var _strcspn=Module["_strcspn"]=wasmExports["strcspn"];var _fflush=wasmExports["fflush"];var _fputs=Module["_fputs"]=wasmExports["fputs"];var _PyMem_RawFree=Module["_PyMem_RawFree"]=wasmExports["PyMem_RawFree"];var _PyEval_RestoreThread=Module["_PyEval_RestoreThread"]=wasmExports["PyEval_RestoreThread"];var _PyEval_SaveThread=Module["_PyEval_SaveThread"]=wasmExports["PyEval_SaveThread"];var _PyMem_RawRealloc=Module["_PyMem_RawRealloc"]=wasmExports["PyMem_RawRealloc"];var _clearerr=Module["_clearerr"]=wasmExports["clearerr"];var _fgets=Module["_fgets"]=wasmExports["fgets"];var _feof=Module["_feof"]=wasmExports["feof"];var _PyErr_CheckSignals=Module["_PyErr_CheckSignals"]=wasmExports["PyErr_CheckSignals"];var _PyMutex_Lock=Module["_PyMutex_Lock"]=wasmExports["PyMutex_Lock"];var _isatty=Module["_isatty"]=wasmExports["isatty"];var _PyMutex_Unlock=Module["_PyMutex_Unlock"]=wasmExports["PyMutex_Unlock"];var _PyObject_Type=Module["_PyObject_Type"]=wasmExports["PyObject_Type"];var __PyErr_SetString=Module["__PyErr_SetString"]=wasmExports["_PyErr_SetString"];var _PyObject_Size=Module["_PyObject_Size"]=wasmExports["PyObject_Size"];var _PyMapping_Size=Module["_PyMapping_Size"]=wasmExports["PyMapping_Size"];var _PyObject_Length=Module["_PyObject_Length"]=wasmExports["PyObject_Length"];var _PyObject_LengthHint=Module["_PyObject_LengthHint"]=wasmExports["PyObject_LengthHint"];var __PyErr_ExceptionMatches=Module["__PyErr_ExceptionMatches"]=wasmExports["_PyErr_ExceptionMatches"];var __PyErr_Clear=Module["__PyErr_Clear"]=wasmExports["_PyErr_Clear"];var __PyObject_LookupSpecial=Module["__PyObject_LookupSpecial"]=wasmExports["_PyObject_LookupSpecial"];var _Py_GenericAlias=Module["_Py_GenericAlias"]=wasmExports["Py_GenericAlias"];var _PyObject_GetOptionalAttr=Module["_PyObject_GetOptionalAttr"]=wasmExports["PyObject_GetOptionalAttr"];var __PyNumber_Index=Module["__PyNumber_Index"]=wasmExports["_PyNumber_Index"];var __PyErr_Format=Module["__PyErr_Format"]=wasmExports["_PyErr_Format"];var _PyMapping_GetOptionalItem=Module["_PyMapping_GetOptionalItem"]=wasmExports["PyMapping_GetOptionalItem"];var _PyDict_GetItemRef=Module["_PyDict_GetItemRef"]=wasmExports["PyDict_GetItemRef"];var _PySequence_SetItem=Module["_PySequence_SetItem"]=wasmExports["PySequence_SetItem"];var _PySequence_DelItem=Module["_PySequence_DelItem"]=wasmExports["PySequence_DelItem"];var _PyObject_DelItemString=Module["_PyObject_DelItemString"]=wasmExports["PyObject_DelItemString"];var _PyObject_CheckReadBuffer=Module["_PyObject_CheckReadBuffer"]=wasmExports["PyObject_CheckReadBuffer"];var _PyObject_AsCharBuffer=Module["_PyObject_AsCharBuffer"]=wasmExports["PyObject_AsCharBuffer"];var _PyObject_AsReadBuffer=Module["_PyObject_AsReadBuffer"]=wasmExports["PyObject_AsReadBuffer"];var _PyObject_AsWriteBuffer=Module["_PyObject_AsWriteBuffer"]=wasmExports["PyObject_AsWriteBuffer"];var _PyBuffer_GetPointer=Module["_PyBuffer_GetPointer"]=wasmExports["PyBuffer_GetPointer"];var _PyBuffer_SizeFromFormat=Module["_PyBuffer_SizeFromFormat"]=wasmExports["PyBuffer_SizeFromFormat"];var _PyObject_CallFunctionObjArgs=Module["_PyObject_CallFunctionObjArgs"]=wasmExports["PyObject_CallFunctionObjArgs"];var _PyBuffer_FromContiguous=Module["_PyBuffer_FromContiguous"]=wasmExports["PyBuffer_FromContiguous"];var _PyObject_CopyData=Module["_PyObject_CopyData"]=wasmExports["PyObject_CopyData"];var _PyBuffer_FillInfo=Module["_PyBuffer_FillInfo"]=wasmExports["PyBuffer_FillInfo"];var __PyBuffer_ReleaseInInterpreter=Module["__PyBuffer_ReleaseInInterpreter"]=wasmExports["_PyBuffer_ReleaseInInterpreter"];var __PyBuffer_ReleaseInInterpreterAndRawFree=Module["__PyBuffer_ReleaseInInterpreterAndRawFree"]=wasmExports["_PyBuffer_ReleaseInInterpreterAndRawFree"];var _PyObject_Format=Module["_PyObject_Format"]=wasmExports["PyObject_Format"];var _PyUnicode_New=Module["_PyUnicode_New"]=wasmExports["PyUnicode_New"];var _PyNumber_Check=Module["_PyNumber_Check"]=wasmExports["PyNumber_Check"];var _PyNumber_Or=Module["_PyNumber_Or"]=wasmExports["PyNumber_Or"];var _PyNumber_Xor=Module["_PyNumber_Xor"]=wasmExports["PyNumber_Xor"];var _PyNumber_And=Module["_PyNumber_And"]=wasmExports["PyNumber_And"];var _PyNumber_Lshift=Module["_PyNumber_Lshift"]=wasmExports["PyNumber_Lshift"];var _PyNumber_Rshift=Module["_PyNumber_Rshift"]=wasmExports["PyNumber_Rshift"];var _PyNumber_Subtract=Module["_PyNumber_Subtract"]=wasmExports["PyNumber_Subtract"];var _PyNumber_Divmod=Module["_PyNumber_Divmod"]=wasmExports["PyNumber_Divmod"];var _PyNumber_Add=Module["_PyNumber_Add"]=wasmExports["PyNumber_Add"];var _PyNumber_Multiply=Module["_PyNumber_Multiply"]=wasmExports["PyNumber_Multiply"];var _PyNumber_MatrixMultiply=Module["_PyNumber_MatrixMultiply"]=wasmExports["PyNumber_MatrixMultiply"];var _PyNumber_FloorDivide=Module["_PyNumber_FloorDivide"]=wasmExports["PyNumber_FloorDivide"];var _PyNumber_TrueDivide=Module["_PyNumber_TrueDivide"]=wasmExports["PyNumber_TrueDivide"];var _PyNumber_Remainder=Module["_PyNumber_Remainder"]=wasmExports["PyNumber_Remainder"];var _PyNumber_Power=Module["_PyNumber_Power"]=wasmExports["PyNumber_Power"];var _PyNumber_InPlaceOr=Module["_PyNumber_InPlaceOr"]=wasmExports["PyNumber_InPlaceOr"];var _PyNumber_InPlaceXor=Module["_PyNumber_InPlaceXor"]=wasmExports["PyNumber_InPlaceXor"];var _PyNumber_InPlaceAnd=Module["_PyNumber_InPlaceAnd"]=wasmExports["PyNumber_InPlaceAnd"];var _PyNumber_InPlaceLshift=Module["_PyNumber_InPlaceLshift"]=wasmExports["PyNumber_InPlaceLshift"];var _PyNumber_InPlaceRshift=Module["_PyNumber_InPlaceRshift"]=wasmExports["PyNumber_InPlaceRshift"];var _PyNumber_InPlaceSubtract=Module["_PyNumber_InPlaceSubtract"]=wasmExports["PyNumber_InPlaceSubtract"];var _PyNumber_InPlaceMatrixMultiply=Module["_PyNumber_InPlaceMatrixMultiply"]=wasmExports["PyNumber_InPlaceMatrixMultiply"];var _PyNumber_InPlaceFloorDivide=Module["_PyNumber_InPlaceFloorDivide"]=wasmExports["PyNumber_InPlaceFloorDivide"];var _PyNumber_InPlaceTrueDivide=Module["_PyNumber_InPlaceTrueDivide"]=wasmExports["PyNumber_InPlaceTrueDivide"];var _PyNumber_InPlaceRemainder=Module["_PyNumber_InPlaceRemainder"]=wasmExports["PyNumber_InPlaceRemainder"];var _PyNumber_InPlaceAdd=Module["_PyNumber_InPlaceAdd"]=wasmExports["PyNumber_InPlaceAdd"];var _PyNumber_InPlaceMultiply=Module["_PyNumber_InPlaceMultiply"]=wasmExports["PyNumber_InPlaceMultiply"];var _PyNumber_InPlacePower=Module["_PyNumber_InPlacePower"]=wasmExports["PyNumber_InPlacePower"];var _PyNumber_Negative=Module["_PyNumber_Negative"]=wasmExports["PyNumber_Negative"];var _PyNumber_Positive=Module["_PyNumber_Positive"]=wasmExports["PyNumber_Positive"];var _PyNumber_Invert=Module["_PyNumber_Invert"]=wasmExports["PyNumber_Invert"];var _PyNumber_Absolute=Module["_PyNumber_Absolute"]=wasmExports["PyNumber_Absolute"];var _PyErr_WarnFormat=Module["_PyErr_WarnFormat"]=wasmExports["PyErr_WarnFormat"];var __PyLong_Copy=Module["__PyLong_Copy"]=wasmExports["_PyLong_Copy"];var _PyNumber_Long=Module["_PyNumber_Long"]=wasmExports["PyNumber_Long"];var _PyLong_FromUnicodeObject=Module["_PyLong_FromUnicodeObject"]=wasmExports["PyLong_FromUnicodeObject"];var _PyNumber_Float=Module["_PyNumber_Float"]=wasmExports["PyNumber_Float"];var _PyLong_AsDouble=Module["_PyLong_AsDouble"]=wasmExports["PyLong_AsDouble"];var _PyFloat_FromString=Module["_PyFloat_FromString"]=wasmExports["PyFloat_FromString"];var _PyNumber_ToBase=Module["_PyNumber_ToBase"]=wasmExports["PyNumber_ToBase"];var __PyLong_Format=Module["__PyLong_Format"]=wasmExports["_PyLong_Format"];var _PySequence_Check=Module["_PySequence_Check"]=wasmExports["PySequence_Check"];var _PySequence_Length=Module["_PySequence_Length"]=wasmExports["PySequence_Length"];var _PySequence_Concat=Module["_PySequence_Concat"]=wasmExports["PySequence_Concat"];var _PySequence_Repeat=Module["_PySequence_Repeat"]=wasmExports["PySequence_Repeat"];var _PySequence_InPlaceConcat=Module["_PySequence_InPlaceConcat"]=wasmExports["PySequence_InPlaceConcat"];var _PySequence_InPlaceRepeat=Module["_PySequence_InPlaceRepeat"]=wasmExports["PySequence_InPlaceRepeat"];var __PySlice_FromIndices=Module["__PySlice_FromIndices"]=wasmExports["_PySlice_FromIndices"];var _PySequence_DelSlice=Module["_PySequence_DelSlice"]=wasmExports["PySequence_DelSlice"];var _PySequence_Tuple=Module["_PySequence_Tuple"]=wasmExports["PySequence_Tuple"];var _PyList_AsTuple=Module["_PyList_AsTuple"]=wasmExports["PyList_AsTuple"];var __PyTuple_Resize=Module["__PyTuple_Resize"]=wasmExports["_PyTuple_Resize"];var _PySeqIter_New=Module["_PySeqIter_New"]=wasmExports["PySeqIter_New"];var _PySequence_List=Module["_PySequence_List"]=wasmExports["PySequence_List"];var __PyList_Extend=Module["__PyList_Extend"]=wasmExports["_PyList_Extend"];var _PySequence_Count=Module["_PySequence_Count"]=wasmExports["PySequence_Count"];var _PySequence_In=Module["_PySequence_In"]=wasmExports["PySequence_In"];var _PySequence_Index=Module["_PySequence_Index"]=wasmExports["PySequence_Index"];var _PyMapping_Check=Module["_PyMapping_Check"]=wasmExports["PyMapping_Check"];var _PyMapping_Length=Module["_PyMapping_Length"]=wasmExports["PyMapping_Length"];var _PyMapping_GetItemString=Module["_PyMapping_GetItemString"]=wasmExports["PyMapping_GetItemString"];var _PyMapping_GetOptionalItemString=Module["_PyMapping_GetOptionalItemString"]=wasmExports["PyMapping_GetOptionalItemString"];var _PyMapping_SetItemString=Module["_PyMapping_SetItemString"]=wasmExports["PyMapping_SetItemString"];var _PyMapping_HasKeyStringWithError=Module["_PyMapping_HasKeyStringWithError"]=wasmExports["PyMapping_HasKeyStringWithError"];var _PyMapping_HasKeyWithError=Module["_PyMapping_HasKeyWithError"]=wasmExports["PyMapping_HasKeyWithError"];var _PyMapping_HasKeyString=Module["_PyMapping_HasKeyString"]=wasmExports["PyMapping_HasKeyString"];var _PyErr_FormatUnraisable=Module["_PyErr_FormatUnraisable"]=wasmExports["PyErr_FormatUnraisable"];var _PyMapping_HasKey=Module["_PyMapping_HasKey"]=wasmExports["PyMapping_HasKey"];var _PyMapping_Keys=Module["_PyMapping_Keys"]=wasmExports["PyMapping_Keys"];var _PyDict_Keys=Module["_PyDict_Keys"]=wasmExports["PyDict_Keys"];var _PyMapping_Items=Module["_PyMapping_Items"]=wasmExports["PyMapping_Items"];var _PyDict_Items=Module["_PyDict_Items"]=wasmExports["PyDict_Items"];var _PyMapping_Values=Module["_PyMapping_Values"]=wasmExports["PyMapping_Values"];var _PyDict_Values=Module["_PyDict_Values"]=wasmExports["PyDict_Values"];var __Py_CheckRecursiveCall=Module["__Py_CheckRecursiveCall"]=wasmExports["_Py_CheckRecursiveCall"];var _PyObject_IsTrue=Module["_PyObject_IsTrue"]=wasmExports["PyObject_IsTrue"];var _PyIter_Check=Module["_PyIter_Check"]=wasmExports["PyIter_Check"];var _PyObject_GetAIter=Module["_PyObject_GetAIter"]=wasmExports["PyObject_GetAIter"];var _PyAIter_Check=Module["_PyAIter_Check"]=wasmExports["PyAIter_Check"];var _PyBool_FromLong=Module["_PyBool_FromLong"]=wasmExports["PyBool_FromLong"];var __PyArg_NoKeywords=Module["__PyArg_NoKeywords"]=wasmExports["_PyArg_NoKeywords"];var _memrchr=Module["_memrchr"]=wasmExports["memrchr"];var _PyByteArray_FromObject=Module["_PyByteArray_FromObject"]=wasmExports["PyByteArray_FromObject"];var _PyByteArray_FromStringAndSize=Module["_PyByteArray_FromStringAndSize"]=wasmExports["PyByteArray_FromStringAndSize"];var __PyObject_New=Module["__PyObject_New"]=wasmExports["_PyObject_New"];var _PyByteArray_Size=Module["_PyByteArray_Size"]=wasmExports["PyByteArray_Size"];var _PyByteArray_AsString=Module["_PyByteArray_AsString"]=wasmExports["PyByteArray_AsString"];var _PyByteArray_Resize=Module["_PyByteArray_Resize"]=wasmExports["PyByteArray_Resize"];var _PyByteArray_Concat=Module["_PyByteArray_Concat"]=wasmExports["PyByteArray_Concat"];var __Py_GetConfig=Module["__Py_GetConfig"]=wasmExports["_Py_GetConfig"];var __PyObject_GC_New=Module["__PyObject_GC_New"]=wasmExports["_PyObject_GC_New"];var __PyArg_UnpackKeywords=Module["__PyArg_UnpackKeywords"]=wasmExports["_PyArg_UnpackKeywords"];var __PyArg_BadArgument=Module["__PyArg_BadArgument"]=wasmExports["_PyArg_BadArgument"];var _PyUnicode_AsEncodedString=Module["_PyUnicode_AsEncodedString"]=wasmExports["PyUnicode_AsEncodedString"];var _PyBuffer_ToContiguous=Module["_PyBuffer_ToContiguous"]=wasmExports["PyBuffer_ToContiguous"];var _PyObject_GC_Del=Module["_PyObject_GC_Del"]=wasmExports["PyObject_GC_Del"];var __PyBytes_Repeat=Module["__PyBytes_Repeat"]=wasmExports["_PyBytes_Repeat"];var __PyObject_GetState=Module["__PyObject_GetState"]=wasmExports["_PyObject_GetState"];var _PyUnicode_DecodeLatin1=Module["_PyUnicode_DecodeLatin1"]=wasmExports["PyUnicode_DecodeLatin1"];var _PyLong_AsInt=Module["_PyLong_AsInt"]=wasmExports["PyLong_AsInt"];var _PyLong_FromSize_t=Module["_PyLong_FromSize_t"]=wasmExports["PyLong_FromSize_t"];var __PyEval_SliceIndex=Module["__PyEval_SliceIndex"]=wasmExports["_PyEval_SliceIndex"];var _PyUnicode_GetDefaultEncoding=Module["_PyUnicode_GetDefaultEncoding"]=wasmExports["PyUnicode_GetDefaultEncoding"];var _PyUnicode_FromEncodedObject=Module["_PyUnicode_FromEncodedObject"]=wasmExports["PyUnicode_FromEncodedObject"];var _PyList_Append=Module["_PyList_Append"]=wasmExports["PyList_Append"];var _PyList_Reverse=Module["_PyList_Reverse"]=wasmExports["PyList_Reverse"];var __PyEval_GetBuiltin=Module["__PyEval_GetBuiltin"]=wasmExports["_PyEval_GetBuiltin"];var _PyObject_GenericGetAttr=Module["_PyObject_GenericGetAttr"]=wasmExports["PyObject_GenericGetAttr"];var _PyType_GenericAlloc=Module["_PyType_GenericAlloc"]=wasmExports["PyType_GenericAlloc"];var _PyObject_Free=Module["_PyObject_Free"]=wasmExports["PyObject_Free"];var _PyObject_Malloc=Module["_PyObject_Malloc"]=wasmExports["PyObject_Malloc"];var __Py_NewReference=Module["__Py_NewReference"]=wasmExports["_Py_NewReference"];var _PyObject_Calloc=Module["_PyObject_Calloc"]=wasmExports["PyObject_Calloc"];var _PyBytes_FromFormatV=Module["_PyBytes_FromFormatV"]=wasmExports["PyBytes_FromFormatV"];var __PyBytesWriter_Resize=Module["__PyBytesWriter_Resize"]=wasmExports["_PyBytesWriter_Resize"];var __PyBytesWriter_Finish=Module["__PyBytesWriter_Finish"]=wasmExports["_PyBytesWriter_Finish"];var __PyBytesWriter_Init=Module["__PyBytesWriter_Init"]=wasmExports["_PyBytesWriter_Init"];var __PyBytesWriter_Alloc=Module["__PyBytesWriter_Alloc"]=wasmExports["_PyBytesWriter_Alloc"];var __PyBytesWriter_WriteBytes=Module["__PyBytesWriter_WriteBytes"]=wasmExports["_PyBytesWriter_WriteBytes"];var __PyBytes_Resize=Module["__PyBytes_Resize"]=wasmExports["_PyBytes_Resize"];var __PyBytesWriter_Dealloc=Module["__PyBytesWriter_Dealloc"]=wasmExports["_PyBytesWriter_Dealloc"];var _PyBytes_FromFormat=Module["_PyBytes_FromFormat"]=wasmExports["PyBytes_FromFormat"];var _PyObject_ASCII=Module["_PyObject_ASCII"]=wasmExports["PyObject_ASCII"];var _PyOS_double_to_string=Module["_PyOS_double_to_string"]=wasmExports["PyOS_double_to_string"];var __PyBytesWriter_Prepare=Module["__PyBytesWriter_Prepare"]=wasmExports["_PyBytesWriter_Prepare"];var _PyBytes_DecodeEscape=Module["_PyBytes_DecodeEscape"]=wasmExports["PyBytes_DecodeEscape"];var _PyBytes_Size=Module["_PyBytes_Size"]=wasmExports["PyBytes_Size"];var __PyBytes_Find=Module["__PyBytes_Find"]=wasmExports["_PyBytes_Find"];var __PyBytes_ReverseFind=Module["__PyBytes_ReverseFind"]=wasmExports["_PyBytes_ReverseFind"];var _PyBytes_Repr=Module["_PyBytes_Repr"]=wasmExports["PyBytes_Repr"];var __PyBytes_Join=Module["__PyBytes_Join"]=wasmExports["_PyBytes_Join"];var _PyBytes_FromObject=Module["_PyBytes_FromObject"]=wasmExports["PyBytes_FromObject"];var _PyErr_BadArgument=Module["_PyErr_BadArgument"]=wasmExports["PyErr_BadArgument"];var _PyObject_Realloc=Module["_PyObject_Realloc"]=wasmExports["PyObject_Realloc"];var __Py_NewReferenceNoTotal=Module["__Py_NewReferenceNoTotal"]=wasmExports["_Py_NewReferenceNoTotal"];var _PyBytes_ConcatAndDel=Module["_PyBytes_ConcatAndDel"]=wasmExports["PyBytes_ConcatAndDel"];var _PyVectorcall_Function=Module["_PyVectorcall_Function"]=wasmExports["PyVectorcall_Function"];var __PyDict_FromItems=Module["__PyDict_FromItems"]=wasmExports["_PyDict_FromItems"];var _PyDict_Next=Module["_PyDict_Next"]=wasmExports["PyDict_Next"];var _PyObject_VectorcallDict=Module["_PyObject_VectorcallDict"]=wasmExports["PyObject_VectorcallDict"];var _PyModule_GetNameObject=Module["_PyModule_GetNameObject"]=wasmExports["PyModule_GetNameObject"];var _PyCallable_Check=Module["_PyCallable_Check"]=wasmExports["PyCallable_Check"];var __PyStack_AsDict=Module["__PyStack_AsDict"]=wasmExports["_PyStack_AsDict"];var _PyObject_Call=Module["_PyObject_Call"]=wasmExports["PyObject_Call"];var _PyCFunction_Call=Module["_PyCFunction_Call"]=wasmExports["PyCFunction_Call"];var _PyEval_CallObjectWithKeywords=Module["_PyEval_CallObjectWithKeywords"]=wasmExports["PyEval_CallObjectWithKeywords"];var _PyObject_CallObject=Module["_PyObject_CallObject"]=wasmExports["PyObject_CallObject"];var _PyEval_CallFunction=Module["_PyEval_CallFunction"]=wasmExports["PyEval_CallFunction"];var __PyObject_CallFunction_SizeT=Module["__PyObject_CallFunction_SizeT"]=wasmExports["_PyObject_CallFunction_SizeT"];var _PyObject_CallMethod=Module["_PyObject_CallMethod"]=wasmExports["PyObject_CallMethod"];var _PyEval_CallMethod=Module["_PyEval_CallMethod"]=wasmExports["PyEval_CallMethod"];var __PyObject_CallMethod=Module["__PyObject_CallMethod"]=wasmExports["_PyObject_CallMethod"];var __PyObject_CallMethodId=Module["__PyObject_CallMethodId"]=wasmExports["_PyObject_CallMethodId"];var __PyObject_CallMethod_SizeT=Module["__PyObject_CallMethod_SizeT"]=wasmExports["_PyObject_CallMethod_SizeT"];var _PyObject_CallMethodObjArgs=Module["_PyObject_CallMethodObjArgs"]=wasmExports["PyObject_CallMethodObjArgs"];var _PyVectorcall_NARGS=Module["_PyVectorcall_NARGS"]=wasmExports["PyVectorcall_NARGS"];var _PyCapsule_New=Module["_PyCapsule_New"]=wasmExports["PyCapsule_New"];var _PyCapsule_IsValid=Module["_PyCapsule_IsValid"]=wasmExports["PyCapsule_IsValid"];var _PyCapsule_GetPointer=Module["_PyCapsule_GetPointer"]=wasmExports["PyCapsule_GetPointer"];var _PyCapsule_GetName=Module["_PyCapsule_GetName"]=wasmExports["PyCapsule_GetName"];var _PyCapsule_GetDestructor=Module["_PyCapsule_GetDestructor"]=wasmExports["PyCapsule_GetDestructor"];var _PyCapsule_GetContext=Module["_PyCapsule_GetContext"]=wasmExports["PyCapsule_GetContext"];var _PyCapsule_SetPointer=Module["_PyCapsule_SetPointer"]=wasmExports["PyCapsule_SetPointer"];var _PyCapsule_SetName=Module["_PyCapsule_SetName"]=wasmExports["PyCapsule_SetName"];var _PyCapsule_SetDestructor=Module["_PyCapsule_SetDestructor"]=wasmExports["PyCapsule_SetDestructor"];var _PyCapsule_SetContext=Module["_PyCapsule_SetContext"]=wasmExports["PyCapsule_SetContext"];var __PyCapsule_SetTraverse=Module["__PyCapsule_SetTraverse"]=wasmExports["_PyCapsule_SetTraverse"];var _PyCapsule_Import=Module["_PyCapsule_Import"]=wasmExports["PyCapsule_Import"];var _PyCell_New=Module["_PyCell_New"]=wasmExports["PyCell_New"];var _PyCell_Get=Module["_PyCell_Get"]=wasmExports["PyCell_Get"];var _PyCell_Set=Module["_PyCell_Set"]=wasmExports["PyCell_Set"];var _PyObject_RichCompare=Module["_PyObject_RichCompare"]=wasmExports["PyObject_RichCompare"];var _PyMethod_Function=Module["_PyMethod_Function"]=wasmExports["PyMethod_Function"];var _PyMethod_Self=Module["_PyMethod_Self"]=wasmExports["PyMethod_Self"];var _PyMethod_New=Module["_PyMethod_New"]=wasmExports["PyMethod_New"];var _PyObject_ClearWeakRefs=Module["_PyObject_ClearWeakRefs"]=wasmExports["PyObject_ClearWeakRefs"];var _PyObject_GenericHash=Module["_PyObject_GenericHash"]=wasmExports["PyObject_GenericHash"];var __PyType_GetDict=Module["__PyType_GetDict"]=wasmExports["_PyType_GetDict"];var __PyType_LookupRef=Module["__PyType_LookupRef"]=wasmExports["_PyType_LookupRef"];var _PyInstanceMethod_New=Module["_PyInstanceMethod_New"]=wasmExports["PyInstanceMethod_New"];var _PyInstanceMethod_Function=Module["_PyInstanceMethod_Function"]=wasmExports["PyInstanceMethod_Function"];var _PyCode_AddWatcher=Module["_PyCode_AddWatcher"]=wasmExports["PyCode_AddWatcher"];var _PyCode_ClearWatcher=Module["_PyCode_ClearWatcher"]=wasmExports["PyCode_ClearWatcher"];var __PyObject_NewVar=Module["__PyObject_NewVar"]=wasmExports["_PyObject_NewVar"];var __PyUnicode_InternMortal=Module["__PyUnicode_InternMortal"]=wasmExports["_PyUnicode_InternMortal"];var _PyUnstable_Code_NewWithPosOnlyArgs=Module["_PyUnstable_Code_NewWithPosOnlyArgs"]=wasmExports["PyUnstable_Code_NewWithPosOnlyArgs"];var _PyUnicode_Compare=Module["_PyUnicode_Compare"]=wasmExports["PyUnicode_Compare"];var _PyUnstable_Code_New=Module["_PyUnstable_Code_New"]=wasmExports["PyUnstable_Code_New"];var _PyCode_NewEmpty=Module["_PyCode_NewEmpty"]=wasmExports["PyCode_NewEmpty"];var _PyUnicode_DecodeFSDefault=Module["_PyUnicode_DecodeFSDefault"]=wasmExports["PyUnicode_DecodeFSDefault"];var _PyCode_Addr2Line=Module["_PyCode_Addr2Line"]=wasmExports["PyCode_Addr2Line"];var __PyCode_CheckLineNumber=Module["__PyCode_CheckLineNumber"]=wasmExports["_PyCode_CheckLineNumber"];var _PyCode_Addr2Location=Module["_PyCode_Addr2Location"]=wasmExports["PyCode_Addr2Location"];var _PyUnstable_Code_GetExtra=Module["_PyUnstable_Code_GetExtra"]=wasmExports["PyUnstable_Code_GetExtra"];var _PyUnstable_Code_SetExtra=Module["_PyUnstable_Code_SetExtra"]=wasmExports["PyUnstable_Code_SetExtra"];var _PyCode_GetVarnames=Module["_PyCode_GetVarnames"]=wasmExports["PyCode_GetVarnames"];var _PyCode_GetCellvars=Module["_PyCode_GetCellvars"]=wasmExports["PyCode_GetCellvars"];var _PyCode_GetFreevars=Module["_PyCode_GetFreevars"]=wasmExports["PyCode_GetFreevars"];var _PyCode_GetCode=Module["_PyCode_GetCode"]=wasmExports["PyCode_GetCode"];var __PyCode_ConstantKey=Module["__PyCode_ConstantKey"]=wasmExports["_PyCode_ConstantKey"];var _PyComplex_AsCComplex=Module["_PyComplex_AsCComplex"]=wasmExports["PyComplex_AsCComplex"];var __PySet_NextEntry=Module["__PySet_NextEntry"]=wasmExports["_PySet_NextEntry"];var _PyFrozenSet_New=Module["_PyFrozenSet_New"]=wasmExports["PyFrozenSet_New"];var _PyLong_FromVoidPtr=Module["_PyLong_FromVoidPtr"]=wasmExports["PyLong_FromVoidPtr"];var __PyUnicode_Copy=Module["__PyUnicode_Copy"]=wasmExports["_PyUnicode_Copy"];var __Py_c_sum=Module["__Py_c_sum"]=wasmExports["_Py_c_sum"];var __Py_c_diff=Module["__Py_c_diff"]=wasmExports["_Py_c_diff"];var __Py_c_neg=Module["__Py_c_neg"]=wasmExports["_Py_c_neg"];var __Py_c_prod=Module["__Py_c_prod"]=wasmExports["_Py_c_prod"];var __Py_c_quot=Module["__Py_c_quot"]=wasmExports["_Py_c_quot"];var __Py_c_pow=Module["__Py_c_pow"]=wasmExports["_Py_c_pow"];var _atan2=Module["_atan2"]=wasmExports["atan2"];var _hypot=Module["_hypot"]=wasmExports["hypot"];var _pow=Module["_pow"]=wasmExports["pow"];var _log=Module["_log"]=wasmExports["log"];var _exp=Module["_exp"]=wasmExports["exp"];var _sin=Module["_sin"]=wasmExports["sin"];var _cos=Module["_cos"]=wasmExports["cos"];var __Py_c_abs=Module["__Py_c_abs"]=wasmExports["_Py_c_abs"];var _PyComplex_FromDoubles=Module["_PyComplex_FromDoubles"]=wasmExports["PyComplex_FromDoubles"];var _PyComplex_RealAsDouble=Module["_PyComplex_RealAsDouble"]=wasmExports["PyComplex_RealAsDouble"];var _PyComplex_ImagAsDouble=Module["_PyComplex_ImagAsDouble"]=wasmExports["PyComplex_ImagAsDouble"];var __Py_HashDouble=Module["__Py_HashDouble"]=wasmExports["_Py_HashDouble"];var __PyUnicode_TransformDecimalAndSpaceToASCII=Module["__PyUnicode_TransformDecimalAndSpaceToASCII"]=wasmExports["_PyUnicode_TransformDecimalAndSpaceToASCII"];var _PyCMethod_New=Module["_PyCMethod_New"]=wasmExports["PyCMethod_New"];var _PyMember_GetOne=Module["_PyMember_GetOne"]=wasmExports["PyMember_GetOne"];var _PyMember_SetOne=Module["_PyMember_SetOne"]=wasmExports["PyMember_SetOne"];var _PyTuple_GetSlice=Module["_PyTuple_GetSlice"]=wasmExports["PyTuple_GetSlice"];var _PyDescr_NewMethod=Module["_PyDescr_NewMethod"]=wasmExports["PyDescr_NewMethod"];var __PyObject_FunctionStr=Module["__PyObject_FunctionStr"]=wasmExports["_PyObject_FunctionStr"];var _PyDescr_NewClassMethod=Module["_PyDescr_NewClassMethod"]=wasmExports["PyDescr_NewClassMethod"];var _PyDescr_NewMember=Module["_PyDescr_NewMember"]=wasmExports["PyDescr_NewMember"];var _PyDescr_NewGetSet=Module["_PyDescr_NewGetSet"]=wasmExports["PyDescr_NewGetSet"];var _PyDescr_NewWrapper=Module["_PyDescr_NewWrapper"]=wasmExports["PyDescr_NewWrapper"];var _PyDescr_IsData=Module["_PyDescr_IsData"]=wasmExports["PyDescr_IsData"];var _PyDictProxy_New=Module["_PyDictProxy_New"]=wasmExports["PyDictProxy_New"];var _PyThreadState_Get=Module["_PyThreadState_Get"]=wasmExports["PyThreadState_Get"];var __PyTrash_thread_deposit_object=Module["__PyTrash_thread_deposit_object"]=wasmExports["_PyTrash_thread_deposit_object"];var __PyTrash_thread_destroy_chain=Module["__PyTrash_thread_destroy_chain"]=wasmExports["_PyTrash_thread_destroy_chain"];var _Py_HashPointer=Module["_Py_HashPointer"]=wasmExports["Py_HashPointer"];var _PyWrapper_New=Module["_PyWrapper_New"]=wasmExports["PyWrapper_New"];var _PyType_GetQualName=Module["_PyType_GetQualName"]=wasmExports["PyType_GetQualName"];var _PyDict_Contains=Module["_PyDict_Contains"]=wasmExports["PyDict_Contains"];var __PyUnicode_EqualToASCIIString=Module["__PyUnicode_EqualToASCIIString"]=wasmExports["_PyUnicode_EqualToASCIIString"];var _PyException_GetCause=Module["_PyException_GetCause"]=wasmExports["PyException_GetCause"];var _PyException_SetCause=Module["_PyException_SetCause"]=wasmExports["PyException_SetCause"];var _PyException_GetContext=Module["_PyException_GetContext"]=wasmExports["PyException_GetContext"];var _PyException_SetContext=Module["_PyException_SetContext"]=wasmExports["PyException_SetContext"];var _PyException_GetArgs=Module["_PyException_GetArgs"]=wasmExports["PyException_GetArgs"];var _PyException_SetArgs=Module["_PyException_SetArgs"]=wasmExports["PyException_SetArgs"];var _PyExceptionClass_Name=Module["_PyExceptionClass_Name"]=wasmExports["PyExceptionClass_Name"];var _PyUnstable_Exc_PrepReraiseStar=Module["_PyUnstable_Exc_PrepReraiseStar"]=wasmExports["PyUnstable_Exc_PrepReraiseStar"];var _PyUnicodeEncodeError_GetEncoding=Module["_PyUnicodeEncodeError_GetEncoding"]=wasmExports["PyUnicodeEncodeError_GetEncoding"];var _PyUnicodeDecodeError_GetEncoding=Module["_PyUnicodeDecodeError_GetEncoding"]=wasmExports["PyUnicodeDecodeError_GetEncoding"];var _PyUnicodeEncodeError_GetObject=Module["_PyUnicodeEncodeError_GetObject"]=wasmExports["PyUnicodeEncodeError_GetObject"];var _PyUnicodeDecodeError_GetObject=Module["_PyUnicodeDecodeError_GetObject"]=wasmExports["PyUnicodeDecodeError_GetObject"];var _PyUnicodeTranslateError_GetObject=Module["_PyUnicodeTranslateError_GetObject"]=wasmExports["PyUnicodeTranslateError_GetObject"];var _PyUnicodeEncodeError_GetStart=Module["_PyUnicodeEncodeError_GetStart"]=wasmExports["PyUnicodeEncodeError_GetStart"];var _PyUnicodeDecodeError_GetStart=Module["_PyUnicodeDecodeError_GetStart"]=wasmExports["PyUnicodeDecodeError_GetStart"];var _PyUnicodeTranslateError_GetStart=Module["_PyUnicodeTranslateError_GetStart"]=wasmExports["PyUnicodeTranslateError_GetStart"];var _PyUnicodeEncodeError_SetStart=Module["_PyUnicodeEncodeError_SetStart"]=wasmExports["PyUnicodeEncodeError_SetStart"];var _PyUnicodeDecodeError_SetStart=Module["_PyUnicodeDecodeError_SetStart"]=wasmExports["PyUnicodeDecodeError_SetStart"];var _PyUnicodeTranslateError_SetStart=Module["_PyUnicodeTranslateError_SetStart"]=wasmExports["PyUnicodeTranslateError_SetStart"];var _PyUnicodeEncodeError_GetEnd=Module["_PyUnicodeEncodeError_GetEnd"]=wasmExports["PyUnicodeEncodeError_GetEnd"];var _PyUnicodeDecodeError_GetEnd=Module["_PyUnicodeDecodeError_GetEnd"]=wasmExports["PyUnicodeDecodeError_GetEnd"];var _PyUnicodeTranslateError_GetEnd=Module["_PyUnicodeTranslateError_GetEnd"]=wasmExports["PyUnicodeTranslateError_GetEnd"];var _PyUnicodeEncodeError_SetEnd=Module["_PyUnicodeEncodeError_SetEnd"]=wasmExports["PyUnicodeEncodeError_SetEnd"];var _PyUnicodeDecodeError_SetEnd=Module["_PyUnicodeDecodeError_SetEnd"]=wasmExports["PyUnicodeDecodeError_SetEnd"];var _PyUnicodeTranslateError_SetEnd=Module["_PyUnicodeTranslateError_SetEnd"]=wasmExports["PyUnicodeTranslateError_SetEnd"];var _PyUnicodeEncodeError_GetReason=Module["_PyUnicodeEncodeError_GetReason"]=wasmExports["PyUnicodeEncodeError_GetReason"];var _PyUnicodeDecodeError_GetReason=Module["_PyUnicodeDecodeError_GetReason"]=wasmExports["PyUnicodeDecodeError_GetReason"];var _PyUnicodeTranslateError_GetReason=Module["_PyUnicodeTranslateError_GetReason"]=wasmExports["PyUnicodeTranslateError_GetReason"];var _PyUnicodeEncodeError_SetReason=Module["_PyUnicodeEncodeError_SetReason"]=wasmExports["PyUnicodeEncodeError_SetReason"];var _PyUnicodeDecodeError_SetReason=Module["_PyUnicodeDecodeError_SetReason"]=wasmExports["PyUnicodeDecodeError_SetReason"];var _PyUnicodeTranslateError_SetReason=Module["_PyUnicodeTranslateError_SetReason"]=wasmExports["PyUnicodeTranslateError_SetReason"];var _PyUnicodeDecodeError_Create=Module["_PyUnicodeDecodeError_Create"]=wasmExports["PyUnicodeDecodeError_Create"];var _PyModule_GetDict=Module["_PyModule_GetDict"]=wasmExports["PyModule_GetDict"];var _PyErr_NewException=Module["_PyErr_NewException"]=wasmExports["PyErr_NewException"];var _PySet_Add=Module["_PySet_Add"]=wasmExports["PySet_Add"];var _PySet_Contains=Module["_PySet_Contains"]=wasmExports["PySet_Contains"];var _PyTuple_Size=Module["_PyTuple_Size"]=wasmExports["PyTuple_Size"];var _PyDict_Copy=Module["_PyDict_Copy"]=wasmExports["PyDict_Copy"];var _PyUnicode_ReadChar=Module["_PyUnicode_ReadChar"]=wasmExports["PyUnicode_ReadChar"];var _PyObject_GenericGetDict=Module["_PyObject_GenericGetDict"]=wasmExports["PyObject_GenericGetDict"];var _PyObject_GenericSetDict=Module["_PyObject_GenericSetDict"]=wasmExports["PyObject_GenericSetDict"];var _PyObject_HasAttrWithError=Module["_PyObject_HasAttrWithError"]=wasmExports["PyObject_HasAttrWithError"];var _PyList_SetSlice=Module["_PyList_SetSlice"]=wasmExports["PyList_SetSlice"];var __PyUnicodeWriter_WriteASCIIString=Module["__PyUnicodeWriter_WriteASCIIString"]=wasmExports["_PyUnicodeWriter_WriteASCIIString"];var _PyObject_GC_Track=Module["_PyObject_GC_Track"]=wasmExports["PyObject_GC_Track"];var __Py_union_type_or=Module["__Py_union_type_or"]=wasmExports["_Py_union_type_or"];var _PyErr_WriteUnraisable=Module["_PyErr_WriteUnraisable"]=wasmExports["PyErr_WriteUnraisable"];var __PyGen_yf=Module["__PyGen_yf"]=wasmExports["_PyGen_yf"];var _PyObject_CallFinalizerFromDealloc=Module["_PyObject_CallFinalizerFromDealloc"]=wasmExports["PyObject_CallFinalizerFromDealloc"];var __Py_MakeCoro=Module["__Py_MakeCoro"]=wasmExports["_Py_MakeCoro"];var __PyObject_GC_NewVar=Module["__PyObject_GC_NewVar"]=wasmExports["_PyObject_GC_NewVar"];var _PyUnstable_InterpreterFrame_GetLine=Module["_PyUnstable_InterpreterFrame_GetLine"]=wasmExports["PyUnstable_InterpreterFrame_GetLine"];var _PyGen_NewWithQualName=Module["_PyGen_NewWithQualName"]=wasmExports["PyGen_NewWithQualName"];var _PyGen_New=Module["_PyGen_New"]=wasmExports["PyGen_New"];var __PyCoro_GetAwaitableIter=Module["__PyCoro_GetAwaitableIter"]=wasmExports["_PyCoro_GetAwaitableIter"];var _PyCoro_New=Module["_PyCoro_New"]=wasmExports["PyCoro_New"];var _PyAsyncGen_New=Module["_PyAsyncGen_New"]=wasmExports["PyAsyncGen_New"];var __PyEval_EvalFrameDefault=Module["__PyEval_EvalFrameDefault"]=wasmExports["_PyEval_EvalFrameDefault"];var _PyFile_FromFd=Module["_PyFile_FromFd"]=wasmExports["PyFile_FromFd"];var _PyFile_GetLine=Module["_PyFile_GetLine"]=wasmExports["PyFile_GetLine"];var _PyFile_WriteObject=Module["_PyFile_WriteObject"]=wasmExports["PyFile_WriteObject"];var _PyFile_WriteString=Module["_PyFile_WriteString"]=wasmExports["PyFile_WriteString"];var _PyObject_AsFileDescriptor=Module["_PyObject_AsFileDescriptor"]=wasmExports["PyObject_AsFileDescriptor"];var __PyLong_FileDescriptor_Converter=Module["__PyLong_FileDescriptor_Converter"]=wasmExports["_PyLong_FileDescriptor_Converter"];var _flockfile=Module["_flockfile"]=wasmExports["flockfile"];var _getc_unlocked=Module["_getc_unlocked"]=wasmExports["getc_unlocked"];var _funlockfile=Module["_funlockfile"]=wasmExports["funlockfile"];var _Py_UniversalNewlineFgets=Module["_Py_UniversalNewlineFgets"]=wasmExports["Py_UniversalNewlineFgets"];var _PyFile_NewStdPrinter=Module["_PyFile_NewStdPrinter"]=wasmExports["PyFile_NewStdPrinter"];var _PyFile_SetOpenCodeHook=Module["_PyFile_SetOpenCodeHook"]=wasmExports["PyFile_SetOpenCodeHook"];var _Py_IsInitialized=Module["_Py_IsInitialized"]=wasmExports["Py_IsInitialized"];var _PyFile_OpenCodeObject=Module["_PyFile_OpenCodeObject"]=wasmExports["PyFile_OpenCodeObject"];var _PyFile_OpenCode=Module["_PyFile_OpenCode"]=wasmExports["PyFile_OpenCode"];var __PyUnicode_AsUTF8String=Module["__PyUnicode_AsUTF8String"]=wasmExports["_PyUnicode_AsUTF8String"];var __Py_write=Module["__Py_write"]=wasmExports["_Py_write"];var _PyFloat_GetMax=Module["_PyFloat_GetMax"]=wasmExports["PyFloat_GetMax"];var _PyFloat_GetMin=Module["_PyFloat_GetMin"]=wasmExports["PyFloat_GetMin"];var _PyFloat_GetInfo=Module["_PyFloat_GetInfo"]=wasmExports["PyFloat_GetInfo"];var _PyStructSequence_New=Module["_PyStructSequence_New"]=wasmExports["PyStructSequence_New"];var _PyStructSequence_SetItem=Module["_PyStructSequence_SetItem"]=wasmExports["PyStructSequence_SetItem"];var __PyFloat_ExactDealloc=Module["__PyFloat_ExactDealloc"]=wasmExports["_PyFloat_ExactDealloc"];var __PyLong_Sign=Module["__PyLong_Sign"]=wasmExports["_PyLong_Sign"];var _frexp=Module["_frexp"]=wasmExports["frexp"];var _modf=Module["_modf"]=wasmExports["modf"];var _PyLong_FromDouble=Module["_PyLong_FromDouble"]=wasmExports["PyLong_FromDouble"];var __PyLong_Lshift=Module["__PyLong_Lshift"]=wasmExports["_PyLong_Lshift"];var _PyFloat_Pack2=Module["_PyFloat_Pack2"]=wasmExports["PyFloat_Pack2"];var _ldexp=Module["_ldexp"]=wasmExports["ldexp"];var _PyFloat_Pack4=Module["_PyFloat_Pack4"]=wasmExports["PyFloat_Pack4"];var _PyFloat_Pack8=Module["_PyFloat_Pack8"]=wasmExports["PyFloat_Pack8"];var _PyFloat_Unpack2=Module["_PyFloat_Unpack2"]=wasmExports["PyFloat_Unpack2"];var _PyFloat_Unpack4=Module["_PyFloat_Unpack4"]=wasmExports["PyFloat_Unpack4"];var _PyFloat_Unpack8=Module["_PyFloat_Unpack8"]=wasmExports["PyFloat_Unpack8"];var _fmod=Module["_fmod"]=wasmExports["fmod"];var _PyErr_SetFromErrno=Module["_PyErr_SetFromErrno"]=wasmExports["PyErr_SetFromErrno"];var _round=Module["_round"]=wasmExports["round"];var _strtol=Module["_strtol"]=wasmExports["strtol"];var _Py_ReprEnter=Module["_Py_ReprEnter"]=wasmExports["Py_ReprEnter"];var _PyDict_Update=Module["_PyDict_Update"]=wasmExports["PyDict_Update"];var _Py_ReprLeave=Module["_Py_ReprLeave"]=wasmExports["Py_ReprLeave"];var _PyDict_Size=Module["_PyDict_Size"]=wasmExports["PyDict_Size"];var _PyFrame_GetLineNumber=Module["_PyFrame_GetLineNumber"]=wasmExports["PyFrame_GetLineNumber"];var _PyFrame_New=Module["_PyFrame_New"]=wasmExports["PyFrame_New"];var _PyFrame_GetVar=Module["_PyFrame_GetVar"]=wasmExports["PyFrame_GetVar"];var __PyUnicode_Equal=Module["__PyUnicode_Equal"]=wasmExports["_PyUnicode_Equal"];var _PyFrame_GetVarString=Module["_PyFrame_GetVarString"]=wasmExports["PyFrame_GetVarString"];var _PyFrame_FastToLocalsWithError=Module["_PyFrame_FastToLocalsWithError"]=wasmExports["PyFrame_FastToLocalsWithError"];var _PyFrame_FastToLocals=Module["_PyFrame_FastToLocals"]=wasmExports["PyFrame_FastToLocals"];var _PyFrame_LocalsToFast=Module["_PyFrame_LocalsToFast"]=wasmExports["PyFrame_LocalsToFast"];var __PyFrame_IsEntryFrame=Module["__PyFrame_IsEntryFrame"]=wasmExports["_PyFrame_IsEntryFrame"];var _PyFrame_GetCode=Module["_PyFrame_GetCode"]=wasmExports["PyFrame_GetCode"];var _PyFrame_GetBack=Module["_PyFrame_GetBack"]=wasmExports["PyFrame_GetBack"];var _PyFrame_GetLocals=Module["_PyFrame_GetLocals"]=wasmExports["PyFrame_GetLocals"];var _PyFrame_GetGlobals=Module["_PyFrame_GetGlobals"]=wasmExports["PyFrame_GetGlobals"];var _PyFrame_GetBuiltins=Module["_PyFrame_GetBuiltins"]=wasmExports["PyFrame_GetBuiltins"];var _PyFrame_GetLasti=Module["_PyFrame_GetLasti"]=wasmExports["PyFrame_GetLasti"];var _PyFrame_GetGenerator=Module["_PyFrame_GetGenerator"]=wasmExports["PyFrame_GetGenerator"];var __PyErr_SetKeyError=Module["__PyErr_SetKeyError"]=wasmExports["_PyErr_SetKeyError"];var _PyDict_DelItem=Module["_PyDict_DelItem"]=wasmExports["PyDict_DelItem"];var _PyDict_GetItem=Module["_PyDict_GetItem"]=wasmExports["PyDict_GetItem"];var _PyDict_Pop=Module["_PyDict_Pop"]=wasmExports["PyDict_Pop"];var _PyCompile_OpcodeStackEffect=Module["_PyCompile_OpcodeStackEffect"]=wasmExports["PyCompile_OpcodeStackEffect"];var _PyFunction_AddWatcher=Module["_PyFunction_AddWatcher"]=wasmExports["PyFunction_AddWatcher"];var _PyFunction_ClearWatcher=Module["_PyFunction_ClearWatcher"]=wasmExports["PyFunction_ClearWatcher"];var _PyFunction_NewWithQualName=Module["_PyFunction_NewWithQualName"]=wasmExports["PyFunction_NewWithQualName"];var __PyFunction_SetVersion=Module["__PyFunction_SetVersion"]=wasmExports["_PyFunction_SetVersion"];var _PyFunction_New=Module["_PyFunction_New"]=wasmExports["PyFunction_New"];var _PyFunction_GetCode=Module["_PyFunction_GetCode"]=wasmExports["PyFunction_GetCode"];var _PyFunction_GetGlobals=Module["_PyFunction_GetGlobals"]=wasmExports["PyFunction_GetGlobals"];var _PyFunction_GetModule=Module["_PyFunction_GetModule"]=wasmExports["PyFunction_GetModule"];var _PyFunction_GetDefaults=Module["_PyFunction_GetDefaults"]=wasmExports["PyFunction_GetDefaults"];var _PyFunction_SetDefaults=Module["_PyFunction_SetDefaults"]=wasmExports["PyFunction_SetDefaults"];var _PyFunction_SetVectorcall=Module["_PyFunction_SetVectorcall"]=wasmExports["PyFunction_SetVectorcall"];var _PyFunction_GetKwDefaults=Module["_PyFunction_GetKwDefaults"]=wasmExports["PyFunction_GetKwDefaults"];var _PyFunction_SetKwDefaults=Module["_PyFunction_SetKwDefaults"]=wasmExports["PyFunction_SetKwDefaults"];var _PyFunction_GetClosure=Module["_PyFunction_GetClosure"]=wasmExports["PyFunction_GetClosure"];var _PyFunction_SetClosure=Module["_PyFunction_SetClosure"]=wasmExports["PyFunction_SetClosure"];var _PyFunction_GetAnnotations=Module["_PyFunction_GetAnnotations"]=wasmExports["PyFunction_GetAnnotations"];var _PyFunction_SetAnnotations=Module["_PyFunction_SetAnnotations"]=wasmExports["PyFunction_SetAnnotations"];var _PyClassMethod_New=Module["_PyClassMethod_New"]=wasmExports["PyClassMethod_New"];var _PyStaticMethod_New=Module["_PyStaticMethod_New"]=wasmExports["PyStaticMethod_New"];var _PyCallIter_New=Module["_PyCallIter_New"]=wasmExports["PyCallIter_New"];var _PyList_GetItemRef=Module["_PyList_GetItemRef"]=wasmExports["PyList_GetItemRef"];var _PyList_SetItem=Module["_PyList_SetItem"]=wasmExports["PyList_SetItem"];var _PyList_Insert=Module["_PyList_Insert"]=wasmExports["PyList_Insert"];var __PyList_AppendTakeRefListResize=Module["__PyList_AppendTakeRefListResize"]=wasmExports["_PyList_AppendTakeRefListResize"];var _PyList_GetSlice=Module["_PyList_GetSlice"]=wasmExports["PyList_GetSlice"];var __PySet_NextEntryRef=Module["__PySet_NextEntryRef"]=wasmExports["_PySet_NextEntryRef"];var _PyList_Clear=Module["_PyList_Clear"]=wasmExports["PyList_Clear"];var __PyList_FromArraySteal=Module["__PyList_FromArraySteal"]=wasmExports["_PyList_FromArraySteal"];var __PyUnicodeWriter_WriteChar=Module["__PyUnicodeWriter_WriteChar"]=wasmExports["_PyUnicodeWriter_WriteChar"];var __PyEval_SliceIndexNotNone=Module["__PyEval_SliceIndexNotNone"]=wasmExports["_PyEval_SliceIndexNotNone"];var _PyObject_HashNotImplemented=Module["_PyObject_HashNotImplemented"]=wasmExports["PyObject_HashNotImplemented"];var __PyLong_New=Module["__PyLong_New"]=wasmExports["_PyLong_New"];var __PyLong_FromDigits=Module["__PyLong_FromDigits"]=wasmExports["_PyLong_FromDigits"];var _PyLong_FromUnsignedLong=Module["_PyLong_FromUnsignedLong"]=wasmExports["PyLong_FromUnsignedLong"];var _PyLong_FromUnsignedLongLong=Module["_PyLong_FromUnsignedLongLong"]=wasmExports["PyLong_FromUnsignedLongLong"];var _PyLong_AsUnsignedLong=Module["_PyLong_AsUnsignedLong"]=wasmExports["PyLong_AsUnsignedLong"];var _PyLong_AsSize_t=Module["_PyLong_AsSize_t"]=wasmExports["PyLong_AsSize_t"];var _PyLong_AsUnsignedLongMask=Module["_PyLong_AsUnsignedLongMask"]=wasmExports["PyLong_AsUnsignedLongMask"];var __PyLong_FromByteArray=Module["__PyLong_FromByteArray"]=wasmExports["_PyLong_FromByteArray"];var _PyLong_AsNativeBytes=Module["_PyLong_AsNativeBytes"]=wasmExports["PyLong_AsNativeBytes"];var _PyLong_FromNativeBytes=Module["_PyLong_FromNativeBytes"]=wasmExports["PyLong_FromNativeBytes"];var _PyLong_FromUnsignedNativeBytes=Module["_PyLong_FromUnsignedNativeBytes"]=wasmExports["PyLong_FromUnsignedNativeBytes"];var _PyLong_AsVoidPtr=Module["_PyLong_AsVoidPtr"]=wasmExports["PyLong_AsVoidPtr"];var _PyLong_FromLongLong=Module["_PyLong_FromLongLong"]=wasmExports["PyLong_FromLongLong"];var _PyLong_AsLongLong=Module["_PyLong_AsLongLong"]=wasmExports["PyLong_AsLongLong"];var _PyLong_AsUnsignedLongLong=Module["_PyLong_AsUnsignedLongLong"]=wasmExports["PyLong_AsUnsignedLongLong"];var _PyLong_AsUnsignedLongLongMask=Module["_PyLong_AsUnsignedLongLongMask"]=wasmExports["PyLong_AsUnsignedLongLongMask"];var _PyLong_AsLongLongAndOverflow=Module["_PyLong_AsLongLongAndOverflow"]=wasmExports["PyLong_AsLongLongAndOverflow"];var __PyLong_UnsignedShort_Converter=Module["__PyLong_UnsignedShort_Converter"]=wasmExports["_PyLong_UnsignedShort_Converter"];var __PyLong_UnsignedInt_Converter=Module["__PyLong_UnsignedInt_Converter"]=wasmExports["_PyLong_UnsignedInt_Converter"];var __PyLong_UnsignedLong_Converter=Module["__PyLong_UnsignedLong_Converter"]=wasmExports["_PyLong_UnsignedLong_Converter"];var __PyLong_UnsignedLongLong_Converter=Module["__PyLong_UnsignedLongLong_Converter"]=wasmExports["_PyLong_UnsignedLongLong_Converter"];var __PyLong_Size_t_Converter=Module["__PyLong_Size_t_Converter"]=wasmExports["_PyLong_Size_t_Converter"];var __PyUnicodeWriter_PrepareInternal=Module["__PyUnicodeWriter_PrepareInternal"]=wasmExports["_PyUnicodeWriter_PrepareInternal"];var __PyLong_Frexp=Module["__PyLong_Frexp"]=wasmExports["_PyLong_Frexp"];var __PyLong_Add=Module["__PyLong_Add"]=wasmExports["_PyLong_Add"];var __PyLong_Subtract=Module["__PyLong_Subtract"]=wasmExports["_PyLong_Subtract"];var __PyLong_Multiply=Module["__PyLong_Multiply"]=wasmExports["_PyLong_Multiply"];var __PyLong_Rshift=Module["__PyLong_Rshift"]=wasmExports["_PyLong_Rshift"];var __PyLong_GCD=Module["__PyLong_GCD"]=wasmExports["_PyLong_GCD"];var __PyLong_DivmodNear=Module["__PyLong_DivmodNear"]=wasmExports["_PyLong_DivmodNear"];var _PyLong_GetInfo=Module["_PyLong_GetInfo"]=wasmExports["PyLong_GetInfo"];var _PyUnstable_Long_IsCompact=Module["_PyUnstable_Long_IsCompact"]=wasmExports["PyUnstable_Long_IsCompact"];var _PyUnstable_Long_CompactValue=Module["_PyUnstable_Long_CompactValue"]=wasmExports["PyUnstable_Long_CompactValue"];var _PyObject_Bytes=Module["_PyObject_Bytes"]=wasmExports["PyObject_Bytes"];var __PyObject_AssertFailed=Module["__PyObject_AssertFailed"]=wasmExports["_PyObject_AssertFailed"];var _PyObject_IS_GC=Module["_PyObject_IS_GC"]=wasmExports["PyObject_IS_GC"];var __PyDict_NewPresized=Module["__PyDict_NewPresized"]=wasmExports["_PyDict_NewPresized"];var __PyDict_GetItemRef_KnownHash_LockHeld=Module["__PyDict_GetItemRef_KnownHash_LockHeld"]=wasmExports["_PyDict_GetItemRef_KnownHash_LockHeld"];var __PyDict_GetItemStringWithError=Module["__PyDict_GetItemStringWithError"]=wasmExports["_PyDict_GetItemStringWithError"];var __PyDict_LoadGlobal=Module["__PyDict_LoadGlobal"]=wasmExports["_PyDict_LoadGlobal"];var __PyDict_SetItem_Take2=Module["__PyDict_SetItem_Take2"]=wasmExports["_PyDict_SetItem_Take2"];var __PyDict_SetItem_KnownHash_LockHeld=Module["__PyDict_SetItem_KnownHash_LockHeld"]=wasmExports["_PyDict_SetItem_KnownHash_LockHeld"];var __PyDict_SetItem_KnownHash=Module["__PyDict_SetItem_KnownHash"]=wasmExports["_PyDict_SetItem_KnownHash"];var __PyDict_DelItem_KnownHash=Module["__PyDict_DelItem_KnownHash"]=wasmExports["_PyDict_DelItem_KnownHash"];var __PyDict_DelItemIf=Module["__PyDict_DelItemIf"]=wasmExports["_PyDict_DelItemIf"];var _PyDict_Clear=Module["_PyDict_Clear"]=wasmExports["PyDict_Clear"];var _PyDict_PopString=Module["_PyDict_PopString"]=wasmExports["PyDict_PopString"];var __PyDict_Pop=Module["__PyDict_Pop"]=wasmExports["_PyDict_Pop"];var _PyDict_MergeFromSeq2=Module["_PyDict_MergeFromSeq2"]=wasmExports["PyDict_MergeFromSeq2"];var _PyDict_Merge=Module["_PyDict_Merge"]=wasmExports["PyDict_Merge"];var __PyDict_MergeEx=Module["__PyDict_MergeEx"]=wasmExports["_PyDict_MergeEx"];var _PyDict_SetDefaultRef=Module["_PyDict_SetDefaultRef"]=wasmExports["PyDict_SetDefaultRef"];var _PyDict_SetDefault=Module["_PyDict_SetDefault"]=wasmExports["PyDict_SetDefault"];var __PyDict_SizeOf=Module["__PyDict_SizeOf"]=wasmExports["_PyDict_SizeOf"];var _PyDict_ContainsString=Module["_PyDict_ContainsString"]=wasmExports["PyDict_ContainsString"];var _PyDict_GetItemString=Module["_PyDict_GetItemString"]=wasmExports["PyDict_GetItemString"];var _PyDict_GetItemStringRef=Module["_PyDict_GetItemStringRef"]=wasmExports["PyDict_GetItemStringRef"];var _PyDict_DelItemString=Module["_PyDict_DelItemString"]=wasmExports["PyDict_DelItemString"];var _PyObject_VisitManagedDict=Module["_PyObject_VisitManagedDict"]=wasmExports["PyObject_VisitManagedDict"];var __PyObject_SetManagedDict=Module["__PyObject_SetManagedDict"]=wasmExports["_PyObject_SetManagedDict"];var _PyObject_ClearManagedDict=Module["_PyObject_ClearManagedDict"]=wasmExports["PyObject_ClearManagedDict"];var _PyDict_Watch=Module["_PyDict_Watch"]=wasmExports["PyDict_Watch"];var _PyDict_Unwatch=Module["_PyDict_Unwatch"]=wasmExports["PyDict_Unwatch"];var _PyDict_AddWatcher=Module["_PyDict_AddWatcher"]=wasmExports["PyDict_AddWatcher"];var _PyDict_ClearWatcher=Module["_PyDict_ClearWatcher"]=wasmExports["PyDict_ClearWatcher"];var _PyArg_ValidateKeywordArguments=Module["_PyArg_ValidateKeywordArguments"]=wasmExports["PyArg_ValidateKeywordArguments"];var _PyODict_New=Module["_PyODict_New"]=wasmExports["PyODict_New"];var _PyODict_SetItem=Module["_PyODict_SetItem"]=wasmExports["PyODict_SetItem"];var __PyErr_ChainExceptions1=Module["__PyErr_ChainExceptions1"]=wasmExports["_PyErr_ChainExceptions1"];var _PyODict_DelItem=Module["_PyODict_DelItem"]=wasmExports["PyODict_DelItem"];var _PyMemoryView_FromMemory=Module["_PyMemoryView_FromMemory"]=wasmExports["PyMemoryView_FromMemory"];var _PyMemoryView_FromBuffer=Module["_PyMemoryView_FromBuffer"]=wasmExports["PyMemoryView_FromBuffer"];var _PyMemoryView_GetContiguous=Module["_PyMemoryView_GetContiguous"]=wasmExports["PyMemoryView_GetContiguous"];var _PyUnicode_AsASCIIString=Module["_PyUnicode_AsASCIIString"]=wasmExports["PyUnicode_AsASCIIString"];var _PyCFunction_New=Module["_PyCFunction_New"]=wasmExports["PyCFunction_New"];var _PyCFunction_NewEx=Module["_PyCFunction_NewEx"]=wasmExports["PyCFunction_NewEx"];var _PyCFunction_GetFunction=Module["_PyCFunction_GetFunction"]=wasmExports["PyCFunction_GetFunction"];var _PyCFunction_GetSelf=Module["_PyCFunction_GetSelf"]=wasmExports["PyCFunction_GetSelf"];var _PyCFunction_GetFlags=Module["_PyCFunction_GetFlags"]=wasmExports["PyCFunction_GetFlags"];var _PyModuleDef_Init=Module["_PyModuleDef_Init"]=wasmExports["PyModuleDef_Init"];var _PyModule_NewObject=Module["_PyModule_NewObject"]=wasmExports["PyModule_NewObject"];var _PyModule_New=Module["_PyModule_New"]=wasmExports["PyModule_New"];var _PyModule_SetDocString=Module["_PyModule_SetDocString"]=wasmExports["PyModule_SetDocString"];var _PyModule_FromDefAndSpec2=Module["_PyModule_FromDefAndSpec2"]=wasmExports["PyModule_FromDefAndSpec2"];var _PyModule_ExecDef=Module["_PyModule_ExecDef"]=wasmExports["PyModule_ExecDef"];var _PyModule_GetName=Module["_PyModule_GetName"]=wasmExports["PyModule_GetName"];var _PyModule_GetFilenameObject=Module["_PyModule_GetFilenameObject"]=wasmExports["PyModule_GetFilenameObject"];var _PyModule_GetFilename=Module["_PyModule_GetFilename"]=wasmExports["PyModule_GetFilename"];var _PyModule_GetDef=Module["_PyModule_GetDef"]=wasmExports["PyModule_GetDef"];var _PyModule_GetState=Module["_PyModule_GetState"]=wasmExports["PyModule_GetState"];var _PyUnicode_AsWideChar=Module["_PyUnicode_AsWideChar"]=wasmExports["PyUnicode_AsWideChar"];var _wcsrchr=Module["_wcsrchr"]=wasmExports["wcsrchr"];var _wcscmp=Module["_wcscmp"]=wasmExports["wcscmp"];var _PySys_FormatStderr=Module["_PySys_FormatStderr"]=wasmExports["PySys_FormatStderr"];var _PyUnicode_Join=Module["_PyUnicode_Join"]=wasmExports["PyUnicode_Join"];var __PyNamespace_New=Module["__PyNamespace_New"]=wasmExports["_PyNamespace_New"];var __PyArg_NoPositional=Module["__PyArg_NoPositional"]=wasmExports["_PyArg_NoPositional"];var __PyUnicode_CheckConsistency=Module["__PyUnicode_CheckConsistency"]=wasmExports["_PyUnicode_CheckConsistency"];var __PyObject_IsFreed=Module["__PyObject_IsFreed"]=wasmExports["_PyObject_IsFreed"];var _fwrite=Module["_fwrite"]=wasmExports["fwrite"];var _fputc=Module["_fputc"]=wasmExports["fputc"];var __PyObject_Dump=Module["__PyObject_Dump"]=wasmExports["_PyObject_Dump"];var _Py_IncRef=Module["_Py_IncRef"]=wasmExports["Py_IncRef"];var _Py_DecRef=Module["_Py_DecRef"]=wasmExports["Py_DecRef"];var __Py_IncRef=Module["__Py_IncRef"]=wasmExports["_Py_IncRef"];var __Py_DecRef=Module["__Py_DecRef"]=wasmExports["_Py_DecRef"];var _PyObject_Init=Module["_PyObject_Init"]=wasmExports["PyObject_Init"];var _PyObject_InitVar=Module["_PyObject_InitVar"]=wasmExports["PyObject_InitVar"];var _PyObject_CallFinalizer=Module["_PyObject_CallFinalizer"]=wasmExports["PyObject_CallFinalizer"];var __Py_ResurrectReference=Module["__Py_ResurrectReference"]=wasmExports["_Py_ResurrectReference"];var _PyObject_Print=Module["_PyObject_Print"]=wasmExports["PyObject_Print"];var _ferror=Module["_ferror"]=wasmExports["ferror"];var __Py_BreakPoint=Module["__Py_BreakPoint"]=wasmExports["_Py_BreakPoint"];var _PyGILState_Ensure=Module["_PyGILState_Ensure"]=wasmExports["PyGILState_Ensure"];var _PyGILState_Release=Module["_PyGILState_Release"]=wasmExports["PyGILState_Release"];var _PyUnicode_DecodeASCII=Module["_PyUnicode_DecodeASCII"]=wasmExports["PyUnicode_DecodeASCII"];var _PyObject_HasAttrStringWithError=Module["_PyObject_HasAttrStringWithError"]=wasmExports["PyObject_HasAttrStringWithError"];var _PyObject_GetOptionalAttrString=Module["_PyObject_GetOptionalAttrString"]=wasmExports["PyObject_GetOptionalAttrString"];var _PyObject_HasAttrString=Module["_PyObject_HasAttrString"]=wasmExports["PyObject_HasAttrString"];var _PyObject_DelAttrString=Module["_PyObject_DelAttrString"]=wasmExports["PyObject_DelAttrString"];var __PyObject_GetDictPtr=Module["__PyObject_GetDictPtr"]=wasmExports["_PyObject_GetDictPtr"];var __PyObject_GenericSetAttrWithDict=Module["__PyObject_GenericSetAttrWithDict"]=wasmExports["_PyObject_GenericSetAttrWithDict"];var _PyObject_Not=Module["_PyObject_Not"]=wasmExports["PyObject_Not"];var _PyThreadState_GetDict=Module["_PyThreadState_GetDict"]=wasmExports["PyThreadState_GetDict"];var _PyObject_GET_WEAKREFS_LISTPTR=Module["_PyObject_GET_WEAKREFS_LISTPTR"]=wasmExports["PyObject_GET_WEAKREFS_LISTPTR"];var _Py_NewRef=Module["_Py_NewRef"]=wasmExports["Py_NewRef"];var _Py_XNewRef=Module["_Py_XNewRef"]=wasmExports["Py_XNewRef"];var _Py_Is=Module["_Py_Is"]=wasmExports["Py_Is"];var _Py_IsNone=Module["_Py_IsNone"]=wasmExports["Py_IsNone"];var _Py_IsTrue=Module["_Py_IsTrue"]=wasmExports["Py_IsTrue"];var _Py_IsFalse=Module["_Py_IsFalse"]=wasmExports["Py_IsFalse"];var __Py_SetRefcnt=Module["__Py_SetRefcnt"]=wasmExports["_Py_SetRefcnt"];var _PyRefTracer_SetTracer=Module["_PyRefTracer_SetTracer"]=wasmExports["PyRefTracer_SetTracer"];var _PyRefTracer_GetTracer=Module["_PyRefTracer_GetTracer"]=wasmExports["PyRefTracer_GetTracer"];var _Py_GetConstant=Module["_Py_GetConstant"]=wasmExports["Py_GetConstant"];var _Py_GetConstantBorrowed=Module["_Py_GetConstantBorrowed"]=wasmExports["Py_GetConstantBorrowed"];var _sleep=Module["_sleep"]=wasmExports["sleep"];var _abort=Module["_abort"]=wasmExports["abort"];var _getenv=Module["_getenv"]=wasmExports["getenv"];var _sbrk=Module["_sbrk"]=wasmExports["sbrk"];var _clock_gettime=Module["_clock_gettime"]=wasmExports["clock_gettime"];var _vsnprintf=Module["_vsnprintf"]=wasmExports["vsnprintf"];var _atexit=Module["_atexit"]=wasmExports["atexit"];var _strstr=Module["_strstr"]=wasmExports["strstr"];var _snprintf=Module["_snprintf"]=wasmExports["snprintf"];var _calloc=wasmExports["calloc"];var _realloc=wasmExports["realloc"];var __PyMem_GetCurrentAllocatorName=Module["__PyMem_GetCurrentAllocatorName"]=wasmExports["_PyMem_GetCurrentAllocatorName"];var _PyMem_SetupDebugHooks=Module["_PyMem_SetupDebugHooks"]=wasmExports["PyMem_SetupDebugHooks"];var _PyMem_GetAllocator=Module["_PyMem_GetAllocator"]=wasmExports["PyMem_GetAllocator"];var _PyMem_SetAllocator=Module["_PyMem_SetAllocator"]=wasmExports["PyMem_SetAllocator"];var _PyObject_GetArenaAllocator=Module["_PyObject_GetArenaAllocator"]=wasmExports["PyObject_GetArenaAllocator"];var _PyObject_SetArenaAllocator=Module["_PyObject_SetArenaAllocator"]=wasmExports["PyObject_SetArenaAllocator"];var _PyMem_RawMalloc=Module["_PyMem_RawMalloc"]=wasmExports["PyMem_RawMalloc"];var _PyMem_RawCalloc=Module["_PyMem_RawCalloc"]=wasmExports["PyMem_RawCalloc"];var _wcslen=Module["_wcslen"]=wasmExports["wcslen"];var __PyMem_Strdup=Module["__PyMem_Strdup"]=wasmExports["_PyMem_Strdup"];var _PyPickleBuffer_FromObject=Module["_PyPickleBuffer_FromObject"]=wasmExports["PyPickleBuffer_FromObject"];var _PyPickleBuffer_GetBuffer=Module["_PyPickleBuffer_GetBuffer"]=wasmExports["PyPickleBuffer_GetBuffer"];var _PyPickleBuffer_Release=Module["_PyPickleBuffer_Release"]=wasmExports["PyPickleBuffer_Release"];var __PySlice_GetLongIndices=Module["__PySlice_GetLongIndices"]=wasmExports["_PySlice_GetLongIndices"];var __PySet_Contains=Module["__PySet_Contains"]=wasmExports["_PySet_Contains"];var _PySet_Size=Module["_PySet_Size"]=wasmExports["PySet_Size"];var _PySet_Clear=Module["_PySet_Clear"]=wasmExports["PySet_Clear"];var _PySet_Pop=Module["_PySet_Pop"]=wasmExports["PySet_Pop"];var _PySlice_New=Module["_PySlice_New"]=wasmExports["PySlice_New"];var _PySlice_GetIndices=Module["_PySlice_GetIndices"]=wasmExports["PySlice_GetIndices"];var _PySlice_GetIndicesEx=Module["_PySlice_GetIndicesEx"]=wasmExports["PySlice_GetIndicesEx"];var _PyStructSequence_GetItem=Module["_PyStructSequence_GetItem"]=wasmExports["PyStructSequence_GetItem"];var _PyStructSequence_InitType2=Module["_PyStructSequence_InitType2"]=wasmExports["PyStructSequence_InitType2"];var _PyStructSequence_InitType=Module["_PyStructSequence_InitType"]=wasmExports["PyStructSequence_InitType"];var __PyStructSequence_NewType=Module["__PyStructSequence_NewType"]=wasmExports["_PyStructSequence_NewType"];var _PyStructSequence_NewType=Module["_PyStructSequence_NewType"]=wasmExports["PyStructSequence_NewType"];var _PyTuple_SetItem=Module["_PyTuple_SetItem"]=wasmExports["PyTuple_SetItem"];var __PyTuple_FromArraySteal=Module["__PyTuple_FromArraySteal"]=wasmExports["_PyTuple_FromArraySteal"];var __PyObject_GC_Resize=Module["__PyObject_GC_Resize"]=wasmExports["_PyObject_GC_Resize"];var _PyType_GetDict=Module["_PyType_GetDict"]=wasmExports["PyType_GetDict"];var _strrchr=Module["_strrchr"]=wasmExports["strrchr"];var _PyType_ClearCache=Module["_PyType_ClearCache"]=wasmExports["PyType_ClearCache"];var _PyType_AddWatcher=Module["_PyType_AddWatcher"]=wasmExports["PyType_AddWatcher"];var _PyType_ClearWatcher=Module["_PyType_ClearWatcher"]=wasmExports["PyType_ClearWatcher"];var _PyType_Watch=Module["_PyType_Watch"]=wasmExports["PyType_Watch"];var _PyType_Unwatch=Module["_PyType_Unwatch"]=wasmExports["PyType_Unwatch"];var _PyType_Modified=Module["_PyType_Modified"]=wasmExports["PyType_Modified"];var _PyUnstable_Type_AssignVersionTag=Module["_PyUnstable_Type_AssignVersionTag"]=wasmExports["PyUnstable_Type_AssignVersionTag"];var _PyType_GetFullyQualifiedName=Module["_PyType_GetFullyQualifiedName"]=wasmExports["PyType_GetFullyQualifiedName"];var _PyType_GetFlags=Module["_PyType_GetFlags"]=wasmExports["PyType_GetFlags"];var _PyType_SUPPORTS_WEAKREFS=Module["_PyType_SUPPORTS_WEAKREFS"]=wasmExports["PyType_SUPPORTS_WEAKREFS"];var _PyType_FromMetaclass=Module["_PyType_FromMetaclass"]=wasmExports["PyType_FromMetaclass"];var _PyType_FromModuleAndSpec=Module["_PyType_FromModuleAndSpec"]=wasmExports["PyType_FromModuleAndSpec"];var _PyType_FromSpec=Module["_PyType_FromSpec"]=wasmExports["PyType_FromSpec"];var _PyType_GetName=Module["_PyType_GetName"]=wasmExports["PyType_GetName"];var _PyType_GetModuleName=Module["_PyType_GetModuleName"]=wasmExports["PyType_GetModuleName"];var _PyType_GetSlot=Module["_PyType_GetSlot"]=wasmExports["PyType_GetSlot"];var _PyType_GetModule=Module["_PyType_GetModule"]=wasmExports["PyType_GetModule"];var _PyType_GetModuleState=Module["_PyType_GetModuleState"]=wasmExports["PyType_GetModuleState"];var _PyType_GetModuleByDef=Module["_PyType_GetModuleByDef"]=wasmExports["PyType_GetModuleByDef"];var __PyType_GetModuleByDef2=Module["__PyType_GetModuleByDef2"]=wasmExports["_PyType_GetModuleByDef2"];var _PyObject_GetTypeData=Module["_PyObject_GetTypeData"]=wasmExports["PyObject_GetTypeData"];var _PyType_GetTypeDataSize=Module["_PyType_GetTypeDataSize"]=wasmExports["PyType_GetTypeDataSize"];var _PyObject_GetItemData=Module["_PyObject_GetItemData"]=wasmExports["PyObject_GetItemData"];var __PyType_Lookup=Module["__PyType_Lookup"]=wasmExports["_PyType_Lookup"];var _PyUnicode_IsIdentifier=Module["_PyUnicode_IsIdentifier"]=wasmExports["PyUnicode_IsIdentifier"];var _PyEval_GetGlobals=Module["_PyEval_GetGlobals"]=wasmExports["PyEval_GetGlobals"];var __PyStaticType_InitForExtension=Module["__PyStaticType_InitForExtension"]=wasmExports["_PyStaticType_InitForExtension"];var __PySuper_Lookup=Module["__PySuper_Lookup"]=wasmExports["_PySuper_Lookup"];var _PyWeakref_NewRef=Module["_PyWeakref_NewRef"]=wasmExports["PyWeakref_NewRef"];var _PyImport_GetModule=Module["_PyImport_GetModule"]=wasmExports["PyImport_GetModule"];var _PyImport_Import=Module["_PyImport_Import"]=wasmExports["PyImport_Import"];var __PyArg_UnpackKeywordsWithVararg=Module["__PyArg_UnpackKeywordsWithVararg"]=wasmExports["_PyArg_UnpackKeywordsWithVararg"];var __Py_hashtable_len=Module["__Py_hashtable_len"]=wasmExports["_Py_hashtable_len"];var __Py_GetErrorHandler=Module["__Py_GetErrorHandler"]=wasmExports["_Py_GetErrorHandler"];var _PyUnicode_CopyCharacters=Module["_PyUnicode_CopyCharacters"]=wasmExports["PyUnicode_CopyCharacters"];var _PyUnicode_Resize=Module["_PyUnicode_Resize"]=wasmExports["PyUnicode_Resize"];var _PyUnicode_FromWideChar=Module["_PyUnicode_FromWideChar"]=wasmExports["PyUnicode_FromWideChar"];var _PyUnicode_FromKindAndData=Module["_PyUnicode_FromKindAndData"]=wasmExports["PyUnicode_FromKindAndData"];var _PyUnicode_AsUCS4=Module["_PyUnicode_AsUCS4"]=wasmExports["PyUnicode_AsUCS4"];var _PyUnicode_AsUCS4Copy=Module["_PyUnicode_AsUCS4Copy"]=wasmExports["PyUnicode_AsUCS4Copy"];var _PyUnicode_Fill=Module["_PyUnicode_Fill"]=wasmExports["PyUnicode_Fill"];var _PyUnicode_AsWideCharString=Module["_PyUnicode_AsWideCharString"]=wasmExports["PyUnicode_AsWideCharString"];var _PyUnicode_FromOrdinal=Module["_PyUnicode_FromOrdinal"]=wasmExports["PyUnicode_FromOrdinal"];var _PyUnicode_FromObject=Module["_PyUnicode_FromObject"]=wasmExports["PyUnicode_FromObject"];var _PyCodec_LookupError=Module["_PyCodec_LookupError"]=wasmExports["PyCodec_LookupError"];var _PyUnicode_DecodeUTF16Stateful=Module["_PyUnicode_DecodeUTF16Stateful"]=wasmExports["PyUnicode_DecodeUTF16Stateful"];var _PyUnicode_DecodeUTF32Stateful=Module["_PyUnicode_DecodeUTF32Stateful"]=wasmExports["PyUnicode_DecodeUTF32Stateful"];var _PyUnicode_DecodeUTF16=Module["_PyUnicode_DecodeUTF16"]=wasmExports["PyUnicode_DecodeUTF16"];var _PyUnicode_DecodeUTF32=Module["_PyUnicode_DecodeUTF32"]=wasmExports["PyUnicode_DecodeUTF32"];var _PyUnicode_AsDecodedObject=Module["_PyUnicode_AsDecodedObject"]=wasmExports["PyUnicode_AsDecodedObject"];var _PyCodec_Decode=Module["_PyCodec_Decode"]=wasmExports["PyCodec_Decode"];var _PyUnicode_AsDecodedUnicode=Module["_PyUnicode_AsDecodedUnicode"]=wasmExports["PyUnicode_AsDecodedUnicode"];var _PyUnicode_AsEncodedObject=Module["_PyUnicode_AsEncodedObject"]=wasmExports["PyUnicode_AsEncodedObject"];var _PyCodec_Encode=Module["_PyCodec_Encode"]=wasmExports["PyCodec_Encode"];var _PyUnicode_EncodeLocale=Module["_PyUnicode_EncodeLocale"]=wasmExports["PyUnicode_EncodeLocale"];var __Py_EncodeLocaleEx=Module["__Py_EncodeLocaleEx"]=wasmExports["_Py_EncodeLocaleEx"];var _PyCodec_StrictErrors=Module["_PyCodec_StrictErrors"]=wasmExports["PyCodec_StrictErrors"];var _PyUnicode_EncodeFSDefault=Module["_PyUnicode_EncodeFSDefault"]=wasmExports["PyUnicode_EncodeFSDefault"];var __PyUnicode_EncodeUTF16=Module["__PyUnicode_EncodeUTF16"]=wasmExports["_PyUnicode_EncodeUTF16"];var __PyUnicode_EncodeUTF32=Module["__PyUnicode_EncodeUTF32"]=wasmExports["_PyUnicode_EncodeUTF32"];var _PyUnicode_AsEncodedUnicode=Module["_PyUnicode_AsEncodedUnicode"]=wasmExports["PyUnicode_AsEncodedUnicode"];var _PyUnicode_DecodeLocaleAndSize=Module["_PyUnicode_DecodeLocaleAndSize"]=wasmExports["PyUnicode_DecodeLocaleAndSize"];var __Py_DecodeLocaleEx=Module["__Py_DecodeLocaleEx"]=wasmExports["_Py_DecodeLocaleEx"];var _PyUnicode_DecodeLocale=Module["_PyUnicode_DecodeLocale"]=wasmExports["PyUnicode_DecodeLocale"];var _PyUnicode_DecodeFSDefaultAndSize=Module["_PyUnicode_DecodeFSDefaultAndSize"]=wasmExports["PyUnicode_DecodeFSDefaultAndSize"];var _PyUnicode_FSConverter=Module["_PyUnicode_FSConverter"]=wasmExports["PyUnicode_FSConverter"];var _PyOS_FSPath=Module["_PyOS_FSPath"]=wasmExports["PyOS_FSPath"];var _PyUnicode_FSDecoder=Module["_PyUnicode_FSDecoder"]=wasmExports["PyUnicode_FSDecoder"];var _wmemchr=Module["_wmemchr"]=wasmExports["wmemchr"];var __PyUnicode_AsUTF8NoNUL=Module["__PyUnicode_AsUTF8NoNUL"]=wasmExports["_PyUnicode_AsUTF8NoNUL"];var _PyUnicode_GetSize=Module["_PyUnicode_GetSize"]=wasmExports["PyUnicode_GetSize"];var _PyUnicode_GetLength=Module["_PyUnicode_GetLength"]=wasmExports["PyUnicode_GetLength"];var _PyUnicode_WriteChar=Module["_PyUnicode_WriteChar"]=wasmExports["PyUnicode_WriteChar"];var _PyUnicode_DecodeUTF7=Module["_PyUnicode_DecodeUTF7"]=wasmExports["PyUnicode_DecodeUTF7"];var _PyUnicode_DecodeUTF7Stateful=Module["_PyUnicode_DecodeUTF7Stateful"]=wasmExports["PyUnicode_DecodeUTF7Stateful"];var _PyUnicode_AsUTF32String=Module["_PyUnicode_AsUTF32String"]=wasmExports["PyUnicode_AsUTF32String"];var _PyUnicode_AsUTF16String=Module["_PyUnicode_AsUTF16String"]=wasmExports["PyUnicode_AsUTF16String"];var _PyUnicode_DecodeUnicodeEscape=Module["_PyUnicode_DecodeUnicodeEscape"]=wasmExports["PyUnicode_DecodeUnicodeEscape"];var _PyUnicode_AsUnicodeEscapeString=Module["_PyUnicode_AsUnicodeEscapeString"]=wasmExports["PyUnicode_AsUnicodeEscapeString"];var _PyUnicode_DecodeRawUnicodeEscape=Module["_PyUnicode_DecodeRawUnicodeEscape"]=wasmExports["PyUnicode_DecodeRawUnicodeEscape"];var _PyUnicode_AsRawUnicodeEscapeString=Module["_PyUnicode_AsRawUnicodeEscapeString"]=wasmExports["PyUnicode_AsRawUnicodeEscapeString"];var _PyUnicode_AsLatin1String=Module["_PyUnicode_AsLatin1String"]=wasmExports["PyUnicode_AsLatin1String"];var __PyUnicodeWriter_PrepareKindInternal=Module["__PyUnicodeWriter_PrepareKindInternal"]=wasmExports["_PyUnicodeWriter_PrepareKindInternal"];var _PyUnicode_DecodeCharmap=Module["_PyUnicode_DecodeCharmap"]=wasmExports["PyUnicode_DecodeCharmap"];var _PyUnicode_BuildEncodingMap=Module["_PyUnicode_BuildEncodingMap"]=wasmExports["PyUnicode_BuildEncodingMap"];var _PyUnicode_AsCharmapString=Module["_PyUnicode_AsCharmapString"]=wasmExports["PyUnicode_AsCharmapString"];var _PyUnicode_Translate=Module["_PyUnicode_Translate"]=wasmExports["PyUnicode_Translate"];var __PyUnicode_IsWhitespace=Module["__PyUnicode_IsWhitespace"]=wasmExports["_PyUnicode_IsWhitespace"];var __PyUnicode_ToDecimalDigit=Module["__PyUnicode_ToDecimalDigit"]=wasmExports["_PyUnicode_ToDecimalDigit"];var _PyUnicode_Count=Module["_PyUnicode_Count"]=wasmExports["PyUnicode_Count"];var _PyUnicode_Find=Module["_PyUnicode_Find"]=wasmExports["PyUnicode_Find"];var _PyUnicode_FindChar=Module["_PyUnicode_FindChar"]=wasmExports["PyUnicode_FindChar"];var _PyUnicode_Tailmatch=Module["_PyUnicode_Tailmatch"]=wasmExports["PyUnicode_Tailmatch"];var __PyUnicode_JoinArray=Module["__PyUnicode_JoinArray"]=wasmExports["_PyUnicode_JoinArray"];var _PyUnicode_Splitlines=Module["_PyUnicode_Splitlines"]=wasmExports["PyUnicode_Splitlines"];var __PyUnicode_IsLinebreak=Module["__PyUnicode_IsLinebreak"]=wasmExports["_PyUnicode_IsLinebreak"];var _wmemcmp=Module["_wmemcmp"]=wasmExports["wmemcmp"];var _PyUnicode_EqualToUTF8=Module["_PyUnicode_EqualToUTF8"]=wasmExports["PyUnicode_EqualToUTF8"];var _PyUnicode_EqualToUTF8AndSize=Module["_PyUnicode_EqualToUTF8AndSize"]=wasmExports["PyUnicode_EqualToUTF8AndSize"];var _PyUnicode_RichCompare=Module["_PyUnicode_RichCompare"]=wasmExports["PyUnicode_RichCompare"];var _PyUnicode_Contains=Module["_PyUnicode_Contains"]=wasmExports["PyUnicode_Contains"];var _PyUnicode_Concat=Module["_PyUnicode_Concat"]=wasmExports["PyUnicode_Concat"];var _PyUnicode_Append=Module["_PyUnicode_Append"]=wasmExports["PyUnicode_Append"];var _PyUnicode_AppendAndDel=Module["_PyUnicode_AppendAndDel"]=wasmExports["PyUnicode_AppendAndDel"];var _PyUnicode_Replace=Module["_PyUnicode_Replace"]=wasmExports["PyUnicode_Replace"];var _PyUnicode_Split=Module["_PyUnicode_Split"]=wasmExports["PyUnicode_Split"];var _PyUnicode_Partition=Module["_PyUnicode_Partition"]=wasmExports["PyUnicode_Partition"];var _PyUnicode_RPartition=Module["_PyUnicode_RPartition"]=wasmExports["PyUnicode_RPartition"];var _PyUnicode_RSplit=Module["_PyUnicode_RSplit"]=wasmExports["PyUnicode_RSplit"];var __PyUnicodeWriter_WriteSubstring=Module["__PyUnicodeWriter_WriteSubstring"]=wasmExports["_PyUnicodeWriter_WriteSubstring"];var __PyUnicodeWriter_WriteLatin1String=Module["__PyUnicodeWriter_WriteLatin1String"]=wasmExports["_PyUnicodeWriter_WriteLatin1String"];var _PyUnicode_Format=Module["_PyUnicode_Format"]=wasmExports["PyUnicode_Format"];var __PyUnicode_ExactDealloc=Module["__PyUnicode_ExactDealloc"]=wasmExports["_PyUnicode_ExactDealloc"];var __Py_hashtable_new_full=Module["__Py_hashtable_new_full"]=wasmExports["_Py_hashtable_new_full"];var __Py_hashtable_get=Module["__Py_hashtable_get"]=wasmExports["_Py_hashtable_get"];var __Py_hashtable_set=Module["__Py_hashtable_set"]=wasmExports["_Py_hashtable_set"];var __PyUnicode_InternInPlace=Module["__PyUnicode_InternInPlace"]=wasmExports["_PyUnicode_InternInPlace"];var _PyUnicode_InternInPlace=Module["_PyUnicode_InternInPlace"]=wasmExports["PyUnicode_InternInPlace"];var _PyUnicode_InternImmortal=Module["_PyUnicode_InternImmortal"]=wasmExports["PyUnicode_InternImmortal"];var __Py_hashtable_destroy=Module["__Py_hashtable_destroy"]=wasmExports["_Py_hashtable_destroy"];var _PyInit__string=Module["_PyInit__string"]=wasmExports["PyInit__string"];var __PyUnicode_IsLowercase=Module["__PyUnicode_IsLowercase"]=wasmExports["_PyUnicode_IsLowercase"];var __PyUnicode_IsUppercase=Module["__PyUnicode_IsUppercase"]=wasmExports["_PyUnicode_IsUppercase"];var __PyUnicode_IsTitlecase=Module["__PyUnicode_IsTitlecase"]=wasmExports["_PyUnicode_IsTitlecase"];var __PyUnicode_IsDecimalDigit=Module["__PyUnicode_IsDecimalDigit"]=wasmExports["_PyUnicode_IsDecimalDigit"];var __PyUnicode_IsDigit=Module["__PyUnicode_IsDigit"]=wasmExports["_PyUnicode_IsDigit"];var __PyUnicode_IsNumeric=Module["__PyUnicode_IsNumeric"]=wasmExports["_PyUnicode_IsNumeric"];var __PyUnicode_IsAlpha=Module["__PyUnicode_IsAlpha"]=wasmExports["_PyUnicode_IsAlpha"];var __PyUnicode_ToNumeric=Module["__PyUnicode_ToNumeric"]=wasmExports["_PyUnicode_ToNumeric"];var __PyUnicode_ToTitlecase=Module["__PyUnicode_ToTitlecase"]=wasmExports["_PyUnicode_ToTitlecase"];var __PyUnicode_ToDigit=Module["__PyUnicode_ToDigit"]=wasmExports["_PyUnicode_ToDigit"];var __PyUnicode_ToUppercase=Module["__PyUnicode_ToUppercase"]=wasmExports["_PyUnicode_ToUppercase"];var __PyUnicode_ToLowercase=Module["__PyUnicode_ToLowercase"]=wasmExports["_PyUnicode_ToLowercase"];var __PyWeakref_ClearRef=Module["__PyWeakref_ClearRef"]=wasmExports["_PyWeakref_ClearRef"];var _PyWeakref_NewProxy=Module["_PyWeakref_NewProxy"]=wasmExports["PyWeakref_NewProxy"];var _PyWeakref_GetRef=Module["_PyWeakref_GetRef"]=wasmExports["PyWeakref_GetRef"];var _PyWeakref_GetObject=Module["_PyWeakref_GetObject"]=wasmExports["PyWeakref_GetObject"];var _PyUnstable_Object_ClearWeakRefsNoCallbacks=Module["_PyUnstable_Object_ClearWeakRefsNoCallbacks"]=wasmExports["PyUnstable_Object_ClearWeakRefsNoCallbacks"];var __PyWeakref_IsDead=Module["__PyWeakref_IsDead"]=wasmExports["_PyWeakref_IsDead"];var _PyErr_ResourceWarning=Module["_PyErr_ResourceWarning"]=wasmExports["PyErr_ResourceWarning"];var _PyErr_WarnExplicit=Module["_PyErr_WarnExplicit"]=wasmExports["PyErr_WarnExplicit"];var _PyErr_WarnExplicitFormat=Module["_PyErr_WarnExplicitFormat"]=wasmExports["PyErr_WarnExplicitFormat"];var __Py_IsInterpreterFinalizing=Module["__Py_IsInterpreterFinalizing"]=wasmExports["_Py_IsInterpreterFinalizing"];var __PyWarnings_Init=Module["__PyWarnings_Init"]=wasmExports["_PyWarnings_Init"];var _PyThreadState_GetFrame=Module["_PyThreadState_GetFrame"]=wasmExports["PyThreadState_GetFrame"];var __PySys_GetAttr=Module["__PySys_GetAttr"]=wasmExports["_PySys_GetAttr"];var __Py_DisplaySourceLine=Module["__Py_DisplaySourceLine"]=wasmExports["_Py_DisplaySourceLine"];var _PyModule_AddObjectRef=Module["_PyModule_AddObjectRef"]=wasmExports["PyModule_AddObjectRef"];var _PyInit__ast=Module["_PyInit__ast"]=wasmExports["PyInit__ast"];var __PyOnceFlag_CallOnceSlow=Module["__PyOnceFlag_CallOnceSlow"]=wasmExports["_PyOnceFlag_CallOnceSlow"];var _PyModule_AddIntConstant=Module["_PyModule_AddIntConstant"]=wasmExports["PyModule_AddIntConstant"];var _PyInit__tokenize=Module["_PyInit__tokenize"]=wasmExports["PyInit__tokenize"];var _PyModule_AddType=Module["_PyModule_AddType"]=wasmExports["PyModule_AddType"];var _PyErr_SyntaxLocationObject=Module["_PyErr_SyntaxLocationObject"]=wasmExports["PyErr_SyntaxLocationObject"];var _PyImport_ImportModuleLevelObject=Module["_PyImport_ImportModuleLevelObject"]=wasmExports["PyImport_ImportModuleLevelObject"];var _PyEval_MergeCompilerFlags=Module["_PyEval_MergeCompilerFlags"]=wasmExports["PyEval_MergeCompilerFlags"];var __PyArena_New=Module["__PyArena_New"]=wasmExports["_PyArena_New"];var __PyArena_Free=Module["__PyArena_Free"]=wasmExports["_PyArena_Free"];var __PyAST_Compile=Module["__PyAST_Compile"]=wasmExports["_PyAST_Compile"];var _Py_CompileStringObject=Module["_Py_CompileStringObject"]=wasmExports["Py_CompileStringObject"];var _PyEval_GetBuiltins=Module["_PyEval_GetBuiltins"]=wasmExports["PyEval_GetBuiltins"];var _PyEval_EvalCode=Module["_PyEval_EvalCode"]=wasmExports["PyEval_EvalCode"];var _PyRun_StringFlags=Module["_PyRun_StringFlags"]=wasmExports["PyRun_StringFlags"];var _PyEval_EvalCodeEx=Module["_PyEval_EvalCodeEx"]=wasmExports["PyEval_EvalCodeEx"];var _Py_GetRecursionLimit=Module["_Py_GetRecursionLimit"]=wasmExports["Py_GetRecursionLimit"];var _Py_SetRecursionLimit=Module["_Py_SetRecursionLimit"]=wasmExports["Py_SetRecursionLimit"];var __PyEval_MatchKeys=Module["__PyEval_MatchKeys"]=wasmExports["_PyEval_MatchKeys"];var __PyEval_MatchClass=Module["__PyEval_MatchClass"]=wasmExports["_PyEval_MatchClass"];var __PyEvalFramePushAndInit=Module["__PyEvalFramePushAndInit"]=wasmExports["_PyEvalFramePushAndInit"];var _PyEval_EvalFrame=Module["_PyEval_EvalFrame"]=wasmExports["PyEval_EvalFrame"];var _PyEval_EvalFrameEx=Module["_PyEval_EvalFrameEx"]=wasmExports["PyEval_EvalFrameEx"];var __PyEval_FrameClearAndPop=Module["__PyEval_FrameClearAndPop"]=wasmExports["_PyEval_FrameClearAndPop"];var _PyTraceBack_Here=Module["_PyTraceBack_Here"]=wasmExports["PyTraceBack_Here"];var __Py_HandlePending=Module["__Py_HandlePending"]=wasmExports["_Py_HandlePending"];var __PyEval_CheckExceptStarTypeValid=Module["__PyEval_CheckExceptStarTypeValid"]=wasmExports["_PyEval_CheckExceptStarTypeValid"];var __PyEval_ExceptionGroupMatch=Module["__PyEval_ExceptionGroupMatch"]=wasmExports["_PyEval_ExceptionGroupMatch"];var _PyErr_SetHandledException=Module["_PyErr_SetHandledException"]=wasmExports["PyErr_SetHandledException"];var __PyEval_FormatExcCheckArg=Module["__PyEval_FormatExcCheckArg"]=wasmExports["_PyEval_FormatExcCheckArg"];var __PyEval_FormatKwargsError=Module["__PyEval_FormatKwargsError"]=wasmExports["_PyEval_FormatKwargsError"];var __PyEval_FormatExcUnbound=Module["__PyEval_FormatExcUnbound"]=wasmExports["_PyEval_FormatExcUnbound"];var __PyThreadState_PopFrame=Module["__PyThreadState_PopFrame"]=wasmExports["_PyThreadState_PopFrame"];var __PyEval_UnpackIterable=Module["__PyEval_UnpackIterable"]=wasmExports["_PyEval_UnpackIterable"];var __PyEval_CheckExceptTypeValid=Module["__PyEval_CheckExceptTypeValid"]=wasmExports["_PyEval_CheckExceptTypeValid"];var __PyEval_MonitorRaise=Module["__PyEval_MonitorRaise"]=wasmExports["_PyEval_MonitorRaise"];var __PyEval_FormatAwaitableError=Module["__PyEval_FormatAwaitableError"]=wasmExports["_PyEval_FormatAwaitableError"];var _PyThreadState_EnterTracing=Module["_PyThreadState_EnterTracing"]=wasmExports["PyThreadState_EnterTracing"];var _PyThreadState_LeaveTracing=Module["_PyThreadState_LeaveTracing"]=wasmExports["PyThreadState_LeaveTracing"];var _PyEval_SetProfile=Module["_PyEval_SetProfile"]=wasmExports["PyEval_SetProfile"];var __PyEval_SetProfile=Module["__PyEval_SetProfile"]=wasmExports["_PyEval_SetProfile"];var _PyEval_SetProfileAllThreads=Module["_PyEval_SetProfileAllThreads"]=wasmExports["PyEval_SetProfileAllThreads"];var _PyInterpreterState_ThreadHead=Module["_PyInterpreterState_ThreadHead"]=wasmExports["PyInterpreterState_ThreadHead"];var _PyThreadState_Next=Module["_PyThreadState_Next"]=wasmExports["PyThreadState_Next"];var _PyEval_SetTrace=Module["_PyEval_SetTrace"]=wasmExports["PyEval_SetTrace"];var _PyEval_SetTraceAllThreads=Module["_PyEval_SetTraceAllThreads"]=wasmExports["PyEval_SetTraceAllThreads"];var _PyEval_GetFrame=Module["_PyEval_GetFrame"]=wasmExports["PyEval_GetFrame"];var _PyEval_GetLocals=Module["_PyEval_GetLocals"]=wasmExports["PyEval_GetLocals"];var _PyEval_GetFrameLocals=Module["_PyEval_GetFrameLocals"]=wasmExports["PyEval_GetFrameLocals"];var _PyEval_GetFrameGlobals=Module["_PyEval_GetFrameGlobals"]=wasmExports["PyEval_GetFrameGlobals"];var _PyEval_GetFrameBuiltins=Module["_PyEval_GetFrameBuiltins"]=wasmExports["PyEval_GetFrameBuiltins"];var _PyEval_GetFuncName=Module["_PyEval_GetFuncName"]=wasmExports["PyEval_GetFuncName"];var _PyEval_GetFuncDesc=Module["_PyEval_GetFuncDesc"]=wasmExports["PyEval_GetFuncDesc"];var _PyUnstable_Eval_RequestCodeExtraIndex=Module["_PyUnstable_Eval_RequestCodeExtraIndex"]=wasmExports["PyUnstable_Eval_RequestCodeExtraIndex"];var _PyCodec_Register=Module["_PyCodec_Register"]=wasmExports["PyCodec_Register"];var _PyCodec_Unregister=Module["_PyCodec_Unregister"]=wasmExports["PyCodec_Unregister"];var _PyCodec_KnownEncoding=Module["_PyCodec_KnownEncoding"]=wasmExports["PyCodec_KnownEncoding"];var _PyCodec_Encoder=Module["_PyCodec_Encoder"]=wasmExports["PyCodec_Encoder"];var _PyCodec_Decoder=Module["_PyCodec_Decoder"]=wasmExports["PyCodec_Decoder"];var _PyCodec_IncrementalEncoder=Module["_PyCodec_IncrementalEncoder"]=wasmExports["PyCodec_IncrementalEncoder"];var _PyCodec_IncrementalDecoder=Module["_PyCodec_IncrementalDecoder"]=wasmExports["PyCodec_IncrementalDecoder"];var _PyCodec_StreamReader=Module["_PyCodec_StreamReader"]=wasmExports["PyCodec_StreamReader"];var _PyCodec_StreamWriter=Module["_PyCodec_StreamWriter"]=wasmExports["PyCodec_StreamWriter"];var _PyCodec_RegisterError=Module["_PyCodec_RegisterError"]=wasmExports["PyCodec_RegisterError"];var _PyCodec_IgnoreErrors=Module["_PyCodec_IgnoreErrors"]=wasmExports["PyCodec_IgnoreErrors"];var _PyCodec_ReplaceErrors=Module["_PyCodec_ReplaceErrors"]=wasmExports["PyCodec_ReplaceErrors"];var _PyCodec_XMLCharRefReplaceErrors=Module["_PyCodec_XMLCharRefReplaceErrors"]=wasmExports["PyCodec_XMLCharRefReplaceErrors"];var _PyCodec_BackslashReplaceErrors=Module["_PyCodec_BackslashReplaceErrors"]=wasmExports["PyCodec_BackslashReplaceErrors"];var _PyCodec_NameReplaceErrors=Module["_PyCodec_NameReplaceErrors"]=wasmExports["PyCodec_NameReplaceErrors"];var _PyStatus_NoMemory=Module["_PyStatus_NoMemory"]=wasmExports["PyStatus_NoMemory"];var _PyStatus_Error=Module["_PyStatus_Error"]=wasmExports["PyStatus_Error"];var _PyStatus_Ok=Module["_PyStatus_Ok"]=wasmExports["PyStatus_Ok"];var _PyCompile_OpcodeStackEffectWithJump=Module["_PyCompile_OpcodeStackEffectWithJump"]=wasmExports["PyCompile_OpcodeStackEffectWithJump"];var __PyCompile_OpcodeIsValid=Module["__PyCompile_OpcodeIsValid"]=wasmExports["_PyCompile_OpcodeIsValid"];var __PyCompile_OpcodeHasArg=Module["__PyCompile_OpcodeHasArg"]=wasmExports["_PyCompile_OpcodeHasArg"];var __PyCompile_OpcodeHasConst=Module["__PyCompile_OpcodeHasConst"]=wasmExports["_PyCompile_OpcodeHasConst"];var __PyCompile_OpcodeHasName=Module["__PyCompile_OpcodeHasName"]=wasmExports["_PyCompile_OpcodeHasName"];var __PyCompile_OpcodeHasJump=Module["__PyCompile_OpcodeHasJump"]=wasmExports["_PyCompile_OpcodeHasJump"];var __PyCompile_OpcodeHasFree=Module["__PyCompile_OpcodeHasFree"]=wasmExports["_PyCompile_OpcodeHasFree"];var __PyCompile_OpcodeHasLocal=Module["__PyCompile_OpcodeHasLocal"]=wasmExports["_PyCompile_OpcodeHasLocal"];var __PyCompile_OpcodeHasExc=Module["__PyCompile_OpcodeHasExc"]=wasmExports["_PyCompile_OpcodeHasExc"];var __PyCompile_CleanDoc=Module["__PyCompile_CleanDoc"]=wasmExports["_PyCompile_CleanDoc"];var __PyCompile_CodeGen=Module["__PyCompile_CodeGen"]=wasmExports["_PyCompile_CodeGen"];var __PyCompile_OptimizeCfg=Module["__PyCompile_OptimizeCfg"]=wasmExports["_PyCompile_OptimizeCfg"];var __PyInstructionSequence_New=Module["__PyInstructionSequence_New"]=wasmExports["_PyInstructionSequence_New"];var __PyCompile_Assemble=Module["__PyCompile_Assemble"]=wasmExports["_PyCompile_Assemble"];var _PyCode_Optimize=Module["_PyCode_Optimize"]=wasmExports["PyCode_Optimize"];var _PyErr_ProgramTextObject=Module["_PyErr_ProgramTextObject"]=wasmExports["PyErr_ProgramTextObject"];var __PyContext_NewHamtForTests=Module["__PyContext_NewHamtForTests"]=wasmExports["_PyContext_NewHamtForTests"];var _PyContext_New=Module["_PyContext_New"]=wasmExports["PyContext_New"];var _PyContext_Copy=Module["_PyContext_Copy"]=wasmExports["PyContext_Copy"];var _PyContext_CopyCurrent=Module["_PyContext_CopyCurrent"]=wasmExports["PyContext_CopyCurrent"];var _PyContext_Enter=Module["_PyContext_Enter"]=wasmExports["PyContext_Enter"];var _PyContext_Exit=Module["_PyContext_Exit"]=wasmExports["PyContext_Exit"];var _PyContextVar_New=Module["_PyContextVar_New"]=wasmExports["PyContextVar_New"];var _PyContextVar_Get=Module["_PyContextVar_Get"]=wasmExports["PyContextVar_Get"];var _PyContextVar_Set=Module["_PyContextVar_Set"]=wasmExports["PyContextVar_Set"];var _PyContextVar_Reset=Module["_PyContextVar_Reset"]=wasmExports["PyContextVar_Reset"];var __PyCriticalSection_BeginSlow=Module["__PyCriticalSection_BeginSlow"]=wasmExports["_PyCriticalSection_BeginSlow"];var __PyCriticalSection2_BeginSlow=Module["__PyCriticalSection2_BeginSlow"]=wasmExports["_PyCriticalSection2_BeginSlow"];var __PyCriticalSection_SuspendAll=Module["__PyCriticalSection_SuspendAll"]=wasmExports["_PyCriticalSection_SuspendAll"];var __PyCriticalSection_Resume=Module["__PyCriticalSection_Resume"]=wasmExports["_PyCriticalSection_Resume"];var _PyCriticalSection_Begin=Module["_PyCriticalSection_Begin"]=wasmExports["PyCriticalSection_Begin"];var _PyCriticalSection_End=Module["_PyCriticalSection_End"]=wasmExports["PyCriticalSection_End"];var _PyCriticalSection2_Begin=Module["_PyCriticalSection2_Begin"]=wasmExports["PyCriticalSection2_Begin"];var _PyCriticalSection2_End=Module["_PyCriticalSection2_End"]=wasmExports["PyCriticalSection2_End"];var __PyEval_AddPendingCall=Module["__PyEval_AddPendingCall"]=wasmExports["_PyEval_AddPendingCall"];var __PyCrossInterpreterData_Lookup=Module["__PyCrossInterpreterData_Lookup"]=wasmExports["_PyCrossInterpreterData_Lookup"];var __PyCrossInterpreterData_RegisterClass=Module["__PyCrossInterpreterData_RegisterClass"]=wasmExports["_PyCrossInterpreterData_RegisterClass"];var __PyCrossInterpreterData_UnregisterClass=Module["__PyCrossInterpreterData_UnregisterClass"]=wasmExports["_PyCrossInterpreterData_UnregisterClass"];var __PyCrossInterpreterData_New=Module["__PyCrossInterpreterData_New"]=wasmExports["_PyCrossInterpreterData_New"];var __PyCrossInterpreterData_Free=Module["__PyCrossInterpreterData_Free"]=wasmExports["_PyCrossInterpreterData_Free"];var __PyCrossInterpreterData_Clear=Module["__PyCrossInterpreterData_Clear"]=wasmExports["_PyCrossInterpreterData_Clear"];var __PyCrossInterpreterData_Init=Module["__PyCrossInterpreterData_Init"]=wasmExports["_PyCrossInterpreterData_Init"];var _PyInterpreterState_GetID=Module["_PyInterpreterState_GetID"]=wasmExports["PyInterpreterState_GetID"];var __PyCrossInterpreterData_InitWithSize=Module["__PyCrossInterpreterData_InitWithSize"]=wasmExports["_PyCrossInterpreterData_InitWithSize"];var __PyObject_CheckCrossInterpreterData=Module["__PyObject_CheckCrossInterpreterData"]=wasmExports["_PyObject_CheckCrossInterpreterData"];var __PyObject_GetCrossInterpreterData=Module["__PyObject_GetCrossInterpreterData"]=wasmExports["_PyObject_GetCrossInterpreterData"];var __PyCrossInterpreterData_Release=Module["__PyCrossInterpreterData_Release"]=wasmExports["_PyCrossInterpreterData_Release"];var __PyCrossInterpreterData_NewObject=Module["__PyCrossInterpreterData_NewObject"]=wasmExports["_PyCrossInterpreterData_NewObject"];var __PyInterpreterState_LookUpID=Module["__PyInterpreterState_LookUpID"]=wasmExports["_PyInterpreterState_LookUpID"];var __PyCrossInterpreterData_ReleaseAndRawFree=Module["__PyCrossInterpreterData_ReleaseAndRawFree"]=wasmExports["_PyCrossInterpreterData_ReleaseAndRawFree"];var __PyXI_InitExcInfo=Module["__PyXI_InitExcInfo"]=wasmExports["_PyXI_InitExcInfo"];var __PyXI_FormatExcInfo=Module["__PyXI_FormatExcInfo"]=wasmExports["_PyXI_FormatExcInfo"];var __PyXI_ExcInfoAsObject=Module["__PyXI_ExcInfoAsObject"]=wasmExports["_PyXI_ExcInfoAsObject"];var __PyXI_ClearExcInfo=Module["__PyXI_ClearExcInfo"]=wasmExports["_PyXI_ClearExcInfo"];var __PyXI_ApplyError=Module["__PyXI_ApplyError"]=wasmExports["_PyXI_ApplyError"];var __PyXI_FreeNamespace=Module["__PyXI_FreeNamespace"]=wasmExports["_PyXI_FreeNamespace"];var __PyXI_NamespaceFromNames=Module["__PyXI_NamespaceFromNames"]=wasmExports["_PyXI_NamespaceFromNames"];var __PyXI_FillNamespaceFromDict=Module["__PyXI_FillNamespaceFromDict"]=wasmExports["_PyXI_FillNamespaceFromDict"];var __PyXI_ApplyNamespace=Module["__PyXI_ApplyNamespace"]=wasmExports["_PyXI_ApplyNamespace"];var __PyXI_ApplyCapturedException=Module["__PyXI_ApplyCapturedException"]=wasmExports["_PyXI_ApplyCapturedException"];var __PyXI_HasCapturedException=Module["__PyXI_HasCapturedException"]=wasmExports["_PyXI_HasCapturedException"];var __PyXI_Enter=Module["__PyXI_Enter"]=wasmExports["_PyXI_Enter"];var __PyThreadState_NewBound=Module["__PyThreadState_NewBound"]=wasmExports["_PyThreadState_NewBound"];var __PyInterpreterState_SetRunningMain=Module["__PyInterpreterState_SetRunningMain"]=wasmExports["_PyInterpreterState_SetRunningMain"];var _PyUnstable_InterpreterState_GetMainModule=Module["_PyUnstable_InterpreterState_GetMainModule"]=wasmExports["PyUnstable_InterpreterState_GetMainModule"];var __PyInterpreterState_SetNotRunningMain=Module["__PyInterpreterState_SetNotRunningMain"]=wasmExports["_PyInterpreterState_SetNotRunningMain"];var _PyThreadState_Clear=Module["_PyThreadState_Clear"]=wasmExports["PyThreadState_Clear"];var __PyXI_Exit=Module["__PyXI_Exit"]=wasmExports["_PyXI_Exit"];var _PyErr_PrintEx=Module["_PyErr_PrintEx"]=wasmExports["PyErr_PrintEx"];var __PyXI_NewInterpreter=Module["__PyXI_NewInterpreter"]=wasmExports["_PyXI_NewInterpreter"];var _Py_NewInterpreterFromConfig=Module["_Py_NewInterpreterFromConfig"]=wasmExports["Py_NewInterpreterFromConfig"];var __PyErr_SetFromPyStatus=Module["__PyErr_SetFromPyStatus"]=wasmExports["_PyErr_SetFromPyStatus"];var _PyThreadState_GetInterpreter=Module["_PyThreadState_GetInterpreter"]=wasmExports["PyThreadState_GetInterpreter"];var __PyXI_EndInterpreter=Module["__PyXI_EndInterpreter"]=wasmExports["_PyXI_EndInterpreter"];var __PyInterpreterState_IsReady=Module["__PyInterpreterState_IsReady"]=wasmExports["_PyInterpreterState_IsReady"];var _PyInterpreterState_Delete=Module["_PyInterpreterState_Delete"]=wasmExports["PyInterpreterState_Delete"];var _Py_EndInterpreter=Module["_Py_EndInterpreter"]=wasmExports["Py_EndInterpreter"];var __PyErr_SetLocaleString=Module["__PyErr_SetLocaleString"]=wasmExports["_PyErr_SetLocaleString"];var _PyErr_GetHandledException=Module["_PyErr_GetHandledException"]=wasmExports["PyErr_GetHandledException"];var _PyErr_GetExcInfo=Module["_PyErr_GetExcInfo"]=wasmExports["PyErr_GetExcInfo"];var _PyErr_SetExcInfo=Module["_PyErr_SetExcInfo"]=wasmExports["PyErr_SetExcInfo"];var _PyErr_SetFromErrnoWithFilenameObject=Module["_PyErr_SetFromErrnoWithFilenameObject"]=wasmExports["PyErr_SetFromErrnoWithFilenameObject"];var _PyErr_SetFromErrnoWithFilenameObjects=Module["_PyErr_SetFromErrnoWithFilenameObjects"]=wasmExports["PyErr_SetFromErrnoWithFilenameObjects"];var _strerror=wasmExports["strerror"];var _PyErr_SetImportErrorSubclass=Module["_PyErr_SetImportErrorSubclass"]=wasmExports["PyErr_SetImportErrorSubclass"];var _PyErr_SetImportError=Module["_PyErr_SetImportError"]=wasmExports["PyErr_SetImportError"];var _PyErr_BadInternalCall=Module["_PyErr_BadInternalCall"]=wasmExports["PyErr_BadInternalCall"];var _PyErr_FormatV=Module["_PyErr_FormatV"]=wasmExports["PyErr_FormatV"];var _PyErr_NewExceptionWithDoc=Module["_PyErr_NewExceptionWithDoc"]=wasmExports["PyErr_NewExceptionWithDoc"];var _PyTraceBack_Print=Module["_PyTraceBack_Print"]=wasmExports["PyTraceBack_Print"];var _PyErr_SyntaxLocation=Module["_PyErr_SyntaxLocation"]=wasmExports["PyErr_SyntaxLocation"];var _PyErr_SyntaxLocationEx=Module["_PyErr_SyntaxLocationEx"]=wasmExports["PyErr_SyntaxLocationEx"];var _PyErr_RangedSyntaxLocationObject=Module["_PyErr_RangedSyntaxLocationObject"]=wasmExports["PyErr_RangedSyntaxLocationObject"];var _PyErr_ProgramText=Module["_PyErr_ProgramText"]=wasmExports["PyErr_ProgramText"];var __Py_fopen_obj=Module["__Py_fopen_obj"]=wasmExports["_Py_fopen_obj"];var _PyUnstable_InterpreterFrame_GetCode=Module["_PyUnstable_InterpreterFrame_GetCode"]=wasmExports["PyUnstable_InterpreterFrame_GetCode"];var _PyUnstable_InterpreterFrame_GetLasti=Module["_PyUnstable_InterpreterFrame_GetLasti"]=wasmExports["PyUnstable_InterpreterFrame_GetLasti"];var _Py_FrozenMain=Module["_Py_FrozenMain"]=wasmExports["Py_FrozenMain"];var _Py_GETENV=Module["_Py_GETENV"]=wasmExports["Py_GETENV"];var _Py_GetVersion=Module["_Py_GetVersion"]=wasmExports["Py_GetVersion"];var _Py_GetCopyright=Module["_Py_GetCopyright"]=wasmExports["Py_GetCopyright"];var _PyImport_ImportFrozenModule=Module["_PyImport_ImportFrozenModule"]=wasmExports["PyImport_ImportFrozenModule"];var _PyRun_AnyFileExFlags=Module["_PyRun_AnyFileExFlags"]=wasmExports["PyRun_AnyFileExFlags"];var _Py_FinalizeEx=Module["_Py_FinalizeEx"]=wasmExports["Py_FinalizeEx"];var _PyGC_Enable=Module["_PyGC_Enable"]=wasmExports["PyGC_Enable"];var _PyGC_Disable=Module["_PyGC_Disable"]=wasmExports["PyGC_Disable"];var _PyGC_IsEnabled=Module["_PyGC_IsEnabled"]=wasmExports["PyGC_IsEnabled"];var _PyGC_Collect=Module["_PyGC_Collect"]=wasmExports["PyGC_Collect"];var _PyTime_PerfCounterRaw=Module["_PyTime_PerfCounterRaw"]=wasmExports["PyTime_PerfCounterRaw"];var _PyTime_AsSecondsDouble=Module["_PyTime_AsSecondsDouble"]=wasmExports["PyTime_AsSecondsDouble"];var _PyUnstable_Object_GC_NewWithExtraData=Module["_PyUnstable_Object_GC_NewWithExtraData"]=wasmExports["PyUnstable_Object_GC_NewWithExtraData"];var _PyObject_GC_IsTracked=Module["_PyObject_GC_IsTracked"]=wasmExports["PyObject_GC_IsTracked"];var _PyObject_GC_IsFinalized=Module["_PyObject_GC_IsFinalized"]=wasmExports["PyObject_GC_IsFinalized"];var _PyUnstable_GC_VisitObjects=Module["_PyUnstable_GC_VisitObjects"]=wasmExports["PyUnstable_GC_VisitObjects"];var _PyArg_Parse=Module["_PyArg_Parse"]=wasmExports["PyArg_Parse"];var __PyArg_Parse_SizeT=Module["__PyArg_Parse_SizeT"]=wasmExports["_PyArg_Parse_SizeT"];var __PyArg_ParseTuple_SizeT=Module["__PyArg_ParseTuple_SizeT"]=wasmExports["_PyArg_ParseTuple_SizeT"];var _PyArg_VaParse=Module["_PyArg_VaParse"]=wasmExports["PyArg_VaParse"];var __PyArg_VaParse_SizeT=Module["__PyArg_VaParse_SizeT"]=wasmExports["_PyArg_VaParse_SizeT"];var __PyArg_ParseTupleAndKeywords_SizeT=Module["__PyArg_ParseTupleAndKeywords_SizeT"]=wasmExports["_PyArg_ParseTupleAndKeywords_SizeT"];var _PyArg_VaParseTupleAndKeywords=Module["_PyArg_VaParseTupleAndKeywords"]=wasmExports["PyArg_VaParseTupleAndKeywords"];var __PyArg_VaParseTupleAndKeywords_SizeT=Module["__PyArg_VaParseTupleAndKeywords_SizeT"]=wasmExports["_PyArg_VaParseTupleAndKeywords_SizeT"];var __PyArg_ParseTupleAndKeywordsFast=Module["__PyArg_ParseTupleAndKeywordsFast"]=wasmExports["_PyArg_ParseTupleAndKeywordsFast"];var _Py_GetCompiler=Module["_Py_GetCompiler"]=wasmExports["Py_GetCompiler"];var _Py_GetPlatform=Module["_Py_GetPlatform"]=wasmExports["Py_GetPlatform"];var _PyEval_ThreadsInitialized=Module["_PyEval_ThreadsInitialized"]=wasmExports["PyEval_ThreadsInitialized"];var _PyThread_init_thread=Module["_PyThread_init_thread"]=wasmExports["PyThread_init_thread"];var _pthread_cond_destroy=Module["_pthread_cond_destroy"]=wasmExports["pthread_cond_destroy"];var _pthread_mutex_destroy=Module["_pthread_mutex_destroy"]=wasmExports["pthread_mutex_destroy"];var _PyEval_InitThreads=Module["_PyEval_InitThreads"]=wasmExports["PyEval_InitThreads"];var _PyEval_AcquireLock=Module["_PyEval_AcquireLock"]=wasmExports["PyEval_AcquireLock"];var _pthread_mutex_lock=Module["_pthread_mutex_lock"]=wasmExports["pthread_mutex_lock"];var _pthread_cond_timedwait=Module["_pthread_cond_timedwait"]=wasmExports["pthread_cond_timedwait"];var _pthread_mutex_unlock=Module["_pthread_mutex_unlock"]=wasmExports["pthread_mutex_unlock"];var _pthread_cond_signal=Module["_pthread_cond_signal"]=wasmExports["pthread_cond_signal"];var _PyThread_exit_thread=Module["_PyThread_exit_thread"]=wasmExports["PyThread_exit_thread"];var _PyThread_get_thread_ident=Module["_PyThread_get_thread_ident"]=wasmExports["PyThread_get_thread_ident"];var _PyEval_ReleaseLock=Module["_PyEval_ReleaseLock"]=wasmExports["PyEval_ReleaseLock"];var _pthread_cond_wait=Module["_pthread_cond_wait"]=wasmExports["pthread_cond_wait"];var _PyEval_AcquireThread=Module["_PyEval_AcquireThread"]=wasmExports["PyEval_AcquireThread"];var _PyEval_ReleaseThread=Module["_PyEval_ReleaseThread"]=wasmExports["PyEval_ReleaseThread"];var _Py_AddPendingCall=Module["_Py_AddPendingCall"]=wasmExports["Py_AddPendingCall"];var __PyEval_MakePendingCalls=Module["__PyEval_MakePendingCalls"]=wasmExports["_PyEval_MakePendingCalls"];var _Py_MakePendingCalls=Module["_Py_MakePendingCalls"]=wasmExports["Py_MakePendingCalls"];var _pthread_mutex_init=Module["_pthread_mutex_init"]=wasmExports["pthread_mutex_init"];var __Py_hashtable_hash_ptr=Module["__Py_hashtable_hash_ptr"]=wasmExports["_Py_hashtable_hash_ptr"];var __Py_hashtable_compare_direct=Module["__Py_hashtable_compare_direct"]=wasmExports["_Py_hashtable_compare_direct"];var __Py_hashtable_size=Module["__Py_hashtable_size"]=wasmExports["_Py_hashtable_size"];var __Py_hashtable_steal=Module["__Py_hashtable_steal"]=wasmExports["_Py_hashtable_steal"];var __Py_hashtable_foreach=Module["__Py_hashtable_foreach"]=wasmExports["_Py_hashtable_foreach"];var __Py_hashtable_new=Module["__Py_hashtable_new"]=wasmExports["_Py_hashtable_new"];var __Py_hashtable_clear=Module["__Py_hashtable_clear"]=wasmExports["_Py_hashtable_clear"];var __PyRecursiveMutex_Lock=Module["__PyRecursiveMutex_Lock"]=wasmExports["_PyRecursiveMutex_Lock"];var __PyRecursiveMutex_Unlock=Module["__PyRecursiveMutex_Unlock"]=wasmExports["_PyRecursiveMutex_Unlock"];var _PyThread_get_thread_ident_ex=Module["_PyThread_get_thread_ident_ex"]=wasmExports["PyThread_get_thread_ident_ex"];var __PyImport_SetModule=Module["__PyImport_SetModule"]=wasmExports["_PyImport_SetModule"];var _PyImport_AddModuleRef=Module["_PyImport_AddModuleRef"]=wasmExports["PyImport_AddModuleRef"];var _PyImport_AddModuleObject=Module["_PyImport_AddModuleObject"]=wasmExports["PyImport_AddModuleObject"];var _PyImport_AddModule=Module["_PyImport_AddModule"]=wasmExports["PyImport_AddModule"];var _PyState_FindModule=Module["_PyState_FindModule"]=wasmExports["PyState_FindModule"];var __PyState_AddModule=Module["__PyState_AddModule"]=wasmExports["_PyState_AddModule"];var _PyState_AddModule=Module["_PyState_AddModule"]=wasmExports["PyState_AddModule"];var _PyState_RemoveModule=Module["_PyState_RemoveModule"]=wasmExports["PyState_RemoveModule"];var __PyImport_ClearExtension=Module["__PyImport_ClearExtension"]=wasmExports["_PyImport_ClearExtension"];var _PyImport_ExtendInittab=Module["_PyImport_ExtendInittab"]=wasmExports["PyImport_ExtendInittab"];var _PyImport_GetMagicNumber=Module["_PyImport_GetMagicNumber"]=wasmExports["PyImport_GetMagicNumber"];var _PyImport_GetMagicTag=Module["_PyImport_GetMagicTag"]=wasmExports["PyImport_GetMagicTag"];var _PyImport_ExecCodeModule=Module["_PyImport_ExecCodeModule"]=wasmExports["PyImport_ExecCodeModule"];var _PyImport_ExecCodeModuleObject=Module["_PyImport_ExecCodeModuleObject"]=wasmExports["PyImport_ExecCodeModuleObject"];var _PyImport_ExecCodeModuleWithPathnames=Module["_PyImport_ExecCodeModuleWithPathnames"]=wasmExports["PyImport_ExecCodeModuleWithPathnames"];var _PyImport_ExecCodeModuleEx=Module["_PyImport_ExecCodeModuleEx"]=wasmExports["PyImport_ExecCodeModuleEx"];var _PyImport_ImportFrozenModuleObject=Module["_PyImport_ImportFrozenModuleObject"]=wasmExports["PyImport_ImportFrozenModuleObject"];var _PyMarshal_ReadObjectFromString=Module["_PyMarshal_ReadObjectFromString"]=wasmExports["PyMarshal_ReadObjectFromString"];var _PyImport_GetImporter=Module["_PyImport_GetImporter"]=wasmExports["PyImport_GetImporter"];var _PyImport_ImportModuleNoBlock=Module["_PyImport_ImportModuleNoBlock"]=wasmExports["PyImport_ImportModuleNoBlock"];var __PyTime_AsMicroseconds=Module["__PyTime_AsMicroseconds"]=wasmExports["_PyTime_AsMicroseconds"];var _PyImport_ImportModuleLevel=Module["_PyImport_ImportModuleLevel"]=wasmExports["PyImport_ImportModuleLevel"];var _PyImport_ReloadModule=Module["_PyImport_ReloadModule"]=wasmExports["PyImport_ReloadModule"];var __PyImport_GetModuleAttr=Module["__PyImport_GetModuleAttr"]=wasmExports["_PyImport_GetModuleAttr"];var _PyInit__imp=Module["_PyInit__imp"]=wasmExports["PyInit__imp"];var __PyRecursiveMutex_IsLockedByCurrentThread=Module["__PyRecursiveMutex_IsLockedByCurrentThread"]=wasmExports["_PyRecursiveMutex_IsLockedByCurrentThread"];var _PyModule_Add=Module["_PyModule_Add"]=wasmExports["PyModule_Add"];var _PyStatus_Exit=Module["_PyStatus_Exit"]=wasmExports["PyStatus_Exit"];var _PyStatus_IsError=Module["_PyStatus_IsError"]=wasmExports["PyStatus_IsError"];var _PyStatus_IsExit=Module["_PyStatus_IsExit"]=wasmExports["PyStatus_IsExit"];var _PyWideStringList_Insert=Module["_PyWideStringList_Insert"]=wasmExports["PyWideStringList_Insert"];var _PyWideStringList_Append=Module["_PyWideStringList_Append"]=wasmExports["PyWideStringList_Append"];var _Py_GetArgcArgv=Module["_Py_GetArgcArgv"]=wasmExports["Py_GetArgcArgv"];var __PyConfig_InitCompatConfig=Module["__PyConfig_InitCompatConfig"]=wasmExports["_PyConfig_InitCompatConfig"];var _PyConfig_InitIsolatedConfig=Module["_PyConfig_InitIsolatedConfig"]=wasmExports["PyConfig_InitIsolatedConfig"];var _PyConfig_SetString=Module["_PyConfig_SetString"]=wasmExports["PyConfig_SetString"];var _Py_DecodeLocale=Module["_Py_DecodeLocale"]=wasmExports["Py_DecodeLocale"];var __PyConfig_AsDict=Module["__PyConfig_AsDict"]=wasmExports["_PyConfig_AsDict"];var __PyConfig_FromDict=Module["__PyConfig_FromDict"]=wasmExports["_PyConfig_FromDict"];var _wcschr=Module["_wcschr"]=wasmExports["wcschr"];var _setvbuf=Module["_setvbuf"]=wasmExports["setvbuf"];var _PyConfig_SetArgv=Module["_PyConfig_SetArgv"]=wasmExports["PyConfig_SetArgv"];var _PyConfig_SetWideStringList=Module["_PyConfig_SetWideStringList"]=wasmExports["PyConfig_SetWideStringList"];var _putchar=Module["_putchar"]=wasmExports["putchar"];var _iprintf=Module["_iprintf"]=wasmExports["iprintf"];var _wcstok=Module["_wcstok"]=wasmExports["wcstok"];var _strtoul=Module["_strtoul"]=wasmExports["strtoul"];var _wcstol=Module["_wcstol"]=wasmExports["wcstol"];var _setlocale=Module["_setlocale"]=wasmExports["setlocale"];var _PyConfig_Read=Module["_PyConfig_Read"]=wasmExports["PyConfig_Read"];var __Py_GetConfigsAsDict=Module["__Py_GetConfigsAsDict"]=wasmExports["_Py_GetConfigsAsDict"];var __PyInterpreterConfig_AsDict=Module["__PyInterpreterConfig_AsDict"]=wasmExports["_PyInterpreterConfig_AsDict"];var __PyInterpreterConfig_InitFromDict=Module["__PyInterpreterConfig_InitFromDict"]=wasmExports["_PyInterpreterConfig_InitFromDict"];var __PyInterpreterConfig_UpdateFromDict=Module["__PyInterpreterConfig_UpdateFromDict"]=wasmExports["_PyInterpreterConfig_UpdateFromDict"];var __PyInterpreterConfig_InitFromState=Module["__PyInterpreterConfig_InitFromState"]=wasmExports["_PyInterpreterConfig_InitFromState"];var _PyMonitoring_EnterScope=Module["_PyMonitoring_EnterScope"]=wasmExports["PyMonitoring_EnterScope"];var _PyMonitoring_ExitScope=Module["_PyMonitoring_ExitScope"]=wasmExports["PyMonitoring_ExitScope"];var __PyMonitoring_FirePyStartEvent=Module["__PyMonitoring_FirePyStartEvent"]=wasmExports["_PyMonitoring_FirePyStartEvent"];var __PyMonitoring_FirePyResumeEvent=Module["__PyMonitoring_FirePyResumeEvent"]=wasmExports["_PyMonitoring_FirePyResumeEvent"];var __PyMonitoring_FirePyReturnEvent=Module["__PyMonitoring_FirePyReturnEvent"]=wasmExports["_PyMonitoring_FirePyReturnEvent"];var __PyMonitoring_FirePyYieldEvent=Module["__PyMonitoring_FirePyYieldEvent"]=wasmExports["_PyMonitoring_FirePyYieldEvent"];var __PyMonitoring_FireCallEvent=Module["__PyMonitoring_FireCallEvent"]=wasmExports["_PyMonitoring_FireCallEvent"];var __PyMonitoring_FireLineEvent=Module["__PyMonitoring_FireLineEvent"]=wasmExports["_PyMonitoring_FireLineEvent"];var __PyMonitoring_FireJumpEvent=Module["__PyMonitoring_FireJumpEvent"]=wasmExports["_PyMonitoring_FireJumpEvent"];var __PyMonitoring_FireBranchEvent=Module["__PyMonitoring_FireBranchEvent"]=wasmExports["_PyMonitoring_FireBranchEvent"];var __PyMonitoring_FireCReturnEvent=Module["__PyMonitoring_FireCReturnEvent"]=wasmExports["_PyMonitoring_FireCReturnEvent"];var __PyMonitoring_FirePyThrowEvent=Module["__PyMonitoring_FirePyThrowEvent"]=wasmExports["_PyMonitoring_FirePyThrowEvent"];var __PyMonitoring_FireRaiseEvent=Module["__PyMonitoring_FireRaiseEvent"]=wasmExports["_PyMonitoring_FireRaiseEvent"];var __PyMonitoring_FireCRaiseEvent=Module["__PyMonitoring_FireCRaiseEvent"]=wasmExports["_PyMonitoring_FireCRaiseEvent"];var __PyMonitoring_FireReraiseEvent=Module["__PyMonitoring_FireReraiseEvent"]=wasmExports["_PyMonitoring_FireReraiseEvent"];var __PyMonitoring_FireExceptionHandledEvent=Module["__PyMonitoring_FireExceptionHandledEvent"]=wasmExports["_PyMonitoring_FireExceptionHandledEvent"];var __PyMonitoring_FirePyUnwindEvent=Module["__PyMonitoring_FirePyUnwindEvent"]=wasmExports["_PyMonitoring_FirePyUnwindEvent"];var __PyMonitoring_FireStopIterationEvent=Module["__PyMonitoring_FireStopIterationEvent"]=wasmExports["_PyMonitoring_FireStopIterationEvent"];var __PyCompile_GetUnaryIntrinsicName=Module["__PyCompile_GetUnaryIntrinsicName"]=wasmExports["_PyCompile_GetUnaryIntrinsicName"];var __PyCompile_GetBinaryIntrinsicName=Module["__PyCompile_GetBinaryIntrinsicName"]=wasmExports["_PyCompile_GetBinaryIntrinsicName"];var _PyTime_MonotonicRaw=Module["_PyTime_MonotonicRaw"]=wasmExports["PyTime_MonotonicRaw"];var __PyParkingLot_Park=Module["__PyParkingLot_Park"]=wasmExports["_PyParkingLot_Park"];var __PyDeadline_Get=Module["__PyDeadline_Get"]=wasmExports["_PyDeadline_Get"];var __PyParkingLot_Unpark=Module["__PyParkingLot_Unpark"]=wasmExports["_PyParkingLot_Unpark"];var __PySemaphore_Init=Module["__PySemaphore_Init"]=wasmExports["_PySemaphore_Init"];var __PySemaphore_Wait=Module["__PySemaphore_Wait"]=wasmExports["_PySemaphore_Wait"];var __PySemaphore_Destroy=Module["__PySemaphore_Destroy"]=wasmExports["_PySemaphore_Destroy"];var __PySemaphore_Wakeup=Module["__PySemaphore_Wakeup"]=wasmExports["_PySemaphore_Wakeup"];var __PyEvent_IsSet=Module["__PyEvent_IsSet"]=wasmExports["_PyEvent_IsSet"];var __PyEvent_Notify=Module["__PyEvent_Notify"]=wasmExports["_PyEvent_Notify"];var __PyParkingLot_UnparkAll=Module["__PyParkingLot_UnparkAll"]=wasmExports["_PyParkingLot_UnparkAll"];var _PyEvent_Wait=Module["_PyEvent_Wait"]=wasmExports["PyEvent_Wait"];var _PyEvent_WaitTimed=Module["_PyEvent_WaitTimed"]=wasmExports["PyEvent_WaitTimed"];var __PyRWMutex_RLock=Module["__PyRWMutex_RLock"]=wasmExports["_PyRWMutex_RLock"];var __PyRWMutex_RUnlock=Module["__PyRWMutex_RUnlock"]=wasmExports["_PyRWMutex_RUnlock"];var __PyRWMutex_Lock=Module["__PyRWMutex_Lock"]=wasmExports["_PyRWMutex_Lock"];var __PyRWMutex_Unlock=Module["__PyRWMutex_Unlock"]=wasmExports["_PyRWMutex_Unlock"];var __PySeqLock_LockWrite=Module["__PySeqLock_LockWrite"]=wasmExports["_PySeqLock_LockWrite"];var _sched_yield=Module["_sched_yield"]=wasmExports["sched_yield"];var __PySeqLock_AbandonWrite=Module["__PySeqLock_AbandonWrite"]=wasmExports["_PySeqLock_AbandonWrite"];var __PySeqLock_UnlockWrite=Module["__PySeqLock_UnlockWrite"]=wasmExports["_PySeqLock_UnlockWrite"];var __PySeqLock_BeginRead=Module["__PySeqLock_BeginRead"]=wasmExports["_PySeqLock_BeginRead"];var __PySeqLock_EndRead=Module["__PySeqLock_EndRead"]=wasmExports["_PySeqLock_EndRead"];var __PySeqLock_AfterFork=Module["__PySeqLock_AfterFork"]=wasmExports["_PySeqLock_AfterFork"];var _PyMarshal_WriteLongToFile=Module["_PyMarshal_WriteLongToFile"]=wasmExports["PyMarshal_WriteLongToFile"];var _PyMarshal_WriteObjectToFile=Module["_PyMarshal_WriteObjectToFile"]=wasmExports["PyMarshal_WriteObjectToFile"];var _PyMarshal_ReadShortFromFile=Module["_PyMarshal_ReadShortFromFile"]=wasmExports["PyMarshal_ReadShortFromFile"];var _PyMarshal_ReadLongFromFile=Module["_PyMarshal_ReadLongFromFile"]=wasmExports["PyMarshal_ReadLongFromFile"];var _PyMarshal_ReadLastObjectFromFile=Module["_PyMarshal_ReadLastObjectFromFile"]=wasmExports["PyMarshal_ReadLastObjectFromFile"];var __Py_fstat_noraise=Module["__Py_fstat_noraise"]=wasmExports["_Py_fstat_noraise"];var _fread=Module["_fread"]=wasmExports["fread"];var _PyMarshal_ReadObjectFromFile=Module["_PyMarshal_ReadObjectFromFile"]=wasmExports["PyMarshal_ReadObjectFromFile"];var _PyMarshal_WriteObjectToString=Module["_PyMarshal_WriteObjectToString"]=wasmExports["PyMarshal_WriteObjectToString"];var _PyMarshal_Init=Module["_PyMarshal_Init"]=wasmExports["PyMarshal_Init"];var __Py_convert_optional_to_ssize_t=Module["__Py_convert_optional_to_ssize_t"]=wasmExports["_Py_convert_optional_to_ssize_t"];var __Py_BuildValue_SizeT=Module["__Py_BuildValue_SizeT"]=wasmExports["_Py_BuildValue_SizeT"];var _Py_VaBuildValue=Module["_Py_VaBuildValue"]=wasmExports["Py_VaBuildValue"];var __Py_VaBuildValue_SizeT=Module["__Py_VaBuildValue_SizeT"]=wasmExports["_Py_VaBuildValue_SizeT"];var _PyModule_AddStringConstant=Module["_PyModule_AddStringConstant"]=wasmExports["PyModule_AddStringConstant"];var _PyOS_vsnprintf=Module["_PyOS_vsnprintf"]=wasmExports["PyOS_vsnprintf"];var _pthread_cond_init=Module["_pthread_cond_init"]=wasmExports["pthread_cond_init"];var _PyTime_TimeRaw=Module["_PyTime_TimeRaw"]=wasmExports["PyTime_TimeRaw"];var __PyTime_AsTimespec_clamp=Module["__PyTime_AsTimespec_clamp"]=wasmExports["_PyTime_AsTimespec_clamp"];var __PyParkingLot_AfterFork=Module["__PyParkingLot_AfterFork"]=wasmExports["_PyParkingLot_AfterFork"];var __PyPathConfig_ClearGlobal=Module["__PyPathConfig_ClearGlobal"]=wasmExports["_PyPathConfig_ClearGlobal"];var _wcscpy=Module["_wcscpy"]=wasmExports["wcscpy"];var _Py_SetPath=Module["_Py_SetPath"]=wasmExports["Py_SetPath"];var _Py_SetPythonHome=Module["_Py_SetPythonHome"]=wasmExports["Py_SetPythonHome"];var _Py_SetProgramName=Module["_Py_SetProgramName"]=wasmExports["Py_SetProgramName"];var _Py_GetPath=Module["_Py_GetPath"]=wasmExports["Py_GetPath"];var _Py_GetPrefix=Module["_Py_GetPrefix"]=wasmExports["Py_GetPrefix"];var _Py_GetExecPrefix=Module["_Py_GetExecPrefix"]=wasmExports["Py_GetExecPrefix"];var _Py_GetProgramFullPath=Module["_Py_GetProgramFullPath"]=wasmExports["Py_GetProgramFullPath"];var _Py_GetPythonHome=Module["_Py_GetPythonHome"]=wasmExports["Py_GetPythonHome"];var _Py_GetProgramName=Module["_Py_GetProgramName"]=wasmExports["Py_GetProgramName"];var _wcsncpy=Module["_wcsncpy"]=wasmExports["wcsncpy"];var _wcsncmp=Module["_wcsncmp"]=wasmExports["wcsncmp"];var __PyPreConfig_InitCompatConfig=Module["__PyPreConfig_InitCompatConfig"]=wasmExports["_PyPreConfig_InitCompatConfig"];var _PyPreConfig_InitIsolatedConfig=Module["_PyPreConfig_InitIsolatedConfig"]=wasmExports["PyPreConfig_InitIsolatedConfig"];var __Py_SetLocaleFromEnv=Module["__Py_SetLocaleFromEnv"]=wasmExports["_Py_SetLocaleFromEnv"];var _PyHash_GetFuncDef=Module["_PyHash_GetFuncDef"]=wasmExports["PyHash_GetFuncDef"];var _Py_IsFinalizing=Module["_Py_IsFinalizing"]=wasmExports["Py_IsFinalizing"];var _nl_langinfo=Module["_nl_langinfo"]=wasmExports["nl_langinfo"];var _setenv=Module["_setenv"]=wasmExports["setenv"];var __PyInterpreterState_SetConfig=Module["__PyInterpreterState_SetConfig"]=wasmExports["_PyInterpreterState_SetConfig"];var _Py_PreInitializeFromArgs=Module["_Py_PreInitializeFromArgs"]=wasmExports["Py_PreInitializeFromArgs"];var _Py_PreInitialize=Module["_Py_PreInitialize"]=wasmExports["Py_PreInitialize"];var _Py_InitializeEx=Module["_Py_InitializeEx"]=wasmExports["Py_InitializeEx"];var _Py_FatalError=Module["_Py_FatalError"]=wasmExports["Py_FatalError"];var _Py_Initialize=Module["_Py_Initialize"]=wasmExports["Py_Initialize"];var __Py_InitializeMain=Module["__Py_InitializeMain"]=wasmExports["_Py_InitializeMain"];var __PyThreadState_New=Module["__PyThreadState_New"]=wasmExports["_PyThreadState_New"];var _Py_Finalize=Module["_Py_Finalize"]=wasmExports["Py_Finalize"];var _PyInterpreterState_New=Module["_PyInterpreterState_New"]=wasmExports["PyInterpreterState_New"];var _Py_NewInterpreter=Module["_Py_NewInterpreter"]=wasmExports["Py_NewInterpreter"];var __Py_write_noraise=Module["__Py_write_noraise"]=wasmExports["_Py_write_noraise"];var _vfprintf=Module["_vfprintf"]=wasmExports["vfprintf"];var __Py_FatalRefcountErrorFunc=Module["__Py_FatalRefcountErrorFunc"]=wasmExports["_Py_FatalRefcountErrorFunc"];var _Py_AtExit=Module["_Py_AtExit"]=wasmExports["Py_AtExit"];var _Py_Exit=Module["_Py_Exit"]=wasmExports["Py_Exit"];var _Py_FdIsInteractive=Module["_Py_FdIsInteractive"]=wasmExports["Py_FdIsInteractive"];var _PyOS_getsig=Module["_PyOS_getsig"]=wasmExports["PyOS_getsig"];var _signal=Module["_signal"]=wasmExports["signal"];var _PyOS_setsig=Module["_PyOS_setsig"]=wasmExports["PyOS_setsig"];var _siginterrupt=Module["_siginterrupt"]=wasmExports["siginterrupt"];var __PyInterpreterState_New=Module["__PyInterpreterState_New"]=wasmExports["_PyInterpreterState_New"];var _PySys_SetObject=Module["_PySys_SetObject"]=wasmExports["PySys_SetObject"];var __Py_IsValidFD=Module["__Py_IsValidFD"]=wasmExports["_Py_IsValidFD"];var _PyOS_mystrnicmp=Module["_PyOS_mystrnicmp"]=wasmExports["PyOS_mystrnicmp"];var __PyThreadState_GetCurrent=Module["__PyThreadState_GetCurrent"]=wasmExports["_PyThreadState_GetCurrent"];var _PyThread_tss_create=Module["_PyThread_tss_create"]=wasmExports["PyThread_tss_create"];var _PyThread_tss_is_created=Module["_PyThread_tss_is_created"]=wasmExports["PyThread_tss_is_created"];var _PyThread_tss_delete=Module["_PyThread_tss_delete"]=wasmExports["PyThread_tss_delete"];var _PyThread_tss_get=Module["_PyThread_tss_get"]=wasmExports["PyThread_tss_get"];var _PyThread_tss_set=Module["_PyThread_tss_set"]=wasmExports["PyThread_tss_set"];var _PyInterpreterState_Clear=Module["_PyInterpreterState_Clear"]=wasmExports["PyInterpreterState_Clear"];var _PyThread_free_lock=Module["_PyThread_free_lock"]=wasmExports["PyThread_free_lock"];var __PyInterpreterState_IsRunningMain=Module["__PyInterpreterState_IsRunningMain"]=wasmExports["_PyInterpreterState_IsRunningMain"];var __PyInterpreterState_FailIfRunningMain=Module["__PyInterpreterState_FailIfRunningMain"]=wasmExports["_PyInterpreterState_FailIfRunningMain"];var __PyInterpreterState_GetWhence=Module["__PyInterpreterState_GetWhence"]=wasmExports["_PyInterpreterState_GetWhence"];var _PyInterpreterState_GetDict=Module["_PyInterpreterState_GetDict"]=wasmExports["PyInterpreterState_GetDict"];var __PyInterpreterState_ObjectToID=Module["__PyInterpreterState_ObjectToID"]=wasmExports["_PyInterpreterState_ObjectToID"];var __PyInterpreterState_GetIDObject=Module["__PyInterpreterState_GetIDObject"]=wasmExports["_PyInterpreterState_GetIDObject"];var _PyThread_allocate_lock=Module["_PyThread_allocate_lock"]=wasmExports["PyThread_allocate_lock"];var __PyInterpreterState_IDInitref=Module["__PyInterpreterState_IDInitref"]=wasmExports["_PyInterpreterState_IDInitref"];var __PyInterpreterState_IDIncref=Module["__PyInterpreterState_IDIncref"]=wasmExports["_PyInterpreterState_IDIncref"];var _PyThread_acquire_lock=Module["_PyThread_acquire_lock"]=wasmExports["PyThread_acquire_lock"];var _PyThread_release_lock=Module["_PyThread_release_lock"]=wasmExports["PyThread_release_lock"];var __PyInterpreterState_IDDecref=Module["__PyInterpreterState_IDDecref"]=wasmExports["_PyInterpreterState_IDDecref"];var __PyInterpreterState_RequiresIDRef=Module["__PyInterpreterState_RequiresIDRef"]=wasmExports["_PyInterpreterState_RequiresIDRef"];var __PyInterpreterState_RequireIDRef=Module["__PyInterpreterState_RequireIDRef"]=wasmExports["_PyInterpreterState_RequireIDRef"];var __PyInterpreterState_LookUpIDObject=Module["__PyInterpreterState_LookUpIDObject"]=wasmExports["_PyInterpreterState_LookUpIDObject"];var __PyThreadState_Prealloc=Module["__PyThreadState_Prealloc"]=wasmExports["_PyThreadState_Prealloc"];var __PyThreadState_Init=Module["__PyThreadState_Init"]=wasmExports["_PyThreadState_Init"];var _PyThreadState_DeleteCurrent=Module["_PyThreadState_DeleteCurrent"]=wasmExports["PyThreadState_DeleteCurrent"];var __PyThreadState_GetDict=Module["__PyThreadState_GetDict"]=wasmExports["_PyThreadState_GetDict"];var _PyThreadState_GetID=Module["_PyThreadState_GetID"]=wasmExports["PyThreadState_GetID"];var _PyThreadState_SetAsyncExc=Module["_PyThreadState_SetAsyncExc"]=wasmExports["PyThreadState_SetAsyncExc"];var _PyThreadState_GetUnchecked=Module["_PyThreadState_GetUnchecked"]=wasmExports["PyThreadState_GetUnchecked"];var _PyInterpreterState_Head=Module["_PyInterpreterState_Head"]=wasmExports["PyInterpreterState_Head"];var _PyInterpreterState_Main=Module["_PyInterpreterState_Main"]=wasmExports["PyInterpreterState_Main"];var _PyInterpreterState_Next=Module["_PyInterpreterState_Next"]=wasmExports["PyInterpreterState_Next"];var __PyThread_CurrentFrames=Module["__PyThread_CurrentFrames"]=wasmExports["_PyThread_CurrentFrames"];var __PyInterpreterState_GetEvalFrameFunc=Module["__PyInterpreterState_GetEvalFrameFunc"]=wasmExports["_PyInterpreterState_GetEvalFrameFunc"];var __PyInterpreterState_SetEvalFrameFunc=Module["__PyInterpreterState_SetEvalFrameFunc"]=wasmExports["_PyInterpreterState_SetEvalFrameFunc"];var __PyInterpreterState_GetConfigCopy=Module["__PyInterpreterState_GetConfigCopy"]=wasmExports["_PyInterpreterState_GetConfigCopy"];var _rewind=Module["_rewind"]=wasmExports["rewind"];var _PyRun_InteractiveLoopFlags=Module["_PyRun_InteractiveLoopFlags"]=wasmExports["PyRun_InteractiveLoopFlags"];var _PyRun_InteractiveOneObject=Module["_PyRun_InteractiveOneObject"]=wasmExports["PyRun_InteractiveOneObject"];var _PyRun_InteractiveOneFlags=Module["_PyRun_InteractiveOneFlags"]=wasmExports["PyRun_InteractiveOneFlags"];var _PyRun_SimpleFileExFlags=Module["_PyRun_SimpleFileExFlags"]=wasmExports["PyRun_SimpleFileExFlags"];var _PyRun_SimpleStringFlags=Module["_PyRun_SimpleStringFlags"]=wasmExports["PyRun_SimpleStringFlags"];var _PyErr_Display=Module["_PyErr_Display"]=wasmExports["PyErr_Display"];var _PyRun_FileExFlags=Module["_PyRun_FileExFlags"]=wasmExports["PyRun_FileExFlags"];var _Py_CompileStringExFlags=Module["_Py_CompileStringExFlags"]=wasmExports["Py_CompileStringExFlags"];var _PyRun_AnyFile=Module["_PyRun_AnyFile"]=wasmExports["PyRun_AnyFile"];var _PyRun_AnyFileEx=Module["_PyRun_AnyFileEx"]=wasmExports["PyRun_AnyFileEx"];var _PyRun_AnyFileFlags=Module["_PyRun_AnyFileFlags"]=wasmExports["PyRun_AnyFileFlags"];var _PyRun_File=Module["_PyRun_File"]=wasmExports["PyRun_File"];var _PyRun_FileEx=Module["_PyRun_FileEx"]=wasmExports["PyRun_FileEx"];var _PyRun_FileFlags=Module["_PyRun_FileFlags"]=wasmExports["PyRun_FileFlags"];var _PyRun_SimpleFile=Module["_PyRun_SimpleFile"]=wasmExports["PyRun_SimpleFile"];var _PyRun_SimpleFileEx=Module["_PyRun_SimpleFileEx"]=wasmExports["PyRun_SimpleFileEx"];var _PyRun_String=Module["_PyRun_String"]=wasmExports["PyRun_String"];var _PyRun_SimpleString=Module["_PyRun_SimpleString"]=wasmExports["PyRun_SimpleString"];var _Py_CompileString=Module["_Py_CompileString"]=wasmExports["Py_CompileString"];var _Py_CompileStringFlags=Module["_Py_CompileStringFlags"]=wasmExports["Py_CompileStringFlags"];var _PyRun_InteractiveOne=Module["_PyRun_InteractiveOne"]=wasmExports["PyRun_InteractiveOne"];var _PyRun_InteractiveLoop=Module["_PyRun_InteractiveLoop"]=wasmExports["PyRun_InteractiveLoop"];var __PyLong_AsTime_t=Module["__PyLong_AsTime_t"]=wasmExports["_PyLong_AsTime_t"];var __PyLong_FromTime_t=Module["__PyLong_FromTime_t"]=wasmExports["_PyLong_FromTime_t"];var __PyTime_ObjectToTime_t=Module["__PyTime_ObjectToTime_t"]=wasmExports["_PyTime_ObjectToTime_t"];var __PyTime_ObjectToTimespec=Module["__PyTime_ObjectToTimespec"]=wasmExports["_PyTime_ObjectToTimespec"];var __PyTime_ObjectToTimeval=Module["__PyTime_ObjectToTimeval"]=wasmExports["_PyTime_ObjectToTimeval"];var __PyTime_FromSeconds=Module["__PyTime_FromSeconds"]=wasmExports["_PyTime_FromSeconds"];var __PyTime_FromLong=Module["__PyTime_FromLong"]=wasmExports["_PyTime_FromLong"];var __PyTime_FromSecondsObject=Module["__PyTime_FromSecondsObject"]=wasmExports["_PyTime_FromSecondsObject"];var __PyTime_FromMillisecondsObject=Module["__PyTime_FromMillisecondsObject"]=wasmExports["_PyTime_FromMillisecondsObject"];var __PyTime_AsLong=Module["__PyTime_AsLong"]=wasmExports["_PyTime_AsLong"];var __PyTime_AsMilliseconds=Module["__PyTime_AsMilliseconds"]=wasmExports["_PyTime_AsMilliseconds"];var __PyTime_AsTimeval=Module["__PyTime_AsTimeval"]=wasmExports["_PyTime_AsTimeval"];var __PyTime_AsTimeval_clamp=Module["__PyTime_AsTimeval_clamp"]=wasmExports["_PyTime_AsTimeval_clamp"];var __PyTime_AsTimevalTime_t=Module["__PyTime_AsTimevalTime_t"]=wasmExports["_PyTime_AsTimevalTime_t"];var __PyTime_AsTimespec=Module["__PyTime_AsTimespec"]=wasmExports["_PyTime_AsTimespec"];var _PyTime_Time=Module["_PyTime_Time"]=wasmExports["PyTime_Time"];var _clock_getres=Module["_clock_getres"]=wasmExports["clock_getres"];var _PyTime_Monotonic=Module["_PyTime_Monotonic"]=wasmExports["PyTime_Monotonic"];var __PyTime_MonotonicWithInfo=Module["__PyTime_MonotonicWithInfo"]=wasmExports["_PyTime_MonotonicWithInfo"];var _PyTime_PerfCounter=Module["_PyTime_PerfCounter"]=wasmExports["PyTime_PerfCounter"];var __PyTime_localtime=Module["__PyTime_localtime"]=wasmExports["_PyTime_localtime"];var _localtime_r=Module["_localtime_r"]=wasmExports["localtime_r"];var __PyTime_gmtime=Module["__PyTime_gmtime"]=wasmExports["_PyTime_gmtime"];var _gmtime_r=Module["_gmtime_r"]=wasmExports["gmtime_r"];var __PyDeadline_Init=Module["__PyDeadline_Init"]=wasmExports["_PyDeadline_Init"];var _getentropy=Module["_getentropy"]=wasmExports["getentropy"];var __Py_open=Module["__Py_open"]=wasmExports["_Py_open"];var _close=Module["_close"]=wasmExports["close"];var __Py_fstat=Module["__Py_fstat"]=wasmExports["_Py_fstat"];var __Py_open_noraise=Module["__Py_open_noraise"]=wasmExports["_Py_open_noraise"];var __PyOS_URandomNonblock=Module["__PyOS_URandomNonblock"]=wasmExports["_PyOS_URandomNonblock"];var _PySys_AuditTuple=Module["_PySys_AuditTuple"]=wasmExports["PySys_AuditTuple"];var _PySys_AddAuditHook=Module["_PySys_AddAuditHook"]=wasmExports["PySys_AddAuditHook"];var __PySys_GetSizeOf=Module["__PySys_GetSizeOf"]=wasmExports["_PySys_GetSizeOf"];var _PyUnstable_PerfMapState_Init=Module["_PyUnstable_PerfMapState_Init"]=wasmExports["PyUnstable_PerfMapState_Init"];var _getpid=Module["_getpid"]=wasmExports["getpid"];var _open=Module["_open"]=wasmExports["open"];var _fdopen=Module["_fdopen"]=wasmExports["fdopen"];var _PyUnstable_WritePerfMapEntry=Module["_PyUnstable_WritePerfMapEntry"]=wasmExports["PyUnstable_WritePerfMapEntry"];var _PyUnstable_PerfMapState_Fini=Module["_PyUnstable_PerfMapState_Fini"]=wasmExports["PyUnstable_PerfMapState_Fini"];var _PyUnstable_CopyPerfMapFile=Module["_PyUnstable_CopyPerfMapFile"]=wasmExports["PyUnstable_CopyPerfMapFile"];var _fopen=Module["_fopen"]=wasmExports["fopen"];var _PySys_ResetWarnOptions=Module["_PySys_ResetWarnOptions"]=wasmExports["PySys_ResetWarnOptions"];var _PySys_AddWarnOptionUnicode=Module["_PySys_AddWarnOptionUnicode"]=wasmExports["PySys_AddWarnOptionUnicode"];var _PySys_AddWarnOption=Module["_PySys_AddWarnOption"]=wasmExports["PySys_AddWarnOption"];var _PySys_HasWarnOptions=Module["_PySys_HasWarnOptions"]=wasmExports["PySys_HasWarnOptions"];var _PySys_AddXOption=Module["_PySys_AddXOption"]=wasmExports["PySys_AddXOption"];var _PySys_GetXOptions=Module["_PySys_GetXOptions"]=wasmExports["PySys_GetXOptions"];var _PyThread_GetInfo=Module["_PyThread_GetInfo"]=wasmExports["PyThread_GetInfo"];var _PySys_SetPath=Module["_PySys_SetPath"]=wasmExports["PySys_SetPath"];var _PySys_SetArgvEx=Module["_PySys_SetArgvEx"]=wasmExports["PySys_SetArgvEx"];var _PySys_SetArgv=Module["_PySys_SetArgv"]=wasmExports["PySys_SetArgv"];var _PySys_WriteStdout=Module["_PySys_WriteStdout"]=wasmExports["PySys_WriteStdout"];var _PySys_FormatStdout=Module["_PySys_FormatStdout"]=wasmExports["PySys_FormatStdout"];var _pthread_condattr_init=Module["_pthread_condattr_init"]=wasmExports["pthread_condattr_init"];var _pthread_condattr_setclock=Module["_pthread_condattr_setclock"]=wasmExports["pthread_condattr_setclock"];var _PyThread_start_joinable_thread=Module["_PyThread_start_joinable_thread"]=wasmExports["PyThread_start_joinable_thread"];var _pthread_attr_init=Module["_pthread_attr_init"]=wasmExports["pthread_attr_init"];var _pthread_attr_setstacksize=Module["_pthread_attr_setstacksize"]=wasmExports["pthread_attr_setstacksize"];var _pthread_attr_destroy=Module["_pthread_attr_destroy"]=wasmExports["pthread_attr_destroy"];var _pthread_create=Module["_pthread_create"]=wasmExports["pthread_create"];var _PyThread_start_new_thread=Module["_PyThread_start_new_thread"]=wasmExports["PyThread_start_new_thread"];var _pthread_detach=Module["_pthread_detach"]=wasmExports["pthread_detach"];var _PyThread_join_thread=Module["_PyThread_join_thread"]=wasmExports["PyThread_join_thread"];var _pthread_join=Module["_pthread_join"]=wasmExports["pthread_join"];var _PyThread_detach_thread=Module["_PyThread_detach_thread"]=wasmExports["PyThread_detach_thread"];var _pthread_self=Module["_pthread_self"]=wasmExports["pthread_self"];var _PyThread_acquire_lock_timed=Module["_PyThread_acquire_lock_timed"]=wasmExports["PyThread_acquire_lock_timed"];var _pthread_mutex_trylock=Module["_pthread_mutex_trylock"]=wasmExports["pthread_mutex_trylock"];var _PyThread_create_key=Module["_PyThread_create_key"]=wasmExports["PyThread_create_key"];var _pthread_key_create=Module["_pthread_key_create"]=wasmExports["pthread_key_create"];var _pthread_key_delete=Module["_pthread_key_delete"]=wasmExports["pthread_key_delete"];var _PyThread_delete_key=Module["_PyThread_delete_key"]=wasmExports["PyThread_delete_key"];var _PyThread_delete_key_value=Module["_PyThread_delete_key_value"]=wasmExports["PyThread_delete_key_value"];var _pthread_setspecific=Module["_pthread_setspecific"]=wasmExports["pthread_setspecific"];var _PyThread_set_key_value=Module["_PyThread_set_key_value"]=wasmExports["PyThread_set_key_value"];var _PyThread_get_key_value=Module["_PyThread_get_key_value"]=wasmExports["PyThread_get_key_value"];var _pthread_getspecific=Module["_pthread_getspecific"]=wasmExports["pthread_getspecific"];var _PyThread_ReInitTLS=Module["_PyThread_ReInitTLS"]=wasmExports["PyThread_ReInitTLS"];var _PyThread_get_stacksize=Module["_PyThread_get_stacksize"]=wasmExports["PyThread_get_stacksize"];var _PyThread_set_stacksize=Module["_PyThread_set_stacksize"]=wasmExports["PyThread_set_stacksize"];var _PyThread_ParseTimeoutArg=Module["_PyThread_ParseTimeoutArg"]=wasmExports["PyThread_ParseTimeoutArg"];var _PyThread_acquire_lock_timed_with_retries=Module["_PyThread_acquire_lock_timed_with_retries"]=wasmExports["PyThread_acquire_lock_timed_with_retries"];var _PyThread_tss_alloc=Module["_PyThread_tss_alloc"]=wasmExports["PyThread_tss_alloc"];var _PyThread_tss_free=Module["_PyThread_tss_free"]=wasmExports["PyThread_tss_free"];var _confstr=Module["_confstr"]=wasmExports["confstr"];var __PyTraceback_Add=Module["__PyTraceback_Add"]=wasmExports["_PyTraceback_Add"];var _PyTraceMalloc_Track=Module["_PyTraceMalloc_Track"]=wasmExports["PyTraceMalloc_Track"];var _PyTraceMalloc_Untrack=Module["_PyTraceMalloc_Untrack"]=wasmExports["PyTraceMalloc_Untrack"];var __PyTraceMalloc_GetTraceback=Module["__PyTraceMalloc_GetTraceback"]=wasmExports["_PyTraceMalloc_GetTraceback"];var _PyOS_mystricmp=Module["_PyOS_mystricmp"]=wasmExports["PyOS_mystricmp"];var __Py_strhex=Module["__Py_strhex"]=wasmExports["_Py_strhex"];var __Py_strhex_bytes_with_sep=Module["__Py_strhex_bytes_with_sep"]=wasmExports["_Py_strhex_bytes_with_sep"];var _localeconv=Module["_localeconv"]=wasmExports["localeconv"];var _mbstowcs=Module["_mbstowcs"]=wasmExports["mbstowcs"];var _mbrtowc=Module["_mbrtowc"]=wasmExports["mbrtowc"];var _Py_EncodeLocale=Module["_Py_EncodeLocale"]=wasmExports["Py_EncodeLocale"];var _fstat=Module["_fstat"]=wasmExports["fstat"];var _stat=Module["_stat"]=wasmExports["stat"];var __Py_stat=Module["__Py_stat"]=wasmExports["_Py_stat"];var _fcntl=Module["_fcntl"]=wasmExports["fcntl"];var __Py_set_inheritable=Module["__Py_set_inheritable"]=wasmExports["_Py_set_inheritable"];var __Py_set_inheritable_async_safe=Module["__Py_set_inheritable_async_safe"]=wasmExports["_Py_set_inheritable_async_safe"];var _wcstombs=Module["_wcstombs"]=wasmExports["wcstombs"];var _write=Module["_write"]=wasmExports["write"];var _readlink=Module["_readlink"]=wasmExports["readlink"];var _realpath=Module["_realpath"]=wasmExports["realpath"];var _getcwd=Module["_getcwd"]=wasmExports["getcwd"];var __Py_normpath=Module["__Py_normpath"]=wasmExports["_Py_normpath"];var __Py_dup=Module["__Py_dup"]=wasmExports["_Py_dup"];var __Py_closerange=Module["__Py_closerange"]=wasmExports["_Py_closerange"];var _sysconf=Module["_sysconf"]=wasmExports["sysconf"];var __Py_UTF8_Edit_Cost=Module["__Py_UTF8_Edit_Cost"]=wasmExports["_Py_UTF8_Edit_Cost"];var _PyUnstable_PerfTrampoline_CompileCode=Module["_PyUnstable_PerfTrampoline_CompileCode"]=wasmExports["PyUnstable_PerfTrampoline_CompileCode"];var _PyUnstable_PerfTrampoline_SetPersistAfterFork=Module["_PyUnstable_PerfTrampoline_SetPersistAfterFork"]=wasmExports["PyUnstable_PerfTrampoline_SetPersistAfterFork"];var _dlopen=Module["_dlopen"]=wasmExports["dlopen"];var _dlerror=Module["_dlerror"]=wasmExports["dlerror"];var _dlsym=Module["_dlsym"]=wasmExports["dlsym"];var _PyErr_SetInterruptEx=Module["_PyErr_SetInterruptEx"]=wasmExports["PyErr_SetInterruptEx"];var _PyInit__ctypes=Module["_PyInit__ctypes"]=wasmExports["PyInit__ctypes"];var _PyInit__posixsubprocess=Module["_PyInit__posixsubprocess"]=wasmExports["PyInit__posixsubprocess"];var _PyInit__bz2=Module["_PyInit__bz2"]=wasmExports["PyInit__bz2"];var _PyInit_zlib=Module["_PyInit_zlib"]=wasmExports["PyInit_zlib"];var _PyInit_array=Module["_PyInit_array"]=wasmExports["PyInit_array"];var _PyInit__asyncio=Module["_PyInit__asyncio"]=wasmExports["PyInit__asyncio"];var _PyInit__bisect=Module["_PyInit__bisect"]=wasmExports["PyInit__bisect"];var _PyInit__contextvars=Module["_PyInit__contextvars"]=wasmExports["PyInit__contextvars"];var _PyInit__csv=Module["_PyInit__csv"]=wasmExports["PyInit__csv"];var _PyInit__heapq=Module["_PyInit__heapq"]=wasmExports["PyInit__heapq"];var _PyInit__json=Module["_PyInit__json"]=wasmExports["PyInit__json"];var _PyInit__lsprof=Module["_PyInit__lsprof"]=wasmExports["PyInit__lsprof"];var _PyInit__opcode=Module["_PyInit__opcode"]=wasmExports["PyInit__opcode"];var _PyInit__pickle=Module["_PyInit__pickle"]=wasmExports["PyInit__pickle"];var _PyInit__queue=Module["_PyInit__queue"]=wasmExports["PyInit__queue"];var _PyInit__random=Module["_PyInit__random"]=wasmExports["PyInit__random"];var _PyInit__struct=Module["_PyInit__struct"]=wasmExports["PyInit__struct"];var _PyInit__zoneinfo=Module["_PyInit__zoneinfo"]=wasmExports["PyInit__zoneinfo"];var _PyInit_math=Module["_PyInit_math"]=wasmExports["PyInit_math"];var _PyInit_cmath=Module["_PyInit_cmath"]=wasmExports["PyInit_cmath"];var _PyInit__statistics=Module["_PyInit__statistics"]=wasmExports["PyInit__statistics"];var _PyInit__datetime=Module["_PyInit__datetime"]=wasmExports["PyInit__datetime"];var _PyInit__decimal=Module["_PyInit__decimal"]=wasmExports["PyInit__decimal"];var _PyInit_binascii=Module["_PyInit_binascii"]=wasmExports["PyInit_binascii"];var _PyInit__md5=Module["_PyInit__md5"]=wasmExports["PyInit__md5"];var _PyInit__sha1=Module["_PyInit__sha1"]=wasmExports["PyInit__sha1"];var _PyInit__sha2=Module["_PyInit__sha2"]=wasmExports["PyInit__sha2"];var _PyInit__sha3=Module["_PyInit__sha3"]=wasmExports["PyInit__sha3"];var _PyInit__blake2=Module["_PyInit__blake2"]=wasmExports["PyInit__blake2"];var _PyInit_pyexpat=Module["_PyInit_pyexpat"]=wasmExports["PyInit_pyexpat"];var _PyInit__elementtree=Module["_PyInit__elementtree"]=wasmExports["PyInit__elementtree"];var _PyInit__codecs_cn=Module["_PyInit__codecs_cn"]=wasmExports["PyInit__codecs_cn"];var _PyInit__codecs_hk=Module["_PyInit__codecs_hk"]=wasmExports["PyInit__codecs_hk"];var _PyInit__codecs_iso2022=Module["_PyInit__codecs_iso2022"]=wasmExports["PyInit__codecs_iso2022"];var _PyInit__codecs_jp=Module["_PyInit__codecs_jp"]=wasmExports["PyInit__codecs_jp"];var _PyInit__codecs_kr=Module["_PyInit__codecs_kr"]=wasmExports["PyInit__codecs_kr"];var _PyInit__codecs_tw=Module["_PyInit__codecs_tw"]=wasmExports["PyInit__codecs_tw"];var _PyInit__multibytecodec=Module["_PyInit__multibytecodec"]=wasmExports["PyInit__multibytecodec"];var _PyInit_unicodedata=Module["_PyInit_unicodedata"]=wasmExports["PyInit_unicodedata"];var _PyInit_mmap=Module["_PyInit_mmap"]=wasmExports["PyInit_mmap"];var _PyInit_select=Module["_PyInit_select"]=wasmExports["PyInit_select"];var _PyInit__socket=Module["_PyInit__socket"]=wasmExports["PyInit__socket"];var _PyInit_atexit=Module["_PyInit_atexit"]=wasmExports["PyInit_atexit"];var _PyInit_faulthandler=Module["_PyInit_faulthandler"]=wasmExports["PyInit_faulthandler"];var _PyInit_posix=Module["_PyInit_posix"]=wasmExports["PyInit_posix"];var _PyInit__signal=Module["_PyInit__signal"]=wasmExports["PyInit__signal"];var _PyInit__tracemalloc=Module["_PyInit__tracemalloc"]=wasmExports["PyInit__tracemalloc"];var _PyInit__suggestions=Module["_PyInit__suggestions"]=wasmExports["PyInit__suggestions"];var _PyInit__codecs=Module["_PyInit__codecs"]=wasmExports["PyInit__codecs"];var _PyInit__collections=Module["_PyInit__collections"]=wasmExports["PyInit__collections"];var _PyInit_errno=Module["_PyInit_errno"]=wasmExports["PyInit_errno"];var _PyInit__io=Module["_PyInit__io"]=wasmExports["PyInit__io"];var _PyInit_itertools=Module["_PyInit_itertools"]=wasmExports["PyInit_itertools"];var _PyInit__sre=Module["_PyInit__sre"]=wasmExports["PyInit__sre"];var _PyInit__sysconfig=Module["_PyInit__sysconfig"]=wasmExports["PyInit__sysconfig"];var _PyInit__thread=Module["_PyInit__thread"]=wasmExports["PyInit__thread"];var _PyInit_time=Module["_PyInit_time"]=wasmExports["PyInit_time"];var _PyInit__typing=Module["_PyInit__typing"]=wasmExports["PyInit__typing"];var _PyInit__weakref=Module["_PyInit__weakref"]=wasmExports["PyInit__weakref"];var _PyInit__abc=Module["_PyInit__abc"]=wasmExports["PyInit__abc"];var _PyInit__functools=Module["_PyInit__functools"]=wasmExports["PyInit__functools"];var _PyInit__locale=Module["_PyInit__locale"]=wasmExports["PyInit__locale"];var _PyInit__operator=Module["_PyInit__operator"]=wasmExports["PyInit__operator"];var _PyInit__stat=Module["_PyInit__stat"]=wasmExports["PyInit__stat"];var _PyInit__symtable=Module["_PyInit__symtable"]=wasmExports["PyInit__symtable"];var _PyInit_gc=Module["_PyInit_gc"]=wasmExports["PyInit_gc"];var _Py_RunMain=Module["_Py_RunMain"]=wasmExports["Py_RunMain"];var _perror=Module["_perror"]=wasmExports["perror"];var _kill=Module["_kill"]=wasmExports["kill"];var _Py_Main=Module["_Py_Main"]=wasmExports["Py_Main"];var _Py_BytesMain=Module["_Py_BytesMain"]=wasmExports["Py_BytesMain"];var _strcat=Module["_strcat"]=wasmExports["strcat"];var _memmove=Module["_memmove"]=wasmExports["memmove"];var _memset=Module["_memset"]=wasmExports["memset"];var _ffi_closure_alloc=Module["_ffi_closure_alloc"]=wasmExports["ffi_closure_alloc"];var _ffi_prep_cif=Module["_ffi_prep_cif"]=wasmExports["ffi_prep_cif"];var _ffi_prep_closure_loc=Module["_ffi_prep_closure_loc"]=wasmExports["ffi_prep_closure_loc"];var _ffi_closure_free=Module["_ffi_closure_free"]=wasmExports["ffi_closure_free"];var _ffi_prep_cif_var=Module["_ffi_prep_cif_var"]=wasmExports["ffi_prep_cif_var"];var _ffi_call=Module["_ffi_call"]=wasmExports["ffi_call"];var _dlclose=Module["_dlclose"]=wasmExports["dlclose"];var ___extenddftf2=Module["___extenddftf2"]=wasmExports["__extenddftf2"];var ___trunctfdf2=Module["___trunctfdf2"]=wasmExports["__trunctfdf2"];var __Py_Gid_Converter=Module["__Py_Gid_Converter"]=wasmExports["_Py_Gid_Converter"];var __Py_Uid_Converter=Module["__Py_Uid_Converter"]=wasmExports["_Py_Uid_Converter"];var _PyOS_BeforeFork=Module["_PyOS_BeforeFork"]=wasmExports["PyOS_BeforeFork"];var _PyOS_AfterFork_Parent=Module["_PyOS_AfterFork_Parent"]=wasmExports["PyOS_AfterFork_Parent"];var _fork=Module["_fork"]=wasmExports["fork"];var _PyOS_AfterFork_Child=Module["_PyOS_AfterFork_Child"]=wasmExports["PyOS_AfterFork_Child"];var __exit=Module["__exit"]=wasmExports["_exit"];var _dup=Module["_dup"]=wasmExports["dup"];var _dup2=Module["_dup2"]=wasmExports["dup2"];var _chdir=Module["_chdir"]=wasmExports["chdir"];var _umask=Module["_umask"]=wasmExports["umask"];var __Py_RestoreSignals=Module["__Py_RestoreSignals"]=wasmExports["_Py_RestoreSignals"];var _setsid=Module["_setsid"]=wasmExports["setsid"];var _setpgid=Module["_setpgid"]=wasmExports["setpgid"];var _setregid=Module["_setregid"]=wasmExports["setregid"];var _setreuid=Module["_setreuid"]=wasmExports["setreuid"];var _execve=Module["_execve"]=wasmExports["execve"];var _execv=Module["_execv"]=wasmExports["execv"];var _opendir=Module["_opendir"]=wasmExports["opendir"];var _dirfd=Module["_dirfd"]=wasmExports["dirfd"];var _readdir=Module["_readdir"]=wasmExports["readdir"];var _closedir=Module["_closedir"]=wasmExports["closedir"];var _BZ2_bzCompressEnd=Module["_BZ2_bzCompressEnd"]=wasmExports["BZ2_bzCompressEnd"];var _BZ2_bzCompressInit=Module["_BZ2_bzCompressInit"]=wasmExports["BZ2_bzCompressInit"];var _BZ2_bzCompress=Module["_BZ2_bzCompress"]=wasmExports["BZ2_bzCompress"];var _BZ2_bzDecompressEnd=Module["_BZ2_bzDecompressEnd"]=wasmExports["BZ2_bzDecompressEnd"];var _BZ2_bzDecompressInit=Module["_BZ2_bzDecompressInit"]=wasmExports["BZ2_bzDecompressInit"];var _BZ2_bzDecompress=Module["_BZ2_bzDecompress"]=wasmExports["BZ2_bzDecompress"];var _adler32=Module["_adler32"]=wasmExports["adler32"];var _deflateInit2_=Module["_deflateInit2_"]=wasmExports["deflateInit2_"];var _deflateEnd=Module["_deflateEnd"]=wasmExports["deflateEnd"];var _deflate=Module["_deflate"]=wasmExports["deflate"];var _deflateSetDictionary=Module["_deflateSetDictionary"]=wasmExports["deflateSetDictionary"];var _crc32=Module["_crc32"]=wasmExports["crc32"];var _inflateInit2_=Module["_inflateInit2_"]=wasmExports["inflateInit2_"];var _inflateEnd=Module["_inflateEnd"]=wasmExports["inflateEnd"];var _inflate=Module["_inflate"]=wasmExports["inflate"];var _inflateSetDictionary=Module["_inflateSetDictionary"]=wasmExports["inflateSetDictionary"];var _zlibVersion=Module["_zlibVersion"]=wasmExports["zlibVersion"];var _deflateCopy=Module["_deflateCopy"]=wasmExports["deflateCopy"];var _inflateCopy=Module["_inflateCopy"]=wasmExports["inflateCopy"];var _acos=Module["_acos"]=wasmExports["acos"];var _acosh=Module["_acosh"]=wasmExports["acosh"];var _asin=Module["_asin"]=wasmExports["asin"];var _asinh=Module["_asinh"]=wasmExports["asinh"];var _atan=Module["_atan"]=wasmExports["atan"];var _atanh=Module["_atanh"]=wasmExports["atanh"];var _cbrt=Module["_cbrt"]=wasmExports["cbrt"];var _copysign=Module["_copysign"]=wasmExports["copysign"];var _cosh=Module["_cosh"]=wasmExports["cosh"];var _erf=Module["_erf"]=wasmExports["erf"];var _erfc=Module["_erfc"]=wasmExports["erfc"];var _exp2=Module["_exp2"]=wasmExports["exp2"];var _expm1=Module["_expm1"]=wasmExports["expm1"];var _fabs=Module["_fabs"]=wasmExports["fabs"];var _fma=Module["_fma"]=wasmExports["fma"];var _sinh=Module["_sinh"]=wasmExports["sinh"];var _sqrt=Module["_sqrt"]=wasmExports["sqrt"];var _tan=Module["_tan"]=wasmExports["tan"];var _tanh=Module["_tanh"]=wasmExports["tanh"];var _nextafter=Module["_nextafter"]=wasmExports["nextafter"];var _log1p=Module["_log1p"]=wasmExports["log1p"];var _log10=Module["_log10"]=wasmExports["log10"];var _log2=Module["_log2"]=wasmExports["log2"];var _explicit_bzero=Module["_explicit_bzero"]=wasmExports["explicit_bzero"];var _strncat=Module["_strncat"]=wasmExports["strncat"];var _mmap=Module["_mmap"]=wasmExports["mmap"];var _munmap=Module["_munmap"]=wasmExports["munmap"];var _msync=Module["_msync"]=wasmExports["msync"];var _madvise=Module["_madvise"]=wasmExports["madvise"];var _ftruncate=Module["_ftruncate"]=wasmExports["ftruncate"];var _mremap=Module["_mremap"]=wasmExports["mremap"];var _poll=Module["_poll"]=wasmExports["poll"];var _select=Module["_select"]=wasmExports["select"];var _inet_ntop=Module["_inet_ntop"]=wasmExports["inet_ntop"];var _gethostbyname=Module["_gethostbyname"]=wasmExports["gethostbyname"];var _gethostbyaddr=Module["_gethostbyaddr"]=wasmExports["gethostbyaddr"];var _gethostname=Module["_gethostname"]=wasmExports["gethostname"];var _getservbyname=Module["_getservbyname"]=wasmExports["getservbyname"];var _ntohs=wasmExports["ntohs"];var _htons=wasmExports["htons"];var _getservbyport=Module["_getservbyport"]=wasmExports["getservbyport"];var _ntohl=Module["_ntohl"]=wasmExports["ntohl"];var _htonl=wasmExports["htonl"];var _inet_aton=Module["_inet_aton"]=wasmExports["inet_aton"];var _inet_ntoa=Module["_inet_ntoa"]=wasmExports["inet_ntoa"];var _inet_pton=Module["_inet_pton"]=wasmExports["inet_pton"];var _gai_strerror=Module["_gai_strerror"]=wasmExports["gai_strerror"];var _freeaddrinfo=Module["_freeaddrinfo"]=wasmExports["freeaddrinfo"];var _if_nameindex=Module["_if_nameindex"]=wasmExports["if_nameindex"];var _if_freenameindex=Module["_if_freenameindex"]=wasmExports["if_freenameindex"];var _if_nametoindex=Module["_if_nametoindex"]=wasmExports["if_nametoindex"];var _if_indextoname=Module["_if_indextoname"]=wasmExports["if_indextoname"];var ___h_errno_location=Module["___h_errno_location"]=wasmExports["__h_errno_location"];var _hstrerror=Module["_hstrerror"]=wasmExports["hstrerror"];var _getsockname=Module["_getsockname"]=wasmExports["getsockname"];var _socket=Module["_socket"]=wasmExports["socket"];var _getsockopt=Module["_getsockopt"]=wasmExports["getsockopt"];var _bind=Module["_bind"]=wasmExports["bind"];var _getpeername=Module["_getpeername"]=wasmExports["getpeername"];var _listen=Module["_listen"]=wasmExports["listen"];var _setsockopt=Module["_setsockopt"]=wasmExports["setsockopt"];var _accept4=Module["_accept4"]=wasmExports["accept4"];var _accept=Module["_accept"]=wasmExports["accept"];var _connect=Module["_connect"]=wasmExports["connect"];var _recv=Module["_recv"]=wasmExports["recv"];var _recvfrom=Module["_recvfrom"]=wasmExports["recvfrom"];var _send=Module["_send"]=wasmExports["send"];var _sendto=Module["_sendto"]=wasmExports["sendto"];var _recvmsg=Module["_recvmsg"]=wasmExports["recvmsg"];var _sendmsg=Module["_sendmsg"]=wasmExports["sendmsg"];var _PyUnstable_AtExit=Module["_PyUnstable_AtExit"]=wasmExports["PyUnstable_AtExit"];var _getrlimit=Module["_getrlimit"]=wasmExports["getrlimit"];var _setrlimit=Module["_setrlimit"]=wasmExports["setrlimit"];var _raise=Module["_raise"]=wasmExports["raise"];var _sigfillset=Module["_sigfillset"]=wasmExports["sigfillset"];var _pthread_sigmask=Module["_pthread_sigmask"]=wasmExports["pthread_sigmask"];var _PyOS_AfterFork=Module["_PyOS_AfterFork"]=wasmExports["PyOS_AfterFork"];var __PyLong_FromGid=Module["__PyLong_FromGid"]=wasmExports["_PyLong_FromGid"];var _sigemptyset=Module["_sigemptyset"]=wasmExports["sigemptyset"];var _sigaddset=Module["_sigaddset"]=wasmExports["sigaddset"];var _access=Module["_access"]=wasmExports["access"];var _ttyname_r=Module["_ttyname_r"]=wasmExports["ttyname_r"];var _fchdir=Module["_fchdir"]=wasmExports["fchdir"];var _fchmod=Module["_fchmod"]=wasmExports["fchmod"];var _fchmodat=Module["_fchmodat"]=wasmExports["fchmodat"];var _chmod=Module["_chmod"]=wasmExports["chmod"];var _fchown=Module["_fchown"]=wasmExports["fchown"];var _fchownat=Module["_fchownat"]=wasmExports["fchownat"];var _chown=Module["_chown"]=wasmExports["chown"];var _chroot=Module["_chroot"]=wasmExports["chroot"];var _ctermid=Module["_ctermid"]=wasmExports["ctermid"];var _fdopendir=Module["_fdopendir"]=wasmExports["fdopendir"];var _rewinddir=Module["_rewinddir"]=wasmExports["rewinddir"];var _mkdirat=Module["_mkdirat"]=wasmExports["mkdirat"];var _mkdir=Module["_mkdir"]=wasmExports["mkdir"];var _getpriority=Module["_getpriority"]=wasmExports["getpriority"];var _readlinkat=Module["_readlinkat"]=wasmExports["readlinkat"];var _unlinkat=Module["_unlinkat"]=wasmExports["unlinkat"];var _rmdir=Module["_rmdir"]=wasmExports["rmdir"];var _symlink=Module["_symlink"]=wasmExports["symlink"];var _system=Module["_system"]=wasmExports["system"];var _uname=Module["_uname"]=wasmExports["uname"];var _futimesat=Module["_futimesat"]=wasmExports["futimesat"];var _futimens=Module["_futimens"]=wasmExports["futimens"];var _times=Module["_times"]=wasmExports["times"];var _fexecve=Module["_fexecve"]=wasmExports["fexecve"];var _posix_openpt=Module["_posix_openpt"]=wasmExports["posix_openpt"];var _grantpt=Module["_grantpt"]=wasmExports["grantpt"];var _unlockpt=Module["_unlockpt"]=wasmExports["unlockpt"];var _ptsname_r=Module["_ptsname_r"]=wasmExports["ptsname_r"];var _login_tty=Module["_login_tty"]=wasmExports["login_tty"];var _getgid=Module["_getgid"]=wasmExports["getgid"];var _getpgrp=Module["_getpgrp"]=wasmExports["getpgrp"];var _getppid=Module["_getppid"]=wasmExports["getppid"];var _getuid=Module["_getuid"]=wasmExports["getuid"];var _getlogin=Module["_getlogin"]=wasmExports["getlogin"];var _killpg=Module["_killpg"]=wasmExports["killpg"];var _setuid=Module["_setuid"]=wasmExports["setuid"];var _setgid=Module["_setgid"]=wasmExports["setgid"];var _getpgid=Module["_getpgid"]=wasmExports["getpgid"];var _setpgrp=Module["_setpgrp"]=wasmExports["setpgrp"];var _wait=Module["_wait"]=wasmExports["wait"];var _wait3=Module["_wait3"]=wasmExports["wait3"];var _wait4=Module["_wait4"]=wasmExports["wait4"];var _waitid=Module["_waitid"]=wasmExports["waitid"];var _waitpid=Module["_waitpid"]=wasmExports["waitpid"];var _getsid=Module["_getsid"]=wasmExports["getsid"];var _tcgetpgrp=Module["_tcgetpgrp"]=wasmExports["tcgetpgrp"];var _tcsetpgrp=Module["_tcsetpgrp"]=wasmExports["tcsetpgrp"];var _openat=Module["_openat"]=wasmExports["openat"];var _dup3=Module["_dup3"]=wasmExports["dup3"];var _lockf=Module["_lockf"]=wasmExports["lockf"];var _readv=Module["_readv"]=wasmExports["readv"];var _pread=Module["_pread"]=wasmExports["pread"];var _writev=Module["_writev"]=wasmExports["writev"];var _pwrite=Module["_pwrite"]=wasmExports["pwrite"];var _pipe=Module["_pipe"]=wasmExports["pipe"];var _truncate=Module["_truncate"]=wasmExports["truncate"];var _posix_fadvise=Module["_posix_fadvise"]=wasmExports["posix_fadvise"];var _unsetenv=Module["_unsetenv"]=wasmExports["unsetenv"];var _fsync=Module["_fsync"]=wasmExports["fsync"];var _sync=Module["_sync"]=wasmExports["sync"];var _fdatasync=Module["_fdatasync"]=wasmExports["fdatasync"];var _fstatvfs=Module["_fstatvfs"]=wasmExports["fstatvfs"];var _statvfs=Module["_statvfs"]=wasmExports["statvfs"];var _fpathconf=Module["_fpathconf"]=wasmExports["fpathconf"];var _pathconf=Module["_pathconf"]=wasmExports["pathconf"];var _getloadavg=Module["_getloadavg"]=wasmExports["getloadavg"];var _lstat=Module["_lstat"]=wasmExports["lstat"];var _fstatat=Module["_fstatat"]=wasmExports["fstatat"];var _renameat=Module["_renameat"]=wasmExports["renameat"];var _rename=Module["_rename"]=wasmExports["rename"];var _unlink=Module["_unlink"]=wasmExports["unlink"];var _utimes=Module["_utimes"]=wasmExports["utimes"];var _qsort=Module["_qsort"]=wasmExports["qsort"];var _PySignal_SetWakeupFd=Module["_PySignal_SetWakeupFd"]=wasmExports["PySignal_SetWakeupFd"];var __PyErr_CheckSignals=Module["__PyErr_CheckSignals"]=wasmExports["_PyErr_CheckSignals"];var _PyErr_SetInterrupt=Module["_PyErr_SetInterrupt"]=wasmExports["PyErr_SetInterrupt"];var _PyOS_InterruptOccurred=Module["_PyOS_InterruptOccurred"]=wasmExports["PyOS_InterruptOccurred"];var __PyOS_IsMainThread=Module["__PyOS_IsMainThread"]=wasmExports["_PyOS_IsMainThread"];var _getitimer=Module["_getitimer"]=wasmExports["getitimer"];var _strsignal=Module["_strsignal"]=wasmExports["strsignal"];var _pause=Module["_pause"]=wasmExports["pause"];var _sigpending=Module["_sigpending"]=wasmExports["sigpending"];var _sigwait=Module["_sigwait"]=wasmExports["sigwait"];var _sigwaitinfo=Module["_sigwaitinfo"]=wasmExports["sigwaitinfo"];var _sigtimedwait=Module["_sigtimedwait"]=wasmExports["sigtimedwait"];var _sigismember=Module["_sigismember"]=wasmExports["sigismember"];var ___libc_current_sigrtmin=Module["___libc_current_sigrtmin"]=wasmExports["__libc_current_sigrtmin"];var ___libc_current_sigrtmax=Module["___libc_current_sigrtmax"]=wasmExports["__libc_current_sigrtmax"];var _isalnum=Module["_isalnum"]=wasmExports["isalnum"];var _tolower=Module["_tolower"]=wasmExports["tolower"];var _toupper=Module["_toupper"]=wasmExports["toupper"];var _clock_settime=Module["_clock_settime"]=wasmExports["clock_settime"];var _pthread_getcpuclockid=Module["_pthread_getcpuclockid"]=wasmExports["pthread_getcpuclockid"];var _clock_nanosleep=Module["_clock_nanosleep"]=wasmExports["clock_nanosleep"];var _time=Module["_time"]=wasmExports["time"];var _mktime=Module["_mktime"]=wasmExports["mktime"];var _wcsftime=Module["_wcsftime"]=wasmExports["wcsftime"];var _clock=Module["_clock"]=wasmExports["clock"];var _wcscoll=Module["_wcscoll"]=wasmExports["wcscoll"];var _wcsxfrm=Module["_wcsxfrm"]=wasmExports["wcsxfrm"];var _gettext=Module["_gettext"]=wasmExports["gettext"];var _dgettext=Module["_dgettext"]=wasmExports["dgettext"];var _dcgettext=Module["_dcgettext"]=wasmExports["dcgettext"];var _textdomain=Module["_textdomain"]=wasmExports["textdomain"];var _bindtextdomain=Module["_bindtextdomain"]=wasmExports["bindtextdomain"];var _bind_textdomain_codeset=Module["_bind_textdomain_codeset"]=wasmExports["bind_textdomain_codeset"];var _gettimeofday=Module["_gettimeofday"]=wasmExports["gettimeofday"];var ___small_fprintf=Module["___small_fprintf"]=wasmExports["__small_fprintf"];var __Py_Get_Getpath_CodeObject=Module["__Py_Get_Getpath_CodeObject"]=wasmExports["_Py_Get_Getpath_CodeObject"];var _ffi_prep_closure=Module["_ffi_prep_closure"]=wasmExports["ffi_prep_closure"];var _ffi_get_struct_offsets=Module["_ffi_get_struct_offsets"]=wasmExports["ffi_get_struct_offsets"];var _ffi_java_raw_size=Module["_ffi_java_raw_size"]=wasmExports["ffi_java_raw_size"];var _ffi_java_raw_to_ptrarray=Module["_ffi_java_raw_to_ptrarray"]=wasmExports["ffi_java_raw_to_ptrarray"];var _ffi_java_ptrarray_to_raw=Module["_ffi_java_ptrarray_to_raw"]=wasmExports["ffi_java_ptrarray_to_raw"];var _ffi_java_raw_call=Module["_ffi_java_raw_call"]=wasmExports["ffi_java_raw_call"];var _ffi_prep_java_raw_closure_loc=Module["_ffi_prep_java_raw_closure_loc"]=wasmExports["ffi_prep_java_raw_closure_loc"];var _ffi_prep_java_raw_closure=Module["_ffi_prep_java_raw_closure"]=wasmExports["ffi_prep_java_raw_closure"];var _ffi_tramp_is_supported=Module["_ffi_tramp_is_supported"]=wasmExports["ffi_tramp_is_supported"];var _ffi_tramp_alloc=Module["_ffi_tramp_alloc"]=wasmExports["ffi_tramp_alloc"];var _ffi_tramp_set_parms=Module["_ffi_tramp_set_parms"]=wasmExports["ffi_tramp_set_parms"];var _ffi_tramp_get_addr=Module["_ffi_tramp_get_addr"]=wasmExports["ffi_tramp_get_addr"];var _ffi_tramp_free=Module["_ffi_tramp_free"]=wasmExports["ffi_tramp_free"];var __hiwire_immortal_add=Module["__hiwire_immortal_add"]=wasmExports["_hiwire_immortal_add"];var __hiwire_immortal_get=Module["__hiwire_immortal_get"]=wasmExports["_hiwire_immortal_get"];var __hiwire_get=Module["__hiwire_get"]=wasmExports["_hiwire_get"];var __hiwire_set=Module["__hiwire_set"]=wasmExports["_hiwire_set"];var _hiwire_num_refs=Module["_hiwire_num_refs"]=wasmExports["hiwire_num_refs"];var __hiwire_slot_info=Module["__hiwire_slot_info"]=wasmExports["_hiwire_slot_info"];var __hiwire_delete=Module["__hiwire_delete"]=wasmExports["_hiwire_delete"];var __hiwire_immortal_table_init=Module["__hiwire_immortal_table_init"]=wasmExports["_hiwire_immortal_table_init"];var _emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=wasmExports["emscripten_GetProcAddress"];var _emscripten_webgl1_get_proc_address=Module["_emscripten_webgl1_get_proc_address"]=wasmExports["emscripten_webgl1_get_proc_address"];var __webgl1_match_ext_proc_address_without_suffix=Module["__webgl1_match_ext_proc_address_without_suffix"]=wasmExports["_webgl1_match_ext_proc_address_without_suffix"];var _emscripten_webgl2_get_proc_address=Module["_emscripten_webgl2_get_proc_address"]=wasmExports["emscripten_webgl2_get_proc_address"];var __webgl2_match_ext_proc_address_without_suffix=Module["__webgl2_match_ext_proc_address_without_suffix"]=wasmExports["_webgl2_match_ext_proc_address_without_suffix"];var _emscripten_webgl_get_proc_address=Module["_emscripten_webgl_get_proc_address"]=wasmExports["emscripten_webgl_get_proc_address"];var _SDL_GL_GetProcAddress=Module["_SDL_GL_GetProcAddress"]=wasmExports["SDL_GL_GetProcAddress"];var _eglGetProcAddress=Module["_eglGetProcAddress"]=wasmExports["eglGetProcAddress"];var _glfwGetProcAddress=Module["_glfwGetProcAddress"]=wasmExports["glfwGetProcAddress"];var _emscripten_webgl_init_context_attributes=Module["_emscripten_webgl_init_context_attributes"]=wasmExports["emscripten_webgl_init_context_attributes"];var _emscripten_is_main_runtime_thread=Module["_emscripten_is_main_runtime_thread"]=wasmExports["emscripten_is_main_runtime_thread"];var _BZ2_blockSort=Module["_BZ2_blockSort"]=wasmExports["BZ2_blockSort"];var _BZ2_bz__AssertH__fail=Module["_BZ2_bz__AssertH__fail"]=wasmExports["BZ2_bz__AssertH__fail"];var _BZ2_bzlibVersion=Module["_BZ2_bzlibVersion"]=wasmExports["BZ2_bzlibVersion"];var _BZ2_compressBlock=Module["_BZ2_compressBlock"]=wasmExports["BZ2_compressBlock"];var _BZ2_indexIntoF=Module["_BZ2_indexIntoF"]=wasmExports["BZ2_indexIntoF"];var _BZ2_decompress=Module["_BZ2_decompress"]=wasmExports["BZ2_decompress"];var _BZ2_bzWriteOpen=Module["_BZ2_bzWriteOpen"]=wasmExports["BZ2_bzWriteOpen"];var _BZ2_bzWrite=Module["_BZ2_bzWrite"]=wasmExports["BZ2_bzWrite"];var _BZ2_bzWriteClose=Module["_BZ2_bzWriteClose"]=wasmExports["BZ2_bzWriteClose"];var _BZ2_bzWriteClose64=Module["_BZ2_bzWriteClose64"]=wasmExports["BZ2_bzWriteClose64"];var _BZ2_bzReadOpen=Module["_BZ2_bzReadOpen"]=wasmExports["BZ2_bzReadOpen"];var _BZ2_bzReadClose=Module["_BZ2_bzReadClose"]=wasmExports["BZ2_bzReadClose"];var _BZ2_bzRead=Module["_BZ2_bzRead"]=wasmExports["BZ2_bzRead"];var _fgetc=Module["_fgetc"]=wasmExports["fgetc"];var _BZ2_bzReadGetUnused=Module["_BZ2_bzReadGetUnused"]=wasmExports["BZ2_bzReadGetUnused"];var _BZ2_bzBuffToBuffCompress=Module["_BZ2_bzBuffToBuffCompress"]=wasmExports["BZ2_bzBuffToBuffCompress"];var _BZ2_bzBuffToBuffDecompress=Module["_BZ2_bzBuffToBuffDecompress"]=wasmExports["BZ2_bzBuffToBuffDecompress"];var _BZ2_bzopen=Module["_BZ2_bzopen"]=wasmExports["BZ2_bzopen"];var _BZ2_bzdopen=Module["_BZ2_bzdopen"]=wasmExports["BZ2_bzdopen"];var _BZ2_bzread=Module["_BZ2_bzread"]=wasmExports["BZ2_bzread"];var _BZ2_bzwrite=Module["_BZ2_bzwrite"]=wasmExports["BZ2_bzwrite"];var _BZ2_bzflush=Module["_BZ2_bzflush"]=wasmExports["BZ2_bzflush"];var _BZ2_bzclose=Module["_BZ2_bzclose"]=wasmExports["BZ2_bzclose"];var _BZ2_bzerror=Module["_BZ2_bzerror"]=wasmExports["BZ2_bzerror"];var _BZ2_bsInitWrite=Module["_BZ2_bsInitWrite"]=wasmExports["BZ2_bsInitWrite"];var _BZ2_hbMakeCodeLengths=Module["_BZ2_hbMakeCodeLengths"]=wasmExports["BZ2_hbMakeCodeLengths"];var _BZ2_hbAssignCodes=Module["_BZ2_hbAssignCodes"]=wasmExports["BZ2_hbAssignCodes"];var _BZ2_hbCreateDecodeTables=Module["_BZ2_hbCreateDecodeTables"]=wasmExports["BZ2_hbCreateDecodeTables"];var _adler32_z=Module["_adler32_z"]=wasmExports["adler32_z"];var _adler32_combine=Module["_adler32_combine"]=wasmExports["adler32_combine"];var _adler32_combine64=Module["_adler32_combine64"]=wasmExports["adler32_combine64"];var _compress2=Module["_compress2"]=wasmExports["compress2"];var _deflateInit_=Module["_deflateInit_"]=wasmExports["deflateInit_"];var _compress=Module["_compress"]=wasmExports["compress"];var _compressBound=Module["_compressBound"]=wasmExports["compressBound"];var _get_crc_table=Module["_get_crc_table"]=wasmExports["get_crc_table"];var _crc32_z=Module["_crc32_z"]=wasmExports["crc32_z"];var _crc32_combine64=Module["_crc32_combine64"]=wasmExports["crc32_combine64"];var _crc32_combine=Module["_crc32_combine"]=wasmExports["crc32_combine"];var _crc32_combine_gen64=Module["_crc32_combine_gen64"]=wasmExports["crc32_combine_gen64"];var _crc32_combine_gen=Module["_crc32_combine_gen"]=wasmExports["crc32_combine_gen"];var _crc32_combine_op=Module["_crc32_combine_op"]=wasmExports["crc32_combine_op"];var _zcalloc=Module["_zcalloc"]=wasmExports["zcalloc"];var _zcfree=Module["_zcfree"]=wasmExports["zcfree"];var _deflateReset=Module["_deflateReset"]=wasmExports["deflateReset"];var _deflateResetKeep=Module["_deflateResetKeep"]=wasmExports["deflateResetKeep"];var _deflateGetDictionary=Module["_deflateGetDictionary"]=wasmExports["deflateGetDictionary"];var __tr_init=Module["__tr_init"]=wasmExports["_tr_init"];var _deflateSetHeader=Module["_deflateSetHeader"]=wasmExports["deflateSetHeader"];var _deflatePending=Module["_deflatePending"]=wasmExports["deflatePending"];var _deflatePrime=Module["_deflatePrime"]=wasmExports["deflatePrime"];var __tr_flush_bits=Module["__tr_flush_bits"]=wasmExports["_tr_flush_bits"];var _deflateParams=Module["_deflateParams"]=wasmExports["deflateParams"];var __tr_align=Module["__tr_align"]=wasmExports["_tr_align"];var __tr_stored_block=Module["__tr_stored_block"]=wasmExports["_tr_stored_block"];var _deflateTune=Module["_deflateTune"]=wasmExports["deflateTune"];var _deflateBound=Module["_deflateBound"]=wasmExports["deflateBound"];var __tr_flush_block=Module["__tr_flush_block"]=wasmExports["_tr_flush_block"];var _gzclose=Module["_gzclose"]=wasmExports["gzclose"];var _gzclose_r=Module["_gzclose_r"]=wasmExports["gzclose_r"];var _gzclose_w=Module["_gzclose_w"]=wasmExports["gzclose_w"];var _gzopen=Module["_gzopen"]=wasmExports["gzopen"];var _gzopen64=Module["_gzopen64"]=wasmExports["gzopen64"];var _gzdopen=Module["_gzdopen"]=wasmExports["gzdopen"];var _gzbuffer=Module["_gzbuffer"]=wasmExports["gzbuffer"];var _gzrewind=Module["_gzrewind"]=wasmExports["gzrewind"];var _gzseek64=Module["_gzseek64"]=wasmExports["gzseek64"];var _gz_error=Module["_gz_error"]=wasmExports["gz_error"];var _gzseek=Module["_gzseek"]=wasmExports["gzseek"];var _gztell64=Module["_gztell64"]=wasmExports["gztell64"];var _gztell=Module["_gztell"]=wasmExports["gztell"];var _gzoffset64=Module["_gzoffset64"]=wasmExports["gzoffset64"];var _gzoffset=Module["_gzoffset"]=wasmExports["gzoffset"];var _gzeof=Module["_gzeof"]=wasmExports["gzeof"];var _gzerror=Module["_gzerror"]=wasmExports["gzerror"];var _gzclearerr=Module["_gzclearerr"]=wasmExports["gzclearerr"];var _gz_intmax=Module["_gz_intmax"]=wasmExports["gz_intmax"];var _gzread=Module["_gzread"]=wasmExports["gzread"];var _gzfread=Module["_gzfread"]=wasmExports["gzfread"];var _gzgetc=Module["_gzgetc"]=wasmExports["gzgetc"];var _gzgetc_=Module["_gzgetc_"]=wasmExports["gzgetc_"];var _gzungetc=Module["_gzungetc"]=wasmExports["gzungetc"];var _inflateReset=Module["_inflateReset"]=wasmExports["inflateReset"];var _gzgets=Module["_gzgets"]=wasmExports["gzgets"];var _gzdirect=Module["_gzdirect"]=wasmExports["gzdirect"];var _gzwrite=Module["_gzwrite"]=wasmExports["gzwrite"];var _gzfwrite=Module["_gzfwrite"]=wasmExports["gzfwrite"];var _gzputc=Module["_gzputc"]=wasmExports["gzputc"];var _gzputs=Module["_gzputs"]=wasmExports["gzputs"];var _gzvprintf=Module["_gzvprintf"]=wasmExports["gzvprintf"];var _gzprintf=Module["_gzprintf"]=wasmExports["gzprintf"];var _gzflush=Module["_gzflush"]=wasmExports["gzflush"];var _gzsetparams=Module["_gzsetparams"]=wasmExports["gzsetparams"];var _inflateBackInit_=Module["_inflateBackInit_"]=wasmExports["inflateBackInit_"];var _inflateBack=Module["_inflateBack"]=wasmExports["inflateBack"];var _inflate_table=Module["_inflate_table"]=wasmExports["inflate_table"];var _inflate_fast=Module["_inflate_fast"]=wasmExports["inflate_fast"];var _inflateBackEnd=Module["_inflateBackEnd"]=wasmExports["inflateBackEnd"];var _inflateResetKeep=Module["_inflateResetKeep"]=wasmExports["inflateResetKeep"];var _inflateReset2=Module["_inflateReset2"]=wasmExports["inflateReset2"];var _inflateInit_=Module["_inflateInit_"]=wasmExports["inflateInit_"];var _inflatePrime=Module["_inflatePrime"]=wasmExports["inflatePrime"];var _inflateGetDictionary=Module["_inflateGetDictionary"]=wasmExports["inflateGetDictionary"];var _inflateGetHeader=Module["_inflateGetHeader"]=wasmExports["inflateGetHeader"];var _inflateSync=Module["_inflateSync"]=wasmExports["inflateSync"];var _inflateSyncPoint=Module["_inflateSyncPoint"]=wasmExports["inflateSyncPoint"];var _inflateUndermine=Module["_inflateUndermine"]=wasmExports["inflateUndermine"];var _inflateValidate=Module["_inflateValidate"]=wasmExports["inflateValidate"];var _inflateMark=Module["_inflateMark"]=wasmExports["inflateMark"];var _inflateCodesUsed=Module["_inflateCodesUsed"]=wasmExports["inflateCodesUsed"];var __tr_tally=Module["__tr_tally"]=wasmExports["_tr_tally"];var _uncompress2=Module["_uncompress2"]=wasmExports["uncompress2"];var _uncompress=Module["_uncompress"]=wasmExports["uncompress"];var _zlibCompileFlags=Module["_zlibCompileFlags"]=wasmExports["zlibCompileFlags"];var _zError=Module["_zError"]=wasmExports["zError"];var _getdate=Module["_getdate"]=wasmExports["getdate"];var _stime=Module["_stime"]=wasmExports["stime"];var _clock_getcpuclockid=Module["_clock_getcpuclockid"]=wasmExports["clock_getcpuclockid"];var _getpwnam=Module["_getpwnam"]=wasmExports["getpwnam"];var _getpwuid=Module["_getpwuid"]=wasmExports["getpwuid"];var _getpwnam_r=Module["_getpwnam_r"]=wasmExports["getpwnam_r"];var _getpwuid_r=Module["_getpwuid_r"]=wasmExports["getpwuid_r"];var _setpwent=Module["_setpwent"]=wasmExports["setpwent"];var _endpwent=Module["_endpwent"]=wasmExports["endpwent"];var _getpwent=Module["_getpwent"]=wasmExports["getpwent"];var _getgrnam=Module["_getgrnam"]=wasmExports["getgrnam"];var _getgrgid=Module["_getgrgid"]=wasmExports["getgrgid"];var _getgrnam_r=Module["_getgrnam_r"]=wasmExports["getgrnam_r"];var _getgrgid_r=Module["_getgrgid_r"]=wasmExports["getgrgid_r"];var _getgrent=Module["_getgrent"]=wasmExports["getgrent"];var _endgrent=Module["_endgrent"]=wasmExports["endgrent"];var _setgrent=Module["_setgrent"]=wasmExports["setgrent"];var _flock=Module["_flock"]=wasmExports["flock"];var _vfork=Module["_vfork"]=wasmExports["vfork"];var _posix_spawn=Module["_posix_spawn"]=wasmExports["posix_spawn"];var _popen=Module["_popen"]=wasmExports["popen"];var _pclose=Module["_pclose"]=wasmExports["pclose"];var _setgroups=Module["_setgroups"]=wasmExports["setgroups"];var _sigaltstack=Module["_sigaltstack"]=wasmExports["sigaltstack"];var ___syscall_uname=Module["___syscall_uname"]=wasmExports["__syscall_uname"];var ___syscall_setpgid=Module["___syscall_setpgid"]=wasmExports["__syscall_setpgid"];var ___syscall_sync=Module["___syscall_sync"]=wasmExports["__syscall_sync"];var ___syscall_getsid=Module["___syscall_getsid"]=wasmExports["__syscall_getsid"];var ___syscall_getpgid=Module["___syscall_getpgid"]=wasmExports["__syscall_getpgid"];var ___syscall_getpid=Module["___syscall_getpid"]=wasmExports["__syscall_getpid"];var ___syscall_getppid=Module["___syscall_getppid"]=wasmExports["__syscall_getppid"];var ___syscall_linkat=Module["___syscall_linkat"]=wasmExports["__syscall_linkat"];var ___syscall_getgroups32=Module["___syscall_getgroups32"]=wasmExports["__syscall_getgroups32"];var ___syscall_setsid=Module["___syscall_setsid"]=wasmExports["__syscall_setsid"];var ___syscall_umask=Module["___syscall_umask"]=wasmExports["__syscall_umask"];var ___syscall_getrusage=Module["___syscall_getrusage"]=wasmExports["__syscall_getrusage"];var ___syscall_getpriority=Module["___syscall_getpriority"]=wasmExports["__syscall_getpriority"];var ___syscall_setpriority=Module["___syscall_setpriority"]=wasmExports["__syscall_setpriority"];var ___syscall_setdomainname=Module["___syscall_setdomainname"]=wasmExports["__syscall_setdomainname"];var ___syscall_getuid32=Module["___syscall_getuid32"]=wasmExports["__syscall_getuid32"];var ___syscall_getgid32=Module["___syscall_getgid32"]=wasmExports["__syscall_getgid32"];var ___syscall_geteuid32=Module["___syscall_geteuid32"]=wasmExports["__syscall_geteuid32"];var ___syscall_getegid32=Module["___syscall_getegid32"]=wasmExports["__syscall_getegid32"];var ___syscall_getresuid32=Module["___syscall_getresuid32"]=wasmExports["__syscall_getresuid32"];var ___syscall_getresgid32=Module["___syscall_getresgid32"]=wasmExports["__syscall_getresgid32"];var ___syscall_pause=Module["___syscall_pause"]=wasmExports["__syscall_pause"];var ___syscall_madvise=Module["___syscall_madvise"]=wasmExports["__syscall_madvise"];var ___syscall_mlock=Module["___syscall_mlock"]=wasmExports["__syscall_mlock"];var ___syscall_munlock=Module["___syscall_munlock"]=wasmExports["__syscall_munlock"];var ___syscall_mprotect=Module["___syscall_mprotect"]=wasmExports["__syscall_mprotect"];var ___syscall_mremap=Module["___syscall_mremap"]=wasmExports["__syscall_mremap"];var ___syscall_mlockall=Module["___syscall_mlockall"]=wasmExports["__syscall_mlockall"];var ___syscall_munlockall=Module["___syscall_munlockall"]=wasmExports["__syscall_munlockall"];var ___syscall_prlimit64=Module["___syscall_prlimit64"]=wasmExports["__syscall_prlimit64"];var _emscripten_stack_get_end=Module["_emscripten_stack_get_end"]=wasmExports["emscripten_stack_get_end"];var _emscripten_stack_get_base=Module["_emscripten_stack_get_base"]=wasmExports["emscripten_stack_get_base"];var ___syscall_setsockopt=Module["___syscall_setsockopt"]=wasmExports["__syscall_setsockopt"];var ___syscall_acct=Module["___syscall_acct"]=wasmExports["__syscall_acct"];var ___syscall_mincore=Module["___syscall_mincore"]=wasmExports["__syscall_mincore"];var ___syscall_pipe2=Module["___syscall_pipe2"]=wasmExports["__syscall_pipe2"];var ___syscall_pselect6=Module["___syscall_pselect6"]=wasmExports["__syscall_pselect6"];var ___syscall_recvmmsg=Module["___syscall_recvmmsg"]=wasmExports["__syscall_recvmmsg"];var ___syscall_sendmmsg=Module["___syscall_sendmmsg"]=wasmExports["__syscall_sendmmsg"];var ___syscall_shutdown=Module["___syscall_shutdown"]=wasmExports["__syscall_shutdown"];var ___syscall_socketpair=Module["___syscall_socketpair"]=wasmExports["__syscall_socketpair"];var ___syscall_wait4=Module["___syscall_wait4"]=wasmExports["__syscall_wait4"];var _cosf=Module["_cosf"]=wasmExports["cosf"];var _sinf=Module["_sinf"]=wasmExports["sinf"];var _expf=Module["_expf"]=wasmExports["expf"];var ___multf3=Module["___multf3"]=wasmExports["__multf3"];var ___addtf3=Module["___addtf3"]=wasmExports["__addtf3"];var ___subtf3=Module["___subtf3"]=wasmExports["__subtf3"];var ___ctype_b_loc=Module["___ctype_b_loc"]=wasmExports["__ctype_b_loc"];var ___ctype_get_mb_cur_max=Module["___ctype_get_mb_cur_max"]=wasmExports["__ctype_get_mb_cur_max"];var ___get_tp=Module["___get_tp"]=wasmExports["__get_tp"];var ___ctype_tolower_loc=Module["___ctype_tolower_loc"]=wasmExports["__ctype_tolower_loc"];var ___ctype_toupper_loc=Module["___ctype_toupper_loc"]=wasmExports["__ctype_toupper_loc"];var ___emscripten_environ_constructor=Module["___emscripten_environ_constructor"]=wasmExports["__emscripten_environ_constructor"];var _emscripten_builtin_malloc=Module["_emscripten_builtin_malloc"]=wasmExports["emscripten_builtin_malloc"];var ___flt_rounds=Module["___flt_rounds"]=wasmExports["__flt_rounds"];var _fegetround=Module["_fegetround"]=wasmExports["fegetround"];var ___fmodeflags=Module["___fmodeflags"]=wasmExports["__fmodeflags"];var ___fpclassify=Module["___fpclassify"]=wasmExports["__fpclassify"];var ___fpclassifyf=Module["___fpclassifyf"]=wasmExports["__fpclassifyf"];var ___fpclassifyl=Module["___fpclassifyl"]=wasmExports["__fpclassifyl"];var ___divtf3=Module["___divtf3"]=wasmExports["__divtf3"];var ___mo_lookup=Module["___mo_lookup"]=wasmExports["__mo_lookup"];var ___month_to_secs=Module["___month_to_secs"]=wasmExports["__month_to_secs"];var ___overflow=Module["___overflow"]=wasmExports["__overflow"];var _scalbn=Module["_scalbn"]=wasmExports["scalbn"];var _floor=Module["_floor"]=wasmExports["floor"];var ___lttf2=Module["___lttf2"]=wasmExports["__lttf2"];var ___fixtfdi=Module["___fixtfdi"]=wasmExports["__fixtfdi"];var ___gttf2=Module["___gttf2"]=wasmExports["__gttf2"];var ___fixtfsi=Module["___fixtfsi"]=wasmExports["__fixtfsi"];var ___floatsitf=Module["___floatsitf"]=wasmExports["__floatsitf"];var ___signbit=Module["___signbit"]=wasmExports["__signbit"];var ___signbitf=Module["___signbitf"]=wasmExports["__signbitf"];var ___signbitl=Module["___signbitl"]=wasmExports["__signbitl"];var _memcpy=wasmExports["memcpy"];var ___stack_chk_fail=Module["___stack_chk_fail"]=wasmExports["__stack_chk_fail"];var ___wasi_syscall_ret=Module["___wasi_syscall_ret"]=wasmExports["__wasi_syscall_ret"];var ___synccall=Module["___synccall"]=wasmExports["__synccall"];var _fabsl=Module["_fabsl"]=wasmExports["fabsl"];var ___getf2=Module["___getf2"]=wasmExports["__getf2"];var ___year_to_secs=Module["___year_to_secs"]=wasmExports["__year_to_secs"];var ___lock=Module["___lock"]=wasmExports["__lock"];var ___unlock=Module["___unlock"]=wasmExports["__unlock"];var _tzset=Module["_tzset"]=wasmExports["tzset"];var ___uflow=Module["___uflow"]=wasmExports["__uflow"];var ___fxstat=Module["___fxstat"]=wasmExports["__fxstat"];var ___fxstatat=Module["___fxstatat"]=wasmExports["__fxstatat"];var ___lxstat=Module["___lxstat"]=wasmExports["__lxstat"];var ___xstat=Module["___xstat"]=wasmExports["__xstat"];var ___xmknod=Module["___xmknod"]=wasmExports["__xmknod"];var _mknod=Module["_mknod"]=wasmExports["mknod"];var ___xmknodat=Module["___xmknodat"]=wasmExports["__xmknodat"];var _mknodat=Module["_mknodat"]=wasmExports["mknodat"];var __Exit=Module["__Exit"]=wasmExports["_Exit"];var _a64l=Module["_a64l"]=wasmExports["a64l"];var _l64a=Module["_l64a"]=wasmExports["l64a"];var _abs=Module["_abs"]=wasmExports["abs"];var _acct=Module["_acct"]=wasmExports["acct"];var _acosf=Module["_acosf"]=wasmExports["acosf"];var _sqrtf=Module["_sqrtf"]=wasmExports["sqrtf"];var _acoshf=Module["_acoshf"]=wasmExports["acoshf"];var _log1pf=Module["_log1pf"]=wasmExports["log1pf"];var _logf=Module["_logf"]=wasmExports["logf"];var _acoshl=Module["_acoshl"]=wasmExports["acoshl"];var _acosl=Module["_acosl"]=wasmExports["acosl"];var ___eqtf2=Module["___eqtf2"]=wasmExports["__eqtf2"];var ___netf2=Module["___netf2"]=wasmExports["__netf2"];var _sqrtl=Module["_sqrtl"]=wasmExports["sqrtl"];var _alarm=Module["_alarm"]=wasmExports["alarm"];var _setitimer=Module["_setitimer"]=wasmExports["setitimer"];var _aligned_alloc=Module["_aligned_alloc"]=wasmExports["aligned_alloc"];var _posix_memalign=Module["_posix_memalign"]=wasmExports["posix_memalign"];var _alphasort=Module["_alphasort"]=wasmExports["alphasort"];var _strcoll=Module["_strcoll"]=wasmExports["strcoll"];var _asctime=Module["_asctime"]=wasmExports["asctime"];var ___nl_langinfo_l=Module["___nl_langinfo_l"]=wasmExports["__nl_langinfo_l"];var _asctime_r=Module["_asctime_r"]=wasmExports["asctime_r"];var _asinf=Module["_asinf"]=wasmExports["asinf"];var _fabsf=Module["_fabsf"]=wasmExports["fabsf"];var _asinhf=Module["_asinhf"]=wasmExports["asinhf"];var _asinhl=Module["_asinhl"]=wasmExports["asinhl"];var _asinl=Module["_asinl"]=wasmExports["asinl"];var _asprintf=Module["_asprintf"]=wasmExports["asprintf"];var _vasprintf=Module["_vasprintf"]=wasmExports["vasprintf"];var _at_quick_exit=Module["_at_quick_exit"]=wasmExports["at_quick_exit"];var _atan2f=Module["_atan2f"]=wasmExports["atan2f"];var _atanf=Module["_atanf"]=wasmExports["atanf"];var _atan2l=Module["_atan2l"]=wasmExports["atan2l"];var _atanl=Module["_atanl"]=wasmExports["atanl"];var _atanhf=Module["_atanhf"]=wasmExports["atanhf"];var _atanhl=Module["_atanhl"]=wasmExports["atanhl"];var _log1pl=Module["_log1pl"]=wasmExports["log1pl"];var ___funcs_on_exit=wasmExports["__funcs_on_exit"];var ____cxa_finalize=Module["____cxa_finalize"]=wasmExports["___cxa_finalize"];var ____cxa_atexit=Module["____cxa_atexit"]=wasmExports["___cxa_atexit"];var ___libc_calloc=Module["___libc_calloc"]=wasmExports["__libc_calloc"];var ___atexit=Module["___atexit"]=wasmExports["__atexit"];var ___cxa_atexit=Module["___cxa_atexit"]=wasmExports["__cxa_atexit"];var ___cxa_finalize=Module["___cxa_finalize"]=wasmExports["__cxa_finalize"];var _atof=Module["_atof"]=wasmExports["atof"];var _strtod=Module["_strtod"]=wasmExports["strtod"];var _atoi=Module["_atoi"]=wasmExports["atoi"];var _atol=Module["_atol"]=wasmExports["atol"];var _atoll=Module["_atoll"]=wasmExports["atoll"];var _basename=Module["_basename"]=wasmExports["basename"];var ___xpg_basename=Module["___xpg_basename"]=wasmExports["__xpg_basename"];var _bcmp=Module["_bcmp"]=wasmExports["bcmp"];var _bcopy=Module["_bcopy"]=wasmExports["bcopy"];var _strcasecmp=Module["_strcasecmp"]=wasmExports["strcasecmp"];var _bsearch=Module["_bsearch"]=wasmExports["bsearch"];var _btowc=Module["_btowc"]=wasmExports["btowc"];var _bzero=Module["_bzero"]=wasmExports["bzero"];var _c16rtomb=Module["_c16rtomb"]=wasmExports["c16rtomb"];var _wcrtomb=Module["_wcrtomb"]=wasmExports["wcrtomb"];var _c32rtomb=Module["_c32rtomb"]=wasmExports["c32rtomb"];var _cabs=Module["_cabs"]=wasmExports["cabs"];var _cabsf=Module["_cabsf"]=wasmExports["cabsf"];var _hypotf=Module["_hypotf"]=wasmExports["hypotf"];var _cabsl=Module["_cabsl"]=wasmExports["cabsl"];var _hypotl=Module["_hypotl"]=wasmExports["hypotl"];var _cacos=Module["_cacos"]=wasmExports["cacos"];var _casin=Module["_casin"]=wasmExports["casin"];var _cacosf=Module["_cacosf"]=wasmExports["cacosf"];var _casinf=Module["_casinf"]=wasmExports["casinf"];var _cacosh=Module["_cacosh"]=wasmExports["cacosh"];var _cacoshf=Module["_cacoshf"]=wasmExports["cacoshf"];var _cacoshl=Module["_cacoshl"]=wasmExports["cacoshl"];var _cacosl=Module["_cacosl"]=wasmExports["cacosl"];var _casinl=Module["_casinl"]=wasmExports["casinl"];var _call_once=Module["_call_once"]=wasmExports["call_once"];var _carg=Module["_carg"]=wasmExports["carg"];var _cargf=Module["_cargf"]=wasmExports["cargf"];var _cargl=Module["_cargl"]=wasmExports["cargl"];var _csqrt=Module["_csqrt"]=wasmExports["csqrt"];var _clog=Module["_clog"]=wasmExports["clog"];var _csqrtf=Module["_csqrtf"]=wasmExports["csqrtf"];var _clogf=Module["_clogf"]=wasmExports["clogf"];var _casinh=Module["_casinh"]=wasmExports["casinh"];var _casinhf=Module["_casinhf"]=wasmExports["casinhf"];var _casinhl=Module["_casinhl"]=wasmExports["casinhl"];var _csqrtl=Module["_csqrtl"]=wasmExports["csqrtl"];var _clogl=Module["_clogl"]=wasmExports["clogl"];var _catan=Module["_catan"]=wasmExports["catan"];var _catanf=Module["_catanf"]=wasmExports["catanf"];var _catanh=Module["_catanh"]=wasmExports["catanh"];var _catanhf=Module["_catanhf"]=wasmExports["catanhf"];var _catanhl=Module["_catanhl"]=wasmExports["catanhl"];var _catanl=Module["_catanl"]=wasmExports["catanl"];var _logl=Module["_logl"]=wasmExports["logl"];var ___trunctfsf2=Module["___trunctfsf2"]=wasmExports["__trunctfsf2"];var ___extendsftf2=Module["___extendsftf2"]=wasmExports["__extendsftf2"];var _catclose=Module["_catclose"]=wasmExports["catclose"];var _catgets=Module["_catgets"]=wasmExports["catgets"];var _catopen=Module["_catopen"]=wasmExports["catopen"];var _cbrtf=Module["_cbrtf"]=wasmExports["cbrtf"];var _cbrtl=Module["_cbrtl"]=wasmExports["cbrtl"];var _ccos=Module["_ccos"]=wasmExports["ccos"];var _ccosh=Module["_ccosh"]=wasmExports["ccosh"];var _ccosf=Module["_ccosf"]=wasmExports["ccosf"];var _ccoshf=Module["_ccoshf"]=wasmExports["ccoshf"];var _coshf=Module["_coshf"]=wasmExports["coshf"];var _sinhf=Module["_sinhf"]=wasmExports["sinhf"];var _copysignf=Module["_copysignf"]=wasmExports["copysignf"];var _ccoshl=Module["_ccoshl"]=wasmExports["ccoshl"];var _ccosl=Module["_ccosl"]=wasmExports["ccosl"];var _ceil=Module["_ceil"]=wasmExports["ceil"];var _ceilf=Module["_ceilf"]=wasmExports["ceilf"];var _ceill=Module["_ceill"]=wasmExports["ceill"];var _cexp=Module["_cexp"]=wasmExports["cexp"];var _cexpf=Module["_cexpf"]=wasmExports["cexpf"];var _cexpl=Module["_cexpl"]=wasmExports["cexpl"];var _cfgetospeed=Module["_cfgetospeed"]=wasmExports["cfgetospeed"];var _cfgetispeed=Module["_cfgetispeed"]=wasmExports["cfgetispeed"];var _cfmakeraw=Module["_cfmakeraw"]=wasmExports["cfmakeraw"];var _cfsetospeed=Module["_cfsetospeed"]=wasmExports["cfsetospeed"];var _cfsetispeed=Module["_cfsetispeed"]=wasmExports["cfsetispeed"];var _cfsetspeed=Module["_cfsetspeed"]=wasmExports["cfsetspeed"];var _cimag=Module["_cimag"]=wasmExports["cimag"];var _cimagf=Module["_cimagf"]=wasmExports["cimagf"];var _cimagl=Module["_cimagl"]=wasmExports["cimagl"];var _clearenv=Module["_clearenv"]=wasmExports["clearenv"];var _clearerr_unlocked=Module["_clearerr_unlocked"]=wasmExports["clearerr_unlocked"];var ___wasi_timestamp_to_timespec=Module["___wasi_timestamp_to_timespec"]=wasmExports["__wasi_timestamp_to_timespec"];var _emscripten_thread_sleep=Module["_emscripten_thread_sleep"]=wasmExports["emscripten_thread_sleep"];var _cnd_broadcast=Module["_cnd_broadcast"]=wasmExports["cnd_broadcast"];var _cnd_destroy=Module["_cnd_destroy"]=wasmExports["cnd_destroy"];var _cnd_init=Module["_cnd_init"]=wasmExports["cnd_init"];var _cnd_signal=Module["_cnd_signal"]=wasmExports["cnd_signal"];var _cnd_timedwait=Module["_cnd_timedwait"]=wasmExports["cnd_timedwait"];var _cnd_wait=Module["_cnd_wait"]=wasmExports["cnd_wait"];var _conj=Module["_conj"]=wasmExports["conj"];var _conjf=Module["_conjf"]=wasmExports["conjf"];var _conjl=Module["_conjl"]=wasmExports["conjl"];var _copysignl=Module["_copysignl"]=wasmExports["copysignl"];var _expm1f=Module["_expm1f"]=wasmExports["expm1f"];var _coshl=Module["_coshl"]=wasmExports["coshl"];var _cosl=Module["_cosl"]=wasmExports["cosl"];var _cpow=Module["_cpow"]=wasmExports["cpow"];var ___muldc3=Module["___muldc3"]=wasmExports["__muldc3"];var _cpowf=Module["_cpowf"]=wasmExports["cpowf"];var ___mulsc3=Module["___mulsc3"]=wasmExports["__mulsc3"];var _cpowl=Module["_cpowl"]=wasmExports["cpowl"];var ___unordtf2=Module["___unordtf2"]=wasmExports["__unordtf2"];var ___multc3=Module["___multc3"]=wasmExports["__multc3"];var _cproj=Module["_cproj"]=wasmExports["cproj"];var _cprojf=Module["_cprojf"]=wasmExports["cprojf"];var _cprojl=Module["_cprojl"]=wasmExports["cprojl"];var _creal=Module["_creal"]=wasmExports["creal"];var _crealf=Module["_crealf"]=wasmExports["crealf"];var _creall=Module["_creall"]=wasmExports["creall"];var _creat=Module["_creat"]=wasmExports["creat"];var _crypt=Module["_crypt"]=wasmExports["crypt"];var ___crypt_blowfish=Module["___crypt_blowfish"]=wasmExports["__crypt_blowfish"];var ___crypt_des=Module["___crypt_des"]=wasmExports["__crypt_des"];var ___crypt_md5=Module["___crypt_md5"]=wasmExports["__crypt_md5"];var _strnlen=Module["_strnlen"]=wasmExports["strnlen"];var ___crypt_sha256=Module["___crypt_sha256"]=wasmExports["__crypt_sha256"];var ___crypt_sha512=Module["___crypt_sha512"]=wasmExports["__crypt_sha512"];var _crypt_r=Module["_crypt_r"]=wasmExports["crypt_r"];var _sprintf=Module["_sprintf"]=wasmExports["sprintf"];var _csin=Module["_csin"]=wasmExports["csin"];var _csinh=Module["_csinh"]=wasmExports["csinh"];var _csinf=Module["_csinf"]=wasmExports["csinf"];var _csinhf=Module["_csinhf"]=wasmExports["csinhf"];var _csinhl=Module["_csinhl"]=wasmExports["csinhl"];var _csinl=Module["_csinl"]=wasmExports["csinl"];var _ctan=Module["_ctan"]=wasmExports["ctan"];var _ctanh=Module["_ctanh"]=wasmExports["ctanh"];var _ctanf=Module["_ctanf"]=wasmExports["ctanf"];var _ctanhf=Module["_ctanhf"]=wasmExports["ctanhf"];var _tanf=Module["_tanf"]=wasmExports["tanf"];var _ctanhl=Module["_ctanhl"]=wasmExports["ctanhl"];var _ctanl=Module["_ctanl"]=wasmExports["ctanl"];var _ctime=Module["_ctime"]=wasmExports["ctime"];var _localtime=Module["_localtime"]=wasmExports["localtime"];var _ctime_r=Module["_ctime_r"]=wasmExports["ctime_r"];var _dcngettext=Module["_dcngettext"]=wasmExports["dcngettext"];var ___gettextdomain=Module["___gettextdomain"]=wasmExports["__gettextdomain"];var _dngettext=Module["_dngettext"]=wasmExports["dngettext"];var _difftime=Module["_difftime"]=wasmExports["difftime"];var _dirname=Module["_dirname"]=wasmExports["dirname"];var _div=Module["_div"]=wasmExports["div"];var _dladdr=Module["_dladdr"]=wasmExports["dladdr"];var ___libc_free=Module["___libc_free"]=wasmExports["__libc_free"];var ___libc_malloc=Module["___libc_malloc"]=wasmExports["__libc_malloc"];var ___dl_seterr=wasmExports["__dl_seterr"];var _dn_comp=Module["_dn_comp"]=wasmExports["dn_comp"];var _dn_expand=Module["_dn_expand"]=wasmExports["dn_expand"];var _dn_skipname=Module["_dn_skipname"]=wasmExports["dn_skipname"];var _dprintf=Module["_dprintf"]=wasmExports["dprintf"];var _vdprintf=Module["_vdprintf"]=wasmExports["vdprintf"];var _erand48=Module["_erand48"]=wasmExports["erand48"];var _drand48=Module["_drand48"]=wasmExports["drand48"];var ___wasi_fd_is_valid=Module["___wasi_fd_is_valid"]=wasmExports["__wasi_fd_is_valid"];var ___duplocale=Module["___duplocale"]=wasmExports["__duplocale"];var _duplocale=Module["_duplocale"]=wasmExports["duplocale"];var _new_dlevent=Module["_new_dlevent"]=wasmExports["new_dlevent"];var __emscripten_find_dylib=wasmExports["_emscripten_find_dylib"];var _strspn=Module["_strspn"]=wasmExports["strspn"];var _pthread_setcancelstate=Module["_pthread_setcancelstate"]=wasmExports["pthread_setcancelstate"];var _emscripten_dlopen=Module["_emscripten_dlopen"]=wasmExports["emscripten_dlopen"];var _emscripten_dlopen_promise=Module["_emscripten_dlopen_promise"]=wasmExports["emscripten_dlopen_promise"];var _ecvt=Module["_ecvt"]=wasmExports["ecvt"];var _emscripten_console_logf=Module["_emscripten_console_logf"]=wasmExports["emscripten_console_logf"];var _emscripten_console_errorf=Module["_emscripten_console_errorf"]=wasmExports["emscripten_console_errorf"];var _emscripten_console_warnf=Module["_emscripten_console_warnf"]=wasmExports["emscripten_console_warnf"];var _emscripten_console_tracef=Module["_emscripten_console_tracef"]=wasmExports["emscripten_console_tracef"];var _emscripten_outf=Module["_emscripten_outf"]=wasmExports["emscripten_outf"];var _emscripten_errf=Module["_emscripten_errf"]=wasmExports["emscripten_errf"];var _emscripten_fiber_init=Module["_emscripten_fiber_init"]=wasmExports["emscripten_fiber_init"];var _emscripten_fiber_init_from_current_context=Module["_emscripten_fiber_init_from_current_context"]=wasmExports["emscripten_fiber_init_from_current_context"];var _emscripten_get_heap_size=Module["_emscripten_get_heap_size"]=wasmExports["emscripten_get_heap_size"];var __emscripten_memcpy_bulkmem=Module["__emscripten_memcpy_bulkmem"]=wasmExports["_emscripten_memcpy_bulkmem"];var _emscripten_builtin_memcpy=Module["_emscripten_builtin_memcpy"]=wasmExports["emscripten_builtin_memcpy"];var ___memset=Module["___memset"]=wasmExports["__memset"];var _emscripten_builtin_memset=Module["_emscripten_builtin_memset"]=wasmExports["emscripten_builtin_memset"];var __emscripten_memset_bulkmem=Module["__emscripten_memset_bulkmem"]=wasmExports["_emscripten_memset_bulkmem"];var ___syscall_munmap=Module["___syscall_munmap"]=wasmExports["__syscall_munmap"];var _emscripten_builtin_free=Module["_emscripten_builtin_free"]=wasmExports["emscripten_builtin_free"];var ___syscall_msync=Module["___syscall_msync"]=wasmExports["__syscall_msync"];var ___syscall_mmap2=Module["___syscall_mmap2"]=wasmExports["__syscall_mmap2"];var _emscripten_builtin_memalign=wasmExports["emscripten_builtin_memalign"];var _emscripten_scan_stack=Module["_emscripten_scan_stack"]=wasmExports["emscripten_scan_stack"];var _emscripten_stack_get_current=Module["_emscripten_stack_get_current"]=wasmExports["emscripten_stack_get_current"];var ___time=Module["___time"]=wasmExports["__time"];var ___gettimeofday=Module["___gettimeofday"]=wasmExports["__gettimeofday"];var _dysize=Module["_dysize"]=wasmExports["dysize"];var _setkey=Module["_setkey"]=wasmExports["setkey"];var _encrypt=Module["_encrypt"]=wasmExports["encrypt"];var _sethostent=Module["_sethostent"]=wasmExports["sethostent"];var _gethostent=Module["_gethostent"]=wasmExports["gethostent"];var _getnetent=Module["_getnetent"]=wasmExports["getnetent"];var _endhostent=Module["_endhostent"]=wasmExports["endhostent"];var _setnetent=Module["_setnetent"]=wasmExports["setnetent"];var _endnetent=Module["_endnetent"]=wasmExports["endnetent"];var _erff=Module["_erff"]=wasmExports["erff"];var _erfcf=Module["_erfcf"]=wasmExports["erfcf"];var _erfl=Module["_erfl"]=wasmExports["erfl"];var _erfcl=Module["_erfcl"]=wasmExports["erfcl"];var _vwarn=Module["_vwarn"]=wasmExports["vwarn"];var _fprintf=Module["_fprintf"]=wasmExports["fprintf"];var _vwarnx=Module["_vwarnx"]=wasmExports["vwarnx"];var _putc=Module["_putc"]=wasmExports["putc"];var _verr=Module["_verr"]=wasmExports["verr"];var _verrx=Module["_verrx"]=wasmExports["verrx"];var _warn=Module["_warn"]=wasmExports["warn"];var _warnx=Module["_warnx"]=wasmExports["warnx"];var _err=Module["_err"]=wasmExports["err"];var _errx=Module["_errx"]=wasmExports["errx"];var _ether_aton_r=Module["_ether_aton_r"]=wasmExports["ether_aton_r"];var _ether_aton=Module["_ether_aton"]=wasmExports["ether_aton"];var _ether_ntoa_r=Module["_ether_ntoa_r"]=wasmExports["ether_ntoa_r"];var _ether_ntoa=Module["_ether_ntoa"]=wasmExports["ether_ntoa"];var _ether_line=Module["_ether_line"]=wasmExports["ether_line"];var _ether_ntohost=Module["_ether_ntohost"]=wasmExports["ether_ntohost"];var _ether_hostton=Module["_ether_hostton"]=wasmExports["ether_hostton"];var _euidaccess=Module["_euidaccess"]=wasmExports["euidaccess"];var _faccessat=Module["_faccessat"]=wasmExports["faccessat"];var _eaccess=Module["_eaccess"]=wasmExports["eaccess"];var _execl=Module["_execl"]=wasmExports["execl"];var _execle=Module["_execle"]=wasmExports["execle"];var _execlp=Module["_execlp"]=wasmExports["execlp"];var _execvp=Module["_execvp"]=wasmExports["execvp"];var _execvpe=Module["_execvpe"]=wasmExports["execvpe"];var _exp10=Module["_exp10"]=wasmExports["exp10"];var _pow10=Module["_pow10"]=wasmExports["pow10"];var _exp10f=Module["_exp10f"]=wasmExports["exp10f"];var _modff=Module["_modff"]=wasmExports["modff"];var _exp2f=Module["_exp2f"]=wasmExports["exp2f"];var _pow10f=Module["_pow10f"]=wasmExports["pow10f"];var _exp10l=Module["_exp10l"]=wasmExports["exp10l"];var _modfl=Module["_modfl"]=wasmExports["modfl"];var _exp2l=Module["_exp2l"]=wasmExports["exp2l"];var _powl=Module["_powl"]=wasmExports["powl"];var _pow10l=Module["_pow10l"]=wasmExports["pow10l"];var ___letf2=Module["___letf2"]=wasmExports["__letf2"];var _scalbnl=Module["_scalbnl"]=wasmExports["scalbnl"];var _expl=Module["_expl"]=wasmExports["expl"];var _expm1l=Module["_expm1l"]=wasmExports["expm1l"];var __flushlbf=Module["__flushlbf"]=wasmExports["_flushlbf"];var ___fsetlocking=Module["___fsetlocking"]=wasmExports["__fsetlocking"];var ___fwriting=Module["___fwriting"]=wasmExports["__fwriting"];var ___freading=Module["___freading"]=wasmExports["__freading"];var ___freadable=Module["___freadable"]=wasmExports["__freadable"];var ___fwritable=Module["___fwritable"]=wasmExports["__fwritable"];var ___flbf=Module["___flbf"]=wasmExports["__flbf"];var ___fbufsize=Module["___fbufsize"]=wasmExports["__fbufsize"];var ___fpending=Module["___fpending"]=wasmExports["__fpending"];var ___fpurge=Module["___fpurge"]=wasmExports["__fpurge"];var _fpurge=Module["_fpurge"]=wasmExports["fpurge"];var ___freadahead=Module["___freadahead"]=wasmExports["__freadahead"];var ___freadptr=Module["___freadptr"]=wasmExports["__freadptr"];var ___freadptrinc=Module["___freadptrinc"]=wasmExports["__freadptrinc"];var ___fseterr=Module["___fseterr"]=wasmExports["__fseterr"];var _fcvt=Module["_fcvt"]=wasmExports["fcvt"];var _fdim=Module["_fdim"]=wasmExports["fdim"];var _fdimf=Module["_fdimf"]=wasmExports["fdimf"];var _fdiml=Module["_fdiml"]=wasmExports["fdiml"];var _fegetexceptflag=Module["_fegetexceptflag"]=wasmExports["fegetexceptflag"];var _fetestexcept=Module["_fetestexcept"]=wasmExports["fetestexcept"];var _feholdexcept=Module["_feholdexcept"]=wasmExports["feholdexcept"];var _fegetenv=Module["_fegetenv"]=wasmExports["fegetenv"];var _feclearexcept=Module["_feclearexcept"]=wasmExports["feclearexcept"];var _feraiseexcept=Module["_feraiseexcept"]=wasmExports["feraiseexcept"];var ___fesetround=Module["___fesetround"]=wasmExports["__fesetround"];var _fesetenv=Module["_fesetenv"]=wasmExports["fesetenv"];var _feof_unlocked=Module["_feof_unlocked"]=wasmExports["feof_unlocked"];var __IO_feof_unlocked=Module["__IO_feof_unlocked"]=wasmExports["_IO_feof_unlocked"];var _ferror_unlocked=Module["_ferror_unlocked"]=wasmExports["ferror_unlocked"];var __IO_ferror_unlocked=Module["__IO_ferror_unlocked"]=wasmExports["_IO_ferror_unlocked"];var _fesetexceptflag=Module["_fesetexceptflag"]=wasmExports["fesetexceptflag"];var _fesetround=Module["_fesetround"]=wasmExports["fesetround"];var _feupdateenv=Module["_feupdateenv"]=wasmExports["feupdateenv"];var _fflush_unlocked=Module["_fflush_unlocked"]=wasmExports["fflush_unlocked"];var _ffs=Module["_ffs"]=wasmExports["ffs"];var _ffsl=Module["_ffsl"]=wasmExports["ffsl"];var _ffsll=Module["_ffsll"]=wasmExports["ffsll"];var _emscripten_futex_wake=Module["_emscripten_futex_wake"]=wasmExports["emscripten_futex_wake"];var _fgetln=Module["_fgetln"]=wasmExports["fgetln"];var _getline=Module["_getline"]=wasmExports["getline"];var _fgetpos=Module["_fgetpos"]=wasmExports["fgetpos"];var _fgets_unlocked=Module["_fgets_unlocked"]=wasmExports["fgets_unlocked"];var ___fgetwc_unlocked=Module["___fgetwc_unlocked"]=wasmExports["__fgetwc_unlocked"];var _fwide=Module["_fwide"]=wasmExports["fwide"];var _mbtowc=Module["_mbtowc"]=wasmExports["mbtowc"];var _fgetwc=Module["_fgetwc"]=wasmExports["fgetwc"];var _fgetwc_unlocked=Module["_fgetwc_unlocked"]=wasmExports["fgetwc_unlocked"];var _getwc_unlocked=Module["_getwc_unlocked"]=wasmExports["getwc_unlocked"];var _fgetws=Module["_fgetws"]=wasmExports["fgetws"];var _fgetws_unlocked=Module["_fgetws_unlocked"]=wasmExports["fgetws_unlocked"];var _fileno_unlocked=Module["_fileno_unlocked"]=wasmExports["fileno_unlocked"];var _finite=Module["_finite"]=wasmExports["finite"];var _finitef=Module["_finitef"]=wasmExports["finitef"];var ___floatunsitf=Module["___floatunsitf"]=wasmExports["__floatunsitf"];var _fmodl=Module["_fmodl"]=wasmExports["fmodl"];var _ftrylockfile=Module["_ftrylockfile"]=wasmExports["ftrylockfile"];var _floorf=Module["_floorf"]=wasmExports["floorf"];var _floorl=Module["_floorl"]=wasmExports["floorl"];var _fmaf=Module["_fmaf"]=wasmExports["fmaf"];var _fmal=Module["_fmal"]=wasmExports["fmal"];var _frexpl=Module["_frexpl"]=wasmExports["frexpl"];var _nextafterl=Module["_nextafterl"]=wasmExports["nextafterl"];var _ilogbl=Module["_ilogbl"]=wasmExports["ilogbl"];var _fmax=Module["_fmax"]=wasmExports["fmax"];var _fmaxf=Module["_fmaxf"]=wasmExports["fmaxf"];var _fmaxl=Module["_fmaxl"]=wasmExports["fmaxl"];var _fmemopen=Module["_fmemopen"]=wasmExports["fmemopen"];var _fmin=Module["_fmin"]=wasmExports["fmin"];var _fminf=Module["_fminf"]=wasmExports["fminf"];var _fminl=Module["_fminl"]=wasmExports["fminl"];var _fmodf=Module["_fmodf"]=wasmExports["fmodf"];var _fmtmsg=Module["_fmtmsg"]=wasmExports["fmtmsg"];var _fnmatch=Module["_fnmatch"]=wasmExports["fnmatch"];var _towupper=Module["_towupper"]=wasmExports["towupper"];var _towlower=Module["_towlower"]=wasmExports["towlower"];var _wctype=Module["_wctype"]=wasmExports["wctype"];var _iswctype=Module["_iswctype"]=wasmExports["iswctype"];var _forkpty=Module["_forkpty"]=wasmExports["forkpty"];var _openpty=Module["_openpty"]=wasmExports["openpty"];var _pipe2=Module["_pipe2"]=wasmExports["pipe2"];var _vfiprintf=Module["_vfiprintf"]=wasmExports["vfiprintf"];var ___small_vfprintf=Module["___small_vfprintf"]=wasmExports["__small_vfprintf"];var _fputs_unlocked=Module["_fputs_unlocked"]=wasmExports["fputs_unlocked"];var ___fputwc_unlocked=Module["___fputwc_unlocked"]=wasmExports["__fputwc_unlocked"];var _wctomb=Module["_wctomb"]=wasmExports["wctomb"];var _fputwc=Module["_fputwc"]=wasmExports["fputwc"];var _fputwc_unlocked=Module["_fputwc_unlocked"]=wasmExports["fputwc_unlocked"];var _putwc_unlocked=Module["_putwc_unlocked"]=wasmExports["putwc_unlocked"];var _fputws=Module["_fputws"]=wasmExports["fputws"];var _wcsrtombs=Module["_wcsrtombs"]=wasmExports["wcsrtombs"];var _fputws_unlocked=Module["_fputws_unlocked"]=wasmExports["fputws_unlocked"];var _fread_unlocked=Module["_fread_unlocked"]=wasmExports["fread_unlocked"];var _freelocale=Module["_freelocale"]=wasmExports["freelocale"];var ___freelocale=Module["___freelocale"]=wasmExports["__freelocale"];var _freopen=Module["_freopen"]=wasmExports["freopen"];var _frexpf=Module["_frexpf"]=wasmExports["frexpf"];var _fscanf=Module["_fscanf"]=wasmExports["fscanf"];var _vfscanf=Module["_vfscanf"]=wasmExports["vfscanf"];var ___isoc99_fscanf=Module["___isoc99_fscanf"]=wasmExports["__isoc99_fscanf"];var _fseek=Module["_fseek"]=wasmExports["fseek"];var _fseeko=Module["_fseeko"]=wasmExports["fseeko"];var _fsetpos=Module["_fsetpos"]=wasmExports["fsetpos"];var _ftello=Module["_ftello"]=wasmExports["ftello"];var _ftime=Module["_ftime"]=wasmExports["ftime"];var _utimensat=Module["_utimensat"]=wasmExports["utimensat"];var _fwprintf=Module["_fwprintf"]=wasmExports["fwprintf"];var _vfwprintf=Module["_vfwprintf"]=wasmExports["vfwprintf"];var _fwrite_unlocked=Module["_fwrite_unlocked"]=wasmExports["fwrite_unlocked"];var _fwscanf=Module["_fwscanf"]=wasmExports["fwscanf"];var _vfwscanf=Module["_vfwscanf"]=wasmExports["vfwscanf"];var ___isoc99_fwscanf=Module["___isoc99_fwscanf"]=wasmExports["__isoc99_fwscanf"];var _gcvt=Module["_gcvt"]=wasmExports["gcvt"];var _get_current_dir_name=Module["_get_current_dir_name"]=wasmExports["get_current_dir_name"];var _strdup=Module["_strdup"]=wasmExports["strdup"];var __IO_getc=Module["__IO_getc"]=wasmExports["_IO_getc"];var _fgetc_unlocked=Module["_fgetc_unlocked"]=wasmExports["fgetc_unlocked"];var __IO_getc_unlocked=Module["__IO_getc_unlocked"]=wasmExports["_IO_getc_unlocked"];var _getchar=Module["_getchar"]=wasmExports["getchar"];var _getchar_unlocked=Module["_getchar_unlocked"]=wasmExports["getchar_unlocked"];var _getdelim=Module["_getdelim"]=wasmExports["getdelim"];var ___getdelim=Module["___getdelim"]=wasmExports["__getdelim"];var _getdents=Module["_getdents"]=wasmExports["getdents"];var _getdomainname=Module["_getdomainname"]=wasmExports["getdomainname"];var _getegid=Module["_getegid"]=wasmExports["getegid"];var _geteuid=Module["_geteuid"]=wasmExports["geteuid"];var _getgroups=Module["_getgroups"]=wasmExports["getgroups"];var _gethostid=Module["_gethostid"]=wasmExports["gethostid"];var _freeifaddrs=Module["_freeifaddrs"]=wasmExports["freeifaddrs"];var _getifaddrs=Module["_getifaddrs"]=wasmExports["getifaddrs"];var ___getitimer=Module["___getitimer"]=wasmExports["__getitimer"];var _getlogin_r=Module["_getlogin_r"]=wasmExports["getlogin_r"];var _getopt=Module["_getopt"]=wasmExports["getopt"];var ___posix_getopt=Module["___posix_getopt"]=wasmExports["__posix_getopt"];var _getopt_long=Module["_getopt_long"]=wasmExports["getopt_long"];var _getopt_long_only=Module["_getopt_long_only"]=wasmExports["getopt_long_only"];var _mblen=Module["_mblen"]=wasmExports["mblen"];var _getpagesize=Module["_getpagesize"]=wasmExports["getpagesize"];var _getresgid=Module["_getresgid"]=wasmExports["getresgid"];var _getresuid=Module["_getresuid"]=wasmExports["getresuid"];var _getrusage=Module["_getrusage"]=wasmExports["getrusage"];var _gets=Module["_gets"]=wasmExports["gets"];var _getservbyname_r=Module["_getservbyname_r"]=wasmExports["getservbyname_r"];var _getservbyport_r=Module["_getservbyport_r"]=wasmExports["getservbyport_r"];var _getsubopt=Module["_getsubopt"]=wasmExports["getsubopt"];var _gettid=Module["_gettid"]=wasmExports["gettid"];var _getw=Module["_getw"]=wasmExports["getw"];var _getwc=Module["_getwc"]=wasmExports["getwc"];var _getwchar=Module["_getwchar"]=wasmExports["getwchar"];var _getwchar_unlocked=Module["_getwchar_unlocked"]=wasmExports["getwchar_unlocked"];var _glob=Module["_glob"]=wasmExports["glob"];var _globfree=Module["_globfree"]=wasmExports["globfree"];var _gmtime=Module["_gmtime"]=wasmExports["gmtime"];var _herror=Module["_herror"]=wasmExports["herror"];var _hcreate=Module["_hcreate"]=wasmExports["hcreate"];var _hdestroy=Module["_hdestroy"]=wasmExports["hdestroy"];var _hsearch=Module["_hsearch"]=wasmExports["hsearch"];var _hcreate_r=Module["_hcreate_r"]=wasmExports["hcreate_r"];var _hdestroy_r=Module["_hdestroy_r"]=wasmExports["hdestroy_r"];var _hsearch_r=Module["_hsearch_r"]=wasmExports["hsearch_r"];var _iconv_open=Module["_iconv_open"]=wasmExports["iconv_open"];var _iconv=Module["_iconv"]=wasmExports["iconv"];var _iconv_close=Module["_iconv_close"]=wasmExports["iconv_close"];var _ioctl=Module["_ioctl"]=wasmExports["ioctl"];var _ilogb=Module["_ilogb"]=wasmExports["ilogb"];var _ilogbf=Module["_ilogbf"]=wasmExports["ilogbf"];var _imaxabs=Module["_imaxabs"]=wasmExports["imaxabs"];var _imaxdiv=Module["_imaxdiv"]=wasmExports["imaxdiv"];var _index=Module["_index"]=wasmExports["index"];var _inet_addr=Module["_inet_addr"]=wasmExports["inet_addr"];var _inet_network=Module["_inet_network"]=wasmExports["inet_network"];var _inet_makeaddr=Module["_inet_makeaddr"]=wasmExports["inet_makeaddr"];var _inet_lnaof=Module["_inet_lnaof"]=wasmExports["inet_lnaof"];var _inet_netof=Module["_inet_netof"]=wasmExports["inet_netof"];var _insque=Module["_insque"]=wasmExports["insque"];var _remque=Module["_remque"]=wasmExports["remque"];var ___intscan=Module["___intscan"]=wasmExports["__intscan"];var ___multi3=Module["___multi3"]=wasmExports["__multi3"];var ___isalnum_l=Module["___isalnum_l"]=wasmExports["__isalnum_l"];var _isalnum_l=Module["_isalnum_l"]=wasmExports["isalnum_l"];var _isalpha=Module["_isalpha"]=wasmExports["isalpha"];var ___isalpha_l=Module["___isalpha_l"]=wasmExports["__isalpha_l"];var _isalpha_l=Module["_isalpha_l"]=wasmExports["isalpha_l"];var _isascii=Module["_isascii"]=wasmExports["isascii"];var _isblank=Module["_isblank"]=wasmExports["isblank"];var ___isblank_l=Module["___isblank_l"]=wasmExports["__isblank_l"];var _isblank_l=Module["_isblank_l"]=wasmExports["isblank_l"];var _iscntrl=Module["_iscntrl"]=wasmExports["iscntrl"];var ___iscntrl_l=Module["___iscntrl_l"]=wasmExports["__iscntrl_l"];var _iscntrl_l=Module["_iscntrl_l"]=wasmExports["iscntrl_l"];var _isdigit=Module["_isdigit"]=wasmExports["isdigit"];var ___isdigit_l=Module["___isdigit_l"]=wasmExports["__isdigit_l"];var _isdigit_l=Module["_isdigit_l"]=wasmExports["isdigit_l"];var _isgraph=Module["_isgraph"]=wasmExports["isgraph"];var ___isgraph_l=Module["___isgraph_l"]=wasmExports["__isgraph_l"];var _isgraph_l=Module["_isgraph_l"]=wasmExports["isgraph_l"];var _islower=Module["_islower"]=wasmExports["islower"];var ___islower_l=Module["___islower_l"]=wasmExports["__islower_l"];var _islower_l=Module["_islower_l"]=wasmExports["islower_l"];var _isprint=Module["_isprint"]=wasmExports["isprint"];var ___isprint_l=Module["___isprint_l"]=wasmExports["__isprint_l"];var _isprint_l=Module["_isprint_l"]=wasmExports["isprint_l"];var _ispunct=Module["_ispunct"]=wasmExports["ispunct"];var ___ispunct_l=Module["___ispunct_l"]=wasmExports["__ispunct_l"];var _ispunct_l=Module["_ispunct_l"]=wasmExports["ispunct_l"];var _issetugid=Module["_issetugid"]=wasmExports["issetugid"];var _isspace=Module["_isspace"]=wasmExports["isspace"];var ___isspace_l=Module["___isspace_l"]=wasmExports["__isspace_l"];var _isspace_l=Module["_isspace_l"]=wasmExports["isspace_l"];var _isupper=Module["_isupper"]=wasmExports["isupper"];var ___isupper_l=Module["___isupper_l"]=wasmExports["__isupper_l"];var _isupper_l=Module["_isupper_l"]=wasmExports["isupper_l"];var _iswalnum=Module["_iswalnum"]=wasmExports["iswalnum"];var _iswalpha=Module["_iswalpha"]=wasmExports["iswalpha"];var ___iswalnum_l=Module["___iswalnum_l"]=wasmExports["__iswalnum_l"];var _iswalnum_l=Module["_iswalnum_l"]=wasmExports["iswalnum_l"];var ___iswalpha_l=Module["___iswalpha_l"]=wasmExports["__iswalpha_l"];var _iswalpha_l=Module["_iswalpha_l"]=wasmExports["iswalpha_l"];var _iswblank=Module["_iswblank"]=wasmExports["iswblank"];var ___iswblank_l=Module["___iswblank_l"]=wasmExports["__iswblank_l"];var _iswblank_l=Module["_iswblank_l"]=wasmExports["iswblank_l"];var _iswcntrl=Module["_iswcntrl"]=wasmExports["iswcntrl"];var ___iswcntrl_l=Module["___iswcntrl_l"]=wasmExports["__iswcntrl_l"];var _iswcntrl_l=Module["_iswcntrl_l"]=wasmExports["iswcntrl_l"];var _iswgraph=Module["_iswgraph"]=wasmExports["iswgraph"];var _iswlower=Module["_iswlower"]=wasmExports["iswlower"];var _iswprint=Module["_iswprint"]=wasmExports["iswprint"];var _iswpunct=Module["_iswpunct"]=wasmExports["iswpunct"];var _iswspace=Module["_iswspace"]=wasmExports["iswspace"];var _iswupper=Module["_iswupper"]=wasmExports["iswupper"];var _iswxdigit=Module["_iswxdigit"]=wasmExports["iswxdigit"];var ___iswctype_l=Module["___iswctype_l"]=wasmExports["__iswctype_l"];var ___wctype_l=Module["___wctype_l"]=wasmExports["__wctype_l"];var _iswctype_l=Module["_iswctype_l"]=wasmExports["iswctype_l"];var _wctype_l=Module["_wctype_l"]=wasmExports["wctype_l"];var _iswdigit=Module["_iswdigit"]=wasmExports["iswdigit"];var ___iswdigit_l=Module["___iswdigit_l"]=wasmExports["__iswdigit_l"];var _iswdigit_l=Module["_iswdigit_l"]=wasmExports["iswdigit_l"];var ___iswgraph_l=Module["___iswgraph_l"]=wasmExports["__iswgraph_l"];var _iswgraph_l=Module["_iswgraph_l"]=wasmExports["iswgraph_l"];var ___iswlower_l=Module["___iswlower_l"]=wasmExports["__iswlower_l"];var _iswlower_l=Module["_iswlower_l"]=wasmExports["iswlower_l"];var ___iswprint_l=Module["___iswprint_l"]=wasmExports["__iswprint_l"];var _iswprint_l=Module["_iswprint_l"]=wasmExports["iswprint_l"];var ___iswpunct_l=Module["___iswpunct_l"]=wasmExports["__iswpunct_l"];var _iswpunct_l=Module["_iswpunct_l"]=wasmExports["iswpunct_l"];var ___iswspace_l=Module["___iswspace_l"]=wasmExports["__iswspace_l"];var _iswspace_l=Module["_iswspace_l"]=wasmExports["iswspace_l"];var ___iswupper_l=Module["___iswupper_l"]=wasmExports["__iswupper_l"];var _iswupper_l=Module["_iswupper_l"]=wasmExports["iswupper_l"];var ___iswxdigit_l=Module["___iswxdigit_l"]=wasmExports["__iswxdigit_l"];var _iswxdigit_l=Module["_iswxdigit_l"]=wasmExports["iswxdigit_l"];var _isxdigit=Module["_isxdigit"]=wasmExports["isxdigit"];var ___isxdigit_l=Module["___isxdigit_l"]=wasmExports["__isxdigit_l"];var _isxdigit_l=Module["_isxdigit_l"]=wasmExports["isxdigit_l"];var _j0=Module["_j0"]=wasmExports["j0"];var _y0=Module["_y0"]=wasmExports["y0"];var _j0f=Module["_j0f"]=wasmExports["j0f"];var _y0f=Module["_y0f"]=wasmExports["y0f"];var _j1=Module["_j1"]=wasmExports["j1"];var _y1=Module["_y1"]=wasmExports["y1"];var _j1f=Module["_j1f"]=wasmExports["j1f"];var _y1f=Module["_y1f"]=wasmExports["y1f"];var _jn=Module["_jn"]=wasmExports["jn"];var _yn=Module["_yn"]=wasmExports["yn"];var _jnf=Module["_jnf"]=wasmExports["jnf"];var _ynf=Module["_ynf"]=wasmExports["ynf"];var _labs=Module["_labs"]=wasmExports["labs"];var ___nl_langinfo=Module["___nl_langinfo"]=wasmExports["__nl_langinfo"];var _nl_langinfo_l=Module["_nl_langinfo_l"]=wasmExports["nl_langinfo_l"];var _lchmod=Module["_lchmod"]=wasmExports["lchmod"];var _lchown=Module["_lchown"]=wasmExports["lchown"];var _lcong48=Module["_lcong48"]=wasmExports["lcong48"];var _ldexpf=Module["_ldexpf"]=wasmExports["ldexpf"];var _scalbnf=Module["_scalbnf"]=wasmExports["scalbnf"];var _ldexpl=Module["_ldexpl"]=wasmExports["ldexpl"];var _ldiv=Module["_ldiv"]=wasmExports["ldiv"];var _get_nprocs_conf=Module["_get_nprocs_conf"]=wasmExports["get_nprocs_conf"];var _get_nprocs=Module["_get_nprocs"]=wasmExports["get_nprocs"];var _get_phys_pages=Module["_get_phys_pages"]=wasmExports["get_phys_pages"];var _get_avphys_pages=Module["_get_avphys_pages"]=wasmExports["get_avphys_pages"];var _lgamma=Module["_lgamma"]=wasmExports["lgamma"];var _lgamma_r=Module["_lgamma_r"]=wasmExports["lgamma_r"];var _lgammaf=Module["_lgammaf"]=wasmExports["lgammaf"];var _lgammaf_r=Module["_lgammaf_r"]=wasmExports["lgammaf_r"];var ___lgammal_r=Module["___lgammal_r"]=wasmExports["__lgammal_r"];var _lgammal=Module["_lgammal"]=wasmExports["lgammal"];var _lgammal_r=Module["_lgammal_r"]=wasmExports["lgammal_r"];var _emscripten_has_threading_support=Module["_emscripten_has_threading_support"]=wasmExports["emscripten_has_threading_support"];var _emscripten_num_logical_cores=Module["_emscripten_num_logical_cores"]=wasmExports["emscripten_num_logical_cores"];var _emscripten_futex_wait=Module["_emscripten_futex_wait"]=wasmExports["emscripten_futex_wait"];var _emscripten_main_thread_process_queued_calls=Module["_emscripten_main_thread_process_queued_calls"]=wasmExports["emscripten_main_thread_process_queued_calls"];var _emscripten_current_thread_process_queued_calls=Module["_emscripten_current_thread_process_queued_calls"]=wasmExports["emscripten_current_thread_process_queued_calls"];var __emscripten_yield=Module["__emscripten_yield"]=wasmExports["_emscripten_yield"];var __emscripten_check_timers=Module["__emscripten_check_timers"]=wasmExports["_emscripten_check_timers"];var _pthread_mutex_consistent=Module["_pthread_mutex_consistent"]=wasmExports["pthread_mutex_consistent"];var _pthread_barrier_init=Module["_pthread_barrier_init"]=wasmExports["pthread_barrier_init"];var _pthread_barrier_destroy=Module["_pthread_barrier_destroy"]=wasmExports["pthread_barrier_destroy"];var _pthread_barrier_wait=Module["_pthread_barrier_wait"]=wasmExports["pthread_barrier_wait"];var _pthread_cond_broadcast=Module["_pthread_cond_broadcast"]=wasmExports["pthread_cond_broadcast"];var _pthread_atfork=Module["_pthread_atfork"]=wasmExports["pthread_atfork"];var _pthread_cancel=Module["_pthread_cancel"]=wasmExports["pthread_cancel"];var _pthread_testcancel=Module["_pthread_testcancel"]=wasmExports["pthread_testcancel"];var ___pthread_detach=Module["___pthread_detach"]=wasmExports["__pthread_detach"];var _pthread_equal=Module["_pthread_equal"]=wasmExports["pthread_equal"];var _pthread_mutexattr_init=Module["_pthread_mutexattr_init"]=wasmExports["pthread_mutexattr_init"];var _pthread_mutexattr_setprotocol=Module["_pthread_mutexattr_setprotocol"]=wasmExports["pthread_mutexattr_setprotocol"];var _pthread_mutexattr_settype=Module["_pthread_mutexattr_settype"]=wasmExports["pthread_mutexattr_settype"];var _pthread_mutexattr_destroy=Module["_pthread_mutexattr_destroy"]=wasmExports["pthread_mutexattr_destroy"];var _pthread_mutexattr_setpshared=Module["_pthread_mutexattr_setpshared"]=wasmExports["pthread_mutexattr_setpshared"];var _pthread_condattr_destroy=Module["_pthread_condattr_destroy"]=wasmExports["pthread_condattr_destroy"];var _pthread_condattr_setpshared=Module["_pthread_condattr_setpshared"]=wasmExports["pthread_condattr_setpshared"];var _pthread_setcanceltype=Module["_pthread_setcanceltype"]=wasmExports["pthread_setcanceltype"];var _pthread_rwlock_init=Module["_pthread_rwlock_init"]=wasmExports["pthread_rwlock_init"];var _pthread_rwlock_destroy=Module["_pthread_rwlock_destroy"]=wasmExports["pthread_rwlock_destroy"];var _pthread_rwlock_rdlock=Module["_pthread_rwlock_rdlock"]=wasmExports["pthread_rwlock_rdlock"];var _pthread_rwlock_tryrdlock=Module["_pthread_rwlock_tryrdlock"]=wasmExports["pthread_rwlock_tryrdlock"];var _pthread_rwlock_timedrdlock=Module["_pthread_rwlock_timedrdlock"]=wasmExports["pthread_rwlock_timedrdlock"];var _pthread_rwlock_wrlock=Module["_pthread_rwlock_wrlock"]=wasmExports["pthread_rwlock_wrlock"];var _pthread_rwlock_trywrlock=Module["_pthread_rwlock_trywrlock"]=wasmExports["pthread_rwlock_trywrlock"];var _pthread_rwlock_timedwrlock=Module["_pthread_rwlock_timedwrlock"]=wasmExports["pthread_rwlock_timedwrlock"];var _pthread_rwlock_unlock=Module["_pthread_rwlock_unlock"]=wasmExports["pthread_rwlock_unlock"];var _pthread_rwlockattr_init=Module["_pthread_rwlockattr_init"]=wasmExports["pthread_rwlockattr_init"];var _pthread_rwlockattr_destroy=Module["_pthread_rwlockattr_destroy"]=wasmExports["pthread_rwlockattr_destroy"];var _pthread_rwlockattr_setpshared=Module["_pthread_rwlockattr_setpshared"]=wasmExports["pthread_rwlockattr_setpshared"];var _pthread_spin_init=Module["_pthread_spin_init"]=wasmExports["pthread_spin_init"];var _pthread_spin_destroy=Module["_pthread_spin_destroy"]=wasmExports["pthread_spin_destroy"];var _pthread_spin_lock=Module["_pthread_spin_lock"]=wasmExports["pthread_spin_lock"];var _pthread_spin_trylock=Module["_pthread_spin_trylock"]=wasmExports["pthread_spin_trylock"];var _pthread_spin_unlock=Module["_pthread_spin_unlock"]=wasmExports["pthread_spin_unlock"];var _sem_init=Module["_sem_init"]=wasmExports["sem_init"];var _sem_post=Module["_sem_post"]=wasmExports["sem_post"];var _sem_wait=Module["_sem_wait"]=wasmExports["sem_wait"];var _sem_trywait=Module["_sem_trywait"]=wasmExports["sem_trywait"];var _sem_destroy=Module["_sem_destroy"]=wasmExports["sem_destroy"];var _pthread_mutex_timedlock=Module["_pthread_mutex_timedlock"]=wasmExports["pthread_mutex_timedlock"];var _emscripten_builtin_pthread_create=Module["_emscripten_builtin_pthread_create"]=wasmExports["emscripten_builtin_pthread_create"];var _emscripten_builtin_pthread_join=Module["_emscripten_builtin_pthread_join"]=wasmExports["emscripten_builtin_pthread_join"];var _pthread_once=Module["_pthread_once"]=wasmExports["pthread_once"];var _emscripten_builtin_pthread_exit=Module["_emscripten_builtin_pthread_exit"]=wasmExports["emscripten_builtin_pthread_exit"];var _pthread_exit=Module["_pthread_exit"]=wasmExports["pthread_exit"];var _emscripten_builtin_pthread_detach=Module["_emscripten_builtin_pthread_detach"]=wasmExports["emscripten_builtin_pthread_detach"];var _thrd_detach=Module["_thrd_detach"]=wasmExports["thrd_detach"];var _link=Module["_link"]=wasmExports["link"];var _linkat=Module["_linkat"]=wasmExports["linkat"];var _llabs=Module["_llabs"]=wasmExports["llabs"];var _lldiv=Module["_lldiv"]=wasmExports["lldiv"];var _llrint=Module["_llrint"]=wasmExports["llrint"];var _rint=Module["_rint"]=wasmExports["rint"];var _llrintf=Module["_llrintf"]=wasmExports["llrintf"];var _rintf=Module["_rintf"]=wasmExports["rintf"];var _llrintl=Module["_llrintl"]=wasmExports["llrintl"];var _rintl=Module["_rintl"]=wasmExports["rintl"];var _llround=Module["_llround"]=wasmExports["llround"];var _llroundf=Module["_llroundf"]=wasmExports["llroundf"];var _roundf=Module["_roundf"]=wasmExports["roundf"];var _llroundl=Module["_llroundl"]=wasmExports["llroundl"];var _roundl=Module["_roundl"]=wasmExports["roundl"];var _log10f=Module["_log10f"]=wasmExports["log10f"];var _log10l=Module["_log10l"]=wasmExports["log10l"];var _log2f=Module["_log2f"]=wasmExports["log2f"];var _log2l=Module["_log2l"]=wasmExports["log2l"];var _logb=Module["_logb"]=wasmExports["logb"];var _logbf=Module["_logbf"]=wasmExports["logbf"];var _logbl=Module["_logbl"]=wasmExports["logbl"];var _strtoull=Module["_strtoull"]=wasmExports["strtoull"];var _nrand48=Module["_nrand48"]=wasmExports["nrand48"];var _lrand48=Module["_lrand48"]=wasmExports["lrand48"];var _lrint=Module["_lrint"]=wasmExports["lrint"];var _lrintf=Module["_lrintf"]=wasmExports["lrintf"];var _lrintl=Module["_lrintl"]=wasmExports["lrintl"];var _lround=Module["_lround"]=wasmExports["lround"];var _lroundf=Module["_lroundf"]=wasmExports["lroundf"];var _lroundl=Module["_lroundl"]=wasmExports["lroundl"];var _lsearch=Module["_lsearch"]=wasmExports["lsearch"];var _lfind=Module["_lfind"]=wasmExports["lfind"];var _mbrlen=Module["_mbrlen"]=wasmExports["mbrlen"];var _mbrtoc16=Module["_mbrtoc16"]=wasmExports["mbrtoc16"];var _mbrtoc32=Module["_mbrtoc32"]=wasmExports["mbrtoc32"];var _mbsinit=Module["_mbsinit"]=wasmExports["mbsinit"];var _mbsnrtowcs=Module["_mbsnrtowcs"]=wasmExports["mbsnrtowcs"];var _mbsrtowcs=Module["_mbsrtowcs"]=wasmExports["mbsrtowcs"];var _memccpy=Module["_memccpy"]=wasmExports["memccpy"];var _memmem=Module["_memmem"]=wasmExports["memmem"];var _mempcpy=Module["_mempcpy"]=wasmExports["mempcpy"];var _mincore=Module["_mincore"]=wasmExports["mincore"];var _mkdtemp=Module["_mkdtemp"]=wasmExports["mkdtemp"];var _mkfifo=Module["_mkfifo"]=wasmExports["mkfifo"];var _mkfifoat=Module["_mkfifoat"]=wasmExports["mkfifoat"];var _mkostemp=Module["_mkostemp"]=wasmExports["mkostemp"];var _mkostemps=Module["_mkostemps"]=wasmExports["mkostemps"];var _mkstemp=Module["_mkstemp"]=wasmExports["mkstemp"];var _mkstemps=Module["_mkstemps"]=wasmExports["mkstemps"];var _mktemp=Module["_mktemp"]=wasmExports["mktemp"];var _timegm=Module["_timegm"]=wasmExports["timegm"];var _mlock=Module["_mlock"]=wasmExports["mlock"];var _mlockall=Module["_mlockall"]=wasmExports["mlockall"];var _emscripten_builtin_mmap=Module["_emscripten_builtin_mmap"]=wasmExports["emscripten_builtin_mmap"];var _setmntent=Module["_setmntent"]=wasmExports["setmntent"];var _endmntent=Module["_endmntent"]=wasmExports["endmntent"];var _getmntent_r=Module["_getmntent_r"]=wasmExports["getmntent_r"];var _sscanf=Module["_sscanf"]=wasmExports["sscanf"];var _getmntent=Module["_getmntent"]=wasmExports["getmntent"];var _addmntent=Module["_addmntent"]=wasmExports["addmntent"];var _hasmntopt=Module["_hasmntopt"]=wasmExports["hasmntopt"];var _mprotect=Module["_mprotect"]=wasmExports["mprotect"];var _jrand48=Module["_jrand48"]=wasmExports["jrand48"];var _mrand48=Module["_mrand48"]=wasmExports["mrand48"];var _mtx_destroy=Module["_mtx_destroy"]=wasmExports["mtx_destroy"];var _mtx_init=Module["_mtx_init"]=wasmExports["mtx_init"];var _mtx_lock=Module["_mtx_lock"]=wasmExports["mtx_lock"];var _mtx_timedlock=Module["_mtx_timedlock"]=wasmExports["mtx_timedlock"];var _mtx_trylock=Module["_mtx_trylock"]=wasmExports["mtx_trylock"];var _mtx_unlock=Module["_mtx_unlock"]=wasmExports["mtx_unlock"];var _munlock=Module["_munlock"]=wasmExports["munlock"];var _munlockall=Module["_munlockall"]=wasmExports["munlockall"];var _emscripten_builtin_munmap=Module["_emscripten_builtin_munmap"]=wasmExports["emscripten_builtin_munmap"];var _nan=Module["_nan"]=wasmExports["nan"];var _nanf=Module["_nanf"]=wasmExports["nanf"];var _nanl=Module["_nanl"]=wasmExports["nanl"];var _nanosleep=Module["_nanosleep"]=wasmExports["nanosleep"];var _nearbyint=Module["_nearbyint"]=wasmExports["nearbyint"];var _nearbyintf=Module["_nearbyintf"]=wasmExports["nearbyintf"];var _nearbyintl=Module["_nearbyintl"]=wasmExports["nearbyintl"];var _getnetbyaddr=Module["_getnetbyaddr"]=wasmExports["getnetbyaddr"];var _getnetbyname=Module["_getnetbyname"]=wasmExports["getnetbyname"];var ___newlocale=Module["___newlocale"]=wasmExports["__newlocale"];var _newlocale=Module["_newlocale"]=wasmExports["newlocale"];var _nextafterf=Module["_nextafterf"]=wasmExports["nextafterf"];var _nexttoward=Module["_nexttoward"]=wasmExports["nexttoward"];var _nexttowardf=Module["_nexttowardf"]=wasmExports["nexttowardf"];var _nexttowardl=Module["_nexttowardl"]=wasmExports["nexttowardl"];var _nftw=Module["_nftw"]=wasmExports["nftw"];var _nice=Module["_nice"]=wasmExports["nice"];var _setpriority=Module["_setpriority"]=wasmExports["setpriority"];var _ns_get16=Module["_ns_get16"]=wasmExports["ns_get16"];var _ns_get32=Module["_ns_get32"]=wasmExports["ns_get32"];var _ns_put16=Module["_ns_put16"]=wasmExports["ns_put16"];var _ns_put32=Module["_ns_put32"]=wasmExports["ns_put32"];var _ns_skiprr=Module["_ns_skiprr"]=wasmExports["ns_skiprr"];var _ns_initparse=Module["_ns_initparse"]=wasmExports["ns_initparse"];var _ns_name_uncompress=Module["_ns_name_uncompress"]=wasmExports["ns_name_uncompress"];var _ns_parserr=Module["_ns_parserr"]=wasmExports["ns_parserr"];var _open_memstream=Module["_open_memstream"]=wasmExports["open_memstream"];var _open_wmemstream=Module["_open_wmemstream"]=wasmExports["open_wmemstream"];var _tcsetattr=Module["_tcsetattr"]=wasmExports["tcsetattr"];var _posix_close=Module["_posix_close"]=wasmExports["posix_close"];var _posix_fallocate=Module["_posix_fallocate"]=wasmExports["posix_fallocate"];var _posix_madvise=Module["_posix_madvise"]=wasmExports["posix_madvise"];var _posix_spawn_file_actions_addchdir_np=Module["_posix_spawn_file_actions_addchdir_np"]=wasmExports["posix_spawn_file_actions_addchdir_np"];var _posix_spawn_file_actions_addclose=Module["_posix_spawn_file_actions_addclose"]=wasmExports["posix_spawn_file_actions_addclose"];var _posix_spawn_file_actions_adddup2=Module["_posix_spawn_file_actions_adddup2"]=wasmExports["posix_spawn_file_actions_adddup2"];var _posix_spawn_file_actions_addfchdir_np=Module["_posix_spawn_file_actions_addfchdir_np"]=wasmExports["posix_spawn_file_actions_addfchdir_np"];var _posix_spawn_file_actions_addopen=Module["_posix_spawn_file_actions_addopen"]=wasmExports["posix_spawn_file_actions_addopen"];var _posix_spawn_file_actions_destroy=Module["_posix_spawn_file_actions_destroy"]=wasmExports["posix_spawn_file_actions_destroy"];var _posix_spawn_file_actions_init=Module["_posix_spawn_file_actions_init"]=wasmExports["posix_spawn_file_actions_init"];var _posix_spawnattr_destroy=Module["_posix_spawnattr_destroy"]=wasmExports["posix_spawnattr_destroy"];var _posix_spawnattr_getflags=Module["_posix_spawnattr_getflags"]=wasmExports["posix_spawnattr_getflags"];var _posix_spawnattr_getpgroup=Module["_posix_spawnattr_getpgroup"]=wasmExports["posix_spawnattr_getpgroup"];var _posix_spawnattr_getsigdefault=Module["_posix_spawnattr_getsigdefault"]=wasmExports["posix_spawnattr_getsigdefault"];var _posix_spawnattr_getsigmask=Module["_posix_spawnattr_getsigmask"]=wasmExports["posix_spawnattr_getsigmask"];var _posix_spawnattr_init=Module["_posix_spawnattr_init"]=wasmExports["posix_spawnattr_init"];var _posix_spawnattr_getschedparam=Module["_posix_spawnattr_getschedparam"]=wasmExports["posix_spawnattr_getschedparam"];var _posix_spawnattr_setschedparam=Module["_posix_spawnattr_setschedparam"]=wasmExports["posix_spawnattr_setschedparam"];var _posix_spawnattr_getschedpolicy=Module["_posix_spawnattr_getschedpolicy"]=wasmExports["posix_spawnattr_getschedpolicy"];var _posix_spawnattr_setschedpolicy=Module["_posix_spawnattr_setschedpolicy"]=wasmExports["posix_spawnattr_setschedpolicy"];var _posix_spawnattr_setflags=Module["_posix_spawnattr_setflags"]=wasmExports["posix_spawnattr_setflags"];var _posix_spawnattr_setpgroup=Module["_posix_spawnattr_setpgroup"]=wasmExports["posix_spawnattr_setpgroup"];var _posix_spawnattr_setsigdefault=Module["_posix_spawnattr_setsigdefault"]=wasmExports["posix_spawnattr_setsigdefault"];var _posix_spawnattr_setsigmask=Module["_posix_spawnattr_setsigmask"]=wasmExports["posix_spawnattr_setsigmask"];var _powf=Module["_powf"]=wasmExports["powf"];var _preadv=Module["_preadv"]=wasmExports["preadv"];var _printf=Module["_printf"]=wasmExports["printf"];var ___small_printf=Module["___small_printf"]=wasmExports["__small_printf"];var _em_proxying_queue_create=Module["_em_proxying_queue_create"]=wasmExports["em_proxying_queue_create"];var _em_proxying_queue_destroy=Module["_em_proxying_queue_destroy"]=wasmExports["em_proxying_queue_destroy"];var _emscripten_proxy_get_system_queue=Module["_emscripten_proxy_get_system_queue"]=wasmExports["emscripten_proxy_get_system_queue"];var _emscripten_proxy_execute_queue=Module["_emscripten_proxy_execute_queue"]=wasmExports["emscripten_proxy_execute_queue"];var _emscripten_proxy_finish=Module["_emscripten_proxy_finish"]=wasmExports["emscripten_proxy_finish"];var _emscripten_proxy_async=Module["_emscripten_proxy_async"]=wasmExports["emscripten_proxy_async"];var _emscripten_proxy_sync=Module["_emscripten_proxy_sync"]=wasmExports["emscripten_proxy_sync"];var _emscripten_proxy_sync_with_ctx=Module["_emscripten_proxy_sync_with_ctx"]=wasmExports["emscripten_proxy_sync_with_ctx"];var _pselect=Module["_pselect"]=wasmExports["pselect"];var _pthread_attr_getdetachstate=Module["_pthread_attr_getdetachstate"]=wasmExports["pthread_attr_getdetachstate"];var _pthread_attr_getguardsize=Module["_pthread_attr_getguardsize"]=wasmExports["pthread_attr_getguardsize"];var _pthread_attr_getinheritsched=Module["_pthread_attr_getinheritsched"]=wasmExports["pthread_attr_getinheritsched"];var _pthread_attr_getschedparam=Module["_pthread_attr_getschedparam"]=wasmExports["pthread_attr_getschedparam"];var _pthread_attr_getschedpolicy=Module["_pthread_attr_getschedpolicy"]=wasmExports["pthread_attr_getschedpolicy"];var _pthread_attr_getscope=Module["_pthread_attr_getscope"]=wasmExports["pthread_attr_getscope"];var _pthread_attr_getstack=Module["_pthread_attr_getstack"]=wasmExports["pthread_attr_getstack"];var _pthread_attr_getstacksize=Module["_pthread_attr_getstacksize"]=wasmExports["pthread_attr_getstacksize"];var _pthread_barrierattr_getpshared=Module["_pthread_barrierattr_getpshared"]=wasmExports["pthread_barrierattr_getpshared"];var _pthread_condattr_getclock=Module["_pthread_condattr_getclock"]=wasmExports["pthread_condattr_getclock"];var _pthread_condattr_getpshared=Module["_pthread_condattr_getpshared"]=wasmExports["pthread_condattr_getpshared"];var _pthread_mutexattr_getprotocol=Module["_pthread_mutexattr_getprotocol"]=wasmExports["pthread_mutexattr_getprotocol"];var _pthread_mutexattr_getpshared=Module["_pthread_mutexattr_getpshared"]=wasmExports["pthread_mutexattr_getpshared"];var _pthread_mutexattr_getrobust=Module["_pthread_mutexattr_getrobust"]=wasmExports["pthread_mutexattr_getrobust"];var _pthread_mutexattr_gettype=Module["_pthread_mutexattr_gettype"]=wasmExports["pthread_mutexattr_gettype"];var _pthread_rwlockattr_getpshared=Module["_pthread_rwlockattr_getpshared"]=wasmExports["pthread_rwlockattr_getpshared"];var _pthread_attr_setdetachstate=Module["_pthread_attr_setdetachstate"]=wasmExports["pthread_attr_setdetachstate"];var _pthread_attr_setguardsize=Module["_pthread_attr_setguardsize"]=wasmExports["pthread_attr_setguardsize"];var _pthread_attr_setinheritsched=Module["_pthread_attr_setinheritsched"]=wasmExports["pthread_attr_setinheritsched"];var _pthread_attr_setschedparam=Module["_pthread_attr_setschedparam"]=wasmExports["pthread_attr_setschedparam"];var _pthread_attr_setschedpolicy=Module["_pthread_attr_setschedpolicy"]=wasmExports["pthread_attr_setschedpolicy"];var _pthread_attr_setscope=Module["_pthread_attr_setscope"]=wasmExports["pthread_attr_setscope"];var _pthread_attr_setstack=Module["_pthread_attr_setstack"]=wasmExports["pthread_attr_setstack"];var __pthread_cleanup_push=Module["__pthread_cleanup_push"]=wasmExports["_pthread_cleanup_push"];var __pthread_cleanup_pop=Module["__pthread_cleanup_pop"]=wasmExports["_pthread_cleanup_pop"];var _pthread_getattr_np=Module["_pthread_getattr_np"]=wasmExports["pthread_getattr_np"];var _pthread_getconcurrency=Module["_pthread_getconcurrency"]=wasmExports["pthread_getconcurrency"];var _pthread_getschedparam=Module["_pthread_getschedparam"]=wasmExports["pthread_getschedparam"];var _thrd_current=Module["_thrd_current"]=wasmExports["thrd_current"];var _emscripten_main_runtime_thread_id=Module["_emscripten_main_runtime_thread_id"]=wasmExports["emscripten_main_runtime_thread_id"];var _pthread_setconcurrency=Module["_pthread_setconcurrency"]=wasmExports["pthread_setconcurrency"];var _pthread_setschedprio=Module["_pthread_setschedprio"]=wasmExports["pthread_setschedprio"];var ___sig_is_blocked=Module["___sig_is_blocked"]=wasmExports["__sig_is_blocked"];var _sigorset=Module["_sigorset"]=wasmExports["sigorset"];var _sigandset=Module["_sigandset"]=wasmExports["sigandset"];var _sigdelset=Module["_sigdelset"]=wasmExports["sigdelset"];var _ptsname=Module["_ptsname"]=wasmExports["ptsname"];var __IO_putc=Module["__IO_putc"]=wasmExports["_IO_putc"];var _putc_unlocked=Module["_putc_unlocked"]=wasmExports["putc_unlocked"];var _fputc_unlocked=Module["_fputc_unlocked"]=wasmExports["fputc_unlocked"];var __IO_putc_unlocked=Module["__IO_putc_unlocked"]=wasmExports["_IO_putc_unlocked"];var _putchar_unlocked=Module["_putchar_unlocked"]=wasmExports["putchar_unlocked"];var _putenv=Module["_putenv"]=wasmExports["putenv"];var _putw=Module["_putw"]=wasmExports["putw"];var _putwc=Module["_putwc"]=wasmExports["putwc"];var _putwchar=Module["_putwchar"]=wasmExports["putwchar"];var _putwchar_unlocked=Module["_putwchar_unlocked"]=wasmExports["putwchar_unlocked"];var _pwritev=Module["_pwritev"]=wasmExports["pwritev"];var _qsort_r=Module["_qsort_r"]=wasmExports["qsort_r"];var _quick_exit=Module["_quick_exit"]=wasmExports["quick_exit"];var _action_abort=Module["_action_abort"]=wasmExports["action_abort"];var _action_terminate=Module["_action_terminate"]=wasmExports["action_terminate"];var _srand=Module["_srand"]=wasmExports["srand"];var _rand=Module["_rand"]=wasmExports["rand"];var _rand_r=Module["_rand_r"]=wasmExports["rand_r"];var _srandom=Module["_srandom"]=wasmExports["srandom"];var _initstate=Module["_initstate"]=wasmExports["initstate"];var _setstate=Module["_setstate"]=wasmExports["setstate"];var _random=Module["_random"]=wasmExports["random"];var _readdir_r=Module["_readdir_r"]=wasmExports["readdir_r"];var _recvmmsg=Module["_recvmmsg"]=wasmExports["recvmmsg"];var _regcomp=Module["_regcomp"]=wasmExports["regcomp"];var _regfree=Module["_regfree"]=wasmExports["regfree"];var _regerror=Module["_regerror"]=wasmExports["regerror"];var _regexec=Module["_regexec"]=wasmExports["regexec"];var _remainder=Module["_remainder"]=wasmExports["remainder"];var _remquo=Module["_remquo"]=wasmExports["remquo"];var _drem=Module["_drem"]=wasmExports["drem"];var _remainderf=Module["_remainderf"]=wasmExports["remainderf"];var _remquof=Module["_remquof"]=wasmExports["remquof"];var _dremf=Module["_dremf"]=wasmExports["dremf"];var _remainderl=Module["_remainderl"]=wasmExports["remainderl"];var _remquol=Module["_remquol"]=wasmExports["remquol"];var _remove=Module["_remove"]=wasmExports["remove"];var _res_init=Module["_res_init"]=wasmExports["res_init"];var _res_mkquery=Module["_res_mkquery"]=wasmExports["res_mkquery"];var ___res_msend=Module["___res_msend"]=wasmExports["__res_msend"];var _res_send=Module["_res_send"]=wasmExports["res_send"];var ___res_state=Module["___res_state"]=wasmExports["__res_state"];var _rindex=Module["_rindex"]=wasmExports["rindex"];var _scalb=Module["_scalb"]=wasmExports["scalb"];var _scalbf=Module["_scalbf"]=wasmExports["scalbf"];var _scalbln=Module["_scalbln"]=wasmExports["scalbln"];var _scalblnf=Module["_scalblnf"]=wasmExports["scalblnf"];var _scalblnl=Module["_scalblnl"]=wasmExports["scalblnl"];var _scandir=Module["_scandir"]=wasmExports["scandir"];var _scanf=Module["_scanf"]=wasmExports["scanf"];var _vscanf=Module["_vscanf"]=wasmExports["vscanf"];var ___isoc99_scanf=Module["___isoc99_scanf"]=wasmExports["__isoc99_scanf"];var _secure_getenv=Module["_secure_getenv"]=wasmExports["secure_getenv"];var _seed48=Module["_seed48"]=wasmExports["seed48"];var _seekdir=Module["_seekdir"]=wasmExports["seekdir"];var _sendmmsg=Module["_sendmmsg"]=wasmExports["sendmmsg"];var _endservent=Module["_endservent"]=wasmExports["endservent"];var _setservent=Module["_setservent"]=wasmExports["setservent"];var _getservent=Module["_getservent"]=wasmExports["getservent"];var _setbuf=Module["_setbuf"]=wasmExports["setbuf"];var _setbuffer=Module["_setbuffer"]=wasmExports["setbuffer"];var _setdomainname=Module["_setdomainname"]=wasmExports["setdomainname"];var _setegid=Module["_setegid"]=wasmExports["setegid"];var _seteuid=Module["_seteuid"]=wasmExports["seteuid"];var __emscripten_timeout=wasmExports["_emscripten_timeout"];var _setlinebuf=Module["_setlinebuf"]=wasmExports["setlinebuf"];var _setresgid=Module["_setresgid"]=wasmExports["setresgid"];var _setresuid=Module["_setresuid"]=wasmExports["setresuid"];var _shm_open=Module["_shm_open"]=wasmExports["shm_open"];var _shm_unlink=Module["_shm_unlink"]=wasmExports["shm_unlink"];var _sigaction=Module["_sigaction"]=wasmExports["sigaction"];var _sigisemptyset=Module["_sigisemptyset"]=wasmExports["sigisemptyset"];var _bsd_signal=Module["_bsd_signal"]=wasmExports["bsd_signal"];var ___sysv_signal=Module["___sysv_signal"]=wasmExports["__sysv_signal"];var _significand=Module["_significand"]=wasmExports["significand"];var _significandf=Module["_significandf"]=wasmExports["significandf"];var _sigprocmask=Module["_sigprocmask"]=wasmExports["sigprocmask"];var _sincos=Module["_sincos"]=wasmExports["sincos"];var _sincosf=Module["_sincosf"]=wasmExports["sincosf"];var _sincosl=Module["_sincosl"]=wasmExports["sincosl"];var _sinhl=Module["_sinhl"]=wasmExports["sinhl"];var _sinl=Module["_sinl"]=wasmExports["sinl"];var _sockatmark=Module["_sockatmark"]=wasmExports["sockatmark"];var _vsprintf=Module["_vsprintf"]=wasmExports["vsprintf"];var _vsiprintf=Module["_vsiprintf"]=wasmExports["vsiprintf"];var ___small_sprintf=Module["___small_sprintf"]=wasmExports["__small_sprintf"];var ___small_vsprintf=Module["___small_vsprintf"]=wasmExports["__small_vsprintf"];var _srand48=Module["_srand48"]=wasmExports["srand48"];var _vsscanf=Module["_vsscanf"]=wasmExports["vsscanf"];var ___isoc99_sscanf=Module["___isoc99_sscanf"]=wasmExports["__isoc99_sscanf"];var _statfs=Module["_statfs"]=wasmExports["statfs"];var _fstatfs=Module["_fstatfs"]=wasmExports["fstatfs"];var _statx=Module["_statx"]=wasmExports["statx"];var _stpcpy=Module["_stpcpy"]=wasmExports["stpcpy"];var _stpncpy=Module["_stpncpy"]=wasmExports["stpncpy"];var ___strcasecmp_l=Module["___strcasecmp_l"]=wasmExports["__strcasecmp_l"];var _strcasecmp_l=Module["_strcasecmp_l"]=wasmExports["strcasecmp_l"];var _strcasestr=Module["_strcasestr"]=wasmExports["strcasestr"];var _strncasecmp=Module["_strncasecmp"]=wasmExports["strncasecmp"];var _strchrnul=Module["_strchrnul"]=wasmExports["strchrnul"];var ___strcoll_l=Module["___strcoll_l"]=wasmExports["__strcoll_l"];var _strcoll_l=Module["_strcoll_l"]=wasmExports["strcoll_l"];var ___strerror_l=Module["___strerror_l"]=wasmExports["__strerror_l"];var _strerror_l=Module["_strerror_l"]=wasmExports["strerror_l"];var _strerror_r=Module["_strerror_r"]=wasmExports["strerror_r"];var ___xpg_strerror_r=Module["___xpg_strerror_r"]=wasmExports["__xpg_strerror_r"];var _strfmon_l=Module["_strfmon_l"]=wasmExports["strfmon_l"];var _strfmon=Module["_strfmon"]=wasmExports["strfmon"];var _strftime=Module["_strftime"]=wasmExports["strftime"];var _strftime_l=Module["_strftime_l"]=wasmExports["strftime_l"];var _strlcat=Module["_strlcat"]=wasmExports["strlcat"];var _strlcpy=Module["_strlcpy"]=wasmExports["strlcpy"];var _strlwr=Module["_strlwr"]=wasmExports["strlwr"];var ___strncasecmp_l=Module["___strncasecmp_l"]=wasmExports["__strncasecmp_l"];var _strncasecmp_l=Module["_strncasecmp_l"]=wasmExports["strncasecmp_l"];var _strndup=Module["_strndup"]=wasmExports["strndup"];var _strsep=Module["_strsep"]=wasmExports["strsep"];var _strtof=Module["_strtof"]=wasmExports["strtof"];var _strtold=Module["_strtold"]=wasmExports["strtold"];var _strtof_l=Module["_strtof_l"]=wasmExports["strtof_l"];var _strtod_l=Module["_strtod_l"]=wasmExports["strtod_l"];var _strtold_l=Module["_strtold_l"]=wasmExports["strtold_l"];var ___strtof_l=Module["___strtof_l"]=wasmExports["__strtof_l"];var ___strtod_l=Module["___strtod_l"]=wasmExports["__strtod_l"];var ___strtold_l=Module["___strtold_l"]=wasmExports["__strtold_l"];var _strtok=Module["_strtok"]=wasmExports["strtok"];var _strtok_r=Module["_strtok_r"]=wasmExports["strtok_r"];var _strtoll=Module["_strtoll"]=wasmExports["strtoll"];var _strtoimax=Module["_strtoimax"]=wasmExports["strtoimax"];var _strtoumax=Module["_strtoumax"]=wasmExports["strtoumax"];var ___strtol_internal=Module["___strtol_internal"]=wasmExports["__strtol_internal"];var ___strtoul_internal=Module["___strtoul_internal"]=wasmExports["__strtoul_internal"];var ___strtoll_internal=Module["___strtoll_internal"]=wasmExports["__strtoll_internal"];var ___strtoull_internal=Module["___strtoull_internal"]=wasmExports["__strtoull_internal"];var ___strtoimax_internal=Module["___strtoimax_internal"]=wasmExports["__strtoimax_internal"];var ___strtoumax_internal=Module["___strtoumax_internal"]=wasmExports["__strtoumax_internal"];var _strtoull_l=Module["_strtoull_l"]=wasmExports["strtoull_l"];var _strtoll_l=Module["_strtoll_l"]=wasmExports["strtoll_l"];var _strtoul_l=Module["_strtoul_l"]=wasmExports["strtoul_l"];var _strtol_l=Module["_strtol_l"]=wasmExports["strtol_l"];var _strupr=Module["_strupr"]=wasmExports["strupr"];var _strverscmp=Module["_strverscmp"]=wasmExports["strverscmp"];var ___strxfrm_l=Module["___strxfrm_l"]=wasmExports["__strxfrm_l"];var _strxfrm=Module["_strxfrm"]=wasmExports["strxfrm"];var _strxfrm_l=Module["_strxfrm_l"]=wasmExports["strxfrm_l"];var _swab=Module["_swab"]=wasmExports["swab"];var _swprintf=Module["_swprintf"]=wasmExports["swprintf"];var _vswprintf=Module["_vswprintf"]=wasmExports["vswprintf"];var _swscanf=Module["_swscanf"]=wasmExports["swscanf"];var _vswscanf=Module["_vswscanf"]=wasmExports["vswscanf"];var ___isoc99_swscanf=Module["___isoc99_swscanf"]=wasmExports["__isoc99_swscanf"];var _symlinkat=Module["_symlinkat"]=wasmExports["symlinkat"];var _setlogmask=Module["_setlogmask"]=wasmExports["setlogmask"];var _closelog=Module["_closelog"]=wasmExports["closelog"];var _openlog=Module["_openlog"]=wasmExports["openlog"];var _syslog=Module["_syslog"]=wasmExports["syslog"];var _vsyslog=Module["_vsyslog"]=wasmExports["vsyslog"];var _tanhf=Module["_tanhf"]=wasmExports["tanhf"];var _tanhl=Module["_tanhl"]=wasmExports["tanhl"];var _tanl=Module["_tanl"]=wasmExports["tanl"];var _tcdrain=Module["_tcdrain"]=wasmExports["tcdrain"];var _tcflow=Module["_tcflow"]=wasmExports["tcflow"];var _tcflush=Module["_tcflush"]=wasmExports["tcflush"];var _tcgetattr=Module["_tcgetattr"]=wasmExports["tcgetattr"];var _tcgetsid=Module["_tcgetsid"]=wasmExports["tcgetsid"];var _tcgetwinsize=Module["_tcgetwinsize"]=wasmExports["tcgetwinsize"];var _tcsendbreak=Module["_tcsendbreak"]=wasmExports["tcsendbreak"];var _tcsetwinsize=Module["_tcsetwinsize"]=wasmExports["tcsetwinsize"];var _tdelete=Module["_tdelete"]=wasmExports["tdelete"];var _tdestroy=Module["_tdestroy"]=wasmExports["tdestroy"];var _telldir=Module["_telldir"]=wasmExports["telldir"];var _tempnam=Module["_tempnam"]=wasmExports["tempnam"];var _ngettext=Module["_ngettext"]=wasmExports["ngettext"];var _tfind=Module["_tfind"]=wasmExports["tfind"];var _tgamma=Module["_tgamma"]=wasmExports["tgamma"];var _tgammaf=Module["_tgammaf"]=wasmExports["tgammaf"];var _tgammal=Module["_tgammal"]=wasmExports["tgammal"];var _thrd_create=Module["_thrd_create"]=wasmExports["thrd_create"];var _thrd_exit=Module["_thrd_exit"]=wasmExports["thrd_exit"];var _thrd_join=Module["_thrd_join"]=wasmExports["thrd_join"];var _thrd_sleep=Module["_thrd_sleep"]=wasmExports["thrd_sleep"];var _thrd_yield=Module["_thrd_yield"]=wasmExports["thrd_yield"];var _emscripten_set_thread_name=Module["_emscripten_set_thread_name"]=wasmExports["emscripten_set_thread_name"];var _timespec_get=Module["_timespec_get"]=wasmExports["timespec_get"];var _tmpfile=Module["_tmpfile"]=wasmExports["tmpfile"];var _tmpnam=Module["_tmpnam"]=wasmExports["tmpnam"];var _toascii=Module["_toascii"]=wasmExports["toascii"];var ___tolower_l=Module["___tolower_l"]=wasmExports["__tolower_l"];var _tolower_l=Module["_tolower_l"]=wasmExports["tolower_l"];var ___toupper_l=Module["___toupper_l"]=wasmExports["__toupper_l"];var _toupper_l=Module["_toupper_l"]=wasmExports["toupper_l"];var ___towupper_l=Module["___towupper_l"]=wasmExports["__towupper_l"];var ___towlower_l=Module["___towlower_l"]=wasmExports["__towlower_l"];var _towupper_l=Module["_towupper_l"]=wasmExports["towupper_l"];var _towlower_l=Module["_towlower_l"]=wasmExports["towlower_l"];var _trunc=Module["_trunc"]=wasmExports["trunc"];var _truncf=Module["_truncf"]=wasmExports["truncf"];var _truncl=Module["_truncl"]=wasmExports["truncl"];var _tsearch=Module["_tsearch"]=wasmExports["tsearch"];var _tss_create=Module["_tss_create"]=wasmExports["tss_create"];var _tss_delete=Module["_tss_delete"]=wasmExports["tss_delete"];var _tss_set=Module["_tss_set"]=wasmExports["tss_set"];var _ttyname=Module["_ttyname"]=wasmExports["ttyname"];var _twalk=Module["_twalk"]=wasmExports["twalk"];var _ualarm=Module["_ualarm"]=wasmExports["ualarm"];var _ungetwc=Module["_ungetwc"]=wasmExports["ungetwc"];var ___uselocale=Module["___uselocale"]=wasmExports["__uselocale"];var _uselocale=Module["_uselocale"]=wasmExports["uselocale"];var _usleep=Module["_usleep"]=wasmExports["usleep"];var _utime=Module["_utime"]=wasmExports["utime"];var _versionsort=Module["_versionsort"]=wasmExports["versionsort"];var ___vfprintf_internal=Module["___vfprintf_internal"]=wasmExports["__vfprintf_internal"];var ___isoc99_vfscanf=Module["___isoc99_vfscanf"]=wasmExports["__isoc99_vfscanf"];var _wcsnlen=Module["_wcsnlen"]=wasmExports["wcsnlen"];var ___isoc99_vfwscanf=Module["___isoc99_vfwscanf"]=wasmExports["__isoc99_vfwscanf"];var _vprintf=Module["_vprintf"]=wasmExports["vprintf"];var ___isoc99_vscanf=Module["___isoc99_vscanf"]=wasmExports["__isoc99_vscanf"];var _vsniprintf=Module["_vsniprintf"]=wasmExports["vsniprintf"];var ___small_vsnprintf=Module["___small_vsnprintf"]=wasmExports["__small_vsnprintf"];var ___isoc99_vsscanf=Module["___isoc99_vsscanf"]=wasmExports["__isoc99_vsscanf"];var ___isoc99_vswscanf=Module["___isoc99_vswscanf"]=wasmExports["__isoc99_vswscanf"];var _vwprintf=Module["_vwprintf"]=wasmExports["vwprintf"];var _vwscanf=Module["_vwscanf"]=wasmExports["vwscanf"];var ___isoc99_vwscanf=Module["___isoc99_vwscanf"]=wasmExports["__isoc99_vwscanf"];var _wcpcpy=Module["_wcpcpy"]=wasmExports["wcpcpy"];var _wcpncpy=Module["_wcpncpy"]=wasmExports["wcpncpy"];var _wcscasecmp=Module["_wcscasecmp"]=wasmExports["wcscasecmp"];var _wcsncasecmp=Module["_wcsncasecmp"]=wasmExports["wcsncasecmp"];var _wcscasecmp_l=Module["_wcscasecmp_l"]=wasmExports["wcscasecmp_l"];var _wcscat=Module["_wcscat"]=wasmExports["wcscat"];var ___wcscoll_l=Module["___wcscoll_l"]=wasmExports["__wcscoll_l"];var _wcscoll_l=Module["_wcscoll_l"]=wasmExports["wcscoll_l"];var _wcscspn=Module["_wcscspn"]=wasmExports["wcscspn"];var _wcsdup=Module["_wcsdup"]=wasmExports["wcsdup"];var _wmemcpy=Module["_wmemcpy"]=wasmExports["wmemcpy"];var ___wcsftime_l=Module["___wcsftime_l"]=wasmExports["__wcsftime_l"];var _wcstoul=Module["_wcstoul"]=wasmExports["wcstoul"];var _wcsftime_l=Module["_wcsftime_l"]=wasmExports["wcsftime_l"];var _wcsncasecmp_l=Module["_wcsncasecmp_l"]=wasmExports["wcsncasecmp_l"];var _wcsncat=Module["_wcsncat"]=wasmExports["wcsncat"];var _wmemset=Module["_wmemset"]=wasmExports["wmemset"];var _wcsnrtombs=Module["_wcsnrtombs"]=wasmExports["wcsnrtombs"];var _wcspbrk=Module["_wcspbrk"]=wasmExports["wcspbrk"];var _wcsspn=Module["_wcsspn"]=wasmExports["wcsspn"];var _wcsstr=Module["_wcsstr"]=wasmExports["wcsstr"];var _wcstof=Module["_wcstof"]=wasmExports["wcstof"];var _wcstod=Module["_wcstod"]=wasmExports["wcstod"];var _wcstold=Module["_wcstold"]=wasmExports["wcstold"];var _wcstoull=Module["_wcstoull"]=wasmExports["wcstoull"];var _wcstoll=Module["_wcstoll"]=wasmExports["wcstoll"];var _wcstoimax=Module["_wcstoimax"]=wasmExports["wcstoimax"];var _wcstoumax=Module["_wcstoumax"]=wasmExports["wcstoumax"];var _wcswcs=Module["_wcswcs"]=wasmExports["wcswcs"];var _wcswidth=Module["_wcswidth"]=wasmExports["wcswidth"];var _wcwidth=Module["_wcwidth"]=wasmExports["wcwidth"];var ___wcsxfrm_l=Module["___wcsxfrm_l"]=wasmExports["__wcsxfrm_l"];var _wcsxfrm_l=Module["_wcsxfrm_l"]=wasmExports["wcsxfrm_l"];var _wctob=Module["_wctob"]=wasmExports["wctob"];var _wctrans=Module["_wctrans"]=wasmExports["wctrans"];var _towctrans=Module["_towctrans"]=wasmExports["towctrans"];var ___wctrans_l=Module["___wctrans_l"]=wasmExports["__wctrans_l"];var ___towctrans_l=Module["___towctrans_l"]=wasmExports["__towctrans_l"];var _wctrans_l=Module["_wctrans_l"]=wasmExports["wctrans_l"];var _towctrans_l=Module["_towctrans_l"]=wasmExports["towctrans_l"];var _wmemmove=Module["_wmemmove"]=wasmExports["wmemmove"];var _wprintf=Module["_wprintf"]=wasmExports["wprintf"];var _wscanf=Module["_wscanf"]=wasmExports["wscanf"];var ___isoc99_wscanf=Module["___isoc99_wscanf"]=wasmExports["__isoc99_wscanf"];var ___libc_realloc=Module["___libc_realloc"]=wasmExports["__libc_realloc"];var _realloc_in_place=Module["_realloc_in_place"]=wasmExports["realloc_in_place"];var _memalign=Module["_memalign"]=wasmExports["memalign"];var _valloc=Module["_valloc"]=wasmExports["valloc"];var _pvalloc=Module["_pvalloc"]=wasmExports["pvalloc"];var _mallinfo=Module["_mallinfo"]=wasmExports["mallinfo"];var _mallopt=Module["_mallopt"]=wasmExports["mallopt"];var _malloc_trim=Module["_malloc_trim"]=wasmExports["malloc_trim"];var _malloc_usable_size=Module["_malloc_usable_size"]=wasmExports["malloc_usable_size"];var _malloc_footprint=Module["_malloc_footprint"]=wasmExports["malloc_footprint"];var _malloc_max_footprint=Module["_malloc_max_footprint"]=wasmExports["malloc_max_footprint"];var _malloc_footprint_limit=Module["_malloc_footprint_limit"]=wasmExports["malloc_footprint_limit"];var _malloc_set_footprint_limit=Module["_malloc_set_footprint_limit"]=wasmExports["malloc_set_footprint_limit"];var _independent_calloc=Module["_independent_calloc"]=wasmExports["independent_calloc"];var _independent_comalloc=Module["_independent_comalloc"]=wasmExports["independent_comalloc"];var _bulk_free=Module["_bulk_free"]=wasmExports["bulk_free"];var _emscripten_builtin_realloc=Module["_emscripten_builtin_realloc"]=wasmExports["emscripten_builtin_realloc"];var _emscripten_builtin_calloc=Module["_emscripten_builtin_calloc"]=wasmExports["emscripten_builtin_calloc"];var _emscripten_get_sbrk_ptr=Module["_emscripten_get_sbrk_ptr"]=wasmExports["emscripten_get_sbrk_ptr"];var _brk=Module["_brk"]=wasmExports["brk"];var ___trap=wasmExports["__trap"];var ___absvdi2=Module["___absvdi2"]=wasmExports["__absvdi2"];var ___absvsi2=Module["___absvsi2"]=wasmExports["__absvsi2"];var ___absvti2=Module["___absvti2"]=wasmExports["__absvti2"];var ___adddf3=Module["___adddf3"]=wasmExports["__adddf3"];var ___fe_getround=Module["___fe_getround"]=wasmExports["__fe_getround"];var ___fe_raise_inexact=Module["___fe_raise_inexact"]=wasmExports["__fe_raise_inexact"];var ___addsf3=Module["___addsf3"]=wasmExports["__addsf3"];var ___ashlti3=Module["___ashlti3"]=wasmExports["__ashlti3"];var ___lshrti3=Module["___lshrti3"]=wasmExports["__lshrti3"];var ___addvdi3=Module["___addvdi3"]=wasmExports["__addvdi3"];var ___addvsi3=Module["___addvsi3"]=wasmExports["__addvsi3"];var ___addvti3=Module["___addvti3"]=wasmExports["__addvti3"];var ___ashldi3=Module["___ashldi3"]=wasmExports["__ashldi3"];var ___ashrdi3=Module["___ashrdi3"]=wasmExports["__ashrdi3"];var ___ashrti3=Module["___ashrti3"]=wasmExports["__ashrti3"];var ___atomic_is_lock_free=Module["___atomic_is_lock_free"]=wasmExports["__atomic_is_lock_free"];var ___atomic_load=Module["___atomic_load"]=wasmExports["__atomic_load"];var ___atomic_store=Module["___atomic_store"]=wasmExports["__atomic_store"];var ___atomic_compare_exchange=Module["___atomic_compare_exchange"]=wasmExports["__atomic_compare_exchange"];var ___atomic_exchange=Module["___atomic_exchange"]=wasmExports["__atomic_exchange"];var ___atomic_load_1=Module["___atomic_load_1"]=wasmExports["__atomic_load_1"];var ___atomic_load_2=Module["___atomic_load_2"]=wasmExports["__atomic_load_2"];var ___atomic_load_4=Module["___atomic_load_4"]=wasmExports["__atomic_load_4"];var ___atomic_load_8=Module["___atomic_load_8"]=wasmExports["__atomic_load_8"];var ___atomic_load_16=Module["___atomic_load_16"]=wasmExports["__atomic_load_16"];var ___atomic_store_1=Module["___atomic_store_1"]=wasmExports["__atomic_store_1"];var ___atomic_store_2=Module["___atomic_store_2"]=wasmExports["__atomic_store_2"];var ___atomic_store_4=Module["___atomic_store_4"]=wasmExports["__atomic_store_4"];var ___atomic_store_8=Module["___atomic_store_8"]=wasmExports["__atomic_store_8"];var ___atomic_store_16=Module["___atomic_store_16"]=wasmExports["__atomic_store_16"];var ___atomic_exchange_1=Module["___atomic_exchange_1"]=wasmExports["__atomic_exchange_1"];var ___atomic_exchange_2=Module["___atomic_exchange_2"]=wasmExports["__atomic_exchange_2"];var ___atomic_exchange_4=Module["___atomic_exchange_4"]=wasmExports["__atomic_exchange_4"];var ___atomic_exchange_8=Module["___atomic_exchange_8"]=wasmExports["__atomic_exchange_8"];var ___atomic_exchange_16=Module["___atomic_exchange_16"]=wasmExports["__atomic_exchange_16"];var ___atomic_compare_exchange_1=Module["___atomic_compare_exchange_1"]=wasmExports["__atomic_compare_exchange_1"];var ___atomic_compare_exchange_2=Module["___atomic_compare_exchange_2"]=wasmExports["__atomic_compare_exchange_2"];var ___atomic_compare_exchange_4=Module["___atomic_compare_exchange_4"]=wasmExports["__atomic_compare_exchange_4"];var ___atomic_compare_exchange_8=Module["___atomic_compare_exchange_8"]=wasmExports["__atomic_compare_exchange_8"];var ___atomic_compare_exchange_16=Module["___atomic_compare_exchange_16"]=wasmExports["__atomic_compare_exchange_16"];var ___atomic_fetch_add_1=Module["___atomic_fetch_add_1"]=wasmExports["__atomic_fetch_add_1"];var ___atomic_fetch_add_2=Module["___atomic_fetch_add_2"]=wasmExports["__atomic_fetch_add_2"];var ___atomic_fetch_add_4=Module["___atomic_fetch_add_4"]=wasmExports["__atomic_fetch_add_4"];var ___atomic_fetch_add_8=Module["___atomic_fetch_add_8"]=wasmExports["__atomic_fetch_add_8"];var ___atomic_fetch_add_16=Module["___atomic_fetch_add_16"]=wasmExports["__atomic_fetch_add_16"];var ___atomic_fetch_sub_1=Module["___atomic_fetch_sub_1"]=wasmExports["__atomic_fetch_sub_1"];var ___atomic_fetch_sub_2=Module["___atomic_fetch_sub_2"]=wasmExports["__atomic_fetch_sub_2"];var ___atomic_fetch_sub_4=Module["___atomic_fetch_sub_4"]=wasmExports["__atomic_fetch_sub_4"];var ___atomic_fetch_sub_8=Module["___atomic_fetch_sub_8"]=wasmExports["__atomic_fetch_sub_8"];var ___atomic_fetch_sub_16=Module["___atomic_fetch_sub_16"]=wasmExports["__atomic_fetch_sub_16"];var ___atomic_fetch_and_1=Module["___atomic_fetch_and_1"]=wasmExports["__atomic_fetch_and_1"];var ___atomic_fetch_and_2=Module["___atomic_fetch_and_2"]=wasmExports["__atomic_fetch_and_2"];var ___atomic_fetch_and_4=Module["___atomic_fetch_and_4"]=wasmExports["__atomic_fetch_and_4"];var ___atomic_fetch_and_8=Module["___atomic_fetch_and_8"]=wasmExports["__atomic_fetch_and_8"];var ___atomic_fetch_and_16=Module["___atomic_fetch_and_16"]=wasmExports["__atomic_fetch_and_16"];var ___atomic_fetch_or_1=Module["___atomic_fetch_or_1"]=wasmExports["__atomic_fetch_or_1"];var ___atomic_fetch_or_2=Module["___atomic_fetch_or_2"]=wasmExports["__atomic_fetch_or_2"];var ___atomic_fetch_or_4=Module["___atomic_fetch_or_4"]=wasmExports["__atomic_fetch_or_4"];var ___atomic_fetch_or_8=Module["___atomic_fetch_or_8"]=wasmExports["__atomic_fetch_or_8"];var ___atomic_fetch_or_16=Module["___atomic_fetch_or_16"]=wasmExports["__atomic_fetch_or_16"];var ___atomic_fetch_xor_1=Module["___atomic_fetch_xor_1"]=wasmExports["__atomic_fetch_xor_1"];var ___atomic_fetch_xor_2=Module["___atomic_fetch_xor_2"]=wasmExports["__atomic_fetch_xor_2"];var ___atomic_fetch_xor_4=Module["___atomic_fetch_xor_4"]=wasmExports["__atomic_fetch_xor_4"];var ___atomic_fetch_xor_8=Module["___atomic_fetch_xor_8"]=wasmExports["__atomic_fetch_xor_8"];var ___atomic_fetch_xor_16=Module["___atomic_fetch_xor_16"]=wasmExports["__atomic_fetch_xor_16"];var ___atomic_fetch_nand_1=Module["___atomic_fetch_nand_1"]=wasmExports["__atomic_fetch_nand_1"];var ___atomic_fetch_nand_2=Module["___atomic_fetch_nand_2"]=wasmExports["__atomic_fetch_nand_2"];var ___atomic_fetch_nand_4=Module["___atomic_fetch_nand_4"]=wasmExports["__atomic_fetch_nand_4"];var ___atomic_fetch_nand_8=Module["___atomic_fetch_nand_8"]=wasmExports["__atomic_fetch_nand_8"];var ___atomic_fetch_nand_16=Module["___atomic_fetch_nand_16"]=wasmExports["__atomic_fetch_nand_16"];var _atomic_flag_clear=Module["_atomic_flag_clear"]=wasmExports["atomic_flag_clear"];var _atomic_flag_clear_explicit=Module["_atomic_flag_clear_explicit"]=wasmExports["atomic_flag_clear_explicit"];var _atomic_flag_test_and_set=Module["_atomic_flag_test_and_set"]=wasmExports["atomic_flag_test_and_set"];var _atomic_flag_test_and_set_explicit=Module["_atomic_flag_test_and_set_explicit"]=wasmExports["atomic_flag_test_and_set_explicit"];var _atomic_signal_fence=Module["_atomic_signal_fence"]=wasmExports["atomic_signal_fence"];var _atomic_thread_fence=Module["_atomic_thread_fence"]=wasmExports["atomic_thread_fence"];var ___bswapdi2=Module["___bswapdi2"]=wasmExports["__bswapdi2"];var ___bswapsi2=Module["___bswapsi2"]=wasmExports["__bswapsi2"];var ___clear_cache=Module["___clear_cache"]=wasmExports["__clear_cache"];var ___clzdi2=Module["___clzdi2"]=wasmExports["__clzdi2"];var ___clzsi2=Module["___clzsi2"]=wasmExports["__clzsi2"];var ___clzti2=Module["___clzti2"]=wasmExports["__clzti2"];var ___cmpdi2=Module["___cmpdi2"]=wasmExports["__cmpdi2"];var ___cmpti2=Module["___cmpti2"]=wasmExports["__cmpti2"];var ___ledf2=Module["___ledf2"]=wasmExports["__ledf2"];var ___gedf2=Module["___gedf2"]=wasmExports["__gedf2"];var ___unorddf2=Module["___unorddf2"]=wasmExports["__unorddf2"];var ___eqdf2=Module["___eqdf2"]=wasmExports["__eqdf2"];var ___ltdf2=Module["___ltdf2"]=wasmExports["__ltdf2"];var ___nedf2=Module["___nedf2"]=wasmExports["__nedf2"];var ___gtdf2=Module["___gtdf2"]=wasmExports["__gtdf2"];var ___lesf2=Module["___lesf2"]=wasmExports["__lesf2"];var ___gesf2=Module["___gesf2"]=wasmExports["__gesf2"];var ___unordsf2=Module["___unordsf2"]=wasmExports["__unordsf2"];var ___eqsf2=Module["___eqsf2"]=wasmExports["__eqsf2"];var ___ltsf2=Module["___ltsf2"]=wasmExports["__ltsf2"];var ___nesf2=Module["___nesf2"]=wasmExports["__nesf2"];var ___gtsf2=Module["___gtsf2"]=wasmExports["__gtsf2"];var ___ctzdi2=Module["___ctzdi2"]=wasmExports["__ctzdi2"];var ___ctzsi2=Module["___ctzsi2"]=wasmExports["__ctzsi2"];var ___ctzti2=Module["___ctzti2"]=wasmExports["__ctzti2"];var ___divdc3=Module["___divdc3"]=wasmExports["__divdc3"];var ___divdf3=Module["___divdf3"]=wasmExports["__divdf3"];var ___divdi3=Module["___divdi3"]=wasmExports["__divdi3"];var ___udivmoddi4=Module["___udivmoddi4"]=wasmExports["__udivmoddi4"];var ___divmoddi4=Module["___divmoddi4"]=wasmExports["__divmoddi4"];var ___divmodsi4=Module["___divmodsi4"]=wasmExports["__divmodsi4"];var ___udivmodsi4=Module["___udivmodsi4"]=wasmExports["__udivmodsi4"];var ___divmodti4=Module["___divmodti4"]=wasmExports["__divmodti4"];var ___udivmodti4=Module["___udivmodti4"]=wasmExports["__udivmodti4"];var ___divsc3=Module["___divsc3"]=wasmExports["__divsc3"];var ___divsf3=Module["___divsf3"]=wasmExports["__divsf3"];var ___divsi3=Module["___divsi3"]=wasmExports["__divsi3"];var ___divtc3=Module["___divtc3"]=wasmExports["__divtc3"];var ___divti3=Module["___divti3"]=wasmExports["__divti3"];var _setThrew=Module["_setThrew"]=wasmExports["setThrew"];var ___wasm_setjmp=Module["___wasm_setjmp"]=wasmExports["__wasm_setjmp"];var ___wasm_setjmp_test=Module["___wasm_setjmp_test"]=wasmExports["__wasm_setjmp_test"];var ___wasm_longjmp=Module["___wasm_longjmp"]=wasmExports["__wasm_longjmp"];var __emscripten_tempret_set=wasmExports["_emscripten_tempret_set"];var __emscripten_tempret_get=wasmExports["_emscripten_tempret_get"];var ___get_temp_ret=Module["___get_temp_ret"]=wasmExports["__get_temp_ret"];var ___set_temp_ret=Module["___set_temp_ret"]=wasmExports["__set_temp_ret"];var _getTempRet0=Module["_getTempRet0"]=wasmExports["getTempRet0"];var _setTempRet0=Module["_setTempRet0"]=wasmExports["setTempRet0"];var ___emutls_get_address=Module["___emutls_get_address"]=wasmExports["__emutls_get_address"];var ___enable_execute_stack=Module["___enable_execute_stack"]=wasmExports["__enable_execute_stack"];var ___extendhfsf2=Module["___extendhfsf2"]=wasmExports["__extendhfsf2"];var ___gnu_h2f_ieee=Module["___gnu_h2f_ieee"]=wasmExports["__gnu_h2f_ieee"];var ___extendsfdf2=Module["___extendsfdf2"]=wasmExports["__extendsfdf2"];var ___ffsdi2=Module["___ffsdi2"]=wasmExports["__ffsdi2"];var ___ffssi2=Module["___ffssi2"]=wasmExports["__ffssi2"];var ___ffsti2=Module["___ffsti2"]=wasmExports["__ffsti2"];var ___fixdfdi=Module["___fixdfdi"]=wasmExports["__fixdfdi"];var ___fixunsdfdi=Module["___fixunsdfdi"]=wasmExports["__fixunsdfdi"];var ___fixdfsi=Module["___fixdfsi"]=wasmExports["__fixdfsi"];var ___fixdfti=Module["___fixdfti"]=wasmExports["__fixdfti"];var ___fixsfdi=Module["___fixsfdi"]=wasmExports["__fixsfdi"];var ___fixunssfdi=Module["___fixunssfdi"]=wasmExports["__fixunssfdi"];var ___fixsfsi=Module["___fixsfsi"]=wasmExports["__fixsfsi"];var ___fixsfti=Module["___fixsfti"]=wasmExports["__fixsfti"];var ___fixtfti=Module["___fixtfti"]=wasmExports["__fixtfti"];var ___fixunsdfsi=Module["___fixunsdfsi"]=wasmExports["__fixunsdfsi"];var ___fixunsdfti=Module["___fixunsdfti"]=wasmExports["__fixunsdfti"];var ___fixunssfsi=Module["___fixunssfsi"]=wasmExports["__fixunssfsi"];var ___fixunssfti=Module["___fixunssfti"]=wasmExports["__fixunssfti"];var ___fixunstfdi=Module["___fixunstfdi"]=wasmExports["__fixunstfdi"];var ___fixunstfsi=Module["___fixunstfsi"]=wasmExports["__fixunstfsi"];var ___fixunstfti=Module["___fixunstfti"]=wasmExports["__fixunstfti"];var ___floatdidf=Module["___floatdidf"]=wasmExports["__floatdidf"];var ___floatdisf=Module["___floatdisf"]=wasmExports["__floatdisf"];var ___floatditf=Module["___floatditf"]=wasmExports["__floatditf"];var ___floatsidf=Module["___floatsidf"]=wasmExports["__floatsidf"];var ___floatsisf=Module["___floatsisf"]=wasmExports["__floatsisf"];var ___floattidf=Module["___floattidf"]=wasmExports["__floattidf"];var ___floattisf=Module["___floattisf"]=wasmExports["__floattisf"];var ___floattitf=Module["___floattitf"]=wasmExports["__floattitf"];var ___floatundidf=Module["___floatundidf"]=wasmExports["__floatundidf"];var ___floatundisf=Module["___floatundisf"]=wasmExports["__floatundisf"];var ___floatunditf=Module["___floatunditf"]=wasmExports["__floatunditf"];var ___floatunsidf=Module["___floatunsidf"]=wasmExports["__floatunsidf"];var ___floatunsisf=Module["___floatunsisf"]=wasmExports["__floatunsisf"];var ___floatuntidf=Module["___floatuntidf"]=wasmExports["__floatuntidf"];var ___floatuntisf=Module["___floatuntisf"]=wasmExports["__floatuntisf"];var ___floatuntitf=Module["___floatuntitf"]=wasmExports["__floatuntitf"];var ___lshrdi3=Module["___lshrdi3"]=wasmExports["__lshrdi3"];var ___moddi3=Module["___moddi3"]=wasmExports["__moddi3"];var ___modsi3=Module["___modsi3"]=wasmExports["__modsi3"];var ___modti3=Module["___modti3"]=wasmExports["__modti3"];var ___muldf3=Module["___muldf3"]=wasmExports["__muldf3"];var ___muldi3=Module["___muldi3"]=wasmExports["__muldi3"];var ___mulodi4=Module["___mulodi4"]=wasmExports["__mulodi4"];var ___mulosi4=Module["___mulosi4"]=wasmExports["__mulosi4"];var ___muloti4=Module["___muloti4"]=wasmExports["__muloti4"];var ___udivti3=Module["___udivti3"]=wasmExports["__udivti3"];var ___mulsf3=Module["___mulsf3"]=wasmExports["__mulsf3"];var ___mulvdi3=Module["___mulvdi3"]=wasmExports["__mulvdi3"];var ___mulvsi3=Module["___mulvsi3"]=wasmExports["__mulvsi3"];var ___mulvti3=Module["___mulvti3"]=wasmExports["__mulvti3"];var ___negdf2=Module["___negdf2"]=wasmExports["__negdf2"];var ___negdi2=Module["___negdi2"]=wasmExports["__negdi2"];var ___negsf2=Module["___negsf2"]=wasmExports["__negsf2"];var ___negti2=Module["___negti2"]=wasmExports["__negti2"];var ___negvdi2=Module["___negvdi2"]=wasmExports["__negvdi2"];var ___negvsi2=Module["___negvsi2"]=wasmExports["__negvsi2"];var ___negvti2=Module["___negvti2"]=wasmExports["__negvti2"];var ___paritydi2=Module["___paritydi2"]=wasmExports["__paritydi2"];var ___paritysi2=Module["___paritysi2"]=wasmExports["__paritysi2"];var ___parityti2=Module["___parityti2"]=wasmExports["__parityti2"];var ___popcountdi2=Module["___popcountdi2"]=wasmExports["__popcountdi2"];var ___popcountsi2=Module["___popcountsi2"]=wasmExports["__popcountsi2"];var ___popcountti2=Module["___popcountti2"]=wasmExports["__popcountti2"];var ___powidf2=Module["___powidf2"]=wasmExports["__powidf2"];var ___powisf2=Module["___powisf2"]=wasmExports["__powisf2"];var ___powitf2=Module["___powitf2"]=wasmExports["__powitf2"];var _emscripten_stack_init=Module["_emscripten_stack_init"]=wasmExports["emscripten_stack_init"];var _emscripten_stack_set_limits=Module["_emscripten_stack_set_limits"]=wasmExports["emscripten_stack_set_limits"];var _emscripten_stack_get_free=Module["_emscripten_stack_get_free"]=wasmExports["emscripten_stack_get_free"];var __emscripten_stack_restore=wasmExports["_emscripten_stack_restore"];var __emscripten_stack_alloc=wasmExports["_emscripten_stack_alloc"];var ___subdf3=Module["___subdf3"]=wasmExports["__subdf3"];var ___subsf3=Module["___subsf3"]=wasmExports["__subsf3"];var ___subvdi3=Module["___subvdi3"]=wasmExports["__subvdi3"];var ___subvsi3=Module["___subvsi3"]=wasmExports["__subvsi3"];var ___subvti3=Module["___subvti3"]=wasmExports["__subvti3"];var ___truncdfhf2=Module["___truncdfhf2"]=wasmExports["__truncdfhf2"];var ___truncdfsf2=Module["___truncdfsf2"]=wasmExports["__truncdfsf2"];var ___truncsfhf2=Module["___truncsfhf2"]=wasmExports["__truncsfhf2"];var ___gnu_f2h_ieee=Module["___gnu_f2h_ieee"]=wasmExports["__gnu_f2h_ieee"];var ___ucmpdi2=Module["___ucmpdi2"]=wasmExports["__ucmpdi2"];var ___ucmpti2=Module["___ucmpti2"]=wasmExports["__ucmpti2"];var ___udivdi3=Module["___udivdi3"]=wasmExports["__udivdi3"];var ___udivsi3=Module["___udivsi3"]=wasmExports["__udivsi3"];var ___umoddi3=Module["___umoddi3"]=wasmExports["__umoddi3"];var ___umodsi3=Module["___umodsi3"]=wasmExports["__umodsi3"];var ___umodti3=Module["___umodti3"]=wasmExports["__umodti3"];var ___cxa_begin_catch=Module["___cxa_begin_catch"]=wasmExports["__cxa_begin_catch"];var ___cxa_rethrow=Module["___cxa_rethrow"]=wasmExports["__cxa_rethrow"];var ___cxa_end_catch=Module["___cxa_end_catch"]=wasmExports["__cxa_end_catch"];var ___cxa_allocate_exception=Module["___cxa_allocate_exception"]=wasmExports["__cxa_allocate_exception"];var ___cxa_free_exception=Module["___cxa_free_exception"]=wasmExports["__cxa_free_exception"];var ___cxa_throw=wasmExports["__cxa_throw"];var ___cxa_pure_virtual=Module["___cxa_pure_virtual"]=wasmExports["__cxa_pure_virtual"];var ___cxa_uncaught_exceptions=Module["___cxa_uncaught_exceptions"]=wasmExports["__cxa_uncaught_exceptions"];var ___cxa_decrement_exception_refcount=wasmExports["__cxa_decrement_exception_refcount"];var ___cxa_increment_exception_refcount=wasmExports["__cxa_increment_exception_refcount"];var ___cxa_current_primary_exception=Module["___cxa_current_primary_exception"]=wasmExports["__cxa_current_primary_exception"];var ___cxa_rethrow_primary_exception=Module["___cxa_rethrow_primary_exception"]=wasmExports["__cxa_rethrow_primary_exception"];var ___cxa_init_primary_exception=Module["___cxa_init_primary_exception"]=wasmExports["__cxa_init_primary_exception"];var ___dynamic_cast=Module["___dynamic_cast"]=wasmExports["__dynamic_cast"];var ___cxa_bad_cast=Module["___cxa_bad_cast"]=wasmExports["__cxa_bad_cast"];var ___cxa_bad_typeid=Module["___cxa_bad_typeid"]=wasmExports["__cxa_bad_typeid"];var ___cxa_throw_bad_array_new_length=Module["___cxa_throw_bad_array_new_length"]=wasmExports["__cxa_throw_bad_array_new_length"];var ___cxa_get_globals_fast=Module["___cxa_get_globals_fast"]=wasmExports["__cxa_get_globals_fast"];var ___cxa_demangle=wasmExports["__cxa_demangle"];var ___cxa_allocate_dependent_exception=Module["___cxa_allocate_dependent_exception"]=wasmExports["__cxa_allocate_dependent_exception"];var ___cxa_free_dependent_exception=Module["___cxa_free_dependent_exception"]=wasmExports["__cxa_free_dependent_exception"];var ___cxa_get_globals=Module["___cxa_get_globals"]=wasmExports["__cxa_get_globals"];var __Unwind_RaiseException=Module["__Unwind_RaiseException"]=wasmExports["_Unwind_RaiseException"];var ___cxa_get_exception_ptr=Module["___cxa_get_exception_ptr"]=wasmExports["__cxa_get_exception_ptr"];var __Unwind_DeleteException=Module["__Unwind_DeleteException"]=wasmExports["_Unwind_DeleteException"];var ___cxa_call_terminate=Module["___cxa_call_terminate"]=wasmExports["__cxa_call_terminate"];var ___cxa_current_exception_type=Module["___cxa_current_exception_type"]=wasmExports["__cxa_current_exception_type"];var ___cxa_uncaught_exception=Module["___cxa_uncaught_exception"]=wasmExports["__cxa_uncaught_exception"];var ___thrown_object_from_unwind_exception=wasmExports["__thrown_object_from_unwind_exception"];var ___get_exception_message=wasmExports["__get_exception_message"];var ___get_exception_terminate_message=Module["___get_exception_terminate_message"]=wasmExports["__get_exception_terminate_message"];var ___cxa_guard_acquire=Module["___cxa_guard_acquire"]=wasmExports["__cxa_guard_acquire"];var ___cxa_guard_release=Module["___cxa_guard_release"]=wasmExports["__cxa_guard_release"];var ___cxa_guard_abort=Module["___cxa_guard_abort"]=wasmExports["__cxa_guard_abort"];var ___gxx_personality_wasm0=Module["___gxx_personality_wasm0"]=wasmExports["__gxx_personality_wasm0"];var __Unwind_SetGR=Module["__Unwind_SetGR"]=wasmExports["_Unwind_SetGR"];var __Unwind_SetIP=Module["__Unwind_SetIP"]=wasmExports["_Unwind_SetIP"];var __Unwind_GetLanguageSpecificData=Module["__Unwind_GetLanguageSpecificData"]=wasmExports["_Unwind_GetLanguageSpecificData"];var __Unwind_GetIP=Module["__Unwind_GetIP"]=wasmExports["_Unwind_GetIP"];var __Unwind_GetRegionStart=Module["__Unwind_GetRegionStart"]=wasmExports["_Unwind_GetRegionStart"];var ___cxa_call_unexpected=Module["___cxa_call_unexpected"]=wasmExports["__cxa_call_unexpected"];var ___cxa_thread_atexit=Module["___cxa_thread_atexit"]=wasmExports["__cxa_thread_atexit"];var ___cxa_deleted_virtual=Module["___cxa_deleted_virtual"]=wasmExports["__cxa_deleted_virtual"];var __Unwind_CallPersonality=Module["__Unwind_CallPersonality"]=wasmExports["_Unwind_CallPersonality"];var _gethostbyaddr_r=Module["_gethostbyaddr_r"]=wasmExports["gethostbyaddr_r"];var _gethostbyname2=Module["_gethostbyname2"]=wasmExports["gethostbyname2"];var _gethostbyname2_r=Module["_gethostbyname2_r"]=wasmExports["gethostbyname2_r"];var _gethostbyname_r=Module["_gethostbyname_r"]=wasmExports["gethostbyname_r"];var _shutdown=Module["_shutdown"]=wasmExports["shutdown"];var _socketpair=Module["_socketpair"]=wasmExports["socketpair"];var ___wasm_apply_data_relocs=wasmExports["__wasm_apply_data_relocs"];var _py_docstring_mod=Module["_py_docstring_mod"]=3474304;var _PyExc_AttributeError=Module["_PyExc_AttributeError"]=2794608;var _stdout=Module["_stdout"]=3326440;var _PyExc_ModuleNotFoundError=Module["_PyExc_ModuleNotFoundError"]=2794512;var __Py_NoneStruct=Module["__Py_NoneStruct"]=2829304;var _internal_error=Module["_internal_error"]=3474312;var _conversion_error=Module["_conversion_error"]=3474316;var _PyExc_ImportError=Module["_PyExc_ImportError"]=2794508;var _pyodide_export_=Module["_pyodide_export_"]=2778088;var _pystate_keepalive_=Module["_pystate_keepalive_"]=2778092;var _pystate_keepalive=Module["_pystate_keepalive"]=3474508;var _compat_null_to_none=Module["_compat_null_to_none"]=3474324;var _py_jsnull=Module["_py_jsnull"]=3474456;var __Py_TrueStruct=Module["__Py_TrueStruct"]=2782932;var __Py_FalseStruct=Module["__Py_FalseStruct"]=2782948;var _Jsr_undefined=Module["_Jsr_undefined"]=3474436;var _jsbind=Module["_jsbind"]=3474380;var _Jsr_error=Module["_Jsr_error"]=3474432;var _PyExc_TypeError=Module["_PyExc_TypeError"]=2794476;var _PyExc_StopIteration=Module["_PyExc_StopIteration"]=2794484;var _PyTraceBack_Type=Module["_PyTraceBack_Type"]=3172300;var _PyExc_GeneratorExit=Module["_PyExc_GeneratorExit"]=2794488;var _PyExc_StopAsyncIteration=Module["_PyExc_StopAsyncIteration"]=2794480;var _PyExc_RuntimeError=Module["_PyExc_RuntimeError"]=2794584;var _PyExc_IndexError=Module["_PyExc_IndexError"]=2794836;var _PyExc_Exception=Module["_PyExc_Exception"]=2794472;var _PyExc_BaseException=Module["_PyExc_BaseException"]=2794468;var _methods=Module["_methods"]=2778896;var _PyExc_SystemError=Module["_PyExc_SystemError"]=2794880;var _PyExc_KeyError=Module["_PyExc_KeyError"]=2794840;var _PySlice_Type=Module["_PySlice_Type"]=2840400;var _PyLong_Type=Module["_PyLong_Type"]=2820548;var _PyBool_Type=Module["_PyBool_Type"]=2783108;var _PyExc_ValueError=Module["_PyExc_ValueError"]=2794500;var _PyExc_NotImplementedError=Module["_PyExc_NotImplementedError"]=2794596;var _PyBaseObject_Type=Module["_PyBaseObject_Type"]=2842440;var _PyExc_OverflowError=Module["_PyExc_OverflowError"]=2794872;var _PyList_Type=Module["_PyList_Type"]=2818960;var _PyTuple_Type=Module["_PyTuple_Type"]=2840912;var _PyExc_RuntimeWarning=Module["_PyExc_RuntimeWarning"]=2795124;var __Py_NotImplementedStruct=Module["__Py_NotImplementedStruct"]=2830080;var _default_signature=Module["_default_signature"]=3474388;var _no_default=Module["_no_default"]=3474384;var _PyCoro_Type=Module["_PyCoro_Type"]=2812480;var _PyGen_Type=Module["_PyGen_Type"]=2811952;var _PyDict_Type=Module["_PyDict_Type"]=2821568;var _compat_to_string_repr=Module["_compat_to_string_repr"]=3474404;var _PyMethod_Type=Module["_PyMethod_Type"]=2788264;var _PyFunction_Type=Module["_PyFunction_Type"]=2816820;var _py_buffer_len_offset=Module["_py_buffer_len_offset"]=2781544;var _py_buffer_shape_offset=Module["_py_buffer_shape_offset"]=2781548;var _Jsr_true=Module["_Jsr_true"]=3474440;var _Jsr_false=Module["_Jsr_false"]=3474444;var _Jsr_novalue=Module["_Jsr_novalue"]=3474448;var _PySet_Type=Module["_PySet_Type"]=2839024;var _PyFloat_Type=Module["_PyFloat_Type"]=2815052;var _compat_dict_to_literalmap=Module["_compat_dict_to_literalmap"]=3474452;var _threadstate_freelist_len=Module["_threadstate_freelist_len"]=3474504;var _threadstate_freelist=Module["_threadstate_freelist"]=3474464;var _stderr=Module["_stderr"]=3326136;var __PyParser_TokenNames=Module["__PyParser_TokenNames"]=2782224;var _PyExc_SyntaxError=Module["_PyExc_SyntaxError"]=2794612;var __PyExc_IncompleteInputError=Module["__PyExc_IncompleteInputError"]=2794624;var _PyExc_LookupError=Module["_PyExc_LookupError"]=2794832;var _PyExc_UnicodeDecodeError=Module["_PyExc_UnicodeDecodeError"]=2794852;var _PyExc_IndentationError=Module["_PyExc_IndentationError"]=2794616;var _PyExc_KeyboardInterrupt=Module["_PyExc_KeyboardInterrupt"]=2794504;var _PyExc_TabError=Module["_PyExc_TabError"]=2794620;var _PyExc_UnicodeError=Module["_PyExc_UnicodeError"]=2794844;var _stdin=Module["_stdin"]=3326288;var _PyExc_MemoryError=Module["_PyExc_MemoryError"]=2794888;var __PyRuntime=Module["__PyRuntime"]=2869536;var _PyComplex_Type=Module["_PyComplex_Type"]=2790556;var _PyUnicode_Type=Module["_PyUnicode_Type"]=2850192;var _PyBytes_Type=Module["_PyBytes_Type"]=2786480;var __Py_EllipsisObject=Module["__Py_EllipsisObject"]=2840256;var __Py_ctype_table=Module["__Py_ctype_table"]=477376;var _PyExc_DeprecationWarning=Module["_PyExc_DeprecationWarning"]=2795112;var _PyExc_SyntaxWarning=Module["_PyExc_SyntaxWarning"]=2795120;var __Py_ctype_tolower=Module["__Py_ctype_tolower"]=478400;var _PyExc_OSError=Module["_PyExc_OSError"]=2794516;var __PyOS_ReadlineTState=Module["__PyOS_ReadlineTState"]=3474580;var _PyOS_InputHook=Module["_PyOS_InputHook"]=3474584;var _PyOS_ReadlineFunctionPointer=Module["_PyOS_ReadlineFunctionPointer"]=3474588;var _PyType_Type=Module["_PyType_Type"]=2842048;var _PyExc_BufferError=Module["_PyExc_BufferError"]=2795100;var _PyCFunction_Type=Module["_PyCFunction_Type"]=2827960;var _PyByteArray_Type=Module["_PyByteArray_Type"]=2784400;var __PyByteArray_empty_string=Module["__PyByteArray_empty_string"]=3474593;var __PyUnion_Type=Module["__PyUnion_Type"]=2852728;var __Py_ctype_toupper=Module["__Py_ctype_toupper"]=478656;var _Py_hexdigits=Module["_Py_hexdigits"]=2858608;var _PyExc_BytesWarning=Module["_PyExc_BytesWarning"]=2795140;var _PyByteArrayIter_Type=Module["_PyByteArrayIter_Type"]=2784672;var __PyLong_DigitValue=Module["__PyLong_DigitValue"]=2819808;var _PyBytesIter_Type=Module["_PyBytesIter_Type"]=2786752;var _PyModule_Type=Module["_PyModule_Type"]=2828712;var _PyCapsule_Type=Module["_PyCapsule_Type"]=2787652;var _PyCell_Type=Module["_PyCell_Type"]=2787912;var _PyInstanceMethod_Type=Module["_PyInstanceMethod_Type"]=2788568;var _PyCode_Type=Module["_PyCode_Type"]=2789756;var _PyFrozenSet_Type=Module["_PyFrozenSet_Type"]=2839584;var _PyExc_ZeroDivisionError=Module["_PyExc_ZeroDivisionError"]=2794876;var _PyMethodDescr_Type=Module["_PyMethodDescr_Type"]=2791024;var _PyClassMethodDescr_Type=Module["_PyClassMethodDescr_Type"]=2791232;var _PyMemberDescr_Type=Module["_PyMemberDescr_Type"]=2791500;var _PyGetSetDescr_Type=Module["_PyGetSetDescr_Type"]=2791772;var _PyWrapperDescr_Type=Module["_PyWrapperDescr_Type"]=2792064;var _PyDictProxy_Type=Module["_PyDictProxy_Type"]=2793008;var _PyProperty_Type=Module["_PyProperty_Type"]=2793468;var _PyReversed_Type=Module["_PyReversed_Type"]=2794176;var _PyEnum_Type=Module["_PyEnum_Type"]=2793904;var _PyExc_BaseExceptionGroup=Module["_PyExc_BaseExceptionGroup"]=2794496;var _PyExc_UnicodeTranslateError=Module["_PyExc_UnicodeTranslateError"]=2794856;var _PyExc_BlockingIOError=Module["_PyExc_BlockingIOError"]=2794520;var _PyExc_BrokenPipeError=Module["_PyExc_BrokenPipeError"]=2794532;var _PyExc_ChildProcessError=Module["_PyExc_ChildProcessError"]=2794528;var _PyExc_ConnectionAbortedError=Module["_PyExc_ConnectionAbortedError"]=2794536;var _PyExc_ConnectionRefusedError=Module["_PyExc_ConnectionRefusedError"]=2794540;var _PyExc_ConnectionResetError=Module["_PyExc_ConnectionResetError"]=2794544;var _PyExc_FileExistsError=Module["_PyExc_FileExistsError"]=2794548;var _PyExc_FileNotFoundError=Module["_PyExc_FileNotFoundError"]=2794552;var _PyExc_IsADirectoryError=Module["_PyExc_IsADirectoryError"]=2794556;var _PyExc_NotADirectoryError=Module["_PyExc_NotADirectoryError"]=2794560;var _PyExc_InterruptedError=Module["_PyExc_InterruptedError"]=2794564;var _PyExc_PermissionError=Module["_PyExc_PermissionError"]=2794568;var _PyExc_ProcessLookupError=Module["_PyExc_ProcessLookupError"]=2794572;var _PyExc_TimeoutError=Module["_PyExc_TimeoutError"]=2794576;var _PyExc_EnvironmentError=Module["_PyExc_EnvironmentError"]=3474596;var _PyExc_IOError=Module["_PyExc_IOError"]=3474600;var _PyExc_SystemExit=Module["_PyExc_SystemExit"]=2794492;var _PyExc_ConnectionError=Module["_PyExc_ConnectionError"]=2794524;var _PyExc_EOFError=Module["_PyExc_EOFError"]=2794580;var _PyExc_RecursionError=Module["_PyExc_RecursionError"]=2794588;var _PyExc_PythonFinalizationError=Module["_PyExc_PythonFinalizationError"]=2794592;var _PyExc_NameError=Module["_PyExc_NameError"]=2794600;var _PyExc_UnboundLocalError=Module["_PyExc_UnboundLocalError"]=2794604;var _PyExc_UnicodeEncodeError=Module["_PyExc_UnicodeEncodeError"]=2794848;var _PyExc_AssertionError=Module["_PyExc_AssertionError"]=2794860;var _PyExc_ArithmeticError=Module["_PyExc_ArithmeticError"]=2794864;var _PyExc_FloatingPointError=Module["_PyExc_FloatingPointError"]=2794868;var _PyExc_ReferenceError=Module["_PyExc_ReferenceError"]=2794884;var _PyExc_Warning=Module["_PyExc_Warning"]=2795104;var _PyExc_UserWarning=Module["_PyExc_UserWarning"]=2795108;var _PyExc_PendingDeprecationWarning=Module["_PyExc_PendingDeprecationWarning"]=2795116;var _PyExc_FutureWarning=Module["_PyExc_FutureWarning"]=2795128;var _PyExc_ImportWarning=Module["_PyExc_ImportWarning"]=2795132;var _PyExc_UnicodeWarning=Module["_PyExc_UnicodeWarning"]=2795136;var _PyExc_EncodingWarning=Module["_PyExc_EncodingWarning"]=2795144;var _PyExc_ResourceWarning=Module["_PyExc_ResourceWarning"]=2795148;var _Py_GenericAliasType=Module["_Py_GenericAliasType"]=2811404;var _PyAsyncGen_Type=Module["_PyAsyncGen_Type"]=2813260;var __PyAsyncGenASend_Type=Module["__PyAsyncGenASend_Type"]=2813552;var _PyStdPrinter_Type=Module["_PyStdPrinter_Type"]=2814432;var __Py_SwappedOp=Module["__Py_SwappedOp"]=2829312;var _PyFrameLocalsProxy_Type=Module["_PyFrameLocalsProxy_Type"]=2815776;var _PyFrame_Type=Module["_PyFrame_Type"]=2816280;var _PyClassMethod_Type=Module["_PyClassMethod_Type"]=2817164;var _PyStaticMethod_Type=Module["_PyStaticMethod_Type"]=2817500;var _PySeqIter_Type=Module["_PySeqIter_Type"]=2817904;var _PyCallIter_Type=Module["_PyCallIter_Type"]=2818144;var _PyDictKeys_Type=Module["_PyDictKeys_Type"]=2823352;var _PyDictValues_Type=Module["_PyDictValues_Type"]=2823936;var _PyDictItems_Type=Module["_PyDictItems_Type"]=2823648;var _PyListIter_Type=Module["_PyListIter_Type"]=2819232;var _PyListRevIter_Type=Module["_PyListRevIter_Type"]=2819504;var _PyDictIterKey_Type=Module["_PyDictIterKey_Type"]=2821824;var _PyDictRevIterKey_Type=Module["_PyDictRevIterKey_Type"]=2822448;var _PyDictRevIterValue_Type=Module["_PyDictRevIterValue_Type"]=2822864;var _PyDictIterItem_Type=Module["_PyDictIterItem_Type"]=2822240;var _PyDictIterValue_Type=Module["_PyDictIterValue_Type"]=2822032;var _PyDictRevIterItem_Type=Module["_PyDictRevIterItem_Type"]=2822656;var _PyODict_Type=Module["_PyODict_Type"]=2824648;var _PyODictIter_Type=Module["_PyODictIter_Type"]=2824896;var _PyODictKeys_Type=Module["_PyODictKeys_Type"]=2825136;var _PyODictValues_Type=Module["_PyODictValues_Type"]=2825616;var _PyODictItems_Type=Module["_PyODictItems_Type"]=2825376;var _PyMemoryView_Type=Module["_PyMemoryView_Type"]=2827140;var _PyCMethod_Type=Module["_PyCMethod_Type"]=2828168;var _PyModuleDef_Type=Module["_PyModuleDef_Type"]=2828376;var __PyNone_Type=Module["__PyNone_Type"]=2829480;var __PyNotImplemented_Type=Module["__PyNotImplemented_Type"]=2829872;var _PyContextToken_Type=Module["_PyContextToken_Type"]=2859596;var _PyContextVar_Type=Module["_PyContextVar_Type"]=2859288;var _PyContext_Type=Module["_PyContext_Type"]=2858960;var _PyEllipsis_Type=Module["_PyEllipsis_Type"]=2840048;var _PyFilter_Type=Module["_PyFilter_Type"]=2856064;var _PyLongRangeIter_Type=Module["_PyLongRangeIter_Type"]=2838016;var _PyMap_Type=Module["_PyMap_Type"]=2856304;var _PyPickleBuffer_Type=Module["_PyPickleBuffer_Type"]=2836896;var _PyRangeIter_Type=Module["_PyRangeIter_Type"]=2837744;var _PyRange_Type=Module["_PyRange_Type"]=2837472;var _PySetIter_Type=Module["_PySetIter_Type"]=2838272;var _PySuper_Type=Module["_PySuper_Type"]=2842944;var _PyTupleIter_Type=Module["_PyTupleIter_Type"]=2841184;var _PyUnicodeIter_Type=Module["_PyUnicodeIter_Type"]=2850464;var _PyZip_Type=Module["_PyZip_Type"]=2856560;var __PyWeakref_CallableProxyType=Module["__PyWeakref_CallableProxyType"]=2853680;var __PyWeakref_ProxyType=Module["__PyWeakref_ProxyType"]=2853472;var __PyWeakref_RefType=Module["__PyWeakref_RefType"]=2853016;var __PySet_Dummy=Module["__PySet_Dummy"]=2839800;var _PyStructSequence_UnnamedField=Module["_PyStructSequence_UnnamedField"]=2840628;var __Py_ascii_whitespace=Module["__Py_ascii_whitespace"]=325408;var __PyIntrinsics_UnaryFunctions=Module["__PyIntrinsics_UnaryFunctions"]=2864528;var __PyIntrinsics_BinaryFunctions=Module["__PyIntrinsics_BinaryFunctions"]=2864624;var __PyEval_ConversionFuncs=Module["__PyEval_ConversionFuncs"]=2858592;var _Py_EMSCRIPTEN_SIGNAL_HANDLING=Module["_Py_EMSCRIPTEN_SIGNAL_HANDLING"]=3512276;var __PyEval_BinaryOps=Module["__PyEval_BinaryOps"]=2858480;var _PyExc_InterpreterError=Module["_PyExc_InterpreterError"]=2860024;var _PyExc_InterpreterNotFoundError=Module["_PyExc_InterpreterNotFoundError"]=2860028;var _PyUnstable_ExecutableKinds=Module["_PyUnstable_ExecutableKinds"]=2860512;var _Py_Version=Module["_Py_Version"]=460964;var _PyImport_Inittab=Module["_PyImport_Inittab"]=2862176;var __PyImport_FrozenBootstrap=Module["__PyImport_FrozenBootstrap"]=3321248;var _PyImport_FrozenModules=Module["_PyImport_FrozenModules"]=3521096;var __PyImport_FrozenStdlib=Module["__PyImport_FrozenStdlib"]=3321520;var __PyImport_FrozenTest=Module["__PyImport_FrozenTest"]=3321728;var _Py_IgnoreEnvironmentFlag=Module["_Py_IgnoreEnvironmentFlag"]=3511020;var _Py_IsolatedFlag=Module["_Py_IsolatedFlag"]=3511040;var _Py_BytesWarningFlag=Module["_Py_BytesWarningFlag"]=3511012;var _Py_InspectFlag=Module["_Py_InspectFlag"]=3511e3;var _Py_InteractiveFlag=Module["_Py_InteractiveFlag"]=3510996;var _Py_OptimizeFlag=Module["_Py_OptimizeFlag"]=3511004;var _Py_DebugFlag=Module["_Py_DebugFlag"]=3510984;var _Py_VerboseFlag=Module["_Py_VerboseFlag"]=3510988;var _Py_QuietFlag=Module["_Py_QuietFlag"]=3510992;var _Py_FrozenFlag=Module["_Py_FrozenFlag"]=3511016;var _Py_UnbufferedStdioFlag=Module["_Py_UnbufferedStdioFlag"]=3511032;var _Py_NoSiteFlag=Module["_Py_NoSiteFlag"]=3511008;var _Py_DontWriteBytecodeFlag=Module["_Py_DontWriteBytecodeFlag"]=3511024;var _Py_NoUserSiteDirectory=Module["_Py_NoUserSiteDirectory"]=3511028;var _Py_HashRandomizationFlag=Module["_Py_HashRandomizationFlag"]=3511036;var _Py_FileSystemDefaultEncoding=Module["_Py_FileSystemDefaultEncoding"]=3511144;var _Py_HasFileSystemDefaultEncoding=Module["_Py_HasFileSystemDefaultEncoding"]=3511148;var _Py_FileSystemDefaultEncodeErrors=Module["_Py_FileSystemDefaultEncodeErrors"]=3511152;var _Py_UTF8Mode=Module["_Py_UTF8Mode"]=3510980;var __Py_HashSecret=Module["__Py_HashSecret"]=3511160;var _PY_TIMEOUT_MAX=Module["_PY_TIMEOUT_MAX"]=492616;var __PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET=Module["__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET"]=493560;var _ffi_type_pointer=Module["_ffi_type_pointer"]=2425108;var _ffi_type_void=Module["_ffi_type_void"]=2425e3;var _ffi_type_sint32=Module["_ffi_type_sint32"]=2425072;var _ffi_type_uint8=Module["_ffi_type_uint8"]=2425012;var _ffi_type_double=Module["_ffi_type_double"]=2425132;var _ffi_type_longdouble=Module["_ffi_type_longdouble"]=2425144;var _ffi_type_float=Module["_ffi_type_float"]=2425120;var _ffi_type_sint16=Module["_ffi_type_sint16"]=2425048;var _ffi_type_uint16=Module["_ffi_type_uint16"]=2425036;var _ffi_type_uint32=Module["_ffi_type_uint32"]=2425060;var _ffi_type_sint64=Module["_ffi_type_sint64"]=2425096;var _ffi_type_uint64=Module["_ffi_type_uint64"]=2425084;var _ffi_type_sint8=Module["_ffi_type_sint8"]=2425024;var _environ=Module["_environ"]=3521120;var __deduplicate_map=Module["__deduplicate_map"]=3521100;var _BZ2_crc32Table=Module["_BZ2_crc32Table"]=3321904;var _BZ2_rNums=Module["_BZ2_rNums"]=3322928;var _z_errmsg=Module["_z_errmsg"]=3325168;var __length_code=Module["__length_code"]=2435824;var __dist_code=Module["__dist_code"]=2435312;var _deflate_copyright=Module["_deflate_copyright"]=2430480;var _inflate_copyright=Module["_inflate_copyright"]=2435008;var ___environ=Module["___environ"]=3521120;var ____environ=Module["____environ"]=3521120;var __environ=Module["__environ"]=3521120;var ___stack_chk_guard=Module["___stack_chk_guard"]=3521132;var _daylight=Module["_daylight"]=3521140;var _timezone=Module["_timezone"]=3521136;var ___tzname=Module["___tzname"]=3521144;var ___timezone=Module["___timezone"]=3521136;var ___daylight=Module["___daylight"]=3521140;var _tzname=Module["_tzname"]=3521144;var ___progname=Module["___progname"]=3523072;var ___optreset=Module["___optreset"]=3522036;var _optind=Module["_optind"]=3325416;var ___optpos=Module["___optpos"]=3522040;var _optarg=Module["_optarg"]=3522044;var _optopt=Module["_optopt"]=3522048;var _opterr=Module["_opterr"]=3325420;var _optreset=Module["_optreset"]=3522036;var _h_errno=Module["_h_errno"]=3522172;var ___signgam=Module["___signgam"]=3537468;var __ns_flagdata=Module["__ns_flagdata"]=2623184;var ___progname_full=Module["___progname_full"]=3523076;var _program_invocation_short_name=Module["_program_invocation_short_name"]=3523072;var _program_invocation_name=Module["_program_invocation_name"]=3523076;var ___sig_pending=Module["___sig_pending"]=3527448;var ___sig_actions=Module["___sig_actions"]=3528368;var _signgam=Module["_signgam"]=3537468;var ___THREW__=Module["___THREW__"]=3544272;var ___threwValue=Module["___threwValue"]=3544276;var ___cxa_unexpected_handler=Module["___cxa_unexpected_handler"]=3336788;var ___cxa_terminate_handler=Module["___cxa_terminate_handler"]=3336784;var ___cxa_new_handler=Module["___cxa_new_handler"]=3567072;var ___wasm_lpad_context=Module["___wasm_lpad_context"]=3567616;var _in6addr_any=Module["_in6addr_any"]=2777900;var _in6addr_loopback=Module["_in6addr_loopback"]=2777916;function applySignatureConversions(wasmExports){wasmExports=Object.assign({},wasmExports);var makeWrapper_pp=f=>a0=>f(a0)>>>0;var makeWrapper_p=f=>()=>f()>>>0;var makeWrapper_pP=f=>a0=>f(a0)>>>0;var makeWrapper_ppp=f=>(a0,a1)=>f(a0,a1)>>>0;var makeWrapper_p_=f=>a0=>f(a0)>>>0;var makeWrapper_pppp=f=>(a0,a1,a2)=>f(a0,a1,a2)>>>0;var makeWrapper_ppppp=f=>(a0,a1,a2,a3)=>f(a0,a1,a2,a3)>>>0;wasmExports["malloc"]=makeWrapper_pp(wasmExports["malloc"]);wasmExports["__errno_location"]=makeWrapper_p(wasmExports["__errno_location"]);wasmExports["sbrk"]=makeWrapper_pP(wasmExports["sbrk"]);wasmExports["calloc"]=makeWrapper_ppp(wasmExports["calloc"]);wasmExports["strerror"]=makeWrapper_p_(wasmExports["strerror"]);wasmExports["pthread_self"]=makeWrapper_p(wasmExports["pthread_self"]);wasmExports["emscripten_stack_get_end"]=makeWrapper_p(wasmExports["emscripten_stack_get_end"]);wasmExports["emscripten_stack_get_base"]=makeWrapper_p(wasmExports["emscripten_stack_get_base"]);wasmExports["emscripten_builtin_malloc"]=makeWrapper_pp(wasmExports["emscripten_builtin_malloc"]);wasmExports["memcpy"]=makeWrapper_pppp(wasmExports["memcpy"]);wasmExports["_emscripten_find_dylib"]=makeWrapper_ppppp(wasmExports["_emscripten_find_dylib"]);wasmExports["emscripten_builtin_memalign"]=makeWrapper_ppp(wasmExports["emscripten_builtin_memalign"]);wasmExports["emscripten_stack_get_current"]=makeWrapper_p(wasmExports["emscripten_stack_get_current"]);wasmExports["emscripten_main_runtime_thread_id"]=makeWrapper_p(wasmExports["emscripten_main_runtime_thread_id"]);wasmExports["memalign"]=makeWrapper_ppp(wasmExports["memalign"]);wasmExports["emscripten_builtin_calloc"]=makeWrapper_ppp(wasmExports["emscripten_builtin_calloc"]);wasmExports["_emscripten_stack_alloc"]=makeWrapper_pp(wasmExports["_emscripten_stack_alloc"]);wasmExports["__cxa_get_exception_ptr"]=makeWrapper_pp(wasmExports["__cxa_get_exception_ptr"]);return wasmExports}function callMain(args=[]){var entryFunction=resolveGlobalSymbol("main").sym;if(!entryFunction)return;args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv;args.forEach(arg=>{HEAPU32[argv_ptr>>>2>>>0]=stringToUTF8OnStack(arg);argv_ptr+=4});HEAPU32[argv_ptr>>>2>>>0]=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){dependenciesFulfilled=run;return}preRun();if(runDependencies>0){dependenciesFulfilled=run;return}function doRun(){Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();var noInitialRun=Module["noInitialRun"]||false;if(!noInitialRun)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}function preInit(){if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].shift()()}}}preInit();run();moduleRtn=readyPromise; - - - return moduleRtn; -} -); -})(); -globalThis._createPyodideModule = _createPyodideModule; diff --git a/crates/execution/assets/pyodide/pyodide.asm.wasm b/crates/execution/assets/pyodide/pyodide.asm.wasm deleted file mode 100755 index 5fac234e3..000000000 Binary files a/crates/execution/assets/pyodide/pyodide.asm.wasm and /dev/null differ diff --git a/crates/execution/assets/pyodide/pyodide.mjs b/crates/execution/assets/pyodide/pyodide.mjs deleted file mode 100644 index 8325d8810..000000000 --- a/crates/execution/assets/pyodide/pyodide.mjs +++ /dev/null @@ -1,4 +0,0 @@ -var Z=Object.defineProperty;var o=(e,t)=>Z(e,"name",{value:t,configurable:!0}),A=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var W=(()=>{for(var e=new Uint8Array(128),t=0;t<64;t++)e[t<26?t+65:t<52?t+71:t<62?t-4:t*4-205]=t;return n=>{for(var i=n.length,s=new Uint8Array((i-(n[i-1]=="=")-(n[i-2]=="="))*3/4|0),r=0,a=0;r>4,s[a++]=c<<4|d>>2,s[a++]=d<<6|u}return s}})();function ee(e){return!isNaN(parseFloat(e))&&isFinite(e)}o(ee,"_isNumber");function P(e){return e.charAt(0).toUpperCase()+e.substring(1)}o(P,"_capitalize");function x(e){return function(){return this[e]}}o(x,"_getter");function $e(e){if(typeof Buffer<"u")return Buffer.from(e,"utf8").toString("base64");let t=typeof TextEncoder<"u"?new TextEncoder().encode(e):Uint8Array.from(e,r=>r.charCodeAt(0)&255),n="";for(let r=0;r-1&&(r=r.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(,.*$)/g,""));var a=r.replace(/^\s+/,"").replace(/\(eval code/g,"(").replace(/^.*?\s+/,""),l=a.match(/ (\(.+\)$)/);a=l?a.replace(l[0],""):a;var c=this.extractLocation(l?l[1]:a),d=l&&a||void 0,u=["eval",""].indexOf(c[0])>-1?void 0:c[0];return new O({functionName:d,fileName:u,lineNumber:c[1],columnNumber:c[2],source:r})},this)},"ErrorStackParser$$parseV8OrIE"),parseFFOrSafari:o(function(i){var s=i.stack.split(` -`).filter(function(r){return!r.match(t)},this);return s.map(function(r){if(r.indexOf(" > eval")>-1&&(r=r.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),r.indexOf("@")===-1&&r.indexOf(":")===-1)return new O({functionName:r});var a=/((.*".+"[^@]*)?[^@]*)(?:@)/,l=r.match(a),c=l&&l[1]?l[1]:void 0,d=this.extractLocation(r.replace(a,""));return new O({functionName:c,fileName:d[0],lineNumber:d[1],columnNumber:d[2],source:r})},this)},"ErrorStackParser$$parseFFOrSafari")}}o(re,"ErrorStackParser");var ie=new re;var M=ie;function oe(){if(typeof API<"u"&&API!==globalThis.API)return API.runtimeEnv;let e=typeof Bun<"u",t=typeof Deno<"u",n=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&!process.browser,i=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent.indexOf("Chrome")===-1&&navigator.userAgent.indexOf("Safari")>-1;return ae({IN_BUN:e,IN_DENO:t,IN_NODE:n,IN_SAFARI:i,IN_SHELL:typeof read=="function"&&typeof load=="function"})}o(oe,"getGlobalRuntimeEnv");var f=oe();function ae(e){let t=e.IN_NODE&&typeof module<"u"&&module.exports&&typeof A=="function"&&typeof __dirname=="string",n=e.IN_NODE&&!t,i=!e.IN_NODE&&!e.IN_DENO&&!e.IN_BUN,s=i&&typeof window<"u"&&typeof window.document<"u"&&typeof document.createElement=="function"&&"sessionStorage"in window&&typeof globalThis.importScripts!="function",r=i&&typeof globalThis.WorkerGlobalScope<"u"&&typeof globalThis.self<"u"&&globalThis.self instanceof globalThis.WorkerGlobalScope;return{...e,IN_BROWSER:i,IN_BROWSER_MAIN_THREAD:s,IN_BROWSER_WEB_WORKER:r,IN_NODE_COMMONJS:t,IN_NODE_ESM:n}}o(ae,"calculateDerivedFlags");var $,D,H,B,L;async function T(){if(!f.IN_NODE||($=(await import("node:url")).default,B=await import("node:fs"),L=await import("node:fs/promises"),H=(await import("node:vm")).default,D=await import("node:path"),C=D.sep,typeof A<"u"))return;let e=B,t=await import("node:crypto"),n=await import("ws"),i=await import("node:child_process"),s={fs:e,crypto:t,ws:n,child_process:i};globalThis.require=function(r){return s[r]}}o(T,"initNodeModules");function se(e,t){return D.resolve(t||".",e)}o(se,"node_resolvePath");function le(e,t){return t===void 0&&(t=location),new URL(e,t).toString()}o(le,"browser_resolvePath");var _;f.IN_NODE?_=se:f.IN_SHELL?_=o(e=>e,"resolvePath"):_=le;var C;f.IN_NODE||(C="/");function ce(e,t){return e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?{response:fetch(e)}:{binary:L.readFile(e).then(n=>new Uint8Array(n.buffer,n.byteOffset,n.byteLength))}}o(ce,"node_getBinaryResponse");function de(e,t){if(e.startsWith("file://")&&(e=e.slice(7)),e.includes("://"))throw new Error("Shell cannot fetch urls");return{binary:Promise.resolve(new Uint8Array(readbuffer(e)))}}o(de,"shell_getBinaryResponse");function ue(e,t){let n=new URL(e,location);return{response:fetch(n,t?{integrity:t}:{})}}o(ue,"browser_getBinaryResponse");var R;f.IN_NODE?R=ce:f.IN_SHELL?R=de:R=ue;async function j(e,t){let{response:n,binary:i}=R(e,t);if(i)return i;let s=await n;if(!s.ok)throw new Error(`Failed to load '${e}': request failed.`);return new Uint8Array(await s.arrayBuffer())}o(j,"loadBinaryFile");var w;if(f.IN_BROWSER_MAIN_THREAD)w=o(async e=>await import(e),"loadScript");else if(f.IN_BROWSER_WEB_WORKER)w=o(async e=>{try{globalThis.importScripts(e)}catch(t){if(t instanceof TypeError)await import(e);else throw t}},"loadScript");else if(f.IN_NODE)w=fe;else if(f.IN_SHELL)w=load;else throw new Error("Cannot determine runtime environment");async function fe(e){e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?H.runInThisContext(await(await fetch(e)).text()):await import(e.startsWith("/" )?e:$.pathToFileURL(e).href)}o(fe,"nodeLoadScript");async function V(e){if(f.IN_NODE){await T();let t=await L.readFile(e,{encoding:"utf8"});return JSON.parse(t)}else if(f.IN_SHELL){let t=read(e);return JSON.parse(t)}else return await(await fetch(e)).json()}o(V,"loadLockFile");async function z(){if(f.IN_NODE_COMMONJS)return __dirname;let e;try{throw new Error}catch(i){e=i}let t=M.parse(e)[0].fileName;if(f.IN_NODE&&!t.startsWith("file://")&&(t=`file://${t}`),f.IN_NODE_ESM){let i=await import("node:path");return(await import("node:url")).fileURLToPath(i.dirname(t))}let n=t.lastIndexOf(C);if(n===-1)throw new Error("Could not extract indexURL path from pyodide module location. Please pass the indexURL explicitly to loadPyodide.");return t.slice(0,n)}o(z,"calculateDirname");function J(e){return e.substring(0,e.lastIndexOf("/")+1)||globalThis.location?.toString()||"."}o(J,"calculateInstallBaseUrl");function q(e){let t=e.FS,n=e.FS.filesystems.MEMFS,i=e.PATH,s={DIR_MODE:16895,FILE_MODE:33279,mount:o(function(r){if(!r.opts.fileSystemHandle)throw new Error("opts.fileSystemHandle is required");return n.mount.apply(null,arguments)},"mount"),syncfs:o(async(r,a,l)=>{try{let c=s.getLocalSet(r),d=await s.getRemoteSet(r),u=a?d:c,y=a?c:d;await s.reconcile(r,u,y),l(null)}catch(c){l(c)}},"syncfs"),getLocalSet:o(r=>{let a=Object.create(null);function l(u){return u!=="."&&u!==".."}o(l,"isRealDir");function c(u){return y=>i.join2(u,y)}o(c,"toAbsolute");let d=t.readdir(r.mountpoint).filter(l).map(c(r.mountpoint));for(;d.length;){let u=d.pop(),y=t.stat(u);t.isDir(y.mode)&&d.push.apply(d,t.readdir(u).filter(l).map(c(u))),a[u]={timestamp:y.mtime,mode:y.mode}}return{type:"local",entries:a}},"getLocalSet"),getRemoteSet:o(async r=>{let a=Object.create(null),l=await me(r.opts.fileSystemHandle);for(let[c,d]of l)c!=="."&&(a[i.join2(r.mountpoint,c)]={timestamp:d.kind==="file"?new Date((await d.getFile()).lastModified):new Date,mode:d.kind==="file"?s.FILE_MODE:s.DIR_MODE});return{type:"remote",entries:a,handles:l}},"getRemoteSet"),loadLocalEntry:o(r=>{let l=t.lookupPath(r,{}).node,c=t.stat(r);if(t.isDir(c.mode))return{timestamp:c.mtime,mode:c.mode};if(t.isFile(c.mode))return l.contents=n.getFileDataAsTypedArray(l),{timestamp:c.mtime,mode:c.mode,contents:l.contents};throw new Error("node type not supported")},"loadLocalEntry"),storeLocalEntry:o((r,a)=>{if(t.isDir(a.mode))t.mkdirTree(r,a.mode);else if(t.isFile(a.mode))t.writeFile(r,a.contents,{canOwn:!0});else throw new Error("node type not supported");t.chmod(r,a.mode),t.utime(r,a.timestamp,a.timestamp)},"storeLocalEntry"),removeLocalEntry:o(r=>{var a=t.stat(r);t.isDir(a.mode)?t.rmdir(r):t.isFile(a.mode)&&t.unlink(r)},"removeLocalEntry"),loadRemoteEntry:o(async r=>{if(r.kind==="file"){let a=await r.getFile();return{contents:new Uint8Array(await a.arrayBuffer()),mode:s.FILE_MODE,timestamp:new Date(a.lastModified)}}else{if(r.kind==="directory")return{mode:s.DIR_MODE,timestamp:new Date};throw new Error("unknown kind: "+r.kind)}},"loadRemoteEntry"),storeRemoteEntry:o(async(r,a,l)=>{let c=r.get(i.dirname(a)),d=t.isFile(l.mode)?await c.getFileHandle(i.basename(a),{create:!0}):await c.getDirectoryHandle(i.basename(a),{create:!0});if(d.kind==="file"){let u=await d.createWritable();await u.write(l.contents),await u.close()}r.set(a,d)},"storeRemoteEntry"),removeRemoteEntry:o(async(r,a)=>{await r.get(i.dirname(a)).removeEntry(i.basename(a)),r.delete(a)},"removeRemoteEntry"),reconcile:o(async(r,a,l)=>{let c=0,d=[];Object.keys(a.entries).forEach(function(m){let g=a.entries[m],h=l.entries[m];(!h||t.isFile(g.mode)&&g.timestamp.getTime()>h.timestamp.getTime())&&(d.push(m),c++)}),d.sort();let u=[];if(Object.keys(l.entries).forEach(function(m){a.entries[m]||(u.push(m),c++)}),u.sort().reverse(),!c)return;let y=a.type==="remote"?a.handles:l.handles;for(let m of d){let g=i.normalize(m.replace(r.mountpoint,"/")).substring(1);if(l.type==="local"){let h=y.get(g),Q=await s.loadRemoteEntry(h);s.storeLocalEntry(m,Q)}else{let h=s.loadLocalEntry(m);await s.storeRemoteEntry(y,g,h)}}for(let m of u)if(l.type==="local")s.removeLocalEntry(m);else{let g=i.normalize(m.replace(r.mountpoint,"/")).substring(1);await s.removeRemoteEntry(y,g)}},"reconcile")};e.FS.filesystems.NATIVEFS_ASYNC=s}o(q,"initializeNativeFS");var me=o(async e=>{let t=[];async function n(s){for await(let r of s.values())t.push(r),r.kind==="directory"&&await n(r)}o(n,"collect"),await n(e);let i=new Map;i.set(".",e);for(let s of t){let r=(await e.resolve(s)).join("/");i.set(r,s)}return i},"getFsHandles");var G=W("AGFzbQEAAAABDANfAGAAAW9gAW8BfwMDAgECByECD2NyZWF0ZV9zZW50aW5lbAAAC2lzX3NlbnRpbmVsAAEKEwIHAPsBAPsbCwkAIAD7GvsUAAs=");var ye=async function(){if(!(globalThis.navigator&&(/iPad|iPhone|iPod/.test(navigator.userAgent)||navigator.platform==="MacIntel"&&typeof navigator.maxTouchPoints<"u"&&navigator.maxTouchPoints>1)))try{let t=await WebAssembly.compile(G);return await WebAssembly.instantiate(t)}catch(t){if(t instanceof WebAssembly.CompileError)return;throw t}}();async function K(){let e=await ye;if(e)return e.exports;let t=Symbol("error marker");return{create_sentinel:o(()=>t,"create_sentinel"),is_sentinel:o(n=>n===t,"is_sentinel")}}o(K,"getSentinelImport");function Y(e){let t={config:e,runtimeEnv:f},n={noImageDecoding:!0,noAudioDecoding:!0,noWasmDecoding:!1,preRun:he(e),print:e.stdout,printErr:e.stderr,onExit(i){n.exitCode=i},thisProgram:e._sysExecutable,arguments:e.args,API:t,locateFile:o(i=>e.indexURL+i,"locateFile"),instantiateWasm:Ne(e.indexURL)};return n}o(Y,"createSettings");function ge(e){return function(t){let n="/";try{t.FS.mkdirTree(e)}catch(i){console.error(`Error occurred while making a home directory '${e}':`),console.error(i),console.error(`Using '${n}' for a home directory instead`),e=n}t.FS.chdir(e)}}o(ge,"createHomeDirectory");function be(e){return function(t){Object.assign(t.ENV,e)}}o(be,"setEnvironment");function ve(e){return e?[async t=>{t.addRunDependency("fsInitHook");try{await e(t.FS,{sitePackages:t.API.sitePackages})}finally{t.removeRunDependency("fsInitHook")}}]:[]}o(ve,"callFsInitHook");function Ee(e){let t=e.HEAPU32[e._Py_Version>>>2],n=t>>>24&255,i=t>>>16&255,s=t>>>8&255;return[n,i,s]}o(Ee,"computeVersionTuple");function Pe(e){let t=j(e);return async n=>{n.API.pyVersionTuple=Ee(n);let[i,s]=n.API.pyVersionTuple;n.FS.mkdirTree("/lib"),n.API.sitePackages=`/lib/python${i}.${s}/site-packages`,n.FS.mkdirTree(n.API.sitePackages),n.addRunDependency("install-stdlib");try{let r=await t;n.FS.writeFile(`/lib/python${i}${s}.zip`,r);}catch(r){console.error("Error occurred while installing the standard library:"),console.error(r)}finally{n.removeRunDependency("install-stdlib")}}}o(Pe,"installStdlib");function he(e){let t;return e.stdLibURL!=null?t=e.stdLibURL:t=e.indexURL+"python_stdlib.zip",[Pe(t),ge(e.env.HOME),be(e.env),q,...ve(e.fsInit)]}o(he,"getFileSystemInitializationFuncs");function Ne(e){if(typeof WasmOffsetConverter<"u")return;let{binary:t,response:n}=R(e+"pyodide.asm.wasm"),i=K();return function(s,r){return async function(){s.sentinel=await i;try{let a;if(n){a=await WebAssembly.instantiateStreaming(n,s);}else{let l=await t;a=await WebAssembly.instantiate(l,s);}let{instance:l,module:c}=a;r(l,c);}catch(a){console.warn("wasm instantiation failed!"),console.warn(a)}}(),{}}}o(Ne,"getInstantiateWasmFunc");var X="0.29.3";function k(e){return e===void 0||e.endsWith("/")?e:e+"/"}o(k,"withTrailingSlash");var U=X;async function Se(e={}){if(await T(),e.lockFileContents&&e.lockFileURL)throw new Error("Can't pass both lockFileContents and lockFileURL");let t=e.indexURL||await z();if(t=k(_(t)),e.packageBaseUrl=k(e.packageBaseUrl),e.cdnUrl=k(e.packageBaseUrl??`https://cdn.jsdelivr.net/pyodide/v${U}/full/`),!e.lockFileContents){let s=e.lockFileURL??t+"pyodide-lock.json";e.lockFileContents=V(s),e.packageBaseUrl??=J(s)}e.indexURL=t,e.packageCacheDir&&(e.packageCacheDir=k(_(e.packageCacheDir)));let n={fullStdLib:!1,jsglobals:globalThis,stdin:globalThis.prompt?()=>globalThis.prompt():void 0,args:[],env:{},packages:[],packageCacheDir:e.packageBaseUrl,enableRunUntilComplete:!0,checkAPIVersion:!0,BUILD_ID:"b7b7b0f46eb68e65c029c0dc739270e8a5d35251e9aab6014ee1c2f630e5d1d0"},i=Object.assign(n,e);return i.env.HOME??="/home/pyodide",i.env.PYTHONINSPECT??="1",i}o(Se,"initializeConfiguration");function Ie(e){let t=Y(e),n=t.API;return n.lockFilePromise=Promise.resolve(e.lockFileContents),t}o(Ie,"createEmscriptenSettings");async function we(e){if(typeof _createPyodideModule!="function"){let t=`${e.indexURL}pyodide.asm.js`;await w(t)}}o(we,"loadWasmScript");async function _e(e,t){if(!e._loadSnapshot)return;let n=await e._loadSnapshot,i=ArrayBuffer.isView(n)?n:new Uint8Array(n);return t.noInitialRun=!0,t.INITIAL_MEMORY=i.length,i}o(_e,"prepareSnapshot");async function Re(e){let t=await _createPyodideModule(e);if(e.exitCode!==void 0)throw new t.ExitStatus(e.exitCode);return t}o(Re,"createPyodideModule");function ke(e,t){let n=e.API;if(t.pyproxyToStringRepr&&n.setPyProxyToStringMethod(!0),t.convertNullToNone&&n.setCompatNullToNone(!0),t.toJsLiteralMap&&n.setCompatToJsLiteralMap(!0),n.version!==U&&t.checkAPIVersion)throw new Error(`Pyodide version does not match: '${U}' <==> '${n.version}'. If you updated the Pyodide version, make sure you also updated the 'indexURL' parameter passed to loadPyodide.`);e.locateFile=i=>{throw i.endsWith(".so")?new Error(`Failed to find dynamic library "${i}"`):new Error(`Unexpected call to locateFile("${i}")`)}}o(ke,"configureAPI");function Ae(e,t,n){let i=e.API,s;return t&&(s=i.restoreSnapshot(t)),i.finalizeBootstrap(s,n._snapshotDeserializer)}o(Ae,"bootstrapPyodide");async function Fe(e,t){let n=e._api;return n.sys.path.insert(0,""),n._pyodide.set_excepthook(),await n.packageIndexReady,n.initializeStreams(t.stdin,t.stdout,t.stderr),e}o(Fe,"finalizeSetup");async function ct(e={}){let t=await Se(e),n=Ie(t);await we(t);let i=await _e(t,n);let s=await Re(n);ke(s,t);let r=Ae(s,i,t);let a=await Fe(r,t);return a}o(ct,"loadPyodide");export{ct as loadPyodide,U as version}; -//# sourceMappingURL=pyodide.mjs.map diff --git a/crates/execution/assets/pyodide/python_dateutil-2.9.0.post0-py2.py3-none-any.whl b/crates/execution/assets/pyodide/python_dateutil-2.9.0.post0-py2.py3-none-any.whl deleted file mode 100644 index b9a87e998..000000000 Binary files a/crates/execution/assets/pyodide/python_dateutil-2.9.0.post0-py2.py3-none-any.whl and /dev/null differ diff --git a/crates/execution/assets/pyodide/python_stdlib.zip b/crates/execution/assets/pyodide/python_stdlib.zip deleted file mode 100644 index 65150abe8..000000000 Binary files a/crates/execution/assets/pyodide/python_stdlib.zip and /dev/null differ diff --git a/crates/execution/assets/pyodide/pytz-2025.2-py2.py3-none-any.whl b/crates/execution/assets/pyodide/pytz-2025.2-py2.py3-none-any.whl deleted file mode 100644 index e32bd1ab4..000000000 Binary files a/crates/execution/assets/pyodide/pytz-2025.2-py2.py3-none-any.whl and /dev/null differ diff --git a/crates/execution/assets/pyodide/six-1.17.0-py2.py3-none-any.whl b/crates/execution/assets/pyodide/six-1.17.0-py2.py3-none-any.whl deleted file mode 100644 index becf377dc..000000000 Binary files a/crates/execution/assets/pyodide/six-1.17.0-py2.py3-none-any.whl and /dev/null differ diff --git a/crates/execution/assets/runners/python-runner.mjs b/crates/execution/assets/runners/python-runner.mjs deleted file mode 100644 index cbc835b83..000000000 --- a/crates/execution/assets/runners/python-runner.mjs +++ /dev/null @@ -1,2543 +0,0 @@ -import { closeSync, createReadStream, mkdirSync, readFileSync, readSync, writeSync } from 'node:fs'; -import { readFile } from 'node:fs/promises'; -import * as moduleBuiltin from 'node:module'; -import { performance as realPerformance } from 'node:perf_hooks'; -import path from 'node:path'; -import readline from 'node:readline'; -import { URL } from 'node:url'; - -const ACCESS_DENIED_CODE = 'ERR_ACCESS_DENIED'; -const ASSET_ROOT_ENV = 'AGENTOS_NODE_IMPORT_CACHE_ASSET_ROOT'; -const PYODIDE_INDEX_URL_ENV = 'AGENTOS_PYODIDE_INDEX_URL'; -const PYODIDE_PACKAGE_BASE_URL_ENV = 'AGENTOS_PYODIDE_PACKAGE_BASE_URL'; -const PYODIDE_PACKAGE_CACHE_DIR_ENV = 'AGENTOS_PYODIDE_PACKAGE_CACHE_DIR'; -const PYODIDE_PACKAGE_CACHE_GUEST_ROOT = '/__agentos_pyodide_cache'; -const PYTHON_CODE_ENV = 'AGENTOS_PYTHON_CODE'; -const PYTHON_FILE_ENV = 'AGENTOS_PYTHON_FILE'; -const PYTHON_ARGV_ENV = 'AGENTOS_PYTHON_ARGV'; -const PYTHON_MODULE_ENV = 'AGENTOS_PYTHON_MODULE'; -const PYTHON_STDIN_PROGRAM_ENV = 'AGENTOS_PYTHON_STDIN_PROGRAM'; -const PYTHON_INTERACTIVE_ENV = 'AGENTOS_PYTHON_INTERACTIVE'; -const PYTHON_PREWARM_ONLY_ENV = 'AGENTOS_PYTHON_PREWARM_ONLY'; -const PYTHON_WARMUP_DEBUG_ENV = 'AGENTOS_PYTHON_WARMUP_DEBUG'; -const PYTHON_WARMUP_METRICS_PREFIX = '__AGENTOS_PYTHON_WARMUP_METRICS__:'; -const PYTHON_PRELOAD_PACKAGES_ENV = 'AGENTOS_PYTHON_PRELOAD_PACKAGES'; -const PYTHON_VFS_RPC_REQUEST_FD_ENV = 'AGENTOS_PYTHON_VFS_RPC_REQUEST_FD'; -const PYTHON_VFS_RPC_RESPONSE_FD_ENV = 'AGENTOS_PYTHON_VFS_RPC_RESPONSE_FD'; -const PYTHON_RUNTIME_ENV_NAMES = ['HOME', 'USER', 'LOGNAME', 'SHELL', 'PWD', 'TMPDIR', 'PATH']; -const INTERNAL_ENV = globalThis.__agentOSPythonInternalEnv ?? Object.create(null); -const ALLOW_PROCESS_BINDINGS = readRunnerEnv('AGENTOS_ALLOW_PROCESS_BINDINGS') === '1'; -const STDIN_FD = 0; -const SUPPORTED_PRELOAD_PACKAGES = ['numpy', 'pandas']; -const SUPPORTED_PRELOAD_PACKAGE_SET = new Set(SUPPORTED_PRELOAD_PACKAGES); -const DENIED_BUILTINS = new Set([ - 'child_process', - 'cluster', - 'dgram', - 'diagnostics_channel', - 'dns', - 'http', - 'http2', - 'https', - 'inspector', - 'module', - 'net', - 'tls', - 'trace_events', - 'v8', - 'vm', - 'worker_threads', -]); -const originalFetch = - typeof globalThis.fetch === 'function' - ? globalThis.fetch.bind(globalThis) - : null; -const originalRequire = - typeof globalThis.require === 'function' - ? globalThis.require.bind(globalThis) - : null; -const PYTHON_STDIN_DONE_SENTINEL = '__AGENTOS_PYTHON_STDIN_DONE__'; -function canCallBridgeSync(bridge) { - return ( - typeof bridge?.applySyncPromise === 'function' || - typeof bridge?.applySync === 'function' || - typeof bridge === 'function' - ); -} - -function callBridgeSync(bridge, args) { - if (typeof bridge?.applySyncPromise === 'function') { - return bridge.applySyncPromise(void 0, args); - } - if (typeof bridge?.applySync === 'function') { - return bridge.applySync(void 0, args); - } - if (typeof bridge === 'function') { - return bridge(...args); - } - return undefined; -} - -const bridgePythonRpc = - canCallBridgeSync(globalThis._pythonRpc) - ? globalThis._pythonRpc - : null; -const bridgePythonStdinRead = - canCallBridgeSync(globalThis._pythonStdinRead) - ? globalThis._pythonStdinRead - : null; -const bridgeKernelStdinRead = globalThis._kernelStdinRead ?? null; -const bridgeLoadFileSync = - canCallBridgeSync(globalThis._loadFileSync) - ? globalThis._loadFileSync - : null; -const originalGetBuiltinModule = - typeof process.getBuiltinModule === 'function' - ? process.getBuiltinModule.bind(process) - : null; -const CONTROL_PIPE_FD = parseControlPipeFd(readRunnerEnv('AGENTOS_CONTROL_PIPE_FD')); -const register = typeof moduleBuiltin?.register === 'function' ? moduleBuiltin.register.bind(moduleBuiltin) : null; - -function readRunnerEnv(name) { - const internalValue = INTERNAL_ENV[name]; - if (typeof internalValue === 'string') { - return internalValue; - } - return process.env[name]; -} - -function requiredEnv(name) { - const value = readRunnerEnv(name); - if (value == null) { - throw new Error(`${name} is required`); - } - return value; -} - -function parseControlPipeFd(value) { - if (typeof value !== 'string' || value.trim() === '') { - return null; - } - - const parsed = Number.parseInt(value, 10); - return Number.isInteger(parsed) && parsed >= 0 ? parsed : null; -} - -function emitControlMessage(message) { - if (CONTROL_PIPE_FD == null) { - return; - } - - try { - writeSync(CONTROL_PIPE_FD, `${JSON.stringify(message)}\n`); - } catch { - // Ignore control-channel write failures during teardown. - } -} - -function normalizeDirectoryPath(value) { - return value.endsWith(path.sep) ? value : `${value}${path.sep}`; -} - -function pathToFileUrlString(value) { - const normalizedPath = path.resolve(value); - return `file://${normalizedPath.startsWith(path.sep) ? normalizedPath : `${path.sep}${normalizedPath}`}`; -} - -function fileUrlToPathString(value) { - const url = value instanceof URL ? value : new URL(String(value)); - if (url.protocol !== 'file:') { - throw new Error(`Expected file URL, received ${url.protocol}`); - } - return decodeURIComponent(url.pathname); -} - -function resolveIndexLocation(value) { - if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(value)) { - const normalizedUrl = value.endsWith('/') ? value : `${value}/`; - if (!normalizedUrl.startsWith('file:')) { - return { - indexPath: normalizedUrl, - indexUrl: normalizedUrl, - }; - } - - const indexPath = normalizeDirectoryPath(fileUrlToPathString(normalizedUrl)); - return { - indexPath, - indexUrl: pathToFileUrlString(indexPath), - }; - } - - const indexPath = normalizeDirectoryPath(path.resolve(value)); - return { - indexPath, - indexUrl: pathToFileUrlString(indexPath), - }; -} - -function normalizeBaseUrl(value) { - if (typeof value !== 'string' || value.trim() === '') { - throw new Error('package base URL must not be empty'); - } - - if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(value)) { - return value.endsWith('/') ? value : `${value}/`; - } - - return normalizeDirectoryPath(path.resolve(value)); -} - -function normalizePyodideShellPath(value) { - if (typeof value !== 'string') { - throw new Error(`expected shell path to be a string, received ${typeof value}`); - } - - if (value.startsWith('file://')) { - return fileUrlToPathString(value); - } - - if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(value)) { - throw new Error(`unsupported Pyodide shell URL ${value}`); - } - - return value; -} - -function installPyodideShellCompat() { - const originalRead = globalThis.read; - const originalReadbuffer = globalThis.readbuffer; - const originalLoad = globalThis.load; - const originalArguments = globalThis.arguments; - const originalScriptArgs = globalThis.scriptArgs; - const originalPrint = globalThis.print; - const originalPrintErr = globalThis.printErr; - - const shellRead = (target, mode) => { - const normalized = normalizePyodideShellPath(String(target)); - if (mode === 'binary') { - return new Uint8Array(readFileSync(normalized)); - } - return readFileSync(normalized, 'utf8'); - }; - - globalThis.read = shellRead; - globalThis.readbuffer = (target) => new Uint8Array(readFileSync(normalizePyodideShellPath(String(target)))); - globalThis.load = async (target) => { - const normalized = normalizePyodideShellPath(String(target)); - await import(normalized.startsWith('/') ? normalized : pathToFileUrlString(normalized)); - }; - globalThis.arguments = []; - globalThis.scriptArgs = []; - const writeShellStream = (stream, args) => { - const value = args.join(' '); - if (value.trim().length === 0) { - return; - } - writeStream(stream, value); - }; - - globalThis.print = (...args) => writeShellStream(process.stdout, args); - globalThis.printErr = (...args) => writeShellStream(process.stderr, args); - - return () => { - if (originalRead === undefined) { - delete globalThis.read; - } else { - globalThis.read = originalRead; - } - if (originalReadbuffer === undefined) { - delete globalThis.readbuffer; - } else { - globalThis.readbuffer = originalReadbuffer; - } - if (originalLoad === undefined) { - delete globalThis.load; - } else { - globalThis.load = originalLoad; - } - if (originalArguments === undefined) { - delete globalThis.arguments; - } else { - globalThis.arguments = originalArguments; - } - if (originalScriptArgs === undefined) { - delete globalThis.scriptArgs; - } else { - globalThis.scriptArgs = originalScriptArgs; - } - if (originalPrint === undefined) { - delete globalThis.print; - } else { - globalThis.print = originalPrint; - } - if (originalPrintErr === undefined) { - delete globalThis.printErr; - } else { - globalThis.printErr = originalPrintErr; - } - }; -} - -function resolvePyodideResource(indexPath, indexUrl, resourceName) { - if (typeof indexPath === 'string' && path.isAbsolute(indexPath)) { - const resourcePath = path.join(indexPath, resourceName); - return { - path: resourcePath, - url: resourcePath, - }; - } - - const resourceUrl = new URL(resourceName, indexUrl).href; - return { - path: resourceUrl, - url: resourceUrl, - }; -} - -function writeStream(stream, message) { - if (message == null) { - return; - } - - const value = typeof message === 'string' ? message : String(message); - stream.write(value.endsWith('\n') ? value : `${value}\n`); -} - -function writePyodideStdout(message) { - if (message == null) { - return; - } - - const value = typeof message === 'string' ? message : String(message); - const trimmed = value.trim(); - if (trimmed.length === 0) { - return; - } - if ( - trimmed.startsWith('Loading ') || - trimmed.startsWith('Loaded ') || - trimmed.startsWith("Didn't find package ") || - (trimmed.startsWith('Package ') && trimmed.includes(' loaded from ')) - ) { - return; - } - - writeStream(process.stdout, value); -} - -function resolvePyodidePackageCacheDir() { - const configured = readRunnerEnv(PYODIDE_PACKAGE_CACHE_DIR_ENV); - if (typeof configured === 'string' && configured.trim() !== '') { - return path.resolve(configured); - } - - return PYODIDE_PACKAGE_CACHE_GUEST_ROOT; -} - -function emitWarmupStage(stage) { - if (readRunnerEnv(PYTHON_WARMUP_DEBUG_ENV) !== '1') { - return; - } - - writeStream(process.stderr, `__AGENTOS_PYTHON_WARMUP_STAGE__:${stage}`); -} - -function emitPythonDebug(channel, message) { - if (readRunnerEnv(PYTHON_WARMUP_DEBUG_ENV) !== '1') { - return; - } - - writeStream(process.stderr, `__AGENTOS_PYTHON_${channel}__:${message}`); -} - -function formatError(error) { - if (error instanceof Error) { - return error.stack || error.message || String(error); - } - - return String(error); -} - -function wrapPythonStartupError(step, context, error) { - const details = Object.entries(context) - .filter(([, value]) => value != null && value !== '') - .map(([key, value]) => `${key}=${value}`) - .join(', '); - const suffix = details.length > 0 ? ` (${details})` : ''; - return new Error(`Python runtime ${step} failed${suffix}: ${formatError(error)}`); -} - -function normalizeFetchHeaders(headers) { - if (headers == null) { - return {}; - } - - if (headers instanceof Headers) { - return Object.fromEntries(headers.entries()); - } - - if (Array.isArray(headers)) { - return Object.fromEntries(headers); - } - - return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key, String(value)])); -} - -async function normalizeFetchBody(body) { - if (body == null) { - return null; - } - - if (typeof body === 'string') { - return Buffer.from(body).toString('base64'); - } - - if (ArrayBuffer.isView(body)) { - return Buffer.from(body.buffer, body.byteOffset, body.byteLength).toString('base64'); - } - - if (body instanceof ArrayBuffer) { - return Buffer.from(body).toString('base64'); - } - - if (typeof Blob !== 'undefined' && body instanceof Blob) { - return Buffer.from(await body.arrayBuffer()).toString('base64'); - } - - throw new Error('unsupported fetch body type for secure-exec Python package loading'); -} - -function emitPythonStartupMetrics({ - prewarmOnly, - startupMs, - loadPyodideMs, - packageLoadMs, - packageCount, - source, -}) { - if (readRunnerEnv(PYTHON_WARMUP_DEBUG_ENV) !== '1') { - return; - } - - writeStream( - process.stderr, - `${PYTHON_WARMUP_METRICS_PREFIX}${JSON.stringify({ - phase: 'startup', - prewarmOnly, - startupMs, - loadPyodideMs, - packageLoadMs, - packageCount, - source, - })}`, - ); -} - -function parsePreloadPackages(value) { - if (value == null || value.trim() === '') { - return []; - } - - let parsed; - try { - parsed = JSON.parse(value); - } catch (error) { - throw new Error( - `${PYTHON_PRELOAD_PACKAGES_ENV} must be a JSON array of package names: ${formatError(error)}`, - ); - } - - if (!Array.isArray(parsed)) { - throw new Error(`${PYTHON_PRELOAD_PACKAGES_ENV} must be a JSON array of package names`); - } - - const packages = []; - const seen = new Set(); - - for (const entry of parsed) { - if (typeof entry !== 'string') { - throw new Error(`${PYTHON_PRELOAD_PACKAGES_ENV} entries must be strings`); - } - - const name = entry.trim(); - if (name.length === 0) { - throw new Error(`${PYTHON_PRELOAD_PACKAGES_ENV} entries must not be empty`); - } - - if (!SUPPORTED_PRELOAD_PACKAGE_SET.has(name)) { - throw new Error( - `Unsupported bundled Python package "${name}". Available packages: ${SUPPORTED_PRELOAD_PACKAGES.join(', ')}`, - ); - } - - if (!seen.has(name)) { - seen.add(name); - packages.push(name); - } - } - - return packages; -} - -function parseOptionalFd(name) { - const value = readRunnerEnv(name); - if (value == null || value.trim() === '') { - return null; - } - - const fd = Number.parseInt(value, 10); - if (!Number.isInteger(fd) || fd < 0) { - throw new Error(`${name} must be a non-negative integer file descriptor`); - } - - return fd; -} - -function normalizeWriteContent(content) { - if (typeof content === 'string') { - return content; - } - if (ArrayBuffer.isView(content)) { - return Buffer.from(content.buffer, content.byteOffset, content.byteLength).toString('base64'); - } - if (content instanceof ArrayBuffer) { - return Buffer.from(content).toString('base64'); - } - throw new Error('fsWrite requires a base64 string or Uint8Array'); -} - -function rejectPendingRpcRequests(pending, error) { - for (const { reject } of pending.values()) { - reject(error); - } - pending.clear(); -} - -function normalizePythonBridgeError(error) { - const normalized = error instanceof Error ? error : new Error(String(error)); - const message = normalized.message || String(error); - const separatorIndex = message.indexOf(': '); - if (separatorIndex > 0) { - const code = message.slice(0, separatorIndex); - if (/^(?:ERR_[A-Z0-9_]+|E[A-Z0-9_]+)$/.test(code)) { - normalized.code = code; - normalized.message = message.slice(separatorIndex + 2); - } - } - if (typeof normalized.code !== 'string') { - normalized.code = 'ERR_AGENTOS_PYTHON_VFS_RPC'; - } - return normalized; -} - -function createPythonBridgeRpcBridge() { - if (!bridgePythonRpc) { - return null; - } - - function requestSync(method, payload = {}) { - try { - return callBridgeSync(bridgePythonRpc, [{ - method, - ...payload, - }]) ?? {}; - } catch (error) { - throw normalizePythonBridgeError(error); - } - } - - return { - fsReadSync(path) { - const result = requestSync('fsRead', { path }); - return result.contentBase64 ?? ''; - }, - async fsRead(path) { - return this.fsReadSync(path); - }, - fsWriteSync(path, content) { - requestSync('fsWrite', { - path, - contentBase64: normalizeWriteContent(content), - }); - }, - async fsWrite(path, content) { - this.fsWriteSync(path, content); - }, - fsStatSync(path) { - const result = requestSync('fsStat', { path }); - return result.stat ?? null; - }, - async fsStat(path) { - return this.fsStatSync(path); - }, - fsLstatSync(path) { - const result = requestSync('fsLstat', { path }); - return result.stat ?? null; - }, - fsReaddirSync(path) { - const result = requestSync('fsReaddir', { path }); - return result.entries ?? []; - }, - async fsReaddir(path) { - return this.fsReaddirSync(path); - }, - fsMkdirSync(path, options = {}) { - requestSync('fsMkdir', { - path, - recursive: options?.recursive === true, - }); - }, - async fsMkdir(path, options = {}) { - this.fsMkdirSync(path, options); - }, - fsUnlinkSync(path) { - requestSync('fsUnlink', { path }); - }, - fsRmdirSync(path) { - requestSync('fsRmdir', { path }); - }, - fsRenameSync(path, destination) { - requestSync('fsRename', { path, destination }); - }, - fsSymlinkSync(target, path) { - requestSync('fsSymlink', { target, path }); - }, - fsReadlinkSync(path) { - const result = requestSync('fsReadlink', { path }); - return result.target ?? ''; - }, - fsSetattrSync(path, attr) { - requestSync('fsSetattr', { path, ...attr }); - }, - httpRequestSync(url, method = 'GET', headersJson = '{}', bodyBase64 = null) { - let headers; - try { - headers = JSON.parse(headersJson); - } catch (error) { - throw new Error(`invalid Python httpRequest headers JSON: ${formatError(error)}`); - } - return JSON.stringify(requestSync('httpRequest', { - url, - httpMethod: method, - headers, - bodyBase64, - })); - }, - dnsLookupSync(hostname, family = null) { - return JSON.stringify(requestSync('dnsLookup', { hostname, family })); - }, - subprocessRunSync( - command, - argsJson = '[]', - cwd = null, - envJson = '{}', - shell = false, - maxBuffer = null, - ) { - let args; - let env; - try { - args = JSON.parse(argsJson); - env = JSON.parse(envJson); - } catch (error) { - throw new Error(`invalid Python subprocessRun payload JSON: ${formatError(error)}`); - } - return JSON.stringify(requestSync('subprocessRun', { - command, - args, - cwd, - env, - shell, - maxBuffer, - })); - }, - socketConnectSync(host, port) { - return JSON.stringify(requestSync('socketConnect', { hostname: host, port })); - }, - socketSendSync(socketId, dataBase64) { - return JSON.stringify(requestSync('socketSend', { socketId, bodyBase64: dataBase64 })); - }, - socketRecvSync(socketId, maxBuffer) { - return JSON.stringify(requestSync('socketRecv', { socketId, maxBuffer })); - }, - socketCloseSync(socketId) { - return JSON.stringify(requestSync('socketClose', { socketId })); - }, - udpCreateSync() { - return JSON.stringify(requestSync('udpCreate', {})); - }, - udpSendtoSync(socketId, host, port, dataBase64) { - return JSON.stringify( - requestSync('udpSendto', { socketId, hostname: host, port, bodyBase64: dataBase64 }), - ); - }, - udpRecvfromSync(socketId, maxBuffer) { - return JSON.stringify(requestSync('udpRecvfrom', { socketId, maxBuffer })); - }, - dispose() {}, - }; -} - -function createPythonFdRpcBridge() { - const requestFd = parseOptionalFd(PYTHON_VFS_RPC_REQUEST_FD_ENV); - const responseFd = parseOptionalFd(PYTHON_VFS_RPC_RESPONSE_FD_ENV); - - if (requestFd == null && responseFd == null) { - return null; - } - - if (requestFd == null || responseFd == null) { - throw new Error( - `both ${PYTHON_VFS_RPC_REQUEST_FD_ENV} and ${PYTHON_VFS_RPC_RESPONSE_FD_ENV} are required`, - ); - } - - let nextRequestId = 1; - const queuedResponses = new Map(); - let responseBuffer = ''; - - function readResponseLineSync() { - while (true) { - const newlineIndex = responseBuffer.indexOf('\n'); - if (newlineIndex >= 0) { - const line = responseBuffer.slice(0, newlineIndex); - responseBuffer = responseBuffer.slice(newlineIndex + 1); - return line; - } - - const chunk = Buffer.alloc(4096); - const bytesRead = readSync(responseFd, chunk, 0, chunk.length, null); - if (bytesRead === 0) { - throw new Error('secure-exec Python VFS RPC response channel closed unexpectedly'); - } - responseBuffer += chunk.subarray(0, bytesRead).toString('utf8'); - } - } - - function parseResponseLine(line) { - try { - return JSON.parse(line); - } catch (error) { - throw new Error(`invalid secure-exec Python VFS RPC response: ${formatError(error)}`); - } - } - - function waitForResponseSync(id) { - const queued = queuedResponses.get(id); - if (queued) { - queuedResponses.delete(id); - return queued; - } - - while (true) { - const line = readResponseLineSync(); - if (line.trim() === '') { - continue; - } - - const message = parseResponseLine(line); - if (message?.id === id) { - return message; - } - queuedResponses.set(message?.id, message); - } - } - - function requestSync(method, payload = {}) { - const id = nextRequestId++; - writeSync( - requestFd, - `${JSON.stringify({ - id, - method, - ...payload, - })}\n`, - ); - - const message = waitForResponseSync(id); - if (message?.ok) { - return message.result ?? {}; - } - - const error = new Error(message?.error?.message || `secure-exec Python VFS RPC request ${id} failed`); - error.code = message?.error?.code || 'ERR_AGENTOS_PYTHON_VFS_RPC'; - throw error; - } - - function request(method, payload = {}) { - return Promise.resolve().then(() => requestSync(method, payload)); - } - - return { - fsReadSync(path) { - const result = requestSync('fsRead', { path }); - return result.contentBase64 ?? ''; - }, - async fsRead(path) { - return this.fsReadSync(path); - }, - fsWriteSync(path, content) { - requestSync('fsWrite', { - path, - contentBase64: normalizeWriteContent(content), - }); - }, - async fsWrite(path, content) { - this.fsWriteSync(path, content); - }, - fsStatSync(path) { - const result = requestSync('fsStat', { path }); - return result.stat ?? null; - }, - async fsStat(path) { - return this.fsStatSync(path); - }, - fsLstatSync(path) { - const result = requestSync('fsLstat', { path }); - return result.stat ?? null; - }, - fsReaddirSync(path) { - const result = requestSync('fsReaddir', { path }); - return result.entries ?? []; - }, - async fsReaddir(path) { - return this.fsReaddirSync(path); - }, - fsMkdirSync(path, options = {}) { - requestSync('fsMkdir', { - path, - recursive: options?.recursive === true, - }); - }, - async fsMkdir(path, options = {}) { - this.fsMkdirSync(path, options); - }, - fsUnlinkSync(path) { - requestSync('fsUnlink', { path }); - }, - fsRmdirSync(path) { - requestSync('fsRmdir', { path }); - }, - fsRenameSync(path, destination) { - requestSync('fsRename', { path, destination }); - }, - fsSymlinkSync(target, path) { - requestSync('fsSymlink', { target, path }); - }, - fsReadlinkSync(path) { - const result = requestSync('fsReadlink', { path }); - return result.target ?? ''; - }, - fsSetattrSync(path, attr) { - requestSync('fsSetattr', { path, ...attr }); - }, - httpRequestSync(url, method = 'GET', headersJson = '{}', bodyBase64 = null) { - let headers; - try { - headers = JSON.parse(headersJson); - } catch (error) { - throw new Error(`invalid Python httpRequest headers JSON: ${formatError(error)}`); - } - return JSON.stringify(requestSync('httpRequest', { - url, - httpMethod: method, - headers, - bodyBase64, - })); - }, - dnsLookupSync(hostname, family = null) { - return JSON.stringify(requestSync('dnsLookup', { hostname, family })); - }, - subprocessRunSync( - command, - argsJson = '[]', - cwd = null, - envJson = '{}', - shell = false, - maxBuffer = null, - ) { - let args; - let env; - try { - args = JSON.parse(argsJson); - env = JSON.parse(envJson); - } catch (error) { - throw new Error(`invalid Python subprocessRun payload JSON: ${formatError(error)}`); - } - return JSON.stringify(requestSync('subprocessRun', { - command, - args, - cwd, - env, - shell, - maxBuffer, - })); - }, - dispose() { - try { - closeSync(requestFd); - } catch { - // Ignore repeated-close shutdown races. - } - try { - closeSync(responseFd); - } catch { - // Ignore repeated-close shutdown races. - } - }, - }; -} - -function accessDenied(subject) { - const error = new Error(`${subject} is not available in the secure-exec guest Python runtime`); - error.code = ACCESS_DENIED_CODE; - return error; -} - -const PYTHON_GUEST_IMPORT_BLOCKLIST_SOURCE = String.raw` -import builtins as _agentos_builtins -import sys as _agentos_sys -import types as _agentos_types - -try: - import agentos_internal_js as _agentos_safe_js - import agentos_internal_pyodide_js as _agentos_safe_pyodide_js - import agentos_internal_pyodide_js_api as _agentos_safe_pyodide_js_api -except Exception: - _agentos_safe_js = None - _agentos_safe_pyodide_js = None - _agentos_safe_pyodide_js_api = None - -def _agentos_raise_access_denied(module_name): - raise RuntimeError(f"{module_name} is not available in the secure-exec guest Python runtime") - -class _SecureExecBlockedModule(_agentos_types.ModuleType): - def __init__(self, name): - super().__init__(name) - self.__dict__['__all__'] = () - - def __getattr__(self, _name): - _agentos_raise_access_denied(self.__name__) - - def __dir__(self): - return [] - -_agentos_blocked_modules = { - _agentos_module_name: _SecureExecBlockedModule(_agentos_module_name) - for _agentos_module_name in ('js', 'pyodide_js') -} - -_agentos_safe_modules = { - "js": _agentos_safe_js, - "pyodide_js": _agentos_safe_pyodide_js, - "pyodide_js._api": _agentos_safe_pyodide_js_api, -} - -_agentos_original_import = _agentos_builtins.__import__ - -def _agentos_allow_internal_js(globals): - module_name = str((globals or {}).get("__name__", "")) - return module_name.startswith("micropip") or module_name.startswith("pyodide.http") - -def _agentos_import(name, globals=None, locals=None, fromlist=(), level=0): - if name in _agentos_safe_modules and _agentos_safe_modules[name] is not None and _agentos_allow_internal_js(globals): - return _agentos_safe_modules[name] - if name in _agentos_blocked_modules: - return _agentos_blocked_modules[name] - return _agentos_original_import(name, globals, locals, fromlist, level) - -_agentos_builtins.__import__ = _agentos_import -_agentos_sys.modules.update(_agentos_blocked_modules) -`; - -const PYTHON_KERNEL_RPC_SHIMS_SOURCE = String.raw` -import base64 as _agentos_base64 -import json as _agentos_json -import socket as _agentos_socket -import subprocess as _agentos_subprocess -import sys as _agentos_sys -import types as _agentos_types -import urllib.error as _agentos_urllib_error -import urllib.request as _agentos_urllib_request -from email.message import Message as _SecureExecMessage -from js import __agentOSPythonVfsRpc as _agentos_rpc - -def _agentos_raise_from_error(error): - if not isinstance(error, dict): - raise RuntimeError(str(error)) - message = str(error.get("message", "secure-exec Python bridge request failed")) - if "EACCES:" in message: - raise PermissionError(message) - if "command not found" in message: - raise FileNotFoundError(message) - raise OSError(message) - -def _agentos_normalize_family(family): - if family in (None, 0): - return None - if family == _agentos_socket.AF_INET: - return 4 - if family == _agentos_socket.AF_INET6: - return 6 - return None - -def _agentos_dns_lookup(hostname, family=None): - try: - result = _agentos_json.loads( - _agentos_rpc.dnsLookupSync(hostname, _agentos_normalize_family(family)) - ) - except Exception as error: - _agentos_raise_from_error({"message": str(error)}) - addresses = result.get("addresses") or [] - if not addresses: - raise OSError(f"secure-exec DNS lookup returned no addresses for {hostname}") - return addresses - -class _SecureExecHttpResponse: - def __init__(self, payload): - self.status = int(payload.get("status", 0)) - self.reason = str(payload.get("reason", "")) - self.url = str(payload.get("url", "")) - self._body = _agentos_base64.b64decode(payload.get("bodyBase64", "") or "") - headers = payload.get("headers") or {} - self.headers = _SecureExecMessage() - for name, values in headers.items(): - for value in values: - self.headers.add_header(str(name), str(value)) - - def read(self, amt=-1): - if amt is None or amt < 0: - return self._body - return self._body[:amt] - - def getcode(self): - return self.status - - def info(self): - return self.headers - - def close(self): - return None - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc, tb): - self.close() - return False - -class _SecureExecPyfetchResponse: - def __init__(self, payload): - self.status = int(payload.get("status", 0)) - self.status_text = str(payload.get("reason", "")) - self.url = str(payload.get("url", "")) - self.headers = {str(name): ", ".join(values) for name, values in (payload.get("headers") or {}).items()} - self._body = _agentos_base64.b64decode(payload.get("bodyBase64", "") or "") - - async def bytes(self): - return self._body - - async def string(self): - return self._body.decode("utf-8", errors="replace") - - def raise_for_status(self): - if self.status >= 400: - raise RuntimeError(f"{self.status} {self.status_text}") - -def _agentos_extract_request_parts(url_or_request, data=None): - if isinstance(url_or_request, _agentos_urllib_request.Request): - request = url_or_request - url = request.full_url - method = request.get_method() - headers = dict(request.header_items()) - payload = request.data if data is None else data - else: - url = str(url_or_request) - method = "POST" if data is not None else "GET" - headers = {} - payload = data - body_base64 = None - if payload is not None: - if isinstance(payload, str): - payload = payload.encode("utf-8") - body_base64 = _agentos_base64.b64encode(payload).decode("ascii") - return url, method, headers, body_base64 - -def _agentos_http_request(url_or_request, data=None): - url, method, headers, body_base64 = _agentos_extract_request_parts(url_or_request, data) - try: - payload = _agentos_json.loads( - _agentos_rpc.httpRequestSync(url, method, _agentos_json.dumps(headers), body_base64) - ) - except Exception as error: - _agentos_raise_from_error({"message": str(error)}) - response = _SecureExecHttpResponse(payload) - if response.status >= 400: - raise _agentos_urllib_error.HTTPError( - url, - response.status, - response.reason, - response.headers, - response, - ) - return response - -async def _agentos_pyfetch(url, **kwargs): - headers = dict(kwargs.get("headers") or {}) - method = str(kwargs.get("method", "GET")).upper() - body = kwargs.get("body") - if body is not None and isinstance(body, str): - body = body.encode("utf-8") - body_base64 = None if body is None else _agentos_base64.b64encode(body).decode("ascii") - try: - payload = _agentos_json.loads( - _agentos_rpc.httpRequestSync( - str(url), - method, - _agentos_json.dumps(headers), - body_base64, - ) - ) - except Exception as error: - _agentos_raise_from_error({"message": str(error)}) - return _SecureExecPyfetchResponse(payload) - -def _agentos_urlopen(url, data=None, timeout=None, *args, **kwargs): - del timeout, args, kwargs - return _agentos_http_request(url, data=data) - -_agentos_urllib_request.urlopen = _agentos_urlopen - -try: - import pyodide.http as _agentos_pyodide_http -except ModuleNotFoundError: - _agentos_pyodide_http = None -else: - _agentos_pyodide_http.pyfetch = _agentos_pyfetch - -_agentos_original_getaddrinfo = _agentos_socket.getaddrinfo - -def _agentos_getaddrinfo(host, port, family=0, type=0, proto=0, flags=0): - if host in (None, "", "0.0.0.0", "::"): - return _agentos_original_getaddrinfo(host, port, family, type, proto, flags) - addresses = _agentos_dns_lookup(host, family) - socktype = type or _agentos_socket.SOCK_STREAM - protocol = proto or 0 - normalized_family = family or _agentos_socket.AF_INET - results = [] - for address in addresses: - entry_family = _agentos_socket.AF_INET6 if ":" in address else _agentos_socket.AF_INET - if family not in (0, entry_family): - continue - if entry_family == _agentos_socket.AF_INET6: - sockaddr = (address, port, 0, 0) - else: - sockaddr = (address, port) - results.append((entry_family, socktype, protocol, "", sockaddr)) - if not results: - raise OSError(f"secure-exec DNS lookup returned no matching addresses for {host}") - return results - -def _agentos_gethostbyname(host): - return _agentos_dns_lookup(host, _agentos_socket.AF_INET)[0] - -_agentos_socket.getaddrinfo = _agentos_getaddrinfo -_agentos_socket.gethostbyname = _agentos_gethostbyname - -# Raw socket bridge: back socket.socket() with the host (outbound TCP + UDP). -# Reads poll (the host uses a short read timeout) so the synchronous RPC never -# stalls the sidecar; the loop below re-polls to emulate blocking semantics. -import base64 as _agentos_base64 -import time as _agentos_time -import errno as _agentos_errno - -_agentos_original_socket_class = _agentos_socket.socket - -def _agentos_socket_oserror(exc): - # Host errors arrive as "E: message"; recover the errno so Python - # code can catch ConnectionRefusedError/TimeoutError/etc. (OSError picks the - # right subclass from the errno). - message = str(getattr(exc, "message", None) or exc) - head = message.split(":", 1)[0].strip() - code = getattr(_agentos_errno, head, 0) if head[:1] == "E" and head.isupper() else 0 - return OSError(code or 0, message) - -def _agentos_socket_rpc(call): - try: - return _agentos_json.loads(call()) - except OSError: - raise - except Exception as exc: - raise _agentos_socket_oserror(exc) from None - -class _SecureExecSocket: - def __init__(self, family=None, type=None, proto=0, fileno=None): - self.family = family if family is not None else _agentos_socket.AF_INET - self.type = type if type is not None else _agentos_socket.SOCK_STREAM - self.proto = proto - self._timeout = None # None blocks; 0 is non-blocking; >0 is a deadline - self._id = None - self._closed = False - self._is_udp = self.type == _agentos_socket.SOCK_DGRAM - if self._is_udp: - resp = _agentos_socket_rpc(lambda: _agentos_rpc.udpCreateSync()) - self._id = int(resp["socketId"]) - - def connect(self, address): - host, port = address[0], address[1] - resp = _agentos_socket_rpc(lambda: _agentos_rpc.socketConnectSync(str(host), int(port))) - self._id = int(resp["socketId"]) - - def connect_ex(self, address): - try: - self.connect(address) - return 0 - except OSError as exc: - return exc.errno or 1 - - def _ensure_id(self): - if self._id is None: - raise OSError(9, "Bad file descriptor") - return self._id - - def send(self, data, flags=0): - sid = self._ensure_id() - b64 = _agentos_base64.b64encode(bytes(data)).decode("ascii") - resp = _agentos_socket_rpc(lambda: _agentos_rpc.socketSendSync(sid, b64)) - return int(resp.get("bytesSent", len(data))) - - def sendall(self, data, flags=0): - payload = bytes(data) - total = 0 - while total < len(payload): - total += self.send(payload[total:], flags) - return None - - def _poll(self, bufsize, recv_fn): - deadline = None - if self._timeout is not None and self._timeout > 0: - deadline = _agentos_time.monotonic() + self._timeout - backoff = 0.0 - while True: - resp = _agentos_socket_rpc(lambda: recv_fn(int(bufsize))) - if resp.get("closed"): - return b"", resp - data = resp.get("dataBase64") or "" - if data: - return _agentos_base64.b64decode(data), resp - if resp.get("timedOut"): - if self._timeout == 0: - raise BlockingIOError(11, "Resource temporarily unavailable") - if deadline is not None and _agentos_time.monotonic() >= deadline: - raise _agentos_socket.timeout("timed out") - # Guest-side capped backoff so a blocking recv on a silent socket - # doesn't hammer the host loop with back-to-back polls. - if backoff: - _agentos_time.sleep(backoff) - backoff = min(backoff * 2 if backoff else 0.005, 0.05) - continue - return b"", resp - - def recv(self, bufsize, flags=0): - sid = self._ensure_id() - data, _ = self._poll(bufsize, lambda n: _agentos_rpc.socketRecvSync(sid, n)) - return data - - def sendto(self, data, *args): - address = args[-1] - host, port = address[0], address[1] - if self._id is None: - resp = _agentos_socket_rpc(lambda: _agentos_rpc.udpCreateSync()) - self._id = int(resp["socketId"]) - b64 = _agentos_base64.b64encode(bytes(data)).decode("ascii") - resp = _agentos_socket_rpc( - lambda: _agentos_rpc.udpSendtoSync(self._id, str(host), int(port), b64) - ) - return int(resp.get("bytesSent", len(data))) - - def recvfrom(self, bufsize, flags=0): - sid = self._ensure_id() - data, resp = self._poll(bufsize, lambda n: _agentos_rpc.udpRecvfromSync(sid, n)) - addr = (resp.get("host", ""), int(resp.get("port", 0))) if resp else ("", 0) - return data, addr - - def settimeout(self, value): - self._timeout = value - - def gettimeout(self): - return self._timeout - - def setblocking(self, flag): - self._timeout = None if flag else 0.0 - - def setsockopt(self, *args, **kwargs): - return None - - def getsockopt(self, *args, **kwargs): - return 0 - - def fileno(self): - return self._id if self._id is not None else -1 - - def getpeername(self): - return ("", 0) - - def getsockname(self): - return ("0.0.0.0", 0) - - def close(self): - if self._closed: - return - self._closed = True - if self._id is not None: - try: - _agentos_rpc.socketCloseSync(self._id) - except Exception: - pass - self._id = None - - def __enter__(self): - return self - - def __exit__(self, *exc): - self.close() - - def __del__(self): - try: - self.close() - except Exception: - pass - -def _agentos_socket_factory(family=-1, type=-1, proto=0, fileno=None): - fam = family if family != -1 else _agentos_socket.AF_INET - typ = type if type != -1 else _agentos_socket.SOCK_STREAM - if ( - fileno is None - and fam in (_agentos_socket.AF_INET, _agentos_socket.AF_INET6) - and typ in (_agentos_socket.SOCK_STREAM, _agentos_socket.SOCK_DGRAM) - ): - return _SecureExecSocket(fam, typ, proto) - return _agentos_original_socket_class(family, type, proto, fileno) - -_agentos_socket.socket = _agentos_socket_factory - -class _SecureExecRequestsResponse: - def __init__(self, payload): - self.status_code = int(payload.get("status", 0)) - self.reason = str(payload.get("reason", "")) - self.url = str(payload.get("url", "")) - self.headers = {str(name): ", ".join(values) for name, values in (payload.get("headers") or {}).items()} - self.content = _agentos_base64.b64decode(payload.get("bodyBase64", "") or "") - self.encoding = "utf-8" - self.ok = self.status_code < 400 - - @property - def text(self): - return self.content.decode(self.encoding, errors="replace") - - def json(self): - return _agentos_json.loads(self.text) - - def raise_for_status(self): - if self.status_code >= 400: - raise RuntimeError(f"{self.status_code} {self.reason}") - -class _SecureExecRequestsSession: - def request(self, method, url, **kwargs): - headers = dict(kwargs.get("headers") or {}) - data = kwargs.get("data") - if data is not None and isinstance(data, str): - data = data.encode("utf-8") - body_base64 = None if data is None else _agentos_base64.b64encode(data).decode("ascii") - try: - payload = _agentos_json.loads( - _agentos_rpc.httpRequestSync( - str(url), - str(method).upper(), - _agentos_json.dumps(headers), - body_base64, - ) - ) - except Exception as error: - _agentos_raise_from_error({"message": str(error)}) - return _SecureExecRequestsResponse(payload) - - def get(self, url, **kwargs): - return self.request("GET", url, **kwargs) - -def _agentos_install_requests_module(): - module = _agentos_types.ModuleType("requests") - session = _SecureExecRequestsSession - module.Session = session - module.Response = _SecureExecRequestsResponse - module.request = lambda method, url, **kwargs: session().request(method, url, **kwargs) - module.get = lambda url, **kwargs: session().get(url, **kwargs) - module.exceptions = _agentos_types.SimpleNamespace(RequestException=RuntimeError) - _agentos_sys.modules["requests"] = module - -try: - import requests as _agentos_requests -except ModuleNotFoundError: - _agentos_install_requests_module() -else: - _agentos_requests.Session = _SecureExecRequestsSession - _agentos_requests.Response = _SecureExecRequestsResponse - _agentos_requests.request = lambda method, url, **kwargs: _SecureExecRequestsSession().request(method, url, **kwargs) - _agentos_requests.get = lambda url, **kwargs: _SecureExecRequestsSession().get(url, **kwargs) - -class _SecureExecCompletedProcess: - def __init__(self, args, returncode, stdout, stderr): - self.args = args - self.returncode = returncode - self.stdout = stdout - self.stderr = stderr - -def _agentos_subprocess_run(args, *, capture_output=False, check=False, cwd=None, env=None, input=None, shell=False, text=False, encoding="utf-8", errors="strict", stdout=None, stderr=None, timeout=None, **kwargs): - del kwargs, stdout, stderr, timeout - if isinstance(args, (str, bytes)): - command = args.decode("utf-8") if isinstance(args, bytes) else args - argv = [] - else: - values = list(args) - if not values: - raise ValueError("subprocess.run args must not be empty") - command = str(values[0]) - argv = [str(value) for value in values[1:]] - merged_env = dict(env or {}) - resolved_cwd = cwd if cwd is not None else _agentos_os.environ.get("PWD") - if input is not None: - raise NotImplementedError("subprocess.run input is not supported in the secure-exec Python runtime") - try: - payload = _agentos_json.loads( - _agentos_rpc.subprocessRunSync( - command, - _agentos_json.dumps(argv), - resolved_cwd, - _agentos_json.dumps(merged_env), - bool(shell), - ) - ) - except Exception as error: - _agentos_raise_from_error({"message": str(error)}) - stdout_bytes = payload.get("stdout", "").encode("utf-8") - stderr_bytes = payload.get("stderr", "").encode("utf-8") - if text or encoding is not None: - stdout_value = stdout_bytes.decode(encoding or "utf-8", errors=errors) - stderr_value = stderr_bytes.decode(encoding or "utf-8", errors=errors) - else: - stdout_value = stdout_bytes - stderr_value = stderr_bytes - result = _SecureExecCompletedProcess( - args, - int(payload.get("exitCode", 1)), - stdout_value if capture_output else None, - stderr_value if capture_output else None, - ) - if check and result.returncode != 0: - raise _agentos_subprocess.CalledProcessError( - result.returncode, - args, - output=result.stdout, - stderr=result.stderr, - ) - return result - -_agentos_subprocess.run = _agentos_subprocess_run -`; - -function hardenProperty(target, key, value) { - try { - Object.defineProperty(target, key, { - value, - writable: false, - configurable: false, - }); - } catch (error) { - try { - target[key] = value; - if (target[key] === value) { - return; - } - } catch { - // Fall through to the original hardening error. - } - throw new Error(`Failed to harden property ${String(key)}`, { cause: error }); - } -} - -function normalizeBuiltin(specifier) { - if (typeof specifier !== 'string') { - return null; - } - - return specifier.startsWith('node:') ? specifier.slice('node:'.length) : specifier; -} - -function installPythonGuestImportBlocklist(pyodide) { - if (typeof pyodide?.runPython !== 'function') { - return; - } - - pyodide.runPython(PYTHON_GUEST_IMPORT_BLOCKLIST_SOURCE); -} - -function buildPythonRuntimeEnv() { - const runtimeEnv = {}; - for (const name of PYTHON_RUNTIME_ENV_NAMES) { - if (typeof process.env[name] === 'string') { - runtimeEnv[name] = process.env[name]; - } - } - return runtimeEnv; -} - -function installPythonRuntimeEnv(pyodide) { - if (typeof pyodide?.runPython !== 'function') { - return; - } - - const runtimeEnv = buildPythonRuntimeEnv(); - - pyodide.runPython(` -import json as _agentos_json -import os as _agentos_os - -for _agentos_key, _agentos_value in _agentos_json.loads(${JSON.stringify(JSON.stringify(runtimeEnv))}).items(): - _agentos_os.environ[_agentos_key] = _agentos_value -`); -} - -function installPythonKernelRpcShims(pyodide) { - if (typeof pyodide?.runPython !== 'function' || !globalThis.__agentOSPythonVfsRpc) { - return; - } - - pyodide.runPython(PYTHON_KERNEL_RPC_SHIMS_SOURCE); -} - -function installPythonMicropipCompat(pyodide) { - if (typeof pyodide?.registerJsModule !== 'function') { - return; - } - - const abortSignalAny = (signals) => { - const values = Array.from(signals ?? []); - if (typeof AbortSignal?.any === 'function') { - return AbortSignal.any(values); - } - - const controller = new AbortController(); - for (const signal of values) { - if (!signal) { - continue; - } - if (signal.aborted) { - controller.abort(signal.reason); - return controller.signal; - } - signal.addEventListener?.( - 'abort', - () => { - if (!controller.signal.aborted) { - controller.abort(signal.reason); - } - }, - { once: true }, - ); - } - return controller.signal; - }; - - pyodide.registerJsModule('agentos_internal_js', { - AbortController, - AbortSignal, - Object, - Request, - fetch: globalThis.fetch, - }); - const pyodideApiCompat = { - abortSignalAny, - install: pyodide?._api?.install, - loadBinaryFile: pyodide?._api?.loadBinaryFile, - lockfile_info: pyodide?._api?.lockfile_info, - lockfile_packages: pyodide?._api?.lockfile_packages, - }; - pyodide.registerJsModule('agentos_internal_pyodide_js', { - loadedPackages: pyodide.loadedPackages, - loadPackage: pyodide.loadPackage?.bind(pyodide), - lockfileBaseUrl: pyodide?._api?.config?.packageBaseUrl ?? '', - _api: pyodideApiCompat, - }); - pyodide.registerJsModule('agentos_internal_pyodide_js_api', pyodideApiCompat); -} - -function installPythonGuestPreloadHardening(bridge = null) { - if (originalRequire) { - hardenProperty(globalThis, 'require', () => { - throw accessDenied('require'); - }); - } - - if (originalFetch) { - const restrictedFetch = async (resource, init = {}) => { - const request = typeof Request !== 'undefined' && resource instanceof Request ? resource : null; - const candidate = - typeof resource === 'string' - ? resource - : resource instanceof URL - ? resource.href - : request?.url; - - let url; - try { - url = new URL(String(candidate ?? '')); - } catch { - throw accessDenied('network access'); - } - - if (url.protocol === 'data:' || url.protocol === 'file:') { - emitPythonDebug('HTTP_DEBUG', `fetch:passthrough:${url.href}`); - return originalFetch(resource, init); - } - - if ((url.protocol === 'http:' || url.protocol === 'https:') && bridge) { - const method = (init.method ?? request?.method ?? 'GET').toUpperCase(); - const headers = normalizeFetchHeaders(init.headers ?? request?.headers); - const bodyBase64 = await normalizeFetchBody(init.body ?? null); - emitPythonDebug('HTTP_DEBUG', `fetch:start:${method}:${url.href}`); - const payload = JSON.parse( - bridge.httpRequestSync(url.href, method, JSON.stringify(headers), bodyBase64), - ); - emitPythonDebug( - 'HTTP_DEBUG', - `fetch:ok:${payload.status ?? 0}:${url.href}`, - ); - const responseBody = Buffer.from(payload.bodyBase64 ?? '', 'base64'); - return new Response(responseBody, { - status: payload.status, - statusText: payload.reason, - headers: payload.headers ?? {}, - }); - } - - if (url.protocol !== 'data:' && url.protocol !== 'file:') { - throw accessDenied(`network access to ${url.protocol}`); - } - return originalFetch(resource, init); - }; - - try { - hardenProperty(globalThis, 'fetch', restrictedFetch); - } catch { - // The shared JS runtime may have already sealed fetch with its own restrictions. - } - } -} - -function installPythonGuestProcessHardening() { - if (!ALLOW_PROCESS_BINDINGS) { - hardenProperty(process, 'binding', () => { - throw accessDenied('process.binding'); - }); - hardenProperty(process, '_linkedBinding', () => { - throw accessDenied('process._linkedBinding'); - }); - hardenProperty(process, 'dlopen', () => { - throw accessDenied('process.dlopen'); - }); - } - - if (originalGetBuiltinModule) { - hardenProperty(process, 'getBuiltinModule', (specifier) => { - const normalized = normalizeBuiltin(specifier); - if (normalized && DENIED_BUILTINS.has(normalized)) { - throw accessDenied(`node:${normalized}`); - } - return originalGetBuiltinModule(specifier); - }); - } -} - -function installPythonGuestLoaderHooks() { - const assetRoot = readRunnerEnv(ASSET_ROOT_ENV); - if (!assetRoot || !register) { - return; - } - - register(new URL('./loader.mjs', import.meta.url), import.meta.url); -} - -function installPythonVfsRpcBridge() { - const bridge = createPythonBridgeRpcBridge() ?? createPythonFdRpcBridge(); - if (!bridge) { - return null; - } - - hardenProperty(globalThis, '__agentOSPythonVfsRpc', bridge); - return bridge; -} - -function installPythonWorkspaceFs(pyodide, bridge) { - if (!bridge) { - return; - } - - const { FS, ERRNO_CODES } = pyodide; - if (!FS?.mount || !FS?.filesystems?.MEMFS || !ERRNO_CODES) { - return; - } - - const MEMFS = FS.filesystems.MEMFS; - const memfsDirNodeOps = MEMFS.ops_table.dir.node; - const memfsDirStreamOps = MEMFS.ops_table.dir.stream; - const memfsFileNodeOps = MEMFS.ops_table.file.node; - const memfsFileStreamOps = MEMFS.ops_table.file.stream; - const memfsLinkNodeOps = MEMFS.ops_table.link.node; - const workspaceDirStreamOps = memfsDirStreamOps; - - function joinGuestPath(parentPath, name) { - return parentPath === '/' ? `/${name}` : `${parentPath}/${name}`; - } - - function nodeGuestPath(node) { - return node.agentOSGuestPath || node.mount?.mountpoint || '/workspace'; - } - - function createFsError(error) { - if (error instanceof FS.ErrnoError) { - return error; - } - - const diagnostic = `${error?.code || ''} ${error?.message || ''} ${error?.stack || ''}`; - const message = diagnostic.toLowerCase(); - let errno = ERRNO_CODES.EIO; - if (/permission denied|access denied|denied/.test(message)) { - errno = ERRNO_CODES.EACCES; - } else if (/read-only|erofs/.test(message)) { - errno = ERRNO_CODES.EROFS; - } else if (/not a directory|enotdir/.test(message)) { - errno = ERRNO_CODES.ENOTDIR; - } else if (/is a directory|eisdir/.test(message)) { - errno = ERRNO_CODES.EISDIR; - } else if (/exists|already exists|eexist/.test(message)) { - errno = ERRNO_CODES.EEXIST; - } else if (/not found|no such file|enoent/.test(message)) { - errno = ERRNO_CODES.ENOENT; - } - - return new FS.ErrnoError(errno); - } - - function withFsErrors(operation) { - try { - return operation(); - } catch (error) { - throw createFsError(error); - } - } - - function updateNodeFromRemoteStat(node, stat) { - if (!stat) { - throw new FS.ErrnoError(ERRNO_CODES.ENOENT); - } - - node.mode = stat.mode; - node.timestamp = Date.now(); - if (FS.isFile(stat.mode) && !node.agentOSDirty) { - node.agentOSRemoteSize = stat.size; - } - } - - function createWorkspaceNode(parent, name, mode, dev, guestPath) { - const node = MEMFS.createNode(parent, name, mode, dev); - node.agentOSGuestPath = guestPath; - node.agentOSDirty = false; - node.agentOSLoaded = FS.isDir(mode); - node.agentOSRemoteSize = 0; - if (FS.isDir(mode)) { - node.node_ops = workspaceDirNodeOps; - node.stream_ops = workspaceDirStreamOps; - } else if (FS.isLink(mode)) { - node.node_ops = workspaceLinkNodeOps; - } else if (FS.isFile(mode)) { - node.node_ops = workspaceFileNodeOps; - node.stream_ops = workspaceFileStreamOps; - } - return node; - } - - function syncDirectory(node) { - const guestPath = nodeGuestPath(node); - const entries = withFsErrors(() => bridge.fsReaddirSync(guestPath)); - const remoteNames = new Set(entries); - - for (const name of Object.keys(node.contents || {})) { - if (remoteNames.has(name)) { - continue; - } - - const child = node.contents[name]; - if (FS.isDir(child.mode)) { - memfsDirNodeOps.rmdir(node, name); - } else { - memfsDirNodeOps.unlink(node, name); - } - } - - for (const name of entries) { - const childPath = joinGuestPath(guestPath, name); - // lstat (don't follow) so a host symlink is created as a link node. - const stat = withFsErrors(() => bridge.fsLstatSync(childPath)); - const existing = node.contents[name]; - - if (existing) { - const existingIsDir = FS.isDir(existing.mode); - const remoteIsDir = Boolean(stat?.isDirectory); - if (existingIsDir !== remoteIsDir) { - if (existingIsDir) { - memfsDirNodeOps.rmdir(node, name); - } else { - memfsDirNodeOps.unlink(node, name); - } - } else { - existing.agentOSGuestPath = childPath; - updateNodeFromRemoteStat(existing, stat); - if (FS.isFile(existing.mode) && !existing.agentOSDirty) { - existing.agentOSLoaded = false; - } - continue; - } - } - - const mode = stat?.mode ?? (stat?.isDirectory ? 0o040755 : 0o100644); - const child = createWorkspaceNode(node, name, mode, 0, childPath); - updateNodeFromRemoteStat(child, stat); - } - } - - function loadFileContents(node) { - if (node.agentOSDirty) { - return; - } - - const stat = withFsErrors(() => bridge.fsStatSync(nodeGuestPath(node))); - updateNodeFromRemoteStat(node, stat); - const contentBase64 = withFsErrors(() => bridge.fsReadSync(nodeGuestPath(node))); - const bytes = Uint8Array.from(Buffer.from(contentBase64, 'base64')); - node.contents = bytes; - node.usedBytes = bytes.length; - node.agentOSLoaded = true; - node.agentOSRemoteSize = bytes.length; - } - - function persistFile(node) { - const contents = node.contents ? MEMFS.getFileDataAsTypedArray(node) : new Uint8Array(0); - withFsErrors(() => bridge.fsWriteSync(nodeGuestPath(node), contents)); - node.agentOSDirty = false; - node.agentOSLoaded = true; - node.agentOSRemoteSize = contents.length; - node.timestamp = Date.now(); - } - - function makeStat(node, stat) { - const mode = stat?.mode ?? node.mode; - const size = FS.isDir(mode) ? 4096 : (node.agentOSDirty ? node.usedBytes : (stat?.size ?? node.usedBytes ?? 0)); - const timestamp = new Date(node.timestamp || Date.now()); - - return { - dev: 1, - ino: node.id, - mode, - nlink: FS.isDir(mode) ? 2 : 1, - uid: 0, - gid: 0, - rdev: 0, - size, - atime: timestamp, - mtime: timestamp, - ctime: timestamp, - blksize: 4096, - blocks: Math.max(1, Math.ceil(size / 4096)), - }; - } - - function toEpochMs(value) { - if (value == null) return null; - if (typeof value === 'number') return value; - if (typeof value.getTime === 'function') return value.getTime(); - return null; - } - - // Propagate chmod/chown/utimes from an Emscripten `setattr` into the host VFS. - // (size/truncate is handled via the dirty-write path, not here.) - function propagateSetattrToHost(node, attr) { - if (!attr) return; - const payload = {}; - if (attr.mode != null) payload.mode = attr.mode & 0o7777; - // `os.chown(p, uid, -1)` keeps a side; never forward a negative sentinel - // (it would saturate to 0 = root on the host). - if (attr.uid != null && attr.uid >= 0) payload.uid = attr.uid; - if (attr.gid != null && attr.gid >= 0) payload.gid = attr.gid; - const atimeMs = toEpochMs(attr.atime ?? attr.timestamp); - const mtimeMs = toEpochMs(attr.mtime ?? attr.timestamp); - if (atimeMs != null && mtimeMs != null) { - payload.atimeMs = Math.trunc(atimeMs); - payload.mtimeMs = Math.trunc(mtimeMs); - } - if (Object.keys(payload).length === 0) return; - withFsErrors(() => bridge.fsSetattrSync(nodeGuestPath(node), payload)); - } - - const workspaceLinkNodeOps = { - // A symlink node reports itself (lstat semantics), not its target — so use - // the in-memory link mode rather than a host stat (which follows the link). - getattr(node) { - return makeStat(node, null); - }, - setattr(node, attr) { - // Host first: if the host op fails (e.g. read-only root) it throws before - // we mutate the in-isolate node, so the two views stay consistent. - propagateSetattrToHost(node, attr); - memfsLinkNodeOps.setattr(node, attr); - }, - readlink(node) { - return withFsErrors(() => bridge.fsReadlinkSync(nodeGuestPath(node))); - }, - }; - - const workspaceFileNodeOps = { - getattr(node) { - const stat = node.agentOSDirty - ? null - : withFsErrors(() => bridge.fsStatSync(nodeGuestPath(node))); - if (stat) { - updateNodeFromRemoteStat(node, stat); - } - return makeStat(node, stat); - }, - setattr(node, attr) { - // Host first (see link setattr) so a failed host op leaves the in-isolate - // node untouched. - propagateSetattrToHost(node, attr); - memfsFileNodeOps.setattr(node, attr); - if (attr?.size != null) { - node.agentOSDirty = true; - node.agentOSLoaded = true; - } - }, - }; - - const workspaceFileStreamOps = { - llseek(stream, offset, whence) { - return memfsFileStreamOps.llseek(stream, offset, whence); - }, - read(stream, buffer, offset, length, position) { - if (!stream.node.agentOSLoaded && !stream.node.agentOSDirty) { - loadFileContents(stream.node); - } - return memfsFileStreamOps.read(stream, buffer, offset, length, position); - }, - write(stream, buffer, offset, length, position, canOwn) { - if (!stream.node.agentOSLoaded && !stream.node.agentOSDirty) { - loadFileContents(stream.node); - } - const written = memfsFileStreamOps.write(stream, buffer, offset, length, position, canOwn); - stream.node.agentOSDirty = true; - persistFile(stream.node); - return written; - }, - mmap(stream, length, position, prot, flags) { - if (!stream.node.agentOSLoaded && !stream.node.agentOSDirty) { - loadFileContents(stream.node); - } - return memfsFileStreamOps.mmap(stream, length, position, prot, flags); - }, - msync(stream, buffer, offset, length, mmapFlags) { - const result = memfsFileStreamOps.msync(stream, buffer, offset, length, mmapFlags); - stream.node.agentOSDirty = true; - persistFile(stream.node); - return result; - }, - }; - - const workspaceDirNodeOps = { - getattr(node) { - const stat = withFsErrors(() => bridge.fsStatSync(nodeGuestPath(node))); - updateNodeFromRemoteStat(node, stat); - return makeStat(node, stat); - }, - setattr(node, attr) { - // Host first (see link setattr). - propagateSetattrToHost(node, attr); - memfsDirNodeOps.setattr(node, attr); - }, - lookup(parent, name) { - syncDirectory(parent); - try { - return memfsDirNodeOps.lookup(parent, name); - } catch (error) { - if (!(error instanceof FS.ErrnoError) || error.errno !== ERRNO_CODES.ENOENT) { - throw error; - } - - const guestPath = joinGuestPath(nodeGuestPath(parent), name); - // lstat (don't follow) so a directly-looked-up host symlink is a link node. - const stat = withFsErrors(() => bridge.fsLstatSync(guestPath)); - const child = createWorkspaceNode(parent, name, stat.mode, 0, guestPath); - updateNodeFromRemoteStat(child, stat); - return child; - } - }, - mknod(parent, name, mode, dev) { - const guestPath = joinGuestPath(nodeGuestPath(parent), name); - const node = createWorkspaceNode(parent, name, mode, dev, guestPath); - if (FS.isDir(mode)) { - withFsErrors(() => bridge.fsMkdirSync(guestPath, { recursive: false })); - } else if (FS.isFile(mode)) { - node.contents = new Uint8Array(0); - node.usedBytes = 0; - node.agentOSDirty = true; - persistFile(node); - } - return node; - }, - rename(oldNode, newDir, newName) { - const source = nodeGuestPath(oldNode); - const destination = joinGuestPath(nodeGuestPath(newDir), newName); - withFsErrors(() => bridge.fsRenameSync(source, destination)); - // `nodeGuestPath` reads the stored path, so retarget the node before it - // moves in the in-memory tree; children re-derive on the next sync. - oldNode.agentOSGuestPath = destination; - memfsDirNodeOps.rename(oldNode, newDir, newName); - }, - unlink(parent, name) { - withFsErrors(() => - bridge.fsUnlinkSync(joinGuestPath(nodeGuestPath(parent), name)), - ); - if (parent.contents && Object.prototype.hasOwnProperty.call(parent.contents, name)) { - memfsDirNodeOps.unlink(parent, name); - } - }, - rmdir(parent, name) { - withFsErrors(() => - bridge.fsRmdirSync(joinGuestPath(nodeGuestPath(parent), name)), - ); - if (parent.contents && Object.prototype.hasOwnProperty.call(parent.contents, name)) { - memfsDirNodeOps.rmdir(parent, name); - } - }, - readdir(node) { - syncDirectory(node); - return memfsDirNodeOps.readdir(node); - }, - symlink(parent, newName, oldPath) { - const guestPath = joinGuestPath(nodeGuestPath(parent), newName); - withFsErrors(() => bridge.fsSymlinkSync(oldPath, guestPath)); - const node = createWorkspaceNode(parent, newName, 0o120777, 0, guestPath); - node.link = oldPath; - node.usedBytes = oldPath.length; - return node; - }, - }; - - const overlayBackend = { - mount(mount) { - const root = MEMFS.mount(mount); - root.agentOSGuestPath = mount.mountpoint; - root.agentOSDirty = false; - root.agentOSLoaded = true; - root.agentOSRemoteSize = 0; - root.node_ops = workspaceDirNodeOps; - root.stream_ops = workspaceDirStreamOps; - return root; - }, - }; - - function mountVfsAt(guestPath) { - try { - FS.mkdir(guestPath); - } catch (error) { - if (!(error instanceof FS.ErrnoError) || error.errno !== ERRNO_CODES.EEXIST) { - throw error; - } - } - FS.mount(overlayBackend, {}, guestPath); - } - - // Mount the kernel VFS over the VM's real top-level directories so Python sees - // the whole guest filesystem — `/tmp`, `/etc`, `/root`, `/usr`, … — exactly - // like the JS/WASM runtimes and `vm.readFile()`. Pyodide owns a handful of - // paths in its own in-isolate FS; keep those on MEMFS so the interpreter, its - // stdlib, and its devices keep working. - const RESERVED_ROOTS = new Set([ - 'lib', - 'dev', - 'proc', - 'home', - '__agentos_pyodide', - '__agentos_pyodide_cache', - ]); - let rootEntries = []; - try { - rootEntries = bridge.fsReaddirSync('/'); - } catch (error) { - // A nested Python child can't reach the kernel VFS (it gets a recoverable - // "unavailable" error and falls back to the in-isolate FS) — that case is - // expected and quiet. Any other failure means the top-level process lost the - // VM root, which is worth surfacing. - if (!/not available for nested child/.test(String(error?.message ?? error))) { - writeStream( - process.stderr, - `agentos: could not bridge the VM filesystem into Python (${formatError(error)}); only /workspace will be visible\n`, - ); - } - rootEntries = []; - } - for (const name of rootEntries) { - if (RESERVED_ROOTS.has(name)) { - continue; - } - const childPath = `/${name}`; - let isDir = false; - try { - isDir = Boolean(bridge.fsStatSync(childPath)?.isDirectory); - } catch { - isDir = false; - } - if (!isDir) { - continue; - } - try { - mountVfsAt(childPath); - } catch { - // A path Pyodide owns or cannot shadow — skip it rather than abort boot. - } - } - // /workspace stays available for backward compatibility even if the VM root - // does not advertise it. - if (!rootEntries.includes('workspace')) { - mountVfsAt('/workspace'); - } -} - -async function readLockFileContents(indexPath, indexURL) { - const { path: lockFilePath, url: lockFileUrl } = resolvePyodideResource( - indexPath, - indexURL, - 'pyodide-lock.json', - ); - try { - if (typeof lockFilePath === 'string' && lockFilePath.startsWith('/') && bridgeLoadFileSync) { - return callBridgeSync(bridgeLoadFileSync, [lockFilePath]); - } - return await readFile(lockFilePath, 'utf8'); - } catch (error) { - throw wrapPythonStartupError('lock file readFile', { - indexPath, - indexURL, - lockFileUrl, - lockFilePath, - }, error); - } -} - -function installPythonStdin(pyodide) { - if (typeof pyodide?.setStdin !== 'function') { - return; - } - - function readFromKernelStdin(buffer) { - while (true) { - if (bridgePythonStdinRead) { - const response = callBridgeSync(bridgePythonStdinRead, [buffer.length, 100]); - if (response === PYTHON_STDIN_DONE_SENTINEL) { - return 0; - } - - const dataBase64 = typeof response === 'string' ? response : ''; - if (dataBase64.length === 0) { - continue; - } - - const chunk = Buffer.from(dataBase64, 'base64'); - const target = Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength); - chunk.copy(target, 0, 0, Math.min(chunk.length, target.length)); - return Math.min(chunk.length, buffer.length); - } - - const response = callBridgeSync(bridgeKernelStdinRead, [buffer.length, 100]); - if (response?.done) { - return 0; - } - - const dataBase64 = typeof response?.dataBase64 === 'string' ? response.dataBase64 : ''; - if (dataBase64.length === 0) { - continue; - } - - const chunk = Buffer.from(dataBase64, 'base64'); - const target = Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength); - chunk.copy(target, 0, 0, Math.min(chunk.length, target.length)); - return Math.min(chunk.length, buffer.length); - } - } - - pyodide.setStdin({ - isatty: false, - read(buffer) { - if (bridgeKernelStdinRead) { - return readFromKernelStdin(buffer); - } - return readSync(STDIN_FD, buffer, 0, buffer.length, null); - }, - }); -} - -function applyPythonArgv(pyodide) { - const argvJson = readRunnerEnv(PYTHON_ARGV_ENV); - if (argvJson == null) { - return; - } - let argv; - try { - argv = JSON.parse(argvJson); - } catch { - return; - } - if (!Array.isArray(argv)) { - return; - } - const normalized = argv.map((value) => String(value)); - pyodide.globals.set('__agentos_argv', pyodide.toPy(normalized)); - try { - pyodide.runPython('import sys as _agentos_sys_argv\n_agentos_sys_argv.argv = list(__agentos_argv)\ndel _agentos_sys_argv'); - } finally { - pyodide.globals.delete('__agentos_argv'); - } -} - -// Drains the guest stdin stream to EOF and returns it as text. Used for -// `python -` (and piped programs), where stdin IS the program body. -function readProgramFromStdin() { - const chunks = []; - const CHUNK = 65536; - if (bridgePythonStdinRead) { - while (true) { - const response = callBridgeSync(bridgePythonStdinRead, [CHUNK, 100]); - if (response === PYTHON_STDIN_DONE_SENTINEL) { - break; - } - const dataBase64 = typeof response === 'string' ? response : ''; - if (dataBase64.length === 0) { - continue; - } - chunks.push(Buffer.from(dataBase64, 'base64')); - } - } else if (bridgeKernelStdinRead) { - while (true) { - const response = callBridgeSync(bridgeKernelStdinRead, [CHUNK, 100]); - if (response?.done) { - break; - } - const dataBase64 = typeof response?.dataBase64 === 'string' ? response.dataBase64 : ''; - if (dataBase64.length === 0) { - continue; - } - chunks.push(Buffer.from(dataBase64, 'base64')); - } - } else { - const buffer = Buffer.alloc(CHUNK); - while (true) { - let bytesRead = 0; - try { - bytesRead = readSync(STDIN_FD, buffer, 0, buffer.length, null); - } catch { - break; - } - if (bytesRead === 0) { - break; - } - chunks.push(Buffer.from(buffer.subarray(0, bytesRead))); - } - } - return Buffer.concat(chunks).toString('utf8'); -} - -// A persistent, kernel-VFS-backed site-packages. The default Pyodide -// site-packages lives in the per-process in-isolate MEMFS, so anything installed -// there vanishes when the process exits. This directory lives on the VM -// filesystem (via the kernel VFS), so `pip install` survives across separate -// `python` invocations and is visible to other processes — just like a real -// `site-packages`. It is prepended to `sys.path` on every boot. -const PYTHON_VFS_SITE_PACKAGES = '/root/.agentos/site-packages'; - -function installPythonVfsSitePackages(pyodide) { - if (typeof pyodide?.runPython !== 'function') { - return; - } - try { - pyodide.globals.set('__agentos_vfs_site', PYTHON_VFS_SITE_PACKAGES); - pyodide.runPython( - 'import os as _os, sys as _sys\n' + - 'try:\n' + - ' _os.makedirs(__agentos_vfs_site, exist_ok=True)\n' + - ' if __agentos_vfs_site not in _sys.path:\n' + - // Append (not prepend): the stdlib + bundled packages stay first, so - // hot imports resolve from the fast in-isolate FS and only genuinely - // pip-installed packages incur a VFS lookup, and a VFS package can't - // shadow the stdlib. - ' _sys.path.append(__agentos_vfs_site)\n' + - // Best-effort: if the VFS site-packages can't be created (e.g. a - // read-only `/root`), persistence is simply unavailable — pip still - // works in-process. Degrade quietly rather than spam stderr. - 'except OSError:\n' + - ' pass\n' + - 'finally:\n' + - ' del _os, _sys', - ); - } catch (error) { - writeStream(process.stderr, `agentos: VFS site-packages setup failed: ${formatError(error)}\n`); - } finally { - try { - pyodide.globals.delete('__agentos_vfs_site'); - } catch {} - } -} - -// `pip` / `python -m pip`: emulate the common pip CLI via Pyodide's micropip, -// which fetches wheels through the runner's kernel-backed fetch (so egress is -// governed by the VM network policy, never an ambient host fetch). Installed -// packages are copied into the persistent VFS site-packages so they survive the -// per-process interpreter and can be imported by a later `python` invocation. -async function runPythonPip(pyodide) { - pyodide.globals.set('__agentos_vfs_site', PYTHON_VFS_SITE_PACKAGES); - try { - await pyodide.runPythonAsync(` -import os, shutil, site, sys -_agentos_pip_args = sys.argv[1:] -if _agentos_pip_args and _agentos_pip_args[0] == "install": - import micropip - _agentos_pip_pkgs = [a for a in _agentos_pip_args[1:] if not a.startswith("-")] - if not _agentos_pip_pkgs: - print("ERROR: You must give at least one requirement to install", file=sys.stderr) - sys.exit(1) - _agentos_sp = site.getsitepackages()[0] - _agentos_before = set(os.listdir(_agentos_sp)) if os.path.isdir(_agentos_sp) else set() - await micropip.install(_agentos_pip_pkgs) - # Persist whatever micropip extracted into the in-isolate site-packages into - # the VFS-backed site-packages so it survives this process. - os.makedirs(__agentos_vfs_site, exist_ok=True) - _agentos_after = set(os.listdir(_agentos_sp)) if os.path.isdir(_agentos_sp) else set() - for _agentos_name in sorted(_agentos_after - _agentos_before): - _agentos_src = os.path.join(_agentos_sp, _agentos_name) - _agentos_dst = os.path.join(__agentos_vfs_site, _agentos_name) - if os.path.isdir(_agentos_src): - shutil.copytree(_agentos_src, _agentos_dst, dirs_exist_ok=True) - else: - shutil.copy2(_agentos_src, _agentos_dst) - print("Successfully installed " + " ".join(_agentos_pip_pkgs)) -elif _agentos_pip_args and _agentos_pip_args[0] in ("--version", "-V", "version"): - print("pip (agentOS micropip shim)") -elif _agentos_pip_args and _agentos_pip_args[0] == "list": - import micropip - for _agentos_pkg in sorted(micropip.list()): - print(_agentos_pkg) -else: - print("usage: pip install [ ...]", file=sys.stderr) - sys.exit(2) -`); - } finally { - try { - pyodide.globals.delete('__agentos_vfs_site'); - } catch {} - } -} - -// Minimal interactive REPL backed by the kernel stdin stream (sys.stdin via -// setStdin). Prompts use the standard PS1/PS2; EOF on stdin ends the session. -async function runPythonRepl(pyodide) { - await pyodide.runPythonAsync(` -import sys -from code import InteractiveConsole -if not hasattr(sys, "ps1"): - sys.ps1 = ">>> " -if not hasattr(sys, "ps2"): - sys.ps2 = "... " -InteractiveConsole(locals={"__name__": "__main__", "__doc__": None}).interact(banner="", exitmsg="") -`); -} - -function resolvePythonSource(pyodide) { - const filePath = readRunnerEnv(PYTHON_FILE_ENV); - if (filePath != null) { - if (typeof pyodide?.FS?.readFile !== 'function') { - throw new Error(`Pyodide FS.readFile() is required to execute ${filePath}`); - } - - return pyodide.FS.readFile(filePath, { encoding: 'utf8' }); - } - - return requiredEnv(PYTHON_CODE_ENV); -} - -let pythonVfsRpcBridge = null; - -try { - const startupStarted = realPerformance.now(); - emitWarmupStage('startup'); - emitWarmupStage(`python-rpc-bridge:${bridgePythonRpc ? 'on' : 'off'}`); - const { indexPath, indexUrl } = resolveIndexLocation(requiredEnv(PYODIDE_INDEX_URL_ENV)); - const bundledPackageBaseUrl = normalizeBaseUrl(indexPath); - const packageBaseUrl = normalizeBaseUrl( - readRunnerEnv(PYODIDE_PACKAGE_BASE_URL_ENV) ?? bundledPackageBaseUrl, - ); - const packageCacheDir = resolvePyodidePackageCacheDir(); - emitWarmupStage(`package-cache-dir:${packageCacheDir}`); - const prewarmOnly = readRunnerEnv(PYTHON_PREWARM_ONLY_ENV) === '1'; - const preloadPackages = parsePreloadPackages(readRunnerEnv(PYTHON_PRELOAD_PACKAGES_ENV)); - const lockFileContents = await readLockFileContents(indexPath, indexUrl).catch((error) => { - throw wrapPythonStartupError('lock file read', { indexPath, indexUrl }, error); - }); - emitWarmupStage('lock-file-ready'); - const { url: pyodideModuleUrl } = resolvePyodideResource(indexPath, indexUrl, 'pyodide.mjs'); - const restorePyodideShellCompat = installPyodideShellCompat(); - const { loadPyodide } = await import(pyodideModuleUrl).catch((error) => { - throw wrapPythonStartupError('module import', { indexPath, indexUrl, pyodideModuleUrl }, error); - }); - emitWarmupStage('module-imported'); - - if (typeof loadPyodide !== 'function') { - throw new Error(`pyodide.mjs at ${indexUrl} does not export loadPyodide()`); - } - - if (prewarmOnly) { - const stdlibResource = resolvePyodideResource(indexPath, indexUrl, 'python_stdlib.zip'); - const wasmResource = resolvePyodideResource(indexPath, indexUrl, 'pyodide.asm.wasm'); - await readFile(stdlibResource.path); - await readFile(wasmResource.path); - restorePyodideShellCompat(); - emitWarmupStage('prewarm-assets-ready'); - emitPythonStartupMetrics({ - prewarmOnly: true, - startupMs: realPerformance.now() - startupStarted, - loadPyodideMs: 0, - packageLoadMs: 0, - packageCount: 0, - source: 'prewarm', - }); - process.exitCode = 0; - } else { - pythonVfsRpcBridge = installPythonVfsRpcBridge(); - installPythonGuestPreloadHardening(pythonVfsRpcBridge); - mkdirSync(packageCacheDir, { recursive: true }); - emitWarmupStage('before-load-pyodide'); - const loadPyodideStarted = realPerformance.now(); - const pyodide = await loadPyodide({ - indexURL: indexPath, - lockFileContents, - packageBaseUrl: bundledPackageBaseUrl, - packageCacheDir, - env: buildPythonRuntimeEnv(), - stdout: writePyodideStdout, - stderr: (message) => writeStream(process.stderr, message), - }).catch((error) => { - throw wrapPythonStartupError( - 'Pyodide bootstrap', - { - indexPath, - indexUrl, - packageBaseUrl, - bundledPackageBaseUrl, - packageCacheDir, - pyodideModuleUrl, - }, - error, - ); - }); - restorePyodideShellCompat(); - emitWarmupStage('after-load-pyodide'); - const loadPyodideMs = realPerformance.now() - loadPyodideStarted; - let packageLoadMs = 0; - - installPythonStdin(pyodide); - installPythonWorkspaceFs(pyodide, pythonVfsRpcBridge); - installPythonVfsSitePackages(pyodide); - installPythonGuestLoaderHooks(); - if (pyodide?._api?.config) { - pyodide._api.config.packageBaseUrl = bundledPackageBaseUrl; - emitWarmupStage(`pyodide-package-base:${pyodide._api.config.packageBaseUrl}`); - } - const canLoadPackages = typeof pyodide?.loadPackage === 'function'; - if (!canLoadPackages && preloadPackages.length > 0) { - throw new Error('Pyodide loadPackage() is required to preload Python packages'); - } - if (canLoadPackages) { - emitWarmupStage('before-load-micropip'); - await pyodide.loadPackage(['micropip']); - emitWarmupStage('after-load-micropip'); - if (preloadPackages.length > 0) { - emitWarmupStage('before-load-preload-packages'); - const packageLoadStarted = realPerformance.now(); - await pyodide.loadPackage(preloadPackages); - packageLoadMs = realPerformance.now() - packageLoadStarted; - emitWarmupStage('after-load-preload-packages'); - } - } - if (pyodide?._api?.config) { - pyodide._api.config.packageBaseUrl = packageBaseUrl; - emitWarmupStage(`micropip-package-base:${pyodide._api.config.packageBaseUrl}`); - } - installPythonMicropipCompat(pyodide); - installPythonKernelRpcShims(pyodide); - installPythonGuestProcessHardening(); - installPythonGuestImportBlocklist(pyodide); - installPythonRuntimeEnv(pyodide); - applyPythonArgv(pyodide); - const moduleName = readRunnerEnv(PYTHON_MODULE_ENV); - const stdinProgram = readRunnerEnv(PYTHON_STDIN_PROGRAM_ENV) === '1'; - const interactive = readRunnerEnv(PYTHON_INTERACTIVE_ENV) === '1'; - const source = moduleName - ? `module:${moduleName}` - : stdinProgram - ? 'stdin' - : interactive - ? 'repl' - : readRunnerEnv(PYTHON_FILE_ENV) != null - ? 'file' - : 'inline'; - emitPythonStartupMetrics({ - prewarmOnly: false, - startupMs: realPerformance.now() - startupStarted, - loadPyodideMs, - packageLoadMs, - packageCount: preloadPackages.length, - source, - }); - if (moduleName === 'pip') { - await runPythonPip(pyodide); - } else if (moduleName) { - pyodide.globals.set('__agentos_module', moduleName); - try { - await pyodide.runPythonAsync( - 'import runpy\nrunpy.run_module(__agentos_module, run_name="__main__", alter_sys=True)', - ); - } finally { - pyodide.globals.delete('__agentos_module'); - } - } else if (stdinProgram) { - await pyodide.runPythonAsync(readProgramFromStdin()); - } else if (interactive) { - await runPythonRepl(pyodide); - } else { - await pyodide.runPythonAsync(resolvePythonSource(pyodide)); - } - } -} catch (error) { - writeStream(process.stderr, formatError(error)); - process.exitCode = 1; -} finally { - pythonVfsRpcBridge?.dispose(); - emitControlMessage({ type: 'python_exit', exitCode: process.exitCode ?? 0 }); -} -process.exit(process.exitCode ?? 0); diff --git a/crates/execution/assets/runners/wasi-module.js b/crates/execution/assets/runners/wasi-module.js deleted file mode 100644 index baebd6ba7..000000000 --- a/crates/execution/assets/runners/wasi-module.js +++ /dev/null @@ -1,2686 +0,0 @@ -if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule === "undefined") { - // Per-backend host seam (C / convergence): native populates it from its own - // host globals (the `|| __agentOs*` fallbacks below); a non-native backend - // (the browser converged worker) can pre-set `globalThis.__agentOSWasiHost` - // with browser-provided equivalents so this same preview1 runner is shared. - const __agentOSWasiHost = - (typeof globalThis.__agentOSWasiHost === "object" && - globalThis.__agentOSWasiHost) || - {}; - const __agentOSWasiRequireBuiltin = - __agentOSWasiHost.requireBuiltin || - (typeof __agentOSRequireBuiltin !== "undefined" - ? __agentOSRequireBuiltin - : (name) => globalThis.require(name)); - const __agentOSFs = () => __agentOSWasiRequireBuiltin("node:fs"); - const __agentOSPath = () => __agentOSWasiRequireBuiltin("node:path"); - const __agentOSCrypto = () => __agentOSWasiRequireBuiltin("node:crypto"); - // Stdio sync-RPC bridge + fd-handle lookup come from the host seam (a - // non-native backend supplies browser equivalents); native falls back to its - // own host globals so behavior is unchanged. - // Lazy resolvers: the native host globals are populated AFTER this module is - // defined (per-execution), so resolve at call time, not at module-load. - const __agentOSWasiSyncRpc = () => - __agentOSWasiHost.syncRpc || - (typeof globalThis.__agentOSSyncRpc !== "undefined" - ? globalThis.__agentOSSyncRpc - : undefined); - const __agentOSWasiLookupFdHandle = () => - __agentOSWasiHost.lookupFdHandle || - (typeof globalThis.lookupFdHandle === "function" - ? globalThis.lookupFdHandle - : undefined); - const __agentOSWasiErrnoSuccess = 0; - const __agentOSWasiErrnoAcces = 2; - const __agentOSWasiErrnoBadf = 8; - const __agentOSWasiErrnoExist = 20; - const __agentOSWasiErrnoFault = 21; - const __agentOSWasiErrnoInval = 28; - const __agentOSWasiErrnoIo = 29; - const __agentOSWasiErrnoNoent = 44; - const __agentOSWasiErrnoNosys = 52; - const __agentOSWasiErrnoNotdir = 54; - const __agentOSWasiErrnoPipe = 64; - const __agentOSWasiErrnoRofs = 69; - const __agentOSWasiErrnoNotcapable = 76; - const __agentOSWasiErrnoXdev = 18; - const __agentOSWasiFiletypeUnknown = 0; - const __agentOSWasiFiletypeCharacterDevice = 2; - const __agentOSWasiFiletypeDirectory = 3; - const __agentOSWasiFiletypeRegularFile = 4; - const __agentOSWasiFiletypeSymbolicLink = 7; - const __agentOSWasiLookupSymlinkFollow = 1; - const __agentOSWasiOpenCreate = 1; - const __agentOSWasiOpenDirectory = 2; - const __agentOSWasiOpenExclusive = 4; - const __agentOSWasiOpenTruncate = 8; - const __agentOSWasiRightFdRead = 1n << 1n; - const __agentOSWasiRightFdWrite = 1n << 6n; - const __agentOSWasiDefaultRightsBase = 0xffffffffffffffffn; - const __agentOSWasiDefaultRightsInheriting = 0xffffffffffffffffn; - const __agentOSWasiWhenceSet = 0; - const __agentOSWasiWhenceCur = 1; - const __agentOSWasiWhenceEnd = 2; - // Read cap: a non-native backend provides it via the seam; native uses its - // build-substituted constant. The ternary short-circuits so the native-only - // placeholder token is never evaluated when the seam supplies a number. - const __agentOSWasmSyncReadLimitBytes = - typeof __agentOSWasiHost.syncReadLimitBytes === "number" - ? __agentOSWasiHost.syncReadLimitBytes - : __SECURE_EXEC_WASM_SYNC_READ_LIMIT_BYTES__; - const __agentOSKernelStdioSyncRpcEnabled = () => - process?.env?.AGENTOS_WASI_STDIO_SYNC_RPC === "1"; - const __agentOSWasiDebugEnabled = () => process?.env?.AGENTOS_WASM_WASI_DEBUG === "1"; - const __agentOSWasiSyscallCountersEnabled = () => - process?.env?.AGENTOS_WASI_SYSCALL_COUNTERS === "1"; - const __agentOSWasiNow = () => - typeof performance?.now === "function" ? performance.now() : Date.now(); - const __agentOSWasiDebug = (message) => { - if (!__agentOSWasiDebugEnabled() || typeof process?.stderr?.write !== "function") { - return; - } - try { - process.stderr.write(`[secure-exec-wasi] ${message}\n`); - } catch { - // Ignore debug logging failures. - } - }; - - class WASI { - constructor(options = {}) { - this.args = Array.isArray(options.args) ? options.args.map((value) => String(value)) : []; - this.env = - options.env && typeof options.env === "object" - ? Object.fromEntries( - Object.entries(options.env).map(([key, value]) => [String(key), String(value)]), - ) - : {}; - this.preopens = options.preopens && typeof options.preopens === "object" ? options.preopens : {}; - this.returnOnExit = options.returnOnExit === true; - this.instance = null; - this.nextFd = 3; - this.fsModule = null; - this.pathModule = null; - this.fdTable = new Map([ - [0, { kind: "stdin", fdFlags: 0 }], - [1, { kind: "stdout", fdFlags: 0 }], - [2, { kind: "stderr", fdFlags: 0 }], - ]); - this.statCache = new Map(); - this.syscallCountersEnabled = __agentOSWasiSyscallCountersEnabled(); - for (const [guestPath, spec] of Object.entries(this.preopens)) { - const normalized = this._normalizePreopenSpec(spec); - if (!normalized) { - continue; - } - this.fdTable.set(this.nextFd++, { - kind: "preopen", - guestPath: String(guestPath), - hostPath: normalized.hostPath, - readOnly: normalized.readOnly, - rightsBase: normalized.rightsBase, - rightsInheriting: normalized.rightsInheriting, - fdFlags: 0, - }); - } - this.wasiImport = { - args_get: (...args) => this._argsGet(...args), - args_sizes_get: (...args) => this._argsSizesGet(...args), - clock_time_get: (...args) => this._clockTimeGet(...args), - clock_res_get: (...args) => this._clockResGet(...args), - environ_get: (...args) => this._environGet(...args), - environ_sizes_get: (...args) => this._environSizesGet(...args), - fd_close: (...args) => this._fdClose(...args), - fd_fdstat_get: (...args) => this._fdFdstatGet(...args), - fd_fdstat_set_flags: (...args) => this._fdFdstatSetFlags(...args), - fd_filestat_get: (...args) => this._fdFilestatGet(...args), - fd_filestat_set_size: (...args) => this._fdFilestatSetSize(...args), - fd_prestat_dir_name: (...args) => this._fdPrestatDirName(...args), - fd_prestat_get: (...args) => this._fdPrestatGet(...args), - fd_pread: (...args) => this._fdPread(...args), - fd_pwrite: (...args) => this._fdPwrite(...args), - fd_readdir: (...args) => this._fdReaddir(...args), - fd_read: (...args) => this._fdRead(...args), - fd_seek: (...args) => this._fdSeek(...args), - fd_sync: (...args) => this._fdSync(...args), - fd_tell: (...args) => this._fdTell(...args), - fd_write: (...args) => this._fdWrite(...args), - path_create_directory: (...args) => this._pathCreateDirectory(...args), - path_filestat_get: (...args) => this._pathFilestatGet(...args), - path_link: (...args) => this._pathLink(...args), - path_open: (...args) => this._pathOpen(...args), - path_readlink: (...args) => this._pathReadlink(...args), - path_remove_directory: (...args) => this._pathRemoveDirectory(...args), - path_rename: (...args) => this._pathRename(...args), - path_symlink: (...args) => this._pathSymlink(...args), - path_unlink_file: (...args) => this._pathUnlinkFile(...args), - poll_oneoff: (...args) => this._pollOneoff(...args), - proc_exit: (...args) => this._procExit(...args), - random_get: (...args) => this._randomGet(...args), - sched_yield: (...args) => this._schedYield(...args), - }; - this._installSyscallCounterWrappers(); - } - - _fs() { - if (!this.fsModule) { - this.fsModule = __agentOSFs(); - } - return this.fsModule; - } - - _path() { - if (!this.pathModule) { - this.pathModule = __agentOSPath(); - } - return this.pathModule; - } - - _recordWasiSyscallMetric(name, startedAt, details = {}) { - if (!this.syscallCountersEnabled || typeof process?.stderr?.write !== "function") { - return; - } - try { - const elapsedMs = __agentOSWasiNow() - startedAt; - process.stderr.write( - `__AGENTOS_WASI_SYSCALL_METRICS__:${JSON.stringify({ - name, - elapsedMs, - ...details, - })}\n`, - ); - } catch { - // Ignore metrics failures. - } - } - - _measureWasiPhase(name, fn) { - if (!this.syscallCountersEnabled || !this._activeWasiMetric) { - return fn(); - } - const startedAt = __agentOSWasiNow(); - try { - return fn(); - } finally { - const phases = (this._activeWasiMetric.phases ??= {}); - phases[name] = (phases[name] ?? 0) + (__agentOSWasiNow() - startedAt); - } - } - - _installSyscallCounterWrappers() { - if (!this.syscallCountersEnabled) { - return; - } - for (const name of [ - "path_open", - "path_filestat_get", - "fd_filestat_get", - "fd_write", - ]) { - const original = this.wasiImport[name]; - if (typeof original !== "function") { - continue; - } - this.wasiImport[name] = (...args) => { - const startedAt = __agentOSWasiNow(); - const previousMetric = this._activeWasiMetric; - const activeMetric = { name, phases: {} }; - this._activeWasiMetric = activeMetric; - let result; - try { - result = original(...args); - } finally { - this._activeWasiMetric = previousMetric; - } - const details = { - result, - fd: Number(args[0]) >>> 0, - iovsLen: name === "fd_write" ? Number(args[2]) >>> 0 : undefined, - phases: activeMetric.phases, - }; - if (name === "path_filestat_get") { - try { - const target = this._readString(args[2], args[3]); - details.pathLen = target.length; - details.pathKind = target.startsWith("/") - ? "absolute" - : target.includes("/") - ? "relative-nested" - : "relative-child"; - details.pathSample = - target.length > 120 ? `${target.slice(0, 120)}...` : target; - } catch { - // Leave path-shape fields absent if the guest pointer is invalid. - } - } - this._recordWasiSyscallMetric(name, startedAt, { - ...details, - }); - return result; - }; - } - } - - start(instance) { - this.instance = instance; - try { - if (typeof instance?.exports?._start === "function") { - instance.exports._start(); - } - return 0; - } catch (error) { - if (error && error.__agentOSWasiExit === true) { - return Number(error.code) >>> 0; - } - throw error; - } - } - - _memoryView() { - const memory = this.instance?.exports?.memory; - if (!(memory instanceof WebAssembly.Memory)) { - throw new Error("WASI memory export is unavailable"); - } - return new DataView(memory.buffer); - } - - _memoryBytes() { - const memory = this.instance?.exports?.memory; - if (!(memory instanceof WebAssembly.Memory)) { - throw new Error("WASI memory export is unavailable"); - } - return new Uint8Array(memory.buffer); - } - - _boundedIovLength(iovs, iovsLen) { - const view = this._memoryView(); - let length = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - length += view.getUint32(entryOffset + 4, true); - if (length > __agentOSWasmSyncReadLimitBytes) { - throw new RangeError( - `WASI read iov length ${length} exceeds ${__agentOSWasmSyncReadLimitBytes}`, - ); - } - } - return length >>> 0; - } - - // Read-side iov capacity, clamped (not thrown) to the sync read cap. A guest - // may legitimately offer a huge read buffer (e.g. iov_len 0xffffffc0 = "read - // up to ~4GB"); the runner reads only what is available, bounded by the cap, - // so the read allocation/RPC stays bounded without rejecting the read. Writes - // keep using _boundedIovLength (throwing) because their iov length is real - // data that must not be silently truncated. - _boundedReadLength(iovs, iovsLen) { - const view = this._memoryView(); - let length = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - length += view.getUint32(entryOffset + 4, true); - if (length >= __agentOSWasmSyncReadLimitBytes) { - return __agentOSWasmSyncReadLimitBytes; - } - } - return length >>> 0; - } - - _normalizeRights(value, fallback) { - try { - return BigInt.asUintN(64, BigInt(value)); - } catch { - return fallback; - } - } - - _normalizePreopenSpec(value) { - // Path-model seam (convergence item C): native maps guest paths to HOST - // paths (its preopen specs carry `hostPath`); a non-native backend with no - // host paths (the browser, whose `require("fs")` IS the kernel VFS) can - // supply `__agentOSWasiHost.normalizePreopen` to treat the guest/VFS path - // as the "hostPath" identity, so the same runner serves both. - if (typeof __agentOSWasiHost.normalizePreopen === "function") { - const seamNormalized = __agentOSWasiHost.normalizePreopen(value, { - defaultRightsBase: __agentOSWasiDefaultRightsBase, - defaultRightsInheriting: __agentOSWasiDefaultRightsInheriting, - normalizeRights: (rights, fallback) => - this._normalizeRights(rights, fallback), - }); - return seamNormalized ?? null; - } - if (typeof value === "string") { - return { - hostPath: String(value), - readOnly: false, - rightsBase: __agentOSWasiDefaultRightsBase, - rightsInheriting: __agentOSWasiDefaultRightsInheriting, - }; - } - if (!value || typeof value !== "object" || typeof value.hostPath !== "string") { - return null; - } - return { - hostPath: String(value.hostPath), - readOnly: value.readOnly === true, - rightsBase: this._normalizeRights( - value.rightsBase, - __agentOSWasiDefaultRightsBase, - ), - rightsInheriting: this._normalizeRights( - value.rightsInheriting, - __agentOSWasiDefaultRightsInheriting, - ), - }; - } - - _descriptorRightsBase(entry) { - return this._normalizeRights( - entry?.rightsBase, - __agentOSWasiDefaultRightsBase, - ); - } - - _descriptorRightsInheriting(entry) { - return this._normalizeRights( - entry?.rightsInheriting, - __agentOSWasiDefaultRightsInheriting, - ); - } - - _hasWriteRights(rights) { - try { - return (BigInt(rights) & __agentOSWasiRightFdWrite) !== 0n; - } catch { - return true; - } - } - - _writeUint32(ptr, value) { - try { - this._memoryView().setUint32(Number(ptr) >>> 0, Number(value) >>> 0, true); - return __agentOSWasiErrnoSuccess; - } catch { - __agentOSWasiDebug(`writeUint32 failed ptr=${Number(ptr)} value=${Number(value)}`); - return __agentOSWasiErrnoFault; - } - } - - _writeUint64(ptr, value) { - try { - this._memoryView().setBigUint64(Number(ptr) >>> 0, BigInt(value), true); - return __agentOSWasiErrnoSuccess; - } catch { - __agentOSWasiDebug(`writeUint64 failed ptr=${Number(ptr)} value=${String(value)}`); - return __agentOSWasiErrnoFault; - } - } - - _writeBytes(ptr, bytes) { - try { - this._memoryBytes().set(bytes, Number(ptr) >>> 0); - return __agentOSWasiErrnoSuccess; - } catch { - __agentOSWasiDebug(`writeBytes failed ptr=${Number(ptr)} len=${bytes?.length ?? 0}`); - return __agentOSWasiErrnoFault; - } - } - - _readBytes(ptr, len) { - const start = Number(ptr) >>> 0; - const end = start + (Number(len) >>> 0); - return Buffer.from(this._memoryBytes().slice(start, end)); - } - - _readString(ptr, len) { - return this._readBytes(ptr, len).toString("utf8"); - } - - _decodeSyncRpcBytes(value) { - if (value == null) { - return null; - } - if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) { - return value; - } - if (value instanceof Uint8Array) { - return Buffer.from(value); - } - if (ArrayBuffer.isView(value)) { - return Buffer.from(value.buffer, value.byteOffset, value.byteLength); - } - if (value instanceof ArrayBuffer) { - return Buffer.from(value); - } - if ( - value && - typeof value === "object" && - value.__agentOSType === "bytes" && - typeof value.base64 === "string" - ) { - return Buffer.from(value.base64, "base64"); - } - return null; - } - - _dequeuePipeBytes(pipe, maxBytes) { - if (!pipe || !Array.isArray(pipe.chunks) || pipe.chunks.length === 0) { - return Buffer.alloc(0); - } - - let remaining = Math.max(0, Number(maxBytes) >>> 0); - if (remaining === 0) { - return Buffer.alloc(0); - } - - const parts = []; - while (remaining > 0 && pipe.chunks.length > 0) { - const chunk = pipe.chunks[0]; - if (!chunk || chunk.length === 0) { - pipe.chunks.shift(); - continue; - } - - if (chunk.length <= remaining) { - parts.push(chunk); - pipe.chunks.shift(); - remaining -= chunk.length; - continue; - } - - parts.push(chunk.subarray(0, remaining)); - pipe.chunks[0] = chunk.subarray(remaining); - remaining = 0; - } - - return Buffer.concat(parts); - } - - _enqueuePipeBytes(pipe, bytes) { - if (!pipe || !Array.isArray(pipe.chunks)) { - return; - } - const chunk = Buffer.from(bytes ?? []); - if (chunk.length === 0) { - return; - } - pipe.chunks.push(chunk); - } - - _pipeHasReaders(pipe) { - return ( - (pipe?.readHandleCount ?? 0) > 0 || - (pipe?.consumers?.size ?? 0) > 0 - ); - } - - _flushPipeConsumers(pipe) { - if ( - !pipe || - typeof pipe.consumers?.entries !== "function" || - !Array.isArray(pipe.chunks) || - pipe.chunks.length === 0 || - typeof globalThis?.__agentOSSyncRpc?.callSync !== "function" - ) { - return false; - } - - let flushed = false; - while (pipe.chunks.length > 0) { - const chunk = pipe.chunks.shift(); - if (!chunk || chunk.length === 0) { - continue; - } - - for (const [consumerKey, consumer] of Array.from(pipe.consumers.entries())) { - if (!consumer || typeof consumer.childId !== "string") { - pipe.consumers.delete(consumerKey); - continue; - } - try { - __agentOSWasiSyncRpc().callSync("child_process.write_stdin", [ - consumer.childId, - chunk, - ]); - flushed = true; - } catch { - pipe.consumers.delete(consumerKey); - } - } - } - - return flushed; - } - - _closePipeConsumers(pipe) { - if ( - !pipe || - typeof pipe.consumers?.entries !== "function" || - typeof globalThis?.__agentOSSyncRpc?.callSync !== "function" - ) { - return false; - } - - let closed = false; - for (const [consumerKey, consumer] of Array.from(pipe.consumers.entries())) { - if (!consumer || typeof consumer.childId !== "string") { - pipe.consumers.delete(consumerKey); - continue; - } - try { - __agentOSWasiSyncRpc().callSync("child_process.close_stdin", [ - consumer.childId, - ]); - closed = true; - } catch { - // Ignore close errors during teardown. - } - pipe.consumers.delete(consumerKey); - } - - return closed; - } - - _pumpPipeProducers(pipe, waitMs) { - if ( - !pipe || - typeof pipe.producers?.entries !== "function" || - typeof globalThis?.__agentOSSyncRpc?.callSync !== "function" - ) { - return false; - } - - let processed = false; - for (const [producerKey, producer] of Array.from(pipe.producers.entries())) { - if (!producer || typeof producer.childId !== "string") { - pipe.producers.delete(producerKey); - continue; - } - - let event = null; - try { - event = __agentOSWasiSyncRpc().callSync("child_process.poll", [ - producer.childId, - Math.max(0, Number(waitMs) >>> 0), - ]); - } catch { - pipe.producers.delete(producerKey); - continue; - } - - if (!event) { - continue; - } - - processed = true; - const streamType = - producer.stream === "stderr" ? "stderr" : producer.stream === "stdout" ? "stdout" : null; - if ((event.type === "stdout" || event.type === "stderr") && event.type === streamType) { - const chunk = this._decodeSyncRpcBytes(event.data); - if (chunk && chunk.length > 0) { - pipe.chunks.push(Buffer.from(chunk)); - } - continue; - } - - if (event.type === "exit") { - pipe.producers.delete(producerKey); - if (pipe.producers.size === 0 && (pipe.writeHandleCount ?? 0) === 0) { - this._closePipeConsumers(pipe); - } - continue; - } - } - - return processed; - } - - _collectIovs(iovs, iovsLen) { - const totalLength = this._boundedIovLength(iovs, iovsLen); - const view = this._memoryView(); - const chunks = []; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - const ptr = view.getUint32(entryOffset, true); - const len = view.getUint32(entryOffset + 4, true); - chunks.push(this._readBytes(ptr, len)); - } - return Buffer.concat(chunks, totalLength); - } - - _writeToIovs(iovs, iovsLen, bytes) { - const view = this._memoryView(); - const memory = this._memoryBytes(); - let sourceOffset = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0) && sourceOffset < bytes.length; index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - const ptr = view.getUint32(entryOffset, true); - const len = view.getUint32(entryOffset + 4, true); - const chunk = bytes.subarray(sourceOffset, sourceOffset + len); - memory.set(chunk, Number(ptr) >>> 0); - sourceOffset += chunk.length; - } - return sourceOffset; - } - - _stringTable(values) { - return values.map((value) => Buffer.from(`${String(value)}\0`, "utf8")); - } - - _writeStringTable(values, offsetsPtr, bufferPtr) { - try { - const view = this._memoryView(); - const memory = this._memoryBytes(); - let cursor = Number(bufferPtr) >>> 0; - for (let index = 0; index < values.length; index += 1) { - const bytes = values[index]; - view.setUint32((Number(offsetsPtr) >>> 0) + index * 4, cursor, true); - memory.set(bytes, cursor); - cursor += bytes.length; - } - return __agentOSWasiErrnoSuccess; - } catch { - __agentOSWasiDebug( - `writeStringTable failed offsetsPtr=${Number(offsetsPtr)} bufferPtr=${Number(bufferPtr)} count=${values.length}`, - ); - return __agentOSWasiErrnoFault; - } - } - - _filetypeForStats(stats) { - if (!stats) { - return __agentOSWasiFiletypeUnknown; - } - const mode = Number(stats.mode); - if (Number.isFinite(mode)) { - switch (mode & 0o170000) { - case 0o040000: - return __agentOSWasiFiletypeDirectory; - case 0o100000: - return __agentOSWasiFiletypeRegularFile; - case 0o120000: - return __agentOSWasiFiletypeSymbolicLink; - case 0o020000: - return __agentOSWasiFiletypeCharacterDevice; - } - } - if (stats.isDirectory === true) { - return __agentOSWasiFiletypeDirectory; - } - if (stats.isSymbolicLink === true) { - return __agentOSWasiFiletypeSymbolicLink; - } - if (typeof stats.isDirectory === "function" && stats.isDirectory()) { - return __agentOSWasiFiletypeDirectory; - } - if (typeof stats.isFile === "function" && stats.isFile()) { - return __agentOSWasiFiletypeRegularFile; - } - if (typeof stats.isSymbolicLink === "function" && stats.isSymbolicLink()) { - return __agentOSWasiFiletypeSymbolicLink; - } - if (typeof stats.isCharacterDevice === "function" && stats.isCharacterDevice()) { - return __agentOSWasiFiletypeCharacterDevice; - } - if (stats.isDirectory === false && stats.isSymbolicLink === false) { - return __agentOSWasiFiletypeRegularFile; - } - return __agentOSWasiFiletypeUnknown; - } - - _filetypeForDirent(dirent) { - if (!dirent || typeof dirent !== "object") { - return __agentOSWasiFiletypeUnknown; - } - if (typeof dirent.isDirectory === "function" && dirent.isDirectory()) { - return __agentOSWasiFiletypeDirectory; - } - if (typeof dirent.isFile === "function" && dirent.isFile()) { - return __agentOSWasiFiletypeRegularFile; - } - if (typeof dirent.isSymbolicLink === "function" && dirent.isSymbolicLink()) { - return __agentOSWasiFiletypeSymbolicLink; - } - if (typeof dirent.isCharacterDevice === "function" && dirent.isCharacterDevice()) { - return __agentOSWasiFiletypeCharacterDevice; - } - return __agentOSWasiFiletypeUnknown; - } - - _clearStatCache() { - this.statCache?.clear?.(); - } - - _statCacheKey(resolved, follow) { - const path = typeof resolved?.guestPath === "string" - ? resolved.guestPath - : this._resolvedFsPath(resolved); - return typeof path === "string" ? `${follow ? "stat" : "lstat"}:${path}` : null; - } - - _fdFiletype(entry) { - if (!entry) { - return __agentOSWasiFiletypeUnknown; - } - if ( - entry.kind === "stdin" || - entry.kind === "stdout" || - entry.kind === "stderr" - ) { - return __agentOSWasiFiletypeCharacterDevice; - } - if (entry.kind === "preopen" || entry.kind === "directory") { - return __agentOSWasiFiletypeDirectory; - } - if (entry.kind === "symlink") { - return __agentOSWasiFiletypeSymbolicLink; - } - return __agentOSWasiFiletypeRegularFile; - } - - _mapFsError(error) { - switch (error?.code) { - case "EACCES": - case "EPERM": - return __agentOSWasiErrnoAcces; - case "ENOENT": - return __agentOSWasiErrnoNoent; - case "ENOTDIR": - return __agentOSWasiErrnoNotdir; - case "EEXIST": - return __agentOSWasiErrnoExist; - case "EINVAL": - return __agentOSWasiErrnoInval; - case "EROFS": - return __agentOSWasiErrnoRofs; - case "EXDEV": - return __agentOSWasiErrnoXdev; - default: - return __agentOSWasiErrnoIo; - } - } - - _descriptorEntry(fd) { - return this.fdTable.get(Number(fd) >>> 0) ?? null; - } - - _localFdHandle(fd) { - // A non-native backend whose `realFd` values are not real host OS fds with - // their own kernel offset (the browser, whose fs descriptors are a JS - // handle table) disables local-fd passthrough so locally-opened files use - // the offset-aware file branches (fd_read/fd_write pass the tracked - // entry.offset as an explicit position) instead of host-passthrough reads - // that rely on a null position advancing a real fd. Native keeps passthrough - // so guest-opened fds can be shared with child processes. - if (__agentOSWasiHost.disableLocalFdPassthrough === true) { - return null; - } - const descriptor = Number(fd) >>> 0; - const entry = this._descriptorEntry(descriptor); - if (!entry || typeof entry.realFd !== "number") { - return null; - } - return { - kind: "host-passthrough", - targetFd: entry.realFd, - displayFd: Number(fd) >>> 0, - refCount: 1, - open: true, - readOnly: entry.readOnly === true, - }; - } - - _externalFdHandle(fd) { - const descriptor = Number(fd) >>> 0; - const localHandle = this._localFdHandle(descriptor); - if (localHandle) { - return localHandle; - } - try { - if (typeof lookupFdHandle === "function") { - return lookupFdHandle(descriptor) ?? null; - } - } catch { - // Fall through to other lookup paths. - } - try { - const __agentOSWasiFdHandleFn = __agentOSWasiLookupFdHandle(); - if (typeof __agentOSWasiFdHandleFn === "function") { - return __agentOSWasiFdHandleFn(descriptor) ?? null; - } - } catch { - // Ignore missing global bridge helpers. - } - return null; - } - - _descriptorHostPath(entry) { - if (!entry) { - return null; - } - if (typeof entry.hostPath === "string") { - return entry.hostPath; - } - if (typeof entry.realFd === "number") { - return __agentOSFs().readlinkSync(`/proc/self/fd/${entry.realFd}`); - } - return null; - } - - _descriptorFsPath(entry) { - if (!entry) { - return null; - } - if (typeof entry.hostPath === "string" && entry.hostPath.length > 0) { - return entry.hostPath; - } - if (typeof entry.guestPath === "string" && entry.guestPath.length > 0) { - return entry.guestPath; - } - return null; - } - - _sidecarManagedProcess() { - if ( - typeof globalThis.__agentOSWasmInternalEnv?.AGENTOS_SANDBOX_ROOT === - "string" && - globalThis.__agentOSWasmInternalEnv.AGENTOS_SANDBOX_ROOT.length > 0 - ) { - return true; - } - return ( - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0 - ); - } - - _descriptorDirectoryFsPath(entry) { - if ( - (entry?.kind === "preopen" || entry?.kind === "directory") && - this._sidecarManagedProcess() - ) { - return this._descriptorGuestPath(entry); - } - return this._descriptorFsPath(entry); - } - - _descriptorGuestPath(entry) { - if (!entry) { - return null; - } - const guestPath = typeof entry.guestPath === "string" ? entry.guestPath : null; - if (guestPath === ".") { - return this._currentGuestCwd(); - } - if (typeof guestPath === "string" && guestPath.length > 0) { - return __agentOSPath().posix.normalize(guestPath); - } - return null; - } - - _descriptorPreopenName(entry) { - if (!entry) { - return null; - } - const guestPath = typeof entry.guestPath === "string" ? entry.guestPath : null; - if (guestPath === ".") { - return this._descriptorGuestPath(entry); - } - if (typeof guestPath === "string" && guestPath.length > 0) { - return __agentOSPath().posix.normalize(guestPath); - } - return null; - } - - _currentDirectoryPreopen() { - for (const entry of this.fdTable.values()) { - if (entry?.kind === "preopen" && entry.guestPath === ".") { - return entry; - } - } - return null; - } - - _descriptorPathBase(entry, target) { - const baseGuestPath = this._descriptorGuestPath(entry); - if (typeof baseGuestPath !== "string") { - return null; - } - return { - entry, - guestPath: baseGuestPath, - hostPath: typeof entry?.hostPath === "string" ? entry.hostPath : null, - }; - } - - _hostPathExists(hostPath) { - return this._measureWasiPhase("hostPathExists", () => { - try { - __agentOSFs().statSync(hostPath); - return true; - } catch { - return false; - } - }); - } - - _createParentExists(guestPath, hostPath) { - const target = - this._sidecarManagedProcess() && typeof guestPath === "string" - ? guestPath - : hostPath; - if (typeof target !== "string") { - return false; - } - return this._measureWasiPhase("createParentExists", () => { - try { - __agentOSFs().statSync(__agentOSPath().dirname(target)); - return true; - } catch { - return false; - } - }); - } - - _currentGuestCwd() { - const pwd = - typeof this.env?.PWD === "string" && this.env.PWD.startsWith("/") - ? this.env.PWD - : typeof this.env?.HOME === "string" && this.env.HOME.startsWith("/") - ? this.env.HOME - : "/"; - return __agentOSPath().posix.normalize(pwd); - } - - _resolveHostMappingForGuestPath(guestPath) { - return this._measureWasiPhase("resolveHostMapping", () => { - const normalized = __agentOSPath().posix.normalize(guestPath); - const mappings = []; - for (const entry of this.fdTable.values()) { - if (entry?.kind !== "preopen" || typeof entry.hostPath !== "string") { - continue; - } - const guestRoot = this._descriptorGuestPath(entry); - if (typeof guestRoot !== "string") { - continue; - } - mappings.push({ - guestRoot, - hostPath: entry.hostPath, - readOnly: entry.readOnly === true, - }); - } - mappings.sort((left, right) => right.guestRoot.length - left.guestRoot.length); - - for (const mapping of mappings) { - const matchesRoot = mapping.guestRoot === "/" && normalized.startsWith("/"); - const matchesNested = - normalized === mapping.guestRoot || - normalized.startsWith(`${mapping.guestRoot}/`); - if (!matchesRoot && !matchesNested) { - continue; - } - const suffix = - normalized === mapping.guestRoot - ? "" - : mapping.guestRoot === "/" - ? normalized.slice(1) - : normalized.slice(mapping.guestRoot.length + 1); - return { - hostPath: suffix - ? __agentOSPath().join(mapping.hostPath, ...suffix.split("/")) - : mapping.hostPath, - readOnly: mapping.readOnly, - }; - } - - return null; - }); - } - - _resolveHostPathForGuestPath(guestPath) { - return this._resolveHostMappingForGuestPath(guestPath)?.hostPath ?? null; - } - - _rootRelativeTargetPrefersCwd(target) { - const normalizedTarget = __agentOSPath().posix.normalize(target || "."); - if (normalizedTarget !== ".") { - return false; - } - return !this._rootRelativeTargetMatchesAbsoluteArg(target); - } - - _rootRelativeTargetMatchesAbsoluteArg(target) { - const rootGuestPath = __agentOSPath().posix.resolve("/", target); - return this.args - .slice(1) - .some( - (arg) => - typeof arg === "string" && - arg.startsWith("/") && - __agentOSPath().posix.normalize(arg) === rootGuestPath, - ); - } - - _rootRelativeTargetIsWithinAbsoluteArg(target) { - const rootGuestPath = __agentOSPath().posix.resolve("/", target); - return this.args - .slice(1) - .some((arg) => { - if (typeof arg !== "string" || !arg.startsWith("/")) { - return false; - } - const normalizedArg = __agentOSPath().posix.normalize(arg); - return ( - rootGuestPath === normalizedArg || - rootGuestPath.startsWith(`${normalizedArg}/`) - ); - }); - } - - _resolveRootRelativePath(target, preferCreateParent = false) { - const rootGuestPath = __agentOSPath().posix.resolve("/", target); - const rootMapping = this._resolveHostMappingForGuestPath(rootGuestPath); - const rootHostPath = rootMapping?.hostPath ?? null; - const cwdGuestPath = this._currentGuestCwd(); - if (cwdGuestPath !== "/") { - const cwdGuestTarget = __agentOSPath().posix.resolve(cwdGuestPath, target); - const cwdMapping = this._resolveHostMappingForGuestPath(cwdGuestTarget); - const cwdHostTarget = cwdMapping?.hostPath ?? null; - if ( - typeof cwdHostTarget === "string" && - ( - ( - preferCreateParent && - !this._rootRelativeTargetIsWithinAbsoluteArg(target) && - this._createParentExists(cwdGuestTarget, cwdHostTarget) - ) || - this._rootRelativeTargetPrefersCwd(target) || - ( - this._hostPathExists(cwdHostTarget) && - !(typeof rootHostPath === "string" && this._hostPathExists(rootHostPath)) - ) - ) - ) { - return { - guestPath: cwdGuestTarget, - hostPath: cwdHostTarget, - readOnly: cwdMapping?.readOnly === true, - }; - } - } - return { - guestPath: rootGuestPath, - hostPath: rootHostPath, - readOnly: rootMapping?.readOnly === true, - }; - } - - _resolveAbsolutePath(target, preferCreateParent = false) { - const rootGuestPath = __agentOSPath().posix.normalize(target); - const rootMapping = this._resolveHostMappingForGuestPath(rootGuestPath); - const rootHostPath = rootMapping?.hostPath ?? null; - const cwdGuestPath = this._currentGuestCwd(); - if ( - cwdGuestPath !== "/" && - !this._rootRelativeTargetIsWithinAbsoluteArg(target) - ) { - const cwdGuestTarget = __agentOSPath().posix.resolve( - cwdGuestPath, - target.replace(/^\/+/, ""), - ); - const cwdMapping = this._resolveHostMappingForGuestPath(cwdGuestTarget); - const cwdHostTarget = cwdMapping?.hostPath ?? null; - if ( - typeof cwdHostTarget === "string" && - ( - ( - preferCreateParent && - this._createParentExists(cwdGuestTarget, cwdHostTarget) - ) || - ( - this._hostPathExists(cwdHostTarget) && - !(typeof rootHostPath === "string" && this._hostPathExists(rootHostPath)) - ) - ) - ) { - return { - guestPath: cwdGuestTarget, - hostPath: cwdHostTarget, - readOnly: cwdMapping?.readOnly === true, - }; - } - } - return { - guestPath: rootGuestPath, - hostPath: rootHostPath, - readOnly: rootMapping?.readOnly === true, - }; - } - - _resolveDescriptorPath(fd, pathPtr, pathLen, options = {}) { - const entry = this._measureWasiPhase("descriptorEntry", () => this._descriptorEntry(fd)); - if (!entry) { - return { error: __agentOSWasiErrnoBadf }; - } - const target = this._measureWasiPhase("readString", () => this._readString(pathPtr, pathLen)); - const base = this._measureWasiPhase("descriptorPathBase", () => this._descriptorPathBase(entry, target)); - if (!base || typeof base.guestPath !== "string") { - return { error: __agentOSWasiErrnoBadf }; - } - const guestPath = this._measureWasiPhase("guestPathResolve", () => - target.startsWith("/") - ? __agentOSPath().posix.normalize(target) - : __agentOSPath().posix.resolve(base.guestPath, target) - ); - const mapped = this._measureWasiPhase("descriptorPathMap", () => - target.startsWith("/") - ? this._resolveAbsolutePath( - target, - options.preferCreateParent === true, - ) - : base.guestPath === "/" - ? this._resolveRootRelativePath( - target, - options.preferCreateParent === true, - ) - : { - guestPath, - ...( - this._resolveHostMappingForGuestPath(guestPath) ?? - { hostPath: null, readOnly: false } - ), - } - ); - const hostPath = mapped.hostPath; - if (typeof hostPath !== "string") { - return { error: __agentOSWasiErrnoNoent }; - } - return { - error: __agentOSWasiErrnoSuccess, - guestPath: mapped.guestPath, - hostPath, - readOnly: mapped.readOnly === true, - }; - } - - _resolvedFsPath(resolved) { - if (this._sidecarManagedProcess() && typeof resolved?.guestPath === "string") { - return resolved.guestPath; - } - return resolved?.hostPath ?? null; - } - - _statResolvedPath(resolved, follow) { - if ( - typeof globalThis?.__agentOSSyncRpc?.callSync === "function" && - typeof resolved?.guestPath === "string" - ) { - return this._measureWasiPhase(follow ? "syncRpcStat" : "syncRpcLstat", () => - __agentOSWasiSyncRpc().callSync(follow ? "fs.statSync" : "fs.lstatSync", [ - resolved.guestPath, - ]) - ); - } - const bridgeStat = follow ? globalThis?._fsStat : globalThis?._fsLstat; - if ( - typeof bridgeStat?.applySyncPromise === "function" && - typeof resolved?.guestPath === "string" - ) { - return this._measureWasiPhase(follow ? "bridgeStatSync" : "bridgeLstatSync", () => - bridgeStat.applySyncPromise(void 0, [resolved.guestPath]) - ); - } - const fsPath = this._resolvedFsPath(resolved); - return this._measureWasiPhase(follow ? "fsModuleStatSync" : "fsModuleLstatSync", () => - follow ? this._fs().statSync(fsPath) : this._fs().lstatSync(fsPath) - ); - } - - - _resolveDescriptorDirectStatPath(fd, target) { - if ( - typeof target !== "string" || - target.length === 0 || - target === "." || - target === ".." || - target.startsWith("/") - ) { - return null; - } - const entry = this._descriptorEntry(fd); - if ( - !entry || - (entry.kind !== "directory" && entry.kind !== "preopen") || - typeof entry.hostPath !== "string" || - entry.hostPath.length === 0 - ) { - return null; - } - const baseGuestPath = this._descriptorGuestPath(entry); - if (typeof baseGuestPath !== "string") { - return null; - } - if (entry.kind === "preopen" && baseGuestPath === "/") { - if (!this._rootRelativeTargetIsWithinAbsoluteArg(target)) { - return null; - } - } else if (target.includes("/")) { - return null; - } - return { - error: __agentOSWasiErrnoSuccess, - guestPath: this._path().posix.resolve(baseGuestPath, target), - hostPath: this._path().join(entry.hostPath, target), - readOnly: entry.readOnly === true, - }; - } - - _writeFilestat(statPtr, stats, fallbackType) { - try { - const view = this._memoryView(); - const offset = Number(statPtr) >>> 0; - const filetype = stats ? this._filetypeForStats(stats) : fallbackType; - view.setBigUint64(offset, 0n, true); - view.setBigUint64(offset + 8, BigInt(stats?.ino ?? 0), true); - view.setUint8(offset + 16, filetype); - view.setBigUint64(offset + 24, BigInt(stats?.nlink ?? 1), true); - view.setBigUint64(offset + 32, BigInt(stats?.size ?? 0), true); - view.setBigUint64(offset + 40, BigInt(Math.trunc((stats?.atimeMs ?? 0) * 1000000)), true); - view.setBigUint64(offset + 48, BigInt(Math.trunc((stats?.mtimeMs ?? 0) * 1000000)), true); - view.setBigUint64(offset + 56, BigInt(Math.trunc((stats?.ctimeMs ?? 0) * 1000000)), true); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _argsSizesGet(argcPtr, argvBufSizePtr) { - const values = this._stringTable(this.args); - const total = values.reduce((sum, value) => sum + value.length, 0); - const argcStatus = this._writeUint32(argcPtr, values.length); - if (argcStatus !== __agentOSWasiErrnoSuccess) { - return argcStatus; - } - return this._writeUint32(argvBufSizePtr, total); - } - - _argsGet(argvPtr, argvBufPtr) { - return this._writeStringTable(this._stringTable(this.args), argvPtr, argvBufPtr); - } - - _environEntries() { - return Object.entries(this.env).map(([key, value]) => `${key}=${value}`); - } - - _environSizesGet(countPtr, bufSizePtr) { - const values = this._stringTable(this._environEntries()); - const total = values.reduce((sum, value) => sum + value.length, 0); - const countStatus = this._writeUint32(countPtr, values.length); - if (countStatus !== __agentOSWasiErrnoSuccess) { - return countStatus; - } - return this._writeUint32(bufSizePtr, total); - } - - _environGet(environPtr, environBufPtr) { - return this._writeStringTable( - this._stringTable(this._environEntries()), - environPtr, - environBufPtr, - ); - } - - _clockTimeGet(_clockId, _precision, resultPtr) { - return this._writeUint64(resultPtr, BigInt(Date.now()) * 1000000n); - } - - _clockResGet(_clockId, resultPtr) { - return this._writeUint64(resultPtr, 1000000n); - } - - _fdWrite(fd, iovs, iovsLen, nwrittenPtr) { - try { - const bytes = this._measureWasiPhase("collectIovs", () => this._collectIovs(iovs, iovsLen)); - const descriptor = Number(fd) >>> 0; - const handle = this._measureWasiPhase("externalFdHandle", () => this._externalFdHandle(descriptor)); - if (handle?.kind === "pipe-write" && handle.pipe) { - if (bytes.length > 0 && !this._pipeHasReaders(handle.pipe)) { - return __agentOSWasiErrnoPipe; - } - this._enqueuePipeBytes(handle.pipe, bytes); - this._flushPipeConsumers(handle.pipe); - return this._writeUint32(nwrittenPtr, bytes.length); - } - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - if (handle.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - if (descriptor === 1 || descriptor === 2) { - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - const useKernelStdioSyncRpc = - sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled(); - if (useKernelStdioSyncRpc) { - const written = this._measureWasiPhase("kernelStdioWrite", () => - Number( - __agentOSWasiSyncRpc().callSync("__kernel_stdio_write", [descriptor, bytes]), - ) >>> 0 - ); - return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written)); - } - } - const written = this._measureWasiPhase("writeSync", () => - __agentOSFs().writeSync( - handle.targetFd, - bytes, - 0, - bytes.length, - null, - ) - ); - return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written)); - } - if (handle?.kind === "guest-file" && typeof handle.targetFd === "number") { - const position = handle.append ? null : (handle.position ?? 0); - const written = this._measureWasiPhase("writeSync", () => - __agentOSFs().writeSync( - handle.targetFd, - bytes, - 0, - bytes.length, - position, - ) - ); - if (handle.append) { - handle.position = this._measureWasiPhase("appendFstat", () => - Number(__agentOSFs().fstatSync(handle.targetFd).size ?? 0) - ); - } else { - handle.position = (handle.position ?? 0) + written; - } - return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written)); - } - if (handle?.kind === "stdio" && typeof handle.targetFd === "number") { - const targetFd = Number(handle.targetFd) >>> 0; - if (targetFd === 1 || targetFd === 2) { - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - const useKernelStdioSyncRpc = - sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled(); - const written = useKernelStdioSyncRpc - ? this._measureWasiPhase("kernelStdioWrite", () => - Number(__agentOSWasiSyncRpc().callSync("__kernel_stdio_write", [targetFd, bytes])) >>> 0 - ) - : this._measureWasiPhase("processStreamWrite", () => - (targetFd === 2 ? process.stderr.write(bytes) : process.stdout.write(bytes), bytes.length) - ); - return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written)); - } - return __agentOSWasiErrnoBadf; - } - const entry = this.fdTable.get(descriptor); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - if (entry.kind === "stdout") { - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - const useKernelStdioSyncRpc = - sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled(); - const written = useKernelStdioSyncRpc - ? this._measureWasiPhase("kernelStdioWrite", () => - Number(__agentOSWasiSyncRpc().callSync("__kernel_stdio_write", [1, bytes])) >>> 0 - ) - : this._measureWasiPhase("processStreamWrite", () => - (process.stdout.write(bytes), bytes.length) - ); - return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written)); - } - if (entry.kind === "stderr") { - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - const useKernelStdioSyncRpc = - sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled(); - const written = useKernelStdioSyncRpc - ? this._measureWasiPhase("kernelStdioWrite", () => - Number(__agentOSWasiSyncRpc().callSync("__kernel_stdio_write", [2, bytes])) >>> 0 - ) - : this._measureWasiPhase("processStreamWrite", () => - (process.stderr.write(bytes), bytes.length) - ); - return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written)); - } - if (entry.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - if (entry.kind === "file") { - this._clearStatCache(); - const position = typeof entry.offset === "number" ? entry.offset : null; - const written = this._measureWasiPhase("writeSync", () => - __agentOSFs().writeSync( - entry.realFd, - bytes, - 0, - bytes.length, - position, - ) - ); - if (typeof entry.offset === "number") { - entry.offset += written; - } - return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written)); - } - return __agentOSWasiErrnoBadf; - } catch (error) { - return this._mapFsError(error); - } - } - - _fdPwrite(fd, iovs, iovsLen, offset, nwrittenPtr) { - try { - const bytes = this._collectIovs(iovs, iovsLen); - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - if (handle.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - const written = __agentOSFs().writeSync( - handle.targetFd, - bytes, - 0, - bytes.length, - Number(offset) >>> 0, - ); - return this._writeUint32(nwrittenPtr, written); - } - const entry = this.fdTable.get(descriptor); - if (!entry || entry.kind !== "file") { - return __agentOSWasiErrnoBadf; - } - if (entry.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - const written = __agentOSFs().writeSync( - entry.realFd, - bytes, - 0, - bytes.length, - Number(offset) >>> 0, - ); - return this._writeUint32(nwrittenPtr, written); - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdPread(fd, iovs, iovsLen, offset, nreadPtr) { - try { - const descriptor = Number(fd) >>> 0; - const explicitOffset = Number(offset) >>> 0; - const totalLength = this._boundedReadLength(iovs, iovsLen); - const buffer = Buffer.alloc(totalLength); - const handle = this._externalFdHandle(descriptor); - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - const bytesRead = __agentOSFs().readSync( - handle.targetFd, - buffer, - 0, - totalLength, - explicitOffset, - ); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } - const entry = this.fdTable.get(descriptor); - if (!entry || entry.kind !== "file") { - return __agentOSWasiErrnoBadf; - } - const bytesRead = __agentOSFs().readSync( - entry.realFd, - buffer, - 0, - totalLength, - explicitOffset, - ); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdRead(fd, iovs, iovsLen, nreadPtr) { - try { - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - if (handle?.kind === "pipe-read" && handle.pipe) { - const totalLength = this._boundedReadLength(iovs, iovsLen); - while (handle.pipe.chunks.length === 0) { - if (handle.pipe.writeHandleCount === 0 && handle.pipe.producers.size === 0) { - return this._writeUint32(nreadPtr, 0); - } - this._pumpPipeProducers(handle.pipe, 10); - } - const chunk = this._dequeuePipeBytes(handle.pipe, totalLength); - const written = this._writeToIovs(iovs, iovsLen, chunk); - return this._writeUint32(nreadPtr, written); - } - if (handle?.kind === "stdio" && Number(handle.targetFd) === 0) { - const totalLength = this._boundedReadLength(iovs, iovsLen); - if (typeof __agentOSWasiHost.readStdin === "function") { - const value = __agentOSWasiHost.readStdin(totalLength); - if (value == null) { - return this._writeUint32(nreadPtr, 0); - } - const chunk = - typeof value === "string" - ? Buffer.from(value, "utf8") - : value instanceof Uint8Array - ? value - : Buffer.from(value); - if (chunk.length === 0) { - return this._writeUint32(nreadPtr, 0); - } - const written = this._writeToIovs(iovs, iovsLen, chunk); - return this._writeUint32(nreadPtr, written); - } - const buffer = Buffer.alloc(totalLength); - const bytesRead = __agentOSFs().readSync(0, buffer, 0, totalLength, null); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } - const entry = this.fdTable.get(descriptor); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - if (entry.kind === "stdin") { - const totalLength = this._boundedReadLength(iovs, iovsLen); - const syncRpc = - typeof globalThis?.__agentOSSyncRpc?.callSync === "function" - ? __agentOSWasiSyncRpc() - : null; - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - if (syncRpc && (sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled())) { - try { - let chunk = null; - while (true) { - const response = syncRpc.callSync("__kernel_stdin_read", [totalLength, 10]); - if ( - response && - typeof response === "object" && - typeof response.dataBase64 === "string" - ) { - chunk = Buffer.from(response.dataBase64, "base64"); - break; - } - if (response && typeof response === "object" && response.done === true) { - chunk = Buffer.alloc(0); - break; - } - if ( - typeof Atomics?.wait === "function" && - typeof syntheticWaitArray !== "undefined" - ) { - Atomics.wait(syntheticWaitArray, 0, 0, 10); - } - } - if (!chunk || chunk.length === 0) { - return this._writeUint32(nreadPtr, 0); - } - const written = this._writeToIovs(iovs, iovsLen, chunk); - return this._writeUint32(nreadPtr, written); - } catch { - // Fall back to direct stdin reads when the sync bridge is unavailable - // in the standalone runner bootstrap. - } - } - // Host-seam stdin (a non-native backend whose stdin is delivered through - // the runtime process object, not a kernel fd): read the queued bytes - // directly instead of fs.readSync on a descriptor the JS fs table does - // not own. - if (typeof __agentOSWasiHost.readStdin === "function") { - const value = __agentOSWasiHost.readStdin(totalLength); - if (value == null) { - return this._writeUint32(nreadPtr, 0); - } - const chunk = - typeof value === "string" - ? Buffer.from(value, "utf8") - : value instanceof Uint8Array - ? value - : Buffer.from(value); - if (chunk.length === 0) { - return this._writeUint32(nreadPtr, 0); - } - const written = this._writeToIovs(iovs, iovsLen, chunk); - return this._writeUint32(nreadPtr, written); - } - const buffer = Buffer.alloc(totalLength); - const directStdinFd = - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ? handle.targetFd - : typeof process?.stdin?.fd === "number" - ? process.stdin.fd - : 0; - const bytesRead = __agentOSFs().readSync( - directStdinFd, - buffer, - 0, - totalLength, - null, - ); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - const totalLength = this._boundedReadLength(iovs, iovsLen); - const buffer = Buffer.alloc(totalLength); - const bytesRead = __agentOSFs().readSync( - handle.targetFd, - buffer, - 0, - totalLength, - null, - ); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } - if (entry.kind !== "file") { - return __agentOSWasiErrnoBadf; - } - // WASI rights: a descriptor opened without FD_READ cannot be read. - if ( - typeof entry.rightsBase === "bigint" && - (entry.rightsBase & __agentOSWasiRightFdRead) === 0n - ) { - return __agentOSWasiErrnoNotcapable; - } - const totalLength = this._boundedReadLength(iovs, iovsLen); - const buffer = Buffer.alloc(totalLength); - const position = typeof entry.offset === "number" ? entry.offset : null; - const bytesRead = __agentOSFs().readSync( - entry.realFd, - buffer, - 0, - totalLength, - position, - ); - if (typeof entry.offset === "number") { - entry.offset += bytesRead; - } - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } catch (error) { - return this._mapFsError(error); - } - } - - _fdClose(fd) { - try { - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - if (handle?.kind === "pipe-read" && handle.pipe) { - handle.open = false; - handle.pipe.readHandleCount = Math.max(0, (handle.pipe.readHandleCount ?? 0) - 1); - if (typeof handle.onClose === "function") { - handle.onClose(handle, descriptor); - } - return __agentOSWasiErrnoSuccess; - } - if (handle?.kind === "pipe-write" && handle.pipe) { - handle.open = false; - handle.pipe.writeHandleCount = Math.max(0, (handle.pipe.writeHandleCount ?? 0) - 1); - if (typeof handle.onClose === "function") { - handle.onClose(handle, descriptor); - } - return __agentOSWasiErrnoSuccess; - } - if (handle?.kind === "guest-file" || handle?.kind === "stdio") { - handle.open = false; - return __agentOSWasiErrnoSuccess; - } - const entry = this.fdTable.get(descriptor); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - const retainedDelegateRefs = (() => { - try { - if (typeof globalThis.__agentOSWasiDelegateFdRefCount === "function") { - return Number(globalThis.__agentOSWasiDelegateFdRefCount(descriptor)) || 0; - } - } catch { - // Fall through to the default close path. - } - return 0; - })(); - if (entry.kind === "file" && retainedDelegateRefs <= 0) { - __agentOSFs().closeSync(entry.realFd); - } - if (descriptor > 2 && retainedDelegateRefs <= 0) { - this.fdTable.delete(descriptor); - } - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdSync(fd) { - try { - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - __agentOSFs().fsyncSync(handle.targetFd); - return __agentOSWasiErrnoSuccess; - } - const entry = this.fdTable.get(descriptor); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - // fsync on a stdio stream (stdin/stdout/stderr) is a no-op success; only - // descriptors with a real backing fd are flushed. - if ( - entry.kind === "stdin" || - entry.kind === "stdout" || - entry.kind === "stderr" - ) { - return __agentOSWasiErrnoSuccess; - } - if (entry.kind !== "file" || typeof entry.realFd !== "number") { - return __agentOSWasiErrnoBadf; - } - __agentOSFs().fsyncSync(entry.realFd); - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdFdstatGet(fd, statPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - const view = this._memoryView(); - const offset = Number(statPtr) >>> 0; - view.setUint8(offset, this._fdFiletype(entry)); - view.setUint16(offset + 2, (Number(entry.fdFlags) >>> 0) & 0xffff, true); - view.setBigUint64(offset + 8, this._descriptorRightsBase(entry), true); - view.setBigUint64(offset + 16, this._descriptorRightsInheriting(entry), true); - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdFdstatSetFlags(fd, flags) { - try { - const entry = this._descriptorEntry(fd); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - entry.fdFlags = (Number(flags) >>> 0) & 0xffff; - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdFilestatGet(fd, statPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - if ( - entry.kind === "stdin" || - entry.kind === "stdout" || - entry.kind === "stderr" - ) { - return this._writeFilestat(statPtr, null, __agentOSWasiFiletypeCharacterDevice); - } - if (entry.kind === "preopen") { - const stats = __agentOSFs().statSync(entry.guestPath); - return this._writeFilestat(statPtr, stats, __agentOSWasiFiletypeDirectory); - } - const stats = - typeof entry.realFd === "number" - ? __agentOSFs().fstatSync(entry.realFd) - : __agentOSFs().statSync(this._descriptorFsPath(entry)); - return this._writeFilestat(statPtr, stats, this._fdFiletype(entry)); - } catch (error) { - return this._mapFsError(error); - } - } - - _fdFilestatSetSize(fd, size) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "file" || typeof entry.realFd !== "number") { - return __agentOSWasiErrnoBadf; - } - if (entry.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - __agentOSFs().ftruncateSync(entry.realFd, Number(size)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _fdSeek(fd, offset, whence, newOffsetPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "file" || typeof entry.realFd !== "number") { - return __agentOSWasiErrnoBadf; - } - const delta = Number(offset); - if (!Number.isFinite(delta)) { - return __agentOSWasiErrnoInval; - } - const currentOffset = typeof entry.offset === "number" ? entry.offset : 0; - let nextOffset = 0; - switch (Number(whence) >>> 0) { - case __agentOSWasiWhenceSet: - nextOffset = delta; - break; - case __agentOSWasiWhenceCur: - nextOffset = currentOffset + delta; - break; - case __agentOSWasiWhenceEnd: { - const stats = __agentOSFs().fstatSync(entry.realFd); - nextOffset = Number(stats?.size ?? 0) + delta; - break; - } - default: - return __agentOSWasiErrnoInval; - } - if (!Number.isFinite(nextOffset) || nextOffset < 0) { - return __agentOSWasiErrnoInval; - } - entry.offset = nextOffset; - return this._writeUint64(newOffsetPtr, BigInt(nextOffset)); - } catch (error) { - return this._mapFsError(error); - } - } - - _fdTell(fd, offsetPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "file") { - return __agentOSWasiErrnoBadf; - } - const offset = typeof entry.offset === "number" ? entry.offset : 0; - return this._writeUint64(offsetPtr, BigInt(offset)); - } catch (error) { - return this._mapFsError(error); - } - } - - _fdPrestatGet(fd, prestatPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "preopen") { - return __agentOSWasiErrnoBadf; - } - const guestPath = this._descriptorPreopenName(entry); - if (typeof guestPath !== "string") { - return __agentOSWasiErrnoBadf; - } - const view = this._memoryView(); - const offset = Number(prestatPtr) >>> 0; - view.setUint8(offset, 0); - view.setUint32(offset + 4, Buffer.byteLength(guestPath), true); - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdPrestatDirName(fd, pathPtr, pathLen) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "preopen") { - return __agentOSWasiErrnoBadf; - } - const guestPath = this._descriptorPreopenName(entry); - if (typeof guestPath !== "string") { - return __agentOSWasiErrnoBadf; - } - const bytes = Buffer.from(guestPath, "utf8"); - if ((Number(pathLen) >>> 0) < bytes.length) { - return __agentOSWasiErrnoFault; - } - return this._writeBytes(pathPtr, bytes); - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdReaddir(fd, bufPtr, bufLen, cookie, bufUsedPtr) { - const startedAt = __agentOSWasiNow(); - const requestedCookie = Number(cookie) >>> 0; - const requestedBufLen = Number(bufLen) >>> 0; - try { - const entry = this._descriptorEntry(fd); - const fsPath = this._descriptorDirectoryFsPath(entry); - if ( - !entry || - (entry.kind !== "preopen" && entry.kind !== "directory") || - typeof fsPath !== "string" - ) { - return __agentOSWasiErrnoBadf; - } - let dirents = - requestedCookie > 0 && Array.isArray(entry.readdirCache) - ? entry.readdirCache - : null; - if (!dirents) { - dirents = __agentOSFs() - .readdirSync(fsPath, { withFileTypes: true }) - .map((entry) => - typeof entry === "string" - ? { name: entry, filetype: __agentOSWasiFiletypeUnknown } - : { - name: String(entry?.name ?? ""), - filetype: this._filetypeForDirent(entry), - } - ) - .sort((left, right) => left.name.localeCompare(right.name)); - entry.readdirCache = dirents; - } - const view = this._memoryView(); - const memory = this._memoryBytes(); - let offset = Number(bufPtr) >>> 0; - const limit = offset + requestedBufLen; - let used = 0; - let recordsReturned = 0; - let stoppedRecordTooLarge = false; - for (let index = requestedCookie; index < dirents.length; index += 1) { - const dirent = dirents[index]; - const name = typeof dirent === "string" ? dirent : String(dirent?.name ?? ""); - const filetype = - typeof dirent === "object" - ? Number(dirent?.filetype ?? __agentOSWasiFiletypeUnknown) >>> 0 - : __agentOSWasiFiletypeUnknown; - const nameBytes = Buffer.from(name, "utf8"); - const recordLen = 24 + nameBytes.length; - if (offset + recordLen > limit) { - const remaining = Math.max(0, limit - offset); - if (remaining > 0) { - const record = Buffer.alloc(recordLen); - const recordView = new DataView( - record.buffer, - record.byteOffset, - record.byteLength, - ); - recordView.setBigUint64(0, BigInt(index + 1), true); - recordView.setBigUint64(8, BigInt(index + 1), true); - recordView.setUint32(16, nameBytes.length, true); - recordView.setUint8( - 20, - filetype, - ); - record.set(nameBytes, 24); - memory.set(record.subarray(0, remaining), offset); - offset += remaining; - used += remaining; - } - stoppedRecordTooLarge = true; - break; - } - view.setBigUint64(offset, BigInt(index + 1), true); - view.setBigUint64(offset + 8, BigInt(index + 1), true); - view.setUint32(offset + 16, nameBytes.length, true); - view.setUint8( - offset + 20, - filetype, - ); - memory.set(nameBytes, offset + 24); - offset += recordLen; - used += recordLen; - recordsReturned += 1; - } - const result = this._writeUint32(bufUsedPtr, used); - this._recordWasiSyscallMetric("fd_readdir", startedAt, { - result, - fd: Number(fd) >>> 0, - cookie: requestedCookie, - bufLen: requestedBufLen, - used, - recordsReturned, - totalDirentsRead: dirents.length, - stoppedRecordTooLarge, - }); - return result; - } catch (error) { - this._recordWasiSyscallMetric("fd_readdir", startedAt, { - result: "error", - fd: Number(fd) >>> 0, - cookie: requestedCookie, - bufLen: requestedBufLen, - }); - return this._mapFsError(error); - } - } - - _pathCreateDirectory(fd, pathPtr, pathLen) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen, { - preferCreateParent: true, - }); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - if (resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - this._clearStatCache(); - __agentOSFs().mkdirSync(this._resolvedFsPath(resolved)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathLink(oldFd, _oldFlags, oldPathPtr, oldPathLen, newFd, newPathPtr, newPathLen) { - try { - const source = this._resolveDescriptorPath(oldFd, oldPathPtr, oldPathLen); - if (source.error !== __agentOSWasiErrnoSuccess) { - return source.error; - } - const destination = this._resolveDescriptorPath(newFd, newPathPtr, newPathLen); - if (destination.error !== __agentOSWasiErrnoSuccess) { - return destination.error; - } - if (source.readOnly || destination.readOnly) { - return __agentOSWasiErrnoRofs; - } - this._clearStatCache(); - __agentOSFs().linkSync(this._resolvedFsPath(source), this._resolvedFsPath(destination)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathOpen(fd, _dirflags, pathPtr, pathLen, oflags, rightsBase, rightsInheriting, _fdflags, openedFdPtr) { - try { - const entry = this._measureWasiPhase("descriptorEntry", () => this._descriptorEntry(fd)); - if ( - !entry || - (entry.kind !== "preopen" && entry.kind !== "directory") || - typeof entry.hostPath !== "string" - ) { - return __agentOSWasiErrnoBadf; - } - const requestedFlags = Number(oflags) >>> 0; - const createOrTruncate = - (requestedFlags & __agentOSWasiOpenCreate) !== 0 || - (requestedFlags & __agentOSWasiOpenTruncate) !== 0; - const resolved = this._measureWasiPhase("resolveDescriptorPath", () => - this._resolveDescriptorPath(fd, pathPtr, pathLen, { - preferCreateParent: createOrTruncate, - }) - ); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - const guestPath = resolved.guestPath; - const fsPath = this._resolvedFsPath(resolved); - const openDirectory = (requestedFlags & __agentOSWasiOpenDirectory) !== 0; - const allowedRightsBase = this._descriptorRightsBase(entry); - const allowedRightsInheriting = this._descriptorRightsInheriting(entry); - const requestedRightsBase = this._normalizeRights(rightsBase, allowedRightsInheriting); - const requestedRightsInheriting = this._normalizeRights( - rightsInheriting, - allowedRightsInheriting, - ); - if ( - (requestedRightsBase & ~allowedRightsInheriting) !== 0n || - (requestedRightsInheriting & ~allowedRightsInheriting) !== 0n - ) { - return __agentOSWasiErrnoAcces; - } - const requestedWriteAccess = - !openDirectory && - (createOrTruncate || this._hasWriteRights(requestedRightsBase)); - if ( - requestedWriteAccess && - !this._hasWriteRights(allowedRightsBase) - ) { - return __agentOSWasiErrnoAcces; - } - if (requestedWriteAccess && resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - if (createOrTruncate) { - this._clearStatCache(); - } - const fsConstants = __agentOSFs().constants ?? {}; - let openFlags = requestedWriteAccess - ? fsConstants.O_RDWR ?? 2 - : fsConstants.O_RDONLY ?? 0; - if ((requestedFlags & __agentOSWasiOpenCreate) !== 0) { - openFlags |= fsConstants.O_CREAT ?? 64; - } - if ((requestedFlags & __agentOSWasiOpenExclusive) !== 0) { - openFlags |= fsConstants.O_EXCL ?? 128; - } - if ((requestedFlags & __agentOSWasiOpenTruncate) !== 0) { - openFlags |= fsConstants.O_TRUNC ?? 512; - } - if (openDirectory) { - openFlags |= fsConstants.O_DIRECTORY ?? 0; - } - const realFd = this._measureWasiPhase("openSync", () => __agentOSFs().openSync(fsPath, openFlags)); - const openedKind = openDirectory || createOrTruncate - ? (openDirectory ? "directory" : "file") - : this._measureWasiPhase("postOpenStat", () => - __agentOSFs().statSync(fsPath).isDirectory() ? "directory" : "file" - ); - const openedFd = this.nextFd++; - this._measureWasiPhase("fdTableSet", () => { - this.fdTable.set(openedFd, { - kind: openedKind, - guestPath, - hostPath: fsPath, - readOnly: resolved.readOnly === true, - realFd, - offset: 0, - rightsBase: requestedRightsBase & allowedRightsInheriting, - rightsInheriting: requestedRightsInheriting & allowedRightsInheriting, - fdFlags: (Number(_fdflags) >>> 0) & 0xffff, - }); - }); - return this._measureWasiPhase("writeOpenedFd", () => this._writeUint32(openedFdPtr, openedFd)); - } catch (error) { - return this._mapFsError(error); - } - } - - _pathSymlink(targetPtr, targetLen, fd, pathPtr, pathLen) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - if (resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - const target = this._readString(targetPtr, targetLen); - this._clearStatCache(); - __agentOSFs().symlinkSync(target, this._resolvedFsPath(resolved)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathRemoveDirectory(fd, pathPtr, pathLen) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - if (resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - this._clearStatCache(); - __agentOSFs().rmdirSync(this._resolvedFsPath(resolved)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathRename(oldFd, oldPathPtr, oldPathLen, newFd, newPathPtr, newPathLen) { - try { - const source = this._resolveDescriptorPath(oldFd, oldPathPtr, oldPathLen); - if (source.error !== __agentOSWasiErrnoSuccess) { - return source.error; - } - const destination = this._resolveDescriptorPath(newFd, newPathPtr, newPathLen); - if (destination.error !== __agentOSWasiErrnoSuccess) { - return destination.error; - } - if (source.readOnly || destination.readOnly) { - return __agentOSWasiErrnoRofs; - } - this._clearStatCache(); - __agentOSFs().renameSync(this._resolvedFsPath(source), this._resolvedFsPath(destination)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathUnlinkFile(fd, pathPtr, pathLen) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - if (resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - this._clearStatCache(); - __agentOSFs().unlinkSync(this._resolvedFsPath(resolved)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathFilestatGet(fd, flags, pathPtr, pathLen, statPtr) { - try { - const target = this._measureWasiPhase("readString", () => this._readString(pathPtr, pathLen)); - const resolved = - this._measureWasiPhase("resolveDirectStatPath", () => this._resolveDescriptorDirectStatPath(fd, target)) ?? - this._measureWasiPhase("resolveDescriptorPath", () => this._resolveDescriptorPath(fd, pathPtr, pathLen)); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - const follow = (Number(flags) & __agentOSWasiLookupSymlinkFollow) !== 0; - const cacheKey = this._statCacheKey(resolved, follow); - let stats = cacheKey ? this.statCache.get(cacheKey) : undefined; - if (stats) { - this._measureWasiPhase("statCacheHit", () => undefined); - } else { - stats = this._measureWasiPhase(follow ? "statSync" : "lstatSync", () => - this._statResolvedPath(resolved, follow) - ); - if (cacheKey) { - this.statCache.set(cacheKey, stats); - } - } - return this._measureWasiPhase("writeFilestat", () => this._writeFilestat(statPtr, stats, this._filetypeForStats(stats))); - } catch (error) { - return this._mapFsError(error); - } - } - - _pathReadlink(fd, pathPtr, pathLen, bufPtr, bufLen, bufUsedPtr) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - const bytes = Buffer.from(__agentOSFs().readlinkSync(resolved.guestPath), "utf8"); - const length = Math.min(bytes.length, Number(bufLen) >>> 0); - const writeStatus = this._writeBytes(bufPtr, bytes.subarray(0, length)); - if (writeStatus !== __agentOSWasiErrnoSuccess) { - return writeStatus; - } - return this._writeUint32(bufUsedPtr, length); - } catch (error) { - return this._mapFsError(error); - } - } - - _pollOneoff(inPtr, outPtr, nsubscriptions, neventsPtr) { - try { - const subscriptionCount = Number(nsubscriptions) >>> 0; - if (subscriptionCount === 0) { - return this._writeUint32(neventsPtr, 0); - } - - const subscriptionSize = 48; - const eventSize = 32; - const kernelPollIn = 0x0001; - const kernelPollOut = 0x0004; - const kernelPollErr = 0x0008; - const kernelPollHup = 0x0010; - const view = this._memoryView(); - const memory = this._memoryBytes(); - const syncRpc = - typeof globalThis?.__agentOSSyncRpc?.callSync === "function" - ? __agentOSWasiSyncRpc() - : null; - const subscriptions = []; - let timeoutMs = null; - - for (let index = 0; index < subscriptionCount; index += 1) { - const base = (Number(inPtr) >>> 0) + index * subscriptionSize; - const tag = view.getUint8(base + 8); - const userdata = memory.slice(base, base + 8); - if (tag === 0) { - const timeoutNs = view.getBigUint64(base + 24, true); - const relativeTimeoutMs = Number(timeoutNs / 1000000n); - timeoutMs = - timeoutMs == null ? relativeTimeoutMs : Math.min(timeoutMs, relativeTimeoutMs); - subscriptions.push({ kind: "clock", userdata }); - continue; - } - - if (tag !== 1 && tag !== 2) { - subscriptions.push({ kind: "unsupported", userdata }); - continue; - } - - const fd = view.getUint32(base + 16, true); - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - const entry = this._descriptorEntry(descriptor); - let targetFd = null; - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - targetFd = Number(handle.targetFd) >>> 0; - } else if ( - entry?.kind === "stdin" || - entry?.kind === "stdout" || - entry?.kind === "stderr" - ) { - targetFd = descriptor; - } - - subscriptions.push({ - kind: tag === 1 ? "fd_read" : "fd_write", - fd: descriptor, - handle, - targetFd, - streamKind: entry?.kind, - userdata, - }); - } - - const deadline = timeoutMs == null ? null : Date.now() + Math.max(0, timeoutMs); - const readyEvents = []; - - while (readyEvents.length === 0) { - for (const subscription of subscriptions) { - // A clock subscription is ready once its deadline has elapsed; report - // it as a first-class event so it is returned alongside any ready fds - // (not only as a fallback when nothing else is ready). - if (subscription.kind === "clock") { - if (deadline != null && Date.now() >= deadline) { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 0, - nbytes: 0, - flags: 0, - }); - } - continue; - } - if (subscription.kind === "fd_read" && subscription.handle?.kind === "pipe-read") { - const pipe = subscription.handle.pipe; - if ( - pipe && - (pipe.chunks.length > 0 || - (pipe.writeHandleCount === 0 && pipe.producers.size === 0)) - ) { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 1, - nbytes: pipe.chunks[0]?.length ?? 0, - flags: 0, - }); - } - continue; - } - - // Without a kernel poll bridge, resolve stdin fd_read readiness from - // the host-seam queued byte count (the browser delivers stdin through - // the runtime process object). Reporting nbytes does not consume input. - if ( - !syncRpc && - subscription.kind === "fd_read" && - subscription.streamKind === "stdin" && - typeof __agentOSWasiHost.stdinReadableBytes === "function" - ) { - const available = Number(__agentOSWasiHost.stdinReadableBytes()) >>> 0; - if (available > 0) { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 1, - nbytes: available, - flags: 0, - }); - } - continue; - } - - if (subscription.kind === "fd_write" && subscription.handle?.kind === "pipe-write") { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 2, - nbytes: 65536, - flags: 0, - }); - continue; - } - - // Without a kernel poll bridge (a non-native backend) stdout/stderr - // are always writable, so resolve their fd_write readiness directly - // instead of leaving it to the (absent) __kernel_poll round-trip. - if ( - !syncRpc && - subscription.kind === "fd_write" && - (subscription.streamKind === "stdout" || - subscription.streamKind === "stderr") - ) { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 2, - nbytes: 65536, - flags: 0, - }); - } - } - - if (readyEvents.length > 0) { - break; - } - - // Without a kernel poll bridge, fd readiness is resolved synchronously - // above (stdio fast paths) or via pipes; if there is no clock to wait on - // and no pipe to pump, no further progress is possible, so stop instead - // of busy-waiting until the caller times out. - if ( - !syncRpc && - !subscriptions.some((subscription) => subscription.kind === "clock") && - !subscriptions.some( - (subscription) => - subscription.handle?.kind === "pipe-read" || - subscription.handle?.kind === "pipe-write", - ) - ) { - break; - } - - const pollTargets = subscriptions - .filter( - (subscription) => - (subscription.kind === "fd_read" || subscription.kind === "fd_write") && - typeof subscription.targetFd === "number", - ) - .map((subscription) => ({ - fd: subscription.targetFd, - events: subscription.kind === "fd_read" ? kernelPollIn : kernelPollOut, - })); - const waitMs = - deadline == null ? 10 : Math.max(0, Math.min(10, deadline - Date.now())); - - if (syncRpc && pollTargets.length > 0) { - let response = null; - try { - response = syncRpc.callSync("__kernel_poll", [pollTargets, waitMs]); - } catch (error) { - __agentOSWasiDebug( - `poll_oneoff __kernel_poll failed: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - } - - const responseEntries = Array.isArray(response?.fds) ? response.fds : []; - for (const subscription of subscriptions) { - if ( - (subscription.kind !== "fd_read" && subscription.kind !== "fd_write") || - typeof subscription.targetFd !== "number" - ) { - continue; - } - - const responseEntry = responseEntries.find( - (entry) => (Number(entry?.fd) >>> 0) === subscription.targetFd, - ); - const revents = Number(responseEntry?.revents) >>> 0; - const interested = - subscription.kind === "fd_read" - ? kernelPollIn | kernelPollErr | kernelPollHup - : kernelPollOut | kernelPollErr | kernelPollHup; - if ((revents & interested) === 0) { - continue; - } - - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: subscription.kind === "fd_read" ? 1 : 2, - nbytes: subscription.kind === "fd_read" ? 1 : 65536, - flags: 0, - }); - } - } - - if (readyEvents.length > 0) { - break; - } - - let pumped = false; - for (const subscription of subscriptions) { - if (subscription.kind === "fd_read" && subscription.handle?.kind === "pipe-read") { - pumped = this._pumpPipeProducers(subscription.handle.pipe, 10) || pumped; - } - } - - if (pumped) { - continue; - } - - if (deadline != null && Date.now() >= deadline) { - break; - } - - if ( - pollTargets.length === 0 && - typeof Atomics?.wait !== "function" && - deadline == null - ) { - break; - } - - if ( - typeof Atomics?.wait === "function" && - typeof syntheticWaitArray !== "undefined" - ) { - Atomics.wait(syntheticWaitArray, 0, 0, waitMs); - } else if (!syncRpc && pollTargets.length === 0) { - break; - } - } - - if ( - readyEvents.length === 0 && - subscriptions.some((subscription) => subscription.kind === "clock") - ) { - const clockSubscription = subscriptions.find( - (subscription) => subscription.kind === "clock", - ); - readyEvents.push({ - userdata: clockSubscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 0, - nbytes: 0, - flags: 0, - }); - } - - for (let index = 0; index < readyEvents.length; index += 1) { - const base = (Number(outPtr) >>> 0) + index * eventSize; - const event = readyEvents[index]; - memory.set(event.userdata, base); - view.setUint16(base + 8, event.error, true); - view.setUint8(base + 10, event.type); - view.setBigUint64(base + 16, BigInt(event.nbytes), true); - view.setUint16(base + 24, event.flags, true); - } - - return this._writeUint32(neventsPtr, readyEvents.length); - } catch (error) { - __agentOSWasiDebug( - `poll_oneoff failed: ${error instanceof Error ? error.message : String(error)}`, - ); - return __agentOSWasiErrnoFault; - } - } - - _randomGet(bufPtr, bufLen) { - try { - const length = Number(bufLen) >>> 0; - const bytes = Buffer.allocUnsafe(length); - __agentOSCrypto().randomFillSync(bytes); - return this._writeBytes(bufPtr, bytes); - } catch { - return __agentOSWasiErrnoFault; - } - } - - _schedYield() { - return __agentOSWasiErrnoSuccess; - } - - _procExit(code) { - if (this.returnOnExit) { - const error = new Error(`wasi exit(${Number(code) >>> 0})`); - error.__agentOSWasiExit = true; - error.code = Number(code) >>> 0; - throw error; - } - process.exit(Number(code) >>> 0); - } - } - - Object.defineProperty(globalThis, "__agentOSWasiModule", { - configurable: true, - enumerable: false, - value: { WASI }, - writable: true, - }); -} diff --git a/crates/execution/assets/runners/wasi-module.js.orig b/crates/execution/assets/runners/wasi-module.js.orig deleted file mode 100644 index 53a9e960b..000000000 --- a/crates/execution/assets/runners/wasi-module.js.orig +++ /dev/null @@ -1,2262 +0,0 @@ -if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule === "undefined") { - // Per-backend host seam (C / convergence): native populates it from its own - // host globals (the `|| __agentOs*` fallbacks below); a non-native backend - // (the browser converged worker) can pre-set `globalThis.__agentOSWasiHost` - // with browser-provided equivalents so this same preview1 runner is shared. - const __agentOSWasiHost = - (typeof globalThis.__agentOSWasiHost === "object" && - globalThis.__agentOSWasiHost) || - {}; - const __agentOSWasiRequireBuiltin = - __agentOSWasiHost.requireBuiltin || - (typeof __agentOSRequireBuiltin !== "undefined" - ? __agentOSRequireBuiltin - : (name) => globalThis.require(name)); - const __agentOSFs = () => __agentOSWasiRequireBuiltin("node:fs"); - const __agentOSPath = () => __agentOSWasiRequireBuiltin("node:path"); - const __agentOSCrypto = () => __agentOSWasiRequireBuiltin("node:crypto"); - // Stdio sync-RPC bridge + fd-handle lookup come from the host seam (a - // non-native backend supplies browser equivalents); native falls back to its - // own host globals so behavior is unchanged. - // Lazy resolvers: the native host globals are populated AFTER this module is - // defined (per-execution), so resolve at call time, not at module-load. - const __agentOSWasiSyncRpc = () => - __agentOSWasiHost.syncRpc || - (typeof globalThis.__agentOSSyncRpc !== "undefined" - ? globalThis.__agentOSSyncRpc - : undefined); - const __agentOSWasiLookupFdHandle = () => - __agentOSWasiHost.lookupFdHandle || - (typeof globalThis.lookupFdHandle === "function" - ? globalThis.lookupFdHandle - : undefined); - const __agentOSWasiErrnoSuccess = 0; - const __agentOSWasiErrnoAcces = 2; - const __agentOSWasiErrnoBadf = 8; - const __agentOSWasiErrnoExist = 20; - const __agentOSWasiErrnoFault = 21; - const __agentOSWasiErrnoInval = 28; - const __agentOSWasiErrnoIo = 29; - const __agentOSWasiErrnoNoent = 44; - const __agentOSWasiErrnoNosys = 52; - const __agentOSWasiErrnoNotdir = 54; - const __agentOSWasiErrnoPipe = 64; - const __agentOSWasiErrnoRofs = 69; - const __agentOSWasiErrnoNotcapable = 76; - const __agentOSWasiErrnoXdev = 18; - const __agentOSWasiFiletypeUnknown = 0; - const __agentOSWasiFiletypeCharacterDevice = 2; - const __agentOSWasiFiletypeDirectory = 3; - const __agentOSWasiFiletypeRegularFile = 4; - const __agentOSWasiFiletypeSymbolicLink = 7; - const __agentOSWasiLookupSymlinkFollow = 1; - const __agentOSWasiOpenCreate = 1; - const __agentOSWasiOpenDirectory = 2; - const __agentOSWasiOpenExclusive = 4; - const __agentOSWasiOpenTruncate = 8; - const __agentOSWasiRightFdRead = 1n << 1n; - const __agentOSWasiRightFdWrite = 1n << 6n; - const __agentOSWasiDefaultRightsBase = 0xffffffffffffffffn; - const __agentOSWasiDefaultRightsInheriting = 0xffffffffffffffffn; - const __agentOSWasiWhenceSet = 0; - const __agentOSWasiWhenceCur = 1; - const __agentOSWasiWhenceEnd = 2; - // Read cap: a non-native backend provides it via the seam; native uses its - // build-substituted constant. The ternary short-circuits so the native-only - // placeholder token is never evaluated when the seam supplies a number. - const __agentOSWasmSyncReadLimitBytes = - typeof __agentOSWasiHost.syncReadLimitBytes === "number" - ? __agentOSWasiHost.syncReadLimitBytes - : __SECURE_EXEC_WASM_SYNC_READ_LIMIT_BYTES__; - const __agentOSKernelStdioSyncRpcEnabled = () => - process?.env?.AGENTOS_WASI_STDIO_SYNC_RPC === "1"; - const __agentOSWasiDebugEnabled = () => process?.env?.AGENTOS_WASM_WASI_DEBUG === "1"; - const __agentOSWasiDebug = (message) => { - if (!__agentOSWasiDebugEnabled() || typeof process?.stderr?.write !== "function") { - return; - } - try { - process.stderr.write(`[secure-exec-wasi] ${message}\n`); - } catch { - // Ignore debug logging failures. - } - }; - - class WASI { - constructor(options = {}) { - this.args = Array.isArray(options.args) ? options.args.map((value) => String(value)) : []; - this.env = - options.env && typeof options.env === "object" - ? Object.fromEntries( - Object.entries(options.env).map(([key, value]) => [String(key), String(value)]), - ) - : {}; - this.preopens = options.preopens && typeof options.preopens === "object" ? options.preopens : {}; - this.returnOnExit = options.returnOnExit === true; - this.instance = null; - this.nextFd = 3; - this.fdTable = new Map([ - [0, { kind: "stdin", fdFlags: 0 }], - [1, { kind: "stdout", fdFlags: 0 }], - [2, { kind: "stderr", fdFlags: 0 }], - ]); - for (const [guestPath, spec] of Object.entries(this.preopens)) { - const normalized = this._normalizePreopenSpec(spec); - if (!normalized) { - continue; - } - this.fdTable.set(this.nextFd++, { - kind: "preopen", - guestPath: String(guestPath), - hostPath: normalized.hostPath, - readOnly: normalized.readOnly, - rightsBase: normalized.rightsBase, - rightsInheriting: normalized.rightsInheriting, - fdFlags: 0, - }); - } - this.wasiImport = { - args_get: (...args) => this._argsGet(...args), - args_sizes_get: (...args) => this._argsSizesGet(...args), - clock_time_get: (...args) => this._clockTimeGet(...args), - clock_res_get: (...args) => this._clockResGet(...args), - environ_get: (...args) => this._environGet(...args), - environ_sizes_get: (...args) => this._environSizesGet(...args), - fd_close: (...args) => this._fdClose(...args), - fd_fdstat_get: (...args) => this._fdFdstatGet(...args), - fd_fdstat_set_flags: (...args) => this._fdFdstatSetFlags(...args), - fd_filestat_get: (...args) => this._fdFilestatGet(...args), - fd_filestat_set_size: (...args) => this._fdFilestatSetSize(...args), - fd_prestat_dir_name: (...args) => this._fdPrestatDirName(...args), - fd_prestat_get: (...args) => this._fdPrestatGet(...args), - fd_pread: (...args) => this._fdPread(...args), - fd_pwrite: (...args) => this._fdPwrite(...args), - fd_readdir: (...args) => this._fdReaddir(...args), - fd_read: (...args) => this._fdRead(...args), - fd_seek: (...args) => this._fdSeek(...args), - fd_sync: (...args) => this._fdSync(...args), - fd_tell: (...args) => this._fdTell(...args), - fd_write: (...args) => this._fdWrite(...args), - path_create_directory: (...args) => this._pathCreateDirectory(...args), - path_filestat_get: (...args) => this._pathFilestatGet(...args), - path_link: (...args) => this._pathLink(...args), - path_open: (...args) => this._pathOpen(...args), - path_readlink: (...args) => this._pathReadlink(...args), - path_remove_directory: (...args) => this._pathRemoveDirectory(...args), - path_rename: (...args) => this._pathRename(...args), - path_symlink: (...args) => this._pathSymlink(...args), - path_unlink_file: (...args) => this._pathUnlinkFile(...args), - poll_oneoff: (...args) => this._pollOneoff(...args), - proc_exit: (...args) => this._procExit(...args), - random_get: (...args) => this._randomGet(...args), - sched_yield: (...args) => this._schedYield(...args), - }; - } - - start(instance) { - this.instance = instance; - try { - if (typeof instance?.exports?._start === "function") { - instance.exports._start(); - } - return 0; - } catch (error) { - if (error && error.__agentOSWasiExit === true) { - return Number(error.code) >>> 0; - } - throw error; - } - } - - _memoryView() { - const memory = this.instance?.exports?.memory; - if (!(memory instanceof WebAssembly.Memory)) { - throw new Error("WASI memory export is unavailable"); - } - return new DataView(memory.buffer); - } - - _memoryBytes() { - const memory = this.instance?.exports?.memory; - if (!(memory instanceof WebAssembly.Memory)) { - throw new Error("WASI memory export is unavailable"); - } - return new Uint8Array(memory.buffer); - } - - _boundedIovLength(iovs, iovsLen) { - const view = this._memoryView(); - let length = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - length += view.getUint32(entryOffset + 4, true); - if (length > __agentOSWasmSyncReadLimitBytes) { - throw new RangeError( - `WASI read iov length ${length} exceeds ${__agentOSWasmSyncReadLimitBytes}`, - ); - } - } - return length >>> 0; - } - - // Read-side iov capacity, clamped (not thrown) to the sync read cap. A guest - // may legitimately offer a huge read buffer (e.g. iov_len 0xffffffc0 = "read - // up to ~4GB"); the runner reads only what is available, bounded by the cap, - // so the read allocation/RPC stays bounded without rejecting the read. Writes - // keep using _boundedIovLength (throwing) because their iov length is real - // data that must not be silently truncated. - _boundedReadLength(iovs, iovsLen) { - const view = this._memoryView(); - let length = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - length += view.getUint32(entryOffset + 4, true); - if (length >= __agentOSWasmSyncReadLimitBytes) { - return __agentOSWasmSyncReadLimitBytes; - } - } - return length >>> 0; - } - - _normalizeRights(value, fallback) { - try { - return BigInt.asUintN(64, BigInt(value)); - } catch { - return fallback; - } - } - - _normalizePreopenSpec(value) { - // Path-model seam (convergence item C): native maps guest paths to HOST - // paths (its preopen specs carry `hostPath`); a non-native backend with no - // host paths (the browser, whose `require("fs")` IS the kernel VFS) can - // supply `__agentOSWasiHost.normalizePreopen` to treat the guest/VFS path - // as the "hostPath" identity, so the same runner serves both. - if (typeof __agentOSWasiHost.normalizePreopen === "function") { - const seamNormalized = __agentOSWasiHost.normalizePreopen(value, { - defaultRightsBase: __agentOSWasiDefaultRightsBase, - defaultRightsInheriting: __agentOSWasiDefaultRightsInheriting, - normalizeRights: (rights, fallback) => - this._normalizeRights(rights, fallback), - }); - return seamNormalized ?? null; - } - if (typeof value === "string") { - return { - hostPath: String(value), - readOnly: false, - rightsBase: __agentOSWasiDefaultRightsBase, - rightsInheriting: __agentOSWasiDefaultRightsInheriting, - }; - } - if (!value || typeof value !== "object" || typeof value.hostPath !== "string") { - return null; - } - return { - hostPath: String(value.hostPath), - readOnly: value.readOnly === true, - rightsBase: this._normalizeRights( - value.rightsBase, - __agentOSWasiDefaultRightsBase, - ), - rightsInheriting: this._normalizeRights( - value.rightsInheriting, - __agentOSWasiDefaultRightsInheriting, - ), - }; - } - - _descriptorRightsBase(entry) { - return this._normalizeRights( - entry?.rightsBase, - __agentOSWasiDefaultRightsBase, - ); - } - - _descriptorRightsInheriting(entry) { - return this._normalizeRights( - entry?.rightsInheriting, - __agentOSWasiDefaultRightsInheriting, - ); - } - - _hasWriteRights(rights) { - try { - return (BigInt(rights) & __agentOSWasiRightFdWrite) !== 0n; - } catch { - return true; - } - } - - _writeUint32(ptr, value) { - try { - this._memoryView().setUint32(Number(ptr) >>> 0, Number(value) >>> 0, true); - return __agentOSWasiErrnoSuccess; - } catch { - __agentOSWasiDebug(`writeUint32 failed ptr=${Number(ptr)} value=${Number(value)}`); - return __agentOSWasiErrnoFault; - } - } - - _writeUint64(ptr, value) { - try { - this._memoryView().setBigUint64(Number(ptr) >>> 0, BigInt(value), true); - return __agentOSWasiErrnoSuccess; - } catch { - __agentOSWasiDebug(`writeUint64 failed ptr=${Number(ptr)} value=${String(value)}`); - return __agentOSWasiErrnoFault; - } - } - - _writeBytes(ptr, bytes) { - try { - this._memoryBytes().set(bytes, Number(ptr) >>> 0); - return __agentOSWasiErrnoSuccess; - } catch { - __agentOSWasiDebug(`writeBytes failed ptr=${Number(ptr)} len=${bytes?.length ?? 0}`); - return __agentOSWasiErrnoFault; - } - } - - _readBytes(ptr, len) { - const start = Number(ptr) >>> 0; - const end = start + (Number(len) >>> 0); - return Buffer.from(this._memoryBytes().slice(start, end)); - } - - _readString(ptr, len) { - return this._readBytes(ptr, len).toString("utf8"); - } - - _decodeSyncRpcBytes(value) { - if (value == null) { - return null; - } - if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) { - return value; - } - if (value instanceof Uint8Array) { - return Buffer.from(value); - } - if (ArrayBuffer.isView(value)) { - return Buffer.from(value.buffer, value.byteOffset, value.byteLength); - } - if (value instanceof ArrayBuffer) { - return Buffer.from(value); - } - if ( - value && - typeof value === "object" && - value.__agentOSType === "bytes" && - typeof value.base64 === "string" - ) { - return Buffer.from(value.base64, "base64"); - } - return null; - } - - _dequeuePipeBytes(pipe, maxBytes) { - if (!pipe || !Array.isArray(pipe.chunks) || pipe.chunks.length === 0) { - return Buffer.alloc(0); - } - - let remaining = Math.max(0, Number(maxBytes) >>> 0); - if (remaining === 0) { - return Buffer.alloc(0); - } - - const parts = []; - while (remaining > 0 && pipe.chunks.length > 0) { - const chunk = pipe.chunks[0]; - if (!chunk || chunk.length === 0) { - pipe.chunks.shift(); - continue; - } - - if (chunk.length <= remaining) { - parts.push(chunk); - pipe.chunks.shift(); - remaining -= chunk.length; - continue; - } - - parts.push(chunk.subarray(0, remaining)); - pipe.chunks[0] = chunk.subarray(remaining); - remaining = 0; - } - - return Buffer.concat(parts); - } - - _enqueuePipeBytes(pipe, bytes) { - if (!pipe || !Array.isArray(pipe.chunks)) { - return; - } - const chunk = Buffer.from(bytes ?? []); - if (chunk.length === 0) { - return; - } - pipe.chunks.push(chunk); - } - - _pipeHasReaders(pipe) { - return ( - (pipe?.readHandleCount ?? 0) > 0 || - (pipe?.consumers?.size ?? 0) > 0 - ); - } - - _flushPipeConsumers(pipe) { - if ( - !pipe || - typeof pipe.consumers?.entries !== "function" || - !Array.isArray(pipe.chunks) || - pipe.chunks.length === 0 || - typeof globalThis?.__agentOSSyncRpc?.callSync !== "function" - ) { - return false; - } - - let flushed = false; - while (pipe.chunks.length > 0) { - const chunk = pipe.chunks.shift(); - if (!chunk || chunk.length === 0) { - continue; - } - - for (const [consumerKey, consumer] of Array.from(pipe.consumers.entries())) { - if (!consumer || typeof consumer.childId !== "string") { - pipe.consumers.delete(consumerKey); - continue; - } - try { - __agentOSWasiSyncRpc().callSync("child_process.write_stdin", [ - consumer.childId, - chunk, - ]); - flushed = true; - } catch { - pipe.consumers.delete(consumerKey); - } - } - } - - return flushed; - } - - _closePipeConsumers(pipe) { - if ( - !pipe || - typeof pipe.consumers?.entries !== "function" || - typeof globalThis?.__agentOSSyncRpc?.callSync !== "function" - ) { - return false; - } - - let closed = false; - for (const [consumerKey, consumer] of Array.from(pipe.consumers.entries())) { - if (!consumer || typeof consumer.childId !== "string") { - pipe.consumers.delete(consumerKey); - continue; - } - try { - __agentOSWasiSyncRpc().callSync("child_process.close_stdin", [ - consumer.childId, - ]); - closed = true; - } catch { - // Ignore close errors during teardown. - } - pipe.consumers.delete(consumerKey); - } - - return closed; - } - - _pumpPipeProducers(pipe, waitMs) { - if ( - !pipe || - typeof pipe.producers?.entries !== "function" || - typeof globalThis?.__agentOSSyncRpc?.callSync !== "function" - ) { - return false; - } - - let processed = false; - for (const [producerKey, producer] of Array.from(pipe.producers.entries())) { - if (!producer || typeof producer.childId !== "string") { - pipe.producers.delete(producerKey); - continue; - } - - let event = null; - try { - event = __agentOSWasiSyncRpc().callSync("child_process.poll", [ - producer.childId, - Math.max(0, Number(waitMs) >>> 0), - ]); - } catch { - pipe.producers.delete(producerKey); - continue; - } - - if (!event) { - continue; - } - - processed = true; - const streamType = - producer.stream === "stderr" ? "stderr" : producer.stream === "stdout" ? "stdout" : null; - if ((event.type === "stdout" || event.type === "stderr") && event.type === streamType) { - const chunk = this._decodeSyncRpcBytes(event.data); - if (chunk && chunk.length > 0) { - pipe.chunks.push(Buffer.from(chunk)); - } - continue; - } - - if (event.type === "exit") { - pipe.producers.delete(producerKey); - if (pipe.producers.size === 0 && (pipe.writeHandleCount ?? 0) === 0) { - this._closePipeConsumers(pipe); - } - continue; - } - } - - return processed; - } - - _collectIovs(iovs, iovsLen) { - const totalLength = this._boundedIovLength(iovs, iovsLen); - const view = this._memoryView(); - const chunks = []; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - const ptr = view.getUint32(entryOffset, true); - const len = view.getUint32(entryOffset + 4, true); - chunks.push(this._readBytes(ptr, len)); - } - return Buffer.concat(chunks, totalLength); - } - - _writeToIovs(iovs, iovsLen, bytes) { - const view = this._memoryView(); - const memory = this._memoryBytes(); - let sourceOffset = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0) && sourceOffset < bytes.length; index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - const ptr = view.getUint32(entryOffset, true); - const len = view.getUint32(entryOffset + 4, true); - const chunk = bytes.subarray(sourceOffset, sourceOffset + len); - memory.set(chunk, Number(ptr) >>> 0); - sourceOffset += chunk.length; - } - return sourceOffset; - } - - _stringTable(values) { - return values.map((value) => Buffer.from(`${String(value)}\0`, "utf8")); - } - - _writeStringTable(values, offsetsPtr, bufferPtr) { - try { - const view = this._memoryView(); - const memory = this._memoryBytes(); - let cursor = Number(bufferPtr) >>> 0; - for (let index = 0; index < values.length; index += 1) { - const bytes = values[index]; - view.setUint32((Number(offsetsPtr) >>> 0) + index * 4, cursor, true); - memory.set(bytes, cursor); - cursor += bytes.length; - } - return __agentOSWasiErrnoSuccess; - } catch { - __agentOSWasiDebug( - `writeStringTable failed offsetsPtr=${Number(offsetsPtr)} bufferPtr=${Number(bufferPtr)} count=${values.length}`, - ); - return __agentOSWasiErrnoFault; - } - } - - _filetypeForStats(stats) { - if (!stats) { - return __agentOSWasiFiletypeUnknown; - } - if (typeof stats.isDirectory === "function" && stats.isDirectory()) { - return __agentOSWasiFiletypeDirectory; - } - if (typeof stats.isFile === "function" && stats.isFile()) { - return __agentOSWasiFiletypeRegularFile; - } - if (typeof stats.isSymbolicLink === "function" && stats.isSymbolicLink()) { - return __agentOSWasiFiletypeSymbolicLink; - } - if (typeof stats.isCharacterDevice === "function" && stats.isCharacterDevice()) { - return __agentOSWasiFiletypeCharacterDevice; - } - return __agentOSWasiFiletypeUnknown; - } - - _fdFiletype(entry) { - if (!entry) { - return __agentOSWasiFiletypeUnknown; - } - if ( - entry.kind === "stdin" || - entry.kind === "stdout" || - entry.kind === "stderr" - ) { - return __agentOSWasiFiletypeCharacterDevice; - } - if (entry.kind === "preopen" || entry.kind === "directory") { - return __agentOSWasiFiletypeDirectory; - } - if (entry.kind === "symlink") { - return __agentOSWasiFiletypeSymbolicLink; - } - return __agentOSWasiFiletypeRegularFile; - } - - _mapFsError(error) { - switch (error?.code) { - case "EACCES": - case "EPERM": - return __agentOSWasiErrnoAcces; - case "ENOENT": - return __agentOSWasiErrnoNoent; - case "ENOTDIR": - return __agentOSWasiErrnoNotdir; - case "EEXIST": - return __agentOSWasiErrnoExist; - case "EINVAL": - return __agentOSWasiErrnoInval; - case "EROFS": - return __agentOSWasiErrnoRofs; - case "EXDEV": - return __agentOSWasiErrnoXdev; - default: - return __agentOSWasiErrnoIo; - } - } - - _descriptorEntry(fd) { - return this.fdTable.get(Number(fd) >>> 0) ?? null; - } - - _localFdHandle(fd) { - // A non-native backend whose `realFd` values are not real host OS fds with - // their own kernel offset (the browser, whose fs descriptors are a JS - // handle table) disables local-fd passthrough so locally-opened files use - // the offset-aware file branches (fd_read/fd_write pass the tracked - // entry.offset as an explicit position) instead of host-passthrough reads - // that rely on a null position advancing a real fd. Native keeps passthrough - // so guest-opened fds can be shared with child processes. - if (__agentOSWasiHost.disableLocalFdPassthrough === true) { - return null; - } - const entry = this._descriptorEntry(fd); - if (!entry || typeof entry.realFd !== "number") { - return null; - } - return { - kind: "host-passthrough", - targetFd: entry.realFd, - displayFd: Number(fd) >>> 0, - refCount: 1, - open: true, - readOnly: entry.readOnly === true, - }; - } - - _externalFdHandle(fd) { - const descriptor = Number(fd) >>> 0; - const localHandle = this._localFdHandle(descriptor); - if (localHandle) { - return localHandle; - } - try { - if (typeof lookupFdHandle === "function") { - return lookupFdHandle(descriptor) ?? null; - } - } catch { - // Fall through to other lookup paths. - } - try { - const __agentOSWasiFdHandleFn = __agentOSWasiLookupFdHandle(); - if (typeof __agentOSWasiFdHandleFn === "function") { - return __agentOSWasiFdHandleFn(descriptor) ?? null; - } - } catch { - // Ignore missing global bridge helpers. - } - return null; - } - - _descriptorHostPath(entry) { - if (!entry) { - return null; - } - if (typeof entry.hostPath === "string") { - return entry.hostPath; - } - if (typeof entry.realFd === "number") { - return __agentOSFs().readlinkSync(`/proc/self/fd/${entry.realFd}`); - } - return null; - } - - _descriptorFsPath(entry) { - if (!entry) { - return null; - } - if (typeof entry.hostPath === "string" && entry.hostPath.length > 0) { - return entry.hostPath; - } - if (typeof entry.guestPath === "string" && entry.guestPath.length > 0) { - return entry.guestPath; - } - return null; - } - - _sidecarManagedProcess() { - if ( - typeof globalThis.__agentOSWasmInternalEnv?.AGENTOS_SANDBOX_ROOT === - "string" && - globalThis.__agentOSWasmInternalEnv.AGENTOS_SANDBOX_ROOT.length > 0 - ) { - return true; - } - return ( - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0 - ); - } - - _descriptorDirectoryFsPath(entry) { - if ( - (entry?.kind === "preopen" || entry?.kind === "directory") && - this._sidecarManagedProcess() - ) { - return this._descriptorGuestPath(entry); - } - return this._descriptorFsPath(entry); - } - - _descriptorGuestPath(entry) { - if (!entry) { - return null; - } - const guestPath = typeof entry.guestPath === "string" ? entry.guestPath : null; - if (guestPath === ".") { - return this._currentGuestCwd(); - } - if (typeof guestPath === "string" && guestPath.length > 0) { - return __agentOSPath().posix.normalize(guestPath); - } - return null; - } - - _descriptorPreopenName(entry) { - if (!entry) { - return null; - } - const guestPath = typeof entry.guestPath === "string" ? entry.guestPath : null; - if (guestPath === ".") { - return this._descriptorGuestPath(entry); - } - if (typeof guestPath === "string" && guestPath.length > 0) { - return __agentOSPath().posix.normalize(guestPath); - } - return null; - } - - _currentDirectoryPreopen() { - for (const entry of this.fdTable.values()) { - if (entry?.kind === "preopen" && entry.guestPath === ".") { - return entry; - } - } - return null; - } - - _descriptorPathBase(entry, target) { - const baseGuestPath = this._descriptorGuestPath(entry); - if (typeof baseGuestPath !== "string") { - return null; - } - return { - entry, - guestPath: baseGuestPath, - hostPath: typeof entry?.hostPath === "string" ? entry.hostPath : null, - }; - } - - _hostPathExists(hostPath) { - try { - __agentOSFs().statSync(hostPath); - return true; - } catch { - return false; - } - } - - _currentGuestCwd() { - const pwd = - typeof this.env?.PWD === "string" && this.env.PWD.startsWith("/") - ? this.env.PWD - : typeof this.env?.HOME === "string" && this.env.HOME.startsWith("/") - ? this.env.HOME - : "/"; - return __agentOSPath().posix.normalize(pwd); - } - - _resolveHostMappingForGuestPath(guestPath) { - const normalized = __agentOSPath().posix.normalize(guestPath); - const mappings = []; - for (const entry of this.fdTable.values()) { - if (entry?.kind !== "preopen" || typeof entry.hostPath !== "string") { - continue; - } - const guestRoot = this._descriptorGuestPath(entry); - if (typeof guestRoot !== "string") { - continue; - } - mappings.push({ - guestRoot, - hostPath: entry.hostPath, - readOnly: entry.readOnly === true, - }); - } - mappings.sort((left, right) => right.guestRoot.length - left.guestRoot.length); - - for (const mapping of mappings) { - const matchesRoot = mapping.guestRoot === "/" && normalized.startsWith("/"); - const matchesNested = - normalized === mapping.guestRoot || - normalized.startsWith(`${mapping.guestRoot}/`); - if (!matchesRoot && !matchesNested) { - continue; - } - const suffix = - normalized === mapping.guestRoot - ? "" - : mapping.guestRoot === "/" - ? normalized.slice(1) - : normalized.slice(mapping.guestRoot.length + 1); - return { - hostPath: suffix - ? __agentOSPath().join(mapping.hostPath, ...suffix.split("/")) - : mapping.hostPath, - readOnly: mapping.readOnly, - }; - } - - return null; - } - - _resolveHostPathForGuestPath(guestPath) { - return this._resolveHostMappingForGuestPath(guestPath)?.hostPath ?? null; - } - - _rootRelativeTargetPrefersCwd(target) { - const normalizedTarget = __agentOSPath().posix.normalize(target || "."); - if (normalizedTarget !== ".") { - return false; - } - return !this._rootRelativeTargetMatchesAbsoluteArg(target); - } - - _rootRelativeTargetMatchesAbsoluteArg(target) { - const rootGuestPath = __agentOSPath().posix.resolve("/", target); - return this.args - .slice(1) - .some( - (arg) => - typeof arg === "string" && - arg.startsWith("/") && - __agentOSPath().posix.normalize(arg) === rootGuestPath, - ); - } - - _resolveRootRelativePath(target, preferCreateParent = false) { - const rootGuestPath = __agentOSPath().posix.resolve("/", target); - const rootMapping = this._resolveHostMappingForGuestPath(rootGuestPath); - const rootHostPath = rootMapping?.hostPath ?? null; - const cwdGuestPath = this._currentGuestCwd(); - if (cwdGuestPath !== "/") { - const cwdGuestTarget = __agentOSPath().posix.resolve(cwdGuestPath, target); - const cwdMapping = this._resolveHostMappingForGuestPath(cwdGuestTarget); - const cwdHostTarget = cwdMapping?.hostPath ?? null; - if ( - typeof cwdHostTarget === "string" && - ( - (preferCreateParent && !this._rootRelativeTargetMatchesAbsoluteArg(target)) || - this._rootRelativeTargetPrefersCwd(target) || - ( - this._hostPathExists(cwdHostTarget) && - !(typeof rootHostPath === "string" && this._hostPathExists(rootHostPath)) - ) - ) - ) { - return { - guestPath: cwdGuestTarget, - hostPath: cwdHostTarget, - readOnly: cwdMapping?.readOnly === true, - }; - } - } - return { - guestPath: rootGuestPath, - hostPath: rootHostPath, - readOnly: rootMapping?.readOnly === true, - }; - } - - _resolveDescriptorPath(fd, pathPtr, pathLen, options = {}) { - const entry = this._descriptorEntry(fd); - if (!entry) { - return { error: __agentOSWasiErrnoBadf }; - } - const target = this._readString(pathPtr, pathLen); - const base = this._descriptorPathBase(entry, target); - if (!base || typeof base.guestPath !== "string") { - return { error: __agentOSWasiErrnoBadf }; - } - const guestPath = target.startsWith("/") - ? __agentOSPath().posix.normalize(target) - : __agentOSPath().posix.resolve(base.guestPath, target); - const mapped = - base.guestPath === "/" && !target.startsWith("/") - ? this._resolveRootRelativePath( - target, - options.preferCreateParent === true, - ) - : { - guestPath, - ...( - this._resolveHostMappingForGuestPath(guestPath) ?? - { hostPath: null, readOnly: false } - ), - }; - const hostPath = mapped.hostPath; - if (typeof hostPath !== "string") { - return { error: __agentOSWasiErrnoNoent }; - } - return { - error: __agentOSWasiErrnoSuccess, - guestPath: mapped.guestPath, - hostPath, - readOnly: mapped.readOnly === true, - }; - } - - _resolvedFsPath(resolved) { - if (this._sidecarManagedProcess() && typeof resolved?.guestPath === "string") { - return resolved.guestPath; - } - return resolved?.hostPath ?? null; - } - - _writeFilestat(statPtr, stats, fallbackType) { - try { - const view = this._memoryView(); - const offset = Number(statPtr) >>> 0; - const filetype = stats ? this._filetypeForStats(stats) : fallbackType; - view.setBigUint64(offset, 0n, true); - view.setBigUint64(offset + 8, BigInt(stats?.ino ?? 0), true); - view.setUint8(offset + 16, filetype); - view.setBigUint64(offset + 24, BigInt(stats?.nlink ?? 1), true); - view.setBigUint64(offset + 32, BigInt(stats?.size ?? 0), true); - view.setBigUint64(offset + 40, BigInt(Math.trunc((stats?.atimeMs ?? 0) * 1000000)), true); - view.setBigUint64(offset + 48, BigInt(Math.trunc((stats?.mtimeMs ?? 0) * 1000000)), true); - view.setBigUint64(offset + 56, BigInt(Math.trunc((stats?.ctimeMs ?? 0) * 1000000)), true); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _argsSizesGet(argcPtr, argvBufSizePtr) { - const values = this._stringTable(this.args); - const total = values.reduce((sum, value) => sum + value.length, 0); - const argcStatus = this._writeUint32(argcPtr, values.length); - if (argcStatus !== __agentOSWasiErrnoSuccess) { - return argcStatus; - } - return this._writeUint32(argvBufSizePtr, total); - } - - _argsGet(argvPtr, argvBufPtr) { - return this._writeStringTable(this._stringTable(this.args), argvPtr, argvBufPtr); - } - - _environEntries() { - return Object.entries(this.env).map(([key, value]) => `${key}=${value}`); - } - - _environSizesGet(countPtr, bufSizePtr) { - const values = this._stringTable(this._environEntries()); - const total = values.reduce((sum, value) => sum + value.length, 0); - const countStatus = this._writeUint32(countPtr, values.length); - if (countStatus !== __agentOSWasiErrnoSuccess) { - return countStatus; - } - return this._writeUint32(bufSizePtr, total); - } - - _environGet(environPtr, environBufPtr) { - return this._writeStringTable( - this._stringTable(this._environEntries()), - environPtr, - environBufPtr, - ); - } - - _clockTimeGet(_clockId, _precision, resultPtr) { - return this._writeUint64(resultPtr, BigInt(Date.now()) * 1000000n); - } - - _clockResGet(_clockId, resultPtr) { - return this._writeUint64(resultPtr, 1000000n); - } - - _fdWrite(fd, iovs, iovsLen, nwrittenPtr) { - try { - const bytes = this._collectIovs(iovs, iovsLen); - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - if (handle?.kind === "pipe-write" && handle.pipe) { - if (bytes.length > 0 && !this._pipeHasReaders(handle.pipe)) { - return __agentOSWasiErrnoPipe; - } - this._enqueuePipeBytes(handle.pipe, bytes); - this._flushPipeConsumers(handle.pipe); - return this._writeUint32(nwrittenPtr, bytes.length); - } - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - if (handle.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - if (descriptor === 1 || descriptor === 2) { - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - const useKernelStdioSyncRpc = - sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled(); - if (useKernelStdioSyncRpc) { - const written = Number( - __agentOSWasiSyncRpc().callSync("__kernel_stdio_write", [descriptor, bytes]), - ) >>> 0; - return this._writeUint32(nwrittenPtr, written); - } - } - const written = __agentOSFs().writeSync( - handle.targetFd, - bytes, - 0, - bytes.length, - null, - ); - return this._writeUint32(nwrittenPtr, written); - } - if (handle?.kind === "guest-file" && typeof handle.targetFd === "number") { - const position = handle.append ? null : (handle.position ?? 0); - const written = __agentOSFs().writeSync( - handle.targetFd, - bytes, - 0, - bytes.length, - position, - ); - if (handle.append) { - handle.position = Number(__agentOSFs().fstatSync(handle.targetFd).size ?? 0); - } else { - handle.position = (handle.position ?? 0) + written; - } - return this._writeUint32(nwrittenPtr, written); - } - if (handle?.kind === "stdio" && typeof handle.targetFd === "number") { - const targetFd = Number(handle.targetFd) >>> 0; - if (targetFd === 1 || targetFd === 2) { - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - const useKernelStdioSyncRpc = - sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled(); - const written = useKernelStdioSyncRpc - ? Number(__agentOSWasiSyncRpc().callSync("__kernel_stdio_write", [targetFd, bytes])) >>> 0 - : (targetFd === 2 ? process.stderr.write(bytes) : process.stdout.write(bytes), bytes.length); - return this._writeUint32(nwrittenPtr, written); - } - return __agentOSWasiErrnoBadf; - } - const entry = this.fdTable.get(descriptor); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - if (entry.kind === "stdout") { - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - const useKernelStdioSyncRpc = - sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled(); - const written = useKernelStdioSyncRpc - ? Number(__agentOSWasiSyncRpc().callSync("__kernel_stdio_write", [1, bytes])) >>> 0 - : (process.stdout.write(bytes), bytes.length); - return this._writeUint32(nwrittenPtr, written); - } - if (entry.kind === "stderr") { - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - const useKernelStdioSyncRpc = - sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled(); - const written = useKernelStdioSyncRpc - ? Number(__agentOSWasiSyncRpc().callSync("__kernel_stdio_write", [2, bytes])) >>> 0 - : (process.stderr.write(bytes), bytes.length); - return this._writeUint32(nwrittenPtr, written); - } - if (entry.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - if (entry.kind === "file") { - const position = typeof entry.offset === "number" ? entry.offset : null; - const written = __agentOSFs().writeSync( - entry.realFd, - bytes, - 0, - bytes.length, - position, - ); - if (typeof entry.offset === "number") { - entry.offset += written; - } - return this._writeUint32(nwrittenPtr, written); - } - return __agentOSWasiErrnoBadf; - } catch (error) { - return this._mapFsError(error); - } - } - - _fdPwrite(fd, iovs, iovsLen, offset, nwrittenPtr) { - try { - const bytes = this._collectIovs(iovs, iovsLen); - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - if (handle.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - const written = __agentOSFs().writeSync( - handle.targetFd, - bytes, - 0, - bytes.length, - Number(offset) >>> 0, - ); - return this._writeUint32(nwrittenPtr, written); - } - const entry = this.fdTable.get(descriptor); - if (!entry || entry.kind !== "file") { - return __agentOSWasiErrnoBadf; - } - if (entry.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - const written = __agentOSFs().writeSync( - entry.realFd, - bytes, - 0, - bytes.length, - Number(offset) >>> 0, - ); - return this._writeUint32(nwrittenPtr, written); - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdPread(fd, iovs, iovsLen, offset, nreadPtr) { - try { - const descriptor = Number(fd) >>> 0; - const explicitOffset = Number(offset) >>> 0; - const totalLength = this._boundedReadLength(iovs, iovsLen); - const buffer = Buffer.alloc(totalLength); - const handle = this._externalFdHandle(descriptor); - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - const bytesRead = __agentOSFs().readSync( - handle.targetFd, - buffer, - 0, - totalLength, - explicitOffset, - ); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } - const entry = this.fdTable.get(descriptor); - if (!entry || entry.kind !== "file") { - return __agentOSWasiErrnoBadf; - } - const bytesRead = __agentOSFs().readSync( - entry.realFd, - buffer, - 0, - totalLength, - explicitOffset, - ); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdRead(fd, iovs, iovsLen, nreadPtr) { - try { - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - if (handle?.kind === "pipe-read" && handle.pipe) { - const totalLength = this._boundedReadLength(iovs, iovsLen); - while (handle.pipe.chunks.length === 0) { - if (handle.pipe.writeHandleCount === 0 && handle.pipe.producers.size === 0) { - return this._writeUint32(nreadPtr, 0); - } - this._pumpPipeProducers(handle.pipe, 10); - } - const chunk = this._dequeuePipeBytes(handle.pipe, totalLength); - const written = this._writeToIovs(iovs, iovsLen, chunk); - return this._writeUint32(nreadPtr, written); - } - if (handle?.kind === "stdio" && Number(handle.targetFd) === 0) { - const totalLength = this._boundedReadLength(iovs, iovsLen); - if (typeof __agentOSWasiHost.readStdin === "function") { - const value = __agentOSWasiHost.readStdin(totalLength); - if (value == null) { - return this._writeUint32(nreadPtr, 0); - } - const chunk = - typeof value === "string" - ? Buffer.from(value, "utf8") - : value instanceof Uint8Array - ? value - : Buffer.from(value); - if (chunk.length === 0) { - return this._writeUint32(nreadPtr, 0); - } - const written = this._writeToIovs(iovs, iovsLen, chunk); - return this._writeUint32(nreadPtr, written); - } - const buffer = Buffer.alloc(totalLength); - const bytesRead = __agentOSFs().readSync(0, buffer, 0, totalLength, null); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } - const entry = this.fdTable.get(descriptor); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - if (entry.kind === "stdin") { - const totalLength = this._boundedReadLength(iovs, iovsLen); - const syncRpc = - typeof globalThis?.__agentOSSyncRpc?.callSync === "function" - ? __agentOSWasiSyncRpc() - : null; - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === "string" && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - if (syncRpc && (sidecarManagedProcess || __agentOSKernelStdioSyncRpcEnabled())) { - try { - let chunk = null; - while (true) { - const response = syncRpc.callSync("__kernel_stdin_read", [totalLength, 10]); - if ( - response && - typeof response === "object" && - typeof response.dataBase64 === "string" - ) { - chunk = Buffer.from(response.dataBase64, "base64"); - break; - } - if (response && typeof response === "object" && response.done === true) { - chunk = Buffer.alloc(0); - break; - } - if ( - typeof Atomics?.wait === "function" && - typeof syntheticWaitArray !== "undefined" - ) { - Atomics.wait(syntheticWaitArray, 0, 0, 10); - } - } - if (!chunk || chunk.length === 0) { - return this._writeUint32(nreadPtr, 0); - } - const written = this._writeToIovs(iovs, iovsLen, chunk); - return this._writeUint32(nreadPtr, written); - } catch { - // Fall back to direct stdin reads when the sync bridge is unavailable - // in the standalone runner bootstrap. - } - } - // Host-seam stdin (a non-native backend whose stdin is delivered through - // the runtime process object, not a kernel fd): read the queued bytes - // directly instead of fs.readSync on a descriptor the JS fs table does - // not own. - if (typeof __agentOSWasiHost.readStdin === "function") { - const value = __agentOSWasiHost.readStdin(totalLength); - if (value == null) { - return this._writeUint32(nreadPtr, 0); - } - const chunk = - typeof value === "string" - ? Buffer.from(value, "utf8") - : value instanceof Uint8Array - ? value - : Buffer.from(value); - if (chunk.length === 0) { - return this._writeUint32(nreadPtr, 0); - } - const written = this._writeToIovs(iovs, iovsLen, chunk); - return this._writeUint32(nreadPtr, written); - } - const buffer = Buffer.alloc(totalLength); - const directStdinFd = - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ? handle.targetFd - : typeof process?.stdin?.fd === "number" - ? process.stdin.fd - : 0; - const bytesRead = __agentOSFs().readSync( - directStdinFd, - buffer, - 0, - totalLength, - null, - ); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - const totalLength = this._boundedReadLength(iovs, iovsLen); - const buffer = Buffer.alloc(totalLength); - const bytesRead = __agentOSFs().readSync( - handle.targetFd, - buffer, - 0, - totalLength, - null, - ); - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } - if (entry.kind !== "file") { - return __agentOSWasiErrnoBadf; - } - // WASI rights: a descriptor opened without FD_READ cannot be read. - if ( - typeof entry.rightsBase === "bigint" && - (entry.rightsBase & __agentOSWasiRightFdRead) === 0n - ) { - return __agentOSWasiErrnoNotcapable; - } - const totalLength = this._boundedReadLength(iovs, iovsLen); - const buffer = Buffer.alloc(totalLength); - const position = typeof entry.offset === "number" ? entry.offset : null; - const bytesRead = __agentOSFs().readSync( - entry.realFd, - buffer, - 0, - totalLength, - position, - ); - if (typeof entry.offset === "number") { - entry.offset += bytesRead; - } - const written = this._writeToIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return this._writeUint32(nreadPtr, written); - } catch (error) { - return this._mapFsError(error); - } - } - - _fdClose(fd) { - try { - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - if (handle?.kind === "pipe-read" && handle.pipe) { - handle.open = false; - handle.pipe.readHandleCount = Math.max(0, (handle.pipe.readHandleCount ?? 0) - 1); - if (typeof handle.onClose === "function") { - handle.onClose(handle, descriptor); - } - return __agentOSWasiErrnoSuccess; - } - if (handle?.kind === "pipe-write" && handle.pipe) { - handle.open = false; - handle.pipe.writeHandleCount = Math.max(0, (handle.pipe.writeHandleCount ?? 0) - 1); - if (typeof handle.onClose === "function") { - handle.onClose(handle, descriptor); - } - return __agentOSWasiErrnoSuccess; - } - if (handle?.kind === "guest-file" || handle?.kind === "stdio") { - handle.open = false; - return __agentOSWasiErrnoSuccess; - } - const entry = this.fdTable.get(descriptor); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - const retainedDelegateRefs = (() => { - try { - if (typeof globalThis.__agentOSWasiDelegateFdRefCount === "function") { - return Number(globalThis.__agentOSWasiDelegateFdRefCount(descriptor)) || 0; - } - } catch { - // Fall through to the default close path. - } - return 0; - })(); - if (entry.kind === "file" && retainedDelegateRefs <= 0) { - __agentOSFs().closeSync(entry.realFd); - } - if (descriptor > 2 && retainedDelegateRefs <= 0) { - this.fdTable.delete(descriptor); - } - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdSync(fd) { - try { - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - __agentOSFs().fsyncSync(handle.targetFd); - return __agentOSWasiErrnoSuccess; - } - const entry = this.fdTable.get(descriptor); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - // fsync on a stdio stream (stdin/stdout/stderr) is a no-op success; only - // descriptors with a real backing fd are flushed. - if ( - entry.kind === "stdin" || - entry.kind === "stdout" || - entry.kind === "stderr" - ) { - return __agentOSWasiErrnoSuccess; - } - if (entry.kind !== "file" || typeof entry.realFd !== "number") { - return __agentOSWasiErrnoBadf; - } - __agentOSFs().fsyncSync(entry.realFd); - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdFdstatGet(fd, statPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - const view = this._memoryView(); - const offset = Number(statPtr) >>> 0; - view.setUint8(offset, this._fdFiletype(entry)); - view.setUint16(offset + 2, (Number(entry.fdFlags) >>> 0) & 0xffff, true); - view.setBigUint64(offset + 8, this._descriptorRightsBase(entry), true); - view.setBigUint64(offset + 16, this._descriptorRightsInheriting(entry), true); - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdFdstatSetFlags(fd, flags) { - try { - const entry = this._descriptorEntry(fd); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - entry.fdFlags = (Number(flags) >>> 0) & 0xffff; - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdFilestatGet(fd, statPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry) { - return __agentOSWasiErrnoBadf; - } - if ( - entry.kind === "stdin" || - entry.kind === "stdout" || - entry.kind === "stderr" - ) { - return this._writeFilestat(statPtr, null, __agentOSWasiFiletypeCharacterDevice); - } - if (entry.kind === "preopen") { - const stats = __agentOSFs().statSync(entry.guestPath); - return this._writeFilestat(statPtr, stats, __agentOSWasiFiletypeDirectory); - } - const stats = - typeof entry.realFd === "number" - ? __agentOSFs().fstatSync(entry.realFd) - : __agentOSFs().statSync(this._descriptorFsPath(entry)); - return this._writeFilestat(statPtr, stats, this._fdFiletype(entry)); - } catch (error) { - return this._mapFsError(error); - } - } - - _fdFilestatSetSize(fd, size) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "file" || typeof entry.realFd !== "number") { - return __agentOSWasiErrnoBadf; - } - if (entry.readOnly === true) { - return __agentOSWasiErrnoRofs; - } - __agentOSFs().ftruncateSync(entry.realFd, Number(size)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _fdSeek(fd, offset, whence, newOffsetPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "file" || typeof entry.realFd !== "number") { - return __agentOSWasiErrnoBadf; - } - const delta = Number(offset); - if (!Number.isFinite(delta)) { - return __agentOSWasiErrnoInval; - } - const currentOffset = typeof entry.offset === "number" ? entry.offset : 0; - let nextOffset = 0; - switch (Number(whence) >>> 0) { - case __agentOSWasiWhenceSet: - nextOffset = delta; - break; - case __agentOSWasiWhenceCur: - nextOffset = currentOffset + delta; - break; - case __agentOSWasiWhenceEnd: { - const stats = __agentOSFs().fstatSync(entry.realFd); - nextOffset = Number(stats?.size ?? 0) + delta; - break; - } - default: - return __agentOSWasiErrnoInval; - } - if (!Number.isFinite(nextOffset) || nextOffset < 0) { - return __agentOSWasiErrnoInval; - } - entry.offset = nextOffset; - return this._writeUint64(newOffsetPtr, BigInt(nextOffset)); - } catch (error) { - return this._mapFsError(error); - } - } - - _fdTell(fd, offsetPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "file") { - return __agentOSWasiErrnoBadf; - } - const offset = typeof entry.offset === "number" ? entry.offset : 0; - return this._writeUint64(offsetPtr, BigInt(offset)); - } catch (error) { - return this._mapFsError(error); - } - } - - _fdPrestatGet(fd, prestatPtr) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "preopen") { - return __agentOSWasiErrnoBadf; - } - const guestPath = this._descriptorPreopenName(entry); - if (typeof guestPath !== "string") { - return __agentOSWasiErrnoBadf; - } - const view = this._memoryView(); - const offset = Number(prestatPtr) >>> 0; - view.setUint8(offset, 0); - view.setUint32(offset + 4, Buffer.byteLength(guestPath), true); - return __agentOSWasiErrnoSuccess; - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdPrestatDirName(fd, pathPtr, pathLen) { - try { - const entry = this._descriptorEntry(fd); - if (!entry || entry.kind !== "preopen") { - return __agentOSWasiErrnoBadf; - } - const guestPath = this._descriptorPreopenName(entry); - if (typeof guestPath !== "string") { - return __agentOSWasiErrnoBadf; - } - const bytes = Buffer.from(guestPath, "utf8"); - if ((Number(pathLen) >>> 0) < bytes.length) { - return __agentOSWasiErrnoFault; - } - return this._writeBytes(pathPtr, bytes); - } catch { - return __agentOSWasiErrnoFault; - } - } - - _fdReaddir(fd, bufPtr, bufLen, cookie, bufUsedPtr) { - try { - const entry = this._descriptorEntry(fd); - const fsPath = this._descriptorDirectoryFsPath(entry); - if ( - !entry || - (entry.kind !== "preopen" && entry.kind !== "directory") || - typeof fsPath !== "string" - ) { - return __agentOSWasiErrnoBadf; - } - const dirents = __agentOSFs() - .readdirSync(fsPath, { withFileTypes: true }) - .sort((left, right) => left.name.localeCompare(right.name)); - const view = this._memoryView(); - const memory = this._memoryBytes(); - let offset = Number(bufPtr) >>> 0; - const limit = offset + (Number(bufLen) >>> 0); - let used = 0; - for (let index = Number(cookie) >>> 0; index < dirents.length; index += 1) { - const dirent = dirents[index]; - const nameBytes = Buffer.from(dirent.name, "utf8"); - const recordLen = 24 + nameBytes.length; - if (offset + recordLen > limit) { - break; - } - view.setBigUint64(offset, BigInt(index + 1), true); - view.setBigUint64(offset + 8, BigInt(index + 1), true); - view.setUint32(offset + 16, nameBytes.length, true); - view.setUint8( - offset + 20, - dirent.isDirectory() - ? __agentOSWasiFiletypeDirectory - : dirent.isSymbolicLink() - ? __agentOSWasiFiletypeSymbolicLink - : __agentOSWasiFiletypeRegularFile, - ); - memory.set(nameBytes, offset + 24); - offset += recordLen; - used += recordLen; - } - return this._writeUint32(bufUsedPtr, used); - } catch (error) { - return this._mapFsError(error); - } - } - - _pathCreateDirectory(fd, pathPtr, pathLen) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - if (resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - __agentOSFs().mkdirSync(this._resolvedFsPath(resolved)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathLink(oldFd, _oldFlags, oldPathPtr, oldPathLen, newFd, newPathPtr, newPathLen) { - try { - const source = this._resolveDescriptorPath(oldFd, oldPathPtr, oldPathLen); - if (source.error !== __agentOSWasiErrnoSuccess) { - return source.error; - } - const destination = this._resolveDescriptorPath(newFd, newPathPtr, newPathLen); - if (destination.error !== __agentOSWasiErrnoSuccess) { - return destination.error; - } - if (source.readOnly || destination.readOnly) { - return __agentOSWasiErrnoRofs; - } - __agentOSFs().linkSync(this._resolvedFsPath(source), this._resolvedFsPath(destination)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathOpen(fd, _dirflags, pathPtr, pathLen, oflags, rightsBase, rightsInheriting, _fdflags, openedFdPtr) { - try { - const entry = this._descriptorEntry(fd); - if ( - !entry || - (entry.kind !== "preopen" && entry.kind !== "directory") || - typeof entry.hostPath !== "string" - ) { - return __agentOSWasiErrnoBadf; - } - const requestedFlags = Number(oflags) >>> 0; - const createOrTruncate = - (requestedFlags & __agentOSWasiOpenCreate) !== 0 || - (requestedFlags & __agentOSWasiOpenTruncate) !== 0; - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen, { - preferCreateParent: createOrTruncate, - }); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - const guestPath = resolved.guestPath; - const fsPath = this._resolvedFsPath(resolved); - const openDirectory = (requestedFlags & __agentOSWasiOpenDirectory) !== 0; - const allowedRightsBase = this._descriptorRightsBase(entry); - const allowedRightsInheriting = this._descriptorRightsInheriting(entry); - const requestedRightsBase = this._normalizeRights(rightsBase, allowedRightsInheriting); - const requestedRightsInheriting = this._normalizeRights( - rightsInheriting, - allowedRightsInheriting, - ); - if ( - (requestedRightsBase & ~allowedRightsInheriting) !== 0n || - (requestedRightsInheriting & ~allowedRightsInheriting) !== 0n - ) { - return __agentOSWasiErrnoAcces; - } - const requestedWriteAccess = - !openDirectory && - (createOrTruncate || this._hasWriteRights(requestedRightsBase)); - if ( - requestedWriteAccess && - !this._hasWriteRights(allowedRightsBase) - ) { - return __agentOSWasiErrnoAcces; - } - if (requestedWriteAccess && resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - const fsConstants = __agentOSFs().constants ?? {}; - let openFlags = requestedWriteAccess - ? fsConstants.O_RDWR ?? 2 - : fsConstants.O_RDONLY ?? 0; - if ((requestedFlags & __agentOSWasiOpenCreate) !== 0) { - openFlags |= fsConstants.O_CREAT ?? 64; - } - if ((requestedFlags & __agentOSWasiOpenExclusive) !== 0) { - openFlags |= fsConstants.O_EXCL ?? 128; - } - if ((requestedFlags & __agentOSWasiOpenTruncate) !== 0) { - openFlags |= fsConstants.O_TRUNC ?? 512; - } - if (openDirectory) { - openFlags |= fsConstants.O_DIRECTORY ?? 0; - } - if (createOrTruncate && !openDirectory) { - __agentOSFs().statSync(__agentOSPath().dirname(fsPath)); - } else { - __agentOSFs().statSync(fsPath); - } - const realFd = __agentOSFs().openSync(fsPath, openFlags); - const stats = - createOrTruncate && !openDirectory - ? __agentOSFs().fstatSync(realFd) - : __agentOSFs().statSync(fsPath); - const openedFd = this.nextFd++; - this.fdTable.set(openedFd, { - kind: stats.isDirectory() ? "directory" : "file", - guestPath, - hostPath: fsPath, - readOnly: resolved.readOnly === true, - realFd, - offset: 0, - rightsBase: requestedRightsBase & allowedRightsInheriting, - rightsInheriting: requestedRightsInheriting & allowedRightsInheriting, - fdFlags: (Number(_fdflags) >>> 0) & 0xffff, - }); - return this._writeUint32(openedFdPtr, openedFd); - } catch (error) { - return this._mapFsError(error); - } - } - - _pathSymlink(targetPtr, targetLen, fd, pathPtr, pathLen) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - if (resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - const target = this._readString(targetPtr, targetLen); - __agentOSFs().symlinkSync(target, this._resolvedFsPath(resolved)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathRemoveDirectory(fd, pathPtr, pathLen) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - if (resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - __agentOSFs().rmdirSync(this._resolvedFsPath(resolved)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathRename(oldFd, oldPathPtr, oldPathLen, newFd, newPathPtr, newPathLen) { - try { - const source = this._resolveDescriptorPath(oldFd, oldPathPtr, oldPathLen); - if (source.error !== __agentOSWasiErrnoSuccess) { - return source.error; - } - const destination = this._resolveDescriptorPath(newFd, newPathPtr, newPathLen); - if (destination.error !== __agentOSWasiErrnoSuccess) { - return destination.error; - } - if (source.readOnly || destination.readOnly) { - return __agentOSWasiErrnoRofs; - } - __agentOSFs().renameSync(this._resolvedFsPath(source), this._resolvedFsPath(destination)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathUnlinkFile(fd, pathPtr, pathLen) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - if (resolved.readOnly) { - return __agentOSWasiErrnoRofs; - } - __agentOSFs().unlinkSync(this._resolvedFsPath(resolved)); - return __agentOSWasiErrnoSuccess; - } catch (error) { - return this._mapFsError(error); - } - } - - _pathFilestatGet(fd, flags, pathPtr, pathLen, statPtr) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - const follow = (Number(flags) & __agentOSWasiLookupSymlinkFollow) !== 0; - const stats = follow - ? __agentOSFs().statSync(this._resolvedFsPath(resolved)) - : __agentOSFs().lstatSync(this._resolvedFsPath(resolved)); - return this._writeFilestat(statPtr, stats, this._filetypeForStats(stats)); - } catch (error) { - return this._mapFsError(error); - } - } - - _pathReadlink(fd, pathPtr, pathLen, bufPtr, bufLen, bufUsedPtr) { - try { - const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen); - if (resolved.error !== __agentOSWasiErrnoSuccess) { - return resolved.error; - } - const bytes = Buffer.from(__agentOSFs().readlinkSync(resolved.guestPath), "utf8"); - const length = Math.min(bytes.length, Number(bufLen) >>> 0); - const writeStatus = this._writeBytes(bufPtr, bytes.subarray(0, length)); - if (writeStatus !== __agentOSWasiErrnoSuccess) { - return writeStatus; - } - return this._writeUint32(bufUsedPtr, length); - } catch (error) { - return this._mapFsError(error); - } - } - - _pollOneoff(inPtr, outPtr, nsubscriptions, neventsPtr) { - try { - const subscriptionCount = Number(nsubscriptions) >>> 0; - if (subscriptionCount === 0) { - return this._writeUint32(neventsPtr, 0); - } - - const subscriptionSize = 48; - const eventSize = 32; - const kernelPollIn = 0x0001; - const kernelPollOut = 0x0004; - const kernelPollErr = 0x0008; - const kernelPollHup = 0x0010; - const view = this._memoryView(); - const memory = this._memoryBytes(); - const syncRpc = - typeof globalThis?.__agentOSSyncRpc?.callSync === "function" - ? __agentOSWasiSyncRpc() - : null; - const subscriptions = []; - let timeoutMs = null; - - for (let index = 0; index < subscriptionCount; index += 1) { - const base = (Number(inPtr) >>> 0) + index * subscriptionSize; - const tag = view.getUint8(base + 8); - const userdata = memory.slice(base, base + 8); - if (tag === 0) { - const timeoutNs = view.getBigUint64(base + 24, true); - const relativeTimeoutMs = Number(timeoutNs / 1000000n); - timeoutMs = - timeoutMs == null ? relativeTimeoutMs : Math.min(timeoutMs, relativeTimeoutMs); - subscriptions.push({ kind: "clock", userdata }); - continue; - } - - if (tag !== 1 && tag !== 2) { - subscriptions.push({ kind: "unsupported", userdata }); - continue; - } - - const fd = view.getUint32(base + 16, true); - const descriptor = Number(fd) >>> 0; - const handle = this._externalFdHandle(descriptor); - const entry = this._descriptorEntry(descriptor); - let targetFd = null; - if ( - (handle?.kind === "passthrough" || handle?.kind === "host-passthrough") && - typeof handle.targetFd === "number" - ) { - targetFd = Number(handle.targetFd) >>> 0; - } else if ( - entry?.kind === "stdin" || - entry?.kind === "stdout" || - entry?.kind === "stderr" - ) { - targetFd = descriptor; - } - - subscriptions.push({ - kind: tag === 1 ? "fd_read" : "fd_write", - fd: descriptor, - handle, - targetFd, - streamKind: entry?.kind, - userdata, - }); - } - - const deadline = timeoutMs == null ? null : Date.now() + Math.max(0, timeoutMs); - const readyEvents = []; - - while (readyEvents.length === 0) { - for (const subscription of subscriptions) { - // A clock subscription is ready once its deadline has elapsed; report - // it as a first-class event so it is returned alongside any ready fds - // (not only as a fallback when nothing else is ready). - if (subscription.kind === "clock") { - if (deadline != null && Date.now() >= deadline) { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 0, - nbytes: 0, - flags: 0, - }); - } - continue; - } - if (subscription.kind === "fd_read" && subscription.handle?.kind === "pipe-read") { - const pipe = subscription.handle.pipe; - if ( - pipe && - (pipe.chunks.length > 0 || - (pipe.writeHandleCount === 0 && pipe.producers.size === 0)) - ) { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 1, - nbytes: pipe.chunks[0]?.length ?? 0, - flags: 0, - }); - } - continue; - } - - // Without a kernel poll bridge, resolve stdin fd_read readiness from - // the host-seam queued byte count (the browser delivers stdin through - // the runtime process object). Reporting nbytes does not consume input. - if ( - !syncRpc && - subscription.kind === "fd_read" && - subscription.streamKind === "stdin" && - typeof __agentOSWasiHost.stdinReadableBytes === "function" - ) { - const available = Number(__agentOSWasiHost.stdinReadableBytes()) >>> 0; - if (available > 0) { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 1, - nbytes: available, - flags: 0, - }); - } - continue; - } - - if (subscription.kind === "fd_write" && subscription.handle?.kind === "pipe-write") { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 2, - nbytes: 65536, - flags: 0, - }); - continue; - } - - // Without a kernel poll bridge (a non-native backend) stdout/stderr - // are always writable, so resolve their fd_write readiness directly - // instead of leaving it to the (absent) __kernel_poll round-trip. - if ( - !syncRpc && - subscription.kind === "fd_write" && - (subscription.streamKind === "stdout" || - subscription.streamKind === "stderr") - ) { - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 2, - nbytes: 65536, - flags: 0, - }); - } - } - - if (readyEvents.length > 0) { - break; - } - - // Without a kernel poll bridge, fd readiness is resolved synchronously - // above (stdio fast paths) or via pipes; if there is no clock to wait on - // and no pipe to pump, no further progress is possible, so stop instead - // of busy-waiting until the caller times out. - if ( - !syncRpc && - !subscriptions.some((subscription) => subscription.kind === "clock") && - !subscriptions.some( - (subscription) => - subscription.handle?.kind === "pipe-read" || - subscription.handle?.kind === "pipe-write", - ) - ) { - break; - } - - const pollTargets = subscriptions - .filter( - (subscription) => - (subscription.kind === "fd_read" || subscription.kind === "fd_write") && - typeof subscription.targetFd === "number", - ) - .map((subscription) => ({ - fd: subscription.targetFd, - events: subscription.kind === "fd_read" ? kernelPollIn : kernelPollOut, - })); - const waitMs = - deadline == null ? 10 : Math.max(0, Math.min(10, deadline - Date.now())); - - if (syncRpc && pollTargets.length > 0) { - let response = null; - try { - response = syncRpc.callSync("__kernel_poll", [pollTargets, waitMs]); - } catch (error) { - __agentOSWasiDebug( - `poll_oneoff __kernel_poll failed: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - } - - const responseEntries = Array.isArray(response?.fds) ? response.fds : []; - for (const subscription of subscriptions) { - if ( - (subscription.kind !== "fd_read" && subscription.kind !== "fd_write") || - typeof subscription.targetFd !== "number" - ) { - continue; - } - - const responseEntry = responseEntries.find( - (entry) => (Number(entry?.fd) >>> 0) === subscription.targetFd, - ); - const revents = Number(responseEntry?.revents) >>> 0; - const interested = - subscription.kind === "fd_read" - ? kernelPollIn | kernelPollErr | kernelPollHup - : kernelPollOut | kernelPollErr | kernelPollHup; - if ((revents & interested) === 0) { - continue; - } - - readyEvents.push({ - userdata: subscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: subscription.kind === "fd_read" ? 1 : 2, - nbytes: subscription.kind === "fd_read" ? 1 : 65536, - flags: 0, - }); - } - } - - if (readyEvents.length > 0) { - break; - } - - let pumped = false; - for (const subscription of subscriptions) { - if (subscription.kind === "fd_read" && subscription.handle?.kind === "pipe-read") { - pumped = this._pumpPipeProducers(subscription.handle.pipe, 10) || pumped; - } - } - - if (pumped) { - continue; - } - - if (deadline != null && Date.now() >= deadline) { - break; - } - - if ( - pollTargets.length === 0 && - typeof Atomics?.wait !== "function" && - deadline == null - ) { - break; - } - - if ( - typeof Atomics?.wait === "function" && - typeof syntheticWaitArray !== "undefined" - ) { - Atomics.wait(syntheticWaitArray, 0, 0, waitMs); - } else if (!syncRpc && pollTargets.length === 0) { - break; - } - } - - if ( - readyEvents.length === 0 && - subscriptions.some((subscription) => subscription.kind === "clock") - ) { - const clockSubscription = subscriptions.find( - (subscription) => subscription.kind === "clock", - ); - readyEvents.push({ - userdata: clockSubscription.userdata, - error: __agentOSWasiErrnoSuccess, - type: 0, - nbytes: 0, - flags: 0, - }); - } - - for (let index = 0; index < readyEvents.length; index += 1) { - const base = (Number(outPtr) >>> 0) + index * eventSize; - const event = readyEvents[index]; - memory.set(event.userdata, base); - view.setUint16(base + 8, event.error, true); - view.setUint8(base + 10, event.type); - view.setBigUint64(base + 16, BigInt(event.nbytes), true); - view.setUint16(base + 24, event.flags, true); - } - - return this._writeUint32(neventsPtr, readyEvents.length); - } catch (error) { - __agentOSWasiDebug( - `poll_oneoff failed: ${error instanceof Error ? error.message : String(error)}`, - ); - return __agentOSWasiErrnoFault; - } - } - - _randomGet(bufPtr, bufLen) { - try { - const length = Number(bufLen) >>> 0; - const bytes = Buffer.allocUnsafe(length); - __agentOSCrypto().randomFillSync(bytes); - return this._writeBytes(bufPtr, bytes); - } catch { - return __agentOSWasiErrnoFault; - } - } - - _schedYield() { - return __agentOSWasiErrnoSuccess; - } - - _procExit(code) { - if (this.returnOnExit) { - const error = new Error(`wasi exit(${Number(code) >>> 0})`); - error.__agentOSWasiExit = true; - error.code = Number(code) >>> 0; - throw error; - } - process.exit(Number(code) >>> 0); - } - } - - Object.defineProperty(globalThis, "__agentOSWasiModule", { - configurable: true, - enumerable: false, - value: { WASI }, - writable: true, - }); -} diff --git a/crates/execution/assets/runners/wasm-runner.mjs b/crates/execution/assets/runners/wasm-runner.mjs deleted file mode 100644 index bb552698a..000000000 --- a/crates/execution/assets/runners/wasm-runner.mjs +++ /dev/null @@ -1,6075 +0,0 @@ -const fsModule = - typeof globalThis._requireFrom === 'function' - ? globalThis._requireFrom('node:fs', '/') - : __agentOSRequireBuiltin('node:fs'); -const fs = fsModule.promises; -const { readSync, writeSync } = fsModule; -const path = - typeof globalThis._requireFrom === 'function' - ? globalThis._requireFrom('node:path', '/') - : __agentOSRequireBuiltin('node:path'); -const { WASI } = globalThis.__agentOSWasiModule; -const HOST_CWD = - typeof process?.env?.AGENTOS_WASM_HOST_CWD === 'string' && - process.env.AGENTOS_WASM_HOST_CWD.length > 0 - ? path.resolve(process.env.AGENTOS_WASM_HOST_CWD) - : path.resolve('.'); - -const WASI_ERRNO_SUCCESS = 0; -const WASI_ERRNO_ACCES = 2; -const WASI_ERRNO_AGAIN = 6; -const WASI_ERRNO_BADF = 8; -const WASI_ERRNO_CHILD = 10; -const WASI_ERRNO_INVAL = 28; -const WASI_ERRNO_NOENT = 44; -const WASI_ERRNO_PIPE = 64; -const WASI_ERRNO_ROFS = 69; -const WASI_ERRNO_SPIPE = 70; -const WASI_ERRNO_SRCH = 71; -const WASI_ERRNO_FAULT = 21; -const WASI_RIGHT_FD_WRITE = 64n; -const WASI_FILETYPE_UNKNOWN = 0; -const WASI_FILETYPE_CHARACTER_DEVICE = 2; -const WASI_FILETYPE_REGULAR_FILE = 4; -const WASI_OFLAGS_CREAT = 1; -const WASI_OFLAGS_DIRECTORY = 2; -const WASI_OFLAGS_EXCL = 4; -const WASI_OFLAGS_TRUNC = 8; -const WASI_FDFLAGS_APPEND = 1; -const WASI_WHENCE_SET = 0; -const WASI_WHENCE_CUR = 1; -const WASI_WHENCE_END = 2; -const WASM_PAGE_BYTES = 65536; -const DEFAULT_VIRTUAL_PID = 1; -const DEFAULT_VIRTUAL_PPID = 0; -const DEFAULT_VIRTUAL_UID = 0; -const DEFAULT_VIRTUAL_GID = 0; -const DEFAULT_VIRTUAL_OS_USER = 'root'; -const DEFAULT_VIRTUAL_OS_HOMEDIR = '/root'; -const DEFAULT_VIRTUAL_OS_SHELL = '/bin/sh'; - -function parseVirtualProcessNumber(value, fallback) { - if (typeof value !== 'string' || value.trim() === '') { - return fallback; - } - const parsed = Number.parseInt(value, 10); - return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback; -} - -function parseVirtualProcessString(value, fallback) { - return typeof value === 'string' && value.length > 0 ? value : fallback; -} - -function resolveVirtualPath(value, fallback) { - const resolved = parseVirtualProcessString(value, fallback); - return resolved.startsWith('/') ? path.posix.normalize(resolved) : fallback; -} - -function isPathLike(specifier) { - return specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('file:'); -} - -function resolveModuleGuestPathToHostPath(guestPath) { - return resolveModuleGuestPathToHostMapping(guestPath)?.hostPath ?? null; -} - -function resolveModuleGuestPathToHostMapping(guestPath) { - if (typeof guestPath !== 'string') { - return null; - } - - const normalized = path.posix.normalize(guestPath); - for (const mapping of GUEST_PATH_MAPPINGS) { - if (mapping.guestPath === '/') { - const suffix = normalized.replace(/^\/+/, ''); - return { - hostPath: suffix ? path.join(mapping.hostPath, suffix) : mapping.hostPath, - readOnly: mapping.readOnly === true, - }; - } - - if ( - normalized !== mapping.guestPath && - !normalized.startsWith(`${mapping.guestPath}/`) - ) { - continue; - } - - const suffix = - normalized === mapping.guestPath - ? '' - : normalized.slice(mapping.guestPath.length + 1); - return { - hostPath: suffix ? path.join(mapping.hostPath, ...suffix.split('/')) : mapping.hostPath, - readOnly: mapping.readOnly === true, - }; - } - - return null; -} - -function resolveModulePath(specifier) { - if (specifier.startsWith('file:')) { - const guestPath = guestFilePathFromUrl(specifier); - if (guestPath) { - return resolveModuleGuestPathToHostPath(guestPath) ?? new URL(specifier); - } - return new URL(specifier); - } - if (isPathLike(specifier)) { - if (specifier.startsWith('/')) { - return resolveModuleGuestPathToHostPath(specifier) ?? path.resolve(process.cwd(), specifier); - } - return path.resolve(process.cwd(), specifier); - } - return specifier; -} - -function parseGuestPathMappings(value) { - if (typeof value !== 'string' || value.length === 0) { - return []; - } - try { - return JSON.parse(value) - .map((entry) => { - const guestPath = - entry && typeof entry.guestPath === 'string' - ? path.posix.normalize(entry.guestPath) - : null; - const hostPath = - entry && typeof entry.hostPath === 'string' - ? path.resolve(entry.hostPath) - : null; - return guestPath && hostPath - ? { guestPath, hostPath, readOnly: entry.readOnly === true } - : null; - }) - .filter(Boolean) - .sort((left, right) => right.guestPath.length - left.guestPath.length); - } catch { - return []; - } -} - -const modulePath = process.env.AGENTOS_WASM_MODULE_PATH; -if (!modulePath) { - throw new Error('AGENTOS_WASM_MODULE_PATH is required'); -} -const moduleBase64 = process.env.AGENTOS_WASM_MODULE_BASE64; -const __agentOSWasmPhaseDebug = process.env.AGENTOS_WASM_WARMUP_DEBUG === '1'; -const __agentOSWasmPhaseTimings = []; -const __agentOSWasiSyscallPhasesEnabled = process.env.AGENTOS_WASI_SYSCALL_PHASES === '1'; -const __agentOSWasiSyscallMetrics = new Map(); -const __agentOSWasiSyncRpcMetrics = new Map(); - -function __agentOSWasmNowNs() { - return process.hrtime.bigint(); -} - -function __agentOSWasmRecordPhase(name, startedNs) { - if (!__agentOSWasmPhaseDebug) { - return; - } - const elapsedNs = __agentOSWasmNowNs() - startedNs; - __agentOSWasmPhaseTimings.push({ - name, - ms: Number(elapsedNs) / 1000000, - }); -} - -function __agentOSWasmMeasurePhase(name, run) { - const startedNs = __agentOSWasmNowNs(); - try { - return run(); - } finally { - __agentOSWasmRecordPhase(name, startedNs); - } -} - -function __agentOSWasiMetricFor(map, key, factory) { - let metric = map.get(key); - if (!metric) { - metric = factory(); - map.set(key, metric); - } - return metric; -} - -function __agentOSWasiSyscallMetric(name) { - return __agentOSWasiMetricFor(__agentOSWasiSyscallMetrics, name, () => ({ - name, - count: 0, - totalNs: 0n, - phases: new Map(), - })); -} - -function __agentOSWasiRecordSyscall(name, startedNs) { - if (!__agentOSWasiSyscallPhasesEnabled) { - return; - } - const metric = __agentOSWasiSyscallMetric(name); - metric.count += 1; - metric.totalNs += __agentOSWasmNowNs() - startedNs; -} - -function __agentOSWasiRecordPhase(syscallName, phaseName, startedNs) { - if (!__agentOSWasiSyscallPhasesEnabled) { - return; - } - const syscall = __agentOSWasiSyscallMetric(syscallName); - const phase = __agentOSWasiMetricFor(syscall.phases, phaseName, () => ({ - name: phaseName, - count: 0, - totalNs: 0n, - })); - phase.count += 1; - phase.totalNs += __agentOSWasmNowNs() - startedNs; -} - -function __agentOSWasiMeasurePhase(syscallName, phaseName, run) { - if (!__agentOSWasiSyscallPhasesEnabled) { - return run(); - } - const startedNs = __agentOSWasmNowNs(); - try { - return run(); - } finally { - __agentOSWasiRecordPhase(syscallName, phaseName, startedNs); - } -} - -function __agentOSWasiRecordSyncRpc(method, route, startedNs) { - if (!__agentOSWasiSyscallPhasesEnabled) { - return; - } - const key = `${route}:${method}`; - const metric = __agentOSWasiMetricFor(__agentOSWasiSyncRpcMetrics, key, () => ({ - method, - route, - count: 0, - totalNs: 0n, - })); - metric.count += 1; - metric.totalNs += __agentOSWasmNowNs() - startedNs; -} - -function __agentOSWasiNsToUs(ns) { - return Number(ns) / 1000; -} - -function __agentOSWasiMetricSummary(metric) { - const totalUs = __agentOSWasiNsToUs(metric.totalNs); - return { - name: metric.name, - count: metric.count, - totalUs, - avgUs: metric.count > 0 ? totalUs / metric.count : 0, - phases: Array.from(metric.phases.values()) - .map((phase) => { - const phaseTotalUs = __agentOSWasiNsToUs(phase.totalNs); - return { - name: phase.name, - count: phase.count, - totalUs: phaseTotalUs, - avgUs: phase.count > 0 ? phaseTotalUs / phase.count : 0, - }; - }) - .sort((left, right) => right.totalUs - left.totalUs), - }; -} - -function __agentOSWasiEmitSyscallPhaseMetrics() { - if (!__agentOSWasiSyscallPhasesEnabled || typeof process?.stderr?.write !== 'function') { - return; - } - try { - process.stderr.write(`__AGENTOS_WASI_SYSCALL_PHASE_METRICS__:${JSON.stringify({ - modulePath, - syscalls: Array.from(__agentOSWasiSyscallMetrics.values()) - .map(__agentOSWasiMetricSummary) - .sort((left, right) => right.totalUs - left.totalUs), - syncRpc: Array.from(__agentOSWasiSyncRpcMetrics.values()) - .map((metric) => { - const totalUs = __agentOSWasiNsToUs(metric.totalNs); - return { - method: metric.method, - route: metric.route, - count: metric.count, - totalUs, - avgUs: metric.count > 0 ? totalUs / metric.count : 0, - }; - }) - .sort((left, right) => right.totalUs - left.totalUs), - })}\n`); - } catch { - // Diagnostics must never change command behavior. - } -} - -if (__agentOSWasiSyscallPhasesEnabled && typeof process?.on === 'function') { - process.on('exit', () => { - __agentOSWasiEmitSyscallPhaseMetrics(); - }); -} - -function __agentOSWasmEmitPhaseMetrics(reason, extra = {}) { - if (!__agentOSWasmPhaseDebug || typeof process?.stderr?.write !== 'function') { - return; - } - try { - process.stderr.write(`__AGENTOS_WASM_PHASE_METRICS__:${JSON.stringify({ - reason, - modulePath, - moduleBytes: typeof moduleBinary !== 'undefined' ? moduleBinary.byteLength : null, - phases: __agentOSWasmPhaseTimings, - ...extra, - })}\n`); - } catch { - // Diagnostics must never change command behavior. - } -} - -const guestArgv = JSON.parse(process.env.AGENTOS_GUEST_ARGV ?? '[]'); -const guestEnv = JSON.parse(process.env.AGENTOS_GUEST_ENV ?? '{}'); -const GUEST_PATH_MAPPINGS = parseGuestPathMappings(process.env.AGENTOS_GUEST_PATH_MAPPINGS); -const permissionTier = process.env.AGENTOS_WASM_PERMISSION_TIER ?? 'full'; -const prewarmOnly = process.env.AGENTOS_WASM_PREWARM_ONLY === '1'; -const maxMemoryBytesValue = Number(process.env.AGENTOS_WASM_MAX_MEMORY_BYTES); -const maxMemoryPages = Number.isFinite(maxMemoryBytesValue) - ? Math.max(0, Math.floor(maxMemoryBytesValue / WASM_PAGE_BYTES)) - : null; -const maxStackBytesValue = Number(process.env.AGENTOS_WASM_MAX_STACK_BYTES); -const maxStackBytes = - Number.isFinite(maxStackBytesValue) && maxStackBytesValue > 0 - ? Math.floor(maxStackBytesValue) - : null; - -// A guest can drive WebAssembly into never-returning recursion. V8's default -// native stack guard already traps that as a generic `RangeError`, but the -// operator-configured `AGENTOS_WASM_MAX_STACK_BYTES` budget was previously -// never consulted, so the cap was dead. When a stack byte budget is set, treat -// a stack-exhaustion trap as enforcement of THAT budget: terminate the guest -// nonzero and attribute the failure to the configured limit instead of leaking -// the engine's generic default-guard message. -function isWasmStackExhaustionTrap(error) { - const message = typeof error?.message === 'string' ? error.message : ''; - // V8 raises `RangeError: Maximum call stack size exceeded` when its native - // stack guard fires on runaway recursion (the WebAssembly call stack is - // mapped onto V8's). Match that explicitly rather than treating every - // `RangeError` as stack exhaustion, so unrelated range failures still - // surface with their own message. - return /maximum call stack size exceeded/i.test(message); -} - -function reportConfiguredStackLimitExceeded(error) { - const detail = typeof error?.message === 'string' && error.message.length > 0 - ? ` (${error.message})` - : ''; - if (typeof process?.stderr?.write === 'function') { - process.stderr.write( - `WebAssembly guest exceeded the configured stack byte limit of ${maxStackBytes} bytes${detail}\n`, - ); - } -} -const frozenTimeValue = Number(process.env.AGENTOS_FROZEN_TIME_MS); -const frozenTimeMs = Number.isFinite(frozenTimeValue) ? Math.trunc(frozenTimeValue) : Date.now(); -const frozenTimeNs = BigInt(frozenTimeMs) * 1000000n; -const VIRTUAL_UID = parseVirtualProcessNumber( - process.env.AGENTOS_VIRTUAL_PROCESS_UID, - DEFAULT_VIRTUAL_UID, -); -const VIRTUAL_GID = parseVirtualProcessNumber( - process.env.AGENTOS_VIRTUAL_PROCESS_GID, - DEFAULT_VIRTUAL_GID, -); -const VIRTUAL_PID = parseVirtualProcessNumber( - process.env.AGENTOS_VIRTUAL_PROCESS_PID, - DEFAULT_VIRTUAL_PID, -); -const VIRTUAL_PPID = parseVirtualProcessNumber( - process.env.AGENTOS_VIRTUAL_PROCESS_PPID, - DEFAULT_VIRTUAL_PPID, -); -const VIRTUAL_OS_USER = parseVirtualProcessString( - (globalThis.__agentOSVirtualOs||{}).user, - DEFAULT_VIRTUAL_OS_USER, -); -const VIRTUAL_OS_HOMEDIR = resolveVirtualPath( - (globalThis.__agentOSVirtualOs||{}).homedir, - DEFAULT_VIRTUAL_OS_HOMEDIR, -); -const VIRTUAL_OS_SHELL = resolveVirtualPath( - (globalThis.__agentOSVirtualOs||{}).shell, - DEFAULT_VIRTUAL_OS_SHELL, -); -const CONTROL_PIPE_FD = parseControlPipeFd(process.env.AGENTOS_CONTROL_PIPE_FD); -const NODE_SYNC_RPC_ENABLE = process.env.AGENTOS_NODE_SYNC_RPC_ENABLE === '1'; -const NODE_SYNC_RPC_REQUEST_FD = parseControlPipeFd(process.env.AGENTOS_NODE_SYNC_RPC_REQUEST_FD); -const NODE_SYNC_RPC_RESPONSE_FD = parseControlPipeFd(process.env.AGENTOS_NODE_SYNC_RPC_RESPONSE_FD); -const KERNEL_STDIO_SYNC_RPC = process.env.AGENTOS_WASI_STDIO_SYNC_RPC === '1'; -const SIDECAR_MANAGED_PROCESS = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === 'string' && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; -let nextSyncRpcId = 1; -let syncRpcResponseBuffer = ''; -const spawnedChildren = new Map(); -const spawnedChildrenById = new Map(); -let nextSyntheticChildPid = 0x40000000; -const syntheticFdEntries = new Map(); -const delegateManagedFdRefCounts = new Map(); -const closedPassthroughFds = new Set(); -globalThis.__agentOSWasiDelegateFdRefCount = (fd) => - delegateManagedFdRefCounts.get(Number(fd) >>> 0) ?? 0; -const passthroughHandles = new Map([ - [0, { kind: 'passthrough', targetFd: 0, displayFd: 0, refCount: 0, open: true }], - [1, { kind: 'passthrough', targetFd: 1, displayFd: 1, refCount: 0, open: true }], - [2, { kind: 'passthrough', targetFd: 2, displayFd: 2, refCount: 0, open: true }], -]); -const retainedSyntheticHandlesByDisplayFd = new Map(); -const retainedSpawnOutputHandlesByFd = new Map(); -let nextSyntheticFd = 64; -let nextSyntheticPipeId = 1; -const syntheticWaitArray = new Int32Array(new SharedArrayBuffer(4)); -let delegateWriteScratch = { base: 0, capacity: 0 }; - -function traceHostProcess(event, details) { - const enabled = - (typeof TRACE_HOST_PROCESS === 'boolean' && TRACE_HOST_PROCESS) || - (typeof HOST_PROCESS_ENV !== 'undefined' && - HOST_PROCESS_ENV?.AGENTOS_TRACE_HOST_PROCESS === '1') || - (typeof process !== 'undefined' && process?.env?.AGENTOS_TRACE_HOST_PROCESS === '1'); - if (!enabled) { - return; - } - try { - process.stderr.write(`[agent-os-host-process] ${event} ${JSON.stringify(details)}\n`); - } catch { - // Ignore tracing failures. - } -} - -const WASI_RIGHT_FD_DATASYNC = 1n << 0n; -const WASI_RIGHT_FD_READ = 1n << 1n; -const WASI_RIGHT_FD_SEEK = 1n << 2n; -const WASI_RIGHT_FD_FDSTAT_SET_FLAGS = 1n << 3n; -const WASI_RIGHT_FD_SYNC = 1n << 4n; -const WASI_RIGHT_FD_TELL = 1n << 5n; -const WASI_RIGHT_FD_ADVISE = 1n << 7n; -const WASI_RIGHT_FD_ALLOCATE = 1n << 8n; -const WASI_RIGHT_PATH_CREATE_DIRECTORY = 1n << 9n; -const WASI_RIGHT_PATH_LINK_SOURCE = 1n << 10n; -const WASI_RIGHT_PATH_LINK_TARGET = 1n << 11n; -const WASI_RIGHT_PATH_OPEN = 1n << 13n; -const WASI_RIGHT_FD_READDIR = 1n << 14n; -const WASI_RIGHT_PATH_READLINK = 1n << 15n; -const WASI_RIGHT_PATH_RENAME_SOURCE = 1n << 16n; -const WASI_RIGHT_PATH_RENAME_TARGET = 1n << 17n; -const WASI_RIGHT_PATH_FILESTAT_GET = 1n << 18n; -const WASI_RIGHT_PATH_FILESTAT_SET_SIZE = 1n << 19n; -const WASI_RIGHT_PATH_FILESTAT_SET_TIMES = 1n << 20n; -const WASI_RIGHT_FD_FILESTAT_GET = 1n << 21n; -const WASI_RIGHT_FD_FILESTAT_SET_SIZE = 1n << 22n; -const WASI_RIGHT_FD_FILESTAT_SET_TIMES = 1n << 23n; -const WASI_RIGHT_PATH_SYMLINK = 1n << 24n; -const WASI_RIGHT_PATH_REMOVE_DIRECTORY = 1n << 25n; -const WASI_RIGHT_PATH_UNLINK_FILE = 1n << 26n; -const WASI_RIGHT_POLL_FD_READWRITE = 1n << 27n; - -const READ_ONLY_PREOPEN_RIGHTS_BASE = - WASI_RIGHT_FD_READ | - WASI_RIGHT_FD_SEEK | - WASI_RIGHT_FD_FDSTAT_SET_FLAGS | - WASI_RIGHT_FD_TELL | - WASI_RIGHT_PATH_OPEN | - WASI_RIGHT_FD_READDIR | - WASI_RIGHT_PATH_READLINK | - WASI_RIGHT_PATH_FILESTAT_GET | - WASI_RIGHT_FD_FILESTAT_GET | - WASI_RIGHT_POLL_FD_READWRITE; -const READ_ONLY_PREOPEN_RIGHTS_INHERITING = - WASI_RIGHT_FD_READ | - WASI_RIGHT_FD_SEEK | - WASI_RIGHT_FD_FDSTAT_SET_FLAGS | - WASI_RIGHT_FD_TELL | - WASI_RIGHT_FD_FILESTAT_GET | - WASI_RIGHT_POLL_FD_READWRITE; -const READ_WRITE_PREOPEN_RIGHTS_BASE = - READ_ONLY_PREOPEN_RIGHTS_BASE | - WASI_RIGHT_FD_DATASYNC | - WASI_RIGHT_FD_SYNC | - WASI_RIGHT_FD_WRITE | - WASI_RIGHT_FD_ADVISE | - WASI_RIGHT_FD_ALLOCATE | - WASI_RIGHT_PATH_CREATE_DIRECTORY | - WASI_RIGHT_PATH_FILESTAT_SET_SIZE | - WASI_RIGHT_PATH_FILESTAT_SET_TIMES | - WASI_RIGHT_FD_FILESTAT_SET_SIZE | - WASI_RIGHT_FD_FILESTAT_SET_TIMES; -const READ_WRITE_PREOPEN_RIGHTS_INHERITING = - READ_ONLY_PREOPEN_RIGHTS_INHERITING | - WASI_RIGHT_FD_DATASYNC | - WASI_RIGHT_FD_SYNC | - WASI_RIGHT_FD_WRITE | - WASI_RIGHT_FD_ADVISE | - WASI_RIGHT_FD_ALLOCATE | - WASI_RIGHT_FD_FILESTAT_SET_SIZE | - WASI_RIGHT_FD_FILESTAT_SET_TIMES; -const FULL_PREOPEN_RIGHTS_BASE = - READ_WRITE_PREOPEN_RIGHTS_BASE | - WASI_RIGHT_PATH_LINK_SOURCE | - WASI_RIGHT_PATH_LINK_TARGET | - WASI_RIGHT_PATH_RENAME_SOURCE | - WASI_RIGHT_PATH_RENAME_TARGET | - WASI_RIGHT_PATH_SYMLINK | - WASI_RIGHT_PATH_REMOVE_DIRECTORY | - WASI_RIGHT_PATH_UNLINK_FILE; -const FULL_PREOPEN_RIGHTS_INHERITING = READ_WRITE_PREOPEN_RIGHTS_INHERITING; - -function buildPreopenRights() { - switch (permissionTier) { - case 'read-only': - return { - rightsBase: READ_ONLY_PREOPEN_RIGHTS_BASE, - rightsInheriting: READ_ONLY_PREOPEN_RIGHTS_INHERITING, - }; - case 'read-write': - return { - rightsBase: READ_WRITE_PREOPEN_RIGHTS_BASE, - rightsInheriting: READ_WRITE_PREOPEN_RIGHTS_INHERITING, - }; - case 'full': - default: - return { - rightsBase: FULL_PREOPEN_RIGHTS_BASE, - rightsInheriting: FULL_PREOPEN_RIGHTS_INHERITING, - }; - } -} - -function createPreopen(hostPath, readOnly = false) { - const rights = - readOnly === true - ? { - rightsBase: READ_ONLY_PREOPEN_RIGHTS_BASE, - rightsInheriting: READ_ONLY_PREOPEN_RIGHTS_INHERITING, - } - : buildPreopenRights(); - return { - hostPath, - readOnly: readOnly === true, - rightsBase: rights.rightsBase, - rightsInheriting: rights.rightsInheriting, - }; -} - -function mappingContainsGuestPath(mapping, guestPath) { - if (!mapping || typeof mapping.guestPath !== 'string' || typeof guestPath !== 'string') { - return false; - } - const normalized = path.posix.normalize(guestPath); - return ( - normalized === mapping.guestPath || - mapping.guestPath === '/' || - normalized.startsWith(`${mapping.guestPath}/`) - ); -} - -function mappingContainsHostPath(mapping, hostPath) { - if (!mapping || typeof mapping.hostPath !== 'string' || typeof hostPath !== 'string') { - return false; - } - const normalized = path.resolve(hostPath); - const root = path.resolve(mapping.hostPath); - return normalized === root || normalized.startsWith(`${root}${path.sep}`); -} - -function readOnlyForCwd(guestCwd) { - for (const mapping of GUEST_PATH_MAPPINGS) { - if ( - mapping?.readOnly === true && - (mappingContainsGuestPath(mapping, guestCwd) || - mappingContainsHostPath(mapping, HOST_CWD)) - ) { - return true; - } - } - return false; -} - -function buildPreopens() { - switch (permissionTier) { - case 'isolated': - return {}; - case 'read-only': - case 'read-write': - case 'full': - default: - const guestCwd = - typeof guestEnv?.PWD === 'string' && guestEnv.PWD.startsWith('/') - ? path.posix.normalize(guestEnv.PWD) - : typeof process.env.PWD === 'string' && process.env.PWD.startsWith('/') - ? path.posix.normalize(process.env.PWD) - : null; - const preopens = {}; - const seen = new Set(); - const cwdReadOnly = readOnlyForCwd(guestCwd); - const cwdMount = guestCwd || '/workspace'; - preopens[cwdMount] = createPreopen(HOST_CWD, cwdReadOnly); - seen.add(cwdMount); - const rootMapping = GUEST_PATH_MAPPINGS.find( - (mapping) => mapping && mapping.guestPath === '/', - ); - if (rootMapping && !seen.has('/')) { - preopens['/'] = createPreopen(rootMapping.hostPath, rootMapping.readOnly); - seen.add('/'); - } - for (const mapping of GUEST_PATH_MAPPINGS) { - if (!mapping || typeof mapping.guestPath !== 'string' || typeof mapping.hostPath !== 'string') { - continue; - } - const guestPath = path.posix.normalize(mapping.guestPath); - if ( - !path.posix.isAbsolute(guestPath) || - seen.has(guestPath) || - guestPath === guestCwd - ) { - continue; - } - preopens[guestPath] = createPreopen(mapping.hostPath, mapping.readOnly); - seen.add(guestPath); - } - if (cwdMount !== '/workspace' && !seen.has('/workspace')) { - preopens['/workspace'] = createPreopen(HOST_CWD, cwdReadOnly); - seen.add('/workspace'); - } - return preopens; - } -} - -function readVarUint(bytes, offset, label) { - let value = 0; - let shift = 0; - let cursor = offset; - for (let count = 0; count < 10; count += 1) { - if (cursor >= bytes.length) { - throw new Error(`WebAssembly ${label} truncated`); - } - const byte = bytes[cursor]; - cursor += 1; - value += (byte & 0x7f) * 2 ** shift; - if ((byte & 0x80) === 0) { - return { value, offset: cursor }; - } - shift += 7; - } - throw new Error(`WebAssembly ${label} exceeds varuint limit`); -} - -function encodeVarUint(value) { - const encoded = []; - let remaining = Math.trunc(value); - do { - let byte = remaining & 0x7f; - remaining = Math.floor(remaining / 128); - if (remaining > 0) { - byte |= 0x80; - } - encoded.push(byte); - } while (remaining > 0); - return encoded; -} - -function appendBytes(out, bytes) { - for (let i = 0; i < bytes.length; i += 1) { - out.push(bytes[i]); - } -} - -function rewriteMemorySection(sectionBytes, limitPages) { - let offset = 0; - const countResult = readVarUint(sectionBytes, offset, 'memory count'); - const count = countResult.value; - offset = countResult.offset; - const rewritten = []; - appendBytes(rewritten, encodeVarUint(count)); - - for (let index = 0; index < count; index += 1) { - const flagsResult = readVarUint(sectionBytes, offset, 'memory flags'); - const flags = flagsResult.value; - offset = flagsResult.offset; - - if ((flags & ~1) !== 0) { - throw new Error( - `configured WebAssembly memory limit does not support memory flags ${flags}`, - ); - } - - const initialResult = readVarUint(sectionBytes, offset, 'memory minimum'); - const initialPages = initialResult.value; - offset = initialResult.offset; - - let maximumPages = null; - if ((flags & 1) !== 0) { - const maximumResult = readVarUint(sectionBytes, offset, 'memory maximum'); - maximumPages = maximumResult.value; - offset = maximumResult.offset; - } - - if (initialPages > limitPages) { - throw new Error( - `initial WebAssembly memory of ${initialPages * WASM_PAGE_BYTES} bytes exceeds the configured limit of ${limitPages * WASM_PAGE_BYTES} bytes`, - ); - } - - const cappedMaximumPages = - maximumPages == null ? limitPages : Math.min(maximumPages, limitPages); - appendBytes(rewritten, encodeVarUint(1)); - appendBytes(rewritten, encodeVarUint(initialPages)); - appendBytes(rewritten, encodeVarUint(cappedMaximumPages)); - } - - if (offset !== sectionBytes.length) { - throw new Error('memory section parsing did not consume the full section'); - } - - return rewritten; -} - -function enforceMemoryLimit(moduleBytes, limitPages) { - if (!Number.isInteger(limitPages)) { - return moduleBytes; - } - - const bytes = moduleBytes instanceof Uint8Array ? moduleBytes : new Uint8Array(moduleBytes); - if (bytes.length < 8 || bytes[0] !== 0 || bytes[1] !== 0x61 || bytes[2] !== 0x73 || bytes[3] !== 0x6d) { - throw new Error('module is not a valid WebAssembly binary'); - } - - const rewritten = Array.from(bytes.slice(0, 8)); - let offset = 8; - - while (offset < bytes.length) { - const sectionStart = offset; - const sectionId = bytes[offset]; - offset += 1; - const sectionSizeResult = readVarUint(bytes, offset, 'section size'); - const sectionSize = sectionSizeResult.value; - offset = sectionSizeResult.offset; - const sectionEnd = offset + sectionSize; - if (sectionEnd > bytes.length) { - throw new Error('section extends past end of module'); - } - - if (sectionId !== 5) { - appendBytes(rewritten, bytes.slice(sectionStart, sectionEnd)); - offset = sectionEnd; - continue; - } - - const rewrittenSection = rewriteMemorySection(bytes.slice(offset, sectionEnd), limitPages); - rewritten.push(sectionId); - appendBytes(rewritten, encodeVarUint(rewrittenSection.length)); - appendBytes(rewritten, rewrittenSection); - offset = sectionEnd; - } - - return Buffer.from(rewritten); -} - -function decodeBase64ToUint8Array(value) { - return Buffer.from(value, 'base64'); -} - -// Memoized kernel-PTY probe for the guest's stdio fds. Rust's -// `stdin().is_terminal()` (and wasi-libc `isatty`) ask `fd_fdstat_get` for a -// CHARACTER_DEVICE filetype; the runner-process fds are pipes, so a delegated -// answer hides the kernel PTY and interactive guests (e.g. brush's prompt) -// believe stdin is not a terminal. Ask the sidecar's kernel instead. -const stdioTtyCache = new Map(); -function stdioFdIsKernelTty(fd) { - const descriptor = Number(fd) >>> 0; - if (descriptor > 2) return false; - if (KERNEL_STDIO_SYNC_RPC) return true; - if (stdioTtyCache.has(descriptor)) return stdioTtyCache.get(descriptor); - let isTty = false; - try { - isTty = callSyncRpc('__kernel_isatty', [descriptor]) === true; - } catch { - isTty = false; - } - stdioTtyCache.set(descriptor, isTty); - return isTty; -} - -// Long event-driven in-RPC waits: the sidecar services __kernel_stdin_read / -// __kernel_poll by parking the RPC and replying when kernel poll state changes -// (reply-by-token), so a long wait costs no dispatch-loop time and near-zero -// CPU (the guest thread blocks in Atomics.wait inside callSync). Keep each -// slice under the 30s guest sync-RPC deadline. -const KERNEL_WAIT_SLICE_MS = 10_000; - -function readKernelStdinChunk(maxBytes) { - const requestedLength = Math.max(1, Number(maxBytes) >>> 0); - while (true) { - const response = callSyncRpc('__kernel_stdin_read', [ - requestedLength, - KERNEL_WAIT_SLICE_MS, - ]); - if (response && typeof response.dataBase64 === 'string') { - return Buffer.from(response.dataBase64, 'base64'); - } - if (response && response.done === true) { - return null; - } - } -} - -const rawModuleBytes = globalThis.__agentOSWasmModuleBytes; -const moduleSource = - rawModuleBytes instanceof Uint8Array - ? Buffer.from(rawModuleBytes.buffer, rawModuleBytes.byteOffset, rawModuleBytes.byteLength) - : typeof moduleBase64 === 'string' && moduleBase64.length > 0 - ? moduleBase64 - : fsModule.readFileSync(resolveModulePath(modulePath)); -const moduleBytes = - typeof moduleSource === 'string' - ? __agentOSWasmMeasurePhase('decodeBase64ToUint8Array', () => decodeBase64ToUint8Array(moduleSource)) - : moduleSource; -const moduleBinary = __agentOSWasmMeasurePhase('enforceMemoryLimit', () => enforceMemoryLimit(moduleBytes, maxMemoryPages)); -const module = __agentOSWasmMeasurePhase('WebAssembly.Module', () => new WebAssembly.Module(moduleBinary)); - -if (prewarmOnly) { - __agentOSWasmEmitPhaseMetrics('prewarm'); - process.exit(0); -} - -const WASI_PREOPENS = buildPreopens(); -const WASI_PREOPEN_FD_BASE = 3; -const WASI_PREOPEN_ENTRIES = Object.entries(WASI_PREOPENS); - -const wasi = new WASI({ - version: 'preview1', - args: guestArgv, - env: guestEnv, - preopens: WASI_PREOPENS, - returnOnExit: true, -}); - -let instanceMemory = null; -const wasiImport = { ...wasi.wasiImport }; -// node:wasi omits sock_shutdown; guest socket teardown happens via fd_close + host_net, so a -// success no-op is sufficient (needed for the cross-compiled X server / X clients). -if (typeof wasiImport.sock_shutdown !== 'function') { - wasiImport.sock_shutdown = () => 0; -} -const delegateClockTimeGet = - typeof wasi.wasiImport.clock_time_get === 'function' - ? wasi.wasiImport.clock_time_get.bind(wasi.wasiImport) - : null; -const delegateClockResGet = - typeof wasi.wasiImport.clock_res_get === 'function' - ? wasi.wasiImport.clock_res_get.bind(wasi.wasiImport) - : null; -const delegatePathOpen = - typeof wasi.wasiImport.path_open === 'function' - ? wasi.wasiImport.path_open.bind(wasi.wasiImport) - : null; -const delegateFdWrite = - typeof wasi.wasiImport.fd_write === 'function' - ? wasi.wasiImport.fd_write.bind(wasi.wasiImport) - : null; -const delegateFdPread = - typeof wasi.wasiImport.fd_pread === 'function' - ? wasi.wasiImport.fd_pread.bind(wasi.wasiImport) - : null; -const delegateFdPwrite = - typeof wasi.wasiImport.fd_pwrite === 'function' - ? wasi.wasiImport.fd_pwrite.bind(wasi.wasiImport) - : null; -const delegateFdSync = - typeof wasi.wasiImport.fd_sync === 'function' - ? wasi.wasiImport.fd_sync.bind(wasi.wasiImport) - : null; - -function decodeSignalMask(maskLo, maskHi) { - const values = []; - const lo = Number(maskLo) >>> 0; - const hi = Number(maskHi) >>> 0; - for (let bit = 0; bit < 32; bit += 1) { - if (((lo >>> bit) & 1) === 1) { - values.push(bit + 1); - } - } - for (let bit = 0; bit < 32; bit += 1) { - if (((hi >>> bit) & 1) === 1) { - values.push(bit + 33); - } - } - return values; -} - -function parseControlPipeFd(value) { - if (typeof value !== 'string' || value.trim() === '') { - return null; - } - - const parsed = Number.parseInt(value, 10); - return Number.isInteger(parsed) && parsed >= 3 ? parsed : null; -} - -function emitControlMessage(message) { - const emitSignalStateFallback = () => { - if ( - message?.type === 'signal_state' && - typeof process?.stdout?.write === 'function' - ) { - try { - process.stdout.write(`__AGENTOS_WASM_SIGNAL_STATE__:${JSON.stringify(message)}\n`); - } catch { - // Ignore signal-state bridge failures during teardown. - } - } - }; - - if (CONTROL_PIPE_FD == null) { - emitSignalStateFallback(); - return; - } - - try { - writeSync(CONTROL_PIPE_FD, `${JSON.stringify(message)}\n`); - } catch { - emitSignalStateFallback(); - } -} - -function isWorkspaceReadOnly() { - return permissionTier === 'read-only' || permissionTier === 'isolated'; -} - -function hasWriteRights(rights) { - try { - return (BigInt(rights) & WASI_RIGHT_FD_WRITE) !== 0n; - } catch { - return true; - } -} - -function hasReadRights(rights) { - try { - return (BigInt(rights) & WASI_RIGHT_FD_READ) !== 0n; - } catch { - return true; - } -} - -function hasMutationOpenFlags(oflags) { - const normalized = Number(oflags) >>> 0; - return ( - (normalized & WASI_OFLAGS_CREAT) !== 0 || - (normalized & WASI_OFLAGS_EXCL) !== 0 || - (normalized & WASI_OFLAGS_TRUNC) !== 0 - ); -} - -function denyReadOnlyMutation() { - return WASI_ERRNO_ROFS; -} - -function guestPathForPreopenKey(key) { - if (key === '.') { - return HOST_FS_GUEST_CWD; - } - return path.posix.normalize(key); -} - -function resolvePathOpenGuestPath(fd, pathPtr, pathLen) { - const target = readGuestString(pathPtr, pathLen); - if (target.startsWith('/')) { - return path.posix.normalize(target); - } - - const handle = lookupFdHandle(fd); - if (handle && typeof handle.guestPath === 'string') { - return path.posix.resolve(handle.guestPath, target); - } - - const preopenIndex = (Number(fd) >>> 0) - WASI_PREOPEN_FD_BASE; - const preopen = WASI_PREOPEN_ENTRIES[preopenIndex]; - if (preopen) { - return path.posix.resolve(guestPathForPreopenKey(preopen[0]), target); - } - - return null; -} - -function guestPathIsReadOnly(guestPath) { - return GUEST_PATH_MAPPINGS.some( - (mapping) => mapping?.readOnly === true && mappingContainsGuestPath(mapping, guestPath), - ); -} - -function resolvedGuestPathIsReadOnly(fd, pathPtr, pathLen) { - try { - const guestPath = resolvePathOpenGuestPath(fd, pathPtr, pathLen); - return typeof guestPath === 'string' && guestPathIsReadOnly(guestPath); - } catch { - return false; - } -} - -// Guest path recorded for a managed (path_open passthrough) fd, if known. -function guestPathForManagedFd(fd) { - const handle = lookupFdHandle(fd); - if (handle?.kind === 'passthrough' && typeof handle.guestPath === 'string') { - return handle.guestPath; - } - return null; -} - -// WASI fstflags bits for *_filestat_set_times. -const WASI_FSTFLAGS_ATIM = 1; -const WASI_FSTFLAGS_ATIM_NOW = 2; -const WASI_FSTFLAGS_MTIM = 4; -const WASI_FSTFLAGS_MTIM_NOW = 8; -const WASI_LOOKUPFLAGS_SYMLINK_FOLLOW = 1; - -// Resolve the (atime, mtime) seconds to apply for a *_filestat_set_times call: -// explicit nanosecond args, "now", or preserve-current (the OMIT case; node's -// utimes has no omit, so re-apply the current value from stat). -function resolveSetTimes(currentStat, atimNs, mtimNs, fstFlags) { - const flags = Number(fstFlags) >>> 0; - const nowSec = Date.now() / 1000; - let atime = currentStat.atimeMs / 1000; - let mtime = currentStat.mtimeMs / 1000; - if (flags & WASI_FSTFLAGS_ATIM_NOW) { - atime = nowSec; - } else if (flags & WASI_FSTFLAGS_ATIM) { - atime = Number(BigInt(atimNs)) / 1e9; - } - if (flags & WASI_FSTFLAGS_MTIM_NOW) { - mtime = nowSec; - } else if (flags & WASI_FSTFLAGS_MTIM) { - mtime = Number(BigInt(mtimNs)) / 1e9; - } - return { atime, mtime }; -} - -// The embedded WASI shim omits the *_filestat_set_times ops entirely, which -// makes instantiation of any module importing them fail with a LinkError -// (vim uses path_filestat_set_times to restore file timestamps). Implement -// them against the bridge fs (the kernel VFS) when the base has no delegate. -if (typeof wasiImport.path_filestat_set_times !== 'function') { - wasiImport.path_filestat_set_times = (fd, flags, pathPtr, pathLen, atimNs, mtimNs, fstFlags) => { - try { - const guestPath = resolvePathOpenGuestPath(fd, pathPtr, pathLen); - if (typeof guestPath !== 'string') { - return WASI_ERRNO_BADF; - } - const follow = (Number(flags) >>> 0) & WASI_LOOKUPFLAGS_SYMLINK_FOLLOW; - const stat = follow ? fsModule.statSync(guestPath) : fsModule.lstatSync(guestPath); - const { atime, mtime } = resolveSetTimes(stat, atimNs, mtimNs, fstFlags); - if (follow || typeof fsModule.lutimesSync !== 'function') { - fsModule.utimesSync(guestPath, atime, mtime); - } else { - fsModule.lutimesSync(guestPath, atime, mtime); - } - return WASI_ERRNO_SUCCESS; - } catch (error) { - return error?.code === 'ENOENT' ? WASI_ERRNO_NOENT : WASI_ERRNO_INVAL; - } - }; -} - -if (typeof wasiImport.fd_filestat_set_times !== 'function') { - wasiImport.fd_filestat_set_times = (fd, atimNs, mtimNs, fstFlags) => { - try { - const guestPath = guestPathForManagedFd(fd); - if (typeof guestPath !== 'string') { - return WASI_ERRNO_BADF; - } - const stat = fsModule.statSync(guestPath); - const { atime, mtime } = resolveSetTimes(stat, atimNs, mtimNs, fstFlags); - fsModule.utimesSync(guestPath, atime, mtime); - return WASI_ERRNO_SUCCESS; - } catch (error) { - return error?.code === 'ENOENT' ? WASI_ERRNO_NOENT : WASI_ERRNO_INVAL; - } - }; -} - -function pathOpenMayCreateTarget(oflags, rightsBase, fdflags) { - const normalizedOflags = Number(oflags) >>> 0; - const normalizedFdflags = Number(fdflags) >>> 0; - return ( - (normalizedOflags & WASI_OFLAGS_CREAT) !== 0 || - ((normalizedFdflags & WASI_FDFLAGS_APPEND) !== 0 && hasWriteRights(rightsBase)) - ); -} - -function precreatePathOpenTarget(fd, pathPtr, pathLen, oflags, rightsBase, fdflags) { - if (!pathOpenMayCreateTarget(oflags, rightsBase, fdflags)) { - return null; - } - - const guestPath = resolvePathOpenGuestPath(fd, pathPtr, pathLen); - if (typeof guestPath !== 'string') { - return null; - } - - if (!fsModule.existsSync(guestPath)) { - fsModule.writeFileSync(guestPath, Buffer.alloc(0)); - } - return guestPath; -} - -function fsOpenFlagForPathOpen(oflags, rightsBase, fdflags) { - const normalizedOflags = Number(oflags) >>> 0; - const normalizedFdflags = Number(fdflags) >>> 0; - const wantsRead = hasReadRights(rightsBase); - const wantsWrite = hasWriteRights(rightsBase); - const wantsExclusive = (normalizedOflags & WASI_OFLAGS_EXCL) !== 0; - const wantsAppend = (normalizedFdflags & WASI_FDFLAGS_APPEND) !== 0; - const wantsTruncate = (normalizedOflags & WASI_OFLAGS_TRUNC) !== 0; - - if (!wantsWrite) { - return 'r'; - } - - if (wantsAppend) { - if (wantsExclusive) { - return wantsRead ? 'ax+' : 'ax'; - } - return wantsRead ? 'a+' : 'a'; - } - - if (wantsTruncate) { - if (wantsExclusive) { - return wantsRead ? 'wx+' : 'wx'; - } - return wantsRead ? 'w+' : 'w'; - } - - return 'r+'; -} - -function allocateSyntheticFd() { - let fd = nextSyntheticFd; - while ( - syntheticFdEntries.has(fd) || - passthroughHandles.has(fd) || - delegateManagedFdRefCounts.has(fd) - ) { - fd += 1; - } - nextSyntheticFd = fd + 1; - return fd; -} - -function openGuestFileForPathOpen(fd, pathPtr, pathLen, oflags, rightsBase, fdflags, openedFdPtr) { - if (!pathOpenMayCreateTarget(oflags, rightsBase, fdflags)) { - return null; - } - - const normalizedOflags = Number(oflags) >>> 0; - const normalizedFdflags = Number(fdflags) >>> 0; - - const guestPath = resolvePathOpenGuestPath(fd, pathPtr, pathLen); - if (typeof guestPath !== 'string') { - return null; - } - - const append = (normalizedFdflags & WASI_FDFLAGS_APPEND) !== 0; - const exclusive = (normalizedOflags & WASI_OFLAGS_EXCL) !== 0; - const truncate = (normalizedOflags & WASI_OFLAGS_TRUNC) !== 0; - if (!append && !exclusive && !truncate && !fsModule.existsSync(guestPath)) { - fsModule.writeFileSync(guestPath, Buffer.alloc(0)); - } - const targetFd = fsModule.openSync( - guestPath, - fsOpenFlagForPathOpen(oflags, rightsBase, fdflags), - 0o666, - ); - const openedFd = allocateSyntheticFd(); - syntheticFdEntries.set(openedFd, { - kind: 'guest-file', - targetFd, - displayFd: openedFd, - refCount: 1, - open: true, - guestPath, - position: append ? Number(fsModule.fstatSync(targetFd).size ?? 0) : 0, - append, - }); - return writeGuestUint32(openedFdPtr, openedFd); -} - -function fsOpenNumericFlagsForManagedPath(rightsBase, fdflags) { - const wantsRead = hasReadRights(rightsBase); - const wantsWrite = hasWriteRights(rightsBase); - let flags = wantsWrite ? (wantsRead ? 0o2 : 0o1) : 0; - if ((Number(fdflags) & WASI_FDFLAGS_APPEND) !== 0) { - flags |= 0o2000; - } - return flags; -} - -function openManagedPathIoFd(guestPath, rightsBase, fdflags) { - if (typeof guestPath !== 'string' || guestPath === '/dev/null') { - return null; - } - try { - return fsModule.openSync( - guestPath, - fsOpenNumericFlagsForManagedPath(rightsBase, fdflags), - 0o666, - ); - } catch { - return null; - } -} - -function retainPathOpenDelegateFd(openedFdPtr, guestPath, fdflags, rightsBase) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return WASI_ERRNO_SUCCESS; - } - - try { - const openedFd = new DataView(instanceMemory.buffer).getUint32(Number(openedFdPtr), true); - const append = (Number(fdflags) & WASI_FDFLAGS_APPEND) !== 0; - retainDelegateFd(openedFd); - if (openedFd > 2 && !passthroughHandles.has(openedFd)) { - const ioFd = openManagedPathIoFd(guestPath, rightsBase, fdflags); - closedPassthroughFds.delete(openedFd); - passthroughHandles.set(openedFd, { - kind: 'passthrough', - targetFd: openedFd, - ioFd, - displayFd: openedFd, - refCount: 0, - open: true, - readOnly: - typeof guestPath === 'string' && - resolveModuleGuestPathToHostMapping(guestPath)?.readOnly === true, - append, - position: append && typeof ioFd === 'number' - ? Number(fsModule.fstatSync(ioFd).size ?? 0) - : 0, - ...(typeof guestPath === 'string' ? { guestPath } : {}), - }); - } - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } -} - -function writeGuestUint32(ptr, value) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return WASI_ERRNO_FAULT; - } - - try { - new DataView(instanceMemory.buffer).setUint32(Number(ptr), Number(value) >>> 0, true); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } -} - -function readGuestUint32(ptr) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - throw new Error('WebAssembly memory is unavailable'); - } - return new DataView(instanceMemory.buffer).getUint32(Number(ptr), true); -} - -function writeGuestUint64(ptr, value) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return WASI_ERRNO_FAULT; - } - - try { - new DataView(instanceMemory.buffer).setBigUint64(Number(ptr), BigInt(value), true); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } -} - -function statTimestampNs(value) { - const numeric = Number(value); - return BigInt(Math.trunc((Number.isFinite(numeric) ? numeric : 0) * 1000000)); -} - -function writeGuestFilestat(ptr, stats, filetype = WASI_FILETYPE_REGULAR_FILE) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return WASI_ERRNO_FAULT; - } - - try { - const view = new DataView(instanceMemory.buffer); - const offset = Number(ptr) >>> 0; - view.setBigUint64(offset, 0n, true); - view.setBigUint64(offset + 8, BigInt(stats?.ino ?? 0), true); - view.setUint8(offset + 16, Number(filetype) >>> 0); - view.setBigUint64(offset + 24, BigInt(stats?.nlink ?? 1), true); - view.setBigUint64(offset + 32, BigInt(stats?.size ?? 0), true); - view.setBigUint64(offset + 40, statTimestampNs(stats?.atimeMs), true); - view.setBigUint64(offset + 48, statTimestampNs(stats?.mtimeMs), true); - view.setBigUint64(offset + 56, statTimestampNs(stats?.ctimeMs), true); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } -} - -function writeGuestFdstat(ptr, filetype, flags, rightsBase, rightsInheriting) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return WASI_ERRNO_FAULT; - } - - try { - const view = new DataView(instanceMemory.buffer); - const offset = Number(ptr) >>> 0; - view.setUint8(offset, Number(filetype) >>> 0); - view.setUint16(offset + 2, Number(flags) >>> 0, true); - view.setBigUint64(offset + 8, BigInt(rightsBase), true); - view.setBigUint64(offset + 16, BigInt(rightsInheriting), true); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } -} - -function mapSyntheticFsError(error) { - switch (error?.code) { - case 'EBADF': - return WASI_ERRNO_BADF; - case 'EACCES': - case 'EPERM': - return WASI_ERRNO_ACCES; - case 'EINVAL': - return WASI_ERRNO_INVAL; - case 'EROFS': - return WASI_ERRNO_ROFS; - default: - return WASI_ERRNO_FAULT; - } -} - -function seekGuestFileHandle(handle, offset, whence) { - const numericWhence = Number(whence) >>> 0; - let base; - if (numericWhence === WASI_WHENCE_SET) { - base = 0n; - } else if (numericWhence === WASI_WHENCE_CUR) { - base = BigInt(handle.position ?? 0); - } else if (numericWhence === WASI_WHENCE_END) { - base = BigInt(Number(fsModule.fstatSync(handle.targetFd).size ?? 0)); - } else { - return null; - } - - const next = base + BigInt(offset); - if (next < 0n || next > BigInt(Number.MAX_SAFE_INTEGER)) { - return null; - } - - handle.position = Number(next); - return next; -} - -function createPipeHandle(kind, pipe, displayFd) { - if (kind === 'pipe-read') { - pipe.readHandleCount += 1; - } else if (kind === 'pipe-write') { - pipe.writeHandleCount += 1; - } - - return { - kind, - pipe, - displayFd: Number(displayFd) >>> 0, - refCount: 1, - open: true, - }; -} - -function retainDelegateFd(fd) { - const numericFd = Number(fd) >>> 0; - delegateManagedFdRefCounts.set(numericFd, (delegateManagedFdRefCounts.get(numericFd) ?? 0) + 1); -} - -function releaseDelegateFd(fd) { - const numericFd = Number(fd) >>> 0; - const current = delegateManagedFdRefCounts.get(numericFd); - if (current == null) { - return false; - } - if (current <= 1) { - delegateManagedFdRefCounts.delete(numericFd); - return true; - } - delegateManagedFdRefCounts.set(numericFd, current - 1); - return false; -} - -function lookupFdHandle(fd) { - const numericFd = Number(fd) >>> 0; - return ( - syntheticFdEntries.get(numericFd) ?? - retainedSpawnOutputHandlesByFd.get(numericFd)?.handle ?? - passthroughHandles.get(numericFd) ?? - null - ); -} - -function lookupSyntheticHandleByDisplayFd(fd, expectedKind = null) { - const numericFd = Number(fd) >>> 0; - for (const handle of syntheticFdEntries.values()) { - if (!handle || handle.displayFd !== numericFd) { - continue; - } - if (expectedKind && handle.kind !== expectedKind) { - continue; - } - return handle; - } - - const retainedHandle = retainedSyntheticHandlesByDisplayFd.get(numericFd) ?? null; - if ( - retainedHandle && - (!expectedKind || retainedHandle.kind === expectedKind) - ) { - return retainedHandle; - } - - return null; -} - -function retainSyntheticHandleByDisplayFd(handle) { - if ( - handle && - (handle.kind === 'pipe-read' || handle.kind === 'pipe-write') - ) { - retainedSyntheticHandlesByDisplayFd.set(handle.displayFd >>> 0, handle); - } -} - -function releaseRetainedSyntheticHandleByDisplayFd(handle) { - if (!handle) { - return; - } - - const displayFd = handle.displayFd >>> 0; - if (retainedSyntheticHandlesByDisplayFd.get(displayFd) === handle) { - retainedSyntheticHandlesByDisplayFd.delete(displayFd); - } -} - -function cloneFdHandle(fd) { - const handle = lookupFdHandle(fd); - if (!handle) { - return null; - } - handle.refCount += 1; - return handle; -} - -function passthroughHandleHasCanonicalMapping(handle) { - for (const current of passthroughHandles.values()) { - if (current === handle) { - return true; - } - } - return false; -} - -function releaseFdHandle(handle) { - if (!handle) { - return; - } - - if (handle.kind === 'passthrough') { - handle.refCount = Math.max(0, handle.refCount - 1); - if ( - handle.refCount === 0 && - handle.open && - handle.targetFd > 2 && - !passthroughHandleHasCanonicalMapping(handle) && - releaseDelegateFd(handle.targetFd) && - typeof delegateManagedFdClose === 'function' - ) { - delegateManagedFdClose(handle.targetFd); - } - if (handle.refCount === 0 && handle.open && typeof handle.ioFd === 'number') { - try { - fsModule.closeSync(handle.ioFd); - } catch {} - handle.ioFd = null; - } - return; - } - - if (handle.kind === 'guest-file') { - handle.refCount = Math.max(0, handle.refCount - 1); - if (handle.refCount === 0 && handle.open) { - handle.open = false; - fsModule.closeSync(handle.targetFd); - } - return; - } - - handle.refCount = Math.max(0, handle.refCount - 1); - if (handle.refCount > 0 || !handle.open) { - return; - } - - handle.open = false; - if (handle.kind === 'pipe-read') { - handle.pipe.readHandleCount = Math.max(0, handle.pipe.readHandleCount - 1); - } else if (handle.kind === 'pipe-write') { - handle.pipe.writeHandleCount = Math.max(0, handle.pipe.writeHandleCount - 1); - if (handle.pipe.writeHandleCount === 0 && (handle.pipe.producers?.size ?? 0) === 0) { - closePipeConsumers(handle.pipe); - } - } -} - -function closeSyntheticFd(fd) { - const numericFd = Number(fd) >>> 0; - const handle = syntheticFdEntries.get(numericFd); - if (!handle) { - return false; - } - - const shouldRetainMapping = - ((handle.kind === 'pipe-write' && (handle.pipe.producers?.size ?? 0) > 0) || - (handle.kind === 'pipe-read' && (handle.pipe.consumers?.size ?? 0) > 0)); - if (shouldRetainMapping) { - retainSyntheticHandleByDisplayFd(handle); - } - if (!shouldRetainMapping) { - syntheticFdEntries.delete(numericFd); - } - releaseFdHandle(handle); - if (shouldRetainMapping) { - collectInactivePipeHandles(handle.pipe); - } - return true; -} - -function closePassthroughFd(fd) { - const numericFd = Number(fd) >>> 0; - const handle = passthroughHandles.get(numericFd); - if (!handle) { - return false; - } - - passthroughHandles.delete(numericFd); - closedPassthroughFds.add(numericFd); - if ((handle.refCount ?? 0) === 0) { - releaseFdHandle(handle); - } - return true; -} - -function rejectClosedPassthroughFd(fd) { - return closedPassthroughFds.has(Number(fd) >>> 0); -} - -function collectInactivePipeHandles(pipe) { - if (!pipe) { - return; - } - - if ( - (pipe.readHandleCount ?? 0) > 0 || - (pipe.writeHandleCount ?? 0) > 0 || - (pipe.producers?.size ?? 0) > 0 || - (pipe.consumers?.size ?? 0) > 0 - ) { - return; - } - - for (const [fd, handle] of Array.from(syntheticFdEntries.entries())) { - if ( - (handle.kind === 'pipe-read' || handle.kind === 'pipe-write') && - handle.pipe === pipe && - !handle.open && - handle.refCount === 0 - ) { - syntheticFdEntries.delete(fd); - } - } - - for (const [displayFd, handle] of Array.from(retainedSyntheticHandlesByDisplayFd.entries())) { - if ( - (handle.kind === 'pipe-read' || handle.kind === 'pipe-write') && - handle.pipe === pipe && - !handle.open && - handle.refCount === 0 - ) { - retainedSyntheticHandlesByDisplayFd.delete(displayFd); - } - } -} - -function resolveSpawnFd(fd) { - const numericFd = Number(fd) >>> 0; - const handle = lookupFdHandle(fd); - if (!handle) { - return numericFd; - } - if (handle.kind === 'passthrough') { - return handle.targetFd >>> 0; - } - if (handle.kind === 'guest-file') { - return numericFd; - } - return handle.displayFd >>> 0; -} - -function spawnStdinFdIsSyntheticPipe(fd) { - const handle = - lookupFdHandle(fd) ?? lookupSyntheticHandleByDisplayFd(fd, 'pipe-read'); - return handle?.kind === 'pipe-read'; -} - -// Shell input redirects (`cmd < file`) reach proc_spawn as a plain file fd in -// stdin_fd. The child cannot share that descriptor across the spawn boundary, -// so the remaining file contents are materialized and written to the child's -// stdin pipe, exactly like POSIX children reading an inherited file fd to EOF. -// Returns null when the fd is not a readable file-backed handle so callers can -// fail loudly instead of leaving the child hanging on an open stdin pipe. -function readSpawnStdinRedirectBytes(fd) { - const numericFd = Number(fd) >>> 0; - const handle = lookupFdHandle(numericFd); - if (!handle) { - return null; - } - - if (handle.kind === 'guest-file') { - const chunks = []; - let position = handle.position ?? 0; - for (;;) { - const buffer = Buffer.alloc(65536); - const bytesRead = fsModule.readSync( - handle.targetFd, - buffer, - 0, - buffer.length, - position, - ); - if (bytesRead <= 0) { - break; - } - chunks.push(buffer.subarray(0, bytesRead)); - position += bytesRead; - } - handle.position = position; - return Buffer.concat(chunks); - } - - if (handle.kind === 'passthrough' && typeof handle.guestPath === 'string') { - if (handle.guestPath === '/dev/null') { - return Buffer.alloc(0); - } - const stats = fsModule.statSync(handle.guestPath); - if (!stats.isFile()) { - return null; - } - return Buffer.from(fsModule.readFileSync(handle.guestPath)); - } - - return null; -} - -function retainSpawnOutputHandle(fd) { - const numericFd = Number(fd) >>> 0; - if (numericFd <= 2) { - return null; - } - - const retained = retainedSpawnOutputHandlesByFd.get(numericFd); - if (retained) { - retained.refCount += 1; - retained.handle.refCount += 1; - return { fd: numericFd, handle: retained.handle }; - } - - const handle = lookupFdHandle(numericFd); - if (handle?.kind !== 'guest-file' && handle?.kind !== 'passthrough') { - return null; - } - - handle.refCount += 1; - retainedSpawnOutputHandlesByFd.set(numericFd, { handle, refCount: 1 }); - return { fd: numericFd, handle }; -} - -function releaseSpawnOutputHandles(retainedHandles) { - for (const retained of retainedHandles ?? []) { - if (!retained || typeof retained.fd !== 'number' || !retained.handle) { - continue; - } - const retainedEntry = retainedSpawnOutputHandlesByFd.get(retained.fd); - if (retainedEntry?.handle === retained.handle) { - retainedEntry.refCount -= 1; - if (retainedEntry.refCount <= 0) { - retainedSpawnOutputHandlesByFd.delete(retained.fd); - } - } - releaseFdHandle(retained.handle); - } -} - -function collectGuestIovBytes(iovs, iovsLen) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - throw new Error('WebAssembly memory is not available'); - } - - const chunks = []; - let totalLength = 0; - - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const view = new DataView(instanceMemory.buffer); - const entryOffset = (Number(iovs) >>> 0) + index * 8; - const ptr = view.getUint32(entryOffset, true); - const len = view.getUint32(entryOffset + 4, true); - const chunk = readGuestBytes(ptr, len); - chunks.push(chunk); - totalLength += chunk.length; - } - - return Buffer.concat(chunks, totalLength); -} - -function writeBytesToGuestIovs(iovs, iovsLen, bytes) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - throw new Error('WebAssembly memory is not available'); - } - - const source = Buffer.from(bytes ?? []); - let written = 0; - - for (let index = 0; index < (Number(iovsLen) >>> 0) && written < source.length; index += 1) { - const view = new DataView(instanceMemory.buffer); - const memory = new Uint8Array(instanceMemory.buffer); - const entryOffset = (Number(iovs) >>> 0) + index * 8; - const ptr = view.getUint32(entryOffset, true); - const len = view.getUint32(entryOffset + 4, true); - const remaining = source.length - written; - const chunkLength = Math.min(len >>> 0, remaining); - memory.set(source.subarray(written, written + chunkLength), ptr >>> 0); - written += chunkLength; - } - - return written >>> 0; -} - -function dequeuePipeBytes(pipe, maxBytes) { - const requested = Math.max(0, Number(maxBytes) >>> 0); - if (requested === 0 || pipe.chunks.length === 0) { - return Buffer.alloc(0); - } - - const parts = []; - let remaining = requested; - while (remaining > 0 && pipe.chunks.length > 0) { - const chunk = pipe.chunks[0]; - if (chunk.length <= remaining) { - parts.push(chunk); - pipe.chunks.shift(); - remaining -= chunk.length; - continue; - } - - parts.push(chunk.subarray(0, remaining)); - pipe.chunks[0] = chunk.subarray(remaining); - remaining = 0; - } - - return Buffer.concat(parts); -} - -function enqueuePipeBytes(pipe, bytes) { - const chunk = Buffer.from(bytes ?? []); - if (chunk.length === 0) { - return; - } - pipe.chunks.push(chunk); -} - -function pipeHasReaders(pipe) { - return ( - (pipe?.readHandleCount ?? 0) > 0 || - (pipe?.consumers?.size ?? 0) > 0 - ); -} - -function unregisterPipeProducer(pipe, producerKey) { - if (!pipe || typeof pipe.producers?.delete !== 'function') { - return; - } - pipe.producers.delete(producerKey); - if (pipe.producers.size === 0 && (pipe.writeHandleCount ?? 0) === 0) { - closePipeConsumers(pipe); - } - collectInactivePipeHandles(pipe); -} - -function unregisterPipeConsumer(pipe, consumerKey) { - if (!pipe || typeof pipe.consumers?.delete !== 'function') { - return; - } - pipe.consumers.delete(consumerKey); - collectInactivePipeHandles(pipe); -} - -function unregisterChildPipeProducers(record) { - if (!record || !record.childId) { - return; - } - - for (const [stream, fd, pipe] of [ - ['stdout', record.stdoutFd, record.stdoutPipe], - ['stderr', record.stderrFd, record.stderrPipe], - ]) { - const outputPipe = - pipe ?? - (() => { - const handle = - lookupFdHandle(fd) ?? lookupSyntheticHandleByDisplayFd(fd, 'pipe-write'); - return handle?.kind === 'pipe-write' ? handle.pipe : null; - })(); - if (outputPipe) { - unregisterPipeProducer(outputPipe, `${record.childId}:${stream}`); - } - } -} - -function unregisterChildPipeConsumers(record) { - if (!record || !record.childId) { - return; - } - - const inputPipe = resolveChildInputPipe(record); - if (inputPipe) { - unregisterPipeConsumer(inputPipe, `${record.childId}:stdin`); - } -} - -function resolveChildInputPipe(record) { - if (!record) { - return null; - } - - return ( - record.stdinPipe ?? - (() => { - const handle = - lookupFdHandle(record.stdinFd) ?? - lookupSyntheticHandleByDisplayFd(record.stdinFd, 'pipe-read'); - return handle?.kind === 'pipe-read' ? handle.pipe : null; - })() - ); -} - -function registerPipeProducer(fd, childId, stream) { - const handle = - lookupFdHandle(fd) ?? lookupSyntheticHandleByDisplayFd(fd, 'pipe-write'); - if (handle?.kind !== 'pipe-write') { - return null; - } - handle.pipe.producers.set(`${childId}:${stream}`, { childId, stream }); - traceHostProcess('register-producer', { fd: Number(fd) >>> 0, childId, stream, pipeId: handle.pipe.id }); - return handle.pipe; -} - -function registerPipeConsumer(fd, childId, stream) { - const handle = - lookupFdHandle(fd) ?? lookupSyntheticHandleByDisplayFd(fd, 'pipe-read'); - if (handle?.kind !== 'pipe-read') { - return null; - } - handle.pipe.consumers.set(`${childId}:${stream}`, { childId, stream }); - const shouldDeferInitialDelivery = - stream === 'stdin' && !spawnedChildrenById.has(childId); - traceHostProcess('register-consumer', { - fd: Number(fd) >>> 0, - childId, - stream, - pipeId: handle.pipe.id, - deferred: shouldDeferInitialDelivery, - }); - if (!shouldDeferInitialDelivery) { - if (handle.pipe.chunks.length > 0) { - flushPipeConsumers(handle.pipe); - } - if (handle.pipe.producers.size === 0 && (handle.pipe.writeHandleCount ?? 0) === 0) { - closePipeConsumers(handle.pipe); - } - } - return handle.pipe; -} - -function flushPipeConsumers(pipe) { - if ( - !pipe || - typeof pipe.consumers?.size !== 'number' || - !Array.isArray(pipe.chunks) || - pipe.consumers.size === 0 || - pipe.chunks.length === 0 - ) { - return false; - } - - let flushed = false; - while (pipe.chunks.length > 0) { - const chunk = pipe.chunks[0]; - if (!chunk || chunk.length === 0) { - pipe.chunks.shift(); - continue; - } - let shouldRetryChunk = false; - for (const [consumerKey, consumer] of Array.from(pipe.consumers.entries())) { - try { - callSyncRpc('child_process.write_stdin', [consumer.childId, chunk]); - traceHostProcess('flush-consumer-write', { - pipeId: pipe.id, - childId: consumer.childId, - bytes: chunk.length, - }); - flushed = true; - } catch (error) { - if (spawnedChildrenById.has(consumer?.childId) && isChildProcessGoneError(error)) { - shouldRetryChunk = true; - continue; - } - traceHostProcess('flush-consumer-write-failed', { - pipeId: pipe.id, - childId: consumer?.childId ?? null, - }); - pipe.consumers.delete(consumerKey); - } - } - if (shouldRetryChunk) { - break; - } - pipe.chunks.shift(); - } - - return flushed; -} - -function closePipeConsumers(pipe) { - if (!pipe || typeof pipe.consumers?.size !== 'number' || pipe.consumers.size === 0) { - return false; - } - - let closed = false; - for (const [consumerKey, consumer] of Array.from(pipe.consumers.entries())) { - try { - callSyncRpc('child_process.close_stdin', [consumer.childId]); - traceHostProcess('close-consumer-stdin', { - pipeId: pipe.id, - childId: consumer.childId, - }); - closed = true; - } catch (error) { - if (spawnedChildrenById.has(consumer?.childId) && isChildProcessGoneError(error)) { - continue; - } - traceHostProcess('close-consumer-stdin-failed', { - pipeId: pipe.id, - childId: consumer?.childId ?? null, - }); - // Ignore close errors during teardown. - } - pipe.consumers.delete(consumerKey); - } - - collectInactivePipeHandles(pipe); - return closed; -} - -function consumeSpawnOutputFd(fd) { - const numericFd = Number(fd) >>> 0; - const handle = syntheticFdEntries.get(numericFd); - if (handle?.kind === 'pipe-write' && handle.open) { - // Release the guest-owned write handle but retain the fd mapping so later - // child stdout/stderr events can still route into the synthetic pipe. - releaseFdHandle(handle); - } -} - -function routeChunkToFd(fd, bytes) { - const numericFd = Number(fd) >>> 0; - const handle = - lookupFdHandle(numericFd) ?? - lookupSyntheticHandleByDisplayFd(numericFd) ?? - (typeof globalThis.lookupFdHandle === 'function' - ? globalThis.lookupFdHandle(numericFd) - : null); - traceHostProcess('route-chunk', { - fd: numericFd, - handleKind: handle?.kind ?? null, - bytes: Buffer.from(bytes ?? []).length, - }); - if (!handle) { - if (isStdioFd(numericFd) && routeChunkToDelegateFd(numericFd, bytes)) { - return; - } - if (isStdioFd(numericFd)) { - writeToStdioFd(numericFd, Buffer.from(bytes ?? [])); - return; - } - if (numericFd > 2 && routeChunkToDelegateFd(numericFd, bytes)) { - return; - } - writeSync(numericFd, bytes); - return; - } - - if (handle.kind === 'passthrough') { - if (handle.append === true && typeof handle.guestPath === 'string') { - fsModule.appendFileSync(handle.guestPath, Buffer.from(bytes ?? [])); - return; - } - if (routeChunkToDelegateFd(handle.targetFd, bytes)) { - return; - } - if (isStdioFd(handle.targetFd)) { - writeToStdioFd(handle.targetFd, Buffer.from(bytes ?? [])); - return; - } - writeSync(handle.targetFd, bytes); - return; - } - - if (handle.kind === 'host-passthrough') { - if (routeChunkToDelegateFd(handle.displayFd ?? numericFd, bytes)) { - return; - } - if (routeChunkToDelegateFd(handle.targetFd, bytes)) { - return; - } - if (isStdioFd(handle.targetFd)) { - writeToStdioFd(handle.targetFd, Buffer.from(bytes ?? [])); - return; - } - writeSync(handle.targetFd, bytes); - return; - } - - if (handle.kind === 'pipe-write') { - enqueuePipeBytes(handle.pipe, bytes); - flushPipeConsumers(handle.pipe); - return; - } - - if (handle.kind === 'guest-file') { - writeBytesToGuestFileHandle(handle, Buffer.from(bytes ?? [])); - return; - } - - throw new Error(`bad file descriptor ${numericFd}`); -} - -function writeBytesToGuestFileHandle(handle, bytes) { - const chunk = Buffer.from(bytes ?? []); - const position = handle.append ? null : (handle.position ?? 0); - const written = fsModule.writeSync( - handle.targetFd, - chunk, - 0, - chunk.length, - position, - ); - if (handle.append) { - handle.position = Number(fsModule.fstatSync(handle.targetFd).size ?? 0); - } else { - handle.position = (handle.position ?? 0) + written; - } - return written; -} - -function routeChunkToDelegateFd(fd, bytes) { - if (!(instanceMemory instanceof WebAssembly.Memory) || typeof delegateManagedFdWrite !== 'function') { - return false; - } - - const chunk = Buffer.from(bytes ?? []); - const needed = 8 + chunk.length + 4; - if ( - delegateWriteScratch.capacity < needed || - delegateWriteScratch.base + needed > instanceMemory.buffer.byteLength - ) { - const pages = Math.max(1, Math.ceil(needed / 65536)); - const basePage = instanceMemory.grow(pages); - delegateWriteScratch = { - base: basePage * 65536, - capacity: pages * 65536, - }; - } - - try { - const iovsPtr = delegateWriteScratch.base; - const dataPtr = iovsPtr + 8; - const nwrittenPtr = dataPtr + chunk.length; - const memory = new Uint8Array(instanceMemory.buffer); - const view = new DataView(instanceMemory.buffer); - memory.set(chunk, dataPtr); - view.setUint32(iovsPtr, dataPtr, true); - view.setUint32(iovsPtr + 4, chunk.length, true); - const result = delegateManagedFdWrite(fd, iovsPtr, 1, nwrittenPtr); - traceHostProcess('route-chunk-delegate', { - fd: Number(fd) >>> 0, - bytes: chunk.length, - result, - }); - return result === WASI_ERRNO_SUCCESS; - } catch (error) { - traceHostProcess('route-chunk-delegate-error', { - fd: Number(fd) >>> 0, - bytes: chunk.length, - message: error instanceof Error ? error.message : String(error), - }); - return false; - } -} - -function finalizeChildExit(record, exitCode, signal) { - const status = - signal == null - ? (Number(exitCode ?? 1) & 0xff) - : 128 + (signalNumberFromName(signal) & 0x7f); - record.exitStatus = status; - for (const fd of record.delegateRetainedFds ?? []) { - if (releaseDelegateFd(fd) && typeof delegateManagedFdClose === 'function') { - delegateManagedFdClose(fd); - } - } - releaseSpawnOutputHandles(record.retainedSpawnOutputHandles); - unregisterChildPipeProducers(record); - unregisterChildPipeConsumers(record); - return status; -} - -function pollChildEvent(record, waitMs) { - if (Array.isArray(record?.pendingEvents) && record.pendingEvents.length > 0) { - return record.pendingEvents.shift() ?? null; - } - if (record?.synthetic) { - return null; - } - return callSyncRpc('child_process.poll', [record.childId, waitMs]); -} - -function isChildProcessGoneError(error) { - return ( - (error instanceof Error && error.code === 'ECHILD') || - (error instanceof Error && - typeof error.message === 'string' && - error.message.startsWith('ECHILD:')) - ); -} - -function resolveSyntheticGuestPath(value, fromGuestDir = '/') { - if (typeof value !== 'string') { - return value; - } - if (value.startsWith('file:')) { - try { - return path.posix.normalize(new URL(value).pathname); - } catch { - return value; - } - } - if (value.startsWith('/')) { - return path.posix.normalize(value); - } - if (value.startsWith('./') || value.startsWith('../')) { - return path.posix.normalize(path.posix.join(fromGuestDir, value)); - } - return value; -} - -function resolveSyntheticHostPath(value, fromGuestDir = '/') { - const mapping = resolveSyntheticHostMapping(value, fromGuestDir); - return mapping?.hostPath ?? null; -} - -function resolveSyntheticHostMapping(value, fromGuestDir = '/') { - const guestPath = resolveSyntheticGuestPath(value, fromGuestDir); - if (typeof guestPath !== 'string') { - return null; - } - return resolveModuleGuestPathToHostMapping(guestPath); -} - -function chmodMappedGuestPath(guestPath, hostPath, mode) { - fsModule.chmodSync(hostPath, mode); - try { - if (typeof guestPath === 'string' && guestPath.length > 0) { - fsModule.chmodSync(guestPath, mode); - } - } catch { - // Best effort: host-mapped paths may not also exist as direct kernel paths. - } -} - -function maybeCreateSyntheticCommandResult(command, args, cwd) { - const basename = path.posix.basename(String(command || '')); - - if (basename === 'chmod') { - if (args.length < 2 || !args.every((arg) => typeof arg === 'string')) { - return null; - } - const modeArg = args[0]; - if (!/^[0-7]{3,4}$/.test(modeArg)) { - return null; - } - const mode = Number.parseInt(modeArg, 8) >>> 0; - try { - for (const targetArg of args.slice(1)) { - const guestPath = resolveSyntheticGuestPath(targetArg, cwd || '/'); - const mapping = resolveSyntheticHostMapping(targetArg, cwd || '/'); - if (!mapping || typeof mapping.hostPath !== 'string') { - throw new Error(`No such file or directory: ${targetArg}`); - } - if (mapping.readOnly) { - const error = new Error(`Read-only file system: ${targetArg}`); - error.code = 'EROFS'; - throw error; - } - chmodMappedGuestPath(guestPath, mapping.hostPath, mode); - } - return { exitCode: 0, stdout: '', stderr: '' }; - } catch (error) { - return { - exitCode: 1, - stdout: '', - stderr: `chmod: ${error instanceof Error ? error.message : String(error)}\n`, - }; - } - } - - if (basename === 'stat') { - if ( - args.length === 3 && - args[0] === '-c' && - (args[1] === '%a' || args[1] === '"%a"') && - typeof args[2] === 'string' - ) { - try { - const hostPath = resolveSyntheticHostPath(args[2], cwd || '/'); - if (typeof hostPath !== 'string') { - return null; - } - const stat = fsModule.statSync(hostPath); - const mode = Number(stat?.mode) >>> 0; - return { - exitCode: 0, - stdout: `${(mode & 0o777).toString(8)}\n`, - stderr: '', - }; - } catch { - return null; - } - } - return null; - } - - return null; -} - -function createSyntheticChildRecord(result, stdinTarget, stdoutTarget, stderrTarget) { - const pid = nextSyntheticChildPid++; - const childId = `synthetic-child-${pid}`; - const pendingEvents = [{ - type: 'exit', - exitCode: Number(result?.exitCode ?? 1) >>> 0, - signal: null, - }]; - - return { - childId, - pid, - stdinFd: stdinTarget, - stdoutFd: stdoutTarget, - stderrFd: stderrTarget, - stdinPipe: null, - stdoutPipe: null, - stderrPipe: null, - delegateRetainedFds: [], - exitStatus: null, - pendingEvents, - synthetic: true, - }; -} - -function emitSyntheticCommandOutput(record, stdoutFd, stderrFd, result) { - const syntheticOutputs = [ - ['stdout', stdoutFd, record.stdoutFd, result?.stdout], - ['stderr', stderrFd, record.stderrFd, result?.stderr], - ]; - - for (const [stream, rawFd, targetFd, value] of syntheticOutputs) { - const text = typeof value === 'string' ? value : ''; - const pipe = registerPipeProducer(targetFd, record.childId, stream); - consumeSpawnOutputFd(rawFd); - if (text.length > 0 && targetFd !== 0xffffffff) { - routeChunkToFd(targetFd, Buffer.from(text, 'utf8')); - } - if (pipe) { - unregisterPipeProducer(pipe, `${record.childId}:${stream}`); - } - } -} - -function reapSpawnedChild(record) { - if (!record) { - return; - } - - spawnedChildren.delete(record.pid); - if (typeof record.childId === 'string' && record.childId.length > 0) { - spawnedChildrenById.delete(record.childId); - } -} - -function processChildEvent(record, event) { - if (!event) { - return false; - } - traceHostProcess('child-event', { - childId: record?.childId ?? null, - pid: record?.pid ?? null, - type: event.type, - exitCode: event.exitCode ?? null, - signal: event.signal ?? null, - }); - - if (event.type === 'stdout' && record.stdoutFd !== 0xffffffff) { - const chunk = decodeSyncRpcValue(event.data); - if (chunk?.length > 0) { - routeChunkToFd(record.stdoutFd, chunk); - } - return true; - } - - if (event.type === 'stderr' && record.stderrFd !== 0xffffffff) { - const chunk = decodeSyncRpcValue(event.data); - if (chunk?.length > 0) { - routeChunkToFd(record.stderrFd, chunk); - } - return true; - } - - if (event.type === 'signal') { - dispatchWasmSignal( - typeof event.number === 'number' ? event.number : signalNumberFromName(event.signal), - ); - return true; - } - - if (event.type === 'exit') { - const exitCode = - typeof event.exitCode === 'number' ? Math.trunc(event.exitCode) : null; - const signal = - typeof event.signal === 'string' ? event.signal : null; - while (true) { - let trailingEvent = null; - try { - trailingEvent = pollChildEvent(record, 0); - } catch (error) { - if (isChildProcessGoneError(error)) { - break; - } - throw error; - } - if (!trailingEvent) { - break; - } - if (!processChildEvent(record, trailingEvent)) { - break; - } - } - finalizeChildExit(record, exitCode, signal); - return true; - } - - return false; -} - -function pumpPipeProducers(pipe, waitMs) { - let processed = false; - for (const [producerKey, producer] of Array.from(pipe.producers.entries())) { - const record = spawnedChildrenById.get(producer.childId); - if (!record) { - unregisterPipeProducer(pipe, producerKey); - continue; - } - if (typeof record.exitStatus === 'number') { - unregisterPipeProducer(pipe, producerKey); - continue; - } - - processed = pumpChildInputPipe(record, 0) || processed; - - const event = pollChildEvent(record, waitMs); - if (!event) { - continue; - } - - processed = true; - processChildEvent(record, event); - } - - return processed; -} - -function pumpChildInputPipe(record, waitMs) { - const inputPipe = resolveChildInputPipe(record); - if (!inputPipe) { - traceHostProcess('pump-child-input-skip-no-pipe', { - childId: record?.childId ?? null, - }); - return false; - } - if (record.pumpingInputPipe === true) { - return false; - } - record.pumpingInputPipe = true; - try { - const stdinReadyAt = Number(record?.stdinReadyAtMs) || 0; - if (stdinReadyAt > Date.now()) { - traceHostProcess('pump-child-input-deferred', { - childId: record?.childId ?? null, - waitMs: Number(waitMs) >>> 0, - stdinReadyAt, - now: Date.now(), - chunkCount: inputPipe.chunks.length, - writeHandleCount: inputPipe.writeHandleCount ?? null, - producerCount: inputPipe.producers?.size ?? null, - }); - return false; - } - - let progressed = false; - traceHostProcess('pump-child-input-begin', { - childId: record?.childId ?? null, - waitMs: Number(waitMs) >>> 0, - chunkCount: inputPipe.chunks.length, - writeHandleCount: inputPipe.writeHandleCount ?? null, - producerCount: inputPipe.producers?.size ?? null, - }); - if (inputPipe.chunks.length > 0) { - progressed = flushPipeConsumers(inputPipe) || progressed; - } - - if (inputPipe.producers.size === 0 && (inputPipe.writeHandleCount ?? 0) === 0) { - return closePipeConsumers(inputPipe) || progressed; - } - - const pumped = pumpPipeProducers(inputPipe, waitMs); - progressed = pumped || progressed; - if (inputPipe.chunks.length > 0) { - progressed = flushPipeConsumers(inputPipe) || progressed; - } - if (inputPipe.producers.size === 0 && (inputPipe.writeHandleCount ?? 0) === 0) { - progressed = closePipeConsumers(inputPipe) || progressed; - } - - return progressed; - } finally { - record.pumpingInputPipe = false; - } -} - -function pumpSpawnedChildren(waitMs) { - let progressed = false; - for (const record of Array.from(spawnedChildren.values())) { - if (!record || typeof record.exitStatus === 'number') { - continue; - } - try { - const event = pollChildEvent(record, waitMs); - if (event) { - processChildEvent(record, event); - progressed = true; - } - progressed = pumpChildInputPipe(record, 0) || progressed; - } catch (error) { - if (!isChildProcessGoneError(error)) { - throw error; - } - } - } - return progressed; -} - -function encodeGuestBytes(value) { - return new TextEncoder().encode(String(value)); -} - -function readGuestBytes(ptr, len) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - throw new Error('WebAssembly memory is not available'); - } - - const start = Number(ptr) >>> 0; - const length = Number(len) >>> 0; - return Buffer.from(new Uint8Array(instanceMemory.buffer, start, length)); -} - -function readGuestString(ptr, len) { - return readGuestBytes(ptr, len).toString('utf8'); -} - -function decodeNullSeparatedStrings(buffer) { - if (!buffer || buffer.length === 0) { - return []; - } - - return buffer - .toString('utf8') - .split('\0') - .filter((entry) => entry.length > 0); -} - -function parseSerializedEnv(buffer) { - const env = {}; - for (const entry of decodeNullSeparatedStrings(buffer)) { - const delimiter = entry.indexOf('='); - if (delimiter <= 0) { - continue; - } - env[entry.slice(0, delimiter)] = entry.slice(delimiter + 1); - } - return env; -} - -function encodeSyncRpcValue(value) { - if ( - value == null || - typeof value === 'string' || - typeof value === 'number' || - typeof value === 'boolean' - ) { - return value; - } - - if (typeof Buffer === 'function' && Buffer.isBuffer(value)) { - return { - __agentOSType: 'bytes', - base64: value.toString('base64'), - }; - } - - if (ArrayBuffer.isView(value)) { - return { - __agentOSType: 'bytes', - base64: Buffer.from(value.buffer, value.byteOffset, value.byteLength).toString('base64'), - }; - } - - if (value instanceof ArrayBuffer) { - return { - __agentOSType: 'bytes', - base64: Buffer.from(value).toString('base64'), - }; - } - - if (Array.isArray(value)) { - return value.map((entry) => encodeSyncRpcValue(entry)); - } - - if (typeof value === 'object') { - return Object.fromEntries( - Object.entries(value).map(([key, entry]) => [key, encodeSyncRpcValue(entry)]), - ); - } - - return String(value); -} - -function decodeSyncRpcValue(value) { - if (Array.isArray(value)) { - return value.map((entry) => decodeSyncRpcValue(entry)); - } - - if (Buffer.isBuffer(value)) { - return value; - } - - if (ArrayBuffer.isView(value)) { - return Buffer.from(value.buffer, value.byteOffset, value.byteLength); - } - - if (value && typeof value === 'object') { - if (value.__type === 'Buffer' && typeof value.data === 'string') { - return Buffer.from(value.data, 'base64'); - } - - if (value.__agentOSType === 'bytes' && typeof value.base64 === 'string') { - return Buffer.from(value.base64, 'base64'); - } - - return Object.fromEntries( - Object.entries(value).map(([key, entry]) => [key, decodeSyncRpcValue(entry)]), - ); - } - - return value; -} - -function readSyncRpcLine() { - while (true) { - const newlineIndex = syncRpcResponseBuffer.indexOf('\n'); - if (newlineIndex >= 0) { - const line = syncRpcResponseBuffer.slice(0, newlineIndex); - syncRpcResponseBuffer = syncRpcResponseBuffer.slice(newlineIndex + 1); - return line; - } - - const chunk = Buffer.alloc(4096); - const bytesRead = readSync(NODE_SYNC_RPC_RESPONSE_FD, chunk, 0, chunk.length, null); - if (bytesRead === 0) { - throw new Error('secure-exec WASM sync RPC response channel closed unexpectedly'); - } - syncRpcResponseBuffer += chunk.subarray(0, bytesRead).toString('utf8'); - } -} - -function callSyncRpc(method, args = []) { - if ( - globalThis.__agentOSSyncRpc && - typeof globalThis.__agentOSSyncRpc.callSync === 'function' - ) { - const startedNs = __agentOSWasmNowNs(); - try { - return globalThis.__agentOSSyncRpc.callSync(method, args); - } finally { - __agentOSWasiRecordSyncRpc(method, 'glue', startedNs); - } - } - - if (!NODE_SYNC_RPC_ENABLE || NODE_SYNC_RPC_REQUEST_FD == null || NODE_SYNC_RPC_RESPONSE_FD == null) { - const error = new Error(`secure-exec WASM sync RPC is unavailable for ${method}`); - error.code = 'ERR_AGENTOS_WASM_SYNC_RPC_UNAVAILABLE'; - throw error; - } - - const startedNs = __agentOSWasmNowNs(); - try { - const payload = JSON.stringify({ - id: nextSyncRpcId++, - method, - args: encodeSyncRpcValue(args), - }); - writeSync(NODE_SYNC_RPC_REQUEST_FD, `${payload}\n`); - - const response = JSON.parse(readSyncRpcLine()); - if (response?.ok) { - return decodeSyncRpcValue(response.result); - } - - const error = new Error( - response?.error?.message || `secure-exec WASM sync RPC ${method} failed`, - ); - if (typeof response?.error?.code === 'string') { - error.code = response.error.code; - } - throw error; - } finally { - __agentOSWasiRecordSyncRpc(method, 'pipe', startedNs); - } -} - -const hostNetSockets = new Map(); -let nextHostNetSocketFd = 0x40000000; -const HOST_NET_TIMEOUT_SENTINEL = '__secure_exec_net_timeout__'; - -function getHostNetSocket(fd) { - return hostNetSockets.get(Number(fd) >>> 0) ?? null; -} - -function dequeueHostNetBytes(socket, maxBytes) { - const requested = Math.max(0, Number(maxBytes) >>> 0); - if (requested === 0 || socket.readChunks.length === 0) { - return Buffer.alloc(0); - } - - const parts = []; - let remaining = requested; - while (remaining > 0 && socket.readChunks.length > 0) { - const chunk = socket.readChunks[0]; - if (chunk.length <= remaining) { - parts.push(chunk); - socket.readChunks.shift(); - remaining -= chunk.length; - continue; - } - - parts.push(chunk.subarray(0, remaining)); - socket.readChunks[0] = chunk.subarray(remaining); - remaining = 0; - } - - return Buffer.concat(parts); -} - -function pollHostNetSocket(socket, waitMs) { - if (!socket?.socketId || socket.closed) { - return null; - } - - const event = callSyncRpc('net.poll', [socket.socketId, Math.max(0, Number(waitMs) >>> 0)]); - if (!event) { - return null; - } - - if (event.type === 'data') { - const chunk = decodeSyncRpcValue(event.data); - if (chunk?.length > 0) { - socket.readChunks.push(Buffer.from(chunk)); - } - return event; - } - - if (event.type === 'end' || event.type === 'close') { - socket.readableEnded = true; - if (event.type === 'close') { - socket.closed = true; - socket.socketId = null; - } - return event; - } - - if (event.type === 'error') { - socket.lastError = String(event.message || event.code || 'socket error'); - socket.closed = true; - socket.socketId = null; - return event; - } - - return event; -} - -function parseHostNetAddress(raw) { - const value = String(raw ?? '').trim(); - if (!value) { - throw new Error('host_net address is required'); - } - - if (value.startsWith('[')) { - const end = value.indexOf(']'); - if (end < 0 || value.charCodeAt(end + 1) !== 58) { - throw new Error(`invalid host_net address ${value}`); - } - return { - host: value.slice(1, end), - port: Number.parseInt(value.slice(end + 2), 10), - }; - } - - const separator = value.lastIndexOf(':'); - if (separator <= 0 || separator === value.length - 1) { - throw new Error(`invalid host_net address ${value}`); - } - - return { - host: value.slice(0, separator), - port: Number.parseInt(value.slice(separator + 1), 10), - }; -} - -function parseHostNetListenAddress(raw) { - const value = String(raw ?? '').trim(); - if (!value) { - throw new Error('host_net listen address is required'); - } - if (value.startsWith('/')) { - return { path: value }; - } - const address = parseHostNetAddress(value); - return { host: address.host, port: address.port }; -} - -function normalizeHostNetAddressInfo(address, port) { - const host = String(address ?? ''); - const numericPort = Number(port); - if (!host || !Number.isInteger(numericPort) || numericPort < 0 || numericPort > 65535) { - return null; - } - return { address: host, port: numericPort }; -} - -function formatHostNetAddressInfo(info) { - const address = String(info?.address ?? ''); - const port = Number(info?.port); - if (!address || !Number.isInteger(port) || port < 0 || port > 65535) { - throw new Error('host_net socket address is incomplete'); - } - return `${address}:${port}`; -} - -const HOST_NET_AF_INET = 2; -const HOST_NET_AF_INET6 = 10; -const HOST_NET_SOCK_DGRAM = 5; -const HOST_NET_SOCKET_TYPE_MASK = 0xf; -const HOST_NET_SOL_SOCKET = 1; -const HOST_NET_WASI_SOL_SOCKET = 0x7fffffff; -const HOST_NET_SO_RCVTIMEO_64 = 20; -const HOST_NET_SO_RCVTIMEO_32 = 66; -const HOST_NET_TIMEVAL_BYTES = 16; - -function hostNetSocketBaseType(socket) { - return Number(socket?.sockType ?? 0) & HOST_NET_SOCKET_TYPE_MASK; -} - -function hostNetSockoptKind(level, optname, optvalLen) { - const normalizedLevel = Number(level) >>> 0; - const normalizedOptname = Number(optname) >>> 0; - const normalizedOptvalLen = Number(optvalLen) >>> 0; - if ( - normalizedLevel !== HOST_NET_SOL_SOCKET && - normalizedLevel !== HOST_NET_WASI_SOL_SOCKET - ) { - return null; - } - if (normalizedOptvalLen !== HOST_NET_TIMEVAL_BYTES) { - return null; - } - if ( - normalizedOptname === HOST_NET_SO_RCVTIMEO_64 || - normalizedOptname === HOST_NET_SO_RCVTIMEO_32 - ) { - return 'recv-timeout'; - } - return null; -} - -function parseHostNetTimevalMs(bytes) { - if (bytes.byteLength !== HOST_NET_TIMEVAL_BYTES) { - return null; - } - const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); - const seconds = view.getBigInt64(0, true); - const microseconds = view.getBigInt64(8, true); - if (seconds < 0n || microseconds < 0n || microseconds > 999999n) { - return null; - } - if (seconds === 0n && microseconds === 0n) { - return null; - } - const milliseconds = seconds * 1000n + (microseconds + 999n) / 1000n; - if (milliseconds > BigInt(Number.MAX_SAFE_INTEGER)) { - return null; - } - return Number(milliseconds); -} - -function ensureHostNetUdpSocket(socket) { - if (!socket || socket.closed || hostNetSocketBaseType(socket) !== HOST_NET_SOCK_DGRAM) { - return null; - } - if (socket.udpSocketId) { - return socket.udpSocketId; - } - - const type = socket.domain === HOST_NET_AF_INET6 ? 'udp6' : 'udp4'; - const result = callSyncRpc('dgram.createSocket', [{ type }]); - if (!result || typeof result.socketId !== 'string') { - throw new Error('host_net dgram socket creation failed'); - } - socket.udpSocketId = result.socketId; - return socket.udpSocketId; -} - -function signalNumberFromName(signal) { - const mapped = LINUX_SIGNAL_NAMES.indexOf(String(signal)); - if (mapped > 0) { - return mapped; - } - if (String(signal).startsWith('SIG')) { - const numeric = Number.parseInt(String(signal).slice(3), 10); - return Number.isInteger(numeric) ? numeric : 15; - } - return 15; -} - -function signalNameFromNumber(signal) { - const numeric = Number(signal) >>> 0; - return LINUX_SIGNAL_NAMES[numeric] ?? `SIG${numeric}`; -} - -const LINUX_SIGNAL_NAMES = [ - null, - 'SIGHUP', - 'SIGINT', - 'SIGQUIT', - 'SIGILL', - 'SIGTRAP', - 'SIGABRT', - 'SIGBUS', - 'SIGFPE', - 'SIGKILL', - 'SIGUSR1', - 'SIGSEGV', - 'SIGUSR2', - 'SIGPIPE', - 'SIGALRM', - 'SIGTERM', - null, - 'SIGCHLD', - 'SIGCONT', - 'SIGSTOP', - 'SIGTSTP', - 'SIGTTIN', - 'SIGTTOU', - 'SIGURG', - 'SIGXCPU', - 'SIGXFSZ', - 'SIGVTALRM', - 'SIGPROF', - 'SIGWINCH', - 'SIGIO', - 'SIGPWR', - 'SIGSYS', -]; - -function writeGuestBytes(ptr, maxLen, bytes, actualLenPtr) { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return WASI_ERRNO_FAULT; - } - - try { - const requestedLength = Number(maxLen) >>> 0; - const memory = new Uint8Array(instanceMemory.buffer); - const written = Math.min(requestedLength, bytes.byteLength); - memory.set(bytes.subarray(0, written), Number(ptr)); - return writeGuestUint32(actualLenPtr, written); - } catch { - return WASI_ERRNO_FAULT; - } -} - -// Perform a single NON-BLOCKING accept on a listening host_net socket. On success it -// registers the accepted connection as a new host_net socket and returns -// { acceptedFd, address } (address is a Buffer: "host:port" for TCP, the peer path for -// AF_UNIX). Returns null when no connection is currently pending. Used by both net_poll -// (to report accurate listener readiness) and net_accept (non-blocking semantics) so the -// server never blocks inside accept() and starves already-connected clients. -function tryHostNetAcceptOnce(socket) { - let result = callSyncRpc('net.server_accept', [socket.serverId]); - if (!result || result === HOST_NET_TIMEOUT_SENTINEL) { - return null; - } - if (typeof result === 'string') { - result = JSON.parse(result); - } - if (!result || typeof result.socketId !== 'string') { - return null; - } - - const acceptedFd = nextHostNetSocketFd++; - hostNetSockets.set(acceptedFd, { - domain: socket.domain, - sockType: socket.sockType, - protocol: socket.protocol, - bindOptions: null, - localInfo: normalizeHostNetAddressInfo(result.info?.localAddress, result.info?.localPort), - localReservation: null, - remoteInfo: normalizeHostNetAddressInfo(result.info?.remoteAddress, result.info?.remotePort), - serverId: null, - socketId: result.socketId, - udpSocketId: null, - recvTimeoutMs: socket.recvTimeoutMs, - readChunks: [], - readableEnded: false, - closed: false, - lastError: null, - }); - - let address; - if (result.info?.remoteAddress != null && result.info?.remotePort != null) { - address = Buffer.from(formatHostNetAddressInfo({ - address: result.info.remoteAddress, - port: result.info.remotePort, - }), 'utf8'); - } else { - address = Buffer.from(String(result.info?.remotePath ?? ''), 'utf8'); - } - return { acceptedFd, address }; -} - -const hostNetImport = { - // Poll an array of pollfd entries (8 bytes each: i32 fd, i16 events, i16 revents). - // Connected sockets report POLLIN when data is queued; listening sockets report POLLIN - // only when a connection is actually pending (a buffered non-blocking accept), so the - // server's WaitForSomething does not spin forever inside a blocking accept(). - // POLLOUT is always writable. - net_poll(fdsPtr, nfds, timeoutMs, retReadyPtr) { - const n = Number(nfds) >>> 0; - const base0 = Number(fdsPtr) >>> 0; - // The patched wasi sysroot's effective poll bits (bits/poll.h): POLLIN=POLLRDNORM=0x1, - // POLLOUT=POLLWRNORM=0x2 (NOT the 0x004 in legacy poll.h). Guests (X server + libxcb) use - // these, so net_poll must match or POLLOUT readiness is never reported and writers block. - const POLLIN = 0x001; - const POLLOUT = 0x002; - const POLLERR = 0x008; - const POLLHUP = 0x010; - const POLLNVAL = 0x020; - const t = Number(timeoutMs) | 0; - const deadline = t < 0 ? null : Date.now() + Math.max(0, t); - const kernelManagedStdio = - KERNEL_STDIO_SYNC_RPC || - (typeof process?.env?.AGENTOS_SANDBOX_ROOT === 'string' && - process.env.AGENTOS_SANDBOX_ROOT.length > 0); - try { - while (true) { - const view = new DataView(instanceMemory.buffer); - let ready = 0; - // fds the kernel owns (PTY/pipe stdio in sidecar-managed mode): their readiness - // comes from a batched __kernel_poll below, which doubles as the wait slice. - const kernelTargets = []; - const kernelEntries = []; - for (let i = 0; i < n; i++) { - const base = base0 + i * 8; - const fd = view.getInt32(base, true); - const events = view.getUint16(base + 4, true); - let revents = 0; - const socket = getHostNetSocket(fd); - const handle = fd >= 0 ? lookupFdHandle(fd >>> 0) : undefined; - if (socket && !socket.closed) { - if (socket.serverId) { - if (events & POLLIN) { - // Report the listener readable only when a connection is actually pending. - if (!socket.pendingAccepts) socket.pendingAccepts = []; - if (socket.pendingAccepts.length === 0) { - const accepted = tryHostNetAcceptOnce(socket); - if (accepted) socket.pendingAccepts.push(accepted); - } - if (socket.pendingAccepts.length > 0) revents |= POLLIN; - } - } else if (socket.socketId) { - if (events & POLLIN && socket.readChunks && socket.readChunks.length > 0) { - revents |= POLLIN; - } - if (events & POLLOUT) revents |= POLLOUT; - } - } else if (handle?.kind === 'pipe-read') { - if (events & POLLIN) { - pumpPipeProducers(handle.pipe, 0); - if (handle.pipe.chunks.length > 0) { - revents |= POLLIN; - } else if ( - handle.pipe.writeHandleCount === 0 && - handle.pipe.producers.size === 0 - ) { - revents |= POLLHUP; - } - } - } else if (handle?.kind === 'pipe-write') { - if (events & POLLOUT) revents |= POLLOUT; - } else if ( - fd >= 0 && - fd <= 2 && - kernelManagedStdio && - (!handle || (handle.kind === 'passthrough' && handle.targetFd === fd)) - ) { - // Kernel-managed stdio (PTY slave / stdio pipes): ask the kernel, like a - // native poll(2) on the terminal fd. - kernelTargets.push({ - fd, - events: - ((events & POLLIN) !== 0 ? KERNEL_POLLIN : 0) | - ((events & POLLOUT) !== 0 ? KERNEL_POLLOUT : 0), - }); - kernelEntries.push({ base, fd, events }); - } else if (handle) { - // Regular files / other VFS-backed fds: always ready, as on Linux. - revents |= events & (POLLIN | POLLOUT); - } else if (fd >= 0 && fd <= 2) { - // Non-kernel-managed stdio (plain runner stdio): report requested - // readiness rather than blocking a guest forever on fds we cannot wait on. - revents |= events & (POLLIN | POLLOUT); - } else if (fd >= 0) { - revents |= POLLNVAL; - } - view.setUint16(base + 6, revents, true); - if (revents) ready++; - } - - if (kernelTargets.length > 0) { - // If something is already ready (or this is a non-blocking poll), probe the - // kernel without waiting; otherwise let the kernel wait one slice for us. - const remaining = deadline == null ? Infinity : deadline - Date.now(); - const sliceMs = - ready > 0 || t === 0 - ? 0 - : Math.max(0, Math.min(KERNEL_WAIT_SLICE_MS, remaining)); - let response = null; - try { - response = callSyncRpc('__kernel_poll', [kernelTargets, sliceMs]); - } catch { - response = null; - } - const responseEntries = Array.isArray(response?.fds) ? response.fds : []; - for (const entry of kernelEntries) { - const responseEntry = responseEntries.find( - (item) => (Number(item?.fd) >>> 0) === (entry.fd >>> 0), - ); - const kernelRevents = Number(responseEntry?.revents) >>> 0; - let revents = 0; - if (kernelRevents & KERNEL_POLLIN) revents |= POLLIN & entry.events; - if (kernelRevents & KERNEL_POLLOUT) revents |= POLLOUT & entry.events; - if (kernelRevents & KERNEL_POLLERR) revents |= POLLERR; - if (kernelRevents & KERNEL_POLLHUP) revents |= POLLHUP; - new DataView(instanceMemory.buffer).setUint16(entry.base + 6, revents, true); - if (revents) ready++; - } - } - - if (ready > 0 || t === 0 || (deadline != null && Date.now() >= deadline)) { - new DataView(instanceMemory.buffer).setUint32(Number(retReadyPtr) >>> 0, ready >>> 0, true); - return 0; - } - let pumpedSocket = false; - const v2 = new DataView(instanceMemory.buffer); - for (let i = 0; i < n; i++) { - const fd = v2.getInt32(base0 + i * 8, true); - const s = getHostNetSocket(fd); - if (s && s.socketId && !s.serverId) { - pollHostNetSocket(s, 10); - pumpedSocket = true; - } - } - if (kernelTargets.length === 0 && !pumpedSocket) { - // Nothing to wait on except time: sleep a slice instead of hot-spinning. - const remaining = deadline == null ? Infinity : deadline - Date.now(); - Atomics.wait(syntheticWaitArray, 0, 0, Math.max(1, Math.min(10, remaining))); - } - } - } catch (_e) { - return WASI_ERRNO_FAULT; - } - }, - net_socket(domain, sockType, protocol, retFdPtr) { - try { - const numericDomain = Number(domain) >>> 0; - const numericType = Number(sockType) >>> 0; - const numericProtocol = Number(protocol) >>> 0; - - const fd = nextHostNetSocketFd++; - hostNetSockets.set(fd, { - domain: numericDomain, - sockType: numericType, - protocol: numericProtocol, - bindOptions: null, - localInfo: null, - localReservation: null, - remoteInfo: null, - serverId: null, - socketId: null, - udpSocketId: null, - recvTimeoutMs: null, - readChunks: [], - readableEnded: false, - closed: false, - lastError: null, - }); - return writeGuestUint32(retFdPtr, fd); - } catch { - return WASI_ERRNO_FAULT; - } - }, - // Mark a host_net socket non-blocking (O_NONBLOCK). The patched wasi-libc fcntl cannot reach - // host_net fds, so libxcb calls this directly. Non-blocking recv returns EAGAIN on no data. - net_set_nonblock(fd, enable) { - const socket = getHostNetSocket(fd); - if (!socket) return WASI_ERRNO_BADF; - socket.nonblock = (Number(enable) >>> 0) !== 0; - return WASI_ERRNO_SUCCESS; - }, - net_connect(fd, addrPtr, addrLen) { - const socket = getHostNetSocket(fd); - if (!socket) { - return WASI_ERRNO_BADF; - } - - try { - let rawAddr = String(readGuestString(addrPtr, addrLen) ?? ''); - // A sockaddr_un serialized from sizeof(struct sockaddr_un) carries trailing NUL - // padding; cut at the first NUL so the unix path is clean before classification. - const nulAt = rawAddr.indexOf(String.fromCharCode(0)); - if (nulAt >= 0) rawAddr = rawAddr.slice(0, nulAt); - rawAddr = rawAddr.trim(); - // AF_UNIX path connect (e.g. X11 /tmp/.X11-unix/X0): the C library passes the - // raw sun_path, the same '/'-prefixed string net_bind/net_listen receive. Route it - // to the sidecar's path-based net.connect, which dials the host-backed unix socket - // the listener bound under the VM sandbox root, so two guests in one VM can talk. - if (rawAddr.startsWith('/')) { - let result; - try { - result = callSyncRpc('net.connect', [{ path: rawAddr }]); - } catch (e) { - try { process.stderr.write('[host_net] connect ' + rawAddr + ' failed: ' + (e && e.message ? e.message : String(e)) + '\n'); } catch (_) {} - return WASI_ERRNO_FAULT; - } - if (!result || typeof result.socketId !== 'string') { - try { process.stderr.write('[host_net] ' + rawAddr + ' returned no socketId\n'); } catch (_) {} - return WASI_ERRNO_FAULT; - } - socket.socketId = result.socketId; - socket.localInfo = null; - socket.localReservation = null; - socket.remoteInfo = null; - socket.readChunks.length = 0; - socket.readableEnded = false; - socket.closed = false; - socket.lastError = null; - return WASI_ERRNO_SUCCESS; - } - const { host, port } = parseHostNetAddress(rawAddr); - if (!Number.isInteger(port) || port < 0 || port > 65535) { - return WASI_ERRNO_FAULT; - } - - const request = { host, port }; - if (socket.bindOptions?.host != null) { - request.localAddress = socket.bindOptions.host; - } - if (socket.bindOptions?.port != null) { - request.localPort = socket.bindOptions.port; - } - if (socket.localReservation != null) { - request.localReservation = socket.localReservation; - } - - const result = callSyncRpc('net.connect', [request]); - if (!result || typeof result.socketId !== 'string') { - return WASI_ERRNO_FAULT; - } - - socket.socketId = result.socketId; - socket.localInfo = normalizeHostNetAddressInfo(result.localAddress, result.localPort); - socket.localReservation = null; - socket.remoteInfo = normalizeHostNetAddressInfo(result.remoteAddress, result.remotePort); - socket.readChunks.length = 0; - socket.readableEnded = false; - socket.closed = false; - socket.lastError = null; - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_getaddrinfo(hostPtr, hostLen, portPtr, portLen, family, retAddrPtr, retAddrLenPtr) { - try { - const hostname = readGuestString(hostPtr, hostLen); - const numericFamily = Number(family) >>> 0; - const lookupOptions = { hostname, all: true }; - if (numericFamily === 4) { - lookupOptions.family = 4; - } else if (numericFamily === 6) { - lookupOptions.family = 6; - } else if (numericFamily !== 0) { - return WASI_ERRNO_INVAL; - } - - const records = callSyncRpc('dns.lookup', [lookupOptions]); - if (!Array.isArray(records)) { - return WASI_ERRNO_FAULT; - } - const payload = records.map((record) => { - const family = Number(record?.family); - if (family !== 4 && family !== 6) { - throw new Error('host_net dns record family is unsupported'); - } - return { - addr: String(record?.address ?? ''), - family, - }; - }); - const encoded = Buffer.from(JSON.stringify(payload), 'utf8'); - return writeGuestBytes( - retAddrPtr, - readGuestUint32(retAddrLenPtr), - encoded, - retAddrLenPtr, - ); - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_bind(fd, addrPtr, addrLen) { - const socket = getHostNetSocket(fd); - if (!socket || socket.closed) { - return WASI_ERRNO_BADF; - } - - try { - if (socket.localReservation != null) { - callSyncRpc('net.release_tcp_port', [socket.localReservation]); - socket.localReservation = null; - } - - socket.bindOptions = parseHostNetListenAddress(readGuestString(addrPtr, addrLen)); - if (hostNetSocketBaseType(socket) === HOST_NET_SOCK_DGRAM) { - if (socket.bindOptions.path != null) { - return WASI_ERRNO_FAULT; - } - const udpSocketId = ensureHostNetUdpSocket(socket); - if (!udpSocketId) { - return WASI_ERRNO_FAULT; - } - const result = callSyncRpc('dgram.bind', [ - udpSocketId, - { - address: socket.bindOptions.host, - port: socket.bindOptions.port, - }, - ]); - socket.localInfo = normalizeHostNetAddressInfo(result?.localAddress, result?.localPort); - return socket.localInfo ? WASI_ERRNO_SUCCESS : WASI_ERRNO_FAULT; - } - - if (socket.bindOptions.path == null) { - const reservation = callSyncRpc('net.reserve_tcp_port', [socket.bindOptions]); - if ( - !reservation || - typeof reservation.reservationId !== 'string' || - !Number.isInteger(Number(reservation.localPort)) - ) { - return WASI_ERRNO_FAULT; - } - socket.localReservation = reservation.reservationId; - socket.bindOptions = { - ...socket.bindOptions, - host: reservation.localAddress ?? socket.bindOptions.host, - port: Number(reservation.localPort), - }; - socket.localInfo = normalizeHostNetAddressInfo( - socket.bindOptions.host ?? '127.0.0.1', - socket.bindOptions.port, - ); - } else { - socket.localInfo = null; - } - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_listen(fd, backlog) { - const socket = getHostNetSocket(fd); - if (!socket || socket.closed) { - return WASI_ERRNO_BADF; - } - if (socket.serverId || !socket.bindOptions) { - return WASI_ERRNO_FAULT; - } - - try { - const request = { - ...socket.bindOptions, - backlog: Math.max(0, Number(backlog) >>> 0), - }; - if (socket.localReservation != null) { - request.localReservation = socket.localReservation; - } - - const result = callSyncRpc('net.listen', [request]); - if (!result || typeof result.serverId !== 'string') { - return WASI_ERRNO_FAULT; - } - socket.serverId = result.serverId; - socket.localReservation = null; - socket.localInfo = normalizeHostNetAddressInfo(result.localAddress, result.localPort); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_accept(fd, retFdPtr, retAddrPtr, retAddrLenPtr) { - const socket = getHostNetSocket(fd); - if (!socket?.serverId || socket.closed) { - return WASI_ERRNO_BADF; - } - - try { - // First drain a connection already buffered by net_poll's readiness probe; otherwise block - // until one arrives (POSIX blocking-accept semantics, for guests that accept() without polling - // first). This no longer starves connected clients: net_poll now reports the listener readable - // only when a connection is actually pending, so the X server only reaches accept() when there - // is one to take, and otherwise services connected client fds instead. - if (!socket.pendingAccepts) socket.pendingAccepts = []; - let accepted = socket.pendingAccepts.shift(); - while (!accepted) { - accepted = tryHostNetAcceptOnce(socket); - if (!accepted) { - pumpSpawnedChildren(10); - } - } - if (writeGuestUint32(retFdPtr, accepted.acceptedFd) !== WASI_ERRNO_SUCCESS) { - return WASI_ERRNO_FAULT; - } - return writeGuestBytes(retAddrPtr, readGuestUint32(retAddrLenPtr), accepted.address, retAddrLenPtr); - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_getsockname(fd, addrPtr, addrLenPtr) { - const socket = getHostNetSocket(fd); - if (!socket || socket.closed) { - return WASI_ERRNO_BADF; - } - if (!socket.localInfo) { - return WASI_ERRNO_INVAL; - } - - try { - const address = Buffer.from(formatHostNetAddressInfo(socket.localInfo), 'utf8'); - return writeGuestBytes(addrPtr, readGuestUint32(addrLenPtr), address, addrLenPtr); - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_getpeername(fd, addrPtr, addrLenPtr) { - const socket = getHostNetSocket(fd); - if (!socket || socket.closed) { - return WASI_ERRNO_BADF; - } - if (!socket.remoteInfo) { - return WASI_ERRNO_INVAL; - } - - try { - const address = Buffer.from(formatHostNetAddressInfo(socket.remoteInfo), 'utf8'); - return writeGuestBytes(addrPtr, readGuestUint32(addrLenPtr), address, addrLenPtr); - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_send(fd, bufPtr, bufLen, flags, retSentPtr) { - const socket = getHostNetSocket(fd); - if (!socket?.socketId || socket.closed) { - return WASI_ERRNO_BADF; - } - - try { - const chunk = readGuestBytes(bufPtr, bufLen); - if ((Number(flags) >>> 0) !== 0) { - // Non-zero send flags are currently ignored in the WASM host_net shim. - } - const written = Number(callSyncRpc('net.write', [socket.socketId, chunk])) >>> 0; - return writeGuestUint32(retSentPtr, written); - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_recv(fd, bufPtr, bufLen, flags, retReceivedPtr) { - const socket = getHostNetSocket(fd); - if (!socket) { - return WASI_ERRNO_BADF; - } - - try { - if ((Number(flags) >>> 0) !== 0) { - // Non-zero recv flags are currently ignored in the WASM host_net shim. - } - - // Non-blocking sockets (O_NONBLOCK via net_set_nonblock, used by libxcb's poll_for_*): - // pull whatever is queued, do ONE short readiness probe, and return EAGAIN if still empty - // instead of blocking. libxcb assumes its "poll" reads never block on an empty socket. - if (socket.nonblock) { - let queued = dequeueHostNetBytes(socket, bufLen); - if (queued.length > 0) { - return writeGuestBytes(bufPtr, bufLen, queued, retReceivedPtr); - } - if (socket.lastError) return WASI_ERRNO_FAULT; - if (socket.readableEnded || socket.closed || !socket.socketId) { - return writeGuestUint32(retReceivedPtr, 0); - } - pollHostNetSocket(socket, 0); - queued = dequeueHostNetBytes(socket, bufLen); - if (queued.length > 0) { - return writeGuestBytes(bufPtr, bufLen, queued, retReceivedPtr); - } - if (socket.readableEnded || socket.closed || !socket.socketId) { - return writeGuestUint32(retReceivedPtr, 0); - } - return WASI_ERRNO_AGAIN; - } - - const deadline = - socket.recvTimeoutMs == null ? null : Date.now() + Math.max(0, socket.recvTimeoutMs); - while (true) { - const queued = dequeueHostNetBytes(socket, bufLen); - if (queued.length > 0) { - return writeGuestBytes(bufPtr, bufLen, queued, retReceivedPtr); - } - - if (socket.lastError) { - return WASI_ERRNO_FAULT; - } - - if (socket.readableEnded || socket.closed || !socket.socketId) { - return writeGuestUint32(retReceivedPtr, 0); - } - - const pollWaitMs = - deadline == null ? 50 : Math.max(0, Math.min(50, deadline - Date.now())); - if (deadline != null && pollWaitMs === 0) { - return WASI_ERRNO_AGAIN; - } - pollHostNetSocket(socket, pollWaitMs); - if (deadline != null && Date.now() >= deadline) { - return WASI_ERRNO_AGAIN; - } - } - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_sendto(fd, bufPtr, bufLen, flags, addrPtr, addrLen, retSentPtr) { - const socket = getHostNetSocket(fd); - if (!socket || socket.closed) { - return WASI_ERRNO_BADF; - } - - try { - if ((Number(flags) >>> 0) !== 0) { - return WASI_ERRNO_INVAL; - } - const udpSocketId = ensureHostNetUdpSocket(socket); - if (!udpSocketId) { - return WASI_ERRNO_FAULT; - } - - const { host, port } = parseHostNetAddress(readGuestString(addrPtr, addrLen)); - const chunk = readGuestBytes(bufPtr, bufLen); - const result = callSyncRpc('dgram.send', [ - udpSocketId, - chunk, - { address: host, port }, - ]); - socket.localInfo = normalizeHostNetAddressInfo(result?.localAddress, result?.localPort); - const written = Number(result?.bytes) >>> 0; - return writeGuestUint32(retSentPtr, written); - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_recvfrom(fd, bufPtr, bufLen, flags, retReceivedPtr, retAddrPtr, retAddrLenPtr) { - const socket = getHostNetSocket(fd); - if (!socket || socket.closed) { - return WASI_ERRNO_BADF; - } - - try { - if ((Number(flags) >>> 0) !== 0) { - return WASI_ERRNO_INVAL; - } - const udpSocketId = ensureHostNetUdpSocket(socket); - if (!udpSocketId) { - return WASI_ERRNO_FAULT; - } - - const deadline = - socket.recvTimeoutMs == null ? null : Date.now() + Math.max(0, socket.recvTimeoutMs); - while (true) { - const pollWaitMs = - deadline == null ? 50 : Math.max(0, Math.min(50, deadline - Date.now())); - if (deadline != null && pollWaitMs === 0) { - return WASI_ERRNO_AGAIN; - } - const event = callSyncRpc('dgram.poll', [udpSocketId, pollWaitMs]); - if (!event) { - if (deadline != null && Date.now() >= deadline) { - return WASI_ERRNO_AGAIN; - } - continue; - } - if (event.type === 'error') { - return WASI_ERRNO_FAULT; - } - if (event.type !== 'message') { - continue; - } - - let bytes; - if (event.data && typeof event.data === 'object' && typeof event.data.base64 === 'string') { - bytes = Buffer.from(event.data.base64, 'base64'); - } else { - try { - bytes = decodeFsBytesPayload(event.data, 'host_net recvfrom data'); - } catch { - return WASI_ERRNO_FAULT; - } - } - const dataResult = writeGuestBytes(bufPtr, bufLen, bytes, retReceivedPtr); - if (dataResult !== WASI_ERRNO_SUCCESS) { - return dataResult; - } - if (!event.remoteAddress || !Number.isInteger(Number(event.remotePort))) { - return WASI_ERRNO_BADF; - } - let address; - try { - address = Buffer.from(formatHostNetAddressInfo({ - address: event.remoteAddress, - port: event.remotePort, - }), 'utf8'); - } catch { - return WASI_ERRNO_INVAL; - } - let addressCapacity; - try { - addressCapacity = readGuestUint32(retAddrLenPtr); - } catch { - return WASI_ERRNO_FAULT; - } - const addressResult = writeGuestBytes(retAddrPtr, addressCapacity, address, retAddrLenPtr); - return addressResult; - } - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_setsockopt(fd, level, optname, optvalPtr, optvalLen) { - const socket = getHostNetSocket(fd); - if (!socket || socket.closed) { - return WASI_ERRNO_BADF; - } - const sockoptKind = hostNetSockoptKind(level, optname, optvalLen); - if (sockoptKind == null) { - return WASI_ERRNO_INVAL; - } - try { - const timeoutMs = parseHostNetTimevalMs(readGuestBytes(optvalPtr, optvalLen)); - if (timeoutMs == null && readGuestBytes(optvalPtr, optvalLen).some((byte) => byte !== 0)) { - return WASI_ERRNO_INVAL; - } - if (sockoptKind === 'recv-timeout') { - socket.recvTimeoutMs = timeoutMs; - } - } catch { - return WASI_ERRNO_FAULT; - } - return WASI_ERRNO_SUCCESS; - }, - net_close(fd) { - const numericFd = Number(fd) >>> 0; - const socket = hostNetSockets.get(numericFd); - if (!socket) { - return WASI_ERRNO_BADF; - } - - hostNetSockets.delete(numericFd); - try { - if (socket.localReservation != null) { - callSyncRpc('net.release_tcp_port', [socket.localReservation]); - } - if (socket.socketId && !socket.closed) { - callSyncRpc('net.destroy', [socket.socketId]); - } - if (socket.udpSocketId) { - callSyncRpc('dgram.close', [socket.udpSocketId]); - } - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } - }, - net_tls_connect(fd, hostnamePtr, hostnameLen) { - const socket = getHostNetSocket(fd); - if (!socket?.socketId || socket.closed) { - return WASI_ERRNO_BADF; - } - - try { - const servername = readGuestString(hostnamePtr, hostnameLen); - const tlsOptions = { servername }; - if (guestEnv.NODE_TLS_REJECT_UNAUTHORIZED === '0') { - tlsOptions.rejectUnauthorized = false; - } - callSyncRpc('net.socket_upgrade_tls', [ - socket.socketId, - JSON.stringify(tlsOptions), - ]); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } - }, -}; - -const hostProcessImport = { - proc_spawn( - argvPtr, - argvLen, - envpPtr, - envpLen, - stdinFd, - stdoutFd, - stderrFd, - cwdPtr, - cwdLen, - retPidPtr, - ) { - if (permissionTier !== 'full') { - return WASI_ERRNO_FAULT; - } - try { - const argv = decodeNullSeparatedStrings(readGuestBytes(argvPtr, argvLen)); - if (argv.length === 0) { - return WASI_ERRNO_FAULT; - } - - const [command, ...args] = argv; - const env = parseSerializedEnv(readGuestBytes(envpPtr, envpLen)); - const cwd = - Number(cwdLen) > 0 ? readGuestString(cwdPtr, cwdLen) : undefined; - const stdinTarget = resolveSpawnFd(stdinFd); - const stdoutTarget = resolveSpawnFd(stdoutFd); - const stderrTarget = resolveSpawnFd(stderrFd); - const syntheticResult = maybeCreateSyntheticCommandResult(command, args, cwd); - if (syntheticResult) { - const record = createSyntheticChildRecord( - syntheticResult, - stdinTarget, - stdoutTarget, - stderrTarget, - ); - spawnedChildren.set(record.pid, record); - spawnedChildrenById.set(record.childId, record); - traceHostProcess('proc-spawn-synthetic', { - command, - childId: record.childId, - pid: record.pid, - exitCode: syntheticResult.exitCode, - }); - emitSyntheticCommandOutput(record, stdoutFd, stderrFd, syntheticResult); - return writeGuestUint32(retPidPtr, record.pid); - } - traceHostProcess('proc-spawn-begin', { - command, - args, - cwd: cwd ?? null, - stdinFd: Number(stdinFd) >>> 0, - stdoutFd: Number(stdoutFd) >>> 0, - stderrFd: Number(stderrFd) >>> 0, - stdinTarget, - stdoutTarget, - stderrTarget, - }); - let stdinRedirectBytes = null; - if ( - stdinTarget > 2 && - stdinTarget !== 0xffffffff && - !spawnStdinFdIsSyntheticPipe(stdinTarget) - ) { - stdinRedirectBytes = readSpawnStdinRedirectBytes(stdinTarget); - if (stdinRedirectBytes == null) { - traceHostProcess('proc-spawn-stdin-redirect-unreadable', { - command, - stdinFd: stdinTarget, - }); - return WASI_ERRNO_FAULT; - } - } - const result = callSyncRpc('child_process.spawn', [ - { - command, - args, - options: { - cwd, - env, - internalBootstrapEnv: {}, - shell: false, - stdio: [ - stdinTarget === 0 - ? 'inherit' - : stdinTarget === 0xffffffff - ? 'ignore' - : 'pipe', - stdoutTarget === 1 - ? 'inherit' - : stdoutTarget === 0xffffffff - ? 'ignore' - : 'pipe', - stderrTarget === 2 - ? 'inherit' - : stderrTarget === 0xffffffff - ? 'ignore' - : 'pipe', - ], - }, - }, - ]); - const pid = Number(result?.pid) >>> 0; - if (!Number.isInteger(pid) || pid === 0 || typeof result?.childId !== 'string') { - return WASI_ERRNO_FAULT; - } - - const stdinPipe = registerPipeConsumer(stdinTarget, result.childId, 'stdin'); - const stdoutPipe = registerPipeProducer(stdoutTarget, result.childId, 'stdout'); - const stderrPipe = registerPipeProducer(stderrTarget, result.childId, 'stderr'); - const retainedSpawnOutputHandles = [stdoutTarget, stderrTarget] - .filter((fd, index, values) => values.indexOf(fd) === index) - .map((fd) => retainSpawnOutputHandle(fd)) - .filter(Boolean); - const delegateRetainedFds = [stdinTarget, stdoutTarget, stderrTarget].filter( - (fd, index, values) => - fd > 2 && - delegateManagedFdRefCounts.has(fd) && - values.indexOf(fd) === index, - ); - for (const fd of delegateRetainedFds) { - retainDelegateFd(fd); - } - const record = { - childId: result.childId, - pid, - stdinFd: stdinTarget, - stdoutFd: stdoutTarget, - stderrFd: stderrTarget, - stdinPipe, - stdoutPipe, - stderrPipe, - stdinReadyAtMs: Date.now() + 100, - delegateRetainedFds, - retainedSpawnOutputHandles, - exitStatus: null, - }; - spawnedChildren.set(pid, record); - spawnedChildrenById.set(result.childId, record); - traceHostProcess('proc-spawn-ready', { - command, - childId: result.childId, - pid, - }); - if (stdinRedirectBytes != null) { - if (stdinRedirectBytes.length > 0) { - callSyncRpc('child_process.write_stdin', [ - result.childId, - stdinRedirectBytes, - ]); - } - callSyncRpc('child_process.close_stdin', [result.childId]); - } - consumeSpawnOutputFd(stdoutFd); - consumeSpawnOutputFd(stderrFd); - return writeGuestUint32(retPidPtr, pid); - } catch (error) { - traceHostProcess('proc-spawn-fault', { - message: error instanceof Error ? error.message : String(error), - }); - return WASI_ERRNO_FAULT; - } - }, - proc_waitpid(pid, options, retStatusPtr, retPidPtr) { - const requestedPid = Number(pid) >>> 0; - if (permissionTier !== 'full') { - return requestedPid === 0xffffffff ? WASI_ERRNO_CHILD : WASI_ERRNO_SRCH; - } - const record = - requestedPid === 0xffffffff - ? spawnedChildren.values().next().value - : spawnedChildren.get(requestedPid); - if (!record) { - return requestedPid === 0xffffffff ? WASI_ERRNO_CHILD : WASI_ERRNO_SRCH; - } - - try { - const nonBlocking = (Number(options) >>> 0) !== 0; - traceHostProcess('proc-waitpid-begin', { - requestedPid, - childId: record.childId, - pid: record.pid, - }); - if (typeof record.exitStatus === 'number') { - if (writeGuestUint32(retStatusPtr, record.exitStatus) !== WASI_ERRNO_SUCCESS) { - return WASI_ERRNO_FAULT; - } - const writePidResult = writeGuestUint32(retPidPtr, record.pid); - if (writePidResult !== WASI_ERRNO_SUCCESS) { - return writePidResult; - } - reapSpawnedChild(record); - return writePidResult; - } - - while (true) { - const event = pollChildEvent( - record, - nonBlocking ? 0 : 10, - ); - if (!event) { - if (!pumpChildInputPipe(record, nonBlocking ? 0 : 10)) { - if (nonBlocking) { - return writeGuestUint32(retPidPtr, 0); - } - } - continue; - } - traceHostProcess('proc-waitpid-poll', { - requestedPid, - childId: record.childId, - type: event.type, - }); - - if (event.type === 'stdout' && record.stdoutFd !== 0xffffffff) { - const chunk = decodeSyncRpcValue(event.data); - if (chunk?.length > 0) { - routeChunkToFd(record.stdoutFd, chunk); - } - continue; - } - - if (event.type === 'stderr' && record.stderrFd !== 0xffffffff) { - const chunk = decodeSyncRpcValue(event.data); - if (chunk?.length > 0) { - routeChunkToFd(record.stderrFd, chunk); - } - continue; - } - - if (event.type === 'signal') { - processChildEvent(record, event); - continue; - } - - if (event.type === 'exit') { - processChildEvent(record, event); - if (writeGuestUint32(retStatusPtr, record.exitStatus ?? 1) !== WASI_ERRNO_SUCCESS) { - return WASI_ERRNO_FAULT; - } - const writePidResult = writeGuestUint32(retPidPtr, record.pid); - if (writePidResult !== WASI_ERRNO_SUCCESS) { - return writePidResult; - } - reapSpawnedChild(record); - return writePidResult; - } - } - } catch { - traceHostProcess('proc-waitpid-fault', { - requestedPid, - childId: record.childId, - pid: record.pid, - }); - return WASI_ERRNO_FAULT; - } - }, - proc_kill(pid, signal) { - if (permissionTier !== 'full') { - return WASI_ERRNO_SRCH; - } - const targetPid = Number(pid) >>> 0; - const signalName = signalNameFromNumber(signal); - - try { - if (targetPid === VIRTUAL_PID) { - callSyncRpc('process.kill', [VIRTUAL_PID, signalName]); - if ( - Number(signal) > 0 && - typeof instance?.exports?.__wasi_signal_trampoline === 'function' - ) { - instance.exports.__wasi_signal_trampoline(Number(signal) | 0); - } - return WASI_ERRNO_SUCCESS; - } - - const record = spawnedChildren.get(targetPid); - if (record) { - callSyncRpc('child_process.kill', [record.childId, signalName]); - return WASI_ERRNO_SUCCESS; - } - - callSyncRpc('process.kill', [targetPid, signalName]); - return WASI_ERRNO_SUCCESS; - } catch (error) { - if (error?.code === 'ESRCH') { - return WASI_ERRNO_SRCH; - } - return WASI_ERRNO_FAULT; - } - }, - proc_getpid(retPidPtr) { - return writeGuestUint32(retPidPtr, VIRTUAL_PID); - }, - proc_getppid(retPidPtr) { - return writeGuestUint32(retPidPtr, VIRTUAL_PPID); - }, - fd_pipe(retReadFdPtr, retWriteFdPtr) { - try { - const pipe = { - id: nextSyntheticPipeId++, - chunks: [], - consumers: new Map(), - producers: new Map(), - readHandleCount: 0, - writeHandleCount: 0, - }; - const readFd = nextSyntheticFd++; - const writeFd = nextSyntheticFd++; - syntheticFdEntries.set(readFd, createPipeHandle('pipe-read', pipe, readFd)); - syntheticFdEntries.set(writeFd, createPipeHandle('pipe-write', pipe, writeFd)); - if (writeGuestUint32(retReadFdPtr, readFd) !== WASI_ERRNO_SUCCESS) { - return WASI_ERRNO_FAULT; - } - return writeGuestUint32(retWriteFdPtr, writeFd); - } catch { - return WASI_ERRNO_FAULT; - } - }, - fd_dup(fd, retNewFdPtr) { - try { - const handle = cloneFdHandle(fd); - if (!handle) { - return WASI_ERRNO_BADF; - } - let duplicatedFd = 0; - while ( - duplicatedFd <= 2 && - ( - syntheticFdEntries.has(duplicatedFd) || - passthroughHandles.has(duplicatedFd) || - delegateManagedFdRefCounts.has(duplicatedFd) - ) - ) { - duplicatedFd += 1; - } - if (duplicatedFd > 2) { - duplicatedFd = nextSyntheticFd++; - } - syntheticFdEntries.set(duplicatedFd, handle); - traceHostProcess('fd-dup', { - fd: Number(fd) >>> 0, - duplicatedFd, - handleKind: handle.kind, - targetFd: handle.targetFd ?? null, - displayFd: handle.displayFd ?? null, - }); - return writeGuestUint32(retNewFdPtr, duplicatedFd); - } catch { - return WASI_ERRNO_FAULT; - } - }, - fd_dup2(oldFd, newFd) { - try { - const sourceFd = Number(oldFd) >>> 0; - const targetFd = Number(newFd) >>> 0; - if (sourceFd === targetFd) { - if (!lookupFdHandle(sourceFd)) { - return WASI_ERRNO_BADF; - } - traceHostProcess('fd-dup2-same-fd', { - oldFd: sourceFd, - newFd: targetFd, - }); - return WASI_ERRNO_SUCCESS; - } - - const sourceHandle = cloneFdHandle(sourceFd); - if (!sourceHandle) { - return WASI_ERRNO_BADF; - } - - traceHostProcess('fd-dup2-begin', { - oldFd: sourceFd, - newFd: targetFd, - sourceKind: sourceHandle.kind, - sourceTargetFd: sourceHandle.targetFd ?? null, - sourceDisplayFd: sourceHandle.displayFd ?? null, - existingKind: syntheticFdEntries.get(targetFd)?.kind ?? passthroughHandles.get(targetFd)?.kind ?? null, - }); - - closeSyntheticFd(targetFd); - closePassthroughFd(targetFd); - syntheticFdEntries.set(targetFd, sourceHandle); - traceHostProcess('fd-dup2-installed', { - oldFd: sourceFd, - newFd: targetFd, - sourceKind: sourceHandle.kind, - }); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } - }, - fd_dup_min(fd, minFd, retNewFdPtr) { - try { - const sourceFd = Number(fd); - const minimumFdNumber = Number(minFd); - if (!Number.isInteger(sourceFd) || sourceFd < 0) { - return WASI_ERRNO_BADF; - } - if (!Number.isInteger(minimumFdNumber) || minimumFdNumber < 0) { - return WASI_ERRNO_INVAL; - } - - const handle = cloneFdHandle(sourceFd); - if (!handle) { - return WASI_ERRNO_BADF; - } - - let duplicatedFd = minimumFdNumber >>> 0; - while ( - syntheticFdEntries.has(duplicatedFd) || - passthroughHandles.has(duplicatedFd) || - delegateManagedFdRefCounts.has(duplicatedFd) - ) { - duplicatedFd += 1; - } - nextSyntheticFd = Math.max(nextSyntheticFd, duplicatedFd + 1); - - syntheticFdEntries.set(duplicatedFd, handle); - traceHostProcess('fd-dup-min', { - fd: sourceFd >>> 0, - minimumFd: minimumFdNumber >>> 0, - duplicatedFd, - handleKind: handle.kind, - targetFd: handle.targetFd ?? null, - displayFd: handle.displayFd ?? null, - }); - return writeGuestUint32(retNewFdPtr, duplicatedFd); - } catch { - return WASI_ERRNO_FAULT; - } - }, - sleep_ms(milliseconds) { - try { - Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, Number(milliseconds) >>> 0); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } - }, - pty_open(retMasterFdPtr, retSlaveFdPtr) { - return WASI_ERRNO_FAULT; - }, - proc_sigaction(signal, action, maskLo, maskHi, flags) { - if (permissionTier !== 'full') { - return WASI_ERRNO_FAULT; - } - try { - const registration = { - action: action === 0 ? 'default' : action === 1 ? 'ignore' : 'user', - mask: decodeSignalMask(maskLo, maskHi), - flags: Number(flags) >>> 0, - }; - emitControlMessage({ - type: 'signal_state', - signal: Number(signal) >>> 0, - registration, - }); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } - }, -}; - -const limitedHostProcessImport = { - fd_dup_min: hostProcessImport.fd_dup_min, -}; - -const hostUserImport = { - getuid(retUidPtr) { - return writeGuestUint32(retUidPtr, VIRTUAL_UID); - }, - getgid(retGidPtr) { - return writeGuestUint32(retGidPtr, VIRTUAL_GID); - }, - geteuid(retUidPtr) { - return writeGuestUint32(retUidPtr, VIRTUAL_UID); - }, - getegid(retGidPtr) { - return writeGuestUint32(retGidPtr, VIRTUAL_GID); - }, - isatty(fd, retBoolPtr) { - const descriptor = Number(fd) >>> 0; - const isTerminal = descriptor <= 2 && stdioFdIsKernelTty(descriptor) ? 1 : 0; - return writeGuestUint32(retBoolPtr, isTerminal); - }, - getpwuid(uid, bufPtr, bufLen, retLenPtr) { - const numericUid = Number(uid) >>> 0; - const passwdEntry = - numericUid === VIRTUAL_UID - ? `${VIRTUAL_OS_USER}:x:${VIRTUAL_UID}:${VIRTUAL_GID}::${VIRTUAL_OS_HOMEDIR}:${VIRTUAL_OS_SHELL}` - : `user${numericUid}:x:${numericUid}:${numericUid}::/home/user${numericUid}:/bin/sh`; - return writeGuestBytes(bufPtr, bufLen, encodeGuestBytes(passwdEntry), retLenPtr); - }, -}; - -const HOST_FS_MODE_REGULAR = 0o100644; -const HOST_FS_MODE_CHARACTER = 0o020666; -const HOST_FS_MODE_FIFO = 0o010600; -const HOST_FS_GUEST_CWD = - typeof guestEnv?.PWD === 'string' && guestEnv.PWD.startsWith('/') - ? path.posix.normalize(guestEnv.PWD) - : '/'; - -for (let index = 0; index < WASI_PREOPEN_ENTRIES.length; index += 1) { - const fd = WASI_PREOPEN_FD_BASE + index; - const [guestPath, preopenSpec] = WASI_PREOPEN_ENTRIES[index]; - if (!passthroughHandles.has(fd)) { - retainDelegateFd(fd); - closedPassthroughFds.delete(fd); - passthroughHandles.set(fd, { - kind: 'passthrough', - targetFd: fd, - displayFd: fd, - refCount: 0, - open: true, - guestPath: guestPathForPreopenKey(guestPath), - readOnly: preopenSpec?.readOnly === true, - }); - } -} - -function hostFsModeFromStat(stat) { - const mode = Number(stat?.mode); - return Number.isInteger(mode) && mode > 0 ? mode >>> 0 : 0; -} - -const hostFsSizeByGuestPath = new Map(); -// Bound the per-path size cache so a guest truncating many distinct paths cannot -// grow it without limit. Entries are insertion-ordered, so evicting the oldest -// key is a cheap LRU-ish bound. -const HOST_FS_SIZE_CACHE_MAX_ENTRIES = 4096; -let hostFsSizeCacheEvictionWarned = false; - -function forgetHostFsSize(guestPath) { - if (typeof guestPath !== 'string') { - return; - } - hostFsSizeByGuestPath.delete(path.posix.normalize(guestPath)); -} - -function rememberHostFsSize(guestPath, size) { - if (typeof guestPath !== 'string') { - return; - } - const normalized = path.posix.normalize(guestPath); - if (!Number.isFinite(size) || size < 0) { - hostFsSizeByGuestPath.delete(normalized); - return; - } - if ( - !hostFsSizeByGuestPath.has(normalized) && - hostFsSizeByGuestPath.size >= HOST_FS_SIZE_CACHE_MAX_ENTRIES - ) { - const oldest = hostFsSizeByGuestPath.keys().next().value; - if (oldest !== undefined) { - hostFsSizeByGuestPath.delete(oldest); - } - if (!hostFsSizeCacheEvictionWarned) { - hostFsSizeCacheEvictionWarned = true; - traceHostProcess('host-fs-size-cache-evict', { - max: HOST_FS_SIZE_CACHE_MAX_ENTRIES, - }); - } - } - hostFsSizeByGuestPath.set(normalized, BigInt(Math.trunc(size))); -} - -function rememberedHostFsSize(guestPath) { - if (typeof guestPath !== 'string') { - return null; - } - return hostFsSizeByGuestPath.get(path.posix.normalize(guestPath)) ?? null; -} - -function resolveHostFsPath(value, fromGuestDir = HOST_FS_GUEST_CWD) { - return resolveHostFsMapping(value, fromGuestDir)?.hostPath ?? null; -} - -function resolveHostFsMapping(value, fromGuestDir = HOST_FS_GUEST_CWD) { - const guestPath = resolveSyntheticGuestPath(value, fromGuestDir); - if (typeof guestPath !== 'string') { - return null; - } - return resolveModuleGuestPathToHostMapping(guestPath); -} - -const hostFsImport = { - fd_mode(fd) { - const descriptor = Number(fd) >>> 0; - if (descriptor <= 2) { - return HOST_FS_MODE_CHARACTER; - } - - const handle = lookupFdHandle(descriptor); - if (handle?.kind === 'pipe-read' || handle?.kind === 'pipe-write') { - return HOST_FS_MODE_FIFO; - } - - try { - const targetFd = - typeof handle?.ioFd === 'number' - ? Number(handle.ioFd) >>> 0 - : typeof handle?.targetFd === 'number' - ? Number(handle.targetFd) >>> 0 - : descriptor; - return hostFsModeFromStat(fsModule.fstatSync(targetFd)) || HOST_FS_MODE_REGULAR; - } catch { - return HOST_FS_MODE_REGULAR; - } - }, - fd_size(fd) { - const descriptor = Number(fd) >>> 0; - try { - const handle = lookupFdHandle(descriptor); - const rememberedSize = rememberedHostFsSize(handle?.guestPath); - if (rememberedSize != null) { - return rememberedSize; - } - if (typeof handle?.ioFd === 'number') { - return BigInt(fsModule.fstatSync(Number(handle.ioFd) >>> 0).size ?? -1); - } - if (typeof handle?.guestPath === 'string') { - const hostPath = resolveHostFsPath(handle.guestPath); - if (typeof hostPath === 'string') { - return BigInt(fsModule.statSync(hostPath).size ?? -1); - } - return BigInt(fsModule.statSync(handle.guestPath).size ?? -1); - } - const targetFd = typeof handle?.targetFd === 'number' - ? Number(handle.targetFd) >>> 0 - : descriptor; - return BigInt(fsModule.fstatSync(targetFd).size ?? -1); - } catch { - return (1n << 64n) - 1n; - } - }, - path_mode(fd, pathPtr, pathLen, followSymlinks) { - try { - const target = resolvePathOpenGuestPath(fd, pathPtr, pathLen); - if (typeof target !== 'string') { - return 0; - } - const hostPath = resolveHostFsPath(target); - if (typeof hostPath !== 'string') { - return 0; - } - const stat = - Number(followSymlinks) === 0 - ? fsModule.lstatSync(hostPath) - : fsModule.statSync(hostPath); - const mode = hostFsModeFromStat(stat); - traceHostProcess('host-fs-path-mode', { - target, - hostPath, - followSymlinks: Number(followSymlinks) >>> 0, - mode, - }); - return mode; - } catch { - traceHostProcess('host-fs-path-mode-fault', {}); - return 0; - } - }, - path_size(fd, pathPtr, pathLen, followSymlinks) { - const target = resolvePathOpenGuestPath(fd, pathPtr, pathLen); - if (typeof target !== 'string') { - return (1n << 64n) - 1n; - } - const rememberedSize = rememberedHostFsSize(target); - if (rememberedSize != null) { - return rememberedSize; - } - - try { - const hostPath = resolveHostFsPath(target); - if (typeof hostPath === 'string') { - const stat = - Number(followSymlinks) === 0 - ? fsModule.lstatSync(hostPath) - : fsModule.statSync(hostPath); - return BigInt(stat?.size ?? -1); - } - const guestStat = - Number(followSymlinks) === 0 - ? fsModule.lstatSync(target) - : fsModule.statSync(target); - return BigInt(guestStat?.size ?? -1); - } catch { - return (1n << 64n) - 1n; - } - }, - chmod(fd, pathPtr, pathLen, mode) { - try { - const target = resolvePathOpenGuestPath(fd, pathPtr, pathLen); - if (typeof target !== 'string') { - return 1; - } - const mapping = resolveHostFsMapping(target); - if (!mapping || typeof mapping.hostPath !== 'string') { - return 1; - } - if (mapping.readOnly) { - return 1; - } - traceHostProcess('host-fs-chmod', { - target, - hostPath: mapping.hostPath, - mode: Number(mode) >>> 0, - }); - chmodMappedGuestPath(target, mapping.hostPath, Number(mode) >>> 0); - return 0; - } catch { - traceHostProcess('host-fs-chmod-fault', {}); - return 1; - } - }, - fchmod(fd, mode) { - try { - const descriptor = Number(fd) >>> 0; - const handle = lookupFdHandle(descriptor); - if (handle?.readOnly === true) { - return 1; - } - if (typeof handle?.guestPath === 'string') { - const mapping = resolveHostFsMapping(handle.guestPath); - if (!mapping || typeof mapping.hostPath !== 'string' || mapping.readOnly) { - return 1; - } - chmodMappedGuestPath(handle.guestPath, mapping.hostPath, Number(mode) >>> 0); - return 0; - } - const targetFd = - typeof handle?.targetFd === 'number' ? Number(handle.targetFd) >>> 0 : descriptor; - fsModule.fchmodSync(targetFd, Number(mode) >>> 0); - return 0; - } catch { - traceHostProcess('host-fs-fchmod-fault', {}); - return 1; - } - }, - ftruncate(fd, length) { - try { - const descriptor = Number(fd) >>> 0; - const nextSize = Number(length); - if (!Number.isFinite(nextSize) || nextSize < 0) { - return 1; - } - const handle = lookupFdHandle(descriptor); - if (handle?.readOnly === true) { - return 1; - } - if (typeof handle?.ioFd === 'number') { - fsModule.ftruncateSync(handle.ioFd, nextSize); - if ((handle.position ?? 0) > nextSize) { - handle.position = nextSize; - } - rememberHostFsSize(handle.guestPath, nextSize); - return 0; - } - if (typeof handle?.guestPath === 'string') { - const pathFd = fsModule.openSync(handle.guestPath, 0o1, 0o666); - try { - fsModule.ftruncateSync(pathFd, nextSize); - if ((handle.position ?? 0) > nextSize) { - handle.position = nextSize; - } - rememberHostFsSize(handle.guestPath, nextSize); - } finally { - fsModule.closeSync(pathFd); - } - return 0; - } - return 1; - } catch { - return 1; - } - }, -}; - -wasiImport.clock_time_get = (clockId, precision, resultPtr) => { - const numericClockId = Number(clockId) >>> 0; - if (numericClockId !== 0 && delegateClockTimeGet) { - return delegateClockTimeGet(clockId, precision, resultPtr); - } - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return delegateClockTimeGet - ? delegateClockTimeGet(clockId, precision, resultPtr) - : WASI_ERRNO_FAULT; - } - - try { - const view = new DataView(instanceMemory.buffer); - view.setBigUint64(Number(resultPtr), frozenTimeNs, true); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } -}; - -wasiImport.clock_res_get = (clockId, resultPtr) => { - const numericClockId = Number(clockId) >>> 0; - if (numericClockId !== 0 && delegateClockResGet) { - return delegateClockResGet(clockId, resultPtr); - } - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return delegateClockResGet - ? delegateClockResGet(clockId, resultPtr) - : WASI_ERRNO_FAULT; - } - - try { - const view = new DataView(instanceMemory.buffer); - view.setBigUint64(Number(resultPtr), 1000000n, true); - return WASI_ERRNO_SUCCESS; - } catch { - return WASI_ERRNO_FAULT; - } -}; - -if (delegatePathOpen) { - wasiImport.path_open = ( - fd, - dirflags, - pathPtr, - pathLen, - oflags, - rightsBase, - rightsInheriting, - fdflags, - openedFdPtr, - ) => { - const workspaceReadOnlyDenied = __agentOSWasiMeasurePhase('path_open', 'readonly_policy', () => - isWorkspaceReadOnly() && - (hasMutationOpenFlags(oflags) || hasWriteRights(rightsBase)) - ); - if (workspaceReadOnlyDenied) { - return denyReadOnlyMutation(); - } - - const passthroughDirHandle = __agentOSWasiMeasurePhase('path_open', 'lookup_handle', () => - lookupFdHandle(fd) - ); - if (passthroughDirHandle && passthroughDirHandle.kind !== 'passthrough') { - return WASI_ERRNO_BADF; - } - if (!passthroughDirHandle && rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - const delegateDirFd = - passthroughDirHandle?.kind === 'passthrough' - ? passthroughDirHandle.targetFd - : fd; - const guestPath = __agentOSWasiMeasurePhase('path_open', 'path_resolution', () => - resolvePathOpenGuestPath(fd, pathPtr, pathLen) - ); - const guestReadOnlyDenied = __agentOSWasiMeasurePhase('path_open', 'readonly_policy', () => - guestPathIsReadOnly(guestPath) && - (hasMutationOpenFlags(oflags) || hasWriteRights(rightsBase)) - ); - if (guestReadOnlyDenied) { - return denyReadOnlyMutation(); - } - const mayCreateTarget = pathOpenMayCreateTarget(oflags, rightsBase, fdflags); - if (!SIDECAR_MANAGED_PROCESS && mayCreateTarget) { - try { - const syntheticResult = __agentOSWasiMeasurePhase( - 'path_open', - 'synthetic_open', - () => openGuestFileForPathOpen( - fd, - pathPtr, - pathLen, - oflags, - rightsBase, - fdflags, - openedFdPtr, - ), - ); - if (syntheticResult != null) { - return syntheticResult; - } - } catch { - return WASI_ERRNO_FAULT; - } - } - - let result = __agentOSWasiMeasurePhase( - 'path_open', - 'delegate_call', - () => delegatePathOpen( - delegateDirFd, - dirflags, - pathPtr, - pathLen, - oflags, - rightsBase, - rightsInheriting, - fdflags, - openedFdPtr, - ), - ); - - // Precreate-and-retry exists for creatable targets the delegate reports - // as missing (e.g. `>>` append redirect targets). Only retry on NOENT: - // retrying on permission errors would mask the real errno and attempt to - // create a file the kernel just denied. - if ( - result === WASI_ERRNO_NOENT && - mayCreateTarget - ) { - try { - __agentOSWasiMeasurePhase('path_open', 'synthetic_precreate', () => - precreatePathOpenTarget(fd, pathPtr, pathLen, oflags, rightsBase, fdflags) - ); - result = __agentOSWasiMeasurePhase( - 'path_open', - 'delegate_call', - () => delegatePathOpen( - delegateDirFd, - dirflags, - pathPtr, - pathLen, - oflags, - rightsBase, - rightsInheriting, - fdflags, - openedFdPtr, - ), - ); - if (!SIDECAR_MANAGED_PROCESS && result !== WASI_ERRNO_SUCCESS) { - const fallbackResult = __agentOSWasiMeasurePhase( - 'path_open', - 'synthetic_open', - () => openGuestFileForPathOpen( - fd, - pathPtr, - pathLen, - oflags, - rightsBase, - fdflags, - openedFdPtr, - ), - ); - if (fallbackResult != null) { - return fallbackResult; - } - } - } catch { - return WASI_ERRNO_FAULT; - } - } - - if (result === WASI_ERRNO_SUCCESS) { - return __agentOSWasiMeasurePhase('path_open', 'fd_bookkeeping', () => - retainPathOpenDelegateFd(openedFdPtr, guestPath, fdflags, rightsBase) - ); - } - return result; - }; -} - -function wrapReadOnlyPathMutation(name, shouldDeny) { - const delegate = typeof wasiImport[name] === 'function' ? wasiImport[name].bind(wasiImport) : null; - if (!delegate) { - return; - } - wasiImport[name] = (...args) => { - if (shouldDeny(...args)) { - return denyReadOnlyMutation(); - } - return delegate(...args); - }; -} - -wrapReadOnlyPathMutation('path_create_directory', (fd, pathPtr, pathLen) => - resolvedGuestPathIsReadOnly(fd, pathPtr, pathLen), -); -wrapReadOnlyPathMutation('path_filestat_set_times', (fd, _flags, pathPtr, pathLen) => - resolvedGuestPathIsReadOnly(fd, pathPtr, pathLen), -); -wrapReadOnlyPathMutation( - 'path_link', - (oldFd, _oldFlags, oldPathPtr, oldPathLen, newFd, newPathPtr, newPathLen) => - resolvedGuestPathIsReadOnly(oldFd, oldPathPtr, oldPathLen) || - resolvedGuestPathIsReadOnly(newFd, newPathPtr, newPathLen), -); -wrapReadOnlyPathMutation('path_remove_directory', (fd, pathPtr, pathLen) => - resolvedGuestPathIsReadOnly(fd, pathPtr, pathLen), -); -wrapReadOnlyPathMutation( - 'path_rename', - (oldFd, oldPathPtr, oldPathLen, newFd, newPathPtr, newPathLen) => - resolvedGuestPathIsReadOnly(oldFd, oldPathPtr, oldPathLen) || - resolvedGuestPathIsReadOnly(newFd, newPathPtr, newPathLen), -); -wrapReadOnlyPathMutation('path_symlink', (_oldPathPtr, _oldPathLen, fd, newPathPtr, newPathLen) => - resolvedGuestPathIsReadOnly(fd, newPathPtr, newPathLen), -); -wrapReadOnlyPathMutation('path_unlink_file', (fd, pathPtr, pathLen) => - resolvedGuestPathIsReadOnly(fd, pathPtr, pathLen), -); - -if (isWorkspaceReadOnly()) { - - wasiImport.fd_write = (fd, iovs, iovsLen, nwrittenPtr) => { - if (Number(fd) > 2) { - return denyReadOnlyMutation(); - } - - return delegateFdWrite ? delegateFdWrite(fd, iovs, iovsLen, nwrittenPtr) : WASI_ERRNO_FAULT; - }; - - wasiImport.fd_pwrite = (fd, iovs, iovsLen, offset, nwrittenPtr) => { - if (Number(fd) > 2) { - return denyReadOnlyMutation(); - } - - return delegateFdPwrite - ? delegateFdPwrite(fd, iovs, iovsLen, offset, nwrittenPtr) - : WASI_ERRNO_FAULT; - }; - - for (const name of [ - 'fd_allocate', - 'fd_filestat_set_size', - 'fd_filestat_set_times', - 'path_create_directory', - 'path_filestat_set_times', - 'path_link', - 'path_remove_directory', - 'path_rename', - 'path_symlink', - 'path_unlink_file', - ]) { - if (typeof wasiImport[name] === 'function') { - wasiImport[name] = () => denyReadOnlyMutation(); - } - } -} - -const delegateManagedFdRead = - typeof wasiImport.fd_read === 'function' - ? wasiImport.fd_read.bind(wasiImport) - : null; -const delegateManagedFdWrite = - typeof wasiImport.fd_write === 'function' - ? wasiImport.fd_write.bind(wasiImport) - : null; -const delegateManagedFdPwrite = - typeof wasiImport.fd_pwrite === 'function' - ? wasiImport.fd_pwrite.bind(wasiImport) - : null; -const delegateManagedFdSeek = - typeof wasiImport.fd_seek === 'function' - ? wasiImport.fd_seek.bind(wasiImport) - : null; -const delegateManagedFdTell = - typeof wasiImport.fd_tell === 'function' - ? wasiImport.fd_tell.bind(wasiImport) - : null; -const delegateManagedFdFdstatGet = - typeof wasiImport.fd_fdstat_get === 'function' - ? wasiImport.fd_fdstat_get.bind(wasiImport) - : null; -const delegateManagedFdFdstatSetFlags = - typeof wasiImport.fd_fdstat_set_flags === 'function' - ? wasiImport.fd_fdstat_set_flags.bind(wasiImport) - : null; -const delegateManagedFdFilestatGet = - typeof wasiImport.fd_filestat_get === 'function' - ? wasiImport.fd_filestat_get.bind(wasiImport) - : null; -const delegateManagedFdFilestatSetSize = - typeof wasiImport.fd_filestat_set_size === 'function' - ? wasiImport.fd_filestat_set_size.bind(wasiImport) - : null; -const delegateManagedFdClose = - typeof wasiImport.fd_close === 'function' - ? wasiImport.fd_close.bind(wasiImport) - : null; -const delegateManagedFdPrestatGet = - typeof wasiImport.fd_prestat_get === 'function' - ? wasiImport.fd_prestat_get.bind(wasiImport) - : null; -const delegateManagedFdPrestatDirName = - typeof wasiImport.fd_prestat_dir_name === 'function' - ? wasiImport.fd_prestat_dir_name.bind(wasiImport) - : null; -const delegateManagedPollOneoff = - typeof wasiImport.poll_oneoff === 'function' - ? wasiImport.poll_oneoff.bind(wasiImport) - : null; -const KERNEL_POLLIN = 0x0001; -const KERNEL_POLLOUT = 0x0004; -const KERNEL_POLLERR = 0x0008; -const KERNEL_POLLHUP = 0x0010; - -wasiImport.fd_read = (fd, iovs, iovsLen, nreadPtr) => { - const numericFd = Number(fd) >>> 0; - const handle = __agentOSWasiMeasurePhase('fd_read', 'lookup_handle', () => - lookupFdHandle(numericFd) - ); - if (handle?.kind === 'pipe-read') { - try { - const requestedLength = __agentOSWasiMeasurePhase('fd_read', 'iov_scan', () => { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return 0; - } - const view = new DataView(instanceMemory.buffer); - let total = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - total += view.getUint32(entryOffset + 4, true); - } - return total >>> 0; - }); - - const pipeClosed = __agentOSWasiMeasurePhase('fd_read', 'pipe_wait', () => { - while (handle.pipe.chunks.length === 0) { - if (handle.pipe.writeHandleCount === 0 && handle.pipe.producers.size === 0) { - return true; - } - - const pumped = pumpPipeProducers(handle.pipe, 10); - if (!pumped) { - Atomics.wait(syntheticWaitArray, 0, 0, 10); - } - } - return false; - }); - if (pipeClosed) { - return __agentOSWasiMeasurePhase('fd_read', 'result_marshal', () => - writeGuestUint32(nreadPtr, 0) - ); - } - - const chunk = __agentOSWasiMeasurePhase('fd_read', 'host_io', () => - dequeuePipeBytes(handle.pipe, requestedLength) - ); - const written = __agentOSWasiMeasurePhase('fd_read', 'guest_iov_write', () => - writeBytesToGuestIovs(iovs, iovsLen, chunk) - ); - return __agentOSWasiMeasurePhase('fd_read', 'result_marshal', () => - writeGuestUint32(nreadPtr, written) - ); - } catch { - return WASI_ERRNO_FAULT; - } - } - - if (handle?.kind === 'guest-file') { - try { - const requestedLength = __agentOSWasiMeasurePhase('fd_read', 'iov_scan', () => { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return 0; - } - const view = new DataView(instanceMemory.buffer); - let total = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - total += view.getUint32(entryOffset + 4, true); - } - return total >>> 0; - }); - const buffer = Buffer.alloc(requestedLength); - const bytesRead = __agentOSWasiMeasurePhase('fd_read', 'host_io', () => - fsModule.readSync( - handle.targetFd, - buffer, - 0, - requestedLength, - handle.position ?? 0, - ) - ); - handle.position = (handle.position ?? 0) + bytesRead; - const written = __agentOSWasiMeasurePhase('fd_read', 'guest_iov_write', () => - writeBytesToGuestIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)) - ); - return __agentOSWasiMeasurePhase('fd_read', 'result_marshal', () => - writeGuestUint32(nreadPtr, written) - ); - } catch { - return WASI_ERRNO_FAULT; - } - } - - if (handle?.kind === 'passthrough' && typeof handle.ioFd === 'number') { - try { - const requestedLength = __agentOSWasiMeasurePhase('fd_read', 'iov_scan', () => { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return 0; - } - const view = new DataView(instanceMemory.buffer); - let total = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - total += view.getUint32(entryOffset + 4, true); - } - return total >>> 0; - }); - const buffer = Buffer.alloc(requestedLength); - const bytesRead = __agentOSWasiMeasurePhase('fd_read', 'host_io', () => - fsModule.readSync( - handle.ioFd, - buffer, - 0, - requestedLength, - handle.position ?? 0, - ) - ); - handle.position = (handle.position ?? 0) + bytesRead; - const written = __agentOSWasiMeasurePhase('fd_read', 'guest_iov_write', () => - writeBytesToGuestIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)) - ); - return __agentOSWasiMeasurePhase('fd_read', 'result_marshal', () => - writeGuestUint32(nreadPtr, written) - ); - } catch (error) { - return mapSyntheticFsError(error); - } - } - - if ( - numericFd === 0 && - handle?.kind === 'passthrough' && - handle.targetFd === 0 && - passthroughHandles.get(0) === handle - ) { - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === 'string' && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - if (sidecarManagedProcess || KERNEL_STDIO_SYNC_RPC) { - try { - const requestedLength = __agentOSWasiMeasurePhase('fd_read', 'iov_scan', () => { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return 0; - } - const view = new DataView(instanceMemory.buffer); - let total = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - total += view.getUint32(entryOffset + 4, true); - } - return total >>> 0; - }); - const chunk = __agentOSWasiMeasurePhase('fd_read', 'kernel_stdin_read', () => - readKernelStdinChunk(requestedLength) - ); - if (!chunk || chunk.length === 0) { - return __agentOSWasiMeasurePhase('fd_read', 'result_marshal', () => - writeGuestUint32(nreadPtr, 0) - ); - } - const written = __agentOSWasiMeasurePhase('fd_read', 'guest_iov_write', () => - writeBytesToGuestIovs(iovs, iovsLen, chunk) - ); - return __agentOSWasiMeasurePhase('fd_read', 'result_marshal', () => - writeGuestUint32(nreadPtr, written) - ); - } catch { - return WASI_ERRNO_FAULT; - } - } - } - - if (!handle && numericFd <= 2) { - return WASI_ERRNO_BADF; - } - - if (handle?.kind === 'passthrough') { - return delegateManagedFdRead - ? __agentOSWasiMeasurePhase('fd_read', 'delegate_call', () => - delegateManagedFdRead(handle.targetFd, iovs, iovsLen, nreadPtr) - ) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(numericFd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdRead - ? __agentOSWasiMeasurePhase('fd_read', 'delegate_call', () => - delegateManagedFdRead(numericFd, iovs, iovsLen, nreadPtr) - ) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_pread = (fd, iovs, iovsLen, offset, nreadPtr) => { - const handle = lookupFdHandle(fd); - if (handle?.kind === 'guest-file') { - try { - const requestedLength = (() => { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return 0; - } - const view = new DataView(instanceMemory.buffer); - let total = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - total += view.getUint32(entryOffset + 4, true); - } - return total >>> 0; - })(); - const buffer = Buffer.alloc(requestedLength); - const bytesRead = fsModule.readSync( - handle.targetFd, - buffer, - 0, - requestedLength, - Number(offset), - ); - const written = writeBytesToGuestIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return writeGuestUint32(nreadPtr, written); - } catch { - return WASI_ERRNO_FAULT; - } - } - - if (handle?.kind === 'passthrough') { - if (typeof handle.ioFd === 'number') { - try { - const requestedLength = (() => { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return 0; - } - const view = new DataView(instanceMemory.buffer); - let total = 0; - for (let index = 0; index < (Number(iovsLen) >>> 0); index += 1) { - const entryOffset = (Number(iovs) >>> 0) + index * 8; - total += view.getUint32(entryOffset + 4, true); - } - return total >>> 0; - })(); - const buffer = Buffer.alloc(requestedLength); - const bytesRead = fsModule.readSync( - handle.ioFd, - buffer, - 0, - requestedLength, - Number(offset), - ); - const written = writeBytesToGuestIovs(iovs, iovsLen, buffer.subarray(0, bytesRead)); - return writeGuestUint32(nreadPtr, written); - } catch (error) { - return mapSyntheticFsError(error); - } - } - return delegateFdPread - ? delegateFdPread(handle.targetFd, iovs, iovsLen, offset, nreadPtr) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateFdPread - ? delegateFdPread(fd, iovs, iovsLen, offset, nreadPtr) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_pwrite = (fd, iovs, iovsLen, offset, nwrittenPtr) => { - const handle = lookupFdHandle(fd); - if (handle?.kind === 'guest-file') { - try { - const bytes = collectGuestIovBytes(iovs, iovsLen); - const written = fsModule.writeSync( - handle.targetFd, - bytes, - 0, - bytes.length, - Number(offset), - ); - return writeGuestUint32(nwrittenPtr, written); - } catch { - return WASI_ERRNO_FAULT; - } - } - - if (handle?.kind === 'passthrough') { - if (handle.readOnly === true) { - return WASI_ERRNO_ROFS; - } - if (typeof handle.ioFd === 'number') { - try { - const bytes = collectGuestIovBytes(iovs, iovsLen); - const written = fsModule.writeSync( - handle.ioFd, - bytes, - 0, - bytes.length, - Number(offset), - ); - // A positioned write can grow the file past a size remembered from a - // prior truncate; drop the stale entry so fd_size/path_size fall - // through to the authoritative fstat. - forgetHostFsSize(handle.guestPath); - return writeGuestUint32(nwrittenPtr, written); - } catch (error) { - return mapSyntheticFsError(error); - } - } - return delegateManagedFdPwrite - ? delegateManagedFdPwrite(handle.targetFd, iovs, iovsLen, offset, nwrittenPtr) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdPwrite - ? delegateManagedFdPwrite(fd, iovs, iovsLen, offset, nwrittenPtr) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_sync = (fd) => { - const handle = lookupFdHandle(fd); - if (handle?.kind === 'guest-file') { - return WASI_ERRNO_SUCCESS; - } - - if (handle?.kind === 'passthrough') { - return delegateFdSync ? delegateFdSync(handle.targetFd) : WASI_ERRNO_SUCCESS; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateFdSync ? delegateFdSync(fd) : WASI_ERRNO_SUCCESS; -}; - -wasiImport.fd_seek = (fd, offset, whence, newOffsetPtr) => { - const handle = lookupFdHandle(fd); - if (handle?.kind === 'guest-file') { - try { - const next = seekGuestFileHandle(handle, offset, whence); - if (next == null) { - return WASI_ERRNO_INVAL; - } - return writeGuestUint64(newOffsetPtr, next); - } catch { - return WASI_ERRNO_FAULT; - } - } - - if (handle && handle.kind !== 'passthrough') { - return WASI_ERRNO_SPIPE; - } - - if (handle?.kind === 'passthrough') { - if (typeof handle.ioFd === 'number') { - try { - const next = seekGuestFileHandle(handle, offset, whence); - if (next == null) { - return WASI_ERRNO_INVAL; - } - return writeGuestUint64(newOffsetPtr, next); - } catch { - return WASI_ERRNO_FAULT; - } - } - return delegateManagedFdSeek - ? delegateManagedFdSeek(handle.targetFd, offset, whence, newOffsetPtr) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdSeek - ? delegateManagedFdSeek(fd, offset, whence, newOffsetPtr) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_tell = (fd, offsetPtr) => { - const handle = lookupFdHandle(fd); - if (handle?.kind === 'guest-file') { - return writeGuestUint64(offsetPtr, BigInt(handle.position ?? 0)); - } - - if (handle && handle.kind !== 'passthrough') { - return WASI_ERRNO_SPIPE; - } - - if (handle?.kind === 'passthrough') { - if (typeof handle.ioFd === 'number') { - return writeGuestUint64(offsetPtr, BigInt(handle.position ?? 0)); - } - return delegateManagedFdTell - ? delegateManagedFdTell(handle.targetFd, offsetPtr) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdTell - ? delegateManagedFdTell(fd, offsetPtr) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_fdstat_get = (fd, statPtr) => { - const handle = __agentOSWasiMeasurePhase('fd_fdstat_get', 'lookup_handle', () => - lookupFdHandle(fd) - ); - // Kernel-PTY stdio must report CHARACTER_DEVICE so guest is_terminal()/ - // isatty() see the TTY (the runner-process fds behind the delegate are - // pipes). Resolve dup'd passthrough handles to their target fd first. - { - const stdioFd = - handle?.kind === 'passthrough' ? Number(handle.targetFd) >>> 0 : Number(fd) >>> 0; - if ((handle == null || handle.kind === 'passthrough') && stdioFd <= 2 && - stdioFdIsKernelTty(stdioFd)) { - return __agentOSWasiMeasurePhase( - 'fd_fdstat_get', - 'marshal_fdstat', - () => writeGuestFdstat( - statPtr, - WASI_FILETYPE_CHARACTER_DEVICE, - 0, - WASI_RIGHT_FD_READ | - WASI_RIGHT_FD_WRITE | - WASI_RIGHT_FD_FDSTAT_SET_FLAGS | - WASI_RIGHT_FD_FILESTAT_GET | - WASI_RIGHT_POLL_FD_READWRITE, - 0n, - ), - ); - } - } - if (handle?.kind === 'pipe-read') { - return __agentOSWasiMeasurePhase( - 'fd_fdstat_get', - 'marshal_fdstat', - () => writeGuestFdstat( - statPtr, - WASI_FILETYPE_UNKNOWN, - 0, - WASI_RIGHT_FD_READ | - WASI_RIGHT_FD_FDSTAT_SET_FLAGS | - WASI_RIGHT_FD_FILESTAT_GET | - WASI_RIGHT_POLL_FD_READWRITE, - 0n, - ), - ); - } - - if (handle?.kind === 'pipe-write') { - return __agentOSWasiMeasurePhase( - 'fd_fdstat_get', - 'marshal_fdstat', - () => writeGuestFdstat( - statPtr, - WASI_FILETYPE_UNKNOWN, - 0, - WASI_RIGHT_FD_WRITE | - WASI_RIGHT_FD_FDSTAT_SET_FLAGS | - WASI_RIGHT_FD_FILESTAT_GET | - WASI_RIGHT_POLL_FD_READWRITE, - 0n, - ), - ); - } - - if (handle && handle.kind !== 'passthrough') { - return WASI_ERRNO_BADF; - } - - if (handle?.kind === 'passthrough') { - return delegateManagedFdFdstatGet - ? __agentOSWasiMeasurePhase('fd_fdstat_get', 'delegate_call', () => - delegateManagedFdFdstatGet(handle.targetFd, statPtr) - ) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdFdstatGet - ? __agentOSWasiMeasurePhase('fd_fdstat_get', 'delegate_call', () => - delegateManagedFdFdstatGet(fd, statPtr) - ) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_fdstat_set_flags = (fd, flags) => { - const handle = lookupFdHandle(fd); - if (handle && handle.kind !== 'passthrough') { - return WASI_ERRNO_BADF; - } - - if (handle?.kind === 'passthrough') { - return delegateManagedFdFdstatSetFlags - ? delegateManagedFdFdstatSetFlags(handle.targetFd, flags) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdFdstatSetFlags - ? delegateManagedFdFdstatSetFlags(fd, flags) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_filestat_get = (fd, statPtr) => { - const handle = lookupFdHandle(fd); - if (handle?.kind === 'guest-file') { - try { - return writeGuestFilestat(statPtr, fsModule.fstatSync(handle.targetFd)); - } catch (error) { - return mapSyntheticFsError(error); - } - } - - if (handle?.kind === 'passthrough') { - if (typeof handle.ioFd === 'number') { - try { - return writeGuestFilestat(statPtr, fsModule.fstatSync(handle.ioFd)); - } catch (error) { - return mapSyntheticFsError(error); - } - } - return delegateManagedFdFilestatGet - ? delegateManagedFdFilestatGet(handle.targetFd, statPtr) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdFilestatGet - ? delegateManagedFdFilestatGet(fd, statPtr) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_filestat_set_size = (fd, size) => { - const handle = lookupFdHandle(fd); - if (handle?.kind === 'guest-file') { - try { - const nextSize = Number(size); - fsModule.ftruncateSync(handle.targetFd, nextSize); - if ((handle.position ?? 0) > nextSize) { - handle.position = nextSize; - } - rememberHostFsSize(handle.guestPath, nextSize); - return WASI_ERRNO_SUCCESS; - } catch (error) { - return mapSyntheticFsError(error); - } - } - - if (handle?.kind === 'passthrough') { - if (handle.readOnly === true) { - return WASI_ERRNO_ROFS; - } - if (typeof handle.ioFd === 'number') { - try { - const nextSize = Number(size); - fsModule.ftruncateSync(handle.ioFd, nextSize); - if ((handle.position ?? 0) > nextSize) { - handle.position = nextSize; - } - rememberHostFsSize(handle.guestPath, nextSize); - return WASI_ERRNO_SUCCESS; - } catch (error) { - return mapSyntheticFsError(error); - } - } - if (typeof handle.guestPath === 'string') { - try { - const nextSize = Number(size); - const pathFd = fsModule.openSync(handle.guestPath, 0o1, 0o666); - try { - fsModule.ftruncateSync(pathFd, nextSize); - if ((handle.position ?? 0) > nextSize) { - handle.position = nextSize; - } - rememberHostFsSize(handle.guestPath, nextSize); - } finally { - fsModule.closeSync(pathFd); - } - return WASI_ERRNO_SUCCESS; - } catch (error) { - return mapSyntheticFsError(error); - } - } - return delegateManagedFdFilestatSetSize - ? delegateManagedFdFilestatSetSize(handle.targetFd, size) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdFilestatSetSize - ? delegateManagedFdFilestatSetSize(fd, size) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_prestat_get = (fd, prestatPtr) => { - const handle = lookupFdHandle(fd); - if (handle && handle.kind !== 'passthrough') { - return WASI_ERRNO_BADF; - } - - if (handle?.kind === 'passthrough') { - return delegateManagedFdPrestatGet - ? delegateManagedFdPrestatGet(handle.targetFd, prestatPtr) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdPrestatGet - ? delegateManagedFdPrestatGet(fd, prestatPtr) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_prestat_dir_name = (fd, pathPtr, pathLen) => { - const handle = lookupFdHandle(fd); - if (handle && handle.kind !== 'passthrough') { - return WASI_ERRNO_BADF; - } - - if (handle?.kind === 'passthrough') { - return delegateManagedFdPrestatDirName - ? delegateManagedFdPrestatDirName(handle.targetFd, pathPtr, pathLen) - : WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdPrestatDirName - ? delegateManagedFdPrestatDirName(fd, pathPtr, pathLen) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_write = (fd, iovs, iovsLen, nwrittenPtr) => { - const handle = __agentOSWasiMeasurePhase('fd_write', 'lookup_handle', () => - lookupFdHandle(fd) - ); - const numericFd = Number(fd) >>> 0; - if (handle?.kind === 'pipe-write') { - try { - const bytes = __agentOSWasiMeasurePhase('fd_write', 'guest_iov_collect', () => - collectGuestIovBytes(iovs, iovsLen) - ); - if (bytes.length > 0 && !pipeHasReaders(handle.pipe)) { - return WASI_ERRNO_PIPE; - } - __agentOSWasiMeasurePhase('fd_write', 'host_io', () => { - enqueuePipeBytes(handle.pipe, bytes); - flushPipeConsumers(handle.pipe); - }); - return __agentOSWasiMeasurePhase('fd_write', 'result_marshal', () => - writeGuestUint32(nwrittenPtr, bytes.length) - ); - } catch { - return WASI_ERRNO_FAULT; - } - } - - if (handle?.kind === 'guest-file') { - try { - const bytes = __agentOSWasiMeasurePhase('fd_write', 'guest_iov_collect', () => - collectGuestIovBytes(iovs, iovsLen) - ); - const written = __agentOSWasiMeasurePhase('fd_write', 'host_io', () => - writeBytesToGuestFileHandle(handle, bytes) - ); - return __agentOSWasiMeasurePhase('fd_write', 'result_marshal', () => - writeGuestUint32(nwrittenPtr, written) - ); - } catch { - return WASI_ERRNO_FAULT; - } - } - - if (numericFd === 1 || numericFd === 2) { - try { - const bytes = __agentOSWasiMeasurePhase('fd_write', 'guest_iov_collect', () => - collectGuestIovBytes(iovs, iovsLen) - ); - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === 'string' && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - if (sidecarManagedProcess || KERNEL_STDIO_SYNC_RPC) { - const written = __agentOSWasiMeasurePhase('fd_write', 'sync_rpc', () => - Number(callSyncRpc('__kernel_stdio_write', [numericFd, bytes])) >>> 0 - ); - return __agentOSWasiMeasurePhase('fd_write', 'result_marshal', () => - writeGuestUint32(nwrittenPtr, written) - ); - } - __agentOSWasiMeasurePhase('fd_write', 'host_io', () => - (numericFd === 1 ? process.stdout : process.stderr).write(bytes) - ); - return __agentOSWasiMeasurePhase('fd_write', 'result_marshal', () => - writeGuestUint32(nwrittenPtr, bytes.length) - ); - } catch { - return WASI_ERRNO_FAULT; - } - } - - if (handle?.kind === 'passthrough') { - if (handle.readOnly === true) { - return WASI_ERRNO_ROFS; - } - if (typeof handle.ioFd === 'number') { - try { - const bytes = __agentOSWasiMeasurePhase('fd_write', 'guest_iov_collect', () => - collectGuestIovBytes(iovs, iovsLen) - ); - const written = __agentOSWasiMeasurePhase('fd_write', 'host_io', () => - writeBytesToGuestFileHandle({ ...handle, targetFd: handle.ioFd }, bytes) - ); - if (handle.append) { - handle.position = Number(fsModule.fstatSync(handle.ioFd).size ?? 0); - } else { - handle.position = (handle.position ?? 0) + written; - } - // The write grew/changed the file; a size remembered from a prior - // truncate is now stale. Drop it so fd_size/path_size fall through to - // the authoritative fstat rather than reporting the old length. - forgetHostFsSize(handle.guestPath); - return __agentOSWasiMeasurePhase('fd_write', 'result_marshal', () => - writeGuestUint32(nwrittenPtr, written) - ); - } catch (error) { - return mapSyntheticFsError(error); - } - } - return delegateManagedFdWrite - ? __agentOSWasiMeasurePhase('fd_write', 'delegate_call', () => - delegateManagedFdWrite(handle.targetFd, iovs, iovsLen, nwrittenPtr) - ) - : WASI_ERRNO_BADF; - } - - if (!handle && numericFd <= 2) { - return WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - return delegateManagedFdWrite - ? __agentOSWasiMeasurePhase('fd_write', 'delegate_call', () => - delegateManagedFdWrite(fd, iovs, iovsLen, nwrittenPtr) - ) - : WASI_ERRNO_BADF; -}; - -wasiImport.fd_close = (fd) => { - traceHostProcess('fd-close-begin', { - fd: Number(fd) >>> 0, - syntheticKind: syntheticFdEntries.get(Number(fd) >>> 0)?.kind ?? null, - passthroughKind: passthroughHandles.get(Number(fd) >>> 0)?.kind ?? null, - }); - if (__agentOSWasiMeasurePhase('fd_close', 'synthetic_close', () => closeSyntheticFd(fd))) { - traceHostProcess('fd-close-synthetic', { fd: Number(fd) >>> 0 }); - return WASI_ERRNO_SUCCESS; - } - - const handle = __agentOSWasiMeasurePhase('fd_close', 'lookup_handle', () => - lookupFdHandle(fd) - ); - if (handle?.kind === 'passthrough') { - traceHostProcess('fd-close-passthrough', { - fd: Number(fd) >>> 0, - targetFd: handle.targetFd ?? null, - }); - __agentOSWasiMeasurePhase('fd_close', 'fd_bookkeeping', () => closePassthroughFd(fd)); - return WASI_ERRNO_SUCCESS; - } - - if (!handle && Number(fd) >>> 0 <= 2) { - return WASI_ERRNO_BADF; - } - - if (rejectClosedPassthroughFd(fd)) { - return WASI_ERRNO_BADF; - } - - if (delegateManagedFdRefCounts.has(Number(fd) >>> 0)) { - const shouldDelegateClose = __agentOSWasiMeasurePhase('fd_close', 'fd_bookkeeping', () => - releaseDelegateFd(fd) - ); - traceHostProcess('fd-close-delegate-tracked', { - fd: Number(fd) >>> 0, - shouldDelegateClose, - remainingRefs: delegateManagedFdRefCounts.get(Number(fd) >>> 0) ?? 0, - }); - if (!shouldDelegateClose) { - return WASI_ERRNO_SUCCESS; - } - passthroughHandles.delete(Number(fd) >>> 0); - } - - traceHostProcess('fd-close-delegate', { fd: Number(fd) >>> 0 }); - return delegateManagedFdClose - ? __agentOSWasiMeasurePhase('fd_close', 'delegate_call', () => - delegateManagedFdClose(fd) - ) - : WASI_ERRNO_BADF; -}; - -wasiImport.poll_oneoff = (inPtr, outPtr, nsubscriptions, neventsPtr) => { - if (!(instanceMemory instanceof WebAssembly.Memory)) { - return delegateManagedPollOneoff - ? delegateManagedPollOneoff(inPtr, outPtr, nsubscriptions, neventsPtr) - : WASI_ERRNO_FAULT; - } - - const subscriptionCount = Number(nsubscriptions) >>> 0; - if (subscriptionCount === 0) { - return writeGuestUint32(neventsPtr, 0); - } - - const subscriptionSize = 48; - const eventSize = 32; - const view = new DataView(instanceMemory.buffer); - const memory = new Uint8Array(instanceMemory.buffer); - const subscriptions = []; - let hasSyntheticSubscription = false; - let hasRemappedPassthroughSubscription = false; - const sidecarManagedProcess = - typeof process?.env?.AGENTOS_SANDBOX_ROOT === 'string' && - process.env.AGENTOS_SANDBOX_ROOT.length > 0; - let timeoutMs = null; - - for (let index = 0; index < subscriptionCount; index += 1) { - const base = (Number(inPtr) >>> 0) + index * subscriptionSize; - const tag = view.getUint8(base + 8); - const userdata = memory.slice(base, base + 8); - if (tag === 0) { - const timeoutNs = view.getBigUint64(base + 24, true); - const relativeTimeoutMs = Number(timeoutNs / 1000000n); - timeoutMs = - timeoutMs == null ? relativeTimeoutMs : Math.min(timeoutMs, relativeTimeoutMs); - subscriptions.push({ kind: 'clock', userdata }); - continue; - } - - if (tag !== 1 && tag !== 2) { - subscriptions.push({ kind: 'unsupported', userdata }); - continue; - } - - const fd = view.getUint32(base + 16, true); - const handle = lookupFdHandle(fd); - if (!handle && rejectClosedPassthroughFd(fd)) { - hasSyntheticSubscription = true; - subscriptions.push({ - kind: tag === 1 ? 'fd_read' : 'fd_write', - fd, - handle, - userdata, - error: WASI_ERRNO_BADF, - }); - continue; - } - if (handle && handle.kind !== 'passthrough') { - hasSyntheticSubscription = true; - } else if (handle?.kind === 'passthrough') { - const targetFd = Number(handle.targetFd) >>> 0; - if ( - targetFd !== fd || - (fd === 0 && (sidecarManagedProcess || KERNEL_STDIO_SYNC_RPC)) - ) { - hasRemappedPassthroughSubscription = true; - } - } else if (!handle && fd <= 2 && (sidecarManagedProcess || KERNEL_STDIO_SYNC_RPC)) { - // Kernel-managed stdio with no local handle: fd 0/1/2 map straight to - // the kernel PTY/pipes, so readiness must come from __kernel_poll — the - // delegate's fds are the runner process's own stdio and never fire for - // guest terminal input (vim's RealWaitForChar polls fd 0 this way). - hasRemappedPassthroughSubscription = true; - } - subscriptions.push({ - kind: tag === 1 ? 'fd_read' : 'fd_write', - fd, - handle, - userdata, - }); - } - - if (!hasSyntheticSubscription && !hasRemappedPassthroughSubscription) { - return delegateManagedPollOneoff - ? delegateManagedPollOneoff(inPtr, outPtr, nsubscriptions, neventsPtr) - : WASI_ERRNO_BADF; - } - - const deadline = timeoutMs == null ? null : Date.now() + Math.max(0, timeoutMs); - const readyEvents = []; - - function collectKernelReadyEvents(waitMs) { - if (!hasRemappedPassthroughSubscription) { - return []; - } - - const kernelPollFdFor = (subscription) => { - if (subscription.kind !== 'fd_read' && subscription.kind !== 'fd_write') { - return null; - } - const fd = Number(subscription.fd) >>> 0; - if (subscription.handle?.kind === 'passthrough') { - const targetFd = Number(subscription.handle.targetFd) >>> 0; - if (targetFd !== fd || (fd === 0 && (sidecarManagedProcess || KERNEL_STDIO_SYNC_RPC))) { - return targetFd; - } - return null; - } - if (!subscription.handle && fd <= 2 && (sidecarManagedProcess || KERNEL_STDIO_SYNC_RPC)) { - return fd; - } - return null; - }; - const pollTargets = subscriptions - .filter((subscription) => kernelPollFdFor(subscription) != null) - .map((subscription) => ({ - fd: kernelPollFdFor(subscription), - events: subscription.kind === 'fd_read' ? KERNEL_POLLIN : KERNEL_POLLOUT, - })); - if (pollTargets.length === 0) { - return []; - } - - let response; - try { - response = callSyncRpc('__kernel_poll', [ - pollTargets, - Math.max(0, Number(waitMs) >>> 0), - ]); - } catch { - return []; - } - - const responseEntries = Array.isArray(response?.fds) ? response.fds : []; - const ready = []; - for (const subscription of subscriptions) { - const kernelFd = kernelPollFdFor(subscription); - if (kernelFd == null) { - continue; - } - - const targetFd = kernelFd; - const responseEntry = responseEntries.find( - (entry) => (Number(entry?.fd) >>> 0) === targetFd - ); - const revents = Number(responseEntry?.revents) >>> 0; - const interested = - subscription.kind === 'fd_read' - ? KERNEL_POLLIN | KERNEL_POLLERR | KERNEL_POLLHUP - : KERNEL_POLLOUT | KERNEL_POLLERR | KERNEL_POLLHUP; - if ((revents & interested) === 0) { - continue; - } - - ready.push({ - userdata: subscription.userdata, - error: WASI_ERRNO_SUCCESS, - type: subscription.kind === 'fd_read' ? 1 : 2, - nbytes: subscription.kind === 'fd_read' ? 1 : 65536, - flags: 0, - }); - } - return ready; - } - - while (readyEvents.length === 0) { - for (const subscription of subscriptions) { - if (subscription.error != null) { - readyEvents.push({ - userdata: subscription.userdata, - error: subscription.error, - type: subscription.kind === 'fd_read' ? 1 : 2, - nbytes: 0, - flags: 0, - }); - continue; - } - - if (subscription.kind === 'fd_read' && subscription.handle?.kind === 'pipe-read') { - const pipe = subscription.handle.pipe; - if (pipe.chunks.length > 0 || (pipe.writeHandleCount === 0 && pipe.producers.size === 0)) { - readyEvents.push({ - userdata: subscription.userdata, - error: WASI_ERRNO_SUCCESS, - type: 1, - nbytes: pipe.chunks[0]?.length ?? 0, - flags: 0, - }); - } - continue; - } - - if (subscription.kind === 'fd_write' && subscription.handle?.kind === 'pipe-write') { - readyEvents.push({ - userdata: subscription.userdata, - error: WASI_ERRNO_SUCCESS, - type: 2, - nbytes: 65536, - flags: 0, - }); - continue; - } - } - - if (readyEvents.length > 0) { - break; - } - - if (hasRemappedPassthroughSubscription) { - // Kernel fds wait event-driven in the sidecar (parked RPC), so the slice - // can be long. Synthetic (pipe) subscriptions still need short local - // pumping, so only use the long slice when every subscription is - // kernel-backed. - const kernelWaitMs = hasSyntheticSubscription - ? deadline == null - ? 10 - : Math.max(0, Math.min(10, deadline - Date.now())) - : deadline == null - ? KERNEL_WAIT_SLICE_MS - : Math.max(0, Math.min(KERNEL_WAIT_SLICE_MS, deadline - Date.now())); - readyEvents.push(...collectKernelReadyEvents(kernelWaitMs)); - if (readyEvents.length > 0) { - break; - } - } - - let pumped = false; - for (const subscription of subscriptions) { - if (subscription.kind === 'fd_read' && subscription.handle?.kind === 'pipe-read') { - pumped = pumpPipeProducers(subscription.handle.pipe, 10) || pumped; - } - } - - if (pumped) { - continue; - } - - if (deadline != null && Date.now() >= deadline) { - break; - } - - Atomics.wait( - syntheticWaitArray, - 0, - 0, - deadline == null ? 10 : Math.max(0, Math.min(10, deadline - Date.now())), - ); - } - - if (readyEvents.length === 0 && subscriptions.some((subscription) => subscription.kind === 'clock')) { - const clockSubscription = subscriptions.find((subscription) => subscription.kind === 'clock'); - readyEvents.push({ - userdata: clockSubscription.userdata, - error: WASI_ERRNO_SUCCESS, - type: 0, - nbytes: 0, - flags: 0, - }); - } - - for (let index = 0; index < readyEvents.length; index += 1) { - const base = (Number(outPtr) >>> 0) + index * eventSize; - const event = readyEvents[index]; - memory.set(event.userdata, base); - view.setUint16(base + 8, event.error, true); - view.setUint8(base + 10, event.type); - view.setBigUint64(base + 16, BigInt(event.nbytes), true); - view.setUint16(base + 24, event.flags, true); - } - - return writeGuestUint32(neventsPtr, readyEvents.length); -}; - -// Terminal event source for crossterm-based guests (brush shell, reedline). -// The patched crossterm WasiEventSource reads keystrokes through this import: -// read(ptr, len, timeout_ms) -> usize -// It performs a timed read of the guest's stdin (the kernel PTY/pipe) and copies -// the bytes into guest memory, returning the count (0 on timeout / EOF). usize::MAX -// (-1 as i32) means block until input. Backed by the same __kernel_stdin_read RPC -// the wasi fd_read path uses, so it works identically under native and browser. -const hostTtyImport = { - // Long event-driven waits: the sidecar parks __kernel_stdin_read and replies - // when the PTY becomes readable (reply-by-token), so a host->guest write the - // caller is waiting for (e.g. the CPR reply to crossterm's cursor-position - // query) lands immediately — no polling slices, no self-deadlock. - read(ptr, len, timeoutMs) { - const cap = Number(len) >>> 0; - if (cap === 0) return 0; - const blocking = (timeoutMs >>> 0) === 0xffffffff; - const deadline = blocking ? Infinity : Date.now() + (Number(timeoutMs) >>> 0); - while (true) { - const remaining = deadline - Date.now(); - if (remaining <= 0) return 0; - const response = callSyncRpc('__kernel_stdin_read', [ - cap, - Math.min(remaining, KERNEL_WAIT_SLICE_MS), - ]); - if (response && typeof response.dataBase64 === 'string') { - const bytes = Buffer.from(response.dataBase64, 'base64'); - const n = Math.min(bytes.length, cap); - if (n > 0) { - new Uint8Array(instanceMemory.buffer).set(bytes.subarray(0, n), ptr >>> 0); - return n; - } - } - if (response && response.done === true) return 0; - } - }, - // `host_tty.isatty(fd)` -> 1 if the guest fd is a kernel PTY, else 0. - isatty(fd) { - const descriptor = Number(fd) >>> 0; - return descriptor <= 2 && stdioFdIsKernelTty(descriptor) ? 1 : 0; - }, - // `host_tty.get_size(fd, colsPtr, rowsPtr)` -> writes the PTY window size as two - // little-endian u16s and returns 0; non-zero (ENOTTY) if fd is not a PTY. - get_size(fd, colsPtr, rowsPtr) { - const size = callSyncRpc('__kernel_tty_size', [fd >>> 0]); - if (!size || typeof size.cols !== 'number' || typeof size.rows !== 'number') { - return 25; // ENOTTY - } - const view = new DataView(instanceMemory.buffer); - view.setUint16(colsPtr >>> 0, size.cols & 0xffff, true); - view.setUint16(rowsPtr >>> 0, size.rows & 0xffff, true); - return 0; - }, - // Toggle terminal raw mode on the guest's PTY. crossterm/pty_probe/vim call this - // instead of tcsetattr; route it to the kernel so the guest gets raw keystrokes. - set_raw_mode(enabled) { - if (!stdioFdIsKernelTty(0)) { - return 25; // ENOTTY - } - callSyncRpc('__pty_set_raw_mode', [(enabled >>> 0) !== 0]); - return 0; - }, -}; - -function __agentOSWasiWrapImport(name, delegate) { - if (!__agentOSWasiSyscallPhasesEnabled || typeof delegate !== 'function') { - return delegate; - } - return (...args) => { - const startedNs = __agentOSWasmNowNs(); - try { - return delegate(...args); - } finally { - __agentOSWasiRecordSyscall(name, startedNs); - } - }; -} - -if (__agentOSWasiSyscallPhasesEnabled) { - for (const [name, delegate] of Object.entries(wasiImport)) { - if (typeof delegate === 'function') { - wasiImport[name] = __agentOSWasiWrapImport(name, delegate.bind(wasiImport)); - } - } -} - -const instance = __agentOSWasmMeasurePhase('WebAssembly.Instance', () => new WebAssembly.Instance(module, { - wasi_snapshot_preview1: wasiImport, - wasi_unstable: wasiImport, - host_tty: hostTtyImport, - // Read-write commands like DuckDB need fd_dup_min from the patched - // wasi-libc surface, but broader host_process capabilities stay - // reserved for the full tier. - host_process: - permissionTier === 'full' - ? hostProcessImport - : permissionTier === 'isolated' - ? undefined - : limitedHostProcessImport, - host_net: permissionTier === 'full' ? hostNetImport : undefined, - host_user: hostUserImport, - host_fs: hostFsImport, -})); - -if (instance.exports.memory instanceof WebAssembly.Memory) { - instanceMemory = instance.exports.memory; -} - -function dispatchWasmSignal(signal) { - const numeric = Number(signal) | 0; - if ( - numeric > 0 && - typeof instance?.exports?.__wasi_signal_trampoline === 'function' - ) { - instance.exports.__wasi_signal_trampoline(numeric); - } -} - -Object.defineProperty(globalThis, '__secureExecWasmSignalDispatch', { - configurable: true, - writable: true, - value: (_eventType, payload) => { - const signal = - typeof payload?.number === 'number' - ? payload.number - : signalNumberFromName(payload?.signal); - dispatchWasmSignal(signal); - }, -}); - -if (typeof instance.exports._start === 'function') { - // The `RuntimeError: unreachable` reports that used to point at - // `WASI.start()` were caused by the host shim around guest startup, not by - // V8 itself. Standalone runs must keep ordinary stdio on local process - // streams unless kernel stdio sync-RPC is explicitly enabled, while - // `poll_oneoff` still routes readiness probes through `__kernel_poll`. - // That preserves the expected startup ordering so guest `_start` checks can - // observe the ready event before we exit the runner. - let exitCode; - try { - exitCode = __agentOSWasmMeasurePhase('wasi.start', () => wasi.start(instance)); - } catch (error) { - __agentOSWasmEmitPhaseMetrics('wasi.start.error', { - error: error && typeof error === 'object' && 'message' in error ? String(error.message) : String(error), - }); - if (maxStackBytes !== null && isWasmStackExhaustionTrap(error)) { - reportConfiguredStackLimitExceeded(error); - process.exit(1); - } - throw error; - } - __agentOSWasmEmitPhaseMetrics('complete', { exitCode }); - process.exit(typeof exitCode === 'number' ? exitCode : 0); -} else if (typeof instance.exports.run === 'function') { - const result = await instance.exports.run(); - if (typeof result !== 'undefined') { - console.log(String(result)); - } -} else { - throw new Error('WebAssembly module must export _start or run'); -} diff --git a/crates/execution/assets/undici-shims/async_hooks.js b/crates/execution/assets/undici-shims/async_hooks.js deleted file mode 100644 index 5cf4ad48e..000000000 --- a/crates/execution/assets/undici-shims/async_hooks.js +++ /dev/null @@ -1,94 +0,0 @@ -"use strict"; - -class AsyncLocalStorage { - constructor() { - this._enabled = false; - this._store = undefined; - } - - disable() { - this._enabled = false; - this._store = undefined; - } - - enterWith(store) { - this._enabled = true; - this._store = store; - } - - exit(callback, ...args) { - const previousEnabled = this._enabled; - const previousStore = this._store; - this._enabled = false; - this._store = undefined; - try { - return callback(...args); - } finally { - this._enabled = previousEnabled; - this._store = previousStore; - } - } - - getStore() { - return this._enabled ? this._store : undefined; - } - - run(store, callback, ...args) { - const previousEnabled = this._enabled; - const previousStore = this._store; - this._enabled = true; - this._store = store; - try { - return callback(...args); - } finally { - this._enabled = previousEnabled; - this._store = previousStore; - } - } -} - -class AsyncResource { - constructor(type = "SecureExecAsyncResource") { - this.type = type; - } - - bind(fn, thisArg = undefined) { - if (typeof fn !== "function") { - return fn; - } - return (...args) => this.runInAsyncScope(fn, thisArg ?? this, ...args); - } - - emitDestroy() {} - - runInAsyncScope(fn, thisArg, ...args) { - return fn.apply(thisArg, args); - } -} - -function createHook() { - return { - enable() { - return this; - }, - disable() { - return this; - }, - }; -} - -function executionAsyncId() { - return 0; -} - -function triggerAsyncId() { - return 0; -} - -module.exports = { - AsyncLocalStorage, - AsyncResource, - createHook, - executionAsyncId, - triggerAsyncId, -}; diff --git a/crates/execution/assets/undici-shims/diagnostics_channel.js b/crates/execution/assets/undici-shims/diagnostics_channel.js deleted file mode 100644 index 1ef5516fd..000000000 --- a/crates/execution/assets/undici-shims/diagnostics_channel.js +++ /dev/null @@ -1,59 +0,0 @@ -"use strict"; - -const subscribers = new Map(); -const channels = new Map(); - -function ensureSubscribers(name) { - let list = subscribers.get(name); - if (!list) { - list = new Set(); - subscribers.set(name, list); - } - return list; -} - -function createChannel(name) { - return { - name, - get hasSubscribers() { - return ensureSubscribers(name).size > 0; - }, - publish(message) { - for (const subscriber of ensureSubscribers(name)) { - subscriber(message, name); - } - }, - subscribe(onMessage) { - ensureSubscribers(name).add(onMessage); - return this; - }, - unsubscribe(onMessage) { - ensureSubscribers(name).delete(onMessage); - return this; - }, - }; -} - -function channel(name) { - if (!channels.has(name)) { - channels.set(name, createChannel(name)); - } - return channels.get(name); -} - -function subscribe(name, onMessage) { - channel(name).subscribe(onMessage); -} - -function unsubscribe(name, onMessage) { - channel(name).unsubscribe(onMessage); -} - -module.exports = { - channel, - hasSubscribers(name) { - return channel(name).hasSubscribers; - }, - subscribe, - unsubscribe, -}; diff --git a/crates/execution/assets/undici-shims/dns-promises.js b/crates/execution/assets/undici-shims/dns-promises.js deleted file mode 100644 index 05461fe55..000000000 --- a/crates/execution/assets/undici-shims/dns-promises.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -function getDnsPromisesModule() { - const mod = globalThis._dnsModule?.promises; - if (!mod) { - throw new Error("node:dns/promises bridge module is not available"); - } - return mod; -} - -const exported = {}; -for (const key of [ - "Resolver", - "lookup", - "resolve", - "resolve4", - "resolve6", - "resolveAny", - "resolveMx", - "resolveTxt", - "resolveSrv", - "resolveCname", - "resolvePtr", - "resolveNs", - "resolveSoa", - "resolveNaptr", - "resolveCaa", -]) { - Object.defineProperty(exported, key, { - enumerable: true, - get() { - return getDnsPromisesModule()[key]; - }, - }); -} - -module.exports = exported; diff --git a/crates/execution/assets/undici-shims/dns.js b/crates/execution/assets/undici-shims/dns.js deleted file mode 100644 index 9646ccd24..000000000 --- a/crates/execution/assets/undici-shims/dns.js +++ /dev/null @@ -1,48 +0,0 @@ -"use strict"; - -function getDnsModule() { - const mod = globalThis._dnsModule; - if (!mod) { - throw new Error("node:dns bridge module is not available"); - } - return mod; -} - -const exported = {}; -for (const key of [ - "ADDRCONFIG", - "ALL", - "Resolver", - "V4MAPPED", - "constants", - "getDefaultResultOrder", - "getServers", - "lookup", - "lookupService", - "promises", - "resolve", - "resolve4", - "resolve6", - "resolveAny", - "resolveMx", - "resolveTxt", - "resolveSrv", - "resolveCname", - "resolvePtr", - "resolveNs", - "resolveSoa", - "resolveNaptr", - "resolveCaa", - "reverse", - "setDefaultResultOrder", - "setServers", -]) { - Object.defineProperty(exported, key, { - enumerable: true, - get() { - return getDnsModule()[key]; - }, - }); -} - -module.exports = exported; diff --git a/crates/execution/assets/undici-shims/http.js b/crates/execution/assets/undici-shims/http.js deleted file mode 100644 index 245cea8f6..000000000 --- a/crates/execution/assets/undici-shims/http.js +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; - -function getHttpModule() { - if (!globalThis._httpModule) { - throw new Error("node:http bridge module is not available"); - } - return globalThis._httpModule; -} - -class AgentPlaceholder {} -class ClientRequestPlaceholder {} -class IncomingMessagePlaceholder {} -class ServerPlaceholder {} -class ServerResponsePlaceholder {} - -const METHODS = [ - "CHECKOUT", - "CONNECT", - "COPY", - "DELETE", - "GET", - "HEAD", - "LOCK", - "M-SEARCH", - "MERGE", - "MKACTIVITY", - "MKCOL", - "MOVE", - "NOTIFY", - "OPTIONS", - "PATCH", - "POST", - "PROPFIND", - "PROPPATCH", - "PURGE", - "PUT", - "REPORT", - "SEARCH", - "SUBSCRIBE", - "TRACE", - "UNLOCK", - "UNSUBSCRIBE", -]; - -module.exports = { - Agent: AgentPlaceholder, - ClientRequest: ClientRequestPlaceholder, - IncomingMessage: IncomingMessagePlaceholder, - METHODS, - STATUS_CODES: {}, - Server: ServerPlaceholder, - ServerResponse: ServerResponsePlaceholder, - _checkInvalidHeaderChar(value) { - return getHttpModule()._checkInvalidHeaderChar(value); - }, - _checkIsHttpToken(value) { - return getHttpModule()._checkIsHttpToken(value); - }, - createServer(...args) { - return getHttpModule().createServer(...args); - }, - get(...args) { - return getHttpModule().get(...args); - }, - globalAgent: new AgentPlaceholder(), - maxHeaderSize: 65535, - request(...args) { - return getHttpModule().request(...args); - }, - validateHeaderName(name, label) { - return getHttpModule().validateHeaderName(name, label); - }, - validateHeaderValue(name, value) { - return getHttpModule().validateHeaderValue(name, value); - }, -}; diff --git a/crates/execution/assets/undici-shims/http2.js b/crates/execution/assets/undici-shims/http2.js deleted file mode 100644 index d6bc80355..000000000 --- a/crates/execution/assets/undici-shims/http2.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; - -const constants = { - HTTP2_HEADER_METHOD: ":method", - HTTP2_HEADER_PATH: ":path", - HTTP2_HEADER_SCHEME: ":scheme", - HTTP2_HEADER_AUTHORITY: ":authority", - HTTP2_HEADER_STATUS: ":status", - HTTP2_HEADER_CONTENT_TYPE: "content-type", - HTTP2_HEADER_CONTENT_LENGTH: "content-length", - HTTP2_HEADER_LAST_MODIFIED: "last-modified", - HTTP2_HEADER_ACCEPT: "accept", - HTTP2_HEADER_ACCEPT_ENCODING: "accept-encoding", - HTTP2_METHOD_GET: "GET", - HTTP2_METHOD_POST: "POST", - HTTP2_METHOD_PUT: "PUT", - HTTP2_METHOD_DELETE: "DELETE", - DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE: 65535, -}; - -function notImplemented(name) { - const error = new Error(`node:http2 ${name} is not available in the secure-exec bridge bootstrap`); - error.code = "ERR_NOT_IMPLEMENTED"; - throw error; -} - -function connect() { - notImplemented("connect"); -} - -function createServer() { - notImplemented("createServer"); -} - -function createSecureServer() { - notImplemented("createSecureServer"); -} - -function getDefaultSettings() { - return { - maxHeaderListSize: constants.DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE, - }; -} - -module.exports = { - constants, - connect, - createServer, - createSecureServer, - getDefaultSettings, -}; diff --git a/crates/execution/assets/undici-shims/https.js b/crates/execution/assets/undici-shims/https.js deleted file mode 100644 index a44de62f6..000000000 --- a/crates/execution/assets/undici-shims/https.js +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; - -function getHttpsModule() { - if (!globalThis._httpsModule) { - throw new Error("node:https bridge module is not available"); - } - return globalThis._httpsModule; -} - -class AgentPlaceholder {} -class ClientRequestPlaceholder {} -class IncomingMessagePlaceholder {} -class ServerPlaceholder {} -class ServerResponsePlaceholder {} - -const METHODS = [ - "CHECKOUT", - "CONNECT", - "COPY", - "DELETE", - "GET", - "HEAD", - "LOCK", - "M-SEARCH", - "MERGE", - "MKACTIVITY", - "MKCOL", - "MOVE", - "NOTIFY", - "OPTIONS", - "PATCH", - "POST", - "PROPFIND", - "PROPPATCH", - "PURGE", - "PUT", - "REPORT", - "SEARCH", - "SUBSCRIBE", - "TRACE", - "UNLOCK", - "UNSUBSCRIBE", -]; - -module.exports = { - Agent: AgentPlaceholder, - ClientRequest: ClientRequestPlaceholder, - IncomingMessage: IncomingMessagePlaceholder, - METHODS, - STATUS_CODES: {}, - Server: ServerPlaceholder, - ServerResponse: ServerResponsePlaceholder, - _checkInvalidHeaderChar(value) { - return getHttpsModule()._checkInvalidHeaderChar(value); - }, - _checkIsHttpToken(value) { - return getHttpsModule()._checkIsHttpToken(value); - }, - createServer(...args) { - return getHttpsModule().createServer(...args); - }, - get(...args) { - return getHttpsModule().get(...args); - }, - globalAgent: new AgentPlaceholder(), - maxHeaderSize: 65535, - request(...args) { - return getHttpsModule().request(...args); - }, - validateHeaderName(name, label) { - return getHttpsModule().validateHeaderName(name, label); - }, - validateHeaderValue(name, value) { - return getHttpsModule().validateHeaderValue(name, value); - }, -}; diff --git a/crates/execution/assets/undici-shims/net.js b/crates/execution/assets/undici-shims/net.js deleted file mode 100644 index d988e62d3..000000000 --- a/crates/execution/assets/undici-shims/net.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -function getNetModule() { - const mod = globalThis._netModule; - if (!mod) { - throw new Error("node:net bridge module is not available"); - } - return mod; -} - -const exported = {}; -for (const key of [ - "BlockList", - "Socket", - "SocketAddress", - "Server", - "Stream", - "connect", - "createConnection", - "createServer", - "getDefaultAutoSelectFamily", - "getDefaultAutoSelectFamilyAttemptTimeout", - "isIP", - "isIPv4", - "isIPv6", - "setDefaultAutoSelectFamily", - "setDefaultAutoSelectFamilyAttemptTimeout", -]) { - Object.defineProperty(exported, key, { - enumerable: true, - get() { - return getNetModule()[key]; - }, - }); -} - -module.exports = exported; diff --git a/crates/execution/assets/undici-shims/package.json b/crates/execution/assets/undici-shims/package.json deleted file mode 100644 index a0df0c867..000000000 --- a/crates/execution/assets/undici-shims/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "commonjs" -} diff --git a/crates/execution/assets/undici-shims/perf_hooks.js b/crates/execution/assets/undici-shims/perf_hooks.js deleted file mode 100644 index f4b560111..000000000 --- a/crates/execution/assets/undici-shims/perf_hooks.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; - -const performance = - globalThis.performance ?? - ({ - now() { - return Date.now(); - }, - timeOrigin: Date.now(), - }); - -module.exports = { performance }; diff --git a/crates/execution/assets/undici-shims/runtime-features.js b/crates/execution/assets/undici-shims/runtime-features.js deleted file mode 100644 index 79ca08b4e..000000000 --- a/crates/execution/assets/undici-shims/runtime-features.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -const knownFeatures = new Set(["crypto", "sqlite", "markAsUncloneable", "zstd"]); - -class RuntimeFeatures { - #map = new Map([ - ["crypto", true], - ["sqlite", false], - ["markAsUncloneable", false], - ["zstd", false], - ]); - - clear() { - this.#map.clear(); - } - - has(feature) { - if (!knownFeatures.has(feature)) { - throw new TypeError(`unknown feature: ${feature}`); - } - return this.#map.get(feature) ?? false; - } - - set(feature, value) { - if (!knownFeatures.has(feature)) { - throw new TypeError(`unknown feature: ${feature}`); - } - this.#map.set(feature, Boolean(value)); - } -} - -const runtimeFeatures = new RuntimeFeatures(); - -module.exports = { - runtimeFeatures, - default: runtimeFeatures, -}; diff --git a/crates/execution/assets/undici-shims/sqlite.js b/crates/execution/assets/undici-shims/sqlite.js deleted file mode 100644 index bd51c8332..000000000 --- a/crates/execution/assets/undici-shims/sqlite.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; - -const error = new Error("No such built-in module: node:sqlite"); -error.code = "ERR_UNKNOWN_BUILTIN_MODULE"; -throw error; diff --git a/crates/execution/assets/undici-shims/stream.js b/crates/execution/assets/undici-shims/stream.js deleted file mode 100644 index 78f074f27..000000000 --- a/crates/execution/assets/undici-shims/stream.js +++ /dev/null @@ -1,121 +0,0 @@ -"use strict"; - -import streamDefault, * as streamNs from "secure-exec-stream-stdlib"; - -const baseStreamModule = streamNs.default ?? streamDefault ?? {}; -const baseFinished = streamNs.finished ?? baseStreamModule.finished; - -const isWebReadableStream = (stream) => - Boolean(stream) && - typeof stream.getReader === "function" && - typeof stream.cancel === "function"; - -const isWebWritableStream = (stream) => - Boolean(stream) && - typeof stream.getWriter === "function" && - typeof stream.abort === "function"; - -const normalizeStreamError = (value) => { - if (value instanceof Error) { - return value; - } - if (value == null) { - return new Error("stream errored"); - } - return new Error(String(value)); -}; - -export const finished = (stream, options, callback) => { - let normalizedOptions = options; - let normalizedCallback = callback; - if (typeof normalizedOptions === "function") { - normalizedCallback = normalizedOptions; - normalizedOptions = {}; - } - if ( - !isWebReadableStream(stream) && - !isWebWritableStream(stream) && - typeof baseFinished === "function" - ) { - return baseFinished(stream, normalizedOptions, normalizedCallback); - } - - const done = - typeof normalizedCallback === "function" ? normalizedCallback : () => {}; - const readableEnabled = normalizedOptions?.readable !== false; - const writableEnabled = normalizedOptions?.writable !== false; - let cancelled = false; - let timer = null; - - const cleanup = () => { - cancelled = true; - if (timer !== null) { - clearTimeout(timer); - timer = null; - } - }; - - const complete = (error = undefined) => { - if (cancelled) { - return; - } - cleanup(); - queueMicrotask(() => done(error)); - }; - - const poll = () => { - if (cancelled) { - return; - } - const state = stream?._state; - if (state === "errored") { - complete(normalizeStreamError(stream?._storedError)); - return; - } - if ( - state === "closed" || - (isWebReadableStream(stream) && !readableEnabled) || - (isWebWritableStream(stream) && !writableEnabled) - ) { - complete(); - return; - } - timer = setTimeout(poll, 0); - }; - - poll(); - return cleanup; -}; - -export const isReadable = (stream) => { - if (isWebReadableStream(stream)) { - return stream._state === "readable"; - } - return Boolean(stream) && stream.readable !== false && stream.destroyed !== true; -}; - -export const isErrored = (stream) => { - if (isWebReadableStream(stream) || isWebWritableStream(stream)) { - return stream?._state === "errored"; - } - return stream?.errored != null; -}; - -export const isDisturbed = (stream) => { - return Boolean( - stream?.locked || - stream?.disturbed === true || - stream?._disturbed === true || - stream?.readableDidRead === true, - ); -}; - -export * from "secure-exec-stream-stdlib"; - -export default { - ...baseStreamModule, - finished, - isReadable, - isErrored, - isDisturbed, -}; diff --git a/crates/execution/assets/undici-shims/tls.js b/crates/execution/assets/undici-shims/tls.js deleted file mode 100644 index 8ca250b59..000000000 --- a/crates/execution/assets/undici-shims/tls.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; - -function getTlsModule() { - const mod = globalThis._tlsModule; - if (!mod) { - throw new Error("node:tls bridge module is not available"); - } - return mod; -} - -const exported = {}; -for (const key of [ - "connect", - "createServer", - "createSecureContext", - "TLSSocket", - "Server", - "checkServerIdentity", - "getCiphers", - "rootCertificates", -]) { - Object.defineProperty(exported, key, { - enumerable: true, - get() { - return getTlsModule()[key]; - }, - }); -} - -module.exports = exported; diff --git a/crates/execution/assets/undici-shims/util-types.js b/crates/execution/assets/undici-shims/util-types.js deleted file mode 100644 index 5e1cc4d26..000000000 --- a/crates/execution/assets/undici-shims/util-types.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; - -function isArrayBuffer(value) { - return value instanceof ArrayBuffer; -} - -function isArrayBufferView(value) { - return ArrayBuffer.isView(value); -} - -function isUint8Array(value) { - return value instanceof Uint8Array; -} - -function isProxy(_value) { - return false; -} - -module.exports = { - isArrayBuffer, - isArrayBufferView, - isProxy, - isUint8Array, -}; diff --git a/crates/execution/assets/undici-shims/web-streams-global.js b/crates/execution/assets/undici-shims/web-streams-global.js deleted file mode 100644 index ef925278b..000000000 --- a/crates/execution/assets/undici-shims/web-streams-global.js +++ /dev/null @@ -1,81 +0,0 @@ -"use strict"; - -import { - ReadableStream as WebReadableStream, - WritableStream as WebWritableStream, - TransformStream as WebTransformStream, -} from "web-streams-polyfill/ponyfill/es2018"; - -class FallbackTextEncoderStream { - constructor() { - const encoder = new globalThis.TextEncoder(); - const stream = new WebTransformStream({ - transform(chunk, controller) { - controller.enqueue(encoder.encode(chunk)); - }, - }); - - this.encoding = "utf-8"; - this.readable = stream.readable; - this.writable = stream.writable; - } -} - -class FallbackTextDecoderStream { - constructor(label = "utf-8", options = undefined) { - const decoder = new globalThis.TextDecoder(label, options); - const stream = new WebTransformStream({ - transform(chunk, controller) { - const text = decoder.decode(chunk, { stream: true }); - if (text.length > 0) { - controller.enqueue(text); - } - }, - flush(controller) { - const text = decoder.decode(); - if (text.length > 0) { - controller.enqueue(text); - } - }, - }); - - this.encoding = decoder.encoding; - this.fatal = decoder.fatal; - this.ignoreBOM = decoder.ignoreBOM; - this.readable = stream.readable; - this.writable = stream.writable; - } -} - -const WebTextEncoderStream = - typeof globalThis.TextEncoderStream === "function" - ? globalThis.TextEncoderStream - : FallbackTextEncoderStream; -const WebTextDecoderStream = - typeof globalThis.TextDecoderStream === "function" - ? globalThis.TextDecoderStream - : FallbackTextDecoderStream; - -if (typeof globalThis.ReadableStream === "undefined") { - globalThis.ReadableStream = WebReadableStream; -} -if (typeof globalThis.WritableStream === "undefined") { - globalThis.WritableStream = WebWritableStream; -} -if (typeof globalThis.TransformStream === "undefined") { - globalThis.TransformStream = WebTransformStream; -} -if (typeof globalThis.TextEncoderStream === "undefined") { - globalThis.TextEncoderStream = WebTextEncoderStream; -} -if (typeof globalThis.TextDecoderStream === "undefined") { - globalThis.TextDecoderStream = WebTextDecoderStream; -} - -export { - WebReadableStream, - WebWritableStream, - WebTransformStream, - WebTextEncoderStream, - WebTextDecoderStream, -}; diff --git a/crates/execution/assets/undici-shims/worker_threads.js b/crates/execution/assets/undici-shims/worker_threads.js deleted file mode 100644 index 9a4dddfd9..000000000 --- a/crates/execution/assets/undici-shims/worker_threads.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; - -module.exports = { - isMainThread: true, - parentPort: null, - workerData: null, -}; diff --git a/crates/execution/assets/undici-shims/zlib.js b/crates/execution/assets/undici-shims/zlib.js deleted file mode 100644 index 3af356f1b..000000000 --- a/crates/execution/assets/undici-shims/zlib.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; - -function getZlibModule() { - const mod = globalThis.__secureExecBuiltinZlibModule; - if (!mod) { - throw new Error("node:zlib bridge module is not available"); - } - return mod; -} - -module.exports = new Proxy( - {}, - { - get(_target, property) { - return getZlibModule()[property]; - }, - has(_target, property) { - return property in getZlibModule(); - }, - ownKeys() { - return Reflect.ownKeys(getZlibModule()); - }, - getOwnPropertyDescriptor(_target, property) { - const descriptor = Object.getOwnPropertyDescriptor(getZlibModule(), property); - if (descriptor) { - return descriptor; - } - return { - configurable: true, - enumerable: true, - value: undefined, - writable: false, - }; - }, - }, -); diff --git a/crates/execution/assets/wasi-preview1-imports.json b/crates/execution/assets/wasi-preview1-imports.json deleted file mode 100644 index 1aaaa4131..000000000 --- a/crates/execution/assets/wasi-preview1-imports.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - "args_get", - "args_sizes_get", - "clock_res_get", - "clock_time_get", - "environ_get", - "environ_sizes_get", - "fd_close", - "fd_fdstat_get", - "fd_fdstat_set_flags", - "fd_filestat_get", - "fd_filestat_set_size", - "fd_pread", - "fd_prestat_dir_name", - "fd_prestat_get", - "fd_pwrite", - "fd_read", - "fd_readdir", - "fd_seek", - "fd_sync", - "fd_tell", - "fd_write", - "path_create_directory", - "path_filestat_get", - "path_link", - "path_open", - "path_readlink", - "path_remove_directory", - "path_rename", - "path_symlink", - "path_unlink_file", - "poll_oneoff", - "proc_exit", - "random_get", - "sched_yield" -] diff --git a/crates/execution/benchmarks/node-import-baseline.md b/crates/execution/benchmarks/node-import-baseline.md deleted file mode 100644 index 4a86d8817..000000000 --- a/crates/execution/benchmarks/node-import-baseline.md +++ /dev/null @@ -1,55 +0,0 @@ -# secure-exec Node Import Benchmark - -- Generated at unix ms: `1775118070728` -- Node binary: `node` -- Node version: `v24.13.0` -- Host: `linux` / `x86_64` / `20` logical CPUs -- Repo root: `/home/nathan/a5` -- Iterations: `5` recorded, `1` warmup -- Reproduce: `cargo run -p secure-exec-execution --bin node-import-bench -- --iterations 5 --warmup-iterations 1` - -| Scenario | Fixture | Cache | Mean wall (ms) | P50 | P95 | Mean import (ms) | Mean startup overhead (ms) | -| --- | --- | --- | ---: | ---: | ---: | ---: | ---: | -| `isolate-startup` | empty entrypoint | disabled | 17.17 | 16.11 | 20.98 | n/a | n/a | -| `cold-local-import` | 24-module local ESM graph | disabled | 19.76 | 18.61 | 22.76 | 2.06 | 17.69 | -| `warm-local-import` | 24-module local ESM graph | primed | 18.84 | 19.00 | 19.52 | 1.89 | 16.95 | -| `builtin-import` | node:path + node:url + node:fs/promises | disabled | 17.89 | 17.13 | 20.14 | 0.84 | 17.05 | -| `large-package-import` | typescript | disabled | 206.93 | 207.47 | 215.58 | 189.49 | 17.44 | - -## Hotspot Guidance - -- Compile-cache reuse cuts the local import graph from 2.06 to 1.89 on average (8.6% faster), but the warm path still spends 16.95 outside guest module evaluation. That keeps startup prewarm work in `ARC-021D` and sidecar warm-pool/snapshot work in `ARC-022` on the critical path above the `17.17` empty-isolate floor. -- Warm local imports still spend 90.0% of wall time in process startup, wrapper evaluation, and stdio handling instead of guest import work. Optimizations that only touch module compilation will not remove that floor. -- The large real-world package import (`typescript`) is 225.7x the builtin path (189.49 versus 0.84). That makes `ARC-021C` the right next import-path optimization story: cache sidecar-scoped resolution results, package-type lookups, and module-format classification before attempting deeper structural rewrites. -- No new PRD stories were added from this run. The measured hotspots already map cleanly onto existing follow-ons: `ARC-021C` for safe resolution and metadata caches, `ARC-021D` for builtin/polyfill prewarm, and `ARC-022` for broader warm-pool and timing-mitigation execution work. - -## Raw Samples - -### `isolate-startup` -- Description: Minimal guest with no extra imports. Measures the current startup floor for create-context plus node process bootstrap. -- Wall samples (ms): [20.98, 17.24, 15.76, 15.74, 16.11] - -### `cold-local-import` -- Description: Cold import of a repo-local ESM graph that simulates layered application modules without compile-cache reuse. -- Wall samples (ms): [18.16, 18.09, 18.61, 21.16, 22.76] -- Guest import samples (ms): [2.09, 2.03, 1.96, 2.24, 2.00] -- Startup overhead samples (ms): [16.07, 16.06, 16.65, 18.92, 20.75] - -### `warm-local-import` -- Description: Warm import of the same local ESM graph after a compile-cache priming pass in an earlier isolate. -- Wall samples (ms): [19.00, 19.52, 19.01, 18.00, 18.65] -- Guest import samples (ms): [1.78, 1.91, 1.87, 2.02, 1.84] -- Startup overhead samples (ms): [17.22, 17.61, 17.14, 15.98, 16.81] - -### `builtin-import` -- Description: Import of the common builtin path used by the wrappers and polyfill-adjacent bootstrap code. -- Wall samples (ms): [20.14, 17.13, 16.58, 15.79, 19.81] -- Guest import samples (ms): [0.85, 0.85, 0.86, 0.83, 0.82] -- Startup overhead samples (ms): [19.29, 16.29, 15.73, 14.97, 18.99] - -### `large-package-import` -- Description: Cold import of the real-world `typescript` package from the workspace root `node_modules` tree. -- Wall samples (ms): [207.96, 203.42, 215.58, 200.22, 207.47] -- Guest import samples (ms): [190.64, 186.51, 198.01, 182.53, 189.76] -- Startup overhead samples (ms): [17.32, 16.91, 17.57, 17.69, 17.71] - diff --git a/crates/execution/build.rs b/crates/execution/build.rs deleted file mode 100644 index c3a30933a..000000000 --- a/crates/execution/build.rs +++ /dev/null @@ -1,99 +0,0 @@ -use std::env; -use std::fs; -use std::path::{Path, PathBuf}; - -/// Large Pyodide runtime assets are excluded from the published crate (see the -/// `exclude` list in Cargo.toml) to keep it under the registry size limit. -/// During in-tree (workspace) builds they are copied from `assets/pyodide/`. -/// -/// When building the published crate (the unpacked tarball, where these assets -/// are absent) Python support is built WITHOUT the externalized Pyodide assets: -/// each missing asset is staged as an empty placeholder so the `include_bytes!` -/// of the OUT_DIR copy still compiles, and the `secure_exec_pyodide_unavailable` -/// cfg is set so the runtime reports Python as unavailable instead of trying to -/// boot an incomplete Pyodide. This keeps `cargo publish` verification free of -/// any CDN/network dependency. Python support remains fully functional in the -/// workspace build where the in-tree assets exist. -const EXTERNALIZED_PYODIDE_ASSETS: &[&str] = &[ - "pyodide.asm.wasm", - "pyodide.asm.js", - "python_stdlib.zip", - "numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl", - "pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl", -]; - -fn main() { - let manifest_dir = - PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set")); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR must be set")); - - println!("cargo:rerun-if-changed=build.rs"); - // Declare the cfg used to gate Python availability so `cargo` does not warn - // about an unexpected cfg name. - println!("cargo:rustc-check-cfg=cfg(secure_exec_pyodide_unavailable)"); - secure_exec_build_support::build_v8_bridge(&manifest_dir, &out_dir); - stage_pyodide_assets(&manifest_dir, &out_dir); -} - -fn stage_pyodide_assets(manifest_dir: &Path, out_dir: &Path) { - let pyodide_out = out_dir.join("pyodide"); - fs::create_dir_all(&pyodide_out).unwrap_or_else(|error| { - panic!( - "failed to create pyodide staging dir {}: {}", - pyodide_out.display(), - error - ) - }); - - let mut pyodide_unavailable = false; - - for asset in EXTERNALIZED_PYODIDE_ASSETS { - let in_tree = manifest_dir.join("assets/pyodide").join(asset); - let dest = pyodide_out.join(asset); - println!("cargo:rerun-if-changed={}", in_tree.display()); - - if dest.exists() && !is_placeholder(&dest) { - continue; - } - - if in_tree.exists() { - fs::copy(&in_tree, &dest).unwrap_or_else(|error| { - panic!( - "failed to copy pyodide asset {} to {}: {}", - in_tree.display(), - dest.display(), - error - ) - }); - } else { - // Published-crate build: the externalized asset is absent and there - // is no CDN dependency. Stage an empty placeholder so `include_bytes!` - // compiles, and mark Python as unavailable for this build. - pyodide_unavailable = true; - fs::write(&dest, b"").unwrap_or_else(|error| { - panic!( - "failed to write pyodide placeholder {}: {}", - dest.display(), - error - ) - }); - } - } - - if pyodide_unavailable { - println!("cargo:rustc-cfg=secure_exec_pyodide_unavailable"); - println!( - "cargo:warning=secure-exec-execution: building without bundled Pyodide assets; \ - guest Python execution will be unavailable in this build." - ); - } -} - -/// A zero-byte staged asset is a placeholder written by a prior published-crate -/// build; treat it as missing so a later workspace build can replace it with the -/// real in-tree asset. -fn is_placeholder(path: &Path) -> bool { - fs::metadata(path) - .map(|meta| meta.len() == 0) - .unwrap_or(false) -} diff --git a/crates/execution/src/benchmark.rs b/crates/execution/src/benchmark.rs deleted file mode 100644 index 7d0076a49..000000000 --- a/crates/execution/src/benchmark.rs +++ /dev/null @@ -1,3590 +0,0 @@ -use crate::{ - CreateJavascriptContextRequest, JavascriptExecutionEngine, JavascriptExecutionError, - StartJavascriptExecutionRequest, -}; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -use std::env; -use std::fmt; -use std::fmt::Write as _; -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; - -const BENCHMARK_MARKER_PREFIX: &str = "__AGENTOS_BENCH__:"; -const LOCAL_GRAPH_MODULE_COUNT: usize = 24; -const BENCHMARK_ARTIFACT_VERSION: u32 = 5; -const BENCHMARK_ARTIFACT_DIR: &str = "target/benchmark-reports/node-import-bench"; -const BENCHMARK_RUN_STATE_FILE: &str = "run-state.json"; -const TRANSPORT_RTT_CHANNEL: &str = "execution-stdio-echo"; -const TRANSPORT_RTT_PAYLOAD_BYTES: [usize; 3] = [32, 4 * 1024, 64 * 1024]; -const TRANSPORT_POLL_TIMEOUT: Duration = Duration::from_secs(5); -const MAX_BENCHMARK_ITERATIONS: usize = 1_000; -const MAX_BENCHMARK_WARMUP_ITERATIONS: usize = 1_000; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct JavascriptBenchmarkConfig { - pub iterations: usize, - pub warmup_iterations: usize, -} - -impl Default for JavascriptBenchmarkConfig { - fn default() -> Self { - Self { - iterations: 5, - warmup_iterations: 1, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] -pub struct BenchmarkHost { - pub node_binary: String, - pub node_version: String, - pub os: &'static str, - pub arch: &'static str, - pub logical_cpus: usize, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct BenchmarkScenarioPhases { - pub context_setup_ms: T, - pub startup_ms: T, - #[serde(skip_serializing_if = "Option::is_none", default)] - pub guest_execution_ms: Option, - pub completion_ms: T, -} - -#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)] -pub struct BenchmarkStats { - pub mean_ms: f64, - pub p50_ms: f64, - pub p95_ms: f64, - pub min_ms: f64, - pub max_ms: f64, - pub stddev_ms: f64, -} - -#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)] -pub struct BenchmarkDistributionStats { - pub mean: f64, - pub p50: f64, - pub p95: f64, - pub min: f64, - pub max: f64, - pub stddev: f64, -} - -#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)] -pub struct BenchmarkResourceUsage { - #[serde(skip_serializing_if = "Option::is_none", default)] - pub rss_bytes: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - pub heap_used_bytes: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - pub cpu_user_us: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - pub cpu_system_us: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - pub cpu_total_us: Option, -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub struct BenchmarkTransportRttReport { - pub channel: &'static str, - pub payload_bytes: usize, - pub samples_ms: Vec, - pub stats: BenchmarkStats, -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub struct BenchmarkScenarioReport { - pub id: &'static str, - pub workload: &'static str, - pub runtime: &'static str, - pub mode: &'static str, - pub description: &'static str, - pub fixture: &'static str, - pub compile_cache: &'static str, - pub wall_samples_ms: Vec, - pub wall_stats: BenchmarkStats, - pub guest_import_samples_ms: Option>, - pub guest_import_stats: Option, - pub startup_overhead_samples_ms: Option>, - pub startup_overhead_stats: Option, - pub phase_samples_ms: BenchmarkScenarioPhases>, - pub phase_stats: BenchmarkScenarioPhases, - #[serde(skip_serializing_if = "Option::is_none", default)] - pub resource_usage_samples: Option>>, - #[serde(skip_serializing_if = "Option::is_none", default)] - pub resource_usage_stats: Option>, -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub struct JavascriptBenchmarkReport { - pub generated_at_unix_ms: u128, - pub config: JavascriptBenchmarkConfig, - pub host: BenchmarkHost, - pub repo_root: PathBuf, - pub transport_rtt: Vec, - pub scenarios: Vec, -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub struct BenchmarkComparison { - pub baseline: BenchmarkComparisonBaseline, - pub summary: BenchmarkComparisonSummary, - pub scenario_deltas: Vec, - pub scenarios_missing_from_baseline: Vec, - pub baseline_only_scenarios: Vec, -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub struct BenchmarkComparisonBaseline { - pub artifact_version: u32, - pub generated_at_unix_ms: u128, - pub path: PathBuf, -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub struct BenchmarkComparisonSummary { - pub compared_scenario_count: usize, - #[serde(skip_serializing_if = "Option::is_none")] - pub largest_wall_improvement: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub largest_wall_regression: Option, -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub struct BenchmarkDeltaHighlight { - pub id: String, - pub delta_ms: f64, - pub delta_pct: f64, -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub struct BenchmarkScenarioDelta { - pub id: String, - pub description: String, - pub wall_mean_ms: BenchmarkMetricDelta, - #[serde(skip_serializing_if = "Option::is_none")] - pub guest_import_mean_ms: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub startup_overhead_mean_ms: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub phase_mean_ms: Option>, -} - -#[derive(Debug, Clone, PartialEq, Serialize)] -pub struct BenchmarkMetricDelta { - pub baseline_ms: f64, - pub current_ms: f64, - pub delta_ms: f64, - pub delta_pct: f64, -} - -impl JavascriptBenchmarkReport { - pub fn render_markdown(&self) -> String { - self.render_markdown_with_comparison(None) - } - - pub fn render_markdown_with_comparison( - &self, - comparison: Option<&BenchmarkComparison>, - ) -> String { - let mut markdown = String::new(); - let _ = writeln!(&mut markdown, "# secure-exec Node Import Benchmark"); - let _ = writeln!(&mut markdown); - let _ = writeln!( - &mut markdown, - "- Generated at unix ms: `{}`", - self.generated_at_unix_ms - ); - let _ = writeln!(&mut markdown, "- Node binary: `{}`", self.host.node_binary); - let _ = writeln!( - &mut markdown, - "- Node version: `{}`", - self.host.node_version.trim() - ); - let _ = writeln!( - &mut markdown, - "- Host: `{}` / `{}` / `{}` logical CPUs", - self.host.os, self.host.arch, self.host.logical_cpus - ); - let _ = writeln!(&mut markdown, "- Repo root: `{}`", self.repo_root.display()); - let _ = writeln!( - &mut markdown, - "- Iterations: `{}` recorded, `{}` warmup", - self.config.iterations, self.config.warmup_iterations - ); - let _ = writeln!( - &mut markdown, - "- Reproduce: `cargo run -p secure-exec-execution --bin node-import-bench -- --iterations {} --warmup-iterations {}`", - self.config.iterations, self.config.warmup_iterations - ); - let _ = writeln!(&mut markdown); - let _ = writeln!(&mut markdown, "## Transport RTT"); - let _ = writeln!(&mut markdown); - let _ = writeln!( - &mut markdown, - "| Channel | Payload (bytes) | Mean RTT (ms) | P50 | P95 |" - ); - let _ = writeln!(&mut markdown, "| --- | ---: | ---: | ---: | ---: |"); - - for transport in &self.transport_rtt { - let _ = writeln!( - &mut markdown, - "| `{}` | {} | {} | {} | {} |", - transport.channel, - transport.payload_bytes, - format_ms(transport.stats.mean_ms), - format_ms(transport.stats.p50_ms), - format_ms(transport.stats.p95_ms), - ); - } - - let _ = writeln!(&mut markdown, "## Control Matrix"); - let _ = writeln!(&mut markdown); - - for row in self.control_matrix() { - let _ = writeln!( - &mut markdown, - "- Workload `{}`: runtimes {}, modes {}, scenarios {}", - row.workload, - format_label_list(&row.runtimes), - format_label_list(&row.modes), - format_label_list(&row.scenario_ids), - ); - } - - let _ = writeln!(&mut markdown); - let _ = writeln!(&mut markdown, "## Scenario Summary"); - let _ = writeln!(&mut markdown); - let _ = writeln!( - &mut markdown, - "| Scenario | Workload | Runtime | Mode | Fixture | Cache | Mean wall (ms) | Mean context (ms) | Mean startup (ms) | Mean guest exec (ms) | Mean completion (ms) | Mean startup overhead (ms) |" - ); - let _ = writeln!( - &mut markdown, - "| --- | --- | --- | --- | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: |" - ); - - for scenario in &self.scenarios { - let guest_execution_mean = scenario - .phase_stats - .guest_execution_ms - .as_ref() - .map(|stats| format_ms(stats.mean_ms)) - .unwrap_or_else(|| String::from("n/a")); - let startup_overhead_mean = scenario - .startup_overhead_stats - .as_ref() - .map(|stats| format_ms(stats.mean_ms)) - .unwrap_or_else(|| String::from("n/a")); - - let _ = writeln!( - &mut markdown, - "| `{}` | `{}` | `{}` | `{}` | {} | {} | {} | {} | {} | {} | {} | {} |", - scenario.id, - scenario.workload, - scenario.runtime, - scenario.mode, - scenario.fixture, - scenario.compile_cache, - format_ms(scenario.wall_stats.mean_ms), - format_ms(scenario.phase_stats.context_setup_ms.mean_ms), - format_ms(scenario.phase_stats.startup_ms.mean_ms), - guest_execution_mean, - format_ms(scenario.phase_stats.completion_ms.mean_ms), - startup_overhead_mean, - ); - } - - let _ = writeln!(&mut markdown); - let _ = writeln!(&mut markdown, "## Stability And Resource Summary"); - let _ = writeln!(&mut markdown); - let _ = writeln!( - &mut markdown, - "| Scenario | Wall P50 (ms) | Wall min-max (ms) | Wall stddev (ms) | Mean RSS (MiB) | Mean heap (MiB) | Mean total CPU (ms) |" - ); - let _ = writeln!( - &mut markdown, - "| --- | ---: | --- | ---: | ---: | ---: | ---: |" - ); - - for scenario in &self.scenarios { - let _ = writeln!( - &mut markdown, - "| `{}` | {} | {}-{} | {} | {} | {} | {} |", - scenario.id, - format_ms(scenario.wall_stats.p50_ms), - format_ms(scenario.wall_stats.min_ms), - format_ms(scenario.wall_stats.max_ms), - format_ms(scenario.wall_stats.stddev_ms), - scenario - .resource_usage_stats - .as_ref() - .and_then(|stats| stats.rss_bytes.as_ref()) - .map(|stats| format_mib(bytes_to_mib(stats.mean))) - .unwrap_or_else(|| String::from("n/a")), - scenario - .resource_usage_stats - .as_ref() - .and_then(|stats| stats.heap_used_bytes.as_ref()) - .map(|stats| format_mib(bytes_to_mib(stats.mean))) - .unwrap_or_else(|| String::from("n/a")), - scenario - .resource_usage_stats - .as_ref() - .and_then(|stats| stats.cpu_total_us.as_ref()) - .map(|stats| format_ms(micros_to_ms(stats.mean))) - .unwrap_or_else(|| String::from("n/a")), - ); - } - - let _ = writeln!(&mut markdown); - let _ = writeln!(&mut markdown, "## Ranked Hotspots"); - let _ = writeln!(&mut markdown); - - for ranking in self.hotspot_rankings() { - let _ = writeln!( - &mut markdown, - "### {} (`{}`, `{}`)", - ranking.label, ranking.dimension, ranking.unit - ); - let _ = writeln!(&mut markdown); - let _ = writeln!( - &mut markdown, - "| Rank | Scenario | Workload | Runtime | Mode | Value |" - ); - let _ = writeln!(&mut markdown, "| ---: | --- | --- | --- | --- | ---: |"); - - for scenario in &ranking.ranked_scenarios { - let _ = writeln!( - &mut markdown, - "| {} | `{}` | `{}` | `{}` | `{}` | {} |", - scenario.rank, - scenario.id, - scenario.workload, - scenario.runtime, - scenario.mode, - format_hotspot_value(ranking.unit, scenario.value), - ); - } - - if !ranking.scenarios_without_metric.is_empty() { - let _ = writeln!(&mut markdown); - let _ = writeln!( - &mut markdown, - "Missing metric for: {}", - format_string_label_list(&ranking.scenarios_without_metric), - ); - } - - let _ = writeln!(&mut markdown); - } - - let _ = writeln!(&mut markdown, "## Hotspot Guidance"); - let _ = writeln!(&mut markdown); - - for line in self.guidance_lines() { - let _ = writeln!(&mut markdown, "- {line}"); - } - - if let Some(comparison) = comparison { - let _ = writeln!(&mut markdown); - let _ = writeln!(&mut markdown, "## Baseline Comparison"); - let _ = writeln!(&mut markdown); - let _ = writeln!( - &mut markdown, - "- Baseline artifact: `{}`", - comparison.baseline.path.display() - ); - let _ = writeln!( - &mut markdown, - "- Baseline generated at unix ms: `{}`", - comparison.baseline.generated_at_unix_ms - ); - let _ = writeln!( - &mut markdown, - "- Compared scenarios: `{}`", - comparison.summary.compared_scenario_count - ); - if let Some(improvement) = &comparison.summary.largest_wall_improvement { - let _ = writeln!( - &mut markdown, - "- Largest wall-time improvement: `{}` at {} ({})", - improvement.id, - format_delta_ms(improvement.delta_ms), - format_delta_pct(improvement.delta_pct), - ); - } - if let Some(regression) = &comparison.summary.largest_wall_regression { - let _ = writeln!( - &mut markdown, - "- Largest wall-time regression: `{}` at {} ({})", - regression.id, - format_delta_ms(regression.delta_ms), - format_delta_pct(regression.delta_pct), - ); - } - if !comparison.scenarios_missing_from_baseline.is_empty() { - let _ = writeln!( - &mut markdown, - "- Scenarios missing from baseline: {}", - comparison.scenarios_missing_from_baseline.join(", ") - ); - } - if !comparison.baseline_only_scenarios.is_empty() { - let _ = writeln!( - &mut markdown, - "- Baseline-only scenarios: {}", - comparison.baseline_only_scenarios.join(", ") - ); - } - let _ = writeln!(&mut markdown); - let _ = writeln!( - &mut markdown, - "| Scenario | Wall delta (ms) | Wall delta % | Import delta (ms) | Startup delta (ms) | Context delta (ms) | Completion delta (ms) |" - ); - let _ = writeln!( - &mut markdown, - "| --- | ---: | ---: | ---: | ---: | ---: | ---: |" - ); - - for scenario in &comparison.scenario_deltas { - let import_delta = scenario - .guest_import_mean_ms - .as_ref() - .map(|delta| format_delta_ms(delta.delta_ms)) - .unwrap_or_else(|| String::from("n/a")); - let startup_delta = scenario - .startup_overhead_mean_ms - .as_ref() - .map(|delta| format_delta_ms(delta.delta_ms)) - .unwrap_or_else(|| String::from("n/a")); - let context_delta = scenario - .phase_mean_ms - .as_ref() - .map(|delta| format_delta_ms(delta.context_setup_ms.delta_ms)) - .unwrap_or_else(|| String::from("n/a")); - let completion_delta = scenario - .phase_mean_ms - .as_ref() - .map(|delta| format_delta_ms(delta.completion_ms.delta_ms)) - .unwrap_or_else(|| String::from("n/a")); - - let _ = writeln!( - &mut markdown, - "| `{}` | {} | {} | {} | {} | {} | {} |", - scenario.id, - format_delta_ms(scenario.wall_mean_ms.delta_ms), - format_delta_pct(scenario.wall_mean_ms.delta_pct), - import_delta, - startup_delta, - context_delta, - completion_delta, - ); - } - } - - let _ = writeln!(&mut markdown); - let _ = writeln!(&mut markdown, "## Raw Samples"); - let _ = writeln!(&mut markdown); - - for scenario in &self.scenarios { - let _ = writeln!(&mut markdown, "### `{}`", scenario.id); - let _ = writeln!(&mut markdown, "- Workload: `{}`", scenario.workload); - let _ = writeln!(&mut markdown, "- Runtime: `{}`", scenario.runtime); - let _ = writeln!(&mut markdown, "- Mode: `{}`", scenario.mode); - let _ = writeln!(&mut markdown, "- Description: {}", scenario.description); - let _ = writeln!( - &mut markdown, - "- Wall samples (ms): {}", - format_sample_list(&scenario.wall_samples_ms) - ); - if let Some(samples) = &scenario.guest_import_samples_ms { - let _ = writeln!( - &mut markdown, - "- Guest import samples (ms): {}", - format_sample_list(samples) - ); - } - if let Some(samples) = &scenario.startup_overhead_samples_ms { - let _ = writeln!( - &mut markdown, - "- Startup overhead samples (ms): {}", - format_sample_list(samples) - ); - } - let _ = writeln!( - &mut markdown, - "- Context setup samples (ms): {}", - format_sample_list(&scenario.phase_samples_ms.context_setup_ms) - ); - let _ = writeln!( - &mut markdown, - "- Startup samples (ms): {}", - format_sample_list(&scenario.phase_samples_ms.startup_ms) - ); - if let Some(samples) = &scenario.phase_samples_ms.guest_execution_ms { - let _ = writeln!( - &mut markdown, - "- Guest execution samples (ms): {}", - format_sample_list(samples) - ); - } - let _ = writeln!( - &mut markdown, - "- Completion samples (ms): {}", - format_sample_list(&scenario.phase_samples_ms.completion_ms) - ); - if let Some(samples) = &scenario.resource_usage_samples { - if let Some(rss_samples) = &samples.rss_bytes { - let _ = writeln!( - &mut markdown, - "- RSS samples (MiB): {}", - format_scaled_sample_list(rss_samples, bytes_to_mib) - ); - } - if let Some(heap_samples) = &samples.heap_used_bytes { - let _ = writeln!( - &mut markdown, - "- Heap samples (MiB): {}", - format_scaled_sample_list(heap_samples, bytes_to_mib) - ); - } - if let Some(cpu_samples) = &samples.cpu_total_us { - let _ = writeln!( - &mut markdown, - "- Total CPU samples (ms): {}", - format_scaled_sample_list(cpu_samples, micros_to_ms) - ); - } - } - let _ = writeln!(&mut markdown); - } - - markdown - } - - pub fn render_json(&self) -> Result { - self.render_json_with_comparison(None) - } - - pub fn render_json_with_comparison( - &self, - comparison: Option<&BenchmarkComparison>, - ) -> Result { - serde_json::to_string_pretty(&self.json_artifact(comparison)) - } - - pub fn write_artifacts( - &self, - output_dir: &Path, - ) -> Result { - self.write_artifacts_with_comparison(output_dir, None) - } - - pub fn write_artifacts_with_comparison( - &self, - output_dir: &Path, - comparison: Option<&BenchmarkComparison>, - ) -> Result { - fs::create_dir_all(output_dir)?; - - let markdown_path = output_dir.join("report.md"); - let json_path = output_dir.join("report.json"); - write_string_atomic( - &markdown_path, - &self.render_markdown_with_comparison(comparison), - )?; - write_string_atomic(&json_path, &self.render_json_with_comparison(comparison)?)?; - - Ok(JavascriptBenchmarkArtifactPaths { - markdown_path, - json_path, - }) - } - - pub fn compare_to_baseline_path( - &self, - baseline_path: &Path, - ) -> Result { - let baseline = load_benchmark_artifact(baseline_path)?; - Ok(BenchmarkComparison::from_reports( - self, - baseline_path, - &baseline, - )) - } - - fn guidance_lines(&self) -> Vec { - let isolate = self.scenario("isolate-startup"); - let cold_local = self.scenario("cold-local-import"); - let warm_local = self.scenario("warm-local-import"); - let prewarmed_local = self.scenario("prewarmed-local-import"); - let builtin = self.scenario("builtin-import"); - let large = self.scenario("large-package-import"); - - let mut guidance = Vec::new(); - - if let ( - Some(cold_import), - Some(warm_import), - Some(warm_context), - Some(warm_startup_phase), - Some(warm_completion), - Some(warm_startup_overhead), - Some(warm_wall), - Some(isolate_wall), - ) = ( - cold_local - .and_then(|scenario| scenario.guest_import_stats.as_ref()) - .map(|stats| stats.mean_ms), - warm_local - .and_then(|scenario| scenario.guest_import_stats.as_ref()) - .map(|stats| stats.mean_ms), - warm_local.map(|scenario| scenario.phase_stats.context_setup_ms.mean_ms), - warm_local.map(|scenario| scenario.phase_stats.startup_ms.mean_ms), - warm_local.map(|scenario| scenario.phase_stats.completion_ms.mean_ms), - warm_local - .and_then(|scenario| scenario.startup_overhead_stats.as_ref()) - .map(|stats| stats.mean_ms), - warm_local.map(|scenario| scenario.wall_stats.mean_ms), - isolate.map(|scenario| scenario.wall_stats.mean_ms), - ) { - guidance.push(format!( - "Compile-cache reuse cuts the local import graph from {} to {} on average ({:.1}% faster), but the warm path still spends {} outside guest module evaluation. That keeps startup prewarm work in `ARC-021D` and sidecar warm-pool/snapshot work in `ARC-022` on the critical path above the `{}` empty-isolate floor.", - format_ms(cold_import), - format_ms(warm_import), - percentage_reduction(cold_import, warm_import), - format_ms(warm_startup_overhead), - format_ms(isolate_wall), - )); - if warm_wall > 0.0 { - guidance.push(format!( - "Warm local imports still spend {:.1}% of wall time in process startup, wrapper evaluation, and stdio handling instead of guest import work. Optimizations that only touch module compilation will not remove that floor.", - percentage_share(warm_startup_overhead, warm_wall), - )); - } - let warm_guest = warm_local - .and_then(|scenario| scenario.phase_stats.guest_execution_ms.as_ref()) - .map(|stats| stats.mean_ms) - .unwrap_or(0.0); - guidance.push(format!( - "The warm path phase split is {} context setup, {} runtime startup, {} guest execution, and {} completion/stdio work. Future attribution can now separate bootstrap wins from pure transport/collection wins instead of treating them as one startup bucket.", - format_ms(warm_context), - format_ms(warm_startup_phase), - format_ms(warm_guest), - format_ms(warm_completion), - )); - } - - if let (Some(warm_startup_overhead), Some(prewarmed_startup_overhead), Some(isolate_wall)) = ( - warm_local - .and_then(|scenario| scenario.startup_overhead_stats.as_ref()) - .map(|stats| stats.mean_ms), - prewarmed_local - .and_then(|scenario| scenario.startup_overhead_stats.as_ref()) - .map(|stats| stats.mean_ms), - isolate.map(|scenario| scenario.wall_stats.mean_ms), - ) { - guidance.push(format!( - "Keeping the current import-cache materialization and builtin/polyfill prewarm alive inside one execution engine cuts warm local startup overhead from {} to {} ({:.1}% faster). The remaining {} of non-import work is the post-prewarm floor that broader warm-pool/snapshot work would still need to attack above the `{}` empty-isolate baseline.", - format_ms(warm_startup_overhead), - format_ms(prewarmed_startup_overhead), - percentage_reduction(warm_startup_overhead, prewarmed_startup_overhead), - format_ms(prewarmed_startup_overhead), - format_ms(isolate_wall), - )); - } - - if let (Some(builtin_import), Some(large_import)) = ( - builtin - .and_then(|scenario| scenario.guest_import_stats.as_ref()) - .map(|stats| stats.mean_ms), - large - .and_then(|scenario| scenario.guest_import_stats.as_ref()) - .map(|stats| stats.mean_ms), - ) { - guidance.push(format!( - "The large real-world package import (`typescript`) is {:.1}x the builtin path ({} versus {}). That makes `ARC-021C` the right next import-path optimization story: cache sidecar-scoped resolution results, package-type lookups, and module-format classification before attempting deeper structural rewrites.", - safe_ratio(large_import, builtin_import), - format_ms(large_import), - format_ms(builtin_import), - )); - } - - if let (Some(smallest), Some(largest)) = - (self.transport_rtt.first(), self.transport_rtt.last()) - { - guidance.push(format!( - "Execution-transport RTT over the stdio bridge rises from {} at {} bytes to {} at {} bytes. That gives later work a direct transport floor to compare against the larger startup and import phases.", - format_ms(smallest.stats.mean_ms), - smallest.payload_bytes, - format_ms(largest.stats.mean_ms), - largest.payload_bytes, - )); - } - - if let Some(noisiest) = self.scenarios.iter().max_by(|lhs, rhs| { - lhs.wall_stats - .stddev_ms - .total_cmp(&rhs.wall_stats.stddev_ms) - }) { - guidance.push(format!( - "Wall-time noise is now surfaced directly in the same artifact set: `{}` currently shows the largest spread at {} stddev over a {}-{} wall range, so future deltas on that path should be judged against stability as well as mean time.", - noisiest.id, - format_ms(noisiest.wall_stats.stddev_ms), - format_ms(noisiest.wall_stats.min_ms), - format_ms(noisiest.wall_stats.max_ms), - )); - } - - if let Some(heaviest) = self.scenarios.iter().max_by(|lhs, rhs| { - lhs.resource_usage_stats - .as_ref() - .and_then(|stats| stats.rss_bytes.as_ref()) - .map(|stats| stats.mean) - .unwrap_or(f64::NEG_INFINITY) - .total_cmp( - &rhs.resource_usage_stats - .as_ref() - .and_then(|stats| stats.rss_bytes.as_ref()) - .map(|stats| stats.mean) - .unwrap_or(f64::NEG_INFINITY), - ) - }) { - if let Some(rss_mean) = heaviest - .resource_usage_stats - .as_ref() - .and_then(|stats| stats.rss_bytes.as_ref()) - { - guidance.push(format!( - "Per-scenario resource reporting is now attached to the benchmark rows themselves: `{}` currently has the highest mean RSS at {} MiB, so import-path changes can now be judged for memory regressions without a separate memory-only pass.", - heaviest.id, - format_mib(bytes_to_mib(rss_mean.mean)), - )); - } - } - - guidance.push(String::from( - "No new PRD stories were added from this run. The measured hotspots already map cleanly onto existing follow-ons: `ARC-021C` for safe resolution and metadata caches, `ARC-021D` for builtin/polyfill prewarm, and `ARC-022` for broader warm-pool and timing-mitigation execution work.", - )); - - guidance - } - - fn scenario(&self, id: &str) -> Option<&BenchmarkScenarioReport> { - self.scenarios.iter().find(|scenario| scenario.id == id) - } - - fn json_artifact<'a>( - &'a self, - comparison: Option<&'a BenchmarkComparison>, - ) -> JavascriptBenchmarkArtifact<'a> { - JavascriptBenchmarkArtifact { - artifact_version: BENCHMARK_ARTIFACT_VERSION, - generated_at_unix_ms: self.generated_at_unix_ms, - command: format!( - "cargo run -p secure-exec-execution --bin node-import-bench -- --iterations {} --warmup-iterations {}", - self.config.iterations, self.config.warmup_iterations - ), - config: &self.config, - host: &self.host, - repo_root: &self.repo_root, - summary: self.summary(), - comparison, - transport_rtt: self - .transport_rtt - .iter() - .map(|transport| BenchmarkTransportRttArtifact { - channel: transport.channel, - payload_bytes: transport.payload_bytes, - samples_ms: &transport.samples_ms, - stats: &transport.stats, - }) - .collect(), - scenarios: self - .scenarios - .iter() - .map(|scenario| BenchmarkScenarioArtifact { - id: scenario.id, - workload: scenario.workload, - runtime: scenario.runtime, - mode: scenario.mode, - description: scenario.description, - fixture: scenario.fixture, - compile_cache: scenario.compile_cache, - wall_samples_ms: &scenario.wall_samples_ms, - wall_stats: &scenario.wall_stats, - guest_import_samples_ms: scenario.guest_import_samples_ms.as_deref(), - guest_import_stats: scenario.guest_import_stats.as_ref(), - startup_overhead_samples_ms: scenario.startup_overhead_samples_ms.as_deref(), - startup_overhead_stats: scenario.startup_overhead_stats.as_ref(), - mean_startup_share_pct: scenario.mean_startup_share_pct(), - phase_samples_ms: &scenario.phase_samples_ms, - phase_stats: &scenario.phase_stats, - resource_usage_samples: scenario.resource_usage_samples.as_ref(), - resource_usage_stats: scenario.resource_usage_stats.as_ref(), - }) - .collect(), - } - } - - fn summary(&self) -> BenchmarkSummaryArtifact<'_> { - BenchmarkSummaryArtifact { - scenario_count: self.scenarios.len(), - recorded_samples_per_scenario: self.config.iterations, - warmup_iterations: self.config.warmup_iterations, - control_matrix: self.control_matrix(), - slowest_wall_scenario: self.slowest_scenario_by(|scenario| scenario.wall_stats.mean_ms), - slowest_guest_import_scenario: self.slowest_scenario_by(|scenario| { - scenario - .guest_import_stats - .as_ref() - .map(|stats| stats.mean_ms) - .unwrap_or(f64::NEG_INFINITY) - }), - highest_startup_share_scenario: self.scenarios.iter().max_by(|lhs, rhs| { - lhs.mean_startup_share_pct() - .unwrap_or(f64::NEG_INFINITY) - .total_cmp(&rhs.mean_startup_share_pct().unwrap_or(f64::NEG_INFINITY)) - }), - hotspot_rankings: self.hotspot_rankings(), - guidance_lines: self.guidance_lines(), - } - } - - fn control_matrix(&self) -> Vec> { - let mut rows = Vec::new(); - let mut row_indexes = BTreeMap::new(); - - for scenario in &self.scenarios { - let row_index = *row_indexes.entry(scenario.workload).or_insert_with(|| { - rows.push(BenchmarkControlMatrixArtifact { - workload: scenario.workload, - runtimes: Vec::new(), - modes: Vec::new(), - scenario_ids: Vec::new(), - }); - rows.len() - 1 - }); - let row = &mut rows[row_index]; - push_unique_label(&mut row.runtimes, scenario.runtime); - push_unique_label(&mut row.modes, scenario.mode); - row.scenario_ids.push(scenario.id); - } - - rows - } - - fn slowest_scenario_by( - &self, - value: impl Fn(&BenchmarkScenarioReport) -> f64, - ) -> Option<&BenchmarkScenarioReport> { - self.scenarios - .iter() - .max_by(|lhs, rhs| value(lhs).total_cmp(&value(rhs))) - } - - fn hotspot_rankings(&self) -> Vec> { - HOTSPOT_METRICS - .iter() - .map(|metric| { - let mut ranked_scenarios = self - .scenarios - .iter() - .filter_map(|scenario| { - (metric.value)(scenario).map(|value| BenchmarkHotspotScenarioArtifact { - rank: 0, - id: scenario.id, - workload: scenario.workload, - runtime: scenario.runtime, - mode: scenario.mode, - value, - }) - }) - .collect::>(); - ranked_scenarios.sort_by(|lhs, rhs| { - rhs.value - .total_cmp(&lhs.value) - .then_with(|| lhs.id.cmp(rhs.id)) - }); - for (index, scenario) in ranked_scenarios.iter_mut().enumerate() { - scenario.rank = index + 1; - } - - BenchmarkHotspotRankingArtifact { - metric: metric.metric, - label: metric.label, - dimension: metric.dimension, - unit: metric.unit, - ranked_scenarios, - scenarios_without_metric: self - .scenarios - .iter() - .filter(|scenario| (metric.value)(scenario).is_none()) - .map(|scenario| scenario.id) - .collect(), - } - }) - .collect() - } -} - -impl BenchmarkScenarioReport { - fn mean_startup_share_pct(&self) -> Option { - let startup_mean = self.startup_overhead_stats.as_ref()?.mean_ms; - let wall_mean = self.wall_stats.mean_ms; - if wall_mean <= 0.0 { - Some(0.0) - } else { - Some((startup_mean / wall_mean) * 100.0) - } - } - - fn wall_range_ms(&self) -> f64 { - self.wall_stats.max_ms - self.wall_stats.min_ms - } -} - -impl BenchmarkResourceUsage> { - fn push_sample(&mut self, sample: &BenchmarkResourceUsage) { - push_optional_sample(&mut self.rss_bytes, sample.rss_bytes); - push_optional_sample(&mut self.heap_used_bytes, sample.heap_used_bytes); - push_optional_sample(&mut self.cpu_user_us, sample.cpu_user_us); - push_optional_sample(&mut self.cpu_system_us, sample.cpu_system_us); - push_optional_sample(&mut self.cpu_total_us, sample.cpu_total_us); - } - - fn into_populated(self) -> Option { - (!self.is_empty()).then_some(self) - } -} - -impl BenchmarkResourceUsage { - fn is_empty(&self) -> bool { - self.rss_bytes.is_none() - && self.heap_used_bytes.is_none() - && self.cpu_user_us.is_none() - && self.cpu_system_us.is_none() - && self.cpu_total_us.is_none() - } -} - -impl BenchmarkComparison { - fn from_reports( - current: &JavascriptBenchmarkReport, - baseline_path: &Path, - baseline: &StoredBenchmarkArtifact, - ) -> Self { - let baseline_path = - fs::canonicalize(baseline_path).unwrap_or_else(|_| baseline_path.to_path_buf()); - let baseline_by_id = baseline - .scenarios - .iter() - .map(|scenario| (scenario.id.as_str(), scenario)) - .collect::>(); - - let mut scenario_deltas = Vec::new(); - let mut scenarios_missing_from_baseline = Vec::new(); - - for scenario in ¤t.scenarios { - if let Some(baseline_scenario) = baseline_by_id.get(scenario.id) { - scenario_deltas.push(BenchmarkScenarioDelta { - id: scenario.id.to_owned(), - description: scenario.description.to_owned(), - wall_mean_ms: BenchmarkMetricDelta::from_means( - baseline_scenario.wall_stats.mean_ms, - scenario.wall_stats.mean_ms, - ), - guest_import_mean_ms: match ( - baseline_scenario.guest_import_stats.as_ref(), - scenario.guest_import_stats.as_ref(), - ) { - (Some(baseline_stats), Some(current_stats)) => { - Some(BenchmarkMetricDelta::from_means( - baseline_stats.mean_ms, - current_stats.mean_ms, - )) - } - _ => None, - }, - startup_overhead_mean_ms: match ( - baseline_scenario.startup_overhead_stats.as_ref(), - scenario.startup_overhead_stats.as_ref(), - ) { - (Some(baseline_stats), Some(current_stats)) => { - Some(BenchmarkMetricDelta::from_means( - baseline_stats.mean_ms, - current_stats.mean_ms, - )) - } - _ => None, - }, - phase_mean_ms: match ( - baseline_scenario.phase_stats.as_ref(), - Some(&scenario.phase_stats), - ) { - (Some(baseline_phase), Some(current_phase)) => { - Some(BenchmarkScenarioPhases { - context_setup_ms: BenchmarkMetricDelta::from_means( - baseline_phase.context_setup_ms.mean_ms, - current_phase.context_setup_ms.mean_ms, - ), - startup_ms: BenchmarkMetricDelta::from_means( - baseline_phase.startup_ms.mean_ms, - current_phase.startup_ms.mean_ms, - ), - guest_execution_ms: match ( - baseline_phase.guest_execution_ms.as_ref(), - current_phase.guest_execution_ms.as_ref(), - ) { - (Some(baseline_stats), Some(current_stats)) => { - Some(BenchmarkMetricDelta::from_means( - baseline_stats.mean_ms, - current_stats.mean_ms, - )) - } - _ => None, - }, - completion_ms: BenchmarkMetricDelta::from_means( - baseline_phase.completion_ms.mean_ms, - current_phase.completion_ms.mean_ms, - ), - }) - } - _ => None, - }, - }); - } else { - scenarios_missing_from_baseline.push(scenario.id.to_owned()); - } - } - - let current_ids = current - .scenarios - .iter() - .map(|scenario| (scenario.id, ())) - .collect::>(); - let baseline_only_scenarios = baseline - .scenarios - .iter() - .filter(|scenario| !current_ids.contains_key(scenario.id.as_str())) - .map(|scenario| scenario.id.clone()) - .collect::>(); - - let largest_wall_improvement = scenario_deltas - .iter() - .filter(|scenario| scenario.wall_mean_ms.delta_ms < 0.0) - .min_by(|lhs, rhs| { - lhs.wall_mean_ms - .delta_ms - .total_cmp(&rhs.wall_mean_ms.delta_ms) - }) - .map(BenchmarkDeltaHighlight::from_wall_delta); - let largest_wall_regression = scenario_deltas - .iter() - .filter(|scenario| scenario.wall_mean_ms.delta_ms > 0.0) - .max_by(|lhs, rhs| { - lhs.wall_mean_ms - .delta_ms - .total_cmp(&rhs.wall_mean_ms.delta_ms) - }) - .map(BenchmarkDeltaHighlight::from_wall_delta); - - Self { - baseline: BenchmarkComparisonBaseline { - artifact_version: baseline.artifact_version, - generated_at_unix_ms: baseline.generated_at_unix_ms, - path: baseline_path, - }, - summary: BenchmarkComparisonSummary { - compared_scenario_count: scenario_deltas.len(), - largest_wall_improvement, - largest_wall_regression, - }, - scenario_deltas, - scenarios_missing_from_baseline, - baseline_only_scenarios, - } - } -} - -impl BenchmarkDeltaHighlight { - fn from_wall_delta(delta: &BenchmarkScenarioDelta) -> Self { - Self { - id: delta.id.clone(), - delta_ms: delta.wall_mean_ms.delta_ms, - delta_pct: delta.wall_mean_ms.delta_pct, - } - } -} - -impl BenchmarkMetricDelta { - fn from_means(baseline_ms: f64, current_ms: f64) -> Self { - let delta_ms = current_ms - baseline_ms; - let delta_pct = if baseline_ms <= 0.0 { - 0.0 - } else { - (delta_ms / baseline_ms) * 100.0 - }; - - Self { - baseline_ms, - current_ms, - delta_ms, - delta_pct, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct JavascriptBenchmarkArtifactPaths { - pub markdown_path: PathBuf, - pub json_path: PathBuf, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct JavascriptBenchmarkRunOutput { - pub artifact_paths: JavascriptBenchmarkArtifactPaths, - pub resumed_stage_count: usize, -} - -#[derive(Debug, Serialize)] -struct JavascriptBenchmarkArtifact<'a> { - artifact_version: u32, - generated_at_unix_ms: u128, - command: String, - config: &'a JavascriptBenchmarkConfig, - host: &'a BenchmarkHost, - repo_root: &'a Path, - summary: BenchmarkSummaryArtifact<'a>, - #[serde(skip_serializing_if = "Option::is_none")] - comparison: Option<&'a BenchmarkComparison>, - transport_rtt: Vec>, - scenarios: Vec>, -} - -#[derive(Debug, Serialize)] -struct BenchmarkSummaryArtifact<'a> { - scenario_count: usize, - recorded_samples_per_scenario: usize, - warmup_iterations: usize, - control_matrix: Vec>, - #[serde(skip_serializing_if = "Option::is_none")] - slowest_wall_scenario: Option<&'a BenchmarkScenarioReport>, - #[serde(skip_serializing_if = "Option::is_none")] - slowest_guest_import_scenario: Option<&'a BenchmarkScenarioReport>, - #[serde(skip_serializing_if = "Option::is_none")] - highest_startup_share_scenario: Option<&'a BenchmarkScenarioReport>, - hotspot_rankings: Vec>, - guidance_lines: Vec, -} - -#[derive(Debug, Serialize)] -struct BenchmarkScenarioArtifact<'a> { - id: &'static str, - workload: &'static str, - runtime: &'static str, - mode: &'static str, - description: &'static str, - fixture: &'static str, - compile_cache: &'static str, - wall_samples_ms: &'a [f64], - wall_stats: &'a BenchmarkStats, - #[serde(skip_serializing_if = "Option::is_none")] - guest_import_samples_ms: Option<&'a [f64]>, - #[serde(skip_serializing_if = "Option::is_none")] - guest_import_stats: Option<&'a BenchmarkStats>, - #[serde(skip_serializing_if = "Option::is_none")] - startup_overhead_samples_ms: Option<&'a [f64]>, - #[serde(skip_serializing_if = "Option::is_none")] - startup_overhead_stats: Option<&'a BenchmarkStats>, - #[serde(skip_serializing_if = "Option::is_none")] - mean_startup_share_pct: Option, - phase_samples_ms: &'a BenchmarkScenarioPhases>, - phase_stats: &'a BenchmarkScenarioPhases, - #[serde(skip_serializing_if = "Option::is_none")] - resource_usage_samples: Option<&'a BenchmarkResourceUsage>>, - #[serde(skip_serializing_if = "Option::is_none")] - resource_usage_stats: Option<&'a BenchmarkResourceUsage>, -} - -#[derive(Debug, Serialize)] -struct BenchmarkControlMatrixArtifact<'a> { - workload: &'a str, - runtimes: Vec<&'a str>, - modes: Vec<&'a str>, - scenario_ids: Vec<&'a str>, -} - -#[derive(Debug, Serialize)] -struct BenchmarkTransportRttArtifact<'a> { - channel: &'static str, - payload_bytes: usize, - samples_ms: &'a [f64], - stats: &'a BenchmarkStats, -} - -#[derive(Debug, Serialize)] -struct BenchmarkHotspotRankingArtifact<'a> { - metric: &'static str, - label: &'static str, - dimension: &'static str, - unit: &'static str, - ranked_scenarios: Vec>, - #[serde(skip_serializing_if = "Vec::is_empty")] - scenarios_without_metric: Vec<&'a str>, -} - -#[derive(Debug, Serialize)] -struct BenchmarkHotspotScenarioArtifact<'a> { - rank: usize, - id: &'a str, - workload: &'a str, - runtime: &'a str, - mode: &'a str, - value: f64, -} - -struct HotspotMetricDefinition { - metric: &'static str, - label: &'static str, - dimension: &'static str, - unit: &'static str, - value: fn(&BenchmarkScenarioReport) -> Option, -} - -const HOTSPOT_METRICS: [HotspotMetricDefinition; 13] = [ - HotspotMetricDefinition { - metric: "wall_mean_ms", - label: "Wall Time", - dimension: "time", - unit: "ms", - value: hotspot_wall_mean_ms, - }, - HotspotMetricDefinition { - metric: "wall_stddev_ms", - label: "Wall Time Stddev", - dimension: "stability", - unit: "ms", - value: hotspot_wall_stddev_ms, - }, - HotspotMetricDefinition { - metric: "wall_range_ms", - label: "Wall Time Range", - dimension: "stability", - unit: "ms", - value: hotspot_wall_range_ms, - }, - HotspotMetricDefinition { - metric: "guest_import_mean_ms", - label: "Guest Import Time", - dimension: "time", - unit: "ms", - value: hotspot_guest_import_mean_ms, - }, - HotspotMetricDefinition { - metric: "startup_overhead_mean_ms", - label: "Startup Overhead", - dimension: "time", - unit: "ms", - value: hotspot_startup_overhead_mean_ms, - }, - HotspotMetricDefinition { - metric: "context_setup_mean_ms", - label: "Context Setup Phase", - dimension: "time", - unit: "ms", - value: hotspot_context_setup_mean_ms, - }, - HotspotMetricDefinition { - metric: "startup_phase_mean_ms", - label: "Runtime Startup Phase", - dimension: "time", - unit: "ms", - value: hotspot_startup_phase_mean_ms, - }, - HotspotMetricDefinition { - metric: "guest_execution_mean_ms", - label: "Guest Execution Phase", - dimension: "time", - unit: "ms", - value: hotspot_guest_execution_mean_ms, - }, - HotspotMetricDefinition { - metric: "completion_mean_ms", - label: "Completion/Stdio Phase", - dimension: "time", - unit: "ms", - value: hotspot_completion_mean_ms, - }, - HotspotMetricDefinition { - metric: "startup_share_pct", - label: "Startup Share Of Wall", - dimension: "share", - unit: "pct", - value: hotspot_startup_share_pct, - }, - HotspotMetricDefinition { - metric: "rss_mean_mib", - label: "RSS", - dimension: "memory", - unit: "MiB", - value: hotspot_rss_mean_mib, - }, - HotspotMetricDefinition { - metric: "heap_mean_mib", - label: "Heap Used", - dimension: "memory", - unit: "MiB", - value: hotspot_heap_mean_mib, - }, - HotspotMetricDefinition { - metric: "cpu_total_mean_ms", - label: "Total CPU", - dimension: "cpu", - unit: "ms", - value: hotspot_total_cpu_mean_ms, - }, -]; - -#[derive(Debug)] -pub enum JavascriptBenchmarkError { - InvalidConfig(&'static str), - InvalidWorkspaceRoot(PathBuf), - InvalidBaselineReport { - path: PathBuf, - message: String, - }, - Io(std::io::Error), - Utf8(std::string::FromUtf8Error), - Execution(JavascriptExecutionError), - NodeVersion(std::io::Error), - MissingBenchmarkMetric(&'static str), - InvalidBenchmarkMetric { - scenario: &'static str, - raw_value: String, - }, - TransportProbeTimeout { - payload_bytes: usize, - }, - TransportProbeExited { - exit_code: i32, - stderr: String, - }, - InvalidTransportProbeResponse { - payload_bytes: usize, - expected: String, - actual: String, - }, - NonZeroExit { - scenario: &'static str, - exit_code: i32, - stderr: String, - }, -} - -impl fmt::Display for JavascriptBenchmarkError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InvalidConfig(message) => write!(f, "invalid benchmark config: {message}"), - Self::InvalidWorkspaceRoot(path) => { - write!( - f, - "failed to resolve workspace root from execution crate path: {}", - path.display() - ) - } - Self::InvalidBaselineReport { path, message } => { - write!( - f, - "failed to parse benchmark baseline artifact {}: {message}", - path.display() - ) - } - Self::Io(err) => write!(f, "benchmark I/O failure: {err}"), - Self::Utf8(err) => write!(f, "benchmark output was not valid UTF-8: {err}"), - Self::Execution(err) => write!(f, "benchmark execution failed: {err}"), - Self::NodeVersion(err) => write!(f, "failed to query node version: {err}"), - Self::MissingBenchmarkMetric(scenario) => { - write!( - f, - "benchmark scenario `{scenario}` did not emit a metric marker" - ) - } - Self::InvalidBenchmarkMetric { - scenario, - raw_value, - } => write!( - f, - "benchmark scenario `{scenario}` emitted an invalid metric: {raw_value}" - ), - Self::TransportProbeTimeout { payload_bytes } => { - write!( - f, - "transport probe timed out waiting for {payload_bytes}-byte round-trip" - ) - } - Self::TransportProbeExited { exit_code, stderr } => { - write!(f, "transport probe exited with code {exit_code}: {stderr}") - } - Self::InvalidTransportProbeResponse { - payload_bytes, - expected, - actual, - } => write!( - f, - "transport probe returned unexpected payload for {payload_bytes}-byte round-trip: expected {expected:?}, got {actual:?}" - ), - Self::NonZeroExit { - scenario, - exit_code, - stderr, - } => write!( - f, - "benchmark scenario `{scenario}` exited with code {exit_code}: {stderr}" - ), - } - } -} - -impl std::error::Error for JavascriptBenchmarkError {} - -impl From for JavascriptBenchmarkError { - fn from(err: std::io::Error) -> Self { - Self::Io(err) - } -} - -impl From for JavascriptBenchmarkError { - fn from(err: std::string::FromUtf8Error) -> Self { - Self::Utf8(err) - } -} - -impl From for JavascriptBenchmarkError { - fn from(err: serde_json::Error) -> Self { - Self::Io(std::io::Error::new(std::io::ErrorKind::InvalidData, err)) - } -} - -impl From for JavascriptBenchmarkError { - fn from(err: JavascriptExecutionError) -> Self { - Self::Execution(err) - } -} - -pub fn run_javascript_benchmarks( - config: &JavascriptBenchmarkConfig, -) -> Result { - validate_benchmark_config(config)?; - - let repo_root = workspace_root()?; - let host = benchmark_host()?; - let workspace = BenchmarkWorkspace::create(&repo_root)?; - let transport_rtt = measure_transport_rtt(&workspace, config)?; - - let mut scenarios = Vec::new(); - - for scenario in benchmark_scenarios() { - scenarios.push(run_scenario(&workspace, config, scenario)?); - } - - Ok(JavascriptBenchmarkReport { - generated_at_unix_ms: SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_millis(), - config: config.clone(), - host, - repo_root, - transport_rtt, - scenarios, - }) -} - -fn benchmark_artifact_dir(repo_root: &Path) -> PathBuf { - repo_root.join(BENCHMARK_ARTIFACT_DIR) -} - -fn benchmark_run_state_path(artifact_dir: &Path) -> PathBuf { - artifact_dir.join(BENCHMARK_RUN_STATE_FILE) -} - -fn load_benchmark_run_state( - state_path: &Path, - config: &JavascriptBenchmarkConfig, - host: &BenchmarkHost, - repo_root: &Path, - definitions: &[ScenarioDefinition], -) -> Result { - match fs::read_to_string(state_path) { - Ok(raw) => match serde_json::from_str::(&raw) { - Ok(state) if state.is_compatible(config, host, repo_root) => { - Ok(state.sanitized(definitions)) - } - Ok(_) | Err(_) => Ok(StoredBenchmarkRunState::new(config, host, repo_root)), - }, - Err(err) if err.kind() == std::io::ErrorKind::NotFound => { - Ok(StoredBenchmarkRunState::new(config, host, repo_root)) - } - Err(err) => Err(JavascriptBenchmarkError::Io(err)), - } -} - -fn persist_benchmark_run_state( - state_path: &Path, - state: &StoredBenchmarkRunState, -) -> Result<(), JavascriptBenchmarkError> { - write_string_atomic(state_path, &serde_json::to_string_pretty(state)?) -} - -fn write_string_atomic(path: &Path, contents: &str) -> Result<(), JavascriptBenchmarkError> { - if let Some(parent) = path.parent() { - fs::create_dir_all(parent)?; - } - - let temp_path = path.with_file_name(format!( - ".{}.tmp-{}-{}", - path.file_name() - .and_then(|name| name.to_str()) - .unwrap_or("artifact"), - std::process::id(), - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_nanos() - )); - fs::write(&temp_path, contents)?; - if let Err(err) = fs::rename(&temp_path, path) { - let _ = fs::remove_file(&temp_path); - return Err(JavascriptBenchmarkError::Io(err)); - } - - Ok(()) -} - -fn remove_file_if_exists(path: &Path) -> Result<(), JavascriptBenchmarkError> { - match fs::remove_file(path) { - Ok(()) => Ok(()), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()), - Err(err) => Err(JavascriptBenchmarkError::Io(err)), - } -} - -fn current_unix_ms() -> u128 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_millis() -} - -#[derive(Debug, Clone, Copy)] -struct ScenarioDefinition { - id: &'static str, - workload: &'static str, - runtime: ScenarioRuntime, - mode: ScenarioMode, - description: &'static str, - fixture: &'static str, - entrypoint: &'static str, - compile_cache: CompileCacheStrategy, - engine_reuse: EngineReuseStrategy, - expect_import_metric: bool, - env: ScenarioEnvironment, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum CompileCacheStrategy { - Disabled, - Primed, -} - -impl CompileCacheStrategy { - fn label(self) -> &'static str { - match self { - Self::Disabled => "disabled", - Self::Primed => "primed", - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum EngineReuseStrategy { - FreshPerSample, - SharedAcrossScenario, - SharedContextAcrossScenario, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum ScenarioEnvironment { - None, - ProjectedWorkspaceNodeModules, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum ScenarioRuntime { - NativeExecution, - HostNode, -} - -impl ScenarioRuntime { - fn label(self) -> &'static str { - match self { - Self::NativeExecution => "native-execution", - Self::HostNode => "host-node", - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum ScenarioMode { - BaselineControl, - TrueColdStart, - NewSessionReplay, - SameSessionReplay, - SameEngineReplay, - HostControl, -} - -impl ScenarioMode { - fn label(self) -> &'static str { - match self { - Self::BaselineControl => "baseline-control", - Self::TrueColdStart => "true-cold-start", - Self::NewSessionReplay => "new-session-replay", - Self::SameSessionReplay => "same-session-replay", - Self::SameEngineReplay => "same-engine-replay", - Self::HostControl => "host-control", - } - } -} - -#[derive(Debug)] -struct SampleMeasurement { - wall_ms: f64, - guest_import_ms: Option, - context_setup_ms: f64, - startup_ms: f64, - completion_ms: f64, - resource_usage: Option>, -} - -#[derive(Debug)] -struct BenchmarkWorkspace { - root: PathBuf, - repo_root: PathBuf, -} - -#[derive(Debug, Deserialize)] -struct StoredBenchmarkArtifact { - artifact_version: u32, - generated_at_unix_ms: u128, - scenarios: Vec, -} - -#[derive(Debug, Deserialize)] -struct StoredBenchmarkScenario { - id: String, - wall_stats: BenchmarkStats, - #[serde(default)] - guest_import_stats: Option, - #[serde(default)] - startup_overhead_stats: Option, - #[serde(default)] - phase_stats: Option>, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -struct StoredBenchmarkRunHost { - node_binary: String, - node_version: String, - os: String, - arch: String, - logical_cpus: usize, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -struct StoredBenchmarkRunState { - artifact_version: u32, - config: JavascriptBenchmarkConfig, - host: StoredBenchmarkRunHost, - repo_root: PathBuf, - #[serde(default)] - transport_rtt: Option>, - #[serde(default)] - scenarios: Vec, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -struct StoredBenchmarkTransportRttReport { - payload_bytes: usize, - samples_ms: Vec, - stats: BenchmarkStats, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -struct StoredBenchmarkScenarioReport { - id: String, - wall_samples_ms: Vec, - wall_stats: BenchmarkStats, - #[serde(default)] - guest_import_samples_ms: Option>, - #[serde(default)] - guest_import_stats: Option, - #[serde(default)] - startup_overhead_samples_ms: Option>, - #[serde(default)] - startup_overhead_stats: Option, - phase_samples_ms: BenchmarkScenarioPhases>, - phase_stats: BenchmarkScenarioPhases, - #[serde(default)] - resource_usage_samples: Option>>, - #[serde(default)] - resource_usage_stats: Option>, -} - -impl BenchmarkWorkspace { - fn create(repo_root: &Path) -> Result { - let root = repo_root.join(format!( - ".tmp-secure-exec-execution-bench-{}-{}", - std::process::id(), - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_nanos() - )); - fs::create_dir_all(&root)?; - write_benchmark_workspace(&root, repo_root)?; - Ok(Self { - root, - repo_root: repo_root.to_path_buf(), - }) - } -} - -impl Drop for BenchmarkWorkspace { - fn drop(&mut self) { - let _ = fs::remove_dir_all(&self.root); - } -} - -impl StoredBenchmarkRunHost { - fn from_host(host: &BenchmarkHost) -> Self { - Self { - node_binary: host.node_binary.clone(), - node_version: host.node_version.clone(), - os: host.os.to_owned(), - arch: host.arch.to_owned(), - logical_cpus: host.logical_cpus, - } - } - - fn matches_host(&self, host: &BenchmarkHost) -> bool { - self.node_binary == host.node_binary - && self.node_version == host.node_version - && self.os == host.os - && self.arch == host.arch - && self.logical_cpus == host.logical_cpus - } -} - -impl StoredBenchmarkRunState { - fn new(config: &JavascriptBenchmarkConfig, host: &BenchmarkHost, repo_root: &Path) -> Self { - Self { - artifact_version: BENCHMARK_ARTIFACT_VERSION, - config: config.clone(), - host: StoredBenchmarkRunHost::from_host(host), - repo_root: repo_root.to_path_buf(), - transport_rtt: None, - scenarios: Vec::new(), - } - } - - fn is_compatible( - &self, - config: &JavascriptBenchmarkConfig, - host: &BenchmarkHost, - repo_root: &Path, - ) -> bool { - self.artifact_version == BENCHMARK_ARTIFACT_VERSION - && self.config == *config - && self.host.matches_host(host) - && self.repo_root == repo_root - } - - fn sanitized(mut self, definitions: &[ScenarioDefinition]) -> Self { - if let Some(transport_rtt) = &self.transport_rtt { - let payloads = transport_rtt - .iter() - .map(|report| report.payload_bytes) - .collect::>(); - if payloads != TRANSPORT_RTT_PAYLOAD_BYTES { - self.transport_rtt = None; - } - } - - let mut scenarios_by_id = self - .scenarios - .into_iter() - .map(|scenario| (scenario.id.clone(), scenario)) - .collect::>(); - self.scenarios = definitions - .iter() - .filter_map(|definition| scenarios_by_id.remove(definition.id)) - .collect(); - self - } - - fn resumed_stage_count(&self, definitions: &[ScenarioDefinition]) -> usize { - usize::from(self.transport_rtt.is_some()) - + definitions - .iter() - .filter(|definition| self.has_scenario(definition.id)) - .count() - } - - fn has_scenario(&self, id: &str) -> bool { - self.scenarios.iter().any(|scenario| scenario.id == id) - } - - fn record_transport_rtt(&mut self, transport_rtt: &[BenchmarkTransportRttReport]) { - self.transport_rtt = Some( - transport_rtt - .iter() - .map(StoredBenchmarkTransportRttReport::from_report) - .collect(), - ); - } - - fn record_scenario(&mut self, scenario: &BenchmarkScenarioReport) { - self.scenarios.retain(|stored| stored.id != scenario.id); - self.scenarios - .push(StoredBenchmarkScenarioReport::from_report(scenario)); - } - - fn to_report( - &self, - config: &JavascriptBenchmarkConfig, - host: &BenchmarkHost, - repo_root: &Path, - definitions: &[ScenarioDefinition], - ) -> JavascriptBenchmarkReport { - let scenarios_by_id = self - .scenarios - .iter() - .map(|scenario| (scenario.id.as_str(), scenario)) - .collect::>(); - - JavascriptBenchmarkReport { - generated_at_unix_ms: current_unix_ms(), - config: config.clone(), - host: host.clone(), - repo_root: repo_root.to_path_buf(), - transport_rtt: self - .transport_rtt - .clone() - .unwrap_or_default() - .into_iter() - .map(StoredBenchmarkTransportRttReport::into_report) - .collect(), - scenarios: definitions - .iter() - .filter_map(|definition| { - scenarios_by_id - .get(definition.id) - .map(|scenario| scenario.to_report(*definition)) - }) - .collect(), - } - } -} - -impl StoredBenchmarkTransportRttReport { - fn from_report(report: &BenchmarkTransportRttReport) -> Self { - Self { - payload_bytes: report.payload_bytes, - samples_ms: report.samples_ms.clone(), - stats: report.stats.clone(), - } - } - - fn into_report(self) -> BenchmarkTransportRttReport { - BenchmarkTransportRttReport { - channel: TRANSPORT_RTT_CHANNEL, - payload_bytes: self.payload_bytes, - samples_ms: self.samples_ms, - stats: self.stats, - } - } -} - -impl StoredBenchmarkScenarioReport { - fn from_report(report: &BenchmarkScenarioReport) -> Self { - Self { - id: report.id.to_owned(), - wall_samples_ms: report.wall_samples_ms.clone(), - wall_stats: report.wall_stats.clone(), - guest_import_samples_ms: report.guest_import_samples_ms.clone(), - guest_import_stats: report.guest_import_stats.clone(), - startup_overhead_samples_ms: report.startup_overhead_samples_ms.clone(), - startup_overhead_stats: report.startup_overhead_stats.clone(), - phase_samples_ms: report.phase_samples_ms.clone(), - phase_stats: report.phase_stats.clone(), - resource_usage_samples: report.resource_usage_samples.clone(), - resource_usage_stats: report.resource_usage_stats.clone(), - } - } - - fn to_report(&self, definition: ScenarioDefinition) -> BenchmarkScenarioReport { - BenchmarkScenarioReport { - id: definition.id, - workload: definition.workload, - runtime: definition.runtime.label(), - mode: definition.mode.label(), - description: definition.description, - fixture: definition.fixture, - compile_cache: definition.compile_cache.label(), - wall_samples_ms: self.wall_samples_ms.clone(), - wall_stats: self.wall_stats.clone(), - guest_import_samples_ms: self.guest_import_samples_ms.clone(), - guest_import_stats: self.guest_import_stats.clone(), - startup_overhead_samples_ms: self.startup_overhead_samples_ms.clone(), - startup_overhead_stats: self.startup_overhead_stats.clone(), - phase_samples_ms: self.phase_samples_ms.clone(), - phase_stats: self.phase_stats.clone(), - resource_usage_samples: self.resource_usage_samples.clone(), - resource_usage_stats: self.resource_usage_stats.clone(), - } - } -} - -pub fn run_javascript_benchmarks_with_recovery( - config: &JavascriptBenchmarkConfig, - baseline_path: Option<&Path>, -) -> Result { - validate_benchmark_config(config)?; - - let repo_root = workspace_root()?; - let host = benchmark_host()?; - let artifact_dir = benchmark_artifact_dir(&repo_root); - let workspace = BenchmarkWorkspace::create(&repo_root)?; - let (report, resumed_stage_count, state_path) = orchestrate_javascript_benchmark_report( - config, - &repo_root, - &host, - &artifact_dir, - || measure_transport_rtt(&workspace, config), - |scenario| run_scenario(&workspace, config, scenario), - )?; - let comparison = baseline_path - .map(|path| report.compare_to_baseline_path(path)) - .transpose()?; - let artifact_paths = - report.write_artifacts_with_comparison(&artifact_dir, comparison.as_ref())?; - remove_file_if_exists(&state_path)?; - - Ok(JavascriptBenchmarkRunOutput { - artifact_paths, - resumed_stage_count, - }) -} - -fn orchestrate_javascript_benchmark_report( - config: &JavascriptBenchmarkConfig, - repo_root: &Path, - host: &BenchmarkHost, - artifact_dir: &Path, - mut measure_transport: MeasureTransport, - mut run_scenario: RunScenario, -) -> Result<(JavascriptBenchmarkReport, usize, PathBuf), JavascriptBenchmarkError> -where - MeasureTransport: FnMut() -> Result, JavascriptBenchmarkError>, - RunScenario: - FnMut(ScenarioDefinition) -> Result, -{ - validate_benchmark_config(config)?; - - fs::create_dir_all(artifact_dir)?; - - let definitions = benchmark_scenarios(); - let state_path = benchmark_run_state_path(artifact_dir); - let mut state = load_benchmark_run_state(&state_path, config, host, repo_root, &definitions)?; - let resumed_stage_count = state.resumed_stage_count(&definitions); - - if state.transport_rtt.is_none() { - let transport_rtt = measure_transport()?; - state.record_transport_rtt(&transport_rtt); - persist_benchmark_run_state(&state_path, &state)?; - } - - for definition in definitions { - if state.has_scenario(definition.id) { - continue; - } - - let scenario = run_scenario(definition)?; - state.record_scenario(&scenario); - persist_benchmark_run_state(&state_path, &state)?; - } - - Ok(( - state.to_report(config, host, repo_root, &benchmark_scenarios()), - resumed_stage_count, - state_path, - )) -} - -fn validate_benchmark_config( - config: &JavascriptBenchmarkConfig, -) -> Result<(), JavascriptBenchmarkError> { - if config.iterations == 0 { - return Err(JavascriptBenchmarkError::InvalidConfig( - "iterations must be greater than zero", - )); - } - if config.iterations > MAX_BENCHMARK_ITERATIONS { - return Err(JavascriptBenchmarkError::InvalidConfig( - "iterations must be less than or equal to 1000", - )); - } - if config.warmup_iterations > MAX_BENCHMARK_WARMUP_ITERATIONS { - return Err(JavascriptBenchmarkError::InvalidConfig( - "warmup iterations must be less than or equal to 1000", - )); - } - - Ok(()) -} - -fn benchmark_scenarios() -> [ScenarioDefinition; 21] { - [ - ScenarioDefinition { - id: "isolate-startup", - workload: "startup-floor", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::BaselineControl, - description: "Minimal guest with no extra imports. Measures the current startup floor for create-context plus node process bootstrap.", - fixture: "empty entrypoint", - entrypoint: "./bench/isolate-startup.mjs", - compile_cache: CompileCacheStrategy::Disabled, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: false, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "prewarmed-isolate-startup", - workload: "startup-floor", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::SameEngineReplay, - description: "Minimal guest after a priming pass while one execution engine keeps materialized assets and builtin/polyfill prewarm state alive, isolating the hot startup floor from import work.", - fixture: "empty entrypoint", - entrypoint: "./bench/isolate-startup.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::SharedAcrossScenario, - expect_import_metric: false, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "cold-local-import", - workload: "local-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::TrueColdStart, - description: "Cold import of a repo-local ESM graph that simulates layered application modules without compile-cache reuse.", - fixture: "24-module local ESM graph", - entrypoint: "./bench/cold-local-import.mjs", - compile_cache: CompileCacheStrategy::Disabled, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "warm-local-import", - workload: "local-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::NewSessionReplay, - description: "Warm import of the same local ESM graph after a compile-cache priming pass in an earlier isolate.", - fixture: "24-module local ESM graph", - entrypoint: "./bench/warm-local-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "same-context-local-import", - workload: "local-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::SameSessionReplay, - description: "Warm import of the same local ESM graph by replaying executions against one reused JavaScript context after a compile-cache priming pass.", - fixture: "24-module local ESM graph", - entrypoint: "./bench/warm-local-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::SharedContextAcrossScenario, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "prewarmed-local-import", - workload: "local-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::SameEngineReplay, - description: "Warm import of the same local ESM graph after compile-cache priming while one execution engine keeps materialized assets and builtin/polyfill prewarm state alive.", - fixture: "24-module local ESM graph", - entrypoint: "./bench/warm-local-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::SharedAcrossScenario, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "host-local-import", - workload: "local-import", - runtime: ScenarioRuntime::HostNode, - mode: ScenarioMode::HostControl, - description: "Direct host-Node control for the same local ESM graph so later runs can separate native executor overhead from guest import work.", - fixture: "24-module local ESM graph", - entrypoint: "./bench/cold-local-import.mjs", - compile_cache: CompileCacheStrategy::Disabled, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "builtin-import", - workload: "builtin-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::TrueColdStart, - description: "Import of the common builtin path used by the wrappers and polyfill-adjacent bootstrap code.", - fixture: "node:path + node:url + node:fs/promises", - entrypoint: "./bench/builtin-import.mjs", - compile_cache: CompileCacheStrategy::Disabled, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "hot-builtin-stream-import", - workload: "builtin-hot-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::SameEngineReplay, - description: "Hot single-import microbench for `node:stream` after a priming pass inside one reused execution engine.", - fixture: "node:stream", - entrypoint: "./bench/hot-builtin-stream-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::SharedAcrossScenario, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "hot-builtin-stream-web-import", - workload: "builtin-hot-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::SameEngineReplay, - description: "Hot single-import microbench for `node:stream/web` after a priming pass inside one reused execution engine.", - fixture: "node:stream/web", - entrypoint: "./bench/hot-builtin-stream-web-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::SharedAcrossScenario, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "hot-builtin-crypto-import", - workload: "builtin-hot-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::SameEngineReplay, - description: "Hot single-import microbench for `node:crypto` after a priming pass inside one reused execution engine.", - fixture: "node:crypto", - entrypoint: "./bench/hot-builtin-crypto-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::SharedAcrossScenario, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "hot-builtin-zlib-import", - workload: "builtin-hot-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::SameEngineReplay, - description: "Hot single-import microbench for `node:zlib` after a priming pass inside one reused execution engine.", - fixture: "node:zlib", - entrypoint: "./bench/hot-builtin-zlib-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::SharedAcrossScenario, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "hot-builtin-assert-import", - workload: "builtin-hot-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::SameEngineReplay, - description: "Hot single-import microbench for `node:assert/strict` after a priming pass inside one reused execution engine.", - fixture: "node:assert/strict", - entrypoint: "./bench/hot-builtin-assert-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::SharedAcrossScenario, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "hot-builtin-url-import", - workload: "builtin-hot-import", - runtime: ScenarioRuntime::NativeExecution, - mode: ScenarioMode::SameEngineReplay, - description: "Hot single-import microbench for `node:url` after a priming pass inside one reused execution engine.", - fixture: "node:url", - entrypoint: "./bench/hot-builtin-url-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::SharedAcrossScenario, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "hot-projected-package-file-import", - workload: "projected-package-hot-import", - runtime: ScenarioRuntime::HostNode, - mode: ScenarioMode::SameEngineReplay, - description: "Hot projected-package single-import microbench for the TypeScript compiler file with compile cache and projected-source manifest reuse enabled across repeated contexts.", - fixture: "projected TypeScript compiler file", - entrypoint: "./bench/hot-projected-package-file-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::ProjectedWorkspaceNodeModules, - }, - ScenarioDefinition { - id: "large-package-import", - workload: "large-package-import", - runtime: ScenarioRuntime::HostNode, - mode: ScenarioMode::TrueColdStart, - description: "Cold import of the real-world `typescript` package from the workspace root `node_modules` tree.", - fixture: "typescript", - entrypoint: "./bench/large-package-import.mjs", - compile_cache: CompileCacheStrategy::Disabled, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "projected-package-import", - workload: "projected-package-import", - runtime: ScenarioRuntime::HostNode, - mode: ScenarioMode::HostControl, - description: "Projected-package guest-path import of TypeScript with compile cache and projected-source manifest reuse enabled across repeated contexts.", - fixture: "projected TypeScript guest-path import", - entrypoint: "./bench/projected-package-import.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::ProjectedWorkspaceNodeModules, - }, - ScenarioDefinition { - id: "pdf-lib-startup", - workload: "pdf-lib-startup", - runtime: ScenarioRuntime::HostNode, - mode: ScenarioMode::HostControl, - description: "Cold import of `pdf-lib` plus representative document setup that creates a PDF page and embeds a standard font.", - fixture: "pdf-lib document creation", - entrypoint: "./bench/pdf-lib-startup.mjs", - compile_cache: CompileCacheStrategy::Disabled, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "jszip-startup", - workload: "jszip-startup", - runtime: ScenarioRuntime::HostNode, - mode: ScenarioMode::HostControl, - description: "Cold import of `jszip` plus representative archive staging that builds a nested archive structure.", - fixture: "jszip archive staging", - entrypoint: "./bench/jszip-startup.mjs", - compile_cache: CompileCacheStrategy::Disabled, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "jszip-end-to-end", - workload: "jszip-end-to-end", - runtime: ScenarioRuntime::HostNode, - mode: ScenarioMode::HostControl, - description: "Cold import of `jszip` plus a full compressed archive roundtrip that writes, compresses, reloads, and validates nested archive contents.", - fixture: "jszip end-to-end archive roundtrip", - entrypoint: "./bench/jszip-end-to-end.mjs", - compile_cache: CompileCacheStrategy::Disabled, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ScenarioDefinition { - id: "jszip-repeated-session-compressed", - workload: "jszip-repeated-session-compressed", - runtime: ScenarioRuntime::HostNode, - mode: ScenarioMode::HostControl, - description: "Repeated-session `jszip` workload after a compile-cache priming pass that compresses and reloads a nested archive in each fresh isolate.", - fixture: "jszip compressed archive roundtrip", - entrypoint: "./bench/jszip-repeated-session-compressed.mjs", - compile_cache: CompileCacheStrategy::Primed, - engine_reuse: EngineReuseStrategy::FreshPerSample, - expect_import_metric: true, - env: ScenarioEnvironment::None, - }, - ] -} - -fn run_scenario( - workspace: &BenchmarkWorkspace, - config: &JavascriptBenchmarkConfig, - scenario: ScenarioDefinition, -) -> Result { - let compile_cache_root = workspace - .root - .join("compile-cache") - .join(scenario.id.replace('-', "_")); - let mut shared_engine = match scenario.engine_reuse { - EngineReuseStrategy::FreshPerSample => None, - EngineReuseStrategy::SharedAcrossScenario - | EngineReuseStrategy::SharedContextAcrossScenario => { - Some(JavascriptExecutionEngine::default()) - } - }; - let mut shared_context = None; - - if scenario.compile_cache == CompileCacheStrategy::Primed { - run_sample( - workspace, - &scenario, - Some(compile_cache_root.clone()), - shared_engine.as_mut(), - &mut shared_context, - )?; - } - - for _ in 0..config.warmup_iterations { - run_sample( - workspace, - &scenario, - compile_cache_root_for_strategy(scenario.compile_cache, &compile_cache_root), - shared_engine.as_mut(), - &mut shared_context, - )?; - } - - let mut wall_samples_ms = Vec::with_capacity(config.iterations); - let mut guest_import_samples_ms = if scenario.expect_import_metric { - Some(Vec::with_capacity(config.iterations)) - } else { - None - }; - let mut context_setup_samples_ms = Vec::with_capacity(config.iterations); - let mut startup_samples_ms = Vec::with_capacity(config.iterations); - let mut completion_samples_ms = Vec::with_capacity(config.iterations); - let mut resource_usage_samples = BenchmarkResourceUsage::>::default(); - - for _ in 0..config.iterations { - let sample = run_sample( - workspace, - &scenario, - compile_cache_root_for_strategy(scenario.compile_cache, &compile_cache_root), - shared_engine.as_mut(), - &mut shared_context, - )?; - wall_samples_ms.push(sample.wall_ms); - context_setup_samples_ms.push(sample.context_setup_ms); - startup_samples_ms.push(sample.startup_ms); - completion_samples_ms.push(sample.completion_ms); - - if let (Some(import_ms), Some(samples)) = - (sample.guest_import_ms, guest_import_samples_ms.as_mut()) - { - samples.push(import_ms); - } - if let Some(resource_usage) = sample.resource_usage.as_ref() { - resource_usage_samples.push_sample(resource_usage); - } - } - - let startup_overhead_samples_ms = guest_import_samples_ms.as_ref().map(|guest_samples| { - context_setup_samples_ms - .iter() - .zip(startup_samples_ms.iter()) - .zip(completion_samples_ms.iter()) - .zip(guest_samples.iter()) - .map(|(((context_ms, startup_ms), completion_ms), _guest_ms)| { - context_ms + startup_ms + completion_ms - }) - .collect::>() - }); - - let phase_samples_ms = BenchmarkScenarioPhases { - context_setup_ms: context_setup_samples_ms, - startup_ms: startup_samples_ms, - guest_execution_ms: guest_import_samples_ms.clone(), - completion_ms: completion_samples_ms, - }; - let resource_usage_samples = resource_usage_samples.into_populated(); - - Ok(BenchmarkScenarioReport { - id: scenario.id, - workload: scenario.workload, - runtime: scenario.runtime.label(), - mode: scenario.mode.label(), - description: scenario.description, - fixture: scenario.fixture, - compile_cache: scenario.compile_cache.label(), - wall_stats: compute_stats(&wall_samples_ms), - guest_import_stats: guest_import_samples_ms - .as_ref() - .map(|samples| compute_stats(samples)), - startup_overhead_stats: startup_overhead_samples_ms - .as_ref() - .map(|samples| compute_stats(samples)), - phase_stats: BenchmarkScenarioPhases { - context_setup_ms: compute_stats(&phase_samples_ms.context_setup_ms), - startup_ms: compute_stats(&phase_samples_ms.startup_ms), - guest_execution_ms: phase_samples_ms - .guest_execution_ms - .as_ref() - .map(|samples| compute_stats(samples)), - completion_ms: compute_stats(&phase_samples_ms.completion_ms), - }, - resource_usage_stats: resource_usage_samples - .as_ref() - .and_then(compute_resource_usage_stats), - wall_samples_ms, - guest_import_samples_ms, - startup_overhead_samples_ms, - phase_samples_ms, - resource_usage_samples, - }) -} - -fn compile_cache_root_for_strategy(strategy: CompileCacheStrategy, root: &Path) -> Option { - match strategy { - CompileCacheStrategy::Disabled => None, - CompileCacheStrategy::Primed => Some(root.to_path_buf()), - } -} - -fn run_sample( - workspace: &BenchmarkWorkspace, - scenario: &ScenarioDefinition, - compile_cache_root: Option, - shared_engine: Option<&mut JavascriptExecutionEngine>, - shared_context: &mut Option, -) -> Result { - match scenario.runtime { - ScenarioRuntime::NativeExecution => run_native_sample( - workspace, - scenario, - compile_cache_root, - shared_engine, - shared_context, - ), - ScenarioRuntime::HostNode => run_host_node_sample(workspace, scenario), - } -} - -fn run_native_sample( - workspace: &BenchmarkWorkspace, - scenario: &ScenarioDefinition, - compile_cache_root: Option, - shared_engine: Option<&mut JavascriptExecutionEngine>, - shared_context: &mut Option, -) -> Result { - let mut fresh_engine = JavascriptExecutionEngine::default(); - let engine = shared_engine.unwrap_or(&mut fresh_engine); - let context_started_at = Instant::now(); - let (context, context_setup_ms) = match scenario.engine_reuse { - EngineReuseStrategy::SharedContextAcrossScenario => { - if let Some(context) = shared_context.as_ref() { - (context.clone(), 0.0) - } else { - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-bench"), - bootstrap_module: None, - compile_cache_root, - }); - let context_setup_ms = context_started_at.elapsed().as_secs_f64() * 1000.0; - *shared_context = Some(context.clone()); - (context, context_setup_ms) - } - } - _ => { - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-bench"), - bootstrap_module: None, - compile_cache_root, - }); - let context_setup_ms = context_started_at.elapsed().as_secs_f64() * 1000.0; - (context, context_setup_ms) - } - }; - - let startup_started_at = Instant::now(); - let execution = engine.start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-bench"), - context_id: context.context_id, - argv: vec![String::from(scenario.entrypoint)], - env: scenario_env(workspace, scenario), - cwd: workspace.root.clone(), - wasm_module_bytes: None, - inline_code: None, - })?; - let startup_ms = startup_started_at.elapsed().as_secs_f64() * 1000.0; - - let completion_started_at = Instant::now(); - let result = execution.wait()?; - let completion_total_ms = completion_started_at.elapsed().as_secs_f64() * 1000.0; - let stdout = String::from_utf8(result.stdout)?; - let stderr = String::from_utf8(result.stderr)?; - - if result.exit_code != 0 { - return Err(JavascriptBenchmarkError::NonZeroExit { - scenario: scenario.id, - exit_code: result.exit_code, - stderr, - }); - } - - let parsed_metrics = - parse_benchmark_metrics(scenario.id, &stdout, scenario.expect_import_metric)?; - let guest_import_ms = parsed_metrics.import_ms; - let completion_ms = guest_import_ms - .map(|guest_ms| saturating_delta_ms(completion_total_ms, guest_ms)) - .unwrap_or(completion_total_ms); - let wall_ms = context_setup_ms + startup_ms + completion_total_ms; - - Ok(SampleMeasurement { - wall_ms, - guest_import_ms, - context_setup_ms, - startup_ms, - completion_ms, - resource_usage: parsed_metrics.resource_usage, - }) -} - -fn run_host_node_sample( - workspace: &BenchmarkWorkspace, - scenario: &ScenarioDefinition, -) -> Result { - let started_at = Instant::now(); - let output = Command::new(crate::host_node::node_binary()) - .arg(scenario.entrypoint) - .current_dir(&workspace.root) - .envs(scenario_env(workspace, scenario)) - .output()?; - let wall_ms = started_at.elapsed().as_secs_f64() * 1000.0; - let stdout = String::from_utf8(output.stdout)?; - let stderr = String::from_utf8(output.stderr)?; - - if !output.status.success() { - return Err(JavascriptBenchmarkError::NonZeroExit { - scenario: scenario.id, - exit_code: output.status.code().unwrap_or(-1), - stderr, - }); - } - - let parsed_metrics = - parse_benchmark_metrics(scenario.id, &stdout, scenario.expect_import_metric)?; - let guest_import_ms = parsed_metrics.import_ms; - let startup_ms = guest_import_ms - .map(|guest_ms| saturating_delta_ms(wall_ms, guest_ms)) - .unwrap_or(wall_ms); - - Ok(SampleMeasurement { - wall_ms, - guest_import_ms, - context_setup_ms: 0.0, - startup_ms, - completion_ms: 0.0, - resource_usage: parsed_metrics.resource_usage, - }) -} - -fn scenario_env( - workspace: &BenchmarkWorkspace, - scenario: &ScenarioDefinition, -) -> BTreeMap { - match scenario.env { - ScenarioEnvironment::None => BTreeMap::new(), - ScenarioEnvironment::ProjectedWorkspaceNodeModules => { - let projected_node_modules = workspace.repo_root.join("node_modules"); - let projected_node_modules_json = - serde_json::to_string(&vec![projected_node_modules.display().to_string()]) - .expect("serialize projected node_modules read path"); - let guest_path_mappings = serde_json::json!([{ - "guestPath": "/root/node_modules", - "hostPath": projected_node_modules.display().to_string(), - }]) - .to_string(); - - BTreeMap::from([ - ( - String::from("AGENTOS_EXTRA_FS_READ_PATHS"), - projected_node_modules_json, - ), - ( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - guest_path_mappings, - ), - ]) - } - } -} - -fn measure_transport_rtt( - workspace: &BenchmarkWorkspace, - config: &JavascriptBenchmarkConfig, -) -> Result, JavascriptBenchmarkError> { - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-transport"), - bootstrap_module: None, - compile_cache_root: None, - }); - let mut execution = engine.start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-transport"), - context_id: context.context_id, - argv: vec![String::from("./bench/transport-echo.mjs")], - env: BTreeMap::from([( - String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - )]), - cwd: workspace.root.clone(), - wasm_module_bytes: None, - inline_code: None, - })?; - - let mut stdout_buffer = String::new(); - let mut stderr_buffer = String::new(); - let mut reports = Vec::with_capacity(TRANSPORT_RTT_PAYLOAD_BYTES.len()); - - for payload_bytes in TRANSPORT_RTT_PAYLOAD_BYTES { - for warmup_index in 0..config.warmup_iterations { - let label = format!("warmup-{}-{warmup_index}", payload_bytes); - measure_transport_roundtrip( - &mut execution, - payload_bytes, - &label, - &mut stdout_buffer, - &mut stderr_buffer, - )?; - } - - let mut samples_ms = Vec::with_capacity(config.iterations); - for iteration in 0..config.iterations { - let label = format!("measure-{}-{iteration}", payload_bytes); - samples_ms.push(measure_transport_roundtrip( - &mut execution, - payload_bytes, - &label, - &mut stdout_buffer, - &mut stderr_buffer, - )?); - } - - reports.push(BenchmarkTransportRttReport { - channel: TRANSPORT_RTT_CHANNEL, - payload_bytes, - stats: compute_stats(&samples_ms), - samples_ms, - }); - } - - execution.close_stdin()?; - let result = execution.wait()?; - if result.exit_code != 0 { - stderr_buffer.push_str(&String::from_utf8(result.stderr)?); - return Err(JavascriptBenchmarkError::TransportProbeExited { - exit_code: result.exit_code, - stderr: stderr_buffer, - }); - } - - Ok(reports) -} - -fn measure_transport_roundtrip( - execution: &mut crate::JavascriptExecution, - payload_bytes: usize, - label: &str, - stdout_buffer: &mut String, - stderr_buffer: &mut String, -) -> Result { - let payload = transport_probe_payload(payload_bytes, label); - let expected_line = format!("{payload}\n"); - let started_at = Instant::now(); - execution.write_stdin(expected_line.as_bytes())?; - - loop { - if let Some(line) = take_complete_line(stdout_buffer) { - if line == payload { - return Ok(started_at.elapsed().as_secs_f64() * 1000.0); - } - return Err(JavascriptBenchmarkError::InvalidTransportProbeResponse { - payload_bytes, - expected: payload, - actual: line, - }); - } - - match execution.poll_event_blocking(TRANSPORT_POLL_TIMEOUT)? { - Some(crate::JavascriptExecutionEvent::Stdout(chunk)) => { - stdout_buffer.push_str(&String::from_utf8(chunk)?); - } - Some(crate::JavascriptExecutionEvent::Stderr(chunk)) => { - stderr_buffer.push_str(&String::from_utf8(chunk)?); - } - Some(crate::JavascriptExecutionEvent::SyncRpcRequest(request)) => { - return Err(JavascriptBenchmarkError::Execution( - JavascriptExecutionError::PendingSyncRpcRequest(request.id), - )); - } - Some(crate::JavascriptExecutionEvent::SignalState { .. }) => {} - Some(crate::JavascriptExecutionEvent::Exited(exit_code)) => { - return Err(JavascriptBenchmarkError::TransportProbeExited { - exit_code, - stderr: stderr_buffer.clone(), - }); - } - None => { - return Err(JavascriptBenchmarkError::TransportProbeTimeout { payload_bytes }); - } - } - } -} - -fn transport_probe_payload(payload_bytes: usize, label: &str) -> String { - if payload_bytes == 0 { - return format!("transport:{label}:"); - } - - let header = format!("transport:{label}:"); - let fill_len = payload_bytes.saturating_sub(header.len()); - format!("{header}{}", "x".repeat(fill_len)) -} - -fn take_complete_line(buffer: &mut String) -> Option { - let newline_index = buffer.find('\n')?; - let line = buffer[..newline_index].trim_end_matches('\r').to_owned(); - buffer.drain(..=newline_index); - Some(line) -} - -#[derive(Debug, Default, Deserialize)] -struct ParsedBenchmarkMetrics { - #[serde(default)] - import_ms: Option, - #[serde(default)] - resource_usage: Option>, -} - -fn parse_benchmark_metrics( - scenario_id: &'static str, - stdout: &str, - expect_import_metric: bool, -) -> Result { - let raw_value = stdout - .lines() - .rev() - .find_map(|line| line.strip_prefix(BENCHMARK_MARKER_PREFIX)) - .ok_or(JavascriptBenchmarkError::MissingBenchmarkMetric( - scenario_id, - ))? - .trim(); - - if let Ok(parsed) = serde_json::from_str::(raw_value) { - let has_resource_usage = match parsed.resource_usage.as_ref() { - Some(resource_usage) => !resource_usage.is_empty(), - None => false, - }; - if parsed.import_ms.is_some() || has_resource_usage { - if expect_import_metric && parsed.import_ms.is_none() { - return Err(JavascriptBenchmarkError::MissingBenchmarkMetric( - scenario_id, - )); - } - return Ok(parsed); - } - } - - raw_value - .parse::() - .map(|import_ms| ParsedBenchmarkMetrics { - import_ms: Some(import_ms), - resource_usage: None, - }) - .map_err(|_| JavascriptBenchmarkError::InvalidBenchmarkMetric { - scenario: scenario_id, - raw_value: raw_value.to_owned(), - }) -} - -fn workspace_root() -> Result { - let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - manifest_dir - .parent() - .and_then(Path::parent) - .map(Path::to_path_buf) - .ok_or(JavascriptBenchmarkError::InvalidWorkspaceRoot(manifest_dir)) -} - -fn load_benchmark_artifact( - baseline_path: &Path, -) -> Result { - let raw = fs::read_to_string(baseline_path)?; - serde_json::from_str(&raw).map_err(|err| JavascriptBenchmarkError::InvalidBaselineReport { - path: baseline_path.to_path_buf(), - message: err.to_string(), - }) -} - -fn benchmark_host() -> Result { - let node_binary = crate::host_node::node_binary(); - let output = Command::new(&node_binary) - .arg("--version") - .output() - .map_err(JavascriptBenchmarkError::NodeVersion)?; - let node_version = String::from_utf8(output.stdout)?; - - Ok(BenchmarkHost { - node_binary, - node_version, - os: env::consts::OS, - arch: env::consts::ARCH, - logical_cpus: std::thread::available_parallelism() - .map(usize::from) - .unwrap_or(1), - }) -} - -fn write_benchmark_workspace( - root: &Path, - repo_root: &Path, -) -> Result<(), JavascriptBenchmarkError> { - fs::create_dir_all(root.join("bench"))?; - fs::create_dir_all(root.join("bench/local-graph"))?; - let host_node_modules = repo_root.join("node_modules"); - let workspace_node_modules = root.join("node_modules"); - if host_node_modules.exists() && !workspace_node_modules.exists() { - std::os::unix::fs::symlink(&host_node_modules, &workspace_node_modules)?; - } - fs::write( - root.join("package.json"), - "{\n \"name\": \"secure-exec-execution-bench\",\n \"private\": true,\n \"type\": \"module\"\n}\n", - )?; - - for index in 0..LOCAL_GRAPH_MODULE_COUNT { - let path = root - .join("bench/local-graph") - .join(format!("mod-{index:02}.mjs")); - let source = if index == 0 { - String::from("export const value = 1;\n") - } else { - format!( - "import {{ value as previous }} from './mod-{previous:02}.mjs';\nexport const value = previous + {index};\n", - previous = index - 1 - ) - }; - fs::write(path, source)?; - } - - let final_value = local_graph_terminal_value(); - fs::write( - root.join("bench/local-graph/root.mjs"), - format!( - "import {{ value }} from './mod-{last:02}.mjs';\nexport {{ value }};\nexport const expected = {final_value};\n", - last = LOCAL_GRAPH_MODULE_COUNT - 1 - ), - )?; - fs::write( - root.join("bench/benchmark-metrics.mjs"), - benchmark_metrics_module_source(), - )?; - - fs::write( - root.join("bench/isolate-startup.mjs"), - resource_only_entrypoint_source("console.log('isolate-ready');"), - )?; - fs::write( - root.join("bench/cold-local-import.mjs"), - local_import_entrypoint_source(final_value), - )?; - fs::write( - root.join("bench/warm-local-import.mjs"), - local_import_entrypoint_source(final_value), - )?; - fs::write( - root.join("bench/builtin-import.mjs"), - timed_entrypoint_source( - "const [pathMod, fsMod, urlMod] = await Promise.all([\n import('node:path'),\n import('node:fs/promises'),\n import('node:url'),\n]);\nif (typeof pathMod.basename !== 'function' || typeof fsMod.readFile !== 'function' || typeof urlMod.pathToFileURL !== 'function') {\n throw new Error('builtin import fixture did not load expected exports');\n}", - ), - )?; - fs::write( - root.join("bench/hot-builtin-stream-import.mjs"), - single_import_entrypoint_source( - "node:stream", - "typeof imported.Readable === 'function'", - "node:stream import did not expose Readable", - ), - )?; - fs::write( - root.join("bench/hot-builtin-stream-web-import.mjs"), - single_import_entrypoint_source( - "node:stream/web", - "typeof imported.ReadableStream === 'function'", - "node:stream/web import did not expose ReadableStream", - ), - )?; - fs::write( - root.join("bench/hot-builtin-crypto-import.mjs"), - single_import_entrypoint_source( - "node:crypto", - "typeof imported.createHash === 'function'", - "node:crypto import did not expose createHash", - ), - )?; - fs::write( - root.join("bench/hot-builtin-zlib-import.mjs"), - single_import_entrypoint_source( - "node:zlib", - "typeof imported.gzipSync === 'function'", - "node:zlib import did not expose gzipSync", - ), - )?; - fs::write( - root.join("bench/hot-builtin-assert-import.mjs"), - single_import_entrypoint_source( - "node:assert/strict", - "typeof imported.strictEqual === 'function'", - "node:assert/strict import did not expose strictEqual", - ), - )?; - fs::write( - root.join("bench/hot-builtin-url-import.mjs"), - single_import_entrypoint_source( - "node:url", - "typeof imported.pathToFileURL === 'function'", - "node:url import did not expose pathToFileURL", - ), - )?; - fs::write( - root.join("bench/large-package-import.mjs"), - timed_entrypoint_source( - "const typescript = await import('typescript');\nif (typeof typescript.transpileModule !== 'function') {\n throw new Error('typescript import did not expose transpileModule');\n}", - ), - )?; - fs::write( - root.join("bench/hot-projected-package-file-import.mjs"), - projected_package_file_import_entrypoint_source(), - )?; - fs::write( - root.join("bench/projected-package-import.mjs"), - projected_package_import_entrypoint_source(), - )?; - fs::write( - root.join("bench/pdf-lib-startup.mjs"), - pdf_lib_startup_entrypoint_source(), - )?; - fs::write( - root.join("bench/jszip-startup.mjs"), - jszip_startup_entrypoint_source(), - )?; - fs::write( - root.join("bench/jszip-end-to-end.mjs"), - jszip_end_to_end_entrypoint_source(), - )?; - fs::write( - root.join("bench/jszip-repeated-session-compressed.mjs"), - jszip_repeated_session_compressed_entrypoint_source(), - )?; - fs::write( - root.join("bench/transport-echo.mjs"), - "process.stdin.setEncoding('utf8');\nlet buffered = '';\nconst flushLines = () => {\n let newlineIndex = buffered.indexOf('\\n');\n while (newlineIndex >= 0) {\n const line = buffered.slice(0, newlineIndex).replace(/\\r$/, '');\n buffered = buffered.slice(newlineIndex + 1);\n process.stdout.write(line);\n newlineIndex = buffered.indexOf('\\n');\n }\n};\nprocess.stdin.on('data', (chunk) => {\n buffered += chunk;\n flushLines();\n});\nprocess.stdin.on('end', () => {\n if (buffered.length > 0) {\n process.stdout.write(buffered.replace(/\\r$/, ''));\n }\n});\n", - )?; - - Ok(()) -} - -fn local_import_entrypoint_source(final_value: usize) -> String { - timed_entrypoint_source(&format!( - "const graph = await import('./local-graph/root.mjs');\nif (graph.value !== {final_value} || graph.expected !== {final_value}) {{\n throw new Error(`local graph import returned ${{\n graph.value\n }} instead of {final_value}`);\n}}" - )) -} - -fn single_import_entrypoint_source( - specifier: &str, - validation_expression: &str, - error_message: &str, -) -> String { - timed_entrypoint_source(&format!( - "const imported = await import('{specifier}');\nif (!({validation_expression})) {{\n throw new Error('{error_message}');\n}}" - )) -} - -fn projected_package_file_import_entrypoint_source() -> String { - timed_entrypoint_source( - "const typescriptModule = await import('../node_modules/typescript/lib/typescript.js');\nconst typescript = typescriptModule.default ?? typescriptModule;\nif (typeof typescript.transpileModule !== 'function') {\n throw new Error('projected package file import did not expose transpileModule');\n}", - ) -} - -fn projected_package_import_entrypoint_source() -> String { - timed_entrypoint_source( - "const typescriptModule = await import('../node_modules/typescript/lib/typescript.js');\nconst typescript = typescriptModule.default ?? typescriptModule;\nconst sourceFile = typescript.createSourceFile(\n 'bench.ts',\n 'const answer: number = 42;',\n typescript.ScriptTarget.ES2022,\n true,\n);\nif (\n typeof typescript.transpileModule !== 'function' ||\n typeof typescript.createSourceFile !== 'function' ||\n !sourceFile ||\n sourceFile.statements.length !== 1\n) {\n throw new Error('projected package import did not expose TypeScript compiler APIs');\n}", - ) -} - -fn pdf_lib_startup_entrypoint_source() -> String { - timed_entrypoint_source( - "const pdfLib = await import('pdf-lib');\nconst pdfDoc = await pdfLib.PDFDocument.create();\nconst page = pdfDoc.addPage([612, 792]);\nconst font = await pdfDoc.embedFont(pdfLib.StandardFonts.Helvetica);\npage.drawText('secure-exec pdf-lib benchmark', {\n x: 50,\n y: 750,\n font,\n size: 18,\n});\nif (pdfDoc.getPageCount() !== 1 || page.getSize().width !== 612) {\n throw new Error('pdf-lib fixture did not create the expected document');\n}", - ) -} - -fn jszip_startup_entrypoint_source() -> String { - timed_entrypoint_source( - "const jszipModule = await import('jszip');\nconst JSZip = jszipModule.default ?? jszipModule;\nconst zip = new JSZip();\nzip.file('README.txt', 'secure-exec benchmark archive');\nconst notes = zip.folder('notes');\nif (!notes) {\n throw new Error('jszip fixture failed to create nested folder');\n}\nnotes.file('todo.txt', 'benchmark staging payload');\nconst fileCount = Object.values(zip.files).filter((entry) => !entry.dir).length;\nif (typeof zip.generateAsync !== 'function' || fileCount !== 2) {\n throw new Error('jszip fixture did not stage the expected archive');\n}", - ) -} - -fn jszip_end_to_end_entrypoint_source() -> String { - timed_entrypoint_source( - "const jszipModule = await import('jszip');\nconst JSZip = jszipModule.default ?? jszipModule;\nconst zip = new JSZip();\nconst repeatedPayload = 'secure-exec benchmark payload '.repeat(512);\nzip.file('README.txt', repeatedPayload);\nconst notes = zip.folder('notes');\nif (!notes) {\n throw new Error('jszip end-to-end fixture failed to create notes folder');\n}\nnotes.file('todo.txt', 'complete the archive roundtrip');\nconst data = zip.folder('data');\nif (!data) {\n throw new Error('jszip end-to-end fixture failed to create data folder');\n}\ndata.file('payload.json', JSON.stringify({\n repeatedPayloadLength: repeatedPayload.length,\n mode: 'cold-end-to-end',\n}));\nconst archiveBytes = await zip.generateAsync({\n type: 'uint8array',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n});\nconst restored = await JSZip.loadAsync(archiveBytes);\nconst restoredFileCount = Object.values(restored.files).filter((entry) => !entry.dir).length;\nconst restoredReadme = await restored.file('README.txt')?.async('string');\nconst restoredTodo = await restored.file('notes/todo.txt')?.async('string');\nconst restoredPayload = await restored.file('data/payload.json')?.async('string');\nif (\n archiveBytes.byteLength >= repeatedPayload.length ||\n restoredFileCount !== 3 ||\n restoredReadme !== repeatedPayload ||\n restoredTodo !== 'complete the archive roundtrip' ||\n !restoredPayload?.includes('cold-end-to-end')\n) {\n throw new Error('jszip end-to-end fixture did not complete the compressed archive roundtrip');\n}", - ) -} - -fn jszip_repeated_session_compressed_entrypoint_source() -> String { - timed_entrypoint_source( - "const jszipModule = await import('jszip');\nconst JSZip = jszipModule.default ?? jszipModule;\nconst zip = new JSZip();\nconst repeatedPayload = 'secure-exec benchmark payload '.repeat(512);\nzip.file('README.txt', repeatedPayload);\nconst notes = zip.folder('notes');\nif (!notes) {\n throw new Error('jszip repeated-session fixture failed to create notes folder');\n}\nnotes.file('todo.txt', 'repeat this session workload');\nconst data = zip.folder('data');\nif (!data) {\n throw new Error('jszip repeated-session fixture failed to create data folder');\n}\ndata.file('payload.json', JSON.stringify({\n repeatedPayloadLength: repeatedPayload.length,\n repeatedSessions: true,\n}));\nconst archiveBytes = await zip.generateAsync({\n type: 'uint8array',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n});\nconst restored = await JSZip.loadAsync(archiveBytes);\nconst restoredFileCount = Object.values(restored.files).filter((entry) => !entry.dir).length;\nconst restoredReadme = await restored.file('README.txt')?.async('string');\nconst restoredTodo = await restored.file('notes/todo.txt')?.async('string');\nif (\n archiveBytes.byteLength >= repeatedPayload.length ||\n restoredFileCount !== 3 ||\n restoredReadme !== repeatedPayload ||\n restoredTodo !== 'repeat this session workload'\n) {\n throw new Error('jszip repeated-session fixture did not complete the compressed archive roundtrip');\n}", - ) -} - -fn benchmark_metrics_module_source() -> String { - format!( - "const BENCHMARK_MARKER_PREFIX = '{BENCHMARK_MARKER_PREFIX}';\n\nexport function emitBenchmarkMetrics(importMs) {{\n const memoryUsage = process.memoryUsage();\n const resourceUsage = typeof process.resourceUsage === 'function'\n ? process.resourceUsage()\n : null;\n const payload = {{\n resource_usage: {{\n rss_bytes: memoryUsage.rss,\n heap_used_bytes: memoryUsage.heapUsed,\n ...(resourceUsage\n ? {{\n cpu_user_us: resourceUsage.userCPUTime,\n cpu_system_us: resourceUsage.systemCPUTime,\n cpu_total_us: resourceUsage.userCPUTime + resourceUsage.systemCPUTime,\n }}\n : {{}}),\n }},\n }};\n\n if (typeof importMs === 'number') {{\n payload.import_ms = importMs;\n }}\n\n console.log(BENCHMARK_MARKER_PREFIX + JSON.stringify(payload));\n}}\n" - ) -} - -fn resource_only_entrypoint_source(body: &str) -> String { - format!( - "import {{ emitBenchmarkMetrics }} from './benchmark-metrics.mjs';\n{body}\nemitBenchmarkMetrics();\n" - ) -} - -fn timed_entrypoint_source(body: &str) -> String { - format!( - "import {{ performance }} from 'node:perf_hooks';\nimport {{ emitBenchmarkMetrics }} from './benchmark-metrics.mjs';\nconst started = performance.now();\n{body}\nemitBenchmarkMetrics(performance.now() - started);\n" - ) -} - -fn local_graph_terminal_value() -> usize { - let mut value = 1; - - for index in 1..LOCAL_GRAPH_MODULE_COUNT { - value += index; - } - - value -} - -fn compute_distribution_stats(samples: &[f64]) -> BenchmarkDistributionStats { - let mut sorted = samples.to_vec(); - sorted.sort_by(|a, b| a.total_cmp(b)); - let mean = sorted.iter().sum::() / sorted.len() as f64; - - BenchmarkDistributionStats { - mean, - p50: percentile(&sorted, 50.0), - p95: percentile(&sorted, 95.0), - min: *sorted.first().unwrap_or(&0.0), - max: *sorted.last().unwrap_or(&0.0), - stddev: standard_deviation(&sorted, mean), - } -} - -fn compute_stats(samples: &[f64]) -> BenchmarkStats { - let stats = compute_distribution_stats(samples); - - BenchmarkStats { - mean_ms: stats.mean, - p50_ms: stats.p50, - p95_ms: stats.p95, - min_ms: stats.min, - max_ms: stats.max, - stddev_ms: stats.stddev, - } -} - -fn compute_resource_usage_stats( - samples: &BenchmarkResourceUsage>, -) -> Option> { - let stats = BenchmarkResourceUsage { - rss_bytes: samples - .rss_bytes - .as_ref() - .map(|samples| compute_distribution_stats(samples)), - heap_used_bytes: samples - .heap_used_bytes - .as_ref() - .map(|samples| compute_distribution_stats(samples)), - cpu_user_us: samples - .cpu_user_us - .as_ref() - .map(|samples| compute_distribution_stats(samples)), - cpu_system_us: samples - .cpu_system_us - .as_ref() - .map(|samples| compute_distribution_stats(samples)), - cpu_total_us: samples - .cpu_total_us - .as_ref() - .map(|samples| compute_distribution_stats(samples)), - }; - - (!stats.is_empty()).then_some(stats) -} - -fn standard_deviation(samples: &[f64], mean: f64) -> f64 { - if samples.is_empty() { - return 0.0; - } - - let variance = samples - .iter() - .map(|sample| { - let delta = sample - mean; - delta * delta - }) - .sum::() - / samples.len() as f64; - - variance.sqrt() -} - -fn percentile(sorted: &[f64], p: f64) -> f64 { - if sorted.is_empty() { - return 0.0; - } - - let rank = ((p / 100.0) * sorted.len() as f64).ceil() as usize; - let index = rank.saturating_sub(1).min(sorted.len() - 1); - sorted[index] -} - -fn percentage_reduction(original: f64, current: f64) -> f64 { - if original <= 0.0 { - 0.0 - } else { - ((original - current) / original) * 100.0 - } -} - -fn percentage_share(part: f64, total: f64) -> f64 { - if total <= 0.0 { - 0.0 - } else { - (part / total) * 100.0 - } -} - -fn safe_ratio(lhs: f64, rhs: f64) -> f64 { - if rhs <= 0.0 { - 0.0 - } else { - lhs / rhs - } -} - -fn saturating_delta_ms(total_ms: f64, subtracted_ms: f64) -> f64 { - (total_ms - subtracted_ms).max(0.0) -} - -fn format_ms(value: f64) -> String { - format!("{value:.2}") -} - -fn format_hotspot_value(unit: &str, value: f64) -> String { - match unit { - "pct" => format!("{value:.1}%"), - "MiB" => format_mib(value), - _ => format_ms(value), - } -} - -fn format_sample_list(samples: &[f64]) -> String { - format_scaled_sample_list(samples, std::convert::identity) -} - -fn format_scaled_sample_list(samples: &[f64], scale: impl Fn(f64) -> f64) -> String { - let mut formatted = String::from("["); - - for (index, sample) in samples.iter().enumerate() { - if index > 0 { - formatted.push_str(", "); - } - let _ = write!(&mut formatted, "{:.2}", scale(*sample)); - } - - formatted.push(']'); - formatted -} - -fn format_mib(value: f64) -> String { - format!("{value:.2}") -} - -fn format_label_list(labels: &[&str]) -> String { - labels - .iter() - .map(|label| format!("`{label}`")) - .collect::>() - .join(", ") -} - -fn format_string_label_list(labels: &[&str]) -> String { - labels - .iter() - .map(|label| format!("`{label}`")) - .collect::>() - .join(", ") -} - -fn push_unique_label<'a>(labels: &mut Vec<&'a str>, value: &'a str) { - if !labels.contains(&value) { - labels.push(value); - } -} - -fn format_delta_ms(value: f64) -> String { - format!("{value:+.2}") -} - -fn format_delta_pct(value: f64) -> String { - format!("{value:+.1}%") -} - -fn push_optional_sample(samples: &mut Option>, value: Option) { - if let Some(value) = value { - samples.get_or_insert_with(Vec::new).push(value); - } -} - -fn bytes_to_mib(value: f64) -> f64 { - value / (1024.0 * 1024.0) -} - -fn micros_to_ms(value: f64) -> f64 { - value / 1000.0 -} - -fn hotspot_wall_mean_ms(scenario: &BenchmarkScenarioReport) -> Option { - Some(scenario.wall_stats.mean_ms) -} - -fn hotspot_wall_stddev_ms(scenario: &BenchmarkScenarioReport) -> Option { - Some(scenario.wall_stats.stddev_ms) -} - -fn hotspot_wall_range_ms(scenario: &BenchmarkScenarioReport) -> Option { - Some(scenario.wall_range_ms()) -} - -fn hotspot_guest_import_mean_ms(scenario: &BenchmarkScenarioReport) -> Option { - scenario - .guest_import_stats - .as_ref() - .map(|stats| stats.mean_ms) -} - -fn hotspot_startup_overhead_mean_ms(scenario: &BenchmarkScenarioReport) -> Option { - scenario - .startup_overhead_stats - .as_ref() - .map(|stats| stats.mean_ms) -} - -fn hotspot_context_setup_mean_ms(scenario: &BenchmarkScenarioReport) -> Option { - Some(scenario.phase_stats.context_setup_ms.mean_ms) -} - -fn hotspot_startup_phase_mean_ms(scenario: &BenchmarkScenarioReport) -> Option { - Some(scenario.phase_stats.startup_ms.mean_ms) -} - -fn hotspot_guest_execution_mean_ms(scenario: &BenchmarkScenarioReport) -> Option { - scenario - .phase_stats - .guest_execution_ms - .as_ref() - .map(|stats| stats.mean_ms) -} - -fn hotspot_completion_mean_ms(scenario: &BenchmarkScenarioReport) -> Option { - Some(scenario.phase_stats.completion_ms.mean_ms) -} - -fn hotspot_startup_share_pct(scenario: &BenchmarkScenarioReport) -> Option { - scenario.mean_startup_share_pct() -} - -fn hotspot_rss_mean_mib(scenario: &BenchmarkScenarioReport) -> Option { - scenario - .resource_usage_stats - .as_ref()? - .rss_bytes - .as_ref() - .map(|stats| bytes_to_mib(stats.mean)) -} - -fn hotspot_heap_mean_mib(scenario: &BenchmarkScenarioReport) -> Option { - scenario - .resource_usage_stats - .as_ref()? - .heap_used_bytes - .as_ref() - .map(|stats| bytes_to_mib(stats.mean)) -} - -fn hotspot_total_cpu_mean_ms(scenario: &BenchmarkScenarioReport) -> Option { - scenario - .resource_usage_stats - .as_ref()? - .cpu_total_us - .as_ref() - .map(|stats| micros_to_ms(stats.mean)) -} - -#[cfg(test)] -mod tests { - use super::*; - use std::cell::RefCell; - use tempfile::tempdir; - - fn synthetic_transport_reports() -> Vec { - TRANSPORT_RTT_PAYLOAD_BYTES - .iter() - .enumerate() - .map(|(index, payload_bytes)| { - let sample = index as f64 + 1.0; - BenchmarkTransportRttReport { - channel: TRANSPORT_RTT_CHANNEL, - payload_bytes: *payload_bytes, - samples_ms: vec![sample], - stats: compute_stats(&[sample]), - } - }) - .collect() - } - - fn synthetic_scenario_report( - definition: ScenarioDefinition, - wall_sample_ms: f64, - ) -> BenchmarkScenarioReport { - let context_setup_ms = wall_sample_ms / 5.0; - let startup_ms = wall_sample_ms / 4.0; - let guest_execution_ms = definition - .expect_import_metric - .then_some(wall_sample_ms / 3.0); - let completion_ms = - wall_sample_ms - context_setup_ms - startup_ms - guest_execution_ms.unwrap_or(0.0); - let startup_overhead_ms = definition - .expect_import_metric - .then_some(context_setup_ms + startup_ms + completion_ms); - let resource_usage_samples = BenchmarkResourceUsage { - rss_bytes: Some(vec![64.0 * 1024.0 * 1024.0]), - heap_used_bytes: Some(vec![12.0 * 1024.0 * 1024.0]), - cpu_user_us: None, - cpu_system_us: None, - cpu_total_us: Some(vec![wall_sample_ms * 1000.0]), - }; - - BenchmarkScenarioReport { - id: definition.id, - workload: definition.workload, - runtime: definition.runtime.label(), - mode: definition.mode.label(), - description: definition.description, - fixture: definition.fixture, - compile_cache: definition.compile_cache.label(), - wall_samples_ms: vec![wall_sample_ms], - wall_stats: compute_stats(&[wall_sample_ms]), - guest_import_samples_ms: guest_execution_ms.map(|sample| vec![sample]), - guest_import_stats: guest_execution_ms.map(|sample| compute_stats(&[sample])), - startup_overhead_samples_ms: startup_overhead_ms.map(|sample| vec![sample]), - startup_overhead_stats: startup_overhead_ms.map(|sample| compute_stats(&[sample])), - phase_samples_ms: BenchmarkScenarioPhases { - context_setup_ms: vec![context_setup_ms], - startup_ms: vec![startup_ms], - guest_execution_ms: guest_execution_ms.map(|sample| vec![sample]), - completion_ms: vec![completion_ms], - }, - phase_stats: BenchmarkScenarioPhases { - context_setup_ms: compute_stats(&[context_setup_ms]), - startup_ms: compute_stats(&[startup_ms]), - guest_execution_ms: guest_execution_ms.map(|sample| compute_stats(&[sample])), - completion_ms: compute_stats(&[completion_ms]), - }, - resource_usage_stats: compute_resource_usage_stats(&resource_usage_samples), - resource_usage_samples: Some(resource_usage_samples), - } - } - - fn synthetic_host() -> BenchmarkHost { - BenchmarkHost { - node_binary: String::from("node"), - node_version: String::from("v22.0.0"), - os: "linux", - arch: "x86_64", - logical_cpus: 8, - } - } - - #[test] - fn javascript_benchmark_config_rejects_unbounded_iteration_counts() { - assert!(matches!( - validate_benchmark_config(&JavascriptBenchmarkConfig { - iterations: 0, - warmup_iterations: 0, - }), - Err(JavascriptBenchmarkError::InvalidConfig( - "iterations must be greater than zero" - )) - )); - assert!(matches!( - validate_benchmark_config(&JavascriptBenchmarkConfig { - iterations: MAX_BENCHMARK_ITERATIONS + 1, - warmup_iterations: 0, - }), - Err(JavascriptBenchmarkError::InvalidConfig( - "iterations must be less than or equal to 1000" - )) - )); - assert!(matches!( - validate_benchmark_config(&JavascriptBenchmarkConfig { - iterations: 1, - warmup_iterations: MAX_BENCHMARK_WARMUP_ITERATIONS + 1, - }), - Err(JavascriptBenchmarkError::InvalidConfig( - "warmup iterations must be less than or equal to 1000" - )) - )); - } - - #[test] - fn javascript_benchmark_orchestration_resumes_completed_stages_from_run_state() { - let tempdir = tempdir().expect("create tempdir"); - let repo_root = tempdir.path().join("repo"); - let artifact_dir = tempdir.path().join("artifacts"); - fs::create_dir_all(&repo_root).expect("create repo root"); - - let config = JavascriptBenchmarkConfig { - iterations: 1, - warmup_iterations: 0, - }; - let host = synthetic_host(); - let definitions = benchmark_scenarios(); - let mut state = StoredBenchmarkRunState::new(&config, &host, &repo_root); - state.record_transport_rtt(&synthetic_transport_reports()); - state.record_scenario(&synthetic_scenario_report(definitions[0], 10.0)); - persist_benchmark_run_state(&benchmark_run_state_path(&artifact_dir), &state) - .expect("persist initial run state"); - - let transport_calls = RefCell::new(0usize); - let scenario_calls = RefCell::new(Vec::new()); - let (report, resumed_stage_count, _) = orchestrate_javascript_benchmark_report( - &config, - &repo_root, - &host, - &artifact_dir, - || { - *transport_calls.borrow_mut() += 1; - Ok(synthetic_transport_reports()) - }, - |definition| { - scenario_calls.borrow_mut().push(definition.id.to_owned()); - Ok(synthetic_scenario_report(definition, 20.0)) - }, - ) - .expect("resume benchmark orchestration"); - - assert_eq!(resumed_stage_count, 2); - assert_eq!(*transport_calls.borrow(), 0); - assert_eq!( - scenario_calls.borrow().as_slice(), - &definitions[1..] - .iter() - .map(|definition| definition.id.to_owned()) - .collect::>() - ); - assert_eq!( - report.transport_rtt.len(), - TRANSPORT_RTT_PAYLOAD_BYTES.len() - ); - assert_eq!(report.scenarios.len(), definitions.len()); - assert_eq!(report.scenarios[0].id, definitions[0].id); - assert_eq!(report.scenarios[1].id, definitions[1].id); - } - - #[test] - fn javascript_benchmark_orchestration_persists_completed_stages_before_failure() { - let tempdir = tempdir().expect("create tempdir"); - let repo_root = tempdir.path().join("repo"); - let artifact_dir = tempdir.path().join("artifacts"); - fs::create_dir_all(&repo_root).expect("create repo root"); - - let config = JavascriptBenchmarkConfig { - iterations: 1, - warmup_iterations: 0, - }; - let host = synthetic_host(); - let state_path = benchmark_run_state_path(&artifact_dir); - let failure = orchestrate_javascript_benchmark_report( - &config, - &repo_root, - &host, - &artifact_dir, - || Ok(synthetic_transport_reports()), - |definition| { - if definition.id == "cold-local-import" { - Err(JavascriptBenchmarkError::InvalidConfig("synthetic failure")) - } else { - Ok(synthetic_scenario_report(definition, 15.0)) - } - }, - ) - .expect_err("expected synthetic orchestration failure"); - - assert!(matches!( - failure, - JavascriptBenchmarkError::InvalidConfig("synthetic failure") - )); - - let stored_state = serde_json::from_str::( - &fs::read_to_string(&state_path).expect("read persisted run state"), - ) - .expect("parse persisted run state"); - assert!(stored_state.transport_rtt.is_some()); - assert_eq!( - stored_state - .scenarios - .iter() - .map(|scenario| scenario.id.as_str()) - .collect::>(), - vec!["isolate-startup", "prewarmed-isolate-startup"] - ); - } -} diff --git a/crates/execution/src/bin/node-import-bench.rs b/crates/execution/src/bin/node-import-bench.rs deleted file mode 100644 index b85e613bb..000000000 --- a/crates/execution/src/bin/node-import-bench.rs +++ /dev/null @@ -1,108 +0,0 @@ -use secure_exec_execution::benchmark::{ - run_javascript_benchmarks_with_recovery, JavascriptBenchmarkConfig, -}; -use std::path::PathBuf; - -struct CliConfig { - benchmark: JavascriptBenchmarkConfig, - baseline_path: Option, -} - -fn main() { - match parse_config(std::env::args().skip(1)) { - Ok(cli_config) => match run_javascript_benchmarks_with_recovery( - &cli_config.benchmark, - cli_config.baseline_path.as_deref(), - ) { - Ok(output) => { - if output.resumed_stage_count > 0 { - eprintln!( - "Resumed {} completed benchmark stages from {}", - output.resumed_stage_count, - output - .artifact_paths - .json_path - .parent() - .expect("benchmark artifact parent directory") - .join("run-state.json") - .display() - ); - } - if let Some(path) = &cli_config.baseline_path { - eprintln!("Compared against baseline {}", path.display()); - } - eprintln!( - "Wrote Markdown report to {}", - output.artifact_paths.markdown_path.display() - ); - eprintln!( - "Wrote JSON report to {}", - output.artifact_paths.json_path.display() - ); - match std::fs::read_to_string(&output.artifact_paths.markdown_path) { - Ok(markdown) => print!("{markdown}"), - Err(err) => { - eprintln!("failed to read generated markdown report: {err}"); - std::process::exit(1); - } - } - } - Err(err) => { - eprintln!("{err}"); - std::process::exit(1); - } - }, - Err(err) => { - eprintln!("{err}"); - eprintln!(); - eprintln!("Usage: cargo run -p secure-exec-execution --bin node-import-bench -- [--iterations N] [--warmup-iterations N] [--baseline PATH]"); - std::process::exit(2); - } - } -} - -fn parse_config(args: impl IntoIterator) -> Result { - let mut benchmark = JavascriptBenchmarkConfig::default(); - let mut baseline_path = None; - let mut args = args.into_iter(); - - while let Some(arg) = args.next() { - match arg.as_str() { - "--iterations" => { - let value = args - .next() - .ok_or_else(|| String::from("missing value for --iterations"))?; - benchmark.iterations = parse_usize_flag("--iterations", &value)?; - } - "--warmup-iterations" => { - let value = args - .next() - .ok_or_else(|| String::from("missing value for --warmup-iterations"))?; - benchmark.warmup_iterations = parse_usize_flag("--warmup-iterations", &value)?; - } - "--baseline" => { - let value = args - .next() - .ok_or_else(|| String::from("missing value for --baseline"))?; - baseline_path = Some(PathBuf::from(value)); - } - "--help" | "-h" => { - return Err(String::from("help requested")); - } - unknown => { - return Err(format!("unknown argument: {unknown}")); - } - } - } - - Ok(CliConfig { - benchmark, - baseline_path, - }) -} - -fn parse_usize_flag(flag: &str, value: &str) -> Result { - value - .parse::() - .map_err(|_| format!("invalid value for {flag}: {value}")) -} diff --git a/crates/execution/src/common.rs b/crates/execution/src/common.rs deleted file mode 100644 index a66c93910..000000000 --- a/crates/execution/src/common.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::collections::BTreeMap; -use std::fmt::Write as _; -use std::time::{SystemTime, UNIX_EPOCH}; - -pub(crate) fn frozen_time_ms() -> u128 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system clock before unix epoch") - .as_millis() -} - -pub(crate) fn stable_hash64(bytes: &[u8]) -> u64 { - let mut hash = 0xcbf29ce484222325_u64; - - for byte in bytes { - hash ^= u64::from(*byte); - hash = hash.wrapping_mul(0x100000001b3); - } - - hash -} - -pub(crate) fn encode_json_string_array(values: &[String]) -> String { - let mut json = String::from("["); - - for (index, value) in values.iter().enumerate() { - if index > 0 { - json.push(','); - } - json.push_str(&encode_json_string(value)); - } - - json.push(']'); - json -} - -pub(crate) fn encode_json_string_map(values: &BTreeMap) -> String { - let mut json = String::from("{"); - - for (index, (key, value)) in values.iter().enumerate() { - if index > 0 { - json.push(','); - } - json.push_str(&encode_json_string(key)); - json.push(':'); - json.push_str(&encode_json_string(value)); - } - - json.push('}'); - json -} - -pub(crate) fn encode_json_string(value: &str) -> String { - let mut json = String::with_capacity(value.len() + 2); - json.push('"'); - - for ch in value.chars() { - match ch { - '"' => json.push_str("\\\""), - '\\' => json.push_str("\\\\"), - '\n' => json.push_str("\\n"), - '\r' => json.push_str("\\r"), - '\t' => json.push_str("\\t"), - '\u{08}' => json.push_str("\\b"), - '\u{0C}' => json.push_str("\\f"), - ch if ch.is_control() || u32::from(ch) > 0xFFFF => { - push_utf16_escape(&mut json, ch); - } - ch => json.push(ch), - } - } - - json.push('"'); - json -} - -fn push_utf16_escape(json: &mut String, ch: char) { - let mut units = [0_u16; 2]; - for unit in ch.encode_utf16(&mut units).iter() { - let _ = write!(json, "\\u{:04x}", unit); - } -} - -#[cfg(test)] -mod tests { - use super::encode_json_string; - - #[test] - fn encode_json_string_escapes_non_bmp_as_surrogate_pairs() { - assert_eq!(encode_json_string("emoji: 😀"), r#""emoji: \ud83d\ude00""#); - } -} diff --git a/crates/execution/src/host_node.rs b/crates/execution/src/host_node.rs deleted file mode 100644 index af5f96011..000000000 --- a/crates/execution/src/host_node.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::path::{Path, PathBuf}; - -const NODE_BINARY_ENV: &str = "AGENTOS_NODE_BINARY"; -const DEFAULT_NODE_BINARY: &str = "node"; - -pub(crate) fn node_binary() -> String { - let configured = - std::env::var(NODE_BINARY_ENV).unwrap_or_else(|_| String::from(DEFAULT_NODE_BINARY)); - resolve_executable_path(&configured).unwrap_or(configured) -} - -fn resolve_executable_path(binary: &str) -> Option { - let path = Path::new(binary); - if path.is_absolute() || binary.contains(std::path::MAIN_SEPARATOR) { - return Some(path.to_string_lossy().into_owned()); - } - - let path_env = std::env::var_os("PATH")?; - for directory in std::env::split_paths(&path_env) { - let candidate: PathBuf = directory.join(binary); - if candidate.is_file() { - return Some(candidate.to_string_lossy().into_owned()); - } - } - - None -} diff --git a/crates/execution/src/javascript.rs b/crates/execution/src/javascript.rs deleted file mode 100644 index d83ed63b7..000000000 --- a/crates/execution/src/javascript.rs +++ /dev/null @@ -1,7818 +0,0 @@ -use crate::common::stable_hash64; -use crate::node_import_cache::{ - NodeImportCache, NodeImportCacheCleanup, NODE_IMPORT_CACHE_ASSET_ROOT_ENV, -}; -use crate::runtime_support::{ - NODE_COMPILE_CACHE_ENV, NODE_DISABLE_COMPILE_CACHE_ENV, NODE_FROZEN_TIME_ENV, - NODE_SANDBOX_ROOT_ENV, -}; -use crate::signal::NodeSignalHandlerRegistration; -use crate::v8_host::{V8RuntimeHost, V8SessionHandle}; -use crate::v8_ipc::BinaryFrame; -use crate::v8_runtime; -use getrandom::getrandom; -use secure_exec_bridge::queue_tracker::{register_queue, TrackedLimit, TrackedReceiver}; -use secure_exec_v8_runtime::runtime_protocol::{RuntimeCommand, WarmSessionHint}; -use serde::Deserialize; -use serde::Serialize; -use serde_json::{json, Value}; -use std::cmp::Reverse; -use std::collections::{BTreeMap, BinaryHeap, HashMap, HashSet, VecDeque}; -use std::fmt; -use std::fs::{self, File}; -use std::io::{BufRead, BufReader, BufWriter, Write}; -use std::os::fd::OwnedFd; -use std::panic::{catch_unwind, AssertUnwindSafe}; -use std::path::{Path, PathBuf}; -use std::sync::{ - atomic::{AtomicU64, Ordering}, - mpsc::{self, Receiver, SyncSender, TrySendError}, - Arc, Condvar, Mutex, OnceLock, -}; -use std::thread; -use std::time::{Duration, Instant}; -use tokio::sync::{ - mpsc::{channel, error::TryRecvError as TokioTryRecvError, Receiver as TokioReceiver}, - Notify, -}; -use tokio::time; - -const NODE_ENTRYPOINT_ENV: &str = "AGENTOS_ENTRYPOINT"; -const NODE_BOOTSTRAP_ENV: &str = "AGENTOS_BOOTSTRAP_MODULE"; -const NODE_GUEST_ARGV_ENV: &str = "AGENTOS_GUEST_ARGV"; -const NODE_PREWARM_IMPORTS_ENV: &str = "AGENTOS_NODE_PREWARM_IMPORTS"; -const NODE_IMPORT_COMPILE_CACHE_NAMESPACE_VERSION: &str = "3"; -const NODE_IMPORT_CACHE_LOADER_PATH_ENV: &str = "AGENTOS_NODE_IMPORT_CACHE_LOADER_PATH"; -const NODE_IMPORT_CACHE_PATH_ENV: &str = "AGENTOS_NODE_IMPORT_CACHE_PATH"; -const NODE_KEEP_STDIN_OPEN_ENV: &str = "SECURE_EXEC_KEEP_STDIN_OPEN"; -const NODE_GUEST_ENTRYPOINT_ENV: &str = "AGENTOS_GUEST_ENTRYPOINT"; -const NODE_GUEST_ENTRYPOINT_MODULE_MODE_ENV: &str = "AGENTOS_GUEST_ENTRYPOINT_MODULE_MODE"; -const NODE_GUEST_PATH_MAPPINGS_ENV: &str = "AGENTOS_GUEST_PATH_MAPPINGS"; -const NODE_VIRTUAL_PROCESS_EXEC_PATH_ENV: &str = "AGENTOS_VIRTUAL_PROCESS_EXEC_PATH"; -const NODE_VIRTUAL_PROCESS_PID_ENV: &str = "AGENTOS_VIRTUAL_PROCESS_PID"; -const NODE_VIRTUAL_PROCESS_PPID_ENV: &str = "AGENTOS_VIRTUAL_PROCESS_PPID"; -const NODE_VIRTUAL_PROCESS_UID_ENV: &str = "AGENTOS_VIRTUAL_PROCESS_UID"; -const NODE_VIRTUAL_PROCESS_GID_ENV: &str = "AGENTOS_VIRTUAL_PROCESS_GID"; -const NODE_PARENT_ALLOW_CHILD_PROCESS_ENV: &str = "AGENTOS_PARENT_NODE_ALLOW_CHILD_PROCESS"; -const NODE_PARENT_ALLOW_WORKER_ENV: &str = "AGENTOS_PARENT_NODE_ALLOW_WORKER"; -const NODE_EXTRA_FS_READ_PATHS_ENV: &str = "AGENTOS_EXTRA_FS_READ_PATHS"; -const NODE_EXTRA_FS_WRITE_PATHS_ENV: &str = "AGENTOS_EXTRA_FS_WRITE_PATHS"; -const NODE_ALLOWED_BUILTINS_ENV: &str = "AGENTOS_ALLOWED_NODE_BUILTINS"; -const NODE_LOOPBACK_EXEMPT_PORTS_ENV: &str = "AGENTOS_LOOPBACK_EXEMPT_PORTS"; -const NODE_SYNC_RPC_ENABLE_ENV: &str = "AGENTOS_NODE_SYNC_RPC_ENABLE"; -const NODE_SYNC_RPC_REQUEST_FD_ENV: &str = "AGENTOS_NODE_SYNC_RPC_REQUEST_FD"; -const NODE_SYNC_RPC_RESPONSE_FD_ENV: &str = "AGENTOS_NODE_SYNC_RPC_RESPONSE_FD"; -const NODE_SYNC_RPC_DATA_BYTES_ENV: &str = "AGENTOS_NODE_SYNC_RPC_DATA_BYTES"; -const NODE_SYNC_RPC_WAIT_TIMEOUT_MS_ENV: &str = "AGENTOS_NODE_SYNC_RPC_WAIT_TIMEOUT_MS"; -static NEXT_V8_SESSION_ID: AtomicU64 = AtomicU64::new(1); -static JAVASCRIPT_TIMER_WHEEL: OnceLock> = OnceLock::new(); - -#[derive(Default)] -struct JsStartPhaseStats { - calls: u64, - total_ns: u128, - max_ns: u128, -} - -static JS_START_PHASES: OnceLock>> = OnceLock::new(); -static JS_EVENT_PHASES: OnceLock>> = OnceLock::new(); - -fn js_start_phases_enabled() -> bool { - std::env::var("AGENTOS_JS_START_PHASES").as_deref() == Ok("1") -} - -fn js_event_phases_enabled() -> bool { - std::env::var("AGENTOS_JS_EVENT_PHASES").as_deref() == Ok("1") -} - -fn record_js_start_phase(stage: &str, elapsed: Duration) { - if !js_start_phases_enabled() { - return; - } - record_js_phase_stats( - &JS_START_PHASES, - "AGENTOS_JS_START_PHASES_FILE", - stage, - elapsed, - ); -} - -fn record_js_event_phase(stage: &str, elapsed: Duration) { - if !js_event_phases_enabled() { - return; - } - record_js_phase_stats( - &JS_EVENT_PHASES, - "AGENTOS_JS_EVENT_PHASES_FILE", - stage, - elapsed, - ); -} - -fn record_js_phase_stats( - phases: &OnceLock>>, - path_env: &str, - stage: &str, - elapsed: Duration, -) { - let phases = phases.get_or_init(|| Mutex::new(BTreeMap::new())); - let Ok(mut phases) = phases.lock() else { - return; - }; - let stats = phases.entry(stage.to_string()).or_default(); - stats.calls += 1; - let elapsed_ns = elapsed.as_nanos(); - stats.total_ns += elapsed_ns; - stats.max_ns = stats.max_ns.max(elapsed_ns); - - let Some(path) = std::env::var_os(path_env) else { - return; - }; - let mut output = String::new(); - for (stage, stats) in phases.iter() { - let total_us = stats.total_ns / 1_000; - let avg_us = if stats.calls == 0 { - 0 - } else { - total_us / u128::from(stats.calls) - }; - let max_us = stats.max_ns / 1_000; - output.push_str(&format!( - "stage={stage} calls={} total_us={total_us} avg_us={avg_us} max_us={max_us}\n", - stats.calls - )); - } - let _ = fs::write(path, output); -} - -const DEFAULT_V8_CPU_TIME_LIMIT_MS: u32 = 30_000; -const DEFAULT_V8_WALL_CLOCK_LIMIT_MS: u32 = 0; -const DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT_MS: u64 = 30_000; -const NODE_SYNC_RPC_DEFAULT_DATA_BYTES: usize = 4 * 1024 * 1024; -const NODE_SYNC_RPC_DEFAULT_WAIT_TIMEOUT_MS: u64 = 30_000; -const NODE_SYNC_RPC_RESPONSE_QUEUE_CAPACITY: usize = 1; -const FORWARD_KERNEL_STDIN_RPC_ENV: &str = "AGENTOS_FORWARD_KERNEL_STDIN_RPC"; -// Defense-in-depth headroom: a transient burst of guest events (e.g. a chatty -// tool/skill turn) should be absorbed by the buffer, so the producer only ever -// hits backpressure under a genuinely stuck consumer rather than on every spike. -const JAVASCRIPT_EVENT_CHANNEL_CAPACITY: usize = 512; -const JAVASCRIPT_EVENT_PAYLOAD_LIMIT_BYTES: usize = 1024 * 1024; -const JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES: usize = 16 * 1024 * 1024; -const KERNEL_STDIN_BUFFER_LIMIT_BYTES: usize = 16 * 1024 * 1024; -const NODE_WARMUP_MARKER_VERSION: &str = "1"; -const NODE_WARMUP_SPECIFIERS: &[&str] = &[ - "secure-exec:builtin/path", - "secure-exec:builtin/url", - "secure-exec:builtin/fs-promises", - "secure-exec:polyfill/path", -]; - -#[derive(Debug, Default, Clone)] -struct SyncBridgePhaseStats { - calls: u64, - total_us: u64, - max_us: u64, -} - -static SYNC_BRIDGE_PHASES: OnceLock>> = - OnceLock::new(); -static SYNC_BRIDGE_REQUEST_ENQUEUED: OnceLock>> = - OnceLock::new(); - -fn sync_bridge_phases_enabled() -> bool { - std::env::var("AGENTOS_SYNC_BRIDGE_PHASES").as_deref() == Ok("1") -} - -fn record_sync_bridge_phase(method: &str, stage: &str, elapsed: Duration) { - if !sync_bridge_phases_enabled() { - return; - } - let stats = SYNC_BRIDGE_PHASES.get_or_init(|| Mutex::new(BTreeMap::new())); - let Ok(mut stats) = stats.lock() else { - return; - }; - let elapsed_us = elapsed.as_micros() as u64; - let key = format!("{method}:{stage}"); - let entry = stats.entry(key).or_default(); - entry.calls += 1; - entry.total_us = entry.total_us.wrapping_add(elapsed_us); - entry.max_us = entry.max_us.max(elapsed_us); - - if let Ok(path) = std::env::var("AGENTOS_SYNC_BRIDGE_PHASES_FILE") { - let mut lines = String::new(); - for (key, value) in stats.iter() { - let Some((method, stage)) = key.split_once(':') else { - continue; - }; - let avg_us = value.total_us.checked_div(value.calls).unwrap_or(0); - lines.push_str(&format!( - "method={method} stage={stage} calls={} total_us={} avg_us={} max_us={}\n", - value.calls, value.total_us, avg_us, value.max_us - )); - } - let _ = fs::write(path, lines); - } -} - -pub fn record_sync_bridge_request_enqueued(call_id: u64, method: &str) { - if !sync_bridge_phases_enabled() { - return; - } - let requests = SYNC_BRIDGE_REQUEST_ENQUEUED.get_or_init(|| Mutex::new(HashMap::new())); - let Ok(mut requests) = requests.lock() else { - return; - }; - if requests.len() > 4096 { - requests.clear(); - } - requests.insert(call_id, (method.to_owned(), Instant::now())); -} - -pub fn record_sync_bridge_request_observed(call_id: u64, fallback_method: &str) { - if !sync_bridge_phases_enabled() { - return; - } - let Some(requests) = SYNC_BRIDGE_REQUEST_ENQUEUED.get() else { - return; - }; - let Ok(mut requests) = requests.lock() else { - return; - }; - let Some((method, started)) = requests.remove(&call_id) else { - return; - }; - let method = if method.is_empty() { - fallback_method - } else { - method.as_str() - }; - record_sync_bridge_phase(method, "request_service_observed", started.elapsed()); -} -const CONTROLLED_STDERR_PREFIXES: &[&str] = - &[crate::node_import_cache::NODE_IMPORT_CACHE_METRICS_PREFIX]; -const RESERVED_NODE_ENV_KEYS: &[&str] = &[ - NODE_BOOTSTRAP_ENV, - NODE_COMPILE_CACHE_ENV, - NODE_DISABLE_COMPILE_CACHE_ENV, - NODE_ENTRYPOINT_ENV, - NODE_EXTRA_FS_READ_PATHS_ENV, - NODE_EXTRA_FS_WRITE_PATHS_ENV, - NODE_SANDBOX_ROOT_ENV, - NODE_FROZEN_TIME_ENV, - NODE_GUEST_ENTRYPOINT_ENV, - NODE_GUEST_ENTRYPOINT_MODULE_MODE_ENV, - NODE_GUEST_ARGV_ENV, - NODE_GUEST_PATH_MAPPINGS_ENV, - NODE_VIRTUAL_PROCESS_EXEC_PATH_ENV, - NODE_VIRTUAL_PROCESS_PID_ENV, - NODE_VIRTUAL_PROCESS_PPID_ENV, - NODE_VIRTUAL_PROCESS_UID_ENV, - NODE_VIRTUAL_PROCESS_GID_ENV, - NODE_PARENT_ALLOW_CHILD_PROCESS_ENV, - NODE_PARENT_ALLOW_WORKER_ENV, - NODE_IMPORT_CACHE_ASSET_ROOT_ENV, - NODE_IMPORT_CACHE_LOADER_PATH_ENV, - NODE_IMPORT_CACHE_PATH_ENV, - NODE_KEEP_STDIN_OPEN_ENV, - NODE_ALLOWED_BUILTINS_ENV, - NODE_LOOPBACK_EXEMPT_PORTS_ENV, - NODE_SYNC_RPC_ENABLE_ENV, - NODE_SYNC_RPC_REQUEST_FD_ENV, - NODE_SYNC_RPC_RESPONSE_FD_ENV, - NODE_SYNC_RPC_DATA_BYTES_ENV, - NODE_SYNC_RPC_WAIT_TIMEOUT_MS_ENV, -]; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(tag = "type", rename_all = "snake_case")] -enum NodeControlMessage { - NodeImportCacheMetrics { - metrics: serde_json::Value, - }, - PythonExit { - #[serde(rename = "exitCode")] - exit_code: i32, - }, - SignalState { - signal: u32, - registration: NodeSignalHandlerRegistration, - }, -} - -#[derive(Debug, Default)] -struct LinePrefixFilter { - pending: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct JavascriptSyncRpcRequest { - pub id: u64, - pub method: String, - pub args: Vec, - pub raw_bytes_args: HashMap>, -} - -#[derive(Debug, Deserialize)] -struct JavascriptSyncRpcRequestWire { - id: u64, - method: String, - #[serde(default)] - args: Vec, -} - -struct JavascriptSyncRpcChannels { - parent_request_reader: File, - parent_response_writer: File, - child_request_writer: OwnedFd, - child_response_reader: OwnedFd, -} - -impl LinePrefixFilter { - fn filter_chunk(&mut self, chunk: &[u8], prefixes: &[&str]) -> Vec { - self.pending.extend_from_slice(chunk); - let mut filtered = Vec::new(); - - while let Some(newline_index) = self.pending.iter().position(|byte| *byte == b'\n') { - let line = self.pending.drain(..=newline_index).collect::>(); - if !has_control_prefix(&line, prefixes) { - filtered.extend_from_slice(&line); - } - } - - filtered - } -} - -fn has_control_prefix(line: &[u8], prefixes: &[&str]) -> bool { - let text = String::from_utf8_lossy(line); - let trimmed = text.trim_end_matches(['\r', '\n']); - prefixes.iter().any(|prefix| trimmed.starts_with(prefix)) -} - -#[derive(Debug)] -struct JavascriptSyncRpcResponseWriter { - sender: SyncSender>, - timeout: Duration, -} - -impl JavascriptSyncRpcResponseWriter { - fn new(writer: File, timeout: Duration) -> Self { - let (sender, receiver) = mpsc::sync_channel(NODE_SYNC_RPC_RESPONSE_QUEUE_CAPACITY); - spawn_javascript_sync_rpc_response_writer(writer, receiver); - Self { sender, timeout } - } - - fn send(&self, payload: Vec) -> Result<(), JavascriptExecutionError> { - let started = Instant::now(); - let mut payload = Some(payload); - - loop { - match self - .sender - .try_send(payload.take().expect("payload should be present")) - { - Ok(()) => return Ok(()), - Err(TrySendError::Disconnected(_)) => { - return Err(JavascriptExecutionError::RpcResponse(String::from( - "JavaScript sync RPC response channel closed unexpectedly", - ))); - } - Err(TrySendError::Full(returned_payload)) => { - if started.elapsed() >= self.timeout { - return Err(JavascriptExecutionError::RpcResponse(format!( - "timed out after {}ms while queueing JavaScript sync RPC response", - self.timeout.as_millis() - ))); - } - payload = Some(returned_payload); - thread::sleep(Duration::from_millis(5)); - } - } - } - } -} - -impl Clone for JavascriptSyncRpcResponseWriter { - fn clone(&self) -> Self { - Self { - sender: self.sender.clone(), - timeout: self.timeout, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum PendingSyncRpcState { - Pending(u64), - TimedOut(u64), -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum PendingSyncRpcResolution { - Pending, - TimedOut, - Missing, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CreateJavascriptContextRequest { - pub vm_id: String, - pub bootstrap_module: Option, - pub compile_cache_root: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct JavascriptContext { - pub context_id: String, - pub vm_id: String, - pub bootstrap_module: Option, - pub compile_cache_dir: Option, -} - -/// Per-execution JavaScript runtime limits, carried as typed fields on the -/// execution request rather than `AGENTOS_*` env vars. The sidecar populates -/// these from the per-VM `VmLimits` (which originate from `CreateVmConfig` on -/// the BARE wire); `None` selects the engine default. See the env-vs-wire rule -/// in `crates/sidecar/CLAUDE.md`. -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct JavascriptExecutionLimits { - /// V8 heap cap in MB. `None`/`Some(0)` keeps the engine default heap. - pub v8_heap_limit_mb: Option, - /// Sync-RPC blocking-wait ceiling in ms. `None` keeps the engine default. - pub sync_rpc_wait_timeout_ms: Option, - /// Active JavaScript CPU-time budget in ms. `None` keeps the engine default; - /// `Some(0)` disables the CPU watchdog. - pub cpu_time_limit_ms: Option, - /// JavaScript wall-clock backstop in ms. `None` keeps the engine default; - /// `Some(0)` disables the wall-clock watchdog. - pub wall_clock_limit_ms: Option, - /// Timeout for materializing the per-VM Node import cache. - pub import_cache_materialize_timeout_ms: Option, -} - -/// Per-execution guest-runtime config carried as typed fields rather than -/// `AGENTOS_*` env vars. The sidecar populates these from kernel state -/// (`user_profile()`, `resource_limits()`) and `CreateVmConfig`; the runtime -/// shim interpolates them into a `_processConfig` object the guest reads, so the -/// guest's virtual identity no longer rides the ambient env channel. `None` -/// keeps the guest-runtime default. See the env-vs-wire rule in -/// `crates/sidecar/CLAUDE.md`. -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct GuestRuntimeConfig { - /// Virtual `process.pid`. - pub virtual_pid: Option, - /// Virtual `process.ppid`. - pub virtual_ppid: Option, - /// Virtual `process.uid` / `process.euid`. - pub virtual_uid: Option, - /// Virtual `process.gid` / `process.egid` / `process.groups`. - pub virtual_gid: Option, - /// Virtual `process.execPath`. - pub virtual_exec_path: Option, - /// `os.cpus().length`. - pub os_cpu_count: Option, - /// `os.totalmem()` in bytes. - pub os_totalmem: Option, - /// `os.freemem()` in bytes. - pub os_freemem: Option, - /// `os.homedir()`. - pub os_homedir: Option, - /// `os.hostname()`. - pub os_hostname: Option, - /// `os.tmpdir()`. - pub os_tmpdir: Option, - /// `os.type()`. - pub os_type: Option, - /// `os.release()`. - pub os_release: Option, - /// `os.version()`. - pub os_version: Option, - /// `os.machine()`. - pub os_machine: Option, - /// Default login shell. - pub os_shell: Option, - /// `os.userInfo().username`. - pub os_user: Option, - /// Opt-in high-resolution monotonic guest clock. Default false preserves - /// the security-oriented coarse clock. - pub high_resolution_time: bool, - /// Optional agent-SDK bundle (esbuild IIFE) to evaluate into the per-sidecar - /// V8 snapshot alongside the bridge, so the SDK is loaded once per sidecar and - /// reused across sessions instead of re-imported on every execution. `None` - /// keeps the bridge-only snapshot (unchanged behavior). The runtime caches the - /// snapshot process-wide keyed by sha256(bridge_code + this bundle). - pub snapshot_userland_code: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StartJavascriptExecutionRequest { - pub vm_id: String, - pub context_id: String, - pub argv: Vec, - pub env: BTreeMap, - pub cwd: PathBuf, - /// Per-execution runtime limits (see [`JavascriptExecutionLimits`]). - pub limits: JavascriptExecutionLimits, - /// Per-execution guest-runtime config (see [`GuestRuntimeConfig`]). - pub guest_runtime: GuestRuntimeConfig, - /// Optional inline JavaScript code supplied by the sidecar. - /// Eval entrypoints always execute this source directly. Module-mode file - /// entrypoints may also use it so the isolate can evaluate the original - /// source without re-reading through the host. CommonJS file entrypoints - /// still go through the normal require() wrapper so Node-style globals such - /// as __filename and __dirname are initialized correctly. - pub inline_code: Option, - /// Optional raw WASM module bytes to expose to the runner isolate for this - /// execution. - pub wasm_module_bytes: Option>>, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum JavascriptExecutionEvent { - Stdout(Vec), - Stderr(Vec), - SyncRpcRequest(JavascriptSyncRpcRequest), - SignalState { - signal: u32, - registration: NodeSignalHandlerRegistration, - }, - Exited(i32), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum JavascriptProcessEvent { - Stdout(Vec), - RawStderr(Vec), - SyncRpcRequest(JavascriptSyncRpcRequest), - Control(NodeControlMessage), - Exited(i32), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct JavascriptExecutionResult { - pub execution_id: String, - pub exit_code: i32, - pub stdout: Vec, - pub stderr: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct GuestPathMapping { - guest_path: String, - host_path: PathBuf, -} - -#[derive(Debug, Deserialize)] -struct GuestPathMappingWire { - #[serde(rename = "guestPath")] - guest_path: String, - #[serde(rename = "hostPath")] - host_path: String, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ModuleResolveMode { - Require, - Import, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LocalResolvedModuleFormat { - Module, - Commonjs, - Json, -} - -impl LocalResolvedModuleFormat { - pub fn as_str(self) -> &'static str { - match self { - Self::Module => "module", - Self::Commonjs => "commonjs", - Self::Json => "json", - } - } -} - -#[derive(Debug, Clone, Default)] -pub struct LocalModuleResolutionCache { - resolve_results: HashMap<(String, String, ModuleResolveMode), Option>, - module_format_results: HashMap>, - package_json_results: HashMap>, - exists_results: HashMap, - stat_results: HashMap>, -} - -/// Read-only filesystem primitives the module resolver needs. The resolution -/// algorithm itself is pure path algebra over these four operations; pointing -/// it at a different backing store (host files vs. the kernel VFS) is purely a -/// matter of supplying a different `ModuleFsReader`. -/// -/// All paths are guest paths (e.g. `/root/node_modules/foo/index.js`). Symlink -/// following is the reader's responsibility: `canonical_guest_path` must return -/// the fully-resolved guest path (realpath), and `path_is_dir`/`path_exists` -/// must follow symlinks the way real Node's `fs.stat`/`fs.existsSync` do. -pub trait ModuleFsReader { - /// Realpath of `guest_path`, expressed as a guest path. `None` if the path - /// does not resolve (does not exist / escapes the addressable tree). - fn canonical_guest_path(&mut self, guest_path: &str) -> Option; - - /// Read the file at `guest_path` as a UTF-8 string, following symlinks. - fn read_to_string(&mut self, guest_path: &str) -> Option; - - /// `Some(true)` if `guest_path` is a directory, `Some(false)` if it exists - /// but is not a directory, `None` if it does not exist. Follows symlinks. - fn path_is_dir(&mut self, guest_path: &str) -> Option; - - /// Whether `guest_path` exists, following symlinks. - fn path_exists(&mut self, guest_path: &str) -> bool; -} - -/// Guest JavaScript module-resolution mode (the `moduleResolution` axis of -/// `jsRuntime`). Defaults to full Node.js resolution. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -enum GuestModuleResolution { - /// node_modules ancestor-walk + exports/conditions + realpath. - #[default] - Node, - /// Relative/absolute ESM only; bare specifiers do not resolve. - Relative, - /// No resolution at all; every specifier (relative included) is denied. - None, -} - -impl GuestModuleResolution { - fn from_env(env: &BTreeMap) -> Self { - match env.get("AGENTOS_JS_MODULE_RESOLUTION").map(String::as_str) { - Some("relative") => Self::Relative, - Some("none") => Self::None, - _ => Self::Node, - } - } -} - -#[derive(Default)] -struct LocalBridgeState { - translator: GuestPathTranslator, - resolution_cache: LocalModuleResolutionCache, - /// jsRuntime module-resolution mode for this execution. - module_resolution: GuestModuleResolution, - handle_descriptions: HashMap, - next_timer_id: u64, - timers: Arc>>, - kernel_stdin: Arc, - forward_kernel_stdin_rpc: bool, - v8_session: Option, - /// Optional read-only reader over the mounted `node_modules` VFS, supplied by - /// the sidecar. When present, the bridge thread resolves module-resolution - /// RPCs (`_resolveModule` / `_loadFile` / `_moduleFormat` / - /// `_batchResolveModules`) inline against this reader, concurrently with the - /// service loop — so a large cold-start module graph does not serialize - /// behind / starve the ACP bootstrap on the single service-loop thread. - /// `None` means "route module resolution to the service loop" (the kernel-VFS - /// fallback for callers that supply no reader). - module_reader: Option>, -} - -impl Drop for LocalBridgeState { - /// Tear down all tracked timers when the bridge state is dropped (which - /// happens when the event-bridge service loop exits on session termination — - /// success, error, or shutdown). Clearing the shared `timers` map cancels both - /// kernel and bridge timers: any in-flight wheel action that wakes afterwards - /// finds its entry gone and suppresses its callback via `timer_should_fire`, - /// so a destroyed session's timers do not fire after the fact. - fn drop(&mut self) { - if let Ok(mut timers) = self.timers.lock() { - timers.clear(); - } - } -} - -#[derive(Debug, Default)] -struct LocalKernelStdinBridge { - state: Mutex, - ready: Condvar, -} - -#[derive(Debug, Default)] -struct LocalKernelStdinState { - bytes: VecDeque, - closed: bool, -} - -#[derive(Debug, Clone, Default)] -struct GuestPathTranslator { - implicit_guest_cwd: String, - implicit_host_cwd: PathBuf, - sandbox_root: Option, - mappings: Vec, -} - -#[derive(Debug, Clone, Deserialize, Default)] -struct LocalPackageJson { - #[serde(default)] - name: Option, - #[serde(default)] - main: Option, - #[serde(default)] - #[serde(rename = "type")] - package_type: Option, - #[serde(default)] - exports: Option, - #[serde(default)] - imports: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct LocalTimerEntry { - delay_ms: u64, - generation: u64, - repeat: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "kebab-case")] -enum PolyfillSourceKind { - NodeStdlibBrowser, - CustomBridge, - Denied, -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase")] -struct PolyfillRegistryGroup { - source: PolyfillSourceKind, - #[serde(default)] - error_code: Option, - names: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase")] -struct PolyfillRegistry { - version: u32, - groups: Vec, -} - -static POLYFILL_REGISTRY: OnceLock = OnceLock::new(); - -fn polyfill_registry() -> &'static PolyfillRegistry { - POLYFILL_REGISTRY.get_or_init(|| { - serde_json::from_str(include_str!("../assets/polyfill-registry.json")) - .expect("polyfill-registry.json must be valid") - }) -} - -#[derive(Debug, Clone, PartialEq)] -enum LocalBridgeCallResult { - Immediate(Value), - Deferred, -} - -/// Upper bound on guest-supplied timer delays, matching the JS `TIMEOUT_MAX` -/// ceiling (`2**31 - 1` ms, ~24.8 days). Guest code can pass a delay up to -/// `u64::MAX` ms; clamping keeps the timer wheel's deadline math and session -/// handle lifetime within Node-compatible bounds. -const MAX_TIMER_DELAY_MS: u64 = 2_147_483_647; - -fn timer_delay_ms(value: Option<&Value>) -> u64 { - let delay = match value { - Some(Value::Number(number)) => number.as_f64().unwrap_or(0.0), - Some(Value::String(text)) => text.parse::().unwrap_or(0.0), - _ => 0.0, - }; - - if !delay.is_finite() || delay <= 0.0 { - 0 - } else { - delay.floor().min(MAX_TIMER_DELAY_MS as f64) as u64 - } -} - -/// Decide whether a woken timer action should fire, and reclaim its tracking -/// entry. Returns `false` (suppressing the callback) when the timer is gone from -/// the map (cleared, or wiped on session teardown) or its generation no longer -/// matches the one captured at scheduling time (re-armed/cancelled). A one-shot -/// (`repeat == false`) timer that does fire is removed from the map so its id is -/// reclaimed. Shared by the kernel-timer and bridge-timer paths so both honor the -/// same cancellation semantics. -fn timer_should_fire( - timers: &Arc>>, - timer_id: u64, - generation: u64, -) -> bool { - timers - .lock() - .ok() - .and_then(|mut timers| { - let (current_generation, repeat) = timers - .get(&timer_id) - .map(|entry| (entry.generation, entry.repeat))?; - if current_generation != generation { - return Some(false); - } - if !repeat { - timers.remove(&timer_id); - } - Some(true) - }) - .unwrap_or(false) -} - -struct TimerWheel { - state: Mutex, - ready: Condvar, -} - -#[derive(Default)] -struct TimerWheelState { - heap: BinaryHeap>, - entries: HashMap, - next_seq: u64, -} - -enum TimerAction { - StreamEvent { - session: V8SessionHandle, - timer_id: u64, - generation: u64, - timers: Arc>>, - }, - BridgeResponse { - session: V8SessionHandle, - call_id: u64, - timer_id: u64, - generation: u64, - timers: Arc>>, - }, -} - -impl TimerAction { - fn execute(self) { - match self { - Self::StreamEvent { - session, - timer_id, - generation, - timers, - } => { - if !timer_should_fire(&timers, timer_id, generation) { - return; - } - - let payload = - v8_runtime::json_to_cbor_payload(&json!(timer_id)).unwrap_or_default(); - let _ = session.send_stream_event("timer", payload); - } - Self::BridgeResponse { - session, - call_id, - timer_id, - generation, - timers, - } => { - if !timer_should_fire(&timers, timer_id, generation) { - return; - } - let _ = session.send_bridge_response(call_id, 0, Vec::new()); - } - } - } -} - -impl TimerWheel { - fn get() -> &'static Arc { - JAVASCRIPT_TIMER_WHEEL.get_or_init(Self::start) - } - - fn start() -> Arc { - let wheel = Arc::new(Self { - state: Mutex::new(TimerWheelState::default()), - ready: Condvar::new(), - }); - let worker = Arc::clone(&wheel); - // Detached daemon: queued entries carry generation-checked session handles, - // matching the previous fire-and-forget timer threads without one OS - // thread per guest timer. - if let Err(error) = thread::Builder::new() - .name(String::from("secure-exec-js-timer-wheel")) - .spawn(move || worker.run()) - { - tracing::warn!(?error, "failed to start JavaScript timer wheel thread"); - } - wheel - } - - fn schedule(&self, delay_ms: u64, action: TimerAction) { - let now = Instant::now(); - let deadline = now - .checked_add(Duration::from_millis(delay_ms)) - .unwrap_or(now); - let mut state = self.lock_state(); - let old_earliest = state.heap.peek().map(|Reverse((deadline, _))| *deadline); - let seq = state.next_seq; - state.next_seq = state.next_seq.wrapping_add(1); - state.heap.push(Reverse((deadline, seq))); - state.entries.insert(seq, action); - if old_earliest.is_none_or(|old| deadline < old) { - self.ready.notify_one(); - } - } - - fn run(&self) { - loop { - let due = { - let mut state = self.lock_state(); - loop { - match state.heap.peek().copied() { - Some(Reverse((deadline, _))) => { - let now = Instant::now(); - if deadline <= now { - break; - } - let timeout = deadline.saturating_duration_since(now); - state = match self.ready.wait_timeout(state, timeout) { - Ok((state, _)) => state, - Err(poisoned) => poisoned.into_inner().0, - }; - } - None => { - state = match self.ready.wait(state) { - Ok(state) => state, - Err(poisoned) => poisoned.into_inner(), - }; - } - } - } - - let now = Instant::now(); - let mut due = Vec::new(); - while let Some(Reverse((deadline, seq))) = state.heap.peek().copied() { - if deadline > now { - break; - } - state.heap.pop(); - if let Some(action) = state.entries.remove(&seq) { - due.push(action); - } - } - due - }; - - for action in due { - if catch_unwind(AssertUnwindSafe(|| action.execute())).is_err() { - tracing::warn!("JavaScript timer wheel action panicked"); - } - } - } - } - - fn lock_state(&self) -> std::sync::MutexGuard<'_, TimerWheelState> { - match self.state.lock() { - Ok(state) => state, - Err(poisoned) => poisoned.into_inner(), - } - } -} - -impl GuestPathTranslator { - fn from_host_context( - env: &BTreeMap, - host_cwd: PathBuf, - guest_cwd: String, - ) -> Self { - let mut mappings = parse_guest_path_mappings_from_env(env) - .into_iter() - .filter(|mapping| mapping.guest_path.starts_with('/')) - .collect::>(); - - if !mappings - .iter() - .any(|mapping| mapping.guest_path == guest_cwd && mapping.host_path == host_cwd) - { - mappings.push(GuestPathMapping { - guest_path: guest_cwd.clone(), - host_path: host_cwd.clone(), - }); - } - - sort_guest_path_mappings(&mut mappings); - - Self { - implicit_guest_cwd: guest_cwd, - implicit_host_cwd: host_cwd, - sandbox_root: env - .get(NODE_SANDBOX_ROOT_ENV) - .filter(|value| Path::new(value.as_str()).is_absolute()) - .map(PathBuf::from), - mappings, - } - } - - fn is_known_host_path(&self, host_path: &Path) -> bool { - if host_path.starts_with(&self.implicit_host_cwd) { - return true; - } - - if let Some(sandbox_root) = &self.sandbox_root { - if host_path.starts_with(sandbox_root) { - return true; - } - } - - self.mappings.iter().any(|mapping| { - host_path.starts_with(&mapping.host_path) - || fs::canonicalize(&mapping.host_path) - .map(|real_path| host_path.starts_with(real_path)) - .unwrap_or(false) - }) - } - - fn from_request(request: &StartJavascriptExecutionRequest) -> Self { - let implicit_guest_cwd = request - .env - .get("PWD") - .filter(|value| value.starts_with('/')) - .cloned() - .or_else(|| { - request - .env - .get("HOME") - .filter(|value| value.starts_with('/')) - .cloned() - }) - .unwrap_or_else(|| String::from("/root")); - let mut translator = Self::from_host_context( - &request.env, - request.cwd.clone(), - implicit_guest_cwd.clone(), - ); - translator.mappings.sort_by(|left, right| { - let left_is_implicit = - left.guest_path == implicit_guest_cwd && left.host_path == request.cwd; - let right_is_implicit = - right.guest_path == implicit_guest_cwd && right.host_path == request.cwd; - right - .guest_path - .len() - .cmp(&left.guest_path.len()) - .then_with(|| right_is_implicit.cmp(&left_is_implicit)) - .then_with(|| { - right - .host_path - .components() - .count() - .cmp(&left.host_path.components().count()) - }) - }); - translator - } - - fn guest_cwd(&self) -> &str { - &self.implicit_guest_cwd - } - - fn resolve_host_entrypoint(&self, cwd: &Path, entrypoint: &str) -> PathBuf { - if entrypoint == "-e" || entrypoint == "--eval" { - return PathBuf::from(entrypoint); - } - - let path = Path::new(entrypoint); - if path.is_absolute() { - if self.is_known_host_path(path) { - return path.to_path_buf(); - } - self.guest_to_host(entrypoint) - .unwrap_or_else(|| path.to_path_buf()) - } else { - cwd.join(path) - } - } - - fn host_to_guest_string(&self, host_path: &Path) -> String { - if !host_path.is_absolute() { - return normalize_guest_path(&host_path.to_string_lossy()); - } - - for mapping in &self.mappings { - if let Ok(stripped) = host_path.strip_prefix(&mapping.host_path) { - return join_guest_path( - &mapping.guest_path, - &stripped.to_string_lossy().replace('\\', "/"), - ); - } - if let Ok(real_mapping_path) = fs::canonicalize(&mapping.host_path) { - if let Ok(stripped) = host_path.strip_prefix(&real_mapping_path) { - return join_guest_path( - &mapping.guest_path, - &stripped.to_string_lossy().replace('\\', "/"), - ); - } - } - } - - if let Ok(stripped) = host_path.strip_prefix(&self.implicit_host_cwd) { - return join_guest_path( - &self.implicit_guest_cwd, - &stripped.to_string_lossy().replace('\\', "/"), - ); - } - - if let Some(sandbox_root) = &self.sandbox_root { - if let Ok(stripped) = host_path.strip_prefix(sandbox_root) { - return join_guest_path("/", &stripped.to_string_lossy().replace('\\', "/")); - } - } - - let basename = host_path - .file_name() - .and_then(|value| value.to_str()) - .unwrap_or("unknown"); - join_guest_path("/unknown", basename) - } - - fn guest_to_host(&self, guest_path: &str) -> Option { - let normalized = normalize_guest_path(guest_path); - let mut fallback_candidate = None; - - for mapping in &self.mappings { - if let Some(suffix) = strip_guest_prefix(&normalized, &mapping.guest_path) { - let candidate = join_host_path(&mapping.host_path, suffix); - if candidate.exists() { - return self.confine_host_path(candidate); - } - if let Ok(real_mapping_path) = fs::canonicalize(&mapping.host_path) { - let real_candidate = join_host_path(&real_mapping_path, suffix); - if real_candidate.exists() { - return self.confine_host_path(real_candidate); - } - if let Some(sibling_candidate) = - resolve_pnpm_sibling_host_path(&real_mapping_path, suffix) - { - return self.confine_host_path(sibling_candidate); - } - } - fallback_candidate.get_or_insert(candidate); - } - } - if let Some(suffix) = strip_guest_prefix(&normalized, &self.implicit_guest_cwd) { - return self.confine_host_path(join_host_path(&self.implicit_host_cwd, suffix)); - } - - if let Some(candidate) = fallback_candidate { - return self.confine_host_path(candidate); - } - - if let Some(sandbox_root) = &self.sandbox_root { - return self.confine_host_path(join_host_path( - sandbox_root, - normalized.trim_start_matches('/'), - )); - } - - None - } - - fn confine_host_path(&self, host_path: PathBuf) -> Option { - let allowed_roots = self.allowed_canonical_host_roots(); - if allowed_roots.is_empty() { - return None; - } - - if let Ok(canonical_path) = fs::canonicalize(&host_path) { - return canonical_path_is_allowed(&canonical_path, &allowed_roots).then_some(host_path); - } - - let existing_ancestor = nearest_existing_host_ancestor(&host_path)?; - let canonical_ancestor = fs::canonicalize(existing_ancestor).ok()?; - canonical_path_is_allowed(&canonical_ancestor, &allowed_roots).then_some(host_path) - } - - fn allowed_canonical_host_roots(&self) -> Vec { - let mut roots = Vec::new(); - for root in self - .mappings - .iter() - .map(|mapping| mapping.host_path.as_path()) - .chain(std::iter::once(self.implicit_host_cwd.as_path())) - .chain(self.sandbox_root.as_deref()) - { - if let Ok(canonical_root) = fs::canonicalize(root) { - if !roots.iter().any(|existing| existing == &canonical_root) { - roots.push(canonical_root); - } - } - } - roots - } - - fn canonical_guest_path(&self, guest_path: &str) -> Option { - let host_path = self.guest_to_host(guest_path)?; - let canonical = fs::canonicalize(host_path).ok()?; - for mapping in &self.mappings { - if strip_guest_prefix(guest_path, &mapping.guest_path).is_none() { - continue; - } - if let Ok(stripped) = canonical.strip_prefix(&mapping.host_path) { - return Some(join_guest_path( - &mapping.guest_path, - &stripped.to_string_lossy().replace('\\', "/"), - )); - } - if let Ok(real_mapping_path) = fs::canonicalize(&mapping.host_path) { - if let Ok(stripped) = canonical.strip_prefix(&real_mapping_path) { - return Some(join_guest_path( - &mapping.guest_path, - &stripped.to_string_lossy().replace('\\', "/"), - )); - } - } - } - if let Some(node_modules_root) = self - .mappings - .iter() - .find(|mapping| mapping.guest_path == "/root/node_modules") - { - if let Ok(stripped) = canonical.strip_prefix(&node_modules_root.host_path) { - return Some(join_guest_path( - &node_modules_root.guest_path, - &stripped.to_string_lossy().replace('\\', "/"), - )); - } - if let Ok(real_root) = fs::canonicalize(&node_modules_root.host_path) { - if let Ok(stripped) = canonical.strip_prefix(&real_root) { - return Some(join_guest_path( - &node_modules_root.guest_path, - &stripped.to_string_lossy().replace('\\', "/"), - )); - } - } - } - let guest = self.host_to_guest_string(&canonical); - (!guest.starts_with("/unknown/")).then_some(normalize_guest_path(&guest)) - } -} - -fn sort_guest_path_mappings(mappings: &mut [GuestPathMapping]) { - mappings.sort_by(|left, right| { - right - .guest_path - .len() - .cmp(&left.guest_path.len()) - .then_with(|| { - right - .host_path - .components() - .count() - .cmp(&left.host_path.components().count()) - }) - }); -} - -fn canonical_path_is_allowed(path: &Path, allowed_roots: &[PathBuf]) -> bool { - allowed_roots - .iter() - .any(|root| path == root || path.starts_with(root)) -} - -fn nearest_existing_host_ancestor(path: &Path) -> Option<&Path> { - let mut candidate = Some(path); - while let Some(current) = candidate { - if fs::symlink_metadata(current).is_ok() { - return Some(current); - } - candidate = current.parent(); - } - None -} - -#[doc(hidden)] -pub struct ModuleResolutionTestHarness { - local_bridge: LocalBridgeState, -} - -impl ModuleResolutionTestHarness { - pub fn new(host_root: impl Into) -> Self { - let host_root = host_root.into(); - let mut mappings = vec![ - GuestPathMapping { - guest_path: String::from("/root/node_modules"), - host_path: host_root.join("node_modules"), - }, - GuestPathMapping { - guest_path: String::from("/root"), - host_path: host_root.clone(), - }, - ]; - sort_guest_path_mappings(&mut mappings); - - // Build via default + in-place assignment rather than `..default()`: - // LocalBridgeState implements Drop (to cancel timers on session teardown), - // and functional-record-update would move fields out of a Drop type (E0509). - let mut local_bridge = LocalBridgeState::default(); - local_bridge.translator = GuestPathTranslator { - implicit_guest_cwd: String::from("/root"), - implicit_host_cwd: host_root, - sandbox_root: None, - mappings, - }; - Self { local_bridge } - } - - pub fn resolve_import(&mut self, specifier: &str, from_path: &str) -> Option { - self.local_bridge - .resolve_module(specifier, from_path, ModuleResolveMode::Import) - } - - pub fn resolve_require(&mut self, specifier: &str, from_path: &str) -> Option { - self.local_bridge - .resolve_module(specifier, from_path, ModuleResolveMode::Require) - } - - pub fn module_format(&mut self, path: &str) -> Option<&'static str> { - self.local_bridge - .module_format(path) - .map(LocalResolvedModuleFormat::as_str) - } -} - -#[doc(hidden)] -pub fn handle_internal_bridge_call_from_host_context( - host_cwd: &Path, - guest_cwd: &str, - env: &BTreeMap, - method: &str, - args: &[Value], -) -> Option { - // default + in-place assign: LocalBridgeState is Drop, so `..default()` (E0509) - // is not allowed. - let mut local_bridge = LocalBridgeState::default(); - local_bridge.translator = - GuestPathTranslator::from_host_context(env, host_cwd.to_path_buf(), guest_cwd.to_owned()); - - match local_bridge.handle_internal_bridge_call(0, method, args) { - Some(LocalBridgeCallResult::Immediate(value)) => Some(value), - _ => None, - } -} - -fn resolve_pnpm_sibling_host_path(real_mapping_path: &Path, suffix: &str) -> Option { - let trimmed = suffix.strip_prefix("node_modules/")?; - let mut current = Some(real_mapping_path); - while let Some(path) = current { - if path.file_name().and_then(|name| name.to_str()) == Some("node_modules") { - let candidate = join_host_path(path, trimmed); - if candidate.exists() { - return Some(candidate); - } - break; - } - current = path.parent(); - } - None -} - -fn parse_guest_path_mappings(request: &StartJavascriptExecutionRequest) -> Vec { - parse_guest_path_mappings_from_env(&request.env) -} - -fn parse_guest_path_mappings_from_env(env: &BTreeMap) -> Vec { - env.get(NODE_GUEST_PATH_MAPPINGS_ENV) - .and_then(|value| serde_json::from_str::>(value).ok()) - .into_iter() - .flatten() - .map(|mapping| GuestPathMapping { - guest_path: normalize_guest_path(&mapping.guest_path), - host_path: PathBuf::from(mapping.host_path), - }) - .collect() -} - -fn normalize_guest_path(path: &str) -> String { - let mut segments = Vec::new(); - let absolute = path.starts_with('/'); - for segment in path.split('/') { - match segment { - "" | "." => {} - ".." => { - segments.pop(); - } - other => segments.push(other), - } - } - if !absolute { - return segments.join("/"); - } - if segments.is_empty() { - String::from("/") - } else { - format!("/{}", segments.join("/")) - } -} - -fn join_guest_path(base: &str, suffix: &str) -> String { - if suffix.is_empty() || suffix == "." { - return normalize_guest_path(base); - } - let trimmed = suffix.trim_start_matches('/'); - normalize_guest_path(&format!("{}/{}", base.trim_end_matches('/'), trimmed)) -} - -fn strip_guest_prefix<'a>(path: &'a str, prefix: &str) -> Option<&'a str> { - if prefix == "/" { - return path.strip_prefix('/'); - } - if path == prefix { - return Some(""); - } - path.strip_prefix(prefix) - .and_then(|suffix| suffix.strip_prefix('/')) -} - -fn join_host_path(base: &Path, suffix: &str) -> PathBuf { - if suffix.is_empty() { - return base.to_path_buf(); - } - let mut joined = base.to_path_buf(); - for segment in suffix.split('/') { - if segment.is_empty() || segment == "." { - continue; - } - if segment == ".." { - joined.pop(); - } else { - joined.push(segment); - } - } - joined -} - -fn translate_v8_bridge_value_to_legacy(value: &Value) -> Value { - match value { - Value::Array(values) => Value::Array( - values - .iter() - .map(translate_v8_bridge_value_to_legacy) - .collect(), - ), - Value::Object(map) if map.get("__type").and_then(Value::as_str) == Some("Buffer") => { - json!({ - "__agentOSType": "bytes", - "base64": map.get("data").cloned().unwrap_or(Value::String(String::new())), - }) - } - Value::Object(map) => Value::Object( - map.iter() - .map(|(key, value)| (key.clone(), translate_v8_bridge_value_to_legacy(value))) - .collect(), - ), - other => other.clone(), - } -} - -fn translate_request_args_for_legacy(method: &str, args: &[Value]) -> Vec { - let mut translated = args - .iter() - .map(translate_v8_bridge_value_to_legacy) - .collect::>(); - - if matches!(method, "fs.writeFileSync" | "fs.promises.writeFile") { - if let Some(Value::String(data)) = translated.get(1) { - translated[1] = json!({ - "__agentOSType": "bytes", - "base64": v8_runtime::base64_encode_pub(data.as_bytes()), - }); - } - } - - translated -} - -fn translate_legacy_bridge_value_to_v8(value: &Value) -> Value { - match value { - Value::Array(values) => Value::Array( - values - .iter() - .map(translate_legacy_bridge_value_to_v8) - .collect(), - ), - Value::Object(map) if map.get("__agentOSType").and_then(Value::as_str) == Some("bytes") => { - json!({ - "__type": "Buffer", - "data": map.get("base64").cloned().unwrap_or(Value::String(String::new())), - }) - } - Value::Object(map) => Value::Object( - map.iter() - .map(|(key, value)| (key.clone(), translate_legacy_bridge_value_to_v8(value))) - .collect(), - ), - other => other.clone(), - } -} - -fn decode_bridge_output_arg(value: &Value) -> Vec { - match value { - Value::String(s) => s.as_bytes().to_vec(), - Value::Object(map) - if map.get("__type").and_then(Value::as_str) == Some("Buffer") - || map.get("__agentOSType").and_then(Value::as_str) == Some("bytes") => - { - let base64_value = map - .get("data") - .or_else(|| map.get("base64")) - .and_then(Value::as_str); - if let Some(base64_value) = base64_value { - if let Some(bytes) = v8_runtime::base64_decode_pub(base64_value) { - return bytes; - } - } - value.to_string().into_bytes() - } - other => other.to_string().into_bytes(), - } -} - -fn decode_bridge_output_args(args: &[Value]) -> Vec { - let mut output = Vec::new(); - for (index, arg) in args.iter().enumerate() { - if index > 0 { - output.push(b' '); - } - output.extend(decode_bridge_output_arg(arg)); - } - output -} - -#[derive(Debug)] -pub enum JavascriptExecutionError { - EmptyArgv, - MissingContext(String), - VmMismatch { expected: String, found: String }, - PrepareImportCache(std::io::Error), - Spawn(std::io::Error), - PendingSyncRpcRequest(u64), - ExpiredSyncRpcRequest(u64), - RpcResponse(String), - Terminate(std::io::Error), - StdinClosed, - Stdin(std::io::Error), - OutputBufferExceeded { stream: &'static str, limit: usize }, - EventChannelClosed, -} - -impl fmt::Display for JavascriptExecutionError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::EmptyArgv => f.write_str("guest JavaScript execution requires argv[0]"), - Self::MissingContext(context_id) => { - write!(f, "unknown guest JavaScript context: {context_id}") - } - Self::VmMismatch { expected, found } => { - write!( - f, - "guest JavaScript context belongs to vm {expected}, not {found}" - ) - } - Self::PrepareImportCache(err) => { - write!( - f, - "failed to prepare sidecar-scoped Node import cache: {err}" - ) - } - Self::Spawn(err) => write!(f, "failed to start guest JavaScript runtime: {err}"), - Self::PendingSyncRpcRequest(id) => { - write!( - f, - "guest JavaScript execution requires servicing pending sync RPC request {id}" - ) - } - Self::ExpiredSyncRpcRequest(id) => { - write!(f, "sync RPC request {id} is no longer pending") - } - Self::RpcResponse(message) => { - write!( - f, - "failed to reply to guest JavaScript sync RPC request: {message}" - ) - } - Self::Terminate(err) => { - write!(f, "failed to terminate guest JavaScript runtime: {err}") - } - Self::StdinClosed => f.write_str("guest JavaScript stdin is already closed"), - Self::Stdin(err) => write!(f, "failed to write guest stdin: {err}"), - Self::OutputBufferExceeded { stream, limit } => { - write!( - f, - "guest JavaScript {stream} exceeded the captured output limit of {limit} bytes" - ) - } - Self::EventChannelClosed => { - f.write_str("guest JavaScript event channel closed unexpectedly") - } - } - } -} - -impl std::error::Error for JavascriptExecutionError {} - -#[derive(Debug)] -pub struct JavascriptExecution { - execution_id: String, - child_pid: u32, - events: tokio::sync::Mutex>, - pending_sync_rpc: Arc>>, - kernel_stdin: Arc, - _import_cache_guard: Arc, - v8_session: V8SessionHandle, - /// Host-direct module resolver state, used ONLY by the standalone `wait()` - /// loop. The real VM runtime resolves modules against the kernel VFS on the - /// sidecar service loop and never reaches this; but `wait()` runs without a - /// kernel (dev/test harness), so it services module-resolution sync RPCs - /// host-directly from the request's path translator. - module_resolution: Mutex<(GuestPathTranslator, LocalModuleResolutionCache)>, -} - -impl JavascriptExecution { - pub fn execution_id(&self) -> &str { - &self.execution_id - } - - pub fn child_pid(&self) -> u32 { - self.child_pid - } - - pub fn v8_session_handle(&self) -> V8SessionHandle { - self.v8_session.clone() - } - - pub fn uses_shared_v8_runtime(&self) -> bool { - true - } - - pub fn write_stdin(&mut self, chunk: &[u8]) -> Result<(), JavascriptExecutionError> { - self.kernel_stdin.write(chunk)?; - let payload = v8_runtime::json_to_cbor_payload(&json!({ - "dataBase64": v8_runtime::base64_encode_pub(chunk), - })) - .map_err(JavascriptExecutionError::Stdin)?; - self.v8_session - .send_stream_event("stdin", payload) - .map_err(JavascriptExecutionError::Stdin) - } - - pub fn close_stdin(&mut self) -> Result<(), JavascriptExecutionError> { - self.kernel_stdin.close(); - let _ = self.v8_session.send_stream_event("stdin_end", vec![]); - Ok(()) - } - - pub(crate) fn write_kernel_stdin_only( - &mut self, - chunk: &[u8], - ) -> Result<(), JavascriptExecutionError> { - self.kernel_stdin.write(chunk) - } - - pub(crate) fn close_kernel_stdin_only(&mut self) { - self.kernel_stdin.close(); - } - - pub fn read_kernel_stdin_sync_rpc( - &self, - request: &JavascriptSyncRpcRequest, - ) -> Result { - if request.method != "__kernel_stdin_read" { - return Ok(Value::Null); - } - - Ok(self.kernel_stdin.read(&request.args)) - } - - pub(crate) fn handle_kernel_stdin_sync_rpc( - &mut self, - request: &JavascriptSyncRpcRequest, - ) -> Result { - if request.method != "__kernel_stdin_read" { - return Ok(false); - } - - let response = self.kernel_stdin.read(&request.args); - self.respond_sync_rpc_success(request.id, response)?; - Ok(true) - } - - pub fn terminate(&self) -> Result<(), JavascriptExecutionError> { - self.v8_session - .terminate() - .map_err(JavascriptExecutionError::Terminate) - } - - pub fn send_stream_event( - &self, - event_type: &str, - payload: Value, - ) -> Result<(), JavascriptExecutionError> { - let payload = v8_runtime::json_to_cbor_payload(&payload) - .map_err(|error| JavascriptExecutionError::RpcResponse(error.to_string()))?; - self.v8_session - .send_stream_event(event_type, payload) - .map_err(|error| JavascriptExecutionError::RpcResponse(error.to_string())) - } - - pub fn respond_sync_rpc_success( - &mut self, - id: u64, - result: Value, - ) -> Result<(), JavascriptExecutionError> { - let phase_start = Instant::now(); - match self.clear_pending_sync_rpc(id)? { - PendingSyncRpcResolution::Pending => {} - PendingSyncRpcResolution::TimedOut => { - return Err(JavascriptExecutionError::ExpiredSyncRpcRequest(id)); - } - PendingSyncRpcResolution::Missing => {} - } - record_sync_bridge_phase( - "sync_rpc_response", - "response_clear_pending", - phase_start.elapsed(), - ); - - let phase_start = Instant::now(); - let payload = translate_legacy_bridge_value_to_v8(&result); - record_sync_bridge_phase( - "sync_rpc_response", - "response_translate_value", - phase_start.elapsed(), - ); - let phase_start = Instant::now(); - let payload = v8_runtime::json_to_cbor_payload(&payload) - .map_err(|e| JavascriptExecutionError::RpcResponse(e.to_string()))?; - record_sync_bridge_phase( - "sync_rpc_response", - "response_encode_cbor", - phase_start.elapsed(), - ); - let phase_start = Instant::now(); - let result = self - .v8_session - .send_bridge_response(id, 0, payload) - .map_err(|e| JavascriptExecutionError::RpcResponse(e.to_string())); - record_sync_bridge_phase("sync_rpc_response", "response_send", phase_start.elapsed()); - result - } - - pub fn respond_sync_rpc_raw_success( - &mut self, - id: u64, - payload: Vec, - ) -> Result<(), JavascriptExecutionError> { - let phase_start = Instant::now(); - match self.clear_pending_sync_rpc(id)? { - PendingSyncRpcResolution::Pending => {} - PendingSyncRpcResolution::TimedOut => { - return Err(JavascriptExecutionError::ExpiredSyncRpcRequest(id)); - } - PendingSyncRpcResolution::Missing => {} - } - record_sync_bridge_phase( - "sync_rpc_raw_response", - "response_clear_pending", - phase_start.elapsed(), - ); - - let phase_start = Instant::now(); - let result = self - .v8_session - .send_bridge_response(id, 2, payload) - .map_err(|e| JavascriptExecutionError::RpcResponse(e.to_string())); - record_sync_bridge_phase( - "sync_rpc_raw_response", - "response_send", - phase_start.elapsed(), - ); - result - } - - pub fn respond_sync_rpc_error( - &mut self, - id: u64, - code: impl Into, - message: impl Into, - ) -> Result<(), JavascriptExecutionError> { - match self.clear_pending_sync_rpc(id)? { - PendingSyncRpcResolution::Pending => {} - PendingSyncRpcResolution::TimedOut => { - return Err(JavascriptExecutionError::ExpiredSyncRpcRequest(id)); - } - PendingSyncRpcResolution::Missing => {} - } - - let error_msg = format!("{}: {}", code.into(), message.into()); - self.v8_session - .send_bridge_response(id, 1, error_msg.into_bytes()) - .map_err(|e| JavascriptExecutionError::RpcResponse(e.to_string())) - } - - pub async fn poll_event( - &self, - timeout: Duration, - ) -> Result, JavascriptExecutionError> { - if timeout.is_zero() { - let mut events = self.events.lock().await; - return match events.try_recv() { - Ok(event) => Ok(Some(event)), - Err(TokioTryRecvError::Empty) => Ok(None), - Err(TokioTryRecvError::Disconnected) => { - Err(JavascriptExecutionError::EventChannelClosed) - } - }; - } - - let mut events = self.events.lock().await; - match time::timeout(timeout, events.recv()).await { - Ok(Some(event)) => Ok(Some(event)), - Ok(None) => Err(JavascriptExecutionError::EventChannelClosed), - Err(_) => Ok(None), - } - } - - pub fn poll_event_blocking( - &self, - timeout: Duration, - ) -> Result, JavascriptExecutionError> { - let deadline = Instant::now() + timeout; - loop { - if let Ok(mut events) = self.events.try_lock() { - match events.try_recv() { - Ok(event) => return Ok(Some(event)), - Err(TokioTryRecvError::Disconnected) => { - return Err(JavascriptExecutionError::EventChannelClosed); - } - Err(TokioTryRecvError::Empty) => { - if Instant::now() >= deadline { - return Ok(None); - } - } - } - } - - if Instant::now() >= deadline { - return Ok(None); - } - thread::sleep(Duration::from_millis(1)); - } - } - - pub fn wait(mut self) -> Result { - self.close_stdin()?; - let mut events = std::mem::replace( - self.events.get_mut(), - channel(JAVASCRIPT_EVENT_CHANNEL_CAPACITY).1, - ); - let execution_id = std::mem::take(&mut self.execution_id); - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - - loop { - match events.blocking_recv() { - Some(JavascriptExecutionEvent::Stdout(chunk)) => { - append_captured_output(&mut stdout, chunk, "stdout")?; - } - Some(JavascriptExecutionEvent::Stderr(chunk)) => { - append_captured_output(&mut stderr, chunk, "stderr")?; - } - Some(JavascriptExecutionEvent::SyncRpcRequest(request)) => { - // The standalone engine has no kernel/service loop. Service - // module-resolution RPCs host-directly (the only FS source - // available here) so `wait()` does not deadlock; everything - // else is unsupported off the VM path. - if self.try_service_standalone_module_sync_rpc(&request)? { - continue; - } - return Err(JavascriptExecutionError::PendingSyncRpcRequest(request.id)); - } - Some(JavascriptExecutionEvent::SignalState { .. }) => {} - Some(JavascriptExecutionEvent::Exited(exit_code)) => { - return Ok(JavascriptExecutionResult { - execution_id, - exit_code, - stdout, - stderr, - }); - } - None => return Err(JavascriptExecutionError::EventChannelClosed), - } - } - } - - /// Service a module-resolution sync RPC host-directly, for consumers that - /// drive the V8 bridge without a kernel/service loop (the standalone - /// `wait()` loop and the Python/WASM prewarm loops). Uses this execution's - /// own path translator (captured at start, including any runtime path - /// mappings) and a persistent cache. Returns `Ok(true)` if the request was a - /// module method and was answered, `Ok(false)` if it should fall through. - /// - /// The real VM runtime resolves modules against the kernel VFS on the - /// sidecar service loop and never calls this. - pub fn try_service_standalone_module_sync_rpc( - &mut self, - request: &JavascriptSyncRpcRequest, - ) -> Result { - let result = { - let mut guard = self.module_resolution.lock().map_err(|_| { - JavascriptExecutionError::RpcResponse(String::from( - "standalone module resolution state poisoned", - )) - })?; - let (translator, cache) = &mut *guard; - let mut resolver = ModuleResolver::new(translator, cache); - match request.method.as_str() { - "__resolve_module" | "_resolveModule" | "_resolveModuleSync" => { - let specifier = request.args.first().and_then(Value::as_str).unwrap_or(""); - let parent = request.args.get(1).and_then(Value::as_str).unwrap_or("/"); - let mode = match request.args.get(2).and_then(Value::as_str) { - Some("import") => ModuleResolveMode::Import, - Some("require") => ModuleResolveMode::Require, - _ if request.method == "_resolveModuleSync" => ModuleResolveMode::Require, - _ => ModuleResolveMode::Import, - }; - resolver - .resolve_module(specifier, parent, mode) - .map(Value::String) - .unwrap_or(Value::Null) - } - "__load_file" | "_loadFile" | "_loadFileSync" => resolver - .load_file(request.args.first().and_then(Value::as_str).unwrap_or("")) - .map(Value::String) - .unwrap_or(Value::Null), - "__module_format" | "_moduleFormat" => resolver - .module_format(request.args.first().and_then(Value::as_str).unwrap_or("")) - .map(|format| Value::String(String::from(format.as_str()))) - .unwrap_or(Value::Null), - "__batch_resolve_modules" | "_batchResolveModules" => { - resolver.batch_resolve_modules(&request.args) - } - _ => return Ok(false), - } - }; - self.respond_sync_rpc_success(request.id, result)?; - Ok(true) - } - - fn clear_pending_sync_rpc( - &self, - id: u64, - ) -> Result { - let mut pending = self.pending_sync_rpc.lock().map_err(|_| { - JavascriptExecutionError::RpcResponse(String::from( - "sync RPC pending-request state lock poisoned", - )) - })?; - match *pending { - Some(PendingSyncRpcState::Pending(current)) if current == id => { - *pending = None; - Ok(PendingSyncRpcResolution::Pending) - } - Some(PendingSyncRpcState::TimedOut(current)) if current == id => { - Ok(PendingSyncRpcResolution::TimedOut) - } - _ => Ok(PendingSyncRpcResolution::Missing), - } - } -} - -impl Drop for JavascriptExecution { - fn drop(&mut self) { - let _ = self.v8_session.destroy(); - } -} - -fn append_captured_output( - target: &mut Vec, - chunk: Vec, - stream: &'static str, -) -> Result<(), JavascriptExecutionError> { - let next_len = target.len().checked_add(chunk.len()).ok_or( - JavascriptExecutionError::OutputBufferExceeded { - stream, - limit: JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES, - }, - )?; - if next_len > JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES { - return Err(JavascriptExecutionError::OutputBufferExceeded { - stream, - limit: JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES, - }); - } - - target.extend(chunk); - Ok(()) -} - -struct V8SessionRegistrationGuard<'a> { - v8_host: &'a V8RuntimeHost, - session_id: String, - active: bool, -} - -impl<'a> V8SessionRegistrationGuard<'a> { - fn new(v8_host: &'a V8RuntimeHost, session_id: String) -> Self { - Self { - v8_host, - session_id, - active: true, - } - } - - fn disarm(&mut self) { - self.active = false; - } -} - -impl Drop for V8SessionRegistrationGuard<'_> { - fn drop(&mut self) { - if self.active { - self.v8_host.unregister_session(&self.session_id); - } - } -} - -struct PendingV8SessionRegistration<'a> { - frame_receiver: TrackedReceiver, - registration_guard: V8SessionRegistrationGuard<'a>, -} - -fn register_v8_session( - v8_host: &V8RuntimeHost, - session_id: String, - heap_limit_mb: u32, - cpu_time_limit_ms: u32, - wall_clock_limit_ms: u32, - warm_hint: Option, - create_session: F, -) -> Result, JavascriptExecutionError> -where - F: FnOnce(RuntimeCommand) -> std::io::Result<()>, -{ - let frame_receiver = v8_host - .register_session(&session_id) - .map_err(JavascriptExecutionError::Spawn)?; - let registration_guard = V8SessionRegistrationGuard::new(v8_host, session_id.clone()); - - create_session(RuntimeCommand::CreateSession { - session_id, - heap_limit_mb: (heap_limit_mb > 0).then_some(heap_limit_mb), - cpu_time_limit_ms: (cpu_time_limit_ms > 0).then_some(cpu_time_limit_ms), - wall_clock_limit_ms: (wall_clock_limit_ms > 0).then_some(wall_clock_limit_ms), - warm_hint, - }) - .map_err(JavascriptExecutionError::Spawn)?; - - Ok(PendingV8SessionRegistration { - frame_receiver, - registration_guard, - }) -} - -#[derive(Default)] -pub struct JavascriptExecutionEngine { - next_context_id: usize, - next_execution_id: usize, - contexts: BTreeMap, - import_caches: BTreeMap, - v8_host: Option, - event_notify: Option>, -} - -impl std::fmt::Debug for JavascriptExecutionEngine { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("JavascriptExecutionEngine") - .field("next_context_id", &self.next_context_id) - .field("next_execution_id", &self.next_execution_id) - .field("contexts", &self.contexts) - .field("v8_host", &self.v8_host.is_some()) - .finish() - } -} - -impl JavascriptExecutionEngine { - #[doc(hidden)] - pub fn set_event_notify(&mut self, notify: Option>) { - self.event_notify = notify; - } - - #[doc(hidden)] - pub fn set_import_cache_base_dir(&mut self, vm_id: impl Into, base_dir: PathBuf) { - self.import_caches - .insert(vm_id.into(), NodeImportCache::new_in(base_dir)); - } - - pub fn create_context(&mut self, request: CreateJavascriptContextRequest) -> JavascriptContext { - self.next_context_id += 1; - self.import_caches.entry(request.vm_id.clone()).or_default(); - - let context = JavascriptContext { - context_id: format!("js-ctx-{}", self.next_context_id), - vm_id: request.vm_id, - bootstrap_module: request.bootstrap_module, - compile_cache_dir: request - .compile_cache_root - .map(resolve_node_import_compile_cache_dir), - }; - self.contexts - .insert(context.context_id.clone(), context.clone()); - context - } - - pub fn start_execution( - &mut self, - request: StartJavascriptExecutionRequest, - ) -> Result { - self.start_execution_with_module_reader(request, None, None) - } - - fn ensure_v8_host(&mut self) -> Result<(), JavascriptExecutionError> { - let should_spawn_v8_host = match self.v8_host.as_mut() { - Some(v8_host) => !v8_host - .is_alive() - .map_err(JavascriptExecutionError::Spawn)?, - None => true, - }; - if should_spawn_v8_host { - self.v8_host = Some(V8RuntimeHost::spawn().map_err(JavascriptExecutionError::Spawn)?); - } - Ok(()) - } - - pub(crate) fn snapshot_userland_ready( - &mut self, - userland_code: &str, - ) -> Result { - self.ensure_v8_host()?; - Ok(self - .v8_host - .as_ref() - .expect("V8 host initialized") - .snapshot_ready(userland_code)) - } - - pub(crate) fn pre_warm_snapshot( - &mut self, - userland_code: &str, - ) -> Result<(), JavascriptExecutionError> { - self.ensure_v8_host()?; - self.v8_host - .as_ref() - .expect("V8 host initialized") - .pre_warm_snapshot(userland_code) - .map_err(JavascriptExecutionError::Spawn) - } - - pub(crate) fn pre_warm_workers( - &mut self, - userland_code: &str, - heap_limit_mb: u32, - count: usize, - ) -> Result<(), JavascriptExecutionError> { - self.ensure_v8_host()?; - self.v8_host - .as_ref() - .expect("V8 host initialized") - .pre_warm_workers(userland_code, heap_limit_mb, count); - Ok(()) - } - - /// Like [`start_execution`](Self::start_execution) but with an optional - /// read-only VFS reader over the mounted `node_modules` tree. When supplied, - /// the bridge thread resolves module-resolution RPCs inline against this - /// reader (off the service loop, concurrently with it) instead of routing - /// them through the service loop. The reader must be `Send` because it is - /// moved onto the bridge thread; it must read the same mount the guest sees. - pub fn start_execution_with_module_reader( - &mut self, - request: StartJavascriptExecutionRequest, - module_reader: Option>, - guest_reader: Option>, - ) -> Result { - let context = self - .contexts - .get(&request.context_id) - .cloned() - .ok_or_else(|| JavascriptExecutionError::MissingContext(request.context_id.clone()))?; - - if context.vm_id != request.vm_id { - return Err(JavascriptExecutionError::VmMismatch { - expected: context.vm_id, - found: request.vm_id, - }); - } - - if request.argv.is_empty() { - return Err(JavascriptExecutionError::EmptyArgv); - } - - let phase_start = Instant::now(); - // Ensure import cache is materialized (still needed for module resolution) - let import_cache = self.import_caches.entry(context.vm_id.clone()).or_default(); - import_cache - .ensure_materialized_with_timeout(javascript_import_cache_materialize_timeout(&request)) - .map_err(JavascriptExecutionError::PrepareImportCache)?; - let import_cache_guard = import_cache.cleanup_guard(); - record_js_start_phase("js_start_import_cache", phase_start.elapsed()); - - self.next_execution_id += 1; - let execution_id = format!("exec-{}", self.next_execution_id); - let sync_rpc_timeout = javascript_sync_rpc_timeout(&request); - - let phase_start = Instant::now(); - self.ensure_v8_host()?; - let v8_host = self.v8_host.as_ref().unwrap(); - record_js_start_phase("js_start_v8_host_ready", phase_start.elapsed()); - - let phase_start = Instant::now(); - // Create a V8 session - let session_id = format!( - "v8-{execution_id}-{}", - NEXT_V8_SESSION_ID.fetch_add(1, Ordering::Relaxed) - ); - let heap_limit_mb = javascript_heap_limit_mb(&request); - let cpu_time_limit_ms = javascript_cpu_time_limit_ms(&request); - let wall_clock_limit_ms = javascript_wall_clock_limit_ms(&request); - let snapshot_userland_code = request - .guest_runtime - .snapshot_userland_code - .clone() - .unwrap_or_default(); - let warm_hint = Some(WarmSessionHint { - bridge_code: V8RuntimeHost::bridge_code().to_owned(), - userland_code: snapshot_userland_code.clone(), - heap_limit_mb: (heap_limit_mb > 0).then_some(heap_limit_mb), - }); - if snapshot_userland_code.is_empty() && heap_limit_mb == 0 { - v8_host.seed_default_warm_workers_async(); - } - let PendingV8SessionRegistration { - frame_receiver, - mut registration_guard, - } = register_v8_session( - v8_host, - session_id.clone(), - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - warm_hint, - |command| v8_host.create_session_from_command(command), - )?; - record_js_start_phase("js_start_v8_session_register", phase_start.elapsed()); - - let phase_start = Instant::now(); - // Build user code: prefer inline code, fall back to entrypoint-based - let translator = GuestPathTranslator::from_request(&request); - let host_entrypoint = translator.resolve_host_entrypoint(&request.cwd, &request.argv[0]); - let guest_entrypoint = if request.argv[0] == "-e" || request.argv[0] == "--eval" { - request.argv[0].clone() - } else if let Some(explicit_guest_entrypoint) = request - .env - .get(NODE_GUEST_ENTRYPOINT_ENV) - .filter(|value| value.starts_with('/')) - { - // Part B (guest-VFS adapter launch): the sidecar already resolved the - // GUEST entrypoint path (AGENTOS_GUEST_ENTRYPOINT). Use it directly as - // the sourceURL / module-resolution base instead of translating the - // host entrypoint — `host_to_guest_string` misses for guest-native - // mounts (`agentos_packages`, whose host staging dir is not in the - // translation map) and falls back to `/unknown/`, which then - // poisons the adapter's own relative/bare imports. For host-backed - // mounts the two values are equal, so this is a no-op there. Applies - // to child launches too (they set AGENTOS_GUEST_ENTRYPOINT as well), - // which is the child-process `/unknown` case. - explicit_guest_entrypoint.clone() - } else { - translator.host_to_guest_string(&host_entrypoint) - }; - let process_argv = if matches!(guest_entrypoint.as_str(), "-e" | "--eval") { - std::iter::once(String::from("node")) - .chain(request.argv.iter().skip(1).cloned()) - .collect::>() - } else { - std::iter::once(String::from("node")) - .chain(std::iter::once(guest_entrypoint.clone())) - .chain(request.argv.iter().skip(1).cloned()) - .collect::>() - }; - let inline_code = request - .inline_code - .clone() - .map(|inline_code| strip_javascript_hashbang(&inline_code)); - let use_module_mode = request - .env - .get(NODE_GUEST_ENTRYPOINT_MODULE_MODE_ENV) - .is_some_and(|value| value == "1" || value.eq_ignore_ascii_case("true")) - || host_entrypoint_uses_module_mode(&host_entrypoint) - || inline_code - .as_deref() - .is_some_and(inline_code_uses_module_mode); - if !matches!(guest_entrypoint.as_str(), "-e" | "--eval") && !use_module_mode { - if let Some(inline_code) = inline_code.as_ref() { - if let Some(parent) = host_entrypoint.parent() { - fs::create_dir_all(parent) - .map_err(JavascriptExecutionError::PrepareImportCache)?; - } - fs::write(&host_entrypoint, inline_code) - .map_err(JavascriptExecutionError::PrepareImportCache)?; - } - } - let user_code = if matches!(guest_entrypoint.as_str(), "-e" | "--eval") { - inline_code.unwrap_or_else(|| build_v8_user_code(&guest_entrypoint, &request.env)) - } else if use_module_mode { - if let Some(inline_code) = inline_code { - format!("{inline_code}\n//# sourceURL={guest_entrypoint}") - } else { - strip_javascript_hashbang(&fs::read_to_string(&host_entrypoint).map_err( - |error| { - JavascriptExecutionError::PrepareImportCache(std::io::Error::new( - error.kind(), - format!( - "failed to read JavaScript entrypoint {}: {error}", - host_entrypoint.display() - ), - )) - }, - )?) - } - } else { - build_v8_user_code(&guest_entrypoint, &request.env) - }; - let user_code = prepend_v8_runtime_shim( - user_code, - &guest_entrypoint, - &process_argv, - translator.guest_cwd(), - &request.env, - heap_limit_mb, - &request.guest_runtime, - ); - record_js_start_phase("js_start_build_user_code", phase_start.elapsed()); - - let phase_start = Instant::now(); - // Create session handle for sending bridge responses - let v8_session = v8_host.session_handle(session_id.clone()); - - // Start the event bridge before execution so early sync bridge calls - // made during module instantiation/evaluation cannot deadlock waiting - // for a response while no host thread is draining session frames yet. - let pending_sync_rpc = Arc::new(Mutex::new(None)); - let kernel_stdin = Arc::new(LocalKernelStdinBridge::default()); - let standalone_translator = translator.clone(); - // default + in-place assign: LocalBridgeState is Drop, so `..Default::default()` - // (E0509) is not allowed. - let mut local_bridge = LocalBridgeState::default(); - local_bridge.translator = translator; - local_bridge.kernel_stdin = kernel_stdin.clone(); - local_bridge.v8_session = Some(v8_session.clone()); - local_bridge.module_reader = module_reader; - local_bridge.module_resolution = GuestModuleResolution::from_env(&request.env); - local_bridge.forward_kernel_stdin_rpc = request - .env - .get(FORWARD_KERNEL_STDIN_RPC_ENV) - .is_some_and(|value| value == "1" || value.eq_ignore_ascii_case("true")); - let events = spawn_v8_event_bridge( - frame_receiver, - pending_sync_rpc.clone(), - sync_rpc_timeout, - v8_session.clone(), - local_bridge, - self.event_notify.clone(), - ); - record_js_start_phase("js_start_event_bridge", phase_start.elapsed()); - - let phase_start = Instant::now(); - // Install the direct module reader on the session thread BEFORE the Execute - // frame so the SetModuleReader command (routed through the same dispatch - // queue) arrives first; module loads then read source directly on the V8 - // thread instead of round-tripping the bridge. - if let Some(guest_reader) = guest_reader { - v8_session - .set_module_reader(guest_reader) - .map_err(JavascriptExecutionError::Spawn)?; - } - record_js_start_phase("js_start_install_module_reader", phase_start.elapsed()); - - let phase_start = Instant::now(); - // Execute bridge code + user code in the V8 isolate - v8_session - .execute( - if use_module_mode { 1 } else { 0 }, - guest_entrypoint.clone(), - V8RuntimeHost::bridge_code().to_owned(), - String::new(), - snapshot_userland_code, - request.guest_runtime.high_resolution_time, - user_code, - request.wasm_module_bytes.clone(), - ) - .map_err(JavascriptExecutionError::Spawn)?; - registration_guard.disarm(); - record_js_start_phase("js_start_send_execute", phase_start.elapsed()); - - Ok(JavascriptExecution { - execution_id, - child_pid: v8_host.child_pid(), - events: tokio::sync::Mutex::new(events), - pending_sync_rpc, - kernel_stdin, - _import_cache_guard: import_cache_guard, - v8_session, - module_resolution: Mutex::new(( - standalone_translator, - LocalModuleResolutionCache::default(), - )), - }) - } - - pub fn dispose_vm(&mut self, vm_id: &str) { - self.contexts.retain(|_, context| context.vm_id != vm_id); - self.import_caches.remove(vm_id); - } - - #[doc(hidden)] - #[allow(dead_code)] - pub fn materialize_import_cache_for_vm( - &mut self, - vm_id: &str, - ) -> Result<&std::path::Path, std::io::Error> { - let import_cache = self.import_caches.entry(vm_id.to_owned()).or_default(); - import_cache.ensure_materialized()?; - Ok(import_cache.cache_path()) - } - - #[doc(hidden)] - #[allow(dead_code)] - pub fn import_cache_path_for_vm(&self, vm_id: &str) -> Option<&std::path::Path> { - self.import_caches - .get(vm_id) - .map(NodeImportCache::cache_path) - } -} - -fn set_pending_sync_rpc_state( - pending_sync_rpc: &Arc>>, - id: u64, -) -> Result<(), JavascriptExecutionError> { - let mut pending = pending_sync_rpc.lock().map_err(|_| { - JavascriptExecutionError::RpcResponse(String::from( - "sync RPC pending-request state lock poisoned", - )) - })?; - *pending = Some(PendingSyncRpcState::Pending(id)); - Ok(()) -} - -fn resolve_node_import_compile_cache_dir(root_dir: PathBuf) -> PathBuf { - root_dir.join(format!( - "node-imports-v{NODE_IMPORT_COMPILE_CACHE_NAMESPACE_VERSION}-{:016x}", - stable_compile_cache_namespace_hash() - )) -} - -fn stable_compile_cache_namespace_hash() -> u64 { - stable_hash64( - [ - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_VERSION"), - NODE_ENTRYPOINT_ENV, - NODE_BOOTSTRAP_ENV, - NODE_GUEST_ARGV_ENV, - NODE_PREWARM_IMPORTS_ENV, - NODE_WARMUP_MARKER_VERSION, - ] - .into_iter() - .chain(NODE_WARMUP_SPECIFIERS.iter().copied()) - .collect::>() - .join("\n") - .as_bytes(), - ) -} - -fn javascript_sync_rpc_timeout(request: &StartJavascriptExecutionRequest) -> Duration { - let timeout_ms = request - .limits - .sync_rpc_wait_timeout_ms - .filter(|value| *value > 0) - .unwrap_or(NODE_SYNC_RPC_DEFAULT_WAIT_TIMEOUT_MS); - Duration::from_millis(timeout_ms) -} - -fn javascript_heap_limit_mb(request: &StartJavascriptExecutionRequest) -> u32 { - request - .limits - .v8_heap_limit_mb - .filter(|value| *value > 0) - .unwrap_or(0) -} - -fn javascript_import_cache_materialize_timeout( - request: &StartJavascriptExecutionRequest, -) -> Duration { - let timeout_ms = request - .limits - .import_cache_materialize_timeout_ms - .filter(|value| *value > 0) - .unwrap_or(DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT_MS); - Duration::from_millis(timeout_ms) -} - -/// Resolve the TRUE CPU-time budget (ms) for a JavaScript execution. -/// -/// Read from typed `limits.jsRuntime.cpuTimeLimitMs`, falling back to a bounded -/// default when unset. `0` remains an explicit trusted opt-out and is normalized -/// to `None` by the V8 session. -fn javascript_cpu_time_limit_ms(request: &StartJavascriptExecutionRequest) -> u32 { - request - .limits - .cpu_time_limit_ms - // Generous active-CPU budget: long-lived adapters are still not capped - // on wall-clock, but CPU-bound runaways no longer pin a core forever by - // default. - .unwrap_or(DEFAULT_V8_CPU_TIME_LIMIT_MS) -} - -/// Resolve the opt-in WALL-CLOCK backstop (ms) for a JavaScript execution. -/// -/// Read from typed `limits.jsRuntime.wallClockLimitMs`, falling back to `0` (no -/// limit). `0` is normalized to `None` by the V8 session, so the wall-clock -/// `TimeoutGuard` is NOT armed and the guest runs without a wall-clock limit. -/// This is INDEPENDENT of the CPU-time budget: setting only one arms only that -/// guard. -fn javascript_wall_clock_limit_ms(request: &StartJavascriptExecutionRequest) -> u32 { - request - .limits - .wall_clock_limit_ms - .unwrap_or(DEFAULT_V8_WALL_CLOCK_LIMIT_MS) -} - -fn spawn_javascript_sync_rpc_timeout( - id: u64, - timeout: Duration, - pending_state: Arc>>, - responses: Option, -) { - let Some(responses) = responses else { - return; - }; - - thread::spawn(move || { - thread::sleep(timeout); - - let should_timeout = match pending_state.lock() { - Ok(mut guard) if *guard == Some(PendingSyncRpcState::Pending(id)) => { - *guard = Some(PendingSyncRpcState::TimedOut(id)); - true - } - Ok(_) => false, - Err(_) => false, - }; - - if !should_timeout { - return; - } - - let _ = write_javascript_sync_rpc_response( - &responses, - json!({ - "id": id, - "ok": false, - "error": { - "code": "ERR_AGENTOS_NODE_SYNC_RPC_TIMEOUT", - "message": format!( - "guest JavaScript sync RPC request {id} timed out after {}ms", - timeout.as_millis() - ), - }, - }), - ); - }); -} - -fn spawn_javascript_sync_rpc_reader( - reader: File, - sender: mpsc::Sender, -) -> std::thread::JoinHandle<()> { - std::thread::spawn(move || { - let mut reader = BufReader::new(reader); - let mut line = String::new(); - - loop { - line.clear(); - match reader.read_line(&mut line) { - Ok(0) => return, - Ok(_) => { - let trimmed = line.trim(); - if trimmed.is_empty() { - continue; - } - - match parse_javascript_sync_rpc_request(trimmed) { - Ok(request) => { - if sender - .send(JavascriptProcessEvent::SyncRpcRequest(request)) - .is_err() - { - return; - } - } - Err(message) => { - if sender - .send(JavascriptProcessEvent::RawStderr( - format!("{message}\n").into_bytes(), - )) - .is_err() - { - return; - } - } - } - } - Err(error) => { - let _ = sender.send(JavascriptProcessEvent::RawStderr( - format!("failed to read JavaScript sync RPC request: {error}\n") - .into_bytes(), - )); - return; - } - } - } - }) -} - -fn parse_javascript_sync_rpc_request(line: &str) -> Result { - let wire: JavascriptSyncRpcRequestWire = - serde_json::from_str(line).map_err(|error| error.to_string())?; - Ok(JavascriptSyncRpcRequest { - id: wire.id, - method: wire.method, - args: wire.args, - raw_bytes_args: HashMap::new(), - }) -} - -fn write_javascript_sync_rpc_response( - writer: &JavascriptSyncRpcResponseWriter, - response: Value, -) -> Result<(), JavascriptExecutionError> { - let mut payload = serde_json::to_vec(&response) - .map_err(|error| JavascriptExecutionError::RpcResponse(error.to_string()))?; - payload.push(b'\n'); - writer.send(payload) -} - -fn spawn_javascript_sync_rpc_response_writer( - writer: File, - receiver: Receiver>, -) -> thread::JoinHandle<()> { - thread::spawn(move || { - let mut writer = BufWriter::new(writer); - while let Ok(payload) = receiver.recv() { - if writer - .write_all(&payload) - .and_then(|()| writer.flush()) - .is_err() - { - return; - } - } - }) -} - -/// Build the user code wrapper for V8 execution. -/// This wraps the entrypoint in a way that the V8 bridge can execute it. -fn build_v8_user_code(entrypoint: &str, env: &BTreeMap) -> String { - // The bridge code (polyfills) sets up the module system and globals. - // User code is executed after the bridge completes. - // For file-based entrypoints, we load and execute them through the module system. - // For inline code (-e flag), we execute directly. - if entrypoint == "-e" || entrypoint == "--eval" { - // Inline code from NODE_EVAL or similar - env.get("AGENTOS_NODE_EVAL").cloned().unwrap_or_default() - } else { - // Module entrypoint - use require to load it - format!( - "require({});\n//# sourceURL={}", - serde_json::to_string(entrypoint).unwrap_or_else(|_| format!("\"{}\"", entrypoint)), - entrypoint - ) - } -} - -fn host_entrypoint_uses_module_mode(entrypoint: &Path) -> bool { - // Agent adapters are launched via an extensionless `/opt/agentos/bin/` - // symlink into the packed package's `node_modules//`. Resolve it - // to the real file so the extension check and the nearest-`package.json` walk - // reflect the package (which carries `"type": "module"`), not the symlink farm - // (which has neither an extension nor a package.json). - let resolved = fs::canonicalize(entrypoint).unwrap_or_else(|_| entrypoint.to_path_buf()); - match resolved.extension().and_then(|ext| ext.to_str()) { - Some("mjs" | "mts") => true, - Some("js") => nearest_package_json_type(&resolved).as_deref() == Some("module"), - _ => false, - } -} - -fn inline_code_uses_module_mode(source: &str) -> bool { - let sanitized = strip_non_code_segments(source); - let tokens = tokenize_inline_module_source(&sanitized); - let has_commonjs_signal = tokens.windows(3).any(|window| { - matches!( - window, - [ - InlineModuleToken::Identifier("module"), - InlineModuleToken::Punct('.'), - InlineModuleToken::Identifier("exports") - ] - ) - }) || tokens.windows(2).any(|window| { - matches!( - window, - [ - InlineModuleToken::Identifier("exports"), - InlineModuleToken::Punct('.' | '[') - ] | [ - InlineModuleToken::Identifier("require"), - InlineModuleToken::Punct('(') - ] - ) - }); - - if has_commonjs_signal { - return false; - } - - tokens.windows(2).any(|window| match window { - [InlineModuleToken::Identifier("import"), InlineModuleToken::Punct('.')] => true, - [InlineModuleToken::Identifier("import"), InlineModuleToken::Punct('(' | ':')] => false, - [InlineModuleToken::Identifier("import"), InlineModuleToken::Identifier(_) - | InlineModuleToken::Punct('{') - | InlineModuleToken::Punct('*') - | InlineModuleToken::StringLiteral] => true, - [InlineModuleToken::Identifier("export"), InlineModuleToken::Identifier( - "default" | "const" | "let" | "var" | "function" | "class" | "async" | "enum" | "type" - | "interface", - ) - | InlineModuleToken::Punct('{') - | InlineModuleToken::Punct('*')] => true, - _ => false, - }) -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum InlineModuleToken<'a> { - Identifier(&'a str), - StringLiteral, - Punct(char), -} - -const INLINE_MODULE_STRING_PLACEHOLDER: char = '\u{1F}'; - -fn strip_non_code_segments(source: &str) -> String { - let mut sanitized = String::with_capacity(source.len()); - let bytes = source.as_bytes(); - let mut index = 0; - sanitize_javascript_code(bytes, &mut index, &mut sanitized, None); - sanitized -} - -fn sanitize_javascript_code( - bytes: &[u8], - index: &mut usize, - output: &mut String, - until_brace_depth: Option, -) { - let mut brace_depth = 0usize; - - while *index < bytes.len() { - let current = bytes[*index]; - - if let Some(target_depth) = until_brace_depth { - match current { - b'{' => brace_depth += 1, - b'}' => { - if brace_depth == target_depth { - output.push(' '); - *index += 1; - return; - } - brace_depth = brace_depth.saturating_sub(1); - } - _ => {} - } - } - - match current { - b'/' if bytes.get(*index + 1) == Some(&b'/') => { - output.push(' '); - output.push(' '); - *index += 2; - while *index < bytes.len() { - let comment_byte = bytes[*index]; - *index += 1; - if comment_byte == b'\n' { - output.push('\n'); - break; - } - output.push(' '); - } - } - b'/' if bytes.get(*index + 1) == Some(&b'*') => { - output.push(' '); - output.push(' '); - *index += 2; - while *index < bytes.len() { - let comment_byte = bytes[*index]; - if comment_byte == b'*' && bytes.get(*index + 1) == Some(&b'/') { - output.push(' '); - output.push(' '); - *index += 2; - break; - } - output.push(if comment_byte == b'\n' { '\n' } else { ' ' }); - *index += 1; - } - } - b'\'' | b'"' => sanitize_string_literal(bytes, index, output, current), - b'`' => sanitize_template_literal(bytes, index, output), - _ => { - output.push(char::from(current)); - *index += 1; - } - } - } -} - -fn sanitize_string_literal(bytes: &[u8], index: &mut usize, output: &mut String, quote: u8) { - output.push(INLINE_MODULE_STRING_PLACEHOLDER); - *index += 1; - - while *index < bytes.len() { - let current = bytes[*index]; - *index += 1; - match current { - b'\\' => { - if *index < bytes.len() { - *index += 1; - } - } - c if c == quote => break, - _ => {} - } - } -} - -fn sanitize_template_literal(bytes: &[u8], index: &mut usize, output: &mut String) { - output.push(INLINE_MODULE_STRING_PLACEHOLDER); - *index += 1; - - while *index < bytes.len() { - let current = bytes[*index]; - match current { - b'\\' => { - *index += 1; - if *index < bytes.len() { - *index += 1; - } - } - b'`' => { - *index += 1; - break; - } - b'$' if bytes.get(*index + 1) == Some(&b'{') => { - output.push(' '); - output.push(' '); - *index += 2; - sanitize_javascript_code(bytes, index, output, Some(0)); - output.push(INLINE_MODULE_STRING_PLACEHOLDER); - } - b'\n' => { - output.push('\n'); - *index += 1; - } - _ => { - *index += 1; - } - } - } -} - -fn tokenize_inline_module_source(source: &str) -> Vec> { - let mut tokens = Vec::new(); - let bytes = source.as_bytes(); - let mut index = 0; - - while index < bytes.len() { - let current = bytes[index]; - match current { - b if b.is_ascii_whitespace() => index += 1, - b if char::from(b) == INLINE_MODULE_STRING_PLACEHOLDER => { - tokens.push(InlineModuleToken::StringLiteral); - index += 1; - } - b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'$' => { - let start = index; - index += 1; - while index < bytes.len() - && matches!(bytes[index], b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_' | b'$') - { - index += 1; - } - tokens.push(InlineModuleToken::Identifier(&source[start..index])); - } - _ => { - tokens.push(InlineModuleToken::Punct(char::from(current))); - index += 1; - } - } - } - - tokens -} - -fn nearest_package_json_type(entrypoint: &Path) -> Option { - let mut current = entrypoint.parent(); - while let Some(dir) = current { - let package_json = dir.join("package.json"); - if let Ok(contents) = fs::read_to_string(&package_json) { - if let Ok(pkg) = serde_json::from_str::(&contents) { - return pkg.package_type; - } - } - current = dir.parent(); - } - None -} - -fn resolve_v8_entrypoint(cwd: &Path, entrypoint: &str) -> String { - if entrypoint == "-e" || entrypoint == "--eval" { - return entrypoint.to_owned(); - } - - let path = Path::new(entrypoint); - let resolved = if path.is_absolute() { - path.to_path_buf() - } else { - cwd.join(path) - }; - resolved.to_string_lossy().into_owned() -} - -fn prepend_v8_runtime_shim( - user_code: String, - entrypoint: &str, - argv: &[String], - cwd: &str, - env: &BTreeMap, - // V8 heap cap in MB (`0` = engine default). Threaded from the typed wire - // limit and interpolated into the shim so guest heap-stats reporting no - // longer depends on an `AGENTOS_V8_HEAP_LIMIT_MB` env var. - heap_limit_mb: u32, - // Typed guest-runtime identity, interpolated into the shim so virtual - // `process.*` identity no longer rides `AGENTOS_VIRTUAL_PROCESS_*` env vars. - guest_runtime: &GuestRuntimeConfig, -) -> String { - let argv_json = serde_json::to_string(argv).unwrap_or_else(|_| String::from("[\"node\"]")); - let entry_json = - serde_json::to_string(entrypoint).unwrap_or_else(|_| String::from("\"/\"")); - let cwd_json = serde_json::to_string(cwd).unwrap_or_else(|_| String::from("\"/\"")); - let env_json = serde_json::to_string(env).unwrap_or_else(|_| String::from("{}")); - // Virtual process identity object. `Option` fields serialize to `null`, which - // the shim treats as "unset" (leaving the V8-baked default) — matching the - // prior behavior when the env var was absent. - let identity_json = serde_json::json!({ - "pid": guest_runtime.virtual_pid, - "ppid": guest_runtime.virtual_ppid, - "uid": guest_runtime.virtual_uid, - "gid": guest_runtime.virtual_gid, - "execPath": guest_runtime.virtual_exec_path, - }) - .to_string(); - // Virtual OS identity (os.cpus/totalmem/freemem/homedir/userInfo/...). Read - // by the bridge + node-import-cache os polyfill from the `__agentOSVirtualOs` - // global instead of `AGENTOS_VIRTUAL_OS_*` env vars. Absent fields stay - // `null`, so the consumers fall back to their built-in defaults. - let virtual_os_json = serde_json::json!({ - "cpuCount": guest_runtime.os_cpu_count, - "totalmem": guest_runtime.os_totalmem, - "freemem": guest_runtime.os_freemem, - "homedir": guest_runtime.os_homedir, - "hostname": guest_runtime.os_hostname, - "tmpdir": guest_runtime.os_tmpdir, - "type": guest_runtime.os_type, - "release": guest_runtime.os_release, - "version": guest_runtime.os_version, - "machine": guest_runtime.os_machine, - "shell": guest_runtime.os_shell, - "user": guest_runtime.os_user, - }) - .to_string(); - let high_resolution_time = guest_runtime.high_resolution_time; - - format!( - r#"(function () {{ - const __guestIdentity = {identity_json}; - Object.defineProperty(globalThis, "__agentOSVirtualOs", {{ - configurable: true, - enumerable: false, - value: {virtual_os_json}, - writable: true, - }}); - const nextArgv = {argv_json}; - const entryFile = {entry_json}; - const nextCwd = {cwd_json}; - const nextEnv = {env_json}; - const nextHighResolutionTime = {high_resolution_time}; - try {{ - const previousProcessConfig = - typeof globalThis._processConfig === "object" && globalThis._processConfig !== null - ? globalThis._processConfig - : {{}}; - Object.defineProperty(globalThis, "_processConfig", {{ - configurable: true, - enumerable: false, - value: Object.freeze({{ - ...previousProcessConfig, - cwd: nextCwd, - env: nextEnv, - argv: nextArgv, - high_resolution_time: nextHighResolutionTime, - }}), - writable: false, - }}); - }} catch (_e) {{}} - Object.defineProperty(globalThis, "__agentOSProcessConfigEnv", {{ - configurable: true, - enumerable: false, - value: nextEnv, - writable: true, - }}); - const visibleEnv = Object.fromEntries( - Object.entries(nextEnv).filter(([key]) => !key.startsWith("AGENTOS_")) - ); - - if (typeof process !== "undefined") {{ - process.argv = nextArgv; - process.argv0 = nextArgv[0] || "node"; - process.env = {{ - ...(process.env || {{}}), - ...visibleEnv, - }}; - const configuredHeapLimitMb = {heap_limit_mb}; - if (Number.isFinite(configuredHeapLimitMb) && configuredHeapLimitMb > 0) {{ - Object.defineProperty(globalThis, "__agentOSV8HeapLimitBytes", {{ - configurable: true, - enumerable: false, - value: configuredHeapLimitMb * 1024 * 1024, - writable: true, - }}); - }} - if (nextEnv.AGENTOS_ALLOW_PROCESS_BINDINGS === "1" && typeof process.binding === "function") {{ - const originalProcessBinding = process.binding.bind(process); - process.binding = (name) => {{ - const bindingName = String(name); - if ( - bindingName === "constants" && - typeof __agentOSConstantsBinding !== "undefined" - ) {{ - const constantsBinding = - __agentOSConstantsBinding.default ?? __agentOSConstantsBinding; - return {{ - fs: constantsBinding, - crypto: constantsBinding, - zlib: constantsBinding, - trace: constantsBinding, - internal: constantsBinding, - os: {{ - UV_UDP_REUSEADDR: constantsBinding.UV_UDP_REUSEADDR, - dlopen: constantsBinding.dlopen, - errno: constantsBinding.errno, - signals: constantsBinding.signals, - priority: constantsBinding.priority, - }}, - }}; - }} - try {{ - return originalProcessBinding(name); - }} catch (error) {{ - const originalMessage = - error && typeof error === "object" && typeof error.message === "string" - ? error.message - : String(error); - throw new Error( - `process.binding(${{bindingName}}) failed: ${{originalMessage}}` - ); - }} - }}; - }} - const nextPid = Number(__guestIdentity.pid); - if (Number.isFinite(nextPid) && nextPid > 0) {{ - process.pid = nextPid; - }} - const nextPpid = Number(__guestIdentity.ppid); - if (Number.isFinite(nextPpid) && nextPpid >= 0) {{ - process.ppid = nextPpid; - }} - const nextUid = Number(__guestIdentity.uid); - if (Number.isFinite(nextUid) && nextUid >= 0) {{ - process.uid = nextUid; - process.euid = nextUid; - }} - const nextGid = Number(__guestIdentity.gid); - if (Number.isFinite(nextGid) && nextGid >= 0) {{ - process.gid = nextGid; - process.egid = nextGid; - process.groups = [nextGid]; - }} - if (typeof __guestIdentity.execPath === "string" && __guestIdentity.execPath.length > 0) {{ - process.execPath = __guestIdentity.execPath; - }} - if (nextEnv.AGENTOS_NODE_IPC === "1" && typeof __runtimeInstallProcessIpcBridge === "function") {{ - process.connected = true; - __runtimeInstallProcessIpcBridge(); - }} - process.cwd = () => nextCwd; - process._cwd = nextCwd; - if (typeof process.getBuiltinModule !== "function") {{ - process.getBuiltinModule = function(specifier) {{ - return globalThis.require ? globalThis.require(specifier) : undefined; - }}; - }} - }} - - globalThis.__runtimeStreamStdin = nextEnv.SECURE_EXEC_KEEP_STDIN_OPEN === "1"; - - if ( - typeof globalThis.WebAssembly === "object" && - globalThis.WebAssembly !== null && - typeof globalThis.WebAssembly.instantiateStreaming !== "function" - ) {{ - globalThis.WebAssembly.instantiateStreaming = async function instantiateStreaming(source, imports) {{ - const response = await source; - if (response == null || typeof response.arrayBuffer !== "function") {{ - throw new TypeError( - "WebAssembly.instantiateStreaming requires a Response or promise for one", - ); - }} - const bytes = new Uint8Array(await response.arrayBuffer()); - return globalThis.WebAssembly.instantiate(bytes, imports); - }}; - }} - - if ( - typeof globalThis.require === "undefined" && - typeof globalThis._moduleModule?.createRequire === "function" - ) {{ - const requireEntryFile = - entryFile === "-e" || entryFile === "--eval" - ? nextCwd === "/" - ? "/__agentos_eval__.js" - : `${{nextCwd.replace(/\/+$/, "")}}/__agentos_eval__.js` - : entryFile; - globalThis.require = - globalThis._moduleModule.createRequire(requireEntryFile); - }} - - // jsRuntime platform tiering: the guest JS host surface is baked into the - // shared V8 snapshot, so non-node platforms are produced by subtractively - // scrubbing baked globals here, per execution. - const __jsPlatform = nextEnv.AGENTOS_JS_PLATFORM || "node"; - // Install the builtin allow-list gate consulted by the bridge's - // rejectRestrictedBuiltinRequest (covers require + ESM builtin loads). Present - // for non-node platforms (empty => deny all) and node + explicit allow-list; - // absent => unrestricted (node default). - {{ - const __builtinAllowRaw = nextEnv.AGENTOS_JS_BUILTIN_ALLOWLIST; - if (typeof __builtinAllowRaw === "string") {{ - let __allowList = []; - try {{ __allowList = JSON.parse(__builtinAllowRaw); }} catch (_e) {{ __allowList = []; }} - if (typeof globalThis.__agentOSInitJsRuntime === "function") {{ - globalThis.__agentOSInitJsRuntime(Array.isArray(__allowList) ? __allowList : []); - }} - try {{ delete globalThis.__agentOSInitJsRuntime; }} catch (_e) {{}} - }} - }} - if (__jsPlatform !== "node") {{ - const __dropGlobal = (name) => {{ - try {{ delete globalThis[name]; }} catch (_e) {{}} - if ( - Object.prototype.hasOwnProperty.call(globalThis, name) || - typeof globalThis[name] !== "undefined" - ) {{ - try {{ globalThis[name] = undefined; }} catch (_e) {{}} - try {{ - Object.defineProperty(globalThis, name, {{ - value: undefined, - configurable: true, - writable: true, - }}); - }} catch (_e) {{}} - try {{ delete globalThis[name]; }} catch (_e) {{}} - }} - }}; - // Node host surface + identity channels — removed on every non-node platform. - [ - "process", "Buffer", "require", "module", "exports", - "__dirname", "__filename", "global", - "_processConfig", "__agentOSProcessConfigEnv", "__agentOSVirtualOs", - ].forEach(__dropGlobal); - if (__jsPlatform === "browser") {{ - // Narrow `crypto` from the full node:crypto module to the WebCrypto object - // (drops randomBytes/createHash/... while keeping subtle/getRandomValues). - try {{ - const __wc = globalThis.crypto && globalThis.crypto.webcrypto; - if (__wc) {{ globalThis.crypto = __wc; }} - }} catch (_e) {{}} - }} - if (__jsPlatform === "neutral" || __jsPlatform === "bare") {{ - // Web-platform globals removed at neutral and below. - [ - "fetch", "Headers", "Request", "Response", "FormData", - "URL", "URLSearchParams", "Blob", "File", "crypto", - "atob", "btoa", "structuredClone", "performance", - "AbortController", "AbortSignal", "Event", "EventTarget", - "MessageChannel", "MessagePort", "MessageEvent", - "ReadableStream", "WritableStream", "TransformStream", - ].forEach(__dropGlobal); - }} - if (__jsPlatform === "bare") {{ - // Universal host primitives removed only at the language-only tier. - [ - "console", "queueMicrotask", - "setTimeout", "clearTimeout", "setInterval", "clearInterval", - "setImmediate", "clearImmediate", - ].forEach(__dropGlobal); - }} - }} -}})(); -{user_code}"# - ) -} - -/// Spawn a V8 event bridge thread that converts V8 BinaryFrame messages -/// into JavascriptExecutionEvent for the sidecar event loop. -/// -/// Internal bridge calls (module loading, logging, timers) are handled locally -/// by the event bridge. Kernel operations (fs, net, child_process, dns) are -/// forwarded to the sidecar via SyncRpcRequest events. -fn spawn_v8_event_bridge( - frame_receiver: TrackedReceiver, - pending_sync_rpc: Arc>>, - _sync_rpc_timeout: Duration, - v8_session: V8SessionHandle, - mut local_bridge: LocalBridgeState, - event_notify: Option>, -) -> TokioReceiver { - let (sender, receiver) = channel(JAVASCRIPT_EVENT_CHANNEL_CAPACITY); - let event_gauge = register_queue( - TrackedLimit::JavascriptEventChannel, - JAVASCRIPT_EVENT_CHANNEL_CAPACITY, - ); - - thread::spawn(move || { - let mut emitted_exit = false; - loop { - let frame_recv_start = Instant::now(); - let Ok(frame) = frame_receiver.recv() else { - break; - }; - let frame_recv_wait = frame_recv_start.elapsed(); - let mut exit_frame_start = None; - let event = match frame { - BinaryFrame::BridgeCall { - call_id, - method, - payload, - .. - } => { - // Convert CBOR payload to JSON args - let phase_start = Instant::now(); - let args = v8_runtime::cbor_payload_to_json_args(&payload).unwrap_or_default(); - record_sync_bridge_phase(&method, "event_decode_args", phase_start.elapsed()); - - // Module resolution / loading must read the mounted - // `node_modules` VFS, not host files directly. When the - // sidecar supplied a read-only VFS module reader, resolve - // these inline on this bridge thread (off the service loop) so - // a large cold-start module graph runs concurrently with — and - // never serializes behind / starves — the ACP bootstrap that - // is itself awaiting the adapter's `session/new` response on - // the single service-loop thread. Without a reader (no mount), - // they flow to the service loop as SyncRpcRequests (mapped to - // `__resolve_module` / `__load_file` / `__module_format` / - // `__batch_resolve_modules`) and resolve against `vm.kernel`. - let is_module_method = matches!( - method.as_str(), - "_resolveModule" - | "_resolveModuleSync" - | "_loadFile" - | "_loadFileSync" - | "_moduleFormat" - | "_batchResolveModules" - ); - let resolve_on_service_loop = - is_module_method && !local_bridge.has_module_reader(); - - // Check if this is an internal bridge call we handle locally - if !resolve_on_service_loop { - if let Some(response) = - local_bridge.handle_internal_bridge_call(call_id, &method, &args) - { - if let LocalBridgeCallResult::Immediate(response) = response { - let cbor_payload = - v8_runtime::json_to_cbor_payload(&response).unwrap_or_default(); - let _ = v8_session.send_bridge_response(call_id, 0, cbor_payload); - } - continue; - } - } - - // Handle logging locally (produce stdout/stderr events) - if method == "_log" || method == "_error" { - let output = decode_bridge_output_args(&args); - // Respond to the bridge call - let _ = v8_session.send_bridge_response( - call_id, - 0, - v8_runtime::json_to_cbor_payload(&Value::Null).unwrap_or_default(), - ); - if method == "_log" { - if !send_javascript_event( - &sender, - &v8_session, - &event_gauge, - event_notify.as_deref(), - JavascriptExecutionEvent::Stdout(output), - ) { - break; - } - } else { - if !send_javascript_event( - &sender, - &v8_session, - &event_gauge, - event_notify.as_deref(), - JavascriptExecutionEvent::Stderr(output), - ) { - break; - } - } - continue; - } - - // Map the bridge method name to the sidecar sync RPC method name - let phase_start = Instant::now(); - let (sidecar_method, _needs_translation) = - v8_runtime::map_bridge_method(&method); - record_sync_bridge_phase(&method, "event_map_method", phase_start.elapsed()); - - // Track pending sync RPC - let phase_start = Instant::now(); - if let Ok(mut pending) = pending_sync_rpc.lock() { - *pending = Some(PendingSyncRpcState::Pending(call_id)); - } - record_sync_bridge_phase(&method, "event_mark_pending", phase_start.elapsed()); - - let phase_start = Instant::now(); - let request_args = translate_request_args_for_legacy(sidecar_method, &args); - let mut raw_bytes_args = HashMap::new(); - if sidecar_method == "net.write" - || sidecar_method == "fs.writeSync" - || sidecar_method == "fs.writevSync" - || sidecar_method == "fs.writeFileSync" - { - if let Ok(Some(bytes)) = v8_runtime::cbor_payload_raw_byte_arg(&payload, 1) - { - raw_bytes_args.insert(1, bytes); - } - } - if method == "_fsReadRaw" { - raw_bytes_args.insert(usize::MAX, Vec::new()); - } - record_sync_bridge_phase( - &method, - "event_translate_args", - phase_start.elapsed(), - ); - Some(JavascriptExecutionEvent::SyncRpcRequest( - JavascriptSyncRpcRequest { - id: call_id, - method: sidecar_method.to_owned(), - args: request_args, - raw_bytes_args, - }, - )) - } - BinaryFrame::Log { - channel, message, .. - } => { - if channel == 0 { - Some(JavascriptExecutionEvent::Stdout(message.into_bytes())) - } else { - Some(JavascriptExecutionEvent::Stderr(message.into_bytes())) - } - } - BinaryFrame::ExecutionResult { - exit_code, error, .. - } => { - let phase_start = Instant::now(); - exit_frame_start = Some(phase_start); - record_js_event_phase("js_exit_frame_recv_wait", frame_recv_wait); - let is_process_exit_error = error.as_ref().is_some_and(|err| { - err.error_type == "ProcessExitError" - || err.message.starts_with("process.exit(") - }); - let resolved_exit_code = error - .as_ref() - .and_then(|err| { - if is_process_exit_error { - parse_process_exit_code_message(&err.message) - } else { - None - } - }) - .unwrap_or(exit_code); - let should_emit_error = error.is_some() && !is_process_exit_error; - if should_emit_error { - let err = error.as_ref().expect("checked above"); - let error_msg = if err.stack.is_empty() { - format!("{}: {}\n", err.error_type, err.message) - } else { - format!("{}\n", err.stack) - }; - if !send_javascript_event( - &sender, - &v8_session, - &event_gauge, - event_notify.as_deref(), - JavascriptExecutionEvent::Stderr(error_msg.into_bytes()), - ) { - break; - } - } - emitted_exit = true; - record_js_event_phase( - "js_exit_frame_to_event_construct", - phase_start.elapsed(), - ); - Some(JavascriptExecutionEvent::Exited(resolved_exit_code)) - } - BinaryFrame::StreamCallback { .. } => None, - _ => None, - }; - - if let Some(event) = event { - let sync_rpc = match &event { - JavascriptExecutionEvent::SyncRpcRequest(request) => { - Some((request.id, request.method.clone())) - } - _ => None, - }; - if let Some((call_id, method)) = sync_rpc.as_ref() { - record_sync_bridge_request_enqueued(*call_id, method); - } - let phase_start = sync_rpc.as_ref().map(|_| Instant::now()); - let exit_send_start = if matches!(&event, JavascriptExecutionEvent::Exited(_)) { - Some(Instant::now()) - } else { - None - }; - if !send_javascript_event( - &sender, - &v8_session, - &event_gauge, - event_notify.as_deref(), - event, - ) { - break; - } - if let (Some((_, method)), Some(start)) = (sync_rpc, phase_start) { - record_sync_bridge_phase(&method, "event_enqueue", start.elapsed()); - } - if let Some(start) = exit_send_start { - record_js_event_phase("js_exit_event_send", start.elapsed()); - } - if let Some(start) = exit_frame_start { - record_js_event_phase("js_exit_frame_to_event_sent", start.elapsed()); - } - } - } - - if !emitted_exit { - let phase_start = Instant::now(); - let sent = send_javascript_event( - &sender, - &v8_session, - &event_gauge, - event_notify.as_deref(), - JavascriptExecutionEvent::Exited(1), - ); - if sent { - record_js_event_phase("js_exit_fallback_event_send", phase_start.elapsed()); - } - } - }); - - receiver -} - -fn send_javascript_event( - sender: &tokio::sync::mpsc::Sender, - v8_session: &V8SessionHandle, - gauge: &secure_exec_bridge::queue_tracker::QueueGauge, - notify: Option<&Notify>, - event: JavascriptExecutionEvent, -) -> bool { - if javascript_event_payload_len(&event) > JAVASCRIPT_EVENT_PAYLOAD_LIMIT_BYTES { - let _ = v8_session.destroy(); - return false; - } - - // Apply backpressure instead of self-destructing when the host consumer is - // slow. A burst of guest events that briefly outpaces the host draining this - // channel is normal; previously a single `try_send` returning `Full` tore the - // whole session down (`destroy()` -> Shutdown -> `Exited(1)`), turning a - // transient backlog into a fatal crash. This bridge runs on its own dedicated - // OS thread (never a Tokio runtime worker), so a blocking send is safe: it - // parks this thread — and, in turn, the guest producing into it — until the - // host drains capacity. The only terminal condition is the receiver being - // dropped (host gone for good), which surfaces as `Closed` and stops the loop. - match sender.blocking_send(event) { - Ok(()) => { - // Sample the live channel depth so the centralized queue tracker can - // warn before the host consumer falls far enough behind to stall the - // session (and surface the high-water mark for debugging). - gauge.observe_depth(sender.max_capacity().saturating_sub(sender.capacity())); - if let Some(notify) = notify { - notify.notify_one(); - } - true - } - Err(_closed) => false, - } -} - -fn javascript_event_payload_len(event: &JavascriptExecutionEvent) -> usize { - match event { - JavascriptExecutionEvent::Stdout(chunk) | JavascriptExecutionEvent::Stderr(chunk) => { - chunk.len() - } - JavascriptExecutionEvent::SyncRpcRequest(_) - | JavascriptExecutionEvent::SignalState { .. } - | JavascriptExecutionEvent::Exited(_) => 0, - } -} - -/// Handle internal bridge calls that don't need to go to the sidecar. -/// Returns Some(response) if handled locally, None if it should be forwarded. -impl LocalBridgeState { - fn handle_internal_bridge_call( - &mut self, - call_id: u64, - method: &str, - args: &[Value], - ) -> Option { - match method { - "_resolveModule" | "_resolveModuleSync" => { - let specifier = args.first().and_then(Value::as_str).unwrap_or(""); - let parent = args.get(1).and_then(Value::as_str).unwrap_or("/"); - let mode = match args.get(2).and_then(Value::as_str) { - Some("import") => ModuleResolveMode::Import, - Some("require") => ModuleResolveMode::Require, - _ if method == "_resolveModule" => ModuleResolveMode::Import, - _ => ModuleResolveMode::Require, - }; - if self.js_runtime_denies_specifier(specifier) { - return Some(LocalBridgeCallResult::Immediate(Value::Null)); - } - let resolved = self.with_module_resolver(|resolver| { - resolver.resolve_module(specifier, parent, mode) - }); - if resolved.is_none() && self.has_module_reader() { - return None; - } - Some(LocalBridgeCallResult::Immediate( - resolved.map(Value::String).unwrap_or(Value::Null), - )) - } - "_moduleFormat" => { - let format = self.module_format(args.first().and_then(Value::as_str).unwrap_or("")); - if format.is_none() && self.has_module_reader() { - return None; - } - Some(LocalBridgeCallResult::Immediate( - format - .map(|format| Value::String(String::from(format.as_str()))) - .unwrap_or(Value::Null), - )) - } - "_loadFile" | "_loadFileSync" => { - let source = self.load_file(args.first().and_then(Value::as_str).unwrap_or("")); - if source.is_none() && self.has_module_reader() { - return None; - } - Some(LocalBridgeCallResult::Immediate( - source.map(Value::String).unwrap_or(Value::Null), - )) - } - "_batchResolveModules" => { - let resolved = self.batch_resolve_modules(args); - if self.has_module_reader() - && resolved - .as_array() - .is_some_and(|items| items.iter().any(Value::is_null)) - { - return None; - } - Some(LocalBridgeCallResult::Immediate(resolved)) - } - "_loadPolyfill" => Some(LocalBridgeCallResult::Immediate( - self.handle_polyfill_dispatch(args), - )), - "_cryptoRandomFill" => { - let size = args.first().and_then(Value::as_u64).unwrap_or(16) as usize; - let mut bytes = vec![0u8; size]; - if getrandom(&mut bytes).is_err() { - return Some(LocalBridgeCallResult::Immediate(Value::Null)); - } - Some(LocalBridgeCallResult::Immediate(Value::String( - v8_runtime::base64_encode_pub(&bytes), - ))) - } - "_cryptoRandomUUID" => { - let mut bytes = [0u8; 16]; - if getrandom(&mut bytes).is_err() { - return Some(LocalBridgeCallResult::Immediate(Value::Null)); - } - bytes[6] = (bytes[6] & 0x0f) | 0x40; - bytes[8] = (bytes[8] & 0x3f) | 0x80; - - Some(LocalBridgeCallResult::Immediate(Value::String(format!( - "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", - bytes[0], - bytes[1], - bytes[2], - bytes[3], - bytes[4], - bytes[5], - bytes[6], - bytes[7], - bytes[8], - bytes[9], - bytes[10], - bytes[11], - bytes[12], - bytes[13], - bytes[14], - bytes[15], - )))) - } - "_kernelStdinRead" | "_kernelStdinReadRaw" if self.forward_kernel_stdin_rpc => None, - "_kernelStdinRead" | "_kernelStdinReadRaw" => Some(LocalBridgeCallResult::Immediate( - self.kernel_stdin.read(args), - )), - "_pythonStdinRead" => Some(LocalBridgeCallResult::Immediate( - self.kernel_stdin.read_python_raw(args), - )), - "_scheduleTimer" => { - self.schedule_bridge_timer_response(call_id, timer_delay_ms(args.first())); - Some(LocalBridgeCallResult::Deferred) - } - _ => None, - } - } - - fn handle_polyfill_dispatch(&mut self, args: &[Value]) -> Value { - let Some(dispatch) = args.first().and_then(Value::as_str) else { - return Value::Null; - }; - if !dispatch.starts_with("__bd:") { - return polyfill_expression(dispatch) - .map(Value::String) - .unwrap_or(Value::Null); - } - let (dispatch_method, payload_json) = dispatch - .strip_prefix("__bd:") - .and_then(|value| value.split_once(':')) - .unwrap_or(("", "[]")); - let payload = serde_json::from_str::(payload_json).unwrap_or_else(|_| json!([])); - let args = payload.as_array().cloned().unwrap_or_default(); - let result = match dispatch_method { - "kernelHandleRegister" => { - if let (Some(id), Some(description)) = ( - args.first().and_then(Value::as_str), - args.get(1).and_then(Value::as_str), - ) { - self.handle_descriptions - .insert(id.to_owned(), description.to_owned()); - } - Value::Null - } - "kernelHandleUnregister" => { - if let Some(id) = args.first().and_then(Value::as_str) { - self.handle_descriptions.remove(id); - } - Value::Null - } - "kernelHandleList" => Value::Array( - self.handle_descriptions - .iter() - .map(|(id, description)| { - json!({ - "id": id, - "description": description, - }) - }) - .collect(), - ), - "kernelTimerCreate" => { - let delay_ms = timer_delay_ms(args.first()); - let repeat = args.get(1).and_then(Value::as_bool).unwrap_or(false); - json!(self.create_kernel_timer(delay_ms, repeat)) - } - "kernelTimerArm" => { - if let Some(timer_id) = args.first().and_then(Value::as_u64) { - self.arm_kernel_timer(timer_id); - } - Value::Null - } - "kernelTimerClear" => { - if let Some(timer_id) = args.first().and_then(Value::as_u64) { - self.clear_kernel_timer(timer_id); - } - Value::Null - } - _ => json!({ - "__bd_error": { - "name": "Error", - "message": format!("No handler: {dispatch_method}"), - } - }), - }; - - if dispatch_method.starts_with("kernel") { - Value::String( - serde_json::to_string(&json!({ "__bd_result": result })) - .unwrap_or_else(|_| String::from("{\"__bd_result\":null}")), - ) - } else { - Value::String( - serde_json::to_string(&json!({ - "__bd_error": { - "name": "Error", - "message": format!("No handler: {dispatch_method}"), - } - })) - .unwrap_or_else(|_| { - String::from( - "{\"__bd_error\":{\"name\":\"Error\",\"message\":\"dispatch failed\"}}", - ) - }), - ) - } - } - - fn create_kernel_timer(&mut self, delay_ms: u64, repeat: bool) -> u64 { - self.next_timer_id += 1; - if let Ok(mut timers) = self.timers.lock() { - timers.insert( - self.next_timer_id, - LocalTimerEntry { - delay_ms, - generation: 0, - repeat, - }, - ); - } - self.next_timer_id - } - - /// Allocate a fresh timer id and register a one-shot (`repeat == false`) - /// tracking entry at generation 0. Used by the bridge-timer path so the - /// queued wheel action can be cancelled (its entry removed) on `clear`/teardown. - fn register_oneshot_timer(&mut self, delay_ms: u64) -> u64 { - self.next_timer_id += 1; - let timer_id = self.next_timer_id; - if let Ok(mut timers) = self.timers.lock() { - timers.insert( - timer_id, - LocalTimerEntry { - delay_ms, - generation: 0, - repeat: false, - }, - ); - } - timer_id - } - - fn arm_kernel_timer(&self, timer_id: u64) { - let Some(session) = self.v8_session.clone() else { - return; - }; - - let Some((delay_ms, generation, timers)) = - self.timers.lock().ok().and_then(|mut timers| { - let entry = timers.get_mut(&timer_id)?; - entry.generation = entry.generation.wrapping_add(1); - Some((entry.delay_ms, entry.generation, self.timers.clone())) - }) - else { - return; - }; - - TimerWheel::get().schedule( - delay_ms, - TimerAction::StreamEvent { - session, - timer_id, - generation, - timers, - }, - ); - } - - fn clear_kernel_timer(&self, timer_id: u64) { - if let Ok(mut timers) = self.timers.lock() { - timers.remove(&timer_id); - } - } - - fn schedule_bridge_timer_response(&mut self, call_id: u64, delay_ms: u64) { - let Some(session) = self.v8_session.clone() else { - return; - }; - - // Register the bridge timer in the shared `timers` map with a generation, - // mirroring the kernel-timer cancellation path. Tracking it means that - // when `LocalBridgeState` is dropped on session teardown (which clears the - // map) or the entry is otherwise removed, the timer wheel observes the - // missing/mismatched generation via `timer_should_fire` and suppresses the - // response instead of touching the torn-down session. - let timer_id = self.register_oneshot_timer(delay_ms); - let generation = 0; - let timers = self.timers.clone(); - - TimerWheel::get().schedule( - delay_ms, - TimerAction::BridgeResponse { - session, - call_id, - timer_id, - generation, - timers, - }, - ); - } - - fn has_module_reader(&self) -> bool { - self.module_reader.is_some() - } - - fn batch_resolve_modules(&mut self, args: &[Value]) -> Value { - self.with_module_resolver(|resolver| resolver.batch_resolve_modules(args)) - } - - fn resolve_module( - &mut self, - specifier: &str, - from_dir: &str, - mode: ModuleResolveMode, - ) -> Option { - if self.js_runtime_denies_specifier(specifier) { - return None; - } - self.with_module_resolver(|resolver| resolver.resolve_module(specifier, from_dir, mode)) - } - - /// jsRuntime resolution gate. Denies builtin and bare/relative imports per the - /// configured `moduleResolution` and builtin allow-list, before the resolver - /// touches the VFS. This is the authoritative chokepoint for the live - /// shared-V8 path (both `import`/`import()` and `require`/`createRequire` - /// route through `_resolveModule` -> here). - fn js_runtime_denies_specifier(&self, specifier: &str) -> bool { - let is_local = specifier.starts_with("./") - || specifier.starts_with("../") - || specifier == "." - || specifier == ".." - || specifier.starts_with('/') - || specifier.starts_with("file:"); - match self.module_resolution { - GuestModuleResolution::Node => false, - // Relative permits local files only; bare specifiers and package - // imports (`#...`) do not resolve. - GuestModuleResolution::Relative => !is_local, - // None denies every specifier, local included. - GuestModuleResolution::None => true, - } - } - - fn module_format(&mut self, path: &str) -> Option { - self.with_module_resolver(|resolver| resolver.module_format(path)) - } - - fn load_file(&mut self, path: &str) -> Option { - self.with_module_resolver(|resolver| resolver.load_file(path)) - } - - /// Run `f` against a resolver bound to this bridge's resolution cache, reading - /// through the supplied VFS `module_reader` when present (the live VM path: - /// resolution executes here on the bridge thread, reading the mounted - /// `node_modules` filesystem in parallel with the service loop), or through - /// the host-backed path translator otherwise (the legacy host-direct path - /// used by `handle_internal_bridge_call_from_host_context`). - fn with_module_resolver( - &mut self, - f: impl FnOnce(&mut ModuleResolver<'_, &mut dyn ModuleFsReader>) -> T, - ) -> T { - let cache = &mut self.resolution_cache; - if let Some(reader) = self.module_reader.as_deref_mut() { - let reader: &mut dyn ModuleFsReader = reader; - let mut resolver = ModuleResolver { reader, cache }; - f(&mut resolver) - } else { - let mut translator = &mut self.translator; - let reader: &mut dyn ModuleFsReader = &mut translator; - let mut resolver = ModuleResolver { reader, cache }; - f(&mut resolver) - } - } -} - -impl ModuleFsReader for &mut dyn ModuleFsReader { - fn canonical_guest_path(&mut self, guest_path: &str) -> Option { - (**self).canonical_guest_path(guest_path) - } - - fn read_to_string(&mut self, guest_path: &str) -> Option { - (**self).read_to_string(guest_path) - } - - fn path_is_dir(&mut self, guest_path: &str) -> Option { - (**self).path_is_dir(guest_path) - } - - fn path_exists(&mut self, guest_path: &str) -> bool { - (**self).path_exists(guest_path) - } -} - -impl ModuleFsReader for &mut GuestPathTranslator { - fn canonical_guest_path(&mut self, guest_path: &str) -> Option { - GuestPathTranslator::canonical_guest_path(self, guest_path) - } - - fn read_to_string(&mut self, guest_path: &str) -> Option { - let host_path = self.guest_to_host(guest_path)?; - fs::read_to_string(host_path).ok() - } - - fn path_is_dir(&mut self, guest_path: &str) -> Option { - self.guest_to_host(guest_path) - .and_then(|host_path| fs::metadata(host_path).ok()) - .map(|metadata| metadata.is_dir()) - } - - fn path_exists(&mut self, guest_path: &str) -> bool { - self.guest_to_host(guest_path) - .map(|host_path| host_path.exists()) - .unwrap_or(false) - } -} - -/// Standard Node module resolution executed as pure path algebra over a -/// [`ModuleFsReader`]. The same algorithm backs both the legacy host-direct -/// path (reader = host path translator) and the live VM path (reader = kernel -/// VFS), guaranteeing they resolve identically. -pub struct ModuleResolver<'a, R: ModuleFsReader> { - reader: R, - cache: &'a mut LocalModuleResolutionCache, -} - -impl<'a, R: ModuleFsReader> ModuleResolver<'a, R> { - /// Construct a resolver over `reader`, reusing `cache` across calls. The - /// cache must be persisted per-VM so cold-start resolution does not rebuild - /// it on every dispatch. - pub fn new(reader: R, cache: &'a mut LocalModuleResolutionCache) -> Self { - Self { reader, cache } - } - - pub fn batch_resolve_modules(&mut self, args: &[Value]) -> Value { - let requests = args - .first() - .and_then(Value::as_array) - .cloned() - .unwrap_or_default(); - Value::Array( - requests - .into_iter() - .map(|request| { - let pair = request.as_array().cloned().unwrap_or_default(); - let specifier = pair.first().and_then(Value::as_str).unwrap_or(""); - let referrer = pair.get(1).and_then(Value::as_str).unwrap_or("/"); - self.resolve_module(specifier, referrer, ModuleResolveMode::Import) - .and_then(|resolved| { - self.load_file(&resolved).map(|source| { - json!({ - "resolved": resolved, - "source": source, - }) - }) - }) - .unwrap_or(Value::Null) - }) - .collect(), - ) - } - - pub fn resolve_module( - &mut self, - specifier: &str, - from_dir: &str, - mode: ModuleResolveMode, - ) -> Option { - let normalized_from_path = self - .reader - .canonical_guest_path(from_dir) - .unwrap_or_else(|| normalize_guest_path(from_dir)); - let normalized_from = if self.cached_stat(&normalized_from_path) == Some(false) { - dirname_guest_path(&normalized_from_path) - } else { - normalize_module_resolve_context(&normalized_from_path) - }; - let cache_key = (specifier.to_owned(), normalized_from.clone(), mode); - if let Some(cached) = self.cache.resolve_results.get(&cache_key) { - return cached.clone(); - } - - let resolved = if let Some(builtin) = normalize_builtin_specifier(specifier) { - Some(builtin) - } else if specifier.starts_with("file:") { - guest_path_from_file_url(specifier) - .and_then(|file_path| self.resolve_path(&file_path, mode)) - } else if specifier.starts_with('/') { - self.resolve_path(specifier, mode) - } else if specifier.starts_with("./") - || specifier.starts_with("../") - || specifier == "." - || specifier == ".." - { - self.resolve_path(&join_guest_path(&normalized_from, specifier), mode) - } else if specifier.starts_with('#') { - self.resolve_package_imports(specifier, &normalized_from, mode) - } else { - self.resolve_package_self_reference(specifier, &normalized_from, mode) - .or_else(|| self.resolve_node_modules(specifier, &normalized_from, mode)) - }; - - if resolved.is_some() || module_resolution_miss_is_stable(&normalized_from) { - self.cache - .resolve_results - .insert(cache_key, resolved.clone()); - } - resolved - } - - pub fn load_file(&mut self, path: &str) -> Option { - let bare = path.trim_start_matches("node:"); - if is_builtin_specifier(path) { - return Some(build_builtin_module_wrapper(bare)); - } - - let source = self.reader.read_to_string(path)?; - Some( - if matches!( - Path::new(path).extension().and_then(|ext| ext.to_str()), - Some("js" | "mjs" | "cjs") - ) { - strip_javascript_hashbang(&source) - } else { - source - }, - ) - } - - pub fn module_format(&mut self, path: &str) -> Option { - if let Some(cached) = self.cache.module_format_results.get(path) { - return *cached; - } - - let format = self.detect_module_format(path); - self.cache - .module_format_results - .insert(path.to_owned(), format); - format - } - - fn detect_module_format(&mut self, path: &str) -> Option { - if is_builtin_specifier(path) { - return Some(LocalResolvedModuleFormat::Module); - } - - let normalized = normalize_guest_path(path); - match Path::new(&normalized) - .extension() - .and_then(|ext| ext.to_str()) - { - Some("mjs" | "mts") => Some(LocalResolvedModuleFormat::Module), - Some("cjs" | "cts") => Some(LocalResolvedModuleFormat::Commonjs), - Some("json") => Some(LocalResolvedModuleFormat::Json), - Some("js") => Some( - if self - .nearest_package_json_type_for_guest_path(&normalized) - .as_deref() - == Some("module") - { - LocalResolvedModuleFormat::Module - } else { - LocalResolvedModuleFormat::Commonjs - }, - ), - _ => None, - } - } - - fn nearest_package_json_type_for_guest_path(&mut self, guest_path: &str) -> Option { - let mut dir = dirname_guest_path(guest_path); - loop { - let package_json_path = join_guest_path(&dir, "package.json"); - if let Some(package_json) = self.read_package_json(&package_json_path) { - return package_json.package_type; - } - if dir == "/" { - break; - } - dir = dirname_guest_path(&dir); - } - None - } - - fn resolve_package_imports( - &mut self, - request: &str, - from_dir: &str, - mode: ModuleResolveMode, - ) -> Option { - let mut dir = normalize_guest_path(from_dir); - loop { - let pkg_json_path = join_guest_path(&dir, "package.json"); - if let Some(pkg_json) = self.read_package_json(&pkg_json_path) { - if let Some(imports) = &pkg_json.imports { - if let Some(target) = resolve_imports_target(imports, request, mode) { - let target_path = if target.starts_with('/') { - target - } else { - join_guest_path(&dir, &target) - }; - return self.resolve_path(&target_path, mode); - } - return None; - } - } - if dir == "/" { - break; - } - dir = dirname_guest_path(&dir); - } - None - } - - fn resolve_package_self_reference( - &mut self, - request: &str, - from_dir: &str, - mode: ModuleResolveMode, - ) -> Option { - let (package_name, subpath) = split_package_request(request)?; - let mut dir = normalize_guest_path(from_dir); - loop { - let pkg_json_path = join_guest_path(&dir, "package.json"); - if let Some(pkg_json) = self.read_package_json(&pkg_json_path) { - if pkg_json.name.as_deref() == Some(package_name) { - return self.resolve_package_entry_from_dir(&dir, subpath, mode); - } - } - if dir == "/" { - break; - } - dir = dirname_guest_path(&dir); - } - None - } - - fn resolve_node_modules( - &mut self, - request: &str, - from_dir: &str, - mode: ModuleResolveMode, - ) -> Option { - let (package_name, subpath) = split_package_request(request)?; - - // Standard Node resolution over the faithful VFS: walk ancestor - // `node_modules` directories (following symlinks via the importer's - // realpath). pnpm/yarn layouts resolve because the VFS exposes their - // symlinks, not because the resolver understands package-manager - // internals (see CLAUDE.md npm Compatibility). - let mut dir = normalize_guest_path(from_dir); - loop { - for package_dir in node_modules_direct_candidate_dirs(&dir, package_name) { - if let Some(entry) = - self.resolve_package_entry_from_dir(&package_dir, subpath, mode) - { - return Some(entry); - } - } - if dir == "/" { - break; - } - dir = dirname_guest_path(&dir); - } - - ["/root/node_modules", "/node_modules"] - .into_iter() - .find_map(|root| { - self.resolve_package_entry_from_dir( - &join_guest_path(root, package_name), - subpath, - mode, - ) - }) - } - - fn resolve_package_entry_from_dir( - &mut self, - package_dir: &str, - subpath: &str, - mode: ModuleResolveMode, - ) -> Option { - let package_json_path = join_guest_path(package_dir, "package.json"); - let pkg_json = self.read_package_json(&package_json_path); - if pkg_json.is_none() && !self.cached_exists(package_dir) { - return None; - } - - if let Some(pkg_json) = pkg_json.as_ref() { - if let Some(exports) = &pkg_json.exports { - let exports_subpath = if subpath.is_empty() { - String::from(".") - } else { - format!("./{subpath}") - }; - let exports_target = resolve_exports_target(exports, &exports_subpath, mode)?; - let target_path = join_guest_path(package_dir, &exports_target); - return self.resolve_path(&target_path, mode).or(Some(target_path)); - } - } - - if !subpath.is_empty() { - return self.resolve_path(&join_guest_path(package_dir, subpath), mode); - } - - let entry_field = pkg_json - .as_ref() - .and_then(|pkg_json| pkg_json.main.as_deref()) - .unwrap_or("index.js"); - let entry_path = join_guest_path(package_dir, entry_field); - self.resolve_path(&entry_path, mode) - .or_else(|| self.resolve_path(&join_guest_path(package_dir, "index"), mode)) - } - - fn resolve_path(&mut self, base_path: &str, mode: ModuleResolveMode) -> Option { - if self.cached_stat(base_path) == Some(false) { - return Some(normalize_guest_path(base_path)); - } - - for extension in [".js", ".json", ".mjs", ".cjs"] { - let candidate = format!("{}{}", normalize_guest_path(base_path), extension); - if self.cached_exists(&candidate) { - return Some(candidate); - } - } - - if self.cached_stat(base_path) == Some(true) { - let pkg_json_path = join_guest_path(base_path, "package.json"); - if let Some(pkg_json) = self.read_package_json(&pkg_json_path) { - if let Some(main) = pkg_json.main.as_deref() { - let entry_path = join_guest_path(base_path, main); - if entry_path != normalize_guest_path(base_path) { - if let Some(entry) = self.resolve_path(&entry_path, mode) { - return Some(entry); - } - } - } - if mode == ModuleResolveMode::Import - && pkg_json.package_type.as_deref() == Some("module") - && self.cached_exists(&join_guest_path(base_path, "index.js")) - { - return Some(join_guest_path(base_path, "index.js")); - } - } - - for extension in [".js", ".json", ".mjs", ".cjs"] { - let index_path = join_guest_path(base_path, &format!("index{extension}")); - if self.cached_exists(&index_path) { - return Some(index_path); - } - } - } - - None - } - - fn read_package_json(&mut self, guest_path: &str) -> Option { - if let Some(cached) = self.cache.package_json_results.get(guest_path).cloned() { - return cached; - } - - let parsed = self - .reader - .read_to_string(guest_path) - .and_then(|contents| serde_json::from_str::(&contents).ok()); - if parsed.is_some() || module_path_miss_is_stable(guest_path) { - self.cache - .package_json_results - .insert(guest_path.to_owned(), parsed.clone()); - } - parsed - } - - fn cached_exists(&mut self, guest_path: &str) -> bool { - if let Some(cached) = self.cache.exists_results.get(guest_path) { - return *cached; - } - let exists = self.reader.path_exists(guest_path); - if exists || module_path_miss_is_stable(guest_path) { - self.cache - .exists_results - .insert(guest_path.to_owned(), exists); - } - exists - } - - fn cached_stat(&mut self, guest_path: &str) -> Option { - if let Some(cached) = self.cache.stat_results.get(guest_path) { - return *cached; - } - let result = self.reader.path_is_dir(guest_path); - if result.is_some() || module_path_miss_is_stable(guest_path) { - self.cache - .stat_results - .insert(guest_path.to_owned(), result); - } - result - } -} - -fn module_resolution_miss_is_stable(from_dir: &str) -> bool { - module_path_miss_is_stable(from_dir) -} - -fn module_path_miss_is_stable(guest_path: &str) -> bool { - guest_path == "/node_modules" - || guest_path.ends_with("/node_modules") - || guest_path.contains("/node_modules/") -} - -fn guest_path_from_file_url(specifier: &str) -> Option { - if !specifier.starts_with("file:") { - return None; - } - - let mut pathname = if let Some(stripped) = specifier.strip_prefix("file://") { - stripped - } else { - specifier.strip_prefix("file:")? - }; - - if let Some(terminator_index) = pathname.find(['?', '#']) { - pathname = &pathname[..terminator_index]; - } - - if !pathname.starts_with('/') { - let slash_index = pathname.find('/')?; - let host = &pathname[..slash_index]; - if !host.is_empty() && host != "localhost" { - return None; - } - pathname = &pathname[slash_index..]; - } - - Some(normalize_guest_path(&percent_decode(pathname)?)) -} - -fn percent_decode(raw: &str) -> Option { - let bytes = raw.as_bytes(); - let mut index = 0; - let mut decoded = Vec::with_capacity(bytes.len()); - while index < bytes.len() { - match bytes[index] { - b'%' if index + 2 < bytes.len() => { - if let (Some(high), Some(low)) = - (hex_digit(bytes[index + 1]), hex_digit(bytes[index + 2])) - { - let value = (high << 4) | low; - decoded.push(value); - index += 3; - } else { - decoded.push(bytes[index]); - index += 1; - } - } - byte => { - decoded.push(byte); - index += 1; - } - } - } - String::from_utf8(decoded).ok() -} - -fn hex_digit(byte: u8) -> Option { - match byte { - b'0'..=b'9' => Some(byte - b'0'), - b'a'..=b'f' => Some(byte - b'a' + 10), - b'A'..=b'F' => Some(byte - b'A' + 10), - _ => None, - } -} - -impl LocalKernelStdinBridge { - fn write(&self, chunk: &[u8]) -> Result<(), JavascriptExecutionError> { - let mut state = self.state.lock().expect("kernel stdin state poisoned"); - if state.closed { - return Err(JavascriptExecutionError::StdinClosed); - } - let next_len = state.bytes.len().checked_add(chunk.len()).ok_or_else(|| { - JavascriptExecutionError::Stdin(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("guest stdin buffer exceeded {KERNEL_STDIN_BUFFER_LIMIT_BYTES} bytes"), - )) - })?; - if next_len > KERNEL_STDIN_BUFFER_LIMIT_BYTES { - return Err(JavascriptExecutionError::Stdin(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("guest stdin buffer exceeded {KERNEL_STDIN_BUFFER_LIMIT_BYTES} bytes"), - ))); - } - - state.bytes.extend(chunk.iter().copied()); - self.ready.notify_all(); - Ok(()) - } - - fn close(&self) { - let mut state = self.state.lock().expect("kernel stdin state poisoned"); - state.closed = true; - self.ready.notify_all(); - } - - fn read(&self, args: &[Value]) -> Value { - let max_bytes = args - .first() - .and_then(Value::as_u64) - .map(|value| value.clamp(1, 64 * 1024) as usize) - .unwrap_or(64 * 1024); - let timeout = Duration::from_millis(args.get(1).and_then(Value::as_u64).unwrap_or(100)); - let deadline = Instant::now() + timeout; - let mut state = self.state.lock().expect("kernel stdin state poisoned"); - - while state.bytes.is_empty() && !state.closed { - let remaining = deadline.saturating_duration_since(Instant::now()); - if remaining.is_zero() { - return Value::Null; - } - let (next_state, wait_result) = self - .ready - .wait_timeout(state, remaining) - .expect("kernel stdin wait poisoned"); - state = next_state; - if wait_result.timed_out() && state.bytes.is_empty() && !state.closed { - return Value::Null; - } - } - - if !state.bytes.is_empty() { - let read_len = state.bytes.len().min(max_bytes); - let bytes = state.bytes.drain(..read_len).collect::>(); - return json!({ - "dataBase64": v8_runtime::base64_encode_pub(&bytes), - }); - } - - json!({ - "done": true, - }) - } - - fn read_python_raw(&self, args: &[Value]) -> Value { - const PYTHON_STDIN_DONE_SENTINEL: &str = "__AGENTOS_PYTHON_STDIN_DONE__"; - - let max_bytes = args - .first() - .and_then(Value::as_u64) - .map(|value| value.clamp(1, 64 * 1024) as usize) - .unwrap_or(64 * 1024); - let timeout = Duration::from_millis(args.get(1).and_then(Value::as_u64).unwrap_or(100)); - let deadline = Instant::now() + timeout; - let mut state = self.state.lock().expect("kernel stdin state poisoned"); - - while state.bytes.is_empty() && !state.closed { - let remaining = deadline.saturating_duration_since(Instant::now()); - if remaining.is_zero() { - return Value::Null; - } - let (next_state, wait_result) = self - .ready - .wait_timeout(state, remaining) - .expect("kernel stdin wait poisoned"); - state = next_state; - if wait_result.timed_out() && state.bytes.is_empty() && !state.closed { - return Value::Null; - } - } - - if !state.bytes.is_empty() { - let read_len = state.bytes.len().min(max_bytes); - let bytes = state.bytes.drain(..read_len).collect::>(); - return Value::String(v8_runtime::base64_encode_pub(&bytes)); - } - - Value::String(String::from(PYTHON_STDIN_DONE_SENTINEL)) - } -} - -fn normalize_module_resolve_context(path: &str) -> String { - let normalized = normalize_guest_path(path); - if normalized.ends_with(".js") - || normalized.ends_with(".mjs") - || normalized.ends_with(".cjs") - || normalized.ends_with(".json") - || normalized.ends_with(".ts") - || normalized.ends_with(".mts") - || normalized.ends_with(".cts") - { - dirname_guest_path(&normalized) - } else { - normalized - } -} - -fn strip_javascript_hashbang(source: &str) -> String { - if let Some(stripped) = source.strip_prefix("#!") { - match stripped.find('\n') { - Some(index) => format!("\n{}", &stripped[index + 1..]), - None => String::new(), - } - } else { - source.to_owned() - } -} - -fn parse_process_exit_code_message(message: &str) -> Option { - let code = message.strip_prefix("process.exit(")?.strip_suffix(')')?; - code.parse::().ok() -} - -fn dirname_guest_path(path: &str) -> String { - let normalized = normalize_guest_path(path); - if normalized == "/" { - return normalized; - } - normalized - .rsplit_once('/') - .map(|(parent, _)| { - if parent.is_empty() { - String::from("/") - } else { - parent.to_owned() - } - }) - .unwrap_or_else(|| String::from("/")) -} - -fn normalize_builtin_specifier(specifier: &str) -> Option { - let bare = specifier.trim_start_matches("node:"); - match bare { - "assert" - | "async_hooks" - | "buffer" - | "child_process" - | "cluster" - | "console" - | "constants" - | "crypto" - | "dgram" - | "diagnostics_channel" - | "dns" - | "dns/promises" - | "events" - | "fs" - | "fs/promises" - | "http" - | "http2" - | "https" - | "inspector" - | "module" - | "net" - | "os" - | "path" - | "path/posix" - | "path/win32" - | "perf_hooks" - | "process" - | "punycode" - | "querystring" - | "readline" - | "repl" - | "sqlite" - | "stream" - | "stream/consumers" - | "stream/promises" - | "stream/web" - | "string_decoder" - | "sys" - | "timers" - | "tls" - | "timers/promises" - | "trace_events" - | "tty" - | "url" - | "util" - | "util/types" - | "domain" - | "vm" - | "v8" - | "wasi" - | "worker_threads" - | "zlib" => Some(format!("node:{bare}")), - _ => None, - } -} - -fn is_builtin_specifier(specifier: &str) -> bool { - normalize_builtin_specifier(specifier).is_some() -} - -fn polyfill_expression(request: &str) -> Option { - let normalized = request.trim_start_matches("node:"); - let entry = polyfill_registry() - .groups - .iter() - .find(|group| group.names.iter().any(|name| name == normalized))?; - - Some(match entry.source { - PolyfillSourceKind::NodeStdlibBrowser | PolyfillSourceKind::CustomBridge => format!( - "globalThis._requireFrom({}, \"/\")", - serde_json::to_string(&format!("node:{normalized}")) - .unwrap_or_else(|_| format!("\"node:{normalized}\"")) - ), - PolyfillSourceKind::Denied => { - let error_code = entry.error_code.as_deref().unwrap_or("ERR_ACCESS_DENIED"); - format!( - "(() => {{ const error = new Error({message}); error.code = {code}; throw error; }})()", - message = serde_json::to_string(&format!( - "node:{normalized} is not available in the secure-exec guest runtime" - )) - .unwrap_or_else(|_| format!( - "\"node:{normalized} is not available in the secure-exec guest runtime\"" - )), - code = serde_json::to_string(error_code) - .unwrap_or_else(|_| "\"ERR_ACCESS_DENIED\"".to_owned()) - ) - } - }) -} - -fn build_builtin_module_wrapper(module_name: &str) -> String { - if module_name == "assert" { - return String::from( - r#"class AssertionError extends Error { - constructor(message = "Assertion failed") { - super(message); - this.name = "AssertionError"; - } -} - -function fail(message) { - throw new AssertionError(message); -} - -function ok(value, message) { - if (!value) fail(message); -} - -function equal(actual, expected, message) { - if (actual != expected) fail(message ?? `Expected ${actual} == ${expected}`); -} - -function notEqual(actual, expected, message) { - if (actual == expected) fail(message ?? `Expected ${actual} != ${expected}`); -} - -function strictEqual(actual, expected, message) { - if (actual !== expected) fail(message ?? `Expected ${actual} === ${expected}`); -} - -function notStrictEqual(actual, expected, message) { - if (actual === expected) fail(message ?? `Expected ${actual} !== ${expected}`); -} - -function serialize(value) { - return JSON.stringify(value); -} - -function deepEqual(actual, expected, message) { - if (serialize(actual) !== serialize(expected)) { - fail(message ?? "Expected values to be deeply equal"); - } -} - -function deepStrictEqual(actual, expected, message) { - return deepEqual(actual, expected, message); -} - -function match(actual, expected, message) { - if (!(expected instanceof RegExp) || !expected.test(String(actual))) { - fail(message ?? `Expected ${actual} to match ${expected}`); - } -} - -function matchesExpectedError(error, expected) { - if (expected == null) return true; - if (expected instanceof RegExp) { - return expected.test(String(error?.message ?? error)); - } - if (typeof expected === "function") { - if (error instanceof expected) return true; - return expected(error) === true; - } - if (typeof expected === "object") { - return Object.entries(expected).every(([key, value]) => serialize(error?.[key]) === serialize(value)); - } - return false; -} - -function throws(fn, expected, message) { - if (typeof fn !== "function") { - fail(message ?? "assert.throws requires a function"); - } - - try { - fn(); - } catch (error) { - if (!matchesExpectedError(error, expected)) { - throw error; - } - return error; - } - - fail(message ?? "Missing expected exception"); -} - -async function rejects(promiseOrFn, expected, message) { - let promise; - if (typeof promiseOrFn === "function") { - promise = promiseOrFn(); - } else { - promise = promiseOrFn; - } - - try { - await promise; - } catch (error) { - if (!matchesExpectedError(error, expected)) { - throw error; - } - return error; - } - - fail(message ?? "Missing expected rejection"); -} - -function ifError(error) { - if (error != null) { - throw error; - } -} - -function assert(value, message) { - ok(value, message); -} - -Object.assign(assert, { - AssertionError, - deepEqual, - deepStrictEqual, - equal, - fail, - ifError, - match, - notEqual, - notStrictEqual, - ok, - rejects, - strict: assert, - strictEqual, - throws, -}); - -export { - AssertionError, - assert as default, - deepEqual, - deepStrictEqual, - equal, - fail, - ifError, - match, - notEqual, - notStrictEqual, - ok, - rejects, - assert as strict, - strictEqual, - throws, -}; -"#, - ); - } - - if module_name == "path" || module_name == "path/posix" || module_name == "path/win32" { - return String::from( - r#"const sep = "/"; -const delimiter = ":"; - -function normalizeSegments(parts) { - const output = []; - for (const part of parts) { - if (!part || part === ".") continue; - if (part === "..") { - if (output.length > 0) output.pop(); - continue; - } - output.push(part); - } - return output; -} - -function isAbsolute(path) { - return String(path || "").startsWith(sep); -} - -function join(...parts) { - const absolute = parts.some((part, index) => index === 0 && isAbsolute(part)); - const normalized = normalizeSegments(parts.flatMap((part) => String(part || "").split(sep))); - const joined = normalized.join(sep); - if (!joined) return absolute ? sep : "."; - return absolute ? `${sep}${joined}` : joined; -} - -function dirname(path) { - const normalized = String(path || ""); - if (!normalized || normalized === sep) return sep; - const parts = normalizeSegments(normalized.split(sep)); - if (parts.length <= 1) return isAbsolute(normalized) ? sep : "."; - const dir = parts.slice(0, -1).join(sep); - return isAbsolute(normalized) ? `${sep}${dir}` : dir; -} - -function basename(path) { - const normalized = normalizeSegments(String(path || "").split(sep)); - return normalized.length === 0 ? "" : normalized[normalized.length - 1]; -} - -function extname(path) { - const base = basename(path); - const index = base.lastIndexOf("."); - if (index <= 0) return ""; - return base.slice(index); -} - -function resolve(...parts) { - const absoluteParts = []; - for (let index = parts.length - 1; index >= 0; index -= 1) { - const part = String(parts[index] || ""); - if (!part) continue; - absoluteParts.unshift(part); - if (isAbsolute(part)) break; - } - if (absoluteParts.length === 0 || !isAbsolute(absoluteParts[0])) { - absoluteParts.unshift(typeof process?.cwd === "function" ? process.cwd() : sep); - } - return join(...absoluteParts); -} - -function relative(from, to) { - const fromResolved = resolve(from); - const toResolved = resolve(to); - if (fromResolved === toResolved) return ""; - - const fromParts = normalizeSegments(fromResolved.split(sep)); - const toParts = normalizeSegments(toResolved.split(sep)); - let shared = 0; - while ( - shared < fromParts.length && - shared < toParts.length && - fromParts[shared] === toParts[shared] - ) { - shared += 1; - } - - const up = new Array(fromParts.length - shared).fill(".."); - const down = toParts.slice(shared); - const result = [...up, ...down].join(sep); - return result || "."; -} - -function parse(path) { - const root = isAbsolute(path) ? sep : ""; - const dir = dirname(path); - const base = basename(path); - const ext = extname(path); - const name = ext ? base.slice(0, -ext.length) : base; - return { root, dir, base, ext, name }; -} - -function format(pathObject = {}) { - const dir = pathObject.dir || pathObject.root || ""; - const base = - pathObject.base || - `${pathObject.name || ""}${pathObject.ext || ""}`; - if (!dir) return base; - if (!base) return dir; - return dir.endsWith(sep) ? `${dir}${base}` : `${dir}${sep}${base}`; -} - -function normalize(path) { - return join(String(path || "")); -} - -const pathModule = { - basename, - delimiter, - dirname, - extname, - format, - isAbsolute, - join, - normalize, - parse, - relative, - resolve, - sep, -}; -const posix = pathModule; -const win32 = pathModule; -pathModule.posix = posix; -pathModule.win32 = win32; - -export { basename, delimiter, dirname, extname, format, isAbsolute, join, normalize, parse, posix, relative, resolve, sep, win32 }; -export default pathModule; -"#, - ); - } - - if module_name == "url" { - return String::from( - r#"const NativeURL = globalThis.URL; - -function normalizeFilePath(value) { - const path = String(value ?? ""); - if (path.length === 0) { - return "/"; - } - return path.startsWith("/") ? path : `/${path}`; -} - -function encodeFilePath(path) { - return path - .split("/") - .map((segment, index) => - index === 0 - ? "" - : encodeURIComponent(segment).replace(/[!'()*]/g, (char) => - `%${char.charCodeAt(0).toString(16).toUpperCase()}` - ) - ) - .join("/"); -} - -function buildFileUrlRecord(href, pathname) { - const searchParams = new URLSearchParams(); - return { - href, - origin: "null", - protocol: "file:", - username: "", - password: "", - host: "", - hostname: "", - port: "", - pathname, - search: "", - searchParams, - hash: "", - toString() { - return href; - }, - toJSON() { - return href; - }, - valueOf() { - return href; - }, - [Symbol.toPrimitive]() { - return href; - }, - }; -} - -function fileURLToPath(value) { - const raw = - typeof value === "string" - ? value - : value && typeof value.href === "string" - ? value.href - : String(value ?? ""); - if (raw.startsWith("/")) { - return raw; - } - if (raw.startsWith("file:")) { - let pathname = raw.startsWith("file://") - ? raw.slice("file://".length) - : raw.slice("file:".length); - const terminatorIndex = pathname.search(/[?#]/); - if (terminatorIndex >= 0) { - pathname = pathname.slice(0, terminatorIndex); - } - if (!pathname.startsWith("/")) { - const slashIndex = pathname.indexOf("/"); - if (slashIndex === -1) { - return "/"; - } - const host = pathname.slice(0, slashIndex); - if (host && host !== "localhost") { - throw new Error(`Expected file URL with an empty host, received ${host}`); - } - pathname = pathname.slice(slashIndex); - } - return decodeURIComponent(pathname || "/"); - } - const url = value instanceof NativeURL ? value : new NativeURL(raw); - if (url.protocol !== "file:") { - throw new Error(`Expected file URL, received ${url.protocol}`); - } - return decodeURIComponent(url.pathname); -} - -function pathToFileURL(path) { - const absolute = normalizeFilePath(path); - const pathname = encodeFilePath(absolute); - const href = `file://${pathname}`; - - try { - return new NativeURL(href); - } catch {} - - return buildFileUrlRecord(href, pathname); -} - -function parse(input, parseQueryString = false) { - const parsed = new NativeURL(String(input ?? "")); - const queryString = parsed.search.length > 0 ? parsed.search.slice(1) : null; - const auth = - parsed.username || parsed.password - ? `${decodeURIComponent(parsed.username)}${parsed.password ? `:${decodeURIComponent(parsed.password)}` : ""}` - : null; - return { - href: parsed.href, - protocol: parsed.protocol, - slashes: true, - auth, - host: parsed.host, - port: parsed.port || null, - hostname: parsed.hostname, - hash: parsed.hash || null, - search: parsed.search || null, - query: parseQueryString ? Object.fromEntries(parsed.searchParams.entries()) : queryString, - pathname: parsed.pathname, - path: `${parsed.pathname}${parsed.search}`, - }; -} - -function format(value) { - if (value == null) return ""; - if (typeof value === "string") return value; - if (typeof value.href === "string") return value.href; - - const protocol = typeof value.protocol === "string" ? value.protocol : "http:"; - const slashes = value.slashes === false ? "" : "//"; - const auth = - typeof value.auth === "string" && value.auth.length > 0 ? `${value.auth}@` : ""; - const host = - typeof value.host === "string" && value.host.length > 0 - ? value.host - : `${value.hostname || ""}${value.port ? `:${value.port}` : ""}`; - const pathname = - typeof value.pathname === "string" - ? value.pathname - : typeof value.path === "string" - ? value.path - : ""; - - let search = ""; - if (typeof value.search === "string") { - search = value.search; - } else if (typeof value.query === "string" && value.query.length > 0) { - search = value.query.startsWith("?") ? value.query : `?${value.query}`; - } else if (value.query && typeof value.query === "object") { - const params = new URLSearchParams(); - for (const [key, entry] of Object.entries(value.query)) { - if (Array.isArray(entry)) { - for (const item of entry) { - params.append(key, String(item)); - } - } else if (entry != null) { - params.append(key, String(entry)); - } - } - const encoded = params.toString(); - search = encoded ? `?${encoded}` : ""; - } - - const hash = typeof value.hash === "string" ? value.hash : ""; - return `${protocol}${slashes}${auth}${host}${pathname}${search}${hash}`; -} - -export { NativeURL as URL, fileURLToPath, format, parse, pathToFileURL }; -export default { URL: NativeURL, fileURLToPath, format, parse, pathToFileURL }; -"#, - ); - } - - if module_name == "readline" { - return String::from( - r#"class MiniEmitter { - constructor() { - this.listeners = new Map(); - } - - on(event, listener) { - const listeners = this.listeners.get(event) ?? []; - listeners.push(listener); - this.listeners.set(event, listeners); - return this; - } - - addListener(event, listener) { - return this.on(event, listener); - } - - once(event, listener) { - const wrapped = (...args) => { - this.off(event, wrapped); - listener(...args); - }; - return this.on(event, wrapped); - } - - off(event, listener) { - const listeners = this.listeners.get(event) ?? []; - this.listeners.set( - event, - listeners.filter((candidate) => candidate !== listener), - ); - return this; - } - - removeListener(event, listener) { - return this.off(event, listener); - } - - emit(event, ...args) { - const listeners = this.listeners.get(event) ?? []; - for (const listener of listeners) { - listener(...args); - } - return listeners.length > 0; - } -} - -export function createInterface(options = {}) { - const input = options.input ?? null; - const output = options.output ?? null; - const emitter = new MiniEmitter(); - let buffer = ""; - let closed = false; - let ended = false; - const queuedLines = []; - let pendingResolve = null; - const pendingQuestionResolves = []; - - const enqueueLine = (line) => { - if (pendingQuestionResolves.length > 0) { - const resolve = pendingQuestionResolves.shift(); - resolve(line); - return; - } - if (pendingResolve) { - const resolve = pendingResolve; - pendingResolve = null; - resolve({ done: false, value: line }); - return; - } - queuedLines.push(line); - }; - - const flush = () => { - if (buffer.length > 0) { - emitter.emit("line", buffer); - enqueueLine(buffer); - buffer = ""; - } - }; - - const onData = (chunk) => { - buffer += typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8"); - while (true) { - const index = buffer.indexOf("\n"); - if (index < 0) break; - const line = buffer.slice(0, index).replace(/\r$/, ""); - buffer = buffer.slice(index + 1); - emitter.emit("line", line); - enqueueLine(line); - } - }; - - const onEnd = () => { - if (ended) return; - ended = true; - flush(); - emitter.emit("close"); - while (pendingQuestionResolves.length > 0) { - const resolve = pendingQuestionResolves.shift(); - resolve(""); - } - if (pendingResolve) { - const resolve = pendingResolve; - pendingResolve = null; - resolve({ done: true, value: void 0 }); - } - }; - - if (input && typeof input.on === "function") { - input.on("data", onData); - input.on("end", onEnd); - if (typeof input.resume === "function") { - input.resume(); - } - } - - emitter.close = () => { - if (closed) return; - closed = true; - if (input && typeof input.off === "function") { - input.off("data", onData); - input.off("end", onEnd); - } - flush(); - emitter.emit("close"); - while (pendingQuestionResolves.length > 0) { - const resolve = pendingQuestionResolves.shift(); - resolve(""); - } - if (pendingResolve) { - const resolve = pendingResolve; - pendingResolve = null; - resolve({ done: true, value: void 0 }); - } - }; - - emitter.question = (prompt, callback) => { - if (output && typeof output.write === "function" && prompt) { - output.write(String(prompt)); - } - const readLine = () => { - if (queuedLines.length > 0) { - return Promise.resolve(queuedLines.shift()); - } - if (closed || ended) { - return Promise.resolve(""); - } - return new Promise((resolve) => { - pendingQuestionResolves.push(resolve); - }); - }; - if (typeof callback === "function") { - void readLine().then((line) => { - callback(line); - }); - return; - } - return readLine(); - }; - - emitter[Symbol.asyncIterator] = () => ({ - next() { - if (queuedLines.length > 0) { - return Promise.resolve({ done: false, value: queuedLines.shift() }); - } - if (closed || ended) { - return Promise.resolve({ done: true, value: void 0 }); - } - return new Promise((resolve) => { - pendingResolve = resolve; - }); - }, - return() { - emitter.close(); - return Promise.resolve({ done: true, value: void 0 }); - }, - [Symbol.asyncIterator]() { - return this; - }, - }); - - return emitter; -} - -export default { createInterface }; -"#, - ); - } - - if module_name == "stream" { - return String::from( - r#"class MiniEmitter { - constructor() { - this._listeners = new Map(); - this._onceListeners = new Map(); - } - - on(event, listener) { - const listeners = this._listeners.get(event) ?? []; - listeners.push(listener); - this._listeners.set(event, listeners); - return this; - } - - once(event, listener) { - const listeners = this._onceListeners.get(event) ?? []; - listeners.push(listener); - this._onceListeners.set(event, listeners); - return this; - } - - off(event, listener) { - for (const map of [this._listeners, this._onceListeners]) { - const listeners = map.get(event) ?? []; - map.set( - event, - listeners.filter((candidate) => candidate !== listener), - ); - } - return this; - } - - removeListener(event, listener) { - return this.off(event, listener); - } - - emit(event, ...args) { - const persistent = [...(this._listeners.get(event) ?? [])]; - const once = [...(this._onceListeners.get(event) ?? [])]; - this._onceListeners.delete(event); - for (const listener of persistent) { - listener(...args); - } - for (const listener of once) { - listener(...args); - } - return persistent.length + once.length > 0; - } -} - -function getCallback(encodingOrCallback, callback) { - if (typeof encodingOrCallback === "function") return encodingOrCallback; - if (typeof callback === "function") return callback; - return null; -} - -function queueResult(callback, error = null) { - if (typeof callback !== "function") return; - queueMicrotask(() => callback(error)); -} - -function createReadableAsyncIterator(stream) { - const queuedChunks = []; - let pendingResolve = null; - let pendingReject = null; - let done = stream?.readableEnded === true; - let error = stream?.errored ?? null; - - const cleanup = () => { - stream?.off?.("data", onData); - stream?.off?.("end", onEnd); - stream?.off?.("close", onEnd); - stream?.off?.("error", onError); - }; - - const settlePending = (result) => { - if (pendingResolve) { - const resolve = pendingResolve; - pendingResolve = null; - pendingReject = null; - resolve(result); - } - }; - - const rejectPending = (reason) => { - if (pendingReject) { - const reject = pendingReject; - pendingResolve = null; - pendingReject = null; - reject(reason); - } - }; - - const onData = (chunk) => { - if (pendingResolve) { - settlePending({ done: false, value: chunk }); - return; - } - queuedChunks.push(chunk); - }; - - const onEnd = () => { - if (done) return; - done = true; - cleanup(); - settlePending({ done: true, value: void 0 }); - }; - - const onError = (reason) => { - error = reason; - done = true; - cleanup(); - rejectPending(reason); - }; - - const pull = () => { - if (done || typeof stream?._read !== "function") { - return; - } - try { - stream._read(); - } catch (reason) { - stream.errored = reason; - onError(reason); - } - }; - - stream?.on?.("data", onData); - stream?.on?.("end", onEnd); - stream?.on?.("close", onEnd); - stream?.on?.("error", onError); - - return { - next() { - if (error) { - return Promise.reject(error); - } - if (queuedChunks.length > 0) { - return Promise.resolve({ done: false, value: queuedChunks.shift() }); - } - if (done) { - return Promise.resolve({ done: true, value: void 0 }); - } - pull(); - if (queuedChunks.length > 0) { - return Promise.resolve({ done: false, value: queuedChunks.shift() }); - } - if (done) { - return Promise.resolve({ done: true, value: void 0 }); - } - return new Promise((resolve, reject) => { - pendingResolve = resolve; - pendingReject = reject; - }); - }, - return() { - done = true; - cleanup(); - stream?.destroy?.(); - return Promise.resolve({ done: true, value: void 0 }); - }, - [Symbol.asyncIterator]() { - return this; - }, - }; -} - -class Stream extends MiniEmitter { - pipe(destination) { - this.on("data", (chunk) => destination.write(chunk)); - this.once("end", () => destination.end()); - return destination; - } - - destroy(error) { - if (this.destroyed) return this; - this.destroyed = true; - if (error) { - this.errored = error; - queueMicrotask(() => this.emit("error", error)); - } - queueMicrotask(() => this.emit("close")); - return this; - } -} - -class Readable extends Stream { - constructor() { - super(); - this.readable = true; - this.readableEnded = false; - this.destroyed = false; - } - - push(chunk) { - if (chunk === null) { - if (!this.readableEnded) { - this.readableEnded = true; - queueMicrotask(() => { - this.emit("end"); - this.emit("close"); - }); - } - return false; - } - this.emit("data", Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk ?? [])); - return true; - } - - static fromWeb(stream) { - if (!stream || typeof stream.getReader !== "function") { - throw new TypeError("Readable.fromWeb expects a WHATWG ReadableStream"); - } - return { - async *[Symbol.asyncIterator]() { - const reader = stream.getReader(); - try { - while (true) { - const { value, done } = await reader.read(); - if (done) break; - yield Buffer.from(value ?? []); - } - } finally { - reader.releaseLock?.(); - } - }, - }; - } - - [Symbol.asyncIterator]() { - return createReadableAsyncIterator(this); - } -} - -class Writable extends Stream { - constructor(options = undefined) { - super(); - this.writable = true; - this.writableEnded = false; - this.destroyed = false; - this._writeOption = - options && typeof options.write === "function" ? options.write : null; - this._destroyOption = - options && typeof options.destroy === "function" ? options.destroy : null; - } - - write(chunk, encodingOrCallback, callback) { - if (this.writableEnded) { - const error = new Error("write after end"); - queueResult(getCallback(encodingOrCallback, callback), error); - this.emit("error", error); - return false; - } - const done = getCallback(encodingOrCallback, callback); - this._write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk ?? []), done); - return true; - } - - _write(_chunk, callback) { - if (!this._writeOption) { - queueResult(callback); - return; - } - try { - this._writeOption.call(this, _chunk, "buffer", callback); - } catch (error) { - queueResult(callback, error); - } - } - - _destroy(error, callback) { - if (!this._destroyOption) { - queueResult(callback, error); - return; - } - try { - this._destroyOption.call(this, error ?? null, callback); - } catch (destroyError) { - queueResult(callback, destroyError); - } - } - - destroy(error) { - if (this.destroyed) return this; - this.destroyed = true; - this._destroy(error ?? null, (destroyError) => { - const finalError = destroyError ?? error; - if (finalError) { - this.errored = finalError; - this.emit("error", finalError); - } - this.emit("close"); - }); - return this; - } - - end(chunk, encodingOrCallback, callback) { - if (chunk !== undefined && chunk !== null) { - this.write(chunk, encodingOrCallback); - } - if (this.writableEnded) { - queueResult(getCallback(encodingOrCallback, callback)); - return this; - } - this.writableEnded = true; - const done = getCallback(encodingOrCallback, callback); - queueMicrotask(() => { - queueResult(done); - this.emit("finish"); - this.destroy(); - }); - return this; - } -} - -class Duplex extends Readable { - constructor() { - super(); - this.writable = true; - this.writableEnded = false; - } - - write(chunk, encodingOrCallback, callback) { - return Writable.prototype.write.call(this, chunk, encodingOrCallback, callback); - } - - _write(chunk, callback) { - queueResult(callback); - } - - end(chunk, encodingOrCallback, callback) { - return Writable.prototype.end.call(this, chunk, encodingOrCallback, callback); - } -} - -class Transform extends Duplex { - _write(chunk, callback) { - try { - this._transform(chunk, "buffer", (error, output) => { - if (!error && output !== undefined && output !== null) { - this.push(output); - } - queueResult(callback, error ?? null); - }); - } catch (error) { - queueResult(callback, error); - this.emit("error", error); - } - } - - _transform(chunk, _encoding, callback) { - callback(null, chunk); - } - - end(chunk, encodingOrCallback, callback) { - Writable.prototype.end.call(this, chunk, encodingOrCallback, callback); - this.push(null); - return this; - } -} - -class PassThrough extends Transform {} - -function finished(stream, callback) { - const done = (error = null) => { - cleanup(); - if (typeof callback === "function") callback(error); - }; - const onFinish = () => done(); - const onEnd = () => done(); - const onClose = () => done(); - const onError = (error) => done(error); - const cleanup = () => { - stream?.off?.("finish", onFinish); - stream?.off?.("end", onEnd); - stream?.off?.("close", onClose); - stream?.off?.("error", onError); - }; - stream?.once?.("finish", onFinish); - stream?.once?.("end", onEnd); - stream?.once?.("close", onClose); - stream?.once?.("error", onError); - return cleanup; -} - -function pipeline(...streams) { - const callback = - streams.length > 0 && typeof streams[streams.length - 1] === "function" - ? streams.pop() - : null; - if (streams.length < 2) { - const error = new TypeError("pipeline requires at least two streams"); - callback?.(error); - throw error; - } - for (let index = 0; index < streams.length - 1; index += 1) { - streams[index].pipe(streams[index + 1]); - } - if (callback) { - finished(streams[streams.length - 1], callback); - } - return streams[streams.length - 1]; -} - -function compose(...streams) { - return pipeline(...streams); -} - -function addAbortSignal(signal, stream) { - if (signal?.aborted) { - stream?.destroy?.(signal.reason); - return stream; - } - signal?.addEventListener?.("abort", () => stream?.destroy?.(signal.reason), { - once: true, - }); - return stream; -} - -function isReadable(stream) { - return Boolean(stream && stream.readable && !stream.destroyed); -} - -function isWritable(stream) { - return Boolean(stream && stream.writable && !stream.destroyed); -} - -function isErrored(stream) { - return Boolean(stream && stream.errored); -} - -function isDisturbed(stream) { - return Boolean( - stream && (stream.disturbed === true || stream.locked || stream.readableDidRead === true), - ); -} - -const streamModule = Stream; -Object.assign(streamModule, { - Duplex, - PassThrough, - Readable, - Stream, - Transform, - Writable, - addAbortSignal, - compose, - finished, - isDisturbed, - isErrored, - isReadable, - isWritable, - pipeline, -}); - -export { - Duplex, - PassThrough, - Readable, - Stream, - Transform, - Writable, - addAbortSignal, - compose, - finished, - isDisturbed, - isErrored, - isReadable, - isWritable, - pipeline, -}; -export default streamModule; -"#, - ); - } - - if module_name == "stream/promises" { - return String::from( - r#"const _m = globalThis._requireFrom("node:stream/promises", "/"); - -export default _m; -export const finished = _m.finished; -export const pipeline = _m.pipeline; -"#, - ); - } - - if module_name == "zlib" { - return String::from( - r#"const _m = globalThis._requireFrom("node:zlib", "/"); -const zlibConstants = - typeof _m.constants === "object" && _m.constants !== null - ? _m.constants - : Object.fromEntries( - Object.entries(_m).filter( - ([key, value]) => /^[A-Z0-9_]+$/.test(key) && typeof value === "number", - ), - ); - -if (typeof _m.constants === "undefined") { - Object.defineProperty(_m, "constants", { - configurable: true, - enumerable: true, - value: zlibConstants, - writable: true, - }); -} - -export default _m; -export const constants = _m.constants; -export const BrotliCompress = _m.BrotliCompress; -export const BrotliDecompress = _m.BrotliDecompress; -export const Deflate = _m.Deflate; -export const DeflateRaw = _m.DeflateRaw; -export const Gunzip = _m.Gunzip; -export const Gzip = _m.Gzip; -export const Inflate = _m.Inflate; -export const InflateRaw = _m.InflateRaw; -export const Unzip = _m.Unzip; -export const brotliCompress = _m.brotliCompress; -export const brotliCompressSync = _m.brotliCompressSync; -export const brotliDecompress = _m.brotliDecompress; -export const brotliDecompressSync = _m.brotliDecompressSync; -export const createBrotliCompress = _m.createBrotliCompress; -export const createBrotliDecompress = _m.createBrotliDecompress; -export const createDeflate = _m.createDeflate; -export const createDeflateRaw = _m.createDeflateRaw; -export const createGunzip = _m.createGunzip; -export const createGzip = _m.createGzip; -export const createInflate = _m.createInflate; -export const createInflateRaw = _m.createInflateRaw; -export const createUnzip = _m.createUnzip; -export const deflate = _m.deflate; -export const deflateRaw = _m.deflateRaw; -export const deflateRawSync = _m.deflateRawSync; -export const deflateSync = _m.deflateSync; -export const gunzip = _m.gunzip; -export const gunzipSync = _m.gunzipSync; -export const gzip = _m.gzip; -export const gzipSync = _m.gzipSync; -export const inflate = _m.inflate; -export const inflateRaw = _m.inflateRaw; -export const inflateRawSync = _m.inflateRawSync; -export const inflateSync = _m.inflateSync; -export const unzip = _m.unzip; -export const unzipSync = _m.unzipSync; -"#, - ); - } - - if module_name == "stream/web" { - return String::from( - r#"export const ReadableStream = globalThis.ReadableStream; -export const WritableStream = globalThis.WritableStream; -export const TransformStream = globalThis.TransformStream; -export const TextEncoderStream = globalThis.TextEncoderStream; -export const TextDecoderStream = globalThis.TextDecoderStream; -export const CompressionStream = globalThis.CompressionStream; -export const DecompressionStream = globalThis.DecompressionStream; -export default { - ReadableStream, - WritableStream, - TransformStream, - TextEncoderStream, - TextDecoderStream, - CompressionStream, - DecompressionStream, -}; -"#, - ); - } - - if module_name == "fs/promises" { - return String::from( - r#"const fsModule = globalThis._requireFrom("node:fs", "/"); -const _m = fsModule.promises; - -export default _m; -export const constants = fsModule.constants; -export const FileHandle = _m.FileHandle; -export const access = _m.access; -export const appendFile = _m.appendFile; -export const chmod = _m.chmod; -export const chown = _m.chown; -export const copyFile = _m.copyFile; -export const cp = _m.cp; -export const lchmod = _m.lchmod; -export const lchown = _m.lchown; -export const link = _m.link; -export const lstat = _m.lstat; -export const lutimes = _m.lutimes; -export const mkdir = _m.mkdir; -export const mkdtemp = _m.mkdtemp; -export const open = _m.open; -export const opendir = _m.opendir; -export const readFile = _m.readFile; -export const readdir = _m.readdir; -export const readlink = _m.readlink; -export const realpath = _m.realpath; -export const rename = _m.rename; -export const rm = _m.rm; -export const rmdir = _m.rmdir; -export const stat = _m.stat; -export const statfs = _m.statfs; -export const symlink = _m.symlink; -export const truncate = _m.truncate; -export const unlink = _m.unlink; -export const utimes = _m.utimes; -export const watch = _m.watch; -export const writeFile = _m.writeFile; -"#, - ); - } - - if module_name == "readline" { - return String::from( - r#"const _m = globalThis._requireFrom("node:readline", "/"); - -function createInterface(...args) { - const interfaceValue = _m.createInterface(...args); - if (interfaceValue && typeof interfaceValue === "object") { - if (interfaceValue.__agentOSReadlineWrapped === true) { - return interfaceValue; - } - Object.defineProperty(interfaceValue, "__agentOSReadlineWrapped", { - value: true, - configurable: true, - enumerable: false, - writable: false, - }); - const options = args[0] && typeof args[0] === "object" ? args[0] : {}; - const output = options.output ?? null; - const originalOn = typeof interfaceValue.on === "function" - ? interfaceValue.on.bind(interfaceValue) - : null; - const originalOff = typeof interfaceValue.off === "function" - ? interfaceValue.off.bind(interfaceValue) - : typeof interfaceValue.removeListener === "function" - ? interfaceValue.removeListener.bind(interfaceValue) - : null; - const originalClose = typeof interfaceValue.close === "function" - ? interfaceValue.close.bind(interfaceValue) - : null; - const queued = []; - const pendingQuestionResolves = []; - let pendingResolve = null; - let done = false; - const enqueue = (line) => { - if (pendingQuestionResolves.length > 0) { - const resolve = pendingQuestionResolves.shift(); - resolve(line); - return; - } - if (pendingResolve) { - const resolve = pendingResolve; - pendingResolve = null; - resolve({ done: false, value: line }); - return; - } - queued.push(line); - }; - const finish = () => { - if (done) { - return; - } - done = true; - while (pendingQuestionResolves.length > 0) { - const resolve = pendingQuestionResolves.shift(); - resolve(""); - } - if (pendingResolve) { - const resolve = pendingResolve; - pendingResolve = null; - resolve({ done: true, value: void 0 }); - } - }; - const readLine = () => { - if (queued.length > 0) { - return Promise.resolve(queued.shift()); - } - if (done) { - return Promise.resolve(""); - } - return new Promise((resolve) => { - pendingQuestionResolves.push(resolve); - }); - }; - originalOn?.("line", enqueue); - originalOn?.("close", finish); - interfaceValue.question = (prompt, callback) => { - if (output && typeof output.write === "function" && prompt) { - output.write(String(prompt)); - } - if (typeof callback === "function") { - void readLine().then((line) => { - callback(line); - }); - return; - } - return readLine(); - }; - interfaceValue[Symbol.asyncIterator] = () => ({ - next() { - if (queued.length > 0) { - return Promise.resolve({ done: false, value: queued.shift() }); - } - if (done) { - return Promise.resolve({ done: true, value: void 0 }); - } - return new Promise((resolve) => { - pendingResolve = resolve; - }); - }, - return() { - originalOff?.("line", enqueue); - originalOff?.("close", finish); - originalClose?.(); - finish(); - return Promise.resolve({ done: true, value: void 0 }); - }, - [Symbol.asyncIterator]() { - return this; - }, - }); - } - return interfaceValue; -} - -export default _m; -export { createInterface }; -"#, - ); - } - - if module_name == "string_decoder" { - return String::from( - r#"class StringDecoder { - constructor(encoding = "utf8") { - this.encoding = encoding; - this.decoder = new TextDecoder(encoding, { fatal: false }); - } - - write(input) { - const buffer = - typeof input === "string" - ? Buffer.from(input, this.encoding) - : Buffer.isBuffer(input) - ? input - : Buffer.from(input ?? []); - return this.decoder.decode(buffer, { stream: true }); - } - - end(input) { - let output = ""; - if (input !== undefined) { - output += this.write(input); - } - output += this.decoder.decode(); - return output; - } -} - -export { StringDecoder }; -export default { StringDecoder }; -"#, - ); - } - - if module_name == "v8" { - return String::from( - r#"function serialize(value) { - return Buffer.from(JSON.stringify(value ?? null), "utf8"); -} - -function deserialize(value) { - const buffer = Buffer.isBuffer(value) ? value : Buffer.from(value ?? []); - return JSON.parse(buffer.toString("utf8")); -} - -class Serializer { - constructor() { - this._value = null; - } - - writeHeader() {} - - writeValue(value) { - this._value = value; - } - - releaseBuffer() { - return serialize(this._value); - } - - transferArrayBuffer() {} -} - -class Deserializer { - constructor(buffer) { - this._buffer = buffer; - } - - readHeader() {} - - readValue() { - return deserialize(this._buffer); - } - - transferArrayBuffer() {} -} - -function cachedDataVersionTag() { - return 0; -} - -function getCppHeapStatistics() { - return { - committed_size_bytes: 0, - resident_size_bytes: 0, - used_size_bytes: 0, - space_statistics: [], - }; -} - -function getHeapCodeStatistics() { - return { - code_and_metadata_size: 0, - bytecode_and_metadata_size: 0, - external_script_source_size: 0, - cpu_profiler_metadata_size: 0, - }; -} - -function configuredHeapLimitBytes() { - const configured = Number(globalThis.__agentOSV8HeapLimitBytes); - if (!Number.isFinite(configured) || configured <= 0) { - return 0; - } - return configured; -} - -function getHeapStatistics() { - const heapLimit = configuredHeapLimitBytes(); - return { - total_heap_size: 0, - total_heap_size_executable: 0, - total_physical_size: 0, - total_available_size: 0, - used_heap_size: 0, - heap_size_limit: heapLimit, - malloced_memory: 0, - peak_malloced_memory: 0, - does_zap_garbage: 0, - number_of_native_contexts: 0, - number_of_detached_contexts: 0, - total_global_handles_size: 0, - used_global_handles_size: 0, - external_memory: 0, - }; -} - -function getHeapSpaceStatistics() { - return []; -} - -function getHeapSnapshot() { - return Readable.fromWeb( - new ReadableStream({ - start(controller) { - controller.enqueue(Buffer.from("{}")); - controller.close(); - }, - }), - ); -} - -function isStringOneByteRepresentation(value) { - return typeof value === "string" && !/[^\x00-\xff]/.test(value); -} - -function queryObjects() { - return []; -} - -function setFlagsFromString() {} - -function setHeapSnapshotNearHeapLimit() { - return []; -} - -function startCpuProfile() { - return { - stop() { - return {}; - }, - }; -} - -function stopCoverage() { - return []; -} - -function takeCoverage() { - return []; -} - -function writeHeapSnapshot() { - return ""; -} - -class GCProfiler { - start() {} - - stop() { - return []; - } -} - -const promiseHooks = {}; -const startupSnapshot = {}; - -export { - GCProfiler, - cachedDataVersionTag, - Deserializer, - deserialize, - getCppHeapStatistics, - getHeapCodeStatistics, - getHeapSnapshot, - getHeapSpaceStatistics, - getHeapStatistics, - isStringOneByteRepresentation, - promiseHooks, - queryObjects, - serialize, - Serializer, - setFlagsFromString, - setHeapSnapshotNearHeapLimit, - startCpuProfile, - startupSnapshot, - stopCoverage, - takeCoverage, - writeHeapSnapshot, -}; -export { - Deserializer as DefaultDeserializer, - Serializer as DefaultSerializer, -}; -export default { - GCProfiler, - cachedDataVersionTag, - DefaultDeserializer: Deserializer, - DefaultSerializer: Serializer, - Deserializer, - deserialize, - getCppHeapStatistics, - getHeapCodeStatistics, - getHeapSnapshot, - getHeapSpaceStatistics, - getHeapStatistics, - isStringOneByteRepresentation, - promiseHooks, - queryObjects, - serialize, - Serializer, - setFlagsFromString, - setHeapSnapshotNearHeapLimit, - startCpuProfile, - startupSnapshot, - stopCoverage, - takeCoverage, - writeHeapSnapshot, -}; -"#, - ); - } - - if module_name == "vm" { - return String::from( - r#"const VM_CONTEXT_TAG = typeof Symbol === "function" ? Symbol.for("secure-exec.vm.context") : "__secure_exec_vm_context__"; -const VM_CONTEXT_ID = typeof Symbol === "function" ? Symbol.for("secure-exec.vm.context.id") : "__secure_exec_vm_context_id__"; - -function createVmNotImplementedError(feature) { - const error = new Error(`node:vm ${feature} is not implemented in the secure-exec guest runtime`); - error.code = "ERR_NOT_IMPLEMENTED"; - return error; -} - -function isVmContextCandidate(value) { - return value !== null && (typeof value === "object" || typeof value === "function"); -} - -function normalizeVmOptions(options = undefined) { - if (typeof options === "string") { - return { filename: options }; - } - if (!options || typeof options !== "object") { - return {}; - } - const normalized = {}; - if (typeof options.filename === "string") { - normalized.filename = options.filename; - } - if (Number.isInteger(options.lineOffset)) { - normalized.lineOffset = options.lineOffset; - } - if (Number.isInteger(options.columnOffset)) { - normalized.columnOffset = options.columnOffset; - } - if (Number.isInteger(options.timeout) && options.timeout > 0) { - normalized.timeout = options.timeout; - } - if (options.cachedData !== undefined) { - normalized.cachedData = options.cachedData; - } - if (options.produceCachedData === true) { - normalized.produceCachedData = true; - } - return normalized; -} - -function mergeVmOptions(baseOptions, overrideOptions) { - return { ...normalizeVmOptions(baseOptions), ...normalizeVmOptions(overrideOptions) }; -} - -function createContext(context = {}) { - if (!isVmContextCandidate(context)) { - throw new TypeError('The "object" argument must be of type object.'); - } - if (context[VM_CONTEXT_TAG] === true && Number.isInteger(context[VM_CONTEXT_ID])) { - return context; - } - const contextId = globalThis._vmCreateContext(context); - Object.defineProperty(context, VM_CONTEXT_TAG, { - value: true, - configurable: true, - enumerable: false, - writable: false, - }); - Object.defineProperty(context, VM_CONTEXT_ID, { - value: contextId, - configurable: false, - enumerable: false, - writable: false, - }); - return context; -} - -function isContext(context) { - return isVmContextCandidate(context) && context[VM_CONTEXT_TAG] === true && Number.isInteger(context[VM_CONTEXT_ID]); -} - -function assertContext(context) { - if (!isContext(context)) { - throw new TypeError('The "contextifiedObject" argument must be a vm context.'); - } - return context; -} - -function runInThisContext(code, options = undefined) { - return globalThis._vmRunInThisContext(String(code), normalizeVmOptions(options)); -} - -function runInContext(code, contextifiedObject, options = undefined) { - const context = assertContext(contextifiedObject); - return globalThis._vmRunInContext(context[VM_CONTEXT_ID], String(code), normalizeVmOptions(options), context); -} - -function runInNewContext(code, contextOrOptions = {}, maybeOptions = undefined) { - const hasExplicitContext = isVmContextCandidate(contextOrOptions); - const context = hasExplicitContext ? contextOrOptions : {}; - const options = hasExplicitContext ? maybeOptions : contextOrOptions; - return runInContext(code, createContext(context), options); -} - -class Script { - constructor(code, options = undefined) { - this.code = String(code); - this.options = normalizeVmOptions(options); - this.filename = this.options.filename ?? "evalmachine."; - this.lineOffset = this.options.lineOffset ?? 0; - this.columnOffset = this.options.columnOffset ?? 0; - this.cachedData = this.options.cachedData; - this.cachedDataProduced = false; - this.cachedDataRejected = false; - } - - createCachedData() { - return typeof Buffer === "function" ? Buffer.alloc(0) : new Uint8Array(0); - } - - runInThisContext(options = undefined) { - return runInThisContext(this.code, mergeVmOptions(this.options, options)); - } - - runInContext(contextifiedObject, options = undefined) { - return runInContext(this.code, contextifiedObject, mergeVmOptions(this.options, options)); - } - - runInNewContext(context = {}, options = undefined) { - return runInNewContext(this.code, context, mergeVmOptions(this.options, options)); - } -} - -function compileFunction() { - throw createVmNotImplementedError("compileFunction"); -} - -function measureMemory() { - throw createVmNotImplementedError("measureMemory"); -} - -export { Script, compileFunction, createContext, isContext, measureMemory, runInContext, runInNewContext, runInThisContext }; -export default { Script, compileFunction, createContext, isContext, measureMemory, runInContext, runInNewContext, runInThisContext }; -"#, - ); - } - - if module_name == "worker_threads" { - return String::from( - r#"function createNotImplementedError(feature) { - const error = new Error(`node:worker_threads ${feature} is not available in the secure-exec guest runtime`); - error.code = "ERR_NOT_IMPLEMENTED"; - return error; -} - -class MessagePort { - postMessage() {} - start() {} - close() {} - unref() { - return this; - } - ref() { - return this; - } -} - -class MessageChannel { - constructor() { - this.port1 = new MessagePort(); - this.port2 = new MessagePort(); - } -} - -class Worker { - constructor() { - throw createNotImplementedError("Worker"); - } -} - -function getEnvironmentData() { - return undefined; -} - -function markAsUncloneable() {} - -function markAsUntransferable() {} - -function moveMessagePortToContext() { - throw createNotImplementedError("moveMessagePortToContext"); -} - -function postMessageToThread() { - throw createNotImplementedError("postMessageToThread"); -} - -function receiveMessageOnPort() { - return undefined; -} - -function setEnvironmentData() {} - -export const BroadcastChannel = globalThis.BroadcastChannel; -export { MessageChannel, MessagePort, Worker, getEnvironmentData, markAsUncloneable, markAsUntransferable, moveMessagePortToContext, postMessageToThread, receiveMessageOnPort, setEnvironmentData }; -export const SHARE_ENV = Symbol.for("secure-exec.worker_threads.SHARE_ENV"); -export const isMainThread = true; -export const parentPort = null; -export const resourceLimits = {}; -export const threadId = 0; -export const workerData = null; -export default { - BroadcastChannel: globalThis.BroadcastChannel, - MessageChannel, - MessagePort, - SHARE_ENV, - Worker, - getEnvironmentData, - isMainThread, - markAsUncloneable, - markAsUntransferable, - moveMessagePortToContext, - parentPort, - postMessageToThread, - receiveMessageOnPort, - resourceLimits, - setEnvironmentData, - threadId, - workerData, -}; -"#, - ); - } - - let default_target = format!( - "globalThis._requireFrom({}, \"/\")", - serde_json::to_string(&format!("node:{module_name}")) - .unwrap_or_else(|_| format!("\"node:{module_name}\"")) - ); - let mut exports = builtin_named_exports(module_name) - .iter() - .collect::>() - .into_iter() - .collect::>(); - exports.sort_unstable(); - - let mut source = format!("const _m = {default_target};\nexport default _m;\n"); - for name in exports { - source.push_str(&format!("export const {name} = _m[\"{name}\"];\n")); - } - source -} - -fn builtin_named_exports(module_name: &str) -> &'static [&'static str] { - match module_name { - "async_hooks" => &[ - "AsyncLocalStorage", - "AsyncResource", - "createHook", - "executionAsyncId", - "triggerAsyncId", - ], - "buffer" => &[ - "Blob", - "Buffer", - "File", - "INSPECT_MAX_BYTES", - "SlowBuffer", - "isUtf8", - ], - "child_process" => &[ - "ChildProcess", - "exec", - "execFile", - "execFileSync", - "execSync", - "fork", - "spawn", - "spawnSync", - ], - "console" => &[ - "Console", - "assert", - "clear", - "context", - "count", - "countReset", - "createTask", - "debug", - "dir", - "dirxml", - "error", - "group", - "groupCollapsed", - "groupEnd", - "info", - "log", - "profile", - "profileEnd", - "table", - "time", - "timeEnd", - "timeLog", - "timeStamp", - "trace", - "warn", - ], - "crypto" => &[ - "createHash", - "createPrivateKey", - "getHashes", - "getRandomValues", - "randomBytes", - "randomFillSync", - "randomUUID", - "subtle", - ], - "diagnostics_channel" => &[ - "Channel", - "channel", - "hasSubscribers", - "subscribe", - "tracingChannel", - "unsubscribe", - ], - "events" => &[ - "EventEmitter", - "addAbortListener", - "defaultMaxListeners", - "errorMonitor", - "getEventListeners", - "getMaxListeners", - "on", - "once", - "setMaxListeners", - ], - "dns" => &[ - "Resolver", - "getServers", - "lookup", - "promises", - "resolve", - "resolve4", - "resolve6", - "setServers", - ], - "dns/promises" => &[ - "Resolver", - "lookup", - "resolve", - "resolve4", - "resolve6", - "resolveAny", - "resolveMx", - "resolveTxt", - "resolveSrv", - "resolveCname", - "resolvePtr", - "resolveNs", - "resolveSoa", - "resolveNaptr", - "resolveCaa", - ], - "fs" => &[ - "access", - "accessSync", - "appendFile", - "appendFileSync", - "chmod", - "chmodSync", - "closeSync", - "constants", - "createReadStream", - "createWriteStream", - "existsSync", - "fstat", - "fstatSync", - "fsyncSync", - "lstat", - "lstatSync", - "mkdir", - "mkdirSync", - "openSync", - "readFile", - "promises", - "readFileSync", - "readdir", - "readSync", - "readdirSync", - "readlink", - "realpathSync", - "rename", - "readlinkSync", - "renameSync", - "rm", - "rmSync", - "stat", - "statSync", - "unlink", - "unlinkSync", - "watch", - "watchFile", - "unwatchFile", - "writeFile", - "writeFileSync", - "writeSync", - ], - "fs/promises" => &[ - "access", - "appendFile", - "chmod", - "chown", - "constants", - "copyFile", - "cp", - "glob", - "lchown", - "link", - "lstat", - "mkdir", - "mkdtemp", - "open", - "opendir", - "readFile", - "readdir", - "readlink", - "realpath", - "rename", - "rm", - "rmdir", - "stat", - "statfs", - "symlink", - "truncate", - "unlink", - "utimes", - "writeFile", - ], - "http" => &[ - "Agent", - "ClientRequest", - "IncomingMessage", - "METHODS", - "Server", - "ServerResponse", - "STATUS_CODES", - "_checkInvalidHeaderChar", - "_checkIsHttpToken", - "createServer", - "get", - "globalAgent", - "maxHeaderSize", - "request", - "validateHeaderName", - "validateHeaderValue", - ], - "http2" => &["connect", "createServer", "createSecureServer"], - "https" => &[ - "Agent", - "ClientRequest", - "IncomingMessage", - "Server", - "ServerResponse", - "_checkInvalidHeaderChar", - "_checkIsHttpToken", - "createServer", - "get", - "globalAgent", - "maxHeaderSize", - "request", - "validateHeaderName", - "validateHeaderValue", - ], - "module" => &[ - "Module", - "_cache", - "_extensions", - "_resolveFilename", - "builtinModules", - "createRequire", - "findSourceMap", - "isBuiltin", - "syncBuiltinESMExports", - "wrap", - ], - "net" => &[ - "BlockList", - "Socket", - "SocketAddress", - "Server", - "Stream", - "connect", - "createConnection", - "createServer", - "getDefaultAutoSelectFamily", - "getDefaultAutoSelectFamilyAttemptTimeout", - "isIP", - "isIPv4", - "isIPv6", - "setDefaultAutoSelectFamily", - "setDefaultAutoSelectFamilyAttemptTimeout", - ], - "os" => &[ - "EOL", - "arch", - "availableParallelism", - "constants", - "cpus", - "endianness", - "freemem", - "homedir", - "hostname", - "networkInterfaces", - "platform", - "release", - "totalmem", - "tmpdir", - "type", - "userInfo", - "version", - ], - "path" | "path/posix" | "path/win32" => &[ - "basename", - "delimiter", - "dirname", - "extname", - "format", - "isAbsolute", - "join", - "normalize", - "parse", - "posix", - "relative", - "resolve", - "sep", - "win32", - ], - "process" => &[ - "arch", "argv", "argv0", "cwd", "env", "execPath", "exit", "pid", "platform", "ppid", - "stderr", "stdin", "stdout", "umask", "version", "versions", - ], - "perf_hooks" => &[ - "PerformanceObserver", - "constants", - "createHistogram", - "performance", - ], - "readline" => &["createInterface"], - "sqlite" => &["DatabaseSync", "StatementSync", "constants"], - "stream" => &[ - "Duplex", - "PassThrough", - "Readable", - "Stream", - "Transform", - "Writable", - "addAbortSignal", - "compose", - "finished", - "isDisturbed", - "isErrored", - "isReadable", - "pipeline", - ], - "stream/consumers" => &["arrayBuffer", "blob", "buffer", "json", "text"], - "sys" => &[ - "MIMEType", - "MIMEParams", - "TextDecoder", - "TextEncoder", - "callbackify", - "debug", - "debuglog", - "deprecate", - "format", - "formatWithOptions", - "inherits", - "inspect", - "parseArgs", - "promisify", - "stripVTControlCharacters", - "types", - ], - "timers" => &[ - "clearImmediate", - "clearInterval", - "clearTimeout", - "setImmediate", - "setInterval", - "setTimeout", - ], - "tty" => &["ReadStream", "WriteStream", "isatty"], - "tls" => &[ - "TLSSocket", - "Server", - "connect", - "createSecureContext", - "createServer", - "getCiphers", - ], - "stream/promises" => &["finished", "pipeline"], - "timers/promises" => &["scheduler", "setImmediate", "setInterval", "setTimeout"], - "url" => &["URL", "fileURLToPath", "format", "parse", "pathToFileURL"], - "util" => &[ - "MIMEType", - "MIMEParams", - "TextDecoder", - "TextEncoder", - "callbackify", - "debug", - "debuglog", - "deprecate", - "format", - "formatWithOptions", - "inherits", - "inspect", - "isDeepStrictEqual", - "parseArgs", - "promisify", - "stripVTControlCharacters", - "types", - ], - "util/types" => &[ - "isAnyArrayBuffer", - "isArgumentsObject", - "isArrayBuffer", - "isArrayBufferView", - "isAsyncFunction", - "isBigInt64Array", - "isBigIntObject", - "isBigUint64Array", - "isBooleanObject", - "isBoxedPrimitive", - "isCryptoKey", - "isDataView", - "isDate", - "isExternal", - "isFloat16Array", - "isFloat32Array", - "isFloat64Array", - "isGeneratorFunction", - "isGeneratorObject", - "isInt16Array", - "isInt32Array", - "isInt8Array", - "isKeyObject", - "isMap", - "isMapIterator", - "isModuleNamespaceObject", - "isNativeError", - "isNumberObject", - "isPromise", - "isProxy", - "isRegExp", - "isSet", - "isSetIterator", - "isSharedArrayBuffer", - "isStringObject", - "isSymbolObject", - "isTypedArray", - "isUint16Array", - "isUint32Array", - "isUint8Array", - "isUint8ClampedArray", - "isWeakMap", - "isWeakSet", - ], - "vm" => &[ - "Script", - "compileFunction", - "createContext", - "isContext", - "measureMemory", - "runInContext", - "runInNewContext", - "runInThisContext", - ], - "v8" => &[ - "cachedDataVersionTag", - "DefaultDeserializer", - "DefaultSerializer", - "Deserializer", - "GCProfiler", - "Serializer", - "deserialize", - "getCppHeapStatistics", - "getHeapCodeStatistics", - "getHeapSnapshot", - "getHeapSpaceStatistics", - "getHeapStatistics", - "isStringOneByteRepresentation", - "promiseHooks", - "queryObjects", - "serialize", - "setFlagsFromString", - "setHeapSnapshotNearHeapLimit", - "startCpuProfile", - "startupSnapshot", - "stopCoverage", - "takeCoverage", - "writeHeapSnapshot", - ], - "worker_threads" => &[ - "MessageChannel", - "MessagePort", - "Worker", - "isMainThread", - "parentPort", - "workerData", - ], - "zlib" => &[ - "BrotliCompress", - "BrotliDecompress", - "Deflate", - "DeflateRaw", - "Gunzip", - "Gzip", - "Inflate", - "InflateRaw", - "Unzip", - "brotliCompress", - "brotliCompressSync", - "brotliDecompress", - "brotliDecompressSync", - "constants", - "createBrotliCompress", - "createBrotliDecompress", - "createDeflate", - "createDeflateRaw", - "createGunzip", - "createGzip", - "createInflate", - "createInflateRaw", - "createUnzip", - "deflate", - "deflateRaw", - "deflateRawSync", - "deflateSync", - "gunzip", - "gunzipSync", - "gzip", - "gzipSync", - "inflate", - "inflateRaw", - "inflateRawSync", - "inflateSync", - "unzip", - "unzipSync", - ], - _ => &[], - } -} - -fn split_package_request(request: &str) -> Option<(&str, &str)> { - if request.starts_with('@') { - let mut parts = request.splitn(3, '/'); - let scope = parts.next()?; - let name = parts.next()?; - let package_name = &request[..scope.len() + 1 + name.len()]; - let subpath = parts.next().unwrap_or(""); - Some((package_name, subpath)) - } else { - request.split_once('/').or(Some((request, ""))) - } -} - -fn node_modules_direct_candidate_dirs(dir: &str, package_name: &str) -> Vec { - let mut candidates = HashSet::new(); - candidates.insert(join_guest_path( - dir, - &format!("node_modules/{package_name}"), - )); - if dir == "/node_modules" || dir.ends_with("/node_modules") { - candidates.insert(join_guest_path(dir, package_name)); - } - let mut candidates = candidates.into_iter().collect::>(); - candidates.sort(); - candidates -} - -fn resolve_exports_target( - exports_field: &Value, - subpath: &str, - mode: ModuleResolveMode, -) -> Option { - match exports_field { - Value::String(value) => (subpath == ".").then(|| value.clone()), - Value::Array(values) => values - .iter() - .find_map(|value| resolve_exports_target(value, subpath, mode)), - Value::Object(record) => { - if subpath == "." - && !record.contains_key(".") - && !record.keys().any(|key| key.starts_with("./")) - { - return resolve_conditional_target(record, mode); - } - if let Some(value) = record.get(subpath) { - return resolve_exports_target(value, ".", mode); - } - for (key, value) in record { - if let Some((prefix, suffix)) = key.split_once('*') { - if subpath.starts_with(prefix) && subpath.ends_with(suffix) { - let wildcard = &subpath[prefix.len()..subpath.len() - suffix.len()]; - let resolved = resolve_exports_target(value, ".", mode)?; - return Some(resolved.replace('*', wildcard)); - } - } - } - if subpath == "." { - record - .get(".") - .and_then(|value| resolve_exports_target(value, ".", mode)) - } else { - None - } - } - _ => None, - } -} - -fn resolve_conditional_target( - record: &serde_json::Map, - mode: ModuleResolveMode, -) -> Option { - let order: &[&str] = match mode { - ModuleResolveMode::Import => &["import", "node", "module", "default", "require"], - ModuleResolveMode::Require => &["require", "node", "default", "import", "module"], - }; - for key in order { - if let Some(value) = record.get(*key) { - if let Some(resolved) = resolve_exports_target(value, ".", mode) { - return Some(resolved); - } - } - } - None -} - -fn resolve_imports_target( - imports_field: &Value, - specifier: &str, - mode: ModuleResolveMode, -) -> Option { - match imports_field { - Value::String(value) => Some(value.clone()), - Value::Array(values) => values - .iter() - .find_map(|value| resolve_imports_target(value, specifier, mode)), - Value::Object(record) => { - if let Some(value) = record.get(specifier) { - return resolve_exports_target(value, ".", mode); - } - for (key, value) in record { - if let Some((prefix, suffix)) = key.split_once('*') { - if specifier.starts_with(prefix) && specifier.ends_with(suffix) { - let wildcard = &specifier[prefix.len()..specifier.len() - suffix.len()]; - let resolved = resolve_exports_target(value, ".", mode)?; - return Some(resolved.replace('*', wildcard)); - } - } - } - None - } - _ => None, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use nix::fcntl::OFlag; - use nix::unistd::pipe2; - use serde_json::Value; - use std::io::BufRead; - use std::time::{SystemTime, UNIX_EPOCH}; - use tempfile::tempdir; - - #[test] - fn javascript_limits_are_read_from_typed_fields_and_env_is_inert() { - // Misleading env values: a reader that still consulted `AGENTOS_*` would - // observe these instead of the typed wire limits. - let env = std::collections::BTreeMap::from([ - ( - String::from("AGENTOS_V8_HEAP_LIMIT_MB"), - String::from("999999"), - ), - ( - String::from("AGENTOS_V8_CPU_TIME_LIMIT_MS"), - String::from("999999"), - ), - ( - String::from("AGENTOS_V8_WALL_CLOCK_LIMIT_MS"), - String::from("999999"), - ), - ( - String::from("AGENTOS_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT_MS"), - String::from("999999"), - ), - ( - String::from(NODE_SYNC_RPC_WAIT_TIMEOUT_MS_ENV), - String::from("999999"), - ), - ]); - let request = StartJavascriptExecutionRequest { - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: String::from("ctx-js"), - argv: vec![String::from("/entry.mjs")], - env, - cwd: std::path::PathBuf::from("/tmp"), - limits: JavascriptExecutionLimits { - v8_heap_limit_mb: Some(64), - sync_rpc_wait_timeout_ms: Some(2_000), - cpu_time_limit_ms: Some(750), - wall_clock_limit_ms: Some(500), - import_cache_materialize_timeout_ms: Some(125), - }, - wasm_module_bytes: None, - inline_code: None, - }; - - assert_eq!( - javascript_heap_limit_mb(&request), - 64, - "heap must come from the typed wire limit, not AGENTOS_V8_HEAP_LIMIT_MB" - ); - assert_eq!( - javascript_sync_rpc_timeout(&request), - std::time::Duration::from_millis(2_000), - "sync-rpc wait must come from the typed wire limit, not env" - ); - assert_eq!( - javascript_cpu_time_limit_ms(&request), - 750, - "CPU budget must come from the typed wire limit, not env" - ); - assert_eq!( - javascript_wall_clock_limit_ms(&request), - 500, - "wall-clock budget must come from the typed wire limit, not env" - ); - assert_eq!( - javascript_import_cache_materialize_timeout(&request), - std::time::Duration::from_millis(125), - "import-cache timeout must come from the typed wire limit, not env" - ); - } - - #[test] - fn javascript_limits_fall_back_to_defaults_when_unset() { - let request = StartJavascriptExecutionRequest { - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: String::from("ctx-js"), - argv: vec![String::from("/entry.mjs")], - env: std::collections::BTreeMap::new(), - cwd: std::path::PathBuf::from("/tmp"), - limits: JavascriptExecutionLimits::default(), - wasm_module_bytes: None, - inline_code: None, - }; - - assert_eq!( - javascript_heap_limit_mb(&request), - 0, - "0 selects the engine default heap" - ); - assert_eq!( - javascript_sync_rpc_timeout(&request), - std::time::Duration::from_millis(NODE_SYNC_RPC_DEFAULT_WAIT_TIMEOUT_MS), - ); - assert_eq!( - javascript_cpu_time_limit_ms(&request), - DEFAULT_V8_CPU_TIME_LIMIT_MS - ); - assert_eq!( - javascript_wall_clock_limit_ms(&request), - DEFAULT_V8_WALL_CLOCK_LIMIT_MS - ); - assert_eq!( - javascript_import_cache_materialize_timeout(&request), - std::time::Duration::from_millis(DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT_MS) - ); - } - - #[test] - fn inline_code_module_detection_prefers_commonjs_when_import_only_appears_in_comment() { - let source = "// import { x } from 'y';\nmodule.exports = { foo: 1 };"; - assert!(!inline_code_uses_module_mode(source)); - } - - #[test] - fn inline_code_module_detection_ignores_import_inside_string_literal() { - let source = "const msg = \"run: import x from 'y'\";\nmodule.exports.msg = msg;"; - assert!(!inline_code_uses_module_mode(source)); - } - - #[test] - fn inline_code_module_detection_accepts_multiline_import_statements() { - let source = "import\n { default as foo }\nfrom 'bar';\nconsole.log(foo);"; - assert!(inline_code_uses_module_mode(source)); - } - - #[test] - fn inline_code_module_detection_accepts_real_esm_source() { - let source = "import { foo } from 'bar';\nexport const baz = 1;\nconsole.log(foo, baz);"; - assert!(inline_code_uses_module_mode(source)); - } - - #[test] - fn inline_code_module_detection_is_deterministic_for_empty_comment_only_and_template_cases() { - assert!(!inline_code_uses_module_mode("")); - assert!(!inline_code_uses_module_mode( - "// import x from 'y';\n/* export const z = 1; */" - )); - assert!(!inline_code_uses_module_mode( - "const msg = `export const nope = 1;`;" - )); - } - - #[test] - fn javascript_sync_rpc_timeout_writes_clear_error_response() { - let (reader_fd, writer_fd) = pipe2(OFlag::O_CLOEXEC).expect("create pipe"); - let reader = File::from(reader_fd); - let writer = File::from(writer_fd); - let response_writer = - JavascriptSyncRpcResponseWriter::new(writer, Duration::from_millis(50)); - let pending = Arc::new(Mutex::new(Some(PendingSyncRpcState::Pending(7)))); - - spawn_javascript_sync_rpc_timeout( - 7, - Duration::from_millis(20), - pending.clone(), - Some(response_writer), - ); - - let mut line = String::new(); - let mut reader = BufReader::new(reader); - reader.read_line(&mut line).expect("read timeout response"); - - let response: Value = serde_json::from_str(line.trim()).expect("parse timeout response"); - assert_eq!(response["id"], Value::from(7)); - assert_eq!(response["ok"], Value::from(false)); - assert_eq!( - response["error"]["code"], - Value::String(String::from("ERR_AGENTOS_NODE_SYNC_RPC_TIMEOUT")) - ); - assert!(response["error"]["message"] - .as_str() - .expect("timeout message") - .contains("timed out after 20ms")); - assert_eq!( - *pending.lock().expect("pending state lock"), - Some(PendingSyncRpcState::TimedOut(7)) - ); - } - - #[test] - fn javascript_sync_rpc_response_writer_times_out_when_queue_is_full() { - let (sender, _receiver) = mpsc::sync_channel(1); - let writer = JavascriptSyncRpcResponseWriter { - sender, - timeout: Duration::from_millis(30), - }; - - writer - .send(b"first\n".to_vec()) - .expect("queue first response"); - - let started = Instant::now(); - let error = writer - .send(b"second\n".to_vec()) - .expect_err("full queue should time out"); - assert!( - started.elapsed() >= Duration::from_millis(30), - "send should wait for the configured timeout" - ); - assert!(error - .to_string() - .contains("timed out after 30ms while queueing JavaScript sync RPC response")); - } - - #[test] - fn javascript_wait_capture_rejects_output_over_limit() { - let mut stdout = vec![b'x'; JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES - 1]; - append_captured_output(&mut stdout, vec![b'y'], "stdout").expect("fill to limit"); - assert_eq!(stdout.len(), JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES); - - let error = append_captured_output(&mut stdout, vec![b'z'], "stdout") - .expect_err("captured output over limit should fail"); - assert!(matches!( - error, - JavascriptExecutionError::OutputBufferExceeded { - stream: "stdout", - limit: JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES, - } - )); - } - - #[test] - fn kernel_stdin_bridge_rejects_buffer_over_limit_and_closed_writes() { - let bridge = LocalKernelStdinBridge::default(); - bridge - .write(&vec![b'x'; KERNEL_STDIN_BUFFER_LIMIT_BYTES]) - .expect("fill stdin buffer to limit"); - - let error = bridge - .write(b"y") - .expect_err("stdin buffer over limit should fail"); - assert!(matches!(error, JavascriptExecutionError::Stdin(_))); - - let bridge = LocalKernelStdinBridge::default(); - bridge.close(); - let error = bridge - .write(b"x") - .expect_err("write after stdin close should fail"); - assert!(matches!(error, JavascriptExecutionError::StdinClosed)); - } - - #[test] - fn javascript_event_sender_reports_closed_receiver() { - let (sender, receiver) = channel(1); - drop(receiver); - let host = V8RuntimeHost::spawn().expect("spawn V8 runtime host"); - let session = host.session_handle(String::from("closed-event-sender-test")); - let gauge = register_queue(TrackedLimit::JavascriptEventChannel, 1); - assert!(!send_javascript_event( - &sender, - &session, - &gauge, - None, - JavascriptExecutionEvent::Exited(1) - )); - } - - // Regression: a full event channel must apply backpressure, not destroy the - // session. The old code called `v8_session.destroy()` on the first `Full`, - // truncating the stream and tearing the session down. - #[test] - fn javascript_event_sender_backpressures_instead_of_destroying_when_full() { - let host = V8RuntimeHost::spawn().expect("spawn V8 runtime host"); - let session_id = format!( - "event-overflow-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time") - .as_nanos() - ); - let _session_receiver = host - .register_session(&session_id) - .expect("register event overflow session"); - let session = host.session_handle(session_id.clone()); - let gauge = register_queue(TrackedLimit::JavascriptEventChannel, 1); - let (sender, mut event_receiver) = channel(1); - - // Drain slowly on another thread so the producer is forced onto the - // blocking-backpressure path the old destroy-on-full code never reached. - let drainer = std::thread::spawn(move || { - let mut drained = 0usize; - while event_receiver.blocking_recv().is_some() { - drained += 1; - std::thread::sleep(std::time::Duration::from_millis(1)); - } - drained - }); - - // Far more events than the 1-slot channel holds; every send must succeed. - const SENDS: usize = 16; - for _ in 0..SENDS { - assert!(send_javascript_event( - &sender, - &session, - &gauge, - None, - JavascriptExecutionEvent::Stdout(Vec::new()) - )); - } - drop(sender); - let drained = drainer.join().expect("drainer thread panicked"); - assert_eq!(drained, SENDS, "every event must survive backpressure"); - - // The session must NOT have been destroyed: it is still registered, so a - // re-registration attempt fails. - host.register_session(&session_id) - .expect_err("session must survive backpressure (not be destroyed)"); - host.unregister_session(&session_id); - } - - #[test] - fn javascript_event_sender_destroys_session_when_event_is_oversized() { - let host = V8RuntimeHost::spawn().expect("spawn V8 runtime host"); - let session_id = format!( - "event-oversized-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time") - .as_nanos() - ); - let receiver = host - .register_session(&session_id) - .expect("register oversized event session"); - let session = host.session_handle(session_id.clone()); - let (sender, _event_receiver) = channel(JAVASCRIPT_EVENT_CHANNEL_CAPACITY); - let gauge = register_queue( - TrackedLimit::JavascriptEventChannel, - JAVASCRIPT_EVENT_CHANNEL_CAPACITY, - ); - - assert!(!send_javascript_event( - &sender, - &session, - &gauge, - None, - JavascriptExecutionEvent::Stdout(vec![0; JAVASCRIPT_EVENT_PAYLOAD_LIMIT_BYTES + 1]) - )); - - drop(receiver); - let recovered = host - .register_session(&session_id) - .expect("oversized event should destroy and deregister the session"); - drop(recovered); - host.unregister_session(&session_id); - } - - #[test] - fn internal_bridge_host_context_resolves_relative_module_path() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time") - .as_nanos(); - let root = std::env::temp_dir().join(format!( - "secure-exec-module-bridge-{}-{unique}", - std::process::id() - )); - let bin_dir = root.join("node_modules/next/dist/bin"); - let cli_dir = root.join("node_modules/next/dist/cli"); - fs::create_dir_all(&bin_dir).expect("create bin dir"); - fs::create_dir_all(&cli_dir).expect("create cli dir"); - fs::write( - root.join("node_modules/next/package.json"), - r#"{"name":"next"}"#, - ) - .expect("write package.json"); - fs::write(bin_dir.join("next"), "#!/usr/bin/env node\n").expect("write next bin"); - fs::write(cli_dir.join("next-build.js"), "module.exports = 1;\n") - .expect("write next-build.js"); - - let env = BTreeMap::new(); - let result = handle_internal_bridge_call_from_host_context( - &root, - "/", - &env, - "_resolveModule", - &[ - Value::String(String::from("../cli/next-build.js")), - Value::String(String::from("/node_modules/next/dist/bin/next")), - Value::String(String::from("import")), - ], - ); - - assert_eq!( - result, - Some(Value::String(String::from( - "/node_modules/next/dist/cli/next-build.js" - ))) - ); - - fs::remove_dir_all(&root).expect("remove temp module tree"); - } - - #[test] - fn register_v8_session_deregisters_on_create_session_failure() { - let host = V8RuntimeHost::spawn().expect("spawn V8 runtime host"); - let session_id = format!( - "v8-register-failure-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time") - .as_nanos() - ); - - let error = - match register_v8_session(&host, session_id.clone(), 0, 0, 0, None, |_command| { - Err(std::io::Error::new( - std::io::ErrorKind::BrokenPipe, - "simulated CreateSession send failure", - )) - }) { - Ok(_) => panic!("register_v8_session should surface create-session send failures"), - Err(error) => error, - }; - - match error { - JavascriptExecutionError::Spawn(inner) => { - assert_eq!(inner.kind(), std::io::ErrorKind::BrokenPipe); - } - other => panic!("unexpected error: {other:?}"), - } - let receiver = host - .register_session(&session_id) - .expect("failed registration should not leak the session output receiver"); - drop(receiver); - host.unregister_session(&session_id); - } - - #[test] - fn javascript_cpu_time_limit_defaults_to_bounded_value() { - let request = StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js-default-cpu"), - context_id: String::from("ctx-js-default-cpu"), - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: std::path::PathBuf::from("/tmp"), - wasm_module_bytes: None, - inline_code: None, - }; - - assert_eq!( - javascript_cpu_time_limit_ms(&request), - 30_000, - "unset JavaScript CPU budget must be bounded by default" - ); - } - - #[test] - fn javascript_execution_drop_keeps_normal_v8_session_cleanup() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-drop-cleanup"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-drop-cleanup"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from("globalThis.__agentOSDropCleanup = true;")), - }) - .expect("start JavaScript execution"); - let session_id = execution.v8_session.session_id().to_owned(); - let host = engine.v8_host.as_ref().expect("shared V8 runtime host"); - - drop(execution); - - let receiver = host - .register_session(&session_id) - .expect("execution drop should still destroy and deregister the session"); - drop(receiver); - host.unregister_session(&session_id); - } - - // --- Timer cancellation / cap regression tests (U4: H2 bridge timers, M3 - // kernel timers). These assert the *safeguards firing* (delay clamped, timer - // entry reclaimed, callback suppressed) and never spawn unbounded threads. --- - - #[test] - fn timer_delay_is_clamped_to_the_cap() { - // A guest can pass an arbitrarily large delay (up to u64::MAX ms); without - // a cap the timer wheel could retain a session Arc behind a deadline that - // is effectively forever away. The cap bounds that lifetime. - assert_eq!( - timer_delay_ms(Some(&json!(u64::MAX))), - MAX_TIMER_DELAY_MS, - "a u64::MAX delay must be clamped to MAX_TIMER_DELAY_MS" - ); - assert_eq!( - timer_delay_ms(Some(&json!(1.0e308_f64))), - MAX_TIMER_DELAY_MS, - "an enormous float delay must be clamped to the cap" - ); - assert_eq!( - timer_delay_ms(Some(&json!(MAX_TIMER_DELAY_MS + 1))), - MAX_TIMER_DELAY_MS, - "a delay one past the cap must clamp down to the cap" - ); - // Below-cap values pass through unchanged so normal timers are unaffected. - assert_eq!(timer_delay_ms(Some(&json!(250))), 250); - assert_eq!(timer_delay_ms(Some(&json!(0))), 0); - } - - #[test] - fn cleared_timer_is_suppressed_and_entry_reclaimed() { - // Mirrors what a woken bridge/kernel timer action does after waiting: it - // consults the shared map via `timer_should_fire`. When the entry has been - // removed (clear or session teardown), the callback must be suppressed. - let timers: Arc>> = - Arc::new(Mutex::new(HashMap::new())); - timers.lock().unwrap().insert( - 7, - LocalTimerEntry { - delay_ms: 1_000, - generation: 0, - repeat: false, - }, - ); - - // Simulate `kernelTimerClear` / teardown removing the entry before the - // action wakes. - timers.lock().unwrap().remove(&7); - - assert!( - !timer_should_fire(&timers, 7, 0), - "a cleared timer must not fire" - ); - assert!( - timers.lock().unwrap().is_empty(), - "tracking map stays empty after a cleared timer is evaluated" - ); - } - - #[test] - fn rearmed_timer_generation_mismatch_suppresses_stale_action() { - // The bridge/kernel timer action captures the generation at schedule time. - // If the timer is re-armed (generation bumped) before the stale action - // wakes, the stale action must observe the mismatch and suppress, while the - // entry survives for the live generation. - let timers: Arc>> = - Arc::new(Mutex::new(HashMap::new())); - timers.lock().unwrap().insert( - 3, - LocalTimerEntry { - delay_ms: 10, - generation: 1, - repeat: false, - }, - ); - - // Stale action captured generation 0; current entry is at generation 1. - assert!( - !timer_should_fire(&timers, 3, 0), - "a stale generation must be suppressed" - ); - assert!( - timers.lock().unwrap().contains_key(&3), - "the live entry must survive a stale-generation evaluation" - ); - - // The matching (current) generation fires and reclaims the one-shot entry. - assert!( - timer_should_fire(&timers, 3, 1), - "the current generation must fire" - ); - assert!( - timers.lock().unwrap().is_empty(), - "a fired one-shot timer must reclaim its id from the map" - ); - } - - #[test] - fn bridge_timer_registration_is_tracked_and_drop_clears_timers() { - // H2: the bridge-timer path must register its timer (so it is cancellable) - // before queuing a wheel action, and session teardown - // (dropping LocalBridgeState) must wipe the tracking map so in-flight timer - // actions are cancelled. - let mut state = LocalBridgeState::default(); - // Observe the same map the queued actions would consult. - let timers = state.timers.clone(); - - let id_a = state.register_oneshot_timer(MAX_TIMER_DELAY_MS); - let id_b = state.register_oneshot_timer(500); - assert_ne!(id_a, id_b, "each bridge timer gets a fresh id"); - assert_eq!( - timers.lock().unwrap().len(), - 2, - "registered bridge timers are tracked in the shared map" - ); - // A registered timer would fire for its captured generation (proving the - // entry is real and consultable) ... - assert!(timer_should_fire(&timers, id_a, 0)); - // ... and seeding a still-pending one before teardown: - let id_c = state.register_oneshot_timer(1_000); - - // Session teardown: dropping the bridge state must clear every timer so any - // queued action wakes to a missing entry and suppresses its callback. - drop(state); - - assert!( - timers.lock().unwrap().is_empty(), - "dropping LocalBridgeState must clear the timers map on teardown" - ); - assert!( - !timer_should_fire(&timers, id_c, 0), - "a pending bridge timer is suppressed after teardown" - ); - } -} diff --git a/crates/execution/src/lib.rs b/crates/execution/src/lib.rs index e06e240ca..1cd76b51c 100644 --- a/crates/execution/src/lib.rs +++ b/crates/execution/src/lib.rs @@ -1,62 +1,3 @@ -#![forbid(unsafe_code)] +//! Compatibility shim for `agentos-execution`. -//! Native execution plane scaffold for the secure-exec runtime migration. - -mod common; -mod host_node; -mod node_import_cache; -mod runtime_support; -mod signal; -pub mod v8_host; -pub mod v8_ipc; -pub mod v8_runtime; - -pub mod benchmark; -#[allow(dead_code, unused_imports)] -pub mod javascript; -pub mod python; -pub mod wasm; - -pub use javascript::{ - record_sync_bridge_request_enqueued, record_sync_bridge_request_observed, - CreateJavascriptContextRequest, GuestRuntimeConfig, JavascriptContext, JavascriptExecution, - JavascriptExecutionEngine, JavascriptExecutionError, JavascriptExecutionEvent, - JavascriptExecutionLimits, JavascriptExecutionResult, JavascriptSyncRpcRequest, - LocalModuleResolutionCache, LocalResolvedModuleFormat, ModuleFsReader, ModuleResolveMode, - ModuleResolver, StartJavascriptExecutionRequest, -}; -pub use python::{ - CreatePythonContextRequest, PythonContext, PythonExecution, PythonExecutionEngine, - PythonExecutionError, PythonExecutionEvent, PythonExecutionLimits, PythonExecutionResult, - PythonVfsRpcMethod, PythonVfsRpcRequest, PythonVfsRpcResponsePayload, PythonVfsRpcStat, - StartPythonExecutionRequest, -}; -pub use secure_exec_bridge::GuestRuntime; -pub use secure_exec_v8_runtime::execution::GuestModuleReader; -pub use signal::{NodeSignalDispositionAction, NodeSignalHandlerRegistration}; -pub use wasm::{ - CreateWasmContextRequest, NativeBinaryFormat, StartWasmExecutionRequest, WasmContext, - WasmExecution, WasmExecutionEngine, WasmExecutionError, WasmExecutionEvent, - WasmExecutionLimits, WasmExecutionResult, WasmPermissionTier, -}; - -pub trait NativeExecutionBridge: secure_exec_bridge::ExecutionBridge {} - -impl NativeExecutionBridge for T where T: secure_exec_bridge::ExecutionBridge {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct ExecutionScaffold { - pub package_name: &'static str, - pub kernel_package: &'static str, - pub target: &'static str, - pub planned_guest_runtimes: [GuestRuntime; 2], -} - -pub fn scaffold() -> ExecutionScaffold { - ExecutionScaffold { - package_name: env!("CARGO_PKG_NAME"), - kernel_package: "secure-exec-kernel", - target: "native", - planned_guest_runtimes: [GuestRuntime::JavaScript, GuestRuntime::WebAssembly], - } -} +pub use agentos_execution::*; diff --git a/crates/execution/src/node_import_cache.rs b/crates/execution/src/node_import_cache.rs deleted file mode 100644 index 434deec40..000000000 --- a/crates/execution/src/node_import_cache.rs +++ /dev/null @@ -1,11394 +0,0 @@ -use std::collections::BTreeSet; -use std::env; -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use std::sync::{Arc, Mutex, OnceLock}; -use std::time::Duration; - -pub(crate) const NODE_IMPORT_CACHE_DEBUG_ENV: &str = "AGENTOS_NODE_IMPORT_CACHE_DEBUG"; -pub(crate) const NODE_IMPORT_CACHE_METRICS_PREFIX: &str = "__AGENTOS_NODE_IMPORT_CACHE_METRICS__:"; -pub(crate) const NODE_IMPORT_CACHE_ASSET_ROOT_ENV: &str = "AGENTOS_NODE_IMPORT_CACHE_ASSET_ROOT"; - -const NODE_IMPORT_CACHE_PATH_ENV: &str = "AGENTOS_NODE_IMPORT_CACHE_PATH"; -const NODE_IMPORT_CACHE_LOADER_PATH_ENV: &str = "AGENTOS_NODE_IMPORT_CACHE_LOADER_PATH"; -const NODE_IMPORT_CACHE_SCHEMA_VERSION: &str = "1"; -const NODE_IMPORT_CACHE_LOADER_VERSION: &str = "8"; -const NODE_IMPORT_CACHE_ASSET_VERSION: &str = "85"; -const NODE_IMPORT_CACHE_DIR_PREFIX: &str = "agentos-node-import-cache"; -const DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT: Duration = Duration::from_secs(30); -const PYODIDE_DIST_DIR: &str = "pyodide-dist"; -const SECURE_EXEC_BUILTIN_SPECIFIER_PREFIX: &str = "secure-exec:builtin/"; -const SECURE_EXEC_POLYFILL_SPECIFIER_PREFIX: &str = "secure-exec:polyfill/"; -const BUNDLED_PYODIDE_MJS: &[u8] = include_bytes!("../assets/pyodide/pyodide.mjs"); -// Large Pyodide assets are excluded from the published crate and staged into -// OUT_DIR by build.rs (copied from `assets/pyodide/` in-tree, or downloaded -// from the release CDN when building the published crate). -const BUNDLED_PYODIDE_ASM_JS: &[u8] = - include_bytes!(concat!(env!("OUT_DIR"), "/pyodide/pyodide.asm.js")); -const BUNDLED_PYODIDE_ASM_WASM: &[u8] = - include_bytes!(concat!(env!("OUT_DIR"), "/pyodide/pyodide.asm.wasm")); -const BUNDLED_PYODIDE_LOCK: &[u8] = include_bytes!("../assets/pyodide/pyodide-lock.json"); -const BUNDLED_PYTHON_STDLIB_ZIP: &[u8] = - include_bytes!(concat!(env!("OUT_DIR"), "/pyodide/python_stdlib.zip")); -const BUNDLED_NUMPY_WHL: &[u8] = include_bytes!(concat!( - env!("OUT_DIR"), - "/pyodide/numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl" -)); -const BUNDLED_PANDAS_WHL: &[u8] = include_bytes!(concat!( - env!("OUT_DIR"), - "/pyodide/pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl" -)); -const BUNDLED_PYTHON_DATEUTIL_WHL: &[u8] = - include_bytes!("../assets/pyodide/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"); -const BUNDLED_PYTZ_WHL: &[u8] = - include_bytes!("../assets/pyodide/pytz-2025.2-py2.py3-none-any.whl"); -const BUNDLED_SIX_WHL: &[u8] = include_bytes!("../assets/pyodide/six-1.17.0-py2.py3-none-any.whl"); -const BUNDLED_MICROPIP_WHL: &[u8] = - include_bytes!("../assets/pyodide/micropip-0.11.0-py3-none-any.whl"); -const BUNDLED_CLICK_WHL: &[u8] = include_bytes!("../assets/pyodide/click-8.3.1-py3-none-any.whl"); -const NODE_PYTHON_RUNNER_SOURCE: &str = include_str!("../assets/runners/python-runner.mjs"); - -static CLEANED_NODE_IMPORT_CACHE_ROOTS: OnceLock>> = OnceLock::new(); -#[cfg(test)] -static NODE_IMPORT_CACHE_TEST_MATERIALIZE_DELAY_MS: AtomicU64 = AtomicU64::new(0); - -#[derive(Clone, Copy)] -struct BundledPyodidePackageAsset { - file_name: &'static str, - bytes: &'static [u8], -} - -const BUNDLED_PYODIDE_PACKAGE_ASSETS: &[BundledPyodidePackageAsset] = &[ - BundledPyodidePackageAsset { - file_name: "numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl", - bytes: BUNDLED_NUMPY_WHL, - }, - BundledPyodidePackageAsset { - file_name: "pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl", - bytes: BUNDLED_PANDAS_WHL, - }, - BundledPyodidePackageAsset { - file_name: "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", - bytes: BUNDLED_PYTHON_DATEUTIL_WHL, - }, - BundledPyodidePackageAsset { - file_name: "pytz-2025.2-py2.py3-none-any.whl", - bytes: BUNDLED_PYTZ_WHL, - }, - BundledPyodidePackageAsset { - file_name: "six-1.17.0-py2.py3-none-any.whl", - bytes: BUNDLED_SIX_WHL, - }, - BundledPyodidePackageAsset { - file_name: "micropip-0.11.0-py3-none-any.whl", - bytes: BUNDLED_MICROPIP_WHL, - }, - BundledPyodidePackageAsset { - file_name: "click-8.3.1-py3-none-any.whl", - bytes: BUNDLED_CLICK_WHL, - }, -]; -const NODE_IMPORT_CACHE_LOADER_TEMPLATE: &str = r#" -import crypto from 'node:crypto'; -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; - -const GUEST_PATH_MAPPINGS = parseGuestPathMappings(process.env.AGENTOS_GUEST_PATH_MAPPINGS); -const ALLOWED_BUILTINS = new Set(parseJsonArray(process.env.AGENTOS_ALLOWED_NODE_BUILTINS)); -const CACHE_PATH = process.env.__NODE_IMPORT_CACHE_PATH_ENV__; -const CACHE_ROOT = CACHE_PATH ? path.dirname(CACHE_PATH) : null; -const GUEST_INTERNAL_CACHE_ROOT = '/.agentos/node-import-cache'; -const HOST_CWD = process.cwd(); -const DEFAULT_GUEST_CWD = - typeof process.env.PWD === 'string' && - process.env.PWD.startsWith('/') - ? path.posix.normalize(process.env.PWD) - : typeof (globalThis.__agentOSVirtualOs||{}).homedir === 'string' && - (globalThis.__agentOSVirtualOs||{}).homedir.startsWith('/') - ? path.posix.normalize((globalThis.__agentOSVirtualOs||{}).homedir) - : '/root'; -const UNMAPPED_GUEST_PATH = '/unknown'; -const PROJECTED_SOURCE_CACHE_ROOT = CACHE_PATH - ? path.join(path.dirname(CACHE_PATH), 'projected-sources') - : null; -const ASSET_ROOT = process.env.__NODE_IMPORT_CACHE_ASSET_ROOT_ENV__; -const DEBUG_ENABLED = process.env.__NODE_IMPORT_CACHE_DEBUG_ENV__ === '1'; -const CONTROL_PIPE_FD = parseControlPipeFd(process.env.AGENTOS_CONTROL_PIPE_FD); -const SCHEMA_VERSION = '__NODE_IMPORT_CACHE_SCHEMA_VERSION__'; -const LOADER_VERSION = '__NODE_IMPORT_CACHE_LOADER_VERSION__'; -const ASSET_VERSION = '__NODE_IMPORT_CACHE_ASSET_VERSION__'; -const MAX_CACHE_RECORD_ENTRIES = 512; -const MAX_CACHE_KEY_BYTES = 4096; -const MAX_CACHE_VALUE_BYTES = 16 * 1024; -const MAX_CACHE_STATE_BYTES = 4 * 1024 * 1024; -const BUILTIN_PREFIX = '__SECURE_EXEC_BUILTIN_SPECIFIER_PREFIX__'; -const POLYFILL_PREFIX = '__SECURE_EXEC_POLYFILL_SPECIFIER_PREFIX__'; -const FS_ASSET_SPECIFIER = `${BUILTIN_PREFIX}fs`; -const FS_PROMISES_ASSET_SPECIFIER = `${BUILTIN_PREFIX}fs-promises`; -const CHILD_PROCESS_ASSET_SPECIFIER = `${BUILTIN_PREFIX}child-process`; -const NET_ASSET_SPECIFIER = `${BUILTIN_PREFIX}net`; -const DGRAM_ASSET_SPECIFIER = `${BUILTIN_PREFIX}dgram`; -const DNS_ASSET_SPECIFIER = `${BUILTIN_PREFIX}dns`; -const DNS_PROMISES_ASSET_SPECIFIER = `${BUILTIN_PREFIX}dns-promises`; -const HTTP_ASSET_SPECIFIER = `${BUILTIN_PREFIX}http`; -const HTTP2_ASSET_SPECIFIER = `${BUILTIN_PREFIX}http2`; -const HTTPS_ASSET_SPECIFIER = `${BUILTIN_PREFIX}https`; -const TLS_ASSET_SPECIFIER = `${BUILTIN_PREFIX}tls`; -const OS_ASSET_SPECIFIER = `${BUILTIN_PREFIX}os`; -const DENIED_BUILTINS = new Set([ - 'child_process', - 'cluster', - 'dgram', - 'dns', - 'dns/promises', - 'http', - 'http2', - 'https', - 'inspector', - 'module', - 'net', - 'tls', - 'trace_events', - 'v8', - 'vm', - 'worker_threads', -].filter((name) => !ALLOWED_BUILTINS.has(name))); - -let cacheState = loadCacheState(); -let dirty = false; -let cacheWriteError = null; -const metrics = { - resolveHits: 0, - resolveMisses: 0, - packageTypeHits: 0, - packageTypeMisses: 0, - moduleFormatHits: 0, - moduleFormatMisses: 0, - sourceHits: 0, - sourceMisses: 0, -}; - -export async function resolve(specifier, context, nextResolve) { - const guestResolvedPath = resolveGuestSpecifier(specifier, context); - if (guestResolvedPath) { - const guestUrl = pathToFileURL(guestResolvedPath).href; - const format = lookupModuleFormat(guestUrl); - flushCacheState(); - emitMetrics(); - return { - shortCircuit: true, - url: guestUrl, - ...(format && format !== 'builtin' ? { format } : {}), - }; - } - - const key = createResolutionKey(specifier, context); - const cached = cacheState.resolutions[key]; - - if (cached && validateResolutionEntry(cached)) { - metrics.resolveHits += 1; - const response = { - shortCircuit: true, - url: cached.resolvedUrl, - }; - - if (cached.format) { - response.format = cached.format; - } - - flushCacheState(); - emitMetrics(); - return response; - } - - metrics.resolveMisses += 1; - - const asset = resolveSecureExecAsset(specifier); - if (asset) { - cacheState.resolutions[key] = { - kind: 'explicit-file', - resolvedUrl: asset.url, - format: 'module', - resolvedFilePath: asset.filePath, - }; - dirty = true; - flushCacheState(); - emitMetrics(); - return { - shortCircuit: true, - url: asset.url, - format: 'module', - }; - } - - const builtinAsset = resolveBuiltinAsset(specifier, context); - if (builtinAsset) { - cacheState.resolutions[key] = { - kind: 'explicit-file', - resolvedUrl: builtinAsset.url, - format: 'module', - resolvedFilePath: builtinAsset.filePath, - }; - dirty = true; - flushCacheState(); - emitMetrics(); - return { - shortCircuit: true, - url: builtinAsset.url, - format: 'module', - }; - } - - const deniedBuiltin = resolveDeniedBuiltin(specifier); - if (deniedBuiltin) { - cacheState.resolutions[key] = { - kind: 'explicit-file', - resolvedUrl: deniedBuiltin.url, - format: 'module', - resolvedFilePath: deniedBuiltin.filePath, - }; - dirty = true; - flushCacheState(); - emitMetrics(); - return { - shortCircuit: true, - url: deniedBuiltin.url, - format: 'module', - }; - } - - const translatedContext = translateContextParentUrl(context); - let resolved; - try { - resolved = await nextResolve(specifier, translatedContext); - } catch (error) { - flushCacheState(); - emitMetrics(); - throw translateErrorToGuest(error); - } - const translatedUrl = translateResolvedUrlToGuest(resolved.url); - const translatedResolved = - translatedUrl === resolved.url ? resolved : { ...resolved, url: translatedUrl }; - const entry = buildResolutionEntry(specifier, context, translatedResolved); - if (entry) { - cacheState.resolutions[key] = entry; - dirty = true; - } - - if (entry && entry.format && resolved.format == null) { - flushCacheState(); - emitMetrics(); - return { - ...translatedResolved, - format: entry.format, - }; - } - - flushCacheState(); - emitMetrics(); - return translatedResolved; -} - -export async function load(url, context, nextLoad) { - try { - const filePath = filePathFromUrl(url); - const format = lookupModuleFormat(url) ?? context.format; - - if (!filePath || !format || format === 'builtin') { - return await nextLoad(url, context); - } - - const projectedPackageSource = loadProjectedPackageSource(url, filePath, format); - if (projectedPackageSource != null) { - flushCacheState(); - emitMetrics(); - return { - shortCircuit: true, - format, - source: projectedPackageSource, - }; - } - - const source = - format === 'wasm' - ? fs.readFileSync(filePath) - : rewriteBuiltinImports(fs.readFileSync(filePath, 'utf8'), filePath); - - return { - shortCircuit: true, - format, - source, - }; - } catch (error) { - flushCacheState(); - emitMetrics(); - throw translateErrorToGuest(error); - } -} - -function loadCacheState() { - if (!CACHE_PATH) { - return emptyCacheState(); - } - - try { - const stat = fs.statSync(CACHE_PATH); - if (!stat.isFile() || stat.size > MAX_CACHE_STATE_BYTES) { - return emptyCacheState(); - } - const parsed = JSON.parse(fs.readFileSync(CACHE_PATH, 'utf8')); - if (!isCompatibleCacheState(parsed)) { - return emptyCacheState(); - } - - return normalizeCacheState(parsed); - } catch { - return emptyCacheState(); - } -} - -function flushCacheState() { - if (!CACHE_PATH || !dirty) { - return; - } - - try { - fs.mkdirSync(path.dirname(CACHE_PATH), { recursive: true }); - - let merged = cacheState; - try { - const existingStat = fs.statSync(CACHE_PATH); - if (existingStat.isFile() && existingStat.size <= MAX_CACHE_STATE_BYTES) { - const existing = JSON.parse(fs.readFileSync(CACHE_PATH, 'utf8')); - if (isCompatibleCacheState(existing)) { - merged = mergeCacheStates(normalizeCacheState(existing), cacheState); - } - } - } catch { - // Ignore missing or unreadable prior state and replace it with the in-memory view. - } - - merged = pruneCacheState(merged); - let serialized = JSON.stringify(merged); - if (byteLengthUtf8(serialized) > MAX_CACHE_STATE_BYTES) { - merged = pruneCacheState(merged, Math.floor(MAX_CACHE_RECORD_ENTRIES / 4)); - serialized = JSON.stringify(merged); - } - if (byteLengthUtf8(serialized) > MAX_CACHE_STATE_BYTES) { - merged = emptyCacheState(); - serialized = JSON.stringify(merged); - } - - const tempPath = `${CACHE_PATH}.${process.pid}.${Date.now()}.tmp`; - fs.writeFileSync(tempPath, serialized); - fs.renameSync(tempPath, CACHE_PATH); - cacheState = merged; - pruneProjectedSourceFiles(); - dirty = false; - } catch (error) { - cacheWriteError = error instanceof Error ? error.message : String(error); - } -} - -function emitMetrics() { - if (!DEBUG_ENABLED) { - return; - } - - const payload = cacheWriteError - ? { ...metrics, cacheWriteError } - : metrics; - - emitControlMessage({ type: 'node_import_cache_metrics', metrics: payload }); -} - -function parseControlPipeFd(value) { - if (typeof value !== 'string' || value.trim() === '') { - return null; - } - - const parsed = Number.parseInt(value, 10); - return Number.isInteger(parsed) && parsed >= 3 ? parsed : null; -} - -function emitControlMessage(message) { - if (CONTROL_PIPE_FD == null) { - if ( - message?.type === 'signal_state' && - typeof process?.stdout?.write === 'function' - ) { - try { - process.stdout.write(`__AGENTOS_WASM_SIGNAL_STATE__:${JSON.stringify(message)}\n`); - } catch { - // Ignore control-channel fallback failures during teardown. - } - } - return; - } - - try { - fs.writeSync(CONTROL_PIPE_FD, `${JSON.stringify(message)}\n`); - } catch { - if ( - message?.type === 'signal_state' && - typeof process?.stdout?.write === 'function' - ) { - try { - process.stdout.write(`__AGENTOS_WASM_SIGNAL_STATE__:${JSON.stringify(message)}\n`); - } catch { - // Ignore control-channel fallback failures during teardown. - } - } - } -} - -function emptyCacheState() { - return { - schemaVersion: SCHEMA_VERSION, - loaderVersion: LOADER_VERSION, - assetVersion: ASSET_VERSION, - nodeVersion: process.version, - resolutions: {}, - packageTypes: {}, - moduleFormats: {}, - projectedSources: {}, - }; -} - -function isCompatibleCacheState(value) { - return ( - isRecord(value) && - value.schemaVersion === SCHEMA_VERSION && - value.loaderVersion === LOADER_VERSION && - value.assetVersion === ASSET_VERSION && - value.nodeVersion === process.version - ); -} - -function normalizeCacheState(value) { - return pruneCacheState({ - ...emptyCacheState(), - ...value, - resolutions: isRecord(value.resolutions) ? value.resolutions : {}, - packageTypes: isRecord(value.packageTypes) ? value.packageTypes : {}, - moduleFormats: isRecord(value.moduleFormats) ? value.moduleFormats : {}, - projectedSources: isRecord(value.projectedSources) ? value.projectedSources : {}, - }); -} - -function mergeCacheStates(base, current) { - return pruneCacheState({ - ...emptyCacheState(), - resolutions: { - ...base.resolutions, - ...current.resolutions, - }, - packageTypes: { - ...base.packageTypes, - ...current.packageTypes, - }, - moduleFormats: { - ...base.moduleFormats, - ...current.moduleFormats, - }, - projectedSources: { - ...base.projectedSources, - ...current.projectedSources, - }, - }); -} - -function pruneCacheState(state, maxEntries = MAX_CACHE_RECORD_ENTRIES) { - return { - ...emptyCacheState(), - ...state, - resolutions: pruneCacheRecord(state.resolutions, maxEntries), - packageTypes: pruneCacheRecord(state.packageTypes, maxEntries), - moduleFormats: pruneCacheRecord(state.moduleFormats, maxEntries), - projectedSources: pruneCacheRecord(state.projectedSources, maxEntries), - }; -} - -function pruneCacheRecord(record, maxEntries) { - if (!isRecord(record)) { - return {}; - } - - const entries = []; - for (const [key, value] of Object.entries(record)) { - if ( - byteLengthUtf8(key) <= MAX_CACHE_KEY_BYTES && - cacheValueLength(value) <= MAX_CACHE_VALUE_BYTES - ) { - entries.push([key, value]); - } - } - - return Object.fromEntries(entries.slice(-maxEntries)); -} - -function cacheValueLength(value) { - try { - return byteLengthUtf8(JSON.stringify(value)); - } catch { - return MAX_CACHE_VALUE_BYTES + 1; - } -} - -function byteLengthUtf8(value) { - return Buffer.byteLength(String(value), 'utf8'); -} - -function pruneProjectedSourceFiles() { - if (!PROJECTED_SOURCE_CACHE_ROOT) { - return; - } - - const retained = new Set(); - for (const entry of Object.values(cacheState.projectedSources)) { - if ( - isRecord(entry) && - typeof entry.cachedPath === 'string' && - path.dirname(entry.cachedPath) === PROJECTED_SOURCE_CACHE_ROOT - ) { - retained.add(path.resolve(entry.cachedPath)); - } - } - - let entries; - try { - entries = fs.readdirSync(PROJECTED_SOURCE_CACHE_ROOT, { withFileTypes: true }); - } catch { - return; - } - - for (const entry of entries) { - if (!entry.isFile()) { - continue; - } - const filePath = path.resolve(PROJECTED_SOURCE_CACHE_ROOT, entry.name); - if (!retained.has(filePath)) { - try { - fs.unlinkSync(filePath); - } catch { - // Best-effort cleanup. A failed unlink should not break module loading. - } - } - } -} - -function loadProjectedPackageSource(url, filePath, format) { - if ( - format === 'wasm' || - !isProjectedPackageSource(filePath) || - !PROJECTED_SOURCE_CACHE_ROOT - ) { - return null; - } - - const cached = cacheState.projectedSources[url]; - if (cached && validateProjectedSourceEntry(cached, filePath, format)) { - metrics.sourceHits += 1; - return fs.readFileSync(cached.cachedPath, 'utf8'); - } - - metrics.sourceMisses += 1; - - const stat = statForPath(filePath); - if (!stat) { - return null; - } - - const source = rewriteBuiltinImports(fs.readFileSync(filePath, 'utf8'), filePath); - const cacheKey = hashString( - JSON.stringify({ - url, - format, - size: stat.size, - mtimeMs: stat.mtimeMs, - }), - ); - const extension = path.extname(filePath) || '.js'; - const cachedPath = path.join( - PROJECTED_SOURCE_CACHE_ROOT, - `${cacheKey}${extension}.cached`, - ); - fs.mkdirSync(path.dirname(cachedPath), { recursive: true }); - fs.writeFileSync(cachedPath, source); - - cacheState.projectedSources[url] = { - kind: 'text', - filePath, - format, - cachedPath, - size: stat.size, - mtimeMs: stat.mtimeMs, - }; - dirty = true; - return source; -} - -function resolveSecureExecAsset(specifier) { - if (typeof specifier !== 'string' || !ASSET_ROOT) { - return null; - } - - if (specifier.startsWith(BUILTIN_PREFIX)) { - return assetModuleDescriptor( - path.join( - ASSET_ROOT, - 'builtins', - `${sanitizeAssetName(specifier.slice(BUILTIN_PREFIX.length))}.mjs`, - ), - ); - } - - if (specifier.startsWith(POLYFILL_PREFIX)) { - return assetModuleDescriptor( - path.join( - ASSET_ROOT, - 'polyfills', - `${sanitizeAssetName(specifier.slice(POLYFILL_PREFIX.length))}.mjs`, - ), - ); - } - - return null; -} - -function rewriteBuiltinImports(source, filePath) { - if (typeof source !== 'string' || isAssetPath(filePath)) { - return source; - } - - let rewritten = source; - - for (const specifier of ['node:fs/promises', 'fs/promises']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - FS_PROMISES_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - FS_PROMISES_ASSET_SPECIFIER, - ); - } - - for (const specifier of ['node:fs', 'fs']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - FS_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - FS_ASSET_SPECIFIER, - ); - } - - if (ALLOWED_BUILTINS.has('child_process')) { - for (const specifier of ['node:child_process', 'child_process']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - CHILD_PROCESS_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - CHILD_PROCESS_ASSET_SPECIFIER, - ); - } - } - - if (ALLOWED_BUILTINS.has('net')) { - for (const specifier of ['node:net', 'net']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - NET_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - NET_ASSET_SPECIFIER, - ); - } - } - - if (ALLOWED_BUILTINS.has('dgram')) { - for (const specifier of ['node:dgram', 'dgram']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - DGRAM_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - DGRAM_ASSET_SPECIFIER, - ); - } - } - - if (ALLOWED_BUILTINS.has('dns')) { - for (const specifier of ['node:dns/promises', 'dns/promises']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - DNS_PROMISES_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - DNS_PROMISES_ASSET_SPECIFIER, - ); - } - for (const specifier of ['node:dns', 'dns']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - DNS_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - DNS_ASSET_SPECIFIER, - ); - } - } - - if (ALLOWED_BUILTINS.has('http')) { - for (const specifier of ['node:http', 'http']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - HTTP_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - HTTP_ASSET_SPECIFIER, - ); - } - } - - if (ALLOWED_BUILTINS.has('http2')) { - for (const specifier of ['node:http2', 'http2']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - HTTP2_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - HTTP2_ASSET_SPECIFIER, - ); - } - } - - if (ALLOWED_BUILTINS.has('https')) { - for (const specifier of ['node:https', 'https']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - HTTPS_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - HTTPS_ASSET_SPECIFIER, - ); - } - } - - if (ALLOWED_BUILTINS.has('tls')) { - for (const specifier of ['node:tls', 'tls']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - TLS_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - TLS_ASSET_SPECIFIER, - ); - } - } - - if (ALLOWED_BUILTINS.has('os')) { - for (const specifier of ['node:os', 'os']) { - rewritten = replaceBuiltinImportSpecifier( - rewritten, - specifier, - OS_ASSET_SPECIFIER, - ); - rewritten = replaceBuiltinDynamicImportSpecifier( - rewritten, - specifier, - OS_ASSET_SPECIFIER, - ); - } - } - - return rewritten; -} - -function replaceBuiltinImportSpecifier(source, specifier, replacement) { - const pattern = new RegExp( - `(\\bfrom\\s*)(['"])${escapeRegExp(specifier)}\\2`, - 'g', - ); - return source.replace(pattern, `$1$2${replacement}$2`); -} - -function replaceBuiltinDynamicImportSpecifier(source, specifier, replacement) { - const pattern = new RegExp( - `(\\bimport\\s*\\(\\s*)(['"])${escapeRegExp(specifier)}\\2(\\s*\\))`, - 'g', - ); - return source.replace(pattern, `$1$2${replacement}$2$3`); -} - -function isAssetPath(filePath) { - return ( - typeof filePath === 'string' && - typeof ASSET_ROOT === 'string' && - (filePath === ASSET_ROOT || filePath.startsWith(`${ASSET_ROOT}${path.sep}`)) - ); -} - -function resolveDeniedBuiltin(specifier) { - if (typeof specifier !== 'string' || !ASSET_ROOT) { - return null; - } - - const normalized = - specifier.startsWith('node:') ? specifier.slice('node:'.length) : specifier; - if (!DENIED_BUILTINS.has(normalized)) { - return null; - } - - return assetModuleDescriptor( - path.join(ASSET_ROOT, 'denied', `${sanitizeAssetName(normalized)}.mjs`), - ); -} - -function resolveBuiltinAsset(specifier, context) { - if ( - typeof specifier !== 'string' || - !ASSET_ROOT || - !specifier.startsWith('node:') - ) { - return null; - } - - if ( - typeof context?.parentURL === 'string' && - (context.parentURL.startsWith(BUILTIN_PREFIX) || - context.parentURL.startsWith(POLYFILL_PREFIX)) - ) { - return null; - } - - const parentPath = filePathFromUrl(context?.parentURL); - if (parentPath && isAssetPath(parentPath)) { - return null; - } - - const normalized = specifier.slice('node:'.length); - switch (normalized) { - case 'fs': - return assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'fs.mjs')); - case 'fs/promises': - return assetModuleDescriptor( - path.join(ASSET_ROOT, 'builtins', 'fs-promises.mjs'), - ); - case 'async_hooks': - return assetModuleDescriptor( - path.join(ASSET_ROOT, 'builtins', 'async-hooks.mjs'), - ); - case 'child_process': - return ALLOWED_BUILTINS.has('child_process') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'child-process.mjs')) - : null; - case 'diagnostics_channel': - return assetModuleDescriptor( - path.join(ASSET_ROOT, 'builtins', 'diagnostics-channel.mjs'), - ); - case 'net': - return ALLOWED_BUILTINS.has('net') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'net.mjs')) - : null; - case 'dgram': - return ALLOWED_BUILTINS.has('dgram') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'dgram.mjs')) - : null; - case 'dns': - return ALLOWED_BUILTINS.has('dns') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'dns.mjs')) - : null; - case 'dns/promises': - return ALLOWED_BUILTINS.has('dns') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'dns-promises.mjs')) - : null; - case 'http': - return ALLOWED_BUILTINS.has('http') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'http.mjs')) - : null; - case 'http2': - return ALLOWED_BUILTINS.has('http2') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'http2.mjs')) - : null; - case 'https': - return ALLOWED_BUILTINS.has('https') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'https.mjs')) - : null; - case 'tls': - return ALLOWED_BUILTINS.has('tls') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'tls.mjs')) - : null; - case 'os': - return ALLOWED_BUILTINS.has('os') - ? assetModuleDescriptor(path.join(ASSET_ROOT, 'builtins', 'os.mjs')) - : null; - default: - return null; - } -} - -function assetModuleDescriptor(filePath) { - if (!statForPath(filePath)) { - return null; - } - - return { - filePath, - url: pathToFileURL(filePath).href, - }; -} - -function sanitizeAssetName(name) { - return String(name).replace(/[^A-Za-z0-9_.-]+/g, '-'); -} - -function escapeRegExp(value) { - return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); -} - -function buildResolutionEntry(specifier, context, resolved) { - const format = lookupModuleFormat(resolved.url) ?? resolved.format; - - if (resolved.url.startsWith('node:')) { - return { - kind: 'builtin', - resolvedUrl: resolved.url, - format, - }; - } - - if (isBareSpecifier(specifier)) { - const packageName = barePackageName(specifier); - if (!packageName) { - return null; - } - - const candidatePackageJsonPaths = barePackageJsonCandidates( - context.parentURL, - packageName, - ); - const selectedPackageJsonPath = firstExistingPath(candidatePackageJsonPaths); - return { - kind: 'bare', - resolvedUrl: resolved.url, - format, - candidatePackageJsonPaths, - selectedPackageJsonPath, - selectedPackageJsonFingerprint: selectedPackageJsonPath - ? fileFingerprint(selectedPackageJsonPath) - : null, - }; - } - - if (isExplicitFileLikeSpecifier(specifier)) { - return { - kind: 'explicit-file', - resolvedUrl: resolved.url, - format, - resolvedFilePath: filePathFromUrl(resolved.url), - }; - } - - return null; -} - -function isProjectedPackageSource(filePath) { - if (typeof filePath !== 'string' || isAssetPath(filePath)) { - return false; - } - - const guestPath = guestPathFromHostPath(filePath); - return typeof guestPath === 'string' && guestPath.includes('/node_modules/'); -} - -function validateResolutionEntry(entry) { - if (!isRecord(entry) || typeof entry.kind !== 'string') { - return false; - } - - switch (entry.kind) { - case 'builtin': - return true; - case 'bare': { - if (!Array.isArray(entry.candidatePackageJsonPaths)) { - return false; - } - - const currentPackageJsonPath = firstExistingPath( - entry.candidatePackageJsonPaths, - ); - if (currentPackageJsonPath !== entry.selectedPackageJsonPath) { - return false; - } - - if ( - currentPackageJsonPath && - !fingerprintMatches( - currentPackageJsonPath, - entry.selectedPackageJsonFingerprint, - ) - ) { - return false; - } - - return formatMatches(entry.resolvedUrl, entry.format); - } - case 'explicit-file': - if ( - typeof entry.resolvedFilePath !== 'string' || - !fs.existsSync(entry.resolvedFilePath) - ) { - return false; - } - - return formatMatches(entry.resolvedUrl, entry.format); - default: - return false; - } -} - -function formatMatches(url, expectedFormat) { - if (expectedFormat == null) { - return true; - } - - return lookupModuleFormat(url) === expectedFormat; -} - -function lookupModuleFormat(url) { - const cached = cacheState.moduleFormats[url]; - if (cached && validateModuleFormatEntry(cached)) { - metrics.moduleFormatHits += 1; - return cached.format; - } - - metrics.moduleFormatMisses += 1; - const entry = buildModuleFormatEntry(url); - if (!entry) { - return null; - } - - cacheState.moduleFormats[url] = entry; - dirty = true; - return entry.format; -} - -function buildModuleFormatEntry(url) { - if (url.startsWith('node:')) { - return { - kind: 'builtin', - url, - format: 'builtin', - }; - } - - const filePath = filePathFromUrl(url); - if (!filePath) { - return null; - } - - const stat = statForPath(filePath); - if (!stat) { - return null; - } - - const extension = path.extname(filePath); - if (extension === '.mjs') { - return createFileFormatEntry(url, filePath, stat, 'module', false); - } - if (extension === '.cjs') { - return createFileFormatEntry(url, filePath, stat, 'commonjs', false); - } - if (extension === '.json') { - return createFileFormatEntry(url, filePath, stat, 'json', false); - } - if (extension === '.wasm') { - return createFileFormatEntry(url, filePath, stat, 'wasm', false); - } - if (extension === '.js' || extension === '') { - const packageType = lookupPackageType(filePath); - return createFileFormatEntry( - url, - filePath, - stat, - packageType === 'module' ? 'module' : 'commonjs', - true, - ); - } - - return null; -} - -function createFileFormatEntry(url, filePath, stat, format, usesPackageType) { - return { - kind: 'file', - url, - filePath, - format, - usesPackageType, - size: stat.size, - mtimeMs: stat.mtimeMs, - }; -} - -function validateModuleFormatEntry(entry) { - if (!isRecord(entry) || typeof entry.kind !== 'string') { - return false; - } - - if (entry.kind === 'builtin') { - return true; - } - - if (entry.kind !== 'file' || typeof entry.filePath !== 'string') { - return false; - } - - const stat = statForPath(entry.filePath); - if (!stat || stat.size !== entry.size || stat.mtimeMs !== entry.mtimeMs) { - return false; - } - - if (entry.usesPackageType) { - const packageType = lookupPackageType(entry.filePath); - const expectedFormat = packageType === 'module' ? 'module' : 'commonjs'; - return entry.format === expectedFormat; - } - - return true; -} - -function validateProjectedSourceEntry(entry, filePath, format) { - if ( - !isRecord(entry) || - entry.kind !== 'text' || - typeof entry.filePath !== 'string' || - typeof entry.cachedPath !== 'string' || - typeof entry.format !== 'string' - ) { - return false; - } - - if (entry.filePath !== filePath || entry.format !== format) { - return false; - } - - const stat = statForPath(filePath); - if (!stat || stat.size !== entry.size || stat.mtimeMs !== entry.mtimeMs) { - return false; - } - - return statForPath(entry.cachedPath)?.isFile() ?? false; -} - -function lookupPackageType(filePath) { - let directory = path.dirname(filePath); - - while (true) { - const packageJsonPath = path.join(directory, 'package.json'); - const cached = cacheState.packageTypes[packageJsonPath]; - if (cached && validatePackageTypeEntry(cached)) { - metrics.packageTypeHits += 1; - if (cached.kind === 'present') { - return cached.packageType; - } - } else { - metrics.packageTypeMisses += 1; - const entry = buildPackageTypeEntry(packageJsonPath); - cacheState.packageTypes[packageJsonPath] = entry; - dirty = true; - if (entry.kind === 'present') { - return entry.packageType; - } - } - - const parent = path.dirname(directory); - if (parent === directory) { - break; - } - directory = parent; - } - - return 'commonjs'; -} - -function buildPackageTypeEntry(packageJsonPath) { - const stat = statForPath(packageJsonPath); - if (!stat) { - return { - kind: 'missing', - packageJsonPath, - }; - } - - const contents = fs.readFileSync(packageJsonPath, 'utf8'); - let packageType = 'commonjs'; - try { - const parsed = JSON.parse(contents); - if (parsed && parsed.type === 'module') { - packageType = 'module'; - } - } catch { - packageType = 'commonjs'; - } - - return { - kind: 'present', - packageJsonPath, - packageType, - size: stat.size, - mtimeMs: stat.mtimeMs, - hash: hashString(contents), - }; -} - -function validatePackageTypeEntry(entry) { - if (!isRecord(entry) || typeof entry.kind !== 'string') { - return false; - } - - if (entry.kind === 'missing') { - return statForPath(entry.packageJsonPath) == null; - } - - if (entry.kind !== 'present') { - return false; - } - - const stat = statForPath(entry.packageJsonPath); - if (!stat) { - return false; - } - - if (stat.size !== entry.size || stat.mtimeMs !== entry.mtimeMs) { - return false; - } - - const contents = fs.readFileSync(entry.packageJsonPath, 'utf8'); - return hashString(contents) === entry.hash; -} - -function fileFingerprint(filePath) { - const stat = statForPath(filePath); - if (!stat) { - return null; - } - - const contents = fs.readFileSync(filePath, 'utf8'); - return { - size: stat.size, - mtimeMs: stat.mtimeMs, - hash: hashString(contents), - }; -} - -function fingerprintMatches(filePath, expectedFingerprint) { - if (!isRecord(expectedFingerprint)) { - return false; - } - - const stat = statForPath(filePath); - if (!stat) { - return false; - } - - if ( - stat.size !== expectedFingerprint.size || - stat.mtimeMs !== expectedFingerprint.mtimeMs - ) { - return false; - } - - const contents = fs.readFileSync(filePath, 'utf8'); - return hashString(contents) === expectedFingerprint.hash; -} - -function barePackageJsonCandidates(parentURL, packageName) { - const parentPath = filePathFromUrl(parentURL); - if (!parentPath) { - return []; - } - - let directory = path.dirname(parentPath); - const candidates = []; - - while (true) { - candidates.push(path.join(directory, 'node_modules', packageName, 'package.json')); - const parent = path.dirname(directory); - if (parent === directory) { - break; - } - directory = parent; - } - - return candidates; -} - -function firstExistingPath(paths) { - for (const candidate of paths) { - if (statForPath(candidate)) { - return candidate; - } - } - - return null; -} - -function statForPath(filePath) { - try { - return fs.statSync(filePath); - } catch { - return null; - } -} - -function createResolutionKey(specifier, context) { - return JSON.stringify({ - specifier, - parentURL: context.parentURL ?? null, - conditions: Array.isArray(context.conditions) - ? [...context.conditions].sort() - : [], - importAttributes: sortObject(context.importAttributes ?? {}), - }); -} - -function sortObject(value) { - if (Array.isArray(value)) { - return value.map((item) => sortObject(item)); - } - - if (isRecord(value)) { - return Object.fromEntries( - Object.keys(value) - .sort() - .map((key) => [key, sortObject(value[key])]), - ); - } - - return value; -} - -function isExplicitFileLikeSpecifier(specifier) { - if (typeof specifier !== 'string') { - return false; - } - - if (specifier.startsWith('file:')) { - const filePath = filePathFromUrl(specifier); - return Boolean(filePath && path.extname(filePath)); - } - - if ( - specifier.startsWith('./') || - specifier.startsWith('../') || - specifier.startsWith('/') - ) { - return Boolean(path.extname(specifier)); - } - - return false; -} - -function isBareSpecifier(specifier) { - if (typeof specifier !== 'string') { - return false; - } - - if ( - specifier.startsWith('./') || - specifier.startsWith('../') || - specifier.startsWith('/') || - specifier.startsWith('file:') || - specifier.startsWith('node:') - ) { - return false; - } - - return !/^[A-Za-z][A-Za-z0-9+.-]*:/.test(specifier); -} - -function barePackageName(specifier) { - if (!isBareSpecifier(specifier)) { - return null; - } - - const parts = specifier.split('/'); - if (specifier.startsWith('@')) { - return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null; - } - - return parts[0] ?? null; -} - -function resolveGuestSpecifier(specifier, context) { - if (typeof specifier !== 'string') { - return null; - } - - if (specifier.startsWith('file:')) { - const filePath = guestFilePathFromUrl(specifier); - if (!filePath) { - return null; - } - if (isInternalImportCachePath(filePath)) { - return null; - } - if (pathExists(filePath) && !guestPathFromHostPath(filePath)) { - return null; - } - return filePath; - } - - if (specifier.startsWith('/')) { - if (isInternalImportCachePath(specifier)) { - return null; - } - if (pathExists(specifier)) { - return null; - } - return path.posix.normalize(specifier); - } - - if (!specifier.startsWith('./') && !specifier.startsWith('../')) { - return null; - } - - const parentPath = guestFilePathFromUrl(context.parentURL); - if (!parentPath) { - return null; - } - - return path.posix.normalize( - path.posix.join(path.posix.dirname(parentPath), specifier), - ); -} - -function translateContextParentUrl(context) { - if (!context || typeof context.parentURL !== 'string') { - return context; - } - - const hostParentUrl = translateResolvedUrlToHost(context.parentURL); - const hostParentPath = guestFilePathFromUrl(hostParentUrl); - const realParentPath = - hostParentPath && pathExists(hostParentPath) ? safeRealpath(hostParentPath) : null; - const normalizedParentUrl = realParentPath - ? pathToFileURL(realParentPath).href - : hostParentUrl; - - if (normalizedParentUrl === context.parentURL) { - return context; - } - - return { - ...context, - parentURL: normalizedParentUrl, - }; -} - -function translateResolvedUrlToGuest(url) { - const hostPath = guestFilePathFromUrl(url); - if (!hostPath) { - return url; - } - - return pathToFileURL(guestVisiblePathFromHostPath(hostPath)).href; -} - -function translateResolvedUrlToHost(url) { - const guestPath = guestFilePathFromUrl(url); - if (!guestPath) { - return url; - } - - if (pathExists(guestPath) && !guestPathFromHostPath(guestPath)) { - return url; - } - - const hostPath = hostPathFromGuestPath(guestPath); - return hostPath ? pathToFileURL(hostPath).href : url; -} - -function filePathFromUrl(url) { - const guestPath = guestFilePathFromUrl(url); - if (!guestPath) { - return null; - } - - if (pathExists(guestPath)) { - return guestPath; - } - - return hostPathFromGuestPath(guestPath) ?? guestPath; -} - -function guestFilePathFromUrl(url) { - if (typeof url !== 'string' || !url.startsWith('file:')) { - return null; - } - - try { - return fileURLToPath(url); - } catch { - return null; - } -} - -function hostPathFromGuestPath(guestPath) { - if (typeof guestPath !== 'string') { - return null; - } - - const normalized = path.posix.normalize(guestPath); - if ( - CACHE_ROOT && - (normalized === GUEST_INTERNAL_CACHE_ROOT || - normalized.startsWith(`${GUEST_INTERNAL_CACHE_ROOT}/`)) - ) { - const suffix = - normalized === GUEST_INTERNAL_CACHE_ROOT - ? '' - : normalized.slice(GUEST_INTERNAL_CACHE_ROOT.length + 1); - return suffix ? path.join(CACHE_ROOT, ...suffix.split('/')) : CACHE_ROOT; - } - - for (const mapping of GUEST_PATH_MAPPINGS) { - if (mapping.guestPath === '/') { - const suffix = normalized.replace(/^\/+/, ''); - return suffix ? path.join(mapping.hostPath, suffix) : mapping.hostPath; - } - - if ( - normalized !== mapping.guestPath && - !normalized.startsWith(`${mapping.guestPath}/`) - ) { - continue; - } - - const suffix = - normalized === mapping.guestPath - ? '' - : normalized.slice(mapping.guestPath.length + 1); - return suffix ? path.join(mapping.hostPath, suffix) : mapping.hostPath; - } - - if ( - normalized === DEFAULT_GUEST_CWD || - normalized.startsWith(`${DEFAULT_GUEST_CWD}/`) - ) { - const suffix = - normalized === DEFAULT_GUEST_CWD - ? '' - : normalized.slice(DEFAULT_GUEST_CWD.length + 1); - return suffix ? path.join(HOST_CWD, ...suffix.split('/')) : HOST_CWD; - } - - return null; -} - -function guestPathFromHostPath(hostPath) { - if (typeof hostPath !== 'string') { - return null; - } - - const normalized = path.resolve(hostPath); - if (isInternalImportCachePath(normalized)) { - return null; - } - for (const mapping of GUEST_PATH_MAPPINGS) { - const hostRoot = path.resolve(mapping.hostPath); - if ( - normalized !== hostRoot && - !normalized.startsWith(`${hostRoot}${path.sep}`) - ) { - continue; - } - - const suffix = - normalized === hostRoot - ? '' - : normalized.slice(hostRoot.length + path.sep.length); - return suffix - ? path.posix.join(mapping.guestPath, suffix.split(path.sep).join('/')) - : mapping.guestPath; - } - - return null; -} - -function guestCwdPathFromHostPath(hostPath) { - if (typeof hostPath !== 'string') { - return null; - } - - const normalized = path.resolve(hostPath); - const hostRoot = path.resolve(HOST_CWD); - if ( - normalized !== hostRoot && - !normalized.startsWith(`${hostRoot}${path.sep}`) - ) { - return null; - } - - const suffix = - normalized === hostRoot - ? '' - : normalized.slice(hostRoot.length + path.sep.length); - return suffix - ? path.posix.join(DEFAULT_GUEST_CWD, suffix.split(path.sep).join('/')) - : DEFAULT_GUEST_CWD; -} - -function guestInternalPathFromHostPath(hostPath) { - if (typeof hostPath !== 'string' || !CACHE_ROOT) { - return null; - } - - const normalized = path.resolve(hostPath); - const hostRoot = path.resolve(CACHE_ROOT); - if ( - normalized !== hostRoot && - !normalized.startsWith(`${hostRoot}${path.sep}`) - ) { - return null; - } - - const suffix = - normalized === hostRoot - ? '' - : normalized.slice(hostRoot.length + path.sep.length); - return suffix - ? path.posix.join(GUEST_INTERNAL_CACHE_ROOT, suffix.split(path.sep).join('/')) - : GUEST_INTERNAL_CACHE_ROOT; -} - -function guestVisiblePathFromHostPath(hostPath) { - return ( - guestPathFromHostPath(hostPath) ?? - guestInternalPathFromHostPath(hostPath) ?? - guestCwdPathFromHostPath(hostPath) ?? - UNMAPPED_GUEST_PATH - ); -} - -function isGuestVisiblePath(value) { - if (typeof value !== 'string' || !path.posix.isAbsolute(value)) { - return false; - } - - const normalized = path.posix.normalize(value); - return ( - normalized === UNMAPPED_GUEST_PATH || - normalized === GUEST_INTERNAL_CACHE_ROOT || - normalized.startsWith(`${GUEST_INTERNAL_CACHE_ROOT}/`) || - normalized === DEFAULT_GUEST_CWD || - normalized.startsWith(`${DEFAULT_GUEST_CWD}/`) || - hostPathFromGuestPath(normalized) != null - ); -} - -function translatePathStringToGuest(value) { - if (typeof value !== 'string') { - return value; - } - - if (value.startsWith('file:')) { - const hostPath = guestFilePathFromUrl(value); - if (!hostPath) { - return value; - } - - const guestPath = isGuestVisiblePath(hostPath) - ? path.posix.normalize(hostPath) - : guestVisiblePathFromHostPath(hostPath); - return pathToFileURL(guestPath).href; - } - - if (!path.isAbsolute(value)) { - return value; - } - - return isGuestVisiblePath(value) - ? path.posix.normalize(value) - : guestVisiblePathFromHostPath(value); -} - -function buildHostToGuestTextReplacements() { - const replacements = new Map(); - const addReplacement = (hostValue, guestValue) => { - if ( - typeof hostValue !== 'string' || - hostValue.length === 0 || - typeof guestValue !== 'string' || - guestValue.length === 0 - ) { - return; - } - - replacements.set(hostValue, guestValue); - }; - - for (const mapping of GUEST_PATH_MAPPINGS) { - const hostRoot = path.resolve(mapping.hostPath); - addReplacement(hostRoot, mapping.guestPath); - addReplacement(pathToFileURL(hostRoot).href, pathToFileURL(mapping.guestPath).href); - const forwardSlashHostRoot = hostRoot.split(path.sep).join('/'); - if (forwardSlashHostRoot !== hostRoot) { - addReplacement(forwardSlashHostRoot, mapping.guestPath); - } - } - - if (CACHE_ROOT) { - const hostRoot = path.resolve(CACHE_ROOT); - addReplacement(hostRoot, GUEST_INTERNAL_CACHE_ROOT); - addReplacement( - pathToFileURL(hostRoot).href, - pathToFileURL(GUEST_INTERNAL_CACHE_ROOT).href, - ); - const forwardSlashHostRoot = hostRoot.split(path.sep).join('/'); - if (forwardSlashHostRoot !== hostRoot) { - addReplacement(forwardSlashHostRoot, GUEST_INTERNAL_CACHE_ROOT); - } - } - - if (!guestPathFromHostPath(HOST_CWD)) { - const hostRoot = path.resolve(HOST_CWD); - addReplacement(hostRoot, DEFAULT_GUEST_CWD); - addReplacement(pathToFileURL(hostRoot).href, pathToFileURL(DEFAULT_GUEST_CWD).href); - const forwardSlashHostRoot = hostRoot.split(path.sep).join('/'); - if (forwardSlashHostRoot !== hostRoot) { - addReplacement(forwardSlashHostRoot, DEFAULT_GUEST_CWD); - } - } - - return [...replacements.entries()].sort((left, right) => right[0].length - left[0].length); -} - -function splitPathLocationSuffix(value) { - if (typeof value !== 'string') { - return { pathLike: value, suffix: '' }; - } - - const match = /^(.*?)(:\d+(?::\d+)?)$/.exec(value); - return match - ? { pathLike: match[1], suffix: match[2] } - : { pathLike: value, suffix: '' }; -} - -function translateTextTokenToGuest(token) { - if (typeof token !== 'string' || token.length === 0) { - return token; - } - - const leading = token.match(/^[("'`[{<]+/)?.[0] ?? ''; - const trailing = token.match(/[)"'`\]}>.,;!?]+$/)?.[0] ?? ''; - const coreEnd = token.length - trailing.length; - const core = token.slice(leading.length, coreEnd); - if (core.length === 0) { - return token; - } - - const { pathLike, suffix } = splitPathLocationSuffix(core); - if ( - typeof pathLike !== 'string' || - (!pathLike.startsWith('file:') && !path.isAbsolute(pathLike)) - ) { - return token; - } - - return `${leading}${translatePathStringToGuest(pathLike)}${suffix}${trailing}`; -} - -function translateTextToGuest(value) { - if (typeof value !== 'string' || value.length === 0) { - return value; - } - - let translated = value; - for (const [hostValue, guestValue] of buildHostToGuestTextReplacements()) { - translated = translated.split(hostValue).join(guestValue); - } - - return translated - .split(/(\s+)/) - .map((token) => (/^\s+$/.test(token) ? token : translateTextTokenToGuest(token))) - .join(''); -} - -function translateErrorToGuest(error) { - if (error == null || typeof error !== 'object') { - return error; - } - - if (typeof error.message === 'string') { - try { - error.message = translateTextToGuest(error.message); - } catch { - // Ignore readonly message bindings. - } - } - - if (typeof error.stack === 'string') { - try { - error.stack = translateTextToGuest(error.stack); - } catch { - // Ignore readonly stack bindings. - } - } - - if (typeof error.path === 'string') { - try { - error.path = translatePathStringToGuest(error.path); - } catch { - // Ignore readonly path bindings. - } - } - - if (typeof error.filename === 'string') { - try { - error.filename = translatePathStringToGuest(error.filename); - } catch { - // Ignore readonly filename bindings. - } - } - - if (typeof error.url === 'string') { - try { - error.url = translatePathStringToGuest(error.url); - } catch { - // Ignore readonly url bindings. - } - } - - if (Array.isArray(error.requireStack)) { - try { - error.requireStack = error.requireStack.map((entry) => translatePathStringToGuest(entry)); - } catch { - // Ignore readonly requireStack bindings. - } - } - - return error; -} - -function pathExists(targetPath) { - try { - return fs.existsSync(targetPath); - } catch { - return false; - } -} - -function safeRealpath(targetPath) { - try { - return fs.realpathSync.native(targetPath); - } catch { - return null; - } -} - -function parseJsonArray(value) { - if (!value) { - return []; - } - - try { - const parsed = JSON.parse(value); - return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === 'string') : []; - } catch { - return []; - } -} - -function isInternalImportCachePath(filePath) { - return typeof filePath === 'string' && filePath.includes(`${path.sep}agentos-node-import-cache-`); -} - -function parseGuestPathMappings(value) { - const parsed = parseJsonArrayLikeObjects(value); - return parsed - .map((entry) => { - const guestPath = - typeof entry.guestPath === 'string' - ? path.posix.normalize(entry.guestPath) - : null; - const hostPath = - typeof entry.hostPath === 'string' ? path.resolve(entry.hostPath) : null; - return guestPath && hostPath ? { guestPath, hostPath } : null; - }) - .filter(Boolean) - .sort((left, right) => { - if (right.guestPath.length !== left.guestPath.length) { - return right.guestPath.length - left.guestPath.length; - } - return right.hostPath.length - left.hostPath.length; - }); -} - -function parseJsonArrayLikeObjects(value) { - if (!value) { - return []; - } - - try { - const parsed = JSON.parse(value); - return Array.isArray(parsed) ? parsed.filter(isRecord) : []; - } catch { - return []; - } -} - -function hashString(contents) { - return crypto.createHash('sha256').update(contents).digest('hex'); -} - -function isRecord(value) { - return value != null && typeof value === 'object' && !Array.isArray(value); -} -"#; - -const NODE_IMPORT_CACHE_REGISTER_SOURCE: &str = r#" -import { register } from 'node:module'; - -const loaderPath = process.env.__NODE_IMPORT_CACHE_LOADER_PATH_ENV__; - -if (!loaderPath) { - throw new Error('__NODE_IMPORT_CACHE_LOADER_PATH_ENV__ is required'); -} - -register(loaderPath, import.meta.url); -"#; - -const NODE_EXECUTION_RUNNER_SOURCE: &str = r#" -const fs = process.getBuiltinModule?.('node:fs'); -const path = process.getBuiltinModule?.('node:path'); -const { pathToFileURL } = process.getBuiltinModule?.('node:url') ?? {}; - -if (!fs || !path || typeof pathToFileURL !== 'function') { - throw new Error('node builtin access is required for the secure-exec guest runtime'); -} - -const HOST_PROCESS_ENV = { ...process.env }; -const ALLOW_PROCESS_BINDINGS = HOST_PROCESS_ENV.AGENTOS_ALLOW_PROCESS_BINDINGS === '1'; -const Module = - typeof process.getBuiltinModule === 'function' - ? process.getBuiltinModule('node:module') - : null; -const syncBuiltinESMExports = - typeof Module?.syncBuiltinESMExports === 'function' - ? Module.syncBuiltinESMExports.bind(Module) - : () => {}; -const GUEST_PATH_MAPPINGS = parseGuestPathMappings(HOST_PROCESS_ENV.AGENTOS_GUEST_PATH_MAPPINGS); -const ALLOWED_BUILTINS = new Set(parseJsonArray(HOST_PROCESS_ENV.AGENTOS_ALLOWED_NODE_BUILTINS)); -const LOOPBACK_EXEMPT_PORTS = new Set(parseJsonArray(HOST_PROCESS_ENV.AGENTOS_LOOPBACK_EXEMPT_PORTS)); -const DENIED_BUILTINS = new Set([ - 'child_process', - 'cluster', - 'dgram', - 'dns', - 'http', - 'http2', - 'https', - 'inspector', - 'module', - 'net', - 'tls', - 'trace_events', - 'v8', - 'vm', - 'worker_threads', -].filter((name) => !ALLOWED_BUILTINS.has(name))); -const originalGetBuiltinModule = - typeof process.getBuiltinModule === 'function' - ? process.getBuiltinModule.bind(process) - : null; -const originalModuleResolveFilename = - typeof Module?._resolveFilename === 'function' - ? Module._resolveFilename.bind(Module) - : null; -const originalModuleLoad = - typeof Module?._load === 'function' ? Module._load.bind(Module) : null; -const originalModuleCache = - Module?._cache && typeof Module._cache === 'object' ? Module._cache : null; -const originalFetch = - typeof globalThis.fetch === 'function' - ? globalThis.fetch.bind(globalThis) - : null; -const HOST_CWD = process.cwd(); -const HOST_EXEC_PATH = process.execPath; -const HOST_EXEC_DIR = path.dirname(HOST_EXEC_PATH); -if (!Module || typeof Module.createRequire !== 'function') { - throw new Error('node:module builtin access is required for the secure-exec guest runtime'); -} -const hostRequire = Module.createRequire(import.meta.url); -const hostOs = hostRequire('node:os'); -const hostNet = hostRequire('node:net'); -const hostDgram = hostRequire('node:dgram'); -const hostDns = hostRequire('node:dns'); -const hostDnsPromises = hostRequire('node:dns/promises'); -const hostHttp = hostRequire('node:http'); -const hostHttp2 = hostRequire('node:http2'); -const hostHttps = hostRequire('node:https'); -const hostTls = hostRequire('node:tls'); -const { EventEmitter } = hostRequire('node:events'); -const { Duplex, Readable, Writable } = hostRequire('node:stream'); -const NODE_SYNC_RPC_ENABLE = HOST_PROCESS_ENV.AGENTOS_NODE_SYNC_RPC_ENABLE === '1'; -const hostWorkerThreads = NODE_SYNC_RPC_ENABLE ? hostRequire('node:worker_threads') : null; -const SIGNAL_EVENTS = new Set( - Object.keys(hostOs.constants?.signals ?? {}).filter((name) => - name.startsWith('SIG'), - ), -); -const TRACKED_PROCESS_SIGNAL_EVENTS = new Set(['SIGCHLD']); -const guestEntryPoint = - HOST_PROCESS_ENV.AGENTOS_GUEST_ENTRYPOINT ?? HOST_PROCESS_ENV.AGENTOS_ENTRYPOINT; -const DEFAULT_VIRTUAL_EXEC_PATH = '/usr/bin/node'; -const DEFAULT_VIRTUAL_PID = 1; -const DEFAULT_VIRTUAL_PPID = 0; -const DEFAULT_VIRTUAL_UID = 0; -const DEFAULT_VIRTUAL_GID = 0; -const DEFAULT_VIRTUAL_OS_HOSTNAME = 'secure-exec'; -const DEFAULT_VIRTUAL_OS_TYPE = 'Linux'; -const DEFAULT_VIRTUAL_OS_PLATFORM = 'linux'; -const DEFAULT_VIRTUAL_OS_RELEASE = '6.8.0-secure-exec'; -const DEFAULT_VIRTUAL_OS_VERSION = '#1 SMP PREEMPT_DYNAMIC secure-exec'; -const DEFAULT_VIRTUAL_OS_ARCH = 'x64'; -const DEFAULT_VIRTUAL_OS_MACHINE = 'x86_64'; -const DEFAULT_VIRTUAL_OS_CPU_MODEL = 'secure-exec Virtual CPU'; -const DEFAULT_VIRTUAL_OS_CPU_COUNT = 1; -const DEFAULT_VIRTUAL_OS_TOTALMEM = 1024 * 1024 * 1024; -const DEFAULT_VIRTUAL_OS_FREEMEM = 768 * 1024 * 1024; -const DEFAULT_VIRTUAL_OS_USER = 'root'; -const DEFAULT_VIRTUAL_OS_HOMEDIR = '/root'; -const DEFAULT_VIRTUAL_OS_SHELL = '/bin/sh'; -const DEFAULT_VIRTUAL_OS_TMPDIR = '/tmp'; -const NODE_SYNC_RPC_REQUEST_FD = parseOptionalFd(HOST_PROCESS_ENV.AGENTOS_NODE_SYNC_RPC_REQUEST_FD); -const NODE_SYNC_RPC_RESPONSE_FD = parseOptionalFd(HOST_PROCESS_ENV.AGENTOS_NODE_SYNC_RPC_RESPONSE_FD); -const NODE_SYNC_RPC_DATA_BYTES = parsePositiveInt( - HOST_PROCESS_ENV.AGENTOS_NODE_SYNC_RPC_DATA_BYTES, - 4 * 1024 * 1024, -); -const NODE_SYNC_RPC_WAIT_TIMEOUT_MS = parsePositiveInt( - HOST_PROCESS_ENV.AGENTOS_NODE_SYNC_RPC_WAIT_TIMEOUT_MS, - 30_000, -); -const NODE_IMPORT_CACHE_PATH = HOST_PROCESS_ENV.AGENTOS_NODE_IMPORT_CACHE_PATH ?? null; -const NODE_IMPORT_CACHE_ROOT = - typeof NODE_IMPORT_CACHE_PATH === 'string' && NODE_IMPORT_CACHE_PATH.length > 0 - ? path.dirname(NODE_IMPORT_CACHE_PATH) - : null; -const CONTROL_PIPE_FD = parseOptionalFd(HOST_PROCESS_ENV.AGENTOS_CONTROL_PIPE_FD); -const GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT = '/.agentos/node-import-cache'; -const UNMAPPED_GUEST_PATH = '/unknown'; -const VIRTUAL_EXEC_PATH = parseVirtualProcessString( - HOST_PROCESS_ENV.AGENTOS_VIRTUAL_PROCESS_EXEC_PATH, - DEFAULT_VIRTUAL_EXEC_PATH, -); -const VIRTUAL_PID = parseVirtualProcessNumber( - HOST_PROCESS_ENV.AGENTOS_VIRTUAL_PROCESS_PID, - DEFAULT_VIRTUAL_PID, -); -const VIRTUAL_PPID = parseVirtualProcessNumber( - HOST_PROCESS_ENV.AGENTOS_VIRTUAL_PROCESS_PPID, - DEFAULT_VIRTUAL_PPID, -); -const VIRTUAL_UID = parseVirtualProcessNumber( - HOST_PROCESS_ENV.AGENTOS_VIRTUAL_PROCESS_UID, - DEFAULT_VIRTUAL_UID, -); -const VIRTUAL_GID = parseVirtualProcessNumber( - HOST_PROCESS_ENV.AGENTOS_VIRTUAL_PROCESS_GID, - DEFAULT_VIRTUAL_GID, -); -const DEFAULT_GUEST_CWD = resolveVirtualPath( - (globalThis.__agentOSVirtualOs||{}).homedir, - DEFAULT_VIRTUAL_OS_HOMEDIR, -); -const VIRTUAL_OS_USER = parseVirtualProcessString( - (globalThis.__agentOSVirtualOs||{}).user, - DEFAULT_VIRTUAL_OS_USER, -); -const VIRTUAL_OS_HOMEDIR = resolveVirtualPath( - (globalThis.__agentOSVirtualOs||{}).homedir, - DEFAULT_VIRTUAL_OS_HOMEDIR, -); -const VIRTUAL_OS_SHELL = resolveVirtualPath( - (globalThis.__agentOSVirtualOs||{}).shell, - DEFAULT_VIRTUAL_OS_SHELL, -); - -function isPathLike(specifier) { - return specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('file:'); -} - -function toImportSpecifier(specifier) { - if (specifier.startsWith('file:')) { - return translatePathStringToGuest(specifier); - } - if (isPathLike(specifier)) { - if (specifier.startsWith('/')) { - return pathToFileURL( - translatePathStringToGuest( - pathExists(specifier) ? path.resolve(specifier) : path.posix.normalize(specifier), - ), - ).href; - } - return pathToFileURL(translatePathStringToGuest(path.resolve(HOST_CWD, specifier))).href; - } - return specifier; -} - -function accessDenied(subject) { - const error = new Error(`${subject} is not available in the secure-exec guest runtime`); - error.code = 'ERR_ACCESS_DENIED'; - return error; -} - -function normalizeBuiltin(specifier) { - return specifier.startsWith('node:') ? specifier.slice('node:'.length) : specifier; -} - -function isBareSpecifier(specifier) { - if (typeof specifier !== 'string') { - return false; - } - - if ( - specifier.startsWith('./') || - specifier.startsWith('../') || - specifier.startsWith('/') || - specifier.startsWith('file:') || - specifier.startsWith('node:') - ) { - return false; - } - - return !/^[A-Za-z][A-Za-z0-9+.-]*:/.test(specifier); -} - -function pathExists(targetPath) { - try { - return fs.existsSync(targetPath); - } catch { - return false; - } -} - -function parseJsonArray(value) { - if (!value) { - return []; - } - - try { - const parsed = JSON.parse(value); - return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === 'string') : []; - } catch { - return []; - } -} - -function parseOptionalFd(value) { - if (value == null || value === '') { - return null; - } - - const parsed = Number.parseInt(value, 10); - return Number.isInteger(parsed) && parsed >= 0 ? parsed : null; -} - -function parsePositiveInt(value, fallback) { - if (value == null || value === '') { - return fallback; - } - - const parsed = Number(value); - return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback; -} - -function parseVirtualProcessNumber(value, fallback) { - if (value == null || value === '') { - return fallback; - } - - const parsed = Number(value); - return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback; -} - -function parseVirtualProcessString(value, fallback) { - return typeof value === 'string' && value.length > 0 ? value : fallback; -} - -function isInternalProcessEnvKey(key) { - return typeof key === 'string' && key.startsWith('AGENTOS_'); -} - -function createGuestProcessEnv(env) { - const guestEnv = {}; - - for (const [key, value] of Object.entries(env ?? {})) { - if (typeof value !== 'string' || isInternalProcessEnvKey(key)) { - continue; - } - guestEnv[key] = value; - } - - return new Proxy(guestEnv, { - defineProperty(target, key, descriptor) { - if (typeof key === 'string' && isInternalProcessEnvKey(key)) { - return true; - } - - const normalized = { ...descriptor }; - if ('value' in normalized) { - normalized.value = String(normalized.value); - } - return Reflect.defineProperty(target, key, normalized); - }, - deleteProperty(target, key) { - if (typeof key === 'string' && isInternalProcessEnvKey(key)) { - return true; - } - return Reflect.deleteProperty(target, key); - }, - get(target, key, receiver) { - if (typeof key === 'string' && isInternalProcessEnvKey(key)) { - return undefined; - } - return Reflect.get(target, key, receiver); - }, - getOwnPropertyDescriptor(target, key) { - if (typeof key === 'string' && isInternalProcessEnvKey(key)) { - return undefined; - } - return Reflect.getOwnPropertyDescriptor(target, key); - }, - has(target, key) { - if (typeof key === 'string' && isInternalProcessEnvKey(key)) { - return false; - } - return Reflect.has(target, key); - }, - ownKeys(target) { - return Reflect.ownKeys(target).filter( - (key) => typeof key !== 'string' || !isInternalProcessEnvKey(key), - ); - }, - set(target, key, value, receiver) { - if (typeof key === 'string' && isInternalProcessEnvKey(key)) { - return true; - } - return Reflect.set(target, key, String(value), receiver); - }, - }); -} - -function parseGuestPathMappings(value) { - if (!value) { - return []; - } - - try { - const parsed = JSON.parse(value); - if (!Array.isArray(parsed)) { - return []; - } - - return parsed - .map((entry) => { - const guestPath = - entry && typeof entry.guestPath === 'string' - ? path.posix.normalize(entry.guestPath) - : null; - const hostPath = - entry && typeof entry.hostPath === 'string' - ? path.resolve(entry.hostPath) - : null; - return guestPath && hostPath - ? { guestPath, hostPath, readOnly: entry.readOnly === true } - : null; - }) - .filter(Boolean) - .sort((left, right) => right.guestPath.length - left.guestPath.length); - } catch { - return []; - } -} - -function hostPathFromGuestPath(guestPath) { - if (typeof guestPath !== 'string') { - return null; - } - - const normalized = path.posix.normalize(guestPath); - if ( - NODE_IMPORT_CACHE_ROOT && - (normalized === GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT || - normalized.startsWith(`${GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT}/`)) - ) { - const suffix = - normalized === GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT - ? '' - : normalized.slice(GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT.length + 1); - return suffix - ? path.join(NODE_IMPORT_CACHE_ROOT, ...suffix.split('/')) - : NODE_IMPORT_CACHE_ROOT; - } - - for (const mapping of GUEST_PATH_MAPPINGS) { - if (mapping.guestPath === '/') { - const suffix = normalized.replace(/^\/+/, ''); - return suffix ? path.join(mapping.hostPath, suffix) : mapping.hostPath; - } - - if ( - normalized !== mapping.guestPath && - !normalized.startsWith(`${mapping.guestPath}/`) - ) { - continue; - } - - const suffix = - normalized === mapping.guestPath - ? '' - : normalized.slice(mapping.guestPath.length + 1); - return suffix ? path.join(mapping.hostPath, suffix) : mapping.hostPath; - } - - if ( - normalized === DEFAULT_GUEST_CWD || - normalized.startsWith(`${DEFAULT_GUEST_CWD}/`) - ) { - const suffix = - normalized === DEFAULT_GUEST_CWD - ? '' - : normalized.slice(DEFAULT_GUEST_CWD.length + 1); - return suffix ? path.join(HOST_CWD, ...suffix.split('/')) : HOST_CWD; - } - - return null; -} - -function guestPathFromHostPath(hostPath) { - if (typeof hostPath !== 'string') { - return null; - } - - const normalized = path.resolve(hostPath); - for (const mapping of GUEST_PATH_MAPPINGS) { - const hostRoot = path.resolve(mapping.hostPath); - if ( - normalized !== hostRoot && - !normalized.startsWith(`${hostRoot}${path.sep}`) - ) { - continue; - } - - const suffix = - normalized === hostRoot - ? '' - : normalized.slice(hostRoot.length + path.sep.length); - return suffix - ? path.posix.join(mapping.guestPath, suffix.split(path.sep).join('/')) - : mapping.guestPath; - } - - return null; -} - -function guestCwdPathFromHostPath(hostPath) { - if (typeof hostPath !== 'string') { - return null; - } - - const normalized = path.resolve(hostPath); - const hostRoot = path.resolve(HOST_CWD); - if ( - normalized !== hostRoot && - !normalized.startsWith(`${hostRoot}${path.sep}`) - ) { - return null; - } - - const suffix = - normalized === hostRoot - ? '' - : normalized.slice(hostRoot.length + path.sep.length); - return suffix - ? path.posix.join(INITIAL_GUEST_CWD, suffix.split(path.sep).join('/')) - : INITIAL_GUEST_CWD; -} - -function guestInternalPathFromHostPath(hostPath) { - if (typeof hostPath !== 'string' || !NODE_IMPORT_CACHE_ROOT) { - return null; - } - - const normalized = path.resolve(hostPath); - const hostRoot = path.resolve(NODE_IMPORT_CACHE_ROOT); - if ( - normalized !== hostRoot && - !normalized.startsWith(`${hostRoot}${path.sep}`) - ) { - return null; - } - - const suffix = - normalized === hostRoot - ? '' - : normalized.slice(hostRoot.length + path.sep.length); - return suffix - ? path.posix.join( - GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT, - suffix.split(path.sep).join('/'), - ) - : GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT; -} - -function guestVisiblePathFromHostPath(hostPath) { - return ( - guestPathFromHostPath(hostPath) ?? - guestInternalPathFromHostPath(hostPath) ?? - guestCwdPathFromHostPath(hostPath) ?? - UNMAPPED_GUEST_PATH - ); -} - -function isGuestVisiblePath(value) { - if (typeof value !== 'string' || !path.posix.isAbsolute(value)) { - return false; - } - - const normalized = path.posix.normalize(value); - return ( - normalized === UNMAPPED_GUEST_PATH || - normalized === GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT || - normalized.startsWith(`${GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT}/`) || - normalized === INITIAL_GUEST_CWD || - normalized.startsWith(`${INITIAL_GUEST_CWD}/`) || - hostPathFromGuestPath(normalized) != null - ); -} - -function translatePathStringToGuest(value) { - if (typeof value !== 'string') { - return value; - } - - if (value.startsWith('file:')) { - try { - const hostPath = new URL(value).pathname; - const guestPath = isGuestVisiblePath(hostPath) - ? path.posix.normalize(hostPath) - : guestVisiblePathFromHostPath(hostPath); - return pathToFileURL(guestPath).href; - } catch { - return value; - } - } - - if (!path.isAbsolute(value)) { - return value; - } - - return isGuestVisiblePath(value) - ? path.posix.normalize(value) - : guestVisiblePathFromHostPath(value); -} - -function buildHostToGuestTextReplacements() { - const replacements = new Map(); - const addReplacement = (hostValue, guestValue) => { - if ( - typeof hostValue !== 'string' || - hostValue.length === 0 || - typeof guestValue !== 'string' || - guestValue.length === 0 - ) { - return; - } - - replacements.set(hostValue, guestValue); - }; - - for (const mapping of GUEST_PATH_MAPPINGS) { - const hostRoot = path.resolve(mapping.hostPath); - addReplacement(hostRoot, mapping.guestPath); - addReplacement(pathToFileURL(hostRoot).href, pathToFileURL(mapping.guestPath).href); - const forwardSlashHostRoot = hostRoot.split(path.sep).join('/'); - if (forwardSlashHostRoot !== hostRoot) { - addReplacement(forwardSlashHostRoot, mapping.guestPath); - } - } - - if (NODE_IMPORT_CACHE_ROOT) { - const hostRoot = path.resolve(NODE_IMPORT_CACHE_ROOT); - addReplacement(hostRoot, GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT); - addReplacement( - pathToFileURL(hostRoot).href, - pathToFileURL(GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT).href, - ); - const forwardSlashHostRoot = hostRoot.split(path.sep).join('/'); - if (forwardSlashHostRoot !== hostRoot) { - addReplacement(forwardSlashHostRoot, GUEST_INTERNAL_NODE_IMPORT_CACHE_ROOT); - } - } - - if (!guestPathFromHostPath(HOST_CWD)) { - const hostRoot = path.resolve(HOST_CWD); - addReplacement(hostRoot, INITIAL_GUEST_CWD); - addReplacement(pathToFileURL(hostRoot).href, pathToFileURL(INITIAL_GUEST_CWD).href); - const forwardSlashHostRoot = hostRoot.split(path.sep).join('/'); - if (forwardSlashHostRoot !== hostRoot) { - addReplacement(forwardSlashHostRoot, INITIAL_GUEST_CWD); - } - } - - return [...replacements.entries()].sort((left, right) => right[0].length - left[0].length); -} - -function splitPathLocationSuffix(value) { - if (typeof value !== 'string') { - return { pathLike: value, suffix: '' }; - } - - const match = /^(.*?)(:\d+(?::\d+)?)$/.exec(value); - return match - ? { pathLike: match[1], suffix: match[2] } - : { pathLike: value, suffix: '' }; -} - -function translateTextTokenToGuest(token) { - if (typeof token !== 'string' || token.length === 0) { - return token; - } - - const leading = token.match(/^[("'`[{<]+/)?.[0] ?? ''; - const trailing = token.match(/[)"'`\]}>.,;!?]+$/)?.[0] ?? ''; - const coreEnd = token.length - trailing.length; - const core = token.slice(leading.length, coreEnd); - if (core.length === 0) { - return token; - } - - const { pathLike, suffix } = splitPathLocationSuffix(core); - if ( - typeof pathLike !== 'string' || - (!pathLike.startsWith('file:') && !path.isAbsolute(pathLike)) - ) { - return token; - } - - return `${leading}${translatePathStringToGuest(pathLike)}${suffix}${trailing}`; -} - -function translateTextToGuest(value) { - if (typeof value !== 'string' || value.length === 0) { - return value; - } - - let translated = value; - for (const [hostValue, guestValue] of buildHostToGuestTextReplacements()) { - translated = translated.split(hostValue).join(guestValue); - } - - return translated - .split(/(\s+)/) - .map((token) => (/^\s+$/.test(token) ? token : translateTextTokenToGuest(token))) - .join(''); -} - -function translateErrorToGuest(error) { - if (error == null || typeof error !== 'object') { - return error; - } - - if (typeof error.message === 'string') { - try { - error.message = translateTextToGuest(error.message); - } catch { - // Ignore readonly message bindings. - } - } - - if (typeof error.stack === 'string') { - try { - error.stack = translateTextToGuest(error.stack); - } catch { - // Ignore readonly stack bindings. - } - } - - if (typeof error.path === 'string') { - try { - error.path = translatePathStringToGuest(error.path); - } catch { - // Ignore readonly path bindings. - } - } - - if (typeof error.filename === 'string') { - try { - error.filename = translatePathStringToGuest(error.filename); - } catch { - // Ignore readonly filename bindings. - } - } - - if (typeof error.url === 'string') { - try { - error.url = translatePathStringToGuest(error.url); - } catch { - // Ignore readonly url bindings. - } - } - - if (Array.isArray(error.requireStack)) { - try { - error.requireStack = error.requireStack.map((entry) => translatePathStringToGuest(entry)); - } catch { - // Ignore readonly requireStack bindings. - } - } - - return error; -} - -function hostPathForSpecifier(specifier, fromGuestDir) { - if (typeof specifier !== 'string') { - return null; - } - - if (specifier.startsWith('file:')) { - try { - return hostPathFromGuestPath(new URL(specifier).pathname); - } catch { - return null; - } - } - - if (specifier.startsWith('/')) { - return hostPathFromGuestPath(specifier); - } - - if (specifier.startsWith('./') || specifier.startsWith('../')) { - return hostPathFromGuestPath( - path.posix.normalize(path.posix.join(fromGuestDir, specifier)), - ); - } - - return null; -} - -function translateGuestPath(value, fromGuestDir = '/') { - if (typeof value !== 'string') { - return value; - } - - const translated = hostPathForSpecifier(value, fromGuestDir); - return translated ?? value; -} - -function resolveGuestFsPath(value, fromGuestDir = '/') { - if (typeof value !== 'string') { - return value; - } - - if (value.startsWith('file:')) { - try { - return path.posix.normalize(new URL(value).pathname); - } catch { - return value; - } - } - - if (value.startsWith('/')) { - return path.posix.normalize(value); - } - - if (value.startsWith('./') || value.startsWith('../')) { - return path.posix.normalize(path.posix.join(fromGuestDir, value)); - } - - return value; -} - -function normalizeFsReadOptions(options) { - return typeof options === 'string' ? { encoding: options } : options; -} - -function normalizeFsWriteContents(contents, options) { - if (typeof contents !== 'string') { - return contents; - } - - const encoding = - typeof options === 'string' - ? options - : options && typeof options === 'object' - ? options.encoding - : undefined; - if (typeof encoding === 'string' && encoding !== 'utf8' && encoding !== 'utf-8') { - return Buffer.from(contents, encoding); - } - - return contents; -} - -function normalizeFsTimeValue(value) { - if (value instanceof Date) { - return value.getTime(); - } - - return value; -} - -function createGuestFsStats(stat) { - if (stat == null || typeof stat !== 'object') { - return stat; - } - - const flags = { - isDirectory: Boolean(stat.isDirectory), - isSymbolicLink: Boolean(stat.isSymbolicLink), - }; - const target = { ...stat }; - - return new Proxy(target, { - get(source, key, receiver) { - switch (key) { - case 'isBlockDevice': - case 'isCharacterDevice': - case 'isFIFO': - case 'isSocket': - return () => false; - case 'isDirectory': - return () => flags.isDirectory; - case 'isFile': - return () => !flags.isDirectory && !flags.isSymbolicLink; - case 'isSymbolicLink': - return () => flags.isSymbolicLink; - case 'toJSON': - return () => ({ ...source, ...flags }); - default: - return Reflect.get(source, key, receiver); - } - }, - }); -} - -function requireSecureExecSyncRpcBridge() { - const bridge = globalThis.__agentOSSyncRpc; - if ( - bridge && - typeof bridge.call === 'function' && - typeof bridge.callSync === 'function' - ) { - return bridge; - } - - const error = new Error('secure-exec sync RPC bridge is unavailable'); - error.code = 'ERR_AGENTOS_NODE_SYNC_RPC_UNAVAILABLE'; - throw error; -} - -function requireFsSyncRpcBridge() { - return requireSecureExecSyncRpcBridge(); -} - -function isPythonWarmupDebugEnabled() { - return process.env.AGENTOS_PYTHON_WARMUP_DEBUG === '1'; -} - -function emitPythonWarmupFsDebug(message) { - if (!isPythonWarmupDebugEnabled()) { - return; - } - - try { - process.stderr.write(`__AGENTOS_PYTHON_FS_DEBUG__:${message}\n`); - } catch { - // Ignore debug logging failures. - } -} - -function formatPythonWarmupFsDebugError(error) { - if (!error || typeof error !== 'object') { - return String(error); - } - - if (typeof error.code === 'string' && error.code.length > 0) { - return error.code; - } - - if (typeof error.message === 'string' && error.message.length > 0) { - return error.message; - } - - return 'unknown'; -} - -function callFsRpc(method, args = []) { - emitPythonWarmupFsDebug(`${method}:start`); - return requireFsSyncRpcBridge() - .call(method, args) - .then( - (result) => { - emitPythonWarmupFsDebug(`${method}:ok`); - return result; - }, - (error) => { - emitPythonWarmupFsDebug( - `${method}:error:${formatPythonWarmupFsDebugError(error)}`, - ); - throw error; - }, - ); -} - -function callFsRpcSync(method, args = []) { - emitPythonWarmupFsDebug(`${method}:start`); - try { - const result = requireFsSyncRpcBridge().callSync(method, args); - emitPythonWarmupFsDebug(`${method}:ok`); - return result; - } catch (error) { - emitPythonWarmupFsDebug( - `${method}:error:${formatPythonWarmupFsDebugError(error)}`, - ); - throw error; - } -} - -function guestProcessUmask(mask) { - const bridge = requireSecureExecSyncRpcBridge(); - if (mask == null) { - return bridge.callSync('process.umask', []); - } - return bridge.callSync('process.umask', [normalizeFsMode(mask) ?? 0]); -} - -function createRpcBackedFsPromises(fromGuestDir = '/') { - const call = (method, args = []) => callFsRpc(method, args); - - return { - access: async (target, mode) => { - await call('fs.promises.access', [ - resolveGuestFsPath(target, fromGuestDir), - mode, - ]); - }, - chmod: async (target, mode) => - call('fs.promises.chmod', [ - resolveGuestFsPath(target, fromGuestDir), - mode, - ]), - chown: async (target, uid, gid) => - call('fs.promises.chown', [ - resolveGuestFsPath(target, fromGuestDir), - uid, - gid, - ]), - copyFile: async (source, destination, mode) => - call('fs.promises.copyFile', [ - resolveGuestFsPath(source, fromGuestDir), - resolveGuestFsPath(destination, fromGuestDir), - mode, - ]), - lstat: async (target) => - createGuestFsStats( - await call('fs.promises.lstat', [resolveGuestFsPath(target, fromGuestDir)]), - ), - mkdir: async (target, options) => - call('fs.promises.mkdir', [ - resolveGuestFsPath(target, fromGuestDir), - options, - ]), - readFile: async (target, options) => - call('fs.promises.readFile', [ - resolveGuestFsPath(target, fromGuestDir), - normalizeFsReadOptions(options), - ]), - readdir: async (target, options) => - call('fs.promises.readdir', [ - resolveGuestFsPath(target, fromGuestDir), - options, - ]), - rename: async (source, destination) => - call('fs.promises.rename', [ - resolveGuestFsPath(source, fromGuestDir), - resolveGuestFsPath(destination, fromGuestDir), - ]), - rmdir: async (target, options) => - call('fs.promises.rmdir', [ - resolveGuestFsPath(target, fromGuestDir), - options, - ]), - stat: async (target) => - createGuestFsStats( - await call('fs.promises.stat', [resolveGuestFsPath(target, fromGuestDir)]), - ), - unlink: async (target) => - call('fs.promises.unlink', [resolveGuestFsPath(target, fromGuestDir)]), - utimes: async (target, atime, mtime) => - call('fs.promises.utimes', [ - resolveGuestFsPath(target, fromGuestDir), - normalizeFsTimeValue(atime), - normalizeFsTimeValue(mtime), - ]), - writeFile: async (target, contents, options) => - call('fs.promises.writeFile', [ - resolveGuestFsPath(target, fromGuestDir), - normalizeFsWriteContents(contents, options), - normalizeFsReadOptions(options), - ]), - }; -} - -function resolveGuestSymlinkTarget(value, fromGuestDir = '/') { - if (typeof value !== 'string') { - return value; - } - - if (value.startsWith('file:') || value.startsWith('/')) { - return resolveGuestFsPath(value, fromGuestDir); - } - - return value; -} - -const INITIAL_GUEST_CWD = guestPathFromHostPath(HOST_CWD) ?? DEFAULT_GUEST_CWD; - -function guestMappedChildNames(guestDir) { - if (typeof guestDir !== 'string') { - return []; - } - - const normalized = path.posix.normalize(guestDir); - const prefix = normalized === '/' ? '/' : `${normalized}/`; - const children = new Set(); - - for (const mapping of GUEST_PATH_MAPPINGS) { - if (!mapping.guestPath.startsWith(prefix)) { - continue; - } - const remainder = mapping.guestPath.slice(prefix.length); - const childName = remainder.split('/')[0]; - if (childName) { - children.add(childName); - } - } - - return [...children].sort(); -} - -function createSyntheticDirent(name) { - return { - name, - isBlockDevice: () => false, - isCharacterDevice: () => false, - isDirectory: () => true, - isFIFO: () => false, - isFile: () => false, - isSocket: () => false, - isSymbolicLink: () => false, - }; -} - -function createGuestDirent(name, stat) { - return { - name, - isBlockDevice: stat.isBlockDevice, - isCharacterDevice: stat.isCharacterDevice, - isDirectory: stat.isDirectory, - isFIFO: stat.isFIFO, - isFile: stat.isFile, - isSocket: stat.isSocket, - isSymbolicLink: stat.isSymbolicLink, - }; -} - -const GUEST_FS_O_RDONLY = 0; -const GUEST_FS_O_WRONLY = 1; -const GUEST_FS_O_RDWR = 2; -const GUEST_FS_O_CREAT = 0o100; -const GUEST_FS_O_EXCL = 0o200; -const GUEST_FS_O_TRUNC = 0o1000; -const GUEST_FS_O_APPEND = 0o2000; -const GUEST_FS_DEFAULT_STREAM_HWM = 64 * 1024; - -function normalizeFsInteger(value, label) { - const numeric = - typeof value === 'number' - ? value - : typeof value === 'bigint' - ? Number(value) - : Number.NaN; - if (!Number.isFinite(numeric) || !Number.isInteger(numeric) || numeric < 0) { - throw new TypeError(`secure-exec ${label} must be a non-negative integer`); - } - return numeric; -} - -function normalizeFsFd(value) { - return normalizeFsInteger(value, 'fd'); -} - -function isStdioFd(fd) { - return fd === 0 || fd === 1 || fd === 2; -} - -function writeToStdioFd(fd, value) { - const stream = - fd === 1 ? process.stdout : fd === 2 ? process.stderr : null; - if (!stream || typeof stream.write !== 'function') { - throw new Error(`secure-exec cannot write stdio fd ${fd}`); - } - stream.write(value); - return typeof value === 'string' ? Buffer.byteLength(value) : value.byteLength; -} - -function normalizeFsMode(mode) { - if (mode == null) { - return null; - } - if (typeof mode === 'string') { - const parsed = Number.parseInt(mode, 8); - if (!Number.isNaN(parsed)) { - return parsed; - } - } - return normalizeFsInteger(mode, 'mode'); -} - -function normalizeFsPosition(position) { - if (position == null) { - return null; - } - return normalizeFsInteger(position, 'position'); -} - -function normalizeFsOpenFlags(flags = 'r') { - if (typeof flags === 'number') { - return flags; - } - - switch (flags) { - case 'r': - case 'rs': - case 'sr': - return GUEST_FS_O_RDONLY; - case 'r+': - case 'rs+': - case 'sr+': - return GUEST_FS_O_RDWR; - case 'w': - return GUEST_FS_O_WRONLY | GUEST_FS_O_CREAT | GUEST_FS_O_TRUNC; - case 'wx': - case 'xw': - return GUEST_FS_O_WRONLY | GUEST_FS_O_CREAT | GUEST_FS_O_TRUNC | GUEST_FS_O_EXCL; - case 'w+': - return GUEST_FS_O_RDWR | GUEST_FS_O_CREAT | GUEST_FS_O_TRUNC; - case 'wx+': - case 'xw+': - return GUEST_FS_O_RDWR | GUEST_FS_O_CREAT | GUEST_FS_O_TRUNC | GUEST_FS_O_EXCL; - case 'a': - return GUEST_FS_O_WRONLY | GUEST_FS_O_CREAT | GUEST_FS_O_APPEND; - case 'ax': - case 'xa': - return GUEST_FS_O_WRONLY | GUEST_FS_O_CREAT | GUEST_FS_O_APPEND | GUEST_FS_O_EXCL; - case 'a+': - return GUEST_FS_O_RDWR | GUEST_FS_O_CREAT | GUEST_FS_O_APPEND; - case 'ax+': - case 'xa+': - return GUEST_FS_O_RDWR | GUEST_FS_O_CREAT | GUEST_FS_O_APPEND | GUEST_FS_O_EXCL; - default: - throw new TypeError(`secure-exec does not support fs open flag ${String(flags)}`); - } -} - -function toGuestBufferView(value, label) { - if (Buffer.isBuffer(value)) { - return value; - } - if (ArrayBuffer.isView(value)) { - return Buffer.from(value.buffer, value.byteOffset, value.byteLength); - } - throw new TypeError(`secure-exec ${label} must be a Buffer, TypedArray, or DataView`); -} - -function decodeFsBytesPayload(value, label) { - const decodeByteArray = (bytes) => { - const denseBytes = Array.from(bytes); - if (denseBytes.length !== bytes.length) { - throw new TypeError(`secure-exec ${label} contains sparse byte values`); - } - if ( - !denseBytes.every( - (byte) => typeof byte === 'number' && Number.isInteger(byte) && byte >= 0 && byte <= 255, - ) - ) { - throw new TypeError(`secure-exec ${label} contains an invalid byte value`); - } - return Buffer.from(denseBytes); - }; - - if (Buffer.isBuffer(value)) { - return value; - } - if (ArrayBuffer.isView(value)) { - return Buffer.from(value.buffer, value.byteOffset, value.byteLength); - } - if (typeof value === 'string') { - return Buffer.from(value); - } - if (Array.isArray(value)) { - return decodeByteArray(value); - } - if ( - value && - typeof value === 'object' && - Array.isArray(value.data) - ) { - return decodeByteArray(value.data); - } - if (value && typeof value === 'object') { - const entries = Object.entries(value); - if ( - entries.length > 0 && - entries.every( - ([key, byte]) => - /^\d+$/.test(key) && typeof byte === 'number' && Number.isInteger(byte), - ) - ) { - const bytes = []; - for (const [key, byte] of entries) { - const index = Number(key); - if (index < 0 || index >= entries.length || bytes[index] !== undefined) { - throw new TypeError(`secure-exec ${label} contains non-contiguous byte keys`); - } - bytes[index] = byte; - } - if (bytes.length !== entries.length || bytes.some((byte) => byte === undefined)) { - throw new TypeError(`secure-exec ${label} contains sparse byte keys`); - } - return decodeByteArray(bytes); - } - } - if ( - value && - typeof value === 'object' && - typeof value.data === 'string' - ) { - return Buffer.from(value.data, 'base64'); - } - - const base64Value = - value && - typeof value === 'object' && - typeof (value.base64 ?? value.dataBase64) === 'string' - ? (value.base64 ?? value.dataBase64) - : null; - if (base64Value == null) { - throw new TypeError(`secure-exec ${label} must be an encoded bytes payload`); - } - return Buffer.from(base64Value, 'base64'); -} - -function normalizeFsReadTarget(buffer, offset, length) { - const target = toGuestBufferView(buffer, 'read buffer'); - const normalizedOffset = offset == null ? 0 : normalizeFsInteger(offset, 'read offset'); - const available = target.byteLength - normalizedOffset; - if (normalizedOffset > target.byteLength) { - throw new RangeError('secure-exec read offset is out of range'); - } - const normalizedLength = - length == null ? available : normalizeFsInteger(length, 'read length'); - if (normalizedLength > available) { - throw new RangeError('secure-exec read length is out of range'); - } - return { target, offset: normalizedOffset, length: normalizedLength }; -} - -function normalizeFsWriteOperation(value, offsetOrPosition, lengthOrEncoding, position) { - if (typeof value === 'string') { - const normalizedPosition = normalizeFsPosition(offsetOrPosition); - const encoding = - typeof lengthOrEncoding === 'string' ? lengthOrEncoding : 'utf8'; - return { - payload: normalizeFsWriteContents(value, { encoding }), - position: normalizedPosition, - result: value, - }; - } - - const source = toGuestBufferView(value, 'write buffer'); - const normalizedOffset = - offsetOrPosition == null ? 0 : normalizeFsInteger(offsetOrPosition, 'write offset'); - const available = source.byteLength - normalizedOffset; - if (normalizedOffset > source.byteLength) { - throw new RangeError('secure-exec write offset is out of range'); - } - const normalizedLength = - lengthOrEncoding == null - ? available - : normalizeFsInteger(lengthOrEncoding, 'write length'); - if (normalizedLength > available) { - throw new RangeError('secure-exec write length is out of range'); - } - - return { - payload: source.subarray(normalizedOffset, normalizedOffset + normalizedLength), - position: normalizeFsPosition(position), - result: value, - }; -} - -function normalizeFsBytesResult(value, label) { - const numeric = - typeof value === 'number' - ? value - : typeof value === 'bigint' - ? Number(value) - : Number.NaN; - if (!Number.isFinite(numeric) || numeric < 0) { - throw new TypeError(`secure-exec ${label} must be numeric`); - } - return Math.trunc(numeric); -} - -function requireFsCallback(callback, methodName) { - if (typeof callback !== 'function') { - throw new TypeError(`secure-exec ${methodName} requires a callback`); - } - return callback; -} - -function invokeFsCallback(callback, error, ...results) { - queueMicrotask(() => callback(error, ...results)); -} - -function readKernelStdinForFs(target, buffer, callback) { - if (target.length === 0) { - invokeFsCallback(callback, null, 0, buffer); - return; - } - - let idleDelayMs = 1; - const attempt = () => { - requireFsSyncRpcBridge() - .call('__kernel_stdin_read', [target.length, 5]) - .then( - (payload) => { - if (payload == null) { - const nextDelayMs = idleDelayMs; - idleDelayMs = Math.min(idleDelayMs * 2, 25); - setTimeout(attempt, nextDelayMs); - return; - } - if (payload && payload.done === true) { - invokeFsCallback(callback, null, 0, buffer); - return; - } - const dataBase64 = - payload && - typeof payload === 'object' && - typeof payload.dataBase64 === 'string' - ? payload.dataBase64 - : ''; - if (!dataBase64) { - const nextDelayMs = idleDelayMs; - idleDelayMs = Math.min(idleDelayMs * 2, 25); - setTimeout(attempt, nextDelayMs); - return; - } - idleDelayMs = 1; - const chunk = Buffer.from(dataBase64, 'base64'); - const bytesRead = Math.min(target.length, chunk.byteLength); - chunk.copy(target.target, target.offset, 0, bytesRead); - invokeFsCallback(callback, null, bytesRead, buffer); - }, - (error) => invokeFsCallback(callback, error), - ); - }; - attempt(); -} - -function createFsWatchUnavailableError(methodName) { - const error = new Error( - `secure-exec ${methodName} is unavailable because the kernel has no file-watching API`, - ); - error.code = 'ERR_AGENTOS_FS_WATCH_UNAVAILABLE'; - return error; -} - -function createRpcBackedFsCallbacks(fromGuestDir = '/') { - const call = (method, args = []) => requireFsSyncRpcBridge().call(method, args); - - return { - close: (fd, callback) => { - const done = requireFsCallback(callback, 'fs.close'); - call('fs.close', [normalizeFsFd(fd)]).then( - () => invokeFsCallback(done, null), - (error) => invokeFsCallback(done, error), - ); - }, - fstat: (fd, options, callback) => { - const done = requireFsCallback( - typeof options === 'function' ? options : callback, - 'fs.fstat', - ); - call('fs.fstat', [normalizeFsFd(fd)]).then( - (stat) => invokeFsCallback(done, null, createGuestFsStats(stat)), - (error) => invokeFsCallback(done, error), - ); - }, - open: (target, flags, mode, callback) => { - if (typeof flags === 'function') { - callback = flags; - flags = undefined; - mode = undefined; - } else if (typeof mode === 'function') { - callback = mode; - mode = undefined; - } - - const done = requireFsCallback(callback, 'fs.open'); - call('fs.open', [ - resolveGuestFsPath(target, fromGuestDir), - normalizeFsOpenFlags(flags ?? 'r'), - normalizeFsMode(mode), - ]).then( - (fd) => invokeFsCallback(done, null, normalizeFsFd(fd)), - (error) => invokeFsCallback(done, error), - ); - }, - read: (fd, buffer, offset, length, position, callback) => { - if (typeof offset === 'function') { - callback = offset; - offset = undefined; - length = undefined; - position = undefined; - } else if (typeof length === 'function') { - callback = length; - length = undefined; - position = undefined; - } else if (typeof position === 'function') { - callback = position; - position = undefined; - } - - const done = requireFsCallback(callback, 'fs.read'); - const target = normalizeFsReadTarget(buffer, offset, length); - const normalizedFd = normalizeFsFd(fd); - const normalizedPosition = normalizeFsPosition(position); - if (normalizedFd === 0 && normalizedPosition == null) { - readKernelStdinForFs(target, buffer, done); - return; - } - call('fs.read', [ - normalizedFd, - target.length, - normalizedPosition, - ]).then( - (payload) => { - const chunk = decodeFsBytesPayload(payload, 'fs.read result'); - const bytesRead = Math.min(target.length, chunk.byteLength); - chunk.copy(target.target, target.offset, 0, bytesRead); - invokeFsCallback(done, null, bytesRead, buffer); - }, - (error) => invokeFsCallback(done, error), - ); - }, - write: (fd, value, offsetOrPosition, lengthOrEncoding, position, callback) => { - if (typeof offsetOrPosition === 'function') { - callback = offsetOrPosition; - offsetOrPosition = undefined; - lengthOrEncoding = undefined; - position = undefined; - } else if (typeof lengthOrEncoding === 'function') { - callback = lengthOrEncoding; - lengthOrEncoding = undefined; - position = undefined; - } else if (typeof position === 'function') { - callback = position; - position = undefined; - } - - const done = requireFsCallback(callback, 'fs.write'); - const write = normalizeFsWriteOperation( - value, - offsetOrPosition, - lengthOrEncoding, - position, - ); - const normalizedFd = normalizeFsFd(fd); - if (isStdioFd(normalizedFd)) { - try { - const bytesWritten = writeToStdioFd(normalizedFd, write.payload); - invokeFsCallback(done, null, bytesWritten, write.result); - } catch (error) { - invokeFsCallback(done, error); - } - return; - } - call('fs.write', [normalizedFd, write.payload, write.position]).then( - (bytesWritten) => - invokeFsCallback( - done, - null, - normalizeFsBytesResult(bytesWritten, 'fs.write result'), - write.result, - ), - (error) => invokeFsCallback(done, error), - ); - }, - }; -} - -function createRpcBackedFsSync(fromGuestDir = '/') { - const callSync = (method, args = []) => callFsRpcSync(method, args); - - return { - accessSync: (target, mode) => - callSync('fs.accessSync', [resolveGuestFsPath(target, fromGuestDir), mode]), - chmodSync: (target, mode) => - callSync('fs.chmodSync', [resolveGuestFsPath(target, fromGuestDir), mode]), - chownSync: (target, uid, gid) => - callSync('fs.chownSync', [resolveGuestFsPath(target, fromGuestDir), uid, gid]), - closeSync: (fd) => { - const normalizedFd = normalizeFsFd(fd); - if (isStdioFd(normalizedFd)) { - return undefined; - } - return callSync('fs.closeSync', [normalizedFd]); - }, - copyFileSync: (source, destination, mode) => - callSync('fs.copyFileSync', [ - resolveGuestFsPath(source, fromGuestDir), - resolveGuestFsPath(destination, fromGuestDir), - mode, - ]), - existsSync: (target) => { - try { - return Boolean(callSync('fs.existsSync', [resolveGuestFsPath(target, fromGuestDir)])); - } catch { - return false; - } - }, - fstatSync: (fd) => { - const normalizedFd = normalizeFsFd(fd); - if (isStdioFd(normalizedFd)) { - return hostFs.fstatSync(normalizedFd); - } - return createGuestFsStats(callSync('fs.fstatSync', [normalizedFd])); - }, - ftruncateSync: (fd, len) => { - const normalizedFd = normalizeFsFd(fd); - if (isStdioFd(normalizedFd)) { - return hostFs.ftruncateSync(normalizedFd, len); - } - return callSync('fs.ftruncateSync', [normalizedFd, normalizeFsInteger(len ?? 0, 'length')]); - }, - linkSync: (existingPath, newPath) => - callSync('fs.linkSync', [ - resolveGuestFsPath(existingPath, fromGuestDir), - resolveGuestFsPath(newPath, fromGuestDir), - ]), - lstatSync: (target) => - createGuestFsStats(callSync('fs.lstatSync', [resolveGuestFsPath(target, fromGuestDir)])), - mkdirSync: (target, options) => - callSync('fs.mkdirSync', [resolveGuestFsPath(target, fromGuestDir), options]), - openSync: (target, flags, mode) => - normalizeFsFd( - callSync('fs.openSync', [ - resolveGuestFsPath(target, fromGuestDir), - normalizeFsOpenFlags(flags ?? 'r'), - normalizeFsMode(mode), - ]), - ), - readFileSync: (target, options) => - callSync('fs.readFileSync', [ - resolveGuestFsPath(target, fromGuestDir), - normalizeFsReadOptions(options), - ]), - readSync: (fd, buffer, offset, length, position) => { - const normalizedFd = normalizeFsFd(fd); - const target = normalizeFsReadTarget(buffer, offset, length); - if (isStdioFd(normalizedFd)) { - return hostFs.readSync( - normalizedFd, - target.target, - target.offset, - target.length, - position, - ); - } - const chunk = decodeFsBytesPayload( - callSync('fs.readSync', [ - normalizedFd, - target.length, - normalizeFsPosition(position), - ]), - 'fs.readSync result', - ); - const bytesRead = Math.min(target.length, chunk.byteLength); - chunk.copy(target.target, target.offset, 0, bytesRead); - return bytesRead; - }, - readdirSync: (target, options) => { - const guestPath = resolveGuestFsPath(target, fromGuestDir); - const entries = callSync('fs.readdirSync', [guestPath, options]); - if (!options || typeof options !== 'object' || !options.withFileTypes) { - return entries; - } - - return entries.map((name) => - createGuestDirent( - name, - createGuestFsStats(callSync('fs.lstatSync', [path.posix.join(guestPath, name)])), - ), - ); - }, - readlinkSync: (target) => - callSync('fs.readlinkSync', [resolveGuestFsPath(target, fromGuestDir)]), - renameSync: (source, destination) => - callSync('fs.renameSync', [ - resolveGuestFsPath(source, fromGuestDir), - resolveGuestFsPath(destination, fromGuestDir), - ]), - rmdirSync: (target, options) => - callSync('fs.rmdirSync', [resolveGuestFsPath(target, fromGuestDir), options]), - statSync: (target) => - createGuestFsStats(callSync('fs.statSync', [resolveGuestFsPath(target, fromGuestDir)])), - symlinkSync: (target, linkPath, type) => - callSync('fs.symlinkSync', [ - resolveGuestSymlinkTarget(target, fromGuestDir), - resolveGuestFsPath(linkPath, fromGuestDir), - type, - ]), - truncateSync: (target, len) => - callSync('fs.truncateSync', [ - resolveGuestFsPath(target, fromGuestDir), - normalizeFsInteger(len ?? 0, 'length'), - ]), - unlinkSync: (target) => - callSync('fs.unlinkSync', [resolveGuestFsPath(target, fromGuestDir)]), - utimesSync: (target, atime, mtime) => - callSync('fs.utimesSync', [ - resolveGuestFsPath(target, fromGuestDir), - normalizeFsTimeValue(atime), - normalizeFsTimeValue(mtime), - ]), - writeSync: (fd, value, offsetOrPosition, lengthOrEncoding, position) => { - const normalizedFd = normalizeFsFd(fd); - const write = normalizeFsWriteOperation( - value, - offsetOrPosition, - lengthOrEncoding, - position, - ); - if (isStdioFd(normalizedFd)) { - return writeToStdioFd(normalizedFd, write.payload); - } - return normalizeFsBytesResult( - callSync('fs.writeSync', [normalizedFd, write.payload, write.position]), - 'fs.writeSync result', - ); - }, - writeFileSync: (target, contents, options) => - callSync('fs.writeFileSync', [ - resolveGuestFsPath(target, fromGuestDir), - normalizeFsWriteContents(contents, options), - normalizeFsReadOptions(options), - ]), - }; -} - -function createGuestReadStreamClass(fromGuestDir = '/') { - const call = (method, args = []) => requireFsSyncRpcBridge().call(method, args); - - return class SecureExecReadStream extends Readable { - constructor(target, options = {}) { - super({ - autoDestroy: options.autoClose !== false, - emitClose: options.emitClose !== false, - highWaterMark: options.highWaterMark, - }); - - this.path = target; - this.fd = typeof options.fd === 'number' ? options.fd : null; - this.flags = options.flags ?? 'r'; - this.mode = options.mode; - this.autoClose = options.autoClose !== false; - this.start = options.start; - this.end = options.end; - this.bytesRead = 0; - this.pending = false; - this.position = - options.start == null ? null : normalizeFsInteger(options.start, 'stream start'); - this.guestDir = fromGuestDir; - - if (options.end != null) { - this.end = normalizeFsInteger(options.end, 'stream end'); - if (this.position != null && this.end < this.position) { - throw new RangeError('secure-exec read stream end must be >= start'); - } - } - - if (options.encoding) { - this.setEncoding(options.encoding); - } - } - - _construct(callback) { - if (typeof this.fd === 'number') { - this.emit('open', this.fd); - this.emit('ready'); - callback(); - return; - } - - call('fs.open', [ - resolveGuestFsPath(this.path, this.guestDir), - normalizeFsOpenFlags(this.flags), - normalizeFsMode(this.mode), - ]).then( - (fd) => { - this.fd = normalizeFsFd(fd); - this.emit('open', this.fd); - this.emit('ready'); - callback(); - }, - (error) => callback(error), - ); - } - - _read(size) { - if (this.pending || typeof this.fd !== 'number') { - return; - } - - let length = size > 0 ? size : this.readableHighWaterMark ?? GUEST_FS_DEFAULT_STREAM_HWM; - if (this.position != null && this.end != null) { - const remaining = this.end - this.position + 1; - if (remaining <= 0) { - this.push(null); - return; - } - length = Math.min(length, remaining); - } - - this.pending = true; - call('fs.read', [this.fd, length, this.position]).then( - (payload) => { - this.pending = false; - const chunk = decodeFsBytesPayload(payload, 'fs.createReadStream chunk'); - if (this.position != null) { - this.position += chunk.byteLength; - } - this.bytesRead += chunk.byteLength; - if (chunk.byteLength === 0) { - this.push(null); - return; - } - this.push(chunk); - }, - (error) => { - this.pending = false; - this.destroy(error); - }, - ); - } - - _destroy(error, callback) { - if (!this.autoClose || typeof this.fd !== 'number') { - callback(error); - return; - } - - const fd = this.fd; - this.fd = null; - call('fs.close', [fd]).then( - () => callback(error), - (closeError) => callback(error ?? closeError), - ); - } - }; -} - -function createGuestWriteStreamClass(fromGuestDir = '/') { - const call = (method, args = []) => requireFsSyncRpcBridge().call(method, args); - - return class SecureExecWriteStream extends Writable { - constructor(target, options = {}) { - super({ - autoDestroy: options.autoClose !== false, - defaultEncoding: options.defaultEncoding, - decodeStrings: options.decodeStrings !== false, - emitClose: options.emitClose !== false, - highWaterMark: options.highWaterMark, - }); - - this.path = target; - this.fd = typeof options.fd === 'number' ? options.fd : null; - this.flags = options.flags ?? 'w'; - this.mode = options.mode; - this.autoClose = options.autoClose !== false; - this.bytesWritten = 0; - this.position = - options.start == null ? null : normalizeFsInteger(options.start, 'stream start'); - this.guestDir = fromGuestDir; - } - - _construct(callback) { - if (typeof this.fd === 'number') { - this.emit('open', this.fd); - this.emit('ready'); - callback(); - return; - } - - call('fs.open', [ - resolveGuestFsPath(this.path, this.guestDir), - normalizeFsOpenFlags(this.flags), - normalizeFsMode(this.mode), - ]).then( - (fd) => { - this.fd = normalizeFsFd(fd); - this.emit('open', this.fd); - this.emit('ready'); - callback(); - }, - (error) => callback(error), - ); - } - - _write(chunk, encoding, callback) { - const write = normalizeFsWriteOperation(chunk, 0, chunk.length, this.position); - call('fs.write', [normalizeFsFd(this.fd), write.payload, write.position]).then( - (bytesWritten) => { - const normalized = normalizeFsBytesResult( - bytesWritten, - 'fs.createWriteStream result', - ); - this.bytesWritten += normalized; - if (this.position != null) { - this.position += normalized; - } - callback(); - }, - (error) => callback(error), - ); - } - - _destroy(error, callback) { - if (!this.autoClose || typeof this.fd !== 'number') { - callback(error); - return; - } - - const fd = this.fd; - this.fd = null; - call('fs.close', [fd]).then( - () => callback(error), - (closeError) => callback(error ?? closeError), - ); - } - }; -} - -function wrapFsModule(fsModule, fromGuestDir = '/') { - const wrapPathFirst = (methodName) => { - const fn = fsModule[methodName]; - return (...args) => - fn(translateGuestPath(args[0], fromGuestDir), ...args.slice(1)); - }; - const wrapRenameLike = (methodName) => { - const fn = fsModule[methodName]; - return (...args) => - fn( - translateGuestPath(args[0], fromGuestDir), - translateGuestPath(args[1], fromGuestDir), - ...args.slice(2), - ); - }; - const existsSync = fsModule.existsSync.bind(fsModule); - const readdirSync = fsModule.readdirSync.bind(fsModule); - const ReadStream = createGuestReadStreamClass(fromGuestDir); - const WriteStream = createGuestWriteStreamClass(fromGuestDir); - - const wrapped = { - ...fsModule, - ReadStream, - WriteStream, - accessSync: wrapPathFirst('accessSync'), - appendFileSync: wrapPathFirst('appendFileSync'), - chmodSync: wrapPathFirst('chmodSync'), - chownSync: wrapPathFirst('chownSync'), - createReadStream: (target, options) => new ReadStream(target, options), - createWriteStream: (target, options) => new WriteStream(target, options), - existsSync: (target) => { - const translated = translateGuestPath(target, fromGuestDir); - return existsSync(translated) || guestMappedChildNames(target).length > 0; - }, - lstatSync: wrapPathFirst('lstatSync'), - mkdirSync: wrapPathFirst('mkdirSync'), - readFileSync: wrapPathFirst('readFileSync'), - readdirSync: (target, options) => { - const translated = translateGuestPath(target, fromGuestDir); - if (existsSync(translated)) { - return readdirSync(translated, options); - } - - const synthetic = guestMappedChildNames(target); - if (synthetic.length > 0) { - return options && typeof options === 'object' && options.withFileTypes - ? synthetic.map((name) => createSyntheticDirent(name)) - : synthetic; - } - - return readdirSync(translated, options); - }, - readlinkSync: wrapPathFirst('readlinkSync'), - realpathSync: wrapPathFirst('realpathSync'), - renameSync: wrapRenameLike('renameSync'), - rmSync: wrapPathFirst('rmSync'), - rmdirSync: wrapPathFirst('rmdirSync'), - statSync: wrapPathFirst('statSync'), - symlinkSync: wrapRenameLike('symlinkSync'), - unlinkSync: wrapPathFirst('unlinkSync'), - unwatchFile: () => {}, - utimesSync: wrapPathFirst('utimesSync'), - watch: () => { - throw createFsWatchUnavailableError('fs.watch'); - }, - watchFile: () => { - throw createFsWatchUnavailableError('fs.watchFile'); - }, - writeFileSync: wrapPathFirst('writeFileSync'), - }; - - if (fsModule.promises) { - wrapped.promises = { - ...fsModule.promises, - access: wrapPathFirstAsync(fsModule.promises.access, fromGuestDir), - appendFile: wrapPathFirstAsync(fsModule.promises.appendFile, fromGuestDir), - chmod: wrapPathFirstAsync(fsModule.promises.chmod, fromGuestDir), - chown: wrapPathFirstAsync(fsModule.promises.chown, fromGuestDir), - lstat: wrapPathFirstAsync(fsModule.promises.lstat, fromGuestDir), - mkdir: wrapPathFirstAsync(fsModule.promises.mkdir, fromGuestDir), - open: wrapPathFirstAsync(fsModule.promises.open, fromGuestDir), - readFile: wrapPathFirstAsync(fsModule.promises.readFile, fromGuestDir), - readdir: wrapPathFirstAsync(fsModule.promises.readdir, fromGuestDir), - readlink: wrapPathFirstAsync(fsModule.promises.readlink, fromGuestDir), - realpath: wrapPathFirstAsync(fsModule.promises.realpath, fromGuestDir), - rename: wrapRenameLikeAsync(fsModule.promises.rename, fromGuestDir), - rm: wrapPathFirstAsync(fsModule.promises.rm, fromGuestDir), - rmdir: wrapPathFirstAsync(fsModule.promises.rmdir, fromGuestDir), - stat: wrapPathFirstAsync(fsModule.promises.stat, fromGuestDir), - symlink: wrapRenameLikeAsync(fsModule.promises.symlink, fromGuestDir), - unlink: wrapPathFirstAsync(fsModule.promises.unlink, fromGuestDir), - utimes: wrapPathFirstAsync(fsModule.promises.utimes, fromGuestDir), - writeFile: wrapPathFirstAsync(fsModule.promises.writeFile, fromGuestDir), - }; - Object.assign(wrapped.promises, createRpcBackedFsPromises(fromGuestDir)); - } - - Object.assign(wrapped, createRpcBackedFsCallbacks(fromGuestDir)); - Object.assign(wrapped, createRpcBackedFsSync(fromGuestDir)); - - return wrapped; -} - -function wrapPathFirstAsync(fn, fromGuestDir) { - return (...args) => - fn(translateGuestPath(args[0], fromGuestDir), ...args.slice(1)); -} - -function wrapRenameLikeAsync(fn, fromGuestDir) { - return (...args) => - fn( - translateGuestPath(args[0], fromGuestDir), - translateGuestPath(args[1], fromGuestDir), - ...args.slice(2), - ); -} - -function createRpcBackedChildProcessModule(fromGuestDir = '/') { - const RPC_POLL_WAIT_MS = 50; - const RPC_IDLE_POLL_DELAY_MS = 10; - const INTERNAL_BOOTSTRAP_ENV_KEYS = [ - 'AGENTOS_ALLOWED_NODE_BUILTINS', - 'AGENTOS_GUEST_PATH_MAPPINGS', - 'AGENTOS_LOOPBACK_EXEMPT_PORTS', - 'AGENTOS_VIRTUAL_PROCESS_EXEC_PATH', - 'AGENTOS_VIRTUAL_PROCESS_UID', - 'AGENTOS_VIRTUAL_PROCESS_GID', - 'AGENTOS_VIRTUAL_PROCESS_VERSION', - ]; - - const bridge = () => requireSecureExecSyncRpcBridge(); - const createUnsupportedChildProcessError = (subject) => { - const error = new Error(`${subject} is not supported by the secure-exec child_process polyfill`); - error.code = 'ERR_AGENTOS_CHILD_PROCESS_UNSUPPORTED'; - return error; - }; - const normalizeSpawnInvocation = (args, options) => { - if (!Array.isArray(args)) { - return { - args: [], - options: args && typeof args === 'object' ? args : options, - }; - } - - return { - args, - options, - }; - }; - const normalizeExecInvocation = (options, callback) => - typeof options === 'function' - ? { options: undefined, callback: options } - : { options, callback }; - const normalizeExecFileInvocation = (args, options, callback) => { - if (typeof args === 'function') { - return { args: [], options: undefined, callback: args }; - } - if (!Array.isArray(args)) { - return { - args: [], - options: args, - callback: typeof options === 'function' ? options : callback, - }; - } - if (typeof options === 'function') { - return { args, options: undefined, callback: options }; - } - return { args, options, callback }; - }; - const normalizeChildProcessSignal = (value) => - typeof value === 'string' && value.length > 0 ? value : 'SIGTERM'; - const normalizeChildProcessEncoding = (options) => - typeof options?.encoding === 'string' ? options.encoding : null; - const normalizeChildProcessTimeout = (options) => - Number.isInteger(options?.timeout) && options.timeout > 0 ? options.timeout : null; - const normalizeChildProcessEnv = (env) => { - const source = env && typeof env === 'object' ? env : {}; - const merged = { - ...Object.fromEntries( - Object.entries(process.env).filter( - ([key, value]) => typeof value === 'string' && !isInternalProcessEnvKey(key), - ), - ), - ...Object.fromEntries( - Object.entries(source).filter( - ([key, value]) => value != null && !isInternalProcessEnvKey(key), - ), - ), - }; - delete merged.NODE_OPTIONS; - - return Object.fromEntries( - Object.entries(merged).map(([key, value]) => [key, String(value)]), - ); - }; - const createChildProcessInternalBootstrapEnv = () => { - const bootstrapEnv = {}; - - for (const key of INTERNAL_BOOTSTRAP_ENV_KEYS) { - if (typeof HOST_PROCESS_ENV[key] === 'string') { - bootstrapEnv[key] = HOST_PROCESS_ENV[key]; - } - } - // Virtual OS identity is no longer carried as `AGENTOS_VIRTUAL_OS_*` env; - // nested child executions receive it via the typed `guest_runtime` → - // `__agentOSVirtualOs` global like every other guest execution. - - return bootstrapEnv; - }; - const normalizeChildProcessStdioEntry = (value, index) => { - if (value == null) { - return 'pipe'; - } - if (value === 'pipe' || value === 'ignore' || value === 'inherit') { - return value; - } - if (value === 'ipc') { - throw createUnsupportedChildProcessError('child_process IPC stdio'); - } - if (value === null && index === 0) { - return 'pipe'; - } - throw createUnsupportedChildProcessError(`child_process stdio=${String(value)}`); - }; - const normalizeChildProcessStdio = (stdio) => { - if (stdio == null) { - return ['pipe', 'pipe', 'pipe']; - } - if (typeof stdio === 'string') { - return [ - normalizeChildProcessStdioEntry(stdio, 0), - normalizeChildProcessStdioEntry(stdio, 1), - normalizeChildProcessStdioEntry(stdio, 2), - ]; - } - if (!Array.isArray(stdio)) { - throw createUnsupportedChildProcessError('child_process stdio configuration'); - } - return [0, 1, 2].map((index) => - normalizeChildProcessStdioEntry(stdio[index], index), - ); - }; - const normalizeChildProcessOptions = (options, shell = false) => { - if (options != null && typeof options !== 'object') { - throw new TypeError('child_process options must be an object'); - } - if (options?.detached) { - throw createUnsupportedChildProcessError('child_process detached'); - } - - return { - cwd: - typeof options?.cwd === 'string' - ? resolveGuestFsPath(options.cwd, fromGuestDir) - : fromGuestDir, - env: normalizeChildProcessEnv(options?.env), - internalBootstrapEnv: createChildProcessInternalBootstrapEnv(), - shell: - shell || - options?.shell === true || - typeof options?.shell === 'string', - stdio: normalizeChildProcessStdio(options?.stdio), - timeout: normalizeChildProcessTimeout(options), - killSignal: normalizeChildProcessSignal(options?.killSignal), - }; - }; - const createRpcSpawnRequest = (command, args, options, shell = false) => ({ - command: String(command), - args: Array.isArray(args) ? args.map((arg) => String(arg)) : [], - options: normalizeChildProcessOptions(options, shell), - }); - const callSpawn = (command, args, options, shell = false) => - bridge().callSync('child_process.spawn', [ - createRpcSpawnRequest(command, args, options, shell), - ]); - const callPoll = (childId, waitMs = 0) => - bridge().callSync('child_process.poll', [childId, waitMs]); - const callKill = (childId, signal) => - bridge().callSync('child_process.kill', [childId, normalizeChildProcessSignal(signal)]); - const callWriteStdin = (childId, chunk) => - bridge().callSync('child_process.write_stdin', [childId, toGuestBufferView(chunk, 'stdin chunk')]); - const callCloseStdin = (childId) => - bridge().callSync('child_process.close_stdin', [childId]); - const encodeChildProcessOutput = (buffer, encoding) => - encoding ? buffer.toString(encoding) : buffer; - const createChildProcessExecError = (subject, exitCode, signal, stdout, stderr) => { - const error = new Error( - signal == null - ? `${subject} exited with code ${exitCode ?? 'unknown'}` - : `${subject} terminated by signal ${signal}`, - ); - error.code = signal == null ? 'ERR_AGENTOS_CHILD_PROCESS_EXIT' : signal; - error.killed = signal != null; - error.signal = signal; - error.stdout = stdout; - error.stderr = stderr; - if (typeof exitCode === 'number') { - error.status = exitCode; - } - return error; - }; - const createSpawnSyncTimeoutError = (command) => { - const error = new Error(`spawnSync ${command} ETIMEDOUT`); - error.code = 'ETIMEDOUT'; - return error; - }; - const createSpawnSyncResult = (pid, stdout, stderr, exitCode, signal, error, encoding) => { - const encodedStdout = encodeChildProcessOutput(stdout, encoding); - const encodedStderr = encodeChildProcessOutput(stderr, encoding); - return { - pid, - output: [null, encodedStdout, encodedStderr], - stdout: encodedStdout, - stderr: encodedStderr, - status: typeof exitCode === 'number' ? exitCode : null, - signal: signal ?? null, - error, - }; - }; - const runChildProcessSync = (command, args, options, shell = false) => { - const normalizedOptions = normalizeChildProcessOptions(options, shell); - const encoding = normalizeChildProcessEncoding(options); - const stdout = []; - const stderr = []; - let child; - try { - child = callSpawn(command, args, options, shell); - } catch (error) { - if ( - error && - typeof error === 'object' && - error.code == null && - /ERR_NATIVE_BINARY_NOT_SUPPORTED\b/i.test(String(error.message ?? error)) - ) { - error.code = 'ERR_NATIVE_BINARY_NOT_SUPPORTED'; - } - return createSpawnSyncResult( - 0, - Buffer.alloc(0), - Buffer.from(error instanceof Error ? error.message : String(error)), - null, - null, - error, - encoding, - ); - } - - const startedAt = Date.now(); - let exitCode = null; - let signal = null; - let error = null; - while (exitCode == null && signal == null) { - if ( - normalizedOptions.timeout != null && - Date.now() - startedAt > normalizedOptions.timeout - ) { - callKill(child.childId, normalizedOptions.killSignal); - signal = normalizedOptions.killSignal; - error = createSpawnSyncTimeoutError(command); - break; - } - - const event = callPoll(child.childId, RPC_POLL_WAIT_MS); - if (!event) { - continue; - } - - if (event.type === 'stdout') { - stdout.push(decodeFsBytesPayload(event.data, 'child_process.spawnSync stdout')); - } else if (event.type === 'stderr') { - stderr.push(decodeFsBytesPayload(event.data, 'child_process.spawnSync stderr')); - } else if (event.type === 'exit') { - exitCode = - typeof event.exitCode === 'number' ? Math.trunc(event.exitCode) : null; - signal = typeof event.signal === 'string' ? event.signal : null; - } - } - - const stdoutBuffer = Buffer.concat(stdout); - const stderrBuffer = Buffer.concat(stderr); - return createSpawnSyncResult( - Number(child.pid) || 0, - stdoutBuffer, - stderrBuffer, - exitCode, - signal, - error, - encoding, - ); - }; - - class SecureExecChildReadable extends Readable { - _read() {} - } - - class SecureExecChildWritable extends Writable { - constructor(childId) { - super(); - this.childId = childId; - } - - _write(chunk, encoding, callback) { - try { - callWriteStdin(this.childId, chunk); - callback(); - } catch (error) { - callback(error); - } - } - - _final(callback) { - try { - callCloseStdin(this.childId); - callback(); - } catch (error) { - callback(error); - } - } - } - - const finalizeChildStream = (stream) => { - if (!stream || stream.destroyed) { - return; - } - stream.push(null); - }; - const emitChildLifecycleEvents = (child) => { - queueMicrotask(() => { - child.emit('exit', child.exitCode, child.signalCode); - child.emit('close', child.exitCode, child.signalCode); - }); - }; - const deliverChildOutput = (child, channel, payload) => { - const chunk = decodeFsBytesPayload(payload, `child_process.${channel}`); - const mode = channel === 'stdout' ? child._stdio[1] : child._stdio[2]; - if (mode === 'ignore') { - return; - } - if (mode === 'inherit') { - (channel === 'stdout' ? process.stdout : process.stderr).write(chunk); - return; - } - - const stream = channel === 'stdout' ? child.stdout : child.stderr; - stream?.push(chunk); - }; - const closeSyntheticChild = (child, exitCode, signalCode) => { - if (child._closed) { - return; - } - child._closed = true; - child.exitCode = exitCode; - child.signalCode = signalCode; - finalizeChildStream(child.stdout); - finalizeChildStream(child.stderr); - if (child.stdin && !child.stdin.destroyed) { - child.stdin.destroy(); - } - emitChildLifecycleEvents(child); - }; - const scheduleSyntheticChildPoll = (child, delayMs) => { - if (child._closed || child._pollTimer != null) { - return; - } - child._pollTimer = setTimeout(() => { - child._pollTimer = null; - if (child._closed) { - return; - } - - let event; - try { - event = callPoll(child._childId, RPC_POLL_WAIT_MS); - } catch (error) { - child._closed = true; - finalizeChildStream(child.stdout); - finalizeChildStream(child.stderr); - queueMicrotask(() => child.emit('error', error)); - return; - } - - if (!event) { - scheduleSyntheticChildPoll(child, RPC_IDLE_POLL_DELAY_MS); - return; - } - - if (event.type === 'stdout' || event.type === 'stderr') { - deliverChildOutput(child, event.type, event.data); - scheduleSyntheticChildPoll(child, 0); - return; - } - - if (event.type === 'exit') { - closeSyntheticChild( - child, - typeof event.exitCode === 'number' ? Math.trunc(event.exitCode) : null, - typeof event.signal === 'string' ? event.signal : null, - ); - return; - } - - scheduleSyntheticChildPoll(child, 0); - }, delayMs); - if (!child._refed) { - child._pollTimer.unref?.(); - } - }; - const createSyntheticChildProcess = (spawnResult, options) => { - const child = Object.create(EventEmitter.prototype); - EventEmitter.call(child); - child._childId = spawnResult.childId; - child._closed = false; - child._pollTimer = null; - child._refed = true; - child._stdio = options.stdio; - child.pid = Math.trunc(Number(spawnResult.pid) || 0); - child.exitCode = null; - child.signalCode = null; - child.spawnfile = String(spawnResult.command ?? ''); - child.spawnargs = [ - child.spawnfile, - ...(Array.isArray(spawnResult.args) ? spawnResult.args.map(String) : []), - ]; - child.stdin = options.stdio[0] === 'pipe' ? new SecureExecChildWritable(child._childId) : null; - child.stdout = options.stdio[1] === 'pipe' ? new SecureExecChildReadable() : null; - child.stderr = options.stdio[2] === 'pipe' ? new SecureExecChildReadable() : null; - child.killed = false; - child.connected = false; - child.kill = (signal = 'SIGTERM') => { - try { - callKill(child._childId, signal); - child.killed = true; - return true; - } catch (error) { - if (error && typeof error === 'object' && error.code === 'ESRCH') { - return false; - } - throw error; - } - }; - child.ref = () => { - child._refed = true; - child._pollTimer?.ref?.(); - return child; - }; - child.unref = () => { - child._refed = false; - child._pollTimer?.unref?.(); - return child; - }; - child.disconnect = () => { - throw createUnsupportedChildProcessError('child_process.disconnect'); - }; - child.send = () => { - throw createUnsupportedChildProcessError('child_process.send'); - }; - queueMicrotask(() => child.emit('spawn')); - scheduleSyntheticChildPoll(child, 0); - return child; - }; - const collectSyntheticChildOutput = (child, options, callback) => { - const encoding = normalizeChildProcessEncoding(options) ?? 'utf8'; - const stdoutChunks = []; - const stderrChunks = []; - const timeout = normalizeChildProcessTimeout(options); - const killSignal = normalizeChildProcessSignal(options?.killSignal); - let timer = null; - - if (child.stdout) { - child.stdout.on('data', (chunk) => { - stdoutChunks.push(Buffer.from(chunk)); - }); - } - if (child.stderr) { - child.stderr.on('data', (chunk) => { - stderrChunks.push(Buffer.from(chunk)); - }); - } - - const promise = new Promise((resolve, reject) => { - if (timeout != null) { - timer = setTimeout(() => { - try { - child.kill(killSignal); - } catch {} - }, timeout); - timer.unref?.(); - } - - child.once('error', reject); - child.once('close', (exitCode, signalCode) => { - if (timer) { - clearTimeout(timer); - } - const stdout = encodeChildProcessOutput(Buffer.concat(stdoutChunks), encoding); - const stderr = encodeChildProcessOutput(Buffer.concat(stderrChunks), encoding); - if (exitCode === 0 && signalCode == null) { - resolve({ stdout, stderr, exitCode, signalCode }); - return; - } - reject(createChildProcessExecError('child_process', exitCode, signalCode, stdout, stderr)); - }); - }); - - if (typeof callback === 'function') { - promise.then( - ({ stdout, stderr }) => callback(null, stdout, stderr), - (error) => callback(error, error.stdout, error.stderr), - ); - } - - return promise; - }; - - const module = { - ChildProcess: EventEmitter, - spawn(command, args, options) { - const invocation = normalizeSpawnInvocation(args, options); - const normalizedOptions = normalizeChildProcessOptions(invocation.options); - let spawnResult; - try { - spawnResult = callSpawn(command, invocation.args, invocation.options); - } catch (error) { - const spawnError = error instanceof Error ? error : new Error(String(error)); - if ( - spawnError.code == null && - /command not found:/i.test(String(spawnError.message ?? '')) - ) { - spawnError.code = 'ENOENT'; - } else if ( - spawnError.code == null && - /ERR_NATIVE_BINARY_NOT_SUPPORTED\b/i.test(String(spawnError.message ?? '')) - ) { - spawnError.code = 'ERR_NATIVE_BINARY_NOT_SUPPORTED'; - } - const child = Object.create(EventEmitter.prototype); - EventEmitter.call(child); - child.spawnfile = String(command); - child.spawnargs = [String(command), ...invocation.args.map(String)]; - child.stdin = null; - child.stdout = null; - child.stderr = null; - child.stdio = [null, null, null]; - child.pid = 0; - child.exitCode = null; - child.signalCode = null; - child.killed = false; - child.connected = false; - child.kill = () => false; - child.ref = () => child; - child.unref = () => child; - child.disconnect = () => { - throw createUnsupportedChildProcessError('child_process.disconnect'); - }; - child.send = () => { - throw createUnsupportedChildProcessError('child_process.send'); - }; - queueMicrotask(() => child.emit('error', spawnError)); - return child; - } - const child = createSyntheticChildProcess(spawnResult, normalizedOptions); - return child; - }, - spawnSync(command, args, options) { - const invocation = normalizeSpawnInvocation(args, options); - return runChildProcessSync(command, invocation.args, invocation.options); - }, - exec(command, options, callback) { - const invocation = normalizeExecInvocation(options, callback); - const child = module.spawn(command, [], { - ...invocation.options, - stdio: ['pipe', 'pipe', 'pipe'], - shell: true, - }); - collectSyntheticChildOutput(child, invocation.options, invocation.callback); - return child; - }, - execSync(command, options) { - const result = runChildProcessSync(command, [], { - ...options, - stdio: ['pipe', 'pipe', 'pipe'], - }, true); - if (result.error) { - throw result.error; - } - if (result.status !== 0 || result.signal != null) { - throw createChildProcessExecError( - 'child_process.execSync', - result.status, - result.signal, - result.stdout, - result.stderr, - ); - } - return result.stdout; - }, - execFile(file, args, options, callback) { - const invocation = normalizeExecFileInvocation(args, options, callback); - const child = module.spawn(file, invocation.args, { - ...invocation.options, - stdio: ['pipe', 'pipe', 'pipe'], - }); - collectSyntheticChildOutput(child, invocation.options, invocation.callback); - return child; - }, - execFileSync(file, args, options) { - const invocation = normalizeExecFileInvocation(args, options); - const result = runChildProcessSync(file, invocation.args, { - ...invocation.options, - stdio: ['pipe', 'pipe', 'pipe'], - }); - if (result.error) { - throw result.error; - } - if (result.status !== 0 || result.signal != null) { - throw createChildProcessExecError( - 'child_process.execFileSync', - result.status, - result.signal, - result.stdout, - result.stderr, - ); - } - return result.stdout; - }, - fork(modulePath, args, options) { - const invocation = normalizeSpawnInvocation(args, options); - return module.spawn('node', [modulePath, ...invocation.args], { - ...invocation.options, - stdio: invocation.options?.stdio ?? ['pipe', 'pipe', 'pipe'], - }); - }, - }; - - return module; -} - -function createRpcBackedNetModule(netModule, fromGuestDir = '/') { - const RPC_POLL_WAIT_MS = 50; - const RPC_IDLE_POLL_DELAY_MS = 10; - const bridge = () => requireSecureExecSyncRpcBridge(); - let defaultAutoSelectFamily = - typeof netModule?.getDefaultAutoSelectFamily === 'function' - ? netModule.getDefaultAutoSelectFamily() - : true; - let defaultAutoSelectFamilyAttemptTimeout = - typeof netModule?.getDefaultAutoSelectFamilyAttemptTimeout === 'function' - ? netModule.getDefaultAutoSelectFamilyAttemptTimeout() - : 250; - const createUnsupportedNetError = (subject) => { - const error = new Error(`${subject} is not supported by the secure-exec net polyfill yet`); - error.code = 'ERR_AGENTOS_NET_UNSUPPORTED'; - return error; - }; - const normalizeNetPort = (value) => { - const numeric = - typeof value === 'number' - ? value - : typeof value === 'string' && value.length > 0 - ? Number(value) - : Number.NaN; - if (!Number.isInteger(numeric) || numeric < 0 || numeric > 65535) { - throw new RangeError(`secure-exec net port must be an integer between 0 and 65535`); - } - return numeric; - }; - const normalizeNetBacklog = (value) => { - const numeric = - typeof value === 'number' - ? value - : typeof value === 'string' && value.length > 0 - ? Number(value) - : Number.NaN; - if (!Number.isInteger(numeric) || numeric < 0) { - throw new RangeError(`secure-exec net backlog must be a non-negative integer`); - } - return numeric; - }; - const normalizeNetConnectInvocation = (args) => { - const values = [...args]; - const callback = - typeof values[values.length - 1] === 'function' ? values.pop() : undefined; - - let options; - if (values[0] != null && typeof values[0] === 'object') { - options = { ...values[0] }; - } else { - options = { port: values[0] }; - if (typeof values[1] === 'string') { - options.host = values[1]; - } - } - - if (options?.lookup != null) { - throw createUnsupportedNetError('net.connect({ lookup })'); - } - - if (typeof options?.path === 'string' && options.path.length > 0) { - return { - callback, - options: { - allowHalfOpen: options?.allowHalfOpen === true, - path: resolveGuestFsPath(options.path, fromGuestDir), - }, - }; - } - - return { - callback, - options: { - allowHalfOpen: options?.allowHalfOpen === true, - host: - typeof options?.host === 'string' && options.host.length > 0 - ? options.host - : 'localhost', - port: normalizeNetPort(options?.port), - }, - }; - }; - const normalizeNetServerCreation = (args) => { - let options = {}; - let connectionListener; - - if (typeof args[0] === 'function') { - connectionListener = args[0]; - } else { - if (args[0] != null) { - if (typeof args[0] !== 'object') { - throw new TypeError('net.createServer options must be an object'); - } - options = { ...args[0] }; - } - if (typeof args[1] === 'function') { - connectionListener = args[1]; - } - } - - return { - connectionListener, - options: { - allowHalfOpen: options.allowHalfOpen === true, - pauseOnConnect: options.pauseOnConnect === true, - }, - }; - }; - const normalizeNetListenInvocation = (args) => { - const values = [...args]; - const callback = - typeof values[values.length - 1] === 'function' ? values.pop() : undefined; - - let backlog; - if (typeof values[values.length - 1] === 'number') { - backlog = normalizeNetBacklog(values.pop()); - } - - let options; - if (values[0] != null && typeof values[0] === 'object') { - options = { ...values[0] }; - } else { - options = { port: values[0] }; - if (typeof values[1] === 'string') { - options.host = values[1]; - } - } - - if (options?.signal != null) { - throw createUnsupportedNetError('net.Server.listen({ signal })'); - } - - if (typeof options?.path === 'string' && options.path.length > 0) { - return { - callback, - options: { - backlog: - options?.backlog != null - ? normalizeNetBacklog(options.backlog) - : backlog, - path: resolveGuestFsPath(options.path, fromGuestDir), - }, - }; - } - - return { - callback, - options: { - backlog: - options?.backlog != null - ? normalizeNetBacklog(options.backlog) - : backlog, - host: - typeof options?.host === 'string' && options.host.length > 0 - ? options.host - : '127.0.0.1', - port: normalizeNetPort(options?.port ?? 0), - }, - }; - }; - const socketFamilyForAddress = (value) => { - if (typeof value !== 'string') { - return undefined; - } - return value.includes(':') ? 'IPv6' : 'IPv4'; - }; - const callConnect = (options) => bridge().callSync('net.connect', [options]); - const callListen = (options) => bridge().callSync('net.listen', [options]); - const callPoll = (socketId, waitMs = 0) => bridge().callSync('net.poll', [socketId, waitMs]); - const callServerPoll = (serverId, waitMs = 0) => - bridge().callSync('net.server_poll', [serverId, waitMs]); - const callServerConnections = (serverId) => - bridge().callSync('net.server_connections', [serverId]); - const callWrite = (socketId, chunk) => - bridge().call('net.write', [socketId, toGuestBufferView(chunk, 'net.write chunk')]); - const callShutdown = (socketId) => bridge().call('net.shutdown', [socketId]); - const callDestroy = (socketId) => bridge().call('net.destroy', [socketId]); - const callServerClose = (serverId) => bridge().call('net.server_close', [serverId]); - - const releaseSocketBridge = (socket) => { - if (socket._agentOSBridgeReleased || socket._agentOSSocketId == null) { - return Promise.resolve(); - } - const socketId = socket._agentOSSocketId; - socket._agentOSBridgeReleased = true; - return callDestroy(socketId).catch(() => {}); - }; - - const finalizeSocketClose = (socket, hadError = false) => { - if (socket._agentOSClosed) { - return; - } - void releaseSocketBridge(socket); - socket._agentOSClosed = true; - socket._agentOSCloseHadError = hadError === true; - socket._agentOSSocketId = null; - socket.connecting = false; - socket.pending = false; - socket._pollTimer && clearTimeout(socket._pollTimer); - socket._pollTimer = null; - if (!socket.readableEnded) { - socket.push(null); - } - queueMicrotask(() => socket.emit('close', hadError)); - }; - const finalizeSocketCloseAfterReadableEnd = (socket, hadError = false) => { - if (socket._agentOSClosed) { - return; - } - if (socket.readableEnded) { - finalizeSocketClose(socket, hadError); - return; - } - socket.once('end', () => finalizeSocketClose(socket, hadError)); - }; - - const scheduleSocketPoll = (socket, delayMs) => { - if (socket._agentOSClosed || socket._agentOSSocketId == null || socket._pollTimer != null) { - return; - } - - socket._pollTimer = setTimeout(() => { - socket._pollTimer = null; - if (socket._agentOSClosed || socket._agentOSSocketId == null) { - return; - } - - let event; - try { - event = callPoll(socket._agentOSSocketId, RPC_POLL_WAIT_MS); - } catch (error) { - socket.destroy(error); - return; - } - - if (!event) { - scheduleSocketPoll(socket, RPC_IDLE_POLL_DELAY_MS); - return; - } - - if (event.type === 'data') { - const chunk = decodeFsBytesPayload(event.data, 'net.data'); - socket.bytesRead += chunk.length; - socket.push(chunk); - scheduleSocketPoll(socket, 0); - return; - } - - if (event.type === 'end') { - socket._agentOSRemoteEnded = true; - finalizeSocketCloseAfterReadableEnd(socket, false); - socket.push(null); - if (!socket._agentOSAllowHalfOpen && !socket.writableEnded) { - socket.end(); - } - scheduleSocketPoll(socket, 0); - return; - } - - if (event.type === 'error') { - const error = new Error( - typeof event.message === 'string' ? event.message : 'secure-exec net socket error', - ); - if (typeof event.code === 'string' && event.code.length > 0) { - error.code = event.code; - } - socket.emit('error', error); - scheduleSocketPoll(socket, 0); - return; - } - - if (event.type === 'close') { - finalizeSocketClose(socket, event.hadError === true); - return; - } - - scheduleSocketPoll(socket, 0); - }, delayMs); - - if (!socket._agentOSRefed) { - socket._pollTimer.unref?.(); - } - }; - const attachSocketState = (socket, result, options = {}, emitConnect = false) => { - socket._agentOSAllowHalfOpen = options.allowHalfOpen === true; - socket._agentOSSocketId = String(result.socketId); - socket.localPath = - typeof result.localPath === 'string' - ? result.localPath - : typeof result.path === 'string' - ? result.path - : undefined; - socket.remotePath = - typeof result.remotePath === 'string' - ? result.remotePath - : typeof result.path === 'string' - ? result.path - : undefined; - socket.localAddress = - socket.localPath ?? result.localAddress; - socket.localPort = result.localPort; - socket.remoteAddress = - socket.remotePath ?? result.remoteAddress; - socket.remotePort = result.remotePort; - socket.remoteFamily = - socket.remotePath != null - ? undefined - : result.remoteFamily ?? socketFamilyForAddress(socket.remoteAddress); - socket.connecting = false; - socket.pending = false; - socket._agentOSClosed = false; - socket._agentOSRemoteEnded = false; - socket._agentOSBridgeReleased = false; - if (emitConnect) { - queueMicrotask(() => { - if (socket._agentOSClosed) { - return; - } - socket.emit('connect'); - socket.emit('ready'); - }); - } - scheduleSocketPoll(socket, 0); - }; - - class SecureExecSocket extends Duplex { - constructor(options = undefined) { - super(options); - this._agentOSAllowHalfOpen = options?.allowHalfOpen === true; - this._agentOSClosed = false; - this._agentOSCloseHadError = false; - this._agentOSExplicitDestroy = false; - this._agentOSRemoteEnded = false; - this._agentOSBridgeReleased = false; - this._agentOSRefed = true; - this._agentOSSocketId = null; - this._pollTimer = null; - this.bytesRead = 0; - this.bytesWritten = 0; - this.connecting = false; - this.pending = false; - this.localAddress = undefined; - this.localPort = undefined; - this.localPath = undefined; - this.remoteAddress = undefined; - this.remoteFamily = undefined; - this.remotePort = undefined; - this.remotePath = undefined; - this.emit = (eventName, ...eventArgs) => { - if (eventName === 'close' && eventArgs.length === 0 && this._agentOSClosed) { - eventArgs = [this._agentOSCloseHadError === true]; - } - return Duplex.prototype.emit.call(this, eventName, ...eventArgs); - }; - this.destroy = (error) => { - this._agentOSExplicitDestroy = true; - return Duplex.prototype.destroy.call(this, error); - }; - } - - _read() {} - - _write(chunk, encoding, callback) { - if (this._agentOSSocketId == null) { - callback(new Error('secure-exec net socket is not connected')); - return; - } - const payload = - typeof chunk === 'string' ? Buffer.from(chunk, encoding) : Buffer.from(chunk); - callWrite(this._agentOSSocketId, payload).then( - (written) => { - if (typeof written === 'number') { - this.bytesWritten += written; - } else { - this.bytesWritten += payload.length; - } - callback(); - }, - (error) => callback(error), - ); - } - - _final(callback) { - if (this._agentOSSocketId == null || this._agentOSClosed) { - callback(); - return; - } - callShutdown(this._agentOSSocketId).then( - () => { - if (this._agentOSRemoteEnded) { - finalizeSocketCloseAfterReadableEnd(this, false); - } - callback(); - }, - (error) => callback(error), - ); - } - - _destroy(error, callback) { - const socketId = this._agentOSSocketId; - this._agentOSSocketId = null; - const finishDestroy = () => { - finalizeSocketClose(this, Boolean(error)); - callback(error); - }; - if ( - socketId == null || - this._agentOSClosed - ) { - finishDestroy(); - return; - } - this._agentOSSocketId = socketId; - releaseSocketBridge(this).then(finishDestroy, () => finishDestroy()); - } - - address() { - if (typeof this.localPath === 'string') { - return this.localPath; - } - if (typeof this.localAddress !== 'string' || typeof this.localPort !== 'number') { - return null; - } - return { - address: this.localAddress, - family: socketFamilyForAddress(this.localAddress), - port: this.localPort, - }; - } - - connect(...args) { - const { callback, options } = normalizeNetConnectInvocation(args); - if (typeof callback === 'function') { - this.once('connect', callback); - } - if (this._agentOSSocketId != null || this.connecting) { - throw new Error('secure-exec net socket is already connected'); - } - - this._agentOSAllowHalfOpen = options.allowHalfOpen; - this.connecting = true; - this.pending = true; - - try { - const result = callConnect(options); - attachSocketState( - this, - { - ...result, - remotePath: result.remotePath ?? options.path, - remoteAddress: result.remoteAddress ?? options.host, - remotePort: result.remotePort ?? options.port, - }, - options, - true, - ); - } catch (error) { - this.connecting = false; - this.pending = false; - this.destroy(error); - } - - return this; - } - - ref() { - this._agentOSRefed = true; - this._pollTimer?.ref?.(); - return this; - } - - unref() { - this._agentOSRefed = false; - this._pollTimer?.unref?.(); - return this; - } - - setKeepAlive() { - return this; - } - - setNoDelay() { - return this; - } - - setTimeout(timeout, callback) { - if (typeof callback === 'function') { - if (Number(timeout) > 0) { - setTimeout(() => { - if (!this._agentOSClosed) { - this.emit('timeout'); - callback(); - } - }, Number(timeout)).unref?.(); - } else { - queueMicrotask(() => callback()); - } - } - return this; - } - } - - const finalizeServerClose = (server) => { - if (server._agentOSClosed) { - return; - } - server._agentOSClosed = true; - server.listening = false; - server._agentOSServerId = null; - server._pollTimer && clearTimeout(server._pollTimer); - server._pollTimer = null; - queueMicrotask(() => server.emit('close')); - }; - const scheduleServerPoll = (server, delayMs) => { - if (server._agentOSClosed || server._agentOSServerId == null || server._pollTimer != null) { - return; - } - - server._pollTimer = setTimeout(() => { - server._pollTimer = null; - if (server._agentOSClosed || server._agentOSServerId == null) { - return; - } - - let event; - try { - event = callServerPoll(server._agentOSServerId, RPC_POLL_WAIT_MS); - } catch (error) { - server.emit('error', error); - finalizeServerClose(server); - return; - } - - if (!event) { - scheduleServerPoll(server, RPC_IDLE_POLL_DELAY_MS); - return; - } - - if (event.type === 'connection') { - const socket = new SecureExecSocket({ allowHalfOpen: server.allowHalfOpen }); - attachSocketState(socket, event, { allowHalfOpen: server.allowHalfOpen }); - if (server.pauseOnConnect) { - socket.pause(); - } - server.emit('connection', socket); - scheduleServerPoll(server, 0); - return; - } - - if (event.type === 'error') { - const error = new Error( - typeof event.message === 'string' ? event.message : 'secure-exec net server error', - ); - if (typeof event.code === 'string' && event.code.length > 0) { - error.code = event.code; - } - server.emit('error', error); - scheduleServerPoll(server, 0); - return; - } - - if (event.type === 'close') { - finalizeServerClose(server); - return; - } - - scheduleServerPoll(server, 0); - }, delayMs); - - if (!server._agentOSRefed) { - server._pollTimer.unref?.(); - } - }; - - class SecureExecServer extends EventEmitter { - constructor(options = {}, connectionListener = undefined) { - super(); - this.allowHalfOpen = options.allowHalfOpen === true; - this.pauseOnConnect = options.pauseOnConnect === true; - this.listening = false; - this.maxConnections = undefined; - this._agentOSClosed = false; - this._agentOSRefed = true; - this._agentOSServerId = null; - this._pollTimer = null; - this._address = null; - if (typeof connectionListener === 'function') { - this.on('connection', connectionListener); - } - } - - address() { - return this._address; - } - - close(callback) { - if (this._agentOSServerId == null || this._agentOSClosed) { - const error = new Error('secure-exec net server is not running'); - error.code = 'ERR_SERVER_NOT_RUNNING'; - if (typeof callback === 'function') { - queueMicrotask(() => callback(error)); - return this; - } - throw error; - } - - if (typeof callback === 'function') { - this.once('close', callback); - } - const serverId = this._agentOSServerId; - callServerClose(serverId).then( - () => finalizeServerClose(this), - (error) => this.emit('error', error), - ); - return this; - } - - getConnections(callback) { - if (this._agentOSServerId == null || this._agentOSClosed) { - const error = new Error('secure-exec net server is not running'); - error.code = 'ERR_SERVER_NOT_RUNNING'; - if (typeof callback === 'function') { - queueMicrotask(() => callback(error)); - return this; - } - throw error; - } - - try { - const count = callServerConnections(this._agentOSServerId); - if (typeof callback === 'function') { - queueMicrotask(() => callback(null, count)); - } - } catch (error) { - if (typeof callback === 'function') { - queueMicrotask(() => callback(error)); - return this; - } - throw error; - } - - return this; - } - - listen(...args) { - const { callback, options } = normalizeNetListenInvocation(args); - if (typeof callback === 'function') { - this.once('listening', callback); - } - if (this._agentOSServerId != null || this.listening) { - throw new Error('secure-exec net server is already listening'); - } - - this._agentOSClosed = false; - try { - const result = callListen(options); - this._agentOSServerId = String(result.serverId); - this._address = - typeof result.path === 'string' - ? result.path - : { - address: result.localAddress, - family: result.family ?? socketFamilyForAddress(result.localAddress), - port: result.localPort, - }; - this.listening = true; - queueMicrotask(() => { - if (this._agentOSClosed) { - return; - } - this.emit('listening'); - }); - scheduleServerPoll(this, 0); - } catch (error) { - this._agentOSServerId = null; - this._address = null; - this.listening = false; - throw error; - } - - return this; - } - - ref() { - this._agentOSRefed = true; - this._pollTimer?.ref?.(); - return this; - } - - unref() { - this._agentOSRefed = false; - this._pollTimer?.unref?.(); - return this; - } - } - - const connect = (...args) => new SecureExecSocket().connect(...args); - const createServer = (...args) => { - const { connectionListener, options } = normalizeNetServerCreation(args); - return new SecureExecServer(options, connectionListener); - }; - const module = Object.assign(Object.create(netModule ?? null), { - BlockList: - typeof netModule?.BlockList === 'function' - ? netModule.BlockList - : class BlockList { - addAddress() { - return this; - } - - addRange() { - return this; - } - - addSubnet() { - return this; - } - - check() { - return false; - } - - rules() { - return []; - } - - toJSON() { - return []; - } - }, - Server: SecureExecServer, - Socket: SecureExecSocket, - SocketAddress: netModule?.SocketAddress, - Stream: SecureExecSocket, - connect, - createConnection: connect, - createServer, - getDefaultAutoSelectFamily() { - return defaultAutoSelectFamily; - }, - getDefaultAutoSelectFamilyAttemptTimeout() { - return defaultAutoSelectFamilyAttemptTimeout; - }, - isIP: netModule?.isIP?.bind(netModule) ?? hostNet.isIP.bind(hostNet), - isIPv4: netModule?.isIPv4?.bind(netModule) ?? hostNet.isIPv4.bind(hostNet), - isIPv6: netModule?.isIPv6?.bind(netModule) ?? hostNet.isIPv6.bind(hostNet), - setDefaultAutoSelectFamily(value) { - defaultAutoSelectFamily = value !== false; - netModule?.setDefaultAutoSelectFamily?.(defaultAutoSelectFamily); - }, - setDefaultAutoSelectFamilyAttemptTimeout(value) { - const numeric = Number(value); - if (!Number.isFinite(numeric) || numeric < 0) { - throw new RangeError(`Invalid auto-select family attempt timeout: ${value}`); - } - defaultAutoSelectFamilyAttemptTimeout = Math.trunc(numeric); - netModule?.setDefaultAutoSelectFamilyAttemptTimeout?.( - defaultAutoSelectFamilyAttemptTimeout, - ); - }, - }); - - return module; -} - -function createRpcBackedTlsModule(tlsModule, netModule) { - const createUnsupportedTlsError = (subject) => { - const error = new Error(`${subject} is not supported by the secure-exec tls polyfill yet`); - error.code = 'ERR_AGENTOS_TLS_UNSUPPORTED'; - return error; - }; - const defineSocketMetadataPassthrough = (tlsSocket, rawSocket) => { - if (tlsSocket === rawSocket) { - return; - } - for (const key of ['localAddress', 'localPort', 'remoteAddress', 'remotePort', 'remoteFamily']) { - try { - Object.defineProperty(tlsSocket, key, { - configurable: true, - enumerable: true, - get() { - return rawSocket[key]; - }, - set(value) { - rawSocket[key] = value; - }, - }); - } catch { - // Ignore non-configurable host properties. - } - } - }; - const normalizeTlsPort = (value) => { - const numeric = - typeof value === 'number' - ? value - : typeof value === 'string' && value.length > 0 - ? Number(value) - : Number.NaN; - if (!Number.isInteger(numeric) || numeric < 0 || numeric > 65535) { - throw new RangeError('secure-exec tls port must be between 0 and 65535'); - } - return numeric; - }; - const normalizeTlsConnectInvocation = (args) => { - const values = [...args]; - const callback = - typeof values[values.length - 1] === 'function' ? values.pop() : undefined; - - let options; - if (values[0] != null && typeof values[0] === 'object') { - options = { ...values[0] }; - } else { - const positional = {}; - if (values.length > 0) { - positional.port = values.shift(); - } - if (typeof values[0] === 'string') { - positional.host = values.shift(); - } - const providedOptions = - values[0] != null && typeof values[0] === 'object' ? { ...values[0] } : {}; - options = { ...providedOptions, ...positional }; - } - - if (typeof options?.path === 'string') { - throw createUnsupportedTlsError('tls.connect({ path })'); - } - if (options?.lookup != null) { - throw createUnsupportedTlsError('tls.connect({ lookup })'); - } - - const transportSocket = options?.socket ?? null; - const host = - typeof options?.host === 'string' && options.host.length > 0 - ? options.host - : 'localhost'; - const tlsOptions = { ...options }; - delete tlsOptions.allowHalfOpen; - delete tlsOptions.host; - delete tlsOptions.lookup; - delete tlsOptions.path; - delete tlsOptions.port; - delete tlsOptions.socket; - if ( - typeof tlsOptions.servername !== 'string' && - typeof host === 'string' && - host.length > 0 && - hostNet.isIP(host) === 0 - ) { - tlsOptions.servername = host; - } - if (tlsOptions.ALPNProtocols == null) { - tlsOptions.ALPNProtocols = ['http/1.1']; - } - - return { - callback, - transportOptions: - transportSocket == null - ? { - allowHalfOpen: options?.allowHalfOpen === true, - host, - port: normalizeTlsPort(options?.port), - } - : null, - transportSocket, - tlsOptions, - }; - }; - const normalizeTlsServerCreation = (args) => { - let options = {}; - let secureConnectionListener; - - if (typeof args[0] === 'function') { - secureConnectionListener = args[0]; - } else { - if (args[0] != null) { - if (typeof args[0] !== 'object') { - throw new TypeError('tls.createServer options must be an object'); - } - options = { ...args[0] }; - } - if (typeof args[1] === 'function') { - secureConnectionListener = args[1]; - } - } - - return { - secureConnectionListener, - options, - }; - }; - const createServerSecureContext = (options) => - options?.secureContext ?? tlsModule.createSecureContext(options ?? {}); - const createClientTlsSocket = (rawSocket, tlsOptions) => { - const tlsSocket = tlsModule.connect({ - ...tlsOptions, - socket: rawSocket, - }); - defineSocketMetadataPassthrough(tlsSocket, rawSocket); - return tlsSocket; - }; - const createServerTlsSocket = (rawSocket, options, secureContext) => { - const tlsSocket = new tlsModule.TLSSocket(rawSocket, { - ...options, - isServer: true, - secureContext, - }); - defineSocketMetadataPassthrough(tlsSocket, rawSocket); - return tlsSocket; - }; - - class SecureExecTlsServer extends EventEmitter { - constructor(options = {}, secureConnectionListener = undefined) { - super(); - this._tlsOptions = { ...options }; - this._secureContext = createServerSecureContext(this._tlsOptions); - this._netServer = netModule.createServer( - { - allowHalfOpen: options.allowHalfOpen === true, - pauseOnConnect: options.pauseOnConnect === true, - }, - (socket) => { - const tlsSocket = createServerTlsSocket(socket, this._tlsOptions, this._secureContext); - tlsSocket.on('secure', () => { - this.emit('secureConnection', tlsSocket); - }); - tlsSocket.on('error', (error) => { - this.emit('tlsClientError', error, tlsSocket); - }); - }, - ); - if (typeof secureConnectionListener === 'function') { - this.on('secureConnection', secureConnectionListener); - } - this._netServer.on('close', () => this.emit('close')); - this._netServer.on('error', (error) => this.emit('error', error)); - this._netServer.on('listening', () => this.emit('listening')); - - Object.defineProperties(this, { - listening: { - enumerable: true, - get: () => this._netServer.listening, - }, - maxConnections: { - enumerable: true, - get: () => this._netServer.maxConnections, - set: (value) => { - this._netServer.maxConnections = value; - }, - }, - }); - } - - address() { - return this._netServer.address(); - } - - close(callback) { - this._netServer.close(callback); - return this; - } - - getConnections(callback) { - return this._netServer.getConnections(callback); - } - - listen(...args) { - this._netServer.listen(...args); - return this; - } - - ref() { - this._netServer.ref(); - return this; - } - - setSecureContext(options) { - if (options == null || typeof options !== 'object') { - throw new TypeError('tls.Server.setSecureContext options must be an object'); - } - this._tlsOptions = { ...options }; - this._secureContext = createServerSecureContext(this._tlsOptions); - return this; - } - - unref() { - this._netServer.unref(); - return this; - } - } - - const connect = (...args) => { - const { callback, transportOptions, transportSocket, tlsOptions } = - normalizeTlsConnectInvocation(args); - const rawSocket = - transportSocket ?? - netModule.connect({ - allowHalfOpen: transportOptions.allowHalfOpen, - host: transportOptions.host, - port: transportOptions.port, - }); - const tlsSocket = createClientTlsSocket(rawSocket, tlsOptions); - if (typeof callback === 'function') { - tlsSocket.once('secureConnect', callback); - } - return tlsSocket; - }; - const createServer = (...args) => { - const { options, secureConnectionListener } = normalizeTlsServerCreation(args); - return new SecureExecTlsServer(options, secureConnectionListener); - }; - const module = Object.assign(Object.create(tlsModule ?? null), { - Server: SecureExecTlsServer, - TLSSocket: tlsModule.TLSSocket, - connect, - createConnection: connect, - createServer, - }); - - return module; -} - -function createTransportBackedServer( - hostServer, - transportServer, - connectionEventName, - forwardedEvents = [], -) { - const forward = (sourceEvent, targetEvent = sourceEvent) => { - transportServer.on(sourceEvent, (...args) => { - hostServer.emit(targetEvent, ...args); - }); - }; - - forward(connectionEventName); - forward('close'); - forward('error'); - forward('listening'); - for (const entry of forwardedEvents) { - if (Array.isArray(entry)) { - forward(entry[0], entry[1] ?? entry[0]); - } else { - forward(entry); - } - } - - const definePassthroughProperty = (property, getter, setter = undefined) => { - try { - Object.defineProperty(hostServer, property, { - configurable: true, - enumerable: true, - get: getter, - set: setter, - }); - } catch { - // Ignore host properties that reject redefinition. - } - }; - - hostServer.address = () => transportServer.address(); - hostServer.close = (callback) => { - transportServer.close(callback); - return hostServer; - }; - hostServer.getConnections = (callback) => transportServer.getConnections(callback); - hostServer.listen = (...args) => { - transportServer.listen(...args); - return hostServer; - }; - hostServer.ref = () => { - transportServer.ref(); - return hostServer; - }; - hostServer.unref = () => { - transportServer.unref(); - return hostServer; - }; - - definePassthroughProperty('listening', () => transportServer.listening); - definePassthroughProperty( - 'maxConnections', - () => transportServer.maxConnections, - (value) => { - transportServer.maxConnections = value; - }, - ); - - return hostServer; -} - -function normalizeHttpPort(value, subject = 'secure-exec http port') { - const numeric = - typeof value === 'number' - ? value - : typeof value === 'string' && value.length > 0 - ? Number(value) - : Number.NaN; - if (!Number.isInteger(numeric) || numeric < 0 || numeric > 65535) { - throw new RangeError(`${subject} must be an integer between 0 and 65535`); - } - return numeric; -} - -function defaultPortForProtocol(protocol) { - switch (protocol) { - case 'https:': - return 443; - case 'http2:': - case 'http:': - default: - return 80; - } -} - -function parseRequestTargetFromHostOption(value, protocol) { - if (typeof value !== 'string' || value.length === 0) { - return null; - } - if (hostNet.isIP(value) !== 0) { - return { - hostname: value, - port: null, - }; - } - - const looksLikeHostPort = - value.startsWith('[') || /^[^:]+:\d+$/.test(value); - if (!looksLikeHostPort) { - return { - hostname: value, - port: null, - }; - } - - try { - const parsed = new URL(`${protocol}//${value}`); - return { - hostname: parsed.hostname || 'localhost', - port: - parsed.port.length > 0 ? normalizeHttpPort(parsed.port) : null, - }; - } catch { - return { - hostname: value, - port: null, - }; - } -} - -function parseRequestTargetFromUrl(value, defaultProtocol) { - if (!(value instanceof URL) && typeof value !== 'string') { - return null; - } - - const parsed = value instanceof URL ? value : new URL(String(value)); - const protocol = - typeof parsed.protocol === 'string' && parsed.protocol.length > 0 - ? parsed.protocol - : defaultProtocol; - const auth = - parsed.username.length > 0 || parsed.password.length > 0 - ? `${decodeURIComponent(parsed.username)}:${decodeURIComponent(parsed.password)}` - : undefined; - return { - protocol, - hostname: parsed.hostname || 'localhost', - port: - parsed.port.length > 0 - ? normalizeHttpPort(parsed.port) - : defaultPortForProtocol(protocol), - path: `${parsed.pathname || '/'}${parsed.search || ''}`, - auth, - }; -} - -function createRpcBackedHttpModule(httpModule, transportModule, defaultProtocol = 'http:') { - const debugHttpLog = (...args) => { - console.error('[agentos http polyfill]', ...args); - }; - const createUnsupportedHttpError = (subject) => { - const error = new Error(`${subject} is not supported by the secure-exec http polyfill yet`); - error.code = 'ERR_AGENTOS_HTTP_UNSUPPORTED'; - return error; - }; - const normalizeRequestInvocation = (args) => { - const values = [...args]; - const callback = - typeof values[values.length - 1] === 'function' ? values.pop() : undefined; - - let options = {}; - if (values[0] instanceof URL || typeof values[0] === 'string') { - options = { - ...options, - ...parseRequestTargetFromUrl(values.shift(), defaultProtocol), - }; - } - if (values[0] != null) { - if (typeof values[0] !== 'object') { - throw new TypeError('secure-exec http request options must be an object'); - } - options = { - ...options, - ...values[0], - }; - } - - if (typeof options.socketPath === 'string') { - throw createUnsupportedHttpError('http request socketPath'); - } - if (options.lookup != null) { - throw createUnsupportedHttpError('http request lookup'); - } - - const protocol = - typeof options.protocol === 'string' && options.protocol.length > 0 - ? options.protocol - : defaultProtocol; - const hostTarget = parseRequestTargetFromHostOption(options.host, protocol); - const hostname = - typeof options.hostname === 'string' && options.hostname.length > 0 - ? options.hostname - : hostTarget?.hostname ?? 'localhost'; - const port = - options.port != null - ? normalizeHttpPort(options.port) - : hostTarget?.port ?? defaultPortForProtocol(protocol); - const path = - typeof options.path === 'string' && options.path.length > 0 - ? options.path - : '/'; - const requestOptions = { - ...options, - protocol, - hostname, - port, - path, - agent: false, - }; - delete requestOptions.agent; - delete requestOptions.createConnection; - delete requestOptions.host; - delete requestOptions.lookup; - delete requestOptions.socketPath; - - return { - callback, - requestOptions, - connectionOptions: { - allowHalfOpen: options.allowHalfOpen === true, - family: options.family, - host: hostname, - localAddress: options.localAddress, - port, - }, - }; - }; - const createRequest = (options, callback) => { - class SecureExecHttpAgent extends httpModule.Agent { - createConnection() { - return transportModule.connect(options.connectionOptions); - } - } - - const agent = new SecureExecHttpAgent({ keepAlive: false }); - const request = httpModule.request( - { - ...options.requestOptions, - agent, - }, - callback, - ); - debugHttpLog('http.request', JSON.stringify(options.requestOptions)); - request.on('socket', (socket) => { - debugHttpLog('http.socket'); - socket?.once?.('connect', () => debugHttpLog('http.socket.connect')); - socket?.once?.('secureConnect', () => debugHttpLog('http.socket.secureConnect')); - socket?.once?.('error', (error) => - debugHttpLog('http.socket.error', error?.code ?? '', error?.message ?? String(error)), - ); - socket?.once?.('close', () => debugHttpLog('http.socket.close')); - }); - request.once('response', (response) => - debugHttpLog('http.response', response?.statusCode ?? ''), - ); - request.once('error', (error) => - debugHttpLog('http.error', error?.code ?? '', error?.message ?? String(error)), - ); - request.once('close', () => debugHttpLog('http.close')); - request.once('close', () => agent.destroy()); - return request; - }; - const normalizeServerCreation = (args) => { - let options = {}; - let requestListener; - - if (typeof args[0] === 'function') { - requestListener = args[0]; - } else { - if (args[0] != null) { - if (typeof args[0] !== 'object') { - throw new TypeError('http.createServer options must be an object'); - } - options = { ...args[0] }; - } - if (typeof args[1] === 'function') { - requestListener = args[1]; - } - } - - return { - options, - requestListener, - transportOptions: { - allowHalfOpen: options.allowHalfOpen === true, - pauseOnConnect: options.pauseOnConnect === true, - }, - }; - }; - - const request = (...args) => { - const normalized = normalizeRequestInvocation(args); - return createRequest(normalized, normalized.callback); - }; - const get = (...args) => { - const req = request(...args); - req.end(); - return req; - }; - const createServer = (...args) => { - const { options, requestListener, transportOptions } = - normalizeServerCreation(args); - const server = httpModule.createServer(options, requestListener); - const transportServer = transportModule.createServer(transportOptions); - return createTransportBackedServer(server, transportServer, 'connection'); - }; - const module = Object.assign(Object.create(httpModule ?? null), { - Agent: httpModule.Agent, - globalAgent: httpModule.globalAgent, - get, - request, - createServer, - }); - - return module; -} - -function createRpcBackedHttpsModule(httpsModule, tlsModule) { - const debugHttpLog = (...args) => { - console.error('[agentos http polyfill]', ...args); - }; - const createUnsupportedHttpsError = (subject) => { - const error = new Error(`${subject} is not supported by the secure-exec https polyfill yet`); - error.code = 'ERR_AGENTOS_HTTPS_UNSUPPORTED'; - return error; - }; - const normalizeRequestInvocation = (args) => { - const values = [...args]; - const callback = - typeof values[values.length - 1] === 'function' ? values.pop() : undefined; - - let options = {}; - if (values[0] instanceof URL || typeof values[0] === 'string') { - options = { - ...options, - ...parseRequestTargetFromUrl(values.shift(), 'https:'), - }; - } - if (values[0] != null) { - if (typeof values[0] !== 'object') { - throw new TypeError('secure-exec https request options must be an object'); - } - options = { - ...options, - ...values[0], - }; - } - - if (typeof options.socketPath === 'string') { - throw createUnsupportedHttpsError('https request socketPath'); - } - if (options.lookup != null) { - throw createUnsupportedHttpsError('https request lookup'); - } - - const hostTarget = parseRequestTargetFromHostOption(options.host, 'https:'); - const hostname = - typeof options.hostname === 'string' && options.hostname.length > 0 - ? options.hostname - : hostTarget?.hostname ?? 'localhost'; - const port = - options.port != null - ? normalizeHttpPort(options.port) - : hostTarget?.port ?? 443; - const path = - typeof options.path === 'string' && options.path.length > 0 - ? options.path - : '/'; - const requestOptions = { - ...options, - protocol: 'https:', - hostname, - port, - path, - agent: false, - }; - delete requestOptions.agent; - delete requestOptions.createConnection; - delete requestOptions.host; - delete requestOptions.lookup; - delete requestOptions.socketPath; - - const tlsConnectOptions = { - allowHalfOpen: options.allowHalfOpen === true, - ALPNProtocols: options.ALPNProtocols, - ca: options.ca, - cert: options.cert, - ciphers: options.ciphers, - crl: options.crl, - ecdhCurve: options.ecdhCurve, - family: options.family, - host: hostname, - key: options.key, - localAddress: options.localAddress, - maxVersion: options.maxVersion, - minVersion: options.minVersion, - passphrase: options.passphrase, - pfx: options.pfx, - port, - rejectUnauthorized: options.rejectUnauthorized, - secureContext: options.secureContext, - servername: options.servername, - session: options.session, - sigalgs: options.sigalgs, - }; - - return { - callback, - requestOptions, - tlsConnectOptions, - }; - }; - const normalizeServerCreation = (args) => { - let options = {}; - let requestListener; - - if (typeof args[0] === 'function') { - requestListener = args[0]; - } else { - if (args[0] != null) { - if (typeof args[0] !== 'object') { - throw new TypeError('https.createServer options must be an object'); - } - options = { ...args[0] }; - } - if (typeof args[1] === 'function') { - requestListener = args[1]; - } - } - - return { - options, - requestListener, - }; - }; - - const request = (...args) => { - const normalized = normalizeRequestInvocation(args); - class SecureExecHttpsAgent extends httpsModule.Agent { - createConnection() { - return tlsModule.connect(normalized.tlsConnectOptions); - } - } - - const agent = new SecureExecHttpsAgent({ keepAlive: false }); - const request = httpsModule.request( - { - ...normalized.requestOptions, - agent, - }, - normalized.callback, - ); - debugHttpLog('https.request', JSON.stringify(normalized.requestOptions)); - request.on('socket', (socket) => { - debugHttpLog('https.socket'); - socket?.once?.('connect', () => debugHttpLog('https.socket.connect')); - socket?.once?.('secureConnect', () => debugHttpLog('https.socket.secureConnect')); - socket?.once?.('error', (error) => - debugHttpLog('https.socket.error', error?.code ?? '', error?.message ?? String(error)), - ); - socket?.once?.('close', () => debugHttpLog('https.socket.close')); - }); - request.once('response', (response) => - debugHttpLog('https.response', response?.statusCode ?? ''), - ); - request.once('error', (error) => - debugHttpLog('https.error', error?.code ?? '', error?.message ?? String(error)), - ); - request.once('close', () => debugHttpLog('https.close')); - request.once('close', () => agent.destroy()); - return request; - }; - const get = (...args) => { - const req = request(...args); - req.end(); - return req; - }; - const createServer = (...args) => { - const { options, requestListener } = normalizeServerCreation(args); - const server = httpsModule.createServer(options, requestListener); - const transportServer = tlsModule.createServer(options); - return createTransportBackedServer(server, transportServer, 'secureConnection', [ - 'tlsClientError', - ]); - }; - const module = Object.assign(Object.create(httpsModule ?? null), { - Agent: httpsModule.Agent, - globalAgent: httpsModule.globalAgent, - get, - request, - createServer, - }); - - return module; -} - -function createRpcBackedHttp2Module(http2Module, netModule, tlsModule) { - const createUnsupportedHttp2Error = (subject) => { - const error = new Error(`${subject} is not supported by the secure-exec http2 polyfill yet`); - error.code = 'ERR_AGENTOS_HTTP2_UNSUPPORTED'; - return error; - }; - const normalizeConnectInvocation = (args) => { - const values = [...args]; - const authority = - values[0] instanceof URL || typeof values[0] === 'string' - ? values.shift() - : 'http://localhost'; - const authorityTarget = parseRequestTargetFromUrl(authority, 'http:'); - const callback = - typeof values[values.length - 1] === 'function' ? values.pop() : undefined; - const options = - values[0] != null && typeof values[0] === 'object' ? { ...values[0] } : {}; - - if (typeof options.socketPath === 'string') { - throw createUnsupportedHttp2Error('http2.connect socketPath'); - } - if (options.lookup != null) { - throw createUnsupportedHttp2Error('http2.connect lookup'); - } - - const connectOptions = { ...options }; - delete connectOptions.createConnection; - delete connectOptions.host; - delete connectOptions.hostname; - delete connectOptions.lookup; - delete connectOptions.port; - delete connectOptions.socketPath; - - const isSecure = authorityTarget.protocol === 'https:'; - return { - authority, - callback, - connectOptions, - createConnection: () => - isSecure - ? tlsModule.connect({ - ALPNProtocols: options.ALPNProtocols ?? ['h2'], - ca: options.ca, - cert: options.cert, - ciphers: options.ciphers, - family: options.family, - host: authorityTarget.hostname, - key: options.key, - localAddress: options.localAddress, - passphrase: options.passphrase, - pfx: options.pfx, - port: authorityTarget.port, - rejectUnauthorized: options.rejectUnauthorized, - secureContext: options.secureContext, - servername: options.servername, - session: options.session, - }) - : netModule.connect({ - allowHalfOpen: options.allowHalfOpen === true, - family: options.family, - host: authorityTarget.hostname, - localAddress: options.localAddress, - port: authorityTarget.port, - }), - }; - }; - const normalizeServerCreation = (args, secure) => { - let options = {}; - let onStream; - - if (typeof args[0] === 'function') { - onStream = args[0]; - } else { - if (args[0] != null) { - if (typeof args[0] !== 'object') { - throw new TypeError( - `http2.${secure ? 'createSecureServer' : 'createServer'} options must be an object`, - ); - } - options = { ...args[0] }; - } - if (typeof args[1] === 'function') { - onStream = args[1]; - } - } - - return { - onStream, - options, - }; - }; - - const connect = (...args) => { - const normalized = normalizeConnectInvocation(args); - return http2Module.connect( - normalized.authority, - { - ...normalized.connectOptions, - createConnection: normalized.createConnection, - }, - normalized.callback, - ); - }; - const createServer = (...args) => { - const { onStream, options } = normalizeServerCreation(args, false); - const server = http2Module.createServer(options, onStream); - const transportServer = netModule.createServer({ - allowHalfOpen: options.allowHalfOpen === true, - pauseOnConnect: options.pauseOnConnect === true, - }); - return createTransportBackedServer(server, transportServer, 'connection'); - }; - const createSecureServer = (...args) => { - const { onStream, options } = normalizeServerCreation(args, true); - const server = http2Module.createSecureServer(options, onStream); - const transportServer = tlsModule.createServer( - { - ...options, - ALPNProtocols: options.ALPNProtocols ?? ['h2'], - }, - ); - return createTransportBackedServer(server, transportServer, 'secureConnection', [ - 'tlsClientError', - ]); - }; - const module = Object.assign(Object.create(http2Module ?? null), { - connect, - createServer, - createSecureServer, - }); - - return module; -} - -function createRpcBackedDgramModule(dgramModule, fromGuestDir = '/') { - const RPC_POLL_WAIT_MS = 50; - const RPC_IDLE_POLL_DELAY_MS = 10; - const bridge = () => requireSecureExecSyncRpcBridge(); - const createUnsupportedDgramError = (subject) => { - const error = new Error(`${subject} is not supported by the secure-exec dgram polyfill yet`); - error.code = 'ERR_AGENTOS_DGRAM_UNSUPPORTED'; - return error; - }; - const normalizeDgramInteger = (value, label) => { - const numeric = - typeof value === 'number' - ? value - : typeof value === 'string' && value.length > 0 - ? Number(value) - : Number.NaN; - if (!Number.isInteger(numeric) || numeric < 0) { - throw new RangeError(`secure-exec ${label} must be a non-negative integer`); - } - return numeric; - }; - const normalizeDgramPort = (value) => { - const numeric = normalizeDgramInteger(value, 'dgram port'); - if (numeric > 65535) { - throw new RangeError(`secure-exec dgram port must be between 0 and 65535`); - } - return numeric; - }; - const socketFamilyForAddress = (value) => { - if (typeof value !== 'string') { - return undefined; - } - return value.includes(':') ? 'IPv6' : 'IPv4'; - }; - const normalizeDgramType = (value) => { - if (value === 'udp4' || value === 'udp6') { - return value; - } - throw new TypeError(`secure-exec dgram socket type must be udp4 or udp6`); - }; - const normalizeDgramCreateSocketInvocation = (args) => { - const values = [...args]; - const callback = - typeof values[values.length - 1] === 'function' ? values.pop() : undefined; - - let options; - if (typeof values[0] === 'string') { - options = { type: values[0] }; - } else if (values[0] != null && typeof values[0] === 'object') { - options = { ...values[0] }; - } else { - throw new TypeError('dgram.createSocket requires a socket type or options object'); - } - - if (options?.recvBufferSize != null || options?.sendBufferSize != null) { - throw createUnsupportedDgramError('dgram.createSocket({ recvBufferSize/sendBufferSize })'); - } - - return { - callback, - options: { - type: normalizeDgramType(options.type), - }, - }; - }; - const normalizeDgramBindInvocation = (args, socketType) => { - const values = [...args]; - const callback = - typeof values[values.length - 1] === 'function' ? values.pop() : undefined; - - let options; - if (values[0] != null && typeof values[0] === 'object') { - options = { ...values[0] }; - } else { - options = { port: values[0] }; - if (typeof values[1] === 'string') { - options.address = values[1]; - } - } - - if (options?.exclusive != null || options?.fd != null || options?.signal != null) { - throw createUnsupportedDgramError('dgram.Socket.bind advanced options'); - } - - return { - callback, - options: { - port: normalizeDgramPort(options?.port ?? 0), - address: - typeof options?.address === 'string' && options.address.length > 0 - ? options.address - : socketType === 'udp6' - ? '::1' - : '127.0.0.1', - }, - }; - }; - const normalizeDgramMessageBuffer = (value) => { - if (typeof value === 'string') { - return Buffer.from(value); - } - if (Array.isArray(value)) { - return Buffer.concat(value.map((entry) => normalizeDgramMessageBuffer(entry))); - } - return Buffer.from(toGuestBufferView(value, 'dgram payload')); - }; - const normalizeDgramSendInvocation = (args) => { - const values = [...args]; - const callback = - typeof values[values.length - 1] === 'function' ? values.pop() : undefined; - if (values.length === 0) { - throw new TypeError('dgram.Socket.send requires a payload'); - } - - let payload = normalizeDgramMessageBuffer(values.shift()); - let port; - let address; - - if ( - values.length >= 3 && - typeof values[0] === 'number' && - typeof values[1] === 'number' - ) { - const offset = normalizeDgramInteger(values.shift(), 'dgram send offset'); - const length = normalizeDgramInteger(values.shift(), 'dgram send length'); - if (offset > payload.length || offset + length > payload.length) { - throw new RangeError('secure-exec dgram send offset/length is out of range'); - } - payload = payload.subarray(offset, offset + length); - port = normalizeDgramPort(values.shift()); - if (typeof values[0] === 'string') { - address = values.shift(); - } - } else if (values[0] != null && typeof values[0] === 'object') { - const options = { ...values.shift() }; - port = normalizeDgramPort(options.port); - address = options.address; - } else { - port = normalizeDgramPort(values.shift()); - if (typeof values[0] === 'string') { - address = values.shift(); - } - } - - return { - callback, - options: { - port, - address: typeof address === 'string' && address.length > 0 ? address : 'localhost', - }, - payload, - }; - }; - const callCreateSocket = (options) => bridge().callSync('dgram.createSocket', [options]); - const callBind = (socketId, options) => bridge().callSync('dgram.bind', [socketId, options]); - const callSend = (socketId, payload, options) => - bridge().call('dgram.send', [socketId, toGuestBufferView(payload, 'dgram.send payload'), options]); - const callPoll = (socketId, waitMs = 0) => bridge().callSync('dgram.poll', [socketId, waitMs]); - const callClose = (socketId) => bridge().call('dgram.close', [socketId]); - - const finalizeDatagramClose = (socket) => { - if (socket._agentOSClosed) { - return; - } - socket._agentOSClosed = true; - socket._agentOSBound = false; - socket._agentOSPollTimer && clearTimeout(socket._agentOSPollTimer); - socket._agentOSPollTimer = null; - queueMicrotask(() => socket.emit('close')); - }; - const attachDatagramBindState = (socket, result, emitListening = false) => { - const alreadyBound = socket._agentOSBound; - socket._agentOSBound = true; - socket._address = { - address: result.localAddress, - family: result.family ?? socketFamilyForAddress(result.localAddress), - port: result.localPort, - }; - if (emitListening && !alreadyBound) { - queueMicrotask(() => { - if (!socket._agentOSClosed) { - socket.emit('listening'); - } - }); - } - scheduleDatagramPoll(socket, 0); - }; - const scheduleDatagramPoll = (socket, delayMs) => { - if ( - socket._agentOSClosed || - socket._agentOSSocketId == null || - !socket._agentOSBound || - socket._agentOSPollTimer != null - ) { - return; - } - - socket._agentOSPollTimer = setTimeout(() => { - socket._agentOSPollTimer = null; - if ( - socket._agentOSClosed || - socket._agentOSSocketId == null || - !socket._agentOSBound - ) { - return; - } - - let event; - try { - event = callPoll(socket._agentOSSocketId, RPC_POLL_WAIT_MS); - } catch (error) { - socket.emit('error', error); - scheduleDatagramPoll(socket, 0); - return; - } - - if (!event) { - scheduleDatagramPoll(socket, RPC_IDLE_POLL_DELAY_MS); - return; - } - - if (event.type === 'message') { - socket.emit( - 'message', - decodeFsBytesPayload(event.data, 'dgram.message'), - { - address: event.remoteAddress, - family: event.remoteFamily ?? socketFamilyForAddress(event.remoteAddress), - port: event.remotePort, - size: decodeFsBytesPayload(event.data, 'dgram.message').length, - }, - ); - scheduleDatagramPoll(socket, 0); - return; - } - - if (event.type === 'error') { - const error = new Error( - typeof event.message === 'string' ? event.message : 'secure-exec dgram socket error', - ); - if (typeof event.code === 'string' && event.code.length > 0) { - error.code = event.code; - } - socket.emit('error', error); - scheduleDatagramPoll(socket, 0); - return; - } - - scheduleDatagramPoll(socket, 0); - }, delayMs); - - if (!socket._agentOSRefed) { - socket._agentOSPollTimer.unref?.(); - } - }; - - class SecureExecDatagramSocket extends EventEmitter { - constructor(options = {}, messageListener = undefined) { - super(); - this.type = options.type; - this._agentOSClosed = false; - this._agentOSRefed = true; - this._agentOSBound = false; - this._agentOSSocketId = null; - this._agentOSPollTimer = null; - this._address = null; - if (typeof messageListener === 'function') { - this.on('message', messageListener); - } - const result = callCreateSocket(options); - this._agentOSSocketId = String(result.socketId); - } - - address() { - return this._address; - } - - bind(...args) { - const { callback, options } = normalizeDgramBindInvocation(args, this.type); - if (typeof callback === 'function') { - this.once('listening', callback); - } - if (this._agentOSClosed) { - throw new Error('secure-exec dgram socket is closed'); - } - attachDatagramBindState(this, callBind(this._agentOSSocketId, options), true); - return this; - } - - close(callback) { - if (typeof callback === 'function') { - this.once('close', callback); - } - if (this._agentOSClosed || this._agentOSSocketId == null) { - queueMicrotask(() => finalizeDatagramClose(this)); - return this; - } - this._agentOSBound = false; - this._agentOSPollTimer && clearTimeout(this._agentOSPollTimer); - this._agentOSPollTimer = null; - const socketId = this._agentOSSocketId; - this._agentOSSocketId = null; - callClose(socketId).then( - () => finalizeDatagramClose(this), - (error) => this.emit('error', error), - ); - return this; - } - - send(...args) { - if (this._agentOSClosed || this._agentOSSocketId == null) { - const error = new Error('secure-exec dgram socket is closed'); - const callback = - typeof args[args.length - 1] === 'function' ? args[args.length - 1] : null; - if (callback) { - queueMicrotask(() => callback(error)); - return; - } - throw error; - } - - const { callback, options, payload } = normalizeDgramSendInvocation(args); - callSend(this._agentOSSocketId, payload, options).then( - (result) => { - attachDatagramBindState(this, result, true); - if (typeof callback === 'function') { - callback(null, typeof result?.bytes === 'number' ? result.bytes : payload.length); - } - }, - (error) => { - if (typeof callback === 'function') { - callback(error); - return; - } - this.emit('error', error); - }, - ); - } - - ref() { - this._agentOSRefed = true; - this._agentOSPollTimer?.ref?.(); - return this; - } - - unref() { - this._agentOSRefed = false; - this._agentOSPollTimer?.unref?.(); - return this; - } - - setBroadcast() { - return this; - } - - setMulticastInterface() { - return this; - } - - setMulticastLoopback() { - return this; - } - - setMulticastTTL() { - return this; - } - - setRecvBufferSize() { - return this; - } - - setSendBufferSize() { - return this; - } - - setTTL() { - return this; - } - - addMembership() { - throw createUnsupportedDgramError('dgram.Socket.addMembership'); - } - - connect() { - throw createUnsupportedDgramError('dgram.Socket.connect'); - } - - disconnect() { - throw createUnsupportedDgramError('dgram.Socket.disconnect'); - } - - dropMembership() { - throw createUnsupportedDgramError('dgram.Socket.dropMembership'); - } - - getRecvBufferSize() { - return 0; - } - - getSendBufferSize() { - return 0; - } - - remoteAddress() { - throw createUnsupportedDgramError('dgram.Socket.remoteAddress'); - } - } - - const createSocket = (...args) => { - const { callback, options } = normalizeDgramCreateSocketInvocation(args); - return new SecureExecDatagramSocket(options, callback); - }; - const module = Object.assign(Object.create(dgramModule ?? null), { - Socket: SecureExecDatagramSocket, - createSocket, - }); - - return module; -} - -function createRpcBackedDnsModule(dnsModule) { - const bridge = () => requireSecureExecSyncRpcBridge(); - const dnsConstants = Object.freeze({ ...(dnsModule?.constants ?? {}) }); - let defaultResultOrder = 'verbatim'; - - const createUnsupportedDnsError = (subject) => { - const error = new Error(`${subject} is not supported by the secure-exec dns polyfill yet`); - error.code = 'ERR_NOT_IMPLEMENTED'; - return error; - }; - - const normalizeDnsHostname = (hostname, methodName) => { - if (typeof hostname !== 'string' || hostname.length === 0) { - throw new TypeError(`secure-exec ${methodName} hostname must be a non-empty string`); - } - return hostname; - }; - - const normalizeDnsFamily = (value, label, allowAny = true) => { - if (value == null) { - return allowAny ? 0 : 4; - } - const numeric = - typeof value === 'number' - ? value - : typeof value === 'string' && value.length > 0 - ? Number(value) - : Number.NaN; - if ( - !Number.isInteger(numeric) || - (!allowAny && numeric !== 4 && numeric !== 6) || - (allowAny && numeric !== 0 && numeric !== 4 && numeric !== 6) - ) { - throw new TypeError( - `secure-exec ${label} must be ${allowAny ? '0, 4, or 6' : '4 or 6'}`, - ); - } - return numeric; - }; - - const normalizeDnsResultOrder = (value) => { - const normalized = value == null ? defaultResultOrder : String(value); - if ( - normalized !== 'verbatim' && - normalized !== 'ipv4first' && - normalized !== 'ipv6first' - ) { - throw new TypeError( - 'secure-exec dns result order must be one of verbatim, ipv4first, or ipv6first', - ); - } - return normalized; - }; - - const sortLookupAddresses = (records, order) => { - if (!Array.isArray(records) || order === 'verbatim') { - return [...records]; - } - const rankFamily = (family) => { - if (order === 'ipv4first') { - return family === 4 ? 0 : family === 6 ? 1 : 2; - } - return family === 6 ? 0 : family === 4 ? 1 : 2; - }; - return [...records].sort((left, right) => rankFamily(left.family) - rankFamily(right.family)); - }; - - const normalizeLookupInvocation = (hostname, options, callback) => { - let normalizedOptions = {}; - let done = callback; - - if (typeof options === 'function') { - done = options; - } else if (typeof options === 'number') { - normalizedOptions = { family: options }; - } else if (options == null) { - normalizedOptions = {}; - } else if (typeof options === 'object') { - normalizedOptions = { ...options }; - } else { - throw new TypeError('secure-exec dns.lookup options must be a number, object, or callback'); - } - - return { - callback: done, - options: { - hostname: normalizeDnsHostname(hostname, 'dns.lookup'), - family: normalizeDnsFamily(normalizedOptions.family, 'dns.lookup family'), - all: normalizedOptions.all === true, - order: normalizeDnsResultOrder( - normalizedOptions.order ?? - (normalizedOptions.verbatim === false ? 'ipv4first' : undefined), - ), - }, - }; - }; - - const normalizeResolveInvocation = (methodName, hostname, rrtype, callback) => { - let type = rrtype; - let done = callback; - if (typeof rrtype === 'function') { - done = rrtype; - type = undefined; - } - if (type == null) { - type = 'A'; - } - const normalizedType = String(type).toUpperCase(); - if ( - normalizedType !== 'A' && - normalizedType !== 'AAAA' && - normalizedType !== 'MX' && - normalizedType !== 'TXT' && - normalizedType !== 'SRV' && - normalizedType !== 'CNAME' && - normalizedType !== 'PTR' && - normalizedType !== 'NS' && - normalizedType !== 'SOA' && - normalizedType !== 'NAPTR' && - normalizedType !== 'CAA' && - normalizedType !== 'ANY' - ) { - throw createUnsupportedDnsError(`${methodName}(${normalizedType})`); - } - return { - callback: done, - options: { - hostname: normalizeDnsHostname(hostname, methodName), - rrtype: normalizedType, - }, - }; - }; - - const resolveRecords = (method, options) => bridge().callSync(method, [options]); - const lookupRecords = (options) => bridge().callSync('dns.lookup', [options]); - - const lookup = (hostname, options, callback) => { - const invocation = normalizeLookupInvocation(hostname, options, callback); - const records = sortLookupAddresses(lookupRecords(invocation.options), invocation.options.order); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => { - if (invocation.options.all) { - invocation.callback(null, records); - } else { - const first = records[0] ?? { address: null, family: invocation.options.family || 0 }; - invocation.callback(null, first.address, first.family); - } - }); - } - return invocation.options.all - ? records - : { - address: records[0]?.address ?? null, - family: records[0]?.family ?? (invocation.options.family || 0), - }; - }; - - const resolve = (hostname, rrtype, callback) => { - const invocation = normalizeResolveInvocation('dns.resolve', hostname, rrtype, callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolve4 = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolve4', hostname, 'A', callback); - const records = resolveRecords('dns.resolve4', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolve6 = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolve6', hostname, 'AAAA', callback); - const records = resolveRecords('dns.resolve6', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolveAny = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolveAny', hostname, 'ANY', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolveMx = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolveMx', hostname, 'MX', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolveTxt = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolveTxt', hostname, 'TXT', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolveSrv = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolveSrv', hostname, 'SRV', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolveCname = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolveCname', hostname, 'CNAME', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolvePtr = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolvePtr', hostname, 'PTR', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolveNs = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolveNs', hostname, 'NS', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolveSoa = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolveSoa', hostname, 'SOA', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolveNaptr = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolveNaptr', hostname, 'NAPTR', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const resolveCaa = (hostname, callback) => { - const invocation = normalizeResolveInvocation('dns.resolveCaa', hostname, 'CAA', callback); - const records = resolveRecords('dns.resolve', invocation.options); - if (typeof invocation.callback === 'function') { - queueMicrotask(() => invocation.callback(null, records)); - } - return records; - }; - - const createInvalidDnsServersError = (subject) => { - const error = new TypeError( - `${subject} expects an array of non-empty server strings`, - ); - error.code = 'ERR_INVALID_ARG_TYPE'; - return error; - }; - - const normalizeDnsServers = (subject, servers) => { - if (!Array.isArray(servers)) { - throw createInvalidDnsServersError(subject); - } - - return servers.map((server) => { - if (typeof server !== 'string' || server.length === 0) { - throw createInvalidDnsServersError(subject); - } - return server; - }); - }; - - // Resolver instances keep guest-owned server lists for API compatibility. - // Queries still use the VM-wide kernel resolver until the sync RPC grows - // per-request nameserver overrides. - class SecureExecResolver { - constructor() { - this._servers = []; - } - - cancel() {} - - getServers() { - return this._servers.slice(); - } - - lookup(hostname, options, callback) { - return lookup(hostname, options, callback); - } - - resolve(hostname, rrtype, callback) { - return resolve(hostname, rrtype, callback); - } - - resolve4(hostname, callback) { - return resolve4(hostname, callback); - } - - resolve6(hostname, callback) { - return resolve6(hostname, callback); - } - - resolveAny(hostname, callback) { - return resolveAny(hostname, callback); - } - - resolveMx(hostname, callback) { - return resolveMx(hostname, callback); - } - - resolveTxt(hostname, callback) { - return resolveTxt(hostname, callback); - } - - resolveSrv(hostname, callback) { - return resolveSrv(hostname, callback); - } - - resolveCname(hostname, callback) { - return resolveCname(hostname, callback); - } - - resolvePtr(hostname, callback) { - return resolvePtr(hostname, callback); - } - - resolveNs(hostname, callback) { - return resolveNs(hostname, callback); - } - - resolveSoa(hostname, callback) { - return resolveSoa(hostname, callback); - } - - resolveNaptr(hostname, callback) { - return resolveNaptr(hostname, callback); - } - - resolveCaa(hostname, callback) { - return resolveCaa(hostname, callback); - } - - setServers(servers) { - this._servers = normalizeDnsServers('dns.Resolver.setServers', servers); - } - } - - class SecureExecPromisesResolver { - constructor() { - this._servers = []; - } - - cancel() {} - - getServers() { - return this._servers.slice(); - } - - lookup(hostname, options) { - return Promise.resolve(lookup(hostname, options)); - } - - resolve(hostname, rrtype) { - return Promise.resolve(resolve(hostname, rrtype)); - } - - resolve4(hostname) { - return Promise.resolve(resolve4(hostname)); - } - - resolve6(hostname) { - return Promise.resolve(resolve6(hostname)); - } - - resolveAny(hostname) { - return Promise.resolve(resolveAny(hostname)); - } - - resolveMx(hostname) { - return Promise.resolve(resolveMx(hostname)); - } - - resolveTxt(hostname) { - return Promise.resolve(resolveTxt(hostname)); - } - - resolveSrv(hostname) { - return Promise.resolve(resolveSrv(hostname)); - } - - resolveCname(hostname) { - return Promise.resolve(resolveCname(hostname)); - } - - resolvePtr(hostname) { - return Promise.resolve(resolvePtr(hostname)); - } - - resolveNs(hostname) { - return Promise.resolve(resolveNs(hostname)); - } - - resolveSoa(hostname) { - return Promise.resolve(resolveSoa(hostname)); - } - - resolveNaptr(hostname) { - return Promise.resolve(resolveNaptr(hostname)); - } - - resolveCaa(hostname) { - return Promise.resolve(resolveCaa(hostname)); - } - - setServers(servers) { - this._servers = normalizeDnsServers( - 'dns.promises.Resolver.setServers', - servers, - ); - } - } - - const promises = Object.freeze({ - Resolver: SecureExecPromisesResolver, - lookup(hostname, options) { - return Promise.resolve(lookup(hostname, options)); - }, - resolve(hostname, rrtype) { - return Promise.resolve(resolve(hostname, rrtype)); - }, - resolve4(hostname) { - return Promise.resolve(resolve4(hostname)); - }, - resolve6(hostname) { - return Promise.resolve(resolve6(hostname)); - }, - resolveAny(hostname) { - return Promise.resolve(resolveAny(hostname)); - }, - resolveMx(hostname) { - return Promise.resolve(resolveMx(hostname)); - }, - resolveTxt(hostname) { - return Promise.resolve(resolveTxt(hostname)); - }, - resolveSrv(hostname) { - return Promise.resolve(resolveSrv(hostname)); - }, - resolveCname(hostname) { - return Promise.resolve(resolveCname(hostname)); - }, - resolvePtr(hostname) { - return Promise.resolve(resolvePtr(hostname)); - }, - resolveNs(hostname) { - return Promise.resolve(resolveNs(hostname)); - }, - resolveSoa(hostname) { - return Promise.resolve(resolveSoa(hostname)); - }, - resolveNaptr(hostname) { - return Promise.resolve(resolveNaptr(hostname)); - }, - resolveCaa(hostname) { - return Promise.resolve(resolveCaa(hostname)); - }, - }); - - const module = { - ADDRCONFIG: dnsConstants.ADDRCONFIG, - ALL: dnsConstants.ALL, - V4MAPPED: dnsConstants.V4MAPPED, - Resolver: SecureExecResolver, - constants: dnsConstants, - getDefaultResultOrder() { - return defaultResultOrder; - }, - getServers() { - return []; - }, - lookup, - lookupService() { - throw createUnsupportedDnsError('dns.lookupService'); - }, - promises, - resolve, - resolve4, - resolve6, - resolveAny, - resolveMx, - resolveTxt, - resolveSrv, - resolveCname, - resolvePtr, - resolveNs, - resolveSoa, - resolveNaptr, - resolveCaa, - reverse() { - throw createUnsupportedDnsError('dns.reverse'); - }, - setDefaultResultOrder(order) { - defaultResultOrder = normalizeDnsResultOrder(order); - }, - setServers() { - throw createUnsupportedDnsError('dns.setServers'); - }, - }; - - return module; -} - -const guestRequireCache = new Map(); -let rootGuestRequire = null; -const hostFs = fs; -const hostFsPromises = fs.promises; -const hostFsWriteSync = fs.writeSync.bind(fs); -const hostFsCloseSync = fs.closeSync.bind(fs); -const guestFs = wrapFsModule(hostFs); -globalThis.__agentOSGuestFs = guestFs; -const guestChildProcess = createRpcBackedChildProcessModule(INITIAL_GUEST_CWD); -const guestNet = createRpcBackedNetModule(hostNet, INITIAL_GUEST_CWD); -const guestDgram = createRpcBackedDgramModule(hostDgram, INITIAL_GUEST_CWD); -const guestDns = createRpcBackedDnsModule(hostDns); -const guestTls = createRpcBackedTlsModule(hostTls, guestNet); -const guestHttp = createRpcBackedHttpModule(hostHttp, guestNet); -const guestHttps = createRpcBackedHttpsModule(hostHttps, guestTls); -const guestHttp2 = createRpcBackedHttp2Module(hostHttp2, guestNet, guestTls); -const guestGetUid = () => VIRTUAL_UID; -const guestGetGid = () => VIRTUAL_GID; -const guestMonotonicNow = - globalThis.performance && typeof globalThis.performance.now === 'function' - ? globalThis.performance.now.bind(globalThis.performance) - : Date.now; -// Virtual OS identity is carried as the typed `__agentOSVirtualOs` structured -// global (populated by the runtime shim from `guest_runtime`), not -// `AGENTOS_VIRTUAL_OS_*` env vars. Absent fields are `undefined` and fall back -// to the defaults below. -const VIRTUAL_OS = globalThis.__agentOSVirtualOs || {}; -const VIRTUAL_OS_HOSTNAME = parseVirtualProcessString( - VIRTUAL_OS.hostname, - DEFAULT_VIRTUAL_OS_HOSTNAME, -); -const VIRTUAL_OS_TYPE = parseVirtualProcessString( - VIRTUAL_OS.type, - DEFAULT_VIRTUAL_OS_TYPE, -); -const VIRTUAL_OS_PLATFORM = parseVirtualProcessString( - VIRTUAL_OS.platform, - DEFAULT_VIRTUAL_OS_PLATFORM, -); -const VIRTUAL_OS_RELEASE = parseVirtualProcessString( - VIRTUAL_OS.release, - DEFAULT_VIRTUAL_OS_RELEASE, -); -const VIRTUAL_OS_VERSION = parseVirtualProcessString( - VIRTUAL_OS.version, - DEFAULT_VIRTUAL_OS_VERSION, -); -const VIRTUAL_OS_ARCH = parseVirtualProcessString( - VIRTUAL_OS.arch, - DEFAULT_VIRTUAL_OS_ARCH, -); -const VIRTUAL_OS_MACHINE = parseVirtualProcessString( - VIRTUAL_OS.machine, - DEFAULT_VIRTUAL_OS_MACHINE, -); -const VIRTUAL_OS_CPU_MODEL = parseVirtualProcessString( - VIRTUAL_OS.cpuModel, - DEFAULT_VIRTUAL_OS_CPU_MODEL, -); -const VIRTUAL_OS_CPU_COUNT = parsePositiveInt( - VIRTUAL_OS.cpuCount, - DEFAULT_VIRTUAL_OS_CPU_COUNT, -); -const VIRTUAL_OS_TOTALMEM = parsePositiveInt( - VIRTUAL_OS.totalmem, - DEFAULT_VIRTUAL_OS_TOTALMEM, -); -const VIRTUAL_OS_FREEMEM = Math.min( - parsePositiveInt(VIRTUAL_OS.freemem, DEFAULT_VIRTUAL_OS_FREEMEM), - VIRTUAL_OS_TOTALMEM, -); -const DEFAULT_VIRTUAL_PROCESS_VERSION = 'v24.0.0'; -const VIRTUAL_PROCESS_VERSION = parseVirtualProcessString( - HOST_PROCESS_ENV.AGENTOS_VIRTUAL_PROCESS_VERSION, - DEFAULT_VIRTUAL_PROCESS_VERSION, -); -const VIRTUAL_PROCESS_RELEASE = deepFreezeObject({ - name: 'node', - lts: 'secure-exec', -}); -const VIRTUAL_PROCESS_CONFIG = deepFreezeObject({ - target_defaults: {}, - variables: { - host_arch: VIRTUAL_OS_ARCH, - node_shared: false, - node_use_openssl: false, - }, -}); -const VIRTUAL_PROCESS_VERSIONS = deepFreezeObject({ - node: VIRTUAL_PROCESS_VERSION.replace(/^v/, ''), - modules: '0', - napi: '0', - uv: '0.0.0', - zlib: '0.0.0', - openssl: '0.0.0', - v8: '0.0', -}); -const VIRTUAL_PROCESS_START_TIME_MS = guestMonotonicNow(); -let guestProcess = process; - -function syncBuiltinModuleExports(hostModule, wrappedModule) { - if ( - hostModule == null || - wrappedModule == null || - typeof hostModule !== 'object' || - typeof wrappedModule !== 'object' - ) { - return; - } - - for (const [key, value] of Object.entries(wrappedModule)) { - try { - hostModule[key] = value; - } catch { - // Ignore immutable bindings and keep the original builtin export. - } - } -} - -function cloneFsModule(fsModule) { - if (fsModule == null || typeof fsModule !== 'object') { - return fsModule; - } - - const cloned = { ...fsModule }; - if (fsModule.promises && typeof fsModule.promises === 'object') { - cloned.promises = { ...fsModule.promises }; - } - return cloned; -} - -function resolveVirtualPath(value, fallback) { - if (typeof value !== 'string' || value.length === 0) { - return fallback; - } - - if (path.posix.isAbsolute(value)) { - return path.posix.normalize(value); - } - - return translatePathStringToGuest(value); -} - -function cloneVirtualCpuInfo(cpu) { - return { - ...cpu, - times: { ...cpu.times }, - }; -} - -function cloneVirtualNetworkInterfaces(networkInterfaces) { - return Object.fromEntries( - Object.entries(networkInterfaces).map(([name, entries]) => [ - name, - entries.map((entry) => ({ ...entry })), - ]), - ); -} - -function encodeUserInfoValue(value, encoding) { - return encoding === 'buffer' ? Buffer.from(String(value)) : String(value); -} - -function deepFreezeObject(value) { - if ( - value == null || - (typeof value !== 'object' && typeof value !== 'function') || - Object.isFrozen(value) - ) { - return value; - } - - for (const nestedValue of Object.values(value)) { - deepFreezeObject(nestedValue); - } - - return Object.freeze(value); -} - -function createVirtualProcessMemoryUsageSnapshot() { - const rss = Math.max( - 1, - Math.min( - VIRTUAL_OS_TOTALMEM, - Math.max(VIRTUAL_OS_TOTALMEM - VIRTUAL_OS_FREEMEM, Math.floor(VIRTUAL_OS_TOTALMEM / 4)), - ), - ); - const heapTotal = Math.max(1, Math.min(rss, Math.floor(rss / 2))); - const heapUsed = Math.max(1, Math.min(heapTotal, Math.floor(heapTotal / 2))); - const external = Math.max(0, Math.min(rss - heapUsed, Math.floor(rss / 8))); - const arrayBuffers = Math.max(0, Math.min(external, Math.floor(external / 2))); - - return { - rss, - heapTotal, - heapUsed, - external, - arrayBuffers, - }; -} - -function createGuestMemoryUsage() { - const memoryUsage = () => createVirtualProcessMemoryUsageSnapshot(); - hardenProperty(memoryUsage, 'rss', () => createVirtualProcessMemoryUsageSnapshot().rss); - return memoryUsage; -} - -function createGuestProcessUptime() { - return () => Math.max(0, (guestMonotonicNow() - VIRTUAL_PROCESS_START_TIME_MS) / 1000); -} - -function createGuestOsModule(osModule) { - const virtualHomeDir = resolveVirtualPath( - (globalThis.__agentOSVirtualOs||{}).homedir, - DEFAULT_VIRTUAL_OS_HOMEDIR, - ); - const virtualTmpDir = resolveVirtualPath( - (globalThis.__agentOSVirtualOs||{}).tmpdir, - DEFAULT_VIRTUAL_OS_TMPDIR, - ); - const virtualUserName = parseVirtualProcessString( - (globalThis.__agentOSVirtualOs||{}).user, - DEFAULT_VIRTUAL_OS_USER, - ); - const virtualShell = resolveVirtualPath( - (globalThis.__agentOSVirtualOs||{}).shell, - DEFAULT_VIRTUAL_OS_SHELL, - ); - const virtualCpuInfo = Object.freeze( - Array.from({ length: VIRTUAL_OS_CPU_COUNT }, () => - Object.freeze({ - model: VIRTUAL_OS_CPU_MODEL, - speed: 0, - times: Object.freeze({ - user: 0, - nice: 0, - sys: 0, - idle: 0, - irq: 0, - }), - }), - ), - ); - const virtualNetworkInterfaces = Object.freeze({ - lo: Object.freeze([ - Object.freeze({ - address: '127.0.0.1', - netmask: '255.0.0.0', - family: 'IPv4', - mac: '00:00:00:00:00:00', - internal: true, - cidr: '127.0.0.1/8', - }), - Object.freeze({ - address: '::1', - netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', - family: 'IPv6', - mac: '00:00:00:00:00:00', - internal: true, - cidr: '::1/128', - scopeid: 0, - }), - ]), - }); - - return Object.assign(Object.create(osModule ?? null), { - arch: () => VIRTUAL_OS_ARCH, - availableParallelism: () => VIRTUAL_OS_CPU_COUNT, - cpus: () => virtualCpuInfo.map((cpu) => cloneVirtualCpuInfo(cpu)), - freemem: () => VIRTUAL_OS_FREEMEM, - getPriority: () => 0, - homedir: () => virtualHomeDir, - hostname: () => VIRTUAL_OS_HOSTNAME, - loadavg: () => [0, 0, 0], - machine: () => VIRTUAL_OS_MACHINE, - networkInterfaces: () => cloneVirtualNetworkInterfaces(virtualNetworkInterfaces), - platform: () => VIRTUAL_OS_PLATFORM, - release: () => VIRTUAL_OS_RELEASE, - setPriority: () => { - throw accessDenied('os.setPriority'); - }, - tmpdir: () => virtualTmpDir, - totalmem: () => VIRTUAL_OS_TOTALMEM, - type: () => VIRTUAL_OS_TYPE, - uptime: () => 0, - userInfo: (options = undefined) => { - const encoding = - options && typeof options === 'object' ? options.encoding : undefined; - return { - username: encodeUserInfoValue(virtualUserName, encoding), - uid: VIRTUAL_UID, - gid: VIRTUAL_GID, - shell: encodeUserInfoValue(virtualShell, encoding), - homedir: encodeUserInfoValue(virtualHomeDir, encoding), - }; - }, - version: () => VIRTUAL_OS_VERSION, - }); -} - -const guestOs = createGuestOsModule(hostOs); -const guestMemoryUsage = createGuestMemoryUsage(); -const guestProcessUptime = createGuestProcessUptime(); - -function isProcessSignalEventName(eventName) { - return typeof eventName === 'string' && SIGNAL_EVENTS.has(eventName); -} - -function emitControlMessage(message) { - if (CONTROL_PIPE_FD == null) { - if ( - message?.type === 'signal_state' && - typeof process?.stdout?.write === 'function' - ) { - try { - process.stdout.write(`__AGENTOS_WASM_SIGNAL_STATE__:${JSON.stringify(message)}\n`); - } catch { - // Ignore signal-state bridge failures during teardown. - } - } - return; - } - - try { - hostFsWriteSync(CONTROL_PIPE_FD, `${JSON.stringify(message)}\n`); - } catch { - // Ignore control-channel write failures during teardown. - } -} - -function isTrackedProcessSignalEventName(eventName) { - return typeof eventName === 'string' && TRACKED_PROCESS_SIGNAL_EVENTS.has(eventName); -} - -function signalEventsAffectedByProcessMethod(methodName, eventName) { - if (methodName === 'removeAllListeners' && eventName == null) { - return [...TRACKED_PROCESS_SIGNAL_EVENTS]; - } - - return isTrackedProcessSignalEventName(eventName) ? [eventName] : []; -} - -function emitGuestProcessSignalState(eventName) { - if (!isTrackedProcessSignalEventName(eventName)) { - return; - } - - const signal = hostOs.constants?.signals?.[eventName]; - if (typeof signal !== 'number') { - return; - } - - const listenerCount = - typeof process.listenerCount === 'function' ? process.listenerCount(eventName) : 0; - emitControlMessage({ - type: 'signal_state', - signal: Number(signal) >>> 0, - registration: { - action: listenerCount > 0 ? 'user' : 'default', - mask: [], - flags: 0, - }, - }); -} - -function createBlockedProcessSignalMethod(methodName) { - const target = process; - const method = - typeof target[methodName] === 'function' ? target[methodName].bind(target) : null; - if (!method) { - return null; - } - - return (...args) => { - const [eventName] = args; - const affectedSignals = signalEventsAffectedByProcessMethod(methodName, eventName); - if (isProcessSignalEventName(eventName) && affectedSignals.length === 0) { - throw accessDenied(`process.${methodName}(${eventName})`); - } - - const result = method(...args); - for (const signalName of affectedSignals) { - emitGuestProcessSignalState(signalName); - } - return result === target ? guestProcess : result; - }; -} - -function createGuestProcessProxy(target) { - let proxy = null; - proxy = new Proxy(target, { - get(source, key) { - return Reflect.get(source, key, proxy); - }, - }); - return proxy; -} - -function normalizeGuestRequireDir(fromGuestDir) { - if (typeof fromGuestDir !== 'string' || fromGuestDir.length === 0) { - return INITIAL_GUEST_CWD; - } - - if (fromGuestDir.startsWith('file:')) { - try { - return path.posix.normalize(new URL(fromGuestDir).pathname); - } catch { - return INITIAL_GUEST_CWD; - } - } - - if (path.posix.isAbsolute(fromGuestDir)) { - return path.posix.normalize(fromGuestDir); - } - - return path.posix.normalize(path.posix.join(INITIAL_GUEST_CWD, fromGuestDir)); -} - -function isPathWithinRoot(candidatePath, rootPath) { - if (typeof candidatePath !== 'string' || typeof rootPath !== 'string') { - return false; - } - - const normalizedCandidate = path.resolve(candidatePath); - const normalizedRoot = path.resolve(rootPath); - return ( - normalizedCandidate === normalizedRoot || - normalizedCandidate.startsWith(`${normalizedRoot}${path.sep}`) - ); -} - -function runtimeHostPathFromGuestPath(guestPath) { - if (typeof guestPath !== 'string') { - return null; - } - - const translated = hostPathFromGuestPath(guestPath); - if (translated) { - return translated; - } - - const cwdGuestPath = guestPathFromHostPath(HOST_CWD); - if ( - typeof cwdGuestPath !== 'string' || - !path.posix.isAbsolute(guestPath) || - !path.posix.isAbsolute(cwdGuestPath) - ) { - return null; - } - - const relative = path.posix.relative(cwdGuestPath, path.posix.normalize(guestPath)); - if ( - relative.startsWith('..') || - relative === '..' || - path.posix.isAbsolute(relative) - ) { - return null; - } - - return relative ? path.join(HOST_CWD, ...relative.split('/')) : HOST_CWD; -} - -function translateModuleResolutionPath(value) { - if (typeof value !== 'string') { - return value; - } - - if (value.startsWith('file:')) { - try { - const guestPath = path.posix.normalize(new URL(value).pathname); - const hostPath = runtimeHostPathFromGuestPath(guestPath); - return hostPath ? pathToFileURL(hostPath).href : value; - } catch { - return value; - } - } - - if (path.posix.isAbsolute(value)) { - return runtimeHostPathFromGuestPath(value) ?? value; - } - - return value; -} - -function translateModuleResolutionParent(parent) { - if (!parent || typeof parent !== 'object') { - return parent; - } - - let nextParent = parent; - let changed = false; - - if (typeof parent.filename === 'string') { - const translatedFilename = translateModuleResolutionPath(parent.filename); - if (translatedFilename !== parent.filename) { - nextParent = { ...nextParent, filename: translatedFilename }; - changed = true; - } - } - - if (Array.isArray(parent.paths)) { - const translatedPaths = parent.paths.map((entry) => - translateModuleResolutionPath(entry), - ); - if (translatedPaths.some((entry, index) => entry !== parent.paths[index])) { - nextParent = { ...nextParent, paths: translatedPaths }; - changed = true; - } - } - - return changed ? nextParent : parent; -} - -function translateModuleResolutionOptions(options) { - if (Array.isArray(options)) { - return options.map((entry) => translateModuleResolutionPath(entry)); - } - - if (!options || typeof options !== 'object' || !Array.isArray(options.paths)) { - return options; - } - - const translatedPaths = options.paths.map((entry) => - translateModuleResolutionPath(entry), - ); - if (translatedPaths.every((entry, index) => entry === options.paths[index])) { - return options; - } - - return { - ...options, - paths: translatedPaths, - }; -} - -function ensureGuestVisibleModuleResolution(specifier, resolved, parent) { - if (typeof resolved !== 'string' || !path.isAbsolute(resolved)) { - return resolved; - } - - if ( - guestVisiblePathFromHostPath(resolved) || - isPathWithinRoot(resolved, HOST_CWD) - ) { - return resolved; - } - - const error = new Error(`Cannot find module '${specifier}'`); - error.code = 'MODULE_NOT_FOUND'; - if (typeof parent?.filename === 'string') { - error.requireStack = [translatePathStringToGuest(parent.filename)]; - } - throw translateErrorToGuest(error); -} - -function createGuestModuleCacheProxy(moduleCache) { - if (!moduleCache || typeof moduleCache !== 'object') { - return moduleCache; - } - - const toHostKey = (key) => - typeof key === 'string' ? translateModuleResolutionPath(key) : key; - const toGuestKey = (key) => - typeof key === 'string' ? translatePathStringToGuest(key) : key; - - return new Proxy(moduleCache, { - defineProperty(target, key, descriptor) { - return Reflect.defineProperty(target, toHostKey(key), descriptor); - }, - deleteProperty(target, key) { - return Reflect.deleteProperty(target, toHostKey(key)); - }, - get(target, key, receiver) { - return Reflect.get(target, toHostKey(key), receiver); - }, - getOwnPropertyDescriptor(target, key) { - const descriptor = Reflect.getOwnPropertyDescriptor(target, toHostKey(key)); - if (!descriptor) { - return descriptor; - } - return { - ...descriptor, - configurable: true, - }; - }, - has(target, key) { - return Reflect.has(target, toHostKey(key)); - }, - ownKeys(target) { - return Reflect.ownKeys(target).map((key) => toGuestKey(key)); - }, - set(target, key, value, receiver) { - return Reflect.set(target, toHostKey(key), value, receiver); - }, - }); -} - -const guestModuleCache = createGuestModuleCacheProxy(originalModuleCache); - -function createGuestRequire(fromGuestDir) { - const normalizedGuestDir = normalizeGuestRequireDir(fromGuestDir); - const cached = guestRequireCache.get(normalizedGuestDir); - if (cached) { - return cached; - } - - const baseRequire = Module.createRequire( - pathToFileURL(path.posix.join(normalizedGuestDir, '__agentos_require__.cjs')), - ); - - const guestRequire = function(specifier) { - const translated = hostPathForSpecifier(specifier, normalizedGuestDir); - try { - if (translated) { - return baseRequire(translated); - } - - return baseRequire(specifier); - } catch (error) { - if (rootGuestRequire && rootGuestRequire !== guestRequire && isBareSpecifier(specifier)) { - return rootGuestRequire(specifier); - } - throw translateErrorToGuest(error); - } - }; - - guestRequire.resolve = (specifier, options) => { - const translated = hostPathForSpecifier(specifier, normalizedGuestDir); - try { - if (translated) { - return translatePathStringToGuest(baseRequire.resolve(translated, options)); - } - - return translatePathStringToGuest(baseRequire.resolve(specifier, options)); - } catch (error) { - if (rootGuestRequire && rootGuestRequire !== guestRequire && isBareSpecifier(specifier)) { - return rootGuestRequire.resolve(specifier, options); - } - throw translateErrorToGuest(error); - } - }; - - guestRequire.cache = guestModuleCache; - - guestRequireCache.set(normalizedGuestDir, guestRequire); - return guestRequire; -} - -function hardenProperty(target, key, value) { - try { - Object.defineProperty(target, key, { - value, - writable: false, - configurable: false, - }); - } catch (error) { - throw new Error(`Failed to harden property ${String(key)}`, { cause: error }); - } -} - -function encodeSyncRpcValue(value) { - if (value == null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { - return value; - } - - if (typeof Buffer === 'function' && Buffer.isBuffer(value)) { - return { - __agentOSType: 'bytes', - base64: value.toString('base64'), - }; - } - - if (ArrayBuffer.isView(value)) { - return { - __agentOSType: 'bytes', - base64: Buffer.from(value.buffer, value.byteOffset, value.byteLength).toString('base64'), - }; - } - - if (value instanceof ArrayBuffer) { - return { - __agentOSType: 'bytes', - base64: Buffer.from(value).toString('base64'), - }; - } - - if (Array.isArray(value)) { - return value.map((entry) => encodeSyncRpcValue(entry)); - } - - if (typeof value === 'object') { - return Object.fromEntries( - Object.entries(value).map(([key, entry]) => [key, encodeSyncRpcValue(entry)]), - ); - } - - return String(value); -} - -function decodeSyncRpcValue(value) { - if (Array.isArray(value)) { - return value.map((entry) => decodeSyncRpcValue(entry)); - } - - if (Buffer.isBuffer(value)) { - return value; - } - - if (ArrayBuffer.isView(value)) { - return Buffer.from(value.buffer, value.byteOffset, value.byteLength); - } - - if (value && typeof value === 'object') { - if (value.__type === 'Buffer' && typeof value.data === 'string') { - return Buffer.from(value.data, 'base64'); - } - - if (value.__agentOSType === 'bytes' && typeof value.base64 === 'string') { - return Buffer.from(value.base64, 'base64'); - } - - return Object.fromEntries( - Object.entries(value).map(([key, entry]) => [key, decodeSyncRpcValue(entry)]), - ); - } - - return value; -} - -function formatSyncRpcError(error) { - if (error instanceof Error) { - return { - message: error.message, - code: typeof error.code === 'string' ? error.code : undefined, - }; - } - - return { - message: String(error), - }; -} - -function createNodeSyncRpcBridge() { - if (!NODE_SYNC_RPC_ENABLE) { - return null; - } - - if (NODE_SYNC_RPC_REQUEST_FD == null || NODE_SYNC_RPC_RESPONSE_FD == null) { - throw new Error('secure-exec Node sync RPC requires request and response file descriptors'); - } - - const Worker = hostWorkerThreads?.Worker; - if (typeof Worker !== 'function') { - throw new Error('secure-exec Node sync RPC requires node:worker_threads support'); - } - - const STATE_INDEX = 0; - const STATUS_INDEX = 1; - const KIND_INDEX = 2; - const REQUEST_LENGTH_INDEX = 3; - const RESPONSE_LENGTH_INDEX = 4; - const STATE_IDLE = 0; - const STATE_REQUEST_READY = 1; - const STATE_RESPONSE_READY = 2; - const STATE_SHUTDOWN = 3; - const STATUS_OK = 0; - const STATUS_ERROR = 1; - const KIND_JSON = 3; - const signalBuffer = new SharedArrayBuffer(5 * Int32Array.BYTES_PER_ELEMENT); - const dataBuffer = new SharedArrayBuffer(NODE_SYNC_RPC_DATA_BYTES); - const signal = new Int32Array(signalBuffer); - const data = new Uint8Array(dataBuffer); - const encoder = new TextEncoder(); - const decoder = new TextDecoder(); - let nextRequestId = 1; - let disposed = false; - - const workerSource = ` - const { parentPort, workerData } = require('node:worker_threads'); - const { readSync, writeSync, closeSync } = require('node:fs'); - const STATE_INDEX = 0; - const STATUS_INDEX = 1; - const KIND_INDEX = 2; - const REQUEST_LENGTH_INDEX = 3; - const RESPONSE_LENGTH_INDEX = 4; - const STATE_IDLE = 0; - const STATE_REQUEST_READY = 1; - const STATE_RESPONSE_READY = 2; - const STATE_SHUTDOWN = 3; - const STATUS_OK = 0; - const STATUS_ERROR = 1; - const KIND_JSON = 3; - const signal = new Int32Array(workerData.signalBuffer); - const data = new Uint8Array(workerData.dataBuffer); - const responseFd = workerData.responseFd; - const encoder = new TextEncoder(); - const decoder = new TextDecoder(); - let responseBuffer = ''; - - function setResponse(status, bytes) { - let payload = bytes; - let nextStatus = status; - if (payload.byteLength > data.byteLength) { - payload = encoder.encode(JSON.stringify({ - message: 'secure-exec Node sync RPC payload exceeded shared buffer capacity', - code: 'ERR_AGENTOS_NODE_SYNC_RPC_PAYLOAD_TOO_LARGE', - })); - nextStatus = STATUS_ERROR; - } - - data.fill(0); - data.set(payload, 0); - Atomics.store(signal, STATUS_INDEX, nextStatus); - Atomics.store(signal, KIND_INDEX, KIND_JSON); - Atomics.store(signal, RESPONSE_LENGTH_INDEX, payload.byteLength); - Atomics.store(signal, STATE_INDEX, STATE_RESPONSE_READY); - Atomics.notify(signal, STATE_INDEX, 1); - } - - function readResponseLineSync() { - while (true) { - const newlineIndex = responseBuffer.indexOf('\\n'); - if (newlineIndex >= 0) { - const line = responseBuffer.slice(0, newlineIndex); - responseBuffer = responseBuffer.slice(newlineIndex + 1); - return line; - } - - const chunk = Buffer.alloc(4096); - const bytesRead = readSync(responseFd, chunk, 0, chunk.length, null); - if (bytesRead === 0) { - throw new Error('secure-exec Node sync RPC response channel closed unexpectedly'); - } - responseBuffer += chunk.subarray(0, bytesRead).toString('utf8'); - } - } - - function waitForRequest() { - while (true) { - const state = Atomics.load(signal, STATE_INDEX); - if (state === STATE_REQUEST_READY || state === STATE_SHUTDOWN) { - return state; - } - - Atomics.wait(signal, STATE_INDEX, state); - } - } - - try { - while (true) { - const state = waitForRequest(); - if (state === STATE_SHUTDOWN) { - break; - } - - try { - const responseLine = readResponseLineSync(); - setResponse(STATUS_OK, encoder.encode(responseLine)); - } catch (error) { - setResponse( - STATUS_ERROR, - encoder.encode(JSON.stringify({ - message: error instanceof Error ? error.message : String(error), - code: typeof error?.code === 'string' ? error.code : 'ERR_AGENTOS_NODE_SYNC_RPC', - })), - ); - } - } - } finally { - try { - closeSync(responseFd); - } catch {} - } - `; - - const worker = new Worker(workerSource, { - eval: true, - workerData: { - signalBuffer, - dataBuffer, - responseFd: NODE_SYNC_RPC_RESPONSE_FD, - }, - }); - worker.unref?.(); - - const readBytes = (length) => { - if (length <= 0) { - return new Uint8Array(0); - } - return data.slice(0, length); - }; - - const resetSignal = () => { - Atomics.store(signal, STATUS_INDEX, STATUS_OK); - Atomics.store(signal, KIND_INDEX, KIND_JSON); - Atomics.store(signal, REQUEST_LENGTH_INDEX, 0); - Atomics.store(signal, RESPONSE_LENGTH_INDEX, 0); - Atomics.store(signal, STATE_INDEX, STATE_IDLE); - Atomics.notify(signal, STATE_INDEX, 1); - }; - - const requestRaw = (method, args = []) => { - if (disposed) { - throw new Error('secure-exec Node sync RPC bridge is already disposed'); - } - - const payload = encoder.encode( - JSON.stringify({ - id: nextRequestId++, - method, - args: encodeSyncRpcValue(args), - }), - ); - if (payload.byteLength > data.byteLength) { - const error = new Error('secure-exec Node sync RPC request exceeded shared buffer capacity'); - error.code = 'ERR_AGENTOS_NODE_SYNC_RPC_PAYLOAD_TOO_LARGE'; - throw error; - } - - data.fill(0); - data.set(payload, 0); - hostFsWriteSync( - NODE_SYNC_RPC_REQUEST_FD, - `${decoder.decode(data.subarray(0, payload.byteLength))}\n`, - ); - Atomics.store(signal, STATUS_INDEX, STATUS_OK); - Atomics.store(signal, KIND_INDEX, KIND_JSON); - Atomics.store(signal, REQUEST_LENGTH_INDEX, payload.byteLength); - Atomics.store(signal, RESPONSE_LENGTH_INDEX, 0); - Atomics.store(signal, STATE_INDEX, STATE_REQUEST_READY); - Atomics.notify(signal, STATE_INDEX, 1); - - while (true) { - const result = Atomics.wait( - signal, - STATE_INDEX, - STATE_REQUEST_READY, - NODE_SYNC_RPC_WAIT_TIMEOUT_MS, - ); - if (result !== 'timed-out') { - break; - } - throw new Error(`secure-exec Node sync RPC timed out while handling ${method}`); - } - - const status = Atomics.load(signal, STATUS_INDEX); - const kind = Atomics.load(signal, KIND_INDEX); - const length = Atomics.load(signal, RESPONSE_LENGTH_INDEX); - const bytes = readBytes(length); - resetSignal(); - - if (kind !== KIND_JSON) { - throw new Error(`secure-exec Node sync RPC returned unsupported payload kind ${kind}`); - } - - if (status === STATUS_ERROR) { - const payload = JSON.parse(decoder.decode(bytes)); - const error = new Error(payload?.message || `secure-exec Node sync RPC ${method} failed`); - if (typeof payload?.code === 'string') { - error.code = payload.code; - } - throw error; - } - - return JSON.parse(decoder.decode(bytes)); - }; - - return { - callSync(method, args = []) { - const response = requestRaw(method, args); - if (response?.ok) { - return decodeSyncRpcValue(response.result); - } - - const error = new Error( - response?.error?.message || `secure-exec Node sync RPC ${method} failed`, - ); - if (typeof response?.error?.code === 'string') { - error.code = response.error.code; - } - throw error; - }, - async call(method, args = []) { - return this.callSync(method, args); - }, - dispose() { - if (disposed) { - return; - } - disposed = true; - Atomics.store(signal, STATE_INDEX, STATE_SHUTDOWN); - Atomics.notify(signal, STATE_INDEX, 1); - try { - hostFsCloseSync(NODE_SYNC_RPC_REQUEST_FD); - } catch {} - worker.terminate().catch(() => {}); - }, - }; -} - -function installGuestHardening() { - hardenProperty(process, 'env', createGuestProcessEnv(HOST_PROCESS_ENV)); - hardenProperty(process, 'cwd', () => INITIAL_GUEST_CWD); - hardenProperty(process, 'chdir', () => { - throw accessDenied('process.chdir'); - }); - syncBuiltinModuleExports(hostFs, guestFs); - syncBuiltinModuleExports(hostFsPromises, guestFs.promises); - if (ALLOWED_BUILTINS.has('os')) { - syncBuiltinModuleExports(hostOs, guestOs); - } - if (ALLOWED_BUILTINS.has('net')) { - syncBuiltinModuleExports(hostNet, guestNet); - } - if (ALLOWED_BUILTINS.has('dgram')) { - syncBuiltinModuleExports(hostDgram, guestDgram); - } - if (ALLOWED_BUILTINS.has('dns')) { - syncBuiltinModuleExports(hostDns, guestDns); - syncBuiltinModuleExports(hostDnsPromises, guestDns.promises); - } - if (ALLOWED_BUILTINS.has('http')) { - syncBuiltinModuleExports(hostHttp, guestHttp); - } - if (ALLOWED_BUILTINS.has('http2')) { - syncBuiltinModuleExports(hostHttp2, guestHttp2); - } - if (ALLOWED_BUILTINS.has('https')) { - syncBuiltinModuleExports(hostHttps, guestHttps); - } - if (ALLOWED_BUILTINS.has('tls')) { - syncBuiltinModuleExports(hostTls, guestTls); - } - try { - syncBuiltinESMExports(); - } catch { - // Ignore runtimes that reject syncing builtin ESM exports. - } - - hardenProperty(process, 'execPath', VIRTUAL_EXEC_PATH); - hardenProperty(process, 'pid', VIRTUAL_PID); - hardenProperty(process, 'ppid', VIRTUAL_PPID); - hardenProperty(process, 'version', VIRTUAL_PROCESS_VERSION); - hardenProperty(process, 'versions', VIRTUAL_PROCESS_VERSIONS); - hardenProperty(process, 'release', VIRTUAL_PROCESS_RELEASE); - hardenProperty(process, 'config', VIRTUAL_PROCESS_CONFIG); - hardenProperty(process, 'platform', VIRTUAL_OS_PLATFORM); - hardenProperty(process, 'arch', VIRTUAL_OS_ARCH); - hardenProperty(process, 'memoryUsage', guestMemoryUsage); - hardenProperty(process, 'uptime', guestProcessUptime); - hardenProperty(process, 'getuid', guestGetUid); - hardenProperty(process, 'getgid', guestGetGid); - hardenProperty(process, 'umask', guestProcessUmask); - - if (!ALLOW_PROCESS_BINDINGS) { - hardenProperty(process, 'binding', () => { - throw accessDenied('process.binding'); - }); - hardenProperty(process, '_linkedBinding', () => { - throw accessDenied('process._linkedBinding'); - }); - hardenProperty(process, 'dlopen', () => { - throw accessDenied('process.dlopen'); - }); - } - for (const methodName of [ - 'addListener', - 'on', - 'once', - 'removeAllListeners', - 'removeListener', - 'off', - 'prependListener', - 'prependOnceListener', - ]) { - const blockedMethod = createBlockedProcessSignalMethod(methodName); - if (blockedMethod) { - hardenProperty(process, methodName, blockedMethod); - } - } - if (Module?._extensions && typeof Module._extensions === 'object') { - hardenProperty(Module._extensions, '.node', () => { - throw accessDenied('native addon loading'); - }); - } - if (originalGetBuiltinModule) { - hardenProperty(process, 'getBuiltinModule', (specifier) => { - const normalized = - typeof specifier === 'string' ? normalizeBuiltin(specifier) : null; - if (normalized === 'process') { - return guestProcess; - } - if (normalized === 'fs') { - return cloneFsModule(guestFs); - } - if (normalized === 'os' && ALLOWED_BUILTINS.has('os')) { - return guestOs; - } - if (normalized === 'net' && ALLOWED_BUILTINS.has('net')) { - return guestNet; - } - if (normalized === 'dgram' && ALLOWED_BUILTINS.has('dgram')) { - return guestDgram; - } - if (normalized === 'dns' && ALLOWED_BUILTINS.has('dns')) { - return guestDns; - } - if (normalized === 'dns/promises' && ALLOWED_BUILTINS.has('dns')) { - return guestDns.promises; - } - if (normalized === 'http' && ALLOWED_BUILTINS.has('http')) { - return guestHttp; - } - if (normalized === 'http2' && ALLOWED_BUILTINS.has('http2')) { - return guestHttp2; - } - if (normalized === 'https' && ALLOWED_BUILTINS.has('https')) { - return guestHttps; - } - if (normalized === 'tls' && ALLOWED_BUILTINS.has('tls')) { - return guestTls; - } - if (normalized === 'child_process' && ALLOWED_BUILTINS.has('child_process')) { - return guestChildProcess; - } - if (normalized && DENIED_BUILTINS.has(normalized)) { - throw accessDenied(`node:${normalized}`); - } - return originalGetBuiltinModule(specifier); - }); - } - - if (originalModuleLoad) { - Module._load = function(request, parent, isMain) { - const normalized = - typeof request === 'string' ? normalizeBuiltin(request) : null; - if (normalized === 'process') { - return guestProcess; - } - if (normalized === 'fs') { - return cloneFsModule(guestFs); - } - if (normalized === 'os' && ALLOWED_BUILTINS.has('os')) { - return guestOs; - } - if (normalized === 'net' && ALLOWED_BUILTINS.has('net')) { - return guestNet; - } - if (normalized === 'dgram' && ALLOWED_BUILTINS.has('dgram')) { - return guestDgram; - } - if (normalized === 'dns' && ALLOWED_BUILTINS.has('dns')) { - return guestDns; - } - if (normalized === 'dns/promises' && ALLOWED_BUILTINS.has('dns')) { - return guestDns.promises; - } - if (normalized === 'http' && ALLOWED_BUILTINS.has('http')) { - return guestHttp; - } - if (normalized === 'http2' && ALLOWED_BUILTINS.has('http2')) { - return guestHttp2; - } - if (normalized === 'https' && ALLOWED_BUILTINS.has('https')) { - return guestHttps; - } - if (normalized === 'tls' && ALLOWED_BUILTINS.has('tls')) { - return guestTls; - } - if (normalized === 'child_process' && ALLOWED_BUILTINS.has('child_process')) { - return guestChildProcess; - } - if (normalized && DENIED_BUILTINS.has(normalized)) { - throw accessDenied(`node:${normalized}`); - } - - return originalModuleLoad(request, parent, isMain); - }; - } - - if (originalModuleResolveFilename) { - Module._resolveFilename = function(request, parent, isMain, options) { - const translatedRequest = translateModuleResolutionPath(request); - const translatedParent = translateModuleResolutionParent(parent); - const translatedOptions = translateModuleResolutionOptions(options); - const resolved = originalModuleResolveFilename( - translatedRequest, - translatedParent, - isMain, - translatedOptions, - ); - return ensureGuestVisibleModuleResolution( - request, - resolved, - translatedParent, - ); - }; - } - - if (guestModuleCache) { - hardenProperty(Module, '_cache', guestModuleCache); - } - - if (originalFetch) { - const restrictedFetch = async (resource, init) => { - const candidate = - typeof resource === 'string' - ? resource - : resource instanceof URL - ? resource.href - : resource?.url; - - let url; - try { - url = new URL(String(candidate ?? '')); - } catch { - throw accessDenied('network access'); - } - - if (url.protocol !== 'data:') { - const normalizedPort = - url.port || (url.protocol === 'https:' ? '443' : url.protocol === 'http:' ? '80' : ''); - const loopbackHost = - url.hostname === '127.0.0.1' || - url.hostname === 'localhost' || - url.hostname === '::1' || - url.hostname === '[::1]'; - const loopbackAllowed = - loopbackHost && - (url.protocol === 'http:' || url.protocol === 'https:') && - LOOPBACK_EXEMPT_PORTS.has(normalizedPort); - - if (!loopbackAllowed) { - throw accessDenied(`network access to ${url.protocol}`); - } - } - - return originalFetch(resource, init); - }; - - hardenProperty(globalThis, 'fetch', restrictedFetch); - } -} - -const entrypoint = HOST_PROCESS_ENV.AGENTOS_ENTRYPOINT; -if (!entrypoint) { - throw new Error('AGENTOS_ENTRYPOINT is required'); -} - -const guestSyncRpc = createNodeSyncRpcBridge(); -installGuestHardening(); -rootGuestRequire = createGuestRequire('/root/node_modules'); -if (ALLOWED_BUILTINS.has('child_process')) { - hardenProperty(globalThis, '__agentOSBuiltinChildProcess', guestChildProcess); -} -hardenProperty(globalThis, '__agentOSBuiltinFs', guestFs); -if (ALLOWED_BUILTINS.has('net')) { - hardenProperty(globalThis, '__agentOSBuiltinNet', guestNet); -} -if (ALLOWED_BUILTINS.has('dgram')) { - hardenProperty(globalThis, '__agentOSBuiltinDgram', guestDgram); -} -if (ALLOWED_BUILTINS.has('dns')) { - hardenProperty(globalThis, '__agentOSBuiltinDns', guestDns); -} -if (ALLOWED_BUILTINS.has('http')) { - hardenProperty(globalThis, '__agentOSBuiltinHttp', guestHttp); -} -if (ALLOWED_BUILTINS.has('http2')) { - hardenProperty(globalThis, '__agentOSBuiltinHttp2', guestHttp2); -} -if (ALLOWED_BUILTINS.has('https')) { - hardenProperty(globalThis, '__agentOSBuiltinHttps', guestHttps); -} -if (ALLOWED_BUILTINS.has('tls')) { - hardenProperty(globalThis, '__agentOSBuiltinTls', guestTls); -} -if (ALLOWED_BUILTINS.has('os')) { - hardenProperty(globalThis, '__agentOSBuiltinOs', guestOs); -} -if (guestSyncRpc) { - hardenProperty(globalThis, '__agentOSSyncRpc', guestSyncRpc); -} -hardenProperty(globalThis, '_requireFrom', (specifier, fromDir = '/') => - createGuestRequire(fromDir)(specifier), -); -hardenProperty( - globalThis, - 'require', - createGuestRequire(path.posix.dirname(guestEntryPoint ?? entrypoint)), -); - -if (HOST_PROCESS_ENV.SECURE_EXEC_KEEP_STDIN_OPEN === '1') { - let stdinKeepalive = setInterval(() => {}, 1_000_000); - const releaseStdinKeepalive = () => { - if (stdinKeepalive !== null) { - clearInterval(stdinKeepalive); - stdinKeepalive = null; - } - }; - - process.stdin.resume(); - process.stdin.once('end', releaseStdinKeepalive); - process.stdin.once('close', releaseStdinKeepalive); - process.stdin.once('error', releaseStdinKeepalive); -} - -const guestArgv = JSON.parse(HOST_PROCESS_ENV.AGENTOS_GUEST_ARGV ?? '[]'); -const bootstrapModule = HOST_PROCESS_ENV.AGENTOS_BOOTSTRAP_MODULE; -const entrypointPath = isPathLike(entrypoint) - ? path.resolve(process.cwd(), entrypoint) - : entrypoint; - -process.argv = [VIRTUAL_EXEC_PATH, guestEntryPoint ?? entrypointPath, ...guestArgv]; -guestProcess = createGuestProcessProxy(process); -hardenProperty(globalThis, 'process', guestProcess); - -try { - if (bootstrapModule) { - await import(toImportSpecifier(bootstrapModule)); - } - - await import(toImportSpecifier(entrypoint)); -} catch (error) { - throw translateErrorToGuest(error); -} finally { - guestSyncRpc?.dispose?.(); -} -"#; - -const NODE_TIMING_BOOTSTRAP_SOURCE: &str = r#" -const frozenTimeValue = Number(process.env.AGENTOS_FROZEN_TIME_MS); -const frozenTimeMs = Number.isFinite(frozenTimeValue) ? Math.trunc(frozenTimeValue) : Date.now(); -const frozenDateNow = () => frozenTimeMs; -const OriginalDate = Date; - -function FrozenDate(...args) { - if (new.target) { - if (args.length === 0) { - return new OriginalDate(frozenTimeMs); - } - return new OriginalDate(...args); - } - return new OriginalDate(frozenTimeMs).toString(); -} - -Object.setPrototypeOf(FrozenDate, OriginalDate); -Object.defineProperty(FrozenDate, 'prototype', { - value: OriginalDate.prototype, - writable: false, - configurable: false, -}); -FrozenDate.parse = OriginalDate.parse; -FrozenDate.UTC = OriginalDate.UTC; -Object.defineProperty(FrozenDate, 'now', { - value: frozenDateNow, - writable: false, - configurable: false, -}); - -try { - Object.defineProperty(globalThis, 'Date', { - value: FrozenDate, - writable: false, - configurable: false, - }); -} catch { - globalThis.Date = FrozenDate; -} - -const originalPerformance = globalThis.performance; -const frozenPerformance = Object.create(null); -if (typeof originalPerformance !== 'undefined' && originalPerformance !== null) { - const performanceSource = - Object.getPrototypeOf(originalPerformance) ?? originalPerformance; - for (const key of Object.getOwnPropertyNames(performanceSource)) { - if (key === 'now') { - continue; - } - try { - const value = originalPerformance[key]; - frozenPerformance[key] = - typeof value === 'function' ? value.bind(originalPerformance) : value; - } catch { - // Ignore properties that throw during access. - } - } -} -Object.defineProperty(frozenPerformance, 'now', { - value: () => 0, - writable: false, - configurable: false, -}); -Object.freeze(frozenPerformance); - -try { - Object.defineProperty(globalThis, 'performance', { - value: frozenPerformance, - writable: false, - configurable: false, - }); -} catch { - globalThis.performance = frozenPerformance; -} - -const frozenHrtimeBigint = BigInt(frozenTimeMs) * 1000000n; -const frozenHrtime = (previous) => { - const seconds = Math.trunc(frozenTimeMs / 1000); - const nanoseconds = Math.trunc((frozenTimeMs % 1000) * 1000000); - - if (!Array.isArray(previous) || previous.length < 2) { - return [seconds, nanoseconds]; - } - - let deltaSeconds = seconds - Number(previous[0]); - let deltaNanoseconds = nanoseconds - Number(previous[1]); - if (deltaNanoseconds < 0) { - deltaSeconds -= 1; - deltaNanoseconds += 1000000000; - } - return [deltaSeconds, deltaNanoseconds]; -}; -frozenHrtime.bigint = () => frozenHrtimeBigint; - -try { - process.hrtime = frozenHrtime; -} catch { - // Ignore runtimes that expose a non-writable process.hrtime binding. -} -"#; - -const NODE_PREWARM_SOURCE: &str = r#" -import path from 'node:path'; -import { pathToFileURL } from 'node:url'; - -function isPathLike(specifier) { - return specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('file:'); -} - -function toImportSpecifier(specifier) { - if (specifier.startsWith('file:')) { - return specifier; - } - if (isPathLike(specifier)) { - return pathToFileURL(path.resolve(process.cwd(), specifier)).href; - } - return specifier; -} - -const imports = JSON.parse(process.env.AGENTOS_NODE_PREWARM_IMPORTS ?? '[]'); -for (const specifier of imports) { - await import(toImportSpecifier(specifier)); -} -"#; - -const NODE_WASM_RUNNER_SOURCE: &str = include_str!("../assets/runners/wasm-runner.mjs"); - -static NEXT_NODE_IMPORT_CACHE_ID: AtomicU64 = AtomicU64::new(1); - -#[derive(Clone, Copy)] -struct BuiltinAsset { - name: &'static str, - module_specifier: &'static str, - init_counter_key: &'static str, -} - -#[derive(Clone, Copy)] -struct DeniedBuiltinAsset { - name: &'static str, - module_specifier: &'static str, -} - -const BUILTIN_ASSETS: &[BuiltinAsset] = &[ - BuiltinAsset { - name: "async-hooks", - module_specifier: "node:async_hooks", - init_counter_key: "__agentOSBuiltinAsyncHooksInitCount", - }, - BuiltinAsset { - name: "assert", - module_specifier: "node:assert", - init_counter_key: "__agentOSBuiltinAssertInitCount", - }, - BuiltinAsset { - name: "buffer", - module_specifier: "node:buffer", - init_counter_key: "__agentOSBuiltinBufferInitCount", - }, - BuiltinAsset { - name: "constants", - module_specifier: "node:constants", - init_counter_key: "__agentOSBuiltinConstantsInitCount", - }, - BuiltinAsset { - name: "events", - module_specifier: "node:events", - init_counter_key: "__agentOSBuiltinEventsInitCount", - }, - BuiltinAsset { - name: "fs", - module_specifier: "node:fs", - init_counter_key: "__agentOSBuiltinFsInitCount", - }, - BuiltinAsset { - name: "path", - module_specifier: "node:path", - init_counter_key: "__agentOSBuiltinPathInitCount", - }, - BuiltinAsset { - name: "url", - module_specifier: "node:url", - init_counter_key: "__agentOSBuiltinUrlInitCount", - }, - BuiltinAsset { - name: "fs-promises", - module_specifier: "node:fs/promises", - init_counter_key: "__agentOSBuiltinFsPromisesInitCount", - }, - BuiltinAsset { - name: "child-process", - module_specifier: "node:child_process", - init_counter_key: "__agentOSBuiltinChildProcessInitCount", - }, - BuiltinAsset { - name: "net", - module_specifier: "node:net", - init_counter_key: "__agentOSBuiltinNetInitCount", - }, - BuiltinAsset { - name: "dgram", - module_specifier: "node:dgram", - init_counter_key: "__agentOSBuiltinDgramInitCount", - }, - BuiltinAsset { - name: "diagnostics-channel", - module_specifier: "node:diagnostics_channel", - init_counter_key: "__agentOSBuiltinDiagnosticsChannelInitCount", - }, - BuiltinAsset { - name: "dns", - module_specifier: "node:dns", - init_counter_key: "__agentOSBuiltinDnsInitCount", - }, - BuiltinAsset { - name: "dns-promises", - module_specifier: "node:dns/promises", - init_counter_key: "__agentOSBuiltinDnsPromisesInitCount", - }, - BuiltinAsset { - name: "http", - module_specifier: "node:http", - init_counter_key: "__agentOSBuiltinHttpInitCount", - }, - BuiltinAsset { - name: "http2", - module_specifier: "node:http2", - init_counter_key: "__agentOSBuiltinHttp2InitCount", - }, - BuiltinAsset { - name: "https", - module_specifier: "node:https", - init_counter_key: "__agentOSBuiltinHttpsInitCount", - }, - BuiltinAsset { - name: "tls", - module_specifier: "node:tls", - init_counter_key: "__agentOSBuiltinTlsInitCount", - }, - BuiltinAsset { - name: "os", - module_specifier: "node:os", - init_counter_key: "__agentOSBuiltinOsInitCount", - }, - BuiltinAsset { - name: "punycode", - module_specifier: "node:punycode", - init_counter_key: "__agentOSBuiltinPunycodeInitCount", - }, - BuiltinAsset { - name: "querystring", - module_specifier: "node:querystring", - init_counter_key: "__agentOSBuiltinQuerystringInitCount", - }, - BuiltinAsset { - name: "stream", - module_specifier: "node:stream", - init_counter_key: "__agentOSBuiltinStreamInitCount", - }, - BuiltinAsset { - name: "string-decoder", - module_specifier: "node:string_decoder", - init_counter_key: "__agentOSBuiltinStringDecoderInitCount", - }, - BuiltinAsset { - name: "util", - module_specifier: "node:util", - init_counter_key: "__agentOSBuiltinUtilInitCount", - }, - BuiltinAsset { - name: "v8", - module_specifier: "node:v8", - init_counter_key: "__agentOSBuiltinV8InitCount", - }, - BuiltinAsset { - name: "vm", - module_specifier: "node:vm", - init_counter_key: "__agentOSBuiltinVmInitCount", - }, - BuiltinAsset { - name: "worker-threads", - module_specifier: "node:worker_threads", - init_counter_key: "__agentOSBuiltinWorkerThreadsInitCount", - }, - BuiltinAsset { - name: "zlib", - module_specifier: "node:zlib", - init_counter_key: "__agentOSBuiltinZlibInitCount", - }, -]; - -const DENIED_BUILTIN_ASSETS: &[DeniedBuiltinAsset] = &[ - DeniedBuiltinAsset { - name: "child_process", - module_specifier: "node:child_process", - }, - DeniedBuiltinAsset { - name: "cluster", - module_specifier: "node:cluster", - }, - DeniedBuiltinAsset { - name: "dgram", - module_specifier: "node:dgram", - }, - DeniedBuiltinAsset { - name: "http", - module_specifier: "node:http", - }, - DeniedBuiltinAsset { - name: "http2", - module_specifier: "node:http2", - }, - DeniedBuiltinAsset { - name: "https", - module_specifier: "node:https", - }, - DeniedBuiltinAsset { - name: "inspector", - module_specifier: "node:inspector", - }, - DeniedBuiltinAsset { - name: "module", - module_specifier: "node:module", - }, - DeniedBuiltinAsset { - name: "net", - module_specifier: "node:net", - }, - DeniedBuiltinAsset { - name: "trace_events", - module_specifier: "node:trace_events", - }, -]; - -const PATH_POLYFILL_ASSET_NAME: &str = "path"; -const PATH_POLYFILL_INIT_COUNTER_KEY: &str = "__agentOSPolyfillPathInitCount"; - -#[derive(Debug)] -pub(crate) struct NodeImportCache { - root_dir: PathBuf, - cleanup: Arc, - materialized: AtomicBool, - cache_path: PathBuf, - loader_path: PathBuf, - register_path: PathBuf, - runner_path: PathBuf, - python_runner_path: PathBuf, - timing_bootstrap_path: PathBuf, - prewarm_path: PathBuf, - wasm_runner_path: PathBuf, - asset_root: PathBuf, - pyodide_dist_path: PathBuf, - prewarm_marker_dir: PathBuf, -} - -#[derive(Debug)] -pub(crate) struct NodeImportCacheCleanup { - root_dir: PathBuf, -} - -#[derive(Debug, Clone)] -struct NodeImportCacheMaterialization { - root_dir: PathBuf, - loader_path: PathBuf, - register_path: PathBuf, - runner_path: PathBuf, - python_runner_path: PathBuf, - timing_bootstrap_path: PathBuf, - prewarm_path: PathBuf, - wasm_runner_path: PathBuf, - asset_root: PathBuf, - pyodide_dist_path: PathBuf, - prewarm_marker_dir: PathBuf, -} - -impl Default for NodeImportCache { - fn default() -> Self { - Self::new_in(default_node_import_cache_base_dir()) - } -} - -fn default_node_import_cache_base_dir() -> PathBuf { - env::temp_dir().join(format!( - "{NODE_IMPORT_CACHE_DIR_PREFIX}-roots-{}", - std::process::id() - )) -} - -fn cleanup_stale_node_import_caches_once(base_dir: &Path) { - let cleaned_roots = CLEANED_NODE_IMPORT_CACHE_ROOTS.get_or_init(|| Mutex::new(BTreeSet::new())); - let should_cleanup = cleaned_roots - .lock() - .map(|mut roots| roots.insert(base_dir.to_path_buf())) - .unwrap_or(true); - - if should_cleanup { - cleanup_stale_node_import_caches(base_dir); - } -} - -fn cleanup_stale_node_import_caches(base_dir: &Path) { - let entries = match fs::read_dir(base_dir) { - Ok(entries) => entries, - Err(error) if error.kind() == io::ErrorKind::NotFound => return, - Err(error) => { - eprintln!( - "agentos: failed to scan node import cache root {}: {error}", - base_dir.display() - ); - return; - } - }; - - for entry in entries.flatten() { - let file_type = match entry.file_type() { - Ok(file_type) => file_type, - Err(_) => continue, - }; - if !file_type.is_dir() { - continue; - } - - let name = entry.file_name(); - if !name - .to_str() - .is_some_and(|name| name.starts_with(NODE_IMPORT_CACHE_DIR_PREFIX)) - { - continue; - } - - let path = entry.path(); - if let Err(error) = fs::remove_dir_all(&path) { - if error.kind() != io::ErrorKind::NotFound { - eprintln!( - "agentos: failed to clean up stale node import cache {}: {error}", - path.display() - ); - } - } - } -} - -impl NodeImportCache { - pub(crate) fn new_in(base_dir: PathBuf) -> Self { - cleanup_stale_node_import_caches_once(&base_dir); - let cache_id = NEXT_NODE_IMPORT_CACHE_ID.fetch_add(1, Ordering::Relaxed); - let root_dir = base_dir.join(format!( - "{NODE_IMPORT_CACHE_DIR_PREFIX}-{}-{cache_id}", - std::process::id() - )); - - Self { - root_dir: root_dir.clone(), - cleanup: Arc::new(NodeImportCacheCleanup { - root_dir: root_dir.clone(), - }), - materialized: AtomicBool::new(false), - cache_path: root_dir.join("state.json"), - loader_path: root_dir.join("loader.mjs"), - register_path: root_dir.join("register.mjs"), - runner_path: root_dir.join("runner.mjs"), - python_runner_path: root_dir.join("python-runner.mjs"), - timing_bootstrap_path: root_dir.join("timing-bootstrap.mjs"), - prewarm_path: root_dir.join("prewarm.mjs"), - wasm_runner_path: root_dir.join("wasm-runner.mjs"), - asset_root: root_dir.join("assets"), - pyodide_dist_path: root_dir.join("assets").join(PYODIDE_DIST_DIR), - prewarm_marker_dir: root_dir.join("warmup"), - } - } -} - -impl Drop for NodeImportCacheCleanup { - fn drop(&mut self) { - if let Err(error) = fs::remove_dir_all(&self.root_dir) { - if error.kind() != io::ErrorKind::NotFound { - eprintln!( - "agentos: failed to clean up node import cache {}: {error}", - self.root_dir.display() - ); - } - } - } -} - -impl NodeImportCache { - pub(crate) fn cache_path(&self) -> &Path { - &self.cache_path - } - - pub(crate) fn cleanup_guard(&self) -> Arc { - Arc::clone(&self.cleanup) - } - - #[cfg_attr(not(test), allow(dead_code))] - pub(crate) fn python_runner_path(&self) -> &Path { - &self.python_runner_path - } - - #[cfg(test)] - pub(crate) fn timing_bootstrap_path(&self) -> &Path { - &self.timing_bootstrap_path - } - - pub(crate) fn wasm_runner_path(&self) -> &Path { - &self.wasm_runner_path - } - - pub(crate) fn asset_root(&self) -> &Path { - &self.asset_root - } - - pub(crate) fn pyodide_dist_path(&self) -> &Path { - &self.pyodide_dist_path - } - - pub(crate) fn prewarm_marker_dir(&self) -> &Path { - &self.prewarm_marker_dir - } - - pub(crate) fn shared_compile_cache_dir(&self) -> PathBuf { - self.root_dir.join("compile-cache") - } - - pub(crate) fn ensure_materialized(&self) -> Result<(), io::Error> { - self.ensure_materialized_with_timeout(DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT) - } - - pub(crate) fn ensure_materialized_with_timeout( - &self, - timeout: Duration, - ) -> Result<(), io::Error> { - if self.materialized.load(Ordering::Acquire) { - return Ok(()); - } - - let materialization = NodeImportCacheMaterialization::from(self); - let (sender, receiver) = std::sync::mpsc::channel(); - std::thread::spawn(move || { - let _ = sender.send(materialization.materialize()); - }); - - match receiver.recv_timeout(timeout) { - Ok(result) => { - result?; - self.materialized.store(true, Ordering::Release); - Ok(()) - } - Err(std::sync::mpsc::RecvTimeoutError::Timeout) => Err(io::Error::new( - io::ErrorKind::TimedOut, - format!( - "timed out materializing node import cache after {} ms", - timeout.as_millis() - ), - )), - Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => Err(io::Error::other( - "node import cache materialization thread exited unexpectedly", - )), - } - } -} - -impl From<&NodeImportCache> for NodeImportCacheMaterialization { - fn from(cache: &NodeImportCache) -> Self { - Self { - root_dir: cache.root_dir.clone(), - loader_path: cache.loader_path.clone(), - register_path: cache.register_path.clone(), - runner_path: cache.runner_path.clone(), - python_runner_path: cache.python_runner_path.clone(), - timing_bootstrap_path: cache.timing_bootstrap_path.clone(), - prewarm_path: cache.prewarm_path.clone(), - wasm_runner_path: cache.wasm_runner_path.clone(), - asset_root: cache.asset_root.clone(), - pyodide_dist_path: cache.pyodide_dist_path.clone(), - prewarm_marker_dir: cache.prewarm_marker_dir.clone(), - } - } -} - -impl NodeImportCacheMaterialization { - fn materialize(self) -> Result<(), io::Error> { - #[cfg(test)] - { - let delay_ms = NODE_IMPORT_CACHE_TEST_MATERIALIZE_DELAY_MS.load(Ordering::Relaxed); - if delay_ms > 0 { - std::thread::sleep(Duration::from_millis(delay_ms)); - } - } - - fs::create_dir_all(&self.root_dir)?; - fs::create_dir_all(self.asset_root.join("builtins"))?; - fs::create_dir_all(self.asset_root.join("denied"))?; - fs::create_dir_all(self.asset_root.join("polyfills"))?; - fs::create_dir_all(&self.pyodide_dist_path)?; - fs::create_dir_all(&self.prewarm_marker_dir)?; - - write_file_if_changed(&self.loader_path, &render_loader_source())?; - write_file_if_changed(&self.register_path, &render_register_source())?; - write_file_if_changed(&self.runner_path, NODE_EXECUTION_RUNNER_SOURCE)?; - write_file_if_changed(&self.python_runner_path, NODE_PYTHON_RUNNER_SOURCE)?; - write_file_if_changed(&self.timing_bootstrap_path, NODE_TIMING_BOOTSTRAP_SOURCE)?; - write_file_if_changed(&self.prewarm_path, NODE_PREWARM_SOURCE)?; - write_file_if_changed(&self.wasm_runner_path, NODE_WASM_RUNNER_SOURCE)?; - - for asset in BUILTIN_ASSETS { - write_file_if_changed( - &self - .asset_root - .join("builtins") - .join(format!("{}.mjs", asset.name)), - &render_builtin_asset_source(asset), - )?; - } - - for asset in DENIED_BUILTIN_ASSETS { - write_file_if_changed( - &self - .asset_root - .join("denied") - .join(format!("{}.mjs", asset.name)), - &render_denied_asset_source(asset.module_specifier), - )?; - } - - write_file_if_changed( - &self - .asset_root - .join("polyfills") - .join(format!("{PATH_POLYFILL_ASSET_NAME}.mjs")), - &render_path_polyfill_source(), - )?; - write_file_if_changed( - &self.pyodide_dist_path.join("pyodide.mjs"), - &render_patched_pyodide_mjs(), - )?; - write_bytes_if_changed( - &self.pyodide_dist_path.join("pyodide.asm.js"), - BUNDLED_PYODIDE_ASM_JS, - )?; - write_bytes_if_changed( - &self.pyodide_dist_path.join("pyodide.asm.wasm"), - BUNDLED_PYODIDE_ASM_WASM, - )?; - write_bytes_if_changed( - &self.pyodide_dist_path.join("pyodide-lock.json"), - BUNDLED_PYODIDE_LOCK, - )?; - write_bytes_if_changed( - &self.pyodide_dist_path.join("python_stdlib.zip"), - BUNDLED_PYTHON_STDLIB_ZIP, - )?; - for asset in BUNDLED_PYODIDE_PACKAGE_ASSETS { - write_bytes_if_changed(&self.pyodide_dist_path.join(asset.file_name), asset.bytes)?; - } - Ok(()) - } -} - -fn render_loader_source() -> String { - NODE_IMPORT_CACHE_LOADER_TEMPLATE - .replace("__NODE_IMPORT_CACHE_PATH_ENV__", NODE_IMPORT_CACHE_PATH_ENV) - .replace( - "__NODE_IMPORT_CACHE_ASSET_ROOT_ENV__", - NODE_IMPORT_CACHE_ASSET_ROOT_ENV, - ) - .replace( - "__NODE_IMPORT_CACHE_DEBUG_ENV__", - NODE_IMPORT_CACHE_DEBUG_ENV, - ) - .replace( - "__NODE_IMPORT_CACHE_METRICS_PREFIX__", - NODE_IMPORT_CACHE_METRICS_PREFIX, - ) - .replace( - "__NODE_IMPORT_CACHE_SCHEMA_VERSION__", - NODE_IMPORT_CACHE_SCHEMA_VERSION, - ) - .replace( - "__NODE_IMPORT_CACHE_LOADER_VERSION__", - NODE_IMPORT_CACHE_LOADER_VERSION, - ) - .replace( - "__NODE_IMPORT_CACHE_ASSET_VERSION__", - NODE_IMPORT_CACHE_ASSET_VERSION, - ) - .replace( - "__SECURE_EXEC_BUILTIN_SPECIFIER_PREFIX__", - SECURE_EXEC_BUILTIN_SPECIFIER_PREFIX, - ) - .replace( - "__SECURE_EXEC_POLYFILL_SPECIFIER_PREFIX__", - SECURE_EXEC_POLYFILL_SPECIFIER_PREFIX, - ) -} - -fn render_patched_pyodide_mjs() -> String { - let source = String::from_utf8_lossy(BUNDLED_PYODIDE_MJS); - source - .replace( - r#"H=(await import("node:vm")).default,"#, - "", - ) - .replace( - r#"async function fe(e){e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?H.runInThisContext(await(await fetch(e)).text()):await import(e.startsWith("/" )?e:$.pathToFileURL(e).href)}o(fe,"nodeLoadScript");"#, - r#"async function fe(e){if(e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")){let t=await(await fetch(e)).text();await import(`data:text/javascript;base64,${$e(t)}`);return}await import(e.startsWith("/")?e:$.pathToFileURL(e).href)}o(fe,"nodeLoadScript");"#, - ) - .replace( - r#"function Ne(e){if(typeof WasmOffsetConverter<"u")return;let{binary:t,response:n}=R(e+"pyodide.asm.wasm"),i=K();return function(s,r){return async function(){s.sentinel=await i;try{let a;if(n){a=await WebAssembly.instantiateStreaming(n,s);}else{let l=await t;a=await WebAssembly.instantiate(l,s);}let{instance:l,module:c}=a;r(l,c);}catch(a){console.warn("wasm instantiation failed!"),console.warn(a)}}(),{}}}o(Ne,"getInstantiateWasmFunc");"#, - r#"function Ne(e){if(typeof WasmOffsetConverter<"u")return;let{binary:t,response:n}=R(e+"pyodide.asm.wasm"),i=K();return function(s,r){return async function(){s.sentinel=await i;try{let a;if(n){a=await WebAssembly.instantiateStreaming(n,s);}else{let l=await t;a=await WebAssembly.instantiate(l,s);}let{instance:l,module:c}=a;r(l,c);}catch(a){console.warn("wasm instantiation failed!"),console.warn(a);throw a}}(),{}}}o(Ne,"getInstantiateWasmFunc");"#, - ) -} - -fn render_register_source() -> String { - NODE_IMPORT_CACHE_REGISTER_SOURCE.replace( - "__NODE_IMPORT_CACHE_LOADER_PATH_ENV__", - NODE_IMPORT_CACHE_LOADER_PATH_ENV, - ) -} - -fn render_builtin_asset_source(asset: &BuiltinAsset) -> String { - match asset.name { - "async-hooks" => render_async_hooks_builtin_asset_source(asset.init_counter_key), - "fs" => render_fs_builtin_asset_source(asset.init_counter_key), - "fs-promises" => render_fs_promises_builtin_asset_source(asset.init_counter_key), - "child-process" => render_child_process_builtin_asset_source(asset.init_counter_key), - "net" => render_net_builtin_asset_source(asset.init_counter_key), - "dgram" => render_dgram_builtin_asset_source(asset.init_counter_key), - "diagnostics-channel" => { - render_diagnostics_channel_builtin_asset_source(asset.init_counter_key) - } - "dns" => render_dns_builtin_asset_source(asset.init_counter_key), - "dns-promises" => render_dns_promises_builtin_asset_source(asset.init_counter_key), - "http" => render_http_builtin_asset_source(asset.init_counter_key), - "http2" => render_http2_builtin_asset_source(asset.init_counter_key), - "https" => render_https_builtin_asset_source(asset.init_counter_key), - "tls" => render_tls_builtin_asset_source(asset.init_counter_key), - "os" => render_os_builtin_asset_source(asset.init_counter_key), - "util" => render_util_builtin_asset_source(asset.init_counter_key), - "v8" => render_v8_builtin_asset_source(asset.init_counter_key), - "vm" => render_vm_builtin_asset_source(asset.init_counter_key), - "worker-threads" => render_worker_threads_builtin_asset_source(asset.init_counter_key), - _ => { - render_passthrough_builtin_asset_source(asset.module_specifier, asset.init_counter_key) - } - } -} - -fn render_passthrough_builtin_asset_source( - module_specifier: &str, - init_counter_key: &str, -) -> String { - let module_specifier = format!("{module_specifier:?}"); - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "import * as namespace from {module_specifier};\n\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -const builtin = namespace.default ?? namespace;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default builtin;\n\ -export * from {module_specifier};\n" - ) -} - -fn render_util_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "import * as namespace from \"node:util\";\n\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -const builtin = namespace.default ?? namespace;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default builtin;\n\ -export const formatWithOptions = builtin.formatWithOptions;\n\ -export * from \"node:util\";\n" - ) -} - -fn render_fs_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -const mod = globalThis.__agentOSBuiltinFs ?? globalThis.__agentOSGuestFs ?? process.getBuiltinModule?.(\"node:fs\");\n\ -if (!mod) {{\n\ - throw new Error('secure-exec guest fs polyfill was not initialized');\n\ -}}\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const Dir = mod.Dir;\n\ -export const Dirent = mod.Dirent;\n\ -export const ReadStream = mod.ReadStream;\n\ -export const Stats = mod.Stats;\n\ -export const WriteStream = mod.WriteStream;\n\ -export const constants = mod.constants;\n\ -export const promises = mod.promises;\n\ -export const access = mod.access;\n\ -export const accessSync = mod.accessSync;\n\ -export const appendFile = mod.appendFile;\n\ -export const appendFileSync = mod.appendFileSync;\n\ -export const chmod = mod.chmod;\n\ -export const chmodSync = mod.chmodSync;\n\ -export const chown = mod.chown;\n\ -export const chownSync = mod.chownSync;\n\ -export const close = mod.close;\n\ -export const closeSync = mod.closeSync;\n\ -export const copyFile = mod.copyFile;\n\ -export const copyFileSync = mod.copyFileSync;\n\ -export const cp = mod.cp;\n\ -export const cpSync = mod.cpSync;\n\ -export const createReadStream = mod.createReadStream;\n\ -export const createWriteStream = mod.createWriteStream;\n\ -export const exists = mod.exists;\n\ -export const existsSync = mod.existsSync;\n\ -export const lchmod = mod.lchmod;\n\ -export const lchmodSync = mod.lchmodSync;\n\ -export const lchown = mod.lchown;\n\ -export const lchownSync = mod.lchownSync;\n\ -export const link = mod.link;\n\ -export const linkSync = mod.linkSync;\n\ -export const lstat = mod.lstat;\n\ -export const lstatSync = mod.lstatSync;\n\ -export const lutimes = mod.lutimes;\n\ -export const lutimesSync = mod.lutimesSync;\n\ -export const mkdir = mod.mkdir;\n\ -export const mkdirSync = mod.mkdirSync;\n\ -export const mkdtemp = mod.mkdtemp;\n\ -export const mkdtempSync = mod.mkdtempSync;\n\ -export const open = mod.open;\n\ -export const openSync = mod.openSync;\n\ -export const opendir = mod.opendir;\n\ -export const opendirSync = mod.opendirSync;\n\ -export const read = mod.read;\n\ -export const readFile = mod.readFile;\n\ -export const readFileSync = mod.readFileSync;\n\ -export const readSync = mod.readSync;\n\ -export const readdir = mod.readdir;\n\ -export const readdirSync = mod.readdirSync;\n\ -export const readlink = mod.readlink;\n\ -export const readlinkSync = mod.readlinkSync;\n\ -export const realpath = mod.realpath;\n\ -export const realpathSync = mod.realpathSync;\n\ -export const rename = mod.rename;\n\ -export const renameSync = mod.renameSync;\n\ -export const rm = mod.rm;\n\ -export const rmSync = mod.rmSync;\n\ -export const rmdir = mod.rmdir;\n\ -export const rmdirSync = mod.rmdirSync;\n\ -export const stat = mod.stat;\n\ -export const statSync = mod.statSync;\n\ -export const statfs = mod.statfs;\n\ -export const statfsSync = mod.statfsSync;\n\ -export const symlink = mod.symlink;\n\ -export const symlinkSync = mod.symlinkSync;\n\ -export const truncate = mod.truncate;\n\ -export const truncateSync = mod.truncateSync;\n\ -export const unlink = mod.unlink;\n\ -export const unlinkSync = mod.unlinkSync;\n\ -export const unwatchFile = mod.unwatchFile;\n\ -export const utimes = mod.utimes;\n\ -export const utimesSync = mod.utimesSync;\n\ -export const watch = mod.watch;\n\ -export const watchFile = mod.watchFile;\n\ -export const write = mod.write;\n\ -export const writeFile = mod.writeFile;\n\ -export const writeFileSync = mod.writeFileSync;\n\ -export const writeSync = mod.writeSync;\n" - ) -} - -fn render_fs_promises_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "import fsModule from \"secure-exec:builtin/fs\";\n\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -const mod = fsModule.promises;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const constants = fsModule.constants;\n\ -export const FileHandle = mod.FileHandle;\n\ -export const access = mod.access;\n\ -export const appendFile = mod.appendFile;\n\ -export const chmod = mod.chmod;\n\ -export const chown = mod.chown;\n\ -export const copyFile = mod.copyFile;\n\ -export const cp = mod.cp;\n\ -export const lchmod = mod.lchmod;\n\ -export const lchown = mod.lchown;\n\ -export const link = mod.link;\n\ -export const lstat = mod.lstat;\n\ -export const lutimes = mod.lutimes;\n\ -export const mkdir = mod.mkdir;\n\ -export const mkdtemp = mod.mkdtemp;\n\ -export const open = mod.open;\n\ -export const opendir = mod.opendir;\n\ -export const readFile = mod.readFile;\n\ -export const readdir = mod.readdir;\n\ -export const readlink = mod.readlink;\n\ -export const realpath = mod.realpath;\n\ -export const rename = mod.rename;\n\ -export const rm = mod.rm;\n\ -export const rmdir = mod.rmdir;\n\ -export const stat = mod.stat;\n\ -export const statfs = mod.statfs;\n\ -export const symlink = mod.symlink;\n\ -export const truncate = mod.truncate;\n\ -export const unlink = mod.unlink;\n\ -export const utimes = mod.utimes;\n\ -export const watch = mod.watch;\n\ -export const writeFile = mod.writeFile;\n" - ) -} - -fn render_async_hooks_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -\n\ -class AsyncLocalStorage {{\n\ - constructor() {{\n\ - this._store = undefined;\n\ - }}\n\ - disable() {{\n\ - this._store = undefined;\n\ - }}\n\ - enterWith(store) {{\n\ - this._store = store;\n\ - }}\n\ - exit(callback, ...args) {{\n\ - return callback(...args);\n\ - }}\n\ - getStore() {{\n\ - return this._store;\n\ - }}\n\ - run(store, callback, ...args) {{\n\ - const previous = this._store;\n\ - this._store = store;\n\ - try {{\n\ - return callback(...args);\n\ - }} finally {{\n\ - this._store = previous;\n\ - }}\n\ - }}\n\ -}}\n\ -\n\ -class AsyncResource {{\n\ - constructor(type = 'SecureExecAsyncResource') {{\n\ - this.type = type;\n\ - }}\n\ - emitBefore() {{}}\n\ - emitAfter() {{}}\n\ - emitDestroy() {{}}\n\ - asyncId() {{\n\ - return 0;\n\ - }}\n\ - triggerAsyncId() {{\n\ - return 0;\n\ - }}\n\ - runInAsyncScope(callback, thisArg, ...args) {{\n\ - return callback.apply(thisArg, args);\n\ - }}\n\ -}}\n\ -\n\ -function createHook() {{\n\ - return {{\n\ - enable() {{\n\ - return this;\n\ - }},\n\ - disable() {{\n\ - return this;\n\ - }},\n\ - }};\n\ -}}\n\ -\n\ -function executionAsyncId() {{\n\ - return 0;\n\ -}}\n\ -\n\ -function triggerAsyncId() {{\n\ - return 0;\n\ -}}\n\ -\n\ -const mod = {{\n\ - AsyncLocalStorage,\n\ - AsyncResource,\n\ - createHook,\n\ - executionAsyncId,\n\ - triggerAsyncId,\n\ -}};\n\ -\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export {{ AsyncLocalStorage, AsyncResource, createHook, executionAsyncId, triggerAsyncId }};\n" - ) -} - -fn render_child_process_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinChildProcess) {{\n\ - const error = new Error(\"node:child_process is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinChildProcess;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const ChildProcess = mod.ChildProcess;\n\ -export const _forkChild = mod._forkChild;\n\ -export const exec = mod.exec;\n\ -export const execFile = mod.execFile;\n\ -export const execFileSync = mod.execFileSync;\n\ -export const execSync = mod.execSync;\n\ -export const fork = mod.fork;\n\ -export const spawn = mod.spawn;\n\ -export const spawnSync = mod.spawnSync;\n" - ) -} - -fn render_net_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinNet) {{\n\ - const error = new Error(\"node:net is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinNet;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const BlockList = mod.BlockList;\n\ -export const Server = mod.Server;\n\ -export const Socket = mod.Socket;\n\ -export const SocketAddress = mod.SocketAddress;\n\ -export const Stream = mod.Stream;\n\ -export const connect = mod.connect;\n\ -export const createConnection = mod.createConnection;\n\ -export const createServer = mod.createServer;\n\ -export const getDefaultAutoSelectFamily = mod.getDefaultAutoSelectFamily;\n\ -export const getDefaultAutoSelectFamilyAttemptTimeout = mod.getDefaultAutoSelectFamilyAttemptTimeout;\n\ -export const isIP = mod.isIP;\n\ -export const isIPv4 = mod.isIPv4;\n\ -export const isIPv6 = mod.isIPv6;\n\ -export const setDefaultAutoSelectFamily = mod.setDefaultAutoSelectFamily;\n\ -export const setDefaultAutoSelectFamilyAttemptTimeout = mod.setDefaultAutoSelectFamilyAttemptTimeout;\n" - ) -} - -fn render_dgram_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinDgram) {{\n\ - const error = new Error(\"node:dgram is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinDgram;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const Socket = mod.Socket;\n\ -export const createSocket = mod.createSocket;\n" - ) -} - -fn render_diagnostics_channel_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - r#"const initCount = (globalThis[{init_counter_key}] ?? 0) + 1; -globalThis[{init_counter_key}] = initCount; - -class Channel {{ - constructor(name = '') {{ - this.name = String(name); - this._subscribers = new Set(); - }} - - get hasSubscribers() {{ - return this._subscribers.size > 0; - }} - - publish(message) {{ - for (const subscriber of Array.from(this._subscribers)) {{ - subscriber(message, this.name); - }} - }} - - subscribe(subscriber) {{ - if (typeof subscriber === 'function') {{ - this._subscribers.add(subscriber); - }} - }} - - unsubscribe(subscriber) {{ - return this._subscribers.delete(subscriber); - }} - - runStores(context, callback, thisArg, ...args) {{ - if (typeof callback !== 'function') {{ - return callback; - }} - return callback.apply(thisArg, args); - }} -}} - -const channelCache = new Map(); - -function channel(name = '') {{ - const channelName = String(name); - let existing = channelCache.get(channelName); - if (!existing) {{ - existing = new Channel(channelName); - channelCache.set(channelName, existing); - }} - return existing; -}} - -function hasSubscribers(name = '') {{ - return channel(name).hasSubscribers; -}} - -function subscribe(name = '', subscriber) {{ - return channel(name).subscribe(subscriber); -}} - -function unsubscribe(name = '', subscriber) {{ - return channel(name).unsubscribe(subscriber); -}} - -function tracingChannel(name = '') {{ - const channelName = String(name); - const tracing = {{ - start: channel(`tracing:${{channelName}}:start`), - end: channel(`tracing:${{channelName}}:end`), - asyncStart: channel(`tracing:${{channelName}}:asyncStart`), - asyncEnd: channel(`tracing:${{channelName}}:asyncEnd`), - error: channel(`tracing:${{channelName}}:error`), - subscribe() {{}}, - unsubscribe() {{ - return true; - }}, - traceSync(fn, context, thisArg, ...args) {{ - if (typeof fn !== 'function') {{ - return fn; - }} - return fn.apply(thisArg, args); - }}, - tracePromise(fn, context, thisArg, ...args) {{ - if (typeof fn !== 'function') {{ - return Promise.resolve(fn); - }} - return Promise.resolve(fn.apply(thisArg, args)); - }}, - traceCallback(fn, position, context, thisArg, ...args) {{ - if (typeof fn !== 'function') {{ - return fn; - }} - return fn.apply(thisArg, args); - }}, - }}; - Object.defineProperty(tracing, 'hasSubscribers', {{ - get() {{ - return ( - tracing.start.hasSubscribers || - tracing.end.hasSubscribers || - tracing.asyncStart.hasSubscribers || - tracing.asyncEnd.hasSubscribers || - tracing.error.hasSubscribers - ); - }}, - enumerable: false, - configurable: true, - }}); - return tracing; -}} - -const mod = {{ Channel, channel, hasSubscribers, subscribe, tracingChannel, unsubscribe }}; - -export const __agentOSInitCount = initCount; -export default mod; -export {{ Channel, channel, hasSubscribers, subscribe, tracingChannel, unsubscribe }}; -"# - ) -} - -fn render_dns_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinDns) {{\n\ - const error = new Error(\"node:dns is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinDns;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const ADDRCONFIG = mod.ADDRCONFIG;\n\ -export const ALL = mod.ALL;\n\ -export const Resolver = mod.Resolver;\n\ -export const V4MAPPED = mod.V4MAPPED;\n\ -export const constants = mod.constants;\n\ -export const getDefaultResultOrder = mod.getDefaultResultOrder;\n\ -export const getServers = mod.getServers;\n\ -export const lookup = mod.lookup;\n\ -export const lookupService = mod.lookupService;\n\ -export const promises = mod.promises;\n\ -export const resolve = mod.resolve;\n\ -export const resolve4 = mod.resolve4;\n\ -export const resolve6 = mod.resolve6;\n\ -export const reverse = mod.reverse;\n\ -export const setDefaultResultOrder = mod.setDefaultResultOrder;\n\ -export const setServers = mod.setServers;\n" - ) -} - -fn render_dns_promises_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinDns) {{\n\ - const error = new Error(\"node:dns/promises is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinDns.promises;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const Resolver = mod.Resolver;\n\ -export const lookup = mod.lookup;\n\ -export const resolve = mod.resolve;\n\ -export const resolve4 = mod.resolve4;\n\ -export const resolve6 = mod.resolve6;\n\ -export const resolveAny = mod.resolveAny;\n\ -export const resolveMx = mod.resolveMx;\n\ -export const resolveTxt = mod.resolveTxt;\n\ -export const resolveSrv = mod.resolveSrv;\n\ -export const resolveCname = mod.resolveCname;\n\ -export const resolvePtr = mod.resolvePtr;\n\ -export const resolveNs = mod.resolveNs;\n\ -export const resolveSoa = mod.resolveSoa;\n\ -export const resolveNaptr = mod.resolveNaptr;\n\ -export const resolveCaa = mod.resolveCaa;\n" - ) -} - -fn render_http_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinHttp) {{\n\ - const error = new Error(\"node:http is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinHttp;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const Agent = mod.Agent;\n\ -export const ClientRequest = mod.ClientRequest;\n\ -export const IncomingMessage = mod.IncomingMessage;\n\ -export const METHODS = mod.METHODS;\n\ -export const OutgoingMessage = mod.OutgoingMessage;\n\ -export const STATUS_CODES = mod.STATUS_CODES;\n\ -export const Server = mod.Server;\n\ -export const ServerResponse = mod.ServerResponse;\n\ -export const createServer = mod.createServer;\n\ -export const get = mod.get;\n\ -export const globalAgent = mod.globalAgent;\n\ -export const maxHeaderSize = mod.maxHeaderSize;\n\ -export const request = mod.request;\n\ -export const setMaxIdleHTTPParsers = mod.setMaxIdleHTTPParsers;\n\ -export const validateHeaderName = mod.validateHeaderName;\n\ -export const validateHeaderValue = mod.validateHeaderValue;\n" - ) -} - -fn render_http2_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinHttp2) {{\n\ - const error = new Error(\"node:http2 is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinHttp2;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const Http2ServerRequest = mod.Http2ServerRequest;\n\ -export const Http2ServerResponse = mod.Http2ServerResponse;\n\ -export const Http2Session = mod.Http2Session;\n\ -export const Http2Stream = mod.Http2Stream;\n\ -export const constants = mod.constants;\n\ -export const connect = mod.connect;\n\ -export const createServer = mod.createServer;\n\ -export const createSecureServer = mod.createSecureServer;\n\ -export const getDefaultSettings = mod.getDefaultSettings;\n\ -export const getPackedSettings = mod.getPackedSettings;\n\ -export const getUnpackedSettings = mod.getUnpackedSettings;\n\ -export const sensitiveHeaders = mod.sensitiveHeaders;\n" - ) -} - -fn render_https_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinHttps) {{\n\ - const error = new Error(\"node:https is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinHttps;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const Agent = mod.Agent;\n\ -export const Server = mod.Server;\n\ -export const createServer = mod.createServer;\n\ -export const get = mod.get;\n\ -export const globalAgent = mod.globalAgent;\n\ -export const request = mod.request;\n" - ) -} - -fn render_tls_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinTls) {{\n\ - const error = new Error(\"node:tls is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinTls;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const CLIENT_RENEG_LIMIT = mod.CLIENT_RENEG_LIMIT;\n\ -export const CLIENT_RENEG_WINDOW = mod.CLIENT_RENEG_WINDOW;\n\ -export const DEFAULT_CIPHERS = mod.DEFAULT_CIPHERS;\n\ -export const DEFAULT_ECDH_CURVE = mod.DEFAULT_ECDH_CURVE;\n\ -export const DEFAULT_MAX_VERSION = mod.DEFAULT_MAX_VERSION;\n\ -export const DEFAULT_MIN_VERSION = mod.DEFAULT_MIN_VERSION;\n\ -export const SecureContext = mod.SecureContext;\n\ -export const Server = mod.Server;\n\ -export const TLSSocket = mod.TLSSocket;\n\ -export const checkServerIdentity = mod.checkServerIdentity;\n\ -export const connect = mod.connect;\n\ -export const createConnection = mod.createConnection;\n\ -export const createSecureContext = mod.createSecureContext;\n\ -export const createSecurePair = mod.createSecurePair;\n\ -export const createServer = mod.createServer;\n\ -export const getCiphers = mod.getCiphers;\n\ -export const rootCertificates = mod.rootCertificates;\n" - ) -} - -fn render_os_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const ACCESS_DENIED_CODE = \"ERR_ACCESS_DENIED\";\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -if (!globalThis.__agentOSBuiltinOs) {{\n\ - const error = new Error(\"node:os is not available in the secure-exec guest runtime\");\n\ - error.code = ACCESS_DENIED_CODE;\n\ - throw error;\n\ -}}\n\n\ -const mod = globalThis.__agentOSBuiltinOs;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const EOL = mod.EOL;\n\ -export const arch = mod.arch;\n\ -export const availableParallelism = mod.availableParallelism;\n\ -export const constants = mod.constants;\n\ -export const cpus = mod.cpus;\n\ -export const devNull = mod.devNull;\n\ -export const endianness = mod.endianness;\n\ -export const freemem = mod.freemem;\n\ -export const getPriority = mod.getPriority;\n\ -export const homedir = mod.homedir;\n\ -export const hostname = mod.hostname;\n\ -export const loadavg = mod.loadavg;\n\ -export const machine = mod.machine;\n\ -export const networkInterfaces = mod.networkInterfaces;\n\ -export const platform = mod.platform;\n\ -export const release = mod.release;\n\ -export const setPriority = mod.setPriority;\n\ -export const tmpdir = mod.tmpdir;\n\ -export const totalmem = mod.totalmem;\n\ -export const type = mod.type;\n\ -export const uptime = mod.uptime;\n\ -export const userInfo = mod.userInfo;\n\ -export const version = mod.version;\n" - ) -} - -fn render_v8_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -const mod = process.getBuiltinModule?.(\"node:v8\");\n\ -if (!mod) {{\n\ - throw new Error(\"secure-exec guest v8 compatibility module was not initialized\");\n\ -}}\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const GCProfiler = mod.GCProfiler;\n\ -export const Deserializer = mod.Deserializer;\n\ -export const Serializer = mod.Serializer;\n\ -export const cachedDataVersionTag = mod.cachedDataVersionTag;\n\ -export const deserialize = mod.deserialize;\n\ -export const getCppHeapStatistics = mod.getCppHeapStatistics;\n\ -export const getHeapCodeStatistics = mod.getHeapCodeStatistics;\n\ -export const getHeapSnapshot = mod.getHeapSnapshot;\n\ -export const getHeapSpaceStatistics = mod.getHeapSpaceStatistics;\n\ -export const getHeapStatistics = mod.getHeapStatistics;\n\ -export const isStringOneByteRepresentation = mod.isStringOneByteRepresentation;\n\ -export const promiseHooks = mod.promiseHooks;\n\ -export const queryObjects = mod.queryObjects;\n\ -export const serialize = mod.serialize;\n\ -export const setFlagsFromString = mod.setFlagsFromString;\n\ -export const setHeapSnapshotNearHeapLimit = mod.setHeapSnapshotNearHeapLimit;\n\ -export const startCpuProfile = mod.startCpuProfile;\n\ -export const startupSnapshot = mod.startupSnapshot;\n\ -export const stopCoverage = mod.stopCoverage;\n\ -export const takeCoverage = mod.takeCoverage;\n\ -export const writeHeapSnapshot = mod.writeHeapSnapshot;\n" - ) -} - -fn render_vm_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -const mod = process.getBuiltinModule?.(\"node:vm\");\n\ -if (!mod) {{\n\ - throw new Error(\"secure-exec guest vm compatibility module was not initialized\");\n\ -}}\n\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const Script = mod.Script;\n\ -export const createContext = mod.createContext;\n\ -export const isContext = mod.isContext;\n\ -export const runInNewContext = mod.runInNewContext;\n\ -export const runInThisContext = mod.runInThisContext;\n" - ) -} - -fn render_worker_threads_builtin_asset_source(init_counter_key: &str) -> String { - let init_counter_key = format!("{init_counter_key:?}"); - - format!( - "const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\ -\n\ -function createNotImplementedError(feature) {{\n\ - const error = new Error(`node:worker_threads ${{feature}} is not available in the secure-exec guest runtime`);\n\ - error.code = \"ERR_NOT_IMPLEMENTED\";\n\ - return error;\n\ -}}\n\ -\n\ -class MessagePort {{\n\ - postMessage() {{}}\n\ - start() {{}}\n\ - close() {{}}\n\ - unref() {{\n\ - return this;\n\ - }}\n\ - ref() {{\n\ - return this;\n\ - }}\n\ -}}\n\ -\n\ -class MessageChannel {{\n\ - constructor() {{\n\ - this.port1 = new MessagePort();\n\ - this.port2 = new MessagePort();\n\ - }}\n\ -}}\n\ -\n\ -class Worker {{\n\ - constructor() {{\n\ - throw createNotImplementedError(\"Worker\");\n\ - }}\n\ -}}\n\ -\n\ -function getEnvironmentData() {{\n\ - return undefined;\n\ -}}\n\ -\n\ -function markAsUncloneable() {{}}\n\ -\n\ -function markAsUntransferable() {{}}\n\ -\n\ -function moveMessagePortToContext() {{\n\ - throw createNotImplementedError(\"moveMessagePortToContext\");\n\ -}}\n\ -\n\ -function postMessageToThread() {{\n\ - throw createNotImplementedError(\"postMessageToThread\");\n\ -}}\n\ -\n\ -function receiveMessageOnPort() {{\n\ - return undefined;\n\ -}}\n\ -\n\ -function setEnvironmentData() {{}}\n\ -\n\ -const mod = {{\n\ - BroadcastChannel: globalThis.BroadcastChannel,\n\ - MessageChannel,\n\ - MessagePort,\n\ - SHARE_ENV: Symbol.for(\"secure-exec.worker_threads.SHARE_ENV\"),\n\ - Worker,\n\ - getEnvironmentData,\n\ - isMainThread: true,\n\ - markAsUncloneable,\n\ - markAsUntransferable,\n\ - moveMessagePortToContext,\n\ - parentPort: null,\n\ - postMessageToThread,\n\ - receiveMessageOnPort,\n\ - resourceLimits: {{}},\n\ - setEnvironmentData,\n\ - threadId: 0,\n\ - workerData: null,\n\ -}};\n\ -\n\ -export const __agentOSInitCount = initCount;\n\ -export default mod;\n\ -export const BroadcastChannel = mod.BroadcastChannel;\n\ -export const MessageChannel = mod.MessageChannel;\n\ -export const MessagePort = mod.MessagePort;\n\ -export const SHARE_ENV = mod.SHARE_ENV;\n\ -export const Worker = mod.Worker;\n\ -export const getEnvironmentData = mod.getEnvironmentData;\n\ -export const isMainThread = mod.isMainThread;\n\ -export const markAsUncloneable = mod.markAsUncloneable;\n\ -export const markAsUntransferable = mod.markAsUntransferable;\n\ -export const moveMessagePortToContext = mod.moveMessagePortToContext;\n\ -export const parentPort = mod.parentPort;\n\ -export const postMessageToThread = mod.postMessageToThread;\n\ -export const receiveMessageOnPort = mod.receiveMessageOnPort;\n\ -export const resourceLimits = mod.resourceLimits;\n\ -export const setEnvironmentData = mod.setEnvironmentData;\n\ -export const threadId = mod.threadId;\n\ -export const workerData = mod.workerData;\n" - ) -} - -fn render_denied_asset_source(module_specifier: &str) -> String { - let message = format!("{module_specifier} is not available in the secure-exec guest runtime"); - format!( - "const error = new Error({message:?});\nerror.code = \"ERR_ACCESS_DENIED\";\nthrow error;\n" - ) -} - -fn render_path_polyfill_source() -> String { - let init_counter_key = format!("{PATH_POLYFILL_INIT_COUNTER_KEY:?}"); - - format!( - "import path from \"node:path\";\n\n\ -const initCount = (globalThis[{init_counter_key}] ?? 0) + 1;\n\ -globalThis[{init_counter_key}] = initCount;\n\n\ -export const __agentOSInitCount = initCount;\n\ -export const basename = (...args) => path.basename(...args);\n\ -export const dirname = (...args) => path.dirname(...args);\n\ -export const join = (...args) => path.join(...args);\n\ -export const resolve = (...args) => path.resolve(...args);\n\ -export const sep = path.sep;\n\ -export default path;\n" - ) -} - -fn write_bytes_if_changed(path: &Path, contents: &[u8]) -> Result<(), io::Error> { - match fs::read(path) { - Ok(existing) if existing == contents => return Ok(()), - Ok(_) | Err(_) => {} - } - - fs::write(path, contents) -} - -fn write_file_if_changed(path: &Path, contents: &str) -> Result<(), io::Error> { - write_bytes_if_changed(path, contents.as_bytes()) -} - -#[cfg(test)] -mod tests { - use super::{ - NodeImportCache, NODE_IMPORT_CACHE_TEST_MATERIALIZE_DELAY_MS, NODE_WASM_RUNNER_SOURCE, - }; - use crate::host_node::node_binary; - use serde_json::Value; - use std::collections::BTreeSet; - use std::fs; - use std::io::Write; - use std::path::Path; - use std::process::{Command, Output, Stdio}; - use std::sync::atomic::Ordering; - use std::time::Duration; - use tempfile::tempdir; - - fn assert_node_available() { - let output = Command::new(node_binary()) - .arg("--version") - .output() - .expect("spawn node --version"); - assert!(output.status.success(), "node --version failed"); - } - - fn write_fixture(path: &Path, contents: &str) { - fs::write(path, contents).expect("write fixture"); - } - - fn run_python_runner( - import_cache: &NodeImportCache, - pyodide_index_url: &Path, - code: &str, - ) -> Output { - run_python_runner_with_env(import_cache, pyodide_index_url, code, &[]) - } - - fn run_python_runner_with_env( - import_cache: &NodeImportCache, - pyodide_index_url: &Path, - code: &str, - env: &[(&str, &str)], - ) -> Output { - let mut command = Command::new(node_binary()); - command - .arg("--import") - .arg(import_cache.timing_bootstrap_path()) - .arg(import_cache.python_runner_path()) - .env("AGENTOS_PYODIDE_INDEX_URL", pyodide_index_url) - .env( - "AGENTOS_PYODIDE_PACKAGE_CACHE_DIR", - pyodide_index_url.join("pyodide-package-cache"), - ) - .env("AGENTOS_PYTHON_CODE", code); - - for (key, value) in env { - command.env(key, value); - } - - command.output().expect("run python runner") - } - - fn run_python_runner_prewarm( - import_cache: &NodeImportCache, - pyodide_index_url: &Path, - env: &[(&str, &str)], - ) -> Output { - let mut command = Command::new(node_binary()); - command - .arg("--import") - .arg(import_cache.timing_bootstrap_path()) - .arg(import_cache.python_runner_path()) - .env("AGENTOS_PYODIDE_INDEX_URL", pyodide_index_url) - .env( - "AGENTOS_PYODIDE_PACKAGE_CACHE_DIR", - pyodide_index_url.join("pyodide-package-cache"), - ) - .env("AGENTOS_PYTHON_PREWARM_ONLY", "1"); - - for (key, value) in env { - command.env(key, value); - } - - command.output().expect("run python runner prewarm") - } - - fn run_python_runner_with_env_and_stdin( - import_cache: &NodeImportCache, - pyodide_index_url: &Path, - code: &str, - env: &[(&str, &str)], - stdin_chunks: &[&[u8]], - ) -> Output { - let mut command = Command::new(node_binary()); - command - .arg("--import") - .arg(import_cache.timing_bootstrap_path()) - .arg(import_cache.python_runner_path()) - .env("AGENTOS_PYODIDE_INDEX_URL", pyodide_index_url) - .env( - "AGENTOS_PYODIDE_PACKAGE_CACHE_DIR", - pyodide_index_url.join("pyodide-package-cache"), - ) - .env("AGENTOS_PYTHON_CODE", code) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - - for (key, value) in env { - command.env(key, value); - } - - let mut child = command.spawn().expect("spawn python runner"); - { - let mut stdin = child.stdin.take().expect("python runner stdin"); - for chunk in stdin_chunks { - stdin - .write_all(chunk) - .expect("write python runner stdin chunk"); - } - } - - child.wait_with_output().expect("wait for python runner") - } - - #[test] - fn materialized_python_runner_hardens_builtin_access_before_load_pyodide() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let pyodide_dir = tempdir().expect("create pyodide fixture dir"); - write_fixture( - &pyodide_dir.path().join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - const capturedFetch = globalThis.fetch; - return { - setStdin(_stdin) {}, - async runPythonAsync() { - try { - await capturedFetch('http://127.0.0.1:1/'); - options.stdout('unexpected'); - } catch (error) { - options.stdout(JSON.stringify({ - code: error.code ?? null, - message: error.message, - })); - } - }, - }; -} -"#, - ); - write_fixture( - &pyodide_dir.path().join("pyodide-lock.json"), - "{\"packages\":[]}\n", - ); - - let output = run_python_runner(&import_cache, pyodide_dir.path(), "print('hello')"); - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse hardening JSON"); - - assert_eq!(output.status.code(), Some(0), "stderr: {stderr}"); - assert_eq!( - parsed["code"], - Value::String(String::from("ERR_ACCESS_DENIED")) - ); - assert!( - parsed["message"] - .as_str() - .expect("fetch denial message") - .contains("network access"), - "unexpected stdout: {stdout}" - ); - } - - #[test] - fn materialized_python_runner_executes_python_code_via_pyodide_callbacks() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let pyodide_dir = tempdir().expect("create pyodide fixture dir"); - write_fixture( - &pyodide_dir.path().join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - return { - setStdin(_stdin) {}, - async runPythonAsync(code) { - options.stdout(`stdout:${code}`); - options.stderr(`stderr:${options.indexURL}:${options.lockFileContents}`); - }, - }; -} -"#, - ); - write_fixture( - &pyodide_dir.path().join("pyodide-lock.json"), - "{\"packages\":[]}\n", - ); - - let output = run_python_runner(&import_cache, pyodide_dir.path(), "print('hello')"); - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - let expected_index_path = format!( - "stderr:{}{}", - pyodide_dir.path().display(), - std::path::MAIN_SEPARATOR - ); - - assert_eq!(output.status.code(), Some(0)); - assert_eq!(stdout, "stdout:print('hello')\n"); - assert!( - stderr.starts_with(&expected_index_path), - "unexpected stderr: {stderr}" - ); - assert!( - stderr.contains("{\"packages\":[]}"), - "lock file contents should be passed to loadPyodide: {stderr}" - ); - } - - #[test] - fn materialized_python_runner_prefers_python_file_over_inline_code() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let pyodide_dir = tempdir().expect("create pyodide fixture dir"); - write_fixture( - &pyodide_dir.path().join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - return { - FS: { - readFile(path, config = {}) { - options.stderr(`file:${path}:${config.encoding ?? 'binary'}`); - return "print('from file')"; - }, - }, - setStdin(_stdin) {}, - async runPythonAsync(code) { - options.stdout(`stdout:${code}`); - }, - }; -} -"#, - ); - write_fixture( - &pyodide_dir.path().join("pyodide-lock.json"), - "{\"packages\":[]}\n", - ); - - let output = run_python_runner_with_env( - &import_cache, - pyodide_dir.path(), - "print('ignored')", - &[("AGENTOS_PYTHON_FILE", "/workspace/script.py")], - ); - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - - assert_eq!(output.status.code(), Some(0), "stderr: {stderr}"); - assert_eq!(stdout, "stdout:print('from file')\n"); - assert!( - stderr.contains("file:/workspace/script.py:utf8"), - "unexpected stderr: {stderr}" - ); - } - - #[test] - fn materialized_python_runner_prewarm_validates_assets_without_running_guest_code() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let pyodide_dir = tempdir().expect("create pyodide fixture dir"); - write_fixture( - &pyodide_dir.path().join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - options.stderr(`prewarm:${options.indexURL}`); - return { - setStdin() { - throw new Error('setStdin should not run during prewarm'); - }, - async runPythonAsync() { - throw new Error('runPythonAsync should not run during prewarm'); - }, - }; -} -"#, - ); - write_fixture( - &pyodide_dir.path().join("pyodide-lock.json"), - "{\"packages\":[]}\n", - ); - fs::write(pyodide_dir.path().join("python_stdlib.zip"), b"stub-stdlib") - .expect("write stdlib fixture"); - fs::write(pyodide_dir.path().join("pyodide.asm.wasm"), b"stub-wasm") - .expect("write wasm fixture"); - - let output = run_python_runner_prewarm( - &import_cache, - pyodide_dir.path(), - &[("AGENTOS_PYTHON_CODE", "print('ignored')")], - ); - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - - assert_eq!(output.status.code(), Some(0), "stderr: {stderr}"); - assert!(stdout.is_empty(), "unexpected stdout: {stdout}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - assert!( - !stderr.contains("setStdin should not run during prewarm"), - "unexpected stderr: {stderr}" - ); - assert!( - !stderr.contains("runPythonAsync should not run during prewarm"), - "unexpected stderr: {stderr}" - ); - } - - #[test] - fn materialized_python_runner_reports_syntax_errors_to_stderr_and_exits_nonzero() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let pyodide_dir = tempdir().expect("create pyodide fixture dir"); - write_fixture( - &pyodide_dir.path().join("pyodide.mjs"), - r#" -export async function loadPyodide() { - return { - setStdin(_stdin) {}, - async runPythonAsync(code) { - throw new Error(`SyntaxError: invalid syntax near ${code}`); - }, - }; -} -"#, - ); - write_fixture( - &pyodide_dir.path().join("pyodide-lock.json"), - "{\"packages\":[]}\n", - ); - - let output = run_python_runner(&import_cache, pyodide_dir.path(), "print("); - let stderr = String::from_utf8_lossy(&output.stderr); - - assert_eq!(output.status.code(), Some(1)); - assert!( - stderr.contains("SyntaxError: invalid syntax near print("), - "unexpected stderr: {stderr}" - ); - } - - #[test] - fn materialized_python_runner_blocks_pyodide_js_escape_modules() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let output = run_python_runner( - &import_cache, - import_cache.pyodide_dist_path(), - r#" -import json -import js -import pyodide_js - -def capture(action): - try: - action() - return {"ok": True} - except Exception as error: - return { - "ok": False, - "type": type(error).__name__, - "message": str(error), - } - -print(json.dumps({ - "js_process_env": capture(lambda: js.process.env), - "js_require": capture(lambda: js.require), - "js_process_exit": capture(lambda: js.process.exit), - "js_process_kill": capture(lambda: js.process.kill), - "js_child_process_builtin": capture( - lambda: js.process.getBuiltinModule("node:child_process") - ), - "js_vm_builtin": capture( - lambda: js.process.getBuiltinModule("node:vm") - ), - "pyodide_js_eval_code": capture(lambda: pyodide_js.eval_code), -})) -"#, - ); - - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - let parsed: Value = - serde_json::from_str(stdout.trim()).expect("parse Python hardening JSON"); - - assert_eq!(output.status.code(), Some(0), "stderr: {stderr}"); - - for key in [ - "js_process_env", - "js_require", - "js_process_exit", - "js_process_kill", - "js_child_process_builtin", - "js_vm_builtin", - ] { - assert_eq!(parsed[key]["ok"], Value::Bool(false), "stdout: {stdout}"); - assert_eq!( - parsed[key]["type"], - Value::String(String::from("RuntimeError")) - ); - assert!( - parsed[key]["message"] - .as_str() - .expect("js hardening message") - .contains("js is not available"), - "stdout: {stdout}" - ); - } - - assert_eq!( - parsed["pyodide_js_eval_code"]["ok"], - Value::Bool(false), - "stdout: {stdout}" - ); - assert_eq!( - parsed["pyodide_js_eval_code"]["type"], - Value::String(String::from("RuntimeError")) - ); - assert!( - parsed["pyodide_js_eval_code"]["message"] - .as_str() - .expect("pyodide_js hardening message") - .contains("pyodide_js is not available"), - "stdout: {stdout}" - ); - } - - #[test] - fn materialized_python_runner_exposes_frozen_time_to_python() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let frozen_time_ms = 1_704_067_200_123_u64; - let output = run_python_runner_with_env( - &import_cache, - import_cache.pyodide_dist_path(), - r#" -import datetime -import json -import time - -first_ns = time.time_ns() -second_ns = time.time_ns() -utc_now = datetime.datetime.now(datetime.timezone.utc) - -print(json.dumps({ - "first_ns": first_ns, - "second_ns": second_ns, - "iso": utc_now.isoformat(timespec="milliseconds"), -})) -"#, - &[("AGENTOS_FROZEN_TIME_MS", "1704067200123")], - ); - - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse frozen-time JSON"); - - assert_eq!(output.status.code(), Some(0), "stderr: {stderr}"); - assert_eq!(parsed["first_ns"], parsed["second_ns"], "stdout: {stdout}"); - let first_ns = parsed["first_ns"] - .as_u64() - .expect("frozen time.time_ns() value"); - assert_eq!(first_ns / 1_000_000, frozen_time_ms, "stdout: {stdout}"); - assert_eq!( - parsed["iso"], - Value::String(String::from("2024-01-01T00:00:00.123+00:00")), - "stdout: {stdout}" - ); - } - - #[test] - fn materialized_python_runner_preloads_bundled_packages_from_local_disk() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let pyodide_dir = tempdir().expect("create pyodide fixture dir"); - write_fixture( - &pyodide_dir.path().join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - return { - setStdin(_stdin) {}, - async loadPackage(packages) { - options.stdout(`packages:${packages.join(',')}`); - options.stderr(`base:${options.packageBaseUrl}`); - }, - async runPythonAsync(code) { - options.stdout(`code:${code}`); - }, - }; -} -"#, - ); - write_fixture( - &pyodide_dir.path().join("pyodide-lock.json"), - "{\"packages\":[]}\n", - ); - - let output = run_python_runner_with_env( - &import_cache, - pyodide_dir.path(), - "print('hello')", - &[("AGENTOS_PYTHON_PRELOAD_PACKAGES", "[\"numpy\",\"pandas\"]")], - ); - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - let expected_package_base = format!( - "base:{}{}", - pyodide_dir.path().display(), - std::path::MAIN_SEPARATOR - ); - - assert_eq!(output.status.code(), Some(0)); - assert_eq!( - stdout, - "packages:micropip\npackages:numpy,pandas\ncode:print('hello')\n" - ); - assert!( - stderr.contains(&expected_package_base), - "expected local package base path in stderr, got: {stderr}" - ); - } - - #[test] - fn materialized_python_runner_rejects_unknown_preload_packages() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let pyodide_dir = tempdir().expect("create pyodide fixture dir"); - write_fixture( - &pyodide_dir.path().join("pyodide.mjs"), - r#" -export async function loadPyodide() { - return { - setStdin(_stdin) {}, - async loadPackage() { - throw new Error('loadPackage should not be called'); - }, - async runPythonAsync(_code) {}, - }; -} -"#, - ); - write_fixture( - &pyodide_dir.path().join("pyodide-lock.json"), - "{\"packages\":[]}\n", - ); - - let output = run_python_runner_with_env( - &import_cache, - pyodide_dir.path(), - "print('hello')", - &[("AGENTOS_PYTHON_PRELOAD_PACKAGES", "[\"requests\"]")], - ); - let stderr = String::from_utf8_lossy(&output.stderr); - - assert_eq!(output.status.code(), Some(1)); - assert!( - stderr.contains("Unsupported bundled Python package \"requests\""), - "unexpected stderr: {stderr}" - ); - assert!( - stderr.contains("Available packages: numpy, pandas"), - "unexpected stderr: {stderr}" - ); - assert!( - !stderr.contains("loadPackage should not be called"), - "runner should validate packages before calling loadPackage: {stderr}" - ); - } - - #[test] - fn materialized_python_runner_streams_multiple_stdin_reads_through_pyodide() { - assert_node_available(); - - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let pyodide_dir = tempdir().expect("create pyodide fixture dir"); - write_fixture( - &pyodide_dir.path().join("pyodide.mjs"), - r#" -const decoder = new TextDecoder(); - -export async function loadPyodide(options) { - let stdin = null; - - function createInputReader() { - let buffered = ''; - - return () => { - while (true) { - const newlineIndex = buffered.indexOf('\n'); - if (newlineIndex >= 0) { - const line = buffered.slice(0, newlineIndex); - buffered = buffered.slice(newlineIndex + 1); - return line; - } - - const chunk = new Uint8Array(64); - const bytesRead = stdin.read(chunk); - if (bytesRead === 0) { - const tail = buffered; - buffered = ''; - return tail; - } - - buffered += decoder.decode(chunk.subarray(0, bytesRead)); - } - }; - } - - return { - setStdin(config) { - stdin = config; - }, - async runPythonAsync(code) { - const input = createInputReader(); - options.stdout(`first:${input()}`); - options.stdout(`second:${input()}`); - options.stdout(`tail:${JSON.stringify(input())}`); - options.stdout(`code:${code}`); - }, - }; -} -"#, - ); - write_fixture( - &pyodide_dir.path().join("pyodide-lock.json"), - "{\"packages\":[]}\n", - ); - - let output = run_python_runner_with_env_and_stdin( - &import_cache, - pyodide_dir.path(), - "print('interactive')", - &[], - &[b"first line\n", b"second line\n"], - ); - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - - assert_eq!(output.status.code(), Some(0), "stderr: {stderr}"); - assert!( - stdout.contains("first:first line\n"), - "unexpected stdout: {stdout}" - ); - assert!( - stdout.contains("second:second line\n"), - "unexpected stdout: {stdout}" - ); - assert!(stdout.contains("tail:\"\""), "unexpected stdout: {stdout}"); - assert!( - stdout.contains("code:print('interactive')"), - "unexpected stdout: {stdout}" - ); - } - - #[test] - fn ensure_materialized_writes_bundled_pyodide_distribution_assets() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - for file_name in [ - "pyodide.mjs", - "pyodide.asm.js", - "pyodide.asm.wasm", - "pyodide-lock.json", - "python_stdlib.zip", - "numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl", - "pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl", - "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", - "pytz-2025.2-py2.py3-none-any.whl", - "six-1.17.0-py2.py3-none-any.whl", - ] { - assert!( - import_cache.pyodide_dist_path().join(file_name).is_file(), - "expected bundled Pyodide asset {file_name} to be materialized" - ); - } - } - - #[test] - fn ensure_materialized_honors_configured_timeout() { - let temp_root = tempdir().expect("create node import cache temp root"); - let import_cache = NodeImportCache::new_in(temp_root.path().to_path_buf()); - - NODE_IMPORT_CACHE_TEST_MATERIALIZE_DELAY_MS.store(50, Ordering::Relaxed); - let error = import_cache - .ensure_materialized_with_timeout(Duration::from_millis(5)) - .expect_err("materialization should time out"); - NODE_IMPORT_CACHE_TEST_MATERIALIZE_DELAY_MS.store(0, Ordering::Relaxed); - - assert_eq!(error.kind(), std::io::ErrorKind::TimedOut); - assert!( - error - .to_string() - .contains("timed out materializing node import cache"), - "unexpected error: {error}" - ); - - std::thread::sleep(Duration::from_millis(75)); - } - - #[test] - fn ensure_materialized_skips_repeated_materialization_after_success() { - let temp_root = tempdir().expect("create node import cache temp root"); - let import_cache = NodeImportCache::new_in(temp_root.path().to_path_buf()); - - import_cache - .ensure_materialized() - .expect("initial materialization should succeed"); - - NODE_IMPORT_CACHE_TEST_MATERIALIZE_DELAY_MS.store(50, Ordering::Relaxed); - let result = import_cache.ensure_materialized_with_timeout(Duration::from_millis(5)); - NODE_IMPORT_CACHE_TEST_MATERIALIZE_DELAY_MS.store(0, Ordering::Relaxed); - result.expect("second materialization should use memoized success"); - } - - #[test] - fn new_in_cleans_stale_temp_roots_without_touching_unrelated_entries() { - let temp_root = tempdir().expect("create node import cache temp root"); - let stale_cache_dir = temp_root - .path() - .join("agentos-node-import-cache-stale-test"); - let unrelated_dir = temp_root.path().join("keep-me"); - fs::create_dir_all(&stale_cache_dir).expect("create stale cache dir"); - fs::create_dir_all(&unrelated_dir).expect("create unrelated dir"); - fs::write(stale_cache_dir.join("state.json"), b"stale").expect("seed stale cache"); - - let import_cache = NodeImportCache::new_in(temp_root.path().to_path_buf()); - - assert!( - !stale_cache_dir.exists(), - "expected stale cache dir to be removed" - ); - assert!(unrelated_dir.exists(), "expected unrelated dir to remain"); - assert!( - import_cache.root_dir.starts_with(temp_root.path()), - "expected import cache root to stay inside the configured temp root" - ); - } - - #[test] - fn materialized_loader_prunes_persisted_resolution_cache_state() { - assert_node_available(); - - let temp_root = tempdir().expect("create node import cache temp root"); - let workspace = tempdir().expect("create loader test workspace"); - let import_cache = NodeImportCache::new_in(temp_root.path().to_path_buf()); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let driver_path = workspace.path().join("drive-loader-cache.mjs"); - write_fixture( - &driver_path, - r#" -import path from 'node:path'; -import { pathToFileURL } from 'node:url'; - -const [loaderPath, workspaceRoot] = process.argv.slice(2); -const loader = await import(`${pathToFileURL(loaderPath).href}?case=${process.pid}-${Date.now()}`); -const parentURL = pathToFileURL(path.join(workspaceRoot, 'entry.mjs')).href; - -for (let index = 0; index < 600; index += 1) { - const specifier = `pkg-${index}`; - const resolvedPath = path.join(workspaceRoot, 'node_modules', specifier, 'index.mjs'); - await loader.resolve(specifier, { parentURL }, async () => ({ - url: pathToFileURL(resolvedPath).href, - format: 'module', - })); -} -"#, - ); - - let output = Command::new(node_binary()) - .arg(&driver_path) - .arg(&import_cache.loader_path) - .arg(workspace.path()) - .env("AGENTOS_NODE_IMPORT_CACHE_PATH", import_cache.cache_path()) - .env( - "AGENTOS_NODE_IMPORT_CACHE_ASSET_ROOT", - import_cache.asset_root(), - ) - .output() - .expect("run loader cache driver"); - let stderr = String::from_utf8_lossy(&output.stderr); - assert_eq!(output.status.code(), Some(0), "stderr: {stderr}"); - - let state: Value = serde_json::from_str( - &fs::read_to_string(import_cache.cache_path()).expect("read cache state"), - ) - .expect("parse cache state"); - let resolutions = state["resolutions"] - .as_object() - .expect("resolution cache object"); - - assert_eq!(resolutions.len(), 512); - assert!( - resolutions.keys().any(|key| key.contains("pkg-599")), - "newest resolution should be retained" - ); - assert!( - !resolutions.keys().any(|key| key.contains("pkg-0\"")), - "oldest resolution should be pruned" - ); - } - - #[test] - fn materialized_loader_ignores_oversized_state_during_flush_merge() { - assert_node_available(); - - let temp_root = tempdir().expect("create node import cache temp root"); - let workspace = tempdir().expect("create loader test workspace"); - let import_cache = NodeImportCache::new_in(temp_root.path().to_path_buf()); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - fs::create_dir_all(import_cache.cache_path().parent().expect("cache parent")) - .expect("create cache parent"); - fs::write(import_cache.cache_path(), vec![b' '; 5 * 1024 * 1024]) - .expect("seed oversized cache state"); - - let driver_path = workspace.path().join("drive-oversized-state.mjs"); - write_fixture( - &driver_path, - r#" -import path from 'node:path'; -import { pathToFileURL } from 'node:url'; - -const [loaderPath, workspaceRoot] = process.argv.slice(2); -const loader = await import(`${pathToFileURL(loaderPath).href}?case=oversized-${process.pid}-${Date.now()}`); -const parentURL = pathToFileURL(path.join(workspaceRoot, 'entry.mjs')).href; -await loader.resolve('pkg-fresh', { parentURL }, async () => ({ - url: pathToFileURL(path.join(workspaceRoot, 'node_modules/pkg-fresh/index.mjs')).href, - format: 'module', -})); -"#, - ); - - let output = Command::new(node_binary()) - .arg(&driver_path) - .arg(&import_cache.loader_path) - .arg(workspace.path()) - .env("AGENTOS_NODE_IMPORT_CACHE_PATH", import_cache.cache_path()) - .env( - "AGENTOS_NODE_IMPORT_CACHE_ASSET_ROOT", - import_cache.asset_root(), - ) - .output() - .expect("run oversized state driver"); - let stderr = String::from_utf8_lossy(&output.stderr); - assert_eq!(output.status.code(), Some(0), "stderr: {stderr}"); - - let state_contents = - fs::read_to_string(import_cache.cache_path()).expect("read rewritten cache state"); - assert!( - state_contents.len() < 4 * 1024 * 1024, - "cache state should be rewritten below the hard limit" - ); - let state: Value = serde_json::from_str(&state_contents).expect("parse cache state"); - assert_eq!( - state["resolutions"] - .as_object() - .expect("resolution cache object") - .len(), - 1 - ); - } - - #[test] - fn materialized_loader_prunes_unreferenced_projected_source_files() { - assert_node_available(); - - let temp_root = tempdir().expect("create node import cache temp root"); - let workspace = tempdir().expect("create loader test workspace"); - let import_cache = NodeImportCache::new_in(temp_root.path().to_path_buf()); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - let node_modules = workspace.path().join("node_modules"); - fs::create_dir_all(&node_modules).expect("create node_modules"); - for index in 0..520 { - let package_dir = node_modules.join(format!("pkg-{index}")); - fs::create_dir_all(&package_dir).expect("create package dir"); - fs::write( - package_dir.join("index.mjs"), - format!("import fs from 'node:fs';\nexport const value = {index};\n"), - ) - .expect("write package source"); - } - - let driver_path = workspace.path().join("drive-projected-source-cache.mjs"); - write_fixture( - &driver_path, - r#" -import path from 'node:path'; -import { pathToFileURL } from 'node:url'; - -const [loaderPath, workspaceRoot] = process.argv.slice(2); -const loader = await import(`${pathToFileURL(loaderPath).href}?case=projected-${process.pid}-${Date.now()}`); - -for (let index = 0; index < 520; index += 1) { - const filePath = path.join(workspaceRoot, 'node_modules', `pkg-${index}`, 'index.mjs'); - await loader.load(pathToFileURL(filePath).href, { format: 'module' }, async () => { - throw new Error('nextLoad should not run for projected package sources'); - }); -} -"#, - ); - - let guest_path_mappings = format!( - r#"[{{"guestPath":"/root/node_modules","hostPath":"{}"}}]"#, - node_modules.display() - ); - let output = Command::new(node_binary()) - .arg(&driver_path) - .arg(&import_cache.loader_path) - .arg(workspace.path()) - .env("AGENTOS_NODE_IMPORT_CACHE_PATH", import_cache.cache_path()) - .env( - "AGENTOS_NODE_IMPORT_CACHE_ASSET_ROOT", - import_cache.asset_root(), - ) - .env("AGENTOS_GUEST_PATH_MAPPINGS", guest_path_mappings) - .output() - .expect("run projected source cache driver"); - let stderr = String::from_utf8_lossy(&output.stderr); - assert_eq!(output.status.code(), Some(0), "stderr: {stderr}"); - - let projected_source_root = import_cache - .cache_path() - .parent() - .expect("cache parent") - .join("projected-sources"); - let cached_file_count = fs::read_dir(&projected_source_root) - .expect("read projected source cache") - .count(); - assert_eq!(cached_file_count, 512); - } - - #[test] - fn ensure_materialized_writes_denied_builtin_assets_for_hardened_modules() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let denied_root = import_cache.asset_root().join("denied"); - let actual = fs::read_dir(&denied_root) - .expect("read denied builtin assets") - .map(|entry| { - entry - .expect("denied builtin asset entry") - .path() - .file_stem() - .expect("denied builtin asset file stem") - .to_string_lossy() - .into_owned() - }) - .collect::>(); - let expected = BTreeSet::from([ - String::from("child_process"), - String::from("cluster"), - String::from("dgram"), - String::from("http"), - String::from("http2"), - String::from("https"), - String::from("inspector"), - String::from("module"), - String::from("net"), - String::from("trace_events"), - ]); - - assert_eq!(actual, expected); - - let module_asset = - fs::read_to_string(denied_root.join("module.mjs")).expect("read module denied asset"); - let trace_events_asset = fs::read_to_string(denied_root.join("trace_events.mjs")) - .expect("read trace_events denied asset"); - - assert!(module_asset.contains("node:module is not available")); - assert!(trace_events_asset.contains("ERR_ACCESS_DENIED")); - } - - #[test] - fn ensure_materialized_writes_v8_vm_and_worker_threads_builtin_assets() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let builtins_root = import_cache.asset_root().join("builtins"); - let v8_asset = - fs::read_to_string(builtins_root.join("v8.mjs")).expect("read v8 builtin asset"); - let vm_asset = - fs::read_to_string(builtins_root.join("vm.mjs")).expect("read vm builtin asset"); - let worker_threads_asset = fs::read_to_string(builtins_root.join("worker-threads.mjs")) - .expect("read worker_threads builtin asset"); - - assert!(v8_asset.contains("process.getBuiltinModule?.(\"node:v8\")")); - assert!(v8_asset.contains("export const cachedDataVersionTag = mod.cachedDataVersionTag;")); - assert!(vm_asset.contains("process.getBuiltinModule?.(\"node:vm\")")); - assert!(vm_asset.contains("export const runInThisContext = mod.runInThisContext;")); - assert!(worker_threads_asset.contains("class Worker")); - assert!(worker_threads_asset.contains("export const isMainThread = mod.isMainThread;")); - } - - #[test] - fn ensure_materialized_writes_async_and_diagnostics_builtin_assets() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let builtins_root = import_cache.asset_root().join("builtins"); - let async_hooks_asset = fs::read_to_string(builtins_root.join("async-hooks.mjs")) - .expect("read async_hooks builtin asset"); - let diagnostics_asset = fs::read_to_string(builtins_root.join("diagnostics-channel.mjs")) - .expect("read diagnostics_channel builtin asset"); - - assert!(async_hooks_asset.contains("class AsyncLocalStorage")); - assert!(async_hooks_asset.contains("function createHook()")); - assert!(diagnostics_asset.contains("function channel(name = '')")); - assert!(diagnostics_asset.contains("class Channel")); - assert!(diagnostics_asset.contains("function tracingChannel(name = '')")); - } - - #[test] - fn ensure_materialized_writes_os_builtin_asset() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let os_asset = - fs::read_to_string(import_cache.asset_root().join("builtins").join("os.mjs")) - .expect("read os builtin asset"); - - assert!(os_asset.contains("__agentOSBuiltinOs")); - assert!(os_asset.contains("export const hostname = mod.hostname")); - assert!(os_asset.contains("export const userInfo = mod.userInfo")); - } - - #[test] - fn ensure_materialized_writes_http_builtin_assets() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let builtins_root = import_cache.asset_root().join("builtins"); - let http_asset = - fs::read_to_string(builtins_root.join("http.mjs")).expect("read http builtin asset"); - let http2_asset = - fs::read_to_string(builtins_root.join("http2.mjs")).expect("read http2 builtin asset"); - let https_asset = - fs::read_to_string(builtins_root.join("https.mjs")).expect("read https builtin asset"); - - assert!(http_asset.contains("__agentOSBuiltinHttp")); - assert!(http_asset.contains("export const request = mod.request")); - assert!(http2_asset.contains("__agentOSBuiltinHttp2")); - assert!(http2_asset.contains("export const connect = mod.connect")); - assert!(https_asset.contains("__agentOSBuiltinHttps")); - assert!(https_asset.contains("export const createServer = mod.createServer")); - } - - #[test] - fn ensure_materialized_writes_net_builtin_asset() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let net_asset = - fs::read_to_string(import_cache.asset_root().join("builtins").join("net.mjs")) - .expect("read net builtin asset"); - - assert!(net_asset.contains("__agentOSBuiltinNet")); - assert!(net_asset.contains("export const connect = mod.connect")); - assert!(net_asset.contains("export const createServer = mod.createServer")); - } - - #[test] - fn ensure_materialized_writes_dgram_builtin_asset() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let dgram_asset = - fs::read_to_string(import_cache.asset_root().join("builtins").join("dgram.mjs")) - .expect("read dgram builtin asset"); - - assert!(dgram_asset.contains("__agentOSBuiltinDgram")); - assert!(dgram_asset.contains("export const Socket = mod.Socket")); - assert!(dgram_asset.contains("export const createSocket = mod.createSocket")); - } - - #[test] - fn ensure_materialized_writes_dns_builtin_asset() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let dns_asset = - fs::read_to_string(import_cache.asset_root().join("builtins").join("dns.mjs")) - .expect("read dns builtin asset"); - - assert!(dns_asset.contains("__agentOSBuiltinDns")); - assert!(dns_asset.contains("export const Resolver = mod.Resolver")); - assert!(dns_asset.contains("export const lookup = mod.lookup")); - assert!(dns_asset.contains("export const resolve4 = mod.resolve4")); - } - - #[test] - fn ensure_materialized_writes_dns_promises_builtin_asset() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let dns_promises_asset = fs::read_to_string( - import_cache - .asset_root() - .join("builtins") - .join("dns-promises.mjs"), - ) - .expect("read dns promises builtin asset"); - - assert!(dns_promises_asset.contains("__agentOSBuiltinDns.promises")); - assert!(dns_promises_asset.contains("export const Resolver = mod.Resolver")); - assert!(dns_promises_asset.contains("export const resolve4 = mod.resolve4")); - } - - #[test] - fn wasm_runner_preopens_guest_cwd_before_root() { - let cwd_index = NODE_WASM_RUNNER_SOURCE - .find("preopens[cwdMount] = createPreopen(HOST_CWD, cwdReadOnly);") - .expect("runner should preopen the guest cwd"); - let root_index = NODE_WASM_RUNNER_SOURCE - .find("preopens['/'] = createPreopen(rootMapping.hostPath, rootMapping.readOnly);") - .expect("runner should preopen the guest root"); - - assert!(cwd_index < root_index); - } - - #[test] - fn wasm_runner_preserves_read_only_mappings_in_preopens() { - assert!(NODE_WASM_RUNNER_SOURCE - .contains("? { guestPath, hostPath, readOnly: entry.readOnly === true }")); - assert!(NODE_WASM_RUNNER_SOURCE.contains("readOnly: readOnly === true,")); - assert!(NODE_WASM_RUNNER_SOURCE.contains("resolveModuleGuestPathToHostMapping")); - assert!(NODE_WASM_RUNNER_SOURCE.contains("rightsBase: READ_ONLY_PREOPEN_RIGHTS_BASE,")); - assert!(NODE_WASM_RUNNER_SOURCE - .contains("preopens[guestPath] = createPreopen(mapping.hostPath, mapping.readOnly);")); - assert!(NODE_WASM_RUNNER_SOURCE.contains("const cwdReadOnly = readOnlyForCwd(guestCwd);")); - assert!(NODE_WASM_RUNNER_SOURCE - .contains("preopens[cwdMount] = createPreopen(HOST_CWD, cwdReadOnly);")); - assert!( - NODE_WASM_RUNNER_SOURCE.contains("if (mapping.readOnly) {\n return 1;\n }") - ); - assert!(NODE_WASM_RUNNER_SOURCE.contains("readOnly: preopenSpec?.readOnly === true,")); - assert!(NODE_WASM_RUNNER_SOURCE - .contains("resolveModuleGuestPathToHostMapping(guestPath)?.readOnly === true")); - assert!(NODE_WASM_RUNNER_SOURCE - .contains("if (handle.readOnly === true) {\n return WASI_ERRNO_ROFS;\n }")); - } - - #[test] - fn ensure_materialized_writes_tls_builtin_asset() { - let import_cache = NodeImportCache::default(); - import_cache - .ensure_materialized() - .expect("materialize node import cache"); - - let tls_asset = - fs::read_to_string(import_cache.asset_root().join("builtins").join("tls.mjs")) - .expect("read tls builtin asset"); - - assert!(tls_asset.contains("__agentOSBuiltinTls")); - assert!(tls_asset.contains("export const connect = mod.connect")); - assert!(tls_asset.contains("export const createServer = mod.createServer")); - } -} diff --git a/crates/execution/src/python.rs b/crates/execution/src/python.rs deleted file mode 100644 index b25a1353b..000000000 --- a/crates/execution/src/python.rs +++ /dev/null @@ -1,2194 +0,0 @@ -use crate::common::{encode_json_string, frozen_time_ms}; -use crate::javascript::{ - CreateJavascriptContextRequest, GuestRuntimeConfig, JavascriptExecution, - JavascriptExecutionEngine, JavascriptExecutionError, JavascriptExecutionEvent, - JavascriptExecutionLimits, JavascriptSyncRpcRequest, StartJavascriptExecutionRequest, -}; -use crate::node_import_cache::{NodeImportCache, NODE_IMPORT_CACHE_ASSET_ROOT_ENV}; -use crate::runtime_support::{ - env_flag_enabled, file_fingerprint, resolve_execution_path, warmup_marker_path, - NODE_DISABLE_COMPILE_CACHE_ENV, NODE_FROZEN_TIME_ENV, -}; -use crate::v8_runtime; -use base64::Engine as _; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; -use std::collections::BTreeMap; -use std::fmt; -use std::fs; -use std::os::unix::fs::MetadataExt; -use std::path::{Component, Path, PathBuf}; -use std::sync::{Arc, Mutex}; -use std::thread; -use std::time::{Duration, Instant}; -const NODE_ALLOW_PROCESS_BINDINGS_ENV: &str = "AGENTOS_ALLOW_PROCESS_BINDINGS"; -const NODE_GUEST_PATH_MAPPINGS_ENV: &str = "AGENTOS_GUEST_PATH_MAPPINGS"; -const NODE_SYNC_RPC_DATA_BYTES_ENV: &str = "AGENTOS_NODE_SYNC_RPC_DATA_BYTES"; -const PYODIDE_INDEX_URL_ENV: &str = "AGENTOS_PYODIDE_INDEX_URL"; -const PYODIDE_PACKAGE_BASE_URL_ENV: &str = "AGENTOS_PYODIDE_PACKAGE_BASE_URL"; -const PYODIDE_PACKAGE_CACHE_DIR_ENV: &str = "AGENTOS_PYODIDE_PACKAGE_CACHE_DIR"; -const PYODIDE_GUEST_ROOT: &str = "/__agentos_pyodide"; -const PYODIDE_CACHE_GUEST_ROOT: &str = "/__agentos_pyodide_cache"; -const PYTHON_CODE_ENV: &str = "AGENTOS_PYTHON_CODE"; -const PYTHON_FILE_ENV: &str = "AGENTOS_PYTHON_FILE"; -const PYTHON_PREWARM_ONLY_ENV: &str = "AGENTOS_PYTHON_PREWARM_ONLY"; -const PYTHON_WARMUP_DEBUG_ENV: &str = "AGENTOS_PYTHON_WARMUP_DEBUG"; -const PYTHON_WARMUP_METRICS_PREFIX: &str = "__AGENTOS_PYTHON_WARMUP_METRICS__:"; -const PYTHON_WARMUP_MARKER_VERSION: &str = "2"; -const DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES: usize = 1024 * 1024; -const DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS: u64 = 5 * 60 * 1000; -const DEFAULT_PYTHON_MAX_OLD_SPACE_MB: usize = 0; -const DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS: u64 = 30_000; -const PYTHON_SYNC_RPC_DATA_BYTES: usize = 20 * 1024 * 1024; -const PYTHON_SYNC_RPC_WAIT_TIMEOUT_MS: u64 = 120_000; -const PYTHON_PREWARM_TIMEOUT: Duration = Duration::from_secs(120); - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PythonVfsRpcMethod { - Read, - Write, - Stat, - Lstat, - ReadDir, - Mkdir, - Unlink, - Rmdir, - Rename, - Symlink, - ReadLink, - Setattr, - HttpRequest, - DnsLookup, - SubprocessRun, - SocketConnect, - SocketSend, - SocketRecv, - SocketClose, - UdpCreate, - UdpSendto, - UdpRecvfrom, -} - -impl PythonVfsRpcMethod { - fn from_wire(value: &str) -> Option { - match value { - "fsRead" => Some(Self::Read), - "fsWrite" => Some(Self::Write), - "fsStat" => Some(Self::Stat), - "fsLstat" => Some(Self::Lstat), - "fsReaddir" => Some(Self::ReadDir), - "fsMkdir" => Some(Self::Mkdir), - "fsUnlink" => Some(Self::Unlink), - "fsRmdir" => Some(Self::Rmdir), - "fsRename" => Some(Self::Rename), - "fsSymlink" => Some(Self::Symlink), - "fsReadlink" => Some(Self::ReadLink), - "fsSetattr" => Some(Self::Setattr), - "httpRequest" => Some(Self::HttpRequest), - "dnsLookup" => Some(Self::DnsLookup), - "subprocessRun" => Some(Self::SubprocessRun), - "socketConnect" => Some(Self::SocketConnect), - "socketSend" => Some(Self::SocketSend), - "socketRecv" => Some(Self::SocketRecv), - "socketClose" => Some(Self::SocketClose), - "udpCreate" => Some(Self::UdpCreate), - "udpSendto" => Some(Self::UdpSendto), - "udpRecvfrom" => Some(Self::UdpRecvfrom), - _ => None, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PythonVfsRpcRequest { - pub id: u64, - pub method: PythonVfsRpcMethod, - pub path: String, - /// Second path for `Rename` (the destination); `None` for other methods. - pub destination: Option, - /// Symlink target (the path the link points at), for `Symlink`. - pub target: Option, - /// `Setattr` metadata fields (each applied only when present). - pub mode: Option, - pub uid: Option, - pub gid: Option, - pub atime_ms: Option, - pub mtime_ms: Option, - pub content_base64: Option, - pub recursive: bool, - pub url: Option, - pub http_method: Option, - pub headers: BTreeMap, - pub body_base64: Option, - pub hostname: Option, - pub family: Option, - /// Port for socket connect/sendto. - pub port: Option, - /// Socket handle for send/recv/close/sendto/recvfrom. - pub socket_id: Option, - pub command: Option, - pub args: Vec, - pub cwd: Option, - pub env: BTreeMap, - pub shell: bool, - pub max_buffer: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PythonVfsRpcStat { - pub mode: u32, - pub size: u64, - pub is_directory: bool, - pub is_symbolic_link: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PythonVfsRpcResponsePayload { - Empty, - Read { - content_base64: String, - }, - Stat { - stat: PythonVfsRpcStat, - }, - ReadDir { - entries: Vec, - }, - Http { - status: u16, - reason: String, - url: String, - headers: BTreeMap>, - body_base64: String, - }, - DnsLookup { - addresses: Vec, - }, - SubprocessRun { - exit_code: i32, - stdout: String, - stderr: String, - max_buffer_exceeded: bool, - }, - SocketCreated { - socket_id: u64, - }, - SocketSent { - bytes_sent: usize, - }, - SocketReceived { - data_base64: String, - closed: bool, - timed_out: bool, - }, - UdpReceived { - data_base64: String, - host: String, - port: u16, - timed_out: bool, - }, - SymlinkTarget { - target: String, - }, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct PythonVfsBridgeRequestWire { - method: String, - #[serde(default)] - path: String, - #[serde(default)] - destination: Option, - #[serde(default)] - target: Option, - // JS numbers cross the bridge as f64; accept that and narrow below. - #[serde(default)] - mode: Option, - #[serde(default)] - uid: Option, - #[serde(default)] - gid: Option, - #[serde(default, rename = "atimeMs")] - atime_ms: Option, - #[serde(default, rename = "mtimeMs")] - mtime_ms: Option, - #[serde(default)] - content_base64: Option, - #[serde(default)] - recursive: bool, - #[serde(default)] - url: Option, - #[serde(default, rename = "httpMethod")] - http_method: Option, - #[serde(default)] - headers: BTreeMap, - #[serde(default, rename = "bodyBase64")] - body_base64: Option, - #[serde(default)] - hostname: Option, - #[serde(default)] - family: Option, - #[serde(default)] - port: Option, - #[serde(default, rename = "socketId")] - socket_id: Option, - #[serde(default)] - command: Option, - #[serde(default)] - args: Vec, - #[serde(default)] - cwd: Option, - #[serde(default)] - env: BTreeMap, - #[serde(default)] - shell: bool, - #[serde(default, rename = "maxBuffer")] - max_buffer: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -struct PythonGuestPathMappingWire { - guest_path: String, - host_path: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CreatePythonContextRequest { - pub vm_id: String, - pub pyodide_dist_path: PathBuf, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PythonContext { - pub context_id: String, - pub vm_id: String, - pub pyodide_dist_path: PathBuf, -} - -/// Per-execution Python runtime limits, carried as typed fields rather than -/// `AGENTOS_*` env vars. Populated by the sidecar from the per-VM `VmLimits` -/// (originating from `CreateVmConfig` on the BARE wire); `None` selects the -/// engine default. See the env-vs-wire rule in `crates/sidecar/CLAUDE.md`. -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct PythonExecutionLimits { - /// Captured-output buffer cap in bytes. `None` keeps the engine default. - pub output_buffer_max_bytes: Option, - /// Execution wall-clock cap in ms. `None` keeps the engine default; - /// `Some(0)` disables the timeout. - pub execution_timeout_ms: Option, - /// Pyodide V8 old-space cap in MB (`0` keeps the V8 default). `None` keeps - /// the engine default. - pub max_old_space_mb: Option, - /// VFS sync-RPC wait ceiling in ms. `None` keeps the engine default. - pub vfs_rpc_timeout_ms: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StartPythonExecutionRequest { - pub vm_id: String, - pub context_id: String, - pub code: String, - pub file_path: Option, - pub env: BTreeMap, - pub cwd: PathBuf, - /// Per-execution runtime limits (see [`PythonExecutionLimits`]). - pub limits: PythonExecutionLimits, - /// Per-execution guest-runtime config, forwarded to the Pyodide runner's JS - /// execution (see [`GuestRuntimeConfig`]). - pub guest_runtime: GuestRuntimeConfig, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PythonExecutionEvent { - Stdout(Vec), - Stderr(Vec), - JavascriptSyncRpcRequest(JavascriptSyncRpcRequest), - VfsRpcRequest(Box), - Exited(i32), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PythonExecutionResult { - pub execution_id: String, - pub exit_code: i32, - pub stdout: Vec, - pub stderr: Vec, -} - -#[derive(Debug)] -pub enum PythonExecutionError { - MissingContext(String), - VmMismatch { - expected: String, - found: String, - }, - /// Guest Python is unavailable because this build was compiled without the - /// bundled Pyodide runtime assets (the published crate excludes them). - RuntimeUnavailable, - PrepareRuntime(std::io::Error), - PrepareWarmPath(std::io::Error), - WarmupFailed { - exit_code: i32, - stderr: String, - }, - Spawn(std::io::Error), - StdinClosed, - Stdin(std::io::Error), - Kill(std::io::Error), - TimedOut(Duration), - PendingVfsRpcRequest(u64), - RpcResponse(String), - OutputBufferExceeded { - stream: &'static str, - limit: usize, - }, - EventChannelClosed, -} - -impl fmt::Display for PythonExecutionError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::MissingContext(context_id) => { - write!(f, "unknown guest Python context: {context_id}") - } - Self::VmMismatch { expected, found } => { - write!( - f, - "guest Python context belongs to vm {expected}, not {found}" - ) - } - Self::RuntimeUnavailable => write!( - f, - "guest Python execution is unavailable: this build of secure-exec-execution \ - was compiled without the bundled Pyodide runtime assets" - ), - Self::PrepareRuntime(err) => { - write!(f, "failed to prepare guest Python runtime assets: {err}") - } - Self::PrepareWarmPath(err) => { - write!(f, "failed to prepare guest Python warm path: {err}") - } - Self::WarmupFailed { exit_code, stderr } => { - if stderr.trim().is_empty() { - write!(f, "guest Python warmup exited with status {exit_code}") - } else { - write!( - f, - "guest Python warmup exited with status {exit_code}: {}", - stderr.trim() - ) - } - } - Self::Spawn(err) => write!(f, "failed to start guest Python runtime: {err}"), - Self::StdinClosed => f.write_str("guest Python stdin is already closed"), - Self::Stdin(err) => write!(f, "failed to write guest stdin: {err}"), - Self::Kill(err) => write!(f, "failed to kill guest Python runtime: {err}"), - Self::TimedOut(timeout) => write!( - f, - "guest Python runtime timed out after {}ms", - timeout.as_millis() - ), - Self::PendingVfsRpcRequest(id) => { - write!( - f, - "guest Python execution requires servicing pending VFS RPC request {id}" - ) - } - Self::RpcResponse(message) => { - write!( - f, - "failed to reply to guest Python VFS RPC request: {message}" - ) - } - Self::OutputBufferExceeded { stream, limit } => { - write!( - f, - "guest Python {stream} exceeded the captured output limit of {limit} bytes" - ) - } - Self::EventChannelClosed => { - f.write_str("guest Python event channel closed unexpectedly") - } - } - } -} - -impl std::error::Error for PythonExecutionError {} - -/// Returns an error when this build was compiled without the bundled Pyodide -/// runtime assets (the published crate excludes them; see `build.rs`). In the -/// workspace build the in-tree assets are present and this is a no-op. -fn ensure_pyodide_available() -> Result<(), PythonExecutionError> { - #[cfg(secure_exec_pyodide_unavailable)] - { - return Err(PythonExecutionError::RuntimeUnavailable); - } - #[cfg(not(secure_exec_pyodide_unavailable))] - { - Ok(()) - } -} - -#[derive(Debug)] -pub struct PythonExecution { - execution_id: String, - child_pid: u32, - inner: JavascriptExecution, - pyodide_dist_path: PathBuf, - pending_vfs_rpc: Arc>>, - v8_session: crate::v8_host::V8SessionHandle, - output_buffer_max_bytes: usize, - execution_timeout: Option, - vfs_rpc_timeout: Duration, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum PendingVfsRpcState { - Pending(u64), - TimedOut(u64), -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum PendingVfsRpcResolution { - Pending, - TimedOut, - Missing, -} - -impl PythonExecution { - pub fn execution_id(&self) -> &str { - &self.execution_id - } - - pub fn child_pid(&self) -> u32 { - self.child_pid - } - - pub fn uses_shared_v8_runtime(&self) -> bool { - self.inner.uses_shared_v8_runtime() - } - - pub fn write_stdin(&mut self, chunk: &[u8]) -> Result<(), PythonExecutionError> { - self.inner - .write_kernel_stdin_only(chunk) - .map_err(map_javascript_error) - } - - pub fn close_stdin(&mut self) -> Result<(), PythonExecutionError> { - self.inner.close_kernel_stdin_only(); - Ok(()) - } - - pub fn cancel(&mut self) -> Result<(), PythonExecutionError> { - self.kill() - } - - pub fn kill(&mut self) -> Result<(), PythonExecutionError> { - self.close_stdin()?; - self.inner.terminate().map_err(map_javascript_error) - } - - pub fn respond_vfs_rpc_success( - &mut self, - id: u64, - payload: PythonVfsRpcResponsePayload, - ) -> Result<(), PythonExecutionError> { - match self.clear_pending_vfs_rpc(id)? { - PendingVfsRpcResolution::Pending => {} - PendingVfsRpcResolution::TimedOut => { - return Err(PythonExecutionError::RpcResponse(format!( - "VFS RPC request {id} is no longer pending" - ))); - } - PendingVfsRpcResolution::Missing => {} - } - - let result = match payload { - PythonVfsRpcResponsePayload::Empty => json!({}), - PythonVfsRpcResponsePayload::Read { content_base64 } => { - json!({ "contentBase64": content_base64 }) - } - PythonVfsRpcResponsePayload::Stat { stat } => json!({ - "stat": { - "mode": stat.mode, - "size": stat.size, - "isDirectory": stat.is_directory, - "isSymbolicLink": stat.is_symbolic_link, - } - }), - PythonVfsRpcResponsePayload::ReadDir { entries } => { - json!({ "entries": entries }) - } - PythonVfsRpcResponsePayload::Http { - status, - reason, - url, - headers, - body_base64, - } => json!({ - "status": status, - "reason": reason, - "url": url, - "headers": headers, - "bodyBase64": body_base64, - }), - PythonVfsRpcResponsePayload::DnsLookup { addresses } => { - json!({ "addresses": addresses }) - } - PythonVfsRpcResponsePayload::SubprocessRun { - exit_code, - stdout, - stderr, - max_buffer_exceeded, - } => json!({ - "exitCode": exit_code, - "stdout": stdout, - "stderr": stderr, - "maxBufferExceeded": max_buffer_exceeded, - }), - PythonVfsRpcResponsePayload::SocketCreated { socket_id } => json!({ - "socketId": socket_id, - }), - PythonVfsRpcResponsePayload::SocketSent { bytes_sent } => json!({ - "bytesSent": bytes_sent, - }), - PythonVfsRpcResponsePayload::SocketReceived { - data_base64, - closed, - timed_out, - } => json!({ - "dataBase64": data_base64, - "closed": closed, - "timedOut": timed_out, - }), - PythonVfsRpcResponsePayload::UdpReceived { - data_base64, - host, - port, - timed_out, - } => json!({ - "dataBase64": data_base64, - "host": host, - "port": port, - "timedOut": timed_out, - }), - PythonVfsRpcResponsePayload::SymlinkTarget { target } => json!({ - "target": target, - }), - }; - - self.inner - .respond_sync_rpc_success(id, result) - .map_err(map_javascript_error) - } - - pub fn respond_vfs_rpc_error( - &mut self, - id: u64, - code: impl Into, - message: impl Into, - ) -> Result<(), PythonExecutionError> { - match self.clear_pending_vfs_rpc(id)? { - PendingVfsRpcResolution::Pending => {} - PendingVfsRpcResolution::TimedOut => { - return Err(PythonExecutionError::RpcResponse(format!( - "VFS RPC request {id} is no longer pending" - ))); - } - PendingVfsRpcResolution::Missing => {} - } - - self.inner - .respond_sync_rpc_error(id, code, message) - .map_err(map_javascript_error) - } - - pub fn respond_javascript_sync_rpc_success( - &mut self, - id: u64, - result: Value, - ) -> Result<(), PythonExecutionError> { - self.inner - .respond_sync_rpc_success(id, result) - .map_err(map_javascript_error) - } - - pub fn respond_javascript_sync_rpc_error( - &mut self, - id: u64, - code: impl Into, - message: impl Into, - ) -> Result<(), PythonExecutionError> { - self.inner - .respond_sync_rpc_error(id, code, message) - .map_err(map_javascript_error) - } - - pub async fn poll_event( - &mut self, - timeout: Duration, - ) -> Result, PythonExecutionError> { - let started = Instant::now(); - loop { - let remaining = if timeout.is_zero() { - Duration::ZERO - } else { - timeout.saturating_sub(started.elapsed()) - }; - match self - .inner - .poll_event(remaining) - .await - .map_err(map_javascript_error)? - { - Some(event) => { - if let Some(event) = self.translate_javascript_event(event)? { - return Ok(Some(event)); - } - } - None => return Ok(None), - } - } - } - - /// Service a module-resolution JS sync RPC host-directly via the underlying - /// JS execution's translator. For consumers driving `poll_event_blocking` - /// manually without a kernel/service loop. - pub fn try_service_standalone_module_sync_rpc( - &mut self, - request: &JavascriptSyncRpcRequest, - ) -> Result { - self.inner - .try_service_standalone_module_sync_rpc(request) - .map_err(map_javascript_error) - } - - pub fn poll_event_blocking( - &mut self, - timeout: Duration, - ) -> Result, PythonExecutionError> { - let deadline = Instant::now() + timeout; - loop { - let remaining = deadline.saturating_duration_since(Instant::now()); - match self - .inner - .poll_event_blocking(remaining) - .map_err(map_javascript_error)? - { - Some(event) => { - if let Some(event) = self.translate_javascript_event(event)? { - return Ok(Some(event)); - } - } - None => { - if Instant::now() >= deadline { - return Ok(None); - } - } - } - } - } - - pub fn wait( - mut self, - timeout: Option, - ) -> Result { - self.close_stdin()?; - - let mut stdout = PythonOutputBuffer::new(self.output_buffer_max_bytes); - let mut stderr = PythonOutputBuffer::new(self.output_buffer_max_bytes); - let started = Instant::now(); - let timeout = match (timeout, self.execution_timeout) { - (Some(requested), Some(configured)) => Some(requested.min(configured)), - (Some(requested), None) => Some(requested), - (None, Some(configured)) => Some(configured), - (None, None) => None, - }; - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("python wait runtime"); - - loop { - let poll_timeout = timeout - .map(|limit| { - let elapsed = started.elapsed(); - if elapsed >= limit { - Duration::ZERO - } else { - limit.saturating_sub(elapsed).min(Duration::from_millis(50)) - } - }) - .unwrap_or_else(|| Duration::from_millis(50)); - - let event = runtime.block_on(self.poll_event(poll_timeout))?; - - match event { - Some(PythonExecutionEvent::Stdout(chunk)) => stdout.extend(&chunk), - Some(PythonExecutionEvent::Stderr(chunk)) => stderr.extend(&chunk), - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - // Module-resolution sync RPCs are serviced host-directly via - // the JS execution's own translator (the standalone Python - // wait loop runs without a kernel/service loop). - if self - .inner - .try_service_standalone_module_sync_rpc(&request) - .map_err(map_javascript_error)? - { - continue; - } - if let Some((code, message)) = python_javascript_sync_rpc_error(&request) { - self.inner - .respond_sync_rpc_error(request.id, code, message) - .map_err(map_javascript_error)?; - continue; - } - return Err(PythonExecutionError::RpcResponse(format!( - "guest Python execution requires servicing pending JavaScript sync RPC request {} {} {:?}", - request.id, request.method, request.args - ))); - } - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - return Err(PythonExecutionError::PendingVfsRpcRequest(request.id)); - } - Some(PythonExecutionEvent::Exited(exit_code)) => { - return Ok(PythonExecutionResult { - execution_id: self.execution_id.clone(), - exit_code, - stdout: stdout.into_inner(), - stderr: stderr.into_inner(), - }); - } - None => {} - } - - if let Some(limit) = timeout { - if started.elapsed() >= limit { - self.kill()?; - return Err(PythonExecutionError::TimedOut(limit)); - } - } - } - } - - fn clear_pending_vfs_rpc( - &self, - id: u64, - ) -> Result { - let mut pending = self - .pending_vfs_rpc - .lock() - .map_err(|_| PythonExecutionError::EventChannelClosed)?; - match *pending { - Some(PendingVfsRpcState::Pending(current)) if current == id => { - *pending = None; - Ok(PendingVfsRpcResolution::Pending) - } - Some(PendingVfsRpcState::TimedOut(current)) if current == id => { - Ok(PendingVfsRpcResolution::TimedOut) - } - _ => Ok(PendingVfsRpcResolution::Missing), - } - } - - fn translate_javascript_event( - &mut self, - event: JavascriptExecutionEvent, - ) -> Result, PythonExecutionError> { - match event { - JavascriptExecutionEvent::Stdout(chunk) => { - Ok(Some(PythonExecutionEvent::Stdout(chunk))) - } - JavascriptExecutionEvent::Stderr(chunk) => { - Ok(Some(PythonExecutionEvent::Stderr(chunk))) - } - JavascriptExecutionEvent::Exited(code) => Ok(Some(PythonExecutionEvent::Exited(code))), - JavascriptExecutionEvent::SignalState { .. } => Ok(None), - JavascriptExecutionEvent::SyncRpcRequest(request) => { - if request.method == "_pythonRpc" { - let request = parse_python_bridge_sync_rpc_request(&request)?; - set_pending_vfs_rpc_state(&self.pending_vfs_rpc, request.id)?; - spawn_python_vfs_rpc_timeout( - request.id, - self.vfs_rpc_timeout, - self.pending_vfs_rpc.clone(), - self.v8_session.clone(), - ); - Ok(Some(PythonExecutionEvent::VfsRpcRequest(Box::new(request)))) - } else { - if self.try_service_standalone_module_sync_rpc(&request)? { - return Ok(None); - } - if let Some(action) = - python_javascript_sync_rpc_action(&self.pyodide_dist_path, &request)? - { - respond_python_javascript_sync_rpc_action( - &mut self.inner, - request.id, - action, - )?; - Ok(None) - } else { - Ok(Some(PythonExecutionEvent::JavascriptSyncRpcRequest( - request, - ))) - } - } - } - } - } -} - -impl Drop for PythonExecution { - fn drop(&mut self) { - let _ = self.close_stdin(); - let _ = self.inner.terminate(); - } -} - -#[derive(Debug, Default)] -pub struct PythonExecutionEngine { - next_context_id: usize, - next_execution_id: usize, - contexts: BTreeMap, - import_caches: BTreeMap, - javascript_context_ids: BTreeMap, - javascript_engine: JavascriptExecutionEngine, -} - -impl PythonExecutionEngine { - pub fn bundled_pyodide_dist_path_for_vm( - &mut self, - vm_id: &str, - ) -> Result { - ensure_pyodide_available()?; - let import_cache = self.import_caches.entry(vm_id.to_owned()).or_default(); - import_cache - .ensure_materialized() - .map_err(PythonExecutionError::PrepareRuntime)?; - Ok(import_cache.pyodide_dist_path().to_path_buf()) - } - - pub fn create_context(&mut self, request: CreatePythonContextRequest) -> PythonContext { - self.next_context_id += 1; - self.import_caches.entry(request.vm_id.clone()).or_default(); - let javascript_context = - self.javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: request.vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - - let context = PythonContext { - context_id: format!("python-ctx-{}", self.next_context_id), - vm_id: request.vm_id, - pyodide_dist_path: request.pyodide_dist_path, - }; - self.javascript_context_ids - .insert(context.context_id.clone(), javascript_context.context_id); - self.contexts - .insert(context.context_id.clone(), context.clone()); - context - } - - pub fn start_execution( - &mut self, - request: StartPythonExecutionRequest, - ) -> Result { - ensure_pyodide_available()?; - let context = self - .contexts - .get(&request.context_id) - .cloned() - .ok_or_else(|| PythonExecutionError::MissingContext(request.context_id.clone()))?; - - if context.vm_id != request.vm_id { - return Err(PythonExecutionError::VmMismatch { - expected: context.vm_id, - found: request.vm_id, - }); - } - - let frozen_time_ms = frozen_time_ms(); - let javascript_context = - self.javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: request.vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let javascript_context_id = javascript_context.context_id.clone(); - self.javascript_context_ids - .insert(context.context_id.clone(), javascript_context_id.clone()); - let warmup_metrics = { - let import_cache = self.import_caches.entry(context.vm_id.clone()).or_default(); - import_cache - .ensure_materialized() - .map_err(PythonExecutionError::PrepareRuntime)?; - prewarm_python_path( - import_cache, - &mut self.javascript_engine, - &javascript_context_id, - &context, - &request, - frozen_time_ms, - )? - }; - - self.next_execution_id += 1; - let execution_id = format!("exec-{}", self.next_execution_id); - let import_cache = self - .import_caches - .get(&context.vm_id) - .expect("vm import cache should exist after materialization"); - let pyodide_dist_path = - resolved_pyodide_dist_path(&context.pyodide_dist_path, &request.cwd); - let javascript_execution = start_python_javascript_execution( - &mut self.javascript_engine, - import_cache, - &javascript_context_id, - &context, - &request, - PythonJavascriptExecutionOptions { - frozen_time_ms, - prewarm_only: false, - warmup_metrics: warmup_metrics.as_deref(), - }, - )?; - let pending_vfs_rpc = Arc::new(Mutex::new(None)); - let vfs_rpc_timeout = python_vfs_rpc_timeout(&request); - - Ok(PythonExecution { - execution_id, - child_pid: javascript_execution.child_pid(), - v8_session: javascript_execution.v8_session_handle(), - inner: javascript_execution, - pyodide_dist_path, - pending_vfs_rpc, - output_buffer_max_bytes: python_output_buffer_max_bytes(&request), - execution_timeout: python_execution_timeout(&request), - vfs_rpc_timeout, - }) - } - - pub fn dispose_vm(&mut self, vm_id: &str) { - self.contexts.retain(|_, context| context.vm_id != vm_id); - self.javascript_context_ids - .retain(|python_context_id, _| self.contexts.contains_key(python_context_id)); - self.import_caches.remove(vm_id); - self.javascript_engine.dispose_vm(vm_id); - } -} - -fn set_pending_vfs_rpc_state( - pending_vfs_rpc: &Arc>>, - id: u64, -) -> Result<(), PythonExecutionError> { - let mut pending = pending_vfs_rpc - .lock() - .map_err(|_| PythonExecutionError::EventChannelClosed)?; - *pending = Some(PendingVfsRpcState::Pending(id)); - Ok(()) -} - -fn map_javascript_error(error: JavascriptExecutionError) -> PythonExecutionError { - match error { - JavascriptExecutionError::EmptyArgv => PythonExecutionError::Spawn(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "guest Python bootstrap requires a JavaScript entrypoint", - )), - JavascriptExecutionError::MissingContext(context_id) => { - PythonExecutionError::MissingContext(context_id) - } - JavascriptExecutionError::VmMismatch { expected, found } => { - PythonExecutionError::VmMismatch { expected, found } - } - JavascriptExecutionError::PrepareImportCache(error) => { - PythonExecutionError::PrepareRuntime(error) - } - JavascriptExecutionError::Spawn(error) => PythonExecutionError::Spawn(error), - JavascriptExecutionError::PendingSyncRpcRequest(id) => { - PythonExecutionError::PendingVfsRpcRequest(id) - } - JavascriptExecutionError::ExpiredSyncRpcRequest(id) => { - PythonExecutionError::RpcResponse(format!("VFS RPC request {id} is no longer pending")) - } - JavascriptExecutionError::RpcResponse(message) => { - PythonExecutionError::RpcResponse(message) - } - JavascriptExecutionError::Terminate(error) => PythonExecutionError::Kill(error), - JavascriptExecutionError::StdinClosed => PythonExecutionError::StdinClosed, - JavascriptExecutionError::Stdin(error) => PythonExecutionError::Stdin(error), - JavascriptExecutionError::OutputBufferExceeded { stream, limit } => { - PythonExecutionError::OutputBufferExceeded { stream, limit } - } - JavascriptExecutionError::EventChannelClosed => PythonExecutionError::EventChannelClosed, - } -} - -struct PythonJavascriptExecutionOptions<'a> { - frozen_time_ms: u128, - prewarm_only: bool, - warmup_metrics: Option<&'a [u8]>, -} - -fn start_python_javascript_execution( - javascript_engine: &mut JavascriptExecutionEngine, - import_cache: &NodeImportCache, - javascript_context_id: &str, - context: &PythonContext, - request: &StartPythonExecutionRequest, - options: PythonJavascriptExecutionOptions<'_>, -) -> Result { - let internal_env = build_python_internal_env( - import_cache, - context, - request, - options.frozen_time_ms, - options.prewarm_only, - ); - let inline_code = - build_python_runner_module_source(import_cache, &internal_env, options.warmup_metrics)?; - let mut env = request.env.clone(); - env.extend(internal_env); - - // The Pyodide runner is itself a V8 execution. Its heap cap (the Python - // `maxOldSpaceMb` knob) and sync-RPC wait ceiling ride the typed runner - // limits, not env — the JS engine reads them from `limits`, not `AGENTOS_*`. - let max_old_space_mb = python_max_old_space_mb(request); - let runner_limits = JavascriptExecutionLimits { - v8_heap_limit_mb: (max_old_space_mb > 0).then_some(max_old_space_mb as u32), - sync_rpc_wait_timeout_ms: Some(PYTHON_SYNC_RPC_WAIT_TIMEOUT_MS), - ..JavascriptExecutionLimits::default() - }; - - javascript_engine - .start_execution(StartJavascriptExecutionRequest { - vm_id: request.vm_id.clone(), - context_id: javascript_context_id.to_owned(), - argv: vec![import_cache.python_runner_path().display().to_string()], - env, - cwd: request.cwd.clone(), - limits: runner_limits, - // Forward the guest-runtime identity so the runner's shim sets - // process.* from typed config rather than env. - guest_runtime: request.guest_runtime.clone(), - wasm_module_bytes: None, - inline_code: Some(inline_code), - }) - .map_err(map_javascript_error) -} - -fn build_python_internal_env( - import_cache: &NodeImportCache, - context: &PythonContext, - request: &StartPythonExecutionRequest, - frozen_time_ms: u128, - prewarm_only: bool, -) -> BTreeMap { - let mut internal_env = request - .env - .iter() - .filter(|(key, _)| key.starts_with("AGENTOS_")) - .map(|(key, value)| (key.clone(), value.clone())) - .collect::>(); - let pyodide_dist_path = resolved_pyodide_dist_path(&context.pyodide_dist_path, &request.cwd); - - add_python_guest_path_mapping(&mut internal_env, &pyodide_dist_path); - - internal_env.insert( - PYODIDE_INDEX_URL_ENV.to_string(), - String::from(PYODIDE_GUEST_ROOT), - ); - internal_env.insert( - PYODIDE_PACKAGE_BASE_URL_ENV.to_string(), - request - .env - .get(PYODIDE_PACKAGE_BASE_URL_ENV) - .cloned() - .unwrap_or_else(|| String::from(PYODIDE_GUEST_ROOT)), - ); - internal_env.insert( - PYODIDE_PACKAGE_CACHE_DIR_ENV.to_string(), - String::from(PYODIDE_CACHE_GUEST_ROOT), - ); - internal_env.insert( - NODE_IMPORT_CACHE_ASSET_ROOT_ENV.to_string(), - import_cache.asset_root().display().to_string(), - ); - internal_env.insert( - NODE_ALLOW_PROCESS_BINDINGS_ENV.to_string(), - String::from("1"), - ); - internal_env.insert( - NODE_SYNC_RPC_DATA_BYTES_ENV.to_string(), - PYTHON_SYNC_RPC_DATA_BYTES.to_string(), - ); - internal_env.insert( - NODE_DISABLE_COMPILE_CACHE_ENV.to_string(), - String::from("1"), - ); - // The runner's V8 heap cap and sync-RPC wait timeout are carried as typed - // `JavascriptExecutionLimits` on the runner request (see the launch site), - // not as `AGENTOS_V8_HEAP_LIMIT_MB` / `AGENTOS_NODE_SYNC_RPC_WAIT_TIMEOUT_MS` - // env knobs, which the JS engine no longer reads. - internal_env.insert(PYTHON_CODE_ENV.to_string(), request.code.clone()); - internal_env.insert(NODE_FROZEN_TIME_ENV.to_string(), frozen_time_ms.to_string()); - if prewarm_only { - internal_env.insert(PYTHON_PREWARM_ONLY_ENV.to_string(), String::from("1")); - } else { - internal_env.insert( - String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - ); - internal_env.remove(PYTHON_PREWARM_ONLY_ENV); - } - if let Some(file_path) = &request.file_path { - internal_env.insert(PYTHON_FILE_ENV.to_string(), file_path.display().to_string()); - } else { - internal_env.remove(PYTHON_FILE_ENV); - } - - internal_env -} - -fn add_python_guest_path_mapping( - internal_env: &mut BTreeMap, - pyodide_dist_path: &Path, -) { - let pyodide_cache_path = pyodide_cache_path(pyodide_dist_path); - let mut mappings = internal_env - .get(NODE_GUEST_PATH_MAPPINGS_ENV) - .and_then(|value| serde_json::from_str::>(value).ok()) - .unwrap_or_default(); - - mappings.retain(|mapping| { - mapping.guest_path != PYODIDE_GUEST_ROOT && mapping.guest_path != PYODIDE_CACHE_GUEST_ROOT - }); - mappings.push(PythonGuestPathMappingWire { - guest_path: String::from(PYODIDE_GUEST_ROOT), - host_path: pyodide_dist_path.display().to_string(), - }); - mappings.push(PythonGuestPathMappingWire { - guest_path: String::from(PYODIDE_CACHE_GUEST_ROOT), - host_path: pyodide_cache_path.display().to_string(), - }); - - let serialized = serde_json::to_string(&mappings).unwrap_or_else(|_| String::from("[]")); - internal_env.insert(String::from(NODE_GUEST_PATH_MAPPINGS_ENV), serialized); -} - -fn pyodide_cache_path(pyodide_dist_path: &Path) -> PathBuf { - let base = pyodide_dist_path - .parent() - .and_then(|parent| { - if parent.file_name().is_some_and(|name| name == "assets") { - parent.parent() - } else { - Some(parent) - } - }) - .unwrap_or(pyodide_dist_path); - - base.join("pyodide-package-cache") -} - -fn build_python_runner_module_source( - import_cache: &NodeImportCache, - internal_env: &BTreeMap, - warmup_metrics: Option<&[u8]>, -) -> Result { - let runner_source = fs::read_to_string(import_cache.python_runner_path()) - .map_err(PythonExecutionError::PrepareRuntime)?; - let runner_source = - format!("import * as __agentOSConstantsBinding from 'node:constants';\n{runner_source}"); - let bootstrap = build_python_runner_bootstrap(internal_env, warmup_metrics); - Ok(insert_python_runner_bootstrap(&runner_source, &bootstrap)) -} - -fn build_python_runner_bootstrap( - internal_env: &BTreeMap, - warmup_metrics: Option<&[u8]>, -) -> String { - let internal_env_json = - serde_json::to_string(internal_env).unwrap_or_else(|_| String::from("{}")); - let warmup_metrics_json = warmup_metrics.map(|bytes| { - serde_json::to_string(&String::from_utf8_lossy(bytes).to_string()) - .unwrap_or_else(|_| String::from("\"\"")) - }); - - match warmup_metrics_json { - Some(warmup_metrics_json) => format!( - "globalThis.__agentOSPythonInternalEnv = {internal_env_json};\n\ -if (typeof process !== 'undefined') {{\n process.env = {{ ...(process.env || {{}}), ...globalThis.__agentOSPythonInternalEnv }};\n}}\n\ -if (typeof process?.stderr?.write === 'function') {{\n process.stderr.write({warmup_metrics_json});\n}}\n" - ), - None => format!( - "globalThis.__agentOSPythonInternalEnv = {internal_env_json};\n\ -if (typeof process !== 'undefined') {{\n process.env = {{ ...(process.env || {{}}), ...globalThis.__agentOSPythonInternalEnv }};\n}}\n" - ), - } -} - -fn insert_python_runner_bootstrap(source: &str, bootstrap: &str) -> String { - let mut insert_at = 0usize; - let mut saw_import = false; - for line in source.split_inclusive('\n') { - let trimmed = line.trim_start(); - if trimmed.starts_with("import ") || (saw_import && trimmed.is_empty()) { - insert_at += line.len(); - saw_import = saw_import || trimmed.starts_with("import "); - continue; - } - break; - } - - format!( - "{}{}{}", - &source[..insert_at], - bootstrap, - &source[insert_at..] - ) -} - -fn parse_python_bridge_sync_rpc_request( - request: &JavascriptSyncRpcRequest, -) -> Result { - if request.method != "_pythonRpc" { - return Err(PythonExecutionError::RpcResponse(format!( - "unexpected JavaScript sync RPC method for guest Python runtime: {}", - request.method - ))); - } - - let payload = request.args.first().ok_or_else(|| { - PythonExecutionError::RpcResponse(String::from( - "guest Python bridge call did not include a request payload", - )) - })?; - - let wire: PythonVfsBridgeRequestWire = - serde_json::from_value(payload.clone()).map_err(|error| { - PythonExecutionError::RpcResponse(format!( - "invalid guest Python bridge request payload: {error}" - )) - })?; - - let method = PythonVfsRpcMethod::from_wire(&wire.method).ok_or_else(|| { - PythonExecutionError::RpcResponse(format!( - "unsupported agentos python rpc method {} for {}", - wire.method, request.id - )) - })?; - - Ok(PythonVfsRpcRequest { - id: request.id, - method, - path: wire.path, - destination: wire.destination, - target: wire.target, - mode: wire.mode.map(|value| value as u32), - uid: wire.uid.map(|value| value as u32), - gid: wire.gid.map(|value| value as u32), - atime_ms: wire.atime_ms.map(|value| value as u64), - mtime_ms: wire.mtime_ms.map(|value| value as u64), - content_base64: wire.content_base64, - recursive: wire.recursive, - url: wire.url, - http_method: wire.http_method, - headers: wire.headers, - body_base64: wire.body_base64, - hostname: wire.hostname, - family: wire.family, - port: wire.port, - socket_id: wire.socket_id, - command: wire.command, - args: wire.args, - cwd: wire.cwd, - env: wire.env, - shell: wire.shell, - max_buffer: wire.max_buffer, - }) -} - -#[derive(Debug)] -struct PythonOutputBuffer { - bytes: Vec, - max_bytes: usize, -} - -impl PythonOutputBuffer { - fn new(max_bytes: usize) -> Self { - Self { - bytes: Vec::new(), - max_bytes, - } - } - - fn extend(&mut self, chunk: &[u8]) { - if self.bytes.len() >= self.max_bytes { - return; - } - - let remaining = self.max_bytes - self.bytes.len(); - let take = remaining.min(chunk.len()); - self.bytes.extend_from_slice(&chunk[..take]); - } - - fn into_inner(self) -> Vec { - self.bytes - } -} - -fn python_output_buffer_max_bytes(request: &StartPythonExecutionRequest) -> usize { - request - .limits - .output_buffer_max_bytes - .unwrap_or(DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES) -} - -fn python_execution_timeout(request: &StartPythonExecutionRequest) -> Option { - match request.limits.execution_timeout_ms { - // `Some(0)` explicitly disables the timeout. - Some(0) => None, - Some(value) => Some(Duration::from_millis(value)), - None => Some(Duration::from_millis(DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS)), - } -} - -fn python_max_old_space_mb(request: &StartPythonExecutionRequest) -> usize { - request - .limits - .max_old_space_mb - .filter(|value| *value > 0) - .unwrap_or(DEFAULT_PYTHON_MAX_OLD_SPACE_MB) -} - -fn python_vfs_rpc_timeout(request: &StartPythonExecutionRequest) -> Duration { - Duration::from_millis( - request - .limits - .vfs_rpc_timeout_ms - .filter(|value| *value > 0) - .unwrap_or(DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS), - ) -} - -fn spawn_python_vfs_rpc_timeout( - id: u64, - timeout: Duration, - pending: Arc>>, - v8_session: crate::v8_host::V8SessionHandle, -) { - thread::spawn(move || { - thread::sleep(timeout); - let should_timeout = match pending.lock() { - Ok(mut guard) if *guard == Some(PendingVfsRpcState::Pending(id)) => { - *guard = Some(PendingVfsRpcState::TimedOut(id)); - true - } - Ok(_) => false, - Err(_) => false, - }; - - if !should_timeout { - return; - } - - let _ = v8_session.send_bridge_response( - id, - 1, - format!( - "ERR_AGENTOS_PYTHON_VFS_RPC_TIMEOUT: guest Python VFS RPC request {id} timed out after {}ms", - timeout.as_millis() - ) - .into_bytes(), - ); - }); -} - -fn resolved_pyodide_dist_path(path: &Path, cwd: &Path) -> PathBuf { - resolve_execution_path(path, cwd) -} - -fn prewarm_python_path( - import_cache: &NodeImportCache, - javascript_engine: &mut JavascriptExecutionEngine, - javascript_context_id: &str, - context: &PythonContext, - request: &StartPythonExecutionRequest, - frozen_time_ms: u128, -) -> Result>, PythonExecutionError> { - let debug_enabled = python_warmup_metrics_enabled(request); - let marker_contents = warmup_marker_contents(import_cache, context, request); - let marker_path = warmup_marker_path( - import_cache.prewarm_marker_dir(), - "python-runner-prewarm", - PYTHON_WARMUP_MARKER_VERSION, - &marker_contents, - ); - let marker_exists = marker_path.exists(); - - let started = Instant::now(); - let mut prewarm_execution = start_python_javascript_execution( - javascript_engine, - import_cache, - javascript_context_id, - context, - request, - PythonJavascriptExecutionOptions { - frozen_time_ms, - prewarm_only: true, - warmup_metrics: None, - }, - )?; - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut sync_rpc_log = Vec::new(); - let result = loop { - match prewarm_execution - .poll_event_blocking(PYTHON_PREWARM_TIMEOUT) - .map_err(map_javascript_error)? - { - Some(JavascriptExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(JavascriptExecutionEvent::Stderr(chunk)) => stderr.extend(chunk), - Some(JavascriptExecutionEvent::Exited(exit_code)) => { - break PythonExecutionResult { - execution_id: String::from("python-prewarm"), - exit_code, - stdout, - stderr, - }; - } - Some(JavascriptExecutionEvent::SignalState { .. }) => {} - Some(JavascriptExecutionEvent::SyncRpcRequest(sync_request)) => { - sync_rpc_log.push(format!( - "{} {} {:?}", - sync_request.id, sync_request.method, sync_request.args - )); - // The Python runner module imports node builtins and the pyodide - // ESM entry; module-resolution sync RPCs are now serviced - // host-directly here (the prewarm has no kernel/service loop), - // using the execution's own translator (with pyodide path - // mappings) so the runner module loader resolves correctly. - if prewarm_execution - .try_service_standalone_module_sync_rpc(&sync_request) - .map_err(map_javascript_error)? - { - sync_rpc_log.push(format!("responded {} (module)", sync_request.id)); - continue; - } - let pyodide_dist_path = - resolved_pyodide_dist_path(&context.pyodide_dist_path, &request.cwd); - if let Some(action) = - python_javascript_sync_rpc_action(&pyodide_dist_path, &sync_request)? - { - respond_python_javascript_sync_rpc_action( - &mut prewarm_execution, - sync_request.id, - action, - )?; - sync_rpc_log.push(format!("responded {}", sync_request.id)); - continue; - } - if let Some((code, message)) = python_javascript_sync_rpc_error(&sync_request) { - prewarm_execution - .respond_sync_rpc_error(sync_request.id, code, message) - .map_err(map_javascript_error)?; - sync_rpc_log.push(format!("errored {}", sync_request.id)); - continue; - } - if sync_request.method == "_pythonRpc" { - let request = parse_python_bridge_sync_rpc_request(&sync_request)?; - return Err(PythonExecutionError::WarmupFailed { - exit_code: 1, - stderr: format!( - "unexpected Python prewarm VFS RPC request {} {} {:?}", - request.id, request.path, request.method - ), - }); - } - return Err(PythonExecutionError::WarmupFailed { - exit_code: 1, - stderr: format!( - "unexpected Python prewarm JavaScript sync RPC request {} {} {:?}", - sync_request.id, sync_request.method, sync_request.args - ), - }); - } - None => { - return Err(PythonExecutionError::WarmupFailed { - exit_code: 1, - stderr: format!( - "python prewarm timed out after {}s\nstdout:\n{}\nstderr:\n{}\nsync rpc:\n{}", - PYTHON_PREWARM_TIMEOUT.as_secs(), - String::from_utf8_lossy(&stdout), - String::from_utf8_lossy(&stderr), - sync_rpc_log.join("\n"), - ), - }); - } - } - }; - let duration_ms = started.elapsed().as_secs_f64() * 1000.0; - - if result.exit_code != 0 { - return Err(PythonExecutionError::WarmupFailed { - exit_code: result.exit_code, - stderr: String::from_utf8_lossy(&result.stderr).into_owned(), - }); - } - - if marker_exists { - return Ok(warmup_metrics_line( - debug_enabled, - false, - "cached", - 0.0, - import_cache, - context, - request, - )); - } - - fs::write(&marker_path, marker_contents).map_err(PythonExecutionError::PrepareWarmPath)?; - Ok(warmup_metrics_line( - debug_enabled, - true, - "executed", - duration_ms, - import_cache, - context, - request, - )) -} - -enum PythonJavascriptSyncRpcAction { - Success(Value), - Error { code: &'static str, message: String }, -} - -fn python_javascript_sync_rpc_action( - pyodide_dist_path: &Path, - request: &JavascriptSyncRpcRequest, -) -> Result, PythonExecutionError> { - let Some(path) = request.args.first().and_then(Value::as_str) else { - return Ok(None); - }; - let path_kind = python_managed_path_kind(pyodide_dist_path, path); - let Some(host_path) = path_kind.host_path() else { - return Ok(None); - }; - - Ok(Some(match request.method.as_str() { - "fs.promises.readFile" | "fs.readFileSync" => { - let bytes = match fs::read(&host_path) { - Ok(bytes) => bytes, - Err(error) => { - return python_sync_rpc_fs_action_error(path, "open", error).map(Some); - } - }; - let encoding = python_prewarm_sync_rpc_encoding(&request.args); - match encoding.as_deref() { - Some("utf8") | Some("utf-8") => PythonJavascriptSyncRpcAction::Success( - Value::String(String::from_utf8_lossy(&bytes).into_owned()), - ), - _ => PythonJavascriptSyncRpcAction::Success(json!({ - "__agentOSType": "bytes", - "base64": v8_runtime::base64_encode_pub(&bytes), - })), - } - } - "fs.statSync" | "fs.promises.stat" => match fs::metadata(&host_path) { - Ok(metadata) => { - PythonJavascriptSyncRpcAction::Success(python_host_stat_value(&metadata)) - } - Err(error) => return python_sync_rpc_fs_action_error(path, "stat", error).map(Some), - }, - "fs.lstatSync" | "fs.promises.lstat" => match fs::symlink_metadata(&host_path) { - Ok(metadata) => { - PythonJavascriptSyncRpcAction::Success(python_host_stat_value(&metadata)) - } - Err(error) => return python_sync_rpc_fs_action_error(path, "lstat", error).map(Some), - }, - "fs.existsSync" => PythonJavascriptSyncRpcAction::Success(Value::Bool(host_path.exists())), - "fs.accessSync" | "fs.promises.access" => match fs::metadata(&host_path) { - Ok(_) => PythonJavascriptSyncRpcAction::Success(Value::Null), - Err(error) => return python_sync_rpc_fs_action_error(path, "access", error).map(Some), - }, - "fs.readdirSync" | "fs.promises.readdir" => match fs::read_dir(&host_path) { - Ok(entries) => PythonJavascriptSyncRpcAction::Success(python_readdir_value( - entries - .filter_map(|entry| entry.ok()) - .filter_map(|entry| entry.file_name().into_string().ok()) - .collect(), - )), - Err(error) => return python_sync_rpc_fs_action_error(path, "scandir", error).map(Some), - }, - "fs.mkdirSync" | "fs.promises.mkdir" => { - let recursive = python_sync_rpc_recursive_flag(&request.args); - if recursive { - fs::create_dir_all(&host_path).map_err(PythonExecutionError::PrepareRuntime)?; - } else { - match fs::create_dir(&host_path) { - Ok(()) => {} - Err(error) => { - return python_sync_rpc_fs_action_error(path, "mkdir", error).map(Some); - } - } - } - PythonJavascriptSyncRpcAction::Success(Value::Null) - } - "fs.writeFileSync" | "fs.promises.writeFile" => { - let contents = python_sync_rpc_bytes_arg(&request.args, 1)?; - if let Some(parent) = host_path.parent() { - fs::create_dir_all(parent).map_err(PythonExecutionError::PrepareRuntime)?; - } - fs::write(&host_path, contents).map_err(PythonExecutionError::PrepareRuntime)?; - PythonJavascriptSyncRpcAction::Success(Value::Null) - } - "fs.realpathSync" | "fs.realpathSync.native" => match fs::canonicalize(&host_path) { - Ok(canonical) => PythonJavascriptSyncRpcAction::Success(Value::String( - path_kind.render_path(pyodide_dist_path, &canonical, path), - )), - Err(error) => { - return python_sync_rpc_fs_action_error(path, "realpath", error).map(Some); - } - }, - _ => return Ok(None), - })) -} - -fn python_sync_rpc_fs_action_error( - path: &str, - syscall: &str, - error: std::io::Error, -) -> Result { - let action = match error.kind() { - std::io::ErrorKind::NotFound => PythonJavascriptSyncRpcAction::Error { - code: "ENOENT", - message: format!("ENOENT: no such file or directory, {syscall} '{path}'"), - }, - std::io::ErrorKind::AlreadyExists => PythonJavascriptSyncRpcAction::Error { - code: "EEXIST", - message: format!("EEXIST: file already exists, {syscall} '{path}'"), - }, - std::io::ErrorKind::PermissionDenied => PythonJavascriptSyncRpcAction::Error { - code: "EACCES", - message: format!("EACCES: permission denied, {syscall} '{path}'"), - }, - _ => { - return Err(PythonExecutionError::PrepareRuntime(std::io::Error::new( - error.kind(), - error.to_string(), - ))); - } - }; - Ok(action) -} - -fn respond_python_javascript_sync_rpc_action( - execution: &mut JavascriptExecution, - id: u64, - action: PythonJavascriptSyncRpcAction, -) -> Result<(), PythonExecutionError> { - match action { - PythonJavascriptSyncRpcAction::Success(value) => execution - .respond_sync_rpc_success(id, value) - .map_err(map_javascript_error), - PythonJavascriptSyncRpcAction::Error { code, message } => execution - .respond_sync_rpc_error(id, code, message) - .map_err(map_javascript_error), - } -} - -#[derive(Debug, Clone)] -enum PythonManagedPathKind { - GuestPyodide, - GuestCache, - HostManaged, - Unmanaged, -} - -impl PythonManagedPathKind { - fn render_path(&self, pyodide_dist_path: &Path, canonical: &Path, original: &str) -> String { - match self { - Self::GuestPyodide | Self::GuestCache => { - python_host_path_to_guest(pyodide_dist_path, canonical) - .unwrap_or_else(|| original.to_owned()) - } - Self::HostManaged => canonical.display().to_string(), - Self::Unmanaged => original.to_owned(), - } - } -} - -fn python_managed_path_kind(pyodide_dist_path: &Path, path: &str) -> PythonManagedResolvedPath { - let cache_path = pyodide_cache_path(pyodide_dist_path); - - if let Some(normalized) = strip_guest_managed_root(path, PYODIDE_GUEST_ROOT) { - let root = canonicalize_existing_or_self(pyodide_dist_path); - let relative = normalize_relative_guest_suffix(normalized); - let host_path = if relative.as_os_str().is_empty() { - root.clone() - } else { - root.join(relative) - }; - if confined_managed_path(&host_path, &root) { - return PythonManagedResolvedPath { - kind: PythonManagedPathKind::GuestPyodide, - host_path: Some(host_path), - }; - } - return PythonManagedResolvedPath { - kind: PythonManagedPathKind::Unmanaged, - host_path: None, - }; - } - - if let Some(normalized) = strip_guest_managed_root(path, PYODIDE_CACHE_GUEST_ROOT) { - let root = canonicalize_existing_or_self(&cache_path); - let relative = normalize_relative_guest_suffix(normalized); - let host_path = if relative.as_os_str().is_empty() { - root.clone() - } else { - root.join(relative) - }; - if confined_managed_path(&host_path, &root) { - return PythonManagedResolvedPath { - kind: PythonManagedPathKind::GuestCache, - host_path: Some(host_path), - }; - } - return PythonManagedResolvedPath { - kind: PythonManagedPathKind::Unmanaged, - host_path: None, - }; - } - - let candidate = PathBuf::from(path); - let pyodide_root = canonicalize_existing_or_self(pyodide_dist_path); - let cache_root = canonicalize_existing_or_self(&cache_path); - if candidate.is_absolute() - && !path_has_parent_or_prefix_component(&candidate) - && confined_managed_path(&candidate, &pyodide_root) - { - return PythonManagedResolvedPath { - kind: PythonManagedPathKind::HostManaged, - host_path: Some(candidate), - }; - } - if candidate.is_absolute() - && !path_has_parent_or_prefix_component(&candidate) - && confined_managed_path(&candidate, &cache_root) - { - return PythonManagedResolvedPath { - kind: PythonManagedPathKind::HostManaged, - host_path: Some(candidate), - }; - } - - PythonManagedResolvedPath { - kind: PythonManagedPathKind::Unmanaged, - host_path: None, - } -} - -#[derive(Debug, Clone)] -struct PythonManagedResolvedPath { - kind: PythonManagedPathKind, - host_path: Option, -} - -impl PythonManagedResolvedPath { - fn host_path(&self) -> Option { - self.host_path.clone() - } - - fn render_path(&self, pyodide_dist_path: &Path, canonical: &Path, original: &str) -> String { - self.kind - .render_path(pyodide_dist_path, canonical, original) - } -} - -fn strip_guest_managed_root<'a>(path: &'a str, root: &str) -> Option<&'a str> { - if path == root { - return Some(""); - } - path.strip_prefix(root)?.strip_prefix('/') -} - -fn normalize_relative_guest_suffix(suffix: &str) -> PathBuf { - let mut normalized = PathBuf::new(); - for segment in suffix.trim_start_matches('/').split('/') { - if segment.is_empty() || segment == "." { - continue; - } - if segment == ".." { - normalized.pop(); - } else { - normalized.push(segment); - } - } - normalized -} - -fn path_has_parent_or_prefix_component(path: &Path) -> bool { - path.components() - .any(|component| matches!(component, Component::ParentDir | Component::Prefix(_))) -} - -fn canonicalize_existing_or_self(path: &Path) -> PathBuf { - fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf()) -} - -fn confined_managed_path(path: &Path, root: &Path) -> bool { - let canonical_root = canonicalize_existing_or_self(root); - let Some(canonical_path) = canonicalize_managed_candidate(path) else { - return false; - }; - - canonical_path == canonical_root || canonical_path.starts_with(canonical_root) -} - -fn canonicalize_managed_candidate(path: &Path) -> Option { - let mut missing_components = Vec::new(); - let mut current = path; - loop { - match fs::canonicalize(current) { - Ok(mut canonical) => { - for component in missing_components.iter().rev() { - canonical.push(component); - } - return Some(canonical); - } - Err(_) => { - let file_name = current.file_name()?.to_owned(); - if Path::new(&file_name) - .components() - .any(|component| !matches!(component, Component::Normal(_))) - { - return None; - } - missing_components.push(file_name); - current = current.parent()?; - } - } - } -} - -fn python_host_path_to_guest(pyodide_dist_path: &Path, host_path: &Path) -> Option { - if let Ok(relative) = host_path.strip_prefix(pyodide_dist_path) { - let suffix = relative.to_string_lossy().replace('\\', "/"); - return Some(if suffix.is_empty() { - String::from(PYODIDE_GUEST_ROOT) - } else { - format!("{PYODIDE_GUEST_ROOT}/{suffix}") - }); - } - - let cache_path = pyodide_cache_path(pyodide_dist_path); - let relative = host_path.strip_prefix(cache_path).ok()?; - let suffix = relative.to_string_lossy().replace('\\', "/"); - Some(if suffix.is_empty() { - String::from(PYODIDE_CACHE_GUEST_ROOT) - } else { - format!("{PYODIDE_CACHE_GUEST_ROOT}/{suffix}") - }) -} - -fn python_host_stat_value(metadata: &fs::Metadata) -> Value { - json!({ - "mode": metadata.mode(), - "size": metadata.size(), - "blocks": metadata.blocks(), - "dev": metadata.dev(), - "rdev": metadata.rdev(), - "isDirectory": metadata.is_dir(), - "isSymbolicLink": metadata.file_type().is_symlink(), - "atimeMs": metadata.atime() * 1000 + (metadata.atime_nsec() / 1_000_000), - "mtimeMs": metadata.mtime() * 1000 + (metadata.mtime_nsec() / 1_000_000), - "ctimeMs": metadata.ctime() * 1000 + (metadata.ctime_nsec() / 1_000_000), - "birthtimeMs": metadata.ctime() * 1000 + (metadata.ctime_nsec() / 1_000_000), - "ino": metadata.ino(), - "nlink": metadata.nlink(), - "uid": metadata.uid(), - "gid": metadata.gid(), - }) -} - -fn python_readdir_value(entries: Vec) -> Value { - json!(entries - .into_iter() - .filter(|entry| entry != "." && entry != "..") - .collect::>()) -} - -fn python_sync_rpc_recursive_flag(args: &[Value]) -> bool { - args.get(1) - .and_then(|value| { - value - .as_bool() - .or_else(|| value.get("recursive").and_then(Value::as_bool)) - }) - .unwrap_or(false) -} - -fn python_sync_rpc_bytes_arg( - args: &[Value], - index: usize, -) -> Result, PythonExecutionError> { - let Some(value) = args.get(index) else { - return Err(PythonExecutionError::RpcResponse(format!( - "sync RPC argument {index} is required" - ))); - }; - - if let Some(text) = value.as_str() { - return Ok(text.as_bytes().to_vec()); - } - - let Some(base64_value) = value - .get("__agentOSType") - .and_then(Value::as_str) - .filter(|kind| *kind == "bytes") - .and_then(|_| value.get("base64")) - .and_then(Value::as_str) - else { - return Err(PythonExecutionError::RpcResponse(format!( - "sync RPC argument {index} must be a string or encoded bytes payload" - ))); - }; - - base64::engine::general_purpose::STANDARD - .decode(base64_value) - .map_err(|error| { - PythonExecutionError::RpcResponse(format!( - "sync RPC argument {index} contains invalid base64: {error}" - )) - }) -} - -fn python_prewarm_sync_rpc_encoding(args: &[Value]) -> Option { - args.get(1).and_then(|value| { - value.as_str().map(str::to_owned).or_else(|| { - value - .get("encoding") - .and_then(Value::as_str) - .map(str::to_owned) - }) - }) -} - -fn python_javascript_sync_rpc_error( - request: &JavascriptSyncRpcRequest, -) -> Option<(&'static str, String)> { - if matches!( - request.method.as_str(), - "net.connect" - | "net.createConnection" - | "dns.lookup" - | "dns.resolve" - | "dns.resolve4" - | "dns.resolve6" - | "dns.reverse" - | "dgram.send" - | "http.request" - | "https.request" - | "tls.connect" - ) { - return Some(( - "ERR_ACCESS_DENIED", - String::from( - "network access is not available during standalone guest Python execution", - ), - )); - } - - None -} - -fn warmup_marker_contents( - import_cache: &NodeImportCache, - context: &PythonContext, - request: &StartPythonExecutionRequest, -) -> String { - let pyodide_dist_path = resolved_pyodide_dist_path(&context.pyodide_dist_path, &request.cwd); - let compile_cache_dir = import_cache.shared_compile_cache_dir(); - - [ - env!("CARGO_PKG_NAME").to_string(), - env!("CARGO_PKG_VERSION").to_string(), - PYTHON_WARMUP_MARKER_VERSION.to_string(), - String::from("secure-exec-v8"), - python_max_old_space_mb(request).to_string(), - compile_cache_dir.display().to_string(), - pyodide_dist_path.display().to_string(), - file_fingerprint(&pyodide_dist_path.join("pyodide.mjs")), - file_fingerprint(&pyodide_dist_path.join("pyodide-lock.json")), - file_fingerprint(&pyodide_dist_path.join("pyodide.asm.js")), - file_fingerprint(&pyodide_dist_path.join("pyodide.asm.wasm")), - file_fingerprint(&pyodide_dist_path.join("python_stdlib.zip")), - ] - .join("\n") -} - -fn python_warmup_metrics_enabled(request: &StartPythonExecutionRequest) -> bool { - env_flag_enabled(&request.env, PYTHON_WARMUP_DEBUG_ENV) -} - -fn warmup_metrics_line( - debug_enabled: bool, - executed: bool, - reason: &str, - duration_ms: f64, - import_cache: &NodeImportCache, - context: &PythonContext, - request: &StartPythonExecutionRequest, -) -> Option> { - if !debug_enabled { - return None; - } - - let compile_cache_dir = import_cache.shared_compile_cache_dir(); - let pyodide_dist_path = resolved_pyodide_dist_path(&context.pyodide_dist_path, &request.cwd); - - Some( - format!( - "{PYTHON_WARMUP_METRICS_PREFIX}{{\"phase\":\"prewarm\",\"executed\":{},\"reason\":{},\"durationMs\":{duration_ms:.3},\"heapLimitMb\":{},\"compileCacheDir\":{},\"pyodideDistPath\":{}}}\n", - if executed { "true" } else { "false" }, - encode_json_string(reason), - python_max_old_space_mb(request), - encode_json_string(&compile_cache_dir.display().to_string()), - encode_json_string(&pyodide_dist_path.display().to_string()), - ) - .into_bytes(), - ) -} - -#[cfg(test)] -mod tests { - use super::{ - python_managed_path_kind, PythonManagedPathKind, PYODIDE_CACHE_GUEST_ROOT, - PYODIDE_GUEST_ROOT, - }; - use std::fs; - #[cfg(unix)] - use std::os::unix::fs::symlink; - use tempfile::tempdir; - - #[test] - fn python_managed_guest_paths_normalize_dot_dot_inside_root() { - let temp = tempdir().expect("create temp dir"); - let pyodide = temp.path().join("pyodide"); - fs::create_dir_all(pyodide.join("lib")).expect("create pyodide lib"); - - let resolved = python_managed_path_kind( - &pyodide, - &format!("{PYODIDE_GUEST_ROOT}/lib/../pyodide.mjs"), - ); - - assert!(matches!(resolved.kind, PythonManagedPathKind::GuestPyodide)); - assert_eq!( - resolved.host_path().expect("host path"), - pyodide.join("pyodide.mjs") - ); - } - - #[test] - fn python_managed_guest_paths_clamp_dot_dot_escape_to_root() { - let temp = tempdir().expect("create temp dir"); - let pyodide = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide).expect("create pyodide root"); - - let resolved = - python_managed_path_kind(&pyodide, &format!("{PYODIDE_GUEST_ROOT}/../../outside.txt")); - - assert!(matches!(resolved.kind, PythonManagedPathKind::GuestPyodide)); - assert_eq!( - resolved.host_path().expect("host path"), - pyodide.join("outside.txt") - ); - } - - #[cfg(unix)] - #[test] - fn python_managed_guest_paths_reject_symlink_escape() { - let temp = tempdir().expect("create temp dir"); - let pyodide = temp.path().join("pyodide"); - let outside = temp.path().join("outside"); - fs::create_dir_all(&pyodide).expect("create pyodide root"); - fs::create_dir_all(&outside).expect("create outside dir"); - symlink(&outside, pyodide.join("escape")).expect("create escape symlink"); - - let resolved = - python_managed_path_kind(&pyodide, &format!("{PYODIDE_GUEST_ROOT}/escape/file.txt")); - - assert!(matches!(resolved.kind, PythonManagedPathKind::Unmanaged)); - assert!(resolved.host_path().is_none()); - } - - #[cfg(unix)] - #[test] - fn python_managed_guest_paths_reject_symlink_escape_to_missing_descendant() { - let temp = tempdir().expect("create temp dir"); - let pyodide = temp.path().join("pyodide"); - let outside = temp.path().join("outside"); - fs::create_dir_all(&pyodide).expect("create pyodide root"); - fs::create_dir_all(&outside).expect("create outside dir"); - symlink(&outside, pyodide.join("escape")).expect("create escape symlink"); - - let resolved = python_managed_path_kind( - &pyodide, - &format!("{PYODIDE_GUEST_ROOT}/escape/missing/file.txt"), - ); - - assert!(matches!(resolved.kind, PythonManagedPathKind::Unmanaged)); - assert!(resolved.host_path().is_none()); - } - - #[test] - fn python_managed_host_paths_accept_canonical_root_descendants() { - let temp = tempdir().expect("create temp dir"); - let pyodide = temp.path().join("pyodide"); - fs::create_dir_all(pyodide.join("pkg")).expect("create pyodide package dir"); - let candidate = pyodide.join("pkg/module.py"); - - let resolved = python_managed_path_kind(&pyodide, &candidate.display().to_string()); - - assert!(matches!(resolved.kind, PythonManagedPathKind::HostManaged)); - assert_eq!(resolved.host_path().expect("host path"), candidate); - } - - #[test] - fn python_managed_host_paths_reject_unresolved_dot_dot_escape() { - let temp = tempdir().expect("create temp dir"); - let pyodide = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide).expect("create pyodide root"); - let candidate = pyodide.join("missing/../../outside.txt"); - - let resolved = python_managed_path_kind(&pyodide, &candidate.display().to_string()); - - assert!(matches!(resolved.kind, PythonManagedPathKind::Unmanaged)); - assert!(resolved.host_path().is_none()); - } - - #[test] - fn python_managed_cache_guest_paths_resolve_inside_cache_root() { - let temp = tempdir().expect("create temp dir"); - let pyodide = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide).expect("create pyodide root"); - - let resolved = python_managed_path_kind( - &pyodide, - &format!("{PYODIDE_CACHE_GUEST_ROOT}/wheels/pkg.whl"), - ); - let host_path = resolved.host_path().expect("host path"); - - assert!(matches!(resolved.kind, PythonManagedPathKind::GuestCache)); - assert!(host_path.ends_with("pyodide-package-cache/wheels/pkg.whl")); - } -} diff --git a/crates/execution/src/runtime_support.rs b/crates/execution/src/runtime_support.rs deleted file mode 100644 index cf9ea2fd6..000000000 --- a/crates/execution/src/runtime_support.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::common::stable_hash64; -use std::collections::BTreeMap; -use std::fs; -use std::os::unix::fs::MetadataExt; -use std::path::{Path, PathBuf}; - -pub(crate) const NODE_COMPILE_CACHE_ENV: &str = "NODE_COMPILE_CACHE"; -pub(crate) const NODE_DISABLE_COMPILE_CACHE_ENV: &str = "NODE_DISABLE_COMPILE_CACHE"; -pub(crate) const NODE_FROZEN_TIME_ENV: &str = "AGENTOS_FROZEN_TIME_MS"; -pub(crate) const NODE_SANDBOX_ROOT_ENV: &str = "AGENTOS_SANDBOX_ROOT"; - -pub(crate) fn env_flag_enabled(env: &BTreeMap, key: &str) -> bool { - env.get(key).is_some_and(|value| value == "1") -} - -pub(crate) fn resolve_execution_path(path: &Path, cwd: &Path) -> PathBuf { - if path.is_absolute() { - path.to_path_buf() - } else { - cwd.join(path) - } -} - -pub(crate) fn warmup_marker_path( - marker_dir: &Path, - prefix: &str, - version: &str, - contents: &str, -) -> PathBuf { - marker_dir.join(format!( - "{prefix}-v{version}-{:016x}.stamp", - stable_hash64(contents.as_bytes()) - )) -} - -pub(crate) fn file_fingerprint(path: &Path) -> String { - match fs::metadata(path) { - Ok(metadata) => format!( - "{}:{}:{}:{}:{}", - metadata.dev(), - metadata.ino(), - metadata.size(), - metadata.mtime(), - metadata.mtime_nsec(), - ), - Err(_) => String::from("missing"), - } -} - -#[cfg(test)] -mod tests { - use super::file_fingerprint; - use std::fs; - use std::os::unix::fs::MetadataExt; - use tempfile::tempdir; - - #[test] - fn file_fingerprint_tracks_inode_and_mutation_time() { - let temp = tempdir().expect("create temp dir"); - let path = temp.path().join("module.wasm"); - - fs::write(&path, b"first").expect("write wasm file"); - let metadata = fs::metadata(&path).expect("stat wasm file"); - let first = file_fingerprint(&path); - - assert_eq!( - first, - format!( - "{}:{}:{}:{}:{}", - metadata.dev(), - metadata.ino(), - metadata.size(), - metadata.mtime(), - metadata.mtime_nsec(), - ) - ); - - std::thread::sleep(std::time::Duration::from_millis(25)); - fs::write(&path, b"second").expect("overwrite wasm file"); - - assert_ne!( - file_fingerprint(&path), - first, - "rewriting a tracked asset in place must invalidate warmup markers" - ); - } -} diff --git a/crates/execution/src/signal.rs b/crates/execution/src/signal.rs deleted file mode 100644 index 4a739f674..000000000 --- a/crates/execution/src/signal.rs +++ /dev/null @@ -1,17 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum NodeSignalDispositionAction { - Default, - Ignore, - User, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct NodeSignalHandlerRegistration { - pub action: NodeSignalDispositionAction, - pub mask: Vec, - pub flags: u32, -} diff --git a/crates/execution/src/v8_host.rs b/crates/execution/src/v8_host.rs deleted file mode 100644 index 40934bed6..000000000 --- a/crates/execution/src/v8_host.rs +++ /dev/null @@ -1,502 +0,0 @@ -//! V8 runtime host — manages a shared embedded V8 runtime with session multiplexing. - -use crate::v8_ipc::{self, BinaryFrame}; -use secure_exec_bridge::queue_tracker::{tracked_sync_channel, TrackedLimit, TrackedReceiver}; -use secure_exec_v8_runtime::embedded_runtime::{ - shared_embedded_runtime, EmbeddedV8Runtime, EmbeddedV8SessionHandle, -}; -use secure_exec_v8_runtime::runtime_protocol::{RuntimeCommand, RuntimeEvent, WarmSessionHint}; -use std::io::{self, Cursor}; -use std::sync::{Arc, OnceLock}; -use std::thread; - -const V8_SESSION_FRAME_CHANNEL_CAPACITY: usize = 1024; - -/// V8 polyfill bridge code generated by `build.rs`. -const V8_BRIDGE_CODE: &str = concat!( - include_str!(concat!(env!("OUT_DIR"), "/v8-bridge.js")), - "\n", - include_str!(concat!(env!("OUT_DIR"), "/v8-bridge-zlib.js")) -); - -/// Manages an embedded V8 runtime with session multiplexing. -pub struct V8RuntimeHost { - shared: Arc, -} - -struct SharedEmbeddedRuntimeClient { - runtime: Arc, -} - -impl V8RuntimeHost { - /// Connect to the process-global embedded V8 runtime client. - pub fn spawn() -> io::Result { - Ok(V8RuntimeHost { - shared: shared_embedded_runtime_client()?, - }) - } - - /// Register a session and return a receiver for its frames. - pub fn register_session(&self, session_id: &str) -> io::Result> { - let (runtime_receiver, registration) = self - .shared - .runtime - .register_session_with_output_registration(session_id)?; - let (sender, receiver) = tracked_sync_channel( - TrackedLimit::V8SessionFrames, - V8_SESSION_FRAME_CHANNEL_CAPACITY, - ); - let thread_name = format!("secure-exec-v8-session-{session_id}"); - let runtime = Arc::clone(&self.shared.runtime); - let runtime_for_thread = Arc::clone(&runtime); - - let spawn_result = thread::Builder::new().name(thread_name).spawn(move || { - while let Ok(frame) = runtime_receiver.recv() { - // Apply backpressure instead of destroying the session when - // the downstream consumer is slow. This thread is dedicated - // to one session, so a blocking send safely parks it — and, - // in turn, backpressures the V8 runtime — until a slot frees. - // Previously a `try_send` that hit the full channel called - // destroy_session_if_output_current(), tearing the session - // down on a transient backlog (the same anti-pattern fixed - // for the event/stdout queues). Only a dropped receiver - // (the consumer is gone for good) is terminal. - if sender.send(from_runtime_event(frame)).is_err() { - let _ = runtime_for_thread.destroy_session_if_output_current(®istration); - break; - } - } - }); - if let Err(error) = spawn_result { - runtime.unregister_session(session_id); - return Err(error); - } - - Ok(receiver) - } - - /// Unregister a session. - pub fn unregister_session(&self, session_id: &str) { - self.shared.runtime.unregister_session(session_id); - } - - pub fn create_session( - &self, - session_id: String, - heap_limit_mb: u32, - cpu_time_limit_ms: u32, - wall_clock_limit_ms: u32, - warm_hint: Option, - ) -> io::Result<()> { - self.shared.runtime.dispatch(RuntimeCommand::CreateSession { - session_id, - heap_limit_mb: non_zero_option(heap_limit_mb), - cpu_time_limit_ms: non_zero_option(cpu_time_limit_ms), - wall_clock_limit_ms: non_zero_option(wall_clock_limit_ms), - warm_hint, - }) - } - - pub fn create_session_from_command(&self, command: RuntimeCommand) -> io::Result<()> { - self.shared.runtime.dispatch(command) - } - - /// Send a frame to the V8 runtime. - pub fn send_frame(&self, frame: &BinaryFrame) -> io::Result<()> { - self.shared.runtime.dispatch(to_runtime_command(frame)?) - } - - /// Get the pre-bundled bridge code (polyfills). - pub fn bridge_code() -> &'static str { - V8_BRIDGE_CODE - } - - /// Pre-build the per-sidecar snapshot for an agent-SDK `userland_code` bundle - /// into the process-wide cache, so the FIRST session that uses it is already - /// warm (no cold-build penalty on the session-create path). Blocks until the - /// snapshot is built; idempotent (a cache hit returns immediately). A no-op for - /// empty `userland_code`. - pub fn pre_warm_snapshot(&self, userland_code: &str) -> io::Result<()> { - if userland_code.is_empty() { - return Ok(()); - } - self.shared.runtime.dispatch(RuntimeCommand::WarmSnapshot { - bridge_code: Self::bridge_code().to_owned(), - userland_code: userland_code.to_owned(), - }) - } - - pub fn pre_warm_workers(&self, userland_code: &str, heap_limit_mb: u32, count: usize) { - self.shared.runtime.pre_warm_workers( - Self::bridge_code().to_owned(), - userland_code.to_owned(), - non_zero_option(heap_limit_mb), - count, - ); - } - - pub fn seed_default_warm_workers_async(&self) { - static DEFAULT_WARM_STARTED: OnceLock<()> = OnceLock::new(); - let runtime = Arc::clone(&self.shared.runtime); - let _ = DEFAULT_WARM_STARTED.get_or_init(|| { - let _ = thread::Builder::new() - .name(String::from("secure-exec-v8-default-warm")) - .spawn(move || { - runtime.pre_warm_workers( - V8_BRIDGE_CODE.to_owned(), - String::new(), - None, - warm_worker_count(), - ); - }); - }); - } - - /// True when the process-wide snapshot cache already has this userland - /// bundle. This is a lookup only; it never creates a snapshot. - pub fn snapshot_ready(&self, userland_code: &str) -> bool { - self.shared - .runtime - .snapshot_ready(Self::bridge_code(), userland_code) - } - - /// Kick a process-wide async warm for the wasm runner snapshot. At most one - /// warm thread is spawned per process; blocking callers should use - /// [`pre_warm_snapshot`](Self::pre_warm_snapshot). - pub fn warm_snapshot_async(userland_code: String) { - if userland_code.is_empty() { - return; - } - static WASM_RUNNER_WARM_STARTED: OnceLock<()> = OnceLock::new(); - let _ = WASM_RUNNER_WARM_STARTED.get_or_init(|| { - let _ = thread::Builder::new() - .name(String::from("secure-exec-wasm-snapshot-warm")) - .spawn(move || { - let Ok(host) = V8RuntimeHost::spawn() else { - return; - }; - if let Err(error) = host.pre_warm_snapshot(&userland_code) { - eprintln!( - "secure-exec-v8-runtime: wasm runner snapshot warm failed: {error}" - ); - } - }); - }); - } - - /// Create a session handle for sending session-scoped frames and cleanup. - pub fn session_handle(&self, session_id: String) -> V8SessionHandle { - V8SessionHandle::new(session_id, Arc::clone(&self.shared.runtime)) - } - - pub fn child_pid(&self) -> u32 { - 0 - } - - pub fn is_alive(&mut self) -> io::Result { - Ok(self.shared.runtime.is_alive()) - } - - #[cfg(test)] - fn runtime_ptr(&self) -> usize { - Arc::as_ptr(&self.shared.runtime) as usize - } -} - -fn non_zero_option(value: u32) -> Option { - (value > 0).then_some(value) -} - -fn warm_worker_count() -> usize { - std::env::var("AGENTOS_V8_WARM_ISOLATES") - .ok() - .and_then(|value| value.parse::().ok()) - .unwrap_or(2) -} - -/// A handle to a single V8 session within the shared runtime. -/// Provides methods for sending frames specific to this session. -pub struct V8SessionHandle { - inner: EmbeddedV8SessionHandle, -} - -impl std::fmt::Debug for V8SessionHandle { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("V8SessionHandle") - .field("session_id", &self.inner.session_id()) - .finish() - } -} - -impl V8SessionHandle { - pub fn new(session_id: String, runtime: Arc) -> Self { - Self { - inner: runtime.session_handle(session_id), - } - } - - /// Send a bridge response back to the V8 isolate. - pub fn send_bridge_response( - &self, - call_id: u64, - status: u8, - payload: Vec, - ) -> io::Result<()> { - self.inner.send_bridge_response(call_id, status, payload) - } - - /// Send a stream event to the V8 isolate (stdin data, timer, etc.). - pub fn send_stream_event(&self, event_type: &str, payload: Vec) -> io::Result<()> { - self.inner.send_stream_event(event_type, payload) - } - - /// Install a direct module-source reader on this session's V8 thread so module - /// loads read source directly instead of round-tripping the bridge. - pub fn set_module_reader( - &self, - reader: Box, - ) -> io::Result<()> { - self.inner.set_module_reader(reader) - } - - /// Execute bridge code + user code in this V8 session without routing through - /// the legacy binary frame encode/decode path. - #[allow(clippy::too_many_arguments)] // mirrors the CreateSession frame - pub fn execute( - &self, - mode: u8, - file_path: String, - bridge_code: String, - post_restore_script: String, - userland_code: String, - high_resolution_time: bool, - user_code: String, - wasm_module_bytes: Option>>, - ) -> io::Result<()> { - self.inner.execute( - mode, - file_path, - bridge_code, - post_restore_script, - userland_code, - high_resolution_time, - user_code, - wasm_module_bytes, - ) - } - - /// Terminate execution in this session. - pub fn terminate(&self) -> io::Result<()> { - self.inner.terminate() - } - - /// Destroy this session in the embedded runtime and remove its receiver. - pub fn destroy(&self) -> io::Result<()> { - let _ = self.inner.terminate(); - self.inner.destroy() - } - - pub fn session_id(&self) -> &str { - self.inner.session_id() - } -} - -impl Clone for V8SessionHandle { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - } - } -} - -/// Pre-build the per-sidecar snapshot for an agent-SDK `userland_code` bundle into -/// the process-wide cache, so the FIRST session that uses it is already warm. Uses -/// the shared embedded runtime directly (no per-call host lifecycle). Blocks until -/// built; idempotent (cache hit returns immediately); no-op for empty input. -/// Eagerly initialize the process-wide embedded V8 runtime (and the V8 platform) -/// on the calling thread. Call this once on a long-lived thread (the sidecar main -/// thread) at startup so V8 is NOT first initialized on a transient worker thread -/// (e.g. a VM-create pre-warm thread that then exits, which corrupts the platform). -pub fn ensure_runtime_initialized() -> io::Result<()> { - shared_embedded_runtime_client().map(|_| ()) -} - -pub fn pre_warm_agent_snapshot(userland_code: &str) -> io::Result<()> { - if userland_code.is_empty() { - return Ok(()); - } - let userland = userland_code.to_owned(); - // Build the SnapshotCreator on a dedicated, fully-joined std::thread rather than - // the caller's (tokio blocking-pool) thread. V8 SnapshotCreator isolates are - // thread-sensitive; a reused pool thread leaves per-thread V8 state that corrupts - // later isolate creation. A spawned+joined thread tears down cleanly, mirroring - // how per-session snapshot builds run on their own dedicated session threads. - let handle = std::thread::Builder::new() - .name("agentos-snapshot-prewarm".to_owned()) - .spawn(move || -> io::Result<()> { - let client = shared_embedded_runtime_client()?; - client.runtime.dispatch(RuntimeCommand::WarmSnapshot { - bridge_code: V8_BRIDGE_CODE.to_owned(), - userland_code: userland, - }) - })?; - handle - .join() - .map_err(|_| io::Error::other("snapshot pre-warm thread panicked"))? -} - -fn shared_embedded_runtime_client() -> io::Result> { - static SHARED_RUNTIME: OnceLock> = OnceLock::new(); - static SHARED_RUNTIME_INIT_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(()); - - if let Some(shared) = SHARED_RUNTIME.get() { - return Ok(Arc::clone(shared)); - } - - let _guard = SHARED_RUNTIME_INIT_LOCK - .lock() - .expect("shared embedded runtime init lock poisoned"); - if let Some(shared) = SHARED_RUNTIME.get() { - return Ok(Arc::clone(shared)); - } - - let shared = Arc::new(SharedEmbeddedRuntimeClient { - runtime: shared_embedded_runtime()?, - }); - let _ = SHARED_RUNTIME.set(Arc::clone(&shared)); - Ok(shared) -} - -fn to_runtime_command(frame: &BinaryFrame) -> io::Result { - let bytes = v8_ipc::encode_frame(frame)?; - let runtime_frame = secure_exec_v8_runtime::ipc_binary::read_frame(&mut Cursor::new(bytes))?; - RuntimeCommand::try_from(runtime_frame) -} - -fn from_runtime_event(event: RuntimeEvent) -> BinaryFrame { - match event { - RuntimeEvent::BridgeCall { - session_id, - call_id, - method, - payload, - } => BinaryFrame::BridgeCall { - session_id, - call_id, - method, - payload, - }, - RuntimeEvent::ExecutionResult { - session_id, - exit_code, - exports, - error, - } => BinaryFrame::ExecutionResult { - session_id, - exit_code, - exports, - error: error.map(from_runtime_execution_error), - }, - RuntimeEvent::Log { - session_id, - channel, - message, - } => BinaryFrame::Log { - session_id, - channel, - message, - }, - RuntimeEvent::StreamCallback { - session_id, - callback_type, - payload, - } => BinaryFrame::StreamCallback { - session_id, - callback_type, - payload, - }, - } -} - -fn from_runtime_execution_error( - error: secure_exec_v8_runtime::ipc_binary::ExecutionErrorBin, -) -> v8_ipc::ExecutionErrorBin { - v8_ipc::ExecutionErrorBin { - error_type: error.error_type, - message: error.message, - stack: error.stack, - code: error.code, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::sync::atomic::{AtomicU64, Ordering}; - - static NEXT_TEST_SESSION_ID: AtomicU64 = AtomicU64::new(1); - - fn next_session_id() -> String { - format!( - "embedded-runtime-host-{}", - NEXT_TEST_SESSION_ID.fetch_add(1, Ordering::Relaxed) - ) - } - - #[test] - fn embedded_runtime_host_reuses_shared_runtime_service() { - let first = V8RuntimeHost::spawn().expect("spawn V8 runtime host"); - let second = V8RuntimeHost::spawn().expect("spawn V8 runtime host"); - assert_eq!( - first.runtime_ptr(), - second.runtime_ptr(), - "V8 runtime hosts should reuse the same embedded runtime service" - ); - } - - #[test] - fn embedded_runtime_host_create_destroy_recycles_session_ids() { - let host = V8RuntimeHost::spawn().expect("spawn V8 runtime host"); - let session_id = next_session_id(); - - let _first_receiver = host - .register_session(&session_id) - .expect("register session output"); - host.send_frame(&BinaryFrame::CreateSession { - session_id: session_id.clone(), - heap_limit_mb: 0, - cpu_time_limit_ms: 0, - wall_clock_limit_ms: 0, - }) - .expect("create embedded runtime session"); - - let duplicate_error = host - .send_frame(&BinaryFrame::CreateSession { - session_id: session_id.clone(), - heap_limit_mb: 0, - cpu_time_limit_ms: 0, - wall_clock_limit_ms: 0, - }) - .expect_err("duplicate session ids should be rejected"); - assert_eq!(duplicate_error.kind(), io::ErrorKind::Other); - - host.session_handle(session_id.clone()) - .destroy() - .expect("destroy embedded runtime session"); - - let _second_receiver = host - .register_session(&session_id) - .expect("re-register session output"); - host.send_frame(&BinaryFrame::CreateSession { - session_id: session_id.clone(), - heap_limit_mb: 0, - cpu_time_limit_ms: 0, - wall_clock_limit_ms: 0, - }) - .expect("recreate embedded runtime session"); - - host.session_handle(session_id) - .destroy() - .expect("destroy recreated session"); - } -} diff --git a/crates/execution/src/v8_ipc.rs b/crates/execution/src/v8_ipc.rs deleted file mode 100644 index c9999d357..000000000 --- a/crates/execution/src/v8_ipc.rs +++ /dev/null @@ -1,613 +0,0 @@ -//! Binary IPC framing for communication with the secure-exec-v8 runtime process. -//! -//! Wire format per frame: -//! [4B total_len (u32 BE, excludes self)] -//! [1B msg_type] -//! [1B sid_len (N)] -//! [N bytes session_id (UTF-8)] -//! [... type-specific fixed fields ...] -//! [M bytes payload (rest of frame)] - -use std::io; - -/// Maximum frame payload: 64 MB. -const MAX_FRAME_SIZE: u32 = 64 * 1024 * 1024; - -// Host → V8 message type codes -const MSG_AUTHENTICATE: u8 = 0x01; -const MSG_CREATE_SESSION: u8 = 0x02; -const MSG_DESTROY_SESSION: u8 = 0x03; -const MSG_INJECT_GLOBALS: u8 = 0x04; -const MSG_EXECUTE: u8 = 0x05; -const MSG_BRIDGE_RESPONSE: u8 = 0x06; -const MSG_STREAM_EVENT: u8 = 0x07; -const MSG_TERMINATE_EXECUTION: u8 = 0x08; - -// V8 → Host message type codes -const MSG_BRIDGE_CALL: u8 = 0x81; -const MSG_EXECUTION_RESULT: u8 = 0x82; -const MSG_LOG: u8 = 0x83; -const MSG_STREAM_CALLBACK: u8 = 0x84; - -// ExecutionResult flags -const FLAG_HAS_EXPORTS: u8 = 0x01; -const FLAG_HAS_ERROR: u8 = 0x02; - -/// A decoded binary frame. -#[derive(Debug, Clone, PartialEq)] -pub enum BinaryFrame { - // Host → V8 - Authenticate { - token: String, - }, - CreateSession { - session_id: String, - heap_limit_mb: u32, - cpu_time_limit_ms: u32, - wall_clock_limit_ms: u32, - }, - DestroySession { - session_id: String, - }, - InjectGlobals { - session_id: String, - payload: Vec, - }, - Execute { - session_id: String, - mode: u8, // 0 = exec (CJS), 1 = run (ESM) - file_path: String, - bridge_code: String, - post_restore_script: String, - // Optional agent-SDK bundle evaluated into the per-sidecar snapshot - // alongside the bridge (empty = bridge-only snapshot). Must stay - // wire-compatible with v8-runtime's ipc_binary BinaryFrame::Execute. - userland_code: String, - high_resolution_time: bool, - user_code: String, - }, - BridgeResponse { - session_id: String, - call_id: u64, - status: u8, // 0 = success, 1 = error, 2 = raw binary - payload: Vec, - }, - StreamEvent { - session_id: String, - event_type: String, - payload: Vec, - }, - TerminateExecution { - session_id: String, - }, - - // V8 → Host - BridgeCall { - session_id: String, - call_id: u64, - method: String, - payload: Vec, - }, - ExecutionResult { - session_id: String, - exit_code: i32, - exports: Option>, - error: Option, - }, - Log { - session_id: String, - channel: u8, // 0 = stdout, 1 = stderr - message: String, - }, - StreamCallback { - session_id: String, - callback_type: String, - payload: Vec, - }, -} - -/// Structured error from V8 execution. -#[derive(Debug, Clone, PartialEq)] -pub struct ExecutionErrorBin { - pub error_type: String, - pub message: String, - pub stack: String, - pub code: String, -} - -/// Encode a frame into a byte buffer (length prefix + body). -pub fn encode_frame(frame: &BinaryFrame) -> io::Result> { - let mut buf = Vec::new(); - // Reserve 4 bytes for length prefix - buf.extend_from_slice(&[0, 0, 0, 0]); - encode_body(&mut buf, frame)?; - let total_len = buf.len() - 4; - if total_len > MAX_FRAME_SIZE as usize { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("frame size {total_len} exceeds maximum {MAX_FRAME_SIZE}"), - )); - } - buf[..4].copy_from_slice(&(total_len as u32).to_be_bytes()); - Ok(buf) -} - -/// Decode a frame from raw bytes (after the 4-byte length prefix has been read). -pub fn decode_frame(buf: &[u8]) -> io::Result { - if buf.is_empty() { - return Err(io::Error::new(io::ErrorKind::InvalidData, "empty frame")); - } - if buf.len() > MAX_FRAME_SIZE as usize { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("frame size {} exceeds maximum {MAX_FRAME_SIZE}", buf.len()), - )); - } - - let msg_type = buf[0]; - let mut pos = 1; - - let sid_len = read_u8(buf, &mut pos)? as usize; - let session_id = read_utf8(buf, &mut pos, sid_len)?; - - match msg_type { - MSG_AUTHENTICATE => { - let remaining = buf.len() - pos; - let token = read_utf8(buf, &mut pos, remaining)?; - Ok(BinaryFrame::Authenticate { token }) - } - MSG_CREATE_SESSION => { - let heap_limit_mb = read_u32(buf, &mut pos)?; - let cpu_time_limit_ms = read_u32(buf, &mut pos)?; - let wall_clock_limit_ms = read_u32(buf, &mut pos)?; - Ok(BinaryFrame::CreateSession { - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - }) - } - MSG_DESTROY_SESSION => Ok(BinaryFrame::DestroySession { session_id }), - MSG_INJECT_GLOBALS => { - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::InjectGlobals { - session_id, - payload, - }) - } - MSG_EXECUTE => { - let mode = read_u8(buf, &mut pos)?; - let fp_len = read_u16(buf, &mut pos)? as usize; - let file_path = read_utf8(buf, &mut pos, fp_len)?; - let bc_len = read_u32(buf, &mut pos)? as usize; - let bridge_code = read_utf8(buf, &mut pos, bc_len)?; - let prs_len = read_u32(buf, &mut pos)? as usize; - let post_restore_script = read_utf8(buf, &mut pos, prs_len)?; - let ul_len = read_u32(buf, &mut pos)? as usize; - let userland_code = read_utf8(buf, &mut pos, ul_len)?; - let high_resolution_time = read_u8(buf, &mut pos)? != 0; - let remaining = buf.len() - pos; - let user_code = read_utf8(buf, &mut pos, remaining)?; - Ok(BinaryFrame::Execute { - session_id, - mode, - file_path, - bridge_code, - post_restore_script, - userland_code, - high_resolution_time, - user_code, - }) - } - MSG_BRIDGE_RESPONSE => { - let call_id = read_u64(buf, &mut pos)?; - let status = read_u8(buf, &mut pos)?; - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::BridgeResponse { - session_id, - call_id, - status, - payload, - }) - } - MSG_STREAM_EVENT => { - let et_len = read_u16(buf, &mut pos)? as usize; - let event_type = read_utf8(buf, &mut pos, et_len)?; - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::StreamEvent { - session_id, - event_type, - payload, - }) - } - MSG_TERMINATE_EXECUTION => Ok(BinaryFrame::TerminateExecution { session_id }), - MSG_BRIDGE_CALL => { - let call_id = read_u64(buf, &mut pos)?; - let m_len = read_u16(buf, &mut pos)? as usize; - let method = read_utf8(buf, &mut pos, m_len)?; - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::BridgeCall { - session_id, - call_id, - method, - payload, - }) - } - MSG_EXECUTION_RESULT => { - let exit_code = read_i32(buf, &mut pos)?; - let flags = read_u8(buf, &mut pos)?; - let exports = if flags & FLAG_HAS_EXPORTS != 0 { - let exp_len = read_u32(buf, &mut pos)? as usize; - let data = read_bytes(buf, &mut pos, exp_len)?; - Some(data) - } else { - None - }; - let error = if flags & FLAG_HAS_ERROR != 0 { - let error_type = read_len_prefixed_u16(buf, &mut pos)?; - let message = read_len_prefixed_u16(buf, &mut pos)?; - let stack = read_len_prefixed_u16(buf, &mut pos)?; - let code = read_len_prefixed_u16(buf, &mut pos)?; - Some(ExecutionErrorBin { - error_type, - message, - stack, - code, - }) - } else { - None - }; - Ok(BinaryFrame::ExecutionResult { - session_id, - exit_code, - exports, - error, - }) - } - MSG_LOG => { - let channel = read_u8(buf, &mut pos)?; - let remaining = buf.len() - pos; - let message = read_utf8(buf, &mut pos, remaining)?; - Ok(BinaryFrame::Log { - session_id, - channel, - message, - }) - } - MSG_STREAM_CALLBACK => { - let ct_len = read_u16(buf, &mut pos)? as usize; - let callback_type = read_utf8(buf, &mut pos, ct_len)?; - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::StreamCallback { - session_id, - callback_type, - payload, - }) - } - _ => Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("unknown message type: 0x{msg_type:02x}"), - )), - } -} - -// -- Encode body -- - -fn encode_body(buf: &mut Vec, frame: &BinaryFrame) -> io::Result<()> { - match frame { - BinaryFrame::Authenticate { token } => { - buf.push(MSG_AUTHENTICATE); - buf.push(0); // no session_id - buf.extend_from_slice(token.as_bytes()); - } - BinaryFrame::CreateSession { - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - } => { - buf.push(MSG_CREATE_SESSION); - write_session_id(buf, session_id)?; - buf.extend_from_slice(&heap_limit_mb.to_be_bytes()); - buf.extend_from_slice(&cpu_time_limit_ms.to_be_bytes()); - buf.extend_from_slice(&wall_clock_limit_ms.to_be_bytes()); - } - BinaryFrame::DestroySession { session_id } => { - buf.push(MSG_DESTROY_SESSION); - write_session_id(buf, session_id)?; - } - BinaryFrame::InjectGlobals { - session_id, - payload, - } => { - buf.push(MSG_INJECT_GLOBALS); - write_session_id(buf, session_id)?; - buf.extend_from_slice(payload); - } - BinaryFrame::Execute { - session_id, - mode, - file_path, - bridge_code, - post_restore_script, - userland_code, - high_resolution_time, - user_code, - } => { - buf.push(MSG_EXECUTE); - write_session_id(buf, session_id)?; - buf.push(*mode); - write_len_prefixed_u16(buf, file_path)?; - let bc_bytes = bridge_code.as_bytes(); - buf.extend_from_slice(&(bc_bytes.len() as u32).to_be_bytes()); - buf.extend_from_slice(bc_bytes); - let prs_bytes = post_restore_script.as_bytes(); - buf.extend_from_slice(&(prs_bytes.len() as u32).to_be_bytes()); - buf.extend_from_slice(prs_bytes); - let ul_bytes = userland_code.as_bytes(); - buf.extend_from_slice(&(ul_bytes.len() as u32).to_be_bytes()); - buf.extend_from_slice(ul_bytes); - buf.push(u8::from(*high_resolution_time)); - buf.extend_from_slice(user_code.as_bytes()); - } - BinaryFrame::BridgeResponse { - session_id, - call_id, - status, - payload, - } => { - buf.push(MSG_BRIDGE_RESPONSE); - write_session_id(buf, session_id)?; - buf.extend_from_slice(&call_id.to_be_bytes()); - buf.push(*status); - buf.extend_from_slice(payload); - } - BinaryFrame::StreamEvent { - session_id, - event_type, - payload, - } => { - buf.push(MSG_STREAM_EVENT); - write_session_id(buf, session_id)?; - write_len_prefixed_u16(buf, event_type)?; - buf.extend_from_slice(payload); - } - BinaryFrame::TerminateExecution { session_id } => { - buf.push(MSG_TERMINATE_EXECUTION); - write_session_id(buf, session_id)?; - } - // V8→Host frames: include encoding for completeness/testing - BinaryFrame::BridgeCall { - session_id, - call_id, - method, - payload, - } => { - buf.push(MSG_BRIDGE_CALL); - write_session_id(buf, session_id)?; - buf.extend_from_slice(&call_id.to_be_bytes()); - write_len_prefixed_u16(buf, method)?; - buf.extend_from_slice(payload); - } - BinaryFrame::ExecutionResult { - session_id, - exit_code, - exports, - error, - } => { - buf.push(MSG_EXECUTION_RESULT); - write_session_id(buf, session_id)?; - buf.extend_from_slice(&exit_code.to_be_bytes()); - let mut flags: u8 = 0; - if exports.is_some() { - flags |= FLAG_HAS_EXPORTS; - } - if error.is_some() { - flags |= FLAG_HAS_ERROR; - } - buf.push(flags); - if let Some(exp) = exports { - buf.extend_from_slice(&(exp.len() as u32).to_be_bytes()); - buf.extend_from_slice(exp); - } - if let Some(err) = error { - write_len_prefixed_u16(buf, &err.error_type)?; - write_len_prefixed_u16(buf, &err.message)?; - write_len_prefixed_u16(buf, &err.stack)?; - write_len_prefixed_u16(buf, &err.code)?; - } - } - BinaryFrame::Log { - session_id, - channel, - message, - } => { - buf.push(MSG_LOG); - write_session_id(buf, session_id)?; - buf.push(*channel); - buf.extend_from_slice(message.as_bytes()); - } - BinaryFrame::StreamCallback { - session_id, - callback_type, - payload, - } => { - buf.push(MSG_STREAM_CALLBACK); - write_session_id(buf, session_id)?; - write_len_prefixed_u16(buf, callback_type)?; - buf.extend_from_slice(payload); - } - } - Ok(()) -} - -// -- Primitive helpers -- - -fn write_session_id(buf: &mut Vec, sid: &str) -> io::Result<()> { - let bytes = sid.as_bytes(); - if bytes.len() > 255 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("session ID byte length {} exceeds u8 max 255", bytes.len()), - )); - } - buf.push(bytes.len() as u8); - buf.extend_from_slice(bytes); - Ok(()) -} - -fn write_len_prefixed_u16(buf: &mut Vec, s: &str) -> io::Result<()> { - let bytes = s.as_bytes(); - if bytes.len() > 0xFFFF { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("string byte length {} exceeds u16 max 65535", bytes.len()), - )); - } - buf.extend_from_slice(&(bytes.len() as u16).to_be_bytes()); - buf.extend_from_slice(bytes); - Ok(()) -} - -fn read_u8(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos >= buf.len() { - return Err(eof()); - } - let v = buf[*pos]; - *pos += 1; - Ok(v) -} - -fn read_u16(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos + 2 > buf.len() { - return Err(eof()); - } - let v = u16::from_be_bytes([buf[*pos], buf[*pos + 1]]); - *pos += 2; - Ok(v) -} - -fn read_u32(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos + 4 > buf.len() { - return Err(eof()); - } - let v = u32::from_be_bytes([buf[*pos], buf[*pos + 1], buf[*pos + 2], buf[*pos + 3]]); - *pos += 4; - Ok(v) -} - -fn read_i32(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos + 4 > buf.len() { - return Err(eof()); - } - let v = i32::from_be_bytes([buf[*pos], buf[*pos + 1], buf[*pos + 2], buf[*pos + 3]]); - *pos += 4; - Ok(v) -} - -fn read_u64(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos + 8 > buf.len() { - return Err(eof()); - } - let mut bytes = [0u8; 8]; - bytes.copy_from_slice(&buf[*pos..*pos + 8]); - *pos += 8; - Ok(u64::from_be_bytes(bytes)) -} - -fn read_utf8(buf: &[u8], pos: &mut usize, len: usize) -> io::Result { - if *pos + len > buf.len() { - return Err(eof()); - } - let s = std::str::from_utf8(&buf[*pos..*pos + len]) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - *pos += len; - Ok(s.to_owned()) -} - -fn read_bytes(buf: &[u8], pos: &mut usize, len: usize) -> io::Result> { - if *pos + len > buf.len() { - return Err(eof()); - } - let data = buf[*pos..*pos + len].to_vec(); - *pos += len; - Ok(data) -} - -fn read_len_prefixed_u16(buf: &[u8], pos: &mut usize) -> io::Result { - let len = read_u16(buf, pos)? as usize; - read_utf8(buf, pos, len) -} - -fn eof() -> io::Error { - io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected end of frame") -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn roundtrip_authenticate() { - let frame = BinaryFrame::Authenticate { - token: "secret123".into(), - }; - let bytes = encode_frame(&frame).unwrap(); - let decoded = decode_frame(&bytes[4..]).unwrap(); - assert_eq!(frame, decoded); - } - - #[test] - fn roundtrip_create_session() { - let frame = BinaryFrame::CreateSession { - session_id: "sess-1".into(), - heap_limit_mb: 256, - cpu_time_limit_ms: 30000, - wall_clock_limit_ms: 45000, - }; - let bytes = encode_frame(&frame).unwrap(); - let decoded = decode_frame(&bytes[4..]).unwrap(); - assert_eq!(frame, decoded); - } - - #[test] - fn roundtrip_bridge_call() { - let frame = BinaryFrame::BridgeCall { - session_id: "sess-1".into(), - call_id: 42, - method: "_fsReadFile".into(), - payload: vec![1, 2, 3], - }; - let bytes = encode_frame(&frame).unwrap(); - let decoded = decode_frame(&bytes[4..]).unwrap(); - assert_eq!(frame, decoded); - } - - #[test] - fn roundtrip_execution_result_with_error() { - let frame = BinaryFrame::ExecutionResult { - session_id: "sess-1".into(), - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message: "something failed".into(), - stack: "at foo:1:1".into(), - code: "ERR_TEST".into(), - }), - }; - let bytes = encode_frame(&frame).unwrap(); - let decoded = decode_frame(&bytes[4..]).unwrap(); - assert_eq!(frame, decoded); - } - - #[test] - fn decode_frame_rejects_oversized_body() { - let oversized = vec![0u8; MAX_FRAME_SIZE as usize + 1]; - let result = decode_frame(&oversized); - assert!(result.is_err()); - let err = result.unwrap_err(); - assert_eq!(err.kind(), io::ErrorKind::InvalidData); - assert!(err.to_string().contains("exceeds maximum")); - } -} diff --git a/crates/execution/src/v8_runtime.rs b/crates/execution/src/v8_runtime.rs deleted file mode 100644 index 9050ee105..000000000 --- a/crates/execution/src/v8_runtime.rs +++ /dev/null @@ -1,434 +0,0 @@ -//! V8 isolate runtime manager backed by the embedded V8 runtime. - -use crate::v8_ipc::{self, BinaryFrame}; -use secure_exec_v8_runtime::embedded_runtime::{spawn_embedded_runtime_ipc, EmbeddedRuntimeHandle}; -use serde_json::Value; -use std::io::{self, BufReader, Read, Write}; -use std::os::unix::net::UnixStream; -use std::sync::{Arc, Mutex}; - -/// Manages an embedded V8 runtime and its IPC connection. -pub struct V8Runtime { - runtime: EmbeddedRuntimeHandle, - reader: BufReader, - writer: UnixStream, -} - -impl V8Runtime { - /// Spawn the embedded V8 runtime and connect over IPC. - pub fn spawn() -> io::Result { - let (stream, runtime) = spawn_embedded_runtime_ipc(None)?; - let writer = stream.try_clone()?; - let reader = BufReader::new(stream); - - Ok(V8Runtime { - runtime, - reader, - writer, - }) - } - - /// Create a new V8 isolate session. - pub fn create_session( - &mut self, - session_id: &str, - heap_limit_mb: u32, - cpu_time_limit_ms: u32, - wall_clock_limit_ms: u32, - ) -> io::Result<()> { - self.send_frame(&BinaryFrame::CreateSession { - session_id: session_id.to_owned(), - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - }) - } - - /// Inject per-session globals (processConfig, osConfig) as CBOR payload. - pub fn inject_globals(&mut self, session_id: &str, payload: Vec) -> io::Result<()> { - self.send_frame(&BinaryFrame::InjectGlobals { - session_id: session_id.to_owned(), - payload, - }) - } - - /// Execute bridge code + user code in a session. - pub fn execute( - &mut self, - session_id: &str, - mode: u8, - file_path: &str, - bridge_code: &str, - user_code: &str, - ) -> io::Result<()> { - self.send_frame(&BinaryFrame::Execute { - session_id: session_id.to_owned(), - mode, - file_path: file_path.to_owned(), - bridge_code: bridge_code.to_owned(), - post_restore_script: String::new(), - userland_code: String::new(), - high_resolution_time: false, - user_code: user_code.to_owned(), - }) - } - - /// Send a bridge response back to the V8 isolate. - pub fn send_bridge_response( - &mut self, - session_id: &str, - call_id: u64, - status: u8, - payload: Vec, - ) -> io::Result<()> { - self.send_frame(&BinaryFrame::BridgeResponse { - session_id: session_id.to_owned(), - call_id, - status, - payload, - }) - } - - /// Send a stream event to the V8 isolate (stdin data, timer, child process events). - pub fn send_stream_event( - &mut self, - session_id: &str, - event_type: &str, - payload: Vec, - ) -> io::Result<()> { - self.send_frame(&BinaryFrame::StreamEvent { - session_id: session_id.to_owned(), - event_type: event_type.to_owned(), - payload, - }) - } - - /// Terminate execution in a session. - pub fn terminate_execution(&mut self, session_id: &str) -> io::Result<()> { - self.send_frame(&BinaryFrame::TerminateExecution { - session_id: session_id.to_owned(), - }) - } - - /// Destroy a session. - pub fn destroy_session(&mut self, session_id: &str) -> io::Result<()> { - self.send_frame(&BinaryFrame::DestroySession { - session_id: session_id.to_owned(), - }) - } - - /// Read the next frame from the V8 runtime. - pub fn read_frame(&mut self) -> io::Result { - let mut len_buf = [0u8; 4]; - self.reader.read_exact(&mut len_buf)?; - let total_len = u32::from_be_bytes(len_buf); - - if total_len > 64 * 1024 * 1024 { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("frame size {total_len} exceeds maximum"), - )); - } - - let mut buf = vec![0u8; total_len as usize]; - self.reader.read_exact(&mut buf)?; - v8_ipc::decode_frame(&buf) - } - - fn send_frame(&mut self, frame: &BinaryFrame) -> io::Result<()> { - let bytes = v8_ipc::encode_frame(frame)?; - self.writer.write_all(&bytes)?; - self.writer.flush() - } -} - -impl Drop for V8Runtime { - fn drop(&mut self) { - self.runtime.shutdown(); - } -} - -/// Thread-safe wrapper for V8Runtime that allows sending from multiple threads. -pub struct SharedV8Runtime { - inner: Arc>, -} - -impl SharedV8Runtime { - pub fn new(runtime: V8Runtime) -> Self { - Self { - inner: Arc::new(Mutex::new(runtime)), - } - } - - pub fn lock(&self) -> std::sync::MutexGuard<'_, V8Runtime> { - self.inner.lock().expect("V8 runtime lock poisoned") - } -} - -impl Clone for SharedV8Runtime { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - } - } -} - -/// Bridge call method name mapping from V8 polyfill names to sidecar sync RPC names. -/// The V8 polyfills use underscore-prefixed camelCase names while the sidecar -/// uses dot-separated category.method names. The mapping lives in -/// `bridge-contract.json` so bridge installation and dispatch drift together. -pub fn map_bridge_method(method: &str) -> (&str, bool) { - if let Some(target) = secure_exec_bridge::bridge_contract().dispatch.get(method) { - (target.method.as_str(), target.translate_args) - } else { - (method, false) - } -} - -/// Deserialize a CBOR payload into a JSON array of arguments. -/// The V8 bridge serializes bridge call args as a CBOR array. -pub fn cbor_payload_to_json_args(payload: &[u8]) -> io::Result> { - if payload.is_empty() { - return Ok(vec![]); - } - let cbor_value: ciborium::value::Value = ciborium::de::from_reader(payload).map_err(|e| { - io::Error::new( - io::ErrorKind::InvalidData, - format!("failed to deserialize CBOR bridge call payload: {e}"), - ) - })?; - match cbor_to_json(cbor_value) { - Value::Array(arr) => Ok(arr), - single => Ok(vec![single]), - } -} - -pub fn cbor_payload_raw_byte_arg(payload: &[u8], index: usize) -> io::Result>> { - if payload.is_empty() { - return Ok(None); - } - let cbor_value: ciborium::value::Value = ciborium::de::from_reader(payload).map_err(|e| { - io::Error::new( - io::ErrorKind::InvalidData, - format!("failed to deserialize CBOR bridge call payload: {e}"), - ) - })?; - let Some(value) = cbor_array_arg(&cbor_value, index) else { - return Ok(None); - }; - Ok(cbor_raw_bytes(value).map(ToOwned::to_owned)) -} - -/// Serialize a JSON value to CBOR bytes for bridge responses. -pub fn json_to_cbor_payload(value: &Value) -> io::Result> { - let cbor_value = json_to_cbor(value); - let mut buf = Vec::new(); - ciborium::ser::into_writer(&cbor_value, &mut buf).map_err(|e| { - io::Error::new( - io::ErrorKind::InvalidData, - format!("failed to serialize CBOR bridge response: {e}"), - ) - })?; - Ok(buf) -} - -fn cbor_array_arg(value: &ciborium::value::Value, index: usize) -> Option<&ciborium::value::Value> { - match value { - ciborium::value::Value::Array(values) => values.get(index), - value if index == 0 => Some(value), - _ => None, - } -} - -fn cbor_raw_bytes(value: &ciborium::value::Value) -> Option<&[u8]> { - match value { - ciborium::value::Value::Bytes(bytes) => Some(bytes), - ciborium::value::Value::Tag(_, inner) => cbor_raw_bytes(inner), - _ => None, - } -} - -fn cbor_to_json(value: ciborium::value::Value) -> Value { - use ciborium::value::Value as Cbor; - match value { - Cbor::Null => Value::Null, - Cbor::Bool(b) => Value::Bool(b), - Cbor::Integer(i) => { - let n: i128 = i.into(); - if let Ok(n) = i64::try_from(n) { - Value::Number(n.into()) - } else if let Ok(n) = u64::try_from(n) { - Value::Number(n.into()) - } else { - Value::Number(serde_json::Number::from_f64(n as f64).unwrap_or(0.into())) - } - } - Cbor::Float(f) => serde_json::Number::from_f64(f) - .map(Value::Number) - .unwrap_or(Value::Null), - Cbor::Text(s) => Value::String(s), - Cbor::Bytes(b) => { - use serde_json::json; - // Encode binary data as base64 with a type marker - json!({ "__type": "Buffer", "data": base64_encode(&b) }) - } - Cbor::Array(arr) => Value::Array(arr.into_iter().map(cbor_to_json).collect()), - Cbor::Map(map) => { - let mut obj = serde_json::Map::new(); - for (k, v) in map { - let key = match k { - Cbor::Text(s) => s, - Cbor::Integer(i) => { - let n: i128 = i.into(); - n.to_string() - } - other => format!("{other:?}"), - }; - obj.insert(key, cbor_to_json(v)); - } - Value::Object(obj) - } - Cbor::Tag(_, inner) => cbor_to_json(*inner), - _ => Value::Null, - } -} - -fn json_to_cbor(value: &Value) -> ciborium::value::Value { - use ciborium::value::Value as Cbor; - match value { - Value::Null => Cbor::Null, - Value::Bool(b) => Cbor::Bool(*b), - Value::Number(n) => { - if let Some(i) = n.as_i64() { - Cbor::Integer(i.into()) - } else if let Some(u) = n.as_u64() { - Cbor::Integer(u.into()) - } else if let Some(f) = n.as_f64() { - Cbor::Float(f) - } else { - Cbor::Null - } - } - Value::String(s) => Cbor::Text(s.clone()), - Value::Array(arr) => Cbor::Array(arr.iter().map(json_to_cbor).collect()), - Value::Object(map) => { - // Check for Buffer type marker - if map.get("__type").and_then(Value::as_str) == Some("Buffer") { - if let Some(data) = map.get("data").and_then(Value::as_str) { - if let Ok(bytes) = base64_decode(data) { - return Cbor::Bytes(bytes); - } - } - } - Cbor::Map( - map.iter() - .map(|(k, v)| (Cbor::Text(k.clone()), json_to_cbor(v))) - .collect(), - ) - } - } -} - -/// Public base64 encode for use in bridge call handlers. -pub fn base64_encode_pub(data: &[u8]) -> String { - base64_encode(data) -} - -pub fn base64_decode_pub(input: &str) -> Option> { - base64_decode(input).ok() -} - -fn base64_encode(data: &[u8]) -> String { - const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - let mut result = String::with_capacity(data.len().div_ceil(3) * 4); - for chunk in data.chunks(3) { - let b0 = chunk[0] as u32; - let b1 = chunk.get(1).copied().unwrap_or(0) as u32; - let b2 = chunk.get(2).copied().unwrap_or(0) as u32; - let triple = (b0 << 16) | (b1 << 8) | b2; - result.push(CHARS[((triple >> 18) & 0x3F) as usize] as char); - result.push(CHARS[((triple >> 12) & 0x3F) as usize] as char); - if chunk.len() > 1 { - result.push(CHARS[((triple >> 6) & 0x3F) as usize] as char); - } else { - result.push('='); - } - if chunk.len() > 2 { - result.push(CHARS[(triple & 0x3F) as usize] as char); - } else { - result.push('='); - } - } - result -} - -fn base64_decode(input: &str) -> Result, ()> { - fn decode_char(c: u8) -> Result { - match c { - b'A'..=b'Z' => Ok(c - b'A'), - b'a'..=b'z' => Ok(c - b'a' + 26), - b'0'..=b'9' => Ok(c - b'0' + 52), - b'+' => Ok(62), - b'/' => Ok(63), - b'=' => Ok(0), - _ => Err(()), - } - } - let bytes = input.as_bytes(); - let mut result = Vec::with_capacity(bytes.len() * 3 / 4); - for chunk in bytes.chunks(4) { - if chunk.len() < 4 { - return Err(()); - } - let a = decode_char(chunk[0])?; - let b = decode_char(chunk[1])?; - let c = decode_char(chunk[2])?; - let d = decode_char(chunk[3])?; - let triple = ((a as u32) << 18) | ((b as u32) << 12) | ((c as u32) << 6) | (d as u32); - result.push((triple >> 16) as u8); - if chunk[2] != b'=' { - result.push((triple >> 8) as u8); - } - if chunk[3] != b'=' { - result.push(triple as u8); - } - } - Ok(result) -} - -#[cfg(test)] -mod tests { - use super::map_bridge_method; - - #[test] - fn audited_bridge_methods_map_to_named_handlers() { - for method in [ - "_cryptoHashDigest", - "_cryptoSubtle", - "_networkHttp2ServerListenRaw", - "_networkHttpServerRequestRaw", - "_networkHttp2SessionConnectRaw", - "_networkHttp2StreamRespondRaw", - "_upgradeSocketWriteRaw", - "_netSocketSetNoDelayRaw", - "_kernelStdioWriteRaw", - "_kernelPollRaw", - "_kernelTtySizeRaw", - "_netSocketUpgradeTlsRaw", - "_tlsGetCiphersRaw", - "_dgramSocketAddressRaw", - "_dgramSocketSetBufferSizeRaw", - ] { - let (mapped, _) = map_bridge_method(method); - assert_ne!(mapped, method, "missing bridge-method mapping for {method}"); - } - } - - #[test] - fn http_request_bridge_shortcut_is_not_mapped() { - assert_eq!( - map_bridge_method("_networkHttpRequestRaw"), - ("_networkHttpRequestRaw", false) - ); - } -} diff --git a/crates/execution/src/wasm.rs b/crates/execution/src/wasm.rs deleted file mode 100644 index 7021288b1..000000000 --- a/crates/execution/src/wasm.rs +++ /dev/null @@ -1,4823 +0,0 @@ -use crate::common::{ - encode_json_string, encode_json_string_array, encode_json_string_map, frozen_time_ms, -}; -use crate::javascript::{ - CreateJavascriptContextRequest, GuestRuntimeConfig, JavascriptExecution, - JavascriptExecutionEngine, JavascriptExecutionError, JavascriptExecutionEvent, - JavascriptExecutionLimits, JavascriptSyncRpcRequest, StartJavascriptExecutionRequest, -}; -use crate::node_import_cache::NodeImportCache; -use crate::runtime_support::{env_flag_enabled, file_fingerprint, warmup_marker_path}; -use crate::signal::{NodeSignalDispositionAction, NodeSignalHandlerRegistration}; -use crate::v8_host::{V8RuntimeHost, V8SessionHandle}; -use crate::v8_runtime; -use base64::Engine as _; -use secure_exec_bridge::queue_tracker::{ - register_limit, warn_limit_exhausted, QueueGauge, TrackedLimit, -}; -use serde_json::{json, Value}; -use std::collections::{BTreeMap, HashMap, VecDeque}; -use std::fmt; -use std::fs; -use std::fs::OpenOptions; -use std::io::{Read, Write}; -use std::os::unix::fs::{FileExt, MetadataExt, PermissionsExt}; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, Mutex, OnceLock}; -use std::time::{Duration, Instant}; - -const WASM_MODULE_PATH_ENV: &str = "AGENTOS_WASM_MODULE_PATH"; -const WASM_GUEST_ARGV_ENV: &str = "AGENTOS_GUEST_ARGV"; -const WASM_GUEST_ENV_ENV: &str = "AGENTOS_GUEST_ENV"; -const WASM_PERMISSION_TIER_ENV: &str = "AGENTOS_WASM_PERMISSION_TIER"; -const WASM_PREWARM_ONLY_ENV: &str = "AGENTOS_WASM_PREWARM_ONLY"; -const WASM_HOST_CWD_ENV: &str = "AGENTOS_WASM_HOST_CWD"; -const WASM_SANDBOX_ROOT_ENV: &str = "AGENTOS_SANDBOX_ROOT"; -const WASM_WARMUP_DEBUG_ENV: &str = "AGENTOS_WASM_WARMUP_DEBUG"; -pub const WASM_MAX_FUEL_ENV: &str = "AGENTOS_WASM_MAX_FUEL"; -pub const WASM_MAX_MEMORY_BYTES_ENV: &str = "AGENTOS_WASM_MAX_MEMORY_BYTES"; -pub const WASM_MAX_STACK_BYTES_ENV: &str = "AGENTOS_WASM_MAX_STACK_BYTES"; -const WASM_WARMUP_METRICS_PREFIX: &str = "__AGENTOS_WASM_WARMUP_METRICS__:"; -const WASM_SIGNAL_STATE_PREFIX: &str = "__AGENTOS_WASM_SIGNAL_STATE__:"; -const WASM_WARMUP_MARKER_VERSION: &str = "1"; -const WASM_PAGE_BYTES: u64 = 65_536; -const WASM_TIMEOUT_EXIT_CODE: i32 = 124; -const MAX_WASM_MODULE_FILE_BYTES: u64 = 256 * 1024 * 1024; -const MAX_WASM_IMPORT_SECTION_ENTRIES: usize = 16_384; -const MAX_WASM_MEMORY_SECTION_ENTRIES: usize = 1_024; -const MAX_WASM_VARUINT_BYTES: usize = 10; -const DEFAULT_WASM_GUEST_HOME: &str = "/root"; -const DEFAULT_WASM_GUEST_USER: &str = "root"; -const DEFAULT_WASM_GUEST_SHELL: &str = "/bin/sh"; -const DEFAULT_WASM_GUEST_PATH: &str = - "/usr/local/sbin:/usr/local/bin:/opt/agentos/bin:/usr/sbin:/usr/bin:/sbin:/bin"; -// Warmup is a best-effort compile-cache optimization; fall back to a cold start -// instead of burning minutes on a stalled prewarm session. -const DEFAULT_WASM_PREWARM_TIMEOUT_MS: u64 = 30_000; -/// Default V8 heap cap (MB) for the wasm *runner* isolate. -/// -/// The runner is trusted sidecar infrastructure: it compiles the WASI runtime + -/// the guest's wasm module (e.g. `bash.wasm`) into its own isolate before the -/// guest runs. That compilation routinely needs far more than the 128 MiB -/// per-*guest*-isolate budget (`isolate::DEFAULT_HEAP_LIMIT_MB`); leaving the -/// runner on that default makes warmup OOM mid-compile, terminating the isolate -/// with an uncatchable (message-less) exception that surfaces as the opaque -/// `WebAssembly warmup exited with status 1 (Error: null)`. Raising the runner -/// heap does NOT weaken guest isolation — the guest module's memory/fuel/stack are -/// bounded separately, Rust-side, from `request.limits`. The value is a ceiling -/// (`heap_limits(0, cap)`), committed only as used, and operators may tune it via -/// typed `limits.wasm.runnerHeapLimitMb`. -/// -/// Note the ceiling is reachable by guest-driven work: the runner compiles the -/// guest's wasm module, so a large/hostile module can push the runner heap toward -/// this cap. That is contained per-isolate (the near-heap-limit guard terminates -/// the offending isolate, never the shared process), but operators running many -/// concurrent wasm commands on memory-constrained hosts may want to lower it. -const DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB: u32 = 2048; -// The whole point of the runner heap default is to exceed the 128 MiB per-guest -// isolate budget that OOMs warmup; enforce that invariant at compile time. -const _: () = assert!(DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB > 128); -const MAX_SYNC_WASM_PREWARM_MODULE_BYTES: u64 = 16 * 1024 * 1024; -const WASM_CAPTURED_OUTPUT_LIMIT_BYTES: usize = 16 * 1024 * 1024; -const WASM_SYNC_READ_LIMIT_BYTES: usize = 16 * 1024 * 1024; -const WASM_INLINE_RUNNER_ENTRYPOINT: &str = "./__agentos_wasm_runner__.mjs"; -const WASM_SNAPSHOT_RUNNER_ENV: &str = "AGENTOS_WASM_SNAPSHOT_RUNNER"; -const WASM_RUNNER_NO_CACHE_ENV: &str = "AGENTOS_WASM_RUNNER_NO_CACHE"; -const WASM_MODULE_BYTES_CACHE_CAPACITY: usize = 64; -const NODE_WASI_MODULE_SOURCE: &str = include_str!("../assets/runners/wasi-module.js"); -const WASM_SIDECAR_ROUTED_FS_SYNC_METHODS: &[&str] = &[ - "fs.accessSync", - "fs.chmodSync", - "fs.closeSync", - "fs.existsSync", - "fs.fdatasyncSync", - "fs.fstatSync", - "fs.fsyncSync", - "fs.ftruncateSync", - "fs.linkSync", - "fs.lstatSync", - "fs.mkdirSync", - "fs.openSync", - "fs.readFileSync", - "fs.readSync", - "fs.readdirSync", - "fs.readlinkSync", - "fs.renameSync", - "fs.rmdirSync", - "fs.statSync", - "fs.symlinkSync", - "fs.unlinkSync", - "fs.writeFileSync", - "fs.writeSync", -]; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum WasmSignalDispositionAction { - Default, - Ignore, - User, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum WasmPermissionTier { - Full, - ReadWrite, - ReadOnly, - Isolated, -} - -impl WasmPermissionTier { - fn as_env_value(self) -> &'static str { - match self { - Self::Full => "full", - Self::ReadWrite => "read-write", - Self::ReadOnly => "read-only", - Self::Isolated => "isolated", - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WasmSignalHandlerRegistration { - pub action: WasmSignalDispositionAction, - pub mask: Vec, - pub flags: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CreateWasmContextRequest { - pub vm_id: String, - pub module_path: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WasmContext { - pub context_id: String, - pub vm_id: String, - pub module_path: Option, -} - -/// Per-execution WebAssembly runtime limits, carried as typed fields rather -/// than `AGENTOS_WASM_*` env vars. Populated by the sidecar from the per-VM -/// kernel `ResourceLimits` (originating from `CreateVmConfig` on the BARE wire); -/// `None` selects "unlimited / engine default". See the env-vs-wire rule in -/// `crates/sidecar/CLAUDE.md`. -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct WasmExecutionLimits { - /// Fuel budget, enforced as a wall-clock timeout (ms) by the WASI runtime. - pub max_fuel: Option, - /// Linear-memory cap in bytes, validated against the module's declared - /// initial/maximum memory before execution. - pub max_memory_bytes: Option, - /// Stack cap in bytes. Validated from the typed wire value so bad config - /// fails closed; runtime V8 stack-limit enforcement is a follow-up — see - /// [`resolve_wasm_stack_limit_bytes`]. - pub max_stack_bytes: Option, - /// Best-effort warmup/compile-cache timeout in ms. - pub prewarm_timeout_ms: Option, - /// V8 heap cap for the trusted JS runner isolate that hosts WASI/WASM. - pub runner_heap_limit_mb: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StartWasmExecutionRequest { - pub vm_id: String, - pub context_id: String, - pub argv: Vec, - pub env: BTreeMap, - pub cwd: PathBuf, - pub permission_tier: WasmPermissionTier, - /// Per-execution runtime limits (see [`WasmExecutionLimits`]). - pub limits: WasmExecutionLimits, - /// Per-execution guest-runtime config, forwarded to the WASI runner's JS - /// execution (see [`JavascriptExecutionLimits`]'s sibling - /// [`crate::javascript::GuestRuntimeConfig`]). - pub guest_runtime: GuestRuntimeConfig, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum WasmExecutionEvent { - Stdout(Vec), - Stderr(Vec), - SyncRpcRequest(JavascriptSyncRpcRequest), - SignalState { - signal: u32, - registration: WasmSignalHandlerRegistration, - }, - Exited(i32), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WasmExecutionResult { - pub execution_id: String, - pub exit_code: i32, - pub stdout: Vec, - pub stderr: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct ResolvedWasmModule { - specifier: String, - resolved_path: PathBuf, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum NativeBinaryFormat { - Elf, - MachO, - PeCoff, -} - -impl NativeBinaryFormat { - fn display_name(self) -> &'static str { - match self { - Self::Elf => "ELF", - Self::MachO => "Mach-O", - Self::PeCoff => "PE/COFF", - } - } -} - -#[derive(Debug)] -pub enum WasmExecutionError { - MissingContext(String), - VmMismatch { - expected: String, - found: String, - }, - MissingModulePath, - InvalidLimit(String), - InvalidModule(String), - NativeBinaryNotSupported { - path: PathBuf, - header: Vec, - format: NativeBinaryFormat, - }, - NonWasmBinary { - path: PathBuf, - header: Vec, - shell_shim: bool, - }, - PrepareWarmPath(std::io::Error), - WarmupSpawn(std::io::Error), - WarmupTimeout(Duration), - WarmupFailed { - exit_code: i32, - stderr: String, - }, - Spawn(std::io::Error), - RpcResponse(String), - StdinClosed, - Stdin(std::io::Error), - OutputBufferExceeded { - stream: &'static str, - limit: usize, - }, - EventChannelClosed, -} - -impl fmt::Display for WasmExecutionError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::MissingContext(context_id) => { - write!(f, "unknown guest WebAssembly context: {context_id}") - } - Self::VmMismatch { expected, found } => { - write!( - f, - "guest WebAssembly context belongs to vm {expected}, not {found}" - ) - } - Self::MissingModulePath => { - f.write_str("guest WebAssembly execution requires a module path") - } - Self::InvalidLimit(message) => write!(f, "invalid WebAssembly limit: {message}"), - Self::InvalidModule(message) => write!(f, "invalid WebAssembly module: {message}"), - Self::NativeBinaryNotSupported { - path, - header, - format, - } => { - let header_hex = header - .iter() - .map(|byte| format!("{byte:02x}")) - .collect::>() - .join(" "); - write!( - f, - "ERR_NATIVE_BINARY_NOT_SUPPORTED: refused to execute native {} guest binary at {} inside the VM; only WebAssembly binaries are runnable there (header bytes: [{header_hex}])", - format.display_name(), - path.display() - ) - } - Self::NonWasmBinary { - path, - header, - shell_shim, - } => { - let header_hex = header - .iter() - .map(|byte| format!("{byte:02x}")) - .collect::>() - .join(" "); - if *shell_shim { - write!( - f, - "refused to compile guest WebAssembly module at {}: file is a shell-shim script (starts with \"#!\", header bytes: [{header_hex}]) instead of a \"\\0asm\" WebAssembly binary", - path.display() - ) - } else { - write!( - f, - "refused to compile guest WebAssembly module at {}: first {} byte(s) [{header_hex}] do not match the \"\\0asm\" WebAssembly magic word", - path.display(), - header.len() - ) - } - } - Self::PrepareWarmPath(err) => { - write!(f, "failed to prepare shared WebAssembly warm path: {err}") - } - Self::WarmupSpawn(err) => { - write!(f, "failed to start WebAssembly warmup runtime: {err}") - } - Self::WarmupTimeout(timeout) => { - write!( - f, - "WebAssembly warmup exceeded the configured timeout after {} ms", - timeout.as_millis() - ) - } - Self::WarmupFailed { exit_code, stderr } => { - if stderr.trim().is_empty() { - write!(f, "WebAssembly warmup exited with status {exit_code}") - } else { - write!( - f, - "WebAssembly warmup exited with status {exit_code}: {}", - stderr.trim() - ) - } - } - Self::Spawn(err) => write!(f, "failed to start guest WebAssembly runtime: {err}"), - Self::RpcResponse(message) => { - write!( - f, - "failed to write guest WebAssembly sync RPC response: {message}" - ) - } - Self::StdinClosed => f.write_str("guest WebAssembly stdin is already closed"), - Self::Stdin(err) => write!(f, "failed to write guest stdin: {err}"), - Self::OutputBufferExceeded { stream, limit } => { - write!( - f, - "guest WebAssembly {stream} exceeded the captured output limit of {limit} bytes" - ) - } - Self::EventChannelClosed => { - f.write_str("guest WebAssembly event channel closed unexpectedly") - } - } - } -} - -impl std::error::Error for WasmExecutionError {} - -#[derive(Debug)] -pub struct WasmExecution { - execution_id: String, - child_pid: u32, - inner: JavascriptExecution, - execution_timeout: Option, - execution_started_at: Instant, - timeout_reported: bool, - fuel_gauge: Option>, - internal_sync_rpc: WasmInternalSyncRpc, - pending_events: VecDeque, - stdout_stream_buffer: Vec, - stderr_stream_buffer: Vec, -} - -#[derive(Debug)] -struct WasmInternalSyncRpc { - module_guest_paths: Vec, - module_host_path: PathBuf, - guest_cwd: String, - host_cwd: PathBuf, - sandbox_root: Option, - guest_path_mappings: Vec, - route_fs_through_sidecar: bool, - next_fd: u32, - open_files: BTreeMap, - pending_events: VecDeque, -} - -#[derive(Debug, Clone)] -struct WasmGuestPathMapping { - guest_path: String, - host_path: PathBuf, - read_only: bool, -} - -impl WasmExecution { - pub fn execution_id(&self) -> &str { - &self.execution_id - } - - pub fn child_pid(&self) -> u32 { - self.child_pid - } - - pub fn v8_session_handle(&self) -> V8SessionHandle { - self.inner.v8_session_handle() - } - - pub fn uses_shared_v8_runtime(&self) -> bool { - self.inner.uses_shared_v8_runtime() - } - - pub fn write_stdin(&mut self, chunk: &[u8]) -> Result<(), WasmExecutionError> { - self.inner.write_stdin(chunk).map_err(map_javascript_error) - } - - /// Feed stdin WITHOUT emitting a `stdin` stream event to the V8 session. - /// Sidecar-managed wasm always reads stdin through the kernel - /// (`__kernel_stdin_read`); the stream event is never consumed there, and - /// while the guest thread is blocked in a sync bridge call every - /// unconsumed event lands in the session's bounded deferred-message queue - /// — one dead event per keystroke until the queue limit kills the session. - pub fn write_stdin_kernel_only(&mut self, chunk: &[u8]) -> Result<(), WasmExecutionError> { - self.inner - .write_kernel_stdin_only(chunk) - .map_err(map_javascript_error) - } - - pub fn close_stdin(&mut self) -> Result<(), WasmExecutionError> { - self.inner.close_stdin().map_err(map_javascript_error) - } - - pub fn send_stream_event( - &self, - event_type: &str, - payload: Value, - ) -> Result<(), WasmExecutionError> { - self.inner - .send_stream_event(event_type, payload) - .map_err(map_javascript_error) - } - - pub fn terminate(&self) -> Result<(), WasmExecutionError> { - self.inner.terminate().map_err(map_javascript_error) - } - - pub fn respond_sync_rpc_success( - &mut self, - id: u64, - result: Value, - ) -> Result<(), WasmExecutionError> { - self.inner - .respond_sync_rpc_success(id, result) - .map_err(map_javascript_error) - } - - pub fn respond_sync_rpc_raw_success( - &mut self, - id: u64, - payload: Vec, - ) -> Result<(), WasmExecutionError> { - self.inner - .respond_sync_rpc_raw_success(id, payload) - .map_err(map_javascript_error) - } - - pub fn respond_sync_rpc_error( - &mut self, - id: u64, - code: impl Into, - message: impl Into, - ) -> Result<(), WasmExecutionError> { - self.inner - .respond_sync_rpc_error(id, code, message) - .map_err(map_javascript_error) - } - - pub async fn poll_event( - &mut self, - timeout: Duration, - ) -> Result, WasmExecutionError> { - loop { - if let Some(event) = self.pending_events.pop_front() { - return Ok(Some(event)); - } - if let Some(event) = self.internal_sync_rpc.pending_events.pop_front() { - self.enqueue_wasm_event(event)?; - continue; - } - if let Some(event) = self.timeout_event_if_expired()? { - return Ok(Some(event)); - } - let poll_timeout = self.deadline_capped_timeout(timeout); - match self - .inner - .poll_event(poll_timeout) - .await - .map_err(map_javascript_error)? - { - Some(event) => { - if let JavascriptExecutionEvent::SyncRpcRequest(request) = &event { - if self.handle_internal_sync_rpc(request)? { - continue; - } - if let Some(signal_state) = self.handle_signal_state_sync_rpc(request)? { - return Ok(Some(signal_state)); - } - } - self.enqueue_javascript_event(event)?; - } - None if poll_timeout < timeout => continue, - None => return Ok(None), - } - } - } - - pub fn poll_event_blocking( - &mut self, - timeout: Duration, - ) -> Result, WasmExecutionError> { - loop { - if let Some(event) = self.pending_events.pop_front() { - return Ok(Some(event)); - } - if let Some(event) = self.internal_sync_rpc.pending_events.pop_front() { - self.enqueue_wasm_event(event)?; - continue; - } - if let Some(event) = self.timeout_event_if_expired()? { - return Ok(Some(event)); - } - let poll_timeout = self.deadline_capped_timeout(timeout); - match self - .inner - .poll_event_blocking(poll_timeout) - .map_err(map_javascript_error)? - { - Some(event) => { - if let JavascriptExecutionEvent::SyncRpcRequest(request) = &event { - if self.handle_internal_sync_rpc(request)? { - continue; - } - if let Some(signal_state) = self.handle_signal_state_sync_rpc(request)? { - return Ok(Some(signal_state)); - } - } - self.enqueue_javascript_event(event)?; - } - None if poll_timeout < timeout => continue, - None => return Ok(None), - } - } - } - - pub fn wait(mut self) -> Result { - self.close_stdin()?; - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - - loop { - match self.poll_event_blocking(Duration::from_millis(50))? { - Some(WasmExecutionEvent::Stdout(chunk)) => { - append_wasm_captured_output(&mut stdout, &chunk, "stdout")?; - } - Some(WasmExecutionEvent::Stderr(chunk)) => { - append_wasm_captured_output(&mut stderr, &chunk, "stderr")?; - } - Some(WasmExecutionEvent::SyncRpcRequest(request)) => { - if self.handle_wait_sync_rpc_request(&request, &mut stdout, &mut stderr)? { - continue; - } - return Err(WasmExecutionError::RpcResponse(format!( - "unexpected guest WebAssembly sync RPC request {} while waiting", - request.method - ))); - } - Some(WasmExecutionEvent::SignalState { .. }) => {} - Some(WasmExecutionEvent::Exited(exit_code)) => { - return Ok(WasmExecutionResult { - execution_id: self.execution_id, - exit_code, - stdout, - stderr, - }); - } - None => {} - } - } - } - - fn deadline_capped_timeout(&self, timeout: Duration) -> Duration { - self.execution_timeout - .map(|limit| { - let elapsed = self.execution_started_at.elapsed(); - if elapsed >= limit { - Duration::ZERO - } else { - timeout.min(limit.saturating_sub(elapsed)) - } - }) - .unwrap_or(timeout) - } - - fn timeout_event_if_expired( - &mut self, - ) -> Result, WasmExecutionError> { - if self.timeout_reported { - return Ok(None); - } - let Some(limit) = self.execution_timeout else { - return Ok(None); - }; - let elapsed = self.execution_started_at.elapsed(); - // Sample elapsed budget each poll so the gauge fires its edge-triggered - // ~80% approach warning before the terminal exhaustion below. - if let Some(gauge) = &self.fuel_gauge { - gauge.observe_depth(duration_millis_saturating_usize(elapsed)); - } - if elapsed < limit { - return Ok(None); - } - - let _ = self.inner.terminate(); - self.timeout_reported = true; - let capacity = duration_millis_saturating_usize(limit); - warn_limit_exhausted(TrackedLimit::WasmFuelMs, capacity, capacity); - self.enqueue_wasm_event(WasmExecutionEvent::Stderr( - b"WebAssembly fuel budget exhausted\n".to_vec(), - ))?; - self.enqueue_wasm_event(WasmExecutionEvent::Exited(WASM_TIMEOUT_EXIT_CODE))?; - Ok(self.pending_events.pop_front()) - } - - fn handle_internal_sync_rpc( - &mut self, - request: &JavascriptSyncRpcRequest, - ) -> Result { - handle_internal_wasm_sync_rpc_request(&mut self.inner, &mut self.internal_sync_rpc, request) - } - - fn handle_signal_state_sync_rpc( - &mut self, - request: &JavascriptSyncRpcRequest, - ) -> Result, WasmExecutionError> { - translate_wasm_signal_state_sync_rpc_request(&mut self.inner, request) - } - - fn enqueue_javascript_event( - &mut self, - event: JavascriptExecutionEvent, - ) -> Result<(), WasmExecutionError> { - match event { - JavascriptExecutionEvent::Stdout(chunk) => { - self.enqueue_stream_chunk(StreamChannel::Stdout, chunk)? - } - JavascriptExecutionEvent::Stderr(chunk) => { - self.enqueue_stream_chunk(StreamChannel::Stderr, chunk)? - } - JavascriptExecutionEvent::SyncRpcRequest(request) => { - self.pending_events - .push_back(WasmExecutionEvent::SyncRpcRequest(request)); - } - JavascriptExecutionEvent::SignalState { - signal, - registration, - } => { - self.pending_events - .push_back(WasmExecutionEvent::SignalState { - signal, - registration: registration.into(), - }); - } - JavascriptExecutionEvent::Exited(code) => { - self.flush_stream_buffers(); - self.pending_events - .push_back(WasmExecutionEvent::Exited(code)); - } - } - Ok(()) - } - - fn enqueue_wasm_event(&mut self, event: WasmExecutionEvent) -> Result<(), WasmExecutionError> { - match event { - WasmExecutionEvent::Stdout(chunk) => { - self.enqueue_stream_chunk(StreamChannel::Stdout, chunk)? - } - WasmExecutionEvent::Stderr(chunk) => { - self.enqueue_stream_chunk(StreamChannel::Stderr, chunk)? - } - WasmExecutionEvent::Exited(code) => { - self.flush_stream_buffers(); - self.pending_events - .push_back(WasmExecutionEvent::Exited(code)); - } - other => self.pending_events.push_back(other), - } - Ok(()) - } - - fn enqueue_stream_chunk( - &mut self, - channel: StreamChannel, - chunk: Vec, - ) -> Result<(), WasmExecutionError> { - let buffer = match channel { - StreamChannel::Stdout => &mut self.stdout_stream_buffer, - StreamChannel::Stderr => &mut self.stderr_stream_buffer, - }; - let stream = match channel { - StreamChannel::Stdout => "stdout", - StreamChannel::Stderr => "stderr", - }; - ensure_wasm_output_capacity(buffer.len(), chunk.len(), stream)?; - buffer.extend_from_slice(&chunk); - - let mut pending_stream_chunk = Vec::new(); - while let Some(newline_index) = buffer.iter().position(|byte| *byte == b'\n') { - let line = buffer.drain(..=newline_index).collect::>(); - if let Some(signal_state) = parse_wasm_signal_state_line(&line)? { - if !pending_stream_chunk.is_empty() { - self.pending_events.push_back(match channel { - StreamChannel::Stdout => { - WasmExecutionEvent::Stdout(std::mem::take(&mut pending_stream_chunk)) - } - StreamChannel::Stderr => { - WasmExecutionEvent::Stderr(std::mem::take(&mut pending_stream_chunk)) - } - }); - } - self.pending_events.push_back(signal_state); - continue; - } - pending_stream_chunk.extend_from_slice(&line); - } - if !pending_stream_chunk.is_empty() { - self.pending_events.push_back(match channel { - StreamChannel::Stdout => WasmExecutionEvent::Stdout(pending_stream_chunk), - StreamChannel::Stderr => WasmExecutionEvent::Stderr(pending_stream_chunk), - }); - } - - Ok(()) - } - - fn flush_stream_buffers(&mut self) { - if !self.stdout_stream_buffer.is_empty() { - self.pending_events - .push_back(WasmExecutionEvent::Stdout(std::mem::take( - &mut self.stdout_stream_buffer, - ))); - } - if !self.stderr_stream_buffer.is_empty() { - self.pending_events - .push_back(WasmExecutionEvent::Stderr(std::mem::take( - &mut self.stderr_stream_buffer, - ))); - } - } - - fn handle_wait_sync_rpc_request( - &mut self, - request: &JavascriptSyncRpcRequest, - stdout: &mut Vec, - stderr: &mut Vec, - ) -> Result { - if self - .inner - .handle_kernel_stdin_sync_rpc(request) - .map_err(map_javascript_error)? - { - return Ok(true); - } - - if request.method != "__kernel_stdio_write" { - return Ok(false); - } - - let Some(descriptor) = request.args.first().and_then(Value::as_u64) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing __kernel_stdio_write descriptor", - ))); - }; - let bytes = decode_wasm_bytes_arg( - request.args.get(1), - "__kernel_stdio_write payload bytes", - WASM_CAPTURED_OUTPUT_LIMIT_BYTES, - )?; - - match descriptor { - 1 => append_wasm_captured_output(stdout, &bytes, "stdout")?, - 2 => append_wasm_captured_output(stderr, &bytes, "stderr")?, - other => { - return Err(WasmExecutionError::RpcResponse(format!( - "unsupported __kernel_stdio_write descriptor {other}", - ))); - } - } - - self.respond_sync_rpc_success(request.id, json!(bytes.len()))?; - Ok(true) - } -} - -#[derive(Clone, Copy)] -enum StreamChannel { - Stdout, - Stderr, -} - -#[derive(Debug, Default)] -pub struct WasmExecutionEngine { - next_context_id: usize, - next_execution_id: usize, - contexts: BTreeMap, - import_caches: BTreeMap, - javascript_context_ids: BTreeMap, - javascript_engine: JavascriptExecutionEngine, -} - -impl WasmExecutionEngine { - pub fn create_context(&mut self, request: CreateWasmContextRequest) -> WasmContext { - self.next_context_id += 1; - self.import_caches.entry(request.vm_id.clone()).or_default(); - let javascript_context = - self.javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: request.vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - - let context = WasmContext { - context_id: format!("wasm-ctx-{}", self.next_context_id), - vm_id: request.vm_id, - module_path: request.module_path, - }; - self.javascript_context_ids - .insert(context.context_id.clone(), javascript_context.context_id); - self.contexts - .insert(context.context_id.clone(), context.clone()); - context - } - - pub fn start_execution( - &mut self, - request: StartWasmExecutionRequest, - ) -> Result { - let context = self - .contexts - .get(&request.context_id) - .cloned() - .ok_or_else(|| WasmExecutionError::MissingContext(request.context_id.clone()))?; - - if context.vm_id != request.vm_id { - return Err(WasmExecutionError::VmMismatch { - expected: context.vm_id, - found: request.vm_id, - }); - } - - let resolved_module = resolve_wasm_module(&context, &request)?; - verify_wasm_module_header(&resolved_module)?; - let prewarm_timeout = resolve_wasm_prewarm_timeout(&request)?; - let javascript_context_id = self - .javascript_context_ids - .get(&context.context_id) - .cloned() - .ok_or_else(|| WasmExecutionError::MissingContext(context.context_id.clone()))?; - { - let import_cache = self.import_caches.entry(context.vm_id.clone()).or_default(); - import_cache - .ensure_materialized_with_timeout(prewarm_timeout) - .map_err(WasmExecutionError::PrepareWarmPath)?; - } - let frozen_time_ms = frozen_time_ms(); - validate_module_limits(&resolved_module, &request)?; - // Surfaces a typed error for a malformed stack byte budget instead of - // silently dropping it. Runtime V8 stack-limit enforcement is tracked - // separately; for now this validation prevents accepting an invalid cap. - wasm_stack_limit_bytes(&request)?; - let execution_timeout = resolve_wasm_execution_timeout(&request)?; - let import_cache = self - .import_caches - .get(&context.vm_id) - .expect("vm import cache should exist after materialization"); - let warmup_metrics = match prewarm_wasm_path( - import_cache, - &mut self.javascript_engine, - &javascript_context_id, - &resolved_module, - &request, - frozen_time_ms, - prewarm_timeout, - ) { - Ok(metrics) => metrics, - Err(WasmExecutionError::WarmupTimeout(_)) => None, - Err(error) => return Err(error), - }; - - self.next_execution_id += 1; - let execution_id = format!("exec-{}", self.next_execution_id); - let javascript_execution = start_wasm_javascript_execution( - &mut self.javascript_engine, - import_cache, - &javascript_context_id, - &resolved_module, - &request, - WasmJavascriptExecutionOptions { - frozen_time_ms, - prewarm_only: false, - warmup_metrics: warmup_metrics.as_deref(), - }, - )?; - let child_pid = javascript_execution.child_pid(); - let sandbox_root = wasm_sandbox_root(&request.env); - let guest_path_mappings = wasm_guest_path_mappings(&request); - - Ok(WasmExecution { - execution_id, - child_pid, - inner: javascript_execution, - execution_timeout, - execution_started_at: Instant::now(), - timeout_reported: false, - // Approach-warn (~80%) before the WASM execution budget is exhausted; - // only registered when a timeout is actually set. - fuel_gauge: execution_timeout.map(|limit| { - register_limit( - TrackedLimit::WasmFuelMs, - duration_millis_saturating_usize(limit), - ) - }), - pending_events: VecDeque::new(), - stdout_stream_buffer: Vec::new(), - stderr_stream_buffer: Vec::new(), - internal_sync_rpc: WasmInternalSyncRpc { - module_guest_paths: wasm_guest_module_paths( - &resolved_module.specifier, - &request.env, - ), - module_host_path: resolved_module.resolved_path.clone(), - guest_cwd: wasm_guest_cwd(&request.env), - host_cwd: request.cwd.clone(), - sandbox_root: sandbox_root.clone(), - guest_path_mappings, - route_fs_through_sidecar: sandbox_root.is_some(), - next_fd: 64, - open_files: BTreeMap::new(), - pending_events: VecDeque::new(), - }, - }) - } - - pub fn dispose_vm(&mut self, vm_id: &str) { - self.contexts.retain(|_, context| context.vm_id != vm_id); - self.javascript_context_ids - .retain(|wasm_context_id, _| self.contexts.contains_key(wasm_context_id)); - self.import_caches.remove(vm_id); - self.javascript_engine.dispose_vm(vm_id); - } -} - -fn map_javascript_error(error: JavascriptExecutionError) -> WasmExecutionError { - match error { - JavascriptExecutionError::EmptyArgv => WasmExecutionError::Spawn(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "guest WebAssembly bootstrap requires a JavaScript entrypoint", - )), - JavascriptExecutionError::MissingContext(context_id) => { - WasmExecutionError::MissingContext(context_id) - } - JavascriptExecutionError::VmMismatch { expected, found } => { - WasmExecutionError::VmMismatch { expected, found } - } - JavascriptExecutionError::PrepareImportCache(error) => { - WasmExecutionError::PrepareWarmPath(error) - } - JavascriptExecutionError::Spawn(error) => WasmExecutionError::Spawn(error), - JavascriptExecutionError::PendingSyncRpcRequest(id) => WasmExecutionError::RpcResponse( - format!("guest WebAssembly sync RPC request {id} is still pending"), - ), - JavascriptExecutionError::ExpiredSyncRpcRequest(id) => WasmExecutionError::RpcResponse( - format!("guest WebAssembly sync RPC request {id} is no longer pending"), - ), - JavascriptExecutionError::RpcResponse(message) => WasmExecutionError::RpcResponse(message), - JavascriptExecutionError::Terminate(error) => WasmExecutionError::Spawn(error), - JavascriptExecutionError::StdinClosed => WasmExecutionError::StdinClosed, - JavascriptExecutionError::Stdin(error) => WasmExecutionError::Stdin(error), - JavascriptExecutionError::OutputBufferExceeded { stream, limit } => { - WasmExecutionError::OutputBufferExceeded { stream, limit } - } - JavascriptExecutionError::EventChannelClosed => WasmExecutionError::EventChannelClosed, - } -} - -fn handle_internal_wasm_sync_rpc_request( - execution: &mut JavascriptExecution, - internal_sync_rpc: &mut WasmInternalSyncRpc, - request: &JavascriptSyncRpcRequest, -) -> Result { - // Module-resolution sync RPCs (the wasm runner imports node builtins + - // its own ESM) are serviced host-directly via the execution's own - // translator; the prewarm has no kernel/service loop. - if execution - .try_service_standalone_module_sync_rpc(request) - .map_err(map_javascript_error)? - { - return Ok(true); - } - - if matches!( - request.method.as_str(), - "fs.promises.readFile" | "fs.readFileSync" - ) && request - .args - .first() - .and_then(Value::as_str) - .is_some_and(|path| { - internal_sync_rpc - .module_guest_paths - .iter() - .any(|candidate| candidate == path) - }) - { - let module_bytes = - fs::read(&internal_sync_rpc.module_host_path).map_err(WasmExecutionError::Spawn)?; - execution - .respond_sync_rpc_success( - request.id, - Value::String(v8_runtime::base64_encode_pub(&module_bytes)), - ) - .map_err(map_javascript_error)?; - return Ok(true); - } - - if wasm_sync_rpc_method_routes_through_sidecar_kernel(request, internal_sync_rpc) { - return Ok(false); - } - - if request.method == "__kernel_isatty" { - execution - .respond_sync_rpc_success(request.id, Value::Bool(false)) - .map_err(map_javascript_error)?; - return Ok(true); - } - - if request.method == "__kernel_tty_size" { - execution - .respond_sync_rpc_success(request.id, json!([80, 24])) - .map_err(map_javascript_error)?; - return Ok(true); - } - - if request.method == "fs.openSync" { - let Some(path) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.openSync path", - ))); - }; - let Some(host_path) = translate_wasm_guest_path(path, internal_sync_rpc) else { - return Ok(false); - }; - let flags = request.args.get(1).unwrap_or(&Value::Null); - if wasm_open_flags_require_write(flags) - && wasm_host_path_is_read_only(&host_path, internal_sync_rpc) - { - return respond_wasm_sync_rpc_value( - execution, - request, - path, - Err(wasm_read_only_filesystem_error(path)), - ) - .map(|()| true); - } - let file = match open_wasm_guest_file(&host_path, flags) { - Ok(file) => file, - Err(error) => { - return respond_wasm_sync_rpc_value(execution, request, path, Err(error)) - .map(|()| true); - } - }; - let fd = internal_sync_rpc.next_fd; - internal_sync_rpc.next_fd += 1; - internal_sync_rpc.open_files.insert(fd, file); - execution - .respond_sync_rpc_success(request.id, json!(fd)) - .map_err(map_javascript_error)?; - return Ok(true); - } - - if matches!(request.method.as_str(), "fs.statSync" | "fs.lstatSync") { - let Some(path) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(format!( - "missing {} path", - request.method - ))); - }; - let Some(host_path) = translate_wasm_guest_path(path, internal_sync_rpc) else { - return Ok(false); - }; - let metadata = if request.method == "fs.lstatSync" { - fs::symlink_metadata(&host_path) - } else { - fs::metadata(&host_path) - }; - return respond_wasm_sync_rpc_metadata(execution, request, path, metadata).map(|()| true); - } - - if request.method == "fs.fstatSync" { - let Some(fd) = request.args.first().and_then(Value::as_u64) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.fstatSync fd", - ))); - }; - let Some(file) = internal_sync_rpc.open_files.get(&(fd as u32)) else { - return Ok(false); - }; - return respond_wasm_sync_rpc_metadata( - execution, - request, - &fd.to_string(), - file.metadata(), - ) - .map(|()| true); - } - - if request.method == "fs.ftruncateSync" { - let Some(fd) = request.args.first().and_then(Value::as_u64) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.ftruncateSync fd", - ))); - }; - let length = request.args.get(1).and_then(Value::as_u64).unwrap_or(0); - let Some(file) = internal_sync_rpc.open_files.get_mut(&(fd as u32)) else { - return Ok(false); - }; - let result = file.set_len(length); - return respond_wasm_sync_rpc_unit(execution, request, &fd.to_string(), result) - .map(|()| true); - } - - if request.method == "fs.closeSync" { - let Some(fd) = request.args.first().and_then(Value::as_u64) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.closeSync fd", - ))); - }; - if internal_sync_rpc.open_files.remove(&(fd as u32)).is_none() { - return Ok(false); - } - execution - .respond_sync_rpc_success(request.id, Value::Null) - .map_err(map_javascript_error)?; - return Ok(true); - } - - if request.method == "fs.chmodSync" { - let Some(path) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.chmodSync path", - ))); - }; - let Some(host_path) = translate_wasm_guest_path(path, internal_sync_rpc) else { - return Ok(false); - }; - if wasm_host_path_is_read_only(&host_path, internal_sync_rpc) { - return respond_wasm_sync_rpc_unit( - execution, - request, - path, - Err(wasm_read_only_filesystem_error(path)), - ) - .map(|()| true); - } - let mode = request.args.get(1).and_then(Value::as_u64).unwrap_or(0) as u32; - let result = (|| -> Result<(), std::io::Error> { - let mut permissions = fs::metadata(&host_path)?.permissions(); - permissions.set_mode(mode); - fs::set_permissions(&host_path, permissions) - })(); - return respond_wasm_sync_rpc_unit(execution, request, path, result).map(|()| true); - } - - if request.method == "fs.mkdirSync" { - let Some(path) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.mkdirSync path", - ))); - }; - let Some(host_path) = translate_wasm_guest_path(path, internal_sync_rpc) else { - return Ok(false); - }; - if wasm_host_path_is_read_only(&host_path, internal_sync_rpc) { - return respond_wasm_sync_rpc_unit( - execution, - request, - path, - Err(wasm_read_only_filesystem_error(path)), - ) - .map(|()| true); - } - let recursive = request - .args - .get(1) - .map(|value| match value { - Value::Bool(flag) => *flag, - Value::Object(options) => options - .get("recursive") - .and_then(Value::as_bool) - .unwrap_or(false), - _ => false, - }) - .unwrap_or(false); - let result = if recursive { - fs::create_dir_all(&host_path) - } else { - fs::create_dir(&host_path) - }; - return respond_wasm_sync_rpc_unit(execution, request, path, result).map(|()| true); - } - - if request.method == "fs.rmdirSync" { - let Some(path) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.rmdirSync path", - ))); - }; - let Some(host_path) = translate_wasm_guest_path(path, internal_sync_rpc) else { - return Ok(false); - }; - if wasm_host_path_is_read_only(&host_path, internal_sync_rpc) { - return respond_wasm_sync_rpc_unit( - execution, - request, - path, - Err(wasm_read_only_filesystem_error(path)), - ) - .map(|()| true); - } - return respond_wasm_sync_rpc_unit(execution, request, path, fs::remove_dir(&host_path)) - .map(|()| true); - } - - if request.method == "fs.unlinkSync" { - let Some(path) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.unlinkSync path", - ))); - }; - let Some(host_path) = translate_wasm_guest_path(path, internal_sync_rpc) else { - return Ok(false); - }; - if wasm_host_path_is_read_only(&host_path, internal_sync_rpc) { - return respond_wasm_sync_rpc_unit( - execution, - request, - path, - Err(wasm_read_only_filesystem_error(path)), - ) - .map(|()| true); - } - return respond_wasm_sync_rpc_unit(execution, request, path, fs::remove_file(&host_path)) - .map(|()| true); - } - - if request.method == "fs.renameSync" { - let Some(source) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.renameSync source", - ))); - }; - let Some(destination) = request.args.get(1).and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.renameSync destination", - ))); - }; - let Some(host_source) = translate_wasm_guest_path(source, internal_sync_rpc) else { - return Ok(false); - }; - let Some(host_destination) = translate_wasm_guest_path(destination, internal_sync_rpc) - else { - return Ok(false); - }; - if wasm_mutation_touches_read_only_mapping( - &host_source, - &host_destination, - internal_sync_rpc, - ) { - return respond_wasm_sync_rpc_unit( - execution, - request, - source, - Err(wasm_read_only_filesystem_error(source)), - ) - .map(|()| true); - } - return respond_wasm_sync_rpc_unit( - execution, - request, - source, - fs::rename(&host_source, &host_destination), - ) - .map(|()| true); - } - - if request.method == "fs.linkSync" { - let Some(source) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.linkSync source", - ))); - }; - let Some(destination) = request.args.get(1).and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.linkSync destination", - ))); - }; - let Some(host_source) = translate_wasm_guest_path(source, internal_sync_rpc) else { - return Ok(false); - }; - let Some(host_destination) = translate_wasm_guest_path(destination, internal_sync_rpc) - else { - return Ok(false); - }; - if wasm_host_path_is_read_only(&host_source, internal_sync_rpc) - || wasm_host_path_is_read_only(&host_destination, internal_sync_rpc) - { - return respond_wasm_sync_rpc_unit( - execution, - request, - source, - Err(wasm_read_only_filesystem_error(source)), - ) - .map(|()| true); - } - return respond_wasm_sync_rpc_unit( - execution, - request, - source, - fs::hard_link(&host_source, &host_destination), - ) - .map(|()| true); - } - - if request.method == "fs.symlinkSync" { - let Some(target) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.symlinkSync target", - ))); - }; - let Some(link_path) = request.args.get(1).and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.symlinkSync path", - ))); - }; - let target_path = if target.starts_with('/') { - let Some(path) = translate_wasm_guest_path(target, internal_sync_rpc) else { - return Ok(false); - }; - path - } else { - PathBuf::from(target) - }; - let Some(host_link_path) = translate_wasm_guest_path(link_path, internal_sync_rpc) else { - return Ok(false); - }; - if wasm_host_path_is_read_only(&host_link_path, internal_sync_rpc) { - return respond_wasm_sync_rpc_unit( - execution, - request, - link_path, - Err(wasm_read_only_filesystem_error(link_path)), - ) - .map(|()| true); - } - return respond_wasm_sync_rpc_unit( - execution, - request, - link_path, - std::os::unix::fs::symlink(&target_path, &host_link_path), - ) - .map(|()| true); - } - - if request.method == "fs.readdirSync" { - let Some(path) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.readdirSync path", - ))); - }; - let Some(host_path) = translate_wasm_guest_path(path, internal_sync_rpc) else { - return Ok(false); - }; - let entries = fs::read_dir(&host_path) - .and_then(|entries| { - entries - .map(|entry| { - entry.map(|value| value.file_name().to_string_lossy().into_owned()) - }) - .collect::, _>>() - }) - .map(|entries| json!(entries)); - return respond_wasm_sync_rpc_value(execution, request, path, entries).map(|()| true); - } - - if request.method == "fs.readlinkSync" { - let Some(path) = request.args.first().and_then(Value::as_str) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.readlinkSync path", - ))); - }; - let Some(host_path) = translate_wasm_guest_path(path, internal_sync_rpc) else { - return Ok(false); - }; - let target = fs::read_link(&host_path).map(|target| { - Value::String( - translate_wasm_host_symlink_target(&target, internal_sync_rpc) - .unwrap_or_else(|| target.to_string_lossy().into_owned()), - ) - }); - return respond_wasm_sync_rpc_value(execution, request, path, target).map(|()| true); - } - - if request.method == "fs.writeSync" { - let Some(fd) = request.args.first().and_then(Value::as_u64) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.writeSync fd", - ))); - }; - let bytes = decode_wasm_bytes_arg( - request.args.get(1), - "fs.writeSync bytes", - WASM_CAPTURED_OUTPUT_LIMIT_BYTES, - )?; - if fd == 1 || fd == 2 { - let bytes_len = bytes.len(); - internal_sync_rpc.pending_events.push_back(if fd == 1 { - WasmExecutionEvent::Stdout(bytes) - } else { - WasmExecutionEvent::Stderr(bytes) - }); - execution - .respond_sync_rpc_success(request.id, json!(bytes_len)) - .map_err(map_javascript_error)?; - return Ok(true); - } - let position = request.args.get(2).and_then(Value::as_u64); - let Some(file) = internal_sync_rpc.open_files.get_mut(&(fd as u32)) else { - return Ok(false); - }; - let written = if let Some(position) = position { - file.write_at(&bytes, position) - .map_err(WasmExecutionError::Spawn)? - } else { - file.write(&bytes).map_err(WasmExecutionError::Spawn)? - }; - execution - .respond_sync_rpc_success(request.id, json!(written)) - .map_err(map_javascript_error)?; - return Ok(true); - } - - if request.method == "fs.readSync" { - let Some(fd) = request.args.first().and_then(Value::as_u64) else { - return Err(WasmExecutionError::RpcResponse(String::from( - "missing fs.readSync fd", - ))); - }; - let length = wasm_sync_read_length(request.args.get(1).and_then(Value::as_u64))?; - let position = request.args.get(2).and_then(Value::as_u64); - let Some(file) = internal_sync_rpc.open_files.get_mut(&(fd as u32)) else { - return Ok(false); - }; - let mut buffer = vec![0u8; length]; - let bytes_read = if let Some(position) = position { - file.read_at(&mut buffer, position) - .map_err(WasmExecutionError::Spawn)? - } else { - file.read(&mut buffer).map_err(WasmExecutionError::Spawn)? - }; - buffer.truncate(bytes_read); - execution - .respond_sync_rpc_success( - request.id, - json!({ - "__agentOSType": "bytes", - "base64": v8_runtime::base64_encode_pub(&buffer), - }), - ) - .map_err(map_javascript_error)?; - return Ok(true); - } - - Ok(false) -} - -fn wasm_sync_rpc_method_routes_through_sidecar_kernel( - request: &JavascriptSyncRpcRequest, - internal_sync_rpc: &WasmInternalSyncRpc, -) -> bool { - internal_sync_rpc.route_fs_through_sidecar - && WASM_SIDECAR_ROUTED_FS_SYNC_METHODS.contains(&request.method.as_str()) -} - -fn translate_wasm_guest_path( - path: &str, - internal_sync_rpc: &WasmInternalSyncRpc, -) -> Option { - if let Some(host_path) = translate_wasm_host_runtime_path(path, internal_sync_rpc) { - return confine_wasm_host_path(host_path, internal_sync_rpc); - } - - let normalized_path = if path.starts_with('/') { - normalize_guest_path(path) - } else { - join_guest_path(&internal_sync_rpc.guest_cwd, path) - }; - - if normalized_path == internal_sync_rpc.module_host_path.to_string_lossy() { - return Some(internal_sync_rpc.module_host_path.clone()); - } - if internal_sync_rpc - .module_guest_paths - .iter() - .any(|candidate| candidate == &normalized_path) - { - return Some(internal_sync_rpc.module_host_path.clone()); - } - for mapping in &internal_sync_rpc.guest_path_mappings { - if let Some(suffix) = strip_guest_prefix(&normalized_path, &mapping.guest_path) { - return confine_wasm_host_path( - join_host_path(&mapping.host_path, &suffix), - internal_sync_rpc, - ); - } - } - if let Some(suffix) = strip_guest_prefix(&normalized_path, &internal_sync_rpc.guest_cwd) { - return confine_wasm_host_path( - join_host_path(&internal_sync_rpc.host_cwd, &suffix), - internal_sync_rpc, - ); - } - if normalized_path.starts_with('/') { - let root_candidate = internal_sync_rpc - .sandbox_root - .as_ref() - .map(|root| join_host_path(root, normalized_path.trim_start_matches('/'))); - if let Some(candidate) = root_candidate.as_ref() { - if candidate.exists() { - return confine_wasm_host_path(candidate.clone(), internal_sync_rpc); - } - } - - // Some shipped WASI command binaries still collapse guest-cwd-relative paths like - // `note.txt` into `/note.txt` before they reach the host bridge. Prefer the true root - // path when it exists, but fall back to the current guest cwd when only that target exists. - if internal_sync_rpc.guest_cwd != "/" { - let cwd_relative_guest_path = join_guest_path( - &internal_sync_rpc.guest_cwd, - normalized_path.trim_start_matches('/'), - ); - for mapping in &internal_sync_rpc.guest_path_mappings { - if let Some(suffix) = - strip_guest_prefix(&cwd_relative_guest_path, &mapping.guest_path) - { - let candidate = join_host_path(&mapping.host_path, &suffix); - if candidate.exists() { - return confine_wasm_host_path(candidate, internal_sync_rpc); - } - } - } - if let Some(suffix) = - strip_guest_prefix(&cwd_relative_guest_path, &internal_sync_rpc.guest_cwd) - { - let candidate = join_host_path(&internal_sync_rpc.host_cwd, &suffix); - if candidate.exists() { - return confine_wasm_host_path(candidate, internal_sync_rpc); - } - } - } - - return root_candidate.and_then(|path| confine_wasm_host_path(path, internal_sync_rpc)); - } - None -} - -fn confine_wasm_host_path( - host_path: PathBuf, - internal_sync_rpc: &WasmInternalSyncRpc, -) -> Option { - if host_path == internal_sync_rpc.module_host_path { - return Some(host_path); - } - - let allowed_roots = wasm_allowed_host_roots(internal_sync_rpc); - if allowed_roots.is_empty() { - return None; - } - - if let Ok(canonical_path) = fs::canonicalize(&host_path) { - return wasm_canonical_path_is_allowed(&canonical_path, &allowed_roots) - .then_some(host_path); - } - - let existing_ancestor = nearest_existing_wasm_host_ancestor(&host_path)?; - let canonical_ancestor = fs::canonicalize(existing_ancestor).ok()?; - wasm_canonical_path_is_allowed(&canonical_ancestor, &allowed_roots).then_some(host_path) -} - -fn wasm_allowed_host_roots(internal_sync_rpc: &WasmInternalSyncRpc) -> Vec { - let mut roots = Vec::new(); - for root in internal_sync_rpc - .guest_path_mappings - .iter() - .map(|mapping| mapping.host_path.as_path()) - .chain(std::iter::once(internal_sync_rpc.host_cwd.as_path())) - .chain(internal_sync_rpc.sandbox_root.as_deref()) - { - if let Ok(canonical_root) = fs::canonicalize(root) { - if !roots.iter().any(|existing| existing == &canonical_root) { - roots.push(canonical_root); - } - } - } - roots -} - -fn wasm_canonical_path_is_allowed(path: &Path, allowed_roots: &[PathBuf]) -> bool { - allowed_roots - .iter() - .any(|root| path == root || path.starts_with(root)) -} - -fn nearest_existing_wasm_host_ancestor(path: &Path) -> Option<&Path> { - let mut candidate = Some(path); - while let Some(current) = candidate { - if fs::symlink_metadata(current).is_ok() { - return Some(current); - } - candidate = current.parent(); - } - None -} - -fn translate_wasm_host_runtime_path( - path: &str, - internal_sync_rpc: &WasmInternalSyncRpc, -) -> Option { - let candidate = Path::new(path); - if !candidate.is_absolute() { - return None; - } - - if candidate == internal_sync_rpc.module_host_path { - return Some(candidate.to_path_buf()); - } - - let mapped_host_root = internal_sync_rpc - .guest_path_mappings - .iter() - .map(|mapping| mapping.host_path.as_path()) - .find(|root| candidate == *root || candidate.starts_with(root)); - if let Some(root) = mapped_host_root { - let _ = root; - return Some(candidate.to_path_buf()); - } - - if candidate == internal_sync_rpc.host_cwd || candidate.starts_with(&internal_sync_rpc.host_cwd) - { - return Some(candidate.to_path_buf()); - } - - if let Some(sandbox_root) = internal_sync_rpc.sandbox_root.as_ref() { - if candidate == sandbox_root || candidate.starts_with(sandbox_root) { - return Some(candidate.to_path_buf()); - } - } - - None -} - -fn translate_wasm_host_symlink_target( - target: &Path, - internal_sync_rpc: &WasmInternalSyncRpc, -) -> Option { - if !target.is_absolute() { - return None; - } - - for mapping in &internal_sync_rpc.guest_path_mappings { - if let Ok(suffix) = target.strip_prefix(&mapping.host_path) { - return Some(join_guest_path( - &mapping.guest_path, - &suffix.to_string_lossy().replace('\\', "/"), - )); - } - } - - if let Some(suffix) = target - .strip_prefix(&internal_sync_rpc.host_cwd) - .ok() - .filter(|_| internal_sync_rpc.guest_cwd.starts_with('/')) - { - return Some(join_guest_path( - &internal_sync_rpc.guest_cwd, - &suffix.to_string_lossy().replace('\\', "/"), - )); - } - - if let Some(sandbox_root) = internal_sync_rpc.sandbox_root.as_ref() { - if let Ok(suffix) = target.strip_prefix(sandbox_root) { - return Some(join_guest_path( - "/", - &suffix.to_string_lossy().replace('\\', "/"), - )); - } - } - - None -} - -fn wasm_host_path_is_read_only(host_path: &Path, internal_sync_rpc: &WasmInternalSyncRpc) -> bool { - let canonical_path = fs::canonicalize(host_path) - .ok() - .or_else(|| { - nearest_existing_wasm_host_ancestor(host_path) - .and_then(|ancestor| fs::canonicalize(ancestor).ok()) - }) - .unwrap_or_else(|| host_path.to_path_buf()); - - internal_sync_rpc - .guest_path_mappings - .iter() - .filter_map(|mapping| { - let root = fs::canonicalize(&mapping.host_path).ok()?; - (canonical_path == root || canonical_path.starts_with(&root)) - .then_some((root.components().count(), mapping.read_only)) - }) - .max_by_key(|(depth, _)| *depth) - .is_some_and(|(_, read_only)| read_only) -} - -fn wasm_mutation_touches_read_only_mapping( - source: &Path, - destination: &Path, - internal_sync_rpc: &WasmInternalSyncRpc, -) -> bool { - wasm_host_path_is_read_only(source, internal_sync_rpc) - || wasm_host_path_is_read_only(destination, internal_sync_rpc) -} - -fn wasm_open_flags_require_write(flags: &Value) -> bool { - match flags.as_str() { - Some(value) => value.contains('w') || value.contains('a') || value.contains('+'), - None if flags.as_u64().unwrap_or(0) == 0 => false, - _ => { - let numeric = flags.as_u64().unwrap_or(0); - (numeric & 0o1) != 0 - || (numeric & 0o2) != 0 - || (numeric & 0o100) != 0 - || (numeric & 0o1000) != 0 - || (numeric & 0o2000) != 0 - } - } -} - -fn wasm_read_only_filesystem_error(path: &str) -> std::io::Error { - let _ = path; - std::io::Error::from_raw_os_error(30) -} - -fn respond_wasm_sync_rpc_metadata( - execution: &mut JavascriptExecution, - request: &JavascriptSyncRpcRequest, - label: &str, - metadata: Result, -) -> Result<(), WasmExecutionError> { - respond_wasm_sync_rpc_value( - execution, - request, - label, - metadata.map(|value| wasm_host_stat_value(&value)), - ) -} - -fn respond_wasm_sync_rpc_unit( - execution: &mut JavascriptExecution, - request: &JavascriptSyncRpcRequest, - label: &str, - result: Result<(), std::io::Error>, -) -> Result<(), WasmExecutionError> { - respond_wasm_sync_rpc_value(execution, request, label, result.map(|()| Value::Null)) -} - -fn respond_wasm_sync_rpc_value( - execution: &mut JavascriptExecution, - request: &JavascriptSyncRpcRequest, - label: &str, - result: Result, -) -> Result<(), WasmExecutionError> { - match result { - Ok(value) => execution - .respond_sync_rpc_success(request.id, value) - .map_err(map_javascript_error), - Err(error) => execution - .respond_sync_rpc_error( - request.id, - wasm_sync_rpc_error_code(&error), - format!("{} {} failed: {error}", request.method, label), - ) - .map_err(map_javascript_error), - } -} - -fn wasm_sync_rpc_error_code(error: &std::io::Error) -> &'static str { - use std::io::ErrorKind; - - if error.raw_os_error() == Some(30) { - return "EROFS"; - } - - match error.kind() { - ErrorKind::NotFound => "ENOENT", - ErrorKind::PermissionDenied => "EACCES", - ErrorKind::AlreadyExists => "EEXIST", - ErrorKind::InvalidInput => "EINVAL", - ErrorKind::IsADirectory => "EISDIR", - ErrorKind::NotADirectory => "ENOTDIR", - _ => "EIO", - } -} - -fn wasm_host_stat_value(metadata: &fs::Metadata) -> Value { - json!({ - "mode": metadata.mode(), - "size": metadata.size(), - "blocks": metadata.blocks(), - "dev": metadata.dev(), - "rdev": metadata.rdev(), - "isDirectory": metadata.is_dir(), - "isSymbolicLink": metadata.file_type().is_symlink(), - "atimeMs": metadata.atime() * 1000 + (metadata.atime_nsec() / 1_000_000), - "mtimeMs": metadata.mtime() * 1000 + (metadata.mtime_nsec() / 1_000_000), - "ctimeMs": metadata.ctime() * 1000 + (metadata.ctime_nsec() / 1_000_000), - "birthtimeMs": metadata.ctime() * 1000 + (metadata.ctime_nsec() / 1_000_000), - "ino": metadata.ino(), - "nlink": metadata.nlink(), - "uid": metadata.uid(), - "gid": metadata.gid(), - }) -} - -fn strip_guest_prefix(path: &str, prefix: &str) -> Option { - let normalized_path = normalize_guest_path(path); - let normalized_prefix = normalize_guest_path(prefix); - if normalized_path == normalized_prefix { - return Some(String::new()); - } - normalized_path - .strip_prefix(&(normalized_prefix + "/")) - .map(str::to_owned) -} - -fn join_host_path(base: &Path, suffix: &str) -> PathBuf { - if suffix.is_empty() { - return base.to_path_buf(); - } - suffix - .split('/') - .filter(|segment| !segment.is_empty()) - .fold(base.to_path_buf(), |path, segment| path.join(segment)) -} - -fn decode_wasm_bytes_arg( - value: Option<&Value>, - label: &'static str, - limit: usize, -) -> Result, WasmExecutionError> { - let base64 = value - .and_then(Value::as_object) - .and_then(|value| value.get("base64")) - .and_then(Value::as_str) - .ok_or_else(|| WasmExecutionError::RpcResponse(format!("missing {label}")))?; - let decoded_len = base64_decoded_len(base64) - .ok_or_else(|| WasmExecutionError::RpcResponse(format!("invalid {label} base64")))?; - if decoded_len > limit { - return Err(WasmExecutionError::OutputBufferExceeded { - stream: label, - limit, - }); - } - base64::engine::general_purpose::STANDARD - .decode(base64) - .map_err(|_| WasmExecutionError::RpcResponse(format!("invalid {label} base64"))) -} - -fn base64_decoded_len(base64: &str) -> Option { - let len = base64.len(); - let padding = base64 - .as_bytes() - .iter() - .rev() - .take_while(|byte| **byte == b'=') - .take(2) - .count(); - let full_quads = len / 4; - let remainder = len % 4; - let base_len = full_quads.checked_mul(3)?.checked_sub(padding)?; - match remainder { - 0 => Some(base_len), - 1 => None, - 2 => base_len.checked_add(1), - 3 => base_len.checked_add(2), - _ => None, - } -} - -fn append_wasm_captured_output( - buffer: &mut Vec, - chunk: &[u8], - stream: &'static str, -) -> Result<(), WasmExecutionError> { - ensure_wasm_output_capacity(buffer.len(), chunk.len(), stream)?; - buffer.extend_from_slice(chunk); - Ok(()) -} - -fn ensure_wasm_output_capacity( - current_len: usize, - chunk_len: usize, - stream: &'static str, -) -> Result<(), WasmExecutionError> { - let Some(next_len) = current_len.checked_add(chunk_len) else { - return Err(WasmExecutionError::OutputBufferExceeded { - stream, - limit: WASM_CAPTURED_OUTPUT_LIMIT_BYTES, - }); - }; - if next_len > WASM_CAPTURED_OUTPUT_LIMIT_BYTES { - return Err(WasmExecutionError::OutputBufferExceeded { - stream, - limit: WASM_CAPTURED_OUTPUT_LIMIT_BYTES, - }); - } - Ok(()) -} - -fn wasm_sync_read_length(length: Option) -> Result { - let length = length.unwrap_or(0); - let length = usize::try_from(length).map_err(|_| { - WasmExecutionError::InvalidLimit(format!("fs.readSync length {length} exceeds host usize")) - })?; - if length > WASM_SYNC_READ_LIMIT_BYTES { - return Err(WasmExecutionError::InvalidLimit(format!( - "fs.readSync length {length} exceeds maximum {WASM_SYNC_READ_LIMIT_BYTES}" - ))); - } - Ok(length) -} - -fn open_wasm_guest_file(path: &Path, flags: &Value) -> std::io::Result { - let mut options = OpenOptions::new(); - let flags_label = flags.to_string(); - - match flags.as_str() { - Some("r") | None if flags.as_u64().unwrap_or(0) == 0 => { - options.read(true); - } - Some("r+") => { - options.read(true).write(true); - } - Some("w") => { - options.write(true).create(true).truncate(true); - } - Some("w+") => { - options.read(true).write(true).create(true).truncate(true); - } - Some("a") => { - options.append(true).create(true); - } - Some("a+") => { - options.read(true).append(true).create(true); - } - _ => { - let numeric = flags.as_u64().ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidInput, - format!("unsupported fs.openSync flags: {flags_label}"), - ) - })?; - let write_only = (numeric & 0o1) != 0; - let read_write = (numeric & 0o2) != 0; - let create = (numeric & 0o100) != 0; - let truncate = (numeric & 0o1000) != 0; - let append = (numeric & 0o2000) != 0; - - if read_write { - options.read(true).write(true); - } else if write_only { - options.write(true); - } else { - options.read(true); - } - if create { - options.create(true); - } - if truncate { - options.truncate(true); - } - if append { - options.append(true); - } - } - } - - options.open(path).map_err(|error| { - std::io::Error::new( - error.kind(), - format!( - "failed to open guest file {} with flags {}: {error}", - path.display(), - flags_label - ), - ) - }) -} - -fn translate_wasm_signal_state_sync_rpc_request( - execution: &mut JavascriptExecution, - request: &JavascriptSyncRpcRequest, -) -> Result, WasmExecutionError> { - if request.method != "process.signal_state" { - return Ok(None); - } - - let signal = request - .args - .first() - .and_then(Value::as_u64) - .ok_or_else(|| WasmExecutionError::RpcResponse(String::from("missing signal number")))?; - let action = match request - .args - .get(1) - .and_then(Value::as_str) - .unwrap_or("default") - { - "ignore" => WasmSignalDispositionAction::Ignore, - "user" => WasmSignalDispositionAction::User, - _ => WasmSignalDispositionAction::Default, - }; - let mask = request - .args - .get(2) - .and_then(Value::as_str) - .map(serde_json::from_str::>) - .transpose() - .map_err(|error| WasmExecutionError::RpcResponse(error.to_string()))? - .unwrap_or_default(); - let flags = request - .args - .get(3) - .and_then(Value::as_u64) - .unwrap_or_default() as u32; - - execution - .respond_sync_rpc_success(request.id, Value::Null) - .map_err(map_javascript_error)?; - - Ok(Some(WasmExecutionEvent::SignalState { - signal: signal as u32, - registration: WasmSignalHandlerRegistration { - action, - mask, - flags, - }, - })) -} - -fn parse_wasm_signal_state_line( - line: &[u8], -) -> Result, WasmExecutionError> { - let line = line.strip_suffix(b"\n").unwrap_or(line); - let line = line.strip_suffix(b"\r").unwrap_or(line); - let payload = match line.strip_prefix(WASM_SIGNAL_STATE_PREFIX.as_bytes()) { - Some(payload) => payload, - None => return Ok(None), - }; - let payload = std::str::from_utf8(payload) - .map_err(|error| WasmExecutionError::RpcResponse(error.to_string()))?; - let message: Value = serde_json::from_str(payload) - .map_err(|error| WasmExecutionError::RpcResponse(error.to_string()))?; - let signal = message - .get("signal") - .and_then(Value::as_u64) - .ok_or_else(|| WasmExecutionError::RpcResponse(String::from("missing signal number")))?; - let registration = message - .get("registration") - .and_then(Value::as_object) - .ok_or_else(|| { - WasmExecutionError::RpcResponse(String::from("missing signal registration")) - })?; - let action = match registration - .get("action") - .and_then(Value::as_str) - .unwrap_or("default") - { - "ignore" => WasmSignalDispositionAction::Ignore, - "user" => WasmSignalDispositionAction::User, - _ => WasmSignalDispositionAction::Default, - }; - let mask = registration - .get("mask") - .and_then(Value::as_array) - .map(|entries| { - entries - .iter() - .filter_map(Value::as_u64) - .map(|value| value as u32) - .collect::>() - }) - .unwrap_or_default(); - let flags = registration - .get("flags") - .and_then(Value::as_u64) - .unwrap_or_default() as u32; - - Ok(Some(WasmExecutionEvent::SignalState { - signal: signal as u32, - registration: WasmSignalHandlerRegistration { - action, - mask, - flags, - }, - })) -} - -struct WasmJavascriptExecutionOptions<'a> { - frozen_time_ms: u128, - prewarm_only: bool, - warmup_metrics: Option<&'a [u8]>, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum WasmSnapshotRunnerMode { - Auto, - Block, - Off, -} - -fn wasm_snapshot_runner_mode() -> WasmSnapshotRunnerMode { - match std::env::var(WASM_SNAPSHOT_RUNNER_ENV) { - Ok(value) if value.eq_ignore_ascii_case("block") => WasmSnapshotRunnerMode::Block, - Ok(value) if value.eq_ignore_ascii_case("off") => WasmSnapshotRunnerMode::Off, - Ok(value) if value.eq_ignore_ascii_case("auto") => WasmSnapshotRunnerMode::Auto, - Ok(value) => { - tracing::warn!( - value, - "{WASM_SNAPSHOT_RUNNER_ENV} must be auto, block, or off; using auto" - ); - WasmSnapshotRunnerMode::Auto - } - Err(_) => WasmSnapshotRunnerMode::Auto, - } -} - -fn start_wasm_javascript_execution( - javascript_engine: &mut JavascriptExecutionEngine, - import_cache: &NodeImportCache, - javascript_context_id: &str, - resolved_module: &ResolvedWasmModule, - request: &StartWasmExecutionRequest, - options: WasmJavascriptExecutionOptions<'_>, -) -> Result { - let wasm_module_bytes = cached_wasm_module_bytes(&resolved_module.resolved_path)?; - let internal_env = build_wasm_internal_env( - resolved_module, - request, - options.frozen_time_ms, - options.prewarm_only, - )?; - let snapshot_mode = wasm_snapshot_runner_mode(); - let mut env = wasm_runner_base_env(request); - let mut guest_runtime = request.guest_runtime.clone(); - - let inline_code = match snapshot_mode { - WasmSnapshotRunnerMode::Off => { - env.extend( - internal_env - .iter() - .map(|(key, value)| (key.clone(), value.clone())), - ); - build_wasm_runner_module_source(import_cache, &internal_env, options.warmup_metrics)? - } - WasmSnapshotRunnerMode::Auto | WasmSnapshotRunnerMode::Block => { - let userland_bundle = build_wasm_runner_userland_bundle(import_cache)?; - let runner_heap_limit_mb = wasm_runner_heap_limit_mb(request); - V8RuntimeHost::warm_snapshot_async(userland_bundle.clone()); - let use_snapshot = match snapshot_mode { - WasmSnapshotRunnerMode::Block => { - if !javascript_engine - .snapshot_userland_ready(&userland_bundle) - .map_err(map_javascript_error)? - { - javascript_engine - .pre_warm_snapshot(&userland_bundle) - .map_err(map_javascript_error)?; - } - javascript_engine - .pre_warm_workers( - &userland_bundle, - runner_heap_limit_mb, - v8_warm_worker_count(), - ) - .map_err(map_javascript_error)?; - javascript_engine - .pre_warm_workers("", 0, v8_warm_worker_count()) - .map_err(map_javascript_error)?; - true - } - WasmSnapshotRunnerMode::Auto => javascript_engine - .snapshot_userland_ready(&userland_bundle) - .unwrap_or(false), - WasmSnapshotRunnerMode::Off => false, - }; - - if use_snapshot { - env = wasm_snapshot_runner_base_env(request); - env.extend( - internal_env - .iter() - .map(|(key, value)| (key.clone(), value.clone())), - ); - guest_runtime.snapshot_userland_code = Some(userland_bundle); - build_wasm_snapshot_runner_inline_code(options.warmup_metrics) - } else { - env.extend( - internal_env - .iter() - .map(|(key, value)| (key.clone(), value.clone())), - ); - build_wasm_runner_module_source( - import_cache, - &internal_env, - options.warmup_metrics, - )? - } - } - }; - - javascript_engine - .start_execution(StartJavascriptExecutionRequest { - vm_id: request.vm_id.clone(), - context_id: javascript_context_id.to_owned(), - argv: vec![String::from(WASM_INLINE_RUNNER_ENTRYPOINT)], - env, - cwd: request.cwd.clone(), - // Guest WASM fuel/memory caps are enforced from `request.limits`, - // and stack caps are validated there until runtime stack enforcement - // lands. These are separate from the runner's V8 heap: the trusted - // runner still has to compile the WASI runtime + guest module into - // its own isolate, which can overflow the 128 MiB per-guest default, - // so size the runner heap explicitly (operator-tunable). - limits: JavascriptExecutionLimits { - v8_heap_limit_mb: Some(wasm_runner_heap_limit_mb(request)), - ..JavascriptExecutionLimits::default() - }, - // Forward the guest-runtime identity so the runner's shim sets - // process.* from typed config rather than env. - guest_runtime, - inline_code: Some(inline_code), - wasm_module_bytes: Some(wasm_module_bytes), - }) - .map_err(map_javascript_error) -} - -struct WasmModuleBytesCache { - entries: HashMap>)>, -} - -fn wasm_module_bytes_cache() -> &'static Mutex { - static CACHE: OnceLock> = OnceLock::new(); - CACHE.get_or_init(|| { - Mutex::new(WasmModuleBytesCache { - entries: HashMap::new(), - }) - }) -} - -fn cached_wasm_module_bytes(path: &Path) -> Result>, WasmExecutionError> { - let current_fingerprint = file_fingerprint(path); - { - let cache = wasm_module_bytes_cache() - .lock() - .expect("wasm module bytes cache lock poisoned"); - if let Some((fingerprint, bytes)) = cache.entries.get(path) { - if fingerprint == ¤t_fingerprint { - return Ok(Arc::clone(bytes)); - } - } - } - - let module_bytes = Arc::new(fs::read(path).map_err(WasmExecutionError::PrepareWarmPath)?); - let fingerprint = file_fingerprint(path); - let mut cache = wasm_module_bytes_cache() - .lock() - .expect("wasm module bytes cache lock poisoned"); - if !cache.entries.contains_key(path) && cache.entries.len() >= WASM_MODULE_BYTES_CACHE_CAPACITY - { - if let Some(evicted_path) = cache.entries.keys().next().cloned() { - cache.entries.remove(&evicted_path); - tracing::warn!( - path = %evicted_path.display(), - "evicting cached wasm module bytes entry" - ); - } - } - cache - .entries - .insert(path.to_path_buf(), (fingerprint, Arc::clone(&module_bytes))); - let cumulative_bytes: usize = cache.entries.values().map(|(_, bytes)| bytes.len()).sum(); - tracing::debug!( - path = %path.display(), - raw_bytes = module_bytes.len(), - cumulative_bytes, - "cached wasm module bytes entry" - ); - Ok(module_bytes) -} - -fn build_wasm_internal_env( - resolved_module: &ResolvedWasmModule, - request: &StartWasmExecutionRequest, - frozen_time_ms: u128, - prewarm_only: bool, -) -> Result, WasmExecutionError> { - let guest_path_mappings = wasm_guest_path_mappings(request); - let mut internal_env = request - .env - .iter() - .filter(|(key, _)| key.starts_with("AGENTOS_")) - .map(|(key, value)| (key.clone(), value.clone())) - .collect::>(); - if let Some(value) = request.env.get("SECURE_EXEC_KEEP_STDIN_OPEN") { - internal_env.insert(String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), value.clone()); - } - scrub_migrated_wasm_limit_env(&mut internal_env); - insert_optional_u64_env( - &mut internal_env, - WASM_MAX_MEMORY_BYTES_ENV, - request.limits.max_memory_bytes, - ); - internal_env.insert( - WASM_MODULE_PATH_ENV.to_string(), - resolved_module.specifier.clone(), - ); - internal_env.insert( - String::from("AGENTOS_FORWARD_KERNEL_STDIN_RPC"), - String::from("1"), - ); - internal_env.insert( - WASM_GUEST_ARGV_ENV.to_string(), - encode_json_string_array(&warmup_guest_argv(resolved_module, request)), - ); - internal_env.insert( - WASM_GUEST_ENV_ENV.to_string(), - encode_json_string_map(&guest_visible_wasm_env(&request.env)), - ); - insert_wasm_runner_identity_env(&mut internal_env, &request.guest_runtime); - internal_env.insert( - WASM_HOST_CWD_ENV.to_string(), - request.cwd.to_string_lossy().into_owned(), - ); - internal_env.insert( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - encode_wasm_guest_path_mappings(&guest_path_mappings), - ); - internal_env.insert( - WASM_PERMISSION_TIER_ENV.to_string(), - request.permission_tier.as_env_value().to_string(), - ); - internal_env.insert( - String::from("AGENTOS_FROZEN_TIME_MS"), - frozen_time_ms.to_string(), - ); - - if prewarm_only { - internal_env.insert(WASM_PREWARM_ONLY_ENV.to_string(), String::from("1")); - } else { - internal_env.remove(WASM_PREWARM_ONLY_ENV); - } - Ok(internal_env) -} - -fn wasm_runner_base_env(request: &StartWasmExecutionRequest) -> BTreeMap { - let mut env = request.env.clone(); - scrub_migrated_wasm_limit_env(&mut env); - env -} - -fn wasm_snapshot_runner_base_env(request: &StartWasmExecutionRequest) -> BTreeMap { - let mut env = request - .env - .iter() - .filter(|(key, _)| !is_internal_wasm_guest_env_key(key)) - .map(|(key, value)| (key.clone(), value.clone())) - .collect::>(); - scrub_migrated_wasm_limit_env(&mut env); - env -} - -fn scrub_migrated_wasm_limit_env(env: &mut BTreeMap) { - for key in [ - WASM_MAX_FUEL_ENV, - WASM_MAX_MEMORY_BYTES_ENV, - WASM_MAX_STACK_BYTES_ENV, - "AGENTOS_WASM_PREWARM_TIMEOUT_MS", - "AGENTOS_WASM_RUNNER_HEAP_LIMIT_MB", - ] { - env.remove(key); - } -} - -fn insert_optional_u64_env(env: &mut BTreeMap, key: &str, value: Option) { - if let Some(value) = value { - env.insert(key.to_string(), value.to_string()); - } else { - env.remove(key); - } -} - -fn insert_wasm_runner_identity_env( - env: &mut BTreeMap, - guest_runtime: &GuestRuntimeConfig, -) { - insert_optional_u64_env( - env, - "AGENTOS_VIRTUAL_PROCESS_UID", - guest_runtime.virtual_uid, - ); - insert_optional_u64_env( - env, - "AGENTOS_VIRTUAL_PROCESS_GID", - guest_runtime.virtual_gid, - ); - insert_optional_u64_env( - env, - "AGENTOS_VIRTUAL_PROCESS_PID", - guest_runtime.virtual_pid, - ); - insert_optional_u64_env( - env, - "AGENTOS_VIRTUAL_PROCESS_PPID", - guest_runtime.virtual_ppid, - ); -} - -fn build_wasm_runner_module_source( - import_cache: &NodeImportCache, - internal_env: &BTreeMap, - warmup_metrics: Option<&[u8]>, -) -> Result { - let runner_source = transformed_wasm_runner_source(import_cache)?; - let bootstrap = build_wasm_runner_bootstrap(internal_env, warmup_metrics); - Ok(insert_wasm_runner_bootstrap(&runner_source, &bootstrap)) -} - -fn transformed_wasm_runner_source( - import_cache: &NodeImportCache, -) -> Result { - if std::env::var(WASM_RUNNER_NO_CACHE_ENV).as_deref() == Ok("1") { - return read_transformed_wasm_runner_source(import_cache); - } - - static RUNNER_SOURCE: OnceLock, Arc>> = OnceLock::new(); - RUNNER_SOURCE - .get_or_init(|| { - read_transformed_wasm_runner_source(import_cache) - .map(Arc::::from) - .map_err(|error| Arc::::from(error.to_string())) - }) - .as_ref() - .map(|source| source.to_string()) - .map_err(|message| { - WasmExecutionError::PrepareWarmPath(std::io::Error::other(message.to_string())) - }) -} - -fn read_transformed_wasm_runner_source( - import_cache: &NodeImportCache, -) -> Result { - let runner_source = fs::read_to_string(import_cache.wasm_runner_path()) - .map_err(WasmExecutionError::PrepareWarmPath)?; - Ok(runner_source.replace( - "import { WASI } from 'node:wasi';\n", - "const { WASI } = globalThis.__agentOSWasiModule;\n", - )) -} - -fn build_wasm_runner_userland_bundle( - import_cache: &NodeImportCache, -) -> Result { - if std::env::var(WASM_RUNNER_NO_CACHE_ENV).as_deref() == Ok("1") { - return build_wasm_runner_userland_bundle_uncached(import_cache); - } - - static USERLAND_BUNDLE: OnceLock, Arc>> = OnceLock::new(); - USERLAND_BUNDLE - .get_or_init(|| { - build_wasm_runner_userland_bundle_uncached(import_cache) - .map(Arc::::from) - .map_err(|error| Arc::::from(error.to_string())) - }) - .as_ref() - .map(|bundle| bundle.to_string()) - .map_err(|message| { - WasmExecutionError::PrepareWarmPath(std::io::Error::other(message.to_string())) - }) -} - -fn build_wasm_runner_userland_bundle_uncached( - import_cache: &NodeImportCache, -) -> Result { - let runner_source = transformed_wasm_runner_source(import_cache)?; - if runner_source - .lines() - .any(|line| line.trim_start().starts_with("import ")) - { - return Err(WasmExecutionError::PrepareWarmPath(std::io::Error::other( - "transformed wasm runner still contains an ESM import statement", - ))); - } - - let mut bundle = build_wasm_runner_snapshot_prelude(); - bundle.push_str("\nglobalThis.__agentOSWasmRunnerRun = async function () {\n"); - bundle.push_str(&runner_source); - bundle.push_str("\n};\n"); - Ok(bundle) -} - -fn build_wasm_runner_snapshot_prelude() -> String { - let bootstrap = build_wasm_runner_bootstrap(&BTreeMap::new(), None); - let bootstrap = bootstrap - .strip_prefix("const __agentOSWasmInternalEnv = {};\n") - .unwrap_or(&bootstrap); - bootstrap.replace(wasm_internal_env_merge_source(), "") -} - -fn build_wasm_snapshot_runner_inline_code(warmup_metrics: Option<&[u8]>) -> String { - let warmup_emit = wasm_warmup_metrics_emit_source(warmup_metrics); - format!( - r#"{warmup_emit}if (typeof process !== "undefined" && typeof globalThis.__agentOSProcessConfigEnv === "object") {{ - process.env = {{ ...(process.env || {{}}), ...globalThis.__agentOSProcessConfigEnv }}; -}} -await globalThis.__agentOSWasmRunnerRun();"# - ) -} - -fn build_wasm_runner_bootstrap( - internal_env: &BTreeMap, - warmup_metrics: Option<&[u8]>, -) -> String { - let internal_env_json = - serde_json::to_string(internal_env).unwrap_or_else(|_| String::from("{}")); - let warmup_emit = wasm_warmup_metrics_emit_source(warmup_metrics); - let wasi_module_source = render_native_wasi_module_source(); - let env_merge_source = wasm_internal_env_merge_source(); - - format!( - r#"const __agentOSWasmInternalEnv = {internal_env_json}; -const __agentOSRequireBuiltin = (specifier) => {{ - if (typeof globalThis.require === "function") {{ - return globalThis.require(specifier); - }} - if (typeof process?.getBuiltinModule === "function") {{ - return process.getBuiltinModule(specifier); - }} - throw new Error(`secure-exec WASM bootstrap cannot load ${{specifier}}`); -}}; -{wasi_module_source} -{env_merge_source} -if (typeof globalThis !== "undefined") {{ - const __agentOSNormalizeBytes = (value) => {{ - if (value == null) {{ - return value; - }} - if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) {{ - return value; - }} - if (value instanceof Uint8Array) {{ - return Buffer.from(value); - }} - if (ArrayBuffer.isView(value)) {{ - return Buffer.from(value.buffer, value.byteOffset, value.byteLength); - }} - if (value instanceof ArrayBuffer) {{ - return Buffer.from(value); - }} - if ( - value && - typeof value === "object" && - value.__agentOSType === "bytes" && - typeof value.base64 === "string" - ) {{ - return Buffer.from(value.base64, "base64"); - }} - return value; - }}; - const __agentOSWasmSyncRpc = {{ - callSync(method, args = []) {{ - switch (method) {{ - case "fs.fstatSync": - return __agentOSRequireBuiltin("node:fs").fstatSync(...args); - case "fs.lstatSync": - return __agentOSRequireBuiltin("node:fs").lstatSync(...args); - case "fs.statSync": - return __agentOSRequireBuiltin("node:fs").statSync(...args); - case "fs.chmodSync": - return __agentOSRequireBuiltin("node:fs").chmodSync(...args); - case "__kernel_stdio_write": - if (typeof _kernelStdioWriteRaw === "undefined") {{ - throw new Error("secure-exec WASM kernel stdio bridge is unavailable"); - }} - return _kernelStdioWriteRaw.applySync(void 0, args); - case "__kernel_stdin_read": - if (typeof _kernelStdinReadRaw === "undefined") {{ - throw new Error("secure-exec WASM kernel stdin bridge is unavailable"); - }} - return _kernelStdinReadRaw.applySync(void 0, args); - case "__kernel_poll": - if (typeof _kernelPollRaw === "undefined") {{ - throw new Error("secure-exec WASM kernel poll bridge is unavailable"); - }} - return _kernelPollRaw.applySync(void 0, args); - case "__kernel_isatty": - if (typeof _kernelIsattyRaw === "undefined") {{ - throw new Error("secure-exec WASM kernel isatty bridge is unavailable"); - }} - return _kernelIsattyRaw.applySync(void 0, args); - case "__kernel_tty_size": - if (typeof _kernelTtySizeRaw === "undefined") {{ - throw new Error("secure-exec WASM kernel tty size bridge is unavailable"); - }} - return _kernelTtySizeRaw.applySync(void 0, args); - case "__pty_set_raw_mode": - if (typeof _ptySetRawMode === "undefined") {{ - throw new Error("secure-exec WASM PTY raw-mode bridge is unavailable"); - }} - return _ptySetRawMode.applySync(void 0, args); - case "child_process.spawn": {{ - if (typeof _childProcessSpawnStart === "undefined") {{ - throw new Error("secure-exec WASM child_process bridge is unavailable"); - }} - const [request] = args; - return _childProcessSpawnStart.applySync(void 0, [ - request?.command ?? "", - JSON.stringify(request?.args ?? []), - JSON.stringify(request?.options ?? {{}}), - ]); - }} - case "child_process.poll": - if (typeof _childProcessPoll === "undefined") {{ - throw new Error("secure-exec WASM child_process poll bridge is unavailable"); - }} - return _childProcessPoll.applySync(void 0, args); - case "child_process.kill": - if (typeof _childProcessKill === "undefined") {{ - throw new Error("secure-exec WASM child_process kill bridge is unavailable"); - }} - return _childProcessKill.applySync(void 0, args); - case "process.kill": - if (typeof _processKill === "undefined") {{ - throw new Error("secure-exec WASM process kill bridge is unavailable"); - }} - return _processKill.applySync(void 0, args); - case "child_process.write_stdin": {{ - if (typeof _childProcessStdinWrite === "undefined") {{ - throw new Error("secure-exec WASM child_process stdin bridge is unavailable"); - }} - const [childId, chunk] = args; - return _childProcessStdinWrite.applySync(void 0, [ - childId, - __agentOSNormalizeBytes(chunk), - ]); - }} - case "child_process.close_stdin": - if (typeof _childProcessStdinClose === "undefined") {{ - throw new Error("secure-exec WASM child_process stdin-close bridge is unavailable"); - }} - return _childProcessStdinClose.applySync(void 0, args); - case "net.connect": - if (typeof _netSocketConnectRaw === "undefined") {{ - throw new Error("secure-exec WASM net.connect bridge is unavailable"); - }} - return _netSocketConnectRaw.applySync(void 0, args); - case "net.reserve_tcp_port": - if (typeof _netReserveTcpPortRaw === "undefined") {{ - throw new Error("secure-exec WASM net.reserve_tcp_port bridge is unavailable"); - }} - return _netReserveTcpPortRaw.applySync(void 0, args); - case "net.release_tcp_port": - if (typeof _netReleaseTcpPortRaw === "undefined") {{ - throw new Error("secure-exec WASM net.release_tcp_port bridge is unavailable"); - }} - return _netReleaseTcpPortRaw.applySync(void 0, args); - case "net.listen": - if (typeof _netServerListenRaw === "undefined") {{ - throw new Error("secure-exec WASM net.listen bridge is unavailable"); - }} - return _netServerListenRaw.applySync(void 0, args); - case "net.server_accept": - if (typeof _netServerAcceptRaw === "undefined") {{ - throw new Error("secure-exec WASM net.server_accept bridge is unavailable"); - }} - return _netServerAcceptRaw.applySync(void 0, args); - case "net.poll": - if (typeof _netSocketPollRaw === "undefined") {{ - throw new Error("secure-exec WASM net.poll bridge is unavailable"); - }} - return _netSocketPollRaw.applySync(void 0, args); - case "net.write": - if (typeof _netSocketWriteRaw === "undefined") {{ - throw new Error("secure-exec WASM net.write bridge is unavailable"); - }} - return _netSocketWriteRaw.applySync(void 0, args); - case "net.destroy": - if (typeof _netSocketDestroyRaw === "undefined") {{ - throw new Error("secure-exec WASM net.destroy bridge is unavailable"); - }} - return _netSocketDestroyRaw.applySync(void 0, args); - case "net.socket_upgrade_tls": - if (typeof _netSocketUpgradeTlsRaw === "undefined") {{ - throw new Error("secure-exec WASM TLS-upgrade bridge is unavailable"); - }} - return _netSocketUpgradeTlsRaw.applySync(void 0, args); - case "dgram.createSocket": - if (typeof _dgramSocketCreateRaw === "undefined") {{ - throw new Error("secure-exec WASM dgram.createSocket bridge is unavailable"); - }} - return _dgramSocketCreateRaw.applySync(void 0, args); - case "dgram.bind": - if (typeof _dgramSocketBindRaw === "undefined") {{ - throw new Error("secure-exec WASM dgram.bind bridge is unavailable"); - }} - return _dgramSocketBindRaw.applySync(void 0, args); - case "dgram.send": {{ - if (typeof _dgramSocketSendRaw === "undefined") {{ - throw new Error("secure-exec WASM dgram.send bridge is unavailable"); - }} - const [socketId, chunk, options = {{}}] = args; - return _dgramSocketSendRaw.applySync(void 0, [ - socketId, - __agentOSNormalizeBytes(chunk), - options, - ]); - }} - case "dgram.poll": - if (typeof _dgramSocketRecvRaw === "undefined") {{ - throw new Error("secure-exec WASM dgram.poll bridge is unavailable"); - }} - const event = _dgramSocketRecvRaw.applySync(void 0, args); - if (event && event.type === "message") {{ - const data = __agentOSNormalizeBytes(event.data); - if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {{ - return {{ - ...event, - data: {{ base64: data.toString("base64") }}, - }}; - }} - }} - if ( - event && - event.type === "message" && - event.data && - typeof event.data === "object" && - typeof event.data.base64 === "string" - ) {{ - return {{ - ...event, - data: {{ base64: event.data.base64 }}, - }}; - }} - return event; - case "dgram.close": - if (typeof _dgramSocketCloseRaw === "undefined") {{ - throw new Error("secure-exec WASM dgram.close bridge is unavailable"); - }} - return _dgramSocketCloseRaw.applySync(void 0, args); - case "dgram.address": - if (typeof _dgramSocketAddressRaw === "undefined") {{ - throw new Error("secure-exec WASM dgram.address bridge is unavailable"); - }} - return _dgramSocketAddressRaw.applySync(void 0, args); - case "dgram.setBufferSize": - if (typeof _dgramSocketSetBufferSizeRaw === "undefined") {{ - throw new Error("secure-exec WASM dgram.setBufferSize bridge is unavailable"); - }} - return _dgramSocketSetBufferSizeRaw.applySync(void 0, args); - case "dgram.getBufferSize": - if (typeof _dgramSocketGetBufferSizeRaw === "undefined") {{ - throw new Error("secure-exec WASM dgram.getBufferSize bridge is unavailable"); - }} - return _dgramSocketGetBufferSizeRaw.applySync(void 0, args); - case "dns.lookup": - if (typeof _networkDnsLookupSyncRaw === "undefined") {{ - throw new Error("secure-exec WASM dns.lookup bridge is unavailable"); - }} - return _networkDnsLookupSyncRaw.applySync(void 0, args); - case "process.signal_state": {{ - if (typeof _processSignalState === "undefined") {{ - throw new Error("secure-exec WASM signal-state bridge is unavailable"); - }} - const [signal, action = "default", maskJson = "[]", flags = 0] = args; - return _processSignalState.applySyncPromise(void 0, [ - signal, - action, - maskJson, - flags, - ]); - }} - default: - throw new Error(`secure-exec WASM sync RPC method not implemented in V8 runtime: ${{method}}`); - }} - }}, - async call(method, args = []) {{ - return this.callSync(method, args); - }}, - }}; - Object.defineProperty(globalThis, "__agentOSSyncRpc", {{ - configurable: true, - enumerable: false, - value: __agentOSWasmSyncRpc, - writable: true, - }}); -}} -{warmup_emit}"# - ) -} - -fn wasm_warmup_metrics_emit_source(warmup_metrics: Option<&[u8]>) -> String { - let warmup_metrics_json = warmup_metrics.map(|bytes| { - serde_json::to_string(&String::from_utf8_lossy(bytes).to_string()) - .unwrap_or_else(|_| String::from("\"\"")) - }); - warmup_metrics_json - .map(|metrics| { - format!( - "if (typeof process?.stderr?.write === \"function\") {{\n process.stderr.write({metrics});\n}}\n" - ) - }) - .unwrap_or_default() -} - -fn wasm_internal_env_merge_source() -> &'static str { - r#"if (typeof process !== "undefined") { - process.env = { ...(process.env || {}), ...__agentOSWasmInternalEnv }; -} -"# -} - -fn render_native_wasi_module_source() -> &'static str { - static SOURCE: OnceLock = OnceLock::new(); - SOURCE.get_or_init(|| { - NODE_WASI_MODULE_SOURCE.replace( - "__SECURE_EXEC_WASM_SYNC_READ_LIMIT_BYTES__", - &WASM_SYNC_READ_LIMIT_BYTES.to_string(), - ) - }) -} - -fn insert_wasm_runner_bootstrap(source: &str, bootstrap: &str) -> String { - let mut insert_at = 0usize; - let mut saw_import = false; - for line in source.split_inclusive('\n') { - let trimmed = line.trim_start(); - if trimmed.starts_with("import ") || (saw_import && trimmed.is_empty()) { - insert_at += line.len(); - saw_import = saw_import || trimmed.starts_with("import "); - continue; - } - break; - } - - format!( - "{}{}{}", - &source[..insert_at], - bootstrap, - &source[insert_at..] - ) -} - -fn prewarm_wasm_path( - import_cache: &NodeImportCache, - javascript_engine: &mut JavascriptExecutionEngine, - javascript_context_id: &str, - resolved_module: &ResolvedWasmModule, - request: &StartWasmExecutionRequest, - frozen_time_ms: u128, - prewarm_timeout: Duration, -) -> Result>, WasmExecutionError> { - let debug_enabled = env_flag_enabled(&request.env, WASM_WARMUP_DEBUG_ENV); - let marker_contents = warmup_marker_contents(resolved_module); - let marker_path = warmup_marker_path( - import_cache.prewarm_marker_dir(), - "wasm-runner-prewarm", - WASM_WARMUP_MARKER_VERSION, - &marker_contents, - ); - - if let Ok(metadata) = fs::metadata(&resolved_module.resolved_path) { - if metadata.len() > MAX_SYNC_WASM_PREWARM_MODULE_BYTES { - return Ok(warmup_metrics_line( - debug_enabled, - false, - "skipped-large-module", - import_cache, - &resolved_module.specifier, - )); - } - } - - if marker_path.exists() { - return Ok(warmup_metrics_line( - debug_enabled, - false, - "cached", - import_cache, - &resolved_module.specifier, - )); - } - - let mut prewarm_execution = start_wasm_javascript_execution( - javascript_engine, - import_cache, - javascript_context_id, - resolved_module, - request, - WasmJavascriptExecutionOptions { - frozen_time_ms, - prewarm_only: true, - warmup_metrics: None, - }, - ) - .map_err(|error| match error { - WasmExecutionError::Spawn(err) => WasmExecutionError::WarmupSpawn(err), - other => other, - })?; - let mut internal_sync_rpc = WasmInternalSyncRpc { - module_guest_paths: wasm_guest_module_paths(&resolved_module.specifier, &request.env), - module_host_path: resolved_module.resolved_path.clone(), - guest_cwd: wasm_guest_cwd(&request.env), - host_cwd: request.cwd.clone(), - sandbox_root: wasm_sandbox_root(&request.env), - guest_path_mappings: wasm_guest_path_mappings(request), - route_fs_through_sidecar: false, - next_fd: 64, - open_files: BTreeMap::new(), - pending_events: VecDeque::new(), - }; - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let started = Instant::now(); - - loop { - let poll_timeout = prewarm_timeout.saturating_sub(started.elapsed()); - if poll_timeout.is_zero() { - let _ = prewarm_execution.terminate(); - return Err(WasmExecutionError::WarmupTimeout(prewarm_timeout)); - } - - match prewarm_execution - .poll_event_blocking(poll_timeout) - .map_err(map_javascript_error)? - { - Some(JavascriptExecutionEvent::Stdout(chunk)) => { - append_wasm_captured_output(&mut stdout, &chunk, "stdout")?; - } - Some(JavascriptExecutionEvent::Stderr(chunk)) => { - append_wasm_captured_output(&mut stderr, &chunk, "stderr")?; - } - Some(JavascriptExecutionEvent::Exited(exit_code)) => { - if exit_code != 0 { - return Err(WasmExecutionError::WarmupFailed { - exit_code, - stderr: String::from_utf8_lossy(&stderr).into_owned(), - }); - } - break; - } - Some(JavascriptExecutionEvent::SyncRpcRequest(sync_request)) => { - let handled = handle_internal_wasm_sync_rpc_request( - &mut prewarm_execution, - &mut internal_sync_rpc, - &sync_request, - )?; - if !handled { - return Err(WasmExecutionError::WarmupFailed { - exit_code: 1, - stderr: format!( - "unexpected WebAssembly prewarm sync RPC request {} {} {:?}", - sync_request.id, sync_request.method, sync_request.args - ), - }); - } - } - Some(JavascriptExecutionEvent::SignalState { .. }) => {} - None => { - let _ = prewarm_execution.terminate(); - return Err(WasmExecutionError::WarmupTimeout(prewarm_timeout)); - } - } - } - - let _ = stdout; - fs::write(&marker_path, marker_contents).map_err(WasmExecutionError::PrepareWarmPath)?; - Ok(warmup_metrics_line( - debug_enabled, - true, - "executed", - import_cache, - &resolved_module.specifier, - )) -} - -fn wasm_guest_module_paths(specifier: &str, env: &BTreeMap) -> Vec { - let mut candidates = Vec::new(); - candidates.push(specifier.to_owned()); - - if specifier.starts_with('/') { - candidates.push(normalize_guest_path(specifier)); - candidates.extend(mapped_guest_paths_for_host_path(Path::new(specifier), env)); - } else if !specifier.starts_with("file:") { - let guest_cwd = wasm_guest_cwd(env); - candidates.push(join_guest_path(&guest_cwd, specifier)); - } - - candidates.sort(); - candidates.dedup(); - candidates -} - -fn wasm_guest_cwd(env: &BTreeMap) -> String { - env.get("PWD") - .filter(|value| value.starts_with('/')) - .cloned() - .or_else(|| { - env.get("HOME") - .filter(|value| value.starts_with('/')) - .cloned() - }) - .unwrap_or_else(|| String::from(DEFAULT_WASM_GUEST_HOME)) -} - -fn mapped_guest_paths_for_host_path( - host_path: &Path, - env: &BTreeMap, -) -> Vec { - if !host_path.is_absolute() { - return Vec::new(); - } - - let mappings = env - .get("AGENTOS_GUEST_PATH_MAPPINGS") - .and_then(|value| serde_json::from_str::>(value).ok()) - .unwrap_or_default(); - - let mut candidates = Vec::new(); - for mapping in mappings { - let Some(guest_root) = mapping.get("guestPath").and_then(Value::as_str) else { - continue; - }; - let Some(host_root) = mapping.get("hostPath").and_then(Value::as_str) else { - continue; - }; - let host_root = Path::new(host_root); - - if let Ok(suffix) = host_path.strip_prefix(host_root) { - candidates.push(join_guest_path( - guest_root, - &suffix.to_string_lossy().replace('\\', "/"), - )); - continue; - } - - let Ok(real_host_root) = host_root.canonicalize() else { - continue; - }; - if let Ok(suffix) = host_path.strip_prefix(&real_host_root) { - candidates.push(join_guest_path( - guest_root, - &suffix.to_string_lossy().replace('\\', "/"), - )); - } - } - - candidates -} - -fn normalize_guest_path(path: &str) -> String { - join_guest_path("/", path) -} - -fn join_guest_path(base: &str, suffix: &str) -> String { - let mut segments = Vec::new(); - let mut absolute = false; - for part in [base, suffix] { - if part.starts_with('/') { - absolute = true; - } - for segment in part.split('/') { - match segment { - "" | "." => {} - ".." => { - let _ = segments.pop(); - } - value => segments.push(value), - } - } - } - - let joined = segments.join("/"); - if absolute { - if joined.is_empty() { - String::from("/") - } else { - format!("/{joined}") - } - } else if joined.is_empty() { - String::from(".") - } else { - joined - } -} - -fn module_path( - context: &WasmContext, - request: &StartWasmExecutionRequest, -) -> Result { - match context.module_path.as_deref() { - Some(module_path) => Ok(module_path.to_owned()), - None => request - .argv - .first() - .cloned() - .ok_or(WasmExecutionError::MissingModulePath), - } -} - -fn guest_visible_wasm_env(env: &BTreeMap) -> BTreeMap { - let mut guest_env = env - .iter() - .filter(|(key, _)| !is_internal_wasm_guest_env_key(key)) - .map(|(key, value)| (key.clone(), value.clone())) - .collect::>(); - let guest_cwd = wasm_guest_cwd(env); - let guest_home = guest_env - .get("HOME") - .filter(|value| value.starts_with('/')) - .cloned() - .unwrap_or_else(|| guest_cwd.clone()); - - guest_env - .entry(String::from("HOME")) - .or_insert_with(|| guest_home.clone()); - guest_env - .entry(String::from("PWD")) - .or_insert_with(|| guest_cwd); - guest_env - .entry(String::from("USER")) - .or_insert_with(|| String::from(DEFAULT_WASM_GUEST_USER)); - guest_env - .entry(String::from("LOGNAME")) - .or_insert_with(|| String::from(DEFAULT_WASM_GUEST_USER)); - guest_env - .entry(String::from("SHELL")) - .or_insert_with(|| String::from(DEFAULT_WASM_GUEST_SHELL)); - guest_env - .entry(String::from("PATH")) - .or_insert_with(|| String::from(DEFAULT_WASM_GUEST_PATH)); - guest_env - .entry(String::from("TMPDIR")) - .or_insert_with(|| String::from("/tmp")); - guest_env -} - -fn wasm_guest_path_mappings(request: &StartWasmExecutionRequest) -> Vec { - let guest_cwd = wasm_guest_cwd(&request.env); - let mut mappings = request - .env - .get("AGENTOS_GUEST_PATH_MAPPINGS") - .and_then(|value| serde_json::from_str::>(value).ok()) - .unwrap_or_default() - .into_iter() - .filter_map(|mapping| { - Some(WasmGuestPathMapping { - guest_path: mapping.get("guestPath")?.as_str()?.to_owned(), - host_path: PathBuf::from(mapping.get("hostPath")?.as_str()?), - read_only: mapping - .get("readOnly") - .and_then(Value::as_bool) - .unwrap_or(false), - }) - }) - .collect::>(); - - if let Some(sandbox_root) = wasm_sandbox_root(&request.env) { - push_wasm_guest_path_mapping(&mut mappings, String::from("/"), sandbox_root); - } - push_wasm_guest_path_mapping(&mut mappings, guest_cwd, request.cwd.clone()); - push_wasm_guest_path_mapping( - &mut mappings, - String::from("/workspace"), - request.cwd.clone(), - ); - mappings.sort_by_key(|mapping| std::cmp::Reverse(mapping.guest_path.len())); - mappings -} - -fn wasm_sandbox_root(env: &BTreeMap) -> Option { - env.get(WASM_SANDBOX_ROOT_ENV) - .filter(|value| Path::new(value.as_str()).is_absolute()) - .map(PathBuf::from) -} - -fn push_wasm_guest_path_mapping( - mappings: &mut Vec, - guest_path: String, - host_path: PathBuf, -) { - if guest_path.is_empty() || !guest_path.starts_with('/') { - return; - } - if mappings - .iter() - .any(|mapping| mapping.guest_path == guest_path) - { - return; - } - mappings.push(WasmGuestPathMapping { - guest_path, - host_path, - read_only: false, - }); -} - -fn encode_wasm_guest_path_mappings(mappings: &[WasmGuestPathMapping]) -> String { - serde_json::to_string( - &mappings - .iter() - .map(|mapping| { - json!({ - "guestPath": mapping.guest_path, - "hostPath": mapping.host_path.to_string_lossy(), - "readOnly": mapping.read_only, - }) - }) - .collect::>(), - ) - .unwrap_or_else(|_| String::from("[]")) -} - -fn is_internal_wasm_guest_env_key(key: &str) -> bool { - key.starts_with("AGENTOS_") || key.starts_with("NODE_SYNC_RPC_") -} - -fn warmup_marker_contents(resolved_module: &ResolvedWasmModule) -> String { - let module_fingerprint = file_fingerprint(&resolved_module.resolved_path); - - [ - env!("CARGO_PKG_NAME").to_string(), - env!("CARGO_PKG_VERSION").to_string(), - WASM_WARMUP_MARKER_VERSION.to_string(), - resolved_module.specifier.clone(), - resolved_module.resolved_path.display().to_string(), - module_fingerprint, - ] - .join("\n") -} - -fn warmup_metrics_line( - debug_enabled: bool, - executed: bool, - reason: &str, - import_cache: &NodeImportCache, - module_specifier: &str, -) -> Option> { - if !debug_enabled { - return None; - } - - Some( - format!( - "{WASM_WARMUP_METRICS_PREFIX}{{\"executed\":{},\"reason\":{},\"modulePath\":{},\"compileCacheDir\":{}}}\n", - if executed { "true" } else { "false" }, - encode_json_string(reason), - encode_json_string(module_specifier), - encode_json_string(&import_cache.shared_compile_cache_dir().display().to_string()), - ) - .into_bytes(), - ) -} - -fn resolve_wasm_execution_timeout( - request: &StartWasmExecutionRequest, -) -> Result, WasmExecutionError> { - // Node's WASI runtime does not expose per-instruction fuel metering, so an - // EXPLICITLY configured "fuel" budget is enforced as a tight wall-clock - // timeout. The value rides the typed `limits.max_fuel` (from the BARE-wire - // resource limits), not an `AGENTOS_WASM_MAX_FUEL` env var. - // - // With no explicit fuel budget there is NO default wall-clock timeout — - // matching the JS execution philosophy (wall-clock backstop is opt-in). - // The guest stays bounded by default anyway: the wasm module executes on - // the runner isolate's thread, whose TRUE-CPU budget (the V8 CPU-time - // watchdog, default 30s ACTIVE CPU) terminates an infinite-loop module - // while letting an idle interactive guest (vim blocked in a kernel input - // wait) live indefinitely, exactly like native Linux. - Ok(request.limits.max_fuel.map(Duration::from_millis)) -} - -/// Resolve and validate the per-execution WASM stack cap from the typed wire -/// limit. Runtime V8 stack-limit enforcement still needs a stack lever on the -/// V8 session and is tracked as a follow-up; for now an out-of-range value is -/// rejected up front so a misconfiguration surfaces instead of being silently -/// dropped. -fn resolve_wasm_stack_limit_bytes( - request: &StartWasmExecutionRequest, -) -> Result, WasmExecutionError> { - match request.limits.max_stack_bytes { - Some(0) => Err(WasmExecutionError::InvalidLimit(String::from( - "wasm max stack bytes must be greater than zero", - ))), - other => Ok(other), - } -} - -fn resolve_wasm_prewarm_timeout( - request: &StartWasmExecutionRequest, -) -> Result { - Ok(Duration::from_millis( - request - .limits - .prewarm_timeout_ms - .filter(|value| *value > 0) - .unwrap_or(DEFAULT_WASM_PREWARM_TIMEOUT_MS), - )) -} - -fn resolve_wasm_module( - context: &WasmContext, - request: &StartWasmExecutionRequest, -) -> Result { - let specifier = module_path(context, request)?; - let resolved_path = resolved_module_path(&specifier, &request.cwd); - Ok(ResolvedWasmModule { - specifier, - resolved_path, - }) -} - -fn resolved_module_path(specifier: &str, cwd: &Path) -> PathBuf { - resolve_path_like_specifier(cwd, specifier) - .map(|path| path.canonicalize().unwrap_or(path)) - .unwrap_or_else(|| PathBuf::from(specifier)) -} - -/// Sniff the first bytes of a resolved WebAssembly module and refuse to hand -/// non-`\0asm` content (such as `#!/bin/sh` shell shims) to `WebAssembly.compile`. -/// -/// Without this guard, resolving a `node_modules/.bin/` shell shim against -/// the WASM path produces an opaque `CompileError: WebAssembly.Module(): expected -/// magic word 00 61 73 6d, found 23 21 2f 62 @+0` during prewarm. That error -/// cascades through hundreds of downstream tests as `ERR_AGENTOS_NODE_SYNC_RPC: -/// WebAssembly warmup exited with status 1: CompileError`, which hides the real -/// command-resolution bug that fed the shim to the WASM engine in the first -/// place. A typed [`WasmExecutionError::NonWasmBinary`] instead names the resolved -/// path and preserves the header bytes so callers can route through the Node -/// dispatch path or surface a clear error. -fn verify_wasm_module_header( - resolved_module: &ResolvedWasmModule, -) -> Result<(), WasmExecutionError> { - let resolved_path = &resolved_module.resolved_path; - let metadata = fs::metadata(resolved_path).map_err(|error| { - WasmExecutionError::InvalidModule(format!( - "failed to stat {}: {error}", - resolved_path.display() - )) - })?; - if metadata.len() > MAX_WASM_MODULE_FILE_BYTES { - return Err(WasmExecutionError::InvalidModule(format!( - "module file size of {} bytes exceeds the configured parser cap of {} bytes", - metadata.len(), - MAX_WASM_MODULE_FILE_BYTES - ))); - } - - let mut file = fs::File::open(resolved_path).map_err(|error| { - WasmExecutionError::InvalidModule(format!( - "failed to open {}: {error}", - resolved_path.display() - )) - })?; - let mut header = [0u8; 4]; - let bytes_read = file.read(&mut header).map_err(|error| { - WasmExecutionError::InvalidModule(format!( - "failed to read header of {}: {error}", - resolved_path.display() - )) - })?; - let header = &header[..bytes_read]; - if header == b"\0asm" { - return Ok(()); - } - - let shell_shim = header.len() >= 2 && &header[..2] == b"#!"; - if let Some(format) = detect_native_binary_format(header) { - return Err(WasmExecutionError::NativeBinaryNotSupported { - path: resolved_path.clone(), - header: header.to_vec(), - format, - }); - } - - Err(WasmExecutionError::NonWasmBinary { - path: resolved_path.clone(), - header: header.to_vec(), - shell_shim, - }) -} - -fn detect_native_binary_format(header: &[u8]) -> Option { - if header.len() >= 4 && &header[..4] == b"\x7fELF" { - return Some(NativeBinaryFormat::Elf); - } - - if header.starts_with(b"MZ") { - return Some(NativeBinaryFormat::PeCoff); - } - - const MACH_O_MAGICS: [&[u8; 4]; 6] = [ - b"\xfe\xed\xfa\xce", - b"\xce\xfa\xed\xfe", - b"\xfe\xed\xfa\xcf", - b"\xcf\xfa\xed\xfe", - b"\xca\xfe\xba\xbe", - b"\xbe\xba\xfe\xca", - ]; - if header.len() >= 4 && MACH_O_MAGICS.iter().any(|magic| header[..4] == magic[..]) { - return Some(NativeBinaryFormat::MachO); - } - - None -} - -fn warmup_guest_argv( - resolved_module: &ResolvedWasmModule, - request: &StartWasmExecutionRequest, -) -> Vec { - if !request.argv.is_empty() { - return request.argv.clone(); - } - - vec![resolved_module.specifier.clone()] -} - -fn wasm_memory_limit_bytes( - request: &StartWasmExecutionRequest, -) -> Result, WasmExecutionError> { - Ok(request.limits.max_memory_bytes) -} - -fn wasm_stack_limit_bytes( - request: &StartWasmExecutionRequest, -) -> Result, WasmExecutionError> { - resolve_wasm_stack_limit_bytes(request) -} - -#[cfg(test)] -fn wasm_memory_limit_pages(memory_limit_bytes: u64) -> Result { - let pages = memory_limit_bytes / WASM_PAGE_BYTES; - u32::try_from(pages).map_err(|_| { - WasmExecutionError::InvalidLimit(format!( - "{WASM_MAX_MEMORY_BYTES_ENV}={memory_limit_bytes}: exceeds V8's wasm page limit range" - )) - }) -} - -/// Resolve the wasm runner isolate's V8 heap cap (MB): the typed per-VM limit if -/// set to a positive value, else the bounded default. -fn wasm_runner_heap_limit_mb(request: &StartWasmExecutionRequest) -> u32 { - request - .limits - .runner_heap_limit_mb - .filter(|value| *value > 0) - .unwrap_or(DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB) -} - -fn v8_warm_worker_count() -> usize { - std::env::var("AGENTOS_V8_WARM_ISOLATES") - .ok() - .and_then(|value| value.parse::().ok()) - .unwrap_or(2) -} - -fn validate_module_limits( - resolved_module: &ResolvedWasmModule, - request: &StartWasmExecutionRequest, -) -> Result<(), WasmExecutionError> { - // Read and validate the wire stack cap on every execution. Runtime stack - // enforcement is a follow-up, but a bad value still fails closed instead of - // being written to an env var. - let _stack_limit = resolve_wasm_stack_limit_bytes(request)?; - - let Some(memory_limit) = wasm_memory_limit_bytes(request)? else { - return Ok(()); - }; - - let resolved_path = &resolved_module.resolved_path; - let metadata = fs::metadata(resolved_path).map_err(|error| { - WasmExecutionError::InvalidModule(format!( - "failed to stat {}: {error}", - resolved_path.display() - )) - })?; - if metadata.len() > MAX_WASM_MODULE_FILE_BYTES { - return Err(WasmExecutionError::InvalidModule(format!( - "module file size of {} bytes exceeds the configured parser cap of {} bytes", - metadata.len(), - MAX_WASM_MODULE_FILE_BYTES - ))); - } - let bytes = fs::read(resolved_path).map_err(|error| { - WasmExecutionError::InvalidModule(format!( - "failed to read {}: {error}", - resolved_path.display() - )) - })?; - let module_limits = extract_wasm_module_limits(&bytes)?; - - if module_limits.imports_memory { - return Err(WasmExecutionError::InvalidModule(String::from( - "configured WebAssembly memory limit does not support imported memories yet", - ))); - } - - if let Some(initial_bytes) = module_limits.initial_memory_bytes { - if initial_bytes > memory_limit { - warn_limit_exhausted( - TrackedLimit::WasmMemoryBytes, - usize_saturating_from_u64(initial_bytes), - usize_saturating_from_u64(memory_limit), - ); - return Err(WasmExecutionError::InvalidModule(format!( - "initial WebAssembly memory of {initial_bytes} bytes exceeds the configured limit of {memory_limit} bytes" - ))); - } - } - - match module_limits.maximum_memory_bytes { - Some(maximum_bytes) if maximum_bytes > memory_limit => { - warn_limit_exhausted( - TrackedLimit::WasmMemoryBytes, - usize_saturating_from_u64(maximum_bytes), - usize_saturating_from_u64(memory_limit), - ); - Err(WasmExecutionError::InvalidModule(format!( - "WebAssembly memory maximum of {maximum_bytes} bytes exceeds the configured limit of {memory_limit} bytes" - ))) - } - Some(_) => Ok(()), - None => Ok(()), - } -} - -fn duration_millis_saturating_usize(duration: Duration) -> usize { - usize::try_from(duration.as_millis()).unwrap_or(usize::MAX) -} - -fn usize_saturating_from_u64(value: u64) -> usize { - usize::try_from(value).unwrap_or(usize::MAX) -} - -#[derive(Debug, Default)] -struct WasmModuleLimits { - imports_memory: bool, - initial_memory_bytes: Option, - maximum_memory_bytes: Option, -} - -fn extract_wasm_module_limits(bytes: &[u8]) -> Result { - if bytes.len() < 8 || &bytes[..4] != b"\0asm" { - return Err(WasmExecutionError::InvalidModule(String::from( - "module is not a valid WebAssembly binary", - ))); - } - - let mut offset = 8; - let mut limits = WasmModuleLimits::default(); - - while offset < bytes.len() { - let section_id = bytes[offset]; - offset += 1; - let section_size = read_varuint_usize(bytes, &mut offset, "section size")?; - let section_end = offset.checked_add(section_size).ok_or_else(|| { - WasmExecutionError::InvalidModule(String::from("section size overflow")) - })?; - if section_end > bytes.len() { - return Err(WasmExecutionError::InvalidModule(String::from( - "section extends past end of module", - ))); - } - - match section_id { - 2 => { - let mut cursor = offset; - let import_count = read_varuint_usize(bytes, &mut cursor, "import count")?; - if import_count > MAX_WASM_IMPORT_SECTION_ENTRIES { - return Err(WasmExecutionError::InvalidModule(format!( - "import section contains {import_count} entries, which exceeds the parser cap of {MAX_WASM_IMPORT_SECTION_ENTRIES}" - ))); - } - for _ in 0..import_count { - skip_name(bytes, &mut cursor)?; - skip_name(bytes, &mut cursor)?; - let kind = read_byte(bytes, &mut cursor)?; - match kind { - 0x02 => { - let _ = read_memory_limits(bytes, &mut cursor)?; - limits.imports_memory = true; - } - 0x00 => { - let _ = read_varuint(bytes, &mut cursor)?; - } - 0x01 => { - skip_table_type(bytes, &mut cursor)?; - } - 0x03 => { - let _ = read_byte(bytes, &mut cursor)?; - let _ = read_byte(bytes, &mut cursor)?; - } - other => { - return Err(WasmExecutionError::InvalidModule(format!( - "unsupported import kind {other}" - ))); - } - } - } - } - 5 => { - let mut cursor = offset; - let memory_count = read_varuint_usize(bytes, &mut cursor, "memory count")?; - if memory_count > MAX_WASM_MEMORY_SECTION_ENTRIES { - return Err(WasmExecutionError::InvalidModule(format!( - "memory section contains {memory_count} entries, which exceeds the parser cap of {MAX_WASM_MEMORY_SECTION_ENTRIES}" - ))); - } - if memory_count > 0 { - let (initial_pages, maximum_pages) = read_memory_limits(bytes, &mut cursor)?; - limits.initial_memory_bytes = - Some(initial_pages.saturating_mul(WASM_PAGE_BYTES)); - limits.maximum_memory_bytes = - maximum_pages.map(|pages| pages.saturating_mul(WASM_PAGE_BYTES)); - } - } - _ => {} - } - - offset = section_end; - } - - Ok(limits) -} - -fn read_memory_limits( - bytes: &[u8], - offset: &mut usize, -) -> Result<(u64, Option), WasmExecutionError> { - let flags = read_varuint(bytes, offset)?; - let initial = read_varuint(bytes, offset)?; - let maximum = if flags & 0x01 != 0 { - Some(read_varuint(bytes, offset)?) - } else { - None - }; - Ok((initial, maximum)) -} - -fn skip_name(bytes: &[u8], offset: &mut usize) -> Result<(), WasmExecutionError> { - let length = read_varuint_usize(bytes, offset, "name length")?; - let end = offset - .checked_add(length) - .ok_or_else(|| WasmExecutionError::InvalidModule(String::from("name length overflow")))?; - if end > bytes.len() { - return Err(WasmExecutionError::InvalidModule(String::from( - "name extends past end of module", - ))); - } - *offset = end; - Ok(()) -} - -fn skip_table_type(bytes: &[u8], offset: &mut usize) -> Result<(), WasmExecutionError> { - let _ = read_byte(bytes, offset)?; - let flags = read_varuint(bytes, offset)?; - let _ = read_varuint(bytes, offset)?; - if flags & 0x01 != 0 { - let _ = read_varuint(bytes, offset)?; - } - Ok(()) -} - -fn read_byte(bytes: &[u8], offset: &mut usize) -> Result { - let Some(byte) = bytes.get(*offset).copied() else { - return Err(WasmExecutionError::InvalidModule(String::from( - "unexpected end of module", - ))); - }; - *offset += 1; - Ok(byte) -} - -fn read_varuint(bytes: &[u8], offset: &mut usize) -> Result { - let mut shift = 0_u32; - let mut value = 0_u64; - let mut encoded_bytes = 0_usize; - - loop { - let byte = read_byte(bytes, offset)?; - encoded_bytes += 1; - if encoded_bytes > MAX_WASM_VARUINT_BYTES { - return Err(WasmExecutionError::InvalidModule(format!( - "varuint exceeds the parser cap of {MAX_WASM_VARUINT_BYTES} bytes" - ))); - } - value |= u64::from(byte & 0x7f) << shift; - if byte & 0x80 == 0 { - return Ok(value); - } - if encoded_bytes == MAX_WASM_VARUINT_BYTES { - return Err(WasmExecutionError::InvalidModule(format!( - "varuint exceeds the parser cap of {MAX_WASM_VARUINT_BYTES} bytes" - ))); - } - shift = shift.saturating_add(7); - if shift >= 64 { - return Err(WasmExecutionError::InvalidModule(String::from( - "varuint is too large", - ))); - } - } -} - -fn read_varuint_usize( - bytes: &[u8], - offset: &mut usize, - label: &str, -) -> Result { - let value = read_varuint(bytes, offset)?; - usize::try_from(value).map_err(|_| { - WasmExecutionError::InvalidModule(format!( - "{label} of {value} exceeds platform usize range" - )) - }) -} - -impl From for WasmSignalDispositionAction { - fn from(value: NodeSignalDispositionAction) -> Self { - match value { - NodeSignalDispositionAction::Default => Self::Default, - NodeSignalDispositionAction::Ignore => Self::Ignore, - NodeSignalDispositionAction::User => Self::User, - } - } -} - -impl From for WasmSignalHandlerRegistration { - fn from(value: NodeSignalHandlerRegistration) -> Self { - Self { - action: value.action.into(), - mask: value.mask, - flags: value.flags, - } - } -} - -fn resolve_path_like_specifier(cwd: &Path, specifier: &str) -> Option { - if specifier.starts_with("file://") { - return Some(PathBuf::from(specifier.trim_start_matches("file://"))); - } - if specifier.starts_with("file:") { - return Some(PathBuf::from(specifier.trim_start_matches("file:"))); - } - if specifier.starts_with('/') { - return Some(PathBuf::from(specifier)); - } - if specifier.starts_with("./") || specifier.starts_with("../") { - return Some(cwd.join(specifier)); - } - - None -} - -#[cfg(test)] -mod tests { - use super::{ - build_wasm_internal_env, build_wasm_runner_bootstrap, open_wasm_guest_file, - resolve_wasm_execution_timeout, resolve_wasm_prewarm_timeout, - resolve_wasm_stack_limit_bytes, resolved_module_path, translate_wasm_guest_path, - translate_wasm_host_symlink_target, wasm_guest_module_paths, wasm_host_path_is_read_only, - wasm_memory_limit_bytes, wasm_memory_limit_pages, wasm_mutation_touches_read_only_mapping, - wasm_read_only_filesystem_error, wasm_runner_base_env, wasm_runner_heap_limit_mb, - wasm_sandbox_root, wasm_snapshot_runner_base_env, wasm_sync_read_length, - wasm_sync_rpc_error_code, wasm_sync_rpc_method_routes_through_sidecar_kernel, - GuestRuntimeConfig, JavascriptSyncRpcRequest, ResolvedWasmModule, - StartWasmExecutionRequest, Value, WasmExecutionError, WasmExecutionLimits, - WasmInternalSyncRpc, WasmPermissionTier, DEFAULT_WASM_PREWARM_TIMEOUT_MS, - DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB, NODE_WASI_MODULE_SOURCE, - WASM_CAPTURED_OUTPUT_LIMIT_BYTES, WASM_MAX_FUEL_ENV, WASM_MAX_MEMORY_BYTES_ENV, - WASM_MAX_STACK_BYTES_ENV, WASM_PAGE_BYTES, WASM_SANDBOX_ROOT_ENV, - WASM_SIDECAR_ROUTED_FS_SYNC_METHODS, WASM_SYNC_READ_LIMIT_BYTES, - }; - use std::collections::{BTreeMap, BTreeSet, VecDeque}; - use std::fs; - use std::os::unix::fs::symlink; - use std::path::{Path, PathBuf}; - use std::time::Duration; - use tempfile::tempdir; - - fn request_with_env(cwd: &Path, env: BTreeMap) -> StartWasmExecutionRequest { - // Translate the legacy `AGENTOS_WASM_*` limit env keys these tests still - // express into the typed limits the engine now reads (mirrors the - // sidecar's config→limits flow). - let parse = |key: &str| env.get(key).and_then(|value| value.parse::().ok()); - let limits = WasmExecutionLimits { - max_fuel: parse(WASM_MAX_FUEL_ENV), - max_memory_bytes: parse(WASM_MAX_MEMORY_BYTES_ENV), - max_stack_bytes: parse(WASM_MAX_STACK_BYTES_ENV), - prewarm_timeout_ms: None, - runner_heap_limit_mb: None, - }; - StartWasmExecutionRequest { - limits, - guest_runtime: GuestRuntimeConfig::default(), - vm_id: String::from("vm-wasm"), - context_id: String::from("ctx-wasm"), - argv: Vec::new(), - env, - cwd: cwd.to_path_buf(), - permission_tier: WasmPermissionTier::Full, - } - } - - fn wasi_imports_from_source(source: &str) -> BTreeSet { - let table_start = source - .find("this.wasiImport = {") - .expect("WASI source should define a wasiImport table"); - let table_body = &source[table_start + "this.wasiImport = {".len()..]; - let table_end = table_body - .find("\n };") - .expect("WASI source should close the wasiImport table"); - - table_body[..table_end] - .lines() - .filter_map(|line| { - let (name, _) = line.trim_start().split_once(':')?; - name.chars() - .all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_') - .then(|| name.to_string()) - }) - .collect() - } - - fn wasm_sync_rpc_request(method: &str) -> JavascriptSyncRpcRequest { - JavascriptSyncRpcRequest { - id: 1, - method: method.to_string(), - args: Vec::new(), - raw_bytes_args: Default::default(), - } - } - - /// Build a request whose typed limits and `AGENTOS_WASM_*` env disagree, so a - /// reader that still consulted env would observe the (wrong) env value. - fn request_with_typed_limits_and_misleading_env( - limits: WasmExecutionLimits, - ) -> StartWasmExecutionRequest { - StartWasmExecutionRequest { - limits, - guest_runtime: GuestRuntimeConfig::default(), - vm_id: String::from("vm-wasm"), - context_id: String::from("ctx-wasm"), - argv: Vec::new(), - // Deliberately huge env values: if any limit were still sourced from - // env, the assertions below would observe these instead. - env: BTreeMap::from([ - (String::from(WASM_MAX_FUEL_ENV), String::from("999999")), - ( - String::from(WASM_MAX_MEMORY_BYTES_ENV), - String::from("999999"), - ), - ( - String::from(WASM_MAX_STACK_BYTES_ENV), - String::from("999999"), - ), - ( - String::from("AGENTOS_WASM_PREWARM_TIMEOUT_MS"), - String::from("999999"), - ), - ( - String::from("AGENTOS_WASM_RUNNER_HEAP_LIMIT_MB"), - String::from("999999"), - ), - ]), - cwd: PathBuf::from("/tmp"), - permission_tier: WasmPermissionTier::Full, - } - } - - #[test] - fn wasm_limits_are_read_from_typed_fields_and_env_is_inert() { - let request = request_with_typed_limits_and_misleading_env(WasmExecutionLimits { - max_fuel: Some(25), - max_memory_bytes: Some(65_536), - max_stack_bytes: Some(131_072), - prewarm_timeout_ms: Some(750), - runner_heap_limit_mb: Some(512), - }); - - assert_eq!( - resolve_wasm_execution_timeout(&request).expect("fuel timeout"), - Some(Duration::from_millis(25)), - "fuel must come from the typed wire limit, not AGENTOS_WASM_MAX_FUEL" - ); - assert_eq!( - wasm_memory_limit_bytes(&request).expect("memory limit"), - Some(65_536), - "memory must come from the typed wire limit, not AGENTOS_WASM_MAX_MEMORY_BYTES" - ); - assert_eq!( - resolve_wasm_stack_limit_bytes(&request).expect("stack limit"), - Some(131_072), - "stack must come from the typed wire limit (retiring the dead AGENTOS_WASM_MAX_STACK_BYTES knob)" - ); - assert_eq!( - resolve_wasm_prewarm_timeout(&request).expect("prewarm timeout"), - Duration::from_millis(750), - "prewarm timeout must come from the typed wire limit, not AGENTOS_WASM_PREWARM_TIMEOUT_MS" - ); - assert_eq!( - wasm_runner_heap_limit_mb(&request), - 512, - "runner heap must come from the typed wire limit, not AGENTOS_WASM_RUNNER_HEAP_LIMIT_MB" - ); - } - - #[test] - fn wasm_limits_default_to_bounded_timeout_when_unset_even_with_env_present() { - // Same misleading env, but no typed limits: no wall-clock fuel timeout - // (the runner's V8 TRUE-CPU budget bounds runaways), and memory and - // stack limits remain absent. - let request = request_with_typed_limits_and_misleading_env(WasmExecutionLimits::default()); - - assert_eq!( - resolve_wasm_execution_timeout(&request).expect("fuel"), - None - ); - assert_eq!(wasm_memory_limit_bytes(&request).expect("memory"), None); - assert_eq!( - resolve_wasm_stack_limit_bytes(&request).expect("stack"), - None - ); - assert_eq!( - resolve_wasm_prewarm_timeout(&request).expect("prewarm"), - Duration::from_millis(DEFAULT_WASM_PREWARM_TIMEOUT_MS) - ); - assert_eq!( - wasm_runner_heap_limit_mb(&request), - DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB - ); - } - - #[test] - fn wasm_internal_env_scrubs_migrated_limit_env_keys() { - let request = request_with_typed_limits_and_misleading_env(WasmExecutionLimits { - max_fuel: Some(25), - max_memory_bytes: Some(65_536), - max_stack_bytes: Some(131_072), - prewarm_timeout_ms: Some(750), - runner_heap_limit_mb: Some(512), - }); - let resolved_module = ResolvedWasmModule { - specifier: String::from("./guest.wasm"), - resolved_path: PathBuf::from("/tmp/guest.wasm"), - }; - - let internal_env = - build_wasm_internal_env(&resolved_module, &request, 1_234, false).expect("env"); - - assert_eq!( - internal_env.get(WASM_MAX_MEMORY_BYTES_ENV), - Some(&String::from("65536")) - ); - assert!(!internal_env.contains_key(WASM_MAX_STACK_BYTES_ENV)); - assert!(!internal_env.contains_key(WASM_MAX_FUEL_ENV)); - assert!(!internal_env.contains_key("AGENTOS_WASM_PREWARM_TIMEOUT_MS")); - assert!(!internal_env.contains_key("AGENTOS_WASM_RUNNER_HEAP_LIMIT_MB")); - } - - #[test] - fn wasm_runner_base_env_scrubs_migrated_limit_env_keys() { - let mut request = request_with_typed_limits_and_misleading_env(WasmExecutionLimits { - max_fuel: Some(25), - max_memory_bytes: Some(65_536), - max_stack_bytes: Some(131_072), - prewarm_timeout_ms: Some(750), - runner_heap_limit_mb: Some(512), - }); - request - .env - .insert(String::from("USER_VISIBLE"), String::from("kept")); - request - .env - .insert(String::from("AGENTOS_TRACE_ID"), String::from("kept")); - - let env = wasm_runner_base_env(&request); - - assert_eq!(env.get("USER_VISIBLE"), Some(&String::from("kept"))); - assert_eq!(env.get("AGENTOS_TRACE_ID"), Some(&String::from("kept"))); - assert!(!env.contains_key(WASM_MAX_FUEL_ENV)); - assert!(!env.contains_key(WASM_MAX_MEMORY_BYTES_ENV)); - assert!(!env.contains_key(WASM_MAX_STACK_BYTES_ENV)); - assert!(!env.contains_key("AGENTOS_WASM_PREWARM_TIMEOUT_MS")); - assert!(!env.contains_key("AGENTOS_WASM_RUNNER_HEAP_LIMIT_MB")); - } - - #[test] - fn wasm_snapshot_runner_base_env_scrubs_internal_and_migrated_limit_env_keys() { - let mut request = request_with_typed_limits_and_misleading_env(WasmExecutionLimits { - max_fuel: Some(25), - max_memory_bytes: Some(65_536), - max_stack_bytes: Some(131_072), - prewarm_timeout_ms: Some(750), - runner_heap_limit_mb: Some(512), - }); - request - .env - .insert(String::from("USER_VISIBLE"), String::from("kept")); - request.env.insert( - String::from("NODE_SYNC_RPC_WAIT_TIMEOUT_MS"), - String::from("999"), - ); - - let env = wasm_snapshot_runner_base_env(&request); - - assert_eq!(env.get("USER_VISIBLE"), Some(&String::from("kept"))); - assert!(!env.contains_key("NODE_SYNC_RPC_WAIT_TIMEOUT_MS")); - assert!(!env.contains_key(WASM_MAX_FUEL_ENV)); - assert!(!env.contains_key(WASM_MAX_MEMORY_BYTES_ENV)); - assert!(!env.contains_key(WASM_MAX_STACK_BYTES_ENV)); - assert!(!env.contains_key("AGENTOS_WASM_PREWARM_TIMEOUT_MS")); - assert!(!env.contains_key("AGENTOS_WASM_RUNNER_HEAP_LIMIT_MB")); - } - - #[test] - fn wasm_stack_limit_of_zero_is_rejected() { - let request = request_with_typed_limits_and_misleading_env(WasmExecutionLimits { - max_stack_bytes: Some(0), - ..WasmExecutionLimits::default() - }); - - assert!( - resolve_wasm_stack_limit_bytes(&request).is_err(), - "a zero stack cap must fail closed rather than be silently dropped" - ); - } - - #[test] - fn resolved_module_path_canonicalizes_path_like_specifiers() { - let temp = tempdir().expect("create temp dir"); - let real = temp.path().join("real.wasm"); - let alias = temp.path().join("alias.wasm"); - fs::write(&real, b"\0asm\x01\0\0\0").expect("write wasm file"); - symlink(&real, &alias).expect("create wasm symlink"); - - let resolved = resolved_module_path("./alias.wasm", temp.path()); - - assert_eq!( - resolved, - real.canonicalize().expect("canonicalize wasm target") - ); - } - - #[test] - fn wasm_prewarm_timeout_is_separate_from_execution_timeout() { - let temp = tempdir().expect("create temp dir"); - let mut request = request_with_env( - temp.path(), - BTreeMap::from([(String::from(WASM_MAX_FUEL_ENV), String::from("25"))]), - ); - request.limits.prewarm_timeout_ms = Some(750); - - assert_eq!( - resolve_wasm_execution_timeout(&request).expect("execution timeout"), - Some(Duration::from_millis(25)) - ); - assert_eq!( - resolve_wasm_prewarm_timeout(&request).expect("prewarm timeout"), - Duration::from_millis(750) - ); - } - - // No explicit fuel budget means no wasm-specific wall-clock timeout. Runaway - // wasm stays bounded by the runner isolate's active-CPU watchdog, so idle - // interactive guests are not killed on wall time. - #[test] - fn wasm_execution_timeout_is_unset_without_fuel_budget() { - let temp = tempdir().expect("create temp dir"); - let request = request_with_env(temp.path(), BTreeMap::new()); - - let timeout = resolve_wasm_execution_timeout(&request) - .expect("execution timeout resolves without fuel env"); - - assert_eq!( - timeout, None, - "no explicit fuel budget means no wall-clock timeout; the runner \ - isolate's TRUE-CPU budget (default 30s active CPU) is the bound \ - that terminates an infinite-loop module (F-004), so an idle \ - interactive guest is not killed on wall time" - ); - } - - #[test] - fn wasm_captured_output_rejects_output_over_limit() { - let mut stdout = vec![b'x'; WASM_CAPTURED_OUTPUT_LIMIT_BYTES - 1]; - super::append_wasm_captured_output(&mut stdout, b"y", "stdout").expect("fill to limit"); - assert_eq!(stdout.len(), WASM_CAPTURED_OUTPUT_LIMIT_BYTES); - - let error = super::append_wasm_captured_output(&mut stdout, b"z", "stdout") - .expect_err("captured output over limit should fail"); - assert!(matches!( - error, - WasmExecutionError::OutputBufferExceeded { - stream: "stdout", - limit: WASM_CAPTURED_OUTPUT_LIMIT_BYTES, - } - )); - } - - #[test] - fn wasm_sync_read_length_rejects_oversized_guest_lengths() { - assert_eq!( - wasm_sync_read_length(Some(WASM_SYNC_READ_LIMIT_BYTES as u64)) - .expect("max read length should be accepted"), - WASM_SYNC_READ_LIMIT_BYTES - ); - - let error = wasm_sync_read_length(Some(WASM_SYNC_READ_LIMIT_BYTES as u64 + 1)) - .expect_err("oversized read length should fail before allocation"); - assert!( - matches!(error, WasmExecutionError::InvalidLimit(message) if message.contains("fs.readSync length")) - ); - } - - #[test] - fn wasm_bytes_arg_rejects_payloads_over_limit_before_decode() { - let mut payload = serde_json::Map::new(); - payload.insert( - String::from("base64"), - Value::String(String::from("YWJjZA==")), - ); - - let error = - super::decode_wasm_bytes_arg(Some(&Value::Object(payload)), "fs.writeSync bytes", 3) - .expect_err("decoded bytes over limit should fail before allocation"); - - assert!(matches!( - error, - WasmExecutionError::OutputBufferExceeded { - stream: "fs.writeSync bytes", - limit: 3, - } - )); - } - - #[test] - fn wasm_runner_bootstrap_caps_wasi_iov_lengths_before_allocation() { - let bootstrap = build_wasm_runner_bootstrap(&BTreeMap::new(), None); - - // The read cap now comes from the per-backend host seam, with the native - // build-substituted constant as the fallback; assert the constant is - // defined and the placeholder was substituted to the value. - assert!(bootstrap.contains("const __agentOSWasmSyncReadLimitBytes =")); - assert!(bootstrap.contains(&format!(": {WASM_SYNC_READ_LIMIT_BYTES};"))); - assert!(!bootstrap.contains("__SECURE_EXEC_WASM_SYNC_READ_LIMIT_BYTES__")); - assert!(bootstrap.contains("_boundedIovLength(iovs, iovsLen)")); - assert!(bootstrap.contains("const totalLength = this._boundedIovLength(iovs, iovsLen);\n const view = this._memoryView();")); - assert!(bootstrap.contains("return Buffer.concat(chunks, totalLength);")); - assert!(bootstrap.contains("const totalLength = this._boundedIovLength(iovs, iovsLen);")); - assert!(!bootstrap.contains("const totalLength = (() => {")); - } - - #[test] - fn wasi_preview1_import_manifest_matches_native_runner() { - let expected: BTreeSet = serde_json::from_str::>(include_str!( - "../assets/wasi-preview1-imports.json" - )) - .expect("parse WASI preview1 import manifest") - .into_iter() - .collect(); - - assert_eq!(expected, wasi_imports_from_source(NODE_WASI_MODULE_SOURCE)); - } - - #[test] - fn wasm_guest_module_paths_include_mapped_guest_paths_for_host_specifiers() { - let temp = tempdir().expect("create temp dir"); - let command_root = temp.path().join("commands"); - let module = command_root.join("hello"); - fs::create_dir_all(&command_root).expect("create command root"); - fs::write(&module, b"\0asm\x01\0\0\0").expect("write wasm file"); - - let candidates = wasm_guest_module_paths( - module.to_string_lossy().as_ref(), - &BTreeMap::from([( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - format!( - "[{{\"guestPath\":\"/__secure_exec/commands/0\",\"hostPath\":\"{}\"}}]", - command_root.display() - ), - )]), - ); - - assert!(candidates.contains(&module.to_string_lossy().into_owned())); - assert!(candidates.contains(&String::from("/__secure_exec/commands/0/hello"))); - } - - #[test] - fn translate_wasm_guest_path_uses_sandbox_root_for_absolute_paths() { - let temp = tempdir().expect("create temp dir"); - let sandbox_root = temp.path().join("shadow-root"); - let cwd = sandbox_root.join("workspace"); - fs::create_dir_all(cwd.join("project")).expect("create host cwd"); - - let internal_sync_rpc = WasmInternalSyncRpc { - module_guest_paths: Vec::new(), - module_host_path: sandbox_root.join("module.wasm"), - guest_cwd: String::from("/workspace"), - host_cwd: cwd.clone(), - sandbox_root: Some(sandbox_root.clone()), - guest_path_mappings: Vec::new(), - route_fs_through_sidecar: false, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - - assert_eq!( - translate_wasm_guest_path("/tmp/redir.txt", &internal_sync_rpc), - Some(sandbox_root.join("tmp/redir.txt")) - ); - assert_eq!( - translate_wasm_guest_path("project/output.txt", &internal_sync_rpc), - Some(cwd.join("project/output.txt")) - ); - } - - #[test] - fn translate_wasm_host_symlink_target_returns_guest_path_for_mapped_targets() { - let temp = tempdir().expect("create temp dir"); - let sandbox_root = temp.path().join("shadow-root"); - let cwd = sandbox_root.join("workspace"); - fs::create_dir_all(cwd.join("project")).expect("create host cwd"); - - let internal_sync_rpc = WasmInternalSyncRpc { - module_guest_paths: Vec::new(), - module_host_path: sandbox_root.join("module.wasm"), - guest_cwd: String::from("/workspace"), - host_cwd: cwd.clone(), - sandbox_root: Some(sandbox_root.clone()), - guest_path_mappings: vec![super::WasmGuestPathMapping { - guest_path: String::from("/"), - host_path: sandbox_root.clone(), - read_only: false, - }], - route_fs_through_sidecar: false, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - - assert_eq!( - translate_wasm_host_symlink_target( - &sandbox_root.join("tmp/sc/pdir/r.txt"), - &internal_sync_rpc - ), - Some(String::from("/tmp/sc/pdir/r.txt")) - ); - assert_eq!( - translate_wasm_host_symlink_target(Path::new("relative-target"), &internal_sync_rpc), - None - ); - } - - #[test] - fn translate_wasm_guest_path_recovers_root_collapsed_relative_paths_from_guest_cwd() { - let temp = tempdir().expect("create temp dir"); - let sandbox_root = temp.path().join("shadow-root"); - let cwd = temp.path().join("mounted-workspace"); - fs::create_dir_all(&sandbox_root).expect("create sandbox root"); - fs::create_dir_all(&cwd).expect("create mounted workspace"); - fs::write(cwd.join("note.txt"), b"hello").expect("write mounted file"); - - let internal_sync_rpc = WasmInternalSyncRpc { - module_guest_paths: Vec::new(), - module_host_path: sandbox_root.join("module.wasm"), - guest_cwd: String::from("/workspace"), - host_cwd: cwd.clone(), - sandbox_root: Some(sandbox_root.clone()), - guest_path_mappings: vec![super::WasmGuestPathMapping { - guest_path: String::from("/workspace"), - host_path: cwd.clone(), - read_only: false, - }], - route_fs_through_sidecar: false, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - - assert_eq!( - translate_wasm_guest_path("/note.txt", &internal_sync_rpc), - Some(cwd.join("note.txt")) - ); - } - - #[test] - fn translate_wasm_guest_path_accepts_host_absolute_paths_within_known_roots() { - let temp = tempdir().expect("create temp dir"); - let sandbox_root = temp.path().join("shadow-root"); - let cwd = temp.path().join("mounted-workspace"); - let mapped_root = temp.path().join("mounted-commands"); - fs::create_dir_all(&sandbox_root).expect("create sandbox root"); - fs::create_dir_all(cwd.join("subdir")).expect("create cwd"); - fs::create_dir_all(&mapped_root).expect("create mapped root"); - - let internal_sync_rpc = WasmInternalSyncRpc { - module_guest_paths: vec![String::from("/workspace/guest.wasm")], - module_host_path: cwd.join("guest.wasm"), - guest_cwd: String::from("/workspace"), - host_cwd: cwd.clone(), - sandbox_root: Some(sandbox_root.clone()), - guest_path_mappings: vec![ - super::WasmGuestPathMapping { - guest_path: String::from("/workspace"), - host_path: cwd.clone(), - read_only: false, - }, - super::WasmGuestPathMapping { - guest_path: String::from("/__secure_exec/commands/0"), - host_path: mapped_root.clone(), - read_only: false, - }, - ], - route_fs_through_sidecar: false, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - - assert_eq!( - translate_wasm_guest_path(cwd.to_string_lossy().as_ref(), &internal_sync_rpc), - Some(cwd.clone()) - ); - assert_eq!( - translate_wasm_guest_path( - cwd.join("subdir/output.txt").to_string_lossy().as_ref(), - &internal_sync_rpc - ), - Some(cwd.join("subdir/output.txt")) - ); - assert_eq!( - translate_wasm_guest_path( - mapped_root.join("tool.wasm").to_string_lossy().as_ref(), - &internal_sync_rpc - ), - Some(mapped_root.join("tool.wasm")) - ); - assert_eq!( - translate_wasm_guest_path( - sandbox_root - .join("tmp/runtime.sock") - .to_string_lossy() - .as_ref(), - &internal_sync_rpc - ), - Some(sandbox_root.join("tmp/runtime.sock")) - ); - } - - #[test] - fn translate_wasm_guest_path_rejects_symlink_escape_from_sandbox_root() { - let temp = tempdir().expect("create temp dir"); - let sandbox_root = temp.path().join("shadow-root"); - let outside = temp.path().join("outside"); - fs::create_dir_all(&sandbox_root).expect("create sandbox root"); - fs::create_dir_all(&outside).expect("create outside root"); - fs::write(outside.join("secret.txt"), b"host secret").expect("write outside file"); - symlink(&outside, sandbox_root.join("escape")).expect("create escape symlink"); - - let internal_sync_rpc = WasmInternalSyncRpc { - module_guest_paths: Vec::new(), - module_host_path: sandbox_root.join("module.wasm"), - guest_cwd: String::from("/"), - host_cwd: sandbox_root.clone(), - sandbox_root: Some(sandbox_root.clone()), - guest_path_mappings: vec![super::WasmGuestPathMapping { - guest_path: String::from("/"), - host_path: sandbox_root, - read_only: false, - }], - route_fs_through_sidecar: false, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - - assert_eq!( - translate_wasm_guest_path("/escape/secret.txt", &internal_sync_rpc), - None - ); - assert_eq!( - translate_wasm_guest_path("/escape/new.txt", &internal_sync_rpc), - None - ); - } - - #[test] - fn wasm_read_only_mapping_blocks_mutating_host_paths() { - let temp = tempdir().expect("create temp dir"); - let sandbox_root = temp.path().join("shadow-root"); - let readonly_root = temp.path().join("readonly"); - fs::create_dir_all(&sandbox_root).expect("create sandbox root"); - fs::create_dir_all(&readonly_root).expect("create readonly root"); - fs::write(readonly_root.join("package.json"), b"{}").expect("write readonly file"); - - let internal_sync_rpc = WasmInternalSyncRpc { - module_guest_paths: Vec::new(), - module_host_path: sandbox_root.join("module.wasm"), - guest_cwd: String::from("/workspace"), - host_cwd: sandbox_root.clone(), - sandbox_root: Some(sandbox_root), - guest_path_mappings: vec![super::WasmGuestPathMapping { - guest_path: String::from("/node_modules"), - host_path: readonly_root.clone(), - read_only: true, - }], - route_fs_through_sidecar: false, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - - let host_path = translate_wasm_guest_path("/node_modules/package.json", &internal_sync_rpc) - .expect("read path should resolve"); - assert_eq!(host_path, readonly_root.join("package.json")); - assert!(wasm_host_path_is_read_only(&host_path, &internal_sync_rpc)); - assert!(wasm_host_path_is_read_only( - &readonly_root.join("new-package.json"), - &internal_sync_rpc - )); - assert_eq!( - wasm_sync_rpc_error_code(&wasm_read_only_filesystem_error("/node_modules")), - "EROFS" - ); - } - - #[test] - fn wasm_open_guest_file_errors_remain_sync_rpc_errors() { - let temp = tempdir().expect("create temp dir"); - let missing_path = temp.path().join("missing.txt"); - - let error = open_wasm_guest_file(&missing_path, &Value::from(0)) - .expect_err("missing file should return an open error"); - - assert_eq!(wasm_sync_rpc_error_code(&error), "ENOENT"); - } - - #[test] - fn wasm_hard_links_are_rejected_when_either_side_is_read_only() { - let temp = tempdir().expect("create temp dir"); - let readonly_root = temp.path().join("readonly"); - let writable_root = temp.path().join("writable"); - fs::create_dir_all(&readonly_root).expect("create readonly root"); - fs::create_dir_all(&writable_root).expect("create writable root"); - let readonly_file = readonly_root.join("package.json"); - let writable_file = writable_root.join("source.txt"); - fs::write(&readonly_file, b"readonly").expect("write readonly source"); - fs::write(&writable_file, b"writable").expect("write writable source"); - - let internal_sync_rpc = WasmInternalSyncRpc { - module_guest_paths: Vec::new(), - module_host_path: writable_root.join("module.wasm"), - guest_cwd: String::from("/workspace"), - host_cwd: writable_root.clone(), - sandbox_root: Some(writable_root.clone()), - guest_path_mappings: vec![ - super::WasmGuestPathMapping { - guest_path: String::from("/node_modules"), - host_path: readonly_root.clone(), - read_only: true, - }, - super::WasmGuestPathMapping { - guest_path: String::from("/workspace"), - host_path: writable_root.clone(), - read_only: false, - }, - ], - route_fs_through_sidecar: false, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - - assert!(wasm_mutation_touches_read_only_mapping( - &readonly_file, - &writable_root.join("alias-from-readonly.json"), - &internal_sync_rpc - )); - assert!(wasm_mutation_touches_read_only_mapping( - &writable_file, - &readonly_root.join("alias-into-readonly.txt"), - &internal_sync_rpc - )); - assert!(!wasm_mutation_touches_read_only_mapping( - &writable_file, - &writable_root.join("alias.txt"), - &internal_sync_rpc - )); - - let raw_alias = writable_root.join("raw-alias.json"); - fs::hard_link(&readonly_file, &raw_alias).expect("host hard link would otherwise succeed"); - fs::write(&raw_alias, b"mutated").expect("write through host hard link alias"); - assert_eq!( - fs::read(&readonly_file).expect("read readonly source"), - b"mutated" - ); - } - - #[test] - fn translate_wasm_guest_path_preserves_real_root_paths_before_guest_cwd_fallback() { - let temp = tempdir().expect("create temp dir"); - let sandbox_root = temp.path().join("shadow-root"); - let cwd = temp.path().join("mounted-workspace"); - fs::create_dir_all(&sandbox_root).expect("create sandbox root"); - fs::create_dir_all(&cwd).expect("create mounted workspace"); - fs::write(sandbox_root.join("note.txt"), b"root").expect("write root file"); - fs::write(cwd.join("note.txt"), b"cwd").expect("write cwd file"); - - let internal_sync_rpc = WasmInternalSyncRpc { - module_guest_paths: Vec::new(), - module_host_path: sandbox_root.join("module.wasm"), - guest_cwd: String::from("/workspace"), - host_cwd: cwd.clone(), - sandbox_root: Some(sandbox_root.clone()), - guest_path_mappings: vec![super::WasmGuestPathMapping { - guest_path: String::from("/workspace"), - host_path: cwd, - read_only: false, - }], - route_fs_through_sidecar: false, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - - assert_eq!( - translate_wasm_guest_path("/note.txt", &internal_sync_rpc), - Some(sandbox_root.join("note.txt")) - ); - } - - #[test] - fn wasm_sandbox_root_reads_absolute_env_only() { - let sandbox_root = wasm_sandbox_root(&BTreeMap::from([( - String::from(WASM_SANDBOX_ROOT_ENV), - String::from("/tmp/secure-exec-shadow"), - )])); - assert_eq!(sandbox_root, Some(PathBuf::from("/tmp/secure-exec-shadow"))); - - let relative = wasm_sandbox_root(&BTreeMap::from([( - String::from(WASM_SANDBOX_ROOT_ENV), - String::from("relative/shadow"), - )])); - assert_eq!(relative, None); - } - - #[test] - fn wasm_sidecar_managed_fs_methods_route_to_kernel_sync_rpc() { - let mut standalone = WasmInternalSyncRpc { - module_guest_paths: Vec::new(), - module_host_path: PathBuf::from("/tmp/module.wasm"), - guest_cwd: String::from("/"), - host_cwd: PathBuf::from("/tmp"), - sandbox_root: None, - guest_path_mappings: Vec::new(), - route_fs_through_sidecar: false, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - let sidecar_managed = WasmInternalSyncRpc { - module_guest_paths: Vec::new(), - module_host_path: PathBuf::from("/tmp/module.wasm"), - guest_cwd: String::from("/"), - host_cwd: PathBuf::from("/tmp"), - sandbox_root: Some(PathBuf::from("/tmp/secure-exec-shadow")), - guest_path_mappings: Vec::new(), - route_fs_through_sidecar: true, - next_fd: 64, - open_files: Default::default(), - pending_events: VecDeque::new(), - }; - - for method in WASM_SIDECAR_ROUTED_FS_SYNC_METHODS { - let request = wasm_sync_rpc_request(method); - assert!( - wasm_sync_rpc_method_routes_through_sidecar_kernel(&request, &sidecar_managed), - "{method} should route through the sidecar kernel for managed WASI executions" - ); - assert!( - !wasm_sync_rpc_method_routes_through_sidecar_kernel(&request, &standalone), - "{method} should stay host-direct for standalone/prewarm WASI execution" - ); - } - - standalone.route_fs_through_sidecar = true; - let non_fs_request = wasm_sync_rpc_request("child_process.spawn"); - assert!(!wasm_sync_rpc_method_routes_through_sidecar_kernel( - &non_fs_request, - &standalone - )); - } - - #[test] - fn wasm_guest_path_mappings_mount_root_to_sandbox_root() { - let temp = tempdir().expect("create temp dir"); - let sandbox_root = temp.path().join("shadow-root"); - let host_cwd = sandbox_root.join("workspace"); - fs::create_dir_all(&host_cwd).expect("create host cwd"); - - let mappings = super::wasm_guest_path_mappings(&request_with_env( - &host_cwd, - BTreeMap::from([ - (String::from("PWD"), String::from("/workspace")), - ( - String::from(WASM_SANDBOX_ROOT_ENV), - sandbox_root.to_string_lossy().into_owned(), - ), - ]), - )); - - assert!(mappings - .iter() - .any(|mapping| { mapping.guest_path == "/" && mapping.host_path == sandbox_root })); - assert!(mappings.iter().any(|mapping| { - mapping.guest_path == "/workspace" && mapping.host_path == host_cwd - })); - } - - #[test] - fn wasm_runner_bootstrap_keeps_root_preopens_rooted() { - let bootstrap = build_wasm_runner_bootstrap(&BTreeMap::new(), None); - - assert!(bootstrap.contains("if (guestPath === \".\") {")); - assert!(!bootstrap.contains("if (guestPath === \".\" || guestPath === \"/\") {")); - } - - #[test] - fn wasm_runner_bootstrap_reports_dot_preopen_to_wasi() { - let bootstrap = build_wasm_runner_bootstrap(&BTreeMap::new(), None); - - // The dot preopen must resolve through the guest cwd, never surface as a - // literal "." (restructured into _currentGuestCwd/_descriptorPreopenName - // by the wasi-shim stat-path rework). - assert!(bootstrap.contains("_currentGuestCwd()")); - assert!(!bootstrap.contains("preopens['.'] = createPreopen(HOST_CWD, cwdReadOnly);")); - assert!(bootstrap.contains("_descriptorPreopenName(entry)")); - assert!(bootstrap.contains( - "if (guestPath === \".\") {\n return this._descriptorGuestPath(entry);" - )); - assert!(bootstrap.contains("const guestPath = this._descriptorPreopenName(entry);")); - } - - #[test] - fn wasm_runner_path_open_uses_guest_mapping_for_absolute_paths() { - let bootstrap = build_wasm_runner_bootstrap(&BTreeMap::new(), None); - - assert!(bootstrap - .contains("const resolved = this._resolveDescriptorPath(fd, pathPtr, pathLen, {")); - assert!( - !bootstrap.contains("const hostPath = __agentOSPath().resolve(baseHostPath, target);") - ); - } - - #[test] - fn wasm_runner_root_preopen_relative_paths_preserve_cwd_fallback() { - let bootstrap = build_wasm_runner_bootstrap(&BTreeMap::new(), None); - - assert!(bootstrap - .contains("const rootGuestPath = __agentOSPath().posix.resolve(\"/\", target);")); - assert!(bootstrap.contains( - "const cwdGuestTarget = __agentOSPath().posix.resolve(cwdGuestPath, target);" - )); - assert!(bootstrap.contains("_rootRelativeTargetPrefersCwd(target)")); - assert!(bootstrap.contains("_rootRelativeTargetMatchesAbsoluteArg(target)")); - assert!(bootstrap.contains("__agentOSPath().posix.normalize(arg) === rootGuestPath")); - assert!(bootstrap.contains("_createParentExists(guestPath, hostPath)")); - assert!(bootstrap.contains( - "preferCreateParent &&\n !this._rootRelativeTargetIsWithinAbsoluteArg(target)" - )); - assert!(bootstrap.contains("this._createParentExists(cwdGuestTarget, cwdHostTarget)")); - } - - #[test] - fn wasm_runner_readdir_uses_guest_preopen_path_in_sidecar() { - let bootstrap = build_wasm_runner_bootstrap(&BTreeMap::new(), None); - - assert!(bootstrap.contains("const fsPath = this._descriptorDirectoryFsPath(entry);")); - assert!( - bootstrap.contains("(entry?.kind === \"preopen\" || entry?.kind === \"directory\")") - ); - } - - #[test] - fn wasm_runner_blocks_read_only_fd_write_paths() { - let bootstrap = build_wasm_runner_bootstrap(&BTreeMap::new(), None); - - assert!(bootstrap.contains("readOnly: entry.readOnly === true,")); - assert!(bootstrap.contains( - "if (handle.readOnly === true) {\n return __agentOSWasiErrnoRofs;\n }" - )); - assert!(bootstrap.contains( - "if (entry.readOnly === true) {\n return __agentOSWasiErrnoRofs;\n }\n const written = __agentOSFs().writeSync(" - )); - } - - #[test] - fn wasm_memory_limit_pages_floor_to_whole_wasm_pages() { - assert_eq!( - wasm_memory_limit_pages(WASM_PAGE_BYTES + 123).expect("page limit"), - 1 - ); - assert_eq!( - wasm_memory_limit_pages(2 * WASM_PAGE_BYTES).expect("page limit"), - 2 - ); - } - - #[test] - fn wasm_memory_limit_no_longer_requires_declared_module_maximum() { - let temp = tempdir().expect("create temp dir"); - let request = request_with_env( - temp.path(), - BTreeMap::from([( - String::from(WASM_MAX_MEMORY_BYTES_ENV), - (2 * WASM_PAGE_BYTES).to_string(), - )]), - ); - - assert!( - super::validate_module_limits( - &super::ResolvedWasmModule { - specifier: String::from("./guest.wasm"), - resolved_path: { - let path = temp.path().join("guest.wasm"); - fs::write( - &path, - wat::parse_str( - r#" -(module - (memory (export "memory") 1) - (func (export "_start")) -) -"#, - ) - .expect("compile wasm fixture"), - ) - .expect("write wasm fixture"); - path - }, - }, - &request, - ) - .is_ok(), - "runtime memory cap should allow modules without a declared maximum" - ); - } -} diff --git a/crates/execution/tests/benchmark.rs b/crates/execution/tests/benchmark.rs deleted file mode 100644 index e1ba11344..000000000 --- a/crates/execution/tests/benchmark.rs +++ /dev/null @@ -1,1134 +0,0 @@ -use secure_exec_execution::benchmark::{ - BenchmarkDistributionStats, BenchmarkHost, BenchmarkResourceUsage, BenchmarkScenarioPhases, - BenchmarkScenarioReport, BenchmarkStats, BenchmarkTransportRttReport, - JavascriptBenchmarkConfig, JavascriptBenchmarkReport, -}; -use serde_json::Value; -use std::fs; -use std::path::PathBuf; -use tempfile::tempdir; - -fn stats( - mean_ms: f64, - p50_ms: f64, - p95_ms: f64, - min_ms: f64, - max_ms: f64, - stddev_ms: f64, -) -> BenchmarkStats { - BenchmarkStats { - mean_ms, - p50_ms, - p95_ms, - min_ms, - max_ms, - stddev_ms, - } -} - -fn phase_samples( - context_setup_ms: Vec, - startup_ms: Vec, - guest_execution_ms: Option>, - completion_ms: Vec, -) -> BenchmarkScenarioPhases> { - BenchmarkScenarioPhases { - context_setup_ms, - startup_ms, - guest_execution_ms, - completion_ms, - } -} - -fn phase_stats( - context_setup_ms: BenchmarkStats, - startup_ms: BenchmarkStats, - guest_execution_ms: Option, - completion_ms: BenchmarkStats, -) -> BenchmarkScenarioPhases { - BenchmarkScenarioPhases { - context_setup_ms, - startup_ms, - guest_execution_ms, - completion_ms, - } -} - -fn transport_rtt( - payload_bytes: usize, - samples_ms: Vec, - stats: BenchmarkStats, -) -> BenchmarkTransportRttReport { - BenchmarkTransportRttReport { - channel: "execution-stdio-echo", - payload_bytes, - samples_ms, - stats, - } -} - -fn distribution_stats( - mean: f64, - p50: f64, - p95: f64, - min: f64, - max: f64, - stddev: f64, -) -> BenchmarkDistributionStats { - BenchmarkDistributionStats { - mean, - p50, - p95, - min, - max, - stddev, - } -} - -fn resource_samples( - rss_bytes: Option>, - heap_used_bytes: Option>, - cpu_total_us: Option>, -) -> BenchmarkResourceUsage> { - BenchmarkResourceUsage { - rss_bytes, - heap_used_bytes, - cpu_user_us: None, - cpu_system_us: None, - cpu_total_us, - } -} - -fn resource_stats( - rss_bytes: Option, - heap_used_bytes: Option, - cpu_total_us: Option, -) -> BenchmarkResourceUsage { - BenchmarkResourceUsage { - rss_bytes, - heap_used_bytes, - cpu_user_us: None, - cpu_system_us: None, - cpu_total_us, - } -} - -/* -Deleted in US-040 because this harness asserted the old startup-path benchmark -marker behavior instead of the current V8 runtime contract. -fn javascript_benchmark_harness_covers_required_startup_and_import_scenarios() { - let report = run_javascript_benchmarks(&JavascriptBenchmarkConfig { - iterations: 1, - warmup_iterations: 0, - }) - .expect("run execution benchmark harness"); - - let scenario_ids = report - .scenarios - .iter() - .map(|scenario| scenario.id) - .collect::>(); - assert_eq!( - scenario_ids, - vec![ - "isolate-startup", - "prewarmed-isolate-startup", - "cold-local-import", - "warm-local-import", - "same-context-local-import", - "prewarmed-local-import", - "host-local-import", - "builtin-import", - "hot-builtin-stream-import", - "hot-builtin-stream-web-import", - "hot-builtin-crypto-import", - "hot-builtin-zlib-import", - "hot-builtin-assert-import", - "hot-builtin-url-import", - "hot-projected-package-file-import", - "large-package-import", - "projected-package-import", - "pdf-lib-startup", - "jszip-startup", - "jszip-end-to-end", - "jszip-repeated-session-compressed", - ] - ); - - for scenario in &report.scenarios { - assert_eq!(scenario.wall_samples_ms.len(), 1); - assert!(scenario.wall_stats.mean_ms >= 0.0); - } - - let warm = report - .scenarios - .iter() - .find(|scenario| scenario.id == "warm-local-import") - .expect("warm-local-import scenario"); - assert_eq!(warm.compile_cache, "primed"); - assert_eq!( - warm.guest_import_samples_ms - .as_ref() - .expect("warm import samples") - .len(), - 1 - ); - assert_eq!( - warm.startup_overhead_samples_ms - .as_ref() - .expect("warm startup samples") - .len(), - 1 - ); - assert_eq!(warm.workload, "local-import"); - assert_eq!(warm.runtime, "native-execution"); - assert_eq!(warm.mode, "new-session-replay"); - - let same_context = report - .scenarios - .iter() - .find(|scenario| scenario.id == "same-context-local-import") - .expect("same-context-local-import scenario"); - assert_eq!(same_context.compile_cache, "primed"); - assert_eq!(same_context.workload, "local-import"); - assert_eq!(same_context.runtime, "native-execution"); - assert_eq!(same_context.mode, "same-session-replay"); - assert_eq!(same_context.wall_samples_ms.len(), 1); - - let prewarmed = report - .scenarios - .iter() - .find(|scenario| scenario.id == "prewarmed-local-import") - .expect("prewarmed-local-import scenario"); - assert_eq!(prewarmed.compile_cache, "primed"); - assert_eq!( - prewarmed - .guest_import_samples_ms - .as_ref() - .expect("prewarmed import samples") - .len(), - 1 - ); - assert_eq!( - prewarmed - .startup_overhead_samples_ms - .as_ref() - .expect("prewarmed startup samples") - .len(), - 1 - ); - assert_eq!(prewarmed.mode, "same-engine-replay"); - - let host = report - .scenarios - .iter() - .find(|scenario| scenario.id == "host-local-import") - .expect("host-local-import scenario"); - assert_eq!(host.workload, "local-import"); - assert_eq!(host.runtime, "host-node"); - assert_eq!(host.mode, "host-control"); - assert_eq!( - host.guest_import_samples_ms - .as_ref() - .expect("host import samples") - .len(), - 1 - ); - - let prewarmed_isolate = report - .scenarios - .iter() - .find(|scenario| scenario.id == "prewarmed-isolate-startup") - .expect("prewarmed-isolate-startup scenario"); - assert_eq!(prewarmed_isolate.workload, "startup-floor"); - assert_eq!(prewarmed_isolate.mode, "same-engine-replay"); - assert_eq!(prewarmed_isolate.compile_cache, "primed"); - assert!(prewarmed_isolate.guest_import_samples_ms.is_none()); - - let hot_builtin = report - .scenarios - .iter() - .find(|scenario| scenario.id == "hot-builtin-crypto-import") - .expect("hot-builtin-crypto-import scenario"); - assert_eq!(hot_builtin.workload, "builtin-hot-import"); - assert_eq!(hot_builtin.mode, "same-engine-replay"); - assert_eq!(hot_builtin.compile_cache, "primed"); - assert_eq!( - hot_builtin - .guest_import_samples_ms - .as_ref() - .expect("hot builtin import samples") - .len(), - 1 - ); - - let hot_projected = report - .scenarios - .iter() - .find(|scenario| scenario.id == "hot-projected-package-file-import") - .expect("hot-projected-package-file-import scenario"); - assert_eq!(hot_projected.workload, "projected-package-hot-import"); - assert_eq!(hot_projected.mode, "same-engine-replay"); - assert_eq!(hot_projected.compile_cache, "primed"); - assert_eq!( - hot_projected - .guest_import_samples_ms - .as_ref() - .expect("hot projected import samples") - .len(), - 1 - ); - - let rendered = report.render_markdown(); - assert!(rendered.contains("ARC-021C")); - assert!(rendered.contains("ARC-021D")); - assert!(rendered.contains("ARC-022")); - assert!(rendered.contains("current import-cache materialization and builtin/polyfill prewarm")); - assert!(rendered.contains("typescript")); - assert!(rendered.contains("projected TypeScript guest-path import")); - assert!(rendered.contains("projected-package-import")); - assert!(rendered.contains("pdf-lib document creation")); - assert!(rendered.contains("jszip archive staging")); - assert!(rendered.contains("jszip end-to-end archive roundtrip")); - assert!(rendered.contains("jszip compressed archive roundtrip")); - assert!(rendered.contains("prewarmed-isolate-startup")); - assert!(rendered.contains("prewarmed-local-import")); - assert!(rendered.contains("same-context-local-import")); - assert!(rendered.contains("host-local-import")); - assert!(rendered.contains("node:path + node:url + node:fs/promises")); - assert!(rendered.contains("node:stream/web")); - assert!(rendered.contains("node:crypto")); - assert!(rendered.contains("projected TypeScript compiler file")); - assert!(rendered.contains("hot-projected-package-file-import")); - assert!(rendered.contains("## Transport RTT")); - assert!(rendered.contains("## Control Matrix")); - assert!(rendered.contains("## Ranked Hotspots")); - assert!(rendered.contains("### Wall Time (`time`, `ms`)")); - assert!(rendered.contains("### Startup Share Of Wall (`share`, `pct`)")); - assert!(rendered.contains("Mean context (ms)")); - assert!(rendered.contains("same-session-replay")); - assert!(rendered.contains("host-control")); - - let json = report.render_json().expect("render benchmark json"); - let parsed: Value = serde_json::from_str(&json).expect("parse benchmark json"); - assert_eq!(parsed["artifact_version"], 5); - assert_eq!(parsed["summary"]["scenario_count"], 21); - assert_eq!(parsed["summary"]["recorded_samples_per_scenario"], 1); - assert_eq!( - parsed["transport_rtt"] - .as_array() - .expect("transport rtt array") - .len(), - 3 - ); - let scenarios = parsed["scenarios"] - .as_array() - .expect("json scenarios array"); - assert_eq!(scenarios.len(), 21); - assert!( - parsed["summary"]["slowest_wall_scenario"]["id"].is_string(), - "expected a summarized slowest wall scenario: {json}" - ); - let startup_floor_matrix = parsed["summary"]["control_matrix"] - .as_array() - .expect("control matrix array") - .iter() - .find(|row| row["workload"] == "startup-floor") - .expect("startup-floor control matrix row"); - assert_eq!( - startup_floor_matrix["modes"].as_array().map(Vec::len), - Some(2) - ); - let local_import_matrix = parsed["summary"]["control_matrix"] - .as_array() - .expect("control matrix array") - .iter() - .find(|row| row["workload"] == "local-import") - .expect("local-import control matrix row"); - assert_eq!( - local_import_matrix["modes"].as_array().map(Vec::len), - Some(5) - ); - assert_eq!( - local_import_matrix["runtimes"].as_array().map(Vec::len), - Some(2) - ); - let builtin_hot_matrix = parsed["summary"]["control_matrix"] - .as_array() - .expect("control matrix array") - .iter() - .find(|row| row["workload"] == "builtin-hot-import") - .expect("builtin-hot-import control matrix row"); - assert_eq!( - builtin_hot_matrix["scenario_ids"].as_array().map(Vec::len), - Some(6) - ); - let hotspot_rankings = parsed["summary"]["hotspot_rankings"] - .as_array() - .expect("hotspot rankings array"); - assert_eq!(hotspot_rankings.len(), 13); - assert_eq!(hotspot_rankings[0]["metric"], "wall_mean_ms"); - assert_eq!(hotspot_rankings[1]["metric"], "wall_stddev_ms"); - assert_eq!(hotspot_rankings[1]["dimension"], "stability"); - assert_eq!(hotspot_rankings[0]["unit"], "ms"); - assert!(scenarios - .iter() - .all(|scenario| scenario["wall_stats"]["stddev_ms"].is_number())); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "prewarmed-isolate-startup" - && scenario["workload"] == "startup-floor" - && scenario["mode"] == "same-engine-replay" - && scenario["compile_cache"] == "primed" - && scenario["guest_import_stats"].is_null() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "same-context-local-import" - && scenario["workload"] == "local-import" - && scenario["runtime"] == "native-execution" - && scenario["mode"] == "same-session-replay" - && scenario["compile_cache"] == "primed" - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "host-local-import" - && scenario["workload"] == "local-import" - && scenario["runtime"] == "host-node" - && scenario["mode"] == "host-control" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "hot-builtin-stream-web-import" - && scenario["fixture"] == "node:stream/web" - && scenario["compile_cache"] == "primed" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "hot-builtin-crypto-import" - && scenario["fixture"] == "node:crypto" - && scenario["compile_cache"] == "primed" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "hot-projected-package-file-import" - && scenario["fixture"] == "projected TypeScript compiler file" - && scenario["compile_cache"] == "primed" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "pdf-lib-startup" - && scenario["fixture"] == "pdf-lib document creation" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "large-package-import" - && scenario["fixture"] == "typescript" - && scenario["compile_cache"] == "disabled" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "jszip-startup" - && scenario["fixture"] == "jszip archive staging" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "jszip-end-to-end" - && scenario["fixture"] == "jszip end-to-end archive roundtrip" - && scenario["compile_cache"] == "disabled" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "jszip-repeated-session-compressed" - && scenario["fixture"] == "jszip compressed archive roundtrip" - && scenario["compile_cache"] == "primed" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "prewarmed-local-import" - && scenario["fixture"] == "24-module local ESM graph" - && scenario["compile_cache"] == "primed" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["id"] == "projected-package-import" - && scenario["fixture"] == "projected TypeScript guest-path import" - && scenario["compile_cache"] == "primed" - && scenario["guest_import_stats"]["mean_ms"].is_number() - })); - assert!(scenarios.iter().any(|scenario| { - scenario["guest_import_samples_ms"].is_array() - && scenario["startup_overhead_samples_ms"].is_array() - && scenario["mean_startup_share_pct"].is_number() - && scenario["phase_stats"]["startup_ms"]["mean_ms"].is_number() - && scenario["phase_samples_ms"]["completion_ms"].is_array() - && scenario["resource_usage_stats"]["rss_bytes"]["mean"].is_number() - && scenario["resource_usage_stats"]["cpu_total_us"]["mean"].is_number() - && scenario["resource_usage_samples"]["heap_used_bytes"].is_array() - })); -} -*/ - -#[test] -fn javascript_benchmark_json_artifact_stays_stable_for_summary_and_samples() { - let report = JavascriptBenchmarkReport { - generated_at_unix_ms: 42, - config: JavascriptBenchmarkConfig { - iterations: 2, - warmup_iterations: 1, - }, - host: BenchmarkHost { - node_binary: String::from("node"), - node_version: String::from("v22.0.0"), - os: "linux", - arch: "x86_64", - logical_cpus: 8, - }, - repo_root: PathBuf::from("/repo"), - transport_rtt: vec![ - transport_rtt(32, vec![0.4, 0.6], stats(0.5, 0.4, 0.6, 0.4, 0.6, 0.1)), - transport_rtt(4096, vec![0.9, 1.1], stats(1.0, 0.9, 1.1, 0.9, 1.1, 0.1)), - transport_rtt(65536, vec![2.6, 3.0], stats(2.8, 2.6, 3.0, 2.6, 3.0, 0.2)), - ], - scenarios: vec![ - BenchmarkScenarioReport { - id: "fast-scenario", - workload: "fixture-a", - runtime: "native-execution", - mode: "true-cold-start", - description: "Faster benchmark path", - fixture: "fixture-a", - compile_cache: "disabled", - wall_samples_ms: vec![10.0, 14.0], - wall_stats: stats(12.0, 10.0, 14.0, 10.0, 14.0, 2.0), - guest_import_samples_ms: Some(vec![4.0, 6.0]), - guest_import_stats: Some(stats(5.0, 4.0, 6.0, 4.0, 6.0, 1.0)), - startup_overhead_samples_ms: Some(vec![6.0, 8.0]), - startup_overhead_stats: Some(stats(7.0, 6.0, 8.0, 6.0, 8.0, 1.0)), - phase_samples_ms: phase_samples( - vec![1.0, 2.0], - vec![2.0, 3.0], - Some(vec![4.0, 6.0]), - vec![3.0, 3.0], - ), - phase_stats: phase_stats( - stats(1.5, 1.0, 2.0, 1.0, 2.0, 0.5), - stats(2.5, 2.0, 3.0, 2.0, 3.0, 0.5), - Some(stats(5.0, 4.0, 6.0, 4.0, 6.0, 1.0)), - stats(3.0, 3.0, 3.0, 3.0, 3.0, 0.0), - ), - resource_usage_samples: Some(resource_samples( - Some(vec![32.0 * 1024.0 * 1024.0, 36.0 * 1024.0 * 1024.0]), - Some(vec![8.0 * 1024.0 * 1024.0, 10.0 * 1024.0 * 1024.0]), - Some(vec![4000.0, 6000.0]), - )), - resource_usage_stats: Some(resource_stats( - Some(distribution_stats( - 34.0 * 1024.0 * 1024.0, - 32.0 * 1024.0 * 1024.0, - 36.0 * 1024.0 * 1024.0, - 32.0 * 1024.0 * 1024.0, - 36.0 * 1024.0 * 1024.0, - 2.0 * 1024.0 * 1024.0, - )), - Some(distribution_stats( - 9.0 * 1024.0 * 1024.0, - 8.0 * 1024.0 * 1024.0, - 10.0 * 1024.0 * 1024.0, - 8.0 * 1024.0 * 1024.0, - 10.0 * 1024.0 * 1024.0, - 1.0 * 1024.0 * 1024.0, - )), - Some(distribution_stats( - 5000.0, 4000.0, 6000.0, 4000.0, 6000.0, 1000.0, - )), - )), - }, - BenchmarkScenarioReport { - id: "slow-scenario", - workload: "fixture-b", - runtime: "host-node", - mode: "host-control", - description: "Slower benchmark path", - fixture: "fixture-b", - compile_cache: "primed", - wall_samples_ms: vec![30.0, 34.0], - wall_stats: stats(32.0, 30.0, 34.0, 30.0, 34.0, 2.0), - guest_import_samples_ms: Some(vec![12.0, 14.0]), - guest_import_stats: Some(stats(13.0, 12.0, 14.0, 12.0, 14.0, 1.0)), - startup_overhead_samples_ms: Some(vec![18.0, 20.0]), - startup_overhead_stats: Some(stats(19.0, 18.0, 20.0, 18.0, 20.0, 1.0)), - phase_samples_ms: phase_samples( - vec![4.0, 4.0], - vec![5.0, 6.0], - Some(vec![12.0, 14.0]), - vec![9.0, 10.0], - ), - phase_stats: phase_stats( - stats(4.0, 4.0, 4.0, 4.0, 4.0, 0.0), - stats(5.5, 5.0, 6.0, 5.0, 6.0, 0.5), - Some(stats(13.0, 12.0, 14.0, 12.0, 14.0, 1.0)), - stats(9.5, 9.0, 10.0, 9.0, 10.0, 0.5), - ), - resource_usage_samples: Some(resource_samples( - Some(vec![64.0 * 1024.0 * 1024.0, 72.0 * 1024.0 * 1024.0]), - Some(vec![14.0 * 1024.0 * 1024.0, 18.0 * 1024.0 * 1024.0]), - Some(vec![9000.0, 11000.0]), - )), - resource_usage_stats: Some(resource_stats( - Some(distribution_stats( - 68.0 * 1024.0 * 1024.0, - 64.0 * 1024.0 * 1024.0, - 72.0 * 1024.0 * 1024.0, - 64.0 * 1024.0 * 1024.0, - 72.0 * 1024.0 * 1024.0, - 4.0 * 1024.0 * 1024.0, - )), - Some(distribution_stats( - 16.0 * 1024.0 * 1024.0, - 14.0 * 1024.0 * 1024.0, - 18.0 * 1024.0 * 1024.0, - 14.0 * 1024.0 * 1024.0, - 18.0 * 1024.0 * 1024.0, - 2.0 * 1024.0 * 1024.0, - )), - Some(distribution_stats( - 10000.0, 9000.0, 11000.0, 9000.0, 11000.0, 1000.0, - )), - )), - }, - ], - }; - - let json = report.render_json().expect("render json"); - let parsed: Value = serde_json::from_str(&json).expect("parse json"); - - assert_eq!(parsed["artifact_version"], 5); - assert_eq!(parsed["generated_at_unix_ms"], 42); - assert_eq!( - parsed["command"].as_str(), - Some( - "cargo run -p secure-exec-execution --bin node-import-bench -- --iterations 2 --warmup-iterations 1" - ) - ); - assert_eq!(parsed["summary"]["scenario_count"], 2); - assert_eq!(parsed["summary"]["recorded_samples_per_scenario"], 2); - assert_eq!( - parsed["summary"]["control_matrix"][0]["workload"].as_str(), - Some("fixture-a") - ); - assert_eq!( - parsed["summary"]["control_matrix"][1]["runtimes"][0].as_str(), - Some("host-node") - ); - assert_eq!( - parsed["transport_rtt"][2]["payload_bytes"].as_u64(), - Some(65536) - ); - assert_eq!(parsed["transport_rtt"][2]["stats"]["mean_ms"], 2.8); - assert_eq!( - parsed["summary"]["slowest_wall_scenario"]["id"].as_str(), - Some("slow-scenario") - ); - assert_eq!( - parsed["summary"]["slowest_guest_import_scenario"]["id"].as_str(), - Some("slow-scenario") - ); - assert_eq!( - parsed["summary"]["highest_startup_share_scenario"]["id"].as_str(), - Some("slow-scenario") - ); - let hotspot_rankings = parsed["summary"]["hotspot_rankings"] - .as_array() - .expect("hotspot rankings array"); - assert_eq!(hotspot_rankings.len(), 13); - assert_eq!(hotspot_rankings[0]["metric"], "wall_mean_ms"); - assert_eq!(hotspot_rankings[0]["label"], "Wall Time"); - assert_eq!( - hotspot_rankings[0]["ranked_scenarios"][0]["id"].as_str(), - Some("slow-scenario") - ); - assert_eq!(hotspot_rankings[0]["ranked_scenarios"][0]["rank"], 1); - assert_eq!(hotspot_rankings[3]["metric"], "guest_import_mean_ms"); - assert_eq!( - hotspot_rankings[3]["ranked_scenarios"][0]["value"].as_f64(), - Some(13.0) - ); - assert_eq!(hotspot_rankings[9]["metric"], "startup_share_pct"); - assert_eq!(hotspot_rankings[9]["unit"], "pct"); - assert_eq!(hotspot_rankings[10]["metric"], "rss_mean_mib"); - assert_eq!(hotspot_rankings[12]["metric"], "cpu_total_mean_ms"); - - let scenarios = parsed["scenarios"].as_array().expect("scenario array"); - assert_eq!(scenarios.len(), 2); - assert_eq!(scenarios[0]["workload"], "fixture-a"); - assert_eq!(scenarios[0]["runtime"], "native-execution"); - assert_eq!(scenarios[0]["mode"], "true-cold-start"); - assert_eq!(scenarios[0]["wall_stats"]["stddev_ms"], 2.0); - assert_eq!(scenarios[0]["mean_startup_share_pct"], 58.333333333333336); - assert_eq!( - scenarios[0]["resource_usage_stats"]["rss_bytes"]["mean"], - 35651584.0 - ); - assert_eq!( - scenarios[0]["resource_usage_stats"]["cpu_total_us"]["mean"], - 5000.0 - ); - assert_eq!( - scenarios[0]["phase_stats"]["context_setup_ms"]["mean_ms"], - 1.5 - ); - assert_eq!(scenarios[0]["phase_stats"]["completion_ms"]["mean_ms"], 3.0); - assert_eq!(scenarios[1]["mean_startup_share_pct"], 59.375); - assert_eq!(scenarios[1]["phase_stats"]["startup_ms"]["mean_ms"], 5.5); - assert_eq!( - scenarios[1]["resource_usage_stats"]["heap_used_bytes"]["mean"], - 16777216.0 - ); -} - -#[test] -fn javascript_benchmark_hotspot_rankings_handle_missing_metrics() { - let report = JavascriptBenchmarkReport { - generated_at_unix_ms: 42, - config: JavascriptBenchmarkConfig { - iterations: 2, - warmup_iterations: 1, - }, - host: BenchmarkHost { - node_binary: String::from("node"), - node_version: String::from("v22.0.0"), - os: "linux", - arch: "x86_64", - logical_cpus: 8, - }, - repo_root: PathBuf::from("/repo"), - transport_rtt: vec![], - scenarios: vec![ - BenchmarkScenarioReport { - id: "alpha", - workload: "fixture-a", - runtime: "native-execution", - mode: "true-cold-start", - description: "Alpha path", - fixture: "fixture-a", - compile_cache: "disabled", - wall_samples_ms: vec![15.0, 17.0], - wall_stats: stats(16.0, 15.0, 17.0, 15.0, 17.0, 1.0), - guest_import_samples_ms: Some(vec![7.0, 9.0]), - guest_import_stats: Some(stats(8.0, 7.0, 9.0, 7.0, 9.0, 1.0)), - startup_overhead_samples_ms: Some(vec![8.0, 8.0]), - startup_overhead_stats: Some(stats(8.0, 8.0, 8.0, 8.0, 8.0, 0.0)), - phase_samples_ms: phase_samples( - vec![2.0, 2.0], - vec![3.0, 3.0], - Some(vec![7.0, 9.0]), - vec![3.0, 3.0], - ), - phase_stats: phase_stats( - stats(2.0, 2.0, 2.0, 2.0, 2.0, 0.0), - stats(3.0, 3.0, 3.0, 3.0, 3.0, 0.0), - Some(stats(8.0, 7.0, 9.0, 7.0, 9.0, 1.0)), - stats(3.0, 3.0, 3.0, 3.0, 3.0, 0.0), - ), - resource_usage_samples: Some(resource_samples( - Some(vec![40.0 * 1024.0 * 1024.0, 44.0 * 1024.0 * 1024.0]), - None, - Some(vec![6000.0, 8000.0]), - )), - resource_usage_stats: Some(resource_stats( - Some(distribution_stats( - 42.0 * 1024.0 * 1024.0, - 40.0 * 1024.0 * 1024.0, - 44.0 * 1024.0 * 1024.0, - 40.0 * 1024.0 * 1024.0, - 44.0 * 1024.0 * 1024.0, - 2.0 * 1024.0 * 1024.0, - )), - None, - Some(distribution_stats( - 7000.0, 6000.0, 8000.0, 6000.0, 8000.0, 1000.0, - )), - )), - }, - BenchmarkScenarioReport { - id: "beta", - workload: "fixture-b", - runtime: "host-node", - mode: "host-control", - description: "Beta path", - fixture: "fixture-b", - compile_cache: "primed", - wall_samples_ms: vec![20.0, 24.0], - wall_stats: stats(22.0, 20.0, 24.0, 20.0, 24.0, 2.0), - guest_import_samples_ms: Some(vec![10.0, 12.0]), - guest_import_stats: Some(stats(11.0, 10.0, 12.0, 10.0, 12.0, 1.0)), - startup_overhead_samples_ms: Some(vec![9.0, 11.0]), - startup_overhead_stats: Some(stats(10.0, 9.0, 11.0, 9.0, 11.0, 1.0)), - phase_samples_ms: phase_samples( - vec![3.0, 3.0], - vec![4.0, 4.0], - Some(vec![10.0, 12.0]), - vec![5.0, 5.0], - ), - phase_stats: phase_stats( - stats(3.0, 3.0, 3.0, 3.0, 3.0, 0.0), - stats(4.0, 4.0, 4.0, 4.0, 4.0, 0.0), - Some(stats(11.0, 10.0, 12.0, 10.0, 12.0, 1.0)), - stats(5.0, 5.0, 5.0, 5.0, 5.0, 0.0), - ), - resource_usage_samples: Some(resource_samples( - Some(vec![60.0 * 1024.0 * 1024.0, 68.0 * 1024.0 * 1024.0]), - Some(vec![12.0 * 1024.0 * 1024.0, 14.0 * 1024.0 * 1024.0]), - Some(vec![9000.0, 12000.0]), - )), - resource_usage_stats: Some(resource_stats( - Some(distribution_stats( - 64.0 * 1024.0 * 1024.0, - 60.0 * 1024.0 * 1024.0, - 68.0 * 1024.0 * 1024.0, - 60.0 * 1024.0 * 1024.0, - 68.0 * 1024.0 * 1024.0, - 4.0 * 1024.0 * 1024.0, - )), - Some(distribution_stats( - 13.0 * 1024.0 * 1024.0, - 12.0 * 1024.0 * 1024.0, - 14.0 * 1024.0 * 1024.0, - 12.0 * 1024.0 * 1024.0, - 14.0 * 1024.0 * 1024.0, - 1.0 * 1024.0 * 1024.0, - )), - Some(distribution_stats( - 10500.0, 9000.0, 12000.0, 9000.0, 12000.0, 1500.0, - )), - )), - }, - BenchmarkScenarioReport { - id: "gamma", - workload: "fixture-c", - runtime: "native-execution", - mode: "baseline-control", - description: "Gamma path", - fixture: "fixture-c", - compile_cache: "disabled", - wall_samples_ms: vec![12.0, 14.0], - wall_stats: stats(13.0, 12.0, 14.0, 12.0, 14.0, 1.0), - guest_import_samples_ms: None, - guest_import_stats: None, - startup_overhead_samples_ms: None, - startup_overhead_stats: None, - phase_samples_ms: phase_samples( - vec![1.0, 1.0], - vec![2.0, 2.0], - None, - vec![4.0, 4.0], - ), - phase_stats: phase_stats( - stats(1.0, 1.0, 1.0, 1.0, 1.0, 0.0), - stats(2.0, 2.0, 2.0, 2.0, 2.0, 0.0), - None, - stats(4.0, 4.0, 4.0, 4.0, 4.0, 0.0), - ), - resource_usage_samples: Some(resource_samples( - Some(vec![24.0 * 1024.0 * 1024.0, 28.0 * 1024.0 * 1024.0]), - None, - None, - )), - resource_usage_stats: Some(resource_stats( - Some(distribution_stats( - 26.0 * 1024.0 * 1024.0, - 24.0 * 1024.0 * 1024.0, - 28.0 * 1024.0 * 1024.0, - 24.0 * 1024.0 * 1024.0, - 28.0 * 1024.0 * 1024.0, - 2.0 * 1024.0 * 1024.0, - )), - None, - None, - )), - }, - ], - }; - - let json = report.render_json().expect("render json"); - let parsed: Value = serde_json::from_str(&json).expect("parse json"); - let hotspot_rankings = parsed["summary"]["hotspot_rankings"] - .as_array() - .expect("hotspot rankings array"); - let wall_ranking = hotspot_rankings - .iter() - .find(|ranking| ranking["metric"] == "wall_mean_ms") - .expect("wall ranking"); - assert_eq!(wall_ranking["ranked_scenarios"][0]["id"], "beta"); - assert_eq!(wall_ranking["ranked_scenarios"][1]["id"], "alpha"); - assert_eq!(wall_ranking["ranked_scenarios"][2]["id"], "gamma"); - - let guest_execution_ranking = hotspot_rankings - .iter() - .find(|ranking| ranking["metric"] == "guest_execution_mean_ms") - .expect("guest execution ranking"); - assert_eq!(guest_execution_ranking["ranked_scenarios"][0]["id"], "beta"); - assert_eq!( - guest_execution_ranking["ranked_scenarios"][1]["id"], - "alpha" - ); - assert_eq!( - guest_execution_ranking["scenarios_without_metric"][0].as_str(), - Some("gamma") - ); - let rss_ranking = hotspot_rankings - .iter() - .find(|ranking| ranking["metric"] == "rss_mean_mib") - .expect("rss ranking"); - assert_eq!(rss_ranking["ranked_scenarios"][0]["id"], "beta"); - let cpu_ranking = hotspot_rankings - .iter() - .find(|ranking| ranking["metric"] == "cpu_total_mean_ms") - .expect("cpu ranking"); - assert_eq!(cpu_ranking["scenarios_without_metric"][0], "gamma"); - - let markdown = report.render_markdown(); - assert!(markdown.contains("## Ranked Hotspots")); - assert!(markdown.contains("## Stability And Resource Summary")); - assert!(markdown.contains("### Guest Execution Phase (`time`, `ms`)")); - assert!(markdown.contains("### RSS (`memory`, `MiB`)")); - assert!(markdown.contains("Missing metric for: `gamma`")); -} - -#[test] -fn javascript_benchmark_comparison_artifact_stays_stable_for_deltas() { - let report = JavascriptBenchmarkReport { - generated_at_unix_ms: 42, - config: JavascriptBenchmarkConfig { - iterations: 2, - warmup_iterations: 1, - }, - host: BenchmarkHost { - node_binary: String::from("node"), - node_version: String::from("v22.0.0"), - os: "linux", - arch: "x86_64", - logical_cpus: 8, - }, - repo_root: PathBuf::from("/repo"), - transport_rtt: vec![ - transport_rtt(32, vec![0.4, 0.6], stats(0.5, 0.4, 0.6, 0.4, 0.6, 0.1)), - transport_rtt(4096, vec![0.9, 1.1], stats(1.0, 0.9, 1.1, 0.9, 1.1, 0.1)), - transport_rtt(65536, vec![2.6, 3.0], stats(2.8, 2.6, 3.0, 2.6, 3.0, 0.2)), - ], - scenarios: vec![ - BenchmarkScenarioReport { - id: "fast-scenario", - workload: "fixture-a", - runtime: "native-execution", - mode: "true-cold-start", - description: "Faster benchmark path", - fixture: "fixture-a", - compile_cache: "disabled", - wall_samples_ms: vec![10.0, 14.0], - wall_stats: stats(12.0, 10.0, 14.0, 10.0, 14.0, 2.0), - guest_import_samples_ms: Some(vec![4.0, 6.0]), - guest_import_stats: Some(stats(5.0, 4.0, 6.0, 4.0, 6.0, 1.0)), - startup_overhead_samples_ms: Some(vec![6.0, 8.0]), - startup_overhead_stats: Some(stats(7.0, 6.0, 8.0, 6.0, 8.0, 1.0)), - phase_samples_ms: phase_samples( - vec![1.0, 2.0], - vec![2.0, 3.0], - Some(vec![4.0, 6.0]), - vec![3.0, 3.0], - ), - phase_stats: phase_stats( - stats(1.5, 1.0, 2.0, 1.0, 2.0, 0.5), - stats(2.5, 2.0, 3.0, 2.0, 3.0, 0.5), - Some(stats(5.0, 4.0, 6.0, 4.0, 6.0, 1.0)), - stats(3.0, 3.0, 3.0, 3.0, 3.0, 0.0), - ), - resource_usage_samples: None, - resource_usage_stats: None, - }, - BenchmarkScenarioReport { - id: "slow-scenario", - workload: "fixture-b", - runtime: "native-execution", - mode: "new-session-replay", - description: "Slower benchmark path", - fixture: "fixture-b", - compile_cache: "primed", - wall_samples_ms: vec![30.0, 34.0], - wall_stats: stats(32.0, 30.0, 34.0, 30.0, 34.0, 2.0), - guest_import_samples_ms: Some(vec![12.0, 14.0]), - guest_import_stats: Some(stats(13.0, 12.0, 14.0, 12.0, 14.0, 1.0)), - startup_overhead_samples_ms: Some(vec![18.0, 20.0]), - startup_overhead_stats: Some(stats(19.0, 18.0, 20.0, 18.0, 20.0, 1.0)), - phase_samples_ms: phase_samples( - vec![4.0, 4.0], - vec![5.0, 6.0], - Some(vec![12.0, 14.0]), - vec![9.0, 10.0], - ), - phase_stats: phase_stats( - stats(4.0, 4.0, 4.0, 4.0, 4.0, 0.0), - stats(5.5, 5.0, 6.0, 5.0, 6.0, 0.5), - Some(stats(13.0, 12.0, 14.0, 12.0, 14.0, 1.0)), - stats(9.5, 9.0, 10.0, 9.0, 10.0, 0.5), - ), - resource_usage_samples: None, - resource_usage_stats: None, - }, - BenchmarkScenarioReport { - id: "current-only", - workload: "fixture-c", - runtime: "host-node", - mode: "host-control", - description: "Current-only scenario", - fixture: "fixture-c", - compile_cache: "disabled", - wall_samples_ms: vec![8.0, 10.0], - wall_stats: stats(9.0, 8.0, 10.0, 8.0, 10.0, 1.0), - guest_import_samples_ms: None, - guest_import_stats: None, - startup_overhead_samples_ms: None, - startup_overhead_stats: None, - phase_samples_ms: phase_samples( - vec![1.0, 1.0], - vec![2.0, 3.0], - None, - vec![5.0, 6.0], - ), - phase_stats: phase_stats( - stats(1.0, 1.0, 1.0, 1.0, 1.0, 0.0), - stats(2.5, 2.0, 3.0, 2.0, 3.0, 0.5), - None, - stats(5.5, 5.0, 6.0, 5.0, 6.0, 0.5), - ), - resource_usage_samples: None, - resource_usage_stats: None, - }, - ], - }; - - let tempdir = tempdir().expect("create tempdir"); - let baseline_path = tempdir.path().join("baseline.json"); - fs::write( - &baseline_path, - r#"{ - "artifact_version": 1, - "generated_at_unix_ms": 24, - "scenarios": [ - { - "id": "fast-scenario", - "wall_stats": { - "mean_ms": 15.0, - "p50_ms": 15.0, - "p95_ms": 15.0, - "min_ms": 15.0, - "max_ms": 15.0, - "stddev_ms": 0.0 - }, - "guest_import_stats": { - "mean_ms": 6.0, - "p50_ms": 6.0, - "p95_ms": 6.0, - "min_ms": 6.0, - "max_ms": 6.0, - "stddev_ms": 0.0 - }, - "startup_overhead_stats": { - "mean_ms": 9.0, - "p50_ms": 9.0, - "p95_ms": 9.0, - "min_ms": 9.0, - "max_ms": 9.0, - "stddev_ms": 0.0 - } - }, - { - "id": "slow-scenario", - "wall_stats": { - "mean_ms": 28.0, - "p50_ms": 28.0, - "p95_ms": 28.0, - "min_ms": 28.0, - "max_ms": 28.0, - "stddev_ms": 0.0 - }, - "guest_import_stats": { - "mean_ms": 11.0, - "p50_ms": 11.0, - "p95_ms": 11.0, - "min_ms": 11.0, - "max_ms": 11.0, - "stddev_ms": 0.0 - }, - "startup_overhead_stats": { - "mean_ms": 17.0, - "p50_ms": 17.0, - "p95_ms": 17.0, - "min_ms": 17.0, - "max_ms": 17.0, - "stddev_ms": 0.0 - } - }, - { - "id": "baseline-only", - "wall_stats": { - "mean_ms": 5.0, - "p50_ms": 5.0, - "p95_ms": 5.0, - "min_ms": 5.0, - "max_ms": 5.0, - "stddev_ms": 0.0 - } - } - ] -}"#, - ) - .expect("write baseline report"); - - let comparison = report - .compare_to_baseline_path(&baseline_path) - .expect("load comparison"); - let json = report - .render_json_with_comparison(Some(&comparison)) - .expect("render comparison json"); - let parsed: Value = serde_json::from_str(&json).expect("parse comparison json"); - - assert_eq!( - parsed["comparison"]["summary"]["compared_scenario_count"], - 2 - ); - assert_eq!( - parsed["comparison"]["summary"]["largest_wall_improvement"]["id"].as_str(), - Some("fast-scenario") - ); - assert_eq!( - parsed["comparison"]["summary"]["largest_wall_regression"]["id"].as_str(), - Some("slow-scenario") - ); - assert_eq!( - parsed["comparison"]["scenario_deltas"][0]["wall_mean_ms"]["delta_ms"], - -3.0 - ); - assert_eq!( - parsed["comparison"]["scenario_deltas"][1]["wall_mean_ms"]["delta_ms"], - 4.0 - ); - assert!( - parsed["comparison"]["scenario_deltas"][0]["phase_mean_ms"].is_null(), - "phase deltas should stay absent when the baseline artifact has no phase data" - ); - assert_eq!( - parsed["comparison"]["scenarios_missing_from_baseline"][0].as_str(), - Some("current-only") - ); - assert_eq!( - parsed["comparison"]["baseline_only_scenarios"][0].as_str(), - Some("baseline-only") - ); - - let markdown = report.render_markdown_with_comparison(Some(&comparison)); - assert!(markdown.contains("## Baseline Comparison")); - assert!(markdown.contains("Context delta (ms)")); - assert!(markdown.contains("Largest wall-time improvement: `fast-scenario`")); - assert!(markdown.contains("Largest wall-time regression: `slow-scenario`")); - assert!(markdown.contains("Scenarios missing from baseline: current-only")); - assert!(markdown.contains("Baseline-only scenarios: baseline-only")); -} diff --git a/crates/execution/tests/bridge.rs b/crates/execution/tests/bridge.rs deleted file mode 100644 index 4aa52868f..000000000 --- a/crates/execution/tests/bridge.rs +++ /dev/null @@ -1,90 +0,0 @@ -#[path = "../../bridge/tests/support.rs"] -mod bridge_support; - -use bridge_support::RecordingBridge; -use secure_exec_bridge::{ - BridgeTypes, CreateJavascriptContextRequest, CreateWasmContextRequest, ExecutionEvent, - ExecutionHandleRequest, ExecutionSignal, GuestKernelCall, GuestRuntime, KillExecutionRequest, - PollExecutionEventRequest, StartExecutionRequest, WriteExecutionStdinRequest, -}; -use secure_exec_execution::NativeExecutionBridge; -use std::collections::BTreeMap; -use std::fmt::Debug; - -fn assert_native_execution_bridge(bridge: &mut B) -where - B: NativeExecutionBridge, - ::Error: Debug, -{ - let js = bridge - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-1"), - bootstrap_module: None, - }) - .expect("create js context"); - let wasm = bridge - .create_wasm_context(CreateWasmContextRequest { - vm_id: String::from("vm-1"), - module_path: Some(String::from("/workspace/module.wasm")), - }) - .expect("create wasm context"); - - assert_eq!(js.runtime, GuestRuntime::JavaScript); - assert_eq!(wasm.runtime, GuestRuntime::WebAssembly); - - let execution = bridge - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-1"), - context_id: js.context_id, - argv: vec![String::from("index.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start execution"); - - bridge - .write_stdin(WriteExecutionStdinRequest { - vm_id: String::from("vm-1"), - execution_id: execution.execution_id.clone(), - chunk: b"stdin".to_vec(), - }) - .expect("write stdin"); - bridge - .close_stdin(ExecutionHandleRequest { - vm_id: String::from("vm-1"), - execution_id: execution.execution_id.clone(), - }) - .expect("close stdin"); - bridge - .kill_execution(KillExecutionRequest { - vm_id: String::from("vm-1"), - execution_id: execution.execution_id, - signal: ExecutionSignal::Interrupt, - }) - .expect("kill execution"); - - match bridge - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-1"), - }) - .expect("poll event") - { - Some(ExecutionEvent::GuestRequest(event)) => { - assert_eq!(event.operation, "stdio.flush"); - } - other => panic!("unexpected execution event: {other:?}"), - } -} - -#[test] -fn execution_crate_compiles_against_method_oriented_execution_bridge() { - let mut bridge = RecordingBridge::default(); - bridge.push_execution_event(ExecutionEvent::GuestRequest(GuestKernelCall { - vm_id: String::from("vm-1"), - execution_id: String::from("exec-queued"), - operation: String::from("stdio.flush"), - payload: Vec::new(), - })); - - assert_native_execution_bridge(&mut bridge); -} diff --git a/crates/execution/tests/cjs_esm_interop.rs b/crates/execution/tests/cjs_esm_interop.rs deleted file mode 100644 index 13e51e7e6..000000000 --- a/crates/execution/tests/cjs_esm_interop.rs +++ /dev/null @@ -1,1314 +0,0 @@ -use secure_exec_execution::{ - javascript::ModuleResolutionTestHarness, CreateJavascriptContextRequest, - JavascriptExecutionEngine, JavascriptExecutionResult, StartJavascriptExecutionRequest, -}; -use serde_json::{json, Value}; -use std::collections::BTreeMap; -use std::fs; -use std::path::{Path, PathBuf}; -use tempfile::TempDir; - -struct Fixture { - temp: TempDir, -} - -impl Fixture { - fn new() -> Self { - Self { - temp: TempDir::new().expect("create temp dir"), - } - } - - fn root(&self) -> &Path { - self.temp.path() - } - - fn host_path(&self, relative: &str) -> PathBuf { - self.root().join(relative) - } - - fn write(&self, relative: &str, contents: &str) { - let path = self.host_path(relative); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).expect("create parent dirs"); - } - fs::write(path, contents).expect("write fixture"); - } - - fn write_json(&self, relative: &str, value: Value) { - self.write( - relative, - &serde_json::to_string_pretty(&value).expect("serialize JSON"), - ); - } - - fn resolver(&self) -> ModuleResolutionTestHarness { - ModuleResolutionTestHarness::new(self.root()) - } -} - -fn assert_import(fixture: &Fixture, specifier: &str, from_path: &str, expected: &str) { - let mut resolver = fixture.resolver(); - assert_eq!( - resolver.resolve_import(specifier, from_path), - Some(String::from(expected)) - ); -} - -fn assert_require(fixture: &Fixture, specifier: &str, from_path: &str, expected: &str) { - let mut resolver = fixture.resolver(); - assert_eq!( - resolver.resolve_require(specifier, from_path), - Some(String::from(expected)) - ); -} - -fn run_guest_result( - fixture: &Fixture, - entrypoint: &str, - env: BTreeMap, -) -> JavascriptExecutionResult { - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from(entrypoint)], - env, - cwd: fixture.root().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - execution.wait().expect("wait for JavaScript execution") -} - -fn assert_guest_success(result: &JavascriptExecutionResult) { - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!( - result.exit_code, 0, - "guest exited with {}\nstdout:\n{}\nstderr:\n{}", - result.exit_code, stdout, stderr - ); - assert!(result.stderr.is_empty(), "unexpected stderr: {}", stderr); -} - -fn run_guest_json(fixture: &Fixture, entrypoint: &str) -> Value { - let result = run_guest_result(fixture, entrypoint, BTreeMap::new()); - assert_guest_success(&result); - serde_json::from_slice(&result.stdout).expect("parse guest stdout as JSON") -} - -fn resolution_nested_exports_conditions_recurse_three_levels() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - json!({ - "exports": { - ".": { - "import": { - "node": { - "default": "./dist/node-default.mjs" - }, - "default": "./dist/import-default.mjs" - }, - "default": "./dist/fallback.mjs" - } - } - }), - ); - fixture.write( - "node_modules/pkg/dist/node-default.mjs", - "export default 'node';", - ); - fixture.write( - "node_modules/pkg/dist/import-default.mjs", - "export default 'import-default';", - ); - fixture.write( - "node_modules/pkg/dist/fallback.mjs", - "export default 'fallback';", - ); - - assert_import( - &fixture, - "pkg", - "/root/project/index.mjs", - "/root/node_modules/pkg/dist/node-default.mjs", - ); -} - -fn resolution_exports_array_and_condition_nesting_uses_first_valid_target() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - json!({ - "exports": { - ".": [ - { "browser": "./dist/browser.mjs" }, - { - "import": { - "node": { - "default": "./dist/node.mjs" - } - } - }, - "./dist/fallback.mjs" - ] - } - }), - ); - fixture.write("node_modules/pkg/dist/node.mjs", "export default 'node';"); - fixture.write( - "node_modules/pkg/dist/fallback.mjs", - "export default 'fallback';", - ); - - assert_import( - &fixture, - "pkg", - "/root/project/index.mjs", - "/root/node_modules/pkg/dist/node.mjs", - ); -} - -fn resolution_require_prefers_cjs_entry_for_dual_packages() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - json!({ - "exports": { - ".": { - "import": "./dist/index.mjs", - "require": "./dist/index.cjs", - "default": "./dist/index.mjs" - } - } - }), - ); - fixture.write("node_modules/pkg/dist/index.mjs", "export default 'esm';"); - fixture.write("node_modules/pkg/dist/index.cjs", "module.exports = 'cjs';"); - - assert_require( - &fixture, - "pkg", - "/root/project/index.cjs", - "/root/node_modules/pkg/dist/index.cjs", - ); -} - -fn resolution_invalid_utf8_file_url_specifiers_are_rejected() { - let fixture = Fixture::new(); - fixture.write("entry.mjs", "export default 1;"); - fixture.write("node_modules/file:/%FF.js", "export default 'fallback';"); - - let mut resolver = fixture.resolver(); - assert_eq!( - resolver.resolve_import("file:///%FF", "/root/project/index.mjs"), - None - ); - assert_eq!( - resolver.resolve_import("file:///%Fé", "/root/project/index.mjs"), - None - ); -} - -fn runtime_exports_dot_named_exports_are_available_to_esm_imports() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - "exports.answer = 42;\nexports.label = 'ok';\nmodule.exports.extra = true;\n", - ); - fixture.write( - "entry.mjs", - r#" -import dep, { answer, label, extra } from "./dep.cjs"; -console.log(JSON.stringify({ answer, label, extra, defaultAnswer: dep.answer })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!( - output, - json!({ - "answer": 42, - "label": "ok", - "extra": true, - "defaultAnswer": 42 - }) - ); -} - -fn runtime_minified_type_module_js_is_not_misclassified_as_cjs() { - let fixture = Fixture::new(); - fixture.write_json("package.json", json!({ "type": "module" })); - fixture.write( - "cli.js", - r#"import{createRequire as H}from"node:module";const require=H(import.meta.url);console.log(JSON.stringify({argv:process.argv.slice(1),fsType:typeof require("node:fs").readFileSync}))"#, - ); - - let output = run_guest_json(&fixture, "./cli.js"); - assert_eq!( - output, - json!({ - "argv": ["/root/cli.js"], - "fsType": "function" - }) - ); -} - -fn runtime_object_define_property_exports_are_available_to_esm_imports() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -Object.defineProperty(exports, "answer", { enumerable: true, value: 42 }); -Object.defineProperty(exports, "label", { enumerable: true, value: "ok" }); -"#, - ); - fixture.write( - "entry.mjs", - r#" -import dep, { answer, label } from "./dep.cjs"; -console.log(JSON.stringify({ answer, label, defaultLabel: dep.label })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!( - output, - json!({ - "answer": 42, - "label": "ok", - "defaultLabel": "ok" - }) - ); -} - -fn runtime_computed_property_cjs_modules_still_work_via_default_import() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -const key = "dynamic"; -module.exports = { [key]: 7, plain: 1 }; -"#, - ); - fixture.write( - "entry.mjs", - r#" -import dep from "./dep.cjs"; -console.log(JSON.stringify(dep)); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "dynamic": 7, "plain": 1 })); -} - -fn runtime_exports_bracket_assignment_preserves_default_export_shape() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -const name = "alpha"; -exports[name] = 1; -module.exports.beta = 2; -"#, - ); - fixture.write( - "entry.mjs", - r#" -import dep, { beta } from "./dep.cjs"; -console.log(JSON.stringify({ alpha: dep.alpha, beta, defaultBeta: dep.beta })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!( - output, - json!({ - "alpha": 1, - "beta": 2, - "defaultBeta": 2 - }) - ); -} - -fn runtime_object_assign_module_exports_exposes_named_esm_imports_via_runtime_fallback() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -Object.assign(module.exports, { answer: 42, label: "ok" }); -"#, - ); - fixture.write( - "entry.mjs", - r#" -import dep, { answer, label } from "./dep.cjs"; -console.log(JSON.stringify({ answer, label, defaultAnswer: dep.answer })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!( - output, - json!({ "answer": 42, "label": "ok", "defaultAnswer": 42 }) - ); -} - -fn runtime_spread_based_module_exports_still_exposes_the_default_export_shape() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -const shared = { alpha: 1 }; -module.exports = { ...shared, beta: 2 }; -"#, - ); - fixture.write( - "entry.mjs", - r#" -import dep from "./dep.cjs"; -console.log(JSON.stringify(dep)); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "alpha": 1, "beta": 2 })); -} - -fn runtime_object_create_descriptor_exports_expose_named_esm_imports_via_runtime_fallback() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -const proto = { inherited: 99 }; -module.exports = Object.create(proto, { - x: { value: 1, enumerable: true }, - hidden: { value: 2, enumerable: false } -}); -"#, - ); - fixture.write( - "entry.mjs", - r#" -import dep, { x } from "./dep.cjs"; -console.log(JSON.stringify({ - x, - defaultX: dep.x, - inherited: dep.inherited, - hasHidden: Object.prototype.hasOwnProperty.call(dep, "hidden") -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!( - output, - json!({ "x": 1, "defaultX": 1, "inherited": 99, "hasHidden": true }) - ); -} - -fn runtime_cjs_reexport_preserves_named_esm_imports_via_runtime_fallback() { - let fixture = Fixture::new(); - fixture.write( - "other.cjs", - r#" -Object.assign(module.exports, { alpha: 1, beta: 2 }); -"#, - ); - fixture.write( - "dep.cjs", - r#" -module.exports = require("./other.cjs"); -"#, - ); - fixture.write( - "entry.mjs", - r#" -import dep, { alpha, beta } from "./dep.cjs"; -console.log(JSON.stringify({ alpha, beta, defaultAlpha: dep.alpha })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "alpha": 1, "beta": 2, "defaultAlpha": 1 })); -} - -fn runtime_require_of_esm_only_packages_either_loads_or_throws_clearly() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - json!({ - "type": "module", - "exports": "./index.mjs" - }), - ); - fixture.write( - "node_modules/pkg/index.mjs", - "export default { value: 42 };", - ); - fixture.write( - "entry.cjs", - r#" -try { - const value = require("pkg"); - console.log(JSON.stringify({ - mode: "loaded", - value: value && value.default ? value.default.value : value.value - })); -} catch (error) { - console.log(JSON.stringify({ - mode: "error", - code: error && error.code ? error.code : null, - message: String(error && error.message ? error.message : error) - })); -} -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - match output.get("mode").and_then(Value::as_str) { - Some("loaded") => { - assert_eq!(output.get("value"), Some(&json!(42))); - } - Some("error") => { - let message = output - .get("message") - .and_then(Value::as_str) - .expect("error message"); - assert!(!message.is_empty(), "expected a non-empty error message"); - } - other => panic!("unexpected require(pkg) mode: {other:?}"), - } -} - -fn runtime_require_type_module_js_main_throws_require_esm() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - json!({ - "type": "module", - "main": "./dist/index.js" - }), - ); - fixture.write("node_modules/pkg/dist/index.js", "export const value = 42;"); - fixture.write( - "entry.cjs", - r#" -try { - require("pkg"); - console.log(JSON.stringify({ mode: "loaded" })); -} catch (error) { - console.log(JSON.stringify({ - mode: "error", - code: error && error.code ? error.code : null, - message: String(error && error.message ? error.message : error) - })); -} -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!(output.get("mode"), Some(&json!("error"))); - assert_eq!(output.get("code"), Some(&json!("ERR_REQUIRE_ESM"))); - let message = output - .get("message") - .and_then(Value::as_str) - .expect("error message"); - assert!(message.contains("require() of ES Module")); -} - -fn runtime_require_fails_closed_when_module_format_bridge_is_missing() { - let fixture = Fixture::new(); - fixture.write("dep.js", "module.exports = { value: 42 };\n"); - fixture.write( - "entry.cjs", - r#" -let bridgeOverride = "not-attempted"; -try { - Object.defineProperty(globalThis, "_moduleFormat", { - configurable: true, - writable: true, - value: undefined - }); - bridgeOverride = "defined"; -} catch (error) { - bridgeOverride = `define-failed:${error && error.message ? error.message : error}`; -} - -try { - require("./dep.js"); - console.log(JSON.stringify({ mode: "loaded", bridgeOverride })); -} catch (error) { - console.log(JSON.stringify({ - mode: "error", - bridgeOverride, - code: error && error.code ? error.code : null, - message: String(error && error.message ? error.message : error) - })); -} -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!(output.get("bridgeOverride"), Some(&json!("defined"))); - assert_eq!(output.get("mode"), Some(&json!("error"))); - assert_eq!( - output.get("code"), - Some(&json!("ERR_AGENTOS_MODULE_FORMAT_BRIDGE_MISSING")) - ); - let message = output - .get("message") - .and_then(Value::as_str) - .expect("error message"); - assert!( - message.contains("module format bridge is not registered"), - "unexpected missing bridge error message: {message}" - ); -} - -fn runtime_import_module_condition_js_target_uses_esm_syntax() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - json!({ - "exports": { - ".": { - "module": "./build/esm/index.js", - "default": "./build/src/index.js" - } - } - }), - ); - fixture.write( - "node_modules/pkg/build/esm/index.js", - "export { answer } from './status';", - ); - fixture.write( - "node_modules/pkg/build/esm/status.js", - "export const answer = 42;", - ); - fixture.write("node_modules/pkg/build/src/index.js", "exports.answer = 7;"); - fixture.write( - "entry.mjs", - r#" -import { answer } from "pkg"; -console.log(JSON.stringify({ answer })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output.get("answer"), Some(&json!(42))); -} - -fn runtime_type_module_export_subpaths_keep_js_files_in_esm_mode() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - json!({ - "type": "module", - "exports": { - "./runtime": "./dist/runtime.js" - } - }), - ); - fixture.write( - "node_modules/pkg/dist/runtime.js", - r#" -globalThis.__pkgRuntimeUrl = import.meta.url; -"#, - ); - fixture.write( - "entry.mjs", - r#" -import "pkg/runtime"; -console.log(JSON.stringify({ - isFileUrl: - typeof globalThis.__pkgRuntimeUrl === "string" && - globalThis.__pkgRuntimeUrl.startsWith("file:///root/node_modules/pkg/dist/runtime.js") -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "isFileUrl": true })); -} - -fn runtime_require_of_dual_packages_uses_the_cjs_entrypoint() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - json!({ - "exports": { - ".": { - "import": "./dist/index.mjs", - "require": "./dist/index.cjs", - "default": "./dist/index.mjs" - } - } - }), - ); - fixture.write( - "node_modules/pkg/dist/index.mjs", - "export default { kind: 'esm' };", - ); - fixture.write( - "node_modules/pkg/dist/index.cjs", - "module.exports = { kind: 'cjs' };", - ); - fixture.write( - "entry.cjs", - r#"console.log(JSON.stringify(require("pkg")));"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!(output, json!({ "kind": "cjs" })); -} - -fn runtime_two_module_circular_require_exposes_partial_exports() { - let fixture = Fixture::new(); - fixture.write( - "a.cjs", - r#" -exports.name = "a"; -const b = require("./b.cjs"); -exports.fromB = b.name; -exports.seesBReady = Boolean(b.ready); -exports.ready = true; -"#, - ); - fixture.write( - "b.cjs", - r#" -exports.name = "b"; -const a = require("./a.cjs"); -exports.fromA = a.name; -exports.seesAReady = Boolean(a.ready); -exports.ready = true; -"#, - ); - fixture.write( - "entry.cjs", - r#" -const a = require("./a.cjs"); -const b = require("./b.cjs"); -console.log(JSON.stringify({ a, b })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!( - output, - json!({ - "a": { - "name": "a", - "fromB": "b", - "seesBReady": true, - "ready": true - }, - "b": { - "name": "b", - "fromA": "a", - "seesAReady": false, - "ready": true - } - }) - ); -} - -fn runtime_three_module_circular_chains_complete_without_hanging() { - let fixture = Fixture::new(); - fixture.write( - "a.cjs", - r#" -exports.name = "a"; -const b = require("./b.cjs"); -exports.chain = (b.chain || []).concat("a"); -"#, - ); - fixture.write( - "b.cjs", - r#" -exports.name = "b"; -const c = require("./c.cjs"); -exports.chain = (c.chain || []).concat("b"); -"#, - ); - fixture.write( - "c.cjs", - r#" -exports.name = "c"; -const a = require("./a.cjs"); -exports.chain = [a.name || "missing", "c"]; -"#, - ); - fixture.write( - "entry.cjs", - r#" -const a = require("./a.cjs"); -const b = require("./b.cjs"); -const c = require("./c.cjs"); -console.log(JSON.stringify({ a: a.chain, b: b.chain, c: c.chain })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!( - output, - json!({ - "a": ["a", "c", "b", "a"], - "b": ["a", "c", "b"], - "c": ["a", "c"] - }) - ); -} - -fn runtime_circular_requires_use_cache_instead_of_re_evaluating_modules() { - let fixture = Fixture::new(); - fixture.write( - "a.cjs", - r#" -globalThis.__aLoads = (globalThis.__aLoads || 0) + 1; -exports.name = "a"; -exports.fromB = require("./b.cjs").name; -"#, - ); - fixture.write( - "b.cjs", - r#" -globalThis.__bLoads = (globalThis.__bLoads || 0) + 1; -exports.name = "b"; -exports.fromA = require("./a.cjs").name; -"#, - ); - fixture.write( - "entry.cjs", - r#" -const first = require("./a.cjs"); -const second = require("./a.cjs"); -console.log(JSON.stringify({ - sameInstance: first === second, - aLoads: globalThis.__aLoads, - bLoads: globalThis.__bLoads, - first, - second -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!(output.get("sameInstance"), Some(&json!(true))); - assert_eq!(output.get("aLoads"), Some(&json!(1))); - assert_eq!(output.get("bLoads"), Some(&json!(1))); - assert_eq!( - output.get("first"), - Some(&json!({ "name": "a", "fromB": "b" })) - ); - assert_eq!( - output.get("second"), - Some(&json!({ "name": "a", "fromB": "b" })) - ); -} - -fn runtime_require_json_returns_the_parsed_object() { - let fixture = Fixture::new(); - fixture.write("data.json", r#"{ "name": "agentos", "ok": true }"#); - fixture.write( - "entry.cjs", - r#"console.log(JSON.stringify(require("./data.json")));"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!(output, json!({ "name": "agentos", "ok": true })); -} - -fn runtime_require_invalid_json_surfaces_a_parse_error() { - let fixture = Fixture::new(); - fixture.write( - "data.json", - "{\n // comments are not valid JSON\n \"ok\": true,\n}\n", - ); - fixture.write( - "entry.cjs", - r#" -try { - require("./data.json"); - throw new Error("require should have failed"); -} catch (error) { - console.log(JSON.stringify({ - message: String(error && error.message ? error.message : error) - })); -} -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - let message = output - .get("message") - .and_then(Value::as_str) - .expect("error message"); - assert!( - message.contains("Unexpected") || message.contains("JSON"), - "unexpected invalid JSON error: {message}" - ); -} - -fn runtime_esm_entrypoints_can_use_require_via_the_runtime_prelude() { - let fixture = Fixture::new(); - fixture.write("dep.cjs", "module.exports = { answer: 42 };"); - fixture.write( - "entry.mjs", - r#" -const dep = require("./dep.cjs"); -console.log(JSON.stringify(dep)); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "answer": 42 })); -} - -fn runtime_esm_default_import_of_cjs_uses_module_exports_value() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -module.exports = function greet(name) { - return `hello ${name}`; -}; -"#, - ); - fixture.write( - "entry.mjs", - r#" -import greet from "./dep.cjs"; -console.log(JSON.stringify({ greeting: greet("agent") })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "greeting": "hello agent" })); -} - -fn runtime_esm_named_imports_of_cjs_use_the_extracted_names() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -exports.answer = 42; -exports.label = "ok"; -"#, - ); - fixture.write( - "entry.mjs", - r#" -import { answer, label } from "./dep.cjs"; -console.log(JSON.stringify({ answer, label })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "answer": 42, "label": "ok" })); -} - -fn runtime_builtin_assert_exposes_deep_strict_equal() { - let fixture = Fixture::new(); - fixture.write( - "entry.cjs", - r#" -const assert = require("node:assert"); -assert.deepStrictEqual({ nested: ["ok"] }, { nested: ["ok"] }); -console.log(JSON.stringify({ - deepStrictEqual: typeof assert.deepStrictEqual -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!(output, json!({ "deepStrictEqual": "function" })); -} - -fn runtime_builtin_assert_exposes_throws() { - let fixture = Fixture::new(); - fixture.write( - "entry.cjs", - r#" -const assert = require("node:assert"); -assert.throws(() => { - throw new Error("boom"); -}, /boom/); -console.log(JSON.stringify({ throws: typeof assert.throws })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!(output, json!({ "throws": "function" })); -} - -fn runtime_builtin_path_normalize_matches_expected_edge_cases() { - let fixture = Fixture::new(); - fixture.write( - "entry.cjs", - r#" -const path = require("node:path"); -console.log(JSON.stringify({ - dot: path.normalize("."), - dotDot: path.normalize("foo/../bar"), - trailing: path.normalize("/tmp/demo/"), - repeated: path.normalize("/tmp//demo//../file") -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!( - output, - json!({ - "dot": ".", - "dotDot": "bar", - "trailing": "/tmp/demo", - "repeated": "/tmp/file" - }) - ); -} - -fn runtime_builtin_path_resolve_and_relative_match_expected_values() { - let fixture = Fixture::new(); - fixture.write( - "entry.cjs", - r#" -const path = require("node:path"); -console.log(JSON.stringify({ - resolve: path.resolve("alpha", "..", "beta", "file.txt"), - relative: path.relative("/root/project/src", "/root/project/tests/spec"), - same: path.relative("/root/project", "/root/project") -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!( - output, - json!({ - "resolve": "/root/beta/file.txt", - "relative": "../tests/spec", - "same": "" - }) - ); -} - -fn runtime_object_assign_module_exports_named_exports_are_visible_to_esm_imports() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -Object.assign(module.exports, { answer: 42, label: "ok" }); -"#, - ); - fixture.write( - "entry.mjs", - r#" -import { answer, label } from "./dep.cjs"; -console.log(JSON.stringify({ answer, label })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "answer": 42, "label": "ok" })); -} - -fn runtime_spread_based_module_exports_named_exports_are_visible_to_esm_imports() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -const shared = { alpha: 1 }; -module.exports = { ...shared, beta: 2 }; -"#, - ); - fixture.write( - "entry.mjs", - r#" -import { alpha, beta } from "./dep.cjs"; -console.log(JSON.stringify({ alpha, beta })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "alpha": 1, "beta": 2 })); -} - -fn runtime_object_define_properties_reexports_are_visible_to_esm_imports() { - let fixture = Fixture::new(); - fixture.write( - "dep.cjs", - r#" -Object.defineProperties(module.exports, { - answer: { enumerable: true, value: 42 }, - label: { enumerable: true, value: "ok" } -}); -"#, - ); - fixture.write( - "entry.mjs", - r#" -import { answer, label } from "./dep.cjs"; -console.log(JSON.stringify({ answer, label })); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "answer": 42, "label": "ok" })); -} - -fn runtime_esm_json_imports_return_the_parsed_object() { - let fixture = Fixture::new(); - fixture.write("data.json", r#"{ "name": "agentos", "ok": true }"#); - fixture.write( - "entry.mjs", - r#" -import data from "./data.json"; -console.log(JSON.stringify(data)); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "name": "agentos", "ok": true })); -} - -fn runtime_intl_datetime_format_does_not_crash() { - let fixture = Fixture::new(); - fixture.write( - "entry.mjs", - r#" -console.log(JSON.stringify({ - formatted: new Intl.DateTimeFormat("en-US").format(new Date("2024-01-02T03:04:05Z")) -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!(output, json!({ "formatted": "2024-01-02" })); -} - -fn runtime_buffer_base64url_encoding_matches_node_behavior() { - let fixture = Fixture::new(); - fixture.write( - "entry.mjs", - r#" -const encoded = Buffer.from("hello").toString("base64url"); -const decoded = Buffer.from(encoded, "base64url").toString("utf8"); -console.log(JSON.stringify({ - isEncoding: Buffer.isEncoding("base64url"), - encoded, - decoded, - byteLength: Buffer.byteLength(encoded, "base64url") -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!( - output, - json!({ - "isEncoding": true, - "encoded": "aGVsbG8", - "decoded": "hello", - "byteLength": 5 - }) - ); -} - -fn runtime_relative_file_urls_preserve_directory_trailing_slashes() { - let fixture = Fixture::new(); - fixture.write( - "entry.mjs", - r#" -const base = "file:///node_modules/.pnpm/pkg/node_modules/pkg/dist/content/utils.js"; -const pkgBase = new URL("../../", base); -console.log(JSON.stringify({ - pkgBase: String(pkgBase), - template: String(new URL("templates/content/types.d.ts", pkgBase)) -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!( - output, - json!({ - "pkgBase": "file:///node_modules/.pnpm/pkg/node_modules/pkg/", - "template": "file:///node_modules/.pnpm/pkg/node_modules/pkg/templates/content/types.d.ts" - }) - ); -} - -fn runtime_require_module_returns_the_module_constructor_shape() { - let fixture = Fixture::new(); - fixture.write( - "entry.cjs", - r#" -const mod = require("module"); -console.log(JSON.stringify({ - hasPrototypeRequire: typeof mod.prototype?.require === "function", - sameConstructor: mod.Module === mod, - hasCreateRequire: typeof mod.createRequire === "function" -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!( - output, - json!({ - "hasPrototypeRequire": true, - "sameConstructor": true, - "hasCreateRequire": true - }) - ); -} - -fn runtime_cjs_entrypoints_can_use_dynamic_import() { - let fixture = Fixture::new(); - fixture.write("dep.mjs", "export const answer = 42;\n"); - fixture.write( - "entry.cjs", - r#" -(async () => { - const mod = await import("./dep.mjs"); - console.log(JSON.stringify({ answer: mod.answer })); -})().catch((error) => { - console.error(String(error && error.stack ? error.stack : error)); - process.exit(1); -}); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.cjs"); - assert_eq!(output, json!({ "answer": 42 })); -} - -fn runtime_export_star_reexport_with_own_static_exports_exposes_all_named_esm_imports() { - // Reproduces `@sinclair/typebox/compiler`: a tsc-compiled barrel that BOTH assigns its own - // export statically (`exports.ValueErrorType = ...`, which static extraction finds, so the set - // is non-empty) AND re-exports a submodule's names at runtime via `__exportStar` (which static - // extraction cannot see). Before the fix, a non-empty static set skipped the runtime fallback, - // so `TypeCompiler` was dropped and `import { TypeCompiler }` threw - // "does not provide an export named 'TypeCompiler'". - let fixture = Fixture::new(); - fixture.write( - "sub.cjs", - r#" -Object.defineProperty(exports, "__esModule", { value: true }); -exports.TypeCompiler = void 0; -exports.TypeCompiler = "compiler"; -"#, - ); - fixture.write( - "barrel.cjs", - r#" -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __exportStar = (this && this.__exportStar) || function(m, exports) { - for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ValueErrorType = void 0; -exports.ValueErrorType = 7; -__exportStar(require("./sub.cjs"), exports); -"#, - ); - fixture.write( - "entry.mjs", - r#" -import barrel, { ValueErrorType, TypeCompiler } from "./barrel.cjs"; -console.log(JSON.stringify({ - ValueErrorType, - TypeCompiler, - defaultValueErrorType: barrel.ValueErrorType, - defaultTypeCompiler: barrel.TypeCompiler, -})); -"#, - ); - - let output = run_guest_json(&fixture, "./entry.mjs"); - assert_eq!( - output, - json!({ - "ValueErrorType": 7, - "TypeCompiler": "compiler", - "defaultValueErrorType": 7, - "defaultTypeCompiler": "compiler" - }) - ); -} - -#[test] -fn cjs_esm_interop_suite() { - // Keep V8-backed integration coverage inside one top-level libtest case. - // Running these guest-runtime cases as separate tests in the same binary - // still trips a V8 teardown/init boundary crash between cases. - resolution_nested_exports_conditions_recurse_three_levels(); - resolution_exports_array_and_condition_nesting_uses_first_valid_target(); - resolution_require_prefers_cjs_entry_for_dual_packages(); - resolution_invalid_utf8_file_url_specifiers_are_rejected(); - runtime_exports_dot_named_exports_are_available_to_esm_imports(); - runtime_minified_type_module_js_is_not_misclassified_as_cjs(); - runtime_object_define_property_exports_are_available_to_esm_imports(); - runtime_computed_property_cjs_modules_still_work_via_default_import(); - runtime_exports_bracket_assignment_preserves_default_export_shape(); - runtime_object_assign_module_exports_exposes_named_esm_imports_via_runtime_fallback(); - runtime_spread_based_module_exports_still_exposes_the_default_export_shape(); - runtime_object_create_descriptor_exports_expose_named_esm_imports_via_runtime_fallback(); - runtime_cjs_reexport_preserves_named_esm_imports_via_runtime_fallback(); - runtime_export_star_reexport_with_own_static_exports_exposes_all_named_esm_imports(); - runtime_require_of_esm_only_packages_either_loads_or_throws_clearly(); - runtime_require_type_module_js_main_throws_require_esm(); - runtime_require_fails_closed_when_module_format_bridge_is_missing(); - runtime_import_module_condition_js_target_uses_esm_syntax(); - runtime_type_module_export_subpaths_keep_js_files_in_esm_mode(); - runtime_require_of_dual_packages_uses_the_cjs_entrypoint(); - runtime_two_module_circular_require_exposes_partial_exports(); - runtime_three_module_circular_chains_complete_without_hanging(); - runtime_circular_requires_use_cache_instead_of_re_evaluating_modules(); - runtime_require_json_returns_the_parsed_object(); - runtime_require_invalid_json_surfaces_a_parse_error(); - runtime_esm_entrypoints_can_use_require_via_the_runtime_prelude(); - runtime_esm_default_import_of_cjs_uses_module_exports_value(); - runtime_esm_named_imports_of_cjs_use_the_extracted_names(); - runtime_builtin_assert_exposes_deep_strict_equal(); - runtime_builtin_assert_exposes_throws(); - runtime_builtin_path_normalize_matches_expected_edge_cases(); - runtime_builtin_path_resolve_and_relative_match_expected_values(); - runtime_object_assign_module_exports_named_exports_are_visible_to_esm_imports(); - runtime_spread_based_module_exports_named_exports_are_visible_to_esm_imports(); - runtime_object_define_properties_reexports_are_visible_to_esm_imports(); - runtime_esm_json_imports_return_the_parsed_object(); - runtime_intl_datetime_format_does_not_crash(); - runtime_buffer_base64url_encoding_matches_node_behavior(); - runtime_relative_file_urls_preserve_directory_trailing_slashes(); - runtime_require_module_returns_the_module_constructor_shape(); - runtime_cjs_entrypoints_can_use_dynamic_import(); -} diff --git a/crates/execution/tests/javascript_v8.rs b/crates/execution/tests/javascript_v8.rs deleted file mode 100644 index e6568852d..000000000 --- a/crates/execution/tests/javascript_v8.rs +++ /dev/null @@ -1,6033 +0,0 @@ -use base64::Engine; -use secure_exec_execution::{ - v8_runtime::map_bridge_method, CreateJavascriptContextRequest, GuestRuntimeConfig, - JavascriptExecution, JavascriptExecutionEngine, JavascriptExecutionEvent, - JavascriptExecutionLimits, JavascriptExecutionResult, JavascriptSyncRpcRequest, - StartJavascriptExecutionRequest, -}; -use serde::Deserialize; -use serde_json::{json, Value}; -use std::collections::{BTreeMap, VecDeque}; -use std::fs; -use std::io::{Read, Write}; -use std::os::unix::fs::symlink; -use std::os::unix::fs::PermissionsExt; -use std::path::Path; -use std::process::{Child, ChildStdin, Command, Stdio}; -use std::sync::mpsc::{self, Receiver, Sender, TryRecvError}; -use std::thread; -use std::time::{Duration, Instant}; -use tempfile::tempdir; - -/* -US-040 execution-test audit - -Deleted coverage: -- `tests/javascript.rs`: removed because the file only exercised the old - `legacy-js-tests` host-Node guest path (`loader.mjs`, `runner.mjs`, - import-cache mutation, and `Command::new("node")` process behavior). The V8 - isolate path no longer uses that guest execution model. -- `permission_flags::node_permission_flags_do_not_expose_workspace_root_or_entrypoint_parent_writes`: - removed because its JavaScript assertions depended on host-Node permission - flags emitted for guest JS launches. V8 guest JS now stays in-process, while - the remaining permission-flag tests still cover the real host-Node launches - that remain for Python and WASM. -- `benchmark::javascript_benchmark_harness_covers_required_startup_and_import_scenarios`: - removed because it depended on pre-V8 benchmark marker behavior from the old - startup harness instead of validating the current V8 execution path. The - stable artifact and markdown benchmark tests remain. -*/ - -// Timing-sensitive assertions flake under the CPU contention of a parallel test -// run (see CLAUDE.md > Testing). Gated off by default; the nightly timing lane -// sets SECURE_EXEC_RUN_TIMING_TESTS=1 to enforce them. -fn run_timing_sensitive_tests() -> bool { - std::env::var_os("SECURE_EXEC_RUN_TIMING_TESTS").is_some() -} - -fn write_fixture(path: &Path, contents: &str) { - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).expect("create fixture parent dirs"); - } - fs::write(path, contents).expect("write fixture"); -} - -fn run_host_node_json(cwd: &Path, entrypoint: &Path) -> Value { - let output = Command::new("node") - .arg(entrypoint) - .current_dir(cwd) - .output() - .expect("run host node"); - - assert!( - output.status.success(), - "host node failed with status {:?}\nstdout:\n{}\nstderr:\n{}", - output.status.code(), - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ); - - serde_json::from_slice(&output.stdout).expect("parse host JSON") -} - -fn write_fake_node_binary(path: &Path, log_path: &Path) { - let script = format!( - "#!/bin/sh\nset -eu\nprintf 'guest-node-invoked\\n' >> \"{}\"\nexit 99\n", - log_path.display() - ); - fs::write(path, script).expect("write fake node binary"); - let mut permissions = fs::metadata(path) - .expect("fake node metadata") - .permissions(); - permissions.set_mode(0o755); - fs::set_permissions(path, permissions).expect("chmod fake node binary"); -} - -#[derive(Debug, Deserialize, Default)] -#[serde(rename_all = "camelCase")] -struct TestJavascriptChildProcessSpawnOptions { - #[serde(default)] - cwd: Option, - #[serde(default)] - env: BTreeMap, - #[serde(default)] - internal_bootstrap_env: BTreeMap, - #[serde(default)] - shell: bool, - #[serde(default)] - timeout: Option, - #[serde(default, rename = "killSignal")] - kill_signal: Option, -} - -#[derive(Debug, Deserialize)] -struct TestJavascriptChildProcessSpawnRequest { - command: String, - #[serde(default)] - args: Vec, - #[serde(default)] - options: TestJavascriptChildProcessSpawnOptions, -} - -type TestJavascriptChildProcessSpawnSyncRequest = ( - TestJavascriptChildProcessSpawnRequest, - Option, - Option>, -); - -#[derive(Debug, Deserialize, Default)] -#[serde(rename_all = "camelCase")] -struct TestLegacyJavascriptChildProcessSpawnOptions { - #[serde(default)] - cwd: Option, - #[serde(default)] - env: BTreeMap, - #[serde(default)] - input: Option, - #[serde(default)] - shell: bool, - #[serde(default, rename = "maxBuffer")] - max_buffer: Option, - #[serde(default)] - timeout: Option, - #[serde(default, rename = "killSignal")] - kill_signal: Option, -} - -enum HostChildOutputEvent { - Stdout(Vec), - Stderr(Vec), - StreamClosed, -} - -struct HostChildRecord { - child: Child, - stdin: Option, - output_events: Receiver, - pending_events: VecDeque, - exit_status: Option, - open_streams: usize, -} - -#[derive(Default)] -struct HostChildProcessHarness { - next_child_id: usize, - children: BTreeMap, -} - -impl HostChildProcessHarness { - fn handle_request( - &mut self, - host_cwd: &Path, - request: JavascriptSyncRpcRequest, - ) -> Result { - match request.method.as_str() { - "child_process.spawn" => self.spawn(host_cwd, &request.args), - "child_process.spawn_sync" => self.spawn_sync(host_cwd, &request.args), - "child_process.poll" => self.poll(&request.args), - "child_process.write_stdin" => self.write_stdin(&request.args), - "child_process.close_stdin" => self.close_stdin(&request.args), - "child_process.kill" => self.kill(&request.args), - "fs.writeFileSync" => self.write_file(host_cwd, &request.args), - other => Err(format!("unsupported sync RPC method: {other}")), - } - } - - fn spawn(&mut self, host_cwd: &Path, args: &[Value]) -> Result { - let request = parse_test_child_process_spawn_request(args)?; - - let child_id = { - self.next_child_id += 1; - format!("child-{}", self.next_child_id) - }; - - let mut command = if request.options.shell { - let mut command = Command::new("/bin/sh"); - command.arg("-c").arg(&request.command); - command.args(&request.args); - command - } else { - let mut command = Command::new(self.map_guest_path(host_cwd, &request.command)); - command.args( - request - .args - .iter() - .map(|arg| self.map_guest_path(host_cwd, arg)), - ); - command - }; - - let child_cwd = request - .options - .cwd - .as_deref() - .map(|cwd| std::path::PathBuf::from(self.map_guest_path(host_cwd, cwd))) - .unwrap_or_else(|| host_cwd.to_path_buf()); - - command - .current_dir(child_cwd) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .env_clear() - .envs(&request.options.env) - .envs(&request.options.internal_bootstrap_env); - - let mut child = command - .spawn() - .map_err(|error| format!("spawn {} failed: {error}", request.command))?; - - let stdin = child.stdin.take(); - let stdout = child - .stdout - .take() - .ok_or_else(|| String::from("spawned child stdout pipe missing"))?; - let stderr = child - .stderr - .take() - .ok_or_else(|| String::from("spawned child stderr pipe missing"))?; - let (output_sender, output_events) = mpsc::channel(); - spawn_output_reader(stdout, output_sender.clone(), true); - spawn_output_reader(stderr, output_sender, false); - - let pid = child.id(); - self.children.insert( - child_id.clone(), - HostChildRecord { - child, - stdin, - output_events, - pending_events: VecDeque::new(), - exit_status: None, - open_streams: 2, - }, - ); - - Ok(json!({ - "childId": child_id, - "pid": pid, - "command": request.command, - "args": request.args, - })) - } - - fn poll(&mut self, args: &[Value]) -> Result { - let child_id = args - .first() - .and_then(Value::as_str) - .ok_or_else(|| String::from("child_process.poll missing child id"))?; - let wait_ms = args.get(1).and_then(Value::as_u64).unwrap_or_default(); - let child = self - .children - .get_mut(child_id) - .ok_or_else(|| format!("unknown child process {child_id}"))?; - - let deadline = std::time::Instant::now() + Duration::from_millis(wait_ms); - loop { - drain_child_output(child); - if let Some(event) = child.pending_events.pop_front() { - return Ok(event); - } - - if child.exit_status.is_none() { - if let Some(status) = child - .child - .try_wait() - .map_err(|error| format!("try_wait {child_id} failed: {error}"))? - { - child.exit_status = Some(status.code().unwrap_or(1)); - } - } - - if let Some(exit_code) = child.exit_status { - if child.pending_events.is_empty() && child.open_streams == 0 { - self.children.remove(child_id); - return Ok(json!({ - "type": "exit", - "exitCode": exit_code, - })); - } - } - - if std::time::Instant::now() >= deadline { - return Ok(Value::Null); - } - - thread::sleep(Duration::from_millis(5)); - } - } - - fn spawn_sync(&mut self, host_cwd: &Path, args: &[Value]) -> Result { - let (request, max_buffer, input) = parse_test_child_process_spawn_sync_request(args)?; - let mut command = if request.options.shell { - let mut command = Command::new("/bin/sh"); - command.arg("-c").arg(&request.command); - command.args(&request.args); - command - } else { - let mut command = Command::new(self.map_guest_path(host_cwd, &request.command)); - command.args( - request - .args - .iter() - .map(|arg| self.map_guest_path(host_cwd, arg)), - ); - command - }; - - let child_cwd = request - .options - .cwd - .as_deref() - .map(|cwd| std::path::PathBuf::from(self.map_guest_path(host_cwd, cwd))) - .unwrap_or_else(|| host_cwd.to_path_buf()); - - command - .current_dir(child_cwd) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .env_clear() - .envs(&request.options.env) - .envs(&request.options.internal_bootstrap_env); - - let mut child = command - .spawn() - .map_err(|error| format!("spawnSync {} failed: {error}", request.command))?; - if let Some(input) = input.as_deref() { - let stdin = child - .stdin - .as_mut() - .ok_or_else(|| String::from("spawnSync child stdin pipe missing"))?; - stdin - .write_all(input) - .map_err(|error| format!("write spawnSync stdin failed: {error}"))?; - } - child.stdin.take(); - - if let Some(timeout_ms) = request.options.timeout { - let deadline = Instant::now() + Duration::from_millis(timeout_ms); - loop { - match child - .try_wait() - .map_err(|error| format!("try_wait for {} failed: {error}", request.command))? - { - Some(_) => break, - None if Instant::now() >= deadline => { - let _ = child.kill(); - let _ = child.wait(); - let signal = request - .options - .kill_signal - .clone() - .unwrap_or_else(|| String::from("SIGTERM")); - return Ok(json!({ - "stdout": "", - "stderr": "", - "code": 1, - "signal": signal, - "timedOut": true, - "maxBufferExceeded": false, - })); - } - None => thread::sleep(Duration::from_millis(5)), - } - } - } - - let output = child - .wait_with_output() - .map_err(|error| format!("wait_with_output for {} failed: {error}", request.command))?; - - let stdout = String::from_utf8_lossy(&output.stdout).into_owned(); - let stderr = String::from_utf8_lossy(&output.stderr).into_owned(); - let max_buffer = max_buffer.unwrap_or(1024 * 1024); - let max_buffer_exceeded = - output.stdout.len() > max_buffer || output.stderr.len() > max_buffer; - - Ok(json!({ - "stdout": stdout, - "stderr": stderr, - "code": output.status.code().unwrap_or(1), - "signal": Value::Null, - "timedOut": false, - "maxBufferExceeded": max_buffer_exceeded, - })) - } - - fn write_stdin(&mut self, args: &[Value]) -> Result { - let child_id = args - .first() - .and_then(Value::as_str) - .ok_or_else(|| String::from("child_process.write_stdin missing child id"))?; - let chunk = decode_guest_bytes( - args.get(1) - .ok_or_else(|| String::from("child_process.write_stdin missing chunk"))?, - )?; - let child = self - .children - .get_mut(child_id) - .ok_or_else(|| format!("unknown child process {child_id}"))?; - if let Some(stdin) = child.stdin.as_mut() { - stdin - .write_all(&chunk) - .map_err(|error| format!("write stdin for {child_id} failed: {error}"))?; - } - Ok(Value::Null) - } - - fn close_stdin(&mut self, args: &[Value]) -> Result { - let child_id = args - .first() - .and_then(Value::as_str) - .ok_or_else(|| String::from("child_process.close_stdin missing child id"))?; - let child = self - .children - .get_mut(child_id) - .ok_or_else(|| format!("unknown child process {child_id}"))?; - child.stdin.take(); - Ok(Value::Null) - } - - fn kill(&mut self, args: &[Value]) -> Result { - let child_id = args - .first() - .and_then(Value::as_str) - .ok_or_else(|| String::from("child_process.kill missing child id"))?; - let child = self - .children - .get_mut(child_id) - .ok_or_else(|| format!("unknown child process {child_id}"))?; - child - .child - .kill() - .map_err(|error| format!("kill {child_id} failed: {error}"))?; - Ok(Value::Null) - } - - fn write_file(&mut self, host_cwd: &Path, args: &[Value]) -> Result { - let path = args - .first() - .and_then(Value::as_str) - .ok_or_else(|| String::from("fs.writeFileSync missing path"))?; - let contents = decode_guest_bytes( - args.get(1) - .ok_or_else(|| String::from("fs.writeFileSync missing contents"))?, - )?; - let mapped_path = std::path::PathBuf::from(self.map_guest_path(host_cwd, path)); - if let Some(parent) = mapped_path.parent() { - fs::create_dir_all(parent) - .map_err(|error| format!("create parent dirs for {} failed: {error}", path))?; - } - fs::write(&mapped_path, contents) - .map_err(|error| format!("write guest file {} failed: {error}", path))?; - Ok(Value::Null) - } - - fn map_guest_path(&self, host_cwd: &Path, candidate: &str) -> String { - if !candidate.starts_with('/') { - return String::from(candidate); - } - - for prefix in ["/root", "/workspace"] { - if candidate == prefix { - return host_cwd.to_string_lossy().into_owned(); - } - if let Some(relative) = candidate.strip_prefix(&format!("{prefix}/")) { - return host_cwd.join(relative).to_string_lossy().into_owned(); - } - } - - String::from(candidate) - } -} - -impl Drop for HostChildProcessHarness { - fn drop(&mut self) { - for child in self.children.values_mut() { - let _ = child.child.kill(); - let _ = child.child.wait(); - } - } -} - -fn spawn_output_reader( - mut reader: impl Read + Send + 'static, - sender: Sender, - stdout: bool, -) { - thread::spawn(move || { - let mut buffer = [0_u8; 8192]; - loop { - match reader.read(&mut buffer) { - Ok(0) => { - let _ = sender.send(HostChildOutputEvent::StreamClosed); - break; - } - Ok(read) => { - let event = if stdout { - HostChildOutputEvent::Stdout(buffer[..read].to_vec()) - } else { - HostChildOutputEvent::Stderr(buffer[..read].to_vec()) - }; - if sender.send(event).is_err() { - break; - } - } - Err(_) => { - let _ = sender.send(HostChildOutputEvent::StreamClosed); - break; - } - } - } - }); -} - -fn drain_child_output(child: &mut HostChildRecord) { - loop { - match child.output_events.try_recv() { - Ok(HostChildOutputEvent::Stdout(chunk)) => { - child.pending_events.push_back(json!({ - "type": "stdout", - "data": encode_guest_bytes(&chunk), - })); - } - Ok(HostChildOutputEvent::Stderr(chunk)) => { - child.pending_events.push_back(json!({ - "type": "stderr", - "data": encode_guest_bytes(&chunk), - })); - } - Ok(HostChildOutputEvent::StreamClosed) => { - child.open_streams = child.open_streams.saturating_sub(1); - } - Err(TryRecvError::Empty | TryRecvError::Disconnected) => break, - } - } -} - -fn encode_guest_bytes(bytes: &[u8]) -> Value { - json!({ - "__agentOSType": "bytes", - "base64": base64::engine::general_purpose::STANDARD.encode(bytes), - }) -} - -fn decode_guest_bytes(value: &Value) -> Result, String> { - let encoded = value - .as_object() - .ok_or_else(|| String::from("expected bytes payload object"))?; - let base64 = encoded - .get("base64") - .and_then(Value::as_str) - .ok_or_else(|| String::from("bytes payload missing base64"))?; - base64::engine::general_purpose::STANDARD - .decode(base64) - .map_err(|error| format!("invalid base64 bytes payload: {error}")) -} - -fn parse_test_child_process_spawn_request( - args: &[Value], -) -> Result { - if let Some(value) = args.first().cloned() { - if let Ok(request) = serde_json::from_value::(value) - { - return Ok(request); - } - } - - let command = args - .first() - .and_then(Value::as_str) - .ok_or_else(|| String::from("child_process.spawn missing command"))?; - let parsed_args = args - .get(1) - .and_then(Value::as_str) - .ok_or_else(|| String::from("child_process.spawn missing args payload")) - .and_then(|value| { - serde_json::from_str::>(value) - .map_err(|error| format!("invalid child_process.spawn args payload: {error}")) - })?; - let parsed_options = args - .get(2) - .and_then(Value::as_str) - .ok_or_else(|| String::from("child_process.spawn missing options payload")) - .and_then(|value| { - serde_json::from_str::(value) - .map_err(|error| format!("invalid child_process.spawn options payload: {error}")) - })?; - - Ok(TestJavascriptChildProcessSpawnRequest { - command: String::from(command), - args: parsed_args, - options: TestJavascriptChildProcessSpawnOptions { - cwd: parsed_options.cwd, - env: parsed_options.env, - internal_bootstrap_env: BTreeMap::new(), - shell: parsed_options.shell, - timeout: parsed_options.timeout, - kill_signal: parsed_options.kill_signal, - }, - }) -} - -fn parse_test_child_process_spawn_sync_request( - args: &[Value], -) -> Result { - let request = parse_test_child_process_spawn_request(args)?; - let parsed_options = args - .get(2) - .and_then(Value::as_str) - .ok_or_else(|| String::from("child_process.spawn_sync missing options payload")) - .and_then(|value| { - serde_json::from_str::(value).map_err( - |error| format!("invalid child_process.spawn_sync options payload: {error}"), - ) - })?; - - let input = parsed_options - .input - .as_ref() - .map(decode_guest_or_string_bytes) - .transpose()?; - - Ok((request, parsed_options.max_buffer, input)) -} - -fn decode_guest_or_string_bytes(value: &Value) -> Result, String> { - match value { - Value::String(text) => Ok(text.as_bytes().to_vec()), - other => decode_guest_bytes(other), - } -} - -/// Poll for the next sync RPC, servicing (host-directly) any module-resolution -/// sync RPCs that surface during module loading. Module resolution now flows as -/// sync RPCs (`__resolve_module` / `__batch_resolve_modules` / `__load_file` / -/// `__module_format`); these tests assert on the *next* non-module sync RPC. -fn expect_next_sync_rpc( - execution: &mut JavascriptExecution, - what: &str, -) -> JavascriptSyncRpcRequest { - loop { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .unwrap_or_else(|error| panic!("poll {what}: {error:?}")) - { - Some(JavascriptExecutionEvent::SyncRpcRequest(request)) => { - if execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC") - { - continue; - } - return request; - } - other => panic!("expected {what}, got {other:?}"), - } - } -} - -fn wait_with_host_child_process_bridge( - mut execution: JavascriptExecution, - host_cwd: &Path, -) -> JavascriptExecutionResult { - execution.close_stdin().expect("close JavaScript stdin"); - let mut harness = HostChildProcessHarness::default(); - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - - loop { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll JavaScript execution event") - { - Some(JavascriptExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(JavascriptExecutionEvent::Stderr(chunk)) => stderr.extend(chunk), - Some(JavascriptExecutionEvent::SignalState { .. }) => {} - Some(JavascriptExecutionEvent::SyncRpcRequest(request)) => { - if execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC") - { - continue; - } - let request_id = request.id; - match harness.handle_request(host_cwd, request) { - Ok(result) => execution - .respond_sync_rpc_success(request_id, result) - .expect("respond to child_process sync RPC"), - Err(message) => execution - .respond_sync_rpc_error(request_id, "ERR_TEST_CHILD_PROCESS_RPC", message) - .expect("respond to child_process sync RPC error"), - } - } - Some(JavascriptExecutionEvent::Exited(exit_code)) => { - return JavascriptExecutionResult { - execution_id: String::new(), - exit_code, - stdout, - stderr, - }; - } - None => panic!("JavaScript execution timed out while awaiting exit"), - } - } -} - -struct EnvVarGuard { - key: &'static str, - previous: Option, -} - -impl EnvVarGuard { - fn set_path(key: &'static str, value: &Path) -> Self { - let previous = std::env::var(key).ok(); - unsafe { - std::env::set_var(key, value); - } - Self { key, previous } - } - - fn set_value(key: &'static str, value: &str) -> Self { - let previous = std::env::var(key).ok(); - unsafe { - std::env::set_var(key, value); - } - Self { key, previous } - } -} - -impl Drop for EnvVarGuard { - fn drop(&mut self) { - match &self.previous { - Some(value) => unsafe { - std::env::set_var(self.key, value); - }, - None => unsafe { - std::env::remove_var(self.key); - }, - } - } -} - -fn javascript_contexts_preserve_vm_and_bootstrap_configuration() { - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: Some(String::from("./bootstrap.mjs")), - compile_cache_root: None, - }); - - assert_eq!(context.context_id, "js-ctx-1"); - assert_eq!(context.vm_id, "vm-js"); - assert_eq!(context.bootstrap_module.as_deref(), Some("./bootstrap.mjs")); - assert_eq!(context.compile_cache_dir, None); -} - -fn javascript_execution_uses_v8_runtime_without_spawning_guest_node_binary() { - let temp = tempdir().expect("create temp dir"); - let fake_node_path = temp.path().join("fake-node.sh"); - let log_path = temp.path().join("node.log"); - write_fake_node_binary(&fake_node_path, &log_path); - let _node_binary = EnvVarGuard::set_path("AGENTOS_NODE_BINARY", &fake_node_path); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from("globalThis.__secureExecRanInV8 = true;")), - }) - .expect("start JavaScript execution"); - - assert!( - execution.uses_shared_v8_runtime(), - "guest JS should run inside the shared V8 runtime" - ); - assert_eq!( - execution.child_pid(), - 0, - "shared V8 runtime executions should keep the embedded host pid internal" - ); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert!( - !log_path.exists(), - "guest JavaScript execution should not invoke the host node binary" - ); -} - -fn javascript_execution_virtual_os_identity_comes_from_guest_runtime_not_env() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - // os.* identity rides the typed guest_runtime; the env carries - // contradictory values to prove the AGENTOS_VIRTUAL_OS_* knobs are - // inert. - guest_runtime: secure_exec_execution::GuestRuntimeConfig { - os_cpu_count: Some(7), - os_totalmem: Some(8_000_000_000), - os_freemem: Some(4_000_000_000), - os_hostname: Some(String::from("vm-hostname")), - os_tmpdir: Some(String::from("/vm-tmp")), - os_type: Some(String::from("VMType")), - os_release: Some(String::from("1.2.3-vm")), - os_version: Some(String::from("VM secure-exec build 42")), - os_machine: Some(String::from("vm64")), - ..Default::default() - }, - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([ - ( - String::from("AGENTOS_VIRTUAL_OS_CPU_COUNT"), - String::from("99"), - ), - ( - String::from("AGENTOS_VIRTUAL_OS_TOTALMEM"), - String::from("123"), - ), - ]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import os from "node:os"; -if (os.cpus().length !== 7) throw new Error(`cpus=${os.cpus().length}`); -if (os.totalmem() !== 8000000000) throw new Error(`totalmem=${os.totalmem()}`); -if (os.freemem() !== 4000000000) throw new Error(`freemem=${os.freemem()}`); -if (os.hostname() !== "vm-hostname") throw new Error(`hostname=${os.hostname()}`); -if (os.tmpdir() !== "/vm-tmp") throw new Error(`tmpdir=${os.tmpdir()}`); -if (os.type() !== "VMType") throw new Error(`type=${os.type()}`); -if (os.release() !== "1.2.3-vm") throw new Error(`release=${os.release()}`); -if (os.version() !== "VM secure-exec build 42") throw new Error(`version=${os.version()}`); -if (os.machine() !== "vm64") throw new Error(`machine=${os.machine()}`); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stderr:\n{stderr}"); - assert!(result.stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_virtualizes_process_metadata_for_inline_v8_code() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - // Identity rides the typed guest_runtime; the env carries different - // values to prove the `AGENTOS_VIRTUAL_PROCESS_*` knobs are inert. - guest_runtime: secure_exec_execution::GuestRuntimeConfig { - virtual_pid: Some(4242), - virtual_ppid: Some(41), - ..Default::default() - }, - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs"), String::from("alpha")], - env: BTreeMap::from([ - ( - String::from("AGENTOS_VIRTUAL_PROCESS_PID"), - String::from("1"), - ), - ( - String::from("AGENTOS_VIRTUAL_PROCESS_PPID"), - String::from("2"), - ), - ]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -if (process.argv[1] !== "/root/entry.mjs") throw new Error(`argv=${process.argv[1]}`); -if (process.argv[2] !== "alpha") throw new Error(`arg2=${process.argv[2]}`); -if (process.cwd() !== "/root") throw new Error(`cwd=${process.cwd()}`); -if (process.pid !== 4242) throw new Error(`pid=${process.pid}`); -if (process.ppid !== 41) throw new Error(`ppid=${process.ppid}`); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(result.stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_process_kill_rejects_invalid_pid_in_guest_js() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -try { - process.kill(Number.NaN, "SIGTERM"); - console.log(JSON.stringify({ caught: false })); -} catch (error) { - console.log(JSON.stringify({ - caught: true, - name: error && error.name, - message: error && error.message, - })); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(result.stderr.is_empty(), "unexpected stderr: {stderr}"); - - let output: Value = serde_json::from_slice(&result.stdout).expect("parse stdout JSON"); - assert_eq!(output.get("caught"), Some(&json!(true))); - assert_eq!(output.get("name"), Some(&json!("TypeError"))); - assert!( - output - .get("message") - .and_then(Value::as_str) - .is_some_and(|message| message.contains("\"pid\" argument")), - "unexpected process.kill error output: {output}" - ); -} - -fn javascript_execution_preserves_binary_process_stdio_writes() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -process.stdout.write(Buffer.from([0x00, 0xbc, 0xff, 0x41])); -process.stderr.write(Buffer.from([0xfe, 0x00, 0x42])); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert_eq!(result.stdout, vec![0x00, 0xbc, 0xff, 0x41]); - assert_eq!(result.stderr, vec![0xfe, 0x00, 0x42]); -} - -fn javascript_execution_intl_number_format_does_not_require_host_icu() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const formatter = new Intl.NumberFormat("en", { - maximumFractionDigits: 2, - minimumFractionDigits: 2, -}); -console.log(formatter.format(1234.5)); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert_eq!(stdout, "1,234.50\n"); -} - -// Regression for #70: `Date#toLocaleDateString` with a non-default locale, -// formatting options, and an explicit IANA time zone used to crash the embedded -// V8 isolate with SIGTRAP. ICU's `DateTimePatternGeneratorCache::CreateGenerator` -// hit a fatal abort under the near-heap-limit path; the OOM guard in -// `crates/v8-runtime/src/isolate.rs` now converts that fatal abort into clean -// termination, and ICU is bundled, so the exact repro runs and returns a string. -fn javascript_execution_to_locale_date_string_does_not_crash_embedded_v8() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const formatted = new Date(Date.UTC(2020, 0, 15)).toLocaleDateString("en-GB", { - day: "2-digit", - month: "2-digit", - year: "numeric", - timeZone: "Europe/Warsaw", -}); -console.log(JSON.stringify({ formatted })); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!( - result.exit_code, 0, - "guest process must not crash (e.g. SIGTRAP); stdout:\n{stdout}\nstderr:\n{stderr}" - ); - - let output: Value = serde_json::from_slice(&result.stdout).expect("parse guest stdout as JSON"); - let formatted = output - .get("formatted") - .and_then(Value::as_str) - .expect("formatted date string present"); - assert!( - !formatted.is_empty(), - "toLocaleDateString returned an empty string: {output}" - ); -} - -#[allow(dead_code)] // quarantined: see the live-stdin/tty harness note above -fn javascript_execution_stream_consumers_text_reads_live_stdin() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - )]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import { text } from "node:stream/consumers"; - -const body = await text(process.stdin); -console.log(JSON.stringify({ body })); -"#, - )), - }) - .expect("start JavaScript execution"); - - execution - .write_stdin(b"alpha\nbeta\n") - .expect("write JavaScript stdin"); - execution.close_stdin().expect("close JavaScript stdin"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(result.stderr.is_empty(), "unexpected stderr: {stderr}"); - - let output: Value = serde_json::from_slice(&result.stdout).expect("parse guest stdout as JSON"); - assert_eq!(output, json!({ "body": "alpha\nbeta\n" })); -} - -#[allow(dead_code)] // quarantined: see the live-stdin/tty harness note above -fn javascript_execution_process_stdin_async_iterator_finishes_with_live_stdin() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - )]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -let body = ""; -for await (const chunk of process.stdin) { - body += chunk; -} -console.log(JSON.stringify({ body })); -"#, - )), - }) - .expect("start JavaScript execution"); - - execution - .write_stdin(b"{\"request_id\":\"init1\"}\n") - .expect("write JavaScript stdin"); - execution.close_stdin().expect("close JavaScript stdin"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(result.stderr.is_empty(), "unexpected stderr: {stderr}"); - - let output: Value = serde_json::from_slice(&result.stdout).expect("parse guest stdout as JSON"); - assert_eq!(output, json!({ "body": "{\"request_id\":\"init1\"}\n" })); -} - -#[allow(dead_code)] // quarantined: see the live-stdin/tty harness note above -fn javascript_execution_process_exit_from_live_stdin_listener_exits_without_waiting_for_eof() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - )]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -process.stdin.setEncoding("utf8"); -process.stdin.once("data", (chunk) => { - process.stdout.write(`stdout:${chunk}`); - process.stderr.write(`stderr:${chunk}`); - process.exit(0); -}); -"#, - )), - }) - .expect("start JavaScript execution"); - - execution - .write_stdin(b"hello-live-stdin\n") - .expect("write JavaScript stdin"); - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let exit_code = loop { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll JavaScript execution event") - { - Some(JavascriptExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(JavascriptExecutionEvent::Stderr(chunk)) => stderr.extend(chunk), - Some(JavascriptExecutionEvent::SignalState { .. }) => {} - Some(JavascriptExecutionEvent::SyncRpcRequest(request)) => { - panic!("unexpected pending sync RPC request: {}", request.id); - } - Some(JavascriptExecutionEvent::Exited(code)) => break code, - None => panic!("JavaScript execution timed out while awaiting exit"), - } - }; - - let stdout = String::from_utf8_lossy(&stdout); - let stderr = String::from_utf8_lossy(&stderr); - assert_eq!(exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!( - stdout.contains("stdout:hello-live-stdin"), - "stdout:\n{stdout}" - ); - assert!( - stderr.contains("stderr:hello-live-stdin"), - "stderr:\n{stderr}" - ); -} - -fn javascript_execution_process_exit_ignores_live_interval_handles() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -process.stdout.write("before exit\n"); -setInterval(() => { - process.stdout.write("interval tick\n"); -}, 1000); -process.exit(7); -process.stdout.write("after exit\n"); -"#, - )), - }) - .expect("start JavaScript execution"); - - let mut stdout = Vec::new(); - let exit_code = loop { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll JavaScript execution event") - { - Some(JavascriptExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(JavascriptExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - Some(JavascriptExecutionEvent::SignalState { .. }) => {} - Some(JavascriptExecutionEvent::SyncRpcRequest(request)) => { - panic!("unexpected pending sync RPC request: {}", request.id); - } - Some(JavascriptExecutionEvent::Exited(code)) => break code, - None => panic!("JavaScript execution timed out while awaiting process.exit"), - } - }; - - let stdout = String::from_utf8_lossy(&stdout); - assert_eq!(exit_code, 7, "stdout:\n{stdout}"); - assert!(stdout.contains("before exit"), "stdout:\n{stdout}"); - assert!(!stdout.contains("after exit"), "stdout:\n{stdout}"); -} - -fn javascript_execution_process_exit_bypasses_promise_catch_handlers() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -Promise.resolve() - .then(() => { - process.stdout.write("before exit\n"); - process.exit(7); - }) - .catch(() => { - process.stdout.write("catch handler ran\n"); - process.exit(2); - }); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 7, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stdout.contains("before exit"), "stdout:\n{stdout}"); - assert!(!stdout.contains("catch handler ran"), "stdout:\n{stdout}"); -} - -#[allow(dead_code)] // quarantined: see the live-stdin/tty harness note above -fn javascript_execution_live_stdin_replays_end_after_late_listener_registration() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - )]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -setTimeout(() => { - process.stdin.setEncoding("utf8"); - let body = ""; - process.stdin.on("data", (chunk) => { - body += chunk; - }); - process.stdin.on("end", () => { - console.log(JSON.stringify({ body })); - }); - process.stdin.resume(); -}, 50); -"#, - )), - }) - .expect("start JavaScript execution"); - - execution - .write_stdin(b"hello-delayed\n") - .expect("write JavaScript stdin"); - execution.close_stdin().expect("close JavaScript stdin"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(result.stderr.is_empty(), "unexpected stderr: {stderr}"); - - let output: Value = serde_json::from_slice(&result.stdout).expect("parse guest stdout as JSON"); - assert_eq!(output, json!({ "body": "hello-delayed\n" })); -} - -fn javascript_execution_file_url_to_path_accepts_guest_absolute_paths() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import { fileURLToPath } from "node:url"; - -const guestPath = "/root/node_modules/@mariozechner/pi-coding-agent/dist/config.js"; -if (fileURLToPath(guestPath) !== guestPath) { - throw new Error(`plain path mismatch: ${fileURLToPath(guestPath)}`); -} - -const href = "file:///root/node_modules/@mariozechner/pi-coding-agent/dist/config.js"; -if (fileURLToPath(href) !== guestPath) { - throw new Error(`file url mismatch: ${fileURLToPath(href)}`); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(result.stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_imports_node_events_without_hanging() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import { EventEmitter, once } from "node:events"; - -const emitter = new EventEmitter(); -const pending = once(emitter, "ready"); -emitter.emit("ready", "ok"); -const [value] = await pending; - -if (value !== "ok") { - throw new Error(`unexpected once payload: ${value}`); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert!( - result.stderr.is_empty(), - "unexpected stderr: {:?}", - result.stderr - ); -} - -fn javascript_execution_imports_node_process_without_hanging() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import process from "node:process"; - -if (!process || typeof process.cwd !== "function") { - throw new Error("node:process did not export the guest process object"); -} - -if (typeof process.pid !== "number" || process.pid <= 0) { - throw new Error(`unexpected pid: ${process.pid}`); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert!( - result.stderr.is_empty(), - "unexpected stderr: {:?}", - result.stderr - ); -} - -fn javascript_execution_imports_node_fs_promises_without_hanging() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import fs from "node:fs/promises"; - -if (typeof fs.access !== "function") { - throw new Error("node:fs/promises did not expose access()"); -} -if (typeof fs.readFile !== "function") { - throw new Error("node:fs/promises did not expose readFile()"); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert!( - result.stderr.is_empty(), - "unexpected stderr: {:?}", - result.stderr - ); -} - -fn javascript_execution_imports_node_perf_hooks_without_hanging() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import { performance } from "node:perf_hooks"; - -if (typeof performance?.now !== "function") { - throw new Error("node:perf_hooks did not expose performance.now()"); -} -const replacementPerformance = { - now() { - const [seconds, nanoseconds] = process.hrtime(); - return seconds * 1000 + nanoseconds / 1e6; - }, -}; -globalThis.performance = replacementPerformance; - -const elapsed = process.hrtime(process.hrtime()); -if (!Array.isArray(elapsed) || elapsed.length !== 2) { - throw new Error("process.hrtime returned an invalid delta"); -} -if (typeof process.hrtime.bigint() !== "bigint") { - throw new Error("process.hrtime.bigint did not return a bigint"); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert!( - result.stderr.is_empty(), - "unexpected stderr: {:?}", - result.stderr - ); -} - -fn javascript_execution_high_resolution_time_opt_in_enables_sub_ms_hrtime() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js-high-res-on"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: GuestRuntimeConfig { - high_resolution_time: true, - ..Default::default() - }, - vm_id: String::from("vm-js-high-res-on"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -if (typeof __secureExecHrNowUs !== "function") { - throw new Error("high-resolution host clock was not installed"); -} -let sawSubMs = false; -for (let attempt = 0; attempt < 80 && !sawSubMs; attempt++) { - const start = process.hrtime.bigint(); - const until = __secureExecHrNowUs() + 200; - while (__secureExecHrNowUs() < until) {} - const delta = process.hrtime.bigint() - start; - if (delta > 0n && delta < 1000000n) { - sawSubMs = true; - } -} -if (!sawSubMs) { - throw new Error("process.hrtime.bigint did not observe a sub-ms delta"); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); -} - -fn javascript_execution_high_resolution_time_default_off_keeps_coarse_clock() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js-high-res-off"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js-high-res-off"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -if (typeof __secureExecHrNowUs !== "undefined") { - throw new Error("high-resolution host clock exists without opt-in"); -} -for (let attempt = 0; attempt < 20; attempt++) { - const now = process.hrtime.bigint(); - if (now % 1000000n !== 0n) { - throw new Error("process.hrtime.bigint was not millisecond aligned: " + now); - } -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); -} - -fn javascript_execution_exposes_compatibility_shims_and_denies_escape_builtins() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const vm = require("node:vm"); -if (typeof vm.runInThisContext !== "function") { - throw new Error("node:vm compatibility shim missing runInThisContext"); -} - -const v8 = require("node:v8"); -if (typeof v8.cachedDataVersionTag !== "function") { - throw new Error("node:v8 compatibility shim missing cachedDataVersionTag"); -} -const heapStats = v8.getHeapStatistics?.(); -if (!heapStats || typeof heapStats.heap_size_limit !== "number" || heapStats.heap_size_limit <= 0) { - throw new Error("node:v8 compatibility shim missing positive heap_size_limit"); -} - -const workerThreads = require("node:worker_threads"); -if (workerThreads.isMainThread !== true) { - throw new Error("node:worker_threads compatibility shim missing isMainThread"); -} - -let workerDenied = false; -try { - new workerThreads.Worker(new URL("data:text/javascript,0")); -} catch (error) { - workerDenied = error?.code === "ERR_NOT_IMPLEMENTED"; -} -if (!workerDenied) { - throw new Error("node:worker_threads Worker should stay unavailable"); -} - -for (const builtin of ["inspector", "cluster"]) { - let denied = false; - try { - require(`node:${builtin}`); - } catch (error) { - denied = - error?.code === "ERR_ACCESS_DENIED" && - String(error?.message ?? "").includes(`node:${builtin}`); - } - if (!denied) { - throw new Error(`node:${builtin} was not denied`); - } -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert!( - result.stderr.is_empty(), - "unexpected stderr: {:?}", - result.stderr - ); -} - -fn javascript_execution_v8_util_format_with_options_matches_node() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import { createRequire } from "node:module"; -import { formatWithOptions as namedFormatWithOptions } from "node:util"; - -const require = createRequire(import.meta.url); -const util = require("node:util"); -const circular = {}; -circular.self = circular; - -console.log(JSON.stringify({ - type: typeof util.formatWithOptions, - namedType: typeof namedFormatWithOptions, - basic: util.formatWithOptions({}, "hello %s %d %j %%", "world", 4, { ok: true }), - extra: util.formatWithOptions({ colors: false }, "value", { alpha: 1 }, "tail"), - object: util.formatWithOptions({ colors: false, depth: 1 }, "%O", { nested: { value: 1 } }), - circular: util.formatWithOptions({}, "%j", circular), -})); -"#, - ); - - let host = run_host_node_json(temp.path(), &temp.path().join("entry.mjs")); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - let guest: Value = serde_json::from_slice(&result.stdout).expect("parse stdout JSON"); - assert_eq!(guest, host); -} - -fn javascript_execution_provides_async_hooks_and_diagnostics_channel_stubs() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import { createRequire } from "node:module"; -import { Channel, tracingChannel as importedTracingChannel } from "node:diagnostics_channel"; - -const require = createRequire(import.meta.url); -const asyncHooks = require("node:async_hooks"); -const diagnosticsChannel = require("node:diagnostics_channel"); - -const hook = asyncHooks.createHook({}); -if (hook.enable() !== hook || hook.disable() !== hook) { - throw new Error("node:async_hooks createHook() did not return a no-op hook"); -} -if (asyncHooks.executionAsyncId() !== 0 || asyncHooks.triggerAsyncId() !== 0) { - throw new Error("node:async_hooks ids should default to 0"); -} - -const storage = new asyncHooks.AsyncLocalStorage(); -const result = storage.run("token", () => storage.getStore()); -if (result !== "token") { - throw new Error(`node:async_hooks AsyncLocalStorage lost store: ${String(result)}`); -} - -const channel = diagnosticsChannel.channel("undici:request:create"); -if (channel.name !== "undici:request:create") { - throw new Error(`unexpected channel name: ${String(channel.name)}`); -} -if (channel.hasSubscribers !== false) { - throw new Error("diagnostics channel should report no subscribers"); -} -if (diagnosticsChannel.hasSubscribers("undici:request:create") !== false) { - throw new Error("diagnostics_channel.hasSubscribers should be false"); -} -if (typeof diagnosticsChannel.tracingChannel !== "function") { - throw new Error("diagnostics_channel.tracingChannel is missing"); -} -if (typeof importedTracingChannel !== "function") { - throw new Error("diagnostics_channel ESM tracingChannel export is missing"); -} -if (typeof Channel !== "function") { - throw new Error("diagnostics_channel ESM Channel export is missing"); -} - -const constructedChannel = new Channel("constructed"); -if (constructedChannel.name !== "constructed" || constructedChannel.hasSubscribers !== false) { - throw new Error("diagnostics_channel Channel constructor returned unexpected state"); -} - -const tracing = diagnosticsChannel.tracingChannel("agent.test"); -if (tracing.hasSubscribers !== false || tracing.start.hasSubscribers !== false) { - throw new Error("diagnostics tracing channel should start without subscribers"); -} -if (tracing.start.name !== "tracing:agent.test:start") { - throw new Error(`unexpected tracing start channel name: ${String(tracing.start.name)}`); -} -const runStoresResult = tracing.start.runStores({ token: 1 }, (left, right) => `${left}:${right}`, undefined, "ok", 42); -if (runStoresResult !== "ok:42") { - throw new Error(`diagnostics tracing channel runStores returned ${String(runStoresResult)}`); -} - -let published = null; -function onPublish(message, name) { - published = { message, name }; -} -tracing.start.subscribe(onPublish); -if (tracing.hasSubscribers !== true || tracing.start.hasSubscribers !== true) { - throw new Error("diagnostics tracing channel did not track subscribers"); -} -tracing.start.publish({ value: 7 }); -if (published?.name !== "tracing:agent.test:start" || published?.message?.value !== 7) { - throw new Error("diagnostics tracing channel did not publish to subscribers"); -} -if (tracing.start.unsubscribe(onPublish) !== true || tracing.hasSubscribers !== false) { - throw new Error("diagnostics tracing channel did not unsubscribe"); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert!( - result.stderr.is_empty(), - "unexpected stderr: {:?}", - result.stderr - ); -} - -fn javascript_execution_supports_require_resolve_for_guest_code() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("local-file.js"), - "module.exports = 'local';\n", - ); - write_fixture( - &temp.path().join("nested/check.cjs"), - r#" -const localResolved = require.resolve("../local-file.js"); -if (localResolved !== "/root/local-file.js") { - throw new Error(`unexpected local resolution: ${String(localResolved)}`); -} - -const packageResolved = require.resolve("some-package"); -if (packageResolved !== "/root/node_modules/some-package/index.js") { - throw new Error(`unexpected package resolution: ${String(packageResolved)}`); -} - -const searchPaths = require.resolve.paths("some-package"); -const expectedPaths = [ - "/root/nested/node_modules", - "/root/node_modules", - "/node_modules", -]; -if (JSON.stringify(searchPaths) !== JSON.stringify(expectedPaths)) { - throw new Error(`unexpected search paths: ${JSON.stringify(searchPaths)}`); -} -"#, - ); - write_fixture( - &temp.path().join("node_modules/some-package/package.json"), - r#"{"main":"./index.js"}"#, - ); - write_fixture( - &temp.path().join("node_modules/some-package/index.js"), - "module.exports = 'pkg';\n", - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -if (require.resolve("fs") !== "node:fs") { - throw new Error(`builtin resolution failed: ${String(require.resolve("fs"))}`); -} - -if (require.resolve("./local-file.js") !== "/root/local-file.js") { - throw new Error(`local resolution failed: ${String(require.resolve("./local-file.js"))}`); -} - -if (require.resolve("some-package") !== "/root/node_modules/some-package/index.js") { - throw new Error(`package resolution failed: ${String(require.resolve("some-package"))}`); -} - -const builtinPaths = require.resolve.paths("fs"); -if (builtinPaths !== null) { - throw new Error(`builtin paths should be null, got ${JSON.stringify(builtinPaths)}`); -} - -const packagePaths = require.resolve.paths("some-package"); -const expectedPackagePaths = ["/root/node_modules", "/node_modules"]; -if (JSON.stringify(packagePaths) !== JSON.stringify(expectedPackagePaths)) { - throw new Error(`unexpected top-level search paths: ${JSON.stringify(packagePaths)}`); -} - -let missingCode = null; -try { - require.resolve("nonexistent"); -} catch (error) { - missingCode = error?.code ?? null; -} -if (missingCode !== "MODULE_NOT_FOUND") { - throw new Error(`unexpected missing-module code: ${String(missingCode)}`); -} - -require("./nested/check.cjs"); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert!( - result.stderr.is_empty(), - "unexpected stderr: {:?}", - result.stderr - ); -} - -fn javascript_execution_rejects_native_node_addons() { - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("addon.node"), "not a native addon\n"); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.js")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -let rejected = false; -try { - require("./addon.node"); -} catch (error) { - rejected = - String(error?.message ?? "").includes(".node extensions are not supported") || - String(error?.message ?? "").includes("native addon loading"); -} -if (!rejected) { - throw new Error("native .node addon should be rejected"); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - assert!( - result.stderr.is_empty(), - "unexpected stderr: {:?}", - result.stderr - ); -} - -fn javascript_execution_surfaces_sync_rpc_requests_from_v8_modules() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import fs from "node:fs"; -fs.statSync("/workspace/note.txt"); -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let request = expect_next_sync_rpc(&mut execution, "poll execution event"); - - assert_eq!(request.method, "fs.statSync"); - assert_eq!(request.args, vec![json!("/workspace/note.txt")]); - - execution - .respond_sync_rpc_success( - request.id, - json!({ - "mode": 0o100644, - "size": 11, - "isDirectory": false, - "isSymbolicLink": false, - }), - ) - .expect("respond to fs.statSync"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); -} - -fn javascript_execution_v8_dgram_bridge_matches_sidecar_rpc_shapes() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import dgram from "node:dgram"; - -const summary = await new Promise((resolve, reject) => { - const socket = dgram.createSocket("udp4"); - socket.on("error", reject); - socket.on("message", (message, rinfo) => { - const address = socket.address(); - socket.close(() => { - resolve({ - address, - message: message.toString("utf8"), - rinfo, - }); - }); - }); - socket.bind(0, "127.0.0.1", () => { - socket.send("ping", 7, "127.0.0.1"); - }); -}); - -if (summary.message !== "pong") { - throw new Error(`unexpected udp message: ${summary.message}`); -} -if (summary.address.address !== "127.0.0.1" || summary.address.port !== 45454) { - throw new Error(`unexpected socket address: ${JSON.stringify(summary.address)}`); -} -if (summary.rinfo.address !== "127.0.0.1" || summary.rinfo.port !== 7) { - throw new Error(`unexpected remote info: ${JSON.stringify(summary.rinfo)}`); -} -"#, - ); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from("[\"dgram\"]"), - )]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let request = expect_next_sync_rpc(&mut execution, "poll dgram.createSocket request"); - assert_eq!(request.method, "dgram.createSocket"); - assert_eq!(request.args, vec![json!({ "type": "udp4" })]); - execution - .respond_sync_rpc_success(request.id, json!({ "socketId": "udp-1", "type": "udp4" })) - .expect("respond to dgram.createSocket"); - - let request = expect_next_sync_rpc(&mut execution, "poll dgram.bind request"); - assert_eq!(request.method, "dgram.bind"); - assert_eq!( - request.args, - vec![json!("udp-1"), json!({ "address": "127.0.0.1", "port": 0 })] - ); - execution - .respond_sync_rpc_success( - request.id, - json!({ - "localAddress": "127.0.0.1", - "localPort": 45454, - "family": "IPv4", - }), - ) - .expect("respond to dgram.bind"); - - let request = expect_next_sync_rpc(&mut execution, "poll dgram.poll request"); - assert_eq!(request.method, "dgram.poll"); - assert_eq!(request.args, vec![json!("udp-1"), json!(0)]); - execution - .respond_sync_rpc_success(request.id, json!(null)) - .expect("respond to initial dgram.poll"); - - let request = expect_next_sync_rpc(&mut execution, "poll dgram.send request"); - assert_eq!(request.method, "dgram.send"); - assert_eq!( - request.args, - vec![ - json!("udp-1"), - json!({ - "__agentOSType": "bytes", - "base64": "cGluZw==", - }), - json!({ - "address": "127.0.0.1", - "port": 7, - }), - ] - ); - execution - .respond_sync_rpc_success( - request.id, - json!({ - "bytes": 4, - "localAddress": "127.0.0.1", - "localPort": 45454, - "family": "IPv4", - }), - ) - .expect("respond to dgram.send"); - - let request = expect_next_sync_rpc(&mut execution, "poll message dgram.poll request"); - assert_eq!(request.method, "dgram.poll"); - assert_eq!(request.args, vec![json!("udp-1"), json!(10)]); - execution - .respond_sync_rpc_success( - request.id, - json!({ - "type": "message", - "data": { - "__agentOSType": "bytes", - "base64": "cG9uZw==", - }, - "remoteAddress": "127.0.0.1", - "remotePort": 7, - "remoteFamily": "IPv4", - }), - ) - .expect("respond to message dgram.poll"); - - let request = expect_next_sync_rpc(&mut execution, "poll dgram.address request"); - assert_eq!(request.method, "dgram.address"); - assert_eq!(request.args, vec![json!("udp-1")]); - execution - .respond_sync_rpc_success( - request.id, - json!("{\"address\":\"127.0.0.1\",\"port\":45454,\"family\":\"IPv4\"}"), - ) - .expect("respond to dgram.address"); - - let request = expect_next_sync_rpc(&mut execution, "poll dgram.close request"); - assert_eq!(request.method, "dgram.close"); - assert_eq!(request.args, vec![json!("udp-1")]); - execution - .respond_sync_rpc_success(request.id, json!(null)) - .expect("respond to dgram.close"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_strips_hashbang_from_module_entrypoints() { - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("package.json"), r#"{"type":"module"}"#); - write_fixture( - &temp.path().join("index.js"), - "#!/usr/bin/env node\nimport fs from \"node:fs\";\nfs.statSync(\"/workspace/hashbang.txt\");\n", - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./index.js")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let request = expect_next_sync_rpc(&mut execution, "poll execution event"); - - assert_eq!(request.method, "fs.statSync"); - assert_eq!(request.args, vec![json!("/workspace/hashbang.txt")]); - - execution - .respond_sync_rpc_success( - request.id, - json!({ - "mode": 0o100644, - "size": 9, - "isDirectory": false, - "isSymbolicLink": false, - }), - ) - .expect("respond to fs.statSync"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_resolves_pnpm_store_dependencies_from_symlinked_entrypoints() { - let temp = tempdir().expect("create temp dir"); - let node_modules = temp.path().join("node_modules"); - let store_root = node_modules.join(".pnpm/pkg@1.0.0/node_modules"); - let pkg_dir = store_root.join("pkg"); - let dep_dir = store_root.join("@scope/dep"); - - fs::create_dir_all(pkg_dir.join("dist")).expect("create package dist"); - fs::create_dir_all(&dep_dir).expect("create dependency dir"); - fs::create_dir_all(node_modules.join("@scope")).expect("create scope dir"); - - write_fixture(&pkg_dir.join("package.json"), r#"{"type":"module"}"#); - write_fixture( - &pkg_dir.join("dist/index.js"), - "import dep from \"@scope/dep\";\ndep();\n", - ); - write_fixture( - &dep_dir.join("package.json"), - r#"{"type":"module","exports":"./index.js"}"#, - ); - write_fixture( - &dep_dir.join("index.js"), - "import fs from \"node:fs\";\nexport default function dep() { fs.statSync(\"/workspace/pnpm.txt\"); }\n", - ); - - symlink(".pnpm/pkg@1.0.0/node_modules/pkg", node_modules.join("pkg")) - .expect("symlink package into node_modules"); - - let guest_mappings = serde_json::to_string(&vec![json!({ - "guestPath": "/root/node_modules", - "hostPath": node_modules.display().to_string(), - })]) - .expect("serialize guest mappings"); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("/root/node_modules/pkg/dist/index.js")], - env: BTreeMap::from([(String::from("AGENTOS_GUEST_PATH_MAPPINGS"), guest_mappings)]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let request = expect_next_sync_rpc(&mut execution, "poll execution event"); - - assert_eq!(request.method, "fs.statSync"); - assert_eq!(request.args, vec![json!("/workspace/pnpm.txt")]); - - execution - .respond_sync_rpc_success( - request.id, - json!({ - "mode": 0o100644, - "size": 8, - "isDirectory": false, - "isSymbolicLink": false, - }), - ) - .expect("respond to fs.statSync"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_resolves_dependencies_from_package_specific_symlink_mounts() { - let temp = tempdir().expect("create temp dir"); - let mounts_root = temp.path().join("mounts"); - let node_modules_root = temp.path().join("node_modules"); - let store_root = node_modules_root.join(".pnpm/pkg@1.0.0/node_modules"); - let pkg_dir = store_root.join("pkg"); - let dep_dir = store_root.join("@scope/dep"); - let mounted_pkg = mounts_root.join("pkg"); - - fs::create_dir_all(pkg_dir.join("dist")).expect("create package dist"); - fs::create_dir_all(&dep_dir).expect("create dependency dir"); - fs::create_dir_all(&mounts_root).expect("create mounts root"); - - write_fixture(&pkg_dir.join("package.json"), r#"{"type":"module"}"#); - write_fixture( - &pkg_dir.join("dist/index.js"), - "import dep from \"@scope/dep\";\ndep();\n", - ); - write_fixture( - &dep_dir.join("package.json"), - r#"{"type":"module","exports":"./index.js"}"#, - ); - write_fixture( - &dep_dir.join("index.js"), - "import fs from \"node:fs\";\nexport default function dep() { fs.statSync(\"/workspace/pkg-mount.txt\"); }\n", - ); - - symlink(&pkg_dir, &mounted_pkg).expect("symlink mounted package to pnpm store"); - - let guest_mappings = serde_json::to_string(&vec![json!({ - "guestPath": "/root/node_modules/pkg", - "hostPath": mounted_pkg.display().to_string(), - })]) - .expect("serialize guest mappings"); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("/root/node_modules/pkg/dist/index.js")], - env: BTreeMap::from([(String::from("AGENTOS_GUEST_PATH_MAPPINGS"), guest_mappings)]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let request = expect_next_sync_rpc(&mut execution, "poll execution event"); - - assert_eq!(request.method, "fs.statSync"); - assert_eq!(request.args, vec![json!("/workspace/pkg-mount.txt")]); - - execution - .respond_sync_rpc_success( - request.id, - json!({ - "mode": 0o100644, - "size": 13, - "isDirectory": false, - "isSymbolicLink": false, - }), - ) - .expect("respond to fs.statSync"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8(result.stdout.clone()).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr.clone()).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_timer_callbacks_fire_and_clear_correctly() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id.clone(), - argv: vec![String::from("./entry.js")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -(async () => { - const clearedTimeout = setTimeout(() => { - throw new Error("cleared timeout fired"); - }, 10); - clearTimeout(clearedTimeout); - - await new Promise((resolve) => setTimeout(resolve, 25)); - - let intervalTicks = 0; - await new Promise((resolve, reject) => { - const interval = setInterval(() => { - intervalTicks += 1; - if (intervalTicks === 2) { - clearInterval(interval); - resolve(); - } else if (intervalTicks > 2) { - reject(new Error(`interval fired too many times: ${intervalTicks}`)); - } - }, 10); - - setTimeout(() => reject(new Error(`interval timeout: ${intervalTicks}`)), 250); - }); - - if (intervalTicks !== 2) { - throw new Error(`interval tick count mismatch: ${intervalTicks}`); - } - - let immediateFired = false; - await new Promise((resolve) => { - setImmediate(() => { - immediateFired = true; - resolve(); - }); - }); - if (!immediateFired) { - throw new Error("setImmediate callback did not fire"); - } - - const order = []; - setImmediate(() => order.push("immediate")); - queueMicrotask(() => order.push("microtask")); - await new Promise((resolve) => setImmediate(resolve)); - if (order.join(",") !== "microtask,immediate") { - throw new Error(`unexpected immediate order: ${order.join(",")}`); - } - - for (let i = 0; i < 100; i += 1) { - await new Promise((resolve) => setImmediate(resolve)); - } - - let clearedImmediateFired = false; - const clearedImmediate = setImmediate(() => { - clearedImmediateFired = true; - }); - clearImmediate(clearedImmediate); - await new Promise((resolve) => setImmediate(resolve)); - if (clearedImmediateFired) { - throw new Error("cleared immediate fired"); - } - - const { setImmediate: promiseImmediate } = await import("node:timers/promises"); - const promiseImmediateValue = await promiseImmediate("promise-value"); - if (promiseImmediateValue !== "promise-value") { - throw new Error(`timers/promises setImmediate mismatch: ${promiseImmediateValue}`); - } - - const t0 = Date.now(); - let chainCount = 0; - const immediateChainMs = await new Promise((resolve) => { - function tick() { - if (++chainCount < 1000) { - setImmediate(tick); - } else { - resolve(Date.now() - t0); - } - } - setImmediate(tick); - }); - // The upper-bound check on the chain latency lives host-side in Rust so it can - // be gated to the nightly timing lane (see run_timing_sensitive_tests); the - // guest only reports the measurement. - console.log(`setImmediate-chain-ms=${immediateChainMs}`); -})().catch((error) => { - process.exitCode = 1; - throw error; -}); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8(result.stdout.clone()).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr.clone()).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - let chain_ms_line = stdout - .lines() - .find(|line| line.starts_with("setImmediate-chain-ms=")) - .expect("setImmediate timing line"); - let chain_ms: u64 = chain_ms_line - .trim_start_matches("setImmediate-chain-ms=") - .parse() - .expect("parse setImmediate timing"); - println!("setImmediate 1000-chain elapsed ms: {chain_ms}"); - if run_timing_sensitive_tests() { - assert!( - chain_ms < 500, - "setImmediate 1000-chain elapsed too high: {chain_ms}ms" - ); - } - - let only_immediate_execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id.clone(), - argv: vec![String::from("./entry.js")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -setImmediate(() => { - console.log("only-immediate-fired"); -}); -"#, - )), - }) - .expect("start only-immediate JavaScript execution"); - - let only_immediate_result = only_immediate_execution - .wait() - .expect("wait for only-immediate JavaScript execution"); - let only_immediate_stdout = - String::from_utf8(only_immediate_result.stdout.clone()).expect("stdout utf8"); - let only_immediate_stderr = - String::from_utf8(only_immediate_result.stderr.clone()).expect("stderr utf8"); - assert_eq!( - only_immediate_result.exit_code, 0, - "stdout:\n{only_immediate_stdout}\nstderr:\n{only_immediate_stderr}" - ); - assert!( - only_immediate_stdout.contains("only-immediate-fired"), - "only pending setImmediate did not fire; stdout:\n{only_immediate_stdout}" - ); - assert!( - only_immediate_stderr.is_empty(), - "unexpected stderr: {only_immediate_stderr}" - ); -} - -fn javascript_execution_v8_readline_polyfill_emits_lines() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import { EventEmitter } from "node:events"; -import { createInterface } from "node:readline"; - -const input = new EventEmitter(); -const seen = []; -const rl = createInterface({ input }); -rl.on("line", (line) => seen.push(line)); -input.emit("data", "alpha\nbeta\r\ngamma"); -input.emit("end"); - -if (seen.length !== 3) { - throw new Error(`expected 3 lines, got ${JSON.stringify(seen)}`); -} -if (seen[0] !== "alpha" || seen[1] !== "beta" || seen[2] !== "gamma") { - throw new Error(`unexpected lines: ${JSON.stringify(seen)}`); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_builtin_wrappers_expose_common_named_exports() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -import { spawn, spawnSync } from "node:child_process"; -import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, statSync, writeFileSync } from "node:fs"; -import { homedir, platform } from "node:os"; -import { basename, dirname, isAbsolute, join, resolve } from "node:path"; - -if (typeof spawn !== "function" || typeof spawnSync !== "function") throw new Error("child_process exports missing"); -if (typeof closeSync !== "function" || typeof existsSync !== "function" || typeof mkdirSync !== "function") throw new Error("fs exports missing"); -if (typeof openSync !== "function" || typeof readFileSync !== "function" || typeof readSync !== "function") throw new Error("fs exports missing"); -if (typeof readdirSync !== "function" || typeof realpathSync !== "function" || typeof statSync !== "function" || typeof writeFileSync !== "function") throw new Error("fs exports missing"); -if (typeof homedir !== "function" || typeof platform !== "function") throw new Error("os exports missing"); -if (typeof basename !== "function" || typeof dirname !== "function" || typeof isAbsolute !== "function" || typeof join !== "function" || typeof resolve !== "function") throw new Error("path exports missing"); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_child_process_conformance_matches_host_node() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import childProcess from "node:child_process"; -import fs from "node:fs"; - -fs.writeFileSync("async-out.txt", Buffer.from("async:beta-async\n", "utf8")); - -const syncPiped = childProcess.spawnSync("/bin/cat", [], { - input: Buffer.from("alpha-sync"), -}); -const syncError = childProcess.spawnSync("/bin/cat", ["definitely-missing-agentos-file"]); -const syncTimeout = childProcess.spawnSync("/bin/sh", ["-c", "sleep 2"], { - timeout: 50, - killSignal: "SIGTERM", - encoding: "utf8", -}); -const stdinDestroyChild = childProcess.spawn("/bin/cat", [], { - stdio: ["pipe", "pipe", "pipe"], -}); -if (typeof stdinDestroyChild.stdin.destroy !== "function") { - throw new Error("child stdin did not expose destroy()"); -} -if ( - typeof stdinDestroyChild.stdout?.destroy !== "function" || - typeof stdinDestroyChild.stderr?.destroy !== "function" -) { - throw new Error("child output streams did not expose destroy()"); -} -const stdinDestroyStatus = await new Promise((resolve, reject) => { - stdinDestroyChild.on("error", reject); - stdinDestroyChild.on("close", (code) => resolve(code)); - stdinDestroyChild.stdin.destroy(); - if (stdinDestroyChild.stdin.destroyed !== true) { - reject(new Error("child stdin destroy() did not mark the stream destroyed")); - } -}); - -const stdinCallbackResult = await new Promise((resolve, reject) => { - const child = childProcess.spawn("/bin/cat", [], { - stdio: ["pipe", "pipe", "pipe"], - }); - const timer = setTimeout(() => { - reject(new Error("spawn(/bin/cat) stdin callback probe did not close within 2s")); - }, 2000); - const stdout = []; - const stderr = []; - let writeCallbackError = null; - let writeCallbackCalled = false; - let endCallbackCalled = false; - child.stdout.on("data", (chunk) => { - stdout.push(Buffer.from(chunk)); - }); - child.stderr.on("data", (chunk) => { - stderr.push(Buffer.from(chunk)); - }); - child.on("error", reject); - child.on("close", (code, signal) => { - clearTimeout(timer); - resolve({ - code, - signal, - writeCallbackCalled, - writeCallbackError, - endCallbackCalled, - stdoutBase64: Buffer.concat(stdout).toString("base64"), - stderrBase64: Buffer.concat(stderr).toString("base64"), - }); - }); - child.stdin.write(Buffer.from("callback:gamma"), (error) => { - writeCallbackCalled = true; - writeCallbackError = error ? String(error?.message ?? error) : null; - child.stdin.end(() => { - endCallbackCalled = true; - }); - }); -}); - -const asyncResult = await new Promise((resolve, reject) => { - const child = childProcess.spawn("/bin/cat", ["async-out.txt"], { - stdio: ["ignore", "pipe", "pipe"], - }); - const timer = setTimeout(() => { - reject(new Error("spawn(/bin/cat async-out.txt) did not close within 2s")); - }, 2000); - const stdout = []; - const stderr = []; - child.stdout.on("data", (chunk) => { - stdout.push(Buffer.from(chunk)); - }); - child.stderr.on("data", (chunk) => { - stderr.push(Buffer.from(chunk)); - }); - child.on("error", reject); - child.on("close", (code, signal) => { - clearTimeout(timer); - resolve({ - code, - signal, - stdoutBase64: Buffer.concat(stdout).toString("base64"), - stderrBase64: Buffer.concat(stderr).toString("base64"), - }); - }); -}); - -const asyncErrorResult = await new Promise((resolve, reject) => { - const child = childProcess.spawn("/bin/cat", ["definitely-missing-agentos-file"], { - stdio: ["ignore", "pipe", "pipe"], - }); - const timer = setTimeout(() => { - reject(new Error("spawn(/bin/cat missing-file) did not close within 2s")); - }, 2000); - const stdout = []; - const stderr = []; - child.stdout.on("data", (chunk) => { - stdout.push(Buffer.from(chunk)); - }); - child.stderr.on("data", (chunk) => { - stderr.push(Buffer.from(chunk)); - }); - child.on("error", reject); - child.on("close", (code, signal) => { - clearTimeout(timer); - resolve({ - code, - signal, - stdoutBase64: Buffer.concat(stdout).toString("base64"), - stderrBase64: Buffer.concat(stderr).toString("base64"), - }); - }); -}); - -console.log(JSON.stringify({ - syncPipedStatus: syncPiped.status, - syncPipedStdoutBase64: Buffer.from(syncPiped.stdout ?? []).toString("base64"), - syncPipedStderrBase64: Buffer.from(syncPiped.stderr ?? []).toString("base64"), - syncErrorStatus: syncError.status, - syncErrorStdoutBase64: Buffer.from(syncError.stdout ?? []).toString("base64"), - syncErrorStderrBase64: Buffer.from(syncError.stderr ?? []).toString("base64"), - syncTimeoutStatus: syncTimeout.status, - syncTimeoutSignal: syncTimeout.signal, - syncTimeoutErrorCode: syncTimeout.error?.code, - syncTimeoutErrorMessage: syncTimeout.error?.message, - syncTimeoutStdout: syncTimeout.stdout, - syncTimeoutStderr: syncTimeout.stderr, - stdinDestroyStatus, - stdinCallbackCode: stdinCallbackResult.code, - stdinCallbackSignal: stdinCallbackResult.signal, - stdinCallbackWriteCallbackCalled: stdinCallbackResult.writeCallbackCalled, - stdinCallbackWriteCallbackError: stdinCallbackResult.writeCallbackError, - stdinCallbackEndCallbackCalled: stdinCallbackResult.endCallbackCalled, - stdinCallbackStdoutBase64: stdinCallbackResult.stdoutBase64, - stdinCallbackStderrBase64: stdinCallbackResult.stderrBase64, - asyncCode: asyncResult.code, - asyncSignal: asyncResult.signal, - asyncStdoutBase64: asyncResult.stdoutBase64, - asyncStderrBase64: asyncResult.stderrBase64, - asyncErrorCode: asyncErrorResult.code, - asyncErrorSignal: asyncErrorResult.signal, - asyncErrorStdoutBase64: asyncErrorResult.stdoutBase64, - asyncErrorStderrBase64: asyncErrorResult.stderrBase64, -})); -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let host = run_host_node_json(temp.path(), &temp.path().join("entry.mjs")); - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = wait_with_host_child_process_bridge(execution, temp.path()); - let stdout = String::from_utf8(result.stdout).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - let guest: Value = serde_json::from_str(stdout.trim()).expect("parse guest JSON"); - assert_eq!( - guest, - host, - "guest child_process result diverged from host Node\nhost: {}\nguest: {}", - serde_json::to_string_pretty(&host).expect("pretty host JSON"), - serde_json::to_string_pretty(&guest).expect("pretty guest JSON") - ); -} - -fn javascript_execution_v8_web_stream_globals_support_basic_io() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const writes = []; -const writable = new WritableStream({ - write(chunk) { - writes.push(new TextDecoder().decode(chunk)); - }, -}); -const writer = writable.getWriter(); -await writer.write(new TextEncoder().encode("hello")); -writer.releaseLock(); - -const readable = new ReadableStream({ - start(controller) { - controller.enqueue("alpha"); - controller.close(); - }, -}); -const reader = readable.getReader(); -const first = await reader.read(); -const second = await reader.read(); -reader.releaseLock(); - -if (writes.length !== 1 || writes[0] !== "hello") { - throw new Error(`unexpected writes: ${JSON.stringify(writes)}`); -} -if (first.value !== "alpha" || first.done !== false || second.done !== true) { - throw new Error(`unexpected reads: ${JSON.stringify({ first, second })}`); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_text_codec_streams_support_pipe_through() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const { - TextEncoderStream: ModuleTextEncoderStream, - TextDecoderStream: ModuleTextDecoderStream, -} = await import("node:stream/web"); - -if (ModuleTextEncoderStream !== TextEncoderStream) { - throw new Error("node:stream/web TextEncoderStream export diverged from global"); -} -if (ModuleTextDecoderStream !== TextDecoderStream) { - throw new Error("node:stream/web TextDecoderStream export diverged from global"); -} - -if (new TextEncoderStream().encoding !== "utf-8") { - throw new Error("unexpected TextEncoderStream encoding"); -} - -const decoder = new ReadableStream({ - start(controller) { - controller.enqueue(new Uint8Array([0xe2, 0x82])); - controller.enqueue(new Uint8Array([0xac, 0x21])); - controller.close(); - }, -}).pipeThrough(new TextDecoderStream()); - -const decoderReader = decoder.getReader(); -const decoded = []; -for (;;) { - const { done, value } = await decoderReader.read(); - if (done) break; - decoded.push(value); -} -decoderReader.releaseLock(); - -if (decoded.join("") !== "€!") { - throw new Error(`unexpected decoded output: ${JSON.stringify(decoded)}`); -} - -const encoded = new ReadableStream({ - start(controller) { - controller.enqueue("hello"); - controller.enqueue(" world"); - controller.close(); - }, -}).pipeThrough(new TextEncoderStream()); - -const encodedReader = encoded.getReader(); -const bytes = []; -for (;;) { - const { done, value } = await encodedReader.read(); - if (done) break; - bytes.push(...value); -} -encodedReader.releaseLock(); - -const roundTrip = new TextDecoder().decode(new Uint8Array(bytes)); -if (roundTrip !== "hello world") { - throw new Error(`unexpected encoded output: ${roundTrip}`); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_abort_controller_dispatches_abort() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const controller = new AbortController(); -let seenAbort = false; -controller.signal.addEventListener("abort", () => { - seenAbort = true; -}); -controller.abort("stop"); -if (!controller.signal.aborted || controller.signal.reason !== "stop" || !seenAbort) { - throw new Error("abort controller did not update signal state"); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_request_accepts_abort_signal() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const controller = new AbortController(); -const request = new Request("http://example.com/test", { - method: "POST", - body: JSON.stringify({ ok: true }), - duplex: "half", - signal: controller.signal, - headers: { "content-type": "application/json" }, -}); -if (!(request.signal instanceof AbortSignal)) { - throw new Error("request signal was not preserved"); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_abort_signal_static_helpers_work() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -if (typeof AbortSignal.timeout !== "function") { - throw new Error("AbortSignal.timeout missing"); -} -if (typeof AbortSignal.any !== "function") { - throw new Error("AbortSignal.any missing"); -} - -const timeoutSignal = AbortSignal.timeout(25); -let timeoutEventCount = 0; -timeoutSignal.addEventListener("abort", () => { - timeoutEventCount += 1; -}); -await new Promise((resolve) => setTimeout(resolve, 60)); -if (!timeoutSignal.aborted) { - throw new Error("AbortSignal.timeout did not abort"); -} -if (timeoutEventCount !== 1) { - throw new Error(`unexpected timeout event count: ${timeoutEventCount}`); -} -if (!timeoutSignal.reason || timeoutSignal.reason.name !== "AbortError") { - throw new Error(`unexpected timeout reason: ${String(timeoutSignal.reason?.name ?? timeoutSignal.reason)}`); -} - -const controller = new AbortController(); -const sibling = new AbortController(); -const composite = AbortSignal.any([sibling.signal, controller.signal]); -let compositeReason; -composite.addEventListener("abort", () => { - compositeReason = composite.reason; -}); -controller.abort("manual-stop"); -await new Promise((resolve) => setTimeout(resolve, 0)); -if (!composite.aborted) { - throw new Error("AbortSignal.any did not abort"); -} -if (compositeReason !== "manual-stop" || composite.reason !== "manual-stop") { - throw new Error(`unexpected composite reason: ${String(composite.reason)}`); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8(result.stdout.clone()).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr.clone()).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_schedule_timer_bridge_resolves() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.js")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -(async () => { - let resolved = false; - await _scheduleTimer.apply(undefined, [15]).then(() => { - resolved = true; - }); - if (!resolved) { - throw new Error("_scheduleTimer did not resolve"); - } -})().catch((error) => { - process.exitCode = 1; - throw error; -}); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); - - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_kernel_poll_bridge_requests_multiple_fds() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.js")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const result = globalThis._kernelPollRaw.applySyncPromise(undefined, [[ - { fd: 0, events: 1 }, - { fd: 1, events: 1 }, -], 250]); -if (result.readyCount !== 1) { - throw new Error(`readyCount=${result.readyCount}`); -} -if (result.fds[0]?.revents !== 1 || result.fds[1]?.revents !== 0) { - throw new Error(`revents=${JSON.stringify(result.fds)}`); -} -console.log(JSON.stringify(result)); -"#, - )), - }) - .expect("start JavaScript execution"); - - let request = expect_next_sync_rpc(&mut execution, "poll execution event"); - - assert_eq!(request.method, "__kernel_poll"); - assert_eq!( - request.args, - vec![ - json!([ - { "fd": 0, "events": 1 }, - { "fd": 1, "events": 1 } - ]), - json!(250), - ] - ); - - execution - .respond_sync_rpc_success( - request.id, - json!({ - "readyCount": 1, - "fds": [ - { "fd": 0, "events": 1, "revents": 1 }, - { "fd": 1, "events": 1, "revents": 0 } - ] - }), - ) - .expect("respond to __kernel_poll"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - let stdout: Value = serde_json::from_slice(&result.stdout).expect("parse guest stdout JSON"); - assert_eq!( - stdout, - json!({ - "readyCount": 1, - "fds": [ - { "fd": 0, "events": 1, "revents": 1 }, - { "fd": 1, "events": 1, "revents": 0 } - ] - }) - ); -} - -fn javascript_execution_v8_crypto_random_sources_use_local_secure_bridge() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.js")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const first = new Uint8Array(32); -const second = new Uint8Array(32); -globalThis.crypto.getRandomValues(first); -globalThis.crypto.getRandomValues(second); - -if (first.every((value) => value === 0)) { - throw new Error("first random buffer was all zero"); -} -if (second.every((value) => value === 0)) { - throw new Error("second random buffer was all zero"); -} -const buffersMatch = first.length === second.length && - first.every((value, index) => value === second[index]); -if (buffersMatch) { - throw new Error("random buffers repeated"); -} - -const uuid = globalThis.crypto.randomUUID(); -if (!/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid)) { - throw new Error(`invalid uuid: ${uuid}`); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8(result.stdout.clone()).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr.clone()).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -#[test] -fn javascript_execution_v8_crypto_basic_operations_emit_expected_sync_rpcs() { - assert_eq!( - map_bridge_method("_cryptoHashDigest"), - ("crypto.hashDigest", false) - ); - assert_eq!( - map_bridge_method("_cryptoHmacDigest"), - ("crypto.hmacDigest", false) - ); - assert_eq!(map_bridge_method("_cryptoPbkdf2"), ("crypto.pbkdf2", false)); - assert_eq!(map_bridge_method("_cryptoScrypt"), ("crypto.scrypt", false)); - assert_eq!( - map_bridge_method("_netSocketConnectRaw"), - ("net.connect", false) - ); - assert_eq!( - map_bridge_method("_networkDnsLookupSyncRaw"), - ("dns.lookup", false) - ); - assert_eq!(map_bridge_method("_netSocketPollRaw"), ("net.poll", false)); -} - -fn javascript_execution_v8_load_polyfill_returns_runtime_module_expressions() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const pathExpr = _loadPolyfill.applySyncPromise(undefined, ["path"]); -if (typeof pathExpr !== "string" || !pathExpr.includes("node:path")) { - throw new Error(`unexpected path polyfill expression: ${String(pathExpr)}`); -} - -const pathModule = Function('"use strict"; return (' + pathExpr + ');')(); -if (pathModule.join("alpha", "beta") !== "alpha/beta") { - throw new Error("path polyfill expression did not resolve the runtime module"); -} - -const deniedExpr = _loadPolyfill.applySyncPromise(undefined, ["inspector"]); -if (typeof deniedExpr !== "string" || !deniedExpr.includes("ERR_ACCESS_DENIED")) { - throw new Error(`unexpected denied polyfill expression: ${String(deniedExpr)}`); -} - -let denied = false; -try { - Function('"use strict"; return (' + deniedExpr + ');')(); -} catch (error) { - denied = error?.code === "ERR_ACCESS_DENIED"; -} -if (!denied) { - throw new Error("denied polyfill expression did not raise ERR_ACCESS_DENIED"); -} - -if (_loadPolyfill.applySyncPromise(undefined, ["not-a-real-builtin"]) !== null) { - throw new Error("unknown polyfill name should return null"); -} -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8(result.stdout.clone()).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr.clone()).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_stream_wrapper_exports_common_node_classes() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import { - Duplex, - PassThrough, - Readable, - Transform, - Writable, - isReadable, - isWritable, -} from "node:stream"; -import { createRequire } from "node:module"; - -for (const [name, value] of Object.entries({ Duplex, PassThrough, Readable, Transform, Writable })) { - if (typeof value !== "function") { - throw new Error(`${name} was not exported as a constructor`); - } -} - -const require = createRequire(import.meta.url); -const cjsStream = require("stream"); -if (typeof cjsStream !== "function") { - throw new Error("require('stream') should return the legacy Stream constructor"); -} -if (cjsStream !== cjsStream.Stream) { - throw new Error("require('stream').Stream should alias the CommonJS export"); -} -if (typeof cjsStream.Readable !== "function") { - throw new Error("require('stream').Readable should stay available on the constructor export"); -} - -const pass = new PassThrough(); -let output = ""; -pass.on("data", (chunk) => { - output += Buffer.from(chunk).toString("utf8"); -}); -if (!isReadable(pass) || !isWritable(pass)) { - throw new Error("stream helpers misreported passthrough readability"); -} -pass.end("hello"); -await new Promise((resolve, reject) => { - pass.once("close", resolve); - pass.once("error", reject); -}); - -if (output !== "hello") { - throw new Error(`unexpected passthrough output: ${output}`); -} - -const lifecycle = []; -let writableOutput = ""; -const writable = new Writable({ - write(chunk, _encoding, callback) { - lifecycle.push("write"); - writableOutput += Buffer.from(chunk).toString("utf8"); - callback(); - }, - destroy(_error, callback) { - lifecycle.push("destroy"); - callback(); - }, -}); -writable.on("finish", () => lifecycle.push("finish")); -writable.end("hi"); -await new Promise((resolve, reject) => { - writable.once("close", resolve); - writable.once("error", reject); -}); - -if (writableOutput !== "hi") { - throw new Error(`unexpected writable output: ${writableOutput}`); -} -if (lifecycle.join(",") !== "write,finish,destroy") { - throw new Error(`unexpected writable lifecycle: ${lifecycle.join(",")}`); -} -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_buffer_wrapper_exposes_commonjs_constants() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const bufferModule = require("buffer"); - -if (typeof bufferModule.constants !== "object" || bufferModule.constants === null) { - throw new Error("require('buffer').constants was not exported"); -} -if (typeof bufferModule.constants.MAX_STRING_LENGTH !== "number") { - throw new Error("require('buffer').constants.MAX_STRING_LENGTH was not exported"); -} -if (typeof bufferModule.kMaxLength !== "number") { - throw new Error("require('buffer').kMaxLength was not exported"); -} -if (bufferModule.Buffer?.constants?.MAX_STRING_LENGTH !== bufferModule.constants.MAX_STRING_LENGTH) { - throw new Error("buffer module constants diverged from Buffer.constants"); -} -if (typeof bufferModule.Blob !== "function") { - throw new Error("require('buffer').Blob was not exported"); -} -if (typeof bufferModule.File !== "function") { - throw new Error("require('buffer').File was not exported"); -} -const file = new bufferModule.File(["hello"], "hello.txt", { type: "text/plain" }); -if (!(file instanceof bufferModule.Blob)) { - throw new Error("buffer module File did not extend Blob"); -} -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -#[allow(dead_code)] // quarantined: see the live-stdin/tty harness note above -fn javascript_execution_v8_tty_module_is_backed_by_live_process() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const tty = require("tty"); - -// tty.isatty / ReadStream / WriteStream read process.std{in,out,err}. When the -// bridge tty stub captured the `process` object at module-load time it snapshotted -// `undefined` (process.ts initializes far later in the bundle's module-cycle order), -// so these threw "Cannot read properties of undefined". Reading the live binding at -// call time fixes it; this test guards against that regression class. -if (typeof tty.isatty !== "function") { - throw new Error("require('tty').isatty was not exported"); -} -for (const fd of [0, 1, 2]) { - if (typeof tty.isatty(fd) !== "boolean") { - throw new Error(`tty.isatty(${fd}) did not return a boolean`); - } -} -if (typeof tty.ReadStream !== "function" || typeof tty.WriteStream !== "function") { - throw new Error("require('tty') stream classes were not exported"); -} -// Constructing the streams exercises the process-backed stdio getters. -new tty.ReadStream(0); -new tty.WriteStream(1); -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_sqlite_module_resolves_via_global_install() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -// require("sqlite") routes through the `_sqliteModule` global. That install was -// dropped once during the network-module split (it fell off the end of the slice), -// making this throw "ReferenceError: _sqliteModule is not defined". Guard it. -const sqlite = require("node:sqlite"); -if (typeof sqlite.DatabaseSync !== "function") { - throw new Error("require('node:sqlite').DatabaseSync was not exported"); -} -if (typeof sqlite.StatementSync !== "function") { - throw new Error("require('node:sqlite').StatementSync was not exported"); -} -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_commonjs_stack_frames_preserve_module_paths() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -require("./probe.cjs"); -"#, - ); - write_fixture( - &temp.path().join("probe.cjs"), - r#" -const previousPrepare = Error.prepareStackTrace; -try { - Error.prepareStackTrace = (_error, stack) => stack; - const stack = new Error("probe").stack ?? []; - const frame = stack.find((callsite) => { - const path = - callsite.getFileName?.() ?? callsite.getScriptNameOrSourceURL?.(); - return typeof path === "string" && path.endsWith("/probe.cjs"); - }); - if (!frame) { - const summary = stack.map((callsite) => ({ - fileName: callsite.getFileName?.() ?? null, - scriptName: callsite.getScriptNameOrSourceURL?.() ?? null, - text: String(callsite), - })); - throw new Error( - "CommonJS stack frames did not preserve the module path: " + - JSON.stringify(summary), - ); - } -} finally { - Error.prepareStackTrace = previousPrepare; -} -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_commonjs_main_entrypoints_preserve_entrypoint_paths() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.cjs"), - r#" -const EVAL_FRAMES = new Set(["[eval]", "[eval]-wrapper"]); -const INTERNAL_FRAME_NAMES = new Set([ - "readCallsites", - "resolveCallerFilePath", - "getCurrentFilePath", -]); - -function readCallsites() { - const previousPrepare = Error.prepareStackTrace; - try { - Error.prepareStackTrace = (_error, stack) => stack; - return new Error("probe").stack ?? []; - } finally { - Error.prepareStackTrace = previousPrepare; - } -} - -function readCallsitePath(callsite) { - const rawPath = - callsite.getFileName?.() ?? callsite.getScriptNameOrSourceURL?.(); - if (!rawPath || rawPath.startsWith("node:") || EVAL_FRAMES.has(rawPath)) { - return null; - } - return rawPath; -} - -function isInternalCallsite(callsite) { - const functionName = callsite.getFunctionName?.(); - if (functionName && INTERNAL_FRAME_NAMES.has(functionName)) { - return true; - } - const methodName = callsite.getMethodName?.(); - if (methodName && INTERNAL_FRAME_NAMES.has(methodName)) { - return true; - } - const callsiteString = String(callsite); - for (const frameName of INTERNAL_FRAME_NAMES) { - if ( - callsiteString.includes(`${frameName} (`) || - callsiteString.includes(`.${frameName} (`) - ) { - return true; - } - } - return false; -} - -function resolveCallerFilePath() { - for (const callsite of readCallsites()) { - const filePath = readCallsitePath(callsite); - if (!filePath || isInternalCallsite(callsite)) { - continue; - } - return filePath; - } - throw new Error("Unable to resolve caller file path."); -} - -const resolved = resolveCallerFilePath(); -if (!resolved.endsWith("/entry.cjs")) { - throw new Error(`resolved ${resolved} instead of /entry.cjs`); -} -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.cjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_inline_commonjs_entrypoints_preserve_entrypoint_paths() { - let temp = tempdir().expect("create temp dir"); - let source = String::from( - r#" -const EVAL_FRAMES = new Set(["[eval]", "[eval]-wrapper"]); -const INTERNAL_FRAME_NAMES = new Set([ - "readCallsites", - "resolveCallerFilePath", - "getCurrentFilePath", -]); - -function readCallsites() { - const previousPrepare = Error.prepareStackTrace; - try { - Error.prepareStackTrace = (_error, stack) => stack; - return new Error("probe").stack ?? []; - } finally { - Error.prepareStackTrace = previousPrepare; - } -} - -function readCallsitePath(callsite) { - const rawPath = - callsite.getFileName?.() ?? callsite.getScriptNameOrSourceURL?.(); - if (!rawPath || rawPath.startsWith("node:") || EVAL_FRAMES.has(rawPath)) { - return null; - } - return rawPath; -} - -function isInternalCallsite(callsite) { - const functionName = callsite.getFunctionName?.(); - if (functionName && INTERNAL_FRAME_NAMES.has(functionName)) { - return true; - } - const methodName = callsite.getMethodName?.(); - if (methodName && INTERNAL_FRAME_NAMES.has(methodName)) { - return true; - } - const callsiteString = String(callsite); - for (const frameName of INTERNAL_FRAME_NAMES) { - if ( - callsiteString.includes(`${frameName} (`) || - callsiteString.includes(`.${frameName} (`) - ) { - return true; - } - } - return false; -} - -function resolveCallerFilePath() { - for (const callsite of readCallsites()) { - const filePath = readCallsitePath(callsite); - if (!filePath || isInternalCallsite(callsite)) { - continue; - } - return filePath; - } - throw new Error("Unable to resolve caller file path."); -} - -const resolved = resolveCallerFilePath(); -if (!resolved.endsWith("/entry.cjs")) { - throw new Error(`resolved ${resolved} instead of /entry.cjs`); -} -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.cjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(source), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_inline_commonjs_entrypoints_preserve_commonjs_globals() { - let temp = tempdir().expect("create temp dir"); - let source = String::from( - r#" -console.log( - JSON.stringify({ - filename: __filename, - dirname: __dirname, - cwd: process.cwd(), - }), -); -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.cjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(source), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - let output: Value = serde_json::from_slice(&result.stdout).expect("parse stdout JSON"); - assert_eq!( - output, - json!({ - "filename": "/root/entry.cjs", - "dirname": "/root", - "cwd": "/root", - }) - ); -} - -fn javascript_execution_v8_commonjs_require_exposes_node_metadata() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("dep.cjs"), - r#" -const hadSelfBeforeDelete = Object.prototype.hasOwnProperty.call( - require.cache, - __filename, -); -delete require.cache[__filename]; -module.exports = { - cacheType: typeof require.cache, - hadSelfBeforeDelete, - hasSelfAfterDelete: Object.prototype.hasOwnProperty.call(require.cache, __filename), - extensionsType: typeof require.extensions, -}; -"#, - ); - write_fixture( - &temp.path().join("entry.cjs"), - r#" -const dep = require("./dep.cjs"); -console.log(JSON.stringify(dep)); -"#, - ); - - let mut host = run_host_node_json(temp.path(), &temp.path().join("entry.cjs")); - host["hadSelfBeforeDelete"] = json!(true); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.cjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - let guest: Value = serde_json::from_slice(&result.stdout).expect("parse stdout JSON"); - assert_eq!( - guest, host, - "guest CommonJS require metadata diverged from host" - ); -} - -fn javascript_execution_v8_https_agents_expose_options_objects() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const http = require("http"); -const https = require("https"); - -for (const [name, module] of Object.entries({ http, https })) { - if (!module.globalAgent || typeof module.globalAgent.options !== "object") { - throw new Error(`${name}.globalAgent.options was not initialized`); - } - const agent = new module.Agent({ keepAlive: true }); - if (!agent.options || agent.options.keepAlive !== true) { - throw new Error(`${name}.Agent did not preserve constructor options`); - } -} -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn javascript_execution_v8_net_socket_readable_state_tracks_ssh2_writable_shape() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import net from "node:net"; - -const isWritable = (stream) => - Boolean(stream?.writable && stream?._readableState?.ended === false); - -const socket = new net.Socket(); -if (socket._readableState?.ended !== false) { - throw new Error(`expected open socket ended=false, got ${String(socket._readableState?.ended)}`); -} -if (!isWritable(socket)) { - throw new Error("ssh2 writable probe should accept an open socket"); -} - -socket.destroy(); - -if (socket._readableState?.ended !== true) { - throw new Error(`expected destroyed socket ended=true, got ${String(socket._readableState?.ended)}`); -} -if (isWritable(socket)) { - throw new Error("ssh2 writable probe should reject a destroyed socket"); -} -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -// Regression: when the host briefly stops draining the V8 -> host event channel -// (capacity = JAVASCRIPT_EVENT_CHANNEL_CAPACITY = 512), a burst of guest events -// must apply backpressure, not tear the session down. The original code called -// `v8_session.destroy()` the instant `try_send` returned `Full`, turning a -// transient backlog into `Exited(1)` with a truncated event stream. -// -// The guest synchronously logs far more lines than the event channel holds. The -// host deliberately does not drain for a window, forcing the bridge onto the -// formerly fatal full path, then drains everything. With backpressure every line -// survives and the session exits cleanly; with the destroy-on-full bug the stream -// is truncated and the session never reaches a clean exit. -// -// Note: this exercises the V8->host event channel (JAVASCRIPT_EVENT_CHANNEL_CAPACITY). -// The upstream per-session v8_session_frames channel does NOT overflow here because -// each guest `console.log` is a synchronous `applySync` that blocks until the bridge -// drains it — so the guest cannot run ahead and only ~1 frame is ever in flight. That -// channel's backpressure (v8_host.rs) only engages under async runtime frame bursts; -// it shares the same TrackedSyncSender blocking-send mechanism covered by the bridge -// queue_tracker unit tests. -fn javascript_execution_v8_event_channel_backpressures_instead_of_destroying_session() { - const LINE_COUNT: usize = 1000; - let temp = tempdir().expect("create temp dir"); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - // Inline code avoids host-serviced module-resolution RPCs, so the - // guest runs autonomously and fills the event channel during the - // no-drain window below without the host's involvement. - wasm_module_bytes: None, - inline_code: Some(format!( - "for (let i = 0; i < {LINE_COUNT}; i++) {{ console.log('LINE:' + i); }}\n" - )), - }) - .expect("start JavaScript execution"); - - // Stop draining long enough for the guest burst to overrun the 512-slot - // channel and exercise the full path. - std::thread::sleep(Duration::from_millis(500)); - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - // A poll error (e.g. EventChannelClosed) means the session was torn down - // out from under us — exactly the destroy-on-full regression — so stop and - // let the assertions below report the truncation rather than panicking. - while let Ok(event) = execution.poll_event_blocking(Duration::from_secs(10)) { - match event { - Some(JavascriptExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(JavascriptExecutionEvent::Stderr(chunk)) => stderr.extend(chunk), - Some(JavascriptExecutionEvent::SignalState { .. }) => {} - Some(JavascriptExecutionEvent::SyncRpcRequest(request)) => { - // No host RPCs are expected on this path; service module RPCs if - // any surface and answer anything else with null so a stray RPC - // cannot wedge the guest. - if execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC") - { - continue; - } - execution - .respond_sync_rpc_success(request.id, Value::Null) - .expect("respond to unexpected sync RPC"); - } - Some(JavascriptExecutionEvent::Exited(code)) => { - exit_code = Some(code); - break; - } - None => break, - } - } - - let stdout = String::from_utf8_lossy(&stdout); - let stderr = String::from_utf8_lossy(&stderr); - let lines = stdout.matches("LINE:").count(); - assert_eq!( - exit_code, - Some(0), - "session must exit cleanly under backpressure (destroy-on-full regression?); \ - lines={lines}/{LINE_COUNT}, stderr: {stderr}" - ); - assert_eq!( - lines, LINE_COUNT, - "every event must survive backpressure with no truncation; stderr: {stderr}" - ); -} - -// Regression: the in-VM bridge socket read loop (`_pumpBridgeReads`) must yield -// a macrotask between delivering successive socket chunks instead of draining an -// entire response synchronously in one burst. -// -// `_netSocketReadRaw` is synchronous, so the original loop read every available -// byte and emitted `readable`/`data` for the whole HTTP response inside a single -// synchronous stack. That collapses the event-loop turn boundaries that undici's -// keep-alive socket recycling depends on: it resolves the caller's `fetch` -// synchronously and only defers reuse with `setImmediate(client[kResume])`, so -// the caller's microtask dispatches the next request while every pooled Client is -// still `kNeedDrain`. The pool then allocates a fresh Client + socket per request, -// each registering EventEmitter listeners until the guest dies -// (MaxListenersExceededWarning + unbounded memory / OOM). -// -// This reproduces the timing deterministically with two scripted socket chunks. -// A `setImmediate` is scheduled the moment the first chunk is delivered (standing -// in for `setImmediate(kResume)`); it MUST get a turn before the second chunk -// surfaces. With the synchronous-burst bug both chunks arrive before the macrotask -// runs and the guest throws; with the per-chunk macrotask yield the macrotask -// interleaves between the chunks and the guest prints `ORDER_OK`. -fn javascript_execution_v8_net_socket_read_loop_yields_macrotask_between_chunks() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -import net from "node:net"; - -const order = []; -let scheduledImmediate = false; - -const socket = net.connect({ host: "127.0.0.1", port: 80 }); - -socket.on("data", (chunk) => { - order.push("data:" + chunk.toString()); - if (!scheduledImmediate) { - scheduledImmediate = true; - // Stand-in for undici's setImmediate(client[kResume]) keep-alive recycle: - // a macrotask scheduled the instant the first socket chunk lands. It must - // get a turn before the next chunk is delivered. - setImmediate(() => { order.push("immediate"); }); - } -}); - -await new Promise((resolve, reject) => { - socket.once("end", resolve); - socket.once("close", resolve); - socket.once("error", reject); -}); - -// Flush any macrotask still pending after the stream ends. -await new Promise((resolve) => setImmediate(resolve)); - -const trace = order.join(","); -const immediateIdx = order.indexOf("immediate"); -const secondChunkIdx = order.indexOf("data:chunk-2"); -if (immediateIdx === -1) { - throw new Error("macrotask never ran: " + trace); -} -if (secondChunkIdx === -1) { - throw new Error("second chunk never delivered: " + trace); -} -if (immediateIdx > secondChunkIdx) { - throw new Error( - "bridge delivered the response in one synchronous burst; the keep-alive " + - "macrotask never interleaved between chunks: " + trace, - ); -} -console.log("ORDER_OK:" + trace); -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let mut execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let chunk1 = base64::engine::general_purpose::STANDARD.encode("chunk-1"); - let chunk2 = base64::engine::general_purpose::STANDARD.encode("chunk-2"); - let mut socket_reads = 0usize; - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - - let exit_code = loop { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll net socket bridge event") - { - Some(JavascriptExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(JavascriptExecutionEvent::Stderr(chunk)) => stderr.extend(chunk), - Some(JavascriptExecutionEvent::SignalState { .. }) => {} - Some(JavascriptExecutionEvent::SyncRpcRequest(request)) => { - if execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC") - { - continue; - } - let request_id = request.id; - let response = match request.method.as_str() { - "net.connect" => json!({ - "socketId": 1, - "localAddress": "127.0.0.1", - "localPort": 12345, - "localFamily": "IPv4", - "remoteAddress": "127.0.0.1", - "remotePort": 80, - "remoteFamily": "IPv4", - }), - "net.socket_wait_connect" => json!( - "{\"localAddress\":\"127.0.0.1\",\"localPort\":12345,\ - \"remoteAddress\":\"127.0.0.1\",\"remotePort\":80}" - ), - // First read -> chunk 1, second read -> chunk 2, then EOF (null). - "net.socket_read" => { - socket_reads += 1; - match socket_reads { - 1 => json!(chunk1), - 2 => json!(chunk2), - _ => Value::Null, - } - } - // Any incidental socket RPC (set_no_delay, poll, shutdown, - // destroy, ...) gets a benign null so the flow proceeds. - _ => Value::Null, - }; - execution - .respond_sync_rpc_success(request_id, response) - .expect("respond to net socket bridge RPC"); - } - Some(JavascriptExecutionEvent::Exited(exit_code)) => break exit_code, - None => panic!("net socket bridge execution timed out while awaiting exit"), - } - }; - - let stdout = String::from_utf8(stdout).expect("stdout utf8"); - let stderr = String::from_utf8(stderr).expect("stderr utf8"); - assert_eq!( - exit_code, 0, - "guest exited non-zero (synchronous-burst regression?)\nstdout: {stdout}\nstderr: {stderr}" - ); - assert!( - stdout.contains("ORDER_OK:data:chunk-1,immediate,data:chunk-2"), - "expected macrotask to interleave between chunks; stdout: {stdout}\nstderr: {stderr}" - ); - assert_eq!( - socket_reads, 3, - "expected exactly chunk1, chunk2, EOF reads" - ); -} - -fn javascript_execution_v8_dynamic_import_accepts_file_urls() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("dep.mjs"), - r#" -export default { value: "ok" }; -"#, - ); - write_fixture( - &temp.path().join("entry.mjs"), - r#" -const href = new URL("./dep.mjs", import.meta.url).href; -const module = await import(href); -console.log(JSON.stringify({ href, value: module.default.value })); -"#, - ); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "unexpected stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - let output: Value = serde_json::from_slice(&result.stdout).expect("parse stdout JSON"); - assert_eq!( - output, - json!({ - "href": "file:///root/dep.mjs", - "value": "ok", - }) - ); -} - -fn javascript_execution_v8_wasm_instantiate_streaming_never_hangs() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const bytes = new Uint8Array([ - 0,97,115,109,1,0,0,0,1,5,1,96,0,1,127,3,2,1,0,7,12,1,8,102,111,114,116,121,84,119,111,0,0,10,6,1,4,0,65,42,11, -]); -const response = new Response(bytes, { - headers: { "content-type": "application/wasm" }, -}); - -let outcome = "pending"; -try { - const result = await WebAssembly.instantiateStreaming(Promise.resolve(response), {}); - if (typeof result?.instance?.exports?.fortyTwo !== "function") { - throw new Error("instantiateStreaming() did not return an exported function"); - } - if (result.instance.exports.fortyTwo() !== 42) { - throw new Error(`unexpected wasm export value: ${result.instance.exports.fortyTwo()}`); - } - outcome = "ok"; -} catch (error) { - if (error?.code !== "ERR_NOT_IMPLEMENTED") { - throw error; - } - outcome = error.code; -} - -console.log(outcome); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8(result.stdout).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - let outcome = stdout.trim(); - assert!( - outcome == "ok" || outcome == "ERR_NOT_IMPLEMENTED", - "unexpected instantiateStreaming outcome: {outcome}" - ); -} - -fn javascript_execution_v8_structured_clone_rebinds_to_sandbox_realm() { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -const source = new Uint8Array([1, 2, 3, 4]); -const typed = structuredClone(source, { transfer: [source.buffer] }); -const map = structuredClone(new Map([["a", 1]])); -const date = structuredClone(new Date(0)); -const regexSource = /agent/gi; -regexSource.lastIndex = 2; -const regex = structuredClone(regexSource); -const dataView = structuredClone(new DataView(new Uint8Array([9, 8, 7, 6]).buffer, 1, 2)); -const circular = { label: "loop" }; -circular.self = circular; -const circularClone = structuredClone(circular); -const nested = structuredClone({ - list: [new Uint16Array([5, 6])], - set: new Set(["x"]), -}); -let functionErrorName = null; -try { - structuredClone(() => {}); -} catch (error) { - functionErrorName = error?.name ?? String(error); -} -console.log(JSON.stringify({ - typed: { - instanceof: typed instanceof Uint8Array, - sameConstructor: typed.constructor === Uint8Array, - constructorName: typed.constructor?.name, - length: typed.length, - first: typed[0], - }, - map: { - instanceof: map instanceof Map, - value: map.get("a"), - }, - date: { - instanceof: date instanceof Date, - value: date.valueOf(), - }, - regex: { - instanceof: regex instanceof RegExp, - source: regex.source, - flags: regex.flags, - lastIndex: regex.lastIndex, - }, - dataView: { - instanceof: dataView instanceof DataView, - byteLength: dataView.byteLength, - first: dataView.getUint8(0), - }, - circular: circularClone !== circular && circularClone.self === circularClone, - nested: { - typedArrayInstanceof: nested.list[0] instanceof Uint16Array, - setInstanceof: nested.set instanceof Set, - setValue: nested.set.has("x"), - }, - functionErrorName, -})); -"#, - )), - }) - .expect("start JavaScript execution"); - - let result = execution.wait().expect("wait for JavaScript execution"); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(result.stderr.is_empty(), "unexpected stderr: {stderr}"); - - let output: Value = serde_json::from_slice(&result.stdout).expect("parse stdout JSON"); - assert_eq!( - output, - json!({ - "typed": { - "instanceof": true, - "sameConstructor": true, - "constructorName": "Uint8Array", - "length": 4, - "first": 1, - }, - "map": { - "instanceof": true, - "value": 1, - }, - "date": { - "instanceof": true, - "value": 0, - }, - "regex": { - "instanceof": true, - "source": "agent", - "flags": "gi", - "lastIndex": 2, - }, - "dataView": { - "instanceof": true, - "byteLength": 2, - "first": 8, - }, - "circular": true, - "nested": { - "typedArrayInstanceof": true, - "setInstanceof": true, - "setValue": true, - }, - "functionErrorName": "DataCloneError", - }) - ); -} - -// --------------------------------------------------------------------------- -// jsRuntime platform / module-resolution coverage -// --------------------------------------------------------------------------- - -fn js_runtime_env(pairs: &[(&str, &str)]) -> BTreeMap { - pairs - .iter() - .map(|(key, value)| (String::from(*key), String::from(*value))) - .collect() -} - -fn run_js_runtime_guest( - env: BTreeMap, - inline_code: &str, -) -> JavascriptExecutionResult { - let temp = tempdir().expect("create temp dir"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env, - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(inline_code.to_owned()), - }) - .expect("start JavaScript execution"); - assert!( - execution.uses_shared_v8_runtime(), - "guest JS must run inside the shared V8 runtime" - ); - execution.wait().expect("wait for JavaScript execution") -} - -/// Run guest code that throws on any policy violation; a clean exit means every -/// assertion held. (Lower tiers have no `console`, so guest code signals failure -/// by throwing, not by printing.) -fn assert_js_runtime_guest_ok(env: BTreeMap, inline_code: &str) { - let result = run_js_runtime_guest(env, inline_code); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!( - result.exit_code, 0, - "guest jsRuntime assertion failed\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); -} - -fn js_runtime_node_platform_keeps_full_node_surface() { - // No jsRuntime env == node platform: the full Node surface stays intact and - // builtins remain importable (positive control for the scrub tests below). - assert_js_runtime_guest_ok( - BTreeMap::new(), - r#" - if (typeof process === "undefined") throw new Error("process missing"); - if (typeof Buffer === "undefined") throw new Error("Buffer missing"); - if (typeof require === "undefined") throw new Error("require missing"); - if (typeof fetch === "undefined") throw new Error("fetch missing"); - const fs = await import("node:fs"); - if (typeof fs.readFileSync !== "function") throw new Error("node:fs not usable"); - "#, - ); -} - -fn js_runtime_bare_platform_strips_all_host_globals() { - // Pentest: nothing host-provided survives, and it cannot be reconstructed via - // constructors / property-name tricks. Language + WebAssembly remain. - assert_js_runtime_guest_ok( - js_runtime_env(&[ - ("AGENTOS_JS_PLATFORM", "bare"), - ("AGENTOS_JS_BUILTIN_ALLOWLIST", "[]"), - ]), - r#" - const banned = [ - "process","Buffer","require","module","exports","__dirname","__filename","global", - "fetch","Headers","Request","Response","URL","URLSearchParams","crypto","structuredClone", - "console","setTimeout","setInterval","setImmediate","queueMicrotask", - "_processConfig","__agentOSProcessConfigEnv", - ]; - for (const name of banned) { - if (typeof globalThis[name] !== "undefined") throw new Error("leaked global: " + name); - if (Object.prototype.hasOwnProperty.call(globalThis, name) && globalThis[name] !== undefined) { - throw new Error("leaked own prop: " + name); - } - } - // process must not be reachable through the Function constructor either. - try { - const f = (function(){}).constructor("return typeof process")(); - if (f !== "undefined") throw new Error("process reachable via Function ctor"); - } catch (e) { if (String(e).includes("reachable")) throw e; } - for (const g of ["JSON","Math","Promise","WebAssembly","Object","Array","Reflect"]) { - if (typeof globalThis[g] === "undefined") throw new Error("language global missing: " + g); - } - // The allow-list plumbing must leave no reachable global: the shim calls the - // one-shot init fn and deletes it, and the old reachable allow-list is gone. - if (typeof globalThis.__agentOSBuiltinAllowlist !== "undefined") { - throw new Error("__agentOSBuiltinAllowlist is still reachable"); - } - if (typeof globalThis.__agentOSInitJsRuntime !== "undefined") { - throw new Error("__agentOSInitJsRuntime is still reachable"); - } - "#, - ); -} - -fn js_runtime_browser_platform_exposes_web_without_node() { - assert_js_runtime_guest_ok( - js_runtime_env(&[ - ("AGENTOS_JS_PLATFORM", "browser"), - ("AGENTOS_JS_BUILTIN_ALLOWLIST", "[]"), - ]), - r#" - for (const name of ["process","Buffer","require","module","_processConfig","__agentOSProcessConfigEnv"]) { - if (typeof globalThis[name] !== "undefined") throw new Error("node global leaked: " + name); - } - for (const name of ["fetch","URL","TextEncoder","TextDecoder","structuredClone","console","setTimeout"]) { - if (typeof globalThis[name] === "undefined") throw new Error("web/universal global missing: " + name); - } - if (typeof crypto === "undefined" || typeof crypto.subtle === "undefined") { - throw new Error("WebCrypto missing"); - } - // crypto must be WebCrypto, not the node:crypto module. - if (typeof crypto.randomBytes === "function" || typeof crypto.createHash === "function") { - throw new Error("node:crypto leaked through globalThis.crypto"); - } - // node:* builtins are denied under browser by the bridge gate, which throws - // an error with code === "ERR_ACCESS_DENIED". - let code = null; - try { await import("node:fs"); } catch (e) { code = e && e.code; } - if (code !== "ERR_ACCESS_DENIED") { - throw new Error("expected ERR_ACCESS_DENIED, got " + code); - } - "#, - ); -} - -fn js_runtime_neutral_platform_drops_web_keeps_universal() { - assert_js_runtime_guest_ok( - js_runtime_env(&[ - ("AGENTOS_JS_PLATFORM", "neutral"), - ("AGENTOS_JS_BUILTIN_ALLOWLIST", "[]"), - ]), - r#" - for (const name of ["process","Buffer","require","fetch","URL","crypto","structuredClone"]) { - if (typeof globalThis[name] !== "undefined") throw new Error("global leaked at neutral: " + name); - } - for (const name of ["console","setTimeout","queueMicrotask","TextEncoder","WebAssembly"]) { - if (typeof globalThis[name] === "undefined") throw new Error("universal global missing: " + name); - } - "#, - ); -} - -fn js_runtime_module_resolution_none_denies_all_imports() { - // AGENTOS_JS_BUILTIN_ALLOWLIST=[] denies builtins; moduleResolution=none denies - // bare AND relative specifiers via static import, dynamic import, and require. - assert_js_runtime_guest_ok( - js_runtime_env(&[ - ("AGENTOS_JS_MODULE_RESOLUTION", "none"), - ("AGENTOS_JS_BUILTIN_ALLOWLIST", "[]"), - ]), - r#" - let n = 0; - try { await import("node:fs"); } catch { n++; } - try { await import("lodash"); } catch { n++; } - try { await import("./local.mjs"); } catch { n++; } - if (n !== 3) throw new Error("expected all imports denied, denied=" + n); - "#, - ); -} - -fn js_runtime_module_resolution_relative_allows_local_denies_bare() { - // Write a local module into the guest cwd, then assert relative resolves while - // bare + builtin do not. - let temp = tempdir().expect("create temp dir"); - std::fs::write(temp.path().join("local.mjs"), "export const ok = 42;\n") - .expect("write local module"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: js_runtime_env(&[ - ("AGENTOS_JS_MODULE_RESOLUTION", "relative"), - ("AGENTOS_JS_BUILTIN_ALLOWLIST", "[]"), - ]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" - const local = await import("./local.mjs"); - if (local.ok !== 42) throw new Error("relative import failed"); - let bareDenied = false; - try { await import("lodash"); } catch { bareDenied = true; } - if (!bareDenied) throw new Error("bare specifier was not denied under relative"); - let builtinDenied = false; - try { await import("node:fs"); } catch { builtinDenied = true; } - if (!builtinDenied) throw new Error("node:fs was not denied under relative"); - "#, - )), - }) - .expect("start JavaScript execution"); - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!( - result.exit_code, 0, - "relative-resolution test failed\nstderr:\n{stderr}" - ); -} - -fn js_runtime_node_platform_allow_list_restricts_builtins() { - // platform=node with an explicit allow-list of just "path": node:path resolves, - // node:fs is denied. - assert_js_runtime_guest_ok( - js_runtime_env(&[("AGENTOS_JS_BUILTIN_ALLOWLIST", "[\"path\"]")]), - r#" - const path = await import("node:path"); - if (typeof path.join !== "function") throw new Error("node:path should be allowed"); - let denied = false; - try { await import("node:fs"); } catch { denied = true; } - if (!denied) throw new Error("node:fs should be denied when not in the allow-list"); - "#, - ); -} - -fn js_runtime_browser_loads_cjs_npm_package() { - // Regression guard: the per-execution shim must NOT scrub the internal CJS - // helpers under browser, so an npm CommonJS package still loads via the - // ESM->CJS interop path. node resolution is the browser default (do not set - // AGENTOS_JS_MODULE_RESOLUTION). - let temp = tempdir().expect("create temp dir"); - let pkg_dir = temp.path().join("node_modules").join("demo-pkg"); - std::fs::create_dir_all(&pkg_dir).expect("create demo-pkg dir"); - std::fs::write( - pkg_dir.join("package.json"), - r#"{"name":"demo-pkg","version":"1.0.0","main":"index.js"}"#, - ) - .expect("write package.json"); - std::fs::write( - pkg_dir.join("index.js"), - "module.exports = { answer: 42 };\n", - ) - .expect("write index.js"); - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: js_runtime_env(&[ - ("AGENTOS_JS_PLATFORM", "browser"), - ("AGENTOS_JS_BUILTIN_ALLOWLIST", "[]"), - ]), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" - const pkg = await import("demo-pkg"); - const v = pkg.answer ?? pkg.default?.answer; - if (v !== 42) throw new Error("npm CJS import failed: " + JSON.stringify(v)); - "#, - )), - }) - .expect("start JavaScript execution"); - let result = execution.wait().expect("wait for JavaScript execution"); - let stderr = String::from_utf8_lossy(&result.stderr); - assert_eq!( - result.exit_code, 0, - "browser npm CJS load test failed\nstderr:\n{stderr}" - ); -} - -fn js_runtime_browser_fetch_is_callable() { - // fetch must survive the browser scrub and be wired to the kernel socket - // table: calling it returns a thenable that rejects on an unreachable host - // rather than throwing synchronously or being undefined. - assert_js_runtime_guest_ok( - js_runtime_env(&[ - ("AGENTOS_JS_PLATFORM", "browser"), - ("AGENTOS_JS_BUILTIN_ALLOWLIST", "[]"), - ]), - r#" - if (typeof fetch !== "function") throw new Error("fetch missing"); - let threwSync = false, settled = "none"; - let p; - try { p = fetch("http://127.0.0.1:1/"); } catch { threwSync = true; } - if (threwSync) throw new Error("fetch threw synchronously"); - if (!p || typeof p.then !== "function") throw new Error("fetch did not return a promise"); - try { await p; settled = "resolved"; } catch { settled = "rejected"; } - if (settled !== "rejected") { - throw new Error("expected fetch to reject on unreachable host, got " + settled); - } - "#, - ); -} - -// SE-EXEC-04 (B.2 / F-001): with an OPT-IN CPU-time budget set, a CPU-bound -// `while (true) {}` guest must be terminated by the TRUE CPU-time watchdog -// instead of pinning a core on the shared, slot-bounded V8 runtime and starving -// peers. The watchdog samples the execution thread's per-thread CPU clock, so a -// tight busy loop burns its budget quickly and is killed. -// -// This is the BOUNDED variant: it sets a small explicit CPU budget via typed -// `limits.jsRuntime.cpuTimeLimitMs` so the watchdog fires fast. The guest run is -// fenced behind a worker thread + recv timeout so a regression surfaces as a -// clear failure instead of a CI hang. -fn javascript_infinite_loop_is_terminated_by_cpu_watchdog() { - let (tx, rx) = mpsc::channel::<(i32, String, String)>(); - thread::spawn(move || { - let temp = match tempdir() { - Ok(temp) => temp, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("tempdir failed: {error}"))); - return; - } - }; - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine.start_execution(StartJavascriptExecutionRequest { - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - // Small bounded budget so the watchdog terminates the runaway fast. - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from("while (true) {}\n")), - limits: JavascriptExecutionLimits { - cpu_time_limit_ms: Some(750), - ..Default::default() - }, - guest_runtime: Default::default(), - }); - - match execution { - Ok(execution) => match execution.wait() { - Ok(result) => { - let stdout = String::from_utf8_lossy(&result.stdout).into_owned(); - let stderr = String::from_utf8_lossy(&result.stderr).into_owned(); - let _ = tx.send((result.exit_code, stdout, stderr)); - } - Err(error) => { - let _ = tx.send((-1, String::new(), format!("wait failed: {error}"))); - } - }, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("start failed: {error}"))); - } - } - }); - - match rx.recv_timeout(Duration::from_secs(20)) { - Ok((exit_code, stdout, stderr)) => { - // The watchdog must terminate the loop with a nonzero exit code. - assert_ne!( - exit_code, 0, - "infinite loop returned a clean exit instead of being terminated by the CPU watchdog: stdout={stdout} stderr={stderr}" - ); - // And it must be attributed to the CPU-time budget specifically. - assert!( - stderr.contains("ERR_SCRIPT_CPU_BUDGET_EXCEEDED") - || stderr.contains("CPU-time budget"), - "termination was not attributed to the CPU-time budget: stdout={stdout} stderr={stderr}" - ); - } - Err(_) => { - // No result within the budget => the watchdog never armed/fired and the - // CPU-bound guest ran unbounded. This is exactly the F-001 break. - panic!( - "infinite-loop guest was NOT terminated by the CPU watchdog \ - (wait() never returned within the bounded test budget => unbounded CPU runaway)" - ); - } - } -} - -// SE-EXEC-04 (F-001) CRITICAL NEGATIVE: with a CPU-time budget set, a guest that -// mostly AWAITS (timers / idle) past the budget window must NOT be killed. The -// watchdog measures TRUE active-JS CPU time (per-thread CPU clock), which does not -// advance while the thread is parked awaiting a timer, so idle/await is excluded. -// -// The guest sleeps for ~1.5s of wall time while the CPU budget is only 300ms. A -// wall-clock timer would have killed it; the CPU-time budget must not, because the -// guest burns almost no CPU. This is what proves I/O/idle wait is excluded. -fn javascript_awaiting_guest_is_not_killed_by_cpu_budget() { - let (tx, rx) = mpsc::channel::<(i32, String, String)>(); - thread::spawn(move || { - let temp = match tempdir() { - Ok(temp) => temp, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("tempdir failed: {error}"))); - return; - } - }; - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js-await"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine.start_execution(StartJavascriptExecutionRequest { - vm_id: String::from("vm-js-await"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - // CPU budget (300ms) much SMALLER than the wall time the guest spends - // awaiting (~1.5s). A correct CPU-time budget excludes the idle wait. - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - "await new Promise((resolve) => setTimeout(resolve, 1500));\n\ - console.log('awaited-ok');\n", - )), - limits: JavascriptExecutionLimits { - cpu_time_limit_ms: Some(300), - ..Default::default() - }, - guest_runtime: Default::default(), - }); - - match execution { - Ok(execution) => match execution.wait() { - Ok(result) => { - let stdout = String::from_utf8_lossy(&result.stdout).into_owned(); - let stderr = String::from_utf8_lossy(&result.stderr).into_owned(); - let _ = tx.send((result.exit_code, stdout, stderr)); - } - Err(error) => { - let _ = tx.send((-1, String::new(), format!("wait failed: {error}"))); - } - }, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("start failed: {error}"))); - } - } - }); - - match rx.recv_timeout(Duration::from_secs(20)) { - Ok((exit_code, stdout, stderr)) => { - assert!( - !stderr.contains("ERR_SCRIPT_CPU_BUDGET_EXCEEDED") - && !stderr.contains("CPU-time budget"), - "an awaiting (low-CPU) guest was wrongly killed by the CPU budget; idle/await \ - must be excluded: exit_code={exit_code} stdout={stdout} stderr={stderr}" - ); - assert_eq!( - exit_code, 0, - "awaiting guest should complete cleanly (idle excluded from CPU budget): \ - stdout={stdout} stderr={stderr}" - ); - assert!( - stdout.contains("awaited-ok"), - "awaiting guest did not run to completion: stdout={stdout} stderr={stderr}" - ); - } - Err(_) => { - panic!( - "awaiting guest never produced a result within the bounded test window \ - (unexpected hang)" - ); - } - } -} - -// SE-EXEC-04 (F-001): with no explicit `limits.jsRuntime.cpuTimeLimitMs`, the -// CPU-budget watchdog uses the bounded default. A short CPU-bound guest still -// runs to completion because it stays below that generous active-CPU budget. We -// deliberately use a SHORT, self-terminating busy loop (not an infinite one) so -// the test cannot hang if the guard regresses. -fn javascript_default_cpu_budget_allows_short_cpu_work() { - let (tx, rx) = mpsc::channel::<(i32, String, String)>(); - thread::spawn(move || { - let temp = match tempdir() { - Ok(temp) => temp, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("tempdir failed: {error}"))); - return; - } - }; - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js-nolimit"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine.start_execution(StartJavascriptExecutionRequest { - vm_id: String::from("vm-js-nolimit"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - // No CPU-limit env: the watchdog uses the bounded default. - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - // ~600ms busy loop: long enough to have tripped the old 30s default's - // removal is irrelevant, but short enough to always finish; importantly - // it self-terminates so the test never hangs. - wasm_module_bytes: None, - inline_code: Some(String::from( - "const end = Date.now() + 600;\n\ - let n = 0;\n\ - while (Date.now() < end) { n++; }\n\ - console.log('busy-done', n > 0);\n", - )), - limits: Default::default(), - guest_runtime: Default::default(), - }); - - match execution { - Ok(execution) => match execution.wait() { - Ok(result) => { - let stdout = String::from_utf8_lossy(&result.stdout).into_owned(); - let stderr = String::from_utf8_lossy(&result.stderr).into_owned(); - let _ = tx.send((result.exit_code, stdout, stderr)); - } - Err(error) => { - let _ = tx.send((-1, String::new(), format!("wait failed: {error}"))); - } - }, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("start failed: {error}"))); - } - } - }); - - match rx.recv_timeout(Duration::from_secs(20)) { - Ok((exit_code, stdout, stderr)) => { - assert!( - !stderr.contains("ERR_SCRIPT_CPU_BUDGET_EXCEEDED") - && !stderr.contains("CPU-time budget"), - "guest was CPU-limited despite staying below the default CPU budget: \ - exit_code={exit_code} stdout={stdout} stderr={stderr}" - ); - assert_eq!( - exit_code, 0, - "short busy loop should exit cleanly under the default CPU budget: \ - stdout={stdout} stderr={stderr}" - ); - assert!( - stdout.contains("busy-done true"), - "busy loop did not run to completion under the default CPU budget: \ - stdout={stdout} stderr={stderr}" - ); - } - Err(_) => { - panic!( - "no-limit guest never produced a result within the bounded test window \ - (unexpected hang)" - ); - } - } -} - -// WALL-CLOCK BACKSTOP (opt-in, complements the CPU-time budget): with -// typed `limits.jsRuntime.wallClockLimitMs` set, a guest that exceeds the wall-clock limit -// must be terminated and the result attributed to the WALL-CLOCK reason. Crucially, -// the wall-clock limit counts elapsed REAL time INCLUDING idle/await, so a guest -// that merely AWAITS past the limit (burning almost no CPU) is still killed — this -// is exactly what the CPU-time budget does NOT do. The guest awaits ~1.5s while the -// wall-clock limit is only 300ms, and NO CPU budget is set, so only the wall-clock -// guard can fire. -// -// BOUNDED variant: small explicit wall-clock limit so the backstop fires fast; the -// run is fenced behind a worker thread + recv timeout so a regression surfaces as a -// clear failure instead of a CI hang. -fn javascript_awaiting_guest_is_terminated_by_wall_clock_backstop() { - let (tx, rx) = mpsc::channel::<(i32, String, String)>(); - thread::spawn(move || { - let temp = match tempdir() { - Ok(temp) => temp, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("tempdir failed: {error}"))); - return; - } - }; - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js-wallclock"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine.start_execution(StartJavascriptExecutionRequest { - vm_id: String::from("vm-js-wallclock"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - // Wall-clock limit (300ms) much SMALLER than the wall time the guest - // spends awaiting (~1.5s). The wall-clock backstop counts idle/await, so - // it must terminate the guest even though it burns almost no CPU. No CPU - // budget is set, proving the two knobs are independent. - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - "await new Promise((resolve) => setTimeout(resolve, 1500));\n\ - console.log('awaited-ok');\n", - )), - limits: JavascriptExecutionLimits { - wall_clock_limit_ms: Some(300), - ..Default::default() - }, - guest_runtime: Default::default(), - }); - - match execution { - Ok(execution) => match execution.wait() { - Ok(result) => { - let stdout = String::from_utf8_lossy(&result.stdout).into_owned(); - let stderr = String::from_utf8_lossy(&result.stderr).into_owned(); - let _ = tx.send((result.exit_code, stdout, stderr)); - } - Err(error) => { - let _ = tx.send((-1, String::new(), format!("wait failed: {error}"))); - } - }, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("start failed: {error}"))); - } - } - }); - - match rx.recv_timeout(Duration::from_secs(20)) { - Ok((exit_code, stdout, stderr)) => { - assert_ne!( - exit_code, 0, - "awaiting guest returned a clean exit instead of being terminated by the \ - wall-clock backstop: stdout={stdout} stderr={stderr}" - ); - // Must be attributed to the WALL-CLOCK reason specifically (not CPU budget). - assert!( - stderr.contains("ERR_SCRIPT_WALL_CLOCK_EXCEEDED") - || stderr.contains("wall-clock limit"), - "termination was not attributed to the wall-clock backstop: \ - stdout={stdout} stderr={stderr}" - ); - assert!( - !stderr.contains("ERR_SCRIPT_CPU_BUDGET_EXCEEDED") - && !stderr.contains("CPU-time budget"), - "wall-clock termination was wrongly attributed to the CPU budget: \ - stdout={stdout} stderr={stderr}" - ); - assert!( - !stdout.contains("awaited-ok"), - "guest ran to completion despite exceeding the wall-clock limit: \ - stdout={stdout} stderr={stderr}" - ); - } - Err(_) => { - panic!( - "awaiting guest was NOT terminated by the wall-clock backstop \ - (wait() never returned within the bounded test window => backstop never fired)" - ); - } - } -} - -// WALL-CLOCK / CPU-BUDGET INDEPENDENCE: setting ONLY the CPU budget must NOT impose -// any wall-clock limit. A guest that awaits past a window which the wall-clock limit -// (if it were armed) would have killed, but burns almost no CPU, must run to -// completion when only `limits.jsRuntime.cpuTimeLimitMs` is set. This confirms the CPU -// budget does not secretly behave like a wall-clock timer and that the knobs are -// independent. -fn javascript_cpu_budget_only_does_not_impose_wall_clock_limit() { - let (tx, rx) = mpsc::channel::<(i32, String, String)>(); - thread::spawn(move || { - let temp = match tempdir() { - Ok(temp) => temp, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("tempdir failed: {error}"))); - return; - } - }; - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js-cpu-only"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine.start_execution(StartJavascriptExecutionRequest { - vm_id: String::from("vm-js-cpu-only"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - // Only the CPU budget is set (300ms). The guest awaits ~1.2s of wall - // time but burns no CPU, so neither guard should fire — proving the CPU - // budget alone does NOT arm a wall-clock limit. - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - "await new Promise((resolve) => setTimeout(resolve, 1200));\n\ - console.log('cpu-only-ok');\n", - )), - limits: JavascriptExecutionLimits { - cpu_time_limit_ms: Some(300), - ..Default::default() - }, - guest_runtime: Default::default(), - }); - - match execution { - Ok(execution) => match execution.wait() { - Ok(result) => { - let stdout = String::from_utf8_lossy(&result.stdout).into_owned(); - let stderr = String::from_utf8_lossy(&result.stderr).into_owned(); - let _ = tx.send((result.exit_code, stdout, stderr)); - } - Err(error) => { - let _ = tx.send((-1, String::new(), format!("wait failed: {error}"))); - } - }, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("start failed: {error}"))); - } - } - }); - - match rx.recv_timeout(Duration::from_secs(20)) { - Ok((exit_code, stdout, stderr)) => { - assert!( - !stderr.contains("ERR_SCRIPT_WALL_CLOCK_EXCEEDED") - && !stderr.contains("wall-clock limit"), - "a wall-clock limit fired despite only the CPU budget being set; the knobs \ - must be independent: exit_code={exit_code} stdout={stdout} stderr={stderr}" - ); - assert_eq!( - exit_code, 0, - "awaiting guest should complete cleanly with only a CPU budget set \ - (idle excluded, no wall-clock limit): stdout={stdout} stderr={stderr}" - ); - assert!( - stdout.contains("cpu-only-ok"), - "guest did not run to completion with only a CPU budget set: \ - stdout={stdout} stderr={stderr}" - ); - } - Err(_) => { - panic!( - "cpu-budget-only guest never produced a result within the bounded test window \ - (unexpected hang)" - ); - } - } -} - -// WALL-CLOCK OPT-IN: with no explicit `limits.jsRuntime.wallClockLimitMs`, there is no -// wall-clock limit. A guest that awaits well past any default a former -// wall-clock timer might have imposed must run to completion. This guards the -// requirement that long-lived ACP adapters (which run indefinitely on -// wall-clock) are never killed by a wall-clock default. The default CPU budget -// remains armed but excludes idle/await time. -fn javascript_no_time_limit_when_neither_env_set() { - let (tx, rx) = mpsc::channel::<(i32, String, String)>(); - thread::spawn(move || { - let temp = match tempdir() { - Ok(temp) => temp, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("tempdir failed: {error}"))); - return; - } - }; - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js-notimelimit"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine.start_execution(StartJavascriptExecutionRequest { - vm_id: String::from("vm-js-notimelimit"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - // No wall-clock env: no wall-clock guard is armed. The default CPU - // budget excludes this idle await. - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - // Awaits ~1.2s, then exits cleanly. Self-terminating so the test cannot - // hang even if (incorrectly) no limit were enforced. - wasm_module_bytes: None, - inline_code: Some(String::from( - "await new Promise((resolve) => setTimeout(resolve, 1200));\n\ - console.log('no-limit-ok');\n", - )), - limits: Default::default(), - guest_runtime: Default::default(), - }); - - match execution { - Ok(execution) => match execution.wait() { - Ok(result) => { - let stdout = String::from_utf8_lossy(&result.stdout).into_owned(); - let stderr = String::from_utf8_lossy(&result.stderr).into_owned(); - let _ = tx.send((result.exit_code, stdout, stderr)); - } - Err(error) => { - let _ = tx.send((-1, String::new(), format!("wait failed: {error}"))); - } - }, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("start failed: {error}"))); - } - } - }); - - match rx.recv_timeout(Duration::from_secs(20)) { - Ok((exit_code, stdout, stderr)) => { - assert!( - !stderr.contains("ERR_SCRIPT_WALL_CLOCK_EXCEEDED") - && !stderr.contains("wall-clock limit") - && !stderr.contains("ERR_SCRIPT_CPU_BUDGET_EXCEEDED") - && !stderr.contains("CPU-time budget"), - "a wall-clock or CPU limit fired despite this idle await staying below the default CPU budget: \ - exit_code={exit_code} stdout={stdout} stderr={stderr}" - ); - assert_eq!( - exit_code, 0, - "awaiting guest should complete cleanly when no wall-clock limit is set: \ - stdout={stdout} stderr={stderr}" - ); - assert!( - stdout.contains("no-limit-ok"), - "guest did not run to completion with no wall-clock limit set: \ - stdout={stdout} stderr={stderr}" - ); - } - Err(_) => { - panic!( - "no-limit guest never produced a result within the bounded test window \ - (unexpected hang)" - ); - } - } -} - -// SE-EXEC-06 (M.1 / F-003): a heap-allocation bomb must be capped by terminating -// the offending isolate, NOT by letting V8 fatal-abort (SIGTRAP) the process-global -// runtime and take down every concurrent tenant. Before the fix, no -// near-heap-limit/OOM callback was registered, so reaching the operator-configured -// `AGENTOS_V8_HEAP_LIMIT_MB` cap triggered V8's default fatal-OOM abort. -// -// BOUNDED safeguard variant: with a small heap cap the guard fires fast, terminates -// the isolate, and the run returns a nonzero exit WITHOUT aborting the process. The -// guest run is fenced behind a wall-clock watchdog on a worker thread so a regression -// surfaces as a clear failure rather than a CI hang or a SIGTRAP that kills the whole -// test binary. -fn javascript_heap_allocation_bomb_is_capped_by_oom_guard() { - let (tx, rx) = mpsc::channel::<(i32, String, String)>(); - thread::spawn(move || { - let temp = match tempdir() { - Ok(temp) => temp, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("tempdir failed: {error}"))); - return; - } - }; - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine.start_execution(StartJavascriptExecutionRequest { - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - // Small bounded heap cap so the OOM guard fires quickly. The cap now - // rides the typed `limits` field (migrated off the dead - // `AGENTOS_V8_HEAP_LIMIT_MB` env knob). - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from( - r#" -// Grow unbounded; with a 32MB heap cap the OOM guard must terminate the isolate -// well before this completes. If it ever completes, the cap did not bound it. -const sink = []; -for (let i = 0; i < 1_000_000; i += 1) { - sink.push(new Array(100_000).fill(i)); -} -console.log("BOMB_COMPLETED_WITHOUT_CAP"); -"#, - )), - limits: JavascriptExecutionLimits { - v8_heap_limit_mb: Some(32), - ..Default::default() - }, - guest_runtime: Default::default(), - }); - - match execution { - Ok(execution) => match execution.wait() { - Ok(result) => { - let stdout = String::from_utf8_lossy(&result.stdout).into_owned(); - let stderr = String::from_utf8_lossy(&result.stderr).into_owned(); - let _ = tx.send((result.exit_code, stdout, stderr)); - } - Err(error) => { - let _ = tx.send((-1, String::new(), format!("wait failed: {error}"))); - } - }, - Err(error) => { - let _ = tx.send((-1, String::new(), format!("start failed: {error}"))); - } - } - }); - - match rx.recv_timeout(Duration::from_secs(30)) { - Ok((exit_code, stdout, stderr)) => { - // The bad actor wins if the bomb runs to completion. - assert!( - !stdout.contains("BOMB_COMPLETED_WITHOUT_CAP"), - "heap bomb completed despite configured heap limit: stdout={stdout} stderr={stderr}" - ); - // Enforcement must be a clean per-isolate termination (nonzero exit), - // not a process-wide abort. - assert_ne!( - exit_code, 0, - "heap bomb returned a clean exit instead of being terminated by the OOM guard: stdout={stdout} stderr={stderr}" - ); - } - Err(_) => { - panic!( - "heap-bomb guest was NOT bounded by the OOM guard \ - (wait() never returned within the bounded test budget)" - ); - } - } -} - -// Adversarial coverage for the builtin allow/deny desync (VECTORS.md A.2). -// A denied builtin must stay denied on EVERY guest resolution path. The most -// likely desync is a sub-path specifier (`dns/promises`) leaking on one path -// while its root (`dns`) is denied on another. The live guest-JS path is the -// shared V8 runtime, whose single `loadBuiltinModule` funnel gates by root -// name (`split('/')[0]`) for require / createRequire / process.getBuiltinModule -// / dynamic import alike. With an allow-list that excludes `dns`, every path -// must reject both `dns` and `dns/promises`. -fn javascript_execution_denies_dns_and_subpaths_on_every_resolution_path() { - assert_js_runtime_guest_ok( - // node platform, allow-list excludes `dns` (only `path`/`module`). - js_runtime_env(&[("AGENTOS_JS_BUILTIN_ALLOWLIST", "[\"path\",\"module\"]")]), - r#" - import { createRequire } from "node:module"; - const require = createRequire(import.meta.url); - - function assertDeniedSync(label, fn) { - let denied = false; - let detail = "no error"; - try { - const mod = fn(); - const keys = mod && typeof mod === "object" ? Object.keys(mod).slice(0, 4).join(",") : typeof mod; - detail = "resolved to " + keys; - } catch (error) { - detail = String(error && error.message); - denied = !!error; - } - if (!denied) throw new Error(label + " was not denied: " + detail); - } - - async function assertDeniedAsync(label, promise) { - let denied = false; - let detail = "no error"; - try { await promise; detail = "import resolved"; } - catch (error) { detail = String(error && error.message); denied = !!error; } - if (!denied) throw new Error(label + " was not denied: " + detail); - } - - // Positive control: an allowed builtin still resolves. - const path = await import("node:path"); - if (typeof path.join !== "function") throw new Error("node:path should be allowed"); - - for (const specifier of ["dns", "node:dns", "dns/promises", "node:dns/promises"]) { - assertDeniedSync("require(" + specifier + ")", () => require(specifier)); - assertDeniedSync( - "createRequire(" + specifier + ")", - () => createRequire(import.meta.url)(specifier), - ); - if (typeof process.getBuiltinModule === "function") { - assertDeniedSync( - "process.getBuiltinModule(" + specifier + ")", - () => process.getBuiltinModule(specifier), - ); - } - await assertDeniedAsync("import(" + specifier + ")", import(specifier)); - } - "#, - ); -} - -#[test] -fn javascript_v8_suite() { - // Keep V8-backed integration coverage inside one top-level libtest case. - // Running these guest-runtime cases as separate tests in the same binary - // still trips a V8 teardown/init boundary crash between cases. - // - // Warm-worker pooling stays OFF here: this harness services guest sync - // RPCs inline on the test thread, and a claimed (pre-created) session - // shifts kernel-stdin RPC timing so the harness sees a pending request - // at wait() (PendingSyncRpcRequest). Production routes these through the - // sidecar service loop and is unaffected (verified: stdin round-trips - // 5/5 through pooled sessions in a live VM). - let _no_warm_workers = EnvVarGuard::set_value("AGENTOS_V8_WARM_ISOLATES", "0"); - javascript_contexts_preserve_vm_and_bootstrap_configuration(); - javascript_execution_virtual_os_identity_comes_from_guest_runtime_not_env(); - javascript_execution_uses_v8_runtime_without_spawning_guest_node_binary(); - javascript_execution_virtualizes_process_metadata_for_inline_v8_code(); - javascript_execution_process_kill_rejects_invalid_pid_in_guest_js(); - javascript_execution_preserves_binary_process_stdio_writes(); - javascript_execution_intl_number_format_does_not_require_host_icu(); - javascript_execution_to_locale_date_string_does_not_crash_embedded_v8(); - // QUARANTINED (2026-07-02, pre-existing on trunk 5367209b — verified by - // bisect): stream-consumers live-stdin fails with PendingSyncRpcRequest in - // THIS harness, which services guest sync RPCs inline on the test thread; - // production stdin round-trips verified 5/5 through the real sidecar. - // Tracked in the perf-backlog spec (0.5 burn-down) — re-enable when the - // harness services pending stdin RPCs during wait(). - // javascript_execution_stream_consumers_text_reads_live_stdin(); - // QUARANTINED with the live-stdin class above (same harness limitation). - // javascript_execution_process_stdin_async_iterator_finishes_with_live_stdin(); - // QUARANTINED with the live-stdin class above (same harness limitation). - // javascript_execution_process_exit_from_live_stdin_listener_exits_without_waiting_for_eof(); - javascript_execution_process_exit_ignores_live_interval_handles(); - javascript_execution_process_exit_bypasses_promise_catch_handlers(); - // QUARANTINED with the live-stdin class above (same harness limitation). - // javascript_execution_live_stdin_replays_end_after_late_listener_registration(); - javascript_execution_file_url_to_path_accepts_guest_absolute_paths(); - javascript_execution_imports_node_events_without_hanging(); - javascript_execution_imports_node_process_without_hanging(); - javascript_execution_imports_node_fs_promises_without_hanging(); - javascript_execution_imports_node_perf_hooks_without_hanging(); - javascript_execution_high_resolution_time_opt_in_enables_sub_ms_hrtime(); - javascript_execution_high_resolution_time_default_off_keeps_coarse_clock(); - javascript_execution_exposes_compatibility_shims_and_denies_escape_builtins(); - javascript_execution_denies_dns_and_subpaths_on_every_resolution_path(); - javascript_execution_v8_util_format_with_options_matches_node(); - javascript_execution_provides_async_hooks_and_diagnostics_channel_stubs(); - javascript_execution_supports_require_resolve_for_guest_code(); - javascript_execution_rejects_native_node_addons(); - javascript_execution_surfaces_sync_rpc_requests_from_v8_modules(); - javascript_execution_v8_dgram_bridge_matches_sidecar_rpc_shapes(); - javascript_execution_strips_hashbang_from_module_entrypoints(); - javascript_execution_resolves_pnpm_store_dependencies_from_symlinked_entrypoints(); - javascript_execution_resolves_dependencies_from_package_specific_symlink_mounts(); - javascript_execution_v8_timer_callbacks_fire_and_clear_correctly(); - javascript_execution_v8_readline_polyfill_emits_lines(); - javascript_execution_v8_builtin_wrappers_expose_common_named_exports(); - javascript_execution_v8_child_process_conformance_matches_host_node(); - javascript_execution_v8_web_stream_globals_support_basic_io(); - javascript_execution_v8_text_codec_streams_support_pipe_through(); - javascript_execution_v8_abort_controller_dispatches_abort(); - javascript_execution_v8_request_accepts_abort_signal(); - javascript_execution_v8_abort_signal_static_helpers_work(); - javascript_execution_v8_schedule_timer_bridge_resolves(); - javascript_execution_v8_kernel_poll_bridge_requests_multiple_fds(); - javascript_execution_v8_crypto_random_sources_use_local_secure_bridge(); - javascript_execution_v8_crypto_basic_operations_emit_expected_sync_rpcs(); - javascript_execution_v8_load_polyfill_returns_runtime_module_expressions(); - javascript_execution_v8_stream_wrapper_exports_common_node_classes(); - javascript_execution_v8_buffer_wrapper_exposes_commonjs_constants(); - // QUARANTINED with the live-stdin class (standalone harness services only - // module-resolution RPCs; tty RPCs are kernel-backed). - // javascript_execution_v8_tty_module_is_backed_by_live_process(); - javascript_execution_v8_sqlite_module_resolves_via_global_install(); - javascript_execution_v8_commonjs_stack_frames_preserve_module_paths(); - javascript_execution_v8_commonjs_main_entrypoints_preserve_entrypoint_paths(); - javascript_execution_v8_inline_commonjs_entrypoints_preserve_entrypoint_paths(); - javascript_execution_v8_inline_commonjs_entrypoints_preserve_commonjs_globals(); - javascript_execution_v8_commonjs_require_exposes_node_metadata(); - javascript_execution_v8_https_agents_expose_options_objects(); - javascript_execution_v8_net_socket_readable_state_tracks_ssh2_writable_shape(); - javascript_execution_v8_event_channel_backpressures_instead_of_destroying_session(); - javascript_execution_v8_net_socket_read_loop_yields_macrotask_between_chunks(); - javascript_execution_v8_dynamic_import_accepts_file_urls(); - javascript_execution_v8_wasm_instantiate_streaming_never_hangs(); - javascript_execution_v8_structured_clone_rebinds_to_sandbox_realm(); - js_runtime_node_platform_keeps_full_node_surface(); - js_runtime_bare_platform_strips_all_host_globals(); - js_runtime_browser_platform_exposes_web_without_node(); - js_runtime_neutral_platform_drops_web_keeps_universal(); - js_runtime_module_resolution_none_denies_all_imports(); - js_runtime_module_resolution_relative_allows_local_denies_bare(); - js_runtime_node_platform_allow_list_restricts_builtins(); - js_runtime_browser_loads_cjs_npm_package(); - js_runtime_browser_fetch_is_callable(); - - // SE-EXEC-06 (F-003): OOM guard terminates a heap-allocation bomb instead of - // letting V8 fatal-abort the process. Runs before the CPU case; both are fenced - // behind worker-thread wall-clock watchdogs. - javascript_heap_allocation_bomb_is_capped_by_oom_guard(); - - // SE-EXEC-04 (F-001): TRUE CPU-time budget. These run LAST because a - // regression in the tight-loop case could leak a CPU-bound worker thread. - // 1. budget SET => tight busy loop terminated (cpu-budget reason) - // 2. budget SET => awaiting/idle guest NOT killed (idle excluded) [critical negative] - // 3. budget UNSET => default watchdog allows short CPU work - javascript_infinite_loop_is_terminated_by_cpu_watchdog(); - javascript_awaiting_guest_is_not_killed_by_cpu_budget(); - javascript_default_cpu_budget_allows_short_cpu_work(); - - // WALL-CLOCK BACKSTOP (opt-in, complements the CPU-time budget): - // 1. wall-clock SET => awaiting guest terminated (wall-clock reason; idle counted) - // 2. CPU budget only => no wall-clock limit imposed (knobs independent) - // 3. wall-clock unset => idle await completes; default CPU budget excludes idle - javascript_awaiting_guest_is_terminated_by_wall_clock_backstop(); - javascript_cpu_budget_only_does_not_impose_wall_clock_limit(); - javascript_no_time_limit_when_neither_env_set(); -} diff --git a/crates/execution/tests/module_resolution.rs b/crates/execution/tests/module_resolution.rs deleted file mode 100644 index 7b6d2d9ce..000000000 --- a/crates/execution/tests/module_resolution.rs +++ /dev/null @@ -1,947 +0,0 @@ -use secure_exec_execution::javascript::ModuleResolutionTestHarness; -use serde::Deserialize; -use serde_json::Value; -use std::fs; -use std::os::unix::fs::symlink; -use std::path::PathBuf; -use tempfile::TempDir; - -struct Fixture { - temp: TempDir, -} - -impl Fixture { - fn new() -> Self { - Self { - temp: TempDir::new().expect("create temp dir"), - } - } - - fn host_path(&self, relative: &str) -> PathBuf { - self.temp.path().join(relative) - } - - fn write(&self, relative: &str, contents: &str) { - let path = self.host_path(relative); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).expect("create parent dirs"); - } - fs::write(path, contents).expect("write fixture file"); - } - - fn write_json(&self, relative: &str, value: Value) { - self.write( - relative, - &serde_json::to_string_pretty(&value).expect("serialize json"), - ); - } - - fn mkdir(&self, relative: &str) { - fs::create_dir_all(self.host_path(relative)).expect("create fixture dir"); - } - - fn symlink_dir(&self, target_relative: &str, link_relative: &str) { - let target = self.host_path(target_relative); - let link = self.host_path(link_relative); - if let Some(parent) = link.parent() { - fs::create_dir_all(parent).expect("create symlink parent"); - } - symlink(target, link).expect("create directory symlink"); - } - - fn resolver(&self) -> ModuleResolutionTestHarness { - ModuleResolutionTestHarness::new(self.temp.path()) - } -} - -fn assert_import(fixture: &Fixture, specifier: &str, from_path: &str, expected: &str) { - let mut resolver = fixture.resolver(); - assert_eq!( - resolver.resolve_import(specifier, from_path), - Some(String::from(expected)) - ); -} - -fn assert_require(fixture: &Fixture, specifier: &str, from_path: &str, expected: &str) { - let mut resolver = fixture.resolver(); - assert_eq!( - resolver.resolve_require(specifier, from_path), - Some(String::from(expected)) - ); -} - -fn assert_require_missing(fixture: &Fixture, specifier: &str, from_path: &str) { - let mut resolver = fixture.resolver(); - assert_eq!(resolver.resolve_require(specifier, from_path), None); -} - -#[derive(Debug, Deserialize)] -struct SharedModuleResolutionFixture { - cases: Vec, - formats: Vec, -} - -#[derive(Debug, Deserialize)] -struct SharedModuleResolutionCase { - name: String, - files: std::collections::BTreeMap, - resolves: Vec, -} - -#[derive(Debug, Deserialize)] -struct SharedModuleResolutionExpectation { - specifier: String, - from: String, - mode: String, - expected: Option, -} - -#[derive(Debug, Deserialize)] -struct SharedModuleFormatCase { - name: String, - files: std::collections::BTreeMap, - path: String, - expected: Option, -} - -#[test] -fn matches_shared_native_browser_conformance_fixture() { - let fixture: SharedModuleResolutionFixture = serde_json::from_str(include_str!( - "../../../tests/fixtures/module-resolution-conformance.json" - )) - .expect("parse shared module resolution fixture"); - - for test_case in fixture.cases { - let fs_fixture = Fixture::new(); - for (path, contents) in &test_case.files { - fs_fixture.write(path, contents); - } - - for resolution in &test_case.resolves { - let mut resolver = fs_fixture.resolver(); - let actual = match resolution.mode.as_str() { - "import" => resolver.resolve_import(&resolution.specifier, &resolution.from), - "require" => resolver.resolve_require(&resolution.specifier, &resolution.from), - other => panic!("unsupported shared fixture mode {other}"), - }; - assert_eq!( - actual, resolution.expected, - "{}: {} from {} in {} mode", - test_case.name, resolution.specifier, resolution.from, resolution.mode - ); - } - } - - for format_case in fixture.formats { - let fs_fixture = Fixture::new(); - for (path, contents) in &format_case.files { - fs_fixture.write(path, contents); - } - - let mut resolver = fs_fixture.resolver(); - let actual = resolver.module_format(&format_case.path).map(String::from); - assert_eq!( - actual, format_case.expected, - "{}: format for {}", - format_case.name, format_case.path - ); - } -} - -#[test] -fn builtin_bare_fs_normalizes_to_node_prefix() { - let fixture = Fixture::new(); - assert_import(&fixture, "fs", "/root/project/index.js", "node:fs"); -} - -#[test] -fn builtin_node_prefix_is_preserved_for_require() { - let fixture = Fixture::new(); - assert_require(&fixture, "node:path", "/root/project/index.js", "node:path"); -} - -#[test] -fn builtin_subpath_normalizes_to_node_prefix() { - let fixture = Fixture::new(); - assert_import( - &fixture, - "fs/promises", - "/root/project/index.js", - "node:fs/promises", - ); -} - -#[test] -fn relative_import_probes_js_extension() { - let fixture = Fixture::new(); - fixture.write("project/src/foo.js", "export default 1;"); - assert_import( - &fixture, - "./foo", - "/root/project/src/index.js", - "/root/project/src/foo.js", - ); -} - -#[test] -fn relative_parent_import_probes_json_extension() { - let fixture = Fixture::new(); - fixture.write("project/data/config.json", r#"{"ok":true}"#); - assert_import( - &fixture, - "../data/config", - "/root/project/src/index.js", - "/root/project/data/config.json", - ); -} - -#[test] -fn absolute_import_resolves_from_guest_root() { - let fixture = Fixture::new(); - fixture.write("shared/util.mjs", "export const ok = true;"); - assert_import( - &fixture, - "/root/shared/util", - "/root/project/src/index.js", - "/root/shared/util.mjs", - ); -} - -#[test] -fn directory_import_uses_package_main_field() { - let fixture = Fixture::new(); - fixture.write_json( - "project/pkg/package.json", - serde_json::json!({ "main": "./dist/main.cjs" }), - ); - fixture.write("project/pkg/dist/main.cjs", "module.exports = 1;"); - assert_require( - &fixture, - "./pkg", - "/root/project/index.js", - "/root/project/pkg/dist/main.cjs", - ); -} - -#[test] -fn bare_package_main_only_type_module_resolves() { - // Regression guard: a bare ESM package whose package.json has `main` but NO - // `exports` map (e.g. @agentclientprotocol/sdk@0.16.1) must still resolve via - // the `main` fallback. `exports` and `main` are separate code paths; this case - // exercises the latter for a scoped package looked up through node_modules. - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/@scope/pkg/package.json", - serde_json::json!({ "type": "module", "main": "dist/acp.js" }), - ); - fixture.write("node_modules/@scope/pkg/dist/acp.js", "export default 1;"); - assert_import( - &fixture, - "@scope/pkg", - "/root/project/src/adapter.js", - "/root/node_modules/@scope/pkg/dist/acp.js", - ); -} - -#[test] -fn directory_import_falls_back_to_index_file() { - let fixture = Fixture::new(); - fixture.write("project/lib/index.cjs", "module.exports = 1;"); - assert_require( - &fixture, - "./lib", - "/root/project/index.js", - "/root/project/lib/index.cjs", - ); -} - -#[test] -fn extension_probe_finds_existing_js_file_directly() { - let fixture = Fixture::new(); - fixture.write("project/src/direct.js", "export default 1;"); - assert_import( - &fixture, - "./direct.js", - "/root/project/src/index.js", - "/root/project/src/direct.js", - ); -} - -#[test] -fn extension_probe_finds_mjs_file() { - let fixture = Fixture::new(); - fixture.write("project/src/mod.mjs", "export default 1;"); - assert_import( - &fixture, - "./mod", - "/root/project/src/index.js", - "/root/project/src/mod.mjs", - ); -} - -#[test] -fn extension_probe_finds_cjs_file() { - let fixture = Fixture::new(); - fixture.write("project/src/common.cjs", "module.exports = 1;"); - assert_require( - &fixture, - "./common", - "/root/project/src/index.js", - "/root/project/src/common.cjs", - ); -} - -#[test] -fn extension_probe_finds_json_file() { - let fixture = Fixture::new(); - fixture.write("project/src/data.json", r#"{"name":"fixture"}"#); - assert_require( - &fixture, - "./data", - "/root/project/src/index.js", - "/root/project/src/data.json", - ); -} - -#[test] -fn dot_specifier_resolves_current_package_directory() { - let fixture = Fixture::new(); - fixture.write_json( - "project/pkg/package.json", - serde_json::json!({ "main": "./entry.js" }), - ); - fixture.write("project/pkg/entry.js", "module.exports = 1;"); - assert_require( - &fixture, - ".", - "/root/project/pkg/index.js", - "/root/project/pkg/entry.js", - ); -} - -#[test] -fn exports_string_shorthand_resolves_package_root() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - serde_json::json!({ "exports": "./dist/index.js" }), - ); - fixture.write("node_modules/pkg/dist/index.js", "export default 1;"); - assert_import( - &fixture, - "pkg", - "/root/project/src/index.js", - "/root/node_modules/pkg/dist/index.js", - ); -} - -#[test] -fn exports_conditions_prefer_import_for_esm_resolution() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - serde_json::json!({ - "exports": { - ".": { - "import": "./dist/import.mjs", - "require": "./dist/require.cjs", - "default": "./dist/default.js" - } - } - }), - ); - fixture.write("node_modules/pkg/dist/import.mjs", "export default 1;"); - fixture.write("node_modules/pkg/dist/require.cjs", "module.exports = 1;"); - fixture.write("node_modules/pkg/dist/default.js", "export default 1;"); - assert_import( - &fixture, - "pkg", - "/root/project/src/index.js", - "/root/node_modules/pkg/dist/import.mjs", - ); -} - -#[test] -fn exports_conditions_prefer_require_for_cjs_resolution() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - serde_json::json!({ - "exports": { - ".": { - "import": "./dist/import.mjs", - "require": "./dist/require.cjs", - "default": "./dist/default.js" - } - } - }), - ); - fixture.write("node_modules/pkg/dist/import.mjs", "export default 1;"); - fixture.write("node_modules/pkg/dist/require.cjs", "module.exports = 1;"); - fixture.write("node_modules/pkg/dist/default.js", "export default 1;"); - assert_require( - &fixture, - "pkg", - "/root/project/src/index.js", - "/root/node_modules/pkg/dist/require.cjs", - ); -} - -#[test] -fn exports_nested_conditions_recurse_for_import_mode() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - serde_json::json!({ - "exports": { - ".": { - "import": { - "node": "./dist/node.mjs", - "default": "./dist/default.mjs" - }, - "default": "./dist/fallback.js" - } - } - }), - ); - fixture.write("node_modules/pkg/dist/node.mjs", "export default 1;"); - fixture.write("node_modules/pkg/dist/default.mjs", "export default 1;"); - fixture.write("node_modules/pkg/dist/fallback.js", "export default 1;"); - assert_import( - &fixture, - "pkg", - "/root/project/src/index.js", - "/root/node_modules/pkg/dist/node.mjs", - ); -} - -#[test] -fn exports_wildcard_subpaths_expand_requested_segment() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - serde_json::json!({ - "exports": { - "./features/*": "./dist/features/*.mjs" - } - }), - ); - fixture.write( - "node_modules/pkg/dist/features/alpha.mjs", - "export default 1;", - ); - assert_import( - &fixture, - "pkg/features/alpha", - "/root/project/src/index.js", - "/root/node_modules/pkg/dist/features/alpha.mjs", - ); -} - -#[test] -fn exports_explicit_subpath_resolves_direct_mapping() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - serde_json::json!({ - "exports": { - "./feature": "./dist/feature.js" - } - }), - ); - fixture.write("node_modules/pkg/dist/feature.js", "export default 1;"); - assert_import( - &fixture, - "pkg/feature", - "/root/project/src/index.js", - "/root/node_modules/pkg/dist/feature.js", - ); -} - -#[test] -fn exports_array_fallback_uses_first_resolvable_target() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - serde_json::json!({ - "exports": [ - null, - "./dist/index.js" - ] - }), - ); - fixture.write("node_modules/pkg/dist/index.js", "export default 1;"); - assert_import( - &fixture, - "pkg", - "/root/project/src/index.js", - "/root/node_modules/pkg/dist/index.js", - ); -} - -#[test] -fn imports_exact_alias_resolves_relative_target() { - let fixture = Fixture::new(); - fixture.write_json( - "project/package.json", - serde_json::json!({ - "imports": { - "#alias": "./src/alias.js" - } - }), - ); - fixture.write("project/src/alias.js", "export default 1;"); - assert_import( - &fixture, - "#alias", - "/root/project/src/index.js", - "/root/project/src/alias.js", - ); -} - -#[test] -fn imports_condition_object_supports_require_mode() { - let fixture = Fixture::new(); - fixture.write_json( - "project/package.json", - serde_json::json!({ - "imports": { - "#config": { - "import": "./src/config.mjs", - "require": "./src/config.cjs" - } - } - }), - ); - fixture.write("project/src/config.mjs", "export default 1;"); - fixture.write("project/src/config.cjs", "module.exports = 1;"); - assert_require( - &fixture, - "#config", - "/root/project/src/index.js", - "/root/project/src/config.cjs", - ); -} - -#[test] -fn imports_wildcard_subpaths_expand_requested_segment() { - let fixture = Fixture::new(); - fixture.write_json( - "project/package.json", - serde_json::json!({ - "imports": { - "#utils/*": "./src/utils/*.js" - } - }), - ); - fixture.write("project/src/utils/math.js", "export default 1;"); - assert_import( - &fixture, - "#utils/math", - "/root/project/src/index.js", - "/root/project/src/utils/math.js", - ); -} - -#[test] -fn imports_walk_up_to_nearest_package_json() { - let fixture = Fixture::new(); - fixture.write_json( - "project/package.json", - serde_json::json!({ - "imports": { - "#shared": "./src/shared.js" - } - }), - ); - fixture.write("project/src/shared.js", "export default 1;"); - assert_import( - &fixture, - "#shared", - "/root/project/src/nested/deeper/index.js", - "/root/project/src/shared.js", - ); -} - -#[test] -fn exports_take_priority_over_main_field() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - serde_json::json!({ - "main": "./legacy.js", - "exports": "./modern.js" - }), - ); - fixture.write("node_modules/pkg/legacy.js", "module.exports = 1;"); - fixture.write("node_modules/pkg/modern.js", "export default 1;"); - assert_import( - &fixture, - "pkg", - "/root/project/src/index.js", - "/root/node_modules/pkg/modern.js", - ); -} - -#[test] -fn type_module_directory_import_uses_index_js_for_import_mode() { - let fixture = Fixture::new(); - fixture.write_json( - "project/esm-dir/package.json", - serde_json::json!({ - "type": "module" - }), - ); - fixture.write("project/esm-dir/index.js", "export default 1;"); - assert_import( - &fixture, - "./esm-dir", - "/root/project/index.js", - "/root/project/esm-dir/index.js", - ); -} - -#[test] -fn main_field_still_beats_nonstandard_module_field() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/pkg/package.json", - serde_json::json!({ - "main": "./main.cjs", - "module": "./module.mjs" - }), - ); - fixture.write("node_modules/pkg/main.cjs", "module.exports = 1;"); - fixture.write("node_modules/pkg/module.mjs", "export default 1;"); - assert_require( - &fixture, - "pkg", - "/root/project/src/index.js", - "/root/node_modules/pkg/main.cjs", - ); -} - -#[test] -fn pnpm_store_dir_is_not_checked_without_flattened_package_symlink() { - let fixture = Fixture::new(); - fixture.write_json( - "project/node_modules/.pnpm/node_modules/pkg/package.json", - serde_json::json!({ "main": "./index.js" }), - ); - fixture.write( - "project/node_modules/.pnpm/node_modules/pkg/index.js", - "module.exports = 1;", - ); - assert_require_missing(&fixture, "pkg", "/root/project/src/index.js"); -} - -#[test] -fn symlinked_package_escape_is_not_resolved() { - let fixture = Fixture::new(); - let outside = TempDir::new().expect("create outside temp dir"); - fs::write( - outside.path().join("secret.js"), - "module.exports = 'secret';", - ) - .expect("write outside file"); - fixture.mkdir("node_modules"); - symlink(outside.path(), fixture.host_path("node_modules/escape")) - .expect("create escape symlink"); - - let mut resolver = fixture.resolver(); - assert_eq!( - resolver.resolve_require("escape/secret", "/root/project/index.js"), - None - ); -} - -#[test] -fn absolute_host_path_fallback_is_not_resolved() { - let fixture = Fixture::new(); - let outside = TempDir::new().expect("create outside temp dir"); - let outside_module = outside.path().join("secret.js"); - fs::write(&outside_module, "module.exports = 'secret';").expect("write outside file"); - - let mut resolver = fixture.resolver(); - assert_eq!( - resolver.resolve_require( - outside_module.to_string_lossy().as_ref(), - "/root/project/index.js", - ), - None - ); -} - -#[test] -fn pnpm_symlinked_referrer_can_resolve_sibling_dependency() { - let fixture = Fixture::new(); - fixture.write( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/pkg-a/index.js", - "module.exports = require('pkg-b');", - ); - fixture.write_json( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/pkg-a/package.json", - serde_json::json!({ "main": "./index.js" }), - ); - fixture.write( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/pkg-b/index.js", - "module.exports = 1;", - ); - fixture.write_json( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/pkg-b/package.json", - serde_json::json!({ "main": "./index.js" }), - ); - fixture.symlink_dir( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/pkg-a", - "node_modules/pkg-a", - ); - - assert_require( - &fixture, - "pkg-b", - "/root/node_modules/pkg-a/index.js", - "/root/node_modules/.pnpm/pkg-a@1.0.0/node_modules/pkg-b/index.js", - ); -} - -#[test] -fn pnpm_symlinked_referrer_prefers_package_store_dependency_over_generic_hoist() { - let fixture = Fixture::new(); - fixture.write_json( - "node_modules/.pnpm/node_modules/dep/package.json", - serde_json::json!({ "main": "./index.js" }), - ); - fixture.write( - "node_modules/.pnpm/node_modules/dep/index.js", - "module.exports = 'generic';", - ); - fixture.write( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/pkg-a/index.js", - "import { named } from 'dep';\nexport default named;\n", - ); - fixture.write_json( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/pkg-a/package.json", - serde_json::json!({ "type": "module" }), - ); - fixture.write( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/dep/index.js", - "export const named = 1;", - ); - fixture.write_json( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/dep/package.json", - serde_json::json!({ - "type": "module", - "exports": "./index.js", - }), - ); - fixture.symlink_dir( - "node_modules/.pnpm/pkg-a@1.0.0/node_modules/pkg-a", - "node_modules/pkg-a", - ); - - assert_import( - &fixture, - "dep", - "/root/node_modules/pkg-a/index.js", - "/root/node_modules/.pnpm/pkg-a@1.0.0/node_modules/dep/index.js", - ); -} - -#[test] -fn root_node_modules_fallback_is_checked_last() { - let fixture = Fixture::new(); - fixture.mkdir("project/src"); - fixture.write_json( - "node_modules/shared-pkg/package.json", - serde_json::json!({ "main": "./index.js" }), - ); - fixture.write("node_modules/shared-pkg/index.js", "module.exports = 1;"); - assert_require( - &fixture, - "shared-pkg", - "/root/project/src/index.js", - "/root/node_modules/shared-pkg/index.js", - ); -} - -// Reproduces the ~/r6 conflict: minimatch@10 (ESM) imports `brace-expansion`. -// Its OWN nested node_modules has the compatible brace-expansion@5 (named ESM -// `expand`), while a hoisted top-level brace-expansion@1 (CJS, no named export) -// exists too. Real Node resolves the nested @5; the VM must do the same. -#[test] -fn nested_dep_wins_over_hoisted_incompatible_version() { - let fixture = Fixture::new(); - - // minimatch@10: ESM package whose esm entry imports brace-expansion. - fixture.write_json( - "node_modules/minimatch/package.json", - serde_json::json!({ - "version": "10.2.5", - "type": "module", - "main": "./dist/commonjs/index.js", - "module": "./dist/esm/index.js", - "exports": { - ".": { - "import": "./dist/esm/index.js", - "require": "./dist/commonjs/index.js" - } - } - }), - ); - fixture.write( - "node_modules/minimatch/dist/esm/index.js", - "import { expand } from 'brace-expansion';\nexport const minimatch = () => {};", - ); - - // minimatch's OWN nested brace-expansion@5 (compatible, real ESM). - fixture.write_json( - "node_modules/minimatch/node_modules/brace-expansion/package.json", - serde_json::json!({ - "version": "5.0.5", - "type": "module", - "main": "./dist/commonjs/index.js", - "module": "./dist/esm/index.js", - "exports": { - ".": { - "import": "./dist/esm/index.js", - "require": "./dist/commonjs/index.js" - } - } - }), - ); - fixture.write( - "node_modules/minimatch/node_modules/brace-expansion/dist/esm/index.js", - "export function expand() {}", - ); - - // Hoisted top-level brace-expansion@1 (incompatible CJS). - fixture.write_json( - "node_modules/brace-expansion/package.json", - serde_json::json!({ "version": "1.1.12", "main": "index.js" }), - ); - fixture.write( - "node_modules/brace-expansion/index.js", - "module.exports = function () {};", - ); - - assert_import( - &fixture, - "brace-expansion", - "/root/node_modules/minimatch/dist/esm/index.js", - "/root/node_modules/minimatch/node_modules/brace-expansion/dist/esm/index.js", - ); -} - -// Regression for the pnpm virtual-store scan shadowing hoisted resolution: a -// consumer imports `dep`; the correct version is hoisted at the top level, but -// an alphabetically-earlier `.pnpm/@ver/node_modules/dep` holds an -// incompatible version. The standard ancestor walk (which finds the hoisted -// copy) must win over the store scan, matching real Node. Before the fix the -// scan ran while walking and returned the wrong store entry first. -#[test] -fn hoisted_dependency_wins_over_alphabetically_earlier_pnpm_store_entry() { - let fixture = Fixture::new(); - - // Consumer is hoisted at the top level (not under .pnpm). - fixture.write( - "node_modules/consumer/index.js", - "import { wanted } from 'dep';\nexport default wanted;", - ); - fixture.write_json( - "node_modules/consumer/package.json", - serde_json::json!({ "type": "module" }), - ); - - // Correct hoisted dep: real ESM with the named export. - fixture.write_json( - "node_modules/dep/package.json", - serde_json::json!({ - "type": "module", - "exports": { ".": { "import": "./index.mjs" } } - }), - ); - fixture.write("node_modules/dep/index.mjs", "export const wanted = 1;"); - - // Incompatible dep nested in the pnpm store under an alphabetically-earlier - // key (`aaa-pkg` sorts before any real consumer key). No named export. - fixture.write_json( - "node_modules/.pnpm/aaa-pkg@1.0.0/node_modules/dep/package.json", - serde_json::json!({ "version": "0.0.1", "main": "index.js" }), - ); - fixture.write( - "node_modules/.pnpm/aaa-pkg@1.0.0/node_modules/dep/index.js", - "module.exports = 1;", - ); - - assert_import( - &fixture, - "dep", - "/root/node_modules/consumer/index.js", - "/root/node_modules/dep/index.mjs", - ); -} - -// Faithful pnpm layout (what pnpm + real Node actually rely on): every package -// lives in its own `.pnpm/@/node_modules/` entry, and a -// consumer's dependency is a *symlink* sibling inside the consumer's store dir -// pointing at the dep's own entry. Top-level `node_modules/` is a symlink -// to the store entry. Resolution must work purely by realpath + the standard -// ancestor walk (Docker-style VFS), with NO `.pnpm` store scanning — and must -// pick the version the symlink points at, not an alphabetically-earlier entry. -#[test] -fn faithful_pnpm_symlink_layout_resolves_via_realpath_walk() { - let fixture = Fixture::new(); - - // consumer@1.0.0 in its store entry; imports `dep`. - fixture.write( - "node_modules/.pnpm/consumer@1.0.0/node_modules/consumer/index.mjs", - "import { wanted } from 'dep';\nexport default wanted;", - ); - fixture.write_json( - "node_modules/.pnpm/consumer@1.0.0/node_modules/consumer/package.json", - serde_json::json!({ "version": "1.0.0", "type": "module", "exports": { ".": "./index.mjs" } }), - ); - - // dep@2.0.0 — the correct version — in its own store entry. - fixture.write( - "node_modules/.pnpm/dep@2.0.0/node_modules/dep/index.mjs", - "export const wanted = 2;", - ); - fixture.write_json( - "node_modules/.pnpm/dep@2.0.0/node_modules/dep/package.json", - serde_json::json!({ "version": "2.0.0", "type": "module", "exports": { ".": "./index.mjs" } }), - ); - - // Decoy: an alphabetically-earlier store entry holding an incompatible dep@1. - fixture.write( - "node_modules/.pnpm/aaa-other@1.0.0/node_modules/dep/index.js", - "module.exports = 1;", - ); - fixture.write_json( - "node_modules/.pnpm/aaa-other@1.0.0/node_modules/dep/package.json", - serde_json::json!({ "version": "1.0.0", "main": "index.js" }), - ); - - // pnpm's sibling symlink: consumer's `dep` -> dep@2.0.0's store entry. - fixture.symlink_dir( - "node_modules/.pnpm/dep@2.0.0/node_modules/dep", - "node_modules/.pnpm/consumer@1.0.0/node_modules/dep", - ); - // Top-level symlink: node_modules/consumer -> consumer's store entry. - fixture.symlink_dir( - "node_modules/.pnpm/consumer@1.0.0/node_modules/consumer", - "node_modules/consumer", - ); - - // Importer is the top-level symlink path. The standard ancestor walk finds - // `dep` via pnpm's sibling symlink in consumer's store dir (which points at - // dep@2.0.0) — no `.pnpm` store scan involved. The resolver returns that - // symlink path; its realpath is dep@2.0.0's entry (the correct version, not - // the alphabetically-earlier aaa-other dep@1). - assert_import( - &fixture, - "dep", - "/root/node_modules/consumer/index.mjs", - "/root/node_modules/.pnpm/consumer@1.0.0/node_modules/dep/index.mjs", - ); -} diff --git a/crates/execution/tests/permission_flags.rs b/crates/execution/tests/permission_flags.rs deleted file mode 100644 index ab0a48579..000000000 --- a/crates/execution/tests/permission_flags.rs +++ /dev/null @@ -1,421 +0,0 @@ -#![cfg(unix)] - -use secure_exec_execution::{ - CreateJavascriptContextRequest, CreatePythonContextRequest, CreateWasmContextRequest, - JavascriptExecutionEngine, PythonExecutionEngine, PythonExecutionEvent, PythonExecutionLimits, - StartJavascriptExecutionRequest, StartPythonExecutionRequest, StartWasmExecutionRequest, - WasmExecutionEngine, WasmExecutionLimits, WasmPermissionTier, -}; -use serde_json::Value; -use std::collections::BTreeMap; -use std::fs; -use std::os::unix::fs::PermissionsExt; -use std::path::Path; -use std::time::Duration; -use tempfile::tempdir; - -struct EnvVarGuard { - key: &'static str, - previous: Option, -} - -impl EnvVarGuard { - fn set(key: &'static str, value: &Path) -> Self { - let previous = std::env::var(key).ok(); - // SAFETY: This test binary controls its own process environment and uses a - // single test to avoid concurrent environment mutation within the process. - unsafe { - std::env::set_var(key, value); - } - Self { key, previous } - } -} - -impl Drop for EnvVarGuard { - fn drop(&mut self) { - match &self.previous { - Some(value) => { - // SAFETY: See EnvVarGuard::set; restoring the test process env is - // limited to this single-threaded test scope. - unsafe { - std::env::set_var(self.key, value); - } - } - None => { - // SAFETY: See EnvVarGuard::set; restoring the test process env is - // limited to this single-threaded test scope. - unsafe { - std::env::remove_var(self.key); - } - } - } - } -} - -fn write_fake_node_binary(path: &Path, log_path: &Path) { - let script = format!( - "#!/bin/sh\nset -eu\nprintf 'host-node-invoked\\n' >> \"{}\"\nexit 1\n", - log_path.display(), - ); - fs::write(path, script).expect("write fake node binary"); - let mut permissions = fs::metadata(path) - .expect("fake node metadata") - .permissions(); - permissions.set_mode(0o755); - fs::set_permissions(path, permissions).expect("chmod fake node binary"); -} - -fn wasm_noop_module() -> Vec { - wat::parse_str( - r#" -(module - (memory (export "memory") 1) - (func (export "_start")) -) -"#, - ) - .expect("compile noop wasm fixture") -} - -fn node_permission_flags_allow_workers_for_internal_javascript_loader_runtime() { - let temp = tempdir().expect("create temp dir"); - let fake_node_path = temp.path().join("fake-node.sh"); - let log_path = temp.path().join("node-args.log"); - write_fake_node_binary(&fake_node_path, &log_path); - let _node_binary = EnvVarGuard::set("AGENTOS_NODE_BINARY", &fake_node_path); - - let js_cwd = temp.path().join("js-project"); - fs::create_dir_all(&js_cwd).expect("create js cwd"); - fs::write(js_cwd.join("entry.mjs"), "console.log('ignored');").expect("write js entry"); - - let mut js_engine = JavascriptExecutionEngine::default(); - let context = js_engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let default_result = js_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id.clone(), - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: js_cwd.clone(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start javascript execution without workers") - .wait() - .expect("wait for javascript execution without workers"); - assert_eq!(default_result.exit_code, 0); - - let worker_result = js_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from("[\"worker_threads\"]"), - )]), - cwd: js_cwd, - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start javascript execution with workers") - .wait() - .expect("wait for javascript execution with workers"); - assert_eq!(worker_result.exit_code, 0); - - assert!( - !log_path.exists(), - "javascript execution should stay inside the V8 runtime, not spawn the host node binary" - ); -} - -fn node_permission_flags_only_propagate_nested_child_capabilities_when_parent_explicitly_allows_them( -) { - let temp = tempdir().expect("create temp dir"); - let fake_node_path = temp.path().join("fake-node.sh"); - let log_path = temp.path().join("node-args.log"); - write_fake_node_binary(&fake_node_path, &log_path); - let _node_binary = EnvVarGuard::set("AGENTOS_NODE_BINARY", &fake_node_path); - - let js_cwd = temp.path().join("js-project"); - fs::create_dir_all(&js_cwd).expect("create js cwd"); - fs::write(js_cwd.join("entry.mjs"), "console.log('ignored');").expect("write js entry"); - - let mut js_engine = JavascriptExecutionEngine::default(); - let context = js_engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let nested_env = |allow_child_process: &str, allow_worker: &str| { - BTreeMap::from([ - ( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from("[\"child_process\",\"worker_threads\"]"), - ), - ( - String::from("AGENTOS_PARENT_NODE_ALLOW_CHILD_PROCESS"), - allow_child_process.to_owned(), - ), - ( - String::from("AGENTOS_PARENT_NODE_ALLOW_WORKER"), - allow_worker.to_owned(), - ), - ]) - }; - - let denied_result = js_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id.clone(), - argv: vec![String::from("./entry.mjs")], - env: nested_env("0", "0"), - cwd: js_cwd.clone(), - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start nested javascript execution without inherited permissions") - .wait() - .expect("wait for nested javascript execution without inherited permissions"); - assert_eq!(denied_result.exit_code, 0); - - let allowed_result = js_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: nested_env("1", "1"), - cwd: js_cwd, - wasm_module_bytes: None, - inline_code: None, - }) - .expect("start nested javascript execution with inherited permissions") - .wait() - .expect("wait for nested javascript execution with inherited permissions"); - assert_eq!(allowed_result.exit_code, 0); - - assert!( - !log_path.exists(), - "nested javascript execution should stay inside the V8 runtime regardless of inherited node flags" - ); -} - -fn python_execution_applies_configured_heap_limit_to_v8_runtime() { - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide-dist"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dist dir"); - fs::write( - pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide() { - const v8 = await import("node:v8"); - const heapLimit = v8.getHeapStatistics().heap_size_limit; - return { - setStdin(_stdin) {}, - async runPythonAsync() { - console.log(String(heapLimit)); - }, - }; -} -"#, - ) - .expect("write pyodide fixture"); - fs::write(pyodide_dir.join("pyodide-lock.json"), "{\"packages\":[]}\n") - .expect("write pyodide lock fixture"); - for asset in ["pyodide.asm.js", "pyodide.asm.wasm", "python_stdlib.zip"] { - fs::write(pyodide_dir.join(asset), []).expect("write pyodide runtime fixture"); - } - - let mut python_engine = PythonExecutionEngine::default(); - let context = python_engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let mut execution = python_engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - limits: PythonExecutionLimits { - max_old_space_mb: Some(64), - ..Default::default() - }, - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('heap limit')"), - file_path: None, - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - }) - .expect("start python execution"); - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - - while exit_code.is_none() { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll python event") - { - Some(PythonExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(PythonExecutionEvent::Stderr(chunk)) => stderr.extend(chunk), - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - // Module-resolution sync RPCs surface during startup; service - // them host-directly, then expect the pyodide cache mkdir. - if execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC") - { - continue; - } - let cache_path = request.args.first().and_then(Value::as_str); - assert_eq!(request.method, "fs.mkdirSync"); - assert!( - cache_path.is_some_and(|path| path.ends_with("pyodide-package-cache")), - "unexpected JS sync RPC request: {request:?}" - ); - execution - .respond_javascript_sync_rpc_success(request.id, Value::Null) - .expect("acknowledge pyodide cache mkdir"); - } - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - panic!("unexpected Python VFS RPC request: {request:?}"); - } - Some(PythonExecutionEvent::Exited(code)) => exit_code = Some(code), - None => panic!("timed out waiting for Python execution"), - } - } - - let stderr = String::from_utf8(stderr).expect("stderr utf8"); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let heap_limit = String::from_utf8(stdout) - .expect("stdout utf8") - .trim() - .parse::() - .expect("parse heap limit"); - assert!( - (16 * 1024 * 1024..256 * 1024 * 1024).contains(&heap_limit), - "expected configured Python heap limit to shape the V8 isolate, got {heap_limit} bytes", - ); -} - -fn wasm_execution_applies_runtime_memory_and_fuel_limits_inside_v8_runtime() { - let temp = tempdir().expect("create temp dir"); - let fake_node_path = temp.path().join("fake-node.sh"); - let log_path = temp.path().join("node-args.log"); - write_fake_node_binary(&fake_node_path, &log_path); - let _node_binary = EnvVarGuard::set("AGENTOS_NODE_BINARY", &fake_node_path); - - let wasm_cwd = temp.path().join("wasm-project"); - fs::create_dir_all(&wasm_cwd).expect("create wasm cwd"); - fs::write(wasm_cwd.join("guest.wasm"), wasm_noop_module()).expect("write wasm module"); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let result = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: WasmExecutionLimits { - max_fuel: Some(250_000), - max_memory_bytes: Some(131_072), - ..Default::default() - }, - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: vec![String::from("./guest.wasm")], - env: BTreeMap::new(), - cwd: wasm_cwd, - permission_tier: WasmPermissionTier::Full, - }) - .expect("start wasm execution") - .wait() - .expect("wait for wasm execution"); - assert_eq!(result.exit_code, 0); - assert!( - !log_path.exists(), - "wasm execution should apply runtime limits inside the shared V8 runtime, not launch the host node binary" - ); -} - -fn wasm_permission_tiers_do_not_fall_back_to_host_node_binary() { - let temp = tempdir().expect("create temp dir"); - let fake_node_path = temp.path().join("fake-node.sh"); - let log_path = temp.path().join("node-args.log"); - write_fake_node_binary(&fake_node_path, &log_path); - let _node_binary = EnvVarGuard::set("AGENTOS_NODE_BINARY", &fake_node_path); - - let mut engine = WasmExecutionEngine::default(); - let tiers = [ - WasmPermissionTier::Isolated, - WasmPermissionTier::ReadOnly, - WasmPermissionTier::ReadWrite, - WasmPermissionTier::Full, - ]; - - for tier in tiers { - let tier_name = match tier { - WasmPermissionTier::Isolated => "isolated", - WasmPermissionTier::ReadOnly => "read-only", - WasmPermissionTier::ReadWrite => "read-write", - WasmPermissionTier::Full => "full", - }; - let wasm_cwd = temp.path().join(format!("wasm-{tier_name}")); - fs::create_dir_all(&wasm_cwd).expect("create tier-specific wasm cwd"); - fs::write(wasm_cwd.join("guest.wasm"), wasm_noop_module()).expect("write wasm module"); - - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let result = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: vec![String::from("./guest.wasm")], - env: BTreeMap::new(), - cwd: wasm_cwd, - permission_tier: tier, - }) - .expect("start wasm execution") - .wait() - .expect("wait for wasm execution"); - assert_eq!(result.exit_code, 0); - } - assert!( - !log_path.exists(), - "wasm permission tiers should stay inside the V8 runtime rather than falling back to the host node binary" - ); -} - -#[test] -fn permission_flags_suite() { - // Keep V8-backed integration coverage inside one top-level libtest case. - // Running these guest-runtime cases as separate tests in the same binary - // still trips a V8 teardown/init boundary crash between cases. - node_permission_flags_allow_workers_for_internal_javascript_loader_runtime(); - node_permission_flags_only_propagate_nested_child_capabilities_when_parent_explicitly_allows_them(); - python_execution_applies_configured_heap_limit_to_v8_runtime(); - wasm_execution_applies_runtime_memory_and_fuel_limits_inside_v8_runtime(); - wasm_permission_tiers_do_not_fall_back_to_host_node_binary(); -} diff --git a/crates/execution/tests/process.rs b/crates/execution/tests/process.rs deleted file mode 100644 index 9b8bbf073..000000000 --- a/crates/execution/tests/process.rs +++ /dev/null @@ -1,238 +0,0 @@ -use secure_exec_execution::{ - CreateJavascriptContextRequest, CreatePythonContextRequest, CreateWasmContextRequest, - JavascriptExecutionEngine, PythonExecutionEngine, PythonExecutionEvent, - StartJavascriptExecutionRequest, StartPythonExecutionRequest, StartWasmExecutionRequest, - WasmExecutionEngine, WasmPermissionTier, -}; -use std::collections::BTreeMap; -use std::fs; -use std::path::Path; -use std::process::Command; -use std::time::{Duration, Instant}; -use tempfile::tempdir; - -fn assert_node_available() { - let binary = std::env::var("AGENTOS_NODE_BINARY").unwrap_or_else(|_| String::from("node")); - let output = Command::new(binary) - .arg("--version") - .output() - .expect("spawn node --version"); - assert!(output.status.success(), "node --version failed"); -} - -fn write_fixture(path: &Path, contents: &str) { - fs::write(path, contents).expect("write fixture"); -} - -fn write_pyodide_lock_fixture(path: &Path) { - write_fixture(path, "{\"packages\":[]}\n"); - let pyodide_dir = path.parent().expect("pyodide fixture parent"); - for asset in ["pyodide.asm.js", "pyodide.asm.wasm", "python_stdlib.zip"] { - let asset_path = pyodide_dir.join(asset); - if !asset_path.exists() { - fs::write(&asset_path, []).expect("write pyodide runtime fixture"); - } - } -} - -fn embedded_runtime_process_keeps_host_pid_internal_for_javascript() { - let temp = tempdir().expect("create temp dir"); - - let mut engine = JavascriptExecutionEngine::default(); - let context = engine.create_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-js"), - bootstrap_module: None, - compile_cache_root: None, - }); - - let execution = engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-js"), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - wasm_module_bytes: None, - inline_code: Some(String::from("globalThis.__secureExecRanInV8 = true;")), - }) - .expect("start JavaScript execution"); - - assert!(execution.uses_shared_v8_runtime()); - assert_eq!(execution.child_pid(), 0); - - let result = execution.wait().expect("wait for JavaScript execution"); - assert_eq!(result.exit_code, 0); -} - -fn embedded_runtime_process_keeps_host_pid_internal_for_wasm() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let module_path = temp.path().join("guest.wasm"); - let module = wat::parse_str( - r#"(module - (func (export "_start")) - )"#, - ) - .expect("compile wasm fixture"); - fs::write(&module_path, module).expect("write wasm fixture"); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(module_path.to_string_lossy().into_owned()), - }); - - let execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: vec![module_path.to_string_lossy().into_owned()], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::ReadWrite, - }) - .expect("start wasm execution"); - - assert!(execution.uses_shared_v8_runtime()); - assert_eq!(execution.child_pid(), 0); - - let result = execution.wait().expect("wait for wasm execution"); - assert_eq!( - result.exit_code, - 0, - "stderr: {}", - String::from_utf8_lossy(&result.stderr) - ); -} - -fn embedded_runtime_process_uses_session_control_for_python_kill() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - options.stdout("ready\n"); - return { - setStdin(_stdin) {}, - async runPythonAsync() { - await new Promise(() => setInterval(() => {}, 1000)); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let mut execution = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('hang')"), - file_path: None, - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution"); - - assert!(execution.uses_shared_v8_runtime()); - assert_eq!(execution.child_pid(), 0); - - let ready_deadline = Instant::now() + Duration::from_secs(5); - let mut saw_ready = false; - while !saw_ready { - if Instant::now() >= ready_deadline { - panic!("timed out waiting for Python execution readiness"); - } - match execution - .poll_event_blocking( - ready_deadline - .saturating_duration_since(Instant::now()) - .min(Duration::from_millis(100)), - ) - .expect("poll Python event before kill") - { - Some(PythonExecutionEvent::Stdout(chunk)) => { - saw_ready = String::from_utf8(chunk) - .expect("stdout utf8") - .contains("ready"); - } - Some(PythonExecutionEvent::Exited(code)) => { - panic!("execution exited unexpectedly before kill with code {code}"); - } - Some(PythonExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - panic!("unexpected VFS RPC request during kill test: {request:?}"); - } - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - assert!( - execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"), - "unexpected JS sync RPC request during kill test: {request:?}" - ); - } - None => panic!("timed out waiting for Python execution readiness"), - } - } - - execution.kill().expect("kill hanging Python execution"); - - let kill_deadline = Instant::now() + Duration::from_secs(5); - let mut exit_code = None; - while exit_code.is_none() { - if Instant::now() >= kill_deadline { - panic!("timed out waiting for killed Python execution to exit"); - } - match execution - .poll_event_blocking( - kill_deadline - .saturating_duration_since(Instant::now()) - .min(Duration::from_millis(100)), - ) - .expect("poll Python event after kill") - { - Some(PythonExecutionEvent::Exited(code)) => exit_code = Some(code), - Some(PythonExecutionEvent::Stdout(_)) | Some(PythonExecutionEvent::Stderr(_)) => {} - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - panic!("unexpected VFS RPC request after kill: {request:?}"); - } - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - assert!( - execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"), - "unexpected JS sync RPC request after kill: {request:?}" - ); - } - None => {} - } - } - - assert_eq!(exit_code, Some(1)); -} - -#[test] -fn embedded_runtime_process_suite() { - embedded_runtime_process_keeps_host_pid_internal_for_javascript(); - embedded_runtime_process_keeps_host_pid_internal_for_wasm(); - embedded_runtime_process_uses_session_control_for_python_kill(); -} diff --git a/crates/execution/tests/python.rs b/crates/execution/tests/python.rs deleted file mode 100644 index a56e875d9..000000000 --- a/crates/execution/tests/python.rs +++ /dev/null @@ -1,1280 +0,0 @@ -use secure_exec_execution::{ - CreatePythonContextRequest, PythonExecutionEngine, PythonExecutionEvent, PythonExecutionLimits, - PythonVfsRpcMethod, PythonVfsRpcResponsePayload, PythonVfsRpcStat, StartPythonExecutionRequest, -}; -use std::collections::BTreeMap; -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; -use std::thread; -use std::time::{Duration, Instant}; -use tempfile::tempdir; - -const PYTHON_WARMUP_METRICS_PREFIX: &str = "__AGENTOS_PYTHON_WARMUP_METRICS__:"; -const PYTHON_EXECUTION_TIMEOUT_MS_ENV: &str = "AGENTOS_PYTHON_EXECUTION_TIMEOUT_MS"; -const PYTHON_MAX_OLD_SPACE_MB_ENV: &str = "AGENTOS_PYTHON_MAX_OLD_SPACE_MB"; -const PYTHON_OUTPUT_BUFFER_MAX_BYTES_ENV: &str = "AGENTOS_PYTHON_OUTPUT_BUFFER_MAX_BYTES"; -const PYTHON_VFS_RPC_TIMEOUT_MS_ENV: &str = "AGENTOS_PYTHON_VFS_RPC_TIMEOUT_MS"; - -#[derive(Debug, Clone, PartialEq)] -struct PythonPrewarmMetrics { - executed: bool, - reason: String, - duration_ms: f64, - compile_cache_dir: String, - pyodide_dist_path: String, -} - -#[derive(Debug, Clone, PartialEq)] -struct PythonStartupMetrics { - prewarm_only: bool, - startup_ms: f64, - load_pyodide_ms: f64, - package_load_ms: f64, - package_count: usize, - source: String, -} - -fn assert_node_available() { - let binary = std::env::var("AGENTOS_NODE_BINARY").unwrap_or_else(|_| String::from("node")); - let output = Command::new(binary) - .arg("--version") - .output() - .expect("spawn node --version"); - assert!(output.status.success(), "node --version failed"); -} - -fn write_fixture(path: &Path, contents: &str) { - fs::write(path, contents).expect("write fixture"); -} - -fn write_pyodide_lock_fixture(path: &Path) { - write_fixture(path, "{\"packages\":[]}\n"); - let pyodide_dir = path.parent().expect("pyodide fixture parent"); - for asset in ["pyodide.asm.js", "pyodide.asm.wasm", "python_stdlib.zip"] { - let asset_path = pyodide_dir.join(asset); - if !asset_path.exists() { - fs::write(&asset_path, []).expect("write pyodide runtime fixture"); - } - } -} - -fn parse_metrics_line<'a>(stderr: &'a str, phase: &str) -> &'a str { - stderr - .lines() - .filter_map(|line| line.strip_prefix(PYTHON_WARMUP_METRICS_PREFIX)) - .find(|line| parse_string_metric(line, "phase") == phase) - .unwrap_or_else(|| panic!("missing {phase} metrics line in stderr: {stderr}")) -} - -fn parse_prewarm_metrics(stderr: &str) -> PythonPrewarmMetrics { - let metrics_line = parse_metrics_line(stderr, "prewarm"); - PythonPrewarmMetrics { - executed: parse_boolean_metric(metrics_line, "executed"), - reason: parse_string_metric(metrics_line, "reason"), - duration_ms: parse_float_metric(metrics_line, "durationMs"), - compile_cache_dir: parse_string_metric(metrics_line, "compileCacheDir"), - pyodide_dist_path: parse_string_metric(metrics_line, "pyodideDistPath"), - } -} - -fn parse_startup_metrics(stderr: &str) -> PythonStartupMetrics { - let metrics_line = parse_metrics_line(stderr, "startup"); - PythonStartupMetrics { - prewarm_only: parse_boolean_metric(metrics_line, "prewarmOnly"), - startup_ms: parse_float_metric(metrics_line, "startupMs"), - load_pyodide_ms: parse_float_metric(metrics_line, "loadPyodideMs"), - package_load_ms: parse_float_metric(metrics_line, "packageLoadMs"), - package_count: parse_metric_value(metrics_line, "packageCount"), - source: parse_string_metric(metrics_line, "source"), - } -} - -fn parse_metric_value(metrics_line: &str, key: &str) -> usize { - parse_float_metric(metrics_line, key) as usize -} - -fn parse_float_metric(metrics_line: &str, key: &str) -> f64 { - let marker = format!("\"{key}\":"); - let start = metrics_line.find(&marker).expect("metric key") + marker.len(); - let digits: String = metrics_line[start..] - .chars() - .skip_while(|ch| !ch.is_ascii_digit() && *ch != '-') - .take_while(|ch| ch.is_ascii_digit() || matches!(ch, '.' | '-' | 'e' | 'E' | '+')) - .collect(); - - digits.parse().expect("float metric value") -} - -fn parse_boolean_metric(metrics_line: &str, key: &str) -> bool { - let marker = format!("\"{key}\":"); - let start = metrics_line.find(&marker).expect("metric key") + marker.len(); - let remaining = &metrics_line[start..]; - - if remaining.starts_with("true") { - true - } else if remaining.starts_with("false") { - false - } else { - panic!("invalid boolean metric for {key}: {metrics_line}"); - } -} - -fn parse_string_metric(metrics_line: &str, key: &str) -> String { - let marker = format!("\"{key}\":\""); - let start = metrics_line.find(&marker).expect("metric key") + marker.len(); - let mut value = String::new(); - let mut escaped = false; - - for ch in metrics_line[start..].chars() { - if escaped { - value.push(match ch { - 'n' => '\n', - 'r' => '\r', - 't' => '\t', - '"' => '"', - '\\' => '\\', - other => other, - }); - escaped = false; - continue; - } - - match ch { - '\\' => escaped = true, - '"' => return value, - other => value.push(other), - } - } - - panic!("unterminated string metric for {key}: {metrics_line}"); -} - -fn run_python_execution( - engine: &mut PythonExecutionEngine, - context_id: String, - cwd: &Path, - code: &str, - env: BTreeMap, -) -> (String, String, i32) { - let execution = engine - .start_execution(StartPythonExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: String::from("vm-python"), - context_id, - code: String::from(code), - file_path: None, - env, - cwd: cwd.to_path_buf(), - }) - .expect("start Python execution"); - - let result = execution.wait(None).expect("wait for Python execution"); - let stdout = String::from_utf8(result.stdout).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - - (stdout, stderr, result.exit_code) -} - -fn assert_process_exits(pid: u32) { - for _ in 0..20 { - let status = Command::new("kill") - .arg("-0") - .arg(pid.to_string()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .expect("probe process with kill -0"); - if !status.success() { - return; - } - thread::sleep(Duration::from_millis(25)); - } - - panic!("process {pid} was still alive after waiting for cleanup"); -} - -fn python_contexts_preserve_vm_and_pyodide_configuration() { - let pyodide_dist_path = PathBuf::from("/tmp/pyodide"); - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dist_path.clone(), - }); - - assert_eq!(context.context_id, "python-ctx-1"); - assert_eq!(context.vm_id, "vm-python"); - assert_eq!(context.pyodide_dist_path, pyodide_dist_path); -} - -fn python_execution_runs_code_and_streams_stdio() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - return { - setStdin(_stdin) {}, - async runPythonAsync(code) { - options.stdout(`stdout:${code}`); - options.stderr(`stderr:${options.indexURL}`); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir.clone(), - }); - - let (stdout, stderr, exit_code) = run_python_execution( - &mut engine, - context.context_id, - temp.path(), - "print('hello')", - BTreeMap::new(), - ); - assert_eq!(exit_code, 0); - assert_eq!(stdout, "stdout:print('hello')\n"); - assert!( - stderr.starts_with("stderr:/__agentos_pyodide/"), - "unexpected stderr: {stderr}" - ); -} - -fn python_execution_wait_bounds_output_buffers() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - return { - setStdin(_stdin) {}, - async runPythonAsync() { - options.stdout('x'.repeat(80)); - options.stderr('y'.repeat(80)); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let result = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - // The cap is enforced from the typed wire limit. The env knob carries - // a much larger value to prove it is inert: if it were still read the - // buffer would not cap at 32. - limits: PythonExecutionLimits { - output_buffer_max_bytes: Some(32), - ..Default::default() - }, - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('ignored')"), - file_path: None, - env: BTreeMap::from([( - String::from(PYTHON_OUTPUT_BUFFER_MAX_BYTES_ENV), - String::from("999999"), - )]), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution") - .wait(None) - .expect("wait for Python execution"); - - assert_eq!(result.exit_code, 0); - assert_eq!(result.stdout.len(), 32, "stdout should be capped"); - assert_eq!(result.stderr.len(), 32, "stderr should be capped"); - assert!(result.stdout.iter().all(|byte| *byte == b'x')); - assert!(result.stderr.iter().all(|byte| *byte == b'y')); -} - -fn python_execution_emits_stdout_before_exit() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - return { - setStdin(_stdin) {}, - async runPythonAsync(code) { - options.stdout(`stdout:${code}`); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let mut execution = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('streamed')"), - file_path: None, - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution"); - - let mut saw_stdout = false; - let mut saw_exit = false; - - while !saw_exit { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll Python event") - { - Some(PythonExecutionEvent::Stdout(chunk)) => { - saw_stdout = String::from_utf8(chunk) - .expect("stdout utf8") - .contains("stdout:print('streamed')"); - } - Some(PythonExecutionEvent::Exited(code)) => { - assert_eq!(code, 0); - saw_exit = true; - } - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - panic!("unexpected VFS RPC request during stdout test: {request:?}"); - } - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - // Module-resolution sync RPCs now surface here (the runner - // module imports node builtins); service them host-directly. - let serviced = execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"); - assert!( - serviced, - "unexpected JS sync RPC request during stdout test: {request:?}" - ); - } - Some(PythonExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - None => panic!("timed out waiting for Python execution event"), - } - } - - assert!(saw_stdout, "expected stdout event before exit"); -} - -fn python_execution_reports_prewarm_and_startup_metrics_when_debug_enabled() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide() { - await new Promise((resolve) => setTimeout(resolve, 20)); - return { - setStdin(_stdin) {}, - async runPythonAsync(code) { - console.log(`ran:${code}`); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir.clone(), - }); - let debug_env = BTreeMap::from([( - String::from("AGENTOS_PYTHON_WARMUP_DEBUG"), - String::from("1"), - )]); - - let (first_stdout, first_stderr, first_exit_code) = run_python_execution( - &mut engine, - context.context_id.clone(), - temp.path(), - "print('first')", - debug_env.clone(), - ); - let first_prewarm = parse_prewarm_metrics(&first_stderr); - let first_startup = parse_startup_metrics(&first_stderr); - - assert_eq!(first_exit_code, 0); - assert!(first_stdout.contains("ran:print('first')")); - assert!( - first_prewarm.executed, - "first prewarm metrics: {first_prewarm:?}" - ); - assert_eq!(first_prewarm.reason, "executed"); - assert!(first_prewarm.duration_ms >= 0.0); - assert!( - first_prewarm.compile_cache_dir.contains("compile-cache"), - "unexpected prewarm metrics: {first_prewarm:?}" - ); - assert_eq!( - PathBuf::from(&first_prewarm.pyodide_dist_path), - pyodide_dir, - "unexpected prewarm metrics: {first_prewarm:?}" - ); - assert!(!first_startup.prewarm_only); - assert!(first_startup.startup_ms > 0.0); - assert!(first_startup.load_pyodide_ms > 0.0); - assert_eq!(first_startup.package_load_ms, 0.0); - assert_eq!(first_startup.package_count, 0); - assert_eq!(first_startup.source, "inline"); - - let (_second_stdout, second_stderr, second_exit_code) = run_python_execution( - &mut engine, - context.context_id, - temp.path(), - "print('second')", - debug_env, - ); - let second_prewarm = parse_prewarm_metrics(&second_stderr); - let second_startup = parse_startup_metrics(&second_stderr); - - assert_eq!(second_exit_code, 0); - assert!( - !second_prewarm.executed, - "second prewarm metrics: {second_prewarm:?}" - ); - assert_eq!(second_prewarm.reason, "cached"); - assert_eq!(second_prewarm.duration_ms, 0.0); - assert!(!second_startup.prewarm_only); - assert!(second_startup.startup_ms > 0.0); - assert!(second_startup.load_pyodide_ms > 0.0); - assert_eq!(second_startup.source, "inline"); -} - -fn python_execution_keeps_streaming_stdin_sessions_alive_until_closed() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -const decoder = new TextDecoder(); - -export async function loadPyodide(options) { - let stdin = null; - return { - setStdin(config) { - stdin = config; - }, - async runPythonAsync(code) { - const chunk = new Uint8Array(8192); - const bytesRead = stdin.read(chunk); - const text = decoder.decode(chunk.subarray(0, bytesRead)); - options.stdout(`stdin:${text}`); - options.stdout(`code:${code}`); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let mut execution = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('streaming')"), - file_path: None, - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution"); - - // Module-resolution sync RPCs surface during startup (the runner module - // imports node builtins); service them, then confirm the execution then - // stays idle (no other event) until stdin closes. - let idle_deadline = Instant::now() + Duration::from_millis(400); - loop { - match execution - .poll_event_blocking(Duration::from_millis(50)) - .expect("poll Python event before stdin write") - { - None => { - if Instant::now() >= idle_deadline { - break; - } - } - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - assert!( - execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"), - "unexpected JS sync RPC before stdin write: {request:?}" - ); - } - other => panic!( - "streaming-stdin execution should stay alive until stdin closes, got {other:?}" - ), - } - } - - execution - .write_stdin(b"still-open") - .expect("write stdin after idle period"); - execution.close_stdin().expect("close stdin"); - - let mut stdout = Vec::new(); - let mut exit_code = None; - - while exit_code.is_none() { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll Python event") - { - Some(PythonExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - panic!("unexpected VFS RPC request during stdin test: {request:?}"); - } - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - assert!( - execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"), - "unexpected JS sync RPC request during stdin test: {request:?}" - ); - } - Some(PythonExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - Some(PythonExecutionEvent::Exited(code)) => exit_code = Some(code), - None => panic!("timed out waiting for Python execution event"), - } - } - - assert_eq!(exit_code, Some(0)); - let stdout = String::from_utf8(stdout).expect("stdout utf8"); - assert!( - stdout.contains("stdin:still-open"), - "unexpected stdout: {stdout}" - ); - assert!( - stdout.contains("code:print('streaming')"), - "unexpected stdout: {stdout}" - ); -} - -fn python_execution_surfaces_vfs_rpc_requests_and_resumes_after_responses() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - return { - setStdin(_stdin) {}, - async runPythonAsync(code) { - const rpc = globalThis.__agentOSPythonVfsRpc; - await rpc.fsMkdir('/workspace', { recursive: true }); - await rpc.fsWrite( - '/workspace/note.txt', - Buffer.from('hello from rpc', 'utf8').toString('base64'), - ); - const content = Buffer.from( - await rpc.fsRead('/workspace/note.txt'), - 'base64', - ).toString('utf8'); - const stat = await rpc.fsStat('/workspace/note.txt'); - const entries = await rpc.fsReaddir('/workspace'); - options.stdout(JSON.stringify({ code, content, stat, entries })); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let mut execution = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('rpc bridge')"), - file_path: None, - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution"); - - let mut stdout = Vec::new(); - let mut exit_code = None; - let mut saw_requests = Vec::new(); - - while exit_code.is_none() { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll Python event") - { - Some(PythonExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(PythonExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - saw_requests.push((request.method, request.path.clone())); - match request.method { - PythonVfsRpcMethod::Mkdir => execution - .respond_vfs_rpc_success(request.id, PythonVfsRpcResponsePayload::Empty) - .expect("respond to mkdir"), - PythonVfsRpcMethod::Write => { - assert_eq!(request.path, "/workspace/note.txt"); - assert_eq!( - request.content_base64.as_deref(), - Some("aGVsbG8gZnJvbSBycGM=") - ); - execution - .respond_vfs_rpc_success(request.id, PythonVfsRpcResponsePayload::Empty) - .expect("respond to write"); - } - PythonVfsRpcMethod::Read => execution - .respond_vfs_rpc_success( - request.id, - PythonVfsRpcResponsePayload::Read { - content_base64: String::from("aGVsbG8gZnJvbSBycGM="), - }, - ) - .expect("respond to read"), - PythonVfsRpcMethod::Stat => execution - .respond_vfs_rpc_success( - request.id, - PythonVfsRpcResponsePayload::Stat { - stat: PythonVfsRpcStat { - mode: 0o100644, - size: 14, - is_directory: false, - is_symbolic_link: false, - }, - }, - ) - .expect("respond to stat"), - PythonVfsRpcMethod::ReadDir => execution - .respond_vfs_rpc_success( - request.id, - PythonVfsRpcResponsePayload::ReadDir { - entries: vec![String::from("note.txt")], - }, - ) - .expect("respond to read_dir"), - PythonVfsRpcMethod::Unlink - | PythonVfsRpcMethod::Rmdir - | PythonVfsRpcMethod::Rename => { - panic!( - "unexpected mutating-FS Python RPC in this test: {:?}", - request.method - ) - } - PythonVfsRpcMethod::HttpRequest - | PythonVfsRpcMethod::DnsLookup - | PythonVfsRpcMethod::SubprocessRun => { - panic!("unexpected non-filesystem Python RPC: {:?}", request.method) - } - other => { - panic!( - "unexpected Python VFS RPC method in this test: {other:?} for {}", - request.path - ) - } - } - } - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - assert!( - execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"), - "unexpected JS sync RPC request during VFS RPC test: {request:?}" - ); - } - Some(PythonExecutionEvent::Exited(code)) => exit_code = Some(code), - None => panic!("timed out waiting for Python execution event"), - } - } - - assert_eq!(exit_code, Some(0)); - assert_eq!( - saw_requests, - vec![ - (PythonVfsRpcMethod::Mkdir, String::from("/workspace")), - ( - PythonVfsRpcMethod::Write, - String::from("/workspace/note.txt") - ), - ( - PythonVfsRpcMethod::Read, - String::from("/workspace/note.txt") - ), - ( - PythonVfsRpcMethod::Stat, - String::from("/workspace/note.txt") - ), - (PythonVfsRpcMethod::ReadDir, String::from("/workspace")), - ] - ); - - let stdout = String::from_utf8(stdout).expect("stdout utf8"); - assert!( - stdout.contains("\"content\":\"hello from rpc\""), - "unexpected stdout: {stdout}" - ); - assert!( - stdout.contains("\"entries\":[\"note.txt\"]"), - "unexpected stdout: {stdout}" - ); - assert!( - stdout.contains("\"size\":14"), - "unexpected stdout: {stdout}" - ); -} - -fn python_execution_wait_timeout_cleans_up_hanging_child() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide() { - return { - setStdin(_stdin) {}, - async runPythonAsync() { - await new Promise(() => setInterval(() => {}, 1000)); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let execution = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('hang')"), - file_path: None, - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution"); - let child_pid = execution.child_pid(); - let uses_shared_v8_runtime = execution.uses_shared_v8_runtime(); - - let error = execution - .wait(Some(Duration::from_millis(100))) - .expect_err("timed out wait"); - match error { - secure_exec_execution::PythonExecutionError::TimedOut(timeout) => { - assert_eq!(timeout, Duration::from_millis(100)); - } - other => panic!("expected timeout error, got {other:?}"), - } - - if !uses_shared_v8_runtime { - assert_process_exits(child_pid); - } -} - -fn python_execution_uses_configured_default_timeout_when_wait_timeout_not_provided() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide() { - return { - setStdin(_stdin) {}, - async runPythonAsync() { - await new Promise(() => setInterval(() => {}, 1000)); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let execution = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - // Enforced from the typed wire limit. The env knob is set to "0" - // (which would *disable* the timeout if it were still read) to prove - // it is inert. - limits: PythonExecutionLimits { - execution_timeout_ms: Some(75), - ..Default::default() - }, - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('hang')"), - file_path: None, - env: BTreeMap::from([( - String::from(PYTHON_EXECUTION_TIMEOUT_MS_ENV), - String::from("0"), - )]), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution"); - let child_pid = execution.child_pid(); - let uses_shared_v8_runtime = execution.uses_shared_v8_runtime(); - - let error = execution - .wait(None) - .expect_err("configured timeout should fire"); - match error { - secure_exec_execution::PythonExecutionError::TimedOut(timeout) => { - assert_eq!(timeout, Duration::from_millis(75)); - } - other => panic!("expected timeout error, got {other:?}"), - } - - if !uses_shared_v8_runtime { - assert_process_exits(child_pid); - } -} - -fn python_vfs_rpc_bridge_times_out_when_sidecar_never_responds() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide() { - return { - setStdin(_stdin) {}, - async runPythonAsync() { - globalThis.__agentOSPythonVfsRpc.fsReadSync('/workspace/never.txt'); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let mut execution = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - // Enforced from the typed wire limit; the env knob carries a much - // larger value to prove it is inert. - limits: PythonExecutionLimits { - vfs_rpc_timeout_ms: Some(50), - ..Default::default() - }, - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('rpc timeout')"), - file_path: None, - env: BTreeMap::from([( - String::from(PYTHON_VFS_RPC_TIMEOUT_MS_ENV), - String::from("600000"), - )]), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution"); - let child_pid = execution.child_pid(); - let uses_shared_v8_runtime = execution.uses_shared_v8_runtime(); - - let mut saw_request = false; - let mut stderr = Vec::new(); - let mut exit_code = None; - - for _ in 0..40 { - match execution - .poll_event_blocking(Duration::from_millis(250)) - .expect("poll Python event") - { - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - saw_request = true; - assert_eq!(request.method, PythonVfsRpcMethod::Read); - assert_eq!(request.path, "/workspace/never.txt"); - } - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - assert!( - execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"), - "unexpected JS sync RPC request during timeout test: {request:?}" - ); - } - Some(PythonExecutionEvent::Stderr(chunk)) => stderr.extend(chunk), - Some(PythonExecutionEvent::Exited(code)) => { - exit_code = Some(code); - break; - } - Some(PythonExecutionEvent::Stdout(chunk)) => { - panic!("unexpected stdout: {}", String::from_utf8_lossy(&chunk)); - } - None => {} - } - } - - assert!(saw_request, "expected a VFS RPC request before timeout"); - assert_eq!( - exit_code, - Some(1), - "stderr: {}", - String::from_utf8_lossy(&stderr) - ); - - let stderr = String::from_utf8(stderr).expect("stderr utf8"); - assert!( - stderr.contains("ERR_AGENTOS_PYTHON_VFS_RPC_TIMEOUT") - || stderr.contains("timed out waiting for a response") - || stderr.contains("timed out after 50ms"), - "unexpected stderr: {stderr}" - ); - if !uses_shared_v8_runtime { - assert_process_exits(child_pid); - } -} - -fn python_execution_surfaces_runtime_stderr() { - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide() { - console.error("runtime stderr before failure"); - return { - setStdin(_stdin) {}, - async runPythonAsync() { - throw new Error("simulated runtime failure"); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let result = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - // Enforced from the typed wire limit. The env knob is set to "0" - // (which would mean "use the V8 default / unlimited" if it were still - // read) to prove it is inert. - limits: PythonExecutionLimits { - max_old_space_mb: Some(64), - ..Default::default() - }, - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('oom')"), - file_path: None, - env: BTreeMap::from([(String::from(PYTHON_MAX_OLD_SPACE_MB_ENV), String::from("0"))]), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution") - .wait(None) - .expect("wait for Python execution"); - - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 1, "stderr: {stderr}"); - assert!( - stderr.contains("runtime stderr before failure") - && stderr.contains("simulated runtime failure"), - "unexpected stderr: {stderr}" - ); -} - -fn python_execution_kill_stops_inflight_process_and_emits_exit() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide(options) { - options.stdout("ready\n"); - return { - setStdin(_stdin) {}, - async runPythonAsync() { - await new Promise(() => setInterval(() => {}, 1000)); - }, - }; -} -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let mut execution = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-python"), - context_id: context.context_id, - code: String::from("print('hang')"), - file_path: None, - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - }) - .expect("start Python execution"); - let child_pid = execution.child_pid(); - let uses_shared_v8_runtime = execution.uses_shared_v8_runtime(); - - let ready_deadline = Instant::now() + Duration::from_secs(5); - let mut saw_ready = false; - while !saw_ready { - if Instant::now() >= ready_deadline { - panic!("timed out waiting for Python execution readiness"); - } - match execution - .poll_event_blocking( - ready_deadline - .saturating_duration_since(Instant::now()) - .min(Duration::from_millis(100)), - ) - .expect("poll Python event before kill") - { - Some(PythonExecutionEvent::Stdout(chunk)) => { - saw_ready = String::from_utf8(chunk) - .expect("stdout utf8") - .contains("ready"); - } - Some(PythonExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - panic!("unexpected VFS RPC request during kill test: {request:?}"); - } - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - assert!( - execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"), - "unexpected JS sync RPC request during kill test: {request:?}" - ); - } - Some(PythonExecutionEvent::Exited(code)) => { - panic!("execution exited unexpectedly before kill with code {code}"); - } - None => panic!("timed out waiting for Python execution readiness"), - } - } - - execution.kill().expect("kill hanging Python execution"); - - let kill_deadline = Instant::now() + Duration::from_secs(5); - let mut exit_code = None; - while exit_code.is_none() { - if Instant::now() >= kill_deadline { - panic!("timed out waiting for killed Python execution to exit"); - } - match execution - .poll_event_blocking( - kill_deadline - .saturating_duration_since(Instant::now()) - .min(Duration::from_millis(100)), - ) - .expect("poll Python event after kill") - { - Some(PythonExecutionEvent::Exited(code)) => exit_code = Some(code), - Some(PythonExecutionEvent::Stdout(_)) | Some(PythonExecutionEvent::Stderr(_)) => {} - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - panic!("unexpected VFS RPC request after kill: {request:?}"); - } - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - assert!( - execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"), - "unexpected JS sync RPC request after kill: {request:?}" - ); - } - None => {} - } - } - - assert_eq!(exit_code, Some(1)); - if !uses_shared_v8_runtime { - assert_process_exits(child_pid); - } -} - -fn python_execution_blocks_network_requests_during_pyodide_init() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let pyodide_dir = temp.path().join("pyodide"); - fs::create_dir_all(&pyodide_dir).expect("create pyodide dir"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide() { - let initResult; - try { - await fetch('https://example.com/pyodide-init-check'); - initResult = { ok: true }; - } catch (error) { - initResult = { - ok: false, - code: error.code ?? null, - message: error.message, - }; - } - - return { - setStdin(_stdin) {}, - async runPythonAsync() { - console.log(JSON.stringify(initResult)); - }, - }; -} - -"#, - ); - write_pyodide_lock_fixture(&pyodide_dir.join("pyodide-lock.json")); - - let mut engine = PythonExecutionEngine::default(); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir, - }); - - let (stdout, stderr, exit_code) = run_python_execution( - &mut engine, - context.context_id, - temp.path(), - "print('ignored')", - BTreeMap::new(), - ); - - assert_eq!(exit_code, 0, "stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - let parsed: serde_json::Value = - serde_json::from_str(stdout.trim()).expect("parse init network JSON"); - assert_eq!(parsed["ok"], serde_json::Value::Bool(false)); - assert!( - parsed["code"].is_null() - || parsed["code"] == serde_json::Value::String(String::from("ERR_ACCESS_DENIED")), - "unexpected network denial payload: {stdout}" - ); - let message = parsed["message"].as_str().expect("network denial message"); - if parsed["code"].is_null() { - assert!( - message.contains("fetch failed"), - "unexpected stdout: {stdout}" - ); - } else { - assert!( - message.contains("network access"), - "unexpected stdout: {stdout}" - ); - } -} - -// Separate libtest cases in this binary still trip a V8 teardown/init crash, so -// keep the Python runtime coverage in one top-level suite until that boundary is fixed. -#[test] -fn python_suite() { - python_contexts_preserve_vm_and_pyodide_configuration(); - python_execution_runs_code_and_streams_stdio(); - python_execution_wait_bounds_output_buffers(); - python_execution_emits_stdout_before_exit(); - python_execution_reports_prewarm_and_startup_metrics_when_debug_enabled(); - python_execution_keeps_streaming_stdin_sessions_alive_until_closed(); - python_execution_surfaces_vfs_rpc_requests_and_resumes_after_responses(); - python_execution_wait_timeout_cleans_up_hanging_child(); - python_execution_uses_configured_default_timeout_when_wait_timeout_not_provided(); - python_vfs_rpc_bridge_times_out_when_sidecar_never_responds(); - python_execution_surfaces_runtime_stderr(); - python_execution_kill_stops_inflight_process_and_emits_exit(); - python_execution_blocks_network_requests_during_pyodide_init(); -} diff --git a/crates/execution/tests/python_prewarm.rs b/crates/execution/tests/python_prewarm.rs deleted file mode 100644 index 103351998..000000000 --- a/crates/execution/tests/python_prewarm.rs +++ /dev/null @@ -1,192 +0,0 @@ -use secure_exec_execution::{ - CreatePythonContextRequest, PythonExecutionEngine, PythonExecutionEvent, - StartPythonExecutionRequest, -}; -use serde_json::Value; -use std::collections::BTreeMap; -use std::fs; -use std::path::{Path, PathBuf}; -use std::time::Duration; -use tempfile::tempdir; - -const PYTHON_WARMUP_METRICS_PREFIX: &str = "__AGENTOS_PYTHON_WARMUP_METRICS__:"; - -fn setup_engine() -> (PythonExecutionEngine, String, PathBuf) { - let mut engine = PythonExecutionEngine::default(); - let pyodide_dir = engine - .bundled_pyodide_dist_path_for_vm("vm-python") - .expect("materialize bundled pyodide"); - let context = engine.create_context(CreatePythonContextRequest { - vm_id: String::from("vm-python"), - pyodide_dist_path: pyodide_dir.clone(), - }); - (engine, context.context_id, pyodide_dir) -} - -fn run_python_execution( - engine: &mut PythonExecutionEngine, - context_id: &str, - cwd: &Path, - code: &str, -) -> (String, String, i32) { - let mut execution = engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-python"), - context_id: context_id.to_string(), - code: code.to_string(), - file_path: None, - env: BTreeMap::from([( - String::from("AGENTOS_PYTHON_WARMUP_DEBUG"), - String::from("1"), - )]), - cwd: cwd.to_path_buf(), - }) - .expect("start Python execution"); - - // Drive the event loop directly instead of `.wait()`: the Pyodide runner - // now sets up a kernel-VFS-backed site-packages on boot, which emits VFS - // RPCs. This prewarm test has no VFS backend, so reject those RPCs and let - // the runner's best-effort site-packages setup degrade. Module-resolution - // sync RPCs are serviced host-directly. - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - loop { - match execution - .poll_event_blocking(Duration::from_secs(60)) - .expect("poll Python event") - { - Some(PythonExecutionEvent::Stdout(chunk)) => stdout.extend(chunk), - Some(PythonExecutionEvent::Stderr(chunk)) => stderr.extend(chunk), - Some(PythonExecutionEvent::JavascriptSyncRpcRequest(request)) => { - let serviced = execution - .try_service_standalone_module_sync_rpc(&request) - .expect("service module sync RPC"); - assert!(serviced, "unexpected JS sync RPC request: {request:?}"); - } - Some(PythonExecutionEvent::VfsRpcRequest(request)) => { - execution - .respond_vfs_rpc_error(request.id, "ENOSYS", "no VFS backend in prewarm test") - .expect("respond to VFS RPC"); - } - Some(PythonExecutionEvent::Exited(exit_code)) => { - return ( - String::from_utf8(stdout).expect("stdout utf8"), - String::from_utf8(stderr).expect("stderr utf8"), - exit_code, - ); - } - None => panic!("timed out waiting for Python execution event"), - } - } -} - -fn parse_metrics(stderr: &str, phase: &str) -> Value { - let payload = stderr - .lines() - .filter_map(|line| line.strip_prefix(PYTHON_WARMUP_METRICS_PREFIX)) - .map(|line| serde_json::from_str::(line).expect("parse metrics json")) - .find(|value| value.get("phase").and_then(Value::as_str) == Some(phase)) - .unwrap_or_else(|| panic!("missing {phase} metrics in stderr: {stderr}")); - payload -} - -fn python_execution_prewarms_once_when_compile_cache_is_ready() { - let temp = tempdir().expect("create temp dir"); - let (mut engine, context_id, _pyodide_dir) = setup_engine(); - let (first_stdout, first_stderr, first_exit_code) = - run_python_execution(&mut engine, &context_id, temp.path(), "print('first')"); - let (second_stdout, second_stderr, second_exit_code) = - run_python_execution(&mut engine, &context_id, temp.path(), "print('second')"); - - assert_eq!(first_exit_code, 0, "stderr: {first_stderr}"); - assert_eq!(second_exit_code, 0, "stderr: {second_stderr}"); - assert_eq!(first_stdout, "first\n"); - assert_eq!(second_stdout, "second\n"); - - let first_prewarm = parse_metrics(&first_stderr, "prewarm"); - let second_prewarm = parse_metrics(&second_stderr, "prewarm"); - - assert_eq!(first_prewarm["executed"], true); - assert_eq!(first_prewarm["reason"], "executed"); - assert_eq!(second_prewarm["executed"], false); - assert_eq!(second_prewarm["reason"], "cached"); -} - -fn python_execution_invalidates_prewarm_stamp_when_pyodide_bundle_changes() { - let temp = tempdir().expect("create temp dir"); - let (mut engine, context_id, pyodide_dir) = setup_engine(); - let pyodide_mjs = pyodide_dir.join("pyodide.mjs"); - let (_first_stdout, first_stderr, first_exit_code) = - run_python_execution(&mut engine, &context_id, temp.path(), "print('first')"); - assert_eq!(first_exit_code, 0, "stderr: {first_stderr}"); - assert_eq!( - parse_metrics(&first_stderr, "prewarm")["reason"], - "executed" - ); - - let original = fs::read_to_string(&pyodide_mjs).expect("read pyodide module"); - fs::write( - &pyodide_mjs, - format!("{original}\n// prewarm invalidation test\n"), - ) - .expect("mutate pyodide module"); - - let (second_stdout, second_stderr, second_exit_code) = - run_python_execution(&mut engine, &context_id, temp.path(), "print('second')"); - assert_eq!(second_exit_code, 0, "stderr: {second_stderr}"); - assert_eq!(second_stdout, "second\n"); - assert_eq!( - parse_metrics(&second_stderr, "prewarm")["reason"], - "executed" - ); -} - -// Separate libtest cases in this binary still trip a V8 teardown/init crash, so -// keep the prewarm coverage in one top-level suite until that boundary is fixed. -// -// cargo-nextest runs every `#[test]` in its OWN process, so that crash cannot -// occur there — `mod python_prewarm_split` below exposes each case as a separate -// test that nextest runs in parallel across cores. Skip the collapsed run under -// nextest so the work isn't done twice; the split cases skip themselves under -// `cargo test`. nextest sets `NEXTEST=1` in each test process; libtest/`cargo -// test` does not. -#[test] -fn python_prewarm_suite() { - if std::env::var_os("NEXTEST").is_some() { - return; - } - python_execution_prewarms_once_when_compile_cache_is_ready(); - python_execution_invalidates_prewarm_stamp_when_pyodide_bundle_changes(); -} - -/// Per-case split of `python_prewarm_suite` for cargo-nextest (process-per-test). -/// -/// Each `#[test]` here runs exactly one Pyodide prewarm case in its own process, -/// so the shared-process V8/Pyodide teardown/init crash that forces the collapsed -/// `python_prewarm_suite` above does not apply, and the cases run in parallel -/// across cores instead of serially. Each case skips itself under plain `cargo -/// test` (where `NEXTEST` is unset) so the collapsed suite owns the run there; the -/// collapsed suite likewise skips under nextest so the work isn't duplicated. -mod python_prewarm_split { - macro_rules! nextest_cases { - ($($case:ident),+ $(,)?) => { - $( - #[test] - fn $case() { - // Covered by the collapsed `super::python_prewarm_suite` under `cargo test`. - if std::env::var_os("NEXTEST").is_none() { - return; - } - super::$case(); - } - )+ - }; - } - - nextest_cases!( - python_execution_prewarms_once_when_compile_cache_is_ready, - python_execution_invalidates_prewarm_stamp_when_pyodide_bundle_changes, - ); -} diff --git a/crates/execution/tests/smoke.rs b/crates/execution/tests/smoke.rs deleted file mode 100644 index be35c6bc3..000000000 --- a/crates/execution/tests/smoke.rs +++ /dev/null @@ -1,14 +0,0 @@ -use secure_exec_execution::{scaffold, GuestRuntime}; - -#[test] -fn execution_scaffold_is_native_and_depends_on_kernel() { - let scaffold = scaffold(); - - assert_eq!(scaffold.package_name, "secure-exec-execution"); - assert_eq!(scaffold.kernel_package, "secure-exec-kernel"); - assert_eq!(scaffold.target, "native"); - assert_eq!( - scaffold.planned_guest_runtimes, - [GuestRuntime::JavaScript, GuestRuntime::WebAssembly] - ); -} diff --git a/crates/execution/tests/wasi_path_open_read_not_blocked.rs b/crates/execution/tests/wasi_path_open_read_not_blocked.rs deleted file mode 100644 index b63b132a7..000000000 --- a/crates/execution/tests/wasi_path_open_read_not_blocked.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Regression test for issue #1: -//! "WASI fdOpen permission check typo (read blocked as write)". -//! -//! The original bug computed write-intent from the READ rights bit -//! (`rightsBase & 2n`, where `2n` == WASI_RIGHT_FD_READ == `1n << 1n`). -//! That meant a pure read open (which sets RIGHT_FD_READ) was treated as a -//! write and rejected with EACCES/EROFS on read-only or isolated tiers. -//! -//! The fix is that write-intent is derived from RIGHT_FD_WRITE -//! (`1n << 6n` == 64n) instead. The WASI module JS that performs `path_open` -//! lives in `crates/execution/assets/runners/wasi-module.js`, and the delegated -//! runner path lives in `crates/execution/assets/runners/wasm-runner.mjs`. -//! -//! `build_wasm_runner_bootstrap` is a private function, so rather than execute -//! it we pin the source-level invariant: write-intent MUST be checked against -//! the WRITE bit and MUST NOT be checked against the READ bit. This locks out -//! reintroducing the typo. If the buggy `& 2n` / READ-bit write check ever -//! returns, this test fails. - -use std::fs; -use std::path::PathBuf; - -fn read_source(rel: &str) -> String { - let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(rel); - fs::read_to_string(&path) - .unwrap_or_else(|err| panic!("failed to read {}: {err}", path.display())) -} - -/// Returns the body of the `_hasWriteRights` JS method in the WASI module asset, -/// or `None` if the method cannot be located. -fn extract_has_write_rights_body(source: &str) -> Option<&str> { - let start = source.find("_hasWriteRights(rights)")?; - let rest = &source[start..]; - // Grab a generous window covering the small method body. - let end = rest.find("_writeUint32").unwrap_or(rest.len().min(800)); - Some(&rest[..end]) -} - -#[test] -fn wasm_runner_write_intent_uses_write_bit_not_read_bit() { - let wasm_src = read_source("assets/runners/wasi-module.js"); - - // The WRITE right constant must be defined as bit 6 (64n), not the read bit. - assert!( - wasm_src.contains("const __agentOSWasiRightFdWrite = 1n << 6n;"), - "expected RIGHT_FD_WRITE to be defined as `1n << 6n` (64n) in wasi-module.js; \ - the write-intent constant is the foundation of the read-vs-write distinction" - ); - - let body = extract_has_write_rights_body(&wasm_src) - .expect("expected to find `_hasWriteRights(rights)` method in wasi-module.js"); - - // Write-intent must be masked against the WRITE bit. - assert!( - body.contains("(BigInt(rights) & __agentOSWasiRightFdWrite) !== 0n"), - "_hasWriteRights must check write-intent against RIGHT_FD_WRITE \ - (__agentOSWasiRightFdWrite); found body: {body}" - ); - - // Guard against reintroducing the original typo: write-intent must NOT be - // derived from the READ bit. `2n` and `1n << 1n` are RIGHT_FD_READ. - assert!( - !body.contains("& 2n"), - "_hasWriteRights must NOT mask against `2n` (RIGHT_FD_READ) — that was \ - the original typo that blocked reads as writes; found body: {body}" - ); - assert!( - !body.contains("1n << 1n"), - "_hasWriteRights must NOT mask against the read bit `1n << 1n`; \ - found body: {body}" - ); - assert!( - !body.contains("RightFdRead"), - "_hasWriteRights must NOT reference the READ rights constant for \ - write-intent; found body: {body}" - ); -} - -#[test] -fn wasm_runner_path_open_gates_write_access_on_write_rights() { - let wasm_src = read_source("assets/runners/wasi-module.js"); - - // path_open derives requestedWriteAccess from create/truncate flags OR the - // WRITE rights bit (via _hasWriteRights), never from the read bit. A pure - // read (RIGHT_FD_READ only, no CREAT/TRUNC) therefore yields - // requestedWriteAccess === false and is not denied on read-only tiers. - assert!( - wasm_src.contains("createOrTruncate || this._hasWriteRights(requestedRightsBase)"), - "path_open must compute write-intent from create/truncate flags or \ - _hasWriteRights(requestedRightsBase), so pure reads are not flagged as writes" - ); - - // EROFS / EACCES must only fire when write access is actually requested. - assert!( - wasm_src.contains("if (requestedWriteAccess && resolved.readOnly) {"), - "read-only EROFS must be gated behind requestedWriteAccess so reads succeed" - ); -} diff --git a/crates/execution/tests/wasm.rs b/crates/execution/tests/wasm.rs deleted file mode 100644 index 2da1f567b..000000000 --- a/crates/execution/tests/wasm.rs +++ /dev/null @@ -1,2868 +0,0 @@ -use base64::Engine; -use secure_exec_execution::wasm::{ - NativeBinaryFormat, WASM_MAX_FUEL_ENV, WASM_MAX_MEMORY_BYTES_ENV, WASM_MAX_STACK_BYTES_ENV, -}; -use secure_exec_execution::{ - CreateWasmContextRequest, StartWasmExecutionRequest, WasmExecutionEngine, WasmExecutionError, - WasmExecutionEvent, WasmExecutionLimits, WasmPermissionTier, -}; -use serde_json::json; -use std::collections::BTreeMap; -use std::fs; -use std::os::unix::fs::symlink; -use std::path::Path; -use std::process::Command; -use std::sync::mpsc; -use std::sync::{Mutex, MutexGuard, OnceLock}; -use std::thread; -use std::time::Duration; -use tempfile::tempdir; - -const WASM_WARMUP_METRICS_PREFIX: &str = "__AGENTOS_WASM_WARMUP_METRICS__:"; - -fn node_binary_env_lock() -> &'static Mutex<()> { - static LOCK: OnceLock> = OnceLock::new(); - LOCK.get_or_init(|| Mutex::new(())) -} - -fn lock_node_binary_env() -> MutexGuard<'static, ()> { - node_binary_env_lock() - .lock() - .expect("lock AGENTOS_NODE_BINARY test guard") -} - -struct EnvVarGuard { - key: &'static str, - previous: Option, -} - -impl EnvVarGuard { - fn set(key: &'static str, value: &Path) -> Self { - let previous = std::env::var(key).ok(); - // SAFETY: These tests mutate process env only within this scoped guard. - unsafe { - std::env::set_var(key, value); - } - Self { key, previous } - } - - fn set_value(key: &'static str, value: &str) -> Self { - let previous = std::env::var(key).ok(); - // SAFETY: The wasm suite runs these env-sensitive cases serially inside - // one libtest entry. - unsafe { - std::env::set_var(key, value); - } - Self { key, previous } - } -} - -impl Drop for EnvVarGuard { - fn drop(&mut self) { - match &self.previous { - Some(value) => { - // SAFETY: Restores the env key owned by this scoped guard. - unsafe { - std::env::set_var(self.key, value); - } - } - None => { - // SAFETY: Restores the env key owned by this scoped guard. - unsafe { - std::env::remove_var(self.key); - } - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct WasmWarmupMetrics { - executed: bool, - reason: String, - module_path: String, - compile_cache_dir: String, -} - -fn assert_node_available() { - let _guard = lock_node_binary_env(); - let binary = std::env::var("AGENTOS_NODE_BINARY").unwrap_or_else(|_| String::from("node")); - let output = Command::new(binary) - .arg("--version") - .output() - .expect("spawn node --version"); - assert!(output.status.success(), "node --version failed"); -} - -fn write_fixture(path: &Path, contents: &[u8]) { - fs::write(path, contents).expect("write fixture"); -} - -fn decode_sync_rpc_bytes(value: &serde_json::Value) -> Vec { - let base64 = value - .get("__agentOSType") - .and_then(serde_json::Value::as_str) - .is_some_and(|kind| kind == "bytes") - .then(|| value.get("base64").and_then(serde_json::Value::as_str)) - .flatten() - .expect("sync rpc bytes payload"); - base64::engine::general_purpose::STANDARD - .decode(base64) - .expect("decode sync rpc bytes") -} - -fn write_fake_node_binary(path: &Path, log_path: &Path) { - let script = format!( - "#!/bin/sh\nset -eu\nprintf 'host-node-invoked\\n' >> \"{}\"\nexit 1\n", - log_path.display(), - ); - fs::write(path, script).expect("write fake node binary"); - let mut permissions = fs::metadata(path) - .expect("fake node metadata") - .permissions(); - use std::os::unix::fs::PermissionsExt; - permissions.set_mode(0o755); - fs::set_permissions(path, permissions).expect("chmod fake node binary"); -} - -fn parse_warmup_metrics(stderr: &str) -> WasmWarmupMetrics { - let metrics_line = stderr - .lines() - .filter_map(|line| line.strip_prefix(WASM_WARMUP_METRICS_PREFIX)) - .next_back() - .expect("warmup metrics line"); - - WasmWarmupMetrics { - executed: parse_boolean_metric(metrics_line, "executed"), - reason: parse_string_metric(metrics_line, "reason"), - module_path: parse_string_metric(metrics_line, "modulePath"), - compile_cache_dir: parse_string_metric(metrics_line, "compileCacheDir"), - } -} - -fn parse_boolean_metric(metrics_line: &str, key: &str) -> bool { - let marker = format!("\"{key}\":"); - let start = metrics_line.find(&marker).expect("metric key") + marker.len(); - let remaining = &metrics_line[start..]; - - if remaining.starts_with("true") { - true - } else if remaining.starts_with("false") { - false - } else { - panic!("invalid boolean metric for {key}: {metrics_line}"); - } -} - -fn parse_string_metric(metrics_line: &str, key: &str) -> String { - let marker = format!("\"{key}\":\""); - let start = metrics_line.find(&marker).expect("metric key") + marker.len(); - let mut value = String::new(); - let mut chars = metrics_line[start..].chars(); - - while let Some(ch) = chars.next() { - match ch { - '\\' => value.push(parse_escaped_char(&mut chars)), - '"' => return value, - other => value.push(other), - } - } - - panic!("unterminated string metric for {key}: {metrics_line}"); -} - -fn parse_escaped_char(chars: &mut std::str::Chars<'_>) -> char { - match chars.next().expect("escaped character") { - 'n' => '\n', - 'r' => '\r', - 't' => '\t', - '"' => '"', - '\\' => '\\', - 'u' => parse_unicode_escape(chars), - other => other, - } -} - -fn parse_unicode_escape(chars: &mut std::str::Chars<'_>) -> char { - let high = parse_unicode_escape_unit(chars); - if !(0xD800..=0xDBFF).contains(&high) { - return char::from_u32(u32::from(high)).expect("basic multilingual plane char"); - } - - assert_eq!(chars.next(), Some('\\'), "expected low surrogate escape"); - assert_eq!(chars.next(), Some('u'), "expected low surrogate marker"); - let low = parse_unicode_escape_unit(chars); - let codepoint = 0x10000 + (((u32::from(high) - 0xD800) << 10) | (u32::from(low) - 0xDC00)); - char::from_u32(codepoint).expect("supplementary plane char") -} - -fn parse_unicode_escape_unit(chars: &mut std::str::Chars<'_>) -> u16 { - let hex: String = chars.take(4).collect(); - assert_eq!(hex.len(), 4, "expected four hex digits in unicode escape"); - u16::from_str_radix(&hex, 16).expect("unicode escape value") -} - -/// Mirror the sidecar's config→limits flow for tests that still express WASM -/// limits via the historical `AGENTOS_WASM_*` env keys: translate them into the -/// typed `WasmExecutionLimits` the engine now reads. Production sources these -/// from the BARE-wire resource limits, never env. -fn wasm_limits_from_env(env: &BTreeMap) -> WasmExecutionLimits { - let parse = |key: &str| env.get(key).and_then(|value| value.parse::().ok()); - WasmExecutionLimits { - max_fuel: parse(WASM_MAX_FUEL_ENV), - max_memory_bytes: parse(WASM_MAX_MEMORY_BYTES_ENV), - max_stack_bytes: parse(WASM_MAX_STACK_BYTES_ENV), - prewarm_timeout_ms: None, - runner_heap_limit_mb: None, - } -} - -fn run_wasm_execution( - engine: &mut WasmExecutionEngine, - context_id: String, - cwd: &Path, - argv: Vec, - env: BTreeMap, - permission_tier: WasmPermissionTier, -) -> (String, String, i32) { - let limits = wasm_limits_from_env(&env); - let execution = engine - .start_execution(StartWasmExecutionRequest { - limits, - guest_runtime: Default::default(), - vm_id: String::from("vm-wasm"), - context_id, - argv, - env, - cwd: cwd.to_path_buf(), - permission_tier, - }) - .expect("start wasm execution"); - - let result = execution.wait().expect("wait for wasm execution"); - let stdout = String::from_utf8(result.stdout).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - - (stdout, stderr, result.exit_code) -} - -fn wasm_stdout_module() -> Vec { - wat::parse_str( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) - (data (i32.const 16) "stdout:wasm-smoke\n") - (func $_start (export "_start") - (i32.store (i32.const 0) (i32.const 16)) - (i32.store (i32.const 4) (i32.const 18)) - (drop - (call $fd_write - (i32.const 1) - (i32.const 0) - (i32.const 1) - (i32.const 40) - ) - ) - ) -) -"#, - ) - .expect("compile wasm fixture") -} - -fn wasm_stdin_echo_module() -> Vec { - wat::parse_str( - r#" -(module - (type $fd_read_t (func (param i32 i32 i32 i32) (result i32))) - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_read" (func $fd_read (type $fd_read_t))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) - (func $_start (export "_start") - (i32.store (i32.const 0) (i32.const 32)) - (i32.store (i32.const 4) (i32.const 64)) - (drop - (call $fd_read - (i32.const 0) - (i32.const 0) - (i32.const 1) - (i32.const 8) - ) - ) - (i32.store (i32.const 16) (i32.const 32)) - (i32.store (i32.const 20) (i32.load (i32.const 8))) - (drop - (call $fd_write - (i32.const 1) - (i32.const 16) - (i32.const 1) - (i32.const 24) - ) - ) - ) -) -"#, - ) - .expect("compile stdin echo wasm fixture") -} - -fn wasm_fdstat_set_flags_module() -> Vec { - wat::parse_str( - r#" -(module - (type $fd_fdstat_get_t (func (param i32 i32) (result i32))) - (type $fd_fdstat_set_flags_t (func (param i32 i32) (result i32))) - (type $proc_exit_t (func (param i32))) - (import "wasi_snapshot_preview1" "fd_fdstat_get" (func $fd_fdstat_get (type $fd_fdstat_get_t))) - (import "wasi_snapshot_preview1" "fd_fdstat_set_flags" (func $fd_fdstat_set_flags (type $fd_fdstat_set_flags_t))) - (import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (type $proc_exit_t))) - (memory (export "memory") 1) - (func $_start (export "_start") - (if - (i32.ne - (call $fd_fdstat_set_flags (i32.const 1) (i32.const 4)) - (i32.const 0) - ) - (then (call $proc_exit (i32.const 41))) - ) - (if - (i32.ne - (call $fd_fdstat_get (i32.const 1) (i32.const 0)) - (i32.const 0) - ) - (then (call $proc_exit (i32.const 42))) - ) - (if - (i32.ne - (i32.load16_u offset=2 (i32.const 0)) - (i32.const 4) - ) - (then (call $proc_exit (i32.const 43))) - ) - ) -) -"#, - ) - .expect("compile fdstat flags wasm fixture") -} - -fn wasm_override_module() -> Vec { - wat::parse_str( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) - (data (i32.const 16) "stdout:evil-smoke\n") - (func $_start (export "_start") - (i32.store (i32.const 0) (i32.const 16)) - (i32.store (i32.const 4) (i32.const 18)) - (drop - (call $fd_write - (i32.const 1) - (i32.const 0) - (i32.const 1) - (i32.const 40) - ) - ) - ) -) -"#, - ) - .expect("compile wasm fixture") -} - -fn wasm_timing_module() -> Vec { - wat::parse_str( - r#" -(module - (type $clock_time_get_t (func (param i32 i64 i32) (result i32))) - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "clock_time_get" (func $clock_time_get (type $clock_time_get_t))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) - (data (i32.const 32) "timing:frozen\n") - (func $_start (export "_start") - (local $counter i32) - (drop (call $clock_time_get (i32.const 0) (i64.const 1) (i32.const 0))) - (loop $spin - local.get $counter - i32.const 1 - i32.add - local.tee $counter - i32.const 20000000 - i32.lt_u - br_if $spin - ) - (drop (call $clock_time_get (i32.const 0) (i64.const 1) (i32.const 8))) - (if - (i64.ne (i64.load (i32.const 0)) (i64.load (i32.const 8))) - (then unreachable) - ) - (i32.store (i32.const 16) (i32.const 32)) - (i32.store (i32.const 20) (i32.const 14)) - (drop - (call $fd_write - (i32.const 1) - (i32.const 16) - (i32.const 1) - (i32.const 24) - ) - ) - ) -) -"#, - ) - .expect("compile timing wasm fixture") -} - -fn wasm_signal_state_module() -> Vec { - wat::parse_str( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (type $proc_sigaction_t (func (param i32 i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (import "host_process" "proc_sigaction" (func $proc_sigaction (type $proc_sigaction_t))) - (memory (export "memory") 1) - (data (i32.const 32) "signal:ready\n") - (func $_start (export "_start") - (drop - (call $proc_sigaction - (i32.const 2) - (i32.const 2) - (i32.const 16384) - (i32.const 0) - (i32.const 4660) - ) - ) - (i32.store (i32.const 0) (i32.const 32)) - (i32.store (i32.const 4) (i32.const 13)) - (drop - (call $fd_write - (i32.const 1) - (i32.const 0) - (i32.const 1) - (i32.const 24) - ) - ) - ) -) -"#, - ) - .expect("compile signal wasm fixture") -} - -fn wat_escape_ascii(input: &str) -> String { - let mut escaped = String::new(); - for ch in input.chars() { - match ch { - '\\' => escaped.push_str("\\\\"), - '"' => escaped.push_str("\\\""), - '\n' => escaped.push_str("\\n"), - '\r' => escaped.push_str("\\0d"), - _ => escaped.push(ch), - } - } - escaped -} - -fn wasm_stdout_chunks_module(chunks: &[&str]) -> Vec { - let mut data_offset = 64u32; - let mut data_segments = String::new(); - let mut writes = String::new(); - - for (index, chunk) in chunks.iter().enumerate() { - let escaped = wat_escape_ascii(chunk); - let chunk_len = chunk.len(); - let iovec_offset = (index as u32) * 8; - data_segments.push_str(&format!( - " (data (i32.const {data_offset}) \"{escaped}\")\n" - )); - writes.push_str(&format!( - " (i32.store (i32.const {iovec_offset}) (i32.const {data_offset}))\n (i32.store (i32.const {}) (i32.const {chunk_len}))\n (drop\n (call $fd_write\n (i32.const 1)\n (i32.const {iovec_offset})\n (i32.const 1)\n (i32.const 40)\n )\n )\n", - iovec_offset + 4 - )); - data_offset += chunk_len as u32; - } - - wat::parse_str(format!( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) -{data_segments} (func $_start (export "_start") -{writes} ) -) -"# - )) - .expect("compile stdout-chunks wasm fixture") -} - -fn wasm_signal_state_line_stdout_module() -> Vec { - wasm_stdout_chunks_module(&[ - "hello\n__AGENTOS_WASM_SIGNAL_STATE__:{\"signal\":2,\"registration\":{\"action\":\"user\",\"mask\":[15],\"flags\":4660}}\n", - ]) -} - -fn wasm_split_signal_state_line_stdout_module() -> Vec { - wasm_stdout_chunks_module(&[ - "__AGENTOS_WASM_SIGNAL_STATE__:", - "{\"signal\":2,\"registration\":{\"action\":\"user\",\"mask\":[15],\"flags\":4660}}\n", - ]) -} - -fn wasm_write_file_module() -> Vec { - wat::parse_str( - r#" -(module - (type $path_open_t (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (type $fd_close_t (func (param i32) (result i32))) - (import "wasi_snapshot_preview1" "path_open" (func $path_open (type $path_open_t))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (import "wasi_snapshot_preview1" "fd_close" (func $fd_close (type $fd_close_t))) - (memory (export "memory") 1) - (data (i32.const 64) "output.txt") - (data (i32.const 80) "tiered-write\n") - (func $_start (export "_start") - (if - (i32.ne - (call $path_open - (i32.const 3) - (i32.const 0) - (i32.const 64) - (i32.const 10) - (i32.const 9) - (i64.const 64) - (i64.const 64) - (i32.const 0) - (i32.const 8) - ) - (i32.const 0) - ) - (then unreachable) - ) - (i32.store (i32.const 0) (i32.const 80)) - (i32.store (i32.const 4) (i32.const 13)) - (if - (i32.ne - (call $fd_write - (i32.load (i32.const 8)) - (i32.const 0) - (i32.const 1) - (i32.const 12) - ) - (i32.const 0) - ) - (then unreachable) - ) - (drop (call $fd_close (i32.load (i32.const 8)))) - ) -) -"#, - ) - .expect("compile write-file wasm fixture") -} - -fn wasm_write_nested_file_module() -> Vec { - wat::parse_str( - r#" -(module - (type $path_open_t (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (type $fd_close_t (func (param i32) (result i32))) - (import "wasi_snapshot_preview1" "path_open" (func $path_open (type $path_open_t))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (import "wasi_snapshot_preview1" "fd_close" (func $fd_close (type $fd_close_t))) - (memory (export "memory") 1) - (data (i32.const 64) "nested/output.txt") - (data (i32.const 96) "nested-write\n") - (func $_start (export "_start") - (if - (i32.ne - (call $path_open - (i32.const 3) - (i32.const 0) - (i32.const 64) - (i32.const 17) - (i32.const 9) - (i64.const 64) - (i64.const 64) - (i32.const 0) - (i32.const 8) - ) - (i32.const 0) - ) - (then unreachable) - ) - (i32.store (i32.const 0) (i32.const 96)) - (i32.store (i32.const 4) (i32.const 13)) - (if - (i32.ne - (call $fd_write - (i32.load (i32.const 8)) - (i32.const 0) - (i32.const 1) - (i32.const 12) - ) - (i32.const 0) - ) - (then unreachable) - ) - (drop (call $fd_close (i32.load (i32.const 8)))) - ) -) -"#, - ) - .expect("compile nested write-file wasm fixture") -} - -fn wasm_expect_write_open_errno_module(expected_errno: u32) -> Vec { - wat::parse_str(format!( - r#" -(module - (type $path_open_t (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) - (type $fd_close_t (func (param i32) (result i32))) - (import "wasi_snapshot_preview1" "path_open" (func $path_open (type $path_open_t))) - (import "wasi_snapshot_preview1" "fd_close" (func $fd_close (type $fd_close_t))) - (memory (export "memory") 1) - (data (i32.const 64) "output.txt") - (func $_start (export "_start") - (local $errno i32) - (local.set $errno - (call $path_open - (i32.const 3) - (i32.const 0) - (i32.const 64) - (i32.const 10) - (i32.const 9) - (i64.const 64) - (i64.const 64) - (i32.const 0) - (i32.const 8) - ) - ) - (if - (i32.ne - (local.get $errno) - (i32.const {expected_errno}) - ) - (then unreachable) - ) - (if - (i32.eq (local.get $errno) (i32.const 0)) - (then - (drop (call $fd_close (i32.load (i32.const 8)))) - ) - ) - ) -) -"# - )) - .expect("compile expected-errno wasm fixture") -} - -fn wasm_escape_preopen_module() -> Vec { - wat::parse_str( - r#" -(module - (type $path_open_t (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "path_open" (func $path_open (type $path_open_t))) - (memory (export "memory") 1) - (data (i32.const 64) "../../../../etc/passwd") - (func $_start (export "_start") - (if - (i32.ne - (call $path_open - (i32.const 3) - (i32.const 0) - (i32.const 64) - (i32.const 22) - (i32.const 0) - (i64.const 0) - (i64.const 0) - (i32.const 0) - (i32.const 8) - ) - (i32.const 44) - ) - (then unreachable) - ) - ) -) -"#, - ) - .expect("compile preopen-escape wasm fixture") -} - -fn wasm_poll_oneoff_module() -> Vec { - wat::parse_str( - r#" -(module - (type $poll_oneoff_t (func (param i32 i32 i32 i32) (result i32))) - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "poll_oneoff" (func $poll_oneoff (type $poll_oneoff_t))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) - (data (i32.const 176) "poll-ready\n") - (func $_start (export "_start") - (i64.store (i32.const 0) (i64.const 1)) - (i32.store8 (i32.const 8) (i32.const 1)) - (i32.store (i32.const 16) (i32.const 0)) - - (i64.store (i32.const 48) (i64.const 2)) - (i32.store8 (i32.const 56) (i32.const 1)) - (i32.store (i32.const 64) (i32.const 1)) - - (if - (i32.ne - (call $poll_oneoff - (i32.const 0) - (i32.const 96) - (i32.const 2) - (i32.const 160) - ) - (i32.const 0) - ) - (then unreachable) - ) - - (if (i32.ne (i32.load (i32.const 160)) (i32.const 1)) (then unreachable)) - (if (i64.ne (i64.load (i32.const 96)) (i64.const 1)) (then unreachable)) - (if (i32.ne (i32.load8_u (i32.const 106)) (i32.const 1)) (then unreachable)) - - (i32.store (i32.const 168) (i32.const 176)) - (i32.store (i32.const 172) (i32.const 11)) - (drop - (call $fd_write - (i32.const 1) - (i32.const 168) - (i32.const 1) - (i32.const 164) - ) - ) - ) -) -"#, - ) - .expect("compile poll_oneoff wasm fixture") -} - -fn wasm_infinite_loop_module() -> Vec { - wat::parse_str( - r#" -(module - (memory (export "memory") 1) - (func $_start (export "_start") - (loop $spin - br $spin - ) - ) -) -"#, - ) - .expect("compile infinite-loop wasm fixture") -} - -fn wasm_memory_capped_module() -> Vec { - wat::parse_str( - r#" -(module - (memory (export "memory") 1 3) - (func $_start (export "_start")) -) -"#, - ) - .expect("compile memory-capped wasm fixture") -} - -fn wasm_memory_grow_until_runtime_limit_module() -> Vec { - wat::parse_str( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) - (data (i32.const 32) "memory-grow-limited\n") - (func $_start (export "_start") - (if - (i32.ne - (memory.grow (i32.const 1)) - (i32.const 1) - ) - (then unreachable) - ) - (if - (i32.ne - (memory.grow (i32.const 1)) - (i32.const -1) - ) - (then unreachable) - ) - (i32.store (i32.const 0) (i32.const 32)) - (i32.store (i32.const 4) (i32.const 20)) - (drop - (call $fd_write - (i32.const 1) - (i32.const 0) - (i32.const 1) - (i32.const 24) - ) - ) - ) -) -"#, - ) - .expect("compile runtime memory-limit wasm fixture") -} - -fn raw_wasm_module(section_id: u8, section_contents: &[u8]) -> Vec { - let mut bytes = Vec::from(*b"\0asm"); - bytes.extend_from_slice(&[0x01, 0x00, 0x00, 0x00]); - bytes.push(section_id); - bytes.extend(encode_varuint(section_contents.len() as u64)); - bytes.extend_from_slice(section_contents); - bytes -} - -fn encode_varuint(mut value: u64) -> Vec { - let mut encoded = Vec::new(); - loop { - let mut byte = (value & 0x7f) as u8; - value >>= 7; - if value != 0 { - byte |= 0x80; - } - encoded.push(byte); - if value == 0 { - return encoded; - } - } -} - -fn wasm_contexts_preserve_vm_and_module_configuration() { - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - assert_eq!(context.context_id, "wasm-ctx-1"); - assert_eq!(context.vm_id, "vm-wasm"); - assert_eq!(context.module_path.as_deref(), Some("./guest.wasm")); -} - -fn wasm_execution_stays_inside_v8_runtime_without_host_node_launches() { - let _guard = lock_node_binary_env(); - let temp = tempdir().expect("create temp dir"); - let fake_node_path = temp.path().join("fake-node.sh"); - let log_path = temp.path().join("node-invocations.log"); - write_fake_node_binary(&fake_node_path, &log_path); - let _node_binary = EnvVarGuard::set("AGENTOS_NODE_BINARY", &fake_node_path); - - write_fixture(&temp.path().join("guest.wasm"), &wasm_stdout_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::from([( - String::from(WASM_MAX_MEMORY_BYTES_ENV), - (2 * 65_536).to_string(), - )]), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 0, "stdout={stdout} stderr={stderr}"); - assert!(stdout.contains("stdout:wasm-smoke"), "stdout={stdout}"); - assert!( - !log_path.exists(), - "WASM prewarm/execution should stay inside the shared V8 runtime, not launch AGENTOS_NODE_BINARY", - ); -} - -fn wasm_execution_runs_guest_module_through_v8() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_stdout_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: vec![String::from("guest.wasm")], - env: BTreeMap::from([(String::from("IGNORED_FOR_NOW"), String::from("ok"))]), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect("start wasm execution"); - - assert_eq!(execution.execution_id(), "exec-1"); - - let result = execution.wait().expect("wait for wasm execution"); - assert_eq!(result.exit_code, 0); - assert!( - result.stderr.is_empty(), - "unexpected stderr: {:?}", - result.stderr - ); - - let stdout = String::from_utf8(result.stdout).expect("stdout utf8"); - assert!(stdout.contains("stdout:wasm-smoke")); -} - -fn wasm_snapshot_runner_block_round_trips_twice() { - assert_node_available(); - let _mode = EnvVarGuard::set_value("AGENTOS_WASM_SNAPSHOT_RUNNER", "block"); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_stdout_chunks_module(&["hello\n"]), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (first_stdout, first_stderr, first_exit) = run_wasm_execution( - &mut engine, - context.context_id.clone(), - temp.path(), - Vec::new(), - BTreeMap::from([(String::from("AGENTOS_WASM_WARMUP_DEBUG"), String::from("1"))]), - WasmPermissionTier::Full, - ); - assert_eq!(first_exit, 0, "stderr={first_stderr}"); - assert_eq!(first_stdout, "hello\n"); - assert!( - !first_stderr.contains("decodeBase64ToUint8Array"), - "raw module bytes path should not base64-decode: {first_stderr}" - ); - - let (second_stdout, second_stderr, second_exit) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::from([(String::from("AGENTOS_WASM_WARMUP_DEBUG"), String::from("1"))]), - WasmPermissionTier::Full, - ); - assert_eq!(second_exit, 0, "stderr={second_stderr}"); - assert_eq!(second_stdout, "hello\n"); - assert!( - !second_stderr.contains("decodeBase64ToUint8Array"), - "raw module bytes path should not base64-decode: {second_stderr}" - ); -} - -fn phase_calls(path: &Path, stage: &str) -> u64 { - let contents = fs::read_to_string(path).unwrap_or_default(); - contents - .lines() - .find(|line| line.starts_with(&format!("stage={stage} "))) - .and_then(|line| { - line.split_whitespace() - .find_map(|field| field.strip_prefix("calls=")) - }) - .and_then(|value| value.parse::().ok()) - .unwrap_or(0) -} - -fn wasm_snapshot_runner_warm_worker_pool_hits() { - assert_node_available(); - let _mode = EnvVarGuard::set_value("AGENTOS_WASM_SNAPSHOT_RUNNER", "block"); - let _warm = EnvVarGuard::set_value("AGENTOS_V8_WARM_ISOLATES", "2"); - let _phases = EnvVarGuard::set_value("AGENTOS_V8_SESSION_PHASES", "1"); - let phases_dir = tempdir().expect("create phases temp dir"); - let phases_file = phases_dir.path().join("v8-phases.txt"); - let _phases_file = EnvVarGuard::set("AGENTOS_V8_SESSION_PHASES_FILE", &phases_file); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_stdout_chunks_module(&["pool-hit\n"]), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - for _ in 0..2 { - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id.clone(), - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - assert_eq!(exit_code, 0, "stderr={stderr}"); - assert_eq!(stdout, "pool-hit\n"); - } - - assert!( - phase_calls(&phases_file, "warm_worker_hit") >= 1, - "expected at least one warm worker pool hit; phases={}", - fs::read_to_string(&phases_file).unwrap_or_default() - ); -} - -fn wasm_snapshot_runner_warm_worker_pool_disabled_falls_back() { - assert_node_available(); - let _mode = EnvVarGuard::set_value("AGENTOS_WASM_SNAPSHOT_RUNNER", "block"); - let _warm = EnvVarGuard::set_value("AGENTOS_V8_WARM_ISOLATES", "0"); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_stdout_chunks_module(&["pool-disabled\n"]), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 0, "stderr={stderr}"); - assert_eq!(stdout, "pool-disabled\n"); -} - -fn wasm_snapshot_runner_warm_hint_mismatch_falls_back() { - assert_node_available(); - let _warm = EnvVarGuard::set_value("AGENTOS_V8_WARM_ISOLATES", "2"); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_stdout_chunks_module(&["mismatch\n"]), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - { - let _mode = EnvVarGuard::set_value("AGENTOS_WASM_SNAPSHOT_RUNNER", "block"); - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id.clone(), - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - assert_eq!(exit_code, 0, "stderr={stderr}"); - assert_eq!(stdout, "mismatch\n"); - } - - let _mode = EnvVarGuard::set_value("AGENTOS_WASM_SNAPSHOT_RUNNER", "off"); - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - assert_eq!(exit_code, 0, "stderr={stderr}"); - assert_eq!(stdout, "mismatch\n"); -} - -fn wasm_snapshot_runner_off_fallback_matches_inline() { - assert_node_available(); - let _mode = EnvVarGuard::set_value("AGENTOS_WASM_SNAPSHOT_RUNNER", "off"); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_stdout_chunks_module(&["hello\n"]), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::from([(String::from("AGENTOS_WASM_WARMUP_DEBUG"), String::from("1"))]), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 0, "stderr={stderr}"); - assert_eq!(stdout, "hello\n"); - assert!( - !stderr.contains("decodeBase64ToUint8Array"), - "raw module bytes path should not base64-decode: {stderr}" - ); -} - -fn wasm_module_bytes_cache_invalidates_when_file_changes() { - assert_node_available(); - let _mode = EnvVarGuard::set_value("AGENTOS_WASM_SNAPSHOT_RUNNER", "block"); - - let temp = tempdir().expect("create temp dir"); - let module_path = temp.path().join("guest.wasm"); - write_fixture(&module_path, &wasm_stdout_chunks_module(&["first\n"])); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (first_stdout, first_stderr, first_exit) = run_wasm_execution( - &mut engine, - context.context_id.clone(), - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - assert_eq!(first_exit, 0, "stderr={first_stderr}"); - assert_eq!(first_stdout, "first\n"); - - write_fixture( - &module_path, - &wasm_stdout_chunks_module(&["second-output\n"]), - ); - - let (second_stdout, second_stderr, second_exit) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - assert_eq!(second_exit, 0, "stderr={second_stderr}"); - assert_eq!(second_stdout, "second-output\n"); -} - -fn wasm_execution_supports_fd_fdstat_set_flags() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_fdstat_set_flags_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (_stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 0, "stderr: {stderr}"); - assert!( - !stderr.contains("fd_fdstat_set_flags"), - "missing WASI fd_fdstat_set_flags import should not leak into stderr: {stderr}" - ); - assert!( - !stderr.contains("LinkError"), - "WASI import gaps should not break module instantiation: {stderr}" - ); -} - -fn wasm_execution_ignores_guest_overrides_for_internal_node_env() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_stdout_module()); - write_fixture(&temp.path().join("evil.wasm"), &wasm_override_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::from([ - ( - String::from("AGENTOS_WASM_MODULE_PATH"), - String::from("./evil.wasm"), - ), - (String::from("AGENTOS_WASM_PREWARM_ONLY"), String::from("1")), - (String::from("NODE_OPTIONS"), String::from("--no-warnings")), - ]), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 0, "stderr: {stderr}"); - assert_eq!(stdout, "stdout:wasm-smoke\n"); - assert!(!stdout.contains("evil-smoke")); -} - -fn wasm_execution_freezes_wasi_clock_time() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_timing_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 0); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - assert!(stdout.contains("timing:frozen"), "stdout: {stdout}"); -} - -fn wasm_execution_rejects_vm_mismatch() { - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let error = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-other"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: Path::new("/tmp").to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect_err("vm mismatch should fail"); - - assert!(error - .to_string() - .contains("guest WebAssembly context belongs to vm vm-wasm, not vm-other")); -} - -fn wasm_execution_streams_exit_event() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_stdout_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let mut execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect("start wasm execution"); - - let mut saw_stdout = false; - let mut saw_exit = false; - - while !saw_exit { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll wasm event") - { - Some(WasmExecutionEvent::Stdout(chunk)) => { - saw_stdout = String::from_utf8(chunk) - .expect("stdout utf8") - .contains("stdout:wasm-smoke"); - } - Some(WasmExecutionEvent::Exited(code)) => { - assert_eq!(code, 0); - saw_exit = true; - } - Some(WasmExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - Some(WasmExecutionEvent::SyncRpcRequest(_)) => {} - Some(WasmExecutionEvent::SignalState { .. }) => {} - None => panic!("timed out waiting for wasm execution event"), - } - } - - assert!(saw_stdout, "expected stdout event before exit"); -} - -fn wasm_execution_can_route_stdio_through_kernel_sync_rpc() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_stdout_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let mut execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::from([( - String::from("AGENTOS_WASI_STDIO_SYNC_RPC"), - String::from("1"), - )]), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect("start wasm execution"); - - let request = match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll wasm event") - { - Some(WasmExecutionEvent::SyncRpcRequest(request)) => request, - other => panic!("expected kernel stdio sync RPC request, got {other:?}"), - }; - - assert_eq!(request.method, "__kernel_stdio_write"); - assert_eq!(request.args.first(), Some(&json!(1))); - assert_eq!( - String::from_utf8(decode_sync_rpc_bytes(&request.args[1])).expect("stdout utf8"), - "stdout:wasm-smoke\n" - ); - - execution - .respond_sync_rpc_success(request.id, json!(18)) - .expect("respond to __kernel_stdio_write"); - - let result = execution.wait().expect("wait for wasm execution"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "stderr={stderr}"); - assert!( - result.stdout.is_empty(), - "stdout should be kernel-routed in this mode" - ); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn wasm_execution_reads_streaming_stdin_via_kernel_bridge() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_stdin_echo_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let mut execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::from([( - String::from("AGENTOS_WASI_STDIO_SYNC_RPC"), - String::from("1"), - )]), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect("start wasm execution"); - - execution - .write_stdin(b"stdin-echo\n") - .expect("write wasm stdin"); - execution.close_stdin().expect("close wasm stdin"); - - let result = execution.wait().expect("wait for wasm execution"); - let stdout = String::from_utf8(result.stdout).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - - assert_eq!(result.exit_code, 0, "stderr={stderr}"); - assert_eq!(stdout, "stdin-echo\n"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); -} - -fn wasm_execution_poll_oneoff_uses_kernel_poll_for_multiple_fds() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_poll_oneoff_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let mut execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect("start wasm execution"); - - let request = match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll wasm event") - { - Some(WasmExecutionEvent::SyncRpcRequest(request)) => request, - other => panic!("expected sync RPC request, got {other:?}"), - }; - - assert_eq!(request.method, "__kernel_poll"); - assert_eq!( - request.args, - vec![ - json!([ - { "fd": 0, "events": 1 }, - { "fd": 1, "events": 1 } - ]), - json!(10), - ] - ); - - execution - .respond_sync_rpc_success( - request.id, - json!({ - "readyCount": 1, - "fds": [ - { "fd": 0, "events": 1, "revents": 1 }, - { "fd": 1, "events": 1, "revents": 0 } - ] - }), - ) - .expect("respond to __kernel_poll"); - - let result = execution.wait().expect("wait for wasm execution"); - let stdout = String::from_utf8(result.stdout).expect("stdout utf8"); - let stderr = String::from_utf8(result.stderr).expect("stderr utf8"); - assert_eq!(result.exit_code, 0, "stdout={stdout} stderr={stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - assert_eq!(stdout, "poll-ready\n"); -} - -fn wasm_execution_emits_signal_state_from_control_channel() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_signal_state_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let mut execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect("start wasm execution"); - - let mut saw_stdout = false; - let mut saw_signal = false; - let mut saw_exit = false; - - while !saw_exit { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll wasm event") - { - Some(WasmExecutionEvent::Stdout(chunk)) => { - saw_stdout = String::from_utf8(chunk) - .expect("stdout utf8") - .contains("signal:ready"); - } - Some(WasmExecutionEvent::SignalState { - signal, - registration, - }) => { - assert_eq!(signal, 2); - assert_eq!( - registration.action, - secure_exec_execution::wasm::WasmSignalDispositionAction::User - ); - assert_eq!(registration.mask, vec![15]); - assert_eq!(registration.flags, 0x1234); - saw_signal = true; - } - Some(WasmExecutionEvent::Exited(code)) => { - assert_eq!(code, 0); - saw_exit = true; - } - Some(WasmExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - Some(WasmExecutionEvent::SyncRpcRequest(_)) => {} - None => panic!("timed out waiting for wasm execution event"), - } - } - - assert!(saw_stdout, "expected stdout event before exit"); - assert!(saw_signal, "expected signal-state event before exit"); -} - -fn wasm_execution_preserves_stdout_when_signal_state_marker_shares_stdout_chunk() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_signal_state_line_stdout_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let mut execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::ReadWrite, - }) - .expect("start wasm execution"); - - let mut stdout = Vec::new(); - let mut saw_signal = false; - let mut saw_exit = false; - - while !saw_exit { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll wasm event") - { - Some(WasmExecutionEvent::Stdout(chunk)) => stdout.push(chunk), - Some(WasmExecutionEvent::SignalState { - signal, - registration, - }) => { - assert_eq!(signal, 2); - assert_eq!( - registration.action, - secure_exec_execution::wasm::WasmSignalDispositionAction::User - ); - assert_eq!(registration.mask, vec![15]); - assert_eq!(registration.flags, 0x1234); - saw_signal = true; - } - Some(WasmExecutionEvent::Exited(code)) => { - assert_eq!(code, 0); - saw_exit = true; - } - Some(WasmExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - Some(WasmExecutionEvent::SyncRpcRequest(_)) => {} - None => panic!("timed out waiting for wasm execution event"), - } - } - - assert_eq!(stdout, vec![b"hello\n".to_vec()]); - assert!(saw_signal, "expected signal-state event before exit"); -} - -fn wasm_execution_reassembles_split_signal_state_marker_across_stdout_chunks() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_split_signal_state_line_stdout_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let mut execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::ReadWrite, - }) - .expect("start wasm execution"); - - let mut saw_signal = false; - let mut saw_exit = false; - let mut stdout = Vec::new(); - - while !saw_exit { - match execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll wasm event") - { - Some(WasmExecutionEvent::Stdout(chunk)) => stdout.push(chunk), - Some(WasmExecutionEvent::SignalState { - signal, - registration, - }) => { - assert_eq!(signal, 2); - assert_eq!( - registration.action, - secure_exec_execution::wasm::WasmSignalDispositionAction::User - ); - assert_eq!(registration.mask, vec![15]); - assert_eq!(registration.flags, 0x1234); - saw_signal = true; - } - Some(WasmExecutionEvent::Exited(code)) => { - assert_eq!(code, 0); - saw_exit = true; - } - Some(WasmExecutionEvent::Stderr(chunk)) => { - panic!("unexpected stderr: {}", String::from_utf8_lossy(&chunk)); - } - Some(WasmExecutionEvent::SyncRpcRequest(_)) => {} - None => panic!("timed out waiting for wasm execution event"), - } - } - - assert!(stdout.is_empty(), "split marker should not leak to stdout"); - assert!( - saw_signal, - "expected reassembled signal-state event before exit" - ); -} - -fn wasm_read_only_tier_blocks_workspace_writes_but_read_write_allows_them() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_write_file_module()); - - let mut engine = WasmExecutionEngine::default(); - let read_only_context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - let read_write_context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (read_only_stdout, read_only_stderr, read_only_exit) = run_wasm_execution( - &mut engine, - read_only_context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::ReadOnly, - ); - - assert_ne!( - read_only_exit, 0, - "read-only tier unexpectedly wrote to workspace: stdout={read_only_stdout} stderr={read_only_stderr}" - ); - assert!( - !temp.path().join("output.txt").exists(), - "read-only tier should not create workspace files" - ); - - let (read_write_stdout, read_write_stderr, read_write_exit) = run_wasm_execution( - &mut engine, - read_write_context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::ReadWrite, - ); - - assert_eq!( - read_write_exit, 0, - "read-write tier should allow workspace writes: stdout={read_write_stdout} stderr={read_write_stderr}" - ); - assert_eq!( - fs::read_to_string(temp.path().join("output.txt")).expect("read output"), - "tiered-write\n" - ); -} - -fn wasm_read_only_tier_returns_rofs_for_write_open() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_expect_write_open_errno_module(69), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::ReadOnly, - ); - - assert_eq!(exit_code, 0, "stdout={stdout} stderr={stderr}"); - assert!(stdout.is_empty(), "stdout={stdout}"); - assert!(stderr.is_empty(), "stderr={stderr}"); - assert!( - !temp.path().join("output.txt").exists(), - "read-only tier should reject write-open before creating the target" - ); -} - -fn wasm_execution_rejects_path_open_escape_outside_preopen() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_escape_preopen_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 0, "stdout={stdout} stderr={stderr}"); - assert!(stdout.is_empty(), "stdout={stdout}"); - assert!(stderr.is_empty(), "stderr={stderr}"); -} - -fn wasm_execution_allows_path_open_for_nested_paths_inside_preopen() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - fs::create_dir_all(temp.path().join("nested")).expect("create nested dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_write_nested_file_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::ReadWrite, - ); - - assert_eq!(exit_code, 0, "stdout={stdout} stderr={stderr}"); - assert!(stdout.is_empty(), "stdout={stdout}"); - assert!(stderr.is_empty(), "stderr={stderr}"); - assert_eq!( - fs::read_to_string(temp.path().join("nested/output.txt")).expect("read nested output"), - "nested-write\n" - ); -} - -fn wasm_full_tier_exposes_host_process_imports_but_read_write_does_not() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_signal_state_module()); - - let mut engine = WasmExecutionEngine::default(); - let full_context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - let read_write_context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (full_stdout, full_stderr, full_exit) = run_wasm_execution( - &mut engine, - full_context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - - assert_eq!(full_exit, 0, "stderr: {full_stderr}"); - assert!(full_stdout.contains("signal:ready")); - - let (_stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - read_write_context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::ReadWrite, - ); - - assert_ne!( - exit_code, 0, - "read-write tier should deny host_process imports" - ); - assert!( - stderr.contains("host_process") || stderr.contains("proc_sigaction"), - "unexpected stderr for denied host_process import: {stderr}" - ); -} - -fn wasm_execution_reuses_shared_warmup_path_across_contexts() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm_stdout_module()); - - let mut engine = WasmExecutionEngine::default(); - let first_context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - let second_context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - let debug_env = - BTreeMap::from([(String::from("AGENTOS_WASM_WARMUP_DEBUG"), String::from("1"))]); - - let (first_stdout, first_stderr, first_exit) = run_wasm_execution( - &mut engine, - first_context.context_id, - temp.path(), - Vec::new(), - debug_env.clone(), - WasmPermissionTier::Full, - ); - let first_warmup = parse_warmup_metrics(&first_stderr); - - assert_eq!(first_exit, 0); - assert!(first_stdout.contains("stdout:wasm-smoke")); - assert!(first_warmup.executed); - assert_eq!(first_warmup.reason, "executed"); - assert_eq!(first_warmup.module_path, "./guest.wasm"); - assert!( - !first_warmup.compile_cache_dir.is_empty(), - "expected shared compile cache dir in metrics" - ); - - let (second_stdout, second_stderr, second_exit) = run_wasm_execution( - &mut engine, - second_context.context_id, - temp.path(), - Vec::new(), - debug_env, - WasmPermissionTier::Full, - ); - let second_warmup = parse_warmup_metrics(&second_stderr); - - assert_eq!(second_exit, 0); - assert!(second_stdout.contains("stdout:wasm-smoke")); - assert!(!second_warmup.executed); - assert_eq!(second_warmup.reason, "cached"); - assert_eq!( - second_warmup.compile_cache_dir, - first_warmup.compile_cache_dir - ); -} - -fn wasm_execution_rewarms_when_symlink_target_changes_with_same_size_module() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let stable_link = temp.path().join("guest.wasm"); - write_fixture(&temp.path().join("good.wasm"), &wasm_stdout_module()); - write_fixture(&temp.path().join("evil.wasm"), &wasm_override_module()); - symlink("./good.wasm", &stable_link).expect("create initial wasm symlink"); - - let mut engine = WasmExecutionEngine::default(); - let first_context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - let second_context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - let debug_env = - BTreeMap::from([(String::from("AGENTOS_WASM_WARMUP_DEBUG"), String::from("1"))]); - - let (first_stdout, first_stderr, first_exit) = run_wasm_execution( - &mut engine, - first_context.context_id, - temp.path(), - Vec::new(), - debug_env.clone(), - WasmPermissionTier::Full, - ); - let first_warmup = parse_warmup_metrics(&first_stderr); - - assert_eq!(first_exit, 0, "stderr: {first_stderr}"); - assert!(first_stdout.contains("stdout:wasm-smoke")); - assert!(first_warmup.executed, "stderr: {first_stderr}"); - - fs::remove_file(&stable_link).expect("remove wasm symlink"); - symlink("./evil.wasm", &stable_link).expect("retarget wasm symlink"); - - let (second_stdout, second_stderr, second_exit) = run_wasm_execution( - &mut engine, - second_context.context_id, - temp.path(), - Vec::new(), - debug_env, - WasmPermissionTier::Full, - ); - let second_warmup = parse_warmup_metrics(&second_stderr); - - assert_eq!(second_exit, 0, "stderr: {second_stderr}"); - assert!(second_stdout.contains("stdout:evil-smoke")); - assert!(second_warmup.executed, "stderr: {second_stderr}"); - assert_eq!(second_warmup.reason, "executed"); -} - -fn wasm_warmup_metrics_encode_emoji_module_paths_as_json() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - let module_name = "guest-😀.wasm"; - write_fixture(&temp.path().join(module_name), &wasm_stdout_module()); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(format!("./{module_name}")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::from([(String::from("AGENTOS_WASM_WARMUP_DEBUG"), String::from("1"))]), - WasmPermissionTier::Full, - ); - let warmup = parse_warmup_metrics(&stderr); - - assert_eq!(exit_code, 0, "stderr: {stderr}"); - assert!(stdout.contains("stdout:wasm-smoke")); - assert!(warmup.executed, "stderr: {stderr}"); - assert_eq!(warmup.module_path, format!("./{module_name}")); - assert!(stderr.contains("\\ud83d\\ude00"), "stderr: {stderr}"); -} - -fn wasm_execution_times_out_when_fuel_budget_is_exhausted() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_infinite_loop_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::from([(String::from(WASM_MAX_FUEL_ENV), String::from("25"))]), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 124, "stdout={stdout} stderr={stderr}"); - assert!(stdout.is_empty(), "stdout={stdout}"); - assert!( - stderr.contains("fuel budget exhausted"), - "stderr should mention the exhausted fuel budget: {stderr}" - ); -} - -fn wasm_execution_poll_path_times_out_when_fuel_budget_is_exhausted() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_infinite_loop_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let mut execution = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: WasmExecutionLimits { - max_fuel: Some(25), - ..Default::default() - }, - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect("start wasm execution"); - - let mut stderr = String::new(); - let mut exit_code = None; - let deadline = std::time::Instant::now() + Duration::from_secs(5); - while exit_code.is_none() { - let remaining = deadline - .checked_duration_since(std::time::Instant::now()) - .expect("poll path did not time out within the bounded test window"); - match execution - .poll_event_blocking(remaining.min(Duration::from_millis(250))) - .expect("poll wasm event") - { - Some(WasmExecutionEvent::Stderr(chunk)) => { - stderr.push_str(&String::from_utf8_lossy(&chunk)); - } - Some(WasmExecutionEvent::Exited(code)) => { - exit_code = Some(code); - } - Some(WasmExecutionEvent::Stdout(_)) - | Some(WasmExecutionEvent::SyncRpcRequest(_)) - | Some(WasmExecutionEvent::SignalState { .. }) - | None => {} - } - } - - assert_eq!(exit_code, Some(124), "stderr={stderr}"); - assert!( - stderr.contains("fuel budget exhausted"), - "stderr should mention the exhausted fuel budget: {stderr}" - ); -} - -fn wasm_execution_allows_prewarm_timeout_to_differ_from_execution_timeout() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_infinite_loop_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::from([(String::from(WASM_MAX_FUEL_ENV), String::from("25"))]), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 124, "stdout={stdout} stderr={stderr}"); - assert!(stdout.is_empty(), "stdout={stdout}"); - assert!( - stderr.contains("fuel budget exhausted"), - "stderr should mention the exhausted fuel budget: {stderr}" - ); -} - -fn wasm_execution_rejects_modules_whose_memory_cap_exceeds_limit() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_memory_capped_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let error = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - // Enforced from the typed wire limit, not an env knob. - limits: WasmExecutionLimits { - max_memory_bytes: Some(2 * 65_536), - ..Default::default() - }, - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect_err("memory limit should reject oversized module maximum"); - - assert!( - error.to_string().contains("memory maximum"), - "unexpected error: {error}" - ); -} - -fn wasm_execution_enforces_runtime_memory_growth_limit_for_modules_without_declared_maximum() { - assert_node_available(); - - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &wasm_memory_grow_until_runtime_limit_module(), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::from([( - String::from(WASM_MAX_MEMORY_BYTES_ENV), - (2 * 65_536_u64).to_string(), - )]), - WasmPermissionTier::Full, - ); - - assert_eq!(exit_code, 0, "stdout={stdout} stderr={stderr}"); - assert!(stderr.is_empty(), "stderr={stderr}"); - assert!( - stdout.contains("memory-grow-limited"), - "stdout should confirm runtime memory.grow enforcement: {stdout}" - ); -} - -fn wasm_execution_rejects_modules_that_exceed_parser_file_size_cap() { - let temp = tempdir().expect("create temp dir"); - let module_path = temp.path().join("guest.wasm"); - let file = fs::File::create(&module_path).expect("create oversize wasm file"); - file.set_len(256_u64 * 1024 * 1024 + 1) - .expect("sparsely size oversize wasm file"); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let error = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - // The memory cap (which gates module-structure validation) is enforced - // from the typed wire limit, not the `AGENTOS_WASM_MAX_MEMORY_BYTES` - // env knob. - limits: WasmExecutionLimits { - max_memory_bytes: Some(65_536), - ..Default::default() - }, - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect_err("oversized module should be rejected before read"); - - assert!( - error - .to_string() - .contains("module file size of 268435457 bytes exceeds the configured parser cap"), - "unexpected error: {error}" - ); -} - -fn wasm_execution_rejects_modules_with_too_many_import_entries() { - let temp = tempdir().expect("create temp dir"); - let mut import_section = encode_varuint(16_385); - import_section.extend_from_slice(&[0x00, 0x00]); - write_fixture( - &temp.path().join("guest.wasm"), - &raw_wasm_module(2, &import_section), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let error = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - // The memory cap (which gates module-structure validation) is enforced - // from the typed wire limit, not the `AGENTOS_WASM_MAX_MEMORY_BYTES` - // env knob. - limits: WasmExecutionLimits { - max_memory_bytes: Some(65_536), - ..Default::default() - }, - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect_err("import cap should reject oversized import section"); - - assert!( - error - .to_string() - .contains("import section contains 16385 entries"), - "unexpected error: {error}" - ); -} - -fn wasm_execution_rejects_modules_with_too_many_memory_entries() { - let temp = tempdir().expect("create temp dir"); - write_fixture( - &temp.path().join("guest.wasm"), - &raw_wasm_module(5, &encode_varuint(1_025)), - ); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let error = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - // The memory cap (which gates module-structure validation) is enforced - // from the typed wire limit, not the `AGENTOS_WASM_MAX_MEMORY_BYTES` - // env knob. - limits: WasmExecutionLimits { - max_memory_bytes: Some(65_536), - ..Default::default() - }, - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect_err("memory cap should reject oversized memory section"); - - assert!( - error - .to_string() - .contains("memory section contains 1025 entries"), - "unexpected error: {error}" - ); -} - -fn wasm_execution_rejects_varuints_that_exceed_parser_iteration_cap() { - let temp = tempdir().expect("create temp dir"); - let mut bytes = Vec::from(*b"\0asm"); - bytes.extend_from_slice(&[0x01, 0x00, 0x00, 0x00]); - bytes.push(5); - bytes.extend_from_slice(&[0x80; 11]); - bytes.push(0x00); - write_fixture(&temp.path().join("guest.wasm"), &bytes); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let error = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - // The memory cap (which gates module-structure validation) is enforced - // from the typed wire limit, not the `AGENTOS_WASM_MAX_MEMORY_BYTES` - // env knob. - limits: WasmExecutionLimits { - max_memory_bytes: Some(65_536), - ..Default::default() - }, - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect_err("varuint cap should reject oversized encodings"); - - assert!( - error - .to_string() - .contains("varuint exceeds the parser cap of 10 bytes"), - "unexpected error: {error}" - ); -} - -// Regression for US-090: a resolved WebAssembly module that turns out to be a -// `node_modules/.bin/` shell-shim script must be rejected by the WASM -// engine with a typed `NonWasmBinary` error BEFORE V8 ever sees the bytes. The -// pre-fix behavior was to base64-encode the `#!/bin/sh` bytes into the prewarm -// env and hand them to `WebAssembly.compile()`, which failed with the opaque -// `CompileError: WebAssembly.Module(): expected magic word 00 61 73 6d, found -// 23 21 2f 62 @+0` cascade that blocked US-088. See -// `.agent/specs/us-090-wasm-warmup-shebang-fix.md` for the full story. -fn wasm_execution_rejects_shell_shim_before_handing_bytes_to_v8() { - let temp = tempdir().expect("create temp dir"); - let node_modules_bin = temp.path().join("node_modules").join(".bin"); - fs::create_dir_all(&node_modules_bin).expect("create node_modules/.bin"); - let shim_path = node_modules_bin.join("fake-shim"); - let shim_script = "#!/bin/sh\n\ -basedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n\ -\n\ -case `uname` in\n\ - *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w \"$basedir\"`;;\n\ -esac\n\ -\n\ -if [ -x \"$basedir/node\" ]; then\n\ - exec \"$basedir/node\" \"$basedir/../fake/dist/cli.js\" \"$@\"\n\ -else\n\ - exec node \"$basedir/../fake/dist/cli.js\" \"$@\"\n\ -fi\n"; - fs::write(&shim_path, shim_script).expect("write shell-shim fixture"); - use std::os::unix::fs::PermissionsExt; - let mut permissions = fs::metadata(&shim_path) - .expect("shim metadata") - .permissions(); - permissions.set_mode(0o755); - fs::set_permissions(&shim_path, permissions).expect("chmod shell-shim"); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(shim_path.to_string_lossy().into_owned()), - }); - - let error = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: vec![shim_path.to_string_lossy().into_owned()], - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect_err("shell shim should be rejected before prewarm/V8"); - - match &error { - secure_exec_execution::WasmExecutionError::NonWasmBinary { - path, - header, - shell_shim, - } => { - assert!( - *shell_shim, - "expected shell_shim=true for shebang header, got header {header:?}" - ); - assert!( - header.starts_with(b"#!"), - "expected header to begin with '#!', got {header:?}" - ); - assert!( - path.ends_with("node_modules/.bin/fake-shim"), - "expected rejected path to name the shim, got {path:?}" - ); - } - other => panic!("expected NonWasmBinary typed error, got {other:?}"), - } - - let rendered = error.to_string(); - assert!( - !rendered.contains("CompileError"), - "rendered error must not mention CompileError (got: {rendered})" - ); - assert!( - !rendered.contains("WebAssembly.Module()"), - "rendered error must not mention WebAssembly.Module() (got: {rendered})" - ); - assert!( - rendered.contains("node_modules/.bin/fake-shim"), - "rendered error must name the resolved shim path (got: {rendered})" - ); - assert!( - rendered.contains("shell-shim"), - "rendered error must describe the shell-shim classification (got: {rendered})" - ); -} - -fn wasm_execution_rejects_random_non_wasm_bytes_with_typed_error() { - let temp = tempdir().expect("create temp dir"); - let module_path = temp.path().join("not-really.wasm"); - fs::write(&module_path, b"hello world, definitely not wasm\n").expect("write non-wasm fixture"); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./not-really.wasm")), - }); - - let error = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect_err("non-wasm file should be rejected before prewarm/V8"); - - match &error { - secure_exec_execution::WasmExecutionError::NonWasmBinary { - header, shell_shim, .. - } => { - assert!( - !*shell_shim, - "expected shell_shim=false for non-#! header, got header {header:?}" - ); - assert_eq!( - header.as_slice(), - b"hell", - "expected first 4 bytes of the fixture, got {header:?}" - ); - } - other => panic!("expected NonWasmBinary typed error, got {other:?}"), - } - - let rendered = error.to_string(); - assert!( - !rendered.contains("CompileError"), - "rendered error must not mention CompileError (got: {rendered})" - ); -} - -fn wasm_execution_rejects_native_binary_headers_with_explicit_error() { - for (file_name, header, expected_format) in [ - ( - "fake-elf.wasm", - b"\x7fELF\x02\x01\x01\x00".as_slice(), - NativeBinaryFormat::Elf, - ), - ( - "fake-macho.wasm", - b"\xfe\xed\xfa\xcf\x00\x00\x00\x00".as_slice(), - NativeBinaryFormat::MachO, - ), - ( - "fake-pe.wasm", - b"MZ\x90\x00\x03\x00\x00\x00".as_slice(), - NativeBinaryFormat::PeCoff, - ), - ] { - let temp = tempdir().expect("create temp dir"); - let module_path = temp.path().join(file_name); - fs::write(&module_path, header).expect("write native-binary fixture"); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(format!("./{file_name}")), - }); - - let error = engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: String::from("vm-wasm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: temp.path().to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect_err("native binary should be rejected before prewarm/V8"); - - match &error { - WasmExecutionError::NativeBinaryNotSupported { - header: observed_header, - format, - .. - } => { - assert_eq!(*format, expected_format); - assert_eq!( - observed_header.as_slice(), - &header[..4], - "expected rejected header bytes for {file_name}" - ); - } - other => panic!("expected NativeBinaryNotSupported typed error, got {other:?}"), - } - - let rendered = error.to_string(); - assert!( - rendered.contains("ERR_NATIVE_BINARY_NOT_SUPPORTED"), - "rendered error must expose the explicit native-binary code (got: {rendered})" - ); - assert!( - rendered.contains(expected_format_display(expected_format)), - "rendered error must name the detected binary format (got: {rendered})" - ); - assert!( - !rendered.contains("CompileError"), - "rendered error must not mention CompileError (got: {rendered})" - ); - } -} - -fn expected_format_display(format: NativeBinaryFormat) -> &'static str { - match format { - NativeBinaryFormat::Elf => "ELF", - NativeBinaryFormat::MachO => "Mach-O", - NativeBinaryFormat::PeCoff => "PE/COFF", - } -} - -// SE-EXEC-05 (B.1 / F-002): never-returning self-recursion. Under a real -// configured stack byte cap (`AGENTOS_WASM_MAX_STACK_BYTES`) this must be bounded -// deterministically and attributed to THAT budget rather than silently ignored. -fn wasm_unbounded_recursion_module() -> Vec { - wat::parse_str( - r#" -(module - (memory (export "memory") 1) - (func $recurse (param $depth i32) (result i32) - (call $recurse (i32.add (local.get $depth) (i32.const 1))) - ) - (func $_start (export "_start") - (drop (call $recurse (i32.const 0))) - ) -) -"#, - ) - .expect("compile unbounded-recursion wasm fixture") -} - -// Watchdog runner for WASM cases that may run unbounded. The whole execution -// (engine + context + wait) happens on a spawned thread, so a guest that the -// engine never terminates cannot hang the test binary: the test thread reclaims -// control after `wall_clock_budget` and reports `None`. -fn run_wasm_execution_with_watchdog( - module_bytes: Vec, - env: BTreeMap, - wall_clock_budget: Duration, -) -> Option<(String, String, i32)> { - let (tx, rx) = mpsc::channel::<(String, String, i32)>(); - thread::spawn(move || { - let temp = match tempdir() { - Ok(temp) => temp, - Err(_) => return, - }; - write_fixture(&temp.path().join("guest.wasm"), &module_bytes); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let result = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - env, - WasmPermissionTier::Full, - ); - let _ = tx.send(result); - }); - - rx.recv_timeout(wall_clock_budget).ok() -} - -// SE-EXEC-05 (B.1) SAFEGUARD [x-ref FAILURES.md#F-002]: with -// `AGENTOS_WASM_MAX_STACK_BYTES` configured, never-returning recursion must be -// terminated nonzero AND the failure must cite the operator-configured stack -// byte budget instead of the engine's generic default-guard message. Before the -// fix the env was never read by the engine (dead cap), so the guest trapped on -// V8's default `RangeError` with a generic message. The run is watchdog-bound so -// it cannot hang CI, and the configured cap makes it terminate fast. -fn wasm_deep_recursion_respects_configured_stack_byte_limit() { - assert_node_available(); - - let env = BTreeMap::from([( - String::from(WASM_MAX_STACK_BYTES_ENV), - String::from("65536"), - )]); - let outcome = run_wasm_execution_with_watchdog( - wasm_unbounded_recursion_module(), - env, - Duration::from_secs(45), - ); - - let (stdout, stderr, exit_code) = - outcome.expect("deep recursion run did not finish within the watchdog budget"); - - assert_ne!( - exit_code, 0, - "deep recursion should be terminated, not run unbounded: stdout={stdout} stderr={stderr}" - ); - assert!( - stderr.contains("65536") || stderr.to_lowercase().contains("configured"), - "termination should cite the configured stack byte limit, not a generic default guard: stderr={stderr}" - ); -} - -// Separate libtest cases in this binary still trip a V8 teardown/init crash, so -// keep the WASM runtime coverage in one top-level suite until that boundary is fixed. -// -// NOT split for cargo-nextest (unlike `python_suite`/`kill_cleanup_suite`): three -// cases here run an infinite-loop guest module (`wasm_execution_times_out_when_ -// fuel_budget_is_exhausted`, `..._poll_path_times_out_...`, `..._allows_prewarm_ -// timeout_to_differ_...`). In this collapsed run they are cheap because earlier -// cases warmed the process-global V8 state, but in a COLD nextest process the -// infinite loop is bounded only by the ~30s V8 CPU-time watchdog, so each costs -// ~30s in isolation and grouping only those three SIGSEGVs (the very shared- -// process teardown crash this suite guards against). Splitting therefore makes -// the binary's wall WORSE (33-92s vs this ~20s collapsed run) and is unsafe, so -// the coverage stays collapsed here. -#[test] -fn wasm_suite() { - wasm_contexts_preserve_vm_and_module_configuration(); - wasm_execution_stays_inside_v8_runtime_without_host_node_launches(); - wasm_execution_runs_guest_module_through_v8(); - wasm_snapshot_runner_block_round_trips_twice(); - wasm_snapshot_runner_warm_worker_pool_hits(); - wasm_snapshot_runner_warm_worker_pool_disabled_falls_back(); - wasm_snapshot_runner_warm_hint_mismatch_falls_back(); - wasm_snapshot_runner_off_fallback_matches_inline(); - wasm_module_bytes_cache_invalidates_when_file_changes(); - wasm_execution_supports_fd_fdstat_set_flags(); - wasm_execution_ignores_guest_overrides_for_internal_node_env(); - wasm_execution_freezes_wasi_clock_time(); - wasm_execution_rejects_vm_mismatch(); - wasm_execution_streams_exit_event(); - wasm_execution_can_route_stdio_through_kernel_sync_rpc(); - wasm_execution_reads_streaming_stdin_via_kernel_bridge(); - wasm_execution_poll_oneoff_uses_kernel_poll_for_multiple_fds(); - wasm_execution_emits_signal_state_from_control_channel(); - wasm_execution_preserves_stdout_when_signal_state_marker_shares_stdout_chunk(); - wasm_execution_reassembles_split_signal_state_marker_across_stdout_chunks(); - wasm_read_only_tier_blocks_workspace_writes_but_read_write_allows_them(); - wasm_read_only_tier_returns_rofs_for_write_open(); - wasm_execution_rejects_path_open_escape_outside_preopen(); - wasm_execution_allows_path_open_for_nested_paths_inside_preopen(); - wasm_full_tier_exposes_host_process_imports_but_read_write_does_not(); - wasm_execution_reuses_shared_warmup_path_across_contexts(); - wasm_execution_rewarms_when_symlink_target_changes_with_same_size_module(); - wasm_warmup_metrics_encode_emoji_module_paths_as_json(); - wasm_execution_times_out_when_fuel_budget_is_exhausted(); - wasm_execution_poll_path_times_out_when_fuel_budget_is_exhausted(); - wasm_execution_allows_prewarm_timeout_to_differ_from_execution_timeout(); - wasm_execution_rejects_modules_whose_memory_cap_exceeds_limit(); - wasm_execution_enforces_runtime_memory_growth_limit_for_modules_without_declared_maximum(); - wasm_execution_rejects_modules_that_exceed_parser_file_size_cap(); - wasm_execution_rejects_modules_with_too_many_import_entries(); - wasm_execution_rejects_modules_with_too_many_memory_entries(); - wasm_execution_rejects_varuints_that_exceed_parser_iteration_cap(); - wasm_execution_rejects_shell_shim_before_handing_bytes_to_v8(); - wasm_execution_rejects_random_non_wasm_bytes_with_typed_error(); - wasm_execution_rejects_native_binary_headers_with_explicit_error(); - - // SE-EXEC-05 (B.1) SAFEGUARD [x-ref FAILURES.md#F-002]: the configured WASM - // stack byte cap must now bound runaway recursion and attribute the failure. - wasm_deep_recursion_respects_configured_stack_byte_limit(); - - // Convergence item C: the official WASI preview1 conformance subset runs on - // the native backend of the SINGLE shared runner (same manifest the browser - // backend runs in packages/browser/tests/browser/wasi-testsuite.spec.ts). - wasi_testsuite_subset_runs_on_native_shared_runner(); -} - -fn wasi_testsuite_subset_runs_on_native_shared_runner() { - assert_node_available(); - - let manifest_source = include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../tests/fixtures/wasi-testsuite-subset.json" - )); - let manifest: serde_json::Value = - serde_json::from_str(manifest_source).expect("parse wasi-testsuite manifest"); - let cases = manifest - .get("cases") - .and_then(serde_json::Value::as_array) - .expect("wasi-testsuite manifest cases"); - assert!(!cases.is_empty(), "wasi-testsuite subset must not be empty"); - - for case in cases { - let name = case - .get("name") - .and_then(serde_json::Value::as_str) - .expect("case name"); - let expected_exit = case - .get("exitCode") - .and_then(serde_json::Value::as_i64) - .expect("case exitCode") as i32; - let expected_stdout = case.get("stdout").and_then(serde_json::Value::as_str); - let wasm = base64::engine::general_purpose::STANDARD - .decode( - case.get("wasmBase64") - .and_then(serde_json::Value::as_str) - .expect("case wasmBase64"), - ) - .expect("decode case wasm"); - - let temp = tempdir().expect("create temp dir"); - write_fixture(&temp.path().join("guest.wasm"), &wasm); - - let mut engine = WasmExecutionEngine::default(); - let context = engine.create_context(CreateWasmContextRequest { - vm_id: String::from("vm-wasm"), - module_path: Some(String::from("./guest.wasm")), - }); - - let (stdout, stderr, exit_code) = run_wasm_execution( - &mut engine, - context.context_id, - temp.path(), - Vec::new(), - BTreeMap::new(), - WasmPermissionTier::Full, - ); - - assert_eq!( - exit_code, expected_exit, - "wasi-testsuite {name}: exit {exit_code} != {expected_exit} (stdout={stdout} stderr={stderr})" - ); - if let Some(expected) = expected_stdout { - assert!( - stdout.contains(expected), - "wasi-testsuite {name}: stdout {stdout:?} missing {expected:?} (stderr={stderr})" - ); - } - } -} diff --git a/crates/kernel/AGENTS.md b/crates/kernel/AGENTS.md deleted file mode 120000 index 681311eb9..000000000 --- a/crates/kernel/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/crates/kernel/CLAUDE.md b/crates/kernel/CLAUDE.md deleted file mode 100644 index 6490451e4..000000000 --- a/crates/kernel/CLAUDE.md +++ /dev/null @@ -1,69 +0,0 @@ -# Kernel - -The kernel provides a POSIX-like userspace environment. The goal is that a program written for Linux should run inside the VM without modification, subject to the execution runtimes available (Node.js, WASM, Python). - -## Linux Compatibility - -- **Correct errno values.** Every kernel operation that fails must return the correct POSIX errno (`ENOENT`, `EACCES`, `EEXIST`, `EISDIR`, `ENOTDIR`, `EXDEV`, `EBADF`, `EPERM`, `ENOSYS`, etc.). Agents check errno values to decide control flow -- wrong errnos cause cascading failures. -- **Standard `/proc` layout.** `/proc/self/`, `/proc/[pid]/`, `/proc/[pid]/fd/`, `/proc/[pid]/environ`, `/proc/[pid]/cwd`, `/proc/[pid]/cmdline` should contain the expected content. -- **Extend procfs surfaces together.** When adding a new `/proc` entry in `crates/kernel/src/kernel.rs`, update path resolution, `read_dir`, read-bytes helpers, stat/lstat sizing, filetype/inode/canonical-path switches, and the focused `crates/kernel/tests/identity.rs` truth suite in the same change so the synthetic proc layer stays internally consistent. -- **Synthetic procfs paths use guest-visible permission subjects.** Permission checks for procfs access should authorize the guest-visible proc path directly rather than resolving through the backing VFS realpath. -- **Hard-link permission checks use different resolvers for source vs destination.** In `crates/kernel/src/permissions.rs`, the existing link source must authorize through `resolved_existing_path(...)` so symlink leaf sources resolve to their real target, while the new link path should still use `resolved_destination_path(...)` for parent-chain authorization. -- **Standard `/dev` devices.** `/dev/null`, `/dev/zero`, `/dev/urandom`, `/dev/stdin`, `/dev/stdout`, `/dev/stderr`, `/dev/fd/*`, `/dev/pts/*` must exist and behave correctly. `/dev/urandom` must return cryptographically random bytes, not deterministic values. -- **Stream-device byte counts belong on length-aware read paths.** For unbounded devices such as `/dev/zero` and `/dev/urandom`, exact Linux-style byte-count assertions should target `pread` / `fd_read` in `device_layer.rs` and kernel FD tests; `read_file()` has no byte-count parameter. -- **Correct signal semantics.** `SIGCHLD` on child exit. `SIGPIPE` on write to broken pipe. `SIGWINCH` on terminal resize. Signal delivery must respect process groups and sessions. -- **Kernel-generated signals must use the mask-aware process-table helpers.** In `crates/kernel/src/process_table.rs`, route `SIGCHLD`/`SIGHUP`/`SIGCONT` and similar internal notifications through the shared queue-or-deliver helpers instead of calling `driver.kill(...)` directly, so blocked signals stay pending until `sigprocmask` unblocks them. -- **Virtual processes should stay on the normal FD table.** For tool-backed child processes, create a regular kernel process entry, wire stdio through fd `0`/`1`/`2` with pipes or PTYs, and use the owner-checked kernel helpers to read stdin, write stdout/stderr, and mark exit instead of introducing side buffers. -- **Kernel `fcntl` state is split between shared descriptions and per-fd entries.** Keep `O_APPEND` on the shared `FileDescription` so dup/fork handles observe the same append mode, but keep `O_NONBLOCK` and `FD_CLOEXEC` on `FdEntry` because they are descriptor-local in the current kernel model. -- **`cleanup_process_resources()` must snapshot and close under one fd-table lock.** If cleanup drops the `fd_tables` lock between collecting descriptors and removing them, a concurrent `dup2` can keep pipe/PTY/socket descriptions alive long enough to skip special-resource teardown and leak the underlying kernel object. -- **`KernelVm` drop-path teardown is easiest to prove in `kernel.rs` unit tests.** When verifying `Drop` or panic-unwind cleanup, clone the private manager handles (`fd_tables`, `pipes`, `ptys`, `sockets`, `driver_pids`) before releasing the VM and assert those clones are empty afterward; external integration tests cannot inspect those counters once the VM is gone. -- **Kernel-owned networking should start in `socket_table.rs`.** Track per-process socket/listener/connection lifecycle there and let `cleanup_process_resources()` reclaim those records on process exit instead of adding ad hoc side counters elsewhere. -- **Kernel socket lifecycle tests should go through `KernelVm` wrappers.** Use `socket_bind_inet`, `socket_listen`, `socket_accept`, and `socket_get` in tests so driver ownership, resource checks, and socket-table state stay exercised together instead of mutating `SocketTable` directly. -- **Kernel TCP data-plane tests should connect peers through `socket_connect_pair()`.** Until listener-routing stories land, build connected stream fixtures with `socket_connect_pair()` and exercise reads, writes, shutdown, and close through the `KernelVm` socket wrappers instead of wiring `SocketTable` peers directly in tests. -- **Kernel loopback-routing coverage should use the explicit loopback wrappers.** Use `socket_connect_inet_loopback()` for guest listener routing and `socket_send_to_inet_loopback()` plus `socket_recv_datagram()` for UDP delivery so tests stay on the in-kernel address-routing path rather than manual pending-connection scaffolds. -- **Loopback stream bind conflicts must stay symmetric with wildcard listeners.** In `crates/kernel/src/socket_table.rs`, binding `127.0.0.1:N` and `0.0.0.0:N` (or `::1:N` and `::N`) on TCP sockets must conflict in either order with `EADDRINUSE`, while distinct specific addresses like `127.0.0.1` vs `127.0.0.2` may still coexist. -- **Kernel UDP tests should assert datagram-boundary truncation.** When a receive buffer is smaller than the payload, `socket_recv_datagram()` should return the truncated payload for that one datagram and leave later queued datagrams untouched; do not test UDP reads like stream partials. -- **Kernel UDP socket-option coverage should stay on the `KernelVm` wrapper surface.** Use `socket_set_datagram_option()`, `socket_add_membership()`, `socket_drop_membership()`, and `socket_get()` in `crates/kernel/tests/udp_datagram.rs` so ownership checks, notifier wiring, and socket-table state all stay exercised together. -- **Kernel Unix-socket tests should use the Unix socket wrappers.** Bind listener and client paths through `socket_bind_unix()`, connect with `socket_connect_unix()`, and accept via `socket_accept()` so path normalization, backlog handling, accepted-socket creation, and stream lifecycle state all stay on the kernel-owned path. -- **Kernel DNS lookups should go through `KernelVm::resolve_dns()`.** Keep hostname normalization, VM overrides, nameserver state, and resolver delegation in `crates/kernel/src/dns.rs`, and have sidecar/runtime callers use `DnsLookupPolicy::CheckPermissions` only for explicit guest DNS APIs. TCP/UDP/HTTP helpers that already gate egress separately should use `SkipPermissions` so the DNS migration does not add a second permission requirement by accident. -- **Mixed readiness tests should use `KernelVm::poll_targets()`.** Build shared poll coverage with `PollTargetEntry::fd(...)` for FD-backed pipes/PTYS and `PollTargetEntry::socket(...)` for socket-table entries so one notifier-driven wait path is exercised across all kernel-managed I/O types. -- **Pipe waiters must retain their requested read length.** In `crates/kernel/src/pipe_manager.rs`, direct writer-to-waiter handoff still has to honor the blocked reader's original `read(fd, len)` byte count; split the payload at that length and buffer any remainder instead of bypassing POSIX `read(2)` semantics. -- **Per-process identity belongs in kernel process metadata, not ad hoc env parsing.** Put uid/gid/euid/egid/group state on `ProcessContext` / `ProcessInfo`, and keep passwd/group rendering in `crates/kernel/src/user.rs` so guest identity syscalls can read kernel-owned values without depending on `/etc/*` or injected env vars. -- **Unknown passwd/group lookups must fail closed.** In `crates/kernel/src/user.rs`, only render entries for the configured guest user and its known group memberships; unknown `getpwuid` / `getgrgid` lookups should map to `ENOENT` instead of synthesizing fake `user123` / `group123` records. -- **FD growth must preserve the global-vs-process errno split.** Any kernel path that allocates a new descriptor slot (`fd_open`, `/dev/fd/*`, proc-backed opens, `dup`, `dup2` when targeting a free slot, `fcntl(F_DUPFD)`) must check the VM-wide open-fd budget before mutating the per-process table so VM exhaustion reports `ENFILE` and per-process exhaustion still reports `EMFILE`. -- **Standard filesystem paths.** `/tmp` must be writable. `/etc/hostname`, `/etc/resolv.conf`, `/etc/passwd`, `/etc/group` should contain valid content. `/usr/bin/env` should exist for shebangs. Shell (`/bin/sh`, `/bin/bash`) must be available. -- **Direct script exec should resolve registered stubs before reparsing files.** When the kernel executes a path under `/bin/` or `/usr/bin/` that corresponds to a registered command driver, dispatch that driver directly before falling back to shebang parsing. -- **Environment variable conventions.** `HOME`, `USER`, `PATH`, `SHELL`, `TERM`, `HOSTNAME`, `PWD`, `LANG` must be set to reasonable values. `PATH` must include standard directories where commands are found. -- **Document deviations in the friction log** at `~/.agents/notes/vm-friction.md`. - -## Virtual Filesystem Design Reference - -- The VFS chunking and metadata architecture is modeled after **JuiceFS** (https://juicefs.com/docs/community/architecture/). Reference JuiceFS docs when designing chunk/block storage, metadata engine separation, or read/write data paths. -- Key JuiceFS concepts that apply: three-tier data model (Chunk/Slice/Block), pluggable metadata engines (SQLite, Redis, PostgreSQL), fixed-size block storage in object stores (S3), and metadata-data separation. -- For detailed design analysis: https://juicefs.com/en/blog/engineering/design-metadata-data-storage - -### Agent-OS filesystem packages - -- The old `fs-sqlite` and `fs-postgres` packages were deleted. They are replaced by the Agent OS `SqliteMetadataStore` and the `ChunkedVFS` composition layer. -- File system drivers live in `registry/file-system/`. Prefer their declarative mount helpers when available; the legacy custom-`VirtualFileSystem` path is only for arbitrary caller-supplied filesystems and compatibility fallbacks. -- The Rivet actor integration currently uses `ChunkedVFS(InMemoryMetadataStore + InMemoryBlockStore)` as legacy temporary infrastructure. This must move to durable metadata and block storage. - -## Filesystem Conventions - -- **OS-level content uses mounts, not post-boot writes.** If agentOS needs custom directories in the VM (e.g., `/etc/agentos/`), mount a pre-populated filesystem at boot -- don't create the kernel and then write files into it afterward. -- **Filesystem semantics must be durable.** Any state that changes filesystem behavior -- including overlay deletes, whiteouts, tombstones, copy-up state, directory entries, inode metadata, or file contents -- must be represented in durable filesystem or metadata storage. No in-memory side tables or transient hacks. -- **Overlay metadata must stay out-of-band from the merged tree.** Store whiteouts or opaque-directory markers under a reserved hidden metadata root and filter that root out of user-visible results. -- **Overlay mutating ops need raw-layer checks plus upper-layer moves.** Once copy-up marks directories opaque, merged `read_dir()` no longer tells you whether lower layers still hold children, so `rmdir`-style emptiness checks must inspect raw upper and lower entries directly. For identity-preserving ops like `rename`, stage the source into the writable upper first and then call the upper filesystem's native `rename`. -- **Overlay raw emptiness scans still need whiteout filtering.** When raw-layer checks walk upper and lower directory entries for `rmdir`, filter each candidate through the upper whiteout markers before deciding the merged directory is non-empty; otherwise a lower-only child that has been whiteouted still forces a false `ENOTEMPTY`. -- **Overlay filesystem behavior must match Linux OverlayFS as closely as possible, including mount-boundary semantics.** Treat the kernel OverlayFS docs as normative. OverlayFS overlays directory trees, not the mount table. Mounted filesystems remain separate mount boundaries, and cross-mount operations must keep normal mount semantics (`EXDEV`, separate identity, separate read-only rules). -- **MountTable unmounts must reject busy parent mounts.** If `/a/b` is still mounted, `MountTable::unmount("/a")` should fail with `EBUSY` instead of removing the parent registration and leaving the child mount dangling. -- **User-facing filesystem APIs should distinguish mounts from layers.** Mounts are separate mounted filesystems presented to the kernel VFS. Layers are overlay-building blocks. Do not collapse those into one generic concept. -- **Middle layers in a Docker-like stack should be frozen layers, not extra writable uppers.** Linux OverlayFS supports one writable upper per overlay mount. Additional stacked layers should be immutable snapshot/materialized lower layers. -- **Layer precedence is highest-first in `lowers`, with bootstrap entries as the writable upper.** When constructing `RootFilesystemDescriptor`, order explicit lower snapshots from highest to lowest precedence, let the bundled base layer fall to the end, and treat `bootstrap_entries` as the single writable upper that overrides the merged lowers. -- **Root filesystem bootstrap must not materialize kernel-owned pseudo-filesystems.** Suppress bootstrap entries under `/dev`, `/proc`, and `/sys` so VM roots do not persist fake storage for paths the kernel owns synthetically. -- **Snapshot-backed VFS invariance tests are the easiest way to prove failed path validation is side-effect free.** In `crates/kernel/tests/vfs.rs`, take a `MemoryFileSystem::snapshot()`, run the invalid-path operation against `MemoryFileSystem::from_snapshot(...)`, and compare the post-op snapshot so rejected paths cannot silently mutate inode metadata or the path index. -- **readdir returns `.` and `..` entries** -- always filter them when iterating children to avoid infinite recursion. -- **`VirtualStat` additions must be propagated end-to-end.** When stat grows new fields, update kernel-backed storage stats, synthetic `/proc` and `/dev` stats, sidecar mount/plugin conversions, sidecar protocol serialization, and the TypeScript `VirtualStat` / `GuestFilesystemStat` adapters together. -- **Creation-mode-sensitive mounts should use the VFS `*_with_mode` hooks.** If a mounted filesystem needs the guest's requested file or directory mode at create time (for example host-backed mounts), thread it through `write_file_with_mode`, `create_file_exclusive_with_mode`, `create_dir_with_mode`, and `mkdir_with_mode` instead of hardcoding defaults and hoping a later chmod is enough. -- **Never interfere with the user's filesystem or code.** Don't write config files, instruction files, or metadata into the user's working directory. Use dedicated OS paths or CLI flags instead. -- **Agent prompt injection must be non-destructive.** Preserve existing user-provided instructions, append rather than replace, and always provide `skipOsInstructions` opt-out. diff --git a/crates/kernel/Cargo.toml b/crates/kernel/Cargo.toml index 0ff6e82d4..eb162ca94 100644 --- a/crates/kernel/Cargo.toml +++ b/crates/kernel/Cargo.toml @@ -4,23 +4,10 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Shared kernel plane for secure-exec native and browser sidecars" +description = "secure-exec-kernel compatibility shim for agentos-kernel" -[dependencies] -secure-exec-bridge = { workspace = true } -vfs = { workspace = true } -base64 = "0.22" -hickory-proto = { version = "0.26.0-beta.3", default-features = false } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -# Drop-in std::time replacement that works on wasm32 (std SystemTime/Instant -# abort there); re-exports std on native. -web-time = "1.1" - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -getrandom = "0.2" -hickory-resolver = "0.26.0-beta.3" -tokio = { version = "1", features = ["rt", "rt-multi-thread"] } +[lib] +name = "secure_exec_kernel" -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } +[dependencies] +agentos_kernel = { package = "agentos-kernel", path = "../../../agentos/crates/kernel", version = "0.0.1" } diff --git a/crates/kernel/src/command_registry.rs b/crates/kernel/src/command_registry.rs deleted file mode 100644 index a2b4d1dbe..000000000 --- a/crates/kernel/src/command_registry.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::vfs::{VfsError, VfsResult, VirtualFileSystem}; -use std::collections::BTreeMap; - -const COMMAND_STUB: &[u8] = b"#!/bin/sh\n# kernel command stub\n"; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CommandDriver { - name: String, - commands: Vec, -} - -impl CommandDriver { - pub fn new(name: N, commands: I) -> Self - where - N: Into, - I: IntoIterator, - C: Into, - { - Self { - name: name.into(), - commands: commands.into_iter().map(Into::into).collect(), - } - } - - pub fn name(&self) -> &str { - &self.name - } - - pub fn commands(&self) -> &[String] { - &self.commands - } - - fn validate_commands(&self) -> VfsResult<()> { - for command in &self.commands { - validate_command_name(command)?; - } - - Ok(()) - } -} - -#[derive(Debug, Default, Clone)] -pub struct CommandRegistry { - commands: BTreeMap, - warnings: Vec, -} - -impl CommandRegistry { - pub fn new() -> Self { - Self::default() - } - - pub fn register(&mut self, driver: CommandDriver) -> VfsResult<()> { - driver.validate_commands()?; - - for command in &driver.commands { - if let Some(existing) = self.commands.get(command) { - self.warnings.push(format!( - "command \"{command}\" overridden: {} -> {}", - existing.name(), - driver.name() - )); - } - - self.commands.insert(command.clone(), driver.clone()); - } - - Ok(()) - } - - pub fn warnings(&self) -> &[String] { - &self.warnings - } - - pub fn resolve(&self, command: &str) -> Option<&CommandDriver> { - self.commands.get(command) - } - - pub fn list(&self) -> BTreeMap { - self.commands - .iter() - .map(|(command, driver)| (command.clone(), driver.name().to_owned())) - .collect() - } - - pub fn populate_bin(&self, vfs: &mut F) -> VfsResult<()> - where - F: VirtualFileSystem, - { - self.populate_commands(vfs, self.commands.keys()) - } - - pub fn populate_driver_bin(&self, vfs: &mut F, driver: &CommandDriver) -> VfsResult<()> - where - F: VirtualFileSystem, - { - self.populate_commands(vfs, driver.commands()) - } - - fn populate_commands(&self, vfs: &mut F, commands: I) -> VfsResult<()> - where - F: VirtualFileSystem, - I: IntoIterator, - S: AsRef, - { - let commands = commands - .into_iter() - .map(|command| { - validate_command_name(command.as_ref())?; - Ok(command.as_ref().to_owned()) - }) - .collect::>>()?; - - if !vfs.exists("/bin") { - vfs.mkdir("/bin", true)?; - } - - for command in commands { - let path = format!("/bin/{command}"); - if !vfs.exists(&path) { - vfs.write_file(&path, COMMAND_STUB.to_vec())?; - let _ = vfs.chmod(&path, 0o755); - } - } - - Ok(()) - } -} - -fn validate_command_name(command: &str) -> VfsResult<()> { - if command.is_empty() - || command == "." - || command == ".." - || command.contains('/') - || command.contains('\0') - { - return Err(VfsError::new( - "EINVAL", - format!("invalid command name {command:?}"), - )); - } - - Ok(()) -} diff --git a/crates/kernel/src/device_layer.rs b/crates/kernel/src/device_layer.rs deleted file mode 100644 index b0729f4ba..000000000 --- a/crates/kernel/src/device_layer.rs +++ /dev/null @@ -1,397 +0,0 @@ -use crate::vfs::{ - VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, VirtualUtimeSpec, -}; -use getrandom::getrandom; -use web_time::{SystemTime, UNIX_EPOCH}; - -const DEVICE_PATHS: &[&str] = &[ - "/dev/null", - "/dev/zero", - "/dev/stdin", - "/dev/stdout", - "/dev/stderr", - "/dev/urandom", -]; - -const DEVICE_DIRS: &[&str] = &["/dev/fd", "/dev/pts"]; -const DEFAULT_STREAM_DEVICE_READ_BYTES: usize = 4096; -const DEV_DIR_ENTRIES: &[(&str, bool)] = &[ - ("null", false), - ("zero", false), - ("stdin", false), - ("stdout", false), - ("stderr", false), - ("urandom", false), - ("fd", true), -]; - -#[derive(Debug, Clone)] -pub struct DeviceLayer { - inner: V, -} - -pub fn create_device_layer(vfs: V) -> DeviceLayer { - DeviceLayer { inner: vfs } -} - -impl DeviceLayer { - pub fn into_inner(self) -> V { - self.inner - } - - pub fn inner(&self) -> &V { - &self.inner - } - - pub fn inner_mut(&mut self) -> &mut V { - &mut self.inner - } -} - -impl VirtualFileSystem for DeviceLayer { - fn read_file(&mut self, path: &str) -> VfsResult> { - if let Some(bytes) = read_stream_device(path, DEFAULT_STREAM_DEVICE_READ_BYTES) { - return bytes; - } - - self.inner.read_file(path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - if path == "/dev" { - return Ok(DEV_DIR_ENTRIES - .iter() - .map(|(name, _)| String::from(*name)) - .collect()); - } - if DEVICE_DIRS.contains(&path) { - return Ok(Vec::new()); - } - self.inner.read_dir(path) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - if path == "/dev" { - let entries = DEV_DIR_ENTRIES - .iter() - .map(|(name, _)| String::from(*name)) - .collect::>(); - if entries.len() > max_entries { - return Err(VfsError::new( - "ENOMEM", - format!( - "directory listing for '{path}' exceeds configured limit of {max_entries} entries" - ), - )); - } - return Ok(entries); - } - if DEVICE_DIRS.contains(&path) { - return Ok(Vec::new()); - } - self.inner.read_dir_limited(path, max_entries) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - if path == "/dev" { - return Ok(DEV_DIR_ENTRIES - .iter() - .map(|(name, is_directory)| VirtualDirEntry { - name: String::from(*name), - is_directory: *is_directory, - is_symbolic_link: false, - }) - .collect()); - } - if DEVICE_DIRS.contains(&path) { - return Ok(Vec::new()); - } - self.inner.read_dir_with_types(path) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - if is_sink_device_path(path) { - let _ = content.into(); - return Ok(()); - } - self.inner.write_file(path, content) - } - - fn create_file_exclusive(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - if is_device_path(path) || is_device_dir(path) { - let _ = content.into(); - return Err(VfsError::new( - "EEXIST", - format!("file already exists, open '{path}'"), - )); - } - self.inner.create_file_exclusive(path, content) - } - - fn append_file(&mut self, path: &str, content: impl Into>) -> VfsResult { - if is_sink_device_path(path) { - return Ok(content.into().len() as u64); - } - self.inner.append_file(path, content) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - if is_device_dir(path) { - return Ok(()); - } - self.inner.create_dir(path) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - if is_device_dir(path) { - return Ok(()); - } - self.inner.mkdir(path, recursive) - } - - fn exists(&self, path: &str) -> bool { - if is_device_path(path) || is_device_dir(path) { - return true; - } - self.inner.exists(path) - } - - fn stat(&mut self, path: &str) -> VfsResult { - if is_device_path(path) { - return Ok(device_stat(path)); - } - if is_device_dir(path) { - return Ok(device_dir_stat(path)); - } - self.inner.stat(path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - if is_device_path(path) { - return Err(VfsError::permission_denied("unlink", path)); - } - self.inner.remove_file(path) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - if is_device_dir(path) { - return Err(VfsError::permission_denied("rmdir", path)); - } - self.inner.remove_dir(path) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - if is_device_path(old_path) || is_device_path(new_path) { - return Err(VfsError::permission_denied("rename", old_path)); - } - self.inner.rename(old_path, new_path) - } - - fn realpath(&self, path: &str) -> VfsResult { - if is_device_path(path) || is_device_dir(path) { - return Ok(String::from(path)); - } - self.inner.realpath(path) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - self.inner.symlink(target, link_path) - } - - fn read_link(&self, path: &str) -> VfsResult { - self.inner.read_link(path) - } - - fn lstat(&self, path: &str) -> VfsResult { - if is_device_path(path) { - return Ok(device_stat(path)); - } - if is_device_dir(path) { - return Ok(device_dir_stat(path)); - } - self.inner.lstat(path) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - if is_device_path(old_path) { - return Err(VfsError::permission_denied("link", old_path)); - } - self.inner.link(old_path, new_path) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - if is_device_path(path) { - return Ok(()); - } - self.inner.chmod(path, mode) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - if is_device_path(path) { - return Ok(()); - } - self.inner.chown(path, uid, gid) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - if is_device_path(path) { - return Ok(()); - } - self.inner.utimes(path, atime_ms, mtime_ms) - } - - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - if is_device_path(path) { - return Ok(()); - } - self.inner.utimes_spec(path, atime, mtime, follow_symlinks) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - if is_sink_device_path(path) { - let _ = length; - return Ok(()); - } - self.inner.truncate(path, length) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - if let Some(bytes) = read_stream_device(path, length) { - return bytes; - } - - self.inner.pread(path, offset, length) - } -} - -fn is_device_path(path: &str) -> bool { - DEVICE_PATHS.contains(&path) || path.starts_with("/dev/fd/") || path.starts_with("/dev/pts/") -} - -/// Standard emulated character devices (`/dev/null`, `/dev/zero`, `/dev/urandom`, -/// `/dev/std{in,out,err}`). On Linux these are world-readable/writable and have no -/// host backing — they are pure kernel emulations whose semantics this device layer -/// already enforces (read/write for the stream devices, `EPERM` for unlink/rename). -/// The permission layer therefore treats them as always accessible, so guest fs ops -/// (`readFileSync`/`existsSync`/redirects on `/dev/null`, …) behave like native Linux -/// regardless of the VM file-permission policy. Excludes `/dev/fd` and `/dev/pts`, -/// which carry process-specific semantics the policy may legitimately govern. -pub fn is_standard_device_path(path: &str) -> bool { - DEVICE_PATHS.contains(&path) -} - -fn is_sink_device_path(path: &str) -> bool { - matches!( - path, - "/dev/null" | "/dev/zero" | "/dev/stdout" | "/dev/stderr" | "/dev/urandom" - ) -} - -fn is_device_dir(path: &str) -> bool { - path == "/dev" || DEVICE_DIRS.contains(&path) -} - -fn device_stat(path: &str) -> VirtualStat { - let now = now_ms(); - VirtualStat { - mode: 0o666, - size: 0, - blocks: 0, - dev: 2, - rdev: device_rdev(path), - is_directory: false, - is_symbolic_link: false, - atime_ms: now, - atime_nsec: 0, - mtime_ms: now, - mtime_nsec: 0, - ctime_ms: now, - ctime_nsec: 0, - birthtime_ms: now, - ino: device_ino(path), - nlink: 1, - uid: 0, - gid: 0, - } -} - -fn device_dir_stat(path: &str) -> VirtualStat { - let now = now_ms(); - VirtualStat { - mode: 0o755, - size: 0, - blocks: 0, - dev: 2, - rdev: 0, - is_directory: true, - is_symbolic_link: false, - atime_ms: now, - atime_nsec: 0, - mtime_ms: now, - mtime_nsec: 0, - ctime_ms: now, - ctime_nsec: 0, - birthtime_ms: now, - ino: device_ino(path), - nlink: 2, - uid: 0, - gid: 0, - } -} - -fn device_ino(path: &str) -> u64 { - match path { - "/dev/null" => 0xffff_0001, - "/dev/zero" => 0xffff_0002, - "/dev/stdin" => 0xffff_0003, - "/dev/stdout" => 0xffff_0004, - "/dev/stderr" => 0xffff_0005, - "/dev/urandom" => 0xffff_0006, - _ => 0xffff_0000, - } -} - -fn device_rdev(path: &str) -> u64 { - match path { - "/dev/null" => encode_device_id(1, 3), - "/dev/zero" => encode_device_id(1, 5), - "/dev/stdin" => encode_device_id(5, 0), - "/dev/stdout" => encode_device_id(5, 1), - "/dev/stderr" => encode_device_id(5, 2), - "/dev/urandom" => encode_device_id(1, 9), - _ => 0, - } -} - -fn encode_device_id(major: u64, minor: u64) -> u64 { - (major << 8) | minor -} - -fn random_bytes(length: usize) -> VfsResult> { - let mut buffer = vec![0; length]; - getrandom(&mut buffer) - .map_err(|error| VfsError::io(format!("failed to read system random bytes: {error}")))?; - Ok(buffer) -} - -fn read_stream_device(path: &str, length: usize) -> Option>> { - match path { - "/dev/null" => Some(Ok(Vec::new())), - "/dev/zero" => Some(Ok(vec![0; length])), - "/dev/urandom" => Some(random_bytes(length)), - _ => None, - } -} - -fn now_ms() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as u64 -} diff --git a/crates/kernel/src/dns.rs b/crates/kernel/src/dns.rs deleted file mode 100644 index d0111835b..000000000 --- a/crates/kernel/src/dns.rs +++ /dev/null @@ -1,679 +0,0 @@ -use hickory_proto::rr::domain::Name; -use hickory_proto::rr::rdata::{A, AAAA}; -use hickory_proto::rr::{RData, Record, RecordType}; -#[cfg(not(target_arch = "wasm32"))] -use hickory_resolver::config::{NameServerConfig, ResolverConfig}; -#[cfg(not(target_arch = "wasm32"))] -use hickory_resolver::net::runtime::TokioRuntimeProvider; -#[cfg(not(target_arch = "wasm32"))] -use hickory_resolver::TokioResolver; -use std::collections::{BTreeMap, BTreeSet}; -use std::error::Error; -use std::fmt; -use std::net::{IpAddr, SocketAddr}; -#[cfg(not(target_arch = "wasm32"))] -use std::net::{Ipv4Addr, Ipv6Addr}; -use std::sync::Arc; -#[cfg(not(target_arch = "wasm32"))] -use std::sync::{mpsc, Mutex}; - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct DnsConfig { - pub name_servers: Vec, - pub overrides: BTreeMap>, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DnsLookupPolicy { - CheckPermissions, - SkipPermissions, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DnsLookupRequest { - hostname: String, - name_servers: Vec, -} - -impl DnsLookupRequest { - pub fn new(hostname: impl Into, name_servers: Vec) -> Self { - Self { - hostname: hostname.into(), - name_servers, - } - } - - pub fn hostname(&self) -> &str { - &self.hostname - } - - pub fn name_servers(&self) -> &[SocketAddr] { - &self.name_servers - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DnsRecordLookupRequest { - hostname: String, - name_servers: Vec, - record_type: RecordType, -} - -impl DnsRecordLookupRequest { - pub fn new( - hostname: impl Into, - name_servers: Vec, - record_type: RecordType, - ) -> Self { - Self { - hostname: hostname.into(), - name_servers, - record_type, - } - } - - pub fn hostname(&self) -> &str { - &self.hostname - } - - pub fn name_servers(&self) -> &[SocketAddr] { - &self.name_servers - } - - pub const fn record_type(&self) -> RecordType { - self.record_type - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DnsResolutionSource { - Literal, - Override, - Resolver, -} - -impl DnsResolutionSource { - pub const fn as_str(self) -> &'static str { - match self { - Self::Literal => "literal", - Self::Override => "override", - Self::Resolver => "resolver", - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DnsResolution { - hostname: String, - source: DnsResolutionSource, - addresses: Vec, -} - -impl DnsResolution { - pub fn new( - hostname: impl Into, - source: DnsResolutionSource, - addresses: Vec, - ) -> Self { - Self { - hostname: hostname.into(), - source, - addresses, - } - } - - pub fn hostname(&self) -> &str { - &self.hostname - } - - pub const fn source(&self) -> DnsResolutionSource { - self.source - } - - pub fn addresses(&self) -> &[IpAddr] { - &self.addresses - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DnsRecordResolution { - hostname: String, - source: DnsResolutionSource, - records: Vec, -} - -impl DnsRecordResolution { - pub fn new( - hostname: impl Into, - source: DnsResolutionSource, - records: Vec, - ) -> Self { - Self { - hostname: hostname.into(), - source, - records, - } - } - - pub fn hostname(&self) -> &str { - &self.hostname - } - - pub const fn source(&self) -> DnsResolutionSource { - self.source - } - - pub fn records(&self) -> &[Record] { - &self.records - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DnsResolverErrorKind { - InvalidInput, - LookupFailed, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DnsResolverError { - kind: DnsResolverErrorKind, - message: String, -} - -impl DnsResolverError { - pub fn invalid_input(message: impl Into) -> Self { - Self { - kind: DnsResolverErrorKind::InvalidInput, - message: message.into(), - } - } - - pub fn lookup_failed(message: impl Into) -> Self { - Self { - kind: DnsResolverErrorKind::LookupFailed, - message: message.into(), - } - } - - pub const fn kind(&self) -> DnsResolverErrorKind { - self.kind - } -} - -impl fmt::Display for DnsResolverError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.message) - } -} - -impl Error for DnsResolverError {} - -pub trait DnsResolver { - fn lookup_ip(&self, request: &DnsLookupRequest) -> Result, DnsResolverError>; - fn lookup_records( - &self, - request: &DnsRecordLookupRequest, - ) -> Result, DnsResolverError>; -} - -pub type SharedDnsResolver = Arc; - -#[cfg(not(target_arch = "wasm32"))] -pub struct HickoryDnsResolver { - worker: Mutex>, -} - -/// On wasm the kernel has no tokio runtime or host DNS stack, so the resolver is -/// a unit type whose `DnsResolver` impl reports that name resolution is -/// unavailable; guests must supply DNS overrides or literal addresses. -#[cfg(target_arch = "wasm32")] -pub struct HickoryDnsResolver; - -#[cfg(not(target_arch = "wasm32"))] -enum DnsWorkerRequest { - LookupIp { - hostname: String, - name_servers: Vec, - response: mpsc::Sender, DnsResolverError>>, - }, - LookupRecords { - hostname: String, - name_servers: Vec, - record_type: RecordType, - response: mpsc::Sender, DnsResolverError>>, - }, -} - -#[cfg(not(target_arch = "wasm32"))] -impl Default for HickoryDnsResolver { - fn default() -> Self { - let (sender, receiver) = mpsc::channel(); - std::thread::Builder::new() - .name("secure-exec-dns-resolver".to_owned()) - .spawn(move || run_dns_worker(receiver)) - .expect("failed to spawn DNS resolver worker"); - Self { - worker: Mutex::new(sender), - } - } -} - -#[cfg(target_arch = "wasm32")] -impl Default for HickoryDnsResolver { - fn default() -> Self { - Self - } -} - -#[cfg(not(target_arch = "wasm32"))] -impl HickoryDnsResolver { - fn send_lookup_ip( - &self, - hostname: String, - name_servers: Vec, - ) -> Result, DnsResolverError> { - let (response, receiver) = mpsc::channel(); - self.worker - .lock() - .unwrap_or_else(|poisoned| poisoned.into_inner()) - .send(DnsWorkerRequest::LookupIp { - hostname, - name_servers, - response, - }) - .map_err(|_| DnsResolverError::lookup_failed("dns resolver worker stopped"))?; - receiver - .recv() - .map_err(|_| DnsResolverError::lookup_failed("dns resolver worker stopped"))? - } - - fn send_lookup_records( - &self, - hostname: String, - name_servers: Vec, - record_type: RecordType, - ) -> Result, DnsResolverError> { - let (response, receiver) = mpsc::channel(); - self.worker - .lock() - .unwrap_or_else(|poisoned| poisoned.into_inner()) - .send(DnsWorkerRequest::LookupRecords { - hostname, - name_servers, - record_type, - response, - }) - .map_err(|_| DnsResolverError::lookup_failed("dns resolver worker stopped"))?; - receiver - .recv() - .map_err(|_| DnsResolverError::lookup_failed("dns resolver worker stopped"))? - } -} - -#[cfg(not(target_arch = "wasm32"))] -impl DnsResolver for HickoryDnsResolver { - fn lookup_ip(&self, request: &DnsLookupRequest) -> Result, DnsResolverError> { - self.send_lookup_ip( - request.hostname().to_owned(), - request.name_servers().to_vec(), - ) - } - - fn lookup_records( - &self, - request: &DnsRecordLookupRequest, - ) -> Result, DnsResolverError> { - self.send_lookup_records( - request.hostname().to_owned(), - request.name_servers().to_vec(), - request.record_type(), - ) - } -} - -#[cfg(not(target_arch = "wasm32"))] -fn run_dns_worker(receiver: mpsc::Receiver) { - let runtime = match tokio::runtime::Runtime::new() { - Ok(runtime) => runtime, - Err(error) => { - for request in receiver { - request.respond_with_error(DnsResolverError::lookup_failed(format!( - "failed to create DNS runtime: {error}" - ))); - } - return; - } - }; - let mut resolvers = BTreeMap::new(); - for request in receiver { - match request { - DnsWorkerRequest::LookupIp { - hostname, - name_servers, - response, - } => { - let result = worker_lookup_ip(&runtime, &mut resolvers, hostname, name_servers); - let _ = response.send(result); - } - DnsWorkerRequest::LookupRecords { - hostname, - name_servers, - record_type, - response, - } => { - let result = worker_lookup_records( - &runtime, - &mut resolvers, - hostname, - name_servers, - record_type, - ); - let _ = response.send(result); - } - } - } -} - -#[cfg(not(target_arch = "wasm32"))] -impl DnsWorkerRequest { - fn respond_with_error(self, error: DnsResolverError) { - match self { - Self::LookupIp { response, .. } => { - let _ = response.send(Err(error)); - } - Self::LookupRecords { response, .. } => { - let _ = response.send(Err(error)); - } - } - } -} - -#[cfg(not(target_arch = "wasm32"))] -fn worker_resolver_for( - resolvers: &mut BTreeMap, TokioResolver>, - name_servers: &[SocketAddr], -) -> Result { - let key = name_servers.to_vec(); - if let Some(resolver) = resolvers.get(&key).cloned() { - return Ok(resolver); - } - - let resolver_config = resolver_config_from_name_servers(name_servers); - let builder = if let Some(config) = resolver_config { - TokioResolver::builder_with_config(config, TokioRuntimeProvider::default()) - } else { - TokioResolver::builder_tokio().map_err(|error| { - DnsResolverError::lookup_failed(format!( - "failed to initialize DNS resolver from system configuration: {error}" - )) - })? - }; - let resolver = builder.build().map_err(|error| { - DnsResolverError::lookup_failed(format!("failed to build DNS resolver: {error}")) - })?; - let resolver = resolvers.entry(key).or_insert_with(|| resolver).clone(); - Ok(resolver) -} - -#[cfg(not(target_arch = "wasm32"))] -fn worker_lookup_ip( - runtime: &tokio::runtime::Runtime, - resolvers: &mut BTreeMap, TokioResolver>, - hostname: String, - name_servers: Vec, -) -> Result, DnsResolverError> { - let resolver = worker_resolver_for(resolvers, &name_servers)?; - runtime.block_on(async move { - let lookup = resolver.lookup_ip(&hostname).await.map_err(|error| { - DnsResolverError::lookup_failed(format!( - "failed to resolve DNS address {hostname}: {error}" - )) - })?; - - let mut addresses = Vec::new(); - let mut seen = BTreeSet::new(); - for ip in lookup.iter() { - if seen.insert(ip) { - addresses.push(ip); - } - } - - if addresses.is_empty() { - return Err(DnsResolverError::lookup_failed(format!( - "failed to resolve DNS address {hostname}" - ))); - } - - Ok(addresses) - }) -} - -#[cfg(not(target_arch = "wasm32"))] -fn worker_lookup_records( - runtime: &tokio::runtime::Runtime, - resolvers: &mut BTreeMap, TokioResolver>, - hostname: String, - name_servers: Vec, - record_type: RecordType, -) -> Result, DnsResolverError> { - let resolver = worker_resolver_for(resolvers, &name_servers)?; - runtime.block_on(async move { - let lookup = resolver - .lookup(&hostname, record_type) - .await - .map_err(|error| { - DnsResolverError::lookup_failed(format!( - "failed to resolve DNS {record_type} record {hostname}: {error}" - )) - })?; - let records = lookup.answers().to_vec(); - if records.is_empty() { - return Err(DnsResolverError::lookup_failed(format!( - "failed to resolve DNS {record_type} record {hostname}" - ))); - } - Ok(records) - }) -} - -#[cfg(target_arch = "wasm32")] -impl DnsResolver for HickoryDnsResolver { - fn lookup_ip(&self, request: &DnsLookupRequest) -> Result, DnsResolverError> { - Err(DnsResolverError::lookup_failed(format!( - "browser sidecar DNS resolver is unavailable for {}; configure DNS overrides or pass a literal address", - request.hostname() - ))) - } - - fn lookup_records( - &self, - request: &DnsRecordLookupRequest, - ) -> Result, DnsResolverError> { - Err(DnsResolverError::lookup_failed(format!( - "browser sidecar DNS record resolver is unavailable for {}; configure DNS overrides or pass a literal address", - request.hostname() - ))) - } -} - -pub fn normalize_dns_hostname(hostname: &str) -> Result { - let normalized = hostname.trim().trim_end_matches('.').to_ascii_lowercase(); - if normalized.is_empty() { - return Err(DnsResolverError::invalid_input( - "DNS hostname must not be empty", - )); - } - Ok(normalized) -} - -pub fn format_dns_resource(hostname: &str) -> Result { - Ok(format!("dns://{}", canonical_dns_subject(hostname)?)) -} - -pub fn resolve_dns( - config: &DnsConfig, - resolver: &dyn DnsResolver, - hostname: &str, -) -> Result { - let trimmed = hostname.trim(); - if let Ok(ip_addr) = trimmed.parse::() { - return Ok(DnsResolution::new( - ip_addr.to_string(), - DnsResolutionSource::Literal, - vec![ip_addr], - )); - } - - let normalized_hostname = normalize_dns_hostname(trimmed)?; - if let Some(addresses) = config.overrides.get(&normalized_hostname) { - return Ok(DnsResolution::new( - normalized_hostname, - DnsResolutionSource::Override, - addresses.clone(), - )); - } - - let request = DnsLookupRequest::new(normalized_hostname.clone(), config.name_servers.clone()); - let addresses = resolver.lookup_ip(&request)?; - if addresses.is_empty() { - return Err(DnsResolverError::lookup_failed(format!( - "failed to resolve DNS address {normalized_hostname}" - ))); - } - - Ok(DnsResolution::new( - normalized_hostname, - DnsResolutionSource::Resolver, - dedupe_addresses(addresses), - )) -} - -pub fn resolve_dns_records( - config: &DnsConfig, - resolver: &dyn DnsResolver, - hostname: &str, - record_type: RecordType, -) -> Result { - let trimmed = hostname.trim(); - let normalized_hostname = normalize_dns_hostname(trimmed)?; - let owner_name = normalized_hostname.parse::().map_err(|error| { - DnsResolverError::invalid_input(format!("invalid DNS hostname: {error}")) - })?; - - if let Some(records) = records_from_literal(trimmed, owner_name.clone(), record_type) { - return Ok(DnsRecordResolution::new( - normalized_hostname, - DnsResolutionSource::Literal, - records, - )); - } - - if let Some(addresses) = config.overrides.get(&normalized_hostname) { - let records = records_from_addresses(owner_name.clone(), addresses, record_type); - if !records.is_empty() { - return Ok(DnsRecordResolution::new( - normalized_hostname, - DnsResolutionSource::Override, - records, - )); - } - } - - let request = DnsRecordLookupRequest::new( - normalized_hostname.clone(), - config.name_servers.clone(), - record_type, - ); - let records = resolver.lookup_records(&request)?; - if records.is_empty() { - return Err(DnsResolverError::lookup_failed(format!( - "failed to resolve DNS {record_type} record {normalized_hostname}" - ))); - } - - Ok(DnsRecordResolution::new( - normalized_hostname, - DnsResolutionSource::Resolver, - records, - )) -} - -fn canonical_dns_subject(hostname: &str) -> Result { - let trimmed = hostname.trim(); - if let Ok(ip_addr) = trimmed.parse::() { - return Ok(ip_addr.to_string()); - } - - normalize_dns_hostname(trimmed) -} - -#[cfg(not(target_arch = "wasm32"))] -fn resolver_config_from_name_servers(name_servers: &[SocketAddr]) -> Option { - if name_servers.is_empty() { - return None; - } - - let name_servers = name_servers - .iter() - .map(|server| { - let mut config = NameServerConfig::udp_and_tcp(server.ip()); - for connection in &mut config.connections { - connection.port = server.port(); - connection.bind_addr = Some(SocketAddr::new( - if server.is_ipv6() { - IpAddr::V6(Ipv6Addr::UNSPECIFIED) - } else { - IpAddr::V4(Ipv4Addr::UNSPECIFIED) - }, - 0, - )); - } - config - }) - .collect(); - - Some(ResolverConfig::from_parts(None, vec![], name_servers)) -} - -fn dedupe_addresses(addresses: Vec) -> Vec { - let mut deduped = Vec::with_capacity(addresses.len()); - let mut seen = BTreeSet::new(); - for address in addresses { - if seen.insert(address) { - deduped.push(address); - } - } - deduped -} - -fn records_from_literal( - hostname: &str, - owner_name: Name, - record_type: RecordType, -) -> Option> { - let ip_addr = hostname.parse::().ok()?; - let records = records_from_addresses(owner_name, &[ip_addr], record_type); - if records.is_empty() { - return None; - } - Some(records) -} - -fn records_from_addresses( - owner_name: Name, - addresses: &[IpAddr], - record_type: RecordType, -) -> Vec { - addresses - .iter() - .filter_map(|ip| match (record_type, ip) { - (RecordType::A, IpAddr::V4(ipv4)) | (RecordType::ANY, IpAddr::V4(ipv4)) => Some( - Record::from_rdata(owner_name.clone(), 60, RData::A(A::from(*ipv4))), - ), - (RecordType::AAAA, IpAddr::V6(ipv6)) | (RecordType::ANY, IpAddr::V6(ipv6)) => Some( - Record::from_rdata(owner_name.clone(), 60, RData::AAAA(AAAA::from(*ipv6))), - ), - _ => None, - }) - .collect() -} diff --git a/crates/kernel/src/fd_table.rs b/crates/kernel/src/fd_table.rs deleted file mode 100644 index 3e57be8ec..000000000 --- a/crates/kernel/src/fd_table.rs +++ /dev/null @@ -1,994 +0,0 @@ -use std::collections::{btree_map::Values, BTreeMap, BTreeSet}; -use std::error::Error; -use std::fmt; -use std::sync::atomic::{AtomicU32, AtomicU64, AtomicUsize, Ordering}; -use std::sync::{Arc, Condvar, Mutex, MutexGuard}; - -pub const MAX_FDS_PER_PROCESS: usize = 256; - -pub const O_RDONLY: u32 = 0; -pub const O_WRONLY: u32 = 1; -pub const O_RDWR: u32 = 2; -pub const O_CREAT: u32 = 0o100; -pub const O_EXCL: u32 = 0o200; -pub const O_TRUNC: u32 = 0o1000; -pub const O_APPEND: u32 = 0o2000; -pub const O_NONBLOCK: u32 = 0o4000; -pub const F_DUPFD: u32 = 0; -pub const F_GETFD: u32 = 1; -pub const F_SETFD: u32 = 2; -pub const F_GETFL: u32 = 3; -pub const F_SETFL: u32 = 4; -pub const FD_CLOEXEC: u32 = 1; -pub const LOCK_SH: u32 = 1; -pub const LOCK_EX: u32 = 2; -pub const LOCK_NB: u32 = 4; -pub const LOCK_UN: u32 = 8; - -pub const FILETYPE_UNKNOWN: u8 = 0; -pub const FILETYPE_CHARACTER_DEVICE: u8 = 2; -pub const FILETYPE_DIRECTORY: u8 = 3; -pub const FILETYPE_REGULAR_FILE: u8 = 4; -pub const FILETYPE_PIPE: u8 = 6; -pub const FILETYPE_SYMBOLIC_LINK: u8 = 7; - -pub type FdResult = Result; -pub type SharedFileDescription = Arc; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FdTableError { - code: &'static str, - message: String, -} - -impl FdTableError { - pub fn code(&self) -> &'static str { - self.code - } - - fn bad_file_descriptor(fd: u32) -> Self { - Self { - code: "EBADF", - message: format!("bad file descriptor {fd}"), - } - } - - fn too_many_open_files() -> Self { - Self { - code: "EMFILE", - message: String::from("too many open files"), - } - } - - fn invalid_argument(message: impl Into) -> Self { - Self { - code: "EINVAL", - message: message.into(), - } - } - - fn would_block(message: impl Into) -> Self { - Self { - code: "EWOULDBLOCK", - message: message.into(), - } - } -} - -impl fmt::Display for FdTableError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for FdTableError {} - -#[derive(Debug)] -pub struct FileDescription { - id: u64, - path: String, - lock_target: Option, - cursor: AtomicU64, - flags: AtomicU32, - ref_count: AtomicUsize, -} - -impl FileDescription { - pub fn new(id: u64, path: impl Into, flags: u32) -> Self { - Self::with_ref_count_and_lock(id, path, flags, 1, None) - } - - pub fn new_with_lock( - id: u64, - path: impl Into, - flags: u32, - lock_target: Option, - ) -> Self { - Self::with_ref_count_and_lock(id, path, flags, 1, lock_target) - } - - pub fn with_ref_count(id: u64, path: impl Into, flags: u32, ref_count: usize) -> Self { - Self::with_ref_count_and_lock(id, path, flags, ref_count, None) - } - - pub fn with_ref_count_and_lock( - id: u64, - path: impl Into, - flags: u32, - ref_count: usize, - lock_target: Option, - ) -> Self { - Self { - id, - path: path.into(), - lock_target, - cursor: AtomicU64::new(0), - flags: AtomicU32::new(flags), - ref_count: AtomicUsize::new(ref_count), - } - } - - pub fn id(&self) -> u64 { - self.id - } - - pub fn path(&self) -> &str { - &self.path - } - - pub fn lock_target(&self) -> Option { - self.lock_target - } - - pub fn cursor(&self) -> u64 { - self.cursor.load(Ordering::SeqCst) - } - - pub fn set_cursor(&self, cursor: u64) { - self.cursor.store(cursor, Ordering::SeqCst); - } - - pub fn flags(&self) -> u32 { - self.flags.load(Ordering::SeqCst) - } - - pub fn update_flags(&self, mask: u32, flags: u32) -> u32 { - let mut current = self.flags(); - loop { - let next = (current & !mask) | (flags & mask); - match self - .flags - .compare_exchange(current, next, Ordering::SeqCst, Ordering::SeqCst) - { - Ok(_) => return next, - Err(observed) => current = observed, - } - } - } - - pub fn ref_count(&self) -> usize { - self.ref_count.load(Ordering::SeqCst) - } - - pub fn increment_ref_count(&self) -> usize { - self.ref_count.fetch_add(1, Ordering::SeqCst) + 1 - } - - pub fn decrement_ref_count(&self) -> usize { - let mut current = self.ref_count.load(Ordering::SeqCst); - loop { - let next = current.saturating_sub(1); - match self - .ref_count - .compare_exchange(current, next, Ordering::SeqCst, Ordering::SeqCst) - { - Ok(_) => return next, - Err(observed) => current = observed, - } - } - } -} - -#[derive(Debug, Clone)] -pub struct FdEntry { - pub fd: u32, - pub description: SharedFileDescription, - pub status_flags: u32, - pub fd_flags: u32, - pub rights: u64, - pub filetype: u8, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct FdStat { - pub filetype: u8, - pub flags: u32, - pub rights: u64, -} - -#[derive(Debug, Clone)] -pub struct StdioOverride { - pub description: SharedFileDescription, - pub filetype: u8, -} - -#[derive(Debug, Clone)] -struct DescriptionFactory { - next_description_id: Arc, -} - -impl DescriptionFactory { - fn new(starting_id: u64) -> Self { - Self { - next_description_id: Arc::new(AtomicU64::new(starting_id)), - } - } - - fn allocate(&self, path: &str, flags: u32) -> SharedFileDescription { - self.allocate_with_lock(path, flags, None) - } - - fn allocate_with_lock( - &self, - path: &str, - flags: u32, - lock_target: Option, - ) -> SharedFileDescription { - let next_id = self.next_description_id.fetch_add(1, Ordering::SeqCst); - Arc::new(FileDescription::new_with_lock( - next_id, - path, - flags, - lock_target, - )) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct FileLockTarget { - ino: u64, -} - -impl FileLockTarget { - pub const fn new(ino: u64) -> Self { - Self { ino } - } - - pub const fn ino(self) -> u64 { - self.ino - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum FileLockMode { - Shared, - Exclusive, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FlockOperation { - Shared { nonblocking: bool }, - Exclusive { nonblocking: bool }, - Unlock, -} - -impl FlockOperation { - pub fn from_bits(operation: u32) -> FdResult { - let nonblocking = operation & LOCK_NB != 0; - match operation & !LOCK_NB { - LOCK_SH => Ok(Self::Shared { nonblocking }), - LOCK_EX => Ok(Self::Exclusive { nonblocking }), - LOCK_UN => Ok(Self::Unlock), - _ => Err(FdTableError::invalid_argument(format!( - "invalid flock operation {operation:#x}" - ))), - } - } -} - -#[derive(Debug, Clone)] -pub struct ProcessFdTable { - entries: BTreeMap, - next_fd: u32, - alloc_desc: DescriptionFactory, - max_fds: usize, -} - -impl ProcessFdTable { - fn new(alloc_desc: DescriptionFactory, max_fds: usize) -> Self { - Self { - entries: BTreeMap::new(), - next_fd: 3, - alloc_desc, - max_fds, - } - } - - pub fn max_fds(&self) -> usize { - self.max_fds - } - - pub fn init_stdio( - &mut self, - stdin_desc: SharedFileDescription, - stdout_desc: SharedFileDescription, - stderr_desc: SharedFileDescription, - ) { - self.entries.insert( - 0, - FdEntry { - fd: 0, - description: stdin_desc, - status_flags: 0, - fd_flags: 0, - rights: 0, - filetype: FILETYPE_CHARACTER_DEVICE, - }, - ); - self.entries.insert( - 1, - FdEntry { - fd: 1, - description: stdout_desc, - status_flags: 0, - fd_flags: 0, - rights: 0, - filetype: FILETYPE_CHARACTER_DEVICE, - }, - ); - self.entries.insert( - 2, - FdEntry { - fd: 2, - description: stderr_desc, - status_flags: 0, - fd_flags: 0, - rights: 0, - filetype: FILETYPE_CHARACTER_DEVICE, - }, - ); - } - - pub fn init_stdio_with_types( - &mut self, - stdin_desc: SharedFileDescription, - stdin_type: u8, - stdout_desc: SharedFileDescription, - stdout_type: u8, - stderr_desc: SharedFileDescription, - stderr_type: u8, - ) { - stdin_desc.increment_ref_count(); - stdout_desc.increment_ref_count(); - stderr_desc.increment_ref_count(); - self.entries.insert( - 0, - FdEntry { - fd: 0, - description: stdin_desc, - status_flags: 0, - fd_flags: 0, - rights: 0, - filetype: stdin_type, - }, - ); - self.entries.insert( - 1, - FdEntry { - fd: 1, - description: stdout_desc, - status_flags: 0, - fd_flags: 0, - rights: 0, - filetype: stdout_type, - }, - ); - self.entries.insert( - 2, - FdEntry { - fd: 2, - description: stderr_desc, - status_flags: 0, - fd_flags: 0, - rights: 0, - filetype: stderr_type, - }, - ); - } - - pub fn open(&mut self, path: &str, flags: u32) -> FdResult { - self.open_with_details(path, flags, FILETYPE_REGULAR_FILE, None) - } - - pub fn open_with_filetype(&mut self, path: &str, flags: u32, filetype: u8) -> FdResult { - self.open_with_details(path, flags, filetype, None) - } - - pub fn open_with_details( - &mut self, - path: &str, - flags: u32, - filetype: u8, - lock_target: Option, - ) -> FdResult { - let fd = self.allocate_fd()?; - let description = - self.alloc_desc - .allocate_with_lock(path, description_flags(flags), lock_target); - self.entries.insert( - fd, - FdEntry { - fd, - description, - status_flags: status_flags(flags), - fd_flags: 0, - rights: 0, - filetype, - }, - ); - Ok(fd) - } - - pub fn open_with( - &mut self, - description: SharedFileDescription, - filetype: u8, - target_fd: Option, - ) -> FdResult { - let fd = match target_fd { - Some(fd) => { - self.validate_fd_bounds(fd)?; - if self.entries.contains_key(&fd) { - self.close(fd); - } - fd - } - None => self.allocate_fd()?, - }; - description.increment_ref_count(); - self.entries.insert( - fd, - FdEntry { - fd, - description, - status_flags: 0, - fd_flags: 0, - rights: 0, - filetype, - }, - ); - Ok(fd) - } - - pub fn get(&self, fd: u32) -> Option<&FdEntry> { - self.entries.get(&fd) - } - - pub fn close(&mut self, fd: u32) -> bool { - let Some(entry) = self.entries.remove(&fd) else { - return false; - }; - entry.description.decrement_ref_count(); - true - } - - pub fn dup(&mut self, fd: u32) -> FdResult { - self.dup_with_status_flags(fd, None) - } - - pub fn dup_with_status_flags( - &mut self, - fd: u32, - status_flags_override: Option, - ) -> FdResult { - let entry = self - .entries - .get(&fd) - .cloned() - .ok_or_else(|| FdTableError::bad_file_descriptor(fd))?; - let new_fd = self.allocate_fd()?; - self.duplicate_entry( - &entry, - new_fd, - status_flags_override.unwrap_or(entry.status_flags), - 0, - ) - } - - pub fn dup2(&mut self, old_fd: u32, new_fd: u32) -> FdResult<()> { - let entry = self - .entries - .get(&old_fd) - .cloned() - .ok_or_else(|| FdTableError::bad_file_descriptor(old_fd))?; - self.validate_fd_bounds(new_fd)?; - if old_fd == new_fd { - return Ok(()); - } - - if self.entries.contains_key(&new_fd) { - self.close(new_fd); - } - - self.duplicate_entry(&entry, new_fd, entry.status_flags, 0)?; - Ok(()) - } - - pub fn stat(&self, fd: u32) -> FdResult { - let entry = self - .entries - .get(&fd) - .ok_or_else(|| FdTableError::bad_file_descriptor(fd))?; - Ok(FdStat { - filetype: entry.filetype, - flags: visible_fd_flags(entry.description.flags(), entry.status_flags), - rights: entry.rights, - }) - } - - pub fn fcntl(&mut self, fd: u32, command: u32, arg: u32) -> FdResult { - match command { - F_DUPFD => { - let entry = self - .entries - .get(&fd) - .cloned() - .ok_or_else(|| FdTableError::bad_file_descriptor(fd))?; - let min_fd = self.validate_fcntl_dup_min(arg)?; - let new_fd = self.allocate_fd_from(min_fd)?; - self.duplicate_entry(&entry, new_fd, entry.status_flags, 0) - } - F_GETFD => { - let entry = self - .entries - .get(&fd) - .ok_or_else(|| FdTableError::bad_file_descriptor(fd))?; - Ok(entry.fd_flags & FD_CLOEXEC) - } - F_SETFD => { - let entry = self - .entries - .get_mut(&fd) - .ok_or_else(|| FdTableError::bad_file_descriptor(fd))?; - entry.fd_flags = arg & FD_CLOEXEC; - Ok(0) - } - F_GETFL => { - let entry = self - .entries - .get(&fd) - .ok_or_else(|| FdTableError::bad_file_descriptor(fd))?; - Ok(visible_fd_flags( - entry.description.flags(), - entry.status_flags, - )) - } - F_SETFL => { - let entry = self - .entries - .get_mut(&fd) - .ok_or_else(|| FdTableError::bad_file_descriptor(fd))?; - entry.status_flags = arg & ENTRY_STATUS_FLAG_MASK; - entry.description.update_flags(SHARED_STATUS_FLAG_MASK, arg); - Ok(0) - } - _ => Err(FdTableError::invalid_argument(format!( - "unsupported fcntl command {command}" - ))), - } - } - - pub fn fork(&self) -> Self { - let mut child = Self::new(self.alloc_desc.clone(), self.max_fds); - child.next_fd = self.next_fd; - - for (fd, entry) in &self.entries { - entry.description.increment_ref_count(); - child.entries.insert( - *fd, - FdEntry { - fd: *fd, - description: Arc::clone(&entry.description), - status_flags: entry.status_flags, - fd_flags: entry.fd_flags, - rights: entry.rights, - filetype: entry.filetype, - }, - ); - } - - child - } - - pub fn close_all(&mut self) { - let fds: Vec = self.entries.keys().copied().collect(); - for fd in fds { - self.close(fd); - } - } - - pub fn len(&self) -> usize { - self.entries.len() - } - - pub fn is_empty(&self) -> bool { - self.entries.is_empty() - } - - pub fn iter(&self) -> Values<'_, u32, FdEntry> { - self.entries.values() - } - - fn allocate_fd(&mut self) -> FdResult { - if self.entries.len() >= self.max_fds { - return Err(FdTableError::too_many_open_files()); - } - - let start = usize::try_from(self.next_fd).unwrap_or(0) % self.max_fds; - for offset in 0..self.max_fds { - let candidate = ((start + offset) % self.max_fds) as u32; - if !self.entries.contains_key(&candidate) { - self.next_fd = candidate.saturating_add(1); - return Ok(candidate); - } - } - - Err(FdTableError::too_many_open_files()) - } - - fn allocate_fd_from(&mut self, min_fd: u32) -> FdResult { - if self.entries.len() >= self.max_fds { - return Err(FdTableError::too_many_open_files()); - } - - if min_fd as usize >= self.max_fds { - return Err(FdTableError::invalid_argument(format!( - "fd {min_fd} exceeds process fd limit" - ))); - } - - for candidate in min_fd..self.max_fds as u32 { - if !self.entries.contains_key(&candidate) { - self.next_fd = candidate.saturating_add(1); - return Ok(candidate); - } - } - - Err(FdTableError::too_many_open_files()) - } - - fn duplicate_entry( - &mut self, - entry: &FdEntry, - new_fd: u32, - status_flags: u32, - fd_flags: u32, - ) -> FdResult { - entry.description.increment_ref_count(); - self.entries.insert( - new_fd, - FdEntry { - fd: new_fd, - description: Arc::clone(&entry.description), - status_flags, - fd_flags, - rights: entry.rights, - filetype: entry.filetype, - }, - ); - Ok(new_fd) - } - - fn validate_fd_bounds(&self, fd: u32) -> FdResult<()> { - if fd as usize >= self.max_fds { - return Err(FdTableError::bad_file_descriptor(fd)); - } - Ok(()) - } - - fn validate_fcntl_dup_min(&self, min_fd: u32) -> FdResult { - if min_fd as usize >= self.max_fds { - return Err(FdTableError::invalid_argument(format!( - "fd {min_fd} exceeds process fd limit" - ))); - } - Ok(min_fd) - } -} - -fn description_flags(flags: u32) -> u32 { - flags & !status_flags(flags) -} - -fn status_flags(flags: u32) -> u32 { - flags & ENTRY_STATUS_FLAG_MASK -} - -fn visible_fd_flags(description_flags: u32, entry_status_flags: u32) -> u32 { - (description_flags & (0b11 | SHARED_STATUS_FLAG_MASK)) - | (entry_status_flags & ENTRY_STATUS_FLAG_MASK) -} - -const SHARED_STATUS_FLAG_MASK: u32 = O_APPEND; -const ENTRY_STATUS_FLAG_MASK: u32 = O_NONBLOCK; - -impl<'a> IntoIterator for &'a ProcessFdTable { - type Item = &'a FdEntry; - type IntoIter = Values<'a, u32, FdEntry>; - - fn into_iter(self) -> Self::IntoIter { - self.entries.values() - } -} - -#[derive(Debug, Clone)] -pub struct FdTableManager { - tables: BTreeMap, - alloc_desc: DescriptionFactory, - max_fds: usize, -} - -impl Default for FdTableManager { - fn default() -> Self { - Self { - tables: BTreeMap::new(), - alloc_desc: DescriptionFactory::new(1), - max_fds: MAX_FDS_PER_PROCESS, - } - } -} - -impl FdTableManager { - pub fn new() -> Self { - Self::default() - } - - pub fn with_max_fds(max_fds: usize) -> Self { - Self { - max_fds, - ..Self::default() - } - } - - pub fn create(&mut self, pid: u32) -> &mut ProcessFdTable { - let mut table = ProcessFdTable::new(self.alloc_desc.clone(), self.max_fds); - table.init_stdio( - self.alloc_desc.allocate("/dev/stdin", O_RDONLY), - self.alloc_desc.allocate("/dev/stdout", O_WRONLY), - self.alloc_desc.allocate("/dev/stderr", O_WRONLY), - ); - self.remove(pid); - self.tables.insert(pid, table); - self.tables - .get_mut(&pid) - .expect("newly created FD table should be stored") - } - - pub fn create_with_stdio( - &mut self, - pid: u32, - stdin_override: Option, - stdout_override: Option, - stderr_override: Option, - ) -> &mut ProcessFdTable { - let mut table = ProcessFdTable::new(self.alloc_desc.clone(), self.max_fds); - let stdin_desc = stdin_override - .as_ref() - .map(|entry| Arc::clone(&entry.description)) - .unwrap_or_else(|| self.alloc_desc.allocate("/dev/stdin", O_RDONLY)); - let stdout_desc = stdout_override - .as_ref() - .map(|entry| Arc::clone(&entry.description)) - .unwrap_or_else(|| self.alloc_desc.allocate("/dev/stdout", O_WRONLY)); - let stderr_desc = stderr_override - .as_ref() - .map(|entry| Arc::clone(&entry.description)) - .unwrap_or_else(|| self.alloc_desc.allocate("/dev/stderr", O_WRONLY)); - - table.init_stdio_with_types( - stdin_desc, - stdin_override - .as_ref() - .map(|entry| entry.filetype) - .unwrap_or(FILETYPE_CHARACTER_DEVICE), - stdout_desc, - stdout_override - .as_ref() - .map(|entry| entry.filetype) - .unwrap_or(FILETYPE_CHARACTER_DEVICE), - stderr_desc, - stderr_override - .as_ref() - .map(|entry| entry.filetype) - .unwrap_or(FILETYPE_CHARACTER_DEVICE), - ); - self.remove(pid); - self.tables.insert(pid, table); - self.tables - .get_mut(&pid) - .expect("newly created FD table should be stored") - } - - pub fn fork(&mut self, parent_pid: u32, child_pid: u32) -> &mut ProcessFdTable { - if !self.tables.contains_key(&parent_pid) { - return self.create(child_pid); - } - - let child = self - .tables - .get(&parent_pid) - .expect("parent table presence was checked") - .fork(); - self.remove(child_pid); - self.tables.insert(child_pid, child); - self.tables - .get_mut(&child_pid) - .expect("forked FD table should be stored") - } - - pub fn get(&self, pid: u32) -> Option<&ProcessFdTable> { - self.tables.get(&pid) - } - - pub fn get_mut(&mut self, pid: u32) -> Option<&mut ProcessFdTable> { - self.tables.get_mut(&pid) - } - - pub fn has(&self, pid: u32) -> bool { - self.tables.contains_key(&pid) - } - - pub fn len(&self) -> usize { - self.tables.len() - } - - pub fn is_empty(&self) -> bool { - self.tables.is_empty() - } - - pub fn total_open_fds(&self) -> usize { - self.tables.values().map(ProcessFdTable::len).sum() - } - - pub fn pids(&self) -> Vec { - self.tables.keys().copied().collect() - } - - pub fn remove(&mut self, pid: u32) { - if let Some(mut table) = self.tables.remove(&pid) { - table.close_all(); - } - } -} - -#[derive(Debug, Clone, Default)] -pub struct FileLockManager { - inner: Arc, -} - -#[derive(Debug, Default)] -struct FileLockManagerInner { - state: Mutex, - wake: Condvar, -} - -#[derive(Debug, Default)] -struct FileLockState { - entries: BTreeMap, -} - -#[derive(Debug, Default)] -struct FileLockEntry { - shared: BTreeSet, - exclusive: Option, -} - -impl FileLockManager { - pub fn new() -> Self { - Self::default() - } - - pub fn apply( - &self, - owner_id: u64, - target: FileLockTarget, - operation: FlockOperation, - ) -> FdResult<()> { - match operation { - FlockOperation::Shared { nonblocking } => { - self.acquire(owner_id, target, FileLockMode::Shared, nonblocking) - } - FlockOperation::Exclusive { nonblocking } => { - self.acquire(owner_id, target, FileLockMode::Exclusive, nonblocking) - } - FlockOperation::Unlock => { - self.release_owner(owner_id); - Ok(()) - } - } - } - - pub fn release_owner(&self, owner_id: u64) -> bool { - let mut state = lock_or_recover(&self.inner.state); - let mut released = false; - state.entries.retain(|_, entry| { - let entry_changed = entry.shared.remove(&owner_id) || entry.exclusive == Some(owner_id); - if entry.exclusive == Some(owner_id) { - entry.exclusive = None; - } - released |= entry_changed; - !entry.is_empty() - }); - drop(state); - if released { - self.inner.wake.notify_all(); - } - released - } - - fn acquire( - &self, - owner_id: u64, - target: FileLockTarget, - mode: FileLockMode, - nonblocking: bool, - ) -> FdResult<()> { - let mut state = lock_or_recover(&self.inner.state); - loop { - let entry = state.entries.entry(target).or_default(); - if entry.can_grant(owner_id, mode) { - entry.grant(owner_id, mode); - return Ok(()); - } - - if nonblocking { - return Err(FdTableError::would_block( - "advisory file lock is unavailable", - )); - } - - state = wait_or_recover(&self.inner.wake, state); - } - } -} - -impl FileLockEntry { - fn can_grant(&self, owner_id: u64, mode: FileLockMode) -> bool { - match mode { - FileLockMode::Shared => self.exclusive.is_none_or(|owner| owner == owner_id), - FileLockMode::Exclusive => { - self.exclusive.is_none_or(|owner| owner == owner_id) - && self.shared.iter().all(|owner| *owner == owner_id) - } - } - } - - fn grant(&mut self, owner_id: u64, mode: FileLockMode) { - match mode { - FileLockMode::Shared => { - self.exclusive = None; - self.shared.insert(owner_id); - } - FileLockMode::Exclusive => { - self.shared.retain(|owner| *owner != owner_id); - self.exclusive = Some(owner_id); - } - } - } - - fn is_empty(&self) -> bool { - self.exclusive.is_none() && self.shared.is_empty() - } -} - -fn lock_or_recover(mutex: &Mutex) -> MutexGuard<'_, T> { - mutex - .lock() - .unwrap_or_else(|poisoned| poisoned.into_inner()) -} - -fn wait_or_recover<'a, T>(condvar: &Condvar, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { - condvar - .wait(guard) - .unwrap_or_else(|poisoned| poisoned.into_inner()) -} diff --git a/crates/kernel/src/kernel.rs b/crates/kernel/src/kernel.rs deleted file mode 100644 index abb5ab248..000000000 --- a/crates/kernel/src/kernel.rs +++ /dev/null @@ -1,5626 +0,0 @@ -use crate::bridge::LifecycleState; -use crate::command_registry::{CommandDriver, CommandRegistry}; -use crate::device_layer::{create_device_layer, DeviceLayer}; -use crate::dns::{ - format_dns_resource, resolve_dns, resolve_dns_records, DnsConfig, DnsLookupPolicy, - DnsRecordResolution, DnsResolution, DnsResolverErrorKind, HickoryDnsResolver, - SharedDnsResolver, -}; -use crate::fd_table::{ - FdEntry, FdStat, FdTableError, FdTableManager, FileDescription, FileLockManager, - FileLockTarget, FlockOperation, ProcessFdTable, FILETYPE_CHARACTER_DEVICE, FILETYPE_DIRECTORY, - FILETYPE_PIPE, FILETYPE_REGULAR_FILE, FILETYPE_SYMBOLIC_LINK, F_DUPFD, O_APPEND, O_CREAT, - O_EXCL, O_NONBLOCK, O_TRUNC, -}; -use crate::mount_table::{MountEntry, MountOptions, MountTable, MountedFileSystem}; -use crate::network_policy::format_tcp_resource; -use crate::permissions::{ - check_command_execution, check_network_access, FsOperation, NetworkOperation, PermissionError, - PermissionedFileSystem, Permissions, -}; -use crate::pipe_manager::{PipeError, PipeManager}; -use crate::poll::{ - PollEvents, PollFd, PollNotifier, PollResult, PollTarget, PollTargetEntry, PollTargetResult, - POLLERR, POLLHUP, POLLIN, POLLNVAL, POLLOUT, -}; -use crate::process_table::{ - DriverProcess, ProcessContext, ProcessExitCallback, ProcessInfo, ProcessStatus, ProcessTable, - ProcessTableError, ProcessWaitResult, SigmaskHow, SignalSet, DEFAULT_PROCESS_UMASK, SIGCONT, - SIGPIPE, SIGSTOP, SIGTSTP, SIGWINCH, -}; -use crate::pty::{ - LineDisciplineConfig, PartialTermios, PtyError, PtyManager, PtyWindowSize, Termios, -}; -use crate::resource_accounting::{ - measure_filesystem_usage, FileSystemUsage, ResourceAccountant, ResourceError, ResourceLimits, - ResourceSnapshot, DEFAULT_MAX_OPEN_FDS, -}; -use crate::root_fs::{RootFileSystem, RootFilesystemError, RootFilesystemSnapshot}; -use crate::socket_table::{ - DatagramSocketOption, InetSocketAddress, ReceivedDatagram, SocketId, SocketMulticastMembership, - SocketReadiness, SocketRecord, SocketShutdown, SocketSpec, SocketState, SocketTable, - SocketTableError, SocketType, -}; -use crate::user::{ProcessIdentity, UserConfig, UserManager}; -use crate::vfs::{ - normalize_path, VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, - VirtualTimeSpec, VirtualUtimeSpec, -}; -use hickory_proto::rr::RecordType; -use std::any::Any; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::error::Error; -use std::fmt; -#[cfg(test)] -use std::sync::OnceLock; -use std::sync::{Arc, Condvar, Mutex, MutexGuard, WaitTimeoutResult}; -use std::time::Duration; -use web_time::{Instant, SystemTime, UNIX_EPOCH}; - -pub type KernelResult = Result; -pub use crate::process_table::{ProcessWaitEvent as WaitPidEvent, WaitPidFlags}; - -pub const SEEK_SET: u8 = 0; -pub const SEEK_CUR: u8 = 1; -pub const SEEK_END: u8 = 2; -const EXECUTABLE_PERMISSION_BITS: u32 = 0o111; -const SHEBANG_LINE_MAX_BYTES: usize = 256; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct KernelError { - code: &'static str, - message: String, -} - -impl KernelError { - pub fn code(&self) -> &'static str { - self.code - } - - fn new(code: &'static str, message: impl Into) -> Self { - Self { - code, - message: message.into(), - } - } - - fn disposed() -> Self { - Self::new("EINVAL", "kernel VM is disposed") - } - - fn no_such_process(pid: u32) -> Self { - Self::new("ESRCH", format!("no such process {pid}")) - } - - fn bad_file_descriptor(fd: u32) -> Self { - Self::new("EBADF", format!("bad file descriptor {fd}")) - } - - fn permission_denied(message: impl Into) -> Self { - Self::new("EPERM", message) - } - - fn command_not_found(command: &str) -> Self { - Self::new("ENOENT", format!("command not found: {command}")) - } -} - -impl fmt::Display for KernelError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for KernelError {} - -#[derive(Clone)] -pub struct KernelVmConfig { - pub vm_id: String, - pub env: BTreeMap, - pub cwd: String, - pub user: UserConfig, - pub permissions: Permissions, - pub loopback_exempt_ports: BTreeSet, - pub dns: DnsConfig, - pub dns_resolver: SharedDnsResolver, - pub resources: ResourceLimits, - pub zombie_ttl: Duration, -} - -impl KernelVmConfig { - pub fn new(vm_id: impl Into) -> Self { - Self { - vm_id: vm_id.into(), - env: BTreeMap::new(), - cwd: String::from("/workspace"), - user: UserConfig::default(), - permissions: Permissions::default(), - loopback_exempt_ports: BTreeSet::new(), - dns: DnsConfig::default(), - dns_resolver: Arc::new(HickoryDnsResolver::default()), - resources: ResourceLimits::default(), - zombie_ttl: Duration::from_secs(60), - } - } -} - -#[derive(Debug, Clone, Default)] -pub struct SpawnOptions { - pub requester_driver: Option, - pub parent_pid: Option, - pub env: BTreeMap, - pub cwd: Option, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct VirtualProcessOptions { - pub parent_pid: Option, - pub env: BTreeMap, - pub cwd: Option, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct ExecOptions { - pub requester_driver: Option, - pub parent_pid: Option, - pub env: BTreeMap, - pub cwd: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RecursiveDirEntry { - pub path: String, - pub is_directory: bool, - pub is_symbolic_link: bool, - pub size: u64, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct OpenShellOptions { - pub requester_driver: Option, - pub command: Option, - pub args: Vec, - pub env: BTreeMap, - pub cwd: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WaitPidResult { - pub pid: u32, - pub status: i32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WaitPidEventResult { - pub pid: u32, - pub status: i32, - pub event: WaitPidEvent, -} - -#[derive(Debug, Clone)] -struct ResolvedSpawnCommand { - command: String, - args: Vec, - driver: CommandDriver, -} - -#[derive(Debug, Clone)] -struct ShebangCommand { - interpreter: String, - args: Vec, -} - -#[derive(Clone)] -pub struct KernelProcessHandle { - pid: u32, - driver: String, - process: Arc, -} - -impl fmt::Debug for KernelProcessHandle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("KernelProcessHandle") - .field("pid", &self.pid) - .field("driver", &self.driver) - .finish_non_exhaustive() - } -} - -impl KernelProcessHandle { - pub fn pid(&self) -> u32 { - self.pid - } - - pub fn driver(&self) -> &str { - &self.driver - } - - pub fn finish(&self, exit_code: i32) { - self.process.finish(exit_code); - } - - pub fn kill(&self, signal: i32) { - self.process.kill(signal); - } - - pub fn wait(&self, timeout: Duration) -> Option { - self.process.wait(timeout) - } - - pub fn kill_signals(&self) -> Vec { - self.process.kill_signals() - } -} - -#[derive(Debug, Clone)] -pub struct OpenShellHandle { - process: KernelProcessHandle, - master_fd: u32, - slave_fd: u32, - pty_path: String, -} - -impl OpenShellHandle { - pub fn process(&self) -> &KernelProcessHandle { - &self.process - } - - pub fn pid(&self) -> u32 { - self.process.pid() - } - - pub fn master_fd(&self) -> u32 { - self.master_fd - } - - pub fn slave_fd(&self) -> u32 { - self.slave_fd - } - - pub fn pty_path(&self) -> &str { - &self.pty_path - } -} - -pub struct KernelVm { - vm_id: String, - boot_time_ms: u64, - boot_instant: Instant, - filesystem: PermissionedFileSystem>, - permissions: Permissions, - loopback_exempt_ports: BTreeSet, - dns: DnsConfig, - dns_resolver: SharedDnsResolver, - env: BTreeMap, - cwd: String, - commands: CommandRegistry, - fd_tables: Arc>, - processes: ProcessTable, - pipes: PipeManager, - ptys: PtyManager, - sockets: SocketTable, - poll_notifier: PollNotifier, - users: UserManager, - resources: ResourceAccountant, - filesystem_usage_cache: Option, - file_locks: FileLockManager, - driver_pids: Arc>>>, - terminated: bool, -} - -fn cleanup_process_resources( - fd_tables: &Mutex, - file_locks: &FileLockManager, - pipes: &PipeManager, - ptys: &PtyManager, - sockets: &SocketTable, - driver_pids: &Mutex>>, - pid: u32, -) { - let mut cleanup = Vec::new(); - { - let mut tables = lock_or_recover(fd_tables); - let descriptors = tables - .get(pid) - .map(|table| { - table - .iter() - .map(|entry| (entry.fd, Arc::clone(&entry.description), entry.filetype)) - .collect::>() - }) - .unwrap_or_default(); - - cleanup_process_resources_test_hook(); - - if let Some(table) = tables.get_mut(pid) { - for (fd, description, filetype) in &descriptors { - table.close(*fd); - cleanup.push((Arc::clone(description), *filetype)); - } - } - tables.remove(pid); - } - - for (description, filetype) in cleanup { - close_special_resource_if_needed(file_locks, pipes, ptys, &description, filetype); - } - - sockets.remove_all_for_pid(pid); - - let mut owners = lock_or_recover(driver_pids); - for pids in owners.values_mut() { - pids.remove(&pid); - } -} - -fn dispose_kernel_vm_resources(kernel: &mut KernelVm) { - kernel.processes.terminate_all(); - let pids = lock_or_recover(&kernel.fd_tables).pids(); - for pid in pids { - cleanup_process_resources( - kernel.fd_tables.as_ref(), - &kernel.file_locks, - &kernel.pipes, - &kernel.ptys, - &kernel.sockets, - kernel.driver_pids.as_ref(), - pid, - ); - } - lock_or_recover(&kernel.driver_pids).clear(); - kernel.terminated = true; -} - -#[cfg(test)] -type CleanupProcessResourcesHook = Arc; - -#[cfg(test)] -fn cleanup_process_resources_test_hook() { - let hook = lock_or_recover(cleanup_process_resources_test_hook_slot()).clone(); - if let Some(hook) = hook { - hook(); - } -} - -#[cfg(not(test))] -fn cleanup_process_resources_test_hook() {} - -#[cfg(test)] -fn cleanup_process_resources_test_hook_slot() -> &'static Mutex> -{ - static HOOK: OnceLock>> = OnceLock::new(); - HOOK.get_or_init(|| Mutex::new(None)) -} - -#[cfg(test)] -fn set_cleanup_process_resources_test_hook(hook: Option) { - *lock_or_recover(cleanup_process_resources_test_hook_slot()) = hook; -} - -fn close_special_resource_if_needed( - file_locks: &FileLockManager, - pipes: &PipeManager, - ptys: &PtyManager, - description: &Arc, - filetype: u8, -) { - if description.ref_count() != 0 { - return; - } - - file_locks.release_owner(description.id()); - - if filetype == FILETYPE_PIPE && pipes.is_pipe(description.id()) { - pipes.close(description.id()); - } - - if ptys.is_pty(description.id()) { - ptys.close(description.id()); - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum ProcNode { - RootDir, - MountsFile, - CpuInfoFile, - MemInfoFile, - LoadAvgFile, - UptimeFile, - VersionFile, - SelfLink { pid: u32 }, - PidDir { pid: u32 }, - PidFdDir { pid: u32 }, - PidCmdline { pid: u32 }, - PidEnviron { pid: u32 }, - PidCwdLink { pid: u32 }, - PidStatFile { pid: u32 }, - PidStatusFile { pid: u32 }, - PidFdLink { pid: u32, fd: u32 }, -} - -impl KernelVm { - pub fn new(filesystem: F, config: KernelVmConfig) -> Self { - let vm_id = config.vm_id; - let boot_time_ms = now_ms(); - let boot_instant = Instant::now(); - let permissions = config.permissions.clone(); - let users = UserManager::from_config(config.user); - let process_table = ProcessTable::with_zombie_ttl(config.zombie_ttl); - let process_table_for_pty = process_table.clone(); - let fd_tables = Arc::new(Mutex::new(FdTableManager::with_max_fds( - config - .resources - .max_open_fds - .unwrap_or(DEFAULT_MAX_OPEN_FDS), - ))); - let file_locks = FileLockManager::new(); - let driver_pids = Arc::new(Mutex::new(BTreeMap::new())); - let poll_notifier = PollNotifier::default(); - let pipes = PipeManager::with_notifier(poll_notifier.clone()); - let ptys = PtyManager::with_signal_handler_and_notifier( - Arc::new(move |pgid, signal| { - let _ = process_table_for_pty.kill(-(pgid as i32), signal); - }), - poll_notifier.clone(), - ); - let sockets = SocketTable::new(); - - let fd_tables_for_exit = Arc::clone(&fd_tables); - let file_locks_for_exit = file_locks.clone(); - let driver_pids_for_exit = Arc::clone(&driver_pids); - let pipes_for_exit = pipes.clone(); - let ptys_for_exit = ptys.clone(); - let sockets_for_exit = sockets.clone(); - process_table.set_on_process_exit(Some(Arc::new(move |pid| { - cleanup_process_resources( - fd_tables_for_exit.as_ref(), - &file_locks_for_exit, - &pipes_for_exit, - &ptys_for_exit, - &sockets_for_exit, - driver_pids_for_exit.as_ref(), - pid, - ); - }))); - - let filesystem = PermissionedFileSystem::new( - create_device_layer(filesystem), - vm_id.clone(), - permissions.clone(), - ); - // Usage accounting is kernel-internal: the cache is populated lazily by - // `filesystem_usage()` through the RAW filesystem so no guest-attributable - // permission check fires at construction (or ever) for quota bookkeeping. - let filesystem_usage_cache = None; - - Self { - vm_id: vm_id.clone(), - boot_time_ms, - boot_instant, - filesystem, - permissions, - loopback_exempt_ports: config.loopback_exempt_ports, - dns: config.dns, - dns_resolver: config.dns_resolver, - env: config.env, - cwd: config.cwd, - commands: CommandRegistry::new(), - fd_tables, - processes: process_table, - pipes, - ptys, - sockets, - poll_notifier, - users, - resources: ResourceAccountant::new(config.resources), - filesystem_usage_cache, - file_locks, - driver_pids, - terminated: false, - } - } - - pub fn vm_id(&self) -> &str { - &self.vm_id - } - - pub fn state(&self) -> LifecycleState { - if self.terminated { - LifecycleState::Terminated - } else if self.processes.running_count() > 0 { - LifecycleState::Busy - } else { - LifecycleState::Ready - } - } - - pub fn commands(&self) -> BTreeMap { - self.commands.list() - } - - pub fn filesystem(&self) -> &PermissionedFileSystem> { - &self.filesystem - } - - pub fn filesystem_mut(&mut self) -> &mut PermissionedFileSystem> { - &mut self.filesystem - } - - pub fn user_manager(&self) -> &UserManager { - &self.users - } - - pub fn environment(&self) -> &BTreeMap { - &self.env - } - - pub fn process_identity( - &self, - requester_driver: &str, - pid: u32, - ) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - Ok(self - .processes - .get(pid) - .ok_or_else(|| KernelError::no_such_process(pid))? - .identity) - } - - pub fn user_profile(&self) -> UserManager { - self.users.clone() - } - - pub fn getuid(&self, requester_driver: &str, pid: u32) -> KernelResult { - Ok(self.process_identity(requester_driver, pid)?.uid) - } - - pub fn getgid(&self, requester_driver: &str, pid: u32) -> KernelResult { - Ok(self.process_identity(requester_driver, pid)?.gid) - } - - pub fn geteuid(&self, requester_driver: &str, pid: u32) -> KernelResult { - Ok(self.process_identity(requester_driver, pid)?.euid) - } - - pub fn getegid(&self, requester_driver: &str, pid: u32) -> KernelResult { - Ok(self.process_identity(requester_driver, pid)?.egid) - } - - pub fn getgroups(&self, requester_driver: &str, pid: u32) -> KernelResult> { - Ok(self - .process_identity(requester_driver, pid)? - .supplementary_gids) - } - - pub fn getpwuid(&self, uid: u32) -> KernelResult { - self.users - .getpwuid(uid) - .ok_or_else(|| KernelError::new("ENOENT", format!("unknown uid {uid}"))) - } - - pub fn getgrgid(&self, gid: u32) -> KernelResult { - self.users - .getgrgid(gid) - .ok_or_else(|| KernelError::new("ENOENT", format!("unknown gid {gid}"))) - } - - pub fn resource_snapshot(&self) -> ResourceSnapshot { - let fd_tables = lock_or_recover(&self.fd_tables); - self.resources.snapshot( - &self.processes, - &fd_tables, - &self.pipes, - &self.ptys, - &self.sockets, - ) - } - - pub fn resource_limits(&self) -> &ResourceLimits { - self.resources.limits() - } - - pub fn set_permissions(&mut self, permissions: Permissions) { - self.filesystem.set_permissions(permissions.clone()); - self.permissions = permissions; - } - - pub fn set_loopback_exempt_ports(&mut self, ports: BTreeSet) { - self.loopback_exempt_ports = ports; - } - - pub fn extend_loopback_exempt_ports(&mut self, ports: impl IntoIterator) { - self.loopback_exempt_ports.extend(ports); - } - - pub fn resolve_dns( - &self, - hostname: &str, - policy: DnsLookupPolicy, - ) -> KernelResult { - self.assert_not_terminated()?; - if matches!(policy, DnsLookupPolicy::CheckPermissions) { - let resource = format_dns_resource(hostname).map_err(map_dns_resolver_error)?; - check_network_access( - &self.vm_id, - &self.permissions, - NetworkOperation::Dns, - &resource, - )?; - } - - resolve_dns(&self.dns, self.dns_resolver.as_ref(), hostname).map_err(map_dns_resolver_error) - } - - pub fn resolve_dns_records( - &self, - hostname: &str, - record_type: RecordType, - policy: DnsLookupPolicy, - ) -> KernelResult { - self.assert_not_terminated()?; - if matches!(policy, DnsLookupPolicy::CheckPermissions) { - let resource = format_dns_resource(hostname).map_err(map_dns_resolver_error)?; - check_network_access( - &self.vm_id, - &self.permissions, - NetworkOperation::Dns, - &resource, - )?; - } - - resolve_dns_records(&self.dns, self.dns_resolver.as_ref(), hostname, record_type) - .map_err(map_dns_resolver_error) - } - - pub fn register_driver(&mut self, driver: CommandDriver) -> KernelResult<()> { - self.assert_not_terminated()?; - let driver_name = driver.name().to_owned(); - let populate_driver = driver.clone(); - self.commands.register(driver)?; - lock_or_recover(&self.driver_pids) - .entry(driver_name) - .or_default(); - self.commands - .populate_driver_bin(&mut self.filesystem, &populate_driver)?; - Ok(()) - } - - pub fn exec( - &mut self, - command: &str, - options: ExecOptions, - ) -> KernelResult { - self.spawn_process( - "sh", - vec![String::from("-c"), String::from(command)], - SpawnOptions { - requester_driver: options.requester_driver, - parent_pid: options.parent_pid, - env: options.env, - cwd: options.cwd, - }, - ) - } - - pub fn open_shell(&mut self, options: OpenShellOptions) -> KernelResult { - let command = options.command.unwrap_or_else(|| String::from("sh")); - let requester_driver = options.requester_driver.clone(); - let process = self.spawn_process( - &command, - options.args, - SpawnOptions { - requester_driver: requester_driver.clone(), - parent_pid: None, - env: options.env, - cwd: options.cwd, - }, - )?; - let owner = requester_driver.as_deref().unwrap_or(process.driver()); - let (master_fd, slave_fd, pty_path) = self.open_pty(owner, process.pid())?; - self.setpgid(owner, process.pid(), process.pid())?; - self.pty_set_foreground_pgid(owner, process.pid(), master_fd, process.pid())?; - Ok(OpenShellHandle { - process, - master_fd, - slave_fd, - pty_path, - }) - } - - pub fn read_file(&mut self, path: &str) -> KernelResult> { - self.assert_not_terminated()?; - self.read_file_internal(None, path) - } - - pub fn pread_file(&mut self, path: &str, offset: u64, length: usize) -> KernelResult> { - self.assert_not_terminated()?; - self.resources.check_pread_length(length)?; - Ok(VirtualFileSystem::pread( - &mut self.filesystem, - path, - offset, - length, - )?) - } - - pub fn read_file_for_process( - &mut self, - requester_driver: &str, - pid: u32, - path: &str, - ) -> KernelResult> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - self.read_file_internal(Some(pid), path) - } - - pub fn write_file(&mut self, path: &str, content: impl Into>) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_resolved_write_path(path)?; - let content = content.into(); - let new_size = content.len() as u64; - let existing = self.storage_stat(path)?; - self.check_write_file_limits_with_existing(path, existing.as_ref(), new_size)?; - self.filesystem.write_file(path, content)?; - self.update_filesystem_usage_cache_for_write(existing.as_ref(), new_size); - Ok(()) - } - - /// Writes `content` at `offset` within an existing file, growing (and - /// zero-filling) it as needed. This is the positional counterpart to - /// [`Self::pread_file`]: it lets a descriptor-based caller (the shared WASI - /// runner over the browser wire, which has no kernel fd offsets) write a - /// region without the lossy, non-atomic read-modify-write it would - /// otherwise have to do client-side. Enforcement matches `write_file`: - /// read-only paths are rejected and the resulting file size is charged - /// against the resource limits before the write. - pub fn pwrite_file( - &mut self, - path: &str, - offset: u64, - content: impl Into>, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_resolved_write_path(path)?; - let content = content.into(); - let existing = self.storage_stat(path)?; - let existing_size = existing.as_ref().map(|stat| stat.size).unwrap_or(0); - let end = offset.saturating_add(content.len() as u64); - self.check_write_file_limits_with_existing( - path, - existing.as_ref(), - existing_size.max(end), - )?; - self.filesystem.pwrite(path, content, offset)?; - self.update_filesystem_usage_cache_for_write(existing.as_ref(), existing_size.max(end)); - Ok(()) - } - - pub fn write_file_for_process( - &mut self, - requester_driver: &str, - pid: u32, - path: &str, - content: impl Into>, - mode: Option, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existed = self.exists_internal(Some(pid), path)?; - let content = content.into(); - let new_size = content.len() as u64; - self.reject_read_only_resolved_write_path(path)?; - let existing = self.storage_stat(path)?; - self.check_write_file_limits_with_existing(path, existing.as_ref(), new_size)?; - VirtualFileSystem::write_file_with_mode(&mut self.filesystem, path, content, mode)?; - self.update_filesystem_usage_cache_for_write(existing.as_ref(), new_size); - if !existed { - let umask = self.processes.get_umask(pid)?; - self.apply_creation_mode(path, mode.unwrap_or(0o666), umask)?; - } - Ok(()) - } - - pub fn create_dir(&mut self, path: &str) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_entry_write_path(path)?; - self.check_create_dir_limits(path)?; - self.filesystem.create_dir(path)?; - self.update_filesystem_usage_cache_for_inode_create(0); - Ok(()) - } - - pub fn create_dir_for_process( - &mut self, - requester_driver: &str, - pid: u32, - path: &str, - mode: Option, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existed = self.exists_internal(Some(pid), path)?; - self.reject_read_only_entry_write_path(path)?; - self.check_create_dir_limits(path)?; - VirtualFileSystem::create_dir_with_mode(&mut self.filesystem, path, mode)?; - self.update_filesystem_usage_cache_for_inode_create(0); - if !existed { - let umask = self.processes.get_umask(pid)?; - self.apply_creation_mode(path, mode.unwrap_or(0o777), umask)?; - } - Ok(()) - } - - pub fn mkdir(&mut self, path: &str, recursive: bool) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_entry_write_path(path)?; - let created_paths = self.missing_directory_paths(path, recursive)?; - self.check_mkdir_limits(path, recursive)?; - self.filesystem.mkdir(path, recursive)?; - self.update_filesystem_usage_cache_for_inode_creates(created_paths.len()); - Ok(()) - } - - pub fn mkdir_for_process( - &mut self, - requester_driver: &str, - pid: u32, - path: &str, - recursive: bool, - mode: Option, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let created_paths = self.missing_directory_paths(path, recursive)?; - self.reject_read_only_entry_write_path(path)?; - self.check_mkdir_limits(path, recursive)?; - VirtualFileSystem::mkdir_with_mode(&mut self.filesystem, path, recursive, mode)?; - if !created_paths.is_empty() { - let umask = self.processes.get_umask(pid)?; - let mode = mode.unwrap_or(0o777); - for created_path in &created_paths { - self.apply_creation_mode(created_path, mode, umask)?; - } - } - self.update_filesystem_usage_cache_for_inode_creates(created_paths.len()); - Ok(()) - } - - pub fn umask( - &self, - requester_driver: &str, - pid: u32, - new_mask: Option, - ) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - match new_mask { - Some(mask) => Ok(self.processes.set_umask(pid, mask)?), - None => Ok(self.processes.get_umask(pid)?), - } - } - - pub fn exists(&self, path: &str) -> KernelResult { - self.assert_not_terminated()?; - self.exists_internal(None, path) - } - - pub fn exists_for_process( - &self, - requester_driver: &str, - pid: u32, - path: &str, - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - self.exists_internal(Some(pid), path) - } - - pub fn stat(&mut self, path: &str) -> KernelResult { - self.assert_not_terminated()?; - self.stat_internal(None, path) - } - - pub fn stat_for_process( - &mut self, - requester_driver: &str, - pid: u32, - path: &str, - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - self.stat_internal(Some(pid), path) - } - - pub fn lstat(&self, path: &str) -> KernelResult { - self.assert_not_terminated()?; - self.lstat_internal(None, path) - } - - pub fn lstat_for_process( - &self, - requester_driver: &str, - pid: u32, - path: &str, - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - self.lstat_internal(Some(pid), path) - } - - pub fn read_link(&self, path: &str) -> KernelResult { - self.assert_not_terminated()?; - self.read_link_internal(None, path) - } - - pub fn read_link_for_process( - &self, - requester_driver: &str, - pid: u32, - path: &str, - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - self.read_link_internal(Some(pid), path) - } - - pub fn read_dir(&mut self, path: &str) -> KernelResult> { - self.assert_not_terminated()?; - let entries = self.read_dir_internal(None, path)?; - self.resources.check_readdir_entries(entries.len())?; - Ok(entries) - } - - pub fn read_dir_for_process( - &mut self, - requester_driver: &str, - pid: u32, - path: &str, - ) -> KernelResult> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let entries = self.read_dir_internal(Some(pid), path)?; - self.resources.check_readdir_entries(entries.len())?; - Ok(entries) - } - - pub fn read_dir_with_types_for_process( - &mut self, - requester_driver: &str, - pid: u32, - path: &str, - ) -> KernelResult> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let entries = self.read_dir_with_types_internal(Some(pid), path)?; - self.resources.check_readdir_entries(entries.len())?; - Ok(entries) - } - - /// Lists a directory with each child's file type in one call. This is the - /// typed counterpart to [`Self::read_dir`]: it lets a descriptor-based caller - /// recover Dirent kinds (`readdir({ withFileTypes })`) without an extra - /// `lstat` round-trip per entry. Reuses `read_dir_internal` so proc, the - /// readdir-entry limit, and read-permission checks behave identically; the - /// per-entry `lstat` is in-process (no wire hops). - pub fn read_dir_with_types(&mut self, path: &str) -> KernelResult> { - self.assert_not_terminated()?; - let names = self.read_dir_internal(None, path)?; - self.resources.check_readdir_entries(names.len())?; - let mut entries = Vec::with_capacity(names.len()); - for name in names { - let child = normalize_path(&format!("{path}/{name}")); - let stat = self.lstat_internal(None, &child)?; - entries.push(VirtualDirEntry { - name, - is_directory: stat.is_directory, - is_symbolic_link: stat.is_symbolic_link, - }); - } - Ok(entries) - } - - pub fn read_dir_recursive( - &mut self, - path: &str, - max_depth: Option, - ) -> KernelResult> { - self.assert_not_terminated()?; - let depth_limit = self.effective_recursive_fs_depth(max_depth)?; - let caller_limited = max_depth.is_some(); - let mut entries = Vec::new(); - let mut queue = VecDeque::from([(normalize_path(path), 0usize)]); - - while let Some((dir_path, depth)) = queue.pop_front() { - self.resources.check_recursive_fs_depth(depth)?; - let names = self.read_dir_internal(None, &dir_path)?; - self.resources.check_readdir_entries(names.len())?; - - for name in names { - if matches!(name.as_str(), "." | "..") { - continue; - } - let child = join_child_path(&dir_path, &name); - let stat = self.lstat_internal(None, &child)?; - let entry = RecursiveDirEntry { - path: child.clone(), - is_directory: stat.is_directory, - is_symbolic_link: stat.is_symbolic_link, - size: stat.size, - }; - entries.push(entry); - self.resources.check_recursive_fs_entries(entries.len())?; - - if stat.is_directory && !stat.is_symbolic_link { - let child_depth = depth.saturating_add(1); - if child_depth <= depth_limit { - queue.push_back((child, child_depth)); - } else if !caller_limited { - self.resources.check_recursive_fs_depth(child_depth)?; - } - } - } - } - - Ok(entries) - } - - pub fn copy_path(&mut self, from: &str, to: &str, recursive: bool) -> KernelResult<()> { - self.assert_not_terminated()?; - let mut entries = 0usize; - self.copy_path_inner(from, to, recursive, 0, &mut entries)?; - Ok(()) - } - - pub fn remove_path(&mut self, path: &str, recursive: bool) -> KernelResult<()> { - self.assert_not_terminated()?; - let mut entries = 0usize; - self.remove_path_inner(path, recursive, 0, &mut entries) - } - - pub fn move_path(&mut self, from: &str, to: &str) -> KernelResult<()> { - self.assert_not_terminated()?; - match self.rename(from, to) { - Ok(()) => Ok(()), - Err(error) if error.code() == "EXDEV" => { - self.copy_path(from, to, true)?; - self.remove_path(from, true) - } - Err(error) => Err(error), - } - } - - pub fn remove_file(&mut self, path: &str) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_entry_write_path(path)?; - let removed = self.storage_lstat(path)?; - self.filesystem.remove_file(path)?; - self.update_filesystem_usage_cache_for_remove(removed.as_ref()); - Ok(()) - } - - pub fn remove_dir(&mut self, path: &str) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_entry_write_path(path)?; - let removed = self.storage_lstat(path)?; - self.filesystem.remove_dir(path)?; - if removed.as_ref().is_some_and(|stat| stat.is_directory) { - self.update_filesystem_usage_cache_for_inode_delete(0); - } - Ok(()) - } - - pub fn rename(&mut self, old_path: &str, new_path: &str) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_entry_write_path(old_path)?; - self.reject_read_only_entry_write_path(new_path)?; - self.check_rename_copy_up_limits(old_path, new_path)?; - self.filesystem.rename(old_path, new_path)?; - // Rename can be a pure metadata move, a destination replacement, or an - // overlay copy-up/removal with hard-link aliasing. Drop the cached root - // usage because the local byte/inode delta is not knowable here. - self.invalidate_filesystem_usage_cache(); - Ok(()) - } - - pub fn realpath(&self, path: &str) -> KernelResult { - self.assert_not_terminated()?; - self.realpath_internal(None, path) - } - - pub fn realpath_for_process( - &self, - requester_driver: &str, - pid: u32, - path: &str, - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - self.realpath_internal(Some(pid), path) - } - - pub fn symlink(&mut self, target: &str, link_path: &str) -> KernelResult<()> { - self.assert_not_terminated()?; - if is_proc_path(target) { - self.filesystem - .check_virtual_path(FsOperation::Write, link_path) - .map_err(KernelError::from)?; - return Err(read_only_filesystem_error(link_path)); - } - self.reject_read_only_entry_write_path(link_path)?; - self.check_symlink_limits(target, link_path)?; - self.filesystem.symlink(target, link_path)?; - self.update_filesystem_usage_cache_for_inode_create(target.len() as u64); - Ok(()) - } - - pub fn chmod(&mut self, path: &str, mode: u32) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_resolved_write_path(path)?; - Ok(self.filesystem.chmod(path, mode)?) - } - - pub fn link(&mut self, old_path: &str, new_path: &str) -> KernelResult<()> { - self.assert_not_terminated()?; - if is_proc_path(old_path) { - self.filesystem - .check_virtual_path(FsOperation::Write, new_path) - .map_err(KernelError::from)?; - return Err(read_only_filesystem_error(new_path)); - } - self.reject_read_only_resolved_write_path(old_path)?; - self.reject_read_only_entry_write_path(new_path)?; - self.filesystem.link(old_path, new_path)?; - // Hard-link creation makes another directory entry for an already - // reachable inode, so measured root usage is unchanged. - Ok(()) - } - - pub fn chown(&mut self, path: &str, uid: u32, gid: u32) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_resolved_write_path(path)?; - Ok(self.filesystem.chown(path, uid, gid)?) - } - - pub fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> KernelResult<()> { - self.utimes_spec( - path, - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(atime_ms)), - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(mtime_ms)), - ) - } - - pub fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_resolved_write_path(path)?; - Ok(self.filesystem.utimes_spec(path, atime, mtime, true)?) - } - - pub fn lutimes( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_entry_write_path(path)?; - Ok(self.filesystem.utimes_spec(path, atime, mtime, false)?) - } - - pub fn futimes( - &mut self, - requester_driver: &str, - pid: u32, - fd: u32, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - let path = self - .description_for_fd(requester_driver, pid, fd)? - .path() - .to_owned(); - self.reject_read_only_resolved_write_path(&path)?; - Ok(self.filesystem.utimes_spec(&path, atime, mtime, true)?) - } - - pub fn truncate(&mut self, path: &str, length: u64) -> KernelResult<()> { - self.assert_not_terminated()?; - self.reject_read_only_resolved_write_path(path)?; - let existing = self.storage_stat(path)?; - self.check_truncate_limits_with_existing(path, existing.as_ref(), length)?; - self.filesystem.truncate(path, length)?; - self.update_filesystem_usage_cache_for_write(existing.as_ref(), length); - Ok(()) - } - - pub fn list_processes(&self) -> BTreeMap { - self.processes.list_processes() - } - - pub fn zombie_timer_count(&self) -> usize { - self.processes.zombie_timer_count() - } - - pub fn spawn_process( - &mut self, - command: &str, - args: Vec, - options: SpawnOptions, - ) -> KernelResult { - self.assert_not_terminated()?; - if let (Some(requester), Some(parent_pid)) = - (options.requester_driver.as_deref(), options.parent_pid) - { - self.assert_driver_owns(requester, parent_pid)?; - } - - let cwd = options.cwd.clone().unwrap_or_else(|| self.cwd.clone()); - let resolved = self.resolve_spawn_command(command, &args, &cwd)?; - - self.resources - .check_process_argv_bytes(&resolved.command, &resolved.args)?; - self.resources - .check_process_env_bytes(&self.env, &options.env)?; - - let mut env = self.env.clone(); - env.extend(options.env.clone()); - check_command_execution( - &self.vm_id, - &self.permissions, - &resolved.command, - &resolved.args, - Some(&cwd), - &env, - )?; - - let inherited_fds = { - let tables = lock_or_recover(&self.fd_tables); - options - .parent_pid - .and_then(|pid| tables.get(pid).map(ProcessFdTable::len)) - .unwrap_or(3) - }; - self.resources - .check_process_spawn(&self.resource_snapshot(), inherited_fds)?; - - self.register_process( - resolved.driver.name().to_owned(), - resolved.command, - resolved.args, - ProcessContext { - pid: 0, - ppid: options.parent_pid.unwrap_or(0), - env, - cwd, - umask: DEFAULT_PROCESS_UMASK, - fds: Default::default(), - identity: self.users.identity(), - blocked_signals: SignalSet::empty(), - pending_signals: SignalSet::empty(), - }, - options.requester_driver.as_deref(), - ) - } - - pub fn create_virtual_process( - &mut self, - requester_driver: &str, - driver: &str, - command: &str, - args: Vec, - options: VirtualProcessOptions, - ) -> KernelResult { - self.assert_not_terminated()?; - if let Some(parent_pid) = options.parent_pid { - self.assert_driver_owns(requester_driver, parent_pid)?; - } - - let cwd = options.cwd.clone().unwrap_or_else(|| self.cwd.clone()); - self.resources.check_process_argv_bytes(command, &args)?; - self.resources - .check_process_env_bytes(&self.env, &options.env)?; - - let mut env = self.env.clone(); - env.extend(options.env.clone()); - check_command_execution( - &self.vm_id, - &self.permissions, - command, - &args, - Some(&cwd), - &env, - )?; - - let inherited_fds = { - let tables = lock_or_recover(&self.fd_tables); - options - .parent_pid - .and_then(|pid| tables.get(pid).map(ProcessFdTable::len)) - .unwrap_or(3) - }; - self.resources - .check_process_spawn(&self.resource_snapshot(), inherited_fds)?; - - self.register_process( - String::from(driver), - String::from(command), - args, - ProcessContext { - pid: 0, - ppid: options.parent_pid.unwrap_or(0), - env, - cwd, - umask: DEFAULT_PROCESS_UMASK, - fds: Default::default(), - identity: self.users.identity(), - blocked_signals: SignalSet::empty(), - pending_signals: SignalSet::empty(), - }, - Some(requester_driver), - ) - } - - pub fn read_process_stdin( - &mut self, - requester_driver: &str, - pid: u32, - length: usize, - timeout: Option, - ) -> KernelResult>> { - self.fd_read_with_timeout_result(requester_driver, pid, 0, length, timeout) - } - - pub fn write_process_stdout( - &mut self, - requester_driver: &str, - pid: u32, - data: &[u8], - ) -> KernelResult { - self.fd_write(requester_driver, pid, 1, data) - } - - pub fn write_process_stderr( - &mut self, - requester_driver: &str, - pid: u32, - data: &[u8], - ) -> KernelResult { - self.fd_write(requester_driver, pid, 2, data) - } - - pub fn exit_process( - &mut self, - requester_driver: &str, - pid: u32, - exit_code: i32, - ) -> KernelResult<()> { - self.assert_driver_owns(requester_driver, pid)?; - self.processes.mark_exited(pid, exit_code); - Ok(()) - } - - fn register_process( - &mut self, - driver_name: String, - command: String, - args: Vec, - mut ctx: ProcessContext, - requester_driver: Option<&str>, - ) -> KernelResult { - let pid = self.processes.allocate_pid()?; - ctx.pid = pid; - - { - let mut tables = lock_or_recover(&self.fd_tables); - if ctx.ppid != 0 { - let parent_pid = ctx.ppid; - tables.fork(parent_pid, pid); - } else { - tables.create(pid); - } - } - - let process = Arc::new(StubDriverProcess::default()); - self.processes.register( - pid, - driver_name.clone(), - command, - args, - ctx, - process.clone(), - ); - - let mut owners = lock_or_recover(&self.driver_pids); - owners.entry(driver_name.clone()).or_default().insert(pid); - if let Some(requester) = requester_driver { - owners - .entry(String::from(requester)) - .or_default() - .insert(pid); - } - - Ok(KernelProcessHandle { - pid, - driver: driver_name, - process, - }) - } - - pub fn waitpid(&mut self, pid: u32) -> KernelResult { - let (pid, status) = self.processes.waitpid(pid)?; - self.cleanup_process_resources(pid); - Ok(WaitPidResult { pid, status }) - } - - pub fn waitpid_with_options( - &mut self, - requester_driver: &str, - waiter_pid: u32, - pid: i32, - flags: WaitPidFlags, - ) -> KernelResult> { - self.assert_driver_owns(requester_driver, waiter_pid)?; - let result = self.processes.waitpid_for(waiter_pid, pid, flags)?; - Ok(result.map(|result| self.finish_waitpid_event(result))) - } - - pub fn wait_and_reap(&mut self, pid: u32) -> KernelResult<(u32, i32)> { - let result = self.waitpid(pid)?; - Ok((result.pid, result.status)) - } - - pub fn open_pipe(&mut self, requester_driver: &str, pid: u32) -> KernelResult<(u32, u32)> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - self.resources - .check_pipe_allocation(&self.resource_snapshot())?; - let mut tables = lock_or_recover(&self.fd_tables); - let table = tables - .get_mut(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - Ok(self.pipes.create_pipe_fds(table)?) - } - - pub fn open_pty( - &mut self, - requester_driver: &str, - pid: u32, - ) -> KernelResult<(u32, u32, String)> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - self.resources - .check_pty_allocation(&self.resource_snapshot())?; - let mut tables = lock_or_recover(&self.fd_tables); - let table = tables - .get_mut(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - Ok(self.ptys.create_pty_fds(table)?) - } - - pub fn socket_create( - &mut self, - requester_driver: &str, - pid: u32, - spec: SocketSpec, - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - self.resources - .check_socket_allocation(&self.resource_snapshot())?; - Ok(self.sockets.allocate(pid, spec).id()) - } - - pub fn set_socket_readiness_sink(&mut self, sink: Option) - where - S: Fn(SocketReadiness) + Send + Sync + 'static, - { - self.sockets.set_readiness_sink(sink); - } - - pub fn socket_get(&self, socket_id: SocketId) -> Option { - self.sockets.get(socket_id) - } - - pub fn socket_records_for_pid(&self, pid: u32) -> Vec { - self.sockets.records_for_owner(pid) - } - - pub fn socket_bind_inet( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - address: InetSocketAddress, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - check_network_access( - &self.vm_id, - &self.permissions, - NetworkOperation::Listen, - &format_tcp_resource(address.host(), address.port()), - )?; - - self.sockets.bind_inet(socket_id, address)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_bind_unix( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - path: impl Into, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - self.sockets - .bind_unix(socket_id, normalize_path(&path.into()))?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_listen( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - backlog: usize, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - if let Some(address) = existing.local_address() { - check_network_access( - &self.vm_id, - &self.permissions, - NetworkOperation::Listen, - &format_tcp_resource(address.host(), address.port()), - )?; - } - - self.sockets.listen(socket_id, backlog)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_queue_incoming_tcp_connection( - &mut self, - requester_driver: &str, - pid: u32, - listener_socket_id: SocketId, - peer_address: InetSocketAddress, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self.sockets.get(listener_socket_id).ok_or_else(|| { - KernelError::new("ENOENT", format!("no such socket {listener_socket_id}")) - })?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {listener_socket_id}" - ))); - } - - self.sockets - .enqueue_incoming_tcp_connection(listener_socket_id, peer_address)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_accept( - &mut self, - requester_driver: &str, - pid: u32, - listener_socket_id: SocketId, - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self.sockets.get(listener_socket_id).ok_or_else(|| { - KernelError::new("ENOENT", format!("no such socket {listener_socket_id}")) - })?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {listener_socket_id}" - ))); - } - - let snapshot = self.resource_snapshot(); - self.resources.check_socket_allocation(&snapshot)?; - self.resources.check_socket_state_transition( - &snapshot, - SocketState::Created, - SocketState::Connected, - )?; - - let socket_id = self.sockets.accept(listener_socket_id)?.id(); - self.poll_notifier.notify(); - Ok(socket_id) - } - - pub fn socket_connect_pair( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - peer_socket_id: SocketId, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - let peer = self.sockets.get(peer_socket_id).ok_or_else(|| { - KernelError::new("ENOENT", format!("no such socket {peer_socket_id}")) - })?; - self.assert_driver_owns(requester_driver, peer.owner_pid())?; - - let mut snapshot = self.resource_snapshot(); - for current_state in [existing.state(), peer.state()] { - self.resources.check_socket_state_transition( - &snapshot, - current_state, - SocketState::Connected, - )?; - if !current_state.counts_as_connection() { - snapshot.socket_connections = snapshot.socket_connections.saturating_add(1); - } - } - - self.sockets.connect_pair(socket_id, peer_socket_id)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_connect_unix( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - target_path: impl Into, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - let target_path = normalize_path(&target_path.into()); - self.sockets - .find_bound_unix_socket(&target_path) - .ok_or_else(|| { - KernelError::new( - "ECONNREFUSED", - format!("no listening socket bound at path {target_path}"), - ) - })?; - - let mut snapshot = self.resource_snapshot(); - self.resources.check_socket_allocation(&snapshot)?; - for current_state in [existing.state(), SocketState::Created] { - self.resources.check_socket_state_transition( - &snapshot, - current_state, - SocketState::Connected, - )?; - if !current_state.counts_as_connection() { - snapshot.socket_connections = snapshot.socket_connections.saturating_add(1); - } - } - - self.sockets - .connect_to_bound_unix_stream(socket_id, target_path)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_connect_inet_loopback( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - target_address: InetSocketAddress, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - check_network_access( - &self.vm_id, - &self.permissions, - NetworkOperation::Http, - &format_tcp_resource(target_address.host(), target_address.port()), - )?; - self.check_loopback_port_allowed( - SocketSpec::tcp(), - &target_address, - "TCP loopback connect", - )?; - - self.sockets - .find_bound_inet_socket(SocketSpec::tcp(), &target_address) - .ok_or_else(|| { - KernelError::new( - "ECONNREFUSED", - format!( - "no listening socket bound at {}:{}", - target_address.host(), - target_address.port() - ), - ) - })?; - - let mut snapshot = self.resource_snapshot(); - self.resources.check_socket_allocation(&snapshot)?; - for current_state in [existing.state(), SocketState::Created] { - self.resources.check_socket_state_transition( - &snapshot, - current_state, - SocketState::Connected, - )?; - if !current_state.counts_as_connection() { - snapshot.socket_connections = snapshot.socket_connections.saturating_add(1); - } - } - - self.sockets - .connect_to_bound_inet_stream(socket_id, target_address)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_send_to_inet_loopback( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - target_address: InetSocketAddress, - data: &[u8], - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - if existing.spec() != SocketSpec::udp() - || existing.state() != SocketState::Bound - || existing.local_address().is_none() - { - self.sockets - .check_send_to_bound_udp_socket(socket_id, target_address.clone())?; - } - check_network_access( - &self.vm_id, - &self.permissions, - NetworkOperation::Http, - &format_tcp_resource(target_address.host(), target_address.port()), - )?; - self.check_loopback_port_allowed(SocketSpec::udp(), &target_address, "UDP loopback send")?; - - self.sockets - .check_send_to_bound_udp_socket(socket_id, target_address.clone())?; - self.resources - .check_socket_datagram_enqueue(&self.resource_snapshot(), data.len())?; - let written = self - .sockets - .send_to_bound_udp_socket(socket_id, target_address, data)?; - if written > 0 { - self.poll_notifier.notify(); - } - Ok(written) - } - - fn check_loopback_port_allowed( - &self, - spec: SocketSpec, - target_address: &InetSocketAddress, - operation: &str, - ) -> KernelResult<()> { - if self - .sockets - .find_bound_inet_socket(spec, target_address) - .is_some() - || self.loopback_exempt_ports.contains(&target_address.port()) - { - return Ok(()); - } - - Err(KernelError::permission_denied(format!( - "{operation} to {}:{} is not owned by this VM and is not loopback-exempt", - target_address.host(), - target_address.port() - ))) - } - - pub fn socket_recv_datagram( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - max_bytes: usize, - ) -> KernelResult> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - let result = self.sockets.recv_datagram(socket_id, max_bytes)?; - if result.is_some() { - self.poll_notifier.notify(); - } - Ok(result) - } - - pub fn socket_set_datagram_option( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - option: DatagramSocketOption, - enabled: bool, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - self.sockets - .set_datagram_socket_option(socket_id, option, enabled)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_add_membership( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - membership: SocketMulticastMembership, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - self.sockets - .add_multicast_membership(socket_id, membership)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_drop_membership( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - membership: SocketMulticastMembership, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - self.sockets - .drop_multicast_membership(socket_id, membership)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_set_state( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - state: SocketState, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - self.resources.check_socket_state_transition( - &self.resource_snapshot(), - existing.state(), - state, - )?; - self.sockets.update_state(socket_id, state)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_write( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - data: &[u8], - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - self.sockets.check_write(socket_id)?; - self.resources - .check_socket_buffer_growth(&self.resource_snapshot(), data.len())?; - let written = self.sockets.write(socket_id, data)?; - if written > 0 { - self.poll_notifier.notify(); - } - Ok(written) - } - - pub fn socket_read( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - max_bytes: usize, - ) -> KernelResult>> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - let result = self.sockets.read(socket_id, max_bytes)?; - if result.is_some() { - self.poll_notifier.notify(); - } - Ok(result) - } - - pub fn socket_shutdown( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - how: SocketShutdown, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - self.sockets.shutdown(socket_id, how)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn socket_close( - &mut self, - requester_driver: &str, - pid: u32, - socket_id: SocketId, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - let existing = self - .sockets - .get(socket_id) - .ok_or_else(|| KernelError::new("ENOENT", format!("no such socket {socket_id}")))?; - if existing.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - - self.sockets.remove(socket_id)?; - self.poll_notifier.notify(); - Ok(()) - } - - pub fn fd_open( - &mut self, - requester_driver: &str, - pid: u32, - path: &str, - flags: u32, - mode: Option, - ) -> KernelResult { - self.assert_not_terminated()?; - self.assert_driver_owns(requester_driver, pid)?; - if let Some(existing_fd) = parse_dev_fd_path(path)? { - { - let tables = lock_or_recover(&self.fd_tables); - let table = tables - .get(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - table - .get(existing_fd) - .ok_or_else(|| KernelError::bad_file_descriptor(existing_fd))?; - } - self.resources - .check_fd_allocation(&self.resource_snapshot(), 1)?; - let mut tables = lock_or_recover(&self.fd_tables); - let table = tables - .get_mut(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - let entry = table - .get(existing_fd) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(existing_fd))?; - return Ok(table.dup_with_status_flags( - existing_fd, - Some(entry.status_flags | (flags & O_NONBLOCK)), - )?); - } - - if let Some(proc_node) = self.resolve_proc_node(path, Some(pid))? { - if open_requires_write_access(flags) { - self.filesystem - .check_virtual_path(FsOperation::Write, path) - .map_err(KernelError::from)?; - return Err(read_only_filesystem_error(path)); - } - - if matches!( - proc_node, - ProcNode::SelfLink { .. } - | ProcNode::PidCwdLink { .. } - | ProcNode::PidFdLink { .. } - ) { - let target = self.proc_symlink_target(&proc_node)?; - return self.fd_open(requester_driver, pid, &target, flags, mode); - } - - self.filesystem - .check_virtual_path(FsOperation::Read, path) - .map_err(KernelError::from)?; - self.resources - .check_fd_allocation(&self.resource_snapshot(), 1)?; - let mut tables = lock_or_recover(&self.fd_tables); - let table = tables - .get_mut(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - return Ok(table.open_with_details( - &self.proc_canonical_path(&proc_node), - flags, - proc_filetype(&proc_node), - None, - )?); - } - - if open_requires_write_access(flags) { - self.reject_read_only_resolved_write_path(path)?; - } - let existed = if flags & O_CREAT != 0 { - self.exists_internal(Some(pid), path)? - } else { - false - }; - let (filetype, lock_target) = self.prepare_fd_open(path, flags, mode)?; - if flags & O_CREAT != 0 && !existed { - let umask = self.processes.get_umask(pid)?; - self.apply_creation_mode(path, mode.unwrap_or(0o666), umask)?; - } - self.resources - .check_fd_allocation(&self.resource_snapshot(), 1)?; - let mut tables = lock_or_recover(&self.fd_tables); - let table = tables - .get_mut(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - Ok(table.open_with_details(path, flags, filetype, lock_target)?) - } - - pub fn fd_read( - &mut self, - requester_driver: &str, - pid: u32, - fd: u32, - length: usize, - ) -> KernelResult> { - Ok(self - .fd_read_with_timeout_result(requester_driver, pid, fd, length, None)? - .unwrap_or_default()) - } - - pub fn fd_read_with_timeout_result( - &mut self, - requester_driver: &str, - pid: u32, - fd: u32, - length: usize, - timeout: Option, - ) -> KernelResult>> { - self.assert_driver_owns(requester_driver, pid)?; - let entry = { - let tables = lock_or_recover(&self.fd_tables); - tables - .get(pid) - .and_then(|table| table.get(fd)) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(fd))? - }; - - if self.pipes.is_pipe(entry.description.id()) { - return Ok(self.pipes.read_with_timeout( - entry.description.id(), - length, - if entry.status_flags & O_NONBLOCK != 0 { - Some(Duration::ZERO) - } else { - timeout.or_else(|| self.blocking_read_timeout()) - }, - )?); - } - - if self.ptys.is_pty(entry.description.id()) { - return Ok(self.ptys.read_with_timeout( - entry.description.id(), - length, - if entry.status_flags & O_NONBLOCK != 0 { - Some(Duration::ZERO) - } else { - timeout.or_else(|| self.blocking_read_timeout()) - }, - )?); - } - - self.resources.check_pread_length(length)?; - - if is_proc_path(entry.description.path()) { - let bytes = self.proc_read_file_from_open_path(Some(pid), entry.description.path())?; - let start = entry.description.cursor() as usize; - let end = start.saturating_add(length).min(bytes.len()); - let chunk = if start >= bytes.len() { - Vec::new() - } else { - bytes[start..end].to_vec() - }; - entry.description.set_cursor( - entry - .description - .cursor() - .saturating_add(chunk.len() as u64), - ); - return Ok(Some(chunk)); - } - - let cursor = entry.description.cursor(); - let bytes = VirtualFileSystem::pread( - &mut self.filesystem, - entry.description.path(), - cursor, - length, - )?; - entry - .description - .set_cursor(cursor.saturating_add(bytes.len() as u64)); - Ok(Some(bytes)) - } - - pub fn fd_write( - &mut self, - requester_driver: &str, - pid: u32, - fd: u32, - data: &[u8], - ) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - self.resources.check_fd_write_size(data.len())?; - let entry = { - let tables = lock_or_recover(&self.fd_tables); - tables - .get(pid) - .and_then(|table| table.get(fd)) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(fd))? - }; - - if self.pipes.is_pipe(entry.description.id()) { - return match self.pipes.write_with_mode( - entry.description.id(), - data, - entry.status_flags & O_NONBLOCK != 0, - ) { - Ok(bytes) => Ok(bytes), - Err(error) => { - if error.code() == "EPIPE" { - self.processes.kill(pid as i32, SIGPIPE)?; - } - Err(error.into()) - } - }; - } - - if self.ptys.is_pty(entry.description.id()) { - return Ok(self.ptys.write(entry.description.id(), data)?); - } - - self.reject_read_only_resolved_write_path(entry.description.path())?; - - let path = entry.description.path().to_owned(); - if is_virtual_device_storage_path(&path) { - VirtualFileSystem::write_file(&mut self.filesystem, &path, data.to_vec())?; - let cursor = entry.description.cursor(); - entry - .description - .set_cursor(cursor.saturating_add(data.len() as u64)); - return Ok(data.len()); - } - let current_size = self.current_storage_file_size(&path)?; - let cursor = entry.description.cursor(); - if entry.description.flags() & O_APPEND != 0 { - let required_size = current_size.max(checked_write_end(current_size, data.len())?); - self.check_path_resize_limits(&path, required_size)?; - let new_len = VirtualFileSystem::append_file(&mut self.filesystem, &path, data)?; - self.update_filesystem_usage_cache_for_resize(current_size, new_len); - entry.description.set_cursor(new_len); - return Ok(data.len()); - } - - let required_size = current_size.max(checked_write_end(cursor, data.len())?); - self.check_path_resize_limits(&path, required_size)?; - VirtualFileSystem::pwrite(&mut self.filesystem, &path, data, cursor)?; - self.update_filesystem_usage_cache_for_resize(current_size, required_size); - entry - .description - .set_cursor(cursor.saturating_add(data.len() as u64)); - Ok(data.len()) - } - - pub fn poll_fds( - &self, - requester_driver: &str, - pid: u32, - fds: Vec, - timeout_ms: i32, - ) -> KernelResult { - let targets = fds - .into_iter() - .map(|poll_fd| PollTargetEntry::fd(poll_fd.fd, poll_fd.events)) - .collect::>(); - let result = self.poll_targets(requester_driver, pid, targets, timeout_ms)?; - Ok(PollResult { - ready_count: result.ready_count, - fds: result - .targets - .into_iter() - .map(|target| match target.target { - PollTarget::Fd(fd) => PollFd { - fd, - events: target.events, - revents: target.revents, - }, - PollTarget::Socket(_) => unreachable!("fd poll should only include fd targets"), - }) - .collect(), - }) - } - - /// A cloneable, Send handle for waiting on kernel poll-state changes off - /// the kernel owner's thread. Pair with a zero-timeout `poll_fds` / - /// `fd_read_with_timeout_result` re-check on the owning thread. - pub fn poll_wait_handle(&self) -> crate::poll::PollWaitHandle { - crate::poll::PollWaitHandle::new(self.poll_notifier.clone()) - } - - pub fn poll_targets( - &self, - requester_driver: &str, - pid: u32, - mut targets: Vec, - timeout_ms: i32, - ) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - if timeout_ms < -1 { - return Err(KernelError::new( - "EINVAL", - format!("invalid poll timeout {timeout_ms}"), - )); - } - - let timeout = if timeout_ms < 0 { - None - } else { - Some(Duration::from_millis(timeout_ms as u64)) - }; - let deadline = timeout.map(|duration| Instant::now() + duration); - - loop { - let observed_generation = self.poll_notifier.snapshot(); - let ready_count = self.populate_poll_target_revents(pid, &mut targets)?; - if ready_count > 0 || matches!(timeout, Some(duration) if duration.is_zero()) { - return Ok(PollTargetResult { - ready_count, - targets, - }); - } - - let remaining = deadline.map(|target| target.saturating_duration_since(Instant::now())); - if matches!(remaining, Some(duration) if duration.is_zero()) { - return Ok(PollTargetResult { - ready_count, - targets, - }); - } - - if !self - .poll_notifier - .wait_for_change(observed_generation, remaining) - { - return Ok(PollTargetResult { - ready_count, - targets, - }); - } - } - } - - pub fn fd_seek( - &mut self, - requester_driver: &str, - pid: u32, - fd: u32, - offset: i64, - whence: u8, - ) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - let entry = { - let tables = lock_or_recover(&self.fd_tables); - tables - .get(pid) - .and_then(|table| table.get(fd)) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(fd))? - }; - - if self.pipes.is_pipe(entry.description.id()) || self.ptys.is_pty(entry.description.id()) { - return Err(KernelError::new("ESPIPE", "illegal seek")); - } - - let base = match whence { - SEEK_SET => 0_i128, - SEEK_CUR => i128::from(entry.description.cursor()), - SEEK_END => { - let size = if is_proc_path(entry.description.path()) { - self.proc_stat_from_open_path(Some(pid), entry.description.path())? - .size - } else { - self.filesystem.stat(entry.description.path())?.size - }; - i128::from(size) - } - _ => { - return Err(KernelError::new( - "EINVAL", - format!("invalid whence {whence}"), - )); - } - }; - let next = base + i128::from(offset); - if next < 0 { - return Err(KernelError::new("EINVAL", "negative seek position")); - } - let next = u64::try_from(next) - .map_err(|_| KernelError::new("EINVAL", "seek position out of range"))?; - entry.description.set_cursor(next); - Ok(next) - } - - pub fn fd_pread( - &mut self, - requester_driver: &str, - pid: u32, - fd: u32, - length: usize, - offset: u64, - ) -> KernelResult> { - self.assert_driver_owns(requester_driver, pid)?; - self.resources.check_pread_length(length)?; - let entry = { - let tables = lock_or_recover(&self.fd_tables); - tables - .get(pid) - .and_then(|table| table.get(fd)) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(fd))? - }; - - if self.pipes.is_pipe(entry.description.id()) || self.ptys.is_pty(entry.description.id()) { - return Err(KernelError::new("ESPIPE", "illegal seek")); - } - - if is_proc_path(entry.description.path()) { - let bytes = self.proc_read_file_from_open_path(Some(pid), entry.description.path())?; - let start = usize::try_from(offset) - .map_err(|_| KernelError::new("EINVAL", "pread offset out of range"))?; - let end = start.saturating_add(length).min(bytes.len()); - return Ok(if start >= bytes.len() { - Vec::new() - } else { - bytes[start..end].to_vec() - }); - } - - Ok(VirtualFileSystem::pread( - &mut self.filesystem, - entry.description.path(), - offset, - length, - )?) - } - - pub fn fd_pwrite( - &mut self, - requester_driver: &str, - pid: u32, - fd: u32, - data: &[u8], - offset: u64, - ) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - self.resources.check_fd_write_size(data.len())?; - let entry = { - let tables = lock_or_recover(&self.fd_tables); - tables - .get(pid) - .and_then(|table| table.get(fd)) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(fd))? - }; - - if self.pipes.is_pipe(entry.description.id()) || self.ptys.is_pty(entry.description.id()) { - return Err(KernelError::new("ESPIPE", "illegal seek")); - } - - self.reject_read_only_resolved_write_path(entry.description.path())?; - - let current_size = self.current_storage_file_size(entry.description.path())?; - let required_size = current_size.max(checked_write_end(offset, data.len())?); - self.check_path_resize_limits(entry.description.path(), required_size)?; - VirtualFileSystem::pwrite( - &mut self.filesystem, - entry.description.path(), - data.to_vec(), - offset, - )?; - self.update_filesystem_usage_cache_for_resize(current_size, required_size); - Ok(data.len()) - } - - pub fn fd_dup(&mut self, requester_driver: &str, pid: u32, fd: u32) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - { - let tables = lock_or_recover(&self.fd_tables); - let table = tables - .get(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - table - .get(fd) - .ok_or_else(|| KernelError::bad_file_descriptor(fd))?; - } - self.resources - .check_fd_allocation(&self.resource_snapshot(), 1)?; - let mut tables = lock_or_recover(&self.fd_tables); - let table = tables - .get_mut(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - Ok(table.dup(fd)?) - } - - pub fn fd_dup2( - &mut self, - requester_driver: &str, - pid: u32, - old_fd: u32, - new_fd: u32, - ) -> KernelResult<()> { - self.assert_driver_owns(requester_driver, pid)?; - let (replaced, needs_fd_growth) = { - let tables = lock_or_recover(&self.fd_tables); - let table = tables - .get(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - table - .get(old_fd) - .ok_or_else(|| KernelError::bad_file_descriptor(old_fd))?; - let replaced = if old_fd == new_fd { - None - } else { - table.get(new_fd).cloned() - }; - if new_fd as usize >= table.max_fds() { - return Err(KernelError::bad_file_descriptor(new_fd)); - } - let needs_fd_growth = old_fd != new_fd && replaced.is_none(); - (replaced, needs_fd_growth) - }; - if needs_fd_growth { - self.resources - .check_fd_allocation(&self.resource_snapshot(), 1)?; - } - { - let mut tables = lock_or_recover(&self.fd_tables); - let table = tables - .get_mut(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - table.dup2(old_fd, new_fd)?; - } - - if let Some(entry) = replaced { - self.close_special_resource_if_needed(&entry.description, entry.filetype); - } - Ok(()) - } - - pub fn fd_close(&mut self, requester_driver: &str, pid: u32, fd: u32) -> KernelResult<()> { - self.assert_driver_owns(requester_driver, pid)?; - let (description, filetype) = { - let mut tables = lock_or_recover(&self.fd_tables); - let table = tables - .get_mut(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - let entry = table - .get(fd) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(fd))?; - table.close(fd); - (entry.description, entry.filetype) - }; - self.close_special_resource_if_needed(&description, filetype); - Ok(()) - } - - pub fn fd_fcntl( - &mut self, - requester_driver: &str, - pid: u32, - fd: u32, - command: u32, - arg: u32, - ) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - if command == F_DUPFD { - { - let tables = lock_or_recover(&self.fd_tables); - let table = tables - .get(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - table - .get(fd) - .ok_or_else(|| KernelError::bad_file_descriptor(fd))?; - if arg as usize >= table.max_fds() { - return Err(KernelError::new( - "EINVAL", - format!("fd {arg} exceeds process fd limit"), - )); - } - } - self.resources - .check_fd_allocation(&self.resource_snapshot(), 1)?; - } - let mut tables = lock_or_recover(&self.fd_tables); - let table = tables - .get_mut(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - let result = table.fcntl(fd, command, arg)?; - if command == F_DUPFD { - self.poll_notifier.notify(); - } - Ok(result) - } - - pub fn fd_flock( - &self, - requester_driver: &str, - pid: u32, - fd: u32, - operation: u32, - ) -> KernelResult<()> { - self.assert_driver_owns(requester_driver, pid)?; - let entry = { - let tables = lock_or_recover(&self.fd_tables); - tables - .get(pid) - .and_then(|table| table.get(fd)) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(fd))? - }; - - if entry.filetype != FILETYPE_REGULAR_FILE { - return Err(KernelError::new( - "EBADF", - format!("file descriptor {fd} does not support advisory locking"), - )); - } - - let target = entry.description.lock_target().ok_or_else(|| { - KernelError::new( - "EBADF", - format!("file descriptor {fd} is missing advisory lock metadata"), - ) - })?; - let operation = FlockOperation::from_bits(operation)?; - self.file_locks - .apply(entry.description.id(), target, operation)?; - Ok(()) - } - - pub fn fd_stat(&self, requester_driver: &str, pid: u32, fd: u32) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - let tables = lock_or_recover(&self.fd_tables); - Ok(tables - .get(pid) - .ok_or_else(|| KernelError::no_such_process(pid))? - .stat(fd)?) - } - - pub fn fd_path(&self, requester_driver: &str, pid: u32, fd: u32) -> KernelResult { - let description = self.description_for_fd(requester_driver, pid, fd)?; - Ok(description.path().to_owned()) - } - - pub fn isatty(&self, requester_driver: &str, pid: u32, fd: u32) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - let entry = { - let tables = lock_or_recover(&self.fd_tables); - tables - .get(pid) - .and_then(|table| table.get(fd)) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(fd))? - }; - Ok(self.ptys.is_slave(entry.description.id())) - } - - pub fn pty_window_size( - &self, - requester_driver: &str, - pid: u32, - fd: u32, - ) -> KernelResult { - let description = self.description_for_fd(requester_driver, pid, fd)?; - Ok(self.ptys.window_size(description.id())?) - } - - pub fn pty_set_discipline( - &self, - requester_driver: &str, - pid: u32, - fd: u32, - config: LineDisciplineConfig, - ) -> KernelResult<()> { - let description = self.description_for_fd(requester_driver, pid, fd)?; - self.ptys.set_discipline(description.id(), config)?; - Ok(()) - } - - pub fn pty_set_foreground_pgid( - &self, - requester_driver: &str, - pid: u32, - fd: u32, - pgid: u32, - ) -> KernelResult<()> { - let description = self.description_for_fd(requester_driver, pid, fd)?; - let requester_sid = self.processes.getsid(pid)?; - let group = self - .processes - .list_processes() - .into_values() - .find(|process| process.pgid == pgid && process.status != ProcessStatus::Exited) - .ok_or_else(|| KernelError::new("ESRCH", format!("no such process group {pgid}")))?; - if group.sid != requester_sid { - return Err(KernelError::permission_denied( - "cannot set foreground process group in different session", - )); - } - self.ptys.set_foreground_pgid(description.id(), pgid)?; - Ok(()) - } - - pub fn tcgetattr(&self, requester_driver: &str, pid: u32, fd: u32) -> KernelResult { - let description = self.description_for_fd(requester_driver, pid, fd)?; - Ok(self.ptys.get_termios(description.id())?) - } - - pub fn tcsetattr( - &self, - requester_driver: &str, - pid: u32, - fd: u32, - termios: PartialTermios, - ) -> KernelResult<()> { - let description = self.description_for_fd(requester_driver, pid, fd)?; - self.ptys.set_termios(description.id(), termios)?; - Ok(()) - } - - pub fn tcgetpgrp(&self, requester_driver: &str, pid: u32, fd: u32) -> KernelResult { - let description = self.description_for_fd(requester_driver, pid, fd)?; - Ok(self.ptys.get_foreground_pgid(description.id())?) - } - - pub fn pty_resize( - &self, - requester_driver: &str, - pid: u32, - fd: u32, - cols: u16, - rows: u16, - ) -> KernelResult<()> { - let description = self.description_for_fd(requester_driver, pid, fd)?; - let target_pgid = self.ptys.resize(description.id(), cols, rows)?; - if let Some(pgid) = target_pgid { - match self.processes.kill(-(pgid as i32), SIGWINCH) { - Ok(()) => {} - Err(error) if error.code() == "ESRCH" => {} - Err(error) => return Err(error.into()), - } - } - Ok(()) - } - - pub fn signal_process( - &self, - requester_driver: &str, - pid: i32, - signal: i32, - ) -> KernelResult<()> { - if pid < 0 { - let pgid = pid.unsigned_abs(); - let members = self - .processes - .list_processes() - .into_values() - .filter(|process| process.pgid == pgid && process.status != ProcessStatus::Exited) - .collect::>(); - if members.is_empty() { - self.processes.kill(pid, signal)?; - return Ok(()); - } - if let Some(process) = members - .iter() - .find(|process| process.driver != requester_driver) - { - return Err(KernelError::permission_denied(format!( - "driver \"{requester_driver}\" does not own process group {pgid} containing PID {}", - process.pid - ))); - } - self.processes.kill(pid, signal)?; - return Ok(()); - } - - let pid = u32::try_from(pid) - .map_err(|_| KernelError::new("EINVAL", format!("invalid pid {pid}")))?; - self.assert_driver_owns(requester_driver, pid)?; - self.processes.kill(pid as i32, signal)?; - Ok(()) - } - - pub fn kill_process(&self, requester_driver: &str, pid: u32, signal: i32) -> KernelResult<()> { - let pid = i32::try_from(pid) - .map_err(|_| KernelError::new("EINVAL", format!("pid {pid} exceeds i32::MAX")))?; - self.signal_process(requester_driver, pid, signal) - } - - pub fn setpgid(&self, requester_driver: &str, pid: u32, pgid: u32) -> KernelResult<()> { - self.assert_driver_owns(requester_driver, pid)?; - let target_pgid = if pgid == 0 { pid } else { pgid }; - if target_pgid != pid { - if let Some(group_owner) = - self.processes - .list_processes() - .into_values() - .find(|process| { - process.pgid == target_pgid && process.status == ProcessStatus::Running - }) - { - if group_owner.driver != requester_driver { - return Err(KernelError::permission_denied(format!( - "driver \"{requester_driver}\" cannot join process group {target_pgid} owned by \"{}\"", - group_owner.driver - ))); - } - } - } - self.processes.setpgid(pid, pgid)?; - Ok(()) - } - - pub fn getpgid(&self, requester_driver: &str, pid: u32) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - Ok(self.processes.getpgid(pid)?) - } - - pub fn getpid(&self, requester_driver: &str, pid: u32) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - Ok(pid) - } - - pub fn sigprocmask( - &self, - requester_driver: &str, - pid: u32, - how: SigmaskHow, - set: SignalSet, - ) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - Ok(self.processes.sigprocmask(pid, how, set)?) - } - - pub fn sigpending(&self, requester_driver: &str, pid: u32) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - Ok(self.processes.sigpending(pid)?) - } - - pub fn getppid(&self, requester_driver: &str, pid: u32) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - Ok(self.processes.getppid(pid)?) - } - - pub fn setsid(&self, requester_driver: &str, pid: u32) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - Ok(self.processes.setsid(pid)?) - } - - pub fn getsid(&self, requester_driver: &str, pid: u32) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - Ok(self.processes.getsid(pid)?) - } - - pub fn dev_fd_read_dir(&self, requester_driver: &str, pid: u32) -> KernelResult> { - self.assert_driver_owns(requester_driver, pid)?; - let tables = lock_or_recover(&self.fd_tables); - let table = tables - .get(pid) - .ok_or_else(|| KernelError::no_such_process(pid))?; - let entry_count = table.len(); - self.resources.check_readdir_entries(entry_count)?; - Ok(table.iter().map(|entry| entry.fd.to_string()).collect()) - } - - pub fn dev_fd_stat( - &mut self, - requester_driver: &str, - pid: u32, - fd: u32, - ) -> KernelResult { - self.assert_driver_owns(requester_driver, pid)?; - let entry = { - let tables = lock_or_recover(&self.fd_tables); - tables - .get(pid) - .and_then(|table| table.get(fd)) - .cloned() - .ok_or_else(|| KernelError::bad_file_descriptor(fd))? - }; - - if self.pipes.is_pipe(entry.description.id()) || self.ptys.is_pty(entry.description.id()) { - return Ok(synthetic_character_device_stat(entry.description.id())); - } - - if is_proc_path(entry.description.path()) { - return self.proc_stat_from_open_path(Some(pid), entry.description.path()); - } - - Ok(self.filesystem.stat(entry.description.path())?) - } - - pub fn dispose(&mut self) -> KernelResult<()> { - if self.terminated { - return Ok(()); - } - - dispose_kernel_vm_resources(self); - Ok(()) - } - - fn prepare_fd_open( - &mut self, - path: &str, - flags: u32, - mode: Option, - ) -> KernelResult<(u8, Option)> { - if open_requires_write_access(flags) { - self.reject_read_only_resolved_write_path(path)?; - } - - if flags & O_CREAT != 0 && flags & O_EXCL != 0 { - self.check_write_file_limits(path, 0)?; - VirtualFileSystem::create_file_exclusive_with_mode( - &mut self.filesystem, - path, - Vec::new(), - mode, - )?; - self.update_filesystem_usage_cache_for_inode_create(0); - let stat = VirtualFileSystem::stat(&mut self.filesystem, path)?; - return Ok(( - filetype_for_path(path, &stat), - Some(FileLockTarget::new(stat.ino)), - )); - } - - let exists = self.filesystem.exists(path)?; - if exists { - if flags & O_TRUNC != 0 { - let existing_size = self.current_storage_file_size(path)?; - self.check_path_resize_limits_with_existing(existing_size, 0)?; - VirtualFileSystem::truncate(&mut self.filesystem, path, 0)?; - self.update_filesystem_usage_cache_for_resize(existing_size, 0); - } - } else if flags & O_CREAT != 0 { - self.check_write_file_limits(path, 0)?; - VirtualFileSystem::write_file_with_mode(&mut self.filesystem, path, Vec::new(), mode)?; - self.update_filesystem_usage_cache_for_inode_create(0); - } else { - let _ = VirtualFileSystem::stat(&mut self.filesystem, path)?; - unreachable!("stat should return an error when opening a missing path"); - } - - let stat = VirtualFileSystem::stat(&mut self.filesystem, path)?; - Ok(( - filetype_for_path(path, &stat), - Some(FileLockTarget::new(stat.ino)), - )) - } - - fn reject_read_only_write_path(&mut self, path: &str) -> KernelResult<()> { - if is_proc_path(path) { - self.filesystem - .check_virtual_path(FsOperation::Write, path) - .map_err(KernelError::from)?; - return Err(read_only_filesystem_error(path)); - } - - if is_agentos_path(path) { - return Err(read_only_filesystem_error(path)); - } - - Ok(()) - } - - fn reject_read_only_resolved_write_path(&mut self, path: &str) -> KernelResult<()> { - self.reject_read_only_write_path(path)?; - - if let Some(resolved) = self.resolve_write_guard_path(path, true)? { - if is_agentos_path(&resolved) { - return Err(read_only_filesystem_error(&resolved)); - } - if self.has_agentos_hardlink_alias(&resolved)? { - return Err(read_only_filesystem_error(&resolved)); - } - } - if self.has_agentos_hardlink_alias(path)? { - return Err(read_only_filesystem_error(path)); - } - - Ok(()) - } - - fn reject_read_only_entry_write_path(&mut self, path: &str) -> KernelResult<()> { - self.reject_read_only_write_path(path)?; - - if let Some(resolved) = self.resolve_write_guard_path(path, false)? { - if is_agentos_path(&resolved) { - return Err(read_only_filesystem_error(&resolved)); - } - if self.has_agentos_hardlink_alias(&resolved)? { - return Err(read_only_filesystem_error(&resolved)); - } - } - if self.has_agentos_hardlink_alias(path)? { - return Err(read_only_filesystem_error(path)); - } - - Ok(()) - } - - fn has_agentos_hardlink_alias(&mut self, path: &str) -> KernelResult { - let Some(target) = self.storage_lstat(path)? else { - return Ok(false); - }; - if target.is_directory || target.is_symbolic_link { - return Ok(false); - } - - self.agentos_subtree_contains_inode("/etc/agentos", target.dev, target.ino) - } - - fn agentos_subtree_contains_inode( - &mut self, - path: &str, - target_dev: u64, - target_ino: u64, - ) -> KernelResult { - let Some(stat) = self.storage_lstat(path)? else { - return Ok(false); - }; - if !stat.is_directory && !stat.is_symbolic_link { - return Ok(stat.dev == target_dev && stat.ino == target_ino); - } - if !stat.is_directory { - return Ok(false); - } - - let children = self.raw_filesystem_mut().read_dir_with_types(path)?; - for child in children { - if child.name == "." || child.name == ".." { - continue; - } - let child_path = join_absolute_path(path, &child.name); - if self.agentos_subtree_contains_inode(&child_path, target_dev, target_ino)? { - return Ok(true); - } - } - - Ok(false) - } - - fn resolve_write_guard_path( - &mut self, - path: &str, - follow_final_symlink: bool, - ) -> KernelResult> { - let normalized = normalize_path(path); - if normalized == "/" { - return Ok(Some(normalized)); - } - - if follow_final_symlink { - if let Ok(resolved) = self.filesystem.realpath(&normalized) { - return Ok(Some(resolved)); - } - } - - let components: Vec<&str> = normalized - .split('/') - .filter(|component| !component.is_empty()) - .collect(); - let mut resolved_prefix = String::from("/"); - let mut raw_prefix = String::from("/"); - - for (index, component) in components.iter().enumerate() { - let is_final = index + 1 == components.len(); - if is_final && !follow_final_symlink { - return Ok(Some(join_absolute_path(&resolved_prefix, component))); - } - - raw_prefix = join_absolute_path(&raw_prefix, component); - match self.filesystem.realpath(&raw_prefix) { - Ok(resolved) => { - resolved_prefix = resolved; - } - Err(error) if error.code() == "ENOENT" => { - let mut resolved = resolved_prefix; - for remaining in &components[index..] { - resolved = join_absolute_path(&resolved, remaining); - } - return Ok(Some(resolved)); - } - Err(error) => return Err(error.into()), - } - } - - Ok(Some(resolved_prefix)) - } - - fn populate_poll_target_revents( - &self, - pid: u32, - targets: &mut [PollTargetEntry], - ) -> KernelResult { - let mut ready_count = 0; - for target in targets.iter_mut() { - target.revents = self.poll_target_entry(pid, target.target, target.events)?; - if !target.revents.is_empty() { - ready_count += 1; - } - } - - Ok(ready_count) - } - - fn poll_target_entry( - &self, - pid: u32, - target: PollTarget, - requested: PollEvents, - ) -> KernelResult { - match target { - PollTarget::Fd(fd) => { - let entry = { - let tables = lock_or_recover(&self.fd_tables); - tables - .get(pid) - .ok_or_else(|| KernelError::no_such_process(pid))? - .get(fd) - .cloned() - }; - if let Some(entry) = entry { - self.poll_entry(&entry, requested) - } else { - Ok(POLLNVAL) - } - } - PollTarget::Socket(socket_id) => { - let socket = self.sockets.get(socket_id); - if let Some(socket) = socket { - if socket.owner_pid() != pid { - return Err(KernelError::permission_denied(format!( - "process {pid} does not own socket {socket_id}" - ))); - } - let mut events = self.sockets.poll(socket_id, requested)?; - if events.intersects(POLLOUT) - && !self.socket_pollout_has_resource_capacity(&socket) - { - events = PollEvents::from_bits(events.bits() & !POLLOUT.bits()); - } - Ok(events) - } else { - Ok(POLLNVAL) - } - } - } - } - - fn socket_pollout_has_resource_capacity(&self, socket: &SocketRecord) -> bool { - let snapshot = self.resource_snapshot(); - if self - .resources - .limits() - .max_socket_buffered_bytes - .is_some_and(|limit| snapshot.socket_buffered_bytes >= limit) - { - return false; - } - - if socket.spec().socket_type == SocketType::Datagram - && self - .resources - .limits() - .max_socket_datagram_queue_len - .is_some_and(|limit| snapshot.socket_datagram_queue_len >= limit) - { - return false; - } - - true - } - - fn poll_entry( - &self, - entry: &crate::fd_table::FdEntry, - requested: PollEvents, - ) -> KernelResult { - if self.pipes.is_pipe(entry.description.id()) { - return Ok(self.pipes.poll(entry.description.id(), requested)?); - } - - if self.ptys.is_pty(entry.description.id()) { - return Ok(self.ptys.poll(entry.description.id(), requested)?); - } - - let access_mode = entry.description.flags() & 0b11; - let mut events = PollEvents::empty(); - if requested.intersects(POLLIN) && access_mode != crate::fd_table::O_WRONLY { - events |= POLLIN; - } - if requested.intersects(POLLOUT) && access_mode != crate::fd_table::O_RDONLY { - events |= POLLOUT; - } - if entry.filetype == FILETYPE_DIRECTORY && requested.intersects(POLLOUT) { - events |= POLLERR; - } - if self.terminated { - events |= POLLHUP; - } - Ok(events) - } - - fn description_for_fd( - &self, - requester_driver: &str, - pid: u32, - fd: u32, - ) -> KernelResult> { - self.assert_driver_owns(requester_driver, pid)?; - lock_or_recover(&self.fd_tables) - .get(pid) - .and_then(|table| table.get(fd)) - .map(|entry| Arc::clone(&entry.description)) - .ok_or_else(|| KernelError::bad_file_descriptor(fd)) - } - - fn assert_not_terminated(&self) -> KernelResult<()> { - if self.terminated { - Err(KernelError::disposed()) - } else { - Ok(()) - } - } - - fn assert_driver_owns(&self, requester_driver: &str, pid: u32) -> KernelResult<()> { - let driver_pids = lock_or_recover(&self.driver_pids); - if driver_pids - .get(requester_driver) - .map(|pids| pids.contains(&pid)) - .unwrap_or(false) - { - return Ok(()); - } - - if driver_pids.values().any(|pids| pids.contains(&pid)) { - return Err(KernelError::permission_denied(format!( - "driver \"{requester_driver}\" does not own PID {pid}" - ))); - } - - Err(KernelError::no_such_process(pid)) - } - - fn cleanup_process_resources(&self, pid: u32) { - cleanup_process_resources( - self.fd_tables.as_ref(), - &self.file_locks, - &self.pipes, - &self.ptys, - &self.sockets, - self.driver_pids.as_ref(), - pid, - ); - } - - fn resolve_spawn_command( - &mut self, - command: &str, - args: &[String], - cwd: &str, - ) -> KernelResult { - if let Some(driver) = self.commands.resolve(command).cloned() { - return Ok(ResolvedSpawnCommand { - command: command.to_owned(), - args: args.to_vec(), - driver, - }); - } - - let Some(path) = self.resolve_executable_path(command, cwd)? else { - return Err(KernelError::command_not_found(command)); - }; - - if let Some(registered_command) = self.resolve_registered_command_path(&path) { - let driver = self - .commands - .resolve(®istered_command) - .cloned() - .ok_or_else(|| KernelError::command_not_found(®istered_command))?; - return Ok(ResolvedSpawnCommand { - command: registered_command, - args: args.to_vec(), - driver, - }); - } - - let shebang = self - .parse_shebang_command(&path)? - .ok_or_else(|| KernelError::new("ENOEXEC", format!("exec format error: {path}")))?; - self.resolve_shebang_command(&path, args, shebang) - } - - fn resolve_executable_path( - &mut self, - command: &str, - cwd: &str, - ) -> KernelResult> { - if !command.contains('/') { - return Ok(None); - } - - let path = if command.starts_with('/') { - normalize_path(command) - } else { - normalize_path(&format!("{cwd}/{command}")) - }; - // exec(2) follows symlinks, and a symlink target may live in a different - // mount (e.g. `/opt/agentos/bin/` is its own single-symlink mount - // pointing into a package tar mount). Resolve the real path before - // stat-ing / reading the executable so cross-mount symlinked commands - // exec their real target instead of failing to read the symlink node. - let path = self.filesystem.realpath(&path).unwrap_or(path); - let stat = self.filesystem.stat(&path)?; - if stat.is_directory { - return Err(KernelError::new( - "EACCES", - format!("permission denied, execute '{path}'"), - )); - } - if stat.mode & EXECUTABLE_PERMISSION_BITS == 0 { - return Err(KernelError::new( - "EACCES", - format!("permission denied, execute '{path}'"), - )); - } - Ok(Some(path)) - } - - fn resolve_registered_command_path(&self, path: &str) -> Option { - let normalized = normalize_path(path); - for prefix in ["/bin/", "/usr/bin/", "/usr/local/bin/"] { - let Some(name) = normalized.strip_prefix(prefix) else { - continue; - }; - if !name.is_empty() && !name.contains('/') && self.commands.resolve(name).is_some() { - return Some(name.to_owned()); - } - } - - if let Some(name) = normalized - .strip_prefix("/__secure_exec/commands/") - .and_then(|suffix| suffix.rsplit('/').next()) - { - if !name.is_empty() && !name.contains('/') && self.commands.resolve(name).is_some() { - return Some(name.to_owned()); - } - } - - None - } - - fn parse_shebang_command(&mut self, path: &str) -> KernelResult> { - let header = self.filesystem.pread(path, 0, SHEBANG_LINE_MAX_BYTES + 1)?; - if !header.starts_with(b"#!") { - return Ok(None); - } - - let line_end = match header.iter().position(|byte| *byte == b'\n') { - Some(index) => index, - None if header.len() <= SHEBANG_LINE_MAX_BYTES => header.len(), - None => { - return Err(KernelError::new( - "ENOEXEC", - format!("shebang line exceeds {SHEBANG_LINE_MAX_BYTES} bytes: {path}"), - )); - } - }; - let line = header[2..line_end] - .strip_suffix(b"\r") - .unwrap_or(&header[2..line_end]); - let text = std::str::from_utf8(line) - .map_err(|_| KernelError::new("ENOEXEC", format!("invalid shebang line: {path}")))?; - let mut parts = text.split_ascii_whitespace(); - let interpreter = parts - .next() - .ok_or_else(|| KernelError::new("ENOEXEC", format!("invalid shebang line: {path}")))?; - Ok(Some(ShebangCommand { - interpreter: interpreter.to_owned(), - args: parts.map(ToOwned::to_owned).collect(), - })) - } - - fn resolve_shebang_command( - &self, - path: &str, - args: &[String], - shebang: ShebangCommand, - ) -> KernelResult { - let mut interpreter_args = shebang.args; - let interpreter = normalize_path(&shebang.interpreter); - let command = if interpreter == "/usr/bin/env" || interpreter == "/bin/env" { - if interpreter_args.is_empty() { - return Err(KernelError::new( - "ENOENT", - format!("missing interpreter after /usr/bin/env in shebang: {path}"), - )); - } - interpreter_args.remove(0) - } else if let Some(command) = self.resolve_registered_command_path(&interpreter) { - command - } else if self.commands.resolve(&shebang.interpreter).is_some() { - shebang.interpreter - } else { - return Err(KernelError::command_not_found(&shebang.interpreter)); - }; - - let driver = self - .commands - .resolve(&command) - .cloned() - .ok_or_else(|| KernelError::command_not_found(&command))?; - let mut resolved_args = interpreter_args; - resolved_args.push(path.to_owned()); - resolved_args.extend(args.iter().cloned()); - Ok(ResolvedSpawnCommand { - command, - args: resolved_args, - driver, - }) - } - - fn finish_waitpid_event(&mut self, result: ProcessWaitResult) -> WaitPidEventResult { - if result.event == WaitPidEvent::Exited { - self.cleanup_process_resources(result.pid); - } - WaitPidEventResult { - pid: result.pid, - status: result.status, - event: result.event, - } - } - - fn raw_filesystem_mut(&mut self) -> &mut F { - self.filesystem.inner_mut().inner_mut() - } - - fn read_file_internal( - &mut self, - current_pid: Option, - path: &str, - ) -> KernelResult> { - if let Some(proc_node) = self.resolve_proc_node(path, current_pid)? { - self.filesystem - .check_virtual_path(FsOperation::Read, path) - .map_err(KernelError::from)?; - return self.proc_read_file(current_pid, &proc_node); - } - - Ok(self.filesystem.read_file(path)?) - } - - fn effective_recursive_fs_depth( - &self, - requested_max_depth: Option, - ) -> KernelResult { - match (requested_max_depth, self.resources.max_recursive_fs_depth()) { - (Some(requested), Some(limit)) if requested > limit => Err(KernelError::new( - "EINVAL", - format!( - "requested recursive filesystem max depth {requested} exceeds configured limit {limit}" - ), - )), - (Some(requested), _) => Ok(requested), - (None, Some(limit)) => Ok(limit), - (None, None) => Ok(usize::MAX), - } - } - - fn copy_path_inner( - &mut self, - from: &str, - to: &str, - recursive: bool, - depth: usize, - entries: &mut usize, - ) -> KernelResult<()> { - self.resources.check_recursive_fs_depth(depth)?; - *entries = entries.saturating_add(1); - self.resources.check_recursive_fs_entries(*entries)?; - let source_stat = self.lstat_internal(None, from)?; - - if source_stat.is_symbolic_link { - let target = self.read_link_internal(None, from)?; - self.symlink(&target, to)?; - return Ok(()); - } - - if source_stat.is_directory { - if !recursive { - return Err(KernelError::new( - "EISDIR", - format!("illegal operation on a directory, copy '{from}'"), - )); - } - - let source_root = normalize_path(from); - let destination_root = normalize_path(to); - if destination_root.starts_with(&(source_root.clone() + "/")) { - return Err(KernelError::new( - "EINVAL", - format!("cannot copy '{from}' into its own descendant '{to}'"), - )); - } - - self.mkdir(&parent_path(&destination_root), true)?; - if !self.exists_internal(None, &destination_root)? { - self.create_dir(&destination_root)?; - } - self.chmod(&destination_root, source_stat.mode)?; - self.chown(&destination_root, source_stat.uid, source_stat.gid)?; - - let names = self.read_dir_internal(None, from)?; - self.resources.check_readdir_entries(names.len())?; - for name in names { - if matches!(name.as_str(), "." | "..") { - continue; - } - let child_from = join_child_path(from, &name); - let child_to = join_child_path(to, &name); - self.copy_path_inner( - &child_from, - &child_to, - true, - depth.saturating_add(1), - entries, - )?; - } - return Ok(()); - } - - let content = self.read_file_internal(None, from)?; - self.write_file(to, content)?; - self.chmod(to, source_stat.mode)?; - self.chown(to, source_stat.uid, source_stat.gid) - } - - fn remove_path_inner( - &mut self, - path: &str, - recursive: bool, - depth: usize, - entries: &mut usize, - ) -> KernelResult<()> { - self.resources.check_recursive_fs_depth(depth)?; - *entries = entries.saturating_add(1); - self.resources.check_recursive_fs_entries(*entries)?; - let stat = self.lstat_internal(None, path)?; - if stat.is_directory && !stat.is_symbolic_link { - if recursive { - let names = self.read_dir_internal(None, path)?; - self.resources.check_readdir_entries(names.len())?; - for name in names { - if matches!(name.as_str(), "." | "..") { - continue; - } - let child = join_child_path(path, &name); - self.remove_path_inner(&child, true, depth.saturating_add(1), entries)?; - } - } - return self.remove_dir(path); - } - - self.remove_file(path) - } - - fn exists_internal(&self, current_pid: Option, path: &str) -> KernelResult { - match self.resolve_proc_node(path, current_pid) { - Ok(Some(_)) => { - self.filesystem - .check_virtual_path(FsOperation::Read, path) - .map_err(KernelError::from)?; - Ok(true) - } - Ok(None) => Ok(self.filesystem.exists(path)?), - Err(error) if error.code() == "ENOENT" => Ok(false), - Err(error) => Err(error), - } - } - - fn stat_internal(&mut self, current_pid: Option, path: &str) -> KernelResult { - if let Some(proc_node) = self.resolve_proc_node(path, current_pid)? { - self.filesystem - .check_virtual_path(FsOperation::Read, path) - .map_err(KernelError::from)?; - return self.proc_stat(current_pid, &proc_node); - } - - Ok(self.filesystem.stat(path)?) - } - - fn lstat_internal(&self, current_pid: Option, path: &str) -> KernelResult { - if let Some(proc_node) = self.resolve_proc_node(path, current_pid)? { - self.filesystem - .check_virtual_path(FsOperation::Read, path) - .map_err(KernelError::from)?; - return self.proc_lstat(&proc_node); - } - - Ok(self.filesystem.lstat(path)?) - } - - fn read_link_internal(&self, current_pid: Option, path: &str) -> KernelResult { - if let Some(proc_node) = self.resolve_proc_node(path, current_pid)? { - self.filesystem - .check_virtual_path(FsOperation::Read, path) - .map_err(KernelError::from)?; - return self.proc_read_link(&proc_node); - } - - Ok(self.filesystem.read_link(path)?) - } - - fn read_dir_internal( - &mut self, - current_pid: Option, - path: &str, - ) -> KernelResult> { - if let Some(proc_node) = self.resolve_proc_node(path, current_pid)? { - self.filesystem - .check_virtual_path(FsOperation::Read, path) - .map_err(KernelError::from)?; - return self.proc_read_dir(current_pid, &proc_node); - } - - if let Some(limit) = self.resources.max_readdir_entries() { - Ok(self.filesystem.read_dir_limited(path, limit)?) - } else { - Ok(self.filesystem.read_dir(path)?) - } - } - - fn read_dir_with_types_internal( - &mut self, - current_pid: Option, - path: &str, - ) -> KernelResult> { - if let Some(proc_node) = self.resolve_proc_node(path, current_pid)? { - self.filesystem - .check_virtual_path(FsOperation::Read, path) - .map_err(KernelError::from)?; - return Ok(self - .proc_read_dir(current_pid, &proc_node)? - .into_iter() - .map(|name| VirtualDirEntry { - name, - is_directory: false, - is_symbolic_link: false, - }) - .collect()); - } - - Ok(self.filesystem.read_dir_with_types(path)?) - } - - fn realpath_internal(&self, current_pid: Option, path: &str) -> KernelResult { - if let Some(proc_node) = self.resolve_proc_node(path, current_pid)? { - self.filesystem - .check_virtual_path(FsOperation::Read, path) - .map_err(KernelError::from)?; - return self.proc_realpath(current_pid, &proc_node); - } - - Ok(self.filesystem.realpath(path)?) - } - - fn resolve_proc_node( - &self, - path: &str, - current_pid: Option, - ) -> KernelResult> { - let normalized = normalize_path(path); - if !is_proc_path(&normalized) { - return Ok(None); - } - - if normalized == "/proc" { - return Ok(Some(ProcNode::RootDir)); - } - - let suffix = normalized - .strip_prefix("/proc/") - .expect("proc path should have /proc prefix"); - let parts = suffix.split('/').collect::>(); - if parts.is_empty() { - return Ok(Some(ProcNode::RootDir)); - } - - let root_node = match parts.as_slice() { - ["mounts"] => Some(ProcNode::MountsFile), - ["cpuinfo"] => Some(ProcNode::CpuInfoFile), - ["meminfo"] => Some(ProcNode::MemInfoFile), - ["loadavg"] => Some(ProcNode::LoadAvgFile), - ["uptime"] => Some(ProcNode::UptimeFile), - ["version"] => Some(ProcNode::VersionFile), - _ => None, - }; - if let Some(node) = root_node { - return Ok(Some(node)); - } - - let pid = match parts[0] { - "self" => current_pid.ok_or_else(|| proc_not_found_error(&normalized))?, - raw => raw - .parse::() - .map_err(|_| proc_not_found_error(&normalized))?, - }; - self.proc_entry(pid)?; - - let node = match parts.as_slice() { - ["self"] => ProcNode::SelfLink { pid }, - [_pid] => ProcNode::PidDir { pid }, - [_pid, "fd"] => ProcNode::PidFdDir { pid }, - [_pid, "cmdline"] => ProcNode::PidCmdline { pid }, - [_pid, "environ"] => ProcNode::PidEnviron { pid }, - [_pid, "cwd"] => ProcNode::PidCwdLink { pid }, - [_pid, "stat"] => ProcNode::PidStatFile { pid }, - [_pid, "status"] => ProcNode::PidStatusFile { pid }, - [_pid, "fd", fd] => { - let fd = fd - .parse::() - .map_err(|_| proc_not_found_error(&normalized))?; - self.proc_fd_entry(pid, fd)?; - ProcNode::PidFdLink { pid, fd } - } - _ => return Err(proc_not_found_error(&normalized)), - }; - - Ok(Some(node)) - } - - fn proc_entry(&self, pid: u32) -> KernelResult { - self.processes - .get(pid) - .ok_or_else(|| proc_not_found_error(&format!("/proc/{pid}"))) - } - - fn proc_fd_entry(&self, pid: u32, fd: u32) -> KernelResult { - lock_or_recover(&self.fd_tables) - .get(pid) - .and_then(|table| table.get(fd)) - .cloned() - .ok_or_else(|| proc_not_found_error(&format!("/proc/{pid}/fd/{fd}"))) - } - - fn proc_read_file( - &mut self, - current_pid: Option, - node: &ProcNode, - ) -> KernelResult> { - match node { - ProcNode::SelfLink { .. } - | ProcNode::PidCwdLink { .. } - | ProcNode::PidFdLink { .. } => { - let target = self.proc_symlink_target(node)?; - self.read_file_internal(current_pid, &target) - } - ProcNode::MountsFile => Ok(self.proc_mounts_bytes()), - ProcNode::CpuInfoFile => Ok(self.proc_cpuinfo_bytes()), - ProcNode::MemInfoFile => Ok(self.proc_meminfo_bytes()), - ProcNode::LoadAvgFile => Ok(self.proc_loadavg_bytes()), - ProcNode::UptimeFile => Ok(self.proc_uptime_bytes()), - ProcNode::VersionFile => Ok(self.proc_version_bytes()), - ProcNode::PidCmdline { pid } => Ok(self.proc_cmdline_bytes(*pid)), - ProcNode::PidEnviron { pid } => Ok(self.proc_environ_bytes(*pid)), - ProcNode::PidStatFile { pid } => Ok(self.proc_stat_bytes(*pid)), - ProcNode::PidStatusFile { pid } => Ok(self.proc_status_bytes(*pid)), - ProcNode::RootDir | ProcNode::PidDir { .. } | ProcNode::PidFdDir { .. } => { - Err(KernelError::new( - "EISDIR", - format!( - "illegal operation on a directory, read '{}'", - self.proc_canonical_path(node) - ), - )) - } - } - } - - fn proc_stat( - &mut self, - current_pid: Option, - node: &ProcNode, - ) -> KernelResult { - match node { - ProcNode::SelfLink { .. } - | ProcNode::PidCwdLink { .. } - | ProcNode::PidFdLink { .. } => { - let target = self.proc_symlink_target(node)?; - self.stat_internal(current_pid, &target) - } - _ => self.proc_lstat(node), - } - } - - fn proc_lstat(&self, node: &ProcNode) -> KernelResult { - match node { - ProcNode::RootDir | ProcNode::PidDir { .. } | ProcNode::PidFdDir { .. } => { - Ok(proc_dir_stat(proc_inode(node))) - } - ProcNode::MountsFile => Ok(proc_file_stat( - proc_inode(node), - self.proc_mounts_bytes().len() as u64, - )), - ProcNode::CpuInfoFile => Ok(proc_file_stat( - proc_inode(node), - self.proc_cpuinfo_bytes().len() as u64, - )), - ProcNode::MemInfoFile => Ok(proc_file_stat( - proc_inode(node), - self.proc_meminfo_bytes().len() as u64, - )), - ProcNode::LoadAvgFile => Ok(proc_file_stat( - proc_inode(node), - self.proc_loadavg_bytes().len() as u64, - )), - ProcNode::UptimeFile => Ok(proc_file_stat( - proc_inode(node), - self.proc_uptime_bytes().len() as u64, - )), - ProcNode::VersionFile => Ok(proc_file_stat( - proc_inode(node), - self.proc_version_bytes().len() as u64, - )), - ProcNode::PidCmdline { pid } => Ok(proc_file_stat( - proc_inode(node), - self.proc_cmdline_bytes(*pid).len() as u64, - )), - ProcNode::PidEnviron { pid } => Ok(proc_file_stat( - proc_inode(node), - self.proc_environ_bytes(*pid).len() as u64, - )), - ProcNode::PidStatFile { pid } => Ok(proc_file_stat( - proc_inode(node), - self.proc_stat_bytes(*pid).len() as u64, - )), - ProcNode::PidStatusFile { pid } => Ok(proc_file_stat( - proc_inode(node), - self.proc_status_bytes(*pid).len() as u64, - )), - ProcNode::SelfLink { .. } - | ProcNode::PidCwdLink { .. } - | ProcNode::PidFdLink { .. } => Ok(proc_symlink_stat( - proc_inode(node), - self.proc_read_link(node)?.len() as u64, - )), - } - } - - fn proc_read_link(&self, node: &ProcNode) -> KernelResult { - match node { - ProcNode::SelfLink { .. } - | ProcNode::PidCwdLink { .. } - | ProcNode::PidFdLink { .. } => self.proc_symlink_target(node), - _ => Err(KernelError::new( - "EINVAL", - format!( - "invalid argument, readlink '{}'", - self.proc_canonical_path(node) - ), - )), - } - } - - fn proc_read_dir( - &mut self, - current_pid: Option, - node: &ProcNode, - ) -> KernelResult> { - match node { - ProcNode::SelfLink { .. } - | ProcNode::PidCwdLink { .. } - | ProcNode::PidFdLink { .. } => { - let target = self.proc_symlink_target(node)?; - self.read_dir_internal(current_pid, &target) - } - ProcNode::RootDir => { - let mut entries = self - .processes - .list_processes() - .keys() - .map(|pid| pid.to_string()) - .collect::>(); - entries.push(String::from("cpuinfo")); - entries.push(String::from("loadavg")); - entries.push(String::from("meminfo")); - entries.push(String::from("mounts")); - entries.push(String::from("self")); - entries.push(String::from("uptime")); - entries.push(String::from("version")); - entries.sort(); - Ok(entries) - } - ProcNode::PidDir { .. } => Ok(vec![ - String::from("cmdline"), - String::from("cwd"), - String::from("environ"), - String::from("fd"), - String::from("stat"), - String::from("status"), - ]), - ProcNode::PidFdDir { pid } => { - let tables = lock_or_recover(&self.fd_tables); - let table = tables - .get(*pid) - .ok_or_else(|| proc_not_found_error(&format!("/proc/{pid}/fd")))?; - Ok(table.iter().map(|entry| entry.fd.to_string()).collect()) - } - _ => Err(KernelError::new( - "ENOTDIR", - format!( - "not a directory, scandir '{}'", - self.proc_canonical_path(node) - ), - )), - } - } - - fn proc_realpath(&self, current_pid: Option, node: &ProcNode) -> KernelResult { - match node { - ProcNode::SelfLink { .. } - | ProcNode::PidCwdLink { .. } - | ProcNode::PidFdLink { .. } => { - let target = self.proc_symlink_target(node)?; - self.realpath_internal(current_pid, &target) - } - _ => Ok(self.proc_canonical_path(node)), - } - } - - fn proc_symlink_target(&self, node: &ProcNode) -> KernelResult { - match node { - ProcNode::SelfLink { pid } => Ok(format!("/proc/{pid}")), - ProcNode::PidCwdLink { pid } => Ok(self.proc_entry(*pid)?.cwd), - ProcNode::PidFdLink { pid, fd } => { - Ok(self.proc_fd_entry(*pid, *fd)?.description.path().to_owned()) - } - _ => Err(KernelError::new( - "EINVAL", - format!( - "'{}' is not a symbolic link", - self.proc_canonical_path(node) - ), - )), - } - } - - fn proc_canonical_path(&self, node: &ProcNode) -> String { - match node { - ProcNode::RootDir => String::from("/proc"), - ProcNode::MountsFile => String::from("/proc/mounts"), - ProcNode::CpuInfoFile => String::from("/proc/cpuinfo"), - ProcNode::MemInfoFile => String::from("/proc/meminfo"), - ProcNode::LoadAvgFile => String::from("/proc/loadavg"), - ProcNode::UptimeFile => String::from("/proc/uptime"), - ProcNode::VersionFile => String::from("/proc/version"), - ProcNode::SelfLink { pid } => format!("/proc/{pid}"), - ProcNode::PidDir { pid } => format!("/proc/{pid}"), - ProcNode::PidFdDir { pid } => format!("/proc/{pid}/fd"), - ProcNode::PidCmdline { pid } => format!("/proc/{pid}/cmdline"), - ProcNode::PidEnviron { pid } => format!("/proc/{pid}/environ"), - ProcNode::PidCwdLink { pid } => format!("/proc/{pid}/cwd"), - ProcNode::PidStatFile { pid } => format!("/proc/{pid}/stat"), - ProcNode::PidStatusFile { pid } => format!("/proc/{pid}/status"), - ProcNode::PidFdLink { pid, fd } => format!("/proc/{pid}/fd/{fd}"), - } - } - - fn proc_cmdline_bytes(&self, pid: u32) -> Vec { - let entry = self - .processes - .get(pid) - .expect("process must exist while procfs path is resolved"); - let mut argv = vec![entry.command]; - argv.extend(entry.args); - null_separated_bytes(argv) - } - - fn proc_environ_bytes(&self, pid: u32) -> Vec { - let entry = self - .processes - .get(pid) - .expect("process must exist while procfs path is resolved"); - null_separated_bytes( - entry - .env - .into_iter() - .map(|(key, value)| format!("{key}={value}")) - .collect(), - ) - } - - fn proc_stat_bytes(&self, pid: u32) -> Vec { - let entry = self - .processes - .get(pid) - .expect("process must exist while procfs path is resolved"); - let command = entry.command.replace(')', "]"); - let state = match entry.status { - ProcessStatus::Running => 'R', - ProcessStatus::Stopped => 'T', - ProcessStatus::Exited => 'Z', - }; - format!( - "{pid} ({command}) {state} {ppid} {pgid} {sid} 0 0 0 0 0 0 0 0 0 0 20 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", - ppid = entry.ppid, - pgid = entry.pgid, - sid = entry.sid, - ) - .into_bytes() - } - - fn proc_mounts_bytes(&self) -> Vec { - let mounts = if let Some(table) = - (self.filesystem.inner().inner() as &dyn Any).downcast_ref::() - { - table.get_mounts() - } else { - vec![MountEntry { - path: String::from("/"), - plugin_id: String::from("root"), - read_only: false, - }] - }; - - mounts - .into_iter() - .map(|mount| { - let options = if mount.read_only { "ro" } else { "rw" }; - format!( - "{source} {target} {fstype} {options} 0 0\n", - source = mount.plugin_id, - target = mount.path, - fstype = mount.plugin_id, - ) - }) - .collect::() - .into_bytes() - } - - fn proc_cpu_count(&self) -> usize { - self.resource_limits().virtual_cpu_count.unwrap_or(1) - } - - fn proc_cpuinfo_bytes(&self) -> Vec { - let mut body = String::new(); - for processor in 0..self.proc_cpu_count() { - body.push_str(&format!( - "processor\t: {processor}\nmodel name\t: secure-exec Virtual CPU\ncpu MHz\t\t: 1000.000\nsiblings\t: 1\ncpu cores\t: 1\n\n" - )); - } - body.into_bytes() - } - - fn proc_mem_total_bytes(&self) -> u64 { - self.resource_limits() - .max_wasm_memory_bytes - .or(self.resource_limits().max_filesystem_bytes) - .unwrap_or(DEFAULT_MAX_OPEN_FDS as u64 * 1024 * 1024) - } - - fn proc_meminfo_bytes(&self) -> Vec { - let total_kb = self.proc_mem_total_bytes().div_ceil(1024); - let zero_kb = 0; - format!( - "MemTotal:{total_kb:>8} kB\nMemFree:{total_kb:>9} kB\nMemAvailable:{total_kb:>4} kB\nBuffers:{zero_kb:>9} kB\nCached:{zero_kb:>10} kB\n" - ) - .into_bytes() - } - - fn proc_loadavg_bytes(&self) -> Vec { - let processes = self.processes.list_processes(); - let running = processes - .values() - .filter(|process| process.status == ProcessStatus::Running) - .count(); - let total = processes.len().max(1); - let last_pid = processes.keys().next_back().copied().unwrap_or(0); - format!("0.00 0.00 0.00 {running}/{total} {last_pid}\n").into_bytes() - } - - fn proc_uptime_bytes(&self) -> Vec { - let uptime = self.boot_instant.elapsed().as_secs_f64(); - format!("{uptime:.2} {uptime:.2}\n").into_bytes() - } - - fn proc_version_bytes(&self) -> Vec { - format!( - "Linux version 6.8.0-agentos (agentos@localhost) #1 SMP boot={}\n", - self.boot_time_ms - ) - .into_bytes() - } - - fn proc_status_bytes(&self, pid: u32) -> Vec { - let entry = self - .processes - .get(pid) - .expect("process must exist while procfs path is resolved"); - let (state_code, state_name) = match entry.status { - ProcessStatus::Running => ('R', "running"), - ProcessStatus::Stopped => ('T', "stopped"), - ProcessStatus::Exited => ('Z', "zombie"), - }; - format!( - "Name:\t{name}\nState:\t{state_code} ({state_name})\nPid:\t{pid}\nPPid:\t{ppid}\nUid:\t{uid}\t{euid}\t{euid}\t{euid}\nGid:\t{gid}\t{egid}\t{egid}\t{egid}\nVmSize:\t{:>8} kB\nVmRSS:\t{:>9} kB\nThreads:\t1\n", - 0, - 0, - name = entry.command, - ppid = entry.ppid, - uid = entry.identity.uid, - euid = entry.identity.euid, - gid = entry.identity.gid, - egid = entry.identity.egid, - ) - .into_bytes() - } - - fn proc_read_file_from_open_path( - &mut self, - current_pid: Option, - path: &str, - ) -> KernelResult> { - let node = self - .resolve_proc_node(path, current_pid)? - .ok_or_else(|| proc_not_found_error(path))?; - self.proc_read_file(current_pid, &node) - } - - fn proc_stat_from_open_path( - &mut self, - current_pid: Option, - path: &str, - ) -> KernelResult { - let node = self - .resolve_proc_node(path, current_pid)? - .ok_or_else(|| proc_not_found_error(path))?; - self.proc_stat(current_pid, &node) - } - - fn filesystem_usage(&mut self) -> KernelResult { - if let Some(usage) = self.filesystem_usage_cache.clone() { - return Ok(usage); - } - let filesystem = self.raw_filesystem_mut(); - let filesystem_any = filesystem as &mut dyn Any; - let usage = if let Some(mount_table) = filesystem_any.downcast_mut::() { - mount_table.root_usage()? - } else { - measure_filesystem_usage(filesystem)? - }; - self.filesystem_usage_cache = Some(usage.clone()); - Ok(usage) - } - - fn invalidate_filesystem_usage_cache(&mut self) { - self.filesystem_usage_cache = None; - } - - fn update_filesystem_usage_cache_for_resize(&mut self, old_size: u64, new_size: u64) { - if let Some(usage) = self.filesystem_usage_cache.as_mut() { - usage.total_bytes = usage - .total_bytes - .saturating_sub(old_size) - .saturating_add(new_size); - } - } - - fn update_filesystem_usage_cache_for_write( - &mut self, - existing: Option<&VirtualStat>, - new_size: u64, - ) { - if is_storage_directory(existing) { - return; - } - - if let Some(stat) = existing { - self.update_filesystem_usage_cache_for_resize(stat.size, new_size); - } else { - self.update_filesystem_usage_cache_for_inode_create(new_size); - } - } - - fn update_filesystem_usage_cache_for_inode_create(&mut self, size: u64) { - if let Some(usage) = self.filesystem_usage_cache.as_mut() { - usage.total_bytes = usage.total_bytes.saturating_add(size); - usage.inode_count = usage.inode_count.saturating_add(1); - } - } - - fn update_filesystem_usage_cache_for_inode_creates(&mut self, count: usize) { - if count == 0 { - return; - } - if let Some(usage) = self.filesystem_usage_cache.as_mut() { - usage.inode_count = usage.inode_count.saturating_add(count); - } - } - - fn update_filesystem_usage_cache_for_inode_delete(&mut self, size: u64) { - if let Some(usage) = self.filesystem_usage_cache.as_mut() { - usage.total_bytes = usage.total_bytes.saturating_sub(size); - usage.inode_count = usage.inode_count.saturating_sub(1); - } - } - - fn update_filesystem_usage_cache_for_remove(&mut self, removed: Option<&VirtualStat>) { - let Some(stat) = removed else { - return; - }; - if stat.is_directory || stat.nlink > 1 { - return; - } - self.update_filesystem_usage_cache_for_inode_delete(stat.size); - } - - fn storage_stat(&mut self, path: &str) -> KernelResult> { - if is_virtual_device_storage_path(path) { - return Ok(None); - } - - match self.raw_filesystem_mut().stat(path) { - Ok(stat) => Ok(Some(stat)), - Err(error) if error.code() == "ENOENT" => Ok(None), - Err(error) => Err(error.into()), - } - } - - fn storage_lstat(&mut self, path: &str) -> KernelResult> { - if is_virtual_device_storage_path(path) { - return Ok(None); - } - - match self.raw_filesystem_mut().lstat(path) { - Ok(stat) => Ok(Some(stat)), - Err(error) if error.code() == "ENOENT" => Ok(None), - Err(error) => Err(error.into()), - } - } - - fn current_storage_file_size(&mut self, path: &str) -> KernelResult { - Ok(self - .storage_stat(path)? - .filter(|stat| !stat.is_directory) - .map(|stat| stat.size) - .unwrap_or(0)) - } - - fn apply_creation_mode(&mut self, path: &str, mode: u32, umask: u32) -> KernelResult<()> { - let masked_mode = (mode & !0o777) | ((mode & 0o777) & !(umask & 0o777)); - Ok(self.filesystem.chmod(path, masked_mode)?) - } - - fn missing_directory_paths( - &mut self, - path: &str, - recursive: bool, - ) -> KernelResult> { - let normalized = normalize_path(path); - if normalized == "/" { - return Ok(Vec::new()); - } - - if !recursive { - return Ok(if self.storage_lstat(&normalized)?.is_none() { - vec![normalized] - } else { - Vec::new() - }); - } - - let mut created = Vec::new(); - let mut current = String::from("/"); - for component in normalized - .split('/') - .filter(|component| !component.is_empty()) - { - current = if current == "/" { - format!("/{component}") - } else { - format!("{current}/{component}") - }; - if self.storage_lstat(¤t)?.is_none() { - created.push(current.clone()); - } - } - Ok(created) - } - - fn check_write_file_limits(&mut self, path: &str, new_size: u64) -> KernelResult<()> { - let existing = self.storage_stat(path)?; - self.check_write_file_limits_with_existing(path, existing.as_ref(), new_size) - } - - fn check_write_file_limits_with_existing( - &mut self, - path: &str, - existing: Option<&VirtualStat>, - new_size: u64, - ) -> KernelResult<()> { - if is_virtual_device_storage_path(path) { - return Ok(()); - } - - if let Some(existing) = existing { - if is_storage_directory(Some(existing)) { - return Ok(()); - } - if new_size <= existing.size { - return Ok(()); - } - - let usage = self.filesystem_usage()?; - self.resources.check_filesystem_usage( - &usage, - usage - .total_bytes - .saturating_sub(existing.size) - .saturating_add(new_size), - usage.inode_count, - )?; - return Ok(()); - } - - let usage = self.filesystem_usage()?; - self.resources.check_filesystem_usage( - &usage, - usage.total_bytes.saturating_add(new_size), - usage.inode_count.saturating_add(1), - )?; - Ok(()) - } - - fn check_create_dir_limits(&mut self, path: &str) -> KernelResult<()> { - if is_virtual_device_storage_path(path) || self.storage_lstat(path)?.is_some() { - return Ok(()); - } - - let parent = parent_path(path); - let Some(parent_stat) = self.storage_stat(&parent)? else { - return Ok(()); - }; - if !parent_stat.is_directory { - return Ok(()); - } - - let usage = self.filesystem_usage()?; - self.resources.check_filesystem_usage( - &usage, - usage.total_bytes, - usage.inode_count.saturating_add(1), - )?; - Ok(()) - } - - fn check_mkdir_limits(&mut self, path: &str, recursive: bool) -> KernelResult<()> { - if is_virtual_device_storage_path(path) { - return Ok(()); - } - - if !recursive { - return self.check_create_dir_limits(path); - } - - let usage = self.filesystem_usage()?; - let new_inodes = count_missing_directory_components(self.raw_filesystem_mut(), path, true)?; - self.resources.check_filesystem_usage( - &usage, - usage.total_bytes, - usage.inode_count.saturating_add(new_inodes), - )?; - Ok(()) - } - - fn check_symlink_limits(&mut self, target: &str, link_path: &str) -> KernelResult<()> { - if is_virtual_device_storage_path(link_path) || self.storage_lstat(link_path)?.is_some() { - return Ok(()); - } - - let parent = parent_path(link_path); - let Some(parent_stat) = self.storage_stat(&parent)? else { - return Ok(()); - }; - if !parent_stat.is_directory { - return Ok(()); - } - - let usage = self.filesystem_usage()?; - self.resources.check_filesystem_usage( - &usage, - usage.total_bytes.saturating_add(target.len() as u64), - usage.inode_count.saturating_add(1), - )?; - Ok(()) - } - - fn check_truncate_limits_with_existing( - &mut self, - path: &str, - existing: Option<&VirtualStat>, - length: u64, - ) -> KernelResult<()> { - if is_virtual_device_storage_path(path) { - return Ok(()); - } - - let Some(existing) = existing else { - return Ok(()); - }; - if is_storage_directory(Some(existing)) { - return Ok(()); - } - self.check_path_resize_limits_with_existing(existing.size, length) - } - - fn check_rename_copy_up_limits(&mut self, old_path: &str, new_path: &str) -> KernelResult<()> { - let max_bytes = self.resource_limits().max_filesystem_bytes; - let max_inodes = self.resource_limits().max_inode_count; - let filesystem_any = self.raw_filesystem_mut() as &mut dyn Any; - - if let Some(root) = filesystem_any.downcast_mut::() { - root.check_rename_copy_up_limits(old_path, new_path, max_bytes, max_inodes)?; - return Ok(()); - } - - if let Some(mount_table) = filesystem_any.downcast_mut::() { - mount_table.check_rename_copy_up_limits(old_path, new_path, max_bytes, max_inodes)?; - } - - Ok(()) - } - - fn check_path_resize_limits(&mut self, path: &str, new_size: u64) -> KernelResult<()> { - if is_virtual_device_storage_path(path) { - return Ok(()); - } - - let Some(existing) = self.storage_stat(path)? else { - return Ok(()); - }; - if existing.is_directory { - return Ok(()); - } - self.check_path_resize_limits_with_existing(existing.size, new_size) - } - - fn check_path_resize_limits_with_existing( - &mut self, - existing_size: u64, - new_size: u64, - ) -> KernelResult<()> { - if new_size <= existing_size { - return Ok(()); - } - - let usage = self.filesystem_usage()?; - self.resources.check_filesystem_usage( - &usage, - usage - .total_bytes - .saturating_sub(existing_size) - .saturating_add(new_size), - usage.inode_count, - )?; - Ok(()) - } - - fn blocking_read_timeout(&self) -> Option { - self.resources - .limits() - .max_blocking_read_ms - .map(Duration::from_millis) - } - - fn close_special_resource_if_needed(&self, description: &Arc, filetype: u8) { - close_special_resource_if_needed( - &self.file_locks, - &self.pipes, - &self.ptys, - description, - filetype, - ); - } -} - -impl KernelVm { - fn check_mount_permissions(&self, path: &str) -> KernelResult<()> { - self.filesystem - .check_path(FsOperation::Write, path) - .map_err(KernelError::from)?; - if is_sensitive_mount_path(path) { - self.filesystem - .check_path(FsOperation::MountSensitive, path) - .map_err(KernelError::from)?; - } - Ok(()) - } - - pub fn mount_filesystem( - &mut self, - path: &str, - filesystem: impl VirtualFileSystem + 'static, - options: MountOptions, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.check_mount_permissions(path)?; - self.filesystem - .inner_mut() - .inner_mut() - .mount(path, filesystem, options) - .map_err(KernelError::from) - } - - pub fn mount_boxed_filesystem( - &mut self, - path: &str, - filesystem: Box, - options: MountOptions, - ) -> KernelResult<()> { - self.assert_not_terminated()?; - self.check_mount_permissions(path)?; - self.filesystem - .inner_mut() - .inner_mut() - .mount_boxed(path, filesystem, options) - .map_err(KernelError::from) - } - - pub fn unmount_filesystem(&mut self, path: &str) -> KernelResult<()> { - self.assert_not_terminated()?; - self.check_mount_permissions(path)?; - self.filesystem - .inner_mut() - .inner_mut() - .unmount(path) - .map_err(KernelError::from) - } - - pub fn mounted_filesystems(&self) -> Vec { - self.filesystem.inner().inner().get_mounts() - } - - pub fn root_filesystem_mut(&mut self) -> Option<&mut RootFileSystem> { - self.filesystem - .inner_mut() - .inner_mut() - .root_virtual_filesystem_mut::() - } - - pub fn snapshot_root_filesystem(&mut self) -> KernelResult { - let usage = self.filesystem_usage()?; - self.resources - .check_filesystem_usage(&usage, usage.total_bytes, usage.inode_count)?; - let root = self - .root_filesystem_mut() - .ok_or_else(|| KernelError::new("EINVAL", "native root filesystem is not available"))?; - root.snapshot().map_err(KernelError::from) - } -} - -#[derive(Default)] -struct StubDriverState { - exit_code: Option, - on_exit: Option, - kill_signals: Vec, -} - -#[derive(Default)] -struct StubDriverProcess { - state: Mutex, - waiters: Condvar, -} - -impl StubDriverProcess { - fn finish(&self, exit_code: i32) { - let callback = { - let mut state = lock_or_recover(&self.state); - if state.exit_code.is_some() { - return; - } - state.exit_code = Some(exit_code); - self.waiters.notify_all(); - state.on_exit.clone() - }; - - if let Some(callback) = callback { - callback(exit_code); - } - } - - fn kill_signals(&self) -> Vec { - lock_or_recover(&self.state).kill_signals.clone() - } -} - -impl DriverProcess for StubDriverProcess { - fn kill(&self, signal: i32) { - { - let mut state = lock_or_recover(&self.state); - state.kill_signals.push(signal); - } - if matches!( - signal, - crate::process_table::SIGCHLD | SIGCONT | SIGSTOP | SIGTSTP | SIGWINCH - ) { - return; - } - self.finish(128 + signal); - } - - fn wait(&self, timeout: Duration) -> Option { - let state = lock_or_recover(&self.state); - if let Some(code) = state.exit_code { - return Some(code); - } - - let (state, _) = wait_timeout_or_recover(&self.waiters, state, timeout); - state.exit_code - } - - fn set_on_exit(&self, callback: ProcessExitCallback) { - let maybe_exit = { - let mut state = lock_or_recover(&self.state); - state.on_exit = Some(callback.clone()); - state.exit_code - }; - - if let Some(code) = maybe_exit { - callback(code); - } - } -} - -impl From for KernelError { - fn from(error: VfsError) -> Self { - map_error(error.code(), error.to_string()) - } -} - -fn lock_or_recover<'a, T>(mutex: &'a Mutex) -> MutexGuard<'a, T> { - match mutex.lock() { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -fn wait_timeout_or_recover<'a, T>( - condvar: &Condvar, - guard: MutexGuard<'a, T>, - timeout: Duration, -) -> (MutexGuard<'a, T>, WaitTimeoutResult) { - match condvar.wait_timeout(guard, timeout) { - Ok(result) => result, - Err(poisoned) => poisoned.into_inner(), - } -} - -fn is_sensitive_mount_path(path: &str) -> bool { - let normalized = crate::vfs::normalize_path(path); - normalized == "/" - || normalized == "/etc" - || normalized.starts_with("/etc/") - || normalized == "/proc" - || normalized.starts_with("/proc/") -} - -impl From for KernelError { - fn from(error: FdTableError) -> Self { - map_error(error.code(), error.to_string()) - } -} - -impl From for KernelError { - fn from(error: PipeError) -> Self { - map_error(error.code(), error.to_string()) - } -} - -impl From for KernelError { - fn from(error: PtyError) -> Self { - map_error(error.code(), error.to_string()) - } -} - -impl From for KernelError { - fn from(error: ProcessTableError) -> Self { - map_error(error.code(), error.to_string()) - } -} - -impl From for KernelError { - fn from(error: PermissionError) -> Self { - map_error(error.code(), error.to_string()) - } -} - -impl From for KernelError { - fn from(error: ResourceError) -> Self { - map_error(error.code(), error.to_string()) - } -} - -impl From for KernelError { - fn from(error: SocketTableError) -> Self { - map_error(error.code(), error.to_string()) - } -} - -impl From for KernelError { - fn from(error: RootFilesystemError) -> Self { - map_error("EINVAL", error.to_string()) - } -} - -fn map_dns_resolver_error(error: crate::dns::DnsResolverError) -> KernelError { - let code = match error.kind() { - DnsResolverErrorKind::InvalidInput => "EINVAL", - DnsResolverErrorKind::LookupFailed => "EHOSTUNREACH", - }; - map_error(code, error.to_string()) -} - -fn map_error(code: &'static str, message: String) -> KernelError { - let trimmed = strip_error_prefix(code, &message) - .map(ToOwned::to_owned) - .unwrap_or(message); - KernelError::new(code, trimmed) -} - -fn strip_error_prefix<'a>(code: &str, message: &'a str) -> Option<&'a str> { - let prefix = format!("{code}: "); - message.strip_prefix(&prefix) -} - -fn parse_dev_fd_path(path: &str) -> KernelResult> { - let Some(raw_fd) = path.strip_prefix("/dev/fd/") else { - return Ok(None); - }; - if raw_fd.is_empty() { - return Err(KernelError::new( - "EBADF", - format!("bad file descriptor: {path}"), - )); - } - let fd = raw_fd - .parse::() - .map_err(|_| KernelError::new("EBADF", format!("bad file descriptor: {path}")))?; - Ok(Some(fd)) -} - -fn count_missing_directory_components( - filesystem: &mut F, - path: &str, - include_final: bool, -) -> VfsResult { - let normalized = normalize_path(path); - let parts = normalized - .split('/') - .filter(|part| !part.is_empty()) - .collect::>(); - let limit = if include_final { - parts.len() - } else { - parts.len().saturating_sub(1) - }; - - let mut current = String::from("/"); - for (index, part) in parts.iter().take(limit).enumerate() { - let candidate = if current == "/" { - format!("/{}", part) - } else { - format!("{current}/{}", part) - }; - - match filesystem.stat(&candidate) { - Ok(stat) => { - if !stat.is_directory { - return Err(VfsError::new( - "ENOTDIR", - format!("not a directory, mkdir '{candidate}'"), - )); - } - current = candidate; - } - Err(error) if error.code() == "ENOENT" => { - return Ok(limit.saturating_sub(index)); - } - Err(error) => return Err(error), - } - } - - Ok(0) -} - -fn parent_path(path: &str) -> String { - let normalized = normalize_path(path); - let Some((head, _)) = normalized.rsplit_once('/') else { - return String::from("/"); - }; - - if head.is_empty() { - String::from("/") - } else { - String::from(head) - } -} - -fn join_absolute_path(parent: &str, child: &str) -> String { - if parent == "/" { - format!("/{child}") - } else { - format!("{parent}/{child}") - } -} - -fn join_child_path(parent: &str, child: &str) -> String { - normalize_path(&join_absolute_path(parent, child)) -} - -fn is_virtual_device_storage_path(path: &str) -> bool { - matches!( - path, - "/dev/null" | "/dev/zero" | "/dev/stdin" | "/dev/stdout" | "/dev/stderr" | "/dev/urandom" - ) || path == "/dev" - || path == "/dev/fd" - || path == "/dev/pts" - || path.starts_with("/dev/fd/") - || path.starts_with("/dev/pts/") -} - -fn is_storage_directory(stat: Option<&VirtualStat>) -> bool { - stat.is_some_and(|stat| stat.is_directory && !stat.is_symbolic_link) -} - -fn is_proc_path(path: &str) -> bool { - let normalized = normalize_path(path); - normalized == "/proc" || normalized.starts_with("/proc/") -} - -fn is_agentos_path(path: &str) -> bool { - let normalized = normalize_path(path); - normalized == "/etc/agentos" || normalized.starts_with("/etc/agentos/") -} - -fn open_requires_write_access(flags: u32) -> bool { - flags & (O_CREAT | O_EXCL | O_TRUNC) != 0 || (flags & 0b11) != crate::fd_table::O_RDONLY -} - -fn checked_write_end(offset: u64, len: usize) -> KernelResult { - offset - .checked_add(len as u64) - .ok_or_else(|| KernelError::new("EINVAL", "write offset out of range")) -} - -fn filetype_for_path(path: &str, stat: &VirtualStat) -> u8 { - if stat.is_directory { - FILETYPE_DIRECTORY - } else if path.starts_with("/dev/") { - FILETYPE_CHARACTER_DEVICE - } else if stat.is_symbolic_link { - FILETYPE_SYMBOLIC_LINK - } else { - FILETYPE_REGULAR_FILE - } -} - -fn synthetic_character_device_stat(ino: u64) -> VirtualStat { - let now = now_ms(); - VirtualStat { - mode: 0o666, - size: 0, - blocks: 0, - dev: 2, - rdev: 0, - is_directory: false, - is_symbolic_link: false, - atime_ms: now, - atime_nsec: 0, - mtime_ms: now, - mtime_nsec: 0, - ctime_ms: now, - ctime_nsec: 0, - birthtime_ms: now, - ino, - nlink: 1, - uid: 0, - gid: 0, - } -} - -fn proc_dir_stat(ino: u64) -> VirtualStat { - let now = now_ms(); - VirtualStat { - mode: 0o555, - size: 0, - blocks: 0, - dev: 3, - rdev: 0, - is_directory: true, - is_symbolic_link: false, - atime_ms: now, - atime_nsec: 0, - mtime_ms: now, - mtime_nsec: 0, - ctime_ms: now, - ctime_nsec: 0, - birthtime_ms: now, - ino, - nlink: 2, - uid: 0, - gid: 0, - } -} - -fn proc_file_stat(ino: u64, size: u64) -> VirtualStat { - let now = now_ms(); - VirtualStat { - mode: 0o444, - size, - blocks: if size == 0 { 0 } else { size.div_ceil(512) }, - dev: 3, - rdev: 0, - is_directory: false, - is_symbolic_link: false, - atime_ms: now, - atime_nsec: 0, - mtime_ms: now, - mtime_nsec: 0, - ctime_ms: now, - ctime_nsec: 0, - birthtime_ms: now, - ino, - nlink: 1, - uid: 0, - gid: 0, - } -} - -fn proc_symlink_stat(ino: u64, size: u64) -> VirtualStat { - let now = now_ms(); - VirtualStat { - mode: 0o777, - size, - blocks: if size == 0 { 0 } else { size.div_ceil(512) }, - dev: 3, - rdev: 0, - is_directory: false, - is_symbolic_link: true, - atime_ms: now, - atime_nsec: 0, - mtime_ms: now, - mtime_nsec: 0, - ctime_ms: now, - ctime_nsec: 0, - birthtime_ms: now, - ino, - nlink: 1, - uid: 0, - gid: 0, - } -} - -fn proc_filetype(node: &ProcNode) -> u8 { - match node { - ProcNode::RootDir | ProcNode::PidDir { .. } | ProcNode::PidFdDir { .. } => { - FILETYPE_DIRECTORY - } - ProcNode::SelfLink { .. } | ProcNode::PidCwdLink { .. } | ProcNode::PidFdLink { .. } => { - FILETYPE_SYMBOLIC_LINK - } - ProcNode::MountsFile - | ProcNode::CpuInfoFile - | ProcNode::MemInfoFile - | ProcNode::LoadAvgFile - | ProcNode::UptimeFile - | ProcNode::VersionFile - | ProcNode::PidCmdline { .. } - | ProcNode::PidEnviron { .. } - | ProcNode::PidStatFile { .. } - | ProcNode::PidStatusFile { .. } => FILETYPE_REGULAR_FILE, - } -} - -fn proc_inode(node: &ProcNode) -> u64 { - match node { - ProcNode::RootDir => 0xfffe_0001, - ProcNode::MountsFile => 0xfffe_0002, - ProcNode::CpuInfoFile => 0xfffe_0003, - ProcNode::MemInfoFile => 0xfffe_0004, - ProcNode::LoadAvgFile => 0xfffe_0005, - ProcNode::UptimeFile => 0xfffe_0006, - ProcNode::VersionFile => 0xfffe_0007, - ProcNode::SelfLink { pid } => 0xfffe_1000 + u64::from(*pid), - ProcNode::PidDir { pid } => 0xfffe_2000 + u64::from(*pid), - ProcNode::PidFdDir { pid } => 0xfffe_3000 + u64::from(*pid), - ProcNode::PidCmdline { pid } => 0xfffe_4000 + u64::from(*pid), - ProcNode::PidEnviron { pid } => 0xfffe_5000 + u64::from(*pid), - ProcNode::PidCwdLink { pid } => 0xfffe_6000 + u64::from(*pid), - ProcNode::PidStatFile { pid } => 0xfffe_7000 + u64::from(*pid), - ProcNode::PidStatusFile { pid } => 0xfffe_8000 + u64::from(*pid), - ProcNode::PidFdLink { pid, fd } => 0xffff_0000 + ((u64::from(*pid)) << 8) + u64::from(*fd), - } -} - -fn null_separated_bytes(parts: Vec) -> Vec { - if parts.is_empty() { - return Vec::new(); - } - - let mut bytes = parts.join("\0").into_bytes(); - bytes.push(0); - bytes -} - -fn proc_not_found_error(path: &str) -> KernelError { - KernelError::new( - "ENOENT", - format!("no such file or directory, stat '{path}'"), - ) -} - -fn read_only_filesystem_error(path: &str) -> KernelError { - KernelError::new("EROFS", format!("read-only filesystem: {path}")) -} - -fn now_ms() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as u64 -} - -impl Drop for KernelVm { - fn drop(&mut self) { - if !self.terminated { - dispose_kernel_vm_resources(self); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::vfs::MemoryFileSystem; - use std::panic::{catch_unwind, AssertUnwindSafe}; - use std::thread; - - struct RetainedKernelResources { - process: KernelProcessHandle, - fd_tables: Arc>, - pipes: PipeManager, - ptys: PtyManager, - sockets: SocketTable, - driver_pids: Arc>>>, - } - - fn kernel_with_live_resources() -> (KernelVm, RetainedKernelResources) { - let mut config = KernelVmConfig::new("vm-drop-resources"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - let _ = kernel.open_pipe("shell", process.pid()).expect("open pipe"); - let _ = kernel.open_pty("shell", process.pid()).expect("open pty"); - let socket = kernel - .socket_create("shell", process.pid(), SocketSpec::tcp()) - .expect("create socket"); - kernel - .socket_set_state("shell", process.pid(), socket, SocketState::Listening) - .expect("mark listener"); - - let retained = RetainedKernelResources { - process: process.clone(), - fd_tables: Arc::clone(&kernel.fd_tables), - pipes: kernel.pipes.clone(), - ptys: kernel.ptys.clone(), - sockets: kernel.sockets.clone(), - driver_pids: Arc::clone(&kernel.driver_pids), - }; - - assert_eq!(lock_or_recover(retained.fd_tables.as_ref()).len(), 1); - assert_eq!(retained.pipes.pipe_count(), 1); - assert_eq!(retained.ptys.pty_count(), 1); - assert_eq!(retained.sockets.snapshot().sockets, 1); - - (kernel, retained) - } - - fn recursive_fs_kernel() -> KernelVm { - let mut config = KernelVmConfig::new("vm-recursive-fs"); - config.permissions = Permissions::allow_all(); - KernelVm::new(MemoryFileSystem::new(), config) - } - - #[test] - fn recursive_copy_preserves_tree_metadata_and_symlinks() { - let mut kernel = recursive_fs_kernel(); - kernel - .mkdir("/src/nested", true) - .expect("create source dirs"); - kernel - .write_file("/src/nested/file.txt", b"hello".to_vec()) - .expect("write source file"); - kernel - .chmod("/src/nested/file.txt", 0o640) - .expect("chmod source file"); - kernel - .chown("/src/nested/file.txt", 42, 43) - .expect("chown source file"); - kernel - .symlink("../nested/file.txt", "/src/link") - .expect("create source symlink"); - - kernel - .copy_path("/src", "/dst", true) - .expect("recursive copy"); - - assert_eq!( - kernel - .read_file("/dst/nested/file.txt") - .expect("read copied"), - b"hello".to_vec() - ); - let copied = kernel.lstat("/dst/nested/file.txt").expect("stat copied"); - assert_eq!(copied.mode & 0o777, 0o640); - assert_eq!((copied.uid, copied.gid), (42, 43)); - let link = kernel.lstat("/dst/link").expect("lstat copied link"); - assert!(link.is_symbolic_link); - assert_eq!( - kernel.read_link("/dst/link").expect("read copied link"), - "../nested/file.txt" - ); - } - - #[test] - fn recursive_remove_deletes_subtree_but_does_not_follow_symlinks() { - let mut kernel = recursive_fs_kernel(); - kernel.mkdir("/tree/dir", true).expect("create tree"); - kernel - .write_file("/tree/dir/file.txt", b"tree".to_vec()) - .expect("write tree file"); - kernel - .write_file("/outside.txt", b"outside".to_vec()) - .expect("write outside file"); - kernel - .symlink("/outside.txt", "/tree/link-out") - .expect("create symlink out of tree"); - - kernel.remove_path("/tree", true).expect("recursive remove"); - - assert!(!kernel.exists("/tree").expect("tree existence")); - assert_eq!( - kernel.read_file("/outside.txt").expect("outside survives"), - b"outside".to_vec() - ); - } - - #[test] - fn read_dir_recursive_respects_user_depth_and_reports_types() { - let mut kernel = recursive_fs_kernel(); - kernel.mkdir("/root/a/b", true).expect("create deep tree"); - kernel - .write_file("/root/a/file.txt", b"x".to_vec()) - .expect("write file"); - kernel - .symlink("a/file.txt", "/root/link") - .expect("create link"); - - let entries = kernel - .read_dir_recursive("/root", Some(0)) - .expect("recursive listing"); - assert_eq!(entries.len(), 2); - assert!(entries - .iter() - .any(|entry| entry.path == "/root/a" && entry.is_directory)); - assert!(entries - .iter() - .any(|entry| entry.path == "/root/link" && entry.is_symbolic_link)); - assert!(!entries.iter().any(|entry| entry.path == "/root/a/file.txt")); - } - - #[test] - fn recursive_ops_enforce_depth_and_entry_bounds() { - let mut depth_config = KernelVmConfig::new("vm-recursive-depth-limit"); - depth_config.permissions = Permissions::allow_all(); - depth_config.resources = ResourceLimits { - max_recursive_fs_depth: Some(1), - ..ResourceLimits::default() - }; - let mut depth_kernel = KernelVm::new(MemoryFileSystem::new(), depth_config); - depth_kernel - .mkdir("/root/a/b", true) - .expect("create deep tree"); - - let error = depth_kernel - .copy_path("/root", "/copy", true) - .expect_err("copy should hit depth limit"); - assert_eq!(error.code(), "ENOMEM"); - assert!(error.to_string().contains("depth 2")); - - let mut entry_config = KernelVmConfig::new("vm-recursive-entry-limit"); - entry_config.permissions = Permissions::allow_all(); - entry_config.resources = ResourceLimits { - max_recursive_fs_entries: Some(2), - ..ResourceLimits::default() - }; - let mut entry_kernel = KernelVm::new(MemoryFileSystem::new(), entry_config); - entry_kernel.mkdir("/root", true).expect("create root"); - entry_kernel - .write_file("/root/a.txt", b"a".to_vec()) - .expect("write a"); - entry_kernel - .write_file("/root/b.txt", b"b".to_vec()) - .expect("write b"); - entry_kernel - .write_file("/root/c.txt", b"c".to_vec()) - .expect("write c"); - - let error = entry_kernel - .read_dir_recursive("/root", None) - .expect_err("listing should hit entry limit"); - assert_eq!(error.code(), "ENOMEM"); - assert!(error.to_string().contains("3 entries")); - } - - fn assert_kernel_drop_released_resources(retained: &RetainedKernelResources) { - assert_eq!(retained.process.wait(Duration::from_millis(50)), Some(143)); - assert_eq!(retained.process.kill_signals(), vec![15]); - assert!( - lock_or_recover(retained.fd_tables.as_ref()).is_empty(), - "kernel drop should remove fd tables" - ); - assert_eq!( - retained.pipes.pipe_count(), - 0, - "kernel drop should close pipes" - ); - assert_eq!( - retained.ptys.pty_count(), - 0, - "kernel drop should close PTYs" - ); - assert_eq!( - retained.sockets.snapshot().sockets, - 0, - "kernel drop should reclaim sockets" - ); - assert!( - lock_or_recover(retained.driver_pids.as_ref()).is_empty(), - "kernel drop should clear driver-owned pid tracking" - ); - } - - #[test] - fn setpgid_rejects_joining_a_process_group_owned_by_another_driver() { - let kernel = KernelVm::new(MemoryFileSystem::new(), KernelVmConfig::new("vm-setpgid")); - - let leader_pid = kernel.processes.allocate_pid().expect("allocate pid"); - kernel.processes.register( - leader_pid, - String::from("driver-a"), - String::from("sh"), - Vec::new(), - ProcessContext { - pid: leader_pid, - ppid: 0, - env: BTreeMap::new(), - cwd: String::from("/"), - umask: DEFAULT_PROCESS_UMASK, - fds: Default::default(), - identity: ProcessIdentity::default(), - blocked_signals: SignalSet::empty(), - pending_signals: SignalSet::empty(), - }, - Arc::new(StubDriverProcess::default()), - ); - - let peer_pid = kernel.processes.allocate_pid().expect("allocate pid"); - kernel.processes.register( - peer_pid, - String::from("driver-b"), - String::from("sh"), - Vec::new(), - ProcessContext { - pid: peer_pid, - ppid: leader_pid, - env: BTreeMap::new(), - cwd: String::from("/"), - umask: DEFAULT_PROCESS_UMASK, - fds: Default::default(), - identity: ProcessIdentity::default(), - blocked_signals: SignalSet::empty(), - pending_signals: SignalSet::empty(), - }, - Arc::new(StubDriverProcess::default()), - ); - - lock_or_recover(&kernel.driver_pids) - .entry(String::from("driver-a")) - .or_default() - .insert(leader_pid); - lock_or_recover(&kernel.driver_pids) - .entry(String::from("driver-b")) - .or_default() - .insert(peer_pid); - - let error = kernel - .setpgid("driver-b", peer_pid, leader_pid) - .expect_err("cross-driver process-group join should be denied"); - assert_eq!(error.code(), "EPERM"); - } - - #[test] - fn sigprocmask_and_sigpending_require_process_ownership() { - let mut kernel = KernelVm::new(MemoryFileSystem::new(), KernelVmConfig::new("vm-sigmask")); - let process = kernel - .register_process( - String::from("driver-a"), - String::from("sleep"), - Vec::new(), - ProcessContext { - pid: 0, - ppid: 0, - env: BTreeMap::new(), - cwd: String::from("/"), - umask: DEFAULT_PROCESS_UMASK, - fds: Default::default(), - identity: ProcessIdentity::default(), - blocked_signals: SignalSet::empty(), - pending_signals: SignalSet::empty(), - }, - None, - ) - .expect("create virtual process"); - let mask = - SignalSet::from_signal(crate::process_table::SIGCHLD).expect("SIGCHLD should be valid"); - - let previous = kernel - .sigprocmask("driver-a", process.pid(), SigmaskHow::Block, mask) - .expect("owner should update signal mask"); - assert_eq!(previous, SignalSet::empty()); - assert_eq!( - kernel - .sigpending("driver-a", process.pid()) - .expect("owner should read pending signals"), - SignalSet::empty() - ); - - let error = kernel - .sigprocmask("driver-b", process.pid(), SigmaskHow::Block, mask) - .expect_err("foreign driver should be rejected"); - assert_eq!(error.code(), "EPERM"); - let error = kernel - .sigpending("driver-b", process.pid()) - .expect_err("foreign driver should be rejected"); - assert_eq!(error.code(), "EPERM"); - } - - #[test] - fn cleanup_process_resources_blocks_concurrent_dup2_until_pipe_cleanup_finishes() { - let fd_tables = Arc::new(Mutex::new(FdTableManager::new())); - let file_locks = FileLockManager::new(); - let pipes = PipeManager::new(); - let ptys = PtyManager::new(); - let sockets = SocketTable::new(); - let driver_pids = Arc::new(Mutex::new(BTreeMap::from([( - String::from("driver"), - BTreeSet::from([41]), - )]))); - let pipe = pipes.create_pipe(); - - { - let mut tables = lock_or_recover(fd_tables.as_ref()); - let table = tables.create(41); - table - .open_with( - Arc::clone(&pipe.read.description), - pipe.read.filetype, - Some(10), - ) - .expect("open pipe read end"); - table - .open_with( - Arc::clone(&pipe.write.description), - pipe.write.filetype, - Some(11), - ) - .expect("open pipe write end"); - } - - let hook_state = Arc::new((Mutex::new((false, false)), Condvar::new())); - let hook_state_for_cleanup = Arc::clone(&hook_state); - set_cleanup_process_resources_test_hook(Some(Arc::new(move || { - let (state, wake) = &*hook_state_for_cleanup; - let mut state = lock_or_recover(state); - state.0 = true; - wake.notify_all(); - while !state.1 { - state = wake.wait(state).expect("wait for cleanup release"); - } - }))); - - let fd_tables_for_cleanup = Arc::clone(&fd_tables); - let pipes_for_cleanup = pipes.clone(); - let driver_pids_for_cleanup = Arc::clone(&driver_pids); - let cleanup_thread = thread::spawn(move || { - cleanup_process_resources( - fd_tables_for_cleanup.as_ref(), - &file_locks, - &pipes_for_cleanup, - &ptys, - &sockets, - driver_pids_for_cleanup.as_ref(), - 41, - ); - }); - - { - let (state, wake) = &*hook_state; - let mut state = lock_or_recover(state); - while !state.0 { - state = wake.wait(state).expect("wait for cleanup hook"); - } - } - - let fd_tables_for_dup = Arc::clone(&fd_tables); - let dup_thread = thread::spawn(move || { - let mut tables = lock_or_recover(fd_tables_for_dup.as_ref()); - let Some(table) = tables.get_mut(41) else { - return Err(String::from("ESRCH")); - }; - table.dup2(10, 12).map_err(|error| error.code().to_string()) - }); - - { - let (state, wake) = &*hook_state; - let mut state = lock_or_recover(state); - state.1 = true; - wake.notify_all(); - } - - cleanup_thread.join().expect("cleanup thread should finish"); - let dup_result = dup_thread.join().expect("dup thread should finish"); - set_cleanup_process_resources_test_hook(None); - - assert_eq!(dup_result, Err(String::from("ESRCH"))); - assert!( - lock_or_recover(fd_tables.as_ref()).get(41).is_none(), - "cleanup should remove the process FD table" - ); - assert_eq!(pipes.pipe_count(), 0, "pipe cleanup should not leak"); - assert!( - lock_or_recover(driver_pids.as_ref()) - .get("driver") - .is_none_or(|pids| pids.is_empty()), - "driver ownership should be cleared" - ); - } - - #[test] - fn drop_disposes_live_kernel_vm_resources() { - let (kernel, retained) = kernel_with_live_resources(); - drop(kernel); - assert_kernel_drop_released_resources(&retained); - } - - #[test] - fn drop_during_panic_still_disposes_live_kernel_vm_resources() { - let retained = Arc::new(Mutex::new(None::)); - let retained_for_panic = Arc::clone(&retained); - - let panic_result = catch_unwind(AssertUnwindSafe(move || { - let (kernel, resources) = kernel_with_live_resources(); - *lock_or_recover(retained_for_panic.as_ref()) = Some(resources); - let _kernel = kernel; - panic!("intentional panic to exercise KernelVm::drop"); - })); - - assert!(panic_result.is_err(), "panic should be observed"); - let retained = lock_or_recover(retained.as_ref()) - .take() - .expect("panic path should retain resources for assertions"); - assert_kernel_drop_released_resources(&retained); - } -} diff --git a/crates/kernel/src/lib.rs b/crates/kernel/src/lib.rs index 63778e094..0fd317339 100644 --- a/crates/kernel/src/lib.rs +++ b/crates/kernel/src/lib.rs @@ -1,52 +1,3 @@ -#![forbid(unsafe_code)] +//! Compatibility shim for `agentos-kernel`. -//! Shared per-VM kernel plane for the secure-exec runtime migration. - -pub use secure_exec_bridge as bridge; -pub mod command_registry; -pub mod device_layer; -pub mod dns; -pub mod fd_table; -pub mod kernel; -pub mod network_policy; -pub mod permissions; -pub mod pipe_manager; -pub mod poll; -pub mod process_table; -pub mod pty; -pub mod resource_accounting; -pub mod socket_table; -pub mod user; - -pub use ::vfs::posix as vfs; - -pub mod mount_plugin { - pub use ::vfs::posix::mount_plugin::*; -} - -pub mod mount_table { - pub use ::vfs::posix::mount_table::*; -} - -pub mod overlay_fs { - pub use ::vfs::posix::overlay_fs::*; -} - -pub mod root_fs { - pub use ::vfs::posix::root_fs::*; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct KernelScaffold { - pub package_name: &'static str, - pub supports_native_sidecar: bool, - pub supports_browser_sidecar: bool, -} - -pub fn scaffold() -> KernelScaffold { - KernelScaffold { - package_name: env!("CARGO_PKG_NAME"), - supports_native_sidecar: true, - supports_browser_sidecar: true, - } -} +pub use agentos_kernel::*; diff --git a/crates/kernel/src/network_policy.rs b/crates/kernel/src/network_policy.rs deleted file mode 100644 index acdeb0043..000000000 --- a/crates/kernel/src/network_policy.rs +++ /dev/null @@ -1,188 +0,0 @@ -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - -pub fn is_loopback_ip(ip: IpAddr) -> bool { - match ip { - IpAddr::V4(ip) => ip.is_loopback(), - IpAddr::V6(ip) => { - ip.is_loopback() - || ip - .to_ipv4_mapped() - .is_some_and(|mapped| mapped.is_loopback()) - } - } -} - -pub fn loopback_cidr(ip: IpAddr) -> &'static str { - match ip { - IpAddr::V4(ip) if ip.is_loopback() => "127.0.0.0/8", - IpAddr::V6(ip) - if ip - .to_ipv4_mapped() - .is_some_and(|mapped| mapped.is_loopback()) => - { - "127.0.0.0/8" - } - IpAddr::V6(_) => "::1/128", - IpAddr::V4(_) => "127.0.0.0/8", - } -} - -pub fn format_tcp_resource(host: &str, port: u16) -> String { - format!("tcp://{host}:{port}") -} - -pub fn restricted_non_loopback_ip_range(ip: IpAddr) -> Option<(&'static str, &'static str)> { - match ip { - IpAddr::V4(ip) => { - if ip.is_unspecified() { - return Some(("0.0.0.0/32", "unspecified")); - } - let [first, second, ..] = ip.octets(); - match (first, second) { - (10, _) => Some(("10.0.0.0/8", "private")), - (100, 64..=127) => Some(("100.64.0.0/10", "carrier-grade-nat")), - (172, 16..=31) => Some(("172.16.0.0/12", "private")), - (192, 168) => Some(("192.168.0.0/16", "private")), - (169, 254) => Some(("169.254.0.0/16", "link-local")), - (224..=239, _) => Some(("224.0.0.0/4", "multicast")), - (240..=255, _) => Some(("240.0.0.0/4", "reserved")), - _ => None, - } - } - IpAddr::V6(ip) => { - if let Some(mapped) = ip.to_ipv4_mapped() { - return restricted_non_loopback_ip_range(IpAddr::V4(mapped)); - } - if let Some(compat) = ipv4_compatible_embedded(ip) { - return restricted_non_loopback_ip_range(IpAddr::V4(compat)); - } - if ip.is_unspecified() { - return Some(("::/128", "unspecified")); - } - - let segments = ip.segments(); - if (segments[0] & 0xfe00) == 0xfc00 { - return Some(("fc00::/7", "unique-local")); - } - if (segments[0] & 0xffc0) == 0xfe80 { - return Some(("fe80::/10", "link-local")); - } - None - } - } -} - -fn ipv4_compatible_embedded(ip: Ipv6Addr) -> Option { - let segments = ip.segments(); - if segments[0..6].iter().any(|&s| s != 0) { - return None; - } - let embedded = (u32::from(segments[6]) << 16) | u32::from(segments[7]); - if embedded == 0 || embedded == 1 { - return None; - } - Some(Ipv4Addr::from(embedded)) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn assert_restricted(ip: IpAddr, expected_label: &str) { - let classification = restricted_non_loopback_ip_range(ip); - assert!( - classification.is_some(), - "{ip} must be classified as a restricted egress target" - ); - let (_cidr, label) = classification.unwrap(); - assert_eq!( - label, expected_label, - "{ip} should be labelled {expected_label}, got {label}" - ); - } - - #[test] - fn classifier_denies_unspecified_and_cgnat_targets() { - assert_restricted(IpAddr::V4(Ipv4Addr::UNSPECIFIED), "unspecified"); - assert_restricted(IpAddr::V6(Ipv6Addr::UNSPECIFIED), "unspecified"); - assert_restricted( - IpAddr::V4(Ipv4Addr::new(100, 64, 0, 1)), - "carrier-grade-nat", - ); - assert_restricted( - IpAddr::V4(Ipv4Addr::new(100, 127, 255, 254)), - "carrier-grade-nat", - ); - assert!( - restricted_non_loopback_ip_range(IpAddr::V4(Ipv4Addr::new(100, 63, 255, 255,))) - .is_none() - ); - assert!( - restricted_non_loopback_ip_range(IpAddr::V4(Ipv4Addr::new(100, 128, 0, 0))).is_none() - ); - } - - #[test] - fn classifier_denies_ipv6_spelled_metadata_addresses() { - assert_restricted( - IpAddr::V6("::ffff:169.254.169.254".parse::().unwrap()), - "link-local", - ); - assert_restricted( - IpAddr::V6("::169.254.169.254".parse::().unwrap()), - "link-local", - ); - assert_restricted( - IpAddr::V6("::10.0.0.1".parse::().unwrap()), - "private", - ); - assert_restricted( - IpAddr::V6("::100.64.0.1".parse::().unwrap()), - "carrier-grade-nat", - ); - assert_eq!( - restricted_non_loopback_ip_range(IpAddr::V6(Ipv6Addr::UNSPECIFIED)), - Some(("::/128", "unspecified")) - ); - assert!( - restricted_non_loopback_ip_range(IpAddr::V6(Ipv6Addr::LOCALHOST)).is_none() - || is_loopback_ip(IpAddr::V6(Ipv6Addr::LOCALHOST)) - ); - assert!(restricted_non_loopback_ip_range(IpAddr::V6( - "::8.8.8.8".parse::().unwrap() - )) - .is_none()); - } - - #[test] - fn classifier_denies_reserved_and_multicast_targets() { - assert_restricted(IpAddr::V4(Ipv4Addr::new(224, 0, 0, 1)), "multicast"); - assert_restricted(IpAddr::V4(Ipv4Addr::new(239, 255, 255, 255)), "multicast"); - assert_restricted(IpAddr::V4(Ipv4Addr::new(240, 0, 0, 1)), "reserved"); - assert_restricted(IpAddr::V4(Ipv4Addr::BROADCAST), "reserved"); - assert_restricted( - IpAddr::V6("::224.0.0.1".parse::().unwrap()), - "multicast", - ); - assert_restricted( - IpAddr::V6("::240.0.0.1".parse::().unwrap()), - "reserved", - ); - assert!( - restricted_non_loopback_ip_range(IpAddr::V4(Ipv4Addr::new(223, 255, 255, 255))) - .is_none() - ); - } - - #[test] - fn tcp_resource_format_matches_permission_resources() { - assert_eq!( - format_tcp_resource("127.0.0.1", 8080), - "tcp://127.0.0.1:8080" - ); - assert_eq!( - format_tcp_resource("example.test", 443), - "tcp://example.test:443" - ); - } -} diff --git a/crates/kernel/src/permissions.rs b/crates/kernel/src/permissions.rs deleted file mode 100644 index 9dd2a389a..000000000 --- a/crates/kernel/src/permissions.rs +++ /dev/null @@ -1,662 +0,0 @@ -use crate::vfs::{ - validate_path, VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, - VirtualUtimeSpec, -}; -use std::collections::{BTreeMap, HashMap}; -use std::error::Error; -use std::fmt; -use std::path::Path; -use std::sync::Arc; - -pub type FsPermissionCheck = Arc PermissionDecision + Send + Sync>; -pub type NetworkPermissionCheck = - Arc PermissionDecision + Send + Sync>; -pub type CommandPermissionCheck = - Arc PermissionDecision + Send + Sync>; -pub type EnvironmentPermissionCheck = - Arc PermissionDecision + Send + Sync>; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PermissionDecision { - pub allow: bool, - pub reason: Option, -} - -impl PermissionDecision { - pub fn allow() -> Self { - Self { - allow: true, - reason: None, - } - } - - pub fn deny(reason: impl Into) -> Self { - Self { - allow: false, - reason: Some(reason.into()), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PermissionError { - code: &'static str, - message: String, -} - -impl PermissionError { - pub fn code(&self) -> &'static str { - self.code - } - - fn access_denied(subject: impl Into, reason: Option<&str>) -> Self { - let subject = subject.into(); - let message = match reason { - Some(reason) => format!("permission denied, {subject}: {reason}"), - None => format!("permission denied, {subject}"), - }; - - Self { - code: "EACCES", - message, - } - } -} - -impl fmt::Display for PermissionError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for PermissionError {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FsOperation { - Read, - Write, - Mkdir, - CreateDir, - ReadDir, - Stat, - Remove, - Rename, - Exists, - Symlink, - ReadLink, - Link, - Chmod, - Chown, - Utimes, - Truncate, - MountSensitive, -} - -impl FsOperation { - fn as_str(self) -> &'static str { - match self { - Self::Read => "read", - Self::Write => "write", - Self::Mkdir => "mkdir", - Self::CreateDir => "createDir", - Self::ReadDir => "readdir", - Self::Stat => "stat", - Self::Remove => "rm", - Self::Rename => "rename", - Self::Exists => "exists", - Self::Symlink => "symlink", - Self::ReadLink => "readlink", - Self::Link => "link", - Self::Chmod => "chmod", - Self::Chown => "chown", - Self::Utimes => "utimes", - Self::Truncate => "truncate", - Self::MountSensitive => "mount", - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FsAccessRequest { - pub vm_id: String, - pub op: FsOperation, - pub path: String, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum NetworkOperation { - Fetch, - Http, - Dns, - Listen, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct NetworkAccessRequest { - pub vm_id: String, - pub op: NetworkOperation, - pub resource: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CommandAccessRequest { - pub vm_id: String, - pub command: String, - pub args: Vec, - pub cwd: Option, - pub env: BTreeMap, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum EnvironmentOperation { - Read, - Write, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnvAccessRequest { - pub vm_id: String, - pub op: EnvironmentOperation, - pub key: String, - pub value: Option, -} - -#[derive(Clone, Default)] -pub struct Permissions { - pub filesystem: Option, - pub network: Option, - pub child_process: Option, - pub environment: Option, -} - -impl Permissions { - pub fn allow_all() -> Self { - Self { - filesystem: Some(Arc::new(|_: &FsAccessRequest| PermissionDecision::allow())), - network: Some(Arc::new(|_: &NetworkAccessRequest| { - PermissionDecision::allow() - })), - child_process: Some(Arc::new(|_: &CommandAccessRequest| { - PermissionDecision::allow() - })), - environment: Some(Arc::new(|_: &EnvAccessRequest| PermissionDecision::allow())), - } - } -} - -pub fn permission_glob_matches(pattern: &str, value: &str) -> bool { - fn matches( - pattern: &[u8], - value: &[u8], - pattern_index: usize, - value_index: usize, - memo: &mut HashMap<(usize, usize), bool>, - ) -> bool { - if let Some(result) = memo.get(&(pattern_index, value_index)) { - return *result; - } - - let result = if pattern_index == pattern.len() { - value_index == value.len() - } else { - match pattern[pattern_index] { - b'?' => { - value_index < value.len() - && value[value_index] != b'/' - && matches(pattern, value, pattern_index + 1, value_index + 1, memo) - } - b'*' => { - let mut next_pattern_index = pattern_index; - while next_pattern_index < pattern.len() && pattern[next_pattern_index] == b'*' - { - next_pattern_index += 1; - } - - if matches(pattern, value, next_pattern_index, value_index, memo) { - true - } else { - let crosses_separators = next_pattern_index - pattern_index > 1; - let mut next_value_index = value_index; - while next_value_index < value.len() - && (crosses_separators || value[next_value_index] != b'/') - { - next_value_index += 1; - if matches(pattern, value, next_pattern_index, next_value_index, memo) { - return true; - } - } - false - } - } - expected => { - value_index < value.len() - && expected == value[value_index] - && matches(pattern, value, pattern_index + 1, value_index + 1, memo) - } - } - }; - - memo.insert((pattern_index, value_index), result); - result - } - - matches( - pattern.as_bytes(), - value.as_bytes(), - 0, - 0, - &mut HashMap::new(), - ) -} - -pub fn filter_env( - vm_id: &str, - env: &BTreeMap, - permissions: &Permissions, -) -> BTreeMap { - let Some(check) = permissions.environment.as_ref() else { - return BTreeMap::new(); - }; - - env.iter() - .filter_map(|(key, value)| { - let request = EnvAccessRequest { - vm_id: vm_id.to_owned(), - op: EnvironmentOperation::Read, - key: key.clone(), - value: Some(value.clone()), - }; - let decision = check(&request); - decision.allow.then(|| (key.clone(), value.clone())) - }) - .collect() -} - -pub fn check_command_execution( - vm_id: &str, - permissions: &Permissions, - command: &str, - args: &[String], - cwd: Option<&str>, - env: &BTreeMap, -) -> Result<(), PermissionError> { - let Some(check) = permissions.child_process.as_ref() else { - return Err(PermissionError::access_denied( - format!("spawn '{command}'"), - None, - )); - }; - - let request = CommandAccessRequest { - vm_id: vm_id.to_owned(), - command: command.to_owned(), - args: args.to_vec(), - cwd: cwd.map(ToOwned::to_owned), - env: env.clone(), - }; - let decision = check(&request); - if decision.allow { - Ok(()) - } else { - Err(PermissionError::access_denied( - format!("spawn '{command}'"), - decision.reason.as_deref(), - )) - } -} - -pub fn check_network_access( - vm_id: &str, - permissions: &Permissions, - op: NetworkOperation, - resource: &str, -) -> Result<(), PermissionError> { - let Some(check) = permissions.network.as_ref() else { - return Err(PermissionError::access_denied(resource, None)); - }; - - let request = NetworkAccessRequest { - vm_id: vm_id.to_owned(), - op, - resource: resource.to_owned(), - }; - let decision = check(&request); - if decision.allow { - Ok(()) - } else { - Err(PermissionError::access_denied( - resource, - decision.reason.as_deref(), - )) - } -} - -#[derive(Clone)] -pub struct PermissionedFileSystem { - inner: F, - vm_id: String, - permissions: Permissions, -} - -impl PermissionedFileSystem { - pub fn new(inner: F, vm_id: impl Into, permissions: Permissions) -> Self { - Self { - inner, - vm_id: vm_id.into(), - permissions, - } - } - - pub fn into_inner(self) -> F { - self.inner - } - - pub fn inner(&self) -> &F { - &self.inner - } - - pub fn inner_mut(&mut self) -> &mut F { - &mut self.inner - } - - pub fn set_permissions(&mut self, permissions: Permissions) { - self.permissions = permissions; - } - - fn check(&self, op: FsOperation, path: &str) -> VfsResult<()> { - validate_path(path)?; - // Standard emulated character devices (/dev/null, /dev/zero, /dev/urandom, - // /dev/std{in,out,err}) are world-accessible on Linux and have no host - // backing; the device layer enforces their fixed semantics. Exempt them from - // the VM file-permission policy so guest fs ops on them (readFileSync / - // existsSync / redirects) behave like native Linux regardless of policy. - if crate::device_layer::is_standard_device_path(path) { - return Ok(()); - } - let Some(check) = self.permissions.filesystem.as_ref() else { - return Err(VfsError::access_denied(op.as_str(), path, None)); - }; - - let request = FsAccessRequest { - vm_id: self.vm_id.clone(), - op, - path: path.to_owned(), - }; - let decision = check(&request); - if decision.allow { - Ok(()) - } else { - Err(VfsError::access_denied( - op.as_str(), - path, - decision.reason.as_deref(), - )) - } - } -} - -impl PermissionedFileSystem { - fn resolved_existing_path(&self, path: &str) -> VfsResult { - self.inner.realpath(path) - } - - fn resolved_destination_path(&self, path: &str) -> VfsResult { - let normalized = crate::vfs::normalize_path(path); - if normalized == "/" { - return Ok(normalized); - } - - let parent = Path::new(&normalized) - .parent() - .unwrap_or_else(|| Path::new("/")) - .to_string_lossy() - .into_owned(); - let basename = Path::new(&normalized) - .file_name() - .map(|value| value.to_string_lossy().into_owned()) - .unwrap_or_default(); - - let mut candidate = parent; - let mut unresolved_segments = Vec::new(); - - let resolved_parent = loop { - match self.inner.realpath(&candidate) { - Ok(resolved) => break resolved, - Err(error) if matches!(error.code(), "ENOENT" | "ENOTDIR") => { - if candidate == "/" { - break String::from("/"); - } - let candidate_path = Path::new(&candidate); - if let Some(segment) = candidate_path.file_name() { - unresolved_segments.push(segment.to_string_lossy().into_owned()); - } - candidate = candidate_path - .parent() - .unwrap_or_else(|| Path::new("/")) - .to_string_lossy() - .into_owned(); - } - Err(error) => return Err(error), - } - }; - - let mut resolved = resolved_parent; - for segment in unresolved_segments.iter().rev() { - if resolved == "/" { - resolved = format!("/{segment}"); - } else { - resolved = format!("{resolved}/{segment}"); - } - } - - if resolved == "/" { - Ok(format!("/{basename}")) - } else { - Ok(format!("{resolved}/{basename}")) - } - } - - fn permission_subject(&self, op: FsOperation, path: &str) -> VfsResult { - validate_path(path)?; - match op { - FsOperation::Read - | FsOperation::ReadDir - | FsOperation::Stat - | FsOperation::ReadLink - | FsOperation::Chmod - | FsOperation::Chown - | FsOperation::Utimes - | FsOperation::Truncate => self.resolved_existing_path(path), - FsOperation::Exists | FsOperation::Write => self - .resolved_existing_path(path) - .or_else(|_| self.resolved_destination_path(path)), - FsOperation::Mkdir - | FsOperation::CreateDir - | FsOperation::Rename - | FsOperation::Symlink - | FsOperation::Link - | FsOperation::MountSensitive - | FsOperation::Remove => self.resolved_destination_path(path), - } - } - - fn check_subject(&self, op: FsOperation, path: &str) -> VfsResult<()> { - let subject = self.permission_subject(op, path)?; - self.check(op, &subject) - } - - fn check_existing_subject(&self, op: FsOperation, path: &str) -> VfsResult<()> { - validate_path(path)?; - let subject = self.resolved_existing_path(path)?; - self.check(op, &subject) - } - - fn check_destination_subject(&self, op: FsOperation, path: &str) -> VfsResult<()> { - validate_path(path)?; - let subject = self.resolved_destination_path(path)?; - self.check(op, &subject) - } - - pub fn check_path(&self, op: FsOperation, path: &str) -> VfsResult<()> { - self.check_subject(op, path) - } - - pub fn check_virtual_path(&self, op: FsOperation, path: &str) -> VfsResult<()> { - self.check(op, path) - } - - pub fn exists(&self, path: &str) -> VfsResult { - if let Err(error) = self.check_subject(FsOperation::Exists, path) { - if matches!(error.code(), "EACCES" | "ENOENT" | "ENOTDIR" | "ELOOP") { - return Ok(false); - } - return Err(error); - } - Ok(self.inner.exists(path)) - } -} - -impl VirtualFileSystem for PermissionedFileSystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - self.check_subject(FsOperation::Read, path)?; - self.inner.read_file(path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - self.check_subject(FsOperation::ReadDir, path)?; - self.inner.read_dir(path) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - self.check_subject(FsOperation::ReadDir, path)?; - self.inner.read_dir_limited(path, max_entries) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - self.check_subject(FsOperation::ReadDir, path)?; - self.inner.read_dir_with_types(path) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - self.check_subject(FsOperation::Write, path)?; - self.inner.write_file(path, content) - } - - fn create_file_exclusive(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - self.check_subject(FsOperation::Write, path)?; - self.inner.create_file_exclusive(path, content) - } - - fn append_file(&mut self, path: &str, content: impl Into>) -> VfsResult { - self.check_subject(FsOperation::Write, path)?; - self.inner.append_file(path, content) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - self.check_subject(FsOperation::CreateDir, path)?; - self.inner.create_dir(path) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - self.check_subject(FsOperation::Mkdir, path)?; - self.inner.mkdir(path, recursive) - } - - fn exists(&self, path: &str) -> bool { - PermissionedFileSystem::exists(self, path).unwrap_or(false) - } - - fn stat(&mut self, path: &str) -> VfsResult { - self.check_subject(FsOperation::Stat, path)?; - self.inner.stat(path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - self.check_subject(FsOperation::Remove, path)?; - self.inner.remove_file(path) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - self.check_subject(FsOperation::Remove, path)?; - self.inner.remove_dir(path) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.check_subject(FsOperation::Rename, old_path)?; - self.check_subject(FsOperation::Rename, new_path)?; - self.inner.rename(old_path, new_path) - } - - fn realpath(&self, path: &str) -> VfsResult { - self.check_subject(FsOperation::Read, path)?; - self.inner.realpath(path) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - self.check_subject(FsOperation::Symlink, link_path)?; - self.inner.symlink(target, link_path) - } - - fn read_link(&self, path: &str) -> VfsResult { - // Authorize the parent-symlink-resolved path (without following the - // final component, matching `lstat`/`readlink` semantics). A lexical - // check would let a symlink whose parent resolves into a denied prefix - // disclose link targets of permission-denied paths. - validate_path(path)?; - let subject = self.resolved_destination_path(path)?; - self.check(FsOperation::ReadLink, &subject)?; - self.inner.read_link(path) - } - - fn lstat(&self, path: &str) -> VfsResult { - // Authorize the parent-symlink-resolved path (see `read_link`); a - // lexical check would leak metadata (size/mode/mtime/inode) of files - // under a permission-denied prefix reached via a symlinked parent. - validate_path(path)?; - let subject = self.resolved_destination_path(path)?; - self.check(FsOperation::Stat, &subject)?; - self.inner.lstat(path) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.check_existing_subject(FsOperation::Link, old_path)?; - self.check_destination_subject(FsOperation::Link, new_path)?; - self.inner.link(old_path, new_path) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - self.check_subject(FsOperation::Chmod, path)?; - self.inner.chmod(path, mode) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - self.check_subject(FsOperation::Chown, path)?; - self.inner.chown(path, uid, gid) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - self.check_subject(FsOperation::Utimes, path)?; - self.inner.utimes(path, atime_ms, mtime_ms) - } - - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - self.check_subject(FsOperation::Utimes, path)?; - self.inner.utimes_spec(path, atime, mtime, follow_symlinks) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - self.check_subject(FsOperation::Truncate, path)?; - self.inner.truncate(path, length) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - self.check_subject(FsOperation::Read, path)?; - self.inner.pread(path, offset, length) - } -} diff --git a/crates/kernel/src/pipe_manager.rs b/crates/kernel/src/pipe_manager.rs deleted file mode 100644 index 3a59b861a..000000000 --- a/crates/kernel/src/pipe_manager.rs +++ /dev/null @@ -1,624 +0,0 @@ -use crate::fd_table::{ - FdResult, FileDescription, ProcessFdTable, SharedFileDescription, FILETYPE_PIPE, O_RDONLY, - O_WRONLY, -}; -use crate::poll::{PollEvents, PollNotifier, POLLERR, POLLHUP, POLLIN, POLLOUT}; -use std::collections::{BTreeMap, VecDeque}; -use std::error::Error; -use std::fmt; -use std::sync::{Arc, Condvar, Mutex, MutexGuard}; -use std::time::Duration; -use web_time::Instant; - -pub const MAX_PIPE_BUFFER_BYTES: usize = 65_536; -pub const PIPE_BUF_BYTES: usize = 4_096; - -pub type PipeResult = Result; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PipeError { - code: &'static str, - message: String, -} - -impl PipeError { - pub fn code(&self) -> &'static str { - self.code - } - - fn bad_file_descriptor(message: impl Into) -> Self { - Self { - code: "EBADF", - message: message.into(), - } - } - - fn broken_pipe(message: impl Into) -> Self { - Self { - code: "EPIPE", - message: message.into(), - } - } - - fn would_block(message: impl Into) -> Self { - Self { - code: "EAGAIN", - message: message.into(), - } - } -} - -impl fmt::Display for PipeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for PipeError {} - -#[derive(Debug, Clone)] -pub struct PipeEnd { - pub description: SharedFileDescription, - pub filetype: u8, -} - -#[derive(Debug, Clone)] -pub struct PipePair { - pub read: PipeEnd, - pub write: PipeEnd, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct PipeRef { - pipe_id: u64, - end: PipeSide, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum PipeSide { - Read, - Write, -} - -#[derive(Debug, Default)] -struct PendingRead { - length: usize, - result: Option>>, -} - -#[derive(Debug, Default)] -struct PipeState { - buffer: VecDeque>, - closed_read: bool, - closed_write: bool, - waiting_reads: VecDeque, -} - -#[derive(Debug)] -struct PipeManagerState { - pipes: BTreeMap, - desc_to_pipe: BTreeMap, - waiters: BTreeMap, - next_pipe_id: u64, - next_desc_id: u64, - next_waiter_id: u64, -} - -impl Default for PipeManagerState { - fn default() -> Self { - Self { - pipes: BTreeMap::new(), - desc_to_pipe: BTreeMap::new(), - waiters: BTreeMap::new(), - next_pipe_id: 1, - next_desc_id: 100_000, - next_waiter_id: 1, - } - } -} - -#[derive(Debug)] -struct PipeManagerInner { - state: Mutex, - waiters: Condvar, -} - -#[derive(Debug, Clone)] -pub struct PipeManager { - inner: Arc, - notifier: Option, -} - -impl Default for PipeManager { - fn default() -> Self { - Self { - inner: Arc::new(PipeManagerInner { - state: Mutex::new(PipeManagerState::default()), - waiters: Condvar::new(), - }), - notifier: None, - } - } -} - -impl PipeManager { - pub fn new() -> Self { - Self::default() - } - - pub(crate) fn with_notifier(notifier: PollNotifier) -> Self { - Self { - notifier: Some(notifier), - ..Self::default() - } - } - - pub fn create_pipe(&self) -> PipePair { - let mut state = lock_or_recover(&self.inner.state); - let pipe_id = state.next_pipe_id; - state.next_pipe_id += 1; - - let read_id = state.next_desc_id; - state.next_desc_id += 1; - let write_id = state.next_desc_id; - state.next_desc_id += 1; - - state.pipes.insert(pipe_id, PipeState::default()); - state.desc_to_pipe.insert( - read_id, - PipeRef { - pipe_id, - end: PipeSide::Read, - }, - ); - state.desc_to_pipe.insert( - write_id, - PipeRef { - pipe_id, - end: PipeSide::Write, - }, - ); - drop(state); - - PipePair { - read: PipeEnd { - description: Arc::new(FileDescription::with_ref_count( - read_id, - format!("pipe:{pipe_id}:read"), - O_RDONLY, - 0, - )), - filetype: FILETYPE_PIPE, - }, - write: PipeEnd { - description: Arc::new(FileDescription::with_ref_count( - write_id, - format!("pipe:{pipe_id}:write"), - O_WRONLY, - 0, - )), - filetype: FILETYPE_PIPE, - }, - } - } - - pub fn poll(&self, description_id: u64, requested: PollEvents) -> PipeResult { - let state = lock_or_recover(&self.inner.state); - let pipe_ref = state - .desc_to_pipe - .get(&description_id) - .copied() - .ok_or_else(|| PipeError::bad_file_descriptor("not a pipe end"))?; - let pipe = state - .pipes - .get(&pipe_ref.pipe_id) - .ok_or_else(|| PipeError::bad_file_descriptor("pipe not found"))?; - - let mut events = PollEvents::empty(); - match pipe_ref.end { - PipeSide::Read => { - if requested.intersects(POLLIN) && !pipe.buffer.is_empty() { - events |= POLLIN; - } - if pipe.closed_write { - events |= POLLHUP; - } - } - PipeSide::Write => { - if pipe.closed_read { - events |= POLLERR; - } else if requested.intersects(POLLOUT) - && (available_capacity(pipe) > 0 || !pipe.waiting_reads.is_empty()) - { - events |= POLLOUT; - } - } - } - - Ok(events) - } - - pub fn write(&self, description_id: u64, data: impl AsRef<[u8]>) -> PipeResult { - self.write_with_mode(description_id, data, true) - } - - pub fn write_blocking(&self, description_id: u64, data: impl AsRef<[u8]>) -> PipeResult { - self.write_with_mode(description_id, data, false) - } - - pub fn write_with_mode( - &self, - description_id: u64, - data: impl AsRef<[u8]>, - nonblocking: bool, - ) -> PipeResult { - let payload = data.as_ref(); - let mut state = lock_or_recover(&self.inner.state); - let pipe_ref = state - .desc_to_pipe - .get(&description_id) - .copied() - .ok_or_else(|| PipeError::bad_file_descriptor("not a pipe write end"))?; - if pipe_ref.end != PipeSide::Write { - return Err(PipeError::bad_file_descriptor("not a pipe write end")); - } - - loop { - let waiter_id = { - let pipe = state - .pipes - .get_mut(&pipe_ref.pipe_id) - .ok_or_else(|| PipeError::bad_file_descriptor("pipe not found"))?; - if pipe.closed_write { - return Err(PipeError::broken_pipe("write end closed")); - } - if pipe.closed_read { - return Err(PipeError::broken_pipe("read end closed")); - } - pipe.waiting_reads.pop_front() - }; - - if let Some(waiter_id) = waiter_id { - let waiter_length = match state.waiters.get(&waiter_id) { - Some(waiter) => waiter.length, - None => continue, - }; - let delivered_len = waiter_length.min(payload.len()); - let delivered = payload[..delivered_len].to_vec(); - let remainder = &payload[delivered_len..]; - - if !remainder.is_empty() { - let pipe = state - .pipes - .get_mut(&pipe_ref.pipe_id) - .ok_or_else(|| PipeError::bad_file_descriptor("pipe not found"))?; - pipe.buffer.push_back(remainder.to_vec()); - } - - if let Some(waiter) = state.waiters.get_mut(&waiter_id) { - waiter.result = Some(Some(delivered)); - self.notify_waiters_and_pollers(); - return Ok(payload.len()); - } - continue; - } - - let current_buffer_size = { - let pipe = state - .pipes - .get(&pipe_ref.pipe_id) - .ok_or_else(|| PipeError::bad_file_descriptor("pipe not found"))?; - buffer_size(&pipe.buffer) - }; - let available = MAX_PIPE_BUFFER_BYTES.saturating_sub(current_buffer_size); - - if payload.len() <= PIPE_BUF_BYTES { - if available >= payload.len() { - let pipe = state - .pipes - .get_mut(&pipe_ref.pipe_id) - .ok_or_else(|| PipeError::bad_file_descriptor("pipe not found"))?; - pipe.buffer.push_back(payload.to_vec()); - self.notify_waiters_and_pollers(); - return Ok(payload.len()); - } - } else if available > 0 { - let chunk_len = available.min(payload.len()); - let pipe = state - .pipes - .get_mut(&pipe_ref.pipe_id) - .ok_or_else(|| PipeError::bad_file_descriptor("pipe not found"))?; - pipe.buffer.push_back(payload[..chunk_len].to_vec()); - self.notify_waiters_and_pollers(); - return Ok(chunk_len); - } - - if nonblocking { - return Err(PipeError::would_block("pipe buffer full")); - } - - state = wait_or_recover(&self.inner.waiters, state); - } - } - - pub fn read(&self, description_id: u64, length: usize) -> PipeResult>> { - self.read_with_timeout(description_id, length, None) - } - - pub fn read_with_timeout( - &self, - description_id: u64, - length: usize, - timeout: Option, - ) -> PipeResult>> { - let mut state = lock_or_recover(&self.inner.state); - let pipe_ref = state - .desc_to_pipe - .get(&description_id) - .copied() - .ok_or_else(|| PipeError::bad_file_descriptor("not a pipe read end"))?; - if pipe_ref.end != PipeSide::Read { - return Err(PipeError::bad_file_descriptor("not a pipe read end")); - } - - let mut waiter_id = None; - let deadline = timeout.map(|duration| Instant::now() + duration); - - loop { - if let Some(id) = waiter_id { - if let Some(waiter) = state.waiters.get_mut(&id) { - if let Some(result) = waiter.result.take() { - state.waiters.remove(&id); - return Ok(result); - } - } - } - - { - let pipe = state - .pipes - .get_mut(&pipe_ref.pipe_id) - .ok_or_else(|| PipeError::bad_file_descriptor("pipe not found"))?; - - if !pipe.buffer.is_empty() { - let result = drain_buffer(&mut pipe.buffer, length); - self.notify_waiters_and_pollers(); - return Ok(Some(result)); - } - - if pipe.closed_write { - if let Some(id) = waiter_id { - state.waiters.remove(&id); - } - return Ok(None); - } - } - - let id = if let Some(id) = waiter_id { - id - } else { - let next = state.next_waiter_id; - state.next_waiter_id += 1; - state.waiters.insert( - next, - PendingRead { - length, - result: None, - }, - ); - let Some(pipe) = state.pipes.get_mut(&pipe_ref.pipe_id) else { - state.waiters.remove(&next); - return Err(PipeError::bad_file_descriptor("pipe not found")); - }; - pipe.waiting_reads.push_back(next); - self.notify_waiters_and_pollers(); - waiter_id = Some(next); - next - }; - - let Some(deadline) = deadline else { - state = wait_or_recover(&self.inner.waiters, state); - if !state.waiters.contains_key(&id) { - waiter_id = None; - } - continue; - }; - - let now = Instant::now(); - if now >= deadline { - if let Some(id) = waiter_id.take() { - state.waiters.remove(&id); - if let Some(pipe) = state.pipes.get_mut(&pipe_ref.pipe_id) { - pipe.waiting_reads.retain(|queued| *queued != id); - } - self.notify_waiters_and_pollers(); - } - return Err(PipeError::would_block("pipe read timed out")); - } - - let remaining = deadline.saturating_duration_since(now); - let (next_state, wait_result) = - wait_timeout_or_recover(&self.inner.waiters, state, remaining); - state = next_state; - if !state.waiters.contains_key(&id) { - waiter_id = None; - } - if wait_result.timed_out() { - if let Some(id) = waiter_id.take() { - state.waiters.remove(&id); - if let Some(pipe) = state.pipes.get_mut(&pipe_ref.pipe_id) { - pipe.waiting_reads.retain(|queued| *queued != id); - } - self.notify_waiters_and_pollers(); - } - return Err(PipeError::would_block("pipe read timed out")); - } - } - } - - pub fn close(&self, description_id: u64) { - let mut state = lock_or_recover(&self.inner.state); - let Some(pipe_ref) = state.desc_to_pipe.remove(&description_id) else { - return; - }; - - let (waiter_ids, remove_pipe, should_notify) = - if let Some(pipe) = state.pipes.get_mut(&pipe_ref.pipe_id) { - match pipe_ref.end { - PipeSide::Read => { - pipe.closed_read = true; - (Vec::new(), pipe.closed_read && pipe.closed_write, true) - } - PipeSide::Write => { - pipe.closed_write = true; - let waiter_ids = pipe.waiting_reads.drain(..).collect::>(); - (waiter_ids, pipe.closed_read && pipe.closed_write, true) - } - } - } else { - (Vec::new(), false, false) - }; - - for waiter_id in waiter_ids { - if let Some(waiter) = state.waiters.get_mut(&waiter_id) { - waiter.result = Some(None); - } - } - - if remove_pipe { - state.pipes.remove(&pipe_ref.pipe_id); - } - if should_notify { - self.notify_waiters_and_pollers(); - } - } - - pub fn is_pipe(&self, description_id: u64) -> bool { - lock_or_recover(&self.inner.state) - .desc_to_pipe - .contains_key(&description_id) - } - - pub fn pipe_id_for(&self, description_id: u64) -> Option { - lock_or_recover(&self.inner.state) - .desc_to_pipe - .get(&description_id) - .map(|pipe_ref| pipe_ref.pipe_id) - } - - pub fn pipe_count(&self) -> usize { - lock_or_recover(&self.inner.state).pipes.len() - } - - pub fn buffered_bytes(&self) -> usize { - lock_or_recover(&self.inner.state) - .pipes - .values() - .map(|pipe| buffer_size(&pipe.buffer)) - .sum() - } - - pub fn waiting_reader_count(&self, description_id: u64) -> PipeResult { - let state = lock_or_recover(&self.inner.state); - let pipe_ref = state - .desc_to_pipe - .get(&description_id) - .copied() - .ok_or_else(|| PipeError::bad_file_descriptor("not a pipe end"))?; - let pipe = state - .pipes - .get(&pipe_ref.pipe_id) - .ok_or_else(|| PipeError::bad_file_descriptor("pipe not found"))?; - Ok(pipe.waiting_reads.len()) - } - - pub fn pending_read_waiter_count(&self) -> usize { - lock_or_recover(&self.inner.state).waiters.len() - } - - pub fn create_pipe_fds(&self, fd_table: &mut ProcessFdTable) -> FdResult<(u32, u32)> { - let pipe = self.create_pipe(); - let read_fd = - fd_table.open_with(Arc::clone(&pipe.read.description), FILETYPE_PIPE, None)?; - match fd_table.open_with(Arc::clone(&pipe.write.description), FILETYPE_PIPE, None) { - Ok(write_fd) => Ok((read_fd, write_fd)), - Err(error) => { - fd_table.close(read_fd); - self.close(pipe.read.description.id()); - self.close(pipe.write.description.id()); - Err(error) - } - } - } - - fn notify_waiters_and_pollers(&self) { - self.inner.waiters.notify_all(); - if let Some(notifier) = &self.notifier { - notifier.notify(); - } - } -} - -fn buffer_size(buffer: &VecDeque>) -> usize { - buffer.iter().map(Vec::len).sum() -} - -fn available_capacity(pipe: &PipeState) -> usize { - MAX_PIPE_BUFFER_BYTES.saturating_sub(buffer_size(&pipe.buffer)) -} - -fn drain_buffer(buffer: &mut VecDeque>, length: usize) -> Vec { - let mut chunks = Vec::new(); - let mut remaining = length; - - while remaining > 0 { - let Some(chunk) = buffer.pop_front() else { - break; - }; - if chunk.len() <= remaining { - remaining -= chunk.len(); - chunks.push(chunk); - } else { - let (head, tail) = chunk.split_at(remaining); - chunks.push(head.to_vec()); - buffer.push_front(tail.to_vec()); - remaining = 0; - } - } - - if chunks.len() == 1 { - return chunks.pop().expect("single chunk should exist"); - } - - let total = chunks.iter().map(Vec::len).sum(); - let mut result = Vec::with_capacity(total); - for chunk in chunks { - result.extend_from_slice(&chunk); - } - result -} - -fn lock_or_recover<'a, T>(mutex: &'a Mutex) -> MutexGuard<'a, T> { - match mutex.lock() { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -fn wait_or_recover<'a, T>(condvar: &Condvar, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { - match condvar.wait(guard) { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -fn wait_timeout_or_recover<'a, T>( - condvar: &Condvar, - guard: MutexGuard<'a, T>, - timeout: Duration, -) -> (MutexGuard<'a, T>, std::sync::WaitTimeoutResult) { - match condvar.wait_timeout(guard, timeout) { - Ok(result) => result, - Err(poisoned) => poisoned.into_inner(), - } -} diff --git a/crates/kernel/src/poll.rs b/crates/kernel/src/poll.rs deleted file mode 100644 index 2566e914d..000000000 --- a/crates/kernel/src/poll.rs +++ /dev/null @@ -1,293 +0,0 @@ -use crate::socket_table::SocketId; -use std::ops::{BitOr, BitOrAssign}; -use std::sync::{Arc, Condvar, Mutex, MutexGuard}; -use std::time::Duration; -use web_time::Instant; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct PollEvents(u16); - -impl PollEvents { - pub const fn empty() -> Self { - Self(0) - } - - pub const fn from_bits(bits: u16) -> Self { - Self(bits) - } - - pub const fn bits(self) -> u16 { - self.0 - } - - pub const fn is_empty(self) -> bool { - self.0 == 0 - } - - pub const fn contains(self, other: Self) -> bool { - self.0 & other.0 == other.0 - } - - pub const fn intersects(self, other: Self) -> bool { - self.0 & other.0 != 0 - } -} - -impl BitOr for PollEvents { - type Output = Self; - - fn bitor(self, rhs: Self) -> Self::Output { - Self(self.0 | rhs.0) - } -} - -impl BitOrAssign for PollEvents { - fn bitor_assign(&mut self, rhs: Self) { - self.0 |= rhs.0; - } -} - -pub const POLLIN: PollEvents = PollEvents(0x0001); -pub const POLLOUT: PollEvents = PollEvents(0x0004); -pub const POLLERR: PollEvents = PollEvents(0x0008); -pub const POLLHUP: PollEvents = PollEvents(0x0010); -pub const POLLNVAL: PollEvents = PollEvents(0x0020); - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct PollFd { - pub fd: u32, - pub events: PollEvents, - pub revents: PollEvents, -} - -impl PollFd { - pub const fn new(fd: u32, events: PollEvents) -> Self { - Self { - fd, - events, - revents: PollEvents::empty(), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PollResult { - pub ready_count: usize, - pub fds: Vec, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PollTarget { - Fd(u32), - Socket(SocketId), -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct PollTargetEntry { - pub target: PollTarget, - pub events: PollEvents, - pub revents: PollEvents, -} - -impl PollTargetEntry { - pub const fn new(target: PollTarget, events: PollEvents) -> Self { - Self { - target, - events, - revents: PollEvents::empty(), - } - } - - pub const fn fd(fd: u32, events: PollEvents) -> Self { - Self::new(PollTarget::Fd(fd), events) - } - - pub const fn socket(socket_id: SocketId, events: PollEvents) -> Self { - Self::new(PollTarget::Socket(socket_id), events) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PollTargetResult { - pub ready_count: usize, - pub targets: Vec, -} - -/// Cloneable, Send handle onto the kernel's poll notifier so a caller can wait -/// for "some poll-visible state changed" OFF the thread that owns the kernel -/// (deferred readiness servicing), then re-check readiness with a zero-timeout -/// poll on the owning thread. Take `snapshot()` BEFORE the readiness check it -/// guards so a change landing between the check and the wait wakes immediately -/// instead of being lost. -#[derive(Debug, Clone)] -pub struct PollWaitHandle { - notifier: PollNotifier, -} - -impl PollWaitHandle { - pub(crate) fn new(notifier: PollNotifier) -> Self { - Self { notifier } - } - - /// Snapshot the current change generation. - pub fn snapshot(&self) -> u64 { - self.notifier.snapshot() - } - - /// Block until the generation moves past `observed` or `timeout` elapses - /// (`None` = wait forever). Returns true when a change was observed. - pub fn wait_for_change(&self, observed: u64, timeout: Option) -> bool { - self.notifier.wait_for_change(observed, timeout) - } -} - -#[derive(Debug, Clone, Default)] -pub(crate) struct PollNotifier { - inner: Arc, -} - -#[derive(Debug, Default)] -struct PollNotifierInner { - generation: Mutex, - waiters: Condvar, -} - -impl PollNotifier { - pub(crate) fn notify(&self) { - let mut generation = lock_or_recover(&self.inner.generation); - *generation = generation.wrapping_add(1); - self.inner.waiters.notify_all(); - } - - pub(crate) fn snapshot(&self) -> u64 { - *lock_or_recover(&self.inner.generation) - } - - pub(crate) fn wait_for_change(&self, observed: u64, timeout: Option) -> bool { - let mut generation = lock_or_recover(&self.inner.generation); - if *generation != observed { - return true; - } - - let Some(timeout) = timeout else { - while *generation == observed { - generation = wait_or_recover(&self.inner.waiters, generation); - } - return true; - }; - - if timeout.is_zero() { - return *generation != observed; - } - - let deadline = Instant::now() + timeout; - loop { - let now = Instant::now(); - if now >= deadline { - return *generation != observed; - } - - let remaining = deadline.saturating_duration_since(now); - let (next_generation, wait_result) = - wait_timeout_or_recover(&self.inner.waiters, generation, remaining); - generation = next_generation; - if *generation != observed { - return true; - } - if wait_result.timed_out() { - return false; - } - } - } -} - -fn lock_or_recover<'a, T>(mutex: &'a Mutex) -> MutexGuard<'a, T> { - match mutex.lock() { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -fn wait_or_recover<'a, T>(condvar: &Condvar, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { - match condvar.wait(guard) { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -fn wait_timeout_or_recover<'a, T>( - condvar: &Condvar, - guard: MutexGuard<'a, T>, - timeout: Duration, -) -> (MutexGuard<'a, T>, std::sync::WaitTimeoutResult) { - match condvar.wait_timeout(guard, timeout) { - Ok(result) => result, - Err(poisoned) => poisoned.into_inner(), - } -} - -#[cfg(test)] -mod tests { - use super::PollNotifier; - use std::sync::mpsc; - use std::thread; - use std::time::Duration; - - #[test] - fn infinite_wait_returns_after_notification_without_waiter_storage() { - let notifier = PollNotifier::default(); - let observed = notifier.snapshot(); - let waiter = notifier.clone(); - let (started_tx, started_rx) = mpsc::channel(); - let (done_tx, done_rx) = mpsc::channel(); - - let handle = thread::spawn(move || { - started_tx.send(()).expect("signal waiter start"); - let changed = waiter.wait_for_change(observed, None); - done_tx.send(changed).expect("signal waiter result"); - }); - - started_rx.recv().expect("waiter should start"); - assert!( - done_rx.recv_timeout(Duration::from_millis(25)).is_err(), - "waiter should stay blocked before notification" - ); - - notifier.notify(); - assert!(done_rx - .recv_timeout(Duration::from_secs(1)) - .expect("waiter should wake after notification")); - handle.join().expect("waiter thread should finish"); - } - - #[test] - fn saturated_generation_still_notifies_waiters() { - let notifier = PollNotifier::default(); - { - let mut generation = super::lock_or_recover(¬ifier.inner.generation); - *generation = u64::MAX; - } - - let observed = notifier.snapshot(); - let waiter = notifier.clone(); - let (started_tx, started_rx) = mpsc::channel(); - let (done_tx, done_rx) = mpsc::channel(); - - let handle = thread::spawn(move || { - started_tx.send(()).expect("signal waiter start"); - let changed = waiter.wait_for_change(observed, Some(Duration::from_secs(1))); - done_tx.send(changed).expect("signal waiter result"); - }); - - started_rx.recv().expect("waiter should start"); - notifier.notify(); - - assert!( - done_rx - .recv_timeout(Duration::from_secs(2)) - .expect("waiter should return after saturated notify"), - "saturated notify should still wake the waiter" - ); - handle.join().expect("waiter thread should finish"); - } -} diff --git a/crates/kernel/src/process_table.rs b/crates/kernel/src/process_table.rs deleted file mode 100644 index a0459973e..000000000 --- a/crates/kernel/src/process_table.rs +++ /dev/null @@ -1,1578 +0,0 @@ -use crate::user::ProcessIdentity; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::error::Error; -use std::fmt; -use std::ops::{BitOr, BitOrAssign}; -use std::sync::atomic::{AtomicUsize, Ordering}; -#[cfg(not(target_arch = "wasm32"))] -use std::sync::WaitTimeoutResult; -use std::sync::{Arc, Condvar, Mutex, MutexGuard, Weak}; -#[cfg(not(target_arch = "wasm32"))] -use std::thread; -use std::time::Duration; -use web_time::{Instant, SystemTime, UNIX_EPOCH}; - -const ZOMBIE_TTL: Duration = Duration::from_secs(60); -const INIT_PID: u32 = 1; -const MAX_ALLOCATED_PID: u32 = i32::MAX as u32; -pub const DEFAULT_PROCESS_UMASK: u32 = 0o022; -pub const SIGHUP: i32 = 1; -pub const SIGCHLD: i32 = 17; -pub const SIGCONT: i32 = 18; -pub const SIGSTOP: i32 = 19; -pub const SIGTSTP: i32 = 20; -pub const SIGTERM: i32 = 15; -pub const SIGKILL: i32 = 9; -pub const SIGPIPE: i32 = 13; -pub const SIGWINCH: i32 = 28; -const MAX_SIGNAL: i32 = 64; - -pub type ProcessResult = Result; -pub type ProcessExitCallback = Arc; - -pub trait DriverProcess: Send + Sync { - fn kill(&self, signal: i32); - fn wait(&self, timeout: Duration) -> Option; - fn set_on_exit(&self, callback: ProcessExitCallback); -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProcessTableError { - code: &'static str, - message: String, -} - -impl ProcessTableError { - pub fn code(&self) -> &'static str { - self.code - } - - fn invalid_signal(signal: i32) -> Self { - Self { - code: "EINVAL", - message: format!("invalid signal {signal}"), - } - } - - fn no_such_process(pid: u32) -> Self { - Self { - code: "ESRCH", - message: format!("no such process {pid}"), - } - } - - fn no_such_process_group(pgid: u32) -> Self { - Self { - code: "ESRCH", - message: format!("no such process group {pgid}"), - } - } - - fn no_matching_child(waiter_pid: u32, pid: i32) -> Self { - Self { - code: "ECHILD", - message: format!("process {waiter_pid} has no matching child for waitpid({pid})"), - } - } - - fn pid_space_exhausted() -> Self { - Self { - code: "EAGAIN", - message: String::from("process id space exhausted"), - } - } - - fn permission_denied(message: impl Into) -> Self { - Self { - code: "EPERM", - message: message.into(), - } - } -} - -impl fmt::Display for ProcessTableError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for ProcessTableError {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ProcessStatus { - Running, - Stopped, - Exited, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct SignalSet { - bits: u64, -} - -impl SignalSet { - pub const fn empty() -> Self { - Self { bits: 0 } - } - - pub const fn is_empty(self) -> bool { - self.bits == 0 - } - - pub fn from_signal(signal: i32) -> ProcessResult { - Ok(Self { - bits: signal_bit(signal)?, - }) - } - - pub fn from_signals(signals: impl IntoIterator) -> ProcessResult { - let mut set = Self::empty(); - for signal in signals { - set.insert(signal)?; - } - Ok(set) - } - - pub fn contains(self, signal: i32) -> bool { - signal_bit(signal) - .map(|bit| self.bits & bit != 0) - .unwrap_or(false) - } - - pub fn insert(&mut self, signal: i32) -> ProcessResult<()> { - self.bits |= signal_bit(signal)?; - Ok(()) - } - - pub fn remove(&mut self, signal: i32) -> ProcessResult<()> { - self.bits &= !signal_bit(signal)?; - Ok(()) - } - - pub fn union(self, other: Self) -> Self { - Self { - bits: self.bits | other.bits, - } - } - - pub fn difference(self, other: Self) -> Self { - Self { - bits: self.bits & !other.bits, - } - } - - pub fn signals(self) -> Vec { - let mut signals = Vec::new(); - for signal in 1..=MAX_SIGNAL { - if self.contains(signal) { - signals.push(signal); - } - } - signals - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SigmaskHow { - Block, - Unblock, - SetMask, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct WaitPidFlags { - bits: u32, -} - -impl WaitPidFlags { - pub const WNOHANG: Self = Self { bits: 1 << 0 }; - pub const WUNTRACED: Self = Self { bits: 1 << 1 }; - pub const WCONTINUED: Self = Self { bits: 1 << 2 }; - - pub const fn empty() -> Self { - Self { bits: 0 } - } - - pub const fn contains(self, other: Self) -> bool { - (self.bits & other.bits) == other.bits - } -} - -impl Default for WaitPidFlags { - fn default() -> Self { - Self::empty() - } -} - -impl BitOr for WaitPidFlags { - type Output = Self; - - fn bitor(self, rhs: Self) -> Self::Output { - Self { - bits: self.bits | rhs.bits, - } - } -} - -impl BitOrAssign for WaitPidFlags { - fn bitor_assign(&mut self, rhs: Self) { - self.bits |= rhs.bits; - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ProcessWaitEvent { - Exited, - Stopped, - Continued, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProcessWaitResult { - pub pid: u32, - pub status: i32, - pub event: ProcessWaitEvent, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProcessFileDescriptors { - pub stdin: u32, - pub stdout: u32, - pub stderr: u32, -} - -impl Default for ProcessFileDescriptors { - fn default() -> Self { - Self { - stdin: 0, - stdout: 1, - stderr: 2, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProcessContext { - pub pid: u32, - pub ppid: u32, - pub env: BTreeMap, - pub cwd: String, - pub umask: u32, - pub fds: ProcessFileDescriptors, - pub identity: ProcessIdentity, - pub blocked_signals: SignalSet, - pub pending_signals: SignalSet, -} - -impl Default for ProcessContext { - fn default() -> Self { - Self { - pid: 0, - ppid: 0, - env: BTreeMap::new(), - cwd: String::from("/"), - umask: DEFAULT_PROCESS_UMASK, - fds: ProcessFileDescriptors::default(), - identity: ProcessIdentity::default(), - blocked_signals: SignalSet::empty(), - pending_signals: SignalSet::empty(), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProcessEntry { - pub pid: u32, - pub ppid: u32, - pub pgid: u32, - pub sid: u32, - pub driver: String, - pub command: String, - pub args: Vec, - pub status: ProcessStatus, - pub exit_code: Option, - pub exit_time_ms: Option, - pub env: BTreeMap, - pub cwd: String, - pub umask: u32, - pub identity: ProcessIdentity, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProcessInfo { - pub pid: u32, - pub ppid: u32, - pub pgid: u32, - pub sid: u32, - pub driver: String, - pub command: String, - pub status: ProcessStatus, - pub exit_code: Option, - pub identity: ProcessIdentity, -} - -#[derive(Clone)] -pub struct ProcessTable { - inner: Arc, -} - -struct ProcessTableInner { - state: Mutex, - waiters: Condvar, - reaper: Arc, -} - -struct ProcessRecord { - entry: ProcessEntry, - driver_process: Arc, - pending_wait_events: VecDeque, - blocked_signals: SignalSet, - pending_signals: SignalSet, -} - -struct ScheduledSignalDelivery { - pid: u32, - signal: i32, - status: ProcessStatus, - driver_process: Arc, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct PendingWaitEvent { - status: i32, - event: ProcessWaitEvent, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum WaitSelector { - AnyChild, - ChildPid(u32), - ProcessGroup(u32), -} - -struct ZombieReaper { - state: Mutex, - wake: Condvar, - thread_spawns: AtomicUsize, -} - -#[derive(Default)] -struct ZombieReaperState { - deadlines: BTreeMap, - shutdown: bool, -} - -struct ProcessTableState { - entries: BTreeMap, - next_pid: u32, - zombie_ttl: Duration, - on_process_exit: Option>, - terminating_all: bool, -} - -impl Default for ProcessTableState { - fn default() -> Self { - Self { - entries: BTreeMap::new(), - next_pid: 1, - zombie_ttl: ZOMBIE_TTL, - on_process_exit: None, - terminating_all: false, - } - } -} - -impl Default for ProcessTable { - fn default() -> Self { - let reaper = Arc::new(ZombieReaper::default()); - Self { - inner: { - let inner = Arc::new(ProcessTableInner { - state: Mutex::new(ProcessTableState::default()), - waiters: Condvar::new(), - reaper, - }); - start_zombie_reaper(Arc::downgrade(&inner), Arc::clone(&inner.reaper)); - inner - }, - } - } -} - -impl ProcessTable { - pub fn new() -> Self { - Self::default() - } - - pub fn with_zombie_ttl(zombie_ttl: Duration) -> Self { - let table = Self::new(); - table.inner.lock_state().zombie_ttl = zombie_ttl; - table - } - - pub fn allocate_pid(&self) -> ProcessResult { - let mut state = self.inner.lock_state(); - let start = normalize_next_pid(state.next_pid); - let mut pid = start; - - loop { - if !state.entries.contains_key(&pid) { - state.next_pid = next_allocated_pid_after(pid); - return Ok(pid); - } - - pid = next_allocated_pid_after(pid); - if pid == start { - return Err(ProcessTableError::pid_space_exhausted()); - } - } - } - - pub fn set_on_process_exit(&self, callback: Option>) { - self.inner.lock_state().on_process_exit = callback; - } - - pub fn register( - &self, - pid: u32, - driver: impl Into, - command: impl Into, - args: Vec, - ctx: ProcessContext, - driver_process: Arc, - ) -> ProcessEntry { - let (pgid, sid) = { - let state = self.inner.lock_state(); - match state.entries.get(&ctx.ppid) { - Some(parent) => (parent.entry.pgid, parent.entry.sid), - None => (pid, pid), - } - }; - - let entry = ProcessEntry { - pid, - ppid: ctx.ppid, - pgid, - sid, - driver: driver.into(), - command: command.into(), - args, - status: ProcessStatus::Running, - exit_code: None, - exit_time_ms: None, - env: ctx.env, - cwd: ctx.cwd, - umask: ctx.umask & 0o777, - identity: ctx.identity, - }; - - let weak = Arc::downgrade(&self.inner); - driver_process.set_on_exit(Arc::new(move |code| { - if let Some(inner) = weak.upgrade() { - mark_exited_inner(&inner, pid, code); - } - })); - - let mut state = self.inner.lock_state(); - state.next_pid = next_pid_after_registered(state.next_pid, pid); - state.entries.insert( - pid, - ProcessRecord { - entry: entry.clone(), - driver_process, - pending_wait_events: VecDeque::new(), - blocked_signals: ctx.blocked_signals, - pending_signals: ctx.pending_signals, - }, - ); - - entry - } - - pub fn get(&self, pid: u32) -> Option { - self.inner - .lock_state() - .entries - .get(&pid) - .map(|record| record.entry.clone()) - } - - pub fn zombie_timer_count(&self) -> usize { - self.reap_due_zombies(); - self.inner.reaper.scheduled_count() - } - - /// Cooperatively reap any zombies whose TTL deadline has elapsed. - /// - /// On native this is a cheap no-op fast path (the background thread does the - /// reaping); on wasm32 there is no reaper thread, so process-table - /// operations drive reaping through this instead. - pub fn reap_due_zombies(&self) { - while let Some(pid) = self.inner.reaper.take_due_pid_now() { - reap_due_pid(&self.inner, &self.inner.reaper, pid); - } - } - - pub fn zombie_reaper_thread_spawn_count(&self) -> usize { - self.inner.reaper.thread_spawn_count() - } - - pub fn running_count(&self) -> usize { - self.inner - .lock_state() - .entries - .values() - .filter(|record| record.entry.status == ProcessStatus::Running) - .count() - } - - pub fn mark_exited(&self, pid: u32, exit_code: i32) { - mark_exited_inner(&self.inner, pid, exit_code); - } - - pub fn mark_stopped(&self, pid: u32, signal: i32) { - mark_wait_event_inner( - &self.inner, - pid, - ProcessStatus::Stopped, - PendingWaitEvent { - status: signal, - event: ProcessWaitEvent::Stopped, - }, - ); - } - - pub fn mark_continued(&self, pid: u32) { - mark_wait_event_inner( - &self.inner, - pid, - ProcessStatus::Running, - PendingWaitEvent { - status: SIGCONT, - event: ProcessWaitEvent::Continued, - }, - ); - } - - pub fn waitpid(&self, pid: u32) -> ProcessResult<(u32, i32)> { - let mut state = self.inner.lock_state(); - loop { - let Some(record) = state.entries.get(&pid) else { - return Err(ProcessTableError::no_such_process(pid)); - }; - - if record.entry.status == ProcessStatus::Exited { - let status = record.entry.exit_code.unwrap_or_default(); - state.entries.remove(&pid); - drop(state); - self.inner.reaper.cancel(pid); - self.inner.waiters.notify_all(); - return Ok((pid, status)); - } - - state = self.inner.wait_for_state(state); - } - } - - pub fn waitpid_for( - &self, - waiter_pid: u32, - pid: i32, - flags: WaitPidFlags, - ) -> ProcessResult> { - let mut state = self.inner.lock_state(); - loop { - let selector = resolve_wait_selector(&state, waiter_pid, pid)?; - let matching_children = matching_child_pids(&state, waiter_pid, selector); - if matching_children.is_empty() { - return Err(ProcessTableError::no_matching_child(waiter_pid, pid)); - } - - if let Some(result) = take_waitable_event(&mut state, &matching_children, flags) { - let should_reap = result.event == ProcessWaitEvent::Exited; - drop(state); - if should_reap { - self.inner.reaper.cancel(result.pid); - self.inner.waiters.notify_all(); - } - return Ok(Some(result)); - } - - if flags.contains(WaitPidFlags::WNOHANG) { - return Ok(None); - } - - state = self.inner.wait_for_state(state); - } - } - - pub fn kill(&self, pid: i32, signal: i32) -> ProcessResult<()> { - if !(0..=MAX_SIGNAL).contains(&signal) { - return Err(ProcessTableError::invalid_signal(signal)); - } - - let deliveries = { - let mut state = self.inner.lock_state(); - if pid < 0 { - let pgid = pid.unsigned_abs(); - let grouped = state - .entries - .values() - .filter(|record| record.entry.pgid == pgid) - .map(|record| record.entry.pid) - .collect::>(); - if grouped.is_empty() { - return Err(ProcessTableError::no_such_process_group(pgid)); - } - if signal == 0 { - return Ok(()); - } - collect_signal_deliveries(&mut state, &grouped, signal)? - } else { - let pid = pid as u32; - let Some(record) = state.entries.get(&pid) else { - return Err(ProcessTableError::no_such_process(pid)); - }; - if record.entry.status == ProcessStatus::Exited || signal == 0 { - return Ok(()); - } - collect_signal_deliveries(&mut state, &[pid], signal)? - } - }; - - if signal == 0 { - return Ok(()); - } - - deliver_signals(&self.inner, deliveries); - Ok(()) - } - - pub fn setpgid(&self, pid: u32, pgid: u32) -> ProcessResult<()> { - let mut state = self.inner.lock_state(); - let (current_sid, target_pgid) = { - let Some(record) = state.entries.get(&pid) else { - return Err(ProcessTableError::no_such_process(pid)); - }; - (record.entry.sid, if pgid == 0 { pid } else { pgid }) - }; - - if target_pgid != pid { - let mut group_exists = false; - for record in state.entries.values() { - if record.entry.pgid != target_pgid || record.entry.status == ProcessStatus::Exited - { - continue; - } - if record.entry.sid != current_sid { - return Err(ProcessTableError::permission_denied( - "cannot join process group in different session", - )); - } - group_exists = true; - break; - } - if !group_exists { - return Err(ProcessTableError::permission_denied(format!( - "no such process group {target_pgid}" - ))); - } - } - - if let Some(record) = state.entries.get_mut(&pid) { - record.entry.pgid = target_pgid; - } - Ok(()) - } - - pub fn getpgid(&self, pid: u32) -> ProcessResult { - self.get(pid) - .map(|entry| entry.pgid) - .ok_or_else(|| ProcessTableError::no_such_process(pid)) - } - - pub fn setsid(&self, pid: u32) -> ProcessResult { - let mut state = self.inner.lock_state(); - let Some(record) = state.entries.get_mut(&pid) else { - return Err(ProcessTableError::no_such_process(pid)); - }; - - if record.entry.pgid == pid { - return Err(ProcessTableError::permission_denied(format!( - "process {pid} is already a process group leader" - ))); - } - - record.entry.sid = pid; - record.entry.pgid = pid; - Ok(pid) - } - - pub fn getsid(&self, pid: u32) -> ProcessResult { - self.get(pid) - .map(|entry| entry.sid) - .ok_or_else(|| ProcessTableError::no_such_process(pid)) - } - - pub fn getppid(&self, pid: u32) -> ProcessResult { - self.get(pid) - .map(|entry| entry.ppid) - .ok_or_else(|| ProcessTableError::no_such_process(pid)) - } - - pub fn get_umask(&self, pid: u32) -> ProcessResult { - self.get(pid) - .map(|entry| entry.umask) - .ok_or_else(|| ProcessTableError::no_such_process(pid)) - } - - pub fn set_umask(&self, pid: u32, umask: u32) -> ProcessResult { - let mut state = self.inner.lock_state(); - let record = state - .entries - .get_mut(&pid) - .ok_or_else(|| ProcessTableError::no_such_process(pid))?; - let previous = record.entry.umask; - record.entry.umask = umask & 0o777; - Ok(previous) - } - - pub fn has_process_group(&self, pgid: u32) -> bool { - self.inner - .lock_state() - .entries - .values() - .any(|record| record.entry.pgid == pgid && record.entry.status != ProcessStatus::Exited) - } - - pub fn list_processes(&self) -> BTreeMap { - self.inner - .lock_state() - .entries - .values() - .map(|record| (record.entry.pid, to_process_info(&record.entry))) - .collect() - } - - pub fn terminate_all(&self) { - let running = { - let mut state = self.inner.lock_state(); - state.terminating_all = true; - self.inner.reaper.clear(); - state - .entries - .values() - .filter(|record| record.entry.status == ProcessStatus::Running) - .map(|record| (record.entry.pid, Arc::clone(&record.driver_process))) - .collect::>() - }; - - for (_, driver) in &running { - driver.kill(SIGTERM); - } - for (pid, driver) in &running { - if let Some(exit_code) = driver.wait(Duration::from_secs(1)) { - self.mark_exited(*pid, exit_code); - } - } - - let survivors = { - let state = self.inner.lock_state(); - running - .iter() - .filter(|(pid, _)| { - state - .entries - .get(pid) - .map(|record| record.entry.status == ProcessStatus::Running) - .unwrap_or(false) - }) - .cloned() - .collect::>() - }; - - for (_, driver) in &survivors { - driver.kill(SIGKILL); - } - for (pid, driver) in &survivors { - if let Some(exit_code) = driver.wait(Duration::from_millis(500)) { - self.mark_exited(*pid, exit_code); - } - } - - self.inner.lock_state().terminating_all = false; - } - - pub fn sigprocmask( - &self, - pid: u32, - how: SigmaskHow, - set: SignalSet, - ) -> ProcessResult { - let (previous, deliveries) = { - let mut state = self.inner.lock_state(); - let record = state - .entries - .get_mut(&pid) - .ok_or_else(|| ProcessTableError::no_such_process(pid))?; - let previous = record.blocked_signals; - record.blocked_signals = match how { - SigmaskHow::Block => previous.union(set), - SigmaskHow::Unblock => previous.difference(set), - SigmaskHow::SetMask => set, - }; - - let unblocked_pending = record.pending_signals.difference(record.blocked_signals); - let deliveries = collect_pending_signal_deliveries(record, unblocked_pending)?; - (previous, deliveries) - }; - - deliver_signals(&self.inner, deliveries); - Ok(previous) - } - - pub fn sigpending(&self, pid: u32) -> ProcessResult { - self.inner - .lock_state() - .entries - .get(&pid) - .map(|record| record.pending_signals) - .ok_or_else(|| ProcessTableError::no_such_process(pid)) - } -} - -fn to_process_info(entry: &ProcessEntry) -> ProcessInfo { - ProcessInfo { - pid: entry.pid, - ppid: entry.ppid, - pgid: entry.pgid, - sid: entry.sid, - driver: entry.driver.clone(), - command: entry.command.clone(), - status: entry.status, - exit_code: entry.exit_code, - identity: entry.identity.clone(), - } -} - -fn mark_exited_inner(inner: &Arc, pid: u32, exit_code: i32) { - let (callback, zombie_ttl, should_schedule, deliveries) = { - let mut state = inner.lock_state(); - let (ppid, pgid) = { - let Some(record) = state.entries.get_mut(&pid) else { - return; - }; - - if record.entry.status == ProcessStatus::Exited { - return; - } - - record.entry.status = ProcessStatus::Exited; - record.entry.exit_code = Some(exit_code); - record.entry.exit_time_ms = Some(now_ms()); - let ppid = record.entry.ppid; - let pgid = record.entry.pgid; - (ppid, pgid) - }; - let mut affected_pgids = BTreeSet::from([pgid]); - reparent_children_to_init(&mut state, pid, &mut affected_pgids); - - let orphaned_group_targets = collect_orphaned_group_signal_targets(&state, &affected_pgids); - - let should_schedule = !state.terminating_all; - let mut deliveries = Vec::new(); - if should_schedule { - if let Some(parent) = state - .entries - .get_mut(&ppid) - .filter(|parent| parent.entry.status == ProcessStatus::Running) - { - if let Some(delivery) = - queue_or_schedule_signal(parent, SIGCHLD).expect("SIGCHLD should be valid") - { - deliveries.push(delivery); - } - } - } - - for target_pid in orphaned_group_targets { - if let Some(record) = state.entries.get_mut(&target_pid) { - if let Some(delivery) = - queue_or_schedule_signal(record, SIGHUP).expect("SIGHUP should be valid") - { - deliveries.push(delivery); - } - if let Some(delivery) = - queue_or_schedule_signal(record, SIGCONT).expect("SIGCONT should be valid") - { - deliveries.push(delivery); - } - } - } - - ( - state.on_process_exit.clone(), - state.zombie_ttl, - should_schedule, - deliveries, - ) - }; - - if should_schedule { - inner.reaper.schedule(pid, zombie_ttl); - } else { - inner.reaper.cancel(pid); - } - - deliver_signals(inner, deliveries); - - if let Some(on_process_exit) = callback { - on_process_exit(pid); - } - - inner.waiters.notify_all(); -} - -fn reparent_children_to_init( - state: &mut ProcessTableState, - exiting_pid: u32, - affected_pgids: &mut BTreeSet, -) { - let new_parent = reparent_target_pid(state, exiting_pid); - for record in state.entries.values_mut() { - if record.entry.ppid != exiting_pid { - continue; - } - record.entry.ppid = new_parent; - affected_pgids.insert(record.entry.pgid); - } -} - -fn reparent_target_pid(state: &ProcessTableState, exiting_pid: u32) -> u32 { - if exiting_pid != INIT_PID - && state - .entries - .get(&INIT_PID) - .map(|record| record.entry.status != ProcessStatus::Exited) - .unwrap_or(false) - { - INIT_PID - } else { - 0 - } -} - -fn collect_orphaned_group_signal_targets( - state: &ProcessTableState, - candidate_pgids: &BTreeSet, -) -> Vec { - let mut targets = Vec::new(); - for &pgid in candidate_pgids { - if !process_group_is_orphaned(state, pgid) || !process_group_has_stopped_member(state, pgid) - { - continue; - } - - for record in state.entries.values() { - if record.entry.pgid == pgid && record.entry.status != ProcessStatus::Exited { - targets.push(record.entry.pid); - } - } - } - targets -} - -fn process_group_is_orphaned(state: &ProcessTableState, pgid: u32) -> bool { - let mut has_member = false; - for record in state.entries.values() { - if record.entry.pgid != pgid || record.entry.status == ProcessStatus::Exited { - continue; - } - has_member = true; - if has_parent_outside_group_in_same_session(state, &record.entry) { - return false; - } - } - - has_member -} - -fn has_parent_outside_group_in_same_session( - state: &ProcessTableState, - entry: &ProcessEntry, -) -> bool { - match entry.ppid { - 0 | INIT_PID => false, - ppid => state - .entries - .get(&ppid) - .map(|parent| { - parent.entry.status != ProcessStatus::Exited - && parent.entry.sid == entry.sid - && parent.entry.pgid != entry.pgid - }) - .unwrap_or(false), - } -} - -fn process_group_has_stopped_member(state: &ProcessTableState, pgid: u32) -> bool { - state - .entries - .values() - .any(|record| record.entry.pgid == pgid && record.entry.status == ProcessStatus::Stopped) -} - -fn mark_wait_event_inner( - inner: &Arc, - pid: u32, - next_status: ProcessStatus, - event: PendingWaitEvent, -) { - let deliveries = { - let mut state = inner.lock_state(); - let ppid = { - let Some(record) = state.entries.get_mut(&pid) else { - return; - }; - - if record.entry.status == ProcessStatus::Exited || record.entry.status == next_status { - return; - } - - record.entry.status = next_status; - record.pending_wait_events.push_back(event); - record.entry.ppid - }; - - state - .entries - .get_mut(&ppid) - .filter(|parent| parent.entry.status == ProcessStatus::Running) - .and_then(|parent| { - queue_or_schedule_signal(parent, SIGCHLD) - .expect("SIGCHLD should be valid") - .into_iter() - .next() - }) - .into_iter() - .collect::>() - }; - - deliver_signals(inner, deliveries); - - inner.waiters.notify_all(); -} - -fn signal_bit(signal: i32) -> ProcessResult { - if !(1..=MAX_SIGNAL).contains(&signal) { - return Err(ProcessTableError::invalid_signal(signal)); - } - Ok(1u64 << (signal - 1)) -} - -fn normalize_next_pid(pid: u32) -> u32 { - if (INIT_PID..=MAX_ALLOCATED_PID).contains(&pid) { - pid - } else { - INIT_PID - } -} - -fn next_allocated_pid_after(pid: u32) -> u32 { - if pid >= MAX_ALLOCATED_PID { - INIT_PID - } else { - pid + 1 - } -} - -fn next_pid_after_registered(current: u32, registered: u32) -> u32 { - let current = normalize_next_pid(current); - if !(INIT_PID..=MAX_ALLOCATED_PID).contains(®istered) { - return current; - } - - if current <= registered { - next_allocated_pid_after(registered) - } else { - current - } -} - -fn signal_can_be_blocked(signal: i32) -> bool { - !matches!(signal, SIGKILL | SIGSTOP | SIGCONT) -} - -fn queue_or_schedule_signal( - record: &mut ProcessRecord, - signal: i32, -) -> ProcessResult> { - if signal_can_be_blocked(signal) && record.blocked_signals.contains(signal) { - record.pending_signals.insert(signal)?; - return Ok(None); - } - - Ok(Some(ScheduledSignalDelivery { - pid: record.entry.pid, - signal, - status: record.entry.status, - driver_process: Arc::clone(&record.driver_process), - })) -} - -fn collect_signal_deliveries( - state: &mut ProcessTableState, - target_pids: &[u32], - signal: i32, -) -> ProcessResult> { - let mut deliveries = Vec::new(); - for pid in target_pids { - let Some(record) = state.entries.get_mut(pid) else { - continue; - }; - if let Some(delivery) = queue_or_schedule_signal(record, signal)? { - deliveries.push(delivery); - } - } - Ok(deliveries) -} - -fn collect_pending_signal_deliveries( - record: &mut ProcessRecord, - signals: SignalSet, -) -> ProcessResult> { - let mut deliveries = Vec::new(); - for signal in signals.signals() { - record.pending_signals.remove(signal)?; - deliveries.push(ScheduledSignalDelivery { - pid: record.entry.pid, - signal, - status: record.entry.status, - driver_process: Arc::clone(&record.driver_process), - }); - } - Ok(deliveries) -} - -fn deliver_signals(inner: &Arc, deliveries: Vec) { - let mut stopped = Vec::new(); - let mut continued = Vec::new(); - - for delivery in &deliveries { - match delivery.signal { - SIGSTOP | SIGTSTP if delivery.status == ProcessStatus::Running => { - stopped.push((delivery.pid, delivery.signal)) - } - SIGCONT if delivery.status == ProcessStatus::Stopped => continued.push(delivery.pid), - _ => {} - } - delivery.driver_process.kill(delivery.signal); - } - - for (pid, signal) in stopped { - mark_wait_event_inner( - inner, - pid, - ProcessStatus::Stopped, - PendingWaitEvent { - status: signal, - event: ProcessWaitEvent::Stopped, - }, - ); - } - for pid in continued { - mark_wait_event_inner( - inner, - pid, - ProcessStatus::Running, - PendingWaitEvent { - status: SIGCONT, - event: ProcessWaitEvent::Continued, - }, - ); - } -} - -fn resolve_wait_selector( - state: &ProcessTableState, - waiter_pid: u32, - pid: i32, -) -> ProcessResult { - let waiter = state - .entries - .get(&waiter_pid) - .ok_or_else(|| ProcessTableError::no_such_process(waiter_pid))?; - - Ok(match pid { - -1 => WaitSelector::AnyChild, - 0 => WaitSelector::ProcessGroup(waiter.entry.pgid), - p if p < -1 => WaitSelector::ProcessGroup(p.unsigned_abs()), - p => WaitSelector::ChildPid(p as u32), - }) -} - -fn matching_child_pids( - state: &ProcessTableState, - waiter_pid: u32, - selector: WaitSelector, -) -> Vec { - state - .entries - .values() - .filter(|record| record.entry.ppid == waiter_pid) - .filter(|record| match selector { - WaitSelector::AnyChild => true, - WaitSelector::ChildPid(pid) => record.entry.pid == pid, - WaitSelector::ProcessGroup(pgid) => record.entry.pgid == pgid, - }) - .map(|record| record.entry.pid) - .collect() -} - -fn take_waitable_event( - state: &mut ProcessTableState, - matching_children: &[u32], - flags: WaitPidFlags, -) -> Option { - for child_pid in matching_children { - let mut non_exit_result = None; - let mut should_reap = false; - { - let record = state.entries.get_mut(child_pid)?; - if let Some(index) = record - .pending_wait_events - .iter() - .position(|event| is_waitable_event(event.event, flags)) - { - let event = record - .pending_wait_events - .remove(index) - .expect("pending wait event should exist"); - non_exit_result = Some(ProcessWaitResult { - pid: *child_pid, - status: event.status, - event: event.event, - }); - } else if record.entry.status == ProcessStatus::Exited { - should_reap = true; - } - } - - if let Some(result) = non_exit_result { - return Some(result); - } - - if should_reap { - let record = state - .entries - .remove(child_pid) - .expect("exited child should still exist"); - return Some(ProcessWaitResult { - pid: *child_pid, - status: record.entry.exit_code.unwrap_or_default(), - event: ProcessWaitEvent::Exited, - }); - } - } - - None -} - -fn is_waitable_event(event: ProcessWaitEvent, flags: WaitPidFlags) -> bool { - match event { - ProcessWaitEvent::Exited => true, - ProcessWaitEvent::Stopped => flags.contains(WaitPidFlags::WUNTRACED), - ProcessWaitEvent::Continued => flags.contains(WaitPidFlags::WCONTINUED), - } -} - -// On native, the zombie reaper runs on a background thread that blocks on a -// condvar until the next TTL deadline. wasm32 is single-threaded with no -// blocking primitives, so there the reaper is driven cooperatively via -// `ProcessTable::reap_due_zombies` from process-table operations instead. -#[cfg(not(target_arch = "wasm32"))] -fn start_zombie_reaper(inner: Weak, reaper: Arc) { - reaper.thread_spawns.fetch_add(1, Ordering::SeqCst); - thread::spawn(move || loop { - let Some(pid) = reaper.take_next_due_pid() else { - return; - }; - - let Some(inner) = inner.upgrade() else { - return; - }; - - reap_due_pid(&inner, &reaper, pid); - }); -} - -#[cfg(target_arch = "wasm32")] -fn start_zombie_reaper(_inner: Weak, _reaper: Arc) {} - -/// Reap a single due zombie pid (shared by the native reaper thread and the -/// cooperative wasm drain). Removes the entry if it is an unparented zombie, -/// otherwise reschedules it for a later TTL pass. -fn reap_due_pid(inner: &ProcessTableInner, reaper: &ZombieReaper, pid: u32) { - let mut state = inner.lock_state(); - let should_reap = state - .entries - .get(&pid) - .map(|record| { - record.entry.status == ProcessStatus::Exited - && !has_living_parent(&state, record.entry.ppid) - }) - .unwrap_or(false); - if should_reap { - state.entries.remove(&pid); - } else if state - .entries - .get(&pid) - .map(|record| record.entry.status == ProcessStatus::Exited) - .unwrap_or(false) - { - reaper.schedule(pid, state.zombie_ttl); - } - drop(state); - inner.waiters.notify_all(); -} - -fn has_living_parent(state: &ProcessTableState, ppid: u32) -> bool { - ppid != 0 - && state - .entries - .get(&ppid) - .map(|record| record.entry.status != ProcessStatus::Exited) - .unwrap_or(false) -} - -impl ProcessTableInner { - fn lock_state(&self) -> MutexGuard<'_, ProcessTableState> { - lock_or_recover(&self.state) - } - - fn wait_for_state<'a>( - &self, - guard: MutexGuard<'a, ProcessTableState>, - ) -> MutexGuard<'a, ProcessTableState> { - wait_or_recover(&self.waiters, guard) - } -} - -fn now_ms() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as u64 -} - -impl Default for ZombieReaper { - fn default() -> Self { - Self { - state: Mutex::new(ZombieReaperState::default()), - wake: Condvar::new(), - thread_spawns: AtomicUsize::new(0), - } - } -} - -impl ZombieReaper { - fn schedule(&self, pid: u32, ttl: Duration) { - let mut state = lock_or_recover(&self.state); - state.deadlines.insert(pid, Instant::now() + ttl); - drop(state); - self.wake.notify_all(); - } - - fn cancel(&self, pid: u32) { - let mut state = lock_or_recover(&self.state); - let removed = state.deadlines.remove(&pid).is_some(); - drop(state); - if removed { - self.wake.notify_all(); - } - } - - fn clear(&self) { - let mut state = lock_or_recover(&self.state); - let changed = !state.deadlines.is_empty(); - state.deadlines.clear(); - drop(state); - if changed { - self.wake.notify_all(); - } - } - - fn shutdown(&self) { - let mut state = lock_or_recover(&self.state); - state.shutdown = true; - drop(state); - self.wake.notify_all(); - } - - fn scheduled_count(&self) -> usize { - lock_or_recover(&self.state).deadlines.len() - } - - fn thread_spawn_count(&self) -> usize { - self.thread_spawns.load(Ordering::SeqCst) - } - - // Blocking variant used only by the native reaper thread. - #[cfg(not(target_arch = "wasm32"))] - fn take_next_due_pid(&self) -> Option { - let mut state = lock_or_recover(&self.state); - loop { - if state.shutdown { - return None; - } - - let Some((pid, deadline)) = state - .deadlines - .iter() - .min_by_key(|(_, deadline)| **deadline) - .map(|(&pid, &deadline)| (pid, deadline)) - else { - state = wait_or_recover(&self.wake, state); - continue; - }; - - let now = Instant::now(); - if deadline <= now { - state.deadlines.remove(&pid); - return Some(pid); - } - - let timeout = deadline.saturating_duration_since(now); - let (next_state, _) = wait_timeout_or_recover(&self.wake, state, timeout); - state = next_state; - } - } - - /// Non-blocking variant of [`take_next_due_pid`]: returns a pid whose TTL - /// deadline has already elapsed, or `None` immediately. Used by the - /// cooperative wasm reaper, which cannot block. - fn take_due_pid_now(&self) -> Option { - let mut state = lock_or_recover(&self.state); - if state.shutdown { - return None; - } - let now = Instant::now(); - let due = state - .deadlines - .iter() - .filter(|(_, deadline)| **deadline <= now) - .min_by_key(|(_, deadline)| **deadline) - .map(|(&pid, _)| pid); - if let Some(pid) = due { - state.deadlines.remove(&pid); - } - due - } -} - -impl Drop for ProcessTableInner { - fn drop(&mut self) { - self.reaper.shutdown(); - } -} - -fn lock_or_recover<'a, T>(mutex: &'a Mutex) -> MutexGuard<'a, T> { - match mutex.lock() { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -fn wait_or_recover<'a, T>(condvar: &Condvar, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { - match condvar.wait(guard) { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -#[cfg(not(target_arch = "wasm32"))] -fn wait_timeout_or_recover<'a, T>( - condvar: &Condvar, - guard: MutexGuard<'a, T>, - timeout: Duration, -) -> (MutexGuard<'a, T>, WaitTimeoutResult) { - match condvar.wait_timeout(guard, timeout) { - Ok(result) => result, - Err(poisoned) => poisoned.into_inner(), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[derive(Default)] - struct TestDriverProcess { - on_exit: Mutex>, - } - - impl TestDriverProcess { - fn exit(&self, exit_code: i32) { - let callback = self - .on_exit - .lock() - .expect("test driver lock poisoned") - .clone(); - if let Some(callback) = callback { - callback(exit_code); - } - } - } - - impl DriverProcess for TestDriverProcess { - fn kill(&self, _signal: i32) {} - - fn wait(&self, _timeout: Duration) -> Option { - None - } - - fn set_on_exit(&self, callback: ProcessExitCallback) { - *self.on_exit.lock().expect("test driver lock poisoned") = Some(callback); - } - } - - fn context(ppid: u32) -> ProcessContext { - ProcessContext { - ppid, - ..ProcessContext::default() - } - } - - #[test] - fn allocate_pid_wraps_without_reusing_live_or_zombie_processes() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let live_high = Arc::new(TestDriverProcess::default()); - let zombie_high = Arc::new(TestDriverProcess::default()); - let live_one = Arc::new(TestDriverProcess::default()); - let max_pid = MAX_ALLOCATED_PID; - - table.register( - max_pid - 1, - "test", - "live-high", - Vec::new(), - context(0), - live_high, - ); - table.register( - max_pid, - "test", - "zombie-high", - Vec::new(), - context(0), - zombie_high.clone(), - ); - table.register(1, "test", "live-one", Vec::new(), context(0), live_one); - zombie_high.exit(0); - - table.inner.lock_state().next_pid = max_pid - 1; - - assert_eq!(table.allocate_pid().expect("allocate pid"), 2); - assert_eq!(table.allocate_pid().expect("allocate pid"), 3); - } -} diff --git a/crates/kernel/src/pty.rs b/crates/kernel/src/pty.rs deleted file mode 100644 index 7d9071207..000000000 --- a/crates/kernel/src/pty.rs +++ /dev/null @@ -1,1271 +0,0 @@ -use crate::fd_table::{ - FdResult, FileDescription, ProcessFdTable, SharedFileDescription, FILETYPE_CHARACTER_DEVICE, - O_RDWR, -}; -use crate::poll::{PollEvents, PollNotifier, POLLHUP, POLLIN, POLLOUT}; -use std::collections::{BTreeMap, VecDeque}; -use std::error::Error; -use std::fmt; -use std::sync::{Arc, Condvar, Mutex, MutexGuard}; -use std::time::Duration; -use web_time::Instant; - -pub const MAX_PTY_BUFFER_BYTES: usize = 65_536; -pub const MAX_CANON: usize = 4_096; -pub const SIGINT: i32 = 2; -pub const SIGQUIT: i32 = 3; -pub const SIGTSTP: i32 = 20; -const DEFAULT_PTY_COLUMNS: u16 = 80; -const DEFAULT_PTY_ROWS: u16 = 24; - -pub type PtyResult = Result; -pub type SignalHandler = Arc; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PtyError { - code: &'static str, - message: String, -} - -impl PtyError { - pub fn code(&self) -> &'static str { - self.code - } - - fn bad_file_descriptor(message: impl Into) -> Self { - Self { - code: "EBADF", - message: message.into(), - } - } - - fn io(message: impl Into) -> Self { - Self { - code: "EIO", - message: message.into(), - } - } - - fn would_block(message: impl Into) -> Self { - Self { - code: "EAGAIN", - message: message.into(), - } - } -} - -impl fmt::Display for PtyError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for PtyError {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct LineDisciplineConfig { - pub canonical: Option, - pub echo: Option, - pub isig: Option, - pub opost: Option, - pub onlcr: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Termios { - pub icrnl: bool, - pub opost: bool, - pub onlcr: bool, - pub icanon: bool, - pub echo: bool, - pub isig: bool, - pub cc: TermiosControlChars, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct PartialTermios { - pub icrnl: Option, - pub opost: Option, - pub onlcr: Option, - pub icanon: Option, - pub echo: Option, - pub isig: Option, - pub cc: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TermiosControlChars { - pub vintr: u8, - pub vquit: u8, - pub vsusp: u8, - pub veof: u8, - pub verase: u8, - pub vkill: u8, - pub vwerase: u8, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct PartialTermiosControlChars { - pub vintr: Option, - pub vquit: Option, - pub vsusp: Option, - pub veof: Option, - pub verase: Option, - pub vkill: Option, - pub vwerase: Option, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct PtyWindowSize { - pub cols: u16, - pub rows: u16, -} - -impl Default for PtyWindowSize { - fn default() -> Self { - Self { - cols: DEFAULT_PTY_COLUMNS, - rows: DEFAULT_PTY_ROWS, - } - } -} - -impl Default for Termios { - fn default() -> Self { - Self { - icrnl: true, - opost: true, - onlcr: true, - icanon: true, - echo: true, - isig: true, - cc: TermiosControlChars { - vintr: 0x03, - vquit: 0x1c, - vsusp: 0x1a, - veof: 0x04, - verase: 0x7f, - vkill: 0x15, - vwerase: 0x17, - }, - } - } -} - -impl Termios { - fn merge(&mut self, update: PartialTermios) { - if let Some(icrnl) = update.icrnl { - self.icrnl = icrnl; - } - if let Some(opost) = update.opost { - self.opost = opost; - } - if let Some(onlcr) = update.onlcr { - self.onlcr = onlcr; - } - if let Some(icanon) = update.icanon { - self.icanon = icanon; - } - if let Some(echo) = update.echo { - self.echo = echo; - } - if let Some(isig) = update.isig { - self.isig = isig; - } - if let Some(cc) = update.cc { - self.cc.merge(cc); - } - } -} - -impl TermiosControlChars { - fn merge(&mut self, update: PartialTermiosControlChars) { - if let Some(vintr) = update.vintr { - self.vintr = vintr; - } - if let Some(vquit) = update.vquit { - self.vquit = vquit; - } - if let Some(vsusp) = update.vsusp { - self.vsusp = vsusp; - } - if let Some(veof) = update.veof { - self.veof = veof; - } - if let Some(verase) = update.verase { - self.verase = verase; - } - if let Some(vkill) = update.vkill { - self.vkill = vkill; - } - if let Some(vwerase) = update.vwerase { - self.vwerase = vwerase; - } - } -} - -#[derive(Debug, Clone)] -pub struct PtyEnd { - pub description: SharedFileDescription, - pub filetype: u8, -} - -#[derive(Debug, Clone)] -pub struct PtyPair { - pub master: PtyEnd, - pub slave: PtyEnd, - pub path: String, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct PtyRef { - pty_id: u64, - end: PtyEndKind, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum PtyEndKind { - Master, - Slave, -} - -#[derive(Debug, Default)] -struct PendingRead { - length: usize, - result: Option>>, -} - -#[derive(Debug, Clone, Default)] -struct PtyState { - path: String, - input_buffer: VecDeque>, - output_buffer: VecDeque>, - input_eof_pending: bool, - closed_master: bool, - closed_slave: bool, - waiting_input_reads: VecDeque, - waiting_output_reads: VecDeque, - termios: Termios, - line_buffer: Vec, - foreground_pgid: u32, - window_size: PtyWindowSize, -} - -#[derive(Debug)] -struct PtyManagerState { - ptys: BTreeMap, - desc_to_pty: BTreeMap, - waiters: BTreeMap, - next_pty_id: u64, - next_desc_id: u64, - next_waiter_id: u64, -} - -impl Default for PtyManagerState { - fn default() -> Self { - Self { - ptys: BTreeMap::new(), - desc_to_pty: BTreeMap::new(), - waiters: BTreeMap::new(), - next_pty_id: 0, - next_desc_id: 200_000, - next_waiter_id: 1, - } - } -} - -#[derive(Debug)] -struct PtyManagerInner { - state: Mutex, - waiters: Condvar, -} - -#[derive(Clone)] -pub struct PtyManager { - inner: Arc, - on_signal: Option, - notifier: Option, -} - -impl Default for PtyManager { - fn default() -> Self { - Self { - inner: Arc::new(PtyManagerInner { - state: Mutex::new(PtyManagerState::default()), - waiters: Condvar::new(), - }), - on_signal: None, - notifier: None, - } - } -} - -impl PtyManager { - pub fn new() -> Self { - Self::default() - } - - pub fn with_signal_handler(on_signal: SignalHandler) -> Self { - let mut manager = Self::new(); - manager.on_signal = Some(on_signal); - manager - } - - pub(crate) fn with_signal_handler_and_notifier( - on_signal: SignalHandler, - notifier: PollNotifier, - ) -> Self { - let mut manager = Self::with_notifier(notifier); - manager.on_signal = Some(on_signal); - manager - } - - pub(crate) fn with_notifier(notifier: PollNotifier) -> Self { - Self { - notifier: Some(notifier), - ..Self::default() - } - } - - pub fn create_pty(&self) -> PtyPair { - let mut state = lock_or_recover(&self.inner.state); - let pty_id = state.next_pty_id; - state.next_pty_id += 1; - - let master_id = state.next_desc_id; - state.next_desc_id += 1; - let slave_id = state.next_desc_id; - state.next_desc_id += 1; - - let path = format!("/dev/pts/{pty_id}"); - state.ptys.insert( - pty_id, - PtyState { - path: path.clone(), - termios: Termios::default(), - window_size: PtyWindowSize::default(), - ..PtyState::default() - }, - ); - state.desc_to_pty.insert( - master_id, - PtyRef { - pty_id, - end: PtyEndKind::Master, - }, - ); - state.desc_to_pty.insert( - slave_id, - PtyRef { - pty_id, - end: PtyEndKind::Slave, - }, - ); - drop(state); - - PtyPair { - master: PtyEnd { - description: Arc::new(FileDescription::with_ref_count( - master_id, - format!("pty:{pty_id}:master"), - O_RDWR, - 0, - )), - filetype: FILETYPE_CHARACTER_DEVICE, - }, - slave: PtyEnd { - description: Arc::new(FileDescription::with_ref_count( - slave_id, - path.clone(), - O_RDWR, - 0, - )), - filetype: FILETYPE_CHARACTER_DEVICE, - }, - path, - } - } - - pub fn create_pty_fds(&self, fd_table: &mut ProcessFdTable) -> FdResult<(u32, u32, String)> { - let pty = self.create_pty(); - let master_fd = fd_table.open_with( - Arc::clone(&pty.master.description), - FILETYPE_CHARACTER_DEVICE, - None, - )?; - match fd_table.open_with( - Arc::clone(&pty.slave.description), - FILETYPE_CHARACTER_DEVICE, - None, - ) { - Ok(slave_fd) => Ok((master_fd, slave_fd, pty.path)), - Err(error) => { - fd_table.close(master_fd); - self.close(pty.master.description.id()); - self.close(pty.slave.description.id()); - Err(error) - } - } - } - - pub fn poll(&self, description_id: u64, requested: PollEvents) -> PtyResult { - let state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - let pty = state - .ptys - .get(&pty_ref.pty_id) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found"))?; - - let mut events = PollEvents::empty(); - match pty_ref.end { - PtyEndKind::Master => { - if requested.intersects(POLLIN) && !pty.output_buffer.is_empty() { - events |= POLLIN; - } - if pty.closed_slave { - events |= POLLHUP; - } else if requested.intersects(POLLOUT) - && (available_capacity(&pty.input_buffer) > 0 - || !pty.waiting_input_reads.is_empty()) - { - events |= POLLOUT; - } - } - PtyEndKind::Slave => { - if requested.intersects(POLLIN) - && (pty.input_eof_pending || !pty.input_buffer.is_empty()) - { - events |= POLLIN; - } - if pty.closed_master { - events |= POLLHUP; - } else if requested.intersects(POLLOUT) - && (available_capacity(&pty.output_buffer) > 0 - || !pty.waiting_output_reads.is_empty()) - { - events |= POLLOUT; - } - } - } - - Ok(events) - } - - pub fn write(&self, description_id: u64, data: impl AsRef<[u8]>) -> PtyResult { - let payload = data.as_ref(); - let mut signals = Vec::new(); - - { - let mut state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - let PtyManagerState { ptys, waiters, .. } = &mut *state; - let pty = ptys - .get_mut(&pty_ref.pty_id) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found"))?; - - match pty_ref.end { - PtyEndKind::Master => { - if pty.closed_master { - return Err(PtyError::io("master closed")); - } - if pty.closed_slave { - return Err(PtyError::io("slave closed")); - } - process_input(pty, waiters, payload, &mut signals)?; - } - PtyEndKind::Slave => { - if pty.closed_slave { - return Err(PtyError::io("slave closed")); - } - if pty.closed_master { - return Err(PtyError::io("master closed")); - } - - let processed = process_output(&pty.termios, payload); - deliver_output(pty, waiters, &processed, false)?; - // Terminal emulation: answer a Device Status Report cursor-position - // query (ESC[6n) with a cursor report (ESC[row;colR) on the slave's - // input. A real terminal emulator on the master side does this; the - // converged PTY may have no such emulator, so crossterm/reedline guests - // that probe the cursor at startup would otherwise stall and abort. - if contains_dsr_cursor_query(payload) { - deliver_input(pty, waiters, b"\x1b[1;1R")?; - } - } - } - } - - self.notify_waiters_and_pollers(); - if let Some(on_signal) = &self.on_signal { - for (pgid, signal) in signals { - if pgid > 0 { - on_signal(pgid, signal); - } - } - } - - Ok(payload.len()) - } - - pub fn read(&self, description_id: u64, length: usize) -> PtyResult>> { - self.read_with_timeout(description_id, length, None) - } - - pub fn read_with_timeout( - &self, - description_id: u64, - length: usize, - timeout: Option, - ) -> PtyResult>> { - let mut state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - let mut waiter_id = None; - let deadline = timeout.map(|duration| Instant::now() + duration); - - loop { - if let Some(id) = waiter_id { - if let Some(waiter) = state.waiters.get_mut(&id) { - if let Some(result) = waiter.result.take() { - state.waiters.remove(&id); - return Ok(result); - } - } - } - - { - let pty = state - .ptys - .get_mut(&pty_ref.pty_id) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found"))?; - - match pty_ref.end { - PtyEndKind::Master => { - if pty.closed_master { - if let Some(id) = waiter_id { - state.waiters.remove(&id); - } - return Err(PtyError::io("master closed")); - } - - if !pty.output_buffer.is_empty() { - let result = drain_buffer(&mut pty.output_buffer, length); - // This reader consumed buffered data directly, so its queued waiter - // entry must be removed or a later delivery will assign data to an - // orphan. - if let Some(id) = waiter_id.take() { - pty.waiting_input_reads.retain(|queued| *queued != id); - pty.waiting_output_reads.retain(|queued| *queued != id); - state.waiters.remove(&id); - } - self.notify_waiters_and_pollers(); - return Ok(Some(result)); - } - - if pty.closed_slave { - if let Some(id) = waiter_id { - state.waiters.remove(&id); - } - return Ok(None); - } - } - PtyEndKind::Slave => { - if pty.closed_slave { - if let Some(id) = waiter_id { - state.waiters.remove(&id); - } - return Err(PtyError::io("slave closed")); - } - - if !pty.input_buffer.is_empty() { - let result = drain_buffer(&mut pty.input_buffer, length); - // This reader consumed buffered data directly, so its queued waiter - // entry must be removed or a later delivery will assign data to an - // orphan. - if let Some(id) = waiter_id.take() { - pty.waiting_input_reads.retain(|queued| *queued != id); - pty.waiting_output_reads.retain(|queued| *queued != id); - state.waiters.remove(&id); - } - self.notify_waiters_and_pollers(); - return Ok(Some(result)); - } - - if pty.input_eof_pending { - pty.input_eof_pending = false; - if let Some(id) = waiter_id { - state.waiters.remove(&id); - } - self.notify_waiters_and_pollers(); - return Ok(None); - } - - if pty.closed_master { - if let Some(id) = waiter_id { - state.waiters.remove(&id); - } - return Ok(None); - } - } - } - } - - let id = if let Some(id) = waiter_id { - id - } else { - let next = state.next_waiter_id; - state.next_waiter_id += 1; - state.waiters.insert( - next, - PendingRead { - length, - result: None, - }, - ); - let Some(pty) = state.ptys.get_mut(&pty_ref.pty_id) else { - state.waiters.remove(&next); - return Err(PtyError::bad_file_descriptor("PTY not found")); - }; - match pty_ref.end { - PtyEndKind::Master => pty.waiting_output_reads.push_back(next), - PtyEndKind::Slave => pty.waiting_input_reads.push_back(next), - } - self.notify_waiters_and_pollers(); - waiter_id = Some(next); - next - }; - - let Some(deadline) = deadline else { - state = wait_or_recover(&self.inner.waiters, state); - if !state.waiters.contains_key(&id) { - waiter_id = None; - } - continue; - }; - - let now = Instant::now(); - if now >= deadline { - if let Some(id) = waiter_id.take() { - state.waiters.remove(&id); - if let Some(pty) = state.ptys.get_mut(&pty_ref.pty_id) { - pty.waiting_input_reads.retain(|queued| *queued != id); - pty.waiting_output_reads.retain(|queued| *queued != id); - } - self.notify_waiters_and_pollers(); - } - return Err(PtyError::would_block("PTY read timed out")); - } - - let remaining = deadline.saturating_duration_since(now); - let (next_state, wait_result) = - wait_timeout_or_recover(&self.inner.waiters, state, remaining); - state = next_state; - if !state.waiters.contains_key(&id) { - waiter_id = None; - } - if wait_result.timed_out() { - if let Some(id) = waiter_id.take() { - state.waiters.remove(&id); - if let Some(pty) = state.ptys.get_mut(&pty_ref.pty_id) { - pty.waiting_input_reads.retain(|queued| *queued != id); - pty.waiting_output_reads.retain(|queued| *queued != id); - } - self.notify_waiters_and_pollers(); - } - return Err(PtyError::would_block("PTY read timed out")); - } - } - } - - pub fn close(&self, description_id: u64) { - let mut state = lock_or_recover(&self.inner.state); - let Some(pty_ref) = state.desc_to_pty.remove(&description_id) else { - return; - }; - - let (waiter_ids, remove_pty) = if let Some(pty) = state.ptys.get_mut(&pty_ref.pty_id) { - match pty_ref.end { - PtyEndKind::Master => { - pty.closed_master = true; - let mut waiters = pty.waiting_input_reads.drain(..).collect::>(); - waiters.extend(pty.waiting_output_reads.drain(..)); - (waiters, pty.closed_master && pty.closed_slave) - } - PtyEndKind::Slave => { - pty.closed_slave = true; - let mut waiters = pty.waiting_output_reads.drain(..).collect::>(); - waiters.extend(pty.waiting_input_reads.drain(..)); - (waiters, pty.closed_master && pty.closed_slave) - } - } - } else { - (Vec::new(), false) - }; - - for waiter_id in waiter_ids { - if let Some(waiter) = state.waiters.get_mut(&waiter_id) { - waiter.result = Some(None); - } - } - - if remove_pty { - state.ptys.remove(&pty_ref.pty_id); - } - self.notify_waiters_and_pollers(); - } - - pub fn is_pty(&self, description_id: u64) -> bool { - lock_or_recover(&self.inner.state) - .desc_to_pty - .contains_key(&description_id) - } - - pub fn is_slave(&self, description_id: u64) -> bool { - lock_or_recover(&self.inner.state) - .desc_to_pty - .get(&description_id) - .map(|pty_ref| pty_ref.end == PtyEndKind::Slave) - .unwrap_or(false) - } - - pub fn set_discipline( - &self, - description_id: u64, - config: LineDisciplineConfig, - ) -> PtyResult<()> { - let mut state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - let pty = state - .ptys - .get_mut(&pty_ref.pty_id) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found"))?; - if let Some(canonical) = config.canonical { - pty.termios.icanon = canonical; - } - if let Some(echo) = config.echo { - pty.termios.echo = echo; - } - if let Some(isig) = config.isig { - pty.termios.isig = isig; - } - if let Some(opost) = config.opost { - pty.termios.opost = opost; - } - if let Some(onlcr) = config.onlcr { - pty.termios.onlcr = onlcr; - } - Ok(()) - } - - pub fn get_termios(&self, description_id: u64) -> PtyResult { - let state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - state - .ptys - .get(&pty_ref.pty_id) - .cloned() - .map(|pty| pty.termios) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found")) - } - - pub fn set_termios(&self, description_id: u64, termios: PartialTermios) -> PtyResult<()> { - let mut state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - let pty = state - .ptys - .get_mut(&pty_ref.pty_id) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found"))?; - pty.termios.merge(termios); - Ok(()) - } - - pub fn set_foreground_pgid(&self, description_id: u64, pgid: u32) -> PtyResult<()> { - let mut state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - let pty = state - .ptys - .get_mut(&pty_ref.pty_id) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found"))?; - pty.foreground_pgid = pgid; - Ok(()) - } - - pub fn get_foreground_pgid(&self, description_id: u64) -> PtyResult { - let state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - state - .ptys - .get(&pty_ref.pty_id) - .map(|pty| pty.foreground_pgid) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found")) - } - - pub fn window_size(&self, description_id: u64) -> PtyResult { - let state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - state - .ptys - .get(&pty_ref.pty_id) - .map(|pty| pty.window_size) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found")) - } - - pub fn resize(&self, description_id: u64, cols: u16, rows: u16) -> PtyResult> { - let mut state = lock_or_recover(&self.inner.state); - let pty_ref = state - .desc_to_pty - .get(&description_id) - .copied() - .ok_or_else(|| PtyError::bad_file_descriptor("not a PTY end"))?; - let pty = state - .ptys - .get_mut(&pty_ref.pty_id) - .ok_or_else(|| PtyError::bad_file_descriptor("PTY not found"))?; - let next_size = PtyWindowSize { cols, rows }; - if pty.window_size == next_size { - return Ok(None); - } - pty.window_size = next_size; - Ok((pty.foreground_pgid > 0).then_some(pty.foreground_pgid)) - } - - pub fn pty_count(&self) -> usize { - lock_or_recover(&self.inner.state).ptys.len() - } - - pub fn buffered_input_bytes(&self) -> usize { - lock_or_recover(&self.inner.state) - .ptys - .values() - .map(|pty| buffer_size(&pty.input_buffer)) - .sum() - } - - pub fn buffered_output_bytes(&self) -> usize { - lock_or_recover(&self.inner.state) - .ptys - .values() - .map(|pty| buffer_size(&pty.output_buffer)) - .sum() - } - - pub fn pending_read_waiter_count(&self) -> usize { - lock_or_recover(&self.inner.state).waiters.len() - } - - pub fn queued_read_waiter_count(&self) -> usize { - lock_or_recover(&self.inner.state) - .ptys - .values() - .map(|pty| pty.waiting_input_reads.len() + pty.waiting_output_reads.len()) - .sum() - } - - pub fn path_for(&self, description_id: u64) -> Option { - let state = lock_or_recover(&self.inner.state); - let pty_ref = state.desc_to_pty.get(&description_id)?; - state.ptys.get(&pty_ref.pty_id).map(|pty| pty.path.clone()) - } - - fn notify_waiters_and_pollers(&self) { - self.inner.waiters.notify_all(); - if let Some(notifier) = &self.notifier { - notifier.notify(); - } - } -} - -/// True if `data` contains a Device Status Report cursor-position query -/// (`ESC [ 6 n`). Used to drive the converged PTY's terminal-style auto-reply. -fn contains_dsr_cursor_query(data: &[u8]) -> bool { - const QUERY: &[u8] = b"\x1b[6n"; - data.windows(QUERY.len()).any(|window| window == QUERY) -} - -fn process_output(termios: &Termios, data: &[u8]) -> Vec { - if !termios.opost || !termios.onlcr || !data.contains(&b'\n') { - return data.to_vec(); - } - - let extra_crs = data - .iter() - .enumerate() - .filter(|(index, byte)| **byte == b'\n' && (*index == 0 || data[*index - 1] != b'\r')) - .count(); - if extra_crs == 0 { - return data.to_vec(); - } - - let mut result = Vec::with_capacity(data.len() + extra_crs); - for (index, byte) in data.iter().enumerate() { - if *byte == b'\n' && (index == 0 || data[index - 1] != b'\r') { - result.push(b'\r'); - } - result.push(*byte); - } - result -} - -fn process_input( - pty: &mut PtyState, - waiters: &mut BTreeMap, - data: &[u8], - signals: &mut Vec<(u32, i32)>, -) -> PtyResult<()> { - if !pty.termios.icanon && !pty.termios.echo && !pty.termios.isig { - let translated = translate_input(&pty.termios, data); - deliver_input(pty, waiters, &translated)?; - return Ok(()); - } - - for mut byte in data.iter().copied() { - if pty.termios.icrnl && byte == b'\r' { - byte = b'\n'; - } - - if pty.termios.isig { - if let Some(signal) = signal_for_byte(&pty.termios, byte) { - if pty.termios.icanon { - pty.line_buffer.clear(); - } - let has_foreground_process_group = pty.foreground_pgid > 0; - // Only echo the signal-generating control char (e.g. "^C") as a - // line-editor fallback when there is NO foreground process group - // to receive the signal. With a foreground process group the - // signal is delivered to it and the char is not echoed, matching - // the integration suite's VINTR/VSUSP/VQUIT expectations. - if pty.termios.echo && !has_foreground_process_group { - deliver_output(pty, waiters, &echo_control_byte(byte), true)?; - if pty.termios.icanon { - deliver_output(pty, waiters, b"\r\n", true)?; - } - } - if has_foreground_process_group { - signals.push((pty.foreground_pgid, signal)); - } else if pty.termios.icanon { - deliver_input(pty, waiters, b"\n")?; - } - continue; - } - } - - if pty.termios.icanon { - if byte == pty.termios.cc.veof { - if pty.line_buffer.is_empty() { - deliver_input_eof(pty, waiters); - } else { - let line = pty.line_buffer.clone(); - deliver_input(pty, waiters, &line)?; - pty.line_buffer.clear(); - } - continue; - } - - if byte == pty.termios.cc.verase || byte == 0x08 { - if let Some(&erased) = pty.line_buffer.last() { - if pty.termios.echo { - deliver_output(pty, waiters, &erase_sequence(erased), true)?; - } - pty.line_buffer.pop(); - } - continue; - } - - if byte == pty.termios.cc.vkill { - if !pty.line_buffer.is_empty() { - if pty.termios.echo { - let erase: Vec = pty - .line_buffer - .iter() - .flat_map(|b| erase_sequence(*b)) - .collect(); - deliver_output(pty, waiters, &erase, true)?; - } - pty.line_buffer.clear(); - } - continue; - } - - if byte == pty.termios.cc.vwerase { - let mut erased: Vec = Vec::new(); - while matches!(pty.line_buffer.last(), Some(b' ') | Some(b'\t')) { - if let Some(b) = pty.line_buffer.pop() { - erased.push(b); - } - } - while let Some(&b) = pty.line_buffer.last() { - if b == b' ' || b == b'\t' { - break; - } - pty.line_buffer.pop(); - erased.push(b); - } - if pty.termios.echo && !erased.is_empty() { - let sequence: Vec = - erased.iter().flat_map(|b| erase_sequence(*b)).collect(); - deliver_output(pty, waiters, &sequence, true)?; - } - continue; - } - - if byte == b'\n' { - let mut line = pty.line_buffer.clone(); - line.push(b'\n'); - if pty.termios.echo { - deliver_output(pty, waiters, b"\r\n", true)?; - } - deliver_input(pty, waiters, &line)?; - pty.line_buffer.clear(); - continue; - } - - if pty.line_buffer.len() >= MAX_CANON { - continue; - } - if pty.termios.echo { - // ECHOCTL: echo control chars in caret form (e.g. 0x01 -> "^A") - // so they are visible; printable bytes echo verbatim. - deliver_output(pty, waiters, &echo_control_byte(byte), true)?; - } - pty.line_buffer.push(byte); - } else { - if pty.termios.echo { - deliver_output(pty, waiters, &[byte], true)?; - } - deliver_input(pty, waiters, &[byte])?; - } - } - - Ok(()) -} - -fn translate_input(termios: &Termios, data: &[u8]) -> Vec { - if !termios.icrnl || !data.contains(&b'\r') { - return data.to_vec(); - } - - data.iter() - .map(|byte| if *byte == b'\r' { b'\n' } else { *byte }) - .collect() -} - -fn deliver_input( - pty: &mut PtyState, - waiters: &mut BTreeMap, - data: &[u8], -) -> PtyResult<()> { - if let Some(waiter_id) = pty.waiting_input_reads.pop_front() { - if let Some(waiter) = waiters.get_mut(&waiter_id) { - if data.len() <= waiter.length { - waiter.result = Some(Some(data.to_vec())); - } else { - // The waiter consumes `waiter.length` bytes directly; only the - // tail is buffered, so the buffer cap must be enforced on the - // tail. Otherwise a single large write past a pending reader - // bypasses MAX_PTY_BUFFER_BYTES entirely. - let tail_len = data.len() - waiter.length; - if tail_len > available_capacity(&pty.input_buffer) { - pty.waiting_input_reads.push_front(waiter_id); - return Err(PtyError::would_block("PTY input buffer full")); - } - let (head, tail) = data.split_at(waiter.length); - waiter.result = Some(Some(head.to_vec())); - pty.input_buffer.push_front(tail.to_vec()); - } - return Ok(()); - } - } - - if buffer_size(&pty.input_buffer).saturating_add(data.len()) > MAX_PTY_BUFFER_BYTES { - return Err(PtyError::would_block("PTY input buffer full")); - } - - pty.input_buffer.push_back(data.to_vec()); - Ok(()) -} - -fn deliver_input_eof(pty: &mut PtyState, waiters: &mut BTreeMap) { - if let Some(waiter_id) = pty.waiting_input_reads.pop_front() { - if let Some(waiter) = waiters.get_mut(&waiter_id) { - waiter.result = Some(None); - return; - } - } - - pty.input_eof_pending = true; -} - -fn deliver_output( - pty: &mut PtyState, - waiters: &mut BTreeMap, - data: &[u8], - echo: bool, -) -> PtyResult<()> { - if let Some(waiter_id) = pty.waiting_output_reads.pop_front() { - if let Some(waiter) = waiters.get_mut(&waiter_id) { - if data.len() <= waiter.length { - waiter.result = Some(Some(data.to_vec())); - } else { - // Enforce the buffer cap on the tail (see deliver_input). - let tail_len = data.len() - waiter.length; - if tail_len > available_capacity(&pty.output_buffer) { - pty.waiting_output_reads.push_front(waiter_id); - let message = if echo { - "PTY output buffer full (echo backpressure)" - } else { - "PTY output buffer full" - }; - return Err(PtyError::would_block(message)); - } - let (head, tail) = data.split_at(waiter.length); - waiter.result = Some(Some(head.to_vec())); - pty.output_buffer.push_front(tail.to_vec()); - } - return Ok(()); - } - } - - if buffer_size(&pty.output_buffer).saturating_add(data.len()) > MAX_PTY_BUFFER_BYTES { - let message = if echo { - "PTY output buffer full (echo backpressure)" - } else { - "PTY output buffer full" - }; - return Err(PtyError::would_block(message)); - } - - pty.output_buffer.push_back(data.to_vec()); - Ok(()) -} - -fn signal_for_byte(termios: &Termios, byte: u8) -> Option { - if byte == termios.cc.vintr { - return Some(SIGINT); - } - if byte == termios.cc.vquit { - return Some(SIGQUIT); - } - if byte == termios.cc.vsusp { - return Some(SIGTSTP); - } - None -} - -fn echo_control_byte(byte: u8) -> Vec { - if byte < 0x20 { - vec![b'^', byte + 0x40] - } else if byte == 0x7f { - b"^?".to_vec() - } else { - vec![byte] - } -} - -/// Backspace-erase sequence for a single buffered input byte, accounting for how -/// wide it was echoed: a control char echoed in caret form (`^X`, ECHOCTL) -/// occupies two columns and needs two `BS SP BS` triples, while a printable byte -/// occupies one. Used by VERASE / VKILL / VWERASE erase echo so the erased echo -/// width matches the displayed width. -fn erase_sequence(byte: u8) -> Vec { - let columns = echo_control_byte(byte).len(); - (0..columns).flat_map(|_| [0x08, 0x20, 0x08]).collect() -} - -fn buffer_size(buffer: &VecDeque>) -> usize { - buffer.iter().map(Vec::len).sum() -} - -fn available_capacity(buffer: &VecDeque>) -> usize { - MAX_PTY_BUFFER_BYTES.saturating_sub(buffer_size(buffer)) -} - -fn drain_buffer(buffer: &mut VecDeque>, length: usize) -> Vec { - let mut chunks = Vec::new(); - let mut remaining = length; - - while remaining > 0 { - let Some(chunk) = buffer.pop_front() else { - break; - }; - if chunk.len() <= remaining { - remaining -= chunk.len(); - chunks.push(chunk); - } else { - let (head, tail) = chunk.split_at(remaining); - chunks.push(head.to_vec()); - buffer.push_front(tail.to_vec()); - remaining = 0; - } - } - - if chunks.len() == 1 { - return chunks.pop().expect("single chunk should exist"); - } - - let total = chunks.iter().map(Vec::len).sum(); - let mut result = Vec::with_capacity(total); - for chunk in chunks { - result.extend_from_slice(&chunk); - } - result -} - -fn lock_or_recover<'a, T>(mutex: &'a Mutex) -> MutexGuard<'a, T> { - match mutex.lock() { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -fn wait_or_recover<'a, T>(condvar: &Condvar, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { - match condvar.wait(guard) { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -fn wait_timeout_or_recover<'a, T>( - condvar: &Condvar, - guard: MutexGuard<'a, T>, - timeout: Duration, -) -> (MutexGuard<'a, T>, std::sync::WaitTimeoutResult) { - match condvar.wait_timeout(guard, timeout) { - Ok(result) => result, - Err(poisoned) => poisoned.into_inner(), - } -} diff --git a/crates/kernel/src/resource_accounting.rs b/crates/kernel/src/resource_accounting.rs deleted file mode 100644 index d189fd941..000000000 --- a/crates/kernel/src/resource_accounting.rs +++ /dev/null @@ -1,736 +0,0 @@ -use crate::fd_table::FdTableManager; -use crate::pipe_manager::PipeManager; -use crate::process_table::{ProcessStatus, ProcessTable}; -use crate::pty::PtyManager; -use crate::socket_table::{SocketState, SocketTable}; -use secure_exec_bridge::queue_tracker::{register_limit, QueueGauge, TrackedLimit}; -use std::collections::BTreeMap; -use std::error::Error; -use std::fmt; -use std::sync::Arc; -use vfs::posix::usage::RootFilesystemResourceLimits; - -pub use vfs::posix::usage::{ - measure_filesystem_usage, FileSystemUsage, DEFAULT_MAX_FILESYSTEM_BYTES, - DEFAULT_MAX_INODE_COUNT, -}; - -pub const DEFAULT_MAX_PROCESSES: usize = 256; -pub const DEFAULT_MAX_OPEN_FDS: usize = 256; -pub const DEFAULT_MAX_PIPES: usize = 128; -pub const DEFAULT_MAX_PTYS: usize = 128; -pub const DEFAULT_MAX_SOCKETS: usize = 256; -pub const DEFAULT_MAX_CONNECTIONS: usize = 256; -pub const DEFAULT_MAX_SOCKET_BUFFERED_BYTES: usize = 4 * 1024 * 1024; -pub const DEFAULT_MAX_SOCKET_DATAGRAM_QUEUE_LEN: usize = 1_024; -pub const DEFAULT_BLOCKING_READ_TIMEOUT_MS: u64 = 5_000; -pub const DEFAULT_MAX_PREAD_BYTES: usize = 64 * 1024 * 1024; -pub const DEFAULT_MAX_FD_WRITE_BYTES: usize = 64 * 1024 * 1024; -pub const DEFAULT_MAX_PROCESS_ARGV_BYTES: usize = 1024 * 1024; -pub const DEFAULT_MAX_PROCESS_ENV_BYTES: usize = 1024 * 1024; -pub const DEFAULT_MAX_READDIR_ENTRIES: usize = 4_096; -pub const DEFAULT_MAX_RECURSIVE_FS_DEPTH: usize = 128; -pub const DEFAULT_MAX_RECURSIVE_FS_ENTRIES: usize = 65_536; -pub const DEFAULT_VIRTUAL_CPU_COUNT: usize = 1; -pub const DEFAULT_MAX_WASM_MEMORY_BYTES: u64 = 128 * 1024 * 1024; - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct ResourceSnapshot { - pub running_processes: usize, - pub exited_processes: usize, - pub fd_tables: usize, - pub open_fds: usize, - pub pipes: usize, - pub pipe_buffered_bytes: usize, - pub ptys: usize, - pub pty_buffered_input_bytes: usize, - pub pty_buffered_output_bytes: usize, - pub sockets: usize, - pub socket_listeners: usize, - pub socket_connections: usize, - pub socket_buffered_bytes: usize, - pub socket_datagram_queue_len: usize, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ResourceLimits { - pub virtual_cpu_count: Option, - pub max_processes: Option, - pub max_open_fds: Option, - pub max_pipes: Option, - pub max_ptys: Option, - pub max_sockets: Option, - pub max_connections: Option, - pub max_socket_buffered_bytes: Option, - pub max_socket_datagram_queue_len: Option, - pub max_filesystem_bytes: Option, - pub max_inode_count: Option, - pub max_blocking_read_ms: Option, - pub max_pread_bytes: Option, - pub max_fd_write_bytes: Option, - pub max_process_argv_bytes: Option, - pub max_process_env_bytes: Option, - pub max_readdir_entries: Option, - pub max_recursive_fs_depth: Option, - pub max_recursive_fs_entries: Option, - pub max_wasm_fuel: Option, - pub max_wasm_memory_bytes: Option, - pub max_wasm_stack_bytes: Option, -} - -impl Default for ResourceLimits { - fn default() -> Self { - Self { - virtual_cpu_count: Some(DEFAULT_VIRTUAL_CPU_COUNT), - max_processes: Some(DEFAULT_MAX_PROCESSES), - max_open_fds: Some(DEFAULT_MAX_OPEN_FDS), - max_pipes: Some(DEFAULT_MAX_PIPES), - max_ptys: Some(DEFAULT_MAX_PTYS), - max_sockets: Some(DEFAULT_MAX_SOCKETS), - max_connections: Some(DEFAULT_MAX_CONNECTIONS), - max_socket_buffered_bytes: Some(DEFAULT_MAX_SOCKET_BUFFERED_BYTES), - max_socket_datagram_queue_len: Some(DEFAULT_MAX_SOCKET_DATAGRAM_QUEUE_LEN), - max_filesystem_bytes: Some(DEFAULT_MAX_FILESYSTEM_BYTES), - max_inode_count: Some(DEFAULT_MAX_INODE_COUNT), - max_blocking_read_ms: Some(DEFAULT_BLOCKING_READ_TIMEOUT_MS), - max_pread_bytes: Some(DEFAULT_MAX_PREAD_BYTES), - max_fd_write_bytes: Some(DEFAULT_MAX_FD_WRITE_BYTES), - max_process_argv_bytes: Some(DEFAULT_MAX_PROCESS_ARGV_BYTES), - max_process_env_bytes: Some(DEFAULT_MAX_PROCESS_ENV_BYTES), - max_readdir_entries: Some(DEFAULT_MAX_READDIR_ENTRIES), - max_recursive_fs_depth: Some(DEFAULT_MAX_RECURSIVE_FS_DEPTH), - max_recursive_fs_entries: Some(DEFAULT_MAX_RECURSIVE_FS_ENTRIES), - max_wasm_fuel: None, - // Match the Workers-style default memory envelope where sensible: - // guests are bounded unless the trusted VM config raises the cap. - max_wasm_memory_bytes: Some(DEFAULT_MAX_WASM_MEMORY_BYTES), - max_wasm_stack_bytes: None, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ResourceError { - code: &'static str, - message: String, -} - -impl RootFilesystemResourceLimits for ResourceLimits { - fn max_filesystem_bytes(&self) -> Option { - self.max_filesystem_bytes - } - - fn max_inode_count(&self) -> Option { - self.max_inode_count - } -} - -impl ResourceError { - pub fn code(&self) -> &'static str { - self.code - } - - fn exhausted(message: impl Into) -> Self { - Self { - code: "EAGAIN", - message: message.into(), - } - } - - fn file_table_full(message: impl Into) -> Self { - Self { - code: "ENFILE", - message: message.into(), - } - } - - fn filesystem_full(message: impl Into) -> Self { - Self { - code: "ENOSPC", - message: message.into(), - } - } - - fn invalid_input(message: impl Into) -> Self { - Self { - code: "EINVAL", - message: message.into(), - } - } - - fn out_of_memory(message: impl Into) -> Self { - Self { - code: "ENOMEM", - message: message.into(), - } - } -} - -impl fmt::Display for ResourceError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for ResourceError {} - -#[derive(Debug, Clone, Default)] -/// Per-VM gauges for the saturating resource limits, registered with the central -/// limit registry so their usage is inspectable and they emit an edge-triggered -/// approach warning (~80%) before the guest hits the hard cap. Only limits that -/// are actually set get a gauge; unbounded (`None`) limits are skipped. -struct ResourceGauges { - processes: Option>, - open_fds: Option>, - pipes: Option>, - ptys: Option>, - sockets: Option>, - connections: Option>, - socket_buffered_bytes: Option>, - socket_datagram_queue_len: Option>, - filesystem_bytes: Option>, - inodes: Option>, - recursive_fs_depth: Option>, - recursive_fs_entries: Option>, -} - -fn register_resource_gauge(name: TrackedLimit, limit: Option) -> Option> { - limit.map(|capacity| register_limit(name, capacity)) -} - -fn register_resource_gauge_u64(name: TrackedLimit, limit: Option) -> Option> { - limit.map(|capacity| register_limit(name, usize_saturating_from_u64(capacity))) -} - -fn usize_saturating_from_u64(value: u64) -> usize { - usize::try_from(value).unwrap_or(usize::MAX) -} - -impl ResourceGauges { - fn new(limits: &ResourceLimits) -> Self { - Self { - processes: register_resource_gauge(TrackedLimit::VmProcesses, limits.max_processes), - open_fds: register_resource_gauge(TrackedLimit::VmOpenFds, limits.max_open_fds), - pipes: register_resource_gauge(TrackedLimit::VmPipes, limits.max_pipes), - ptys: register_resource_gauge(TrackedLimit::VmPtys, limits.max_ptys), - sockets: register_resource_gauge(TrackedLimit::VmSockets, limits.max_sockets), - connections: register_resource_gauge( - TrackedLimit::VmConnections, - limits.max_connections, - ), - socket_buffered_bytes: register_resource_gauge( - TrackedLimit::VmSocketBufferedBytes, - limits.max_socket_buffered_bytes, - ), - socket_datagram_queue_len: register_resource_gauge( - TrackedLimit::VmSocketDatagramQueueLen, - limits.max_socket_datagram_queue_len, - ), - filesystem_bytes: register_resource_gauge_u64( - TrackedLimit::VmFilesystemBytes, - limits.max_filesystem_bytes, - ), - inodes: register_resource_gauge(TrackedLimit::VmInodes, limits.max_inode_count), - recursive_fs_depth: register_resource_gauge( - TrackedLimit::VmRecursiveFsDepth, - limits.max_recursive_fs_depth, - ), - recursive_fs_entries: register_resource_gauge( - TrackedLimit::VmRecursiveFsEntries, - limits.max_recursive_fs_entries, - ), - } - } -} - -pub struct ResourceAccountant { - limits: ResourceLimits, - gauges: ResourceGauges, -} - -impl ResourceAccountant { - pub fn new(limits: ResourceLimits) -> Self { - let gauges = ResourceGauges::new(&limits); - Self { limits, gauges } - } - - /// Sample the saturating-resource gauges from a fresh snapshot so the central - /// registry tracks usage and warns before any cap is reached. - fn observe_resource_gauges(&self, snapshot: &ResourceSnapshot) { - if let Some(gauge) = &self.gauges.processes { - gauge.observe_depth(snapshot.running_processes + snapshot.exited_processes); - } - if let Some(gauge) = &self.gauges.open_fds { - gauge.observe_depth(snapshot.open_fds); - } - if let Some(gauge) = &self.gauges.pipes { - gauge.observe_depth(snapshot.pipes); - } - if let Some(gauge) = &self.gauges.ptys { - gauge.observe_depth(snapshot.ptys); - } - if let Some(gauge) = &self.gauges.sockets { - gauge.observe_depth(snapshot.sockets); - } - if let Some(gauge) = &self.gauges.connections { - gauge.observe_depth(snapshot.socket_connections); - } - if let Some(gauge) = &self.gauges.socket_buffered_bytes { - gauge.observe_depth(snapshot.socket_buffered_bytes); - } - if let Some(gauge) = &self.gauges.socket_datagram_queue_len { - gauge.observe_depth(snapshot.socket_datagram_queue_len); - } - } - - pub fn limits(&self) -> &ResourceLimits { - &self.limits - } - - pub fn snapshot( - &self, - processes: &ProcessTable, - fd_tables: &FdTableManager, - pipes: &PipeManager, - ptys: &PtyManager, - sockets: &SocketTable, - ) -> ResourceSnapshot { - let process_list = processes.list_processes(); - let running_processes = process_list - .values() - .filter(|process| process.status == ProcessStatus::Running) - .count(); - let exited_processes = process_list - .values() - .filter(|process| process.status == ProcessStatus::Exited) - .count(); - let socket_snapshot = sockets.snapshot(); - - let snapshot = ResourceSnapshot { - running_processes, - exited_processes, - fd_tables: fd_tables.len(), - open_fds: fd_tables.total_open_fds(), - pipes: pipes.pipe_count(), - pipe_buffered_bytes: pipes.buffered_bytes(), - ptys: ptys.pty_count(), - pty_buffered_input_bytes: ptys.buffered_input_bytes(), - pty_buffered_output_bytes: ptys.buffered_output_bytes(), - sockets: socket_snapshot.sockets, - socket_listeners: socket_snapshot.listeners, - socket_connections: socket_snapshot.connections, - socket_buffered_bytes: socket_snapshot.buffered_bytes, - socket_datagram_queue_len: socket_snapshot.datagram_queue_len, - }; - self.observe_resource_gauges(&snapshot); - snapshot - } - - pub fn check_process_spawn( - &self, - snapshot: &ResourceSnapshot, - additional_fds: usize, - ) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_processes { - if snapshot.running_processes + snapshot.exited_processes >= limit { - return Err(ResourceError::exhausted("maximum process limit reached")); - } - } - - self.check_open_fds(snapshot, additional_fds) - } - - pub fn check_process_argv_bytes( - &self, - command: &str, - args: &[String], - ) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_process_argv_bytes { - let total = argv_payload_bytes(command, args); - if total > limit { - return Err(ResourceError::invalid_input(format!( - "process argv payload {total} bytes exceeds configured limit {limit}" - ))); - } - } - - Ok(()) - } - - pub fn check_process_env_bytes( - &self, - inherited_env: &BTreeMap, - overrides: &BTreeMap, - ) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_process_env_bytes { - let total = merged_env_payload_bytes(inherited_env, overrides); - if total > limit { - return Err(ResourceError::invalid_input(format!( - "process environment payload {total} bytes exceeds configured limit {limit}" - ))); - } - } - - Ok(()) - } - - pub fn check_pipe_allocation(&self, snapshot: &ResourceSnapshot) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_pipes { - if snapshot.pipes >= limit { - return Err(ResourceError::exhausted("maximum pipe count reached")); - } - } - - self.check_open_fds(snapshot, 2) - } - - pub fn check_pty_allocation(&self, snapshot: &ResourceSnapshot) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_ptys { - if snapshot.ptys >= limit { - return Err(ResourceError::exhausted("maximum PTY count reached")); - } - } - - self.check_open_fds(snapshot, 2) - } - - pub fn check_socket_allocation( - &self, - snapshot: &ResourceSnapshot, - ) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_sockets { - if snapshot.sockets >= limit { - return Err(ResourceError::exhausted("maximum socket count reached")); - } - } - - Ok(()) - } - - pub fn check_socket_state_transition( - &self, - snapshot: &ResourceSnapshot, - current: SocketState, - next: SocketState, - ) -> Result<(), ResourceError> { - if !current.counts_as_connection() && next.counts_as_connection() { - if let Some(limit) = self.limits.max_connections { - if snapshot.socket_connections >= limit { - return Err(ResourceError::exhausted("maximum connection count reached")); - } - } - } - - Ok(()) - } - - pub fn check_socket_buffer_growth( - &self, - snapshot: &ResourceSnapshot, - additional_bytes: usize, - ) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_socket_buffered_bytes { - if snapshot - .socket_buffered_bytes - .saturating_add(additional_bytes) - > limit - { - return Err(ResourceError::exhausted( - "maximum socket buffered byte limit reached", - )); - } - } - - Ok(()) - } - - pub fn check_socket_datagram_enqueue( - &self, - snapshot: &ResourceSnapshot, - additional_bytes: usize, - ) -> Result<(), ResourceError> { - self.check_socket_buffer_growth(snapshot, additional_bytes)?; - if let Some(limit) = self.limits.max_socket_datagram_queue_len { - if snapshot.socket_datagram_queue_len.saturating_add(1) > limit { - return Err(ResourceError::exhausted( - "maximum socket datagram queue length reached", - )); - } - } - - Ok(()) - } - - pub fn check_pread_length(&self, length: usize) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_pread_bytes { - if length > limit { - return Err(ResourceError::invalid_input(format!( - "pread length {length} exceeds configured limit {limit}" - ))); - } - } - - Ok(()) - } - - pub fn check_fd_write_size(&self, size: usize) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_fd_write_bytes { - if size > limit { - return Err(ResourceError::invalid_input(format!( - "write size {size} exceeds configured limit {limit}" - ))); - } - } - - Ok(()) - } - - pub fn check_fd_allocation( - &self, - snapshot: &ResourceSnapshot, - additional_fds: usize, - ) -> Result<(), ResourceError> { - self.check_open_fds(snapshot, additional_fds) - } - - pub fn max_readdir_entries(&self) -> Option { - self.limits.max_readdir_entries - } - - pub fn max_recursive_fs_depth(&self) -> Option { - self.limits.max_recursive_fs_depth - } - - pub fn max_recursive_fs_entries(&self) -> Option { - self.limits.max_recursive_fs_entries - } - - pub fn check_readdir_entries(&self, entries: usize) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_readdir_entries { - if entries > limit { - return Err(ResourceError::out_of_memory(format!( - "directory listing with {entries} entries exceeds configured limit {limit}" - ))); - } - } - - Ok(()) - } - - pub fn check_recursive_fs_depth(&self, depth: usize) -> Result<(), ResourceError> { - if let Some(gauge) = self.gauges.recursive_fs_depth.as_ref() { - gauge.observe_depth(depth); - } - if let Some(limit) = self.limits.max_recursive_fs_depth { - if depth > limit { - return Err(ResourceError::out_of_memory(format!( - "recursive filesystem operation depth {depth} exceeds configured limit {limit}" - ))); - } - } - - Ok(()) - } - - pub fn check_recursive_fs_entries(&self, entries: usize) -> Result<(), ResourceError> { - if let Some(gauge) = self.gauges.recursive_fs_entries.as_ref() { - gauge.observe_depth(entries); - } - if let Some(limit) = self.limits.max_recursive_fs_entries { - if entries > limit { - return Err(ResourceError::out_of_memory(format!( - "recursive filesystem operation with {entries} entries exceeds configured limit {limit}" - ))); - } - } - - Ok(()) - } - - fn check_open_fds( - &self, - snapshot: &ResourceSnapshot, - additional_fds: usize, - ) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_open_fds { - if snapshot.open_fds.saturating_add(additional_fds) > limit { - return Err(ResourceError::file_table_full( - "maximum open file descriptor limit reached", - )); - } - } - - Ok(()) - } - - pub fn check_filesystem_usage( - &self, - _usage: &FileSystemUsage, - resulting_bytes: u64, - resulting_inodes: usize, - ) -> Result<(), ResourceError> { - if let Some(limit) = self.limits.max_filesystem_bytes { - if resulting_bytes > limit { - return Err(ResourceError::filesystem_full( - "maximum filesystem size limit reached", - )); - } - } - - if let Some(limit) = self.limits.max_inode_count { - if resulting_inodes > limit { - return Err(ResourceError::filesystem_full( - "maximum inode count limit reached", - )); - } - } - - // Sample the gauges only on the success path: observing the *projected* - // value before the bounds check would latch a spurious near/at-capacity - // warning for a write that is then rejected and never actually applied. - if let Some(gauge) = &self.gauges.filesystem_bytes { - gauge.observe_depth(usize_saturating_from_u64(resulting_bytes)); - } - if let Some(gauge) = &self.gauges.inodes { - gauge.observe_depth(resulting_inodes); - } - Ok(()) - } -} - -fn argv_payload_bytes(command: &str, args: &[String]) -> usize { - let command_bytes = command.len().saturating_add(1); - command_bytes.saturating_add( - args.iter() - .map(|arg| arg.len().saturating_add(1)) - .sum::(), - ) -} - -fn env_entry_payload_bytes(key: &str, value: &str) -> usize { - key.len() - .saturating_add(1) - .saturating_add(value.len()) - .saturating_add(1) -} - -fn merged_env_payload_bytes( - inherited_env: &BTreeMap, - overrides: &BTreeMap, -) -> usize { - let mut total = inherited_env - .iter() - .map(|(key, value)| env_entry_payload_bytes(key, value)) - .sum::(); - - for (key, value) in overrides { - if let Some(previous) = inherited_env.get(key) { - total = total.saturating_sub(env_entry_payload_bytes(key, previous)); - } - total = total.saturating_add(env_entry_payload_bytes(key, value)); - } - - total -} - -#[cfg(test)] -mod gauge_tests { - use super::*; - use secure_exec_bridge::queue_tracker::{ - set_limit_warning_handler, LimitWarning, TrackedLimit, - }; - use std::sync::{Arc, Mutex}; - - #[test] - fn resource_gauges_track_usage_and_warn_on_approach() { - let captured: Arc>> = Arc::new(Mutex::new(Vec::new())); - let sink = Arc::clone(&captured); - // Filter by name so a gauge from a concurrently-running test can't pollute. - set_limit_warning_handler(Box::new(move |warning| { - if warning.name == TrackedLimit::VmOpenFds { - sink.lock().expect("sink mutex").push(warning.clone()); - } - })); - - let limits = ResourceLimits { - max_open_fds: Some(10), - ..ResourceLimits::default() - }; - let accountant = ResourceAccountant::new(limits); - let snapshot = ResourceSnapshot { - open_fds: 9, // 90% of the cap - ..ResourceSnapshot::default() - }; - accountant.observe_resource_gauges(&snapshot); - - // The gauge reflects the sampled usage... - let gauge = accountant - .gauges - .open_fds - .as_ref() - .expect("open_fds gauge registered when the limit is set"); - assert_eq!(gauge.depth(), 9); - assert_eq!(gauge.capacity(), 10); - assert_eq!(gauge.high_water(), 9); - - // ...and crossing ~80% emits the approach warning to the host sink. - assert!( - captured - .lock() - .unwrap() - .iter() - .any(|warning| warning.name == TrackedLimit::VmOpenFds), - "open_fds at 90% of cap must emit an approach warning" - ); - } - - #[test] - fn unset_limit_registers_no_gauge() { - let limits = ResourceLimits { - max_ptys: None, - ..ResourceLimits::default() - }; - let accountant = ResourceAccountant::new(limits); - assert!( - accountant.gauges.ptys.is_none(), - "an unbounded (None) limit must not register a gauge" - ); - } - - #[test] - fn filesystem_gauge_not_latched_by_rejected_write() { - let limits = ResourceLimits { - max_filesystem_bytes: Some(1000), - max_inode_count: Some(100), - ..ResourceLimits::default() - }; - let accountant = ResourceAccountant::new(limits); - let usage = FileSystemUsage::default(); - - // A write that would exceed the byte cap is rejected and must NOT latch - // the gauge to the projected (never-applied) value. - let rejected = accountant.check_filesystem_usage(&usage, 2000, 0); - assert!(rejected.is_err()); - let bytes_gauge = accountant - .gauges - .filesystem_bytes - .as_ref() - .expect("filesystem_bytes gauge registered"); - assert_eq!( - bytes_gauge.depth(), - 0, - "a rejected over-limit write must not bump the gauge" - ); - - // A successful write does update it. - accountant - .check_filesystem_usage(&usage, 500, 7) - .expect("under-limit write is accepted"); - assert_eq!(bytes_gauge.depth(), 500); - assert_eq!( - accountant.gauges.inodes.as_ref().unwrap().depth(), - 7, - "inode gauge tracks the accepted value" - ); - } -} diff --git a/crates/kernel/src/socket_table.rs b/crates/kernel/src/socket_table.rs deleted file mode 100644 index 6f958aca3..000000000 --- a/crates/kernel/src/socket_table.rs +++ /dev/null @@ -1,2395 +0,0 @@ -use crate::poll::{PollEvents, POLLERR, POLLHUP, POLLIN, POLLOUT}; -use crate::vfs::normalize_path; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::error::Error; -use std::fmt; -use std::net::{Ipv4Addr, Ipv6Addr}; -use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use std::sync::{Arc, Mutex, MutexGuard}; -use std::time::Instant; - -pub type SocketId = u64; -pub type SocketResult = Result; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SocketReadinessKind { - Data, - Accept, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct SocketReadiness { - pub socket_id: SocketId, - pub kind: SocketReadinessKind, -} - -type SocketReadinessSink = Arc; - -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] -pub struct SocketReadTraceSnapshot { - pub socket_record_clone_calls: u64, - pub socket_record_clone_us: u64, - pub read_recv_calls: u64, - pub read_recv_bytes: u64, - pub read_recv_chunks: u64, - pub read_recv_copy_us: u64, -} - -struct SocketReadTraceCounters { - socket_record_clone_calls: AtomicU64, - socket_record_clone_us: AtomicU64, - read_recv_calls: AtomicU64, - read_recv_bytes: AtomicU64, - read_recv_chunks: AtomicU64, - read_recv_copy_us: AtomicU64, -} - -impl SocketReadTraceCounters { - const fn new() -> Self { - Self { - socket_record_clone_calls: AtomicU64::new(0), - socket_record_clone_us: AtomicU64::new(0), - read_recv_calls: AtomicU64::new(0), - read_recv_bytes: AtomicU64::new(0), - read_recv_chunks: AtomicU64::new(0), - read_recv_copy_us: AtomicU64::new(0), - } - } -} - -static SOCKET_READ_TRACE_ENABLED: AtomicBool = AtomicBool::new(false); -static SOCKET_READ_TRACE_COUNTERS: SocketReadTraceCounters = SocketReadTraceCounters::new(); - -pub fn set_socket_read_trace_enabled(enabled: bool) { - SOCKET_READ_TRACE_ENABLED.store(enabled, Ordering::Relaxed); -} - -pub fn reset_socket_read_trace() { - for counter in [ - &SOCKET_READ_TRACE_COUNTERS.socket_record_clone_calls, - &SOCKET_READ_TRACE_COUNTERS.socket_record_clone_us, - &SOCKET_READ_TRACE_COUNTERS.read_recv_calls, - &SOCKET_READ_TRACE_COUNTERS.read_recv_bytes, - &SOCKET_READ_TRACE_COUNTERS.read_recv_chunks, - &SOCKET_READ_TRACE_COUNTERS.read_recv_copy_us, - ] { - counter.store(0, Ordering::Relaxed); - } -} - -pub fn socket_read_trace_snapshot() -> SocketReadTraceSnapshot { - SocketReadTraceSnapshot { - socket_record_clone_calls: SOCKET_READ_TRACE_COUNTERS - .socket_record_clone_calls - .load(Ordering::Relaxed), - socket_record_clone_us: SOCKET_READ_TRACE_COUNTERS - .socket_record_clone_us - .load(Ordering::Relaxed), - read_recv_calls: SOCKET_READ_TRACE_COUNTERS - .read_recv_calls - .load(Ordering::Relaxed), - read_recv_bytes: SOCKET_READ_TRACE_COUNTERS - .read_recv_bytes - .load(Ordering::Relaxed), - read_recv_chunks: SOCKET_READ_TRACE_COUNTERS - .read_recv_chunks - .load(Ordering::Relaxed), - read_recv_copy_us: SOCKET_READ_TRACE_COUNTERS - .read_recv_copy_us - .load(Ordering::Relaxed), - } -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct InetSocketAddress { - host: String, - port: u16, -} - -impl InetSocketAddress { - pub fn new(host: impl Into, port: u16) -> Self { - Self { - host: host.into(), - port, - } - } - - pub fn host(&self) -> &str { - &self.host - } - - pub const fn port(&self) -> u16 { - self.port - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum SocketDomain { - Inet, - Inet6, - Unix, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum SocketType { - Stream, - Datagram, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum SocketState { - Created, - Bound, - Listening, - Connected, -} - -impl SocketState { - pub const fn counts_as_listener(self) -> bool { - matches!(self, Self::Listening) - } - - pub const fn counts_as_connection(self) -> bool { - matches!(self, Self::Connected) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SocketShutdown { - Read, - Write, - Both, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DatagramSocketOption { - ReuseAddr, - ReusePort, - Broadcast, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct SocketSpec { - pub domain: SocketDomain, - pub socket_type: SocketType, -} - -impl SocketSpec { - pub const fn new(domain: SocketDomain, socket_type: SocketType) -> Self { - Self { - domain, - socket_type, - } - } - - pub const fn tcp() -> Self { - Self::new(SocketDomain::Inet, SocketType::Stream) - } - - pub const fn udp() -> Self { - Self::new(SocketDomain::Inet, SocketType::Datagram) - } - - pub const fn unix_stream() -> Self { - Self::new(SocketDomain::Unix, SocketType::Stream) - } - - pub const fn unix_datagram() -> Self { - Self::new(SocketDomain::Unix, SocketType::Datagram) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SocketRecord { - id: SocketId, - owner_pid: u32, - spec: SocketSpec, - state: SocketState, - local_address: Option, - peer_address: Option, - local_unix_path: Option, - peer_unix_path: Option, - listener_state: Option, - connection_state: Option, - datagram_state: Option, -} - -impl SocketRecord { - pub const fn id(&self) -> SocketId { - self.id - } - - pub const fn owner_pid(&self) -> u32 { - self.owner_pid - } - - pub const fn spec(&self) -> SocketSpec { - self.spec - } - - pub const fn state(&self) -> SocketState { - self.state - } - - pub fn local_address(&self) -> Option<&InetSocketAddress> { - self.local_address.as_ref() - } - - pub fn peer_address(&self) -> Option<&InetSocketAddress> { - self.peer_address.as_ref() - } - - pub fn local_unix_path(&self) -> Option<&str> { - self.local_unix_path.as_deref() - } - - pub fn peer_unix_path(&self) -> Option<&str> { - self.peer_unix_path.as_deref() - } - - pub fn listen_backlog(&self) -> Option { - self.listener_state.as_ref().map(|state| state.backlog) - } - - pub fn pending_accept_count(&self) -> usize { - self.listener_state - .as_ref() - .map(|state| state.pending_accepts.len()) - .unwrap_or(0) - } - - pub fn peer_socket_id(&self) -> Option { - self.connection_state - .as_ref() - .and_then(|state| state.peer_socket_id) - } - - pub fn buffered_read_bytes(&self) -> usize { - self.connection_state - .as_ref() - .map(ConnectionState::buffered_len) - .unwrap_or(0) - } - - pub fn read_shutdown(&self) -> bool { - self.connection_state - .as_ref() - .map(|state| state.read_shutdown) - .unwrap_or(false) - } - - pub fn write_shutdown(&self) -> bool { - self.connection_state - .as_ref() - .map(|state| state.write_shutdown) - .unwrap_or(false) - } - - pub fn peer_write_shutdown(&self) -> bool { - self.connection_state - .as_ref() - .map(|state| state.peer_write_shutdown) - .unwrap_or(false) - } - - pub fn queued_datagrams(&self) -> usize { - self.datagram_state - .as_ref() - .map(|state| state.recv_queue.len()) - .unwrap_or(0) - } - - pub fn queued_datagram_bytes(&self) -> usize { - self.datagram_state - .as_ref() - .map(|state| datagram_queue_bytes(&state.recv_queue)) - .unwrap_or(0) - } - - pub fn reuse_address(&self) -> bool { - self.datagram_state - .as_ref() - .map(|state| state.reuse_addr) - .unwrap_or(false) - } - - pub fn reuse_port(&self) -> bool { - self.datagram_state - .as_ref() - .map(|state| state.reuse_port) - .unwrap_or(false) - } - - pub fn broadcast_enabled(&self) -> bool { - self.datagram_state - .as_ref() - .map(|state| state.broadcast) - .unwrap_or(false) - } - - pub fn multicast_membership_count(&self) -> usize { - self.datagram_state - .as_ref() - .map(|state| state.multicast_memberships.len()) - .unwrap_or(0) - } - - pub fn has_multicast_membership(&self, membership: &SocketMulticastMembership) -> bool { - self.datagram_state - .as_ref() - .map(|state| state.multicast_memberships.contains(membership)) - .unwrap_or(false) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ReceivedDatagram { - source_address: Option, - payload: Vec, -} - -impl ReceivedDatagram { - pub fn source_address(&self) -> Option<&InetSocketAddress> { - self.source_address.as_ref() - } - - pub fn payload(&self) -> &[u8] { - &self.payload - } - - pub fn into_parts(self) -> (Option, Vec) { - (self.source_address, self.payload) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct SocketTableSnapshot { - pub sockets: usize, - pub listeners: usize, - pub connections: usize, - pub buffered_bytes: usize, - pub datagram_queue_len: usize, -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct SocketMulticastMembership { - group_address: String, - interface_address: Option, -} - -impl SocketMulticastMembership { - pub fn new(group_address: impl Into, interface_address: Option) -> Self { - Self { - group_address: group_address.into(), - interface_address, - } - } - - pub fn group_address(&self) -> &str { - &self.group_address - } - - pub fn interface_address(&self) -> Option<&str> { - self.interface_address.as_deref() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SocketTableError { - code: &'static str, - message: String, -} - -impl SocketTableError { - pub fn code(&self) -> &'static str { - self.code - } - - fn not_found(socket_id: SocketId) -> Self { - Self { - code: "ENOENT", - message: format!("no such socket {socket_id}"), - } - } - - fn invalid_argument(message: impl Into) -> Self { - Self { - code: "EINVAL", - message: message.into(), - } - } - - fn address_in_use(message: impl Into) -> Self { - Self { - code: "EADDRINUSE", - message: message.into(), - } - } - - fn address_not_available(message: impl Into) -> Self { - Self { - code: "EADDRNOTAVAIL", - message: message.into(), - } - } - - fn not_found_address(message: impl Into) -> Self { - Self { - code: "ECONNREFUSED", - message: message.into(), - } - } - - fn would_block(message: impl Into) -> Self { - Self { - code: "EAGAIN", - message: message.into(), - } - } - - fn not_connected(message: impl Into) -> Self { - Self { - code: "ENOTCONN", - message: message.into(), - } - } - - fn broken_pipe(message: impl Into) -> Self { - Self { - code: "EPIPE", - message: message.into(), - } - } -} - -impl fmt::Display for SocketTableError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for SocketTableError {} - -#[derive(Debug, Default)] -struct SocketTableState { - sockets: BTreeMap, - by_owner: BTreeMap>, - bound_inet_streams: BTreeMap, - bound_inet_datagrams: BTreeMap>, - bound_unix_streams: BTreeMap, - multicast_groups: BTreeMap>, - next_socket_id: SocketId, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct ListenerState { - backlog: usize, - pending_accepts: VecDeque, -} - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -struct ConnectionState { - peer_socket_id: Option, - recv_buffer: VecDeque>, - recv_buffer_len: usize, - read_shutdown: bool, - write_shutdown: bool, - peer_write_shutdown: bool, -} - -impl ConnectionState { - fn buffered_len(&self) -> usize { - self.recv_buffer_len - } - - fn has_buffered_data(&self) -> bool { - self.recv_buffer_len > 0 - } - - fn push_recv(&mut self, data: &[u8]) { - if data.is_empty() { - return; - } - self.recv_buffer.push_back(data.to_vec()); - self.recv_buffer_len = self.recv_buffer_len.saturating_add(data.len()); - } - - fn read_recv(&mut self, max_bytes: usize) -> Option> { - if max_bytes == 0 { - return Some(Vec::new()); - } - if self.recv_buffer_len == 0 { - return None; - } - - let read_len = self.recv_buffer_len.min(max_bytes); - self.recv_buffer_len -= read_len; - - let mut remaining = read_len; - let mut chunks = 0usize; - let trace_started = SOCKET_READ_TRACE_ENABLED - .load(Ordering::Relaxed) - .then(Instant::now); - let mut out = Vec::with_capacity(read_len); - while remaining > 0 { - let mut chunk = self.recv_buffer.pop_front()?; - chunks += 1; - if chunk.len() <= remaining { - remaining -= chunk.len(); - out.extend_from_slice(&chunk); - continue; - } - - let tail = chunk.split_off(remaining); - out.extend_from_slice(&chunk); - self.recv_buffer.push_front(tail); - remaining = 0; - } - if let Some(started) = trace_started { - SOCKET_READ_TRACE_COUNTERS - .read_recv_calls - .fetch_add(1, Ordering::Relaxed); - SOCKET_READ_TRACE_COUNTERS.read_recv_bytes.fetch_add( - u64::try_from(read_len).unwrap_or(u64::MAX), - Ordering::Relaxed, - ); - SOCKET_READ_TRACE_COUNTERS - .read_recv_chunks - .fetch_add(u64::try_from(chunks).unwrap_or(u64::MAX), Ordering::Relaxed); - SOCKET_READ_TRACE_COUNTERS.read_recv_copy_us.fetch_add( - u64::try_from(started.elapsed().as_micros()).unwrap_or(u64::MAX), - Ordering::Relaxed, - ); - } - Some(out) - } - - fn clear_recv(&mut self) { - self.recv_buffer.clear(); - self.recv_buffer_len = 0; - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct PendingConnection { - peer_address: Option, - peer_unix_path: Option, - accepted_socket_id: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -struct DatagramState { - recv_queue: VecDeque, - reuse_addr: bool, - reuse_port: bool, - broadcast: bool, - multicast_memberships: BTreeSet, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct QueuedDatagram { - source_address: Option, - payload: Vec, -} - -struct SocketTableInner { - state: Mutex, - readiness_sink: Mutex>, -} - -impl Default for SocketTableInner { - fn default() -> Self { - Self { - state: Mutex::new(SocketTableState::default()), - readiness_sink: Mutex::new(None), - } - } -} - -impl fmt::Debug for SocketTableInner { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SocketTableInner") - .field("state", &self.state) - .finish_non_exhaustive() - } -} - -#[derive(Debug, Clone, Default)] -pub struct SocketTable { - inner: Arc, -} - -impl SocketTable { - pub fn new() -> Self { - Self::default() - } - - pub fn set_readiness_sink(&self, sink: Option) - where - F: Fn(SocketReadiness) + Send + Sync + 'static, - { - let mut target = lock_or_recover(&self.inner.readiness_sink); - *target = sink.map(|sink| Arc::new(sink) as SocketReadinessSink); - } - - fn emit_readiness(&self, readiness: Option) { - let Some(readiness) = readiness else { - return; - }; - let sink = lock_or_recover(&self.inner.readiness_sink).clone(); - if let Some(sink) = sink { - sink(readiness); - } - } - - pub fn allocate(&self, owner_pid: u32, spec: SocketSpec) -> SocketRecord { - self.allocate_with_state(owner_pid, spec, SocketState::Created) - } - - pub fn allocate_with_state( - &self, - owner_pid: u32, - spec: SocketSpec, - state: SocketState, - ) -> SocketRecord { - let mut table = lock_or_recover(&self.inner.state); - let socket_id = next_socket_id(&mut table); - let record = SocketRecord { - id: socket_id, - owner_pid, - spec, - state, - local_address: None, - peer_address: None, - local_unix_path: None, - peer_unix_path: None, - listener_state: None, - connection_state: default_connection_state(spec, state), - datagram_state: default_datagram_state(spec), - }; - table.sockets.insert(socket_id, record.clone()); - table - .by_owner - .entry(owner_pid) - .or_default() - .insert(socket_id); - record - } - - pub fn get(&self, socket_id: SocketId) -> Option { - lock_or_recover(&self.inner.state) - .sockets - .get(&socket_id) - .cloned() - } - - pub fn records_for_owner(&self, owner_pid: u32) -> Vec { - let table = lock_or_recover(&self.inner.state); - let Some(socket_ids) = table.by_owner.get(&owner_pid) else { - return Vec::new(); - }; - socket_ids - .iter() - .filter_map(|socket_id| table.sockets.get(socket_id).cloned()) - .collect() - } - - pub fn update_state( - &self, - socket_id: SocketId, - new_state: SocketState, - ) -> SocketResult { - let mut table = lock_or_recover(&self.inner.state); - let record = table - .sockets - .get_mut(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - validate_state_transition(record.state, new_state)?; - record.state = new_state; - if new_state != SocketState::Listening { - record.listener_state = None; - } - if new_state == SocketState::Connected && supports_connection_lifecycle(record.spec) { - record - .connection_state - .get_or_insert_with(ConnectionState::default); - } else if new_state != SocketState::Connected { - record.connection_state = None; - } - Ok(record.clone()) - } - - pub fn bind_inet( - &self, - socket_id: SocketId, - address: InetSocketAddress, - ) -> SocketResult { - let mut address = normalize_inet_address(address); - let mut table = lock_or_recover(&self.inner.state); - let existing = table - .sockets - .get(&socket_id) - .cloned() - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - if !supports_inet_bind(existing.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {socket_id} is not an INET socket" - ))); - } - // POSIX bind(port=0) assigns a free ephemeral port (kernel-owned, so the - // converged browser path does not need a host port allocator). - if address.port() == 0 { - let port = assign_ephemeral_inet_port(&table, existing.spec, address.host())?; - address = normalize_inet_address(InetSocketAddress::new(address.host(), port)); - } - let conflicting_ids = - lookup_conflicting_bound_inet_socket_ids(&table, existing.spec, &address); - if has_incompatible_inet_bind_conflict(&table, &existing, &conflicting_ids) { - return Err(SocketTableError::address_in_use(format!( - "address {}:{} is already bound", - address.host(), - address.port() - ))); - } - let cloned = { - let record = table - .sockets - .get_mut(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - - match record.state { - SocketState::Created => {} - SocketState::Bound if record.local_address.as_ref() == Some(&address) => { - return Ok(record.clone()); - } - SocketState::Bound | SocketState::Listening | SocketState::Connected => { - return Err(SocketTableError::invalid_argument(format!( - "socket {socket_id} cannot bind in state {:?}", - record.state - ))); - } - } - - record.local_address = Some(address.clone()); - record.peer_address = None; - record.local_unix_path = None; - record.peer_unix_path = None; - record.listener_state = None; - record.connection_state = None; - record.state = SocketState::Bound; - record.clone() - }; - register_bound_inet_socket(&mut table, cloned.spec, address, socket_id); - Ok(cloned) - } - - pub fn set_datagram_socket_option( - &self, - socket_id: SocketId, - option: DatagramSocketOption, - enabled: bool, - ) -> SocketResult { - let mut table = lock_or_recover(&self.inner.state); - let record = table - .sockets - .get_mut(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let datagram_state = datagram_state_mut(record)?; - - match option { - DatagramSocketOption::ReuseAddr => datagram_state.reuse_addr = enabled, - DatagramSocketOption::ReusePort => datagram_state.reuse_port = enabled, - DatagramSocketOption::Broadcast => datagram_state.broadcast = enabled, - } - - Ok(record.clone()) - } - - pub fn add_multicast_membership( - &self, - socket_id: SocketId, - membership: SocketMulticastMembership, - ) -> SocketResult { - let mut table = lock_or_recover(&self.inner.state); - let normalized_membership = { - let record = table - .sockets - .get(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - validate_multicast_socket(record)?; - normalize_multicast_membership(record.spec, membership)? - }; - - let cloned = { - let record = table - .sockets - .get_mut(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let datagram_state = datagram_state_mut(record)?; - datagram_state - .multicast_memberships - .insert(normalized_membership.clone()); - record.clone() - }; - - table - .multicast_groups - .entry(normalized_membership) - .or_default() - .insert(socket_id); - Ok(cloned) - } - - pub fn drop_multicast_membership( - &self, - socket_id: SocketId, - membership: SocketMulticastMembership, - ) -> SocketResult { - let mut table = lock_or_recover(&self.inner.state); - let normalized_membership = { - let record = table - .sockets - .get(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - validate_multicast_socket(record)?; - normalize_multicast_membership(record.spec, membership)? - }; - - let cloned = { - let record = table - .sockets - .get_mut(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let datagram_state = datagram_state_mut(record)?; - if !datagram_state - .multicast_memberships - .remove(&normalized_membership) - { - return Err(SocketTableError::address_not_available(format!( - "socket {socket_id} has not joined multicast group {}", - normalized_membership.group_address() - ))); - } - record.clone() - }; - - if let Some(members) = table.multicast_groups.get_mut(&normalized_membership) { - members.remove(&socket_id); - if members.is_empty() { - table.multicast_groups.remove(&normalized_membership); - } - } - - Ok(cloned) - } - - pub fn bind_unix( - &self, - socket_id: SocketId, - path: impl Into, - ) -> SocketResult { - let path = normalize_unix_socket_path(path.into())?; - let mut table = lock_or_recover(&self.inner.state); - let existing = table - .sockets - .get(&socket_id) - .cloned() - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - if !supports_unix_stream_lifecycle(existing.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {socket_id} is not a Unix stream socket" - ))); - } - let existing_id = table.bound_unix_streams.get(&path).copied(); - let cloned = { - let record = table - .sockets - .get_mut(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - - if let Some(bound_socket_id) = existing_id { - if bound_socket_id != socket_id { - return Err(SocketTableError::address_in_use(format!( - "path {path} is already bound" - ))); - } - } - - match record.state { - SocketState::Created => {} - SocketState::Bound if record.local_unix_path.as_deref() == Some(path.as_str()) => { - return Ok(record.clone()); - } - SocketState::Bound | SocketState::Listening | SocketState::Connected => { - return Err(SocketTableError::invalid_argument(format!( - "socket {socket_id} cannot bind in state {:?}", - record.state - ))); - } - } - - record.local_address = None; - record.peer_address = None; - record.local_unix_path = Some(path.clone()); - record.peer_unix_path = None; - record.listener_state = None; - record.connection_state = None; - record.state = SocketState::Bound; - record.clone() - }; - table.bound_unix_streams.insert(path, socket_id); - Ok(cloned) - } - - pub fn listen(&self, socket_id: SocketId, backlog: usize) -> SocketResult { - if backlog == 0 { - return Err(SocketTableError::invalid_argument( - "listener backlog must be greater than zero", - )); - } - - let mut table = lock_or_recover(&self.inner.state); - let record = table - .sockets - .get_mut(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - - if !supports_listener_lifecycle(record.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {socket_id} is not a stream socket" - ))); - } - if record.state != SocketState::Bound || !has_bound_endpoint(record) { - return Err(SocketTableError::invalid_argument(format!( - "socket {socket_id} must be bound before listen" - ))); - } - - record.state = SocketState::Listening; - record.listener_state = Some(ListenerState { - backlog, - pending_accepts: VecDeque::new(), - }); - Ok(record.clone()) - } - - pub fn enqueue_incoming_tcp_connection( - &self, - listener_socket_id: SocketId, - peer_address: InetSocketAddress, - ) -> SocketResult<()> { - let readiness = { - let mut table = lock_or_recover(&self.inner.state); - let record = table - .sockets - .get_mut(&listener_socket_id) - .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?; - - if record.state != SocketState::Listening { - return Err(SocketTableError::invalid_argument(format!( - "socket {listener_socket_id} is not listening" - ))); - } - - let listener_state = record.listener_state.as_mut().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {listener_socket_id} has no listener state" - )) - })?; - - if listener_state.pending_accepts.len() >= listener_state.backlog { - return Err(SocketTableError::would_block(format!( - "listener {listener_socket_id} backlog is full" - ))); - } - - let was_empty = listener_state.pending_accepts.is_empty(); - listener_state.pending_accepts.push_back(PendingConnection { - peer_address: Some(peer_address), - peer_unix_path: None, - accepted_socket_id: None, - }); - was_empty.then_some(SocketReadiness { - socket_id: listener_socket_id, - kind: SocketReadinessKind::Accept, - }) - }; - self.emit_readiness(readiness); - Ok(()) - } - - pub fn accept(&self, listener_socket_id: SocketId) -> SocketResult { - let mut table = lock_or_recover(&self.inner.state); - let (owner_pid, spec, local_address, local_unix_path, pending) = { - let record = table - .sockets - .get_mut(&listener_socket_id) - .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?; - - if record.state != SocketState::Listening { - return Err(SocketTableError::invalid_argument(format!( - "socket {listener_socket_id} is not listening" - ))); - } - - let listener_state = record.listener_state.as_mut().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {listener_socket_id} has no listener state" - )) - })?; - let pending = listener_state.pending_accepts.pop_front().ok_or_else(|| { - SocketTableError::would_block(format!( - "listener {listener_socket_id} has no pending connections" - )) - })?; - - ( - record.owner_pid, - record.spec, - record.local_address.clone(), - record.local_unix_path.clone(), - pending, - ) - }; - - if let Some(accepted_socket_id) = pending.accepted_socket_id { - return table - .sockets - .get(&accepted_socket_id) - .cloned() - .ok_or_else(|| SocketTableError::not_found(accepted_socket_id)); - } - - let socket_id = next_socket_id(&mut table); - let record = SocketRecord { - id: socket_id, - owner_pid, - spec, - state: SocketState::Connected, - local_address, - peer_address: pending.peer_address, - local_unix_path, - peer_unix_path: pending.peer_unix_path, - listener_state: None, - connection_state: default_connection_state(spec, SocketState::Connected), - datagram_state: default_datagram_state(spec), - }; - table.sockets.insert(socket_id, record.clone()); - table - .by_owner - .entry(owner_pid) - .or_default() - .insert(socket_id); - Ok(record) - } - - pub fn connect_pair( - &self, - socket_id: SocketId, - peer_socket_id: SocketId, - ) -> SocketResult<(SocketRecord, SocketRecord)> { - if socket_id == peer_socket_id { - return Err(SocketTableError::invalid_argument( - "socket cannot connect to itself", - )); - } - - let mut table = lock_or_recover(&self.inner.state); - let mut socket = table - .sockets - .remove(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let Some(mut peer) = table.sockets.remove(&peer_socket_id) else { - table.sockets.insert(socket_id, socket); - return Err(SocketTableError::not_found(peer_socket_id)); - }; - - if let Err(error) = validate_connect_pair(&socket, &peer) { - table.sockets.insert(socket_id, socket); - table.sockets.insert(peer_socket_id, peer); - return Err(error); - } - - socket.state = SocketState::Connected; - socket.peer_address = peer.local_address.clone(); - socket.peer_unix_path = peer.local_unix_path.clone(); - socket.listener_state = None; - socket.connection_state = Some(ConnectionState { - peer_socket_id: Some(peer_socket_id), - ..ConnectionState::default() - }); - - peer.state = SocketState::Connected; - peer.peer_address = socket.local_address.clone(); - peer.peer_unix_path = socket.local_unix_path.clone(); - peer.listener_state = None; - peer.connection_state = Some(ConnectionState { - peer_socket_id: Some(socket_id), - ..ConnectionState::default() - }); - - let socket_clone = socket.clone(); - let peer_clone = peer.clone(); - table.sockets.insert(socket_id, socket); - table.sockets.insert(peer_socket_id, peer); - Ok((socket_clone, peer_clone)) - } - - pub fn find_bound_inet_socket( - &self, - spec: SocketSpec, - address: &InetSocketAddress, - ) -> Option { - let address = normalize_inet_address(address.clone()); - let table = lock_or_recover(&self.inner.state); - let socket_id = lookup_bound_inet_socket(&table, spec, &address)?; - table.sockets.get(&socket_id).cloned() - } - - pub fn connect_to_bound_inet_stream( - &self, - socket_id: SocketId, - target_address: InetSocketAddress, - ) -> SocketResult<()> { - let target_address = normalize_inet_address(target_address); - let (result, readiness) = { - let mut table = lock_or_recover(&self.inner.state); - let listener_socket_id = - lookup_bound_inet_socket_in_table(&table.bound_inet_streams, &target_address) - .ok_or_else(|| { - SocketTableError::not_found_address(format!( - "no listening socket bound at {}:{}", - target_address.host(), - target_address.port() - )) - })?; - - if socket_id == listener_socket_id { - return Err(SocketTableError::invalid_argument( - "socket cannot connect to its own listening endpoint", - )); - } - - let mut client = table - .sockets - .remove(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let mut accept_was_empty = false; - let result = (|| { - // Validate the listener and confirm backlog capacity BEFORE consuming a - // socket id. The id counter is monotonic (saturating_add) and never - // reclaims, so allocating an id before this check leaks one on every - // rejected connect (for example when the backlog is full). - { - let listener = table - .sockets - .get(&listener_socket_id) - .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?; - validate_connect_to_listener(&client, listener)?; - - let listener_state = listener.listener_state.as_ref().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {listener_socket_id} has no listener state" - )) - })?; - if listener_state.pending_accepts.len() >= listener_state.backlog { - return Err(SocketTableError::would_block(format!( - "listener {listener_socket_id} backlog is full" - ))); - } - } - - // Capacity confirmed: only now is it safe to consume a socket id. - let accepted_socket_id = next_socket_id(&mut table); - let listener = table - .sockets - .get_mut(&listener_socket_id) - .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?; - let listener_state = listener.listener_state.as_mut().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {listener_socket_id} has no listener state" - )) - })?; - - let accepted = SocketRecord { - id: accepted_socket_id, - owner_pid: listener.owner_pid, - spec: listener.spec, - state: SocketState::Connected, - local_address: listener.local_address.clone(), - peer_address: client.local_address.clone(), - local_unix_path: None, - peer_unix_path: None, - listener_state: None, - connection_state: Some(ConnectionState { - peer_socket_id: Some(socket_id), - ..ConnectionState::default() - }), - datagram_state: default_datagram_state(listener.spec), - }; - - accept_was_empty = listener_state.pending_accepts.is_empty(); - listener_state.pending_accepts.push_back(PendingConnection { - peer_address: client.local_address.clone(), - peer_unix_path: None, - accepted_socket_id: Some(accepted_socket_id), - }); - - client.state = SocketState::Connected; - client.peer_address = listener.local_address.clone(); - client.peer_unix_path = None; - client.listener_state = None; - client.connection_state = Some(ConnectionState { - peer_socket_id: Some(accepted_socket_id), - ..ConnectionState::default() - }); - - Ok(accepted) - })(); - - let result = match result { - Ok(accepted) => { - let accepted_socket_id = accepted.id; - table.sockets.insert(socket_id, client); - table.sockets.insert(accepted_socket_id, accepted.clone()); - table - .by_owner - .entry(accepted.owner_pid) - .or_default() - .insert(accepted_socket_id); - Ok(()) - } - Err(error) => { - table.sockets.insert(socket_id, client); - Err(error) - } - }; - let readiness = result.is_ok().then_some(()).and_then(|()| { - accept_was_empty.then_some(SocketReadiness { - socket_id: listener_socket_id, - kind: SocketReadinessKind::Accept, - }) - }); - (result, readiness) - }; - self.emit_readiness(readiness); - result - } - - pub fn find_bound_unix_socket(&self, path: &str) -> Option { - let path = normalize_unix_socket_path(path).ok()?; - let table = lock_or_recover(&self.inner.state); - let socket_id = table.bound_unix_streams.get(&path).copied()?; - table.sockets.get(&socket_id).cloned() - } - - pub fn connect_to_bound_unix_stream( - &self, - socket_id: SocketId, - target_path: impl Into, - ) -> SocketResult<()> { - let target_path = normalize_unix_socket_path(target_path.into())?; - let (result, readiness) = { - let mut table = lock_or_recover(&self.inner.state); - let listener_socket_id = table - .bound_unix_streams - .get(&target_path) - .copied() - .ok_or_else(|| { - SocketTableError::not_found_address(format!( - "no listening socket bound at path {target_path}" - )) - })?; - - if socket_id == listener_socket_id { - return Err(SocketTableError::invalid_argument( - "socket cannot connect to its own listening endpoint", - )); - } - - let mut client = table - .sockets - .remove(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let mut accept_was_empty = false; - let result = (|| { - // Validate the listener and confirm backlog capacity BEFORE consuming a - // socket id. The id counter is monotonic (saturating_add) and never - // reclaims, so allocating an id before this check leaks one on every - // rejected connect (for example when the backlog is full). - { - let listener = table - .sockets - .get(&listener_socket_id) - .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?; - validate_connect_to_listener(&client, listener)?; - - let listener_state = listener.listener_state.as_ref().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {listener_socket_id} has no listener state" - )) - })?; - if listener_state.pending_accepts.len() >= listener_state.backlog { - return Err(SocketTableError::would_block(format!( - "listener {listener_socket_id} backlog is full" - ))); - } - } - - // Capacity confirmed: only now is it safe to consume a socket id. - let accepted_socket_id = next_socket_id(&mut table); - let listener = table - .sockets - .get_mut(&listener_socket_id) - .ok_or_else(|| SocketTableError::not_found(listener_socket_id))?; - let listener_state = listener.listener_state.as_mut().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {listener_socket_id} has no listener state" - )) - })?; - - let accepted = SocketRecord { - id: accepted_socket_id, - owner_pid: listener.owner_pid, - spec: listener.spec, - state: SocketState::Connected, - local_address: None, - peer_address: None, - local_unix_path: listener.local_unix_path.clone(), - peer_unix_path: client.local_unix_path.clone(), - listener_state: None, - connection_state: Some(ConnectionState { - peer_socket_id: Some(socket_id), - ..ConnectionState::default() - }), - datagram_state: default_datagram_state(listener.spec), - }; - - accept_was_empty = listener_state.pending_accepts.is_empty(); - listener_state.pending_accepts.push_back(PendingConnection { - peer_address: None, - peer_unix_path: client.local_unix_path.clone(), - accepted_socket_id: Some(accepted_socket_id), - }); - - client.state = SocketState::Connected; - client.peer_address = None; - client.peer_unix_path = listener.local_unix_path.clone(); - client.listener_state = None; - client.connection_state = Some(ConnectionState { - peer_socket_id: Some(accepted_socket_id), - ..ConnectionState::default() - }); - - Ok(accepted) - })(); - - let result = match result { - Ok(accepted) => { - let accepted_socket_id = accepted.id; - table.sockets.insert(socket_id, client); - table.sockets.insert(accepted_socket_id, accepted.clone()); - table - .by_owner - .entry(accepted.owner_pid) - .or_default() - .insert(accepted_socket_id); - Ok(()) - } - Err(error) => { - table.sockets.insert(socket_id, client); - Err(error) - } - }; - let readiness = result.is_ok().then_some(()).and_then(|()| { - accept_was_empty.then_some(SocketReadiness { - socket_id: listener_socket_id, - kind: SocketReadinessKind::Accept, - }) - }); - (result, readiness) - }; - self.emit_readiness(readiness); - result - } - - pub fn send_to_bound_udp_socket( - &self, - socket_id: SocketId, - target_address: InetSocketAddress, - data: &[u8], - ) -> SocketResult { - let target_address = normalize_inet_address(target_address); - let readiness = { - let mut table = lock_or_recover(&self.inner.state); - let sender = table - .sockets - .get(&socket_id) - .cloned() - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - validate_bound_udp_sender(&sender)?; - - let receiver_socket_id = lookup_bound_inet_datagram_socket_in_table( - &table.bound_inet_datagrams, - &target_address, - ) - .ok_or_else(|| { - SocketTableError::not_found_address(format!( - "no UDP socket bound at {}:{}", - target_address.host(), - target_address.port() - )) - })?; - let receiver = table - .sockets - .get_mut(&receiver_socket_id) - .ok_or_else(|| SocketTableError::not_found(receiver_socket_id))?; - validate_bound_udp_receiver(receiver)?; - - let datagram_state = receiver.datagram_state.as_mut().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {receiver_socket_id} does not support datagrams" - )) - })?; - let was_empty = datagram_state.recv_queue.is_empty(); - datagram_state.recv_queue.push_back(QueuedDatagram { - source_address: sender.local_address.clone(), - payload: data.to_vec(), - }); - was_empty.then_some(SocketReadiness { - socket_id: receiver_socket_id, - kind: SocketReadinessKind::Data, - }) - }; - self.emit_readiness(readiness); - Ok(data.len()) - } - - pub fn check_send_to_bound_udp_socket( - &self, - socket_id: SocketId, - target_address: InetSocketAddress, - ) -> SocketResult<()> { - let target_address = normalize_inet_address(target_address); - let table = lock_or_recover(&self.inner.state); - let sender = table - .sockets - .get(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - validate_bound_udp_sender(sender)?; - - let receiver_socket_id = lookup_bound_inet_datagram_socket_in_table( - &table.bound_inet_datagrams, - &target_address, - ) - .ok_or_else(|| { - SocketTableError::not_found_address(format!( - "no UDP socket bound at {}:{}", - target_address.host(), - target_address.port() - )) - })?; - let receiver = table - .sockets - .get(&receiver_socket_id) - .ok_or_else(|| SocketTableError::not_found(receiver_socket_id))?; - validate_bound_udp_receiver(receiver)?; - Ok(()) - } - - pub fn recv_datagram( - &self, - socket_id: SocketId, - max_bytes: usize, - ) -> SocketResult> { - let mut table = lock_or_recover(&self.inner.state); - let record = table - .sockets - .get_mut(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - validate_bound_udp_receiver(record)?; - - let datagram_state = record.datagram_state.as_mut().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {socket_id} does not support datagrams" - )) - })?; - let Some(datagram) = datagram_state.recv_queue.pop_front() else { - return Err(SocketTableError::would_block(format!( - "socket {socket_id} has no queued datagrams" - ))); - }; - - let payload = if datagram.payload.len() > max_bytes { - datagram.payload[..max_bytes].to_vec() - } else { - datagram.payload - }; - Ok(Some(ReceivedDatagram { - source_address: datagram.source_address, - payload, - })) - } - - pub fn poll(&self, socket_id: SocketId, requested: PollEvents) -> SocketResult { - let table = lock_or_recover(&self.inner.state); - let record = table - .sockets - .get(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - - let mut events = PollEvents::empty(); - match record.state { - SocketState::Listening => { - if requested.intersects(POLLIN) && record.pending_accept_count() > 0 { - events |= POLLIN; - } - } - SocketState::Connected => { - let connection = record.connection_state.as_ref().ok_or_else(|| { - SocketTableError::not_connected(format!("socket {socket_id} is not connected")) - })?; - let peer = connection - .peer_socket_id - .and_then(|peer_socket_id| table.sockets.get(&peer_socket_id)); - - if requested.intersects(POLLIN) && connection.has_buffered_data() { - events |= POLLIN; - } - if connection.peer_write_shutdown || peer.is_none() { - events |= POLLHUP; - } - - if requested.intersects(POLLOUT) && !connection.write_shutdown { - if peer - .and_then(|peer| peer.connection_state.as_ref()) - .map(|peer_connection| peer_connection.read_shutdown) - .unwrap_or(true) - { - events |= POLLERR; - } else { - events |= POLLOUT; - } - } - } - SocketState::Bound if supports_inet_datagram_lifecycle(record.spec) => { - let datagram_state = record.datagram_state.as_ref().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {socket_id} does not support datagrams" - )) - })?; - if requested.intersects(POLLIN) && !datagram_state.recv_queue.is_empty() { - events |= POLLIN; - } - if requested.intersects(POLLOUT) { - events |= POLLOUT; - } - } - SocketState::Created | SocketState::Bound => {} - } - - Ok(events) - } - - pub fn write(&self, socket_id: SocketId, data: &[u8]) -> SocketResult { - let readiness = { - let mut table = lock_or_recover(&self.inner.state); - let record = table - .sockets - .get(&socket_id) - .cloned() - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let connection = record.connection_state.as_ref().ok_or_else(|| { - SocketTableError::not_connected(format!("socket {socket_id} is not connected")) - })?; - if record.state != SocketState::Connected { - return Err(SocketTableError::not_connected(format!( - "socket {socket_id} is not connected" - ))); - } - if connection.write_shutdown { - return Err(SocketTableError::broken_pipe(format!( - "socket {socket_id} write side is shut down" - ))); - } - - let peer_socket_id = connection.peer_socket_id.ok_or_else(|| { - SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed")) - })?; - let peer = table.sockets.get_mut(&peer_socket_id).ok_or_else(|| { - SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed")) - })?; - let peer_connection = peer.connection_state.as_mut().ok_or_else(|| { - SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed")) - })?; - if peer_connection.read_shutdown { - return Err(SocketTableError::broken_pipe(format!( - "socket {peer_socket_id} read side is shut down" - ))); - } - - let was_empty = !peer_connection.has_buffered_data(); - peer_connection.push_recv(data); - (was_empty && !data.is_empty()).then_some(SocketReadiness { - socket_id: peer_socket_id, - kind: SocketReadinessKind::Data, - }) - }; - self.emit_readiness(readiness); - Ok(data.len()) - } - - pub fn check_write(&self, socket_id: SocketId) -> SocketResult<()> { - let table = lock_or_recover(&self.inner.state); - let record = table - .sockets - .get(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let connection = record.connection_state.as_ref().ok_or_else(|| { - SocketTableError::not_connected(format!("socket {socket_id} is not connected")) - })?; - if record.state != SocketState::Connected { - return Err(SocketTableError::not_connected(format!( - "socket {socket_id} is not connected" - ))); - } - if connection.write_shutdown { - return Err(SocketTableError::broken_pipe(format!( - "socket {socket_id} write side is shut down" - ))); - } - - let peer_socket_id = connection.peer_socket_id.ok_or_else(|| { - SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed")) - })?; - let peer = table.sockets.get(&peer_socket_id).ok_or_else(|| { - SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed")) - })?; - let peer_connection = peer.connection_state.as_ref().ok_or_else(|| { - SocketTableError::broken_pipe(format!("socket {socket_id} peer is closed")) - })?; - if peer_connection.read_shutdown { - return Err(SocketTableError::broken_pipe(format!( - "socket {peer_socket_id} read side is shut down" - ))); - } - - Ok(()) - } - - pub fn read(&self, socket_id: SocketId, max_bytes: usize) -> SocketResult>> { - if max_bytes == 0 { - return Ok(Some(Vec::new())); - } - - let mut table = lock_or_recover(&self.inner.state); - let record_ref = table - .sockets - .get(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let clone_started = SOCKET_READ_TRACE_ENABLED - .load(Ordering::Relaxed) - .then(Instant::now); - let record = record_ref.clone(); - if let Some(started) = clone_started { - SOCKET_READ_TRACE_COUNTERS - .socket_record_clone_calls - .fetch_add(1, Ordering::Relaxed); - SOCKET_READ_TRACE_COUNTERS.socket_record_clone_us.fetch_add( - u64::try_from(started.elapsed().as_micros()).unwrap_or(u64::MAX), - Ordering::Relaxed, - ); - } - if record.state != SocketState::Connected { - return Err(SocketTableError::not_connected(format!( - "socket {socket_id} is not connected" - ))); - } - - let connection = record.connection_state.as_ref().ok_or_else(|| { - SocketTableError::not_connected(format!("socket {socket_id} is not connected")) - })?; - if connection.read_shutdown { - return Ok(None); - } - if connection.has_buffered_data() { - let record = table - .sockets - .get_mut(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - let connection = record.connection_state.as_mut().ok_or_else(|| { - SocketTableError::not_connected(format!("socket {socket_id} is not connected")) - })?; - return Ok(connection.read_recv(max_bytes)); - } - - let peer_open = connection - .peer_socket_id - .map(|peer_socket_id| table.sockets.contains_key(&peer_socket_id)) - .unwrap_or(false); - if connection.peer_write_shutdown || !peer_open { - return Ok(None); - } - - Err(SocketTableError::would_block(format!( - "socket {socket_id} has no readable data" - ))) - } - - pub fn shutdown(&self, socket_id: SocketId, how: SocketShutdown) -> SocketResult { - let mut table = lock_or_recover(&self.inner.state); - let record = table - .sockets - .remove(&socket_id) - .ok_or_else(|| SocketTableError::not_found(socket_id))?; - - if record.state != SocketState::Connected { - table.sockets.insert(socket_id, record); - return Err(SocketTableError::not_connected(format!( - "socket {socket_id} is not connected" - ))); - } - - let Some(mut connection) = record.connection_state.clone() else { - table.sockets.insert(socket_id, record); - return Err(SocketTableError::not_connected(format!( - "socket {socket_id} is not connected" - ))); - }; - - if matches!(how, SocketShutdown::Read | SocketShutdown::Both) { - connection.clear_recv(); - connection.read_shutdown = true; - } - if matches!(how, SocketShutdown::Write | SocketShutdown::Both) { - connection.write_shutdown = true; - if let Some(peer_socket_id) = connection.peer_socket_id { - if let Some(peer) = table.sockets.get_mut(&peer_socket_id) { - if let Some(peer_connection) = peer.connection_state.as_mut() { - peer_connection.peer_write_shutdown = true; - } - } - } - } - - let mut record = record; - record.connection_state = Some(connection); - let cloned = record.clone(); - table.sockets.insert(socket_id, record); - Ok(cloned) - } - - pub fn remove(&self, socket_id: SocketId) -> SocketResult { - let mut table = lock_or_recover(&self.inner.state); - remove_socket(&mut table, socket_id).ok_or_else(|| SocketTableError::not_found(socket_id)) - } - - pub fn remove_all_for_pid(&self, owner_pid: u32) -> Vec { - let mut table = lock_or_recover(&self.inner.state); - let Some(socket_ids) = table.by_owner.remove(&owner_pid) else { - return Vec::new(); - }; - - socket_ids - .into_iter() - .filter_map(|socket_id| remove_socket(&mut table, socket_id)) - .collect() - } - - pub fn snapshot(&self) -> SocketTableSnapshot { - let table = lock_or_recover(&self.inner.state); - let mut snapshot = SocketTableSnapshot { - sockets: table.sockets.len(), - ..SocketTableSnapshot::default() - }; - for record in table.sockets.values() { - if record.state.counts_as_listener() { - snapshot.listeners += 1; - } - if record.state.counts_as_connection() { - snapshot.connections += 1; - } - if let Some(connection) = &record.connection_state { - snapshot.buffered_bytes = snapshot - .buffered_bytes - .saturating_add(connection.buffered_len()); - } - if let Some(datagram_state) = &record.datagram_state { - snapshot.datagram_queue_len = snapshot - .datagram_queue_len - .saturating_add(datagram_state.recv_queue.len()); - snapshot.buffered_bytes = snapshot - .buffered_bytes - .saturating_add(datagram_queue_bytes(&datagram_state.recv_queue)); - } - } - snapshot - } -} - -fn datagram_queue_bytes(queue: &VecDeque) -> usize { - queue - .iter() - .map(|datagram| datagram.payload.len()) - .sum::() -} - -fn next_socket_id(table: &mut SocketTableState) -> SocketId { - if table.next_socket_id == 0 { - table.next_socket_id = 1; - } - let socket_id = table.next_socket_id; - table.next_socket_id = table.next_socket_id.saturating_add(1); - socket_id -} - -fn validate_state_transition(current: SocketState, next: SocketState) -> SocketResult<()> { - if current == SocketState::Connected && next != SocketState::Connected { - return Err(SocketTableError::invalid_argument(format!( - "invalid socket state transition from {current:?} to {next:?}" - ))); - } - Ok(()) -} - -fn validate_connect_pair(socket: &SocketRecord, peer: &SocketRecord) -> SocketResult<()> { - if !supports_connection_lifecycle(socket.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} does not support stream connections", - socket.id - ))); - } - if !supports_connection_lifecycle(peer.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} does not support stream connections", - peer.id - ))); - } - if !matches!(socket.state, SocketState::Created | SocketState::Bound) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} cannot connect in state {:?}", - socket.id, socket.state - ))); - } - if !matches!(peer.state, SocketState::Created | SocketState::Bound) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} cannot connect in state {:?}", - peer.id, peer.state - ))); - } - Ok(()) -} - -fn default_connection_state(spec: SocketSpec, state: SocketState) -> Option { - if state == SocketState::Connected && supports_connection_lifecycle(spec) { - Some(ConnectionState::default()) - } else { - None - } -} - -fn default_datagram_state(spec: SocketSpec) -> Option { - if supports_inet_datagram_lifecycle(spec) { - Some(DatagramState::default()) - } else { - None - } -} - -fn supports_connection_lifecycle(spec: SocketSpec) -> bool { - matches!(spec.socket_type, SocketType::Stream) -} - -fn supports_listener_lifecycle(spec: SocketSpec) -> bool { - matches!(spec.socket_type, SocketType::Stream) - && matches!( - spec.domain, - SocketDomain::Inet | SocketDomain::Inet6 | SocketDomain::Unix - ) -} - -fn supports_inet_bind(spec: SocketSpec) -> bool { - matches!(spec.domain, SocketDomain::Inet | SocketDomain::Inet6) - && matches!(spec.socket_type, SocketType::Stream | SocketType::Datagram) -} - -fn supports_unix_stream_lifecycle(spec: SocketSpec) -> bool { - matches!(spec.socket_type, SocketType::Stream) && matches!(spec.domain, SocketDomain::Unix) -} - -fn supports_inet_stream_lifecycle(spec: SocketSpec) -> bool { - matches!(spec.socket_type, SocketType::Stream) - && matches!(spec.domain, SocketDomain::Inet | SocketDomain::Inet6) -} - -fn supports_inet_datagram_lifecycle(spec: SocketSpec) -> bool { - matches!(spec.socket_type, SocketType::Datagram) - && matches!(spec.domain, SocketDomain::Inet | SocketDomain::Inet6) -} - -/// Pick a free ephemeral port for `bind(port=0)`, scanning the IANA dynamic -/// range and skipping any already in conflict for `spec`/`host`. -fn assign_ephemeral_inet_port( - table: &SocketTableState, - spec: SocketSpec, - host: &str, -) -> SocketResult { - const EPHEMERAL_START: u16 = 49152; - const EPHEMERAL_END: u16 = 65535; - for port in EPHEMERAL_START..=EPHEMERAL_END { - let candidate = normalize_inet_address(InetSocketAddress::new(host, port)); - if lookup_conflicting_bound_inet_socket_ids(table, spec, &candidate).is_empty() { - return Ok(port); - } - } - Err(SocketTableError::address_in_use( - "no free ephemeral port available", - )) -} - -fn lookup_conflicting_bound_inet_socket_ids( - table: &SocketTableState, - spec: SocketSpec, - address: &InetSocketAddress, -) -> Vec { - if supports_inet_stream_lifecycle(spec) { - table - .bound_inet_streams - .iter() - .find_map(|(bound_address, socket_id)| { - inet_stream_bind_addresses_overlap(bound_address, address).then_some(*socket_id) - }) - .into_iter() - .collect() - } else if supports_inet_datagram_lifecycle(spec) { - table - .bound_inet_datagrams - .iter() - .filter(|(bound_address, _)| inet_stream_bind_addresses_overlap(bound_address, address)) - .flat_map(|(_, socket_ids)| socket_ids.iter().copied()) - .collect() - } else { - Vec::new() - } -} - -fn lookup_bound_inet_socket( - table: &SocketTableState, - spec: SocketSpec, - address: &InetSocketAddress, -) -> Option { - if supports_inet_stream_lifecycle(spec) { - lookup_bound_inet_socket_in_table(&table.bound_inet_streams, address) - } else if supports_inet_datagram_lifecycle(spec) { - lookup_bound_inet_datagram_socket_in_table(&table.bound_inet_datagrams, address) - } else { - None - } -} - -fn inet_stream_bind_addresses_overlap( - existing: &InetSocketAddress, - requested: &InetSocketAddress, -) -> bool { - if existing == requested { - return true; - } - - wildcard_inet_address(existing).as_ref() == Some(requested) - || wildcard_inet_address(requested).as_ref() == Some(existing) -} - -fn lookup_bound_inet_socket_in_table( - sockets: &BTreeMap, - address: &InetSocketAddress, -) -> Option { - sockets.get(address).copied().or_else(|| { - wildcard_inet_address(address).and_then(|wildcard| sockets.get(&wildcard).copied()) - }) -} - -fn lookup_bound_inet_datagram_socket_in_table( - sockets: &BTreeMap>, - address: &InetSocketAddress, -) -> Option { - sockets - .get(address) - .and_then(|socket_ids| socket_ids.first().copied()) - .or_else(|| { - wildcard_inet_address(address).and_then(|wildcard| { - sockets - .get(&wildcard) - .and_then(|socket_ids| socket_ids.first().copied()) - }) - }) -} - -fn register_bound_inet_socket( - table: &mut SocketTableState, - spec: SocketSpec, - address: InetSocketAddress, - socket_id: SocketId, -) { - if supports_inet_stream_lifecycle(spec) { - table.bound_inet_streams.insert(address, socket_id); - } else if supports_inet_datagram_lifecycle(spec) { - table - .bound_inet_datagrams - .entry(address) - .or_default() - .insert(socket_id); - } -} - -fn validate_connect_to_listener( - client: &SocketRecord, - listener: &SocketRecord, -) -> SocketResult<()> { - if !supports_connection_lifecycle(client.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} does not support stream connections", - client.id - ))); - } - if !supports_listener_lifecycle(listener.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} is not a stream listener", - listener.id - ))); - } - if !matches!(client.state, SocketState::Created | SocketState::Bound) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} cannot connect in state {:?}", - client.id, client.state - ))); - } - if listener.state != SocketState::Listening { - return Err(SocketTableError::invalid_argument(format!( - "socket {} is not listening", - listener.id - ))); - } - Ok(()) -} - -fn has_bound_endpoint(record: &SocketRecord) -> bool { - record.local_address.is_some() || record.local_unix_path.is_some() -} - -fn validate_bound_udp_sender(sender: &SocketRecord) -> SocketResult<()> { - if !supports_inet_datagram_lifecycle(sender.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} is not an INET datagram socket", - sender.id - ))); - } - if sender.state != SocketState::Bound || sender.local_address.is_none() { - return Err(SocketTableError::invalid_argument(format!( - "socket {} must be bound before sending datagrams", - sender.id - ))); - } - Ok(()) -} - -fn validate_bound_udp_receiver(receiver: &SocketRecord) -> SocketResult<()> { - if !supports_inet_datagram_lifecycle(receiver.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} is not an INET datagram socket", - receiver.id - ))); - } - if receiver.state != SocketState::Bound || receiver.local_address.is_none() { - return Err(SocketTableError::invalid_argument(format!( - "socket {} must be bound to receive datagrams", - receiver.id - ))); - } - Ok(()) -} - -fn datagram_state_mut(record: &mut SocketRecord) -> SocketResult<&mut DatagramState> { - if !supports_inet_datagram_lifecycle(record.spec) { - return Err(SocketTableError::invalid_argument(format!( - "socket {} is not an INET datagram socket", - record.id - ))); - } - record.datagram_state.as_mut().ok_or_else(|| { - SocketTableError::invalid_argument(format!( - "socket {} does not support datagrams", - record.id - )) - }) -} - -fn validate_multicast_socket(record: &SocketRecord) -> SocketResult<()> { - validate_bound_udp_receiver(record)?; - if record.spec.domain != SocketDomain::Inet { - return Err(SocketTableError::invalid_argument(format!( - "socket {} multicast membership is only implemented for IPv4 datagrams", - record.id - ))); - } - Ok(()) -} - -fn normalize_multicast_membership( - spec: SocketSpec, - membership: SocketMulticastMembership, -) -> SocketResult { - let group_address = membership.group_address.trim().to_ascii_lowercase(); - let interface_address = membership - .interface_address - .map(|value| value.trim().to_ascii_lowercase()) - .filter(|value| !value.is_empty()); - - match spec.domain { - SocketDomain::Inet => { - let parsed = group_address.parse::().map_err(|_| { - SocketTableError::invalid_argument(format!( - "invalid IPv4 multicast address {group_address}" - )) - })?; - if !parsed.is_multicast() { - return Err(SocketTableError::invalid_argument(format!( - "address {group_address} is not an IPv4 multicast group" - ))); - } - } - SocketDomain::Inet6 => { - let parsed = group_address.parse::().map_err(|_| { - SocketTableError::invalid_argument(format!( - "invalid IPv6 multicast address {group_address}" - )) - })?; - if !parsed.is_multicast() { - return Err(SocketTableError::invalid_argument(format!( - "address {group_address} is not an IPv6 multicast group" - ))); - } - } - SocketDomain::Unix => { - return Err(SocketTableError::invalid_argument( - "unix sockets do not support multicast membership", - )); - } - } - - Ok(SocketMulticastMembership::new( - group_address, - interface_address, - )) -} - -fn has_incompatible_inet_bind_conflict( - table: &SocketTableState, - record: &SocketRecord, - conflicting_ids: &[SocketId], -) -> bool { - conflicting_ids.iter().any(|conflicting_id| { - if *conflicting_id == record.id { - return false; - } - - let Some(existing) = table.sockets.get(conflicting_id) else { - return false; - }; - - if supports_inet_datagram_lifecycle(record.spec) { - !inet_datagram_bind_shares_port(record, existing) - } else { - true - } - }) -} - -fn inet_datagram_bind_shares_port(requested: &SocketRecord, existing: &SocketRecord) -> bool { - (requested.reuse_port() && existing.reuse_port()) - || (requested.reuse_address() && existing.reuse_address()) -} - -fn remove_socket(table: &mut SocketTableState, socket_id: SocketId) -> Option { - let record = table.sockets.remove(&socket_id)?; - unregister_bound_socket(table, &record); - unregister_multicast_memberships(table, &record); - if let Some(listener_state) = record.listener_state.as_ref() { - let pending_socket_ids = listener_state - .pending_accepts - .iter() - .filter_map(|pending| pending.accepted_socket_id) - .collect::>(); - for pending_socket_id in pending_socket_ids { - let _ = remove_socket(table, pending_socket_id); - } - } - if let Some(connection) = record.connection_state.as_ref() { - if let Some(peer_socket_id) = connection.peer_socket_id { - if let Some(peer) = table.sockets.get_mut(&peer_socket_id) { - if let Some(peer_connection) = peer.connection_state.as_mut() { - if peer_connection.peer_socket_id == Some(socket_id) { - peer_connection.peer_socket_id = None; - } - peer_connection.peer_write_shutdown = true; - } - } - } - } - if let Some(owner_sockets) = table.by_owner.get_mut(&record.owner_pid) { - owner_sockets.remove(&socket_id); - if owner_sockets.is_empty() { - table.by_owner.remove(&record.owner_pid); - } - } - Some(record) -} - -fn unregister_bound_socket(table: &mut SocketTableState, record: &SocketRecord) { - let Some(address) = record.local_address.as_ref() else { - if supports_unix_stream_lifecycle(record.spec) { - if let Some(path) = record.local_unix_path.as_ref() { - if table.bound_unix_streams.get(path).copied() == Some(record.id) { - table.bound_unix_streams.remove(path); - } - } - } - return; - }; - if supports_inet_stream_lifecycle(record.spec) - && table.bound_inet_streams.get(address).copied() == Some(record.id) - { - table.bound_inet_streams.remove(address); - } - if supports_inet_datagram_lifecycle(record.spec) { - if let Some(socket_ids) = table.bound_inet_datagrams.get_mut(address) { - socket_ids.remove(&record.id); - if socket_ids.is_empty() { - table.bound_inet_datagrams.remove(address); - } - } - } -} - -fn unregister_multicast_memberships(table: &mut SocketTableState, record: &SocketRecord) { - let Some(datagram_state) = record.datagram_state.as_ref() else { - return; - }; - - for membership in &datagram_state.multicast_memberships { - if let Some(socket_ids) = table.multicast_groups.get_mut(membership) { - socket_ids.remove(&record.id); - if socket_ids.is_empty() { - table.multicast_groups.remove(membership); - } - } - } -} - -fn normalize_inet_address(address: InetSocketAddress) -> InetSocketAddress { - match address.host().to_ascii_lowercase().as_str() { - "localhost" => InetSocketAddress::new("127.0.0.1", address.port()), - _ => address, - } -} - -fn wildcard_inet_address(address: &InetSocketAddress) -> Option { - match address.host() { - "127.0.0.1" => Some(InetSocketAddress::new("0.0.0.0", address.port())), - "::1" => Some(InetSocketAddress::new("::", address.port())), - _ => None, - } -} - -fn normalize_unix_socket_path(path: impl AsRef) -> SocketResult { - let normalized = normalize_path(path.as_ref()); - if normalized == "/" { - return Err(SocketTableError::invalid_argument( - "unix socket path must not be empty or root", - )); - } - Ok(normalized) -} - -fn lock_or_recover<'a, T>(mutex: &'a Mutex) -> MutexGuard<'a, T> { - match mutex.lock() { - Ok(guard) => guard, - Err(poisoned) => poisoned.into_inner(), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - /// Reads the monotonic socket-id counter without advancing it, so a test can - /// observe whether a code path consumed an id. - fn peek_next_socket_id(table: &SocketTable) -> SocketId { - lock_or_recover(&table.inner.state).next_socket_id - } - - #[test] - fn full_backlog_unix_connect_does_not_consume_socket_id() { - let table = SocketTable::new(); - let path = "/tmp/leak-test/server.sock"; - - let listener = table.allocate(1, SocketSpec::unix_stream()); - table - .bind_unix(listener.id, path) - .expect("bind unix listener"); - table.listen(listener.id, 1).expect("listen with backlog 1"); - - // Fill the only backlog slot with one pending connection. - let first = table.allocate(2, SocketSpec::unix_stream()); - table - .connect_to_bound_unix_stream(first.id, path) - .expect("first connect fills the backlog"); - - // A second connect must be rejected because the backlog is full, and it - // must NOT consume a socket id (the counter is monotonic and never reclaims). - let second = table.allocate(2, SocketSpec::unix_stream()); - let before = peek_next_socket_id(&table); - let error = table - .connect_to_bound_unix_stream(second.id, path) - .expect_err("full-backlog connect must fail"); - assert_eq!(error.code(), "EAGAIN"); - let after = peek_next_socket_id(&table); - - assert_eq!( - before, after, - "full-backlog unix connect leaked a socket id (counter advanced from {before} to {after})" - ); - } - - #[test] - fn full_backlog_inet_connect_does_not_consume_socket_id() { - let table = SocketTable::new(); - let target = InetSocketAddress::new("127.0.0.1", 49222); - - let listener = table.allocate(1, SocketSpec::tcp()); - table - .bind_inet(listener.id, target.clone()) - .expect("bind inet listener"); - table.listen(listener.id, 1).expect("listen with backlog 1"); - - // Fill the only backlog slot with one pending connection. - let first = table.allocate(2, SocketSpec::tcp()); - table - .connect_to_bound_inet_stream(first.id, target.clone()) - .expect("first connect fills the backlog"); - - // A second connect must be rejected because the backlog is full, and it - // must NOT consume a socket id (the counter is monotonic and never reclaims). - let second = table.allocate(2, SocketSpec::tcp()); - let before = peek_next_socket_id(&table); - let error = table - .connect_to_bound_inet_stream(second.id, target) - .expect_err("full-backlog connect must fail"); - assert_eq!(error.code(), "EAGAIN"); - let after = peek_next_socket_id(&table); - - assert_eq!( - before, after, - "full-backlog inet connect leaked a socket id (counter advanced from {before} to {after})" - ); - } -} diff --git a/crates/kernel/src/user.rs b/crates/kernel/src/user.rs deleted file mode 100644 index bb5518764..000000000 --- a/crates/kernel/src/user.rs +++ /dev/null @@ -1,138 +0,0 @@ -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProcessIdentity { - pub uid: u32, - pub gid: u32, - pub euid: u32, - pub egid: u32, - pub supplementary_gids: Vec, -} - -impl Default for ProcessIdentity { - fn default() -> Self { - Self { - uid: 1000, - gid: 1000, - euid: 1000, - egid: 1000, - supplementary_gids: vec![1000], - } - } -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct UserConfig { - pub uid: Option, - pub gid: Option, - pub euid: Option, - pub egid: Option, - pub username: Option, - pub homedir: Option, - pub shell: Option, - pub gecos: Option, - pub group_name: Option, - /// Supplementary groups are VM configuration, not guest-mutable state. - /// The primary gid is always injected and duplicate gids are dropped. - pub supplementary_gids: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct UserManager { - pub uid: u32, - pub gid: u32, - pub euid: u32, - pub egid: u32, - pub username: String, - pub homedir: String, - pub shell: String, - pub gecos: String, - pub group_name: String, - pub supplementary_gids: Vec, -} - -impl Default for UserManager { - fn default() -> Self { - Self::from_config(UserConfig::default()) - } -} - -impl UserManager { - pub fn new() -> Self { - Self::default() - } - - pub fn from_config(config: UserConfig) -> Self { - let uid = config.uid.unwrap_or(1000); - let gid = config.gid.unwrap_or(1000); - let username = config.username.unwrap_or_else(|| String::from("agentos")); - let supplementary_gids = normalize_supplementary_gids(gid, config.supplementary_gids); - - Self { - uid, - gid, - euid: config.euid.unwrap_or(uid), - egid: config.egid.unwrap_or(gid), - username: username.clone(), - homedir: config - .homedir - .unwrap_or_else(|| String::from("/home/agentos")), - shell: config.shell.unwrap_or_else(|| String::from("/bin/sh")), - gecos: config.gecos.unwrap_or_default(), - group_name: config.group_name.unwrap_or(username), - supplementary_gids, - } - } - - pub fn identity(&self) -> ProcessIdentity { - ProcessIdentity { - uid: self.uid, - gid: self.gid, - euid: self.euid, - egid: self.egid, - supplementary_gids: self.supplementary_gids.clone(), - } - } - - pub fn getgroups(&self) -> Vec { - self.supplementary_gids.clone() - } - - pub fn getpwuid(&self, uid: u32) -> Option { - if uid == self.uid { - return Some(format!( - "{}:x:{}:{}:{}:{}:{}", - self.username, self.uid, self.gid, self.gecos, self.homedir, self.shell - )); - } - - None - } - - pub fn getgrgid(&self, gid: u32) -> Option { - if gid == self.gid { - return Some(format!( - "{}:x:{}:{}", - self.group_name, self.gid, self.username - )); - } - - if self.supplementary_gids.contains(&gid) { - // Supplementary group names are synthetic because only numeric - // secondary group ids are configured for the VM. - let group_name = format!("group{gid}"); - return Some(format!("{group_name}:x:{gid}:{}", self.username)); - } - - None - } -} - -fn normalize_supplementary_gids(primary_gid: u32, supplementary_gids: Vec) -> Vec { - let mut normalized = Vec::with_capacity(supplementary_gids.len() + 1); - normalized.push(primary_gid); - for gid in supplementary_gids { - if !normalized.contains(&gid) { - normalized.push(gid); - } - } - normalized -} diff --git a/crates/kernel/tests/agentos_read_only.rs b/crates/kernel/tests/agentos_read_only.rs deleted file mode 100644 index a9971de24..000000000 --- a/crates/kernel/tests/agentos_read_only.rs +++ /dev/null @@ -1,343 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::fd_table::{O_CREAT, O_RDONLY, O_TRUNC, O_WRONLY}; -use secure_exec_kernel::kernel::{ - KernelError, KernelResult, KernelVm, KernelVmConfig, SpawnOptions, -}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::root_fs::{ - FilesystemEntry, RootFileSystem, RootFilesystemDescriptor, RootFilesystemMode, - RootFilesystemSnapshot, -}; -use secure_exec_kernel::vfs::{ - MemoryFileSystem, VirtualFileSystem, VirtualTimeSpec, VirtualUtimeSpec, -}; -use std::fmt::Debug; - -const DRIVER: &str = "shell"; -const INSTRUCTIONS: &str = "/etc/agentos/instructions.md"; - -fn assert_erofs(result: KernelResult) { - let error = result.expect_err("operation should fail on read-only agentos path"); - assert_eq!(error.code(), "EROFS"); -} - -fn seeded_kernel() -> KernelVm { - let mut filesystem = MemoryFileSystem::new(); - filesystem - .write_file(INSTRUCTIONS, b"original instructions".to_vec()) - .expect("seed instructions before kernel starts"); - filesystem.mkdir("/tmp", true).expect("seed tmp directory"); - - let mut config = KernelVmConfig::new("vm-agentos-read-only"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(filesystem, config); - kernel - .register_driver(CommandDriver::new(DRIVER, ["sh"])) - .expect("register shell driver"); - kernel -} - -fn seeded_kernel_with_hardlink_alias() -> KernelVm { - let mut filesystem = MemoryFileSystem::new(); - filesystem - .write_file(INSTRUCTIONS, b"original instructions".to_vec()) - .expect("seed instructions before kernel starts"); - filesystem.mkdir("/tmp", true).expect("seed tmp directory"); - filesystem - .link(INSTRUCTIONS, "/tmp/instructions-hardlink.md") - .expect("seed hardlink alias before kernel starts"); - - let mut config = KernelVmConfig::new("vm-agentos-hardlink-read-only"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(filesystem, config); - kernel - .register_driver(CommandDriver::new(DRIVER, ["sh"])) - .expect("register shell driver"); - kernel -} - -fn spawn_shell(kernel: &mut KernelVm) -> u32 { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from(DRIVER)), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") - .pid() -} - -fn read_instructions(kernel: &mut KernelVm) -> Result { - let bytes = kernel.read_file(INSTRUCTIONS)?; - Ok(String::from_utf8(bytes).expect("instructions should be utf8")) -} - -#[test] -fn agentos_instructions_are_readable_but_not_writable() { - let mut kernel = seeded_kernel(); - let pid = spawn_shell(&mut kernel); - - assert_eq!( - read_instructions(&mut kernel).expect("read instructions"), - "original instructions" - ); - - assert_erofs(kernel.write_file(INSTRUCTIONS, "tampered")); - assert_erofs(kernel.write_file_for_process(DRIVER, pid, INSTRUCTIONS, "tampered", Some(0o644))); - assert_erofs(kernel.remove_file(INSTRUCTIONS)); - assert_erofs(kernel.rename(INSTRUCTIONS, "/tmp/instructions.md")); - assert_erofs(kernel.rename("/tmp/replacement.md", INSTRUCTIONS)); - assert_erofs(kernel.chmod(INSTRUCTIONS, 0o777)); - assert_erofs(kernel.link(INSTRUCTIONS, "/tmp/instructions-link.md")); - - let fd = kernel - .fd_open(DRIVER, pid, INSTRUCTIONS, O_RDONLY, None) - .expect("open instructions read-only"); - let contents = kernel - .fd_read(DRIVER, pid, fd, 64) - .expect("read instructions fd"); - assert_eq!( - String::from_utf8(contents).expect("instructions should be utf8"), - "original instructions" - ); - - assert_erofs(kernel.fd_open(DRIVER, pid, INSTRUCTIONS, O_WRONLY, None)); - assert_erofs(kernel.fd_open(DRIVER, pid, INSTRUCTIONS, O_TRUNC, None)); - assert_erofs(kernel.fd_open( - DRIVER, - pid, - "/etc/agentos/generated.md", - O_CREAT | O_WRONLY, - Some(0o644), - )); - assert_erofs(kernel.fd_write(DRIVER, pid, fd, b"tampered")); - assert_erofs(kernel.fd_pwrite(DRIVER, pid, fd, b"tampered", 0)); - - assert_eq!( - read_instructions(&mut kernel).expect("read instructions after failed writes"), - "original instructions" - ); -} - -#[test] -fn agentos_directory_rejects_new_children_and_metadata_updates() { - let mut kernel = seeded_kernel(); - let pid = spawn_shell(&mut kernel); - - assert_erofs(kernel.create_dir("/etc/agentos/nested")); - assert_erofs(kernel.create_dir_for_process(DRIVER, pid, "/etc/agentos/nested", Some(0o755))); - assert_erofs(kernel.mkdir("/etc/agentos/nested/deeper", true)); - assert_erofs(kernel.mkdir_for_process( - DRIVER, - pid, - "/etc/agentos/nested/deeper", - true, - Some(0o755), - )); - assert_erofs(kernel.symlink("/tmp/source", "/etc/agentos/source-link")); - assert_erofs(kernel.chown("/etc/agentos", 1000, 1000)); - assert_erofs(kernel.utimes("/etc/agentos", 1, 1)); - assert_erofs(kernel.truncate(INSTRUCTIONS, 0)); - - assert_eq!( - read_instructions(&mut kernel).expect("read instructions after failed metadata updates"), - "original instructions" - ); -} - -#[test] -fn agentos_protection_follows_symlink_aliases() { - let mut kernel = seeded_kernel(); - let pid = spawn_shell(&mut kernel); - - kernel - .symlink(INSTRUCTIONS, "/tmp/instructions-alias") - .expect("create writable-path symlink to instructions"); - assert_erofs(kernel.write_file("/tmp/instructions-alias", "tampered")); - assert_erofs(kernel.write_file_for_process( - DRIVER, - pid, - "/tmp/instructions-alias", - "tampered", - Some(0o644), - )); - assert_erofs(kernel.truncate("/tmp/instructions-alias", 0)); - assert_erofs(kernel.chmod("/tmp/instructions-alias", 0o777)); - assert_erofs(kernel.chown("/tmp/instructions-alias", 1000, 1000)); - assert_erofs(kernel.utimes("/tmp/instructions-alias", 1, 1)); - assert_erofs(kernel.link("/tmp/instructions-alias", "/tmp/instructions-hardlink")); - - let fd = kernel - .fd_open(DRIVER, pid, "/tmp/instructions-alias", O_RDONLY, None) - .expect("open instructions alias read-only"); - assert_erofs(kernel.fd_write(DRIVER, pid, fd, b"tampered")); - assert_erofs(kernel.fd_pwrite(DRIVER, pid, fd, b"tampered", 0)); - assert_erofs(kernel.fd_open(DRIVER, pid, "/tmp/instructions-alias", O_WRONLY, None)); - assert_erofs(kernel.futimes( - DRIVER, - pid, - fd, - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(1)), - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(1)), - )); - - assert_eq!( - read_instructions(&mut kernel).expect("read instructions after failed alias writes"), - "original instructions" - ); - - kernel - .remove_file("/tmp/instructions-alias") - .expect("outside symlink alias should remain removable"); - assert_eq!( - read_instructions(&mut kernel).expect("read instructions after removing alias"), - "original instructions" - ); -} - -#[test] -fn agentos_protection_rejects_preexisting_hardlink_aliases() { - let mut kernel = seeded_kernel_with_hardlink_alias(); - let pid = spawn_shell(&mut kernel); - let alias = "/tmp/instructions-hardlink.md"; - let symlink_alias = "/tmp/instructions-symlink-to-hardlink.md"; - - assert_eq!( - kernel - .read_file(alias) - .expect("read hardlink alias to instructions"), - b"original instructions".to_vec() - ); - assert_erofs(kernel.write_file(alias, "tampered")); - assert_erofs(kernel.write_file_for_process(DRIVER, pid, alias, "tampered", Some(0o644))); - assert_erofs(kernel.truncate(alias, 0)); - assert_erofs(kernel.chmod(alias, 0o777)); - assert_erofs(kernel.chown(alias, 1000, 1000)); - assert_erofs(kernel.utimes(alias, 1, 1)); - assert_erofs(kernel.remove_file(alias)); - assert_erofs(kernel.rename(alias, "/tmp/moved-hardlink.md")); - - let fd = kernel - .fd_open(DRIVER, pid, alias, O_RDONLY, None) - .expect("open hardlink alias read-only"); - assert_erofs(kernel.fd_write(DRIVER, pid, fd, b"tampered")); - assert_erofs(kernel.fd_pwrite(DRIVER, pid, fd, b"tampered", 0)); - assert_erofs(kernel.fd_open(DRIVER, pid, alias, O_WRONLY, None)); - assert_erofs(kernel.futimes( - DRIVER, - pid, - fd, - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(1)), - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(1)), - )); - - kernel - .symlink(alias, symlink_alias) - .expect("create symlink to hardlink alias"); - assert_erofs(kernel.write_file(symlink_alias, "tampered")); - assert_erofs(kernel.truncate(symlink_alias, 0)); - assert_erofs(kernel.fd_open(DRIVER, pid, symlink_alias, O_WRONLY, None)); - - assert_eq!( - read_instructions(&mut kernel).expect("read instructions after hardlink writes"), - "original instructions" - ); - assert_eq!( - kernel - .read_file(alias) - .expect("hardlink alias should still exist"), - b"original instructions".to_vec() - ); -} - -#[test] -fn agentos_protection_ignores_unrelated_files_in_other_overlay_layers() { - // Regression coverage for layered roots: the protected instructions file - // lives in a lower snapshot layer while new files land in the writable - // upper. Inode numbers overlap across layer filesystems, so the hardlink - // alias check must compare per-instance device ids instead of treating - // every equal inode number as an alias of the protected file. - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/etc/agentos"), - FilesystemEntry::file( - "/etc/agentos/instructions.md", - b"original instructions".to_vec(), - ), - FilesystemEntry::directory("/bin"), - FilesystemEntry::directory("/tmp"), - ], - }], - bootstrap_entries: vec![], - }) - .expect("create layered root filesystem"); - - let mut config = KernelVmConfig::new("vm-agentos-layered-alias"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(root, config); - - // Write enough files for the upper layer's inode counter to sweep past - // the lower layer's inode numbers, then verify metadata updates on every - // unrelated file still succeed. - for index in 0..8 { - let path = format!("/tmp/unrelated-{index}.txt"); - kernel - .write_file(&path, "unrelated") - .expect("write unrelated file in upper layer"); - kernel - .chmod(&path, 0o755) - .expect("chmod unrelated upper-layer file must not trip agentos protection"); - } - - assert_erofs(kernel.chmod("/etc/agentos/instructions.md", 0o777)); - assert_erofs(kernel.write_file("/etc/agentos/instructions.md", "tampered")); - assert_eq!( - kernel - .read_file("/etc/agentos/instructions.md") - .expect("read instructions"), - b"original instructions".to_vec() - ); -} - -#[test] -fn agentos_protection_rejects_creates_through_symlinked_parent() { - let mut kernel = seeded_kernel(); - let pid = spawn_shell(&mut kernel); - - kernel - .symlink("/etc/agentos", "/tmp/agentos-alias") - .expect("create writable-path symlink to agentos directory"); - - assert_erofs(kernel.write_file("/tmp/agentos-alias/generated.md", "tampered")); - assert_erofs(kernel.create_dir("/tmp/agentos-alias/nested")); - assert_erofs(kernel.mkdir("/tmp/agentos-alias/nested/deeper", true)); - assert_erofs(kernel.remove_file("/tmp/agentos-alias/instructions.md")); - assert_erofs(kernel.rename( - "/tmp/agentos-alias/instructions.md", - "/tmp/moved-instructions.md", - )); - kernel - .write_file("/tmp/replacement.md", "replacement") - .expect("write replacement outside protected tree"); - assert_erofs(kernel.rename("/tmp/replacement.md", "/tmp/agentos-alias/replacement.md")); - assert_erofs(kernel.symlink("/tmp/source", "/tmp/agentos-alias/source-link")); - assert_erofs(kernel.fd_open( - DRIVER, - pid, - "/tmp/agentos-alias/generated.md", - O_CREAT | O_WRONLY, - Some(0o644), - )); - - assert_eq!( - read_instructions(&mut kernel) - .expect("read instructions after failed symlinked-parent creates"), - "original instructions" - ); -} diff --git a/crates/kernel/tests/api_surface.rs b/crates/kernel/tests/api_surface.rs deleted file mode 100644 index b35a856ae..000000000 --- a/crates/kernel/tests/api_surface.rs +++ /dev/null @@ -1,1293 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::fd_table::{ - FD_CLOEXEC, F_DUPFD, F_GETFD, F_GETFL, F_SETFD, F_SETFL, LOCK_EX, LOCK_NB, LOCK_SH, LOCK_UN, - O_APPEND, O_CREAT, O_EXCL, O_NONBLOCK, O_RDWR, -}; -use secure_exec_kernel::kernel::{ - ExecOptions, KernelVm, KernelVmConfig, OpenShellOptions, SpawnOptions, WaitPidFlags, - WaitPidResult, SEEK_SET, -}; -use secure_exec_kernel::mount_table::{MountOptions, MountTable}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::pipe_manager::MAX_PIPE_BUFFER_BYTES; -use secure_exec_kernel::process_table::{ProcessWaitEvent, SIGWINCH}; -use secure_exec_kernel::vfs::{ - MemoryFileSystem, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, MAX_PATH_LENGTH, -}; -use std::cell::{Cell, RefCell}; - -fn assert_kernel_error_code( - result: secure_exec_kernel::kernel::KernelResult, - expected: &str, -) { - let error = result.expect_err("operation should fail"); - assert_eq!(error.code(), expected); -} - -fn spawn_shell( - kernel: &mut KernelVm, -) -> secure_exec_kernel::kernel::KernelProcessHandle { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") -} - -fn spawn_shell_in( - kernel: &mut KernelVm, -) -> secure_exec_kernel::kernel::KernelProcessHandle { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") -} - -fn assert_not_trivial_pattern(bytes: &[u8]) { - assert!(bytes.iter().any(|byte| *byte != 0)); - assert!( - bytes.windows(2).any(|window| window[0] != window[1]), - "random data should not collapse to a repeated byte" - ); -} - -struct AtomicityProbeFileSystem { - inner: RefCell, - exclusive_race_pending: Cell, - append_race_pending: Cell, - target_path: &'static str, -} - -impl AtomicityProbeFileSystem { - fn new(target_path: &'static str) -> Self { - let mut inner = MemoryFileSystem::new(); - inner - .write_file(target_path, Vec::new()) - .expect("seed append target"); - Self { - inner: RefCell::new(inner), - exclusive_race_pending: Cell::new(false), - append_race_pending: Cell::new(false), - target_path, - } - } - - fn trigger_exclusive_race(&self) { - self.inner - .borrow_mut() - .remove_file(self.target_path) - .expect("clear target before exclusive race"); - self.exclusive_race_pending.set(true); - } - - fn trigger_append_race(&self) { - self.inner - .borrow_mut() - .write_file(self.target_path, Vec::new()) - .expect("reset target before append race"); - self.append_race_pending.set(true); - } -} - -impl VirtualFileSystem for AtomicityProbeFileSystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - self.inner.borrow_mut().read_file(path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - self.inner.borrow_mut().read_dir(path) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - self.inner.borrow_mut().read_dir_limited(path, max_entries) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - self.inner.borrow_mut().read_dir_with_types(path) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - let content = content.into(); - if path == self.target_path { - if self.exclusive_race_pending.replace(false) { - self.inner - .borrow_mut() - .write_file(path, b"winner".to_vec()) - .expect("inject competing exclusive creator"); - } - if self.append_race_pending.replace(false) { - self.inner - .borrow_mut() - .write_file(path, b"RACE".to_vec()) - .expect("inject competing append writer"); - } - } - self.inner.borrow_mut().write_file(path, content) - } - - fn create_file_exclusive(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - if path == self.target_path && self.exclusive_race_pending.replace(false) { - self.inner - .borrow_mut() - .write_file(path, b"winner".to_vec()) - .expect("inject competing exclusive creator"); - return Err(secure_exec_kernel::vfs::VfsError::new( - "EEXIST", - format!("file already exists, open '{path}'"), - )); - } - self.inner.borrow_mut().create_file_exclusive(path, content) - } - - fn append_file(&mut self, path: &str, content: impl Into>) -> VfsResult { - if path == self.target_path && self.append_race_pending.replace(false) { - self.inner - .borrow_mut() - .append_file(path, b"RACE".to_vec()) - .expect("inject competing append writer"); - } - self.inner.borrow_mut().append_file(path, content) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - self.inner.borrow_mut().create_dir(path) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - self.inner.borrow_mut().mkdir(path, recursive) - } - - fn exists(&self, path: &str) -> bool { - if path == self.target_path && self.exclusive_race_pending.get() { - return false; - } - self.inner.borrow().exists(path) - } - - fn stat(&mut self, path: &str) -> VfsResult { - self.inner.borrow_mut().stat(path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - self.inner.borrow_mut().remove_file(path) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - self.inner.borrow_mut().remove_dir(path) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.inner.borrow_mut().rename(old_path, new_path) - } - - fn realpath(&self, path: &str) -> VfsResult { - self.inner.borrow().realpath(path) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - self.inner.borrow_mut().symlink(target, link_path) - } - - fn read_link(&self, path: &str) -> VfsResult { - self.inner.borrow().read_link(path) - } - - fn lstat(&self, path: &str) -> VfsResult { - self.inner.borrow().lstat(path) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.inner.borrow_mut().link(old_path, new_path) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - self.inner.borrow_mut().chmod(path, mode) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - self.inner.borrow_mut().chown(path, uid, gid) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - self.inner.borrow_mut().utimes(path, atime_ms, mtime_ms) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - self.inner.borrow_mut().truncate(path, length) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - self.inner.borrow_mut().pread(path, offset, length) - } -} - -#[test] -fn kernel_fd_surface_supports_open_seek_positional_io_dup_and_dev_fd_views() { - let mut config = KernelVmConfig::new("vm-api-fd"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .filesystem_mut() - .write_file("/tmp/data.txt", b"hello".to_vec()) - .expect("seed file"); - - let process = spawn_shell(&mut kernel); - let fd = kernel - .fd_open("shell", process.pid(), "/tmp/data.txt", O_RDWR, None) - .expect("open existing file"); - let created_fd = kernel - .fd_open( - "shell", - process.pid(), - "/tmp/created.txt", - O_CREAT | O_RDWR, - None, - ) - .expect("open created file"); - kernel - .fd_write("shell", process.pid(), created_fd, b"created") - .expect("write created file"); - assert_eq!( - kernel - .filesystem_mut() - .read_file("/tmp/created.txt") - .expect("read created file"), - b"created".to_vec() - ); - - let entries = kernel - .dev_fd_read_dir("shell", process.pid()) - .expect("list /dev/fd"); - assert!(entries.contains(&String::from("0"))); - assert!(entries.contains(&String::from("1"))); - assert!(entries.contains(&fd.to_string())); - assert!(entries.contains(&created_fd.to_string())); - - let pread = kernel - .fd_pread("shell", process.pid(), fd, 2, 1) - .expect("pread from offset"); - assert_eq!(pread, b"el".to_vec()); - assert_eq!( - kernel - .fd_seek("shell", process.pid(), fd, 4, SEEK_SET) - .expect("seek to byte 4"), - 4 - ); - - let dup_fd = kernel - .fd_dup("shell", process.pid(), fd) - .expect("duplicate fd"); - let dup_read = kernel - .fd_read("shell", process.pid(), dup_fd, 1) - .expect("read through dup"); - assert_eq!(dup_read, b"o".to_vec()); - - kernel - .fd_dup2("shell", process.pid(), fd, 20) - .expect("dup2 onto target fd"); - kernel - .fd_seek("shell", process.pid(), 20, 0, SEEK_SET) - .expect("seek dup2 target to start"); - let full = kernel - .fd_read("shell", process.pid(), fd, 5) - .expect("read full file"); - assert_eq!(full, b"hello".to_vec()); - - kernel - .fd_pwrite("shell", process.pid(), fd, b"X", 1) - .expect("pwrite at offset"); - assert_eq!( - kernel - .filesystem_mut() - .read_file("/tmp/data.txt") - .expect("read updated file"), - b"hXllo".to_vec() - ); - - let file_stat = kernel - .dev_fd_stat("shell", process.pid(), fd) - .expect("stat regular file fd"); - assert_eq!(file_stat.size, 5); - assert_eq!(file_stat.blocks, 1); - // Device ids are unique per filesystem instance; assert the fd stat - // reports the same device as a direct path stat on the same filesystem. - assert_eq!( - file_stat.dev, - kernel - .filesystem_mut() - .stat("/tmp/data.txt") - .expect("stat updated file") - .dev - ); - assert_eq!(file_stat.rdev, 0); - assert!(!file_stat.is_directory); - - let (read_fd, write_fd) = kernel.open_pipe("shell", process.pid()).expect("open pipe"); - kernel - .fd_write("shell", process.pid(), write_fd, b"pipe-data") - .expect("write pipe"); - let dev_dup = kernel - .fd_open( - "shell", - process.pid(), - &format!("/dev/fd/{read_fd}"), - 0, - None, - ) - .expect("duplicate through /dev/fd"); - let pipe_bytes = kernel - .fd_read("shell", process.pid(), dev_dup, 32) - .expect("read duplicated pipe fd"); - assert_eq!(pipe_bytes, b"pipe-data".to_vec()); - - let pipe_stat = kernel - .dev_fd_stat("shell", process.pid(), read_fd) - .expect("stat pipe fd"); - assert_eq!(pipe_stat.mode, 0o666); - assert_eq!(pipe_stat.size, 0); - assert_eq!(pipe_stat.blocks, 0); - assert_eq!(pipe_stat.dev, 2); - assert!(!pipe_stat.is_directory); - - process.finish(0); - kernel.waitpid(process.pid()).expect("wait for shell"); -} - -#[test] -fn kernel_process_umask_applies_to_created_files_and_directories() { - let mut config = KernelVmConfig::new("vm-api-umask"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = spawn_shell(&mut kernel); - assert_eq!( - kernel - .umask("shell", process.pid(), None) - .expect("read default umask"), - 0o022 - ); - assert_eq!( - kernel - .umask("shell", process.pid(), Some(0o027)) - .expect("set umask"), - 0o022 - ); - - let created_fd = kernel - .fd_open( - "shell", - process.pid(), - "/tmp/umask-file.txt", - O_CREAT | O_RDWR, - Some(0o666), - ) - .expect("create file with umask"); - kernel - .fd_close("shell", process.pid(), created_fd) - .expect("close created fd"); - let file_stat = kernel.stat("/tmp/umask-file.txt").expect("stat umask file"); - assert_eq!(file_stat.mode & 0o777, 0o640); - - kernel - .mkdir_for_process( - "shell", - process.pid(), - "/tmp/private-dir", - false, - Some(0o777), - ) - .expect("create directory with umask"); - let dir_stat = kernel.stat("/tmp/private-dir").expect("stat private dir"); - assert_eq!(dir_stat.mode & 0o777, 0o750); - - process.finish(0); - kernel.waitpid(process.pid()).expect("wait for shell"); -} - -#[test] -fn read_dir_with_types_for_process_reports_entries_and_enforces_driver_ownership() { - let mut config = KernelVmConfig::new("vm-api-readdir-types"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .register_driver(CommandDriver::new("other", ["other"])) - .expect("register other driver"); - kernel - .filesystem_mut() - .write_file("/tmp/typed-file.txt", b"hello".to_vec()) - .expect("seed typed file"); - kernel - .filesystem_mut() - .mkdir("/tmp/typed-dir", true) - .expect("seed typed dir"); - - let process = spawn_shell(&mut kernel); - let entries = kernel - .read_dir_with_types_for_process("shell", process.pid(), "/tmp") - .expect("read typed entries"); - - let file_entry = entries - .iter() - .find(|entry| entry.name == "typed-file.txt") - .expect("typed file entry"); - assert!(!file_entry.is_directory); - assert!(!file_entry.is_symbolic_link); - - let dir_entry = entries - .iter() - .find(|entry| entry.name == "typed-dir") - .expect("typed dir entry"); - assert!(dir_entry.is_directory); - assert!(!dir_entry.is_symbolic_link); - - assert_kernel_error_code( - kernel.read_dir_with_types_for_process("other", process.pid(), "/tmp"), - "EPERM", - ); - - process.finish(0); - kernel.waitpid(process.pid()).expect("wait for shell"); -} - -#[test] -fn kernel_fd_surface_reads_exact_byte_counts_from_device_nodes() { - let mut config = KernelVmConfig::new("vm-api-fd-devices"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = spawn_shell(&mut kernel); - - let zero_fd = kernel - .fd_open("shell", process.pid(), "/dev/zero", O_RDWR, None) - .expect("open /dev/zero"); - let zeroes = kernel - .fd_read("shell", process.pid(), zero_fd, 5) - .expect("read 5 bytes from /dev/zero"); - assert_eq!(zeroes.len(), 5); - assert!(zeroes.iter().all(|byte| *byte == 0)); - - let random_fd = kernel - .fd_open("shell", process.pid(), "/dev/urandom", O_RDWR, None) - .expect("open /dev/urandom"); - let random = kernel - .fd_read("shell", process.pid(), random_fd, 1024 * 1024) - .expect("read 1MiB from /dev/urandom"); - assert_eq!(random.len(), 1024 * 1024); - assert_not_trivial_pattern(&random[..1024]); - - process.finish(0); - kernel.waitpid(process.pid()).expect("wait for shell"); -} - -#[test] -fn kernel_fd_surface_supports_nonblocking_pipe_duplicates_via_dev_fd() { - let mut config = KernelVmConfig::new("vm-api-fd-nonblock"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = spawn_shell(&mut kernel); - let (read_fd, write_fd) = kernel.open_pipe("shell", process.pid()).expect("open pipe"); - let nonblocking_read_fd = kernel - .fd_open( - "shell", - process.pid(), - &format!("/dev/fd/{read_fd}"), - O_NONBLOCK, - None, - ) - .expect("duplicate read end with O_NONBLOCK"); - let nonblocking_write_fd = kernel - .fd_open( - "shell", - process.pid(), - &format!("/dev/fd/{write_fd}"), - O_NONBLOCK, - None, - ) - .expect("duplicate write end with O_NONBLOCK"); - - assert_eq!( - kernel - .fd_stat("shell", process.pid(), read_fd) - .expect("stat blocking read fd") - .flags - & O_NONBLOCK, - 0 - ); - assert_ne!( - kernel - .fd_stat("shell", process.pid(), nonblocking_read_fd) - .expect("stat nonblocking read fd") - .flags - & O_NONBLOCK, - 0 - ); - assert_ne!( - kernel - .fd_stat("shell", process.pid(), nonblocking_write_fd) - .expect("stat nonblocking write fd") - .flags - & O_NONBLOCK, - 0 - ); - - assert_kernel_error_code( - kernel.fd_read("shell", process.pid(), nonblocking_read_fd, 1), - "EAGAIN", - ); - - kernel - .fd_write( - "shell", - process.pid(), - write_fd, - &vec![7; MAX_PIPE_BUFFER_BYTES], - ) - .expect("fill pipe buffer"); - assert_kernel_error_code( - kernel.fd_write("shell", process.pid(), nonblocking_write_fd, &[8]), - "EAGAIN", - ); - - process.finish(0); - kernel.waitpid(process.pid()).expect("wait for shell"); -} - -#[test] -fn kernel_fd_surface_supports_fcntl_status_and_descriptor_flags() { - let mut config = KernelVmConfig::new("vm-api-fcntl"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = spawn_shell(&mut kernel); - let (read_fd, _write_fd) = kernel.open_pipe("shell", process.pid()).expect("open pipe"); - - assert_eq!( - kernel - .fd_fcntl("shell", process.pid(), read_fd, F_GETFL, 0) - .expect("initial F_GETFL"), - 0 - ); - kernel - .fd_fcntl("shell", process.pid(), read_fd, F_SETFL, O_NONBLOCK) - .expect("set O_NONBLOCK"); - assert_eq!( - kernel - .fd_fcntl("shell", process.pid(), read_fd, F_GETFL, 0) - .expect("updated F_GETFL") - & O_NONBLOCK, - O_NONBLOCK - ); - assert_kernel_error_code(kernel.fd_read("shell", process.pid(), read_fd, 1), "EAGAIN"); - - kernel - .fd_fcntl("shell", process.pid(), read_fd, F_SETFD, FD_CLOEXEC) - .expect("set cloexec"); - assert_eq!( - kernel - .fd_fcntl("shell", process.pid(), read_fd, F_GETFD, 0) - .expect("read cloexec"), - FD_CLOEXEC - ); - - let dup_fd = kernel - .fd_fcntl("shell", process.pid(), read_fd, F_DUPFD, 10) - .expect("duplicate with minimum fd"); - assert_eq!(dup_fd, 10); - assert_eq!( - kernel - .fd_fcntl("shell", process.pid(), dup_fd, F_GETFD, 0) - .expect("dup cloexec should be clear"), - 0 - ); - assert_eq!( - kernel - .fd_fcntl("shell", process.pid(), dup_fd, F_GETFL, 0) - .expect("dup status flags") - & O_NONBLOCK, - O_NONBLOCK - ); - - process.finish(0); - kernel.waitpid(process.pid()).expect("wait for shell"); -} - -#[test] -fn kernel_fd_surface_uses_atomic_exclusive_create() { - let target = "/tmp/race.txt"; - let filesystem = AtomicityProbeFileSystem::new(target); - filesystem.trigger_exclusive_race(); - - let mut config = KernelVmConfig::new("vm-api-exclusive-create"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(filesystem, config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = spawn_shell_in(&mut kernel); - assert_kernel_error_code( - kernel.fd_open( - "shell", - process.pid(), - target, - O_CREAT | O_EXCL | O_RDWR, - None, - ), - "EEXIST", - ); - assert_eq!( - kernel - .filesystem_mut() - .read_file(target) - .expect("winner should remain visible"), - b"winner".to_vec() - ); - - process.finish(0); - kernel.waitpid(process.pid()).expect("wait shell"); -} - -#[test] -fn kernel_fd_surface_uses_atomic_append_writes() { - let target = "/tmp/race.txt"; - let filesystem = AtomicityProbeFileSystem::new(target); - filesystem.trigger_append_race(); - - let mut config = KernelVmConfig::new("vm-api-append-write"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(filesystem, config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = spawn_shell_in(&mut kernel); - let fd = kernel - .fd_open("shell", process.pid(), target, O_APPEND | O_RDWR, None) - .expect("open append target"); - assert_eq!( - kernel - .fd_write("shell", process.pid(), fd, b"mine") - .expect("append write"), - 4 - ); - assert_eq!( - kernel - .filesystem_mut() - .read_file(target) - .expect("read appended file"), - b"RACEmine".to_vec() - ); - - process.finish(0); - kernel.waitpid(process.pid()).expect("wait shell"); -} - -#[test] -fn kernel_fd_surface_supports_advisory_locks_and_releases_on_last_close() { - let mut config = KernelVmConfig::new("vm-api-flock-close"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .filesystem_mut() - .write_file("/tmp/lock.txt", b"lock".to_vec()) - .expect("seed file"); - - let owner = spawn_shell(&mut kernel); - let contender = spawn_shell(&mut kernel); - let owner_fd = kernel - .fd_open("shell", owner.pid(), "/tmp/lock.txt", O_RDWR, None) - .expect("owner opens lock file"); - let owner_dup = kernel - .fd_dup("shell", owner.pid(), owner_fd) - .expect("duplicate owner fd"); - let contender_fd = kernel - .fd_open("shell", contender.pid(), "/tmp/lock.txt", O_RDWR, None) - .expect("contender opens lock file"); - - kernel - .fd_flock("shell", owner.pid(), owner_fd, LOCK_EX) - .expect("owner acquires exclusive lock"); - kernel - .fd_flock("shell", owner.pid(), owner_dup, LOCK_EX | LOCK_NB) - .expect("duplicate shares exclusive lock"); - assert_kernel_error_code( - kernel.fd_flock("shell", contender.pid(), contender_fd, LOCK_SH | LOCK_NB), - "EWOULDBLOCK", - ); - - kernel - .fd_close("shell", owner.pid(), owner_fd) - .expect("close original owner fd"); - assert_kernel_error_code( - kernel.fd_flock("shell", contender.pid(), contender_fd, LOCK_SH | LOCK_NB), - "EWOULDBLOCK", - ); - - kernel - .fd_close("shell", owner.pid(), owner_dup) - .expect("close duplicate owner fd"); - kernel - .fd_flock("shell", contender.pid(), contender_fd, LOCK_SH | LOCK_NB) - .expect("lock released on last close"); - kernel - .fd_flock("shell", contender.pid(), contender_fd, LOCK_UN) - .expect("unlock contender"); - - owner.finish(0); - contender.finish(0); - kernel.waitpid(owner.pid()).expect("wait owner"); - kernel.waitpid(contender.pid()).expect("wait contender"); -} - -#[test] -fn kernel_fd_surface_supports_shared_locks_and_nonblocking_upgrade_conflicts() { - let mut config = KernelVmConfig::new("vm-api-flock-shared"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .filesystem_mut() - .write_file("/tmp/shared-lock.txt", b"shared".to_vec()) - .expect("seed file"); - - let first = spawn_shell(&mut kernel); - let second = spawn_shell(&mut kernel); - let first_fd = kernel - .fd_open("shell", first.pid(), "/tmp/shared-lock.txt", O_RDWR, None) - .expect("first opens file"); - let second_fd = kernel - .fd_open("shell", second.pid(), "/tmp/shared-lock.txt", O_RDWR, None) - .expect("second opens file"); - - kernel - .fd_flock("shell", first.pid(), first_fd, LOCK_SH) - .expect("first shared lock"); - kernel - .fd_flock("shell", second.pid(), second_fd, LOCK_SH) - .expect("second shared lock"); - assert_kernel_error_code( - kernel.fd_flock("shell", first.pid(), first_fd, LOCK_EX | LOCK_NB), - "EWOULDBLOCK", - ); - - kernel - .fd_flock("shell", second.pid(), second_fd, LOCK_UN) - .expect("unlock second shared lock"); - kernel - .fd_flock("shell", first.pid(), first_fd, LOCK_EX | LOCK_NB) - .expect("first upgrades to exclusive once peer unlocks"); - - first.finish(0); - second.finish(0); - kernel.waitpid(first.pid()).expect("wait first"); - kernel.waitpid(second.pid()).expect("wait second"); -} - -#[test] -fn kernel_fd_surface_shares_advisory_locks_across_fork_inherited_fds() { - let mut config = KernelVmConfig::new("vm-api-flock-fork"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .filesystem_mut() - .write_file("/tmp/fork-lock.txt", b"fork".to_vec()) - .expect("seed file"); - - let parent = spawn_shell(&mut kernel); - let inherited_fd = kernel - .fd_open("shell", parent.pid(), "/tmp/fork-lock.txt", O_RDWR, None) - .expect("parent opens file"); - kernel - .fd_flock("shell", parent.pid(), inherited_fd, LOCK_EX) - .expect("parent acquires exclusive lock"); - - let child = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - parent_pid: Some(parent.pid()), - ..SpawnOptions::default() - }, - ) - .expect("spawn child with inherited fds"); - let contender = spawn_shell(&mut kernel); - let contender_fd = kernel - .fd_open("shell", contender.pid(), "/tmp/fork-lock.txt", O_RDWR, None) - .expect("contender opens file"); - - kernel - .fd_flock("shell", child.pid(), inherited_fd, LOCK_EX | LOCK_NB) - .expect("child sees the inherited open-file-description lock"); - assert_kernel_error_code( - kernel.fd_flock("shell", contender.pid(), contender_fd, LOCK_SH | LOCK_NB), - "EWOULDBLOCK", - ); - - parent.finish(0); - child.finish(0); - contender.finish(0); - kernel.waitpid(parent.pid()).expect("wait parent"); - kernel.waitpid(child.pid()).expect("wait child"); - kernel.waitpid(contender.pid()).expect("wait contender"); -} - -#[test] -fn waitpid_returns_structured_result_and_process_introspection_works() { - let mut config = KernelVmConfig::new("vm-api-proc"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let parent = spawn_shell(&mut kernel); - let child = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - parent_pid: Some(parent.pid()), - ..SpawnOptions::default() - }, - ) - .expect("spawn child"); - - assert_eq!( - kernel.getpid("shell", child.pid()).expect("getpid"), - child.pid() - ); - assert_eq!( - kernel.getppid("shell", child.pid()).expect("getppid"), - parent.pid() - ); - assert_eq!( - kernel.getsid("shell", child.pid()).expect("inherited sid"), - parent.pid() - ); - assert_eq!( - kernel.setsid("shell", child.pid()).expect("setsid"), - child.pid() - ); - assert_eq!( - kernel.getsid("shell", child.pid()).expect("new sid"), - child.pid() - ); - - let processes = kernel.list_processes(); - assert_eq!( - processes.get(&parent.pid()).expect("parent info").command, - "sh" - ); - assert_eq!( - processes.get(&child.pid()).expect("child info").ppid, - parent.pid() - ); - - child.finish(23); - assert_eq!( - kernel.waitpid(child.pid()).expect("wait child"), - WaitPidResult { - pid: child.pid(), - status: 23, - } - ); - - parent.finish(0); - kernel.waitpid(parent.pid()).expect("wait parent"); -} - -#[test] -fn waitpid_with_options_supports_wnohang_and_any_child_waits() { - let mut config = KernelVmConfig::new("vm-api-waitpid-flags"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let parent = spawn_shell(&mut kernel); - let child = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - parent_pid: Some(parent.pid()), - ..SpawnOptions::default() - }, - ) - .expect("spawn child"); - - assert_eq!( - kernel - .waitpid_with_options("shell", parent.pid(), -1, WaitPidFlags::WNOHANG) - .expect("wnohang wait should succeed"), - None - ); - - child.finish(9); - let waited = kernel - .waitpid_with_options("shell", parent.pid(), -1, WaitPidFlags::empty()) - .expect("wait for any child should succeed") - .expect("child exit should be reported"); - assert_eq!(waited.pid, child.pid()); - assert_eq!(waited.status, 9); - assert_eq!(waited.event, ProcessWaitEvent::Exited); - assert_eq!( - kernel.list_processes().get(&child.pid()), - None, - "exited child should be reaped after wait" - ); - - parent.finish(0); - kernel.waitpid(parent.pid()).expect("wait parent"); -} - -#[test] -fn proc_filesystem_exposes_live_process_metadata_and_fd_symlinks() { - let mut config = KernelVmConfig::new("vm-api-procfs"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .filesystem_mut() - .write_file("/tmp/data.txt", b"hello".to_vec()) - .expect("seed procfs data file"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - cwd: Some(String::from("/tmp")), - env: std::collections::BTreeMap::from([( - String::from("VISIBLE_MARKER"), - String::from("present"), - )]), - ..SpawnOptions::default() - }, - ) - .expect("spawn procfs shell"); - let fd = kernel - .fd_open("shell", process.pid(), "/tmp/data.txt", O_RDWR, None) - .expect("open procfs data file"); - - let proc_entries = kernel - .read_dir_for_process("shell", process.pid(), "/proc") - .expect("read /proc"); - assert!(proc_entries.contains(&String::from("self"))); - assert!(proc_entries.contains(&String::from("mounts"))); - assert!(proc_entries.contains(&process.pid().to_string())); - - assert_eq!( - kernel - .read_link_for_process("shell", process.pid(), "/proc/self") - .expect("read /proc/self link"), - format!("/proc/{}", process.pid()) - ); - assert_eq!( - kernel - .realpath_for_process("shell", process.pid(), "/proc/self") - .expect("realpath /proc/self"), - format!("/proc/{}", process.pid()) - ); - - let self_lstat = kernel - .lstat_for_process("shell", process.pid(), "/proc/self") - .expect("lstat /proc/self"); - assert!(self_lstat.is_symbolic_link); - let self_stat = kernel - .stat_for_process("shell", process.pid(), "/proc/self") - .expect("stat /proc/self"); - assert!(self_stat.is_directory); - - let fd_entries = kernel - .read_dir_for_process("shell", process.pid(), "/proc/self/fd") - .expect("read /proc/self/fd"); - assert!(fd_entries.contains(&String::from("0"))); - assert!(fd_entries.contains(&fd.to_string())); - assert_eq!( - kernel - .read_link_for_process("shell", process.pid(), &format!("/proc/self/fd/{fd}"),) - .expect("read proc fd link"), - String::from("/tmp/data.txt") - ); - - assert_eq!( - kernel - .read_link_for_process("shell", process.pid(), "/proc/self/cwd") - .expect("read cwd link"), - String::from("/tmp") - ); - assert_eq!( - kernel - .read_file_for_process("shell", process.pid(), "/proc/self/cmdline") - .expect("read cmdline"), - b"sh\0".to_vec() - ); - - let environ = String::from_utf8( - kernel - .read_file_for_process("shell", process.pid(), "/proc/self/environ") - .expect("read environ"), - ) - .expect("proc environ should be utf8"); - assert!(environ.contains("VISIBLE_MARKER=present")); - - let stat_text = String::from_utf8( - kernel - .read_file_for_process("shell", process.pid(), "/proc/self/stat") - .expect("read stat"), - ) - .expect("proc stat should be utf8"); - assert!(stat_text.starts_with(&format!("{} (sh) R ", process.pid()))); - - let error = kernel - .write_file("/proc/mounts", b"blocked".to_vec()) - .expect_err("procfs should be read-only"); - assert_eq!(error.code(), "EROFS"); - - process.finish(0); - kernel.waitpid(process.pid()).expect("wait procfs shell"); -} - -#[test] -fn proc_mounts_lists_root_and_active_mounts() { - let mut config = KernelVmConfig::new("vm-api-proc-mounts"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .mount_filesystem( - "/data", - MemoryFileSystem::new(), - MountOptions::new("memory").read_only(true), - ) - .expect("mount memory filesystem"); - - let mounts = String::from_utf8(kernel.read_file("/proc/mounts").expect("read proc mounts")) - .expect("proc mounts should be utf8"); - assert!(mounts.contains("root / root rw 0 0")); - assert!(mounts.contains("memory /data memory ro 0 0")); -} - -#[test] -fn filesystem_operations_return_linux_errno_values_for_common_failures() { - let mut config = KernelVmConfig::new("vm-api-errno"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MountTable::new(MemoryFileSystem::new()), config); - - kernel.create_dir("/dir").expect("create dir"); - assert_kernel_error_code(kernel.write_file("/dir", b"blocked".to_vec()), "EISDIR"); - - kernel - .write_file("/file", b"parent".to_vec()) - .expect("write file parent"); - assert_kernel_error_code(kernel.stat("/file/child"), "ENOTDIR"); - - let long_path = format!("/{}", "a".repeat(MAX_PATH_LENGTH)); - assert_kernel_error_code(kernel.stat(&long_path), "ENAMETOOLONG"); - - kernel - .mount_filesystem( - "/readonly", - MemoryFileSystem::new(), - MountOptions::new("memory").read_only(true), - ) - .expect("mount readonly fs"); - assert_kernel_error_code( - kernel.write_file("/readonly/blocked.txt", b"blocked".to_vec()), - "EROFS", - ); -} - -#[test] -fn open_shell_configures_pty_and_exec_uses_shell_driver() { - let mut config = KernelVmConfig::new("vm-api-shell"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let shell = kernel - .open_shell(OpenShellOptions { - requester_driver: Some(String::from("shell")), - ..OpenShellOptions::default() - }) - .expect("open shell"); - assert!(shell.pty_path().starts_with("/dev/pts/")); - assert_eq!( - kernel.getpgid("shell", shell.pid()).expect("shell pgid"), - shell.pid() - ); - assert_eq!( - kernel - .tcgetpgrp("shell", shell.pid(), shell.master_fd()) - .expect("foreground pgid"), - shell.pid() - ); - - shell.process().finish(0); - kernel.waitpid(shell.pid()).expect("wait shell"); - - let exec = kernel - .exec( - "echo hello", - ExecOptions { - requester_driver: Some(String::from("shell")), - ..ExecOptions::default() - }, - ) - .expect("exec through shell"); - assert_eq!(exec.driver(), "shell"); - assert_eq!( - kernel - .list_processes() - .get(&exec.pid()) - .expect("exec process") - .command, - "sh" - ); - - exec.finish(0); - kernel.waitpid(exec.pid()).expect("wait exec"); -} - -#[test] -fn pty_resize_delivers_sigwinch_to_the_foreground_process_group() { - let mut config = KernelVmConfig::new("vm-api-shell"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let shell = kernel - .open_shell(OpenShellOptions { - requester_driver: Some(String::from("shell")), - ..OpenShellOptions::default() - }) - .expect("open shell"); - - kernel - .pty_resize("shell", shell.pid(), shell.master_fd(), 120, 40) - .expect("resize shell pty"); - kernel - .pty_resize("shell", shell.pid(), shell.master_fd(), 120, 40) - .expect("repeat shell pty resize"); - - assert_eq!(shell.process().kill_signals(), vec![SIGWINCH]); - - shell.process().finish(0); - kernel.waitpid(shell.pid()).expect("wait shell"); -} - -#[test] -fn shell_foreground_process_group_must_stay_in_the_same_session() { - let mut config = KernelVmConfig::new("vm-api-shell"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let shell = kernel - .open_shell(OpenShellOptions { - requester_driver: Some(String::from("shell")), - ..OpenShellOptions::default() - }) - .expect("open shell"); - let peer = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - parent_pid: Some(shell.pid()), - ..SpawnOptions::default() - }, - ) - .expect("spawn peer"); - - assert_eq!( - kernel.getsid("shell", peer.pid()).expect("peer sid"), - shell.pid() - ); - assert_eq!( - kernel.setsid("shell", peer.pid()).expect("setsid"), - peer.pid() - ); - - let error = kernel - .pty_set_foreground_pgid("shell", shell.pid(), shell.master_fd(), peer.pid()) - .expect_err("different-session process group should be rejected"); - assert_eq!(error.code(), "EPERM"); - assert!(error.to_string().contains("different session")); - - peer.finish(0); - kernel.waitpid(peer.pid()).expect("wait peer"); - shell.process().finish(0); - kernel.waitpid(shell.pid()).expect("wait shell"); -} - -#[test] -fn virtual_filesystem_default_pwrite_zero_fills_missing_bytes() { - let mut filesystem = MemoryFileSystem::new(); - filesystem - .write_file("/tmp/pwrite.txt", b"AB".to_vec()) - .expect("seed file"); - - VirtualFileSystem::pwrite(&mut filesystem, "/tmp/pwrite.txt", b"CD".to_vec(), 5) - .expect("default pwrite"); - - assert_eq!( - filesystem - .read_file("/tmp/pwrite.txt") - .expect("read back pwrite result"), - vec![b'A', b'B', 0, 0, 0, b'C', b'D'] - ); -} diff --git a/crates/kernel/tests/bridge.rs b/crates/kernel/tests/bridge.rs deleted file mode 100644 index 9756bc433..000000000 --- a/crates/kernel/tests/bridge.rs +++ /dev/null @@ -1,338 +0,0 @@ -mod bridge_support; - -use bridge_support::RecordingBridge; -use secure_exec_kernel::bridge::{ - ClockRequest, CommandPermissionRequest, CreateDirRequest, CreateJavascriptContextRequest, - CreateWasmContextRequest, DiagnosticRecord, DirectoryEntry, EnvironmentAccess, - EnvironmentPermissionRequest, ExecutionEvent, ExecutionHandleRequest, ExecutionSignal, - FilesystemAccess, FilesystemPermissionRequest, FilesystemSnapshot, FlushFilesystemStateRequest, - GuestKernelCall, GuestRuntime, HostBridge, LifecycleEventRecord, LifecycleState, - LoadFilesystemStateRequest, LogLevel, LogRecord, NetworkAccess, NetworkPermissionRequest, - PathRequest, PollExecutionEventRequest, RandomBytesRequest, ReadDirRequest, ReadFileRequest, - RenameRequest, ScheduleTimerRequest, StructuredEventRecord, SymlinkRequest, TruncateRequest, - WriteExecutionStdinRequest, WriteFileRequest, -}; -use std::collections::BTreeMap; -use std::fmt::Debug; -use std::time::{Duration, SystemTime}; - -fn assert_host_bridge(bridge: &mut B) -where - B: HostBridge, - ::Error: Debug, -{ - let contents = bridge - .read_file(ReadFileRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - }) - .expect("read file"); - assert_eq!(contents, b"hello".to_vec()); - - bridge - .write_file(WriteFileRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/output.txt"), - contents: b"world".to_vec(), - }) - .expect("write file"); - assert!(bridge - .exists(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/output.txt"), - }) - .expect("exists after write")); - - let directory = bridge - .read_dir(ReadDirRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace"), - }) - .expect("read dir"); - assert_eq!(directory.len(), 1); - - let metadata = bridge - .stat(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - }) - .expect("stat"); - assert_eq!(metadata.kind, secure_exec_kernel::bridge::FileKind::File); - assert_eq!(metadata.size, 5); - - bridge - .create_dir(CreateDirRequest { - vm_id: String::from("vm-1"), - path: String::from("/tmp"), - recursive: true, - }) - .expect("create dir"); - bridge - .rename(RenameRequest { - vm_id: String::from("vm-1"), - from_path: String::from("/workspace/output.txt"), - to_path: String::from("/workspace/output-renamed.txt"), - }) - .expect("rename"); - bridge - .symlink(SymlinkRequest { - vm_id: String::from("vm-1"), - target_path: String::from("/workspace/input.txt"), - link_path: String::from("/workspace/input-link.txt"), - }) - .expect("symlink"); - assert_eq!( - bridge - .read_link(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input-link.txt"), - }) - .expect("readlink"), - "/workspace/input.txt" - ); - bridge - .truncate(TruncateRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - len: 2, - }) - .expect("truncate"); - assert_eq!( - bridge - .read_file(ReadFileRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - }) - .expect("read after truncate"), - b"he".to_vec() - ); - - assert_eq!( - bridge - .check_filesystem_access(FilesystemPermissionRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/input.txt"), - access: FilesystemAccess::Read, - }) - .expect("filesystem permission"), - secure_exec_kernel::bridge::PermissionDecision::allow() - ); - assert_eq!( - bridge - .check_network_access(NetworkPermissionRequest { - vm_id: String::from("vm-1"), - access: NetworkAccess::Fetch, - resource: String::from("https://example.test"), - }) - .expect("network permission"), - secure_exec_kernel::bridge::PermissionDecision::allow() - ); - assert_eq!( - bridge - .check_command_execution(CommandPermissionRequest { - vm_id: String::from("vm-1"), - command: String::from("node"), - args: vec![String::from("--version")], - cwd: Some(String::from("/workspace")), - env: BTreeMap::new(), - }) - .expect("command permission"), - secure_exec_kernel::bridge::PermissionDecision::allow() - ); - assert_eq!( - bridge - .check_environment_access(EnvironmentPermissionRequest { - vm_id: String::from("vm-1"), - access: EnvironmentAccess::Read, - key: String::from("PATH"), - value: None, - }) - .expect("env permission"), - secure_exec_kernel::bridge::PermissionDecision::allow() - ); - - assert_eq!( - bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: String::from("vm-1"), - }) - .expect("load snapshot") - .expect("snapshot present") - .format, - "tar" - ); - bridge - .flush_filesystem_state(FlushFilesystemStateRequest { - vm_id: String::from("vm-2"), - snapshot: FilesystemSnapshot { - format: String::from("tar"), - bytes: vec![9, 9, 9], - }, - }) - .expect("flush snapshot"); - assert_eq!( - bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: String::from("vm-2"), - }) - .expect("load flushed snapshot") - .expect("flushed snapshot present") - .bytes, - vec![9, 9, 9] - ); - - assert_eq!( - bridge - .wall_clock(ClockRequest { - vm_id: String::from("vm-1"), - }) - .expect("wall clock"), - SystemTime::UNIX_EPOCH + Duration::from_secs(1_710_000_000) - ); - assert_eq!( - bridge - .monotonic_clock(ClockRequest { - vm_id: String::from("vm-1"), - }) - .expect("monotonic clock"), - Duration::from_millis(42) - ); - assert_eq!( - bridge - .schedule_timer(ScheduleTimerRequest { - vm_id: String::from("vm-1"), - delay: Duration::from_millis(5), - }) - .expect("schedule timer") - .timer_id, - "timer-1" - ); - assert_eq!( - bridge - .fill_random_bytes(RandomBytesRequest { - vm_id: String::from("vm-1"), - len: 4, - }) - .expect("random bytes"), - vec![0xA5; 4] - ); - - bridge - .emit_log(LogRecord { - vm_id: String::from("vm-1"), - level: LogLevel::Info, - message: String::from("started"), - }) - .expect("emit log"); - bridge - .emit_diagnostic(DiagnosticRecord { - vm_id: String::from("vm-1"), - message: String::from("healthy"), - fields: BTreeMap::from([(String::from("uptime_ms"), String::from("10"))]), - }) - .expect("emit diagnostic"); - bridge - .emit_structured_event(StructuredEventRecord { - vm_id: String::from("vm-1"), - name: String::from("process.stdout"), - fields: BTreeMap::from([(String::from("fd"), String::from("1"))]), - }) - .expect("emit structured event"); - bridge - .emit_lifecycle(LifecycleEventRecord { - vm_id: String::from("vm-1"), - state: LifecycleState::Ready, - detail: Some(String::from("booted")), - }) - .expect("emit lifecycle"); - - let js_context = bridge - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-1"), - bootstrap_module: Some(String::from("@secure-exec/bootstrap")), - }) - .expect("create js context"); - assert_eq!(js_context.runtime, GuestRuntime::JavaScript); - - let wasm_context = bridge - .create_wasm_context(CreateWasmContextRequest { - vm_id: String::from("vm-1"), - module_path: Some(String::from("/workspace/module.wasm")), - }) - .expect("create wasm context"); - assert_eq!(wasm_context.runtime, GuestRuntime::WebAssembly); - - let execution = bridge - .start_execution(secure_exec_kernel::bridge::StartExecutionRequest { - vm_id: String::from("vm-1"), - context_id: js_context.context_id, - argv: vec![String::from("index.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start execution"); - assert_eq!(execution.execution_id, "exec-1"); - - bridge - .write_stdin(WriteExecutionStdinRequest { - vm_id: String::from("vm-1"), - execution_id: execution.execution_id.clone(), - chunk: b"input".to_vec(), - }) - .expect("write stdin"); - bridge - .close_stdin(ExecutionHandleRequest { - vm_id: String::from("vm-1"), - execution_id: execution.execution_id.clone(), - }) - .expect("close stdin"); - bridge - .kill_execution(secure_exec_kernel::bridge::KillExecutionRequest { - vm_id: String::from("vm-1"), - execution_id: execution.execution_id, - signal: ExecutionSignal::Terminate, - }) - .expect("kill execution"); - - match bridge - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-1"), - }) - .expect("poll execution event") - { - Some(ExecutionEvent::GuestRequest(event)) => { - assert_eq!(event.operation, "fs.read"); - } - other => panic!("unexpected execution event: {other:?}"), - } - - let _ = wasm_context; -} - -#[test] -fn host_bridge_traits_are_method_oriented_and_composable() { - let mut bridge = RecordingBridge::default(); - bridge.seed_file("/workspace/input.txt", b"hello".to_vec()); - bridge.seed_directory( - "/workspace", - vec![DirectoryEntry { - name: String::from("input.txt"), - kind: secure_exec_kernel::bridge::FileKind::File, - }], - ); - bridge.seed_snapshot( - "vm-1", - FilesystemSnapshot { - format: String::from("tar"), - bytes: vec![1, 2, 3], - }, - ); - bridge.push_execution_event(ExecutionEvent::GuestRequest(GuestKernelCall { - vm_id: String::from("vm-1"), - execution_id: String::from("exec-seeded"), - operation: String::from("fs.read"), - payload: b"{}".to_vec(), - })); - - assert_host_bridge(&mut bridge); -} diff --git a/crates/kernel/tests/bridge_support.rs b/crates/kernel/tests/bridge_support.rs deleted file mode 100644 index d03ffca4d..000000000 --- a/crates/kernel/tests/bridge_support.rs +++ /dev/null @@ -1,447 +0,0 @@ -use secure_exec_kernel::bridge::{ - BridgeTypes, ChmodRequest, ClockBridge, ClockRequest, CommandPermissionRequest, - CreateDirRequest, CreateJavascriptContextRequest, CreateWasmContextRequest, DiagnosticRecord, - DirectoryEntry, EnvironmentPermissionRequest, EventBridge, ExecutionBridge, ExecutionEvent, - ExecutionHandleRequest, FileKind, FileMetadata, FilesystemBridge, FilesystemPermissionRequest, - FilesystemSnapshot, FlushFilesystemStateRequest, GuestContextHandle, GuestRuntime, - KillExecutionRequest, LifecycleEventRecord, LoadFilesystemStateRequest, LogRecord, - NetworkPermissionRequest, PathRequest, PermissionBridge, PermissionDecision, PersistenceBridge, - PollExecutionEventRequest, RandomBridge, RandomBytesRequest, ReadDirRequest, ReadFileRequest, - RenameRequest, ScheduleTimerRequest, ScheduledTimer, StartExecutionRequest, StartedExecution, - StructuredEventRecord, SymlinkRequest, TruncateRequest, WriteExecutionStdinRequest, - WriteFileRequest, -}; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::time::{Duration, SystemTime}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StubError { - message: String, -} - -impl StubError { - fn missing(kind: &'static str, key: &str) -> Self { - Self { - message: format!("missing {kind}: {key}"), - } - } - - fn invalid(kind: &'static str, key: &str) -> Self { - Self { - message: format!("invalid {kind}: {key}"), - } - } -} - -#[derive(Debug)] -pub struct RecordingBridge { - next_context_id: usize, - next_execution_id: usize, - next_timer_id: usize, - files: BTreeMap>, - directories: BTreeMap>, - symlinks: BTreeMap, - snapshots: BTreeMap, - execution_events: VecDeque, - pub permission_checks: Vec, - pub log_events: Vec, - pub diagnostic_events: Vec, - pub structured_events: Vec, - pub lifecycle_events: Vec, - pub scheduled_timers: Vec, - pub stdin_writes: Vec, - pub closed_executions: Vec, - pub killed_executions: Vec, -} - -impl Default for RecordingBridge { - fn default() -> Self { - let mut directories = BTreeMap::new(); - directories.insert(String::from("/"), Vec::new()); - - Self { - next_context_id: 1, - next_execution_id: 1, - next_timer_id: 1, - files: BTreeMap::new(), - directories, - symlinks: BTreeMap::new(), - snapshots: BTreeMap::new(), - execution_events: VecDeque::new(), - permission_checks: Vec::new(), - log_events: Vec::new(), - diagnostic_events: Vec::new(), - structured_events: Vec::new(), - lifecycle_events: Vec::new(), - scheduled_timers: Vec::new(), - stdin_writes: Vec::new(), - closed_executions: Vec::new(), - killed_executions: Vec::new(), - } - } -} - -#[allow(dead_code)] -impl RecordingBridge { - pub fn seed_file(&mut self, path: impl Into, contents: impl Into>) { - self.files.insert(path.into(), contents.into()); - } - - pub fn seed_directory(&mut self, path: impl Into, entries: Vec) { - self.directories.insert(path.into(), entries); - } - - pub fn seed_snapshot(&mut self, vm_id: impl Into, snapshot: FilesystemSnapshot) { - self.snapshots.insert(vm_id.into(), snapshot); - } - - pub fn push_execution_event(&mut self, event: ExecutionEvent) { - self.execution_events.push_back(event); - } - - fn metadata_for_path(&self, path: &str, follow_links: bool) -> Result { - let mut current_path = path.to_owned(); - let mut seen_links = BTreeSet::new(); - - if follow_links { - while let Some(target) = self.symlinks.get(¤t_path) { - if !seen_links.insert(current_path.clone()) { - return Err(StubError::invalid("symlink cycle", ¤t_path)); - } - current_path = target.clone(); - } - } else if self.symlinks.contains_key(¤t_path) { - return Ok(FileMetadata { - mode: 0o777, - size: 0, - kind: FileKind::SymbolicLink, - }); - } - - if let Some(bytes) = self.files.get(¤t_path) { - return Ok(FileMetadata { - mode: 0o644, - size: bytes.len() as u64, - kind: FileKind::File, - }); - } - - if let Some(entries) = self.directories.get(¤t_path) { - return Ok(FileMetadata { - mode: 0o755, - size: entries.len() as u64, - kind: FileKind::Directory, - }); - } - - Err(StubError::missing("path", ¤t_path)) - } -} - -impl BridgeTypes for RecordingBridge { - type Error = StubError; -} - -impl FilesystemBridge for RecordingBridge { - fn read_file(&mut self, request: ReadFileRequest) -> Result, Self::Error> { - self.files - .get(&request.path) - .cloned() - .ok_or_else(|| StubError::missing("file", &request.path)) - } - - fn write_file(&mut self, request: WriteFileRequest) -> Result<(), Self::Error> { - self.files.insert(request.path, request.contents); - Ok(()) - } - - fn stat(&mut self, request: PathRequest) -> Result { - self.metadata_for_path(&request.path, true) - } - - fn lstat(&mut self, request: PathRequest) -> Result { - self.metadata_for_path(&request.path, false) - } - - fn read_dir(&mut self, request: ReadDirRequest) -> Result, Self::Error> { - Ok(self - .directories - .get(&request.path) - .cloned() - .unwrap_or_default()) - } - - fn create_dir(&mut self, request: CreateDirRequest) -> Result<(), Self::Error> { - self.directories.entry(request.path).or_default(); - Ok(()) - } - - fn remove_file(&mut self, request: PathRequest) -> Result<(), Self::Error> { - self.files.remove(&request.path); - Ok(()) - } - - fn remove_dir(&mut self, request: PathRequest) -> Result<(), Self::Error> { - self.directories.remove(&request.path); - Ok(()) - } - - fn rename(&mut self, request: RenameRequest) -> Result<(), Self::Error> { - if let Some(bytes) = self.files.remove(&request.from_path) { - self.files.insert(request.to_path, bytes); - return Ok(()); - } - - if let Some(target) = self.symlinks.remove(&request.from_path) { - self.symlinks.insert(request.to_path, target); - return Ok(()); - } - - if let Some(entries) = self.directories.remove(&request.from_path) { - self.directories.insert(request.to_path, entries); - return Ok(()); - } - - Err(StubError::missing("rename source", &request.from_path)) - } - - fn symlink(&mut self, request: SymlinkRequest) -> Result<(), Self::Error> { - self.symlinks.insert(request.link_path, request.target_path); - Ok(()) - } - - fn read_link(&mut self, request: PathRequest) -> Result { - self.symlinks - .get(&request.path) - .cloned() - .ok_or_else(|| StubError::missing("symlink", &request.path)) - } - - fn chmod(&mut self, _request: ChmodRequest) -> Result<(), Self::Error> { - Ok(()) - } - - fn truncate(&mut self, request: TruncateRequest) -> Result<(), Self::Error> { - let Some(bytes) = self.files.get_mut(&request.path) else { - return Err(StubError::missing("file", &request.path)); - }; - - bytes.resize(request.len as usize, 0); - Ok(()) - } - - fn exists(&mut self, request: PathRequest) -> Result { - Ok(self.files.contains_key(&request.path) - || self.directories.contains_key(&request.path) - || self.symlinks.contains_key(&request.path)) - } -} - -impl PermissionBridge for RecordingBridge { - fn check_filesystem_access( - &mut self, - request: FilesystemPermissionRequest, - ) -> Result { - self.permission_checks - .push(format!("fs:{}:{}", request.vm_id, request.path)); - Ok(PermissionDecision::allow()) - } - - fn check_network_access( - &mut self, - request: NetworkPermissionRequest, - ) -> Result { - self.permission_checks - .push(format!("net:{}:{}", request.vm_id, request.resource)); - Ok(PermissionDecision::allow()) - } - - fn check_command_execution( - &mut self, - request: CommandPermissionRequest, - ) -> Result { - self.permission_checks - .push(format!("cmd:{}:{}", request.vm_id, request.command)); - Ok(PermissionDecision::allow()) - } - - fn check_environment_access( - &mut self, - request: EnvironmentPermissionRequest, - ) -> Result { - self.permission_checks - .push(format!("env:{}:{}", request.vm_id, request.key)); - Ok(PermissionDecision::allow()) - } -} - -impl PersistenceBridge for RecordingBridge { - fn load_filesystem_state( - &mut self, - request: LoadFilesystemStateRequest, - ) -> Result, Self::Error> { - Ok(self.snapshots.get(&request.vm_id).cloned()) - } - - fn flush_filesystem_state( - &mut self, - request: FlushFilesystemStateRequest, - ) -> Result<(), Self::Error> { - self.snapshots.insert(request.vm_id, request.snapshot); - Ok(()) - } -} - -impl ClockBridge for RecordingBridge { - fn wall_clock(&mut self, _request: ClockRequest) -> Result { - Ok(SystemTime::UNIX_EPOCH + Duration::from_secs(1_710_000_000)) - } - - fn monotonic_clock(&mut self, _request: ClockRequest) -> Result { - Ok(Duration::from_millis(42)) - } - - fn schedule_timer( - &mut self, - request: ScheduleTimerRequest, - ) -> Result { - self.scheduled_timers.push(request.clone()); - - let timer = ScheduledTimer { - timer_id: format!("timer-{}", self.next_timer_id), - delay: request.delay, - }; - self.next_timer_id += 1; - - Ok(timer) - } -} - -impl RandomBridge for RecordingBridge { - fn fill_random_bytes(&mut self, request: RandomBytesRequest) -> Result, Self::Error> { - Ok(vec![0xA5; request.len]) - } -} - -impl EventBridge for RecordingBridge { - fn emit_structured_event(&mut self, event: StructuredEventRecord) -> Result<(), Self::Error> { - self.structured_events.push(event); - Ok(()) - } - - fn emit_diagnostic(&mut self, event: DiagnosticRecord) -> Result<(), Self::Error> { - self.diagnostic_events.push(event); - Ok(()) - } - - fn emit_log(&mut self, event: LogRecord) -> Result<(), Self::Error> { - self.log_events.push(event); - Ok(()) - } - - fn emit_lifecycle(&mut self, event: LifecycleEventRecord) -> Result<(), Self::Error> { - self.lifecycle_events.push(event); - Ok(()) - } -} - -impl ExecutionBridge for RecordingBridge { - fn create_javascript_context( - &mut self, - _request: CreateJavascriptContextRequest, - ) -> Result { - let handle = GuestContextHandle { - context_id: format!("js-context-{}", self.next_context_id), - runtime: GuestRuntime::JavaScript, - }; - self.next_context_id += 1; - Ok(handle) - } - - fn create_wasm_context( - &mut self, - _request: CreateWasmContextRequest, - ) -> Result { - let handle = GuestContextHandle { - context_id: format!("wasm-context-{}", self.next_context_id), - runtime: GuestRuntime::WebAssembly, - }; - self.next_context_id += 1; - Ok(handle) - } - - fn start_execution( - &mut self, - _request: StartExecutionRequest, - ) -> Result { - let execution = StartedExecution { - execution_id: format!("exec-{}", self.next_execution_id), - }; - self.next_execution_id += 1; - Ok(execution) - } - - fn write_stdin(&mut self, request: WriteExecutionStdinRequest) -> Result<(), Self::Error> { - self.stdin_writes.push(request); - Ok(()) - } - - fn close_stdin(&mut self, request: ExecutionHandleRequest) -> Result<(), Self::Error> { - self.closed_executions.push(request); - Ok(()) - } - - fn kill_execution(&mut self, request: KillExecutionRequest) -> Result<(), Self::Error> { - self.killed_executions.push(request); - Ok(()) - } - - fn poll_execution_event( - &mut self, - _request: PollExecutionEventRequest, - ) -> Result, Self::Error> { - Ok(self.execution_events.pop_front()) - } -} - -#[test] -fn recording_bridge_rejects_symlink_cycles_when_following_metadata() { - let mut bridge = RecordingBridge::default(); - bridge - .symlink(SymlinkRequest { - vm_id: String::from("vm-1"), - target_path: String::from("/b"), - link_path: String::from("/a"), - }) - .expect("create first symlink"); - bridge - .symlink(SymlinkRequest { - vm_id: String::from("vm-1"), - target_path: String::from("/a"), - link_path: String::from("/b"), - }) - .expect("create second symlink"); - - let error = bridge - .stat(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/a"), - }) - .expect_err("cyclic symlink metadata should fail"); - assert_eq!( - error, - StubError { - message: String::from("invalid symlink cycle: /a"), - } - ); - assert_eq!( - bridge - .lstat(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/a"), - }) - .expect("lstat should not follow cyclic symlink") - .kind, - FileKind::SymbolicLink - ); -} diff --git a/crates/kernel/tests/command_registry.rs b/crates/kernel/tests/command_registry.rs deleted file mode 100644 index e50d69f4d..000000000 --- a/crates/kernel/tests/command_registry.rs +++ /dev/null @@ -1,196 +0,0 @@ -use secure_exec_kernel::command_registry::{CommandDriver, CommandRegistry}; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::vfs::{MemoryFileSystem, VirtualFileSystem}; - -#[test] -fn registers_and_resolves_commands() { - let mut registry = CommandRegistry::new(); - let driver = CommandDriver::new("wasmvm", ["grep", "sed", "cat"]); - - registry - .register(driver.clone()) - .expect("register commands"); - - assert_eq!(registry.resolve("grep"), Some(&driver)); - assert_eq!(registry.resolve("sed"), Some(&driver)); - assert_eq!(registry.resolve("cat"), Some(&driver)); -} - -#[test] -fn returns_none_for_unknown_commands() { - let registry = CommandRegistry::new(); - - assert!(registry.resolve("nonexistent").is_none()); -} - -#[test] -fn last_registered_driver_wins_on_conflict() { - let mut registry = CommandRegistry::new(); - registry - .register(CommandDriver::new("wasmvm", ["node"])) - .expect("register wasm driver"); - registry - .register(CommandDriver::new("node", ["node"])) - .expect("register node driver"); - - assert_eq!( - registry - .resolve("node") - .expect("node should resolve") - .name(), - "node" - ); -} - -#[test] -fn list_returns_command_to_driver_name_mapping() { - let mut registry = CommandRegistry::new(); - registry - .register(CommandDriver::new("wasmvm", ["grep", "cat"])) - .expect("register wasm driver"); - registry - .register(CommandDriver::new("node", ["node", "npm"])) - .expect("register node driver"); - - let commands = registry.list(); - assert_eq!(commands.get("grep"), Some(&String::from("wasmvm"))); - assert_eq!(commands.get("node"), Some(&String::from("node"))); - assert_eq!(commands.len(), 4); -} - -#[test] -fn records_warning_when_overriding_existing_command() { - let mut registry = CommandRegistry::new(); - registry - .register(CommandDriver::new("wasmvm", ["sh", "grep"])) - .expect("register wasm driver"); - registry - .register(CommandDriver::new("node", ["sh"])) - .expect("register node driver"); - - let warnings = registry.warnings(); - assert_eq!(warnings.len(), 1); - assert!(warnings[0].contains("sh")); - assert!(warnings[0].contains("wasmvm")); - assert!(warnings[0].contains("node")); -} - -#[test] -fn populate_bin_creates_stub_entries() { - let mut vfs = MemoryFileSystem::new(); - let mut registry = CommandRegistry::new(); - registry - .register(CommandDriver::new("wasmvm", ["grep", "cat"])) - .expect("register commands"); - - registry.populate_bin(&mut vfs).expect("populate /bin"); - - assert!(vfs.exists("/bin/grep")); - assert!(vfs.exists("/bin/cat")); - assert_eq!( - vfs.read_text_file("/bin/grep").expect("read stub"), - "#!/bin/sh\n# kernel command stub\n" - ); - assert_eq!( - vfs.stat("/bin/grep").expect("stat stub").mode & 0o777, - 0o755 - ); -} - -#[test] -fn rejects_command_names_that_escape_bin_stub_paths() { - for command in ["", ".", "..", "../escape", "nested/escape", "nul\0byte"] { - let mut registry = CommandRegistry::new(); - let error = registry - .register(CommandDriver::new("wasmvm", [command])) - .expect_err("invalid command name should be rejected"); - - assert_eq!(error.code(), "EINVAL"); - assert!( - error.message().contains("invalid command name"), - "unexpected error: {error}" - ); - assert!(registry.list().is_empty()); - } -} - -#[test] -fn populate_bin_rejects_invalid_names_before_writing_any_stubs() { - let mut vfs = MemoryFileSystem::new(); - let driver = CommandDriver::new("wasmvm", ["good", "../escape"]); - let registry = CommandRegistry::new(); - - let error = registry - .populate_driver_bin(&mut vfs, &driver) - .expect_err("invalid command name should reject population"); - - assert_eq!(error.code(), "EINVAL"); - assert!( - error.message().contains("invalid command name"), - "unexpected error: {error}" - ); - assert!(!vfs.exists("/bin")); - assert!(!vfs.exists("/bin/good")); - assert!(!vfs.exists("/escape")); -} - -#[test] -fn kernel_driver_registration_rejects_command_path_names_without_writing_stubs() { - let mut config = KernelVmConfig::new("vm-invalid-command-path"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - - let error = kernel - .register_driver(CommandDriver::new("wasmvm", ["../escape"])) - .expect_err("invalid command should reject driver registration"); - - assert_eq!(error.code(), "EINVAL"); - assert!( - error.to_string().contains("invalid command name"), - "unexpected error: {error}" - ); - assert!(!kernel.exists("/escape").expect("check escaped path")); - assert!(!kernel - .exists("/bin/../escape") - .expect("check normalized escaped path")); -} - -#[test] -fn mounted_agentos_command_paths_resolve_to_registered_drivers() { - let mut config = KernelVmConfig::new("vm-mounted-command-path"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("wasmvm", ["sh", "xu"])) - .expect("register drivers"); - - kernel - .mkdir("/__secure_exec/commands/0", true) - .expect("create mounted command root"); - kernel - .write_file( - "/__secure_exec/commands/0/xu", - b"#!/bin/sh\n# kernel command stub\n".to_vec(), - ) - .expect("write mounted command stub"); - kernel - .chmod("/__secure_exec/commands/0/xu", 0o755) - .expect("chmod mounted command stub"); - - let process = kernel - .spawn_process( - "/__secure_exec/commands/0/xu", - vec![String::from("hello-agentos")], - SpawnOptions::default(), - ) - .expect("spawn mounted command path"); - - let info = kernel - .list_processes() - .get(&process.pid()) - .cloned() - .expect("process info"); - assert_eq!(info.command, "xu"); - assert_eq!(info.driver, "wasmvm"); -} diff --git a/crates/kernel/tests/default_deny_guards.rs b/crates/kernel/tests/default_deny_guards.rs deleted file mode 100644 index 773efed8c..000000000 --- a/crates/kernel/tests/default_deny_guards.rs +++ /dev/null @@ -1,300 +0,0 @@ -//! Default-deny / fail-closed guards (CI hardening, item #5). -//! -//! These tests pin down the secure-exec security posture so a refactor cannot -//! silently weaken it: -//! -//! 1. Default-deny: with no policy configured (`Permissions::default()`), -//! every guarded capability -- filesystem, network, child-process spawn, -//! and environment reads -- is DENIED / fails closed. -//! -//! 2. Fail-closed on new variants: adding a new `FsOperation`, -//! `NetworkOperation`, or `EnvironmentOperation` variant must force a -//! compile error here (via exhaustive `match` with no wildcard arm) so a -//! new capability cannot be added without consciously deciding how the -//! default-deny path treats it. A runtime test additionally confirms each -//! enumerated variant is denied under the empty policy. -//! -//! 3. Safe defaults: every safety-critical NON-TIME resource limit -//! (processes, open fds, sockets, connections, pipes, ptys, filesystem -//! bytes, inodes, and the socket buffer/queue caps) is bounded by default -//! -- i.e. `Some(_)`, never silently unbounded. Time budgets (CPU / -//! wall-clock) are intentionally OPT-IN and are deliberately NOT asserted -//! here. - -use secure_exec_kernel::permissions::{ - check_command_execution, check_network_access, filter_env, EnvAccessRequest, - EnvironmentOperation, FsAccessRequest, FsOperation, NetworkAccessRequest, NetworkOperation, - PermissionedFileSystem, Permissions, -}; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::vfs::{MemoryFileSystem, VfsResult, VirtualFileSystem}; -use std::collections::BTreeMap; -use std::fmt::Debug; - -// --------------------------------------------------------------------------- -// Exhaustive variant enumerations. -// -// These functions list EVERY variant of each capability enum without a `_` -// wildcard arm. If a new variant is added, these stop compiling, forcing the -// author to revisit the default-deny tests. This is the compile-time half of -// "new unmatched permission/FsOperation variant fails closed". -// --------------------------------------------------------------------------- - -fn all_fs_operations() -> Vec { - use FsOperation::*; - // Exhaustive match (no wildcard) so a new variant breaks the build here. - let exhaustiveness_witness = |op: FsOperation| match op { - Read | Write | Mkdir | CreateDir | ReadDir | Stat | Remove | Rename | Exists | Symlink - | ReadLink | Link | Chmod | Chown | Utimes | Truncate | MountSensitive => (), - }; - let all = vec![ - Read, - Write, - Mkdir, - CreateDir, - ReadDir, - Stat, - Remove, - Rename, - Exists, - Symlink, - ReadLink, - Link, - Chmod, - Chown, - Utimes, - Truncate, - MountSensitive, - ]; - for op in &all { - exhaustiveness_witness(*op); - } - all -} - -fn all_network_operations() -> Vec { - use NetworkOperation::*; - let exhaustiveness_witness = |op: NetworkOperation| match op { - Fetch | Http | Dns | Listen => (), - }; - let all = vec![Fetch, Http, Dns, Listen]; - for op in &all { - exhaustiveness_witness(*op); - } - all -} - -fn all_environment_operations() -> Vec { - use EnvironmentOperation::*; - let exhaustiveness_witness = |op: EnvironmentOperation| match op { - Read | Write => (), - }; - let all = vec![Read, Write]; - for op in &all { - exhaustiveness_witness(*op); - } - all -} - -// --------------------------------------------------------------------------- -// 1 + 2: default-deny / fail-closed for every capability and variant. -// --------------------------------------------------------------------------- - -fn assert_fs_denied(result: VfsResult) { - let error = result.expect_err("filesystem op must be denied under empty policy"); - assert_eq!( - error.code(), - "EACCES", - "fs denial should be EACCES, got {error:?}" - ); -} - -#[test] -fn default_permissions_have_no_policy() { - // The derived Default leaves every capability unset (None), which is what - // forces the fail-closed branch in each checker. - let permissions = Permissions::default(); - assert!(permissions.filesystem.is_none(), "fs default must be None"); - assert!(permissions.network.is_none(), "net default must be None"); - assert!( - permissions.child_process.is_none(), - "child_process default must be None" - ); - assert!( - permissions.environment.is_none(), - "environment default must be None" - ); -} - -#[test] -fn default_policy_denies_all_filesystem_operations() { - let permissions = Permissions::default(); - // Seed a real file so the permission gate -- not a missing-path ENOENT -- - // is what rejects the request. - let mut backing = MemoryFileSystem::new(); - backing - .write_file("/secret.txt", b"top secret".to_vec()) - .expect("seed file"); - backing.mkdir("/dir", false).expect("seed dir"); - let fs = PermissionedFileSystem::new(backing, "vm-default-deny", permissions); - - // `check_virtual_path` is the pure permission gate (no path resolution), - // so every enumerated FsOperation must be denied with EACCES. Using the - // enumerated list keeps coverage in lock-step with the enum. - for op in all_fs_operations() { - assert_fs_denied(fs.check_virtual_path(op, "/secret.txt")); - } - // `check_path` (which resolves the path first) must also deny for an - // existing path -- proving denial isn't an artifact of a missing file. - assert_fs_denied(fs.check_path(FsOperation::Read, "/secret.txt")); - assert_fs_denied(fs.check_path(FsOperation::Write, "/secret.txt")); - - // And the concrete VFS operations fail closed as well. - let mut fs = fs; - assert_fs_denied(fs.read_file("/secret.txt")); - assert_fs_denied(fs.write_file("/secret.txt", b"x".to_vec())); - assert_fs_denied(fs.read_dir("/dir")); - assert_fs_denied(fs.stat("/secret.txt")); - assert_fs_denied(fs.remove_file("/secret.txt")); -} - -#[test] -fn default_policy_denies_all_network_operations() { - let permissions = Permissions::default(); - for op in all_network_operations() { - let result = check_network_access( - "vm-default-deny", - &permissions, - op, - "https://example.com:443", - ); - let error = result.expect_err("network op must be denied under empty policy"); - assert_eq!(error.code(), "EACCES", "net denial should be EACCES"); - } -} - -#[test] -fn default_policy_denies_child_process_spawn() { - let permissions = Permissions::default(); - let result = check_command_execution( - "vm-default-deny", - &permissions, - "/bin/sh", - &["-c".to_string(), "echo hi".to_string()], - None, - &BTreeMap::new(), - ); - let error = result.expect_err("spawn must be denied under empty policy"); - assert_eq!(error.code(), "EACCES", "spawn denial should be EACCES"); -} - -#[test] -fn default_policy_denies_all_environment_reads() { - let permissions = Permissions::default(); - - // filter_env with no environment policy must scrub everything. - let mut env = BTreeMap::new(); - env.insert("SECRET_TOKEN".to_string(), "abc123".to_string()); - env.insert("PATH".to_string(), "/usr/bin".to_string()); - let filtered = filter_env("vm-default-deny", &env, &permissions); - assert!( - filtered.is_empty(), - "empty env policy must deny ALL env vars, leaked: {filtered:?}" - ); - - // The variant enumeration also drives a sanity check that EnvAccessRequest - // can be built for every op (keeps coverage in lock-step with the enum). - for op in all_environment_operations() { - let _request = EnvAccessRequest { - vm_id: "vm-default-deny".to_string(), - op, - key: "SECRET_TOKEN".to_string(), - value: Some("abc123".to_string()), - }; - } - - // Sanity: a NetworkAccessRequest / FsAccessRequest can likewise be built - // (guards against signature drift breaking the deny paths above). - let _ = NetworkAccessRequest { - vm_id: "vm".to_string(), - op: NetworkOperation::Fetch, - resource: "https://x".to_string(), - }; - let _ = FsAccessRequest { - vm_id: "vm".to_string(), - op: FsOperation::Read, - path: "/x".to_string(), - }; -} - -// --------------------------------------------------------------------------- -// 3: safe defaults -- no safety-critical NON-TIME resource limit is silently -// unbounded. -// --------------------------------------------------------------------------- - -#[test] -fn safety_critical_resource_limits_are_bounded_by_default() { - let limits = ResourceLimits::default(); - - // Each of these is a safety-critical, NON-TIME limit. None of them may be - // silently unbounded (i.e. they must be `Some(_)`). The closure takes the - // human-readable name so a failure points at the exact limit. - let bounded: &[(&str, bool)] = &[ - ("max_processes", limits.max_processes.is_some()), - ("max_open_fds", limits.max_open_fds.is_some()), - ("max_pipes", limits.max_pipes.is_some()), - ("max_ptys", limits.max_ptys.is_some()), - ("max_sockets", limits.max_sockets.is_some()), - ("max_connections", limits.max_connections.is_some()), - ( - "max_socket_buffered_bytes", - limits.max_socket_buffered_bytes.is_some(), - ), - ( - "max_socket_datagram_queue_len", - limits.max_socket_datagram_queue_len.is_some(), - ), - ( - "max_filesystem_bytes", - limits.max_filesystem_bytes.is_some(), - ), - ("max_inode_count", limits.max_inode_count.is_some()), - ]; - - let unbounded: Vec<&str> = bounded - .iter() - .filter(|(_, is_bounded)| !is_bounded) - .map(|(name, _)| *name) - .collect(); - - assert!( - unbounded.is_empty(), - "safety-critical NON-TIME resource limit(s) are silently unbounded by \ -default (must be Some(_)): {unbounded:?}. If a limit is intentionally being \ -made opt-in, that is a security-policy change -- review it before relaxing \ -this guard." - ); - - // Defaults must also be non-zero (a 0 cap would be unusable, and a refactor - // that zeroed them out would be just as broken as leaving them unbounded). - assert!(limits.max_processes.unwrap() > 0); - assert!(limits.max_open_fds.unwrap() > 0); - assert!(limits.max_sockets.unwrap() > 0); - assert!(limits.max_filesystem_bytes.unwrap() > 0); - assert!(limits.max_inode_count.unwrap() > 0); -} - -#[test] -fn time_budgets_remain_opt_in() { - // Documents the intentional posture: CPU / wall-clock budgets are opt-in, - // so there is no default time cap to assert. `max_blocking_read_ms` is a - // per-syscall blocking-read timeout (a safety backstop for hung reads), - // NOT a CPU/wall-clock execution budget, so we leave it untouched here. - // - // This test exists so that if someone later adds a *default* CPU/wall-clock - // cap they are reminded to reconcile it with the "time budgets are opt-in" - // decision rather than this test silently passing on stale assumptions. - let limits = ResourceLimits::default(); - // No assertion that a CPU/wall budget is set: that is correct today. - let _ = limits.max_blocking_read_ms; -} diff --git a/crates/kernel/tests/device_layer.rs b/crates/kernel/tests/device_layer.rs deleted file mode 100644 index 772d3ebbd..000000000 --- a/crates/kernel/tests/device_layer.rs +++ /dev/null @@ -1,207 +0,0 @@ -use secure_exec_kernel::device_layer::create_device_layer; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::vfs::{MemoryFileSystem, VfsResult, VirtualFileSystem}; -use std::fmt::Debug; - -fn assert_error_code(result: VfsResult, expected: &str) { - let error = result.expect_err("operation should fail"); - assert_eq!(error.code(), expected); -} - -fn create_test_vfs() -> impl VirtualFileSystem { - create_device_layer(MemoryFileSystem::new()) -} - -fn assert_not_trivial_pattern(bytes: &[u8]) { - assert!(bytes.iter().any(|byte| *byte != 0)); - assert!( - bytes.windows(2).any(|window| window[0] != window[1]), - "random data should not collapse to a repeated byte" - ); - - let first_step = bytes[1].wrapping_sub(bytes[0]); - assert!( - bytes - .windows(2) - .any(|window| window[1].wrapping_sub(window[0]) != first_step), - "random data should not look like a simple arithmetic progression" - ); -} - -#[test] -fn special_devices_expose_expected_read_and_write_behavior() { - let mut filesystem = create_test_vfs(); - - assert_eq!( - filesystem - .read_file("/dev/null") - .expect("read /dev/null") - .len(), - 0 - ); - - filesystem - .write_file("/dev/zero", "ignored") - .expect("write /dev/zero"); - let zeroes = filesystem - .pread("/dev/zero", 0, 5) - .expect("pread 5 bytes from /dev/zero"); - assert_eq!(zeroes.len(), 5); - assert!(zeroes.iter().all(|byte| *byte == 0)); - - let first = filesystem - .pread("/dev/urandom", 0, 1024) - .expect("pread /dev/urandom"); - let second = filesystem - .pread("/dev/urandom", 0, 1024 * 1024) - .expect("pread 1MiB from /dev/urandom"); - assert_eq!(first.len(), 1024); - assert_eq!(second.len(), 1024 * 1024); - assert_not_trivial_pattern(&first); - assert_not_trivial_pattern(&second[..1024]); - assert_ne!(first, second); -} - -#[test] -fn kernel_direct_device_pread_obeys_resource_limits_before_allocation() { - let mut config = KernelVmConfig::new("vm-device-pread-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_pread_bytes: Some(4), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - - let error = kernel - .pread_file("/dev/zero", 0, 5) - .expect_err("oversized direct device pread should be rejected"); - assert_eq!(error.code(), "EINVAL"); - assert!( - error.to_string().contains("pread length 5"), - "unexpected error: {error}" - ); - - assert_eq!( - kernel - .pread_file("/dev/zero", 0, 4) - .expect("bounded direct device pread should succeed"), - vec![0; 4] - ); -} - -#[test] -fn device_paths_exist_and_stat_as_devices() { - let mut filesystem = create_test_vfs(); - - for path in [ - "/dev/null", - "/dev/zero", - "/dev/stdin", - "/dev/stdout", - "/dev/stderr", - "/dev/urandom", - "/dev", - ] { - assert!(filesystem.exists(path), "{path} should exist"); - } - - let device_stat = filesystem.stat("/dev/null").expect("stat /dev/null"); - assert!(!device_stat.is_directory); - assert_eq!(device_stat.mode, 0o666); - - let dir_stat = filesystem.stat("/dev").expect("stat /dev"); - assert!(dir_stat.is_directory); - assert_eq!(dir_stat.mode, 0o755); -} - -#[test] -fn readdir_lists_known_device_entries() { - let mut filesystem = create_test_vfs(); - let entries = filesystem.read_dir("/dev").expect("read /dev"); - - assert!(entries.contains(&String::from("null"))); - assert!(entries.contains(&String::from("zero"))); - assert!(entries.contains(&String::from("stdin"))); - assert!(entries.contains(&String::from("fd"))); -} - -#[test] -fn stdio_devices_behave_like_write_sinks_without_backing_vfs_state() { - let mut filesystem = create_test_vfs(); - - assert_error_code(filesystem.read_file("/dev/stdin"), "ENOENT"); - assert_error_code(filesystem.read_file("/dev/stdout"), "ENOENT"); - assert_error_code(filesystem.read_file("/dev/stderr"), "ENOENT"); - - filesystem - .write_file("/dev/stdout", "output") - .expect("write /dev/stdout"); - filesystem - .write_file("/dev/stderr", "error output") - .expect("write /dev/stderr"); - assert_eq!( - filesystem - .append_file("/dev/stdout", "more output") - .expect("append /dev/stdout"), - "more output".len() as u64 - ); - filesystem - .truncate("/dev/stderr", 0) - .expect("truncate /dev/stderr"); - - assert_error_code(filesystem.read_file("/dev/stdout"), "ENOENT"); - assert_error_code(filesystem.read_file("/dev/stderr"), "ENOENT"); -} - -#[test] -fn mutating_device_paths_fails_closed_or_noops_like_the_legacy_layer() { - let mut filesystem = create_test_vfs(); - filesystem - .write_file("/tmp/a.txt", "data") - .expect("write regular file"); - - assert_error_code(filesystem.remove_file("/dev/null"), "EPERM"); - assert_error_code(filesystem.rename("/dev/null", "/tmp/x"), "EPERM"); - assert_error_code(filesystem.rename("/tmp/a.txt", "/dev/null"), "EPERM"); - assert_error_code(filesystem.link("/dev/null", "/tmp/devlink"), "EPERM"); - - filesystem - .truncate("/dev/null", 0) - .expect("truncate /dev/null"); - assert_eq!( - filesystem - .read_file("/dev/null") - .expect("read /dev/null") - .len(), - 0 - ); -} - -#[test] -fn realpath_and_non_device_passthrough_match_legacy_behavior() { - let mut filesystem = create_test_vfs(); - - assert_eq!( - filesystem - .realpath("/dev/null") - .expect("realpath /dev/null"), - "/dev/null" - ); - assert_eq!( - filesystem.realpath("/dev/fd").expect("realpath /dev/fd"), - "/dev/fd" - ); - - filesystem - .write_file("/tmp/test.txt", "hello") - .expect("write regular file"); - assert_eq!( - filesystem - .read_text_file("/tmp/test.txt") - .expect("read regular file"), - "hello" - ); -} diff --git a/crates/kernel/tests/dns_resolution.rs b/crates/kernel/tests/dns_resolution.rs deleted file mode 100644 index c56a28220..000000000 --- a/crates/kernel/tests/dns_resolution.rs +++ /dev/null @@ -1,207 +0,0 @@ -use hickory_resolver::proto::rr::{Record, RecordType}; -use secure_exec_kernel::dns::{ - DnsConfig, DnsLookupPolicy, DnsLookupRequest, DnsRecordLookupRequest, DnsResolver, - DnsResolverError, -}; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig}; -use secure_exec_kernel::permissions::{ - NetworkAccessRequest, NetworkOperation, PermissionDecision, Permissions, -}; -use secure_exec_kernel::vfs::MemoryFileSystem; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -use std::sync::{Arc, Mutex}; - -#[derive(Debug, Clone)] -struct MockDnsResolver { - requests: Arc>>, - record_requests: Arc>>, - response: Vec, -} - -impl MockDnsResolver { - fn new(response: Vec) -> Self { - Self { - requests: Arc::new(Mutex::new(Vec::new())), - record_requests: Arc::new(Mutex::new(Vec::new())), - response, - } - } - - fn requests(&self) -> Vec { - self.requests.lock().expect("mock requests").clone() - } - - fn record_requests(&self) -> Vec { - self.record_requests - .lock() - .expect("mock record requests") - .clone() - } -} - -impl DnsResolver for MockDnsResolver { - fn lookup_ip(&self, request: &DnsLookupRequest) -> Result, DnsResolverError> { - self.requests - .lock() - .expect("mock requests") - .push(request.clone()); - Ok(self.response.clone()) - } - - fn lookup_records( - &self, - request: &DnsRecordLookupRequest, - ) -> Result, DnsResolverError> { - self.record_requests - .lock() - .expect("mock record requests") - .push(request.clone()); - Ok(Vec::new()) - } -} - -fn new_kernel(config: KernelVmConfig) -> KernelVm { - KernelVm::new(MemoryFileSystem::new(), config) -} - -#[test] -fn kernel_dns_resolution_prefers_overrides_before_the_resolver() { - let resolver = MockDnsResolver::new(vec![IpAddr::V4(Ipv4Addr::new(198, 51, 100, 44))]); - let mut config = KernelVmConfig::new("vm-dns-override"); - config.permissions = Permissions::allow_all(); - config.dns = DnsConfig { - name_servers: vec!["203.0.113.53:5353" - .parse::() - .expect("nameserver")], - overrides: std::iter::once(( - String::from("example.test"), - vec![IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))], - )) - .collect(), - }; - config.dns_resolver = Arc::new(resolver.clone()); - let kernel = new_kernel(config); - - let resolution = kernel - .resolve_dns(" Example.Test. ", DnsLookupPolicy::CheckPermissions) - .expect("resolve override hostname"); - - assert_eq!(resolution.hostname(), "example.test"); - assert_eq!(resolution.source().as_str(), "override"); - assert_eq!( - resolution.addresses(), - &[IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))] - ); - assert!( - resolver.requests().is_empty(), - "override lookup should not reach the resolver" - ); -} - -#[test] -fn kernel_dns_resolution_passes_vm_nameservers_into_the_resolver() { - let resolver = MockDnsResolver::new(vec![ - IpAddr::V4(Ipv4Addr::new(198, 51, 100, 7)), - IpAddr::V4(Ipv4Addr::new(198, 51, 100, 7)), - ]); - let mut config = KernelVmConfig::new("vm-dns-resolver"); - config.permissions = Permissions::allow_all(); - config.dns = DnsConfig { - name_servers: vec!["203.0.113.53:5353" - .parse::() - .expect("nameserver")], - overrides: Default::default(), - }; - config.dns_resolver = Arc::new(resolver.clone()); - let kernel = new_kernel(config); - - let resolution = kernel - .resolve_dns("resolver.example.test", DnsLookupPolicy::CheckPermissions) - .expect("resolve via mock resolver"); - - assert_eq!(resolution.source().as_str(), "resolver"); - assert_eq!( - resolution.addresses(), - &[IpAddr::V4(Ipv4Addr::new(198, 51, 100, 7))] - ); - - let requests = resolver.requests(); - assert_eq!(requests.len(), 1); - assert_eq!(requests[0].hostname(), "resolver.example.test"); - assert_eq!( - requests[0].name_servers(), - &["203.0.113.53:5353" - .parse::() - .expect("nameserver")] - ); -} - -#[test] -fn kernel_dns_resolution_checks_network_permissions_when_requested() { - let permission_requests = Arc::new(Mutex::new(Vec::::new())); - let permission_requests_for_check = Arc::clone(&permission_requests); - let resolver = MockDnsResolver::new(vec![IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))]); - let mut config = KernelVmConfig::new("vm-dns-permissions"); - config.permissions = Permissions { - network: Some(Arc::new(move |request: &NetworkAccessRequest| { - permission_requests_for_check - .lock() - .expect("permission requests") - .push(request.clone()); - PermissionDecision::deny("dns denied") - })), - ..Permissions::allow_all() - }; - config.dns_resolver = Arc::new(resolver); - let kernel = new_kernel(config); - - let error = kernel - .resolve_dns("example.test", DnsLookupPolicy::CheckPermissions) - .expect_err("dns permission should deny lookup"); - assert_eq!(error.code(), "EACCES"); - - let requests = permission_requests.lock().expect("permission requests"); - assert_eq!(requests.len(), 1); - assert_eq!(requests[0].vm_id, "vm-dns-permissions"); - assert_eq!(requests[0].op, NetworkOperation::Dns); - assert_eq!(requests[0].resource, "dns://example.test"); -} - -#[test] -fn kernel_dns_resolution_denies_by_default_before_resolver_lookup() { - let resolver = MockDnsResolver::new(vec![IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))]); - let mut config = KernelVmConfig::new("vm-dns-default-deny"); - config.dns_resolver = Arc::new(resolver.clone()); - let kernel = new_kernel(config); - - let lookup_error = kernel - .resolve_dns("example.test", DnsLookupPolicy::CheckPermissions) - .expect_err("missing network hook should deny address lookup"); - assert_eq!(lookup_error.code(), "EACCES"); - assert!( - lookup_error.to_string().contains("dns://example.test"), - "unexpected error: {lookup_error}" - ); - - let record_error = kernel - .resolve_dns_records( - "example.test", - RecordType::A, - DnsLookupPolicy::CheckPermissions, - ) - .expect_err("missing network hook should deny record lookup"); - assert_eq!(record_error.code(), "EACCES"); - assert!( - record_error.to_string().contains("dns://example.test"), - "unexpected error: {record_error}" - ); - - assert!( - resolver.requests().is_empty(), - "permission denial should happen before address resolver lookup" - ); - assert!( - resolver.record_requests().is_empty(), - "permission denial should happen before record resolver lookup" - ); -} diff --git a/crates/kernel/tests/fd_table.rs b/crates/kernel/tests/fd_table.rs deleted file mode 100644 index cbd9d95b1..000000000 --- a/crates/kernel/tests/fd_table.rs +++ /dev/null @@ -1,462 +0,0 @@ -use secure_exec_kernel::fd_table::{ - FdResult, FdTableManager, FileDescription, FileLockManager, FileLockTarget, FlockOperation, - FD_CLOEXEC, FILETYPE_CHARACTER_DEVICE, FILETYPE_REGULAR_FILE, F_DUPFD, F_GETFD, F_GETFL, - F_SETFD, F_SETFL, LOCK_EX, LOCK_NB, LOCK_SH, LOCK_UN, MAX_FDS_PER_PROCESS, O_APPEND, - O_NONBLOCK, O_RDONLY, O_WRONLY, -}; -use std::fmt::Debug; -use std::sync::Arc; - -fn assert_error_code(result: FdResult, expected: &str) { - let error = result.expect_err("operation should fail"); - assert_eq!(error.code(), expected); -} - -#[test] -fn preallocates_stdio_fds_0_1_2() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get(1).expect("FD table should exist"); - let stdin = table.get(0).expect("stdin entry"); - let stdout = table.get(1).expect("stdout entry"); - let stderr = table.get(2).expect("stderr entry"); - - assert_eq!(stdin.filetype, FILETYPE_CHARACTER_DEVICE); - assert_eq!(stdout.filetype, FILETYPE_CHARACTER_DEVICE); - assert_eq!(stderr.filetype, FILETYPE_CHARACTER_DEVICE); - - assert_eq!(stdin.description.flags(), O_RDONLY); - assert_eq!(stdout.description.flags(), O_WRONLY); - assert_eq!(stderr.description.flags(), O_WRONLY); -} - -#[test] -fn opens_new_fds_starting_at_three() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let fd = manager - .get_mut(1) - .expect("FD table should exist") - .open("/tmp/test.txt", O_RDONLY) - .expect("open regular file"); - - assert_eq!(fd, 3); -} - -#[test] -fn dup_shares_the_same_file_description() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let fd = table - .open("/tmp/test.txt", O_RDONLY) - .expect("open source FD"); - let dup_fd = table.dup(fd).expect("duplicate FD"); - - let original = Arc::clone(&table.get(fd).expect("source entry").description); - let duplicated = Arc::clone(&table.get(dup_fd).expect("dup entry").description); - - assert_ne!(dup_fd, fd); - assert!(Arc::ptr_eq(&original, &duplicated)); -} - -#[test] -fn dup2_replaces_the_target_fd() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let fd = table - .open("/tmp/test.txt", O_RDONLY) - .expect("open source FD"); - table.dup2(fd, 10).expect("dup2 into target FD"); - - let source = Arc::clone(&table.get(fd).expect("source entry").description); - let target = Arc::clone(&table.get(10).expect("target entry").description); - - assert!(Arc::ptr_eq(&source, &target)); -} - -#[test] -fn dup2_rejects_target_fds_past_the_process_limit() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let fd = table - .open("/tmp/test.txt", O_RDONLY) - .expect("open source FD"); - let result = table.dup2(fd, MAX_FDS_PER_PROCESS as u32); - - assert_error_code(result, "EBADF"); -} - -#[test] -fn open_with_rejects_target_fds_past_the_process_limit() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let description = Arc::new(FileDescription::new(999, "/tmp/test.txt", O_RDONLY)); - let result = table.open_with( - description, - FILETYPE_REGULAR_FILE, - Some(MAX_FDS_PER_PROCESS as u32), - ); - - assert_error_code(result, "EBADF"); -} - -#[test] -fn open_with_replaces_target_fd_and_releases_previous_entry() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let target_fd = table - .open("/tmp/old.txt", O_RDONLY) - .expect("open target FD"); - let previous = Arc::clone(&table.get(target_fd).expect("target entry").description); - let replacement = Arc::new(FileDescription::new(999, "/tmp/new.txt", O_RDONLY)); - - assert_eq!(previous.ref_count(), 1); - - let opened = table - .open_with( - Arc::clone(&replacement), - FILETYPE_REGULAR_FILE, - Some(target_fd), - ) - .expect("replace target FD"); - - assert_eq!(opened, target_fd); - assert_eq!(previous.ref_count(), 0); - assert_eq!(replacement.ref_count(), 2); - assert!(Arc::ptr_eq( - &table.get(target_fd).expect("replacement entry").description, - &replacement - )); -} - -#[test] -fn configurable_process_fd_limit_returns_emfile() { - let mut manager = FdTableManager::with_max_fds(5); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - table - .open("/tmp/test-1.txt", O_RDONLY) - .expect("first non-stdio FD should open"); - table - .open("/tmp/test-2.txt", O_RDONLY) - .expect("second non-stdio FD should open"); - - let result = table.open("/tmp/test-3.txt", O_RDONLY); - assert_error_code(result, "EMFILE"); -} - -#[test] -fn close_decrements_refcount() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let fd = table - .open("/tmp/test.txt", O_RDONLY) - .expect("open source FD"); - let dup_fd = table.dup(fd).expect("duplicate FD"); - let description = Arc::clone(&table.get(fd).expect("source entry").description); - - assert_eq!(description.ref_count(), 2); - assert!(table.close(dup_fd)); - assert_eq!(description.ref_count(), 1); -} - -#[test] -fn fork_creates_an_independent_table_with_shared_descriptions() { - let mut manager = FdTableManager::new(); - manager.create(1); - let fd = manager - .get_mut(1) - .expect("parent table should exist") - .open("/tmp/test.txt", O_RDONLY) - .expect("open source FD"); - - manager.fork(1, 2); - - let parent_description = Arc::clone( - &manager - .get(1) - .expect("parent table should exist") - .get(fd) - .expect("parent FD entry") - .description, - ); - let child_description = { - let child = manager.get_mut(2).expect("child table should exist"); - let description = Arc::clone(&child.get(fd).expect("child FD entry").description); - assert!(child.close(fd)); - description - }; - - assert!(Arc::ptr_eq(&parent_description, &child_description)); - assert!(manager - .get(1) - .expect("parent table should still exist") - .get(fd) - .is_some()); -} - -#[test] -fn stat_returns_fd_metadata() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let fd = manager - .get_mut(1) - .expect("FD table should exist") - .open_with_filetype("/tmp/test.txt", O_WRONLY, FILETYPE_REGULAR_FILE) - .expect("open regular file"); - let stat = manager - .get(1) - .expect("FD table should exist") - .stat(fd) - .expect("stat FD"); - - assert_eq!(stat.filetype, FILETYPE_REGULAR_FILE); - assert_eq!(stat.flags, O_WRONLY); -} - -#[test] -fn nonblocking_status_flags_are_tracked_per_fd_entry() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let fd = table - .open_with_filetype( - "/tmp/test.txt", - O_WRONLY | O_NONBLOCK, - FILETYPE_REGULAR_FILE, - ) - .expect("open regular file"); - let dup_fd = table - .dup_with_status_flags(fd, Some(0)) - .expect("duplicate regular file without nonblocking"); - - let original = table.stat(fd).expect("stat original FD"); - let duplicated = table.stat(dup_fd).expect("stat duplicate FD"); - - assert_eq!(original.flags, O_WRONLY | O_NONBLOCK); - assert_eq!(duplicated.flags, O_WRONLY); - assert_eq!( - table.get(fd).expect("original entry").description.flags(), - O_WRONLY - ); - assert_eq!( - table - .get(dup_fd) - .expect("duplicate entry") - .description - .flags(), - O_WRONLY - ); -} - -#[test] -fn fcntl_getfl_and_setfl_report_visible_status_flags() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let fd = table - .open_with_filetype("/tmp/test.txt", O_WRONLY | O_APPEND, FILETYPE_REGULAR_FILE) - .expect("open append file"); - - assert_eq!( - table.fcntl(fd, F_GETFL, 0).expect("initial F_GETFL"), - O_WRONLY | O_APPEND - ); - - table - .fcntl(fd, F_SETFL, O_APPEND | O_NONBLOCK) - .expect("set append and nonblocking"); - - assert_eq!( - table.fcntl(fd, F_GETFL, 0).expect("updated F_GETFL"), - O_WRONLY | O_APPEND | O_NONBLOCK - ); - assert_eq!( - table.stat(fd).expect("stat after F_SETFL").flags, - O_WRONLY | O_APPEND | O_NONBLOCK - ); -} - -#[test] -fn fcntl_fd_flags_are_per_descriptor() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let fd = table - .open("/tmp/test.txt", O_RDONLY) - .expect("open source FD"); - let dup_fd = table.dup(fd).expect("duplicate FD"); - - table - .fcntl(fd, F_SETFD, FD_CLOEXEC) - .expect("set cloexec on source"); - - assert_eq!( - table.fcntl(fd, F_GETFD, 0).expect("read source FD flags"), - FD_CLOEXEC - ); - assert_eq!( - table - .fcntl(dup_fd, F_GETFD, 0) - .expect("read duplicate FD flags"), - 0 - ); -} - -#[test] -fn fcntl_dupfd_uses_lowest_available_fd_at_or_above_minimum() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let fd = table - .open("/tmp/test.txt", O_RDONLY) - .expect("open source FD"); - let filler_a = table.open("/tmp/a.txt", O_RDONLY).expect("open filler a"); - let filler_b = table.open("/tmp/b.txt", O_RDONLY).expect("open filler b"); - let filler_c = table.open("/tmp/c.txt", O_RDONLY).expect("open filler c"); - assert_eq!((fd, filler_a, filler_b, filler_c), (3, 4, 5, 6)); - - assert!(table.close(5), "fd 5 should be available for F_DUPFD reuse"); - - let duplicated = table - .fcntl(fd, F_DUPFD, 5) - .expect("duplicate into lowest fd >= 5"); - - assert_eq!(duplicated, 5); - assert_eq!( - table - .fcntl(duplicated, F_GETFD, 0) - .expect("new duplicate should clear FD flags"), - 0 - ); -} - -#[test] -fn fcntl_dupfd_rejects_minimum_fd_past_the_process_limit() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let fd = table - .open("/tmp/test.txt", O_RDONLY) - .expect("open source FD"); - - assert_error_code( - table.fcntl(fd, F_DUPFD, MAX_FDS_PER_PROCESS as u32), - "EINVAL", - ); -} - -#[test] -fn stat_reports_ebadf_for_invalid_fd() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let result = manager.get(1).expect("FD table should exist").stat(999); - - assert_error_code(result, "EBADF"); -} - -#[test] -fn open_reuses_a_freed_fd_after_next_fd_moves_past_the_limit() { - let mut manager = FdTableManager::new(); - manager.create(1); - - let table = manager.get_mut(1).expect("FD table should exist"); - let mut opened = Vec::new(); - for _ in 3..MAX_FDS_PER_PROCESS { - opened.push( - table - .open("/tmp/test.txt", O_RDONLY) - .expect("open should fill remaining slots"), - ); - } - - assert!(table.close(5), "fd 5 should be open before reuse"); - - let reused = table - .open("/tmp/reused.txt", O_RDONLY) - .expect("open should wrap and reuse a freed fd"); - assert_eq!(reused, 5); -} - -#[test] -fn flock_operation_parser_accepts_supported_modes() { - assert_eq!( - FlockOperation::from_bits(LOCK_SH).expect("shared operation"), - FlockOperation::Shared { nonblocking: false } - ); - assert_eq!( - FlockOperation::from_bits(LOCK_EX | LOCK_NB).expect("exclusive nonblocking operation"), - FlockOperation::Exclusive { nonblocking: true } - ); - assert_eq!( - FlockOperation::from_bits(LOCK_UN).expect("unlock operation"), - FlockOperation::Unlock - ); -} - -#[test] -fn flock_manager_enforces_shared_and_exclusive_conflicts() { - let locks = FileLockManager::new(); - let target = FileLockTarget::new(42); - - locks - .apply(1, target, FlockOperation::Shared { nonblocking: false }) - .expect("first shared lock"); - locks - .apply(2, target, FlockOperation::Shared { nonblocking: false }) - .expect("second shared lock"); - - let blocked = locks.apply(3, target, FlockOperation::Exclusive { nonblocking: true }); - assert_error_code(blocked, "EWOULDBLOCK"); - - locks - .apply(1, target, FlockOperation::Unlock) - .expect("unlock first shared lock"); - locks - .apply(2, target, FlockOperation::Unlock) - .expect("unlock second shared lock"); - locks - .apply(3, target, FlockOperation::Exclusive { nonblocking: true }) - .expect("exclusive lock becomes available"); -} - -#[test] -fn flock_manager_treats_reacquire_on_same_description_as_non_conflicting() { - let locks = FileLockManager::new(); - let target = FileLockTarget::new(7); - - locks - .apply(99, target, FlockOperation::Exclusive { nonblocking: false }) - .expect("initial exclusive lock"); - locks - .apply(99, target, FlockOperation::Exclusive { nonblocking: true }) - .expect("same description can reacquire exclusive lock"); - locks - .apply(99, target, FlockOperation::Shared { nonblocking: true }) - .expect("same description can downgrade to shared lock"); - - let shared = locks.apply(100, target, FlockOperation::Shared { nonblocking: true }); - shared.expect("downgrade should allow other shared holders"); -} diff --git a/crates/kernel/tests/identity.rs b/crates/kernel/tests/identity.rs deleted file mode 100644 index 4c5cb9ca1..000000000 --- a/crates/kernel/tests/identity.rs +++ /dev/null @@ -1,216 +0,0 @@ -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, VirtualProcessOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::user::UserConfig; -use secure_exec_kernel::vfs::MemoryFileSystem; -use std::collections::BTreeMap; -use std::thread; -use std::time::Duration; - -fn configured_kernel() -> KernelVm { - let mut config = KernelVmConfig::new("vm-identity"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_wasm_memory_bytes: Some(256 * 1024 * 1024), - ..ResourceLimits::default() - }; - config.user = UserConfig { - uid: Some(501), - gid: Some(502), - euid: Some(700), - egid: Some(701), - username: Some(String::from("deploy")), - homedir: Some(String::from("/srv/deploy")), - shell: Some(String::from("/bin/bash")), - gecos: Some(String::from("Deploy User")), - group_name: Some(String::from("deployers")), - supplementary_gids: vec![44, 502, 900], - }; - KernelVm::new(MemoryFileSystem::new(), config) -} - -fn read_utf8(kernel: &mut KernelVm, path: &str) -> String { - String::from_utf8(kernel.read_file(path).expect("read proc file")).expect("utf8 proc file") -} - -fn read_utf8_for_process( - kernel: &mut KernelVm, - requester_driver: &str, - pid: u32, - path: &str, -) -> String { - String::from_utf8( - kernel - .read_file_for_process(requester_driver, pid, path) - .expect("read proc file for process"), - ) - .expect("utf8 proc file") -} - -fn parse_status_fields(body: &str) -> BTreeMap<&str, &str> { - body.lines() - .filter_map(|line| line.split_once(':')) - .map(|(key, value)| (key, value.trim())) - .collect() -} - -#[test] -fn identity_syscalls_and_process_metadata_use_kernel_managed_values() { - let mut kernel = configured_kernel(); - - let process = kernel - .create_virtual_process( - "identity-driver", - "identity-driver", - "identity-check", - Vec::new(), - VirtualProcessOptions::default(), - ) - .expect("create identity process"); - let pid = process.pid(); - - assert_eq!( - kernel - .process_identity("identity-driver", pid) - .expect("read process identity") - .supplementary_gids, - vec![502, 44, 900] - ); - assert_eq!(kernel.getuid("identity-driver", pid).expect("getuid"), 501); - assert_eq!(kernel.getgid("identity-driver", pid).expect("getgid"), 502); - assert_eq!( - kernel.geteuid("identity-driver", pid).expect("geteuid"), - 700 - ); - assert_eq!( - kernel.getegid("identity-driver", pid).expect("getegid"), - 701 - ); - assert_eq!( - kernel.getgroups("identity-driver", pid).expect("getgroups"), - vec![502, 44, 900] - ); - - let process_info = kernel - .list_processes() - .get(&pid) - .expect("process info") - .clone(); - assert_eq!(process_info.identity.uid, 501); - assert_eq!(process_info.identity.gid, 502); - assert_eq!(process_info.identity.euid, 700); - assert_eq!(process_info.identity.egid, 701); - assert_eq!(process_info.identity.supplementary_gids, vec![502, 44, 900]); - - assert_eq!( - kernel.getpwuid(501).expect("primary uid lookup"), - "deploy:x:501:502:Deploy User:/srv/deploy:/bin/bash" - ); - let unknown_uid = kernel.getpwuid(77).expect_err("unknown uid should fail"); - assert_eq!(unknown_uid.code(), "ENOENT"); - assert_eq!( - kernel.getgrgid(502).expect("primary gid lookup"), - "deployers:x:502:deploy" - ); - assert_eq!( - kernel.getgrgid(44).expect("supplementary gid lookup"), - "group44:x:44:deploy" - ); - let unknown_gid = kernel.getgrgid(77).expect_err("unknown gid should fail"); - assert_eq!(unknown_gid.code(), "ENOENT"); -} - -#[test] -fn identity_queries_require_process_ownership() { - let mut kernel = configured_kernel(); - let process = kernel - .create_virtual_process( - "identity-driver", - "identity-driver", - "identity-check", - Vec::new(), - VirtualProcessOptions::default(), - ) - .expect("create identity process"); - - let error = kernel - .getuid("other-driver", process.pid()) - .expect_err("foreign driver should be rejected"); - assert_eq!(error.code(), "EPERM"); -} - -#[test] -fn procfs_exposes_linux_like_identity_and_system_files() { - let mut kernel = configured_kernel(); - let process = kernel - .create_virtual_process( - "identity-driver", - "identity-driver", - "identity-check", - Vec::new(), - VirtualProcessOptions::default(), - ) - .expect("create identity process"); - let pid = process.pid(); - - let proc_entries = kernel.read_dir("/proc").expect("read /proc"); - assert!(proc_entries.contains(&String::from("cpuinfo"))); - assert!(proc_entries.contains(&String::from("loadavg"))); - assert!(proc_entries.contains(&String::from("meminfo"))); - assert!(proc_entries.contains(&String::from("mounts"))); - assert!(proc_entries.contains(&String::from("self"))); - assert!(proc_entries.contains(&String::from("uptime"))); - assert!(proc_entries.contains(&String::from("version"))); - assert!(proc_entries.contains(&pid.to_string())); - - let pid_entries = kernel - .read_dir(&format!("/proc/{pid}")) - .expect("read /proc/"); - assert!(pid_entries.contains(&String::from("status"))); - - let status = read_utf8(&mut kernel, &format!("/proc/{pid}/status")); - let self_status = - read_utf8_for_process(&mut kernel, "identity-driver", pid, "/proc/self/status"); - assert_eq!(status, self_status); - - let status_fields = parse_status_fields(&status); - assert_eq!(status_fields["Name"], "identity-check"); - assert_eq!(status_fields["State"], "R (running)"); - assert_eq!(status_fields["Pid"], pid.to_string()); - assert_eq!(status_fields["PPid"], "0"); - assert_eq!(status_fields["Uid"], "501\t700\t700\t700"); - assert_eq!(status_fields["Gid"], "502\t701\t701\t701"); - assert_eq!(status_fields["VmSize"], "0 kB"); - assert_eq!(status_fields["VmRSS"], "0 kB"); - assert_eq!(status_fields["Threads"], "1"); - - let cpuinfo = read_utf8(&mut kernel, "/proc/cpuinfo"); - assert!(cpuinfo.contains("processor\t: 0")); - assert!(cpuinfo.contains("model name\t: secure-exec Virtual CPU")); - - let meminfo = read_utf8(&mut kernel, "/proc/meminfo"); - assert!(meminfo.contains("MemTotal: 262144 kB")); - assert!(meminfo.contains("MemFree: 262144 kB")); - assert!(meminfo.contains("MemAvailable:262144 kB")); - - let loadavg = read_utf8(&mut kernel, "/proc/loadavg"); - assert!(loadavg.starts_with("0.00 0.00 0.00 1/1 ")); - assert!(loadavg.ends_with('\n')); - - thread::sleep(Duration::from_millis(20)); - let uptime = read_utf8(&mut kernel, "/proc/uptime"); - let uptime_parts = uptime.split_whitespace().collect::>(); - assert_eq!(uptime_parts.len(), 2); - let uptime_seconds = uptime_parts[0].parse::().expect("uptime seconds"); - let idle_seconds = uptime_parts[1].parse::().expect("idle seconds"); - assert!(uptime_seconds > 0.0); - assert!(idle_seconds >= uptime_seconds); - - let version = read_utf8(&mut kernel, "/proc/version"); - assert!(version.starts_with("Linux version 6.8.0-agentos")); - - let status_stat = kernel - .stat(&format!("/proc/{pid}/status")) - .expect("stat proc status"); - assert_eq!(status_stat.size, status.len() as u64); -} diff --git a/crates/kernel/tests/kernel_integration.rs b/crates/kernel/tests/kernel_integration.rs deleted file mode 100644 index df4a1b1b5..000000000 --- a/crates/kernel/tests/kernel_integration.rs +++ /dev/null @@ -1,347 +0,0 @@ -use secure_exec_kernel::bridge::LifecycleState; -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::process_table::SIGPIPE; -use secure_exec_kernel::pty::LineDisciplineConfig; -use secure_exec_kernel::vfs::MemoryFileSystem; -use std::time::Duration; - -#[test] -fn minimal_vm_lifecycle_transitions_between_ready_busy_and_terminated() { - let mut config = KernelVmConfig::new("vm-kernel"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - assert_eq!(kernel.state(), LifecycleState::Ready); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - assert_eq!(kernel.state(), LifecycleState::Busy); - - let (master_fd, slave_fd, path) = kernel.open_pty("shell", process.pid()).expect("open pty"); - assert!(path.starts_with("/dev/pts/")); - kernel - .pty_set_discipline( - "shell", - process.pid(), - master_fd, - LineDisciplineConfig { - canonical: Some(false), - echo: Some(false), - isig: Some(false), - ..Default::default() - }, - ) - .expect("set raw mode"); - - kernel - .fd_write("shell", process.pid(), master_fd, b"kernel-ready") - .expect("write PTY input"); - let data = kernel - .fd_read("shell", process.pid(), slave_fd, 64) - .expect("read PTY slave"); - assert_eq!(String::from_utf8(data).expect("valid utf8"), "kernel-ready"); - - process.finish(0); - let (_, exit_code) = kernel.wait_and_reap(process.pid()).expect("reap shell"); - assert_eq!(exit_code, 0); - assert_eq!(kernel.state(), LifecycleState::Ready); - assert_eq!(kernel.resource_snapshot().fd_tables, 0); - assert_eq!(kernel.resource_snapshot().open_fds, 0); - - kernel.dispose().expect("dispose kernel"); - assert_eq!(kernel.state(), LifecycleState::Terminated); -} - -#[test] -fn dispose_kills_running_processes_and_cleans_special_resources() { - let mut config = KernelVmConfig::new("vm-dispose"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - let _ = kernel.open_pipe("shell", process.pid()).expect("open pipe"); - let _ = kernel.open_pty("shell", process.pid()).expect("open pty"); - - kernel.dispose().expect("dispose kernel"); - assert_eq!(kernel.state(), LifecycleState::Terminated); - assert_eq!(process.wait(Duration::from_millis(50)), Some(143)); - assert_eq!(process.kill_signals(), vec![15]); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.fd_tables, 0); - assert_eq!(snapshot.open_fds, 0); - assert_eq!(snapshot.pipes, 0); - assert_eq!(snapshot.ptys, 0); -} - -#[test] -fn process_exit_cleanup_closes_pipe_writers_and_returns_eof_to_readers() { - let mut config = KernelVmConfig::new("vm-process-exit-pipe"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let writer = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn writer"); - let (read_fd, write_fd) = kernel - .open_pipe("shell", writer.pid()) - .expect("open writer pipe"); - let reader = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - parent_pid: Some(writer.pid()), - ..SpawnOptions::default() - }, - ) - .expect("spawn reader"); - - kernel - .fd_close("shell", reader.pid(), write_fd) - .expect("close inherited write end"); - kernel - .fd_write("shell", writer.pid(), write_fd, b"before-exit") - .expect("write pipe contents"); - let bytes = kernel - .fd_read("shell", reader.pid(), read_fd, 64) - .expect("read pipe contents"); - assert_eq!(String::from_utf8(bytes).expect("valid utf8"), "before-exit"); - - writer.finish(0); - assert_eq!( - kernel - .open_pipe("shell", writer.pid()) - .expect_err("exited writer should lose PID ownership") - .code(), - "ESRCH" - ); - - let eof = kernel - .fd_read("shell", reader.pid(), read_fd, 64) - .expect("read EOF after writer exit"); - assert!(eof.is_empty()); -} - -#[test] -fn broken_pipe_writes_deliver_sigpipe_and_return_epipe() { - let mut config = KernelVmConfig::new("vm-broken-pipe-sigpipe"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let writer = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn writer"); - let (read_fd, write_fd) = kernel - .open_pipe("shell", writer.pid()) - .expect("open writer pipe"); - - kernel - .fd_close("shell", writer.pid(), read_fd) - .expect("close inherited read end"); - - let error = kernel - .fd_write("shell", writer.pid(), write_fd, b"fail") - .expect_err("broken pipe writes should fail"); - assert_eq!(error.code(), "EPIPE"); - assert_eq!(writer.kill_signals(), vec![SIGPIPE]); - assert_eq!(writer.wait(Duration::from_millis(50)), Some(128 + SIGPIPE)); -} - -#[test] -fn process_exit_cleanup_removes_fd_tables_before_and_after_reap() { - let mut config = KernelVmConfig::new("vm-process-exit-fds"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn process"); - let _ = kernel.open_pipe("shell", process.pid()).expect("open pipe"); - let _ = kernel.open_pty("shell", process.pid()).expect("open pty"); - - process.finish(0); - - let snapshot_after_exit = kernel.resource_snapshot(); - assert_eq!(snapshot_after_exit.fd_tables, 0); - assert_eq!(snapshot_after_exit.open_fds, 0); - assert_eq!(snapshot_after_exit.pipes, 0); - assert_eq!(snapshot_after_exit.ptys, 0); - - let (_, exit_code) = kernel - .wait_and_reap(process.pid()) - .expect("wait and reap exited process"); - assert_eq!(exit_code, 0); - - let snapshot_after_reap = kernel.resource_snapshot(); - assert_eq!(snapshot_after_reap.fd_tables, 0); - assert_eq!(snapshot_after_reap.open_fds, 0); - assert_eq!( - kernel - .fd_stat("shell", process.pid(), 0) - .expect_err("reaped process should not keep FD entries") - .code(), - "ESRCH" - ); -} - -#[test] -fn spawn_process_executes_shebang_scripts_with_registered_interpreters() { - let mut config = KernelVmConfig::new("vm-shebang"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .register_driver(CommandDriver::new("node", ["node"])) - .expect("register node"); - - kernel - .write_file("/tmp/script.sh", b"#!/bin/sh -eu\necho shell\n".to_vec()) - .expect("write shell script"); - kernel - .chmod("/tmp/script.sh", 0o755) - .expect("chmod shell script"); - let shell_process = kernel - .spawn_process( - "/tmp/script.sh", - vec![String::from("arg")], - SpawnOptions::default(), - ) - .expect("spawn shell script"); - assert_eq!( - kernel - .read_file(&format!("/proc/{}/cmdline", shell_process.pid())) - .expect("read shell cmdline"), - b"sh\0-eu\0/tmp/script.sh\0arg\0".to_vec() - ); - - kernel - .write_file( - "/tmp/script.mjs", - b"#!/usr/bin/env node --trace-warnings\nconsole.log('node');\n".to_vec(), - ) - .expect("write node script"); - kernel - .chmod("/tmp/script.mjs", 0o755) - .expect("chmod node script"); - let node_process = kernel - .spawn_process("/tmp/script.mjs", Vec::new(), SpawnOptions::default()) - .expect("spawn node script"); - assert_eq!( - kernel - .read_file(&format!("/proc/{}/cmdline", node_process.pid())) - .expect("read node cmdline"), - b"node\0--trace-warnings\0/tmp/script.mjs\0".to_vec() - ); -} - -#[test] -fn spawn_process_rejects_invalid_shebang_scripts() { - let mut config = KernelVmConfig::new("vm-shebang-errors"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - kernel - .write_file("/tmp/missing.sh", b"#!/missing/interpreter\n".to_vec()) - .expect("write missing-interpreter script"); - kernel - .chmod("/tmp/missing.sh", 0o755) - .expect("chmod missing-interpreter script"); - let missing = kernel - .spawn_process("/tmp/missing.sh", Vec::new(), SpawnOptions::default()) - .expect_err("missing interpreter should fail"); - assert_eq!(missing.code(), "ENOENT"); - - let long_shebang = format!("#!/{0}\n", "a".repeat(256)); - kernel - .write_file("/tmp/long.sh", long_shebang.into_bytes()) - .expect("write long-shebang script"); - kernel - .chmod("/tmp/long.sh", 0o755) - .expect("chmod long-shebang script"); - let long_error = kernel - .spawn_process("/tmp/long.sh", Vec::new(), SpawnOptions::default()) - .expect_err("overlong shebang should fail"); - assert_eq!(long_error.code(), "ENOEXEC"); -} - -#[test] -fn driver_registration_rejects_command_names_that_escape_bin_stubs() { - let mut config = KernelVmConfig::new("vm-command-registry-traversal"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - - let error = kernel - .register_driver(CommandDriver::new("malicious", ["safe", "../escape"])) - .expect_err("path-like command names should be rejected"); - - assert_eq!(error.code(), "EINVAL"); - assert!( - error.to_string().contains("invalid command name"), - "unexpected error: {error}" - ); - assert!(!kernel.exists("/bin").expect("check /bin")); - assert!(!kernel.exists("/bin/safe").expect("check safe stub")); - assert!(!kernel.exists("/escape").expect("check escaped stub")); -} diff --git a/crates/kernel/tests/loopback_routing.rs b/crates/kernel/tests/loopback_routing.rs deleted file mode 100644 index 9dc9acf5d..000000000 --- a/crates/kernel/tests/loopback_routing.rs +++ /dev/null @@ -1,707 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelProcessHandle, KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::socket_table::{ - InetSocketAddress, SocketReadiness, SocketReadinessKind, SocketSpec, SocketState, -}; -use secure_exec_kernel::vfs::MemoryFileSystem; -use std::sync::{Arc, Mutex}; - -fn spawn_shell(kernel: &mut KernelVm) -> KernelProcessHandle { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") -} - -fn new_kernel(vm_id: &str) -> KernelVm { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel -} - -fn take_readiness_events(events: &Arc>>) -> Vec { - let mut events = events.lock().expect("readiness events lock"); - std::mem::take(&mut *events) -} - -#[test] -fn kernel_loopback_connect_routes_into_guest_listener_and_accepts_connected_socket() { - let mut kernel = new_kernel("vm-loopback-tcp"); - let server = spawn_shell(&mut kernel); - let client = spawn_shell(&mut kernel); - - let listener = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create listener"); - kernel - .socket_bind_inet( - "shell", - server.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 43131), - ) - .expect("bind listener"); - kernel - .socket_listen("shell", server.pid(), listener, 1) - .expect("listen"); - - let client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::tcp()) - .expect("create client socket"); - kernel - .socket_bind_inet( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("127.0.0.1", 54031), - ) - .expect("bind client"); - - kernel - .socket_connect_inet_loopback( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("localhost", 43131), - ) - .expect("route loopback connect"); - - let listener_record = kernel.socket_get(listener).expect("listener record"); - assert_eq!(listener_record.state(), SocketState::Listening); - assert_eq!(listener_record.pending_accept_count(), 1); - - let client_record = kernel.socket_get(client_socket).expect("client record"); - assert_eq!(client_record.state(), SocketState::Connected); - assert_eq!( - client_record.peer_address(), - Some(&InetSocketAddress::new("127.0.0.1", 43131)) - ); - - let accepted = kernel - .socket_accept("shell", server.pid(), listener) - .expect("accept loopback connection"); - let accepted_record = kernel.socket_get(accepted).expect("accepted record"); - assert_eq!(accepted_record.state(), SocketState::Connected); - assert_eq!(accepted_record.peer_socket_id(), Some(client_socket)); - assert_eq!( - accepted_record.peer_address(), - Some(&InetSocketAddress::new("127.0.0.1", 54031)) - ); - - let client_after_accept = kernel - .socket_get(client_socket) - .expect("client after accept"); - assert_eq!(client_after_accept.peer_socket_id(), Some(accepted)); - - kernel - .socket_write("shell", client.pid(), client_socket, b"ping") - .expect("client write"); - let payload = kernel - .socket_read("shell", server.pid(), accepted, 16) - .expect("accepted read") - .expect("accepted payload"); - assert_eq!(payload, b"ping"); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_listeners, 1); - assert_eq!(snapshot.socket_connections, 2); -} - -#[test] -fn kernel_loopback_readiness_events_are_edge_triggered() { - let mut kernel = new_kernel("vm-loopback-readiness-edge"); - let events = Arc::new(Mutex::new(Vec::new())); - let captured_events = Arc::clone(&events); - kernel.set_socket_readiness_sink(Some(move |readiness| { - captured_events - .lock() - .expect("readiness events lock") - .push(readiness); - })); - - let server = spawn_shell(&mut kernel); - let client = spawn_shell(&mut kernel); - - let listener = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create listener"); - kernel - .socket_bind_inet( - "shell", - server.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 43141), - ) - .expect("bind listener"); - kernel - .socket_listen("shell", server.pid(), listener, 4) - .expect("listen"); - - let client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::tcp()) - .expect("create client socket"); - kernel - .socket_bind_inet( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("127.0.0.1", 54041), - ) - .expect("bind client"); - kernel - .socket_connect_inet_loopback( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("127.0.0.1", 43141), - ) - .expect("connect loopback client"); - assert_eq!( - take_readiness_events(&events), - vec![SocketReadiness { - socket_id: listener, - kind: SocketReadinessKind::Accept, - }] - ); - - let second_client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::tcp()) - .expect("create second client socket"); - kernel - .socket_bind_inet( - "shell", - client.pid(), - second_client_socket, - InetSocketAddress::new("127.0.0.1", 54042), - ) - .expect("bind second client"); - kernel - .socket_connect_inet_loopback( - "shell", - client.pid(), - second_client_socket, - InetSocketAddress::new("127.0.0.1", 43141), - ) - .expect("connect second loopback client"); - assert!( - take_readiness_events(&events).is_empty(), - "second pending accept should not emit another readiness edge" - ); - - let accepted = kernel - .socket_accept("shell", server.pid(), listener) - .expect("accept first connection"); - let _second_accepted = kernel - .socket_accept("shell", server.pid(), listener) - .expect("accept second connection"); - assert!(take_readiness_events(&events).is_empty()); - - kernel - .socket_write("shell", client.pid(), client_socket, b"A") - .expect("write first byte"); - kernel - .socket_write("shell", client.pid(), client_socket, b"B") - .expect("write second byte while peer buffer is nonempty"); - assert_eq!( - take_readiness_events(&events), - vec![SocketReadiness { - socket_id: accepted, - kind: SocketReadinessKind::Data, - }] - ); - - assert_eq!( - kernel - .socket_read("shell", server.pid(), accepted, 1) - .expect("partial read") - .expect("partial payload"), - b"A" - ); - kernel - .socket_write("shell", client.pid(), client_socket, b"C") - .expect("write while peer buffer still has data"); - assert!( - take_readiness_events(&events).is_empty(), - "write while nonempty should not emit another data edge" - ); - assert_eq!( - kernel - .socket_read("shell", server.pid(), accepted, 8) - .expect("drain read") - .expect("drained payload"), - b"BC" - ); - kernel - .socket_write("shell", client.pid(), client_socket, b"D") - .expect("write after full drain"); - assert_eq!( - take_readiness_events(&events), - vec![SocketReadiness { - socket_id: accepted, - kind: SocketReadinessKind::Data, - }] - ); - - let udp_sender = kernel - .socket_create("shell", client.pid(), SocketSpec::udp()) - .expect("create udp sender"); - kernel - .socket_bind_inet( - "shell", - client.pid(), - udp_sender, - InetSocketAddress::new("127.0.0.1", 54043), - ) - .expect("bind udp sender"); - let udp_receiver = kernel - .socket_create("shell", server.pid(), SocketSpec::udp()) - .expect("create udp receiver"); - kernel - .socket_bind_inet( - "shell", - server.pid(), - udp_receiver, - InetSocketAddress::new("127.0.0.1", 43143), - ) - .expect("bind udp receiver"); - take_readiness_events(&events); - kernel - .socket_send_to_inet_loopback( - "shell", - client.pid(), - udp_sender, - InetSocketAddress::new("127.0.0.1", 43143), - b"one", - ) - .expect("send first datagram"); - kernel - .socket_send_to_inet_loopback( - "shell", - client.pid(), - udp_sender, - InetSocketAddress::new("127.0.0.1", 43143), - b"two", - ) - .expect("send second datagram while queue is nonempty"); - assert_eq!( - take_readiness_events(&events), - vec![SocketReadiness { - socket_id: udp_receiver, - kind: SocketReadinessKind::Data, - }] - ); - kernel - .socket_recv_datagram("shell", server.pid(), udp_receiver, 16) - .expect("receive first datagram"); - kernel - .socket_recv_datagram("shell", server.pid(), udp_receiver, 16) - .expect("receive second datagram"); - kernel - .socket_send_to_inet_loopback( - "shell", - client.pid(), - udp_sender, - InetSocketAddress::new("127.0.0.1", 43143), - b"three", - ) - .expect("send datagram after drain"); - assert_eq!( - take_readiness_events(&events), - vec![SocketReadiness { - socket_id: udp_receiver, - kind: SocketReadinessKind::Data, - }] - ); -} - -#[test] -fn kernel_loopback_connect_matches_wildcard_listener_bindings() { - let mut kernel = new_kernel("vm-loopback-tcp-wildcard"); - let server = spawn_shell(&mut kernel); - let client = spawn_shell(&mut kernel); - - let listener = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create listener"); - kernel - .socket_bind_inet( - "shell", - server.pid(), - listener, - InetSocketAddress::new("0.0.0.0", 43132), - ) - .expect("bind wildcard listener"); - kernel - .socket_listen("shell", server.pid(), listener, 1) - .expect("listen"); - - let client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::tcp()) - .expect("create client socket"); - kernel - .socket_bind_inet( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("127.0.0.1", 54032), - ) - .expect("bind client"); - - kernel - .socket_connect_inet_loopback( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("127.0.0.1", 43132), - ) - .expect("route loopback connect to wildcard listener"); - - let accepted = kernel - .socket_accept("shell", server.pid(), listener) - .expect("accept wildcard loopback connection"); - let accepted_record = kernel.socket_get(accepted).expect("accepted record"); - assert_eq!(accepted_record.state(), SocketState::Connected); - assert_eq!(accepted_record.peer_socket_id(), Some(client_socket)); - - kernel - .socket_write("shell", client.pid(), client_socket, b"ping") - .expect("client write"); - let payload = kernel - .socket_read("shell", server.pid(), accepted, 16) - .expect("accepted read") - .expect("accepted payload"); - assert_eq!(payload, b"ping"); -} - -#[test] -fn kernel_loopback_tcp_delivery_respects_receive_buffer_limit() { - let mut config = KernelVmConfig::new("vm-loopback-tcp-buffer-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_socket_buffered_bytes: Some(5), - ..ResourceLimits::default() - }; - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - let server = spawn_shell(&mut kernel); - let client = spawn_shell(&mut kernel); - - let listener = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create listener"); - kernel - .socket_bind_inet( - "shell", - server.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 43136), - ) - .expect("bind listener"); - kernel - .socket_listen("shell", server.pid(), listener, 1) - .expect("listen"); - - let client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::tcp()) - .expect("create client socket"); - kernel - .socket_bind_inet( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("127.0.0.1", 54036), - ) - .expect("bind client"); - kernel - .socket_connect_inet_loopback( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("127.0.0.1", 43136), - ) - .expect("connect loopback client"); - let accepted = kernel - .socket_accept("shell", server.pid(), listener) - .expect("accept loopback connection"); - - kernel - .socket_write("shell", client.pid(), client_socket, b"12345") - .expect("fill receive buffer"); - let error = kernel - .socket_write("shell", client.pid(), client_socket, b"6") - .expect_err("extra stream byte should exceed receive buffer limit"); - assert_eq!(error.code(), "EAGAIN"); - assert_eq!( - kernel - .socket_get(accepted) - .expect("accepted stream") - .buffered_read_bytes(), - 5 - ); - - let drained = kernel - .socket_read("shell", server.pid(), accepted, 5) - .expect("drain receive buffer") - .expect("stream payload"); - assert_eq!(drained, b"12345"); - kernel - .socket_write("shell", client.pid(), client_socket, b"6") - .expect("write succeeds after draining receive buffer"); -} - -#[test] -fn kernel_loopback_stream_bind_rejects_wildcard_after_loopback_specific() { - let mut kernel = new_kernel("vm-loopback-bind-specific-first"); - let server = spawn_shell(&mut kernel); - let wildcard = spawn_shell(&mut kernel); - - let specific_listener = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create specific listener"); - kernel - .socket_bind_inet( - "shell", - server.pid(), - specific_listener, - InetSocketAddress::new("127.0.0.1", 43133), - ) - .expect("bind specific listener"); - - let wildcard_listener = kernel - .socket_create("shell", wildcard.pid(), SocketSpec::tcp()) - .expect("create wildcard listener"); - let error = kernel - .socket_bind_inet( - "shell", - wildcard.pid(), - wildcard_listener, - InetSocketAddress::new("0.0.0.0", 43133), - ) - .expect_err("wildcard bind should conflict with loopback listener"); - assert_eq!(error.code(), "EADDRINUSE"); -} - -#[test] -fn kernel_loopback_stream_bind_rejects_loopback_specific_after_wildcard() { - let mut kernel = new_kernel("vm-loopback-bind-wildcard-first"); - let server = spawn_shell(&mut kernel); - let loopback = spawn_shell(&mut kernel); - - let wildcard_listener = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create wildcard listener"); - kernel - .socket_bind_inet( - "shell", - server.pid(), - wildcard_listener, - InetSocketAddress::new("0.0.0.0", 43134), - ) - .expect("bind wildcard listener"); - - let loopback_listener = kernel - .socket_create("shell", loopback.pid(), SocketSpec::tcp()) - .expect("create loopback listener"); - let error = kernel - .socket_bind_inet( - "shell", - loopback.pid(), - loopback_listener, - InetSocketAddress::new("127.0.0.1", 43134), - ) - .expect_err("loopback bind should conflict with wildcard listener"); - assert_eq!(error.code(), "EADDRINUSE"); -} - -#[test] -fn kernel_loopback_stream_bind_allows_non_overlapping_specific_addresses() { - let mut kernel = new_kernel("vm-loopback-bind-non-overlap"); - let first = spawn_shell(&mut kernel); - let second = spawn_shell(&mut kernel); - - let first_listener = kernel - .socket_create("shell", first.pid(), SocketSpec::tcp()) - .expect("create first listener"); - kernel - .socket_bind_inet( - "shell", - first.pid(), - first_listener, - InetSocketAddress::new("127.0.0.1", 43135), - ) - .expect("bind first listener"); - - let second_listener = kernel - .socket_create("shell", second.pid(), SocketSpec::tcp()) - .expect("create second listener"); - kernel - .socket_bind_inet( - "shell", - second.pid(), - second_listener, - InetSocketAddress::new("127.0.0.2", 43135), - ) - .expect("bind second listener"); -} - -#[test] -fn kernel_loopback_udp_delivery_stays_within_socket_table() { - let mut kernel = new_kernel("vm-loopback-udp"); - let sender = spawn_shell(&mut kernel); - let receiver = spawn_shell(&mut kernel); - - let sender_socket = kernel - .socket_create("shell", sender.pid(), SocketSpec::udp()) - .expect("create sender socket"); - kernel - .socket_bind_inet( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 54041), - ) - .expect("bind sender"); - - let receiver_socket = kernel - .socket_create("shell", receiver.pid(), SocketSpec::udp()) - .expect("create receiver socket"); - kernel - .socket_bind_inet( - "shell", - receiver.pid(), - receiver_socket, - InetSocketAddress::new("127.0.0.1", 43141), - ) - .expect("bind receiver"); - - let written = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("localhost", 43141), - b"ping-udp", - ) - .expect("send udp payload"); - assert_eq!(written, b"ping-udp".len()); - assert_eq!( - kernel - .socket_get(receiver_socket) - .expect("receiver record") - .queued_datagrams(), - 1 - ); - - let datagram = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 64) - .expect("receive datagram") - .expect("datagram payload"); - assert_eq!( - datagram.source_address(), - Some(&InetSocketAddress::new("127.0.0.1", 54041)) - ); - assert_eq!(datagram.payload(), b"ping-udp"); - assert_eq!( - kernel - .socket_get(receiver_socket) - .expect("receiver after read") - .queued_datagrams(), - 0 - ); -} - -#[test] -fn kernel_loopback_udp_delivery_respects_datagram_queue_limit() { - let mut config = KernelVmConfig::new("vm-loopback-udp-queue-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_socket_datagram_queue_len: Some(1), - ..ResourceLimits::default() - }; - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - let sender = spawn_shell(&mut kernel); - let receiver = spawn_shell(&mut kernel); - - let sender_socket = kernel - .socket_create("shell", sender.pid(), SocketSpec::udp()) - .expect("create sender socket"); - kernel - .socket_bind_inet( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 54042), - ) - .expect("bind sender"); - - let receiver_socket = kernel - .socket_create("shell", receiver.pid(), SocketSpec::udp()) - .expect("create receiver socket"); - kernel - .socket_bind_inet( - "shell", - receiver.pid(), - receiver_socket, - InetSocketAddress::new("127.0.0.1", 43142), - ) - .expect("bind receiver"); - - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43142), - b"one", - ) - .expect("send first datagram"); - let error = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43142), - b"two", - ) - .expect_err("second datagram should exceed queue limit"); - assert_eq!(error.code(), "EAGAIN"); - assert_eq!( - kernel - .socket_get(receiver_socket) - .expect("receiver socket") - .queued_datagrams(), - 1 - ); - - let datagram = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 16) - .expect("receive datagram") - .expect("datagram payload"); - assert_eq!(datagram.payload(), b"one"); - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43142), - b"two", - ) - .expect("send succeeds after draining datagram queue"); -} diff --git a/crates/kernel/tests/permissions.rs b/crates/kernel/tests/permissions.rs deleted file mode 100644 index de08858e4..000000000 --- a/crates/kernel/tests/permissions.rs +++ /dev/null @@ -1,685 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::mount_table::{MountOptions, MountTable}; -use secure_exec_kernel::permissions::{ - check_command_execution, check_network_access, filter_env, permission_glob_matches, - EnvAccessRequest, FsAccessRequest, NetworkOperation, PermissionDecision, - PermissionedFileSystem, Permissions, -}; -use secure_exec_kernel::vfs::{MemoryFileSystem, VfsResult, VirtualFileSystem}; -use std::collections::BTreeMap; -use std::fmt::Debug; -use std::sync::{Arc, Mutex}; - -fn filesystem_fixture() -> MemoryFileSystem { - let mut filesystem = MemoryFileSystem::new(); - filesystem - .write_file("/existing.txt", b"hello".to_vec()) - .expect("seed existing file"); - filesystem - .mkdir("/existing-dir", false) - .expect("seed existing directory"); - filesystem - .write_file("/existing-dir/nested.txt", b"nested".to_vec()) - .expect("seed nested file"); - filesystem -} - -fn wrap_filesystem(permissions: Permissions) -> PermissionedFileSystem { - PermissionedFileSystem::new(filesystem_fixture(), "vm-permissions", permissions) -} - -fn assert_fs_access_denied(result: VfsResult) { - let error = result.expect_err("filesystem operation should be denied"); - assert_eq!(error.code(), "EACCES"); -} - -#[test] -fn permission_wrapped_filesystem_denies_write_with_reason() { - let permissions = Permissions { - filesystem: Some(Arc::new(|request: &FsAccessRequest| { - if request.path.starts_with("/tmp") { - PermissionDecision::allow() - } else { - PermissionDecision::deny("tmp-only sandbox") - } - })), - ..Permissions::default() - }; - - let mut filesystem = - PermissionedFileSystem::new(MemoryFileSystem::new(), "vm-permissions", permissions); - - let error = filesystem - .write_file("/etc/secret.txt", b"nope".to_vec()) - .expect_err("non-/tmp writes should be denied"); - assert_eq!(error.code(), "EACCES"); - assert!(error.to_string().contains("tmp-only sandbox")); -} - -#[test] -fn permission_wrapped_filesystem_denies_access_by_default() { - let mut filesystem = wrap_filesystem(Permissions::default()); - - assert!(filesystem.inner().exists("/existing.txt")); - assert_fs_access_denied(filesystem.read_file("/existing.txt")); - assert_fs_access_denied(filesystem.write_file("/new.txt", b"hello".to_vec())); - assert_fs_access_denied(filesystem.stat("/existing.txt")); - assert!( - !PermissionedFileSystem::exists(&filesystem, "/existing.txt") - .expect("permissioned exists should fail closed") - ); - assert_fs_access_denied(filesystem.mkdir("/created-dir", false)); - assert_fs_access_denied(filesystem.read_dir("/")); - assert_fs_access_denied(filesystem.remove_file("/existing.txt")); -} - -#[test] -fn permission_wrapped_filesystem_allows_access_with_explicit_allow_all_callback() { - let permissions = Permissions { - filesystem: Some(Arc::new(|_: &FsAccessRequest| PermissionDecision::allow())), - ..Permissions::default() - }; - let mut filesystem = wrap_filesystem(permissions); - - assert_eq!( - filesystem - .read_file("/existing.txt") - .expect("read existing file"), - b"hello".to_vec() - ); - filesystem - .write_file("/new.txt", b"world".to_vec()) - .expect("write new file"); - assert!(filesystem - .exists("/existing.txt") - .expect("existing file should be visible")); - assert!(filesystem.stat("/existing.txt").is_ok()); - filesystem - .mkdir("/created-dir", false) - .expect("create directory"); - let root_entries = filesystem.read_dir("/").expect("read root directory"); - assert!(root_entries.iter().any(|entry| entry == "existing.txt")); - assert!(root_entries.iter().any(|entry| entry == "existing-dir")); - assert!(root_entries.iter().any(|entry| entry == "new.txt")); - assert!(root_entries.iter().any(|entry| entry == "created-dir")); - filesystem - .remove_file("/existing.txt") - .expect("remove existing file"); - assert!(!filesystem.inner().exists("/existing.txt")); -} - -#[test] -fn permission_wrapped_filesystem_resolves_symlinks_before_permission_checks() { - let mut inner = MemoryFileSystem::new(); - inner.mkdir("/allowed", true).expect("seed allowed dir"); - inner.mkdir("/private", true).expect("seed private dir"); - inner - .write_file("/private/secret.txt", b"secret".to_vec()) - .expect("seed secret file"); - inner - .symlink("/private/secret.txt", "/allowed/alias.txt") - .expect("seed symlink"); - - let checked_paths = Arc::new(Mutex::new(Vec::new())); - let checked_paths_for_permission = Arc::clone(&checked_paths); - let permissions = Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - checked_paths_for_permission - .lock() - .expect("permission path lock poisoned") - .push(request.path.clone()); - if request.path.starts_with("/allowed") { - PermissionDecision::allow() - } else { - PermissionDecision::deny("allowed-only") - } - })), - ..Permissions::default() - }; - - let mut filesystem = PermissionedFileSystem::new(inner, "vm-permissions", permissions); - - let error = filesystem - .read_file("/allowed/alias.txt") - .expect_err("symlink read should use resolved target path"); - assert_eq!(error.code(), "EACCES"); - assert_eq!( - checked_paths - .lock() - .expect("permission path lock poisoned") - .as_slice(), - [String::from("/private/secret.txt")].as_slice() - ); -} - -#[test] -fn permission_wrapped_filesystem_link_checks_source_and_destination_permissions() { - let mut inner = MemoryFileSystem::new(); - inner.mkdir("/allowed", true).expect("seed allowed dir"); - inner.mkdir("/private", true).expect("seed private dir"); - inner - .write_file("/private/source.txt", b"source".to_vec()) - .expect("seed source file"); - - let checked_paths = Arc::new(Mutex::new(Vec::new())); - let checked_paths_for_permission = Arc::clone(&checked_paths); - let permissions = Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - checked_paths_for_permission - .lock() - .expect("permission path lock poisoned") - .push(request.path.clone()); - PermissionDecision::allow() - })), - ..Permissions::default() - }; - - let mut filesystem = PermissionedFileSystem::new(inner, "vm-permissions", permissions); - filesystem - .link("/private/source.txt", "/allowed/linked.txt") - .expect("hardlink should succeed"); - - assert_eq!( - checked_paths - .lock() - .expect("permission path lock poisoned") - .as_slice(), - [ - String::from("/private/source.txt"), - String::from("/allowed/linked.txt"), - ] - .as_slice() - ); -} - -#[test] -fn permission_wrapped_filesystem_link_resolves_source_as_existing_path() { - let mut inner = MemoryFileSystem::new(); - inner.mkdir("/allowed", true).expect("seed allowed dir"); - inner.mkdir("/private", true).expect("seed private dir"); - inner - .write_file("/private/source.txt", b"source".to_vec()) - .expect("seed source file"); - inner - .symlink("/private/source.txt", "/allowed/source-link") - .expect("seed source symlink"); - - let checked_paths = Arc::new(Mutex::new(Vec::new())); - let checked_paths_for_permission = Arc::clone(&checked_paths); - let permissions = Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - checked_paths_for_permission - .lock() - .expect("permission path lock poisoned") - .push(request.path.clone()); - if request.path.starts_with("/allowed") { - PermissionDecision::allow() - } else { - PermissionDecision::deny("allowed-only") - } - })), - ..Permissions::default() - }; - - let mut filesystem = PermissionedFileSystem::new(inner, "vm-permissions", permissions); - let error = filesystem - .link("/allowed/source-link", "/allowed/linked.txt") - .expect_err("hardlink source should resolve through the existing target path"); - assert_eq!(error.code(), "EACCES"); - assert_eq!( - checked_paths - .lock() - .expect("permission path lock poisoned") - .as_slice(), - [String::from("/private/source.txt")].as_slice() - ); -} - -#[test] -fn permission_wrapped_filesystem_remove_checks_resolved_destination_path() { - let mut inner = MemoryFileSystem::new(); - inner.mkdir("/allowed", true).expect("seed allowed dir"); - inner.mkdir("/private", true).expect("seed private dir"); - inner - .write_file("/private/secret.txt", b"secret".to_vec()) - .expect("seed secret file"); - inner - .symlink("/private", "/allowed/private-link") - .expect("seed directory symlink"); - - let checked_paths = Arc::new(Mutex::new(Vec::new())); - let checked_paths_for_permission = Arc::clone(&checked_paths); - let permissions = Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - checked_paths_for_permission - .lock() - .expect("permission path lock poisoned") - .push(request.path.clone()); - if request.path.starts_with("/allowed") { - PermissionDecision::allow() - } else { - PermissionDecision::deny("allowed-only") - } - })), - ..Permissions::default() - }; - - let mut filesystem = PermissionedFileSystem::new(inner, "vm-permissions", permissions); - let error = filesystem - .remove_file("/allowed/private-link/secret.txt") - .expect_err("remove should resolve symlinked parent before permission check"); - assert_eq!(error.code(), "EACCES"); - assert_eq!( - checked_paths - .lock() - .expect("permission path lock poisoned") - .as_slice(), - [String::from("/private/secret.txt")].as_slice() - ); -} - -#[test] -fn permission_wrapped_filesystem_exists_fails_closed_on_permission_denied() { - let permissions = Permissions { - filesystem: Some(Arc::new(|_: &FsAccessRequest| { - PermissionDecision::deny("hidden") - })), - ..Permissions::default() - }; - let filesystem = wrap_filesystem(permissions); - - assert!( - !PermissionedFileSystem::exists(&filesystem, "/existing.txt") - .expect("permissioned exists should fail closed") - ); - assert!(!VirtualFileSystem::exists(&filesystem, "/existing.txt")); -} - -#[test] -fn filter_env_only_keeps_allowed_keys() { - let permissions = Permissions { - environment: Some(Arc::new(|request: &EnvAccessRequest| PermissionDecision { - allow: request.key != "SECRET_KEY", - reason: None, - })), - ..Permissions::default() - }; - - let env = BTreeMap::from([ - (String::from("HOME"), String::from("/home/agentos")), - (String::from("PATH"), String::from("/usr/bin")), - (String::from("SECRET_KEY"), String::from("hidden")), - ]); - - let filtered = filter_env("vm-permissions", &env, &permissions); - assert_eq!(filtered.get("HOME"), Some(&String::from("/home/agentos"))); - assert_eq!(filtered.get("PATH"), Some(&String::from("/usr/bin"))); - assert!(!filtered.contains_key("SECRET_KEY")); -} - -#[test] -fn command_permissions_deny_when_callback_is_absent() { - let error = check_command_execution( - "vm-permissions", - &Permissions::default(), - "sh", - &[], - Some("/workspace"), - &BTreeMap::new(), - ) - .expect_err("missing command permission hook should fail closed"); - - assert_eq!(error.code(), "EACCES"); - assert!(error.to_string().contains("spawn 'sh'")); -} - -#[test] -fn network_permissions_deny_when_callback_is_absent() { - let error = check_network_access( - "vm-permissions", - &Permissions::default(), - NetworkOperation::Dns, - "example.test", - ) - .expect_err("missing network permission hook should fail closed"); - - assert_eq!(error.code(), "EACCES"); - assert!(error.to_string().contains("example.test")); -} - -#[test] -fn child_process_permissions_block_spawn() { - let mut config = KernelVmConfig::new("vm-permissions"); - config.permissions = Permissions { - child_process: Some(Arc::new(|request| { - if request.command == "blocked" { - PermissionDecision::deny("blocked by policy") - } else { - PermissionDecision::allow() - } - })), - ..Permissions::allow_all() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("alpha", ["blocked"])) - .expect("register driver"); - - let error = kernel - .spawn_process("blocked", Vec::new(), SpawnOptions::default()) - .expect_err("spawn should be denied"); - assert_eq!(error.code(), "EACCES"); - assert!(error.to_string().contains("blocked by policy")); -} - -#[test] -fn permission_glob_single_star_does_not_cross_path_separators() { - assert!(permission_glob_matches("network/*", "network/foo")); - assert!(!permission_glob_matches("network/*", "network/foo/bar")); - assert!(permission_glob_matches( - "/workspace/*", - "/workspace/file.txt" - )); - assert!(!permission_glob_matches( - "/workspace/*", - "/workspace/nested/file.txt", - )); -} - -#[test] -fn permission_glob_double_star_still_matches_nested_paths() { - assert!(permission_glob_matches( - "/workspace/**", - "/workspace/nested/file.txt", - )); - assert!(permission_glob_matches("tcp://**", "tcp://127.0.0.1:43111")); -} - -#[test] -fn kernel_vm_config_defaults_to_deny_all_permissions() { - let mut kernel = KernelVm::new(MemoryFileSystem::new(), KernelVmConfig::new("vm-defaults")); - - let error = kernel - .write_file("/tmp/denied.txt", b"nope".to_vec()) - .expect_err("default config should deny filesystem writes"); - assert_eq!(error.code(), "EACCES"); -} - -#[test] -fn kernel_default_spawn_cwd_matches_workspace() { - let captured_cwd = Arc::new(Mutex::new(None)); - let captured_cwd_for_permission = Arc::clone(&captured_cwd); - - let mut config = KernelVmConfig::new("vm-default-cwd"); - config.permissions = Permissions { - child_process: Some(Arc::new(move |request| { - *captured_cwd_for_permission - .lock() - .expect("captured cwd lock poisoned") = request.cwd.clone(); - PermissionDecision::allow() - })), - ..Permissions::allow_all() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("alpha", ["echo"])) - .expect("register driver"); - - let process = kernel - .spawn_process("echo", Vec::new(), SpawnOptions::default()) - .expect("spawn should succeed"); - - assert_eq!( - captured_cwd - .lock() - .expect("captured cwd lock poisoned") - .as_deref(), - Some("/workspace") - ); - - process.finish(0); - kernel.wait_and_reap(process.pid()).expect("reap process"); -} - -#[test] -fn driver_pid_ownership_is_enforced_across_kernel_operations() { - let mut config = KernelVmConfig::new("vm-auth"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("alpha", ["alpha-cmd"])) - .expect("register alpha"); - kernel - .register_driver(CommandDriver::new("beta", ["beta-cmd"])) - .expect("register beta"); - - let alpha = kernel - .spawn_process( - "alpha-cmd", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("alpha")), - ..SpawnOptions::default() - }, - ) - .expect("spawn alpha"); - let beta = kernel - .spawn_process( - "beta-cmd", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("beta")), - ..SpawnOptions::default() - }, - ) - .expect("spawn beta"); - - let error = kernel - .open_pipe("alpha", beta.pid()) - .expect_err("alpha should not open a pipe for beta"); - assert_eq!(error.code(), "EPERM"); - assert!(error.to_string().contains("does not own PID")); - - let error = kernel - .kill_process("beta", alpha.pid(), 15) - .expect_err("beta should not kill alpha"); - assert_eq!(error.code(), "EPERM"); - - alpha.finish(0); - beta.finish(0); - kernel.wait_and_reap(alpha.pid()).expect("reap alpha"); - kernel.wait_and_reap(beta.pid()).expect("reap beta"); -} - -#[test] -fn kernel_mounts_require_write_permission_on_the_mount_path() { - let checked = Arc::new(Mutex::new(Vec::new())); - let checked_for_permission = Arc::clone(&checked); - let mut config = KernelVmConfig::new("vm-mount-permissions"); - config.permissions = Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - checked_for_permission - .lock() - .expect("checked mount paths lock poisoned") - .push((request.op, request.path.clone())); - PermissionDecision::deny("mounts disabled") - })), - ..Permissions::default() - }; - - let mut kernel = KernelVm::new(MountTable::new(MemoryFileSystem::new()), config); - let error = kernel - .mount_filesystem( - "/workspace", - MemoryFileSystem::new(), - MountOptions::new("memory"), - ) - .expect_err("mount should be denied"); - assert_eq!(error.code(), "EACCES"); - assert!(error.to_string().contains("mounts disabled")); - assert_eq!( - checked - .lock() - .expect("checked mount paths lock poisoned") - .as_slice(), - [( - secure_exec_kernel::permissions::FsOperation::Write, - String::from("/workspace") - )] - .as_slice() - ); -} - -#[test] -fn kernel_sensitive_mounts_require_explicit_sensitive_permission() { - let checked = Arc::new(Mutex::new(Vec::new())); - let checked_for_permission = Arc::clone(&checked); - let mut config = KernelVmConfig::new("vm-sensitive-mounts"); - config.permissions = Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - checked_for_permission - .lock() - .expect("checked mount paths lock poisoned") - .push((request.op, request.path.clone())); - match request.op { - secure_exec_kernel::permissions::FsOperation::Write => PermissionDecision::allow(), - secure_exec_kernel::permissions::FsOperation::MountSensitive => { - PermissionDecision::deny("sensitive mounts require elevation") - } - other => panic!("unexpected filesystem permission probe: {other:?}"), - } - })), - ..Permissions::default() - }; - - let mut kernel = KernelVm::new(MountTable::new(MemoryFileSystem::new()), config); - let error = kernel - .mount_filesystem("/etc", MemoryFileSystem::new(), MountOptions::new("memory")) - .expect_err("sensitive mount should be denied"); - assert_eq!(error.code(), "EACCES"); - assert!(error - .to_string() - .contains("sensitive mounts require elevation")); - assert_eq!( - checked - .lock() - .expect("checked mount paths lock poisoned") - .as_slice(), - [ - ( - secure_exec_kernel::permissions::FsOperation::Write, - String::from("/etc"), - ), - ( - secure_exec_kernel::permissions::FsOperation::MountSensitive, - String::from("/etc"), - ), - ] - .as_slice() - ); -} - -#[test] -fn kernel_unmounts_require_write_permission_on_the_mount_path() { - let checked = Arc::new(Mutex::new(Vec::new())); - let checked_for_permission = Arc::clone(&checked); - let mut config = KernelVmConfig::new("vm-unmount-permissions"); - config.permissions = Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - checked_for_permission - .lock() - .expect("checked unmount paths lock poisoned") - .push((request.op, request.path.clone())); - PermissionDecision::deny("unmounts disabled") - })), - ..Permissions::default() - }; - - let mut kernel = KernelVm::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .filesystem_mut() - .inner_mut() - .inner_mut() - .mount( - "/workspace", - MemoryFileSystem::new(), - MountOptions::new("memory"), - ) - .expect("seed mount"); - - let error = kernel - .unmount_filesystem("/workspace") - .expect_err("unmount should be denied"); - assert_eq!(error.code(), "EACCES"); - assert!(error.to_string().contains("unmounts disabled")); - assert_eq!( - checked - .lock() - .expect("checked unmount paths lock poisoned") - .as_slice(), - [( - secure_exec_kernel::permissions::FsOperation::Write, - String::from("/workspace") - )] - .as_slice() - ); -} - -#[test] -fn kernel_sensitive_unmounts_require_explicit_sensitive_permission() { - let checked = Arc::new(Mutex::new(Vec::new())); - let checked_for_permission = Arc::clone(&checked); - let mut config = KernelVmConfig::new("vm-sensitive-unmounts"); - config.permissions = Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - checked_for_permission - .lock() - .expect("checked sensitive unmount paths lock poisoned") - .push((request.op, request.path.clone())); - match request.op { - secure_exec_kernel::permissions::FsOperation::Write => PermissionDecision::allow(), - secure_exec_kernel::permissions::FsOperation::MountSensitive => { - PermissionDecision::deny("sensitive mounts require elevation") - } - other => panic!("unexpected filesystem permission probe: {other:?}"), - } - })), - ..Permissions::default() - }; - - let mut kernel = KernelVm::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .filesystem_mut() - .inner_mut() - .inner_mut() - .mount("/etc", MemoryFileSystem::new(), MountOptions::new("memory")) - .expect("seed sensitive mount"); - - let error = kernel - .unmount_filesystem("/etc") - .expect_err("sensitive unmount should be denied"); - assert_eq!(error.code(), "EACCES"); - assert!(error - .to_string() - .contains("sensitive mounts require elevation")); - assert_eq!( - checked - .lock() - .expect("checked sensitive unmount paths lock poisoned") - .as_slice(), - [ - ( - secure_exec_kernel::permissions::FsOperation::Write, - String::from("/etc"), - ), - ( - secure_exec_kernel::permissions::FsOperation::MountSensitive, - String::from("/etc"), - ), - ] - .as_slice() - ); -} diff --git a/crates/kernel/tests/pipe_manager.rs b/crates/kernel/tests/pipe_manager.rs deleted file mode 100644 index 55dc93c7a..000000000 --- a/crates/kernel/tests/pipe_manager.rs +++ /dev/null @@ -1,379 +0,0 @@ -use secure_exec_kernel::fd_table::{FdResult, FdTableManager, FILETYPE_PIPE}; -use secure_exec_kernel::pipe_manager::{ - PipeManager, PipeResult, MAX_PIPE_BUFFER_BYTES, PIPE_BUF_BYTES, -}; -use std::fmt::Debug; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; -use std::thread; -use std::time::{Duration, Instant}; - -fn assert_pipe_error(result: PipeResult, expected: &str) { - let error = result.expect_err("operation should fail"); - assert_eq!(error.code(), expected); -} - -fn assert_fd_error(result: FdResult, expected: &str) { - let error = result.expect_err("operation should fail"); - assert_eq!(error.code(), expected); -} - -fn wait_for_waiting_reader(manager: &PipeManager, description_id: u64) { - wait_for_waiting_readers(manager, description_id, 1); -} - -fn wait_for_waiting_readers(manager: &PipeManager, description_id: u64, expected: usize) { - let deadline = Instant::now() + Duration::from_secs(1); - loop { - let count = manager - .waiting_reader_count(description_id) - .expect("pipe should still exist"); - if count >= expected { - return; - } - assert!( - Instant::now() < deadline, - "expected {expected} waiting readers on pipe description {description_id}, got {count}" - ); - thread::sleep(Duration::from_millis(1)); - } -} - -#[test] -fn create_pipe_returns_distinct_read_and_write_descriptions() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - - assert_ne!(pipe.read.description.id(), pipe.write.description.id()); - assert!(manager.is_pipe(pipe.read.description.id())); - assert!(manager.is_pipe(pipe.write.description.id())); -} - -#[test] -fn buffered_writes_are_read_back_and_partial_reads_preserve_remainder() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - - manager - .write(pipe.write.description.id(), b"hello world") - .expect("write pipe contents"); - - let first = manager - .read(pipe.read.description.id(), 5) - .expect("read first slice") - .expect("first slice should contain data"); - let second = manager - .read(pipe.read.description.id(), 1024) - .expect("read remainder") - .expect("remainder should contain data"); - - assert_eq!(String::from_utf8(first).expect("utf8"), "hello"); - assert_eq!(String::from_utf8(second).expect("utf8"), " world"); -} - -#[test] -fn read_blocks_until_a_writer_delivers_data() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - let read_id = pipe.read.description.id(); - let write_id = pipe.write.description.id(); - let reader = manager.clone(); - - let handle = thread::spawn(move || { - reader - .read(read_id, 1024) - .expect("blocking read should succeed") - .expect("blocking read should produce data") - }); - - thread::sleep(Duration::from_millis(10)); - manager - .write(write_id, b"delayed") - .expect("write delayed payload"); - - assert_eq!( - String::from_utf8(handle.join().expect("reader thread should finish")).expect("utf8"), - "delayed" - ); -} - -#[test] -fn closing_the_write_end_delivers_eof_to_waiting_readers() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - let read_id = pipe.read.description.id(); - let write_id = pipe.write.description.id(); - let reader = manager.clone(); - - let handle = thread::spawn(move || reader.read(read_id, 1024).expect("blocking read")); - wait_for_waiting_reader(&manager, read_id); - manager.close(write_id); - - assert_eq!(handle.join().expect("reader thread should finish"), None); -} - -#[test] -fn closing_the_read_end_does_not_wake_waiting_readers() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - let read_id = pipe.read.description.id(); - let write_id = pipe.write.description.id(); - let reader = manager.clone(); - let completed = Arc::new(AtomicBool::new(false)); - let completed_for_thread = Arc::clone(&completed); - - let handle = thread::spawn(move || { - let result = reader.read(read_id, 1024).expect("blocking read"); - completed_for_thread.store(true, Ordering::SeqCst); - result - }); - - wait_for_waiting_reader(&manager, read_id); - manager.close(read_id); - thread::sleep(Duration::from_millis(25)); - assert!(!completed.load(Ordering::SeqCst)); - - manager.close(write_id); - assert_eq!(handle.join().expect("reader thread should finish"), None); -} - -#[test] -fn buffer_limit_is_enforced_until_the_reader_drains_the_pipe() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - - manager - .write(pipe.write.description.id(), vec![0; MAX_PIPE_BUFFER_BYTES]) - .expect("fill pipe buffer"); - assert_pipe_error(manager.write(pipe.write.description.id(), [1]), "EAGAIN"); - - let drained = manager - .read(pipe.read.description.id(), MAX_PIPE_BUFFER_BYTES) - .expect("drain buffer") - .expect("buffer should contain data"); - assert_eq!(drained.len(), MAX_PIPE_BUFFER_BYTES); - - manager - .write(pipe.write.description.id(), vec![2; 1024]) - .expect("write after draining"); -} - -#[test] -fn blocking_small_writes_wait_for_full_pipe_buf_capacity() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - let read_id = pipe.read.description.id(); - let write_id = pipe.write.description.id(); - let writer = manager.clone(); - - manager - .write( - write_id, - vec![0; MAX_PIPE_BUFFER_BYTES - (PIPE_BUF_BYTES - 1)], - ) - .expect("fill pipe to one byte below PIPE_BUF headroom"); - - let handle = thread::spawn(move || { - writer - .write_blocking(write_id, vec![1; PIPE_BUF_BYTES]) - .expect("small blocking write should eventually succeed") - }); - - thread::sleep(Duration::from_millis(25)); - assert!( - !handle.is_finished(), - "PIPE_BUF-sized write should wait until the full chunk fits" - ); - - let first = manager - .read(read_id, 1) - .expect("drain one byte") - .expect("byte should be present"); - assert_eq!(first, vec![0]); - - assert_eq!( - handle.join().expect("writer thread should finish"), - PIPE_BUF_BYTES - ); - - let drained = manager - .read(read_id, MAX_PIPE_BUFFER_BYTES) - .expect("drain remainder") - .expect("remainder should be present"); - assert_eq!(drained.len(), MAX_PIPE_BUFFER_BYTES); - assert!(drained[..drained.len() - PIPE_BUF_BYTES] - .iter() - .all(|byte| *byte == 0)); - assert!(drained[drained.len() - PIPE_BUF_BYTES..] - .iter() - .all(|byte| *byte == 1)); -} - -#[test] -fn waiting_reader_receives_large_writes_without_hitting_the_buffer_limit() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - let read_id = pipe.read.description.id(); - let write_id = pipe.write.description.id(); - let reader = manager.clone(); - - let handle = thread::spawn(move || { - reader - .read(read_id, MAX_PIPE_BUFFER_BYTES + 1024) - .expect("blocking read should succeed") - .expect("blocking read should receive data") - .len() - }); - - wait_for_waiting_reader(&manager, read_id); - manager - .write(write_id, vec![7; MAX_PIPE_BUFFER_BYTES + 1024]) - .expect("large direct write should bypass buffering"); - - assert_eq!( - handle.join().expect("reader thread should finish"), - MAX_PIPE_BUFFER_BYTES + 1024 - ); -} - -#[test] -fn direct_handoff_honors_waiting_reader_length_and_buffers_the_remainder() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - let read_id = pipe.read.description.id(); - let write_id = pipe.write.description.id(); - let reader = manager.clone(); - - let handle = thread::spawn(move || { - reader - .read(read_id, 10) - .expect("blocking read should succeed") - .expect("blocking read should receive data") - }); - - wait_for_waiting_reader(&manager, read_id); - manager - .write(write_id, vec![7; 1024]) - .expect("direct handoff write should succeed"); - - let first = handle.join().expect("reader thread should finish"); - let second = manager - .read(read_id, 2048) - .expect("remainder read should succeed") - .expect("remainder should stay buffered"); - - assert_eq!(first, vec![7; 10]); - assert_eq!(second.len(), 1014); - assert!(second.iter().all(|byte| *byte == 7)); -} - -#[test] -fn many_waiting_readers_are_cleaned_up_when_the_write_end_closes() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - let read_id = pipe.read.description.id(); - let write_id = pipe.write.description.id(); - let mut handles = Vec::new(); - - for _ in 0..32 { - let reader = manager.clone(); - handles.push(thread::spawn(move || { - reader.read(read_id, 1024).expect("blocking read") - })); - } - - wait_for_waiting_readers(&manager, read_id, handles.len()); - manager.close(write_id); - - for handle in handles { - assert_eq!(handle.join().expect("reader thread should finish"), None); - } - assert_eq!(manager.pending_read_waiter_count(), 0); - assert_eq!( - manager - .waiting_reader_count(read_id) - .expect("pipe should remain until read end closes"), - 0 - ); -} - -#[test] -fn many_timed_out_readers_are_removed_from_the_waiting_queue() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - let read_id = pipe.read.description.id(); - let mut handles = Vec::new(); - - for _ in 0..32 { - let reader = manager.clone(); - handles.push(thread::spawn(move || { - reader - .read_with_timeout(read_id, 1024, Some(Duration::from_secs(2))) - .expect_err("read should time out") - .code() - .to_owned() - })); - } - - wait_for_waiting_readers(&manager, read_id, handles.len()); - for handle in handles { - assert_eq!( - handle.join().expect("reader thread should finish"), - "EAGAIN" - ); - } - assert_eq!(manager.pending_read_waiter_count(), 0); - assert_eq!( - manager - .waiting_reader_count(read_id) - .expect("pipe should remain open"), - 0 - ); -} - -#[test] -fn writing_after_the_read_end_closes_returns_epipe() { - let manager = PipeManager::new(); - let pipe = manager.create_pipe(); - - manager.close(pipe.read.description.id()); - assert_pipe_error(manager.write(pipe.write.description.id(), b"fail"), "EPIPE"); -} - -#[test] -fn create_pipe_fds_allocates_pipe_entries_in_the_fd_table() { - let manager = PipeManager::new(); - let mut tables = FdTableManager::new(); - tables.create(1); - - let (read_fd, write_fd) = manager - .create_pipe_fds(tables.get_mut(1).expect("FD table should exist")) - .expect("create pipe FDs"); - let table = tables.get(1).expect("FD table should exist"); - - assert_eq!(read_fd, 3); - assert_eq!(write_fd, 4); - assert_eq!( - table.get(read_fd).expect("read entry").filetype, - FILETYPE_PIPE - ); - assert_eq!( - table.get(write_fd).expect("write entry").filetype, - FILETYPE_PIPE - ); -} - -#[test] -fn create_pipe_fds_propagates_fd_allocation_failures() { - let manager = PipeManager::new(); - let mut tables = FdTableManager::new(); - let table = tables.create(1); - - for index in 0..253 { - table - .open(&format!("/tmp/file-{index}"), 0) - .expect("fill remaining FD slots"); - } - - assert_fd_error(manager.create_pipe_fds(table), "EMFILE"); -} diff --git a/crates/kernel/tests/poll.rs b/crates/kernel/tests/poll.rs deleted file mode 100644 index 5c050ff9f..000000000 --- a/crates/kernel/tests/poll.rs +++ /dev/null @@ -1,422 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::poll::{PollFd, PollTargetEntry, POLLERR, POLLHUP, POLLIN, POLLOUT}; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::socket_table::{InetSocketAddress, SocketShutdown, SocketSpec}; -use secure_exec_kernel::vfs::MemoryFileSystem; -use std::time::{Duration, Instant}; - -fn kernel_vm(vm_id: &str) -> KernelVm { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell driver"); - kernel -} - -fn spawn_shell(kernel: &mut KernelVm) -> u32 { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") - .pid() -} - -fn bind_udp_socket(kernel: &mut KernelVm, pid: u32, port: u16) -> u64 { - let socket_id = kernel - .socket_create("shell", pid, SocketSpec::udp()) - .expect("create UDP socket"); - kernel - .socket_bind_inet( - "shell", - pid, - socket_id, - InetSocketAddress::new("127.0.0.1", port), - ) - .expect("bind UDP socket"); - socket_id -} - -#[test] -fn poll_reports_pipe_readiness_and_hangup() { - let mut kernel = kernel_vm("vm-poll-pipe"); - let pid = spawn_shell(&mut kernel); - let (read_fd, write_fd) = kernel.open_pipe("shell", pid).expect("open pipe"); - - let initial = kernel - .poll_fds( - "shell", - pid, - vec![PollFd::new(read_fd, POLLIN), PollFd::new(write_fd, POLLOUT)], - 0, - ) - .expect("poll initial pipe state"); - assert_eq!(initial.ready_count, 1); - assert_eq!(initial.fds[0].revents.bits(), 0); - assert_eq!(initial.fds[1].revents, POLLOUT); - - kernel - .fd_write("shell", pid, write_fd, b"hello") - .expect("write pipe payload"); - kernel - .fd_close("shell", pid, write_fd) - .expect("close pipe writer"); - - let ready = kernel - .poll_fds("shell", pid, vec![PollFd::new(read_fd, POLLIN)], 0) - .expect("poll readable pipe"); - assert_eq!(ready.ready_count, 1); - assert!(ready.fds[0].revents.contains(POLLIN)); - assert!(ready.fds[0].revents.contains(POLLHUP)); -} - -#[test] -fn poll_reports_pipe_peer_close_as_pollerr_on_writer() { - let mut kernel = kernel_vm("vm-poll-pipe-err"); - let pid = spawn_shell(&mut kernel); - let (read_fd, write_fd) = kernel.open_pipe("shell", pid).expect("open pipe"); - - kernel - .fd_close("shell", pid, read_fd) - .expect("close pipe reader"); - - let ready = kernel - .poll_fds("shell", pid, vec![PollFd::new(write_fd, POLLOUT)], 0) - .expect("poll closed writer peer"); - assert_eq!(ready.ready_count, 1); - assert!(ready.fds[0].revents.contains(POLLERR)); - assert!(!ready.fds[0].revents.contains(POLLOUT)); -} - -#[test] -fn poll_targets_report_socket_stream_readiness_and_hangup() { - let mut kernel = kernel_vm("vm-poll-socket-stream"); - let client_pid = spawn_shell(&mut kernel); - let server_pid = spawn_shell(&mut kernel); - - let client_socket = kernel - .socket_create("shell", client_pid, SocketSpec::tcp()) - .expect("create client socket"); - let server_socket = kernel - .socket_create("shell", server_pid, SocketSpec::tcp()) - .expect("create server socket"); - kernel - .socket_connect_pair("shell", client_pid, client_socket, server_socket) - .expect("connect socket pair"); - - let initial = kernel - .poll_targets( - "shell", - client_pid, - vec![PollTargetEntry::socket(client_socket, POLLOUT)], - 0, - ) - .expect("poll writable client socket"); - assert_eq!(initial.ready_count, 1); - assert_eq!(initial.targets[0].revents, POLLOUT); - - kernel - .socket_write("shell", client_pid, client_socket, b"socket-ready") - .expect("write client payload"); - let readable = kernel - .poll_targets( - "shell", - server_pid, - vec![PollTargetEntry::socket(server_socket, POLLIN)], - 0, - ) - .expect("poll readable server socket"); - assert_eq!(readable.ready_count, 1); - assert_eq!(readable.targets[0].revents, POLLIN); - - kernel - .socket_shutdown("shell", client_pid, client_socket, SocketShutdown::Write) - .expect("shutdown client write side"); - let hung_up = kernel - .poll_targets( - "shell", - server_pid, - vec![PollTargetEntry::socket(server_socket, POLLIN | POLLOUT)], - 0, - ) - .expect("poll server after peer shutdown"); - assert_eq!(hung_up.ready_count, 1); - assert!(hung_up.targets[0].revents.contains(POLLIN)); - assert!(hung_up.targets[0].revents.contains(POLLHUP)); - assert!(hung_up.targets[0].revents.contains(POLLOUT)); -} - -#[test] -fn poll_targets_suppress_stream_pollout_when_socket_buffer_limit_is_full() { - let mut config = KernelVmConfig::new("vm-poll-socket-buffer-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_socket_buffered_bytes: Some(3), - ..ResourceLimits::default() - }; - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell driver"); - let client_pid = spawn_shell(&mut kernel); - let server_pid = spawn_shell(&mut kernel); - - let client_socket = kernel - .socket_create("shell", client_pid, SocketSpec::tcp()) - .expect("create client socket"); - let server_socket = kernel - .socket_create("shell", server_pid, SocketSpec::tcp()) - .expect("create server socket"); - kernel - .socket_connect_pair("shell", client_pid, client_socket, server_socket) - .expect("connect socket pair"); - - let writable = kernel - .poll_targets( - "shell", - client_pid, - vec![PollTargetEntry::socket(client_socket, POLLOUT)], - 0, - ) - .expect("poll initially writable client socket"); - assert_eq!(writable.ready_count, 1); - assert_eq!(writable.targets[0].revents, POLLOUT); - - kernel - .socket_write("shell", client_pid, client_socket, b"abc") - .expect("fill stream receive buffer budget"); - let blocked = kernel - .poll_targets( - "shell", - client_pid, - vec![PollTargetEntry::socket(client_socket, POLLOUT)], - 0, - ) - .expect("poll client socket at buffer limit"); - assert_eq!(blocked.ready_count, 0); - assert_eq!( - blocked.targets[0].revents, - secure_exec_kernel::poll::PollEvents::empty() - ); - - let _ = kernel - .socket_read("shell", server_pid, server_socket, 3) - .expect("drain stream receive buffer"); - let writable_again = kernel - .poll_targets( - "shell", - client_pid, - vec![PollTargetEntry::socket(client_socket, POLLOUT)], - 0, - ) - .expect("poll client socket after draining buffer"); - assert_eq!(writable_again.ready_count, 1); - assert_eq!(writable_again.targets[0].revents, POLLOUT); -} - -#[test] -fn poll_targets_suppress_udp_pollout_when_datagram_queue_limit_is_full() { - let mut config = KernelVmConfig::new("vm-poll-udp-queue-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_socket_datagram_queue_len: Some(1), - ..ResourceLimits::default() - }; - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell driver"); - let sender_pid = spawn_shell(&mut kernel); - let receiver_pid = spawn_shell(&mut kernel); - let sender_socket = bind_udp_socket(&mut kernel, sender_pid, 54161); - let receiver_socket = bind_udp_socket(&mut kernel, receiver_pid, 43162); - - let writable = kernel - .poll_targets( - "shell", - sender_pid, - vec![PollTargetEntry::socket(sender_socket, POLLOUT)], - 0, - ) - .expect("poll initially writable UDP socket"); - assert_eq!(writable.ready_count, 1); - assert_eq!(writable.targets[0].revents, POLLOUT); - - kernel - .socket_send_to_inet_loopback( - "shell", - sender_pid, - sender_socket, - InetSocketAddress::new("127.0.0.1", 43162), - b"queued", - ) - .expect("fill UDP datagram queue budget"); - let blocked = kernel - .poll_targets( - "shell", - sender_pid, - vec![PollTargetEntry::socket(sender_socket, POLLOUT)], - 0, - ) - .expect("poll UDP socket at queue limit"); - assert_eq!(blocked.ready_count, 0); - assert_eq!( - blocked.targets[0].revents, - secure_exec_kernel::poll::PollEvents::empty() - ); - - let _ = kernel - .socket_recv_datagram("shell", receiver_pid, receiver_socket, 16) - .expect("drain UDP datagram queue"); - let writable_again = kernel - .poll_targets( - "shell", - sender_pid, - vec![PollTargetEntry::socket(sender_socket, POLLOUT)], - 0, - ) - .expect("poll UDP socket after draining queue"); - assert_eq!(writable_again.ready_count, 1); - assert_eq!(writable_again.targets[0].revents, POLLOUT); -} - -#[test] -fn poll_targets_support_mixed_fd_and_socket_sets() { - let mut kernel = kernel_vm("vm-poll-mixed"); - let pid = spawn_shell(&mut kernel); - let sender_pid = spawn_shell(&mut kernel); - let (pipe_read_fd, _pipe_write_fd) = kernel.open_pipe("shell", pid).expect("open pipe"); - let (master_fd, slave_fd, _path) = kernel.open_pty("shell", pid).expect("open pty"); - let receiver_socket = bind_udp_socket(&mut kernel, pid, 43161); - let sender_socket = bind_udp_socket(&mut kernel, sender_pid, 54061); - - kernel - .fd_write("shell", pid, slave_fd, b"tty-ready") - .expect("write pty output"); - kernel - .socket_send_to_inet_loopback( - "shell", - sender_pid, - sender_socket, - InetSocketAddress::new("localhost", 43161), - b"udp-ready", - ) - .expect("send UDP payload"); - - let ready = kernel - .poll_targets( - "shell", - pid, - vec![ - PollTargetEntry::fd(pipe_read_fd, POLLIN), - PollTargetEntry::fd(master_fd, POLLIN), - PollTargetEntry::socket(receiver_socket, POLLIN), - ], - -1, - ) - .expect("poll mixed target set"); - assert_eq!(ready.ready_count, 2); - assert_eq!(ready.targets[0].revents.bits(), 0); - assert_eq!(ready.targets[1].revents, POLLIN); - assert_eq!(ready.targets[2].revents, POLLIN); -} - -#[test] -fn poll_targets_respect_finite_timeouts_across_fd_and_socket_sets() { - let mut kernel = kernel_vm("vm-poll-timeout"); - let pid = spawn_shell(&mut kernel); - let _peer_pid = spawn_shell(&mut kernel); - let (read_fd, _write_fd) = kernel.open_pipe("shell", pid).expect("open pipe"); - let listener = kernel - .socket_create("shell", pid, SocketSpec::tcp()) - .expect("create listener socket"); - kernel - .socket_bind_inet( - "shell", - pid, - listener, - InetSocketAddress::new("127.0.0.1", 43162), - ) - .expect("bind listener"); - kernel - .socket_listen("shell", pid, listener, 1) - .expect("listen"); - - let start = Instant::now(); - let ready = kernel - .poll_targets( - "shell", - pid, - vec![ - PollTargetEntry::fd(read_fd, POLLIN), - PollTargetEntry::socket(listener, POLLIN), - ], - 30, - ) - .expect("poll timeout"); - let elapsed = start.elapsed(); - - assert_eq!(ready.ready_count, 0); - assert_eq!(ready.targets[0].revents.bits(), 0); - assert_eq!(ready.targets[1].revents.bits(), 0); - assert!( - elapsed >= Duration::from_millis(20), - "expected poll to wait, observed {elapsed:?}" - ); -} - -#[test] -fn poll_fds_rejects_requester_that_does_not_own_process() { - let mut kernel = kernel_vm("vm-poll-requester-owner"); - let pid = spawn_shell(&mut kernel); - let (read_fd, _write_fd) = kernel.open_pipe("shell", pid).expect("open pipe"); - kernel - .register_driver(CommandDriver::new("other-driver", ["other-sh"])) - .expect("register other driver"); - kernel - .spawn_process( - "other-sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("other-driver")), - ..SpawnOptions::default() - }, - ) - .expect("spawn other driver process"); - - let error = kernel - .poll_fds("other-driver", pid, vec![PollFd::new(read_fd, POLLIN)], 0) - .expect_err("foreign driver should not poll shell-owned process"); - - assert_eq!(error.code(), "EPERM"); -} - -#[test] -fn poll_targets_rejects_socket_owned_by_another_process() { - let mut kernel = kernel_vm("vm-poll-socket-owner"); - let socket_owner_pid = spawn_shell(&mut kernel); - let polling_pid = spawn_shell(&mut kernel); - let socket_id = kernel - .socket_create("shell", socket_owner_pid, SocketSpec::tcp()) - .expect("create socket"); - - let error = kernel - .poll_targets( - "shell", - polling_pid, - vec![PollTargetEntry::socket(socket_id, POLLIN)], - 0, - ) - .expect_err("process should not poll a socket it does not own"); - - assert_eq!(error.code(), "EPERM"); -} diff --git a/crates/kernel/tests/process_table.rs b/crates/kernel/tests/process_table.rs deleted file mode 100644 index 56609da51..000000000 --- a/crates/kernel/tests/process_table.rs +++ /dev/null @@ -1,1393 +0,0 @@ -use secure_exec_kernel::process_table::{ - DriverProcess, ProcessContext, ProcessExitCallback, ProcessResult, ProcessStatus, ProcessTable, - ProcessWaitEvent, SigmaskHow, SignalSet, WaitPidFlags, SIGCHLD, SIGCONT, SIGHUP, SIGSTOP, - SIGTERM, SIGTSTP, -}; -use std::collections::BTreeMap; -use std::fmt::Debug; -use std::sync::{mpsc, Arc, Condvar, Mutex}; -use std::thread; -use std::time::{Duration, Instant}; - -fn assert_error_code(result: ProcessResult, expected: &str) { - let error = result.expect_err("operation should fail"); - assert_eq!(error.code(), expected); -} - -#[derive(Default)] -struct MockProcessState { - kills: Vec, - exit_code: Option, - on_exit: Option, - ignore_sigterm: bool, -} - -#[derive(Default)] -struct MockDriverProcess { - state: Mutex, - exited: Condvar, -} - -impl MockDriverProcess { - fn new() -> Arc { - Arc::new(Self::default()) - } - - fn stubborn() -> Arc { - Arc::new(Self { - state: Mutex::new(MockProcessState { - ignore_sigterm: true, - ..MockProcessState::default() - }), - exited: Condvar::new(), - }) - } - - fn schedule_exit(self: &Arc, delay: Duration, exit_code: i32) { - let process = Arc::clone(self); - thread::spawn(move || { - thread::sleep(delay); - process.exit(exit_code); - }); - } - - fn exit(&self, exit_code: i32) { - let callback = { - let mut state = self.state.lock().expect("mock process lock poisoned"); - if state.exit_code.is_some() { - return; - } - state.exit_code = Some(exit_code); - self.exited.notify_all(); - state.on_exit.clone() - }; - - if let Some(callback) = callback { - callback(exit_code); - } - } - - fn kills(&self) -> Vec { - self.state - .lock() - .expect("mock process lock poisoned") - .kills - .clone() - } -} - -impl DriverProcess for MockDriverProcess { - fn kill(&self, signal: i32) { - let should_exit = { - let mut state = self.state.lock().expect("mock process lock poisoned"); - state.kills.push(signal); - signal == 9 || (signal == 15 && !state.ignore_sigterm) - }; - - if should_exit { - self.exit(128 + signal); - } - } - - fn wait(&self, timeout: Duration) -> Option { - let state = self.state.lock().expect("mock process lock poisoned"); - if state.exit_code.is_some() { - return state.exit_code; - } - - let (state, _) = self - .exited - .wait_timeout(state, timeout) - .expect("mock process wait lock poisoned"); - state.exit_code - } - - fn set_on_exit(&self, callback: ProcessExitCallback) { - self.state - .lock() - .expect("mock process lock poisoned") - .on_exit = Some(callback); - } -} - -fn create_context(ppid: u32) -> ProcessContext { - ProcessContext { - pid: 0, - ppid, - env: BTreeMap::new(), - cwd: String::from("/"), - ..ProcessContext::default() - } -} - -fn allocate_pid(table: &ProcessTable) -> u32 { - table.allocate_pid().expect("allocate pid") -} - -fn wait_for(predicate: impl Fn() -> bool, timeout: Duration) { - let deadline = Instant::now() + timeout; - while Instant::now() < deadline { - if predicate() { - return; - } - thread::sleep(Duration::from_millis(10)); - } - - assert!(predicate(), "condition should become true before timeout"); -} - -#[test] -fn register_allocates_expected_process_metadata_and_parent_groups() { - let table = ProcessTable::new(); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - - let parent_entry = table.register( - parent_pid, - "wasmvm", - "grep", - vec![String::from("-r"), String::from("foo")], - create_context(0), - parent, - ); - let child_entry = table.register( - child_pid, - "node", - "node", - vec![String::from("-e"), String::from("1+1")], - create_context(parent_pid), - child, - ); - - assert_eq!(parent_entry.pid, 1); - assert_eq!(child_entry.pid, 2); - assert_eq!(parent_entry.pgid, 1); - assert_eq!(parent_entry.sid, 1); - assert_eq!(child_entry.pgid, 1); - assert_eq!(child_entry.sid, 1); - assert_eq!(child_entry.driver, "node"); -} - -#[test] -fn waitpid_resolves_for_exiting_and_already_exited_processes() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let process = MockDriverProcess::new(); - let pid = allocate_pid(&table); - table.register( - pid, - "wasmvm", - "echo", - vec![String::from("hello")], - create_context(0), - process.clone(), - ); - - process.schedule_exit(Duration::from_millis(10), 0); - assert_eq!( - table.waitpid(pid).expect("waitpid should resolve"), - (pid, 0) - ); - assert_eq!(table.zombie_timer_count(), 0); - assert!( - table.get(pid).is_none(), - "waitpid should reap exited processes" - ); - - let exited_pid = allocate_pid(&table); - table.register( - exited_pid, - "wasmvm", - "true", - Vec::new(), - create_context(0), - MockDriverProcess::new(), - ); - table.mark_exited(exited_pid, 42); - - assert_eq!( - table - .waitpid(exited_pid) - .expect("waitpid should resolve immediately"), - (exited_pid, 42) - ); - assert_eq!(table.zombie_timer_count(), 0); - assert!( - table.get(exited_pid).is_none(), - "waitpid should reap already exited processes" - ); -} - -#[test] -fn long_lived_parent_retains_zombies_until_waited_under_pressure() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let parent = MockDriverProcess::new(); - let parent_pid = allocate_pid(&table); - let mut child_pids = Vec::new(); - - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent, - ); - - for index in 0..100 { - let child = MockDriverProcess::new(); - let child_pid = allocate_pid(&table); - table.register( - child_pid, - "wasmvm", - format!("child-{index}"), - Vec::new(), - create_context(parent_pid), - child.clone(), - ); - child.exit(index); - child_pids.push((child_pid, index)); - } - - for (child_pid, _) in &child_pids { - assert_eq!( - table - .get(*child_pid) - .expect("child zombie should be retained") - .status, - ProcessStatus::Exited - ); - } - assert_eq!(table.zombie_reaper_thread_spawn_count(), 1); - assert_eq!(table.zombie_timer_count(), child_pids.len()); - - for (child_pid, status) in child_pids { - assert_eq!( - table - .waitpid_for(parent_pid, -1, WaitPidFlags::empty()) - .expect("parent wait should succeed"), - Some(secure_exec_kernel::process_table::ProcessWaitResult { - pid: child_pid, - status, - event: ProcessWaitEvent::Exited, - }) - ); - } - assert_eq!(table.zombie_timer_count(), 0); -} - -#[test] -fn allocate_pid_wraps_without_reusing_live_or_zombie_entries() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let max_pid = i32::MAX as u32; - let cursor_seed = MockDriverProcess::new(); - let live_high = MockDriverProcess::new(); - let zombie_high = MockDriverProcess::new(); - let live_one = MockDriverProcess::new(); - - // Registering max_pid - 2 after the high PIDs moves the public allocation cursor back to max_pid - 1. - table.register( - max_pid - 1, - "wasmvm", - "live-high", - Vec::new(), - create_context(0), - live_high, - ); - table.register( - max_pid, - "wasmvm", - "zombie-high", - Vec::new(), - create_context(0), - zombie_high.clone(), - ); - table.register( - max_pid - 2, - "wasmvm", - "cursor-seed", - Vec::new(), - create_context(0), - cursor_seed, - ); - table.register( - 1, - "wasmvm", - "live-one", - Vec::new(), - create_context(0), - live_one, - ); - zombie_high.exit(0); - - assert_eq!( - table - .get(max_pid) - .expect("zombie high PID should remain allocated") - .status, - ProcessStatus::Exited - ); - - assert_eq!(table.allocate_pid().expect("allocate wrapped pid"), 2); - assert_eq!(table.allocate_pid().expect("allocate next pid"), 3); -} - -#[test] -fn waitpid_for_supports_wnohang_and_waiting_for_any_child() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let parent = MockDriverProcess::new(); - let child_a = MockDriverProcess::new(); - let child_b = MockDriverProcess::new(); - - let parent_pid = allocate_pid(&table); - let child_a_pid = allocate_pid(&table); - let child_b_pid = allocate_pid(&table); - - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent, - ); - table.register( - child_a_pid, - "wasmvm", - "child-a", - Vec::new(), - create_context(parent_pid), - child_a, - ); - table.register( - child_b_pid, - "wasmvm", - "child-b", - Vec::new(), - create_context(parent_pid), - child_b.clone(), - ); - - assert_eq!( - table - .waitpid_for(parent_pid, -1, WaitPidFlags::WNOHANG) - .expect("wnohang wait should succeed"), - None - ); - - child_b.exit(27); - assert_eq!( - table - .waitpid_for(parent_pid, -1, WaitPidFlags::empty()) - .expect("wait for any child should succeed"), - Some(secure_exec_kernel::process_table::ProcessWaitResult { - pid: child_b_pid, - status: 27, - event: ProcessWaitEvent::Exited, - }) - ); - assert!( - table.get(child_b_pid).is_none(), - "waited child should be reaped" - ); - assert!( - table.get(child_a_pid).is_some(), - "other matching children should remain" - ); -} - -#[test] -fn on_process_exit_runs_before_waitpid_waiters_are_notified() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let process = MockDriverProcess::new(); - let pid = allocate_pid(&table); - table.register( - pid, - "wasmvm", - "sleep", - vec![String::from("1")], - create_context(0), - process.clone(), - ); - - let (callback_entered_tx, callback_entered_rx) = mpsc::channel(); - let callback_gate = Arc::new((Mutex::new(false), Condvar::new())); - let callback_gate_for_exit = Arc::clone(&callback_gate); - table.set_on_process_exit(Some(Arc::new(move |_| { - callback_entered_tx - .send(()) - .expect("callback should report entry"); - let (released, wake) = &*callback_gate_for_exit; - let mut released = released.lock().expect("callback gate lock poisoned"); - while !*released { - released = wake - .wait(released) - .expect("callback gate wait lock poisoned"); - } - }))); - - let waiter_table = table.clone(); - let (wait_result_tx, wait_result_rx) = mpsc::channel(); - let waiter = thread::spawn(move || { - let result = waiter_table.waitpid(pid).expect("waitpid should resolve"); - wait_result_tx - .send(result) - .expect("waiter should report exit result"); - }); - - thread::sleep(Duration::from_millis(10)); - let process_for_exit = process.clone(); - let exit_handle = thread::spawn(move || { - process_for_exit.exit(0); - }); - - callback_entered_rx - .recv_timeout(Duration::from_millis(100)) - .expect("exit callback should run"); - assert!(wait_result_rx.try_recv().is_err()); - - let (released, wake) = &*callback_gate; - *released.lock().expect("callback gate lock poisoned") = true; - wake.notify_all(); - assert_eq!( - wait_result_rx - .recv_timeout(Duration::from_millis(100)) - .expect("waitpid should resolve after callback"), - (pid, 0) - ); - exit_handle.join().expect("exit thread should finish"); - waiter.join().expect("waiter thread should finish"); -} - -#[test] -fn waitpid_for_reports_stopped_and_continued_children_once() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent.clone(), - ); - table.register( - child_pid, - "wasmvm", - "child", - Vec::new(), - create_context(parent_pid), - child, - ); - - table.mark_stopped(child_pid, SIGSTOP); - assert_eq!( - table - .waitpid_for(parent_pid, child_pid as i32, WaitPidFlags::WNOHANG) - .expect("stopped child lookup should succeed"), - None - ); - assert_eq!( - table - .waitpid_for( - parent_pid, - child_pid as i32, - WaitPidFlags::WNOHANG | WaitPidFlags::WUNTRACED, - ) - .expect("wuntraced wait should succeed"), - Some(secure_exec_kernel::process_table::ProcessWaitResult { - pid: child_pid, - status: SIGSTOP, - event: ProcessWaitEvent::Stopped, - }) - ); - assert_eq!( - table - .get(child_pid) - .expect("child remains registered") - .status, - ProcessStatus::Stopped - ); - - table.mark_continued(child_pid); - assert_eq!( - table - .waitpid_for( - parent_pid, - child_pid as i32, - WaitPidFlags::WNOHANG | WaitPidFlags::WCONTINUED, - ) - .expect("wcontinued wait should succeed"), - Some(secure_exec_kernel::process_table::ProcessWaitResult { - pid: child_pid, - status: SIGCONT, - event: ProcessWaitEvent::Continued, - }) - ); - assert_eq!( - table - .get(child_pid) - .expect("child remains registered") - .status, - ProcessStatus::Running - ); - assert_eq!(parent.kills(), vec![SIGCHLD, SIGCHLD]); -} - -#[test] -fn kill_routes_signals_and_validates_process_existence() { - let table = ProcessTable::new(); - let process = MockDriverProcess::new(); - let pid = allocate_pid(&table); - table.register( - pid, - "wasmvm", - "sleep", - vec![String::from("1")], - create_context(0), - process.clone(), - ); - - table - .kill(pid as i32, 0) - .expect("signal 0 is an existence check"); - assert!(process.kills().is_empty()); - - table - .kill(pid as i32, 15) - .expect("signal should be delivered"); - assert_eq!(process.kills(), vec![15]); - - assert_error_code(table.kill(999, 15), "ESRCH"); - assert_error_code(table.kill(pid as i32, -1), "EINVAL"); - assert_error_code(table.kill(pid as i32, 100), "EINVAL"); -} - -#[test] -fn kill_updates_job_control_state_for_stop_and_continue_signals() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent.clone(), - ); - table.register( - child_pid, - "wasmvm", - "child", - Vec::new(), - create_context(parent_pid), - child.clone(), - ); - - table - .kill(child_pid as i32, SIGTSTP) - .expect("SIGTSTP should stop the child"); - assert_eq!(child.kills(), vec![SIGTSTP]); - assert_eq!( - table - .get(child_pid) - .expect("child remains registered") - .status, - ProcessStatus::Stopped - ); - assert_eq!( - table - .waitpid_for( - parent_pid, - child_pid as i32, - WaitPidFlags::WNOHANG | WaitPidFlags::WUNTRACED, - ) - .expect("stopped child wait should succeed"), - Some(secure_exec_kernel::process_table::ProcessWaitResult { - pid: child_pid, - status: SIGTSTP, - event: ProcessWaitEvent::Stopped, - }) - ); - - table - .kill(child_pid as i32, SIGCONT) - .expect("SIGCONT should continue the child"); - assert_eq!(child.kills(), vec![SIGTSTP, SIGCONT]); - assert_eq!( - table - .get(child_pid) - .expect("child remains registered") - .status, - ProcessStatus::Running - ); - assert_eq!( - table - .waitpid_for( - parent_pid, - child_pid as i32, - WaitPidFlags::WNOHANG | WaitPidFlags::WCONTINUED, - ) - .expect("continued child wait should succeed"), - Some(secure_exec_kernel::process_table::ProcessWaitResult { - pid: child_pid, - status: SIGCONT, - event: ProcessWaitEvent::Continued, - }) - ); - assert_eq!(parent.kills(), vec![SIGCHLD, SIGCHLD]); -} - -#[test] -fn exiting_child_delivers_sigchld_to_living_parent() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent.clone(), - ); - table.register( - child_pid, - "wasmvm", - "child", - Vec::new(), - create_context(parent_pid), - child.clone(), - ); - - child.exit(0); - - wait_for( - || parent.kills() == vec![SIGCHLD], - Duration::from_millis(100), - ); - assert_eq!( - table.waitpid(child_pid).expect("reap child"), - (child_pid, 0) - ); -} - -#[test] -fn blocked_sigchld_is_queued_until_the_parent_unblocks_it() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - let sigchld_mask = SignalSet::from_signal(SIGCHLD).expect("SIGCHLD should be valid"); - - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent.clone(), - ); - table.register( - child_pid, - "wasmvm", - "child", - Vec::new(), - create_context(parent_pid), - child.clone(), - ); - - assert_eq!( - table - .sigprocmask(parent_pid, SigmaskHow::Block, sigchld_mask) - .expect("block SIGCHLD"), - SignalSet::empty() - ); - - child.exit(0); - - wait_for( - || { - table - .get(child_pid) - .is_some_and(|entry| entry.status == ProcessStatus::Exited) - }, - Duration::from_millis(100), - ); - assert!(parent.kills().is_empty(), "SIGCHLD should remain pending"); - assert_eq!( - table.sigpending(parent_pid).expect("pending signals"), - sigchld_mask - ); - - table - .sigprocmask(parent_pid, SigmaskHow::Unblock, sigchld_mask) - .expect("unblock SIGCHLD"); - - wait_for( - || parent.kills() == vec![SIGCHLD], - Duration::from_millis(100), - ); - assert_eq!( - table.sigpending(parent_pid).expect("pending signals"), - SignalSet::empty() - ); -} - -#[test] -fn killed_child_delivers_sigchld_to_living_parent() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent.clone(), - ); - table.register( - child_pid, - "wasmvm", - "child", - Vec::new(), - create_context(parent_pid), - child.clone(), - ); - - table - .kill(child_pid as i32, 15) - .expect("deliver SIGTERM to child"); - - wait_for( - || parent.kills() == vec![SIGCHLD], - Duration::from_millis(100), - ); - assert_eq!( - table.waitpid(child_pid).expect("reap killed child"), - (child_pid, 143) - ); -} - -#[test] -fn blocked_sigterm_is_delivered_when_the_process_unblocks_it() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let process = MockDriverProcess::new(); - let pid = allocate_pid(&table); - let sigterm_mask = SignalSet::from_signal(SIGTERM).expect("SIGTERM should be valid"); - - table.register( - pid, - "wasmvm", - "sleep", - Vec::new(), - create_context(0), - process.clone(), - ); - - table - .sigprocmask(pid, SigmaskHow::Block, sigterm_mask) - .expect("block SIGTERM"); - table - .kill(pid as i32, SIGTERM) - .expect("queue blocked SIGTERM"); - - assert!( - process.kills().is_empty(), - "blocked SIGTERM should not deliver" - ); - assert_eq!( - table.sigpending(pid).expect("pending signals"), - sigterm_mask - ); - - table - .sigprocmask(pid, SigmaskHow::Unblock, sigterm_mask) - .expect("unblock SIGTERM"); - - wait_for( - || process.kills() == vec![SIGTERM], - Duration::from_millis(100), - ); - assert_eq!(table.waitpid(pid).expect("reap SIGTERM exit"), (pid, 143)); -} - -#[test] -fn process_groups_and_sessions_follow_legacy_rules() { - let table = ProcessTable::new(); - - let p1 = allocate_pid(&table); - let p2 = allocate_pid(&table); - let p3 = allocate_pid(&table); - let p4 = allocate_pid(&table); - - table.register( - p1, - "wasmvm", - "sh", - Vec::new(), - create_context(0), - MockDriverProcess::new(), - ); - table.register( - p2, - "wasmvm", - "child", - Vec::new(), - create_context(p1), - MockDriverProcess::new(), - ); - table.register( - p3, - "wasmvm", - "peer", - Vec::new(), - create_context(p1), - MockDriverProcess::new(), - ); - table.register( - p4, - "wasmvm", - "other", - Vec::new(), - create_context(p1), - MockDriverProcess::new(), - ); - - table - .setpgid(p2, 0) - .expect("process can create its own group"); - table - .setpgid(p3, p2) - .expect("peer can join an existing group in the same session"); - assert_eq!(table.getpgid(p2).expect("pgid"), p2); - assert_eq!(table.getpgid(p3).expect("pgid"), p2); - assert!(table.has_process_group(p2)); - - table.setsid(p4).expect("child can become a session leader"); - assert_eq!(table.getsid(p4).expect("sid"), p4); - assert_error_code(table.setpgid(p3, p4), "EPERM"); -} - -#[test] -fn negative_pid_kill_targets_entire_process_groups() { - let table = ProcessTable::new(); - let leader = MockDriverProcess::new(); - let peer = MockDriverProcess::new(); - let pid1 = allocate_pid(&table); - let pid2 = allocate_pid(&table); - - table.register( - pid1, - "wasmvm", - "leader", - Vec::new(), - create_context(0), - leader.clone(), - ); - table.register( - pid2, - "wasmvm", - "peer", - Vec::new(), - create_context(pid1), - peer.clone(), - ); - table.setpgid(pid2, pid1).expect("peer joins leader group"); - - table - .kill(-(pid1 as i32), 15) - .expect("group kill should succeed"); - - assert_eq!(leader.kills(), vec![15]); - assert_eq!(peer.kills(), vec![15]); -} - -#[test] -fn negative_pid_signal_zero_checks_process_group_liveness() { - let table = ProcessTable::new(); - let leader = MockDriverProcess::new(); - let peer = MockDriverProcess::new(); - let leader_pid = allocate_pid(&table); - let peer_pid = allocate_pid(&table); - - table.register( - leader_pid, - "wasmvm", - "leader", - Vec::new(), - create_context(0), - leader.clone(), - ); - table.register( - peer_pid, - "wasmvm", - "peer", - Vec::new(), - create_context(leader_pid), - peer.clone(), - ); - table - .setpgid(peer_pid, leader_pid) - .expect("peer joins leader group"); - - table - .kill(-(leader_pid as i32), 0) - .expect("signal 0 should check process group liveness"); - - assert!(leader.kills().is_empty()); - assert!(peer.kills().is_empty()); - assert_error_code(table.kill(-999, 0), "ESRCH"); -} - -#[test] -fn negative_pid_kill_reaches_stopped_and_exited_group_members() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let init = MockDriverProcess::new(); - let parent = MockDriverProcess::new(); - let leader = MockDriverProcess::stubborn(); - let stopped = MockDriverProcess::stubborn(); - let zombie = MockDriverProcess::stubborn(); - let init_pid = allocate_pid(&table); - let parent_pid = allocate_pid(&table); - let leader_pid = allocate_pid(&table); - let stopped_pid = allocate_pid(&table); - let zombie_pid = allocate_pid(&table); - - table.register( - init_pid, - "wasmvm", - "init", - Vec::new(), - create_context(0), - init, - ); - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(init_pid), - parent, - ); - table.register( - leader_pid, - "wasmvm", - "leader", - Vec::new(), - create_context(parent_pid), - leader.clone(), - ); - table.register( - stopped_pid, - "wasmvm", - "stopped", - Vec::new(), - create_context(parent_pid), - stopped.clone(), - ); - table.register( - zombie_pid, - "wasmvm", - "zombie", - Vec::new(), - create_context(parent_pid), - zombie.clone(), - ); - table - .setpgid(leader_pid, 0) - .expect("leader becomes process-group leader"); - table - .setpgid(stopped_pid, leader_pid) - .expect("stopped peer joins leader group"); - table - .setpgid(zombie_pid, leader_pid) - .expect("zombie peer joins leader group"); - table.mark_stopped(stopped_pid, SIGSTOP); - zombie.exit(23); - - table - .kill(-(leader_pid as i32), 15) - .expect("group kill should include stopped and zombie members"); - - assert_eq!(leader.kills(), vec![15]); - assert_eq!(stopped.kills(), vec![15]); - assert_eq!(zombie.kills(), vec![15]); -} - -#[test] -fn exiting_parent_reparents_children_to_pid_one_when_available() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let init = MockDriverProcess::new(); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - let init_pid = allocate_pid(&table); - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - - table.register( - init_pid, - "wasmvm", - "init", - Vec::new(), - create_context(0), - init, - ); - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(init_pid), - parent.clone(), - ); - table.register( - child_pid, - "wasmvm", - "child", - Vec::new(), - create_context(parent_pid), - child, - ); - - parent.exit(0); - - assert_eq!( - table - .getppid(child_pid) - .expect("child should be reparented"), - 1 - ); -} - -#[test] -fn orphaned_stopped_process_groups_receive_sighup_and_sigcont() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let init = MockDriverProcess::new(); - let parent = MockDriverProcess::new(); - let leader = MockDriverProcess::new(); - let stopped = MockDriverProcess::new(); - let init_pid = allocate_pid(&table); - let parent_pid = allocate_pid(&table); - let leader_pid = allocate_pid(&table); - let stopped_pid = allocate_pid(&table); - - table.register( - init_pid, - "wasmvm", - "init", - Vec::new(), - create_context(0), - init, - ); - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(init_pid), - parent.clone(), - ); - table.register( - leader_pid, - "wasmvm", - "leader", - Vec::new(), - create_context(parent_pid), - leader.clone(), - ); - table.register( - stopped_pid, - "wasmvm", - "stopped", - Vec::new(), - create_context(parent_pid), - stopped.clone(), - ); - table - .setpgid(leader_pid, 0) - .expect("leader becomes process-group leader"); - table - .setpgid(stopped_pid, leader_pid) - .expect("stopped peer joins leader group"); - table.mark_stopped(stopped_pid, SIGSTOP); - - parent.exit(0); - - assert_eq!(leader.kills(), vec![SIGHUP, SIGCONT]); - assert_eq!(stopped.kills(), vec![SIGHUP, SIGCONT]); -} - -#[test] -fn terminate_all_escalates_from_sigterm_to_sigkill_for_survivors() { - let table = ProcessTable::new(); - let graceful = MockDriverProcess::new(); - let stubborn = MockDriverProcess::stubborn(); - - let pid1 = allocate_pid(&table); - let pid2 = allocate_pid(&table); - table.register( - pid1, - "wasmvm", - "graceful", - Vec::new(), - create_context(0), - graceful.clone(), - ); - table.register( - pid2, - "wasmvm", - "stubborn", - Vec::new(), - create_context(0), - stubborn.clone(), - ); - - table.terminate_all(); - - assert_eq!(graceful.kills(), vec![15]); - assert_eq!(stubborn.kills(), vec![15, 9]); - assert_eq!( - table - .get(pid1) - .expect("graceful process should remain as zombie") - .status, - ProcessStatus::Exited - ); - assert_eq!( - table - .get(pid2) - .expect("stubborn process should remain as zombie") - .status, - ProcessStatus::Exited - ); - assert_eq!(table.zombie_timer_count(), 0); -} - -#[test] -fn list_processes_returns_a_snapshot_of_registered_processes() { - let table = ProcessTable::new(); - let pid1 = allocate_pid(&table); - let pid2 = allocate_pid(&table); - - table.register( - pid1, - "wasmvm", - "ls", - Vec::new(), - create_context(0), - MockDriverProcess::new(), - ); - table.register( - pid2, - "node", - "node", - Vec::new(), - create_context(0), - MockDriverProcess::new(), - ); - - let processes = table.list_processes(); - assert_eq!(processes.len(), 2); - assert_eq!(processes.get(&pid1).expect("process info").command, "ls"); - assert_eq!(processes.get(&pid2).expect("process info").driver, "node"); -} - -#[test] -fn waitpid_rejects_unknown_processes() { - let table = ProcessTable::new(); - assert_error_code(table.waitpid(9999), "ESRCH"); -} - -#[test] -fn waitpid_for_supports_pid_zero_and_negative_process_group_selectors() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let parent = MockDriverProcess::new(); - let same_group_child = MockDriverProcess::new(); - let other_group_child = MockDriverProcess::new(); - - let parent_pid = allocate_pid(&table); - let same_group_child_pid = allocate_pid(&table); - let other_group_child_pid = allocate_pid(&table); - - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent, - ); - table.register( - same_group_child_pid, - "wasmvm", - "same-group", - Vec::new(), - create_context(parent_pid), - same_group_child.clone(), - ); - table.register( - other_group_child_pid, - "wasmvm", - "other-group", - Vec::new(), - create_context(parent_pid), - other_group_child.clone(), - ); - table - .setpgid(other_group_child_pid, 0) - .expect("child should become group leader"); - - other_group_child.exit(13); - assert_eq!( - table - .waitpid_for(parent_pid, 0, WaitPidFlags::WNOHANG) - .expect("pid=0 wait should succeed"), - None - ); - - same_group_child.exit(11); - assert_eq!( - table - .waitpid_for(parent_pid, 0, WaitPidFlags::empty()) - .expect("pid=0 wait should reap same-group child"), - Some(secure_exec_kernel::process_table::ProcessWaitResult { - pid: same_group_child_pid, - status: 11, - event: ProcessWaitEvent::Exited, - }) - ); - assert_eq!( - table - .waitpid_for( - parent_pid, - -(other_group_child_pid as i32), - WaitPidFlags::empty(), - ) - .expect("negative pgid wait should reap matching child"), - Some(secure_exec_kernel::process_table::ProcessWaitResult { - pid: other_group_child_pid, - status: 13, - event: ProcessWaitEvent::Exited, - }) - ); -} - -#[test] -fn zombie_reaper_uses_a_single_worker_for_many_exits() { - let table = ProcessTable::with_zombie_ttl(Duration::from_millis(100)); - let mut pids = Vec::new(); - - for index in 0..100 { - let process = MockDriverProcess::new(); - let pid = allocate_pid(&table); - table.register( - pid, - "wasmvm", - format!("proc-{index}"), - Vec::new(), - create_context(0), - process.clone(), - ); - process.exit(0); - pids.push(pid); - } - - assert_eq!(table.zombie_reaper_thread_spawn_count(), 1); - assert_eq!(table.zombie_timer_count(), 100); - - wait_for(|| table.zombie_timer_count() == 0, Duration::from_secs(2)); - - for pid in pids { - assert!(table.get(pid).is_none(), "process {pid} should be reaped"); - } -} - -#[test] -fn zombie_reaper_preserves_child_exit_code_while_parent_is_alive() { - let table = ProcessTable::with_zombie_ttl(Duration::from_millis(50)); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent, - ); - table.register( - child_pid, - "wasmvm", - "child", - Vec::new(), - create_context(parent_pid), - child.clone(), - ); - - child.exit(41); - thread::sleep(Duration::from_millis(200)); - - assert_eq!( - table - .waitpid(child_pid) - .expect("child exit code should be preserved"), - (child_pid, 41) - ); -} - -#[test] -fn zombie_reaper_reaps_exited_children_after_their_parent_exits() { - let table = ProcessTable::with_zombie_ttl(Duration::from_millis(50)); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent.clone(), - ); - table.register( - child_pid, - "wasmvm", - "child", - Vec::new(), - create_context(parent_pid), - child.clone(), - ); - - child.exit(17); - thread::sleep(Duration::from_millis(120)); - parent.exit(0); - - wait_for( - || table.get(parent_pid).is_none() && table.get(child_pid).is_none(), - Duration::from_secs(1), - ); -} diff --git a/crates/kernel/tests/pty.rs b/crates/kernel/tests/pty.rs deleted file mode 100644 index 00e85e0d5..000000000 --- a/crates/kernel/tests/pty.rs +++ /dev/null @@ -1,752 +0,0 @@ -use secure_exec_kernel::pty::{ - LineDisciplineConfig, PartialTermios, PartialTermiosControlChars, PtyManager, MAX_CANON, - MAX_PTY_BUFFER_BYTES, SIGINT, -}; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, Instant}; - -fn wait_for(predicate: impl Fn() -> bool, timeout: Duration) { - let deadline = Instant::now() + timeout; - while Instant::now() < deadline { - if predicate() { - return; - } - std::thread::sleep(Duration::from_millis(10)); - } - - assert!(predicate(), "condition should become true before timeout"); -} - -#[test] -fn raw_mode_delivers_bytes_and_applies_icrnl_translation() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - manager - .set_discipline( - pty.master.description.id(), - LineDisciplineConfig { - canonical: Some(false), - echo: Some(false), - isig: Some(false), - ..Default::default() - }, - ) - .expect("set raw mode"); - - manager - .write(pty.master.description.id(), b"hello\rworld") - .expect("write master"); - let data = manager - .read(pty.slave.description.id(), 64) - .expect("read slave") - .expect("slave should receive data"); - - assert_eq!(String::from_utf8(data).expect("valid utf8"), "hello\nworld"); -} - -#[test] -fn raw_mode_pending_short_read_buffers_remaining_bytes() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - manager - .set_discipline( - pty.master.description.id(), - LineDisciplineConfig { - canonical: Some(false), - echo: Some(false), - isig: Some(false), - ..Default::default() - }, - ) - .expect("set raw mode"); - - let reader = { - let manager = manager.clone(); - let slave_id = pty.slave.description.id(); - std::thread::spawn(move || { - manager - .read_with_timeout(slave_id, 1, Some(Duration::from_secs(1))) - .expect("pending short read") - .expect("first byte should be delivered") - }) - }; - - manager - .write(pty.master.description.id(), b"hello") - .expect("write raw input"); - - let first = reader.join().expect("reader thread should finish"); - assert_eq!(first, b"h"); - - let remaining = manager - .read(pty.slave.description.id(), 64) - .expect("read remaining bytes") - .expect("remaining bytes should stay buffered"); - assert_eq!(remaining, b"ello"); -} - -#[test] -fn split_delivery_with_second_queued_reader_leaves_no_stale_waiters() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - manager - .set_discipline( - pty.master.description.id(), - LineDisciplineConfig { - canonical: Some(false), - echo: Some(false), - isig: Some(false), - ..Default::default() - }, - ) - .expect("set raw mode"); - - let slave_id = pty.slave.description.id(); - - // Reader A asks for one byte and must be first in the waiter queue. - let reader_a = { - let manager = manager.clone(); - std::thread::spawn(move || { - manager - .read_with_timeout(slave_id, 1, Some(Duration::from_secs(5))) - .expect("first read should succeed") - .expect("first read should deliver data") - }) - }; - wait_for( - || manager.pending_read_waiter_count() == 1, - Duration::from_secs(1), - ); - - // Reader B queues behind A and will pick up the buffered tail. - let reader_b = { - let manager = manager.clone(); - std::thread::spawn(move || { - manager - .read_with_timeout(slave_id, 64, Some(Duration::from_secs(5))) - .expect("second read should succeed") - .expect("second read should deliver data") - }) - }; - wait_for( - || manager.pending_read_waiter_count() == 2, - Duration::from_secs(1), - ); - - // The split delivery hands "h" to reader A and buffers "ello", which - // reader B drains directly from the input buffer. - manager - .write(pty.master.description.id(), b"hello") - .expect("write raw input"); - - assert_eq!(reader_a.join().expect("reader A should finish"), b"h"); - assert_eq!(reader_b.join().expect("reader B should finish"), b"ello"); - - // Reader B returned via the direct buffer-drain path, so its waiter - // entry and queue id must be gone. - assert_eq!(manager.pending_read_waiter_count(), 0); - assert_eq!(manager.queued_read_waiter_count(), 0); - - // A stale waiter would swallow this write and the read would time out. - manager - .write(pty.master.description.id(), b"world") - .expect("write after split delivery"); - let follow_up = manager - .read_with_timeout(slave_id, 64, Some(Duration::from_secs(1))) - .expect("follow-up read should succeed") - .expect("follow-up read should deliver data"); - assert_eq!(follow_up, b"world"); -} - -#[test] -fn split_output_delivery_with_second_queued_reader_leaves_no_stale_waiters() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - manager - .set_discipline( - pty.master.description.id(), - LineDisciplineConfig { - canonical: Some(false), - echo: Some(false), - isig: Some(false), - ..Default::default() - }, - ) - .expect("set raw mode"); - - let master_id = pty.master.description.id(); - - // Reader A asks for one byte and must be first in the waiter queue. - let reader_a = { - let manager = manager.clone(); - std::thread::spawn(move || { - manager - .read_with_timeout(master_id, 1, Some(Duration::from_secs(5))) - .expect("first read should succeed") - .expect("first read should deliver data") - }) - }; - wait_for( - || manager.pending_read_waiter_count() == 1, - Duration::from_secs(1), - ); - - // Reader B queues behind A and will pick up the buffered tail. - let reader_b = { - let manager = manager.clone(); - std::thread::spawn(move || { - manager - .read_with_timeout(master_id, 64, Some(Duration::from_secs(5))) - .expect("second read should succeed") - .expect("second read should deliver data") - }) - }; - wait_for( - || manager.pending_read_waiter_count() == 2, - Duration::from_secs(1), - ); - - // The split delivery hands "h" to reader A and buffers "ello", which - // reader B drains directly from the output buffer. - manager - .write(pty.slave.description.id(), b"hello") - .expect("write slave output"); - - assert_eq!(reader_a.join().expect("reader A should finish"), b"h"); - assert_eq!(reader_b.join().expect("reader B should finish"), b"ello"); - - // Reader B returned via the direct buffer-drain path, so its waiter - // entry and queue id must be gone. - assert_eq!(manager.pending_read_waiter_count(), 0); - assert_eq!(manager.queued_read_waiter_count(), 0); - - // A stale waiter would swallow this write and the read would time out. - manager - .write(pty.slave.description.id(), b"world") - .expect("write after split delivery"); - let follow_up = manager - .read_with_timeout(master_id, 64, Some(Duration::from_secs(1))) - .expect("follow-up read should succeed") - .expect("follow-up read should deliver data"); - assert_eq!(follow_up, b"world"); -} - -#[test] -fn canonical_mode_buffers_until_newline_and_honors_backspace() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - manager - .write(pty.master.description.id(), b"echo helo\x7flo\n") - .expect("write canonical input"); - - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read canonical line") - .expect("line should be available"); - assert_eq!(String::from_utf8(line).expect("valid utf8"), "echo hello\n"); - - let echo = manager - .read(pty.master.description.id(), 64) - .expect("read echo") - .expect("echo should be available"); - assert_eq!( - String::from_utf8(echo).expect("valid utf8"), - "echo helo\x08 \x08lo\r\n" - ); -} - -#[test] -fn canonical_mode_eof_on_empty_line_returns_hangup_once() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - manager - .write(pty.master.description.id(), [0x04]) - .expect("write eof char"); - - let eof = manager - .read(pty.slave.description.id(), 64) - .expect("read eof marker"); - assert_eq!(eof, None); - - manager - .write(pty.master.description.id(), b"after\n") - .expect("write after eof marker"); - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read line after eof") - .expect("line should be available"); - assert_eq!(line, b"after\n"); -} - -#[test] -fn canonical_mode_eof_after_pending_text_delivers_text_without_eof_byte() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - manager - .write(pty.master.description.id(), b"partial\x04") - .expect("write partial line followed by eof"); - - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read partial line") - .expect("partial line should be delivered"); - assert_eq!(line, b"partial"); -} - -#[test] -fn control_characters_signal_the_foreground_process_group() { - let signals = Arc::new(Mutex::new(Vec::new())); - let signal_log = Arc::clone(&signals); - let manager = PtyManager::with_signal_handler(Arc::new(move |pgid, signal| { - signal_log - .lock() - .expect("signal log lock poisoned") - .push((pgid, signal)); - })); - let pty = manager.create_pty(); - - manager - .set_foreground_pgid(pty.master.description.id(), 42) - .expect("set foreground pgid"); - manager - .write(pty.master.description.id(), [0x03]) - .expect("write intr char"); - - assert_eq!( - *signals.lock().expect("signal log lock poisoned"), - vec![(42, SIGINT)] - ); -} - -#[test] -fn window_size_reports_default_and_resize_updates() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - let initial = manager - .window_size(pty.slave.description.id()) - .expect("read initial pty size"); - assert_eq!((initial.cols, initial.rows), (80, 24)); - - manager - .resize(pty.master.description.id(), 100, 20) - .expect("resize pty"); - let resized = manager - .window_size(pty.slave.description.id()) - .expect("read resized pty size"); - assert_eq!((resized.cols, resized.rows), (100, 20)); -} - -#[test] -fn control_character_without_foreground_process_group_clears_canonical_line() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - manager - .write(pty.master.description.id(), b"partial command") - .expect("write partial line"); - manager - .write(pty.master.description.id(), [0x03]) - .expect("write intr char"); - - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read canonical interrupt fallback") - .expect("fallback line should be available"); - assert_eq!(line, b"\n"); - - let echo = manager - .read(pty.master.description.id(), 64) - .expect("read interrupt echo") - .expect("echo should be available"); - assert_eq!( - String::from_utf8(echo).expect("valid utf8"), - "partial command^C\r\n" - ); -} - -#[test] -fn peer_close_returns_hangup_instead_of_blocking() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - manager.close(pty.master.description.id()); - let result = manager - .read(pty.slave.description.id(), 16) - .expect("read after hangup"); - - assert_eq!(result, None); -} - -#[test] -fn oversized_raw_write_fails_atomically() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - manager - .set_discipline( - pty.master.description.id(), - LineDisciplineConfig { - canonical: Some(false), - echo: Some(false), - isig: Some(false), - ..Default::default() - }, - ) - .expect("set raw mode"); - - let error = manager - .write( - pty.master.description.id(), - vec![b'x'; MAX_PTY_BUFFER_BYTES + 1], - ) - .expect_err("oversized write should fail"); - assert_eq!(error.code(), "EAGAIN"); - - manager - .write(pty.master.description.id(), vec![b'a'; MAX_CANON.min(8)]) - .expect("subsequent small write should still succeed"); - let data = manager - .read(pty.slave.description.id(), 16) - .expect("read after failed write") - .expect("data should be buffered"); - assert_eq!(data, vec![b'a'; MAX_CANON.min(8)]); -} - -#[test] -fn canonical_echo_backpressure_does_not_mutate_pending_line() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - manager - .write(pty.slave.description.id(), vec![b'x'; MAX_PTY_BUFFER_BYTES]) - .expect("fill master output buffer"); - - let error = manager - .write(pty.master.description.id(), b"a") - .expect_err("echo backpressure should reject the input byte"); - assert_eq!(error.code(), "EAGAIN"); - - let drained = manager - .read(pty.master.description.id(), MAX_PTY_BUFFER_BYTES) - .expect("read full echo buffer") - .expect("echo buffer should have data"); - assert_eq!(drained.len(), MAX_PTY_BUFFER_BYTES); - - manager - .write(pty.master.description.id(), b"\n") - .expect("newline should succeed after draining echo buffer"); - let line = manager - .read(pty.slave.description.id(), 16) - .expect("read canonical line") - .expect("line should be delivered"); - - assert_eq!(line, b"\n"); -} - -#[test] -fn many_pending_reads_are_cleaned_up_when_peer_closes() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - let reader_count = 64; - let mut readers = Vec::new(); - - for _ in 0..reader_count { - let manager = manager.clone(); - let slave_id = pty.slave.description.id(); - readers.push(std::thread::spawn(move || { - manager - .read_with_timeout(slave_id, 1, Some(Duration::from_secs(5))) - .expect("read should finish on peer close") - })); - } - - wait_for( - || manager.pending_read_waiter_count() == reader_count, - Duration::from_secs(1), - ); - - manager.close(pty.master.description.id()); - - for reader in readers { - assert_eq!(reader.join().expect("reader thread should finish"), None); - } - assert_eq!(manager.pending_read_waiter_count(), 0); - assert_eq!(manager.queued_read_waiter_count(), 0); -} - -#[test] -fn many_timed_out_reads_are_removed_from_waiter_queues() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - let reader_count = 64; - let mut readers = Vec::new(); - - for _ in 0..reader_count { - let manager = manager.clone(); - let slave_id = pty.slave.description.id(); - readers.push(std::thread::spawn(move || { - manager - .read_with_timeout(slave_id, 1, Some(Duration::from_millis(25))) - .expect_err("read should time out") - .code() - })); - } - - for reader in readers { - assert_eq!( - reader.join().expect("reader thread should finish"), - "EAGAIN" - ); - } - assert_eq!(manager.pending_read_waiter_count(), 0); - assert_eq!(manager.queued_read_waiter_count(), 0); -} - -#[test] -fn set_discipline_only_updates_requested_fields() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - manager - .set_discipline( - pty.master.description.id(), - LineDisciplineConfig { - canonical: Some(false), - echo: Some(false), - isig: Some(false), - ..Default::default() - }, - ) - .expect("set initial raw mode"); - manager - .set_discipline( - pty.master.description.id(), - LineDisciplineConfig { - echo: Some(true), - ..LineDisciplineConfig::default() - }, - ) - .expect("enable echo only"); - - let termios = manager - .get_termios(pty.master.description.id()) - .expect("read merged termios"); - assert!(!termios.icanon); - assert!(termios.echo); - assert!(!termios.isig); -} - -#[test] -fn set_termios_only_updates_requested_fields() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - manager - .set_termios( - pty.master.description.id(), - PartialTermios { - echo: Some(false), - cc: Some(PartialTermiosControlChars { - verase: Some(0x08), - ..PartialTermiosControlChars::default() - }), - ..PartialTermios::default() - }, - ) - .expect("merge termios update"); - - let termios = manager - .get_termios(pty.master.description.id()) - .expect("read merged termios"); - assert!(termios.icrnl); - assert!(termios.icanon); - assert!(!termios.echo); - assert_eq!(termios.cc.verase, 0x08); - assert_eq!(termios.cc.vintr, 0x03); -} - -#[test] -fn canonical_mode_kill_erases_the_whole_line() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - // Type "abc", then VKILL (Ctrl-U, 0x15) to wipe the line, then "xy\n". - manager - .write(pty.master.description.id(), b"abc\x15xy\n") - .expect("write canonical input with kill"); - - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read canonical line") - .expect("line should be available"); - assert_eq!(String::from_utf8(line).expect("valid utf8"), "xy\n"); - - let echo = manager - .read(pty.master.description.id(), 64) - .expect("read echo") - .expect("echo should be available"); - // "abc" echoed, then three BS-SP-BS to erase them, then "xy", then CRLF. - assert_eq!( - String::from_utf8(echo).expect("valid utf8"), - "abc\x08 \x08\x08 \x08\x08 \x08xy\r\n" - ); -} - -#[test] -fn canonical_mode_kill_on_empty_line_is_noop() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - manager - .write(pty.master.description.id(), b"\x15hi\n") - .expect("write kill on empty line"); - - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read canonical line") - .expect("line should be available"); - assert_eq!(String::from_utf8(line).expect("valid utf8"), "hi\n"); - - let echo = manager - .read(pty.master.description.id(), 64) - .expect("read echo") - .expect("echo should be available"); - // No erase output for the empty-line kill; just the "hi" echo + CRLF. - assert_eq!(String::from_utf8(echo).expect("valid utf8"), "hi\r\n"); -} - -#[test] -fn canonical_mode_werase_erases_preceding_word_and_trailing_space() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - // "foo bar " then VWERASE (Ctrl-W, 0x17) erases the trailing space and - // "bar", leaving "foo ", then "baz\n". - manager - .write(pty.master.description.id(), b"foo bar \x17baz\n") - .expect("write canonical input with werase"); - - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read canonical line") - .expect("line should be available"); - assert_eq!(String::from_utf8(line).expect("valid utf8"), "foo baz\n"); - - let echo = manager - .read(pty.master.description.id(), 64) - .expect("read echo") - .expect("echo should be available"); - // "foo bar " echoed (8 chars), then 4 BS-SP-BS erases (space + "bar"), - // then "baz", then CRLF. - let mut expected = String::from("foo bar "); - expected.push_str(&"\x08 \x08".repeat(4)); - expected.push_str("baz\r\n"); - assert_eq!(String::from_utf8(echo).expect("valid utf8"), expected); -} - -#[test] -fn canonical_mode_werase_on_leading_whitespace_only_erases_it() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - // Only whitespace before VWERASE: erase all of it, nothing else. - manager - .write(pty.master.description.id(), b" \x17done\n") - .expect("write whitespace then werase"); - - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read canonical line") - .expect("line should be available"); - assert_eq!(String::from_utf8(line).expect("valid utf8"), "done\n"); -} - -#[test] -fn canonical_mode_echoctl_echoes_control_char_in_caret_form() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - // A control char that is neither a signal, VEOF, VERASE, VKILL, VWERASE, - // nor newline (0x01 = Ctrl-A) is buffered and echoed as caret form "^A". - manager - .write(pty.master.description.id(), b"a\x01b\n") - .expect("write control char in canonical mode"); - - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read canonical line") - .expect("line should be available"); - // The raw control byte is delivered to the slave verbatim. - assert_eq!(line, b"a\x01b\n"); - - let echo = manager - .read(pty.master.description.id(), 64) - .expect("read echo") - .expect("echo should be available"); - assert_eq!(String::from_utf8(echo).expect("valid utf8"), "a^Ab\r\n"); -} - -#[test] -fn canonical_mode_erase_after_echoctl_removes_both_caret_columns() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - // Type Ctrl-A (echoed "^A", two columns), then VERASE (0x7f): the erase - // must remove both caret columns, then "z\n". - manager - .write(pty.master.description.id(), b"\x01\x7fz\n") - .expect("write control char then erase"); - - let line = manager - .read(pty.slave.description.id(), 64) - .expect("read canonical line") - .expect("line should be available"); - assert_eq!(line, b"z\n"); - - let echo = manager - .read(pty.master.description.id(), 64) - .expect("read echo") - .expect("echo should be available"); - // "^A" echoed, then two BS-SP-BS to erase both columns, then "z", then CRLF. - let mut expected = String::from("^A"); - expected.push_str(&"\x08 \x08".repeat(2)); - expected.push_str("z\r\n"); - assert_eq!(String::from_utf8(echo).expect("valid utf8"), expected); -} - -#[test] -fn set_termios_updates_kill_and_werase_control_chars() { - let manager = PtyManager::new(); - let pty = manager.create_pty(); - - let termios = manager - .get_termios(pty.master.description.id()) - .expect("read default termios"); - assert_eq!(termios.cc.vkill, 0x15); - assert_eq!(termios.cc.vwerase, 0x17); - - manager - .set_termios( - pty.master.description.id(), - PartialTermios { - cc: Some(PartialTermiosControlChars { - vkill: Some(0x18), - vwerase: Some(0x1a), - ..PartialTermiosControlChars::default() - }), - ..PartialTermios::default() - }, - ) - .expect("merge termios update"); - - let termios = manager - .get_termios(pty.master.description.id()) - .expect("read merged termios"); - assert_eq!(termios.cc.vkill, 0x18); - assert_eq!(termios.cc.vwerase, 0x1a); - // Unspecified control chars keep their defaults. - assert_eq!(termios.cc.verase, 0x7f); -} diff --git a/crates/kernel/tests/resource_accounting.rs b/crates/kernel/tests/resource_accounting.rs deleted file mode 100644 index 8462363a2..000000000 --- a/crates/kernel/tests/resource_accounting.rs +++ /dev/null @@ -1,1487 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::fd_table::O_RDWR; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, SpawnOptions, SEEK_SET}; -use secure_exec_kernel::mount_table::{MountOptions, MountTable}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::pty::LineDisciplineConfig; -use secure_exec_kernel::resource_accounting::{ - ResourceLimits, DEFAULT_MAX_CONNECTIONS, DEFAULT_MAX_OPEN_FDS, DEFAULT_MAX_PIPES, - DEFAULT_MAX_PROCESSES, DEFAULT_MAX_PTYS, DEFAULT_MAX_SOCKETS, - DEFAULT_MAX_SOCKET_BUFFERED_BYTES, DEFAULT_MAX_SOCKET_DATAGRAM_QUEUE_LEN, - DEFAULT_VIRTUAL_CPU_COUNT, -}; -use secure_exec_kernel::root_fs::{ - FilesystemEntry, RootFileSystem, RootFilesystemDescriptor, RootFilesystemMode, - RootFilesystemSnapshot, -}; -use secure_exec_kernel::socket_table::{InetSocketAddress, SocketSpec}; -use secure_exec_kernel::vfs::{MemoryFileSystem, VirtualFileSystem}; -use std::collections::BTreeMap; -use std::time::{Duration, Instant}; - -#[test] -fn resource_snapshot_counts_processes_fds_pipes_and_ptys() { - let mut config = KernelVmConfig::new("vm-resources"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - let (read_fd, write_fd) = kernel.open_pipe("shell", process.pid()).expect("open pipe"); - let (master_fd, slave_fd, _) = kernel.open_pty("shell", process.pid()).expect("open pty"); - kernel - .pty_set_discipline( - "shell", - process.pid(), - master_fd, - LineDisciplineConfig { - canonical: Some(false), - echo: Some(false), - isig: Some(false), - ..Default::default() - }, - ) - .expect("set raw pty"); - - kernel - .fd_write("shell", process.pid(), write_fd, b"pipe-data") - .expect("write pipe"); - kernel - .fd_write("shell", process.pid(), master_fd, b"term") - .expect("write pty"); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.running_processes, 1); - assert_eq!(snapshot.fd_tables, 1); - assert_eq!(snapshot.pipes, 1); - assert_eq!(snapshot.ptys, 1); - assert_eq!(snapshot.open_fds, 7); - assert_eq!(snapshot.pipe_buffered_bytes, 9); - assert_eq!(snapshot.pty_buffered_input_bytes, 4); - assert_eq!(snapshot.pty_buffered_output_bytes, 0); - - let _ = kernel - .fd_read("shell", process.pid(), read_fd, 16) - .expect("drain pipe"); - let _ = kernel - .fd_read("shell", process.pid(), slave_fd, 16) - .expect("drain pty"); - process.finish(0); - kernel.wait_and_reap(process.pid()).expect("reap process"); -} - -#[test] -fn resource_limits_default_to_bounded_values() { - let limits = ResourceLimits::default(); - - assert_eq!(limits.virtual_cpu_count, Some(DEFAULT_VIRTUAL_CPU_COUNT)); - assert_eq!(limits.max_processes, Some(DEFAULT_MAX_PROCESSES)); - assert_eq!(limits.max_open_fds, Some(DEFAULT_MAX_OPEN_FDS)); - assert_eq!(limits.max_pipes, Some(DEFAULT_MAX_PIPES)); - assert_eq!(limits.max_ptys, Some(DEFAULT_MAX_PTYS)); - assert_eq!(limits.max_sockets, Some(DEFAULT_MAX_SOCKETS)); - assert_eq!(limits.max_connections, Some(DEFAULT_MAX_CONNECTIONS)); - assert_eq!( - limits.max_socket_buffered_bytes, - Some(DEFAULT_MAX_SOCKET_BUFFERED_BYTES) - ); - assert_eq!( - limits.max_socket_datagram_queue_len, - Some(DEFAULT_MAX_SOCKET_DATAGRAM_QUEUE_LEN) - ); -} - -#[test] -fn socket_stream_buffered_bytes_count_against_resource_limits() { - let mut config = KernelVmConfig::new("vm-socket-buffer-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_socket_buffered_bytes: Some(5), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - let writer = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn writer"); - let reader = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn reader"); - let writer_socket = kernel - .socket_create("shell", writer.pid(), SocketSpec::tcp()) - .expect("create writer socket"); - let reader_socket = kernel - .socket_create("shell", reader.pid(), SocketSpec::tcp()) - .expect("create reader socket"); - kernel - .socket_connect_pair("shell", writer.pid(), writer_socket, reader_socket) - .expect("connect socket pair"); - - kernel - .socket_write("shell", writer.pid(), writer_socket, b"12345") - .expect("fill stream receive buffer budget"); - assert_eq!(kernel.resource_snapshot().socket_buffered_bytes, 5); - - let error = kernel - .socket_write("shell", writer.pid(), writer_socket, b"!") - .expect_err("extra byte should exceed buffered byte limit"); - assert_eq!(error.code(), "EAGAIN"); - assert_eq!(kernel.resource_snapshot().socket_buffered_bytes, 5); - - let drained = kernel - .socket_read("shell", reader.pid(), reader_socket, 5) - .expect("drain stream receive buffer") - .expect("stream payload"); - assert_eq!(drained, b"12345"); - assert_eq!(kernel.resource_snapshot().socket_buffered_bytes, 0); - - kernel - .socket_write("shell", writer.pid(), writer_socket, b"!") - .expect("write should succeed after draining stream buffer"); - assert_eq!(kernel.resource_snapshot().socket_buffered_bytes, 1); -} - -#[test] -fn udp_datagram_queue_counts_against_resource_limits() { - let mut config = KernelVmConfig::new("vm-socket-datagram-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_socket_datagram_queue_len: Some(1), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - let sender = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn sender"); - let receiver = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn receiver"); - let sender_socket = kernel - .socket_create("shell", sender.pid(), SocketSpec::udp()) - .expect("create sender socket"); - kernel - .socket_bind_inet( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 54196), - ) - .expect("bind sender socket"); - let receiver_socket = kernel - .socket_create("shell", receiver.pid(), SocketSpec::udp()) - .expect("create receiver socket"); - kernel - .socket_bind_inet( - "shell", - receiver.pid(), - receiver_socket, - InetSocketAddress::new("127.0.0.1", 43196), - ) - .expect("bind receiver socket"); - - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43196), - b"one", - ) - .expect("enqueue first datagram"); - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_datagram_queue_len, 1); - assert_eq!(snapshot.socket_buffered_bytes, 3); - - let error = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43196), - b"two", - ) - .expect_err("second datagram should exceed queue length limit"); - assert_eq!(error.code(), "EAGAIN"); - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_datagram_queue_len, 1); - assert_eq!(snapshot.socket_buffered_bytes, 3); - - let datagram = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 16) - .expect("receive datagram") - .expect("datagram payload"); - assert_eq!(datagram.payload(), b"one"); - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_datagram_queue_len, 0); - assert_eq!(snapshot.socket_buffered_bytes, 0); - - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43196), - b"two", - ) - .expect("send should succeed after draining datagram queue"); - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_datagram_queue_len, 1); - assert_eq!(snapshot.socket_buffered_bytes, 3); -} - -#[test] -fn resource_limits_reject_extra_processes_pipes_and_ptys() { - let mut config = KernelVmConfig::new("vm-limits"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_processes: Some(1), - max_open_fds: Some(16), - max_pipes: Some(1), - max_ptys: Some(1), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn initial process"); - - let error = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect_err("second process should exceed process limit"); - assert_eq!(error.code(), "EAGAIN"); - - kernel - .open_pipe("shell", process.pid()) - .expect("first pipe should succeed"); - let error = kernel - .open_pipe("shell", process.pid()) - .expect_err("second pipe should exceed pipe limit"); - assert_eq!(error.code(), "EAGAIN"); - - kernel - .open_pty("shell", process.pid()) - .expect("first PTY should fit within the configured caps"); - let error = kernel - .open_pty("shell", process.pid()) - .expect_err("second PTY should exceed PTY limit"); - assert_eq!(error.code(), "EAGAIN"); - - process.finish(0); - kernel.wait_and_reap(process.pid()).expect("reap process"); -} - -#[test] -fn resource_limits_reject_global_fd_growth_with_enfile() { - let mut config = KernelVmConfig::new("vm-open-fd-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_open_fds: Some(8), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - kernel - .write_file("/tmp/a.txt", b"a".to_vec()) - .expect("seed first file"); - kernel - .write_file("/tmp/b.txt", b"b".to_vec()) - .expect("seed second file"); - kernel - .write_file("/tmp/c.txt", b"c".to_vec()) - .expect("seed third file"); - - let process_a = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn first process"); - kernel - .fd_open("shell", process_a.pid(), "/tmp/a.txt", 0, None) - .expect("first extra FD should fit"); - kernel - .fd_open("shell", process_a.pid(), "/tmp/b.txt", 0, None) - .expect("second extra FD should fit"); - - let process_b = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn second process at the global FD ceiling"); - - let error = kernel - .fd_open("shell", process_b.pid(), "/tmp/c.txt", 0, None) - .expect_err("extra open should exceed the VM-wide FD limit"); - assert_eq!(error.code(), "ENFILE"); - - process_a.finish(0); - kernel - .wait_and_reap(process_a.pid()) - .expect("reap first process"); - process_b.finish(0); - kernel - .wait_and_reap(process_b.pid()) - .expect("reap second process"); -} - -#[test] -fn zombie_processes_count_against_process_limits_until_reaped() { - let mut config = KernelVmConfig::new("vm-zombie-process-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_processes: Some(1), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn initial process"); - process.finish(0); - - let error = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect_err("zombie should still count against process limit"); - assert_eq!(error.code(), "EAGAIN"); - - kernel.wait_and_reap(process.pid()).expect("reap zombie"); - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn should succeed after zombie is reaped"); -} - -#[test] -fn filesystem_limits_reject_inode_growth_and_file_expansion() { - let mut config = KernelVmConfig::new("vm-filesystem-limits"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(5), - max_inode_count: Some(4), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .write_file("/tmp/a.txt", b"hello".to_vec()) - .expect("seed file within byte limit"); - kernel - .create_dir("/tmp/dir") - .expect("create directory within inode limit"); - - let write_error = kernel - .write_file("/tmp/b.txt", b"!".to_vec()) - .expect_err("additional file should exceed inode limit"); - assert_eq!(write_error.code(), "ENOSPC"); - - let truncate_error = kernel - .truncate("/tmp/a.txt", 6) - .expect_err("truncate should exceed filesystem byte limit"); - assert_eq!(truncate_error.code(), "ENOSPC"); - assert_eq!( - kernel - .read_file("/tmp/a.txt") - .expect("file should stay unchanged"), - b"hello".to_vec() - ); -} - -#[test] -fn filesystem_limits_reject_fd_pwrite_before_resizing_file() { - let mut config = KernelVmConfig::new("vm-fd-pwrite-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(16), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .filesystem_mut() - .write_file("/tmp/data.txt", b"abc".to_vec()) - .expect("seed file"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - let fd = kernel - .fd_open("shell", process.pid(), "/tmp/data.txt", 0, None) - .expect("open file"); - - let error = kernel - .fd_pwrite("shell", process.pid(), fd, b"z", 16) - .expect_err("pwrite should exceed filesystem byte limit"); - assert_eq!(error.code(), "ENOSPC"); - assert_eq!( - kernel - .read_file("/tmp/data.txt") - .expect("file should stay unchanged"), - b"abc".to_vec() - ); - - process.finish(0); - kernel.wait_and_reap(process.pid()).expect("reap shell"); -} - -#[test] -fn filesystem_limits_ignore_read_only_mount_usage() { - let mut config = KernelVmConfig::new("vm-mounted-filesystem-limits"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(16), - ..ResourceLimits::default() - }; - - let mut mounted = MemoryFileSystem::new(); - mounted - .write_file("/big.bin", vec![b'x'; 1024]) - .expect("seed mounted file"); - - let mut kernel = KernelVm::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .filesystem_mut() - .inner_mut() - .inner_mut() - .mount("/mnt", mounted, MountOptions::new("memory").read_only(true)) - .expect("mount read-only filesystem"); - - kernel - .write_file("/tmp/a.txt", b"ok".to_vec()) - .expect("mounted files should not count against root filesystem byte limits"); -} - -#[test] -fn filesystem_limits_reject_overlay_rename_copy_up_before_materializing_lower_tree() { - let mut config = KernelVmConfig::new("vm-overlay-rename-copy-up-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(8), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/lower"), - FilesystemEntry::file("/lower/big.bin", vec![b'x'; 32]), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - let error = kernel - .rename("/lower", "/moved") - .expect_err("copying up lower tree should exceed byte limit"); - assert_eq!(error.code(), "ENOSPC"); - assert_eq!( - kernel - .read_file("/lower/big.bin") - .expect("source tree should remain readable"), - vec![b'x'; 32] - ); - assert!(!kernel.exists("/moved").expect("check destination")); -} - -#[test] -fn filesystem_limits_preserve_read_only_error_before_overlay_rename_copy_up_limit() { - let mut config = KernelVmConfig::new("vm-overlay-rename-copy-up-read-only"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(8), - ..ResourceLimits::default() - }; - - let mut root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::ReadOnly, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/lower"), - FilesystemEntry::file("/lower/big.bin", vec![b'x'; 32]), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("build root filesystem"); - root.finish_bootstrap(); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - let error = kernel - .rename("/lower", "/moved") - .expect_err("read-only root should reject before copy-up accounting"); - assert_eq!(error.code(), "EROFS"); -} - -#[test] -fn filesystem_limits_preserve_missing_destination_parent_before_overlay_rename_copy_up_limit() { - let mut config = KernelVmConfig::new("vm-overlay-rename-copy-up-missing-parent"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(8), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/lower"), - FilesystemEntry::file("/lower/big.bin", vec![b'x'; 32]), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - let error = kernel - .rename("/lower", "/missing/moved") - .expect_err("missing destination parent should reject before copy-up accounting"); - assert_eq!(error.code(), "ENOENT"); -} - -#[test] -fn filesystem_limits_allow_overlay_rename_into_lower_only_destination_parent() { - let mut config = KernelVmConfig::new("vm-overlay-rename-lower-destination-parent"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_inode_count: Some(3), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/dest"), - FilesystemEntry::file("/dest/keep.txt", b"keep".to_vec()), - FilesystemEntry::file("/src.bin", b"src".to_vec()), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - kernel - .rename("/src.bin", "/dest/src.bin") - .expect("lower-only destination parent should be materialized first"); - assert_eq!( - kernel - .read_file("/dest/src.bin") - .expect("renamed file should be readable"), - b"src".to_vec() - ); - assert_eq!( - kernel - .read_file("/dest/keep.txt") - .expect("lower sibling should remain visible"), - b"keep".to_vec() - ); - assert!(!kernel.exists("/src.bin").expect("source should be hidden")); -} - -#[test] -fn filesystem_limits_allow_overlay_rename_through_lower_symlink_destination_parent() { - let mut config = KernelVmConfig::new("vm-overlay-rename-symlink-destination-parent"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_inode_count: Some(5), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/real"), - FilesystemEntry::symlink("/link", "/real"), - FilesystemEntry::file("/src.bin", b"src".to_vec()), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - kernel - .rename("/src.bin", "/link/src.bin") - .expect("symlink destination parent should resolve to materialized target"); - assert_eq!( - kernel - .read_file("/real/src.bin") - .expect("renamed file should be readable through target"), - b"src".to_vec() - ); - assert!(!kernel.exists("/src.bin").expect("source should be hidden")); -} - -#[test] -fn filesystem_limits_allow_overlay_rename_through_lower_symlink_ancestor() { - let mut config = KernelVmConfig::new("vm-overlay-rename-symlink-destination-ancestor"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_inode_count: Some(5), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/real"), - FilesystemEntry::directory("/real/subdir"), - FilesystemEntry::symlink("/link", "/real"), - FilesystemEntry::file("/src.bin", b"src".to_vec()), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - kernel - .rename("/src.bin", "/link/subdir/src.bin") - .expect("symlink ancestor should resolve to materialized target"); - assert_eq!( - kernel - .read_file("/real/subdir/src.bin") - .expect("renamed file should be readable through target"), - b"src".to_vec() - ); - assert_eq!( - kernel - .read_file("/link/subdir/src.bin") - .expect("renamed file should be readable through symlink"), - b"src".to_vec() - ); - assert!(!kernel.exists("/src.bin").expect("source should be hidden")); -} - -#[test] -fn filesystem_limits_allow_overlay_rename_through_chained_lower_symlink_destination_parent() { - let mut config = KernelVmConfig::new("vm-overlay-rename-chained-symlink-destination-parent"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_inode_count: Some(7), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/a"), - FilesystemEntry::directory("/real"), - FilesystemEntry::directory("/other"), - FilesystemEntry::symlink("/a/link", "/real"), - FilesystemEntry::symlink("/real/subdir", "/other"), - FilesystemEntry::file("/src.bin", b"src".to_vec()), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - kernel - .rename("/src.bin", "/a/link/subdir/src.bin") - .expect("chained symlink destination parent should resolve to materialized target"); - assert_eq!( - kernel - .read_file("/other/src.bin") - .expect("renamed file should be readable through final target"), - b"src".to_vec() - ); - assert_eq!( - kernel - .read_file("/a/link/subdir/src.bin") - .expect("renamed file should be readable through symlink chain"), - b"src".to_vec() - ); - assert!(!kernel.exists("/src.bin").expect("source should be hidden")); -} - -#[test] -fn filesystem_limits_allow_overlay_rename_through_upper_symlink_to_lower_destination_parent() { - let mut config = KernelVmConfig::new("vm-overlay-rename-upper-symlink-to-lower-parent"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_inode_count: Some(5), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/real"), - FilesystemEntry::directory("/real/subdir"), - FilesystemEntry::file("/src.bin", b"src".to_vec()), - ], - }], - bootstrap_entries: vec![FilesystemEntry::symlink("/link", "/real")], - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - kernel - .rename("/src.bin", "/link/subdir/src.bin") - .expect("upper symlink should resolve to lower destination parent"); - assert_eq!( - kernel - .read_file("/real/subdir/src.bin") - .expect("renamed file should be readable through target"), - b"src".to_vec() - ); - assert_eq!( - kernel - .read_file("/link/subdir/src.bin") - .expect("renamed file should be readable through symlink"), - b"src".to_vec() - ); - assert!(!kernel.exists("/src.bin").expect("source should be hidden")); -} - -#[test] -fn filesystem_limits_reject_overlay_rename_copy_up_against_existing_upper_usage() { - let mut config = KernelVmConfig::new("vm-overlay-rename-copy-up-existing-usage-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(8), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/lower"), - FilesystemEntry::file("/lower/small.bin", vec![b'x'; 7]), - ], - }], - bootstrap_entries: vec![FilesystemEntry::file("/existing.bin", vec![b'y'; 7])], - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - let error = kernel - .rename("/lower", "/moved") - .expect_err("copy-up should include current upper usage"); - assert_eq!(error.code(), "ENOSPC"); - assert_eq!( - kernel - .read_file("/lower/small.bin") - .expect("source tree should remain readable"), - vec![b'x'; 7] - ); - assert_eq!( - kernel - .read_file("/existing.bin") - .expect("existing upper file should remain readable"), - vec![b'y'; 7] - ); - assert!(!kernel.exists("/moved").expect("check destination")); -} - -#[test] -fn filesystem_limits_allow_overlay_rename_copy_up_when_replacing_upper_destination_within_limit() { - let mut config = KernelVmConfig::new("vm-overlay-rename-copy-up-replace-destination"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(13), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![FilesystemEntry::file("/src.bin", vec![b'x'; 7])], - }], - bootstrap_entries: vec![FilesystemEntry::file("/dst.bin", vec![b'y'; 7])], - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - kernel - .rename("/src.bin", "/dst.bin") - .expect("destination replacement should subtract removed upper usage"); - assert_eq!( - kernel - .read_file("/dst.bin") - .expect("destination should contain renamed source"), - vec![b'x'; 7] - ); - assert!(!kernel.exists("/src.bin").expect("source should be hidden")); -} - -#[test] -fn filesystem_limits_reject_overlay_rename_copy_up_when_replaced_destination_hardlink_remains() { - let mut config = KernelVmConfig::new("vm-overlay-rename-copy-up-hardlink-destination"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(8), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![FilesystemEntry::file("/src.bin", vec![b'x'; 7])], - }], - bootstrap_entries: vec![FilesystemEntry::file("/dst.bin", vec![b'y'; 7])], - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - kernel - .link("/dst.bin", "/alias.bin") - .expect("create destination hardlink"); - - let error = kernel - .rename("/src.bin", "/dst.bin") - .expect_err("destination alias should keep old inode usage live"); - assert_eq!(error.code(), "ENOSPC"); - assert_eq!( - kernel - .read_file("/dst.bin") - .expect("destination should remain unchanged"), - vec![b'y'; 7] - ); - assert_eq!( - kernel - .read_file("/alias.bin") - .expect("alias should remain readable"), - vec![b'y'; 7] - ); -} - -#[test] -fn filesystem_limits_reject_overlay_rename_copy_up_against_inode_limit() { - let mut config = KernelVmConfig::new("vm-overlay-rename-copy-up-inode-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_inode_count: Some(2), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/lower"), - FilesystemEntry::directory("/lower/child"), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - let error = kernel - .rename("/lower", "/moved") - .expect_err("copy-up should include current upper inode usage"); - assert_eq!(error.code(), "ENOSPC"); - assert!(kernel.exists("/lower/child").expect("source child remains")); - assert!(!kernel.exists("/moved").expect("check destination")); -} - -#[test] -fn filesystem_limits_allow_upper_only_overlay_directory_rename_at_inode_limit() { - let mut config = KernelVmConfig::new("vm-overlay-upper-only-rename-at-inode-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_inode_count: Some(3), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: Vec::new(), - bootstrap_entries: vec![ - FilesystemEntry::directory("/dir"), - FilesystemEntry::file("/dir/file.txt", b"upper".to_vec()), - ], - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - kernel - .rename("/dir", "/renamed") - .expect("upper-only rename should not allocate inodes"); - assert_eq!( - kernel - .read_file("/renamed/file.txt") - .expect("renamed file should remain readable"), - b"upper".to_vec() - ); - assert!(!kernel.exists("/dir").expect("old directory should be gone")); -} - -#[test] -fn filesystem_limits_do_not_double_count_upper_hardlinks_during_overlay_rename_preflight() { - let mut config = KernelVmConfig::new("vm-overlay-rename-hardlink-accounting"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(8), - ..ResourceLimits::default() - }; - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: Vec::new(), - bootstrap_entries: vec![FilesystemEntry::file("/existing.bin", vec![b'x'; 7])], - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - kernel - .link("/existing.bin", "/alias.bin") - .expect("create hardlink"); - - kernel - .rename("/existing.bin", "/renamed.bin") - .expect("hardlinked upper inode should be counted once"); - assert_eq!( - kernel - .read_file("/renamed.bin") - .expect("renamed hardlink source should remain readable"), - vec![b'x'; 7] - ); - assert_eq!( - kernel - .read_file("/alias.bin") - .expect("alias should remain readable"), - vec![b'x'; 7] - ); -} - -#[test] -fn filesystem_limits_preserve_not_directory_errors_for_upper_files() { - let mut config = KernelVmConfig::new("vm-overlay-read-dir-upper-file"); - config.permissions = Permissions::allow_all(); - - let root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: Vec::new(), - bootstrap_entries: vec![FilesystemEntry::file("/file.txt", b"upper".to_vec())], - }) - .expect("build root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(root), config); - - let error = kernel - .read_dir("/file.txt") - .expect_err("upper file should not read as an empty directory"); - assert_eq!(error.code(), "ENOTDIR"); -} - -#[test] -fn filesystem_limits_reject_overlay_rename_copy_up_in_nested_root_mount() { - let mut config = KernelVmConfig::new("vm-overlay-rename-copy-up-nested-mount-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(8), - ..ResourceLimits::default() - }; - - let mounted_root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/lower"), - FilesystemEntry::file("/lower/big.bin", vec![b'x'; 32]), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("build mounted root filesystem"); - let mut kernel = KernelVm::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .mount_filesystem("/mnt", mounted_root, MountOptions::new("root")) - .expect("mount root filesystem"); - - let error = kernel - .rename("/mnt/lower", "/mnt/moved") - .expect_err("nested mount copy-up should exceed byte limit"); - assert_eq!(error.code(), "ENOSPC"); - assert_eq!( - kernel - .read_file("/mnt/lower/big.bin") - .expect("source tree should remain readable"), - vec![b'x'; 32] - ); - assert!(!kernel.exists("/mnt/moved").expect("check destination")); -} - -#[test] -fn blocking_pipe_and_pty_reads_time_out_instead_of_hanging_forever() { - let mut config = KernelVmConfig::new("vm-read-timeouts"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_blocking_read_ms: Some(25), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - - let (read_fd, _write_fd) = kernel.open_pipe("shell", process.pid()).expect("open pipe"); - let (master_fd, slave_fd, _) = kernel.open_pty("shell", process.pid()).expect("open pty"); - kernel - .pty_set_discipline( - "shell", - process.pid(), - master_fd, - LineDisciplineConfig { - canonical: Some(false), - echo: Some(false), - isig: Some(false), - ..Default::default() - }, - ) - .expect("set raw pty"); - - let started = Instant::now(); - let pipe_error = kernel - .fd_read("shell", process.pid(), read_fd, 16) - .expect_err("empty pipe read should time out"); - assert_eq!(pipe_error.code(), "EAGAIN"); - assert!( - started.elapsed() >= Duration::from_millis(20), - "pipe read timed out too early: {:?}", - started.elapsed() - ); - - let started = Instant::now(); - let pty_error = kernel - .fd_read("shell", process.pid(), slave_fd, 16) - .expect_err("empty PTY read should time out"); - assert_eq!(pty_error.code(), "EAGAIN"); - assert!( - started.elapsed() >= Duration::from_millis(20), - "PTY read timed out too early: {:?}", - started.elapsed() - ); - - process.finish(0); - kernel.wait_and_reap(process.pid()).expect("reap shell"); -} - -#[test] -fn resource_limits_reject_oversized_spawn_payloads() { - let mut config = KernelVmConfig::new("vm-spawn-payload-limits"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_process_argv_bytes: Some(13), - max_process_env_bytes: Some(15), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let argv_error = kernel - .spawn_process( - "sh", - vec![String::from("1234567890")], - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect_err("oversized argv should be rejected"); - assert_eq!(argv_error.code(), "EINVAL"); - - let env_error = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - env: BTreeMap::from([(String::from("LONG"), String::from("1234567890"))]), - ..SpawnOptions::default() - }, - ) - .expect_err("oversized environment should be rejected"); - assert_eq!(env_error.code(), "EINVAL"); -} - -#[test] -fn resource_limits_reject_oversized_pread_and_write_operations() { - let mut config = KernelVmConfig::new("vm-io-op-limits"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_pread_bytes: Some(4), - max_fd_write_bytes: Some(3), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .write_file("/tmp/data.txt", b"hello".to_vec()) - .expect("seed file"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - let fd = kernel - .fd_open("shell", process.pid(), "/tmp/data.txt", 0, None) - .expect("open file"); - - let pread_error = kernel - .fd_pread("shell", process.pid(), fd, 5, 0) - .expect_err("oversized pread should be rejected"); - assert_eq!(pread_error.code(), "EINVAL"); - - let write_error = kernel - .fd_write("shell", process.pid(), fd, b"four") - .expect_err("oversized fd_write should be rejected"); - assert_eq!(write_error.code(), "EINVAL"); - - let pwrite_error = kernel - .fd_pwrite("shell", process.pid(), fd, b"four", 0) - .expect_err("oversized fd_pwrite should be rejected"); - assert_eq!(pwrite_error.code(), "EINVAL"); - - assert_eq!( - kernel - .read_file("/tmp/data.txt") - .expect("file should remain unchanged"), - b"hello".to_vec() - ); - - process.finish(0); - kernel.wait_and_reap(process.pid()).expect("reap shell"); -} - -#[test] -fn fd_write_rejects_unaddressable_sparse_offsets_without_mutating_file() { - let mut config = KernelVmConfig::new("vm-fd-write-huge-offset"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: None, - max_fd_write_bytes: Some(8), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel - .write_file("/tmp/data.txt", b"safe".to_vec()) - .expect("seed file"); - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - let fd = kernel - .fd_open("shell", process.pid(), "/tmp/data.txt", O_RDWR, None) - .expect("open file"); - kernel - .fd_seek("shell", process.pid(), fd, i64::MAX, SEEK_SET) - .expect("seek to unaddressable offset"); - - let error = kernel - .fd_write("shell", process.pid(), fd, b"x") - .expect_err("huge sparse fd_write should be rejected"); - assert_eq!(error.code(), "ENOMEM"); - assert_eq!( - kernel - .read_file("/tmp/data.txt") - .expect("file should remain unchanged"), - b"safe".to_vec() - ); -} - -#[test] -fn snapshot_root_filesystem_rejects_current_usage_over_configured_limit() { - let mut root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/workspace"), - FilesystemEntry::file("/workspace/data.txt", b"large".to_vec()), - ], - }], - bootstrap_entries: Vec::new(), - }) - .expect("create root filesystem"); - root.write_file("/workspace/extra.txt", b"extra".to_vec()) - .expect("write extra data before applying kernel limit"); - - let mut config = KernelVmConfig::new("vm-snapshot-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_filesystem_bytes: Some(4), - ..ResourceLimits::default() - }; - let mut kernel = KernelVm::new(MountTable::new(root), config); - - let error = kernel - .snapshot_root_filesystem() - .expect_err("snapshot should be rejected before cloning root contents"); - assert_eq!(error.code(), "ENOSPC"); -} - -#[test] -fn resource_limits_reject_oversized_direct_pread_before_device_allocation() { - let mut config = KernelVmConfig::new("vm-direct-pread-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_pread_bytes: Some(4), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - - let error = kernel - .pread_file("/dev/zero", 0, 5) - .expect_err("oversized direct pread should be rejected"); - assert_eq!(error.code(), "EINVAL"); - assert!( - error.to_string().contains("pread length 5"), - "unexpected error: {error}" - ); - - assert_eq!( - kernel - .pread_file("/dev/zero", 0, 4) - .expect("bounded direct pread should succeed"), - vec![0; 4] - ); -} - -#[test] -fn resource_limits_reject_oversized_fd_read_before_device_allocation() { - let mut config = KernelVmConfig::new("vm-fd-read-device-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_pread_bytes: Some(4), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - let fd = kernel - .fd_open("shell", process.pid(), "/dev/zero", 0, None) - .expect("open device"); - - let error = kernel - .fd_read("shell", process.pid(), fd, 5) - .expect_err("oversized fd read should be rejected"); - assert_eq!(error.code(), "EINVAL"); - assert!( - error.to_string().contains("pread length 5"), - "unexpected error: {error}" - ); - - assert_eq!( - kernel - .fd_read("shell", process.pid(), fd, 4) - .expect("bounded fd read should succeed"), - vec![0; 4] - ); - - process.finish(0); - kernel.wait_and_reap(process.pid()).expect("reap shell"); -} - -#[test] -fn resource_limits_reject_oversized_readdir_batches() { - let mut config = KernelVmConfig::new("vm-readdir-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_readdir_entries: Some(2), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel.create_dir("/tmp").expect("create tmp"); - kernel - .write_file("/tmp/a.txt", b"a".to_vec()) - .expect("write first entry"); - kernel - .write_file("/tmp/b.txt", b"b".to_vec()) - .expect("write second entry"); - kernel - .write_file("/tmp/c.txt", b"c".to_vec()) - .expect("write third entry"); - - let error = kernel - .read_dir("/tmp") - .expect_err("oversized readdir batch should be rejected"); - assert_eq!(error.code(), "ENOMEM"); -} diff --git a/crates/kernel/tests/smoke.rs b/crates/kernel/tests/smoke.rs deleted file mode 100644 index fe6648bf3..000000000 --- a/crates/kernel/tests/smoke.rs +++ /dev/null @@ -1,10 +0,0 @@ -use secure_exec_kernel::scaffold; - -#[test] -fn kernel_scaffold_targets_native_and_browser_sidecars() { - let scaffold = scaffold(); - - assert_eq!(scaffold.package_name, "secure-exec-kernel"); - assert!(scaffold.supports_native_sidecar); - assert!(scaffold.supports_browser_sidecar); -} diff --git a/crates/kernel/tests/socket_permissions.rs b/crates/kernel/tests/socket_permissions.rs deleted file mode 100644 index d60cd98ef..000000000 --- a/crates/kernel/tests/socket_permissions.rs +++ /dev/null @@ -1,279 +0,0 @@ -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, VirtualProcessOptions}; -use secure_exec_kernel::permissions::{ - NetworkAccessRequest, NetworkOperation, PermissionDecision, Permissions, -}; -use secure_exec_kernel::socket_table::{InetSocketAddress, SocketSpec, SocketState}; -use secure_exec_kernel::vfs::MemoryFileSystem; -use std::collections::BTreeSet; -use std::sync::{Arc, Mutex}; - -fn spawn_shell(kernel: &mut KernelVm) -> u32 { - kernel - .create_virtual_process( - "shell", - "shell", - "sh", - Vec::new(), - VirtualProcessOptions::default(), - ) - .expect("spawn shell") - .pid() -} - -fn kernel_with_network_permissions( - callback: impl Fn(&NetworkAccessRequest) -> PermissionDecision + Send + Sync + 'static, -) -> KernelVm { - let mut config = KernelVmConfig::new("vm-socket-permissions"); - config.permissions = Permissions { - network: Some(Arc::new(callback)), - ..Permissions::allow_all() - }; - KernelVm::new(MemoryFileSystem::new(), config) -} - -fn kernel_with_loopback_exempt_ports( - ports: impl IntoIterator, -) -> KernelVm { - let mut config = KernelVmConfig::new("vm-socket-loopback"); - config.permissions = Permissions::allow_all(); - config.loopback_exempt_ports = ports.into_iter().collect::>(); - KernelVm::new(MemoryFileSystem::new(), config) -} - -#[test] -fn socket_bind_inet_checks_network_listen_permission_before_mutation() { - let requests = Arc::new(Mutex::new(Vec::new())); - let requests_for_callback = Arc::clone(&requests); - let mut kernel = kernel_with_network_permissions(move |request| { - requests_for_callback - .lock() - .expect("request log lock") - .push(request.clone()); - PermissionDecision::deny("network disabled") - }); - let pid = spawn_shell(&mut kernel); - let socket = kernel - .socket_create("shell", pid, SocketSpec::tcp()) - .expect("create socket"); - - let error = kernel - .socket_bind_inet( - "shell", - pid, - socket, - InetSocketAddress::new("127.0.0.1", 8080), - ) - .expect_err("bind should be denied by network policy"); - - assert_eq!(error.code(), "EACCES"); - assert_eq!( - kernel.socket_get(socket).expect("socket exists").state(), - SocketState::Created - ); - assert_eq!( - *requests.lock().expect("request log lock"), - vec![NetworkAccessRequest { - vm_id: String::from("vm-socket-permissions"), - op: NetworkOperation::Listen, - resource: String::from("tcp://127.0.0.1:8080"), - }] - ); -} - -#[test] -fn socket_connect_inet_loopback_checks_network_http_permission_before_mutation() { - let requests = Arc::new(Mutex::new(Vec::new())); - let requests_for_callback = Arc::clone(&requests); - let mut kernel = kernel_with_network_permissions(move |request| { - requests_for_callback - .lock() - .expect("request log lock") - .push(request.clone()); - match request.op { - NetworkOperation::Listen => PermissionDecision::allow(), - NetworkOperation::Http => PermissionDecision::deny("connect disabled"), - NetworkOperation::Fetch | NetworkOperation::Dns => PermissionDecision::allow(), - } - }); - - let server_pid = spawn_shell(&mut kernel); - let listener = kernel - .socket_create("shell", server_pid, SocketSpec::tcp()) - .expect("create listener socket"); - let target = InetSocketAddress::new("127.0.0.1", 9090); - kernel - .socket_bind_inet("shell", server_pid, listener, target.clone()) - .expect("bind listener"); - kernel - .socket_listen("shell", server_pid, listener, 1) - .expect("listen"); - - let client_pid = spawn_shell(&mut kernel); - let client = kernel - .socket_create("shell", client_pid, SocketSpec::tcp()) - .expect("create client socket"); - let error = kernel - .socket_connect_inet_loopback("shell", client_pid, client, target) - .expect_err("connect should be denied by network policy"); - - assert_eq!(error.code(), "EACCES"); - assert_eq!( - kernel - .socket_get(client) - .expect("client socket exists") - .state(), - SocketState::Created - ); - assert!(requests - .lock() - .expect("request log lock") - .iter() - .any(|request| request.op == NetworkOperation::Http - && request.resource == "tcp://127.0.0.1:9090")); - assert_eq!(kernel.resource_snapshot().socket_connections, 0); -} - -#[test] -fn socket_send_to_inet_loopback_checks_network_http_permission_before_mutation() { - let requests = Arc::new(Mutex::new(Vec::new())); - let requests_for_callback = Arc::clone(&requests); - let mut kernel = kernel_with_network_permissions(move |request| { - requests_for_callback - .lock() - .expect("request log lock") - .push(request.clone()); - match request.op { - NetworkOperation::Listen => PermissionDecision::allow(), - NetworkOperation::Http => PermissionDecision::deny("udp send disabled"), - NetworkOperation::Fetch | NetworkOperation::Dns => PermissionDecision::allow(), - } - }); - - let receiver_pid = spawn_shell(&mut kernel); - let receiver = kernel - .socket_create("shell", receiver_pid, SocketSpec::udp()) - .expect("create UDP receiver"); - let target = InetSocketAddress::new("127.0.0.1", 9091); - kernel - .socket_bind_inet("shell", receiver_pid, receiver, target.clone()) - .expect("bind UDP receiver"); - - let sender_pid = spawn_shell(&mut kernel); - let sender = kernel - .socket_create("shell", sender_pid, SocketSpec::udp()) - .expect("create UDP sender"); - kernel - .socket_bind_inet( - "shell", - sender_pid, - sender, - InetSocketAddress::new("127.0.0.1", 0), - ) - .expect("bind UDP sender"); - - let error = kernel - .socket_send_to_inet_loopback("shell", sender_pid, sender, target, b"blocked") - .expect_err("UDP send should be denied by network policy"); - - assert_eq!(error.code(), "EACCES"); - assert!(requests - .lock() - .expect("request log lock") - .iter() - .any(|request| request.op == NetworkOperation::Http - && request.resource == "tcp://127.0.0.1:9091")); - let empty_queue = kernel - .socket_recv_datagram("shell", receiver_pid, receiver, 64) - .expect_err("denied UDP send must not enqueue a datagram"); - assert_eq!(empty_queue.code(), "EAGAIN"); -} - -#[test] -fn socket_connect_inet_loopback_requires_owned_or_exempt_port() { - let mut kernel = kernel_with_loopback_exempt_ports([]); - let pid = spawn_shell(&mut kernel); - let client = kernel - .socket_create("shell", pid, SocketSpec::tcp()) - .expect("create client socket"); - let error = kernel - .socket_connect_inet_loopback( - "shell", - pid, - client, - InetSocketAddress::new("127.0.0.1", 7777), - ) - .expect_err("unowned non-exempt loopback port should be denied"); - - assert_eq!(error.code(), "EPERM"); - assert!(error.to_string().contains("not loopback-exempt")); - assert_eq!(kernel.resource_snapshot().socket_connections, 0); -} - -#[test] -fn socket_connect_inet_loopback_allows_exempt_port_to_reach_connect_path() { - let mut kernel = kernel_with_loopback_exempt_ports([7777]); - let pid = spawn_shell(&mut kernel); - let client = kernel - .socket_create("shell", pid, SocketSpec::tcp()) - .expect("create client socket"); - let error = kernel - .socket_connect_inet_loopback( - "shell", - pid, - client, - InetSocketAddress::new("127.0.0.1", 7777), - ) - .expect_err("exempt but unbound loopback port should fail as not listening"); - - assert_eq!(error.code(), "ECONNREFUSED"); - assert_eq!(kernel.resource_snapshot().socket_connections, 0); -} - -#[test] -fn socket_send_to_inet_loopback_requires_owned_or_exempt_port() { - let mut kernel = kernel_with_loopback_exempt_ports([]); - let pid = spawn_shell(&mut kernel); - let socket = kernel - .socket_create("shell", pid, SocketSpec::udp()) - .expect("create UDP socket"); - kernel - .socket_bind_inet("shell", pid, socket, InetSocketAddress::new("127.0.0.1", 0)) - .expect("bind UDP socket"); - - let error = kernel - .socket_send_to_inet_loopback( - "shell", - pid, - socket, - InetSocketAddress::new("127.0.0.1", 7777), - b"hello", - ) - .expect_err("unowned non-exempt loopback UDP port should be denied"); - - assert_eq!(error.code(), "EPERM"); - assert!(error.to_string().contains("not loopback-exempt")); -} - -#[test] -fn socket_send_to_inet_loopback_allows_exempt_port_to_reach_udp_path() { - let mut kernel = kernel_with_loopback_exempt_ports([7777]); - let pid = spawn_shell(&mut kernel); - let socket = kernel - .socket_create("shell", pid, SocketSpec::udp()) - .expect("create UDP socket"); - kernel - .socket_bind_inet("shell", pid, socket, InetSocketAddress::new("127.0.0.1", 0)) - .expect("bind UDP socket"); - - let error = kernel - .socket_send_to_inet_loopback( - "shell", - pid, - socket, - InetSocketAddress::new("127.0.0.1", 7777), - b"hello", - ) - .expect_err("exempt but unbound loopback UDP port should fail as not bound"); - - assert_eq!(error.code(), "ECONNREFUSED"); -} diff --git a/crates/kernel/tests/socket_table.rs b/crates/kernel/tests/socket_table.rs deleted file mode 100644 index 786d4bf64..000000000 --- a/crates/kernel/tests/socket_table.rs +++ /dev/null @@ -1,322 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelProcessHandle, KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::socket_table::{InetSocketAddress, SocketSpec, SocketState}; -use secure_exec_kernel::vfs::MemoryFileSystem; - -fn spawn_shell(kernel: &mut KernelVm) -> KernelProcessHandle { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") -} - -fn new_kernel(vm_id: &str) -> KernelVm { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel -} - -#[test] -fn socket_resources_appear_in_kernel_resource_snapshot_and_cleanup_with_process_exit() { - let mut config = KernelVmConfig::new("vm-socket-resources"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = spawn_shell(&mut kernel); - let listener = kernel - .socket_create("shell", process.pid(), SocketSpec::tcp()) - .expect("create listener socket"); - kernel - .socket_set_state("shell", process.pid(), listener, SocketState::Listening) - .expect("mark listener"); - - let connected = kernel - .socket_create("shell", process.pid(), SocketSpec::tcp()) - .expect("create connected socket"); - kernel - .socket_set_state("shell", process.pid(), connected, SocketState::Connected) - .expect("mark connected"); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.sockets, 2); - assert_eq!(snapshot.socket_listeners, 1); - assert_eq!(snapshot.socket_connections, 1); - - process.finish(0); - - let snapshot_after_exit = kernel.resource_snapshot(); - assert_eq!(snapshot_after_exit.sockets, 0); - assert_eq!(snapshot_after_exit.socket_listeners, 0); - assert_eq!(snapshot_after_exit.socket_connections, 0); -} - -#[test] -fn socket_resource_limits_reject_extra_sockets_and_connections() { - let mut config = KernelVmConfig::new("vm-socket-limits"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_sockets: Some(2), - max_connections: Some(1), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = spawn_shell(&mut kernel); - let listener = kernel - .socket_create("shell", process.pid(), SocketSpec::tcp()) - .expect("create listener socket"); - kernel - .socket_set_state("shell", process.pid(), listener, SocketState::Listening) - .expect("mark listener"); - - let first_connection = kernel - .socket_create("shell", process.pid(), SocketSpec::tcp()) - .expect("create first connection socket"); - kernel - .socket_set_state( - "shell", - process.pid(), - first_connection, - SocketState::Connected, - ) - .expect("mark first connection"); - - let socket_error = kernel - .socket_create("shell", process.pid(), SocketSpec::tcp()) - .expect_err("third socket should exceed max_sockets"); - assert_eq!(socket_error.code(), "EAGAIN"); - - kernel - .socket_close("shell", process.pid(), listener) - .expect("close listener"); - let second_connection = kernel - .socket_create("shell", process.pid(), SocketSpec::tcp()) - .expect("create replacement socket"); - let connection_error = kernel - .socket_set_state( - "shell", - process.pid(), - second_connection, - SocketState::Connected, - ) - .expect_err("second connection should exceed max_connections"); - assert_eq!(connection_error.code(), "EAGAIN"); -} - -#[test] -fn socket_resource_snapshot_counts_stream_bytes_and_udp_queue_pressure() { - let mut kernel = new_kernel("vm-socket-buffer-snapshot"); - let sender = spawn_shell(&mut kernel); - let receiver = spawn_shell(&mut kernel); - - let stream_sender = kernel - .socket_create("shell", sender.pid(), SocketSpec::tcp()) - .expect("create stream sender"); - let stream_receiver = kernel - .socket_create("shell", receiver.pid(), SocketSpec::tcp()) - .expect("create stream receiver"); - kernel - .socket_connect_pair("shell", sender.pid(), stream_sender, stream_receiver) - .expect("connect stream pair"); - kernel - .socket_write("shell", sender.pid(), stream_sender, b"hello") - .expect("write stream payload"); - - let datagram_sender = kernel - .socket_create("shell", sender.pid(), SocketSpec::udp()) - .expect("create datagram sender"); - kernel - .socket_bind_inet( - "shell", - sender.pid(), - datagram_sender, - InetSocketAddress::new("127.0.0.1", 54071), - ) - .expect("bind datagram sender"); - let datagram_receiver = kernel - .socket_create("shell", receiver.pid(), SocketSpec::udp()) - .expect("create datagram receiver"); - kernel - .socket_bind_inet( - "shell", - receiver.pid(), - datagram_receiver, - InetSocketAddress::new("127.0.0.1", 43171), - ) - .expect("bind datagram receiver"); - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - datagram_sender, - InetSocketAddress::new("127.0.0.1", 43171), - b"abc", - ) - .expect("send first datagram"); - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - datagram_sender, - InetSocketAddress::new("127.0.0.1", 43171), - b"defg", - ) - .expect("send second datagram"); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_buffered_bytes, 12); - assert_eq!(snapshot.socket_datagram_queue_len, 2); - - let _ = kernel - .socket_read("shell", receiver.pid(), stream_receiver, 5) - .expect("read stream payload"); - let _ = kernel - .socket_recv_datagram("shell", receiver.pid(), datagram_receiver, 16) - .expect("receive datagram"); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_buffered_bytes, 4); - assert_eq!(snapshot.socket_datagram_queue_len, 1); -} - -#[test] -fn socket_resource_limits_reject_buffer_and_datagram_queue_growth() { - let mut config = KernelVmConfig::new("vm-socket-buffer-limits"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_socket_buffered_bytes: Some(5), - max_socket_datagram_queue_len: Some(1), - ..ResourceLimits::default() - }; - - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - let sender = spawn_shell(&mut kernel); - let receiver = spawn_shell(&mut kernel); - - let stream_sender = kernel - .socket_create("shell", sender.pid(), SocketSpec::tcp()) - .expect("create stream sender"); - let stream_receiver = kernel - .socket_create("shell", receiver.pid(), SocketSpec::tcp()) - .expect("create stream receiver"); - kernel - .socket_connect_pair("shell", sender.pid(), stream_sender, stream_receiver) - .expect("connect stream pair"); - - kernel - .socket_write("shell", sender.pid(), stream_sender, b"12345") - .expect("write up to stream buffer limit"); - let stream_error = kernel - .socket_write("shell", sender.pid(), stream_sender, b"6") - .expect_err("extra stream byte should exceed socket buffer limit"); - assert_eq!(stream_error.code(), "EAGAIN"); - assert_eq!( - kernel - .socket_get(stream_receiver) - .expect("stream receiver") - .buffered_read_bytes(), - 5 - ); - let _ = kernel - .socket_read("shell", receiver.pid(), stream_receiver, 5) - .expect("drain stream buffer"); - kernel - .socket_write("shell", sender.pid(), stream_sender, b"6") - .expect("write should succeed after draining stream buffer"); - let _ = kernel - .socket_read("shell", receiver.pid(), stream_receiver, 1) - .expect("drain second stream write"); - - let datagram_sender = kernel - .socket_create("shell", sender.pid(), SocketSpec::udp()) - .expect("create datagram sender"); - kernel - .socket_bind_inet( - "shell", - sender.pid(), - datagram_sender, - InetSocketAddress::new("127.0.0.1", 54072), - ) - .expect("bind datagram sender"); - let datagram_receiver = kernel - .socket_create("shell", receiver.pid(), SocketSpec::udp()) - .expect("create datagram receiver"); - kernel - .socket_bind_inet( - "shell", - receiver.pid(), - datagram_receiver, - InetSocketAddress::new("127.0.0.1", 43172), - ) - .expect("bind datagram receiver"); - - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - datagram_sender, - InetSocketAddress::new("127.0.0.1", 43172), - b"abc", - ) - .expect("send first datagram"); - let queue_error = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - datagram_sender, - InetSocketAddress::new("127.0.0.1", 43172), - b"d", - ) - .expect_err("second datagram should exceed queue length limit"); - assert_eq!(queue_error.code(), "EAGAIN"); - assert_eq!( - kernel - .socket_get(datagram_receiver) - .expect("datagram receiver") - .queued_datagrams(), - 1 - ); - let _ = kernel - .socket_recv_datagram("shell", receiver.pid(), datagram_receiver, 16) - .expect("drain datagram queue"); - - let byte_error = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - datagram_sender, - InetSocketAddress::new("127.0.0.1", 43172), - b"123456", - ) - .expect_err("oversized datagram should exceed socket buffer byte limit"); - assert_eq!(byte_error.code(), "EAGAIN"); - assert_eq!( - kernel - .socket_get(datagram_receiver) - .expect("datagram receiver after oversized send") - .queued_datagrams(), - 0 - ); -} diff --git a/crates/kernel/tests/stdio_devices.rs b/crates/kernel/tests/stdio_devices.rs deleted file mode 100644 index 6871448ac..000000000 --- a/crates/kernel/tests/stdio_devices.rs +++ /dev/null @@ -1,53 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::vfs::MemoryFileSystem; - -#[test] -fn default_process_stdout_and_stderr_accept_writes_without_pipe_rewiring() { - let mut config = KernelVmConfig::new("vm-stdio-devices"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - - let process = kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell"); - - assert_eq!( - kernel - .write_process_stdout("shell", process.pid(), b"stdout-data") - .expect("write stdout"), - "stdout-data".len() - ); - assert_eq!( - kernel - .write_process_stderr("shell", process.pid(), b"stderr-data") - .expect("write stderr"), - "stderr-data".len() - ); - - assert_eq!( - kernel - .read_file("/dev/stdout") - .expect_err("stdout should not persist") - .code(), - "ENOENT" - ); - assert_eq!( - kernel - .read_file("/dev/stderr") - .expect_err("stderr should not persist") - .code(), - "ENOENT" - ); -} diff --git a/crates/kernel/tests/tcp_data_plane.rs b/crates/kernel/tests/tcp_data_plane.rs deleted file mode 100644 index 728acd182..000000000 --- a/crates/kernel/tests/tcp_data_plane.rs +++ /dev/null @@ -1,246 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelProcessHandle, KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::socket_table::{ - InetSocketAddress, SocketShutdown, SocketSpec, SocketState, -}; -use secure_exec_kernel::vfs::MemoryFileSystem; - -fn spawn_shell(kernel: &mut KernelVm) -> KernelProcessHandle { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") -} - -fn new_kernel(vm_id: &str) -> KernelVm { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel -} - -#[test] -fn tcp_connected_sockets_transfer_data_bidirectionally() { - let mut kernel = new_kernel("vm-tcp-data-plane"); - let client = spawn_shell(&mut kernel); - let server = spawn_shell(&mut kernel); - - let client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::tcp()) - .expect("create client socket"); - kernel - .socket_bind_inet( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("127.0.0.1", 54011), - ) - .expect("bind client socket"); - - let server_socket = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create server socket"); - kernel - .socket_bind_inet( - "shell", - server.pid(), - server_socket, - InetSocketAddress::new("127.0.0.1", 43121), - ) - .expect("bind server socket"); - - kernel - .socket_connect_pair("shell", client.pid(), client_socket, server_socket) - .expect("connect pair"); - - let client_record = kernel.socket_get(client_socket).expect("client record"); - assert_eq!(client_record.state(), SocketState::Connected); - assert_eq!(client_record.peer_socket_id(), Some(server_socket)); - assert_eq!( - client_record.peer_address(), - Some(&InetSocketAddress::new("127.0.0.1", 43121)) - ); - - let server_record = kernel.socket_get(server_socket).expect("server record"); - assert_eq!(server_record.state(), SocketState::Connected); - assert_eq!(server_record.peer_socket_id(), Some(client_socket)); - assert_eq!( - server_record.peer_address(), - Some(&InetSocketAddress::new("127.0.0.1", 54011)) - ); - - let written = kernel - .socket_write("shell", client.pid(), client_socket, b"hello server") - .expect("write client payload"); - assert_eq!(written, b"hello server".len()); - assert_eq!( - kernel - .socket_get(server_socket) - .expect("server socket after write") - .buffered_read_bytes(), - b"hello server".len() - ); - - let first_read = kernel - .socket_read("shell", server.pid(), server_socket, 5) - .expect("read first chunk") - .expect("first chunk should be available"); - assert_eq!(first_read, b"hello"); - - let second_read = kernel - .socket_read("shell", server.pid(), server_socket, 64) - .expect("read remaining bytes") - .expect("remaining bytes should be available"); - assert_eq!(second_read, b" server"); - - kernel - .socket_write("shell", server.pid(), server_socket, b"ack") - .expect("write server reply"); - let reply = kernel - .socket_read("shell", client.pid(), client_socket, 16) - .expect("read server reply") - .expect("reply should be available"); - assert_eq!(reply, b"ack"); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_connections, 2); -} - -#[test] -fn tcp_shutdown_and_close_propagate_eof_and_broken_pipe() { - let mut kernel = new_kernel("vm-tcp-shutdown-close"); - let client = spawn_shell(&mut kernel); - let server = spawn_shell(&mut kernel); - - let client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::tcp()) - .expect("create client socket"); - let server_socket = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create server socket"); - kernel - .socket_connect_pair("shell", client.pid(), client_socket, server_socket) - .expect("connect pair"); - - kernel - .socket_shutdown("shell", server.pid(), server_socket, SocketShutdown::Write) - .expect("shutdown server write side"); - assert_eq!( - kernel - .socket_read("shell", client.pid(), client_socket, 32) - .expect("read after peer write shutdown"), - None - ); - assert!(kernel - .socket_get(client_socket) - .expect("client after peer write shutdown") - .peer_write_shutdown()); - - kernel - .socket_write("shell", client.pid(), client_socket, b"still-open") - .expect("client write after peer write shutdown"); - let payload = kernel - .socket_read("shell", server.pid(), server_socket, 64) - .expect("server read after peer write shutdown") - .expect("server should still read"); - assert_eq!(payload, b"still-open"); - - kernel - .socket_shutdown("shell", server.pid(), server_socket, SocketShutdown::Read) - .expect("shutdown server read side"); - let write_error = kernel - .socket_write("shell", client.pid(), client_socket, b"no-reader") - .expect_err("peer read shutdown should reject writes"); - assert_eq!(write_error.code(), "EPIPE"); - - kernel - .socket_close("shell", client.pid(), client_socket) - .expect("close client socket"); - assert_eq!( - kernel - .socket_read("shell", server.pid(), server_socket, 32) - .expect("read after peer close"), - None - ); - let closed_write_error = kernel - .socket_write("shell", server.pid(), server_socket, b"peer-gone") - .expect_err("peer close should reject writes"); - assert_eq!(closed_write_error.code(), "EPIPE"); - - kernel - .socket_close("shell", server.pid(), server_socket) - .expect("close server socket"); - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.sockets, 0); - assert_eq!(snapshot.socket_connections, 0); -} - -#[test] -fn tcp_writes_respect_socket_buffer_backpressure() { - let mut config = KernelVmConfig::new("vm-tcp-buffer-backpressure"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_socket_buffered_bytes: Some(5), - ..ResourceLimits::default() - }; - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - let client = spawn_shell(&mut kernel); - let server = spawn_shell(&mut kernel); - - let client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::tcp()) - .expect("create client socket"); - let server_socket = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create server socket"); - kernel - .socket_connect_pair("shell", client.pid(), client_socket, server_socket) - .expect("connect pair"); - - let written = kernel - .socket_write("shell", client.pid(), client_socket, b"12345") - .expect("fill server receive buffer"); - assert_eq!(written, 5); - let error = kernel - .socket_write("shell", client.pid(), client_socket, b"6") - .expect_err("extra byte should exceed socket buffer limit"); - assert_eq!(error.code(), "EAGAIN"); - assert_eq!( - kernel - .socket_get(server_socket) - .expect("server socket") - .buffered_read_bytes(), - 5 - ); - - let drained = kernel - .socket_read("shell", server.pid(), server_socket, 5) - .expect("read server payload") - .expect("payload should be available"); - assert_eq!(drained, b"12345"); - let written = kernel - .socket_write("shell", client.pid(), client_socket, b"6") - .expect("write should succeed after draining buffer"); - assert_eq!(written, 1); - assert_eq!( - kernel - .socket_get(server_socket) - .expect("server socket after recovery") - .buffered_read_bytes(), - 1 - ); -} diff --git a/crates/kernel/tests/tcp_listener.rs b/crates/kernel/tests/tcp_listener.rs deleted file mode 100644 index 11499c00e..000000000 --- a/crates/kernel/tests/tcp_listener.rs +++ /dev/null @@ -1,218 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelProcessHandle, KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::socket_table::{InetSocketAddress, SocketSpec, SocketState}; -use secure_exec_kernel::vfs::MemoryFileSystem; - -fn spawn_shell(kernel: &mut KernelVm) -> KernelProcessHandle { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") -} - -fn new_kernel(vm_id: &str) -> KernelVm { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel -} - -#[test] -fn tcp_listener_bind_listen_and_accept_preserve_listener_state() { - let mut kernel = new_kernel("vm-tcp-listener-accept"); - let process = spawn_shell(&mut kernel); - let listener = kernel - .socket_create("shell", process.pid(), SocketSpec::tcp()) - .expect("create listener socket"); - - kernel - .socket_bind_inet( - "shell", - process.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 43111), - ) - .expect("bind listener"); - kernel - .socket_listen("shell", process.pid(), listener, 2) - .expect("listen"); - kernel - .socket_queue_incoming_tcp_connection( - "shell", - process.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 54001), - ) - .expect("queue first connection"); - kernel - .socket_queue_incoming_tcp_connection( - "shell", - process.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 54002), - ) - .expect("queue second connection"); - - let listener_record = kernel.socket_get(listener).expect("listener record"); - assert_eq!(listener_record.state(), SocketState::Listening); - assert_eq!(listener_record.listen_backlog(), Some(2)); - assert_eq!(listener_record.pending_accept_count(), 2); - assert_eq!( - listener_record.local_address(), - Some(&InetSocketAddress::new("127.0.0.1", 43111)) - ); - - let first_accepted = kernel - .socket_accept("shell", process.pid(), listener) - .expect("accept first connection"); - let first_record = kernel.socket_get(first_accepted).expect("first accepted"); - assert_eq!(first_record.state(), SocketState::Connected); - assert_eq!( - first_record.local_address(), - Some(&InetSocketAddress::new("127.0.0.1", 43111)) - ); - assert_eq!( - first_record.peer_address(), - Some(&InetSocketAddress::new("127.0.0.1", 54001)) - ); - - let listener_after_first_accept = kernel.socket_get(listener).expect("listener after accept"); - assert_eq!(listener_after_first_accept.state(), SocketState::Listening); - assert_eq!(listener_after_first_accept.pending_accept_count(), 1); - - let second_accepted = kernel - .socket_accept("shell", process.pid(), listener) - .expect("accept second connection"); - let second_record = kernel.socket_get(second_accepted).expect("second accepted"); - assert_eq!(second_record.state(), SocketState::Connected); - assert_eq!( - second_record.peer_address(), - Some(&InetSocketAddress::new("127.0.0.1", 54002)) - ); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_listeners, 1); - assert_eq!(snapshot.socket_connections, 2); - - let accept_error = kernel - .socket_accept("shell", process.pid(), listener) - .expect_err("empty listener should not accept"); - assert_eq!(accept_error.code(), "EAGAIN"); -} - -#[test] -fn tcp_listener_requires_bind_and_enforces_backlog_capacity() { - let mut kernel = new_kernel("vm-tcp-listener-backlog"); - let process = spawn_shell(&mut kernel); - let listener = kernel - .socket_create("shell", process.pid(), SocketSpec::tcp()) - .expect("create listener socket"); - - let listen_error = kernel - .socket_listen("shell", process.pid(), listener, 1) - .expect_err("listen should require bind"); - assert_eq!(listen_error.code(), "EINVAL"); - - kernel - .socket_bind_inet( - "shell", - process.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 43112), - ) - .expect("bind listener"); - kernel - .socket_listen("shell", process.pid(), listener, 1) - .expect("listen"); - kernel - .socket_queue_incoming_tcp_connection( - "shell", - process.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 55001), - ) - .expect("queue first connection"); - - let backlog_error = kernel - .socket_queue_incoming_tcp_connection( - "shell", - process.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 55002), - ) - .expect_err("second queued connection should exceed backlog"); - assert_eq!(backlog_error.code(), "EAGAIN"); -} - -#[test] -fn tcp_listener_close_removes_pending_accepted_socket() { - let mut kernel = new_kernel("vm-tcp-listener-close-pending"); - let server = spawn_shell(&mut kernel); - let client = spawn_shell(&mut kernel); - let listener = kernel - .socket_create("shell", server.pid(), SocketSpec::tcp()) - .expect("create listener socket"); - kernel - .socket_bind_inet( - "shell", - server.pid(), - listener, - InetSocketAddress::new("127.0.0.1", 43113), - ) - .expect("bind listener"); - kernel - .socket_listen("shell", server.pid(), listener, 1) - .expect("listen"); - - let client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::tcp()) - .expect("create client socket"); - kernel - .socket_connect_inet_loopback( - "shell", - client.pid(), - client_socket, - InetSocketAddress::new("127.0.0.1", 43113), - ) - .expect("connect client to listener"); - - assert_eq!( - kernel - .socket_get(listener) - .expect("listener with pending accept") - .pending_accept_count(), - 1 - ); - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.sockets, 3); - assert_eq!(snapshot.socket_listeners, 1); - assert_eq!(snapshot.socket_connections, 2); - - kernel - .socket_close("shell", server.pid(), listener) - .expect("close listener"); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.sockets, 1); - assert_eq!(snapshot.socket_listeners, 0); - assert_eq!(snapshot.socket_connections, 1); - let client_record = kernel - .socket_get(client_socket) - .expect("client socket should remain"); - assert_eq!(client_record.peer_socket_id(), None); - assert!(client_record.peer_write_shutdown()); - let error = kernel - .socket_accept("shell", server.pid(), listener) - .expect_err("closed listener should not accept"); - assert_eq!(error.code(), "ENOENT"); -} diff --git a/crates/kernel/tests/udp_datagram.rs b/crates/kernel/tests/udp_datagram.rs deleted file mode 100644 index 25725ce13..000000000 --- a/crates/kernel/tests/udp_datagram.rs +++ /dev/null @@ -1,438 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelProcessHandle, KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::socket_table::{ - DatagramSocketOption, InetSocketAddress, SocketMulticastMembership, SocketSpec, -}; -use secure_exec_kernel::vfs::MemoryFileSystem; - -fn spawn_shell(kernel: &mut KernelVm) -> KernelProcessHandle { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") -} - -fn new_kernel(vm_id: &str) -> KernelVm { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel -} - -#[test] -fn udp_datagrams_preserve_boundaries_and_truncate_per_receive() { - let mut kernel = new_kernel("vm-udp-boundaries"); - let sender = spawn_shell(&mut kernel); - let receiver = spawn_shell(&mut kernel); - - let sender_socket = kernel - .socket_create("shell", sender.pid(), SocketSpec::udp()) - .expect("create sender socket"); - kernel - .socket_bind_inet( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 54051), - ) - .expect("bind sender"); - - let receiver_socket = kernel - .socket_create("shell", receiver.pid(), SocketSpec::udp()) - .expect("create receiver socket"); - kernel - .socket_bind_inet( - "shell", - receiver.pid(), - receiver_socket, - InetSocketAddress::new("127.0.0.1", 43151), - ) - .expect("bind receiver"); - - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43151), - b"first-datagram", - ) - .expect("send first datagram"); - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("localhost", 43151), - b"second", - ) - .expect("send second datagram"); - - assert_eq!( - kernel - .socket_get(receiver_socket) - .expect("receiver after sends") - .queued_datagrams(), - 2 - ); - - let first = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 5) - .expect("receive first datagram") - .expect("first payload"); - assert_eq!( - first.source_address(), - Some(&InetSocketAddress::new("127.0.0.1", 54051)) - ); - assert_eq!(first.payload(), b"first"); - - assert_eq!( - kernel - .socket_get(receiver_socket) - .expect("receiver after first receive") - .queued_datagrams(), - 1 - ); - - let second = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 64) - .expect("receive second datagram") - .expect("second payload"); - assert_eq!(second.payload(), b"second"); - - let empty_error = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 64) - .expect_err("empty UDP queue should report would-block"); - assert_eq!(empty_error.code(), "EAGAIN"); -} - -#[test] -fn udp_loopback_send_reaches_wildcard_bound_receiver() { - let mut kernel = new_kernel("vm-udp-wildcard-delivery"); - let sender = spawn_shell(&mut kernel); - let receiver = spawn_shell(&mut kernel); - - let sender_socket = kernel - .socket_create("shell", sender.pid(), SocketSpec::udp()) - .expect("create sender socket"); - kernel - .socket_bind_inet( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 54053), - ) - .expect("bind sender"); - - let receiver_socket = kernel - .socket_create("shell", receiver.pid(), SocketSpec::udp()) - .expect("create receiver socket"); - kernel - .socket_bind_inet( - "shell", - receiver.pid(), - receiver_socket, - InetSocketAddress::new("0.0.0.0", 43153), - ) - .expect("bind receiver to wildcard"); - - let written = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43153), - b"wildcard", - ) - .expect("send to wildcard-bound receiver"); - assert_eq!(written, b"wildcard".len()); - - let datagram = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 64) - .expect("receive datagram") - .expect("queued datagram"); - assert_eq!( - datagram.source_address(), - Some(&InetSocketAddress::new("127.0.0.1", 54053)) - ); - assert_eq!(datagram.payload(), b"wildcard"); -} - -#[test] -fn udp_send_and_receive_require_bound_sockets_and_bound_targets() { - let mut kernel = new_kernel("vm-udp-errors"); - let sender = spawn_shell(&mut kernel); - let receiver = spawn_shell(&mut kernel); - - let sender_socket = kernel - .socket_create("shell", sender.pid(), SocketSpec::udp()) - .expect("create sender socket"); - let receiver_socket = kernel - .socket_create("shell", receiver.pid(), SocketSpec::udp()) - .expect("create receiver socket"); - - let unbound_send_error = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43152), - b"payload", - ) - .expect_err("unbound sender should fail"); - assert_eq!(unbound_send_error.code(), "EINVAL"); - - kernel - .socket_bind_inet( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 54052), - ) - .expect("bind sender"); - - let missing_target_error = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43152), - b"payload", - ) - .expect_err("missing receiver should fail"); - assert_eq!(missing_target_error.code(), "EPERM"); - - let unbound_recv_error = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 64) - .expect_err("unbound receiver should fail"); - assert_eq!(unbound_recv_error.code(), "EINVAL"); -} - -#[test] -fn udp_datagram_queue_limit_rejects_extra_datagrams_without_mutating_queue() { - let mut config = KernelVmConfig::new("vm-udp-queue-limit"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_socket_datagram_queue_len: Some(1), - ..ResourceLimits::default() - }; - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - let sender = spawn_shell(&mut kernel); - let receiver = spawn_shell(&mut kernel); - - let sender_socket = kernel - .socket_create("shell", sender.pid(), SocketSpec::udp()) - .expect("create sender socket"); - kernel - .socket_bind_inet( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 54054), - ) - .expect("bind sender"); - - let receiver_socket = kernel - .socket_create("shell", receiver.pid(), SocketSpec::udp()) - .expect("create receiver socket"); - kernel - .socket_bind_inet( - "shell", - receiver.pid(), - receiver_socket, - InetSocketAddress::new("127.0.0.1", 43154), - ) - .expect("bind receiver"); - - kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43154), - b"one", - ) - .expect("send first datagram"); - let queue_error = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43154), - b"two", - ) - .expect_err("second datagram should exceed queue length limit"); - assert_eq!(queue_error.code(), "EAGAIN"); - let receiver_record = kernel - .socket_get(receiver_socket) - .expect("receiver after rejected datagram"); - assert_eq!(receiver_record.queued_datagrams(), 1); - assert_eq!(receiver_record.queued_datagram_bytes(), 3); - - let datagram = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 16) - .expect("receive queued datagram") - .expect("datagram payload"); - assert_eq!(datagram.payload(), b"one"); - let receiver_record = kernel - .socket_get(receiver_socket) - .expect("receiver after drain"); - assert_eq!(receiver_record.queued_datagrams(), 0); - assert_eq!(receiver_record.queued_datagram_bytes(), 0); - - let written = kernel - .socket_send_to_inet_loopback( - "shell", - sender.pid(), - sender_socket, - InetSocketAddress::new("127.0.0.1", 43154), - b"two", - ) - .expect("send should succeed after draining datagram queue"); - assert_eq!(written, 3); - let receiver_record = kernel - .socket_get(receiver_socket) - .expect("receiver after resumed send"); - assert_eq!(receiver_record.queued_datagrams(), 1); - assert_eq!(receiver_record.queued_datagram_bytes(), 3); - let datagram = kernel - .socket_recv_datagram("shell", receiver.pid(), receiver_socket, 16) - .expect("receive resumed datagram") - .expect("resumed datagram payload"); - assert_eq!(datagram.payload(), b"two"); -} - -#[test] -fn udp_reuseport_allows_two_sockets_to_bind_the_same_port() { - let mut kernel = new_kernel("vm-udp-reuseport"); - let first = spawn_shell(&mut kernel); - let second = spawn_shell(&mut kernel); - - let first_socket = kernel - .socket_create("shell", first.pid(), SocketSpec::udp()) - .expect("create first UDP socket"); - kernel - .socket_set_datagram_option( - "shell", - first.pid(), - first_socket, - DatagramSocketOption::ReusePort, - true, - ) - .expect("enable REUSEPORT on first socket"); - - let second_socket = kernel - .socket_create("shell", second.pid(), SocketSpec::udp()) - .expect("create second UDP socket"); - kernel - .socket_set_datagram_option( - "shell", - second.pid(), - second_socket, - DatagramSocketOption::ReusePort, - true, - ) - .expect("enable REUSEPORT on second socket"); - - let shared_address = InetSocketAddress::new("127.0.0.1", 43153); - kernel - .socket_bind_inet("shell", first.pid(), first_socket, shared_address.clone()) - .expect("bind first socket"); - kernel - .socket_bind_inet("shell", second.pid(), second_socket, shared_address) - .expect("bind second socket to the same port"); - - assert!(kernel - .socket_get(first_socket) - .expect("first socket state") - .reuse_port()); - assert!(kernel - .socket_get(second_socket) - .expect("second socket state") - .reuse_port()); -} - -#[test] -fn udp_broadcast_option_is_tracked_in_kernel_socket_state() { - let mut kernel = new_kernel("vm-udp-broadcast"); - let process = spawn_shell(&mut kernel); - let socket_id = kernel - .socket_create("shell", process.pid(), SocketSpec::udp()) - .expect("create UDP socket"); - - kernel - .socket_bind_inet( - "shell", - process.pid(), - socket_id, - InetSocketAddress::new("0.0.0.0", 43154), - ) - .expect("bind UDP socket"); - kernel - .socket_set_datagram_option( - "shell", - process.pid(), - socket_id, - DatagramSocketOption::Broadcast, - true, - ) - .expect("enable broadcast"); - - assert!(kernel - .socket_get(socket_id) - .expect("socket state after broadcast enable") - .broadcast_enabled()); -} - -#[test] -fn udp_multicast_memberships_are_added_and_removed_from_socket_state() { - let mut kernel = new_kernel("vm-udp-multicast-membership"); - let process = spawn_shell(&mut kernel); - let socket_id = kernel - .socket_create("shell", process.pid(), SocketSpec::udp()) - .expect("create UDP socket"); - - kernel - .socket_bind_inet( - "shell", - process.pid(), - socket_id, - InetSocketAddress::new("0.0.0.0", 43155), - ) - .expect("bind UDP socket"); - - let membership = SocketMulticastMembership::new("239.1.2.3", None); - kernel - .socket_add_membership("shell", process.pid(), socket_id, membership.clone()) - .expect("join multicast group"); - - let joined = kernel - .socket_get(socket_id) - .expect("socket state after join"); - assert_eq!(joined.multicast_membership_count(), 1); - assert!(joined.has_multicast_membership(&membership)); - - kernel - .socket_drop_membership("shell", process.pid(), socket_id, membership.clone()) - .expect("leave multicast group"); - - let left = kernel - .socket_get(socket_id) - .expect("socket state after leave"); - assert_eq!(left.multicast_membership_count(), 0); - assert!(!left.has_multicast_membership(&membership)); -} diff --git a/crates/kernel/tests/unix_domain_socket.rs b/crates/kernel/tests/unix_domain_socket.rs deleted file mode 100644 index 11f5c99a2..000000000 --- a/crates/kernel/tests/unix_domain_socket.rs +++ /dev/null @@ -1,195 +0,0 @@ -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelProcessHandle, KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::socket_table::{SocketShutdown, SocketSpec, SocketState}; -use secure_exec_kernel::vfs::MemoryFileSystem; - -fn spawn_shell(kernel: &mut KernelVm) -> KernelProcessHandle { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") -} - -fn new_kernel(vm_id: &str) -> KernelVm { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell"); - kernel -} - -#[test] -fn unix_domain_sockets_bind_connect_accept_and_transfer_data() { - let mut kernel = new_kernel("vm-unix-domain-flow"); - let server = spawn_shell(&mut kernel); - let client = spawn_shell(&mut kernel); - - let listener = kernel - .socket_create("shell", server.pid(), SocketSpec::unix_stream()) - .expect("create unix listener"); - kernel - .socket_bind_unix("shell", server.pid(), listener, "/tmp/kernel/server.sock") - .expect("bind unix listener"); - kernel - .socket_listen("shell", server.pid(), listener, 1) - .expect("listen on unix listener"); - - let client_socket = kernel - .socket_create("shell", client.pid(), SocketSpec::unix_stream()) - .expect("create unix client"); - kernel - .socket_bind_unix( - "shell", - client.pid(), - client_socket, - "/tmp/kernel/client.sock", - ) - .expect("bind unix client"); - kernel - .socket_connect_unix( - "shell", - client.pid(), - client_socket, - "/tmp/kernel/server.sock", - ) - .expect("connect unix client"); - - let listener_record = kernel.socket_get(listener).expect("listener record"); - assert_eq!(listener_record.state(), SocketState::Listening); - assert_eq!( - listener_record.local_unix_path(), - Some("/tmp/kernel/server.sock") - ); - assert_eq!(listener_record.pending_accept_count(), 1); - - let client_record = kernel.socket_get(client_socket).expect("client record"); - assert_eq!(client_record.state(), SocketState::Connected); - assert_eq!( - client_record.local_unix_path(), - Some("/tmp/kernel/client.sock") - ); - assert_eq!( - client_record.peer_unix_path(), - Some("/tmp/kernel/server.sock") - ); - - let accepted = kernel - .socket_accept("shell", server.pid(), listener) - .expect("accept unix client"); - let accepted_record = kernel.socket_get(accepted).expect("accepted record"); - assert_eq!(accepted_record.state(), SocketState::Connected); - assert_eq!( - accepted_record.local_unix_path(), - Some("/tmp/kernel/server.sock") - ); - assert_eq!( - accepted_record.peer_unix_path(), - Some("/tmp/kernel/client.sock") - ); - assert_eq!(accepted_record.peer_socket_id(), Some(client_socket)); - - kernel - .socket_write("shell", client.pid(), client_socket, b"ping-unix") - .expect("write unix payload"); - let payload = kernel - .socket_read("shell", server.pid(), accepted, 64) - .expect("read unix payload") - .expect("unix payload"); - assert_eq!(payload, b"ping-unix"); - - kernel - .socket_shutdown("shell", server.pid(), accepted, SocketShutdown::Write) - .expect("shutdown accepted write side"); - assert_eq!( - kernel - .socket_read("shell", client.pid(), client_socket, 16) - .expect("read unix eof"), - None - ); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.socket_listeners, 1); - assert_eq!(snapshot.socket_connections, 2); -} - -#[test] -fn unix_domain_sockets_require_bound_listener_paths_and_backlog_capacity() { - let mut kernel = new_kernel("vm-unix-domain-errors"); - let server = spawn_shell(&mut kernel); - let client = spawn_shell(&mut kernel); - - let listener = kernel - .socket_create("shell", server.pid(), SocketSpec::unix_stream()) - .expect("create unix listener"); - let listen_error = kernel - .socket_listen("shell", server.pid(), listener, 1) - .expect_err("unix listen should require bind"); - assert_eq!(listen_error.code(), "EINVAL"); - - let missing_target = kernel - .socket_create("shell", client.pid(), SocketSpec::unix_stream()) - .expect("create missing-target client"); - let connect_error = kernel - .socket_connect_unix( - "shell", - client.pid(), - missing_target, - "/tmp/kernel/missing.sock", - ) - .expect_err("missing unix listener should fail"); - assert_eq!(connect_error.code(), "ECONNREFUSED"); - - kernel - .socket_bind_unix("shell", server.pid(), listener, "/tmp/kernel/listener.sock") - .expect("bind unix listener"); - kernel - .socket_listen("shell", server.pid(), listener, 1) - .expect("listen on bound unix listener"); - - let duplicate_listener = kernel - .socket_create("shell", server.pid(), SocketSpec::unix_stream()) - .expect("create duplicate listener"); - let duplicate_bind_error = kernel - .socket_bind_unix( - "shell", - server.pid(), - duplicate_listener, - "/tmp/kernel/listener.sock", - ) - .expect_err("duplicate unix path should fail"); - assert_eq!(duplicate_bind_error.code(), "EADDRINUSE"); - - let first_client = kernel - .socket_create("shell", client.pid(), SocketSpec::unix_stream()) - .expect("create first client"); - kernel - .socket_connect_unix( - "shell", - client.pid(), - first_client, - "/tmp/kernel/listener.sock", - ) - .expect("connect first client"); - - let second_client = kernel - .socket_create("shell", client.pid(), SocketSpec::unix_stream()) - .expect("create second client"); - let backlog_error = kernel - .socket_connect_unix( - "shell", - client.pid(), - second_client, - "/tmp/kernel/listener.sock", - ) - .expect_err("second connect should exceed backlog"); - assert_eq!(backlog_error.code(), "EAGAIN"); -} diff --git a/crates/kernel/tests/user.rs b/crates/kernel/tests/user.rs deleted file mode 100644 index f9fdf0faf..000000000 --- a/crates/kernel/tests/user.rs +++ /dev/null @@ -1,167 +0,0 @@ -use secure_exec_kernel::user::{UserConfig, UserManager}; - -#[test] -fn uses_sensible_defaults_when_not_configured() { - let user = UserManager::new(); - - assert_eq!(user.uid, 1000); - assert_eq!(user.gid, 1000); - assert_eq!(user.euid, 1000); - assert_eq!(user.egid, 1000); - assert_eq!(user.username, "agentos"); - assert_eq!(user.homedir, "/home/agentos"); - assert_eq!(user.shell, "/bin/sh"); - assert_eq!(user.gecos, ""); -} - -#[test] -fn empty_config_uses_the_same_defaults() { - let user = UserManager::from_config(UserConfig::default()); - - assert_eq!(user.uid, 1000); - assert_eq!(user.gid, 1000); - assert_eq!(user.username, "agentos"); -} - -#[test] -fn effective_ids_default_to_real_ids() { - let with_uid = UserManager::from_config(UserConfig { - uid: Some(500), - ..UserConfig::default() - }); - let with_gid = UserManager::from_config(UserConfig { - gid: Some(500), - ..UserConfig::default() - }); - - assert_eq!(with_uid.euid, 500); - assert_eq!(with_gid.egid, 500); -} - -#[test] -fn accepts_custom_configuration() { - let user = UserManager::from_config(UserConfig { - uid: Some(501), - gid: Some(502), - euid: Some(0), - egid: Some(0), - username: Some(String::from("admin")), - homedir: Some(String::from("/home/admin")), - shell: Some(String::from("/bin/bash")), - gecos: Some(String::from("Admin User")), - ..UserConfig::default() - }); - - assert_eq!(user.uid, 501); - assert_eq!(user.gid, 502); - assert_eq!(user.euid, 0); - assert_eq!(user.egid, 0); - assert_eq!(user.username, "admin"); - assert_eq!(user.homedir, "/home/admin"); - assert_eq!(user.shell, "/bin/bash"); - assert_eq!(user.gecos, "Admin User"); -} - -#[test] -fn supports_root_configuration() { - let user = UserManager::from_config(UserConfig { - uid: Some(0), - gid: Some(0), - username: Some(String::from("root")), - homedir: Some(String::from("/root")), - ..UserConfig::default() - }); - - assert_eq!(user.uid, 0); - assert_eq!(user.gid, 0); - assert_eq!(user.euid, 0); - assert_eq!(user.egid, 0); - assert_eq!(user.username, "root"); - assert_eq!(user.homedir, "/root"); -} - -#[test] -fn getpwuid_returns_configured_entry_for_the_active_user() { - let user = UserManager::new(); - - assert_eq!( - user.getpwuid(1000), - Some(String::from("agentos:x:1000:1000::/home/agentos:/bin/sh")) - ); - - let with_gecos = UserManager::from_config(UserConfig { - gecos: Some(String::from("Test User")), - ..UserConfig::default() - }); - assert_eq!( - with_gecos.getpwuid(1000), - Some(String::from( - "agentos:x:1000:1000:Test User:/home/agentos:/bin/sh" - )) - ); -} - -#[test] -fn getpwuid_returns_custom_entry_and_rejects_unknown_uids() { - let deploy = UserManager::from_config(UserConfig { - uid: Some(501), - gid: Some(502), - username: Some(String::from("deploy")), - homedir: Some(String::from("/opt/deploy")), - shell: Some(String::from("/bin/bash")), - gecos: Some(String::from("Deploy User")), - ..UserConfig::default() - }); - - assert_eq!( - deploy.getpwuid(501), - Some(String::from( - "deploy:x:501:502:Deploy User:/opt/deploy:/bin/bash" - )) - ); - assert_eq!(deploy.getpwuid(9999), None); -} - -#[test] -fn getpwuid_handles_root_uid_for_root_and_non_root_configs() { - let user = UserManager::new(); - assert_eq!(user.getpwuid(0), None); - - let root = UserManager::from_config(UserConfig { - uid: Some(0), - gid: Some(0), - username: Some(String::from("root")), - homedir: Some(String::from("/root")), - ..UserConfig::default() - }); - assert_eq!( - root.getpwuid(0), - Some(String::from("root:x:0:0::/root:/bin/sh")) - ); -} - -#[test] -fn getgroups_and_getgrgid_use_kernel_managed_group_state() { - let user = UserManager::from_config(UserConfig { - gid: Some(123), - username: Some(String::from("deploy")), - group_name: Some(String::from("deployers")), - supplementary_gids: vec![456, 123, 456, 789], - ..UserConfig::default() - }); - - assert_eq!(user.getgroups(), vec![123, 456, 789]); - assert_eq!( - user.getgrgid(123), - Some(String::from("deployers:x:123:deploy")) - ); - assert_eq!( - user.getgrgid(456), - Some(String::from("group456:x:456:deploy")) - ); - assert_eq!( - user.getgrgid(789), - Some(String::from("group789:x:789:deploy")) - ); - assert_eq!(user.getgrgid(999), None); -} diff --git a/crates/kernel/tests/virtual_process.rs b/crates/kernel/tests/virtual_process.rs deleted file mode 100644 index 749e8a567..000000000 --- a/crates/kernel/tests/virtual_process.rs +++ /dev/null @@ -1,240 +0,0 @@ -use secure_exec_kernel::kernel::{ - KernelVm, KernelVmConfig, VirtualProcessOptions, WaitPidEvent, WaitPidFlags, -}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::socket_table::{InetSocketAddress, SocketSpec}; -use secure_exec_kernel::vfs::MemoryFileSystem; -use std::time::Duration; - -fn assert_kernel_error_code( - result: secure_exec_kernel::kernel::KernelResult, - expected: &str, -) { - let error = result.expect_err("operation should fail"); - assert_eq!(error.code(), expected); -} - -fn new_kernel(vm_id: &str) -> KernelVm { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - KernelVm::new(MemoryFileSystem::new(), config) -} - -#[test] -fn virtual_processes_appear_in_process_listings_and_wait_like_children() { - let mut kernel = new_kernel("vm-virtual-process-tree"); - - let parent = kernel - .create_virtual_process( - "tool-dispatch", - "tool", - "agentos-toolkit", - vec![String::from("parent")], - VirtualProcessOptions::default(), - ) - .expect("create virtual parent"); - let child = kernel - .create_virtual_process( - "tool-dispatch", - "tool", - "agentos-toolkit", - vec![String::from("child")], - VirtualProcessOptions { - parent_pid: Some(parent.pid()), - ..VirtualProcessOptions::default() - }, - ) - .expect("create virtual child"); - - let processes = kernel.list_processes(); - assert_eq!(processes.get(&parent.pid()).expect("parent info").ppid, 0); - let child_info = processes.get(&child.pid()).expect("child info"); - assert_eq!(child_info.ppid, parent.pid()); - assert_eq!(child_info.driver, "tool"); - assert_eq!(child_info.command, "agentos-toolkit"); - - kernel - .exit_process("tool-dispatch", child.pid(), 23) - .expect("exit virtual child"); - let waited = kernel - .waitpid_with_options( - "tool-dispatch", - parent.pid(), - child.pid() as i32, - WaitPidFlags::empty(), - ) - .expect("wait child event") - .expect("child exit event"); - assert_eq!(waited.pid, child.pid()); - assert_eq!(waited.status, 23); - assert_eq!(waited.event, WaitPidEvent::Exited); - assert!( - !kernel.list_processes().contains_key(&child.pid()), - "waited child should be reaped" - ); - - kernel - .exit_process("tool-dispatch", parent.pid(), 0) - .expect("exit virtual parent"); - assert_eq!( - kernel.waitpid(parent.pid()).expect("wait parent"), - secure_exec_kernel::kernel::WaitPidResult { - pid: parent.pid(), - status: 0, - } - ); -} - -#[test] -fn virtual_process_stdio_uses_standard_fd_helpers_and_owner_checks() { - let mut kernel = new_kernel("vm-virtual-process-stdio"); - let process = kernel - .create_virtual_process( - "tool-dispatch", - "tool", - "agentos-toolkit", - vec![String::from("echo")], - VirtualProcessOptions::default(), - ) - .expect("create virtual process"); - - let (stdin_read_fd, stdin_write_fd) = kernel - .open_pipe("tool-dispatch", process.pid()) - .expect("open stdin pipe"); - kernel - .fd_dup2("tool-dispatch", process.pid(), stdin_read_fd, 0) - .expect("wire stdin pipe"); - kernel - .fd_write("tool-dispatch", process.pid(), stdin_write_fd, b"input") - .expect("write stdin payload"); - assert_eq!( - kernel - .read_process_stdin( - "tool-dispatch", - process.pid(), - 32, - Some(Duration::from_millis(5)) - ) - .expect("read virtual stdin") - .expect("stdin bytes"), - b"input".to_vec() - ); - - let (stdout_read_fd, stdout_write_fd) = kernel - .open_pipe("tool-dispatch", process.pid()) - .expect("open stdout pipe"); - kernel - .fd_dup2("tool-dispatch", process.pid(), stdout_write_fd, 1) - .expect("wire stdout pipe"); - kernel - .write_process_stdout("tool-dispatch", process.pid(), b"stdout-data") - .expect("write virtual stdout"); - assert_eq!( - kernel - .fd_read("tool-dispatch", process.pid(), stdout_read_fd, 64) - .expect("read stdout pipe"), - b"stdout-data".to_vec() - ); - - let (stderr_read_fd, stderr_write_fd) = kernel - .open_pipe("tool-dispatch", process.pid()) - .expect("open stderr pipe"); - kernel - .fd_dup2("tool-dispatch", process.pid(), stderr_write_fd, 2) - .expect("wire stderr pipe"); - kernel - .write_process_stderr("tool-dispatch", process.pid(), b"stderr-data") - .expect("write virtual stderr"); - assert_eq!( - kernel - .fd_read("tool-dispatch", process.pid(), stderr_read_fd, 64) - .expect("read stderr pipe"), - b"stderr-data".to_vec() - ); - - assert_kernel_error_code( - kernel.write_process_stdout("other-driver", process.pid(), b"denied"), - "EPERM", - ); - - kernel - .exit_process("tool-dispatch", process.pid(), 9) - .expect("exit virtual process"); - assert_eq!( - kernel.waitpid(process.pid()).expect("wait virtual process"), - secure_exec_kernel::kernel::WaitPidResult { - pid: process.pid(), - status: 9, - } - ); -} - -#[test] -fn virtual_process_exit_reclaims_owned_sockets() { - let mut kernel = new_kernel("vm-virtual-process-socket-cleanup"); - let process = kernel - .create_virtual_process( - "tool-dispatch", - "tool", - "agentos-toolkit", - Vec::new(), - VirtualProcessOptions::default(), - ) - .expect("create virtual process"); - let socket = kernel - .socket_create("tool-dispatch", process.pid(), SocketSpec::tcp()) - .expect("create virtual-process socket"); - kernel - .socket_bind_inet( - "tool-dispatch", - process.pid(), - socket, - InetSocketAddress::new("127.0.0.1", 43107), - ) - .expect("bind virtual-process socket"); - kernel - .socket_listen("tool-dispatch", process.pid(), socket, 1) - .expect("listen on virtual-process socket"); - - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.sockets, 1); - assert_eq!(snapshot.socket_listeners, 1); - - kernel - .exit_process("tool-dispatch", process.pid(), 0) - .expect("exit virtual process"); - - assert!(kernel.socket_get(socket).is_none()); - let snapshot = kernel.resource_snapshot(); - assert_eq!(snapshot.sockets, 0); - assert_eq!(snapshot.socket_listeners, 0); - - let replacement = kernel - .create_virtual_process( - "tool-dispatch", - "tool", - "agentos-toolkit", - Vec::new(), - VirtualProcessOptions::default(), - ) - .expect("create replacement virtual process"); - let replacement_socket = kernel - .socket_create("tool-dispatch", replacement.pid(), SocketSpec::tcp()) - .expect("create replacement socket"); - kernel - .socket_bind_inet( - "tool-dispatch", - replacement.pid(), - replacement_socket, - InetSocketAddress::new("127.0.0.1", 43107), - ) - .expect("rebind address after virtual process exit cleanup"); - - assert_eq!( - kernel.waitpid(process.pid()).expect("wait virtual process"), - secure_exec_kernel::kernel::WaitPidResult { - pid: process.pid(), - status: 0, - } - ); -} diff --git a/crates/native-baseline/Cargo.toml b/crates/native-baseline/Cargo.toml deleted file mode 100644 index a28bd4e5b..000000000 --- a/crates/native-baseline/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "native-baseline" -version.workspace = true -edition.workspace = true -license.workspace = true -publish = false - -# Native floor for the differential perf harness. std-only on purpose: this is the -# glibc fork/posix_spawn + execve baseline that the agent-os "emulation tax" divides -# against. No secure-exec deps — it must measure the host, not the emulator. - -[[bin]] -name = "native-baseline" -path = "src/main.rs" - -[dependencies] diff --git a/crates/native-baseline/README.md b/crates/native-baseline/README.md deleted file mode 100644 index e06b6d67f..000000000 --- a/crates/native-baseline/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# native-baseline - -Native floor binary for the differential benchmark matrix. - -Build the host lane: - -```sh -cargo build --release -p native-baseline -``` - -Build the WASI lane used by the VM WASM executor: - -```sh -cargo build --release --target wasm32-wasip1 -p native-baseline -``` - -The wasm artifact is written to `target/wasm32-wasip1/release/native-baseline.wasm`. diff --git a/crates/native-baseline/src/main.rs b/crates/native-baseline/src/main.rs deleted file mode 100644 index a6af9a665..000000000 --- a/crates/native-baseline/src/main.rs +++ /dev/null @@ -1,1018 +0,0 @@ -//! Native floor for the differential perf harness. -//! -//! Runs one logical op many times, timing each with a monotonic clock, and emits -//! the raw per-iteration sample array (nanoseconds) as JSON to stdout. The TypeScript -//! harness reduces these samples with the SAME `stats()` it applies to the node and -//! guest layers, so the percentile math is identical across all three layers and the -//! "emulation tax" ratio is honest. -//! -//! Ops (held byte-identical to the node + guest layers): -//! spawn_exit -> /bin/sh -c 'exit 0' (fork/posix_spawn + execve + reap) -//! exec_capture -> /bin/sh -c 'printf hi' (same, plus stdout capture) -//! fs_stat -> stat a small host file -//! fs_write -> overwrite a small host file -//! fs_read -> read a 64 KiB host file -//! dns_lookup -> resolve localhost -//! tcp_connect -> localhost TCP connect+close -//! tcp_echo -> localhost TCP connect+echo -//! pipe_echo -> shell pipe echo through cat -//! cpu_loop -> bounded integer loop -//! alloc_free -> allocate/drop a 64 KiB Vec -//! -//! Usage: native-baseline --op spawn_exit|exec_capture --iters N --warmup W - -use std::fs::File; -use std::io::{Read, Write}; -#[cfg(not(target_family = "wasm"))] -use std::net::{TcpListener, TcpStream, ToSocketAddrs, UdpSocket}; -#[cfg(all(unix, not(target_family = "wasm")))] -use std::os::unix::net::{UnixListener, UnixStream}; -use std::path::Path; -#[cfg(not(target_family = "wasm"))] -use std::process::{Command, Stdio}; -#[cfg(not(target_family = "wasm"))] -use std::thread; -#[cfg(target_family = "wasm")] -use std::time::SystemTime; -use std::time::{Duration, Instant}; - -#[derive(Clone, Copy)] -enum Op { - SpawnExit, - ExecCapture, - NodeStdoutDiscard2b, - NodeStdoutCapture2b, - NodeStdoutListenerOnly2b, - NodeExit, - NodeFanout, - NodeReapStorm, - NodeStdinRoundtrip, - PipeChain, - FsStat, - FsStatX32, - FsWrite, - FsRead, - StreamCopy, - FsOpenClose, - FsMkdirRmdir, - FsRename, - FsReaddir, - FsFsync, - DnsLookup, - DnsLookupX2, - DnsConcurrent, - TcpConnect, - TcpEcho, - UnixConnect, - UnixEcho, - HttpLoopbackGet, - TcpConcurrent, - TcpThroughput, - TcpTinyWrites, - UdpEcho, - PipeEcho, - PipeThroughput, - PipeBackpressure, - StdioWriteSync, - CpuLoop, - SleepTimer, - YieldLoop, - AllocFree, -} - -struct BenchConfig { - size_bytes: Option, - entry_count: Option, - timer_count: Option, - sleep_ns: Option, - chunk_count: Option, -} - -const OP_NAMES: &[&str] = &[ - "spawn_exit", - "exec_capture", - "node_stdout_discard_2b", - "node_stdout_capture_2b", - "node_stdout_listener_only_2b", - "node_exit", - "node_fanout", - "node_reap_storm", - "node_stdin_roundtrip", - "pipe_chain", - "fs_stat", - "fs_stat_x32", - "fs_write", - "fs_read", - "stream_copy", - "fs_open_close", - "fs_mkdir_rmdir", - "fs_rename", - "fs_readdir", - "fs_fsync", - "dns_lookup", - "dns_lookup_x2", - "dns_concurrent", - "tcp_connect", - "tcp_echo", - "unix_connect", - "unix_echo", - "http_loopback_get", - "tcp_concurrent", - "tcp_throughput", - "tcp_tiny_writes", - "udp_echo", - "pipe_echo", - "pipe_throughput", - "pipe_backpressure", - "stdio_write_sync", - "cpu_loop", - "sleep_timer", - "yield_loop", - "alloc_free", -]; - -impl Op { - #[cfg(target_family = "wasm")] - fn supported_on_wasm(self) -> bool { - matches!( - self, - Op::FsStat - | Op::FsStatX32 - | Op::FsWrite - | Op::FsRead - | Op::StreamCopy - | Op::FsOpenClose - | Op::FsMkdirRmdir - | Op::FsRename - | Op::FsReaddir - | Op::FsFsync - | Op::CpuLoop - | Op::SleepTimer - | Op::YieldLoop - | Op::AllocFree - ) - } -} - -fn parse_op(name: &str) -> Option { - Some(match name { - "spawn_exit" => Op::SpawnExit, - "exec_capture" => Op::ExecCapture, - "node_stdout_discard_2b" => Op::NodeStdoutDiscard2b, - "node_stdout_capture_2b" => Op::NodeStdoutCapture2b, - "node_stdout_listener_only_2b" => Op::NodeStdoutListenerOnly2b, - "node_exit" => Op::NodeExit, - "node_fanout" => Op::NodeFanout, - "node_reap_storm" => Op::NodeReapStorm, - "node_stdin_roundtrip" => Op::NodeStdinRoundtrip, - "pipe_chain" => Op::PipeChain, - "fs_stat" => Op::FsStat, - "fs_stat_x32" => Op::FsStatX32, - "fs_write" => Op::FsWrite, - "fs_read" => Op::FsRead, - "stream_copy" => Op::StreamCopy, - "fs_open_close" => Op::FsOpenClose, - "fs_mkdir_rmdir" => Op::FsMkdirRmdir, - "fs_rename" => Op::FsRename, - "fs_readdir" => Op::FsReaddir, - "fs_fsync" => Op::FsFsync, - "dns_lookup" => Op::DnsLookup, - "dns_lookup_x2" => Op::DnsLookupX2, - "dns_concurrent" => Op::DnsConcurrent, - "tcp_connect" => Op::TcpConnect, - "tcp_echo" => Op::TcpEcho, - "unix_connect" => Op::UnixConnect, - "unix_echo" => Op::UnixEcho, - "http_loopback_get" => Op::HttpLoopbackGet, - "tcp_concurrent" => Op::TcpConcurrent, - "tcp_throughput" => Op::TcpThroughput, - "tcp_tiny_writes" => Op::TcpTinyWrites, - "udp_echo" => Op::UdpEcho, - "pipe_echo" => Op::PipeEcho, - "pipe_throughput" => Op::PipeThroughput, - "pipe_backpressure" => Op::PipeBackpressure, - "stdio_write_sync" => Op::StdioWriteSync, - "cpu_loop" => Op::CpuLoop, - "sleep_timer" => Op::SleepTimer, - "yield_loop" => Op::YieldLoop, - "alloc_free" => Op::AllocFree, - _ => return None, - }) -} - -fn op_name(op: Op) -> &'static str { - match op { - Op::SpawnExit => "spawn_exit", - Op::ExecCapture => "exec_capture", - Op::NodeStdoutDiscard2b => "node_stdout_discard_2b", - Op::NodeStdoutCapture2b => "node_stdout_capture_2b", - Op::NodeStdoutListenerOnly2b => "node_stdout_listener_only_2b", - Op::NodeExit => "node_exit", - Op::NodeFanout => "node_fanout", - Op::NodeReapStorm => "node_reap_storm", - Op::NodeStdinRoundtrip => "node_stdin_roundtrip", - Op::PipeChain => "pipe_chain", - Op::FsStat => "fs_stat", - Op::FsStatX32 => "fs_stat_x32", - Op::FsWrite => "fs_write", - Op::FsRead => "fs_read", - Op::StreamCopy => "stream_copy", - Op::FsOpenClose => "fs_open_close", - Op::FsMkdirRmdir => "fs_mkdir_rmdir", - Op::FsRename => "fs_rename", - Op::FsReaddir => "fs_readdir", - Op::FsFsync => "fs_fsync", - Op::DnsLookup => "dns_lookup", - Op::DnsLookupX2 => "dns_lookup_x2", - Op::DnsConcurrent => "dns_concurrent", - Op::TcpConnect => "tcp_connect", - Op::TcpEcho => "tcp_echo", - Op::UnixConnect => "unix_connect", - Op::UnixEcho => "unix_echo", - Op::HttpLoopbackGet => "http_loopback_get", - Op::TcpConcurrent => "tcp_concurrent", - Op::TcpThroughput => "tcp_throughput", - Op::TcpTinyWrites => "tcp_tiny_writes", - Op::UdpEcho => "udp_echo", - Op::PipeEcho => "pipe_echo", - Op::PipeThroughput => "pipe_throughput", - Op::PipeBackpressure => "pipe_backpressure", - Op::StdioWriteSync => "stdio_write_sync", - Op::CpuLoop => "cpu_loop", - Op::SleepTimer => "sleep_timer", - Op::YieldLoop => "yield_loop", - Op::AllocFree => "alloc_free", - } -} - -#[cfg(not(target_family = "wasm"))] -type Timer = Instant; - -#[cfg(not(target_family = "wasm"))] -fn timer_start() -> Timer { - Instant::now() -} - -#[cfg(not(target_family = "wasm"))] -fn elapsed_ns(timer: Timer) -> u128 { - timer.elapsed().as_nanos() -} - -#[cfg(target_family = "wasm")] -struct Timer { - instant: Option, - system: SystemTime, -} - -#[cfg(target_family = "wasm")] -fn timer_start() -> Timer { - Timer { - instant: std::panic::catch_unwind(Instant::now).ok(), - system: SystemTime::now(), - } -} - -#[cfg(target_family = "wasm")] -fn elapsed_ns(timer: Timer) -> u128 { - if let Some(instant) = timer.instant { - if let Ok(elapsed) = std::panic::catch_unwind(|| instant.elapsed()) { - return elapsed.as_nanos(); - } - } - timer.system.elapsed().map(|d| d.as_nanos()).unwrap_or(0) -} - -fn run_once(op: Op, iter: usize, base_dir: &Path, config: &BenchConfig) { - match op { - #[cfg(not(target_family = "wasm"))] - Op::SpawnExit => { - let status = Command::new("/bin/sh") - .args(["-c", "exit 0"]) - .status() - .expect("spawn /bin/sh failed"); - assert!(status.success(), "expected exit 0, got {status:?}"); - } - #[cfg(not(target_family = "wasm"))] - Op::ExecCapture => { - let out = Command::new("/bin/sh") - .args(["-c", "printf hi"]) - .output() - .expect("spawn /bin/sh failed"); - assert_eq!(out.stdout, b"hi", "unexpected stdout"); - } - #[cfg(not(target_family = "wasm"))] - Op::NodeStdoutDiscard2b => { - let size_bytes = config.size_bytes.unwrap_or(2); - let script = format!("process.stdout.write(Buffer.alloc({size_bytes}, 55))"); - let status = Command::new("node") - .arg("-e") - .arg(&script) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .expect("spawn node failed"); - assert!(status.success(), "expected exit 0, got {status:?}"); - } - #[cfg(not(target_family = "wasm"))] - Op::NodeStdoutCapture2b => { - let size_bytes = config.size_bytes.unwrap_or(2); - let script = format!("process.stdout.write(Buffer.alloc({size_bytes}, 55))"); - let out = Command::new("node") - .arg("-e") - .arg(&script) - .output() - .expect("spawn node failed"); - assert!( - out.status.success(), - "expected exit 0, got {:?}", - out.status - ); - assert_eq!(out.stdout.len(), size_bytes, "unexpected stdout byte count"); - } - #[cfg(not(target_family = "wasm"))] - Op::NodeStdoutListenerOnly2b => { - let size_bytes = config.size_bytes.unwrap_or(2); - let script = format!("process.stdout.write(Buffer.alloc({size_bytes}, 55))"); - let mut child = Command::new("node") - .arg("-e") - .arg(&script) - .stdout(Stdio::piped()) - .stderr(Stdio::null()) - .spawn() - .expect("spawn node failed"); - let mut stdout = child.stdout.take().expect("stdout pipe"); - let mut bytes = Vec::new(); - stdout.read_to_end(&mut bytes).expect("read stdout"); - let status = child.wait().expect("wait node child"); - assert!(status.success(), "expected exit 0, got {status:?}"); - assert_eq!(bytes.len(), size_bytes, "unexpected stdout byte count"); - } - // Real host node process that immediately exits. This is the apples-to-apples - // floor for the guest layer, where the same logical op spins a V8 isolate. - #[cfg(not(target_family = "wasm"))] - Op::NodeExit => { - let status = Command::new("node") - .args(["-e", "process.exit(0)"]) - .status() - .expect("spawn node failed"); - assert!(status.success(), "expected exit 0, got {status:?}"); - } - #[cfg(not(target_family = "wasm"))] - Op::NodeFanout | Op::NodeReapStorm => { - let mut children = Vec::new(); - for _ in 0..8 { - children.push( - Command::new("node") - .args(["-e", "process.exit(0)"]) - .spawn() - .expect("spawn node failed"), - ); - } - for mut child in children { - let status = child.wait().expect("wait node child"); - assert!(status.success(), "expected exit 0, got {status:?}"); - } - } - #[cfg(not(target_family = "wasm"))] - Op::NodeStdinRoundtrip => { - let size_bytes = config.size_bytes.unwrap_or(4096); - let payload = vec![9_u8; size_bytes]; - let mut child = Command::new("node") - .args([ - "-e", - "process.stdin.on('data', (chunk) => process.stdout.write(chunk)); process.stdin.on('end', () => process.exit(0));", - ]) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::null()) - .spawn() - .expect("spawn node failed"); - child - .stdin - .take() - .expect("child stdin") - .write_all(&payload) - .expect("write child stdin"); - let out = child.wait_with_output().expect("wait node child"); - assert!( - out.status.success(), - "expected exit 0, got {:?}", - out.status - ); - assert_eq!(out.stdout, payload, "stdin roundtrip mismatch"); - } - #[cfg(not(target_family = "wasm"))] - Op::PipeChain => { - let out = Command::new("/bin/sh") - .args(["-c", "printf hello | cat | cat >/dev/null"]) - .output() - .expect("run pipe chain"); - assert!(out.status.success(), "pipe chain failed: {out:?}"); - } - Op::FsStat => { - let path = base_dir.join("secure-exec-native-fs-stat.txt"); - std::fs::write(&path, b"hi").expect("write stat fixture"); - let meta = std::fs::metadata(&path).expect("stat fixture"); - assert!(meta.len() >= 2); - } - Op::FsStatX32 => { - let path = base_dir.join("secure-exec-native-fs-stat-x32.txt"); - if !path.exists() { - std::fs::write(&path, b"hi").expect("write stat fixture"); - } - // Every lane must measure the SAME work (32 stats): under wasm the - // post-quota-fix batch runs faster than the guest clock granularity, - // so samples may read 0-1ms quantized — that is the truthful value; - // never batch one lane harder than the others. - let batches = config.chunk_count.unwrap_or(1); - for _ in 0..batches { - for _ in 0..32 { - let meta = std::fs::metadata(&path).expect("stat fixture"); - assert!(meta.len() >= 2); - } - } - } - Op::FsWrite => { - let path = base_dir.join("secure-exec-native-fs-write.txt"); - if let Some(size_bytes) = config.size_bytes { - std::fs::write(path, vec![(iter & 255) as u8; size_bytes]).expect("write fixture"); - } else { - std::fs::write(path, format!("hello-{iter:08}")).expect("write fixture"); - } - } - Op::FsRead => { - let size_bytes = config.size_bytes.unwrap_or(64 * 1024); - let path = base_dir.join("secure-exec-native-fs-read.bin"); - let rewrite = std::fs::metadata(&path) - .map(|meta| meta.len() != size_bytes as u64) - .unwrap_or(true); - if rewrite { - std::fs::write(&path, vec![7_u8; size_bytes]).expect("write read fixture"); - } - let data = std::fs::read(path).expect("read fixture"); - assert_eq!(data.len(), size_bytes); - } - Op::StreamCopy => { - let size_bytes = config.size_bytes.unwrap_or(64 * 1024); - let src = base_dir.join(format!( - "secure-exec-native-stream-copy-src-{size_bytes}.bin" - )); - let dst = base_dir.join(format!( - "secure-exec-native-stream-copy-dst-{size_bytes}-{iter}.bin" - )); - let rewrite = std::fs::metadata(&src) - .map(|meta| meta.len() != size_bytes as u64) - .unwrap_or(true); - if rewrite { - std::fs::write(&src, vec![7_u8; size_bytes]).expect("write stream source"); - } - let mut input = File::open(&src).expect("open stream source"); - let mut output = File::create(&dst).expect("create stream destination"); - let mut copied = 0_usize; - let mut buf = vec![0_u8; 16 * 1024]; - loop { - let n = input.read(&mut buf).expect("read stream source"); - if n == 0 { - break; - } - output - .write_all(&buf[..n]) - .expect("write stream destination"); - copied += n; - } - drop(output); - let meta = std::fs::metadata(&dst).expect("stat stream destination"); - std::fs::remove_file(&dst).expect("remove stream destination"); - assert_eq!(copied, size_bytes); - assert_eq!(meta.len(), size_bytes as u64); - } - Op::FsOpenClose => { - let path = base_dir.join("secure-exec-native-fs-open-close.txt"); - std::fs::write(&path, b"hi").expect("write open fixture"); - let file = File::open(path).expect("open fixture"); - drop(file); - } - Op::FsMkdirRmdir => { - let path = base_dir.join(format!("secure-exec-native-dir-{iter}")); - std::fs::create_dir(&path).expect("create dir"); - std::fs::remove_dir(&path).expect("remove dir"); - } - Op::FsRename => { - let from = base_dir.join(format!("secure-exec-native-rename-{iter}.a")); - let to = base_dir.join(format!("secure-exec-native-rename-{iter}.b")); - std::fs::write(&from, b"hi").expect("write rename fixture"); - std::fs::rename(&from, &to).expect("rename fixture"); - std::fs::remove_file(&to).expect("remove rename fixture"); - } - Op::FsReaddir => { - let entry_count = config.entry_count.unwrap_or(32); - let dir = base_dir.join("secure-exec-native-readdir"); - std::fs::create_dir_all(&dir).expect("create readdir dir"); - let marker = dir.join(format!(".fixture-ready-{entry_count}")); - if !marker.exists() { - for i in 0..entry_count { - let path = dir.join(format!("{i}.txt")); - if !path.exists() { - std::fs::write(&path, b"hi").expect("write readdir fixture"); - } - } - std::fs::write(&marker, b"ready").expect("write readdir fixture marker"); - } - let count = std::fs::read_dir(dir).expect("read dir").count(); - assert!(count > entry_count); - } - Op::FsFsync => { - let path = base_dir.join("secure-exec-native-fsync.txt"); - let mut file = File::create(path).expect("create fsync fixture"); - file.write_all(b"hello").expect("write fsync fixture"); - file.sync_all().expect("fsync fixture"); - } - #[cfg(not(target_family = "wasm"))] - Op::DnsLookup => { - let addrs: Vec<_> = ("localhost", 80) - .to_socket_addrs() - .expect("resolve localhost") - .collect(); - assert!(!addrs.is_empty()); - } - #[cfg(not(target_family = "wasm"))] - Op::DnsLookupX2 => { - for _ in 0..2 { - let addrs: Vec<_> = ("localhost", 80) - .to_socket_addrs() - .expect("resolve localhost") - .collect(); - assert!(!addrs.is_empty()); - } - } - #[cfg(not(target_family = "wasm"))] - Op::DnsConcurrent => { - let threads: Vec<_> = (0..4) - .map(|_| { - thread::spawn(|| { - let addrs: Vec<_> = ("localhost", 80) - .to_socket_addrs() - .expect("resolve localhost") - .collect(); - assert!(!addrs.is_empty()); - }) - }) - .collect(); - for handle in threads { - handle.join().expect("join resolver"); - } - } - #[cfg(not(target_family = "wasm"))] - Op::TcpConnect => { - let listener = TcpListener::bind("127.0.0.1:0").expect("bind tcp listener"); - let addr = listener.local_addr().expect("listener addr"); - let server = thread::spawn(move || { - let _ = listener.accept().expect("accept tcp connect"); - }); - let _stream = TcpStream::connect(addr).expect("connect tcp listener"); - server.join().expect("join tcp server"); - } - #[cfg(not(target_family = "wasm"))] - Op::TcpEcho => { - let payload = vec![7_u8; config.size_bytes.unwrap_or(5)]; - let listener = TcpListener::bind("127.0.0.1:0").expect("bind tcp listener"); - let addr = listener.local_addr().expect("listener addr"); - let expected_len = payload.len(); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept tcp echo"); - let mut buf = vec![0_u8; expected_len]; - stream.read_exact(&mut buf).expect("read tcp echo"); - stream.write_all(&buf).expect("write tcp echo"); - }); - let mut stream = TcpStream::connect(addr).expect("connect tcp echo"); - stream.write_all(&payload).expect("write client echo"); - let mut buf = vec![0_u8; payload.len()]; - stream.read_exact(&mut buf).expect("read client echo"); - assert_eq!(buf, payload); - server.join().expect("join tcp server"); - } - #[cfg(all(unix, not(target_family = "wasm")))] - Op::UnixConnect => { - let sock = base_dir.join(format!("secure-exec-native-unix-connect-{iter}.sock")); - let _ = std::fs::remove_file(&sock); - let listener = UnixListener::bind(&sock).expect("bind unix listener"); - let server = thread::spawn(move || { - let (_stream, _) = listener.accept().expect("accept unix connect"); - }); - let stream = UnixStream::connect(&sock).expect("connect unix listener"); - drop(stream); - server.join().expect("join unix server"); - let _ = std::fs::remove_file(&sock); - } - #[cfg(all(unix, not(target_family = "wasm")))] - Op::UnixEcho => { - let payload = vec![7_u8; config.size_bytes.unwrap_or(16)]; - let sock = base_dir.join(format!("secure-exec-native-unix-echo-{iter}.sock")); - let _ = std::fs::remove_file(&sock); - let listener = UnixListener::bind(&sock).expect("bind unix listener"); - let expected_len = payload.len(); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept unix echo"); - let mut buf = vec![0_u8; expected_len]; - stream.read_exact(&mut buf).expect("read unix echo"); - stream.write_all(&buf).expect("write unix echo"); - }); - let mut stream = UnixStream::connect(&sock).expect("connect unix echo"); - stream.write_all(&payload).expect("write client unix echo"); - let mut buf = vec![0_u8; payload.len()]; - stream.read_exact(&mut buf).expect("read client unix echo"); - assert_eq!(buf, payload); - server.join().expect("join unix server"); - let _ = std::fs::remove_file(&sock); - } - #[cfg(not(target_family = "wasm"))] - Op::HttpLoopbackGet => { - let listener = TcpListener::bind("127.0.0.1:0").expect("bind http listener"); - let addr = listener.local_addr().expect("listener addr"); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept http"); - let mut request = Vec::new(); - let mut byte = [0_u8; 1]; - while !request.ends_with(b"\r\n\r\n") { - stream.read_exact(&mut byte).expect("read http request"); - request.push(byte[0]); - } - assert!( - request.starts_with(b"GET / HTTP/1.1\r\n"), - "unexpected HTTP request" - ); - stream - .write_all( - b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nok", - ) - .expect("write http response"); - }); - let mut stream = TcpStream::connect(addr).expect("connect http listener"); - stream - .write_all(b"GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n") - .expect("write http request"); - let mut response = Vec::new(); - stream - .read_to_end(&mut response) - .expect("read http response"); - assert!( - response.ends_with(b"\r\n\r\nok"), - "unexpected HTTP response body" - ); - server.join().expect("join http server"); - } - #[cfg(not(target_family = "wasm"))] - Op::TcpConcurrent => { - let listener = TcpListener::bind("127.0.0.1:0").expect("bind tcp listener"); - let addr = listener.local_addr().expect("listener addr"); - let server = thread::spawn(move || { - for _ in 0..4 { - let (mut stream, _) = listener.accept().expect("accept tcp connect"); - let mut buf = [0_u8; 1]; - let _ = stream.read(&mut buf); - } - }); - let mut clients = Vec::new(); - for _ in 0..4 { - clients.push(TcpStream::connect(addr).expect("connect tcp listener")); - } - for mut client in clients { - client.write_all(b"x").expect("write connect byte"); - } - server.join().expect("join tcp server"); - } - #[cfg(not(target_family = "wasm"))] - Op::TcpThroughput => { - let payload = vec![7_u8; config.size_bytes.unwrap_or(64 * 1024)]; - let listener = TcpListener::bind("127.0.0.1:0").expect("bind tcp listener"); - let addr = listener.local_addr().expect("listener addr"); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept tcp throughput"); - let mut buf = vec![0_u8; 64 * 1024]; - stream.read_exact(&mut buf).expect("read tcp throughput"); - stream.write_all(&buf).expect("write tcp throughput"); - }); - let mut stream = TcpStream::connect(addr).expect("connect tcp throughput"); - stream.write_all(&payload).expect("write client throughput"); - let mut out = vec![0_u8; payload.len()]; - stream.read_exact(&mut out).expect("read client throughput"); - assert_eq!(out.len(), payload.len()); - server.join().expect("join tcp server"); - } - #[cfg(not(target_family = "wasm"))] - Op::TcpTinyWrites => { - let listener = TcpListener::bind("127.0.0.1:0").expect("bind tcp listener"); - let addr = listener.local_addr().expect("listener addr"); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept tcp tiny"); - let mut buf = [0_u8; 16]; - stream.read_exact(&mut buf).expect("read tcp tiny"); - stream.write_all(&buf).expect("write tcp tiny"); - }); - let mut stream = TcpStream::connect(addr).expect("connect tcp tiny"); - for _ in 0..16 { - stream.write_all(b"x").expect("write tiny byte"); - } - let mut out = [0_u8; 16]; - stream.read_exact(&mut out).expect("read tiny echo"); - server.join().expect("join tcp server"); - } - #[cfg(not(target_family = "wasm"))] - Op::UdpEcho => { - let payload = vec![7_u8; config.size_bytes.unwrap_or(5)]; - let server = UdpSocket::bind("127.0.0.1:0").expect("bind udp server"); - let addr = server.local_addr().expect("udp addr"); - let expected_len = payload.len(); - let handle = thread::spawn(move || { - let mut buf = vec![0_u8; expected_len]; - let (n, peer) = server.recv_from(&mut buf).expect("recv udp"); - server.send_to(&buf[..n], peer).expect("send udp"); - }); - let client = UdpSocket::bind("127.0.0.1:0").expect("bind udp client"); - client.send_to(&payload, addr).expect("send udp client"); - let mut buf = vec![0_u8; payload.len()]; - let (n, _) = client.recv_from(&mut buf).expect("recv udp client"); - assert_eq!(n, payload.len()); - assert_eq!(buf, payload); - handle.join().expect("join udp server"); - } - #[cfg(not(target_family = "wasm"))] - Op::PipeEcho => { - let out = Command::new("/bin/sh") - .args(["-c", "printf hello | cat >/dev/null"]) - .output() - .expect("run pipe echo"); - assert!(out.status.success(), "pipe command failed: {out:?}"); - } - #[cfg(not(target_family = "wasm"))] - Op::PipeThroughput | Op::PipeBackpressure => { - #[cfg(unix)] - { - let (mut left, mut right) = UnixStream::pair().expect("unix stream pair"); - let payload = vec![9_u8; config.size_bytes.unwrap_or(64 * 1024)]; - let expected_len = payload.len(); - let reader = thread::spawn(move || { - let mut out = vec![0_u8; expected_len]; - right.read_exact(&mut out).expect("pipe read"); - out - }); - left.write_all(&payload).expect("pipe write"); - let out = reader.join().expect("join pipe reader"); - assert_eq!(out.len(), payload.len()); - } - #[cfg(not(unix))] - { - let out = Command::new("/bin/sh") - .args(["-c", "printf hello | cat >/dev/null"]) - .output() - .expect("run pipe fallback"); - assert!(out.status.success(), "pipe fallback failed: {out:?}"); - } - } - Op::StdioWriteSync => { - let size_bytes = config.size_bytes.unwrap_or(64 * 1024); - let chunk_count = config.chunk_count.unwrap_or(8); - let payload = vec![7_u8; size_bytes]; - #[cfg(not(target_family = "wasm"))] - let mut sink: Box = Box::new( - std::fs::OpenOptions::new() - .write(true) - .open("/dev/null") - .expect("open /dev/null"), - ); - #[cfg(target_family = "wasm")] - let mut sink: Box = Box::new(std::io::sink()); - for _ in 0..chunk_count { - sink.write_all(&payload).expect("write stdio payload"); - } - sink.flush().expect("flush stdio payload"); - } - Op::CpuLoop => { - let mut acc = 0_u64; - for i in 0..2_000_000_u64 { - acc = acc.wrapping_add(i ^ (acc.rotate_left(7))); - } - std::hint::black_box(acc); - } - Op::SleepTimer => { - let count = config.timer_count.unwrap_or(50); - let sleep_ns = config.sleep_ns.unwrap_or(1_000_000); - let duration = Duration::from_nanos(sleep_ns); - for _ in 0..count { - std::thread::sleep(duration); - } - } - Op::YieldLoop => { - let count = config.timer_count.unwrap_or(1000); - for _ in 0..count { - // This is the closest native analogue to setImmediate cadence: it - // yields scheduler turn-taking, but it does not model JS task queues. - std::thread::yield_now(); - } - } - Op::AllocFree => { - let mut data = vec![0_u8; 4 * 1024 * 1024]; - for (i, byte) in data.iter_mut().enumerate() { - *byte = (i % 251) as u8; - } - std::hint::black_box(data); - } - #[cfg(target_family = "wasm")] - _ => unreachable!("unsupported wasm op checked before execution"), - } -} - -fn arg_value(args: &[String], flag: &str) -> Option { - args.iter() - .position(|a| a == flag) - .and_then(|i| args.get(i + 1).cloned()) -} - -#[cfg(not(target_family = "wasm"))] -fn run_node_exit_phases() -> Vec<(&'static str, u128)> { - let total_start = timer_start(); - let spawn_start = timer_start(); - let mut child = Command::new("node") - .args(["-e", "process.exit(0)"]) - .spawn() - .expect("spawn node failed"); - let spawn_ns = elapsed_ns(spawn_start); - - let wait_start = timer_start(); - let status = child.wait().expect("wait node child"); - let wait_ns = elapsed_ns(wait_start); - assert!(status.success(), "expected exit 0, got {status:?}"); - - vec![ - ("total", elapsed_ns(total_start)), - ("spawn", spawn_ns), - ("wait_reap", wait_ns), - ] -} - -#[cfg(not(target_family = "wasm"))] -fn run_node_fanout_phases() -> Vec<(&'static str, u128)> { - let total_start = timer_start(); - let spawn_start = timer_start(); - let mut children = Vec::new(); - for _ in 0..8 { - children.push( - Command::new("node") - .args(["-e", "process.exit(0)"]) - .spawn() - .expect("spawn node failed"), - ); - } - let spawn_ns = elapsed_ns(spawn_start); - - let wait_start = timer_start(); - for mut child in children { - let status = child.wait().expect("wait node child"); - assert!(status.success(), "expected exit 0, got {status:?}"); - } - let wait_ns = elapsed_ns(wait_start); - - vec![ - ("total", elapsed_ns(total_start)), - ("spawn_batch", spawn_ns), - ("wait_reap_batch", wait_ns), - ] -} - -#[cfg(not(target_family = "wasm"))] -fn run_phases_once(op: Op) -> Option> { - match op { - Op::NodeExit => Some(run_node_exit_phases()), - Op::NodeFanout | Op::NodeReapStorm => Some(run_node_fanout_phases()), - _ => None, - } -} - -#[cfg(target_family = "wasm")] -fn run_phases_once(_op: Op) -> Option> { - None -} - -fn write_phase_json(op_name: &str, samples: &[(String, Vec)]) { - let mut out = String::with_capacity(1024); - out.push_str("{\"layer\":\"native\",\"op\":\""); - out.push_str(op_name); - out.push_str("\",\"unit\":\"ns\",\"phases\":{"); - for (phase_index, (phase, values)) in samples.iter().enumerate() { - if phase_index > 0 { - out.push(','); - } - out.push('"'); - out.push_str(phase); - out.push_str("\":["); - for (sample_index, value) in values.iter().enumerate() { - if sample_index > 0 { - out.push(','); - } - out.push_str(&value.to_string()); - } - out.push(']'); - } - out.push_str("}}"); - println!("{out}"); -} - -fn main() { - let args: Vec = std::env::args().skip(1).collect(); - - if args.iter().any(|arg| arg == "--list-ops") { - for name in OP_NAMES { - println!("{name}"); - } - return; - } - - let op_arg = arg_value(&args, "--op"); - let op = match op_arg.as_deref().and_then(parse_op) { - Some(op) => op, - None => { - eprintln!("unknown --op {:?}", op_arg.as_deref()); - std::process::exit(2); - } - }; - let op_name = op_name(op); - #[cfg(target_family = "wasm")] - if !op.supported_on_wasm() { - println!("{{\"unsupported\":true,\"op\":\"{op_name}\"}}"); - return; - } - let iters: usize = arg_value(&args, "--iters") - .and_then(|s| s.parse().ok()) - .unwrap_or(300); - let warmup: usize = arg_value(&args, "--warmup") - .and_then(|s| s.parse().ok()) - .unwrap_or(30); - let base_dir = if let Some(path) = arg_value(&args, "--base-dir") { - let path = std::path::PathBuf::from(path); - if !path.exists() { - std::fs::create_dir_all(&path).expect("create base dir"); - } - path - } else { - std::env::temp_dir() - }; - let config = BenchConfig { - size_bytes: arg_value(&args, "--size-bytes").and_then(|s| s.parse().ok()), - entry_count: arg_value(&args, "--entry-count").and_then(|s| s.parse().ok()), - timer_count: arg_value(&args, "--timer-count").and_then(|s| s.parse().ok()), - sleep_ns: arg_value(&args, "--sleep-ns").and_then(|s| s.parse().ok()), - chunk_count: arg_value(&args, "--chunk-count").and_then(|s| s.parse().ok()), - }; - let phases = args.iter().any(|arg| arg == "--phases"); - - let total = warmup + iters; - if phases { - let Some(first) = run_phases_once(op) else { - eprintln!("--phases is not supported for --op {op_name}"); - std::process::exit(2); - }; - let mut phase_samples = first - .into_iter() - .map(|(name, _)| (name.to_string(), Vec::with_capacity(iters))) - .collect::>(); - for i in 0..total { - let phase_values = run_phases_once(op).expect("checked phase support"); - if i >= warmup { - for (phase_name, value) in phase_values { - if let Some((_, values)) = phase_samples - .iter_mut() - .find(|(name, _)| name == phase_name) - { - values.push(value); - } - } - } - } - write_phase_json(op_name, &phase_samples); - return; - } - - let mut samples: Vec = Vec::with_capacity(iters); - for i in 0..total { - let t = timer_start(); - run_once(op, i, &base_dir, &config); - let ns = elapsed_ns(t); - if i >= warmup { - samples.push(ns); - } - } - - // Hand-built JSON (no serde dep): {"layer":"native","op":..,"unit":"ns","samples":[..]} - let mut out = String::with_capacity(samples.len() * 8 + 64); - out.push_str("{\"layer\":\"native\",\"op\":\""); - out.push_str(op_name); - out.push_str("\",\"unit\":\"ns\",\"samples\":["); - for (i, s) in samples.iter().enumerate() { - if i > 0 { - out.push(','); - } - out.push_str(&s.to_string()); - } - out.push_str("]}"); - println!("{out}"); -} diff --git a/crates/secure-exec-client/AGENTS.md b/crates/secure-exec-client/AGENTS.md deleted file mode 120000 index 681311eb9..000000000 --- a/crates/secure-exec-client/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/crates/secure-exec-client/CLAUDE.md b/crates/secure-exec-client/CLAUDE.md deleted file mode 100644 index c2e1c0e6d..000000000 --- a/crates/secure-exec-client/CLAUDE.md +++ /dev/null @@ -1,7 +0,0 @@ -See `../CLAUDE.md` for crate-wide runtime and testing rules. - -## Local Patterns - -- Keep this crate Agent OS-agnostic: no `agentos-protocol`, `agentos-client`, `agentos-sidecar`, ACP, agents, sessions, or toolkit semantics. -- The generic transport resolves `SECURE_EXEC_SIDECAR_BIN` / `secure-exec-sidecar`; product wrappers such as Agent OS must resolve their own wrapper binary and pass it explicitly. -- Expose raw secure-exec wire types and transport primitives only; ergonomic product facades belong in product-specific client crates. diff --git a/crates/secure-exec-client/Cargo.toml b/crates/secure-exec-client/Cargo.toml deleted file mode 100644 index ec0d1cf2e..000000000 --- a/crates/secure-exec-client/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "secure-exec-client" -version.workspace = true -edition.workspace = true -license.workspace = true -repository.workspace = true -description = "Rust client transport for the Secure Exec native sidecar" - -[dependencies] -secure-exec-sidecar-protocol = { workspace = true } - -futures = "0.3" -parking_lot = "0.12" -scc = "2" -thiserror = "2" -tokio = { version = "1", features = ["io-util", "macros", "process", "rt", "sync"] } -tracing = "0.1" diff --git a/crates/secure-exec-client/src/error.rs b/crates/secure-exec-client/src/error.rs deleted file mode 100644 index ae061ae26..000000000 --- a/crates/secure-exec-client/src/error.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub use secure_exec_sidecar_protocol::wire::ProtocolCodecError; - -/// Errors produced by the low-level sidecar transport. -#[derive(thiserror::Error, Debug)] -pub enum TransportError { - /// A framing or BARE codec failure on the sidecar transport. - #[error("transport error: {0}")] - Protocol(#[from] ProtocolCodecError), - - /// A sidecar process, stdin/stdout, or connection failure with context. - #[error("sidecar error: {0}")] - Sidecar(String), -} - -/// Convenience alias for sidecar transport results. -pub type TransportResult = std::result::Result; diff --git a/crates/secure-exec-client/src/lib.rs b/crates/secure-exec-client/src/lib.rs deleted file mode 100644 index 4da4ab71f..000000000 --- a/crates/secure-exec-client/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![forbid(unsafe_code)] - -//! Low-level Rust client transport for the Secure Exec native sidecar. -//! -//! This crate owns the framed stdio transport and exposes the generated Secure Exec wire protocol. -//! Higher level products layer their own authentication, extension payloads, and -//! typed API surfaces on top of this transport. - -pub mod error; -pub mod transport; -pub mod wire; - -pub use error::{ProtocolCodecError, TransportError, TransportResult}; -pub use transport::{SidecarTransport, WireSidecarCallback}; diff --git a/crates/secure-exec-client/src/transport.rs b/crates/secure-exec-client/src/transport.rs deleted file mode 100644 index d9e9da320..000000000 --- a/crates/secure-exec-client/src/transport.rs +++ /dev/null @@ -1,688 +0,0 @@ -//! `SidecarTransport`: spawns a native sidecar binary and speaks the existing framed -//! BARE protocol over its stdio. -//! -//! This mirrors the TypeScript `Sidecar`. Generated wire payloads are the native -//! transport path. -//! -//! Request-id direction is load-bearing: host-initiated `Request`/`Response` frames use positive ids -//! allocated by this transport, while sidecar-initiated `SidecarRequest`/`SidecarResponse` callbacks -//! echo the id allocated by the sidecar. - -use std::process::Stdio; -use std::sync::atomic::{AtomicI64, AtomicUsize, Ordering}; -use std::sync::{Arc, Weak}; - -use scc::HashMap as SccHashMap; -use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use tokio::process::{Child, ChildStdout, Command}; -use tokio::sync::{broadcast, mpsc, oneshot}; - -use crate::wire::{self, WireFrameCodec}; -use crate::TransportError; - -/// Broadcast capacity for the structured/lifecycle/process event fan-out. -const EVENT_CHANNEL_CAPACITY: usize = 4096; - -/// Maximum outbound frames buffered while the writer task drains to sidecar stdin. -const REQUEST_FRAME_QUEUE_CAPACITY: usize = 4096; - -/// Maximum callback/control response frames buffered ahead of regular host requests. -const CONTROL_FRAME_QUEUE_CAPACITY: usize = 1024; - -/// Maximum in-flight host-initiated sidecar requests per transport. -const PENDING_REQUEST_LIMIT: usize = 4096; - -/// Env var that overrides the sidecar binary path. Defaults to `secure-exec-sidecar` on `PATH`. -/// Product clients can pass an explicit binary path to [`SidecarTransport::spawn`]. -const SIDECAR_BIN_ENV: &str = "SECURE_EXEC_SIDECAR_BIN"; - -/// A registered callback that answers a sidecar-initiated request using generated wire types. -pub type WireSidecarCallback = Arc< - dyn Fn( - wire::SidecarRequestPayload, - wire::OwnershipScope, - ) -> futures::future::BoxFuture< - 'static, - Result, - > + Send - + Sync, ->; - -/// Owns the spawned sidecar child, the framed BARE stdio I/O tasks, the pending-response map, the -/// event fan-out, and the callback dispatch table. -pub struct SidecarTransport { - /// The spawned sidecar process (stdout/stdin taken by the I/O tasks; kept for kill on drop). - child: parking_lot::Mutex>, - /// Pending host-initiated requests, keyed by positive `RequestId`. - pending: SccHashMap>, - pending_request_lock: parking_lot::Mutex<()>, - /// Host request-id counter (positive, starts at 1). - request_counter: AtomicI64, - /// Negotiated max frame size. - max_frame_bytes: AtomicUsize, - /// Structured-event fan-out for `Event` frames. - event_tx: broadcast::Sender<(wire::OwnershipScope, wire::EventPayload)>, - /// Registered host callbacks for `SidecarRequest` frames. - callbacks: SccHashMap<&'static str, WireSidecarCallback>, - /// Outbound host request frames drained by the writer task into the child's stdin. - request_writer_tx: mpsc::Sender>, - /// Outbound callback/control response frames. The writer drains this before regular requests. - control_writer_tx: mpsc::Sender>, -} - -impl SidecarTransport { - /// Spawn the native sidecar binary and start the stdio I/O tasks. - /// - /// Does NOT run the handshake. Product clients drive Authenticate and any follow-up setup using - /// [`request_wire`](Self::request_wire) once the transport is live. - pub async fn spawn(binary_path: Option) -> Result, TransportError> { - let bin = resolve_sidecar_binary_path(binary_path); - let mut child = Command::new(&bin) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .kill_on_drop(true) - .spawn() - .map_err(|error| { - TransportError::Sidecar(format!("failed to spawn sidecar '{bin}': {error}")) - })?; - - let stdin = child - .stdin - .take() - .ok_or_else(|| TransportError::Sidecar("sidecar stdin was not piped".to_string()))?; - let stdout = child - .stdout - .take() - .ok_or_else(|| TransportError::Sidecar("sidecar stdout was not piped".to_string()))?; - - let (request_writer_tx, request_writer_rx) = mpsc::channel(REQUEST_FRAME_QUEUE_CAPACITY); - let (control_writer_tx, control_writer_rx) = mpsc::channel(CONTROL_FRAME_QUEUE_CAPACITY); - let (event_tx, _) = broadcast::channel(EVENT_CHANNEL_CAPACITY); - - let transport = Arc::new(Self { - child: parking_lot::Mutex::new(Some(child)), - pending: SccHashMap::new(), - pending_request_lock: parking_lot::Mutex::new(()), - request_counter: AtomicI64::new(1), - max_frame_bytes: AtomicUsize::new(wire::DEFAULT_MAX_FRAME_BYTES), - event_tx, - callbacks: SccHashMap::new(), - request_writer_tx, - control_writer_tx, - }); - - tokio::spawn(run_writer(stdin, control_writer_rx, request_writer_rx)); - tokio::spawn(run_reader(Arc::downgrade(&transport), stdout)); - - Ok(transport) - } - - /// Allocate the next positive host request id. - pub fn next_request_id(&self) -> wire::RequestId { - self.request_counter.fetch_add(1, Ordering::SeqCst) - } - - /// Issue a host request using generated wire protocol types and await a generated response. - pub async fn request_wire( - &self, - ownership: wire::OwnershipScope, - payload: wire::RequestPayload, - ) -> Result { - self.request_wire_with_frame_limit(ownership, payload, None) - .await - } - - /// Issue a host request using generated wire protocol types with a caller-specific frame limit. - pub async fn request_wire_bounded( - &self, - ownership: wire::OwnershipScope, - payload: wire::RequestPayload, - max_frame_bytes: usize, - ) -> Result { - self.request_wire_with_frame_limit(ownership, payload, Some(max_frame_bytes)) - .await - } - - async fn request_wire_with_frame_limit( - &self, - ownership: wire::OwnershipScope, - payload: wire::RequestPayload, - max_frame_bytes: Option, - ) -> Result { - let request_id = self.next_request_id(); - let frame = wire::ProtocolFrame::RequestFrame(wire::RequestFrame { - schema: wire::protocol_schema(), - request_id, - ownership, - payload, - }); - let bytes = self.encode_wire_frame(&frame, max_frame_bytes)?; - - let (tx, rx) = oneshot::channel(); - self.register_pending_request(request_id, tx)?; - let _pending_guard = PendingRequestGuard::new(self, request_id); - - if self.request_writer_tx.send(bytes).await.is_err() { - self.pending.remove(&request_id); - return Err(TransportError::Sidecar( - "sidecar transport closed".to_string(), - )); - } - - rx.await - .map_err(|_| TransportError::Sidecar("sidecar transport disconnected".to_string())) - } - - /// Subscribe to structured/lifecycle/process events using generated wire protocol types. - pub fn subscribe_wire_events( - &self, - ) -> broadcast::Receiver<(wire::OwnershipScope, wire::EventPayload)> { - self.event_tx.subscribe() - } - - /// Register a callback that answers a class of sidecar-initiated requests using generated wire - /// protocol types. - pub fn register_wire_callback(&self, key: &'static str, callback: WireSidecarCallback) { - let _ = self.callbacks.insert(key, callback); - } - - /// Return the currently negotiated max frame size. - pub fn max_frame_bytes(&self) -> usize { - self.max_frame_bytes.load(Ordering::Relaxed) - } - - /// Update the negotiated max frame size after authentication. - pub fn set_max_frame_bytes(&self, max_frame_bytes: usize) { - self.max_frame_bytes - .store(max_frame_bytes, Ordering::SeqCst); - } - - /// Kill the child sidecar process if this transport still owns one. - pub fn kill_child(&self) { - if let Some(mut child) = self.child.lock().take() { - let _ = child.start_kill(); - } - } - - fn encode_wire_frame( - &self, - frame: &wire::ProtocolFrame, - max_frame_bytes: Option, - ) -> Result, TransportError> { - let transport_limit = self.max_frame_bytes.load(Ordering::Relaxed); - let max_frame_bytes = max_frame_bytes - .map(|limit| limit.min(transport_limit)) - .unwrap_or(transport_limit); - let codec = WireFrameCodec::new(max_frame_bytes); - Ok(codec.encode(frame)?) - } - - /// Route a decoded inbound frame. Host transports only legitimately receive `Response`, `Event`, - /// and `SidecarRequest` frames. - async fn handle_wire_frame(self: &Arc, frame: wire::ProtocolFrame) { - match frame { - wire::ProtocolFrame::ResponseFrame(response) => { - match self.pending.remove(&response.request_id) { - Some((_, tx)) => { - let _ = tx.send(response.payload); - } - None => { - tracing::warn!( - request_id = response.request_id, - "response for unknown request id" - ) - } - } - } - wire::ProtocolFrame::EventFrame(event) => { - let _ = self.event_tx.send((event.ownership, event.payload)); - } - wire::ProtocolFrame::SidecarRequestFrame(request) => { - self.dispatch_sidecar_request(request).await - } - wire::ProtocolFrame::SidecarResponseFrame(_) | wire::ProtocolFrame::RequestFrame(_) => { - tracing::warn!("unexpected inbound frame on host transport") - } - } - } - - /// Dispatch a sidecar-initiated request to its registered callback. The callback runs in a - /// spawned task so long-running host callbacks (tool execution, permission prompts) cannot stall - /// the reader loop, which must keep draining responses for any requests the callback itself - /// issues through this transport. - async fn dispatch_sidecar_request(self: &Arc, frame: wire::SidecarRequestFrame) { - let key = sidecar_request_key(&frame.payload); - let callback = self.callbacks.read(&key, |_, value| value.clone()); - match callback { - Some(callback) => { - let transport = Arc::downgrade(self); - tokio::spawn(async move { - match callback(frame.payload, frame.ownership.clone()).await { - Ok(payload) => { - let response = wire::ProtocolFrame::SidecarResponseFrame( - wire::SidecarResponseFrame { - schema: wire::protocol_schema(), - request_id: frame.request_id, - ownership: frame.ownership, - payload, - }, - ); - // If the transport is gone, the child is being killed; drop the reply. - let Some(transport) = transport.upgrade() else { - return; - }; - if let Ok(bytes) = transport.encode_wire_frame(&response, None) { - let _ = transport.control_writer_tx.send(bytes).await; - } - } - Err(error) => tracing::warn!(?error, key, "sidecar callback failed"), - } - }); - } - None => tracing::warn!(key, "no callback registered for sidecar request"), - } - } - - /// Reject every in-flight request after the transport disconnects. - fn fail_all_pending(&self) { - self.pending.clear(); - } - - fn register_pending_request( - &self, - request_id: wire::RequestId, - tx: oneshot::Sender, - ) -> Result<(), TransportError> { - let _guard = self.pending_request_lock.lock(); - if pending_request_count(self) >= PENDING_REQUEST_LIMIT { - return Err(TransportError::Sidecar(format!( - "sidecar pending request limit exceeded: at most {PENDING_REQUEST_LIMIT} requests can be in flight" - ))); - } - let _ = self.pending.insert(request_id, tx); - Ok(()) - } -} - -struct PendingRequestGuard<'a> { - transport: &'a SidecarTransport, - request_id: wire::RequestId, -} - -impl<'a> PendingRequestGuard<'a> { - fn new(transport: &'a SidecarTransport, request_id: wire::RequestId) -> Self { - Self { - transport, - request_id, - } - } -} - -impl Drop for PendingRequestGuard<'_> { - fn drop(&mut self) { - let _ = self.transport.pending.remove(&self.request_id); - } -} - -fn pending_request_count(transport: &SidecarTransport) -> usize { - let mut count = 0; - transport.pending.scan(|_, _| { - count += 1; - }); - count -} - -/// Map a sidecar-request payload to the callback registry key. -fn sidecar_request_key(payload: &wire::SidecarRequestPayload) -> &'static str { - match payload { - wire::SidecarRequestPayload::HostCallbackRequest(_) => "host_callback", - wire::SidecarRequestPayload::JsBridgeCallRequest(_) => "js_bridge_call", - wire::SidecarRequestPayload::ExtEnvelope(_) => "ext", - } -} - -/// Drain outbound channels into the child's stdin. Control responses are preferred so a full request -/// queue cannot starve sidecar-request replies. -async fn run_writer( - mut stdin: W, - mut control_rx: mpsc::Receiver>, - mut request_rx: mpsc::Receiver>, -) where - W: AsyncWrite + Unpin, -{ - let mut prefer_control = true; - loop { - let (bytes, wrote_control) = if prefer_control { - tokio::select! { - biased; - bytes = control_rx.recv() => match bytes { - Some(bytes) => (bytes, true), - None => match request_rx.recv().await { - Some(bytes) => (bytes, false), - None => break, - }, - }, - bytes = request_rx.recv() => match bytes { - Some(bytes) => (bytes, false), - None => match control_rx.recv().await { - Some(bytes) => (bytes, true), - None => break, - }, - }, - } - } else { - tokio::select! { - biased; - bytes = request_rx.recv() => match bytes { - Some(bytes) => (bytes, false), - None => match control_rx.recv().await { - Some(bytes) => (bytes, true), - None => break, - }, - }, - bytes = control_rx.recv() => match bytes { - Some(bytes) => (bytes, true), - None => match request_rx.recv().await { - Some(bytes) => (bytes, false), - None => break, - }, - }, - } - }; - if stdin.write_all(&bytes).await.is_err() { - break; - } - if stdin.flush().await.is_err() { - break; - } - prefer_control = !wrote_control; - } -} - -/// Read length-prefixed BARE frames from the child's stdout and route them. Holds a `Weak` so the -/// transport can drop (and `kill_on_drop` the child) independently; exits on EOF/read error or once -/// the transport is gone. -async fn run_reader(transport: Weak, mut stdout: ChildStdout) { - loop { - let mut length_buf = [0u8; 4]; - if stdout.read_exact(&mut length_buf).await.is_err() { - break; - } - let length = u32::from_be_bytes(length_buf) as usize; - - let Some(transport) = transport.upgrade() else { - break; - }; - let max_frame_bytes = transport.max_frame_bytes.load(Ordering::Relaxed); - if frame_length_exceeds_limit(length, max_frame_bytes) { - tracing::warn!( - size = length, - max = max_frame_bytes, - "sidecar frame exceeds negotiated limit" - ); - break; - } - - let mut frame_bytes = vec![0u8; 4 + length]; - frame_bytes[..4].copy_from_slice(&length_buf); - if stdout.read_exact(&mut frame_bytes[4..]).await.is_err() { - break; - } - - let codec = WireFrameCodec::new(max_frame_bytes); - match codec.decode(&frame_bytes) { - Ok(frame) => transport.handle_wire_frame(frame).await, - Err(error) => tracing::warn!(?error, "failed to decode sidecar frame"), - } - } - - if let Some(transport) = transport.upgrade() { - transport.fail_all_pending(); - } -} - -fn frame_length_exceeds_limit(length: usize, max_frame_bytes: usize) -> bool { - length > max_frame_bytes -} - -fn resolve_sidecar_binary_path(binary_path: Option) -> String { - binary_path - .or_else(|| std::env::var(SIDECAR_BIN_ENV).ok()) - .unwrap_or_else(|| "secure-exec-sidecar".to_string()) -} - -#[cfg(test)] -mod tests { - use super::*; - use std::sync::Mutex; - - static ENV_LOCK: Mutex<()> = Mutex::new(()); - - fn test_transport() -> SidecarTransport { - let (request_writer_tx, _request_writer_rx) = mpsc::channel(REQUEST_FRAME_QUEUE_CAPACITY); - let (control_writer_tx, _control_writer_rx) = mpsc::channel(CONTROL_FRAME_QUEUE_CAPACITY); - let (event_tx, _) = broadcast::channel(EVENT_CHANNEL_CAPACITY); - SidecarTransport { - child: parking_lot::Mutex::new(None), - pending: SccHashMap::new(), - pending_request_lock: parking_lot::Mutex::new(()), - request_counter: AtomicI64::new(1), - max_frame_bytes: AtomicUsize::new(wire::DEFAULT_MAX_FRAME_BYTES), - event_tx, - callbacks: SccHashMap::new(), - request_writer_tx, - control_writer_tx, - } - } - - #[test] - fn binary_path_prefers_explicit_path_over_env() { - let _guard = ENV_LOCK.lock().expect("env lock"); - let previous = std::env::var(SIDECAR_BIN_ENV).ok(); - std::env::set_var(SIDECAR_BIN_ENV, "/tmp/from-env"); - - assert_eq!( - resolve_sidecar_binary_path(Some("/tmp/from-config".to_string())), - "/tmp/from-config" - ); - - restore_env(SIDECAR_BIN_ENV, previous); - } - - #[test] - fn binary_path_uses_secure_exec_env_fallback() { - let _guard = ENV_LOCK.lock().expect("env lock"); - let previous = std::env::var(SIDECAR_BIN_ENV).ok(); - std::env::set_var(SIDECAR_BIN_ENV, "/tmp/secure-exec-sidecar"); - - assert_eq!( - resolve_sidecar_binary_path(None), - "/tmp/secure-exec-sidecar" - ); - - restore_env(SIDECAR_BIN_ENV, previous); - } - - #[test] - fn binary_path_defaults_to_secure_exec_sidecar() { - let _guard = ENV_LOCK.lock().expect("env lock"); - let previous = std::env::var(SIDECAR_BIN_ENV).ok(); - std::env::remove_var(SIDECAR_BIN_ENV); - - assert_eq!(resolve_sidecar_binary_path(None), "secure-exec-sidecar"); - - restore_env(SIDECAR_BIN_ENV, previous); - } - - fn restore_env(key: &str, value: Option) { - match value { - Some(value) => std::env::set_var(key, value), - None => std::env::remove_var(key), - } - } - - #[test] - fn frame_length_limit_rejects_oversized_declared_length() { - assert!(!frame_length_exceeds_limit(1024, 1024)); - assert!(frame_length_exceeds_limit(1025, 1024)); - } - - #[test] - fn transport_encodes_requests_with_generated_wire_codec() { - let transport = test_transport(); - let frame = wire::ProtocolFrame::RequestFrame(wire::RequestFrame { - schema: wire::protocol_schema(), - request_id: 7, - ownership: wire::OwnershipScope::ConnectionOwnership(wire::ConnectionOwnership { - connection_id: "conn-1".to_string(), - }), - payload: wire::RequestPayload::AuthenticateRequest(wire::AuthenticateRequest { - client_name: "transport-test".to_string(), - auth_token: "token".to_string(), - protocol_version: wire::PROTOCOL_VERSION, - bridge_version: 1, - }), - }); - - let encoded = transport - .encode_wire_frame(&frame, None) - .expect("encode transport frame"); - let decoded = WireFrameCodec::default() - .decode(&encoded) - .expect("decode generated wire frame"); - - assert!(matches!( - decoded, - wire::ProtocolFrame::RequestFrame(wire::RequestFrame { - payload: wire::RequestPayload::AuthenticateRequest(_), - .. - }) - )); - } - - #[tokio::test] - async fn transport_fans_out_generated_wire_events() { - let transport = Arc::new(test_transport()); - let mut wire_events = transport.subscribe_wire_events(); - - transport - .handle_wire_frame(wire::ProtocolFrame::EventFrame(wire::EventFrame { - schema: wire::protocol_schema(), - ownership: wire::OwnershipScope::VmOwnership(wire::VmOwnership { - connection_id: "conn-1".to_string(), - session_id: "session-1".to_string(), - vm_id: "vm-1".to_string(), - }), - payload: wire::EventPayload::ProcessOutputEvent(wire::ProcessOutputEvent { - process_id: "proc-1".to_string(), - channel: wire::StreamChannel::Stdout, - chunk: b"hello".to_vec(), - }), - })) - .await; - - let (ownership, payload) = wire_events.recv().await.expect("wire event"); - assert!(matches!( - ownership, - wire::OwnershipScope::VmOwnership(wire::VmOwnership { - connection_id, - session_id, - vm_id, - }) if connection_id == "conn-1" && session_id == "session-1" && vm_id == "vm-1" - )); - assert!(matches!( - payload, - wire::EventPayload::ProcessOutputEvent(wire::ProcessOutputEvent { - process_id, - channel: wire::StreamChannel::Stdout, - chunk, - }) if process_id == "proc-1" && chunk == b"hello".to_vec() - )); - } - - #[test] - fn pending_request_guard_removes_registered_slot_on_drop() { - let transport = test_transport(); - let (tx, _rx) = oneshot::channel(); - transport - .register_pending_request(1, tx) - .expect("register pending request"); - - { - let _guard = PendingRequestGuard::new(&transport, 1); - assert_eq!(pending_request_count(&transport), 1); - } - - assert_eq!(pending_request_count(&transport), 0); - } - - #[test] - fn pending_request_limit_rejects_full_transport() { - let transport = test_transport(); - for request_id in 1..=PENDING_REQUEST_LIMIT as wire::RequestId { - let (tx, _rx) = oneshot::channel(); - transport - .register_pending_request(request_id, tx) - .expect("register pending request"); - } - let (tx, _rx) = oneshot::channel(); - let error = transport - .register_pending_request((PENDING_REQUEST_LIMIT + 1) as wire::RequestId, tx) - .expect_err("full pending map should reject"); - - assert!( - error - .to_string() - .contains("sidecar pending request limit exceeded"), - "unexpected error: {error}" - ); - } - - #[tokio::test] - async fn writer_prioritizes_control_frames_over_request_backlog() { - let (client, mut server) = tokio::io::duplex(64); - let (control_tx, control_rx) = mpsc::channel(CONTROL_FRAME_QUEUE_CAPACITY); - let (request_tx, request_rx) = mpsc::channel(REQUEST_FRAME_QUEUE_CAPACITY); - request_tx - .send(vec![b'r']) - .await - .expect("send request frame"); - control_tx - .send(vec![b'c']) - .await - .expect("send control frame"); - drop(control_tx); - drop(request_tx); - - let writer = tokio::spawn(run_writer(client, control_rx, request_rx)); - let mut first = [0u8; 1]; - server - .read_exact(&mut first) - .await - .expect("read first byte"); - writer.await.expect("writer task"); - - assert_eq!(first, [b'c']); - } - - #[tokio::test] - async fn writer_alternates_when_control_and_request_are_ready() { - let (client, mut server) = tokio::io::duplex(64); - let (control_tx, control_rx) = mpsc::channel(CONTROL_FRAME_QUEUE_CAPACITY); - let (request_tx, request_rx) = mpsc::channel(REQUEST_FRAME_QUEUE_CAPACITY); - control_tx.send(vec![b'c']).await.expect("control one"); - control_tx.send(vec![b'C']).await.expect("control two"); - request_tx.send(vec![b'r']).await.expect("request one"); - request_tx.send(vec![b'R']).await.expect("request two"); - drop(control_tx); - drop(request_tx); - - let writer = tokio::spawn(run_writer(client, control_rx, request_rx)); - let mut output = [0u8; 4]; - server.read_exact(&mut output).await.expect("read output"); - writer.await.expect("writer task"); - - assert_eq!(output, [b'c', b'r', b'C', b'R']); - } -} diff --git a/crates/secure-exec-client/src/wire.rs b/crates/secure-exec-client/src/wire.rs deleted file mode 100644 index 6f0577807..000000000 --- a/crates/secure-exec-client/src/wire.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Raw generated Secure Exec sidecar protocol types and BARE frame helpers. - -pub use secure_exec_sidecar_protocol::wire::*; diff --git a/crates/secure-exec-client/tests/wire_protocol.rs b/crates/secure-exec-client/tests/wire_protocol.rs deleted file mode 100644 index 0054fddd3..000000000 --- a/crates/secure-exec-client/tests/wire_protocol.rs +++ /dev/null @@ -1,66 +0,0 @@ -use secure_exec_client::wire::{ - self, AuthenticateRequest, ConnectionOwnership, OwnershipScope, ProtocolFrame, RequestFrame, - RequestPayload, WireFrameCodec, -}; -use secure_exec_client::ProtocolCodecError; - -#[test] -fn generated_wire_frame_codec_round_trips_authenticate() { - let frame = authenticate_frame(); - let codec = WireFrameCodec::default(); - - let encoded = codec.encode(&frame).expect("encode generated wire frame"); - let declared = u32::from_be_bytes(encoded[..4].try_into().expect("length prefix")); - assert_eq!(declared as usize, encoded.len() - 4); - - let decoded = codec.decode(&encoded).expect("decode generated wire frame"); - - assert_eq!(decoded, frame); -} - -#[test] -fn generated_wire_frame_codec_rejects_oversized_payloads() { - let frame = authenticate_frame(); - let codec = WireFrameCodec::new(8); - - let error = codec.encode(&frame).expect_err("oversized frame must fail"); - - assert!(matches!( - error, - ProtocolCodecError::FrameTooLarge { size, max: 8 } if size > 8 - )); -} - -#[test] -fn generated_wire_frame_codec_rejects_schema_mismatches() { - let mut frame = authenticate_frame(); - let ProtocolFrame::RequestFrame(request) = &mut frame else { - unreachable!("authenticate frame is a request") - }; - request.schema.version = wire::PROTOCOL_VERSION + 1; - - let error = WireFrameCodec::default() - .encode(&frame) - .expect_err("schema mismatch must fail"); - - assert!(matches!( - error, - ProtocolCodecError::UnsupportedSchema { version, .. } if version == wire::PROTOCOL_VERSION + 1 - )); -} - -fn authenticate_frame() -> ProtocolFrame { - ProtocolFrame::RequestFrame(RequestFrame { - schema: wire::protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: "conn-1".to_string(), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: "secure-exec-client-test".to_string(), - auth_token: "token".to_string(), - protocol_version: wire::PROTOCOL_VERSION, - bridge_version: 1, - }), - }) -} diff --git a/crates/secure-exec-vfs/AGENTS.md b/crates/secure-exec-vfs/AGENTS.md deleted file mode 120000 index 681311eb9..000000000 --- a/crates/secure-exec-vfs/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/crates/secure-exec-vfs/CLAUDE.md b/crates/secure-exec-vfs/CLAUDE.md deleted file mode 100644 index ffc47d114..000000000 --- a/crates/secure-exec-vfs/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -# secure-exec-vfs - -- `secure-exec-vfs` contains concrete backend adapters for secure-exec deployments: S3, host-disk metadata/block stores, and bridge/callback-backed stores. -- Keep policy decisions, trusted configuration validation, mount descriptor parsing, and sidecar lifecycle wiring in the sidecar plugin layer. -- Generic filesystem algorithms and in-memory stores belong in `vfs`. diff --git a/crates/secure-exec-vfs/Cargo.toml b/crates/secure-exec-vfs/Cargo.toml deleted file mode 100644 index 71fa222c5..000000000 --- a/crates/secure-exec-vfs/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "secure-exec-vfs" -version.workspace = true -edition.workspace = true -license.workspace = true -repository.workspace = true -description = "Secure Exec virtual filesystem backends" - -[dependencies] -async-trait = "0.1" -aws-sdk-s3 = "1" -rusqlite = { version = "0.32", features = ["bundled"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -vfs = { workspace = true } - -[dev-dependencies] -aws-config = "1" -aws-credential-types = "1" -tempfile = "3" -tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] } diff --git a/crates/secure-exec-vfs/src/callback_store.rs b/crates/secure-exec-vfs/src/callback_store.rs deleted file mode 100644 index 7f0d0a505..000000000 --- a/crates/secure-exec-vfs/src/callback_store.rs +++ /dev/null @@ -1,588 +0,0 @@ -use async_trait::async_trait; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::time::Duration; -use vfs::engine::{ - BlockKey, ChunkEdit, ChunkRange, ChunkRef, CreateInodeAttrs, DentryStat, InodeMeta, InodePatch, - MetadataStore, SnapshotId, VfsError, VfsResult, -}; - -pub const VFS_METADATA_EXT_NAMESPACE: &str = "secure-exec.vfs.metadata.v1"; -const CALLBACK_METADATA_TIMEOUT: Duration = Duration::from_secs(30); - -pub trait CallbackMetadataClient: Clone + Send + Sync + 'static { - type Ownership: Clone + Send + Sync + 'static; - type Error: fmt::Display; - - fn invoke_metadata_callback( - &self, - ownership: Self::Ownership, - namespace: &str, - payload: Vec, - timeout: Duration, - ) -> Result<(String, Vec), Self::Error>; -} - -#[derive(Clone)] -pub struct CallbackMetadataStore -where - C: CallbackMetadataClient, -{ - requests: C, - ownership: C::Ownership, - mount_id: String, -} - -impl CallbackMetadataStore -where - C: CallbackMetadataClient, -{ - pub fn new(requests: C, ownership: C::Ownership, mount_id: String) -> Self { - Self { - requests, - ownership, - mount_id, - } - } - - fn invoke(&self, method: MetadataCallbackMethod) -> VfsResult { - let request = MetadataCallbackRequest { - mount_id: self.mount_id.clone(), - method, - }; - let payload = serde_json::to_vec(&request).map_err(|error| { - VfsError::eio(format!( - "encode vfs metadata callback request for mount '{}': {error}", - self.mount_id - )) - })?; - let (namespace, payload) = self - .requests - .invoke_metadata_callback( - self.ownership.clone(), - VFS_METADATA_EXT_NAMESPACE, - payload, - CALLBACK_METADATA_TIMEOUT, - ) - .map_err(Self::sidecar_error_to_vfs)?; - if namespace != VFS_METADATA_EXT_NAMESPACE { - return Err(VfsError::eio(format!( - "unexpected vfs metadata callback namespace '{namespace}'" - ))); - } - let response: MetadataCallbackResponse = - serde_json::from_slice(&payload).map_err(|error| { - VfsError::eio(format!( - "decode vfs metadata callback response for mount '{}': {error}", - self.mount_id - )) - })?; - if let MetadataCallbackResponse::Err { code, message } = &response { - return Err(VfsError::new(code_from_string(code), message.clone())); - } - Ok(response) - } - - fn sidecar_error_to_vfs(error: C::Error) -> VfsError { - VfsError::eio(error.to_string()) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct MetadataCallbackRequest { - pub mount_id: String, - pub method: MetadataCallbackMethod, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "type", rename_all = "camelCase")] -pub enum MetadataCallbackMethod { - Resolve { - path: String, - }, - ResolveParent { - path: String, - }, - Lstat { - path: String, - }, - ListDir { - ino: u64, - }, - Create { - parent: u64, - name: String, - attrs: CreateInodeAttrs, - }, - Link { - parent: u64, - name: String, - target: u64, - }, - Remove { - parent: u64, - name: String, - }, - Rename { - src_parent: u64, - src: String, - dst_parent: u64, - dst: String, - }, - SetAttr { - ino: u64, - patch: InodePatch, - }, - CommitWrite { - ino: u64, - edits: Vec, - new_size: u64, - }, - GetChunks { - ino: u64, - range: ChunkRange, - }, - Snapshot { - root: u64, - }, - Fork { - snap: SnapshotId, - }, - Gc, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "type", rename_all = "camelCase")] -pub enum MetadataCallbackResponse { - InodeMeta { meta: InodeMeta }, - ResolveParent { parent: InodeMeta, name: String }, - DentryStats { entries: Vec }, - Unit, - BlockKeys { keys: Vec }, - ChunkRefs { chunks: Vec }, - Snapshot { id: SnapshotId }, - Inode { ino: u64 }, - Err { code: String, message: String }, -} - -#[async_trait] -impl MetadataStore for CallbackMetadataStore -where - C: CallbackMetadataClient, -{ - async fn resolve(&self, path: &str) -> VfsResult { - match self.invoke(MetadataCallbackMethod::Resolve { - path: path.to_owned(), - })? { - MetadataCallbackResponse::InodeMeta { meta } => Ok(meta), - other => Err(unexpected_response("resolve", other)), - } - } - - async fn resolve_parent(&self, path: &str) -> VfsResult<(InodeMeta, String)> { - match self.invoke(MetadataCallbackMethod::ResolveParent { - path: path.to_owned(), - })? { - MetadataCallbackResponse::ResolveParent { parent, name } => Ok((parent, name)), - other => Err(unexpected_response("resolveParent", other)), - } - } - - async fn lstat(&self, path: &str) -> VfsResult { - match self.invoke(MetadataCallbackMethod::Lstat { - path: path.to_owned(), - })? { - MetadataCallbackResponse::InodeMeta { meta } => Ok(meta), - other => Err(unexpected_response("lstat", other)), - } - } - - async fn list_dir(&self, ino: u64) -> VfsResult> { - match self.invoke(MetadataCallbackMethod::ListDir { ino })? { - MetadataCallbackResponse::DentryStats { entries } => Ok(entries), - other => Err(unexpected_response("listDir", other)), - } - } - - async fn create( - &self, - parent: u64, - name: &str, - attrs: CreateInodeAttrs, - ) -> VfsResult { - match self.invoke(MetadataCallbackMethod::Create { - parent, - name: name.to_owned(), - attrs, - })? { - MetadataCallbackResponse::InodeMeta { meta } => Ok(meta), - other => Err(unexpected_response("create", other)), - } - } - - async fn link(&self, parent: u64, name: &str, target: u64) -> VfsResult<()> { - match self.invoke(MetadataCallbackMethod::Link { - parent, - name: name.to_owned(), - target, - })? { - MetadataCallbackResponse::Unit => Ok(()), - other => Err(unexpected_response("link", other)), - } - } - - async fn remove(&self, parent: u64, name: &str) -> VfsResult> { - match self.invoke(MetadataCallbackMethod::Remove { - parent, - name: name.to_owned(), - })? { - MetadataCallbackResponse::BlockKeys { keys } => Ok(keys), - other => Err(unexpected_response("remove", other)), - } - } - - async fn rename( - &self, - src_parent: u64, - src: &str, - dst_parent: u64, - dst: &str, - ) -> VfsResult> { - match self.invoke(MetadataCallbackMethod::Rename { - src_parent, - src: src.to_owned(), - dst_parent, - dst: dst.to_owned(), - })? { - MetadataCallbackResponse::BlockKeys { keys } => Ok(keys), - other => Err(unexpected_response("rename", other)), - } - } - - async fn set_attr(&self, ino: u64, patch: InodePatch) -> VfsResult> { - match self.invoke(MetadataCallbackMethod::SetAttr { ino, patch })? { - MetadataCallbackResponse::BlockKeys { keys } => Ok(keys), - other => Err(unexpected_response("setAttr", other)), - } - } - - async fn commit_write( - &self, - ino: u64, - edits: Vec, - new_size: u64, - ) -> VfsResult> { - match self.invoke(MetadataCallbackMethod::CommitWrite { - ino, - edits, - new_size, - })? { - MetadataCallbackResponse::BlockKeys { keys } => Ok(keys), - other => Err(unexpected_response("commitWrite", other)), - } - } - - async fn get_chunks(&self, ino: u64, range: ChunkRange) -> VfsResult> { - match self.invoke(MetadataCallbackMethod::GetChunks { ino, range })? { - MetadataCallbackResponse::ChunkRefs { chunks } => Ok(chunks), - other => Err(unexpected_response("getChunks", other)), - } - } - - async fn snapshot(&self, root: u64) -> VfsResult { - match self.invoke(MetadataCallbackMethod::Snapshot { root })? { - MetadataCallbackResponse::Snapshot { id } => Ok(id), - other => Err(unexpected_response("snapshot", other)), - } - } - - async fn fork(&self, snap: SnapshotId) -> VfsResult { - match self.invoke(MetadataCallbackMethod::Fork { snap })? { - MetadataCallbackResponse::Inode { ino } => Ok(ino), - other => Err(unexpected_response("fork", other)), - } - } - - async fn gc(&self) -> VfsResult> { - match self.invoke(MetadataCallbackMethod::Gc)? { - MetadataCallbackResponse::BlockKeys { keys } => Ok(keys), - other => Err(unexpected_response("gc", other)), - } - } -} - -fn unexpected_response(method: &str, response: MetadataCallbackResponse) -> VfsError { - VfsError::eio(format!( - "unexpected vfs metadata callback response for {method}: {response:?}" - )) -} - -fn code_from_string(code: &str) -> &'static str { - match code { - "ENOENT" => "ENOENT", - "EEXIST" => "EEXIST", - "ENOTDIR" => "ENOTDIR", - "EISDIR" => "EISDIR", - "ELOOP" => "ELOOP", - "ENAMETOOLONG" => "ENAMETOOLONG", - "ENOTEMPTY" => "ENOTEMPTY", - "EOPNOTSUPP" => "EOPNOTSUPP", - "EROFS" => "EROFS", - "EINVAL" => "EINVAL", - "EACCES" => "EACCES", - "EPERM" => "EPERM", - "ENOSYS" => "ENOSYS", - _ => "EIO", - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::sync::{Arc, Mutex}; - use vfs::engine::engines::{ChunkedFs, ChunkedFsOptions}; - use vfs::engine::mem::{InMemoryMetadataStore, MemoryBlockStore}; - use vfs::engine::{InodeType, MetadataStore, Storage, Timespec, VirtualFileSystem}; - - #[derive(Default)] - struct RecordingMetadataTransport { - requests: Mutex>, - } - - impl CallbackMetadataClient for Arc { - type Ownership = String; - type Error = String; - - fn invoke_metadata_callback( - &self, - _ownership: Self::Ownership, - namespace: &str, - payload: Vec, - _timeout: Duration, - ) -> Result<(String, Vec), Self::Error> { - assert_eq!(namespace, VFS_METADATA_EXT_NAMESPACE); - let callback_request: MetadataCallbackRequest = - serde_json::from_slice(&payload).expect("decode metadata callback"); - self.requests - .lock() - .expect("lock request log") - .push(callback_request); - - let now = Timespec { sec: 1, nsec: 2 }; - let response = MetadataCallbackResponse::InodeMeta { - meta: InodeMeta { - ino: 7, - kind: InodeType::File, - mode: 0o644, - uid: 1000, - gid: 1000, - size: 5, - nlink: 1, - atime: now, - mtime: now, - ctime: now, - birthtime: now, - storage: Storage::Inline(b"hello".to_vec()), - symlink_target: None, - }, - }; - let payload = serde_json::to_vec(&response).expect("encode metadata callback response"); - Ok((VFS_METADATA_EXT_NAMESPACE.to_string(), payload)) - } - } - - #[tokio::test] - async fn callback_metadata_store_sends_typed_ext_requests() { - let transport = Arc::new(RecordingMetadataTransport::default()); - let store = CallbackMetadataStore::new( - transport.clone(), - "vm-owner".to_string(), - "mount-a".to_string(), - ); - - let meta = store - .resolve("/file.txt") - .await - .expect("resolve via callback"); - assert_eq!(meta.ino, 7); - assert_eq!(meta.storage, Storage::Inline(b"hello".to_vec())); - - let requests = transport.requests.lock().expect("lock request log"); - assert_eq!(requests.len(), 1); - assert_eq!(requests[0].mount_id, "mount-a"); - match &requests[0].method { - MetadataCallbackMethod::Resolve { path } => assert_eq!(path, "/file.txt"), - other => panic!("unexpected method: {other:?}"), - } - } - - #[derive(Default)] - struct DelegatingMetadataTransport { - inner: InMemoryMetadataStore, - methods: Mutex>, - } - - impl CallbackMetadataClient for Arc { - type Ownership = String; - type Error = String; - - fn invoke_metadata_callback( - &self, - _ownership: Self::Ownership, - namespace: &str, - payload: Vec, - _timeout: Duration, - ) -> Result<(String, Vec), Self::Error> { - assert_eq!(namespace, VFS_METADATA_EXT_NAMESPACE); - let request: MetadataCallbackRequest = - serde_json::from_slice(&payload).map_err(|err| err.to_string())?; - let inner = self.inner.clone(); - let response = std::thread::spawn(move || { - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .map_err(|err| err.to_string())?; - runtime.block_on(handle_metadata_callback(inner, request.method)) - }) - .join() - .map_err(|_| "metadata callback thread panicked".to_string())??; - self.methods - .lock() - .expect("lock method log") - .push(method_name(&response)); - let payload = serde_json::to_vec(&response).map_err(|err| err.to_string())?; - Ok((VFS_METADATA_EXT_NAMESPACE.to_string(), payload)) - } - } - - async fn handle_metadata_callback( - inner: InMemoryMetadataStore, - method: MetadataCallbackMethod, - ) -> Result { - let result = match method { - MetadataCallbackMethod::Resolve { path } => inner - .resolve(&path) - .await - .map(|meta| MetadataCallbackResponse::InodeMeta { meta }), - MetadataCallbackMethod::ResolveParent { path } => inner - .resolve_parent(&path) - .await - .map(|(parent, name)| MetadataCallbackResponse::ResolveParent { parent, name }), - MetadataCallbackMethod::Lstat { path } => inner - .lstat(&path) - .await - .map(|meta| MetadataCallbackResponse::InodeMeta { meta }), - MetadataCallbackMethod::ListDir { ino } => inner - .list_dir(ino) - .await - .map(|entries| MetadataCallbackResponse::DentryStats { entries }), - MetadataCallbackMethod::Create { - parent, - name, - attrs, - } => inner - .create(parent, &name, attrs) - .await - .map(|meta| MetadataCallbackResponse::InodeMeta { meta }), - MetadataCallbackMethod::Link { - parent, - name, - target, - } => inner - .link(parent, &name, target) - .await - .map(|()| MetadataCallbackResponse::Unit), - MetadataCallbackMethod::Remove { parent, name } => inner - .remove(parent, &name) - .await - .map(|keys| MetadataCallbackResponse::BlockKeys { keys }), - MetadataCallbackMethod::Rename { - src_parent, - src, - dst_parent, - dst, - } => inner - .rename(src_parent, &src, dst_parent, &dst) - .await - .map(|keys| MetadataCallbackResponse::BlockKeys { keys }), - MetadataCallbackMethod::SetAttr { ino, patch } => inner - .set_attr(ino, patch) - .await - .map(|keys| MetadataCallbackResponse::BlockKeys { keys }), - MetadataCallbackMethod::CommitWrite { - ino, - edits, - new_size, - } => inner - .commit_write(ino, edits, new_size) - .await - .map(|keys| MetadataCallbackResponse::BlockKeys { keys }), - MetadataCallbackMethod::GetChunks { ino, range } => inner - .get_chunks(ino, range) - .await - .map(|chunks| MetadataCallbackResponse::ChunkRefs { chunks }), - MetadataCallbackMethod::Snapshot { root } => inner - .snapshot(root) - .await - .map(|id| MetadataCallbackResponse::Snapshot { id }), - MetadataCallbackMethod::Fork { snap } => inner - .fork(snap) - .await - .map(|ino| MetadataCallbackResponse::Inode { ino }), - MetadataCallbackMethod::Gc => inner - .gc() - .await - .map(|keys| MetadataCallbackResponse::BlockKeys { keys }), - }; - Ok( - result.unwrap_or_else(|error| MetadataCallbackResponse::Err { - code: error.code().to_string(), - message: error.message().to_string(), - }), - ) - } - - fn method_name(response: &MetadataCallbackResponse) -> &'static str { - match response { - MetadataCallbackResponse::InodeMeta { .. } => "inodeMeta", - MetadataCallbackResponse::ResolveParent { .. } => "resolveParent", - MetadataCallbackResponse::DentryStats { .. } => "dentryStats", - MetadataCallbackResponse::Unit => "unit", - MetadataCallbackResponse::BlockKeys { .. } => "blockKeys", - MetadataCallbackResponse::ChunkRefs { .. } => "chunkRefs", - MetadataCallbackResponse::Snapshot { .. } => "snapshot", - MetadataCallbackResponse::Inode { .. } => "inode", - MetadataCallbackResponse::Err { .. } => "err", - } - } - - #[tokio::test] - async fn callback_metadata_store_drives_chunked_filesystem_round_trip() { - let transport = Arc::new(DelegatingMetadataTransport::default()); - let metadata = CallbackMetadataStore::new( - transport.clone(), - "vm-owner".to_string(), - "mount-a".to_string(), - ); - let fs = ChunkedFs::with_options( - metadata, - MemoryBlockStore::new(), - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - - fs.write_file("/file.txt", b"abcdefgh").await.unwrap(); - fs.pwrite("/file.txt", b"YY", 2).await.unwrap(); - assert_eq!(fs.read_file("/file.txt").await.unwrap(), b"abYYefgh"); - fs.truncate("/file.txt", 5).await.unwrap(); - assert_eq!(fs.read_file("/file.txt").await.unwrap(), b"abYYe"); - - let methods = transport.methods.lock().expect("lock method log"); - assert!(methods.contains(&"blockKeys")); - assert!(methods.contains(&"chunkRefs")); - } -} diff --git a/crates/secure-exec-vfs/src/lib.rs b/crates/secure-exec-vfs/src/lib.rs deleted file mode 100644 index ccf59b99b..000000000 --- a/crates/secure-exec-vfs/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![forbid(unsafe_code)] - -pub mod callback_store; -pub mod local; -pub mod s3; - -pub use callback_store::{CallbackMetadataClient, CallbackMetadataStore}; -pub use local::{FileBlockStore, SqliteMetadataStore}; -pub use s3::{S3BlockStore, S3BlockStoreOptions, S3ObjectBackend, S3ObjectBackendOptions}; diff --git a/crates/secure-exec-vfs/src/local/file_block_store.rs b/crates/secure-exec-vfs/src/local/file_block_store.rs deleted file mode 100644 index b4296c3c5..000000000 --- a/crates/secure-exec-vfs/src/local/file_block_store.rs +++ /dev/null @@ -1,109 +0,0 @@ -use async_trait::async_trait; -use std::fs; -use std::path::{Path, PathBuf}; -use vfs::engine::block::BlockStore; -use vfs::engine::error::{VfsError, VfsResult}; -use vfs::engine::types::BlockKey; - -#[derive(Debug, Clone)] -pub struct FileBlockStore { - root: PathBuf, -} - -impl FileBlockStore { - pub fn new(root: impl Into) -> VfsResult { - let root = root.into(); - fs::create_dir_all(&root) - .map_err(|err| VfsError::eio(format!("create block root {}: {err}", root.display())))?; - Ok(Self { root }) - } - - fn path_for(&self, key: &BlockKey) -> PathBuf { - let (prefix, suffix) = key.0.split_at(key.0.len().min(2)); - self.root.join(prefix).join(suffix) - } - - fn ensure_safe_key(key: &BlockKey) -> VfsResult<()> { - if key.0.contains('/') || key.0.contains('\\') || key.0 == "." || key.0 == ".." { - return Err(VfsError::einval(format!("unsafe block key: {}", key.0))); - } - Ok(()) - } - - pub fn root(&self) -> &Path { - &self.root - } -} - -#[async_trait] -impl BlockStore for FileBlockStore { - async fn get(&self, key: &BlockKey) -> VfsResult> { - Self::ensure_safe_key(key)?; - let path = self.path_for(key); - fs::read(&path).map_err(|err| { - if err.kind() == std::io::ErrorKind::NotFound { - VfsError::enoent(&key.0) - } else { - VfsError::eio(format!("read block {}: {err}", path.display())) - } - }) - } - - async fn get_range(&self, key: &BlockKey, off: u64, len: u64) -> VfsResult> { - let data = self.get(key).await?; - let start = usize::try_from(off) - .map_err(|_| VfsError::einval(format!("range offset is too large: {off}")))?; - let len = usize::try_from(len) - .map_err(|_| VfsError::einval(format!("range length is too large: {len}")))?; - if start >= data.len() { - return Ok(Vec::new()); - } - let end = start.saturating_add(len).min(data.len()); - Ok(data[start..end].to_vec()) - } - - async fn put(&self, key: &BlockKey, data: &[u8]) -> VfsResult<()> { - Self::ensure_safe_key(key)?; - let path = self.path_for(key); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent) - .map_err(|err| VfsError::eio(format!("create block dir: {err}")))?; - } - fs::write(&path, data) - .map_err(|err| VfsError::eio(format!("write block {}: {err}", path.display()))) - } - - async fn exists(&self, key: &BlockKey) -> VfsResult { - Self::ensure_safe_key(key)?; - Ok(self.path_for(key).exists()) - } - - async fn delete_many(&self, keys: &[BlockKey]) -> VfsResult<()> { - let mut errors = Vec::new(); - for key in keys { - if let Err(error) = Self::ensure_safe_key(key) { - errors.push(error.to_string()); - continue; - } - match fs::remove_file(self.path_for(key)) { - Ok(()) => {} - Err(err) if err.kind() == std::io::ErrorKind::NotFound => {} - Err(err) => errors.push(format!("delete block {}: {err}", key.0)), - } - } - if errors.is_empty() { - Ok(()) - } else { - Err(VfsError::eio(format!( - "delete {} local blocks failed: {}", - errors.len(), - errors.join("; ") - ))) - } - } - - async fn copy(&self, src: &BlockKey, dst: &BlockKey) -> VfsResult<()> { - let data = self.get(src).await?; - self.put(dst, &data).await - } -} diff --git a/crates/secure-exec-vfs/src/local/mod.rs b/crates/secure-exec-vfs/src/local/mod.rs deleted file mode 100644 index 869cdf405..000000000 --- a/crates/secure-exec-vfs/src/local/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod file_block_store; -mod sqlite_metadata_store; - -pub use file_block_store::FileBlockStore; -pub use sqlite_metadata_store::SqliteMetadataStore; diff --git a/crates/secure-exec-vfs/src/local/sqlite_metadata_store.rs b/crates/secure-exec-vfs/src/local/sqlite_metadata_store.rs deleted file mode 100644 index 64e1eae9b..000000000 --- a/crates/secure-exec-vfs/src/local/sqlite_metadata_store.rs +++ /dev/null @@ -1,438 +0,0 @@ -use async_trait::async_trait; -use rusqlite::{params, Connection}; -use std::collections::BTreeMap; -use std::path::Path; -use std::sync::Mutex; -use vfs::engine::error::{VfsError, VfsResult}; -use vfs::engine::mem::metadata_store::MetadataDump; -use vfs::engine::mem::InMemoryMetadataStore; -use vfs::engine::metadata::MetadataStore; -use vfs::engine::types::{ - BlockKey, ChunkEdit, ChunkRange, ChunkRef, CreateInodeAttrs, DentryStat, InodeMeta, InodePatch, - InodeType, SnapshotId, Storage, Timespec, DEFAULT_CHUNK_SIZE, -}; - -pub struct SqliteMetadataStore { - connection: Mutex, - inner: InMemoryMetadataStore, -} - -impl SqliteMetadataStore { - pub fn open(path: impl AsRef) -> VfsResult { - let connection = Connection::open(path) - .map_err(|err| VfsError::eio(format!("open SQLite metadata store: {err}")))?; - Self::from_connection(connection) - } - - pub fn in_memory() -> VfsResult { - let connection = Connection::open_in_memory() - .map_err(|err| VfsError::eio(format!("open in-memory SQLite metadata store: {err}")))?; - Self::from_connection(connection) - } - - fn from_connection(mut connection: Connection) -> VfsResult { - install_schema(&connection)?; - let dump = load_dump(&connection)?; - let inner = dump - .map(InMemoryMetadataStore::from_dump) - .unwrap_or_default(); - if load_dump(&connection)?.is_none() { - persist_dump(&mut connection, &inner.dump())?; - } - Ok(Self { - connection: Mutex::new(connection), - inner, - }) - } - - pub fn has_schema(&self) -> VfsResult { - let connection = self.connection.lock().expect("sqlite mutex poisoned"); - let count: i64 = connection - .query_row( - "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name IN ('inodes', 'dentries', 'chunks', 'block_refs', 'snapshots')", - [], - |row| row.get(0), - ) - .map_err(|err| VfsError::eio(format!("inspect SQLite schema: {err}")))?; - Ok(count == 5) - } - - fn persist(&self) -> VfsResult<()> { - let dump = self.inner.dump(); - let mut connection = self.connection.lock().expect("sqlite mutex poisoned"); - persist_dump(&mut connection, &dump) - } -} - -fn install_schema(connection: &Connection) -> VfsResult<()> { - connection - .execute_batch( - " - CREATE TABLE IF NOT EXISTS inodes ( - ino INTEGER PRIMARY KEY, - kind INTEGER NOT NULL, - mode INTEGER NOT NULL, - uid INTEGER NOT NULL, - gid INTEGER NOT NULL, - size INTEGER NOT NULL, - nlink INTEGER NOT NULL, - atime_ns INTEGER NOT NULL, mtime_ns INTEGER NOT NULL, - ctime_ns INTEGER NOT NULL, birthtime_ns INTEGER NOT NULL, - storage_mode INTEGER NOT NULL, - storage_chunk_size INTEGER, - inline_content BLOB, - symlink_target TEXT - ); - CREATE TABLE IF NOT EXISTS dentries ( - parent_ino INTEGER NOT NULL, - name TEXT NOT NULL, - child_ino INTEGER NOT NULL, - kind INTEGER NOT NULL, - PRIMARY KEY (parent_ino, name) - ); - CREATE INDEX IF NOT EXISTS dentries_parent ON dentries(parent_ino); - CREATE TABLE IF NOT EXISTS chunks ( - ino INTEGER NOT NULL, - chunk_index INTEGER NOT NULL, - block_key TEXT NOT NULL, - len INTEGER NOT NULL, - PRIMARY KEY (ino, chunk_index) - ); - CREATE TABLE IF NOT EXISTS block_refs ( - block_key TEXT PRIMARY KEY, - refcount INTEGER NOT NULL - ); - CREATE TABLE IF NOT EXISTS snapshots ( - snapshot_id INTEGER PRIMARY KEY, - root_ino INTEGER NOT NULL, - created_ns INTEGER NOT NULL - ); - ", - ) - .map_err(|err| VfsError::eio(format!("install SQLite metadata schema: {err}"))) -} - -fn load_dump(connection: &Connection) -> VfsResult> { - let inode_count: i64 = connection - .query_row("SELECT COUNT(*) FROM inodes", [], |row| row.get(0)) - .map_err(|err| VfsError::eio(format!("count SQLite inodes: {err}")))?; - if inode_count == 0 { - return Ok(None); - } - - let mut inodes = BTreeMap::new(); - let mut next_ino = 1; - let mut statement = connection - .prepare( - "SELECT ino, kind, mode, uid, gid, size, nlink, atime_ns, mtime_ns, ctime_ns, - birthtime_ns, storage_mode, storage_chunk_size, inline_content, symlink_target - FROM inodes", - ) - .map_err(|err| VfsError::eio(format!("prepare inode load: {err}")))?; - let rows = statement - .query_map([], |row| { - let ino: u64 = row.get(0)?; - let kind_id: i64 = row.get(1)?; - let storage_id: i64 = row.get(11)?; - let chunk_size: Option = row.get(12)?; - let inline_content: Option> = row.get(13)?; - let symlink_target: Option = row.get(14)?; - let kind = match kind_id { - 0 => InodeType::File, - 1 => InodeType::Directory, - _ => InodeType::Symlink, - }; - let storage = match storage_id { - 1 => Storage::Inline(inline_content.unwrap_or_default()), - 2 => Storage::Chunked { - chunk_size: chunk_size.unwrap_or(DEFAULT_CHUNK_SIZE), - }, - _ => Storage::None, - }; - Ok(InodeMeta { - ino, - kind, - mode: row.get(2)?, - uid: row.get(3)?, - gid: row.get(4)?, - size: row.get(5)?, - nlink: row.get(6)?, - atime: ns_to_timespec(row.get(7)?), - mtime: ns_to_timespec(row.get(8)?), - ctime: ns_to_timespec(row.get(9)?), - birthtime: ns_to_timespec(row.get(10)?), - storage, - symlink_target, - }) - }) - .map_err(|err| VfsError::eio(format!("load SQLite inodes: {err}")))?; - for row in rows { - let meta = row.map_err(|err| VfsError::eio(format!("load SQLite inode row: {err}")))?; - next_ino = next_ino.max(meta.ino + 1); - inodes.insert(meta.ino, meta); - } - - let mut dentries = BTreeMap::new(); - let mut statement = connection - .prepare("SELECT parent_ino, name, child_ino FROM dentries") - .map_err(|err| VfsError::eio(format!("prepare dentry load: {err}")))?; - let rows = statement - .query_map([], |row| { - Ok(( - (row.get::<_, u64>(0)?, row.get::<_, String>(1)?), - row.get::<_, u64>(2)?, - )) - }) - .map_err(|err| VfsError::eio(format!("load SQLite dentries: {err}")))?; - for row in rows { - let (key, value) = - row.map_err(|err| VfsError::eio(format!("load SQLite dentry row: {err}")))?; - dentries.insert(key, value); - } - - let mut chunks = BTreeMap::new(); - let mut statement = connection - .prepare("SELECT ino, chunk_index, block_key, len FROM chunks") - .map_err(|err| VfsError::eio(format!("prepare chunk load: {err}")))?; - let rows = statement - .query_map([], |row| { - let index = row.get::<_, u64>(1)?; - Ok(( - (row.get::<_, u64>(0)?, index), - ChunkRef { - index, - key: BlockKey(row.get(2)?), - len: row.get(3)?, - }, - )) - }) - .map_err(|err| VfsError::eio(format!("load SQLite chunks: {err}")))?; - for row in rows { - let (key, value) = - row.map_err(|err| VfsError::eio(format!("load SQLite chunk row: {err}")))?; - chunks.insert(key, value); - } - - let mut block_refs = BTreeMap::new(); - let mut statement = connection - .prepare("SELECT block_key, refcount FROM block_refs") - .map_err(|err| VfsError::eio(format!("prepare block ref load: {err}")))?; - let rows = statement - .query_map([], |row| Ok((BlockKey(row.get(0)?), row.get::<_, u64>(1)?))) - .map_err(|err| VfsError::eio(format!("load SQLite block refs: {err}")))?; - for row in rows { - let (key, value) = - row.map_err(|err| VfsError::eio(format!("load SQLite block ref row: {err}")))?; - block_refs.insert(key, value); - } - - Ok(Some(MetadataDump { - next_ino, - inodes, - dentries, - chunks, - block_refs, - })) -} - -fn persist_dump(connection: &mut Connection, dump: &MetadataDump) -> VfsResult<()> { - let tx = connection - .transaction() - .map_err(|err| VfsError::eio(format!("begin SQLite metadata transaction: {err}")))?; - tx.execute_batch( - " - DELETE FROM snapshots; - DELETE FROM block_refs; - DELETE FROM chunks; - DELETE FROM dentries; - DELETE FROM inodes; - ", - ) - .map_err(|err| VfsError::eio(format!("clear SQLite metadata tables: {err}")))?; - - for meta in dump.inodes.values() { - let (storage_mode, storage_chunk_size, inline_content) = match &meta.storage { - Storage::None => (0, None, None), - Storage::Inline(data) => (1, None, Some(data.as_slice())), - Storage::Chunked { chunk_size } => (2, Some(*chunk_size), None), - }; - tx.execute( - "INSERT INTO inodes - (ino, kind, mode, uid, gid, size, nlink, atime_ns, mtime_ns, ctime_ns, birthtime_ns, - storage_mode, storage_chunk_size, inline_content, symlink_target) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - params![ - meta.ino, - kind_id(meta.kind), - meta.mode, - meta.uid, - meta.gid, - meta.size, - meta.nlink, - timespec_to_ns(meta.atime), - timespec_to_ns(meta.mtime), - timespec_to_ns(meta.ctime), - timespec_to_ns(meta.birthtime), - storage_mode, - storage_chunk_size, - inline_content, - meta.symlink_target, - ], - ) - .map_err(|err| VfsError::eio(format!("persist SQLite inode {}: {err}", meta.ino)))?; - } - - for ((parent, name), child) in &dump.dentries { - let kind = dump - .inodes - .get(child) - .map(|meta| meta.kind) - .ok_or_else(|| VfsError::eio(format!("dentry points to missing inode {child}")))?; - tx.execute( - "INSERT INTO dentries (parent_ino, name, child_ino, kind) VALUES (?, ?, ?, ?)", - params![parent, name, child, kind_id(kind)], - ) - .map_err(|err| VfsError::eio(format!("persist SQLite dentry {name}: {err}")))?; - } - - for ((ino, index), chunk) in &dump.chunks { - tx.execute( - "INSERT INTO chunks (ino, chunk_index, block_key, len) VALUES (?, ?, ?, ?)", - params![ino, index, chunk.key.0, chunk.len], - ) - .map_err(|err| VfsError::eio(format!("persist SQLite chunk {ino}/{index}: {err}")))?; - } - - for (key, refcount) in &dump.block_refs { - tx.execute( - "INSERT INTO block_refs (block_key, refcount) VALUES (?, ?)", - params![key.0, refcount], - ) - .map_err(|err| VfsError::eio(format!("persist SQLite block ref {}: {err}", key.0)))?; - } - - tx.commit() - .map_err(|err| VfsError::eio(format!("commit SQLite metadata transaction: {err}"))) -} - -fn kind_id(kind: InodeType) -> i64 { - match kind { - InodeType::File => 0, - InodeType::Directory => 1, - InodeType::Symlink => 2, - } -} - -fn timespec_to_ns(time: Timespec) -> i64 { - time.sec.saturating_mul(1_000_000_000) + i64::from(time.nsec) -} - -fn ns_to_timespec(ns: i64) -> Timespec { - Timespec { - sec: ns / 1_000_000_000, - nsec: ns.rem_euclid(1_000_000_000) as u32, - } -} - -#[async_trait] -impl MetadataStore for SqliteMetadataStore { - async fn resolve(&self, path: &str) -> VfsResult { - self.inner.resolve(path).await - } - - async fn resolve_parent(&self, path: &str) -> VfsResult<(InodeMeta, String)> { - self.inner.resolve_parent(path).await - } - - async fn lstat(&self, path: &str) -> VfsResult { - self.inner.lstat(path).await - } - - async fn list_dir(&self, ino: u64) -> VfsResult> { - self.inner.list_dir(ino).await - } - - async fn create( - &self, - parent: u64, - name: &str, - attrs: CreateInodeAttrs, - ) -> VfsResult { - let result = self.inner.create(parent, name, attrs).await; - if result.is_ok() { - self.persist()?; - } - result - } - - async fn link(&self, parent: u64, name: &str, target: u64) -> VfsResult<()> { - let result = self.inner.link(parent, name, target).await; - if result.is_ok() { - self.persist()?; - } - result - } - - async fn remove(&self, parent: u64, name: &str) -> VfsResult> { - let result = self.inner.remove(parent, name).await; - if result.is_ok() { - self.persist()?; - } - result - } - - async fn rename( - &self, - src_parent: u64, - src: &str, - dst_parent: u64, - dst: &str, - ) -> VfsResult> { - let result = self.inner.rename(src_parent, src, dst_parent, dst).await; - if result.is_ok() { - self.persist()?; - } - result - } - - async fn set_attr(&self, ino: u64, patch: InodePatch) -> VfsResult> { - let result = self.inner.set_attr(ino, patch).await; - if result.is_ok() { - self.persist()?; - } - result - } - - async fn commit_write( - &self, - ino: u64, - edits: Vec, - new_size: u64, - ) -> VfsResult> { - let result = self.inner.commit_write(ino, edits, new_size).await; - if result.is_ok() { - self.persist()?; - } - result - } - - async fn get_chunks(&self, ino: u64, range: ChunkRange) -> VfsResult> { - self.inner.get_chunks(ino, range).await - } - - async fn snapshot(&self, root: u64) -> VfsResult { - self.inner.snapshot(root).await - } - - async fn fork(&self, snap: SnapshotId) -> VfsResult { - let result = self.inner.fork(snap).await; - if result.is_ok() { - self.persist()?; - } - result - } - - async fn gc(&self) -> VfsResult> { - self.inner.gc().await - } -} diff --git a/crates/secure-exec-vfs/src/s3/block_store.rs b/crates/secure-exec-vfs/src/s3/block_store.rs deleted file mode 100644 index 56b096a91..000000000 --- a/crates/secure-exec-vfs/src/s3/block_store.rs +++ /dev/null @@ -1,195 +0,0 @@ -use async_trait::async_trait; -use aws_sdk_s3::primitives::{ByteStream, ByteStreamError}; -use aws_sdk_s3::types::{Delete, ObjectIdentifier}; -use aws_sdk_s3::Client; -use vfs::engine::{BlockKey, BlockStore, VfsError, VfsResult}; - -#[derive(Debug, Clone, Default)] -pub struct S3BlockStoreOptions { - pub prefix: String, -} - -#[derive(Debug, Clone)] -pub struct S3BlockStore { - client: Client, - bucket: String, - options: S3BlockStoreOptions, -} - -impl S3BlockStore { - pub fn new(client: Client, bucket: impl Into) -> Self { - Self::with_options(client, bucket, S3BlockStoreOptions::default()) - } - - pub fn with_options( - client: Client, - bucket: impl Into, - options: S3BlockStoreOptions, - ) -> Self { - Self { - client, - bucket: bucket.into(), - options, - } - } - - fn key_for(&self, key: &BlockKey) -> String { - format!("{}{}", self.options.prefix, key.0) - } -} - -#[async_trait] -impl BlockStore for S3BlockStore { - async fn get(&self, key: &BlockKey) -> VfsResult> { - let object_key = self.key_for(key); - let response = self - .client - .get_object() - .bucket(&self.bucket) - .key(&object_key) - .send() - .await - .map_err(|err| s3_error(format!("get s3 block '{object_key}': {err}")))?; - collect_body(response.body, &object_key).await - } - - async fn get_range(&self, key: &BlockKey, off: u64, len: u64) -> VfsResult> { - if len == 0 { - return Ok(Vec::new()); - } - let object_key = self.key_for(key); - let end = off - .checked_add(len) - .and_then(|value| value.checked_sub(1)) - .ok_or_else(|| VfsError::einval("invalid S3 byte range"))?; - let response = self - .client - .get_object() - .bucket(&self.bucket) - .key(&object_key) - .range(format!("bytes={off}-{end}")) - .send() - .await - .map_err(|err| s3_error(format!("get s3 block range '{object_key}': {err}")))?; - collect_body(response.body, &object_key).await - } - - async fn put(&self, key: &BlockKey, data: &[u8]) -> VfsResult<()> { - let object_key = self.key_for(key); - self.client - .put_object() - .bucket(&self.bucket) - .key(&object_key) - .body(ByteStream::from(data.to_vec())) - .send() - .await - .map_err(|err| s3_error(format!("put s3 block '{object_key}': {err}")))?; - Ok(()) - } - - async fn exists(&self, key: &BlockKey) -> VfsResult { - let object_key = self.key_for(key); - match self - .client - .head_object() - .bucket(&self.bucket) - .key(&object_key) - .send() - .await - { - Ok(_) => Ok(true), - Err(err) - if err.as_service_error().is_some_and(|err| { - err.is_not_found() - || matches!(err.meta().code(), Some("NotFound" | "NoSuchKey")) - }) => - { - Ok(false) - } - Err(err) => Err(s3_error(format!("head s3 block '{object_key}': {err}"))), - } - } - - async fn delete_many(&self, keys: &[BlockKey]) -> VfsResult<()> { - let mut errors = Vec::new(); - for chunk in keys.chunks(1000) { - let mut object_keys = Vec::with_capacity(chunk.len()); - let mut objects = Vec::with_capacity(chunk.len()); - for key in chunk { - let object_key = self.key_for(key); - let object = ObjectIdentifier::builder() - .key(&object_key) - .build() - .map_err(|err| { - s3_error(format!("build s3 delete key '{object_key}': {err}")) - })?; - object_keys.push(object_key); - objects.push(object); - } - let delete = Delete::builder() - .set_objects(Some(objects)) - .quiet(true) - .build() - .map_err(|err| s3_error(format!("build s3 delete batch: {err}")))?; - match self - .client - .delete_objects() - .bucket(&self.bucket) - .delete(delete) - .send() - .await - { - Ok(response) => { - for error in response.errors() { - let key = error.key().unwrap_or(""); - let code = error.code().unwrap_or("unknown"); - let message = error.message().unwrap_or("unknown error"); - errors.push(format!("delete s3 block '{key}': {code}: {message}")); - } - } - Err(err) => errors.push(format!( - "delete s3 block batch [{}]: {err}", - object_keys.join(", ") - )), - } - } - if errors.is_empty() { - Ok(()) - } else { - Err(s3_error(format!( - "delete {} s3 blocks failed: {}", - errors.len(), - errors.join("; ") - ))) - } - } - - async fn copy(&self, src: &BlockKey, dst: &BlockKey) -> VfsResult<()> { - let src_key = self.key_for(src); - let dst_key = self.key_for(dst); - self.client - .copy_object() - .bucket(&self.bucket) - .copy_source(format!("{}/{}", self.bucket, src_key)) - .key(&dst_key) - .send() - .await - .map_err(|err| s3_error(format!("copy s3 block '{src_key}' to '{dst_key}': {err}")))?; - Ok(()) - } -} - -pub(crate) async fn collect_body(body: ByteStream, key: &str) -> VfsResult> { - body.collect() - .await - .map_err(|err| body_error(key, err)) - .map(|bytes| bytes.into_bytes().to_vec()) -} - -pub(crate) fn s3_error(message: impl Into) -> VfsError { - VfsError::eio(message) -} - -fn body_error(key: &str, err: ByteStreamError) -> VfsError { - VfsError::eio(format!("read s3 object '{key}': {err}")) -} diff --git a/crates/secure-exec-vfs/src/s3/mod.rs b/crates/secure-exec-vfs/src/s3/mod.rs deleted file mode 100644 index 68b9f5bf4..000000000 --- a/crates/secure-exec-vfs/src/s3/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod block_store; -mod object_backend; - -pub use block_store::{S3BlockStore, S3BlockStoreOptions}; -pub use object_backend::{S3ObjectBackend, S3ObjectBackendOptions}; diff --git a/crates/secure-exec-vfs/src/s3/object_backend.rs b/crates/secure-exec-vfs/src/s3/object_backend.rs deleted file mode 100644 index 86d215dd6..000000000 --- a/crates/secure-exec-vfs/src/s3/object_backend.rs +++ /dev/null @@ -1,238 +0,0 @@ -use super::block_store::{collect_body, s3_error}; -use async_trait::async_trait; -use aws_sdk_s3::primitives::ByteStream; -use aws_sdk_s3::Client; -use std::collections::HashMap; -use vfs::engine::{InodeType, ObjectBackend, ObjectEntry, ObjectMeta, Timespec, VfsResult}; - -#[derive(Debug, Clone, Default)] -pub struct S3ObjectBackendOptions { - pub prefix: String, -} - -#[derive(Debug, Clone)] -pub struct S3ObjectBackend { - client: Client, - bucket: String, - options: S3ObjectBackendOptions, -} - -impl S3ObjectBackend { - pub fn new(client: Client, bucket: impl Into) -> Self { - Self::with_options(client, bucket, S3ObjectBackendOptions::default()) - } - - pub fn with_options( - client: Client, - bucket: impl Into, - options: S3ObjectBackendOptions, - ) -> Self { - Self { - client, - bucket: bucket.into(), - options, - } - } - - fn key_for(&self, key: &str) -> String { - format!("{}{}", self.options.prefix, key) - } - - fn strip_prefix<'a>(&self, key: &'a str) -> &'a str { - key.strip_prefix(&self.options.prefix).unwrap_or(key) - } -} - -#[async_trait] -impl ObjectBackend for S3ObjectBackend { - async fn list(&self, prefix: &str) -> VfsResult> { - let s3_prefix = self.key_for(prefix); - let mut continuation = None; - let mut entries = Vec::new(); - loop { - let response = self - .client - .list_objects_v2() - .bucket(&self.bucket) - .prefix(&s3_prefix) - .delimiter("/") - .set_continuation_token(continuation) - .send() - .await - .map_err(|err| s3_error(format!("list s3 prefix '{s3_prefix}': {err}")))?; - - for object in response.contents() { - let Some(key) = object.key() else { - continue; - }; - entries.push(ObjectEntry { - name: self.strip_prefix(key).to_string(), - size: object.size().unwrap_or(0).max(0) as u64, - mtime: object - .last_modified() - .map(timespec_from_smithy) - .unwrap_or_else(Timespec::now), - is_prefix: false, - }); - } - - for prefix in response.common_prefixes() { - let Some(prefix) = prefix.prefix() else { - continue; - }; - entries.push(ObjectEntry { - name: self.strip_prefix(prefix).to_string(), - size: 0, - mtime: Timespec::now(), - is_prefix: true, - }); - } - - if response.is_truncated().unwrap_or(false) { - continuation = response.next_continuation_token().map(ToOwned::to_owned); - } else { - break; - } - } - Ok(entries) - } - - async fn head(&self, key: &str) -> VfsResult> { - let s3_key = self.key_for(key); - let response = match self - .client - .head_object() - .bucket(&self.bucket) - .key(&s3_key) - .send() - .await - { - Ok(response) => response, - Err(err) - if err.as_service_error().is_some_and(|err| { - err.is_not_found() - || matches!(err.meta().code(), Some("NotFound" | "NoSuchKey")) - }) => - { - return Ok(None); - } - Err(err) => return Err(s3_error(format!("head s3 object '{s3_key}': {err}"))), - }; - - let metadata = response.metadata(); - let kind = metadata - .and_then(|metadata| metadata.get("vfs-kind")) - .map(|kind| match kind.as_str() { - "directory" => InodeType::Directory, - "symlink" => InodeType::Symlink, - _ => InodeType::File, - }) - .unwrap_or(InodeType::File); - Ok(Some(ObjectMeta { - size: response.content_length().unwrap_or(0).max(0) as u64, - mtime: response - .last_modified() - .map(timespec_from_smithy) - .unwrap_or_else(Timespec::now), - mode: metadata - .and_then(|metadata| metadata.get("vfs-mode")) - .and_then(|mode| u32::from_str_radix(mode, 8).ok()) - .unwrap_or(0o644), - uid: metadata - .and_then(|metadata| metadata.get("vfs-uid")) - .and_then(|uid| uid.parse().ok()) - .unwrap_or(0), - gid: metadata - .and_then(|metadata| metadata.get("vfs-gid")) - .and_then(|gid| gid.parse().ok()) - .unwrap_or(0), - kind, - symlink_target: metadata - .and_then(|metadata| metadata.get("vfs-symlink-target").cloned()), - })) - } - - async fn get_range(&self, key: &str, off: u64, len: u64) -> VfsResult> { - if len == 0 { - return Ok(Vec::new()); - } - let s3_key = self.key_for(key); - let end = off - .checked_add(len) - .and_then(|value| value.checked_sub(1)) - .ok_or_else(|| vfs::engine::VfsError::einval("invalid S3 byte range"))?; - let response = self - .client - .get_object() - .bucket(&self.bucket) - .key(&s3_key) - .range(format!("bytes={off}-{end}")) - .send() - .await - .map_err(|err| s3_error(format!("get s3 object range '{s3_key}': {err}")))?; - collect_body(response.body, &s3_key).await - } - - async fn put(&self, key: &str, data: &[u8], meta: ObjectMeta) -> VfsResult<()> { - let s3_key = self.key_for(key); - let mut metadata = HashMap::new(); - metadata.insert("vfs-kind".to_string(), kind_name(meta.kind).to_string()); - metadata.insert("vfs-mode".to_string(), format!("{:o}", meta.mode)); - metadata.insert("vfs-uid".to_string(), meta.uid.to_string()); - metadata.insert("vfs-gid".to_string(), meta.gid.to_string()); - if let Some(target) = meta.symlink_target { - metadata.insert("vfs-symlink-target".to_string(), target); - } - self.client - .put_object() - .bucket(&self.bucket) - .key(&s3_key) - .body(ByteStream::from(data.to_vec())) - .set_metadata(Some(metadata)) - .send() - .await - .map_err(|err| s3_error(format!("put s3 object '{s3_key}': {err}")))?; - Ok(()) - } - - async fn copy(&self, src: &str, dst: &str) -> VfsResult<()> { - let src_key = self.key_for(src); - let dst_key = self.key_for(dst); - self.client - .copy_object() - .bucket(&self.bucket) - .copy_source(format!("{}/{}", self.bucket, src_key)) - .key(&dst_key) - .send() - .await - .map_err(|err| s3_error(format!("copy s3 object '{src_key}' to '{dst_key}': {err}")))?; - Ok(()) - } - - async fn delete(&self, key: &str) -> VfsResult<()> { - let s3_key = self.key_for(key); - self.client - .delete_object() - .bucket(&self.bucket) - .key(&s3_key) - .send() - .await - .map_err(|err| s3_error(format!("delete s3 object '{s3_key}': {err}")))?; - Ok(()) - } -} - -fn kind_name(kind: InodeType) -> &'static str { - match kind { - InodeType::File => "file", - InodeType::Directory => "directory", - InodeType::Symlink => "symlink", - } -} - -fn timespec_from_smithy(time: &aws_sdk_s3::primitives::DateTime) -> Timespec { - Timespec { - sec: time.secs(), - nsec: 0, - } -} diff --git a/crates/secure-exec-vfs/tests/local.rs b/crates/secure-exec-vfs/tests/local.rs deleted file mode 100644 index 6c9b7ed72..000000000 --- a/crates/secure-exec-vfs/tests/local.rs +++ /dev/null @@ -1,97 +0,0 @@ -use secure_exec_vfs::{FileBlockStore, SqliteMetadataStore}; -use vfs::engine::engines::{ChunkedFs, ChunkedFsOptions}; -use vfs::engine::mem::MemoryBlockStore; -use vfs::engine::{BlockKey, BlockStore, VirtualFileSystem}; - -#[tokio::test] -async fn file_block_store_persists_blocks() { - let temp = tempfile::tempdir().unwrap(); - let store = FileBlockStore::new(temp.path()).unwrap(); - let key = BlockKey::from_content(b"persistent"); - store.put(&key, b"persistent").await.unwrap(); - assert_eq!(store.get(&key).await.unwrap(), b"persistent"); - - let reopened = FileBlockStore::new(temp.path()).unwrap(); - assert_eq!(reopened.get(&key).await.unwrap(), b"persistent"); -} - -#[tokio::test] -async fn sqlite_store_installs_canonical_schema() { - let store = SqliteMetadataStore::in_memory().unwrap(); - assert!(store.has_schema().unwrap()); -} - -#[tokio::test] -async fn sqlite_store_reopens_persisted_metadata() { - let temp = tempfile::tempdir().unwrap(); - let db = temp.path().join("metadata.sqlite"); - let blocks = MemoryBlockStore::new(); - - { - let metadata = SqliteMetadataStore::open(&db).unwrap(); - let fs = ChunkedFs::with_options( - metadata, - blocks.clone(), - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - fs.mkdir("/dir", false).await.unwrap(); - fs.write_file("/dir/file", b"persisted").await.unwrap(); - } - - let metadata = SqliteMetadataStore::open(&db).unwrap(); - let fs = ChunkedFs::with_options( - metadata, - blocks, - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - assert_eq!(fs.read_file("/dir/file").await.unwrap(), b"persisted"); - assert_eq!(fs.read_dir("/dir").await.unwrap(), vec!["file"]); -} - -#[tokio::test] -async fn chunked_local_reopens_and_cleans_stale_blocks() { - let temp = tempfile::tempdir().unwrap(); - let db = temp.path().join("metadata.sqlite"); - let block_root = temp.path().join("blocks"); - let stale_key = BlockKey::from_content(b"efgh"); - - { - let metadata = SqliteMetadataStore::open(&db).unwrap(); - let blocks = FileBlockStore::new(&block_root).unwrap(); - let fs = ChunkedFs::with_options( - metadata, - blocks, - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - fs.write_file("/file", b"abcdefgh").await.unwrap(); - } - - let metadata = SqliteMetadataStore::open(&db).unwrap(); - let blocks = FileBlockStore::new(&block_root).unwrap(); - let fs = ChunkedFs::with_options( - metadata, - blocks.clone(), - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - - assert_eq!(fs.read_file("/file").await.unwrap(), b"abcdefgh"); - fs.truncate("/file", 5).await.unwrap(); - assert_eq!(fs.read_file("/file").await.unwrap(), b"abcde"); - assert!(!blocks.exists(&stale_key).await.unwrap()); -} diff --git a/crates/secure-exec-vfs/tests/s3.rs b/crates/secure-exec-vfs/tests/s3.rs deleted file mode 100644 index 7859ff90c..000000000 --- a/crates/secure-exec-vfs/tests/s3.rs +++ /dev/null @@ -1,588 +0,0 @@ -use aws_config::BehaviorVersion; -use aws_credential_types::Credentials; -use aws_sdk_s3::config::Builder as S3ConfigBuilder; -use aws_sdk_s3::Client; -use secure_exec_vfs::{S3BlockStore, S3BlockStoreOptions, S3ObjectBackend, S3ObjectBackendOptions}; -use std::collections::{BTreeMap, BTreeSet}; -use std::io::{Read, Write}; -use std::net::{TcpListener, TcpStream}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex}; -use std::thread::{self, JoinHandle}; -use std::time::Duration; -use vfs::engine::engines::{ChunkedFs, ChunkedFsOptions, ObjectFs}; -use vfs::engine::{BlockKey, BlockStore, VirtualFileSystem}; - -#[tokio::test] -async fn s3_block_store_round_trips_and_cleans_blocks() { - let server = MockS3Server::start(); - let store = S3BlockStore::with_options( - s3_client(server.base_url()).await, - "test-bucket", - S3BlockStoreOptions { - prefix: "blocks/".to_string(), - }, - ); - let first = BlockKey::from_content(b"abcdef"); - let second = BlockKey::from_content(b"ghijkl"); - - store.put(&first, b"abcdef").await.unwrap(); - assert!(store.exists(&first).await.unwrap()); - assert_eq!(store.get_range(&first, 2, 3).await.unwrap(), b"cde"); - store.copy(&first, &second).await.unwrap(); - assert_eq!(store.get(&second).await.unwrap(), b"abcdef"); - - store - .delete_many(&[first.clone(), second.clone()]) - .await - .unwrap(); - assert!(!store.exists(&first).await.unwrap()); - assert!(!store.exists(&second).await.unwrap()); - assert!(server - .requests() - .iter() - .any(|request| request.method == "POST")); -} - -#[tokio::test] -async fn object_s3_round_trips_native_objects() { - let server = MockS3Server::start(); - let backend = S3ObjectBackend::with_options( - s3_client(server.base_url()).await, - "test-bucket", - S3ObjectBackendOptions { - prefix: "objects/".to_string(), - }, - ); - let fs = ObjectFs::new(backend); - - fs.write_file("/dir/file.txt", b"hello object s3") - .await - .unwrap(); - assert_eq!( - fs.read_file("/dir/file.txt").await.unwrap(), - b"hello object s3" - ); - assert_eq!(fs.pread("/dir/file.txt", 6, 6).await.unwrap(), b"object"); - assert!(fs.exists("/dir/file.txt").await); - assert_eq!(fs.read_dir("/dir").await.unwrap(), vec!["file.txt"]); - - fs.rename("/dir/file.txt", "/dir/renamed.txt") - .await - .unwrap(); - assert_eq!( - fs.read_file("/dir/renamed.txt").await.unwrap(), - b"hello object s3" - ); - assert!(!fs.exists("/dir/file.txt").await); - assert!(server - .object_keys() - .iter() - .any(|key| key == "test-bucket/objects/dir/renamed.txt")); -} - -#[tokio::test] -async fn chunked_s3_reopens_metadata_and_cleans_truncated_chunks() { - let server = MockS3Server::start(); - let temp = tempfile::tempdir().unwrap(); - let db = temp.path().join("metadata.sqlite"); - let stale_key = BlockKey::from_content(b"efgh"); - - { - let metadata = secure_exec_vfs::SqliteMetadataStore::open(&db).unwrap(); - let blocks = S3BlockStore::with_options( - s3_client(server.base_url()).await, - "test-bucket", - S3BlockStoreOptions { - prefix: "chunked/blocks/".to_string(), - }, - ); - let fs = ChunkedFs::with_options( - metadata, - blocks, - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - fs.write_file("/file", b"abcdefgh").await.unwrap(); - } - - let metadata = secure_exec_vfs::SqliteMetadataStore::open(&db).unwrap(); - let blocks = S3BlockStore::with_options( - s3_client(server.base_url()).await, - "test-bucket", - S3BlockStoreOptions { - prefix: "chunked/blocks/".to_string(), - }, - ); - let fs = ChunkedFs::with_options( - metadata, - blocks, - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - - assert_eq!(fs.read_file("/file").await.unwrap(), b"abcdefgh"); - fs.truncate("/file", 5).await.unwrap(); - assert_eq!(fs.read_file("/file").await.unwrap(), b"abcde"); - assert!(!server - .object_keys() - .iter() - .any(|key| { key == &format!("test-bucket/chunked/blocks/{}", stale_key.0) })); -} - -async fn s3_client(endpoint: &str) -> Client { - let shared_config = aws_config::defaults(BehaviorVersion::latest()) - .region(aws_sdk_s3::config::Region::new("us-east-1")) - .credentials_provider(Credentials::new( - "minioadmin", - "minioadmin", - None, - None, - "secure-exec-vfs-test", - )) - .load() - .await; - Client::from_conf( - S3ConfigBuilder::from(&shared_config) - .endpoint_url(endpoint) - .force_path_style(true) - .build(), - ) -} - -#[derive(Clone, Debug)] -struct LoggedRequest { - method: String, -} - -#[derive(Clone, Debug, Default)] -struct StoredObject { - body: Vec, - metadata: BTreeMap, -} - -struct MockS3Server { - base_url: String, - shutdown: Arc, - objects: Arc>>, - requests: Arc>>, - handle: Option>, -} - -impl MockS3Server { - fn start() -> Self { - let listener = TcpListener::bind("127.0.0.1:0").expect("bind mock s3"); - listener - .set_nonblocking(true) - .expect("configure mock s3 listener"); - let address = listener.local_addr().expect("resolve mock s3 address"); - let shutdown = Arc::new(AtomicBool::new(false)); - let objects = Arc::new(Mutex::new(BTreeMap::new())); - let requests = Arc::new(Mutex::new(Vec::new())); - let shutdown_for_thread = Arc::clone(&shutdown); - let objects_for_thread = Arc::clone(&objects); - let requests_for_thread = Arc::clone(&requests); - - let handle = thread::spawn(move || { - while !shutdown_for_thread.load(Ordering::SeqCst) { - match listener.accept() { - Ok((stream, _)) => { - handle_stream(stream, &objects_for_thread, &requests_for_thread) - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - thread::sleep(Duration::from_millis(10)); - } - Err(_) => break, - } - } - }); - - Self { - base_url: format!("http://{}", address), - shutdown, - objects, - requests, - handle: Some(handle), - } - } - - fn base_url(&self) -> &str { - &self.base_url - } - - fn object_keys(&self) -> Vec { - self.objects - .lock() - .expect("lock mock s3 objects") - .keys() - .cloned() - .collect() - } - - fn requests(&self) -> Vec { - self.requests.lock().expect("lock mock s3 requests").clone() - } -} - -impl Drop for MockS3Server { - fn drop(&mut self) { - self.shutdown.store(true, Ordering::SeqCst); - if let Some(handle) = self.handle.take() { - handle.join().expect("join mock s3 thread"); - } - } -} - -fn handle_stream( - mut stream: TcpStream, - objects: &Arc>>, - requests: &Arc>>, -) { - stream - .set_read_timeout(Some(Duration::from_secs(2))) - .expect("set mock s3 read timeout"); - - let mut buffer = Vec::new(); - let mut header_end = None; - while header_end.is_none() { - let mut chunk = [0; 1024]; - match stream.read(&mut chunk) { - Ok(0) => return, - Ok(read) => { - buffer.extend_from_slice(&chunk[..read]); - header_end = find_header_end(&buffer); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => continue, - Err(_) => return, - } - } - - let header_end = header_end.expect("parse mock s3 headers"); - let header_text = String::from_utf8_lossy(&buffer[..header_end]).into_owned(); - let mut lines = header_text.split("\r\n"); - let request_line = match lines.next() { - Some(line) if !line.is_empty() => line, - _ => return, - }; - let mut request_parts = request_line.split_whitespace(); - let method = request_parts.next().unwrap_or_default().to_owned(); - let raw_target = request_parts.next().unwrap_or_default(); - let (raw_path, raw_query) = raw_target.split_once('?').unwrap_or((raw_target, "")); - let raw_query = raw_query.to_owned(); - let path = decode_url_component(raw_path); - - let mut headers = BTreeMap::new(); - let mut content_length = 0usize; - for line in lines { - if let Some((name, value)) = line.split_once(':') { - let name = name.trim().to_ascii_lowercase(); - let value = value.trim().to_owned(); - if name == "content-length" { - content_length = value.parse::().unwrap_or(0); - } - headers.insert(name, value); - } - } - - while buffer.len() < header_end + 4 + content_length { - let mut chunk = [0; 1024]; - match stream.read(&mut chunk) { - Ok(0) => break, - Ok(read) => buffer.extend_from_slice(&chunk[..read]), - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => continue, - Err(_) => break, - } - } - let body = buffer[header_end + 4..header_end + 4 + content_length].to_vec(); - requests - .lock() - .expect("lock mock s3 request log") - .push(LoggedRequest { - method: method.clone(), - }); - - match method.as_str() { - "GET" if raw_query.contains("list-type=2") => { - let query = parse_query(&raw_query); - let xml = list_objects_xml( - &path, - query.get("prefix").map(String::as_str).unwrap_or_default(), - query.get("delimiter").map(String::as_str), - objects, - ); - send_response(&mut stream, 200, "OK", "application/xml", xml.as_bytes()); - } - "GET" => { - let key = path.trim_start_matches('/'); - if let Some(object) = objects - .lock() - .expect("lock mock s3 objects") - .get(key) - .cloned() - { - let bytes = apply_range(&object.body, headers.get("range").map(String::as_str)); - send_response(&mut stream, 200, "OK", "application/octet-stream", &bytes); - } else { - send_not_found(&mut stream); - } - } - "HEAD" => { - let key = path.trim_start_matches('/'); - let object = objects - .lock() - .expect("lock mock s3 objects") - .get(key) - .cloned(); - match object { - Some(object) => send_head_response(&mut stream, 200, "OK", &object), - None => send_head_response(&mut stream, 404, "Not Found", &StoredObject::default()), - } - } - "PUT" => { - let key = path.trim_start_matches('/').to_owned(); - let object = if let Some(source) = headers.get("x-amz-copy-source") { - let source = decode_url_component(source) - .trim_start_matches('/') - .to_owned(); - objects - .lock() - .expect("lock mock s3 objects") - .get(&source) - .cloned() - .unwrap_or_default() - } else { - StoredObject { - body, - metadata: headers - .iter() - .filter_map(|(name, value)| { - name.strip_prefix("x-amz-meta-") - .map(|name| (name.to_string(), value.clone())) - }) - .collect(), - } - }; - objects - .lock() - .expect("lock mock s3 objects") - .insert(key, object); - send_response(&mut stream, 200, "OK", "application/xml", b""); - } - "DELETE" => { - objects - .lock() - .expect("lock mock s3 objects") - .remove(path.trim_start_matches('/')); - send_response(&mut stream, 204, "No Content", "application/xml", b""); - } - "POST" if raw_query.starts_with("delete") => { - let keys = parse_delete_objects_keys(&body); - let bucket = path.trim_matches('/'); - let mut objects = objects.lock().expect("lock mock s3 objects"); - if keys.is_empty() { - let bucket_prefix = format!("{bucket}/"); - objects.retain(|key, _| !key.starts_with(&bucket_prefix)); - } else { - for key in keys { - objects.remove(&format!("{bucket}/{key}")); - } - } - send_response( - &mut stream, - 200, - "OK", - "application/xml", - br#""#, - ); - } - _ => send_response( - &mut stream, - 405, - "Method Not Allowed", - "text/plain", - b"unsupported", - ), - } -} - -fn list_objects_xml( - path: &str, - prefix: &str, - delimiter: Option<&str>, - objects: &Arc>>, -) -> String { - let bucket = path - .trim_start_matches('/') - .split('/') - .next() - .unwrap_or_default(); - let full_prefix = format!("{bucket}/{prefix}"); - let delimiter = delimiter.unwrap_or_default(); - let mut contents = Vec::new(); - let mut common_prefixes = BTreeSet::new(); - - for (key, object) in objects.lock().expect("lock mock s3 objects").iter() { - let Some(relative) = key.strip_prefix(&full_prefix) else { - continue; - }; - if !delimiter.is_empty() { - if let Some((first, _)) = relative.split_once(delimiter) { - common_prefixes.insert(format!("{prefix}{first}{delimiter}")); - continue; - } - } - contents.push(( - key.strip_prefix(&format!("{bucket}/")) - .unwrap_or(key) - .to_owned(), - object.body.len(), - )); - } - - let mut xml = String::from( - r#""#, - ); - xml.push_str("false"); - for (key, len) in contents { - xml.push_str(""); - xml.push_str(&escape_xml(&key)); - xml.push_str(""); - xml.push_str(&len.to_string()); - xml.push_str(""); - } - for prefix in common_prefixes { - xml.push_str(""); - xml.push_str(&escape_xml(&prefix)); - xml.push_str(""); - } - xml.push_str(""); - xml -} - -fn apply_range(bytes: &[u8], range: Option<&str>) -> Vec { - let Some(range) = range.and_then(|range| range.strip_prefix("bytes=")) else { - return bytes.to_vec(); - }; - let Some((start, end)) = range.split_once('-') else { - return bytes.to_vec(); - }; - let start = start.parse::().unwrap_or(0); - let end = end - .parse::() - .unwrap_or(bytes.len().saturating_sub(1)) - .min(bytes.len().saturating_sub(1)); - if start >= bytes.len() || start > end { - return Vec::new(); - } - bytes[start..=end].to_vec() -} - -fn send_not_found(stream: &mut TcpStream) { - send_response( - stream, - 404, - "Not Found", - "application/xml", - br#"NoSuchKeymissing"#, - ); -} - -fn send_head_response(stream: &mut TcpStream, status: u16, reason: &str, object: &StoredObject) { - let mut response = format!( - "HTTP/1.1 {status} {reason}\r\nContent-Length: {}\r\nConnection: close\r\nx-amz-request-id: test\r\n", - object.body.len() - ); - for (name, value) in &object.metadata { - response.push_str(&format!("x-amz-meta-{name}: {value}\r\n")); - } - response.push_str("\r\n"); - stream - .write_all(response.as_bytes()) - .expect("write mock s3 head response"); - stream.flush().expect("flush mock s3 response"); -} - -fn send_response( - stream: &mut TcpStream, - status: u16, - reason: &str, - content_type: &str, - body: &[u8], -) { - let response = format!( - "HTTP/1.1 {status} {reason}\r\nContent-Length: {}\r\nContent-Type: {content_type}\r\nConnection: close\r\nx-amz-request-id: test\r\n\r\n", - body.len() - ); - stream - .write_all(response.as_bytes()) - .expect("write mock s3 response headers"); - stream.write_all(body).expect("write mock s3 response body"); - stream.flush().expect("flush mock s3 response"); -} - -fn find_header_end(buffer: &[u8]) -> Option { - buffer.windows(4).position(|window| window == b"\r\n\r\n") -} - -fn parse_query(raw: &str) -> BTreeMap { - raw.split('&') - .map(|pair| { - let (name, value) = pair.split_once('=').unwrap_or((pair, "")); - (decode_url_component(name), decode_url_component(value)) - }) - .collect() -} - -fn parse_delete_objects_keys(body: &[u8]) -> Vec { - let text = String::from_utf8_lossy(body); - let mut keys = Vec::new(); - let mut rest = text.as_ref(); - while let Some((_, after_start)) = rest.split_once("") { - let Some((key, after_end)) = after_start.split_once("") else { - break; - }; - keys.push(decode_url_component(key)); - rest = after_end; - } - keys -} - -fn decode_url_component(raw: &str) -> String { - let mut decoded = String::new(); - let bytes = raw.as_bytes(); - let mut index = 0; - while index < bytes.len() { - if bytes[index] == b'%' && index + 2 < bytes.len() { - let code = std::str::from_utf8(&bytes[index + 1..index + 3]) - .ok() - .and_then(|hex| u8::from_str_radix(hex, 16).ok()); - if let Some(code) = code { - decoded.push(code as char); - index += 3; - continue; - } - } - if bytes[index] == b'+' { - decoded.push(' '); - } else { - decoded.push(bytes[index] as char); - } - index += 1; - } - decoded -} - -fn escape_xml(value: &str) -> String { - value - .replace('&', "&") - .replace('<', "<") - .replace('>', ">") - .replace('"', """) - .replace('\'', "'") -} diff --git a/crates/sidecar-browser/AGENTS.md b/crates/sidecar-browser/AGENTS.md deleted file mode 120000 index 681311eb9..000000000 --- a/crates/sidecar-browser/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/crates/sidecar-browser/CLAUDE.md b/crates/sidecar-browser/CLAUDE.md deleted file mode 100644 index 91a5d062a..000000000 --- a/crates/sidecar-browser/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -# Browser Support - -- Browser support is untested after the secure-exec split; only build-level validation is required during migration. -- Provenance: moved from rivet-dev/agentos@87ed8e21e454. -- Keep the browser sidecar separate from the native sidecar because worker transport and main-thread ownership differ from stdio/socket transport. diff --git a/crates/sidecar-browser/Cargo.toml b/crates/sidecar-browser/Cargo.toml index a73421927..5af67837f 100644 --- a/crates/sidecar-browser/Cargo.toml +++ b/crates/sidecar-browser/Cargo.toml @@ -3,21 +3,11 @@ name = "secure-exec-sidecar-browser" version.workspace = true edition.workspace = true license.workspace = true -description = "Browser-side Secure Exec sidecar scaffold" +repository.workspace = true +description = "secure-exec-sidecar-browser compatibility shim for agentos-native-sidecar-browser" [lib] -crate-type = ["cdylib", "rlib"] +name = "secure_exec_sidecar_browser" [dependencies] -secure-exec-bridge = { path = "../bridge" } -secure-exec-kernel = { path = "../kernel" } -secure-exec-sidecar-core = { path = "../sidecar-core" } -secure-exec-sidecar-protocol = { path = "../sidecar-protocol" } -secure-exec-vm-config = { path = "../vm-config" } -base64 = "0.22" -serde_json = "1.0" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } -js-sys = "0.3" -wasm-bindgen = "0.2" +agentos_native_sidecar_browser = { package = "agentos-native-sidecar-browser", path = "../../../agentos/crates/native-sidecar-browser", version = "0.0.1" } diff --git a/crates/sidecar-browser/src/lib.rs b/crates/sidecar-browser/src/lib.rs index b1b82c221..7b8db7a44 100644 --- a/crates/sidecar-browser/src/lib.rs +++ b/crates/sidecar-browser/src/lib.rs @@ -1,121 +1,3 @@ -#![forbid(unsafe_code)] +//! Compatibility shim for `agentos-native-sidecar-browser`. -//! Browser-side sidecar scaffold for the secure-exec runtime migration. - -mod service; -#[cfg(target_arch = "wasm32")] -mod wasm; -pub mod wire_dispatch; - -pub use service::{ - BrowserExecutionOptions, BrowserExtension, BrowserExtensionContext, BrowserExtensionHost, - BrowserExtensionRequest, BrowserExtensionResponse, BrowserSidecar, BrowserSidecarConfig, - BrowserSidecarError, -}; -#[cfg(target_arch = "wasm32")] -pub use wasm::{BrowserJsBridge, BrowserSidecarWasm}; - -use secure_exec_bridge::{BridgeTypes, GuestRuntime, HostBridge}; -use secure_exec_sidecar_protocol::wire::WasmPermissionTier; -use std::collections::BTreeMap; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum BrowserWorkerEntrypoint { - JavaScript { bootstrap_module: Option }, - WebAssembly { module_path: Option }, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BrowserWorkerSpawnRequest { - pub vm_id: String, - pub context_id: String, - pub execution_id: String, - pub runtime: GuestRuntime, - pub entrypoint: BrowserWorkerEntrypoint, - pub wasm_permission_tier: Option, - pub process_config: BrowserWorkerProcessConfig, - pub os_config: BrowserWorkerOsConfig, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BrowserWorkerProcessConfig { - pub cwd: String, - pub env: BTreeMap, - pub argv: Vec, - pub platform: String, - pub arch: String, - pub version: String, - pub pid: u32, - pub ppid: u32, - pub uid: u32, - pub gid: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BrowserWorkerOsConfig { - pub platform: String, - pub arch: String, - pub r#type: String, - pub release: String, - pub version: String, - pub cpu_count: u64, - pub totalmem: u64, - pub freemem: u64, - pub hostname: String, - pub homedir: String, - pub tmpdir: String, - pub machine: String, - pub user: String, - pub shell: String, - pub uid: u32, - pub gid: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BrowserWorkerHandle { - pub worker_id: String, - pub runtime: GuestRuntime, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BrowserWorkerHandleRequest { - pub vm_id: String, - pub execution_id: String, - pub worker_id: String, -} - -pub trait BrowserHostBridge: HostBridge {} - -impl BrowserHostBridge for T where T: HostBridge {} - -pub trait BrowserWorkerBridge: BridgeTypes { - fn create_worker( - &mut self, - request: BrowserWorkerSpawnRequest, - ) -> Result; - - fn terminate_worker(&mut self, request: BrowserWorkerHandleRequest) -> Result<(), Self::Error>; -} - -pub trait BrowserSidecarBridge: BrowserHostBridge + BrowserWorkerBridge {} - -impl BrowserSidecarBridge for T where T: BrowserHostBridge + BrowserWorkerBridge {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct BrowserSidecarScaffold { - pub package_name: &'static str, - pub kernel_package: &'static str, - pub execution_host_thread: &'static str, - pub guest_worker_owner_thread: &'static str, -} - -pub fn scaffold() -> BrowserSidecarScaffold { - let kernel = secure_exec_kernel::scaffold(); - - BrowserSidecarScaffold { - package_name: env!("CARGO_PKG_NAME"), - kernel_package: kernel.package_name, - execution_host_thread: "main", - guest_worker_owner_thread: "main", - } -} +pub use agentos_native_sidecar_browser::*; diff --git a/crates/sidecar-browser/src/service.rs b/crates/sidecar-browser/src/service.rs deleted file mode 100644 index b2ac263b7..000000000 --- a/crates/sidecar-browser/src/service.rs +++ /dev/null @@ -1,2282 +0,0 @@ -use crate::{ - BrowserSidecarBridge, BrowserWorkerEntrypoint, BrowserWorkerHandle, BrowserWorkerHandleRequest, - BrowserWorkerOsConfig, BrowserWorkerProcessConfig, BrowserWorkerSpawnRequest, -}; -use secure_exec_bridge::{ - BridgeTypes, CreateJavascriptContextRequest, CreateWasmContextRequest, ExecutionEvent, - ExecutionHandleRequest, GuestContextHandle, GuestRuntime, KillExecutionRequest, - LifecycleEventRecord, LifecycleState, PollExecutionEventRequest, SignalDispositionAction, - SignalHandlerRegistration, StartExecutionRequest, StartedExecution, StructuredEventRecord, - WriteExecutionStdinRequest, -}; -use secure_exec_kernel::bridge::LifecycleState as KernelLifecycleState; -use secure_exec_kernel::kernel::{KernelError, KernelVm, KernelVmConfig, VirtualProcessOptions}; -use secure_exec_kernel::mount_table::MountTable; -use secure_exec_kernel::poll::{PollTargetEntry, POLLERR, POLLHUP, POLLIN}; -use secure_exec_kernel::process_table::ProcessStatus; -use secure_exec_kernel::root_fs::{ - RootFilesystemMode as KernelRootFilesystemMode, RootFilesystemSnapshot, -}; -use secure_exec_kernel::socket_table::{ - InetSocketAddress, SocketId, SocketSpec, SocketState, SocketType, -}; -use secure_exec_sidecar_core::{ - apply_process_signal_state_update, build_root_mount_table, - ensure_vm_fetch_raw_response_buffer_within_limit, ensure_vm_fetch_response_within_limit, - handle_guest_filesystem_call, handle_guest_kernel_call, parse_kernel_http_fetch_response, - process_snapshot_entry_from_kernel, serialize_kernel_http_fetch_request, - unsupported_guest_kernel_call_detail, SharedProcessSnapshotEntry, VmLayerStore, - VM_FETCH_BUFFER_LIMIT_BYTES, -}; -use secure_exec_sidecar_core::{ - ensure_command_aliases_available, ensure_toolkit_name_available, - ensure_toolkit_registry_capacity, registered_tool_command_names, shared_guest_runtime_identity, - validate_toolkit_registration, -}; -use secure_exec_sidecar_protocol::protocol::{ - FindBoundUdpRequest, FindListenerRequest, GuestFilesystemCallRequest, - GuestFilesystemResultResponse, GuestKernelCallRequest, GuestKernelResultResponse, - ProjectedModuleDescriptor, RegisterHostCallbacksRequest, RootFilesystemEntry, - SignalDispositionAction as ProtocolSignalDispositionAction, - SignalHandlerRegistration as ProtocolSignalHandlerRegistration, SocketStateEntry, - WasmPermissionTier, -}; -use secure_exec_vm_config::RootFilesystemConfig; -use std::collections::{BTreeMap, BTreeSet}; -use std::error::Error; -use std::fmt; -use std::time::{Duration, Instant}; - -type BridgeError = ::Error; -type BrowserKernel = KernelVm; -const BROWSER_WORKER_DRIVER: &str = "browser.worker"; -const BROWSER_VM_FETCH_TIMEOUT: Duration = Duration::from_secs(30); -#[cfg(not(target_arch = "wasm32"))] -const BROWSER_VM_FETCH_TIMEOUT_MS_ENV: &str = "SECURE_EXEC_TEST_BROWSER_VM_FETCH_TIMEOUT_MS"; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BrowserSidecarConfig { - pub sidecar_id: String, -} - -impl Default for BrowserSidecarConfig { - fn default() -> Self { - Self { - sidecar_id: String::from("secure-exec-sidecar-browser"), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum BrowserSidecarError { - InvalidState(String), - Kernel(String), - Bridge(String), -} - -impl fmt::Display for BrowserSidecarError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InvalidState(message) | Self::Kernel(message) | Self::Bridge(message) => { - f.write_str(message) - } - } - } -} - -impl Error for BrowserSidecarError {} - -struct VmState { - kernel: BrowserKernel, - configuration: BrowserVmConfiguration, - layers: VmLayerStore, - toolkits: BTreeMap, - signal_states: BTreeMap>, - contexts: BTreeSet, - active_executions: BTreeSet, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -struct BrowserVmConfiguration { - instructions: Vec, - projected_modules: Vec, - command_permissions: BTreeMap, - create_loopback_exempt_ports: BTreeSet, - loopback_exempt_ports: Vec, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct BrowserExecutionOptions { - pub command_name: Option, - pub wasm_permission_tier: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct ContextState { - vm_id: String, - runtime: GuestRuntime, - entrypoint: BrowserWorkerEntrypoint, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct ExecutionState { - vm_id: String, - worker: BrowserWorkerHandle, - kernel_pid: u32, - stdin_write_fd: u32, - cwd: String, -} - -pub trait BrowserExtension: Send + Sync { - fn namespace(&self) -> &str; - - fn handle_request( - &self, - context: &mut BrowserExtensionContext<'_>, - payload: &[u8], - ) -> Result, BrowserSidecarError> { - let _ = context; - let _ = payload; - Err(BrowserSidecarError::InvalidState(format!( - "browser extension {} does not handle requests", - self.namespace() - ))) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BrowserExtensionRequest { - pub namespace: String, - pub payload: Vec, - /// VM the request is scoped to (from the wire ownership scope), so extensions - /// that drive guest executions know which VM to target. `None` for connection/ - /// session-scoped requests that carry no VM. - pub vm_id: Option, - /// Owning connection (from the wire ownership scope), for per-connection - /// ownership enforcement inside extensions. - pub connection_id: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BrowserExtensionResponse { - pub namespace: String, - pub payload: Vec, -} - -pub trait BrowserExtensionHost { - fn write_file( - &mut self, - vm_id: &str, - path: &str, - contents: Vec, - ) -> Result<(), BrowserSidecarError>; - - fn read_file(&mut self, vm_id: &str, path: &str) -> Result, BrowserSidecarError>; - - fn mkdir( - &mut self, - vm_id: &str, - path: &str, - recursive: bool, - ) -> Result<(), BrowserSidecarError>; - - fn read_dir(&mut self, vm_id: &str, path: &str) -> Result, BrowserSidecarError>; - - fn create_javascript_context( - &mut self, - request: CreateJavascriptContextRequest, - ) -> Result; - - fn create_wasm_context( - &mut self, - request: CreateWasmContextRequest, - ) -> Result; - - fn start_execution( - &mut self, - request: StartExecutionRequest, - ) -> Result; - - fn write_stdin( - &mut self, - request: WriteExecutionStdinRequest, - ) -> Result<(), BrowserSidecarError>; - - fn close_stdin(&mut self, request: ExecutionHandleRequest) -> Result<(), BrowserSidecarError>; - - fn kill_execution(&mut self, request: KillExecutionRequest) -> Result<(), BrowserSidecarError>; - - fn poll_execution_event( - &mut self, - request: PollExecutionEventRequest, - ) -> Result, BrowserSidecarError>; -} - -pub struct BrowserExtensionContext<'a> { - host: &'a mut dyn BrowserExtensionHost, - vm_id: Option, - connection_id: Option, -} - -impl<'a> BrowserExtensionContext<'a> { - pub fn new(host: &'a mut dyn BrowserExtensionHost) -> Self { - Self { - host, - vm_id: None, - connection_id: None, - } - } - - /// Construct with the wire ownership scope threaded in (VM + connection), so - /// extensions can target the right VM and enforce per-connection ownership. - pub fn with_ownership( - host: &'a mut dyn BrowserExtensionHost, - vm_id: Option, - connection_id: Option, - ) -> Self { - Self { - host, - vm_id, - connection_id, - } - } - - /// VM this request is scoped to, if any. - pub fn vm_id(&self) -> Option<&str> { - self.vm_id.as_deref() - } - - /// Owning connection of this request, if any. - pub fn connection_id(&self) -> Option<&str> { - self.connection_id.as_deref() - } - - pub fn write_file( - &mut self, - vm_id: &str, - path: &str, - contents: impl Into>, - ) -> Result<(), BrowserSidecarError> { - self.host.write_file(vm_id, path, contents.into()) - } - - pub fn read_file(&mut self, vm_id: &str, path: &str) -> Result, BrowserSidecarError> { - self.host.read_file(vm_id, path) - } - - pub fn mkdir( - &mut self, - vm_id: &str, - path: &str, - recursive: bool, - ) -> Result<(), BrowserSidecarError> { - self.host.mkdir(vm_id, path, recursive) - } - - pub fn read_dir( - &mut self, - vm_id: &str, - path: &str, - ) -> Result, BrowserSidecarError> { - self.host.read_dir(vm_id, path) - } - - pub fn create_javascript_context( - &mut self, - request: CreateJavascriptContextRequest, - ) -> Result { - self.host.create_javascript_context(request) - } - - pub fn create_wasm_context( - &mut self, - request: CreateWasmContextRequest, - ) -> Result { - self.host.create_wasm_context(request) - } - - pub fn start_execution( - &mut self, - request: StartExecutionRequest, - ) -> Result { - self.host.start_execution(request) - } - - pub fn write_stdin( - &mut self, - request: WriteExecutionStdinRequest, - ) -> Result<(), BrowserSidecarError> { - self.host.write_stdin(request) - } - - pub fn close_stdin( - &mut self, - request: ExecutionHandleRequest, - ) -> Result<(), BrowserSidecarError> { - self.host.close_stdin(request) - } - - pub fn kill_execution( - &mut self, - request: KillExecutionRequest, - ) -> Result<(), BrowserSidecarError> { - self.host.kill_execution(request) - } - - pub fn poll_execution_event( - &mut self, - request: PollExecutionEventRequest, - ) -> Result, BrowserSidecarError> { - self.host.poll_execution_event(request) - } -} - -pub struct BrowserSidecar { - bridge: B, - config: BrowserSidecarConfig, - vms: BTreeMap, - contexts: BTreeMap, - executions: BTreeMap, - extensions: BTreeMap>, -} - -impl BrowserSidecar -where - B: BrowserSidecarBridge, - BridgeError: fmt::Debug, -{ - pub fn new(bridge: B, config: BrowserSidecarConfig) -> Self { - Self::with_extensions(bridge, config, Vec::new()) - .expect("empty browser extension registry should be valid") - } - - pub fn with_extensions( - bridge: B, - config: BrowserSidecarConfig, - extensions: Vec>, - ) -> Result { - let mut sidecar = Self { - bridge, - config, - vms: BTreeMap::new(), - contexts: BTreeMap::new(), - executions: BTreeMap::new(), - extensions: BTreeMap::new(), - }; - for extension in extensions { - sidecar.register_extension(extension)?; - } - Ok(sidecar) - } - - pub fn register_extension( - &mut self, - extension: Box, - ) -> Result<(), BrowserSidecarError> { - let namespace = extension.namespace(); - if namespace.is_empty() { - return Err(BrowserSidecarError::InvalidState(String::from( - "browser extension namespace must not be empty", - ))); - } - if self.extensions.contains_key(namespace) { - return Err(BrowserSidecarError::InvalidState(format!( - "browser extension namespace already registered: {namespace}", - ))); - } - self.extensions.insert(namespace.to_string(), extension); - Ok(()) - } - - pub fn extension_count(&self) -> usize { - self.extensions.len() - } - - pub fn has_extension(&self, namespace: &str) -> bool { - self.extensions.contains_key(namespace) - } - - pub fn dispatch_extension_request( - &mut self, - request: BrowserExtensionRequest, - ) -> Result { - let Some(extension) = self.extensions.remove(&request.namespace) else { - return Err(BrowserSidecarError::InvalidState(format!( - "no browser extension registered for namespace {}", - request.namespace - ))); - }; - let payload = { - let mut context = BrowserExtensionContext::with_ownership( - self, - request.vm_id.clone(), - request.connection_id.clone(), - ); - extension.handle_request(&mut context, &request.payload) - }; - self.extensions.insert(request.namespace.clone(), extension); - let payload = payload?; - Ok(BrowserExtensionResponse { - namespace: request.namespace, - payload, - }) - } - - pub fn sidecar_id(&self) -> &str { - &self.config.sidecar_id - } - - pub fn bridge(&self) -> &B { - &self.bridge - } - - pub fn bridge_mut(&mut self) -> &mut B { - &mut self.bridge - } - - pub fn into_bridge(self) -> B { - self.bridge - } - - pub fn vm_count(&self) -> usize { - self.vms.len() - } - - pub fn context_count(&self, vm_id: &str) -> usize { - self.vms - .get(vm_id) - .map(|vm| vm.contexts.len()) - .unwrap_or_default() - } - - pub fn active_worker_count(&self, vm_id: &str) -> usize { - self.vms - .get(vm_id) - .map(|vm| vm.active_executions.len()) - .unwrap_or_default() - } - - pub fn create_vm(&mut self, config: KernelVmConfig) -> Result<(), BrowserSidecarError> { - self.create_vm_with_root_filesystem(config, RootFilesystemConfig::default()) - } - - pub fn configure_vm( - &mut self, - vm_id: &str, - permissions: Option, - instructions: Vec, - projected_modules: Vec, - command_permissions: BTreeMap, - loopback_exempt_ports: impl IntoIterator, - ) -> Result<(), BrowserSidecarError> { - let vm = self - .vms - .get_mut(vm_id) - .ok_or_else(|| BrowserSidecarError::InvalidState(format!("unknown VM {vm_id}")))?; - if let Some(permissions) = permissions { - vm.kernel.set_permissions(permissions); - } - let loopback_exempt_ports: Vec = loopback_exempt_ports.into_iter().collect(); - vm.configuration.instructions = instructions; - vm.configuration.projected_modules = projected_modules; - vm.configuration.command_permissions = command_permissions; - vm.configuration.loopback_exempt_ports = loopback_exempt_ports.clone(); - let mut effective_loopback_exempt_ports = - vm.configuration.create_loopback_exempt_ports.clone(); - effective_loopback_exempt_ports.extend(loopback_exempt_ports); - vm.kernel - .set_loopback_exempt_ports(effective_loopback_exempt_ports); - Ok(()) - } - - pub fn create_vm_with_root_filesystem( - &mut self, - config: KernelVmConfig, - root_filesystem: RootFilesystemConfig, - ) -> Result<(), BrowserSidecarError> { - let vm_id = config.vm_id.clone(); - if self.vms.contains_key(&vm_id) { - return Err(BrowserSidecarError::InvalidState(format!( - "browser sidecar VM already exists: {vm_id}" - ))); - } - - self.emit_lifecycle( - &vm_id, - LifecycleState::Starting, - Some(String::from( - "browser sidecar booting kernel on main thread", - )), - )?; - let create_loopback_exempt_ports = config.loopback_exempt_ports.clone(); - self.vms.insert( - vm_id.clone(), - VmState { - kernel: KernelVm::new( - build_root_mount_table(&root_filesystem, &config.resources) - .map_err(Self::sidecar_core_error)?, - config, - ), - configuration: BrowserVmConfiguration { - create_loopback_exempt_ports, - ..BrowserVmConfiguration::default() - }, - layers: VmLayerStore::default(), - toolkits: BTreeMap::new(), - signal_states: BTreeMap::new(), - contexts: BTreeSet::new(), - active_executions: BTreeSet::new(), - }, - ); - if let Some(root) = self - .vms - .get_mut(&vm_id) - .and_then(|vm| vm.kernel.root_filesystem_mut()) - { - root.finish_bootstrap(); - } - self.emit_lifecycle( - &vm_id, - LifecycleState::Ready, - Some(String::from( - "browser sidecar kernel is ready on the main thread", - )), - )?; - Ok(()) - } - - pub fn write_file( - &mut self, - vm_id: &str, - path: &str, - contents: impl Into>, - ) -> Result<(), BrowserSidecarError> { - let vm = self.vm_mut(vm_id)?; - vm.kernel - .write_file(path, contents) - .map_err(Self::kernel_error) - } - - pub fn read_file(&mut self, vm_id: &str, path: &str) -> Result, BrowserSidecarError> { - let vm = self.vm_mut(vm_id)?; - vm.kernel.read_file(path).map_err(Self::kernel_error) - } - - pub fn mkdir( - &mut self, - vm_id: &str, - path: &str, - recursive: bool, - ) -> Result<(), BrowserSidecarError> { - let vm = self.vm_mut(vm_id)?; - vm.kernel.mkdir(path, recursive).map_err(Self::kernel_error) - } - - pub fn read_dir( - &mut self, - vm_id: &str, - path: &str, - ) -> Result, BrowserSidecarError> { - let vm = self.vm_mut(vm_id)?; - vm.kernel.read_dir(path).map_err(Self::kernel_error) - } - - pub fn snapshot_root_filesystem( - &mut self, - vm_id: &str, - ) -> Result { - let vm = self.vm_mut(vm_id)?; - vm.kernel - .snapshot_root_filesystem() - .map_err(Self::kernel_error) - } - - pub fn create_layer(&mut self, vm_id: &str) -> Result { - self.vm_mut(vm_id)? - .layers - .create_writable_layer() - .map_err(Self::sidecar_core_error) - } - - pub fn seal_layer( - &mut self, - vm_id: &str, - layer_id: &str, - ) -> Result { - self.vm_mut(vm_id)? - .layers - .seal_layer(layer_id) - .map_err(Self::sidecar_core_error) - } - - pub fn import_snapshot( - &mut self, - vm_id: &str, - entries: &[RootFilesystemEntry], - ) -> Result { - let snapshot = root_snapshot_from_entries(entries)?; - self.vm_mut(vm_id)? - .layers - .import_snapshot(snapshot) - .map_err(Self::sidecar_core_error) - } - - pub fn export_snapshot( - &mut self, - vm_id: &str, - layer_id: &str, - ) -> Result { - self.vm_mut(vm_id)? - .layers - .export_snapshot(layer_id) - .map_err(Self::sidecar_core_error) - } - - pub fn create_overlay( - &mut self, - vm_id: &str, - mode: KernelRootFilesystemMode, - upper_layer_id: Option, - lower_layer_ids: Vec, - ) -> Result { - self.vm_mut(vm_id)? - .layers - .create_overlay_layer(mode, upper_layer_id, lower_layer_ids) - .map_err(Self::sidecar_core_error) - } - - pub fn register_host_callbacks( - &mut self, - vm_id: &str, - payload: RegisterHostCallbacksRequest, - ) -> Result<(String, u32), BrowserSidecarError> { - validate_toolkit_registration(&payload) - .map_err(|error| BrowserSidecarError::InvalidState(error.to_string()))?; - let vm = self.vm_mut(vm_id)?; - ensure_toolkit_name_available(&vm.toolkits, &payload.name) - .map_err(|error| BrowserSidecarError::InvalidState(error.to_string()))?; - ensure_command_aliases_available(&vm.toolkits, &payload) - .map_err(|error| BrowserSidecarError::InvalidState(error.to_string()))?; - ensure_toolkit_registry_capacity(&vm.toolkits, &payload) - .map_err(|error| BrowserSidecarError::InvalidState(error.to_string()))?; - - let registration = payload.name.clone(); - vm.toolkits.insert(registration.clone(), payload); - let command_count = u32::try_from(registered_tool_command_names(&vm.toolkits).len()) - .map_err(|_| { - BrowserSidecarError::InvalidState(String::from( - "registered host callback command count exceeds u32", - )) - })?; - Ok((registration, command_count)) - } - - pub fn bootstrap_root_filesystem_entries( - &mut self, - vm_id: &str, - entries: &[RootFilesystemEntry], - ) -> Result { - for entry in entries { - self.apply_root_filesystem_entry(vm_id, entry)?; - } - u32::try_from(entries.len()).map_err(|_| { - BrowserSidecarError::InvalidState(String::from( - "root filesystem bootstrap entry count exceeds u32", - )) - }) - } - - pub fn guest_filesystem_call( - &mut self, - vm_id: &str, - payload: GuestFilesystemCallRequest, - ) -> Result { - let vm = self.vm_mut(vm_id)?; - handle_guest_filesystem_call(&mut vm.kernel, payload).map_err(Self::sidecar_core_error) - } - - pub fn guest_kernel_call( - &mut self, - vm_id: &str, - payload: GuestKernelCallRequest, - ) -> Result { - let execution = self.ensure_execution_state(vm_id, &payload.execution_id)?; - let kernel_pid = execution.kernel_pid; - let vm = self.vm_mut(vm_id)?; - let response = handle_guest_kernel_call( - &mut vm.kernel, - kernel_pid, - BROWSER_WORKER_DRIVER, - &payload.operation, - &payload.payload, - ) - .map_err(Self::sidecar_core_error)?; - Ok(GuestKernelResultResponse { payload: response }) - } - - pub fn kernel_state(&self, vm_id: &str) -> Result { - let vm = self.vm(vm_id)?; - Ok(match vm.kernel.state() { - KernelLifecycleState::Starting => LifecycleState::Starting, - KernelLifecycleState::Ready => LifecycleState::Ready, - KernelLifecycleState::Busy => LifecycleState::Busy, - KernelLifecycleState::Terminated => LifecycleState::Terminated, - }) - } - - pub fn zombie_timer_count(&self, vm_id: &str) -> Result { - let vm = self.vm(vm_id)?; - Ok(vm.kernel.zombie_timer_count() as u64) - } - - pub fn process_snapshot_entries( - &self, - vm_id: &str, - ) -> Result, BrowserSidecarError> { - let vm = self.vm(vm_id)?; - let process_table = vm.kernel.list_processes(); - Ok(self - .executions - .iter() - .filter(|(_, execution)| execution.vm_id == vm_id) - .filter_map(|(execution_id, execution)| { - process_table.get(&execution.kernel_pid).map(|info| { - process_snapshot_entry_from_kernel( - execution_id, - info, - execution.cwd.clone(), - None, - ) - }) - }) - .collect()) - } - - pub fn signal_state( - &self, - vm_id: &str, - execution_id: &str, - ) -> Result, BrowserSidecarError> { - let vm = self.vm(vm_id)?; - Ok(vm - .signal_states - .get(execution_id) - .cloned() - .unwrap_or_default()) - } - - pub fn find_listener( - &self, - vm_id: &str, - request: &FindListenerRequest, - ) -> Result, BrowserSidecarError> { - let vm = self.vm(vm_id)?; - for (execution_id, execution) in &self.executions { - if execution.vm_id != vm_id { - continue; - } - for record in vm.kernel.socket_records_for_pid(execution.kernel_pid) { - if let Some(path) = request.path.as_deref() { - if record.state() == SocketState::Listening - && record.spec().socket_type == SocketType::Stream - && record.local_unix_path() == Some(path) - { - return Ok(Some(SocketStateEntry { - process_id: execution_id.clone(), - host: None, - port: None, - path: Some(path.to_string()), - })); - } - continue; - } - - let Some(address) = record.local_address() else { - continue; - }; - if record.state() != SocketState::Listening - || record.spec().socket_type != SocketType::Stream - || !socket_host_matches(request.host.as_deref(), address.host()) - || request.port.is_some_and(|port| address.port() != port) - { - continue; - } - return Ok(Some(SocketStateEntry { - process_id: execution_id.clone(), - host: Some(address.host().to_string()), - port: Some(address.port()), - path: None, - })); - } - } - Ok(None) - } - - pub fn find_bound_udp( - &self, - vm_id: &str, - request: &FindBoundUdpRequest, - ) -> Result, BrowserSidecarError> { - let vm = self.vm(vm_id)?; - for (execution_id, execution) in &self.executions { - if execution.vm_id != vm_id { - continue; - } - for record in vm.kernel.socket_records_for_pid(execution.kernel_pid) { - let Some(address) = record.local_address() else { - continue; - }; - if record.state() != SocketState::Bound - || record.spec().socket_type != SocketType::Datagram - || !socket_host_matches(request.host.as_deref(), address.host()) - || request.port.is_some_and(|port| address.port() != port) - { - continue; - } - return Ok(Some(SocketStateEntry { - process_id: execution_id.clone(), - host: Some(address.host().to_string()), - port: Some(address.port()), - path: None, - })); - } - } - Ok(None) - } - - pub fn vm_fetch( - &mut self, - vm_id: &str, - request: &secure_exec_sidecar_protocol::protocol::VmFetchRequest, - ) -> Result { - let target_path = if request.path.starts_with('/') { - request.path.clone() - } else { - format!("/{}", request.path) - }; - let listener = self - .find_listener( - vm_id, - &FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(request.port), - path: None, - }, - )? - .ok_or_else(|| { - BrowserSidecarError::InvalidState(format!( - "vm.fetch could not find a guest HTTP listener on port {}", - request.port - )) - })?; - let target_execution_id = listener.process_id; - let target = self.ensure_execution_state(vm_id, &target_execution_id)?; - let request_bytes = serialize_kernel_http_fetch_request( - request.port, - &target_path, - &request.method, - &request.headers_json, - request.body.as_deref(), - ) - .map_err(|error| BrowserSidecarError::InvalidState(error.to_string()))?; - let url = format!("http://127.0.0.1:{}{}", request.port, target_path); - - let socket_id = { - let vm = self.vm_mut(vm_id)?; - let socket_id = vm - .kernel - .socket_create(BROWSER_WORKER_DRIVER, target.kernel_pid, SocketSpec::tcp()) - .map_err(Self::kernel_error)?; - let result = vm - .kernel - .socket_connect_inet_loopback( - BROWSER_WORKER_DRIVER, - target.kernel_pid, - socket_id, - InetSocketAddress::new("127.0.0.1", request.port), - ) - .map_err(Self::kernel_error) - .and_then(|()| { - vm.kernel - .socket_write( - BROWSER_WORKER_DRIVER, - target.kernel_pid, - socket_id, - &request_bytes, - ) - .map(|_| ()) - .map_err(Self::kernel_error) - }); - if let Err(error) = result { - let _ = vm - .kernel - .socket_close(BROWSER_WORKER_DRIVER, target.kernel_pid, socket_id); - return Err(error); - } - socket_id - }; - - let result = self.read_vm_fetch_response( - vm_id, - target.kernel_pid, - socket_id, - &url, - VM_FETCH_BUFFER_LIMIT_BYTES, - ); - let close_result = { - let vm = self.vm_mut(vm_id)?; - vm.kernel - .socket_close(BROWSER_WORKER_DRIVER, target.kernel_pid, socket_id) - .map_err(Self::kernel_error) - }; - - match (result, close_result) { - (Ok(response), Ok(())) => Ok(response), - (Err(error), _) => Err(error), - (Ok(_), Err(error)) => Err(error), - } - } - - fn read_vm_fetch_response( - &mut self, - vm_id: &str, - kernel_pid: u32, - socket_id: SocketId, - url: &str, - max_fetch_response_bytes: usize, - ) -> Result { - let mut response_buffer = Vec::new(); - let mut peer_closed = false; - let deadline = Instant::now() + browser_vm_fetch_timeout(); - - loop { - if let Some(response) = - parse_kernel_http_fetch_response(&response_buffer, peer_closed, url) - .map_err(|error| BrowserSidecarError::InvalidState(error.to_string()))? - { - ensure_vm_fetch_response_within_limit( - &response, - "vm.fetch", - max_fetch_response_bytes, - ) - .map_err(|error| BrowserSidecarError::InvalidState(error.to_string()))?; - return Ok(response); - } - if Instant::now() >= deadline { - let preview = String::from_utf8_lossy(&response_buffer); - return Err(BrowserSidecarError::InvalidState(format!( - "vm.fetch timed out waiting for kernel TCP HTTP response ({} buffered bytes: {:?})", - response_buffer.len(), - preview.chars().take(200).collect::() - ))); - } - - let poll = { - let vm = self.vm_mut(vm_id)?; - vm.kernel - .poll_targets( - BROWSER_WORKER_DRIVER, - kernel_pid, - vec![PollTargetEntry::socket( - socket_id, - POLLIN | POLLHUP | POLLERR, - )], - 5, - ) - .map_err(Self::kernel_error)? - }; - let revents = poll - .targets - .first() - .map(|entry| entry.revents) - .unwrap_or_default(); - if revents.intersects(POLLERR) { - return Err(BrowserSidecarError::InvalidState(String::from( - "vm.fetch kernel TCP socket reported POLLERR", - ))); - } - if revents.intersects(POLLIN) { - let read_result = { - let vm = self.vm_mut(vm_id)?; - vm.kernel - .socket_read(BROWSER_WORKER_DRIVER, kernel_pid, socket_id, 64 * 1024) - }; - match read_result { - Ok(Some(bytes)) if !bytes.is_empty() => { - response_buffer.extend(bytes); - ensure_vm_fetch_raw_response_buffer_within_limit( - response_buffer.len(), - "vm.fetch", - ) - .map_err(|error| BrowserSidecarError::InvalidState(error.to_string()))?; - } - Ok(Some(_)) => {} - Ok(None) => peer_closed = true, - Err(error) if error.code() == "EAGAIN" => {} - Err(error) => return Err(Self::kernel_error(error)), - } - } - if revents.intersects(POLLHUP) { - peer_closed = true; - } - } - } - - pub fn create_kernel_tcp_listener_for_execution( - &mut self, - vm_id: &str, - execution_id: &str, - host: &str, - port: u16, - backlog: usize, - ) -> Result { - let execution = self.ensure_execution_state(vm_id, execution_id)?; - let vm = self.vm_mut(vm_id)?; - let socket_id = vm - .kernel - .socket_create( - BROWSER_WORKER_DRIVER, - execution.kernel_pid, - SocketSpec::tcp(), - ) - .map_err(Self::kernel_error)?; - vm.kernel - .socket_bind_inet( - BROWSER_WORKER_DRIVER, - execution.kernel_pid, - socket_id, - InetSocketAddress::new(host, port), - ) - .map_err(Self::kernel_error)?; - vm.kernel - .socket_listen( - BROWSER_WORKER_DRIVER, - execution.kernel_pid, - socket_id, - backlog, - ) - .map_err(Self::kernel_error)?; - Ok(socket_id) - } - - pub fn create_kernel_bound_udp_for_execution( - &mut self, - vm_id: &str, - execution_id: &str, - host: &str, - port: u16, - ) -> Result { - let execution = self.ensure_execution_state(vm_id, execution_id)?; - let vm = self.vm_mut(vm_id)?; - let socket_id = vm - .kernel - .socket_create( - BROWSER_WORKER_DRIVER, - execution.kernel_pid, - SocketSpec::udp(), - ) - .map_err(Self::kernel_error)?; - vm.kernel - .socket_bind_inet( - BROWSER_WORKER_DRIVER, - execution.kernel_pid, - socket_id, - InetSocketAddress::new(host, port), - ) - .map_err(Self::kernel_error)?; - Ok(socket_id) - } - - pub fn read_execution_stdin( - &mut self, - vm_id: &str, - execution_id: &str, - length: usize, - timeout: Duration, - ) -> Result>, BrowserSidecarError> { - let execution = self.ensure_execution_state(vm_id, execution_id)?; - let vm = self.vm_mut(vm_id)?; - vm.kernel - .read_process_stdin( - BROWSER_WORKER_DRIVER, - execution.kernel_pid, - length, - Some(timeout), - ) - .map_err(Self::kernel_error) - } - - pub fn dispose_vm(&mut self, vm_id: &str) -> Result<(), BrowserSidecarError> { - // Remove the VM bookkeeping up front and take ownership of its state, so - // that EVERY exit path below — including a mid-dispose `?` failure while - // releasing executions or emitting lifecycle events — reclaims the - // VmState (and the BrowserKernel it owns) instead of stranding it in the - // `vms` map for the process lifetime. - let Some(vm_state) = self.vms.remove(vm_id) else { - return Err(BrowserSidecarError::InvalidState(format!( - "unknown browser sidecar VM: {vm_id}" - ))); - }; - - // Dropping per-context bookkeeping is infallible, so do it - // unconditionally; `contexts` can never retain an entry for a VM that - // has already been removed from `vms`. - for context_id in &vm_state.contexts { - self.contexts.remove(context_id); - } - - // Release every execution, attempting all of them and retaining only the - // first error. A single worker-termination failure must not abandon the - // remaining executions (their `ExecutionState`s would otherwise leak), - // and `release_execution` already removes each entry from `executions` - // before doing fallible bridge work, so the maps stay drained even when - // the bridge reports an error. - let mut first_error: Option = None; - for execution_id in &vm_state.active_executions { - if let Err(error) = self.release_execution(execution_id, "browser.worker.disposed") { - first_error.get_or_insert(error); - } - } - - // Emit the terminal lifecycle event regardless of the outcome above; the - // VM is already gone from the registry either way. - let terminated = self.emit_lifecycle( - vm_id, - LifecycleState::Terminated, - Some(String::from( - "browser sidecar VM disposed on the main thread", - )), - ); - - match first_error { - Some(error) => Err(error), - None => terminated, - } - } - - pub fn create_javascript_context( - &mut self, - request: CreateJavascriptContextRequest, - ) -> Result { - self.ensure_vm(&request.vm_id)?; - - let vm_id = request.vm_id.clone(); - let entrypoint = BrowserWorkerEntrypoint::JavaScript { - bootstrap_module: request.bootstrap_module.clone(), - }; - let handle = self - .bridge - .create_javascript_context(request) - .map_err(Self::bridge_error)?; - - self.register_context(vm_id, handle.clone(), entrypoint)?; - Ok(handle) - } - - pub fn create_wasm_context( - &mut self, - request: CreateWasmContextRequest, - ) -> Result { - self.ensure_vm(&request.vm_id)?; - - let vm_id = request.vm_id.clone(); - let entrypoint = BrowserWorkerEntrypoint::WebAssembly { - module_path: request.module_path.clone(), - }; - let handle = self - .bridge - .create_wasm_context(request) - .map_err(Self::bridge_error)?; - - self.register_context(vm_id, handle.clone(), entrypoint)?; - Ok(handle) - } - - pub fn start_execution( - &mut self, - request: StartExecutionRequest, - ) -> Result { - self.start_execution_with_options(request, BrowserExecutionOptions::default()) - } - - pub fn start_execution_with_options( - &mut self, - request: StartExecutionRequest, - options: BrowserExecutionOptions, - ) -> Result { - self.ensure_vm(&request.vm_id)?; - - let context = self - .contexts - .get(&request.context_id) - .cloned() - .ok_or_else(|| { - BrowserSidecarError::InvalidState(format!( - "unknown browser sidecar context: {}", - request.context_id - )) - })?; - - if context.vm_id != request.vm_id { - return Err(BrowserSidecarError::InvalidState(format!( - "browser sidecar context {} belongs to vm {}, not {}", - request.context_id, context.vm_id, request.vm_id - ))); - } - - let guest_cwd = request.cwd.clone(); - let (kernel_pid, stdin_write_fd) = { - let vm = self.vm_mut(&request.vm_id)?; - let kernel_handle = vm - .kernel - .create_virtual_process( - BROWSER_WORKER_DRIVER, - BROWSER_WORKER_DRIVER, - request - .argv - .first() - .map(String::as_str) - .unwrap_or("browser-worker"), - request.argv.clone(), - VirtualProcessOptions { - env: request.env.clone(), - cwd: Some(guest_cwd.clone()), - ..VirtualProcessOptions::default() - }, - ) - .map_err(Self::kernel_error)?; - let kernel_pid = kernel_handle.pid(); - match Self::configure_process_stdio(&mut vm.kernel, kernel_pid) { - Ok(stdin_write_fd) => (kernel_pid, stdin_write_fd), - Err(error) => { - Self::cleanup_pending_kernel_process(&mut vm.kernel, kernel_pid)?; - return Err(error); - } - } - }; - - let (process_config, os_config) = { - let vm = self.vm(&request.vm_id)?; - browser_worker_identity(&vm.kernel, &request, kernel_pid) - }; - let wasm_permission_tier = match context.runtime { - GuestRuntime::JavaScript => None, - GuestRuntime::WebAssembly => Some(self.resolve_wasm_permission_tier( - &request.vm_id, - options.command_name.as_deref(), - options.wasm_permission_tier, - &context.entrypoint, - )?), - }; - - let started = match self.bridge.start_execution(request.clone()) { - Ok(started) => started, - Err(error) => { - let vm = self.vm_mut(&request.vm_id)?; - Self::cleanup_pending_kernel_process(&mut vm.kernel, kernel_pid)?; - return Err(Self::bridge_error(error)); - } - }; - - let worker = match self.bridge.create_worker(BrowserWorkerSpawnRequest { - vm_id: request.vm_id.clone(), - context_id: request.context_id.clone(), - execution_id: started.execution_id.clone(), - runtime: context.runtime, - entrypoint: context.entrypoint.clone(), - wasm_permission_tier, - process_config, - os_config, - }) { - Ok(worker) => worker, - Err(error) => { - let vm = self.vm_mut(&request.vm_id)?; - Self::cleanup_pending_kernel_process(&mut vm.kernel, kernel_pid)?; - self.bridge - .kill_execution(KillExecutionRequest { - vm_id: request.vm_id, - execution_id: started.execution_id, - signal: secure_exec_bridge::ExecutionSignal::Kill, - }) - .map_err(Self::bridge_error)?; - return Err(Self::bridge_error(error)); - } - }; - - let worker_id = worker.worker_id.clone(); - self.executions.insert( - started.execution_id.clone(), - ExecutionState { - vm_id: request.vm_id.clone(), - worker: worker.clone(), - kernel_pid, - stdin_write_fd, - cwd: guest_cwd, - }, - ); - let vm_state = self - .vms - .get_mut(&request.vm_id) - .expect("VM should exist after validation"); - vm_state - .active_executions - .insert(started.execution_id.clone()); - - self.emit_structured( - &request.vm_id, - "browser.worker.spawned", - BTreeMap::from([ - (String::from("context_id"), request.context_id), - (String::from("execution_id"), started.execution_id.clone()), - ( - String::from("runtime"), - runtime_label(context.runtime).to_string(), - ), - (String::from("worker_id"), worker_id), - ]), - )?; - self.emit_lifecycle( - &request.vm_id, - LifecycleState::Busy, - Some(String::from( - "browser sidecar is coordinating guest execution on the main thread", - )), - )?; - - Ok(started) - } - - fn resolve_wasm_permission_tier( - &self, - vm_id: &str, - command_name: Option<&str>, - explicit_tier: Option, - entrypoint: &BrowserWorkerEntrypoint, - ) -> Result { - let vm = self.vm(vm_id)?; - Ok(explicit_tier - .or_else(|| { - command_name - .and_then(|command| vm.configuration.command_permissions.get(command).copied()) - }) - .or_else(|| { - let BrowserWorkerEntrypoint::WebAssembly { - module_path: Some(module_path), - } = entrypoint - else { - return None; - }; - module_path - .rsplit('/') - .next() - .and_then(|name| vm.configuration.command_permissions.get(name).copied()) - }) - .unwrap_or(WasmPermissionTier::Full)) - } - - fn configure_process_stdio( - kernel: &mut BrowserKernel, - kernel_pid: u32, - ) -> Result { - let (stdin_read_fd, stdin_write_fd) = kernel - .open_pipe(BROWSER_WORKER_DRIVER, kernel_pid) - .map_err(Self::kernel_error)?; - kernel - .fd_dup2(BROWSER_WORKER_DRIVER, kernel_pid, stdin_read_fd, 0) - .map_err(Self::kernel_error)?; - let (_stdout_read_fd, stdout_write_fd) = kernel - .open_pipe(BROWSER_WORKER_DRIVER, kernel_pid) - .map_err(Self::kernel_error)?; - kernel - .fd_dup2(BROWSER_WORKER_DRIVER, kernel_pid, stdout_write_fd, 1) - .map_err(Self::kernel_error)?; - let (_stderr_read_fd, stderr_write_fd) = kernel - .open_pipe(BROWSER_WORKER_DRIVER, kernel_pid) - .map_err(Self::kernel_error)?; - kernel - .fd_dup2(BROWSER_WORKER_DRIVER, kernel_pid, stderr_write_fd, 2) - .map_err(Self::kernel_error)?; - Ok(stdin_write_fd) - } - - fn cleanup_pending_kernel_process( - kernel: &mut BrowserKernel, - kernel_pid: u32, - ) -> Result<(), BrowserSidecarError> { - kernel - .exit_process(BROWSER_WORKER_DRIVER, kernel_pid, 1) - .map_err(Self::kernel_error)?; - kernel.waitpid(kernel_pid).map_err(Self::kernel_error)?; - Ok(()) - } - - fn reap_execution_kernel_process( - &mut self, - vm_id: &str, - kernel_pid: u32, - ) -> Result<(), BrowserSidecarError> { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(()); - }; - let Some(process) = vm.kernel.list_processes().get(&kernel_pid).cloned() else { - return Ok(()); - }; - - if process.status != ProcessStatus::Exited { - vm.kernel - .exit_process(BROWSER_WORKER_DRIVER, kernel_pid, 1) - .map_err(Self::kernel_error)?; - } - vm.kernel.waitpid(kernel_pid).map_err(Self::kernel_error)?; - Ok(()) - } - - pub fn write_stdin( - &mut self, - request: WriteExecutionStdinRequest, - ) -> Result<(), BrowserSidecarError> { - self.ensure_execution(&request.vm_id, &request.execution_id)?; - let execution = self.ensure_execution_state(&request.vm_id, &request.execution_id)?; - { - let vm = self.vm_mut(&request.vm_id)?; - vm.kernel - .fd_write( - BROWSER_WORKER_DRIVER, - execution.kernel_pid, - execution.stdin_write_fd, - &request.chunk, - ) - .map_err(Self::kernel_error)?; - } - self.bridge.write_stdin(request).map_err(Self::bridge_error) - } - - pub fn close_stdin( - &mut self, - request: ExecutionHandleRequest, - ) -> Result<(), BrowserSidecarError> { - self.ensure_execution(&request.vm_id, &request.execution_id)?; - let execution = self.ensure_execution_state(&request.vm_id, &request.execution_id)?; - { - let vm = self.vm_mut(&request.vm_id)?; - vm.kernel - .fd_close( - BROWSER_WORKER_DRIVER, - execution.kernel_pid, - execution.stdin_write_fd, - ) - .map_err(Self::kernel_error)?; - } - self.bridge.close_stdin(request).map_err(Self::bridge_error) - } - - pub fn kill_execution( - &mut self, - request: KillExecutionRequest, - ) -> Result<(), BrowserSidecarError> { - self.ensure_execution(&request.vm_id, &request.execution_id)?; - self.signal_execution_kernel_process( - &request.vm_id, - &request.execution_id, - secure_exec_sidecar_core::execution_signal_to_kernel(request.signal), - )?; - self.bridge - .kill_execution(request) - .map_err(Self::bridge_error) - } - - pub fn signal_execution_kernel_process( - &mut self, - vm_id: &str, - execution_id: &str, - signal: i32, - ) -> Result<(), BrowserSidecarError> { - self.ensure_execution(vm_id, execution_id)?; - let execution = self.ensure_execution_state(vm_id, execution_id)?; - { - let vm = self.vm_mut(vm_id)?; - vm.kernel - .kill_process(BROWSER_WORKER_DRIVER, execution.kernel_pid, signal) - .map_err(Self::kernel_error)?; - } - Ok(()) - } - - pub fn poll_execution_event( - &mut self, - request: PollExecutionEventRequest, - ) -> Result, BrowserSidecarError> { - self.ensure_vm(&request.vm_id)?; - - let event = self - .bridge - .poll_execution_event(request) - .map_err(Self::bridge_error)?; - - match &event { - Some(ExecutionEvent::Stdout(chunk)) => { - let execution = self.ensure_execution_state(&chunk.vm_id, &chunk.execution_id)?; - let vm = self.vm_mut(&chunk.vm_id)?; - vm.kernel - .write_process_stdout(BROWSER_WORKER_DRIVER, execution.kernel_pid, &chunk.chunk) - .map_err(Self::kernel_error)?; - } - Some(ExecutionEvent::Stderr(chunk)) => { - let execution = self.ensure_execution_state(&chunk.vm_id, &chunk.execution_id)?; - let vm = self.vm_mut(&chunk.vm_id)?; - vm.kernel - .write_process_stderr(BROWSER_WORKER_DRIVER, execution.kernel_pid, &chunk.chunk) - .map_err(Self::kernel_error)?; - } - Some(ExecutionEvent::Exited(exited)) => { - let execution = self.ensure_execution_state(&exited.vm_id, &exited.execution_id)?; - { - let vm = self.vm_mut(&exited.vm_id)?; - vm.kernel - .exit_process( - BROWSER_WORKER_DRIVER, - execution.kernel_pid, - exited.exit_code, - ) - .map_err(Self::kernel_error)?; - } - self.release_execution(&exited.execution_id, "browser.worker.reaped")?; - } - Some(ExecutionEvent::GuestRequest(call)) => { - let fields = unsupported_guest_kernel_call_detail( - None, - &call.execution_id, - &call.operation, - call.payload.len(), - ) - .into_iter() - .collect(); - self.emit_structured( - &call.vm_id, - secure_exec_sidecar_core::UNSUPPORTED_GUEST_KERNEL_CALL_EVENT, - fields, - )?; - } - Some(ExecutionEvent::SignalState(state)) => { - self.ensure_execution_state(&state.vm_id, &state.execution_id)?; - let registration = protocol_signal_registration(&state.registration); - let vm = self.vm_mut(&state.vm_id)?; - apply_process_signal_state_update( - &mut vm.signal_states, - &state.execution_id, - state.signal, - registration, - ); - } - None => {} - } - - Ok(event) - } - - fn register_context( - &mut self, - vm_id: String, - handle: GuestContextHandle, - entrypoint: BrowserWorkerEntrypoint, - ) -> Result<(), BrowserSidecarError> { - self.contexts.insert( - handle.context_id.clone(), - ContextState { - vm_id: vm_id.clone(), - runtime: handle.runtime, - entrypoint, - }, - ); - let vm_state = self - .vms - .get_mut(&vm_id) - .expect("VM should exist while registering a guest context"); - vm_state.contexts.insert(handle.context_id.clone()); - - self.emit_structured( - &vm_id, - "browser.context.created", - BTreeMap::from([ - (String::from("context_id"), handle.context_id), - ( - String::from("runtime"), - runtime_label(handle.runtime).to_string(), - ), - ]), - ) - } - - fn release_execution( - &mut self, - execution_id: &str, - event_name: &'static str, - ) -> Result<(), BrowserSidecarError> { - let Some(execution) = self.executions.remove(execution_id) else { - return Ok(()); - }; - - if let Some(vm_state) = self.vms.get_mut(&execution.vm_id) { - vm_state.active_executions.remove(execution_id); - vm_state.signal_states.remove(execution_id); - } - - let vm_id = execution.vm_id; - self.reap_execution_kernel_process(&vm_id, execution.kernel_pid)?; - let runtime = execution.worker.runtime; - let worker_id = execution.worker.worker_id; - self.bridge - .terminate_worker(BrowserWorkerHandleRequest { - vm_id: vm_id.clone(), - execution_id: execution_id.to_string(), - worker_id: worker_id.clone(), - }) - .map_err(Self::bridge_error)?; - - self.emit_structured( - &vm_id, - event_name, - BTreeMap::from([ - (String::from("execution_id"), execution_id.to_string()), - (String::from("runtime"), runtime_label(runtime).to_string()), - (String::from("worker_id"), worker_id), - ]), - )?; - - let next_state = if self.active_worker_count(&vm_id) == 0 { - LifecycleState::Ready - } else { - LifecycleState::Busy - }; - self.emit_lifecycle( - &vm_id, - next_state, - Some(String::from( - "browser sidecar worker bookkeeping was updated on the main thread", - )), - ) - } - - fn ensure_vm(&self, vm_id: &str) -> Result<(), BrowserSidecarError> { - if self.vms.contains_key(vm_id) { - Ok(()) - } else { - Err(BrowserSidecarError::InvalidState(format!( - "unknown browser sidecar VM: {vm_id}" - ))) - } - } - - fn ensure_execution(&self, vm_id: &str, execution_id: &str) -> Result<(), BrowserSidecarError> { - let execution = self.executions.get(execution_id).ok_or_else(|| { - BrowserSidecarError::InvalidState(format!( - "unknown browser sidecar execution: {execution_id}" - )) - })?; - - if execution.vm_id == vm_id { - Ok(()) - } else { - Err(BrowserSidecarError::InvalidState(format!( - "browser sidecar execution {execution_id} belongs to vm {}, not {vm_id}", - execution.vm_id - ))) - } - } - - fn ensure_execution_state( - &self, - vm_id: &str, - execution_id: &str, - ) -> Result { - let execution = self.executions.get(execution_id).cloned().ok_or_else(|| { - BrowserSidecarError::InvalidState(format!( - "unknown browser sidecar execution: {execution_id}" - )) - })?; - - if execution.vm_id == vm_id { - Ok(execution) - } else { - Err(BrowserSidecarError::InvalidState(format!( - "browser sidecar execution {execution_id} belongs to vm {}, not {vm_id}", - execution.vm_id - ))) - } - } - - fn vm(&self, vm_id: &str) -> Result<&VmState, BrowserSidecarError> { - self.vms.get(vm_id).ok_or_else(|| { - BrowserSidecarError::InvalidState(format!("unknown browser sidecar VM: {vm_id}")) - }) - } - - fn vm_mut(&mut self, vm_id: &str) -> Result<&mut VmState, BrowserSidecarError> { - self.vms.get_mut(vm_id).ok_or_else(|| { - BrowserSidecarError::InvalidState(format!("unknown browser sidecar VM: {vm_id}")) - }) - } - - fn emit_lifecycle( - &mut self, - vm_id: &str, - state: LifecycleState, - detail: Option, - ) -> Result<(), BrowserSidecarError> { - self.bridge - .emit_lifecycle(LifecycleEventRecord { - vm_id: vm_id.to_string(), - state, - detail, - }) - .map_err(Self::bridge_error) - } - - fn emit_structured( - &mut self, - vm_id: &str, - name: &str, - fields: BTreeMap, - ) -> Result<(), BrowserSidecarError> { - self.bridge - .emit_structured_event(StructuredEventRecord { - vm_id: vm_id.to_string(), - name: name.to_string(), - fields, - }) - .map_err(Self::bridge_error) - } - - fn bridge_error(error: BridgeError) -> BrowserSidecarError { - BrowserSidecarError::Bridge(format!("{error:?}")) - } - - fn sidecar_core_error( - error: secure_exec_sidecar_core::SidecarCoreError, - ) -> BrowserSidecarError { - BrowserSidecarError::InvalidState(error.to_string()) - } - - fn kernel_error(error: KernelError) -> BrowserSidecarError { - BrowserSidecarError::Kernel(error.to_string()) - } - - fn apply_root_filesystem_entry( - &mut self, - vm_id: &str, - entry: &RootFilesystemEntry, - ) -> Result<(), BrowserSidecarError> { - // Shared with native: write the bootstrap entry through the VM's filesystem - // (trusted, pre-guest; permissions default to allow at bootstrap time) with - // deterministic mode/uid/gid defaults — see sidecar-core::apply_root_filesystem_entry. - let filesystem = self.vm_mut(vm_id)?.kernel.filesystem_mut(); - secure_exec_sidecar_core::apply_root_filesystem_entry(filesystem, entry) - .map_err(Self::sidecar_core_error) - } -} - -fn root_snapshot_from_entries( - entries: &[RootFilesystemEntry], -) -> Result { - // Shared with native (sidecar-core): protocol entries -> kernel snapshot. - secure_exec_sidecar_core::root_snapshot_from_entries(entries) - .map_err(|error| BrowserSidecarError::InvalidState(error.to_string())) -} - -#[cfg(not(target_arch = "wasm32"))] -fn browser_vm_fetch_timeout() -> Duration { - std::env::var(BROWSER_VM_FETCH_TIMEOUT_MS_ENV) - .ok() - .and_then(|value| value.parse::().ok()) - .map(Duration::from_millis) - .unwrap_or(BROWSER_VM_FETCH_TIMEOUT) -} - -#[cfg(target_arch = "wasm32")] -fn browser_vm_fetch_timeout() -> Duration { - BROWSER_VM_FETCH_TIMEOUT -} - -fn socket_host_matches(requested: Option<&str>, actual: &str) -> bool { - match requested { - None => true, - Some(requested) if requested == actual => true, - Some(requested) - if is_unspecified_socket_host(requested) && is_unspecified_socket_host(actual) => - { - true - } - Some(requested) if is_unspecified_socket_host(requested) => is_loopback_socket_host(actual), - Some(requested) if requested.eq_ignore_ascii_case("localhost") => { - is_loopback_socket_host(actual) - } - _ => false, - } -} - -fn is_unspecified_socket_host(host: &str) -> bool { - host == "0.0.0.0" || host == "::" -} - -fn is_loopback_socket_host(host: &str) -> bool { - host == "127.0.0.1" || host == "::1" || host.eq_ignore_ascii_case("localhost") -} - -impl BrowserExtensionHost for BrowserSidecar -where - B: BrowserSidecarBridge, - BridgeError: fmt::Debug, -{ - fn write_file( - &mut self, - vm_id: &str, - path: &str, - contents: Vec, - ) -> Result<(), BrowserSidecarError> { - BrowserSidecar::write_file(self, vm_id, path, contents) - } - - fn read_file(&mut self, vm_id: &str, path: &str) -> Result, BrowserSidecarError> { - BrowserSidecar::read_file(self, vm_id, path) - } - - fn mkdir( - &mut self, - vm_id: &str, - path: &str, - recursive: bool, - ) -> Result<(), BrowserSidecarError> { - BrowserSidecar::mkdir(self, vm_id, path, recursive) - } - - fn read_dir(&mut self, vm_id: &str, path: &str) -> Result, BrowserSidecarError> { - BrowserSidecar::read_dir(self, vm_id, path) - } - - fn create_javascript_context( - &mut self, - request: CreateJavascriptContextRequest, - ) -> Result { - BrowserSidecar::create_javascript_context(self, request) - } - - fn create_wasm_context( - &mut self, - request: CreateWasmContextRequest, - ) -> Result { - BrowserSidecar::create_wasm_context(self, request) - } - - fn start_execution( - &mut self, - request: StartExecutionRequest, - ) -> Result { - BrowserSidecar::start_execution(self, request) - } - - fn write_stdin( - &mut self, - request: WriteExecutionStdinRequest, - ) -> Result<(), BrowserSidecarError> { - BrowserSidecar::write_stdin(self, request) - } - - fn close_stdin(&mut self, request: ExecutionHandleRequest) -> Result<(), BrowserSidecarError> { - BrowserSidecar::close_stdin(self, request) - } - - fn kill_execution(&mut self, request: KillExecutionRequest) -> Result<(), BrowserSidecarError> { - BrowserSidecar::kill_execution(self, request) - } - - fn poll_execution_event( - &mut self, - request: PollExecutionEventRequest, - ) -> Result, BrowserSidecarError> { - BrowserSidecar::poll_execution_event(self, request) - } -} - -fn runtime_label(runtime: GuestRuntime) -> &'static str { - match runtime { - GuestRuntime::JavaScript => "javascript", - GuestRuntime::WebAssembly => "webassembly", - } -} - -fn protocol_signal_registration( - registration: &SignalHandlerRegistration, -) -> ProtocolSignalHandlerRegistration { - ProtocolSignalHandlerRegistration { - action: match registration.action { - SignalDispositionAction::Default => ProtocolSignalDispositionAction::Default, - SignalDispositionAction::Ignore => ProtocolSignalDispositionAction::Ignore, - SignalDispositionAction::User => ProtocolSignalDispositionAction::User, - }, - mask: registration.mask.clone(), - flags: registration.flags, - } -} - -#[cfg(test)] -impl BrowserSidecar -where - B: BrowserSidecarBridge, - BridgeError: fmt::Debug, -{ - /// Test-only: number of entries still tracked in the global `contexts` map. - pub(crate) fn test_total_context_count(&self) -> usize { - self.contexts.len() - } - - /// Test-only: number of entries still tracked in the global `executions` map. - pub(crate) fn test_total_execution_count(&self) -> usize { - self.executions.len() - } - - /// Test-only: inject a context directly into both the global `contexts` map - /// and the owning VM's context set, bypassing the bridge round-trip so a - /// dispose-path test can exercise cleanup at the smallest seam. - pub(crate) fn test_insert_context(&mut self, vm_id: &str, context_id: &str) { - self.contexts.insert( - context_id.to_string(), - ContextState { - vm_id: vm_id.to_string(), - runtime: GuestRuntime::JavaScript, - entrypoint: BrowserWorkerEntrypoint::JavaScript { - bootstrap_module: None, - }, - }, - ); - if let Some(vm) = self.vms.get_mut(vm_id) { - vm.contexts.insert(context_id.to_string()); - } - } - - /// Test-only: inject an active execution directly into both the global - /// `executions` map and the owning VM's active-execution set. - pub(crate) fn test_insert_execution(&mut self, vm_id: &str, execution_id: &str) { - self.executions.insert( - execution_id.to_string(), - ExecutionState { - vm_id: vm_id.to_string(), - worker: BrowserWorkerHandle { - worker_id: format!("worker-{execution_id}"), - runtime: GuestRuntime::JavaScript, - }, - kernel_pid: 0, - stdin_write_fd: 0, - cwd: String::new(), - }, - ); - if let Some(vm) = self.vms.get_mut(vm_id) { - vm.active_executions.insert(execution_id.to_string()); - } - } -} - -#[cfg(test)] -#[allow(clippy::items_after_test_module)] // browser_worker_identity below is shared with the worker shim -mod tests { - use super::*; - use secure_exec_bridge::{ - ChmodRequest, ClockRequest, CommandPermissionRequest, CreateDirRequest, DiagnosticRecord, - DirectoryEntry, EnvironmentPermissionRequest, ExecutionHandleRequest, FileMetadata, - FilesystemPermissionRequest, FilesystemSnapshot, FlushFilesystemStateRequest, - LoadFilesystemStateRequest, LogRecord, NetworkPermissionRequest, PathRequest, - PermissionDecision, RandomBytesRequest, ReadDirRequest, ReadFileRequest, RenameRequest, - ScheduleTimerRequest, ScheduledTimer, SymlinkRequest, TruncateRequest, WriteFileRequest, - }; - use secure_exec_bridge::{ - ClockBridge, EventBridge, ExecutionBridge, FilesystemBridge, PermissionBridge, - PersistenceBridge, RandomBridge, - }; - use secure_exec_kernel::kernel::KernelVmConfig; - use std::time::SystemTime; - - #[derive(Debug, Clone, PartialEq, Eq)] - struct TestBridgeError(String); - - /// Minimal bridge whose `terminate_worker` can be forced to fail, used to - /// drive a mid-dispose error through `release_execution`. - #[derive(Default)] - struct TerminateFailingBridge { - fail_terminate: bool, - } - - impl BridgeTypes for TerminateFailingBridge { - type Error = TestBridgeError; - } - - impl FilesystemBridge for TerminateFailingBridge { - fn read_file(&mut self, _request: ReadFileRequest) -> Result, Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn write_file(&mut self, _request: WriteFileRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn stat(&mut self, _request: PathRequest) -> Result { - unimplemented!("not exercised by dispose test") - } - fn lstat(&mut self, _request: PathRequest) -> Result { - unimplemented!("not exercised by dispose test") - } - fn read_dir( - &mut self, - _request: ReadDirRequest, - ) -> Result, Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn create_dir(&mut self, _request: CreateDirRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn remove_file(&mut self, _request: PathRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn remove_dir(&mut self, _request: PathRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn rename(&mut self, _request: RenameRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn symlink(&mut self, _request: SymlinkRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn read_link(&mut self, _request: PathRequest) -> Result { - unimplemented!("not exercised by dispose test") - } - fn chmod(&mut self, _request: ChmodRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn truncate(&mut self, _request: TruncateRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn exists(&mut self, _request: PathRequest) -> Result { - unimplemented!("not exercised by dispose test") - } - } - - impl PermissionBridge for TerminateFailingBridge { - fn check_filesystem_access( - &mut self, - _request: FilesystemPermissionRequest, - ) -> Result { - unimplemented!("not exercised by dispose test") - } - fn check_network_access( - &mut self, - _request: NetworkPermissionRequest, - ) -> Result { - unimplemented!("not exercised by dispose test") - } - fn check_command_execution( - &mut self, - _request: CommandPermissionRequest, - ) -> Result { - unimplemented!("not exercised by dispose test") - } - fn check_environment_access( - &mut self, - _request: EnvironmentPermissionRequest, - ) -> Result { - unimplemented!("not exercised by dispose test") - } - } - - impl PersistenceBridge for TerminateFailingBridge { - fn load_filesystem_state( - &mut self, - _request: LoadFilesystemStateRequest, - ) -> Result, Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn flush_filesystem_state( - &mut self, - _request: FlushFilesystemStateRequest, - ) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - } - - impl ClockBridge for TerminateFailingBridge { - fn wall_clock(&mut self, _request: ClockRequest) -> Result { - unimplemented!("not exercised by dispose test") - } - fn monotonic_clock(&mut self, _request: ClockRequest) -> Result { - unimplemented!("not exercised by dispose test") - } - fn schedule_timer( - &mut self, - _request: ScheduleTimerRequest, - ) -> Result { - unimplemented!("not exercised by dispose test") - } - } - - impl RandomBridge for TerminateFailingBridge { - fn fill_random_bytes( - &mut self, - _request: RandomBytesRequest, - ) -> Result, Self::Error> { - unimplemented!("not exercised by dispose test") - } - } - - impl EventBridge for TerminateFailingBridge { - fn emit_structured_event( - &mut self, - _event: StructuredEventRecord, - ) -> Result<(), Self::Error> { - Ok(()) - } - fn emit_diagnostic(&mut self, _event: DiagnosticRecord) -> Result<(), Self::Error> { - Ok(()) - } - fn emit_log(&mut self, _event: LogRecord) -> Result<(), Self::Error> { - Ok(()) - } - fn emit_lifecycle(&mut self, _event: LifecycleEventRecord) -> Result<(), Self::Error> { - Ok(()) - } - } - - impl ExecutionBridge for TerminateFailingBridge { - fn create_javascript_context( - &mut self, - _request: CreateJavascriptContextRequest, - ) -> Result { - unimplemented!("not exercised by dispose test") - } - fn create_wasm_context( - &mut self, - _request: CreateWasmContextRequest, - ) -> Result { - unimplemented!("not exercised by dispose test") - } - fn start_execution( - &mut self, - _request: StartExecutionRequest, - ) -> Result { - unimplemented!("not exercised by dispose test") - } - fn write_stdin(&mut self, _request: WriteExecutionStdinRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn close_stdin(&mut self, _request: ExecutionHandleRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn kill_execution(&mut self, _request: KillExecutionRequest) -> Result<(), Self::Error> { - unimplemented!("not exercised by dispose test") - } - fn poll_execution_event( - &mut self, - _request: PollExecutionEventRequest, - ) -> Result, Self::Error> { - unimplemented!("not exercised by dispose test") - } - } - - impl crate::BrowserWorkerBridge for TerminateFailingBridge { - fn create_worker( - &mut self, - _request: BrowserWorkerSpawnRequest, - ) -> Result { - unimplemented!("not exercised by dispose test") - } - - fn terminate_worker( - &mut self, - _request: BrowserWorkerHandleRequest, - ) -> Result<(), Self::Error> { - if self.fail_terminate { - Err(TestBridgeError(String::from("forced terminate failure"))) - } else { - Ok(()) - } - } - } - - // A mid-dispose worker-termination failure must still drain the VM, context, - // and execution bookkeeping for that id — otherwise the VmState (holding a - // BrowserKernel) and ContextState leak for the process lifetime. - #[test] - fn dispose_vm_drains_maps_even_when_worker_termination_fails() { - let bridge = TerminateFailingBridge { - fail_terminate: true, - }; - let mut sidecar = BrowserSidecar::new(bridge, BrowserSidecarConfig::default()); - - sidecar - .create_vm(KernelVmConfig::new("vm-leak")) - .expect("create vm"); - sidecar.test_insert_context("vm-leak", "ctx-leak"); - sidecar.test_insert_execution("vm-leak", "exec-leak"); - - assert_eq!(sidecar.vm_count(), 1); - assert_eq!(sidecar.test_total_context_count(), 1); - assert_eq!(sidecar.test_total_execution_count(), 1); - - // The forced terminate_worker failure surfaces as an error, but the - // dispose must still have reclaimed every entry for `vm-leak`. - let result = sidecar.dispose_vm("vm-leak"); - assert!(result.is_err(), "forced terminate failure should surface"); - - assert_eq!(sidecar.vm_count(), 0, "VmState leaked after failed dispose"); - assert_eq!( - sidecar.test_total_context_count(), - 0, - "ContextState leaked after failed dispose" - ); - assert_eq!( - sidecar.test_total_execution_count(), - 0, - "ExecutionState leaked after failed dispose" - ); - } -} - -fn browser_worker_identity( - kernel: &BrowserKernel, - request: &StartExecutionRequest, - kernel_pid: u32, -) -> (BrowserWorkerProcessConfig, BrowserWorkerOsConfig) { - let mut env = kernel.environment().clone(); - env.extend(request.env.clone()); - let user = kernel.user_profile(); - let resource_limits = kernel.resource_limits(); - let identity = - shared_guest_runtime_identity(&user, resource_limits, Some(u64::from(kernel_pid)), Some(0)); - - ( - BrowserWorkerProcessConfig { - cwd: request.cwd.clone(), - env, - argv: request.argv.clone(), - platform: identity.process_platform.clone(), - arch: identity.process_arch.clone(), - version: String::from("v22.0.0"), - pid: kernel_pid, - ppid: 0, - uid: identity.virtual_uid as u32, - gid: identity.virtual_gid as u32, - }, - BrowserWorkerOsConfig { - platform: identity.process_platform, - arch: identity.process_arch.clone(), - r#type: identity.os_type, - release: identity.os_release, - version: identity.os_version, - cpu_count: identity.os_cpu_count, - totalmem: identity.os_totalmem, - freemem: identity.os_freemem, - hostname: identity.os_hostname, - homedir: identity.os_homedir, - tmpdir: identity.os_tmpdir, - machine: identity.os_machine, - user: identity.os_user, - shell: identity.os_shell, - uid: identity.virtual_uid as u32, - gid: identity.virtual_gid as u32, - }, - ) -} diff --git a/crates/sidecar-browser/src/wasm.rs b/crates/sidecar-browser/src/wasm.rs deleted file mode 100644 index 634491a9d..000000000 --- a/crates/sidecar-browser/src/wasm.rs +++ /dev/null @@ -1,924 +0,0 @@ -use crate::wire_dispatch::{BrowserWireDispatcher, BROWSER_SIDECAR_ID}; -use crate::{ - BrowserWorkerBridge, BrowserWorkerEntrypoint, BrowserWorkerHandle, BrowserWorkerHandleRequest, - BrowserWorkerOsConfig, BrowserWorkerProcessConfig, BrowserWorkerSpawnRequest, -}; -use base64::Engine; -use js_sys::{Error as JsError, Function, Reflect, Uint8Array, JSON}; -use secure_exec_bridge::{ - BridgeTypes, ChmodRequest, ClockBridge, ClockRequest, CommandPermissionRequest, - CreateDirRequest, CreateJavascriptContextRequest, CreateWasmContextRequest, DiagnosticRecord, - DirectoryEntry, EnvironmentAccess, EnvironmentPermissionRequest, EventBridge, ExecutionBridge, - ExecutionEvent, ExecutionExited, ExecutionHandleRequest, ExecutionSignal, ExecutionSignalState, - FileKind, FileMetadata, FilesystemAccess, FilesystemBridge, FilesystemPermissionRequest, - FilesystemSnapshot, FlushFilesystemStateRequest, GuestContextHandle, GuestKernelCall, - GuestRuntime, KillExecutionRequest, LifecycleEventRecord, LoadFilesystemStateRequest, LogLevel, - LogRecord, NetworkAccess, NetworkPermissionRequest, OutputChunk, PathRequest, PermissionBridge, - PermissionDecision, PermissionVerdict, PersistenceBridge, PollExecutionEventRequest, - RandomBridge, RandomBytesRequest, ReadDirRequest, ReadFileRequest, RenameRequest, - ScheduleTimerRequest, ScheduledTimer, SignalDispositionAction, SignalHandlerRegistration, - StartExecutionRequest, StartedExecution, StructuredEventRecord, SymlinkRequest, - TruncateRequest, WriteExecutionStdinRequest, WriteFileRequest, -}; -use secure_exec_sidecar_protocol::wire::WasmPermissionTier; -use serde_json::{json, Value}; -use std::collections::BTreeMap; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use wasm_bindgen::prelude::*; -use wasm_bindgen::JsCast; - -#[wasm_bindgen] -pub struct BrowserSidecarWasm { - dispatcher: BrowserWireDispatcher, -} - -#[wasm_bindgen] -impl BrowserSidecarWasm { - #[wasm_bindgen(constructor)] - pub fn new(host_bridge: Option) -> Self { - Self { - dispatcher: BrowserWireDispatcher::new(BrowserJsBridge::new(host_bridge)), - } - } - - #[wasm_bindgen(getter, js_name = sidecarId)] - pub fn sidecar_id(&self) -> String { - String::from(BROWSER_SIDECAR_ID) - } - - #[wasm_bindgen(js_name = pushFrame)] - pub fn push_frame(&mut self, frame: Uint8Array) -> Result { - let bytes = frame.to_vec(); - let response = self - .dispatcher - .handle_request_bytes(&bytes) - .map_err(js_error)?; - Ok(Uint8Array::from(response.as_slice()).into()) - } - - #[wasm_bindgen(js_name = pollEvent)] - pub fn poll_event(&mut self) -> Result { - match self.dispatcher.poll_event_bytes().map_err(js_error)? { - Some(event) => Ok(Uint8Array::from(event.as_slice()).into()), - None => Ok(JsValue::NULL), - } - } -} - -impl Default for BrowserSidecarWasm { - fn default() -> Self { - Self::new(None) - } -} - -fn js_error(error: impl ToString) -> JsValue { - JsError::new(&error.to_string()).into() -} - -/// The wasm-side host bridge: marshals every kernel/host operation to the JS host -/// object installed in the Worker. Exported so wrapper crates (e.g. Agent OS) can -/// build their own `#[wasm_bindgen]` entry over `BrowserWireDispatcher` while -/// registering their own `BrowserExtension`s, instead of re-implementing the bridge. -#[derive(Clone, Debug)] -pub struct BrowserJsBridge { - host: Option, - next_timer: u64, -} - -impl BrowserJsBridge { - pub fn new(host: Option) -> Self { - Self { - host: host.filter(|value| !value.is_null() && !value.is_undefined()), - next_timer: 0, - } - } - - fn unsupported(&self, operation: &str) -> Result { - Err(format!( - "{operation} is not available because no browser sidecar host bridge method is installed" - )) - } - - fn call(&self, method: &str, request: Value) -> Result { - let Some(host) = &self.host else { - return self.unsupported(method); - }; - let function = Reflect::get(host, &JsValue::from_str(method)) - .map_err(format_js_error)? - .dyn_into::() - .map_err(|_| { - format!("browser sidecar host bridge method {method} is not a function") - })?; - let request = serde_json::to_string(&request) - .map_err(|error| format!("serialize {method} request: {error}"))?; - function - .call1(host, &JsValue::from_str(&request)) - .map_err(format_js_error) - } - - fn call_void(&self, method: &str, request: Value) -> Result<(), String> { - let _ = self.call(method, request)?; - Ok(()) - } - - fn call_json(&self, method: &str, request: Value) -> Result { - js_value_to_json(self.call(method, request)?) - } - - fn call_bytes(&self, method: &str, request: Value) -> Result, String> { - let value = self.call(method, request)?; - if value.is_null() || value.is_undefined() { - return Ok(Vec::new()); - } - if value.is_instance_of::() { - return Ok(Uint8Array::new(&value).to_vec()); - } - if let Some(encoded) = value.as_string() { - return base64::engine::general_purpose::STANDARD - .decode(encoded) - .map_err(|error| format!("{method} returned invalid base64: {error}")); - } - Err(format!( - "{method} must return Uint8Array, base64 string, null, or undefined" - )) - } -} - -fn format_js_error(error: JsValue) -> String { - if let Some(message) = Reflect::get(&error, &JsValue::from_str("message")) - .ok() - .and_then(|value| value.as_string()) - { - return message; - } - error - .as_string() - .unwrap_or_else(|| String::from("JavaScript error")) -} - -fn js_value_to_json(value: JsValue) -> Result { - if value.is_undefined() || value.is_null() { - return Ok(Value::Null); - } - if let Some(text) = value.as_string() { - return serde_json::from_str(&text).map_err(|error| format!("parse JSON string: {error}")); - } - let text = JSON::stringify(&value) - .map_err(format_js_error)? - .as_string() - .ok_or_else(|| String::from("JSON.stringify returned a non-string value"))?; - serde_json::from_str(&text).map_err(|error| format!("parse JSON value: {error}")) -} - -fn get_string(value: &Value, key: &str) -> Result { - value - .get(key) - .and_then(Value::as_str) - .map(ToOwned::to_owned) - .ok_or_else(|| format!("missing string field '{key}'")) -} - -fn get_optional_string(value: &Value, key: &str) -> Option { - value - .get(key) - .and_then(Value::as_str) - .map(ToOwned::to_owned) -} - -fn get_u64(value: &Value, key: &str) -> Result { - value - .get(key) - .and_then(Value::as_u64) - .ok_or_else(|| format!("missing u64 field '{key}'")) -} - -fn get_i32(value: &Value, key: &str) -> Result { - value - .get(key) - .and_then(Value::as_i64) - .and_then(|number| i32::try_from(number).ok()) - .ok_or_else(|| format!("missing i32 field '{key}'")) -} - -fn base_request(vm_id: impl Into) -> Value { - json!({ "vmId": vm_id.into() }) -} - -fn path_request(request: PathRequest) -> Value { - json!({ "vmId": request.vm_id, "path": request.path }) -} - -fn file_kind_from_json(value: &Value) -> Result { - match value.as_str().unwrap_or("other") { - "file" => Ok(FileKind::File), - "directory" => Ok(FileKind::Directory), - "symbolicLink" | "symlink" => Ok(FileKind::SymbolicLink), - "other" => Ok(FileKind::Other), - kind => Err(format!("unknown file kind '{kind}'")), - } -} - -fn metadata_from_json(value: Value) -> Result { - Ok(FileMetadata { - mode: u32::try_from(get_u64(&value, "mode")?) - .map_err(|_| String::from("metadata mode exceeds u32"))?, - size: get_u64(&value, "size")?, - kind: file_kind_from_json(value.get("kind").unwrap_or(&Value::Null))?, - }) -} - -fn directory_entries_from_json(value: Value) -> Result, String> { - let entries = value - .as_array() - .ok_or_else(|| String::from("readDir response must be an array"))?; - entries - .iter() - .map(|entry| { - Ok(DirectoryEntry { - name: get_string(entry, "name")?, - kind: file_kind_from_json(entry.get("kind").unwrap_or(&Value::Null))?, - }) - }) - .collect() -} - -fn permission_decision_from_json(value: Value) -> Result { - let verdict = match value - .get("verdict") - .and_then(Value::as_str) - .unwrap_or("deny") - { - "allow" => PermissionVerdict::Allow, - "deny" => PermissionVerdict::Deny, - "prompt" => PermissionVerdict::Prompt, - verdict => return Err(format!("unknown permission verdict '{verdict}'")), - }; - Ok(PermissionDecision { - verdict, - reason: get_optional_string(&value, "reason"), - }) -} - -fn filesystem_access_to_json(access: FilesystemAccess) -> &'static str { - match access { - FilesystemAccess::Read => "read", - FilesystemAccess::Write => "write", - FilesystemAccess::Stat => "stat", - FilesystemAccess::ReadDir => "readDir", - FilesystemAccess::CreateDir => "createDir", - FilesystemAccess::Remove => "remove", - FilesystemAccess::Rename => "rename", - FilesystemAccess::Symlink => "symlink", - FilesystemAccess::ReadLink => "readLink", - FilesystemAccess::Chmod => "chmod", - FilesystemAccess::Truncate => "truncate", - } -} - -fn network_access_to_json(access: NetworkAccess) -> &'static str { - match access { - NetworkAccess::Fetch => "fetch", - NetworkAccess::Http => "http", - NetworkAccess::Dns => "dns", - NetworkAccess::Listen => "listen", - } -} - -fn environment_access_to_json(access: EnvironmentAccess) -> &'static str { - match access { - EnvironmentAccess::Read => "read", - EnvironmentAccess::Write => "write", - } -} - -fn log_level_to_json(level: LogLevel) -> &'static str { - match level { - LogLevel::Trace => "trace", - LogLevel::Debug => "debug", - LogLevel::Info => "info", - LogLevel::Warn => "warn", - LogLevel::Error => "error", - } -} - -fn guest_runtime_to_json(runtime: GuestRuntime) -> &'static str { - match runtime { - GuestRuntime::JavaScript => "javascript", - GuestRuntime::WebAssembly => "webassembly", - } -} - -fn guest_runtime_from_json(value: &Value) -> Result { - match value.as_str().unwrap_or("javascript") { - "javascript" | "js" => Ok(GuestRuntime::JavaScript), - "webassembly" | "wasm" => Ok(GuestRuntime::WebAssembly), - runtime => Err(format!("unknown guest runtime '{runtime}'")), - } -} - -fn signal_to_json(signal: ExecutionSignal) -> &'static str { - match signal { - ExecutionSignal::Terminate => "terminate", - ExecutionSignal::Interrupt => "interrupt", - ExecutionSignal::Kill => "kill", - } -} - -fn signal_action_from_json(value: &Value) -> Result { - match value.as_str().unwrap_or("default") { - "default" => Ok(SignalDispositionAction::Default), - "ignore" => Ok(SignalDispositionAction::Ignore), - "user" => Ok(SignalDispositionAction::User), - action => Err(format!("unknown signal disposition action '{action}'")), - } -} - -fn signal_registration_from_json(value: &Value) -> Result { - let mask = value - .get("mask") - .and_then(Value::as_array) - .map(|entries| { - entries - .iter() - .map(|entry| { - entry - .as_u64() - .and_then(|number| u32::try_from(number).ok()) - .ok_or_else(|| String::from("invalid signal mask entry")) - }) - .collect::, _>>() - }) - .transpose()? - .unwrap_or_default(); - Ok(SignalHandlerRegistration { - action: signal_action_from_json(value.get("action").unwrap_or(&Value::Null))?, - mask, - flags: value - .get("flags") - .and_then(Value::as_u64) - .and_then(|number| u32::try_from(number).ok()) - .unwrap_or(0), - }) -} - -fn system_time_from_ms(ms: u64) -> SystemTime { - UNIX_EPOCH + Duration::from_millis(ms) -} - -fn map_to_json(map: BTreeMap) -> Value { - Value::Object( - map.into_iter() - .map(|(key, value)| (key, Value::String(value))) - .collect(), - ) -} - -fn snapshot_to_json(snapshot: FilesystemSnapshot) -> Value { - json!({ - "format": snapshot.format, - "bytesBase64": base64::engine::general_purpose::STANDARD.encode(snapshot.bytes), - }) -} - -fn snapshot_from_json(value: &Value) -> Result { - Ok(FilesystemSnapshot { - format: get_string(value, "format")?, - bytes: base64::engine::general_purpose::STANDARD - .decode(get_string(value, "bytesBase64")?) - .map_err(|error| format!("invalid filesystem snapshot bytes: {error}"))?, - }) -} - -fn output_chunk_from_json(value: &Value) -> Result { - Ok(OutputChunk { - vm_id: get_string(value, "vmId")?, - execution_id: get_string(value, "executionId")?, - chunk: base64::engine::general_purpose::STANDARD - .decode(get_string(value, "chunkBase64")?) - .map_err(|error| format!("invalid output chunk bytes: {error}"))?, - }) -} - -fn execution_event_from_json(value: Value) -> Result, String> { - if value.is_null() { - return Ok(None); - } - match value.get("type").and_then(Value::as_str).unwrap_or("") { - "stdout" => Ok(Some(ExecutionEvent::Stdout(output_chunk_from_json( - &value, - )?))), - "stderr" => Ok(Some(ExecutionEvent::Stderr(output_chunk_from_json( - &value, - )?))), - "exited" => Ok(Some(ExecutionEvent::Exited(ExecutionExited { - vm_id: get_string(&value, "vmId")?, - execution_id: get_string(&value, "executionId")?, - exit_code: get_i32(&value, "exitCode")?, - }))), - "guestRequest" => Ok(Some(ExecutionEvent::GuestRequest(GuestKernelCall { - vm_id: get_string(&value, "vmId")?, - execution_id: get_string(&value, "executionId")?, - operation: get_string(&value, "operation")?, - payload: base64::engine::general_purpose::STANDARD - .decode(get_string(&value, "payloadBase64")?) - .map_err(|error| format!("invalid guest request payload: {error}"))?, - }))), - "signalState" => Ok(Some(ExecutionEvent::SignalState(ExecutionSignalState { - vm_id: get_string(&value, "vmId")?, - execution_id: get_string(&value, "executionId")?, - signal: u32::try_from(get_u64(&value, "signal")?) - .map_err(|_| String::from("signal exceeds u32"))?, - registration: signal_registration_from_json( - value.get("registration").unwrap_or(&Value::Null), - )?, - }))), - event_type => Err(format!("unknown execution event type '{event_type}'")), - } -} - -fn worker_entrypoint_to_json(entrypoint: BrowserWorkerEntrypoint) -> Value { - match entrypoint { - BrowserWorkerEntrypoint::JavaScript { bootstrap_module } => { - json!({ "kind": "javascript", "bootstrapModule": bootstrap_module }) - } - BrowserWorkerEntrypoint::WebAssembly { module_path } => { - json!({ "kind": "webassembly", "modulePath": module_path }) - } - } -} - -fn process_config_to_json(config: BrowserWorkerProcessConfig) -> Value { - json!({ - "cwd": config.cwd, - "env": map_to_json(config.env), - "argv": config.argv, - "platform": config.platform, - "arch": config.arch, - "version": config.version, - "pid": config.pid, - "ppid": config.ppid, - "uid": config.uid, - "gid": config.gid, - }) -} - -fn os_config_to_json(config: BrowserWorkerOsConfig) -> Value { - json!({ - "platform": config.platform, - "arch": config.arch, - "type": config.r#type, - "release": config.release, - "version": config.version, - "cpuCount": config.cpu_count, - "totalmem": config.totalmem, - "freemem": config.freemem, - "hostname": config.hostname, - "homedir": config.homedir, - "tmpdir": config.tmpdir, - "machine": config.machine, - "user": config.user, - "shell": config.shell, - "uid": config.uid, - "gid": config.gid, - }) -} - -fn wasm_permission_tier_to_json(tier: Option) -> Value { - tier.map(|tier| Value::String(format!("{tier:?}").to_ascii_lowercase())) - .unwrap_or(Value::Null) -} - -impl BridgeTypes for BrowserJsBridge { - type Error = String; -} - -impl FilesystemBridge for BrowserJsBridge { - fn read_file(&mut self, request: ReadFileRequest) -> Result, Self::Error> { - self.call_bytes( - "readFile", - json!({ "vmId": request.vm_id, "path": request.path }), - ) - } - - fn write_file(&mut self, request: WriteFileRequest) -> Result<(), Self::Error> { - self.call_void( - "writeFile", - json!({ - "vmId": request.vm_id, - "path": request.path, - "contentsBase64": base64::engine::general_purpose::STANDARD.encode(request.contents), - }), - ) - } - - fn stat(&mut self, request: PathRequest) -> Result { - metadata_from_json(self.call_json("stat", path_request(request))?) - } - - fn lstat(&mut self, request: PathRequest) -> Result { - metadata_from_json(self.call_json("lstat", path_request(request))?) - } - - fn read_dir(&mut self, request: ReadDirRequest) -> Result, Self::Error> { - directory_entries_from_json(self.call_json( - "readDir", - json!({ "vmId": request.vm_id, "path": request.path }), - )?) - } - - fn create_dir(&mut self, request: CreateDirRequest) -> Result<(), Self::Error> { - self.call_void( - "createDir", - json!({ "vmId": request.vm_id, "path": request.path, "recursive": request.recursive }), - ) - } - - fn remove_file(&mut self, request: PathRequest) -> Result<(), Self::Error> { - self.call_void("removeFile", path_request(request)) - } - - fn remove_dir(&mut self, request: PathRequest) -> Result<(), Self::Error> { - self.call_void("removeDir", path_request(request)) - } - - fn rename(&mut self, request: RenameRequest) -> Result<(), Self::Error> { - self.call_void( - "rename", - json!({ - "vmId": request.vm_id, - "fromPath": request.from_path, - "toPath": request.to_path, - }), - ) - } - - fn symlink(&mut self, request: SymlinkRequest) -> Result<(), Self::Error> { - self.call_void( - "symlink", - json!({ - "vmId": request.vm_id, - "targetPath": request.target_path, - "linkPath": request.link_path, - }), - ) - } - - fn read_link(&mut self, request: PathRequest) -> Result { - get_string( - &self.call_json("readLink", path_request(request))?, - "targetPath", - ) - } - - fn chmod(&mut self, request: ChmodRequest) -> Result<(), Self::Error> { - self.call_void( - "chmod", - json!({ "vmId": request.vm_id, "path": request.path, "mode": request.mode }), - ) - } - - fn truncate(&mut self, request: TruncateRequest) -> Result<(), Self::Error> { - self.call_void( - "truncate", - json!({ "vmId": request.vm_id, "path": request.path, "len": request.len }), - ) - } - - fn exists(&mut self, request: PathRequest) -> Result { - self.call_json("exists", path_request(request))? - .as_bool() - .ok_or_else(|| String::from("exists response must be boolean")) - } -} - -impl PermissionBridge for BrowserJsBridge { - fn check_filesystem_access( - &mut self, - request: FilesystemPermissionRequest, - ) -> Result { - permission_decision_from_json(self.call_json( - "checkFilesystemAccess", - json!({ - "vmId": request.vm_id, - "path": request.path, - "access": filesystem_access_to_json(request.access), - }), - )?) - } - - fn check_network_access( - &mut self, - request: NetworkPermissionRequest, - ) -> Result { - permission_decision_from_json(self.call_json( - "checkNetworkAccess", - json!({ - "vmId": request.vm_id, - "access": network_access_to_json(request.access), - "resource": request.resource, - }), - )?) - } - - fn check_command_execution( - &mut self, - request: CommandPermissionRequest, - ) -> Result { - permission_decision_from_json(self.call_json( - "checkCommandExecution", - json!({ - "vmId": request.vm_id, - "command": request.command, - "args": request.args, - "cwd": request.cwd, - "env": map_to_json(request.env), - }), - )?) - } - - fn check_environment_access( - &mut self, - request: EnvironmentPermissionRequest, - ) -> Result { - permission_decision_from_json(self.call_json( - "checkEnvironmentAccess", - json!({ - "vmId": request.vm_id, - "access": environment_access_to_json(request.access), - "key": request.key, - "value": request.value, - }), - )?) - } -} - -impl PersistenceBridge for BrowserJsBridge { - fn load_filesystem_state( - &mut self, - request: LoadFilesystemStateRequest, - ) -> Result, Self::Error> { - let value = self.call_json("loadFilesystemState", json!({ "vmId": request.vm_id }))?; - if value.is_null() { - return Ok(None); - } - snapshot_from_json(&value).map(Some) - } - - fn flush_filesystem_state( - &mut self, - request: FlushFilesystemStateRequest, - ) -> Result<(), Self::Error> { - self.call_void( - "flushFilesystemState", - json!({ - "vmId": request.vm_id, - "snapshot": snapshot_to_json(request.snapshot), - }), - ) - } -} - -impl ClockBridge for BrowserJsBridge { - fn wall_clock(&mut self, request: ClockRequest) -> Result { - if self.host.is_none() { - return Ok(SystemTime::now()); - } - let value = self.call_json("wallClock", base_request(request.vm_id))?; - Ok(system_time_from_ms(get_u64(&value, "unixTimeMs")?)) - } - - fn monotonic_clock(&mut self, request: ClockRequest) -> Result { - if self.host.is_none() { - return Ok(Duration::ZERO); - } - let value = self.call_json("monotonicClock", base_request(request.vm_id))?; - Ok(Duration::from_millis(get_u64(&value, "elapsedMs")?)) - } - - fn schedule_timer( - &mut self, - request: ScheduleTimerRequest, - ) -> Result { - if self.host.is_none() { - self.next_timer += 1; - return Ok(ScheduledTimer { - timer_id: format!("browser-sidecar-wasm-timer-{}", self.next_timer), - delay: request.delay, - }); - } - let value = self.call_json( - "scheduleTimer", - json!({ - "vmId": request.vm_id, - "delayMs": request.delay.as_millis() as u64, - }), - )?; - Ok(ScheduledTimer { - timer_id: get_string(&value, "timerId")?, - delay: Duration::from_millis(get_u64(&value, "delayMs")?), - }) - } -} - -impl RandomBridge for BrowserJsBridge { - fn fill_random_bytes(&mut self, request: RandomBytesRequest) -> Result, Self::Error> { - if self.host.is_some() { - return self.call_bytes( - "fillRandomBytes", - json!({ "vmId": request.vm_id, "len": request.len }), - ); - } - let mut bytes = vec![0; request.len]; - getrandom::getrandom(&mut bytes) - .map_err(|error| format!("fill_random_bytes failed: {error}"))?; - Ok(bytes) - } -} - -impl EventBridge for BrowserJsBridge { - fn emit_structured_event(&mut self, event: StructuredEventRecord) -> Result<(), Self::Error> { - if self.host.is_none() { - return Ok(()); - } - self.call_void( - "emitStructuredEvent", - json!({ "vmId": event.vm_id, "name": event.name, "fields": map_to_json(event.fields) }), - ) - } - - fn emit_diagnostic(&mut self, event: DiagnosticRecord) -> Result<(), Self::Error> { - if self.host.is_none() { - return Ok(()); - } - self.call_void( - "emitDiagnostic", - json!({ "vmId": event.vm_id, "message": event.message, "fields": map_to_json(event.fields) }), - ) - } - - fn emit_log(&mut self, event: LogRecord) -> Result<(), Self::Error> { - if self.host.is_none() { - return Ok(()); - } - self.call_void( - "emitLog", - json!({ - "vmId": event.vm_id, - "level": log_level_to_json(event.level), - "message": event.message, - }), - ) - } - - fn emit_lifecycle(&mut self, event: LifecycleEventRecord) -> Result<(), Self::Error> { - if self.host.is_none() { - return Ok(()); - } - self.call_void( - "emitLifecycle", - json!({ - "vmId": event.vm_id, - "state": format!("{:?}", event.state).to_ascii_lowercase(), - "detail": event.detail, - }), - ) - } -} - -impl ExecutionBridge for BrowserJsBridge { - fn create_javascript_context( - &mut self, - request: CreateJavascriptContextRequest, - ) -> Result { - let value = self.call_json( - "createJavascriptContext", - json!({ - "vmId": request.vm_id, - "bootstrapModule": request.bootstrap_module, - }), - )?; - Ok(GuestContextHandle { - context_id: get_string(&value, "contextId")?, - runtime: get_optional_string(&value, "runtime") - .map(|runtime| guest_runtime_from_json(&Value::String(runtime))) - .transpose()? - .unwrap_or(GuestRuntime::JavaScript), - }) - } - - fn create_wasm_context( - &mut self, - request: CreateWasmContextRequest, - ) -> Result { - let value = self.call_json( - "createWasmContext", - json!({ "vmId": request.vm_id, "modulePath": request.module_path }), - )?; - Ok(GuestContextHandle { - context_id: get_string(&value, "contextId")?, - runtime: get_optional_string(&value, "runtime") - .map(|runtime| guest_runtime_from_json(&Value::String(runtime))) - .transpose()? - .unwrap_or(GuestRuntime::WebAssembly), - }) - } - - fn start_execution( - &mut self, - request: StartExecutionRequest, - ) -> Result { - let value = self.call_json( - "startExecution", - json!({ - "vmId": request.vm_id, - "contextId": request.context_id, - "argv": request.argv, - "env": map_to_json(request.env), - "cwd": request.cwd, - }), - )?; - Ok(StartedExecution { - execution_id: get_string(&value, "executionId")?, - }) - } - - fn write_stdin(&mut self, request: WriteExecutionStdinRequest) -> Result<(), Self::Error> { - self.call_void( - "writeExecutionStdin", - json!({ - "vmId": request.vm_id, - "executionId": request.execution_id, - "chunkBase64": base64::engine::general_purpose::STANDARD.encode(request.chunk), - }), - ) - } - - fn close_stdin(&mut self, request: ExecutionHandleRequest) -> Result<(), Self::Error> { - self.call_void( - "closeExecutionStdin", - json!({ "vmId": request.vm_id, "executionId": request.execution_id }), - ) - } - - fn kill_execution(&mut self, request: KillExecutionRequest) -> Result<(), Self::Error> { - self.call_void( - "killExecution", - json!({ - "vmId": request.vm_id, - "executionId": request.execution_id, - "signal": signal_to_json(request.signal), - }), - ) - } - - fn poll_execution_event( - &mut self, - request: PollExecutionEventRequest, - ) -> Result, Self::Error> { - execution_event_from_json( - self.call_json("pollExecutionEvent", json!({ "vmId": request.vm_id }))?, - ) - } -} - -impl BrowserWorkerBridge for BrowserJsBridge { - fn create_worker( - &mut self, - request: BrowserWorkerSpawnRequest, - ) -> Result { - let value = self.call_json( - "createWorker", - json!({ - "vmId": request.vm_id, - "contextId": request.context_id, - "executionId": request.execution_id, - "runtime": guest_runtime_to_json(request.runtime), - "entrypoint": worker_entrypoint_to_json(request.entrypoint), - "wasmPermissionTier": wasm_permission_tier_to_json(request.wasm_permission_tier), - "process": process_config_to_json(request.process_config), - "os": os_config_to_json(request.os_config), - }), - )?; - Ok(BrowserWorkerHandle { - worker_id: get_string(&value, "workerId")?, - runtime: get_optional_string(&value, "runtime") - .map(|runtime| guest_runtime_from_json(&Value::String(runtime))) - .transpose()? - .unwrap_or(request.runtime), - }) - } - - fn terminate_worker(&mut self, request: BrowserWorkerHandleRequest) -> Result<(), Self::Error> { - if self.host.is_none() { - return Ok(()); - } - self.call_void( - "terminateWorker", - json!({ - "vmId": request.vm_id, - "executionId": request.execution_id, - "workerId": request.worker_id, - }), - ) - } -} diff --git a/crates/sidecar-browser/src/wire_dispatch.rs b/crates/sidecar-browser/src/wire_dispatch.rs deleted file mode 100644 index 4cd8e79d2..000000000 --- a/crates/sidecar-browser/src/wire_dispatch.rs +++ /dev/null @@ -1,1132 +0,0 @@ -use crate::{ - BrowserExecutionOptions, BrowserExtensionRequest, BrowserSidecar, BrowserSidecarBridge, - BrowserSidecarConfig, -}; -use secure_exec_bridge::{ - CreateJavascriptContextRequest, CreateWasmContextRequest, ExecutionEvent, - ExecutionHandleRequest, GuestRuntime, KillExecutionRequest, PollExecutionEventRequest, - StartExecutionRequest, WriteExecutionStdinRequest, -}; -use secure_exec_kernel::kernel::KernelVmConfig; -use secure_exec_sidecar_core::{ - authenticated_response, bound_udp_snapshot_response, connection_id_of, - execution_signal_from_number, layer_created_response, layer_sealed_response, - listener_snapshot_response, overlay_created_response, permissions_from_policy, - process_exited_event, process_killed_response, process_output_event, process_snapshot_response, - process_started_response, protocol_process_snapshot_entry, protocol_root_filesystem_mode, - reject, respond, root_filesystem_bootstrapped_response, root_filesystem_snapshot_response, - root_snapshot_entry, route_request_payload, session_opened_response, session_scope_of, - signal_state_response, snapshot_exported_response, snapshot_imported_response, - stdin_closed_response, stdin_written_response, unsupported_guest_kernel_call_event, - unsupported_host_callback_direction_dispatch, validate_authenticate_versions, - vm_configured_response, vm_created_response, vm_disposed_response, vm_id_of, - vm_lifecycle_event, zombie_timer_count_response, DispatchResult, RequestRoute, -}; -use secure_exec_sidecar_protocol::protocol::{ - AuthenticateRequest, BootstrapRootFilesystemRequest, CloseStdinRequest, ConfigureVmRequest, - CreateLayerRequest, CreateOverlayRequest, CreateVmRequest, DisposeVmRequest, EventFrame, - ExecuteRequest, ExportSnapshotRequest, ExtEnvelope, FindBoundUdpRequest, FindListenerRequest, - GetProcessSnapshotRequest, GetSignalStateRequest, GetZombieTimerCountRequest, GuestRuntimeKind, - HostCallbacksRegisteredResponse, ImportSnapshotRequest, KillProcessRequest, OpenSessionRequest, - OwnershipScope, RegisterHostCallbacksRequest, RequestFrame, ResponsePayload, SealLayerRequest, - SnapshotRootFilesystemRequest, SocketStateEntry, StreamChannel, VmFetchRequest, - VmFetchResponse, VmLifecycleState, WriteStdinRequest, -}; -use secure_exec_sidecar_protocol::wire::{ - request_frame_to_compat, CompatDispatchResult, ProtocolCodecError, ProtocolFrame, - WireFrameCodec, -}; -use secure_exec_vm_config::CreateVmConfig; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::fmt; - -pub const BROWSER_SIDECAR_ID: &str = "secure-exec-sidecar-browser"; -pub const BROWSER_MAX_FRAME_BYTES: usize = 64 * 1024 * 1024; - -#[derive(Debug, Clone, PartialEq, Eq)] -struct ExecutionRecord { - vm_id: String, - process_id: String, - ownership: OwnershipScope, -} - -type ProcessExecutionKey = (String, String); - -pub struct BrowserWireDispatcher { - codec: WireFrameCodec, - sidecar: BrowserSidecar, - next_connection: usize, - next_session: usize, - next_vm: usize, - active_vms: BTreeSet, - executions: BTreeMap, - process_executions: BTreeMap, - pending_events: VecDeque, -} - -impl BrowserWireDispatcher -where - B: BrowserSidecarBridge, - ::Error: fmt::Debug, -{ - pub fn new(bridge: B) -> Self { - Self { - codec: WireFrameCodec::new(BROWSER_MAX_FRAME_BYTES), - sidecar: BrowserSidecar::new(bridge, BrowserSidecarConfig::default()), - next_connection: 0, - next_session: 0, - next_vm: 0, - active_vms: BTreeSet::new(), - executions: BTreeMap::new(), - process_executions: BTreeMap::new(), - pending_events: VecDeque::new(), - } - } - - pub fn vm_count(&self) -> usize { - self.sidecar.vm_count() - } - - pub fn sidecar_mut(&mut self) -> &mut BrowserSidecar { - &mut self.sidecar - } - - pub fn handle_request_bytes(&mut self, bytes: &[u8]) -> Result, ProtocolCodecError> { - let generated_request = match self.codec.decode_message(bytes)? { - ProtocolFrame::RequestFrame(request) => request, - _ => { - return Err(ProtocolCodecError::SerializeFailure(String::from( - "browser sidecar expected a request frame", - ))); - } - }; - let request = request_frame_to_compat(generated_request)?; - let dispatch = self.dispatch(request); - for event in dispatch.events.iter().cloned() { - self.pending_events.push_back(event); - } - let generated = secure_exec_sidecar_protocol::wire::dispatch_result_from_compat( - CompatDispatchResult { - response: dispatch.response, - events: Vec::new(), - }, - )?; - self.codec - .encode_message(&ProtocolFrame::ResponseFrame(generated.response)) - } - - pub fn poll_event_bytes(&mut self) -> Result>, ProtocolCodecError> { - if self.pending_events.is_empty() { - self.pump_execution_events(); - } - let Some(event) = self.pending_events.pop_front() else { - return Ok(None); - }; - let generated = secure_exec_sidecar_protocol::wire::event_frame_from_compat(event)?; - self.codec - .encode_message(&ProtocolFrame::EventFrame(generated)) - .map(Some) - } - - fn dispatch(&mut self, request: RequestFrame) -> DispatchResult { - match route_request_payload(&request) { - RequestRoute::Authenticate(payload) => self.authenticate(&request, payload), - RequestRoute::OpenSession(payload) => self.open_session(&request, payload), - RequestRoute::CreateVm(payload) => self.create_vm(&request, payload), - RequestRoute::DisposeVm(payload) => self.dispose_vm(&request, payload), - RequestRoute::BootstrapRootFilesystem(payload) => { - self.bootstrap_root_filesystem(&request, payload) - } - RequestRoute::ConfigureVm(payload) => self.configure_vm(&request, payload), - RequestRoute::RegisterHostCallbacks(payload) => { - self.register_host_callbacks(&request, payload) - } - RequestRoute::CreateLayer(payload) => self.create_layer(&request, payload), - RequestRoute::SealLayer(payload) => self.seal_layer(&request, payload), - RequestRoute::ImportSnapshot(payload) => self.import_snapshot(&request, payload), - RequestRoute::ExportSnapshot(payload) => self.export_snapshot(&request, payload), - RequestRoute::CreateOverlay(payload) => self.create_overlay(&request, payload), - RequestRoute::GuestFilesystemCall(payload) => { - self.guest_filesystem_call(&request, payload) - } - RequestRoute::GuestKernelCall(payload) => self.guest_kernel_call(&request, payload), - RequestRoute::SnapshotRootFilesystem(payload) => { - self.snapshot_root_filesystem(&request, payload) - } - RequestRoute::GetProcessSnapshot(payload) => { - self.get_process_snapshot(&request, payload) - } - RequestRoute::GetResourceSnapshot(payload) => { - // Resource snapshots surface the native sidecar's queue/limit - // trackers, which the converged browser runtime does not run. - let _ = payload; - rejected( - &request, - "unsupported", - "get_resource_snapshot is not available in the converged browser runtime", - ) - } - RequestRoute::GetSignalState(payload) => self.get_signal_state(&request, payload), - RequestRoute::GetZombieTimerCount(payload) => { - self.get_zombie_timer_count(&request, payload) - } - RequestRoute::Execute(payload) => self.execute(&request, payload), - RequestRoute::WriteStdin(payload) => self.write_stdin(&request, payload), - RequestRoute::ResizePty(payload) => { - // The converged browser path resizes the PTY through the driver's - // master-side resize, not via a native wire ResizePty op, so this - // route is not exercised by the in-browser terminal. - let _ = payload; - rejected( - &request, - "unsupported", - "resize_pty is handled by the converged browser driver, not the native wire op", - ) - } - RequestRoute::CloseStdin(payload) => self.close_stdin(&request, payload), - RequestRoute::KillProcess(payload) => self.kill_process(&request, payload), - RequestRoute::FindListener(payload) => self.find_listener(&request, payload), - RequestRoute::FindBoundUdp(payload) => self.find_bound_udp(&request, payload), - RequestRoute::VmFetch(payload) => self.vm_fetch(&request, payload), - RequestRoute::Ext(payload) => self.ext(&request, payload), - RequestRoute::LinkPackage(payload) => { - // Package linking projects host-filesystem package trees into the - // VM, which the converged browser runtime does not provide. - let _ = payload; - rejected( - &request, - "unsupported", - "link_package is not available in the converged browser runtime", - ) - } - RequestRoute::ProvidedCommands(payload) => { - // Provided command metadata is retained by the native sidecar's - // host-backed package projection, which the converged browser - // runtime does not provide. - let _ = payload; - rejected( - &request, - "unsupported", - "provided_commands is not available in the converged browser runtime", - ) - } - RequestRoute::UnsupportedHostCallbackDirection => { - unsupported_host_callback_direction_dispatch(&request) - } - } - } - - fn bootstrap_root_filesystem( - &mut self, - request: &RequestFrame, - payload: BootstrapRootFilesystemRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "bootstrap_root_filesystem requires VM ownership", - ); - }; - let entry_count = match self - .sidecar - .bootstrap_root_filesystem_entries(&vm_id, &payload.entries) - { - Ok(entry_count) => entry_count, - Err(error) => return rejected(request, "bootstrap_root_failed", &error.to_string()), - }; - DispatchResult { - response: root_filesystem_bootstrapped_response(request, entry_count), - events: Vec::new(), - } - } - - fn configure_vm( - &mut self, - request: &RequestFrame, - payload: ConfigureVmRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "configure_vm requires VM ownership", - ); - }; - if !payload.mounts.is_empty() - || !payload.software.is_empty() - || payload.module_access_cwd.is_some() - { - return rejected( - request, - "unsupported_request", - "browser ConfigureVm does not support host mounts, software installs, or moduleAccessCwd", - ); - } - - let permissions = match payload.permissions { - Some(policy) => { - let policy = - secure_exec_sidecar_protocol::wire::permissions_policy_config_from_wire(policy); - if let Err(error) = secure_exec_sidecar_core::validate_permissions_policy(&policy) { - return rejected(request, "invalid_config", &error.to_string()); - } - Some(permissions_from_policy(policy)) - } - None => None, - }; - if let Err(error) = self.sidecar.configure_vm( - &vm_id, - permissions, - payload.instructions, - payload.projected_modules, - payload.command_permissions.into_iter().collect(), - payload.loopback_exempt_ports, - ) { - return rejected(request, "configure_vm_failed", &error.to_string()); - } - DispatchResult { - response: vm_configured_response(request, 0, 0, Vec::new()), - events: Vec::new(), - } - } - - fn register_host_callbacks( - &mut self, - request: &RequestFrame, - payload: RegisterHostCallbacksRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "register_host_callbacks requires VM ownership", - ); - }; - let (registration, command_count) = - match self.sidecar.register_host_callbacks(&vm_id, payload) { - Ok(result) => result, - Err(error) => { - return rejected( - request, - "register_host_callbacks_failed", - &error.to_string(), - ) - } - }; - DispatchResult { - response: respond( - request, - ResponsePayload::HostCallbacksRegistered(HostCallbacksRegisteredResponse { - registration, - command_count, - }), - ), - events: Vec::new(), - } - } - - fn guest_filesystem_call( - &mut self, - request: &RequestFrame, - payload: secure_exec_sidecar_protocol::protocol::GuestFilesystemCallRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "guest_filesystem_call requires VM ownership", - ); - }; - let result = match self.sidecar.guest_filesystem_call(&vm_id, payload) { - Ok(result) => result, - Err(error) => return rejected(request, "guest_filesystem_failed", &error.to_string()), - }; - DispatchResult { - response: respond(request, ResponsePayload::GuestFilesystemResult(result)), - events: Vec::new(), - } - } - - fn guest_kernel_call( - &mut self, - request: &RequestFrame, - payload: secure_exec_sidecar_protocol::protocol::GuestKernelCallRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "guest_kernel_call requires VM ownership", - ); - }; - let result = match self.sidecar.guest_kernel_call(&vm_id, payload) { - Ok(result) => result, - Err(error) => return rejected(request, "guest_kernel_failed", &error.to_string()), - }; - DispatchResult { - response: respond(request, ResponsePayload::GuestKernelResult(result)), - events: Vec::new(), - } - } - - fn create_layer( - &mut self, - request: &RequestFrame, - _payload: CreateLayerRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "create_layer requires VM ownership", - ); - }; - let layer_id = match self.sidecar.create_layer(&vm_id) { - Ok(layer_id) => layer_id, - Err(error) => return rejected(request, "create_layer_failed", &error.to_string()), - }; - DispatchResult { - response: layer_created_response(request, layer_id), - events: Vec::new(), - } - } - - fn seal_layer(&mut self, request: &RequestFrame, payload: SealLayerRequest) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "seal_layer requires VM ownership", - ); - }; - let layer_id = match self.sidecar.seal_layer(&vm_id, &payload.layer_id) { - Ok(layer_id) => layer_id, - Err(error) => return rejected(request, "seal_layer_failed", &error.to_string()), - }; - DispatchResult { - response: layer_sealed_response(request, layer_id), - events: Vec::new(), - } - } - - fn import_snapshot( - &mut self, - request: &RequestFrame, - payload: ImportSnapshotRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "import_snapshot requires VM ownership", - ); - }; - let layer_id = match self.sidecar.import_snapshot(&vm_id, &payload.entries) { - Ok(layer_id) => layer_id, - Err(error) => return rejected(request, "import_snapshot_failed", &error.to_string()), - }; - DispatchResult { - response: snapshot_imported_response(request, layer_id), - events: Vec::new(), - } - } - - fn export_snapshot( - &mut self, - request: &RequestFrame, - payload: ExportSnapshotRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "export_snapshot requires VM ownership", - ); - }; - let snapshot = match self.sidecar.export_snapshot(&vm_id, &payload.layer_id) { - Ok(snapshot) => snapshot, - Err(error) => return rejected(request, "export_snapshot_failed", &error.to_string()), - }; - DispatchResult { - response: snapshot_exported_response( - request, - payload.layer_id, - snapshot.entries.iter().map(root_snapshot_entry).collect(), - ), - events: Vec::new(), - } - } - - fn create_overlay( - &mut self, - request: &RequestFrame, - payload: CreateOverlayRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "create_overlay requires VM ownership", - ); - }; - let mode = protocol_root_filesystem_mode(payload.mode); - let layer_id = match self.sidecar.create_overlay( - &vm_id, - mode, - payload.upper_layer_id, - payload.lower_layer_ids, - ) { - Ok(layer_id) => layer_id, - Err(error) => return rejected(request, "create_overlay_failed", &error.to_string()), - }; - DispatchResult { - response: overlay_created_response(request, layer_id), - events: Vec::new(), - } - } - - fn snapshot_root_filesystem( - &mut self, - request: &RequestFrame, - _payload: SnapshotRootFilesystemRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "snapshot_root_filesystem requires VM ownership", - ); - }; - let snapshot = match self.sidecar.snapshot_root_filesystem(&vm_id) { - Ok(snapshot) => snapshot, - Err(error) => return rejected(request, "snapshot_root_failed", &error.to_string()), - }; - DispatchResult { - response: root_filesystem_snapshot_response( - request, - snapshot.entries.iter().map(root_snapshot_entry).collect(), - ), - events: Vec::new(), - } - } - - fn get_process_snapshot( - &mut self, - request: &RequestFrame, - _payload: GetProcessSnapshotRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "get_process_snapshot requires VM ownership", - ); - }; - let mut processes = match self.sidecar.process_snapshot_entries(&vm_id) { - Ok(processes) => processes, - Err(error) => return rejected(request, "process_snapshot_failed", &error.to_string()), - }; - for process in &mut processes { - if let Some(record) = self.executions.get(&process.process_id) { - process.process_id = record.process_id.clone(); - } - } - DispatchResult { - response: process_snapshot_response( - request, - processes - .into_iter() - .map(protocol_process_snapshot_entry) - .collect(), - ), - events: Vec::new(), - } - } - - fn get_signal_state( - &mut self, - request: &RequestFrame, - payload: GetSignalStateRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "get_signal_state requires VM ownership", - ); - }; - let Some(execution_id) = self.execution_id_for(&vm_id, &payload.process_id) else { - return rejected( - request, - "unknown_process", - "get_signal_state process is not active", - ); - }; - let handlers = match self.sidecar.signal_state(&vm_id, &execution_id) { - Ok(handlers) => handlers, - Err(error) => return rejected(request, "signal_state_failed", &error.to_string()), - }; - DispatchResult { - response: signal_state_response(request, payload.process_id, handlers), - events: Vec::new(), - } - } - - fn get_zombie_timer_count( - &mut self, - request: &RequestFrame, - _payload: GetZombieTimerCountRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "get_zombie_timer_count requires VM ownership", - ); - }; - let count = match self.sidecar.zombie_timer_count(&vm_id) { - Ok(count) => count, - Err(error) => { - return rejected(request, "zombie_timer_count_failed", &error.to_string()) - } - }; - DispatchResult { - response: zombie_timer_count_response(request, count), - events: Vec::new(), - } - } - - fn find_listener( - &mut self, - request: &RequestFrame, - payload: FindListenerRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "find_listener requires VM ownership", - ); - }; - let listener = match self.sidecar.find_listener(&vm_id, &payload) { - Ok(listener) => listener, - Err(error) => return rejected(request, "find_listener_failed", &error.to_string()), - } - .map(|entry| self.client_socket_state_entry(entry)); - DispatchResult { - response: listener_snapshot_response(request, listener), - events: Vec::new(), - } - } - - fn find_bound_udp( - &mut self, - request: &RequestFrame, - payload: FindBoundUdpRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "find_bound_udp requires VM ownership", - ); - }; - let socket = match self.sidecar.find_bound_udp(&vm_id, &payload) { - Ok(socket) => socket, - Err(error) => return rejected(request, "find_bound_udp_failed", &error.to_string()), - } - .map(|entry| self.client_socket_state_entry(entry)); - DispatchResult { - response: bound_udp_snapshot_response(request, socket), - events: Vec::new(), - } - } - - fn vm_fetch(&mut self, request: &RequestFrame, payload: VmFetchRequest) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "vm.fetch requires VM ownership", - ); - }; - if let Err(error) = serde_json::from_str::(&payload.headers_json) { - return rejected( - request, - "invalid_request", - &format!("vm.fetch headers_json must be valid JSON: {error}"), - ); - } - - let response_json = match self.sidecar.vm_fetch(&vm_id, &payload) { - Ok(response_json) => response_json, - Err(error) => return rejected(request, "vm_fetch_failed", &error.to_string()), - }; - DispatchResult { - response: respond( - request, - ResponsePayload::VmFetchResult(VmFetchResponse { response_json }), - ), - events: Vec::new(), - } - } - - fn authenticate( - &mut self, - request: &RequestFrame, - payload: AuthenticateRequest, - ) -> DispatchResult { - if let Err(error) = validate_authenticate_versions(&payload) { - return rejected(request, error.code(), error.message()); - } - - self.next_connection += 1; - let connection_id = format!("browser-connection-{}", self.next_connection); - DispatchResult { - response: authenticated_response( - request.request_id, - BROWSER_SIDECAR_ID, - connection_id, - BROWSER_MAX_FRAME_BYTES as u32, - ), - events: Vec::new(), - } - } - - fn client_socket_state_entry(&self, mut entry: SocketStateEntry) -> SocketStateEntry { - if let Some(record) = self.executions.get(&entry.process_id) { - entry.process_id = record.process_id.clone(); - } - entry - } - - fn open_session( - &mut self, - request: &RequestFrame, - _payload: OpenSessionRequest, - ) -> DispatchResult { - let Some(connection_id) = connection_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "open_session requires connection ownership", - ); - }; - self.next_session += 1; - let session_id = format!("browser-session-{}", self.next_session); - DispatchResult { - response: session_opened_response(request.request_id, connection_id, session_id), - events: Vec::new(), - } - } - - fn create_vm(&mut self, request: &RequestFrame, payload: CreateVmRequest) -> DispatchResult { - let Some((connection_id, session_id)) = session_scope_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "create_vm requires session ownership", - ); - }; - let create_config: CreateVmConfig = match serde_json::from_str(&payload.config) { - Ok(config) => config, - Err(error) => { - return rejected( - request, - "invalid_config", - &format!("invalid create VM config JSON: {error}"), - ); - } - }; - if let Err(error) = create_config.validate(BROWSER_MAX_FRAME_BYTES) { - return rejected( - request, - "invalid_config", - &format!("invalid create VM config: {error}"), - ); - } - - self.next_vm += 1; - let vm_id = format!("vm-{}", self.next_vm); - let mut kernel_config = KernelVmConfig::new(vm_id.clone()); - kernel_config.env = create_config.env.clone(); - if let Some(cwd) = create_config.cwd.clone() { - kernel_config.cwd = cwd; - } - kernel_config.loopback_exempt_ports = create_config - .loopback_exempt_ports - .iter() - .copied() - .collect(); - let limits = match secure_exec_sidecar_core::vm_limits_from_config( - create_config.limits.as_ref(), - BROWSER_MAX_FRAME_BYTES, - ) { - Ok(limits) => limits, - Err(error) => { - return rejected(request, "invalid_config", &error.to_string()); - } - }; - kernel_config.resources = limits.resources; - let permissions = create_config - .permissions - .clone() - .unwrap_or_else(secure_exec_sidecar_core::deny_all_policy); - if let Err(error) = secure_exec_sidecar_core::validate_permissions_policy(&permissions) { - return rejected(request, "invalid_config", &error.to_string()); - } - kernel_config.permissions = permissions_from_policy(permissions); - - if let Err(error) = self - .sidecar - .create_vm_with_root_filesystem(kernel_config, create_config.root_filesystem) - { - return rejected(request, "create_vm_failed", &error.to_string()); - } - self.active_vms.insert(vm_id.clone()); - - let ownership = OwnershipScope::vm(&connection_id, &session_id, &vm_id); - DispatchResult { - response: vm_created_response(request, vm_id.clone()), - events: vec![ - vm_lifecycle_event( - &connection_id, - &session_id, - &vm_id, - VmLifecycleState::Creating, - ), - EventFrame::new( - ownership, - secure_exec_sidecar_protocol::protocol::EventPayload::VmLifecycle( - secure_exec_sidecar_protocol::protocol::VmLifecycleEvent { - state: VmLifecycleState::Ready, - }, - ), - ), - ], - } - } - - fn dispose_vm(&mut self, request: &RequestFrame, _payload: DisposeVmRequest) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "dispose_vm requires VM ownership", - ); - }; - if let Err(error) = self.sidecar.dispose_vm(&vm_id) { - return rejected(request, "dispose_vm_failed", &error.to_string()); - } - self.active_vms.remove(&vm_id); - self.executions.retain(|_, record| record.vm_id != vm_id); - self.process_executions - .retain(|(process_vm_id, _), _| process_vm_id != &vm_id); - DispatchResult { - response: vm_disposed_response(request, vm_id), - events: Vec::new(), - } - } - - fn ext(&mut self, request: &RequestFrame, payload: ExtEnvelope) -> DispatchResult { - let response = match self - .sidecar - .dispatch_extension_request(BrowserExtensionRequest { - namespace: payload.namespace, - payload: payload.payload, - vm_id: vm_id_of(&request.ownership), - connection_id: connection_id_of(&request.ownership), - }) { - Ok(response) => response, - Err(error) => return rejected(request, "extension_failed", &error.to_string()), - }; - DispatchResult { - response: respond( - request, - ResponsePayload::ExtResult(ExtEnvelope { - namespace: response.namespace, - payload: response.payload, - }), - ), - events: Vec::new(), - } - } - - fn execute(&mut self, request: &RequestFrame, payload: ExecuteRequest) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "execute requires VM ownership", - ); - }; - let process_key = (vm_id.clone(), payload.process_id.clone()); - if self.process_executions.contains_key(&process_key) { - return rejected( - request, - "process_already_active", - "process_id is already active", - ); - } - let runtime = match payload - .runtime - .clone() - .unwrap_or(GuestRuntimeKind::JavaScript) - { - GuestRuntimeKind::JavaScript | GuestRuntimeKind::Python => GuestRuntime::JavaScript, - GuestRuntimeKind::WebAssembly => GuestRuntime::WebAssembly, - }; - let context = match runtime { - GuestRuntime::JavaScript => { - self.sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: payload.entrypoint.clone(), - }) - } - GuestRuntime::WebAssembly => { - self.sidecar.create_wasm_context(CreateWasmContextRequest { - vm_id: vm_id.clone(), - module_path: payload.entrypoint.clone(), - }) - } - }; - let context = match context { - Ok(context) => context, - Err(error) => return rejected(request, "execute_failed", &error.to_string()), - }; - - let mut argv = Vec::new(); - if let Some(command) = payload.command.clone() { - argv.push(command); - } - argv.extend(payload.args.clone()); - let started = match self.sidecar.start_execution_with_options( - StartExecutionRequest { - vm_id: vm_id.clone(), - context_id: context.context_id, - argv, - env: payload.env.clone().into_iter().collect(), - cwd: payload.cwd.clone().unwrap_or_else(|| String::from("/")), - }, - BrowserExecutionOptions { - command_name: payload.command.clone(), - wasm_permission_tier: payload.wasm_permission_tier, - }, - ) { - Ok(started) => started, - Err(error) => return rejected(request, "execute_failed", &error.to_string()), - }; - - self.executions.insert( - started.execution_id.clone(), - ExecutionRecord { - vm_id: vm_id.clone(), - process_id: payload.process_id.clone(), - ownership: request.ownership.clone(), - }, - ); - self.process_executions - .insert(process_key, started.execution_id.clone()); - DispatchResult { - response: process_started_response(request, payload.process_id, None), - events: Vec::new(), - } - } - - fn write_stdin( - &mut self, - request: &RequestFrame, - payload: WriteStdinRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "write_stdin requires VM ownership", - ); - }; - let Some(execution_id) = self.execution_id_for(&vm_id, &payload.process_id) else { - return rejected( - request, - "unknown_process", - "write_stdin process is not active", - ); - }; - let accepted_bytes = payload.chunk.len() as u64; - if let Err(error) = self.sidecar.write_stdin(WriteExecutionStdinRequest { - vm_id, - execution_id, - chunk: payload.chunk, - }) { - return rejected(request, "write_stdin_failed", &error.to_string()); - } - DispatchResult { - response: stdin_written_response(request, payload.process_id, accepted_bytes), - events: Vec::new(), - } - } - - fn close_stdin( - &mut self, - request: &RequestFrame, - payload: CloseStdinRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "close_stdin requires VM ownership", - ); - }; - let Some(execution_id) = self.execution_id_for(&vm_id, &payload.process_id) else { - return rejected( - request, - "unknown_process", - "close_stdin process is not active", - ); - }; - if let Err(error) = self.sidecar.close_stdin(ExecutionHandleRequest { - vm_id, - execution_id, - }) { - return rejected(request, "close_stdin_failed", &error.to_string()); - } - DispatchResult { - response: stdin_closed_response(request, payload.process_id), - events: Vec::new(), - } - } - - fn kill_process( - &mut self, - request: &RequestFrame, - payload: KillProcessRequest, - ) -> DispatchResult { - let Some(vm_id) = vm_id_of(&request.ownership) else { - return rejected( - request, - "invalid_ownership", - "kill_process requires VM ownership", - ); - }; - let Some(execution_id) = self.execution_id_for(&vm_id, &payload.process_id) else { - return DispatchResult { - response: process_killed_response(request, payload.process_id), - events: Vec::new(), - }; - }; - let signal = match secure_exec_sidecar_core::parse_posix_signal(&payload.signal) { - Some(signal) => signal, - None => { - return rejected( - request, - "kill_process_failed", - &format!("unsupported kill_process signal {}", payload.signal), - ); - } - }; - if signal == 0 { - return DispatchResult { - response: process_killed_response(request, payload.process_id), - events: Vec::new(), - }; - } - if let Err(error) = - self.sidecar - .signal_execution_kernel_process(&vm_id, &execution_id, signal) - { - return rejected(request, "kill_process_failed", &error.to_string()); - } - if let Some(bridge_signal) = execution_signal_from_number(signal) { - if let Err(error) = self - .sidecar - .bridge_mut() - .kill_execution(KillExecutionRequest { - vm_id, - execution_id, - signal: bridge_signal, - }) - { - return rejected(request, "kill_process_failed", &format!("{error:?}")); - } - } - DispatchResult { - response: process_killed_response(request, payload.process_id), - events: Vec::new(), - } - } - - fn pump_execution_events(&mut self) { - for vm_id in self.active_vms.iter().cloned().collect::>() { - while let Ok(Some(event)) = - self.sidecar - .poll_execution_event(PollExecutionEventRequest { - vm_id: vm_id.clone(), - }) - { - if let Some(frame) = self.execution_event_to_frame(event) { - self.pending_events.push_back(frame); - } - } - } - } - - fn execution_event_to_frame(&mut self, event: ExecutionEvent) -> Option { - match event { - ExecutionEvent::Stdout(chunk) => { - let record = self.executions.get(&chunk.execution_id)?; - Some(process_output_event( - record.ownership.clone(), - &record.process_id, - StreamChannel::Stdout, - chunk.chunk, - )) - } - ExecutionEvent::Stderr(chunk) => { - let record = self.executions.get(&chunk.execution_id)?; - Some(process_output_event( - record.ownership.clone(), - &record.process_id, - StreamChannel::Stderr, - chunk.chunk, - )) - } - ExecutionEvent::Exited(exited) => { - let record = self.executions.remove(&exited.execution_id)?; - self.process_executions - .remove(&(record.vm_id.clone(), record.process_id.clone())); - Some(process_exited_event( - record.ownership, - &record.process_id, - exited.exit_code, - )) - } - ExecutionEvent::GuestRequest(call) => { - let record = self.executions.get(&call.execution_id)?; - Some(unsupported_guest_kernel_call_event( - record.ownership.clone(), - &record.process_id, - &call.execution_id, - &call.operation, - call.payload.len(), - )) - } - ExecutionEvent::SignalState(_) => None, - } - } - - fn execution_id_for(&self, vm_id: &str, process_id: &str) -> Option { - self.process_executions - .get(&(vm_id.to_string(), process_id.to_string())) - .cloned() - } -} - -fn rejected(request: &RequestFrame, code: &str, message: &str) -> DispatchResult { - DispatchResult { - response: reject(request, code, message), - events: Vec::new(), - } -} diff --git a/crates/sidecar-browser/tests/bridge.rs b/crates/sidecar-browser/tests/bridge.rs deleted file mode 100644 index 45d21078c..000000000 --- a/crates/sidecar-browser/tests/bridge.rs +++ /dev/null @@ -1,148 +0,0 @@ -#[path = "../../bridge/tests/support.rs"] -mod bridge_support; - -use bridge_support::RecordingBridge; -use secure_exec_bridge::{ - BridgeTypes, ClockRequest, CreateJavascriptContextRequest, CreateWasmContextRequest, - DiagnosticRecord, ExecutionEvent, ExecutionSignal, GuestKernelCall, GuestRuntime, - KillExecutionRequest, LifecycleEventRecord, LifecycleState, LogLevel, LogRecord, - PollExecutionEventRequest, RandomBytesRequest, ScheduleTimerRequest, StructuredEventRecord, -}; -use secure_exec_sidecar_browser::{ - BrowserSidecarBridge, BrowserWorkerBridge, BrowserWorkerHandle, BrowserWorkerHandleRequest, - BrowserWorkerSpawnRequest, -}; -use std::collections::BTreeMap; -use std::fmt::Debug; -use std::time::Duration; - -impl BrowserWorkerBridge for RecordingBridge { - fn create_worker( - &mut self, - request: BrowserWorkerSpawnRequest, - ) -> Result { - Ok(BrowserWorkerHandle { - worker_id: format!("bridge-worker-{}", request.context_id), - runtime: request.runtime, - }) - } - - fn terminate_worker( - &mut self, - _request: BrowserWorkerHandleRequest, - ) -> Result<(), Self::Error> { - Ok(()) - } -} - -fn assert_browser_sidecar_bridge(bridge: &mut B) -where - B: BrowserSidecarBridge, - ::Error: Debug, -{ - assert_eq!( - bridge - .monotonic_clock(ClockRequest { - vm_id: String::from("vm-browser"), - }) - .expect("monotonic clock"), - Duration::from_millis(42) - ); - assert_eq!( - bridge - .fill_random_bytes(RandomBytesRequest { - vm_id: String::from("vm-browser"), - len: 3, - }) - .expect("random bytes"), - vec![0xA5; 3] - ); - assert_eq!( - bridge - .schedule_timer(ScheduleTimerRequest { - vm_id: String::from("vm-browser"), - delay: Duration::from_millis(8), - }) - .expect("schedule timer") - .timer_id, - "timer-1" - ); - - let js = bridge - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: Some(String::from("@secure-exec/browser")), - }) - .expect("create js context"); - let wasm = bridge - .create_wasm_context(CreateWasmContextRequest { - vm_id: String::from("vm-browser"), - module_path: Some(String::from("/workspace/main.wasm")), - }) - .expect("create wasm context"); - - assert_eq!(js.runtime, GuestRuntime::JavaScript); - assert_eq!(wasm.runtime, GuestRuntime::WebAssembly); - - bridge - .emit_log(LogRecord { - vm_id: String::from("vm-browser"), - level: LogLevel::Debug, - message: String::from("worker online"), - }) - .expect("emit log"); - bridge - .emit_diagnostic(DiagnosticRecord { - vm_id: String::from("vm-browser"), - message: String::from("worker created"), - fields: BTreeMap::new(), - }) - .expect("emit diagnostic"); - bridge - .emit_structured_event(StructuredEventRecord { - vm_id: String::from("vm-browser"), - name: String::from("worker.message"), - fields: BTreeMap::from([(String::from("kind"), String::from("ready"))]), - }) - .expect("emit structured event"); - bridge - .emit_lifecycle(LifecycleEventRecord { - vm_id: String::from("vm-browser"), - state: LifecycleState::Starting, - detail: Some(String::from("bootstrapping worker")), - }) - .expect("emit lifecycle"); - - bridge - .kill_execution(KillExecutionRequest { - vm_id: String::from("vm-browser"), - execution_id: String::from("exec-browser"), - signal: ExecutionSignal::Kill, - }) - .expect("kill execution"); - - match bridge - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-browser"), - }) - .expect("poll event") - { - Some(ExecutionEvent::GuestRequest(event)) => { - assert_eq!(event.operation, "module.load"); - } - other => panic!("unexpected execution event: {other:?}"), - } -} - -#[test] -fn browser_sidecar_crate_compiles_against_composed_host_bridge() { - let mut bridge = RecordingBridge::default(); - bridge.push_execution_event(ExecutionEvent::GuestRequest(GuestKernelCall { - vm_id: String::from("vm-browser"), - execution_id: String::from("exec-browser"), - operation: String::from("module.load"), - payload: Vec::new(), - })); - - assert_browser_sidecar_bridge(&mut bridge); -} diff --git a/crates/sidecar-browser/tests/service.rs b/crates/sidecar-browser/tests/service.rs deleted file mode 100644 index 0bf907c78..000000000 --- a/crates/sidecar-browser/tests/service.rs +++ /dev/null @@ -1,1393 +0,0 @@ -#[path = "../../bridge/tests/support.rs"] -mod bridge_support; - -use bridge_support::RecordingBridge; -use secure_exec_bridge::{ - CreateJavascriptContextRequest, CreateWasmContextRequest, ExecutionEvent, ExecutionExited, - ExecutionSignal, ExecutionSignalState, GuestKernelCall, GuestRuntime, KillExecutionRequest, - LifecycleState, PollExecutionEventRequest, SignalDispositionAction, SignalHandlerRegistration, - StartExecutionRequest, -}; -use secure_exec_kernel::kernel::KernelVmConfig; -use secure_exec_kernel::permissions::{ - NetworkAccessRequest, NetworkOperation, PermissionDecision, Permissions, -}; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::root_fs::FilesystemEntryKind; -use secure_exec_sidecar_browser::{ - BrowserSidecar, BrowserSidecarConfig, BrowserWorkerBridge, BrowserWorkerEntrypoint, - BrowserWorkerHandle, BrowserWorkerHandleRequest, BrowserWorkerOsConfig, - BrowserWorkerProcessConfig, BrowserWorkerSpawnRequest, -}; -use secure_exec_sidecar_protocol::wire::{ - FindBoundUdpRequest, FindListenerRequest, GuestKernelCallRequest, WasmPermissionTier, -}; -use secure_exec_vm_config::{ - RootFilesystemConfig, RootFilesystemEntry, RootFilesystemEntryEncoding, - RootFilesystemEntryKind, RootFilesystemLowerDescriptor, RootFilesystemMode, -}; -use std::collections::BTreeMap; -use std::sync::{Arc, Mutex}; -use std::time::Duration; - -impl BrowserWorkerBridge for RecordingBridge { - fn create_worker( - &mut self, - request: BrowserWorkerSpawnRequest, - ) -> Result { - if let Some(error) = self.next_worker_create_error() { - return Err(error); - } - - let kind = match request.runtime { - GuestRuntime::JavaScript => "js", - GuestRuntime::WebAssembly => "wasm", - }; - self.browser_worker_spawns.push(BTreeMap::from([ - (String::from("vm_id"), request.vm_id.clone()), - (String::from("context_id"), request.context_id.clone()), - (String::from("execution_id"), request.execution_id.clone()), - ( - String::from("process_platform"), - request.process_config.platform.clone(), - ), - ( - String::from("process_arch"), - request.process_config.arch.clone(), - ), - ( - String::from("process_cwd"), - request.process_config.cwd.clone(), - ), - ( - String::from("process_pid"), - request.process_config.pid.to_string(), - ), - ( - String::from("process_uid"), - request.process_config.uid.to_string(), - ), - ( - String::from("process_gid"), - request.process_config.gid.to_string(), - ), - ( - String::from("process_env_base"), - request - .process_config - .env - .get("BASE_ENV") - .cloned() - .unwrap_or_default(), - ), - ( - String::from("process_env_exec"), - request - .process_config - .env - .get("EXEC_ENV") - .cloned() - .unwrap_or_default(), - ), - ( - String::from("os_platform"), - request.os_config.platform.clone(), - ), - ( - String::from("os_cpu_count"), - request.os_config.cpu_count.to_string(), - ), - ( - String::from("os_totalmem"), - request.os_config.totalmem.to_string(), - ), - ( - String::from("os_freemem"), - request.os_config.freemem.to_string(), - ), - (String::from("os_user"), request.os_config.user.clone()), - (String::from("os_uid"), request.os_config.uid.to_string()), - (String::from("os_gid"), request.os_config.gid.to_string()), - ( - String::from("os_homedir"), - request.os_config.homedir.clone(), - ), - ( - String::from("os_hostname"), - request.os_config.hostname.clone(), - ), - (String::from("os_type"), request.os_config.r#type.clone()), - ( - String::from("os_release"), - request.os_config.release.clone(), - ), - ( - String::from("os_version"), - request.os_config.version.clone(), - ), - (String::from("os_tmpdir"), request.os_config.tmpdir.clone()), - ( - String::from("os_machine"), - request.os_config.machine.clone(), - ), - ( - String::from("wasm_permission_tier"), - request - .wasm_permission_tier - .map(|tier| format!("{tier:?}")) - .unwrap_or_default(), - ), - ])); - - Ok(BrowserWorkerHandle { - worker_id: format!("{kind}-worker-{}", request.context_id), - runtime: request.runtime, - }) - } - - fn terminate_worker(&mut self, request: BrowserWorkerHandleRequest) -> Result<(), Self::Error> { - self.terminated_workers - .push((request.vm_id, request.execution_id, request.worker_id)); - Ok(()) - } -} - -fn permissive_config(vm_id: &str) -> KernelVmConfig { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - config -} - -fn test_process_config() -> BrowserWorkerProcessConfig { - BrowserWorkerProcessConfig { - cwd: String::from("/workspace"), - env: BTreeMap::new(), - argv: vec![String::from("node")], - platform: String::from("linux"), - arch: String::from("x64"), - version: String::from("v22.0.0"), - pid: 1, - ppid: 0, - uid: 1000, - gid: 1000, - } -} - -fn test_os_config() -> BrowserWorkerOsConfig { - BrowserWorkerOsConfig { - platform: String::from("linux"), - arch: String::from("x64"), - r#type: String::from("Linux"), - release: String::from("6.8.0-secure-exec"), - version: String::from("#1 SMP PREEMPT_DYNAMIC secure-exec"), - cpu_count: 1, - totalmem: 1024 * 1024 * 1024, - freemem: 512 * 1024 * 1024, - hostname: String::from("secure-exec"), - homedir: String::from("/home/user"), - tmpdir: String::from("/tmp"), - machine: String::from("x86_64"), - user: String::from("user"), - shell: String::from("/bin/sh"), - uid: 1000, - gid: 1000, - } -} - -#[test] -fn browser_sidecar_runs_guest_javascript_from_main_thread_workers() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - sidecar - .create_vm(permissive_config("vm-browser")) - .expect("create vm"); - - let context = sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: Some(String::from("@secure-exec/browser")), - }) - .expect("create JavaScript context"); - let started = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id.clone(), - argv: vec![String::from("node"), String::from("script.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start JavaScript execution"); - - assert_eq!(sidecar.sidecar_id(), "secure-exec-sidecar-browser"); - assert_eq!(sidecar.vm_count(), 1); - assert_eq!(sidecar.context_count("vm-browser"), 1); - assert_eq!(sidecar.active_worker_count("vm-browser"), 1); - - sidecar - .bridge_mut() - .push_execution_event(ExecutionEvent::Exited(ExecutionExited { - vm_id: String::from("vm-browser"), - execution_id: started.execution_id.clone(), - exit_code: 0, - })); - let event = sidecar - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-browser"), - }) - .expect("poll execution event"); - - assert!(matches!( - event, - Some(ExecutionEvent::Exited(ExecutionExited { - execution_id, - exit_code: 0, - .. - })) if execution_id == started.execution_id - )); - assert_eq!(sidecar.active_worker_count("vm-browser"), 0); - - let bridge = sidecar.into_bridge(); - let states = bridge - .lifecycle_events - .iter() - .map(|event| event.state) - .collect::>(); - assert_eq!( - states, - vec![ - LifecycleState::Starting, - LifecycleState::Ready, - LifecycleState::Busy, - LifecycleState::Ready, - ] - ); - let structured_names = bridge - .structured_events - .iter() - .map(|event| event.name.as_str()) - .collect::>(); - assert_eq!( - structured_names, - vec![ - "browser.context.created", - "browser.worker.spawned", - "browser.worker.reaped", - ] - ); -} - -#[test] -fn browser_worker_spawn_receives_virtual_identity_config() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - let mut config = permissive_config("vm-browser"); - config - .env - .insert(String::from("BASE_ENV"), String::from("base")); - config.user.username = Some(String::from("runner")); - config.user.uid = Some(501); - config.user.gid = Some(20); - config.user.homedir = Some(String::from("/home/runner")); - config.user.shell = Some(String::from("/bin/bash")); - config.resources = ResourceLimits { - virtual_cpu_count: Some(4), - max_wasm_memory_bytes: Some(256 * 1024 * 1024), - ..ResourceLimits::default() - }; - sidecar.create_vm(config).expect("create vm"); - - let context = sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: None, - }) - .expect("create JavaScript context"); - sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id, - argv: vec![String::from("node"), String::from("identity.js")], - env: BTreeMap::from([(String::from("EXEC_ENV"), String::from("exec"))]), - cwd: String::from("/workspace"), - }) - .expect("start execution"); - - let bridge = sidecar.into_bridge(); - let spawn = bridge - .browser_worker_spawns - .last() - .expect("worker spawn should be recorded"); - assert_eq!( - spawn.get("process_platform").map(String::as_str), - Some("linux") - ); - assert_eq!(spawn.get("process_arch").map(String::as_str), Some("x64")); - assert_eq!( - spawn.get("process_cwd").map(String::as_str), - Some("/workspace") - ); - assert_eq!( - spawn.get("execution_id").map(String::as_str), - Some("exec-1") - ); - assert_eq!( - spawn.get("process_env_base").map(String::as_str), - Some("base") - ); - assert_eq!( - spawn.get("process_env_exec").map(String::as_str), - Some("exec") - ); - assert_eq!(spawn.get("os_platform").map(String::as_str), Some("linux")); - assert_eq!(spawn.get("os_cpu_count").map(String::as_str), Some("4")); - assert_eq!( - spawn.get("os_totalmem").map(String::as_str), - Some("268435456") - ); - assert_eq!( - spawn.get("os_freemem").map(String::as_str), - Some("268435456") - ); - assert_eq!(spawn.get("os_user").map(String::as_str), Some("runner")); - assert_eq!( - spawn.get("os_homedir").map(String::as_str), - Some("/home/runner") - ); - assert_eq!( - spawn.get("os_hostname").map(String::as_str), - Some("secure-exec") - ); - assert_eq!(spawn.get("os_type").map(String::as_str), Some("Linux")); - assert_eq!( - spawn.get("os_release").map(String::as_str), - Some("6.8.0-secure-exec") - ); - assert_eq!( - spawn.get("os_version").map(String::as_str), - Some("#1 SMP PREEMPT_DYNAMIC secure-exec") - ); - assert_eq!(spawn.get("os_tmpdir").map(String::as_str), Some("/tmp")); - assert_eq!(spawn.get("os_machine").map(String::as_str), Some("x86_64")); - assert!( - spawn - .get("process_pid") - .and_then(|pid| pid.parse::().ok()) - .is_some_and(|pid| pid > 0), - "worker process pid should come from the kernel" - ); - assert_eq!(spawn.get("process_uid").map(String::as_str), Some("501")); - assert_eq!(spawn.get("process_gid").map(String::as_str), Some("20")); - assert_eq!(spawn.get("os_uid").map(String::as_str), Some("501")); - assert_eq!(spawn.get("os_gid").map(String::as_str), Some("20")); -} - -#[test] -fn browser_sidecar_runs_guest_wasm_from_main_thread_workers() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - sidecar - .create_vm(permissive_config("vm-browser")) - .expect("create vm"); - - let context = sidecar - .create_wasm_context(CreateWasmContextRequest { - vm_id: String::from("vm-browser"), - module_path: Some(String::from("/workspace/app.wasm")), - }) - .expect("create WebAssembly context"); - let started = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id.clone(), - argv: vec![String::from("wasm"), String::from("/workspace/app.wasm")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start WebAssembly execution"); - - assert_eq!(sidecar.context_count("vm-browser"), 1); - assert_eq!(sidecar.active_worker_count("vm-browser"), 1); - - sidecar - .kill_execution(KillExecutionRequest { - vm_id: String::from("vm-browser"), - execution_id: started.execution_id, - signal: ExecutionSignal::Kill, - }) - .expect("kill execution"); - sidecar.dispose_vm("vm-browser").expect("dispose vm"); - - assert_eq!(sidecar.vm_count(), 0); - - let bridge = sidecar.into_bridge(); - assert_eq!(bridge.killed_executions.len(), 1); - assert_eq!( - bridge - .browser_worker_spawns - .first() - .and_then(|spawn| spawn.get("wasm_permission_tier")) - .map(String::as_str), - Some("Full") - ); - assert_eq!( - bridge - .lifecycle_events - .last() - .expect("final lifecycle event") - .state, - LifecycleState::Terminated - ); - assert!(bridge.structured_events.iter().any(|event| { - event.name == "browser.worker.spawned" - && event.fields.get("runtime") == Some(&String::from("webassembly")) - })); -} - -#[test] -fn browser_worker_spawn_requests_preserve_browser_entrypoints() { - let javascript = BrowserWorkerSpawnRequest { - vm_id: String::from("vm-browser"), - context_id: String::from("ctx-js"), - execution_id: String::from("exec-js"), - runtime: GuestRuntime::JavaScript, - entrypoint: BrowserWorkerEntrypoint::JavaScript { - bootstrap_module: Some(String::from("@secure-exec/browser")), - }, - wasm_permission_tier: None, - process_config: test_process_config(), - os_config: test_os_config(), - }; - let wasm = BrowserWorkerSpawnRequest { - vm_id: String::from("vm-browser"), - context_id: String::from("ctx-wasm"), - execution_id: String::from("exec-wasm"), - runtime: GuestRuntime::WebAssembly, - entrypoint: BrowserWorkerEntrypoint::WebAssembly { - module_path: Some(String::from("/workspace/app.wasm")), - }, - wasm_permission_tier: Some(WasmPermissionTier::ReadOnly), - process_config: test_process_config(), - os_config: test_os_config(), - }; - - assert!(matches!( - javascript.entrypoint, - BrowserWorkerEntrypoint::JavaScript { - bootstrap_module: Some(_) - } - )); - assert!(matches!( - wasm.entrypoint, - BrowserWorkerEntrypoint::WebAssembly { - module_path: Some(_) - } - )); -} - -#[test] -fn browser_sidecar_routes_kernel_filesystem_and_execution_state_through_vm_state() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - sidecar - .create_vm(permissive_config("vm-browser")) - .expect("create vm"); - - assert_eq!( - sidecar.kernel_state("vm-browser").expect("kernel ready"), - LifecycleState::Ready - ); - - sidecar - .mkdir("vm-browser", "/workspace", true) - .expect("create workspace"); - sidecar - .write_file("vm-browser", "/workspace/hello.txt", b"hello".to_vec()) - .expect("write kernel file"); - assert_eq!( - sidecar - .read_file("vm-browser", "/workspace/hello.txt") - .expect("read kernel file"), - b"hello".to_vec() - ); - assert_eq!( - sidecar - .read_dir("vm-browser", "/workspace") - .expect("read workspace"), - vec![String::from("hello.txt")] - ); - - let context = sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: Some(String::from("@secure-exec/browser")), - }) - .expect("create JavaScript context"); - let started = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id, - argv: vec![String::from("node"), String::from("script.js")], - env: BTreeMap::from([(String::from("MODE"), String::from("browser"))]), - cwd: String::from("/workspace"), - }) - .expect("start execution"); - - assert_eq!( - sidecar.kernel_state("vm-browser").expect("kernel busy"), - LifecycleState::Busy - ); - - sidecar - .write_stdin(secure_exec_bridge::WriteExecutionStdinRequest { - vm_id: String::from("vm-browser"), - execution_id: started.execution_id.clone(), - chunk: b"input".to_vec(), - }) - .expect("write stdin"); - assert_eq!( - sidecar - .read_execution_stdin( - "vm-browser", - &started.execution_id, - 16, - Duration::from_millis(5), - ) - .expect("read stdin"), - Some(b"input".to_vec()) - ); - - sidecar - .bridge_mut() - .push_execution_event(ExecutionEvent::GuestRequest(GuestKernelCall { - vm_id: String::from("vm-browser"), - execution_id: started.execution_id.clone(), - operation: String::from("fs.read"), - payload: b"{\"path\":\"/workspace/input.txt\"}".to_vec(), - })); - sidecar - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-browser"), - }) - .expect("poll guest kernel call"); - let guest_call_events = sidecar - .bridge() - .structured_events - .iter() - .filter(|event| event.name == "guest.kernel_call.unsupported") - .collect::>(); - assert_eq!(guest_call_events.len(), 1); - assert_eq!( - guest_call_events[0].fields["execution_id"], - started.execution_id - ); - assert_eq!(guest_call_events[0].fields["operation"], "fs.read"); - assert_eq!( - guest_call_events[0].fields["payload_size_bytes"], - b"{\"path\":\"/workspace/input.txt\"}".len().to_string() - ); - - sidecar - .bridge_mut() - .push_execution_event(ExecutionEvent::SignalState(ExecutionSignalState { - vm_id: String::from("vm-browser"), - execution_id: started.execution_id.clone(), - signal: 15, - registration: SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![2], - flags: 0, - }, - })); - sidecar - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-browser"), - }) - .expect("poll signal state"); - let signal_state = sidecar - .signal_state("vm-browser", &started.execution_id) - .expect("signal state"); - let sigterm = signal_state.get(&15).expect("SIGTERM handler"); - assert_eq!( - sigterm.action, - secure_exec_sidecar_protocol::wire::SignalDispositionAction::User - ); - assert_eq!(sigterm.mask, vec![2]); - - sidecar - .create_kernel_tcp_listener_for_execution( - "vm-browser", - &started.execution_id, - "127.0.0.1", - 34567, - 16, - ) - .expect("create listener owned by execution"); - sidecar - .create_kernel_bound_udp_for_execution( - "vm-browser", - &started.execution_id, - "127.0.0.1", - 34568, - ) - .expect("create UDP binding owned by execution"); - assert!(sidecar - .find_listener( - "vm-browser", - &FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34567), - path: None, - }, - ) - .expect("find listener before exit") - .is_some()); - assert!(sidecar - .find_bound_udp( - "vm-browser", - &FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34568), - }, - ) - .expect("find UDP binding before exit") - .is_some()); - - sidecar - .bridge_mut() - .push_execution_event(ExecutionEvent::Exited(ExecutionExited { - vm_id: String::from("vm-browser"), - execution_id: started.execution_id.clone(), - exit_code: 0, - })); - sidecar - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-browser"), - }) - .expect("poll exit"); - - assert_eq!( - sidecar - .kernel_state("vm-browser") - .expect("kernel ready after exit"), - LifecycleState::Ready - ); - assert!(sidecar - .signal_state("vm-browser", &started.execution_id) - .expect("signal state after exit") - .is_empty()); - assert!(sidecar - .find_listener( - "vm-browser", - &FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34567), - path: None, - }, - ) - .expect("find listener after exit") - .is_none()); - assert!(sidecar - .find_bound_udp( - "vm-browser", - &FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34568), - }, - ) - .expect("find UDP binding after exit") - .is_none()); -} - -#[test] -fn browser_sidecar_routes_guest_kernel_call_net_loopback_through_vm_state() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - sidecar - .create_vm(permissive_config("vm-browser")) - .expect("create vm"); - let context = sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: Some(String::from("@secure-exec/browser")), - }) - .expect("create JavaScript context"); - let started = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id, - argv: vec![String::from("node"), String::from("script.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start execution"); - - // The synchronous guest kernel-call path (`GuestKernelCallRequest` -> - // shared `handle_guest_kernel_call` -> kernel sockets) is the converged - // replacement for the fire-and-forget `GuestRequest` bail. Drive a full - // loopback TCP exchange through it to prove the wiring end to end. - let call = |sidecar: &mut BrowserSidecar, - operation: &str, - request: serde_json::Value| - -> serde_json::Value { - let result = sidecar - .guest_kernel_call( - "vm-browser", - GuestKernelCallRequest { - execution_id: started.execution_id.clone(), - operation: String::from(operation), - payload: serde_json::to_vec(&request).expect("encode request"), - }, - ) - .expect("guest kernel call"); - serde_json::from_slice(&result.payload).expect("decode response") - }; - - let listener = call( - &mut sidecar, - "net.listen", - serde_json::json!({ "host": "127.0.0.1", "port": 39221 }), - ); - let listener_id = listener["socketId"].as_u64().expect("listener socket id"); - - let client = call( - &mut sidecar, - "net.connect", - serde_json::json!({ "host": "127.0.0.1", "port": 39221 }), - ); - let client_id = client["socketId"].as_u64().expect("client socket id"); - - let accepted = call( - &mut sidecar, - "net.accept", - serde_json::json!({ "socketId": listener_id }), - ); - let accepted_id = accepted["socketId"].as_u64().expect("accepted socket id"); - - // base64("hello") == "aGVsbG8=" (asserted directly so no decode is needed). - let write = call( - &mut sidecar, - "net.write", - serde_json::json!({ "socketId": client_id, "data": "aGVsbG8=" }), - ); - assert_eq!(write["written"].as_u64(), Some(5)); - - let read = call( - &mut sidecar, - "net.read", - serde_json::json!({ "socketId": accepted_id }), - ); - assert_eq!(read["closed"].as_bool(), Some(false)); - assert_eq!(read["data"].as_str(), Some("aGVsbG8=")); - - // Unknown operations surface as a rejected guest kernel call rather than a - // silent fail-open. - let error = sidecar - .guest_kernel_call( - "vm-browser", - GuestKernelCallRequest { - execution_id: started.execution_id.clone(), - operation: String::from("net.teleport"), - payload: b"{}".to_vec(), - }, - ) - .expect_err("unsupported operation rejected"); - assert!(error - .to_string() - .contains("unsupported guest kernel call operation: net.teleport")); -} - -#[test] -fn browser_sidecar_keeps_kernel_sockets_scoped_per_execution() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - sidecar - .create_vm(permissive_config("vm-browser")) - .expect("create vm"); - - let context = sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: Some(String::from("@secure-exec/browser")), - }) - .expect("create JavaScript context"); - - let first = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id.clone(), - argv: vec![String::from("node"), String::from("first.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start first execution"); - let second = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id, - argv: vec![String::from("node"), String::from("second.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start second execution"); - - sidecar - .create_kernel_tcp_listener_for_execution( - "vm-browser", - &first.execution_id, - "127.0.0.1", - 34601, - 16, - ) - .expect("create first listener"); - sidecar - .create_kernel_tcp_listener_for_execution( - "vm-browser", - &second.execution_id, - "127.0.0.1", - 34602, - 16, - ) - .expect("create second listener"); - sidecar - .create_kernel_bound_udp_for_execution( - "vm-browser", - &first.execution_id, - "127.0.0.1", - 34611, - ) - .expect("create first UDP binding"); - sidecar - .create_kernel_bound_udp_for_execution( - "vm-browser", - &second.execution_id, - "127.0.0.1", - 34612, - ) - .expect("create second UDP binding"); - - let second_listener = sidecar - .find_listener( - "vm-browser", - &FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34602), - path: None, - }, - ) - .expect("find second listener before exit") - .expect("second listener exists"); - assert_eq!(second_listener.process_id, second.execution_id); - - sidecar - .bridge_mut() - .push_execution_event(ExecutionEvent::Exited(ExecutionExited { - vm_id: String::from("vm-browser"), - execution_id: first.execution_id.clone(), - exit_code: 0, - })); - sidecar - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-browser"), - }) - .expect("poll first exit"); - - assert!(sidecar - .find_listener( - "vm-browser", - &FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34601), - path: None, - }, - ) - .expect("find first listener after exit") - .is_none()); - assert!(sidecar - .find_bound_udp( - "vm-browser", - &FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34611), - }, - ) - .expect("find first UDP binding after exit") - .is_none()); - - let second_listener = sidecar - .find_listener( - "vm-browser", - &FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34602), - path: None, - }, - ) - .expect("find second listener after first exit") - .expect("second listener remains"); - assert_eq!(second_listener.process_id, second.execution_id); - let second_udp = sidecar - .find_bound_udp( - "vm-browser", - &FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34612), - }, - ) - .expect("find second UDP binding after first exit") - .expect("second UDP binding remains"); - assert_eq!(second_udp.process_id, second.execution_id); - assert_eq!( - sidecar.kernel_state("vm-browser").expect("kernel state"), - LifecycleState::Busy - ); -} - -#[test] -fn browser_sidecar_kernel_tcp_listener_obeys_vm_network_policy() { - let requests = Arc::new(Mutex::new(Vec::new())); - let requests_for_callback = Arc::clone(&requests); - let mut config = KernelVmConfig::new("vm-browser"); - config.permissions = Permissions { - network: Some(Arc::new(move |request: &NetworkAccessRequest| { - requests_for_callback - .lock() - .expect("request log lock") - .push(request.clone()); - PermissionDecision::deny("network disabled") - })), - ..Permissions::allow_all() - }; - - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - sidecar.create_vm(config).expect("create vm"); - - let context = sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: Some(String::from("@secure-exec/browser")), - }) - .expect("create JavaScript context"); - let started = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id, - argv: vec![String::from("node"), String::from("server.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start execution"); - - let error = sidecar - .create_kernel_tcp_listener_for_execution( - "vm-browser", - &started.execution_id, - "127.0.0.1", - 34621, - 16, - ) - .expect_err("TCP listener should be denied by network policy"); - - assert!( - error.to_string().contains("EACCES"), - "unexpected error: {error}" - ); - assert!(sidecar - .find_listener( - "vm-browser", - &FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34621), - path: None, - }, - ) - .expect("find listener after denied bind") - .is_none()); - assert_eq!( - *requests.lock().expect("request log lock"), - vec![NetworkAccessRequest { - vm_id: String::from("vm-browser"), - op: NetworkOperation::Listen, - resource: String::from("tcp://127.0.0.1:34621"), - }] - ); -} - -#[test] -fn browser_sidecar_reaps_kernel_process_after_normal_execution_exit() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - let mut config = KernelVmConfig::new("vm-browser"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_processes: Some(1), - ..ResourceLimits::default() - }; - sidecar.create_vm(config).expect("create vm"); - - let context = sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: Some(String::from("@secure-exec/browser")), - }) - .expect("create JavaScript context"); - - let started = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id.clone(), - argv: vec![String::from("node"), String::from("script.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("start first execution"); - - sidecar - .bridge_mut() - .push_execution_event(ExecutionEvent::Exited(ExecutionExited { - vm_id: String::from("vm-browser"), - execution_id: started.execution_id, - exit_code: 0, - })); - sidecar - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-browser"), - }) - .expect("poll exit"); - - sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id, - argv: vec![String::from("node"), String::from("script.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("completed execution should not leak the one-process limit"); -} - -#[test] -fn browser_sidecar_preserves_default_deny_kernel_permissions() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - sidecar - .create_vm(KernelVmConfig::new("vm-browser")) - .expect("create vm"); - - let error = sidecar - .write_file("vm-browser", "/workspace/denied.txt", b"denied".to_vec()) - .expect_err("default permissions should deny filesystem writes"); - - // Under default deny-all the write's parent-directory resolution is the - // first denied operation, so the error reports the read denial on the - // parent; the write itself never proceeds. - assert_eq!( - error.to_string(), - "EACCES: permission denied, read '/workspace'" - ); -} - -#[test] -fn browser_sidecar_builds_mount_table_root_from_root_filesystem_config() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - sidecar - .create_vm_with_root_filesystem( - permissive_config("vm-browser"), - RootFilesystemConfig { - disable_default_base_layer: true, - lowers: vec![ - RootFilesystemLowerDescriptor::Snapshot { - entries: vec![ - RootFilesystemEntry { - path: String::from("/workspace/shared.txt"), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("higher")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }, - RootFilesystemEntry { - path: String::from("/workspace/higher-only.txt"), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("higher-only")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }, - ], - }, - RootFilesystemLowerDescriptor::Snapshot { - entries: vec![ - RootFilesystemEntry { - path: String::from("/workspace/shared.txt"), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("lower")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }, - RootFilesystemEntry { - path: String::from("/workspace/lower-only.txt"), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("lower-only")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }, - ], - }, - ], - bootstrap_entries: vec![ - RootFilesystemEntry { - path: String::from("/workspace/shared.txt"), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("upper")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }, - RootFilesystemEntry { - path: String::from("/workspace/upper-only.txt"), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("upper-only")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }, - ], - ..RootFilesystemConfig::default() - }, - ) - .expect("create vm with root filesystem config"); - - for (path, expected) in [ - ("/workspace/shared.txt", b"upper".as_slice()), - ("/workspace/higher-only.txt", b"higher-only".as_slice()), - ("/workspace/lower-only.txt", b"lower-only".as_slice()), - ("/workspace/upper-only.txt", b"upper-only".as_slice()), - ] { - assert_eq!( - sidecar - .read_file("vm-browser", path) - .unwrap_or_else(|error| panic!("read {path}: {error}")), - expected.to_vec() - ); - } - sidecar - .write_file("vm-browser", "/workspace/new.txt", b"new-upper".to_vec()) - .expect("write upper entry"); - - let snapshot = sidecar - .snapshot_root_filesystem("vm-browser") - .expect("snapshot root filesystem"); - assert!(snapshot.entries.iter().any(|entry| { - entry.path == "/workspace/new.txt" - && entry.kind == FilesystemEntryKind::File - && entry.content.as_deref() == Some(b"new-upper".as_slice()) - })); -} - -#[test] -fn browser_sidecar_locks_read_only_root_after_bootstrap() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - sidecar - .create_vm_with_root_filesystem( - permissive_config("vm-browser"), - RootFilesystemConfig { - mode: RootFilesystemMode::ReadOnly, - disable_default_base_layer: true, - bootstrap_entries: vec![RootFilesystemEntry { - path: String::from("/workspace/bootstrap.txt"), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("bootstrapped")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - ..RootFilesystemConfig::default() - }, - ) - .expect("create read-only VM with bootstrap entries"); - - assert_eq!( - sidecar - .read_file("vm-browser", "/workspace/bootstrap.txt") - .expect("read bootstrap entry"), - b"bootstrapped".to_vec() - ); - - let error = sidecar - .write_file("vm-browser", "/workspace/new.txt", b"new".to_vec()) - .expect_err("read-only root should reject writes after bootstrap"); - assert_eq!( - error.to_string(), - "EROFS: read-only filesystem: /workspace/new.txt" - ); -} - -#[test] -fn browser_sidecar_reaps_pending_kernel_process_when_worker_startup_fails() { - let mut bridge = RecordingBridge::default(); - bridge.push_worker_create_error("worker startup failed"); - - let mut sidecar = BrowserSidecar::new(bridge, BrowserSidecarConfig::default()); - let mut config = KernelVmConfig::new("vm-browser"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_processes: Some(1), - ..ResourceLimits::default() - }; - sidecar.create_vm(config).expect("create vm"); - - let context = sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: Some(String::from("@secure-exec/browser")), - }) - .expect("create JavaScript context"); - - let failed = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id.clone(), - argv: vec![String::from("node"), String::from("script.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect_err("worker creation should fail"); - - assert!(failed.to_string().contains("worker startup failed")); - assert_eq!(sidecar.active_worker_count("vm-browser"), 0); - assert_eq!(sidecar.bridge().killed_executions.len(), 1); - assert_eq!(sidecar.bridge().killed_executions[0].execution_id, "exec-1"); - assert_eq!( - sidecar.kernel_state("vm-browser").expect("kernel ready"), - LifecycleState::Ready - ); - - let started = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id, - argv: vec![String::from("node"), String::from("script.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("leaked pending process would exhaust the one-process limit"); - - assert_eq!(started.execution_id, "exec-2"); - assert_eq!(sidecar.active_worker_count("vm-browser"), 1); -} - -#[test] -fn browser_sidecar_reaps_pending_kernel_process_when_stdio_setup_fails() { - let mut sidecar = - BrowserSidecar::new(RecordingBridge::default(), BrowserSidecarConfig::default()); - let mut config = KernelVmConfig::new("vm-browser"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_processes: Some(1), - max_pipes: Some(0), - ..ResourceLimits::default() - }; - sidecar.create_vm(config).expect("create vm"); - - let context = sidecar - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-browser"), - bootstrap_module: Some(String::from("@secure-exec/browser")), - }) - .expect("create JavaScript context"); - - for _ in 0..2 { - let failed = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id.clone(), - argv: vec![String::from("node"), String::from("script.js")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect_err("stdio setup should fail before worker creation"); - - assert!(failed.to_string().contains("maximum pipe count reached")); - assert_eq!(sidecar.active_worker_count("vm-browser"), 0); - assert_eq!( - sidecar.kernel_state("vm-browser").expect("kernel ready"), - LifecycleState::Ready - ); - } -} - -#[test] -fn browser_sidecar_reaps_pending_kernel_process_when_bridge_execution_start_fails() { - let mut bridge = RecordingBridge::default(); - bridge.push_execution_start_error("execution start failed"); - - let mut sidecar = BrowserSidecar::new(bridge, BrowserSidecarConfig::default()); - let mut config = KernelVmConfig::new("vm-browser"); - config.permissions = Permissions::allow_all(); - config.resources = ResourceLimits { - max_processes: Some(1), - ..ResourceLimits::default() - }; - sidecar.create_vm(config).expect("create vm"); - - let context = sidecar - .create_wasm_context(CreateWasmContextRequest { - vm_id: String::from("vm-browser"), - module_path: Some(String::from("/workspace/app.wasm")), - }) - .expect("create WebAssembly context"); - - let failed = sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id.clone(), - argv: vec![String::from("wasm"), String::from("/workspace/app.wasm")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect_err("execution start should fail"); - - assert!(failed.to_string().contains("execution start failed")); - assert_eq!(sidecar.active_worker_count("vm-browser"), 0); - assert_eq!( - sidecar.kernel_state("vm-browser").expect("kernel ready"), - LifecycleState::Ready - ); - assert!(sidecar.bridge().terminated_workers.is_empty()); - - sidecar - .start_execution(StartExecutionRequest { - vm_id: String::from("vm-browser"), - context_id: context.context_id, - argv: vec![String::from("wasm"), String::from("/workspace/app.wasm")], - env: BTreeMap::new(), - cwd: String::from("/workspace"), - }) - .expect("leaked pending process would exhaust the one-process limit"); -} diff --git a/crates/sidecar-browser/tests/smoke.rs b/crates/sidecar-browser/tests/smoke.rs deleted file mode 100644 index 3b84767a0..000000000 --- a/crates/sidecar-browser/tests/smoke.rs +++ /dev/null @@ -1,147 +0,0 @@ -#[path = "../../bridge/tests/support.rs"] -mod bridge_support; - -use bridge_support::RecordingBridge; -use secure_exec_kernel::kernel::KernelVmConfig; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_sidecar_browser::{ - scaffold, BrowserExtension, BrowserExtensionContext, BrowserExtensionRequest, BrowserSidecar, - BrowserSidecarConfig, BrowserWorkerBridge, BrowserWorkerHandle, BrowserWorkerHandleRequest, - BrowserWorkerSpawnRequest, -}; - -struct SmokeExtension(&'static str); - -impl BrowserExtension for SmokeExtension { - fn namespace(&self) -> &str { - self.0 - } - - fn handle_request( - &self, - context: &mut BrowserExtensionContext<'_>, - payload: &[u8], - ) -> Result, secure_exec_sidecar_browser::BrowserSidecarError> { - if payload == b"context-fs" { - context.mkdir("vm-ext", "/workspace", true)?; - context.write_file("vm-ext", "/workspace/context.txt", b"from-context")?; - return context.read_file("vm-ext", "/workspace/context.txt"); - } - let mut response = self.0.as_bytes().to_vec(); - response.push(b':'); - response.extend_from_slice(payload); - Ok(response) - } -} - -impl BrowserWorkerBridge for RecordingBridge { - fn create_worker( - &mut self, - request: BrowserWorkerSpawnRequest, - ) -> Result { - Ok(BrowserWorkerHandle { - worker_id: format!("smoke-worker-{}", request.context_id), - runtime: request.runtime, - }) - } - - fn terminate_worker( - &mut self, - _request: BrowserWorkerHandleRequest, - ) -> Result<(), Self::Error> { - Ok(()) - } -} - -fn permissive_config(vm_id: &str) -> KernelVmConfig { - let mut config = KernelVmConfig::new(vm_id); - config.permissions = Permissions::allow_all(); - config -} - -#[test] -fn browser_sidecar_scaffold_stays_on_main_thread_with_shared_kernel() { - let scaffold = scaffold(); - - assert_eq!(scaffold.package_name, "secure-exec-sidecar-browser"); - assert_eq!(scaffold.kernel_package, "secure-exec-kernel"); - assert_eq!(scaffold.execution_host_thread, "main"); - assert_eq!(scaffold.guest_worker_owner_thread, "main"); -} - -#[test] -fn browser_sidecar_accepts_extension_signature() { - let mut sidecar = BrowserSidecar::with_extensions( - RecordingBridge::default(), - BrowserSidecarConfig::default(), - vec![Box::new(SmokeExtension("dev.rivet.agentos.browser-smoke"))], - ) - .expect("construct browser sidecar with extension"); - - assert_eq!(sidecar.extension_count(), 1); - assert!(sidecar.has_extension("dev.rivet.agentos.browser-smoke")); - - let error = sidecar - .register_extension(Box::new(SmokeExtension("dev.rivet.agentos.browser-smoke"))) - .expect_err("duplicate extension namespace should fail"); - assert!(error - .to_string() - .contains("browser extension namespace already registered")); -} - -#[test] -fn browser_sidecar_dispatches_extension_requests_by_namespace() { - let mut sidecar = BrowserSidecar::with_extensions( - RecordingBridge::default(), - BrowserSidecarConfig::default(), - vec![Box::new(SmokeExtension("dev.rivet.agentos.browser-smoke"))], - ) - .expect("construct browser sidecar with extension"); - - let response = sidecar - .dispatch_extension_request(BrowserExtensionRequest { - namespace: String::from("dev.rivet.agentos.browser-smoke"), - payload: b"ping".to_vec(), - vm_id: None, - connection_id: None, - }) - .expect("dispatch extension request"); - assert_eq!(response.namespace, "dev.rivet.agentos.browser-smoke"); - assert_eq!(response.payload, b"dev.rivet.agentos.browser-smoke:ping"); - - let error = sidecar - .dispatch_extension_request(BrowserExtensionRequest { - namespace: String::from("missing"), - payload: Vec::new(), - vm_id: None, - connection_id: None, - }) - .expect_err("unknown extension namespace should fail"); - assert!(error - .to_string() - .contains("no browser extension registered for namespace missing")); -} - -#[test] -fn browser_extension_context_exposes_vm_filesystem_primitives() { - let mut sidecar = BrowserSidecar::with_extensions( - RecordingBridge::default(), - BrowserSidecarConfig::default(), - vec![Box::new(SmokeExtension("dev.rivet.agentos.browser-smoke"))], - ) - .expect("construct browser sidecar with extension"); - sidecar - .create_vm(permissive_config("vm-ext")) - .expect("create vm for extension context"); - - let response = sidecar - .dispatch_extension_request(BrowserExtensionRequest { - namespace: String::from("dev.rivet.agentos.browser-smoke"), - payload: b"context-fs".to_vec(), - vm_id: Some(String::from("vm-ext")), - connection_id: Some(String::from("conn-ext")), - }) - .expect("dispatch extension request through context"); - - assert_eq!(response.payload, b"from-context"); -} diff --git a/crates/sidecar-browser/tests/wire_dispatch.rs b/crates/sidecar-browser/tests/wire_dispatch.rs deleted file mode 100644 index 6e1c9b0f6..000000000 --- a/crates/sidecar-browser/tests/wire_dispatch.rs +++ /dev/null @@ -1,1745 +0,0 @@ -#[path = "../../bridge/tests/support.rs"] -mod bridge_support; - -use bridge_support::RecordingBridge; -use secure_exec_bridge::{ - CreateJavascriptContextRequest, ExecutionEvent, ExecutionSignal, ExecutionSignalState, - GuestKernelCall, OutputChunk, SignalDispositionAction, SignalHandlerRegistration, - StartExecutionRequest, -}; -use secure_exec_kernel::kernel::KernelVmConfig; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_sidecar_browser::{ - wire_dispatch::BrowserWireDispatcher, BrowserExtension, BrowserExtensionContext, - BrowserSidecarError, BrowserWorkerBridge, BrowserWorkerHandle, BrowserWorkerHandleRequest, - BrowserWorkerSpawnRequest, -}; -use secure_exec_sidecar_protocol::wire::{ - protocol_schema, AuthenticateRequest, BootstrapRootFilesystemRequest, ConfigureVmRequest, - ConnectionOwnership, CreateOverlayRequest, CreateVmRequest, ExecuteRequest, - ExportSnapshotRequest, ExtEnvelope, FilesystemOperation, FindBoundUdpRequest, - FindListenerRequest, GetSignalStateRequest, GuestFilesystemCallRequest, - GuestFilesystemOperation, GuestRuntimeKind, HostFilesystemCallRequest, ImportSnapshotRequest, - KillProcessRequest, OpenSessionRequest, OwnershipScope, PermissionsPolicy, - PersistenceFlushRequest, PersistenceLoadRequest, ProtocolFrame, RegisterHostCallbacksRequest, - RegisteredHostCallbackDefinition, RequestFrame, RequestPayload, ResponsePayload, - RootFilesystemEntry, RootFilesystemEntryEncoding, RootFilesystemEntryKind, RootFilesystemMode, - SealLayerRequest, SidecarPlacement, SidecarPlacementShared, VmFetchRequest, VmOwnership, - WasmPermissionTier, WireFrameCodec, PROTOCOL_VERSION, -}; -use std::collections::{BTreeMap, HashMap}; - -struct WireExtension; - -impl BrowserExtension for WireExtension { - fn namespace(&self) -> &str { - "dev.rivet.secure-exec.browser-wire-test" - } - - fn handle_request( - &self, - _context: &mut BrowserExtensionContext<'_>, - payload: &[u8], - ) -> Result, BrowserSidecarError> { - let mut response = b"wire-ext:".to_vec(); - response.extend_from_slice(payload); - Ok(response) - } -} - -impl BrowserWorkerBridge for RecordingBridge { - fn create_worker( - &mut self, - request: BrowserWorkerSpawnRequest, - ) -> Result { - self.browser_worker_spawns.push(BTreeMap::from([( - String::from("wasm_permission_tier"), - request - .wasm_permission_tier - .map(|tier| format!("{tier:?}")) - .unwrap_or_default(), - )])); - Ok(BrowserWorkerHandle { - worker_id: format!("wire-worker-{}", request.context_id), - runtime: request.runtime, - }) - } - - fn terminate_worker( - &mut self, - _request: BrowserWorkerHandleRequest, - ) -> Result<(), Self::Error> { - Ok(()) - } -} - -fn create_wire_vm( - codec: &WireFrameCodec, - dispatcher: &mut BrowserWireDispatcher, -) -> (String, OwnershipScope) { - let auth = dispatch( - codec, - dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: String::from("client"), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("browser-wire-test"), - auth_token: String::from("test-token"), - protocol_version: PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - }, - ); - let ResponsePayload::AuthenticatedResponse(authenticated) = auth.payload else { - panic!("unexpected auth response: {:?}", auth.payload); - }; - let connection = OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: authenticated.connection_id.clone(), - }); - let session = dispatch( - codec, - dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 2, - ownership: connection, - payload: RequestPayload::OpenSessionRequest(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: None, - }), - metadata: Default::default(), - }), - }, - ); - let ResponsePayload::SessionOpenedResponse(opened) = session.payload else { - panic!("unexpected session response: {:?}", session.payload); - }; - let config = secure_exec_vm_config::CreateVmConfig { - cwd: Some(String::from("/workspace")), - permissions: Some(secure_exec_sidecar_core::allow_all_policy()), - ..Default::default() - }; - let created = dispatch( - codec, - dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 3, - ownership: OwnershipScope::SessionOwnership( - secure_exec_sidecar_protocol::wire::SessionOwnership { - connection_id: authenticated.connection_id.clone(), - session_id: opened.session_id.clone(), - }, - ), - payload: RequestPayload::CreateVmRequest(CreateVmRequest::json_config( - GuestRuntimeKind::JavaScript, - config, - )), - }, - ); - let ResponsePayload::VmCreatedResponse(created) = created.payload else { - panic!("unexpected create VM response: {:?}", created.payload); - }; - let ownership = OwnershipScope::VmOwnership(VmOwnership { - connection_id: authenticated.connection_id, - session_id: opened.session_id, - vm_id: created.vm_id.clone(), - }); - (created.vm_id, ownership) -} - -fn execute_wire_process( - codec: &WireFrameCodec, - dispatcher: &mut BrowserWireDispatcher, - ownership: OwnershipScope, - request_id: i64, - process_id: &str, -) -> ResponsePayload { - dispatch( - codec, - dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id, - ownership, - payload: RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: process_id.to_string(), - command: Some(String::from("node")), - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(String::from("/workspace/main.js")), - args: vec![String::from("main.js")], - env: Default::default(), - cwd: Some(String::from("/workspace")), - wasm_permission_tier: None, - }), - }, - ) - .payload -} - -#[test] -fn browser_wire_dispatcher_handles_lifecycle_and_execution_frames() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - - let auth = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: String::from("client"), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("browser-wire-test"), - auth_token: String::from("test-token"), - protocol_version: PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - }, - ); - let ResponsePayload::AuthenticatedResponse(authenticated) = auth.payload else { - panic!("unexpected auth response: {:?}", auth.payload); - }; - assert_eq!(authenticated.sidecar_id, "secure-exec-sidecar-browser"); - - let session = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 2, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: authenticated.connection_id.clone(), - }), - payload: RequestPayload::OpenSessionRequest(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: None, - }), - metadata: Default::default(), - }), - }, - ); - let ResponsePayload::SessionOpenedResponse(opened) = session.payload else { - panic!("unexpected session response: {:?}", session.payload); - }; - - let mut config = secure_exec_vm_config::CreateVmConfig { - cwd: Some(String::from("/workspace")), - permissions: Some(secure_exec_sidecar_core::allow_all_policy()), - ..Default::default() - }; - config - .env - .insert(String::from("BASE_ENV"), String::from("base")); - let create = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 3, - ownership: OwnershipScope::SessionOwnership( - secure_exec_sidecar_protocol::wire::SessionOwnership { - connection_id: authenticated.connection_id.clone(), - session_id: opened.session_id.clone(), - }, - ), - payload: RequestPayload::CreateVmRequest(CreateVmRequest::json_config( - GuestRuntimeKind::JavaScript, - config, - )), - }, - ); - let ResponsePayload::VmCreatedResponse(created) = create.payload else { - panic!("unexpected create response: {:?}", create.payload); - }; - assert_eq!(dispatcher.vm_count(), 1); - - let ownership = OwnershipScope::VmOwnership(VmOwnership { - connection_id: authenticated.connection_id, - session_id: opened.session_id, - vm_id: created.vm_id.clone(), - }); - - let bootstrap = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 4, - ownership: ownership.clone(), - payload: RequestPayload::BootstrapRootFilesystemRequest( - BootstrapRootFilesystemRequest { - entries: vec![RootFilesystemEntry { - path: String::from("/workspace/wire.txt"), - kind: RootFilesystemEntryKind::File, - mode: Some(0o644), - uid: Some(1000), - gid: Some(1000), - content: Some(String::from("aGVsbG8gd2lyZQ==")), - encoding: Some(RootFilesystemEntryEncoding::Base64), - target: None, - executable: false, - }], - }, - ), - }, - ); - assert!(matches!( - bootstrap.payload, - ResponsePayload::RootFilesystemBootstrappedResponse(_) - )); - - let read_file = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 5, - ownership: ownership.clone(), - payload: RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/workspace/wire.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - }, - ); - let ResponsePayload::GuestFilesystemResultResponse(result) = read_file.payload else { - panic!("unexpected read_file response: {:?}", read_file.payload); - }; - assert_eq!(result.content.as_deref(), Some("hello wire")); - assert_eq!(result.encoding, Some(RootFilesystemEntryEncoding::Utf8)); - - let snapshot = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 6, - ownership: ownership.clone(), - payload: RequestPayload::SnapshotRootFilesystemRequest, - }, - ); - let ResponsePayload::RootFilesystemSnapshotResponse(snapshot) = snapshot.payload else { - panic!("unexpected snapshot response: {:?}", snapshot.payload); - }; - assert!(snapshot - .entries - .iter() - .any(|entry| entry.path == "/workspace/wire.txt" - && entry.content.as_deref() == Some("hello wire"))); - - let execute = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 7, - ownership: ownership.clone(), - payload: RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from("proc-1"), - command: Some(String::from("node")), - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(String::from("/workspace/main.js")), - args: vec![String::from("main.js")], - env: Default::default(), - cwd: Some(String::from("/workspace")), - wasm_permission_tier: None, - }), - }, - ); - assert!(matches!( - execute.payload, - ResponsePayload::ProcessStartedResponse(_) - )); - - dispatcher - .sidecar_mut() - .create_kernel_tcp_listener_for_execution(&created.vm_id, "exec-1", "127.0.0.1", 34567, 16) - .expect("create kernel listener"); - dispatcher - .sidecar_mut() - .create_kernel_bound_udp_for_execution(&created.vm_id, "exec-1", "127.0.0.1", 34568) - .expect("create kernel UDP socket"); - - let listener = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 71, - ownership: ownership.clone(), - payload: RequestPayload::FindListenerRequest(FindListenerRequest { - host: Some(String::from("localhost")), - port: Some(34567), - path: None, - }), - }, - ); - let ResponsePayload::ListenerSnapshotResponse(listener) = listener.payload else { - panic!("unexpected listener response: {:?}", listener.payload); - }; - let listener = listener.listener.expect("listener should be found"); - assert_eq!(listener.process_id, "proc-1"); - assert_eq!(listener.host.as_deref(), Some("127.0.0.1")); - assert_eq!(listener.port, Some(34567)); - - let udp = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 72, - ownership: ownership.clone(), - payload: RequestPayload::FindBoundUdpRequest(FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(34568), - }), - }, - ); - let ResponsePayload::BoundUdpSnapshotResponse(udp) = udp.payload else { - panic!("unexpected UDP response: {:?}", udp.payload); - }; - let udp = udp.socket.expect("UDP socket should be found"); - assert_eq!(udp.process_id, "proc-1"); - assert_eq!(udp.host.as_deref(), Some("127.0.0.1")); - assert_eq!(udp.port, Some(34568)); - - let snapshot = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 8, - ownership: ownership.clone(), - payload: RequestPayload::GetProcessSnapshotRequest, - }, - ); - let ResponsePayload::ProcessSnapshotResponse(snapshot) = snapshot.payload else { - panic!( - "unexpected process snapshot response: {:?}", - snapshot.payload - ); - }; - let process = snapshot - .processes - .iter() - .find(|process| process.process_id == "proc-1") - .expect("client process should be represented in snapshot"); - assert!(process.pid > 0); - assert_eq!(process.cwd, "/workspace"); - - dispatcher - .sidecar_mut() - .bridge_mut() - .push_execution_event(ExecutionEvent::SignalState(ExecutionSignalState { - vm_id: created.vm_id.clone(), - execution_id: String::from("exec-1"), - signal: 15, - registration: SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![2], - flags: 0, - }, - })); - while dispatcher - .poll_event_bytes() - .expect("pump signal state") - .is_some() - {} - - let signal_state = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 9, - ownership: ownership.clone(), - payload: RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("proc-1"), - }), - }, - ); - let ResponsePayload::SignalStateResponse(signal_state) = signal_state.payload else { - panic!( - "unexpected signal state response: {:?}", - signal_state.payload - ); - }; - assert_eq!(signal_state.process_id, "proc-1"); - let sigterm = signal_state.handlers.get(&15).expect("SIGTERM handler"); - assert_eq!( - sigterm.action, - secure_exec_sidecar_protocol::wire::SignalDispositionAction::User - ); - assert_eq!(sigterm.mask, vec![2]); - - let invalid_signal = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 91, - ownership: ownership.clone(), - payload: RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("proc-1"), - signal: String::from("SIGBOGUS"), - }), - }, - ); - let ResponsePayload::RejectedResponse(rejected) = invalid_signal.payload else { - panic!( - "unexpected invalid signal response: {:?}", - invalid_signal.payload - ); - }; - assert_eq!(rejected.code, "kill_process_failed"); - assert!(rejected - .message - .contains("unsupported kill_process signal SIGBOGUS")); - assert!(dispatcher - .sidecar_mut() - .bridge() - .killed_executions - .is_empty()); - - let signal_zero = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 92, - ownership: ownership.clone(), - payload: RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("proc-1"), - signal: String::from("0"), - }), - }, - ); - assert!(matches!( - signal_zero.payload, - ResponsePayload::ProcessKilledResponse(_) - )); - assert!(dispatcher - .sidecar_mut() - .bridge() - .killed_executions - .is_empty()); - - let continue_signal = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 94, - ownership: ownership.clone(), - payload: RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("proc-1"), - signal: String::from("SIGCONT"), - }), - }, - ); - assert!(matches!( - continue_signal.payload, - ResponsePayload::ProcessKilledResponse(_) - )); - assert!(dispatcher - .sidecar_mut() - .bridge() - .killed_executions - .is_empty()); - - let zombie_count = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 10, - ownership: ownership.clone(), - payload: RequestPayload::GetZombieTimerCountRequest, - }, - ); - let ResponsePayload::ZombieTimerCountResponse(zombie_count) = zombie_count.payload else { - panic!( - "unexpected zombie count response: {:?}", - zombie_count.payload - ); - }; - assert_eq!(zombie_count.count, 0); - - dispatcher - .sidecar_mut() - .bridge_mut() - .push_execution_event(ExecutionEvent::Stdout(OutputChunk { - vm_id: created.vm_id, - execution_id: String::from("exec-1"), - chunk: b"hello\n".to_vec(), - })); - let output = loop { - let event = dispatcher - .poll_event_bytes() - .expect("poll event") - .expect("event should be encoded"); - let ProtocolFrame::EventFrame(event) = codec.decode_message(&event).expect("decode event") - else { - panic!("expected event frame"); - }; - if let secure_exec_sidecar_protocol::wire::EventPayload::ProcessOutputEvent(output) = - event.payload - { - break output; - } - }; - assert_eq!(output.process_id, "proc-1"); - assert_eq!(output.chunk, b"hello\n"); - - dispatcher - .sidecar_mut() - .bridge_mut() - .push_execution_event(ExecutionEvent::GuestRequest(GuestKernelCall { - vm_id: String::from("vm-1"), - execution_id: String::from("exec-1"), - operation: String::from("fs.read"), - payload: b"{\"path\":\"/workspace/input.txt\"}".to_vec(), - })); - let guest_request_event = loop { - let event = dispatcher - .poll_event_bytes() - .expect("poll guest request event") - .expect("guest request event should be encoded"); - let ProtocolFrame::EventFrame(event) = codec.decode_message(&event).expect("decode event") - else { - panic!("expected event frame"); - }; - if let secure_exec_sidecar_protocol::wire::EventPayload::StructuredEvent(event) = - event.payload - { - if event.name == "guest.kernel_call.unsupported" { - break event; - } - } - }; - assert_eq!(guest_request_event.detail["process_id"], "proc-1"); - assert_eq!(guest_request_event.detail["execution_id"], "exec-1"); - assert_eq!(guest_request_event.detail["operation"], "fs.read"); - assert_eq!( - guest_request_event.detail["payload_size_bytes"], - b"{\"path\":\"/workspace/input.txt\"}".len().to_string() - ); - - let interrupt = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 93, - ownership, - payload: RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("proc-1"), - signal: String::from("SIGINT"), - }), - }, - ); - assert!(matches!( - interrupt.payload, - ResponsePayload::ProcessKilledResponse(_) - )); - let killed = &dispatcher.sidecar_mut().bridge().killed_executions; - assert_eq!(killed.len(), 1); - assert_eq!(killed[0].signal, ExecutionSignal::Interrupt); -} - -#[test] -fn browser_wire_dispatcher_rejects_duplicate_active_process_ids() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - let (_, ownership) = create_wire_vm(&codec, &mut dispatcher); - - let first = execute_wire_process(&codec, &mut dispatcher, ownership.clone(), 10, "proc-1"); - assert!(matches!(first, ResponsePayload::ProcessStartedResponse(_))); - - let duplicate = execute_wire_process(&codec, &mut dispatcher, ownership, 11, "proc-1"); - let ResponsePayload::RejectedResponse(rejected) = duplicate else { - panic!("unexpected duplicate process response: {:?}", duplicate); - }; - assert_eq!(rejected.code, "process_already_active"); - assert_eq!( - dispatcher - .sidecar_mut() - .bridge() - .browser_worker_spawns - .len(), - 1 - ); -} - -#[test] -fn browser_wire_dispatcher_rejects_protocol_version_mismatch() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - - let response = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: String::from("client"), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("browser-wire-test"), - auth_token: String::from("test-token"), - protocol_version: PROTOCOL_VERSION + 1, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - }, - ); - - let ResponsePayload::RejectedResponse(rejected) = response.payload else { - panic!("unexpected auth mismatch response: {:?}", response.payload); - }; - assert_eq!(rejected.code, "protocol_version_mismatch"); - assert!(rejected - .message - .contains("sidecar protocol version mismatch")); -} - -#[test] -fn browser_wire_dispatcher_rejects_bridge_contract_version_mismatch() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - - let response = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: String::from("client"), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("browser-wire-test"), - auth_token: String::from("test-token"), - protocol_version: PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version + 1, - }), - }, - ); - - let ResponsePayload::RejectedResponse(rejected) = response.payload else { - panic!( - "unexpected bridge mismatch response: {:?}", - response.payload - ); - }; - assert_eq!(rejected.code, "bridge_version_mismatch"); - assert!(rejected - .message - .contains("bridge contract version mismatch")); -} - -#[test] -fn browser_wire_dispatcher_routes_extension_frames() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - dispatcher - .sidecar_mut() - .register_extension(Box::new(WireExtension)) - .expect("register wire extension"); - - let response = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: String::from("client"), - }), - payload: RequestPayload::ExtEnvelope(ExtEnvelope { - namespace: String::from("dev.rivet.secure-exec.browser-wire-test"), - payload: b"ping".to_vec(), - }), - }, - ); - - let ResponsePayload::ExtEnvelope(envelope) = response.payload else { - panic!("unexpected extension response: {:?}", response.payload); - }; - assert_eq!( - envelope.namespace, - "dev.rivet.secure-exec.browser-wire-test" - ); - assert_eq!(envelope.payload, b"wire-ext:ping"); -} - -#[test] -fn browser_wire_dispatcher_configures_vm_permissions() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - let mut config = KernelVmConfig::new("vm-config"); - config.permissions = Permissions::allow_all(); - dispatcher - .sidecar_mut() - .create_vm(config) - .expect("create configurable vm"); - let ownership = OwnershipScope::VmOwnership(VmOwnership { - connection_id: String::from("conn"), - session_id: String::from("session"), - vm_id: String::from("vm-config"), - }); - - let bootstrap = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: ownership.clone(), - payload: RequestPayload::BootstrapRootFilesystemRequest( - BootstrapRootFilesystemRequest { - entries: vec![RootFilesystemEntry { - path: String::from("/workspace/config.txt"), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("before")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - }, - ), - }, - ); - assert!(matches!( - bootstrap.payload, - ResponsePayload::RootFilesystemBootstrappedResponse(_) - )); - - let configured = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 2, - ownership: ownership.clone(), - payload: RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: Some(PermissionsPolicy::deny_all()), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: Default::default(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - }), - }, - ); - let ResponsePayload::VmConfiguredResponse(configured) = configured.payload else { - panic!("unexpected configure response: {:?}", configured.payload); - }; - assert_eq!(configured.applied_mounts, 0); - assert_eq!(configured.applied_software, 0); - - let read_after_deny = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 3, - ownership, - payload: RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/workspace/config.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - }, - ); - let ResponsePayload::RejectedResponse(rejected) = read_after_deny.payload else { - panic!( - "unexpected read-after-configure response: {:?}", - read_after_deny.payload - ); - }; - assert_eq!(rejected.code, "guest_filesystem_failed"); -} - -#[test] -fn browser_wire_create_vm_without_permissions_defaults_to_deny_all() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - - let auth = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: String::from("client"), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("browser-wire-test"), - auth_token: String::from("test-token"), - protocol_version: PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - }, - ); - let ResponsePayload::AuthenticatedResponse(authenticated) = auth.payload else { - panic!("unexpected auth response: {:?}", auth.payload); - }; - let session = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 2, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: authenticated.connection_id.clone(), - }), - payload: RequestPayload::OpenSessionRequest(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: None, - }), - metadata: Default::default(), - }), - }, - ); - let ResponsePayload::SessionOpenedResponse(opened) = session.payload else { - panic!("unexpected session response: {:?}", session.payload); - }; - - let config = secure_exec_vm_config::CreateVmConfig { - cwd: Some(String::from("/workspace")), - permissions: None, - root_filesystem: secure_exec_vm_config::RootFilesystemConfig { - bootstrap_entries: vec![secure_exec_vm_config::RootFilesystemEntry { - path: String::from("/workspace/default-deny.txt"), - kind: secure_exec_vm_config::RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("secret")), - encoding: Some(secure_exec_vm_config::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - ..Default::default() - }, - ..Default::default() - }; - let create = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 3, - ownership: OwnershipScope::SessionOwnership( - secure_exec_sidecar_protocol::wire::SessionOwnership { - connection_id: authenticated.connection_id.clone(), - session_id: opened.session_id.clone(), - }, - ), - payload: RequestPayload::CreateVmRequest(CreateVmRequest::json_config( - GuestRuntimeKind::JavaScript, - config, - )), - }, - ); - let ResponsePayload::VmCreatedResponse(created) = create.payload else { - panic!("unexpected create response: {:?}", create.payload); - }; - - let read = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 4, - ownership: OwnershipScope::VmOwnership(VmOwnership { - connection_id: authenticated.connection_id, - session_id: opened.session_id, - vm_id: created.vm_id, - }), - payload: RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/workspace/default-deny.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - }, - ); - let ResponsePayload::RejectedResponse(rejected) = read.payload else { - panic!("unexpected default-deny read response: {:?}", read.payload); - }; - assert_eq!(rejected.code, "guest_filesystem_failed"); -} - -#[test] -fn browser_wire_create_vm_applies_read_only_root_filesystem_config() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - - let auth = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: String::from("client"), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("browser-wire-test"), - auth_token: String::from("test-token"), - protocol_version: PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - }, - ); - let ResponsePayload::AuthenticatedResponse(authenticated) = auth.payload else { - panic!("unexpected auth response: {:?}", auth.payload); - }; - let session = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 2, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: authenticated.connection_id.clone(), - }), - payload: RequestPayload::OpenSessionRequest(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: None, - }), - metadata: Default::default(), - }), - }, - ); - let ResponsePayload::SessionOpenedResponse(opened) = session.payload else { - panic!("unexpected session response: {:?}", session.payload); - }; - - let config = secure_exec_vm_config::CreateVmConfig { - cwd: Some(String::from("/workspace")), - permissions: Some(secure_exec_sidecar_core::allow_all_policy()), - root_filesystem: secure_exec_vm_config::RootFilesystemConfig { - mode: secure_exec_vm_config::RootFilesystemMode::ReadOnly, - disable_default_base_layer: true, - bootstrap_entries: vec![secure_exec_vm_config::RootFilesystemEntry { - path: String::from("/workspace/bootstrap.txt"), - kind: secure_exec_vm_config::RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("bootstrapped")), - encoding: Some(secure_exec_vm_config::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - ..Default::default() - }, - ..Default::default() - }; - let create = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 3, - ownership: OwnershipScope::SessionOwnership( - secure_exec_sidecar_protocol::wire::SessionOwnership { - connection_id: authenticated.connection_id.clone(), - session_id: opened.session_id.clone(), - }, - ), - payload: RequestPayload::CreateVmRequest(CreateVmRequest::json_config( - GuestRuntimeKind::JavaScript, - config, - )), - }, - ); - let ResponsePayload::VmCreatedResponse(created) = create.payload else { - panic!("unexpected create response: {:?}", create.payload); - }; - let ownership = OwnershipScope::VmOwnership(VmOwnership { - connection_id: authenticated.connection_id, - session_id: opened.session_id, - vm_id: created.vm_id, - }); - - let read = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 4, - ownership: ownership.clone(), - payload: RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/workspace/bootstrap.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - }, - ); - let ResponsePayload::GuestFilesystemResultResponse(read) = read.payload else { - panic!("unexpected read response: {:?}", read.payload); - }; - assert_eq!(read.content.as_deref(), Some("bootstrapped")); - - let write = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 5, - ownership, - payload: RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/workspace/new.txt"), - destination_path: None, - target: None, - content: Some(String::from("new")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - recursive: false, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - }, - ); - let ResponsePayload::RejectedResponse(rejected) = write.payload else { - panic!("unexpected write response: {:?}", write.payload); - }; - assert_eq!(rejected.code, "guest_filesystem_failed"); - assert_eq!( - rejected.message, - "EROFS: read-only filesystem: /workspace/new.txt" - ); -} - -#[test] -fn browser_wire_dispatcher_configures_wasm_command_permissions() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - let mut config = KernelVmConfig::new("vm-wasm-perms"); - config.permissions = Permissions::allow_all(); - dispatcher - .sidecar_mut() - .create_vm(config) - .expect("create wasm permissions vm"); - let ownership = OwnershipScope::VmOwnership(VmOwnership { - connection_id: String::from("conn"), - session_id: String::from("session"), - vm_id: String::from("vm-wasm-perms"), - }); - - let configured = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: ownership.clone(), - payload: RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: vec![String::from("keep wasm read-only")], - projected_modules: Vec::new(), - command_permissions: HashMap::from([( - String::from("wasm"), - WasmPermissionTier::ReadOnly, - )]), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - }), - }, - ); - assert!(matches!( - configured.payload, - ResponsePayload::VmConfiguredResponse(_) - )); - - let executed = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 2, - ownership: ownership.clone(), - payload: RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from("proc-wasm"), - command: Some(String::from("wasm")), - runtime: Some(GuestRuntimeKind::WebAssembly), - entrypoint: Some(String::from("/workspace/app.wasm")), - args: vec![String::from("/workspace/app.wasm")], - env: Default::default(), - cwd: Some(String::from("/workspace")), - wasm_permission_tier: None, - }), - }, - ); - assert!(matches!( - executed.payload, - ResponsePayload::ProcessStartedResponse(_) - )); - assert_eq!( - dispatcher - .sidecar_mut() - .bridge() - .browser_worker_spawns - .first() - .and_then(|spawn| spawn.get("wasm_permission_tier")) - .map(String::as_str), - Some("ReadOnly") - ); - - let explicit = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 3, - ownership, - payload: RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from("proc-wasm-explicit"), - command: Some(String::from("wasm")), - runtime: Some(GuestRuntimeKind::WebAssembly), - entrypoint: Some(String::from("/workspace/app.wasm")), - args: vec![String::from("/workspace/app.wasm")], - env: Default::default(), - cwd: Some(String::from("/workspace")), - wasm_permission_tier: Some(WasmPermissionTier::ReadWrite), - }), - }, - ); - assert!(matches!( - explicit.payload, - ResponsePayload::ProcessStartedResponse(_) - )); - assert_eq!( - dispatcher - .sidecar_mut() - .bridge() - .browser_worker_spawns - .get(1) - .and_then(|spawn| spawn.get("wasm_permission_tier")) - .map(String::as_str), - Some("ReadWrite") - ); -} - -#[test] -fn browser_wire_dispatcher_registers_host_callbacks() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - let mut config = KernelVmConfig::new("vm-tools"); - config.permissions = Permissions::allow_all(); - dispatcher - .sidecar_mut() - .create_vm(config) - .expect("create tools vm"); - let ownership = OwnershipScope::VmOwnership(VmOwnership { - connection_id: String::from("conn"), - session_id: String::from("session"), - vm_id: String::from("vm-tools"), - }); - - let response = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: ownership.clone(), - payload: RequestPayload::RegisterHostCallbacksRequest(test_toolkit_payload( - "browser", - "agentos-browser", - )), - }, - ); - let ResponsePayload::HostCallbacksRegisteredResponse(registered) = response.payload else { - panic!("unexpected register response: {:?}", response.payload); - }; - assert_eq!(registered.registration, "browser"); - assert_eq!(registered.command_count, 2); - - let duplicate = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 2, - ownership, - payload: RequestPayload::RegisterHostCallbacksRequest(test_toolkit_payload( - "browser", - "agentos-browser-2", - )), - }, - ); - let ResponsePayload::RejectedResponse(rejected) = duplicate.payload else { - panic!("unexpected duplicate response: {:?}", duplicate.payload); - }; - assert_eq!(rejected.code, "register_host_callbacks_failed"); - assert!(rejected.message.contains("toolkit already registered")); -} - -#[test] -fn browser_wire_dispatcher_manages_snapshot_layers() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - let mut config = KernelVmConfig::new("vm-layers"); - config.permissions = Permissions::allow_all(); - dispatcher - .sidecar_mut() - .create_vm(config) - .expect("create layer vm"); - let ownership = OwnershipScope::VmOwnership(VmOwnership { - connection_id: String::from("conn"), - session_id: String::from("session"), - vm_id: String::from("vm-layers"), - }); - - let lower_layer = import_snapshot_layer( - &codec, - &mut dispatcher, - ownership.clone(), - 1, - &[ - ("/workspace/lower.txt", "lower"), - ("/workspace/shared.txt", "lower"), - ], - ); - let upper_layer = import_snapshot_layer( - &codec, - &mut dispatcher, - ownership.clone(), - 2, - &[ - ("/workspace/upper.txt", "upper"), - ("/workspace/shared.txt", "upper"), - ], - ); - - let overlay = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 3, - ownership: ownership.clone(), - payload: RequestPayload::CreateOverlayRequest(CreateOverlayRequest { - mode: RootFilesystemMode::Ephemeral, - upper_layer_id: Some(upper_layer), - lower_layer_ids: vec![lower_layer], - }), - }, - ); - let ResponsePayload::OverlayCreatedResponse(overlay) = overlay.payload else { - panic!("unexpected overlay response: {:?}", overlay.payload); - }; - - let exported = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 4, - ownership: ownership.clone(), - payload: RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: overlay.layer_id, - }), - }, - ); - let ResponsePayload::SnapshotExportedResponse(exported) = exported.payload else { - panic!("unexpected export response: {:?}", exported.payload); - }; - assert!(exported - .entries - .iter() - .any(|entry| entry.path == "/workspace/lower.txt" - && entry.content.as_deref() == Some("lower"))); - assert!(exported - .entries - .iter() - .any(|entry| entry.path == "/workspace/upper.txt" - && entry.content.as_deref() == Some("upper"))); - assert!(exported - .entries - .iter() - .any(|entry| entry.path == "/workspace/shared.txt" - && entry.content.as_deref() == Some("upper"))); - - let created = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 5, - ownership: ownership.clone(), - payload: RequestPayload::CreateLayerRequest, - }, - ); - let ResponsePayload::LayerCreatedResponse(created) = created.payload else { - panic!("unexpected create layer response: {:?}", created.payload); - }; - let sealed = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 6, - ownership, - payload: RequestPayload::SealLayerRequest(SealLayerRequest { - layer_id: created.layer_id, - }), - }, - ); - assert!(matches!( - sealed.payload, - ResponsePayload::LayerSealedResponse(_) - )); -} - -#[test] -fn browser_wire_dispatcher_rejects_reverse_host_callback_requests() { - let codec = WireFrameCodec::default(); - for payload in [ - RequestPayload::HostFilesystemCallRequest(HostFilesystemCallRequest { - operation: FilesystemOperation::Read, - path: String::from("/state"), - payload_size_bytes: 0, - }), - RequestPayload::PersistenceLoadRequest(PersistenceLoadRequest { - key: String::from("state"), - }), - RequestPayload::PersistenceFlushRequest(PersistenceFlushRequest { - key: String::from("state"), - payload_size_bytes: 0, - }), - ] { - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - - let response = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: String::from("client"), - }), - payload, - }, - ); - - let ResponsePayload::RejectedResponse(rejected) = response.payload else { - panic!("unexpected rejection response: {:?}", response.payload); - }; - assert_eq!(rejected.code, "unsupported_direction"); - } -} - -#[test] -fn browser_wire_dispatcher_rejects_vm_fetch_when_guest_listener_is_missing() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - let mut config = KernelVmConfig::new("vm"); - config.permissions = Permissions::allow_all(); - dispatcher - .sidecar_mut() - .create_vm(config) - .expect("create vm for vm.fetch"); - let response = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::VmOwnership(VmOwnership { - connection_id: String::from("conn"), - session_id: String::from("session"), - vm_id: String::from("vm"), - }), - payload: RequestPayload::VmFetchRequest(VmFetchRequest { - port: 3000, - method: String::from("GET"), - path: String::from("/"), - headers_json: String::from("{}"), - body: None, - }), - }, - ); - - let ResponsePayload::RejectedResponse(rejected) = response.payload else { - panic!("unexpected vm.fetch response: {:?}", response.payload); - }; - assert_eq!(rejected.code, "vm_fetch_failed"); - assert!( - rejected - .message - .contains("could not find a guest HTTP listener on port 3000"), - "unexpected vm.fetch rejection: {}", - rejected.message - ); -} - -#[test] -fn browser_wire_dispatcher_rejects_vm_fetch_with_invalid_headers_json() { - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - let mut config = KernelVmConfig::new("vm"); - config.permissions = Permissions::allow_all(); - dispatcher - .sidecar_mut() - .create_vm(config) - .expect("create vm for vm.fetch"); - let response = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::VmOwnership(VmOwnership { - connection_id: String::from("conn"), - session_id: String::from("session"), - vm_id: String::from("vm"), - }), - payload: RequestPayload::VmFetchRequest(VmFetchRequest { - port: 3000, - method: String::from("GET"), - path: String::from("/"), - headers_json: String::from("{not-json"), - body: None, - }), - }, - ); - - let ResponsePayload::RejectedResponse(rejected) = response.payload else { - panic!("unexpected vm.fetch response: {:?}", response.payload); - }; - assert_eq!(rejected.code, "invalid_request"); - assert!( - rejected.message.contains("headers_json must be valid JSON"), - "unexpected vm.fetch rejection: {}", - rejected.message - ); -} - -#[test] -fn browser_wire_dispatcher_vm_fetch_enters_kernel_loopback_when_listener_exists() { - std::env::set_var("SECURE_EXEC_TEST_BROWSER_VM_FETCH_TIMEOUT_MS", "5"); - let codec = WireFrameCodec::default(); - let mut dispatcher = BrowserWireDispatcher::new(RecordingBridge::default()); - let mut config = KernelVmConfig::new("vm"); - config.permissions = Permissions::allow_all(); - dispatcher - .sidecar_mut() - .create_vm(config) - .expect("create vm for vm.fetch"); - let context = dispatcher - .sidecar_mut() - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm"), - bootstrap_module: None, - }) - .expect("create context"); - let started = dispatcher - .sidecar_mut() - .start_execution(StartExecutionRequest { - vm_id: String::from("vm"), - context_id: context.context_id, - argv: Vec::new(), - env: BTreeMap::new(), - cwd: String::from("/"), - }) - .expect("start execution"); - dispatcher - .sidecar_mut() - .create_kernel_tcp_listener_for_execution( - "vm", - &started.execution_id, - "127.0.0.1", - 3000, - 16, - ) - .expect("create listener"); - - let response = dispatch( - &codec, - &mut dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: OwnershipScope::VmOwnership(VmOwnership { - connection_id: String::from("conn"), - session_id: String::from("session"), - vm_id: String::from("vm"), - }), - payload: RequestPayload::VmFetchRequest(VmFetchRequest { - port: 3000, - method: String::from("GET"), - path: String::from("/health"), - headers_json: String::from("{}"), - body: None, - }), - }, - ); - std::env::remove_var("SECURE_EXEC_TEST_BROWSER_VM_FETCH_TIMEOUT_MS"); - - let ResponsePayload::RejectedResponse(rejected) = response.payload else { - panic!("unexpected vm.fetch response: {:?}", response.payload); - }; - assert_eq!(rejected.code, "vm_fetch_failed"); - assert!( - rejected - .message - .contains("timed out waiting for kernel TCP HTTP response"), - "unexpected vm.fetch rejection: {}", - rejected.message - ); - assert!( - !rejected.message.contains("not implemented"), - "vm.fetch should no longer stop at the unsupported platform branch" - ); -} - -fn test_toolkit_payload(name: &str, alias: &str) -> RegisterHostCallbacksRequest { - RegisterHostCallbacksRequest { - name: name.to_string(), - description: format!("{name} automation"), - command_aliases: vec![alias.to_string()], - registry_command_aliases: vec![String::from("agentos")], - callbacks: std::collections::HashMap::from([( - String::from("screenshot"), - RegisteredHostCallbackDefinition { - description: String::from("Take a screenshot"), - input_schema: String::from( - r#"{"type":"object","properties":{},"additionalProperties":false}"#, - ), - timeout_ms: None, - examples: Vec::new(), - }, - )]), - } -} - -fn import_snapshot_layer( - codec: &WireFrameCodec, - dispatcher: &mut BrowserWireDispatcher, - ownership: OwnershipScope, - request_id: i64, - files: &[(&str, &str)], -) -> String { - let response = dispatch( - codec, - dispatcher, - RequestFrame { - schema: protocol_schema(), - request_id, - ownership, - payload: RequestPayload::ImportSnapshotRequest(ImportSnapshotRequest { - entries: files - .iter() - .map(|(path, content)| RootFilesystemEntry { - path: path.to_string(), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(content.to_string()), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }) - .collect(), - }), - }, - ); - let ResponsePayload::SnapshotImportedResponse(imported) = response.payload else { - panic!("unexpected import response: {:?}", response.payload); - }; - imported.layer_id -} - -fn dispatch( - codec: &WireFrameCodec, - dispatcher: &mut BrowserWireDispatcher, - request: RequestFrame, -) -> secure_exec_sidecar_protocol::wire::ResponseFrame { - let request = codec - .encode_message(&ProtocolFrame::RequestFrame(request)) - .expect("encode request"); - let response = dispatcher - .handle_request_bytes(&request) - .expect("dispatch request"); - let ProtocolFrame::ResponseFrame(response) = - codec.decode_message(&response).expect("decode response") - else { - panic!("expected response frame"); - }; - response -} diff --git a/crates/sidecar-core/Cargo.toml b/crates/sidecar-core/Cargo.toml index 03a5c99ab..c7bdc7d3e 100644 --- a/crates/sidecar-core/Cargo.toml +++ b/crates/sidecar-core/Cargo.toml @@ -4,13 +4,10 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Shared Secure Exec sidecar logic for native and browser shells" +description = "secure-exec-sidecar-core compatibility shim for agentos-native-sidecar-core" + +[lib] +name = "secure_exec_sidecar_core" [dependencies] -secure-exec-bridge = { workspace = true } -secure-exec-kernel = { workspace = true } -secure-exec-sidecar-protocol = { workspace = true } -secure-exec-vm-config = { workspace = true } -base64 = "0.22" -serde_json = "1.0" -vfs = { workspace = true } +agentos_native_sidecar_core = { package = "agentos-native-sidecar-core", path = "../../../agentos/crates/native-sidecar-core", version = "0.0.1" } diff --git a/crates/sidecar-core/src/bridge_bytes.rs b/crates/sidecar-core/src/bridge_bytes.rs deleted file mode 100644 index dd9a6a6cc..000000000 --- a/crates/sidecar-core/src/bridge_bytes.rs +++ /dev/null @@ -1,85 +0,0 @@ -use base64::Engine; -use serde_json::{json, Value}; - -pub fn encoded_bytes_value(bytes: &[u8]) -> Value { - json!({ - "__agentOSType": "bytes", - "base64": base64::engine::general_purpose::STANDARD.encode(bytes), - }) -} - -pub fn decode_encoded_bytes_value(value: &Value) -> Result, String> { - let Some(base64_value) = value - .get("__agentOSType") - .and_then(Value::as_str) - .filter(|kind| *kind == "bytes") - .and_then(|_| value.get("base64")) - .and_then(Value::as_str) - else { - return Err(String::from("must be a string or encoded bytes payload")); - }; - - decode_base64(base64_value) -} - -pub fn bridge_buffer_value(bytes: &[u8]) -> Value { - json!({ - "__type": "buffer", - "value": base64::engine::general_purpose::STANDARD.encode(bytes), - }) -} - -pub fn decode_bridge_buffer_value(value: &Value) -> Result, String> { - let base64_value = value - .as_object() - .filter(|object| object.get("__type").and_then(Value::as_str) == Some("buffer")) - .and_then(|object| object.get("value")) - .and_then(Value::as_str) - .ok_or_else(|| String::from("must be a serialized bridge buffer"))?; - - decode_base64(base64_value) -} - -pub fn decode_base64(value: &str) -> Result, String> { - base64::engine::general_purpose::STANDARD - .decode(value) - .map_err(|error| format!("contains invalid base64: {error}")) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn round_trips_encoded_bytes_payload() { - let value = encoded_bytes_value(b"hello"); - - assert_eq!(decode_encoded_bytes_value(&value), Ok(b"hello".to_vec())); - } - - #[test] - fn round_trips_bridge_buffer_payload() { - let value = bridge_buffer_value(b"secret"); - - assert_eq!(decode_bridge_buffer_value(&value), Ok(b"secret".to_vec())); - } - - #[test] - fn rejects_wrong_payload_shapes() { - assert_eq!( - decode_encoded_bytes_value(&json!({ "__agentOSType": "text", "base64": "aGk=" })), - Err(String::from("must be a string or encoded bytes payload")) - ); - assert_eq!( - decode_bridge_buffer_value(&json!({ "__type": "bytes", "value": "aGk=" })), - Err(String::from("must be a serialized bridge buffer")) - ); - } - - #[test] - fn labels_invalid_base64() { - assert!(decode_base64("not base64!") - .expect_err("invalid base64 should fail") - .starts_with("contains invalid base64:")); - } -} diff --git a/crates/sidecar-core/src/diagnostics.rs b/crates/sidecar-core/src/diagnostics.rs deleted file mode 100644 index 7416015b0..000000000 --- a/crates/sidecar-core/src/diagnostics.rs +++ /dev/null @@ -1,172 +0,0 @@ -use secure_exec_kernel::process_table::{ProcessInfo, ProcessStatus}; -use secure_exec_sidecar_protocol::protocol::{ProcessSnapshotEntry, ProcessSnapshotStatus}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SharedProcessSnapshotStatus { - Running, - Stopped, - Exited, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SharedProcessSnapshotEntry { - pub process_id: String, - pub pid: u32, - pub ppid: u32, - pub pgid: u32, - pub sid: u32, - pub driver: String, - pub command: String, - pub args: Vec, - pub cwd: String, - pub status: SharedProcessSnapshotStatus, - pub exit_code: Option, -} - -pub fn process_status_from_kernel(status: ProcessStatus) -> SharedProcessSnapshotStatus { - match status { - ProcessStatus::Running => SharedProcessSnapshotStatus::Running, - ProcessStatus::Stopped => SharedProcessSnapshotStatus::Stopped, - ProcessStatus::Exited => SharedProcessSnapshotStatus::Exited, - } -} - -pub fn process_snapshot_entry_from_kernel( - process_id: &str, - info: &ProcessInfo, - cwd: impl Into, - exit_code: Option, -) -> SharedProcessSnapshotEntry { - SharedProcessSnapshotEntry { - process_id: process_id.to_owned(), - pid: info.pid, - ppid: info.ppid, - pgid: info.pgid, - sid: info.sid, - driver: info.driver.clone(), - command: info.command.clone(), - args: Vec::new(), - cwd: cwd.into(), - status: if exit_code.is_some() { - SharedProcessSnapshotStatus::Exited - } else { - process_status_from_kernel(info.status) - }, - exit_code: exit_code.or(info.exit_code), - } -} - -pub fn protocol_process_snapshot_entry(entry: SharedProcessSnapshotEntry) -> ProcessSnapshotEntry { - ProcessSnapshotEntry { - process_id: entry.process_id, - pid: entry.pid, - ppid: entry.ppid, - pgid: entry.pgid, - sid: entry.sid, - driver: entry.driver, - command: entry.command, - args: entry.args, - cwd: entry.cwd, - status: match entry.status { - SharedProcessSnapshotStatus::Running => ProcessSnapshotStatus::Running, - SharedProcessSnapshotStatus::Stopped => ProcessSnapshotStatus::Stopped, - SharedProcessSnapshotStatus::Exited => ProcessSnapshotStatus::Exited, - }, - exit_code: entry.exit_code, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use secure_exec_kernel::user::ProcessIdentity; - - fn process_info(status: ProcessStatus, exit_code: Option) -> ProcessInfo { - ProcessInfo { - pid: 42, - ppid: 1, - pgid: 42, - sid: 42, - driver: "javascript".to_owned(), - command: "node".to_owned(), - status, - exit_code, - identity: ProcessIdentity::default(), - } - } - - #[test] - fn maps_kernel_process_statuses() { - assert_eq!( - process_status_from_kernel(ProcessStatus::Running), - SharedProcessSnapshotStatus::Running - ); - assert_eq!( - process_status_from_kernel(ProcessStatus::Stopped), - SharedProcessSnapshotStatus::Stopped - ); - assert_eq!( - process_status_from_kernel(ProcessStatus::Exited), - SharedProcessSnapshotStatus::Exited - ); - } - - #[test] - fn builds_process_snapshot_from_kernel_info() { - let entry = process_snapshot_entry_from_kernel( - "exec-1", - &process_info(ProcessStatus::Running, None), - "/workspace", - None, - ); - - assert_eq!(entry.process_id, "exec-1"); - assert_eq!(entry.pid, 42); - assert_eq!(entry.ppid, 1); - assert_eq!(entry.pgid, 42); - assert_eq!(entry.sid, 42); - assert_eq!(entry.driver, "javascript"); - assert_eq!(entry.command, "node"); - assert_eq!(entry.args, Vec::::new()); - assert_eq!(entry.cwd, "/workspace"); - assert_eq!(entry.status, SharedProcessSnapshotStatus::Running); - assert_eq!(entry.exit_code, None); - } - - #[test] - fn explicit_exit_code_marks_snapshot_exited() { - let entry = process_snapshot_entry_from_kernel( - "exec-1", - &process_info(ProcessStatus::Running, Some(9)), - "/workspace", - Some(7), - ); - - assert_eq!(entry.status, SharedProcessSnapshotStatus::Exited); - assert_eq!(entry.exit_code, Some(7)); - } - - #[test] - fn maps_shared_process_snapshot_to_protocol_entry() { - let entry = protocol_process_snapshot_entry(SharedProcessSnapshotEntry { - process_id: String::from("proc-1"), - pid: 42, - ppid: 1, - pgid: 42, - sid: 42, - driver: String::from("javascript"), - command: String::from("node"), - args: vec![String::from("app.js")], - cwd: String::from("/workspace"), - status: SharedProcessSnapshotStatus::Stopped, - exit_code: None, - }); - - assert_eq!(entry.process_id, "proc-1"); - assert_eq!(entry.pid, 42); - assert_eq!(entry.args, vec![String::from("app.js")]); - assert_eq!(entry.cwd, "/workspace"); - assert_eq!(entry.status, ProcessSnapshotStatus::Stopped); - assert_eq!(entry.exit_code, None); - } -} diff --git a/crates/sidecar-core/src/frames.rs b/crates/sidecar-core/src/frames.rs deleted file mode 100644 index 66b5d55f1..000000000 --- a/crates/sidecar-core/src/frames.rs +++ /dev/null @@ -1,693 +0,0 @@ -use secure_exec_sidecar_protocol::protocol::{ - AgentosProjectedAgent, AuthenticateRequest, AuthenticatedResponse, BoundUdpSnapshotResponse, - EventFrame, EventPayload, LayerCreatedResponse, LayerSealedResponse, ListenerSnapshotResponse, - OverlayCreatedResponse, OwnershipScope, PackageCommands, PackageLinkedResponse, - ProcessExitedEvent, ProcessKilledResponse, ProcessOutputEvent, ProcessSnapshotEntry, - ProcessSnapshotResponse, ProcessStartedResponse, ProjectedCommand, ProtocolSchema, - ProvidedCommandsResponse, RejectedResponse, RequestFrame, RequestId, ResponseFrame, - ResponsePayload, RootFilesystemBootstrappedResponse, RootFilesystemEntry, - RootFilesystemSnapshotResponse, SessionOpenedResponse, SignalHandlerRegistration, - SignalStateResponse, SnapshotExportedResponse, SnapshotImportedResponse, SocketStateEntry, - StdinClosedResponse, StdinWrittenResponse, StreamChannel, StructuredEvent, - VmConfiguredResponse, VmCreatedResponse, VmDisposedResponse, VmLifecycleEvent, - VmLifecycleState, ZombieTimerCountResponse, PROTOCOL_VERSION, -}; -use std::collections::HashMap; - -pub const UNSUPPORTED_GUEST_KERNEL_CALL_EVENT: &str = "guest.kernel_call.unsupported"; - -#[derive(Debug, Clone)] -pub struct DispatchResult { - pub response: ResponseFrame, - pub events: Vec, -} - -pub fn response_with_ownership( - request_id: RequestId, - ownership: OwnershipScope, - payload: ResponsePayload, -) -> ResponseFrame { - ResponseFrame { - schema: ProtocolSchema::current(), - request_id, - ownership, - payload, - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum AuthenticateVersionError { - ProtocolVersionMismatch(String), - BridgeVersionMismatch(String), -} - -impl AuthenticateVersionError { - pub fn code(&self) -> &'static str { - match self { - Self::ProtocolVersionMismatch(_) => "protocol_version_mismatch", - Self::BridgeVersionMismatch(_) => "bridge_version_mismatch", - } - } - - pub fn message(&self) -> &str { - match self { - Self::ProtocolVersionMismatch(message) | Self::BridgeVersionMismatch(message) => { - message - } - } - } -} - -pub fn validate_authenticate_versions( - payload: &AuthenticateRequest, -) -> Result<(), AuthenticateVersionError> { - if payload.protocol_version != PROTOCOL_VERSION { - return Err(AuthenticateVersionError::ProtocolVersionMismatch(format!( - "sidecar protocol version mismatch: expected {}, got {}", - PROTOCOL_VERSION, payload.protocol_version - ))); - } - - let expected_bridge_version = secure_exec_bridge::bridge_contract().version; - if payload.bridge_version != expected_bridge_version { - return Err(AuthenticateVersionError::BridgeVersionMismatch(format!( - "bridge contract version mismatch: expected {expected_bridge_version}, got {}", - payload.bridge_version - ))); - } - - Ok(()) -} - -pub fn authenticated_response( - request_id: RequestId, - sidecar_id: impl Into, - connection_id: String, - max_frame_bytes: u32, -) -> ResponseFrame { - response_with_ownership( - request_id, - OwnershipScope::connection(&connection_id), - ResponsePayload::Authenticated(AuthenticatedResponse { - sidecar_id: sidecar_id.into(), - connection_id, - max_frame_bytes, - }), - ) -} - -pub fn session_opened_response( - request_id: RequestId, - owner_connection_id: String, - session_id: String, -) -> ResponseFrame { - response_with_ownership( - request_id, - OwnershipScope::session(&owner_connection_id, &session_id), - ResponsePayload::SessionOpened(SessionOpenedResponse { - session_id, - owner_connection_id, - }), - ) -} - -pub fn respond(request: &RequestFrame, payload: ResponsePayload) -> ResponseFrame { - response_with_ownership(request.request_id, request.ownership.clone(), payload) -} - -pub fn reject(request: &RequestFrame, code: &str, message: &str) -> ResponseFrame { - respond( - request, - ResponsePayload::Rejected(RejectedResponse { - code: code.to_owned(), - message: message.to_owned(), - }), - ) -} - -pub fn vm_created_response(request: &RequestFrame, vm_id: String) -> ResponseFrame { - respond( - request, - ResponsePayload::VmCreated(VmCreatedResponse { vm_id }), - ) -} - -pub fn vm_disposed_response(request: &RequestFrame, vm_id: String) -> ResponseFrame { - respond( - request, - ResponsePayload::VmDisposed(VmDisposedResponse { vm_id }), - ) -} - -pub fn root_filesystem_bootstrapped_response( - request: &RequestFrame, - entry_count: u32, -) -> ResponseFrame { - respond( - request, - ResponsePayload::RootFilesystemBootstrapped(RootFilesystemBootstrappedResponse { - entry_count, - }), - ) -} - -pub fn vm_configured_response( - request: &RequestFrame, - applied_mounts: u32, - applied_software: u32, - projected_commands: Vec, - agents: Vec, -) -> ResponseFrame { - respond( - request, - ResponsePayload::VmConfigured(VmConfiguredResponse { - applied_mounts, - applied_software, - projected_commands, - agents, - }), - ) -} - -pub fn package_linked_response( - request: &RequestFrame, - projected_commands: Vec, - agents: Vec, -) -> ResponseFrame { - respond( - request, - ResponsePayload::PackageLinked(PackageLinkedResponse { - projected_commands, - agents, - }), - ) -} - -pub fn provided_commands_response( - request: &RequestFrame, - packages: Vec, -) -> ResponseFrame { - respond( - request, - ResponsePayload::ProvidedCommands(ProvidedCommandsResponse { packages }), - ) -} - -pub fn layer_created_response(request: &RequestFrame, layer_id: String) -> ResponseFrame { - respond( - request, - ResponsePayload::LayerCreated(LayerCreatedResponse { layer_id }), - ) -} - -pub fn layer_sealed_response(request: &RequestFrame, layer_id: String) -> ResponseFrame { - respond( - request, - ResponsePayload::LayerSealed(LayerSealedResponse { layer_id }), - ) -} - -pub fn snapshot_imported_response(request: &RequestFrame, layer_id: String) -> ResponseFrame { - respond( - request, - ResponsePayload::SnapshotImported(SnapshotImportedResponse { layer_id }), - ) -} - -pub fn snapshot_exported_response( - request: &RequestFrame, - layer_id: String, - entries: Vec, -) -> ResponseFrame { - respond( - request, - ResponsePayload::SnapshotExported(SnapshotExportedResponse { layer_id, entries }), - ) -} - -pub fn overlay_created_response(request: &RequestFrame, layer_id: String) -> ResponseFrame { - respond( - request, - ResponsePayload::OverlayCreated(OverlayCreatedResponse { layer_id }), - ) -} - -pub fn root_filesystem_snapshot_response( - request: &RequestFrame, - entries: Vec, -) -> ResponseFrame { - respond( - request, - ResponsePayload::RootFilesystemSnapshot(RootFilesystemSnapshotResponse { entries }), - ) -} - -pub fn process_started_response( - request: &RequestFrame, - process_id: String, - pid: Option, -) -> ResponseFrame { - respond( - request, - ResponsePayload::ProcessStarted(ProcessStartedResponse { process_id, pid }), - ) -} - -pub fn stdin_written_response( - request: &RequestFrame, - process_id: String, - accepted_bytes: u64, -) -> ResponseFrame { - respond( - request, - ResponsePayload::StdinWritten(StdinWrittenResponse { - process_id, - accepted_bytes, - }), - ) -} - -pub fn stdin_closed_response(request: &RequestFrame, process_id: String) -> ResponseFrame { - respond( - request, - ResponsePayload::StdinClosed(StdinClosedResponse { process_id }), - ) -} - -pub fn process_killed_response(request: &RequestFrame, process_id: String) -> ResponseFrame { - respond( - request, - ResponsePayload::ProcessKilled(ProcessKilledResponse { process_id }), - ) -} - -pub fn process_snapshot_response( - request: &RequestFrame, - processes: Vec, -) -> ResponseFrame { - respond( - request, - ResponsePayload::ProcessSnapshot(ProcessSnapshotResponse { processes }), - ) -} - -pub fn listener_snapshot_response( - request: &RequestFrame, - listener: Option, -) -> ResponseFrame { - respond( - request, - ResponsePayload::ListenerSnapshot(ListenerSnapshotResponse { listener }), - ) -} - -pub fn bound_udp_snapshot_response( - request: &RequestFrame, - socket: Option, -) -> ResponseFrame { - respond( - request, - ResponsePayload::BoundUdpSnapshot(BoundUdpSnapshotResponse { socket }), - ) -} - -pub fn signal_state_response( - request: &RequestFrame, - process_id: String, - handlers: impl IntoIterator, -) -> ResponseFrame { - respond( - request, - ResponsePayload::SignalState(SignalStateResponse { - process_id, - handlers: handlers.into_iter().collect(), - }), - ) -} - -pub fn zombie_timer_count_response(request: &RequestFrame, count: u64) -> ResponseFrame { - respond( - request, - ResponsePayload::ZombieTimerCount(ZombieTimerCountResponse { count }), - ) -} - -pub fn event(ownership: OwnershipScope, payload: EventPayload) -> EventFrame { - EventFrame::new(ownership, payload) -} - -pub fn vm_lifecycle_event( - connection_id: &str, - session_id: &str, - vm_id: &str, - state: VmLifecycleState, -) -> EventFrame { - event( - OwnershipScope::vm(connection_id, session_id, vm_id), - EventPayload::VmLifecycle(VmLifecycleEvent { state }), - ) -} - -pub fn process_output_event( - ownership: OwnershipScope, - process_id: &str, - channel: StreamChannel, - chunk: Vec, -) -> EventFrame { - event( - ownership, - EventPayload::ProcessOutput(ProcessOutputEvent { - process_id: process_id.to_owned(), - channel, - chunk, - }), - ) -} - -pub fn process_exited_event( - ownership: OwnershipScope, - process_id: &str, - exit_code: i32, -) -> EventFrame { - event( - ownership, - EventPayload::ProcessExited(ProcessExitedEvent { - process_id: process_id.to_owned(), - exit_code, - }), - ) -} - -pub fn unsupported_guest_kernel_call_event( - ownership: OwnershipScope, - process_id: &str, - execution_id: &str, - operation: &str, - payload_size_bytes: usize, -) -> EventFrame { - event( - ownership, - EventPayload::Structured(StructuredEvent { - name: String::from(UNSUPPORTED_GUEST_KERNEL_CALL_EVENT), - detail: unsupported_guest_kernel_call_detail( - Some(process_id), - execution_id, - operation, - payload_size_bytes, - ), - }), - ) -} - -pub fn unsupported_guest_kernel_call_detail( - process_id: Option<&str>, - execution_id: &str, - operation: &str, - payload_size_bytes: usize, -) -> HashMap { - let mut detail = HashMap::from([ - (String::from("execution_id"), execution_id.to_owned()), - (String::from("operation"), operation.to_owned()), - ( - String::from("payload_size_bytes"), - payload_size_bytes.to_string(), - ), - ]); - if let Some(process_id) = process_id { - detail.insert(String::from("process_id"), process_id.to_owned()); - } - detail -} - -#[cfg(test)] -mod tests { - use super::*; - use secure_exec_sidecar_protocol::protocol::RequestPayload; - - fn authenticate_request() -> AuthenticateRequest { - AuthenticateRequest { - client_name: String::from("test"), - auth_token: String::from("token"), - protocol_version: secure_exec_sidecar_protocol::protocol::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - } - } - - #[test] - fn reject_preserves_request_identity_and_ownership() { - let request = RequestFrame::new( - 42, - OwnershipScope::connection("conn-1"), - RequestPayload::Authenticate(authenticate_request()), - ); - - let response = reject(&request, "bad_request", "nope"); - - assert_eq!(response.request_id, request.request_id); - assert_eq!(response.ownership, request.ownership); - match response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "bad_request"); - assert_eq!(rejected.message, "nope"); - } - other => panic!("unexpected response payload: {other:?}"), - } - } - - #[test] - fn validates_authenticate_versions() { - validate_authenticate_versions(&authenticate_request()).expect("current versions"); - - let mut stale_protocol = authenticate_request(); - stale_protocol.protocol_version = stale_protocol.protocol_version.saturating_sub(1); - let error = validate_authenticate_versions(&stale_protocol).expect_err("protocol mismatch"); - assert_eq!(error.code(), "protocol_version_mismatch"); - assert!(error - .message() - .contains("sidecar protocol version mismatch")); - - let mut stale_bridge = authenticate_request(); - stale_bridge.bridge_version = stale_bridge.bridge_version.saturating_sub(1); - let error = validate_authenticate_versions(&stale_bridge).expect_err("bridge mismatch"); - assert_eq!(error.code(), "bridge_version_mismatch"); - assert!(error.message().contains("bridge contract version mismatch")); - } - - #[test] - fn authenticated_response_sets_connection_ownership() { - let response = - authenticated_response(7, "secure-exec-test", String::from("conn-test"), 1024); - - assert_eq!(response.request_id, 7); - assert_eq!(response.ownership, OwnershipScope::connection("conn-test")); - match response.payload { - ResponsePayload::Authenticated(authenticated) => { - assert_eq!(authenticated.sidecar_id, "secure-exec-test"); - assert_eq!(authenticated.connection_id, "conn-test"); - assert_eq!(authenticated.max_frame_bytes, 1024); - } - other => panic!("unexpected response payload: {other:?}"), - } - } - - #[test] - fn session_opened_response_sets_session_ownership() { - let response = - session_opened_response(8, String::from("conn-1"), String::from("session-1")); - - assert_eq!(response.request_id, 8); - assert_eq!( - response.ownership, - OwnershipScope::session("conn-1", "session-1") - ); - match response.payload { - ResponsePayload::SessionOpened(opened) => { - assert_eq!(opened.owner_connection_id, "conn-1"); - assert_eq!(opened.session_id, "session-1"); - } - other => panic!("unexpected response payload: {other:?}"), - } - } - - #[test] - fn lifecycle_response_helpers_preserve_request_ownership() { - let request = RequestFrame::new( - 43, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - RequestPayload::Authenticate(authenticate_request()), - ); - - let created = vm_created_response(&request, String::from("vm-1")); - assert_eq!(created.request_id, request.request_id); - assert_eq!(created.ownership, request.ownership); - match created.payload { - ResponsePayload::VmCreated(created) => assert_eq!(created.vm_id, "vm-1"), - other => panic!("unexpected response payload: {other:?}"), - } - - let bootstrapped = root_filesystem_bootstrapped_response(&request, 3); - assert_eq!(bootstrapped.request_id, request.request_id); - assert_eq!(bootstrapped.ownership, request.ownership); - match bootstrapped.payload { - ResponsePayload::RootFilesystemBootstrapped(bootstrapped) => { - assert_eq!(bootstrapped.entry_count, 3); - } - other => panic!("unexpected response payload: {other:?}"), - } - - let disposed = vm_disposed_response(&request, String::from("vm-1")); - assert_eq!(disposed.request_id, request.request_id); - assert_eq!(disposed.ownership, request.ownership); - match disposed.payload { - ResponsePayload::VmDisposed(disposed) => assert_eq!(disposed.vm_id, "vm-1"), - other => panic!("unexpected response payload: {other:?}"), - } - } - - #[test] - fn process_started_response_preserves_pid() { - let request = RequestFrame::new( - 44, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - RequestPayload::Authenticate(authenticate_request()), - ); - - let started = process_started_response(&request, String::from("proc-1"), Some(123)); - assert_eq!(started.request_id, request.request_id); - assert_eq!(started.ownership, request.ownership); - match started.payload { - ResponsePayload::ProcessStarted(started) => { - assert_eq!(started.process_id, "proc-1"); - assert_eq!(started.pid, Some(123)); - } - other => panic!("unexpected response payload: {other:?}"), - } - - let started_without_pid = process_started_response(&request, String::from("proc-2"), None); - match started_without_pid.payload { - ResponsePayload::ProcessStarted(started) => { - assert_eq!(started.process_id, "proc-2"); - assert_eq!(started.pid, None); - } - other => panic!("unexpected response payload: {other:?}"), - } - } - - #[test] - fn shared_response_helpers_preserve_payloads() { - let request = RequestFrame::new( - 45, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - RequestPayload::Authenticate(authenticate_request()), - ); - - match vm_configured_response(&request, 2, 3, Vec::new()).payload { - ResponsePayload::VmConfigured(configured) => { - assert_eq!(configured.applied_mounts, 2); - assert_eq!(configured.applied_software, 3); - assert!(configured.projected_commands.is_empty()); - } - other => panic!("unexpected response payload: {other:?}"), - } - - match snapshot_exported_response(&request, String::from("layer-1"), Vec::new()).payload { - ResponsePayload::SnapshotExported(exported) => { - assert_eq!(exported.layer_id, "layer-1"); - assert!(exported.entries.is_empty()); - } - other => panic!("unexpected response payload: {other:?}"), - } - - match stdin_written_response(&request, String::from("proc-1"), 9).payload { - ResponsePayload::StdinWritten(written) => { - assert_eq!(written.process_id, "proc-1"); - assert_eq!(written.accepted_bytes, 9); - } - other => panic!("unexpected response payload: {other:?}"), - } - - match process_killed_response(&request, String::from("proc-1")).payload { - ResponsePayload::ProcessKilled(killed) => { - assert_eq!(killed.process_id, "proc-1"); - } - other => panic!("unexpected response payload: {other:?}"), - } - - match signal_state_response(&request, String::from("proc-1"), []).payload { - ResponsePayload::SignalState(state) => { - assert_eq!(state.process_id, "proc-1"); - assert!(state.handlers.is_empty()); - } - other => panic!("unexpected response payload: {other:?}"), - } - - match zombie_timer_count_response(&request, 4).payload { - ResponsePayload::ZombieTimerCount(count) => assert_eq!(count.count, 4), - other => panic!("unexpected response payload: {other:?}"), - } - } - - #[test] - fn process_event_helpers_build_vm_owned_events() { - let ownership = OwnershipScope::vm("conn-1", "session-1", "vm-1"); - - let output = process_output_event( - ownership.clone(), - "proc-1", - StreamChannel::Stdout, - b"hello".to_vec(), - ); - assert_eq!(output.ownership, ownership); - match output.payload { - EventPayload::ProcessOutput(event) => { - assert_eq!(event.process_id, "proc-1"); - assert_eq!(event.channel, StreamChannel::Stdout); - assert_eq!(event.chunk, b"hello"); - } - other => panic!("unexpected event payload: {other:?}"), - } - - let exited = process_exited_event(output.ownership, "proc-1", 7); - match exited.payload { - EventPayload::ProcessExited(event) => { - assert_eq!(event.process_id, "proc-1"); - assert_eq!(event.exit_code, 7); - } - other => panic!("unexpected event payload: {other:?}"), - } - } - - #[test] - fn unsupported_guest_kernel_call_event_preserves_execution_identity() { - let ownership = OwnershipScope::vm("conn-1", "session-1", "vm-1"); - let event = unsupported_guest_kernel_call_event( - ownership.clone(), - "proc-1", - "exec-1", - "fs.read", - 17, - ); - - assert_eq!(event.ownership, ownership); - match event.payload { - EventPayload::Structured(event) => { - assert_eq!(event.name, "guest.kernel_call.unsupported"); - assert_eq!(event.detail["process_id"], "proc-1"); - assert_eq!(event.detail["execution_id"], "exec-1"); - assert_eq!(event.detail["operation"], "fs.read"); - assert_eq!(event.detail["payload_size_bytes"], "17"); - } - other => panic!("unexpected event payload: {other:?}"), - } - } - - #[test] - fn unsupported_guest_kernel_call_detail_can_omit_process_identity() { - let detail = unsupported_guest_kernel_call_detail(None, "exec-1", "fs.read", 17); - - assert_eq!(detail["execution_id"], "exec-1"); - assert_eq!(detail["operation"], "fs.read"); - assert_eq!(detail["payload_size_bytes"], "17"); - assert!(!detail.contains_key("process_id")); - } -} diff --git a/crates/sidecar-core/src/guest_fs.rs b/crates/sidecar-core/src/guest_fs.rs deleted file mode 100644 index 2e2603658..000000000 --- a/crates/sidecar-core/src/guest_fs.rs +++ /dev/null @@ -1,556 +0,0 @@ -use crate::SidecarCoreError; -use base64::Engine; -use secure_exec_kernel::kernel::KernelVm; -use secure_exec_kernel::vfs::{VirtualFileSystem, VirtualStat}; -use secure_exec_sidecar_protocol::protocol::{ - GuestDirEntry, GuestFilesystemCallRequest, GuestFilesystemOperation, - GuestFilesystemResultResponse, GuestFilesystemStat, RootFilesystemEntryEncoding, -}; - -pub fn handle_guest_filesystem_call( - kernel: &mut KernelVm, - payload: GuestFilesystemCallRequest, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let response = match payload.operation { - GuestFilesystemOperation::ReadFile => { - let bytes = kernel.read_file(&payload.path).map_err(kernel_error)?; - let (content, encoding) = encode_guest_filesystem_content(bytes); - GuestFilesystemResultResponse { - operation: payload.operation, - path: payload.path, - content: Some(content), - encoding: Some(encoding), - entries: None, - stat: None, - exists: None, - target: None, - } - } - GuestFilesystemOperation::Pread => { - let offset = payload - .offset - .ok_or_else(|| SidecarCoreError::new("guest filesystem pread requires offset"))?; - let len = payload - .len - .ok_or_else(|| SidecarCoreError::new("guest filesystem pread requires len"))?; - let length = usize::try_from(len).map_err(|_| { - SidecarCoreError::new("guest filesystem pread len must fit within usize") - })?; - let bytes = kernel - .pread_file(&payload.path, offset, length) - .map_err(kernel_error)?; - let (content, encoding) = encode_guest_filesystem_content(bytes); - GuestFilesystemResultResponse { - operation: payload.operation, - path: payload.path, - content: Some(content), - encoding: Some(encoding), - entries: None, - stat: None, - exists: None, - target: None, - } - } - GuestFilesystemOperation::WriteFile => { - let bytes = decode_guest_filesystem_content( - &payload.path, - payload.content.as_deref(), - payload.encoding, - )?; - kernel - .write_file(&payload.path, bytes) - .map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::Pwrite => { - let offset = payload - .offset - .ok_or_else(|| SidecarCoreError::new("guest filesystem pwrite requires offset"))?; - let bytes = decode_guest_filesystem_content( - &payload.path, - payload.content.as_deref(), - payload.encoding, - )?; - kernel - .pwrite_file(&payload.path, offset, bytes) - .map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::CreateDir => { - kernel.create_dir(&payload.path).map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::Mkdir => { - kernel - .mkdir(&payload.path, payload.recursive) - .map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::Exists => GuestFilesystemResultResponse { - operation: payload.operation, - path: payload.path.clone(), - content: None, - encoding: None, - entries: None, - stat: None, - exists: Some(kernel.exists(&payload.path).map_err(kernel_error)?), - target: None, - }, - GuestFilesystemOperation::Stat => GuestFilesystemResultResponse { - operation: payload.operation, - path: payload.path.clone(), - content: None, - encoding: None, - entries: None, - stat: Some(guest_filesystem_stat( - kernel.stat(&payload.path).map_err(kernel_error)?, - )), - exists: None, - target: None, - }, - GuestFilesystemOperation::Lstat => GuestFilesystemResultResponse { - operation: payload.operation, - path: payload.path.clone(), - content: None, - encoding: None, - entries: None, - stat: Some(guest_filesystem_stat( - kernel.lstat(&payload.path).map_err(kernel_error)?, - )), - exists: None, - target: None, - }, - GuestFilesystemOperation::ReadDir => GuestFilesystemResultResponse { - operation: payload.operation, - path: payload.path.clone(), - content: None, - encoding: None, - entries: Some( - kernel - .read_dir_with_types(&payload.path) - .map_err(kernel_error)? - .into_iter() - .map(|entry| GuestDirEntry { - path: if payload.path == "/" { - format!("/{}", entry.name) - } else { - format!("{}/{}", payload.path, entry.name) - }, - name: entry.name, - is_directory: entry.is_directory, - is_symbolic_link: entry.is_symbolic_link, - size: 0, - }) - .collect(), - ), - stat: None, - exists: None, - target: None, - }, - GuestFilesystemOperation::ReadDirRecursive => { - let max_depth = payload - .max_depth - .map(|depth| { - usize::try_from(depth).map_err(|_| { - SidecarCoreError::new( - "guest filesystem read_dir_recursive max_depth must fit within usize", - ) - }) - }) - .transpose()?; - GuestFilesystemResultResponse { - operation: payload.operation, - path: payload.path.clone(), - content: None, - encoding: None, - entries: Some( - kernel - .read_dir_recursive(&payload.path, max_depth) - .map_err(kernel_error)? - .into_iter() - .map(|entry| GuestDirEntry { - name: entry - .path - .rsplit('/') - .next() - .unwrap_or(entry.path.as_str()) - .to_owned(), - path: entry.path, - is_directory: entry.is_directory, - is_symbolic_link: entry.is_symbolic_link, - size: entry.size, - }) - .collect(), - ), - stat: None, - exists: None, - target: None, - } - } - GuestFilesystemOperation::RemoveFile => { - kernel.remove_file(&payload.path).map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::RemoveDir => { - kernel.remove_dir(&payload.path).map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::Remove => { - kernel - .remove_path(&payload.path, payload.recursive) - .map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::Copy => { - let destination = payload.destination_path.ok_or_else(|| { - SidecarCoreError::new("guest filesystem copy requires a destination_path") - })?; - kernel - .copy_path(&payload.path, &destination, payload.recursive) - .map_err(kernel_error)?; - targeted_guest_filesystem_response(payload.operation, payload.path, destination) - } - GuestFilesystemOperation::Move => { - let destination = payload.destination_path.ok_or_else(|| { - SidecarCoreError::new("guest filesystem move requires a destination_path") - })?; - kernel - .move_path(&payload.path, &destination) - .map_err(kernel_error)?; - targeted_guest_filesystem_response(payload.operation, payload.path, destination) - } - GuestFilesystemOperation::Rename => { - let destination = payload.destination_path.ok_or_else(|| { - SidecarCoreError::new("guest filesystem rename requires a destination_path") - })?; - kernel - .rename(&payload.path, &destination) - .map_err(kernel_error)?; - targeted_guest_filesystem_response(payload.operation, payload.path, destination) - } - GuestFilesystemOperation::Realpath => targeted_guest_filesystem_response( - payload.operation, - payload.path.clone(), - kernel.realpath(&payload.path).map_err(kernel_error)?, - ), - GuestFilesystemOperation::Symlink => { - let target = payload.target.ok_or_else(|| { - SidecarCoreError::new("guest filesystem symlink requires a target") - })?; - kernel - .symlink(&target, &payload.path) - .map_err(kernel_error)?; - targeted_guest_filesystem_response(payload.operation, payload.path, target) - } - GuestFilesystemOperation::ReadLink => targeted_guest_filesystem_response( - payload.operation, - payload.path.clone(), - kernel.read_link(&payload.path).map_err(kernel_error)?, - ), - GuestFilesystemOperation::Link => { - let destination = payload.destination_path.ok_or_else(|| { - SidecarCoreError::new("guest filesystem link requires a destination_path") - })?; - kernel - .link(&payload.path, &destination) - .map_err(kernel_error)?; - targeted_guest_filesystem_response(payload.operation, payload.path, destination) - } - GuestFilesystemOperation::Chmod => { - let mode = payload - .mode - .ok_or_else(|| SidecarCoreError::new("guest filesystem chmod requires a mode"))?; - kernel.chmod(&payload.path, mode).map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::Chown => { - let uid = payload - .uid - .ok_or_else(|| SidecarCoreError::new("guest filesystem chown requires a uid"))?; - let gid = payload - .gid - .ok_or_else(|| SidecarCoreError::new("guest filesystem chown requires a gid"))?; - kernel - .chown(&payload.path, uid, gid) - .map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::Utimes => { - let atime_ms = payload.atime_ms.ok_or_else(|| { - SidecarCoreError::new("guest filesystem utimes requires atime_ms") - })?; - let mtime_ms = payload.mtime_ms.ok_or_else(|| { - SidecarCoreError::new("guest filesystem utimes requires mtime_ms") - })?; - kernel - .utimes(&payload.path, atime_ms, mtime_ms) - .map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - GuestFilesystemOperation::Truncate => { - let len = payload - .len - .ok_or_else(|| SidecarCoreError::new("guest filesystem truncate requires len"))?; - kernel.truncate(&payload.path, len).map_err(kernel_error)?; - empty_guest_filesystem_response(payload.operation, payload.path) - } - }; - - Ok(response) -} - -pub fn empty_guest_filesystem_response( - operation: GuestFilesystemOperation, - path: String, -) -> GuestFilesystemResultResponse { - GuestFilesystemResultResponse { - operation, - path, - content: None, - encoding: None, - entries: None, - stat: None, - exists: None, - target: None, - } -} - -pub fn targeted_guest_filesystem_response( - operation: GuestFilesystemOperation, - path: String, - target: String, -) -> GuestFilesystemResultResponse { - GuestFilesystemResultResponse { - target: Some(target), - ..empty_guest_filesystem_response(operation, path) - } -} - -pub fn encode_guest_filesystem_content(content: Vec) -> (String, RootFilesystemEntryEncoding) { - match String::from_utf8(content) { - Ok(text) => (text, RootFilesystemEntryEncoding::Utf8), - Err(error) => ( - base64::engine::general_purpose::STANDARD.encode(error.into_bytes()), - RootFilesystemEntryEncoding::Base64, - ), - } -} - -pub fn decode_guest_filesystem_content( - path: &str, - content: Option<&str>, - encoding: Option, -) -> Result, SidecarCoreError> { - let content = content.ok_or_else(|| { - SidecarCoreError::new(format!( - "guest filesystem write_file for {path} requires content" - )) - })?; - - match encoding.unwrap_or(RootFilesystemEntryEncoding::Utf8) { - RootFilesystemEntryEncoding::Utf8 => Ok(content.as_bytes().to_vec()), - RootFilesystemEntryEncoding::Base64 => base64::engine::general_purpose::STANDARD - .decode(content) - .map_err(|error| { - SidecarCoreError::new(format!( - "invalid base64 guest filesystem content for {path}: {error}" - )) - }), - } -} - -pub fn guest_filesystem_stat(stat: VirtualStat) -> GuestFilesystemStat { - GuestFilesystemStat { - mode: stat.mode, - size: stat.size, - blocks: stat.blocks, - dev: stat.dev, - rdev: stat.rdev, - is_directory: stat.is_directory, - is_symbolic_link: stat.is_symbolic_link, - atime_ms: stat.atime_ms, - mtime_ms: stat.mtime_ms, - ctime_ms: stat.ctime_ms, - birthtime_ms: stat.birthtime_ms, - ino: stat.ino, - nlink: stat.nlink, - uid: stat.uid, - gid: stat.gid, - } -} - -fn kernel_error(error: secure_exec_kernel::kernel::KernelError) -> SidecarCoreError { - SidecarCoreError::new(error.to_string()) -} - -#[cfg(test)] -mod tests { - use super::*; - use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig}; - use secure_exec_kernel::permissions::Permissions; - use secure_exec_kernel::vfs::MemoryFileSystem; - - fn test_kernel() -> KernelVm { - let mut config = KernelVmConfig::new("guest-fs-test"); - config.permissions = Permissions::allow_all(); - KernelVm::new(MemoryFileSystem::new(), config) - } - - fn request(operation: GuestFilesystemOperation, path: &str) -> GuestFilesystemCallRequest { - GuestFilesystemCallRequest { - operation, - path: path.to_string(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - } - } - - #[test] - fn handles_kernel_backed_guest_filesystem_round_trip() { - let mut kernel = test_kernel(); - let mut mkdir = request(GuestFilesystemOperation::Mkdir, "/tmp"); - mkdir.recursive = true; - handle_guest_filesystem_call(&mut kernel, mkdir).unwrap(); - - let mut write = request(GuestFilesystemOperation::WriteFile, "/tmp/blob.bin"); - write.content = Some(String::from("//4A")); - write.encoding = Some(RootFilesystemEntryEncoding::Base64); - handle_guest_filesystem_call(&mut kernel, write).unwrap(); - - let read = handle_guest_filesystem_call( - &mut kernel, - request(GuestFilesystemOperation::ReadFile, "/tmp/blob.bin"), - ) - .unwrap(); - assert_eq!(read.content.as_deref(), Some("//4A")); - assert_eq!(read.encoding, Some(RootFilesystemEntryEncoding::Base64)); - - let stat = handle_guest_filesystem_call( - &mut kernel, - request(GuestFilesystemOperation::Stat, "/tmp/blob.bin"), - ) - .unwrap(); - let stat = stat.stat.expect("stat response"); - assert_eq!(stat.size, 3); - assert!(!stat.is_directory); - } - - #[test] - fn reports_required_guest_filesystem_fields() { - let mut kernel = test_kernel(); - let error = handle_guest_filesystem_call( - &mut kernel, - request(GuestFilesystemOperation::Pread, "/missing"), - ) - .unwrap_err(); - assert_eq!(error.to_string(), "guest filesystem pread requires offset"); - - let error = handle_guest_filesystem_call( - &mut kernel, - request(GuestFilesystemOperation::Pwrite, "/missing"), - ) - .unwrap_err(); - assert_eq!(error.to_string(), "guest filesystem pwrite requires offset"); - } - - #[test] - fn pwrite_overwrites_in_place_without_truncating_the_file() { - let mut kernel = test_kernel(); - let mut write = request(GuestFilesystemOperation::WriteFile, "/seek.txt"); - write.content = Some(String::from("abcd")); - write.encoding = Some(RootFilesystemEntryEncoding::Utf8); - handle_guest_filesystem_call(&mut kernel, write).unwrap(); - - // Overwrite "cd" with "XY" at offset 2; the rest of the file ("ab") - // must survive. The lossy client-side read-modify-write this replaces - // would have discarded "ab" whenever the readback failed. - let mut pwrite = request(GuestFilesystemOperation::Pwrite, "/seek.txt"); - pwrite.content = Some(String::from("XY")); - pwrite.encoding = Some(RootFilesystemEntryEncoding::Utf8); - pwrite.offset = Some(2); - handle_guest_filesystem_call(&mut kernel, pwrite).unwrap(); - - let read = handle_guest_filesystem_call( - &mut kernel, - request(GuestFilesystemOperation::ReadFile, "/seek.txt"), - ) - .unwrap(); - assert_eq!(read.content.as_deref(), Some("abXY")); - } - - #[test] - fn pwrite_past_end_grows_and_zero_fills_the_hole() { - let mut kernel = test_kernel(); - let mut write = request(GuestFilesystemOperation::WriteFile, "/hole.bin"); - write.content = Some(String::from("ab")); - write.encoding = Some(RootFilesystemEntryEncoding::Utf8); - handle_guest_filesystem_call(&mut kernel, write).unwrap(); - - let mut pwrite = request(GuestFilesystemOperation::Pwrite, "/hole.bin"); - pwrite.content = Some(String::from("Z")); - pwrite.encoding = Some(RootFilesystemEntryEncoding::Utf8); - pwrite.offset = Some(4); - handle_guest_filesystem_call(&mut kernel, pwrite).unwrap(); - - let read = handle_guest_filesystem_call( - &mut kernel, - request(GuestFilesystemOperation::ReadFile, "/hole.bin"), - ) - .unwrap(); - // "ab" + zero-fill(2) + "Z" -> bytes [97,98,0,0,90]. - let decoded = - decode_guest_filesystem_content("/hole.bin", read.content.as_deref(), read.encoding) - .unwrap(); - assert_eq!(decoded, vec![97u8, 98, 0, 0, 90]); - } - - #[test] - fn read_dir_returns_typed_entries_in_one_call() { - let mut kernel = test_kernel(); - let mut mkdir = request(GuestFilesystemOperation::Mkdir, "/d"); - mkdir.recursive = true; - handle_guest_filesystem_call(&mut kernel, mkdir).unwrap(); - let mut subdir = request(GuestFilesystemOperation::Mkdir, "/d/sub"); - subdir.recursive = true; - handle_guest_filesystem_call(&mut kernel, subdir).unwrap(); - let mut write = request(GuestFilesystemOperation::WriteFile, "/d/file.txt"); - write.content = Some(String::from("hi")); - write.encoding = Some(RootFilesystemEntryEncoding::Utf8); - handle_guest_filesystem_call(&mut kernel, write).unwrap(); - let mut link = request(GuestFilesystemOperation::Symlink, "/d/link"); - link.target = Some(String::from("file.txt")); - handle_guest_filesystem_call(&mut kernel, link).unwrap(); - - // One ReadDir carries every child's type; no per-entry lstat needed. - let result = handle_guest_filesystem_call( - &mut kernel, - request(GuestFilesystemOperation::ReadDir, "/d"), - ) - .unwrap(); - let entries = result.entries.expect("entries"); - assert_eq!(entries.len(), 3); - let by = |name: &str| { - entries - .iter() - .find(|entry| entry.name == name) - .unwrap_or_else(|| panic!("missing {name}")) - }; - assert!(by("sub").is_directory && !by("sub").is_symbolic_link); - assert!(!by("file.txt").is_directory && !by("file.txt").is_symbolic_link); - assert!(by("link").is_symbolic_link); - } -} diff --git a/crates/sidecar-core/src/guest_net.rs b/crates/sidecar-core/src/guest_net.rs deleted file mode 100644 index 87177b224..000000000 --- a/crates/sidecar-core/src/guest_net.rs +++ /dev/null @@ -1,875 +0,0 @@ -//! Shared synchronous guest kernel-call dispatcher. -//! -//! Guest networking, and (later) spawn/WASI, syscalls flow through a single -//! generic synchronous wire payload (`GuestKernelCallRequest` -> -//! `GuestKernelResultResponse`) carrying an `operation` string plus a JSON -//! `payload`, mirroring the native `service_javascript_sync_rpc` design. This -//! module is the backend-agnostic dispatcher that decodes the operation and -//! routes it into the kernel, exactly as `guest_fs::handle_guest_filesystem_call` -//! does for the filesystem family. It is unit-tested without an executor. - -use crate::SidecarCoreError; -use base64::Engine; -use secure_exec_kernel::dns::DnsLookupPolicy; -use secure_exec_kernel::kernel::{KernelError, KernelVm}; -use secure_exec_kernel::poll::{ - PollEvents, PollTargetEntry, POLLERR, POLLHUP, POLLIN, POLLNVAL, POLLOUT, -}; -use secure_exec_kernel::socket_table::{InetSocketAddress, SocketId, SocketShutdown, SocketSpec}; -use secure_exec_kernel::vfs::VirtualFileSystem; -use serde_json::{json, Value}; - -const DEFAULT_LOOPBACK_HOST: &str = "127.0.0.1"; -const DEFAULT_LISTEN_BACKLOG: usize = 128; -const DEFAULT_READ_MAX_BYTES: usize = 64 * 1024; -/// Guest `net.poll` waits run on the sidecar's synchronous request path, so the -/// caller-requested timeout is clamped to a small ceiling: the executor blocks -/// on its own sync-bridge and re-polls rather than parking the sidecar. Mirrors -/// the native `clamp_javascript_net_poll_wait` 50 ms ceiling. -const MAX_POLL_WAIT_MS: i64 = 50; - -/// Dispatch a single synchronous guest kernel call into the kernel. -/// -/// `payload` is the JSON request body for `operation`; the returned bytes are -/// the JSON response body. Errors map kernel failures (including POSIX errno -/// codes) into [`SidecarCoreError`] so both backends surface identical messages. -pub fn handle_guest_kernel_call( - kernel: &mut KernelVm, - pid: u32, - requester_driver: &str, - operation: &str, - payload: &[u8], -) -> Result, SidecarCoreError> -where - F: VirtualFileSystem + 'static, -{ - let request = decode_request(payload)?; - - let response = match operation { - "net.connect" => net_connect(kernel, pid, requester_driver, &request)?, - "net.listen" => net_listen(kernel, pid, requester_driver, &request)?, - "net.accept" => net_accept(kernel, pid, requester_driver, &request)?, - "net.write" => net_write(kernel, pid, requester_driver, &request)?, - "net.read" => net_read(kernel, pid, requester_driver, &request)?, - "net.poll" => net_poll(kernel, pid, requester_driver, &request)?, - "net.shutdown" => net_shutdown(kernel, pid, requester_driver, &request)?, - "net.close" => net_close(kernel, pid, requester_driver, &request)?, - "net.udp_bind" => net_udp_bind(kernel, pid, requester_driver, &request)?, - "net.send_to" => net_send_to(kernel, pid, requester_driver, &request)?, - "net.recv_from" => net_recv_from(kernel, pid, requester_driver, &request)?, - "dgram.create" => dgram_create(kernel, pid, requester_driver, &request)?, - "dgram.bind" => dgram_bind(kernel, pid, requester_driver, &request)?, - "dgram.send" => dgram_send(kernel, pid, requester_driver, &request)?, - "dgram.recv" => dgram_recv(kernel, pid, requester_driver, &request)?, - "dgram.close" => net_close(kernel, pid, requester_driver, &request)?, - "dgram.address" => dgram_address(kernel, &request)?, - "dns.lookup" => dns_lookup(kernel, &request)?, - other if crate::guest_pty::is_pty_operation(other) => { - crate::guest_pty::dispatch_pty_operation( - kernel, - pid, - requester_driver, - other, - &request, - )? - } - other => { - return Err(SidecarCoreError::new(format!( - "unsupported guest kernel call operation: {other}" - ))) - } - }; - - serde_json::to_vec(&response).map_err(|error| { - SidecarCoreError::new(format!( - "failed to encode guest kernel call response: {error}" - )) - }) -} - -fn net_connect( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let host = optional_str(request, "host").unwrap_or(DEFAULT_LOOPBACK_HOST); - let port = require_port(request, "port")?; - let socket_id = kernel - .socket_create(driver, pid, SocketSpec::tcp()) - .map_err(kernel_error)?; - if let Err(error) = kernel.socket_connect_inet_loopback( - driver, - pid, - socket_id, - InetSocketAddress::new(host, port), - ) { - let _ = kernel.socket_close(driver, pid, socket_id); - return Err(kernel_error(error)); - } - let record = kernel.socket_get(socket_id); - let local = record.as_ref().and_then(|record| record.local_address()); - Ok(json!({ - "socketId": socket_id, - "localAddress": local.map(InetSocketAddress::host), - "localPort": local.map(InetSocketAddress::port), - "remoteAddress": host, - "remotePort": port, - })) -} - -fn net_listen( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let host = optional_str(request, "host").unwrap_or(DEFAULT_LOOPBACK_HOST); - let port = require_port(request, "port")?; - let backlog = optional_u64(request, "backlog") - .map(|value| value as usize) - .unwrap_or(DEFAULT_LISTEN_BACKLOG); - let socket_id = kernel - .socket_create(driver, pid, SocketSpec::tcp()) - .map_err(kernel_error)?; - let result = kernel - .socket_bind_inet(driver, pid, socket_id, InetSocketAddress::new(host, port)) - .and_then(|()| kernel.socket_listen(driver, pid, socket_id, backlog)); - if let Err(error) = result { - let _ = kernel.socket_close(driver, pid, socket_id); - return Err(kernel_error(error)); - } - let record = kernel.socket_get(socket_id); - let local = record.as_ref().and_then(|record| record.local_address()); - Ok(json!({ - "socketId": socket_id, - "localAddress": local.map(InetSocketAddress::host), - "localPort": local.map(InetSocketAddress::port), - })) -} - -fn net_accept( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let listener = require_socket_id(request)?; - match kernel.socket_accept(driver, pid, listener) { - Ok(socket_id) => { - let record = kernel.socket_get(socket_id); - let peer = record.as_ref().and_then(|record| record.peer_address()); - Ok(json!({ - "socketId": socket_id, - "remoteAddress": peer.map(InetSocketAddress::host), - "remotePort": peer.map(InetSocketAddress::port), - })) - } - Err(error) if would_block(&error) => Ok(json!({ "socketId": Value::Null })), - Err(error) => Err(kernel_error(error)), - } -} - -fn net_write( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - let data = decode_data(request)?; - let written = kernel - .socket_write(driver, pid, socket_id, &data) - .map_err(kernel_error)?; - Ok(json!({ "written": written })) -} - -fn net_read( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - let max_bytes = optional_u64(request, "maxBytes") - .map(|value| value as usize) - .unwrap_or(DEFAULT_READ_MAX_BYTES); - match kernel.socket_read(driver, pid, socket_id, max_bytes) { - Ok(Some(bytes)) => Ok(json!({ "data": encode_data(&bytes), "closed": false })), - Ok(None) => Ok(json!({ "data": Value::Null, "closed": true })), - Err(error) if would_block(&error) => Ok(json!({ "data": Value::Null, "closed": false })), - Err(error) => Err(kernel_error(error)), - } -} - -fn net_poll( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - let events = optional_u64(request, "events") - .map(|bits| PollEvents::from_bits(bits as u16)) - .unwrap_or(POLLIN | POLLOUT | POLLHUP | POLLERR); - let timeout_ms = optional_u64(request, "timeoutMs") - .map(|value| value as i64) - .unwrap_or(0) - .clamp(0, MAX_POLL_WAIT_MS) as i32; - let result = kernel - .poll_targets( - driver, - pid, - vec![PollTargetEntry::socket(socket_id, events)], - timeout_ms, - ) - .map_err(kernel_error)?; - let revents = result - .targets - .first() - .map(|entry| entry.revents) - .unwrap_or_else(PollEvents::empty); - Ok(json!({ - "revents": revents.bits(), - "readable": revents.intersects(POLLIN), - "writable": revents.intersects(POLLOUT), - "hangup": revents.intersects(POLLHUP), - "error": revents.intersects(POLLERR | POLLNVAL), - })) -} - -fn net_udp_bind( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let host = optional_str(request, "host").unwrap_or(DEFAULT_LOOPBACK_HOST); - let port = require_port(request, "port")?; - let socket_id = kernel - .socket_create(driver, pid, SocketSpec::udp()) - .map_err(kernel_error)?; - if let Err(error) = - kernel.socket_bind_inet(driver, pid, socket_id, InetSocketAddress::new(host, port)) - { - let _ = kernel.socket_close(driver, pid, socket_id); - return Err(kernel_error(error)); - } - let record = kernel.socket_get(socket_id); - let local = record.as_ref().and_then(|record| record.local_address()); - Ok(json!({ - "socketId": socket_id, - "localAddress": local.map(InetSocketAddress::host), - "localPort": local.map(InetSocketAddress::port), - })) -} - -fn net_send_to( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - let host = optional_str(request, "host").unwrap_or(DEFAULT_LOOPBACK_HOST); - let port = require_port(request, "port")?; - let data = decode_data(request)?; - let written = kernel - .socket_send_to_inet_loopback( - driver, - pid, - socket_id, - InetSocketAddress::new(host, port), - &data, - ) - .map_err(kernel_error)?; - Ok(json!({ "written": written })) -} - -fn net_recv_from( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - let max_bytes = optional_u64(request, "maxBytes") - .map(|value| value as usize) - .unwrap_or(DEFAULT_READ_MAX_BYTES); - match kernel.socket_recv_datagram(driver, pid, socket_id, max_bytes) { - Ok(Some(datagram)) => { - let source = datagram.source_address(); - Ok(json!({ - "data": encode_data(datagram.payload()), - "remoteAddress": source.map(InetSocketAddress::host), - "remotePort": source.map(InetSocketAddress::port), - })) - } - Ok(None) => Ok(json!({ "data": Value::Null })), - Err(error) if would_block(&error) => Ok(json!({ "data": Value::Null })), - Err(error) => Err(kernel_error(error)), - } -} - -fn dgram_create( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - _request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = kernel - .socket_create(driver, pid, SocketSpec::udp()) - .map_err(kernel_error)?; - Ok(json!({ "socketId": socket_id })) -} - -fn dgram_bind( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - let host = optional_str(request, "host").unwrap_or(DEFAULT_LOOPBACK_HOST); - let port = optional_u64(request, "port") - .map(|value| u16::try_from(value).unwrap_or(0)) - .unwrap_or(0); - kernel - .socket_bind_inet(driver, pid, socket_id, InetSocketAddress::new(host, port)) - .map_err(kernel_error)?; - let record = kernel.socket_get(socket_id); - let local = record.as_ref().and_then(|record| record.local_address()); - Ok(json!({ - "host": local.map(InetSocketAddress::host), - "port": local.map(InetSocketAddress::port), - })) -} - -fn dgram_send( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - // Auto-bind an unbound datagram socket to an ephemeral port, as Node does on - // the first send. - let needs_bind = kernel - .socket_get(socket_id) - .map(|record| record.local_address().is_none()) - .unwrap_or(false); - if needs_bind { - // Auto-bind to loopback (not 0.0.0.0) so the receiver sees a 127.0.0.1 - // source for loopback delivery, matching POSIX/Node semantics. - kernel - .socket_bind_inet( - driver, - pid, - socket_id, - InetSocketAddress::new("127.0.0.1", 0), - ) - .map_err(kernel_error)?; - } - let host = optional_str(request, "host").unwrap_or(DEFAULT_LOOPBACK_HOST); - let port = require_port(request, "port")?; - let data = decode_data(request)?; - let written = kernel - .socket_send_to_inet_loopback( - driver, - pid, - socket_id, - InetSocketAddress::new(host, port), - &data, - ) - .map_err(kernel_error)?; - Ok(json!({ "bytes": written })) -} - -fn dgram_recv( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - let max_bytes = optional_u64(request, "maxBytes") - .map(|value| value as usize) - .unwrap_or(DEFAULT_READ_MAX_BYTES); - match kernel.socket_recv_datagram(driver, pid, socket_id, max_bytes) { - Ok(Some(datagram)) => { - let source = datagram.source_address(); - Ok(json!({ - "data": encode_data(datagram.payload()), - "remoteAddress": source.map(InetSocketAddress::host), - "remotePort": source.map(InetSocketAddress::port), - })) - } - Ok(None) => Ok(json!({ "data": Value::Null })), - Err(error) if would_block(&error) => Ok(json!({ "data": Value::Null })), - Err(error) => Err(kernel_error(error)), - } -} - -fn dgram_address(kernel: &KernelVm, request: &Value) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - let record = kernel.socket_get(socket_id); - let local = record.as_ref().and_then(|record| record.local_address()); - Ok(json!({ - "host": local.map(InetSocketAddress::host), - "port": local.map(InetSocketAddress::port), - })) -} - -fn dns_lookup(kernel: &KernelVm, request: &Value) -> Result -where - F: VirtualFileSystem + 'static, -{ - let hostname = optional_str(request, "hostname").ok_or_else(|| { - SidecarCoreError::new("guest dns.lookup requires string field `hostname`") - })?; - let resolution = kernel - .resolve_dns(hostname, DnsLookupPolicy::CheckPermissions) - .map_err(kernel_error)?; - let addresses = resolution - .addresses() - .iter() - .map(|address| { - json!({ - "address": address.to_string(), - "family": if address.is_ipv6() { 6 } else { 4 }, - }) - }) - .collect::>(); - Ok(json!({ - "hostname": resolution.hostname(), - "addresses": addresses, - })) -} - -fn net_shutdown( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - let how = match optional_str(request, "how").unwrap_or("both") { - "read" => SocketShutdown::Read, - "write" => SocketShutdown::Write, - "both" => SocketShutdown::Both, - other => { - return Err(SidecarCoreError::new(format!( - "guest net.shutdown received unsupported `how` value: {other}" - ))) - } - }; - kernel - .socket_shutdown(driver, pid, socket_id, how) - .map_err(kernel_error)?; - Ok(json!({})) -} - -fn net_close( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let socket_id = require_socket_id(request)?; - kernel - .socket_close(driver, pid, socket_id) - .map_err(kernel_error)?; - Ok(json!({})) -} - -fn decode_request(payload: &[u8]) -> Result { - if payload.is_empty() { - return Ok(Value::Null); - } - serde_json::from_slice(payload).map_err(|error| { - SidecarCoreError::new(format!("invalid guest kernel call payload: {error}")) - }) -} - -fn optional_str<'a>(request: &'a Value, key: &str) -> Option<&'a str> { - request.get(key).and_then(Value::as_str) -} - -fn optional_u64(request: &Value, key: &str) -> Option { - request.get(key).and_then(Value::as_u64) -} - -fn require_port(request: &Value, key: &str) -> Result { - let value = optional_u64(request, key).ok_or_else(|| { - SidecarCoreError::new(format!("guest kernel call requires numeric field `{key}`")) - })?; - u16::try_from(value).map_err(|_| { - SidecarCoreError::new(format!( - "guest kernel call field `{key}` must be a valid port" - )) - }) -} - -fn require_socket_id(request: &Value) -> Result { - optional_u64(request, "socketId") - .ok_or_else(|| SidecarCoreError::new("guest kernel call requires numeric field `socketId`")) -} - -fn decode_data(request: &Value) -> Result, SidecarCoreError> { - let data = optional_str(request, "data") - .ok_or_else(|| SidecarCoreError::new("guest kernel call requires string field `data`"))?; - base64::engine::general_purpose::STANDARD - .decode(data) - .map_err(|error| { - SidecarCoreError::new(format!("invalid base64 guest socket data: {error}")) - }) -} - -fn encode_data(bytes: &[u8]) -> String { - base64::engine::general_purpose::STANDARD.encode(bytes) -} - -fn would_block(error: &KernelError) -> bool { - matches!(error.code(), "EAGAIN" | "EWOULDBLOCK") -} - -fn kernel_error(error: KernelError) -> SidecarCoreError { - SidecarCoreError::new(error.to_string()) -} - -#[cfg(test)] -mod tests { - use super::*; - use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, VirtualProcessOptions}; - use secure_exec_kernel::permissions::Permissions; - use secure_exec_kernel::vfs::MemoryFileSystem; - - fn test_kernel() -> KernelVm { - let mut config = KernelVmConfig::new("guest-net-test"); - config.permissions = Permissions::allow_all(); - KernelVm::new(MemoryFileSystem::new(), config) - } - - fn guest_pid(kernel: &mut KernelVm) -> u32 { - kernel - .create_virtual_process( - "shell", - "shell", - "sh", - Vec::new(), - VirtualProcessOptions::default(), - ) - .expect("spawn guest process") - .pid() - } - - fn call( - kernel: &mut KernelVm, - pid: u32, - operation: &str, - request: Value, - ) -> Value { - let payload = serde_json::to_vec(&request).expect("encode request"); - let bytes = - handle_guest_kernel_call(kernel, pid, "shell", operation, &payload).expect("dispatch"); - serde_json::from_slice(&bytes).expect("decode response") - } - - #[test] - fn loopback_tcp_round_trip_through_kernel() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - - let listener = call( - &mut kernel, - pid, - "net.listen", - json!({ "host": "127.0.0.1", "port": 44551 }), - ); - let listener_id = listener["socketId"].as_u64().expect("listener socket id"); - - let client = call( - &mut kernel, - pid, - "net.connect", - json!({ "host": "127.0.0.1", "port": 44551 }), - ); - let client_id = client["socketId"].as_u64().expect("client socket id"); - - let accepted = call( - &mut kernel, - pid, - "net.accept", - json!({ "socketId": listener_id }), - ); - let accepted_id = accepted["socketId"].as_u64().expect("accepted socket id"); - - let payload = b"hello kernel loopback"; - let write = call( - &mut kernel, - pid, - "net.write", - json!({ "socketId": client_id, "data": encode_data(payload) }), - ); - assert_eq!(write["written"].as_u64(), Some(payload.len() as u64)); - - let read = call( - &mut kernel, - pid, - "net.read", - json!({ "socketId": accepted_id }), - ); - assert_eq!(read["closed"].as_bool(), Some(false)); - let decoded = base64::engine::general_purpose::STANDARD - .decode(read["data"].as_str().expect("read data")) - .expect("decode read data"); - assert_eq!(decoded, payload); - - call( - &mut kernel, - pid, - "net.close", - json!({ "socketId": client_id }), - ); - call( - &mut kernel, - pid, - "net.close", - json!({ "socketId": accepted_id }), - ); - call( - &mut kernel, - pid, - "net.close", - json!({ "socketId": listener_id }), - ); - } - - #[test] - fn accept_without_pending_connection_reports_null_socket() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - let listener = call( - &mut kernel, - pid, - "net.listen", - json!({ "host": "127.0.0.1", "port": 44552 }), - ); - let listener_id = listener["socketId"].as_u64().expect("listener socket id"); - - let accepted = call( - &mut kernel, - pid, - "net.accept", - json!({ "socketId": listener_id }), - ); - assert!(accepted["socketId"].is_null()); - } - - #[test] - fn poll_reports_readability_after_loopback_write() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - let listener = call( - &mut kernel, - pid, - "net.listen", - json!({ "host": "127.0.0.1", "port": 44561 }), - ); - let listener_id = listener["socketId"].as_u64().expect("listener socket id"); - let client = call( - &mut kernel, - pid, - "net.connect", - json!({ "host": "127.0.0.1", "port": 44561 }), - ); - let client_id = client["socketId"].as_u64().expect("client socket id"); - let accepted = call( - &mut kernel, - pid, - "net.accept", - json!({ "socketId": listener_id }), - ); - let accepted_id = accepted["socketId"].as_u64().expect("accepted socket id"); - - let before = call( - &mut kernel, - pid, - "net.poll", - json!({ "socketId": accepted_id }), - ); - assert_eq!(before["readable"].as_bool(), Some(false)); - - call( - &mut kernel, - pid, - "net.write", - json!({ "socketId": client_id, "data": encode_data(b"ping") }), - ); - - let after = call( - &mut kernel, - pid, - "net.poll", - json!({ "socketId": accepted_id }), - ); - assert_eq!(after["readable"].as_bool(), Some(true)); - } - - #[test] - fn udp_loopback_datagram_round_trip() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - let receiver = call( - &mut kernel, - pid, - "net.udp_bind", - json!({ "host": "127.0.0.1", "port": 45601 }), - ); - let receiver_id = receiver["socketId"].as_u64().expect("receiver socket id"); - let sender = call( - &mut kernel, - pid, - "net.udp_bind", - json!({ "host": "127.0.0.1", "port": 45602 }), - ); - let sender_id = sender["socketId"].as_u64().expect("sender socket id"); - - let payload = b"datagram payload"; - let sent = call( - &mut kernel, - pid, - "net.send_to", - json!({ "socketId": sender_id, "host": "127.0.0.1", "port": 45601, "data": encode_data(payload) }), - ); - assert_eq!(sent["written"].as_u64(), Some(payload.len() as u64)); - - let received = call( - &mut kernel, - pid, - "net.recv_from", - json!({ "socketId": receiver_id }), - ); - let decoded = base64::engine::general_purpose::STANDARD - .decode(received["data"].as_str().expect("datagram data")) - .expect("decode datagram"); - assert_eq!(decoded, payload); - assert_eq!(received["remotePort"].as_u64(), Some(45602)); - } - - #[test] - fn dns_lookup_resolves_literal_addresses() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - let resolution = call( - &mut kernel, - pid, - "dns.lookup", - json!({ "hostname": "127.0.0.1" }), - ); - assert_eq!(resolution["hostname"].as_str(), Some("127.0.0.1")); - let addresses = resolution["addresses"].as_array().expect("addresses array"); - assert_eq!(addresses.len(), 1); - assert_eq!(addresses[0]["address"].as_str(), Some("127.0.0.1")); - assert_eq!(addresses[0]["family"].as_u64(), Some(4)); - } - - #[test] - fn dgram_loopback_round_trip_with_auto_bind_sender() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - - let receiver = call(&mut kernel, pid, "dgram.create", json!({})); - let receiver_id = receiver["socketId"].as_u64().expect("receiver id"); - call( - &mut kernel, - pid, - "dgram.bind", - json!({ "socketId": receiver_id, "host": "127.0.0.1", "port": 46711 }), - ); - - // Sender is never bound explicitly -> dgram.send auto-binds it. - let sender = call(&mut kernel, pid, "dgram.create", json!({})); - let sender_id = sender["socketId"].as_u64().expect("sender id"); - let payload = b"dgram-auto-bind"; - let sent = call( - &mut kernel, - pid, - "dgram.send", - json!({ "socketId": sender_id, "host": "127.0.0.1", "port": 46711, "data": encode_data(payload) }), - ); - assert_eq!(sent["bytes"].as_u64(), Some(payload.len() as u64)); - - let recv = call( - &mut kernel, - pid, - "dgram.recv", - json!({ "socketId": receiver_id }), - ); - let decoded = base64::engine::general_purpose::STANDARD - .decode(recv["data"].as_str().expect("recv data")) - .expect("decode"); - assert_eq!(decoded, payload); - // The auto-bound sender got an ephemeral port in the dynamic range. - assert!(recv["remotePort"].as_u64().expect("remote port") >= 49152); - } - - #[test] - fn unsupported_operation_is_reported() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - let error = - handle_guest_kernel_call(&mut kernel, pid, "shell", "net.teleport", b"{}").unwrap_err(); - assert!(error - .to_string() - .contains("unsupported guest kernel call operation: net.teleport")); - } -} diff --git a/crates/sidecar-core/src/guest_pty.rs b/crates/sidecar-core/src/guest_pty.rs deleted file mode 100644 index aa4af0007..000000000 --- a/crates/sidecar-core/src/guest_pty.rs +++ /dev/null @@ -1,468 +0,0 @@ -//! Guest PTY kernel-call dispatch. -//! -//! Pseudo-terminal syscalls flow through the same generic synchronous wire -//! payload as guest networking (`GuestKernelCallRequest` -> -//! `GuestKernelResultResponse`) carrying a `pty.*` `operation` string plus a -//! JSON `payload`. This module is the backend-agnostic dispatcher that decodes a -//! `pty.*` operation and routes it into the kernel's `PtyManager`, exactly as -//! [`crate::guest_net`] does for the `net.*`/`dns.*` family. It is delegated to -//! from `handle_guest_kernel_call` and unit-tested without an executor. -//! -//! The PTY is inherently fd/stream based, so unlike the path-based filesystem -//! family the read/write operations carry a kernel fd and route through the -//! kernel's generic by-fd read/write (which already dispatches pty fds through -//! the line discipline). `pty.open` allocates a master/slave pair; the host -//! drives the master while a guest's std streams bind to the slave. - -use crate::SidecarCoreError; -use base64::Engine; -use secure_exec_kernel::kernel::{KernelError, KernelVm}; -use secure_exec_kernel::pty::{PartialTermios, PartialTermiosControlChars}; -use secure_exec_kernel::vfs::VirtualFileSystem; -use serde_json::{json, Value}; -use std::time::Duration; - -const DEFAULT_READ_MAX_BYTES: usize = 64 * 1024; -/// Guest pty reads run on the sidecar's synchronous request path, so a blocking -/// read is clamped to a small ceiling: the guest re-reads rather than parking -/// the sidecar (mirrors the `net.poll` 50 ms ceiling in [`crate::guest_net`]). -const MAX_PTY_READ_WAIT_MS: u64 = 50; - -/// True when `operation` names a `pty.*` guest kernel call. -pub fn is_pty_operation(operation: &str) -> bool { - operation.starts_with("pty.") -} - -/// Dispatch a single `pty.*` guest kernel call into the kernel. `request` is the -/// already-decoded JSON request body; the returned `Value` is the JSON response -/// body the guest sync-bridge consumes. -pub fn dispatch_pty_operation( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - operation: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - match operation { - "pty.open" => pty_open(kernel, pid, driver), - "pty.read" => pty_read(kernel, pid, driver, request), - "pty.write" => pty_write(kernel, pid, driver, request), - "pty.close" => pty_close(kernel, pid, driver, request), - "pty.resize" => pty_resize(kernel, pid, driver, request), - "pty.setForegroundPgid" => pty_set_foreground_pgid(kernel, pid, driver, request), - "pty.tcgetattr" => pty_tcgetattr(kernel, pid, driver, request), - "pty.tcsetattr" => pty_tcsetattr(kernel, pid, driver, request), - other => Err(SidecarCoreError::new(format!( - "unsupported guest pty operation: {other}" - ))), - } -} - -fn pty_open(kernel: &mut KernelVm, pid: u32, driver: &str) -> Result -where - F: VirtualFileSystem + 'static, -{ - let (master_fd, slave_fd, path) = kernel.open_pty(driver, pid).map_err(kernel_error)?; - Ok(json!({ "masterFd": master_fd, "slaveFd": slave_fd, "path": path })) -} - -fn pty_read( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let fd = require_fd(request)?; - let max_bytes = optional_u64(request, "maxBytes") - .map(|value| value as usize) - .unwrap_or(DEFAULT_READ_MAX_BYTES); - let wait_ms = optional_u64(request, "timeoutMs") - .unwrap_or(MAX_PTY_READ_WAIT_MS) - .min(MAX_PTY_READ_WAIT_MS); - let timeout = Some(Duration::from_millis(wait_ms)); - match kernel.fd_read_with_timeout_result(driver, pid, fd, max_bytes, timeout) { - Ok(Some(bytes)) => Ok(json!({ "data": encode_data(&bytes) })), - // No data within the (short) timeout. A zero/short blocking read with an empty - // line discipline buffer surfaces as EAGAIN; the guest polls again, so this is - // a no-data result (`data: null`), not an error — mirrors guest_net.net_read. - Ok(None) => Ok(json!({ "data": Value::Null })), - Err(error) if would_block(&error) => Ok(json!({ "data": Value::Null })), - Err(error) => Err(kernel_error(error)), - } -} - -fn pty_write( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let fd = require_fd(request)?; - let data = decode_data(request)?; - let written = kernel - .fd_write(driver, pid, fd, &data) - .map_err(kernel_error)?; - Ok(json!({ "written": written })) -} - -fn pty_close( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let fd = require_fd(request)?; - kernel.fd_close(driver, pid, fd).map_err(kernel_error)?; - Ok(json!({})) -} - -fn pty_resize( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let fd = require_fd(request)?; - let cols = require_u16(request, "cols")?; - let rows = require_u16(request, "rows")?; - kernel - .pty_resize(driver, pid, fd, cols, rows) - .map_err(kernel_error)?; - Ok(json!({})) -} - -fn pty_set_foreground_pgid( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let fd = require_fd(request)?; - let pgid = optional_u32(request, "pgid")?.unwrap_or(pid); - if pgid == pid { - kernel.setpgid(driver, pid, pgid).map_err(kernel_error)?; - } - kernel - .pty_set_foreground_pgid(driver, pid, fd, pgid) - .map_err(kernel_error)?; - Ok(json!({})) -} - -fn pty_tcgetattr( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let fd = require_fd(request)?; - let termios = kernel.tcgetattr(driver, pid, fd).map_err(kernel_error)?; - Ok(json!({ - "icrnl": termios.icrnl, - "opost": termios.opost, - "onlcr": termios.onlcr, - "icanon": termios.icanon, - "echo": termios.echo, - "isig": termios.isig, - "cc": { - "vintr": termios.cc.vintr, - "vquit": termios.cc.vquit, - "vsusp": termios.cc.vsusp, - "veof": termios.cc.veof, - "verase": termios.cc.verase, - "vkill": termios.cc.vkill, - "vwerase": termios.cc.vwerase, - }, - })) -} - -fn pty_tcsetattr( - kernel: &mut KernelVm, - pid: u32, - driver: &str, - request: &Value, -) -> Result -where - F: VirtualFileSystem + 'static, -{ - let fd = require_fd(request)?; - let partial = parse_partial_termios(request); - kernel - .tcsetattr(driver, pid, fd, partial) - .map_err(kernel_error)?; - Ok(json!({})) -} - -/// A `pty.tcsetattr` request supplies only the termios fields it wants changed; -/// every field is optional so the guest can flip raw mode (icanon/echo/opost) -/// without restating the rest. -fn parse_partial_termios(request: &Value) -> PartialTermios { - let cc = request.get("cc").map(|cc| PartialTermiosControlChars { - vintr: optional_u8(cc, "vintr"), - vquit: optional_u8(cc, "vquit"), - vsusp: optional_u8(cc, "vsusp"), - veof: optional_u8(cc, "veof"), - verase: optional_u8(cc, "verase"), - vkill: optional_u8(cc, "vkill"), - vwerase: optional_u8(cc, "vwerase"), - }); - PartialTermios { - icrnl: optional_bool(request, "icrnl"), - opost: optional_bool(request, "opost"), - onlcr: optional_bool(request, "onlcr"), - icanon: optional_bool(request, "icanon"), - echo: optional_bool(request, "echo"), - isig: optional_bool(request, "isig"), - cc, - } -} - -fn require_fd(request: &Value) -> Result { - let fd = optional_u64(request, "fd") - .ok_or_else(|| SidecarCoreError::new("guest pty call requires numeric field `fd`"))?; - u32::try_from(fd) - .map_err(|_| SidecarCoreError::new("guest pty call field `fd` must be a valid descriptor")) -} - -fn require_u16(request: &Value, key: &str) -> Result { - let value = optional_u64(request, key).ok_or_else(|| { - SidecarCoreError::new(format!("guest pty call requires numeric field `{key}`")) - })?; - u16::try_from(value) - .map_err(|_| SidecarCoreError::new(format!("guest pty call field `{key}` is out of range"))) -} - -fn optional_u32(request: &Value, key: &str) -> Result, SidecarCoreError> { - optional_u64(request, key) - .map(u32::try_from) - .transpose() - .map_err(|_| SidecarCoreError::new(format!("guest pty call field `{key}` is out of range"))) -} - -fn optional_u64(request: &Value, key: &str) -> Option { - request.get(key).and_then(Value::as_u64) -} - -fn optional_bool(request: &Value, key: &str) -> Option { - request.get(key).and_then(Value::as_bool) -} - -fn optional_u8(request: &Value, key: &str) -> Option { - optional_u64(request, key).and_then(|value| u8::try_from(value).ok()) -} - -fn decode_data(request: &Value) -> Result, SidecarCoreError> { - let data = request - .get("data") - .and_then(Value::as_str) - .ok_or_else(|| SidecarCoreError::new("guest pty call requires string field `data`"))?; - base64::engine::general_purpose::STANDARD - .decode(data) - .map_err(|error| SidecarCoreError::new(format!("invalid base64 guest pty data: {error}"))) -} - -fn encode_data(bytes: &[u8]) -> String { - base64::engine::general_purpose::STANDARD.encode(bytes) -} - -fn would_block(error: &KernelError) -> bool { - matches!(error.code(), "EAGAIN" | "EWOULDBLOCK") -} - -fn kernel_error(error: KernelError) -> SidecarCoreError { - SidecarCoreError::new(error.to_string()) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::guest_net::handle_guest_kernel_call; - use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, VirtualProcessOptions}; - use secure_exec_kernel::permissions::Permissions; - use secure_exec_kernel::vfs::MemoryFileSystem; - - fn test_kernel() -> KernelVm { - let mut config = KernelVmConfig::new("guest-pty-test"); - config.permissions = Permissions::allow_all(); - KernelVm::new(MemoryFileSystem::new(), config) - } - - fn guest_pid(kernel: &mut KernelVm) -> u32 { - kernel - .create_virtual_process( - "shell", - "shell", - "sh", - Vec::new(), - VirtualProcessOptions::default(), - ) - .expect("spawn guest process") - .pid() - } - - /// Drive a `pty.*` call through the same public entry the wire dispatcher uses, - /// so the test covers the `handle_guest_kernel_call` -> `dispatch_pty_operation` - /// delegation, not just the inner functions. - fn call( - kernel: &mut KernelVm, - pid: u32, - operation: &str, - request: Value, - ) -> Value { - let payload = serde_json::to_vec(&request).expect("encode request"); - let bytes = - handle_guest_kernel_call(kernel, pid, "shell", operation, &payload).expect("dispatch"); - serde_json::from_slice(&bytes).expect("decode response") - } - - fn read_until_data(kernel: &mut KernelVm, pid: u32, fd: u64) -> Vec { - for _ in 0..200 { - let response = call(kernel, pid, "pty.read", json!({ "fd": fd })); - if let Some(data) = response["data"].as_str() { - return base64::engine::general_purpose::STANDARD - .decode(data) - .expect("decode pty read"); - } - } - panic!("pty.read timed out"); - } - - #[test] - fn loopback_pty_round_trip_through_kernel_line_discipline() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - - let pair = call(&mut kernel, pid, "pty.open", json!({})); - let master = pair["masterFd"].as_u64().expect("master fd"); - let slave = pair["slaveFd"].as_u64().expect("slave fd"); - assert!(pair["path"] - .as_str() - .expect("pty path") - .starts_with("/dev/")); - - // Raw mode so the loopback carries exactly what is written. - call( - &mut kernel, - pid, - "pty.tcsetattr", - json!({ "fd": slave, "icanon": false, "echo": false, "opost": false, "isig": false }), - ); - - let input = base64::engine::general_purpose::STANDARD.encode(b"ping-pty"); - call( - &mut kernel, - pid, - "pty.write", - json!({ "fd": master, "data": input }), - ); - assert_eq!(read_until_data(&mut kernel, pid, slave), b"ping-pty"); - - let reply = base64::engine::general_purpose::STANDARD.encode(b"ECHO:ping-pty"); - call( - &mut kernel, - pid, - "pty.write", - json!({ "fd": slave, "data": reply }), - ); - assert_eq!(read_until_data(&mut kernel, pid, master), b"ECHO:ping-pty"); - - call(&mut kernel, pid, "pty.close", json!({ "fd": slave })); - call(&mut kernel, pid, "pty.close", json!({ "fd": master })); - } - - #[test] - fn tcsetattr_then_tcgetattr_reflects_raw_mode() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - let pair = call(&mut kernel, pid, "pty.open", json!({})); - let slave = pair["slaveFd"].as_u64().expect("slave fd"); - - // Default is canonical + echo. - let before = call(&mut kernel, pid, "pty.tcgetattr", json!({ "fd": slave })); - assert_eq!(before["icanon"].as_bool(), Some(true)); - assert_eq!(before["echo"].as_bool(), Some(true)); - - call( - &mut kernel, - pid, - "pty.tcsetattr", - json!({ "fd": slave, "icanon": false, "echo": false }), - ); - let after = call(&mut kernel, pid, "pty.tcgetattr", json!({ "fd": slave })); - assert_eq!(after["icanon"].as_bool(), Some(false)); - assert_eq!(after["echo"].as_bool(), Some(false)); - // isig was not in the partial update, so it is untouched. - assert_eq!(after["isig"].as_bool(), Some(true)); - } - - #[test] - fn empty_pty_read_is_null_not_error() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - let pair = call(&mut kernel, pid, "pty.open", json!({})); - let master = pair["masterFd"].as_u64().expect("master fd"); - - // Nothing has been written, so a zero-timeout poll must report no data rather - // than surfacing EAGAIN as a dispatch error (the interactive shell polls). - let response = call( - &mut kernel, - pid, - "pty.read", - json!({ "fd": master, "timeoutMs": 0 }), - ); - assert!(response["data"].is_null()); - } - - #[test] - fn set_foreground_pgid_defaults_to_active_guest_process_group() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - let pair = call(&mut kernel, pid, "pty.open", json!({})); - let master = pair["masterFd"].as_u64().expect("master fd"); - - call( - &mut kernel, - pid, - "pty.setForegroundPgid", - json!({ "fd": master }), - ); - - assert_eq!(kernel.getpgid("shell", pid).expect("pgid"), pid); - assert_eq!( - kernel - .tcgetpgrp("shell", pid, master as u32) - .expect("foreground pgid"), - pid - ); - } - - #[test] - fn unsupported_pty_operation_is_rejected() { - let mut kernel = test_kernel(); - let pid = guest_pid(&mut kernel); - let payload = serde_json::to_vec(&json!({})).unwrap(); - let error = handle_guest_kernel_call(&mut kernel, pid, "shell", "pty.bogus", &payload) - .expect_err("unknown pty op rejected"); - assert!(error.to_string().contains("pty.bogus")); - } -} diff --git a/crates/sidecar-core/src/identity.rs b/crates/sidecar-core/src/identity.rs deleted file mode 100644 index f2474165b..000000000 --- a/crates/sidecar-core/src/identity.rs +++ /dev/null @@ -1,98 +0,0 @@ -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::user::UserManager; - -use crate::{virtual_os_cpu_count, virtual_os_freemem_bytes, virtual_os_totalmem_bytes}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SharedGuestRuntimeIdentity { - pub virtual_pid: Option, - pub virtual_ppid: Option, - pub virtual_uid: u64, - pub virtual_gid: u64, - pub process_platform: String, - pub process_arch: String, - pub os_cpu_count: u64, - pub os_totalmem: u64, - pub os_freemem: u64, - pub os_homedir: String, - pub os_hostname: String, - pub os_shell: String, - pub os_user: String, - pub os_tmpdir: String, - pub os_type: String, - pub os_release: String, - pub os_version: String, - pub os_machine: String, -} - -pub fn shared_guest_runtime_identity( - user: &UserManager, - resource_limits: &ResourceLimits, - virtual_pid: Option, - virtual_ppid: Option, -) -> SharedGuestRuntimeIdentity { - SharedGuestRuntimeIdentity { - virtual_pid, - virtual_ppid, - virtual_uid: u64::from(user.uid), - virtual_gid: u64::from(user.gid), - process_platform: String::from("linux"), - process_arch: String::from("x64"), - os_cpu_count: virtual_os_cpu_count(resource_limits) as u64, - os_totalmem: virtual_os_totalmem_bytes(resource_limits), - os_freemem: virtual_os_freemem_bytes(resource_limits), - os_homedir: user.homedir.clone(), - os_hostname: String::from("secure-exec"), - os_shell: user.shell.clone(), - os_user: user.username.clone(), - os_tmpdir: String::from("/tmp"), - os_type: String::from("Linux"), - os_release: String::from("6.8.0-secure-exec"), - os_version: String::from("#1 SMP PREEMPT_DYNAMIC secure-exec"), - os_machine: String::from("x86_64"), - } -} - -#[cfg(test)] -mod tests { - use super::*; - use secure_exec_kernel::resource_accounting::ResourceLimits; - use secure_exec_kernel::user::{UserConfig, UserManager}; - - #[test] - fn builds_guest_identity_from_kernel_user_and_limits() { - let user = UserManager::from_config(UserConfig { - uid: Some(501), - gid: Some(20), - username: Some(String::from("runner")), - homedir: Some(String::from("/Users/runner")), - shell: Some(String::from("/bin/zsh")), - ..UserConfig::default() - }); - let limits = ResourceLimits { - virtual_cpu_count: Some(6), - max_wasm_memory_bytes: Some(512 * 1024 * 1024), - ..ResourceLimits::default() - }; - - let identity = shared_guest_runtime_identity(&user, &limits, Some(42), Some(1)); - - assert_eq!(identity.virtual_pid, Some(42)); - assert_eq!(identity.virtual_ppid, Some(1)); - assert_eq!(identity.virtual_uid, 501); - assert_eq!(identity.virtual_gid, 20); - assert_eq!(identity.process_platform, "linux"); - assert_eq!(identity.process_arch, "x64"); - assert_eq!(identity.os_cpu_count, 6); - assert_eq!(identity.os_totalmem, 512 * 1024 * 1024); - assert_eq!(identity.os_homedir, "/Users/runner"); - assert_eq!(identity.os_hostname, "secure-exec"); - assert_eq!(identity.os_shell, "/bin/zsh"); - assert_eq!(identity.os_user, "runner"); - assert_eq!(identity.os_tmpdir, "/tmp"); - assert_eq!(identity.os_type, "Linux"); - assert_eq!(identity.os_release, "6.8.0-secure-exec"); - assert_eq!(identity.os_version, "#1 SMP PREEMPT_DYNAMIC secure-exec"); - assert_eq!(identity.os_machine, "x86_64"); - } -} diff --git a/crates/sidecar-core/src/layers.rs b/crates/sidecar-core/src/layers.rs deleted file mode 100644 index b24ef842e..000000000 --- a/crates/sidecar-core/src/layers.rs +++ /dev/null @@ -1,293 +0,0 @@ -use crate::SidecarCoreError; -use secure_exec_kernel::root_fs::{ - FilesystemEntry, FilesystemEntryKind, RootFileSystem, - RootFilesystemDescriptor as KernelRootFilesystemDescriptor, - RootFilesystemMode as KernelRootFilesystemMode, RootFilesystemSnapshot, -}; -use std::collections::{BTreeMap, BTreeSet}; - -pub const MAX_VM_LAYERS: usize = 256; - -#[derive(Debug)] -pub struct VmLayerStore { - next_layer_id: u64, - layers: BTreeMap, -} - -impl Default for VmLayerStore { - fn default() -> Self { - Self { - next_layer_id: 1, - layers: BTreeMap::new(), - } - } -} - -#[derive(Debug)] -enum VmLayer { - Writable(RootFileSystem), - Snapshot(RootFilesystemSnapshot), - Overlay(VmOverlayLayer), -} - -#[derive(Debug, Clone)] -struct VmOverlayLayer { - mode: KernelRootFilesystemMode, - upper_layer_id: Option, - lower_layer_ids: Vec, -} - -impl VmLayerStore { - pub fn layer_count(&self) -> usize { - self.layers.len() - } - - pub fn create_writable_layer(&mut self) -> Result { - self.ensure_layer_capacity()?; - let filesystem = new_writable_layer()?; - let layer_id = self.allocate_layer_id()?; - self.layers - .insert(layer_id.clone(), VmLayer::Writable(filesystem)); - Ok(layer_id) - } - - pub fn seal_layer(&mut self, layer_id: &str) -> Result { - let snapshot = match self.layers.get_mut(layer_id) { - Some(VmLayer::Writable(filesystem)) => filesystem - .snapshot() - .map_err(|error| SidecarCoreError::new(format!("seal layer: {error}")))?, - Some(VmLayer::Snapshot(_)) | Some(VmLayer::Overlay(_)) => { - return Err(SidecarCoreError::new(format!( - "layer {layer_id} is not writable" - ))); - } - None => return Err(SidecarCoreError::new(format!("unknown layer: {layer_id}"))), - }; - let sealed_layer_id = self.allocate_layer_id()?; - match self - .layers - .remove(layer_id) - .expect("layer should still exist after snapshot") - { - VmLayer::Writable(_) => {} - VmLayer::Snapshot(_) | VmLayer::Overlay(_) => { - return Err(SidecarCoreError::new(format!( - "layer {layer_id} is not writable" - ))); - } - } - self.layers - .insert(sealed_layer_id.clone(), VmLayer::Snapshot(snapshot)); - Ok(sealed_layer_id) - } - - pub fn import_snapshot( - &mut self, - snapshot: RootFilesystemSnapshot, - ) -> Result { - self.ensure_layer_capacity()?; - let layer_id = self.allocate_layer_id()?; - self.layers - .insert(layer_id.clone(), VmLayer::Snapshot(snapshot)); - Ok(layer_id) - } - - pub fn export_snapshot( - &mut self, - layer_id: &str, - ) -> Result { - materialize_vm_layer_snapshot(self, layer_id) - } - - pub fn create_overlay_layer( - &mut self, - mode: KernelRootFilesystemMode, - upper_layer_id: Option, - lower_layer_ids: Vec, - ) -> Result { - self.ensure_layer_capacity()?; - for layer_id in &lower_layer_ids { - if !self.layers.contains_key(layer_id) { - return Err(SidecarCoreError::new(format!( - "unknown lower layer: {layer_id}" - ))); - } - } - if let Some(layer_id) = upper_layer_id.as_ref() { - if !self.layers.contains_key(layer_id) { - return Err(SidecarCoreError::new(format!( - "unknown upper layer: {layer_id}" - ))); - } - } - - let layer_id = self.allocate_layer_id()?; - self.layers.insert( - layer_id.clone(), - VmLayer::Overlay(VmOverlayLayer { - mode, - upper_layer_id, - lower_layer_ids, - }), - ); - Ok(layer_id) - } - - fn ensure_layer_capacity(&self) -> Result<(), SidecarCoreError> { - if self.layers.len() >= MAX_VM_LAYERS { - return Err(SidecarCoreError::new(format!( - "VM layer limit exceeded: limit is {MAX_VM_LAYERS}" - ))); - } - Ok(()) - } - - fn allocate_layer_id(&mut self) -> Result { - let layer_id = format!("layer-{}", self.next_layer_id); - self.next_layer_id = self - .next_layer_id - .checked_add(1) - .ok_or_else(|| SidecarCoreError::new("VM layer id overflow"))?; - Ok(layer_id) - } -} - -fn new_writable_layer() -> Result { - RootFileSystem::from_descriptor(KernelRootFilesystemDescriptor { - mode: KernelRootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }) - .map_err(|error| SidecarCoreError::new(format!("create writable layer: {error}"))) -} - -fn materialize_vm_layer_snapshot( - layers: &mut VmLayerStore, - layer_id: &str, -) -> Result { - materialize_vm_layer_snapshot_inner(layers, layer_id, &mut BTreeSet::new()) -} - -fn materialize_vm_layer_snapshot_inner( - layers: &mut VmLayerStore, - layer_id: &str, - active: &mut BTreeSet, -) -> Result { - if !active.insert(layer_id.to_owned()) { - return Err(SidecarCoreError::new(format!( - "layer graph cycle detected at {layer_id}" - ))); - } - - let result = if let Some(VmLayer::Snapshot(snapshot)) = layers.layers.get(layer_id) { - Ok(snapshot.clone()) - } else if let Some(VmLayer::Overlay(overlay)) = layers.layers.get(layer_id) { - let overlay = overlay.clone(); - let lowers = overlay - .lower_layer_ids - .iter() - .map(|lower_id| materialize_vm_layer_snapshot_inner(layers, lower_id, active)) - .collect::, _>>()?; - let bootstrap_entries = match overlay.upper_layer_id.as_deref() { - Some(upper_layer_id) => dedupe_overlay_bootstrap_entries( - &lowers, - materialize_vm_layer_snapshot_inner(layers, upper_layer_id, active)?.entries, - ), - None => Vec::new(), - }; - let mut root = RootFileSystem::from_descriptor(KernelRootFilesystemDescriptor { - mode: overlay.mode, - disable_default_base_layer: true, - lowers, - bootstrap_entries, - }) - .map_err(|error| SidecarCoreError::new(format!("materialize overlay layer: {error}")))?; - root.snapshot() - .map_err(|error| SidecarCoreError::new(format!("snapshot overlay layer: {error}"))) - } else if let Some(VmLayer::Writable(filesystem)) = layers.layers.get_mut(layer_id) { - filesystem - .snapshot() - .map_err(|error| SidecarCoreError::new(format!("snapshot writable layer: {error}"))) - } else { - Err(SidecarCoreError::new(format!("unknown layer: {layer_id}"))) - }; - - active.remove(layer_id); - result -} - -fn dedupe_overlay_bootstrap_entries( - lowers: &[RootFilesystemSnapshot], - upper_entries: Vec, -) -> Vec { - let mut lower_paths = lowers - .iter() - .flat_map(|snapshot| snapshot.entries.iter().map(|entry| entry.path.clone())) - .collect::>(); - - upper_entries - .into_iter() - .filter(|entry| { - if lower_paths.contains(&entry.path) - && matches!(entry.kind, FilesystemEntryKind::Directory) - { - return false; - } - lower_paths.insert(entry.path.clone()); - true - }) - .collect() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn imports_exports_and_overlays_snapshots() { - let mut layers = VmLayerStore::default(); - let lower = layers - .import_snapshot(RootFilesystemSnapshot { - entries: vec![FilesystemEntry::file("/value.txt", b"lower".to_vec())], - }) - .expect("import lower"); - let upper = layers - .import_snapshot(RootFilesystemSnapshot { - entries: vec![FilesystemEntry::file("/extra.txt", b"upper".to_vec())], - }) - .expect("import upper"); - let overlay = layers - .create_overlay_layer( - KernelRootFilesystemMode::Ephemeral, - Some(upper), - vec![lower], - ) - .expect("create overlay"); - - let snapshot = layers.export_snapshot(&overlay).expect("export overlay"); - assert!(snapshot - .entries - .iter() - .any(|entry| entry.path == "/value.txt")); - assert!(snapshot - .entries - .iter() - .any(|entry| entry.path == "/extra.txt")); - } - - #[test] - fn sealing_non_writable_layer_is_rejected() { - let mut layers = VmLayerStore::default(); - let layer = layers - .import_snapshot(RootFilesystemSnapshot { - entries: Vec::new(), - }) - .expect("import snapshot"); - - let error = layers - .seal_layer(&layer) - .expect_err("snapshot layer should not seal"); - assert!(error.to_string().contains("is not writable")); - } -} diff --git a/crates/sidecar-core/src/lib.rs b/crates/sidecar-core/src/lib.rs index 929a33e18..201c7407d 100644 --- a/crates/sidecar-core/src/lib.rs +++ b/crates/sidecar-core/src/lib.rs @@ -1,98 +1,3 @@ -#![forbid(unsafe_code)] +//! Compatibility shim for `agentos-native-sidecar-core`. -//! Backend-agnostic sidecar logic shared by native and browser shells. - -pub mod bridge_bytes; -pub mod diagnostics; -pub mod frames; -pub mod guest_fs; -pub mod guest_net; -pub mod guest_pty; -pub mod identity; -pub mod layers; -pub mod limits; -pub mod net; -pub mod permissions; -pub mod root_fs; -pub mod router; -pub mod signals; -pub mod tools; -pub mod vm_fetch; - -pub use bridge_bytes::{ - bridge_buffer_value, decode_base64, decode_bridge_buffer_value, decode_encoded_bytes_value, - encoded_bytes_value, -}; -pub use diagnostics::{ - process_snapshot_entry_from_kernel, process_status_from_kernel, - protocol_process_snapshot_entry, SharedProcessSnapshotEntry, SharedProcessSnapshotStatus, -}; -pub use frames::{ - authenticated_response, bound_udp_snapshot_response, event, layer_created_response, - layer_sealed_response, listener_snapshot_response, overlay_created_response, - package_linked_response, process_exited_event, process_killed_response, process_output_event, - process_snapshot_response, process_started_response, provided_commands_response, reject, - respond, response_with_ownership, root_filesystem_bootstrapped_response, - root_filesystem_snapshot_response, session_opened_response, signal_state_response, - snapshot_exported_response, snapshot_imported_response, stdin_closed_response, - stdin_written_response, unsupported_guest_kernel_call_detail, - unsupported_guest_kernel_call_event, validate_authenticate_versions, vm_configured_response, - vm_created_response, vm_disposed_response, vm_lifecycle_event, zombie_timer_count_response, - AuthenticateVersionError, DispatchResult, UNSUPPORTED_GUEST_KERNEL_CALL_EVENT, -}; -pub use guest_fs::{ - decode_guest_filesystem_content, empty_guest_filesystem_response, - encode_guest_filesystem_content, guest_filesystem_stat, handle_guest_filesystem_call, - targeted_guest_filesystem_response, -}; -pub use guest_net::handle_guest_kernel_call; -pub use identity::{shared_guest_runtime_identity, SharedGuestRuntimeIdentity}; -pub use layers::{VmLayerStore, MAX_VM_LAYERS}; -pub use limits::{ - validate_vm_limits, virtual_os_cpu_count, virtual_os_freemem_bytes, virtual_os_totalmem_bytes, - vm_limits_from_config, AcpLimits, HttpLimits, JsRuntimeLimits, PluginLimits, PythonLimits, - ToolLimits, VmLimits, WasmLimits, -}; -pub use net::{ - local_endpoint_value, remote_endpoint_value, socket_addr_family, socket_address_value, - tcp_socket_info_value, unix_socket_info_value, -}; -pub use permissions::{ - allow_all_policy, deny_all_policy, environment_permission_capability, - evaluate_permissions_policy, filesystem_permission_capability, fs_permission_capability, - network_permission_capability, permission_mode_to_kernel_decision, permissions_from_policy, - validate_permissions_policy, -}; -pub use root_fs::{ - apply_root_filesystem_entry, build_root_filesystem, build_root_filesystem_with_loaded_snapshot, - build_root_mount_table, build_root_mount_table_with_loaded_snapshot, - convert_root_filesystem_entry, protocol_root_filesystem_mode, - root_filesystem_descriptor_from_config, root_filesystem_mode_from_config, - root_filesystem_protocol_descriptor_from_config, root_snapshot_entry, - root_snapshot_from_entries, SidecarCoreError, -}; -pub use router::{ - connection_id_of, generated_wire_blocking_extension_interrupt, request_dispatch_mode, - request_is_unsupported_host_callback_direction, route_request_payload, session_scope_of, - unsupported_host_callback_direction_dispatch, vm_id_of, BlockingExtensionInterrupt, - RequestDispatchMode, RequestRoute, UNSUPPORTED_HOST_CALLBACK_DIRECTION_CODE, - UNSUPPORTED_HOST_CALLBACK_DIRECTION_MESSAGE, -}; -pub use signals::{ - apply_process_signal_state_update, canonical_signal_name, default_signal_exit_code, - execution_signal_from_number, execution_signal_to_kernel, is_valid_posix_signal_number, - parse_posix_signal, parse_process_signal_state_request, signal_number_from_name, -}; -pub use tools::{ - ensure_command_aliases_available, ensure_toolkit_name_available, - ensure_toolkit_registry_capacity, registered_tool_command_names, validate_toolkit_registration, - ToolRegistrationError, DEFAULT_TOOL_TIMEOUT_MS, MAX_REGISTERED_TOOLKITS, - MAX_REGISTERED_TOOLS_PER_VM, MAX_TOOLKIT_NAME_LENGTH, MAX_TOOLS_PER_TOOLKIT, - MAX_TOOL_DESCRIPTION_LENGTH, MAX_TOOL_EXAMPLES_PER_TOOL, MAX_TOOL_EXAMPLE_INPUT_BYTES, - MAX_TOOL_NAME_LENGTH, MAX_TOOL_SCHEMA_BYTES, MAX_TOOL_SCHEMA_DEPTH, MAX_TOOL_TIMEOUT_MS, -}; -pub use vm_fetch::{ - ensure_vm_fetch_raw_response_buffer_within_limit, ensure_vm_fetch_response_within_limit, - parse_kernel_http_fetch_response, serialize_kernel_http_fetch_request, - VM_FETCH_BUFFER_LIMIT_BYTES, -}; +pub use agentos_native_sidecar_core::*; diff --git a/crates/sidecar-core/src/limits.rs b/crates/sidecar-core/src/limits.rs deleted file mode 100644 index b10bd3b02..000000000 --- a/crates/sidecar-core/src/limits.rs +++ /dev/null @@ -1,704 +0,0 @@ -//! Typed, operator-tunable VM-scoped runtime limits. -//! -//! `VmLimits` is the single home for runtime bounds that operators may tune through the typed -//! create-VM JSON config. Every field is a concrete value (not `Option`): the `Default` impls own -//! the numbers and they are byte-identical to the historical hardcoded constants, so behavior is -//! unchanged unless an operator overrides a config field. - -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_vm_config::{ResourceLimitsConfig, VmLimitsConfig}; - -use crate::SidecarCoreError; - -/// Default cap on `vm.fetch()` buffered response bodies. Historically aliased to the wire frame -/// cap; decoupled here but still validated to stay within the negotiated frame budget. -pub const DEFAULT_MAX_FETCH_RESPONSE_BYTES: usize = 1024 * 1024; - -pub const DEFAULT_TOOL_TIMEOUT_MS: u64 = 30_000; -pub const MAX_TOOL_TIMEOUT_MS: u64 = 300_000; -pub const MAX_REGISTERED_TOOLKITS: usize = 64; -pub const MAX_REGISTERED_TOOLS_PER_VM: usize = 256; -pub const MAX_TOOLS_PER_TOOLKIT: usize = 64; -pub const MAX_TOOL_SCHEMA_BYTES: usize = 16 * 1024; -pub const MAX_TOOL_EXAMPLES_PER_TOOL: usize = 16; -pub const MAX_TOOL_EXAMPLE_INPUT_BYTES: usize = 4 * 1024; - -pub const MAX_PERSISTED_MANIFEST_BYTES: usize = 64 * 1024 * 1024; -pub const MAX_PERSISTED_MANIFEST_FILE_BYTES: u64 = 1024 * 1024 * 1024; - -pub const DEFAULT_ACP_MAX_READ_LINE_BYTES: usize = 16 * 1024 * 1024; -pub const DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT: usize = 1024 * 1024; - -pub const DEFAULT_JS_CAPTURED_OUTPUT_LIMIT_BYTES: usize = 16 * 1024 * 1024; -pub const DEFAULT_JS_STDIN_BUFFER_LIMIT_BYTES: usize = 16 * 1024 * 1024; -pub const DEFAULT_JS_EVENT_PAYLOAD_LIMIT_BYTES: usize = 1024 * 1024; -pub const DEFAULT_V8_IPC_MAX_FRAME_BYTES: u32 = 64 * 1024 * 1024; -pub const DEFAULT_V8_HEAP_LIMIT_MB: u32 = 128; -pub const DEFAULT_V8_CPU_TIME_LIMIT_MS: u32 = 30_000; -pub const DEFAULT_V8_WALL_CLOCK_LIMIT_MS: u32 = 0; -pub const DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT_MS: u64 = 30_000; - -pub const DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES: usize = 1024 * 1024; -pub const DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS: u64 = 5 * 60 * 1000; -/// `0` keeps the Pyodide runner's V8 old-space at the engine default. -pub const DEFAULT_PYTHON_MAX_OLD_SPACE_MB: usize = 0; -pub const DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS: u64 = 30 * 1000; - -pub const DEFAULT_WASM_MAX_MODULE_FILE_BYTES: u64 = 256 * 1024 * 1024; -pub const DEFAULT_WASM_CAPTURED_OUTPUT_LIMIT_BYTES: usize = 16 * 1024 * 1024; -pub const DEFAULT_WASM_SYNC_READ_LIMIT_BYTES: usize = 16 * 1024 * 1024; -pub const DEFAULT_WASM_PREWARM_TIMEOUT_MS: u64 = 30_000; -pub const DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB: u32 = 2048; - -/// All operator-tunable VM-scoped limits. Fields are concrete values; the `Default` impls own the -/// numbers and equal today's hardcoded constants, so unset operator config leaves behavior -/// unchanged. -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct VmLimits { - /// Kernel resource limits (existing type, existing `resource.*` keys). - pub resources: ResourceLimits, - pub http: HttpLimits, - pub tools: ToolLimits, - pub plugins: PluginLimits, - pub acp: AcpLimits, - pub js_runtime: JsRuntimeLimits, - pub python: PythonLimits, - pub wasm: WasmLimits, -} - -pub fn virtual_os_cpu_count(resource_limits: &ResourceLimits) -> usize { - resource_limits.virtual_cpu_count.unwrap_or(1).max(1) -} - -pub fn virtual_os_totalmem_bytes(resource_limits: &ResourceLimits) -> u64 { - resource_limits - .max_wasm_memory_bytes - .unwrap_or(1024 * 1024 * 1024) -} - -pub fn virtual_os_freemem_bytes(resource_limits: &ResourceLimits) -> u64 { - resource_limits - .max_wasm_memory_bytes - .unwrap_or(512 * 1024 * 1024) -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct HttpLimits { - /// Cap on `vm.fetch()` buffered response bodies. Must be `<=` the sidecar wire frame cap. - pub max_fetch_response_bytes: usize, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ToolLimits { - pub default_tool_timeout_ms: u64, - pub max_tool_timeout_ms: u64, - pub max_registered_toolkits: usize, - pub max_registered_tools_per_vm: usize, - pub max_tools_per_toolkit: usize, - pub max_tool_schema_bytes: usize, - pub max_tool_examples_per_tool: usize, - pub max_tool_example_input_bytes: usize, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PluginLimits { - pub max_persisted_manifest_bytes: usize, - pub max_persisted_manifest_file_bytes: u64, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct AcpLimits { - /// Maximum length of a single ACP adapter stdout line. Threaded into `AcpClientOptions`. - pub max_read_line_bytes: usize, - /// Pre-session ACP adapter stdout buffer cap. - pub stdout_buffer_byte_limit: usize, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct JsRuntimeLimits { - /// `None` keeps the V8 engine default heap. Carried as the typed - /// `JavascriptExecutionLimits.v8_heap_limit_mb` on the execution request - /// (no longer the `AGENTOS_V8_HEAP_LIMIT_MB` env knob). - pub v8_heap_limit_mb: Option, - /// Sync-RPC blocking-wait ceiling in ms. `None` keeps the engine default. - pub sync_rpc_wait_timeout_ms: Option, - /// Active JavaScript CPU-time budget in ms. `0` disables the CPU watchdog. - pub cpu_time_limit_ms: u32, - /// JavaScript wall-clock backstop in ms. `0` disables the wall-clock watchdog. - pub wall_clock_limit_ms: u32, - /// Timeout for materializing the per-VM Node import cache. - pub import_cache_materialize_timeout_ms: u64, - pub captured_output_limit_bytes: usize, - pub stdin_buffer_limit_bytes: usize, - pub event_payload_limit_bytes: usize, - /// V8 IPC codec frame cap. Must feed both codec sides (`crates/execution/src/v8_ipc.rs` and - /// `crates/v8-runtime/src/ipc_binary.rs`). - pub v8_ipc_max_frame_bytes: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PythonLimits { - pub output_buffer_max_bytes: usize, - pub execution_timeout_ms: u64, - /// Pyodide V8 old-space cap in MB (`0` keeps the V8 default). - pub max_old_space_mb: usize, - pub vfs_rpc_timeout_ms: u64, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WasmLimits { - pub max_module_file_bytes: u64, - pub captured_output_limit_bytes: usize, - /// WASM sync read cap. Also templated into the JS runner shim, so it must flow from one field. - pub sync_read_limit_bytes: usize, - /// Best-effort warmup/compile-cache timeout. - pub prewarm_timeout_ms: u64, - /// V8 heap cap for the trusted JS runner isolate that hosts WASI/WASM. - pub runner_heap_limit_mb: u32, -} - -impl Default for HttpLimits { - fn default() -> Self { - Self { - max_fetch_response_bytes: DEFAULT_MAX_FETCH_RESPONSE_BYTES, - } - } -} - -impl Default for ToolLimits { - fn default() -> Self { - Self { - default_tool_timeout_ms: DEFAULT_TOOL_TIMEOUT_MS, - max_tool_timeout_ms: MAX_TOOL_TIMEOUT_MS, - max_registered_toolkits: MAX_REGISTERED_TOOLKITS, - max_registered_tools_per_vm: MAX_REGISTERED_TOOLS_PER_VM, - max_tools_per_toolkit: MAX_TOOLS_PER_TOOLKIT, - max_tool_schema_bytes: MAX_TOOL_SCHEMA_BYTES, - max_tool_examples_per_tool: MAX_TOOL_EXAMPLES_PER_TOOL, - max_tool_example_input_bytes: MAX_TOOL_EXAMPLE_INPUT_BYTES, - } - } -} - -impl Default for PluginLimits { - fn default() -> Self { - Self { - max_persisted_manifest_bytes: MAX_PERSISTED_MANIFEST_BYTES, - max_persisted_manifest_file_bytes: MAX_PERSISTED_MANIFEST_FILE_BYTES, - } - } -} - -impl Default for AcpLimits { - fn default() -> Self { - Self { - max_read_line_bytes: DEFAULT_ACP_MAX_READ_LINE_BYTES, - stdout_buffer_byte_limit: DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT, - } - } -} - -impl Default for JsRuntimeLimits { - fn default() -> Self { - Self { - // Workers-style 128 MiB heap cap by default. Operators can raise or - // clear this through trusted VM config when a VM needs more room. - v8_heap_limit_mb: Some(DEFAULT_V8_HEAP_LIMIT_MB), - sync_rpc_wait_timeout_ms: None, - cpu_time_limit_ms: DEFAULT_V8_CPU_TIME_LIMIT_MS, - wall_clock_limit_ms: DEFAULT_V8_WALL_CLOCK_LIMIT_MS, - import_cache_materialize_timeout_ms: DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT_MS, - captured_output_limit_bytes: DEFAULT_JS_CAPTURED_OUTPUT_LIMIT_BYTES, - stdin_buffer_limit_bytes: DEFAULT_JS_STDIN_BUFFER_LIMIT_BYTES, - event_payload_limit_bytes: DEFAULT_JS_EVENT_PAYLOAD_LIMIT_BYTES, - v8_ipc_max_frame_bytes: DEFAULT_V8_IPC_MAX_FRAME_BYTES, - } - } -} - -impl Default for PythonLimits { - fn default() -> Self { - Self { - output_buffer_max_bytes: DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES, - execution_timeout_ms: DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS, - max_old_space_mb: DEFAULT_PYTHON_MAX_OLD_SPACE_MB, - vfs_rpc_timeout_ms: DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS, - } - } -} - -impl Default for WasmLimits { - fn default() -> Self { - Self { - max_module_file_bytes: DEFAULT_WASM_MAX_MODULE_FILE_BYTES, - captured_output_limit_bytes: DEFAULT_WASM_CAPTURED_OUTPUT_LIMIT_BYTES, - sync_read_limit_bytes: DEFAULT_WASM_SYNC_READ_LIMIT_BYTES, - prewarm_timeout_ms: DEFAULT_WASM_PREWARM_TIMEOUT_MS, - runner_heap_limit_mb: DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB, - } - } -} - -pub fn vm_limits_from_config( - config: Option<&VmLimitsConfig>, - sidecar_max_frame_bytes: usize, -) -> Result { - let mut limits = VmLimits::default(); - let Some(config) = config else { - validate_vm_limits(&limits, sidecar_max_frame_bytes)?; - return Ok(limits); - }; - - if let Some(resources) = config.resources.as_ref() { - apply_resource_limits_config(&mut limits.resources, resources)?; - } - if let Some(http) = config.http.as_ref() { - set_usize( - &mut limits.http.max_fetch_response_bytes, - http.max_fetch_response_bytes, - "limits.http.maxFetchResponseBytes", - )?; - } - if let Some(tools) = config.tools.as_ref() { - set_u64( - &mut limits.tools.default_tool_timeout_ms, - tools.default_tool_timeout_ms, - "limits.tools.defaultToolTimeoutMs", - )?; - set_u64( - &mut limits.tools.max_tool_timeout_ms, - tools.max_tool_timeout_ms, - "limits.tools.maxToolTimeoutMs", - )?; - set_usize( - &mut limits.tools.max_registered_toolkits, - tools.max_registered_toolkits, - "limits.tools.maxRegisteredToolkits", - )?; - set_usize( - &mut limits.tools.max_registered_tools_per_vm, - tools.max_registered_tools_per_vm, - "limits.tools.maxRegisteredToolsPerVm", - )?; - set_usize( - &mut limits.tools.max_tools_per_toolkit, - tools.max_tools_per_toolkit, - "limits.tools.maxToolsPerToolkit", - )?; - set_usize( - &mut limits.tools.max_tool_schema_bytes, - tools.max_tool_schema_bytes, - "limits.tools.maxToolSchemaBytes", - )?; - set_usize( - &mut limits.tools.max_tool_examples_per_tool, - tools.max_tool_examples_per_tool, - "limits.tools.maxToolExamplesPerTool", - )?; - set_usize( - &mut limits.tools.max_tool_example_input_bytes, - tools.max_tool_example_input_bytes, - "limits.tools.maxToolExampleInputBytes", - )?; - } - if let Some(plugins) = config.plugins.as_ref() { - set_usize( - &mut limits.plugins.max_persisted_manifest_bytes, - plugins.max_persisted_manifest_bytes, - "limits.plugins.maxPersistedManifestBytes", - )?; - set_u64( - &mut limits.plugins.max_persisted_manifest_file_bytes, - plugins.max_persisted_manifest_file_bytes, - "limits.plugins.maxPersistedManifestFileBytes", - )?; - } - if let Some(acp) = config.acp.as_ref() { - set_usize( - &mut limits.acp.max_read_line_bytes, - acp.max_read_line_bytes, - "limits.acp.maxReadLineBytes", - )?; - set_usize( - &mut limits.acp.stdout_buffer_byte_limit, - acp.stdout_buffer_byte_limit, - "limits.acp.stdoutBufferByteLimit", - )?; - } - if let Some(js_runtime) = config.js_runtime.as_ref() { - if let Some(value) = js_runtime.v8_heap_limit_mb { - limits.js_runtime.v8_heap_limit_mb = Some( - u32::try_from(value) - .map_err(|_| integer_too_large("limits.jsRuntime.v8HeapLimitMb", value))?, - ); - } - if let Some(value) = js_runtime.cpu_time_limit_ms { - limits.js_runtime.cpu_time_limit_ms = u32::try_from(value) - .map_err(|_| integer_too_large("limits.jsRuntime.cpuTimeLimitMs", value))?; - } - if let Some(value) = js_runtime.wall_clock_limit_ms { - limits.js_runtime.wall_clock_limit_ms = u32::try_from(value) - .map_err(|_| integer_too_large("limits.jsRuntime.wallClockLimitMs", value))?; - } - set_u64( - &mut limits.js_runtime.import_cache_materialize_timeout_ms, - js_runtime.import_cache_materialize_timeout_ms, - "limits.jsRuntime.importCacheMaterializeTimeoutMs", - )?; - set_usize( - &mut limits.js_runtime.captured_output_limit_bytes, - js_runtime.captured_output_limit_bytes, - "limits.jsRuntime.capturedOutputLimitBytes", - )?; - set_usize( - &mut limits.js_runtime.stdin_buffer_limit_bytes, - js_runtime.stdin_buffer_limit_bytes, - "limits.jsRuntime.stdinBufferLimitBytes", - )?; - set_usize( - &mut limits.js_runtime.event_payload_limit_bytes, - js_runtime.event_payload_limit_bytes, - "limits.jsRuntime.eventPayloadLimitBytes", - )?; - if let Some(value) = js_runtime.v8_ipc_max_frame_bytes { - limits.js_runtime.v8_ipc_max_frame_bytes = u32::try_from(value) - .map_err(|_| integer_too_large("limits.jsRuntime.v8IpcMaxFrameBytes", value))?; - } - if let Some(value) = js_runtime.sync_rpc_wait_timeout_ms { - limits.js_runtime.sync_rpc_wait_timeout_ms = Some(value); - } - } - if let Some(python) = config.python.as_ref() { - set_usize( - &mut limits.python.output_buffer_max_bytes, - python.output_buffer_max_bytes, - "limits.python.outputBufferMaxBytes", - )?; - set_u64( - &mut limits.python.execution_timeout_ms, - python.execution_timeout_ms, - "limits.python.executionTimeoutMs", - )?; - set_usize( - &mut limits.python.max_old_space_mb, - python.max_old_space_mb, - "limits.python.maxOldSpaceMb", - )?; - set_u64( - &mut limits.python.vfs_rpc_timeout_ms, - python.vfs_rpc_timeout_ms, - "limits.python.vfsRpcTimeoutMs", - )?; - } - if let Some(wasm) = config.wasm.as_ref() { - set_u64( - &mut limits.wasm.max_module_file_bytes, - wasm.max_module_file_bytes, - "limits.wasm.maxModuleFileBytes", - )?; - set_usize( - &mut limits.wasm.captured_output_limit_bytes, - wasm.captured_output_limit_bytes, - "limits.wasm.capturedOutputLimitBytes", - )?; - set_usize( - &mut limits.wasm.sync_read_limit_bytes, - wasm.sync_read_limit_bytes, - "limits.wasm.syncReadLimitBytes", - )?; - set_u64( - &mut limits.wasm.prewarm_timeout_ms, - wasm.prewarm_timeout_ms, - "limits.wasm.prewarmTimeoutMs", - )?; - if let Some(value) = wasm.runner_heap_limit_mb { - limits.wasm.runner_heap_limit_mb = u32::try_from(value) - .map_err(|_| integer_too_large("limits.wasm.runnerHeapLimitMb", value))?; - } - } - - validate_vm_limits(&limits, sidecar_max_frame_bytes)?; - Ok(limits) -} - -fn apply_resource_limits_config( - limits: &mut ResourceLimits, - config: &ResourceLimitsConfig, -) -> Result<(), SidecarCoreError> { - set_optional_usize( - &mut limits.virtual_cpu_count, - config.cpu_count, - "limits.resources.cpuCount", - )?; - set_optional_usize( - &mut limits.max_processes, - config.max_processes, - "limits.resources.maxProcesses", - )?; - set_optional_usize( - &mut limits.max_open_fds, - config.max_open_fds, - "limits.resources.maxOpenFds", - )?; - set_optional_usize( - &mut limits.max_pipes, - config.max_pipes, - "limits.resources.maxPipes", - )?; - set_optional_usize( - &mut limits.max_ptys, - config.max_ptys, - "limits.resources.maxPtys", - )?; - set_optional_usize( - &mut limits.max_sockets, - config.max_sockets, - "limits.resources.maxSockets", - )?; - set_optional_usize( - &mut limits.max_connections, - config.max_connections, - "limits.resources.maxConnections", - )?; - set_optional_usize( - &mut limits.max_socket_buffered_bytes, - config.max_socket_buffered_bytes, - "limits.resources.maxSocketBufferedBytes", - )?; - set_optional_usize( - &mut limits.max_socket_datagram_queue_len, - config.max_socket_datagram_queue_len, - "limits.resources.maxSocketDatagramQueueLen", - )?; - set_optional_u64( - &mut limits.max_filesystem_bytes, - config.max_filesystem_bytes, - ); - set_optional_usize( - &mut limits.max_inode_count, - config.max_inode_count, - "limits.resources.maxInodeCount", - )?; - set_optional_u64( - &mut limits.max_blocking_read_ms, - config.max_blocking_read_ms, - ); - set_optional_usize( - &mut limits.max_pread_bytes, - config.max_pread_bytes, - "limits.resources.maxPreadBytes", - )?; - set_optional_usize( - &mut limits.max_fd_write_bytes, - config.max_fd_write_bytes, - "limits.resources.maxFdWriteBytes", - )?; - set_optional_usize( - &mut limits.max_process_argv_bytes, - config.max_process_argv_bytes, - "limits.resources.maxProcessArgvBytes", - )?; - set_optional_usize( - &mut limits.max_process_env_bytes, - config.max_process_env_bytes, - "limits.resources.maxProcessEnvBytes", - )?; - set_optional_usize( - &mut limits.max_readdir_entries, - config.max_readdir_entries, - "limits.resources.maxReaddirEntries", - )?; - set_optional_usize( - &mut limits.max_recursive_fs_depth, - config.max_recursive_fs_depth, - "limits.resources.maxRecursiveFsDepth", - )?; - set_optional_usize( - &mut limits.max_recursive_fs_entries, - config.max_recursive_fs_entries, - "limits.resources.maxRecursiveFsEntries", - )?; - set_optional_u64(&mut limits.max_wasm_fuel, config.max_wasm_fuel); - set_optional_u64( - &mut limits.max_wasm_memory_bytes, - config.max_wasm_memory_bytes, - ); - set_optional_usize( - &mut limits.max_wasm_stack_bytes, - config.max_wasm_stack_bytes, - "limits.resources.maxWasmStackBytes", - )?; - Ok(()) -} - -fn set_usize(target: &mut usize, value: Option, key: &str) -> Result<(), SidecarCoreError> { - if let Some(value) = value { - *target = usize::try_from(value).map_err(|_| integer_too_large(key, value))?; - } - Ok(()) -} - -fn set_u64(target: &mut u64, value: Option, _key: &str) -> Result<(), SidecarCoreError> { - if let Some(value) = value { - *target = value; - } - Ok(()) -} - -fn set_optional_usize( - target: &mut Option, - value: Option, - key: &str, -) -> Result<(), SidecarCoreError> { - if let Some(value) = value { - *target = Some(usize::try_from(value).map_err(|_| integer_too_large(key, value))?); - } - Ok(()) -} - -fn set_optional_u64(target: &mut Option, value: Option) { - if let Some(value) = value { - *target = Some(value); - } -} - -fn integer_too_large(key: &str, value: u64) -> SidecarCoreError { - SidecarCoreError::new(format!("{key} value {value} does not fit this platform")) -} - -/// Cross-field validation. Fail-by-default: reject any configuration that would deadlock or -/// violate the wire frame budget with an explicit, actionable message. -pub fn validate_vm_limits( - limits: &VmLimits, - sidecar_max_frame_bytes: usize, -) -> Result<(), SidecarCoreError> { - if limits.http.max_fetch_response_bytes == 0 { - return Err(SidecarCoreError::new( - "limits.http.max_fetch_response_bytes must be greater than zero".to_string(), - )); - } - if limits.http.max_fetch_response_bytes > sidecar_max_frame_bytes { - return Err(SidecarCoreError::new(format!( - "limits.http.max_fetch_response_bytes ({}) must be <= the sidecar wire frame cap ({})", - limits.http.max_fetch_response_bytes, sidecar_max_frame_bytes - ))); - } - - if limits.tools.default_tool_timeout_ms > limits.tools.max_tool_timeout_ms { - return Err(SidecarCoreError::new(format!( - "limits.tools.default_tool_timeout_ms ({}) must be <= limits.tools.max_tool_timeout_ms ({})", - limits.tools.default_tool_timeout_ms, limits.tools.max_tool_timeout_ms - ))); - } - - let nonzero_usize: [(&str, usize); 13] = [ - ( - "limits.tools.max_registered_toolkits", - limits.tools.max_registered_toolkits, - ), - ( - "limits.tools.max_registered_tools_per_vm", - limits.tools.max_registered_tools_per_vm, - ), - ( - "limits.tools.max_tools_per_toolkit", - limits.tools.max_tools_per_toolkit, - ), - ( - "limits.tools.max_tool_schema_bytes", - limits.tools.max_tool_schema_bytes, - ), - ( - "limits.tools.max_tool_example_input_bytes", - limits.tools.max_tool_example_input_bytes, - ), - ( - "limits.plugins.max_persisted_manifest_bytes", - limits.plugins.max_persisted_manifest_bytes, - ), - ( - "limits.acp.max_read_line_bytes", - limits.acp.max_read_line_bytes, - ), - ( - "limits.acp.stdout_buffer_byte_limit", - limits.acp.stdout_buffer_byte_limit, - ), - ( - "limits.js_runtime.captured_output_limit_bytes", - limits.js_runtime.captured_output_limit_bytes, - ), - ( - "limits.js_runtime.stdin_buffer_limit_bytes", - limits.js_runtime.stdin_buffer_limit_bytes, - ), - ( - "limits.js_runtime.event_payload_limit_bytes", - limits.js_runtime.event_payload_limit_bytes, - ), - ( - "limits.python.output_buffer_max_bytes", - limits.python.output_buffer_max_bytes, - ), - ( - "limits.wasm.captured_output_limit_bytes", - limits.wasm.captured_output_limit_bytes, - ), - ]; - for (key, value) in nonzero_usize { - if value == 0 { - return Err(SidecarCoreError::new(format!( - "{key} must be greater than zero" - ))); - } - } - - if limits.wasm.sync_read_limit_bytes == 0 { - return Err(SidecarCoreError::new( - "limits.wasm.sync_read_limit_bytes must be greater than zero".to_string(), - )); - } - if limits.wasm.prewarm_timeout_ms == 0 { - return Err(SidecarCoreError::new( - "limits.wasm.prewarm_timeout_ms must be greater than zero".to_string(), - )); - } - if limits.wasm.runner_heap_limit_mb == 0 { - return Err(SidecarCoreError::new( - "limits.wasm.runner_heap_limit_mb must be greater than zero".to_string(), - )); - } - if limits.wasm.max_module_file_bytes == 0 { - return Err(SidecarCoreError::new( - "limits.wasm.max_module_file_bytes must be greater than zero".to_string(), - )); - } - if limits.js_runtime.v8_ipc_max_frame_bytes == 0 { - return Err(SidecarCoreError::new( - "limits.js_runtime.v8_ipc_max_frame_bytes must be greater than zero".to_string(), - )); - } - if limits.python.execution_timeout_ms == 0 { - return Err(SidecarCoreError::new( - "limits.python.execution_timeout_ms must be greater than zero".to_string(), - )); - } - if limits.python.vfs_rpc_timeout_ms == 0 { - return Err(SidecarCoreError::new( - "limits.python.vfs_rpc_timeout_ms must be greater than zero".to_string(), - )); - } - if let Some(0) = limits.js_runtime.v8_heap_limit_mb { - return Err(SidecarCoreError::new( - "limits.js_runtime.v8_heap_limit_mb must be greater than zero".to_string(), - )); - } - if limits.js_runtime.import_cache_materialize_timeout_ms == 0 { - return Err(SidecarCoreError::new( - "limits.js_runtime.import_cache_materialize_timeout_ms must be greater than zero" - .to_string(), - )); - } - - Ok(()) -} diff --git a/crates/sidecar-core/src/net.rs b/crates/sidecar-core/src/net.rs deleted file mode 100644 index 9eb626a4a..000000000 --- a/crates/sidecar-core/src/net.rs +++ /dev/null @@ -1,98 +0,0 @@ -use serde_json::{json, Value}; -use std::net::SocketAddr; - -pub fn socket_addr_family(addr: &SocketAddr) -> &'static str { - match addr { - SocketAddr::V4(_) => "IPv4", - SocketAddr::V6(_) => "IPv6", - } -} - -pub fn socket_address_value(addr: &SocketAddr) -> Value { - json!({ - "address": addr.ip().to_string(), - "family": socket_addr_family(addr), - "port": addr.port(), - }) -} - -pub fn local_endpoint_value(addr: &SocketAddr) -> Value { - json!({ - "localAddress": addr.ip().to_string(), - "localPort": addr.port(), - "family": socket_addr_family(addr), - }) -} - -pub fn remote_endpoint_value(addr: &SocketAddr, port: u16) -> Value { - json!({ - "remoteAddress": addr.ip().to_string(), - "remotePort": port, - "remoteFamily": socket_addr_family(addr), - }) -} - -pub fn tcp_socket_info_value(local: &SocketAddr, remote: &SocketAddr) -> Value { - json!({ - "localAddress": local.ip().to_string(), - "localPort": local.port(), - "localFamily": socket_addr_family(local), - "remoteAddress": remote.ip().to_string(), - "remotePort": remote.port(), - "remoteFamily": socket_addr_family(remote), - }) -} - -pub fn unix_socket_info_value(local_path: Option<&str>, remote_path: Option<&str>) -> Value { - json!({ - "localPath": local_path, - "remotePath": remote_path, - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - - #[test] - fn formats_socket_families() { - assert_eq!( - socket_addr_family(&SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 1)), - "IPv4" - ); - assert_eq!( - socket_addr_family(&SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 1)), - "IPv6" - ); - } - - #[test] - fn formats_tcp_socket_info() { - let local = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 1234); - let remote = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 80); - - assert_eq!( - tcp_socket_info_value(&local, &remote), - json!({ - "localAddress": "127.0.0.1", - "localPort": 1234, - "localFamily": "IPv4", - "remoteAddress": "10.0.0.1", - "remotePort": 80, - "remoteFamily": "IPv4", - }) - ); - } - - #[test] - fn formats_unix_socket_info() { - assert_eq!( - unix_socket_info_value(Some("/tmp/server.sock"), Some("/tmp/client.sock")), - json!({ - "localPath": "/tmp/server.sock", - "remotePath": "/tmp/client.sock", - }) - ); - } -} diff --git a/crates/sidecar-core/src/permissions.rs b/crates/sidecar-core/src/permissions.rs deleted file mode 100644 index 6413106b2..000000000 --- a/crates/sidecar-core/src/permissions.rs +++ /dev/null @@ -1,636 +0,0 @@ -use crate::root_fs::SidecarCoreError; -use secure_exec_bridge::FilesystemAccess; -use secure_exec_kernel::permissions::{ - permission_glob_matches, CommandAccessRequest, EnvAccessRequest, EnvironmentOperation, - FsAccessRequest, FsOperation, NetworkAccessRequest, NetworkOperation, PermissionDecision, - Permissions, -}; -use secure_exec_vm_config as vm_config; -use std::sync::Arc; - -pub fn deny_all_policy() -> vm_config::PermissionsPolicy { - vm_config::PermissionsPolicy { - fs: Some(vm_config::FsPermissionScope::Mode( - vm_config::PermissionMode::Deny, - )), - network: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Deny, - )), - child_process: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Deny, - )), - process: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Deny, - )), - env: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Deny, - )), - binding: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Deny, - )), - } -} - -pub fn allow_all_policy() -> vm_config::PermissionsPolicy { - vm_config::PermissionsPolicy { - fs: Some(vm_config::FsPermissionScope::Mode( - vm_config::PermissionMode::Allow, - )), - network: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Allow, - )), - child_process: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Allow, - )), - process: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Allow, - )), - env: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Allow, - )), - binding: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Allow, - )), - } -} - -pub fn evaluate_permissions_policy( - permissions: &vm_config::PermissionsPolicy, - domain: &str, - capability: &str, - resource: Option<&str>, -) -> vm_config::PermissionMode { - match domain { - "fs" => evaluate_fs_permission_scope( - permissions.fs.as_ref(), - capability_operation(capability, domain), - resource, - ), - "network" => evaluate_pattern_permission_scope( - permissions.network.as_ref(), - capability_operation(capability, domain), - resource, - ), - "child_process" => evaluate_pattern_permission_scope( - permissions.child_process.as_ref(), - capability_operation(capability, domain), - resource, - ), - "process" => evaluate_pattern_permission_scope( - permissions.process.as_ref(), - capability_operation(capability, domain), - resource, - ), - "env" => evaluate_pattern_permission_scope( - permissions.env.as_ref(), - capability_operation(capability, domain), - resource, - ), - "binding" => evaluate_pattern_permission_scope( - permissions.binding.as_ref(), - capability_operation(capability, domain), - resource, - ), - _ => vm_config::PermissionMode::Deny, - } -} - -fn evaluate_fs_permission_scope( - scope: Option<&vm_config::FsPermissionScope>, - operation: &str, - resource: Option<&str>, -) -> vm_config::PermissionMode { - match scope { - Some(vm_config::FsPermissionScope::Mode(mode)) => *mode, - Some(vm_config::FsPermissionScope::Rules(rules)) => { - let mut mode = rules.default.unwrap_or(vm_config::PermissionMode::Deny); - for rule in &rules.rules { - if fs_rule_matches(rule, operation, resource) { - mode = rule.mode; - } - } - mode - } - None => vm_config::PermissionMode::Deny, - } -} - -fn evaluate_pattern_permission_scope( - scope: Option<&vm_config::PatternPermissionScope>, - operation: &str, - resource: Option<&str>, -) -> vm_config::PermissionMode { - match scope { - Some(vm_config::PatternPermissionScope::Mode(mode)) => *mode, - Some(vm_config::PatternPermissionScope::Rules(rules)) => { - let mut mode = rules.default.unwrap_or(vm_config::PermissionMode::Deny); - for rule in &rules.rules { - if pattern_rule_matches(rule, operation, resource) { - mode = rule.mode; - } - } - mode - } - None => vm_config::PermissionMode::Deny, - } -} - -fn fs_rule_matches( - rule: &vm_config::FsPermissionRule, - operation: &str, - resource: Option<&str>, -) -> bool { - let operations_match = permission_operation_matches(&rule.operations, operation); - let paths_match = permission_resource_matches(&rule.paths, resource); - operations_match && paths_match -} - -fn pattern_rule_matches( - rule: &vm_config::PatternPermissionRule, - operation: &str, - resource: Option<&str>, -) -> bool { - let operations_match = permission_operation_matches(&rule.operations, operation); - let patterns_match = permission_resource_matches(&rule.patterns, resource); - operations_match && patterns_match -} - -fn permission_operation_matches(candidates: &[String], operation: &str) -> bool { - candidates - .iter() - .any(|candidate| candidate == "*" || candidate == operation) -} - -fn permission_resource_matches(patterns: &[String], resource: Option<&str>) -> bool { - resource.is_some_and(|value| { - patterns - .iter() - .any(|pattern| permission_glob_matches(pattern, value)) - }) -} - -pub fn validate_permissions_policy( - permissions: &vm_config::PermissionsPolicy, -) -> Result<(), SidecarCoreError> { - if let Some(scope) = permissions.fs.as_ref() { - validate_fs_permission_scope("fs", scope)?; - } - if let Some(scope) = permissions.network.as_ref() { - validate_pattern_permission_scope("network", scope)?; - } - if let Some(scope) = permissions.child_process.as_ref() { - validate_pattern_permission_scope("child_process", scope)?; - } - if let Some(scope) = permissions.process.as_ref() { - validate_pattern_permission_scope("process", scope)?; - } - if let Some(scope) = permissions.env.as_ref() { - validate_pattern_permission_scope("env", scope)?; - } - if let Some(scope) = permissions.binding.as_ref() { - validate_pattern_permission_scope("binding", scope)?; - } - Ok(()) -} - -fn validate_fs_permission_scope( - domain: &str, - scope: &vm_config::FsPermissionScope, -) -> Result<(), SidecarCoreError> { - let vm_config::FsPermissionScope::Rules(rule_set) = scope else { - return Ok(()); - }; - - for (index, rule) in rule_set.rules.iter().enumerate() { - validate_permission_rule_field( - &rule.operations, - &format!("{domain}.rules[{index}].operations"), - )?; - validate_permission_rule_field(&rule.paths, &format!("{domain}.rules[{index}].paths"))?; - } - - Ok(()) -} - -fn validate_pattern_permission_scope( - domain: &str, - scope: &vm_config::PatternPermissionScope, -) -> Result<(), SidecarCoreError> { - let vm_config::PatternPermissionScope::Rules(rule_set) = scope else { - return Ok(()); - }; - - for (index, rule) in rule_set.rules.iter().enumerate() { - validate_permission_rule_field( - &rule.operations, - &format!("{domain}.rules[{index}].operations"), - )?; - validate_permission_rule_field( - &rule.patterns, - &format!("{domain}.rules[{index}].patterns"), - )?; - } - - Ok(()) -} - -fn validate_permission_rule_field(values: &[String], field: &str) -> Result<(), SidecarCoreError> { - if values.is_empty() { - return Err(SidecarCoreError::new(format!( - "invalid permissions policy: {field} must not be empty; use [\"*\"] for wildcard" - ))); - } - Ok(()) -} - -fn capability_operation<'a>(capability: &'a str, domain: &str) -> &'a str { - capability - .strip_prefix(domain) - .and_then(|value| value.strip_prefix('.')) - .unwrap_or("") -} - -pub fn permission_mode_to_kernel_decision( - mode: vm_config::PermissionMode, - capability: &str, -) -> PermissionDecision { - match mode { - vm_config::PermissionMode::Allow => PermissionDecision::allow(), - vm_config::PermissionMode::Ask => { - PermissionDecision::deny(format!("permission prompt required for {capability}")) - } - vm_config::PermissionMode::Deny => { - PermissionDecision::deny(format!("blocked by {capability} policy")) - } - } -} - -pub fn permissions_from_policy(policy: vm_config::PermissionsPolicy) -> Permissions { - let fs_policy = Arc::new(policy.clone()); - let network_policy = Arc::new(policy.clone()); - let child_process_policy = Arc::new(policy.clone()); - let env_policy = Arc::new(policy); - - Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - let capability = fs_permission_capability(request.op); - permission_mode_to_kernel_decision( - evaluate_permissions_policy(&fs_policy, "fs", capability, Some(&request.path)), - capability, - ) - })), - network: Some(Arc::new(move |request: &NetworkAccessRequest| { - let capability = network_permission_capability(request.op); - permission_mode_to_kernel_decision( - evaluate_permissions_policy( - &network_policy, - "network", - capability, - Some(&request.resource), - ), - capability, - ) - })), - child_process: Some(Arc::new(move |request: &CommandAccessRequest| { - let capability = "child_process.spawn"; - permission_mode_to_kernel_decision( - evaluate_permissions_policy( - &child_process_policy, - "child_process", - capability, - Some(&request.command), - ), - capability, - ) - })), - environment: Some(Arc::new(move |request: &EnvAccessRequest| { - let capability = environment_permission_capability(request.op); - permission_mode_to_kernel_decision( - evaluate_permissions_policy(&env_policy, "env", capability, Some(&request.key)), - capability, - ) - })), - } -} - -pub fn fs_permission_capability(operation: FsOperation) -> &'static str { - match operation { - FsOperation::Read => filesystem_permission_capability(FilesystemAccess::Read), - FsOperation::Write => filesystem_permission_capability(FilesystemAccess::Write), - FsOperation::Mkdir | FsOperation::CreateDir => { - filesystem_permission_capability(FilesystemAccess::CreateDir) - } - FsOperation::ReadDir => filesystem_permission_capability(FilesystemAccess::ReadDir), - FsOperation::Stat | FsOperation::Exists => { - filesystem_permission_capability(FilesystemAccess::Stat) - } - FsOperation::Remove => filesystem_permission_capability(FilesystemAccess::Remove), - FsOperation::Rename => filesystem_permission_capability(FilesystemAccess::Rename), - FsOperation::Symlink => filesystem_permission_capability(FilesystemAccess::Symlink), - FsOperation::ReadLink => filesystem_permission_capability(FilesystemAccess::ReadLink), - FsOperation::Link | FsOperation::Chmod | FsOperation::Chown | FsOperation::Utimes => { - filesystem_permission_capability(FilesystemAccess::Write) - } - FsOperation::Truncate => filesystem_permission_capability(FilesystemAccess::Truncate), - FsOperation::MountSensitive => "fs.mount_sensitive", - } -} - -pub fn filesystem_permission_capability(access: FilesystemAccess) -> &'static str { - match access { - FilesystemAccess::Read => "fs.read", - FilesystemAccess::Write => "fs.write", - FilesystemAccess::Stat => "fs.stat", - FilesystemAccess::ReadDir => "fs.readdir", - FilesystemAccess::CreateDir => "fs.create_dir", - FilesystemAccess::Remove => "fs.rm", - FilesystemAccess::Rename => "fs.rename", - FilesystemAccess::Symlink => "fs.symlink", - FilesystemAccess::ReadLink => "fs.readlink", - FilesystemAccess::Chmod => "fs.chmod", - FilesystemAccess::Truncate => "fs.truncate", - } -} - -pub fn network_permission_capability(operation: NetworkOperation) -> &'static str { - match operation { - NetworkOperation::Fetch => "network.fetch", - NetworkOperation::Http => "network.http", - NetworkOperation::Dns => "network.dns", - NetworkOperation::Listen => "network.listen", - } -} - -pub fn environment_permission_capability(operation: EnvironmentOperation) -> &'static str { - match operation { - EnvironmentOperation::Read => "env.read", - EnvironmentOperation::Write => "env.write", - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn permissions_default_to_deny() { - let policy = vm_config::PermissionsPolicy { - fs: None, - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }; - - assert_eq!( - evaluate_permissions_policy(&policy, "fs", "fs.read", Some("/tmp/a")), - vm_config::PermissionMode::Deny - ); - } - - #[test] - fn permissions_default_to_deny_for_every_domain() { - let policy = vm_config::PermissionsPolicy { - fs: None, - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }; - - for (domain, capability, resource) in [ - ("fs", "fs.read", "/workspace/file.txt"), - ("network", "network.http", "example.com:443"), - ("child_process", "child_process.spawn", "sh"), - ("process", "process.kill", "123"), - ("env", "env.read", "TOKEN"), - ("binding", "binding.call", "shell"), - ] { - assert_eq!( - evaluate_permissions_policy(&policy, domain, capability, Some(resource)), - vm_config::PermissionMode::Deny, - "{domain} should default to deny", - ); - } - } - - #[test] - fn ask_permission_modes_become_kernel_denials() { - let decision = - permission_mode_to_kernel_decision(vm_config::PermissionMode::Ask, "network.http"); - - assert!(!decision.allow); - assert_eq!( - decision.reason.as_deref(), - Some("permission prompt required for network.http") - ); - } - - #[test] - fn ask_permission_modes_deny_every_policy_domain() { - let policy = vm_config::PermissionsPolicy { - fs: Some(vm_config::FsPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - network: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - child_process: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - process: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - env: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - binding: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - }; - - for (domain, capability, resource) in [ - ("fs", "fs.read", "/workspace/file.txt"), - ("network", "network.http", "example.com:443"), - ("child_process", "child_process.spawn", "sh"), - ("process", "process.kill", "123"), - ("env", "env.read", "TOKEN"), - ("binding", "binding.call", "shell"), - ] { - let mode = evaluate_permissions_policy(&policy, domain, capability, Some(resource)); - assert_eq!( - mode, - vm_config::PermissionMode::Ask, - "{domain} should preserve Ask until kernel-decision mapping", - ); - let decision = permission_mode_to_kernel_decision(mode, capability); - assert!( - !decision.allow, - "{domain} Ask should map to a kernel denial", - ); - assert_eq!( - decision.reason.as_deref(), - Some(format!("permission prompt required for {capability}").as_str()), - "{domain} Ask denial should explain the denied prompt", - ); - } - } - - #[test] - fn ask_permission_modes_deny_every_kernel_callback_domain() { - let permissions = permissions_from_policy(vm_config::PermissionsPolicy { - fs: Some(vm_config::FsPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - network: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - child_process: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - process: None, - env: Some(vm_config::PatternPermissionScope::Mode( - vm_config::PermissionMode::Ask, - )), - binding: None, - }); - - assert!( - !permissions.filesystem.expect("filesystem callback")(&FsAccessRequest { - vm_id: String::from("vm"), - op: FsOperation::Read, - path: String::from("/workspace/file.txt"), - }) - .allow - ); - assert!( - !permissions.network.expect("network callback")(&NetworkAccessRequest { - vm_id: String::from("vm"), - op: NetworkOperation::Http, - resource: String::from("example.com:443"), - }) - .allow - ); - assert!( - !permissions.child_process.expect("child_process callback")(&CommandAccessRequest { - vm_id: String::from("vm"), - command: String::from("sh"), - args: Vec::new(), - cwd: None, - env: Default::default(), - }) - .allow - ); - assert!( - !permissions.environment.expect("environment callback")(&EnvAccessRequest { - vm_id: String::from("vm"), - op: EnvironmentOperation::Read, - key: String::from("TOKEN"), - value: None, - }) - .allow - ); - } - - #[test] - fn permissions_from_policy_builds_kernel_callbacks() { - let policy = vm_config::PermissionsPolicy { - fs: Some(vm_config::FsPermissionScope::Rules( - vm_config::FsPermissionRuleSet { - default: Some(vm_config::PermissionMode::Deny), - rules: vec![vm_config::FsPermissionRule { - mode: vm_config::PermissionMode::Allow, - operations: vec![String::from("read")], - paths: vec![String::from("/workspace/**")], - }], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }; - - let permissions = permissions_from_policy(policy); - let check = permissions.filesystem.expect("filesystem callback"); - - assert!( - check(&FsAccessRequest { - vm_id: String::from("vm"), - op: FsOperation::Read, - path: String::from("/workspace/file.txt"), - }) - .allow - ); - assert!( - !check(&FsAccessRequest { - vm_id: String::from("vm"), - op: FsOperation::Read, - path: String::from("/secrets/file.txt"), - }) - .allow - ); - } - - #[test] - fn last_matching_rule_wins() { - let policy = vm_config::PermissionsPolicy { - fs: Some(vm_config::FsPermissionScope::Rules( - vm_config::FsPermissionRuleSet { - default: Some(vm_config::PermissionMode::Deny), - rules: vec![ - vm_config::FsPermissionRule { - mode: vm_config::PermissionMode::Allow, - operations: vec![String::from("read")], - paths: vec![String::from("/workspace/**")], - }, - vm_config::FsPermissionRule { - mode: vm_config::PermissionMode::Deny, - operations: vec![String::from("read")], - paths: vec![String::from("/workspace/secrets/**")], - }, - ], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }; - - assert_eq!( - evaluate_permissions_policy(&policy, "fs", "fs.read", Some("/workspace/secrets/key")), - vm_config::PermissionMode::Deny - ); - } - - #[test] - fn empty_rule_fields_are_rejected() { - let policy = vm_config::PermissionsPolicy { - fs: Some(vm_config::FsPermissionScope::Rules( - vm_config::FsPermissionRuleSet { - default: None, - rules: vec![vm_config::FsPermissionRule { - mode: vm_config::PermissionMode::Allow, - operations: Vec::new(), - paths: vec![String::from("*")], - }], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }; - - let error = validate_permissions_policy(&policy).expect_err("policy should be invalid"); - assert!(error - .to_string() - .contains("fs.rules[0].operations must not be empty")); - } -} diff --git a/crates/sidecar-core/src/root_fs.rs b/crates/sidecar-core/src/root_fs.rs deleted file mode 100644 index 680f73ddb..000000000 --- a/crates/sidecar-core/src/root_fs.rs +++ /dev/null @@ -1,715 +0,0 @@ -use base64::Engine; -use secure_exec_bridge::FilesystemSnapshot; -use secure_exec_kernel::mount_table::MountTable; -use secure_exec_kernel::root_fs::{ - decode_snapshot_with_import_limits, is_supported_root_filesystem_snapshot_format, - FilesystemEntry, FilesystemEntryKind, RootFileSystem, - RootFilesystemDescriptor as KernelRootFilesystemDescriptor, RootFilesystemImportLimits, - RootFilesystemMode as KernelRootFilesystemMode, RootFilesystemSnapshot, -}; -use secure_exec_kernel::vfs::{normalize_path, VirtualFileSystem}; -use secure_exec_sidecar_protocol::protocol::{ - RootFilesystemDescriptor as ProtocolRootFilesystemDescriptor, - RootFilesystemEntry as ProtocolRootFilesystemEntry, - RootFilesystemEntryEncoding as ProtocolRootFilesystemEntryEncoding, - RootFilesystemEntryKind as ProtocolRootFilesystemEntryKind, - RootFilesystemLowerDescriptor as ProtocolRootFilesystemLowerDescriptor, - RootFilesystemMode as ProtocolRootFilesystemMode, - SnapshotRootFilesystemLower as ProtocolSnapshotRootFilesystemLower, -}; -use secure_exec_vm_config as vm_config; -use std::error::Error; -use std::fmt; -use vfs::posix::usage::RootFilesystemResourceLimits; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SidecarCoreError { - message: String, -} - -impl SidecarCoreError { - pub fn new(message: impl Into) -> Self { - Self { - message: message.into(), - } - } -} - -impl fmt::Display for SidecarCoreError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.message) - } -} - -impl Error for SidecarCoreError {} - -pub fn root_filesystem_descriptor_from_config( - config: &vm_config::RootFilesystemConfig, -) -> Result { - root_filesystem_descriptor_from_config_with_import_limits( - config, - &RootFilesystemImportLimits::default(), - ) -} - -fn root_filesystem_descriptor_from_config_with_import_limits( - config: &vm_config::RootFilesystemConfig, - import_limits: &RootFilesystemImportLimits, -) -> Result { - Ok(KernelRootFilesystemDescriptor { - mode: root_filesystem_mode_from_config(config.mode), - disable_default_base_layer: config.disable_default_base_layer, - lowers: config - .lowers - .iter() - .map(|lower| root_filesystem_lower_from_config(lower, import_limits)) - .collect::, _>>()?, - bootstrap_entries: config - .bootstrap_entries - .iter() - .map(root_filesystem_entry_from_config) - .collect::, _>>()?, - }) -} - -pub fn root_filesystem_protocol_descriptor_from_config( - config: &vm_config::RootFilesystemConfig, -) -> ProtocolRootFilesystemDescriptor { - ProtocolRootFilesystemDescriptor { - mode: match config.mode { - vm_config::RootFilesystemMode::Ephemeral => ProtocolRootFilesystemMode::Ephemeral, - vm_config::RootFilesystemMode::ReadOnly => ProtocolRootFilesystemMode::ReadOnly, - }, - disable_default_base_layer: config.disable_default_base_layer, - lowers: config - .lowers - .iter() - .map(root_filesystem_protocol_lower_from_config) - .collect(), - bootstrap_entries: config - .bootstrap_entries - .iter() - .map(root_filesystem_protocol_entry_from_config) - .collect(), - } -} - -pub fn build_root_filesystem( - config: &vm_config::RootFilesystemConfig, - limits: &impl RootFilesystemResourceLimits, -) -> Result { - build_root_filesystem_with_loaded_snapshot(config, None, limits) -} - -pub fn build_root_filesystem_with_loaded_snapshot( - config: &vm_config::RootFilesystemConfig, - loaded_snapshot: Option<&FilesystemSnapshot>, - limits: &impl RootFilesystemResourceLimits, -) -> Result { - let import_limits = RootFilesystemImportLimits::from_resource_limits(limits); - let descriptor = if let Some(restored) = supported_loaded_snapshot(loaded_snapshot) { - KernelRootFilesystemDescriptor { - mode: root_filesystem_mode_from_config(config.mode), - disable_default_base_layer: true, - lowers: vec![ - decode_snapshot_with_import_limits(&restored.bytes, &import_limits).map_err( - |error| { - SidecarCoreError::new(format!("decode restored root filesystem: {error}")) - }, - )?, - ], - bootstrap_entries: config - .bootstrap_entries - .iter() - .map(root_filesystem_entry_from_config) - .collect::, _>>()?, - } - } else { - root_filesystem_descriptor_from_config_with_import_limits(config, &import_limits)? - }; - RootFileSystem::from_descriptor_with_import_limits(descriptor, &import_limits) - .map_err(|error| SidecarCoreError::new(format!("build root filesystem: {error}"))) -} - -pub fn build_root_mount_table( - config: &vm_config::RootFilesystemConfig, - limits: &impl RootFilesystemResourceLimits, -) -> Result { - Ok(MountTable::new(build_root_filesystem(config, limits)?)) -} - -pub fn build_root_mount_table_with_loaded_snapshot( - config: &vm_config::RootFilesystemConfig, - loaded_snapshot: Option<&FilesystemSnapshot>, - limits: &impl RootFilesystemResourceLimits, -) -> Result { - Ok(MountTable::new(build_root_filesystem_with_loaded_snapshot( - config, - loaded_snapshot, - limits, - )?)) -} - -pub fn root_filesystem_mode_from_config( - mode: vm_config::RootFilesystemMode, -) -> KernelRootFilesystemMode { - match mode { - vm_config::RootFilesystemMode::Ephemeral => KernelRootFilesystemMode::Ephemeral, - vm_config::RootFilesystemMode::ReadOnly => KernelRootFilesystemMode::ReadOnly, - } -} - -pub fn protocol_root_filesystem_mode(mode: ProtocolRootFilesystemMode) -> KernelRootFilesystemMode { - match mode { - ProtocolRootFilesystemMode::Ephemeral => KernelRootFilesystemMode::Ephemeral, - ProtocolRootFilesystemMode::ReadOnly => KernelRootFilesystemMode::ReadOnly, - } -} - -fn supported_loaded_snapshot(snapshot: Option<&FilesystemSnapshot>) -> Option<&FilesystemSnapshot> { - snapshot.filter(|snapshot| is_supported_root_filesystem_snapshot_format(&snapshot.format)) -} - -fn root_filesystem_lower_from_config( - lower: &vm_config::RootFilesystemLowerDescriptor, - import_limits: &RootFilesystemImportLimits, -) -> Result { - match lower { - vm_config::RootFilesystemLowerDescriptor::Snapshot { entries } => { - Ok(RootFilesystemSnapshot { - entries: entries - .iter() - .map(root_filesystem_entry_from_config) - .collect::, _>>()?, - }) - } - vm_config::RootFilesystemLowerDescriptor::BundledBaseFilesystem => Ok( - secure_exec_kernel::root_fs::load_bundled_base_snapshot_with_limits(import_limits) - .map_err(|error| { - SidecarCoreError::new(format!("load bundled base filesystem lower: {error}")) - })?, - ), - } -} - -fn root_filesystem_entry_from_config( - entry: &vm_config::RootFilesystemEntry, -) -> Result { - let mode = entry.mode.unwrap_or(match entry.kind { - vm_config::RootFilesystemEntryKind::File => { - if entry.executable { - 0o755 - } else { - 0o644 - } - } - vm_config::RootFilesystemEntryKind::Directory => 0o755, - vm_config::RootFilesystemEntryKind::Symlink => 0o777, - }); - - let content = match entry.content.as_ref() { - Some(content) => match entry.encoding { - Some(vm_config::RootFilesystemEntryEncoding::Base64) => Some( - base64::engine::general_purpose::STANDARD - .decode(content) - .map_err(|error| { - SidecarCoreError::new(format!( - "invalid base64 root filesystem content for {}: {error}", - entry.path - )) - })?, - ), - Some(vm_config::RootFilesystemEntryEncoding::Utf8) | None => { - Some(content.as_bytes().to_vec()) - } - }, - None => None, - }; - - Ok(FilesystemEntry { - path: normalize_path(&entry.path), - kind: match entry.kind { - vm_config::RootFilesystemEntryKind::File => FilesystemEntryKind::File, - vm_config::RootFilesystemEntryKind::Directory => FilesystemEntryKind::Directory, - vm_config::RootFilesystemEntryKind::Symlink => FilesystemEntryKind::Symlink, - }, - mode, - uid: entry.uid.unwrap_or(0), - gid: entry.gid.unwrap_or(0), - content, - target: entry.target.clone(), - }) -} - -fn root_filesystem_protocol_lower_from_config( - lower: &vm_config::RootFilesystemLowerDescriptor, -) -> ProtocolRootFilesystemLowerDescriptor { - match lower { - vm_config::RootFilesystemLowerDescriptor::Snapshot { entries } => { - ProtocolRootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - ProtocolSnapshotRootFilesystemLower { - entries: entries - .iter() - .map(root_filesystem_protocol_entry_from_config) - .collect(), - }, - ) - } - vm_config::RootFilesystemLowerDescriptor::BundledBaseFilesystem => { - ProtocolRootFilesystemLowerDescriptor::BundledBaseFilesystemLower - } - } -} - -fn root_filesystem_protocol_entry_from_config( - entry: &vm_config::RootFilesystemEntry, -) -> ProtocolRootFilesystemEntry { - ProtocolRootFilesystemEntry { - path: entry.path.clone(), - kind: match entry.kind { - vm_config::RootFilesystemEntryKind::File => ProtocolRootFilesystemEntryKind::File, - vm_config::RootFilesystemEntryKind::Directory => { - ProtocolRootFilesystemEntryKind::Directory - } - vm_config::RootFilesystemEntryKind::Symlink => ProtocolRootFilesystemEntryKind::Symlink, - }, - mode: entry.mode, - uid: entry.uid, - gid: entry.gid, - content: entry.content.clone(), - encoding: entry.encoding.map(|encoding| match encoding { - vm_config::RootFilesystemEntryEncoding::Utf8 => { - ProtocolRootFilesystemEntryEncoding::Utf8 - } - vm_config::RootFilesystemEntryEncoding::Base64 => { - ProtocolRootFilesystemEntryEncoding::Base64 - } - }), - target: entry.target.clone(), - executable: entry.executable, - } -} - -pub fn root_snapshot_entry(entry: &FilesystemEntry) -> ProtocolRootFilesystemEntry { - let (content, encoding) = entry - .content - .clone() - .map(snapshot_entry_content) - .map(|(content, encoding)| (Some(content), Some(encoding))) - .unwrap_or((None, None)); - - ProtocolRootFilesystemEntry { - path: entry.path.clone(), - kind: match entry.kind { - FilesystemEntryKind::File => ProtocolRootFilesystemEntryKind::File, - FilesystemEntryKind::Directory => ProtocolRootFilesystemEntryKind::Directory, - FilesystemEntryKind::Symlink => ProtocolRootFilesystemEntryKind::Symlink, - }, - mode: Some(entry.mode), - uid: Some(entry.uid), - gid: Some(entry.gid), - content, - encoding, - target: entry.target.clone(), - executable: entry.mode & 0o111 != 0, - } -} - -/// Convert a protocol root-filesystem entry into a kernel `FilesystemEntry`, decoding -/// content (utf8/base64) and applying per-kind mode defaults. Shared by native and -/// browser bootstrap + snapshot paths. -pub fn convert_root_filesystem_entry( - entry: &ProtocolRootFilesystemEntry, -) -> Result { - let mode = entry.mode.unwrap_or(match entry.kind { - ProtocolRootFilesystemEntryKind::File => { - if entry.executable { - 0o755 - } else { - 0o644 - } - } - ProtocolRootFilesystemEntryKind::Directory => 0o755, - ProtocolRootFilesystemEntryKind::Symlink => 0o777, - }); - - let content = match entry.content.as_ref() { - Some(content) => match entry.encoding { - Some(ProtocolRootFilesystemEntryEncoding::Base64) => Some( - base64::engine::general_purpose::STANDARD - .decode(content) - .map_err(|error| { - SidecarCoreError::new(format!( - "invalid base64 root filesystem content for {}: {error}", - entry.path - )) - })?, - ), - Some(ProtocolRootFilesystemEntryEncoding::Utf8) | None => { - Some(content.as_bytes().to_vec()) - } - }, - None => None, - }; - - Ok(FilesystemEntry { - path: normalize_path(&entry.path), - kind: match entry.kind { - ProtocolRootFilesystemEntryKind::File => FilesystemEntryKind::File, - ProtocolRootFilesystemEntryKind::Directory => FilesystemEntryKind::Directory, - ProtocolRootFilesystemEntryKind::Symlink => FilesystemEntryKind::Symlink, - }, - mode, - uid: entry.uid.unwrap_or(0), - gid: entry.gid.unwrap_or(0), - content, - target: entry.target.clone(), - }) -} - -/// Build a kernel snapshot from protocol entries (shared by native + browser). -pub fn root_snapshot_from_entries( - entries: &[ProtocolRootFilesystemEntry], -) -> Result { - Ok(RootFilesystemSnapshot { - entries: entries - .iter() - .map(convert_root_filesystem_entry) - .collect::, _>>()?, - }) -} - -/// Write one root-filesystem bootstrap entry (file/dir/symlink) into a VFS, creating -/// parent dirs and applying deterministic mode/uid/gid defaults (chmod/chown for -/// non-symlinks). Shared by native (raw root FS) and browser (kernel `filesystem_mut`). -pub fn apply_root_filesystem_entry( - filesystem: &mut F, - entry: &ProtocolRootFilesystemEntry, -) -> Result<(), SidecarCoreError> { - let kernel_entry = convert_root_filesystem_entry(entry)?; - - let parent = parent_directory(&kernel_entry.path); - if parent != "/" && !filesystem.exists(&parent) { - filesystem.mkdir(&parent, true).map_err(vfs_err)?; - } - - match kernel_entry.kind { - FilesystemEntryKind::Directory => filesystem - .mkdir(&kernel_entry.path, true) - .map_err(vfs_err)?, - FilesystemEntryKind::File => filesystem - .write_file(&kernel_entry.path, kernel_entry.content.unwrap_or_default()) - .map_err(vfs_err)?, - FilesystemEntryKind::Symlink => filesystem - .symlink( - kernel_entry.target.as_deref().ok_or_else(|| { - SidecarCoreError::new(format!( - "root filesystem bootstrap for symlink {} requires a target", - entry.path - )) - })?, - &kernel_entry.path, - ) - .map_err(vfs_err)?, - } - - if !matches!(kernel_entry.kind, FilesystemEntryKind::Symlink) { - filesystem - .chmod(&kernel_entry.path, kernel_entry.mode) - .map_err(vfs_err)?; - filesystem - .chown(&kernel_entry.path, kernel_entry.uid, kernel_entry.gid) - .map_err(vfs_err)?; - } - - Ok(()) -} - -fn vfs_err(error: E) -> SidecarCoreError { - SidecarCoreError::new(error.to_string()) -} - -fn parent_directory(path: &str) -> String { - match path.rfind('/') { - Some(0) | None => String::from("/"), - Some(index) => path[..index].to_string(), - } -} - -fn snapshot_entry_content(content: Vec) -> (String, ProtocolRootFilesystemEntryEncoding) { - match String::from_utf8(content) { - Ok(text) => (text, ProtocolRootFilesystemEntryEncoding::Utf8), - Err(error) => ( - base64::engine::general_purpose::STANDARD.encode(error.into_bytes()), - ProtocolRootFilesystemEntryEncoding::Base64, - ), - } -} - -#[cfg(test)] -mod tests { - use super::*; - use secure_exec_kernel::resource_accounting::ResourceLimits; - use secure_exec_kernel::vfs::VirtualFileSystem; - - #[test] - fn builds_root_filesystem_from_snapshot_lower_and_bootstrap_upper() { - let mut root = build_root_filesystem( - &vm_config::RootFilesystemConfig { - disable_default_base_layer: true, - lowers: vec![vm_config::RootFilesystemLowerDescriptor::Snapshot { - entries: vec![vm_config::RootFilesystemEntry { - path: String::from("/workspace/value.txt"), - kind: vm_config::RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("lower")), - encoding: Some(vm_config::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - }], - bootstrap_entries: vec![vm_config::RootFilesystemEntry { - path: String::from("/workspace/value.txt"), - kind: vm_config::RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("upper")), - encoding: Some(vm_config::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - ..vm_config::RootFilesystemConfig::default() - }, - &ResourceLimits::default(), - ) - .expect("build root filesystem"); - - assert_eq!( - root.read_file("/workspace/value.txt") - .expect("read merged value"), - b"upper".to_vec() - ); - } - - #[test] - fn decodes_base64_root_filesystem_entries() { - let mut root = build_root_filesystem( - &vm_config::RootFilesystemConfig { - disable_default_base_layer: true, - bootstrap_entries: vec![vm_config::RootFilesystemEntry { - path: String::from("/bin/tool"), - kind: vm_config::RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("dG9vbA==")), - encoding: Some(vm_config::RootFilesystemEntryEncoding::Base64), - target: None, - executable: true, - }], - ..vm_config::RootFilesystemConfig::default() - }, - &ResourceLimits::default(), - ) - .expect("build root filesystem"); - - assert_eq!(root.read_file("/bin/tool").expect("read file"), b"tool"); - assert_eq!( - root.stat("/bin/tool").expect("stat file").mode & 0o777, - 0o755 - ); - } - - #[test] - fn serializes_root_snapshot_entries_as_utf8_or_base64() { - let text = root_snapshot_entry(&FilesystemEntry { - path: String::from("/workspace/text.txt"), - kind: FilesystemEntryKind::File, - mode: 0o755, - uid: 501, - gid: 20, - content: Some(b"hello".to_vec()), - target: None, - }); - - assert_eq!(text.path, "/workspace/text.txt"); - assert_eq!(text.kind, ProtocolRootFilesystemEntryKind::File); - assert_eq!(text.mode, Some(0o755)); - assert_eq!(text.uid, Some(501)); - assert_eq!(text.gid, Some(20)); - assert_eq!(text.content.as_deref(), Some("hello")); - assert_eq!( - text.encoding, - Some(ProtocolRootFilesystemEntryEncoding::Utf8) - ); - assert!(text.executable); - - let binary = root_snapshot_entry(&FilesystemEntry { - path: String::from("/workspace/binary.bin"), - kind: FilesystemEntryKind::File, - mode: 0o644, - uid: 0, - gid: 0, - content: Some(vec![0xff, 0x00]), - target: None, - }); - - assert_eq!(binary.content.as_deref(), Some("/wA=")); - assert_eq!( - binary.encoding, - Some(ProtocolRootFilesystemEntryEncoding::Base64) - ); - assert!(!binary.executable); - } - - #[test] - fn builds_protocol_descriptor_from_config_without_normalizing_optional_fields() { - let descriptor = - root_filesystem_protocol_descriptor_from_config(&vm_config::RootFilesystemConfig { - mode: vm_config::RootFilesystemMode::ReadOnly, - disable_default_base_layer: true, - lowers: vec![ - vm_config::RootFilesystemLowerDescriptor::BundledBaseFilesystem, - vm_config::RootFilesystemLowerDescriptor::Snapshot { - entries: vec![vm_config::RootFilesystemEntry { - path: String::from("relative/lower.txt"), - kind: vm_config::RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("lower")), - encoding: None, - target: None, - executable: false, - }], - }, - ], - bootstrap_entries: vec![vm_config::RootFilesystemEntry { - path: String::from("/bin/tool"), - kind: vm_config::RootFilesystemEntryKind::File, - mode: Some(0o700), - uid: Some(1000), - gid: Some(1000), - content: Some(String::from("dG9vbA==")), - encoding: Some(vm_config::RootFilesystemEntryEncoding::Base64), - target: None, - executable: true, - }], - }); - - assert_eq!(descriptor.mode, ProtocolRootFilesystemMode::ReadOnly); - assert!(descriptor.disable_default_base_layer); - assert_eq!(descriptor.lowers.len(), 2); - assert!(matches!( - descriptor.lowers[0], - ProtocolRootFilesystemLowerDescriptor::BundledBaseFilesystemLower - )); - let ProtocolRootFilesystemLowerDescriptor::SnapshotRootFilesystemLower(snapshot) = - &descriptor.lowers[1] - else { - panic!("expected snapshot lower"); - }; - assert_eq!(snapshot.entries[0].path, "relative/lower.txt"); - assert_eq!(snapshot.entries[0].mode, None); - assert_eq!(snapshot.entries[0].encoding, None); - - let entry = &descriptor.bootstrap_entries[0]; - assert_eq!(entry.path, "/bin/tool"); - assert_eq!(entry.kind, ProtocolRootFilesystemEntryKind::File); - assert_eq!(entry.mode, Some(0o700)); - assert_eq!(entry.uid, Some(1000)); - assert_eq!(entry.gid, Some(1000)); - assert_eq!(entry.content.as_deref(), Some("dG9vbA==")); - assert_eq!( - entry.encoding, - Some(ProtocolRootFilesystemEntryEncoding::Base64) - ); - assert!(entry.executable); - } - - #[test] - fn maps_root_filesystem_modes_to_kernel_modes() { - assert_eq!( - root_filesystem_mode_from_config(vm_config::RootFilesystemMode::Ephemeral), - KernelRootFilesystemMode::Ephemeral - ); - assert_eq!( - root_filesystem_mode_from_config(vm_config::RootFilesystemMode::ReadOnly), - KernelRootFilesystemMode::ReadOnly - ); - assert_eq!( - protocol_root_filesystem_mode(ProtocolRootFilesystemMode::Ephemeral), - KernelRootFilesystemMode::Ephemeral - ); - assert_eq!( - protocol_root_filesystem_mode(ProtocolRootFilesystemMode::ReadOnly), - KernelRootFilesystemMode::ReadOnly - ); - } - - #[test] - fn restored_snapshot_replaces_config_lowers_but_preserves_bootstrap_entries() { - let restored = RootFilesystemSnapshot { - entries: vec![FilesystemEntry::file( - "/workspace/restored.txt", - b"restored", - )], - }; - let loaded_snapshot = FilesystemSnapshot { - format: String::from(secure_exec_kernel::root_fs::ROOT_FILESYSTEM_SNAPSHOT_FORMAT), - bytes: secure_exec_kernel::root_fs::encode_snapshot(&restored) - .expect("encode restored snapshot"), - }; - let mut root = build_root_filesystem_with_loaded_snapshot( - &vm_config::RootFilesystemConfig { - disable_default_base_layer: true, - lowers: vec![vm_config::RootFilesystemLowerDescriptor::Snapshot { - entries: vec![vm_config::RootFilesystemEntry { - path: String::from("/workspace/ignored-lower.txt"), - kind: vm_config::RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("ignored")), - encoding: Some(vm_config::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - }], - bootstrap_entries: vec![vm_config::RootFilesystemEntry { - path: String::from("/workspace/bootstrap.txt"), - kind: vm_config::RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from("bootstrap")), - encoding: Some(vm_config::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - ..vm_config::RootFilesystemConfig::default() - }, - Some(&loaded_snapshot), - &ResourceLimits::default(), - ) - .expect("build root filesystem from restored snapshot"); - - assert_eq!( - root.read_file("/workspace/restored.txt") - .expect("read restored file"), - b"restored".to_vec() - ); - assert_eq!( - root.read_file("/workspace/bootstrap.txt") - .expect("read bootstrap file"), - b"bootstrap".to_vec() - ); - assert!( - root.read_file("/workspace/ignored-lower.txt").is_err(), - "restored snapshots should replace configured lowers" - ); - } -} diff --git a/crates/sidecar-core/src/router.rs b/crates/sidecar-core/src/router.rs deleted file mode 100644 index f167fc77a..000000000 --- a/crates/sidecar-core/src/router.rs +++ /dev/null @@ -1,457 +0,0 @@ -use crate::frames::{reject, DispatchResult}; -use secure_exec_sidecar_protocol::protocol::{ - AuthenticateRequest, BootstrapRootFilesystemRequest, CloseStdinRequest, ConfigureVmRequest, - CreateLayerRequest, CreateOverlayRequest, CreateVmRequest, DisposeVmRequest, ExecuteRequest, - ExportSnapshotRequest, ExtEnvelope, FindBoundUdpRequest, FindListenerRequest, - GetProcessSnapshotRequest, GetResourceSnapshotRequest, GetSignalStateRequest, - GetZombieTimerCountRequest, GuestFilesystemCallRequest, GuestKernelCallRequest, - ImportSnapshotRequest, KillProcessRequest, LinkPackageRequest, OpenSessionRequest, - OwnershipScope, ProvidedCommandsRequest, RegisterHostCallbacksRequest, RequestFrame, - RequestPayload, ResizePtyRequest, SealLayerRequest, SnapshotRootFilesystemRequest, - VmFetchRequest, WriteStdinRequest, -}; -use secure_exec_sidecar_protocol::wire as generated_wire; - -pub const UNSUPPORTED_HOST_CALLBACK_DIRECTION_CODE: &str = "unsupported_direction"; -pub const UNSUPPORTED_HOST_CALLBACK_DIRECTION_MESSAGE: &str = - "host callback request categories are sidecar-to-host only in this scaffold"; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum RequestDispatchMode { - Immediate, - Async, -} - -// Request payload variants intentionally vary widely in size (small acks next -// to bulky create/exec payloads); boxing is a wire-adjacent refactor. -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Clone)] -pub enum RequestRoute { - Authenticate(AuthenticateRequest), - OpenSession(OpenSessionRequest), - CreateVm(CreateVmRequest), - DisposeVm(DisposeVmRequest), - BootstrapRootFilesystem(BootstrapRootFilesystemRequest), - ConfigureVm(ConfigureVmRequest), - RegisterHostCallbacks(RegisterHostCallbacksRequest), - CreateLayer(CreateLayerRequest), - SealLayer(SealLayerRequest), - ImportSnapshot(ImportSnapshotRequest), - ExportSnapshot(ExportSnapshotRequest), - CreateOverlay(CreateOverlayRequest), - GuestFilesystemCall(GuestFilesystemCallRequest), - GuestKernelCall(GuestKernelCallRequest), - SnapshotRootFilesystem(SnapshotRootFilesystemRequest), - Execute(ExecuteRequest), - WriteStdin(WriteStdinRequest), - ResizePty(ResizePtyRequest), - CloseStdin(CloseStdinRequest), - KillProcess(KillProcessRequest), - GetProcessSnapshot(GetProcessSnapshotRequest), - GetResourceSnapshot(GetResourceSnapshotRequest), - FindListener(FindListenerRequest), - FindBoundUdp(FindBoundUdpRequest), - VmFetch(VmFetchRequest), - GetSignalState(GetSignalStateRequest), - GetZombieTimerCount(GetZombieTimerCountRequest), - LinkPackage(LinkPackageRequest), - ProvidedCommands(ProvidedCommandsRequest), - Ext(ExtEnvelope), - UnsupportedHostCallbackDirection, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum BlockingExtensionInterrupt<'a> { - ExtensionPayload(&'a [u8]), - KillProcess, -} - -pub fn route_request_payload(request: &RequestFrame) -> RequestRoute { - match request.payload.clone() { - RequestPayload::Authenticate(payload) => RequestRoute::Authenticate(payload), - RequestPayload::OpenSession(payload) => RequestRoute::OpenSession(payload), - RequestPayload::CreateVm(payload) => RequestRoute::CreateVm(payload), - RequestPayload::DisposeVm(payload) => RequestRoute::DisposeVm(payload), - RequestPayload::BootstrapRootFilesystem(payload) => { - RequestRoute::BootstrapRootFilesystem(payload) - } - RequestPayload::ConfigureVm(payload) => RequestRoute::ConfigureVm(payload), - RequestPayload::RegisterHostCallbacks(payload) => { - RequestRoute::RegisterHostCallbacks(payload) - } - RequestPayload::CreateLayer(payload) => RequestRoute::CreateLayer(payload), - RequestPayload::SealLayer(payload) => RequestRoute::SealLayer(payload), - RequestPayload::ImportSnapshot(payload) => RequestRoute::ImportSnapshot(payload), - RequestPayload::ExportSnapshot(payload) => RequestRoute::ExportSnapshot(payload), - RequestPayload::CreateOverlay(payload) => RequestRoute::CreateOverlay(payload), - RequestPayload::GuestFilesystemCall(payload) => RequestRoute::GuestFilesystemCall(payload), - RequestPayload::GuestKernelCall(payload) => RequestRoute::GuestKernelCall(payload), - RequestPayload::SnapshotRootFilesystem(payload) => { - RequestRoute::SnapshotRootFilesystem(payload) - } - RequestPayload::Execute(payload) => RequestRoute::Execute(payload), - RequestPayload::WriteStdin(payload) => RequestRoute::WriteStdin(payload), - RequestPayload::ResizePty(payload) => RequestRoute::ResizePty(payload), - RequestPayload::CloseStdin(payload) => RequestRoute::CloseStdin(payload), - RequestPayload::KillProcess(payload) => RequestRoute::KillProcess(payload), - RequestPayload::GetProcessSnapshot(payload) => RequestRoute::GetProcessSnapshot(payload), - RequestPayload::GetResourceSnapshot(payload) => RequestRoute::GetResourceSnapshot(payload), - RequestPayload::FindListener(payload) => RequestRoute::FindListener(payload), - RequestPayload::FindBoundUdp(payload) => RequestRoute::FindBoundUdp(payload), - RequestPayload::VmFetch(payload) => RequestRoute::VmFetch(payload), - RequestPayload::GetSignalState(payload) => RequestRoute::GetSignalState(payload), - RequestPayload::GetZombieTimerCount(payload) => RequestRoute::GetZombieTimerCount(payload), - RequestPayload::LinkPackage(payload) => RequestRoute::LinkPackage(payload), - RequestPayload::ProvidedCommands(payload) => RequestRoute::ProvidedCommands(payload), - RequestPayload::HostFilesystemCall(_) - | RequestPayload::PersistenceLoad(_) - | RequestPayload::PersistenceFlush(_) => RequestRoute::UnsupportedHostCallbackDirection, - RequestPayload::Ext(payload) => RequestRoute::Ext(payload), - } -} - -pub fn generated_wire_blocking_extension_interrupt<'a>( - active_request: &generated_wire::RequestFrame, - blocking_namespace: &str, - interrupting_request: &'a generated_wire::RequestFrame, -) -> Option> { - if interrupting_request.ownership != active_request.ownership { - return None; - } - - match &interrupting_request.payload { - generated_wire::RequestPayload::ExtEnvelope(envelope) - if envelope.namespace == blocking_namespace => - { - Some(BlockingExtensionInterrupt::ExtensionPayload( - &envelope.payload, - )) - } - generated_wire::RequestPayload::ExtEnvelope(_) => None, - generated_wire::RequestPayload::KillProcessRequest(_) => { - Some(BlockingExtensionInterrupt::KillProcess) - } - _ => None, - } -} - -pub fn request_dispatch_mode(request: &RequestFrame) -> RequestDispatchMode { - match request.payload { - RequestPayload::DisposeVm(_) | RequestPayload::Ext(_) => RequestDispatchMode::Async, - RequestPayload::Authenticate(_) - | RequestPayload::OpenSession(_) - | RequestPayload::CreateVm(_) - | RequestPayload::BootstrapRootFilesystem(_) - | RequestPayload::ConfigureVm(_) - | RequestPayload::RegisterHostCallbacks(_) - | RequestPayload::CreateLayer(_) - | RequestPayload::SealLayer(_) - | RequestPayload::ImportSnapshot(_) - | RequestPayload::ExportSnapshot(_) - | RequestPayload::CreateOverlay(_) - | RequestPayload::GuestFilesystemCall(_) - | RequestPayload::GuestKernelCall(_) - | RequestPayload::SnapshotRootFilesystem(_) - | RequestPayload::Execute(_) - | RequestPayload::WriteStdin(_) - | RequestPayload::ResizePty(_) - | RequestPayload::CloseStdin(_) - | RequestPayload::KillProcess(_) - | RequestPayload::GetProcessSnapshot(_) - | RequestPayload::GetResourceSnapshot(_) - | RequestPayload::FindListener(_) - | RequestPayload::FindBoundUdp(_) - | RequestPayload::VmFetch(_) - | RequestPayload::GetSignalState(_) - | RequestPayload::GetZombieTimerCount(_) - | RequestPayload::LinkPackage(_) - | RequestPayload::ProvidedCommands(_) - | RequestPayload::HostFilesystemCall(_) - | RequestPayload::PersistenceLoad(_) - | RequestPayload::PersistenceFlush(_) => RequestDispatchMode::Immediate, - } -} - -pub fn request_is_unsupported_host_callback_direction(request: &RequestFrame) -> bool { - matches!( - request.payload, - RequestPayload::HostFilesystemCall(_) - | RequestPayload::PersistenceLoad(_) - | RequestPayload::PersistenceFlush(_) - ) -} - -pub fn unsupported_host_callback_direction_dispatch(request: &RequestFrame) -> DispatchResult { - debug_assert!(request_is_unsupported_host_callback_direction(request)); - DispatchResult { - response: reject( - request, - UNSUPPORTED_HOST_CALLBACK_DIRECTION_CODE, - UNSUPPORTED_HOST_CALLBACK_DIRECTION_MESSAGE, - ), - events: Vec::new(), - } -} - -pub fn connection_id_of(ownership: &OwnershipScope) -> Option { - match ownership { - OwnershipScope::ConnectionOwnership(ownership) => Some(ownership.connection_id.clone()), - OwnershipScope::SessionOwnership(ownership) => Some(ownership.connection_id.clone()), - OwnershipScope::VmOwnership(ownership) => Some(ownership.connection_id.clone()), - } -} - -pub fn session_scope_of(ownership: &OwnershipScope) -> Option<(String, String)> { - match ownership { - OwnershipScope::SessionOwnership(ownership) => Some(( - ownership.connection_id.clone(), - ownership.session_id.clone(), - )), - OwnershipScope::VmOwnership(ownership) => Some(( - ownership.connection_id.clone(), - ownership.session_id.clone(), - )), - OwnershipScope::ConnectionOwnership(_) => None, - } -} - -pub fn vm_id_of(ownership: &OwnershipScope) -> Option { - match ownership { - OwnershipScope::VmOwnership(ownership) => Some(ownership.vm_id.clone()), - OwnershipScope::ConnectionOwnership(_) | OwnershipScope::SessionOwnership(_) => None, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use secure_exec_sidecar_protocol::protocol::{ - AuthenticateRequest, ExtEnvelope, FilesystemOperation, HostFilesystemCallRequest, - OwnershipScope, PersistenceFlushRequest, PersistenceLoadRequest, ResponsePayload, - PROTOCOL_VERSION, - }; - use secure_exec_sidecar_protocol::wire as generated_wire; - - fn request(payload: RequestPayload) -> RequestFrame { - RequestFrame::new(7, OwnershipScope::connection("conn"), payload) - } - - fn generated_request( - request_id: i64, - ownership: generated_wire::OwnershipScope, - payload: generated_wire::RequestPayload, - ) -> generated_wire::RequestFrame { - generated_wire::RequestFrame { - schema: generated_wire::protocol_schema(), - request_id, - ownership, - payload, - } - } - - fn reverse_host_callback_payloads() -> Vec { - vec![ - RequestPayload::HostFilesystemCall(HostFilesystemCallRequest { - operation: FilesystemOperation::Read, - path: String::from("/state"), - payload_size_bytes: 0, - }), - RequestPayload::PersistenceLoad(PersistenceLoadRequest { - key: String::from("state"), - }), - RequestPayload::PersistenceFlush(PersistenceFlushRequest { - key: String::from("state"), - payload_size_bytes: 0, - }), - ] - } - - #[test] - fn dispose_and_ext_requests_are_async() { - let ext = request(RequestPayload::Ext(ExtEnvelope { - namespace: String::from("test"), - payload: Vec::new(), - })); - assert_eq!(request_dispatch_mode(&ext), RequestDispatchMode::Async); - } - - #[test] - fn normal_requests_are_immediate() { - let authenticate = request(RequestPayload::Authenticate(AuthenticateRequest { - client_name: String::from("test"), - auth_token: String::from("token"), - protocol_version: PROTOCOL_VERSION, - bridge_version: 1, - })); - assert_eq!( - request_dispatch_mode(&authenticate), - RequestDispatchMode::Immediate - ); - } - - #[test] - fn host_callback_requests_are_identified_as_reverse_direction_only() { - for payload in reverse_host_callback_payloads() { - let host_call = request(payload); - - assert!(request_is_unsupported_host_callback_direction(&host_call)); - assert_eq!( - request_dispatch_mode(&host_call), - RequestDispatchMode::Immediate - ); - } - } - - #[test] - fn routes_protocol_payloads_through_shared_enum() { - let authenticate = request(RequestPayload::Authenticate(AuthenticateRequest { - client_name: String::from("test"), - auth_token: String::from("token"), - protocol_version: PROTOCOL_VERSION, - bridge_version: 1, - })); - assert!(matches!( - route_request_payload(&authenticate), - RequestRoute::Authenticate(_) - )); - - let extension = request(RequestPayload::Ext(ExtEnvelope { - namespace: String::from("test"), - payload: vec![1, 2, 3], - })); - assert!(matches!( - route_request_payload(&extension), - RequestRoute::Ext(_) - )); - - for payload in reverse_host_callback_payloads() { - let host_call = request(payload); - assert!(matches!( - route_request_payload(&host_call), - RequestRoute::UnsupportedHostCallbackDirection - )); - } - } - - #[test] - fn unsupported_host_callback_dispatch_rejects_with_shared_code() { - for payload in reverse_host_callback_payloads() { - let host_call = request(payload); - - let dispatch = unsupported_host_callback_direction_dispatch(&host_call); - - assert!(dispatch.events.is_empty()); - assert_eq!(dispatch.response.request_id, host_call.request_id); - assert_eq!(dispatch.response.ownership, host_call.ownership); - match dispatch.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, UNSUPPORTED_HOST_CALLBACK_DIRECTION_CODE); - assert_eq!( - rejected.message, - UNSUPPORTED_HOST_CALLBACK_DIRECTION_MESSAGE - ); - } - other => panic!("unexpected response payload: {other:?}"), - } - } - } - - #[test] - fn generated_wire_prompt_interrupt_classifier_matches_only_same_scope_interrupts() { - let ownership = generated_wire::OwnershipScope::VmOwnership(generated_wire::VmOwnership { - connection_id: String::from("conn"), - session_id: String::from("session"), - vm_id: String::from("vm"), - }); - let active = generated_request( - 1, - ownership.clone(), - generated_wire::RequestPayload::ExtEnvelope(generated_wire::ExtEnvelope { - namespace: String::from("prompt"), - payload: b"active".to_vec(), - }), - ); - - let same_namespace = generated_request( - 2, - ownership.clone(), - generated_wire::RequestPayload::ExtEnvelope(generated_wire::ExtEnvelope { - namespace: String::from("prompt"), - payload: b"cancel".to_vec(), - }), - ); - assert_eq!( - generated_wire_blocking_extension_interrupt(&active, "prompt", &same_namespace), - Some(BlockingExtensionInterrupt::ExtensionPayload(b"cancel")) - ); - - let kill = generated_request( - 3, - ownership.clone(), - generated_wire::RequestPayload::KillProcessRequest( - generated_wire::KillProcessRequest { - process_id: String::from("proc"), - signal: String::from("SIGTERM"), - }, - ), - ); - assert_eq!( - generated_wire_blocking_extension_interrupt(&active, "prompt", &kill), - Some(BlockingExtensionInterrupt::KillProcess) - ); - - let other_namespace = generated_request( - 4, - ownership.clone(), - generated_wire::RequestPayload::ExtEnvelope(generated_wire::ExtEnvelope { - namespace: String::from("other"), - payload: b"cancel".to_vec(), - }), - ); - assert_eq!( - generated_wire_blocking_extension_interrupt(&active, "prompt", &other_namespace), - None - ); - - let other_scope = generated_request( - 5, - generated_wire::OwnershipScope::VmOwnership(generated_wire::VmOwnership { - connection_id: String::from("conn"), - session_id: String::from("session"), - vm_id: String::from("other-vm"), - }), - generated_wire::RequestPayload::KillProcessRequest( - generated_wire::KillProcessRequest { - process_id: String::from("proc"), - signal: String::from("SIGTERM"), - }, - ), - ); - assert_eq!( - generated_wire_blocking_extension_interrupt(&active, "prompt", &other_scope), - None - ); - } - - #[test] - fn ownership_scope_helpers_extract_shared_ids() { - let connection = OwnershipScope::connection("conn-1"); - let session = OwnershipScope::session("conn-1", "session-1"); - let vm = OwnershipScope::vm("conn-1", "session-1", "vm-1"); - - assert_eq!(connection_id_of(&connection).as_deref(), Some("conn-1")); - assert_eq!(connection_id_of(&session).as_deref(), Some("conn-1")); - assert_eq!(connection_id_of(&vm).as_deref(), Some("conn-1")); - assert_eq!( - session_scope_of(&session), - Some((String::from("conn-1"), String::from("session-1"))) - ); - assert_eq!( - session_scope_of(&vm), - Some((String::from("conn-1"), String::from("session-1"))) - ); - assert_eq!(session_scope_of(&connection), None); - assert_eq!(vm_id_of(&vm).as_deref(), Some("vm-1")); - assert_eq!(vm_id_of(&session), None); - } -} diff --git a/crates/sidecar-core/src/signals.rs b/crates/sidecar-core/src/signals.rs deleted file mode 100644 index ed32b4ca5..000000000 --- a/crates/sidecar-core/src/signals.rs +++ /dev/null @@ -1,339 +0,0 @@ -use secure_exec_bridge::ExecutionSignal; -use secure_exec_sidecar_protocol::protocol::{SignalDispositionAction, SignalHandlerRegistration}; -use serde_json::Value; -use std::collections::BTreeMap; - -pub fn execution_signal_to_kernel(signal: ExecutionSignal) -> i32 { - match signal { - ExecutionSignal::Terminate => 15, - ExecutionSignal::Interrupt => 2, - ExecutionSignal::Kill => 9, - } -} - -pub fn execution_signal_from_number(signal: i32) -> Option { - match signal { - 2 => Some(ExecutionSignal::Interrupt), - 9 => Some(ExecutionSignal::Kill), - 15 => Some(ExecutionSignal::Terminate), - _ => None, - } -} - -pub fn default_signal_exit_code(signal: i32) -> Option { - (signal > 0).then_some(128 + signal) -} - -pub fn is_valid_posix_signal_number(signal: u32) -> bool { - signal <= 31 -} - -pub fn parse_posix_signal(signal: &str) -> Option { - let trimmed = signal.trim(); - if trimmed.is_empty() { - return None; - } - - if let Ok(value) = trimmed.parse::() { - return (0..=31).contains(&value).then_some(value); - } - - let upper = trimmed.to_ascii_uppercase(); - let normalized = upper.strip_prefix("SIG").unwrap_or(&upper); - signal_number_from_name(normalized) -} - -pub fn canonical_signal_name(signal: i32) -> Option<&'static str> { - match signal { - 1 => Some("SIGHUP"), - 2 => Some("SIGINT"), - 3 => Some("SIGQUIT"), - 4 => Some("SIGILL"), - 5 => Some("SIGTRAP"), - 6 => Some("SIGABRT"), - 7 => Some("SIGBUS"), - 8 => Some("SIGFPE"), - 9 => Some("SIGKILL"), - 10 => Some("SIGUSR1"), - 11 => Some("SIGSEGV"), - 12 => Some("SIGUSR2"), - 13 => Some("SIGPIPE"), - 14 => Some("SIGALRM"), - 15 => Some("SIGTERM"), - 16 => Some("SIGSTKFLT"), - 17 => Some("SIGCHLD"), - 18 => Some("SIGCONT"), - 19 => Some("SIGSTOP"), - 20 => Some("SIGTSTP"), - 21 => Some("SIGTTIN"), - 22 => Some("SIGTTOU"), - 23 => Some("SIGURG"), - 24 => Some("SIGXCPU"), - 25 => Some("SIGXFSZ"), - 26 => Some("SIGVTALRM"), - 27 => Some("SIGPROF"), - 28 => Some("SIGWINCH"), - 29 => Some("SIGIO"), - 30 => Some("SIGPWR"), - 31 => Some("SIGSYS"), - _ => None, - } -} - -pub fn signal_number_from_name(signal: &str) -> Option { - match signal { - "0" => Some(0), - "HUP" => Some(1), - "INT" => Some(2), - "QUIT" => Some(3), - "ILL" => Some(4), - "TRAP" => Some(5), - "ABRT" | "IOT" => Some(6), - "BUS" => Some(7), - "FPE" => Some(8), - "KILL" => Some(9), - "USR1" => Some(10), - "SEGV" => Some(11), - "USR2" => Some(12), - "PIPE" => Some(13), - "ALRM" => Some(14), - "TERM" => Some(15), - "STKFLT" => Some(16), - "CHLD" => Some(17), - "CONT" => Some(18), - "STOP" => Some(19), - "TSTP" => Some(20), - "TTIN" => Some(21), - "TTOU" => Some(22), - "URG" => Some(23), - "XCPU" => Some(24), - "XFSZ" => Some(25), - "VTALRM" => Some(26), - "PROF" => Some(27), - "WINCH" => Some(28), - "IO" | "POLL" => Some(29), - "PWR" => Some(30), - "SYS" => Some(31), - _ => None, - } -} - -pub fn parse_process_signal_state_request( - args: &[Value], -) -> Result<(u32, SignalHandlerRegistration), crate::SidecarCoreError> { - let signal = signal_state_u32_arg(args, 0, "process.signal_state signal")?; - validate_process_signal_number(signal, "process.signal_state signal")?; - let action = signal_state_str_arg(args, 1, "process.signal_state action")?; - let mask_json = signal_state_str_arg(args, 2, "process.signal_state mask")?; - let flags = signal_state_u32_arg(args, 3, "process.signal_state flags")?; - let mask: Vec = serde_json::from_str(mask_json).map_err(|error| { - crate::SidecarCoreError::new(format!( - "process.signal_state mask must be valid JSON: {error}" - )) - })?; - for signal in &mask { - validate_process_signal_number(*signal, "process.signal_state mask entries")?; - } - let action = match action.trim().to_ascii_lowercase().as_str() { - "default" => SignalDispositionAction::Default, - "ignore" => SignalDispositionAction::Ignore, - "user" => SignalDispositionAction::User, - other => { - return Err(crate::SidecarCoreError::new(format!( - "unsupported process.signal_state action {other}" - ))); - } - }; - - Ok(( - signal, - SignalHandlerRegistration { - action, - mask, - flags, - }, - )) -} - -pub fn apply_process_signal_state_update( - signal_states: &mut BTreeMap>, - process_id: &str, - signal: u32, - registration: SignalHandlerRegistration, -) { - if registration.action == SignalDispositionAction::Default - && registration.mask.is_empty() - && registration.flags == 0 - { - let remove_process_entry = signal_states - .get_mut(process_id) - .map(|handlers| { - handlers.remove(&signal); - handlers.is_empty() - }) - .unwrap_or(false); - if remove_process_entry { - signal_states.remove(process_id); - } - return; - } - - signal_states - .entry(process_id.to_owned()) - .or_default() - .insert(signal, registration); -} - -fn validate_process_signal_number(signal: u32, label: &str) -> Result<(), crate::SidecarCoreError> { - if is_valid_posix_signal_number(signal) { - Ok(()) - } else { - Err(crate::SidecarCoreError::new(format!( - "{label} must be a valid POSIX signal" - ))) - } -} - -fn signal_state_u32_arg( - args: &[Value], - index: usize, - label: &str, -) -> Result { - let value = args - .get(index) - .ok_or_else(|| crate::SidecarCoreError::new(format!("{label} missing")))?; - if let Some(value) = value.as_u64() { - return u32::try_from(value) - .map_err(|_| crate::SidecarCoreError::new(format!("{label} must fit in u32"))); - } - if let Some(value) = value.as_i64() { - return u32::try_from(value) - .map_err(|_| crate::SidecarCoreError::new(format!("{label} must fit in u32"))); - } - if let Some(value) = value.as_str() { - return value - .parse::() - .map_err(|error| crate::SidecarCoreError::new(format!("{label}: {error}"))); - } - Err(crate::SidecarCoreError::new(format!( - "{label} must be a u32" - ))) -} - -fn signal_state_str_arg<'a>( - args: &'a [Value], - index: usize, - label: &str, -) -> Result<&'a str, crate::SidecarCoreError> { - args.get(index) - .and_then(Value::as_str) - .ok_or_else(|| crate::SidecarCoreError::new(format!("{label} must be a string"))) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn execution_signal_mapping_matches_posix_defaults() { - assert_eq!(execution_signal_to_kernel(ExecutionSignal::Interrupt), 2); - assert_eq!(execution_signal_to_kernel(ExecutionSignal::Kill), 9); - assert_eq!(execution_signal_to_kernel(ExecutionSignal::Terminate), 15); - assert_eq!( - execution_signal_from_number(2), - Some(ExecutionSignal::Interrupt) - ); - assert_eq!(execution_signal_from_number(9), Some(ExecutionSignal::Kill)); - assert_eq!( - execution_signal_from_number(15), - Some(ExecutionSignal::Terminate) - ); - assert_eq!(execution_signal_from_number(10), None); - } - - #[test] - fn default_signal_exit_code_is_128_plus_signal() { - assert_eq!(default_signal_exit_code(2), Some(130)); - assert_eq!(default_signal_exit_code(9), Some(137)); - assert_eq!(default_signal_exit_code(15), Some(143)); - assert_eq!(default_signal_exit_code(0), None); - } - - #[test] - fn validates_posix_signal_number_range() { - assert!(is_valid_posix_signal_number(0)); - assert!(is_valid_posix_signal_number(31)); - assert!(!is_valid_posix_signal_number(32)); - } - - #[test] - fn parses_signal_names_and_numbers() { - assert_eq!(parse_posix_signal("SIGTERM"), Some(15)); - assert_eq!(parse_posix_signal("term"), Some(15)); - assert_eq!(canonical_signal_name(16), Some("SIGSTKFLT")); - assert_eq!(parse_posix_signal("9"), Some(9)); - assert_eq!(parse_posix_signal("0"), Some(0)); - assert_eq!(parse_posix_signal("SIGBOGUS"), None); - assert_eq!(parse_posix_signal("32"), None); - } - - #[test] - fn parses_and_applies_process_signal_state_updates() { - let args = vec![ - Value::from(15), - Value::from("user"), - Value::from("[2]"), - Value::from(0), - ]; - let (signal, registration) = - parse_process_signal_state_request(&args).expect("signal state"); - assert_eq!(signal, 15); - assert_eq!(registration.action, SignalDispositionAction::User); - assert_eq!(registration.mask, vec![2]); - - let mut states = BTreeMap::new(); - apply_process_signal_state_update(&mut states, "proc-1", signal, registration); - assert!(states - .get("proc-1") - .is_some_and(|handlers| handlers.contains_key(&15))); - - apply_process_signal_state_update( - &mut states, - "proc-1", - 15, - SignalHandlerRegistration { - action: SignalDispositionAction::Default, - mask: Vec::new(), - flags: 0, - }, - ); - assert!(!states.contains_key("proc-1")); - } - - #[test] - fn rejects_unknown_process_signal_state_values() { - let invalid_signal = parse_process_signal_state_request(&[ - Value::from(32), - Value::from("user"), - Value::from("[]"), - Value::from(0), - ]) - .expect_err("unknown signal must fail"); - assert_eq!( - invalid_signal.to_string(), - "process.signal_state signal must be a valid POSIX signal" - ); - - let invalid_mask = parse_process_signal_state_request(&[ - Value::from(15), - Value::from("user"), - Value::from("[32]"), - Value::from(0), - ]) - .expect_err("unknown mask signal must fail"); - assert_eq!( - invalid_mask.to_string(), - "process.signal_state mask entries must be a valid POSIX signal" - ); - } -} diff --git a/crates/sidecar-core/src/tools.rs b/crates/sidecar-core/src/tools.rs deleted file mode 100644 index a0eff79a8..000000000 --- a/crates/sidecar-core/src/tools.rs +++ /dev/null @@ -1,352 +0,0 @@ -use secure_exec_sidecar_protocol::protocol::RegisterHostCallbacksRequest; -use serde_json::Value; -use std::collections::{BTreeMap, BTreeSet}; -use std::error::Error; -use std::fmt; - -pub const DEFAULT_TOOL_TIMEOUT_MS: u64 = 30_000; -pub const MAX_TOOL_TIMEOUT_MS: u64 = 300_000; -pub const MAX_REGISTERED_TOOLKITS: usize = 64; -pub const MAX_REGISTERED_TOOLS_PER_VM: usize = 256; -pub const MAX_TOOLS_PER_TOOLKIT: usize = 64; -pub const MAX_TOOLKIT_NAME_LENGTH: usize = 64; -pub const MAX_TOOL_NAME_LENGTH: usize = 64; -pub const MAX_TOOL_DESCRIPTION_LENGTH: usize = 200; -pub const MAX_TOOL_SCHEMA_BYTES: usize = 16 * 1024; -pub const MAX_TOOL_SCHEMA_DEPTH: usize = 32; -pub const MAX_TOOL_EXAMPLES_PER_TOOL: usize = 16; -pub const MAX_TOOL_EXAMPLE_INPUT_BYTES: usize = 4 * 1024; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ToolRegistrationError { - InvalidState(String), - Conflict(String), -} - -impl fmt::Display for ToolRegistrationError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InvalidState(message) | Self::Conflict(message) => f.write_str(message), - } - } -} - -impl Error for ToolRegistrationError {} - -pub fn validate_toolkit_registration( - payload: &RegisterHostCallbacksRequest, -) -> Result<(), ToolRegistrationError> { - validate_toolkit_name(&payload.name)?; - if payload.description.is_empty() { - return Err(ToolRegistrationError::InvalidState(format!( - "toolkit {} is missing a description", - payload.name - ))); - } - validate_description_length( - &format!("Toolkit \"{}\"", payload.name), - &payload.description, - )?; - validate_command_aliases("command alias", &payload.command_aliases)?; - validate_command_aliases("registry command alias", &payload.registry_command_aliases)?; - for alias in &payload.command_aliases { - if payload.registry_command_aliases.contains(alias) { - return Err(ToolRegistrationError::InvalidState(format!( - "host callback command alias must not also be a registry command alias: {alias}" - ))); - } - } - if payload.callbacks.is_empty() { - return Err(ToolRegistrationError::InvalidState(format!( - "toolkit {} must define at least one tool", - payload.name - ))); - } - if payload.callbacks.len() > MAX_TOOLS_PER_TOOLKIT { - return Err(ToolRegistrationError::InvalidState(format!( - "toolkit {} defines {} tools, max is {MAX_TOOLS_PER_TOOLKIT}", - payload.name, - payload.callbacks.len() - ))); - } - for (tool_name, tool) in &payload.callbacks { - validate_tool_name(tool_name)?; - if tool.description.is_empty() { - return Err(ToolRegistrationError::InvalidState(format!( - "tool {} in toolkit {} is missing a description", - tool_name, payload.name - ))); - } - validate_description_length( - &format!("Tool \"{}/{}\"", payload.name, tool_name), - &tool.description, - )?; - let tool_input_schema: Value = - serde_json::from_str(&tool.input_schema).map_err(|error| { - ToolRegistrationError::InvalidState(format!( - "Tool \"{}/{}\" input schema is invalid JSON: {error}", - payload.name, tool_name - )) - })?; - validate_tool_schema_shape( - &format!("Tool \"{}/{}\" input schema", payload.name, tool_name), - &tool_input_schema, - )?; - if let Some(timeout_ms) = tool.timeout_ms { - if timeout_ms > MAX_TOOL_TIMEOUT_MS { - return Err(ToolRegistrationError::InvalidState(format!( - "Tool \"{}/{}\" timeout is {timeout_ms}ms, max is {MAX_TOOL_TIMEOUT_MS}ms", - payload.name, tool_name - ))); - } - } - if tool.examples.len() > MAX_TOOL_EXAMPLES_PER_TOOL { - return Err(ToolRegistrationError::InvalidState(format!( - "Tool \"{}/{}\" defines {} examples, max is {MAX_TOOL_EXAMPLES_PER_TOOL}", - payload.name, - tool_name, - tool.examples.len() - ))); - } - for (index, example) in tool.examples.iter().enumerate() { - validate_description_length( - &format!("Tool \"{}/{}\" example {index}", payload.name, tool_name), - &example.description, - )?; - let example_input: Value = serde_json::from_str(&example.input).map_err(|error| { - ToolRegistrationError::InvalidState(format!( - "Tool \"{}/{}\" example {index} input is invalid JSON: {error}", - payload.name, tool_name - )) - })?; - validate_json_byte_length( - &format!( - "Tool \"{}/{}\" example {index} input", - payload.name, tool_name - ), - &example_input, - MAX_TOOL_EXAMPLE_INPUT_BYTES, - )?; - } - } - Ok(()) -} - -pub fn ensure_toolkit_name_available( - toolkits: &BTreeMap, - toolkit_name: &str, -) -> Result<(), ToolRegistrationError> { - if toolkits.contains_key(toolkit_name) { - return Err(ToolRegistrationError::Conflict(format!( - "toolkit already registered: {toolkit_name}" - ))); - } - Ok(()) -} - -pub fn ensure_command_aliases_available( - toolkits: &BTreeMap, - payload: &RegisterHostCallbacksRequest, -) -> Result<(), ToolRegistrationError> { - let requested_command_aliases = payload.command_aliases.iter().collect::>(); - let requested_registry_aliases = payload - .registry_command_aliases - .iter() - .collect::>(); - for toolkit in toolkits.values() { - for alias in &toolkit.command_aliases { - if requested_command_aliases.contains(alias) - || requested_registry_aliases.contains(alias) - { - return Err(ToolRegistrationError::Conflict(format!( - "host callback command alias already registered: {alias}" - ))); - } - } - for alias in &toolkit.registry_command_aliases { - if requested_command_aliases.contains(alias) { - return Err(ToolRegistrationError::Conflict(format!( - "host callback command alias already registered: {alias}" - ))); - } - } - } - Ok(()) -} - -pub fn ensure_toolkit_registry_capacity( - toolkits: &BTreeMap, - payload: &RegisterHostCallbacksRequest, -) -> Result<(), ToolRegistrationError> { - if toolkits.len() >= MAX_REGISTERED_TOOLKITS { - return Err(ToolRegistrationError::InvalidState(format!( - "VM already has {} registered toolkits, max is {MAX_REGISTERED_TOOLKITS}", - toolkits.len() - ))); - } - - let registered_tools = toolkits - .values() - .map(|toolkit| toolkit.callbacks.len()) - .sum::(); - let total_tools = registered_tools - .checked_add(payload.callbacks.len()) - .ok_or_else(|| { - ToolRegistrationError::InvalidState(String::from( - "registered host callback count overflow", - )) - })?; - if total_tools > MAX_REGISTERED_TOOLS_PER_VM { - return Err(ToolRegistrationError::InvalidState(format!( - "VM would have {total_tools} registered host callbacks, max is {MAX_REGISTERED_TOOLS_PER_VM}" - ))); - } - - Ok(()) -} - -pub fn registered_tool_command_names( - toolkits: &BTreeMap, -) -> Vec { - let mut seen = BTreeSet::new(); - let mut commands = Vec::new(); - for toolkit in toolkits.values() { - for alias in toolkit - .registry_command_aliases - .iter() - .chain(toolkit.command_aliases.iter()) - { - if seen.insert(alias.clone()) { - commands.push(alias.clone()); - } - } - } - commands -} - -fn validate_toolkit_name(name: &str) -> Result<(), ToolRegistrationError> { - if name.len() > MAX_TOOLKIT_NAME_LENGTH { - return Err(ToolRegistrationError::InvalidState(format!( - "invalid toolkit name {name}; max length is {MAX_TOOLKIT_NAME_LENGTH}" - ))); - } - if name.is_empty() - || !name - .chars() - .all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '-') - { - return Err(ToolRegistrationError::InvalidState(format!( - "invalid toolkit name {name}; expected lowercase alphanumeric characters plus hyphens" - ))); - } - Ok(()) -} - -fn validate_tool_name(name: &str) -> Result<(), ToolRegistrationError> { - if name.len() > MAX_TOOL_NAME_LENGTH { - return Err(ToolRegistrationError::InvalidState(format!( - "invalid tool name {name}; max length is {MAX_TOOL_NAME_LENGTH}" - ))); - } - if name.is_empty() - || !name - .chars() - .all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '-') - { - return Err(ToolRegistrationError::InvalidState(format!( - "invalid tool name {name}; expected lowercase alphanumeric characters plus hyphens" - ))); - } - Ok(()) -} - -fn validate_command_aliases(label: &str, aliases: &[String]) -> Result<(), ToolRegistrationError> { - let mut seen = BTreeSet::new(); - for alias in aliases { - validate_command_alias(label, alias)?; - if !seen.insert(alias) { - return Err(ToolRegistrationError::InvalidState(format!( - "duplicate host callback {label}: {alias}" - ))); - } - } - Ok(()) -} - -fn validate_command_alias(label: &str, alias: &str) -> Result<(), ToolRegistrationError> { - if alias.is_empty() - || alias == "." - || alias == ".." - || alias.contains('/') - || alias.contains('\0') - { - return Err(ToolRegistrationError::InvalidState(format!( - "invalid host callback {label}: {alias:?}" - ))); - } - Ok(()) -} - -fn validate_description_length( - label: &str, - description: &str, -) -> Result<(), ToolRegistrationError> { - if description.len() > MAX_TOOL_DESCRIPTION_LENGTH { - return Err(ToolRegistrationError::InvalidState(format!( - "{label} description is {} characters, max is {MAX_TOOL_DESCRIPTION_LENGTH}", - description.len() - ))); - } - Ok(()) -} - -fn validate_tool_schema_shape(label: &str, schema: &Value) -> Result<(), ToolRegistrationError> { - validate_json_byte_length(label, schema, MAX_TOOL_SCHEMA_BYTES)?; - validate_json_depth(label, schema, 0) -} - -fn validate_json_byte_length( - label: &str, - value: &Value, - limit: usize, -) -> Result<(), ToolRegistrationError> { - let length = serde_json::to_vec(value) - .map_err(|error| { - ToolRegistrationError::InvalidState(format!("{label} is invalid JSON: {error}")) - })? - .len(); - if length > limit { - return Err(ToolRegistrationError::InvalidState(format!( - "{label} is {length} bytes, max is {limit}" - ))); - } - Ok(()) -} - -fn validate_json_depth( - label: &str, - value: &Value, - depth: usize, -) -> Result<(), ToolRegistrationError> { - if depth > MAX_TOOL_SCHEMA_DEPTH { - return Err(ToolRegistrationError::InvalidState(format!( - "{label} exceeds max JSON depth {MAX_TOOL_SCHEMA_DEPTH}" - ))); - } - - match value { - Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => Ok(()), - Value::Array(values) => { - for value in values { - validate_json_depth(label, value, depth + 1)?; - } - Ok(()) - } - Value::Object(object) => { - for value in object.values() { - validate_json_depth(label, value, depth + 1)?; - } - Ok(()) - } - } -} diff --git a/crates/sidecar-core/src/vm_fetch.rs b/crates/sidecar-core/src/vm_fetch.rs deleted file mode 100644 index 8f2282d5d..000000000 --- a/crates/sidecar-core/src/vm_fetch.rs +++ /dev/null @@ -1,389 +0,0 @@ -use crate::SidecarCoreError; -use base64::Engine as _; -use serde_json::{json, Value}; -use std::collections::BTreeMap; - -// Keep raw loopback fetch buffers inside the default sidecar wire frame budget. -pub const VM_FETCH_BUFFER_LIMIT_BYTES: usize = 1024 * 1024; - -pub fn parse_kernel_http_fetch_response( - buffer: &[u8], - peer_closed: bool, - url: &str, -) -> Result, SidecarCoreError> { - let Some(header_end) = find_http_header_end(buffer) else { - return Ok(None); - }; - let header_bytes = &buffer[..header_end]; - let head = String::from_utf8_lossy(header_bytes); - let mut lines = head.split("\r\n"); - let status_line = lines.next().unwrap_or_default(); - let mut status_parts = status_line.splitn(3, ' '); - let version = status_parts.next().unwrap_or_default(); - if !version.starts_with("HTTP/") { - return Err(SidecarCoreError::new(format!( - "invalid vm.fetch HTTP response status line: {status_line}" - ))); - } - let status = status_parts - .next() - .ok_or_else(|| { - SidecarCoreError::new(format!( - "invalid vm.fetch HTTP response status line: {status_line}" - )) - })? - .parse::() - .map_err(|error| { - SidecarCoreError::new(format!( - "invalid vm.fetch HTTP response status code in {status_line:?}: {error}" - )) - })?; - let status_text = status_parts.next().unwrap_or_default(); - let mut headers = Vec::new(); - let mut raw_headers = Vec::new(); - let mut content_length = None; - let mut transfer_encoding_values = Vec::new(); - for line in lines { - if line.is_empty() { - continue; - } - let Some((name, value)) = line.split_once(':') else { - return Err(SidecarCoreError::new(format!( - "invalid vm.fetch HTTP response header line: {line}" - ))); - }; - let value = value.trim().to_owned(); - let normalized = name.to_ascii_lowercase(); - if normalized == "content-length" { - content_length = Some(value.parse::().map_err(|error| { - SidecarCoreError::new(format!( - "invalid vm.fetch Content-Length header {value:?}: {error}" - )) - })?); - } else if normalized == "transfer-encoding" { - transfer_encoding_values.push(value.clone()); - } - headers.push(json!([normalized, value.clone()])); - raw_headers.push(Value::String(name.to_owned())); - raw_headers.push(Value::String(value)); - } - - let body_start = header_end + 4; - let transfer_encoding = transfer_encoding_tokens(&transfer_encoding_values); - let is_chunked = transfer_encoding.iter().any(|token| token == "chunked"); - let body = if is_chunked { - if content_length.is_some() { - return Err(SidecarCoreError::new( - "vm.fetch HTTP response cannot include both Transfer-Encoding: chunked and Content-Length", - )); - } - if transfer_encoding.len() != 1 { - return Err(SidecarCoreError::new(format!( - "unsupported vm.fetch Transfer-Encoding: {}", - transfer_encoding.join(", ") - ))); - } - let Some(decoded) = decode_kernel_http_chunked_body(&buffer[body_start..])? else { - return Ok(None); - }; - decoded - } else if !transfer_encoding.is_empty() { - return Err(SidecarCoreError::new(format!( - "unsupported vm.fetch Transfer-Encoding: {}", - transfer_encoding.join(", ") - ))); - } else if let Some(content_length) = content_length { - let body_end = body_start.saturating_add(content_length); - if buffer.len() < body_end { - return Ok(None); - } - buffer[body_start..body_end].to_vec() - } else if peer_closed { - buffer[body_start..].to_vec() - } else { - return Ok(None); - }; - - serde_json::to_string(&json!({ - "status": status, - "statusText": status_text, - "headers": headers, - "rawHeaders": raw_headers, - "body": base64::engine::general_purpose::STANDARD.encode(&body), - "bodyEncoding": "base64", - "url": url, - })) - .map(Some) - .map_err(|error| SidecarCoreError::new(format!("ERR_AGENTOS_NODE_SYNC_RPC: {error}"))) -} - -pub fn serialize_kernel_http_fetch_request( - port: u16, - path: &str, - method: &str, - headers_json: &str, - body: Option<&str>, -) -> Result, SidecarCoreError> { - let headers = parse_vm_fetch_headers(headers_json)?; - let method = if method.is_empty() { "GET" } else { method }; - let target_path = if path.starts_with('/') { - path.to_owned() - } else { - format!("/{path}") - }; - let mut lines = vec![format!("{method} {target_path} HTTP/1.1")]; - let mut has_host = false; - let mut has_connection = false; - let mut has_content_length = false; - - for (name, values) in &headers { - match name.as_str() { - "host" => has_host = true, - "connection" => has_connection = true, - "content-length" => has_content_length = true, - _ => {} - } - lines.push(format!("{name}: {}", values.join(", "))); - } - if !has_host { - lines.push(format!("Host: 127.0.0.1:{port}")); - } - if !has_connection { - lines.push(String::from("Connection: close")); - } - let body = body.unwrap_or("").as_bytes(); - if !has_content_length && !body.is_empty() { - lines.push(format!("Content-Length: {}", body.len())); - } - lines.push(String::new()); - lines.push(String::new()); - - let mut request = lines.join("\r\n").into_bytes(); - request.extend_from_slice(body); - Ok(request) -} - -pub fn ensure_vm_fetch_response_within_limit( - response_json: &str, - operation: &str, - limit: usize, -) -> Result<(), SidecarCoreError> { - let size = response_json.len(); - if size > limit { - return Err(SidecarCoreError::new(format!( - "{operation} payload is {size} bytes, limit is {limit}" - ))); - } - Ok(()) -} - -pub fn ensure_vm_fetch_raw_response_buffer_within_limit( - size: usize, - operation: &str, -) -> Result<(), SidecarCoreError> { - if size > VM_FETCH_BUFFER_LIMIT_BYTES { - return Err(SidecarCoreError::new(format!( - "{operation} raw response buffer is {size} bytes, limit is {VM_FETCH_BUFFER_LIMIT_BYTES}" - ))); - } - Ok(()) -} - -fn parse_vm_fetch_headers( - headers_json: &str, -) -> Result>, SidecarCoreError> { - let headers: BTreeMap = serde_json::from_str(headers_json).map_err(|error| { - SidecarCoreError::new(format!("vm.fetch headers_json must be valid JSON: {error}")) - })?; - let mut normalized = BTreeMap::>::new(); - for (raw_name, value) in headers { - let values = match value { - Value::String(text) => vec![text], - Value::Array(values) => values - .into_iter() - .map(|entry| { - entry.as_str().map(str::to_owned).ok_or_else(|| { - SidecarCoreError::new(format!( - "vm.fetch header {raw_name} must contain only strings" - )) - }) - }) - .collect::, _>>()?, - other => { - return Err(SidecarCoreError::new(format!( - "vm.fetch header {raw_name} must be a string or string array, received {other}" - ))); - } - }; - normalized - .entry(raw_name.to_ascii_lowercase()) - .or_default() - .extend(values); - } - Ok(normalized) -} - -fn find_http_header_end(buffer: &[u8]) -> Option { - buffer.windows(4).position(|window| window == b"\r\n\r\n") -} - -fn find_crlf(buffer: &[u8], start: usize) -> Option { - buffer - .get(start..)? - .windows(2) - .position(|window| window == b"\r\n") - .map(|offset| start + offset) -} - -fn transfer_encoding_tokens(values: &[String]) -> Vec { - values - .iter() - .flat_map(|value| value.split(',')) - .map(|token| token.trim().to_ascii_lowercase()) - .filter(|token| !token.is_empty()) - .collect() -} - -fn decode_kernel_http_chunked_body(buffer: &[u8]) -> Result>, SidecarCoreError> { - let mut offset = 0; - let mut body = Vec::new(); - loop { - let Some(line_end) = find_crlf(buffer, offset) else { - return Ok(None); - }; - let size_line = std::str::from_utf8(&buffer[offset..line_end]).map_err(|error| { - SidecarCoreError::new(format!( - "invalid vm.fetch chunk size line encoding: {error}" - )) - })?; - let size_part = size_line.split(';').next().unwrap_or_default(); - if size_part.is_empty() || !size_part.bytes().all(|byte| byte.is_ascii_hexdigit()) { - return Err(SidecarCoreError::new(format!( - "invalid vm.fetch chunk size line: {size_line:?}" - ))); - } - let chunk_size = usize::from_str_radix(size_part, 16).map_err(|error| { - SidecarCoreError::new(format!( - "invalid vm.fetch chunk size {size_part:?}: {error}" - )) - })?; - let chunk_start = line_end + 2; - let chunk_end = chunk_start - .checked_add(chunk_size) - .ok_or_else(|| SidecarCoreError::new("vm.fetch chunk size overflow"))?; - if chunk_size > 0 { - let chunk_terminator_end = chunk_end - .checked_add(2) - .ok_or_else(|| SidecarCoreError::new("vm.fetch chunk terminator overflow"))?; - if chunk_terminator_end > buffer.len() { - return Ok(None); - } - if buffer.get(chunk_end..chunk_terminator_end) != Some(b"\r\n") { - return Err(SidecarCoreError::new("invalid vm.fetch chunk terminator")); - } - body.extend_from_slice(&buffer[chunk_start..chunk_end]); - offset = chunk_terminator_end; - continue; - } - - if buffer.get(chunk_start..chunk_start + 2) == Some(b"\r\n") { - return Ok(Some(body)); - } - let Some(trailer_end) = find_http_header_end(&buffer[chunk_start..]) else { - return Ok(None); - }; - let trailer_bytes = &buffer[chunk_start..chunk_start + trailer_end]; - let trailers = String::from_utf8_lossy(trailer_bytes); - for line in trailers.split("\r\n") { - if line.is_empty() { - continue; - } - if line.starts_with(' ') || line.starts_with('\t') || !line.contains(':') { - return Err(SidecarCoreError::new(format!( - "invalid vm.fetch chunk trailer line: {line}" - ))); - } - } - return Ok(Some(body)); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use serde_json::Value; - - #[test] - fn parses_content_length_response() { - let response = parse_kernel_http_fetch_response( - b"HTTP/1.1 201 Created\r\nContent-Length: 5\r\nX-Test: ok\r\n\r\nhello", - false, - "http://127.0.0.1:8080/hello", - ) - .expect("parse response") - .expect("complete response"); - let value: Value = serde_json::from_str(&response).expect("response json"); - - assert_eq!(value["status"], 201); - assert_eq!(value["statusText"], "Created"); - assert_eq!(value["body"], "aGVsbG8="); - assert_eq!(value["url"], "http://127.0.0.1:8080/hello"); - } - - #[test] - fn serializes_loopback_fetch_request() { - let request = serialize_kernel_http_fetch_request( - 3000, - "submit", - "POST", - r#"{"x-test":["a","b"]}"#, - Some("hello"), - ) - .expect("serialize request"); - - assert_eq!( - String::from_utf8(request).expect("utf8 request"), - "POST /submit HTTP/1.1\r\nx-test: a, b\r\nHost: 127.0.0.1:3000\r\nConnection: close\r\nContent-Length: 5\r\n\r\nhello" - ); - } - - #[test] - fn decodes_chunked_response_body() { - let response = parse_kernel_http_fetch_response( - b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n", - false, - "http://127.0.0.1:8080/chunked", - ) - .expect("parse response") - .expect("complete response"); - let value: Value = serde_json::from_str(&response).expect("response json"); - - assert_eq!(value["body"], "aGVsbG8="); - } - - #[test] - fn waits_for_incomplete_body() { - let response = parse_kernel_http_fetch_response( - b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhe", - false, - "http://127.0.0.1:8080/partial", - ) - .expect("parse response"); - - assert!(response.is_none()); - } - - #[test] - fn rejects_invalid_chunked_content_length_combination() { - let error = parse_kernel_http_fetch_response( - b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n", - false, - "http://127.0.0.1:8080/bad", - ) - .expect_err("response should be invalid"); - - assert!(error - .to_string() - .contains("cannot include both Transfer-Encoding: chunked and Content-Length")); - } -} diff --git a/crates/sidecar-protocol/Cargo.toml b/crates/sidecar-protocol/Cargo.toml index ec54cab67..ca82d1468 100644 --- a/crates/sidecar-protocol/Cargo.toml +++ b/crates/sidecar-protocol/Cargo.toml @@ -4,17 +4,10 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Shared Secure Exec sidecar wire protocol and frame helpers" +description = "secure-exec-sidecar-protocol compatibility shim for agentos-sidecar-protocol" [lib] name = "secure_exec_sidecar_protocol" [dependencies] -secure-exec-vm-config = { workspace = true } -serde = { version = "1.0", features = ["derive"] } -serde_bare = "0.5" -serde_json = "1.0" -vbare = { workspace = true } - -[build-dependencies] -vbare-compiler = { workspace = true } +agentos_sidecar_protocol = { package = "agentos-sidecar-protocol", path = "../../../agentos/crates/sidecar-protocol", version = "0.0.1" } diff --git a/crates/sidecar-protocol/build.rs b/crates/sidecar-protocol/build.rs deleted file mode 100644 index 1b273ca2f..000000000 --- a/crates/sidecar-protocol/build.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::{env, fs, path::PathBuf}; - -fn main() { - let manifest_dir = - PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set")); - let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR must be set")); - let source_schema = manifest_dir - .join("protocol") - .join("secure_exec_sidecar_v1.bare"); - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed={}", source_schema.display()); - - let schema_dir = out_dir.join("protocol-schema"); - fs::create_dir_all(&schema_dir).expect("failed to create generated protocol schema dir"); - fs::copy(&source_schema, schema_dir.join("v1.bare")).unwrap_or_else(|error| { - panic!( - "failed to stage protocol schema from {}: {}", - source_schema.display(), - error - ) - }); - - let cfg = vbare_compiler::Config::default(); - vbare_compiler::process_schemas_with_config(&schema_dir, &cfg) - .expect("failed to generate sidecar protocol from BARE schema"); -} diff --git a/crates/sidecar-protocol/protocol/README.md b/crates/sidecar-protocol/protocol/README.md deleted file mode 100644 index b6b747970..000000000 --- a/crates/sidecar-protocol/protocol/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Sidecar BARE Migration Plan - -`secure_exec_sidecar_v1.bare` is the canonical schema for the sidecar wire protocol value carried on native transports. It covers every current `request`, `response`, `event`, `sidecar_request`, and `sidecar_response` frame shape from [`crates/sidecar-protocol/src/protocol.rs`](../src/protocol.rs). - -## Framing - -The native sidecar transport keeps the current framing boundary during migration: - -- 4-byte big-endian length prefix -- one encoded `ProtocolFrame` payload immediately after the prefix - -US-083 and US-084 should replace only the payload codec first. They should not redesign the outer length prefix at the same time, because the current stdio/native-process tests and bridge code already rely on that framing contract. - -## Compatibility Rules - -The migration keeps the current semantic invariants unchanged across codecs: - -- `ProtocolSchema.name` is `secure-exec-sidecar` -- `ProtocolSchema.version` is `7` -- host-originated `request_id` values stay positive -- sidecar-originated `request_id` values stay negative -- ownership scope rules and response-correlation rules stay exactly the same -- `max_frame_bytes` and duplicate-response hardening stay transport-level requirements, not JSON-specific behavior - -## JSON Boundary - -The current protocol still has several fields modeled as `serde_json::Value` on the Rust side and `unknown`/structured JS values on the TypeScript side. BARE v1 represents those fields as `JsonUtf8`: - -- UTF-8 JSON text inside the BARE field -- canonicalized by the codec before hashing/comparison in tests -- intentionally temporary until later protocol work replaces them with BARE-native typed payloads - -This applies to fields such as session config blobs, ACP notifications, mount plugin configs, tool schemas/inputs, JS bridge arguments, and tool results. - -## Rollout Plan - -1. US-082: lock the schema and this plan in repo, with tests that fail if Rust adds a new frame payload without updating the schema. -2. US-083: add a Rust BARE codec alongside the existing JSON codec while preserving the current 4-byte big-endian frame prefix. -3. US-083: make the Rust decoder dual-stack by inspecting the first payload byte after the length prefix. - JSON frames begin with `{` today, while BARE frames begin with a union tag byte/varint, so the decoder can distinguish the two without an extra wrapper frame. -4. US-083: once a connection's first successfully decoded frame is known, pin the connection to that codec for all later frames on that transport. -5. US-084: teach the TypeScript native sidecar client and related bridge transports to emit and decode the BARE payload form using the same schema. -6. US-084: keep JSON decode support only for the migration window; once both sides default to BARE and the targeted tests are green, delete JSON encoding and the dual-stack sniffing path. - -## Normalization Notes - -BARE does not have Serde's "omitted but defaults to empty list/map" behavior. The codec should therefore normalize these fields explicitly: - -- omitted/defaulted collection fields in JSON become empty lists/maps in BARE -- optional fields remain explicit `optional` values -- response payloads that are currently "rejected" remain valid correlated responses, just as they do in `ResponseTracker` - -That normalization rule is part of schema compatibility and should be preserved in tests when the codec lands. diff --git a/crates/sidecar-protocol/protocol/secure_exec_sidecar_v1.bare b/crates/sidecar-protocol/protocol/secure_exec_sidecar_v1.bare deleted file mode 100644 index 99c37838d..000000000 --- a/crates/sidecar-protocol/protocol/secure_exec_sidecar_v1.bare +++ /dev/null @@ -1,883 +0,0 @@ -# Secure Exec sidecar protocol schema, version 1. -# This schema is generator-ready: numeric ordinals are intentionally omitted -# and type blocks are ordered before first use. - -type JsonUtf8 str - -type ProtocolSchema struct { - name: str - version: u16 -} - -type RequestId i64 - -type ExtEnvelope struct { - namespace: str - payload: data -} - -type ConnectionOwnership struct { - connectionId: str -} - -type SessionOwnership struct { - connectionId: str - sessionId: str -} - -type VmOwnership struct { - connectionId: str - sessionId: str - vmId: str -} - -type OwnershipScope union { - ConnectionOwnership | - SessionOwnership | - VmOwnership -} - -type AuthenticateRequest struct { - clientName: str - authToken: str - protocolVersion: u16 - bridgeVersion: u32 -} - -type SidecarPlacementShared struct { - pool: optional -} - -type SidecarPlacementExplicit struct { - sidecarId: str -} - -type SidecarPlacement union { - SidecarPlacementShared | - SidecarPlacementExplicit -} - -type OpenSessionRequest struct { - placement: SidecarPlacement - metadata: map -} - -type GuestRuntimeKind enum { - JAVA_SCRIPT - PYTHON - WEB_ASSEMBLY -} - -type RootFilesystemMode enum { - EPHEMERAL - READ_ONLY -} - -type RootFilesystemEntryKind enum { - FILE - DIRECTORY - SYMLINK -} - -type RootFilesystemEntryEncoding enum { - UTF8 - BASE64 -} - -type RootFilesystemEntry struct { - path: str - kind: RootFilesystemEntryKind - mode: optional - uid: optional - gid: optional - content: optional - encoding: optional - target: optional - executable: bool -} - -type SnapshotRootFilesystemLower struct { - entries: list -} - -type BundledBaseFilesystemLower void - -type RootFilesystemLowerDescriptor union { - SnapshotRootFilesystemLower | - BundledBaseFilesystemLower -} - -type RootFilesystemDescriptor struct { - mode: RootFilesystemMode - disableDefaultBaseLayer: bool - lowers: list - bootstrapEntries: list -} - -type PermissionMode enum { - ALLOW - ASK - DENY -} - -type FsPermissionRule struct { - mode: PermissionMode - operations: list - paths: list -} - -type FsPermissionRuleSet struct { - default: optional - rules: list -} - -type FsPermissionScope union { - PermissionMode | - FsPermissionRuleSet -} - -type PatternPermissionRule struct { - mode: PermissionMode - operations: list - patterns: list -} - -type PatternPermissionRuleSet struct { - default: optional - rules: list -} - -type PatternPermissionScope union { - PermissionMode | - PatternPermissionRuleSet -} - -type PermissionsPolicy struct { - fs: optional - network: optional - childProcess: optional - process: optional - env: optional - binding: optional -} - -type CreateVmRequest struct { - runtime: GuestRuntimeKind - config: JsonUtf8 -} - -type DisposeReason enum { - REQUESTED - CONNECTION_CLOSED - HOST_SHUTDOWN -} - -type DisposeVmRequest struct { - reason: DisposeReason -} - -type BootstrapRootFilesystemRequest struct { - entries: list -} - -type MountPluginDescriptor struct { - id: str - config: JsonUtf8 -} - -type MountDescriptor struct { - guestPath: str - readOnly: bool - plugin: MountPluginDescriptor -} - -type SoftwareDescriptor struct { - packageName: str - root: str -} - -type ProjectedModuleDescriptor struct { - packageName: str - entrypoint: str -} - -type WasmPermissionTier enum { - FULL - READ_WRITE - READ_ONLY - ISOLATED -} - -# agentOS package descriptor. The sidecar reads `agentos-package.json`, projects -# the self-contained package read-only under `//`, -# and links its `bin/` commands onto $PATH. `tar`/`dir` are trusted host paths -# (the client configures its own VM); the sidecar is the host-side TCB that builds -# the staging tree. New clients send `tar`; `dir` remains accepted for local tests -# and transition fixtures. -type PackageDescriptor struct { - dir: optional - tar: optional -} - -type AgentosProjectedAgent struct { - id: str - acpEntrypoint: str - adapterEntrypoint: str -} - -type LinkPackageRequest struct { - package: PackageDescriptor -} - -type PackageCommands struct { - packageName: str - commands: list -} - -type ProvidedCommandsRequest void - -type ProvidedCommandsResponse struct { - packages: list -} - -type ProjectedCommand struct { - name: str - guestPath: str -} - -type PackageLinkedResponse struct { - projectedCommands: list - agents: list -} - -type ConfigureVmRequest struct { - mounts: list - software: list - permissions: optional - moduleAccessCwd: optional - instructions: list - projectedModules: list - commandPermissions: map - loopbackExemptPorts: list - packages: list - packagesMountAt: str - bootstrapCommands: list - toolShimCommands: list -} - -type RegisteredHostCallbackExample struct { - description: str - input: JsonUtf8 -} - -type RegisteredHostCallbackDefinition struct { - description: str - inputSchema: JsonUtf8 - timeoutMs: optional - examples: list -} - -type RegisterHostCallbacksRequest struct { - name: str - description: str - commandAliases: list - registryCommandAliases: list - callbacks: map -} - -type CreateLayerRequest void - -type SealLayerRequest struct { - layerId: str -} - -type ImportSnapshotRequest struct { - entries: list -} - -type ExportSnapshotRequest struct { - layerId: str -} - -type CreateOverlayRequest struct { - mode: RootFilesystemMode - upperLayerId: optional - lowerLayerIds: list -} - -type GuestFilesystemOperation enum { - READ_FILE - WRITE_FILE - CREATE_DIR - MKDIR - EXISTS - STAT - LSTAT - READ_DIR - READ_DIR_RECURSIVE - REMOVE_FILE - REMOVE_DIR - REMOVE - COPY - MOVE - RENAME - REALPATH - SYMLINK - READ_LINK - LINK - CHMOD - CHOWN - UTIMES - TRUNCATE - PREAD - PWRITE -} - -type GuestFilesystemCallRequest struct { - operation: GuestFilesystemOperation - path: str - destinationPath: optional - target: optional - content: optional - encoding: optional - recursive: bool - maxDepth: optional - mode: optional - uid: optional - gid: optional - atimeMs: optional - mtimeMs: optional - len: optional - offset: optional -} - -type GuestKernelCallRequest struct { - executionId: str - operation: str - payload: data -} - -type SnapshotRootFilesystemRequest void - -type ExecuteRequest struct { - processId: str - command: optional - runtime: optional - entrypoint: optional - args: list - env: map - cwd: optional - wasmPermissionTier: optional -} - -type WriteStdinRequest struct { - processId: str - chunk: data -} - -type ResizePtyRequest struct { - processId: str - cols: u16 - rows: u16 -} - -type CloseStdinRequest struct { - processId: str -} - -type KillProcessRequest struct { - processId: str - signal: str -} - -type GetProcessSnapshotRequest void - -type GetResourceSnapshotRequest void - -type FindListenerRequest struct { - host: optional - port: optional - path: optional -} - -type FindBoundUdpRequest struct { - host: optional - port: optional -} - -type GetSignalStateRequest struct { - processId: str -} - -type GetZombieTimerCountRequest void - -type FilesystemOperation enum { - READ - WRITE - STAT - READ_DIR - MKDIR - REMOVE - RENAME -} - -type HostFilesystemCallRequest struct { - operation: FilesystemOperation - path: str - payloadSizeBytes: u64 -} - -type PersistenceLoadRequest struct { - key: str -} - -type PersistenceFlushRequest struct { - key: str - payloadSizeBytes: u64 -} - -type VmFetchRequest struct { - port: u16 - method: str - path: str - headersJson: str - body: optional -} - -type RequestPayload union { - AuthenticateRequest | - OpenSessionRequest | - CreateVmRequest | - DisposeVmRequest | - BootstrapRootFilesystemRequest | - ConfigureVmRequest | - RegisterHostCallbacksRequest | - CreateLayerRequest | - SealLayerRequest | - ImportSnapshotRequest | - ExportSnapshotRequest | - CreateOverlayRequest | - GuestFilesystemCallRequest | - SnapshotRootFilesystemRequest | - ExecuteRequest | - WriteStdinRequest | - CloseStdinRequest | - KillProcessRequest | - GetProcessSnapshotRequest | - FindListenerRequest | - FindBoundUdpRequest | - GetSignalStateRequest | - GetZombieTimerCountRequest | - HostFilesystemCallRequest | - PersistenceLoadRequest | - PersistenceFlushRequest | - VmFetchRequest | - ExtEnvelope | - GuestKernelCallRequest | - ResizePtyRequest | - GetResourceSnapshotRequest | - LinkPackageRequest | - ProvidedCommandsRequest -} - -type RequestFrame struct { - schema: ProtocolSchema - requestId: RequestId - ownership: OwnershipScope - payload: RequestPayload -} - -type AuthenticatedResponse struct { - sidecarId: str - connectionId: str - maxFrameBytes: u32 -} - -type SessionOpenedResponse struct { - sessionId: str - ownerConnectionId: str -} - -type VmCreatedResponse struct { - vmId: str -} - -type VmDisposedResponse struct { - vmId: str -} - -type RootFilesystemBootstrappedResponse struct { - entryCount: u32 -} - -type VmConfiguredResponse struct { - appliedMounts: u32 - appliedSoftware: u32 - projectedCommands: list - agents: list -} - -type HostCallbacksRegisteredResponse struct { - registration: str - commandCount: u32 -} - -type LayerCreatedResponse struct { - layerId: str -} - -type LayerSealedResponse struct { - layerId: str -} - -type SnapshotImportedResponse struct { - layerId: str -} - -type SnapshotExportedResponse struct { - layerId: str - entries: list -} - -type OverlayCreatedResponse struct { - layerId: str -} - -type GuestFilesystemStat struct { - mode: u32 - size: u64 - blocks: u64 - dev: u64 - rdev: u64 - isDirectory: bool - isSymbolicLink: bool - atimeMs: u64 - mtimeMs: u64 - ctimeMs: u64 - birthtimeMs: u64 - ino: u64 - nlink: u64 - uid: u32 - gid: u32 -} - -type GuestDirEntry struct { - name: str - path: str - isDirectory: bool - isSymbolicLink: bool - size: u64 -} - -type GuestFilesystemResultResponse struct { - operation: GuestFilesystemOperation - path: str - content: optional - encoding: optional - entries: optional> - stat: optional - exists: optional - target: optional -} - -type GuestKernelResultResponse struct { - payload: data -} - -type RootFilesystemSnapshotResponse struct { - entries: list -} - -type ProcessStartedResponse struct { - processId: str - pid: optional -} - -type StdinWrittenResponse struct { - processId: str - acceptedBytes: u64 -} - -type PtyResizedResponse struct { - processId: str - cols: u16 - rows: u16 -} - -type StdinClosedResponse struct { - processId: str -} - -type ProcessKilledResponse struct { - processId: str -} - -type ProcessSnapshotStatus enum { - RUNNING - EXITED - STOPPED -} - -type ProcessSnapshotEntry struct { - processId: str - pid: u32 - ppid: u32 - pgid: u32 - sid: u32 - driver: str - command: str - args: list - cwd: str - status: ProcessSnapshotStatus - exitCode: optional -} - -type ProcessSnapshotResponse struct { - processes: list -} - -type QueueSnapshotEntry struct { - name: str - category: str - depth: u64 - highWater: u64 - capacity: u64 - fillPercent: u64 -} - -type ResourceSnapshotResponse struct { - runningProcesses: u64 - exitedProcesses: u64 - fdTables: u64 - openFds: u64 - pipes: u64 - pipeBufferedBytes: u64 - ptys: u64 - ptyBufferedInputBytes: u64 - ptyBufferedOutputBytes: u64 - sockets: u64 - socketListeners: u64 - socketConnections: u64 - socketBufferedBytes: u64 - socketDatagramQueueLen: u64 - queueSnapshots: list -} - -type SocketStateEntry struct { - processId: str - host: optional - port: optional - path: optional -} - -type ListenerSnapshotResponse struct { - listener: optional -} - -type BoundUdpSnapshotResponse struct { - socket: optional -} - -type SignalDispositionAction enum { - DEFAULT - IGNORE - USER -} - -type SignalHandlerRegistration struct { - action: SignalDispositionAction - mask: list - flags: u32 -} - -type SignalStateResponse struct { - processId: str - handlers: map -} - -type ZombieTimerCountResponse struct { - count: u64 -} - -type FilesystemResultResponse struct { - operation: FilesystemOperation - status: str - payloadSizeBytes: u64 -} - -type PermissionDecisionResponse struct { - capability: str - decision: PermissionMode -} - -type PersistenceStateResponse struct { - key: str - found: bool - payloadSizeBytes: u64 -} - -type PersistenceFlushedResponse struct { - key: str - committedBytes: u64 -} - -type RejectedResponse struct { - code: str - message: str -} - -type VmFetchResponse struct { - responseJson: str -} - -type ResponsePayload union { - AuthenticatedResponse | - SessionOpenedResponse | - VmCreatedResponse | - VmDisposedResponse | - RootFilesystemBootstrappedResponse | - VmConfiguredResponse | - HostCallbacksRegisteredResponse | - LayerCreatedResponse | - LayerSealedResponse | - SnapshotImportedResponse | - SnapshotExportedResponse | - OverlayCreatedResponse | - GuestFilesystemResultResponse | - RootFilesystemSnapshotResponse | - ProcessStartedResponse | - StdinWrittenResponse | - StdinClosedResponse | - ProcessKilledResponse | - ProcessSnapshotResponse | - ListenerSnapshotResponse | - BoundUdpSnapshotResponse | - SignalStateResponse | - ZombieTimerCountResponse | - FilesystemResultResponse | - PermissionDecisionResponse | - PersistenceStateResponse | - PersistenceFlushedResponse | - RejectedResponse | - VmFetchResponse | - ExtEnvelope | - GuestKernelResultResponse | - PtyResizedResponse | - ResourceSnapshotResponse | - PackageLinkedResponse | - ProvidedCommandsResponse -} - -type ResponseFrame struct { - schema: ProtocolSchema - requestId: RequestId - ownership: OwnershipScope - payload: ResponsePayload -} - -type VmLifecycleState enum { - CREATING - READY - DISPOSING - DISPOSED - FAILED -} - -type VmLifecycleEvent struct { - state: VmLifecycleState -} - -type StreamChannel enum { - STDOUT - STDERR -} - -type ProcessOutputEvent struct { - processId: str - channel: StreamChannel - chunk: data -} - -type ProcessExitedEvent struct { - processId: str - exitCode: i32 -} - -type StructuredEvent struct { - name: str - detail: map -} - -type EventPayload union { - VmLifecycleEvent | - ProcessOutputEvent | - ProcessExitedEvent | - StructuredEvent | - ExtEnvelope -} - -type EventFrame struct { - schema: ProtocolSchema - ownership: OwnershipScope - payload: EventPayload -} - -type HostCallbackRequest struct { - invocationId: str - callbackKey: str - input: JsonUtf8 - timeoutMs: u64 -} - -type JsBridgeCallRequest struct { - callId: str - mountId: str - operation: str - args: JsonUtf8 -} - -type SidecarRequestPayload union { - HostCallbackRequest | - JsBridgeCallRequest | - ExtEnvelope -} - -type SidecarRequestFrame struct { - schema: ProtocolSchema - requestId: RequestId - ownership: OwnershipScope - payload: SidecarRequestPayload -} - -type HostCallbackResultResponse struct { - invocationId: str - result: optional - error: optional -} - -type JsBridgeResultResponse struct { - callId: str - result: optional - error: optional -} - -type SidecarResponsePayload union { - HostCallbackResultResponse | - JsBridgeResultResponse | - ExtEnvelope -} - -type SidecarResponseFrame struct { - schema: ProtocolSchema - requestId: RequestId - ownership: OwnershipScope - payload: SidecarResponsePayload -} - -type ProtocolFrame union { - RequestFrame | - ResponseFrame | - EventFrame | - SidecarRequestFrame | - SidecarResponseFrame -} diff --git a/crates/sidecar-protocol/src/generated_protocol.rs b/crates/sidecar-protocol/src/generated_protocol.rs deleted file mode 100644 index 3b0c75f39..000000000 --- a/crates/sidecar-protocol/src/generated_protocol.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Generated protocol surface produced by `vbare_compiler` (see `build.rs`). -// The generator emits type aliases and enum variant names verbatim from the -// BARE schema, so some are unused here and some share a common postfix; these -// lints are silenced for the generated code rather than editing build output. -#![allow(dead_code)] -#![allow(clippy::enum_variant_names)] - -include!(concat!(env!("OUT_DIR"), "/combined_imports.rs")); diff --git a/crates/sidecar-protocol/src/lib.rs b/crates/sidecar-protocol/src/lib.rs index 7929ac051..ba867c9d6 100644 --- a/crates/sidecar-protocol/src/lib.rs +++ b/crates/sidecar-protocol/src/lib.rs @@ -1,10 +1,3 @@ -#![forbid(unsafe_code)] -// Wire enums intentionally have wide size variance (small acks next to bulky -// payload variants); boxing them is a wire-adjacent refactor tracked separately. -#![allow(clippy::large_enum_variant, clippy::result_large_err)] +//! Compatibility shim for `agentos-sidecar-protocol`. -//! Shared Secure Exec sidecar wire protocol surface. - -pub mod generated_protocol; -pub mod protocol; -pub mod wire; +pub use agentos_sidecar_protocol::*; diff --git a/crates/sidecar-protocol/src/protocol.rs b/crates/sidecar-protocol/src/protocol.rs deleted file mode 100644 index a82bab77d..000000000 --- a/crates/sidecar-protocol/src/protocol.rs +++ /dev/null @@ -1,2774 +0,0 @@ -use crate::generated_protocol::v1 as generated_protocol; -use serde::de::{self, SeqAccess, Visitor}; -use serde::ser::SerializeTuple; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serde_json::Value; -use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; -use std::error::Error; -use std::fmt; - -pub use crate::wire::{OwnershipRequirement, ProtocolCodecError, RequestDirection}; - -pub const PROTOCOL_NAME: &str = crate::wire::PROTOCOL_NAME; -pub const PROTOCOL_VERSION: u16 = crate::wire::PROTOCOL_VERSION; -pub const DEFAULT_MAX_FRAME_BYTES: usize = crate::wire::DEFAULT_MAX_FRAME_BYTES; -pub const DEFAULT_COMPLETED_RESPONSE_CAP: usize = 10_000; -pub type RequestId = crate::wire::RequestId; -pub type ExtEnvelope = crate::wire::ExtEnvelope; - -fn serialize_bare_newtype_tag(serializer: S, tag: u64, payload: &T) -> Result -where - S: Serializer, - T: Serialize, -{ - let mut tuple = serializer.serialize_tuple(2)?; - tuple.serialize_element(&serde_bare::Uint(tag))?; - tuple.serialize_element(payload)?; - tuple.end() -} - -/// Convert the compatibility protocol frame into the generated wire frame. -pub fn to_generated_protocol_frame( - frame: &ProtocolFrame, -) -> Result { - Ok(match frame { - ProtocolFrame::Request(frame) => { - generated_protocol::ProtocolFrame::RequestFrame(generated_protocol::RequestFrame { - schema: to_generated_protocol_schema(&frame.schema), - request_id: frame.request_id, - ownership: to_generated_ownership_scope(&frame.ownership), - payload: to_generated_request_payload(&frame.payload)?, - }) - } - ProtocolFrame::Response(frame) => { - generated_protocol::ProtocolFrame::ResponseFrame(generated_protocol::ResponseFrame { - schema: to_generated_protocol_schema(&frame.schema), - request_id: frame.request_id, - ownership: to_generated_ownership_scope(&frame.ownership), - payload: to_generated_response_payload(&frame.payload)?, - }) - } - ProtocolFrame::Event(frame) => { - generated_protocol::ProtocolFrame::EventFrame(generated_protocol::EventFrame { - schema: to_generated_protocol_schema(&frame.schema), - ownership: to_generated_ownership_scope(&frame.ownership), - payload: to_generated_event_payload(&frame.payload), - }) - } - ProtocolFrame::SidecarRequest(frame) => { - generated_protocol::ProtocolFrame::SidecarRequestFrame( - generated_protocol::SidecarRequestFrame { - schema: to_generated_protocol_schema(&frame.schema), - request_id: frame.request_id, - ownership: to_generated_ownership_scope(&frame.ownership), - payload: to_generated_sidecar_request_payload(&frame.payload)?, - }, - ) - } - ProtocolFrame::SidecarResponse(frame) => { - generated_protocol::ProtocolFrame::SidecarResponseFrame( - generated_protocol::SidecarResponseFrame { - schema: to_generated_protocol_schema(&frame.schema), - request_id: frame.request_id, - ownership: to_generated_ownership_scope(&frame.ownership), - payload: to_generated_sidecar_response_payload(&frame.payload)?, - }, - ) - } - }) -} - -/// Convert the generated wire frame into the compatibility protocol frame. -pub fn from_generated_protocol_frame( - frame: generated_protocol::ProtocolFrame, -) -> Result { - Ok(match frame { - generated_protocol::ProtocolFrame::RequestFrame(frame) => { - ProtocolFrame::Request(RequestFrame { - schema: from_generated_protocol_schema(frame.schema), - request_id: frame.request_id, - ownership: from_generated_ownership_scope(frame.ownership), - payload: from_generated_request_payload(frame.payload)?, - }) - } - generated_protocol::ProtocolFrame::ResponseFrame(frame) => { - ProtocolFrame::Response(ResponseFrame { - schema: from_generated_protocol_schema(frame.schema), - request_id: frame.request_id, - ownership: from_generated_ownership_scope(frame.ownership), - payload: from_generated_response_payload(frame.payload)?, - }) - } - generated_protocol::ProtocolFrame::EventFrame(frame) => ProtocolFrame::Event(EventFrame { - schema: from_generated_protocol_schema(frame.schema), - ownership: from_generated_ownership_scope(frame.ownership), - payload: from_generated_event_payload(frame.payload), - }), - generated_protocol::ProtocolFrame::SidecarRequestFrame(frame) => { - ProtocolFrame::SidecarRequest(SidecarRequestFrame { - schema: from_generated_protocol_schema(frame.schema), - request_id: frame.request_id, - ownership: from_generated_ownership_scope(frame.ownership), - payload: from_generated_sidecar_request_payload(frame.payload)?, - }) - } - generated_protocol::ProtocolFrame::SidecarResponseFrame(frame) => { - ProtocolFrame::SidecarResponse(SidecarResponseFrame { - schema: from_generated_protocol_schema(frame.schema), - request_id: frame.request_id, - ownership: from_generated_ownership_scope(frame.ownership), - payload: from_generated_sidecar_response_payload(frame.payload)?, - }) - } - }) -} - -fn to_generated_protocol_schema(schema: &ProtocolSchema) -> generated_protocol::ProtocolSchema { - schema.clone() -} - -fn from_generated_protocol_schema(schema: generated_protocol::ProtocolSchema) -> ProtocolSchema { - schema -} - -// `OwnershipScope` is now an alias for the generated `crate::wire::OwnershipScope`, so the -// compat<->generated converters are identity functions. They are retained so the JSON-carrying -// frame-conversion chain (still hand-written, out of scope for this pass) keeps compiling -// without site-by-site rewiring. -pub(crate) fn to_generated_ownership_scope( - ownership: &OwnershipScope, -) -> generated_protocol::OwnershipScope { - ownership.clone() -} - -pub(crate) fn from_generated_ownership_scope( - ownership: generated_protocol::OwnershipScope, -) -> OwnershipScope { - ownership -} - -fn to_generated_dispose_reason(reason: &DisposeReason) -> generated_protocol::DisposeReason { - match reason { - DisposeReason::Requested => generated_protocol::DisposeReason::Requested, - DisposeReason::ConnectionClosed => generated_protocol::DisposeReason::ConnectionClosed, - DisposeReason::HostShutdown => generated_protocol::DisposeReason::HostShutdown, - } -} - -fn from_generated_dispose_reason(reason: generated_protocol::DisposeReason) -> DisposeReason { - match reason { - generated_protocol::DisposeReason::Requested => DisposeReason::Requested, - generated_protocol::DisposeReason::ConnectionClosed => DisposeReason::ConnectionClosed, - generated_protocol::DisposeReason::HostShutdown => DisposeReason::HostShutdown, - } -} - -fn to_generated_filesystem_operation( - operation: &FilesystemOperation, -) -> generated_protocol::FilesystemOperation { - match operation { - FilesystemOperation::Read => generated_protocol::FilesystemOperation::Read, - FilesystemOperation::Write => generated_protocol::FilesystemOperation::Write, - FilesystemOperation::Stat => generated_protocol::FilesystemOperation::Stat, - FilesystemOperation::ReadDir => generated_protocol::FilesystemOperation::ReadDir, - FilesystemOperation::Mkdir => generated_protocol::FilesystemOperation::Mkdir, - FilesystemOperation::Remove => generated_protocol::FilesystemOperation::Remove, - FilesystemOperation::Rename => generated_protocol::FilesystemOperation::Rename, - } -} - -fn from_generated_filesystem_operation( - operation: generated_protocol::FilesystemOperation, -) -> FilesystemOperation { - match operation { - generated_protocol::FilesystemOperation::Read => FilesystemOperation::Read, - generated_protocol::FilesystemOperation::Write => FilesystemOperation::Write, - generated_protocol::FilesystemOperation::Stat => FilesystemOperation::Stat, - generated_protocol::FilesystemOperation::ReadDir => FilesystemOperation::ReadDir, - generated_protocol::FilesystemOperation::Mkdir => FilesystemOperation::Mkdir, - generated_protocol::FilesystemOperation::Remove => FilesystemOperation::Remove, - generated_protocol::FilesystemOperation::Rename => FilesystemOperation::Rename, - } -} - -fn to_generated_guest_filesystem_operation( - operation: &GuestFilesystemOperation, -) -> generated_protocol::GuestFilesystemOperation { - match operation { - GuestFilesystemOperation::ReadFile => { - generated_protocol::GuestFilesystemOperation::ReadFile - } - GuestFilesystemOperation::WriteFile => { - generated_protocol::GuestFilesystemOperation::WriteFile - } - GuestFilesystemOperation::CreateDir => { - generated_protocol::GuestFilesystemOperation::CreateDir - } - GuestFilesystemOperation::Mkdir => generated_protocol::GuestFilesystemOperation::Mkdir, - GuestFilesystemOperation::Exists => generated_protocol::GuestFilesystemOperation::Exists, - GuestFilesystemOperation::Stat => generated_protocol::GuestFilesystemOperation::Stat, - GuestFilesystemOperation::Lstat => generated_protocol::GuestFilesystemOperation::Lstat, - GuestFilesystemOperation::ReadDir => generated_protocol::GuestFilesystemOperation::ReadDir, - GuestFilesystemOperation::ReadDirRecursive => { - generated_protocol::GuestFilesystemOperation::ReadDirRecursive - } - GuestFilesystemOperation::RemoveFile => { - generated_protocol::GuestFilesystemOperation::RemoveFile - } - GuestFilesystemOperation::RemoveDir => { - generated_protocol::GuestFilesystemOperation::RemoveDir - } - GuestFilesystemOperation::Remove => generated_protocol::GuestFilesystemOperation::Remove, - GuestFilesystemOperation::Copy => generated_protocol::GuestFilesystemOperation::Copy, - GuestFilesystemOperation::Move => generated_protocol::GuestFilesystemOperation::Move, - GuestFilesystemOperation::Rename => generated_protocol::GuestFilesystemOperation::Rename, - GuestFilesystemOperation::Realpath => { - generated_protocol::GuestFilesystemOperation::Realpath - } - GuestFilesystemOperation::Symlink => generated_protocol::GuestFilesystemOperation::Symlink, - GuestFilesystemOperation::ReadLink => { - generated_protocol::GuestFilesystemOperation::ReadLink - } - GuestFilesystemOperation::Link => generated_protocol::GuestFilesystemOperation::Link, - GuestFilesystemOperation::Chmod => generated_protocol::GuestFilesystemOperation::Chmod, - GuestFilesystemOperation::Chown => generated_protocol::GuestFilesystemOperation::Chown, - GuestFilesystemOperation::Utimes => generated_protocol::GuestFilesystemOperation::Utimes, - GuestFilesystemOperation::Truncate => { - generated_protocol::GuestFilesystemOperation::Truncate - } - GuestFilesystemOperation::Pread => generated_protocol::GuestFilesystemOperation::Pread, - GuestFilesystemOperation::Pwrite => generated_protocol::GuestFilesystemOperation::Pwrite, - } -} - -fn from_generated_guest_filesystem_operation( - operation: generated_protocol::GuestFilesystemOperation, -) -> GuestFilesystemOperation { - match operation { - generated_protocol::GuestFilesystemOperation::ReadFile => { - GuestFilesystemOperation::ReadFile - } - generated_protocol::GuestFilesystemOperation::WriteFile => { - GuestFilesystemOperation::WriteFile - } - generated_protocol::GuestFilesystemOperation::CreateDir => { - GuestFilesystemOperation::CreateDir - } - generated_protocol::GuestFilesystemOperation::Mkdir => GuestFilesystemOperation::Mkdir, - generated_protocol::GuestFilesystemOperation::Exists => GuestFilesystemOperation::Exists, - generated_protocol::GuestFilesystemOperation::Stat => GuestFilesystemOperation::Stat, - generated_protocol::GuestFilesystemOperation::Lstat => GuestFilesystemOperation::Lstat, - generated_protocol::GuestFilesystemOperation::ReadDir => GuestFilesystemOperation::ReadDir, - generated_protocol::GuestFilesystemOperation::ReadDirRecursive => { - GuestFilesystemOperation::ReadDirRecursive - } - generated_protocol::GuestFilesystemOperation::RemoveFile => { - GuestFilesystemOperation::RemoveFile - } - generated_protocol::GuestFilesystemOperation::RemoveDir => { - GuestFilesystemOperation::RemoveDir - } - generated_protocol::GuestFilesystemOperation::Remove => GuestFilesystemOperation::Remove, - generated_protocol::GuestFilesystemOperation::Copy => GuestFilesystemOperation::Copy, - generated_protocol::GuestFilesystemOperation::Move => GuestFilesystemOperation::Move, - generated_protocol::GuestFilesystemOperation::Rename => GuestFilesystemOperation::Rename, - generated_protocol::GuestFilesystemOperation::Realpath => { - GuestFilesystemOperation::Realpath - } - generated_protocol::GuestFilesystemOperation::Symlink => GuestFilesystemOperation::Symlink, - generated_protocol::GuestFilesystemOperation::ReadLink => { - GuestFilesystemOperation::ReadLink - } - generated_protocol::GuestFilesystemOperation::Link => GuestFilesystemOperation::Link, - generated_protocol::GuestFilesystemOperation::Chmod => GuestFilesystemOperation::Chmod, - generated_protocol::GuestFilesystemOperation::Chown => GuestFilesystemOperation::Chown, - generated_protocol::GuestFilesystemOperation::Utimes => GuestFilesystemOperation::Utimes, - generated_protocol::GuestFilesystemOperation::Truncate => { - GuestFilesystemOperation::Truncate - } - generated_protocol::GuestFilesystemOperation::Pread => GuestFilesystemOperation::Pread, - generated_protocol::GuestFilesystemOperation::Pwrite => GuestFilesystemOperation::Pwrite, - } -} - -fn to_generated_permission_mode(mode: &PermissionMode) -> generated_protocol::PermissionMode { - mode.clone() -} - -fn from_generated_permission_mode(mode: generated_protocol::PermissionMode) -> PermissionMode { - mode -} - -fn to_generated_root_filesystem_entry_encoding( - encoding: &RootFilesystemEntryEncoding, -) -> generated_protocol::RootFilesystemEntryEncoding { - match encoding { - RootFilesystemEntryEncoding::Utf8 => generated_protocol::RootFilesystemEntryEncoding::Utf8, - RootFilesystemEntryEncoding::Base64 => { - generated_protocol::RootFilesystemEntryEncoding::Base64 - } - } -} - -fn from_generated_root_filesystem_entry_encoding( - encoding: generated_protocol::RootFilesystemEntryEncoding, -) -> RootFilesystemEntryEncoding { - match encoding { - generated_protocol::RootFilesystemEntryEncoding::Utf8 => RootFilesystemEntryEncoding::Utf8, - generated_protocol::RootFilesystemEntryEncoding::Base64 => { - RootFilesystemEntryEncoding::Base64 - } - } -} - -fn to_generated_stream_channel(channel: &StreamChannel) -> generated_protocol::StreamChannel { - match channel { - StreamChannel::Stdout => generated_protocol::StreamChannel::Stdout, - StreamChannel::Stderr => generated_protocol::StreamChannel::Stderr, - } -} - -fn from_generated_stream_channel(channel: generated_protocol::StreamChannel) -> StreamChannel { - match channel { - generated_protocol::StreamChannel::Stdout => StreamChannel::Stdout, - generated_protocol::StreamChannel::Stderr => StreamChannel::Stderr, - } -} - -fn to_generated_vm_lifecycle_state( - state: &VmLifecycleState, -) -> generated_protocol::VmLifecycleState { - match state { - VmLifecycleState::Creating => generated_protocol::VmLifecycleState::Creating, - VmLifecycleState::Ready => generated_protocol::VmLifecycleState::Ready, - VmLifecycleState::Disposing => generated_protocol::VmLifecycleState::Disposing, - VmLifecycleState::Disposed => generated_protocol::VmLifecycleState::Disposed, - VmLifecycleState::Failed => generated_protocol::VmLifecycleState::Failed, - } -} - -fn from_generated_vm_lifecycle_state( - state: generated_protocol::VmLifecycleState, -) -> VmLifecycleState { - match state { - generated_protocol::VmLifecycleState::Creating => VmLifecycleState::Creating, - generated_protocol::VmLifecycleState::Ready => VmLifecycleState::Ready, - generated_protocol::VmLifecycleState::Disposing => VmLifecycleState::Disposing, - generated_protocol::VmLifecycleState::Disposed => VmLifecycleState::Disposed, - generated_protocol::VmLifecycleState::Failed => VmLifecycleState::Failed, - } -} - -fn to_generated_guest_filesystem_stat( - stat: &GuestFilesystemStat, -) -> generated_protocol::GuestFilesystemStat { - stat.clone() -} - -fn from_generated_guest_filesystem_stat( - stat: generated_protocol::GuestFilesystemStat, -) -> GuestFilesystemStat { - stat -} - -fn to_generated_process_snapshot_entry( - entry: &ProcessSnapshotEntry, -) -> generated_protocol::ProcessSnapshotEntry { - entry.clone() -} - -fn from_generated_process_snapshot_entry( - entry: generated_protocol::ProcessSnapshotEntry, -) -> ProcessSnapshotEntry { - entry -} - -fn to_generated_ext_envelope(envelope: &ExtEnvelope) -> generated_protocol::ExtEnvelope { - envelope.clone() -} - -fn from_generated_ext_envelope(envelope: generated_protocol::ExtEnvelope) -> ExtEnvelope { - envelope -} - -fn to_generated_request_payload( - payload: &RequestPayload, -) -> Result { - Ok(match payload { - RequestPayload::Authenticate(inner) => { - generated_protocol::RequestPayload::AuthenticateRequest(inner.clone()) - } - RequestPayload::OpenSession(inner) => { - generated_protocol::RequestPayload::OpenSessionRequest(inner.clone()) - } - RequestPayload::CreateVm(inner) => { - generated_protocol::RequestPayload::CreateVmRequest(inner.clone()) - } - RequestPayload::DisposeVm(inner) => generated_protocol::RequestPayload::DisposeVmRequest( - generated_protocol::DisposeVmRequest { - reason: to_generated_dispose_reason(&inner.reason), - }, - ), - RequestPayload::BootstrapRootFilesystem(inner) => { - generated_protocol::RequestPayload::BootstrapRootFilesystemRequest(inner.clone()) - } - RequestPayload::ConfigureVm(inner) => { - generated_protocol::RequestPayload::ConfigureVmRequest(inner.clone()) - } - RequestPayload::RegisterHostCallbacks(inner) => { - generated_protocol::RequestPayload::RegisterHostCallbacksRequest(inner.clone()) - } - RequestPayload::CreateLayer(_) => generated_protocol::RequestPayload::CreateLayerRequest, - RequestPayload::SealLayer(inner) => { - generated_protocol::RequestPayload::SealLayerRequest(inner.clone()) - } - RequestPayload::ImportSnapshot(inner) => { - generated_protocol::RequestPayload::ImportSnapshotRequest(inner.clone()) - } - RequestPayload::ExportSnapshot(inner) => { - generated_protocol::RequestPayload::ExportSnapshotRequest(inner.clone()) - } - RequestPayload::CreateOverlay(inner) => { - generated_protocol::RequestPayload::CreateOverlayRequest(inner.clone()) - } - RequestPayload::GuestFilesystemCall(inner) => { - generated_protocol::RequestPayload::GuestFilesystemCallRequest(inner.clone()) - } - RequestPayload::SnapshotRootFilesystem(_) => { - generated_protocol::RequestPayload::SnapshotRootFilesystemRequest - } - RequestPayload::Execute(inner) => { - generated_protocol::RequestPayload::ExecuteRequest(inner.clone()) - } - RequestPayload::WriteStdin(inner) => { - generated_protocol::RequestPayload::WriteStdinRequest(inner.clone()) - } - RequestPayload::CloseStdin(inner) => { - generated_protocol::RequestPayload::CloseStdinRequest(inner.clone()) - } - RequestPayload::KillProcess(inner) => { - generated_protocol::RequestPayload::KillProcessRequest(inner.clone()) - } - RequestPayload::GetProcessSnapshot(_) => { - generated_protocol::RequestPayload::GetProcessSnapshotRequest - } - RequestPayload::GetResourceSnapshot(_) => { - generated_protocol::RequestPayload::GetResourceSnapshotRequest - } - RequestPayload::FindListener(inner) => { - generated_protocol::RequestPayload::FindListenerRequest(inner.clone()) - } - RequestPayload::FindBoundUdp(inner) => { - generated_protocol::RequestPayload::FindBoundUdpRequest(inner.clone()) - } - RequestPayload::VmFetch(inner) => { - generated_protocol::RequestPayload::VmFetchRequest(inner.clone()) - } - RequestPayload::GetSignalState(inner) => { - generated_protocol::RequestPayload::GetSignalStateRequest(inner.clone()) - } - RequestPayload::GetZombieTimerCount(_) => { - generated_protocol::RequestPayload::GetZombieTimerCountRequest - } - RequestPayload::HostFilesystemCall(inner) => { - generated_protocol::RequestPayload::HostFilesystemCallRequest( - generated_protocol::HostFilesystemCallRequest { - operation: to_generated_filesystem_operation(&inner.operation), - path: inner.path.clone(), - payload_size_bytes: inner.payload_size_bytes, - }, - ) - } - RequestPayload::PersistenceLoad(inner) => { - generated_protocol::RequestPayload::PersistenceLoadRequest(inner.clone()) - } - RequestPayload::PersistenceFlush(inner) => { - generated_protocol::RequestPayload::PersistenceFlushRequest(inner.clone()) - } - RequestPayload::Ext(inner) => { - generated_protocol::RequestPayload::ExtEnvelope(to_generated_ext_envelope(inner)) - } - RequestPayload::GuestKernelCall(inner) => { - generated_protocol::RequestPayload::GuestKernelCallRequest(inner.clone()) - } - RequestPayload::ResizePty(inner) => { - generated_protocol::RequestPayload::ResizePtyRequest(inner.clone()) - } - RequestPayload::LinkPackage(inner) => { - generated_protocol::RequestPayload::LinkPackageRequest(inner.clone()) - } - RequestPayload::ProvidedCommands(_) => { - generated_protocol::RequestPayload::ProvidedCommandsRequest - } - }) -} - -fn from_generated_request_payload( - payload: generated_protocol::RequestPayload, -) -> Result { - Ok(match payload { - generated_protocol::RequestPayload::AuthenticateRequest(inner) => { - RequestPayload::Authenticate(inner) - } - generated_protocol::RequestPayload::OpenSessionRequest(inner) => { - RequestPayload::OpenSession(inner) - } - generated_protocol::RequestPayload::CreateVmRequest(inner) => { - RequestPayload::CreateVm(inner) - } - generated_protocol::RequestPayload::DisposeVmRequest(inner) => { - RequestPayload::DisposeVm(DisposeVmRequest { - reason: from_generated_dispose_reason(inner.reason), - }) - } - generated_protocol::RequestPayload::BootstrapRootFilesystemRequest(inner) => { - RequestPayload::BootstrapRootFilesystem(inner) - } - generated_protocol::RequestPayload::ConfigureVmRequest(inner) => { - RequestPayload::ConfigureVm(inner) - } - generated_protocol::RequestPayload::RegisterHostCallbacksRequest(inner) => { - RequestPayload::RegisterHostCallbacks(inner) - } - generated_protocol::RequestPayload::CreateLayerRequest => { - RequestPayload::CreateLayer(CreateLayerRequest {}) - } - generated_protocol::RequestPayload::SealLayerRequest(inner) => { - RequestPayload::SealLayer(inner) - } - generated_protocol::RequestPayload::ImportSnapshotRequest(inner) => { - RequestPayload::ImportSnapshot(inner) - } - generated_protocol::RequestPayload::ExportSnapshotRequest(inner) => { - RequestPayload::ExportSnapshot(inner) - } - generated_protocol::RequestPayload::CreateOverlayRequest(inner) => { - RequestPayload::CreateOverlay(inner) - } - generated_protocol::RequestPayload::GuestFilesystemCallRequest(inner) => { - RequestPayload::GuestFilesystemCall(inner) - } - generated_protocol::RequestPayload::SnapshotRootFilesystemRequest => { - RequestPayload::SnapshotRootFilesystem(SnapshotRootFilesystemRequest {}) - } - generated_protocol::RequestPayload::ExecuteRequest(inner) => RequestPayload::Execute(inner), - generated_protocol::RequestPayload::WriteStdinRequest(inner) => { - RequestPayload::WriteStdin(inner) - } - generated_protocol::RequestPayload::CloseStdinRequest(inner) => { - RequestPayload::CloseStdin(inner) - } - generated_protocol::RequestPayload::KillProcessRequest(inner) => { - RequestPayload::KillProcess(inner) - } - generated_protocol::RequestPayload::GetProcessSnapshotRequest => { - RequestPayload::GetProcessSnapshot(GetProcessSnapshotRequest {}) - } - generated_protocol::RequestPayload::GetResourceSnapshotRequest => { - RequestPayload::GetResourceSnapshot(GetResourceSnapshotRequest {}) - } - generated_protocol::RequestPayload::FindListenerRequest(inner) => { - RequestPayload::FindListener(inner) - } - generated_protocol::RequestPayload::FindBoundUdpRequest(inner) => { - RequestPayload::FindBoundUdp(inner) - } - generated_protocol::RequestPayload::VmFetchRequest(inner) => RequestPayload::VmFetch(inner), - generated_protocol::RequestPayload::GetSignalStateRequest(inner) => { - RequestPayload::GetSignalState(inner) - } - generated_protocol::RequestPayload::GetZombieTimerCountRequest => { - RequestPayload::GetZombieTimerCount(GetZombieTimerCountRequest {}) - } - generated_protocol::RequestPayload::HostFilesystemCallRequest(inner) => { - RequestPayload::HostFilesystemCall(HostFilesystemCallRequest { - operation: from_generated_filesystem_operation(inner.operation), - path: inner.path, - payload_size_bytes: inner.payload_size_bytes, - }) - } - generated_protocol::RequestPayload::PersistenceLoadRequest(inner) => { - RequestPayload::PersistenceLoad(inner) - } - generated_protocol::RequestPayload::PersistenceFlushRequest(inner) => { - RequestPayload::PersistenceFlush(inner) - } - generated_protocol::RequestPayload::ExtEnvelope(inner) => { - RequestPayload::Ext(from_generated_ext_envelope(inner)) - } - generated_protocol::RequestPayload::GuestKernelCallRequest(inner) => { - RequestPayload::GuestKernelCall(inner) - } - generated_protocol::RequestPayload::ResizePtyRequest(inner) => { - RequestPayload::ResizePty(inner) - } - generated_protocol::RequestPayload::LinkPackageRequest(inner) => { - RequestPayload::LinkPackage(inner) - } - generated_protocol::RequestPayload::ProvidedCommandsRequest => { - RequestPayload::ProvidedCommands(ProvidedCommandsRequest {}) - } - }) -} - -fn to_generated_response_payload( - payload: &ResponsePayload, -) -> Result { - Ok(match payload { - ResponsePayload::Authenticated(inner) => { - generated_protocol::ResponsePayload::AuthenticatedResponse(inner.clone()) - } - ResponsePayload::SessionOpened(inner) => { - generated_protocol::ResponsePayload::SessionOpenedResponse(inner.clone()) - } - ResponsePayload::VmCreated(inner) => { - generated_protocol::ResponsePayload::VmCreatedResponse(inner.clone()) - } - ResponsePayload::VmDisposed(inner) => { - generated_protocol::ResponsePayload::VmDisposedResponse(inner.clone()) - } - ResponsePayload::RootFilesystemBootstrapped(inner) => { - generated_protocol::ResponsePayload::RootFilesystemBootstrappedResponse(inner.clone()) - } - ResponsePayload::VmConfigured(inner) => { - generated_protocol::ResponsePayload::VmConfiguredResponse(inner.clone()) - } - ResponsePayload::HostCallbacksRegistered(inner) => { - generated_protocol::ResponsePayload::HostCallbacksRegisteredResponse(inner.clone()) - } - ResponsePayload::LayerCreated(inner) => { - generated_protocol::ResponsePayload::LayerCreatedResponse(inner.clone()) - } - ResponsePayload::LayerSealed(inner) => { - generated_protocol::ResponsePayload::LayerSealedResponse(inner.clone()) - } - ResponsePayload::SnapshotImported(inner) => { - generated_protocol::ResponsePayload::SnapshotImportedResponse(inner.clone()) - } - ResponsePayload::SnapshotExported(inner) => { - generated_protocol::ResponsePayload::SnapshotExportedResponse( - generated_protocol::SnapshotExportedResponse { - layer_id: inner.layer_id.clone(), - entries: inner.entries.clone(), - }, - ) - } - ResponsePayload::OverlayCreated(inner) => { - generated_protocol::ResponsePayload::OverlayCreatedResponse(inner.clone()) - } - ResponsePayload::GuestFilesystemResult(inner) => { - generated_protocol::ResponsePayload::GuestFilesystemResultResponse( - generated_protocol::GuestFilesystemResultResponse { - operation: to_generated_guest_filesystem_operation(&inner.operation), - path: inner.path.clone(), - content: inner.content.clone(), - encoding: inner - .encoding - .as_ref() - .map(to_generated_root_filesystem_entry_encoding), - entries: inner.entries.clone(), - stat: inner.stat.as_ref().map(to_generated_guest_filesystem_stat), - exists: inner.exists, - target: inner.target.clone(), - }, - ) - } - ResponsePayload::RootFilesystemSnapshot(inner) => { - generated_protocol::ResponsePayload::RootFilesystemSnapshotResponse( - generated_protocol::RootFilesystemSnapshotResponse { - entries: inner.entries.clone(), - }, - ) - } - ResponsePayload::ProcessStarted(inner) => { - generated_protocol::ResponsePayload::ProcessStartedResponse(inner.clone()) - } - ResponsePayload::StdinWritten(inner) => { - generated_protocol::ResponsePayload::StdinWrittenResponse(inner.clone()) - } - ResponsePayload::StdinClosed(inner) => { - generated_protocol::ResponsePayload::StdinClosedResponse(inner.clone()) - } - ResponsePayload::ProcessKilled(inner) => { - generated_protocol::ResponsePayload::ProcessKilledResponse(inner.clone()) - } - ResponsePayload::ProcessSnapshot(inner) => { - generated_protocol::ResponsePayload::ProcessSnapshotResponse( - generated_protocol::ProcessSnapshotResponse { - processes: inner - .processes - .iter() - .map(to_generated_process_snapshot_entry) - .collect(), - }, - ) - } - ResponsePayload::ResourceSnapshot(inner) => { - generated_protocol::ResponsePayload::ResourceSnapshotResponse(inner.clone()) - } - ResponsePayload::ListenerSnapshot(inner) => { - generated_protocol::ResponsePayload::ListenerSnapshotResponse(inner.clone()) - } - ResponsePayload::BoundUdpSnapshot(inner) => { - generated_protocol::ResponsePayload::BoundUdpSnapshotResponse(inner.clone()) - } - ResponsePayload::VmFetchResult(inner) => { - generated_protocol::ResponsePayload::VmFetchResponse(inner.clone()) - } - ResponsePayload::SignalState(inner) => { - generated_protocol::ResponsePayload::SignalStateResponse(inner.clone()) - } - ResponsePayload::ZombieTimerCount(inner) => { - generated_protocol::ResponsePayload::ZombieTimerCountResponse(inner.clone()) - } - ResponsePayload::FilesystemResult(inner) => { - generated_protocol::ResponsePayload::FilesystemResultResponse( - generated_protocol::FilesystemResultResponse { - operation: to_generated_filesystem_operation(&inner.operation), - status: inner.status.clone(), - payload_size_bytes: inner.payload_size_bytes, - }, - ) - } - ResponsePayload::PermissionDecision(inner) => { - generated_protocol::ResponsePayload::PermissionDecisionResponse( - generated_protocol::PermissionDecisionResponse { - capability: inner.capability.clone(), - decision: to_generated_permission_mode(&inner.decision), - }, - ) - } - ResponsePayload::PersistenceState(inner) => { - generated_protocol::ResponsePayload::PersistenceStateResponse(inner.clone()) - } - ResponsePayload::PersistenceFlushed(inner) => { - generated_protocol::ResponsePayload::PersistenceFlushedResponse(inner.clone()) - } - ResponsePayload::Rejected(inner) => { - generated_protocol::ResponsePayload::RejectedResponse(inner.clone()) - } - ResponsePayload::ExtResult(inner) => { - generated_protocol::ResponsePayload::ExtEnvelope(to_generated_ext_envelope(inner)) - } - ResponsePayload::GuestKernelResult(inner) => { - generated_protocol::ResponsePayload::GuestKernelResultResponse(inner.clone()) - } - ResponsePayload::PtyResized(inner) => { - generated_protocol::ResponsePayload::PtyResizedResponse(inner.clone()) - } - ResponsePayload::PackageLinked(inner) => { - generated_protocol::ResponsePayload::PackageLinkedResponse(inner.clone()) - } - ResponsePayload::ProvidedCommands(inner) => { - generated_protocol::ResponsePayload::ProvidedCommandsResponse(inner.clone()) - } - }) -} - -fn from_generated_response_payload( - payload: generated_protocol::ResponsePayload, -) -> Result { - Ok(match payload { - generated_protocol::ResponsePayload::AuthenticatedResponse(inner) => { - ResponsePayload::Authenticated(inner) - } - generated_protocol::ResponsePayload::SessionOpenedResponse(inner) => { - ResponsePayload::SessionOpened(inner) - } - generated_protocol::ResponsePayload::VmCreatedResponse(inner) => { - ResponsePayload::VmCreated(inner) - } - generated_protocol::ResponsePayload::VmDisposedResponse(inner) => { - ResponsePayload::VmDisposed(inner) - } - generated_protocol::ResponsePayload::RootFilesystemBootstrappedResponse(inner) => { - ResponsePayload::RootFilesystemBootstrapped(inner) - } - generated_protocol::ResponsePayload::VmConfiguredResponse(inner) => { - ResponsePayload::VmConfigured(inner) - } - generated_protocol::ResponsePayload::HostCallbacksRegisteredResponse(inner) => { - ResponsePayload::HostCallbacksRegistered(inner) - } - generated_protocol::ResponsePayload::LayerCreatedResponse(inner) => { - ResponsePayload::LayerCreated(inner) - } - generated_protocol::ResponsePayload::LayerSealedResponse(inner) => { - ResponsePayload::LayerSealed(inner) - } - generated_protocol::ResponsePayload::SnapshotImportedResponse(inner) => { - ResponsePayload::SnapshotImported(inner) - } - generated_protocol::ResponsePayload::SnapshotExportedResponse(inner) => { - ResponsePayload::SnapshotExported(SnapshotExportedResponse { - layer_id: inner.layer_id, - entries: inner.entries, - }) - } - generated_protocol::ResponsePayload::OverlayCreatedResponse(inner) => { - ResponsePayload::OverlayCreated(inner) - } - generated_protocol::ResponsePayload::GuestFilesystemResultResponse(inner) => { - ResponsePayload::GuestFilesystemResult(GuestFilesystemResultResponse { - operation: from_generated_guest_filesystem_operation(inner.operation), - path: inner.path, - content: inner.content, - encoding: inner - .encoding - .map(from_generated_root_filesystem_entry_encoding), - entries: inner.entries, - stat: inner.stat.map(from_generated_guest_filesystem_stat), - exists: inner.exists, - target: inner.target, - }) - } - generated_protocol::ResponsePayload::RootFilesystemSnapshotResponse(inner) => { - ResponsePayload::RootFilesystemSnapshot(RootFilesystemSnapshotResponse { - entries: inner.entries, - }) - } - generated_protocol::ResponsePayload::ProcessStartedResponse(inner) => { - ResponsePayload::ProcessStarted(inner) - } - generated_protocol::ResponsePayload::StdinWrittenResponse(inner) => { - ResponsePayload::StdinWritten(inner) - } - generated_protocol::ResponsePayload::StdinClosedResponse(inner) => { - ResponsePayload::StdinClosed(inner) - } - generated_protocol::ResponsePayload::ProcessKilledResponse(inner) => { - ResponsePayload::ProcessKilled(inner) - } - generated_protocol::ResponsePayload::ProcessSnapshotResponse(inner) => { - ResponsePayload::ProcessSnapshot(ProcessSnapshotResponse { - processes: inner - .processes - .into_iter() - .map(from_generated_process_snapshot_entry) - .collect(), - }) - } - generated_protocol::ResponsePayload::ResourceSnapshotResponse(inner) => { - ResponsePayload::ResourceSnapshot(inner) - } - generated_protocol::ResponsePayload::ListenerSnapshotResponse(inner) => { - ResponsePayload::ListenerSnapshot(inner) - } - generated_protocol::ResponsePayload::BoundUdpSnapshotResponse(inner) => { - ResponsePayload::BoundUdpSnapshot(inner) - } - generated_protocol::ResponsePayload::VmFetchResponse(inner) => { - ResponsePayload::VmFetchResult(inner) - } - generated_protocol::ResponsePayload::SignalStateResponse(inner) => { - ResponsePayload::SignalState(inner) - } - generated_protocol::ResponsePayload::ZombieTimerCountResponse(inner) => { - ResponsePayload::ZombieTimerCount(inner) - } - generated_protocol::ResponsePayload::FilesystemResultResponse(inner) => { - ResponsePayload::FilesystemResult(FilesystemResultResponse { - operation: from_generated_filesystem_operation(inner.operation), - status: inner.status, - payload_size_bytes: inner.payload_size_bytes, - }) - } - generated_protocol::ResponsePayload::PermissionDecisionResponse(inner) => { - ResponsePayload::PermissionDecision(PermissionDecisionResponse { - capability: inner.capability, - decision: from_generated_permission_mode(inner.decision), - }) - } - generated_protocol::ResponsePayload::PersistenceStateResponse(inner) => { - ResponsePayload::PersistenceState(inner) - } - generated_protocol::ResponsePayload::PersistenceFlushedResponse(inner) => { - ResponsePayload::PersistenceFlushed(inner) - } - generated_protocol::ResponsePayload::RejectedResponse(inner) => { - ResponsePayload::Rejected(inner) - } - generated_protocol::ResponsePayload::ExtEnvelope(inner) => { - ResponsePayload::ExtResult(from_generated_ext_envelope(inner)) - } - generated_protocol::ResponsePayload::GuestKernelResultResponse(inner) => { - ResponsePayload::GuestKernelResult(inner) - } - generated_protocol::ResponsePayload::PtyResizedResponse(inner) => { - ResponsePayload::PtyResized(inner) - } - generated_protocol::ResponsePayload::PackageLinkedResponse(inner) => { - ResponsePayload::PackageLinked(inner) - } - generated_protocol::ResponsePayload::ProvidedCommandsResponse(inner) => { - ResponsePayload::ProvidedCommands(inner) - } - }) -} - -fn to_generated_event_payload(payload: &EventPayload) -> generated_protocol::EventPayload { - match payload { - EventPayload::VmLifecycle(inner) => generated_protocol::EventPayload::VmLifecycleEvent( - generated_protocol::VmLifecycleEvent { - state: to_generated_vm_lifecycle_state(&inner.state), - }, - ), - EventPayload::ProcessOutput(inner) => generated_protocol::EventPayload::ProcessOutputEvent( - generated_protocol::ProcessOutputEvent { - process_id: inner.process_id.clone(), - channel: to_generated_stream_channel(&inner.channel), - chunk: inner.chunk.clone(), - }, - ), - EventPayload::ProcessExited(inner) => { - generated_protocol::EventPayload::ProcessExitedEvent(inner.clone()) - } - EventPayload::Structured(inner) => { - generated_protocol::EventPayload::StructuredEvent(inner.clone()) - } - EventPayload::Ext(inner) => { - generated_protocol::EventPayload::ExtEnvelope(to_generated_ext_envelope(inner)) - } - } -} - -fn from_generated_event_payload(payload: generated_protocol::EventPayload) -> EventPayload { - match payload { - generated_protocol::EventPayload::VmLifecycleEvent(inner) => { - EventPayload::VmLifecycle(VmLifecycleEvent { - state: from_generated_vm_lifecycle_state(inner.state), - }) - } - generated_protocol::EventPayload::ProcessOutputEvent(inner) => { - EventPayload::ProcessOutput(ProcessOutputEvent { - process_id: inner.process_id, - channel: from_generated_stream_channel(inner.channel), - chunk: inner.chunk, - }) - } - generated_protocol::EventPayload::ProcessExitedEvent(inner) => { - EventPayload::ProcessExited(inner) - } - generated_protocol::EventPayload::StructuredEvent(inner) => EventPayload::Structured(inner), - generated_protocol::EventPayload::ExtEnvelope(inner) => { - EventPayload::Ext(from_generated_ext_envelope(inner)) - } - } -} - -fn to_generated_sidecar_request_payload( - payload: &SidecarRequestPayload, -) -> Result { - Ok(match payload { - SidecarRequestPayload::HostCallback(inner) => { - generated_protocol::SidecarRequestPayload::HostCallbackRequest(inner.clone()) - } - SidecarRequestPayload::JsBridgeCall(inner) => { - generated_protocol::SidecarRequestPayload::JsBridgeCallRequest(inner.clone()) - } - SidecarRequestPayload::Ext(inner) => { - generated_protocol::SidecarRequestPayload::ExtEnvelope(to_generated_ext_envelope(inner)) - } - }) -} - -fn from_generated_sidecar_request_payload( - payload: generated_protocol::SidecarRequestPayload, -) -> Result { - Ok(match payload { - generated_protocol::SidecarRequestPayload::HostCallbackRequest(inner) => { - SidecarRequestPayload::HostCallback(inner) - } - generated_protocol::SidecarRequestPayload::JsBridgeCallRequest(inner) => { - SidecarRequestPayload::JsBridgeCall(inner) - } - generated_protocol::SidecarRequestPayload::ExtEnvelope(inner) => { - SidecarRequestPayload::Ext(from_generated_ext_envelope(inner)) - } - }) -} - -fn to_generated_sidecar_response_payload( - payload: &SidecarResponsePayload, -) -> Result { - Ok(match payload { - SidecarResponsePayload::HostCallbackResult(inner) => { - generated_protocol::SidecarResponsePayload::HostCallbackResultResponse(inner.clone()) - } - SidecarResponsePayload::JsBridgeResult(inner) => { - generated_protocol::SidecarResponsePayload::JsBridgeResultResponse(inner.clone()) - } - SidecarResponsePayload::ExtResult(inner) => { - generated_protocol::SidecarResponsePayload::ExtEnvelope(to_generated_ext_envelope( - inner, - )) - } - }) -} - -fn from_generated_sidecar_response_payload( - payload: generated_protocol::SidecarResponsePayload, -) -> Result { - Ok(match payload { - generated_protocol::SidecarResponsePayload::HostCallbackResultResponse(inner) => { - SidecarResponsePayload::HostCallbackResult(inner) - } - generated_protocol::SidecarResponsePayload::JsBridgeResultResponse(inner) => { - SidecarResponsePayload::JsBridgeResult(inner) - } - generated_protocol::SidecarResponsePayload::ExtEnvelope(inner) => { - SidecarResponsePayload::ExtResult(from_generated_ext_envelope(inner)) - } - }) -} - -macro_rules! impl_bare_newtype_union_enum { - ( - $name:ident, - $json_name:ident, - $(#[$json_attr:meta])* - { - $($variant:ident($ty:ty) = $tag:literal),+ $(,)? - } - ) => { - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] - $(#[$json_attr])* - enum $json_name { - $($variant($ty)),+ - } - - impl From<&$name> for $json_name { - fn from(value: &$name) -> Self { - match value { - $($name::$variant(inner) => Self::$variant(inner.clone()),)+ - } - } - } - - impl From<$json_name> for $name { - fn from(value: $json_name) -> Self { - match value { - $($json_name::$variant(inner) => Self::$variant(inner),)+ - } - } - } - - impl Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - if serializer.is_human_readable() { - $json_name::from(self).serialize(serializer) - } else { - match self { - $(Self::$variant(inner) => serialize_bare_newtype_tag(serializer, $tag, inner),)+ - } - } - } - } - - impl<'de> Deserialize<'de> for $name { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - if deserializer.is_human_readable() { - Ok($json_name::deserialize(deserializer)?.into()) - } else { - struct UnionVisitor; - - impl<'de> Visitor<'de> for UnionVisitor { - type Value = $name; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "a {} BARE union", stringify!($name)) - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let serde_bare::Uint(tag) = seq - .next_element()? - .ok_or_else(|| de::Error::custom(concat!("missing ", stringify!($name), " tag")))?; - match tag { - $( - $tag => { - let payload = seq.next_element::<$ty>()?.ok_or_else(|| { - de::Error::custom(format!( - "missing {} payload for tag {}", - stringify!($variant), - $tag - )) - })?; - Ok($name::$variant(payload)) - } - )+ - _ => Err(de::Error::custom(format!( - "unknown {} tag: {}", - stringify!($name), - tag - ))), - } - } - } - - deserializer.deserialize_tuple(2, UnionVisitor) - } - } - } - }; -} - -pub type ProtocolSchema = crate::wire::ProtocolSchema; - -pub type OwnershipScope = crate::wire::OwnershipScope; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ProtocolFrame { - Request(RequestFrame), - Response(ResponseFrame), - Event(EventFrame), - SidecarRequest(SidecarRequestFrame), - SidecarResponse(SidecarResponseFrame), -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct RequestFrame { - pub schema: ProtocolSchema, - pub request_id: RequestId, - pub ownership: OwnershipScope, - pub payload: RequestPayload, -} - -impl RequestFrame { - pub fn new(request_id: RequestId, ownership: OwnershipScope, payload: RequestPayload) -> Self { - Self { - schema: ProtocolSchema::current(), - request_id, - ownership, - payload, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct ResponseFrame { - pub schema: ProtocolSchema, - pub request_id: RequestId, - pub ownership: OwnershipScope, - pub payload: ResponsePayload, -} - -impl ResponseFrame { - pub fn new(request_id: RequestId, ownership: OwnershipScope, payload: ResponsePayload) -> Self { - Self { - schema: ProtocolSchema::current(), - request_id, - ownership, - payload, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct SidecarRequestFrame { - pub schema: ProtocolSchema, - pub request_id: RequestId, - pub ownership: OwnershipScope, - pub payload: SidecarRequestPayload, -} - -impl SidecarRequestFrame { - pub fn new( - request_id: RequestId, - ownership: OwnershipScope, - payload: SidecarRequestPayload, - ) -> Self { - Self { - schema: ProtocolSchema::current(), - request_id, - ownership, - payload, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct SidecarResponseFrame { - pub schema: ProtocolSchema, - pub request_id: RequestId, - pub ownership: OwnershipScope, - pub payload: SidecarResponsePayload, -} - -impl SidecarResponseFrame { - pub fn new( - request_id: RequestId, - ownership: OwnershipScope, - payload: SidecarResponsePayload, - ) -> Self { - Self { - schema: ProtocolSchema::current(), - request_id, - ownership, - payload, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct EventFrame { - pub schema: ProtocolSchema, - pub ownership: OwnershipScope, - pub payload: EventPayload, -} - -impl EventFrame { - pub fn new(ownership: OwnershipScope, payload: EventPayload) -> Self { - Self { - schema: ProtocolSchema::current(), - ownership, - payload, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum RequestPayload { - Authenticate(AuthenticateRequest), - OpenSession(OpenSessionRequest), - CreateVm(CreateVmRequest), - DisposeVm(DisposeVmRequest), - BootstrapRootFilesystem(BootstrapRootFilesystemRequest), - ConfigureVm(ConfigureVmRequest), - RegisterHostCallbacks(RegisterHostCallbacksRequest), - CreateLayer(CreateLayerRequest), - SealLayer(SealLayerRequest), - ImportSnapshot(ImportSnapshotRequest), - ExportSnapshot(ExportSnapshotRequest), - CreateOverlay(CreateOverlayRequest), - GuestFilesystemCall(GuestFilesystemCallRequest), - SnapshotRootFilesystem(SnapshotRootFilesystemRequest), - Execute(ExecuteRequest), - WriteStdin(WriteStdinRequest), - CloseStdin(CloseStdinRequest), - KillProcess(KillProcessRequest), - GetProcessSnapshot(GetProcessSnapshotRequest), - FindListener(FindListenerRequest), - FindBoundUdp(FindBoundUdpRequest), - VmFetch(VmFetchRequest), - GetSignalState(GetSignalStateRequest), - GetZombieTimerCount(GetZombieTimerCountRequest), - HostFilesystemCall(HostFilesystemCallRequest), - PersistenceLoad(PersistenceLoadRequest), - PersistenceFlush(PersistenceFlushRequest), - Ext(ExtEnvelope), - GuestKernelCall(GuestKernelCallRequest), - ResizePty(ResizePtyRequest), - GetResourceSnapshot(GetResourceSnapshotRequest), - LinkPackage(LinkPackageRequest), - ProvidedCommands(ProvidedCommandsRequest), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ResponsePayload { - Authenticated(AuthenticatedResponse), - SessionOpened(SessionOpenedResponse), - VmCreated(VmCreatedResponse), - VmDisposed(VmDisposedResponse), - RootFilesystemBootstrapped(RootFilesystemBootstrappedResponse), - VmConfigured(VmConfiguredResponse), - HostCallbacksRegistered(HostCallbacksRegisteredResponse), - LayerCreated(LayerCreatedResponse), - LayerSealed(LayerSealedResponse), - SnapshotImported(SnapshotImportedResponse), - SnapshotExported(SnapshotExportedResponse), - OverlayCreated(OverlayCreatedResponse), - GuestFilesystemResult(GuestFilesystemResultResponse), - RootFilesystemSnapshot(RootFilesystemSnapshotResponse), - ProcessStarted(ProcessStartedResponse), - StdinWritten(StdinWrittenResponse), - StdinClosed(StdinClosedResponse), - ProcessKilled(ProcessKilledResponse), - ProcessSnapshot(ProcessSnapshotResponse), - ListenerSnapshot(ListenerSnapshotResponse), - BoundUdpSnapshot(BoundUdpSnapshotResponse), - VmFetchResult(VmFetchResponse), - SignalState(SignalStateResponse), - ZombieTimerCount(ZombieTimerCountResponse), - FilesystemResult(FilesystemResultResponse), - PermissionDecision(PermissionDecisionResponse), - PersistenceState(PersistenceStateResponse), - PersistenceFlushed(PersistenceFlushedResponse), - Rejected(RejectedResponse), - ExtResult(ExtEnvelope), - GuestKernelResult(GuestKernelResultResponse), - PtyResized(PtyResizedResponse), - ResourceSnapshot(ResourceSnapshotResponse), - PackageLinked(PackageLinkedResponse), - ProvidedCommands(ProvidedCommandsResponse), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum SidecarRequestPayload { - HostCallback(HostCallbackRequest), - JsBridgeCall(JsBridgeCallRequest), - Ext(ExtEnvelope), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum SidecarResponsePayload { - HostCallbackResult(HostCallbackResultResponse), - JsBridgeResult(JsBridgeResultResponse), - ExtResult(ExtEnvelope), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum EventPayload { - VmLifecycle(VmLifecycleEvent), - ProcessOutput(ProcessOutputEvent), - ProcessExited(ProcessExitedEvent), - Structured(StructuredEvent), - Ext(ExtEnvelope), -} - -pub type SidecarPlacement = crate::wire::SidecarPlacement; - -pub type SidecarPlacementShared = crate::wire::SidecarPlacementShared; - -pub type SidecarPlacementExplicit = crate::wire::SidecarPlacementExplicit; - -pub type GuestRuntimeKind = crate::wire::GuestRuntimeKind; - -pub type DisposeReason = crate::wire::DisposeReason; - -pub type FilesystemOperation = crate::wire::FilesystemOperation; - -pub type GuestFilesystemOperation = crate::wire::GuestFilesystemOperation; - -pub type PermissionMode = crate::wire::PermissionMode; - -pub type FsPermissionRule = crate::wire::FsPermissionRule; - -pub type PatternPermissionRule = crate::wire::PatternPermissionRule; - -pub type FsPermissionRuleSet = crate::wire::FsPermissionRuleSet; - -pub type PatternPermissionRuleSet = crate::wire::PatternPermissionRuleSet; - -pub type FsPermissionScope = crate::wire::FsPermissionScope; - -pub type PatternPermissionScope = crate::wire::PatternPermissionScope; - -pub type PermissionsPolicy = crate::wire::PermissionsPolicy; - -pub type RootFilesystemEntryKind = crate::wire::RootFilesystemEntryKind; - -pub type RootFilesystemMode = crate::wire::RootFilesystemMode; - -pub type RootFilesystemLowerDescriptor = crate::wire::RootFilesystemLowerDescriptor; - -pub type SnapshotRootFilesystemLower = crate::wire::SnapshotRootFilesystemLower; - -pub type StreamChannel = crate::wire::StreamChannel; - -pub type VmLifecycleState = crate::wire::VmLifecycleState; - -pub type AuthenticateRequest = crate::wire::AuthenticateRequest; - -pub type OpenSessionRequest = crate::wire::OpenSessionRequest; - -pub type CreateVmRequest = crate::wire::CreateVmRequest; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct DisposeVmRequest { - pub reason: DisposeReason, -} - -pub type BootstrapRootFilesystemRequest = crate::wire::BootstrapRootFilesystemRequest; - -pub type RootFilesystemDescriptor = crate::wire::RootFilesystemDescriptor; - -pub type RootFilesystemEntryEncoding = crate::wire::RootFilesystemEntryEncoding; - -pub type RootFilesystemEntry = crate::wire::RootFilesystemEntry; - -pub type ConfigureVmRequest = crate::wire::ConfigureVmRequest; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] -pub struct CreateLayerRequest {} - -pub type SealLayerRequest = crate::wire::SealLayerRequest; - -pub type ImportSnapshotRequest = crate::wire::ImportSnapshotRequest; - -pub type ExportSnapshotRequest = crate::wire::ExportSnapshotRequest; - -pub type CreateOverlayRequest = crate::wire::CreateOverlayRequest; - -pub type GuestFilesystemCallRequest = crate::wire::GuestFilesystemCallRequest; - -pub type GuestKernelCallRequest = crate::wire::GuestKernelCallRequest; -pub type ResizePtyRequest = crate::wire::ResizePtyRequest; -pub type PackageDescriptor = crate::wire::PackageDescriptor; -pub type AgentosProjectedAgent = crate::wire::AgentosProjectedAgent; -pub type PackageCommands = crate::wire::PackageCommands; -pub type ProjectedCommand = crate::wire::ProjectedCommand; -pub type LinkPackageRequest = crate::wire::LinkPackageRequest; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] -pub struct ProvidedCommandsRequest {} - -pub type GuestKernelResultResponse = crate::wire::GuestKernelResultResponse; -pub type PtyResizedResponse = crate::wire::PtyResizedResponse; -pub type PackageLinkedResponse = crate::wire::PackageLinkedResponse; -pub type ProvidedCommandsResponse = crate::wire::ProvidedCommandsResponse; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] -pub struct SnapshotRootFilesystemRequest {} - -pub type MountDescriptor = crate::wire::MountDescriptor; - -pub type MountPluginDescriptor = crate::wire::MountPluginDescriptor; - -pub type SoftwareDescriptor = crate::wire::SoftwareDescriptor; - -pub type ProjectedModuleDescriptor = crate::wire::ProjectedModuleDescriptor; - -pub type WasmPermissionTier = crate::wire::WasmPermissionTier; - -pub type ExecuteRequest = crate::wire::ExecuteRequest; - -pub type WriteStdinRequest = crate::wire::WriteStdinRequest; - -pub type CloseStdinRequest = crate::wire::CloseStdinRequest; - -pub type KillProcessRequest = crate::wire::KillProcessRequest; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] -pub struct GetProcessSnapshotRequest {} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] -pub struct GetResourceSnapshotRequest {} - -pub type FindListenerRequest = crate::wire::FindListenerRequest; - -pub type FindBoundUdpRequest = crate::wire::FindBoundUdpRequest; - -pub type VmFetchRequest = crate::wire::VmFetchRequest; - -pub type GetSignalStateRequest = crate::wire::GetSignalStateRequest; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] -pub struct GetZombieTimerCountRequest {} - -pub type HostFilesystemCallRequest = crate::wire::HostFilesystemCallRequest; - -pub type PersistenceLoadRequest = crate::wire::PersistenceLoadRequest; - -pub type PersistenceFlushRequest = crate::wire::PersistenceFlushRequest; - -pub type RegisterHostCallbacksRequest = crate::wire::RegisterHostCallbacksRequest; - -pub type RegisteredHostCallbackDefinition = crate::wire::RegisteredHostCallbackDefinition; - -pub type RegisteredHostCallbackExample = crate::wire::RegisteredHostCallbackExample; - -pub type HostCallbackRequest = crate::wire::HostCallbackRequest; - -pub type JsBridgeCallRequest = crate::wire::JsBridgeCallRequest; - -pub type AuthenticatedResponse = crate::wire::AuthenticatedResponse; - -pub type SessionOpenedResponse = crate::wire::SessionOpenedResponse; - -pub type VmCreatedResponse = crate::wire::VmCreatedResponse; - -pub type VmDisposedResponse = crate::wire::VmDisposedResponse; - -pub type RootFilesystemBootstrappedResponse = crate::wire::RootFilesystemBootstrappedResponse; - -pub type VmConfiguredResponse = crate::wire::VmConfiguredResponse; - -pub type HostCallbacksRegisteredResponse = crate::wire::HostCallbacksRegisteredResponse; - -pub type GuestFilesystemStat = crate::wire::GuestFilesystemStat; - -pub type GuestDirEntry = crate::wire::GuestDirEntry; - -pub type GuestFilesystemResultResponse = crate::wire::GuestFilesystemResultResponse; - -pub type RootFilesystemSnapshotResponse = crate::wire::RootFilesystemSnapshotResponse; - -pub type LayerCreatedResponse = crate::wire::LayerCreatedResponse; - -pub type LayerSealedResponse = crate::wire::LayerSealedResponse; - -pub type SnapshotImportedResponse = crate::wire::SnapshotImportedResponse; - -pub type SnapshotExportedResponse = crate::wire::SnapshotExportedResponse; - -pub type OverlayCreatedResponse = crate::wire::OverlayCreatedResponse; - -pub type ProcessStartedResponse = crate::wire::ProcessStartedResponse; - -pub type StdinWrittenResponse = crate::wire::StdinWrittenResponse; - -pub type StdinClosedResponse = crate::wire::StdinClosedResponse; - -pub type ProcessKilledResponse = crate::wire::ProcessKilledResponse; - -pub type ProcessSnapshotStatus = crate::wire::ProcessSnapshotStatus; - -pub type ProcessSnapshotEntry = crate::wire::ProcessSnapshotEntry; - -pub type ProcessSnapshotResponse = crate::wire::ProcessSnapshotResponse; - -pub type QueueSnapshotEntry = crate::wire::QueueSnapshotEntry; - -pub type ResourceSnapshotResponse = crate::wire::ResourceSnapshotResponse; - -pub type SocketStateEntry = crate::wire::SocketStateEntry; - -pub type ListenerSnapshotResponse = crate::wire::ListenerSnapshotResponse; - -pub type BoundUdpSnapshotResponse = crate::wire::BoundUdpSnapshotResponse; - -pub type VmFetchResponse = crate::wire::VmFetchResponse; - -pub type SignalDispositionAction = crate::wire::SignalDispositionAction; - -pub type SignalHandlerRegistration = crate::wire::SignalHandlerRegistration; - -pub type SignalStateResponse = crate::wire::SignalStateResponse; - -pub type ZombieTimerCountResponse = crate::wire::ZombieTimerCountResponse; - -pub type FilesystemResultResponse = crate::wire::FilesystemResultResponse; - -pub type PermissionDecisionResponse = crate::wire::PermissionDecisionResponse; - -pub type PersistenceStateResponse = crate::wire::PersistenceStateResponse; - -pub type PersistenceFlushedResponse = crate::wire::PersistenceFlushedResponse; - -pub type HostCallbackResultResponse = crate::wire::HostCallbackResultResponse; - -pub type JsBridgeResultResponse = crate::wire::JsBridgeResultResponse; - -pub type RejectedResponse = crate::wire::RejectedResponse; - -pub type VmLifecycleEvent = crate::wire::VmLifecycleEvent; - -pub type ProcessOutputEvent = crate::wire::ProcessOutputEvent; - -pub type ProcessExitedEvent = crate::wire::ProcessExitedEvent; - -pub type StructuredEvent = crate::wire::StructuredEvent; - -impl_bare_newtype_union_enum!( - ProtocolFrame, - JsonProtocolFrame, - #[serde(tag = "frame_type", rename_all = "snake_case")] - { - Request(RequestFrame) = 0, - Response(ResponseFrame) = 1, - Event(EventFrame) = 2, - SidecarRequest(SidecarRequestFrame) = 3, - SidecarResponse(SidecarResponseFrame) = 4, - } -); - -impl_bare_newtype_union_enum!( - RequestPayload, - JsonRequestPayload, - #[serde(tag = "type", rename_all = "snake_case")] - { - Authenticate(AuthenticateRequest) = 0, - OpenSession(OpenSessionRequest) = 1, - CreateVm(CreateVmRequest) = 2, - DisposeVm(DisposeVmRequest) = 3, - BootstrapRootFilesystem(BootstrapRootFilesystemRequest) = 4, - ConfigureVm(ConfigureVmRequest) = 5, - RegisterHostCallbacks(RegisterHostCallbacksRequest) = 6, - CreateLayer(CreateLayerRequest) = 7, - SealLayer(SealLayerRequest) = 8, - ImportSnapshot(ImportSnapshotRequest) = 9, - ExportSnapshot(ExportSnapshotRequest) = 10, - CreateOverlay(CreateOverlayRequest) = 11, - GuestFilesystemCall(GuestFilesystemCallRequest) = 12, - SnapshotRootFilesystem(SnapshotRootFilesystemRequest) = 13, - Execute(ExecuteRequest) = 14, - WriteStdin(WriteStdinRequest) = 15, - CloseStdin(CloseStdinRequest) = 16, - KillProcess(KillProcessRequest) = 17, - GetProcessSnapshot(GetProcessSnapshotRequest) = 18, - FindListener(FindListenerRequest) = 19, - FindBoundUdp(FindBoundUdpRequest) = 20, - GetSignalState(GetSignalStateRequest) = 21, - GetZombieTimerCount(GetZombieTimerCountRequest) = 22, - HostFilesystemCall(HostFilesystemCallRequest) = 23, - PersistenceLoad(PersistenceLoadRequest) = 24, - PersistenceFlush(PersistenceFlushRequest) = 25, - VmFetch(VmFetchRequest) = 26, - Ext(ExtEnvelope) = 27, - GuestKernelCall(GuestKernelCallRequest) = 28, - ResizePty(ResizePtyRequest) = 29, - GetResourceSnapshot(GetResourceSnapshotRequest) = 30, - LinkPackage(LinkPackageRequest) = 31, - ProvidedCommands(ProvidedCommandsRequest) = 32, - } -); - -impl_bare_newtype_union_enum!( - ResponsePayload, - JsonResponsePayload, - #[serde(tag = "type", rename_all = "snake_case")] - { - Authenticated(AuthenticatedResponse) = 0, - SessionOpened(SessionOpenedResponse) = 1, - VmCreated(VmCreatedResponse) = 2, - VmDisposed(VmDisposedResponse) = 3, - RootFilesystemBootstrapped(RootFilesystemBootstrappedResponse) = 4, - VmConfigured(VmConfiguredResponse) = 5, - HostCallbacksRegistered(HostCallbacksRegisteredResponse) = 6, - LayerCreated(LayerCreatedResponse) = 7, - LayerSealed(LayerSealedResponse) = 8, - SnapshotImported(SnapshotImportedResponse) = 9, - SnapshotExported(SnapshotExportedResponse) = 10, - OverlayCreated(OverlayCreatedResponse) = 11, - GuestFilesystemResult(GuestFilesystemResultResponse) = 12, - RootFilesystemSnapshot(RootFilesystemSnapshotResponse) = 13, - ProcessStarted(ProcessStartedResponse) = 14, - StdinWritten(StdinWrittenResponse) = 15, - StdinClosed(StdinClosedResponse) = 16, - ProcessKilled(ProcessKilledResponse) = 17, - ProcessSnapshot(ProcessSnapshotResponse) = 18, - ListenerSnapshot(ListenerSnapshotResponse) = 19, - BoundUdpSnapshot(BoundUdpSnapshotResponse) = 20, - SignalState(SignalStateResponse) = 21, - ZombieTimerCount(ZombieTimerCountResponse) = 22, - FilesystemResult(FilesystemResultResponse) = 23, - PermissionDecision(PermissionDecisionResponse) = 24, - PersistenceState(PersistenceStateResponse) = 25, - PersistenceFlushed(PersistenceFlushedResponse) = 26, - Rejected(RejectedResponse) = 27, - VmFetchResult(VmFetchResponse) = 28, - ExtResult(ExtEnvelope) = 29, - GuestKernelResult(GuestKernelResultResponse) = 30, - PtyResized(PtyResizedResponse) = 31, - ResourceSnapshot(ResourceSnapshotResponse) = 32, - PackageLinked(PackageLinkedResponse) = 33, - ProvidedCommands(ProvidedCommandsResponse) = 34, - } -); - -impl_bare_newtype_union_enum!( - SidecarRequestPayload, - JsonSidecarRequestPayload, - #[serde(tag = "type", rename_all = "snake_case")] - { - HostCallback(HostCallbackRequest) = 0, - JsBridgeCall(JsBridgeCallRequest) = 1, - Ext(ExtEnvelope) = 2, - } -); - -impl_bare_newtype_union_enum!( - SidecarResponsePayload, - JsonSidecarResponsePayload, - #[allow(clippy::enum_variant_names)] - #[serde(tag = "type", rename_all = "snake_case")] - { - HostCallbackResult(HostCallbackResultResponse) = 0, - JsBridgeResult(JsBridgeResultResponse) = 1, - ExtResult(ExtEnvelope) = 2, - } -); - -impl_bare_newtype_union_enum!( - EventPayload, - JsonEventPayload, - #[serde(tag = "type", rename_all = "snake_case")] - { - VmLifecycle(VmLifecycleEvent) = 0, - ProcessOutput(ProcessOutputEvent) = 1, - ProcessExited(ProcessExitedEvent) = 2, - Structured(StructuredEvent) = 3, - Ext(ExtEnvelope) = 4, - } -); - -fn serialize_payload( - frame: &ProtocolFrame, - payload_codec: NativePayloadCodec, -) -> Result, ProtocolCodecError> { - match payload_codec { - NativePayloadCodec::Json => serde_json::to_vec(frame) - .map_err(|error| ProtocolCodecError::SerializeFailure(error.to_string())), - NativePayloadCodec::Bare => serde_bare::to_vec(&to_generated_protocol_frame(frame)?) - .map_err(|error| ProtocolCodecError::SerializeFailure(error.to_string())), - } -} - -fn deserialize_payload( - payload: &[u8], - payload_codec: NativePayloadCodec, -) -> Result { - match payload_codec { - NativePayloadCodec::Json => serde_json::from_slice(payload) - .map_err(|error| ProtocolCodecError::DeserializeFailure(error.to_string())), - NativePayloadCodec::Bare => { - let frame: generated_protocol::ProtocolFrame = serde_bare::from_slice(payload) - .map_err(|error| ProtocolCodecError::DeserializeFailure(error.to_string()))?; - from_generated_protocol_frame(frame) - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum NativePayloadCodec { - Json, - Bare, -} - -impl NativePayloadCodec { - pub fn sniff(payload: &[u8]) -> Self { - match payload.first() { - Some(b'{') => Self::Json, - _ => Self::Bare, - } - } - - pub fn alternate(self) -> Self { - match self { - Self::Json => Self::Bare, - Self::Bare => Self::Json, - } - } -} - -#[derive(Debug, Clone)] -pub struct NativeFrameCodec { - max_frame_bytes: usize, - payload_codec: NativePayloadCodec, -} - -impl NativeFrameCodec { - pub fn new(max_frame_bytes: usize) -> Self { - Self::with_payload_codec(max_frame_bytes, NativePayloadCodec::Json) - } - - pub fn with_payload_codec(max_frame_bytes: usize, payload_codec: NativePayloadCodec) -> Self { - Self { - max_frame_bytes, - payload_codec, - } - } - - pub fn max_frame_bytes(&self) -> usize { - self.max_frame_bytes - } - - pub fn payload_codec(&self) -> NativePayloadCodec { - self.payload_codec - } - - pub fn encode(&self, frame: &ProtocolFrame) -> Result, ProtocolCodecError> { - self.encode_with_codec(frame, self.payload_codec) - } - - pub fn encode_with_codec( - &self, - frame: &ProtocolFrame, - payload_codec: NativePayloadCodec, - ) -> Result, ProtocolCodecError> { - validate_frame(frame)?; - - let payload = serialize_payload(frame, payload_codec)?; - if payload.len() > self.max_frame_bytes { - return Err(ProtocolCodecError::FrameTooLarge { - size: payload.len(), - max: self.max_frame_bytes, - }); - } - - let length = - u32::try_from(payload.len()).map_err(|_| ProtocolCodecError::FrameTooLarge { - size: payload.len(), - max: u32::MAX as usize, - })?; - - let mut encoded = Vec::with_capacity(4 + payload.len()); - encoded.extend_from_slice(&length.to_be_bytes()); - encoded.extend_from_slice(&payload); - Ok(encoded) - } - - pub fn decode(&self, bytes: &[u8]) -> Result { - self.decode_detected(bytes).map(|(frame, _)| frame) - } - - pub fn decode_with_codec( - &self, - bytes: &[u8], - payload_codec: NativePayloadCodec, - ) -> Result { - let payload = self.checked_payload(bytes)?; - let frame = deserialize_payload(payload, payload_codec)?; - validate_frame(&frame)?; - Ok(frame) - } - - pub fn decode_detected( - &self, - bytes: &[u8], - ) -> Result<(ProtocolFrame, NativePayloadCodec), ProtocolCodecError> { - let payload = self.checked_payload(bytes)?; - let primary = NativePayloadCodec::sniff(payload); - - match deserialize_payload(payload, primary) { - Ok(frame) => { - validate_frame(&frame)?; - Ok((frame, primary)) - } - Err(primary_error) => { - let alternate = primary.alternate(); - let frame = deserialize_payload(payload, alternate).map_err(|_| primary_error)?; - validate_frame(&frame)?; - Ok((frame, alternate)) - } - } - } - - fn checked_payload<'a>(&self, bytes: &'a [u8]) -> Result<&'a [u8], ProtocolCodecError> { - if bytes.len() < 4 { - return Err(ProtocolCodecError::TruncatedFrame { - actual: bytes.len(), - }); - } - - let declared = - u32::from_be_bytes(bytes[..4].try_into().expect("length prefix is four bytes")) - as usize; - if declared > self.max_frame_bytes { - return Err(ProtocolCodecError::FrameTooLarge { - size: declared, - max: self.max_frame_bytes, - }); - } - - let actual = bytes.len() - 4; - if declared != actual { - return Err(ProtocolCodecError::LengthPrefixMismatch { declared, actual }); - } - Ok(&bytes[4..]) - } -} - -impl Default for NativeFrameCodec { - fn default() -> Self { - Self::new(DEFAULT_MAX_FRAME_BYTES) - } -} - -#[derive(Debug)] -pub struct ResponseTracker { - pending: HashMap, - completed: HashSet, - completed_order: VecDeque, - completed_cap: usize, -} - -#[derive(Debug)] -pub struct SidecarResponseTracker { - pending: HashMap, - completed: HashSet, - completed_order: VecDeque, - completed_cap: usize, -} - -impl ResponseTracker { - pub fn with_completed_cap(completed_cap: usize) -> Self { - Self { - pending: HashMap::new(), - completed: HashSet::new(), - completed_order: VecDeque::new(), - completed_cap: completed_cap.max(1), - } - } - - pub fn completed_count(&self) -> usize { - self.completed.len() - } - - pub fn register_request(&mut self, request: &RequestFrame) -> Result<(), ResponseTrackerError> { - if self.pending.contains_key(&request.request_id) - || self.completed.contains(&request.request_id) - { - return Err(ResponseTrackerError::DuplicateRequestId { - request_id: request.request_id, - }); - } - - self.pending.insert( - request.request_id, - PendingRequest { - ownership: request.ownership.clone(), - expected_response: request.payload.expected_response(), - }, - ); - Ok(()) - } - - pub fn accept_response( - &mut self, - response: &ResponseFrame, - ) -> Result<(), ResponseTrackerError> { - if self.completed.contains(&response.request_id) { - return Err(ResponseTrackerError::DuplicateResponse { - request_id: response.request_id, - }); - } - - let pending = self.pending.get(&response.request_id).ok_or( - ResponseTrackerError::UnmatchedResponse { - request_id: response.request_id, - }, - )?; - - if pending.ownership != response.ownership { - return Err(ResponseTrackerError::OwnershipMismatch { - request_id: response.request_id, - expected: Box::new(pending.ownership.clone()), - actual: Box::new(response.ownership.clone()), - }); - } - - if !pending.expected_response.matches(&response.payload) { - return Err(ResponseTrackerError::ResponseKindMismatch { - request_id: response.request_id, - expected: pending.expected_response.as_str().to_string(), - actual: response.payload.kind_name().to_string(), - }); - } - - self.pending - .remove(&response.request_id) - .expect("pending response should still exist after validation"); - self.completed.insert(response.request_id); - self.completed_order.push_back(response.request_id); - while self.completed.len() > self.completed_cap { - if let Some(evicted) = self.completed_order.pop_front() { - self.completed.remove(&evicted); - } - } - Ok(()) - } -} - -impl Default for ResponseTracker { - fn default() -> Self { - Self::with_completed_cap(DEFAULT_COMPLETED_RESPONSE_CAP) - } -} - -impl SidecarResponseTracker { - pub fn with_completed_cap(completed_cap: usize) -> Self { - Self { - pending: HashMap::new(), - completed: HashSet::new(), - completed_order: VecDeque::new(), - completed_cap: completed_cap.max(1), - } - } - - pub fn pending_count(&self) -> usize { - self.pending.len() - } - - pub fn completed_count(&self) -> usize { - self.completed.len() - } - - pub fn register_request( - &mut self, - request: &SidecarRequestFrame, - ) -> Result<(), SidecarResponseTrackerError> { - if self.pending.contains_key(&request.request_id) - || self.completed.contains(&request.request_id) - { - return Err(SidecarResponseTrackerError::DuplicateRequestId { - request_id: request.request_id, - }); - } - - self.pending.insert( - request.request_id, - PendingSidecarRequest { - ownership: request.ownership.clone(), - expected_response: request.payload.expected_response(), - }, - ); - Ok(()) - } - - pub fn accept_response( - &mut self, - response: &SidecarResponseFrame, - ) -> Result<(), SidecarResponseTrackerError> { - if self.completed.contains(&response.request_id) { - return Err(SidecarResponseTrackerError::DuplicateResponse { - request_id: response.request_id, - }); - } - - let pending = self.pending.get(&response.request_id).ok_or( - SidecarResponseTrackerError::UnmatchedResponse { - request_id: response.request_id, - }, - )?; - - if pending.ownership != response.ownership { - return Err(SidecarResponseTrackerError::OwnershipMismatch { - request_id: response.request_id, - expected: Box::new(pending.ownership.clone()), - actual: Box::new(response.ownership.clone()), - }); - } - - if !pending.expected_response.matches(&response.payload) { - return Err(SidecarResponseTrackerError::ResponseKindMismatch { - request_id: response.request_id, - expected: pending.expected_response.as_str().to_string(), - actual: response.payload.kind_name().to_string(), - }); - } - - self.pending - .remove(&response.request_id) - .expect("pending sidecar response should still exist after validation"); - self.completed.insert(response.request_id); - self.completed_order.push_back(response.request_id); - while self.completed.len() > self.completed_cap { - if let Some(evicted) = self.completed_order.pop_front() { - self.completed.remove(&evicted); - } - } - Ok(()) - } -} - -impl Default for SidecarResponseTracker { - fn default() -> Self { - Self::with_completed_cap(DEFAULT_COMPLETED_RESPONSE_CAP) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ResponseTrackerError { - DuplicateRequestId { - request_id: RequestId, - }, - UnmatchedResponse { - request_id: RequestId, - }, - DuplicateResponse { - request_id: RequestId, - }, - OwnershipMismatch { - request_id: RequestId, - expected: Box, - actual: Box, - }, - ResponseKindMismatch { - request_id: RequestId, - expected: String, - actual: String, - }, -} - -impl fmt::Display for ResponseTrackerError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::DuplicateRequestId { request_id } => { - write!(f, "request id {request_id} is already tracked") - } - Self::UnmatchedResponse { request_id } => { - write!( - f, - "response id {request_id} does not match any pending request" - ) - } - Self::DuplicateResponse { request_id } => { - write!(f, "response id {request_id} has already been completed") - } - Self::OwnershipMismatch { - request_id, - expected, - actual, - } => write!( - f, - "response id {request_id} used ownership {:?}, expected {:?}", - actual, expected - ), - Self::ResponseKindMismatch { - request_id, - expected, - actual, - } => write!( - f, - "response id {request_id} carried {actual}, expected {expected}", - ), - } - } -} - -impl Error for ResponseTrackerError {} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum SidecarResponseTrackerError { - DuplicateRequestId { - request_id: RequestId, - }, - UnmatchedResponse { - request_id: RequestId, - }, - DuplicateResponse { - request_id: RequestId, - }, - OwnershipMismatch { - request_id: RequestId, - expected: Box, - actual: Box, - }, - ResponseKindMismatch { - request_id: RequestId, - expected: String, - actual: String, - }, -} - -impl fmt::Display for SidecarResponseTrackerError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::DuplicateRequestId { request_id } => { - write!(f, "sidecar request id {request_id} is already tracked") - } - Self::UnmatchedResponse { request_id } => { - write!( - f, - "sidecar response id {request_id} does not match any pending request" - ) - } - Self::DuplicateResponse { request_id } => { - write!( - f, - "sidecar response id {request_id} has already been completed" - ) - } - Self::OwnershipMismatch { - request_id, - expected, - actual, - } => write!( - f, - "sidecar response id {request_id} used ownership {:?}, expected {:?}", - actual, expected - ), - Self::ResponseKindMismatch { - request_id, - expected, - actual, - } => write!( - f, - "sidecar response id {request_id} carried {actual}, expected {expected}", - ), - } - } -} - -impl Error for SidecarResponseTrackerError {} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct PendingRequest { - ownership: OwnershipScope, - expected_response: ExpectedResponseKind, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct PendingSidecarRequest { - ownership: OwnershipScope, - expected_response: ExpectedSidecarResponseKind, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum ExpectedResponseKind { - Authenticated, - SessionOpened, - VmCreated, - VmDisposed, - RootFilesystemBootstrapped, - VmConfigured, - HostCallbacksRegistered, - LayerCreated, - LayerSealed, - SnapshotImported, - SnapshotExported, - OverlayCreated, - GuestFilesystemResult, - RootFilesystemSnapshot, - ProcessStarted, - StdinWritten, - StdinClosed, - ProcessKilled, - ProcessSnapshot, - ResourceSnapshot, - ListenerSnapshot, - BoundUdpSnapshot, - VmFetchResult, - SignalState, - ZombieTimerCount, - FilesystemResult, - // `PermissionDecision` is a sidecar-initiated callback response, so no host - // request maps to it in `expected_response_kind`; kept for protocol symmetry. - #[allow(dead_code)] - PermissionDecision, - PersistenceState, - PersistenceFlushed, - ExtResult, - GuestKernelResult, - PtyResized, - PackageLinked, - ProvidedCommands, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum ExpectedSidecarResponseKind { - HostCallback, - JsBridge, - Ext, -} - -impl ExpectedResponseKind { - fn as_str(self) -> &'static str { - match self { - Self::Authenticated => "authenticated", - Self::SessionOpened => "session_opened", - Self::VmCreated => "vm_created", - Self::VmDisposed => "vm_disposed", - Self::RootFilesystemBootstrapped => "root_filesystem_bootstrapped", - Self::VmConfigured => "vm_configured", - Self::HostCallbacksRegistered => "host_callbacks_registered", - Self::LayerCreated => "layer_created", - Self::LayerSealed => "layer_sealed", - Self::SnapshotImported => "snapshot_imported", - Self::SnapshotExported => "snapshot_exported", - Self::OverlayCreated => "overlay_created", - Self::GuestFilesystemResult => "guest_filesystem_result", - Self::RootFilesystemSnapshot => "root_filesystem_snapshot", - Self::ProcessStarted => "process_started", - Self::StdinWritten => "stdin_written", - Self::StdinClosed => "stdin_closed", - Self::ProcessKilled => "process_killed", - Self::ProcessSnapshot => "process_snapshot", - Self::ResourceSnapshot => "resource_snapshot", - Self::ListenerSnapshot => "listener_snapshot", - Self::BoundUdpSnapshot => "bound_udp_snapshot", - Self::VmFetchResult => "vm_fetch_result", - Self::SignalState => "signal_state", - Self::ZombieTimerCount => "zombie_timer_count", - Self::FilesystemResult => "filesystem_result", - Self::PermissionDecision => "permission_decision", - Self::PersistenceState => "persistence_state", - Self::PersistenceFlushed => "persistence_flushed", - Self::ExtResult => "ext_result", - Self::GuestKernelResult => "guest_kernel_result", - Self::PtyResized => "pty_resized", - Self::PackageLinked => "package_linked", - Self::ProvidedCommands => "provided_commands_response", - } - } - - fn matches(self, payload: &ResponsePayload) -> bool { - match payload { - ResponsePayload::Rejected(_) => true, - _ => payload.kind_name() == self.as_str(), - } - } -} - -impl ExpectedSidecarResponseKind { - fn as_str(self) -> &'static str { - match self { - Self::HostCallback => "host_callback_result", - Self::JsBridge => "js_bridge_result", - Self::Ext => "ext_result", - } - } - - fn matches(self, payload: &SidecarResponsePayload) -> bool { - payload.kind_name() == self.as_str() - } -} - -impl RequestPayload { - fn ownership_requirement(&self) -> OwnershipRequirement { - match self { - Self::Authenticate(_) | Self::OpenSession(_) => OwnershipRequirement::Connection, - Self::CreateVm(_) | Self::PersistenceLoad(_) | Self::PersistenceFlush(_) => { - OwnershipRequirement::Session - } - Self::DisposeVm(_) - | Self::BootstrapRootFilesystem(_) - | Self::ConfigureVm(_) - | Self::RegisterHostCallbacks(_) - | Self::CreateLayer(_) - | Self::SealLayer(_) - | Self::ImportSnapshot(_) - | Self::ExportSnapshot(_) - | Self::CreateOverlay(_) - | Self::GuestFilesystemCall(_) - | Self::SnapshotRootFilesystem(_) - | Self::Execute(_) - | Self::WriteStdin(_) - | Self::CloseStdin(_) - | Self::KillProcess(_) - | Self::GetProcessSnapshot(_) - | Self::GetResourceSnapshot(_) - | Self::FindListener(_) - | Self::FindBoundUdp(_) - | Self::VmFetch(_) - | Self::GetSignalState(_) - | Self::GetZombieTimerCount(_) - | Self::GuestKernelCall(_) - | Self::ResizePty(_) - | Self::LinkPackage(_) - | Self::ProvidedCommands(_) - | Self::HostFilesystemCall(_) => OwnershipRequirement::Vm, - Self::Ext(_) => OwnershipRequirement::Any, - } - } - - fn expected_response(&self) -> ExpectedResponseKind { - match self { - Self::Authenticate(_) => ExpectedResponseKind::Authenticated, - Self::OpenSession(_) => ExpectedResponseKind::SessionOpened, - Self::CreateVm(_) => ExpectedResponseKind::VmCreated, - Self::DisposeVm(_) => ExpectedResponseKind::VmDisposed, - Self::BootstrapRootFilesystem(_) => ExpectedResponseKind::RootFilesystemBootstrapped, - Self::ConfigureVm(_) => ExpectedResponseKind::VmConfigured, - Self::RegisterHostCallbacks(_) => ExpectedResponseKind::HostCallbacksRegistered, - Self::CreateLayer(_) => ExpectedResponseKind::LayerCreated, - Self::SealLayer(_) => ExpectedResponseKind::LayerSealed, - Self::ImportSnapshot(_) => ExpectedResponseKind::SnapshotImported, - Self::ExportSnapshot(_) => ExpectedResponseKind::SnapshotExported, - Self::CreateOverlay(_) => ExpectedResponseKind::OverlayCreated, - Self::GuestFilesystemCall(_) => ExpectedResponseKind::GuestFilesystemResult, - Self::SnapshotRootFilesystem(_) => ExpectedResponseKind::RootFilesystemSnapshot, - Self::Execute(_) => ExpectedResponseKind::ProcessStarted, - Self::WriteStdin(_) => ExpectedResponseKind::StdinWritten, - Self::CloseStdin(_) => ExpectedResponseKind::StdinClosed, - Self::KillProcess(_) => ExpectedResponseKind::ProcessKilled, - Self::GetProcessSnapshot(_) => ExpectedResponseKind::ProcessSnapshot, - Self::GetResourceSnapshot(_) => ExpectedResponseKind::ResourceSnapshot, - Self::FindListener(_) => ExpectedResponseKind::ListenerSnapshot, - Self::FindBoundUdp(_) => ExpectedResponseKind::BoundUdpSnapshot, - Self::VmFetch(_) => ExpectedResponseKind::VmFetchResult, - Self::GetSignalState(_) => ExpectedResponseKind::SignalState, - Self::GetZombieTimerCount(_) => ExpectedResponseKind::ZombieTimerCount, - Self::HostFilesystemCall(_) => ExpectedResponseKind::FilesystemResult, - Self::PersistenceLoad(_) => ExpectedResponseKind::PersistenceState, - Self::PersistenceFlush(_) => ExpectedResponseKind::PersistenceFlushed, - Self::Ext(_) => ExpectedResponseKind::ExtResult, - Self::GuestKernelCall(_) => ExpectedResponseKind::GuestKernelResult, - Self::ResizePty(_) => ExpectedResponseKind::PtyResized, - Self::LinkPackage(_) => ExpectedResponseKind::PackageLinked, - Self::ProvidedCommands(_) => ExpectedResponseKind::ProvidedCommands, - } - } -} - -impl SidecarRequestPayload { - fn ownership_requirement(&self) -> OwnershipRequirement { - OwnershipRequirement::Vm - } - - fn expected_response(&self) -> ExpectedSidecarResponseKind { - match self { - Self::HostCallback(_) => ExpectedSidecarResponseKind::HostCallback, - Self::JsBridgeCall(_) => ExpectedSidecarResponseKind::JsBridge, - Self::Ext(_) => ExpectedSidecarResponseKind::Ext, - } - } -} - -impl ResponsePayload { - fn ownership_requirement(&self) -> OwnershipRequirement { - match self { - Self::Authenticated(_) | Self::SessionOpened(_) => OwnershipRequirement::Connection, - Self::VmCreated(_) | Self::PersistenceState(_) | Self::PersistenceFlushed(_) => { - OwnershipRequirement::Session - } - Self::Rejected(_) => OwnershipRequirement::Any, - Self::VmDisposed(_) - | Self::RootFilesystemBootstrapped(_) - | Self::VmConfigured(_) - | Self::HostCallbacksRegistered(_) - | Self::LayerCreated(_) - | Self::LayerSealed(_) - | Self::SnapshotImported(_) - | Self::SnapshotExported(_) - | Self::OverlayCreated(_) - | Self::GuestFilesystemResult(_) - | Self::RootFilesystemSnapshot(_) - | Self::ProcessStarted(_) - | Self::StdinWritten(_) - | Self::StdinClosed(_) - | Self::ProcessKilled(_) - | Self::ProcessSnapshot(_) - | Self::ResourceSnapshot(_) - | Self::ListenerSnapshot(_) - | Self::BoundUdpSnapshot(_) - | Self::VmFetchResult(_) - | Self::SignalState(_) - | Self::ZombieTimerCount(_) - | Self::FilesystemResult(_) - | Self::PermissionDecision(_) - | Self::GuestKernelResult(_) - | Self::PtyResized(_) - | Self::PackageLinked(_) - | Self::ProvidedCommands(_) => OwnershipRequirement::Vm, - Self::ExtResult(_) => OwnershipRequirement::Any, - } - } - - fn kind_name(&self) -> &'static str { - match self { - Self::Authenticated(_) => "authenticated", - Self::SessionOpened(_) => "session_opened", - Self::VmCreated(_) => "vm_created", - Self::VmDisposed(_) => "vm_disposed", - Self::RootFilesystemBootstrapped(_) => "root_filesystem_bootstrapped", - Self::VmConfigured(_) => "vm_configured", - Self::HostCallbacksRegistered(_) => "host_callbacks_registered", - Self::LayerCreated(_) => "layer_created", - Self::LayerSealed(_) => "layer_sealed", - Self::SnapshotImported(_) => "snapshot_imported", - Self::SnapshotExported(_) => "snapshot_exported", - Self::OverlayCreated(_) => "overlay_created", - Self::GuestFilesystemResult(_) => "guest_filesystem_result", - Self::RootFilesystemSnapshot(_) => "root_filesystem_snapshot", - Self::ProcessStarted(_) => "process_started", - Self::StdinWritten(_) => "stdin_written", - Self::StdinClosed(_) => "stdin_closed", - Self::ProcessKilled(_) => "process_killed", - Self::ProcessSnapshot(_) => "process_snapshot", - Self::ResourceSnapshot(_) => "resource_snapshot", - Self::ListenerSnapshot(_) => "listener_snapshot", - Self::BoundUdpSnapshot(_) => "bound_udp_snapshot", - Self::VmFetchResult(_) => "vm_fetch_result", - Self::SignalState(_) => "signal_state", - Self::ZombieTimerCount(_) => "zombie_timer_count", - Self::FilesystemResult(_) => "filesystem_result", - Self::PermissionDecision(_) => "permission_decision", - Self::PersistenceState(_) => "persistence_state", - Self::PersistenceFlushed(_) => "persistence_flushed", - Self::Rejected(_) => "rejected", - Self::ExtResult(_) => "ext_result", - Self::GuestKernelResult(_) => "guest_kernel_result", - Self::PtyResized(_) => "pty_resized", - Self::PackageLinked(_) => "package_linked", - Self::ProvidedCommands(_) => "provided_commands_response", - } - } -} - -impl SidecarResponsePayload { - fn ownership_requirement(&self) -> OwnershipRequirement { - OwnershipRequirement::Vm - } - - fn kind_name(&self) -> &'static str { - match self { - Self::HostCallbackResult(_) => "host_callback_result", - Self::JsBridgeResult(_) => "js_bridge_result", - Self::ExtResult(_) => "ext_result", - } - } -} - -impl EventPayload { - fn ownership_requirement(&self) -> OwnershipRequirement { - match self { - Self::Structured(_) => OwnershipRequirement::SessionOrVm, - Self::VmLifecycle(_) | Self::ProcessOutput(_) | Self::ProcessExited(_) => { - OwnershipRequirement::Vm - } - Self::Ext(_) => OwnershipRequirement::Any, - } - } -} - -pub fn validate_frame(frame: &ProtocolFrame) -> Result<(), ProtocolCodecError> { - match frame { - ProtocolFrame::Request(request) => validate_request(request), - ProtocolFrame::Response(response) => validate_response(response), - ProtocolFrame::Event(event) => validate_event(event), - ProtocolFrame::SidecarRequest(request) => validate_sidecar_request(request), - ProtocolFrame::SidecarResponse(response) => validate_sidecar_response(response), - } -} - -fn validate_request(request: &RequestFrame) -> Result<(), ProtocolCodecError> { - validate_schema(&request.schema)?; - validate_request_id_direction(request.request_id, RequestDirection::Host)?; - - validate_ownership(&request.ownership)?; - validate_requirement(request.payload.ownership_requirement(), &request.ownership)?; - if let RequestPayload::Authenticate(authenticate) = &request.payload { - if authenticate.auth_token.is_empty() { - return Err(ProtocolCodecError::EmptyAuthToken); - } - } - - Ok(()) -} - -fn validate_response(response: &ResponseFrame) -> Result<(), ProtocolCodecError> { - validate_schema(&response.schema)?; - validate_request_id_direction(response.request_id, RequestDirection::Host)?; - - validate_ownership(&response.ownership)?; - validate_requirement( - response.payload.ownership_requirement(), - &response.ownership, - )?; - Ok(()) -} - -fn validate_sidecar_request(request: &SidecarRequestFrame) -> Result<(), ProtocolCodecError> { - validate_schema(&request.schema)?; - validate_request_id_direction(request.request_id, RequestDirection::Sidecar)?; - validate_ownership(&request.ownership)?; - validate_requirement(request.payload.ownership_requirement(), &request.ownership)?; - Ok(()) -} - -fn validate_sidecar_response(response: &SidecarResponseFrame) -> Result<(), ProtocolCodecError> { - validate_schema(&response.schema)?; - validate_request_id_direction(response.request_id, RequestDirection::Sidecar)?; - validate_ownership(&response.ownership)?; - validate_requirement( - response.payload.ownership_requirement(), - &response.ownership, - )?; - Ok(()) -} - -fn validate_event(event: &EventFrame) -> Result<(), ProtocolCodecError> { - validate_schema(&event.schema)?; - validate_ownership(&event.ownership)?; - validate_requirement(event.payload.ownership_requirement(), &event.ownership)?; - Ok(()) -} - -fn validate_schema(schema: &ProtocolSchema) -> Result<(), ProtocolCodecError> { - if schema.name != PROTOCOL_NAME || schema.version != PROTOCOL_VERSION { - return Err(ProtocolCodecError::UnsupportedSchema { - name: schema.name.clone(), - version: schema.version, - }); - } - - Ok(()) -} - -fn validate_ownership(ownership: &OwnershipScope) -> Result<(), ProtocolCodecError> { - match ownership { - OwnershipScope::ConnectionOwnership(inner) => { - validate_non_empty("connection_id", &inner.connection_id) - } - OwnershipScope::SessionOwnership(inner) => { - validate_non_empty("connection_id", &inner.connection_id)?; - validate_non_empty("session_id", &inner.session_id) - } - OwnershipScope::VmOwnership(inner) => { - validate_non_empty("connection_id", &inner.connection_id)?; - validate_non_empty("session_id", &inner.session_id)?; - validate_non_empty("vm_id", &inner.vm_id) - } - } -} - -fn validate_non_empty(field: &'static str, value: &str) -> Result<(), ProtocolCodecError> { - if value.is_empty() { - return Err(ProtocolCodecError::EmptyOwnershipField { field }); - } - - Ok(()) -} - -fn validate_request_id_direction( - request_id: RequestId, - direction: RequestDirection, -) -> Result<(), ProtocolCodecError> { - if request_id == 0 { - return Err(ProtocolCodecError::InvalidRequestId); - } - - let matches_direction = match direction { - RequestDirection::Host => request_id > 0, - RequestDirection::Sidecar => request_id < 0, - }; - if matches_direction { - Ok(()) - } else { - Err(ProtocolCodecError::InvalidRequestDirection { - request_id, - expected: direction, - }) - } -} - -fn validate_requirement( - required: OwnershipRequirement, - ownership: &OwnershipScope, -) -> Result<(), ProtocolCodecError> { - let actual = match ownership { - OwnershipScope::ConnectionOwnership(..) => OwnershipRequirement::Connection, - OwnershipScope::SessionOwnership(..) => OwnershipRequirement::Session, - OwnershipScope::VmOwnership(..) => OwnershipRequirement::Vm, - }; - - let valid = match required { - OwnershipRequirement::Any => true, - OwnershipRequirement::Connection => { - matches!(ownership, OwnershipScope::ConnectionOwnership(..)) - } - OwnershipRequirement::Session => matches!(ownership, OwnershipScope::SessionOwnership(..)), - OwnershipRequirement::Vm => matches!(ownership, OwnershipScope::VmOwnership(..)), - OwnershipRequirement::SessionOrVm => { - matches!( - ownership, - OwnershipScope::SessionOwnership(..) | OwnershipScope::VmOwnership(..) - ) - } - }; - - if valid { - Ok(()) - } else { - Err(ProtocolCodecError::InvalidOwnershipScope { required, actual }) - } -} - -// --------------------------------------------------------------------------- -// JavaScript sync-RPC request types (deserialized from guest Node.js processes) -// --------------------------------------------------------------------------- - -#[derive(Debug, Deserialize, Default)] -pub struct JavascriptChildProcessSpawnOptions { - #[serde(default)] - pub cwd: Option, - #[serde(default)] - pub env: BTreeMap, - #[serde(rename = "internalBootstrapEnv", default)] - pub internal_bootstrap_env: BTreeMap, - #[serde(default)] - pub input: Option, - #[serde(default)] - pub shell: bool, - #[serde(default)] - pub detached: bool, - #[serde(default)] - pub stdio: Vec, - #[serde(default)] - pub timeout: Option, - #[serde(rename = "killSignal", default)] - pub kill_signal: Option, -} - -#[derive(Debug, Deserialize)] -pub struct JavascriptChildProcessSpawnRequest { - pub command: String, - #[serde(default)] - pub args: Vec, - #[serde(default)] - pub options: JavascriptChildProcessSpawnOptions, -} - -#[derive(Debug, Deserialize)] -pub struct JavascriptNetConnectRequest { - #[serde(default)] - pub host: Option, - #[serde(default)] - pub port: Option, - #[serde(default)] - pub path: Option, - #[serde(rename = "localAddress", default)] - pub local_address: Option, - #[serde(rename = "localPort", default)] - pub local_port: Option, - #[serde(rename = "localReservation", default)] - pub local_reservation: Option, -} - -#[derive(Debug, Deserialize)] -pub struct JavascriptNetReserveTcpPortRequest { - #[serde(default)] - pub host: Option, - #[serde(default)] - pub port: Option, -} - -#[derive(Debug, Deserialize)] -pub struct JavascriptNetListenRequest { - #[serde(default)] - pub host: Option, - #[serde(default)] - pub port: Option, - #[serde(default)] - pub path: Option, - #[serde(default)] - pub backlog: Option, - #[serde(rename = "localReservation", default)] - pub local_reservation: Option, -} - -#[derive(Debug, Deserialize)] -pub struct JavascriptDgramCreateSocketRequest { - #[serde(rename = "type")] - pub socket_type: String, -} - -#[derive(Debug, Deserialize)] -pub struct JavascriptDgramBindRequest { - #[serde(default)] - pub address: Option, - #[serde(default)] - pub port: u16, -} - -#[derive(Debug, Deserialize)] -pub struct JavascriptDgramSendRequest { - #[serde(default)] - pub address: Option, - pub port: u16, -} - -#[derive(Debug, Deserialize)] -pub struct JavascriptDnsLookupRequest { - pub hostname: String, - #[serde(default)] - pub family: Option, -} - -#[derive(Debug, Deserialize)] -pub struct JavascriptDnsResolveRequest { - pub hostname: String, - #[serde(default)] - pub rrtype: Option, -} diff --git a/crates/sidecar-protocol/src/wire.rs b/crates/sidecar-protocol/src/wire.rs deleted file mode 100644 index 6ad73cf8b..000000000 --- a/crates/sidecar-protocol/src/wire.rs +++ /dev/null @@ -1,1269 +0,0 @@ -//! Generated Secure Exec sidecar wire protocol surface. -//! -//! This module is the public generated protocol entrypoint. The hand-written -//! `protocol` module remains an internal compatibility layer while callers move -//! to generated wire frames. - -use std::error::Error; -use std::fmt; - -pub use crate::generated_protocol::v1::*; - -// The generated BARE types intentionally omit `Copy`/`Default`; restore them on the -// crate-local generated types so the wider sidecar keeps the ergonomics it relies on -// after the hand-written protocol types were replaced with these aliases. These live in -// `wire` (not `protocol`) because `protocol.rs` is `#[path]`-included by integration -// tests, where the generated types would be foreign and the impls would break the orphan rule. -impl Copy for crate::generated_protocol::v1::GuestFilesystemOperation {} -impl Copy for crate::generated_protocol::v1::RootFilesystemMode {} -impl Copy for crate::generated_protocol::v1::WasmPermissionTier {} - -// `derive(Default)` cannot be added: these are foreign generated types, so the -// `Default` impl must be written by hand here (orphan rule). -#[allow(clippy::derivable_impls)] -impl Default for crate::generated_protocol::v1::RootFilesystemEntryKind { - fn default() -> Self { - Self::File - } -} - -impl Default for crate::generated_protocol::v1::RootFilesystemEntry { - fn default() -> Self { - Self { - path: String::new(), - kind: crate::generated_protocol::v1::RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: None, - encoding: None, - target: None, - executable: false, - } - } -} - -#[allow(clippy::derivable_impls)] -impl Default for crate::generated_protocol::v1::RootFilesystemMode { - fn default() -> Self { - Self::Ephemeral - } -} - -#[allow(clippy::derivable_impls)] -impl Default for crate::generated_protocol::v1::RootFilesystemDescriptor { - fn default() -> Self { - Self { - mode: crate::generated_protocol::v1::RootFilesystemMode::default(), - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - } - } -} - -impl crate::generated_protocol::v1::PermissionsPolicy { - pub fn deny_all() -> Self { - use crate::generated_protocol::v1::{ - FsPermissionScope, PatternPermissionScope, PermissionMode, - }; - Self { - fs: Some(FsPermissionScope::PermissionMode(PermissionMode::Deny)), - network: Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)), - child_process: Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)), - process: Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)), - env: Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)), - binding: Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)), - } - } - - pub fn allow_all() -> Self { - use crate::generated_protocol::v1::{ - FsPermissionScope, PatternPermissionScope, PermissionMode, - }; - Self { - fs: Some(FsPermissionScope::PermissionMode(PermissionMode::Allow)), - network: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - child_process: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - process: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - env: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - binding: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - } - } -} - -impl Default for crate::generated_protocol::v1::PermissionsPolicy { - fn default() -> Self { - Self::deny_all() - } -} - -impl crate::generated_protocol::v1::CreateVmRequest { - pub fn json_config( - runtime: crate::generated_protocol::v1::GuestRuntimeKind, - config: secure_exec_vm_config::CreateVmConfig, - ) -> Self { - Self { - runtime, - config: serde_json::to_string(&config).expect("serialize create VM config"), - } - } - - pub fn legacy_test_config( - runtime: crate::generated_protocol::v1::GuestRuntimeKind, - metadata: std::collections::HashMap, - root_filesystem: crate::generated_protocol::v1::RootFilesystemDescriptor, - permissions: Option, - ) -> Self { - let metadata: std::collections::BTreeMap<_, _> = metadata.into_iter().collect(); - let mut config = secure_exec_vm_config::CreateVmConfig { - cwd: metadata.get("cwd").cloned(), - env: legacy_env_config(&metadata), - root_filesystem: legacy_root_filesystem_config(root_filesystem), - permissions: permissions.map(permissions_policy_config_from_wire), - limits: legacy_limits_config(&metadata), - dns: legacy_dns_config(&metadata), - native_root: legacy_native_root_config(&metadata), - listen: legacy_listen_config(&metadata), - ..Default::default() - }; - config.loopback_exempt_ports = legacy_loopback_exempt_ports(&config.env); - Self::json_config(runtime, config) - } -} - -fn legacy_env_config( - metadata: &std::collections::BTreeMap, -) -> std::collections::BTreeMap { - metadata - .iter() - .filter_map(|(key, value)| { - key.strip_prefix("env.") - .map(|name| (name.to_string(), value.clone())) - }) - .collect() -} - -fn legacy_root_filesystem_config( - descriptor: crate::generated_protocol::v1::RootFilesystemDescriptor, -) -> secure_exec_vm_config::RootFilesystemConfig { - secure_exec_vm_config::RootFilesystemConfig { - mode: match descriptor.mode { - crate::generated_protocol::v1::RootFilesystemMode::Ephemeral => { - secure_exec_vm_config::RootFilesystemMode::Ephemeral - } - crate::generated_protocol::v1::RootFilesystemMode::ReadOnly => { - secure_exec_vm_config::RootFilesystemMode::ReadOnly - } - }, - disable_default_base_layer: descriptor.disable_default_base_layer, - lowers: descriptor - .lowers - .into_iter() - .map(legacy_root_lower_config) - .collect(), - bootstrap_entries: descriptor - .bootstrap_entries - .into_iter() - .map(legacy_root_entry_config) - .collect(), - } -} - -fn legacy_root_lower_config( - lower: crate::generated_protocol::v1::RootFilesystemLowerDescriptor, -) -> secure_exec_vm_config::RootFilesystemLowerDescriptor { - match lower { - crate::generated_protocol::v1::RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - snapshot, - ) => secure_exec_vm_config::RootFilesystemLowerDescriptor::Snapshot { - entries: snapshot - .entries - .into_iter() - .map(legacy_root_entry_config) - .collect(), - }, - crate::generated_protocol::v1::RootFilesystemLowerDescriptor::BundledBaseFilesystemLower => { - secure_exec_vm_config::RootFilesystemLowerDescriptor::BundledBaseFilesystem - } - } -} - -fn legacy_root_entry_config( - entry: crate::generated_protocol::v1::RootFilesystemEntry, -) -> secure_exec_vm_config::RootFilesystemEntry { - secure_exec_vm_config::RootFilesystemEntry { - path: entry.path, - kind: match entry.kind { - crate::generated_protocol::v1::RootFilesystemEntryKind::File => { - secure_exec_vm_config::RootFilesystemEntryKind::File - } - crate::generated_protocol::v1::RootFilesystemEntryKind::Directory => { - secure_exec_vm_config::RootFilesystemEntryKind::Directory - } - crate::generated_protocol::v1::RootFilesystemEntryKind::Symlink => { - secure_exec_vm_config::RootFilesystemEntryKind::Symlink - } - }, - mode: entry.mode, - uid: entry.uid, - gid: entry.gid, - content: entry.content, - encoding: entry.encoding.map(|encoding| match encoding { - crate::generated_protocol::v1::RootFilesystemEntryEncoding::Utf8 => { - secure_exec_vm_config::RootFilesystemEntryEncoding::Utf8 - } - crate::generated_protocol::v1::RootFilesystemEntryEncoding::Base64 => { - secure_exec_vm_config::RootFilesystemEntryEncoding::Base64 - } - }), - target: entry.target, - executable: entry.executable, - } -} - -pub fn permissions_policy_config_from_wire( - permissions: crate::generated_protocol::v1::PermissionsPolicy, -) -> secure_exec_vm_config::PermissionsPolicy { - secure_exec_vm_config::PermissionsPolicy { - fs: permissions.fs.map(legacy_fs_permission_scope_config), - network: permissions - .network - .map(legacy_pattern_permission_scope_config), - child_process: permissions - .child_process - .map(legacy_pattern_permission_scope_config), - process: permissions - .process - .map(legacy_pattern_permission_scope_config), - env: permissions.env.map(legacy_pattern_permission_scope_config), - binding: permissions - .binding - .map(legacy_pattern_permission_scope_config), - } -} - -fn legacy_permission_mode_config( - mode: crate::generated_protocol::v1::PermissionMode, -) -> secure_exec_vm_config::PermissionMode { - match mode { - crate::generated_protocol::v1::PermissionMode::Allow => { - secure_exec_vm_config::PermissionMode::Allow - } - crate::generated_protocol::v1::PermissionMode::Ask => { - secure_exec_vm_config::PermissionMode::Ask - } - crate::generated_protocol::v1::PermissionMode::Deny => { - secure_exec_vm_config::PermissionMode::Deny - } - } -} - -fn legacy_fs_permission_scope_config( - scope: crate::generated_protocol::v1::FsPermissionScope, -) -> secure_exec_vm_config::FsPermissionScope { - match scope { - crate::generated_protocol::v1::FsPermissionScope::PermissionMode(mode) => { - secure_exec_vm_config::FsPermissionScope::Mode(legacy_permission_mode_config(mode)) - } - crate::generated_protocol::v1::FsPermissionScope::FsPermissionRuleSet(rules) => { - secure_exec_vm_config::FsPermissionScope::Rules( - secure_exec_vm_config::FsPermissionRuleSet { - default: rules.default.map(legacy_permission_mode_config), - rules: rules - .rules - .into_iter() - .map(|rule| secure_exec_vm_config::FsPermissionRule { - mode: legacy_permission_mode_config(rule.mode), - operations: rule.operations, - paths: rule.paths, - }) - .collect(), - }, - ) - } - } -} - -fn legacy_pattern_permission_scope_config( - scope: crate::generated_protocol::v1::PatternPermissionScope, -) -> secure_exec_vm_config::PatternPermissionScope { - match scope { - crate::generated_protocol::v1::PatternPermissionScope::PermissionMode(mode) => { - secure_exec_vm_config::PatternPermissionScope::Mode(legacy_permission_mode_config(mode)) - } - crate::generated_protocol::v1::PatternPermissionScope::PatternPermissionRuleSet(rules) => { - secure_exec_vm_config::PatternPermissionScope::Rules( - secure_exec_vm_config::PatternPermissionRuleSet { - default: rules.default.map(legacy_permission_mode_config), - rules: rules - .rules - .into_iter() - .map(|rule| secure_exec_vm_config::PatternPermissionRule { - mode: legacy_permission_mode_config(rule.mode), - operations: rule.operations, - patterns: rule.patterns, - }) - .collect(), - }, - ) - } - } -} - -fn legacy_dns_config( - metadata: &std::collections::BTreeMap, -) -> Option { - let mut dns = secure_exec_vm_config::VmDnsConfig::default(); - if let Some(value) = metadata.get("network.dns.servers") { - dns.name_servers = value - .split(',') - .map(str::trim) - .filter(|entry| !entry.is_empty()) - .map(str::to_string) - .collect(); - } - for (key, value) in metadata { - let Some(hostname) = key.strip_prefix("network.dns.override.") else { - continue; - }; - dns.overrides.insert( - hostname.to_string(), - value - .split(',') - .map(str::trim) - .filter(|entry| !entry.is_empty()) - .map(str::to_string) - .collect(), - ); - } - if dns.name_servers.is_empty() && dns.overrides.is_empty() { - None - } else { - Some(dns) - } -} - -fn legacy_native_root_config( - metadata: &std::collections::BTreeMap, -) -> Option { - let id = metadata.get("rootFilesystem.nativePlugin.id")?; - let config = metadata - .get("rootFilesystem.nativePlugin.config") - .map(|value| serde_json::from_str(value).expect("parse native root plugin config")) - .unwrap_or_else(|| serde_json::Value::Object(serde_json::Map::new())); - let read_only = metadata - .get("rootFilesystem.nativePlugin.readOnly") - .map(|value| value.parse::().expect("parse native root readOnly")) - .unwrap_or(false); - Some(secure_exec_vm_config::NativeRootFilesystemConfig { - plugin: secure_exec_vm_config::MountPluginDescriptor { - id: id.clone(), - config, - }, - read_only, - }) -} - -fn legacy_listen_config( - metadata: &std::collections::BTreeMap, -) -> Option { - let listen = secure_exec_vm_config::VmListenPolicyConfig { - port_min: metadata - .get("network.listen.port_min") - .map(|value| value.parse::().expect("parse network.listen.port_min")), - port_max: metadata - .get("network.listen.port_max") - .map(|value| value.parse::().expect("parse network.listen.port_max")), - allow_privileged: metadata - .get("network.listen.allow_privileged") - .map(|value| { - value - .parse::() - .expect("parse network.listen.allow_privileged") - }), - }; - if listen.port_min.is_none() && listen.port_max.is_none() && listen.allow_privileged.is_none() { - None - } else { - Some(listen) - } -} - -fn legacy_loopback_exempt_ports(env: &std::collections::BTreeMap) -> Vec { - let Some(value) = env.get("AGENTOS_LOOPBACK_EXEMPT_PORTS") else { - return Vec::new(); - }; - serde_json::from_str::>(value) - .unwrap_or_default() - .into_iter() - .filter_map(|value| match value { - serde_json::Value::Number(number) => number.as_u64(), - serde_json::Value::String(value) => value.parse::().ok(), - _ => None, - }) - .filter_map(|port| u16::try_from(port).ok()) - .collect() -} - -fn legacy_limits_config( - metadata: &std::collections::BTreeMap, -) -> Option { - let resources = secure_exec_vm_config::ResourceLimitsConfig { - cpu_count: legacy_u64(metadata, "resource.cpu_count"), - max_processes: legacy_u64(metadata, "resource.max_processes"), - max_open_fds: legacy_u64(metadata, "resource.max_open_fds"), - max_pipes: legacy_u64(metadata, "resource.max_pipes"), - max_ptys: legacy_u64(metadata, "resource.max_ptys"), - max_sockets: legacy_u64(metadata, "resource.max_sockets"), - max_connections: legacy_u64(metadata, "resource.max_connections"), - max_socket_buffered_bytes: legacy_u64(metadata, "resource.max_socket_buffered_bytes"), - max_socket_datagram_queue_len: legacy_u64( - metadata, - "resource.max_socket_datagram_queue_len", - ), - max_filesystem_bytes: legacy_u64(metadata, "resource.max_filesystem_bytes"), - max_inode_count: legacy_u64(metadata, "resource.max_inode_count"), - max_blocking_read_ms: legacy_u64(metadata, "resource.max_blocking_read_ms"), - max_pread_bytes: legacy_u64(metadata, "resource.max_pread_bytes"), - max_fd_write_bytes: legacy_u64(metadata, "resource.max_fd_write_bytes"), - max_process_argv_bytes: legacy_u64(metadata, "resource.max_process_argv_bytes"), - max_process_env_bytes: legacy_u64(metadata, "resource.max_process_env_bytes"), - max_readdir_entries: legacy_u64(metadata, "resource.max_readdir_entries"), - max_recursive_fs_depth: legacy_u64(metadata, "resource.max_recursive_fs_depth"), - max_recursive_fs_entries: legacy_u64(metadata, "resource.max_recursive_fs_entries"), - max_wasm_fuel: legacy_u64(metadata, "resource.max_wasm_fuel"), - max_wasm_memory_bytes: legacy_u64(metadata, "resource.max_wasm_memory_bytes"), - max_wasm_stack_bytes: legacy_u64(metadata, "resource.max_wasm_stack_bytes"), - }; - let http = secure_exec_vm_config::HttpLimitsConfig { - max_fetch_response_bytes: legacy_u64(metadata, "limits.http.max_fetch_response_bytes"), - }; - let tools = secure_exec_vm_config::ToolLimitsConfig { - default_tool_timeout_ms: legacy_u64(metadata, "limits.tools.default_tool_timeout_ms"), - max_tool_timeout_ms: legacy_u64(metadata, "limits.tools.max_tool_timeout_ms"), - max_registered_toolkits: legacy_u64(metadata, "limits.tools.max_registered_toolkits"), - max_registered_tools_per_vm: legacy_u64( - metadata, - "limits.tools.max_registered_tools_per_vm", - ), - max_tools_per_toolkit: legacy_u64(metadata, "limits.tools.max_tools_per_toolkit"), - max_tool_schema_bytes: legacy_u64(metadata, "limits.tools.max_tool_schema_bytes"), - max_tool_examples_per_tool: legacy_u64(metadata, "limits.tools.max_tool_examples_per_tool"), - max_tool_example_input_bytes: legacy_u64( - metadata, - "limits.tools.max_tool_example_input_bytes", - ), - }; - let plugins = secure_exec_vm_config::PluginLimitsConfig { - max_persisted_manifest_bytes: legacy_u64( - metadata, - "limits.plugins.max_persisted_manifest_bytes", - ), - max_persisted_manifest_file_bytes: legacy_u64( - metadata, - "limits.plugins.max_persisted_manifest_file_bytes", - ), - }; - let acp = secure_exec_vm_config::AcpLimitsConfig { - max_read_line_bytes: legacy_u64(metadata, "limits.acp.max_read_line_bytes"), - stdout_buffer_byte_limit: legacy_u64(metadata, "limits.acp.stdout_buffer_byte_limit"), - }; - let js_runtime = secure_exec_vm_config::JsRuntimeLimitsConfig { - v8_heap_limit_mb: legacy_u64(metadata, "limits.js_runtime.v8_heap_limit_mb"), - sync_rpc_wait_timeout_ms: legacy_u64( - metadata, - "limits.js_runtime.sync_rpc_wait_timeout_ms", - ), - cpu_time_limit_ms: legacy_u64(metadata, "limits.js_runtime.cpu_time_limit_ms"), - wall_clock_limit_ms: legacy_u64(metadata, "limits.js_runtime.wall_clock_limit_ms"), - import_cache_materialize_timeout_ms: legacy_u64( - metadata, - "limits.js_runtime.import_cache_materialize_timeout_ms", - ), - captured_output_limit_bytes: legacy_u64( - metadata, - "limits.js_runtime.captured_output_limit_bytes", - ), - stdin_buffer_limit_bytes: legacy_u64( - metadata, - "limits.js_runtime.stdin_buffer_limit_bytes", - ), - event_payload_limit_bytes: legacy_u64( - metadata, - "limits.js_runtime.event_payload_limit_bytes", - ), - v8_ipc_max_frame_bytes: legacy_u64(metadata, "limits.js_runtime.v8_ipc_max_frame_bytes"), - }; - let python = secure_exec_vm_config::PythonLimitsConfig { - output_buffer_max_bytes: legacy_u64(metadata, "limits.python.output_buffer_max_bytes"), - execution_timeout_ms: legacy_u64(metadata, "limits.python.execution_timeout_ms"), - max_old_space_mb: legacy_u64(metadata, "limits.python.max_old_space_mb"), - vfs_rpc_timeout_ms: legacy_u64(metadata, "limits.python.vfs_rpc_timeout_ms"), - }; - let wasm = secure_exec_vm_config::WasmLimitsConfig { - max_module_file_bytes: legacy_u64(metadata, "limits.wasm.max_module_file_bytes"), - captured_output_limit_bytes: legacy_u64( - metadata, - "limits.wasm.captured_output_limit_bytes", - ), - sync_read_limit_bytes: legacy_u64(metadata, "limits.wasm.sync_read_limit_bytes"), - prewarm_timeout_ms: legacy_u64(metadata, "limits.wasm.prewarm_timeout_ms"), - runner_heap_limit_mb: legacy_u64(metadata, "limits.wasm.runner_heap_limit_mb"), - }; - - let config = secure_exec_vm_config::VmLimitsConfig { - resources: legacy_has_resource_limits(&resources).then_some(resources), - http: http.max_fetch_response_bytes.is_some().then_some(http), - tools: legacy_has_tool_limits(&tools).then_some(tools), - plugins: legacy_has_plugin_limits(&plugins).then_some(plugins), - acp: legacy_has_acp_limits(&acp).then_some(acp), - js_runtime: legacy_has_js_runtime_limits(&js_runtime).then_some(js_runtime), - python: legacy_has_python_limits(&python).then_some(python), - wasm: legacy_has_wasm_limits(&wasm).then_some(wasm), - }; - - if config.resources.is_none() - && config.http.is_none() - && config.tools.is_none() - && config.plugins.is_none() - && config.acp.is_none() - && config.js_runtime.is_none() - && config.python.is_none() - && config.wasm.is_none() - { - None - } else { - Some(config) - } -} - -fn legacy_u64(metadata: &std::collections::BTreeMap, key: &str) -> Option { - metadata.get(key).map(|value| { - value - .parse::() - .unwrap_or_else(|error| panic!("parse {key}: {error}")) - }) -} - -fn legacy_has_resource_limits(config: &secure_exec_vm_config::ResourceLimitsConfig) -> bool { - config.cpu_count.is_some() - || config.max_processes.is_some() - || config.max_open_fds.is_some() - || config.max_pipes.is_some() - || config.max_ptys.is_some() - || config.max_sockets.is_some() - || config.max_connections.is_some() - || config.max_socket_buffered_bytes.is_some() - || config.max_socket_datagram_queue_len.is_some() - || config.max_filesystem_bytes.is_some() - || config.max_inode_count.is_some() - || config.max_blocking_read_ms.is_some() - || config.max_pread_bytes.is_some() - || config.max_fd_write_bytes.is_some() - || config.max_process_argv_bytes.is_some() - || config.max_process_env_bytes.is_some() - || config.max_readdir_entries.is_some() - || config.max_wasm_fuel.is_some() - || config.max_wasm_memory_bytes.is_some() - || config.max_wasm_stack_bytes.is_some() -} - -fn legacy_has_tool_limits(config: &secure_exec_vm_config::ToolLimitsConfig) -> bool { - config.default_tool_timeout_ms.is_some() - || config.max_tool_timeout_ms.is_some() - || config.max_registered_toolkits.is_some() - || config.max_registered_tools_per_vm.is_some() - || config.max_tools_per_toolkit.is_some() - || config.max_tool_schema_bytes.is_some() - || config.max_tool_examples_per_tool.is_some() - || config.max_tool_example_input_bytes.is_some() -} - -fn legacy_has_plugin_limits(config: &secure_exec_vm_config::PluginLimitsConfig) -> bool { - config.max_persisted_manifest_bytes.is_some() - || config.max_persisted_manifest_file_bytes.is_some() -} - -fn legacy_has_acp_limits(config: &secure_exec_vm_config::AcpLimitsConfig) -> bool { - config.max_read_line_bytes.is_some() || config.stdout_buffer_byte_limit.is_some() -} - -fn legacy_has_js_runtime_limits(config: &secure_exec_vm_config::JsRuntimeLimitsConfig) -> bool { - config.v8_heap_limit_mb.is_some() - || config.sync_rpc_wait_timeout_ms.is_some() - || config.cpu_time_limit_ms.is_some() - || config.wall_clock_limit_ms.is_some() - || config.import_cache_materialize_timeout_ms.is_some() - || config.captured_output_limit_bytes.is_some() - || config.stdin_buffer_limit_bytes.is_some() - || config.event_payload_limit_bytes.is_some() - || config.v8_ipc_max_frame_bytes.is_some() -} - -fn legacy_has_python_limits(config: &secure_exec_vm_config::PythonLimitsConfig) -> bool { - config.output_buffer_max_bytes.is_some() - || config.execution_timeout_ms.is_some() - || config.max_old_space_mb.is_some() - || config.vfs_rpc_timeout_ms.is_some() -} - -fn legacy_has_wasm_limits(config: &secure_exec_vm_config::WasmLimitsConfig) -> bool { - config.max_module_file_bytes.is_some() - || config.captured_output_limit_bytes.is_some() - || config.sync_read_limit_bytes.is_some() - || config.prewarm_timeout_ms.is_some() - || config.runner_heap_limit_mb.is_some() -} - -// Ownership-scope constructor ergonomics. The generated BARE union exposes only the -// tuple-wrapped variants (`ConnectionOwnership`/`SessionOwnership`/`VmOwnership`); restore -// the hand-written `connection`/`session`/`vm` helpers the sidecar relies on. These live in -// `wire` (not `protocol`) for the same orphan-rule reason as the impls above: `protocol.rs` -// is `#[path]`-included by integration tests where the generated type is foreign. -impl crate::generated_protocol::v1::OwnershipScope { - pub fn connection(connection_id: impl Into) -> Self { - Self::ConnectionOwnership(crate::generated_protocol::v1::ConnectionOwnership { - connection_id: connection_id.into(), - }) - } - - pub fn session(connection_id: impl Into, session_id: impl Into) -> Self { - Self::SessionOwnership(crate::generated_protocol::v1::SessionOwnership { - connection_id: connection_id.into(), - session_id: session_id.into(), - }) - } - - pub fn vm( - connection_id: impl Into, - session_id: impl Into, - vm_id: impl Into, - ) -> Self { - Self::VmOwnership(crate::generated_protocol::v1::VmOwnership { - connection_id: connection_id.into(), - session_id: session_id.into(), - vm_id: vm_id.into(), - }) - } -} - -pub const PROTOCOL_NAME: &str = "secure-exec-sidecar"; -pub const PROTOCOL_VERSION: u16 = 7; -// 16 MiB: large enough to carry a trusted-client CreateVm config that inlines an -// entire base-filesystem snapshot, while still bounding a single frame. -pub const DEFAULT_MAX_FRAME_BYTES: usize = 16 * 1024 * 1024; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ProtocolCodecError { - TruncatedFrame { - actual: usize, - }, - LengthPrefixMismatch { - declared: usize, - actual: usize, - }, - FrameTooLarge { - size: usize, - max: usize, - }, - UnsupportedSchema { - name: String, - version: u16, - }, - InvalidRequestId, - InvalidRequestDirection { - request_id: RequestId, - expected: RequestDirection, - }, - EmptyOwnershipField { - field: &'static str, - }, - EmptyAuthToken, - InvalidOwnershipScope { - required: OwnershipRequirement, - actual: OwnershipRequirement, - }, - SerializeFailure(String), - DeserializeFailure(String), -} - -impl fmt::Display for ProtocolCodecError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::TruncatedFrame { actual } => { - write!( - f, - "protocol frame is truncated: only {actual} bytes provided" - ) - } - Self::LengthPrefixMismatch { declared, actual } => write!( - f, - "protocol frame length prefix mismatch: declared {declared} bytes, got {actual}", - ), - Self::FrameTooLarge { size, max } => { - write!(f, "protocol frame is {size} bytes, limit is {max}") - } - Self::UnsupportedSchema { name, version } => write!( - f, - "unsupported protocol schema {name}@{version}; expected {PROTOCOL_NAME}@{PROTOCOL_VERSION}", - ), - Self::InvalidRequestId => write!(f, "protocol request identifiers must be non-zero"), - Self::InvalidRequestDirection { - request_id, - expected, - } => write!(f, "protocol request id {request_id} must be {expected}",), - Self::EmptyOwnershipField { field } => { - write!(f, "protocol ownership field `{field}` cannot be empty") - } - Self::EmptyAuthToken => { - write!(f, "authenticate requests require a non-empty auth token") - } - Self::InvalidOwnershipScope { required, actual } => write!( - f, - "protocol frame requires {required} ownership but carried {actual}", - ), - Self::SerializeFailure(message) => { - write!(f, "protocol frame serialization failed: {message}") - } - Self::DeserializeFailure(message) => { - write!(f, "protocol frame deserialization failed: {message}") - } - } - } -} - -impl Error for ProtocolCodecError {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum OwnershipRequirement { - Any, - Connection, - Session, - Vm, - SessionOrVm, -} - -impl fmt::Display for OwnershipRequirement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Any => write!(f, "any"), - Self::Connection => write!(f, "connection"), - Self::Session => write!(f, "session"), - Self::Vm => write!(f, "vm"), - Self::SessionOrVm => write!(f, "session-or-vm"), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum RequestDirection { - Host, - Sidecar, -} - -impl fmt::Display for RequestDirection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Host => write!(f, "positive"), - Self::Sidecar => write!(f, "negative"), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WireDispatchResult { - pub response: ResponseFrame, - pub events: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CompatDispatchResult { - pub response: crate::protocol::ResponseFrame, - pub events: Vec, -} - -#[derive(Debug, Clone)] -pub struct WireFrameCodec { - max_frame_bytes: usize, -} - -impl WireFrameCodec { - pub fn new(max_frame_bytes: usize) -> Self { - Self { max_frame_bytes } - } - - pub fn max_frame_bytes(&self) -> usize { - self.max_frame_bytes - } - - pub fn encode(&self, frame: &ProtocolFrame) -> Result, ProtocolCodecError> { - validate_frame(frame)?; - - let payload = serde_bare::to_vec(frame) - .map_err(|error| ProtocolCodecError::SerializeFailure(error.to_string()))?; - if payload.len() > self.max_frame_bytes { - return Err(ProtocolCodecError::FrameTooLarge { - size: payload.len(), - max: self.max_frame_bytes, - }); - } - - let length = - u32::try_from(payload.len()).map_err(|_| ProtocolCodecError::FrameTooLarge { - size: payload.len(), - max: u32::MAX as usize, - })?; - - let mut encoded = Vec::with_capacity(4 + payload.len()); - encoded.extend_from_slice(&length.to_be_bytes()); - encoded.extend_from_slice(&payload); - Ok(encoded) - } - - pub fn decode(&self, bytes: &[u8]) -> Result { - let payload = self.checked_payload(bytes)?; - let frame = serde_bare::from_slice(payload) - .map_err(|error| ProtocolCodecError::DeserializeFailure(error.to_string()))?; - validate_frame(&frame)?; - Ok(frame) - } - - /// Encode a frame as a bare message WITHOUT the 4-byte length prefix. - /// - /// Stream transports (stdio) use [`encode`] so frames can be delimited in a - /// byte stream. Message transports where the boundary is the call itself - /// (the browser `pushFrame` / `postMessage` path) use this so the on-wire - /// bytes match the TypeScript `encodeProtocolFramePayload(frame, "bare")`, - /// which emits the raw bare frame with no prefix. - pub fn encode_message(&self, frame: &ProtocolFrame) -> Result, ProtocolCodecError> { - validate_frame(frame)?; - let payload = serde_bare::to_vec(frame) - .map_err(|error| ProtocolCodecError::SerializeFailure(error.to_string()))?; - if payload.len() > self.max_frame_bytes { - return Err(ProtocolCodecError::FrameTooLarge { - size: payload.len(), - max: self.max_frame_bytes, - }); - } - Ok(payload) - } - - /// Decode a bare message produced by [`encode_message`] (no length prefix). - pub fn decode_message(&self, bytes: &[u8]) -> Result { - if bytes.len() > self.max_frame_bytes { - return Err(ProtocolCodecError::FrameTooLarge { - size: bytes.len(), - max: self.max_frame_bytes, - }); - } - let frame = serde_bare::from_slice(bytes) - .map_err(|error| ProtocolCodecError::DeserializeFailure(error.to_string()))?; - validate_frame(&frame)?; - Ok(frame) - } - - fn checked_payload<'a>(&self, bytes: &'a [u8]) -> Result<&'a [u8], ProtocolCodecError> { - if bytes.len() < 4 { - return Err(ProtocolCodecError::TruncatedFrame { - actual: bytes.len(), - }); - } - - let declared = - u32::from_be_bytes(bytes[..4].try_into().expect("length prefix is four bytes")) - as usize; - if declared > self.max_frame_bytes { - return Err(ProtocolCodecError::FrameTooLarge { - size: declared, - max: self.max_frame_bytes, - }); - } - - let actual = bytes.len() - 4; - if declared != actual { - return Err(ProtocolCodecError::LengthPrefixMismatch { declared, actual }); - } - - Ok(&bytes[4..]) - } -} - -impl Default for WireFrameCodec { - fn default() -> Self { - Self::new(DEFAULT_MAX_FRAME_BYTES) - } -} - -pub fn protocol_schema() -> ProtocolSchema { - ProtocolSchema::current() -} - -impl ProtocolSchema { - pub fn current() -> Self { - Self { - name: PROTOCOL_NAME.to_string(), - version: PROTOCOL_VERSION, - } - } -} - -impl Default for ProtocolSchema { - fn default() -> Self { - Self::current() - } -} - -pub fn request_frame_to_compat( - request: RequestFrame, -) -> Result { - match crate::protocol::from_generated_protocol_frame(ProtocolFrame::RequestFrame(request))? { - crate::protocol::ProtocolFrame::Request(request) => Ok(request), - crate::protocol::ProtocolFrame::Response(_) - | crate::protocol::ProtocolFrame::Event(_) - | crate::protocol::ProtocolFrame::SidecarRequest(_) - | crate::protocol::ProtocolFrame::SidecarResponse(_) => { - Err(ProtocolCodecError::DeserializeFailure(String::from( - "wire request frame converted to non-request compatibility frame", - ))) - } - } -} - -pub fn ownership_scope_to_compat(ownership: OwnershipScope) -> crate::protocol::OwnershipScope { - crate::protocol::from_generated_ownership_scope(ownership) -} - -pub fn request_payload_to_compat( - ownership: &crate::protocol::OwnershipScope, - payload: RequestPayload, -) -> Result { - match crate::protocol::from_generated_protocol_frame(ProtocolFrame::RequestFrame( - RequestFrame { - schema: protocol_schema(), - request_id: 1, - ownership: crate::protocol::to_generated_ownership_scope(ownership), - payload, - }, - ))? { - crate::protocol::ProtocolFrame::Request(request) => Ok(request.payload), - crate::protocol::ProtocolFrame::Response(_) - | crate::protocol::ProtocolFrame::Event(_) - | crate::protocol::ProtocolFrame::SidecarRequest(_) - | crate::protocol::ProtocolFrame::SidecarResponse(_) => { - Err(ProtocolCodecError::DeserializeFailure(String::from( - "wire request payload converted to non-request compatibility frame", - ))) - } - } -} - -pub fn response_payload_from_compat( - ownership: &crate::protocol::OwnershipScope, - payload: crate::protocol::ResponsePayload, -) -> Result { - match crate::protocol::to_generated_protocol_frame(&crate::protocol::ProtocolFrame::Response( - crate::protocol::ResponseFrame::new(1, ownership.clone(), payload), - ))? { - ProtocolFrame::ResponseFrame(response) => Ok(response.payload), - ProtocolFrame::RequestFrame(_) - | ProtocolFrame::EventFrame(_) - | ProtocolFrame::SidecarRequestFrame(_) - | ProtocolFrame::SidecarResponseFrame(_) => Err(ProtocolCodecError::SerializeFailure( - String::from("compatibility response payload converted to non-response wire frame"), - )), - } -} - -pub fn event_frame_from_compat( - event: crate::protocol::EventFrame, -) -> Result { - match crate::protocol::to_generated_protocol_frame(&crate::protocol::ProtocolFrame::Event( - event, - ))? { - ProtocolFrame::EventFrame(event) => Ok(event), - ProtocolFrame::RequestFrame(_) - | ProtocolFrame::ResponseFrame(_) - | ProtocolFrame::SidecarRequestFrame(_) - | ProtocolFrame::SidecarResponseFrame(_) => Err(ProtocolCodecError::SerializeFailure( - String::from("compatibility event converted to non-event wire frame"), - )), - } -} - -pub fn event_frame_to_compat( - event: EventFrame, -) -> Result { - match crate::protocol::from_generated_protocol_frame(ProtocolFrame::EventFrame(event))? { - crate::protocol::ProtocolFrame::Event(event) => Ok(event), - crate::protocol::ProtocolFrame::Request(_) - | crate::protocol::ProtocolFrame::Response(_) - | crate::protocol::ProtocolFrame::SidecarRequest(_) - | crate::protocol::ProtocolFrame::SidecarResponse(_) => { - Err(ProtocolCodecError::DeserializeFailure(String::from( - "wire event converted to non-event compatibility frame", - ))) - } - } -} - -pub fn sidecar_request_frame_from_compat( - request: crate::protocol::SidecarRequestFrame, -) -> Result { - match crate::protocol::to_generated_protocol_frame( - &crate::protocol::ProtocolFrame::SidecarRequest(request), - )? { - ProtocolFrame::SidecarRequestFrame(request) => Ok(request), - ProtocolFrame::RequestFrame(_) - | ProtocolFrame::ResponseFrame(_) - | ProtocolFrame::EventFrame(_) - | ProtocolFrame::SidecarResponseFrame(_) => { - Err(ProtocolCodecError::SerializeFailure(String::from( - "compatibility sidecar request converted to non-sidecar-request wire frame", - ))) - } - } -} - -pub fn sidecar_request_payload_to_compat( - ownership: &crate::protocol::OwnershipScope, - payload: SidecarRequestPayload, -) -> Result { - match crate::protocol::from_generated_protocol_frame(ProtocolFrame::SidecarRequestFrame( - SidecarRequestFrame { - schema: protocol_schema(), - request_id: -1, - ownership: crate::protocol::to_generated_ownership_scope(ownership), - payload, - }, - ))? { - crate::protocol::ProtocolFrame::SidecarRequest(request) => Ok(request.payload), - crate::protocol::ProtocolFrame::Request(_) - | crate::protocol::ProtocolFrame::Response(_) - | crate::protocol::ProtocolFrame::Event(_) - | crate::protocol::ProtocolFrame::SidecarResponse(_) => { - Err(ProtocolCodecError::DeserializeFailure(String::from( - "wire sidecar request payload converted to non-sidecar-request compatibility frame", - ))) - } - } -} - -pub fn sidecar_response_frame_to_compat( - response: SidecarResponseFrame, -) -> Result { - match crate::protocol::from_generated_protocol_frame(ProtocolFrame::SidecarResponseFrame( - response, - ))? { - crate::protocol::ProtocolFrame::SidecarResponse(response) => Ok(response), - crate::protocol::ProtocolFrame::Request(_) - | crate::protocol::ProtocolFrame::Response(_) - | crate::protocol::ProtocolFrame::Event(_) - | crate::protocol::ProtocolFrame::SidecarRequest(_) => { - Err(ProtocolCodecError::DeserializeFailure(String::from( - "wire sidecar response converted to non-sidecar-response compatibility frame", - ))) - } - } -} - -pub fn sidecar_response_frame_from_compat( - response: crate::protocol::SidecarResponseFrame, -) -> Result { - match crate::protocol::to_generated_protocol_frame( - &crate::protocol::ProtocolFrame::SidecarResponse(response), - )? { - ProtocolFrame::SidecarResponseFrame(response) => Ok(response), - ProtocolFrame::RequestFrame(_) - | ProtocolFrame::ResponseFrame(_) - | ProtocolFrame::EventFrame(_) - | ProtocolFrame::SidecarRequestFrame(_) => { - Err(ProtocolCodecError::SerializeFailure(String::from( - "compatibility sidecar response converted to non-sidecar-response wire frame", - ))) - } - } -} - -pub fn dispatch_result_from_compat( - result: CompatDispatchResult, -) -> Result { - let response = match crate::protocol::to_generated_protocol_frame( - &crate::protocol::ProtocolFrame::Response(result.response), - )? { - ProtocolFrame::ResponseFrame(response) => response, - ProtocolFrame::RequestFrame(_) - | ProtocolFrame::EventFrame(_) - | ProtocolFrame::SidecarRequestFrame(_) - | ProtocolFrame::SidecarResponseFrame(_) => { - return Err(ProtocolCodecError::SerializeFailure(String::from( - "compatibility dispatch response converted to non-response wire frame", - ))); - } - }; - - let events = result - .events - .into_iter() - .map(|event| { - match crate::protocol::to_generated_protocol_frame( - &crate::protocol::ProtocolFrame::Event(event), - )? { - ProtocolFrame::EventFrame(event) => Ok(event), - ProtocolFrame::RequestFrame(_) - | ProtocolFrame::ResponseFrame(_) - | ProtocolFrame::SidecarRequestFrame(_) - | ProtocolFrame::SidecarResponseFrame(_) => { - Err(ProtocolCodecError::SerializeFailure(String::from( - "compatibility dispatch event converted to non-event wire frame", - ))) - } - } - }) - .collect::, _>>()?; - - Ok(WireDispatchResult { response, events }) -} - -fn validate_frame(frame: &ProtocolFrame) -> Result<(), ProtocolCodecError> { - match frame { - ProtocolFrame::RequestFrame(frame) => { - validate_schema(&frame.schema)?; - validate_request_id(frame.request_id) - } - ProtocolFrame::ResponseFrame(frame) => { - validate_schema(&frame.schema)?; - validate_request_id(frame.request_id) - } - ProtocolFrame::EventFrame(frame) => validate_schema(&frame.schema), - ProtocolFrame::SidecarRequestFrame(frame) => { - validate_schema(&frame.schema)?; - validate_request_id(frame.request_id) - } - ProtocolFrame::SidecarResponseFrame(frame) => { - validate_schema(&frame.schema)?; - validate_request_id(frame.request_id) - } - } -} - -fn validate_schema(schema: &ProtocolSchema) -> Result<(), ProtocolCodecError> { - if schema.name != PROTOCOL_NAME || schema.version != PROTOCOL_VERSION { - return Err(ProtocolCodecError::UnsupportedSchema { - name: schema.name.clone(), - version: schema.version, - }); - } - Ok(()) -} - -fn validate_request_id(request_id: RequestId) -> Result<(), ProtocolCodecError> { - if request_id == 0 { - return Err(ProtocolCodecError::InvalidRequestId); - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::generated_protocol::v1::{ - FsPermissionScope, PatternPermissionScope, PermissionMode, - }; - use std::collections::BTreeMap; - - #[test] - fn legacy_metadata_preserves_js_runtime_limits_with_only_new_fields() { - let metadata = BTreeMap::from([( - String::from("limits.js_runtime.cpu_time_limit_ms"), - String::from("123"), - )]); - - let config = legacy_limits_config(&metadata).expect("limits config"); - let js_runtime = config.js_runtime.expect("js runtime limits"); - - assert_eq!(js_runtime.cpu_time_limit_ms, Some(123)); - } - - #[test] - fn legacy_metadata_preserves_wasm_limits_with_only_new_fields() { - let metadata = BTreeMap::from([( - String::from("limits.wasm.prewarm_timeout_ms"), - String::from("456"), - )]); - - let config = legacy_limits_config(&metadata).expect("limits config"); - let wasm = config.wasm.expect("wasm limits"); - - assert_eq!(wasm.prewarm_timeout_ms, Some(456)); - } - - #[test] - fn legacy_metadata_preserves_wasm_runner_heap_limit_as_only_new_field() { - let metadata = BTreeMap::from([( - String::from("limits.wasm.runner_heap_limit_mb"), - String::from("789"), - )]); - - let config = legacy_limits_config(&metadata).expect("limits config"); - let wasm = config.wasm.expect("wasm limits"); - - assert_eq!(wasm.runner_heap_limit_mb, Some(789)); - } - - #[test] - fn permissions_policy_default_matches_no_policy_deny_all() { - let policy = PermissionsPolicy::default(); - - assert!(matches!( - policy.fs, - Some(FsPermissionScope::PermissionMode(PermissionMode::Deny)) - )); - for scope in [ - policy.network, - policy.child_process, - policy.process, - policy.env, - policy.binding, - ] { - assert!(matches!( - scope, - Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)) - )); - } - } - - #[test] - fn permissions_policy_allow_all_remains_explicit() { - let policy = PermissionsPolicy::allow_all(); - - assert!(matches!( - policy.fs, - Some(FsPermissionScope::PermissionMode(PermissionMode::Allow)) - )); - for scope in [ - policy.network, - policy.child_process, - policy.process, - policy.env, - policy.binding, - ] { - assert!(matches!( - scope, - Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow - )) - )); - } - } -} diff --git a/crates/sidecar/AGENTS.md b/crates/sidecar/AGENTS.md deleted file mode 120000 index 681311eb9..000000000 --- a/crates/sidecar/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/crates/sidecar/CLAUDE.md b/crates/sidecar/CLAUDE.md deleted file mode 100644 index 8601adf8c..000000000 --- a/crates/sidecar/CLAUDE.md +++ /dev/null @@ -1,35 +0,0 @@ -See `../CLAUDE.md` for crate-wide runtime and testing rules. - -## env vs BARE wire — channel classification - -Spawned language-host engines are configured two ways: the **BARE wire/structured request** (`protocol.rs` payloads, `CreateVmConfig`, and the per-engine `Start{Javascript,Wasm,Python}ExecutionRequest` structs in `crates/execution`) and the **`AGENTOS_*` env channel** (assembled in `prepare_guest_runtime_env` / `apply_wasm_limit_env` in `src/execution.rs`, read back by the engines/bridge). Every setting belongs to exactly one of three buckets: - -1. **Process-wide / host / build / test → env.** Shared across all VMs, not per-VM configurable (e.g. `SECURE_EXEC_NODE`, `*_V8_BRIDGE_BUILD_SCRIPT`, pyodide index/cache URLs, all test/debug knobs). Leave on env. -2. **Per-VM bootstrap-before-wire → env (explicit carve-out).** Must exist at `exec` time *before* the wire/sync-RPC bridge is up: `AGENTOS_SANDBOX_ROOT`, the sync-RPC bridge fds (`AGENTOS_NODE_SYNC_RPC_ENABLE`/`_REQUEST_FD`/`_RESPONSE_FD`/`_DATA_BYTES`/`_WAIT_TIMEOUT_MS`), entrypoint/argv/payload (`AGENTOS_ENTRYPOINT`/`_GUEST_ENTRYPOINT`/`_GUEST_ARGV`/`_BOOTSTRAP_MODULE`, `_PYTHON_CODE`/`_PYTHON_FILE`, `_WASM_MODULE_PATH`). Keep on env; keep scrubbed from guest `process.env` and from `child_process` spawns. -3. **Per-VM runtime config → BARE wire.** Anything per-VM the established wire/bridge could carry: resource limits, isolation policy, virtualized identity. MUST ride the wire (a typed field on `CreateVmConfig`/`VmLimits` or the per-execution request), read by the engine from that field. New per-VM settings default here. - -**Dead-cap anti-pattern.** A value set on the wire that is then silently re-emitted as an `AGENTOS_*` env knob is the dead-cap failure mode — the env knob can be wrong, stale, or never read while the wire value is ignored (this is exactly how `AGENTOS_WASM_MAX_STACK_BYTES` was set into env but never read). If it's on the wire, the engine reads it from the wire path; do not duplicate it onto env "just in case", and per the versionless-lockstep rule do not keep an env knob as a fallback. - -Migration status: **resource limits** (typed `*ExecutionLimits` on the execution request) and **virtualized identity** (`process.{pid,ppid,uid,gid}` interpolated into the runtime shim; `os.{cpus,totalmem,freemem,homedir,userInfo,…}` via the `__agentOSVirtualOs` global the shim sets) are migrated to the wire. **Isolation policy** (`AGENTOS_GUEST_PATH_MAPPINGS`, `EXTRA_FS_*_PATHS`, `ALLOWED_NODE_BUILTINS`, `LOOPBACK_EXEMPT_PORTS`, `WASM_PERMISSION_TIER`) is bucket 3 but still on env — future work. Note: the guest module loader and `os` module (`guestOs`) read their inputs at module-evaluation; the runtime shim sets `__agentOSVirtualOs` early enough that this works (verified by `os_resource_limits_are_vm_scoped` in `tests/builtin_conformance.rs`, which asserts the guest's `os.*` identity reflects the configured VM). - -## Local Patterns - -- `RequestPayload::Ext`, `ResponsePayload::ExtResult`, `EventPayload::Ext`, and sidecar callback `Ext` payloads are opaque to core sidecar code; dispatch only by namespace and leave inner payload decoding to the registered extension. -- `ExtensionContext` primitives should delegate to existing `NativeSidecar` ownership, process, event, and callback paths instead of giving extensions direct access to internal maps such as VM tables or ACP session state. -- Extension callbacks and events must stay transport-agnostic: do not expose stdio, socket, or browser `postMessage` details through the `Extension` trait or `ExtensionContext`. -- Stdio blocking-request interruption must stay extension-owned. Core stdio may call generic `Extension` hooks, but production secure-exec-sidecar code must not decode ACP payloads or depend on `agentos-protocol`. -- Sidecar-to-host callback protocol must stay agent-agnostic: use `HostCallback{callback_key}` for generic host callbacks, and keep toolkit-specific naming and schemas out of the core callback frame. -- Legacy ACP helpers under `tests/acp_legacy/` are fixtures only; production ACP behavior belongs in `crates/agentos-sidecar`, not `crates/sidecar/src`. -- Tool CLI `--json` and `--json-file` payloads in `src/tools.rs` must be validated against the registered host callback `input_schema` before building `HostCallbackRequest`; relying on the host callback to fail closed leaves non-TypeScript hosts and any pre-dispatch checks exposed to raw, unvalidated payload shapes. -- `net.poll` waits in `src/execution.rs` must stay explicitly bounded. The sync-RPC handler runs on the sidecar's main sync-RPC thread, so guest `wait_ms` values must be clamped via `clamp_javascript_net_poll_wait(...)` to the 50 ms ceiling; longer waits should return the currently observed socket state after the ceiling expires instead of blocking dispose/shutdown or unrelated VM work. -- `kill_process` signal parsing in `src/execution.rs` must stay aligned with the guest `child_process.kill(...)` bridge contract: accept the full 1..31 signal table plus common aliases (`SIGIOT` -> `SIGABRT`, `SIGPOLL` -> `SIGIO`), and terminate shared-V8 child executions directly for non-streamed signals so child polls still observe prompt exits. -- `child_process.poll` in `src/execution.rs` must reserve `Value::Null` for the real "no events pending" case. If a tracked child disappears after descendant-event drain, return a typed `ECHILD` execution error instead so guest poll loops stop instead of spinning on a ghost child. -- Child stdin plumbing in `src/execution.rs` must mirror the root-process path for nested `child_process` children too: always call `child.execution.write_stdin()` / `close_stdin()` and the kernel pipe helpers together. Kernel-only writes or closes leave shared-V8 WASM children stuck behind the local `kernel_stdin` bridge, so pipelines like `echo hello | wc -c` never observe EOF. -- Child JavaScript executions use `service_javascript_sync_rpc(...)` in `src/execution.rs`, not the top-level `src/service.rs`, for `process.*` bridge calls. When changing guest self-signal behavior (`process.kill`, `process.abort()`, signal-shape exit reporting), mirror the top-level bookkeeping there too or spawned Node children will regress to `unsupported JavaScript sync RPC method process.kill` and report plain exit codes. -- Nested JavaScript child signal registration currently arrives through the sync-RPC method `process.signal_state`, not just `ActiveExecutionEvent::SignalState`. When fixing descendant `SIGCHLD` or job-control behavior in `src/execution.rs`, keep the nested `process.signal_state` bookkeeping aligned with the top-level `src/service.rs` handler or grandchildren will silently lose their registered signal handlers. -- The sidecar protocol `Authenticate` handshake must carry `secure_exec_bridge::bridge_contract().version`; `src/service.rs` should reject mismatches with `bridge_version_mismatch` before opening a connection so bridge-contract drift fails fast instead of crashing later on the first divergent RPC. -- `plugins/host_dir.rs` metadata writes must keep the old symlink-leaf safety contract for plain ops (`chmod`/`chown`/`utimes` still reject symlink leaves), while the richer timestamp path should only mutate symlink metadata when the caller explicitly requests nofollow semantics (`lutimes` / `utimes_spec(..., false)`). -- Mounted filesystem shutdown now happens explicitly during `src/vm.rs` disposal/reconfigure, not just in `MountTable::drop`. Bridge-backed mounts can therefore emit `SidecarRequestPayload::JsBridgeCall` during teardown, and host-visible flush failures should surface as the structured event `filesystem.mount.shutdown_failed` with the mount metadata plus the original error code/message. -- Guest runtime env setup in `src/execution.rs` must add writable `host_dir` / `module_access` mount roots to `AGENTOS_EXTRA_FS_WRITE_PATHS`, not just the VM shadow cwd. Without those extra write roots, guest `fs.*` bridge calls misclassify writable mounts as read-only (`EROFS`) and cross-mount rename tests never reach the intended `EXDEV` path. -- Python mapped host-path access in `src/filesystem.rs` must stay on the anchored-fd path: open the mapped root once, resolve descendants with `openat2(RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS)`, and perform the actual syscall through `/proc/self/fd/` or an anchored parent dir. Do not reintroduce resolve-then-use `PathBuf` opens, and when filtering `read_dir` results from a proc-fd directory, rebuild child host paths from the resolved directory host path plus `file_name()` instead of reusing `DirEntry::path()`, which points back into procfs. -- In `tests/builtin_conformance.rs`, isolated extra tests that open a host listener should finish sidecar/session/VM setup before starting any accept deadline. Those tests run in subprocesses that can queue behind the shared sidecar-runtime lock, so a server timeout that starts before VM creation will flake under the normal parallel `cargo test` harness. diff --git a/crates/sidecar/Cargo.toml b/crates/sidecar/Cargo.toml index 89be156ff..6cbe7dddc 100644 --- a/crates/sidecar/Cargo.toml +++ b/crates/sidecar/Cargo.toml @@ -4,72 +4,10 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Native Secure Exec sidecar runtime" +description = "secure-exec-sidecar compatibility shim for agentos-native-sidecar" [lib] name = "secure_exec_sidecar" -[[bin]] -name = "secure-exec-sidecar" -path = "src/main.rs" - [dependencies] -secure-exec-bridge = { workspace = true } -secure-exec-kernel = { workspace = true } -secure-exec-sidecar-protocol = { workspace = true } -secure-exec-sidecar-core = { workspace = true } -secure-exec-execution = { workspace = true } -secure-exec-vm-config = { workspace = true } -secure-exec-vfs = { workspace = true } -async-trait = "0.1" -aes = "0.8" -aes-gcm = "0.10" -aws-config = "1" -aws-credential-types = "1" -aws-sdk-s3 = "1" -base64 = "0.22" -blake3 = "1" -bytes = "1" -ctr = "0.9" -filetime = "0.2" -h2 = "0.4" -http = "1" -hmac = "0.12" -hickory-resolver = "0.26.0-beta.3" -jsonwebtoken = "8.3.0" -log = "0.4" -md-5 = "0.10" -nix = { version = "0.29", features = ["fs", "poll", "process", "signal", "user"] } -# `vendored` builds OpenSSL from source → self-contained binary with no -# system-openssl discovery on any runner (ubuntu/macOS). openssl backs the -# guest crypto runtime (RSA/EC/DH/AES), so it cannot be a TLS-only stack. -openssl = { version = "0.10", features = ["vendored"] } -pbkdf2 = "0.12" -rustls = { version = "0.23.37", default-features = false, features = ["aws_lc_rs", "std", "tls12"] } -rustls-native-certs = "0.8" -rustls-pemfile = "2.2" -tokio-rustls = { version = "0.26", default-features = false, features = ["aws_lc_rs", "tls12"] } -rusqlite = { version = "0.32", features = ["bundled"] } -scrypt = "0.11" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -sha1 = "0.10" -sha2 = "0.10" -socket2 = "0.6" -tokio = { version = "1", features = ["io-std", "io-util", "macros", "net", "rt", "rt-multi-thread", "sync", "time"] } -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["fmt"] } -ureq = { version = "2.10", features = ["json"] } -url = "2" -vfs = { workspace = true } - -[target.'cfg(target_os = "macos")'.dependencies] -# macOS has no openat2/RESOLVE_BENEATH; cap-std provides the audited -# resolve-beneath path resolution used in place of openat2 on this platform. -cap-std = "3" - -[dev-dependencies] -serde_bare = "0.5" -tar = "0.4" -wat = "1.0" -v8 = "130" +agentos_native_sidecar = { package = "agentos-native-sidecar", path = "../../../agentos/crates/native-sidecar", version = "0.0.1" } diff --git a/crates/sidecar/assets/base-filesystem.json b/crates/sidecar/assets/base-filesystem.json deleted file mode 100644 index 64e03bfa5..000000000 --- a/crates/sidecar/assets/base-filesystem.json +++ /dev/null @@ -1,536 +0,0 @@ -{ - "source": { - "snapshotPath": "alpine-defaults.json", - "image": "alpine:3.22", - "snapshotCreatedAt": "2026-06-22T19:45:20.529Z", - "builtAt": "2026-06-23T03:47:12.644Z", - "transforms": [ - "Normalize HOSTNAME to secure-exec", - "Preserve the captured user-level environment and filesystem layout as the secure-exec base layer", - "Add the non-Alpine /workspace directory (default agent working directory) owned by the base user" - ] - }, - "environment": { - "env": { - "CHARSET": "UTF-8", - "HOME": "/home/agentos", - "HOSTNAME": "secure-exec", - "LANG": "C.UTF-8", - "LC_COLLATE": "C", - "LOGNAME": "agentos", - "PAGER": "less", - "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "SHELL": "/bin/sh", - "USER": "agentos" - }, - "prompt": "\\h:\\w\\$ " - }, - "filesystem": { - "entries": [ - { - "path": "/", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/bin", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/alpine-release", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "3.22.4\n" - }, - { - "path": "/etc/apk", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/busybox-paths.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/crontabs", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/group", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "root:x:0:root\nbin:x:1:root,bin,daemon\ndaemon:x:2:root,bin,daemon\nsys:x:3:root,bin\nadm:x:4:root,daemon\ntty:x:5:\ndisk:x:6:root\nlp:x:7:lp\nkmem:x:9:\nwheel:x:10:root\nfloppy:x:11:root\nmail:x:12:mail\nnews:x:13:news\nuucp:x:14:uucp\ncron:x:16:cron\naudio:x:18:\ncdrom:x:19:\ndialout:x:20:root\nftp:x:21:\nsshd:x:22:\ninput:x:23:\ntape:x:26:root\nvideo:x:27:root\nnetdev:x:28:\nkvm:x:34:kvm\ngames:x:35:\nshadow:x:42:\nwww-data:x:82:\nusers:x:100:games\nntp:x:123:\nabuild:x:300:\nutmp:x:406:\nping:x:999:\nnogroup:x:65533:\nnobody:x:65534:\nagentos:x:1000:\n" - }, - { - "path": "/etc/hostname", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "secure-exec\n" - }, - { - "path": "/etc/logrotate.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/modprobe.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/modules-load.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/network", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/nsswitch.conf", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "# musl itself does not support NSS, however some third-party DNS\n# implementations use the nsswitch.conf file to determine what\n# policy to follow.\n# Editing this file is not recommended.\nhosts: files dns\n" - }, - { - "path": "/etc/opt", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/os-release", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "../usr/lib/os-release" - }, - { - "path": "/etc/passwd", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "root:x:0:0:root:/root:/bin/sh\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\nlp:x:4:7:lp:/var/spool/lpd:/sbin/nologin\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/mail:/sbin/nologin\nnews:x:9:13:news:/usr/lib/news:/sbin/nologin\nuucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin\ncron:x:16:16:cron:/var/spool/cron:/sbin/nologin\nftp:x:21:21::/var/lib/ftp:/sbin/nologin\nsshd:x:22:22:sshd:/dev/null:/sbin/nologin\ngames:x:35:35:games:/usr/games:/sbin/nologin\nntp:x:123:123:NTP:/var/empty:/sbin/nologin\nguest:x:405:100:guest:/dev/null:/sbin/nologin\nnobody:x:65534:65534:nobody:/:/sbin/nologin\nagentos:x:1000:1000::/home/agentos:/bin/sh\n" - }, - { - "path": "/etc/periodic", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/profile", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "export PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\nexport PAGER=less\numask 022\n\n# use nicer PS1 for bash and busybox ash\nif [ -n \"$BASH_VERSION\" -o \"$BB_ASH_VERSION\" ]; then\n\tPS1='\\h:\\w\\$ '\n# use nicer PS1 for zsh\nelif [ -n \"$ZSH_VERSION\" ]; then\n\tPS1='%m:%~%# '\n# set up fallback default PS1\nelse\n\t: \"${HOSTNAME:=$(hostname)}\"\n\tPS1='${HOSTNAME%%.*}:$PWD'\n\t[ \"$(id -u)\" -eq 0 ] && PS1=\"${PS1}# \" || PS1=\"${PS1}\\$ \"\nfi\n\nfor script in /etc/profile.d/*.sh ; do\n\tif [ -r \"$script\" ] ; then\n\t\t. \"$script\"\n\tfi\ndone\nunset script\n" - }, - { - "path": "/etc/profile.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/secfixes.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/shadow", - "type": "file", - "mode": "640", - "uid": 0, - "gid": 42, - "content": "root:*::0:::::\nbin:!::0:::::\ndaemon:!::0:::::\nlp:!::0:::::\nsync:!::0:::::\nshutdown:!::0:::::\nhalt:!::0:::::\nmail:!::0:::::\nnews:!::0:::::\nuucp:!::0:::::\ncron:!::0:::::\nftp:!::0:::::\nsshd:!::0:::::\ngames:!::0:::::\nntp:!::0:::::\nguest:!::0:::::\nnobody:!::0:::::\nagentos:!:20626:0:99999:7:::\n" - }, - { - "path": "/etc/shells", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "# valid login shells\n/bin/sh\n/bin/ash\n" - }, - { - "path": "/etc/ssl", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/ssl1.1", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/sysctl.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/udhcpc", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/home", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/home/agentos", - "type": "directory", - "mode": "2755", - "uid": 1000, - "gid": 1000 - }, - { - "path": "/lib", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/lib/apk", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/lib/firmware", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/lib/modules-load.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/lib/sysctl.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/media", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/media/cdrom", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/media/floppy", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/media/usb", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/mnt", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/opt", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/root", - "type": "directory", - "mode": "700", - "uid": 0, - "gid": 0 - }, - { - "path": "/run", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/run/lock", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/sbin", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/srv", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/sys", - "type": "directory", - "mode": "555", - "uid": 0, - "gid": 0 - }, - { - "path": "/tmp", - "type": "directory", - "mode": "1777", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/bin", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/bin/env", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "/bin/busybox" - }, - { - "path": "/usr/lib", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/lib/os-release", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "NAME=\"Alpine Linux\"\nID=alpine\nVERSION_ID=3.22.4\nPRETTY_NAME=\"Alpine Linux v3.22\"\nHOME_URL=\"https://alpinelinux.org/\"\nBUG_REPORT_URL=\"https://gitlab.alpinelinux.org/alpine/aports/-/issues\"\n" - }, - { - "path": "/usr/local", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/sbin", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/share", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/cache", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/empty", - "type": "directory", - "mode": "555", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/lib", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/local", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/lock", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "../run/lock" - }, - { - "path": "/var/log", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/mail", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/opt", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/run", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "../run" - }, - { - "path": "/var/spool", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/spool/cron", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/spool/cron/crontabs", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "../../../etc/crontabs" - }, - { - "path": "/var/tmp", - "type": "directory", - "mode": "1777", - "uid": 0, - "gid": 0 - }, - { - "path": "/workspace", - "type": "directory", - "mode": "755", - "uid": 1000, - "gid": 1000 - } - ] - } -} diff --git a/crates/sidecar/build.rs b/crates/sidecar/build.rs deleted file mode 100644 index 955b501ed..000000000 --- a/crates/sidecar/build.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::{env, fs, path::PathBuf}; - -// Stage the base filesystem fixture into OUT_DIR. In-tree builds use the -// canonical secure-exec package fixture from the current workspace; the -// published crate falls back to the vendored `assets/base-filesystem.json` copy. -fn main() { - let manifest_dir = - PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set")); - let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR must be set")); - - println!("cargo:rerun-if-changed=build.rs"); - - let workspace_fixtures = [ - manifest_dir.join("../../packages/secure-exec-core/fixtures/base-filesystem.json"), - manifest_dir.join("../../packages/core/fixtures/base-filesystem.json"), - ]; - let vendored = manifest_dir.join("assets/base-filesystem.json"); - let src = workspace_fixtures - .into_iter() - .find(|fixture| fixture.exists()) - .unwrap_or(vendored); - - println!("cargo:rerun-if-changed={}", src.display()); - - let dest = out_dir.join("base-filesystem.json"); - fs::copy(&src, &dest).unwrap_or_else(|error| { - panic!( - "failed to stage base-filesystem.json from {} to {}: {}", - src.display(), - dest.display(), - error - ) - }); -} diff --git a/crates/sidecar/src/bootstrap.rs b/crates/sidecar/src/bootstrap.rs deleted file mode 100644 index ab31ddb9c..000000000 --- a/crates/sidecar/src/bootstrap.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! Root filesystem bootstrap and snapshot helpers extracted from vm.rs. - -use crate::protocol::RootFilesystemEntry; -use crate::state::SidecarKernel; -use crate::SidecarError; - -use secure_exec_kernel::root_fs::{ - FilesystemEntry as KernelFilesystemEntry, RootFilesystemSnapshot, -}; -use secure_exec_kernel::vfs::VirtualFileSystem; -use std::collections::BTreeMap; - -pub(crate) fn root_snapshot_entry(entry: &KernelFilesystemEntry) -> RootFilesystemEntry { - secure_exec_sidecar_core::root_snapshot_entry(entry) -} - -pub(crate) fn root_snapshot_entries(snapshot: &RootFilesystemSnapshot) -> Vec { - snapshot.entries.iter().map(root_snapshot_entry).collect() -} - -pub(crate) fn root_snapshot_from_entries( - entries: &[RootFilesystemEntry], -) -> Result { - secure_exec_sidecar_core::root_snapshot_from_entries(entries) - .map_err(|error| SidecarError::InvalidState(error.to_string())) -} - -pub(crate) fn apply_root_filesystem_entry( - filesystem: &mut F, - entry: &RootFilesystemEntry, -) -> Result<(), SidecarError> -where - F: VirtualFileSystem, -{ - secure_exec_sidecar_core::apply_root_filesystem_entry(filesystem, entry) - .map_err(|error| SidecarError::InvalidState(error.to_string())) -} - -pub(crate) fn discover_command_guest_paths(kernel: &mut SidecarKernel) -> BTreeMap { - let mut command_guest_paths = BTreeMap::new(); - let Ok(command_roots) = kernel.read_dir("/__secure_exec/commands") else { - return command_guest_paths; - }; - - let mut ordered_roots = command_roots - .into_iter() - .filter(|entry| !entry.is_empty() && entry.chars().all(|ch| ch.is_ascii_digit())) - .collect::>(); - ordered_roots.sort(); - - for root in ordered_roots { - let guest_root = format!("/__secure_exec/commands/{root}"); - let Ok(entries) = kernel.read_dir(&guest_root) else { - continue; - }; - - for entry in entries { - if entry.starts_with('.') || command_guest_paths.contains_key(&entry) { - continue; - } - command_guest_paths.insert(entry.clone(), format!("{guest_root}/{entry}")); - } - } - - command_guest_paths -} diff --git a/crates/sidecar/src/bridge.rs b/crates/sidecar/src/bridge.rs deleted file mode 100644 index ad5d30ea8..000000000 --- a/crates/sidecar/src/bridge.rs +++ /dev/null @@ -1,1173 +0,0 @@ -//! Host bridge filesystem and permission plumbing extracted from service.rs. - -#![cfg_attr(test, allow(dead_code))] - -use crate::plugins::register_native_mount_plugins; -use crate::service::{audit_fields, emit_security_audit_event, plugin_error}; -use crate::state::{BridgeError, SharedBridge, SharedSidecarRequestClient}; -use crate::{NativeSidecarBridge, SidecarError}; - -use secure_exec_bridge::FilesystemAccess; -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, FileSystemPluginRegistry, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::MountedVirtualFileSystem; -use secure_exec_kernel::permissions::{ - CommandAccessRequest, EnvAccessRequest, FsAccessRequest, FsOperation, NetworkAccessRequest, - PermissionDecision, Permissions, -}; -use secure_exec_kernel::vfs::MemoryFileSystem; -use secure_exec_sidecar_core::permissions::filesystem_permission_capability; -use std::fmt; -use std::sync::Arc; - -#[cfg(test)] -use crate::service::{dirname, normalize_path}; -#[cfg(test)] -use crate::state::HOST_REALPATH_MAX_SYMLINK_DEPTH; -#[cfg(test)] -use secure_exec_bridge::{ - ChmodRequest, CreateDirRequest, FileKind, FileMetadata, PathRequest, ReadDirRequest, - ReadFileRequest, RenameRequest, SymlinkRequest, TruncateRequest, WriteFileRequest, -}; -#[cfg(test)] -use secure_exec_kernel::vfs::{ - VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, -}; -#[cfg(test)] -use std::collections::{BTreeMap, BTreeSet}; -#[cfg(test)] -use std::path::Path; -#[cfg(test)] -use std::sync::Mutex; -#[cfg(test)] -use std::time::{SystemTime, UNIX_EPOCH}; - -#[cfg(test)] -#[derive(Clone)] -pub(crate) struct HostFilesystem { - bridge: SharedBridge, - vm_id: String, - links: Arc>, -} - -#[cfg(test)] -#[derive(Debug, Clone, Default)] -struct HostFilesystemMetadataState { - uid: Option, - gid: Option, - atime_ms: Option, - mtime_ms: Option, - ctime_ms: Option, - birthtime_ms: Option, -} - -#[cfg(test)] -impl HostFilesystemMetadataState { - fn apply_to_stat(&self, stat: &mut VirtualStat) { - if let Some(uid) = self.uid { - stat.uid = uid; - } - if let Some(gid) = self.gid { - stat.gid = gid; - } - if let Some(atime_ms) = self.atime_ms { - stat.atime_ms = atime_ms; - } - if let Some(mtime_ms) = self.mtime_ms { - stat.mtime_ms = mtime_ms; - } - if let Some(ctime_ms) = self.ctime_ms { - stat.ctime_ms = ctime_ms; - } - if let Some(birthtime_ms) = self.birthtime_ms { - stat.birthtime_ms = birthtime_ms; - } - } -} - -#[cfg(test)] -#[derive(Debug, Clone)] -struct HostFilesystemLinkedInode { - canonical_path: String, - paths: BTreeSet, - metadata: HostFilesystemMetadataState, -} - -#[cfg(test)] -#[derive(Debug, Default)] -struct HostFilesystemLinkState { - next_ino: u64, - path_to_ino: BTreeMap, - inodes: BTreeMap, -} - -#[cfg(test)] -#[derive(Debug, Clone)] -struct HostFilesystemTrackedIdentity { - canonical_path: String, - ino: u64, - nlink: u64, - metadata: HostFilesystemMetadataState, -} - -#[cfg(test)] -impl HostFilesystem { - pub(crate) fn new(bridge: SharedBridge, vm_id: impl Into) -> Self { - Self { - bridge, - vm_id: vm_id.into(), - links: Arc::new(Mutex::new(HostFilesystemLinkState { - next_ino: 1, - ..HostFilesystemLinkState::default() - })), - } - } - - fn vfs_error(error: SidecarError) -> VfsError { - VfsError::io(error.to_string()) - } - - fn bridge_path_not_found(op: &'static str, path: &str) -> VfsError { - VfsError::new( - "ENOENT", - format!("no such file or directory, {op} '{path}'"), - ) - } - - fn link_state_error() -> VfsError { - VfsError::io("native sidecar host filesystem link state lock poisoned") - } - - fn current_time_ms() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as u64 - } - - fn file_metadata_to_stat( - metadata: FileMetadata, - identity: Option<&HostFilesystemTrackedIdentity>, - ) -> VirtualStat { - let mut stat = VirtualStat { - mode: metadata.mode, - size: metadata.size, - blocks: if metadata.size == 0 { - 0 - } else { - metadata.size.div_ceil(512) - }, - dev: 1, - rdev: 0, - is_directory: metadata.kind == FileKind::Directory, - is_symbolic_link: metadata.kind == FileKind::SymbolicLink, - atime_ms: 0, - atime_nsec: 0, - mtime_ms: 0, - mtime_nsec: 0, - ctime_ms: 0, - ctime_nsec: 0, - birthtime_ms: 0, - ino: identity.map_or(0, |tracked| tracked.ino), - nlink: identity.map_or(1, |tracked| tracked.nlink), - uid: 0, - gid: 0, - }; - if let Some(identity) = identity { - identity.metadata.apply_to_stat(&mut stat); - } - stat - } - - fn tracked_identity(&self, path: &str) -> VfsResult> { - let normalized = normalize_path(path); - let links = self.links.lock().map_err(|_| Self::link_state_error())?; - Ok(links.path_to_ino.get(&normalized).and_then(|ino| { - links - .inodes - .get(ino) - .map(|inode| HostFilesystemTrackedIdentity { - canonical_path: inode.canonical_path.clone(), - ino: *ino, - nlink: inode.paths.len() as u64, - metadata: inode.metadata.clone(), - }) - })) - } - - fn tracked_identity_for_stat( - &self, - path: &str, - ) -> VfsResult> - where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, - { - let normalized = normalize_path(path); - if let Some(identity) = self.tracked_identity(&normalized)? { - return Ok(Some(identity)); - } - - let resolved = self.realpath(&normalized)?; - if resolved == normalized { - return Ok(None); - } - - self.tracked_identity(&resolved) - } - - fn tracked_successor(&self, path: &str) -> VfsResult> { - let normalized = normalize_path(path); - let links = self.links.lock().map_err(|_| Self::link_state_error())?; - Ok(links - .path_to_ino - .get(&normalized) - .and_then(|ino| links.inodes.get(ino)) - .and_then(|inode| { - inode - .paths - .iter() - .find(|candidate| **candidate != normalized) - .cloned() - })) - } - - fn ensure_tracked_path(&self, path: &str) -> VfsResult { - let normalized = normalize_path(path); - let mut links = self.links.lock().map_err(|_| Self::link_state_error())?; - if let Some(ino) = links.path_to_ino.get(&normalized).copied() { - return Ok(ino); - } - - let ino = links.next_ino; - links.next_ino += 1; - links.path_to_ino.insert(normalized.clone(), ino); - links.inodes.insert( - ino, - HostFilesystemLinkedInode { - canonical_path: normalized.clone(), - paths: BTreeSet::from([normalized]), - metadata: HostFilesystemMetadataState::default(), - }, - ); - Ok(ino) - } - - fn track_link(&self, old_path: &str, new_path: &str) -> VfsResult<()> { - let normalized_old = normalize_path(old_path); - let normalized_new = normalize_path(new_path); - let ino = self.ensure_tracked_path(&normalized_old)?; - let mut links = self.links.lock().map_err(|_| Self::link_state_error())?; - links.path_to_ino.insert(normalized_new.clone(), ino); - links - .inodes - .get_mut(&ino) - .expect("tracked inode should exist") - .paths - .insert(normalized_new); - Ok(()) - } - - fn metadata_target_path(&self, path: &str) -> VfsResult - where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, - { - if let Some(identity) = self.tracked_identity(path)? { - return Ok(identity.canonical_path); - } - - let normalized = normalize_path(path); - self.bridge - .with_mut(|bridge| { - bridge.stat(PathRequest { - vm_id: self.vm_id.clone(), - path: normalized.clone(), - }) - }) - .map_err(Self::vfs_error)?; - self.realpath(&normalized) - } - - fn update_metadata( - &self, - path: &str, - update: impl FnOnce(&mut HostFilesystemMetadataState), - ) -> VfsResult<()> - where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, - { - let target = self.metadata_target_path(path)?; - let ino = self.ensure_tracked_path(&target)?; - let mut links = self.links.lock().map_err(|_| Self::link_state_error())?; - let inode = links - .inodes - .get_mut(&ino) - .expect("tracked inode should exist"); - update(&mut inode.metadata); - Ok(()) - } - - fn apply_remove(&self, path: &str) -> VfsResult<()> { - let normalized = normalize_path(path); - let mut links = self.links.lock().map_err(|_| Self::link_state_error())?; - let Some(ino) = links.path_to_ino.remove(&normalized) else { - return Ok(()); - }; - let remove_inode = { - let inode = links - .inodes - .get_mut(&ino) - .expect("tracked inode should exist"); - inode.paths.remove(&normalized); - if inode.paths.is_empty() { - true - } else { - if inode.canonical_path == normalized { - inode.canonical_path = inode - .paths - .iter() - .next() - .expect("tracked inode should retain at least one path") - .clone(); - } - false - } - }; - if remove_inode { - links.inodes.remove(&ino); - } - Ok(()) - } - - fn apply_rename(&self, old_path: &str, new_path: &str) -> VfsResult<()> { - let normalized_old = normalize_path(old_path); - let normalized_new = normalize_path(new_path); - let mut links = self.links.lock().map_err(|_| Self::link_state_error())?; - let Some(ino) = links.path_to_ino.remove(&normalized_old) else { - return Ok(()); - }; - links.path_to_ino.insert(normalized_new.clone(), ino); - let inode = links - .inodes - .get_mut(&ino) - .expect("tracked inode should exist"); - inode.paths.remove(&normalized_old); - inode.paths.insert(normalized_new.clone()); - if inode.canonical_path == normalized_old { - inode.canonical_path = normalized_new; - } - Ok(()) - } - - fn apply_rename_prefix(&self, old_prefix: &str, new_prefix: &str) -> VfsResult<()> { - let normalized_old = normalize_path(old_prefix); - let normalized_new = normalize_path(new_prefix); - let prefix = if normalized_old == "/" { - String::from("/") - } else { - format!("{}/", normalized_old.trim_end_matches('/')) - }; - - let mut links = self.links.lock().map_err(|_| Self::link_state_error())?; - let affected = links - .path_to_ino - .keys() - .filter(|path| *path == &normalized_old || path.starts_with(&prefix)) - .cloned() - .collect::>(); - - for old_path in affected { - let suffix = old_path - .strip_prefix(&normalized_old) - .expect("tracked path should match renamed prefix"); - let new_path = if normalized_new == "/" { - normalize_path(&format!("/{}", suffix.trim_start_matches('/'))) - } else if suffix.is_empty() { - normalized_new.clone() - } else { - normalize_path(&format!( - "{}/{}", - normalized_new.trim_end_matches('/'), - suffix.trim_start_matches('/') - )) - }; - let ino = links - .path_to_ino - .remove(&old_path) - .expect("tracked path should exist"); - links.path_to_ino.insert(new_path.clone(), ino); - let inode = links - .inodes - .get_mut(&ino) - .expect("tracked inode should exist"); - inode.paths.remove(&old_path); - inode.paths.insert(new_path.clone()); - if inode.canonical_path == old_path { - inode.canonical_path = new_path; - } - } - Ok(()) - } -} - -#[cfg(test)] -impl VirtualFileSystem for HostFilesystem -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - fn read_file(&mut self, path: &str) -> VfsResult> { - let normalized = self - .tracked_identity(path)? - .map(|identity| identity.canonical_path) - .unwrap_or_else(|| normalize_path(path)); - self.bridge - .with_mut(|bridge| { - bridge.read_file(ReadFileRequest { - vm_id: self.vm_id.clone(), - path: normalized, - }) - }) - .map_err(Self::vfs_error) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - let normalized = normalize_path(path); - let mut entries = self - .bridge - .with_mut(|bridge| { - bridge.read_dir(ReadDirRequest { - vm_id: self.vm_id.clone(), - path: normalized.clone(), - }) - }) - .map_err(Self::vfs_error)?; - let links = self.links.lock().map_err(|_| Self::link_state_error())?; - for linked_path in links.path_to_ino.keys() { - if dirname(linked_path) != normalized { - continue; - } - let name = Path::new(linked_path) - .file_name() - .map(|value| value.to_string_lossy().into_owned()) - .unwrap_or_else(|| linked_path.trim_start_matches('/').to_owned()); - if entries.iter().all(|entry| entry.name != name) { - entries.push(secure_exec_bridge::DirectoryEntry { - name, - kind: FileKind::File, - }); - } - } - Ok(entries.into_iter().map(|entry| entry.name).collect()) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - let normalized = normalize_path(path); - let mut entries = self - .bridge - .with_mut(|bridge| { - bridge.read_dir(ReadDirRequest { - vm_id: self.vm_id.clone(), - path: normalized.clone(), - }) - }) - .map_err(Self::vfs_error)?; - let links = self.links.lock().map_err(|_| Self::link_state_error())?; - for linked_path in links.path_to_ino.keys() { - if dirname(linked_path) != normalized { - continue; - } - let name = Path::new(linked_path) - .file_name() - .map(|value| value.to_string_lossy().into_owned()) - .unwrap_or_else(|| linked_path.trim_start_matches('/').to_owned()); - if entries.iter().all(|entry| entry.name != name) { - entries.push(secure_exec_bridge::DirectoryEntry { - name, - kind: FileKind::File, - }); - } - } - Ok(entries - .into_iter() - .map(|entry| VirtualDirEntry { - name: entry.name, - is_directory: entry.kind == FileKind::Directory, - is_symbolic_link: entry.kind == FileKind::SymbolicLink, - }) - .collect()) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - let normalized = self - .tracked_identity(path)? - .map(|identity| identity.canonical_path) - .unwrap_or_else(|| normalize_path(path)); - self.bridge - .with_mut(|bridge| { - bridge.write_file(WriteFileRequest { - vm_id: self.vm_id.clone(), - path: normalized, - contents: content.into(), - }) - }) - .map_err(Self::vfs_error) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - let normalized = normalize_path(path); - self.bridge - .with_mut(|bridge| { - bridge.create_dir(CreateDirRequest { - vm_id: self.vm_id.clone(), - path: normalized, - recursive: false, - }) - }) - .map_err(Self::vfs_error) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - let normalized = normalize_path(path); - self.bridge - .with_mut(|bridge| { - bridge.create_dir(CreateDirRequest { - vm_id: self.vm_id.clone(), - path: normalized, - recursive, - }) - }) - .map_err(Self::vfs_error) - } - - fn exists(&self, path: &str) -> bool { - if self.tracked_identity(path).ok().flatten().is_some() { - return true; - } - let normalized = normalize_path(path); - self.bridge - .with_mut(|bridge| { - bridge.exists(PathRequest { - vm_id: self.vm_id.clone(), - path: normalized, - }) - }) - .unwrap_or(false) - } - - fn stat(&mut self, path: &str) -> VfsResult { - let identity = self.tracked_identity_for_stat(path)?; - let normalized = identity - .as_ref() - .map(|identity| identity.canonical_path.clone()) - .unwrap_or_else(|| normalize_path(path)); - let metadata = match self.bridge.with_mut(|bridge| { - bridge.stat(PathRequest { - vm_id: self.vm_id.clone(), - path: normalized.clone(), - }) - }) { - Ok(metadata) => metadata, - Err(error) => { - if !self.exists(&normalized) { - return Err(Self::bridge_path_not_found("stat", &normalized)); - } - return Err(Self::vfs_error(error)); - } - }; - Ok(Self::file_metadata_to_stat(metadata, identity.as_ref())) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - let normalized = normalize_path(path); - if let Some(identity) = self.tracked_identity(&normalized)? { - let canonical = identity.canonical_path; - let nlink = identity.nlink; - if canonical == normalized { - if nlink > 1 { - let successor = self - .tracked_successor(&normalized)? - .expect("tracked inode should retain a successor path"); - self.bridge - .with_mut(|bridge| { - bridge.rename(RenameRequest { - vm_id: self.vm_id.clone(), - from_path: canonical.clone(), - to_path: successor, - }) - }) - .map_err(Self::vfs_error)?; - } else { - self.bridge - .with_mut(|bridge| { - bridge.remove_file(PathRequest { - vm_id: self.vm_id.clone(), - path: canonical, - }) - }) - .map_err(Self::vfs_error)?; - } - } - self.apply_remove(&normalized)?; - return Ok(()); - } - - self.bridge - .with_mut(|bridge| { - bridge.remove_file(PathRequest { - vm_id: self.vm_id.clone(), - path: normalized, - }) - }) - .map_err(Self::vfs_error) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - let normalized = normalize_path(path); - self.bridge - .with_mut(|bridge| { - bridge.remove_dir(PathRequest { - vm_id: self.vm_id.clone(), - path: normalized, - }) - }) - .map_err(Self::vfs_error) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let normalized_old = normalize_path(old_path); - let normalized_new = normalize_path(new_path); - let tracked = self.tracked_identity(&normalized_old)?; - if let Some(identity) = tracked { - let canonical = identity.canonical_path; - if self.exists(&normalized_new) { - return Err(VfsError::new( - "EEXIST", - format!("file already exists, rename '{new_path}'"), - )); - } - if canonical == normalized_old { - self.bridge - .with_mut(|bridge| { - bridge.rename(RenameRequest { - vm_id: self.vm_id.clone(), - from_path: canonical, - to_path: normalized_new.clone(), - }) - }) - .map_err(Self::vfs_error)?; - } - self.apply_rename(&normalized_old, &normalized_new)?; - return Ok(()); - } - - let old_kind = self - .bridge - .with_mut(|bridge| { - bridge.lstat(PathRequest { - vm_id: self.vm_id.clone(), - path: normalized_old.clone(), - }) - }) - .ok() - .map(|metadata| metadata.kind); - self.bridge - .with_mut(|bridge| { - bridge.rename(RenameRequest { - vm_id: self.vm_id.clone(), - from_path: normalized_old.clone(), - to_path: normalized_new.clone(), - }) - }) - .map_err(Self::vfs_error)?; - if old_kind == Some(FileKind::Directory) { - self.apply_rename_prefix(&normalized_old, &normalized_new)?; - } - Ok(()) - } - - fn realpath(&self, path: &str) -> VfsResult { - let original = normalize_path(path); - let mut normalized = original.clone(); - - for _ in 0..HOST_REALPATH_MAX_SYMLINK_DEPTH { - match self.lstat(&normalized) { - Ok(stat) if stat.is_symbolic_link => { - let target = self.read_link(&normalized)?; - normalized = if target.starts_with('/') { - normalize_path(&target) - } else { - normalize_path(&format!("{}/{}", dirname(&normalized), target)) - }; - } - Ok(_) | Err(_) => return Ok(normalized), - } - } - - Err(VfsError::new( - "ELOOP", - format!("too many levels of symbolic links, '{original}'"), - )) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - self.bridge - .with_mut(|bridge| { - bridge.symlink(SymlinkRequest { - vm_id: self.vm_id.clone(), - target_path: normalize_path(target), - link_path: normalize_path(link_path), - }) - }) - .map_err(Self::vfs_error) - } - - fn read_link(&self, path: &str) -> VfsResult { - let normalized = normalize_path(path); - self.bridge - .with_mut(|bridge| { - bridge.read_link(PathRequest { - vm_id: self.vm_id.clone(), - path: normalized, - }) - }) - .map_err(Self::vfs_error) - } - - fn lstat(&self, path: &str) -> VfsResult { - let identity = self.tracked_identity(path)?; - let normalized = identity - .as_ref() - .map(|identity| identity.canonical_path.clone()) - .unwrap_or_else(|| normalize_path(path)); - let metadata = match self.bridge.with_mut(|bridge| { - bridge.lstat(PathRequest { - vm_id: self.vm_id.clone(), - path: normalized.clone(), - }) - }) { - Ok(metadata) => metadata, - Err(error) => { - let exists = self - .bridge - .with_mut(|bridge| { - bridge.exists(PathRequest { - vm_id: self.vm_id.clone(), - path: normalized.clone(), - }) - }) - .unwrap_or(false); - if !exists { - return Err(Self::bridge_path_not_found("lstat", &normalized)); - } - return Err(Self::vfs_error(error)); - } - }; - Ok(Self::file_metadata_to_stat(metadata, identity.as_ref())) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let normalized_old = normalize_path(old_path); - let normalized_new = normalize_path(new_path); - if self.exists(&normalized_new) { - return Err(VfsError::new( - "EEXIST", - format!("file already exists, link '{new_path}'"), - )); - } - - let old_stat = self.stat(&normalized_old)?; - if old_stat.is_directory || old_stat.is_symbolic_link { - return Err(VfsError::new( - "EPERM", - format!("operation not permitted, link '{old_path}'"), - )); - } - let parent = self.lstat(&dirname(&normalized_new))?; - if !parent.is_directory { - return Err(VfsError::new( - "ENOENT", - format!("no such file or directory, link '{new_path}'"), - )); - } - - self.track_link(&normalized_old, &normalized_new) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - let normalized = normalize_path(path); - self.bridge - .with_mut(|bridge| { - bridge.chmod(ChmodRequest { - vm_id: self.vm_id.clone(), - path: normalized, - mode, - }) - }) - .map_err(Self::vfs_error) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - let now = Self::current_time_ms(); - self.update_metadata(path, |metadata| { - metadata.uid = Some(uid); - metadata.gid = Some(gid); - metadata.ctime_ms = Some(now); - }) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - let now = Self::current_time_ms(); - self.update_metadata(path, |metadata| { - metadata.atime_ms = Some(atime_ms); - metadata.mtime_ms = Some(mtime_ms); - metadata.ctime_ms = Some(now); - }) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - let normalized = self - .tracked_identity(path)? - .map(|identity| identity.canonical_path) - .unwrap_or_else(|| normalize_path(path)); - self.bridge - .with_mut(|bridge| { - bridge.truncate(TruncateRequest { - vm_id: self.vm_id.clone(), - path: normalized, - len: length, - }) - }) - .map_err(Self::vfs_error) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - let bytes = self.read_file(path)?; - let start = offset as usize; - if start >= bytes.len() { - return Ok(Vec::new()); - } - let end = start.saturating_add(length).min(bytes.len()); - Ok(bytes[start..end].to_vec()) - } -} - -#[cfg(test)] -#[derive(Clone)] -pub(crate) struct ScopedHostFilesystem { - inner: HostFilesystem, - guest_root: String, -} - -#[cfg(test)] -impl ScopedHostFilesystem { - pub(crate) fn new(inner: HostFilesystem, guest_root: impl Into) -> Self { - Self { - inner, - guest_root: normalize_path(&guest_root.into()), - } - } - - fn scoped_path(&self, path: &str) -> String { - let normalized = normalize_path(path); - if self.guest_root == "/" { - return normalized; - } - if normalized == "/" { - return self.guest_root.clone(); - } - format!( - "{}/{}", - self.guest_root.trim_end_matches('/'), - normalized.trim_start_matches('/') - ) - } - - fn scoped_target(&self, target: &str) -> String { - if target.starts_with('/') { - self.scoped_path(target) - } else { - target.to_owned() - } - } - - fn strip_guest_root_prefix<'a>(&self, target: &'a str) -> Option<&'a str> { - if target == self.guest_root { - Some("") - } else { - target - .strip_prefix(self.guest_root.as_str()) - .filter(|stripped| stripped.starts_with('/')) - } - } - - pub(crate) fn unscoped_target(&self, target: String) -> String { - if !target.starts_with('/') || self.guest_root == "/" { - return target; - } - match self.strip_guest_root_prefix(&target) { - Some(stripped) => format!("/{}", stripped.trim_start_matches('/')), - None => target, - } - } -} - -#[cfg(test)] -impl VirtualFileSystem for ScopedHostFilesystem -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - fn read_file(&mut self, path: &str) -> VfsResult> { - self.inner.read_file(&self.scoped_path(path)) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - self.inner.read_dir(&self.scoped_path(path)) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - self.inner.read_dir_with_types(&self.scoped_path(path)) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - self.inner.write_file(&self.scoped_path(path), content) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - self.inner.create_dir(&self.scoped_path(path)) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - self.inner.mkdir(&self.scoped_path(path), recursive) - } - - fn exists(&self, path: &str) -> bool { - self.inner.exists(&self.scoped_path(path)) - } - - fn stat(&mut self, path: &str) -> VfsResult { - self.inner.stat(&self.scoped_path(path)) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - self.inner.remove_file(&self.scoped_path(path)) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - self.inner.remove_dir(&self.scoped_path(path)) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.inner - .rename(&self.scoped_path(old_path), &self.scoped_path(new_path)) - } - - fn realpath(&self, path: &str) -> VfsResult { - let resolved = self.inner.realpath(&self.scoped_path(path))?; - Ok(self.unscoped_target(resolved)) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - self.inner - .symlink(&self.scoped_target(target), &self.scoped_path(link_path)) - } - - fn read_link(&self, path: &str) -> VfsResult { - self.inner - .read_link(&self.scoped_path(path)) - .map(|target| self.unscoped_target(target)) - } - - fn lstat(&self, path: &str) -> VfsResult { - self.inner.lstat(&self.scoped_path(path)) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.inner - .link(&self.scoped_path(old_path), &self.scoped_path(new_path)) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - self.inner.chmod(&self.scoped_path(path), mode) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - self.inner.chown(&self.scoped_path(path), uid, gid) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - self.inner - .utimes(&self.scoped_path(path), atime_ms, mtime_ms) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - self.inner.truncate(&self.scoped_path(path), length) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - self.inner.pread(&self.scoped_path(path), offset, length) - } -} - -#[derive(Clone)] -pub(crate) struct MountPluginContext { - pub(crate) bridge: SharedBridge, - pub(crate) connection_id: String, - pub(crate) session_id: String, - pub(crate) vm_id: String, - pub(crate) sidecar_requests: SharedSidecarRequestClient, - pub(crate) max_pread_bytes: Option, -} - -impl crate::plugins::host_dir::HostDirReadLimitContext for MountPluginContext { - fn host_dir_max_read_bytes(&self) -> Option { - self.max_pread_bytes - } -} - -#[derive(Debug)] -struct MemoryMountPlugin; - -impl FileSystemPluginFactory for MemoryMountPlugin { - fn plugin_id(&self) -> &'static str { - "memory" - } - - fn open( - &self, - _request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - Ok(Box::new(MountedVirtualFileSystem::new( - MemoryFileSystem::new(), - ))) - } -} - -pub(crate) fn bridge_permissions(bridge: SharedBridge, vm_id: &str) -> Permissions -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let vm_id = vm_id.to_owned(); - - let filesystem_bridge = bridge.clone(); - let filesystem_vm_id = vm_id.clone(); - let network_bridge = bridge.clone(); - let network_vm_id = vm_id.clone(); - let command_bridge = bridge.clone(); - let command_vm_id = vm_id.clone(); - let environment_bridge = bridge; - - Permissions { - filesystem: Some(Arc::new(move |request: &FsAccessRequest| { - let access = match request.op { - FsOperation::Read => FilesystemAccess::Read, - FsOperation::Write => FilesystemAccess::Write, - FsOperation::Mkdir | FsOperation::CreateDir => FilesystemAccess::CreateDir, - FsOperation::ReadDir => FilesystemAccess::ReadDir, - FsOperation::Stat | FsOperation::Exists => FilesystemAccess::Stat, - FsOperation::Remove => FilesystemAccess::Remove, - FsOperation::Rename => FilesystemAccess::Rename, - FsOperation::Symlink => FilesystemAccess::Symlink, - FsOperation::ReadLink => FilesystemAccess::ReadLink, - FsOperation::Link => FilesystemAccess::Write, - FsOperation::Chmod => FilesystemAccess::Write, - FsOperation::Chown => FilesystemAccess::Write, - FsOperation::Utimes => FilesystemAccess::Write, - FsOperation::Truncate => FilesystemAccess::Truncate, - FsOperation::MountSensitive => FilesystemAccess::Write, - }; - let policy = if request.op == FsOperation::MountSensitive { - "fs.mount_sensitive" - } else { - filesystem_permission_capability(access) - }; - let decision = if request.op == FsOperation::MountSensitive { - filesystem_bridge - .static_permission_decision( - &filesystem_vm_id, - policy, - "fs", - Some(&request.path), - ) - .unwrap_or_else(|| { - PermissionDecision::deny("missing fs.mount_sensitive permission policy") - }) - } else { - filesystem_bridge.filesystem_decision(&filesystem_vm_id, &request.path, access) - }; - - if !decision.allow { - emit_security_audit_event( - &filesystem_bridge, - &filesystem_vm_id, - "security.permission.denied", - audit_fields([ - ( - String::from("operation"), - filesystem_operation_label(request.op).to_owned(), - ), - (String::from("path"), request.path.clone()), - (String::from("policy"), String::from(policy)), - ( - String::from("reason"), - decision - .reason - .clone() - .unwrap_or_else(|| String::from("permission denied")), - ), - ]), - ); - } - - decision - })), - network: Some(Arc::new(move |request: &NetworkAccessRequest| { - network_bridge.network_decision(&network_vm_id, request) - })), - child_process: Some(Arc::new(move |request: &CommandAccessRequest| { - command_bridge.command_decision(&command_vm_id, request) - })), - environment: Some(Arc::new(move |request: &EnvAccessRequest| { - environment_bridge.environment_decision(&vm_id, request) - })), - } -} - -fn filesystem_operation_label(operation: FsOperation) -> &'static str { - match operation { - FsOperation::Read => "read", - FsOperation::Write => "write", - FsOperation::Mkdir => "mkdir", - FsOperation::CreateDir => "createDir", - FsOperation::ReadDir => "readdir", - FsOperation::Stat => "stat", - FsOperation::Remove => "rm", - FsOperation::Rename => "rename", - FsOperation::Exists => "exists", - FsOperation::Symlink => "symlink", - FsOperation::ReadLink => "readlink", - FsOperation::Link => "link", - FsOperation::Chmod => "chmod", - FsOperation::Chown => "chown", - FsOperation::Utimes => "utimes", - FsOperation::Truncate => "truncate", - FsOperation::MountSensitive => "mount", - } -} - -pub(crate) fn build_mount_plugin_registry( -) -> Result>, SidecarError> -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let mut registry = FileSystemPluginRegistry::new(); - registry.register(MemoryMountPlugin).map_err(plugin_error)?; - register_native_mount_plugins(&mut registry).map_err(plugin_error)?; - Ok(registry) -} diff --git a/crates/sidecar/src/crypto_cipher.rs b/crates/sidecar/src/crypto_cipher.rs deleted file mode 100644 index 088c35225..000000000 --- a/crates/sidecar/src/crypto_cipher.rs +++ /dev/null @@ -1,633 +0,0 @@ -//! Pure-Rust (RustCrypto) AES cipher primitives backing guest `node:crypto` -//! `createCipheriv`/`createDecipheriv` and SubtleCrypto AES, replacing the prior -//! OpenSSL `Crypter`. Supports `aes-{128,192,256}-{cbc,ctr,gcm}` with streaming -//! `update`/`final`, PKCS#7 auto-padding (CBC), and AEAD aad/auth-tag handling -//! (GCM). Behaviour matches Node so the concatenation of every `update()` output -//! plus `final()` equals the reference ciphertext/plaintext byte-for-byte. -//! -//! This module is intentionally backend-agnostic (no OpenSSL, no host coupling) -//! so the same implementation can serve the native and wasm sidecars. - -use aes::cipher::generic_array::GenericArray; -use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit, KeyIvInit, StreamCipher}; -use aes::{Aes128, Aes192, Aes256}; -use aes_gcm::aead::consts::U12; -use aes_gcm::aead::AeadInPlace; -use aes_gcm::AesGcm; - -const AES_BLOCK_LEN: usize = 16; - -/// Error type for cipher operations. Mapped by the caller to a `SidecarError`. -#[derive(Debug)] -pub(crate) struct CipherError(pub(crate) String); - -impl CipherError { - fn new(message: impl Into) -> Self { - CipherError(message.into()) - } -} - -type Result = std::result::Result; - -#[derive(Clone, Copy, PartialEq, Eq)] -enum AesMode { - Cbc, - Ctr, - Gcm, -} - -#[derive(Clone, Copy, PartialEq, Eq)] -enum AesBits { - A128, - A192, - A256, -} - -impl AesBits { - fn key_len(self) -> usize { - match self { - AesBits::A128 => 16, - AesBits::A192 => 24, - AesBits::A256 => 32, - } - } -} - -/// Parse a Node cipher name (`aes-256-cbc`) into (bits, mode). -fn parse_algorithm(name: &str) -> Result<(AesBits, AesMode)> { - let lower = name.to_ascii_lowercase(); - let (bits, mode) = match lower.as_str() { - "aes-128-cbc" => (AesBits::A128, AesMode::Cbc), - "aes-192-cbc" => (AesBits::A192, AesMode::Cbc), - "aes-256-cbc" => (AesBits::A256, AesMode::Cbc), - "aes-128-ctr" => (AesBits::A128, AesMode::Ctr), - "aes-192-ctr" => (AesBits::A192, AesMode::Ctr), - "aes-256-ctr" => (AesBits::A256, AesMode::Ctr), - "aes-128-gcm" => (AesBits::A128, AesMode::Gcm), - "aes-192-gcm" => (AesBits::A192, AesMode::Gcm), - "aes-256-gcm" => (AesBits::A256, AesMode::Gcm), - other => { - return Err(CipherError::new(format!( - "unsupported crypto cipher algorithm {other}" - ))) - } - }; - Ok((bits, mode)) -} - -/// Returns true when the algorithm is an AEAD (GCM) cipher. -pub(crate) fn is_aead(algorithm: &str) -> bool { - algorithm.to_ascii_lowercase().ends_with("-gcm") -} - -/// Default AEAD authentication tag length in bytes. -pub(crate) fn default_aead_tag_len() -> usize { - AES_BLOCK_LEN -} - -enum AesBlockCipher { - A128(Aes128), - A192(Aes192), - A256(Aes256), -} - -impl AesBlockCipher { - fn new(bits: AesBits, key: &[u8]) -> Result { - if key.len() != bits.key_len() { - return Err(CipherError::new(format!( - "Invalid key length: expected {} bytes, got {}", - bits.key_len(), - key.len() - ))); - } - Ok(match bits { - AesBits::A128 => AesBlockCipher::A128(Aes128::new(GenericArray::from_slice(key))), - AesBits::A192 => AesBlockCipher::A192(Aes192::new(GenericArray::from_slice(key))), - AesBits::A256 => AesBlockCipher::A256(Aes256::new(GenericArray::from_slice(key))), - }) - } - - fn encrypt_block(&self, block: &mut [u8; AES_BLOCK_LEN]) { - let ga = GenericArray::from_mut_slice(block); - match self { - AesBlockCipher::A128(cipher) => cipher.encrypt_block(ga), - AesBlockCipher::A192(cipher) => cipher.encrypt_block(ga), - AesBlockCipher::A256(cipher) => cipher.encrypt_block(ga), - } - } - - fn decrypt_block(&self, block: &mut [u8; AES_BLOCK_LEN]) { - let ga = GenericArray::from_mut_slice(block); - match self { - AesBlockCipher::A128(cipher) => cipher.decrypt_block(ga), - AesBlockCipher::A192(cipher) => cipher.decrypt_block(ga), - AesBlockCipher::A256(cipher) => cipher.decrypt_block(ga), - } - } -} - -enum AesCtrStream { - A128(ctr::Ctr128BE), - A192(ctr::Ctr128BE), - A256(ctr::Ctr128BE), -} - -impl AesCtrStream { - fn new(bits: AesBits, key: &[u8], iv: &[u8]) -> Result { - if key.len() != bits.key_len() { - return Err(CipherError::new(format!( - "Invalid key length: expected {} bytes, got {}", - bits.key_len(), - key.len() - ))); - } - if iv.len() != AES_BLOCK_LEN { - return Err(CipherError::new(format!( - "Invalid IV length: expected {AES_BLOCK_LEN} bytes, got {}", - iv.len() - ))); - } - let invalid = |_| CipherError::new("Invalid key/IV length for AES-CTR"); - Ok(match bits { - AesBits::A128 => AesCtrStream::A128( - ctr::Ctr128BE::::new_from_slices(key, iv).map_err(invalid)?, - ), - AesBits::A192 => AesCtrStream::A192( - ctr::Ctr128BE::::new_from_slices(key, iv).map_err(invalid)?, - ), - AesBits::A256 => AesCtrStream::A256( - ctr::Ctr128BE::::new_from_slices(key, iv).map_err(invalid)?, - ), - }) - } - - fn apply(&mut self, buf: &mut [u8]) { - match self { - AesCtrStream::A128(stream) => stream.apply_keystream(buf), - AesCtrStream::A192(stream) => stream.apply_keystream(buf), - AesCtrStream::A256(stream) => stream.apply_keystream(buf), - } - } -} - -struct CbcState { - cipher: AesBlockCipher, - /// Previous ciphertext block used for chaining (initialised to the IV). - chain: [u8; AES_BLOCK_LEN], - /// Pending input bytes that have not yet formed a processable block. - buffer: Vec, - decrypt: bool, - pad: bool, -} - -enum CipherKind { - Cbc(CbcState), - Ctr(AesCtrStream), - Gcm(GcmState), -} - -struct GcmState { - bits: AesBits, - key: Vec, - iv: Vec, - aad: Vec, - buffer: Vec, - decrypt: bool, - /// Caller-supplied authentication tag (decrypt only). - auth_tag: Option>, - tag_len: usize, -} - -/// Streaming AES cipher session mirroring Node's `Cipheriv`/`Decipheriv`. -pub(crate) struct StreamCipherSession { - kind: CipherKind, -} - -impl StreamCipherSession { - /// Construct a cipher session. `pad` controls PKCS#7 auto-padding for CBC - /// (Node's `setAutoPadding`). `aad`/`auth_tag` apply to AEAD (GCM) modes. - #[allow(clippy::too_many_arguments)] // mirrors Node's createCipheriv surface - pub(crate) fn new( - algorithm: &str, - key: &[u8], - iv: Option<&[u8]>, - decrypt: bool, - pad: bool, - aad: Option<&[u8]>, - auth_tag: Option<&[u8]>, - tag_len: usize, - ) -> Result { - let (bits, mode) = parse_algorithm(algorithm)?; - let kind = match mode { - AesMode::Cbc => { - let iv = iv.ok_or_else(|| CipherError::new("CBC cipher requires an IV"))?; - if iv.len() != AES_BLOCK_LEN { - return Err(CipherError::new(format!( - "Invalid IV length: expected {AES_BLOCK_LEN} bytes, got {}", - iv.len() - ))); - } - let mut chain = [0_u8; AES_BLOCK_LEN]; - chain.copy_from_slice(iv); - CipherKind::Cbc(CbcState { - cipher: AesBlockCipher::new(bits, key)?, - chain, - buffer: Vec::new(), - decrypt, - pad, - }) - } - AesMode::Ctr => { - let iv = iv.ok_or_else(|| CipherError::new("CTR cipher requires an IV"))?; - CipherKind::Ctr(AesCtrStream::new(bits, key, iv)?) - } - AesMode::Gcm => { - let iv = iv.ok_or_else(|| CipherError::new("GCM cipher requires an IV"))?; - if key.len() != bits.key_len() { - return Err(CipherError::new(format!( - "Invalid key length: expected {} bytes, got {}", - bits.key_len(), - key.len() - ))); - } - CipherKind::Gcm(GcmState { - bits, - key: key.to_vec(), - iv: iv.to_vec(), - aad: aad.map(<[u8]>::to_vec).unwrap_or_default(), - buffer: Vec::new(), - decrypt, - auth_tag: auth_tag.map(<[u8]>::to_vec), - tag_len: if tag_len == 0 { - default_aead_tag_len() - } else { - tag_len - }, - }) - } - }; - Ok(StreamCipherSession { kind }) - } - - /// Process input, returning whatever output is ready (Node `update`). - pub(crate) fn update(&mut self, data: &[u8]) -> Result> { - match &mut self.kind { - CipherKind::Cbc(state) => Ok(cbc_update(state, data)), - CipherKind::Ctr(stream) => { - let mut output = data.to_vec(); - stream.apply(&mut output); - Ok(output) - } - CipherKind::Gcm(state) => { - state.buffer.extend_from_slice(data); - Ok(Vec::new()) - } - } - } - - /// Flush the cipher (Node `final`). For AEAD encryption, the authentication - /// tag is returned alongside the final output bytes. - pub(crate) fn finalize(self) -> Result { - match self.kind { - CipherKind::Cbc(state) => Ok(CipherFinal { - data: cbc_finalize(state)?, - auth_tag: None, - }), - CipherKind::Ctr(_) => Ok(CipherFinal { - data: Vec::new(), - auth_tag: None, - }), - CipherKind::Gcm(state) => gcm_finalize(state), - } - } -} - -/// Output of `finalize`, optionally carrying an AEAD auth tag. -pub(crate) struct CipherFinal { - pub(crate) data: Vec, - pub(crate) auth_tag: Option>, -} - -fn cbc_update(state: &mut CbcState, data: &[u8]) -> Vec { - state.buffer.extend_from_slice(data); - let mut output = Vec::new(); - // For decryption with padding we must retain the final block so `finalize` - // can strip PKCS#7; otherwise process every complete block now. - let reserve = usize::from(state.decrypt && state.pad); - while state.buffer.len() > reserve * AES_BLOCK_LEN - && state.buffer.len() >= AES_BLOCK_LEN - && state.buffer.len() - AES_BLOCK_LEN >= reserve * AES_BLOCK_LEN - { - let mut block = [0_u8; AES_BLOCK_LEN]; - block.copy_from_slice(&state.buffer[..AES_BLOCK_LEN]); - let processed = cbc_process_block(state, block); - output.extend_from_slice(&processed); - state.buffer.drain(..AES_BLOCK_LEN); - } - output -} - -fn cbc_process_block(state: &mut CbcState, mut block: [u8; AES_BLOCK_LEN]) -> [u8; AES_BLOCK_LEN] { - if state.decrypt { - let ciphertext = block; - state.cipher.decrypt_block(&mut block); - for (byte, chain) in block.iter_mut().zip(state.chain.iter()) { - *byte ^= *chain; - } - state.chain = ciphertext; - block - } else { - for (byte, chain) in block.iter_mut().zip(state.chain.iter()) { - *byte ^= *chain; - } - state.cipher.encrypt_block(&mut block); - state.chain = block; - block - } -} - -fn cbc_finalize(mut state: CbcState) -> Result> { - if state.decrypt { - if state.pad { - if state.buffer.len() != AES_BLOCK_LEN { - return Err(CipherError::new( - "wrong final block length (bad decrypt input)", - )); - } - let mut block = [0_u8; AES_BLOCK_LEN]; - block.copy_from_slice(&state.buffer); - let plaintext = cbc_process_block(&mut state, block); - strip_pkcs7(&plaintext) - } else { - if !state.buffer.is_empty() { - return Err(CipherError::new( - "wrong final block length (bad decrypt input)", - )); - } - Ok(Vec::new()) - } - } else if state.pad { - // PKCS#7: always emit one padded block, even when the remainder is empty. - let remainder = state.buffer.len(); - let pad = AES_BLOCK_LEN - remainder; - let mut block = [0_u8; AES_BLOCK_LEN]; - block[..remainder].copy_from_slice(&state.buffer); - for byte in block.iter_mut().skip(remainder) { - *byte = pad as u8; - } - Ok(cbc_process_block(&mut state, block).to_vec()) - } else { - if !state.buffer.is_empty() { - return Err(CipherError::new( - "data not a multiple of block length (no padding)", - )); - } - Ok(Vec::new()) - } -} - -fn strip_pkcs7(block: &[u8]) -> Result> { - let pad = *block - .last() - .ok_or_else(|| CipherError::new("empty block during unpad"))? as usize; - if pad == 0 || pad > AES_BLOCK_LEN || pad > block.len() { - return Err(CipherError::new("bad decrypt (invalid PKCS#7 padding)")); - } - if block[block.len() - pad..] - .iter() - .any(|&byte| byte as usize != pad) - { - return Err(CipherError::new("bad decrypt (invalid PKCS#7 padding)")); - } - Ok(block[..block.len() - pad].to_vec()) -} - -fn gcm_cipher(bits: AesBits, key: &[u8]) -> Result { - let invalid = |_| CipherError::new("Invalid key length for AES-GCM"); - Ok(match bits { - AesBits::A128 => GcmAead::A128(Box::new( - AesGcm::::new_from_slice(key).map_err(invalid)?, - )), - AesBits::A192 => GcmAead::A192(Box::new( - AesGcm::::new_from_slice(key).map_err(invalid)?, - )), - AesBits::A256 => GcmAead::A256(Box::new( - AesGcm::::new_from_slice(key).map_err(invalid)?, - )), - }) -} - -enum GcmAead { - A128(Box>), - A192(Box>), - A256(Box>), -} - -impl GcmAead { - fn encrypt_detached(&self, nonce: &[u8], aad: &[u8], buffer: &mut [u8]) -> Result> { - let nonce = GenericArray::from_slice(nonce); - let tag = match self { - GcmAead::A128(c) => c.encrypt_in_place_detached(nonce, aad, buffer), - GcmAead::A192(c) => c.encrypt_in_place_detached(nonce, aad, buffer), - GcmAead::A256(c) => c.encrypt_in_place_detached(nonce, aad, buffer), - } - .map_err(|_| CipherError::new("AEAD encryption failed"))?; - Ok(tag.to_vec()) - } - - fn decrypt_detached( - &self, - nonce: &[u8], - aad: &[u8], - buffer: &mut [u8], - tag: &[u8], - ) -> Result<()> { - let nonce = GenericArray::from_slice(nonce); - let tag = GenericArray::from_slice(tag); - match self { - GcmAead::A128(c) => c.decrypt_in_place_detached(nonce, aad, buffer, tag), - GcmAead::A192(c) => c.decrypt_in_place_detached(nonce, aad, buffer, tag), - GcmAead::A256(c) => c.decrypt_in_place_detached(nonce, aad, buffer, tag), - } - .map_err(|_| CipherError::new("Unsupported state or unable to authenticate data")) - } -} - -fn gcm_finalize(state: GcmState) -> Result { - if state.iv.len() != 12 { - return Err(CipherError::new(format!( - "GCM requires a 12-byte IV, got {}", - state.iv.len() - ))); - } - let cipher = gcm_cipher(state.bits, &state.key)?; - let mut buffer = state.buffer.clone(); - if state.decrypt { - let tag = state - .auth_tag - .as_ref() - .ok_or_else(|| CipherError::new("missing AEAD auth tag for decryption"))?; - if tag.len() != default_aead_tag_len() { - return Err(CipherError::new(format!( - "GCM auth tag must be {} bytes, got {}", - default_aead_tag_len(), - tag.len() - ))); - } - cipher.decrypt_detached(&state.iv, &state.aad, &mut buffer, tag)?; - Ok(CipherFinal { - data: buffer, - auth_tag: None, - }) - } else { - let mut tag = cipher.encrypt_detached(&state.iv, &state.aad, &mut buffer)?; - tag.truncate(state.tag_len); - Ok(CipherFinal { - data: buffer, - auth_tag: Some(tag), - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn encrypt_all( - algorithm: &str, - key: &[u8], - iv: &[u8], - plaintext: &[u8], - ) -> (Vec, Option>) { - let mut session = - StreamCipherSession::new(algorithm, key, Some(iv), false, true, None, None, 16) - .unwrap(); - let mut out = session.update(plaintext).unwrap(); - let fin = session.finalize().unwrap(); - out.extend_from_slice(&fin.data); - (out, fin.auth_tag) - } - - fn decrypt_all( - algorithm: &str, - key: &[u8], - iv: &[u8], - ciphertext: &[u8], - tag: Option<&[u8]>, - ) -> Vec { - let mut session = - StreamCipherSession::new(algorithm, key, Some(iv), true, true, None, tag, 16).unwrap(); - let mut out = session.update(ciphertext).unwrap(); - let fin = session.finalize().unwrap(); - out.extend_from_slice(&fin.data); - out - } - - #[test] - fn aes_256_cbc_roundtrip() { - let key = [7_u8; 32]; - let iv = [9_u8; 16]; - let plaintext = b"secure-exec-crypto-surface"; - let (ciphertext, _) = encrypt_all("aes-256-cbc", &key, &iv, plaintext); - let recovered = decrypt_all("aes-256-cbc", &key, &iv, &ciphertext, None); - assert_eq!(recovered, plaintext); - } - - #[test] - fn aes_256_cbc_matches_known_vector() { - // NIST SP 800-38A F.2.5 CBC-AES256.Encrypt, first block. - let key = [ - 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, - 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, - 0x09, 0x14, 0xdf, 0xf4, - ]; - let iv = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, - 0x0e, 0x0f, - ]; - let plaintext = [ - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, - 0x17, 0x2a, - ]; - // Disable padding so the single block maps 1:1 to the known ciphertext. - let mut session = - StreamCipherSession::new("aes-256-cbc", &key, Some(&iv), false, false, None, None, 16) - .unwrap(); - let mut out = session.update(&plaintext).unwrap(); - out.extend_from_slice(&session.finalize().unwrap().data); - assert_eq!( - out, - vec![ - 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, - 0xfb, 0xd6 - ] - ); - } - - #[test] - fn aes_128_ctr_roundtrip_chunked() { - let key = [1_u8; 16]; - let iv = [2_u8; 16]; - let plaintext = b"the quick brown fox jumps over the lazy dog"; - // Chunked update must equal a single update for stream ciphers. - let mut session = - StreamCipherSession::new("aes-128-ctr", &key, Some(&iv), false, true, None, None, 16) - .unwrap(); - let mut ciphertext = session.update(&plaintext[..10]).unwrap(); - ciphertext.extend_from_slice(&session.update(&plaintext[10..]).unwrap()); - ciphertext.extend_from_slice(&session.finalize().unwrap().data); - let recovered = decrypt_all("aes-128-ctr", &key, &iv, &ciphertext, None); - assert_eq!(recovered, plaintext); - } - - #[test] - fn aes_256_gcm_roundtrip_with_tag() { - let key = [3_u8; 32]; - let iv = [4_u8; 12]; - let plaintext = b"authenticated payload"; - let (ciphertext, tag) = encrypt_all("aes-256-gcm", &key, &iv, plaintext); - let tag = tag.expect("gcm tag"); - assert_eq!(tag.len(), 16); - let recovered = decrypt_all("aes-256-gcm", &key, &iv, &ciphertext, Some(&tag)); - assert_eq!(recovered, plaintext); - } - - #[test] - fn aes_256_gcm_rejects_tampered_tag() { - let key = [3_u8; 32]; - let iv = [4_u8; 12]; - let (ciphertext, tag) = encrypt_all("aes-256-gcm", &key, &iv, b"payload"); - let mut tag = tag.unwrap(); - tag[0] ^= 0xff; - let mut session = StreamCipherSession::new( - "aes-256-gcm", - &key, - Some(&iv), - true, - true, - None, - Some(&tag), - 16, - ) - .unwrap(); - session.update(&ciphertext).unwrap(); - assert!(session.finalize().is_err()); - } - - #[test] - fn cbc_chunked_update_matches_single() { - let key = [5_u8; 16]; - let iv = [6_u8; 16]; - let plaintext = b"0123456789abcdefghABCDEFGH"; // 26 bytes, spans blocks - let (single, _) = encrypt_all("aes-128-cbc", &key, &iv, plaintext); - - let mut session = - StreamCipherSession::new("aes-128-cbc", &key, Some(&iv), false, true, None, None, 16) - .unwrap(); - let mut chunked = session.update(&plaintext[..5]).unwrap(); - chunked.extend_from_slice(&session.update(&plaintext[5..20]).unwrap()); - chunked.extend_from_slice(&session.update(&plaintext[20..]).unwrap()); - chunked.extend_from_slice(&session.finalize().unwrap().data); - assert_eq!(chunked, single); - } -} diff --git a/crates/sidecar/src/execution.rs b/crates/sidecar/src/execution.rs deleted file mode 100644 index 1359aed1d..000000000 --- a/crates/sidecar/src/execution.rs +++ /dev/null @@ -1,24490 +0,0 @@ -//! Process execution, networking, and runtime event handling extracted from service.rs. - -use secure_exec_vm_config as vm_config; - -use crate::filesystem::{ - handle_python_vfs_rpc_request as filesystem_handle_python_vfs_rpc_request, - service_javascript_fs_read_sync_rpc, service_javascript_fs_readdir_raw_sync_rpc, - service_javascript_fs_sync_rpc, service_javascript_module_sync_rpc, -}; -use crate::protocol::{ - CloseStdinRequest, EventFrame, EventPayload, ExecuteRequest, FindBoundUdpRequest, - FindListenerRequest, GetProcessSnapshotRequest, GetResourceSnapshotRequest, - GetSignalStateRequest, GetZombieTimerCountRequest, GuestKernelCallRequest, - GuestKernelResultResponse, GuestRuntimeKind, JavascriptChildProcessSpawnOptions, - JavascriptChildProcessSpawnRequest, JavascriptDgramBindRequest, - JavascriptDgramCreateSocketRequest, JavascriptDgramSendRequest, JavascriptDnsLookupRequest, - JavascriptDnsResolveRequest, JavascriptNetConnectRequest, JavascriptNetListenRequest, - JavascriptNetReserveTcpPortRequest, KillProcessRequest, OwnershipScope, ProcessExitedEvent, - ProcessOutputEvent, ProcessSnapshotEntry, ProcessSnapshotStatus, PtyResizedResponse, - QueueSnapshotEntry, RequestFrame, ResizePtyRequest, ResourceSnapshotResponse, ResponseFrame, - ResponsePayload, SidecarRequestPayload, SignalDispositionAction, SignalHandlerRegistration, - SocketStateEntry, StreamChannel, VmFetchRequest, VmFetchResponse, WasmPermissionTier, - WriteStdinRequest, -}; -use crate::service::{ - audit_fields, dirname, emit_security_audit_event, emit_structured_event, javascript_error, - kernel_error, log_stale_process_event, normalize_host_path, normalize_path, - parse_javascript_child_process_spawn_request, path_is_within_root, - process_event_queue_overflow_error, python_error, wasm_error, MAX_PROCESS_EVENT_QUEUE, -}; -use crate::state::{ - ActiveCipherSession, ActiveDhSession, ActiveDiffieHellmanSession, ActiveEcdhSession, - ActiveExecution, ActiveExecutionEvent, ActiveHttp2Server, ActiveHttp2Session, - ActiveHttp2Stream, ActiveHttpServer, ActiveMappedHostFd, ActiveProcess, ActiveSqliteDatabase, - ActiveSqliteStatement, ActiveTcpListener, ActiveTcpSocket, ActiveTlsState, ActiveTlsStream, - ActiveUdpSocket, ActiveUnixListener, ActiveUnixSocket, BridgeError, ExitedProcessSnapshot, - Http2BridgeEvent, Http2RuntimeSnapshot, Http2SessionCommand, Http2SessionSnapshot, - Http2SocketSnapshot, JavascriptHttpLoopbackTarget, JavascriptSocketEventPusher, - JavascriptSocketFamily, JavascriptSocketPathContext, JavascriptTcpListenerEvent, - JavascriptTcpSocketEvent, JavascriptTlsBridgeOptions, JavascriptTlsClientHello, - JavascriptTlsDataValue, JavascriptTlsMaterial, JavascriptUdpFamily, JavascriptUdpSocketEvent, - JavascriptUnixListenerEvent, KernelSocketReadinessEvent, KernelSocketReadinessRegistry, - KernelSocketReadinessTarget, LoopbackTlsPendingWriteHandle, LoopbackTlsPendingWriteState, - NetworkResourceCounts, PendingTcpSocket, PendingUnixSocket, ProcNetEntry, ProcessEventEnvelope, - PythonHostSocket, ResolvedChildProcessExecution, ResolvedTcpConnectAddr, SharedBridge, - SharedSidecarRequestClient, SidecarKernel, SocketQueryKind, ToolExecution, VmDnsConfig, - VmListenPolicy, VmState, DEFAULT_JAVASCRIPT_NET_BACKLOG, EXECUTION_DRIVER_NAME, - EXECUTION_SANDBOX_ROOT_ENV, JAVASCRIPT_COMMAND, LOOPBACK_EXEMPT_PORTS_ENV, - MAPPED_HOST_FD_START, PYTHON_COMMAND, TOOL_DRIVER_NAME, - VM_LISTEN_ALLOW_PRIVILEGED_METADATA_KEY, WASM_COMMAND, WASM_STDIO_SYNC_RPC_ENV, -}; -use crate::tools::{ - format_tool_failure_output, is_tool_command, normalized_tool_command_name, - resolve_tool_command, ToolCommandResolution, -}; -use crate::wire::{ProtocolFrame as WireProtocolFrame, WireFrameCodec}; -use crate::{DispatchResult, NativeSidecar, NativeSidecarBridge, SidecarError}; - -use base64::Engine; -use bytes::Bytes; -use h2::{client, server, Reason}; -use hickory_resolver::proto::rr::{RData, Record, RecordType}; -use hmac::{Hmac, Mac}; -use http::{HeaderMap, HeaderName, HeaderValue, Method, Request, Response, Uri}; -use md5::Md5; -use nix::libc; -use nix::poll::{poll, PollFd as NixPollFd, PollFlags, PollTimeout}; -use nix::sys::signal::{kill as send_signal, Signal}; -use nix::sys::wait::WaitStatus; -#[cfg(not(target_os = "macos"))] -use nix::sys::wait::{waitid as wait_on_child, Id as WaitId, WaitPidFlag}; -#[cfg(target_os = "macos")] -use nix::sys::wait::{waitpid, WaitPidFlag}; -use nix::unistd::Pid; -use openssl::bn::{BigNum, BigNumContext}; -use openssl::derive::Deriver; -use openssl::dh::Dh; -use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm}; -use openssl::hash::MessageDigest; -use openssl::nid::Nid; -use openssl::pkey::{Id as PKeyId, PKey, Params, Private, Public}; -use openssl::rand::rand_bytes; -use openssl::rsa::{Padding, Rsa}; -use openssl::sign::{Signer, Verifier}; -use pbkdf2::pbkdf2_hmac; - -use crate::crypto_cipher::{CipherError as AesCipherError, StreamCipherSession}; -use rusqlite::types::ValueRef as SqliteValueRef; -use rusqlite::{ - Connection as SqliteConnection, OpenFlags as SqliteOpenFlags, Statement as SqliteStatement, -}; -use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; -use rustls::crypto::aws_lc_rs; -use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName}; -use rustls::{ - ClientConfig, ClientConnection, DigitallySignedStruct, RootCertStore, ServerConfig, - ServerConnection, SignatureScheme, -}; -use scrypt::{scrypt, Params as ScryptParams}; -use secure_exec_bridge::{queue_tracker, LifecycleState}; -use secure_exec_execution::wasm::WasmExecutionError; -use secure_exec_execution::{ - javascript::handle_internal_bridge_call_from_host_context, v8_host::V8SessionHandle, - v8_runtime, CreateJavascriptContextRequest, CreatePythonContextRequest, - CreateWasmContextRequest, GuestModuleReader, GuestRuntimeConfig, JavascriptExecutionEvent, - JavascriptExecutionLimits, JavascriptSyncRpcRequest, ModuleFsReader, - NodeSignalDispositionAction, NodeSignalHandlerRegistration, PythonExecutionEvent, - PythonExecutionLimits, PythonVfsRpcMethod, PythonVfsRpcRequest, PythonVfsRpcResponsePayload, - StartJavascriptExecutionRequest, StartPythonExecutionRequest, StartWasmExecutionRequest, - WasmExecutionEvent, WasmExecutionLimits, WasmPermissionTier as ExecutionWasmPermissionTier, -}; -use secure_exec_kernel::dns::{ - DnsLookupPolicy, DnsRecordResolution, DnsResolutionSource as KernelDnsResolutionSource, -}; -use secure_exec_kernel::kernel::{KernelProcessHandle, SpawnOptions, VirtualProcessOptions}; -pub(crate) use secure_exec_kernel::network_policy::format_tcp_resource; -use secure_exec_kernel::network_policy::{ - is_loopback_ip, loopback_cidr, restricted_non_loopback_ip_range, -}; -use secure_exec_kernel::permissions::NetworkOperation; -use secure_exec_kernel::poll::{PollEvents, PollFd, PollTargetEntry, POLLERR, POLLHUP, POLLIN}; -use secure_exec_kernel::process_table::{ProcessStatus, WaitPidFlags, SIGKILL, SIGTERM}; -use secure_exec_kernel::pty::{LineDisciplineConfig, MAX_PTY_BUFFER_BYTES}; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::root_fs::RootFilesystemMode; -use secure_exec_kernel::socket_table::{ - reset_socket_read_trace, set_socket_read_trace_enabled, socket_read_trace_snapshot, - InetSocketAddress, SocketDomain, SocketId, SocketShutdown as KernelSocketShutdown, SocketSpec, - SocketState, SocketType, -}; -use secure_exec_sidecar_core::{ - apply_process_signal_state_update, bound_udp_snapshot_response, bridge_buffer_value, - decode_base64, decode_bridge_buffer_value, decode_encoded_bytes_value, encoded_bytes_value, - ensure_vm_fetch_raw_response_buffer_within_limit, ensure_vm_fetch_response_within_limit, - listener_snapshot_response, local_endpoint_value, parse_kernel_http_fetch_response, - parse_process_signal_state_request, process_killed_response, - process_snapshot_entry_from_kernel, process_snapshot_response, process_started_response, - remote_endpoint_value, shared_guest_runtime_identity, signal_state_response, - socket_addr_family, socket_address_value, stdin_closed_response, stdin_written_response, - tcp_socket_info_value, unix_socket_info_value, zombie_timer_count_response, - SharedProcessSnapshotEntry, SharedProcessSnapshotStatus, SidecarCoreError, - VM_FETCH_BUFFER_LIMIT_BYTES, -}; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Map, Value}; -use sha1::Sha1; -use sha2::{digest::Digest, Sha224, Sha256, Sha384, Sha512}; -use socket2::{SockRef, TcpKeepalive}; -use std::collections::VecDeque; -use std::collections::{BTreeMap, BTreeSet}; -use std::fmt; -use std::fs; -use std::io::{Cursor, Read, Write}; -use std::net::{ - IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, TcpListener, TcpStream, ToSocketAddrs, - UdpSocket, -}; -use std::os::fd::{AsFd, BorrowedFd}; -use std::os::unix::fs::{MetadataExt, PermissionsExt}; -use std::os::unix::net::{SocketAddr as UnixSocketAddr, UnixListener, UnixStream}; -use std::path::{Path, PathBuf}; -use std::pin::Pin; -use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use std::sync::mpsc::{self, RecvTimeoutError, Sender}; -use std::sync::{Arc, Mutex, OnceLock, Weak}; -use std::thread; -use std::time::{Duration, Instant}; -use tokio::io::{AsyncRead, AsyncWrite}; -use tokio::runtime::Builder as TokioRuntimeBuilder; -use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver}; -use tokio_rustls::{TlsAcceptor, TlsConnector}; -use url::Url; - -const DEFAULT_KERNEL_STDIN_READ_MAX_BYTES: usize = 64 * 1024; -const DEFAULT_KERNEL_STDIN_READ_TIMEOUT_MS: u64 = 100; -const JAVASCRIPT_NET_TIMEOUT_SENTINEL: &str = "__secure_exec_net_timeout__"; -const PYTHON_PYODIDE_GUEST_ROOT: &str = "/__agentos_pyodide"; -const PYTHON_PYODIDE_CACHE_GUEST_ROOT: &str = "/__agentos_pyodide_cache"; -const TCP_SOCKET_POLL_TIMEOUT: Duration = Duration::from_millis(100); -const TLS_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(5); -const LOOPBACK_TLS_HANDSHAKE_POLL_TIMEOUT: Duration = Duration::from_millis(1); -const LOOPBACK_TLS_PENDING_WRITE_BUFFER_BYTES: usize = 4 * 1024 * 1024; -const LOOPBACK_TLS_PENDING_WRITE_WARNING_BYTES: usize = - LOOPBACK_TLS_PENDING_WRITE_BUFFER_BYTES * 4 / 5; -const HTTP_LOOPBACK_REQUEST_TIMEOUT: Duration = Duration::from_secs(30); -const PROCESS_EXIT_DRAIN_INITIAL_QUIET: Duration = Duration::from_millis(1); -const PROCESS_EXIT_DRAIN_TRAILING_QUIET: Duration = Duration::from_millis(25); - -struct NetTcpTraceCounters { - socket_read_calls: AtomicU64, - socket_read_zero_wait_calls: AtomicU64, - socket_read_data_events: AtomicU64, - socket_read_bytes: AtomicU64, - socket_read_kernel_us: AtomicU64, - socket_read_end_events: AtomicU64, - socket_read_eagain: AtomicU64, - socket_read_errors: AtomicU64, - socket_read_push_attempts: AtomicU64, - socket_read_push_sent: AtomicU64, - socket_read_push_missing: AtomicU64, - socket_read_push_errors: AtomicU64, - socket_write_calls: AtomicU64, - socket_write_bytes: AtomicU64, - socket_write_kernel_us: AtomicU64, - socket_write_errors: AtomicU64, - server_accept_calls: AtomicU64, - server_accept_zero_wait_calls: AtomicU64, - server_accept_connections: AtomicU64, - server_accept_eagain: AtomicU64, - server_accept_errors: AtomicU64, - kernel_poll_targets: AtomicU64, - kernel_poll_zero_wait_calls: AtomicU64, - kernel_poll_wait_us: AtomicU64, - kernel_poll_elapsed_us: AtomicU64, - kernel_poll_empty: AtomicU64, - kernel_poll_ready: AtomicU64, - kernel_poll_revents_read: AtomicU64, - kernel_poll_revents_hup: AtomicU64, - kernel_poll_revents_err: AtomicU64, - kernel_poll_revents_bits_or: AtomicU64, -} - -impl NetTcpTraceCounters { - const fn new() -> Self { - Self { - socket_read_calls: AtomicU64::new(0), - socket_read_zero_wait_calls: AtomicU64::new(0), - socket_read_data_events: AtomicU64::new(0), - socket_read_bytes: AtomicU64::new(0), - socket_read_kernel_us: AtomicU64::new(0), - socket_read_end_events: AtomicU64::new(0), - socket_read_eagain: AtomicU64::new(0), - socket_read_errors: AtomicU64::new(0), - socket_read_push_attempts: AtomicU64::new(0), - socket_read_push_sent: AtomicU64::new(0), - socket_read_push_missing: AtomicU64::new(0), - socket_read_push_errors: AtomicU64::new(0), - socket_write_calls: AtomicU64::new(0), - socket_write_bytes: AtomicU64::new(0), - socket_write_kernel_us: AtomicU64::new(0), - socket_write_errors: AtomicU64::new(0), - server_accept_calls: AtomicU64::new(0), - server_accept_zero_wait_calls: AtomicU64::new(0), - server_accept_connections: AtomicU64::new(0), - server_accept_eagain: AtomicU64::new(0), - server_accept_errors: AtomicU64::new(0), - kernel_poll_targets: AtomicU64::new(0), - kernel_poll_zero_wait_calls: AtomicU64::new(0), - kernel_poll_wait_us: AtomicU64::new(0), - kernel_poll_elapsed_us: AtomicU64::new(0), - kernel_poll_empty: AtomicU64::new(0), - kernel_poll_ready: AtomicU64::new(0), - kernel_poll_revents_read: AtomicU64::new(0), - kernel_poll_revents_hup: AtomicU64::new(0), - kernel_poll_revents_err: AtomicU64::new(0), - kernel_poll_revents_bits_or: AtomicU64::new(0), - } - } -} - -static NET_TCP_TRACE_COUNTERS: NetTcpTraceCounters = NetTcpTraceCounters::new(); -pub(crate) const MAX_PER_PROCESS_STATE_HANDLES: usize = 1024; -const DEFAULT_SCRYPT_COST: u64 = 16_384; -const DEFAULT_SCRYPT_BLOCK_SIZE: u32 = 8; -const DEFAULT_SCRYPT_PARALLELIZATION: u32 = 1; -const SQLITE_JS_SAFE_INTEGER_MAX: i64 = 9_007_199_254_740_991; -const HTTP_LOOPBACK_REQUEST_TIMEOUT_MS_ENV: &str = - "SECURE_EXEC_TEST_HTTP_LOOPBACK_REQUEST_TIMEOUT_MS"; - -trait Http2AsyncIo: AsyncRead + AsyncWrite + Unpin + Send {} - -impl Http2AsyncIo for T where T: AsyncRead + AsyncWrite + Unpin + Send {} - -fn http_loopback_request_timeout() -> Duration { - std::env::var(HTTP_LOOPBACK_REQUEST_TIMEOUT_MS_ENV) - .ok() - .and_then(|value| value.parse::().ok()) - .map(Duration::from_millis) - .unwrap_or(HTTP_LOOPBACK_REQUEST_TIMEOUT) -} - -/// Block until `fd` is readable or `deadline` passes. Returns whether it became readable. -/// -/// BLOCKING: parks the calling OS thread in `poll(2)`. The unix/tcp accept and -/// udp recv callers run on the sidecar's single-thread tokio runtime, so a -/// non-zero wait stalls the whole event loop for up to `deadline` — the same -/// stall as the fixed sleeps this replaced, and only acceptable because the -/// guest net path always polls with wait == 0. Keep deadlines bounded and do -/// not add wait > 0 callers on paths that service concurrent VM traffic. -fn wait_fd_readable_until(fd: BorrowedFd<'_>, deadline: Instant) -> bool { - let remaining = deadline.saturating_duration_since(Instant::now()); - if remaining.is_zero() { - return false; - } - - let timeout_ms = remaining.as_millis().saturating_add(u128::from( - !remaining.subsec_nanos().is_multiple_of(1_000_000), - )); - let timeout = - PollTimeout::try_from(timeout_ms.min(i32::MAX as u128)).unwrap_or(PollTimeout::MAX); - let mut fds = [NixPollFd::new(fd, PollFlags::POLLIN)]; - match poll(&mut fds, timeout) { - Ok(0) => false, - Ok(_) => fds[0] - .revents() - .unwrap_or_else(PollFlags::empty) - .intersects(PollFlags::POLLIN | PollFlags::POLLHUP | PollFlags::POLLERR), - Err(_) => true, - } -} - -const DEFAULT_ALLOWED_NODE_BUILTINS: &[&str] = &[ - "assert", - "buffer", - "console", - "child_process", - "crypto", - "dns", - "events", - "fs", - "http", - "http2", - "https", - "module", - "os", - "path", - "perf_hooks", - "querystring", - "sqlite", - "stream", - "string_decoder", - "timers", - "tls", - "tty", - "url", - "util", - "zlib", -]; -const EXECUTION_REQUEST_TTY_ENV: &str = "AGENTOS_EXEC_TTY"; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum JavascriptCryptoDigestAlgorithm { - Md5, - Sha1, - Sha224, - Sha256, - Sha384, - Sha512, -} - -#[derive(Debug, Default, Deserialize)] -#[serde(default, rename_all = "camelCase")] -struct JavascriptScryptOptions { - #[serde(alias = "N")] - cost: Option, - #[serde(alias = "r")] - block_size: Option, - #[serde(alias = "p")] - parallelization: Option, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct JavascriptHttpListenRequest { - server_id: u64, - #[serde(default)] - port: Option, - #[serde(default)] - hostname: Option, -} - -#[derive(Debug, Default, Deserialize)] -#[serde(default, rename_all = "camelCase")] -struct JavascriptHttpRequestOptions { - method: Option, - headers: BTreeMap, - body: Option, - reject_unauthorized: Option, -} - -#[derive(Debug, Default, Deserialize)] -#[serde(default, rename_all = "camelCase")] -struct JavascriptHttp2ServerListenRequest { - server_id: u64, - secure: bool, - port: Option, - host: Option, - backlog: Option, - timeout: Option, - settings: BTreeMap, - tls: Option, -} - -#[derive(Debug, Default, Deserialize)] -#[serde(default, rename_all = "camelCase")] -struct JavascriptHttp2SessionConnectRequest { - authority: Option, - protocol: Option, - host: Option, - port: Option, - settings: BTreeMap, - tls: Option, -} - -#[derive(Debug, Default, Deserialize)] -#[serde(default, rename_all = "camelCase")] -struct JavascriptHttp2RequestOptions { - end_stream: bool, -} - -#[derive(Debug, Default, Deserialize)] -#[serde(default, rename_all = "camelCase")] -struct JavascriptHttp2FileResponseOptions { - offset: Option, - length: Option, -} - -#[derive(Debug, Clone)] -struct HttpHeaderCollection { - normalized: BTreeMap>, - raw_pairs: Vec<(String, String)>, -} - -#[derive(Debug)] -struct InsecureTlsVerifier { - supported_schemes: Vec, -} - -impl ServerCertVerifier for InsecureTlsVerifier { - fn verify_server_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp_response: &[u8], - _now: rustls::pki_types::UnixTime, - ) -> Result { - Ok(ServerCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result { - Ok(HandshakeSignatureValid::assertion()) - } - - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result { - Ok(HandshakeSignatureValid::assertion()) - } - - fn supported_verify_schemes(&self) -> Vec { - self.supported_schemes.clone() - } -} - -impl ActiveProcess { - pub(crate) fn new( - kernel_pid: u32, - kernel_handle: KernelProcessHandle, - runtime: GuestRuntimeKind, - execution: ActiveExecution, - ) -> Self { - Self { - kernel_pid, - kernel_handle, - kernel_stdin_writer_fd: None, - tty_master_fd: None, - runtime, - detached: false, - execution, - guest_cwd: String::from("/"), - env: BTreeMap::new(), - host_cwd: PathBuf::from("/"), - host_write_dirty: false, - mapped_host_fds: BTreeMap::new(), - next_mapped_host_fd: MAPPED_HOST_FD_START, - pending_execution_events: VecDeque::new(), - pending_self_signal_exit: None, - child_processes: BTreeMap::new(), - next_child_process_id: 0, - http_servers: BTreeMap::new(), - pending_http_requests: BTreeMap::new(), - http2: Default::default(), - tcp_listeners: BTreeMap::new(), - next_tcp_listener_id: 0, - tcp_sockets: BTreeMap::new(), - next_tcp_socket_id: 0, - tcp_port_reservations: BTreeMap::new(), - next_tcp_port_reservation_id: 0, - unix_listeners: BTreeMap::new(), - next_unix_listener_id: 0, - unix_sockets: BTreeMap::new(), - next_unix_socket_id: 0, - udp_sockets: BTreeMap::new(), - next_udp_socket_id: 0, - python_sockets: BTreeMap::new(), - next_python_socket_id: 0, - cipher_sessions: BTreeMap::new(), - next_cipher_session_id: 0, - diffie_hellman_sessions: BTreeMap::new(), - next_diffie_hellman_session_id: 0, - sqlite_databases: BTreeMap::new(), - next_sqlite_database_id: 0, - sqlite_statements: BTreeMap::new(), - next_sqlite_statement_id: 0, - tty_master_owner: None, - deferred_kernel_wait_rpc: None, - module_resolution_cache: secure_exec_execution::LocalModuleResolutionCache::default(), - } - } - - pub(crate) fn queue_pending_execution_event( - &mut self, - event: ActiveExecutionEvent, - ) -> Result<(), SidecarError> { - if self.pending_execution_events.len() >= MAX_PROCESS_EVENT_QUEUE { - return Err(process_event_queue_overflow_error()); - } - self.pending_execution_events.push_back(event); - Ok(()) - } - - pub(crate) fn with_host_cwd(mut self, host_cwd: PathBuf) -> Self { - self.host_cwd = host_cwd; - self - } - - pub(crate) fn mark_host_write_dirty(&mut self) { - self.host_write_dirty = true; - } - - pub(crate) fn host_write_dirty_recursive(&self) -> bool { - self.host_write_dirty - || self - .child_processes - .values() - .any(ActiveProcess::host_write_dirty_recursive) - } - - pub(crate) fn clean_host_writes_are_observable_recursive(&self) -> bool { - matches!( - self.execution, - ActiveExecution::Javascript(_) | ActiveExecution::Python(_) | ActiveExecution::Wasm(_) - ) && self - .child_processes - .values() - .all(ActiveProcess::clean_host_writes_are_observable_recursive) - } - - pub(crate) fn with_guest_cwd(mut self, guest_cwd: String) -> Self { - self.guest_cwd = guest_cwd; - self - } - - pub(crate) fn with_env(mut self, env: BTreeMap) -> Self { - self.env = env; - self - } - - pub(crate) fn with_kernel_stdin_writer_fd(mut self, fd: u32) -> Self { - self.kernel_stdin_writer_fd = Some(fd); - self - } - - pub(crate) fn with_tty_master_fd(mut self, fd: Option) -> Self { - self.tty_master_fd = fd; - self - } - - pub(crate) fn with_detached(mut self, detached: bool) -> Self { - self.detached = detached; - self - } - - pub(crate) fn allocate_mapped_host_fd(&mut self, fd: ActiveMappedHostFd) -> u32 { - let handle = self.next_mapped_host_fd; - self.next_mapped_host_fd = self - .next_mapped_host_fd - .checked_add(1) - .unwrap_or(MAPPED_HOST_FD_START); - self.mapped_host_fds.insert(handle, fd); - handle - } - - pub(crate) fn mapped_host_fd(&self, fd: u32) -> Option<&ActiveMappedHostFd> { - self.mapped_host_fds.get(&fd) - } - - pub(crate) fn mapped_host_fd_mut(&mut self, fd: u32) -> Option<&mut ActiveMappedHostFd> { - self.mapped_host_fds.get_mut(&fd) - } - - pub(crate) fn close_mapped_host_fd(&mut self, fd: u32) -> bool { - self.mapped_host_fds.remove(&fd).is_some() - } - - pub(crate) fn allocate_child_process_id(&mut self) -> String { - self.next_child_process_id += 1; - format!("child-{}", self.next_child_process_id) - } - - fn allocate_tcp_listener_id(&mut self) -> String { - self.next_tcp_listener_id += 1; - format!("listener-{}", self.next_tcp_listener_id) - } - - fn allocate_tcp_socket_id(&mut self) -> String { - self.next_tcp_socket_id += 1; - format!("socket-{}", self.next_tcp_socket_id) - } - - fn allocate_tcp_port_reservation_id(&mut self) -> String { - self.next_tcp_port_reservation_id += 1; - format!("tcp-port-reservation-{}", self.next_tcp_port_reservation_id) - } - - fn allocate_unix_listener_id(&mut self) -> String { - self.next_unix_listener_id += 1; - format!("unix-listener-{}", self.next_unix_listener_id) - } - - fn allocate_unix_socket_id(&mut self) -> String { - self.next_unix_socket_id += 1; - format!("unix-socket-{}", self.next_unix_socket_id) - } - - fn allocate_udp_socket_id(&mut self) -> String { - self.next_udp_socket_id += 1; - format!("udp-socket-{}", self.next_udp_socket_id) - } - - pub(crate) fn network_resource_counts(&self) -> NetworkResourceCounts { - let mut counts = NetworkResourceCounts { - sockets: self.http_servers.len() - + self.tcp_listeners.len() - + self.tcp_sockets.len() - + self.unix_listeners.len() - + self.unix_sockets.len() - + self.udp_sockets.len() - + self.python_sockets.len(), - connections: self.tcp_sockets.len() + self.unix_sockets.len(), - }; - if let Ok(http2) = self.http2.shared.lock() { - counts.sockets += http2.servers.len() + http2.sessions.len(); - counts.connections += http2.sessions.len(); - } - - for child in self.child_processes.values() { - let child_counts = child.network_resource_counts(); - counts.sockets += child_counts.sockets; - counts.connections += child_counts.connections; - } - - counts - } - - fn sidecar_only_network_resource_counts(&self) -> NetworkResourceCounts { - let mut counts = NetworkResourceCounts { - sockets: self.http_servers.len() - + self - .tcp_listeners - .values() - .filter(|listener| listener.kernel_socket_id.is_none()) - .count() - + self - .tcp_sockets - .values() - .filter(|socket| socket.kernel_socket_id.is_none()) - .count() - + self.unix_listeners.len() - + self.unix_sockets.len() - + self - .udp_sockets - .values() - .filter(|socket| socket.kernel_socket_id.is_none()) - .count() - + self.python_sockets.len(), - connections: self - .tcp_sockets - .values() - .filter(|socket| socket.kernel_socket_id.is_none()) - .count() - + self.unix_sockets.len(), - }; - if let Ok(http2) = self.http2.shared.lock() { - counts.sockets += http2.servers.len() + http2.sessions.len(); - counts.connections += http2.sessions.len(); - } - - for child in self.child_processes.values() { - let child_counts = child.sidecar_only_network_resource_counts(); - counts.sockets += child_counts.sockets; - counts.connections += child_counts.connections; - } - - counts - } -} - -fn poll_tool_process_event( - execution: &ToolExecution, -) -> Result, SidecarError> { - let event = execution - .pending_events - .lock() - .unwrap_or_else(|poisoned| poisoned.into_inner()) - .pop_front(); - if event.is_some() { - return Ok(event); - } - if execution.events_overflowed.load(Ordering::Relaxed) { - return Err(process_event_queue_overflow_error()); - } - Ok(None) -} - -fn descendant_pending_execution_event_capacity( - root: &ActiveProcess, - child_path: &[&str], -) -> Option { - let mut child = root; - for child_process_id in child_path { - child = child.child_processes.get(*child_process_id)?; - } - Some(MAX_PROCESS_EVENT_QUEUE.saturating_sub(child.pending_execution_events.len())) -} - -fn poll_child_execution_after_exit( - child: &mut ActiveProcess, - wait: Duration, -) -> Result, SidecarError> { - match child.execution.poll_event_blocking(wait) { - Ok(event) => Ok(event), - Err(SidecarError::Execution(message)) - if child.runtime == GuestRuntimeKind::WebAssembly - && message == WasmExecutionError::EventChannelClosed.to_string() => - { - Ok(None) - } - Err(error) => Err(error), - } -} - -fn closed_javascript_event_channel(message: &str) -> bool { - message == "guest JavaScript event channel closed unexpectedly" -} - -fn closed_python_event_channel(message: &str) -> bool { - message == "guest Python event channel closed unexpectedly" -} - -fn closed_wasm_event_channel(message: &str) -> bool { - message == WasmExecutionError::EventChannelClosed.to_string() -} - -fn missing_vm_error(vm_id: &str) -> SidecarError { - SidecarError::InvalidState(format!("VM {vm_id} is no longer active")) -} - -fn missing_process_error(vm_id: &str, process_id: &str) -> SidecarError { - SidecarError::InvalidState(format!( - "VM {vm_id} no longer has active process {process_id}" - )) -} - -/// Map a shared guest-kernel-call dispatcher error into a sidecar error, -/// preserving POSIX errno codes (`ECODE: message`) as kernel errors so guest -/// callers observe Linux-faithful failures, mirroring the filesystem path. -fn guest_kernel_core_error(error: secure_exec_sidecar_core::SidecarCoreError) -> SidecarError { - let message = error.to_string(); - let is_errno = message.split_once(':').is_some_and(|(code, _)| { - code.len() >= 2 - && code.starts_with('E') - && code[1..] - .bytes() - .all(|byte| byte.is_ascii_uppercase() || byte.is_ascii_digit() || byte == b'_') - }); - if is_errno { - SidecarError::Kernel(message) - } else { - SidecarError::InvalidState(message) - } -} - -fn is_broken_pipe_error(error: &SidecarError) -> bool { - matches!(error, SidecarError::Execution(message) if message.contains("Broken pipe") || message.contains("os error 32") || message.contains("EPIPE")) -} - -fn javascript_child_process_gone_error(process_id: &str, child_path: &[&str]) -> SidecarError { - let child_label = if child_path.is_empty() { - process_id.to_owned() - } else { - format!("{process_id}/{}", child_path.join("/")) - }; - SidecarError::Execution(format!( - "ECHILD: child_process {child_label} is no longer available" - )) -} - -fn is_javascript_child_process_gone_error(error: &SidecarError) -> bool { - matches!( - error, - SidecarError::Execution(message) if guest_errno_code(message) == Some("ECHILD") - ) -} - -fn loopback_tls_transport_registry( -) -> &'static Mutex>> { - static REGISTRY: OnceLock< - Mutex>>, - > = OnceLock::new(); - REGISTRY.get_or_init(|| Mutex::new(BTreeMap::new())) -} - -#[cfg(test)] -#[allow(dead_code)] -pub(crate) fn loopback_tls_registry_len() -> usize { - loopback_tls_transport_registry() - .lock() - .expect("loopback TLS transport registry lock poisoned") - .len() -} - -#[cfg(test)] -pub(crate) fn loopback_tls_registry_contains(key: &str) -> bool { - loopback_tls_transport_registry() - .lock() - .expect("loopback TLS transport registry lock poisoned") - .contains_key(key) -} - -fn loopback_tls_transport_key( - vm_id: &str, - socket_id: SocketId, - peer_socket_id: SocketId, -) -> String { - let (lower, higher) = if socket_id <= peer_socket_id { - (socket_id, peer_socket_id) - } else { - (peer_socket_id, socket_id) - }; - format!("{vm_id}:{lower}:{higher}") -} - -fn loopback_tls_endpoint( - vm_id: &str, - socket_id: SocketId, - peer_socket_id: SocketId, -) -> Result { - let key = loopback_tls_transport_key(vm_id, socket_id, peer_socket_id); - let registry = loopback_tls_transport_registry(); - let mut transports = registry.lock().map_err(|_| { - SidecarError::InvalidState(String::from( - "loopback TLS transport registry lock poisoned", - )) - })?; - transports.retain(|_, pair| pair.strong_count() > 0); - let pair = transports - .get(&key) - .and_then(Weak::upgrade) - .unwrap_or_else(|| { - let pair = Arc::new(crate::state::LoopbackTlsTransportPair { - state: Mutex::new(crate::state::LoopbackTlsTransportPairState::default()), - ready: std::sync::Condvar::new(), - }); - transports.insert(key.clone(), Arc::downgrade(&pair)); - pair - }); - Ok(crate::state::LoopbackTlsEndpoint { - pair, - is_lower_socket: socket_id <= peer_socket_id, - poll_timeout: TCP_SOCKET_POLL_TIMEOUT, - registry_key: Some(key), - }) -} - -impl crate::state::LoopbackTlsEndpoint { - fn set_poll_timeout(&mut self, timeout: Duration) { - self.poll_timeout = timeout; - } - - fn interrupt_reader(pair: &Arc, is_lower_socket: bool) { - if let Ok(mut state) = pair.state.lock() { - if is_lower_socket { - state.lower_read_interrupt = true; - } else { - state.higher_read_interrupt = true; - } - pair.ready.notify_all(); - } - } - - fn shutdown_write(&self) -> Result<(), SidecarError> { - let mut state = self.pair.state.lock().map_err(|_| { - SidecarError::InvalidState(String::from("loopback TLS transport lock poisoned")) - })?; - if self.is_lower_socket { - state.lower_write_closed = true; - } else { - state.higher_write_closed = true; - } - self.pair.ready.notify_all(); - Ok(()) - } - - fn close_endpoint(&self) -> Result<(), SidecarError> { - let mut state = self.pair.state.lock().map_err(|_| { - SidecarError::InvalidState(String::from("loopback TLS transport lock poisoned")) - })?; - if self.is_lower_socket { - state.lower_write_closed = true; - state.lower_closed = true; - } else { - state.higher_write_closed = true; - state.higher_closed = true; - } - self.pair.ready.notify_all(); - Ok(()) - } -} - -impl LoopbackTlsPendingWriteHandle { - pub(crate) fn new(endpoint: &crate::state::LoopbackTlsEndpoint) -> Self { - Self { - state: Arc::new(Mutex::new(LoopbackTlsPendingWriteState { - buffer: Vec::new(), - warned_near_cap: false, - flushing: false, - defer_shutdown_write: false, - failure_message: None, - })), - tls_handshake_complete: Arc::new(AtomicBool::new(false)), - failed: Arc::new(AtomicBool::new(false)), - pair: Arc::clone(&endpoint.pair), - is_lower_socket: endpoint.is_lower_socket, - handshake_started_at: Instant::now(), - } - } - - fn failure_error(&self) -> SidecarError { - let message = self - .state - .lock() - .ok() - .and_then(|state| state.failure_message.clone()) - .unwrap_or_else(|| String::from("loopback TLS pending write failed")); - SidecarError::Execution(message) - } - - fn mark_failed(&self, message: impl Into) { - self.failed.store(true, Ordering::SeqCst); - if let Ok(mut state) = self.state.lock() { - state.buffer.clear(); - state.flushing = false; - state.defer_shutdown_write = false; - state.failure_message = Some(message.into()); - } - } - - fn clear_for_close(&self) { - self.mark_failed("loopback TLS socket closed before buffered writes flushed"); - } - - fn fail_if_pending(&self, message: impl Into) { - let has_pending = self - .state - .lock() - .map(|state| !state.buffer.is_empty() || state.flushing || state.defer_shutdown_write) - .unwrap_or(true); - if has_pending { - self.mark_failed(message); - } - } - - fn should_buffer_write(&self) -> Result { - if self.failed.load(Ordering::SeqCst) { - return Err(self.failure_error()); - } - let state = self.state.lock().map_err(|_| { - SidecarError::InvalidState(String::from("loopback TLS pending write lock poisoned")) - })?; - Ok(!self.tls_handshake_complete.load(Ordering::SeqCst) - || !state.buffer.is_empty() - || state.flushing) - } - - pub(crate) fn append_write(&self, contents: &[u8]) -> Result<(), SidecarError> { - if self.failed.load(Ordering::SeqCst) { - return Err(self.failure_error()); - } - let mut state = self.state.lock().map_err(|_| { - SidecarError::InvalidState(String::from("loopback TLS pending write lock poisoned")) - })?; - let observed = state.buffer.len().saturating_add(contents.len()); - if observed > LOOPBACK_TLS_PENDING_WRITE_BUFFER_BYTES { - return Err(SidecarError::Execution(format!( - "loopback TLS pending write buffer exceeded: {observed} bytes > {cap} bytes (limit: loopback TLS pending write buffer)", - cap = LOOPBACK_TLS_PENDING_WRITE_BUFFER_BYTES - ))); - } - if !state.warned_near_cap && observed >= LOOPBACK_TLS_PENDING_WRITE_WARNING_BYTES { - state.warned_near_cap = true; - tracing::warn!( - limit = "loopback_tls_pending_write_buffer", - observed_bytes = observed, - cap_bytes = LOOPBACK_TLS_PENDING_WRITE_BUFFER_BYTES, - fill_percent = - (observed as f64 / LOOPBACK_TLS_PENDING_WRITE_BUFFER_BYTES as f64) * 100.0, - wired = "invariant.loopbackTlsPendingWriteBufferBytes", - "loopback TLS pending write buffer is near capacity" - ); - } - state.buffer.extend_from_slice(contents); - Ok(()) - } - - fn defer_shutdown_write(&self) -> Result<(), SidecarError> { - if self.failed.load(Ordering::SeqCst) { - return Err(self.failure_error()); - } - let mut state = self.state.lock().map_err(|_| { - SidecarError::InvalidState(String::from("loopback TLS pending write lock poisoned")) - })?; - state.defer_shutdown_write = true; - Ok(()) - } - - fn take_buffer_for_flush(&self) -> Result>, SidecarError> { - let mut state = self.state.lock().map_err(|_| { - SidecarError::InvalidState(String::from("loopback TLS pending write lock poisoned")) - })?; - if state.buffer.is_empty() { - return Ok(None); - } - state.flushing = true; - Ok(Some(std::mem::take(&mut state.buffer))) - } - - fn finish_flush(&self) { - if let Ok(mut state) = self.state.lock() { - state.flushing = false; - } - } - - fn take_deferred_shutdown_write(&self) -> Result { - let mut state = self.state.lock().map_err(|_| { - SidecarError::InvalidState(String::from("loopback TLS pending write lock poisoned")) - })?; - if state.buffer.is_empty() && !state.flushing && state.defer_shutdown_write { - state.defer_shutdown_write = false; - return Ok(true); - } - Ok(false) - } - - fn interrupt_own_reader(&self) { - crate::state::LoopbackTlsEndpoint::interrupt_reader(&self.pair, self.is_lower_socket); - } -} - -fn parse_tls_client_hello_from_bytes( - buffer: &[u8], -) -> Result, SidecarError> { - if buffer.is_empty() { - return Ok(None); - } - - let mut acceptor = rustls::server::Acceptor::default(); - let mut cursor = Cursor::new(buffer); - acceptor.read_tls(&mut cursor).map_err(sidecar_net_error)?; - let Some(accepted) = acceptor.accept().map_err(|(error, _)| { - SidecarError::Execution(format!("failed to parse TLS client hello: {error}")) - })? - else { - return Ok(None); - }; - let client_hello = accepted.client_hello(); - let alpn_protocols = client_hello.alpn().map(|protocols| { - protocols - .filter_map(|protocol| String::from_utf8(protocol.to_vec()).ok()) - .collect::>() - }); - Ok(Some(JavascriptTlsClientHello { - servername: client_hello.server_name().map(str::to_owned), - alpn_protocols, - })) -} - -fn peek_loopback_tls_client_hello( - vm_id: &str, - socket_id: SocketId, - peer_socket_id: SocketId, -) -> Result, SidecarError> { - let key = loopback_tls_transport_key(vm_id, socket_id, peer_socket_id); - let registry = loopback_tls_transport_registry(); - let pair = registry - .lock() - .map_err(|_| { - SidecarError::InvalidState(String::from( - "loopback TLS transport registry lock poisoned", - )) - })? - .get(&key) - .and_then(Weak::upgrade); - let Some(pair) = pair else { - return Ok(None); - }; - let is_lower_socket = socket_id <= peer_socket_id; - let state = pair.state.lock().map_err(|_| { - SidecarError::InvalidState(String::from("loopback TLS transport lock poisoned")) - })?; - let buffered = if is_lower_socket { - state.higher_to_lower.iter().copied().collect::>() - } else { - state.lower_to_higher.iter().copied().collect::>() - }; - drop(state); - parse_tls_client_hello_from_bytes(&buffered) -} - -fn wait_for_loopback_peer_socket_id( - kernel: &SidecarKernel, - socket_id: SocketId, -) -> Option { - // Keep the total wait budget aligned with the previous ~500ms poll window. - let deadline = Instant::now() + Duration::from_millis(500); - let mut backoff = Duration::from_micros(100); - loop { - if let Some(peer_socket_id) = kernel - .socket_get(socket_id) - .and_then(|record| record.peer_socket_id()) - { - return Some(peer_socket_id); - } - let now = Instant::now(); - if now >= deadline { - break; - } - std::thread::sleep(backoff.min(deadline.saturating_duration_since(now))); - backoff = (backoff * 2).min(Duration::from_millis(1)); - } - None -} - -impl Drop for crate::state::LoopbackTlsEndpoint { - fn drop(&mut self) { - let _ = self.close_endpoint(); - - // Eagerly prune this endpoint's registry entry once we are the last owner - // of the shared transport pair. Without this, the `Weak` entry survives - // until the next `loopback_tls_endpoint()` call runs its lazy `retain()`, - // so dead entries accumulate under intermittent use. We must NOT remove - // the entry while a peer endpoint still shares the pair, otherwise a later - // connection for the same socket pair would fail to find it and build a - // mismatched fresh pair. - let Some(key) = self.registry_key.take() else { - return; - }; - let Ok(mut transports) = loopback_tls_transport_registry().lock() else { - // Lock poisoned: leave the entry for the lazy `retain()` to reclaim. - return; - }; - let should_remove = match transports.get(&key) { - // Only prune when the registered entry still points at *our* pair and - // `self` is its last strong owner. During `Drop` `self.pair` is still - // alive, so a strong count of 1 (after dropping the temporary upgrade) - // means no other endpoint references it. - Some(weak) => match weak.upgrade() { - Some(existing) => { - let same_pair = Arc::ptr_eq(&existing, &self.pair); - drop(existing); - same_pair && Arc::strong_count(&self.pair) <= 1 - } - None => true, - }, - None => false, - }; - if should_remove { - transports.remove(&key); - } - } -} - -impl Read for crate::state::LoopbackTlsEndpoint { - fn read(&mut self, buffer: &mut [u8]) -> std::io::Result { - let mut state = self - .pair - .state - .lock() - .map_err(|_| std::io::Error::other("loopback TLS transport lock poisoned"))?; - - loop { - let (peer_write_closed, peer_closed) = if self.is_lower_socket { - (state.higher_write_closed, state.higher_closed) - } else { - (state.lower_write_closed, state.lower_closed) - }; - - let incoming = if self.is_lower_socket { - &mut state.higher_to_lower - } else { - &mut state.lower_to_higher - }; - - if !incoming.is_empty() { - let count = incoming.len().min(buffer.len()); - let (head, tail) = incoming.as_slices(); - let head_count = head.len().min(count); - buffer[..head_count].copy_from_slice(&head[..head_count]); - if head_count < count { - buffer[head_count..count].copy_from_slice(&tail[..count - head_count]); - } - incoming.drain(..count); - return Ok(count); - } - - if peer_write_closed || peer_closed { - return Ok(0); - } - - let read_interrupted = if self.is_lower_socket { - std::mem::take(&mut state.lower_read_interrupt) - } else { - std::mem::take(&mut state.higher_read_interrupt) - }; - if read_interrupted { - return Err(std::io::Error::new( - std::io::ErrorKind::WouldBlock, - "loopback TLS transport read interrupted", - )); - } - - let (next_state, wait_result) = self - .pair - .ready - .wait_timeout(state, self.poll_timeout) - .map_err(|_| std::io::Error::other("loopback TLS transport lock poisoned"))?; - state = next_state; - if wait_result.timed_out() { - return Err(std::io::Error::new( - std::io::ErrorKind::WouldBlock, - "loopback TLS transport read timed out", - )); - } - } - } -} - -impl Write for crate::state::LoopbackTlsEndpoint { - fn write(&mut self, buffer: &[u8]) -> std::io::Result { - let mut state = self - .pair - .state - .lock() - .map_err(|_| std::io::Error::other("loopback TLS transport lock poisoned"))?; - - let peer_closed = if self.is_lower_socket { - state.higher_closed - } else { - state.lower_closed - }; - let outgoing = if self.is_lower_socket { - &mut state.lower_to_higher - } else { - &mut state.higher_to_lower - }; - if peer_closed { - return Err(std::io::Error::new( - std::io::ErrorKind::BrokenPipe, - "loopback TLS peer is closed", - )); - } - - outgoing.extend(buffer.iter().copied()); - self.pair.ready.notify_all(); - Ok(buffer.len()) - } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } -} - -#[cfg(test)] -mod loopback_tls_registry_tests { - use super::{ - loopback_tls_endpoint, loopback_tls_registry_contains, loopback_tls_transport_key, - }; - - // Each test uses a unique vm_id so the process-global registry stays - // partitioned across concurrently running tests. - - #[test] - fn dropping_endpoint_removes_its_registry_entry() { - let vm_id = "loopback-tls-drop-removes-entry"; - let key = loopback_tls_transport_key(vm_id, 1, 2); - - let endpoint = loopback_tls_endpoint(vm_id, 1, 2).expect("create endpoint"); - assert!( - loopback_tls_registry_contains(&key), - "registry should contain the key while the endpoint is alive" - ); - - drop(endpoint); - assert!( - !loopback_tls_registry_contains(&key), - "registry entry must be pruned in the endpoint's Drop, not left for the lazy retain()" - ); - } - - #[test] - fn registry_entry_survives_until_last_peer_endpoint_drops() { - let vm_id = "loopback-tls-shared-pair"; - let key = loopback_tls_transport_key(vm_id, 3, 4); - - // Both peers of a loopback connection share the same transport pair. - let lower = loopback_tls_endpoint(vm_id, 3, 4).expect("create lower endpoint"); - let higher = loopback_tls_endpoint(vm_id, 4, 3).expect("create higher endpoint"); - assert!(loopback_tls_registry_contains(&key)); - - // Dropping one peer must keep the entry, since the other peer still owns - // the shared pair and a later connection must be able to find it. - drop(lower); - assert!( - loopback_tls_registry_contains(&key), - "entry must survive while a peer endpoint still shares the pair" - ); - - drop(higher); - assert!( - !loopback_tls_registry_contains(&key), - "entry must be pruned once the last peer endpoint drops" - ); - } -} - -// TCP types moved to crate::state - -struct ActiveTcpConnectRequest<'a, B> { - bridge: &'a SharedBridge, - kernel: &'a mut SidecarKernel, - kernel_pid: u32, - vm_id: &'a str, - dns: &'a VmDnsConfig, - host: &'a str, - port: u16, - local_address: Option<&'a str>, - local_port: Option, - local_reservation: Option<(JavascriptSocketFamily, u16)>, - context: &'a JavascriptSocketPathContext, -} - -struct ActiveUdpSendToRequest<'a, B> { - bridge: &'a SharedBridge, - kernel: &'a mut SidecarKernel, - kernel_pid: u32, - vm_id: &'a str, - dns: &'a VmDnsConfig, - host: &'a str, - port: u16, - context: &'a JavascriptSocketPathContext, - contents: &'a [u8], -} - -struct UdpRemoteAddrRequest<'a, B> { - bridge: &'a SharedBridge, - kernel: &'a SidecarKernel, - vm_id: &'a str, - dns: &'a VmDnsConfig, - host: &'a str, - port: u16, - family: JavascriptUdpFamily, - context: &'a JavascriptSocketPathContext, -} - -pub(crate) struct JavascriptSyncRpcServiceRequest<'a, B> { - pub(crate) bridge: &'a SharedBridge, - pub(crate) vm_id: &'a str, - pub(crate) dns: &'a VmDnsConfig, - pub(crate) socket_paths: &'a JavascriptSocketPathContext, - pub(crate) kernel: &'a mut SidecarKernel, - pub(crate) kernel_readiness: KernelSocketReadinessRegistry, - pub(crate) process: &'a mut ActiveProcess, - pub(crate) sync_request: &'a JavascriptSyncRpcRequest, - pub(crate) resource_limits: &'a ResourceLimits, - pub(crate) network_counts: NetworkResourceCounts, -} - -pub(crate) enum JavascriptSyncRpcServiceResponse { - Json(Value), - Raw(Vec), -} - -impl From for JavascriptSyncRpcServiceResponse { - fn from(value: Value) -> Self { - Self::Json(value) - } -} - -impl JavascriptSyncRpcServiceResponse { - fn as_json(&self) -> Option<&Value> { - match self { - Self::Json(value) => Some(value), - Self::Raw(_) => None, - } - } -} - -pub(crate) struct JavascriptNetSyncRpcServiceRequest<'a, B> { - pub(crate) bridge: &'a SharedBridge, - pub(crate) vm_id: &'a str, - pub(crate) dns: &'a VmDnsConfig, - pub(crate) socket_paths: &'a JavascriptSocketPathContext, - pub(crate) kernel: &'a mut SidecarKernel, - pub(crate) kernel_readiness: KernelSocketReadinessRegistry, - pub(crate) process: &'a mut ActiveProcess, - pub(crate) sync_request: &'a JavascriptSyncRpcRequest, - pub(crate) resource_limits: &'a ResourceLimits, - pub(crate) network_counts: NetworkResourceCounts, -} - -struct LoopbackHttpResponseWaitRequest<'a, B> { - bridge: &'a SharedBridge, - vm_id: &'a str, - dns: &'a VmDnsConfig, - socket_paths: &'a JavascriptSocketPathContext, - kernel: &'a mut SidecarKernel, - kernel_readiness: KernelSocketReadinessRegistry, - process: &'a mut ActiveProcess, - resource_limits: &'a ResourceLimits, - request_key: (u64, u64), -} - -pub(crate) struct LoopbackHttpDispatchRequest<'a, B> { - pub(crate) bridge: &'a SharedBridge, - pub(crate) vm_id: &'a str, - pub(crate) dns: &'a VmDnsConfig, - pub(crate) socket_paths: &'a JavascriptSocketPathContext, - pub(crate) kernel: &'a mut SidecarKernel, - pub(crate) kernel_readiness: KernelSocketReadinessRegistry, - pub(crate) process: &'a mut ActiveProcess, - pub(crate) resource_limits: &'a ResourceLimits, - pub(crate) server_id: u64, - pub(crate) request_json: &'a str, -} - -struct JavascriptDgramSyncRpcServiceRequest<'a, B> { - bridge: &'a SharedBridge, - kernel: &'a mut SidecarKernel, - vm_id: &'a str, - dns: &'a VmDnsConfig, - socket_paths: &'a JavascriptSocketPathContext, - process: &'a mut ActiveProcess, - kernel_readiness: KernelSocketReadinessRegistry, - sync_request: &'a JavascriptSyncRpcRequest, - resource_limits: &'a ResourceLimits, - network_counts: NetworkResourceCounts, -} - -struct JavascriptHttp2SyncRpcServiceRequest<'a, B> { - bridge: &'a SharedBridge, - kernel: &'a mut SidecarKernel, - vm_id: &'a str, - dns: &'a VmDnsConfig, - socket_paths: &'a JavascriptSocketPathContext, - process: &'a mut ActiveProcess, - sync_request: &'a JavascriptSyncRpcRequest, - resource_limits: &'a ResourceLimits, - network_counts: NetworkResourceCounts, -} - -impl ActiveTcpSocket { - fn connect(request: ActiveTcpConnectRequest<'_, B>) -> Result - where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, - { - let ActiveTcpConnectRequest { - bridge, - kernel, - kernel_pid, - vm_id, - dns, - host, - port, - local_address, - local_port, - local_reservation, - context, - } = request; - let resolved = resolve_tcp_connect_addr(bridge, kernel, vm_id, dns, host, port, context)?; - if resolved.use_kernel_loopback { - let family = JavascriptSocketFamily::from_ip(resolved.guest_remote_addr.ip()); - let requested_local_port = local_port.unwrap_or(0); - let local_port = if requested_local_port != 0 - && local_reservation == Some((family, requested_local_port)) - { - requested_local_port - } else { - allocate_guest_listen_port( - requested_local_port, - family, - &context.used_tcp_guest_ports, - context.listen_policy, - )? - }; - let local_ip = match (family, local_address) { - (JavascriptSocketFamily::Ipv4, Some("0.0.0.0")) => { - IpAddr::V4(Ipv4Addr::UNSPECIFIED) - } - (JavascriptSocketFamily::Ipv4, Some("127.0.0.1") | Some("localhost") | None) => { - IpAddr::V4(Ipv4Addr::LOCALHOST) - } - (JavascriptSocketFamily::Ipv6, Some("::")) => IpAddr::V6(Ipv6Addr::UNSPECIFIED), - (JavascriptSocketFamily::Ipv6, Some("::1") | Some("localhost") | None) => { - IpAddr::V6(Ipv6Addr::LOCALHOST) - } - (JavascriptSocketFamily::Ipv4, Some(other)) => { - return Err(SidecarError::Execution(format!( - "EACCES: TCP sockets must bind to loopback or unspecified addresses, got {other}" - ))); - } - (JavascriptSocketFamily::Ipv6, Some(other)) => { - return Err(SidecarError::Execution(format!( - "EACCES: TCP sockets must bind to loopback or unspecified addresses, got {other}" - ))); - } - }; - let local_addr = SocketAddr::new(local_ip, local_port); - let spec = match family { - JavascriptSocketFamily::Ipv4 => SocketSpec::tcp(), - JavascriptSocketFamily::Ipv6 => { - SocketSpec::new(SocketDomain::Inet6, SocketType::Stream) - } - }; - let socket_id = kernel - .socket_create(EXECUTION_DRIVER_NAME, kernel_pid, spec) - .map_err(kernel_error)?; - kernel - .socket_bind_inet( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - InetSocketAddress::new(local_ip.to_string(), local_port), - ) - .map_err(kernel_error)?; - kernel - .socket_connect_inet_loopback( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - InetSocketAddress::new( - resolved.guest_remote_addr.ip().to_string(), - resolved.guest_remote_addr.port(), - ), - ) - .map_err(kernel_error)?; - return Ok(Self::from_kernel( - socket_id, - None, - local_addr, - resolved.guest_remote_addr, - )); - } - - let stream = TcpStream::connect_timeout(&resolved.actual_addr, Duration::from_secs(30)) - .map_err(sidecar_net_error)?; - let guest_local_addr = stream.local_addr().map_err(sidecar_net_error)?; - Self::from_stream(stream, None, guest_local_addr, resolved.guest_remote_addr) - } - - fn from_stream( - stream: TcpStream, - listener_id: Option, - guest_local_addr: SocketAddr, - guest_remote_addr: SocketAddr, - ) -> Result { - let read_stream = stream.try_clone().map_err(sidecar_net_error)?; - read_stream - .set_read_timeout(Some(TCP_SOCKET_POLL_TIMEOUT)) - .map_err(sidecar_net_error)?; - let stream = Arc::new(Mutex::new(stream)); - let pending_read_stream = Arc::new(Mutex::new(Some(read_stream))); - let (sender, events) = mpsc::channel(); - let tls_mode = Arc::new(AtomicBool::new(false)); - let tls_stream = Arc::new(Mutex::new(None)); - let tls_state = Arc::new(Mutex::new(None)); - let loopback_tls_pending_write = Arc::new(Mutex::new(None)); - let saw_local_shutdown = Arc::new(AtomicBool::new(false)); - let saw_remote_end = Arc::new(AtomicBool::new(false)); - let close_notified = Arc::new(AtomicBool::new(false)); - - Ok(Self { - stream: Some(stream), - pending_read_stream: Some(pending_read_stream), - events: Some(events), - event_sender: Some(sender), - event_pusher: Arc::new(Mutex::new(None)), - kernel_socket_id: None, - no_delay: false, - keep_alive: false, - keep_alive_initial_delay_secs: None, - guest_local_addr, - guest_remote_addr, - listener_id, - tls_mode, - tls_stream, - tls_state, - loopback_tls_pending_write, - saw_local_shutdown, - saw_remote_end, - close_notified, - }) - } - - fn from_kernel( - socket_id: SocketId, - listener_id: Option, - guest_local_addr: SocketAddr, - guest_remote_addr: SocketAddr, - ) -> Self { - let (sender, events) = mpsc::channel(); - Self { - stream: None, - pending_read_stream: None, - events: Some(events), - event_sender: Some(sender), - event_pusher: Arc::new(Mutex::new(None)), - kernel_socket_id: Some(socket_id), - no_delay: false, - keep_alive: false, - keep_alive_initial_delay_secs: None, - guest_local_addr, - guest_remote_addr, - listener_id, - tls_mode: Arc::new(AtomicBool::new(false)), - tls_stream: Arc::new(Mutex::new(None)), - tls_state: Arc::new(Mutex::new(None)), - loopback_tls_pending_write: Arc::new(Mutex::new(None)), - saw_local_shutdown: Arc::new(AtomicBool::new(false)), - saw_remote_end: Arc::new(AtomicBool::new(false)), - close_notified: Arc::new(AtomicBool::new(false)), - } - } - - fn set_event_pusher(&self, session: Option, socket_id: String) { - let Some(session) = session else { - return; - }; - if let Ok(mut pusher) = self.event_pusher.lock() { - *pusher = Some(JavascriptSocketEventPusher { session, socket_id }); - } - } - - fn poll( - &mut self, - kernel: &mut SidecarKernel, - kernel_pid: u32, - wait: Duration, - trace_enabled: bool, - ) -> Result, SidecarError> { - if self.tls_mode.load(Ordering::SeqCst) { - self.ensure_tcp_reader()?; - return match self - .events - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("TCP socket event channel missing")) - })? - .recv_timeout(wait) - { - Ok(event) => Ok(Some(event)), - Err(RecvTimeoutError::Timeout) => Ok(None), - Err(RecvTimeoutError::Disconnected) => Ok(None), - }; - } - - if let Some(socket_id) = self.kernel_socket_id { - let poll_started = Instant::now(); - let result = kernel - .poll_targets( - EXECUTION_DRIVER_NAME, - kernel_pid, - vec![PollTargetEntry::socket( - socket_id, - POLLIN | POLLHUP | POLLERR, - )], - i32::try_from(wait.as_millis()).unwrap_or(i32::MAX), - ) - .map_err(kernel_error)?; - let poll_elapsed = poll_started.elapsed(); - let revents = result - .targets - .first() - .map(|entry| entry.revents) - .unwrap_or_else(PollEvents::empty); - record_net_tcp_kernel_poll(trace_enabled, wait, poll_elapsed, revents); - if revents.is_empty() { - return Ok(None); - } - if revents.intersects(POLLIN) { - let read_started = Instant::now(); - let read_result = - kernel.socket_read(EXECUTION_DRIVER_NAME, kernel_pid, socket_id, 64 * 1024); - if trace_enabled { - NET_TCP_TRACE_COUNTERS.socket_read_kernel_us.fetch_add( - duration_micros_u64(read_started.elapsed()), - Ordering::Relaxed, - ); - } - return match read_result { - Ok(Some(bytes)) if !bytes.is_empty() => { - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .socket_read_data_events - .fetch_add(1, Ordering::Relaxed); - NET_TCP_TRACE_COUNTERS.socket_read_bytes.fetch_add( - u64::try_from(bytes.len()).unwrap_or(u64::MAX), - Ordering::Relaxed, - ); - } - Ok(Some(JavascriptTcpSocketEvent::Data(bytes))) - } - Ok(Some(_)) => { - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .socket_read_data_events - .fetch_add(1, Ordering::Relaxed); - } - Ok(Some(JavascriptTcpSocketEvent::Data(Vec::new()))) - } - Ok(None) => { - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .socket_read_end_events - .fetch_add(1, Ordering::Relaxed); - } - self.saw_remote_end.store(true, Ordering::SeqCst); - Ok(Some(JavascriptTcpSocketEvent::End)) - } - Err(error) if error.code() == "EAGAIN" => { - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .socket_read_eagain - .fetch_add(1, Ordering::Relaxed); - } - Ok(None) - } - Err(error) => { - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .socket_read_errors - .fetch_add(1, Ordering::Relaxed); - } - Ok(Some(JavascriptTcpSocketEvent::Error { - code: Some(error.code().to_string()), - message: error.to_string(), - })) - } - }; - } - if revents.intersects(POLLHUP) { - self.saw_remote_end.store(true, Ordering::SeqCst); - return Ok(Some(JavascriptTcpSocketEvent::End)); - } - if revents.intersects(POLLERR) { - return Ok(Some(JavascriptTcpSocketEvent::Error { - code: Some(String::from("EPIPE")), - message: String::from("kernel TCP socket reported POLLERR"), - })); - } - return Ok(None); - } - - self.ensure_tcp_reader()?; - match self - .events - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("TCP socket event channel missing")) - })? - .recv_timeout(wait) - { - Ok(event) => Ok(Some(event)), - Err(RecvTimeoutError::Timeout) => Ok(None), - Err(RecvTimeoutError::Disconnected) => Ok(None), - } - } - - fn ensure_tcp_reader(&self) -> Result<(), SidecarError> { - if self.kernel_socket_id.is_some() { - return Ok(()); - } - if self.tls_mode.load(Ordering::SeqCst) { - return Ok(()); - } - let read_stream = self - .pending_read_stream - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("TCP socket reader handle missing")) - })? - .lock() - .map_err(|_| { - SidecarError::InvalidState(String::from("TCP socket reader lock poisoned")) - })? - .take(); - if let Some(read_stream) = read_stream { - spawn_tcp_socket_reader( - read_stream, - self.event_sender - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("TCP socket event sender missing")) - })? - .clone(), - Arc::clone(&self.event_pusher), - Arc::clone(&self.tls_mode), - Arc::clone(&self.saw_local_shutdown), - Arc::clone(&self.saw_remote_end), - Arc::clone(&self.close_notified), - ); - } - Ok(()) - } - - fn socket_info(&self) -> Value { - tcp_socket_info_value(&self.guest_local_addr, &self.guest_remote_addr) - } - - fn set_no_delay(&mut self, enable: bool) -> Result<(), SidecarError> { - self.no_delay = enable; - if self.kernel_socket_id.is_some() { - return Ok(()); - } - let stream = self - .stream - .as_ref() - .ok_or_else(|| SidecarError::InvalidState(String::from("TCP socket stream missing")))? - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TCP socket lock poisoned")))?; - stream.set_nodelay(enable).map_err(sidecar_net_error) - } - - fn set_keep_alive( - &mut self, - enable: bool, - initial_delay_secs: Option, - ) -> Result<(), SidecarError> { - self.keep_alive = enable; - self.keep_alive_initial_delay_secs = initial_delay_secs; - if self.kernel_socket_id.is_some() { - return Ok(()); - } - let stream = self - .stream - .as_ref() - .ok_or_else(|| SidecarError::InvalidState(String::from("TCP socket stream missing")))? - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TCP socket lock poisoned")))?; - let socket = SockRef::from(&*stream); - socket.set_keepalive(enable).map_err(sidecar_net_error)?; - if enable { - if let Some(delay_secs) = initial_delay_secs.filter(|delay_secs| *delay_secs > 0) { - socket - .set_tcp_keepalive( - &TcpKeepalive::new().with_time(Duration::from_secs(delay_secs)), - ) - .map_err(sidecar_net_error)?; - } - } - Ok(()) - } - - fn upgrade_tls( - &self, - vm_id: &str, - kernel: &SidecarKernel, - options: JavascriptTlsBridgeOptions, - ) -> Result<(), SidecarError> { - if self.tls_mode.load(Ordering::SeqCst) { - return Ok(()); - } - - let client_hello = if options.is_server { - self.peek_tls_client_hello(vm_id, kernel)? - } else { - None - }; - - let (tls_stream, loopback_pending_write) = if let Some(socket_id) = self.kernel_socket_id { - let peer_socket_id = wait_for_loopback_peer_socket_id(kernel, socket_id) - .ok_or_else(|| { - SidecarError::Execution(format!( - "ERR_NOT_IMPLEMENTED: kernel-backed loopback socket {socket_id} has no peer for TLS upgrade" - )) - })?; - let endpoint = loopback_tls_endpoint(vm_id, socket_id, peer_socket_id)?; - let pending_write = LoopbackTlsPendingWriteHandle::new(&endpoint); - let tls_stream = if options.is_server { - ActiveTlsStream::LoopbackServer(build_server_loopback_tls_stream( - endpoint, &options, - )?) - } else { - ActiveTlsStream::LoopbackClient(build_client_loopback_tls_stream( - endpoint, &options, - )?) - }; - (tls_stream, Some(pending_write)) - } else { - self.pending_read_stream - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("TCP socket reader handle missing")) - })? - .lock() - .map_err(|_| { - SidecarError::InvalidState(String::from("TCP socket reader lock poisoned")) - })? - .take(); - let stream = self - .stream - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("TCP socket stream missing")) - })? - .lock() - .map_err(|_| { - SidecarError::InvalidState(String::from("TCP socket lock poisoned")) - })?; - let cloned = stream.try_clone().map_err(sidecar_net_error)?; - drop(stream); - - if options.is_server { - ( - ActiveTlsStream::Server(build_server_tls_stream(cloned, &options)?), - None, - ) - } else { - ( - ActiveTlsStream::Client(build_client_tls_stream(cloned, &options)?), - None, - ) - } - }; - - let tls_state = ActiveTlsState { - client_hello, - local_certificates: tls_local_certificates(&options)?, - session_reused: false, - }; - - self.tls_mode.store(true, Ordering::SeqCst); - { - let mut state = self - .tls_state - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TLS state lock poisoned")))?; - *state = Some(tls_state); - } - { - let mut stream = self.tls_stream.lock().map_err(|_| { - SidecarError::InvalidState(String::from("TLS stream lock poisoned")) - })?; - *stream = Some(tls_stream); - } - { - let mut pending = self.loopback_tls_pending_write.lock().map_err(|_| { - SidecarError::InvalidState(String::from( - "loopback TLS pending write handle lock poisoned", - )) - })?; - *pending = loopback_pending_write.clone(); - } - - spawn_tls_socket_reader( - Arc::clone(&self.tls_stream), - loopback_pending_write, - self.event_sender - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("TCP socket event sender missing")) - })? - .clone(), - Arc::clone(&self.event_pusher), - Arc::clone(&self.saw_local_shutdown), - Arc::clone(&self.saw_remote_end), - Arc::clone(&self.close_notified), - ); - Ok(()) - } - - fn peek_tls_client_hello( - &self, - vm_id: &str, - kernel: &SidecarKernel, - ) -> Result, SidecarError> { - if let Some(socket_id) = self.kernel_socket_id { - let Some(peer_socket_id) = kernel - .socket_get(socket_id) - .and_then(|record| record.peer_socket_id()) - else { - return Ok(None); - }; - return peek_loopback_tls_client_hello(vm_id, socket_id, peer_socket_id); - } - - let stream = self - .stream - .as_ref() - .ok_or_else(|| SidecarError::InvalidState(String::from("TCP socket stream missing")))? - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TCP socket lock poisoned")))?; - let mut buffer = vec![0_u8; 16 * 1024]; - let bytes = match stream.peek(&mut buffer) { - Ok(0) => return Ok(None), - Ok(bytes) => bytes, - Err(error) - if matches!( - error.kind(), - std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut - ) => - { - return Ok(None); - } - Err(error) => return Err(sidecar_net_error(error)), - }; - parse_tls_client_hello_from_bytes(&buffer[..bytes]) - } - - fn tls_client_hello_json( - &self, - vm_id: &str, - kernel: &SidecarKernel, - ) -> Result { - if let Some(client_hello) = self - .tls_state - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TLS state lock poisoned")))? - .as_ref() - .and_then(|state| state.client_hello.clone()) - { - return javascript_net_json_string( - serde_json::to_value(client_hello).map_err(|error| { - SidecarError::InvalidState(format!( - "failed to serialize TLS client hello: {error}" - )) - })?, - "net.socket_get_tls_client_hello", - ); - } - - javascript_net_json_string( - serde_json::to_value( - self.peek_tls_client_hello(vm_id, kernel)? - .unwrap_or_default(), - ) - .map_err(|error| { - SidecarError::InvalidState(format!("failed to serialize TLS client hello: {error}")) - })?, - "net.socket_get_tls_client_hello", - ) - } - - fn tls_query(&self, query: &str, detailed: bool) -> Result { - let state = self - .tls_state - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TLS state lock poisoned")))? - .clone(); - let mut tls_stream = self - .tls_stream - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TLS stream lock poisoned")))?; - let Some(stream) = tls_stream.as_mut() else { - return javascript_net_json_string( - tls_bridge_undefined_value(), - "net.socket_tls_query", - ); - }; - - let payload = match query { - "getSession" => tls_bridge_undefined_value(), - "isSessionReused" => Value::Bool( - state - .as_ref() - .is_some_and(|tls_state| tls_state.session_reused), - ), - "getPeerCertificate" => { - let certificate = stream - .peer_certificates() - .and_then(|certificates| certificates.first()) - .map(|certificate| { - tls_certificate_bridge_value(certificate.as_ref(), detailed) - }); - certificate.unwrap_or_else(tls_bridge_undefined_value) - } - "getCertificate" => state - .as_ref() - .and_then(|tls_state| tls_state.local_certificates.first()) - .map(|certificate| tls_certificate_bridge_value(certificate, detailed)) - .unwrap_or_else(tls_bridge_undefined_value), - "getProtocol" => stream - .protocol_version() - .map(tls_protocol_name) - .map(Value::String) - .unwrap_or(Value::Null), - "getCipher" => stream - .negotiated_cipher_suite() - .map(tls_cipher_bridge_value) - .unwrap_or_else(tls_bridge_undefined_value), - other => { - return Err(SidecarError::InvalidState(format!( - "unsupported TLS query {other}" - ))); - } - }; - javascript_net_json_string(payload, "net.socket_tls_query") - } - - fn write_all( - &self, - kernel: &mut SidecarKernel, - kernel_pid: u32, - contents: &[u8], - ) -> Result { - if self.tls_mode.load(Ordering::SeqCst) { - let loopback_pending_write = self - .loopback_tls_pending_write - .lock() - .map_err(|_| { - SidecarError::InvalidState(String::from( - "loopback TLS pending write handle lock poisoned", - )) - })? - .clone(); - if let Some(pending_write) = loopback_pending_write.as_ref() { - if pending_write.should_buffer_write()? { - pending_write.append_write(contents)?; - return Ok(contents.len()); - } - pending_write.interrupt_own_reader(); - } - let mut tls_stream = self.tls_stream.lock().map_err(|_| { - SidecarError::InvalidState(String::from("TLS stream lock poisoned")) - })?; - let stream = tls_stream.as_mut().ok_or_else(|| { - SidecarError::InvalidState(String::from("TLS stream missing for upgraded socket")) - })?; - stream.write_all(contents)?; - return Ok(contents.len()); - } - if let Some(socket_id) = self.kernel_socket_id { - return kernel - .socket_write(EXECUTION_DRIVER_NAME, kernel_pid, socket_id, contents) - .map_err(kernel_error); - } - - let mut stream = self - .stream - .as_ref() - .ok_or_else(|| SidecarError::InvalidState(String::from("TCP socket stream missing")))? - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TCP socket lock poisoned")))?; - stream.write_all(contents).map_err(sidecar_net_error)?; - Ok(contents.len()) - } - - fn shutdown_write( - &self, - kernel: &mut SidecarKernel, - kernel_pid: u32, - ) -> Result<(), SidecarError> { - if self.tls_mode.load(Ordering::SeqCst) { - let loopback_pending_write = self - .loopback_tls_pending_write - .lock() - .map_err(|_| { - SidecarError::InvalidState(String::from( - "loopback TLS pending write handle lock poisoned", - )) - })? - .clone(); - if let Some(pending_write) = loopback_pending_write.as_ref() { - if pending_write.should_buffer_write()? { - pending_write.defer_shutdown_write()?; - self.saw_local_shutdown.store(true, Ordering::SeqCst); - return Ok(()); - } - pending_write.interrupt_own_reader(); - } - if let Some(stream) = self - .tls_stream - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TLS stream lock poisoned")))? - .as_mut() - { - let _ = stream.send_close_notify(); - let _ = stream.shutdown_write(); - } - if self.kernel_socket_id.is_some() { - self.saw_local_shutdown.store(true, Ordering::SeqCst); - return Ok(()); - } - } - if let Some(socket_id) = self.kernel_socket_id { - self.saw_local_shutdown.store(true, Ordering::SeqCst); - match kernel.socket_shutdown( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - KernelSocketShutdown::Write, - ) { - Ok(()) => {} - Err(error) if error.code() == "ENOENT" => {} - Err(error) => return Err(kernel_error(error)), - } - return Ok(()); - } - let stream = self - .stream - .as_ref() - .ok_or_else(|| SidecarError::InvalidState(String::from("TCP socket stream missing")))? - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TCP socket lock poisoned")))?; - self.saw_local_shutdown.store(true, Ordering::SeqCst); - match stream.shutdown(Shutdown::Write) { - Ok(()) => {} - Err(error) if error.kind() == std::io::ErrorKind::NotConnected => {} - Err(error) => return Err(sidecar_net_error(error)), - } - if self.saw_remote_end.load(Ordering::SeqCst) - && !self.close_notified.swap(true, Ordering::SeqCst) - { - let _ = self - .event_sender - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("TCP socket event sender missing")) - })? - .send(JavascriptTcpSocketEvent::Close { had_error: false }); - } - Ok(()) - } - - fn close(&self, kernel: &mut SidecarKernel, kernel_pid: u32) -> Result<(), SidecarError> { - if self.tls_mode.load(Ordering::SeqCst) { - if let Some(pending_write) = self - .loopback_tls_pending_write - .lock() - .map_err(|_| { - SidecarError::InvalidState(String::from( - "loopback TLS pending write handle lock poisoned", - )) - })? - .take() - { - pending_write.clear_for_close(); - pending_write.interrupt_own_reader(); - } - if let Some(stream) = self - .tls_stream - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TLS stream lock poisoned")))? - .as_mut() - { - let _ = stream.send_close_notify(); - let _ = stream.close(); - } - } - if let Some(socket_id) = self.kernel_socket_id { - return close_kernel_socket_idempotent(kernel, kernel_pid, socket_id); - } - let stream = self - .stream - .as_ref() - .ok_or_else(|| SidecarError::InvalidState(String::from("TCP socket stream missing")))? - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("TCP socket lock poisoned")))?; - stream.shutdown(Shutdown::Both).map_err(sidecar_net_error) - } -} - -fn close_kernel_socket_idempotent( - kernel: &mut SidecarKernel, - kernel_pid: u32, - socket_id: SocketId, -) -> Result<(), SidecarError> { - match kernel.socket_close(EXECUTION_DRIVER_NAME, kernel_pid, socket_id) { - Ok(()) => Ok(()), - Err(error) if error.code() == "ENOENT" => Ok(()), - Err(error) => Err(kernel_error(error)), - } -} - -fn register_kernel_readiness_target( - registry: &KernelSocketReadinessRegistry, - kernel_socket_id: Option, - session: Option, - target_id: String, - event: KernelSocketReadinessEvent, -) { - let (Some(kernel_socket_id), Some(session)) = (kernel_socket_id, session) else { - return; - }; - if let Ok(mut targets) = registry.lock() { - targets.insert( - kernel_socket_id, - KernelSocketReadinessTarget { - session, - target_id, - event, - }, - ); - } -} - -fn unregister_kernel_readiness_target( - registry: &KernelSocketReadinessRegistry, - kernel_socket_id: Option, -) { - let Some(kernel_socket_id) = kernel_socket_id else { - return; - }; - if let Ok(mut targets) = registry.lock() { - targets.remove(&kernel_socket_id); - } -} - -fn release_tcp_socket_handle( - process: &mut ActiveProcess, - socket_id: &str, - socket: ActiveTcpSocket, - kernel: &mut SidecarKernel, - kernel_readiness: &KernelSocketReadinessRegistry, -) { - unregister_kernel_readiness_target(kernel_readiness, socket.kernel_socket_id); - if let Some(listener_id) = socket.listener_id.as_deref() { - if let Some(listener) = process.tcp_listeners.get_mut(listener_id) { - listener.release_connection(socket_id); - } - } - let _ = socket.close(kernel, process.kernel_pid); -} - -fn release_unix_socket_handle( - process: &mut ActiveProcess, - socket_id: &str, - socket: ActiveUnixSocket, -) { - if let Some(listener_id) = socket.listener_id.as_deref() { - if let Some(listener) = process.unix_listeners.get_mut(listener_id) { - listener.release_connection(socket_id); - } - } - let _ = socket.close(); -} - -impl ActiveTlsStream { - fn is_loopback(&self) -> bool { - matches!(self, Self::LoopbackClient(_) | Self::LoopbackServer(_)) - } - - fn is_handshaking(&self) -> bool { - match self { - Self::Client(stream) => stream.conn.is_handshaking(), - Self::Server(stream) => stream.conn.is_handshaking(), - Self::LoopbackClient(stream) => stream.conn.is_handshaking(), - Self::LoopbackServer(stream) => stream.conn.is_handshaking(), - } - } - - fn set_loopback_poll_timeout(&mut self, timeout: Duration) { - match self { - Self::LoopbackClient(stream) => stream.sock.set_poll_timeout(timeout), - Self::LoopbackServer(stream) => stream.sock.set_poll_timeout(timeout), - Self::Client(_) | Self::Server(_) => {} - } - } - - fn write_all(&mut self, contents: &[u8]) -> Result<(), SidecarError> { - match self { - Self::Client(stream) => { - stream.write_all(contents).map_err(sidecar_net_error)?; - stream.flush().map_err(sidecar_net_error) - } - Self::Server(stream) => { - stream.write_all(contents).map_err(sidecar_net_error)?; - stream.flush().map_err(sidecar_net_error) - } - Self::LoopbackClient(stream) => { - stream.write_all(contents).map_err(sidecar_net_error)?; - stream.flush().map_err(sidecar_net_error) - } - Self::LoopbackServer(stream) => { - stream.write_all(contents).map_err(sidecar_net_error)?; - stream.flush().map_err(sidecar_net_error) - } - } - } - - fn read(&mut self, buffer: &mut [u8]) -> std::io::Result { - match self { - Self::Client(stream) => stream.read(buffer), - Self::Server(stream) => stream.read(buffer), - Self::LoopbackClient(stream) => stream.read(buffer), - Self::LoopbackServer(stream) => stream.read(buffer), - } - } - - fn send_close_notify(&mut self) -> Result<(), SidecarError> { - match self { - Self::Client(stream) => { - stream.conn.send_close_notify(); - let _ = stream.conn.complete_io(&mut stream.sock); - } - Self::Server(stream) => { - stream.conn.send_close_notify(); - let _ = stream.conn.complete_io(&mut stream.sock); - } - Self::LoopbackClient(stream) => { - stream.conn.send_close_notify(); - let _ = stream.conn.complete_io(&mut stream.sock); - } - Self::LoopbackServer(stream) => { - stream.conn.send_close_notify(); - let _ = stream.conn.complete_io(&mut stream.sock); - } - } - Ok(()) - } - - fn shutdown_write(&mut self) -> Result<(), SidecarError> { - match self { - Self::Client(stream) => stream - .sock - .shutdown(Shutdown::Write) - .map_err(sidecar_net_error), - Self::Server(stream) => stream - .sock - .shutdown(Shutdown::Write) - .map_err(sidecar_net_error), - Self::LoopbackClient(stream) => stream.sock.shutdown_write(), - Self::LoopbackServer(stream) => stream.sock.shutdown_write(), - } - } - - fn close(&mut self) -> Result<(), SidecarError> { - match self { - Self::Client(stream) => stream - .sock - .shutdown(Shutdown::Both) - .map_err(sidecar_net_error), - Self::Server(stream) => stream - .sock - .shutdown(Shutdown::Both) - .map_err(sidecar_net_error), - Self::LoopbackClient(stream) => stream.sock.close_endpoint(), - Self::LoopbackServer(stream) => stream.sock.close_endpoint(), - } - } - - fn peer_certificates(&self) -> Option<&[CertificateDer<'static>]> { - match self { - Self::Client(stream) => stream.conn.peer_certificates(), - Self::Server(stream) => stream.conn.peer_certificates(), - Self::LoopbackClient(stream) => stream.conn.peer_certificates(), - Self::LoopbackServer(stream) => stream.conn.peer_certificates(), - } - } - - fn negotiated_cipher_suite(&self) -> Option { - match self { - Self::Client(stream) => stream.conn.negotiated_cipher_suite(), - Self::Server(stream) => stream.conn.negotiated_cipher_suite(), - Self::LoopbackClient(stream) => stream.conn.negotiated_cipher_suite(), - Self::LoopbackServer(stream) => stream.conn.negotiated_cipher_suite(), - } - } - - fn protocol_version(&self) -> Option { - match self { - Self::Client(stream) => stream.conn.protocol_version(), - Self::Server(stream) => stream.conn.protocol_version(), - Self::LoopbackClient(stream) => stream.conn.protocol_version(), - Self::LoopbackServer(stream) => stream.conn.protocol_version(), - } - } -} - -// ActiveTcpListener moved to crate::state - -// Unix socket types moved to crate::state - -impl ActiveUnixSocket { - fn connect(host_path: &Path, guest_path: &str) -> Result { - let stream = UnixStream::connect(host_path).map_err(sidecar_net_error)?; - Self::from_stream(stream, None, None, Some(guest_path.to_owned())) - } - - fn from_stream( - stream: UnixStream, - listener_id: Option, - local_path: Option, - remote_path: Option, - ) -> Result { - let read_stream = stream.try_clone().map_err(sidecar_net_error)?; - let stream = Arc::new(Mutex::new(stream)); - let (sender, events) = mpsc::channel(); - let event_pusher = Arc::new(Mutex::new(None)); - let saw_local_shutdown = Arc::new(AtomicBool::new(false)); - let saw_remote_end = Arc::new(AtomicBool::new(false)); - let close_notified = Arc::new(AtomicBool::new(false)); - spawn_unix_socket_reader( - read_stream, - sender.clone(), - Arc::clone(&event_pusher), - Arc::clone(&saw_local_shutdown), - Arc::clone(&saw_remote_end), - Arc::clone(&close_notified), - ); - - Ok(Self { - stream, - events, - event_sender: sender, - event_pusher, - listener_id, - local_path, - remote_path, - saw_local_shutdown, - saw_remote_end, - close_notified, - }) - } - - fn set_event_pusher(&self, session: Option, socket_id: String) { - let Some(session) = session else { - return; - }; - if let Ok(mut pusher) = self.event_pusher.lock() { - *pusher = Some(JavascriptSocketEventPusher { session, socket_id }); - } - } - - fn poll(&mut self, wait: Duration) -> Result, SidecarError> { - match self.events.recv_timeout(wait) { - Ok(event) => Ok(Some(event)), - Err(RecvTimeoutError::Timeout) => Ok(None), - Err(RecvTimeoutError::Disconnected) => Ok(None), - } - } - - fn socket_info(&self) -> Value { - unix_socket_info_value(self.local_path.as_deref(), self.remote_path.as_deref()) - } - - fn write_all(&self, contents: &[u8]) -> Result { - let mut stream = self - .stream - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("Unix socket lock poisoned")))?; - stream.write_all(contents).map_err(sidecar_net_error)?; - Ok(contents.len()) - } - - fn shutdown_write(&self) -> Result<(), SidecarError> { - let stream = self - .stream - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("Unix socket lock poisoned")))?; - self.saw_local_shutdown.store(true, Ordering::SeqCst); - stream - .shutdown(Shutdown::Write) - .map_err(sidecar_net_error)?; - if self.saw_remote_end.load(Ordering::SeqCst) - && !self.close_notified.swap(true, Ordering::SeqCst) - { - let _ = self - .event_sender - .send(JavascriptTcpSocketEvent::Close { had_error: false }); - } - Ok(()) - } - - fn close(&self) -> Result<(), SidecarError> { - let stream = self - .stream - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("Unix socket lock poisoned")))?; - stream.shutdown(Shutdown::Both).map_err(sidecar_net_error) - } -} - -// ActiveUnixListener moved to crate::state - -impl ActiveUnixListener { - fn bind( - host_path: &Path, - guest_path: &str, - backlog: Option, - ) -> Result { - if let Some(parent) = host_path.parent() { - fs::create_dir_all(parent).map_err(sidecar_net_error)?; - } - let listener = UnixListener::bind(host_path).map_err(sidecar_net_error)?; - listener.set_nonblocking(true).map_err(sidecar_net_error)?; - Ok(Self { - listener, - path: guest_path.to_owned(), - backlog: usize::try_from(backlog.unwrap_or(DEFAULT_JAVASCRIPT_NET_BACKLOG)) - .expect("default backlog fits within usize"), - active_connection_ids: BTreeSet::new(), - }) - } - - fn path(&self) -> &str { - &self.path - } - - fn poll( - &mut self, - wait: Duration, - ) -> Result, SidecarError> { - let deadline = Instant::now() + wait; - loop { - match self.listener.accept() { - Ok((stream, remote_addr)) => { - if self.active_connection_ids.len() >= self.backlog { - let _ = stream.shutdown(Shutdown::Both); - if wait.is_zero() || Instant::now() >= deadline { - return Ok(None); - } - continue; - } - - let local_path = Some(self.path.clone()); - let remote_path = unix_socket_path(&remote_addr); - return Ok(Some(JavascriptUnixListenerEvent::Connection( - PendingUnixSocket { - stream, - local_path, - remote_path, - }, - ))); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - if wait.is_zero() || Instant::now() >= deadline { - return Ok(None); - } - if !wait_fd_readable_until(self.listener.as_fd(), deadline) { - return Ok(None); - } - } - Err(error) => { - return Ok(Some(JavascriptUnixListenerEvent::Error { - code: io_error_code(&error), - message: error.to_string(), - })); - } - } - } - } - - fn close(&self) -> Result<(), SidecarError> { - Ok(()) - } - - fn active_connection_count(&self) -> usize { - self.active_connection_ids.len() - } - - fn register_connection(&mut self, socket_id: &str) { - self.active_connection_ids.insert(socket_id.to_string()); - } - - fn release_connection(&mut self, socket_id: &str) { - self.active_connection_ids.remove(socket_id); - } -} - -impl ActiveTcpListener { - fn bind( - bind_host: &str, - guest_host: &str, - guest_port: u16, - backlog: Option, - ) -> Result { - let bind_addr = resolve_tcp_bind_addr(bind_host, 0)?; - let guest_addr = resolve_tcp_bind_addr(guest_host, guest_port)?; - let listener = TcpListener::bind(bind_addr).map_err(sidecar_net_error)?; - listener.set_nonblocking(true).map_err(sidecar_net_error)?; - let local_addr = listener.local_addr().map_err(sidecar_net_error)?; - Ok(Self { - listener: Some(listener), - kernel_socket_id: None, - local_addr: Some(local_addr), - guest_local_addr: guest_addr, - backlog: usize::try_from(backlog.unwrap_or(DEFAULT_JAVASCRIPT_NET_BACKLOG)) - .expect("default backlog fits within usize"), - active_connection_ids: BTreeSet::new(), - }) - } - - fn bind_kernel( - kernel: &mut SidecarKernel, - kernel_pid: u32, - guest_host: &str, - guest_port: u16, - backlog: Option, - ) -> Result { - let guest_addr = resolve_tcp_bind_addr(guest_host, guest_port)?; - let spec = match guest_addr { - SocketAddr::V4(_) => SocketSpec::tcp(), - SocketAddr::V6(_) => SocketSpec::new(SocketDomain::Inet6, SocketType::Stream), - }; - let socket_id = kernel - .socket_create(EXECUTION_DRIVER_NAME, kernel_pid, spec) - .map_err(kernel_error)?; - kernel - .socket_bind_inet( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - InetSocketAddress::new(guest_addr.ip().to_string(), guest_addr.port()), - ) - .map_err(kernel_error)?; - kernel - .socket_listen( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - usize::try_from(backlog.unwrap_or(DEFAULT_JAVASCRIPT_NET_BACKLOG)) - .expect("default backlog fits within usize"), - ) - .map_err(kernel_error)?; - Ok(Self { - listener: None, - kernel_socket_id: Some(socket_id), - local_addr: Some(guest_addr), - guest_local_addr: guest_addr, - backlog: usize::try_from(backlog.unwrap_or(DEFAULT_JAVASCRIPT_NET_BACKLOG)) - .expect("default backlog fits within usize"), - active_connection_ids: BTreeSet::new(), - }) - } - - pub(crate) fn local_addr(&self) -> SocketAddr { - self.local_addr.unwrap_or(self.guest_local_addr) - } - - fn guest_local_addr(&self) -> SocketAddr { - self.guest_local_addr - } - - fn poll( - &mut self, - kernel: &mut SidecarKernel, - kernel_pid: u32, - wait: Duration, - trace_enabled: bool, - ) -> Result, SidecarError> { - if let Some(socket_id) = self.kernel_socket_id { - let poll_started = Instant::now(); - let result = kernel - .poll_targets( - EXECUTION_DRIVER_NAME, - kernel_pid, - vec![PollTargetEntry::socket(socket_id, POLLIN)], - i32::try_from(wait.as_millis()).unwrap_or(i32::MAX), - ) - .map_err(kernel_error)?; - let poll_elapsed = poll_started.elapsed(); - let revents = result - .targets - .first() - .map(|entry| entry.revents) - .unwrap_or_else(PollEvents::empty); - record_net_tcp_kernel_poll(trace_enabled, wait, poll_elapsed, revents); - if revents.is_empty() { - return Ok(None); - } - let accepted_socket_id = - match kernel.socket_accept(EXECUTION_DRIVER_NAME, kernel_pid, socket_id) { - Ok(accepted_socket_id) => accepted_socket_id, - Err(error) if error.code() == "EAGAIN" => { - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .server_accept_eagain - .fetch_add(1, Ordering::Relaxed); - } - return Ok(None); - } - Err(error) => { - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .server_accept_errors - .fetch_add(1, Ordering::Relaxed); - } - return Ok(Some(JavascriptTcpListenerEvent::Error { - code: Some(error.code().to_string()), - message: error.to_string(), - })); - } - }; - let accepted = kernel.socket_get(accepted_socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!( - "accepted kernel TCP socket {accepted_socket_id} is missing" - )) - })?; - let local_addr = accepted.local_address().ok_or_else(|| { - SidecarError::InvalidState(format!( - "accepted kernel TCP socket {accepted_socket_id} missing local address" - )) - })?; - let remote_addr = accepted.peer_address().ok_or_else(|| { - SidecarError::InvalidState(format!( - "accepted kernel TCP socket {accepted_socket_id} missing peer address" - )) - })?; - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .server_accept_connections - .fetch_add(1, Ordering::Relaxed); - } - return Ok(Some(JavascriptTcpListenerEvent::Connection( - PendingTcpSocket { - stream: None, - kernel_socket_id: Some(accepted_socket_id), - preallocated: true, - guest_local_addr: resolve_tcp_bind_addr(local_addr.host(), local_addr.port())?, - guest_remote_addr: resolve_tcp_bind_addr( - remote_addr.host(), - remote_addr.port(), - )?, - }, - ))); - } - - let deadline = Instant::now() + wait; - loop { - match self - .listener - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("TCP listener socket missing")) - })? - .accept() - { - Ok((stream, remote_addr)) => { - if self.active_connection_ids.len() >= self.backlog { - let _ = stream.shutdown(Shutdown::Both); - if wait.is_zero() || Instant::now() >= deadline { - return Ok(None); - } - continue; - } - return Ok(Some(JavascriptTcpListenerEvent::Connection( - PendingTcpSocket { - stream: Some(stream), - kernel_socket_id: None, - preallocated: false, - guest_local_addr: self.guest_local_addr, - guest_remote_addr: SocketAddr::new( - remote_addr.ip(), - remote_addr.port(), - ), - }, - ))); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - if wait.is_zero() || Instant::now() >= deadline { - return Ok(None); - } - if !wait_fd_readable_until( - self.listener - .as_ref() - .expect("TCP listener checked before accept") - .as_fd(), - deadline, - ) { - return Ok(None); - } - } - Err(error) => { - return Ok(Some(JavascriptTcpListenerEvent::Error { - code: io_error_code(&error), - message: error.to_string(), - })); - } - } - } - } - - fn close(&self, kernel: &mut SidecarKernel, kernel_pid: u32) -> Result<(), SidecarError> { - if let Some(socket_id) = self.kernel_socket_id { - close_kernel_socket_idempotent(kernel, kernel_pid, socket_id)?; - } - Ok(()) - } - - fn active_connection_count(&self) -> usize { - self.active_connection_ids.len() - } - - fn register_connection(&mut self, socket_id: &str) { - self.active_connection_ids.insert(socket_id.to_string()); - } - - fn release_connection(&mut self, socket_id: &str) { - self.active_connection_ids.remove(socket_id); - } -} - -// UDP types moved to crate::state - -impl ActiveUdpSocket { - fn new( - kernel: &mut SidecarKernel, - kernel_pid: u32, - family: JavascriptUdpFamily, - ) -> Result { - let spec = match family { - JavascriptUdpFamily::Ipv4 => SocketSpec::udp(), - JavascriptUdpFamily::Ipv6 => SocketSpec::new(SocketDomain::Inet6, SocketType::Datagram), - }; - let socket_id = kernel - .socket_create(EXECUTION_DRIVER_NAME, kernel_pid, spec) - .map_err(kernel_error)?; - Ok(Self { - family, - socket: None, - kernel_socket_id: Some(socket_id), - guest_local_addr: None, - recv_buffer_size: 0, - send_buffer_size: 0, - }) - } - - fn local_addr(&self) -> Option { - self.guest_local_addr - } - - fn socket(&self) -> Result<&UdpSocket, SidecarError> { - self.socket - .as_ref() - .ok_or_else(|| SidecarError::Execution(String::from("EBADF: bad file descriptor"))) - } - - fn bind( - &mut self, - kernel: &mut SidecarKernel, - kernel_pid: u32, - host: Option<&str>, - port: u16, - context: &JavascriptSocketPathContext, - ) -> Result { - if self.socket.is_some() || self.guest_local_addr.is_some() { - return Err(SidecarError::Execution(String::from( - "EINVAL: secure-exec dgram socket is already bound", - ))); - } - - let (bind_host, guest_host, guest_family) = normalize_udp_bind_host(host, self.family)?; - let guest_port = allocate_guest_listen_port( - port, - guest_family, - &context.used_udp_guest_ports, - context.listen_policy, - )?; - let local_addr = resolve_udp_bind_addr(guest_host, guest_port, self.family)?; - if let Some(socket_id) = self.kernel_socket_id { - kernel - .socket_bind_inet( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - InetSocketAddress::new(local_addr.ip().to_string(), local_addr.port()), - ) - .map_err(kernel_error)?; - } else { - let bind_addr = resolve_udp_bind_addr(bind_host, 0, self.family)?; - let socket = UdpSocket::bind(bind_addr).map_err(sidecar_net_error)?; - socket.set_nonblocking(true).map_err(sidecar_net_error)?; - self.socket = Some(socket); - } - self.guest_local_addr = Some(local_addr); - Ok(local_addr) - } - - fn ensure_bound_for_send( - &mut self, - kernel: &mut SidecarKernel, - kernel_pid: u32, - context: &JavascriptSocketPathContext, - ) -> Result { - if let Some(local_addr) = self.local_addr() { - return Ok(local_addr); - } - - self.bind(kernel, kernel_pid, None, 0, context) - } - - fn send_to( - &mut self, - request: ActiveUdpSendToRequest<'_, B>, - ) -> Result<(usize, SocketAddr), SidecarError> - where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, - { - let ActiveUdpSendToRequest { - bridge, - kernel, - kernel_pid, - vm_id, - dns, - host, - port, - context, - contents, - } = request; - let remote_addr = resolve_udp_addr(UdpRemoteAddrRequest { - bridge, - kernel, - vm_id, - dns, - host, - port, - family: self.family, - context, - })?; - let local_addr = self.ensure_bound_for_send(kernel, kernel_pid, context)?; - let written = if let Some(socket_id) = self.kernel_socket_id { - if is_loopback_ip(remote_addr.ip()) && remote_addr.port() == port { - kernel - .socket_send_to_inet_loopback( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - InetSocketAddress::new(remote_addr.ip().to_string(), remote_addr.port()), - contents, - ) - .map_err(kernel_error)? - } else { - return Err(SidecarError::Execution(String::from( - "ERR_NOT_IMPLEMENTED: external UDP datagrams are not yet supported by the kernel-backed V8 bridge", - ))); - } - } else { - let socket = self.socket.as_ref().ok_or_else(|| { - SidecarError::InvalidState(String::from("UDP socket is not initialized")) - })?; - socket - .send_to(contents, remote_addr) - .map_err(sidecar_net_error)? - }; - Ok((written, local_addr)) - } - - fn poll( - &self, - kernel: &mut SidecarKernel, - kernel_pid: u32, - wait: Duration, - ) -> Result, SidecarError> { - if let Some(socket_id) = self.kernel_socket_id { - let result = kernel - .poll_targets( - EXECUTION_DRIVER_NAME, - kernel_pid, - vec![PollTargetEntry::socket(socket_id, POLLIN)], - i32::try_from(wait.as_millis()).unwrap_or(i32::MAX), - ) - .map_err(kernel_error)?; - let revents = result - .targets - .first() - .map(|entry| entry.revents) - .unwrap_or_else(PollEvents::empty); - if revents.is_empty() { - return Ok(None); - } - return match kernel.socket_recv_datagram( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - 64 * 1024, - ) { - Ok(Some(datagram)) => { - let (source_address, payload) = datagram.into_parts(); - let remote_addr = source_address - .map(|source| { - resolve_udp_bind_addr(source.host(), source.port(), self.family) - }) - .transpose()? - .unwrap_or_else(|| match self.family { - JavascriptUdpFamily::Ipv4 => { - SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0) - } - JavascriptUdpFamily::Ipv6 => { - SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 0) - } - }); - Ok(Some(JavascriptUdpSocketEvent::Message { - data: payload, - remote_addr, - })) - } - Ok(None) => Ok(None), - Err(error) if error.code() == "EAGAIN" => Ok(None), - Err(error) => Ok(Some(JavascriptUdpSocketEvent::Error { - code: Some(error.code().to_string()), - message: error.to_string(), - })), - }; - } - let socket = self.socket()?; - let deadline = Instant::now() + wait; - let mut buffer = vec![0_u8; 64 * 1024]; - - loop { - match socket.recv_from(&mut buffer) { - Ok((bytes_read, remote_addr)) => { - return Ok(Some(JavascriptUdpSocketEvent::Message { - data: buffer[..bytes_read].to_vec(), - remote_addr, - })); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - if wait.is_zero() || Instant::now() >= deadline { - return Ok(None); - } - if !wait_fd_readable_until(socket.as_fd(), deadline) { - return Ok(None); - } - } - Err(error) => { - return Ok(Some(JavascriptUdpSocketEvent::Error { - code: io_error_code(&error), - message: error.to_string(), - })); - } - } - } - } - - fn close(&mut self, kernel: &mut SidecarKernel, kernel_pid: u32) { - if let Some(socket_id) = self.kernel_socket_id { - let _ = close_kernel_socket_idempotent(kernel, kernel_pid, socket_id); - } - self.socket.take(); - self.guest_local_addr = None; - } - - fn set_buffer_size(&mut self, which: &str, size: usize) -> Result<(), SidecarError> { - match which { - "recv" => self.recv_buffer_size = size, - "send" => self.send_buffer_size = size, - other => { - return Err(SidecarError::InvalidState(format!( - "unsupported UDP buffer size kind {other}" - ))); - } - } - if self.kernel_socket_id.is_some() { - return Ok(()); - } - let socket = self.socket()?; - let socket = SockRef::from(socket); - match which { - "recv" => socket.set_recv_buffer_size(size).map_err(sidecar_net_error), - "send" => socket.set_send_buffer_size(size).map_err(sidecar_net_error), - other => Err(SidecarError::InvalidState(format!( - "unsupported UDP buffer size kind {other}" - ))), - } - } - - fn get_buffer_size(&self, which: &str) -> Result { - if self.kernel_socket_id.is_some() { - return Ok(match which { - "recv" => self.recv_buffer_size, - "send" => self.send_buffer_size, - other => { - return Err(SidecarError::InvalidState(format!( - "unsupported UDP buffer size kind {other}" - ))); - } - }); - } - let socket = self.socket()?; - let socket = SockRef::from(socket); - match which { - "recv" => socket.recv_buffer_size().map_err(sidecar_net_error), - "send" => socket.send_buffer_size().map_err(sidecar_net_error), - other => Err(SidecarError::InvalidState(format!( - "unsupported UDP buffer size kind {other}" - ))), - } - } -} - -// ActiveExecution, ActiveExecutionEvent, SocketQueryKind moved to crate::state - -impl ActiveExecution { - pub(crate) fn uses_shared_v8_runtime(&self) -> bool { - match self { - Self::Javascript(execution) => execution.uses_shared_v8_runtime(), - Self::Python(execution) => execution.uses_shared_v8_runtime(), - Self::Wasm(execution) => execution.uses_shared_v8_runtime(), - Self::Tool(_) => false, - } - } - - pub(crate) fn child_pid(&self) -> u32 { - match self { - Self::Javascript(execution) => execution.child_pid(), - Self::Python(execution) => execution.child_pid(), - Self::Wasm(execution) => execution.child_pid(), - Self::Tool(_) => 0, - } - } - - pub(crate) fn write_stdin(&mut self, chunk: &[u8]) -> Result<(), SidecarError> { - match self { - Self::Javascript(execution) => execution - .write_stdin(chunk) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Python(execution) => execution - .write_stdin(chunk) - .map_err(|error| SidecarError::Execution(error.to_string())), - // Sidecar wasm always runs with kernel-managed stdio - // (AGENTOS_WASI_STDIO_SYNC_RPC=1): the guest reads fd 0 via - // `__kernel_stdin_read`, so skip the V8 `stdin` stream event — - // it is never consumed and would flood the session's deferred - // message queue while the guest blocks in a sync read. - Self::Wasm(execution) => execution - .write_stdin_kernel_only(chunk) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Tool(_) => Ok(()), - } - } - - pub(crate) fn close_stdin(&mut self) -> Result<(), SidecarError> { - match self { - Self::Javascript(execution) => execution - .close_stdin() - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Python(execution) => execution - .close_stdin() - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Wasm(execution) => execution - .close_stdin() - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Tool(_) => Ok(()), - } - } - - pub(crate) fn respond_python_vfs_rpc_success( - &mut self, - id: u64, - payload: PythonVfsRpcResponsePayload, - ) -> Result<(), SidecarError> { - match self { - Self::Python(execution) => execution - .respond_vfs_rpc_success(id, payload) - .map_err(|error| SidecarError::Execution(error.to_string())), - _ => Err(SidecarError::InvalidState(String::from( - "only Python executions can service Python VFS RPC responses", - ))), - } - } - - pub(crate) fn respond_python_vfs_rpc_error( - &mut self, - id: u64, - code: impl Into, - message: impl Into, - ) -> Result<(), SidecarError> { - match self { - Self::Python(execution) => execution - .respond_vfs_rpc_error(id, code, message) - .map_err(|error| SidecarError::Execution(error.to_string())), - _ => Err(SidecarError::InvalidState(String::from( - "only Python executions can service Python VFS RPC responses", - ))), - } - } - - pub(crate) fn send_javascript_stream_event( - &self, - event_type: &str, - payload: Value, - ) -> Result<(), SidecarError> { - match self { - Self::Javascript(execution) => execution - .send_stream_event(event_type, payload) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Wasm(execution) => execution - .send_stream_event(event_type, payload) - .map_err(|error| SidecarError::Execution(error.to_string())), - _ => Err(SidecarError::InvalidState(String::from( - "only embedded V8 executions can receive JavaScript stream events", - ))), - } - } - - pub(crate) fn javascript_v8_session_handle(&self) -> Option { - match self { - Self::Javascript(execution) => Some(execution.v8_session_handle()), - Self::Wasm(execution) => Some(execution.v8_session_handle()), - _ => None, - } - } - - pub(crate) fn terminate(&mut self) -> Result<(), SidecarError> { - match self { - Self::Javascript(execution) => execution - .terminate() - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Python(execution) => execution - .kill() - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Wasm(execution) => execution - .terminate() - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Tool(_) => Ok(()), - } - } - - pub(crate) fn respond_javascript_sync_rpc_success( - &mut self, - id: u64, - result: Value, - ) -> Result<(), SidecarError> { - match self { - Self::Javascript(execution) => execution - .respond_sync_rpc_success(id, result) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Python(execution) => execution - .respond_javascript_sync_rpc_success(id, result) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Wasm(execution) => execution - .respond_sync_rpc_success(id, result) - .map_err(|error| SidecarError::Execution(error.to_string())), - _ => Err(SidecarError::InvalidState(String::from( - "only JavaScript, Python, and WebAssembly executions can service JavaScript sync RPC responses", - ))), - } - } - - pub(crate) fn respond_javascript_sync_rpc_raw_success( - &mut self, - id: u64, - payload: Vec, - ) -> Result<(), SidecarError> { - match self { - Self::Javascript(execution) => execution - .respond_sync_rpc_raw_success(id, payload) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Wasm(execution) => execution - .respond_sync_rpc_raw_success(id, payload) - .map_err(|error| SidecarError::Execution(error.to_string())), - _ => Err(SidecarError::InvalidState(String::from( - "only embedded V8 executions can service raw JavaScript sync RPC responses", - ))), - } - } - - pub(crate) fn respond_javascript_sync_rpc_response( - &mut self, - id: u64, - response: JavascriptSyncRpcServiceResponse, - ) -> Result<(), SidecarError> { - match response { - JavascriptSyncRpcServiceResponse::Json(result) => { - self.respond_javascript_sync_rpc_success(id, result) - } - JavascriptSyncRpcServiceResponse::Raw(payload) => { - self.respond_javascript_sync_rpc_raw_success(id, payload) - } - } - } - - pub(crate) fn respond_javascript_sync_rpc_error( - &mut self, - id: u64, - code: impl Into, - message: impl Into, - ) -> Result<(), SidecarError> { - match self { - Self::Javascript(execution) => execution - .respond_sync_rpc_error(id, code, message) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Python(execution) => execution - .respond_javascript_sync_rpc_error(id, code, message) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Wasm(execution) => execution - .respond_sync_rpc_error(id, code, message) - .map_err(|error| SidecarError::Execution(error.to_string())), - _ => Err(SidecarError::InvalidState(String::from( - "only JavaScript, Python, and WebAssembly executions can service JavaScript sync RPC responses", - ))), - } - } - - pub(crate) async fn poll_event( - &mut self, - timeout: Duration, - ) -> Result, SidecarError> { - match self { - Self::Javascript(execution) => execution - .poll_event(timeout) - .await - .map(|event| { - event.map(|event| match event { - JavascriptExecutionEvent::Stdout(chunk) => { - ActiveExecutionEvent::Stdout(chunk) - } - JavascriptExecutionEvent::Stderr(chunk) => { - ActiveExecutionEvent::Stderr(chunk) - } - JavascriptExecutionEvent::SyncRpcRequest(request) => { - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) - } - JavascriptExecutionEvent::SignalState { - signal, - registration, - } => ActiveExecutionEvent::SignalState { - signal, - registration: map_node_signal_registration(registration), - }, - JavascriptExecutionEvent::Exited(code) => { - ActiveExecutionEvent::Exited(code) - } - }) - }) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Python(execution) => execution - .poll_event(timeout) - .await - .map(|event| { - event.map(|event| match event { - PythonExecutionEvent::Stdout(chunk) => ActiveExecutionEvent::Stdout(chunk), - PythonExecutionEvent::Stderr(chunk) => ActiveExecutionEvent::Stderr(chunk), - PythonExecutionEvent::JavascriptSyncRpcRequest(request) => { - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) - } - PythonExecutionEvent::VfsRpcRequest(request) => { - ActiveExecutionEvent::PythonVfsRpcRequest(request) - } - PythonExecutionEvent::Exited(code) => ActiveExecutionEvent::Exited(code), - }) - }) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Wasm(execution) => execution - .poll_event(timeout) - .await - .map(|event| { - event.map(|event| match event { - WasmExecutionEvent::Stdout(chunk) => ActiveExecutionEvent::Stdout(chunk), - WasmExecutionEvent::Stderr(chunk) => ActiveExecutionEvent::Stderr(chunk), - WasmExecutionEvent::SyncRpcRequest(request) => { - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) - } - WasmExecutionEvent::SignalState { - signal, - registration, - } => ActiveExecutionEvent::SignalState { - signal, - registration: map_wasm_signal_registration(registration), - }, - WasmExecutionEvent::Exited(code) => ActiveExecutionEvent::Exited(code), - }) - }) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Tool(execution) => { - let _ = timeout; - poll_tool_process_event(execution) - } - } - } - - pub(crate) fn poll_event_blocking( - &mut self, - timeout: Duration, - ) -> Result, SidecarError> { - match self { - Self::Javascript(execution) => execution - .poll_event_blocking(timeout) - .map(|event| { - event.map(|event| match event { - JavascriptExecutionEvent::Stdout(chunk) => { - ActiveExecutionEvent::Stdout(chunk) - } - JavascriptExecutionEvent::Stderr(chunk) => { - ActiveExecutionEvent::Stderr(chunk) - } - JavascriptExecutionEvent::SyncRpcRequest(request) => { - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) - } - JavascriptExecutionEvent::SignalState { - signal, - registration, - } => ActiveExecutionEvent::SignalState { - signal, - registration: map_node_signal_registration(registration), - }, - JavascriptExecutionEvent::Exited(code) => { - ActiveExecutionEvent::Exited(code) - } - }) - }) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Python(execution) => execution - .poll_event_blocking(timeout) - .map(|event| { - event.map(|event| match event { - PythonExecutionEvent::Stdout(chunk) => ActiveExecutionEvent::Stdout(chunk), - PythonExecutionEvent::Stderr(chunk) => ActiveExecutionEvent::Stderr(chunk), - PythonExecutionEvent::JavascriptSyncRpcRequest(request) => { - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) - } - PythonExecutionEvent::VfsRpcRequest(request) => { - ActiveExecutionEvent::PythonVfsRpcRequest(request) - } - PythonExecutionEvent::Exited(code) => ActiveExecutionEvent::Exited(code), - }) - }) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Wasm(execution) => execution - .poll_event_blocking(timeout) - .map(|event| { - event.map(|event| match event { - WasmExecutionEvent::Stdout(chunk) => ActiveExecutionEvent::Stdout(chunk), - WasmExecutionEvent::Stderr(chunk) => ActiveExecutionEvent::Stderr(chunk), - WasmExecutionEvent::SyncRpcRequest(request) => { - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) - } - WasmExecutionEvent::SignalState { - signal, - registration, - } => ActiveExecutionEvent::SignalState { - signal, - registration: map_wasm_signal_registration(registration), - }, - WasmExecutionEvent::Exited(code) => ActiveExecutionEvent::Exited(code), - }) - }) - .map_err(|error| SidecarError::Execution(error.to_string())), - Self::Tool(execution) => { - let _ = timeout; - poll_tool_process_event(execution) - } - } - } -} - -struct ToolProcessEventRequest { - sidecar_requests: SharedSidecarRequestClient, - connection_id: String, - session_id: String, - vm_id: String, - tool_resolution: ToolCommandResolution, - cancelled: Arc, - pending_events: Arc>>, - events_overflowed: Arc, -} - -pub(crate) fn send_tool_process_event( - pending_events: &Arc>>, - events_overflowed: &AtomicBool, - event: ActiveExecutionEvent, -) -> bool { - let mut pending_events = pending_events - .lock() - .unwrap_or_else(|poisoned| poisoned.into_inner()); - if pending_events.len() >= MAX_PROCESS_EVENT_QUEUE { - events_overflowed.store(true, Ordering::Relaxed); - return false; - } - pending_events.push_back(event); - true -} - -fn spawn_tool_process_events(request: ToolProcessEventRequest) { - let ToolProcessEventRequest { - sidecar_requests, - connection_id, - session_id, - vm_id, - tool_resolution, - cancelled, - pending_events, - events_overflowed, - } = request; - std::thread::spawn(move || match tool_resolution { - ToolCommandResolution::Failure(message) => { - if !send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Stderr(format_tool_failure_output(&message)), - ) { - return; - } - let _ = send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Exited(1), - ); - } - ToolCommandResolution::Invoke { request, timeout } => { - let response = sidecar_requests.invoke( - OwnershipScope::vm(connection_id.clone(), session_id.clone(), vm_id.clone()), - SidecarRequestPayload::HostCallback(request.clone()), - timeout, - ); - if cancelled.load(Ordering::Relaxed) { - return; - } - - match response { - Ok(crate::protocol::SidecarResponsePayload::HostCallbackResult(result)) => { - if let Some(value) = result.result { - let value: serde_json::Value = serde_json::from_str(&value) - .unwrap_or(serde_json::Value::String(value)); - let stdout = serde_json::to_vec(&json!({ - "ok": true, - "result": value, - })) - .unwrap_or_else(|error| { - format_tool_failure_output(&format!( - "failed to serialize tool result: {error}" - )) - }); - if !send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Stdout(stdout), - ) { - return; - } - let _ = send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Exited(0), - ); - } else { - let message = result - .error - .unwrap_or_else(|| String::from("tool invocation returned no result")); - if !send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Stderr(format_tool_failure_output(&message)), - ) { - return; - } - let _ = send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Exited(1), - ); - } - } - Ok(_) => { - if !send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Stderr(format_tool_failure_output( - "unexpected sidecar tool response", - )), - ) { - return; - } - let _ = send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Exited(1), - ); - } - Err(error) => { - if !send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Stderr(format_tool_failure_output( - &error.to_string(), - )), - ) { - return; - } - let _ = send_tool_process_event( - &pending_events, - &events_overflowed, - ActiveExecutionEvent::Exited(1), - ); - } - } - } - }); -} - -impl NativeSidecar -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - pub(crate) async fn execute( - &mut self, - request: &RequestFrame, - payload: ExecuteRequest, - ) -> Result { - let execute_total_start = Instant::now(); - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self - .vms - .get_mut(&vm_id) - .ok_or_else(|| missing_vm_error(&vm_id))?; - if vm.active_processes.contains_key(&payload.process_id) { - return Err(SidecarError::InvalidState(format!( - "VM {vm_id} already has an active process with id {}", - payload.process_id - ))); - } - - if let Some(command) = payload.command.as_deref() { - if let Some(tool_resolution) = - resolve_tool_command(vm, command, &payload.args, payload.cwd.as_deref())? - { - let guest_cwd = payload - .cwd - .as_deref() - .map(normalize_path) - .unwrap_or_else(|| vm.guest_cwd.clone()); - let kernel_handle = vm - .kernel - .create_virtual_process( - EXECUTION_DRIVER_NAME, - TOOL_DRIVER_NAME, - command, - std::iter::once(command.to_owned()) - .chain(payload.args.iter().cloned()) - .collect(), - VirtualProcessOptions { - env: vm.guest_env.clone(), - cwd: Some(guest_cwd.clone()), - ..VirtualProcessOptions::default() - }, - ) - .map_err(kernel_error)?; - let kernel_pid = kernel_handle.pid(); - let tool_execution = ToolExecution::default(); - let cancelled = tool_execution.cancelled.clone(); - let pending_events = tool_execution.pending_events.clone(); - let events_overflowed = tool_execution.events_overflowed.clone(); - vm.active_processes.insert( - payload.process_id.clone(), - ActiveProcess::new( - kernel_pid, - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Tool(tool_execution), - ) - .with_guest_cwd(guest_cwd.clone()) - .with_host_cwd(resolve_vm_guest_path_to_host(vm, &guest_cwd)), - ); - self.bridge.emit_lifecycle(&vm_id, LifecycleState::Busy)?; - spawn_tool_process_events(ToolProcessEventRequest { - sidecar_requests: self.sidecar_requests.clone(), - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - tool_resolution, - cancelled, - pending_events, - events_overflowed, - }); - - return Ok(DispatchResult { - response: process_started_response( - request, - payload.process_id, - Some(kernel_pid), - ), - events: Vec::new(), - }); - } - } - - let requested_tty = payload - .env - .get(EXECUTION_REQUEST_TTY_ENV) - .is_some_and(|value| value == "1" || value.eq_ignore_ascii_case("true")); - let phase_start = Instant::now(); - let resolved = resolve_execute_request(vm, &payload)?; - record_execute_phase("resolve_execute_request", phase_start.elapsed()); - let phase_start = Instant::now(); - let mut env = resolved.env.clone(); - env.remove(EXECUTION_REQUEST_TTY_ENV); - let sandbox_root = normalize_host_path(&vm.cwd); - env.insert( - String::from(EXECUTION_SANDBOX_ROOT_ENV), - sandbox_root.to_string_lossy().into_owned(), - ); - if resolved.runtime == GuestRuntimeKind::JavaScript { - env.insert( - String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - ); - // A TTY guest-node process reads stdin through the kernel PTY: host - // input is written to the PTY master (write_kernel_process_stdin), - // line discipline runs (echo / VERASE / ICRNL / VEOF), and the - // sidecar drains the cooked bytes from the slave and forwards them - // to the isolate's stream-stdin dispatch - // (forward_tty_slave_input_to_javascript). The in-isolate - // `_kernelStdinRead` bridge stays local; no RPC forwarding is - // needed because the isolate never reads kernel fd 0 itself. - } else if resolved.runtime == GuestRuntimeKind::WebAssembly { - env.insert(String::from(WASM_STDIO_SYNC_RPC_ENV), String::from("1")); - } - let launch_entrypoint = if resolved.runtime == GuestRuntimeKind::JavaScript { - resolve_agentos_package_javascript_launch_entrypoint(vm, &mut env) - .unwrap_or_else(|| resolved.entrypoint.clone()) - } else { - resolved.entrypoint.clone() - }; - let argv = std::iter::once(launch_entrypoint.clone()) - .chain(resolved.execution_args.iter().cloned()) - .collect::>(); - record_execute_phase("env_argv_setup", phase_start.elapsed()); - let phase_start = Instant::now(); - let kernel_handle = vm - .kernel - .spawn_process( - &resolved.command, - argv, - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(resolved.guest_cwd.clone()), - ..SpawnOptions::default() - }, - ) - .map_err(kernel_error)?; - let kernel_pid = kernel_handle.pid(); - record_execute_phase("kernel_spawn_process", phase_start.elapsed()); - let tty_master_fd = if requested_tty { - let (master_fd, slave_fd, _) = vm - .kernel - .open_pty(EXECUTION_DRIVER_NAME, kernel_pid) - .map_err(kernel_error)?; - vm.kernel - .fd_dup2(EXECUTION_DRIVER_NAME, kernel_pid, slave_fd, 0) - .map_err(kernel_error)?; - vm.kernel - .fd_dup2(EXECUTION_DRIVER_NAME, kernel_pid, slave_fd, 1) - .map_err(kernel_error)?; - vm.kernel - .fd_dup2(EXECUTION_DRIVER_NAME, kernel_pid, slave_fd, 2) - .map_err(kernel_error)?; - vm.kernel - .pty_set_foreground_pgid(EXECUTION_DRIVER_NAME, kernel_pid, master_fd, kernel_pid) - .map_err(kernel_error)?; - if let Some((cols, rows)) = requested_pty_window_size(&env) { - vm.kernel - .pty_resize(EXECUTION_DRIVER_NAME, kernel_pid, master_fd, cols, rows) - .map_err(kernel_error)?; - } - Some(master_fd) - } else { - None - }; - - let (execution, process_env) = match resolved.runtime { - GuestRuntimeKind::JavaScript => { - let phase_start = Instant::now(); - let inline_code = load_javascript_entrypoint_source( - vm, - &resolved.host_cwd, - &launch_entrypoint, - &env, - ); - record_execute_phase("js_load_entrypoint_source", phase_start.elapsed()); - let phase_start = Instant::now(); - prepare_javascript_shadow(vm, &resolved, &env)?; - record_execute_phase("js_prepare_shadow", phase_start.elapsed()); - - let phase_start = Instant::now(); - let context = - self.javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: Some(self.cache_root.join("node-compile-cache")), - }); - record_execute_phase("js_create_context", phase_start.elapsed()); - let phase_start = Instant::now(); - let built_reader = build_module_reader(vm, &resolved); - let guest_reader = built_reader.clone().map(|reader| { - Box::new(crate::plugins::host_dir::SessionModuleReader::new(reader)) - as Box - }); - let module_reader = - built_reader.map(|reader| Box::new(reader) as Box); - record_execute_phase("js_build_module_reader", phase_start.elapsed()); - let phase_start = Instant::now(); - let execution = self - .javascript_engine - .start_execution_with_module_reader( - StartJavascriptExecutionRequest { - guest_runtime: guest_runtime_identity(vm, None, None), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: std::iter::once(launch_entrypoint.clone()) - .chain(resolved.execution_args.iter().cloned()) - .collect(), - env: env.clone(), - cwd: resolved.host_cwd.clone(), - limits: javascript_execution_limits(vm), - inline_code, - wasm_module_bytes: None, - }, - module_reader, - guest_reader, - ) - .map_err(javascript_error)?; - record_execute_phase("js_start_execution", phase_start.elapsed()); - (ActiveExecution::Javascript(execution), env.clone()) - } - GuestRuntimeKind::Python => { - // The `python` command path (marked by AGENTOS_PYTHON_ARGV) is - // explicit about file mode via AGENTOS_PYTHON_FILE, so a `-c` code - // string that happens to end in `.py` is never mistaken for a path. - // The low-level execute API keeps the `.py`-suffix heuristic. - let python_file_path = if resolved.env.contains_key("AGENTOS_PYTHON_ARGV") { - resolved.env.get("AGENTOS_PYTHON_FILE").map(PathBuf::from) - } else { - python_file_entrypoint(&resolved.entrypoint) - }; - let pyodide_dist_path = self - .python_engine - .bundled_pyodide_dist_path_for_vm(&vm_id) - .map_err(python_error)?; - let pyodide_cache_path = pyodide_dist_path - .parent() - .and_then(Path::parent) - .unwrap_or(pyodide_dist_path.as_path()) - .join("pyodide-package-cache"); - add_runtime_guest_path_mapping( - &mut env, - PYTHON_PYODIDE_GUEST_ROOT, - &pyodide_dist_path, - ); - add_runtime_guest_path_mapping( - &mut env, - PYTHON_PYODIDE_CACHE_GUEST_ROOT, - &pyodide_cache_path, - ); - add_runtime_host_access_path( - &mut env, - "AGENTOS_EXTRA_FS_READ_PATHS", - &pyodide_dist_path, - true, - ); - add_runtime_host_access_path( - &mut env, - "AGENTOS_EXTRA_FS_READ_PATHS", - &pyodide_cache_path, - true, - ); - add_runtime_host_access_path( - &mut env, - "AGENTOS_EXTRA_FS_WRITE_PATHS", - &pyodide_cache_path, - false, - ); - let context = self - .python_engine - .create_context(CreatePythonContextRequest { - vm_id: vm_id.clone(), - pyodide_dist_path, - }); - let execution = self - .python_engine - .start_execution(StartPythonExecutionRequest { - vm_id: vm_id.clone(), - context_id: context.context_id, - code: resolved.entrypoint.clone(), - file_path: python_file_path, - env: env.clone(), - cwd: resolved.host_cwd.clone(), - limits: python_execution_limits(vm), - guest_runtime: guest_runtime_identity(vm, None, None), - }) - .map_err(python_error)?; - (ActiveExecution::Python(execution), env.clone()) - } - GuestRuntimeKind::WebAssembly => { - let wasm_limits = wasm_execution_limits(vm); - let wasm_guest_runtime = - guest_runtime_identity(vm, Some(u64::from(kernel_pid)), Some(0)); - let wasm_permission_tier = resolved.wasm_permission_tier.unwrap_or_else(|| { - resolve_wasm_permission_tier( - vm, - Some(&resolved.command), - None, - &resolved.entrypoint, - ) - }); - let context = self.wasm_engine.create_context(CreateWasmContextRequest { - vm_id: vm_id.clone(), - module_path: Some(resolved.entrypoint.clone()), - }); - let execution = self - .wasm_engine - .start_execution(StartWasmExecutionRequest { - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: resolved.process_args.clone(), - env: env.clone(), - cwd: resolved.host_cwd.clone(), - permission_tier: execution_wasm_permission_tier(wasm_permission_tier), - limits: wasm_limits, - guest_runtime: wasm_guest_runtime, - }) - .map_err(wasm_error)?; - (ActiveExecution::Wasm(Box::new(execution)), env) - } - }; - let child_pid = execution.child_pid(); - let phase_start = Instant::now(); - let kernel_stdin_writer_fd = if let Some(master_fd) = tty_master_fd { - master_fd - } else { - install_kernel_stdin_pipe(&mut vm.kernel, kernel_pid)? - }; - vm.active_processes.insert( - payload.process_id.clone(), - ActiveProcess::new(kernel_pid, kernel_handle, resolved.runtime, execution) - .with_kernel_stdin_writer_fd(kernel_stdin_writer_fd) - .with_tty_master_fd(tty_master_fd) - .with_guest_cwd(resolved.guest_cwd.clone()) - .with_env(process_env) - .with_host_cwd(resolved.host_cwd.clone()), - ); - self.bridge.emit_lifecycle(&vm_id, LifecycleState::Busy)?; - mark_execute_response_ready(&vm_id, &payload.process_id); - record_execute_phase("process_register_and_lifecycle", phase_start.elapsed()); - record_execute_phase("execute_total", execute_total_start.elapsed()); - - Ok(DispatchResult { - response: process_started_response( - request, - payload.process_id, - Some(if child_pid == 0 { - kernel_pid - } else { - child_pid - }), - ), - events: Vec::new(), - }) - } - - pub(crate) async fn resize_pty( - &mut self, - request: &RequestFrame, - payload: ResizePtyRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self - .vms - .get_mut(&vm_id) - .ok_or_else(|| missing_vm_error(&vm_id))?; - let process = vm - .active_processes - .get_mut(&payload.process_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "VM {vm_id} has no active process {}", - payload.process_id - )) - })?; - let Some(writer_fd) = process.kernel_stdin_writer_fd else { - return Err(SidecarError::InvalidState(format!( - "process {} does not have a PTY", - payload.process_id - ))); - }; - vm.kernel - .pty_resize( - EXECUTION_DRIVER_NAME, - process.kernel_pid, - writer_fd, - payload.cols, - payload.rows, - ) - .map_err(kernel_error)?; - - Ok(DispatchResult { - response: self.respond( - request, - ResponsePayload::PtyResized(PtyResizedResponse { - process_id: payload.process_id, - cols: payload.cols, - rows: payload.rows, - }), - ), - events: Vec::new(), - }) - } - - pub(crate) async fn write_stdin( - &mut self, - request: &RequestFrame, - payload: WriteStdinRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self - .vms - .get_mut(&vm_id) - .ok_or_else(|| missing_vm_error(&vm_id))?; - let process = vm - .active_processes - .get_mut(&payload.process_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "VM {vm_id} has no active process {}", - payload.process_id - )) - })?; - // For a TTY JavaScript process, host stdin must go ONLY to the kernel PTY - // master (so line discipline + echo apply); feeding the in-process local - // stdin bridge as well would double-deliver the input. Non-TTY JS (piped - // stdin) still uses the local bridge; wasm/python always take the - // streaming/no-op `write_stdin` path plus the kernel master write below. - let tty_js = - process.runtime == GuestRuntimeKind::JavaScript && process.tty_master_fd.is_some(); - if !tty_js { - process.execution.write_stdin(&payload.chunk)?; - } - write_kernel_process_stdin(&mut vm.kernel, process, &payload.chunk)?; - - Ok(DispatchResult { - response: stdin_written_response( - request, - payload.process_id, - payload.chunk.len() as u64, - ), - events: Vec::new(), - }) - } - - pub(crate) async fn close_stdin( - &mut self, - request: &RequestFrame, - payload: CloseStdinRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self - .vms - .get_mut(&vm_id) - .ok_or_else(|| missing_vm_error(&vm_id))?; - let process = vm - .active_processes - .get_mut(&payload.process_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "VM {vm_id} has no active process {}", - payload.process_id - )) - })?; - process.execution.close_stdin()?; - close_kernel_process_stdin(&mut vm.kernel, process)?; - - Ok(DispatchResult { - response: stdin_closed_response(request, payload.process_id), - events: Vec::new(), - }) - } - - pub(crate) async fn kill_process( - &mut self, - request: &RequestFrame, - payload: KillProcessRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - self.kill_process_internal(&vm_id, &payload.process_id, &payload.signal)?; - - Ok(DispatchResult { - response: process_killed_response(request, payload.process_id), - events: Vec::new(), - }) - } - - pub(crate) async fn find_listener( - &mut self, - request: &RequestFrame, - payload: FindListenerRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - require_vm_inspection_permission( - &self.bridge, - &vm_id, - "network.inspect", - "network", - &socket_query_resource(SocketQueryKind::TcpListener, &payload), - )?; - - let listener = - find_socket_state_entry(self.vms.get(&vm_id), SocketQueryKind::TcpListener, &payload)?; - - Ok(DispatchResult { - response: listener_snapshot_response(request, listener), - events: Vec::new(), - }) - } - - pub(crate) async fn get_process_snapshot( - &mut self, - request: &RequestFrame, - _payload: GetProcessSnapshotRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - require_vm_inspection_permission( - &self.bridge, - &vm_id, - "process.inspect", - "process", - "process://snapshot", - )?; - - let processes = self - .vms - .get_mut(&vm_id) - .map(|vm| { - prune_exited_process_snapshots(vm); - snapshot_vm_processes(vm) - }) - .unwrap_or_default(); - - Ok(DispatchResult { - response: process_snapshot_response(request, processes), - events: Vec::new(), - }) - } - - pub(crate) async fn guest_kernel_call( - &mut self, - request: &RequestFrame, - payload: GuestKernelCallRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self.vms.get_mut(&vm_id).ok_or_else(|| { - SidecarError::InvalidState(format!("VM {vm_id} no longer exists for guest kernel call")) - })?; - let kernel_pid = vm - .active_processes - .get(&payload.execution_id) - .map(|process| process.kernel_pid) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "VM {vm_id} has no active process {} for guest kernel call", - payload.execution_id - )) - })?; - - let response = secure_exec_sidecar_core::handle_guest_kernel_call( - &mut vm.kernel, - kernel_pid, - EXECUTION_DRIVER_NAME, - &payload.operation, - &payload.payload, - ) - .map_err(guest_kernel_core_error)?; - - Ok(DispatchResult { - response: self.respond( - request, - ResponsePayload::GuestKernelResult(GuestKernelResultResponse { payload: response }), - ), - events: Vec::new(), - }) - } - - pub(crate) async fn get_resource_snapshot( - &mut self, - request: &RequestFrame, - _payload: GetResourceSnapshotRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - require_vm_inspection_permission( - &self.bridge, - &vm_id, - "process.inspect", - "process", - "process://resources", - )?; - - let snapshot = self - .vms - .get(&vm_id) - .map(|vm| vm.kernel.resource_snapshot()) - .unwrap_or_default(); - let queue_snapshots = queue_tracker::queue_snapshot() - .into_iter() - .map(|queue| QueueSnapshotEntry { - name: queue.name.as_str().to_owned(), - category: queue.category.as_str().to_owned(), - depth: queue.depth as u64, - high_water: queue.high_water as u64, - capacity: queue.capacity as u64, - fill_percent: queue.fill_percent as u64, - }) - .collect(); - - Ok(DispatchResult { - response: self.respond( - request, - ResponsePayload::ResourceSnapshot(ResourceSnapshotResponse { - running_processes: snapshot.running_processes as u64, - exited_processes: snapshot.exited_processes as u64, - fd_tables: snapshot.fd_tables as u64, - open_fds: snapshot.open_fds as u64, - pipes: snapshot.pipes as u64, - pipe_buffered_bytes: snapshot.pipe_buffered_bytes as u64, - ptys: snapshot.ptys as u64, - pty_buffered_input_bytes: snapshot.pty_buffered_input_bytes as u64, - pty_buffered_output_bytes: snapshot.pty_buffered_output_bytes as u64, - sockets: snapshot.sockets as u64, - socket_listeners: snapshot.socket_listeners as u64, - socket_connections: snapshot.socket_connections as u64, - socket_buffered_bytes: snapshot.socket_buffered_bytes as u64, - socket_datagram_queue_len: snapshot.socket_datagram_queue_len as u64, - queue_snapshots, - }), - ), - events: Vec::new(), - }) - } - - pub(crate) async fn find_bound_udp( - &mut self, - request: &RequestFrame, - payload: FindBoundUdpRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let lookup_request = FindListenerRequest { - host: payload.host, - port: payload.port, - path: None, - }; - require_vm_inspection_permission( - &self.bridge, - &vm_id, - "network.inspect", - "network", - &socket_query_resource(SocketQueryKind::UdpBound, &lookup_request), - )?; - let socket = find_socket_state_entry( - self.vms.get(&vm_id), - SocketQueryKind::UdpBound, - &lookup_request, - )?; - - Ok(DispatchResult { - response: bound_udp_snapshot_response(request, socket), - events: Vec::new(), - }) - } - - pub(crate) async fn vm_fetch( - &mut self, - request: &RequestFrame, - payload: VmFetchRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self - .vms - .get_mut(&vm_id) - .ok_or_else(|| SidecarError::InvalidState(String::from("unknown sidecar VM")))?; - let target_path = if payload.path.starts_with('/') { - payload.path.clone() - } else { - format!("/{}", payload.path) - }; - let request_url = Url::parse(&format!("http://127.0.0.1:{}{target_path}", payload.port)) - .map_err(|error| { - SidecarError::InvalidState(format!( - "invalid vm.fetch target {target_path:?}: {error}" - )) - })?; - let header_values: BTreeMap = serde_json::from_str(&payload.headers_json) - .map_err(|error| { - SidecarError::InvalidState(format!( - "vm.fetch headers_json must be valid JSON: {error}" - )) - })?; - let options = JavascriptHttpRequestOptions { - method: Some(payload.method), - headers: header_values, - body: payload.body, - reject_unauthorized: None, - }; - let headers = parse_http_header_collection(&options.headers, "vm.fetch headers")?; - let target_process_id = find_kernel_http_listener_process(vm, payload.port); - if let Some(target_process_id) = target_process_id { - let max_fetch_response_bytes = vm.limits.http.max_fetch_response_bytes; - let response_json = match dispatch_kernel_http_fetch( - &self.bridge, - &vm_id, - vm, - &target_process_id, - payload.port, - &target_path, - &options, - &headers, - max_fetch_response_bytes, - ) { - Ok(response_json) => response_json, - Err(error) => { - if let Some(exit_code) = kernel_http_fetch_target_exit_code(&error) { - let _ = vm; - self.finish_active_process_exit(&vm_id, &target_process_id, exit_code)?; - } - return Err(error); - } - }; - let response = self.respond( - request, - ResponsePayload::VmFetchResult(VmFetchResponse { response_json }), - ); - ensure_vm_fetch_response_frame_within_limit(&response, self.config.max_frame_bytes)?; - - return Ok(DispatchResult { - response, - events: Vec::new(), - }); - } - - let Some((target_process_id, server_id)) = - vm.active_processes - .iter() - .find_map(|(process_id, process)| { - process - .http_servers - .iter() - .find(|(_, server)| server.guest_local_addr.port() == payload.port) - .map(|(server_id, _)| (process_id.clone(), *server_id)) - }) - else { - return Err(SidecarError::Execution(format!( - "vm.fetch could not find a guest HTTP listener on port {}", - payload.port - ))); - }; - let socket_paths = build_javascript_socket_path_context(vm)?; - let resource_limits = vm.kernel.resource_limits().clone(); - let kernel_readiness = Arc::clone(&vm.kernel_socket_readiness); - let process = vm - .active_processes - .get_mut(&target_process_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "vm.fetch target process disappeared: {target_process_id}" - )) - })?; - let request_json = serialize_http_loopback_request(&request_url, &options, &headers)?; - let response_json = dispatch_loopback_http_request(LoopbackHttpDispatchRequest { - bridge: &self.bridge, - vm_id: &vm_id, - dns: &vm.dns, - socket_paths: &socket_paths, - kernel: &mut vm.kernel, - kernel_readiness, - process, - resource_limits: &resource_limits, - server_id, - request_json: &request_json, - })?; - - let response = self.respond( - request, - ResponsePayload::VmFetchResult(VmFetchResponse { response_json }), - ); - ensure_vm_fetch_response_frame_within_limit(&response, self.config.max_frame_bytes)?; - - Ok(DispatchResult { - response, - events: Vec::new(), - }) - } - - pub(crate) async fn get_signal_state( - &mut self, - request: &RequestFrame, - payload: GetSignalStateRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let handlers = self - .vms - .get(&vm_id) - .and_then(|vm| vm.signal_states.get(&payload.process_id)) - .cloned() - .unwrap_or_default(); - - Ok(DispatchResult { - response: signal_state_response(request, payload.process_id, handlers), - events: Vec::new(), - }) - } - - pub(crate) async fn get_zombie_timer_count( - &mut self, - request: &RequestFrame, - _payload: GetZombieTimerCountRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let count = self - .vms - .get(&vm_id) - .map(|vm| vm.kernel.zombie_timer_count() as u64) - .unwrap_or_default(); - - Ok(DispatchResult { - response: zombie_timer_count_response(request, count), - events: Vec::new(), - }) - } - - pub(crate) fn kill_process_internal( - &mut self, - vm_id: &str, - process_id: &str, - signal: &str, - ) -> Result<(), SidecarError> { - let signal_name = signal.to_owned(); - let signal = parse_signal(signal)?; - let vm = self - .vms - .get_mut(vm_id) - .ok_or_else(|| SidecarError::InvalidState(format!("unknown sidecar VM {vm_id}")))?; - let process = vm.active_processes.get_mut(process_id).ok_or_else(|| { - SidecarError::InvalidState(format!("VM {vm_id} has no active process {process_id}")) - })?; - let kernel_pid = process.kernel_pid; - if !matches!(signal, 0 | libc::SIGCONT) { - // A guest parked in a deferred kernel-wait sync RPC is blocked in a - // native bridge wait the kill cannot interrupt; answer the parked - // RPC first so the termination can take effect. - flush_parked_kernel_wait_rpc(process); - } - - enum KillBehavior { - Tool, - SharedV8StateOnly, - SharedV8Continue, - SharedV8Terminate, - SharedV8DispatchOrTerminate, - Noop, - HostPid(u32), - } - - let behavior = match &process.execution { - ActiveExecution::Tool(_) => KillBehavior::Tool, - ActiveExecution::Javascript(execution) - if execution.uses_shared_v8_runtime() && matches!(signal, 0 | libc::SIGSTOP) => - { - KillBehavior::SharedV8StateOnly - } - ActiveExecution::Javascript(execution) - if execution.uses_shared_v8_runtime() && signal == libc::SIGCONT => - { - KillBehavior::SharedV8Continue - } - ActiveExecution::Wasm(execution) - if execution.uses_shared_v8_runtime() - && matches!(signal, 0 | libc::SIGSTOP | libc::SIGCONT) => - { - KillBehavior::SharedV8StateOnly - } - ActiveExecution::Python(execution) - if execution.uses_shared_v8_runtime() - && matches!(signal, 0 | libc::SIGSTOP | libc::SIGCONT) => - { - KillBehavior::SharedV8StateOnly - } - ActiveExecution::Javascript(execution) - if execution.uses_shared_v8_runtime() && signal == SIGKILL => - { - KillBehavior::SharedV8Terminate - } - ActiveExecution::Wasm(execution) - if execution.uses_shared_v8_runtime() && signal == SIGKILL => - { - KillBehavior::SharedV8Terminate - } - ActiveExecution::Javascript(execution) if execution.uses_shared_v8_runtime() => { - KillBehavior::SharedV8DispatchOrTerminate - } - ActiveExecution::Wasm(execution) if execution.uses_shared_v8_runtime() => { - KillBehavior::SharedV8Terminate - } - ActiveExecution::Python(execution) if execution.uses_shared_v8_runtime() => { - KillBehavior::SharedV8Terminate - } - ActiveExecution::Javascript(execution) if execution.child_pid() == 0 => { - KillBehavior::Noop - } - _ => KillBehavior::HostPid(process.execution.child_pid()), - }; - - match behavior { - KillBehavior::Tool => { - let ActiveExecution::Tool(execution) = &process.execution else { - unreachable!("kill behavior must match tool execution"); - }; - if signal != 0 { - execution.cancelled.store(true, Ordering::Relaxed); - process.queue_pending_execution_event(ActiveExecutionEvent::Exited( - 128 + signal, - ))?; - } - } - KillBehavior::SharedV8StateOnly => { - if matches!(signal, libc::SIGSTOP | libc::SIGCONT) { - vm.kernel - .kill_process(EXECUTION_DRIVER_NAME, kernel_pid, signal) - .map_err(kernel_error)?; - } - } - KillBehavior::SharedV8Continue => { - vm.kernel - .kill_process(EXECUTION_DRIVER_NAME, kernel_pid, signal) - .map_err(kernel_error)?; - if signal != 0 && !dispatch_v8_process_signal(process, signal)? { - process.execution.terminate()?; - } - } - KillBehavior::SharedV8Terminate => { - if signal != 0 && matches!(process.execution, ActiveExecution::Python(_)) { - close_kernel_process_stdin(&mut vm.kernel, process)?; - } - process.execution.terminate()?; - let needs_synthetic_exit = matches!(process.execution, ActiveExecution::Wasm(_)) - || (signal == SIGKILL - && matches!(process.execution, ActiveExecution::Javascript(_))); - if signal != 0 && needs_synthetic_exit { - process.queue_pending_execution_event(ActiveExecutionEvent::Exited( - 128 + signal, - ))?; - } - } - KillBehavior::SharedV8DispatchOrTerminate => { - if signal != 0 && !dispatch_v8_process_signal(process, signal)? { - process.execution.terminate()?; - } - } - KillBehavior::Noop => {} - KillBehavior::HostPid(pid) => { - if signal != 0 && matches!(process.execution, ActiveExecution::Python(_)) { - close_kernel_process_stdin(&mut vm.kernel, process)?; - } - signal_runtime_process(pid, signal)?; - } - } - emit_security_audit_event( - &self.bridge, - vm_id, - "security.process.kill", - audit_fields([ - (String::from("source"), String::from("control_plane")), - (String::from("source_pid"), String::from("0")), - (String::from("target_pid"), process.kernel_pid.to_string()), - (String::from("process_id"), process_id.to_owned()), - (String::from("signal"), signal_name), - ( - String::from("host_pid"), - process.execution.child_pid().to_string(), - ), - ]), - ); - Ok(()) - } - - pub async fn pump_process_events( - &mut self, - ownership: &OwnershipScope, - ) -> Result { - let mut emitted_any = false; - - let mut queued_envelopes = Vec::new(); - { - let pending_capacity = self.pending_process_event_capacity(); - let receiver = self.process_event_receiver.as_mut().ok_or_else(|| { - SidecarError::InvalidState(String::from("process event receiver unavailable")) - })?; - loop { - if queued_envelopes.len() >= pending_capacity { - if receiver.is_empty() { - break; - } - return Err(process_event_queue_overflow_error()); - } - match receiver.try_recv() { - Ok(envelope) => { - queued_envelopes.push(envelope); - emitted_any = true; - } - Err(tokio::sync::mpsc::error::TryRecvError::Empty) => break, - Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => break, - } - } - } - for envelope in queued_envelopes { - self.queue_pending_process_event(envelope)?; - } - - let vm_ids = self.vm_ids_for_scope(ownership)?; - for vm_id in vm_ids { - while let Some(vm) = self.vms.get(&vm_id) { - let connection_id = vm.connection_id.clone(); - let session_id = vm.session_id.clone(); - let process_ids = self - .vms - .get(&vm_id) - .map(|vm| vm.active_processes.keys().cloned().collect::>()) - .unwrap_or_default(); - let mut emitted_this_pass = false; - - for process_id in process_ids { - if self - .vms - .get(&vm_id) - .is_some_and(|vm| vm.detached_child_processes.contains(&process_id)) - { - continue; - } - enum ProcessPollResult { - Event(Box>), - RecoverClosedChannel, - } - let poll_result = { - let Some(vm) = self.vms.get_mut(&vm_id) else { - continue; - }; - let Some(process) = vm.active_processes.get_mut(&process_id) else { - continue; - }; - if let Some(event) = process.pending_execution_events.pop_front() { - ProcessPollResult::Event(Box::new(Some(event))) - } else { - match process.execution.poll_event(Duration::ZERO).await { - Ok(event) => ProcessPollResult::Event(Box::new(event)), - Err(SidecarError::Execution(message)) - if (process.runtime == GuestRuntimeKind::JavaScript - && closed_javascript_event_channel(&message)) - || (process.runtime == GuestRuntimeKind::Python - && closed_python_event_channel(&message)) - || (process.runtime == GuestRuntimeKind::WebAssembly - && closed_wasm_event_channel(&message)) => - { - ProcessPollResult::RecoverClosedChannel - } - Err(other) => return Err(other), - } - } - }; - let event = match poll_result { - ProcessPollResult::Event(event) => *event, - ProcessPollResult::RecoverClosedChannel => { - self.recover_closed_root_runtime_process_event(&vm_id, &process_id)? - } - }; - - let Some(event) = event else { - continue; - }; - if matches!(&event, ActiveExecutionEvent::Exited(_)) { - record_execute_response_to_exit_milestone( - "execute_response_to_exit_event_polled", - &vm_id, - &process_id, - ); - } - - if Self::internal_execution_event(&event) { - // These events are sidecar work items, not client-facing - // process events. Handle them immediately so a sibling - // process can service sync RPCs while another request - // waits on VM-local networking. - self.handle_execution_event(&vm_id, &process_id, event)?; - } else { - self.queue_pending_process_event(ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - process_id: process_id.clone(), - event, - })?; - } - emitted_any = true; - emitted_this_pass = true; - } - - if !emitted_this_pass { - break; - } - } - - if self.pump_detached_child_process_events(&vm_id)? { - emitted_any = true; - } - } - - Ok(emitted_any) - } - - fn internal_execution_event(event: &ActiveExecutionEvent) -> bool { - matches!( - event, - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } - ) - } - - fn recover_closed_root_runtime_process_event( - &mut self, - vm_id: &str, - process_id: &str, - ) -> Result, SidecarError> { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(None); - }; - let Some(process) = vm.active_processes.get(process_id) else { - return Ok(None); - }; - if process.execution.uses_shared_v8_runtime() { - return Ok(None); - } - if process.runtime != GuestRuntimeKind::JavaScript - && process.runtime != GuestRuntimeKind::Python - && process.runtime != GuestRuntimeKind::WebAssembly - { - return Ok(None); - } - let runtime_child_pid = process.execution.child_pid(); - if runtime_child_pid == 0 { - return Ok(None); - } - if let Some(status) = runtime_child_exit_status(runtime_child_pid)? { - return Ok(Some(ActiveExecutionEvent::Exited(status))); - } - if runtime_child_is_alive(runtime_child_pid)? { - return Ok(None); - } - Ok(Some(ActiveExecutionEvent::Exited(0))) - } - - fn active_process_by_path<'a>( - process: &'a ActiveProcess, - child_path: &[&str], - ) -> Option<&'a ActiveProcess> { - let mut current = process; - for child_id in child_path { - current = current.child_processes.get(*child_id)?; - } - Some(current) - } - - fn active_process_by_path_mut<'a>( - process: &'a mut ActiveProcess, - child_path: &[&str], - ) -> Option<&'a mut ActiveProcess> { - let mut current = process; - for child_id in child_path { - current = current.child_processes.get_mut(*child_id)?; - } - Some(current) - } - - fn active_process_by_owned_path_mut<'a>( - process: &'a mut ActiveProcess, - child_path: &[String], - ) -> Option<&'a mut ActiveProcess> { - let mut current = process; - for child_id in child_path { - current = current.child_processes.get_mut(child_id)?; - } - Some(current) - } - - fn active_process_path_by_kernel_pid( - process: &ActiveProcess, - kernel_pid: u32, - ) -> Option> { - if process.kernel_pid == kernel_pid { - return Some(Vec::new()); - } - - for (child_id, child) in &process.child_processes { - let Some(mut path) = Self::active_process_path_by_kernel_pid(child, kernel_pid) else { - continue; - }; - path.insert(0, child_id.clone()); - return Some(path); - } - - None - } - - fn descendant_parent_process<'a>( - vm: &'a VmState, - process_id: &str, - child_path: &[&str], - ) -> Option<&'a ActiveProcess> { - let root = vm.active_processes.get(process_id)?; - Self::active_process_by_path(root, child_path) - } - - fn descendant_parent_process_mut<'a>( - vm: &'a mut VmState, - process_id: &str, - child_path: &[&str], - ) -> Option<&'a mut ActiveProcess> { - let root = vm.active_processes.get_mut(process_id)?; - Self::active_process_by_path_mut(root, child_path) - } - - fn child_process_path_label(process_id: &str, child_path: &[&str]) -> String { - if child_path.is_empty() { - process_id.to_owned() - } else { - format!("{process_id}/{}", child_path.join("/")) - } - } - - fn adopt_detached_child_processes( - current_process_id: &str, - process: &mut ActiveProcess, - ) -> Vec<(String, ActiveProcess)> { - let mut adopted = Vec::new(); - let child_ids = process.child_processes.keys().cloned().collect::>(); - for child_id in child_ids { - let child_process_id = format!("{current_process_id}/{child_id}"); - let Some(mut child) = process.child_processes.remove(&child_id) else { - continue; - }; - if child.detached { - adopted.push((child_process_id, child)); - continue; - } - - adopted.extend(Self::adopt_detached_child_processes( - &child_process_id, - &mut child, - )); - process.child_processes.insert(child_id, child); - } - adopted - } - - fn child_process_signal_key<'a>(process_id: &'a str, child_path: &[&'a str]) -> &'a str { - child_path.last().copied().unwrap_or(process_id) - } - - fn resolve_detached_child_process_path( - vm: &VmState, - detached_process_id: &str, - ) -> Option<(String, Vec)> { - let root_process_id = vm - .active_processes - .keys() - .filter(|candidate| { - detached_process_id == candidate.as_str() - || detached_process_id - .strip_prefix(candidate.as_str()) - .is_some_and(|remainder| remainder.starts_with('/')) - }) - .max_by_key(|candidate| candidate.len())? - .clone(); - - let remainder = detached_process_id - .strip_prefix(root_process_id.as_str()) - .unwrap_or_default(); - if remainder.is_empty() { - return Some((root_process_id, Vec::new())); - } - - Some(( - root_process_id, - remainder - .trim_start_matches('/') - .split('/') - .map(str::to_owned) - .collect(), - )) - } - - fn pump_detached_child_process_events(&mut self, vm_id: &str) -> Result { - let detached_process_ids = self - .vms - .get(vm_id) - .map(|vm| { - vm.detached_child_processes - .iter() - .cloned() - .collect::>() - }) - .unwrap_or_default(); - let mut emitted_any = false; - for detached_process_id in detached_process_ids { - let Some((root_process_id, child_path)) = self - .vms - .get(vm_id) - .and_then(|vm| Self::resolve_detached_child_process_path(vm, &detached_process_id)) - else { - if let Some(vm) = self.vms.get_mut(vm_id) { - vm.detached_child_processes.remove(&detached_process_id); - } - continue; - }; - if child_path.is_empty() { - loop { - enum ProcessPollResult { - Event(Box>), - RecoverClosedChannel, - } - let poll_result = { - let Some(vm) = self.vms.get_mut(vm_id) else { - break; - }; - let Some(process) = vm.active_processes.get_mut(&root_process_id) else { - break; - }; - if let Some(event) = process.pending_execution_events.pop_front() { - ProcessPollResult::Event(Box::new(Some(event))) - } else { - match process.execution.poll_event_blocking(Duration::ZERO) { - Ok(event) => ProcessPollResult::Event(Box::new(event)), - Err(SidecarError::Execution(message)) - if (process.runtime == GuestRuntimeKind::JavaScript - && closed_javascript_event_channel(&message)) - || (process.runtime == GuestRuntimeKind::Python - && closed_python_event_channel(&message)) - || (process.runtime == GuestRuntimeKind::WebAssembly - && closed_wasm_event_channel(&message)) => - { - ProcessPollResult::RecoverClosedChannel - } - Err(error) => return Err(error), - } - } - }; - let event = match poll_result { - ProcessPollResult::Event(event) => *event, - ProcessPollResult::RecoverClosedChannel => { - self.recover_closed_root_runtime_process_event(vm_id, &root_process_id)? - } - }; - let Some(event) = event else { - break; - }; - if matches!(&event, ActiveExecutionEvent::Exited(_)) { - record_execute_response_to_exit_milestone( - "execute_response_to_detached_exit_event_polled", - vm_id, - &detached_process_id, - ); - } - let Some((connection_id, session_id)) = self - .vms - .get(vm_id) - .map(|vm| (vm.connection_id.clone(), vm.session_id.clone())) - else { - break; - }; - match event { - ActiveExecutionEvent::Stdout(chunk) => { - self.queue_pending_process_event(ProcessEventEnvelope { - connection_id, - session_id, - vm_id: vm_id.to_owned(), - process_id: detached_process_id.clone(), - event: ActiveExecutionEvent::Stdout(chunk), - })?; - emitted_any = true; - } - ActiveExecutionEvent::Stderr(chunk) => { - self.queue_pending_process_event(ProcessEventEnvelope { - connection_id, - session_id, - vm_id: vm_id.to_owned(), - process_id: detached_process_id.clone(), - event: ActiveExecutionEvent::Stderr(chunk), - })?; - emitted_any = true; - } - ActiveExecutionEvent::Exited(exit_code) => { - if let Some(vm) = self.vms.get_mut(vm_id) { - vm.detached_child_processes.remove(&detached_process_id); - } - self.queue_pending_process_event(ProcessEventEnvelope { - connection_id, - session_id, - vm_id: vm_id.to_owned(), - process_id: detached_process_id.clone(), - event: ActiveExecutionEvent::Exited(exit_code), - })?; - emitted_any = true; - break; - } - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) => { - self.handle_javascript_sync_rpc_request( - vm_id, - &root_process_id, - request, - )?; - } - ActiveExecutionEvent::PythonVfsRpcRequest(request) => { - self.handle_python_vfs_rpc_request(vm_id, &root_process_id, *request)?; - } - ActiveExecutionEvent::SignalState { - signal, - registration, - } => { - if let Some(vm) = self.vms.get_mut(vm_id) { - vm.signal_states - .entry(root_process_id.clone()) - .or_default() - .insert(signal, registration); - } - } - } - } - continue; - } - - let parent_path = child_path[..child_path.len() - 1] - .iter() - .map(String::as_str) - .collect::>(); - let child_process_id = child_path.last().expect("child path cannot be empty"); - - loop { - let event = match self.poll_descendant_javascript_child_process( - vm_id, - &root_process_id, - &parent_path, - child_process_id, - 0, - ) { - Ok(event) => event, - Err(SidecarError::InvalidState(message)) - if message.contains("unknown child process") - || message.contains("unknown child process path") => - { - if let Some(vm) = self.vms.get_mut(vm_id) { - vm.detached_child_processes.remove(&detached_process_id); - } - break; - } - Err(error) if is_javascript_child_process_gone_error(&error) => { - if let Some(vm) = self.vms.get_mut(vm_id) { - vm.detached_child_processes.remove(&detached_process_id); - } - break; - } - Err(error) => return Err(error), - }; - - let Some(event_type) = event.get("type").and_then(Value::as_str) else { - break; - }; - let Some((connection_id, session_id)) = self - .vms - .get(vm_id) - .map(|vm| (vm.connection_id.clone(), vm.session_id.clone())) - else { - break; - }; - - let envelope = match event_type { - "stdout" => Some(ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.to_owned(), - process_id: detached_process_id.clone(), - event: ActiveExecutionEvent::Stdout(javascript_sync_rpc_bytes_arg( - &[event.get("data").cloned().unwrap_or(Value::Null)], - 0, - "detached child_process stdout", - )?), - }), - "stderr" => Some(ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.to_owned(), - process_id: detached_process_id.clone(), - event: ActiveExecutionEvent::Stderr(javascript_sync_rpc_bytes_arg( - &[event.get("data").cloned().unwrap_or(Value::Null)], - 0, - "detached child_process stderr", - )?), - }), - "exit" => { - if let Some(vm) = self.vms.get_mut(vm_id) { - vm.detached_child_processes.remove(&detached_process_id); - } - Some(ProcessEventEnvelope { - connection_id, - session_id, - vm_id: vm_id.to_owned(), - process_id: detached_process_id.clone(), - event: ActiveExecutionEvent::Exited( - event - .get("exitCode") - .and_then(Value::as_i64) - .map(|value| value as i32) - .unwrap_or(1), - ), - }) - } - _ => None, - }; - - let Some(envelope) = envelope else { - break; - }; - self.queue_pending_process_event(envelope)?; - emitted_any = true; - - if event_type == "exit" { - break; - } - } - } - - Ok(emitted_any) - } - pub(crate) fn drain_queued_descendant_javascript_child_process_events( - &mut self, - vm_id: &str, - process_id: &str, - child_path: &[&str], - ) -> Result<(), SidecarError> { - if child_path.is_empty() { - return Ok(()); - } - let target_process_id = Self::child_process_path_label(process_id, child_path); - let mut child_capacity = self - .vms - .get(vm_id) - .and_then(|vm| vm.active_processes.get(process_id)) - .and_then(|root| descendant_pending_execution_event_capacity(root, child_path)); - - let mut deferred = VecDeque::new(); - while let Some(envelope) = self.pending_process_events.pop_front() { - if envelope.vm_id == vm_id && envelope.process_id == target_process_id { - if matches!(child_capacity, Some(0)) { - self.pending_process_events.push_front(envelope); - while let Some(deferred_envelope) = deferred.pop_back() { - self.pending_process_events.push_front(deferred_envelope); - } - return Err(process_event_queue_overflow_error()); - } - if let Some(vm) = self.vms.get_mut(vm_id) { - if let Some(root) = vm.active_processes.get_mut(process_id) { - if let Some(child) = Self::active_process_by_path_mut(root, child_path) { - child.queue_pending_execution_event(envelope.event)?; - child_capacity = child_capacity.map(|capacity| capacity - 1); - continue; - } - } - } - } - deferred.push_back(envelope); - } - self.pending_process_events = deferred; - - let mut queued = Vec::new(); - { - let transfer_capacity = self - .pending_process_event_capacity() - .min(child_capacity.unwrap_or(usize::MAX)); - let receiver = self.process_event_receiver.as_mut().ok_or_else(|| { - SidecarError::InvalidState(String::from("process event receiver unavailable")) - })?; - loop { - if queued.len() >= transfer_capacity { - if receiver.is_empty() { - break; - } - return Err(process_event_queue_overflow_error()); - } - match receiver.try_recv() { - Ok(envelope) => queued.push(envelope), - Err(tokio::sync::mpsc::error::TryRecvError::Empty) => break, - Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => break, - } - } - } - for envelope in queued { - if envelope.vm_id == vm_id && envelope.process_id == target_process_id { - if let Some(vm) = self.vms.get_mut(vm_id) { - if let Some(root) = vm.active_processes.get_mut(process_id) { - if let Some(child) = Self::active_process_by_path_mut(root, child_path) { - child.queue_pending_execution_event(envelope.event)?; - continue; - } - } - } - } - self.queue_pending_process_event(envelope)?; - } - - Ok(()) - } - - pub(crate) fn handle_execution_event( - &mut self, - vm_id: &str, - process_id: &str, - event: ActiveExecutionEvent, - ) -> Result, SidecarError> { - let Some(vm) = self.vms.get(vm_id) else { - log_stale_process_event(&self.bridge, vm_id, process_id, "execution event dispatch"); - return Ok(None); - }; - if !vm.active_processes.contains_key(process_id) { - log_stale_process_event(&self.bridge, vm_id, process_id, "execution event dispatch"); - return Ok(None); - } - let (connection_id, session_id) = { (vm.connection_id.clone(), vm.session_id.clone()) }; - let ownership = OwnershipScope::vm(&connection_id, &session_id, vm_id); - - if self.capture_extension_process_output_event(vm_id, process_id, &event) { - return Ok(None); - } - - match event { - ActiveExecutionEvent::Stdout(chunk) => Ok(Some(EventFrame::new( - ownership, - EventPayload::ProcessOutput(ProcessOutputEvent { - process_id: process_id.to_owned(), - channel: StreamChannel::Stdout, - chunk, - }), - ))), - ActiveExecutionEvent::Stderr(chunk) => Ok(Some(EventFrame::new( - ownership, - EventPayload::ProcessOutput(ProcessOutputEvent { - process_id: process_id.to_owned(), - channel: StreamChannel::Stderr, - chunk, - }), - ))), - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) => { - self.handle_javascript_sync_rpc_request(vm_id, process_id, request)?; - Ok(None) - } - ActiveExecutionEvent::PythonVfsRpcRequest(request) => { - self.handle_python_vfs_rpc_request(vm_id, process_id, *request)?; - Ok(None) - } - ActiveExecutionEvent::SignalState { - signal, - registration, - } => { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(None); - }; - if !vm.active_processes.contains_key(process_id) { - return Ok(None); - } - vm.signal_states - .entry(process_id.to_owned()) - .or_default() - .insert(signal, registration); - Ok(None) - } - ActiveExecutionEvent::Exited(exit_code) => { - record_execute_response_to_exit_milestone( - "execute_response_to_exit_event_handle", - vm_id, - process_id, - ); - record_execute_response_to_exit(vm_id, process_id); - let phase_start = Instant::now(); - let became_idle = self - .finish_active_process_exit(vm_id, process_id, exit_code)? - .unwrap_or(false); - record_execute_phase("process_exit_cleanup", phase_start.elapsed()); - - let phase_start = Instant::now(); - if became_idle { - self.bridge.emit_lifecycle(vm_id, LifecycleState::Ready)?; - } - record_execute_phase("process_exit_lifecycle_emit", phase_start.elapsed()); - - Ok(Some(EventFrame::new( - ownership, - EventPayload::ProcessExited(ProcessExitedEvent { - process_id: process_id.to_owned(), - exit_code, - }), - ))) - } - } - } - - pub(crate) fn finish_active_process_exit( - &mut self, - vm_id: &str, - process_id: &str, - exit_code: i32, - ) -> Result, SidecarError> { - let Some(vm) = self.vms.get_mut(vm_id) else { - log_stale_process_event(&self.bridge, vm_id, process_id, "process exit cleanup"); - return Ok(None); - }; - if !vm.active_processes.contains_key(process_id) { - log_stale_process_event(&self.bridge, vm_id, process_id, "process exit cleanup"); - return Ok(None); - } - - let phase_start = Instant::now(); - prune_exited_process_snapshots(vm); - record_execute_phase( - "process_exit_cleanup_prune_snapshots", - phase_start.elapsed(), - ); - let phase_start = Instant::now(); - let process_table = vm.kernel.list_processes(); - record_execute_phase("process_exit_cleanup_list_processes", phase_start.elapsed()); - let phase_start = Instant::now(); - let Some(mut process) = vm.active_processes.remove(process_id) else { - return Ok(None); - }; - record_execute_phase("process_exit_cleanup_remove_active", phase_start.elapsed()); - let phase_start = Instant::now(); - if let Some(info) = process_table.get(&process.kernel_pid) { - vm.exited_process_snapshots - .push_back(ExitedProcessSnapshot { - captured_at: Instant::now(), - process: build_process_snapshot_entry( - process_id, - &process, - info, - Some(exit_code), - ), - }); - } - record_execute_phase("process_exit_cleanup_build_snapshot", phase_start.elapsed()); - let phase_start = Instant::now(); - let detached_children = Self::adopt_detached_child_processes(process_id, &mut process); - record_execute_phase("process_exit_cleanup_adopt_detached", phase_start.elapsed()); - let phase_start = Instant::now(); - let should_sync_host_writes = process.host_write_dirty_recursive() - || !process.clean_host_writes_are_observable_recursive(); - if should_sync_host_writes { - sync_process_host_writes_to_kernel(vm, &process)?; - } else { - record_execute_phase( - "process_exit_cleanup_sync_host_writes_clean_skip", - Duration::ZERO, - ); - } - record_execute_phase( - "process_exit_cleanup_sync_host_writes", - phase_start.elapsed(), - ); - let phase_start = Instant::now(); - let kernel_readiness = Arc::clone(&vm.kernel_socket_readiness); - terminate_child_process_tree(&mut vm.kernel, &mut process, &kernel_readiness); - record_execute_phase( - "process_exit_cleanup_terminate_child_tree", - phase_start.elapsed(), - ); - let phase_start = Instant::now(); - process.kernel_handle.finish(exit_code); - record_execute_phase("process_exit_cleanup_kernel_finish", phase_start.elapsed()); - let phase_start = Instant::now(); - let _ = vm.kernel.wait_and_reap(process.kernel_pid); - record_execute_phase("process_exit_cleanup_wait_and_reap", phase_start.elapsed()); - let phase_start = Instant::now(); - vm.signal_states.remove(process_id); - record_execute_phase( - "process_exit_cleanup_signal_state_remove", - phase_start.elapsed(), - ); - let phase_start = Instant::now(); - for (detached_process_id, detached_child) in detached_children { - vm.detached_child_processes - .insert(detached_process_id.clone()); - vm.active_processes - .insert(detached_process_id, detached_child); - } - record_execute_phase( - "process_exit_cleanup_reinsert_detached", - phase_start.elapsed(), - ); - let phase_start = Instant::now(); - let became_idle = vm.active_processes.is_empty(); - record_execute_phase("process_exit_cleanup_became_idle", phase_start.elapsed()); - let phase_start = Instant::now(); - self.prune_extension_process_resource(process_id); - record_execute_phase("process_exit_cleanup_prune_resource", phase_start.elapsed()); - - Ok(Some(became_idle)) - } - - pub(crate) fn drain_process_events_blocking_with_limit( - &mut self, - vm_id: &str, - process_id: &str, - max_events: usize, - ) -> Result, SidecarError> { - let mut events = Vec::new(); - if max_events == 0 { - return Ok(events); - } - let mut deadline = Instant::now() + PROCESS_EXIT_DRAIN_INITIAL_QUIET; - - loop { - if events.len() >= max_events { - break; - } - let event = { - let Some(vm) = self.vms.get_mut(vm_id) else { - break; - }; - let Some(process) = vm.active_processes.get_mut(process_id) else { - break; - }; - if let Some(event) = process.pending_execution_events.pop_front() { - Some(event) - } else { - match process.execution.poll_event_blocking(Duration::ZERO) { - Ok(event) => event, - Err(SidecarError::Execution(_)) => None, - Err(other) => return Err(other), - } - } - }; - - let Some(event) = event else { - if Instant::now() >= deadline { - break; - } - let blocking_wait = deadline.saturating_duration_since(Instant::now()); - if blocking_wait.is_zero() { - break; - } - if events.len() >= max_events { - break; - } - let delayed_event = { - let Some(vm) = self.vms.get_mut(vm_id) else { - break; - }; - let Some(process) = vm.active_processes.get_mut(process_id) else { - break; - }; - if let Some(event) = process.pending_execution_events.pop_front() { - Some(event) - } else { - match process.execution.poll_event_blocking(blocking_wait) { - Ok(event) => event, - Err(SidecarError::Execution(_)) => None, - Err(other) => return Err(other), - } - } - }; - let Some(event) = delayed_event else { - break; - }; - events.push(event); - deadline = Instant::now() + PROCESS_EXIT_DRAIN_TRAILING_QUIET; - continue; - }; - events.push(event); - deadline = Instant::now() + PROCESS_EXIT_DRAIN_TRAILING_QUIET; - } - - Ok(events) - } - - pub(crate) fn handle_python_vfs_rpc_request( - &mut self, - vm_id: &str, - process_id: &str, - request: PythonVfsRpcRequest, - ) -> Result<(), SidecarError> { - match request.method { - PythonVfsRpcMethod::Read - | PythonVfsRpcMethod::Write - | PythonVfsRpcMethod::Stat - | PythonVfsRpcMethod::Lstat - | PythonVfsRpcMethod::ReadDir - | PythonVfsRpcMethod::Mkdir - | PythonVfsRpcMethod::Unlink - | PythonVfsRpcMethod::Rmdir - | PythonVfsRpcMethod::Rename - | PythonVfsRpcMethod::Symlink - | PythonVfsRpcMethod::ReadLink - | PythonVfsRpcMethod::Setattr => { - filesystem_handle_python_vfs_rpc_request(self, vm_id, process_id, request) - } - PythonVfsRpcMethod::HttpRequest => { - self.handle_python_http_rpc_request(vm_id, process_id, request) - } - PythonVfsRpcMethod::DnsLookup => { - self.handle_python_dns_rpc_request(vm_id, process_id, request) - } - PythonVfsRpcMethod::SubprocessRun => { - self.handle_python_subprocess_rpc_request(vm_id, process_id, request) - } - PythonVfsRpcMethod::SocketConnect - | PythonVfsRpcMethod::SocketSend - | PythonVfsRpcMethod::SocketRecv - | PythonVfsRpcMethod::SocketClose - | PythonVfsRpcMethod::UdpCreate - | PythonVfsRpcMethod::UdpSendto - | PythonVfsRpcMethod::UdpRecvfrom => { - self.handle_python_socket_rpc_request(vm_id, process_id, request) - } - } - } - - fn handle_python_http_rpc_request( - &mut self, - vm_id: &str, - process_id: &str, - request: PythonVfsRpcRequest, - ) -> Result<(), SidecarError> { - let Some(vm) = self.vms.get(vm_id) else { - return Ok(()); - }; - if !vm.active_processes.contains_key(process_id) { - return Ok(()); - } - let response = (|| { - let url_text = request.url.as_deref().ok_or_else(|| { - SidecarError::InvalidState(String::from("python httpRequest requires a url")) - })?; - let url = Url::parse(url_text) - .map_err(|error| SidecarError::Execution(format!("ERR_INVALID_URL: {error}")))?; - let host = url.host_str().ok_or_else(|| { - SidecarError::Execution(String::from("ERR_INVALID_URL: missing host")) - })?; - let port = url.port_or_known_default().ok_or_else(|| { - SidecarError::Execution(String::from("ERR_INVALID_URL: missing port")) - })?; - self.bridge.require_network_access( - vm_id, - NetworkOperation::Http, - format_tcp_resource(host, port), - )?; - // Pin the outbound connection to the IP addresses that pass the - // egress range guard at resolution time. A literal IP is validated - // directly; a hostname is resolved once here and the resulting - // address set is pinned into the HTTP client's resolver below so a - // rebinding DNS server cannot make the second (TLS/TCP) lookup land - // on a private/link-local/metadata IP that this check rejected. - let pinned_addresses = if let Ok(literal_ip) = host.parse::() { - filter_dns_safe_ip_addrs(vec![literal_ip], host)? - } else { - filter_dns_safe_ip_addrs( - resolve_dns_ip_addrs( - &self.bridge, - &vm.kernel, - vm_id, - &vm.dns, - host, - DnsLookupPolicy::SkipPermissions, - )?, - host, - )? - }; - let mut headers = BTreeMap::new(); - for (name, value) in &request.headers { - headers.insert(name.clone(), Value::String(value.clone())); - } - let options = JavascriptHttpRequestOptions { - method: Some( - request - .http_method - .clone() - .unwrap_or_else(|| String::from("GET")), - ), - headers, - body: request.body_base64.as_deref().map(|body| { - String::from_utf8( - base64::engine::general_purpose::STANDARD - .decode(body) - .unwrap_or_default(), - ) - .unwrap_or_default() - }), - reject_unauthorized: None, - }; - let headers = - parse_http_header_collection(&options.headers, "python httpRequest headers")?; - let response = - issue_outbound_http_request(&url, &options, &headers, &pinned_addresses)?; - let payload_json = response.as_str().ok_or_else(|| { - SidecarError::Execution(String::from( - "python httpRequest returned a non-string response payload", - )) - })?; - let payload: Value = serde_json::from_str(payload_json).map_err(|error| { - SidecarError::Execution(format!( - "python httpRequest response must be valid JSON: {error}" - )) - })?; - let header_map = payload - .get("headers") - .and_then(Value::as_array) - .map(|entries| { - let mut normalized = BTreeMap::>::new(); - for entry in entries { - let Some(pair) = entry.as_array() else { - continue; - }; - let Some(name) = pair.first().and_then(Value::as_str) else { - continue; - }; - let Some(value) = pair.get(1).and_then(Value::as_str) else { - continue; - }; - normalized - .entry(name.to_owned()) - .or_default() - .push(value.to_owned()); - } - normalized - }) - .unwrap_or_default(); - Ok(PythonVfsRpcResponsePayload::Http { - status: payload - .get("status") - .and_then(Value::as_u64) - .map(|value| value as u16) - .unwrap_or_default(), - reason: payload - .get("statusText") - .and_then(Value::as_str) - .unwrap_or_default() - .to_owned(), - url: payload - .get("url") - .and_then(Value::as_str) - .unwrap_or(url_text) - .to_owned(), - headers: header_map, - body_base64: payload - .get("body") - .and_then(Value::as_str) - .unwrap_or_default() - .to_owned(), - }) - })(); - - self.respond_python_rpc(vm_id, process_id, request.id, response) - } - - fn handle_python_dns_rpc_request( - &mut self, - vm_id: &str, - process_id: &str, - request: PythonVfsRpcRequest, - ) -> Result<(), SidecarError> { - let Some(vm) = self.vms.get(vm_id) else { - return Ok(()); - }; - if !vm.active_processes.contains_key(process_id) { - return Ok(()); - } - let response = (|| { - let hostname = request.hostname.as_deref().ok_or_else(|| { - SidecarError::InvalidState(String::from("python dnsLookup requires a hostname")) - })?; - let mut addresses = filter_dns_safe_ip_addrs( - resolve_dns_ip_addrs( - &self.bridge, - &vm.kernel, - vm_id, - &vm.dns, - hostname, - DnsLookupPolicy::CheckPermissions, - )?, - hostname, - )?; - if let Some(family) = request.family { - addresses.retain(|address| { - matches!((family, address), (4, IpAddr::V4(_)) | (6, IpAddr::V6(_))) - }); - } - Ok(PythonVfsRpcResponsePayload::DnsLookup { - addresses: addresses - .into_iter() - .map(|address| address.to_string()) - .collect(), - }) - })(); - - self.respond_python_rpc(vm_id, process_id, request.id, response) - } - - fn handle_python_subprocess_rpc_request( - &mut self, - vm_id: &str, - process_id: &str, - request: PythonVfsRpcRequest, - ) -> Result<(), SidecarError> { - let command = request.command.clone().ok_or_else(|| { - SidecarError::InvalidState(String::from("python subprocessRun requires a command")) - })?; - let (internal_bootstrap_env, cwd) = { - let Some(vm) = self.vms.get(vm_id) else { - return Ok(()); - }; - let Some(process) = vm.active_processes.get(process_id) else { - return Ok(()); - }; - let virtual_home = guest_virtual_home(vm); - let cwd = request.cwd.clone().or_else(|| { - guest_runtime_path_for_host_path( - &vm.guest_env, - &virtual_home, - &vm.host_cwd, - &process.host_cwd.to_string_lossy(), - ) - }); - ( - sanitize_javascript_child_process_internal_bootstrap_env(&vm.guest_env), - cwd, - ) - }; - let response = self - .spawn_javascript_child_process_sync( - vm_id, - process_id, - JavascriptChildProcessSpawnRequest { - command, - args: request.args.clone(), - options: JavascriptChildProcessSpawnOptions { - cwd, - env: request.env.clone(), - input: None, - internal_bootstrap_env, - shell: request.shell, - detached: false, - stdio: vec![ - String::from("pipe"), - String::from("pipe"), - String::from("pipe"), - ], - timeout: None, - kill_signal: None, - }, - }, - request.max_buffer, - ) - .map(|payload| PythonVfsRpcResponsePayload::SubprocessRun { - exit_code: payload - .get("code") - .and_then(Value::as_i64) - .map(|value| value as i32) - .unwrap_or(1), - stdout: payload - .get("stdout") - .and_then(Value::as_str) - .unwrap_or_default() - .to_owned(), - stderr: payload - .get("stderr") - .and_then(Value::as_str) - .unwrap_or_default() - .to_owned(), - max_buffer_exceeded: payload - .get("maxBufferExceeded") - .and_then(Value::as_bool) - .unwrap_or(false), - }); - - self.respond_python_rpc(vm_id, process_id, request.id, response) - } - - fn handle_python_socket_rpc_request( - &mut self, - vm_id: &str, - process_id: &str, - request: PythonVfsRpcRequest, - ) -> Result<(), SidecarError> { - if !self.vms.contains_key(vm_id) { - return Ok(()); - } - let response = self.python_socket_op(vm_id, process_id, &request); - self.respond_python_rpc(vm_id, process_id, request.id, response) - } - - fn python_socket_op( - &mut self, - vm_id: &str, - process_id: &str, - request: &PythonVfsRpcRequest, - ) -> Result { - match request.method { - PythonVfsRpcMethod::SocketConnect => { - let host = python_socket_host(request)?; - let port = python_socket_port(request)?; - self.check_python_socket_limit(vm_id)?; - self.bridge.require_network_access( - vm_id, - NetworkOperation::Http, - format_tcp_resource(&host, port), - )?; - let pinned = self.python_socket_pinned_addrs(vm_id, &host, port)?; - let stream = python_connect_tcp(&pinned, port)?; - stream - .set_read_timeout(Some(PYTHON_SOCKET_READ_POLL)) - .map_err(python_socket_io_error)?; - // Bound writes too: without a write timeout `write_all` on a - // stalled peer would block the shared event loop indefinitely. - stream - .set_write_timeout(Some(PYTHON_SOCKET_WRITE_TIMEOUT)) - .map_err(python_socket_io_error)?; - let socket_id = - self.store_python_socket(vm_id, process_id, PythonHostSocket::Tcp(stream))?; - Ok(PythonVfsRpcResponsePayload::SocketCreated { socket_id }) - } - PythonVfsRpcMethod::SocketSend => { - let data = python_socket_payload(request)?; - let socket = self.python_socket_mut(vm_id, process_id, request)?; - let PythonHostSocket::Tcp(stream) = socket else { - return Err(python_socket_kind_error("send", "TCP")); - }; - stream.write_all(&data).map_err(python_socket_io_error)?; - Ok(PythonVfsRpcResponsePayload::SocketSent { - bytes_sent: data.len(), - }) - } - PythonVfsRpcMethod::SocketRecv => { - let max = python_socket_recv_len(request); - let socket = self.python_socket_mut(vm_id, process_id, request)?; - let PythonHostSocket::Tcp(stream) = socket else { - return Err(python_socket_kind_error("recv", "TCP")); - }; - let mut buf = vec![0u8; max]; - match stream.read(&mut buf) { - Ok(0) => Ok(PythonVfsRpcResponsePayload::SocketReceived { - data_base64: String::new(), - closed: true, - timed_out: false, - }), - Ok(n) => Ok(PythonVfsRpcResponsePayload::SocketReceived { - data_base64: base64::engine::general_purpose::STANDARD.encode(&buf[..n]), - closed: false, - timed_out: false, - }), - Err(error) if python_socket_would_block(&error) => { - Ok(PythonVfsRpcResponsePayload::SocketReceived { - data_base64: String::new(), - closed: false, - timed_out: true, - }) - } - Err(error) => Err(python_socket_io_error(error)), - } - } - PythonVfsRpcMethod::SocketClose => { - self.remove_python_socket(vm_id, process_id, request); - Ok(PythonVfsRpcResponsePayload::Empty) - } - PythonVfsRpcMethod::UdpCreate => { - self.check_python_socket_limit(vm_id)?; - let socket = UdpSocket::bind("0.0.0.0:0").map_err(python_socket_io_error)?; - socket - .set_read_timeout(Some(PYTHON_SOCKET_READ_POLL)) - .map_err(python_socket_io_error)?; - let socket_id = - self.store_python_socket(vm_id, process_id, PythonHostSocket::Udp(socket))?; - Ok(PythonVfsRpcResponsePayload::SocketCreated { socket_id }) - } - PythonVfsRpcMethod::UdpSendto => { - let host = python_socket_host(request)?; - let port = python_socket_port(request)?; - let data = python_socket_payload(request)?; - self.bridge.require_network_access( - vm_id, - NetworkOperation::Http, - format_tcp_resource(&host, port), - )?; - let pinned = self.python_socket_pinned_addrs(vm_id, &host, port)?; - let target = pinned - .first() - .map(|ip| SocketAddr::new(*ip, port)) - .ok_or_else(|| { - SidecarError::Execution(format!("EAI_NONAME: cannot resolve {host}")) - })?; - let socket = self.python_socket_mut(vm_id, process_id, request)?; - let PythonHostSocket::Udp(udp) = socket else { - return Err(python_socket_kind_error("sendto", "UDP")); - }; - let sent = udp.send_to(&data, target).map_err(python_socket_io_error)?; - Ok(PythonVfsRpcResponsePayload::SocketSent { bytes_sent: sent }) - } - PythonVfsRpcMethod::UdpRecvfrom => { - let max = python_socket_recv_len(request); - let socket = self.python_socket_mut(vm_id, process_id, request)?; - let PythonHostSocket::Udp(udp) = socket else { - return Err(python_socket_kind_error("recvfrom", "UDP")); - }; - let mut buf = vec![0u8; max]; - match udp.recv_from(&mut buf) { - Ok((n, addr)) => Ok(PythonVfsRpcResponsePayload::UdpReceived { - data_base64: base64::engine::general_purpose::STANDARD.encode(&buf[..n]), - host: addr.ip().to_string(), - port: addr.port(), - timed_out: false, - }), - Err(error) if python_socket_would_block(&error) => { - Ok(PythonVfsRpcResponsePayload::UdpReceived { - data_base64: String::new(), - host: String::new(), - port: 0, - timed_out: true, - }) - } - Err(error) => Err(python_socket_io_error(error)), - } - } - _ => Err(SidecarError::InvalidState(String::from( - "non-socket python RPC reached the socket dispatcher unexpectedly", - ))), - } - } - - /// Resolve `host` to the egress-guard-approved IP set, then apply the same - /// loopback-connect gate the JS raw-TCP path uses (`filter_tcp_connect_ip_addrs`) - /// so a rebinding DNS server can't map an allowlisted hostname onto a - /// sidecar-local loopback port the VM policy didn't open. - fn python_socket_pinned_addrs( - &self, - vm_id: &str, - host: &str, - port: u16, - ) -> Result, SidecarError> { - let Some(vm) = self.vms.get(vm_id) else { - return Err(SidecarError::InvalidState(String::from( - "python socket op for unknown vm", - ))); - }; - let context = build_javascript_socket_path_context(vm)?; - if let Ok(literal_ip) = host.parse::() { - filter_tcp_connect_ip_addrs(vec![literal_ip], host, port, &context) - } else { - filter_tcp_connect_ip_addrs( - resolve_dns_ip_addrs( - &self.bridge, - &vm.kernel, - vm_id, - &vm.dns, - host, - DnsLookupPolicy::SkipPermissions, - )?, - host, - port, - &context, - ) - } - } - - /// Enforce the VM's `max_sockets` resource limit before opening another - /// host socket for the guest (the registry is otherwise unbounded — a - /// hostile guest could exhaust the sidecar's fds/memory). - fn check_python_socket_limit(&self, vm_id: &str) -> Result<(), SidecarError> { - let Some(vm) = self.vms.get(vm_id) else { - return Ok(()); - }; - let limit = vm.kernel.resource_limits().max_sockets; - let current = vm_network_resource_counts(vm).sockets; - check_network_resource_limit(limit, current, 1, "socket") - } - - fn store_python_socket( - &mut self, - vm_id: &str, - process_id: &str, - socket: PythonHostSocket, - ) -> Result { - let process = self - .vms - .get_mut(vm_id) - .and_then(|vm| vm.active_processes.get_mut(process_id)) - .ok_or_else(|| { - SidecarError::InvalidState(String::from("python socket op for reaped vm/process")) - })?; - let socket_id = process.next_python_socket_id; - process.next_python_socket_id = process.next_python_socket_id.wrapping_add(1); - process.python_sockets.insert(socket_id, socket); - Ok(socket_id) - } - - fn python_socket_mut( - &mut self, - vm_id: &str, - process_id: &str, - request: &PythonVfsRpcRequest, - ) -> Result<&mut PythonHostSocket, SidecarError> { - let socket_id = request.socket_id.ok_or_else(|| { - SidecarError::InvalidState(String::from("python socket op requires socketId")) - })?; - self.vms - .get_mut(vm_id) - .and_then(|vm| vm.active_processes.get_mut(process_id)) - .and_then(|process| process.python_sockets.get_mut(&socket_id)) - .ok_or_else(|| { - SidecarError::Execution(format!("EBADF: unknown python socket {socket_id}")) - }) - } - - fn remove_python_socket( - &mut self, - vm_id: &str, - process_id: &str, - request: &PythonVfsRpcRequest, - ) { - let Some(socket_id) = request.socket_id else { - return; - }; - if let Some(process) = self - .vms - .get_mut(vm_id) - .and_then(|vm| vm.active_processes.get_mut(process_id)) - { - process.python_sockets.remove(&socket_id); - } - } - - fn respond_python_rpc( - &mut self, - vm_id: &str, - process_id: &str, - request_id: u64, - response: Result, - ) -> Result<(), SidecarError> { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(()); - }; - let Some(process) = vm.active_processes.get_mut(process_id) else { - return Ok(()); - }; - let result = match response { - Ok(payload) => process - .execution - .respond_python_vfs_rpc_success(request_id, payload), - Err(error) => process.execution.respond_python_vfs_rpc_error( - request_id, - "ERR_AGENTOS_PYTHON_VFS_RPC", - error.to_string(), - ), - }; - match result { - Ok(()) => Ok(()), - Err(error) if is_broken_pipe_error(&error) => Ok(()), - Err(error) => Err(error), - } - } - - pub(crate) fn resolve_javascript_child_process_execution( - &self, - vm: &VmState, - parent_env: &BTreeMap, - parent_guest_cwd: &str, - parent_host_cwd: &Path, - request: &JavascriptChildProcessSpawnRequest, - ) -> Result { - let mut runtime_env = parent_env.clone(); - runtime_env.extend(request.options.internal_bootstrap_env.clone()); - let (guest_cwd, host_cwd_override) = request - .options - .cwd - .as_deref() - .map(|cwd| { - let normalized_parent_host_cwd = normalize_host_path(parent_host_cwd); - let requested_host_cwd = normalize_host_path(Path::new(cwd)); - if path_is_within_root(&requested_host_cwd, &normalized_parent_host_cwd) { - let relative = requested_host_cwd - .strip_prefix(&normalized_parent_host_cwd) - .unwrap_or_else(|_| Path::new("")); - let relative = relative.to_string_lossy().replace('\\', "/"); - let guest_cwd = if relative.is_empty() { - parent_guest_cwd.to_owned() - } else { - normalize_path(&format!("{parent_guest_cwd}/{relative}")) - }; - (guest_cwd, Some(requested_host_cwd)) - } else if Path::new(cwd).is_relative() { - ( - normalize_path(&format!("{parent_guest_cwd}/{cwd}")), - Some(normalize_host_path(&parent_host_cwd.join(cwd))), - ) - } else { - (normalize_path(cwd), None) - } - }) - .unwrap_or_else(|| (parent_guest_cwd.to_owned(), None)); - let inherited_host_cwd = (host_cwd_override.is_none() && guest_cwd == parent_guest_cwd) - .then(|| normalize_host_path(parent_host_cwd)); - let host_cwd = host_cwd_override - .or(inherited_host_cwd) - .or_else(|| { - host_runtime_path_for_guest_path_with_env( - vm, - &runtime_env, - &guest_cwd, - parent_host_cwd, - ) - }) - .unwrap_or_else(|| { - let candidate = PathBuf::from(&guest_cwd); - if guest_cwd == parent_guest_cwd { - normalize_host_path(parent_host_cwd) - } else if candidate.is_absolute() { - shadow_path_for_guest(vm, &guest_cwd) - } else { - vm.host_cwd.clone() - } - }); - let mut env = parent_env.clone(); - env.extend(request.options.env.clone()); - // Child JavaScript executions must resolve their own entrypoint/eval state. - // Reusing the parent's values makes the sidecar load the wrong source file. - env.remove("AGENTOS_GUEST_ENTRYPOINT"); - env.remove("AGENTOS_NODE_EVAL"); - - let (command, process_args) = if request.options.shell { - let tokens = tokenize_shell_free_command(&request.command); - let requires_shell = command_requires_shell(&request.command) - || tokens.first().is_some_and(|command| { - is_posix_shell_builtin(command) || shell_first_token_requires_shell(command) - }); - if requires_shell { - if !vm.command_guest_paths.contains_key("sh") { - return Err(SidecarError::InvalidState(format!( - "shell-mode child_process command requires /bin/sh, which is not \ - installed in this VM (install a software package that provides sh, \ - for example @secure-exec/coreutils): {}", - request.command - ))); - } - ( - String::from("sh"), - vec![String::from("-c"), request.command.clone()], - ) - } else { - let Some((command, args)) = tokens.split_first() else { - return Err(SidecarError::InvalidState(String::from( - "child_process shell command must not be empty", - ))); - }; - (command.clone(), args.to_vec()) - } - } else { - (request.command.clone(), request.args.clone()) - }; - let process_args = apply_shell_cwd_prefix(&command, process_args, &guest_cwd); - if is_tool_command(vm, &command) { - let command = normalized_tool_command_name(&command).unwrap_or(command); - return Ok(ResolvedChildProcessExecution { - command: command.clone(), - process_args: std::iter::once(command.clone()) - .chain(process_args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint: command, - execution_args: process_args, - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: true, - }); - } - - if is_path_like_specifier(&command) - && matches!( - Path::new(&command).extension().and_then(|ext| ext.to_str()), - Some("js" | "mjs" | "cjs" | "ts" | "mts" | "cts") - ) - { - let guest_entrypoint = if command.starts_with('/') { - normalize_path(&command) - } else if command.starts_with("file:") { - normalize_path(command.trim_start_matches("file:")) - } else { - normalize_path(&format!("{guest_cwd}/{command}")) - }; - let host_entrypoint = if command.starts_with("./") || command.starts_with("../") { - normalize_host_path(&host_cwd.join(&command)) - } else { - host_runtime_path_for_guest_path_with_env( - vm, - &runtime_env, - &guest_entrypoint, - parent_host_cwd, - ) - .unwrap_or_else(|| { - let candidate = PathBuf::from(&guest_entrypoint); - if candidate.is_absolute() { - candidate - } else { - host_cwd.join(&guest_entrypoint) - } - }) - }; - env.insert(String::from("AGENTOS_GUEST_ENTRYPOINT"), guest_entrypoint); - let guest_entrypoint = env.get("AGENTOS_GUEST_ENTRYPOINT").cloned(); - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, guest_entrypoint)?; - - return Ok(ResolvedChildProcessExecution { - command: command.clone(), - process_args: std::iter::once(command) - .chain(process_args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint: host_entrypoint.to_string_lossy().into_owned(), - execution_args: process_args, - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - if is_node_runtime_command(&command) { - if let Some(cli) = resolve_host_node_cli_entrypoint(&command) { - env.insert( - String::from("AGENTOS_NODE_EVAL"), - build_host_node_cli_eval(&cli), - ); - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, None)?; - add_runtime_guest_path_mapping(&mut env, &cli.guest_root, &cli.package_root); - add_runtime_host_access_path( - &mut env, - "AGENTOS_EXTRA_FS_READ_PATHS", - &cli.package_root, - true, - ); - - return Ok(ResolvedChildProcessExecution { - command: command.clone(), - process_args: std::iter::once(command.clone()) - .chain(process_args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint: String::from("-e"), - execution_args: std::iter::once(cli.guest_entrypoint.clone()) - .chain(process_args.iter().cloned()) - .collect(), - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - if process_args.is_empty() { - env.insert(String::from("AGENTOS_NODE_EVAL"), String::new()); - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, None)?; - - return Ok(ResolvedChildProcessExecution { - command: command.clone(), - process_args: vec![command.clone()], - runtime: GuestRuntimeKind::JavaScript, - entrypoint: String::from("-e"), - execution_args: Vec::new(), - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - if let Some((entrypoint, execution_args)) = - resolve_special_node_cli_invocation(&process_args, &mut env) - { - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, None)?; - - return Ok(ResolvedChildProcessExecution { - command: command.clone(), - process_args: std::iter::once(command.clone()) - .chain(process_args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint, - execution_args, - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - let Some(entrypoint_specifier) = process_args.first() else { - return Err(SidecarError::InvalidState(format!( - "{command} child_process spawn requires an entrypoint" - ))); - }; - - let (entrypoint, execution_args) = if is_path_like_specifier(entrypoint_specifier) { - let guest_entrypoint = if entrypoint_specifier.starts_with('/') { - normalize_path(entrypoint_specifier) - } else if entrypoint_specifier.starts_with("file:") { - normalize_path(entrypoint_specifier.trim_start_matches("file:")) - } else { - normalize_path(&format!("{guest_cwd}/{entrypoint_specifier}")) - }; - let host_entrypoint = if entrypoint_specifier.starts_with("./") - || entrypoint_specifier.starts_with("../") - { - normalize_host_path(&host_cwd.join(entrypoint_specifier)) - } else { - host_runtime_path_for_guest_path_with_env( - vm, - &runtime_env, - &guest_entrypoint, - parent_host_cwd, - ) - .unwrap_or_else(|| { - let candidate = PathBuf::from(&guest_entrypoint); - if candidate.is_absolute() { - candidate - } else { - host_cwd.join(&guest_entrypoint) - } - }) - }; - env.insert(String::from("AGENTOS_GUEST_ENTRYPOINT"), guest_entrypoint); - ( - host_entrypoint.to_string_lossy().into_owned(), - process_args.iter().skip(1).cloned().collect(), - ) - } else { - ( - entrypoint_specifier.clone(), - process_args.iter().skip(1).cloned().collect(), - ) - }; - let guest_entrypoint = env.get("AGENTOS_GUEST_ENTRYPOINT").cloned(); - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, guest_entrypoint)?; - - return Ok(ResolvedChildProcessExecution { - command: command.clone(), - process_args: std::iter::once(command) - .chain(process_args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint, - execution_args, - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - if is_python_runtime_command(&command) { - return resolve_python_command_execution( - vm, - &command, - &process_args, - env, - guest_cwd, - host_cwd, - ); - } - - let guest_entrypoint = resolve_guest_command_entrypoint( - vm, - &guest_cwd, - &command, - env.get("PATH").map(String::as_str), - ) - .ok_or_else(|| SidecarError::InvalidState(format!("command not found: {command}")))?; - let host_entrypoint = resolve_vm_guest_path_to_host(vm, &guest_entrypoint); - let wasm_permission_tier = vm.command_permissions.get(&command).copied().or_else(|| { - Path::new(&guest_entrypoint) - .file_name() - .and_then(|name| name.to_str()) - .and_then(|name| vm.command_permissions.get(name).copied()) - }); - if let Some((javascript_guest_entrypoint, javascript_host_entrypoint)) = - resolve_javascript_command_entrypoint(vm, &guest_entrypoint, &host_entrypoint) - { - prepare_guest_runtime_env( - vm, - &mut env, - &guest_cwd, - &host_cwd, - Some(javascript_guest_entrypoint), - )?; - - return Ok(ResolvedChildProcessExecution { - command: command.clone(), - process_args: std::iter::once(command) - .chain(process_args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint: javascript_host_entrypoint.to_string_lossy().into_owned(), - execution_args: process_args, - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - prepare_guest_runtime_env( - vm, - &mut env, - &guest_cwd, - &host_cwd, - Some(guest_entrypoint.clone()), - )?; - - Ok(ResolvedChildProcessExecution { - command: command.clone(), - process_args: std::iter::once(command) - .chain(process_args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::WebAssembly, - entrypoint: host_entrypoint.to_string_lossy().into_owned(), - execution_args: process_args, - env, - guest_cwd, - host_cwd, - wasm_permission_tier, - tool_command: false, - }) - } - - pub(crate) fn spawn_javascript_child_process( - &mut self, - vm_id: &str, - process_id: &str, - request: JavascriptChildProcessSpawnRequest, - ) -> Result { - let total_start = Instant::now(); - let phase_start = Instant::now(); - let resolved = { - let vm = self.vms.get(vm_id).ok_or_else(|| missing_vm_error(vm_id))?; - let parent = vm - .active_processes - .get(process_id) - .ok_or_else(|| missing_process_error(vm_id, process_id))?; - self.resolve_javascript_child_process_execution( - vm, - &parent.env, - &parent.guest_cwd, - &parent.host_cwd, - &request, - )? - }; - record_execute_phase("child_process_resolve_execution", phase_start.elapsed()); - let (parent_kernel_pid, child_process_id) = { - let vm = self - .vms - .get_mut(vm_id) - .ok_or_else(|| missing_vm_error(vm_id))?; - let process = vm - .active_processes - .get_mut(process_id) - .ok_or_else(|| missing_process_error(vm_id, process_id))?; - (process.kernel_pid, process.allocate_child_process_id()) - }; - let sidecar_requests = self.sidecar_requests.clone(); - let vm = self - .vms - .get_mut(vm_id) - .ok_or_else(|| missing_vm_error(vm_id))?; - let phase_start = Instant::now(); - let (kernel_pid, kernel_handle, execution, kernel_stdin_writer_fd) = if resolved - .tool_command - { - let tool_resolution = resolve_tool_command( - vm, - &resolved.command, - &resolved.execution_args, - Some(&resolved.guest_cwd), - )? - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "tool command no longer resolves: {}", - resolved.command - )) - })?; - let kernel_handle = vm - .kernel - .create_virtual_process( - EXECUTION_DRIVER_NAME, - TOOL_DRIVER_NAME, - &resolved.command, - resolved.process_args.clone(), - VirtualProcessOptions { - parent_pid: Some(parent_kernel_pid), - env: resolved.env.clone(), - cwd: Some(resolved.guest_cwd.clone()), - }, - ) - .map_err(kernel_error)?; - let kernel_pid = kernel_handle.pid(); - let tool_execution = ToolExecution::default(); - let cancelled = tool_execution.cancelled.clone(); - let pending_events = tool_execution.pending_events.clone(); - let events_overflowed = tool_execution.events_overflowed.clone(); - spawn_tool_process_events(ToolProcessEventRequest { - sidecar_requests: sidecar_requests.clone(), - connection_id: vm.connection_id.clone(), - session_id: vm.session_id.clone(), - vm_id: vm_id.to_owned(), - tool_resolution, - cancelled, - pending_events, - events_overflowed, - }); - ( - kernel_pid, - kernel_handle, - ActiveExecution::Tool(tool_execution), - None, - ) - } else { - let kernel_command = match resolved.runtime { - GuestRuntimeKind::JavaScript => JAVASCRIPT_COMMAND, - GuestRuntimeKind::WebAssembly => WASM_COMMAND, - GuestRuntimeKind::Python => PYTHON_COMMAND, - }; - let kernel_handle = vm - .kernel - .spawn_process( - kernel_command, - resolved.process_args.clone(), - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - parent_pid: Some(parent_kernel_pid), - env: resolved.env.clone(), - cwd: Some(resolved.guest_cwd.clone()), - }, - ) - .map_err(kernel_error)?; - let kernel_pid = kernel_handle.pid(); - if request.options.detached { - vm.kernel - .setsid(EXECUTION_DRIVER_NAME, kernel_pid) - .map_err(kernel_error)?; - } - let mut execution_env = resolved.env.clone(); - execution_env.insert( - String::from(EXECUTION_SANDBOX_ROOT_ENV), - normalize_host_path(&vm.cwd).to_string_lossy().into_owned(), - ); - - let execution = match resolved.runtime { - GuestRuntimeKind::JavaScript => { - execution_env.extend(sanitize_javascript_child_process_internal_bootstrap_env( - &request.options.internal_bootstrap_env, - )); - execution_env.insert( - String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - ); - let launch_entrypoint = resolve_agentos_package_javascript_launch_entrypoint( - vm, - &mut execution_env, - ) - .unwrap_or_else(|| resolved.entrypoint.clone()); - let context = - self.javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.to_owned(), - bootstrap_module: None, - compile_cache_root: Some( - self.cache_root.join("node-compile-cache"), - ), - }); - let inline_code = load_javascript_entrypoint_source( - vm, - &resolved.host_cwd, - &launch_entrypoint, - &execution_env, - ); - prepare_javascript_shadow(vm, &resolved, &execution_env)?; - - let built_reader = build_module_reader(vm, &resolved); - let guest_reader = built_reader.clone().map(|reader| { - Box::new(crate::plugins::host_dir::SessionModuleReader::new(reader)) - as Box - }); - let module_reader = built_reader - .map(|reader| Box::new(reader) as Box); - let execution = self - .javascript_engine - .start_execution_with_module_reader( - StartJavascriptExecutionRequest { - guest_runtime: guest_runtime_identity( - vm, - Some(u64::from(kernel_pid)), - Some(u64::from(parent_kernel_pid)), - ), - vm_id: vm_id.to_owned(), - context_id: context.context_id, - argv: std::iter::once(launch_entrypoint) - .chain(resolved.execution_args.clone()) - .collect(), - env: execution_env, - cwd: resolved.host_cwd.clone(), - limits: javascript_execution_limits(vm), - inline_code, - wasm_module_bytes: None, - }, - module_reader, - guest_reader, - ) - .map_err(javascript_error)?; - ActiveExecution::Javascript(execution) - } - GuestRuntimeKind::WebAssembly => { - execution_env.insert(String::from(WASM_STDIO_SYNC_RPC_ENV), String::from("1")); - let wasm_limits = wasm_execution_limits(vm); - let wasm_guest_runtime = guest_runtime_identity( - vm, - Some(u64::from(kernel_pid)), - Some(u64::from(parent_kernel_pid)), - ); - let context = self.wasm_engine.create_context(CreateWasmContextRequest { - vm_id: vm_id.to_owned(), - module_path: Some(resolved.entrypoint.clone()), - }); - let execution = self - .wasm_engine - .start_execution(StartWasmExecutionRequest { - vm_id: vm_id.to_owned(), - context_id: context.context_id, - argv: resolved.process_args.clone(), - env: execution_env, - cwd: resolved.host_cwd.clone(), - permission_tier: execution_wasm_permission_tier( - resolved - .wasm_permission_tier - .unwrap_or(WasmPermissionTier::Full), - ), - limits: wasm_limits, - guest_runtime: wasm_guest_runtime, - }) - .map_err(wasm_error)?; - ActiveExecution::Wasm(Box::new(execution)) - } - GuestRuntimeKind::Python => { - // Nested `python` child_process: set up the Pyodide context the - // same way the top-level execute path does, so a guest shell or - // node parent can spawn `python` exactly like `node`. - let python_file_path = if execution_env.contains_key("AGENTOS_PYTHON_ARGV") { - execution_env.get("AGENTOS_PYTHON_FILE").map(PathBuf::from) - } else { - python_file_entrypoint(&resolved.entrypoint) - }; - let pyodide_dist_path = self - .python_engine - .bundled_pyodide_dist_path_for_vm(vm_id) - .map_err(python_error)?; - let pyodide_cache_path = pyodide_dist_path - .parent() - .and_then(Path::parent) - .unwrap_or(pyodide_dist_path.as_path()) - .join("pyodide-package-cache"); - add_runtime_guest_path_mapping( - &mut execution_env, - PYTHON_PYODIDE_GUEST_ROOT, - &pyodide_dist_path, - ); - add_runtime_guest_path_mapping( - &mut execution_env, - PYTHON_PYODIDE_CACHE_GUEST_ROOT, - &pyodide_cache_path, - ); - add_runtime_host_access_path( - &mut execution_env, - "AGENTOS_EXTRA_FS_READ_PATHS", - &pyodide_dist_path, - true, - ); - add_runtime_host_access_path( - &mut execution_env, - "AGENTOS_EXTRA_FS_READ_PATHS", - &pyodide_cache_path, - true, - ); - add_runtime_host_access_path( - &mut execution_env, - "AGENTOS_EXTRA_FS_WRITE_PATHS", - &pyodide_cache_path, - false, - ); - let context = self - .python_engine - .create_context(CreatePythonContextRequest { - vm_id: vm_id.to_owned(), - pyodide_dist_path, - }); - let execution = self - .python_engine - .start_execution(StartPythonExecutionRequest { - vm_id: vm_id.to_owned(), - context_id: context.context_id, - code: resolved.entrypoint.clone(), - file_path: python_file_path, - env: execution_env, - cwd: resolved.host_cwd.clone(), - limits: python_execution_limits(vm), - guest_runtime: guest_runtime_identity( - vm, - Some(u64::from(kernel_pid)), - Some(u64::from(parent_kernel_pid)), - ), - }) - .map_err(python_error)?; - ActiveExecution::Python(execution) - } - }; - let kernel_stdin_writer_fd = match javascript_child_process_stdin_mode(&request) { - "pipe" => Some(install_kernel_stdin_pipe(&mut vm.kernel, kernel_pid)?), - "ignore" => { - vm.kernel - .fd_close(EXECUTION_DRIVER_NAME, kernel_pid, 0) - .map_err(kernel_error)?; - None - } - "inherit" => None, - _ => Some(install_kernel_stdin_pipe(&mut vm.kernel, kernel_pid)?), - }; - (kernel_pid, kernel_handle, execution, kernel_stdin_writer_fd) - }; - record_execute_phase( - "child_process_spawn_and_start_execution", - phase_start.elapsed(), - ); - - let phase_start = Instant::now(); - // Shared-terminal detection: when the child's kernel fd 1 is a PTY (the - // slave inherited from a TTY shell), record who owns the host-facing - // master so the child's stdio writes surface through master drains - // instead of child stdout events (see `tty_master_owner`). - let child_fd1_is_tty = vm - .kernel - .isatty(EXECUTION_DRIVER_NAME, kernel_pid, 1) - .unwrap_or(false); - let process = vm - .active_processes - .get_mut(process_id) - .ok_or_else(|| missing_process_error(vm_id, process_id))?; - let inherited_tty_master_owner = if child_fd1_is_tty { - process - .tty_master_fd - .map(|master_fd| (process.kernel_pid, master_fd)) - .or(process.tty_master_owner) - } else { - None - }; - process.child_processes.insert( - child_process_id.clone(), - ActiveProcess::new(kernel_pid, kernel_handle, resolved.runtime, execution) - .with_detached(request.options.detached) - .with_guest_cwd(resolved.guest_cwd.clone()) - .with_env(resolved.env.clone()) - .with_host_cwd(resolved.host_cwd.clone()), - ); - { - let child = process - .child_processes - .get_mut(&child_process_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "child process {child_process_id} disappeared during spawn" - )) - })?; - child.tty_master_owner = inherited_tty_master_owner; - if let Some(kernel_stdin_writer_fd) = kernel_stdin_writer_fd { - child.kernel_stdin_writer_fd = Some(kernel_stdin_writer_fd); - } - } - record_execute_phase("child_process_register", phase_start.elapsed()); - record_execute_phase("child_process_spawn_total", total_start.elapsed()); - Ok(json!({ - "childId": child_process_id, - "pid": kernel_pid, - "command": resolved.command, - "args": resolved.process_args, - })) - } - - pub(crate) fn spawn_javascript_child_process_sync( - &mut self, - vm_id: &str, - process_id: &str, - request: JavascriptChildProcessSpawnRequest, - max_buffer: Option, - ) -> Result { - let sync_input = javascript_child_process_sync_input_bytes(request.options.input.as_ref())?; - let timeout_deadline = request - .options - .timeout - .map(|timeout_ms| Instant::now() + Duration::from_millis(timeout_ms)); - let timeout_signal = request - .options - .kill_signal - .clone() - .unwrap_or_else(|| String::from("SIGTERM")); - let spawned = self.spawn_javascript_child_process(vm_id, process_id, request)?; - let child_process_id = spawned - .get("childId") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "child_process.spawn_sync response is missing childId", - )) - })? - .to_owned(); - - if let Some(input) = sync_input.as_deref() { - self.write_javascript_child_process_stdin(vm_id, process_id, &child_process_id, input)?; - } - self.close_javascript_child_process_stdin(vm_id, process_id, &child_process_id)?; - - let max_buffer = max_buffer.unwrap_or(1024 * 1024); - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut max_buffer_exceeded = false; - let mut kill_sent = false; - let mut timed_out = false; - - let exit_code = loop { - let wait_ms = if let Some(deadline) = timeout_deadline { - let now = Instant::now(); - if now >= deadline { - if !kill_sent { - timed_out = true; - self.kill_javascript_child_process( - vm_id, - process_id, - &child_process_id, - &timeout_signal, - )?; - kill_sent = true; - } - 0 - } else { - u64::try_from(deadline.saturating_duration_since(now).as_millis().min(50)) - .unwrap_or(50) - } - } else { - 50 - }; - let event = - self.poll_javascript_child_process(vm_id, process_id, &child_process_id, wait_ms)?; - if event.is_null() { - continue; - } - - match event.get("type").and_then(Value::as_str) { - Some("stdout") => { - let chunk = javascript_sync_rpc_bytes_arg( - &[event.get("data").cloned().unwrap_or(Value::Null)], - 0, - "child_process.spawn_sync stdout", - )?; - stdout.extend_from_slice(&chunk); - if stdout.len() > max_buffer && !kill_sent { - max_buffer_exceeded = true; - self.kill_javascript_child_process( - vm_id, - process_id, - &child_process_id, - "SIGTERM", - )?; - kill_sent = true; - } - } - Some("stderr") => { - let chunk = javascript_sync_rpc_bytes_arg( - &[event.get("data").cloned().unwrap_or(Value::Null)], - 0, - "child_process.spawn_sync stderr", - )?; - stderr.extend_from_slice(&chunk); - if stderr.len() > max_buffer && !kill_sent { - max_buffer_exceeded = true; - self.kill_javascript_child_process( - vm_id, - process_id, - &child_process_id, - "SIGTERM", - )?; - kill_sent = true; - } - } - Some("exit") => { - break event - .get("exitCode") - .and_then(Value::as_i64) - .map(|value| value as i32) - .unwrap_or(1); - } - _ => {} - } - }; - - Ok(json!({ - "stdout": String::from_utf8_lossy(&stdout), - "stderr": String::from_utf8_lossy(&stderr), - "code": exit_code, - "signal": if timed_out { Value::String(timeout_signal) } else { Value::Null }, - "timedOut": timed_out, - "maxBufferExceeded": max_buffer_exceeded, - })) - } - - fn spawn_descendant_javascript_child_process( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - request: JavascriptChildProcessSpawnRequest, - ) -> Result { - let total_start = Instant::now(); - let current_process_label = - Self::child_process_path_label(process_id, current_process_path); - let phase_start = Instant::now(); - let (resolved, parent_kernel_pid) = { - let vm = self.vms.get(vm_id).ok_or_else(|| missing_vm_error(vm_id))?; - let root = vm - .active_processes - .get(process_id) - .ok_or_else(|| missing_process_error(vm_id, process_id))?; - let parent = - Self::active_process_by_path(root, current_process_path).ok_or_else(|| { - SidecarError::InvalidState(format!( - "unknown child process path {current_process_label} during nested spawn" - )) - })?; - ( - self.resolve_javascript_child_process_execution( - vm, - &parent.env, - &parent.guest_cwd, - &parent.host_cwd, - &request, - )?, - parent.kernel_pid, - ) - }; - record_execute_phase("child_process_resolve_execution", phase_start.elapsed()); - - let sidecar_requests = self.sidecar_requests.clone(); - let vm = self - .vms - .get_mut(vm_id) - .ok_or_else(|| missing_vm_error(vm_id))?; - let phase_start = Instant::now(); - let child_process_id = { - let root = vm - .active_processes - .get_mut(process_id) - .ok_or_else(|| missing_process_error(vm_id, process_id))?; - let parent = - Self::active_process_by_path_mut(root, current_process_path).ok_or_else(|| { - SidecarError::InvalidState(format!( - "unknown child process path {current_process_label} during nested spawn" - )) - })?; - parent.allocate_child_process_id() - }; - let mut child_path = current_process_path.to_vec(); - child_path.push(child_process_id.as_str()); - let (kernel_pid, kernel_handle, execution, kernel_stdin_writer_fd) = if resolved - .tool_command - { - let tool_resolution = resolve_tool_command( - vm, - &resolved.command, - &resolved.execution_args, - Some(&resolved.guest_cwd), - )? - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "tool command no longer resolves: {}", - resolved.command - )) - })?; - let kernel_handle = vm - .kernel - .create_virtual_process( - EXECUTION_DRIVER_NAME, - TOOL_DRIVER_NAME, - &resolved.command, - resolved.process_args.clone(), - VirtualProcessOptions { - parent_pid: Some(parent_kernel_pid), - env: resolved.env.clone(), - cwd: Some(resolved.guest_cwd.clone()), - }, - ) - .map_err(kernel_error)?; - let kernel_pid = kernel_handle.pid(); - let tool_execution = ToolExecution::default(); - let cancelled = tool_execution.cancelled.clone(); - let pending_events = tool_execution.pending_events.clone(); - let events_overflowed = tool_execution.events_overflowed.clone(); - spawn_tool_process_events(ToolProcessEventRequest { - sidecar_requests: sidecar_requests.clone(), - connection_id: vm.connection_id.clone(), - session_id: vm.session_id.clone(), - vm_id: vm_id.to_owned(), - tool_resolution, - cancelled, - pending_events, - events_overflowed, - }); - ( - kernel_pid, - kernel_handle, - ActiveExecution::Tool(tool_execution), - None, - ) - } else { - let kernel_command = match resolved.runtime { - GuestRuntimeKind::JavaScript => JAVASCRIPT_COMMAND, - GuestRuntimeKind::WebAssembly => WASM_COMMAND, - GuestRuntimeKind::Python => PYTHON_COMMAND, - }; - let kernel_handle = vm - .kernel - .spawn_process( - kernel_command, - resolved.process_args.clone(), - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - parent_pid: Some(parent_kernel_pid), - env: resolved.env.clone(), - cwd: Some(resolved.guest_cwd.clone()), - }, - ) - .map_err(kernel_error)?; - let kernel_pid = kernel_handle.pid(); - if request.options.detached { - vm.kernel - .setsid(EXECUTION_DRIVER_NAME, kernel_pid) - .map_err(kernel_error)?; - } - let mut execution_env = resolved.env.clone(); - execution_env.insert( - String::from(EXECUTION_SANDBOX_ROOT_ENV), - normalize_host_path(&vm.cwd).to_string_lossy().into_owned(), - ); - let execution = match resolved.runtime { - GuestRuntimeKind::JavaScript => { - execution_env.extend(sanitize_javascript_child_process_internal_bootstrap_env( - &request.options.internal_bootstrap_env, - )); - execution_env.insert( - String::from("SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - ); - let launch_entrypoint = resolve_agentos_package_javascript_launch_entrypoint( - vm, - &mut execution_env, - ) - .unwrap_or_else(|| resolved.entrypoint.clone()); - let context = - self.javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.to_owned(), - bootstrap_module: None, - compile_cache_root: Some( - self.cache_root.join("node-compile-cache"), - ), - }); - let inline_code = load_javascript_entrypoint_source( - vm, - &resolved.host_cwd, - &launch_entrypoint, - &execution_env, - ); - prepare_javascript_shadow(vm, &resolved, &execution_env)?; - - let built_reader = build_module_reader(vm, &resolved); - let guest_reader = built_reader.clone().map(|reader| { - Box::new(crate::plugins::host_dir::SessionModuleReader::new(reader)) - as Box - }); - let module_reader = built_reader - .map(|reader| Box::new(reader) as Box); - let execution = self - .javascript_engine - .start_execution_with_module_reader( - StartJavascriptExecutionRequest { - guest_runtime: guest_runtime_identity( - vm, - Some(u64::from(kernel_pid)), - Some(u64::from(parent_kernel_pid)), - ), - vm_id: vm_id.to_owned(), - context_id: context.context_id, - argv: std::iter::once(launch_entrypoint) - .chain(resolved.execution_args.clone()) - .collect(), - env: execution_env, - cwd: resolved.host_cwd.clone(), - limits: javascript_execution_limits(vm), - inline_code, - wasm_module_bytes: None, - }, - module_reader, - guest_reader, - ) - .map_err(javascript_error)?; - ActiveExecution::Javascript(execution) - } - GuestRuntimeKind::WebAssembly => { - execution_env.insert(String::from(WASM_STDIO_SYNC_RPC_ENV), String::from("1")); - let wasm_limits = wasm_execution_limits(vm); - let wasm_guest_runtime = guest_runtime_identity( - vm, - Some(u64::from(kernel_pid)), - Some(u64::from(parent_kernel_pid)), - ); - let context = self.wasm_engine.create_context(CreateWasmContextRequest { - vm_id: vm_id.to_owned(), - module_path: Some(resolved.entrypoint.clone()), - }); - let execution = self - .wasm_engine - .start_execution(StartWasmExecutionRequest { - vm_id: vm_id.to_owned(), - context_id: context.context_id, - argv: resolved.process_args.clone(), - env: execution_env, - cwd: resolved.host_cwd.clone(), - permission_tier: execution_wasm_permission_tier( - resolved - .wasm_permission_tier - .unwrap_or(WasmPermissionTier::Full), - ), - limits: wasm_limits, - guest_runtime: wasm_guest_runtime, - }) - .map_err(wasm_error)?; - ActiveExecution::Wasm(Box::new(execution)) - } - GuestRuntimeKind::Python => { - // Nested `python` child_process: set up the Pyodide context the - // same way the top-level execute path does, so a guest shell or - // node parent can spawn `python` exactly like `node`. - let python_file_path = if execution_env.contains_key("AGENTOS_PYTHON_ARGV") { - execution_env.get("AGENTOS_PYTHON_FILE").map(PathBuf::from) - } else { - python_file_entrypoint(&resolved.entrypoint) - }; - let pyodide_dist_path = self - .python_engine - .bundled_pyodide_dist_path_for_vm(vm_id) - .map_err(python_error)?; - let pyodide_cache_path = pyodide_dist_path - .parent() - .and_then(Path::parent) - .unwrap_or(pyodide_dist_path.as_path()) - .join("pyodide-package-cache"); - add_runtime_guest_path_mapping( - &mut execution_env, - PYTHON_PYODIDE_GUEST_ROOT, - &pyodide_dist_path, - ); - add_runtime_guest_path_mapping( - &mut execution_env, - PYTHON_PYODIDE_CACHE_GUEST_ROOT, - &pyodide_cache_path, - ); - add_runtime_host_access_path( - &mut execution_env, - "AGENTOS_EXTRA_FS_READ_PATHS", - &pyodide_dist_path, - true, - ); - add_runtime_host_access_path( - &mut execution_env, - "AGENTOS_EXTRA_FS_READ_PATHS", - &pyodide_cache_path, - true, - ); - add_runtime_host_access_path( - &mut execution_env, - "AGENTOS_EXTRA_FS_WRITE_PATHS", - &pyodide_cache_path, - false, - ); - let context = self - .python_engine - .create_context(CreatePythonContextRequest { - vm_id: vm_id.to_owned(), - pyodide_dist_path, - }); - let execution = self - .python_engine - .start_execution(StartPythonExecutionRequest { - vm_id: vm_id.to_owned(), - context_id: context.context_id, - code: resolved.entrypoint.clone(), - file_path: python_file_path, - env: execution_env, - cwd: resolved.host_cwd.clone(), - limits: python_execution_limits(vm), - guest_runtime: guest_runtime_identity( - vm, - Some(u64::from(kernel_pid)), - Some(u64::from(parent_kernel_pid)), - ), - }) - .map_err(python_error)?; - ActiveExecution::Python(execution) - } - }; - let kernel_stdin_writer_fd = match javascript_child_process_stdin_mode(&request) { - "pipe" => Some(install_kernel_stdin_pipe(&mut vm.kernel, kernel_pid)?), - "ignore" => { - vm.kernel - .fd_close(EXECUTION_DRIVER_NAME, kernel_pid, 0) - .map_err(kernel_error)?; - None - } - "inherit" => None, - _ => Some(install_kernel_stdin_pipe(&mut vm.kernel, kernel_pid)?), - }; - (kernel_pid, kernel_handle, execution, kernel_stdin_writer_fd) - }; - record_execute_phase( - "child_process_spawn_and_start_execution", - phase_start.elapsed(), - ); - - let phase_start = Instant::now(); - let child_fd1_is_tty = vm - .kernel - .isatty(EXECUTION_DRIVER_NAME, kernel_pid, 1) - .unwrap_or(false); - let root = vm - .active_processes - .get_mut(process_id) - .ok_or_else(|| missing_process_error(vm_id, process_id))?; - let parent = - Self::active_process_by_path_mut(root, current_process_path).ok_or_else(|| { - SidecarError::InvalidState(format!( - "unknown child process path {current_process_label} during nested spawn" - )) - })?; - let inherited_tty_master_owner = if child_fd1_is_tty { - parent - .tty_master_fd - .map(|master_fd| (parent.kernel_pid, master_fd)) - .or(parent.tty_master_owner) - } else { - None - }; - parent.child_processes.insert( - child_process_id.clone(), - ActiveProcess::new(kernel_pid, kernel_handle, resolved.runtime, execution) - .with_detached(request.options.detached) - .with_guest_cwd(resolved.guest_cwd.clone()) - .with_env(resolved.env.clone()) - .with_host_cwd(resolved.host_cwd.clone()), - ); - { - let child = parent - .child_processes - .get_mut(&child_process_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "child process {child_process_id} disappeared during nested spawn" - )) - })?; - child.tty_master_owner = inherited_tty_master_owner; - if let Some(kernel_stdin_writer_fd) = kernel_stdin_writer_fd { - child.kernel_stdin_writer_fd = Some(kernel_stdin_writer_fd); - } - } - record_execute_phase("child_process_register", phase_start.elapsed()); - record_execute_phase("child_process_spawn_total", total_start.elapsed()); - Ok(json!({ - "childId": child_process_id, - "pid": kernel_pid, - "command": resolved.command, - "args": resolved.process_args, - })) - } - - fn spawn_descendant_javascript_child_process_sync( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - request: JavascriptChildProcessSpawnRequest, - max_buffer: Option, - ) -> Result { - let sync_input = javascript_child_process_sync_input_bytes(request.options.input.as_ref())?; - let timeout_deadline = request - .options - .timeout - .map(|timeout_ms| Instant::now() + Duration::from_millis(timeout_ms)); - let timeout_signal = request - .options - .kill_signal - .clone() - .unwrap_or_else(|| String::from("SIGTERM")); - let spawned = self.spawn_descendant_javascript_child_process( - vm_id, - process_id, - current_process_path, - request, - )?; - let child_process_id = spawned - .get("childId") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "child_process.spawn_sync response is missing childId", - )) - })? - .to_owned(); - - if let Some(input) = sync_input.as_deref() { - self.write_descendant_javascript_child_process_stdin( - vm_id, - process_id, - current_process_path, - &child_process_id, - input, - )?; - } - self.close_descendant_javascript_child_process_stdin( - vm_id, - process_id, - current_process_path, - &child_process_id, - )?; - - let max_buffer = max_buffer.unwrap_or(1024 * 1024); - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut max_buffer_exceeded = false; - let mut kill_sent = false; - let mut timed_out = false; - - let exit_code = loop { - let wait_ms = if let Some(deadline) = timeout_deadline { - let now = Instant::now(); - if now >= deadline { - if !kill_sent { - timed_out = true; - self.kill_descendant_javascript_child_process( - vm_id, - process_id, - current_process_path, - &child_process_id, - &timeout_signal, - )?; - kill_sent = true; - } - 0 - } else { - u64::try_from(deadline.saturating_duration_since(now).as_millis().min(50)) - .unwrap_or(50) - } - } else { - 50 - }; - let event = self.poll_descendant_javascript_child_process( - vm_id, - process_id, - current_process_path, - &child_process_id, - wait_ms, - )?; - if event.is_null() { - continue; - } - - match event.get("type").and_then(Value::as_str) { - Some("stdout") => { - let chunk = javascript_sync_rpc_bytes_arg( - &[event.get("data").cloned().unwrap_or(Value::Null)], - 0, - "child_process.spawn_sync stdout", - )?; - stdout.extend_from_slice(&chunk); - if stdout.len() > max_buffer && !kill_sent { - max_buffer_exceeded = true; - self.kill_descendant_javascript_child_process( - vm_id, - process_id, - current_process_path, - &child_process_id, - "SIGTERM", - )?; - kill_sent = true; - } - } - Some("stderr") => { - let chunk = javascript_sync_rpc_bytes_arg( - &[event.get("data").cloned().unwrap_or(Value::Null)], - 0, - "child_process.spawn_sync stderr", - )?; - stderr.extend_from_slice(&chunk); - if stderr.len() > max_buffer && !kill_sent { - max_buffer_exceeded = true; - self.kill_descendant_javascript_child_process( - vm_id, - process_id, - current_process_path, - &child_process_id, - "SIGTERM", - )?; - kill_sent = true; - } - } - Some("exit") => { - break event - .get("exitCode") - .and_then(Value::as_i64) - .map(|value| value as i32) - .unwrap_or(1); - } - _ => {} - } - }; - - Ok(json!({ - "stdout": String::from_utf8_lossy(&stdout), - "stderr": String::from_utf8_lossy(&stderr), - "code": exit_code, - "signal": if timed_out { Value::String(timeout_signal) } else { Value::Null }, - "timedOut": timed_out, - "maxBufferExceeded": max_buffer_exceeded, - })) - } - - fn handle_descendant_javascript_child_process_rpc( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - request: &JavascriptSyncRpcRequest, - ) -> Result { - match request.method.as_str() { - "child_process.spawn" => { - let Some(vm) = self.vms.get(vm_id) else { - return Ok(Value::Null); - }; - let (payload, _) = parse_javascript_child_process_spawn_request(vm, &request.args)?; - self.spawn_descendant_javascript_child_process( - vm_id, - process_id, - current_process_path, - payload, - ) - } - "child_process.spawn_sync" => { - let Some(vm) = self.vms.get(vm_id) else { - return Ok(Value::Null); - }; - let (payload, max_buffer) = - parse_javascript_child_process_spawn_request(vm, &request.args)?; - self.spawn_descendant_javascript_child_process_sync( - vm_id, - process_id, - current_process_path, - payload, - max_buffer, - ) - } - "child_process.poll" => { - let child_process_id = - javascript_sync_rpc_arg_str(&request.args, 0, "child_process.poll child id")?; - let wait_ms = javascript_sync_rpc_arg_u64_optional( - &request.args, - 1, - "child_process.poll wait ms", - )? - .unwrap_or_default(); - self.poll_descendant_javascript_child_process( - vm_id, - process_id, - current_process_path, - child_process_id, - wait_ms, - ) - } - "child_process.write_stdin" => { - let child_process_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "child_process.write_stdin child id", - )?; - let chunk = javascript_sync_rpc_bytes_arg( - &request.args, - 1, - "child_process.write_stdin chunk", - )?; - self.write_descendant_javascript_child_process_stdin( - vm_id, - process_id, - current_process_path, - child_process_id, - &chunk, - )?; - Ok(Value::Null) - } - "child_process.close_stdin" => { - let child_process_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "child_process.close_stdin child id", - )?; - self.close_descendant_javascript_child_process_stdin( - vm_id, - process_id, - current_process_path, - child_process_id, - )?; - Ok(Value::Null) - } - "child_process.kill" => { - let child_process_id = - javascript_sync_rpc_arg_str(&request.args, 0, "child_process.kill child id")?; - let signal = - javascript_sync_rpc_arg_str(&request.args, 1, "child_process.kill signal")?; - self.kill_descendant_javascript_child_process( - vm_id, - process_id, - current_process_path, - child_process_id, - signal, - )?; - Ok(Value::Null) - } - _ => Err(SidecarError::InvalidState(format!( - "unsupported nested child process RPC method {}", - request.method - ))), - } - } - - /// Deferred servicing for a CHILD's `__kernel_stdin_read` / `__kernel_poll` - /// inside the child-event pump: probe readiness with a zero timeout, reply - /// when ready / expired / non-blocking, otherwise park the RPC on the child - /// (reply-by-token). The pump loop re-checks the parked RPC every - /// iteration, so the dispatch loop never blocks in a kernel wait on the - /// child's behalf. Returns false when the RPC must be serviced inline - /// (non-TTY JavaScript local stdin bridge). - fn service_child_kernel_wait_rpc( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - child_process_id: &str, - request: &JavascriptSyncRpcRequest, - ) -> Result { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(true); - }; - let kernel = &mut vm.kernel; - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(true); - }; - let Some(parent) = Self::active_process_by_path_mut(root, current_process_path) else { - return Ok(true); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Ok(true); - }; - if request.method == "__kernel_stdin_read" - && matches!(child.execution, ActiveExecution::Javascript(_)) - && child.tty_master_fd.is_none() - { - return Ok(false); - } - let now = Instant::now(); - let requested_timeout_ms = match request.method.as_str() { - "__kernel_stdin_read" => parse_kernel_stdin_read_args(request)?.1, - _ => u64::try_from(parse_kernel_poll_args(request)?.1).unwrap_or(0), - }; - let deadline = match &child.deferred_kernel_wait_rpc { - Some((parked, parked_deadline)) if parked.id == request.id => *parked_deadline, - _ => now + Duration::from_millis(requested_timeout_ms), - }; - let kernel_pid = child.kernel_pid; - let probe = match request.method.as_str() { - "__kernel_stdin_read" => { - let (max_bytes, _) = parse_kernel_stdin_read_args(request)?; - kernel_stdin_read_response(kernel, kernel_pid, max_bytes, Duration::ZERO) - } - _ => { - let (fd_requests, _) = parse_kernel_poll_args(request)?; - kernel_poll_response(kernel, kernel_pid, &fd_requests, 0) - } - }; - let probe = match probe { - Ok(value) => value, - Err(error) => { - child.deferred_kernel_wait_rpc = None; - child - .execution - .respond_javascript_sync_rpc_error( - request.id, - javascript_sync_rpc_error_code(&error), - error.to_string(), - ) - .or_else(ignore_stale_javascript_sync_rpc_response)?; - return Ok(true); - } - }; - let ready = match request.method.as_str() { - "__kernel_stdin_read" => !probe.is_null(), - _ => probe.get("readyCount").and_then(Value::as_u64).unwrap_or(0) > 0, - }; - if ready || requested_timeout_ms == 0 || now >= deadline { - child.deferred_kernel_wait_rpc = None; - child - .execution - .respond_javascript_sync_rpc_response(request.id, probe.into()) - .or_else(ignore_stale_javascript_sync_rpc_response)?; - return Ok(true); - } - child.deferred_kernel_wait_rpc = Some((request.clone(), deadline)); - Ok(true) - } - - /// Service `__kernel_stdio_write` for a process writing to the SHARED - /// terminal (`tty_master_owner` set): write through the process's own PTY - /// slave (line discipline applies), then drain the master and surface the - /// drained bytes as the OWNER's ordered output stream — the single - /// host-facing path. No child stdout event is queued, so nothing gets - /// relayed (and re-rendered) by the parent shell. - pub(crate) fn service_shared_tty_stdio_write( - &mut self, - vm_id: &str, - writer_kernel_pid: u32, - owner: (u32, u32), - request: &JavascriptSyncRpcRequest, - ) -> Result { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "__kernel_stdio_write fd")?; - let chunk = javascript_sync_rpc_bytes_arg(&request.args, 1, "__kernel_stdio_write chunk")?; - if fd != 1 && fd != 2 { - return Err(SidecarError::InvalidState(format!( - "__kernel_stdio_write only supports fd 1/2, got {fd}" - ))); - } - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(json!(chunk.len())); - }; - let written = if fd == 1 { - vm.kernel - .write_process_stdout(EXECUTION_DRIVER_NAME, writer_kernel_pid, &chunk) - .map_err(kernel_error)? - } else { - vm.kernel - .write_process_stderr(EXECUTION_DRIVER_NAME, writer_kernel_pid, &chunk) - .map_err(kernel_error)? - }; - let (owner_pid, master_fd) = owner; - let mut drained: Vec = Vec::new(); - loop { - match vm.kernel.fd_read_with_timeout_result( - EXECUTION_DRIVER_NAME, - owner_pid, - master_fd, - MAX_PTY_BUFFER_BYTES, - Some(Duration::ZERO), - ) { - Ok(Some(bytes)) if !bytes.is_empty() => drained.extend(bytes), - Ok(_) => break, - Err(error) if error.code() == "EAGAIN" => break, - Err(error) => return Err(kernel_error(error)), - } - } - if !drained.is_empty() { - if let Some(owner_process) = vm - .active_processes - .values_mut() - .find(|process| process.kernel_pid == owner_pid) - { - owner_process - .queue_pending_execution_event(ActiveExecutionEvent::Stdout(drained))?; - } - } - Ok(json!(written)) - } - - /// Re-check a child's parked kernel-wait RPC (see - /// `service_child_kernel_wait_rpc`); called once per pump-loop iteration. - fn recheck_child_deferred_kernel_wait_rpc( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - child_process_id: &str, - ) -> Result<(), SidecarError> { - let parked = { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(()); - }; - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(()); - }; - let Some(parent) = Self::active_process_by_path_mut(root, current_process_path) else { - return Ok(()); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Ok(()); - }; - child - .deferred_kernel_wait_rpc - .as_ref() - .map(|(request, _)| request.clone()) - }; - if let Some(request) = parked { - let _ = self.service_child_kernel_wait_rpc( - vm_id, - process_id, - current_process_path, - child_process_id, - &request, - )?; - } - Ok(()) - } - - fn poll_descendant_javascript_child_process( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - child_process_id: &str, - wait_ms: u64, - ) -> Result { - let mut child_path = current_process_path.to_vec(); - child_path.push(child_process_id); - let child_gone_error = || javascript_child_process_gone_error(process_id, &child_path); - let deadline = Instant::now() + Duration::from_millis(wait_ms); - let mut polled_once = false; - - loop { - self.drain_queued_descendant_javascript_child_process_events( - vm_id, - process_id, - &child_path, - )?; - self.recheck_child_deferred_kernel_wait_rpc( - vm_id, - process_id, - current_process_path, - child_process_id, - )?; - enum ChildPollResult { - Event(Box>), - RecoverRuntimeExit, - Timeout, - } - let wait = if wait_ms == 0 { - Duration::ZERO - } else { - deadline.saturating_duration_since(Instant::now()) - }; - let poll_result = { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let Some(parent) = - Self::descendant_parent_process_mut(vm, process_id, current_process_path) - else { - return Err(child_gone_error()); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Err(child_gone_error()); - }; - if let Some(event) = child.pending_execution_events.pop_front() { - ChildPollResult::Event(Box::new(Some(event))) - } else if polled_once && wait.is_zero() { - ChildPollResult::Timeout - } else { - polled_once = true; - match child.execution.poll_event_blocking(wait) { - Ok(Some(event)) => ChildPollResult::Event(Box::new(Some(event))), - Ok(None) => ChildPollResult::RecoverRuntimeExit, - Err(SidecarError::Execution(message)) - if (child.runtime == GuestRuntimeKind::JavaScript - && closed_javascript_event_channel(&message)) - || (child.runtime == GuestRuntimeKind::Python - && closed_python_event_channel(&message)) - || (child.runtime == GuestRuntimeKind::WebAssembly - && closed_wasm_event_channel(&message)) => - { - ChildPollResult::RecoverRuntimeExit - } - Err(error) => return Err(error), - } - } - }; - let event = match poll_result { - ChildPollResult::Event(event) => *event, - ChildPollResult::Timeout => return Ok(Value::Null), - ChildPollResult::RecoverRuntimeExit => self - .recover_descendant_runtime_child_process_event( - vm_id, - process_id, - current_process_path, - child_process_id, - wait.as_millis().try_into().unwrap_or(u64::MAX), - )?, - }; - - let Some(event) = event else { - return Ok(Value::Null); - }; - - match event { - ActiveExecutionEvent::Stdout(chunk) => { - return Ok(json!({ - "type": "stdout", - "data": javascript_sync_rpc_bytes_value(&chunk), - })); - } - ActiveExecutionEvent::Stderr(chunk) => { - return Ok(json!({ - "type": "stderr", - "data": javascript_sync_rpc_bytes_value(&chunk), - })); - } - ActiveExecutionEvent::Exited(exit_code) => { - let cleanup_start = Instant::now(); - let had_trailing_events = { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let Some(parent) = Self::descendant_parent_process_mut( - vm, - process_id, - current_process_path, - ) else { - return Ok(Value::Null); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Ok(Value::Null); - }; - let mut quiet_deadline = Instant::now() + PROCESS_EXIT_DRAIN_INITIAL_QUIET; - loop { - let wait = quiet_deadline.saturating_duration_since(Instant::now()); - let next = poll_child_execution_after_exit(child, wait)?; - let Some(next) = next else { - break; - }; - if matches!(next, ActiveExecutionEvent::Exited(_)) { - continue; - } - child.queue_pending_execution_event(next)?; - quiet_deadline = Instant::now() + PROCESS_EXIT_DRAIN_TRAILING_QUIET; - } - if !child.pending_execution_events.is_empty() { - child.queue_pending_execution_event(ActiveExecutionEvent::Exited( - exit_code, - ))?; - true - } else { - false - } - }; - if had_trailing_events { - continue; - } - - let parent_signal_key = - Self::child_process_signal_key(process_id, current_process_path); - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let signal_name = { - let Some(parent) = Self::descendant_parent_process_mut( - vm, - process_id, - current_process_path, - ) else { - return Ok(Value::Null); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Ok(Value::Null); - }; - child.pending_self_signal_exit.take().and_then(|signal| { - if exit_code == 128 + signal { - canonical_signal_name(signal).map(str::to_owned) - } else { - None - } - }) - }; - let (parent_runtime_pid, parent_v8_signal_session, should_signal_parent) = { - let Some(parent) = - Self::descendant_parent_process(vm, process_id, current_process_path) - else { - return Ok(Value::Null); - }; - ( - parent.execution.child_pid(), - parent.execution.javascript_v8_session_handle().filter(|_| { - matches!( - &parent.execution, - ActiveExecution::Javascript(execution) - if execution.uses_shared_v8_runtime() - ) - }), - vm.signal_states - .get(parent_signal_key) - .and_then(|handlers| handlers.get(&(libc::SIGCHLD as u32))) - .is_some_and(|registration| { - registration.action != SignalDispositionAction::Default - }), - ) - }; - let Some(parent) = - Self::descendant_parent_process_mut(vm, process_id, current_process_path) - else { - return Ok(Value::Null); - }; - let Some(mut child) = parent.child_processes.remove(child_process_id) else { - return Ok(Value::Null); - }; - let child_process_label = - Self::child_process_path_label(process_id, &child_path); - let detached_children = - Self::adopt_detached_child_processes(&child_process_label, &mut child); - sync_process_host_writes_to_kernel(vm, &child)?; - let kernel_readiness = Arc::clone(&vm.kernel_socket_readiness); - terminate_child_process_tree(&mut vm.kernel, &mut child, &kernel_readiness); - child.kernel_handle.finish(exit_code); - let _ = vm.kernel.wait_and_reap(child.kernel_pid); - vm.signal_states.remove(child_process_id); - for (detached_process_id, detached_child) in detached_children { - vm.detached_child_processes - .insert(detached_process_id.clone()); - vm.active_processes - .insert(detached_process_id, detached_child); - } - if should_signal_parent { - if let Some(session) = parent_v8_signal_session { - dispatch_v8_session_signal_async(session, libc::SIGCHLD); - } else { - signal_runtime_process(parent_runtime_pid, libc::SIGCHLD)?; - } - } - let mut payload = Map::new(); - payload.insert(String::from("type"), Value::String(String::from("exit"))); - payload.insert(String::from("exitCode"), Value::from(exit_code)); - if let Some(signal_name) = signal_name { - payload.insert(String::from("signal"), Value::String(signal_name)); - } - record_execute_phase("child_process_exit_cleanup", cleanup_start.elapsed()); - return Ok(Value::Object(payload)); - } - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) => { - let mut current_child_path = current_process_path.to_vec(); - current_child_path.push(child_process_id); - if matches!( - request.method.as_str(), - "__kernel_stdin_read" | "__kernel_poll" - ) && self.service_child_kernel_wait_rpc( - vm_id, - process_id, - current_process_path, - child_process_id, - &request, - )? { - // Replied immediately or parked on the child; the pump - // loop re-checks parked RPCs every iteration. - continue; - } - if request.method == "__kernel_stdio_write" { - let shared_tty = { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(Value::Null); - }; - let Some(parent) = - Self::active_process_by_path_mut(root, current_process_path) - else { - return Ok(Value::Null); - }; - parent - .child_processes - .get(child_process_id) - .and_then(|child| { - child - .tty_master_owner - .map(|owner| (child.kernel_pid, owner)) - }) - }; - if let Some((child_kernel_pid, owner)) = shared_tty { - let response = self.service_shared_tty_stdio_write( - vm_id, - child_kernel_pid, - owner, - &request, - ); - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(Value::Null); - }; - let Some(parent) = - Self::active_process_by_path_mut(root, current_process_path) - else { - return Ok(Value::Null); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) - else { - return Ok(Value::Null); - }; - match response { - Ok(result) => child - .execution - .respond_javascript_sync_rpc_response(request.id, result.into()) - .or_else(ignore_stale_javascript_sync_rpc_response)?, - Err(error) => child - .execution - .respond_javascript_sync_rpc_error( - request.id, - javascript_sync_rpc_error_code(&error), - error.to_string(), - ) - .or_else(ignore_stale_javascript_sync_rpc_response)?, - } - continue; - } - } - let response = if request.method == "process.signal_state" { - let (signal, registration) = - parse_process_signal_state_request(&request.args) - .map_err(|error| SidecarError::InvalidState(error.to_string()))?; - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let signal_key = - Self::child_process_signal_key(process_id, ¤t_child_path) - .to_owned(); - apply_process_signal_state_update( - &mut vm.signal_states, - &signal_key, - signal, - registration, - ); - Ok(Value::Null.into()) - } else if request.method == "process.kill" { - self.handle_descendant_process_kill_rpc( - vm_id, - process_id, - current_process_path, - child_process_id, - &request, - ) - .map(Into::into) - } else if request.method.starts_with("child_process.") { - self.handle_descendant_javascript_child_process_rpc( - vm_id, - process_id, - ¤t_child_path, - &request, - ) - .map(Into::into) - } else { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let resource_limits = vm.kernel.resource_limits().clone(); - let network_counts = vm_network_resource_counts(vm); - let socket_paths = build_javascript_socket_path_context(vm)?; - let kernel_readiness = Arc::clone(&vm.kernel_socket_readiness); - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(Value::Null); - }; - let Some(parent) = - Self::active_process_by_path_mut(root, current_process_path) - else { - return Ok(Value::Null); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Ok(Value::Null); - }; - service_javascript_sync_rpc(JavascriptSyncRpcServiceRequest { - bridge: &self.bridge, - vm_id, - dns: &vm.dns, - socket_paths: &socket_paths, - kernel: &mut vm.kernel, - kernel_readiness, - process: child, - sync_request: &request, - resource_limits: &resource_limits, - network_counts, - }) - }; - - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let Some(parent) = - Self::descendant_parent_process_mut(vm, process_id, current_process_path) - else { - return Ok(Value::Null); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Ok(Value::Null); - }; - let parent_signal_event = response - .as_ref() - .ok() - .and_then(JavascriptSyncRpcServiceResponse::as_json) - .and_then(|result| { - let target_path_label = - Self::child_process_path_label(process_id, current_process_path); - if request.method != "process.kill" - || result.get("action").and_then(Value::as_str) != Some("user") - || result.get("targetProcessPath").and_then(Value::as_str) - != Some(target_path_label.as_str()) - { - return None; - } - Some(json!({ - "type": "signal", - "signal": result.get("signal").and_then(Value::as_str).unwrap_or_default(), - "number": result.get("number").and_then(Value::as_i64).unwrap_or_default(), - })) - }); - match response { - Ok(result) => child - .execution - .respond_javascript_sync_rpc_response(request.id, result) - .or_else(ignore_stale_javascript_sync_rpc_response)?, - Err(error) => child - .execution - .respond_javascript_sync_rpc_error( - request.id, - javascript_sync_rpc_error_code(&error), - error.to_string(), - ) - .or_else(ignore_stale_javascript_sync_rpc_response)?, - } - if let Some(event) = parent_signal_event { - return Ok(event); - } - } - ActiveExecutionEvent::PythonVfsRpcRequest(request) => { - // The kernel-VFS bridge is wired for top-level Python - // executions; a nested Python child (spawned by a JS/Python - // parent) cannot service VFS RPCs through this child-event - // path. Respond with a recoverable error instead of aborting - // the child, so its runner falls back to the in-isolate FS - // for the nested process — top-level Python keeps the full - // VFS root. - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let Some(parent) = - Self::descendant_parent_process_mut(vm, process_id, current_process_path) - else { - return Ok(Value::Null); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Ok(Value::Null); - }; - // Best-effort: deliver the "unavailable" error so the child's - // pending VFS RPC resolves and its runner falls back to the - // in-isolate FS. If delivery fails the child has already gone - // away (broken pipe / no-longer-pending), so dropping the - // result is correct here — there is nothing left to hang. - let _ = child.execution.respond_python_vfs_rpc_error( - request.id, - "ERR_AGENTOS_PYTHON_VFS_UNAVAILABLE", - "python VFS is not available for nested child processes", - ); - } - ActiveExecutionEvent::SignalState { - signal, - registration, - } => { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let signal_key = - Self::child_process_signal_key(process_id, &child_path).to_owned(); - apply_process_signal_state_update( - &mut vm.signal_states, - &signal_key, - signal, - registration.clone(), - ); - return Ok(json!({ - "type": "signal_state", - "signal": signal, - "registration": registration, - })); - } - } - } - } - - fn recover_descendant_runtime_child_process_event( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - child_process_id: &str, - wait_ms: u64, - ) -> Result, SidecarError> { - let ( - parent_kernel_pid, - child_kernel_pid, - child_runtime_pid, - child_runtime, - child_shared_runtime, - ) = { - let mut child_path = current_process_path.to_vec(); - child_path.push(child_process_id); - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(None); - }; - let Some(parent) = - Self::descendant_parent_process_mut(vm, process_id, current_process_path) - else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - ( - parent.kernel_pid, - child.kernel_pid, - child.execution.child_pid(), - child.runtime.clone(), - child.execution.uses_shared_v8_runtime(), - ) - }; - if child_runtime != GuestRuntimeKind::JavaScript - && child_runtime != GuestRuntimeKind::Python - && child_runtime != GuestRuntimeKind::WebAssembly - { - return Ok(None); - } - let wait_deadline = Instant::now() + Duration::from_millis(wait_ms.min(25)); - loop { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(None); - }; - if let Some(process_info) = vm.kernel.list_processes().get(&child_kernel_pid) { - if process_info.status == ProcessStatus::Exited { - return Ok(Some(ActiveExecutionEvent::Exited( - process_info.exit_code.unwrap_or(0), - ))); - } - } - if let Some(wait_result) = vm - .kernel - .waitpid_with_options( - EXECUTION_DRIVER_NAME, - parent_kernel_pid, - child_kernel_pid as i32, - WaitPidFlags::WNOHANG, - ) - .map_err(kernel_error)? - { - return Ok(Some(ActiveExecutionEvent::Exited(wait_result.status))); - } - - if !child_shared_runtime && child_runtime_pid != 0 { - if let Some(status) = runtime_child_exit_status(child_runtime_pid)? { - return Ok(Some(ActiveExecutionEvent::Exited(status))); - } - if !runtime_child_is_alive(child_runtime_pid)? { - return Ok(Some(ActiveExecutionEvent::Exited(0))); - } - } - if Instant::now() >= wait_deadline { - return Ok(None); - } - std::thread::sleep(Duration::from_millis(5)); - } - } - - fn write_descendant_javascript_child_process_stdin( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - child_process_id: &str, - chunk: &[u8], - ) -> Result<(), SidecarError> { - let mut child_path = current_process_path.to_vec(); - child_path.push(child_process_id); - let Some(vm) = self.vms.get_mut(vm_id) else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - let Some(parent) = Self::active_process_by_path_mut(root, current_process_path) else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - if let Err(error) = child.execution.write_stdin(chunk) { - if is_broken_pipe_error(&error) { - return Ok(()); - } - return Err(error); - } - write_kernel_process_stdin(&mut vm.kernel, child, chunk) - } - - fn close_descendant_javascript_child_process_stdin( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - child_process_id: &str, - ) -> Result<(), SidecarError> { - let mut child_path = current_process_path.to_vec(); - child_path.push(child_process_id); - let Some(vm) = self.vms.get_mut(vm_id) else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - let Some(parent) = Self::active_process_by_path_mut(root, current_process_path) else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Err(javascript_child_process_gone_error(process_id, &child_path)); - }; - child.execution.close_stdin()?; - close_kernel_process_stdin(&mut vm.kernel, child) - } - - fn kill_descendant_javascript_child_process( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - child_process_id: &str, - signal: &str, - ) -> Result<(), SidecarError> { - let signal_name = signal.to_owned(); - let signal = parse_signal(signal)?; - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(()); - }; - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(()); - }; - let Some(parent) = Self::active_process_by_path_mut(root, current_process_path) else { - return Ok(()); - }; - let source_pid = parent.kernel_pid; - let Some(child) = parent.child_processes.get_mut(child_process_id) else { - return Ok(()); - }; - terminate_tracked_child_process_for_signal(&mut vm.kernel, child, signal)?; - let child_process_label = if current_process_path.is_empty() { - child_process_id.to_owned() - } else { - format!("{}/{}", current_process_path.join("/"), child_process_id) - }; - emit_security_audit_event( - &self.bridge, - vm_id, - "security.process.kill", - audit_fields([ - (String::from("source"), String::from("guest_child_process")), - (String::from("source_pid"), source_pid.to_string()), - (String::from("target_pid"), child.kernel_pid.to_string()), - (String::from("process_id"), process_id.to_owned()), - (String::from("child_process_id"), child_process_label), - (String::from("signal"), signal_name), - ]), - ); - Ok(()) - } - - fn handle_descendant_process_kill_rpc( - &mut self, - vm_id: &str, - process_id: &str, - current_process_path: &[&str], - child_process_id: &str, - request: &JavascriptSyncRpcRequest, - ) -> Result { - let target_pid = javascript_sync_rpc_arg_i32(&request.args, 0, "process.kill target pid")?; - let signal_name = javascript_sync_rpc_arg_str(&request.args, 1, "process.kill signal")?; - let signal = parse_signal(signal_name)?; - - let mut source_path = current_process_path.to_vec(); - source_path.push(child_process_id); - - if signal != 0 && target_pid < 0 { - let pgid = target_pid.unsigned_abs(); - let caller_kernel_pid = { - let Some(vm) = self.vms.get(vm_id) else { - return Err(SidecarError::InvalidState(String::from( - "ESRCH: unknown VM during process.kill", - ))); - }; - let Some(root) = vm.active_processes.get(process_id) else { - return Err(SidecarError::InvalidState(format!( - "ESRCH: unknown process {process_id} during process.kill", - ))); - }; - let Some(source) = Self::active_process_by_path(root, &source_path) else { - return Err(SidecarError::InvalidState(format!( - "ESRCH: unknown child process {child_process_id} during process.kill", - ))); - }; - source.kernel_pid - }; - let caller_is_member = - self.signal_vm_process_group(vm_id, caller_kernel_pid, pgid, signal_name)?; - if !caller_is_member { - return Ok(Value::Null); - } - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(Value::Null); - }; - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(Value::Null); - }; - let Some(source) = Self::active_process_by_path_mut(root, &source_path) else { - return Ok(Value::Null); - }; - source.pending_self_signal_exit = None; - if !matches!( - canonical_signal_name(signal), - Some("SIGWINCH" | "SIGCHLD" | "SIGCONT" | "SIGURG") - ) { - source.pending_self_signal_exit = Some(signal); - } - return Ok(json!({ - "self": true, - "action": "default", - })); - } - - let Some(vm) = self.vms.get_mut(vm_id) else { - return Err(SidecarError::InvalidState(String::from( - "ESRCH: unknown VM during process.kill", - ))); - }; - - if signal == 0 { - vm.kernel - .signal_process(EXECUTION_DRIVER_NAME, target_pid, signal) - .map_err(kernel_error)?; - return Ok(Value::Null); - } - - let target_kernel_pid = u32::try_from(target_pid).map_err(|_| { - SidecarError::InvalidState(format!("EINVAL: invalid process pid {target_pid}")) - })?; - let (source_pid, located_target_path) = { - let Some(root) = vm.active_processes.get(process_id) else { - return Err(SidecarError::InvalidState(format!( - "ESRCH: unknown process {process_id} during process.kill", - ))); - }; - let Some(source) = Self::active_process_by_path(root, &source_path) else { - return Err(SidecarError::InvalidState(format!( - "ESRCH: unknown child process {child_process_id} during process.kill", - ))); - }; - vm.kernel - .signal_process(EXECUTION_DRIVER_NAME, target_pid, 0) - .map_err(kernel_error)?; - ( - source.kernel_pid, - Self::active_process_path_by_kernel_pid(root, target_kernel_pid), - ) - }; - let Some(target_path) = located_target_path else { - // The target is alive but not part of this root's process tree. - // Resolve it VM-wide so cross-tree pids and untracked kernel - // processes still receive the signal. - self.signal_vm_kernel_pid(vm_id, target_kernel_pid, signal_name)?; - return Ok(Value::Null); - }; - let Some(vm) = self.vms.get_mut(vm_id) else { - return Err(SidecarError::InvalidState(String::from( - "ESRCH: unknown VM during process.kill", - ))); - }; - - if source_pid == target_kernel_pid { - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(Value::Null); - }; - let Some(source) = Self::active_process_by_path_mut(root, &source_path) else { - return Ok(Value::Null); - }; - source.pending_self_signal_exit = None; - if !matches!( - canonical_signal_name(signal), - Some("SIGWINCH" | "SIGCHLD" | "SIGCONT" | "SIGURG") - ) { - source.pending_self_signal_exit = Some(signal); - } - return Ok(json!({ - "self": true, - "action": "default", - })); - } - - let signal_key = target_path.last().map(String::as_str).unwrap_or(process_id); - let registration = vm - .signal_states - .get(signal_key) - .and_then(|handlers| handlers.get(&(signal as u32))) - .cloned(); - - let action = match registration - .as_ref() - .map(|registration| ®istration.action) - { - Some(SignalDispositionAction::Ignore) => "ignore", - Some(SignalDispositionAction::User) => { - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(Value::Null); - }; - let Some(target) = Self::active_process_by_owned_path_mut(root, &target_path) - else { - return Err(SidecarError::InvalidState(format!( - "ESRCH: unknown process pid {target_pid}" - ))); - }; - if let Some(session) = target.execution.javascript_v8_session_handle().filter( - |_| matches!(&target.execution, ActiveExecution::Javascript(execution) if execution.uses_shared_v8_runtime()) - || matches!(&target.execution, ActiveExecution::Wasm(execution) if execution.uses_shared_v8_runtime()), - ) { - dispatch_v8_session_signal_async(session, signal); - } else if !dispatch_v8_process_signal(target, signal)? { - return Err(SidecarError::InvalidState(format!( - "unsupported guest signal delivery for pid {target_pid}" - ))); - } - "user" - } - Some(SignalDispositionAction::Default) | None - if matches!( - canonical_signal_name(signal), - Some("SIGWINCH" | "SIGCHLD" | "SIGURG") - ) => - { - "ignore" - } - Some(SignalDispositionAction::Default) | None => { - let Some(root) = vm.active_processes.get_mut(process_id) else { - return Ok(Value::Null); - }; - let Some(target) = Self::active_process_by_owned_path_mut(root, &target_path) - else { - return Err(SidecarError::InvalidState(format!( - "ESRCH: unknown process pid {target_pid}" - ))); - }; - apply_active_process_default_signal(&mut vm.kernel, target, signal)?; - "default" - } - }; - - let target_path_label = Self::child_process_path_label( - process_id, - &target_path.iter().map(String::as_str).collect::>(), - ); - emit_security_audit_event( - &self.bridge, - vm_id, - "security.process.kill", - audit_fields([ - (String::from("source"), String::from("guest_process")), - (String::from("source_pid"), source_pid.to_string()), - (String::from("target_pid"), target_pid.to_string()), - (String::from("process_id"), process_id.to_owned()), - ( - String::from("target_process_path"), - target_path_label.clone(), - ), - (String::from("signal"), signal_name.to_owned()), - ]), - ); - - Ok(json!({ - "self": false, - "action": action, - "signal": signal_name, - "number": signal, - "targetProcessPath": target_path_label, - })) - } - - pub(crate) fn poll_javascript_child_process( - &mut self, - vm_id: &str, - process_id: &str, - child_process_id: &str, - wait_ms: u64, - ) -> Result { - self.poll_descendant_javascript_child_process( - vm_id, - process_id, - &[], - child_process_id, - wait_ms, - ) - } - - pub(crate) fn write_javascript_child_process_stdin( - &mut self, - vm_id: &str, - process_id: &str, - child_process_id: &str, - chunk: &[u8], - ) -> Result<(), SidecarError> { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Err(javascript_child_process_gone_error( - process_id, - &[child_process_id], - )); - }; - let Some(child) = vm - .active_processes - .get_mut(process_id) - .ok_or_else(|| missing_process_error(vm_id, process_id))? - .child_processes - .get_mut(child_process_id) - else { - return Err(javascript_child_process_gone_error( - process_id, - &[child_process_id], - )); - }; - if let Err(error) = child.execution.write_stdin(chunk) { - if is_broken_pipe_error(&error) { - return Ok(()); - } - return Err(error); - } - write_kernel_process_stdin(&mut vm.kernel, child, chunk) - } - - pub(crate) fn close_javascript_child_process_stdin( - &mut self, - vm_id: &str, - process_id: &str, - child_process_id: &str, - ) -> Result<(), SidecarError> { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Err(javascript_child_process_gone_error( - process_id, - &[child_process_id], - )); - }; - let Some(child) = vm - .active_processes - .get_mut(process_id) - .ok_or_else(|| missing_process_error(vm_id, process_id))? - .child_processes - .get_mut(child_process_id) - else { - return Err(javascript_child_process_gone_error( - process_id, - &[child_process_id], - )); - }; - child.execution.close_stdin()?; - close_kernel_process_stdin(&mut vm.kernel, child) - } - - pub(crate) fn kill_javascript_child_process( - &mut self, - vm_id: &str, - process_id: &str, - child_process_id: &str, - signal: &str, - ) -> Result<(), SidecarError> { - let signal_name = signal.to_owned(); - let signal = parse_signal(signal)?; - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(()); - }; - let process = vm - .active_processes - .get_mut(process_id) - .ok_or_else(|| missing_process_error(vm_id, process_id))?; - let source_pid = process.kernel_pid; - let child = process - .child_processes - .get_mut(child_process_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "unknown child process {child_process_id} during kill" - )) - })?; - terminate_tracked_child_process_for_signal(&mut vm.kernel, child, signal)?; - emit_security_audit_event( - &self.bridge, - vm_id, - "security.process.kill", - audit_fields([ - (String::from("source"), String::from("guest_child_process")), - (String::from("source_pid"), source_pid.to_string()), - (String::from("target_pid"), child.kernel_pid.to_string()), - (String::from("process_id"), process_id.to_owned()), - ( - String::from("child_process_id"), - child_process_id.to_owned(), - ), - (String::from("signal"), signal_name), - ]), - ); - Ok(()) - } - - /// Delivers a signal to one kernel pid inside a VM, resolving the target - /// through the active-process tree first so tracked sidecar executions get - /// the same termination handling as a direct `child_process.kill`. - /// Untracked kernel processes (for example WASM subprocess trees) receive - /// the signal through the kernel process table directly. - pub(crate) fn signal_vm_kernel_pid( - &mut self, - vm_id: &str, - target_kernel_pid: u32, - signal_name: &str, - ) -> Result<(), SidecarError> { - let signal = parse_signal(signal_name)?; - let located = { - let Some(vm) = self.vms.get(vm_id) else { - return Err(SidecarError::InvalidState(String::from( - "ESRCH: unknown VM during process.kill", - ))); - }; - let alive = vm - .kernel - .list_processes() - .get(&target_kernel_pid) - .is_some_and(|info| info.status != ProcessStatus::Exited); - if !alive { - return Err(SidecarError::InvalidState(format!( - "ESRCH: no such process {target_kernel_pid}" - ))); - } - vm.active_processes.iter().find_map(|(process_id, root)| { - Self::active_process_path_by_kernel_pid(root, target_kernel_pid) - .map(|path| (process_id.clone(), path)) - }) - }; - - match located { - Some((process_id, path)) if path.is_empty() => { - self.kill_process_internal(vm_id, &process_id, signal_name) - } - Some((process_id, path)) => { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(()); - }; - let Some(root) = vm.active_processes.get_mut(&process_id) else { - return Ok(()); - }; - let Some(target) = Self::active_process_by_owned_path_mut(root, &path) else { - return Err(SidecarError::InvalidState(format!( - "ESRCH: no such process {target_kernel_pid}" - ))); - }; - terminate_tracked_child_process_for_signal(&mut vm.kernel, target, signal)?; - emit_security_audit_event( - &self.bridge, - vm_id, - "security.process.kill", - audit_fields([ - (String::from("source"), String::from("guest_process")), - (String::from("target_pid"), target_kernel_pid.to_string()), - (String::from("process_id"), process_id), - (String::from("signal"), signal_name.to_owned()), - ]), - ); - Ok(()) - } - None => { - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(()); - }; - let target_pid = i32::try_from(target_kernel_pid).map_err(|_| { - SidecarError::InvalidState(format!( - "EINVAL: invalid process pid {target_kernel_pid}" - )) - })?; - vm.kernel - .signal_process(EXECUTION_DRIVER_NAME, target_pid, signal) - .map_err(kernel_error)?; - emit_security_audit_event( - &self.bridge, - vm_id, - "security.process.kill", - audit_fields([ - (String::from("source"), String::from("guest_process")), - (String::from("target_pid"), target_kernel_pid.to_string()), - (String::from("signal"), signal_name.to_owned()), - ]), - ); - Ok(()) - } - } - } - - /// Delivers a signal to every live member of a VM process group, matching - /// Linux `kill(-pgid, sig)` semantics. Returns whether the caller itself - /// is a member of the group so entry points can apply self-signal - /// delivery; the caller is intentionally skipped here. - pub(crate) fn signal_vm_process_group( - &mut self, - vm_id: &str, - caller_kernel_pid: u32, - pgid: u32, - signal_name: &str, - ) -> Result { - parse_signal(signal_name)?; - let members = { - let Some(vm) = self.vms.get(vm_id) else { - return Err(SidecarError::InvalidState(String::from( - "ESRCH: unknown VM during process.kill", - ))); - }; - vm.kernel - .list_processes() - .into_iter() - .filter(|(_, info)| info.pgid == pgid && info.status != ProcessStatus::Exited) - .map(|(pid, _)| pid) - .collect::>() - }; - if members.is_empty() { - return Err(SidecarError::InvalidState(format!( - "ESRCH: no such process group {pgid}" - ))); - } - - let mut caller_is_member = false; - for member_pid in members { - if member_pid == caller_kernel_pid { - caller_is_member = true; - continue; - } - match self.signal_vm_kernel_pid(vm_id, member_pid, signal_name) { - Ok(()) => {} - // Group members can exit while the group is being signaled. A - // vanished member is not an error for the group kill overall. - Err(error) if sidecar_error_is_esrch(&error) => {} - Err(error) => return Err(error), - } - } - Ok(caller_is_member) - } -} - -/// Applies a kill signal to a tracked child execution. Shared-runtime -/// executions for lethal signals are terminated directly with a synthetic -/// signal exit so child polls observe a prompt close; everything else routes -/// through the kernel process table. -fn terminate_tracked_child_process_for_signal( - kernel: &mut SidecarKernel, - child: &mut ActiveProcess, - signal: i32, -) -> Result<(), SidecarError> { - let should_terminate_shared_runtime = child.execution.uses_shared_v8_runtime() - && signal != 0 - && !matches!( - signal, - libc::SIGHUP - | libc::SIGINT - | libc::SIGTERM - | libc::SIGCHLD - | libc::SIGWINCH - | libc::SIGSTOP - | libc::SIGCONT - ); - if should_terminate_shared_runtime { - child.execution.terminate()?; - child.pending_self_signal_exit = Some(signal); - child.queue_pending_execution_event(ActiveExecutionEvent::Exited(128 + signal))?; - } else { - kernel - .kill_process(EXECUTION_DRIVER_NAME, child.kernel_pid, signal) - .map_err(kernel_error)?; - } - Ok(()) -} - -fn sidecar_error_is_esrch(error: &SidecarError) -> bool { - error.to_string().contains("ESRCH") -} - -fn apply_active_process_default_signal( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - signal: i32, -) -> Result<(), SidecarError> { - if matches!(signal, libc::SIGSTOP | libc::SIGCONT) { - return kernel - .kill_process(EXECUTION_DRIVER_NAME, process.kernel_pid, signal) - .map_err(kernel_error); - } - - if signal != 0 && matches!(process.execution, ActiveExecution::Python(_)) { - close_kernel_process_stdin(kernel, process)?; - } - - if process.execution.uses_shared_v8_runtime() { - process.execution.terminate()?; - if signal != 0 && matches!(process.execution, ActiveExecution::Wasm(_)) { - process.queue_pending_execution_event(ActiveExecutionEvent::Exited(128 + signal))?; - } - return Ok(()); - } - - kernel - .kill_process(EXECUTION_DRIVER_NAME, process.kernel_pid, signal) - .map_err(kernel_error) -} - -fn map_wasm_signal_registration( - registration: secure_exec_execution::wasm::WasmSignalHandlerRegistration, -) -> SignalHandlerRegistration { - SignalHandlerRegistration { - action: match registration.action { - secure_exec_execution::wasm::WasmSignalDispositionAction::Default => { - crate::protocol::SignalDispositionAction::Default - } - secure_exec_execution::wasm::WasmSignalDispositionAction::Ignore => { - crate::protocol::SignalDispositionAction::Ignore - } - secure_exec_execution::wasm::WasmSignalDispositionAction::User => { - crate::protocol::SignalDispositionAction::User - } - }, - mask: registration.mask, - flags: registration.flags, - } -} - -fn map_node_signal_registration( - registration: NodeSignalHandlerRegistration, -) -> SignalHandlerRegistration { - SignalHandlerRegistration { - action: match registration.action { - NodeSignalDispositionAction::Default => SignalDispositionAction::Default, - NodeSignalDispositionAction::Ignore => SignalDispositionAction::Ignore, - NodeSignalDispositionAction::User => SignalDispositionAction::User, - }, - mask: registration.mask, - flags: registration.flags, - } -} - -fn javascript_child_process_sync_input_bytes( - value: Option<&Value>, -) -> Result>, SidecarError> { - let Some(value) = value else { - return Ok(None); - }; - - match value { - Value::Null => Ok(None), - Value::String(text) => Ok(Some(text.as_bytes().to_vec())), - other => javascript_sync_rpc_bytes_arg( - std::slice::from_ref(other), - 0, - "child_process.spawn_sync input", - ) - .map(Some), - } -} - -// bridge_permissions moved to crate::bridge - -// reconcile_mounts, resolve_cwd moved to crate::vm - -fn resolve_execute_request( - vm: &VmState, - payload: &ExecuteRequest, -) -> Result { - let payload_env: BTreeMap = payload - .env - .iter() - .map(|(k, v)| (k.clone(), v.clone())) - .collect(); - if let Some(command) = payload.command.as_deref() { - return resolve_command_execution( - vm, - command, - &payload.args, - &payload_env, - payload.cwd.as_deref(), - payload.wasm_permission_tier, - ); - } - - let runtime = payload.runtime.clone().ok_or_else(|| { - SidecarError::InvalidState(String::from("execute requires either command or runtime")) - })?; - let entrypoint = payload.entrypoint.clone().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "execute requires either command or entrypoint", - )) - })?; - let (guest_cwd, host_cwd, allow_host_path_overrides) = - resolve_execution_cwds(vm, payload.cwd.as_deref()); - let mut env = vm.guest_env.clone(); - env.extend(payload_env.clone()); - - let requested_host_entrypoint = resolve_host_entrypoint_within_vm_host_cwd(vm, &entrypoint); - if requested_host_entrypoint.is_some() && !allow_host_path_overrides { - let requested_cwd = payload.cwd.as_deref().unwrap_or(guest_cwd.as_str()); - return Err(SidecarError::InvalidState(format!( - "execution cwd {requested_cwd} is outside sandbox root {}", - vm.host_cwd.to_string_lossy() - ))); - } - let host_entrypoint_override = allow_host_path_overrides - .then(|| resolve_host_entrypoint_within_vm_host_cwd(vm, &entrypoint)) - .flatten(); - - let guest_entrypoint = host_entrypoint_override - .as_ref() - .map(|(guest_entrypoint, _)| guest_entrypoint.clone()) - .or_else(|| guest_entrypoint_for_specifier(&guest_cwd, &entrypoint)); - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, guest_entrypoint)?; - - Ok(ResolvedChildProcessExecution { - command: match runtime { - GuestRuntimeKind::JavaScript => String::from(JAVASCRIPT_COMMAND), - GuestRuntimeKind::Python => String::from(PYTHON_COMMAND), - GuestRuntimeKind::WebAssembly => String::from(WASM_COMMAND), - }, - process_args: std::iter::once(entrypoint.clone()) - .chain(payload.args.iter().cloned()) - .collect(), - runtime, - entrypoint: host_entrypoint_override - .map(|(_, host_entrypoint)| host_entrypoint) - .unwrap_or(entrypoint), - execution_args: payload.args.clone(), - env, - guest_cwd, - host_cwd, - wasm_permission_tier: payload.wasm_permission_tier, - tool_command: false, - }) -} - -fn resolve_command_execution( - vm: &VmState, - command: &str, - args: &[String], - extra_env: &BTreeMap, - cwd: Option<&str>, - explicit_wasm_permission_tier: Option, -) -> Result { - let (guest_cwd, host_cwd, allow_host_path_overrides) = resolve_execution_cwds(vm, cwd); - let mut env = vm.guest_env.clone(); - env.extend(extra_env.clone()); - let args = apply_shell_cwd_prefix(command, args.to_vec(), &guest_cwd); - - if is_tool_command(vm, command) { - let command = normalized_tool_command_name(command).unwrap_or_else(|| command.to_owned()); - return Ok(ResolvedChildProcessExecution { - command: command.clone(), - process_args: std::iter::once(command.clone()) - .chain(args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint: command, - execution_args: args, - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: true, - }); - } - - if is_python_runtime_command(command) { - return resolve_python_command_execution(vm, command, &args, env, guest_cwd, host_cwd); - } - - if is_node_runtime_command(command) { - if let Some(cli) = resolve_host_node_cli_entrypoint(command) { - env.insert( - String::from("AGENTOS_NODE_EVAL"), - build_host_node_cli_eval(&cli), - ); - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, None)?; - add_runtime_guest_path_mapping(&mut env, &cli.guest_root, &cli.package_root); - add_runtime_host_access_path( - &mut env, - "AGENTOS_EXTRA_FS_READ_PATHS", - &cli.package_root, - true, - ); - - return Ok(ResolvedChildProcessExecution { - command: String::from(JAVASCRIPT_COMMAND), - process_args: std::iter::once(command.to_owned()) - .chain(args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint: String::from("-e"), - execution_args: std::iter::once(cli.guest_entrypoint.clone()) - .chain(args.iter().cloned()) - .collect(), - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - if args.is_empty() { - env.insert(String::from("AGENTOS_NODE_EVAL"), String::new()); - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, None)?; - - return Ok(ResolvedChildProcessExecution { - command: String::from(JAVASCRIPT_COMMAND), - process_args: vec![command.to_owned()], - runtime: GuestRuntimeKind::JavaScript, - entrypoint: String::from("-e"), - execution_args: Vec::new(), - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - if let Some((entrypoint, execution_args)) = - resolve_special_node_cli_invocation(&args, &mut env) - { - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, None)?; - - return Ok(ResolvedChildProcessExecution { - command: String::from(JAVASCRIPT_COMMAND), - process_args: std::iter::once(command.to_owned()) - .chain(args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint, - execution_args, - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - let Some(entrypoint_specifier) = args.first() else { - return Err(SidecarError::InvalidState(format!( - "{command} execution requires an entrypoint" - ))); - }; - - let (entrypoint, execution_args, guest_entrypoint) = { - let requested_host_entrypoint = - resolve_host_entrypoint_within_vm_host_cwd(vm, entrypoint_specifier); - if requested_host_entrypoint.is_some() && !allow_host_path_overrides { - let requested_cwd = cwd.unwrap_or(guest_cwd.as_str()); - return Err(SidecarError::InvalidState(format!( - "execution cwd {requested_cwd} is outside sandbox root {}", - vm.host_cwd.to_string_lossy() - ))); - } - let host_entrypoint_override = allow_host_path_overrides - .then(|| resolve_host_entrypoint_within_vm_host_cwd(vm, entrypoint_specifier)) - .flatten(); - let guest_entrypoint = host_entrypoint_override - .as_ref() - .map(|(guest_entrypoint, _)| guest_entrypoint.clone()) - .or_else(|| guest_entrypoint_for_specifier(&guest_cwd, entrypoint_specifier)); - let entrypoint = host_entrypoint_override.map_or_else( - || { - guest_entrypoint.as_ref().map_or_else( - || entrypoint_specifier.clone(), - |guest_entrypoint| { - resolve_vm_guest_path_to_host(vm, guest_entrypoint) - .to_string_lossy() - .into_owned() - }, - ) - }, - |(_, host_entrypoint)| host_entrypoint, - ); - ( - entrypoint, - args.iter().skip(1).cloned().collect(), - guest_entrypoint, - ) - }; - - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, guest_entrypoint)?; - - return Ok(ResolvedChildProcessExecution { - command: String::from(JAVASCRIPT_COMMAND), - process_args: std::iter::once(command.to_owned()) - .chain(args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint, - execution_args, - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - if command.ends_with(".js") || command.ends_with(".mjs") || command.ends_with(".cjs") { - let requested_host_entrypoint = resolve_host_entrypoint_within_vm_host_cwd(vm, command); - if requested_host_entrypoint.is_some() && !allow_host_path_overrides { - let requested_cwd = cwd.unwrap_or(guest_cwd.as_str()); - return Err(SidecarError::InvalidState(format!( - "execution cwd {requested_cwd} is outside sandbox root {}", - vm.host_cwd.to_string_lossy() - ))); - } - let host_entrypoint_override = allow_host_path_overrides - .then(|| resolve_host_entrypoint_within_vm_host_cwd(vm, command)) - .flatten(); - let guest_entrypoint = host_entrypoint_override - .as_ref() - .map(|(guest_entrypoint, _)| guest_entrypoint.clone()) - .or_else(|| guest_entrypoint_for_specifier(&guest_cwd, command)); - let entrypoint = host_entrypoint_override.map_or_else( - || { - guest_entrypoint.as_ref().map_or_else( - || command.to_owned(), - |guest_entrypoint| { - resolve_vm_guest_path_to_host(vm, guest_entrypoint) - .to_string_lossy() - .into_owned() - }, - ) - }, - |(_, host_entrypoint)| host_entrypoint, - ); - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, guest_entrypoint)?; - - return Ok(ResolvedChildProcessExecution { - command: String::from(JAVASCRIPT_COMMAND), - process_args: std::iter::once(command.to_owned()) - .chain(args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint, - execution_args: args.to_vec(), - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - - let guest_entrypoint = resolve_guest_command_entrypoint( - vm, - &guest_cwd, - command, - env.get("PATH").map(String::as_str), - ) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "command not found on native sidecar path: {command}" - )) - })?; - let wasm_permission_tier = explicit_wasm_permission_tier - .or_else(|| vm.command_permissions.get(command).copied()) - .or_else(|| { - Path::new(&guest_entrypoint) - .file_name() - .and_then(|name| name.to_str()) - .and_then(|name| vm.command_permissions.get(name).copied()) - }); - - let host_entrypoint = resolve_vm_guest_path_to_host(vm, &guest_entrypoint); - if let Some((javascript_guest_entrypoint, javascript_host_entrypoint)) = - resolve_javascript_command_entrypoint(vm, &guest_entrypoint, &host_entrypoint) - { - prepare_guest_runtime_env( - vm, - &mut env, - &guest_cwd, - &host_cwd, - Some(javascript_guest_entrypoint), - )?; - - return Ok(ResolvedChildProcessExecution { - command: command.to_owned(), - process_args: std::iter::once(command.to_owned()) - .chain(args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::JavaScript, - entrypoint: javascript_host_entrypoint.to_string_lossy().into_owned(), - execution_args: args.to_vec(), - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }); - } - prepare_guest_runtime_env( - vm, - &mut env, - &guest_cwd, - &host_cwd, - Some(guest_entrypoint.clone()), - )?; - - Ok(ResolvedChildProcessExecution { - command: command.to_owned(), - process_args: std::iter::once(command.to_owned()) - .chain(args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::WebAssembly, - entrypoint: host_entrypoint.to_string_lossy().into_owned(), - execution_args: args.to_vec(), - env, - guest_cwd, - host_cwd, - wasm_permission_tier, - tool_command: false, - }) -} - -const MAX_JAVASCRIPT_COMMAND_REDIRECT_DEPTH: usize = 4; - -fn resolve_javascript_command_entrypoint( - vm: &VmState, - guest_entrypoint: &str, - host_entrypoint: &Path, -) -> Option<(String, PathBuf)> { - // agentOS package content is served guest-native (tar + single-symlink - // mounts) and is never materialized on the host, so the shebang-reading - // fallback below (which reads the host path) cannot classify these - // entrypoints. Within the package mount the only runtimes are WebAssembly - // (`*.wasm`) and JavaScript, and `bin/` launchers are frequently - // extensionless — so classify by extension here: `.wasm` is WASM (fall - // through), everything else in the mount is JavaScript. - if guest_path_is_within_agentos_package_mount(vm, guest_entrypoint) { - let extension = Path::new(guest_entrypoint) - .extension() - .and_then(|extension| extension.to_str()); - if extension != Some("wasm") { - return Some((guest_entrypoint.to_owned(), host_entrypoint.to_path_buf())); - } - return None; - } - - resolve_javascript_command_entrypoint_inner( - vm, - guest_entrypoint, - host_entrypoint, - MAX_JAVASCRIPT_COMMAND_REDIRECT_DEPTH, - ) -} - -fn resolve_javascript_command_entrypoint_inner( - vm: &VmState, - guest_entrypoint: &str, - host_entrypoint: &Path, - redirects_remaining: usize, -) -> Option<(String, PathBuf)> { - if redirects_remaining > 0 { - let symlink_target = fs::symlink_metadata(host_entrypoint) - .ok() - .filter(|metadata| metadata.file_type().is_symlink()) - .and_then(|_| fs::read_link(host_entrypoint).ok()); - if let Some(symlink_target) = symlink_target { - let guest_parent = Path::new(guest_entrypoint) - .parent() - .and_then(|path| path.to_str()) - .unwrap_or("/"); - let symlink_guest_entrypoint = if symlink_target.is_absolute() { - normalize_path(&symlink_target.to_string_lossy()) - } else { - normalize_path(&format!( - "{guest_parent}/{}", - symlink_target.to_string_lossy().replace('\\', "/") - )) - }; - let symlink_host_entrypoint = - resolve_vm_guest_path_to_host(vm, &symlink_guest_entrypoint); - return resolve_javascript_command_entrypoint_inner( - vm, - &symlink_guest_entrypoint, - &symlink_host_entrypoint, - redirects_remaining - 1, - ); - } - } - - let script = load_executable_script_preview(host_entrypoint)?; - let interpreter = parse_script_interpreter_name(&script); - - if interpreter.is_none() && is_probable_javascript_entrypoint(host_entrypoint, &script) { - return Some((guest_entrypoint.to_owned(), host_entrypoint.to_path_buf())); - } - - let interpreter = interpreter?; - if interpreter == "node" { - return Some((guest_entrypoint.to_owned(), host_entrypoint.to_path_buf())); - } - - if redirects_remaining == 0 || !matches!(interpreter.as_str(), "sh" | "bash" | "dash") { - return None; - } - - let shim_target = parse_node_shell_shim_target(&script)?; - let guest_parent = Path::new(guest_entrypoint) - .parent() - .and_then(|path| path.to_str()) - .unwrap_or("/"); - let shim_guest_entrypoint = normalize_path(&format!("{guest_parent}/{shim_target}")); - let shim_host_entrypoint = resolve_vm_guest_path_to_host(vm, &shim_guest_entrypoint); - resolve_javascript_command_entrypoint_inner( - vm, - &shim_guest_entrypoint, - &shim_host_entrypoint, - redirects_remaining - 1, - ) -} - -fn load_executable_script_preview(path: &Path) -> Option { - let bytes = fs::read(path).ok()?; - let preview_len = bytes.len().min(16 * 1024); - Some(String::from_utf8_lossy(&bytes[..preview_len]).into_owned()) -} - -fn parse_script_interpreter_name(script: &str) -> Option { - let shebang = script.lines().next()?.strip_prefix("#!")?.trim(); - let mut tokens = shebang.split_whitespace(); - let command = tokens.next()?; - let command_name = Path::new(command).file_name()?.to_str()?; - if command_name == "env" { - for token in tokens { - if token.starts_with('-') { - continue; - } - return Path::new(token) - .file_name() - .and_then(|name| name.to_str()) - .map(ToOwned::to_owned); - } - return None; - } - - Some(command_name.to_owned()) -} - -fn parse_node_shell_shim_target(script: &str) -> Option { - for line in script.lines() { - let trimmed = line.trim(); - if !trimmed.starts_with("exec ") { - continue; - } - - let mut remaining = trimmed; - while let Some(start) = remaining.find("\"$basedir/") { - let after_prefix = &remaining[start + "\"$basedir/".len()..]; - let end = after_prefix.find('"')?; - let candidate = &after_prefix[..end]; - remaining = &after_prefix[end + 1..]; - - if candidate.is_empty() || candidate == "node" || candidate.ends_with("/node") { - continue; - } - - return Some(candidate.to_owned()); - } - } - - None -} - -fn is_probable_javascript_entrypoint(path: &Path, script: &str) -> bool { - let extension = path - .extension() - .and_then(|value| value.to_str()) - .unwrap_or_default(); - if matches!(extension, "js" | "cjs" | "mjs") { - return true; - } - - if !path - .components() - .any(|component| component.as_os_str() == "node_modules") - { - return false; - } - - let preview = script.trim_start_matches('\u{feff}').trim_start(); - !preview.is_empty() - && !preview.starts_with("#!") - && (preview.starts_with("\"use strict\"") - || preview.starts_with("'use strict'") - || preview.starts_with("import ") - || preview.starts_with("export ") - || preview.starts_with("const ") - || preview.starts_with("let ") - || preview.starts_with("var ") - || preview.starts_with("Object.defineProperty(exports") - || preview.starts_with("module.exports") - || preview.starts_with("require(")) -} - -fn resolve_guest_execution_cwd(vm: &VmState, value: Option<&str>) -> String { - value - .map(normalize_path) - .unwrap_or_else(|| vm.guest_cwd.clone()) -} - -fn resolve_execution_cwds(vm: &VmState, value: Option<&str>) -> (String, PathBuf, bool) { - if let Some(raw_cwd) = value { - let normalized_vm_host_cwd = normalize_host_path(&vm.host_cwd); - let requested_host_cwd = normalize_host_path(Path::new(raw_cwd)); - if path_is_within_root(&requested_host_cwd, &normalized_vm_host_cwd) { - let relative = requested_host_cwd - .strip_prefix(&normalized_vm_host_cwd) - .unwrap_or_else(|_| Path::new("")); - let relative = relative.to_string_lossy().replace('\\', "/"); - let guest_cwd = if relative.is_empty() { - String::from("/") - } else { - normalize_path(&format!("/{relative}")) - }; - return (guest_cwd, requested_host_cwd, true); - } - } - - let guest_cwd = resolve_guest_execution_cwd(vm, value); - let host_cwd = if value.is_none() { - vm.host_cwd.clone() - } else { - resolve_vm_guest_path_to_host(vm, &guest_cwd) - }; - (guest_cwd, host_cwd, value.is_none()) -} - -fn resolve_vm_guest_path_to_host(vm: &VmState, guest_path: &str) -> PathBuf { - host_mount_path_for_guest_path(vm, guest_path) - .unwrap_or_else(|| shadow_path_for_guest(vm, guest_path)) -} - -fn shadow_path_for_guest(vm: &VmState, guest_path: &str) -> PathBuf { - let normalized = normalize_path(guest_path); - let relative = normalized.trim_start_matches('/'); - if relative.is_empty() { - return vm.cwd.clone(); - } - vm.cwd.join(relative) -} - -fn apply_shell_cwd_prefix(command: &str, mut args: Vec, guest_cwd: &str) -> Vec { - if guest_cwd == "/" || !is_shell_command(command) { - return args; - } - - let Some(flag) = args.first() else { - return args; - }; - if !matches!(flag.as_str(), "-c" | "-lc") || args.len() < 2 { - return args; - } - - let command_text = args[1].clone(); - let quoted_cwd = shell_single_quote(guest_cwd); - args[1] = format!("cd {quoted_cwd} && {command_text}"); - args -} - -fn is_shell_command(command: &str) -> bool { - Path::new(command) - .file_name() - .and_then(|name| name.to_str()) - .unwrap_or(command) - .trim_end_matches(".exe") - .eq("sh") - || Path::new(command) - .file_name() - .and_then(|name| name.to_str()) - .unwrap_or(command) - .trim_end_matches(".exe") - .eq("bash") -} - -fn shell_single_quote(value: &str) -> String { - if value.is_empty() { - return String::from("''"); - } - format!("'{}'", value.replace('\'', "'\"'\"'")) -} - -pub(crate) fn sync_active_process_host_writes_to_kernel( - vm: &mut VmState, -) -> Result<(), SidecarError> { - if vm.root_filesystem_mode != RootFilesystemMode::ReadOnly { - let shadow_root = vm.cwd.clone(); - sync_host_directory_tree_to_kernel(vm, &shadow_root, "/")?; - } - - let normalized_vm_root = normalize_host_path(&vm.cwd); - let extra_roots = collect_active_process_host_sync_roots(vm, &normalized_vm_root); - for (host_cwd, guest_cwd) in extra_roots { - sync_host_directory_tree_to_kernel(vm, &host_cwd, &guest_cwd)?; - } - - Ok(()) -} - -fn collect_active_process_host_sync_roots( - vm: &VmState, - normalized_vm_root: &Path, -) -> Vec<(PathBuf, String)> { - let mut roots = Vec::new(); - let mut seen = BTreeSet::new(); - - for process in vm.active_processes.values() { - collect_process_host_sync_roots(process, normalized_vm_root, &mut seen, &mut roots); - } - - roots -} - -fn collect_process_host_sync_roots( - process: &ActiveProcess, - normalized_vm_root: &Path, - seen: &mut BTreeSet<(PathBuf, String)>, - roots: &mut Vec<(PathBuf, String)>, -) { - let normalized_host_cwd = normalize_host_path(&process.host_cwd); - if !path_is_within_root(&normalized_host_cwd, normalized_vm_root) { - let guest_cwd = normalize_path(&process.guest_cwd); - if seen.insert((normalized_host_cwd.clone(), guest_cwd.clone())) { - roots.push((normalized_host_cwd, guest_cwd)); - } - } - - for child in process.child_processes.values() { - collect_process_host_sync_roots(child, normalized_vm_root, seen, roots); - } -} - -fn sync_process_host_writes_to_kernel( - vm: &mut VmState, - process: &ActiveProcess, -) -> Result<(), SidecarError> { - if vm.root_filesystem_mode != RootFilesystemMode::ReadOnly { - let shadow_root = vm.cwd.clone(); - sync_host_directory_tree_to_kernel(vm, &shadow_root, "/")?; - } - - if !path_is_within_root( - &normalize_host_path(&process.host_cwd), - &normalize_host_path(&vm.cwd), - ) { - sync_host_directory_tree_to_kernel(vm, &process.host_cwd, &process.guest_cwd)?; - } - - Ok(()) -} - -fn host_sync_root_is_filesystem_root(host_root: &Path) -> bool { - normalize_host_path(host_root) == Path::new("/") -} - -fn sync_host_directory_tree_to_kernel( - vm: &mut VmState, - host_root: &Path, - guest_root: &str, -) -> Result<(), SidecarError> { - let normalized_host_root = normalize_host_path(host_root); - let normalized_guest_root = normalize_path(guest_root); - if host_sync_root_is_filesystem_root(host_root) { - // A process tracked with host cwd "/" would pull the entire host - // filesystem into the kernel VFS (until the size/inode caps fire). - // No sanctioned flow shadows the host root wholesale; host access is - // scoped through mounts. - tracing::warn!("skipping host shadow sync rooted at the host filesystem root"); - return Ok(()); - } - let mut synced_file_times = BTreeMap::new(); - sync_host_directory_tree_to_kernel_inner( - vm, - &normalized_host_root, - &normalized_host_root, - &normalized_guest_root, - &mut synced_file_times, - ) -} - -fn sync_host_directory_tree_to_kernel_inner( - vm: &mut VmState, - host_root: &Path, - current_host_dir: &Path, - guest_root: &str, - synced_file_times: &mut BTreeMap<(u64, u64), (u64, u64)>, -) -> Result<(), SidecarError> { - let entries = match fs::read_dir(current_host_dir) { - Ok(entries) => entries, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(()), - Err(error) if error.kind() == std::io::ErrorKind::PermissionDenied => { - // Host dirs the sidecar user cannot read (e.g. root-owned - // /lost+found under a host-root mount) are skipped rather than - // failing the whole shadow sync; the guest just won't see them. - tracing::warn!( - path = %current_host_dir.display(), - "skipping unreadable host shadow directory" - ); - return Ok(()); - } - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to read host shadow directory {}: {error}", - current_host_dir.display() - ))); - } - }; - - for entry in entries { - let entry = entry.map_err(|error| { - SidecarError::Io(format!( - "failed to read host shadow entry in {}: {error}", - current_host_dir.display() - )) - })?; - let host_path = entry.path(); - let file_type = entry.file_type().map_err(|error| { - SidecarError::Io(format!( - "failed to stat host shadow entry {}: {error}", - host_path.display() - )) - })?; - let relative_path = host_path - .strip_prefix(host_root) - .map_err(|error| { - SidecarError::InvalidState(format!( - "failed to relativize host shadow path {} against {}: {error}", - host_path.display(), - host_root.display() - )) - })? - .to_string_lossy() - .replace('\\', "/"); - let guest_path = if guest_root == "/" { - normalize_path(&format!("/{relative_path}")) - } else { - normalize_path(&format!( - "{}/{}", - guest_root.trim_end_matches('/'), - relative_path - )) - }; - - if should_skip_shadow_sync_path(vm, &guest_path) { - continue; - } - - if file_type.is_dir() { - let metadata = entry.metadata().map_err(|error| { - SidecarError::Io(format!( - "failed to read host shadow metadata {}: {error}", - host_path.display() - )) - })?; - if !is_shadow_bootstrap_dir(&guest_path) - && !vm.kernel.exists(&guest_path).unwrap_or(false) - { - vm.kernel.mkdir(&guest_path, true).map_err(|error| { - SidecarError::InvalidState(format!( - "failed to sync host shadow directory {} to guest {}: {}", - host_path.display(), - guest_path, - kernel_error(error) - )) - })?; - vm.kernel - .chmod(&guest_path, host_shadow_mode(&metadata)) - .map_err(|error| { - SidecarError::InvalidState(format!( - "failed to sync host shadow directory mode {} to guest {}: {}", - host_path.display(), - guest_path, - kernel_error(error) - )) - })?; - } - sync_host_directory_tree_to_kernel_inner( - vm, - host_root, - &host_path, - guest_root, - synced_file_times, - )?; - continue; - } - - if file_type.is_file() { - let metadata = entry.metadata().map_err(|error| { - SidecarError::Io(format!( - "failed to read host shadow metadata {}: {error}", - host_path.display() - )) - })?; - let timestamp_key = (metadata.dev(), metadata.ino()); - let (atime_ms, mtime_ms) = - *synced_file_times.entry(timestamp_key).or_insert_with(|| { - ( - metadata_time_ms(metadata.atime(), metadata.atime_nsec()), - metadata_time_ms(metadata.mtime(), metadata.mtime_nsec()), - ) - }); - let desired_mode = host_shadow_mode(&metadata); - // Fast path: skip the expensive re-read + re-write when the kernel already - // holds a copy of this shadow file that matches on size, mode, and mtime. - // - // Every read-side fs op (exists/stat/readFile/...) triggers a full - // shadow-tree reconciliation walk. Without this skip the walk re-reads every - // file's bytes from the host and re-writes them into the kernel VFS on every - // op -- O(whole tree) per op, and super-linear as the VM's shadow grows, - // which is a dominant source of session-creation/runtime latency on - // populated VMs. - // - // This is a (size, mode, mtime) quick-check, the same heuristic rsync uses - // by default. It needs no separate cache to invalidate -- it compares against - // the kernel's own stat, so a kernel reset (e.g. a layer swap) or any host - // change that moves size/mode/mtime forces a resync. Limitation: mtime is - // compared at the millisecond granularity the kernel stores (utimes truncates - // to ms), so a host-side rewrite that preserves byte length AND mode AND lands - // in the same wall-clock millisecond can be skipped and leave stale bytes. - // That window is sub-millisecond same-length edits; if it ever matters here, - // upgrade this to a content digest (or full-precision mtime) for files whose - // mtime is within the last few ms of `now`. - if let Ok(existing) = vm.kernel.lstat(&guest_path) { - if !existing.is_directory - && !existing.is_symbolic_link - && existing.size == metadata.len() - && (existing.mode & 0o7777) == (desired_mode & 0o7777) - && existing.mtime_ms == mtime_ms - { - continue; - } - } - let bytes = match read_host_shadow_file(&host_path, desired_mode) { - Ok(bytes) => bytes, - // The host entry vanished between the walk and the read - // (short-lived files churn constantly — editor swap files, - // temp files). Skipping matches native semantics; failing - // here would poison EVERY subsequent fs op on the VM. - Err(error) if error.kind() == std::io::ErrorKind::NotFound => continue, - // Same tolerance for entries the sidecar user cannot read - // (root-owned files under a host-root mount): skip them - // rather than poisoning the whole sync. - Err(error) - if error.kind() == std::io::ErrorKind::PermissionDenied - || error.raw_os_error() == Some(libc::EPERM) => - { - tracing::warn!( - path = %host_path.display(), - "skipping unreadable host shadow file" - ); - continue; - } - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to read host shadow file {}: {error}", - host_path.display() - ))); - } - }; - match vm.kernel.write_file(&guest_path, bytes) { - Ok(()) => {} - // ENOENT here means the guest-side path cannot currently - // receive the write (e.g. it is a symlink whose target was - // just unlinked by the guest — vim's swap-file dance). The - // entry is mid-churn; skip it rather than failing the VM. - Err(error) if error.code() == "ENOENT" => continue, - Err(error) => { - return Err(SidecarError::InvalidState(format!( - "failed to sync host shadow file {} to guest {}: {}", - host_path.display(), - guest_path, - kernel_error(error) - ))); - } - } - vm.kernel - .chmod(&guest_path, desired_mode) - .map_err(|error| { - SidecarError::InvalidState(format!( - "failed to sync host shadow file mode {} to guest {}: {}", - host_path.display(), - guest_path, - kernel_error(error) - )) - })?; - vm.kernel - .utimes(&guest_path, atime_ms, mtime_ms) - .map_err(|error| { - SidecarError::InvalidState(format!( - "failed to sync host shadow file times {} to guest {}: {}", - host_path.display(), - guest_path, - kernel_error(error) - )) - })?; - continue; - } - - if file_type.is_symlink() { - let target = match fs::read_link(&host_path) { - Ok(target) => target, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => continue, - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to read host shadow symlink {}: {error}", - host_path.display() - ))); - } - }; - replace_kernel_symlink(vm, &guest_path, &target.to_string_lossy())?; - } - } - - Ok(()) -} - -fn replace_kernel_symlink( - vm: &mut VmState, - guest_path: &str, - target: &str, -) -> Result<(), SidecarError> { - if vm.kernel.symlink(target, guest_path).is_ok() { - return Ok(()); - } - - if let Ok(existing_target) = vm.kernel.read_link(guest_path) { - if existing_target == target { - return Ok(()); - } - } - - let _ = vm.kernel.remove_file(guest_path); - let _ = vm.kernel.remove_dir(guest_path); - vm.kernel - .symlink(target, guest_path) - .map_err(kernel_error)?; - Ok(()) -} - -fn host_shadow_mode(metadata: &fs::Metadata) -> u32 { - metadata.permissions().mode() & 0o7777 -} - -/// Reads a shadow-root file back into the kernel even when guest-visible mode -/// bits make it unreadable for the host user. The sidecar is the kernel for -/// this tree, so guest permission bits (for example a 0o200 write-only file -/// produced by `chmod` plus a shell append redirect) must not break the -/// exit-time shadow sync. The original mode is restored after the read. -fn read_host_shadow_file(host_path: &Path, mode: u32) -> std::io::Result> { - match fs::read(host_path) { - Ok(bytes) => Ok(bytes), - Err(error) if error.kind() == std::io::ErrorKind::PermissionDenied => { - fs::set_permissions(host_path, fs::Permissions::from_mode(mode | 0o400))?; - let result = fs::read(host_path); - fs::set_permissions(host_path, fs::Permissions::from_mode(mode))?; - result - } - Err(error) => Err(error), - } -} - -fn metadata_time_ms(seconds: i64, nanos: i64) -> u64 { - let seconds = seconds.max(0) as u64; - let nanos = nanos.max(0) as u64; - seconds - .saturating_mul(1_000) - .saturating_add(nanos / 1_000_000) -} - -fn is_shadow_bootstrap_dir(path: &str) -> bool { - matches!( - path, - "/dev" - | "/proc" - | "/tmp" - | "/bin" - | "/lib" - | "/sbin" - | "/boot" - | "/etc" - | "/root" - | "/run" - | "/srv" - | "/sys" - | "/opt" - | "/mnt" - | "/media" - | "/home" - | "/home/agentos" - | "/usr" - | "/usr/bin" - | "/usr/games" - | "/usr/include" - | "/usr/lib" - | "/usr/libexec" - | "/usr/man" - | "/usr/local" - | "/usr/local/bin" - | "/usr/sbin" - | "/usr/share" - | "/usr/share/man" - | "/var" - | "/var/cache" - | "/var/empty" - | "/var/lib" - | "/var/lock" - | "/var/log" - | "/var/run" - | "/var/spool" - | "/var/tmp" - | "/etc/agentos" - | "/workspace" - ) -} - -#[cfg(test)] -mod shadow_sync_tests { - use super::{is_protected_agentos_shadow_sync_path, is_shadow_bootstrap_dir}; - - #[test] - fn shadow_bootstrap_sync_skips_virtual_home_tree() { - assert!(is_shadow_bootstrap_dir("/home")); - assert!(is_shadow_bootstrap_dir("/home/agentos")); - } - - #[test] - fn protected_agentos_paths_are_not_shadow_synced() { - assert!(is_protected_agentos_shadow_sync_path("/etc/agentos")); - assert!(is_protected_agentos_shadow_sync_path( - "/etc/agentos/instructions.md" - )); - assert!(!is_protected_agentos_shadow_sync_path("/etc/agentos-copy")); - assert!(!is_protected_agentos_shadow_sync_path("/etc/agentos.md")); - } -} - -fn is_kernel_owned_shadow_sync_path(path: &str) -> bool { - matches!(path, "/dev" | "/proc" | "/sys") - || path.starts_with("/dev/") - || path.starts_with("/proc/") - || path.starts_with("/sys/") -} - -pub(crate) fn is_protected_agentos_shadow_sync_path(path: &str) -> bool { - path == "/etc/agentos" || path.starts_with("/etc/agentos/") -} - -fn should_skip_shadow_sync_path(vm: &VmState, guest_path: &str) -> bool { - is_kernel_owned_shadow_sync_path(guest_path) - || is_protected_agentos_shadow_sync_path(guest_path) - // agentOS package content is served guest-native from read-only tar - // mounts; it is already present in the guest and cannot be written, so a - // host->guest shadow sync would fail with EROFS. Skip it. - || guest_path_is_within_agentos_package_mount(vm, guest_path) - || host_mount_path_for_guest_path_from_mounts(&vm.configuration.mounts, guest_path) - .is_some() -} - -fn resolve_path_like_guest_specifier(cwd: &str, specifier: &str) -> String { - if specifier.starts_with("file://") { - normalize_path(specifier.trim_start_matches("file://")) - } else if specifier.starts_with("file:") { - normalize_path(specifier.trim_start_matches("file:")) - } else if specifier.starts_with('/') { - normalize_path(specifier) - } else { - normalize_path(&format!("{cwd}/{specifier}")) - } -} - -fn guest_entrypoint_for_specifier(cwd: &str, specifier: &str) -> Option { - is_path_like_specifier(specifier).then(|| resolve_path_like_guest_specifier(cwd, specifier)) -} - -fn is_node_runtime_command(command: &str) -> bool { - matches!(command, "node" | "npm" | "npx") - || Path::new(command) - .file_name() - .and_then(|name| name.to_str()) - .is_some_and(|name| matches!(name, "node" | "npm" | "npx")) -} - -fn python_command_base_name(command: &str) -> &str { - Path::new(command) - .file_name() - .and_then(|name| name.to_str()) - .unwrap_or(command) -} - -/// `python` / `python3` (and `pip` / `pip3`, which map to `python -m pip`) are -/// served by the embedded Pyodide runtime, mirroring how `node` is served by the -/// embedded V8 runtime. -fn is_python_runtime_command(command: &str) -> bool { - matches!( - python_command_base_name(command), - "python" | "python3" | "pip" | "pip3" - ) -} - -/// Parse a `python` / `pip` command line into a Pyodide execution. Supports the -/// CPython program selectors `-c CODE`, `-m MODULE`, a `SCRIPT` path, `-` / -/// piped stdin programs, and a bare interpreter (interactive REPL). The chosen -/// mode plus `sys.argv` are forwarded to the runner as `AGENTOS_PYTHON_*` control -/// env, which the runner consumes and never exposes in the guest `os.environ`. -fn resolve_python_command_execution( - vm: &VmState, - command: &str, - args: &[String], - mut env: BTreeMap, - guest_cwd: String, - host_cwd: PathBuf, -) -> Result { - let base_name = python_command_base_name(command); - let is_pip = matches!(base_name, "pip" | "pip3"); - - let mut entrypoint = String::new(); - let mut argv: Vec = Vec::new(); - let mut module: Option = None; - let mut stdin_program = false; - let mut interactive = false; - let mut guest_entrypoint: Option = None; - - if is_pip { - module = Some(String::from("pip")); - argv.push(String::from("pip")); - argv.extend(args.iter().cloned()); - } else { - // Skip the value-less interpreter flags we can safely ignore so they do - // not get mistaken for a script path. - let mut idx = 0; - while let Some(flag) = args.get(idx) { - match flag.as_str() { - "-B" | "-E" | "-I" | "-O" | "-OO" | "-q" | "-s" | "-S" | "-u" | "-v" | "-b" - | "-d" | "-x" => idx += 1, - _ => break, - } - } - let rest = &args[idx..]; - match rest.first().map(String::as_str) { - Some("-c") => { - entrypoint = rest.get(1).cloned().ok_or_else(|| { - SidecarError::InvalidState(String::from("argument expected for the -c option")) - })?; - argv.push(String::from("-c")); - argv.extend(rest.iter().skip(2).cloned()); - } - Some("-m") => { - let name = rest.get(1).cloned().ok_or_else(|| { - SidecarError::InvalidState(String::from("argument expected for the -m option")) - })?; - module = Some(name); - argv.push(String::from("-m")); - argv.extend(rest.iter().skip(2).cloned()); - } - Some("-") => { - stdin_program = true; - argv.push(String::from("-")); - argv.extend(rest.iter().skip(1).cloned()); - } - Some(spec) if !spec.starts_with('-') => { - let resolved_guest = guest_entrypoint_for_specifier(&guest_cwd, spec) - .unwrap_or_else(|| spec.to_string()); - entrypoint = resolved_guest.clone(); - env.insert(String::from("AGENTOS_PYTHON_FILE"), resolved_guest.clone()); - guest_entrypoint = Some(resolved_guest); - argv.push(spec.to_string()); - argv.extend(rest.iter().skip(1).cloned()); - } - Some(other) => { - return Err(SidecarError::InvalidState(format!( - "unsupported python option: {other}" - ))); - } - None => { - interactive = true; - argv.push(String::new()); - } - } - } - - env.insert( - String::from("AGENTOS_PYTHON_ARGV"), - serde_json::to_string(&argv).unwrap_or_else(|_| String::from("[]")), - ); - if let Some(module) = &module { - env.insert(String::from("AGENTOS_PYTHON_MODULE"), module.clone()); - } - if stdin_program { - env.insert( - String::from("AGENTOS_PYTHON_STDIN_PROGRAM"), - String::from("1"), - ); - } - if interactive { - env.insert( - String::from("AGENTOS_PYTHON_INTERACTIVE"), - String::from("1"), - ); - } - - prepare_guest_runtime_env(vm, &mut env, &guest_cwd, &host_cwd, guest_entrypoint)?; - - Ok(ResolvedChildProcessExecution { - command: String::from(PYTHON_COMMAND), - process_args: std::iter::once(command.to_owned()) - .chain(args.iter().cloned()) - .collect(), - runtime: GuestRuntimeKind::Python, - entrypoint, - execution_args: args.to_vec(), - env, - guest_cwd, - host_cwd, - wasm_permission_tier: None, - tool_command: false, - }) -} - -fn resolve_special_node_cli_invocation( - args: &[String], - env: &mut BTreeMap, -) -> Option<(String, Vec)> { - let first = args.first()?; - match first.as_str() { - "-e" | "--eval" => { - env.insert( - String::from("AGENTOS_NODE_EVAL"), - args.get(1).cloned().unwrap_or_default(), - ); - Some((first.clone(), args.iter().skip(2).cloned().collect())) - } - "-v" | "--version" => { - env.insert( - String::from("AGENTOS_NODE_EVAL"), - String::from("console.log(process.version);"), - ); - Some((String::from("-e"), args.to_vec())) - } - _ => None, - } -} - -fn node_runtime_command_name(command: &str) -> Option<&str> { - let name = Path::new(command) - .file_name() - .and_then(|name| name.to_str())?; - matches!(name, "node" | "npm" | "npx").then_some(name) -} - -struct ResolvedHostNodeCliEntrypoint { - command_name: String, - guest_root: String, - guest_entrypoint: String, - package_root: PathBuf, -} - -fn resolve_host_node_cli_entrypoint(command: &str) -> Option { - let command_name = node_runtime_command_name(command)?; - if !matches!(command_name, "npm" | "npx") { - return None; - } - - let path = std::env::var_os("PATH")?; - for root in std::env::split_paths(&path) { - let candidate = root.join(command_name); - if !candidate.is_file() { - continue; - } - let entrypoint = candidate.canonicalize().ok().unwrap_or(candidate); - let package_root = entrypoint.parent()?.parent()?.to_path_buf(); - let guest_root = format!("/__secure_exec/node-runtime/{command_name}"); - let relative_entrypoint = entrypoint.strip_prefix(&package_root).ok()?; - let guest_entrypoint = normalize_path(&format!( - "{guest_root}/{}", - relative_entrypoint.to_string_lossy().replace('\\', "/") - )); - return Some(ResolvedHostNodeCliEntrypoint { - command_name: command_name.to_owned(), - guest_root, - guest_entrypoint, - package_root, - }); - } - - None -} - -fn build_host_node_cli_eval(cli: &ResolvedHostNodeCliEntrypoint) -> String { - let guest_npm_main = normalize_path(&format!("{}/lib/npm.js", cli.guest_root)); - let guest_npm_cli = normalize_path(&format!("{}/bin/npm-cli.js", cli.guest_root)); - let guest_package_json = normalize_path(&format!("{}/package.json", cli.guest_root)); - let guest_display_module = normalize_path(&format!("{}/lib/utils/display.js", cli.guest_root)); - let guest_log_file_module = - normalize_path(&format!("{}/lib/utils/log-file.js", cli.guest_root)); - let debug_preamble = "const __agentOSDebugNpmCli = !!process.env.CODEX_DEBUG_NPM_CLI; const __agentOSDebugLog = (...args) => { if (__agentOSDebugNpmCli) { console.error('[secure-exec npm debug]', ...args); } }; const __agentOSIsProcessExitError = (error) => !!(error && typeof error === 'object' && (error._isProcessExit === true || error.name === 'ProcessExitError')); const __agentOSResolveExitCode = (code) => Number.isFinite(code) ? code : (Number.isFinite(process.exitCode) ? process.exitCode : 0); const __agentOSFinish = (code) => { process.exitCode = __agentOSResolveExitCode(code); }; if (__agentOSDebugNpmCli) { const __agentOSWrapAsyncFsMethod = (__agentOSTarget, __agentOSMethod) => { const __agentOSOriginal = __agentOSTarget[__agentOSMethod]; if (typeof __agentOSOriginal !== 'function' || __agentOSOriginal.__agentOSDebugWrapped) { return; } const __agentOSWrapped = async (...args) => { const target = args.length > 0 ? args[0] : ''; __agentOSDebugLog(`fs.${__agentOSMethod}:start`, String(target)); try { const result = await __agentOSOriginal.apply(__agentOSTarget, args); __agentOSDebugLog(`fs.${__agentOSMethod}:done`, String(target)); return result; } catch (error) { __agentOSDebugLog(`fs.${__agentOSMethod}:error`, String(target), error && error.stack ? error.stack : String(error)); throw error; } }; __agentOSWrapped.__agentOSDebugWrapped = true; __agentOSTarget[__agentOSMethod] = __agentOSWrapped; }; const __agentOSWrapSyncFsMethod = (__agentOSTarget, __agentOSMethod) => { const __agentOSOriginal = __agentOSTarget[__agentOSMethod]; if (typeof __agentOSOriginal !== 'function' || __agentOSOriginal.__agentOSDebugWrapped) { return; } const __agentOSWrapped = (...args) => { const target = args.length > 0 ? args[0] : ''; __agentOSDebugLog(`fs.${__agentOSMethod}:start`, String(target)); try { const result = __agentOSOriginal.apply(__agentOSTarget, args); __agentOSDebugLog(`fs.${__agentOSMethod}:done`, String(target)); return result; } catch (error) { __agentOSDebugLog(`fs.${__agentOSMethod}:error`, String(target), error && error.stack ? error.stack : String(error)); throw error; } }; __agentOSWrapped.__agentOSDebugWrapped = true; __agentOSTarget[__agentOSMethod] = __agentOSWrapped; }; const __agentOSFsPromiseModules = [require('fs/promises'), require('node:fs/promises')]; for (const __agentOSFsPromises of __agentOSFsPromiseModules) { for (const __agentOSMethod of ['access', 'lstat', 'mkdir', 'open', 'readFile', 'readdir', 'readlink', 'realpath', 'rename', 'rm', 'rmdir', 'stat', 'symlink', 'unlink', 'writeFile']) { __agentOSWrapAsyncFsMethod(__agentOSFsPromises, __agentOSMethod); } } const __agentOSFsModules = [require('fs'), require('node:fs')]; for (const __agentOSFs of __agentOSFsModules) { for (const __agentOSMethod of ['accessSync', 'existsSync', 'lstatSync', 'mkdirSync', 'openSync', 'readFileSync', 'readdirSync', 'readlinkSync', 'realpathSync', 'renameSync', 'rmSync', 'rmdirSync', 'statSync', 'symlinkSync', 'unlinkSync', 'writeFileSync']) { __agentOSWrapSyncFsMethod(__agentOSFs, __agentOSMethod); } } }"; - let display_stub = format!( - "const __agentOSDisplayModulePath = require.resolve({display_module}); const __agentOSLogFileModulePath = require.resolve({log_file_module}); const __agentOSColorPassthrough = new Proxy((value) => value, {{ get: () => __agentOSColorPassthrough, apply: (_target, _thisArg, args) => args[0] }}); class __AgentOSNpmDisplayStub {{ constructor() {{ this.chalk = {{ noColor: __agentOSColorPassthrough, stdout: __agentOSColorPassthrough, stderr: __agentOSColorPassthrough }}; this._logPaused = true; this._logBuffer = []; this._outputBuffer = []; this._write = (stream, values) => {{ if (!Array.isArray(values) || values.length === 0) {{ return; }} const text = values.map((value) => typeof value === 'string' ? value : String(value)).join(' '); if (text.length === 0) {{ return; }} const normalized = text.replace(/\\r\\n/g, '\\n'); if (/^\\n?> npx\\n> /u.test(normalized)) {{ return; }} stream.write(text.endsWith('\\n') ? text : `${{text}}\\n`); }}; this._inputHandler = (level, ...args) => {{ if (level !== 'read') {{ return; }} const [resolve, reject, callback] = args; Promise.resolve().then(() => callback()).then(resolve, reject); }}; this._logHandler = (level, ...args) => {{ if (level === 'resume') {{ this._logPaused = false; for (const entry of this._logBuffer.splice(0)) {{ this._write(process.stderr, entry); }} return; }} if (level === 'pause') {{ this._logPaused = true; return; }} if (this._logPaused) {{ this._logBuffer.push(args); return; }} this._write(process.stderr, args); }}; this._outputHandler = (level, ...args) => {{ if (level === 'buffer') {{ this._outputBuffer.push(['standard', args]); return; }} if (level === 'flush') {{ for (const [bufferLevel, bufferArgs] of this._outputBuffer.splice(0)) {{ this._write(bufferLevel === 'error' ? process.stderr : process.stdout, bufferArgs); }} return; }} this._write(level === 'error' ? process.stderr : process.stdout, args); }}; process.on('input', this._inputHandler); process.on('log', this._logHandler); process.on('output', this._outputHandler); }} async load() {{ process.emit('log', 'resume'); process.emit('output', 'flush'); }} off() {{ if (this._inputHandler) {{ process.off('input', this._inputHandler); }} if (this._logHandler) {{ process.off('log', this._logHandler); }} if (this._outputHandler) {{ process.off('output', this._outputHandler); }} this._logBuffer.length = 0; this._outputBuffer.length = 0; }} }} class __AgentOSNpmLogFileStub {{ constructor() {{ this.files = []; }} async load() {{ return []; }} off() {{}} }} globalThis._moduleCache[__agentOSDisplayModulePath] = {{ exports: __AgentOSNpmDisplayStub }}; globalThis._moduleCache[__agentOSLogFileModulePath] = {{ exports: __AgentOSNpmLogFileStub }};", - display_module = serde_json::to_string(&guest_display_module) - .unwrap_or_else(|_| format!("\"{guest_display_module}\"")), - log_file_module = serde_json::to_string(&guest_log_file_module) - .unwrap_or_else(|_| format!("\"{guest_log_file_module}\"")), - ); - let registry_fetch_stub = "const { createRequire: __agentOSCreateRequire } = require('module'); const __agentOSNpmRequire = __agentOSCreateRequire(require.resolve(__AGENTOS_NPM_MAIN__)); try { const __agentOSMinipassFetchPath = __agentOSNpmRequire.resolve('minipass-fetch'); const __agentOSMinipassFetch = __agentOSNpmRequire(__agentOSMinipassFetchPath); const { FetchError: __agentOSFetchError, Headers: __agentOSFetchHeaders, Request: __agentOSFetchRequest, Response: __agentOSFetchResponse, AbortError: __agentOSAbortError } = __agentOSMinipassFetch; const { Minipass: __agentOSMinipass } = __agentOSNpmRequire('minipass'); const __agentOSCreateBinaryMinipass = () => new __agentOSMinipass({ objectMode: false, encoding: null }); const __agentOSCloneBuffer = (buffer) => Buffer.isBuffer(buffer) ? Buffer.from(buffer) : Buffer.from(buffer ?? []); const __agentOSBufferToArrayBuffer = (buffer) => { const bytes = __agentOSCloneBuffer(buffer); return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength); }; const __agentOSAttachBufferedBodyMethods = (response, responseBuffer) => { const __agentOSReadBuffer = async () => __agentOSCloneBuffer(responseBuffer); response.__agentOSBufferedBody = __agentOSCloneBuffer(responseBuffer); response.buffer = __agentOSReadBuffer; response.text = async () => (await __agentOSReadBuffer()).toString('utf8'); response.json = async () => JSON.parse(await response.text()); response.arrayBuffer = async () => __agentOSBufferToArrayBuffer(await __agentOSReadBuffer()); response.clone = () => { const clonedBody = __agentOSCreateBinaryMinipass(); const clonedBuffer = __agentOSCloneBuffer(responseBuffer); clonedBody.end(clonedBuffer); const clonedResponse = new __agentOSFetchResponse(clonedBody, { url: response.url, status: response.status, statusText: response.statusText, headers: response.headers, size: response.size, timeout: response.timeout, counter: response.counter, trailer: response.trailer }); return __agentOSAttachBufferedBodyMethods(clonedResponse, clonedBuffer); }; return response; }; const __agentOSNormalizeHeaders = (__agentOSHeaders) => { const normalized = {}; __agentOSHeaders.forEach((value, key) => { if (normalized[key] === undefined) { normalized[key] = value; return; } if (Array.isArray(normalized[key])) { normalized[key].push(value); return; } normalized[key] = [normalized[key], value]; }); return normalized; }; const __agentOSPatchedMinipassFetch = async (input, opts = {}) => { const request = input instanceof __agentOSFetchRequest ? input : new __agentOSFetchRequest(input, opts); const __agentOSController = !request.signal && typeof AbortController === 'function' ? new AbortController() : null; const __agentOSSignal = request.signal ?? __agentOSController?.signal; let __agentOSTimer = null; if (__agentOSController && Number.isFinite(request.timeout) && request.timeout > 0) { __agentOSTimer = setTimeout(() => __agentOSController.abort(new Error(`network timeout at: ${request.url}`)), request.timeout); __agentOSTimer.unref?.(); } try { const requestHeaders = {}; request.headers.forEach((value, key) => { requestHeaders[key] = value; }); const response = await fetch(request.url, { method: request.method, headers: requestHeaders, body: request.body ?? undefined, redirect: request.redirect ?? opts.redirect ?? 'follow', signal: __agentOSSignal, ...(request.body ? { duplex: 'half' } : {}) }); const responseBody = __agentOSCreateBinaryMinipass(); const contentType = String(response.headers.get('content-type') || '').toLowerCase(); const responseBuffer = contentType.includes('json') ? Buffer.from(JSON.stringify(await response.json())) : contentType.startsWith('text/') ? Buffer.from(await response.text()) : Buffer.from(await response.arrayBuffer()); responseBody.end(responseBuffer); return __agentOSAttachBufferedBodyMethods(new __agentOSFetchResponse(responseBody, { url: response.url, status: response.status, statusText: response.statusText, headers: __agentOSNormalizeHeaders(response.headers), size: request.size, timeout: request.timeout, counter: request.counter ?? opts.counter ?? 0, trailer: Promise.resolve(new __agentOSFetchHeaders()) }), responseBuffer); } catch (error) { if (error instanceof Error) { throw error; } throw new __agentOSFetchError(String(error), 'system', error); } finally { if (__agentOSTimer) { clearTimeout(__agentOSTimer); } } }; globalThis.__agentOSPatchedMinipassFetch = __agentOSPatchedMinipassFetch; __agentOSPatchedMinipassFetch.isRedirect = typeof __agentOSMinipassFetch.isRedirect === 'function' ? __agentOSMinipassFetch.isRedirect.bind(__agentOSMinipassFetch) : (code) => code === 301 || code === 302 || code === 303 || code === 307 || code === 308; __agentOSPatchedMinipassFetch.FetchError = __agentOSFetchError; __agentOSPatchedMinipassFetch.Headers = __agentOSFetchHeaders; __agentOSPatchedMinipassFetch.Request = __agentOSFetchRequest; __agentOSPatchedMinipassFetch.Response = __agentOSFetchResponse; __agentOSPatchedMinipassFetch.AbortError = __agentOSAbortError; globalThis._moduleCache[__agentOSMinipassFetchPath] = { exports: __agentOSPatchedMinipassFetch }; __agentOSDebugLog('patched-minipass-fetch', __agentOSMinipassFetchPath); const __agentOSCheckResponsePath = __agentOSNpmRequire.resolve('npm-registry-fetch/lib/check-response.js'); const __agentOSCheckResponse = __agentOSNpmRequire(__agentOSCheckResponsePath); const __agentOSEnsureResponseBodyStream = (response) => { if (!response || (response.body && typeof response.body.on === 'function')) { return response; } const body = __agentOSCreateBinaryMinipass(); const finishWithError = (error) => body.emit('error', error instanceof Error ? error : new Error(String(error))); try { if (typeof response.buffer === 'function') { Promise.resolve(response.buffer()).then((buffer) => body.end(buffer), finishWithError); } else if (Buffer.isBuffer(response.body) || typeof response.body === 'string') { body.end(response.body); } else if (response.body && typeof response.body[Symbol.asyncIterator] === 'function') { (async () => { try { for await (const chunk of response.body) { body.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); } body.end(); } catch (error) { finishWithError(error); body.end(); } })(); } else { body.end(); } } catch (error) { finishWithError(error); body.end(); } return new __agentOSFetchResponse(body, response); }; globalThis._moduleCache[__agentOSCheckResponsePath] = { exports: (payload) => { const normalized = { ...payload, res: __agentOSEnsureResponseBodyStream(payload.res) }; __agentOSDebugLog('check-response-body', normalized.res && normalized.res.status, typeof (normalized.res && normalized.res.body), normalized.res && normalized.res.body && typeof normalized.res.body.on, normalized.res && normalized.res.body && normalized.res.body.constructor && normalized.res.body.constructor.name, !!(normalized.res && normalized.res.__agentOSBufferedBody), normalized.res && typeof normalized.res.json); return __agentOSCheckResponse(normalized); } }; __agentOSDebugLog('patched-check-response', __agentOSCheckResponsePath); } catch (error) { __agentOSDebugLog('patch-minipass-fetch-failed', error && error.stack ? error.stack : String(error)); } try { const __agentOSRegistryFetchPath = __agentOSNpmRequire.resolve('npm-registry-fetch'); const __agentOSRegistryFetch = __agentOSNpmRequire(__agentOSRegistryFetchPath); const __agentOSWrapRegistryFetch = (fn) => { const wrapResult = (promise) => Promise.resolve(promise).then((res) => { __agentOSDebugLog('registry-fetch-result', res && res.status, typeof (res && res.body), res && res.body && typeof res.body.on, res && res.body && res.body.constructor && res.body.constructor.name, !!(res && res.__agentOSBufferedBody), res && typeof res.json); return res; }); const wrapped = (uri, opts = {}) => wrapResult(globalThis.__agentOSPatchedMinipassFetch(uri, { method: opts.method, headers: opts.headers, body: opts.body, redirect: opts.redirect, signal: opts.signal, timeout: opts.timeout, size: opts.size, counter: opts.counter })); if (typeof fn.json === 'function') { wrapped.json = (uri, opts = {}) => wrapped(uri, opts).then((res) => res.json()); } if (fn.json && typeof fn.json.stream === 'function') { wrapped.json = wrapped.json || {}; wrapped.json.stream = (uri, path, opts = {}) => fn.json.stream(uri, path, { ...opts, agent: false }); } if (typeof fn.pickRegistry === 'function') { wrapped.pickRegistry = fn.pickRegistry.bind(fn); } if (typeof fn.getAuth === 'function') { wrapped.getAuth = fn.getAuth.bind(fn); } return wrapped; }; globalThis._moduleCache[__agentOSRegistryFetchPath] = { exports: __agentOSWrapRegistryFetch(__agentOSRegistryFetch) }; __agentOSDebugLog('patched-npm-registry-fetch', __agentOSRegistryFetchPath); } catch (error) { __agentOSDebugLog('patch-npm-registry-fetch-failed', error && error.stack ? error.stack : String(error)); }"; - match cli.command_name.as_str() { - "npx" => format!( - "{debug_preamble} {display_stub} {registry_fetch_stub} process.argv[1] = require.resolve({npm_cli}); process.argv.splice(2, 0, 'exec'); __agentOSDebugLog('argv', JSON.stringify(process.argv), 'cwd', process.cwd()); (async () => {{ const pkg = require({package_json}); if (process.argv.includes('--version') || process.argv.includes('-v')) {{ __agentOSDebugLog('version-shortcut'); console.log(pkg.version); __agentOSFinish(0); return; }} const Npm = require({npm_main}); const npm = new Npm(); __agentOSDebugLog('before-load'); const loaded = await npm.load(); __agentOSDebugLog('after-load', loaded && loaded.command, JSON.stringify(loaded && loaded.args)); if (!loaded.exec) {{ __agentOSDebugLog('no-exec'); __agentOSFinish(); return; }} if (!loaded.command) {{ __agentOSDebugLog('no-command'); const {{ output }} = require('proc-log'); output.standard(npm.usage); __agentOSFinish(1); return; }} __agentOSDebugLog('before-exec', loaded.command, JSON.stringify(loaded.args)); await npm.exec(loaded.command, loaded.args); __agentOSDebugLog('after-exec', __agentOSResolveExitCode()); __agentOSFinish(); }})().catch((error) => {{ if (__agentOSIsProcessExitError(error)) {{ __agentOSDebugLog('process-exit-error', __agentOSResolveExitCode(error.code)); __agentOSFinish(error.code); return; }} console.error(error && error.stack ? error.stack : String(error)); __agentOSFinish(error && typeof error === 'object' && Number.isFinite(error.exitCode) ? error.exitCode : 1); }});", - debug_preamble = debug_preamble, - display_stub = display_stub, - registry_fetch_stub = registry_fetch_stub.replace( - "__AGENTOS_NPM_MAIN__", - &serde_json::to_string(&guest_npm_main) - .unwrap_or_else(|_| format!("\"{guest_npm_main}\"")), - ), - npm_main = serde_json::to_string(&guest_npm_main) - .unwrap_or_else(|_| format!("\"{guest_npm_main}\"")), - npm_cli = serde_json::to_string(&guest_npm_cli) - .unwrap_or_else(|_| format!("\"{guest_npm_cli}\"")), - package_json = serde_json::to_string(&guest_package_json) - .unwrap_or_else(|_| format!("\"{guest_package_json}\"")), - ), - _ => format!( - "{debug_preamble} {display_stub} {registry_fetch_stub} __agentOSDebugLog('argv', JSON.stringify(process.argv), 'cwd', process.cwd()); (async () => {{ const pkg = require({package_json}); if (process.argv.includes('--version') || process.argv.includes('-v')) {{ __agentOSDebugLog('version-shortcut'); console.log(pkg.version); __agentOSFinish(0); return; }} const Npm = require({npm_main}); const npm = new Npm(); __agentOSDebugLog('before-load'); const loaded = await npm.load(); __agentOSDebugLog('after-load', loaded && loaded.command, JSON.stringify(loaded && loaded.args)); if (!loaded.exec) {{ __agentOSDebugLog('no-exec'); __agentOSFinish(); return; }} if (!loaded.command) {{ __agentOSDebugLog('no-command'); const {{ output }} = require('proc-log'); output.standard(npm.usage); __agentOSFinish(1); return; }} __agentOSDebugLog('before-exec', loaded.command, JSON.stringify(loaded.args)); await npm.exec(loaded.command, loaded.args); __agentOSDebugLog('after-exec', __agentOSResolveExitCode()); __agentOSFinish(); }})().catch((error) => {{ if (__agentOSIsProcessExitError(error)) {{ __agentOSDebugLog('process-exit-error', __agentOSResolveExitCode(error.code)); __agentOSFinish(error.code); return; }} console.error(error && error.stack ? error.stack : String(error)); __agentOSFinish(error && typeof error === 'object' && Number.isFinite(error.exitCode) ? error.exitCode : 1); }});", - debug_preamble = debug_preamble, - display_stub = display_stub, - registry_fetch_stub = registry_fetch_stub.replace( - "__AGENTOS_NPM_MAIN__", - &serde_json::to_string(&guest_npm_main) - .unwrap_or_else(|_| format!("\"{guest_npm_main}\"")), - ), - npm_main = serde_json::to_string(&guest_npm_main) - .unwrap_or_else(|_| format!("\"{guest_npm_main}\"")), - package_json = serde_json::to_string(&guest_package_json) - .unwrap_or_else(|_| format!("\"{guest_package_json}\"")), - ), - } -} - -fn resolve_guest_command_entrypoint( - vm: &VmState, - guest_cwd: &str, - command: &str, - path_env: Option<&str>, -) -> Option { - if !is_path_like_specifier(command) { - if let Some(entrypoint) = vm.command_guest_paths.get(command) { - return Some(entrypoint.clone()); - } - - for search_dir in guest_command_search_dirs(vm, guest_cwd, path_env) { - let candidate = normalize_path(&format!("{search_dir}/{command}")); - if let Some(entrypoint) = resolve_guest_command_path_candidate(vm, &candidate) { - return Some(entrypoint); - } - } - - return None; - } - - let normalized = resolve_path_like_guest_specifier(guest_cwd, command); - resolve_guest_command_path_candidate(vm, &normalized).or_else(|| { - // Some guest shells materialize PATH lookups into absolute candidate paths. - // If that path points into a searched directory but does not exist, fall - // back to the command basename so the sidecar can remap VM command packages. - let parent_dir = Path::new(&normalized).parent()?.to_str()?; - if !guest_command_search_dirs(vm, guest_cwd, path_env) - .iter() - .any(|search_dir| normalize_path(search_dir) == normalize_path(parent_dir)) - { - return None; - } - - let file_name = Path::new(&normalized).file_name()?.to_str()?; - vm.command_guest_paths.get(file_name).cloned() - }) -} - -fn guest_command_search_dirs(vm: &VmState, guest_cwd: &str, path_env: Option<&str>) -> Vec { - let mut search_dirs = Vec::new(); - let mut seen = BTreeSet::new(); - - if let Some(path) = path_env.or_else(|| vm.guest_env.get("PATH").map(String::as_str)) { - for segment in path.split(':') { - let trimmed = segment.trim(); - if trimmed.is_empty() { - continue; - } - let normalized = if trimmed.starts_with('/') { - normalize_path(trimmed) - } else { - normalize_path(&format!("{guest_cwd}/{trimmed}")) - }; - if seen.insert(normalized.clone()) { - search_dirs.push(normalized); - } - } - } - - for fallback in ["/bin", "/usr/bin", "/usr/local/bin"] { - let normalized = String::from(fallback); - if seen.insert(normalized.clone()) { - search_dirs.push(normalized); - } - } - - search_dirs -} - -fn resolve_guest_command_path_candidate(vm: &VmState, candidate: &str) -> Option { - if candidate.starts_with(&format!("{}/", crate::package_projection::OPT_AGENTOS_BIN)) { - if let Ok(realpath) = vm.kernel.realpath(candidate) { - return Some(normalize_path(&realpath)); - } - } - - if candidate.starts_with("/bin/") - || candidate.starts_with("/usr/bin/") - || candidate.starts_with("/usr/local/bin/") - || candidate.starts_with(&format!("{}/", crate::package_projection::OPT_AGENTOS_BIN)) - || candidate.starts_with("/__secure_exec/commands/") - { - if let Some(file_name) = Path::new(candidate) - .file_name() - .and_then(|name| name.to_str()) - { - if let Some(guest_entrypoint) = vm.command_guest_paths.get(file_name) { - return Some(guest_entrypoint.clone()); - } - } - } - - if vm - .kernel - .exists(candidate) - .ok() - .is_some_and(|exists| exists) - { - return Some(normalize_path(candidate)); - } - - resolve_vm_guest_path_to_host(vm, candidate) - .is_file() - .then(|| normalize_path(candidate)) -} - -fn resolve_host_entrypoint_within_vm_host_cwd( - vm: &VmState, - specifier: &str, -) -> Option<(String, String)> { - let candidate = Path::new(specifier); - if !candidate.is_absolute() { - return None; - } - - let normalized_entrypoint = normalize_host_path(candidate); - let normalized_host_cwd = normalize_host_path(&vm.host_cwd); - if !path_is_within_root(&normalized_entrypoint, &normalized_host_cwd) { - return None; - } - - let relative = normalized_entrypoint - .strip_prefix(&normalized_host_cwd) - .ok()? - .to_string_lossy() - .replace('\\', "/"); - let guest_entrypoint = if relative.is_empty() { - String::from("/") - } else { - normalize_path(&format!("/{relative}")) - }; - Some(( - guest_entrypoint, - normalized_entrypoint.to_string_lossy().into_owned(), - )) -} - -fn prepare_guest_runtime_env( - vm: &VmState, - env: &mut BTreeMap, - guest_cwd: &str, - host_cwd: &Path, - guest_entrypoint: Option, -) -> Result<(), SidecarError> { - let user = vm.kernel.user_profile(); - let path_mappings = runtime_guest_path_mappings(vm); - let read_paths = expand_host_access_paths( - std::iter::once(vm.cwd.clone()) - .chain( - path_mappings - .iter() - .map(|mapping| PathBuf::from(&mapping.host_path)), - ) - .chain(std::iter::once(host_cwd.to_path_buf())) - .collect::>() - .as_slice(), - ); - let write_paths = dedupe_host_paths( - std::iter::once(vm.cwd.clone()) - .chain(std::iter::once(host_cwd.to_path_buf())) - .chain(runtime_guest_writable_host_paths(vm)) - .collect::>() - .as_slice(), - ); - let allowed_node_builtins = configured_allowed_node_builtins(vm); - let loopback_exempt_ports = configured_loopback_exempt_ports(vm); - - env.insert( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - serde_json::to_string(&path_mappings).map_err(|error| { - SidecarError::InvalidState(format!("failed to encode guest path mappings: {error}")) - })?, - ); - env.entry(String::from(EXECUTION_SANDBOX_ROOT_ENV)) - .or_insert_with(|| normalize_host_path(&vm.cwd).to_string_lossy().into_owned()); - env.insert( - String::from("AGENTOS_EXTRA_FS_READ_PATHS"), - serde_json::to_string( - &read_paths - .iter() - .map(|path| path.to_string_lossy().into_owned()) - .collect::>(), - ) - .map_err(|error| { - SidecarError::InvalidState(format!("failed to encode read paths: {error}")) - })?, - ); - env.insert( - String::from("AGENTOS_EXTRA_FS_WRITE_PATHS"), - serde_json::to_string( - &write_paths - .iter() - .map(|path| path.to_string_lossy().into_owned()) - .collect::>(), - ) - .map_err(|error| { - SidecarError::InvalidState(format!("failed to encode write paths: {error}")) - })?, - ); - env.insert( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - serde_json::to_string(&allowed_node_builtins).map_err(|error| { - SidecarError::InvalidState(format!("failed to encode allowed builtins: {error}")) - })?, - ); - // The guest JS host platform drives subtractive global scrubbing in the - // per-execution runtime shim (see prepend_v8_runtime_shim). - env.insert( - String::from("AGENTOS_JS_PLATFORM"), - js_runtime_platform_env(vm).to_owned(), - ); - // Module-resolution mode (omitted when full Node resolution / the default). - if let Some(resolution) = js_runtime_module_resolution_env(vm) { - env.insert( - String::from("AGENTOS_JS_MODULE_RESOLUTION"), - resolution.to_owned(), - ); - } - // Builtin allow-list gate for the live resolver. Present only when builtins - // should be restricted (non-node platform => deny all; node + explicit - // allow-list => exactly those). Absent => unrestricted (node default). - if let Some(allowlist) = js_runtime_enforced_builtins(vm) { - env.insert( - String::from("AGENTOS_JS_BUILTIN_ALLOWLIST"), - serde_json::to_string(&allowlist).map_err(|error| { - SidecarError::InvalidState(format!( - "failed to encode jsRuntime builtin allow-list: {error}" - )) - })?, - ); - } - // Virtual OS identity (os.cpus/totalmem/freemem/homedir/userInfo/...) now - // rides the typed `guest_runtime` (see `guest_runtime_identity`), exposed to - // the guest as the `__agentOSVirtualOs` structured global by the runtime - // shim — no longer the `AGENTOS_VIRTUAL_OS_*` env vars. - // Virtual process uid/gid now ride the typed `guest_runtime` identity - // (see `guest_runtime_identity`), not the `AGENTOS_VIRTUAL_PROCESS_*` env. - env.entry(String::from("HOME")) - .or_insert_with(|| user.homedir.clone()); - env.entry(String::from("USER")) - .or_insert_with(|| user.username.clone()); - env.entry(String::from("LOGNAME")) - .or_insert_with(|| user.username.clone()); - env.entry(String::from("SHELL")) - .or_insert_with(|| user.shell.clone()); - env.entry(String::from("PATH")).or_insert_with(|| { - vm.guest_env - .get("PATH") - .cloned() - .unwrap_or_else(|| crate::vm::DEFAULT_GUEST_PATH_ENV.to_owned()) - }); - env.entry(String::from("TMPDIR")) - .or_insert_with(|| String::from("/tmp")); - env.insert(String::from("PWD"), guest_cwd.to_owned()); - if !loopback_exempt_ports.is_empty() { - env.insert( - String::from(LOOPBACK_EXEMPT_PORTS_ENV), - serde_json::to_string(&loopback_exempt_ports).map_err(|error| { - SidecarError::InvalidState(format!("failed to encode loopback exemptions: {error}")) - })?, - ); - } - if let Some(guest_entrypoint) = guest_entrypoint { - env.insert(String::from("AGENTOS_GUEST_ENTRYPOINT"), guest_entrypoint); - } - Ok(()) -} - -/// Build the typed per-execution JavaScript limits from the per-VM `VmLimits` -/// (sourced from `CreateVmConfig` on the BARE wire). These ride the execution -/// request, not `AGENTOS_*` env vars — see the env-vs-wire rule in -/// `crates/sidecar/CLAUDE.md`. -fn javascript_execution_limits(vm: &VmState) -> JavascriptExecutionLimits { - JavascriptExecutionLimits { - v8_heap_limit_mb: vm.limits.js_runtime.v8_heap_limit_mb, - sync_rpc_wait_timeout_ms: vm.limits.js_runtime.sync_rpc_wait_timeout_ms, - cpu_time_limit_ms: Some(vm.limits.js_runtime.cpu_time_limit_ms), - wall_clock_limit_ms: Some(vm.limits.js_runtime.wall_clock_limit_ms), - import_cache_materialize_timeout_ms: Some( - vm.limits.js_runtime.import_cache_materialize_timeout_ms, - ), - } -} - -/// Build the typed per-execution guest-runtime identity (virtual `process.*`) -/// from kernel state. Replaces the `AGENTOS_VIRTUAL_PROCESS_{UID,GID,PID,PPID}` -/// env round-trip: the runtime shim reads these from `guest_runtime`, not env. -/// `uid`/`gid` come from the VM user profile (applied to every guest); -/// `pid`/`ppid` are per-process and only set for paths that assigned them. -fn guest_runtime_identity( - vm: &VmState, - virtual_pid: Option, - virtual_ppid: Option, -) -> GuestRuntimeConfig { - let user = vm.kernel.user_profile(); - let resource_limits = vm.kernel.resource_limits(); - let identity = shared_guest_runtime_identity(&user, resource_limits, virtual_pid, virtual_ppid); - GuestRuntimeConfig { - virtual_uid: Some(identity.virtual_uid), - virtual_gid: Some(identity.virtual_gid), - virtual_pid: identity.virtual_pid, - virtual_ppid: identity.virtual_ppid, - virtual_exec_path: None, - os_cpu_count: Some(identity.os_cpu_count), - os_totalmem: Some(identity.os_totalmem), - os_freemem: Some(identity.os_freemem), - os_homedir: Some(identity.os_homedir), - os_hostname: Some(identity.os_hostname), - os_tmpdir: Some(identity.os_tmpdir), - os_type: Some(identity.os_type), - os_release: Some(identity.os_release), - os_version: Some(identity.os_version), - os_machine: Some(identity.os_machine), - os_shell: Some(identity.os_shell), - os_user: Some(identity.os_user), - high_resolution_time: vm - .configuration - .js_runtime - .as_ref() - .is_some_and(|cfg| cfg.high_resolution_time.unwrap_or(false)), - // Userland bundle to bake into the per-sidecar snapshot. The sidecar - // derives this from configured agent packages with `agent.snapshot`. - snapshot_userland_code: vm.configuration.snapshot_userland_code.clone(), - } -} - -/// The guest's virtual home directory, sourced from the VM user profile (the -/// same value carried to the guest as `os.homedir()` via `guest_runtime`). Used -/// by sidecar-internal `~`-path resolution; falls back to `/root` for a -/// non-absolute profile value. -fn guest_virtual_home(vm: &VmState) -> String { - let homedir = vm.kernel.user_profile().homedir; - if homedir.starts_with('/') { - homedir - } else { - String::from("/root") - } -} - -/// Build the typed per-execution Python limits from the per-VM `VmLimits`. -fn python_execution_limits(vm: &VmState) -> PythonExecutionLimits { - PythonExecutionLimits { - output_buffer_max_bytes: Some(vm.limits.python.output_buffer_max_bytes), - execution_timeout_ms: Some(vm.limits.python.execution_timeout_ms), - max_old_space_mb: Some(vm.limits.python.max_old_space_mb), - vfs_rpc_timeout_ms: Some(vm.limits.python.vfs_rpc_timeout_ms), - } -} - -/// Build the typed per-execution WebAssembly limits from the per-VM kernel -/// `ResourceLimits`. Replaces the old `apply_wasm_limit_env` env round-trip; -/// notably this is the path that finally enforces the stack cap that the -/// `AGENTOS_WASM_MAX_STACK_BYTES` env knob set but no reader consumed. -fn wasm_execution_limits(vm: &VmState) -> WasmExecutionLimits { - let resource_limits = vm.kernel.resource_limits(); - WasmExecutionLimits { - max_fuel: resource_limits.max_wasm_fuel, - max_memory_bytes: resource_limits.max_wasm_memory_bytes, - max_stack_bytes: resource_limits - .max_wasm_stack_bytes - .map(|value| value as u64), - prewarm_timeout_ms: Some(vm.limits.wasm.prewarm_timeout_ms), - runner_heap_limit_mb: Some(vm.limits.wasm.runner_heap_limit_mb), - } -} - -/// The guest JavaScript host platform configured for this VM, defaulting to -/// full Node.js emulation when no `jsRuntime` config was supplied at create. -fn js_runtime_platform(vm: &VmState) -> vm_config::JsRuntimePlatform { - vm.configuration - .js_runtime - .as_ref() - .map(|cfg| cfg.platform) - .unwrap_or(vm_config::JsRuntimePlatform::Node) -} - -/// Lowercase wire name for the configured platform, mirroring the serde -/// representation of `vm_config::JsRuntimePlatform`. -fn js_runtime_platform_env(vm: &VmState) -> &'static str { - match js_runtime_platform(vm) { - vm_config::JsRuntimePlatform::Node => "node", - vm_config::JsRuntimePlatform::Browser => "browser", - vm_config::JsRuntimePlatform::Neutral => "neutral", - vm_config::JsRuntimePlatform::Bare => "bare", - } -} - -/// Wire name for the configured module-resolution mode, or `None` when it is the -/// full-Node default (which the live resolver also assumes when the env is unset). -fn js_runtime_module_resolution_env(vm: &VmState) -> Option<&'static str> { - let resolution = vm - .configuration - .js_runtime - .as_ref() - .map(|cfg| cfg.module_resolution) - .unwrap_or(vm_config::JsModuleResolution::Node); - match resolution { - vm_config::JsModuleResolution::Node => None, - vm_config::JsModuleResolution::Relative => Some("relative"), - vm_config::JsModuleResolution::None => Some("none"), - } -} - -/// The builtin allow-list the live resolver should enforce, or `None` to leave -/// builtins unrestricted (full Node default — preserving today's behavior). -/// Non-node platforms enforce an empty list (deny all builtins). -fn js_runtime_enforced_builtins(vm: &VmState) -> Option> { - if js_runtime_platform(vm) != vm_config::JsRuntimePlatform::Node { - return Some(Vec::new()); - } - vm.configuration - .js_runtime - .as_ref() - .and_then(|cfg| cfg.allowed_builtins.clone()) -} - -fn configured_allowed_node_builtins(vm: &VmState) -> Vec { - // Non-node platforms expose no Node builtin modules at all. - if js_runtime_platform(vm) != vm_config::JsRuntimePlatform::Node { - return Vec::new(); - } - // Under the node platform an explicit allow-list wins — including an explicit - // empty list, which means deny all. Absence falls back to the engine default. - let configured = match vm - .configuration - .js_runtime - .as_ref() - .and_then(|cfg| cfg.allowed_builtins.as_ref()) - { - Some(list) => list.clone(), - None => DEFAULT_ALLOWED_NODE_BUILTINS - .iter() - .map(|value| (*value).to_owned()) - .collect::>(), - }; - dedupe_strings(&configured) -} - -fn configured_loopback_exempt_ports(vm: &VmState) -> Vec { - if !vm.configuration.loopback_exempt_ports.is_empty() { - return vm - .configuration - .loopback_exempt_ports - .iter() - .map(ToString::to_string) - .collect(); - } - - vm.create_loopback_exempt_ports - .iter() - .map(ToString::to_string) - .collect() -} - -/// Extract the `hostPath` string from a mount plugin's JSON-encoded config. -fn mount_config_host_path(config: &str) -> Option { - serde_json::from_str::(config) - .ok()? - .get("hostPath") - .and_then(Value::as_str) - .map(str::to_owned) -} - -/// Host path backing a mount for HOST-SIDE resolution (entrypoint launch, import -/// cache location). `agentos_packages` is deliberately excluded by callers: -/// package tar mounts are guest-native and resolve through the kernel VFS. -fn mount_config_host_backing_path(config: &str) -> Option { - let value = serde_json::from_str::(config).ok()?; - value - .get("hostPath") - .and_then(Value::as_str) - .map(str::to_owned) -} - -fn runtime_guest_writable_host_paths(vm: &VmState) -> Vec { - vm.configuration - .mounts - .iter() - .filter(|mount| !mount.read_only) - .filter_map(|mount| { - ((mount.plugin.id == "host_dir") || (mount.plugin.id == "module_access")) - .then(|| mount_config_host_path(&mount.plugin.config)) - .flatten() - .map(PathBuf::from) - }) - .collect() -} - -fn runtime_guest_path_mappings(vm: &VmState) -> Vec { - let mut mappings = vm - .configuration - .mounts - .iter() - .filter_map(|mount| { - ((mount.plugin.id == "host_dir") || (mount.plugin.id == "module_access")) - .then(|| { - mount_config_host_path(&mount.plugin.config).map(|host_path| { - RuntimeGuestPathMapping { - guest_path: normalize_path(&mount.guest_path), - host_path, - read_only: mount.read_only, - } - }) - }) - .flatten() - }) - .collect::>(); - let mut command_root_mappings = vm - .command_guest_paths - .values() - .filter_map(|guest_path| { - Path::new(guest_path) - .parent() - .and_then(|parent| parent.to_str()) - .map(normalize_path) - }) - .collect::>() - .into_iter() - .map(|guest_path| RuntimeGuestPathMapping { - host_path: resolve_vm_guest_path_to_host(vm, &guest_path) - .to_string_lossy() - .into_owned(), - guest_path, - read_only: false, - }) - .collect::>(); - mappings.append(&mut command_root_mappings); - let mut extra_node_modules_roots = mappings - .iter() - .filter(|mapping| mapping.guest_path.starts_with("/root/node_modules/")) - .filter_map(|mapping| { - host_node_modules_root(Path::new(&mapping.host_path)).map(|host_root| { - RuntimeGuestPathMapping { - guest_path: String::from("/root/node_modules"), - host_path: host_root.to_string_lossy().into_owned(), - read_only: mapping.read_only, - } - }) - }) - .collect::>(); - mappings.append(&mut extra_node_modules_roots); - mappings.push(RuntimeGuestPathMapping { - guest_path: String::from("/"), - host_path: vm.cwd.to_string_lossy().into_owned(), - read_only: false, - }); - mappings.sort_by_key(|mapping| std::cmp::Reverse(mapping.guest_path.len())); - mappings.dedup_by(|left, right| { - left.guest_path == right.guest_path && left.host_path == right.host_path - }); - mappings -} - -/// Build a `Send`-able, read-only VFS module reader over the VM's read-only -/// `host_dir`/`module_access` mounts (and the derived `/root/node_modules` root -/// for nested mounts). When present, the V8 bridge thread resolves modules -/// inline against this reader — concurrently with the service loop — so a large -/// cold-start module graph never serializes behind / starves an in-flight ACP -/// `session/new` bootstrap on the single service-loop thread. The reader reads -/// the same mounted tree the guest sees (anchored `openat2`, escaping-symlink -/// refusal), never the host-direct path translator. Returns `None` when the VM -/// has no usable read-only mount, so resolution falls back to the service-loop -/// kernel reader. -fn build_module_reader( - vm: &VmState, - resolved: &ResolvedChildProcessExecution, -) -> Option { - let mut pairs: Vec<(String, PathBuf)> = vm - .configuration - .mounts - .iter() - .filter(|mount| mount.read_only) - .filter(|mount| (mount.plugin.id == "host_dir") || (mount.plugin.id == "module_access")) - .filter_map(|mount| { - mount_config_host_path(&mount.plugin.config) - .map(|host_path| (normalize_path(&mount.guest_path), PathBuf::from(host_path))) - }) - .collect(); - - let guest_entrypoint = resolved - .env - .get("AGENTOS_GUEST_ENTRYPOINT") - .map(|path| normalize_path(path)); - if let Some(guest_entrypoint) = guest_entrypoint.as_deref() { - let entrypoint_in_read_only_mount = pairs.iter().any(|(guest_path, _)| { - guest_entrypoint == guest_path - || guest_entrypoint.starts_with(&format!("{guest_path}/")) - }); - if !entrypoint_in_read_only_mount { - return None; - } - } - - // Mirror runtime_guest_path_mappings: a mount nested under - // `/root/node_modules/` implies a `/root/node_modules` root the resolver - // walks, so expose that root too (e.g. software-package mounts). - let extra_roots: Vec<(String, PathBuf)> = pairs - .iter() - .filter(|(guest_path, _)| guest_path.starts_with("/root/node_modules/")) - .filter_map(|(_, host_path)| { - host_node_modules_root(host_path).map(|root| (String::from("/root/node_modules"), root)) - }) - .collect(); - pairs.extend(extra_roots); - - crate::plugins::host_dir::HostDirModuleReader::from_mounts(pairs) -} - -fn host_node_modules_root(path: &Path) -> Option { - if let Some(root) = path - .ancestors() - .filter(|candidate| { - candidate.file_name().and_then(|name| name.to_str()) == Some("node_modules") - }) - .last() - .map(Path::to_path_buf) - { - return Some(root); - } - - fs::canonicalize(path) - .ok()? - .ancestors() - .filter(|candidate| { - candidate.file_name().and_then(|name| name.to_str()) == Some("node_modules") - }) - .last() - .map(Path::to_path_buf) -} - -#[cfg(test)] -mod runtime_guest_path_mapping_tests { - use super::{host_node_modules_root, javascript_sync_rpc_option_bool}; - use serde_json::json; - use std::fs; - use std::time::{SystemTime, UNIX_EPOCH}; - - #[test] - fn host_node_modules_root_prefers_workspace_root_over_pnpm_package_node_modules() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let temp = std::env::temp_dir().join(format!("secure-exec-sidecar-node-modules-{unique}")); - let workspace_node_modules = temp.join("node_modules"); - let package_root = workspace_node_modules - .join(".pnpm") - .join("example@1.0.0") - .join("node_modules") - .join("@scope") - .join("pkg"); - fs::create_dir_all(&package_root).expect("package root should be created"); - - let resolved = - host_node_modules_root(&package_root).expect("node_modules root should resolve"); - - assert_eq!(resolved, workspace_node_modules); - - fs::remove_dir_all(&temp).expect("temp tree should be removed"); - } - - #[test] - fn host_node_modules_root_preserves_symlinked_workspace_node_modules_path() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let temp = - std::env::temp_dir().join(format!("secure-exec-sidecar-node-modules-symlink-{unique}")); - let workspace_node_modules = temp.join("node_modules"); - let package_link = workspace_node_modules.join("@scope").join("pkg"); - let real_package = temp.join("registry").join("agent").join("pkg"); - fs::create_dir_all(package_link.parent().expect("package parent should exist")) - .expect("scoped parent should be created"); - fs::create_dir_all(&real_package).expect("real package root should be created"); - std::os::unix::fs::symlink(&real_package, &package_link) - .expect("package symlink should be created"); - - let resolved = - host_node_modules_root(&package_link).expect("node_modules root should resolve"); - - assert_eq!(resolved, workspace_node_modules); - - fs::remove_dir_all(&temp).expect("temp tree should be removed"); - } - - #[test] - fn javascript_sync_rpc_option_bool_accepts_boolean_recursive_argument() { - assert_eq!( - javascript_sync_rpc_option_bool(&[json!("/workspace"), json!(true)], 1, "recursive"), - Some(true) - ); - assert_eq!( - javascript_sync_rpc_option_bool( - &[json!("/workspace"), json!({ "recursive": false })], - 1, - "recursive" - ), - Some(false) - ); - } -} - -#[cfg(test)] -mod kernel_poll_sync_rpc_tests { - use super::{ - service_javascript_kernel_poll_sync_rpc, ActiveExecution, ActiveProcess, - JavascriptSyncRpcRequest, KernelPollFdResponse, SidecarKernel, ToolExecution, - EXECUTION_DRIVER_NAME, JAVASCRIPT_COMMAND, - }; - use secure_exec_kernel::command_registry::CommandDriver; - use secure_exec_kernel::kernel::{KernelVmConfig, SpawnOptions}; - use secure_exec_kernel::mount_table::MountTable; - use secure_exec_kernel::permissions::Permissions; - use secure_exec_kernel::poll::{POLLHUP, POLLIN}; - use secure_exec_kernel::vfs::MemoryFileSystem; - use serde_json::{json, Value}; - use std::collections::HashMap; - #[test] - fn javascript_kernel_poll_sync_rpc_reports_multiple_kernel_fds() { - let mut config = KernelVmConfig::new("vm-js-kernel-poll"); - config.permissions = Permissions::allow_all(); - let mut kernel = SidecarKernel::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .register_driver(CommandDriver::new( - EXECUTION_DRIVER_NAME, - [JAVASCRIPT_COMMAND], - )) - .expect("register execution driver"); - - let kernel_handle = kernel - .spawn_process( - JAVASCRIPT_COMMAND, - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - ..SpawnOptions::default() - }, - ) - .expect("spawn javascript kernel process"); - let pid = kernel_handle.pid(); - - let (stdin_read_fd, stdin_write_fd) = kernel - .open_pipe(EXECUTION_DRIVER_NAME, pid) - .expect("open kernel stdin pipe"); - kernel - .fd_dup2(EXECUTION_DRIVER_NAME, pid, stdin_read_fd, 0) - .expect("dup stdin pipe onto fd 0"); - kernel - .fd_close(EXECUTION_DRIVER_NAME, pid, stdin_read_fd) - .expect("close original stdin read fd"); - - let process = ActiveProcess::new( - pid, - kernel_handle, - super::GuestRuntimeKind::JavaScript, - ActiveExecution::Tool(ToolExecution::default()), - ); - - kernel - .fd_write(EXECUTION_DRIVER_NAME, pid, stdin_write_fd, b"poll-ready") - .expect("write kernel stdin payload"); - kernel - .fd_close(EXECUTION_DRIVER_NAME, pid, stdin_write_fd) - .expect("close kernel stdin writer"); - - let response = service_javascript_kernel_poll_sync_rpc( - &mut kernel, - &process, - &JavascriptSyncRpcRequest { - id: 1, - method: String::from("__kernel_poll"), - raw_bytes_args: HashMap::new(), - args: vec![ - json!([ - { "fd": 0, "events": POLLIN.bits() }, - { "fd": 1, "events": POLLIN.bits() } - ]), - json!(250), - ], - }, - ) - .expect("poll kernel fds"); - - assert_eq!(response["readyCount"], Value::from(1)); - let fds: Vec = - serde_json::from_value(response["fds"].clone()).expect("kernel poll fd response"); - assert_eq!( - fds, - vec![ - KernelPollFdResponse { - fd: 0, - events: POLLIN.bits(), - revents: (POLLIN | POLLHUP).bits(), - }, - KernelPollFdResponse { - fd: 1, - events: POLLIN.bits(), - revents: 0, - }, - ] - ); - - process.kernel_handle.finish(0); - kernel.waitpid(pid).expect("wait javascript kernel process"); - } -} - -fn dedupe_strings(values: &[String]) -> Vec { - let mut seen = BTreeSet::new(); - let mut deduped = Vec::new(); - for value in values { - if seen.insert(value.clone()) { - deduped.push(value.clone()); - } - } - deduped -} - -fn dedupe_host_paths(paths: &[PathBuf]) -> Vec { - let mut seen = BTreeSet::new(); - let mut deduped = Vec::new(); - for path in paths { - let normalized = normalize_host_path(path); - let key = normalized.to_string_lossy().into_owned(); - if seen.insert(key) { - deduped.push(normalized); - } - } - deduped -} - -fn expand_host_access_paths(paths: &[PathBuf]) -> Vec { - let mut expanded = Vec::new(); - let mut seen = BTreeSet::new(); - - let mut add_path = |candidate: PathBuf| { - let normalized = normalize_host_path(&candidate); - let key = normalized.to_string_lossy().into_owned(); - if seen.insert(key) { - expanded.push(normalized); - } - }; - - for host_path in paths { - add_path(host_path.clone()); - if let Ok(realpath) = fs::canonicalize(host_path) { - add_path(realpath); - } - - if host_path.file_name().and_then(|name| name.to_str()) != Some("node_modules") { - continue; - } - - let mut current = host_path.parent(); - while let Some(parent) = current { - let candidate = parent.join("node_modules"); - if candidate.exists() { - add_path(candidate.clone()); - if let Ok(realpath) = fs::canonicalize(&candidate) { - add_path(realpath); - } - } - current = parent.parent(); - } - } - - expanded -} - -fn prepare_javascript_shadow( - vm: &mut VmState, - resolved: &ResolvedChildProcessExecution, - env: &BTreeMap, -) -> Result<(), SidecarError> { - let guest_entrypoint = env - .get("AGENTOS_GUEST_ENTRYPOINT") - .cloned() - // An absolute `entrypoint` may be a host path that lives inside the VM's - // host cwd (callers can pass a fully-qualified host path). The guest sees - // it at its translated guest path (host_cwd -> guest_cwd), so the shadow - // must be keyed by that guest path rather than the raw host path. Falling - // back to the host path here would materialize the file at the wrong guest - // location and the runtime's `require()` would fail with "Cannot find - // module". - .or_else(|| { - resolve_host_entrypoint_within_vm_host_cwd(vm, &resolved.entrypoint) - .map(|(guest_entrypoint, _)| guest_entrypoint) - }) - .or_else(|| { - resolved - .entrypoint - .starts_with('/') - .then(|| normalize_path(&resolved.entrypoint)) - }); - let Some(guest_entrypoint) = guest_entrypoint else { - return Ok(()); - }; - if host_mount_path_for_guest_path(vm, &guest_entrypoint).is_some() { - return Ok(()); - } - if vm.kernel.lstat(&guest_entrypoint).is_err() { - let host_entrypoint = { - let candidate = Path::new(&resolved.entrypoint); - if candidate.is_absolute() { - candidate.to_path_buf() - } else { - resolved.host_cwd.join(candidate) - } - }; - if host_entrypoint.exists() { - materialize_host_path_to_shadow(vm, &guest_entrypoint, &host_entrypoint)?; - // The shadow write only stages the file on the host side; the runtime - // resolves modules against the kernel VFS, so the staged entrypoint - // must be synced into the kernel before execution starts (otherwise - // `require()` reports "Cannot find module"). - return sync_shadow_entrypoint_into_kernel(vm, &guest_entrypoint); - } - } - materialize_guest_path_to_shadow(vm, &guest_entrypoint) -} - -fn resolve_agentos_package_javascript_launch_entrypoint( - vm: &mut VmState, - env: &mut BTreeMap, -) -> Option { - let guest_entrypoint = env - .get("AGENTOS_GUEST_ENTRYPOINT") - .filter(|path| path.starts_with('/')) - .map(|path| normalize_path(path))?; - if !guest_path_is_within_agentos_package_mount(vm, &guest_entrypoint) { - return None; - } - - let real_entrypoint = normalize_path(&vm.kernel.realpath(&guest_entrypoint).ok()?); - if !guest_path_is_within_agentos_package_mount(vm, &real_entrypoint) { - return None; - } - - env.insert( - String::from("AGENTOS_GUEST_ENTRYPOINT"), - real_entrypoint.clone(), - ); - if guest_javascript_entrypoint_uses_module_mode(vm, &real_entrypoint) { - env.insert( - String::from("AGENTOS_GUEST_ENTRYPOINT_MODULE_MODE"), - String::from("1"), - ); - } else { - env.remove("AGENTOS_GUEST_ENTRYPOINT_MODULE_MODE"); - } - Some(real_entrypoint) -} - -fn guest_path_is_within_agentos_package_mount(vm: &VmState, guest_path: &str) -> bool { - let normalized = normalize_path(guest_path); - vm.configuration.mounts.iter().any(|mount| { - mount.plugin.id == "agentos_packages" && { - let guest_root = normalize_path(&mount.guest_path); - normalized == guest_root || normalized.starts_with(&format!("{guest_root}/")) - } - }) -} - -fn guest_javascript_entrypoint_uses_module_mode(vm: &mut VmState, guest_path: &str) -> bool { - match Path::new(guest_path) - .extension() - .and_then(|ext| ext.to_str()) - { - Some("mjs" | "mts") => true, - Some("js") => nearest_guest_package_json_type(vm, guest_path).as_deref() == Some("module"), - _ => false, - } -} - -fn nearest_guest_package_json_type(vm: &mut VmState, guest_path: &str) -> Option { - let mut dir = dirname(guest_path); - loop { - let package_json_path = if dir == "/" { - String::from("/package.json") - } else { - normalize_path(&format!("{dir}/package.json")) - }; - if let Ok(bytes) = vm.kernel.read_file(&package_json_path) { - if let Ok(value) = serde_json::from_slice::(&bytes) { - if let Some(package_type) = value.get("type").and_then(Value::as_str) { - return Some(package_type.to_owned()); - } - } - } - if dir == "/" { - return None; - } - dir = dirname(&dir); - } -} - -/// Sync a freshly-staged shadow entrypoint into the kernel VFS so the runtime's -/// kernel-backed module resolver can read it. Mirrors the host->kernel file sync -/// used by the broader shadow reconciliation, but scoped to the single -/// entrypoint we just materialized. -fn sync_shadow_entrypoint_into_kernel( - vm: &mut VmState, - guest_entrypoint: &str, -) -> Result<(), SidecarError> { - if vm.kernel.exists(guest_entrypoint).unwrap_or(false) { - return Ok(()); - } - let shadow_path = shadow_path_for_guest(vm, guest_entrypoint); - let bytes = match fs::read(&shadow_path) { - Ok(bytes) => bytes, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(()), - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to read staged shadow entrypoint {}: {error}", - shadow_path.display() - ))); - } - }; - if let Some(parent) = guest_parent_path(guest_entrypoint) { - if !vm.kernel.exists(&parent).unwrap_or(false) { - vm.kernel.mkdir(&parent, true).map_err(kernel_error)?; - } - } - vm.kernel - .write_file(guest_entrypoint, bytes) - .map_err(kernel_error)?; - Ok(()) -} - -fn guest_parent_path(guest_path: &str) -> Option { - let parent = Path::new(guest_path).parent()?; - let parent = parent.to_string_lossy(); - if parent.is_empty() || parent == "/" { - None - } else { - Some(parent.into_owned()) - } -} - -fn materialize_host_path_to_shadow( - vm: &VmState, - guest_path: &str, - host_path: &Path, -) -> Result<(), SidecarError> { - let shadow_path = shadow_path_for_guest(vm, guest_path); - let metadata = fs::symlink_metadata(host_path) - .map_err(|error| SidecarError::Io(format!("failed to stat host entrypoint: {error}")))?; - - if metadata.file_type().is_symlink() { - if let Some(parent) = shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!("failed to create shadow symlink parent: {error}")) - })?; - } - let _ = fs::remove_file(&shadow_path); - let _ = fs::remove_dir_all(&shadow_path); - let target = fs::read_link(host_path) - .map_err(|error| SidecarError::Io(format!("failed to read host symlink: {error}")))?; - std::os::unix::fs::symlink(&target, &shadow_path) - .map_err(|error| SidecarError::Io(format!("failed to mirror host symlink: {error}")))?; - return Ok(()); - } - - if metadata.is_dir() { - fs::create_dir_all(&shadow_path).map_err(|error| { - SidecarError::Io(format!("failed to create shadow directory: {error}")) - })?; - fs::set_permissions( - &shadow_path, - fs::Permissions::from_mode(metadata.permissions().mode() & 0o7777), - ) - .map_err(|error| { - SidecarError::Io(format!( - "failed to set shadow directory mode on {}: {error}", - shadow_path.display() - )) - })?; - return Ok(()); - } - - if let Some(parent) = shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!("failed to create shadow parent: {error}")) - })?; - } - let bytes = fs::read(host_path) - .map_err(|error| SidecarError::Io(format!("failed to read host entrypoint: {error}")))?; - fs::write(&shadow_path, bytes).map_err(|error| { - SidecarError::Io(format!( - "failed to mirror host file into shadow root: {error}" - )) - })?; - fs::set_permissions( - &shadow_path, - fs::Permissions::from_mode(metadata.permissions().mode() & 0o7777), - ) - .map_err(|error| { - SidecarError::Io(format!( - "failed to set shadow file mode on {}: {error}", - shadow_path.display() - )) - })?; - Ok(()) -} - -fn materialize_guest_path_to_shadow( - vm: &mut VmState, - guest_path: &str, -) -> Result<(), SidecarError> { - let stat = vm.kernel.lstat(guest_path).map_err(kernel_error)?; - let shadow_path = shadow_path_for_guest(vm, guest_path); - - if stat.is_symbolic_link { - if let Some(parent) = shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!("failed to create shadow symlink parent: {error}")) - })?; - } - let _ = fs::remove_file(&shadow_path); - let _ = fs::remove_dir_all(&shadow_path); - let target = vm.kernel.read_link(guest_path).map_err(kernel_error)?; - std::os::unix::fs::symlink(&target, &shadow_path) - .map_err(|error| SidecarError::Io(format!("failed to mirror symlink: {error}")))?; - return Ok(()); - } - - if stat.is_directory { - fs::create_dir_all(&shadow_path).map_err(|error| { - SidecarError::Io(format!("failed to create shadow directory: {error}")) - })?; - fs::set_permissions(&shadow_path, fs::Permissions::from_mode(stat.mode & 0o7777)).map_err( - |error| { - SidecarError::Io(format!( - "failed to set shadow directory mode on {}: {error}", - shadow_path.display() - )) - }, - )?; - return Ok(()); - } - - if let Some(parent) = shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!("failed to create shadow parent: {error}")) - })?; - } - let bytes = vm.kernel.read_file(guest_path).map_err(kernel_error)?; - fs::write(&shadow_path, bytes).map_err(|error| { - SidecarError::Io(format!( - "failed to mirror guest file into shadow root: {error}" - )) - })?; - fs::set_permissions(&shadow_path, fs::Permissions::from_mode(stat.mode & 0o7777)).map_err( - |error| { - SidecarError::Io(format!( - "failed to set shadow file mode on {}: {error}", - shadow_path.display() - )) - }, - )?; - Ok(()) -} - -fn load_javascript_entrypoint_source( - vm: &mut VmState, - host_cwd: &Path, - entrypoint: &str, - env: &BTreeMap, -) -> Option { - let mut read_guest_file = |path: &str| { - vm.kernel - .read_file(path) - .ok() - .and_then(|bytes| String::from_utf8(bytes).ok()) - }; - - if let Some(source) = env - .get("AGENTOS_GUEST_ENTRYPOINT") - .filter(|path| path.starts_with('/')) - .and_then(|path| read_guest_file(path)) - { - return Some(source); - } - - if entrypoint.starts_with('/') { - if let Some(source) = read_guest_file(entrypoint) { - return Some(source); - } - } - - let host_entrypoint = if Path::new(entrypoint).is_absolute() { - PathBuf::from(entrypoint) - } else { - host_cwd.join(entrypoint) - }; - let normalized_entrypoint = normalize_host_path(&host_entrypoint); - let sandbox_root = normalize_host_path(&vm.cwd); - let host_cwd = normalize_host_path(&vm.host_cwd); - if !path_is_within_root(&normalized_entrypoint, &sandbox_root) - && !path_is_within_root(&normalized_entrypoint, &host_cwd) - { - return None; - } - - fs::read_to_string(&normalized_entrypoint).ok() -} - -fn emit_dns_resolution_event( - bridge: &SharedBridge, - vm_id: &str, - hostname: &str, - source: KernelDnsResolutionSource, - addresses: &[IpAddr], - dns: &VmDnsConfig, -) where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let _ = emit_structured_event( - bridge, - vm_id, - "network.dns.resolved", - audit_fields([ - ("hostname", hostname.to_owned()), - ("source", source.as_str().to_owned()), - ( - "addresses", - addresses - .iter() - .map(ToString::to_string) - .collect::>() - .join(","), - ), - ("address_count", addresses.len().to_string()), - ("resolver_count", dns.name_servers.len().to_string()), - ( - "resolvers", - dns.name_servers - .iter() - .map(ToString::to_string) - .collect::>() - .join(","), - ), - ]), - ); -} - -fn emit_dns_record_resolution_event( - bridge: &SharedBridge, - vm_id: &str, - hostname: &str, - resolution: &DnsRecordResolution, - dns: &VmDnsConfig, -) where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - if let Some(addresses) = dns_resolution_ip_addrs(resolution.records()) { - emit_dns_resolution_event( - bridge, - vm_id, - hostname, - resolution.source(), - &addresses, - dns, - ); - return; - } - - let _ = emit_structured_event( - bridge, - vm_id, - "network.dns.resolved", - audit_fields([ - ("hostname", hostname.to_owned()), - ("source", resolution.source().as_str().to_owned()), - ( - "addresses", - resolution - .records() - .iter() - .map(summarize_dns_record) - .collect::>() - .join(","), - ), - ("address_count", resolution.records().len().to_string()), - ("resolver_count", dns.name_servers.len().to_string()), - ( - "resolvers", - dns.name_servers - .iter() - .map(ToString::to_string) - .collect::>() - .join(","), - ), - ]), - ); -} - -fn emit_dns_resolution_failure_event( - bridge: &SharedBridge, - vm_id: &str, - hostname: &str, - dns: &VmDnsConfig, - error: &SidecarError, -) where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let _ = emit_structured_event( - bridge, - vm_id, - "network.dns.resolve_failed", - audit_fields([ - ("hostname", hostname.to_owned()), - ("reason", error.to_string()), - ("resolver_count", dns.name_servers.len().to_string()), - ( - "resolvers", - dns.name_servers - .iter() - .map(ToString::to_string) - .collect::>() - .join(","), - ), - ]), - ); -} - -fn parse_dns_record_type(rrtype: &str) -> Result { - match rrtype { - "A" => Ok(RecordType::A), - "AAAA" => Ok(RecordType::AAAA), - "MX" => Ok(RecordType::MX), - "TXT" => Ok(RecordType::TXT), - "SRV" => Ok(RecordType::SRV), - "CNAME" => Ok(RecordType::CNAME), - "PTR" => Ok(RecordType::PTR), - "NS" => Ok(RecordType::NS), - "SOA" => Ok(RecordType::SOA), - "NAPTR" => Ok(RecordType::NAPTR), - "CAA" => Ok(RecordType::CAA), - "ANY" => Ok(RecordType::ANY), - other => Err(SidecarError::Execution(format!( - "ERR_NOT_IMPLEMENTED: dns rrtype {other} is not supported by the secure-exec dns bridge" - ))), - } -} - -fn dns_resolution_to_node_value( - resolution: &DnsRecordResolution, - requested_type: &str, -) -> Result { - let safe_ips = dns_resolution_safe_ip_set(resolution.records(), resolution.hostname())?; - match requested_type { - "A" | "AAAA" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| dns_record_ip_string(record, &safe_ips)) - .map(Value::String) - .collect(), - )), - "MX" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| match record.data() { - RData::MX(mx) => Some(json!({ - "priority": mx.preference, - "exchange": normalize_dns_name_for_node(&mx.exchange), - "type": "MX", - })), - _ => None, - }) - .collect(), - )), - "TXT" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| match record.data() { - RData::TXT(txt) => Some(Value::Array( - txt.txt_data - .iter() - .map(|entry| Value::String(String::from_utf8_lossy(entry).into_owned())) - .collect(), - )), - _ => None, - }) - .collect(), - )), - "SRV" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| match record.data() { - RData::SRV(srv) => Some(json!({ - "priority": srv.priority, - "weight": srv.weight, - "port": srv.port, - "name": normalize_dns_name_for_node(&srv.target), - "type": "SRV", - })), - _ => None, - }) - .collect(), - )), - "CNAME" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| match record.data() { - RData::CNAME(name) => Some(Value::String(normalize_dns_name_for_node(&name.0))), - _ => None, - }) - .collect(), - )), - "PTR" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| match record.data() { - RData::PTR(name) => Some(Value::String(normalize_dns_name_for_node(&name.0))), - _ => None, - }) - .collect(), - )), - "NS" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| match record.data() { - RData::NS(name) => Some(Value::String(normalize_dns_name_for_node(&name.0))), - _ => None, - }) - .collect(), - )), - "SOA" => resolution - .records() - .iter() - .find_map(|record| match record.data() { - RData::SOA(soa) => Some(json!({ - "nsname": normalize_dns_name_for_node(&soa.mname), - "hostmaster": normalize_dns_name_for_node(&soa.rname), - "serial": soa.serial, - "refresh": soa.refresh, - "retry": soa.retry, - "expire": soa.expire, - "minttl": soa.minimum, - })), - _ => None, - }) - .ok_or_else(|| { - SidecarError::Execution(String::from("failed to resolve DNS SOA record")) - }), - "NAPTR" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| match record.data() { - RData::NAPTR(naptr) => Some(json!({ - "flags": String::from_utf8_lossy(&naptr.flags).into_owned(), - "service": String::from_utf8_lossy(&naptr.services).into_owned(), - "regexp": String::from_utf8_lossy(&naptr.regexp).into_owned(), - "replacement": normalize_dns_name_for_node(&naptr.replacement), - "order": naptr.order, - "preference": naptr.preference, - })), - _ => None, - }) - .collect(), - )), - "CAA" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| match record.data() { - RData::CAA(caa) => { - let mut value = serde_json::Map::new(); - value.insert( - "critical".to_owned(), - Value::from(u8::from(caa.issuer_critical)), - ); - value.insert("type".to_owned(), Value::String(String::from("CAA"))); - if caa.tag.eq_ignore_ascii_case("iodef") { - value.insert( - "iodef".to_owned(), - Value::String( - caa.value_as_iodef() - .map(|url| url.to_string()) - .unwrap_or_else(|_| { - String::from_utf8_lossy(&caa.value).into_owned() - }), - ), - ); - } else if let Ok((issuer, _params)) = caa.value_as_issue() { - let field = if caa.tag.eq_ignore_ascii_case("issuewild") { - "issuewild" - } else { - "issue" - }; - value.insert( - field.to_owned(), - Value::String( - issuer.as_ref().map(ToString::to_string).unwrap_or_else(|| { - String::from_utf8_lossy(&caa.value).into_owned() - }), - ), - ); - } else { - value.insert( - caa.tag.to_ascii_lowercase(), - Value::String(String::from_utf8_lossy(&caa.value).into_owned()), - ); - } - Some(Value::Object(value)) - } - _ => None, - }) - .collect(), - )), - "ANY" => Ok(Value::Array( - resolution - .records() - .iter() - .filter_map(|record| dns_any_record_to_value(record, &safe_ips)) - .collect(), - )), - other => Err(SidecarError::Execution(format!( - "ERR_NOT_IMPLEMENTED: dns rrtype {other} is not supported by the secure-exec dns bridge" - ))), - } -} - -fn dns_resolution_safe_ip_set( - records: &[Record], - hostname: &str, -) -> Result, SidecarError> { - let ips = records - .iter() - .filter_map(dns_record_ip_addr) - .collect::>(); - if ips.is_empty() { - return Ok(BTreeSet::new()); - } - Ok(filter_dns_safe_ip_addrs(ips, hostname)? - .into_iter() - .collect()) -} - -fn dns_resolution_ip_addrs(records: &[Record]) -> Option> { - let ips = records - .iter() - .filter_map(dns_record_ip_addr) - .collect::>(); - if ips.is_empty() { - return None; - } - Some(ips) -} - -fn dns_record_ip_addr(record: &Record) -> Option { - match record.data() { - RData::A(address) => Some(IpAddr::V4(**address)), - RData::AAAA(address) => Some(IpAddr::V6(**address)), - _ => None, - } -} - -fn dns_record_ip_string(record: &Record, safe_ips: &BTreeSet) -> Option { - let ip = dns_record_ip_addr(record)?; - safe_ips.contains(&ip).then(|| ip.to_string()) -} - -fn dns_any_record_to_value(record: &Record, safe_ips: &BTreeSet) -> Option { - let value = match record.data() { - RData::A(_) | RData::AAAA(_) => json!({ - "address": dns_record_ip_string(record, safe_ips)?, - "ttl": record.ttl(), - "type": record.record_type().to_string(), - }), - RData::MX(mx) => json!({ - "exchange": normalize_dns_name_for_node(&mx.exchange), - "priority": mx.preference, - "type": "MX", - }), - RData::TXT(txt) => json!({ - "entries": txt - .txt_data - .iter() - .map(|entry| String::from_utf8_lossy(entry).into_owned()) - .collect::>(), - "type": "TXT", - }), - RData::SRV(srv) => json!({ - "name": normalize_dns_name_for_node(&srv.target), - "port": srv.port, - "priority": srv.priority, - "weight": srv.weight, - "type": "SRV", - }), - RData::CNAME(name) => json!({ - "value": normalize_dns_name_for_node(&name.0), - "type": "CNAME", - }), - RData::PTR(name) => json!({ - "value": normalize_dns_name_for_node(&name.0), - "type": "PTR", - }), - RData::NS(name) => json!({ - "value": normalize_dns_name_for_node(&name.0), - "type": "NS", - }), - RData::SOA(soa) => json!({ - "nsname": normalize_dns_name_for_node(&soa.mname), - "hostmaster": normalize_dns_name_for_node(&soa.rname), - "serial": soa.serial, - "refresh": soa.refresh, - "retry": soa.retry, - "expire": soa.expire, - "minttl": soa.minimum, - "type": "SOA", - }), - RData::NAPTR(naptr) => json!({ - "flags": String::from_utf8_lossy(&naptr.flags).into_owned(), - "service": String::from_utf8_lossy(&naptr.services).into_owned(), - "regexp": String::from_utf8_lossy(&naptr.regexp).into_owned(), - "replacement": normalize_dns_name_for_node(&naptr.replacement), - "order": naptr.order, - "preference": naptr.preference, - "type": "NAPTR", - }), - RData::CAA(caa) => { - let mut value = serde_json::Map::new(); - value.insert( - "critical".to_owned(), - Value::from(u8::from(caa.issuer_critical)), - ); - value.insert("type".to_owned(), Value::String(String::from("CAA"))); - if caa.tag.eq_ignore_ascii_case("iodef") { - value.insert( - "iodef".to_owned(), - Value::String( - caa.value_as_iodef() - .map(|url| url.to_string()) - .unwrap_or_else(|_| String::from_utf8_lossy(&caa.value).into_owned()), - ), - ); - } else if let Ok((issuer, _params)) = caa.value_as_issue() { - let field = if caa.tag.eq_ignore_ascii_case("issuewild") { - "issuewild" - } else { - "issue" - }; - value.insert( - field.to_owned(), - Value::String( - issuer - .as_ref() - .map(ToString::to_string) - .unwrap_or_else(|| String::from_utf8_lossy(&caa.value).into_owned()), - ), - ); - } - Value::Object(value) - } - _ => return None, - }; - Some(value) -} - -fn normalize_dns_name_for_node(name: &impl ToString) -> String { - name.to_string().trim_end_matches('.').to_owned() -} - -fn summarize_dns_record(record: &Record) -> String { - match record.data() { - RData::A(_) | RData::AAAA(_) => record.data().to_string(), - _ => format!("{} {}", record.record_type(), record.data()), - } -} - -// build_root_filesystem, convert_root_lower_descriptor, convert_root_filesystem_entry, -// root_snapshot_entry moved to crate::bootstrap - -// apply_root_filesystem_entry, ensure_parent_directories moved to crate::bootstrap - -// ProcNetEntry moved to crate::state - -fn find_socket_state_entry( - vm: Option<&VmState>, - kind: SocketQueryKind, - request: &FindListenerRequest, -) -> Result, SidecarError> { - let vm = vm.ok_or_else(|| SidecarError::InvalidState(String::from("unknown sidecar VM")))?; - - for (process_id, process) in &vm.active_processes { - if let Some(path) = request.path.as_deref() { - if matches!(kind, SocketQueryKind::TcpListener) { - for listener in process.unix_listeners.values() { - if listener.path() != path { - continue; - } - return Ok(Some(SocketStateEntry { - process_id: process_id.to_owned(), - host: None, - port: None, - path: Some(path.to_owned()), - })); - } - } - } - - if request.path.is_none() { - if let Some(entry) = - find_kernel_socket_state_entry(&vm.kernel, process_id, process, kind, request)? - { - return Ok(Some(entry)); - } - - match kind { - SocketQueryKind::TcpListener => { - for server in process.http_servers.values() { - let local_addr = server.guest_local_addr; - let local_host = local_addr.ip().to_string(); - if !socket_host_matches(request.host.as_deref(), &local_host) { - continue; - } - if let Some(port) = request.port { - if local_addr.port() != port { - continue; - } - } - return Ok(Some(SocketStateEntry { - process_id: process_id.to_owned(), - host: Some(local_host), - port: Some(local_addr.port()), - path: None, - })); - } - - for listener in process.tcp_listeners.values() { - if listener.kernel_socket_id.is_some() { - continue; - } - let local_addr = listener.guest_local_addr(); - let local_host = local_addr.ip().to_string(); - if !socket_host_matches(request.host.as_deref(), &local_host) { - continue; - } - if let Some(port) = request.port { - if local_addr.port() != port { - continue; - } - } - return Ok(Some(SocketStateEntry { - process_id: process_id.to_owned(), - host: Some(local_host), - port: Some(local_addr.port()), - path: None, - })); - } - } - SocketQueryKind::UdpBound => { - for socket in process.udp_sockets.values() { - if socket.kernel_socket_id.is_some() { - continue; - } - let Some(local_addr) = socket.local_addr() else { - continue; - }; - let local_host = local_addr.ip().to_string(); - if !socket_host_matches(request.host.as_deref(), &local_host) { - continue; - } - if let Some(port) = request.port { - if local_addr.port() != port { - continue; - } - } - return Ok(Some(SocketStateEntry { - process_id: process_id.to_owned(), - host: Some(local_host), - port: Some(local_addr.port()), - path: None, - })); - } - } - } - } - - let child_pid = process.execution.child_pid(); - let inodes = socket_inodes_for_pid(child_pid)?; - if inodes.is_empty() { - continue; - } - - if let Some(path) = request.path.as_deref() { - if let Some(listener) = find_unix_socket_for_pid(child_pid, &inodes, path, process_id)? - { - return Ok(Some(listener)); - } - continue; - } - - let table_paths = match kind { - SocketQueryKind::TcpListener => [ - format!("/proc/{child_pid}/net/tcp"), - format!("/proc/{child_pid}/net/tcp6"), - ], - SocketQueryKind::UdpBound => [ - format!("/proc/{child_pid}/net/udp"), - format!("/proc/{child_pid}/net/udp6"), - ], - }; - for table_path in table_paths { - if let Some(entry) = find_inet_socket_for_pid( - &table_path, - &inodes, - kind, - request.host.as_deref(), - request.port, - process_id, - )? { - return Ok(Some(entry)); - } - } - } - - Ok(None) -} - -fn require_vm_inspection_permission( - bridge: &SharedBridge, - vm_id: &str, - capability: &str, - domain: &str, - resource: &str, -) -> Result<(), SidecarError> -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let decision = bridge.static_permission_decision(vm_id, capability, domain, Some(resource)); - if decision.as_ref().is_some_and(|decision| decision.allow) { - return Ok(()); - } - - let reason = decision - .and_then(|decision| decision.reason) - .unwrap_or_else(|| format!("{capability} permission required")); - Err(SidecarError::Execution(format!( - "EACCES: permission denied, {resource}: {reason}" - ))) -} - -fn socket_query_resource(kind: SocketQueryKind, request: &FindListenerRequest) -> String { - if let Some(path) = request.path.as_deref() { - return format!("unix://{path}"); - } - - let host = request.host.as_deref().unwrap_or("*"); - let port = request - .port - .map_or_else(|| String::from("*"), |port| port.to_string()); - match kind { - SocketQueryKind::TcpListener => format!("tcp://{host}:{port}"), - SocketQueryKind::UdpBound => format!("udp://{host}:{port}"), - } -} - -fn snapshot_vm_processes(vm: &VmState) -> Vec { - let process_table = vm.kernel.list_processes(); - snapshot_vm_processes_inner(vm, &process_table) -} - -fn snapshot_vm_processes_inner( - vm: &VmState, - process_table: &BTreeMap, -) -> Vec { - let mut entries = Vec::new(); - - for (process_id, process) in &vm.active_processes { - collect_process_snapshot_entries(process_id, process, process_table, &mut entries); - } - - for exited in &vm.exited_process_snapshots { - entries.push(exited.process.clone()); - } - - entries -} - -fn prune_exited_process_snapshots(vm: &mut VmState) { - let cutoff = Instant::now() - EXITED_PROCESS_SNAPSHOT_RETENTION; - while vm - .exited_process_snapshots - .front() - .is_some_and(|snapshot| snapshot.captured_at < cutoff) - { - vm.exited_process_snapshots.pop_front(); - } -} - -fn build_process_snapshot_entry( - process_id: &str, - process: &ActiveProcess, - info: &secure_exec_kernel::process_table::ProcessInfo, - exit_code: Option, -) -> ProcessSnapshotEntry { - wire_process_snapshot_entry_from_shared(process_snapshot_entry_from_kernel( - process_id, - info, - process.guest_cwd.clone(), - exit_code, - )) -} - -fn wire_process_snapshot_entry_from_shared( - entry: SharedProcessSnapshotEntry, -) -> ProcessSnapshotEntry { - ProcessSnapshotEntry { - process_id: entry.process_id, - pid: entry.pid, - ppid: entry.ppid, - pgid: entry.pgid, - sid: entry.sid, - driver: entry.driver, - command: entry.command, - args: entry.args, - cwd: entry.cwd, - status: match entry.status { - SharedProcessSnapshotStatus::Running => ProcessSnapshotStatus::Running, - SharedProcessSnapshotStatus::Stopped => ProcessSnapshotStatus::Stopped, - SharedProcessSnapshotStatus::Exited => ProcessSnapshotStatus::Exited, - }, - exit_code: entry.exit_code, - } -} - -fn collect_process_snapshot_entries( - process_id: &str, - process: &ActiveProcess, - process_table: &BTreeMap, - entries: &mut Vec, -) { - if let Some(info) = process_table.get(&process.kernel_pid) { - entries.push(build_process_snapshot_entry( - process_id, process, info, None, - )); - } - - for (child_id, child) in &process.child_processes { - let child_process_id = format!("{process_id}/{child_id}"); - collect_process_snapshot_entries(&child_process_id, child, process_table, entries); - } -} - -fn find_kernel_socket_state_entry( - kernel: &SidecarKernel, - process_id: &str, - process: &ActiveProcess, - kind: SocketQueryKind, - request: &FindListenerRequest, -) -> Result, SidecarError> { - let entry = match kind { - SocketQueryKind::TcpListener => process - .tcp_listeners - .values() - .filter_map(|listener| listener.kernel_socket_id) - .find_map(|socket_id| { - kernel_socket_state_entry(kernel, process_id, socket_id, kind, request) - }), - SocketQueryKind::UdpBound => process - .udp_sockets - .values() - .filter_map(|socket| socket.kernel_socket_id) - .find_map(|socket_id| { - kernel_socket_state_entry(kernel, process_id, socket_id, kind, request) - }), - }; - - if entry.is_some() { - return Ok(entry); - } - - for child in process.child_processes.values() { - if let Some(entry) = - find_kernel_socket_state_entry(kernel, process_id, child, kind, request)? - { - return Ok(Some(entry)); - } - } - - Ok(None) -} - -fn kernel_socket_state_entry( - kernel: &SidecarKernel, - process_id: &str, - socket_id: SocketId, - kind: SocketQueryKind, - request: &FindListenerRequest, -) -> Option { - let record = kernel.socket_get(socket_id)?; - let local_address = record.local_address()?; - match kind { - SocketQueryKind::TcpListener if record.state() == SocketState::Listening => {} - SocketQueryKind::TcpListener => return None, - SocketQueryKind::UdpBound => {} - } - - if !socket_host_matches(request.host.as_deref(), local_address.host()) { - return None; - } - if request - .port - .is_some_and(|port| local_address.port() != port) - { - return None; - } - - Some(SocketStateEntry { - process_id: process_id.to_owned(), - host: Some(local_address.host().to_owned()), - port: Some(local_address.port()), - path: None, - }) -} - -fn socket_inodes_for_pid(pid: u32) -> Result, SidecarError> { - let fd_dir = PathBuf::from(format!("/proc/{pid}/fd")); - let entries = match fs::read_dir(&fd_dir) { - Ok(entries) => entries, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(BTreeSet::new()), - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to read socket descriptors for process {pid}: {error}" - ))); - } - }; - - let mut inodes = BTreeSet::new(); - for entry in entries { - let entry = entry.map_err(|error| { - SidecarError::Io(format!( - "failed to inspect fd entry for process {pid}: {error}" - )) - })?; - let target = match fs::read_link(entry.path()) { - Ok(target) => target, - Err(_) => continue, - }; - if let Some(inode) = parse_socket_inode(&target) { - inodes.insert(inode); - } - } - - Ok(inodes) -} - -fn parse_socket_inode(target: &Path) -> Option { - let value = target.to_string_lossy(); - let trimmed = value.strip_prefix("socket:[")?.strip_suffix(']')?; - trimmed.parse().ok() -} - -fn unix_socket_path(addr: &UnixSocketAddr) -> Option { - addr.as_pathname() - .map(|path| path.to_string_lossy().into_owned()) -} - -fn find_unix_socket_for_pid( - pid: u32, - inodes: &BTreeSet, - path: &str, - process_id: &str, -) -> Result, SidecarError> { - let table_path = format!("/proc/{pid}/net/unix"); - let contents = match fs::read_to_string(&table_path) { - Ok(contents) => contents, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(None), - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to inspect unix sockets for process {pid}: {error}" - ))); - } - }; - - for line in contents.lines().skip(1) { - let columns = line.split_whitespace().collect::>(); - if columns.len() < 8 { - continue; - } - let Ok(inode) = columns[6].parse::() else { - continue; - }; - if !inodes.contains(&inode) || columns[7] != path { - continue; - } - return Ok(Some(SocketStateEntry { - process_id: process_id.to_owned(), - host: None, - port: None, - path: Some(path.to_owned()), - })); - } - - Ok(None) -} - -fn find_inet_socket_for_pid( - table_path: &str, - inodes: &BTreeSet, - kind: SocketQueryKind, - requested_host: Option<&str>, - requested_port: Option, - process_id: &str, -) -> Result, SidecarError> { - for entry in parse_proc_net_entries(table_path)? { - if !inodes.contains(&entry.inode) { - continue; - } - if matches!(kind, SocketQueryKind::TcpListener) && entry.state != "0A" { - continue; - } - if !socket_host_matches(requested_host, &entry.local_host) { - continue; - } - if let Some(port) = requested_port { - if entry.local_port != port { - continue; - } - } - return Ok(Some(SocketStateEntry { - process_id: process_id.to_owned(), - host: Some(entry.local_host), - port: Some(entry.local_port), - path: None, - })); - } - - Ok(None) -} - -fn is_unspecified_socket_host(host: &str) -> bool { - host == "0.0.0.0" || host == "::" -} - -fn is_loopback_socket_host(host: &str) -> bool { - host == "127.0.0.1" || host == "::1" || host.eq_ignore_ascii_case("localhost") -} - -pub(crate) fn vm_network_resource_counts(vm: &VmState) -> NetworkResourceCounts { - let snapshot = vm.kernel.resource_snapshot(); - let mut counts = NetworkResourceCounts { - sockets: snapshot.sockets, - connections: snapshot.socket_connections, - }; - for process in vm.active_processes.values() { - let process_counts = process.sidecar_only_network_resource_counts(); - counts.sockets += process_counts.sockets; - counts.connections += process_counts.connections; - } - counts -} - -#[allow(clippy::too_many_arguments)] -fn collect_javascript_socket_port_state( - kernel: &SidecarKernel, - process_id: &str, - process: &ActiveProcess, - tcp_guest_to_host: &mut BTreeMap<(JavascriptSocketFamily, u16), u16>, - http_loopback_targets: &mut BTreeMap< - (JavascriptSocketFamily, u16), - JavascriptHttpLoopbackTarget, - >, - udp_guest_to_host: &mut BTreeMap<(JavascriptSocketFamily, u16), u16>, - udp_host_to_guest: &mut BTreeMap<(JavascriptSocketFamily, u16), u16>, - used_tcp_ports: &mut BTreeMap>, - used_udp_ports: &mut BTreeMap>, -) { - for (family, port) in process.tcp_port_reservations.values() { - used_tcp_ports.entry(*family).or_default().insert(*port); - } - - let mut record_tcp_listener = |guest_addr: SocketAddr, host_port: u16| { - let family = JavascriptSocketFamily::from_ip(guest_addr.ip()); - used_tcp_ports - .entry(family) - .or_default() - .insert(guest_addr.port()); - // VM-local loopback connects should also resolve listeners bound to - // unspecified guest addresses like 0.0.0.0/::. - tcp_guest_to_host.insert((family, guest_addr.port()), host_port); - }; - - for listener in process.tcp_listeners.values() { - let local_addr = listener - .kernel_socket_id - .and_then(|socket_id| kernel.socket_get(socket_id)) - .and_then(|record| record.local_address().cloned()) - .and_then(|address| resolve_tcp_bind_addr(address.host(), address.port()).ok()) - .unwrap_or_else(|| listener.guest_local_addr()); - record_tcp_listener(local_addr, local_addr.port()); - } - - for (server_id, server) in &process.http_servers { - let host_port = match server.listener.local_addr() { - Ok(addr) => addr.port(), - Err(_) => continue, - }; - record_tcp_listener(server.guest_local_addr, host_port); - let family = JavascriptSocketFamily::from_ip(server.guest_local_addr.ip()); - http_loopback_targets.insert( - (family, server.guest_local_addr.port()), - JavascriptHttpLoopbackTarget { - process_id: process_id.to_owned(), - server_id: *server_id, - }, - ); - } - - if let Ok(http2) = process.http2.shared.lock() { - for server in http2.servers.values() { - record_tcp_listener(server.guest_local_addr, server.actual_local_addr.port()); - } - } - - for socket in process.tcp_sockets.values() { - let guest_addr = socket - .kernel_socket_id - .and_then(|socket_id| kernel.socket_get(socket_id)) - .and_then(|record| record.local_address().cloned()) - .and_then(|address| resolve_tcp_bind_addr(address.host(), address.port()).ok()) - .unwrap_or(socket.guest_local_addr); - let family = JavascriptSocketFamily::from_ip(guest_addr.ip()); - used_tcp_ports - .entry(family) - .or_default() - .insert(guest_addr.port()); - } - - for socket in process.udp_sockets.values() { - let guest_addr = socket - .kernel_socket_id - .and_then(|socket_id| kernel.socket_get(socket_id)) - .and_then(|record| record.local_address().cloned()) - .and_then(|address| { - resolve_udp_bind_addr(address.host(), address.port(), socket.family).ok() - }) - .or_else(|| socket.local_addr()); - let Some(guest_addr) = guest_addr else { - continue; - }; - let family = JavascriptSocketFamily::from_ip(guest_addr.ip()); - used_udp_ports - .entry(family) - .or_default() - .insert(guest_addr.port()); - if let Some(host_addr) = socket - .socket - .as_ref() - .and_then(|socket| socket.local_addr().ok()) - { - if is_loopback_ip(guest_addr.ip()) { - udp_guest_to_host.insert((family, guest_addr.port()), host_addr.port()); - udp_host_to_guest.insert((family, host_addr.port()), guest_addr.port()); - } - } else if socket.kernel_socket_id.is_some() && is_loopback_ip(guest_addr.ip()) { - udp_guest_to_host.insert((family, guest_addr.port()), guest_addr.port()); - udp_host_to_guest.insert((family, guest_addr.port()), guest_addr.port()); - } - } - - for (child_process_id, child) in &process.child_processes { - let child_id = format!("{process_id}/{child_process_id}"); - collect_javascript_socket_port_state( - kernel, - &child_id, - child, - tcp_guest_to_host, - http_loopback_targets, - udp_guest_to_host, - udp_host_to_guest, - used_tcp_ports, - used_udp_ports, - ); - } -} - -pub(crate) fn build_javascript_socket_path_context( - vm: &VmState, -) -> Result { - let mut loopback_exempt_ports = vm.create_loopback_exempt_ports.clone(); - loopback_exempt_ports.extend(vm.configuration.loopback_exempt_ports.iter().copied()); - let mut tcp_loopback_guest_to_host_ports = BTreeMap::new(); - let mut http_loopback_targets = BTreeMap::new(); - let mut udp_loopback_guest_to_host_ports = BTreeMap::new(); - let mut udp_loopback_host_to_guest_ports = BTreeMap::new(); - let mut used_tcp_guest_ports = BTreeMap::new(); - let mut used_udp_guest_ports = BTreeMap::new(); - for (process_id, process) in &vm.active_processes { - collect_javascript_socket_port_state( - &vm.kernel, - process_id, - process, - &mut tcp_loopback_guest_to_host_ports, - &mut http_loopback_targets, - &mut udp_loopback_guest_to_host_ports, - &mut udp_loopback_host_to_guest_ports, - &mut used_tcp_guest_ports, - &mut used_udp_guest_ports, - ); - } - Ok(JavascriptSocketPathContext { - sandbox_root: vm.cwd.clone(), - mounts: vm.configuration.mounts.clone(), - listen_policy: vm.listen_policy, - loopback_exempt_ports, - tcp_loopback_guest_to_host_ports, - http_loopback_targets, - udp_loopback_guest_to_host_ports, - udp_loopback_host_to_guest_ports, - used_tcp_guest_ports, - used_udp_guest_ports, - }) -} - -fn check_network_resource_limit( - limit: Option, - current: usize, - additional: usize, - label: &str, -) -> Result<(), SidecarError> { - if let Some(limit) = limit { - if current.saturating_add(additional) > limit { - return Err(SidecarError::Execution(format!( - "EAGAIN: maximum {label} count reached" - ))); - } - } - Ok(()) -} - -fn normalize_tcp_listen_host( - host: Option<&str>, -) -> Result<(JavascriptSocketFamily, &'static str, &'static str), SidecarError> { - match host.unwrap_or("127.0.0.1") { - "127.0.0.1" | "localhost" => Ok((JavascriptSocketFamily::Ipv4, "127.0.0.1", "127.0.0.1")), - "::1" => Ok((JavascriptSocketFamily::Ipv6, "::1", "::1")), - "0.0.0.0" => Ok((JavascriptSocketFamily::Ipv4, "127.0.0.1", "0.0.0.0")), - "::" => Ok((JavascriptSocketFamily::Ipv6, "::1", "::")), - other => Err(SidecarError::Execution(format!( - "EACCES: TCP listeners must bind to loopback or unspecified addresses, got {other}" - ))), - } -} - -fn normalize_udp_bind_host( - host: Option<&str>, - family: JavascriptUdpFamily, -) -> Result<(&'static str, &'static str, JavascriptSocketFamily), SidecarError> { - match (family, host) { - (JavascriptUdpFamily::Ipv4, None) | (JavascriptUdpFamily::Ipv4, Some("0.0.0.0")) => { - Ok(("127.0.0.1", "0.0.0.0", JavascriptSocketFamily::Ipv4)) - } - (JavascriptUdpFamily::Ipv4, Some("127.0.0.1")) - | (JavascriptUdpFamily::Ipv4, Some("localhost")) => { - Ok(("127.0.0.1", "127.0.0.1", JavascriptSocketFamily::Ipv4)) - } - (JavascriptUdpFamily::Ipv6, None) | (JavascriptUdpFamily::Ipv6, Some("::")) => { - Ok(("::1", "::", JavascriptSocketFamily::Ipv6)) - } - (JavascriptUdpFamily::Ipv6, Some("::1")) - | (JavascriptUdpFamily::Ipv6, Some("localhost")) => { - Ok(("::1", "::1", JavascriptSocketFamily::Ipv6)) - } - (JavascriptUdpFamily::Ipv4, Some(other)) => Err(SidecarError::Execution(format!( - "EACCES: udp4 sockets must bind to 127.0.0.1 or 0.0.0.0, got {other}" - ))), - (JavascriptUdpFamily::Ipv6, Some(other)) => Err(SidecarError::Execution(format!( - "EACCES: udp6 sockets must bind to ::1 or ::, got {other}" - ))), - } -} - -fn allocate_guest_listen_port( - requested_port: u16, - family: JavascriptSocketFamily, - used_ports: &BTreeMap>, - policy: VmListenPolicy, -) -> Result { - let is_allowed = |port: u16| { - port >= policy.port_min - && port <= policy.port_max - && (policy.allow_privileged || port >= 1024) - }; - let used = used_ports.get(&family); - - if requested_port != 0 { - if !is_allowed(requested_port) { - let reason = if requested_port < 1024 && !policy.allow_privileged { - format!( - "EACCES: privileged listen port {requested_port} requires {}=true", - VM_LISTEN_ALLOW_PRIVILEGED_METADATA_KEY - ) - } else { - format!( - "EACCES: listen port {requested_port} is outside the allowed range {}-{}", - policy.port_min, policy.port_max - ) - }; - return Err(SidecarError::Execution(reason)); - } - if used.is_some_and(|ports| ports.contains(&requested_port)) { - return Err(sidecar_net_error(std::io::Error::from_raw_os_error( - libc::EADDRINUSE, - ))); - } - return Ok(requested_port); - } - - let allocation_start = policy - .port_min - .max(if policy.allow_privileged { 1 } else { 1024 }); - for candidate in allocation_start..=policy.port_max { - if used.is_some_and(|ports| ports.contains(&candidate)) { - continue; - } - return Ok(candidate); - } - - Err(sidecar_net_error(std::io::Error::from_raw_os_error( - libc::EADDRINUSE, - ))) -} - -fn socket_host_matches(requested: Option<&str>, actual: &str) -> bool { - match requested { - None => true, - Some(requested) if requested == actual => true, - Some(requested) - if is_unspecified_socket_host(requested) && is_unspecified_socket_host(actual) => - { - true - } - Some(requested) if is_unspecified_socket_host(requested) => is_loopback_socket_host(actual), - Some(requested) if requested.eq_ignore_ascii_case("localhost") => { - is_loopback_socket_host(actual) - } - _ => false, - } -} - -fn parse_proc_net_entries(table_path: &str) -> Result, SidecarError> { - let contents = match fs::read_to_string(table_path) { - Ok(contents) => contents, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()), - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to inspect socket table {table_path}: {error}" - ))); - } - }; - - let mut entries = Vec::new(); - for line in contents.lines().skip(1) { - let columns = line.split_whitespace().collect::>(); - if columns.len() < 10 { - continue; - } - let Some((host, port)) = parse_proc_ip_port(columns[1]) else { - continue; - }; - let Ok(inode) = columns[9].parse::() else { - continue; - }; - entries.push(ProcNetEntry { - local_host: host, - local_port: port, - state: columns[3].to_owned(), - inode, - }); - } - - Ok(entries) -} - -fn parse_proc_ip_port(value: &str) -> Option<(String, u16)> { - let (raw_ip, raw_port) = value.split_once(':')?; - let port = u16::from_str_radix(raw_port, 16).ok()?; - let host = match raw_ip.len() { - 8 => { - let raw = u32::from_str_radix(raw_ip, 16).ok()?; - Ipv4Addr::from(raw.to_le_bytes()).to_string() - } - 32 => { - let mut bytes = [0_u8; 16]; - for (index, chunk) in raw_ip.as_bytes().chunks(8).enumerate() { - let word = u32::from_str_radix(std::str::from_utf8(chunk).ok()?, 16).ok()?; - bytes[index * 4..(index + 1) * 4].copy_from_slice(&word.to_le_bytes()); - } - Ipv6Addr::from(bytes).to_string() - } - _ => return None, - }; - Some((host, port)) -} - -fn python_file_entrypoint(entrypoint: &str) -> Option { - let path = Path::new(entrypoint); - (path.extension().and_then(|extension| extension.to_str()) == Some("py")) - .then(|| path.to_path_buf()) -} - -fn add_runtime_guest_path_mapping( - env: &mut BTreeMap, - guest_path: &str, - host_path: &Path, -) { - let mut mappings = env - .get("AGENTOS_GUEST_PATH_MAPPINGS") - .and_then(|value| serde_json::from_str::>(value).ok()) - .unwrap_or_default(); - mappings.retain(|mapping| { - mapping - .get("guestPath") - .and_then(Value::as_str) - .map(|existing| normalize_path(existing) != normalize_path(guest_path)) - .unwrap_or(true) - }); - mappings.push(json!({ - "guestPath": normalize_path(guest_path), - "hostPath": host_path.display().to_string(), - })); - if let Ok(serialized) = serde_json::to_string(&mappings) { - env.insert(String::from("AGENTOS_GUEST_PATH_MAPPINGS"), serialized); - } -} - -fn add_runtime_host_access_path( - env: &mut BTreeMap, - key: &str, - host_path: &Path, - expand: bool, -) { - let existing = env - .get(key) - .and_then(|value| serde_json::from_str::>(value).ok()) - .unwrap_or_default() - .into_iter() - .map(PathBuf::from) - .collect::>(); - let mut paths = existing; - paths.push(host_path.to_path_buf()); - let normalized = if expand { - expand_host_access_paths(&paths) - } else { - dedupe_host_paths(&paths) - }; - let serialized = normalized - .iter() - .map(|path| path.to_string_lossy().into_owned()) - .collect::>(); - if let Ok(serialized) = serde_json::to_string(&serialized) { - env.insert(key.to_owned(), serialized); - } -} - -// discover_command_guest_paths moved to crate::bootstrap - -fn is_path_like_specifier(specifier: &str) -> bool { - specifier.starts_with('/') - || specifier.starts_with("./") - || specifier.starts_with("../") - || specifier.starts_with("file:") -} - -fn execution_wasm_permission_tier(tier: WasmPermissionTier) -> ExecutionWasmPermissionTier { - match tier { - WasmPermissionTier::Full => ExecutionWasmPermissionTier::Full, - WasmPermissionTier::ReadWrite => ExecutionWasmPermissionTier::ReadWrite, - WasmPermissionTier::ReadOnly => ExecutionWasmPermissionTier::ReadOnly, - WasmPermissionTier::Isolated => ExecutionWasmPermissionTier::Isolated, - } -} - -fn resolve_wasm_permission_tier( - vm: &VmState, - command_name: Option<&str>, - explicit_tier: Option, - entrypoint: &str, -) -> WasmPermissionTier { - explicit_tier - .or_else(|| command_name.and_then(|command| vm.command_permissions.get(command).copied())) - .or_else(|| { - Path::new(entrypoint) - .file_name() - .and_then(|name| name.to_str()) - .and_then(|command| vm.command_permissions.get(command).copied()) - }) - .unwrap_or(WasmPermissionTier::Full) -} - -fn tokenize_shell_free_command(command: &str) -> Vec { - command - .split_whitespace() - .filter(|segment| !segment.is_empty()) - .map(str::to_owned) - .collect() -} - -fn is_posix_shell_builtin(command: &str) -> bool { - matches!( - command, - "." | ":" - | "break" - | "cd" - | "continue" - | "eval" - | "exec" - | "exit" - | "export" - | "readonly" - | "return" - | "set" - | "shift" - | "times" - | "trap" - | "umask" - | "unset" - ) -} - -/// Single-token checks for shell-mode commands whose first word forces a real -/// shell even when the command string has no shell metacharacters. This is not -/// a parser: env-assignment prefixes (`FOO=bar cmd`) and shell reserved words -/// have no meaning outside `sh`, so whitespace-tokenizing them would silently -/// run the wrong program. -fn shell_first_token_requires_shell(token: &str) -> bool { - token.contains('=') || is_shell_reserved_word(token) -} - -fn is_shell_reserved_word(token: &str) -> bool { - matches!( - token, - "if" | "then" - | "elif" - | "else" - | "fi" - | "for" - | "in" - | "do" - | "done" - | "while" - | "until" - | "case" - | "esac" - | "{" - | "}" - | "!" - ) -} - -fn command_requires_shell(command: &str) -> bool { - command.chars().any(|ch| { - matches!( - ch, - '|' | '&' - | ';' - | '<' - | '>' - | '(' - | ')' - | '$' - | '`' - | '*' - | '?' - | '[' - | ']' - | '{' - | '}' - | '~' - | '\'' - | '"' - | '\\' - | '\n' - ) - }) -} - -fn host_mount_path_for_guest_path(vm: &VmState, guest_path: &str) -> Option { - let normalized = normalize_path(guest_path); - - let mut mounts = vm - .configuration - .mounts - .iter() - .filter_map(|mount| { - ((mount.plugin.id == "host_dir") || (mount.plugin.id == "module_access")) - .then(|| { - mount_config_host_backing_path(&mount.plugin.config) - .map(|host_path| (mount.guest_path.as_str(), host_path)) - }) - .flatten() - }) - .collect::>(); - mounts.sort_by_key(|mount| std::cmp::Reverse(mount.0.len())); - - for (guest_root, host_root) in mounts { - if normalized != guest_root && !normalized.starts_with(&format!("{guest_root}/")) { - continue; - } - - let suffix = normalized - .strip_prefix(guest_root) - .unwrap_or_default() - .trim_start_matches('/'); - let mut path = PathBuf::from(host_root); - if !suffix.is_empty() { - path.push(suffix); - } - return Some(path); - } - - None -} - -fn host_runtime_path_for_guest_path_with_env( - vm: &VmState, - runtime_env: &BTreeMap, - guest_path: &str, - default_host_cwd: &Path, -) -> Option { - if let Some(path) = host_mount_path_for_guest_path(vm, guest_path) { - return Some(path); - } - if let Some(path) = host_path_from_runtime_guest_mappings(runtime_env, guest_path) { - return Some(path); - } - - let normalized = normalize_path(guest_path); - let virtual_home = guest_virtual_home(vm); - - if normalized == virtual_home || normalized.starts_with(&format!("{virtual_home}/")) { - let suffix = normalized - .strip_prefix(&virtual_home) - .unwrap_or_default() - .trim_start_matches('/'); - let mut host_path = default_host_cwd.to_path_buf(); - if !suffix.is_empty() { - host_path.push(suffix); - } - return Some(host_path); - } - - None -} - -#[derive(Deserialize, Serialize)] -struct RuntimeGuestPathMapping { - #[serde(rename = "guestPath")] - guest_path: String, - #[serde(rename = "hostPath")] - host_path: String, - #[serde(rename = "readOnly", default)] - read_only: bool, -} - -pub(crate) fn host_path_from_runtime_guest_mappings( - runtime_env: &BTreeMap, - guest_path: &str, -) -> Option { - let mappings = runtime_env - .get("AGENTOS_GUEST_PATH_MAPPINGS") - .and_then(|value| serde_json::from_str::>(value).ok())?; - let normalized = normalize_path(guest_path); - - let mut sorted_mappings = mappings - .into_iter() - .filter_map(|mapping| { - (!mapping.guest_path.is_empty() && !mapping.host_path.is_empty()).then_some(( - normalize_path(&mapping.guest_path), - PathBuf::from(mapping.host_path), - )) - }) - .collect::>(); - sorted_mappings.sort_by_key(|mapping| std::cmp::Reverse(mapping.0.len())); - - for (guest_root, mut host_root) in sorted_mappings { - if guest_root != "/" - && normalized != guest_root - && !normalized.starts_with(&format!("{guest_root}/")) - { - continue; - } - if guest_root == "/" && !normalized.starts_with('/') { - continue; - } - - if host_root.is_relative() { - host_root = std::env::current_dir().ok()?.join(host_root); - } - - let suffix = if guest_root == "/" { - normalized.trim_start_matches('/') - } else { - normalized - .strip_prefix(&guest_root) - .unwrap_or_default() - .trim_start_matches('/') - }; - if !suffix.is_empty() { - host_root.push(suffix); - } - return Some(host_root); - } - - None -} - -fn guest_runtime_path_for_host_path( - runtime_env: &BTreeMap, - virtual_home: &str, - cwd: &Path, - host_path: &str, -) -> Option { - let resolved = if host_path.starts_with("file://") { - PathBuf::from(host_path.trim_start_matches("file://")) - } else if host_path.starts_with("file:") { - PathBuf::from(host_path.trim_start_matches("file:")) - } else { - let candidate = PathBuf::from(host_path); - if candidate.is_absolute() { - candidate - } else if host_path.starts_with("./") || host_path.starts_with("../") { - cwd.join(candidate) - } else { - return None; - } - }; - let normalized = normalize_host_path(&resolved); - - if let Some(path) = guest_path_from_runtime_host_mappings(runtime_env, &normalized) { - return Some(path); - } - - let normalized_cwd = normalize_host_path(cwd); - if !path_is_within_root(&normalized, &normalized_cwd) { - return None; - } - - let virtual_home = if virtual_home.starts_with('/') { - virtual_home.to_string() - } else { - String::from("/root") - }; - let suffix = normalized - .strip_prefix(&normalized_cwd) - .ok()? - .to_string_lossy() - .replace('\\', "/") - .trim_start_matches('/') - .to_owned(); - - Some(if suffix.is_empty() { - virtual_home - } else { - normalize_path(&format!("{virtual_home}/{suffix}")) - }) -} - -fn guest_path_from_runtime_host_mappings( - runtime_env: &BTreeMap, - host_path: &Path, -) -> Option { - let mappings = runtime_env - .get("AGENTOS_GUEST_PATH_MAPPINGS") - .and_then(|value| serde_json::from_str::>(value).ok())?; - let normalized = normalize_host_path(host_path); - - let mut sorted_mappings = mappings - .into_iter() - .filter_map(|mapping| { - (!mapping.guest_path.is_empty() && !mapping.host_path.is_empty()).then_some(( - normalize_path(&mapping.guest_path), - normalize_host_path(Path::new(&mapping.host_path)), - )) - }) - .collect::>(); - sorted_mappings.sort_by_key(|mapping| std::cmp::Reverse(mapping.1.as_os_str().len())); - - for (guest_root, host_root) in sorted_mappings { - if !path_is_within_root(&normalized, &host_root) { - continue; - } - let suffix = normalized - .strip_prefix(&host_root) - .ok()? - .to_string_lossy() - .replace('\\', "/") - .trim_start_matches('/') - .to_owned(); - - return Some(if suffix.is_empty() { - guest_root - } else if guest_root == "/" { - normalize_path(&format!("/{suffix}")) - } else { - normalize_path(&format!("{guest_root}/{suffix}")) - }); - } - - None -} - -fn host_mount_path_for_guest_path_from_mounts( - mounts: &[crate::protocol::MountDescriptor], - guest_path: &str, -) -> Option { - let normalized = normalize_path(guest_path); - - let mut host_mounts = mounts - .iter() - .filter_map(|mount| { - ((mount.plugin.id == "host_dir") || (mount.plugin.id == "module_access")) - .then(|| { - mount_config_host_backing_path(&mount.plugin.config) - .map(|host_path| (mount.guest_path.as_str(), host_path)) - }) - .flatten() - }) - .collect::>(); - host_mounts.sort_by_key(|mount| std::cmp::Reverse(mount.0.len())); - - for (guest_root, host_root) in host_mounts { - if normalized != guest_root && !normalized.starts_with(&format!("{guest_root}/")) { - continue; - } - - let suffix = normalized - .strip_prefix(guest_root) - .unwrap_or_default() - .trim_start_matches('/'); - let mut path = PathBuf::from(host_root); - if !suffix.is_empty() { - path.push(suffix); - } - return Some(path); - } - - None -} - -#[cfg(test)] -mod host_mount_path_for_guest_path_from_mounts_tests { - use super::host_mount_path_for_guest_path_from_mounts; - use crate::protocol::{MountDescriptor, MountPluginDescriptor}; - use serde_json::json; - use std::path::PathBuf; - - #[test] - fn resolves_module_access_mount_paths() { - let mounts = vec![MountDescriptor { - guest_path: String::from("/root/node_modules"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("module_access"), - config: json!({ - "hostPath": "/tmp/workspace/node_modules", - }) - .to_string(), - }, - }]; - - let resolved = - host_mount_path_for_guest_path_from_mounts(&mounts, "/root/node_modules/pkg/index.js") - .expect("module_access mount should resolve"); - - assert_eq!( - resolved, - PathBuf::from("/tmp/workspace/node_modules/pkg/index.js") - ); - } - - #[test] - fn does_not_resolve_agentos_packages_as_host_paths() { - let mounts = vec![MountDescriptor { - guest_path: String::from("/opt/agentos/bin/pi"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("agentos_packages"), - config: json!({ - "kind": "singleSymlink", - "target": "../pkgs/pi/current/bin/pi", - }) - .to_string(), - }, - }]; - - assert!( - host_mount_path_for_guest_path_from_mounts(&mounts, "/opt/agentos/bin/pi").is_none() - ); - } -} - -fn resolve_guest_socket_host_path( - context: &JavascriptSocketPathContext, - guest_path: &str, -) -> PathBuf { - if let Some(path) = host_mount_path_for_guest_path_from_mounts(&context.mounts, guest_path) { - return path; - } - - let normalized = normalize_path(guest_path); - let mut host_path = context.sandbox_root.clone(); - let suffix = normalized.trim_start_matches('/'); - if !suffix.is_empty() { - host_path.push(suffix); - } - host_path -} - -fn ensure_kernel_parent_directories( - kernel: &mut SidecarKernel, - path: &str, -) -> Result<(), SidecarError> { - let parent = dirname(path); - if parent != "/" && !kernel.exists(&parent).map_err(kernel_error)? { - kernel.mkdir(&parent, true).map_err(kernel_error)?; - } - Ok(()) -} - -// JavascriptChildProcessSpawnOptions, JavascriptChildProcessSpawnRequest moved to crate::protocol -// ResolvedChildProcessExecution moved to crate::state - -pub(crate) fn sanitize_javascript_child_process_internal_bootstrap_env( - env: &BTreeMap, -) -> BTreeMap { - const ALLOWED_KEYS: &[&str] = &[ - "AGENTOS_ALLOWED_NODE_BUILTINS", - "AGENTOS_GUEST_PATH_MAPPINGS", - "AGENTOS_LOOPBACK_EXEMPT_PORTS", - "AGENTOS_VIRTUAL_PROCESS_EXEC_PATH", - "AGENTOS_VIRTUAL_PROCESS_UID", - "AGENTOS_VIRTUAL_PROCESS_GID", - "AGENTOS_VIRTUAL_PROCESS_VERSION", - ]; - - env.iter() - .filter(|(key, _)| { - ALLOWED_KEYS.contains(&key.as_str()) || key.starts_with("AGENTOS_VIRTUAL_OS_") - }) - .map(|(key, value)| (key.clone(), value.clone())) - .collect() -} - -// Network request types moved to crate::protocol - -// VmDnsConfig, DnsResolutionSource moved to crate::state - -fn resolve_tcp_bind_addr(host: &str, port: u16) -> Result { - (host, port) - .to_socket_addrs() - .map_err(sidecar_net_error)? - .next() - .ok_or_else(|| { - SidecarError::Execution(format!("failed to resolve TCP bind address {host}:{port}")) - }) -} - -pub(crate) fn format_dns_resource(hostname: &str) -> String { - format!("dns://{hostname}") -} - -// --- Guest Python socket bridge helpers ------------------------------------ - -/// Host-socket read timeout for one `recv`/`recvfrom` RPC. Kept short so the -/// synchronous RPC returns promptly (data, or a `timed_out` flag the Python -/// shim re-polls on) and never stalls the shared sidecar event loop. -// Short so a recv/recvfrom RPC holds the shared event loop only briefly; the -// guest shim adds a capped backoff between polls to bound the poll rate. -const PYTHON_SOCKET_READ_POLL: Duration = Duration::from_millis(25); -const PYTHON_SOCKET_CONNECT_TIMEOUT: Duration = Duration::from_secs(30); -const PYTHON_SOCKET_WRITE_TIMEOUT: Duration = Duration::from_secs(30); -const PYTHON_SOCKET_DEFAULT_RECV: usize = 65536; -const PYTHON_SOCKET_MAX_RECV: usize = 4 * 1024 * 1024; - -fn python_socket_host(request: &PythonVfsRpcRequest) -> Result { - request - .hostname - .clone() - .ok_or_else(|| SidecarError::InvalidState(String::from("python socket op requires a host"))) -} - -fn python_socket_port(request: &PythonVfsRpcRequest) -> Result { - request - .port - .ok_or_else(|| SidecarError::InvalidState(String::from("python socket op requires a port"))) -} - -fn python_socket_payload(request: &PythonVfsRpcRequest) -> Result, SidecarError> { - let Some(body) = request.body_base64.as_deref() else { - return Ok(Vec::new()); - }; - base64::engine::general_purpose::STANDARD - .decode(body) - .map_err(|error| { - SidecarError::InvalidState(format!("invalid base64 python socket payload: {error}")) - }) -} - -fn python_socket_recv_len(request: &PythonVfsRpcRequest) -> usize { - request - .max_buffer - .unwrap_or(PYTHON_SOCKET_DEFAULT_RECV) - .clamp(1, PYTHON_SOCKET_MAX_RECV) -} - -fn python_connect_tcp(addrs: &[IpAddr], port: u16) -> Result { - let mut last_error: Option = None; - for ip in addrs { - let addr = SocketAddr::new(*ip, port); - match TcpStream::connect_timeout(&addr, PYTHON_SOCKET_CONNECT_TIMEOUT) { - Ok(stream) => return Ok(stream), - Err(error) => last_error = Some(error.to_string()), - } - } - Err(SidecarError::Execution(format!( - "ECONNREFUSED: {}", - last_error.unwrap_or_else(|| String::from("no resolved addresses")) - ))) -} - -fn python_socket_would_block(error: &std::io::Error) -> bool { - matches!( - error.kind(), - std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut - ) -} - -fn python_socket_io_error(error: std::io::Error) -> SidecarError { - SidecarError::Execution(format!("EIO: python socket: {error}")) -} - -fn python_socket_kind_error(op: &str, expected: &str) -> SidecarError { - SidecarError::Execution(format!( - "EOPNOTSUPP: python socket {op} requires a {expected} socket" - )) -} - -fn blocked_dns_resolution_error( - resource: &str, - ip: IpAddr, - cidr: &str, - label: &str, -) -> SidecarError { - SidecarError::Execution(format!( - "EACCES: blocked outbound network access to {resource}: {ip} is within restricted {label} range {cidr}" - )) -} - -fn blocked_loopback_connect_error(resource: &str, ip: IpAddr, port: u16) -> SidecarError { - SidecarError::Execution(format!( - "EACCES: blocked outbound network access to {resource}: {ip} is loopback ({}) and port {port} is not owned by this VM and is not listed in {LOOPBACK_EXEMPT_PORTS_ENV}", - loopback_cidr(ip) - )) -} - -fn filter_dns_safe_ip_addrs( - addresses: Vec, - hostname: &str, -) -> Result, SidecarError> { - let resource = format_dns_resource(hostname); - let mut allowed = Vec::new(); - let mut blocked = None; - - for ip in addresses { - if let Some((cidr, label)) = restricted_non_loopback_ip_range(ip) { - blocked.get_or_insert((ip, cidr, label)); - continue; - } - allowed.push(ip); - } - - if allowed.is_empty() { - let (ip, cidr, label) = blocked.expect("blocked DNS results should capture a reason"); - return Err(blocked_dns_resolution_error(&resource, ip, cidr, label)); - } - - Ok(allowed) -} - -fn loopback_connect_allowed(context: &JavascriptSocketPathContext, port: u16) -> bool { - context.loopback_port_allowed(port) -} - -fn filter_tcp_connect_ip_addrs( - addresses: Vec, - host: &str, - port: u16, - context: &JavascriptSocketPathContext, -) -> Result, SidecarError> { - let resource = format_tcp_resource(host, port); - let mut allowed = Vec::new(); - let mut blocked = None; - - for ip in addresses { - if let Some((cidr, label)) = restricted_non_loopback_ip_range(ip) { - blocked.get_or_insert_with(|| blocked_dns_resolution_error(&resource, ip, cidr, label)); - continue; - } - if is_loopback_ip(ip) && !loopback_connect_allowed(context, port) { - blocked.get_or_insert_with(|| blocked_loopback_connect_error(&resource, ip, port)); - continue; - } - allowed.push(ip); - } - - if allowed.is_empty() { - return Err(blocked.expect("blocked TCP connect results should capture a reason")); - } - - Ok(allowed) -} - -fn resolve_tcp_connect_addr( - bridge: &SharedBridge, - kernel: &SidecarKernel, - vm_id: &str, - dns: &VmDnsConfig, - host: &str, - port: u16, - context: &JavascriptSocketPathContext, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let allowed = filter_tcp_connect_ip_addrs( - resolve_dns_ip_addrs( - bridge, - kernel, - vm_id, - dns, - host, - DnsLookupPolicy::SkipPermissions, - )?, - host, - port, - context, - )?; - let ip = allowed - .iter() - .copied() - .find(|candidate| { - let family = JavascriptSocketFamily::from_ip(*candidate); - context.translate_tcp_loopback_port(family, port).is_some() - }) - // We do not implement Happy Eyeballs yet, so prefer IPv4 over a - // verbatim IPv6-first DNS answer for general outbound TCP connects. - .or_else(|| allowed.iter().copied().find(IpAddr::is_ipv4)) - .or_else(|| allowed.first().copied()) - .ok_or_else(|| { - SidecarError::Execution(format!("failed to resolve TCP address {host}:{port}")) - })?; - let family = JavascriptSocketFamily::from_ip(ip); - let translated_loopback_port = context.translate_tcp_loopback_port(family, port); - let use_kernel_loopback = is_loopback_ip(ip) && translated_loopback_port == Some(port); - let actual_port = if is_loopback_ip(ip) { - translated_loopback_port.unwrap_or(port) - } else { - port - }; - Ok(ResolvedTcpConnectAddr { - actual_addr: SocketAddr::new(ip, actual_port), - guest_remote_addr: SocketAddr::new(ip, port), - use_kernel_loopback, - }) -} - -fn resolve_dns_ip_addrs( - bridge: &SharedBridge, - kernel: &SidecarKernel, - vm_id: &str, - dns: &VmDnsConfig, - hostname: &str, - policy: DnsLookupPolicy, -) -> Result, SidecarError> -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let resolution = match kernel.resolve_dns(hostname, policy) { - Ok(resolution) => resolution, - Err(error) => { - let sidecar_error = kernel_error(error.clone()); - if error.code() != "EACCES" { - emit_dns_resolution_failure_event(bridge, vm_id, hostname, dns, &sidecar_error); - } - return Err(sidecar_error); - } - }; - emit_dns_resolution_event( - bridge, - vm_id, - hostname, - resolution.source(), - resolution.addresses(), - dns, - ); - Ok(resolution.addresses().to_vec()) -} - -fn resolve_dns_records( - bridge: &SharedBridge, - kernel: &SidecarKernel, - vm_id: &str, - dns: &VmDnsConfig, - hostname: &str, - record_type: RecordType, - policy: DnsLookupPolicy, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let resolution = match kernel.resolve_dns_records(hostname, record_type, policy) { - Ok(resolution) => resolution, - Err(error) => { - let sidecar_error = kernel_error(error.clone()); - if error.code() != "EACCES" { - emit_dns_resolution_failure_event(bridge, vm_id, hostname, dns, &sidecar_error); - } - return Err(sidecar_error); - } - }; - emit_dns_record_resolution_event(bridge, vm_id, hostname, &resolution, dns); - Ok(resolution) -} - -fn filter_dns_ip_addrs( - addresses: Vec, - family: Option, -) -> Result, SidecarError> { - let filtered: Vec<_> = match family.unwrap_or(0) { - 0 => addresses, - 4 => addresses - .into_iter() - .filter(|ip| matches!(ip, IpAddr::V4(_))) - .collect(), - 6 => addresses - .into_iter() - .filter(|ip| matches!(ip, IpAddr::V6(_))) - .collect(), - other => { - return Err(SidecarError::InvalidState(format!( - "unsupported dns family {other}" - ))); - } - }; - - if filtered.is_empty() { - return Err(SidecarError::Execution(String::from( - "failed to resolve DNS address for requested family", - ))); - } - - Ok(filtered) -} - -fn resolve_udp_bind_addr( - host: &str, - port: u16, - family: JavascriptUdpFamily, -) -> Result { - (host, port) - .to_socket_addrs() - .map_err(sidecar_net_error)? - .find(|addr| family.matches_addr(addr)) - .ok_or_else(|| { - SidecarError::Execution(format!( - "failed to resolve {} UDP bind address {host}:{port}", - family.socket_type() - )) - }) -} - -fn resolve_udp_addr(request: UdpRemoteAddrRequest<'_, B>) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let UdpRemoteAddrRequest { - bridge, - kernel, - vm_id, - dns, - host, - port, - family, - context, - } = request; - resolve_dns_ip_addrs( - bridge, - kernel, - vm_id, - dns, - host, - DnsLookupPolicy::SkipPermissions, - )? - .into_iter() - .map(|ip| { - let family_key = JavascriptSocketFamily::from_ip(ip); - let actual_port = if is_loopback_ip(ip) { - context - .translate_udp_loopback_port(family_key, port) - .unwrap_or(port) - } else { - port - }; - SocketAddr::new(ip, actual_port) - }) - .find(|addr| family.matches_addr(addr)) - .ok_or_else(|| { - SidecarError::Execution(format!( - "failed to resolve {} UDP address {host}:{port}", - family.socket_type() - )) - }) -} - -fn javascript_net_timeout_value() -> Value { - Value::String(String::from(JAVASCRIPT_NET_TIMEOUT_SENTINEL)) -} - -fn javascript_net_json_string(value: Value, label: &str) -> Result { - serde_json::to_string(&value) - .map(Value::String) - .map_err(|error| { - SidecarError::InvalidState(format!("failed to serialize {label} payload: {error}")) - }) -} - -fn javascript_net_read_value( - event: Option, -) -> Result { - match event { - Some(JavascriptTcpSocketEvent::Data(chunk)) => Ok(Value::String( - base64::engine::general_purpose::STANDARD.encode(chunk), - )), - Some(JavascriptTcpSocketEvent::End | JavascriptTcpSocketEvent::Close { .. }) => { - Ok(Value::Null) - } - Some(JavascriptTcpSocketEvent::Error { code, message }) => { - let detail = code.unwrap_or_else(|| String::from("socket read")); - Err(SidecarError::Execution(format!("{detail}: {message}"))) - } - None => Ok(javascript_net_timeout_value()), - } -} - -fn io_error_code(error: &std::io::Error) -> Option { - match error.raw_os_error() { - Some(libc::EADDRINUSE) => Some(String::from("EADDRINUSE")), - Some(libc::EADDRNOTAVAIL) => Some(String::from("EADDRNOTAVAIL")), - Some(libc::ECONNREFUSED) => Some(String::from("ECONNREFUSED")), - Some(libc::ECONNRESET) => Some(String::from("ECONNRESET")), - Some(libc::EINVAL) => Some(String::from("EINVAL")), - Some(libc::EPIPE) => Some(String::from("EPIPE")), - Some(libc::ETIMEDOUT) => Some(String::from("ETIMEDOUT")), - Some(libc::EHOSTUNREACH) => Some(String::from("EHOSTUNREACH")), - Some(libc::ENETUNREACH) => Some(String::from("ENETUNREACH")), - _ => None, - } -} - -fn sidecar_net_error(error: std::io::Error) -> SidecarError { - let message = match io_error_code(&error) { - Some(code) => format!("{code}: {error}"), - None => error.to_string(), - }; - SidecarError::Execution(message) -} - -fn tls_provider() -> Arc { - Arc::new(aws_lc_rs::default_provider()) -} - -fn tls_local_certificates( - options: &JavascriptTlsBridgeOptions, -) -> Result>, SidecarError> { - let Some(certificates) = options.cert.as_ref() else { - return Ok(Vec::new()); - }; - tls_material_entries(certificates) -} - -fn tls_material_entries(material: &JavascriptTlsMaterial) -> Result>, SidecarError> { - match material { - JavascriptTlsMaterial::Single(entry) => tls_data_value(entry).map(|value| vec![value]), - JavascriptTlsMaterial::Many(entries) => entries.iter().map(tls_data_value).collect(), - } -} - -fn tls_data_value(value: &JavascriptTlsDataValue) -> Result, SidecarError> { - match value { - JavascriptTlsDataValue::Buffer { data } => base64::engine::general_purpose::STANDARD - .decode(data) - .map_err(|error| { - SidecarError::InvalidState(format!("TLS material contains invalid base64: {error}")) - }), - JavascriptTlsDataValue::String { data } => Ok(data.as_bytes().to_vec()), - } -} - -fn tls_certificates_from_material( - material: &JavascriptTlsMaterial, -) -> Result>, SidecarError> { - let mut certificates = Vec::new(); - for entry in tls_material_entries(material)? { - let mut reader = std::io::BufReader::new(Cursor::new(entry.clone())); - let parsed = rustls_pemfile::certs(&mut reader) - .collect::, _>>() - .map_err(sidecar_net_error)?; - if parsed.is_empty() { - certificates.push(CertificateDer::from(entry)); - } else { - certificates.extend(parsed); - } - } - if certificates.is_empty() { - return Err(SidecarError::InvalidState(String::from( - "TLS certificate material did not contain any certificates", - ))); - } - Ok(certificates) -} - -fn tls_private_key_from_material( - material: &JavascriptTlsMaterial, -) -> Result, SidecarError> { - for entry in tls_material_entries(material)? { - let mut reader = std::io::BufReader::new(Cursor::new(entry)); - if let Some(key) = rustls_pemfile::private_key(&mut reader).map_err(sidecar_net_error)? { - return Ok(key); - } - } - Err(SidecarError::InvalidState(String::from( - "TLS private key material did not contain a supported key", - ))) -} - -fn tls_root_store(options: &JavascriptTlsBridgeOptions) -> Result { - let mut roots = RootCertStore::empty(); - if let Some(ca) = options.ca.as_ref() { - for certificate in tls_certificates_from_material(ca)? { - roots.add(certificate).map_err(|error| { - SidecarError::InvalidState(format!("failed to add TLS CA certificate: {error}")) - })?; - } - return Ok(roots); - } - - for certificate in rustls_native_certs::load_native_certs().certs { - roots.add(certificate).map_err(|error| { - SidecarError::InvalidState(format!( - "failed to add native TLS certificate to root store: {error}" - )) - })?; - } - Ok(roots) -} - -fn build_client_tls_stream( - stream: TcpStream, - options: &JavascriptTlsBridgeOptions, -) -> Result, SidecarError> { - let config = build_client_tls_config(options)?; - let server_name = options - .servername - .clone() - .unwrap_or_else(|| String::from("localhost")); - let server_name = ServerName::try_from(server_name) - .map_err(|_| SidecarError::InvalidState(String::from("invalid TLS servername")))?; - stream - .set_read_timeout(Some(TLS_HANDSHAKE_TIMEOUT)) - .map_err(sidecar_net_error)?; - stream - .set_write_timeout(Some(TLS_HANDSHAKE_TIMEOUT)) - .map_err(sidecar_net_error)?; - let mut tls_stream = rustls::StreamOwned::new( - ClientConnection::new(Arc::new(config), server_name).map_err(|error| { - SidecarError::Execution(format!("failed to start TLS client: {error}")) - })?, - stream, - ); - while tls_stream.conn.is_handshaking() { - tls_stream - .conn - .complete_io(&mut tls_stream.sock) - .map_err(sidecar_net_error)?; - } - tls_stream - .sock - .set_read_timeout(Some(TCP_SOCKET_POLL_TIMEOUT)) - .map_err(sidecar_net_error)?; - tls_stream - .sock - .set_write_timeout(None) - .map_err(sidecar_net_error)?; - Ok(tls_stream) -} - -fn build_client_loopback_tls_stream( - transport: crate::state::LoopbackTlsEndpoint, - options: &JavascriptTlsBridgeOptions, -) -> Result, SidecarError> -{ - let config = build_client_tls_config(options)?; - let server_name = options - .servername - .clone() - .unwrap_or_else(|| String::from("localhost")); - let server_name = ServerName::try_from(server_name) - .map_err(|_| SidecarError::InvalidState(String::from("invalid TLS servername")))?; - let mut tls_stream = rustls::StreamOwned::new( - ClientConnection::new(Arc::new(config), server_name).map_err(|error| { - SidecarError::Execution(format!("failed to start TLS client: {error}")) - })?, - transport, - ); - match tls_stream.conn.complete_io(&mut tls_stream.sock) { - Ok(_) => {} - Err(error) - if matches!( - error.kind(), - std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut - ) => {} - Err(error) => return Err(sidecar_net_error(error)), - } - Ok(tls_stream) -} - -fn build_client_tls_config( - options: &JavascriptTlsBridgeOptions, -) -> Result { - let provider = tls_provider(); - let builder = ClientConfig::builder_with_provider(provider.clone()) - .with_safe_default_protocol_versions() - .map_err(|error| { - SidecarError::InvalidState(format!("invalid TLS protocol config: {error}")) - })?; - - let mut config = if options.reject_unauthorized == Some(false) { - let verifier = Arc::new(InsecureTlsVerifier { - supported_schemes: provider - .signature_verification_algorithms - .supported_schemes(), - }); - builder - .dangerous() - .with_custom_certificate_verifier(verifier) - .with_no_client_auth() - } else { - builder - .with_root_certificates(tls_root_store(options)?) - .with_no_client_auth() - }; - - if let Some(protocols) = options.alpn_protocols.as_ref() { - config.alpn_protocols = protocols - .iter() - .map(|protocol| protocol.as_bytes().to_vec()) - .collect(); - } - Ok(config) -} - -fn build_server_tls_stream( - stream: TcpStream, - options: &JavascriptTlsBridgeOptions, -) -> Result, SidecarError> { - let config = build_server_tls_config(options)?; - stream - .set_read_timeout(Some(TLS_HANDSHAKE_TIMEOUT)) - .map_err(sidecar_net_error)?; - stream - .set_write_timeout(Some(TLS_HANDSHAKE_TIMEOUT)) - .map_err(sidecar_net_error)?; - let mut tls_stream = rustls::StreamOwned::new( - ServerConnection::new(Arc::new(config)).map_err(|error| { - SidecarError::Execution(format!("failed to start TLS server: {error}")) - })?, - stream, - ); - while tls_stream.conn.is_handshaking() { - tls_stream - .conn - .complete_io(&mut tls_stream.sock) - .map_err(sidecar_net_error)?; - } - tls_stream - .sock - .set_read_timeout(Some(TCP_SOCKET_POLL_TIMEOUT)) - .map_err(sidecar_net_error)?; - tls_stream - .sock - .set_write_timeout(None) - .map_err(sidecar_net_error)?; - Ok(tls_stream) -} - -fn build_server_loopback_tls_stream( - transport: crate::state::LoopbackTlsEndpoint, - options: &JavascriptTlsBridgeOptions, -) -> Result, SidecarError> -{ - let config = build_server_tls_config(options)?; - Ok(rustls::StreamOwned::new( - ServerConnection::new(Arc::new(config)).map_err(|error| { - SidecarError::Execution(format!("failed to start TLS server: {error}")) - })?, - transport, - )) -} - -fn build_server_tls_config( - options: &JavascriptTlsBridgeOptions, -) -> Result { - let certificates = tls_certificates_from_material(options.cert.as_ref().ok_or_else(|| { - SidecarError::InvalidState(String::from("TLS server upgrade requires a certificate")) - })?)?; - let key = tls_private_key_from_material(options.key.as_ref().ok_or_else(|| { - SidecarError::InvalidState(String::from("TLS server upgrade requires a private key")) - })?)?; - - let mut config = ServerConfig::builder_with_provider(tls_provider()) - .with_safe_default_protocol_versions() - .map_err(|error| { - SidecarError::InvalidState(format!("invalid TLS protocol config: {error}")) - })? - .with_no_client_auth() - .with_single_cert(certificates, key) - .map_err(|error| { - SidecarError::InvalidState(format!("invalid TLS server config: {error}")) - })?; - - if let Some(protocols) = options.alpn_protocols.as_ref() { - config.alpn_protocols = protocols - .iter() - .map(|protocol| protocol.as_bytes().to_vec()) - .collect(); - } - Ok(config) -} - -fn tls_protocol_name(version: rustls::ProtocolVersion) -> String { - match version { - rustls::ProtocolVersion::TLSv1_2 => String::from("TLSv1.2"), - rustls::ProtocolVersion::TLSv1_3 => String::from("TLSv1.3"), - other => other - .as_str() - .map(str::to_owned) - .unwrap_or_else(|| format!("{other:?}")), - } -} - -fn tls_cipher_bridge_value(suite: rustls::SupportedCipherSuite) -> Value { - tls_bridge_object(vec![ - ( - "name", - suite - .suite() - .as_str() - .map(|value| Value::String(value.to_owned())) - .unwrap_or(Value::Null), - ), - ( - "standardName", - suite - .suite() - .as_str() - .map(|value| Value::String(value.to_owned())) - .unwrap_or(Value::Null), - ), - ( - "version", - Value::String(if suite.tls13().is_some() { - String::from("TLSv1.3") - } else { - String::from("TLSv1.2") - }), - ), - ]) -} - -fn tls_certificate_bridge_value(certificate: &[u8], detailed: bool) -> Value { - let mut fields = vec![("raw", tls_bridge_buffer_value(certificate))]; - if detailed { - fields.push(("issuerCertificate", tls_bridge_undefined_value())); - } - tls_bridge_object(fields) -} - -fn tls_bridge_buffer_value(bytes: &[u8]) -> Value { - json!({ - "type": "buffer", - "data": base64::engine::general_purpose::STANDARD.encode(bytes), - }) -} - -fn tls_bridge_object(entries: Vec<(&str, Value)>) -> Value { - let value = entries - .into_iter() - .map(|(key, value)| (key.to_owned(), value)) - .collect::>(); - json!({ - "type": "object", - "id": 1, - "value": value, - }) -} - -fn tls_bridge_undefined_value() -> Value { - json!({ - "type": "undefined", - }) -} - -fn spawn_tcp_socket_reader( - stream: TcpStream, - sender: Sender, - event_pusher: Arc>>, - tls_mode: Arc, - saw_local_shutdown: Arc, - saw_remote_end: Arc, - close_notified: Arc, -) { - thread::spawn(move || { - let mut stream = stream; - let mut buffer = vec![0_u8; 64 * 1024]; - loop { - if tls_mode.load(Ordering::SeqCst) { - break; - } - match stream.read(&mut buffer) { - Ok(0) => { - saw_remote_end.store(true, Ordering::SeqCst); - let _ = sender.send(JavascriptTcpSocketEvent::End); - push_socket_event(&event_pusher, "end"); - if saw_local_shutdown.load(Ordering::SeqCst) - && !close_notified.swap(true, Ordering::SeqCst) - { - let _ = sender.send(JavascriptTcpSocketEvent::Close { had_error: false }); - push_socket_event(&event_pusher, "close"); - } - break; - } - Ok(bytes_read) => { - if sender - .send(JavascriptTcpSocketEvent::Data( - buffer[..bytes_read].to_vec(), - )) - .is_err() - { - break; - } - push_socket_event(&event_pusher, "data"); - } - Err(error) - if matches!( - error.kind(), - std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut - ) => - { - continue; - } - Err(error) => { - let code = io_error_code(&error); - let _ = sender.send(JavascriptTcpSocketEvent::Error { - code, - message: error.to_string(), - }); - push_socket_event(&event_pusher, "error"); - if !close_notified.swap(true, Ordering::SeqCst) { - let _ = sender.send(JavascriptTcpSocketEvent::Close { had_error: true }); - push_socket_event(&event_pusher, "close"); - } - break; - } - } - } - }); -} - -fn push_socket_event( - event_pusher: &Arc>>, - event: &'static str, -) { - NET_TCP_TRACE_COUNTERS - .socket_read_push_attempts - .fetch_add(1, Ordering::Relaxed); - let target = event_pusher.lock().ok().and_then(|guard| guard.clone()); - let Some(target) = target else { - NET_TCP_TRACE_COUNTERS - .socket_read_push_missing - .fetch_add(1, Ordering::Relaxed); - return; - }; - let payload = v8_runtime::json_to_cbor_payload(&json!({ - "socketId": target.socket_id, - "event": event, - })) - .unwrap_or_default(); - match target.session.send_stream_event("net_socket", payload) { - Ok(()) => { - NET_TCP_TRACE_COUNTERS - .socket_read_push_sent - .fetch_add(1, Ordering::Relaxed); - } - Err(_) => { - NET_TCP_TRACE_COUNTERS - .socket_read_push_errors - .fetch_add(1, Ordering::Relaxed); - } - } -} - -fn send_tls_socket_error_and_close( - sender: &Sender, - event_pusher: &Arc>>, - close_notified: &Arc, - code: Option, - message: String, -) { - let _ = sender.send(JavascriptTcpSocketEvent::Error { code, message }); - push_socket_event(event_pusher, "error"); - if !close_notified.swap(true, Ordering::SeqCst) { - let _ = sender.send(JavascriptTcpSocketEvent::Close { had_error: true }); - push_socket_event(event_pusher, "close"); - } -} - -fn fail_loopback_tls_pending_reader( - pending_write: &LoopbackTlsPendingWriteHandle, - sender: &Sender, - event_pusher: &Arc>>, - close_notified: &Arc, - code: Option, - message: String, -) { - pending_write.mark_failed(message.clone()); - send_tls_socket_error_and_close(sender, event_pusher, close_notified, code, message); -} - -fn flush_loopback_tls_pending_writes( - tls_stream: &Arc>>, - pending_write: &LoopbackTlsPendingWriteHandle, - sender: &Sender, - event_pusher: &Arc>>, - close_notified: &Arc, -) -> bool { - loop { - let bytes = match pending_write.take_buffer_for_flush() { - Ok(bytes) => bytes, - Err(error) => { - fail_loopback_tls_pending_reader( - pending_write, - sender, - event_pusher, - close_notified, - Some(String::from("EIO")), - error.to_string(), - ); - return false; - } - }; - - if let Some(bytes) = bytes { - let write_result = { - let mut guard = match tls_stream.lock() { - Ok(guard) => guard, - Err(_) => { - pending_write.finish_flush(); - fail_loopback_tls_pending_reader( - pending_write, - sender, - event_pusher, - close_notified, - Some(String::from("EIO")), - String::from("TLS stream lock poisoned while flushing pending writes"), - ); - return false; - } - }; - let Some(stream) = guard.as_mut() else { - pending_write.finish_flush(); - fail_loopback_tls_pending_reader( - pending_write, - sender, - event_pusher, - close_notified, - Some(String::from("EIO")), - String::from("TLS stream missing while flushing pending writes"), - ); - return false; - }; - stream.write_all(&bytes) - }; - pending_write.finish_flush(); - if let Err(error) = write_result { - fail_loopback_tls_pending_reader( - pending_write, - sender, - event_pusher, - close_notified, - Some(String::from("EIO")), - format!("loopback TLS pending write flush failed: {error}"), - ); - return false; - } - continue; - } - - let should_shutdown = match pending_write.take_deferred_shutdown_write() { - Ok(should_shutdown) => should_shutdown, - Err(error) => { - fail_loopback_tls_pending_reader( - pending_write, - sender, - event_pusher, - close_notified, - Some(String::from("EIO")), - error.to_string(), - ); - return false; - } - }; - if should_shutdown { - let shutdown_result = { - let mut guard = match tls_stream.lock() { - Ok(guard) => guard, - Err(_) => { - fail_loopback_tls_pending_reader( - pending_write, - sender, - event_pusher, - close_notified, - Some(String::from("EIO")), - String::from("TLS stream lock poisoned during deferred shutdown"), - ); - return false; - } - }; - let Some(stream) = guard.as_mut() else { - fail_loopback_tls_pending_reader( - pending_write, - sender, - event_pusher, - close_notified, - Some(String::from("EIO")), - String::from("TLS stream missing during deferred shutdown"), - ); - return false; - }; - stream - .send_close_notify() - .and_then(|_| stream.shutdown_write()) - }; - if let Err(error) = shutdown_result { - fail_loopback_tls_pending_reader( - pending_write, - sender, - event_pusher, - close_notified, - Some(String::from("EIO")), - format!("loopback TLS deferred shutdown failed: {error}"), - ); - return false; - } - continue; - } - - return true; - } -} - -fn spawn_tls_socket_reader( - tls_stream: Arc>>, - loopback_pending_write: Option, - sender: Sender, - event_pusher: Arc>>, - saw_local_shutdown: Arc, - saw_remote_end: Arc, - close_notified: Arc, -) { - thread::spawn(move || { - let mut buffer = vec![0_u8; 64 * 1024]; - loop { - if let Some(pending_write) = loopback_pending_write.as_ref() { - let is_handshaking = { - let mut guard = match tls_stream.lock() { - Ok(guard) => guard, - Err(_) => { - pending_write.mark_failed("TLS stream lock poisoned"); - return; - } - }; - let Some(stream) = guard.as_mut() else { - pending_write.mark_failed("TLS stream missing"); - return; - }; - if stream.is_loopback() { - let is_handshaking = stream.is_handshaking(); - stream.set_loopback_poll_timeout(LOOPBACK_TLS_HANDSHAKE_POLL_TIMEOUT); - is_handshaking - } else { - false - } - }; - - if is_handshaking { - if pending_write.handshake_started_at.elapsed() >= TLS_HANDSHAKE_TIMEOUT { - fail_loopback_tls_pending_reader( - pending_write, - &sender, - &event_pusher, - &close_notified, - Some(String::from("ETIMEDOUT")), - format!( - "loopback TLS handshake timed out after {}ms", - TLS_HANDSHAKE_TIMEOUT.as_millis() - ), - ); - return; - } - } else { - pending_write - .tls_handshake_complete - .store(true, Ordering::SeqCst); - if !flush_loopback_tls_pending_writes( - &tls_stream, - pending_write, - &sender, - &event_pusher, - &close_notified, - ) { - return; - } - } - } - - let read_result = { - let mut guard = match tls_stream.lock() { - Ok(guard) => guard, - Err(_) => { - if let Some(pending_write) = loopback_pending_write.as_ref() { - pending_write.mark_failed("TLS stream lock poisoned"); - } - return; - } - }; - let Some(stream) = guard.as_mut() else { - if let Some(pending_write) = loopback_pending_write.as_ref() { - pending_write.mark_failed("TLS stream missing"); - } - return; - }; - stream.read(&mut buffer) - }; - - match read_result { - Ok(0) => { - if let Some(pending_write) = loopback_pending_write.as_ref() { - pending_write.fail_if_pending( - "loopback TLS peer closed before buffered writes flushed", - ); - } - saw_remote_end.store(true, Ordering::SeqCst); - let _ = sender.send(JavascriptTcpSocketEvent::End); - push_socket_event(&event_pusher, "end"); - if saw_local_shutdown.load(Ordering::SeqCst) - && !close_notified.swap(true, Ordering::SeqCst) - { - let _ = sender.send(JavascriptTcpSocketEvent::Close { had_error: false }); - push_socket_event(&event_pusher, "close"); - } - break; - } - Ok(bytes_read) => { - if sender - .send(JavascriptTcpSocketEvent::Data( - buffer[..bytes_read].to_vec(), - )) - .is_err() - { - break; - } - push_socket_event(&event_pusher, "data"); - } - Err(error) - if matches!( - error.kind(), - std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut - ) => - { - // The TLS reader and writer share one rustls stream mutex. Yield after - // timed-out reads so request writes can acquire the lock promptly. - std::thread::sleep(Duration::from_millis(1)); - continue; - } - Err(error) if error.kind() == std::io::ErrorKind::UnexpectedEof => { - if let Some(pending_write) = loopback_pending_write.as_ref() { - pending_write.fail_if_pending( - "loopback TLS peer closed before buffered writes flushed", - ); - } - saw_remote_end.store(true, Ordering::SeqCst); - let _ = sender.send(JavascriptTcpSocketEvent::End); - push_socket_event(&event_pusher, "end"); - if saw_local_shutdown.load(Ordering::SeqCst) - && !close_notified.swap(true, Ordering::SeqCst) - { - let _ = sender.send(JavascriptTcpSocketEvent::Close { had_error: false }); - push_socket_event(&event_pusher, "close"); - } - break; - } - Err(error) => { - if let Some(pending_write) = loopback_pending_write.as_ref() { - pending_write.mark_failed(format!( - "loopback TLS reader failed before buffered writes flushed: {error}" - )); - } - let code = io_error_code(&error); - let _ = sender.send(JavascriptTcpSocketEvent::Error { - code, - message: error.to_string(), - }); - push_socket_event(&event_pusher, "error"); - if !close_notified.swap(true, Ordering::SeqCst) { - let _ = sender.send(JavascriptTcpSocketEvent::Close { had_error: true }); - push_socket_event(&event_pusher, "close"); - } - break; - } - } - } - }); -} - -fn spawn_unix_socket_reader( - stream: UnixStream, - sender: Sender, - event_pusher: Arc>>, - saw_local_shutdown: Arc, - saw_remote_end: Arc, - close_notified: Arc, -) { - thread::spawn(move || { - let mut stream = stream; - let mut buffer = vec![0_u8; 64 * 1024]; - loop { - match stream.read(&mut buffer) { - Ok(0) => { - saw_remote_end.store(true, Ordering::SeqCst); - let _ = sender.send(JavascriptTcpSocketEvent::End); - push_socket_event(&event_pusher, "end"); - if saw_local_shutdown.load(Ordering::SeqCst) - && !close_notified.swap(true, Ordering::SeqCst) - { - let _ = sender.send(JavascriptTcpSocketEvent::Close { had_error: false }); - push_socket_event(&event_pusher, "close"); - } - break; - } - Ok(bytes_read) => { - if sender - .send(JavascriptTcpSocketEvent::Data( - buffer[..bytes_read].to_vec(), - )) - .is_err() - { - break; - } - push_socket_event(&event_pusher, "data"); - } - Err(error) => { - let code = io_error_code(&error); - let _ = sender.send(JavascriptTcpSocketEvent::Error { - code, - message: error.to_string(), - }); - push_socket_event(&event_pusher, "error"); - if !close_notified.swap(true, Ordering::SeqCst) { - let _ = sender.send(JavascriptTcpSocketEvent::Close { had_error: true }); - push_socket_event(&event_pusher, "close"); - } - break; - } - } - } - }); -} - -/// Unblock a guest thread parked in a deferred `__kernel_stdin_read` / -/// `__kernel_poll` sync RPC. Isolate termination cannot interrupt the native -/// bridge wait, so teardown must answer the parked RPC BEFORE dropping the -/// execution (drop joins the guest thread) or cleanup deadlocks against it. -fn flush_parked_kernel_wait_rpc(process: &mut ActiveProcess) { - if let Some((request, _)) = process.deferred_kernel_wait_rpc.take() { - let _ = process - .execution - .respond_javascript_sync_rpc_error(request.id, "EINTR", "process teardown") - .or_else(ignore_stale_javascript_sync_rpc_response); - } -} - -fn terminate_child_process_tree( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - kernel_readiness: &KernelSocketReadinessRegistry, -) { - flush_parked_kernel_wait_rpc(process); - let sqlite_database_ids = process.sqlite_databases.keys().copied().collect::>(); - for database_id in sqlite_database_ids { - let _ = close_sqlite_database(kernel, process, database_id); - } - process.sqlite_statements.clear(); - process.http_servers.clear(); - process.pending_http_requests.clear(); - if let Ok(mut http2) = process.http2.shared.lock() { - let sessions = http2.sessions.values().cloned().collect::>(); - http2.server_events.clear(); - http2.session_events.clear(); - http2.streams.clear(); - http2.servers.clear(); - http2.sessions.clear(); - http2.event_session = None; - drop(http2); - for session in sessions { - let (respond_to, _rx) = mpsc::channel(); - let _ = session.command_tx.send(Http2SessionCommand::Close { - abrupt: true, - respond_to, - }); - } - } - - let listener_ids = process.tcp_listeners.keys().cloned().collect::>(); - for listener_id in listener_ids { - if let Some(listener) = process.tcp_listeners.remove(&listener_id) { - unregister_kernel_readiness_target(kernel_readiness, listener.kernel_socket_id); - let _ = listener.close(kernel, process.kernel_pid); - } - } - - let sockets = process.tcp_sockets.keys().cloned().collect::>(); - for socket_id in sockets { - if let Some(socket) = process.tcp_sockets.remove(&socket_id) { - unregister_kernel_readiness_target(kernel_readiness, socket.kernel_socket_id); - let _ = socket.close(kernel, process.kernel_pid); - } - } - - let unix_listener_ids = process.unix_listeners.keys().cloned().collect::>(); - for listener_id in unix_listener_ids { - if let Some(listener) = process.unix_listeners.remove(&listener_id) { - let _ = listener.close(); - } - } - - let unix_sockets = process.unix_sockets.keys().cloned().collect::>(); - for socket_id in unix_sockets { - if let Some(socket) = process.unix_sockets.remove(&socket_id) { - let _ = socket.close(); - } - } - - let udp_socket_ids = process.udp_sockets.keys().cloned().collect::>(); - for socket_id in udp_socket_ids { - if let Some(mut socket) = process.udp_sockets.remove(&socket_id) { - unregister_kernel_readiness_target(kernel_readiness, socket.kernel_socket_id); - socket.close(kernel, process.kernel_pid); - } - } - - let child_ids = process.child_processes.keys().cloned().collect::>(); - for child_id in child_ids { - let Some(mut child) = process.child_processes.remove(&child_id) else { - continue; - }; - terminate_child_process_tree(kernel, &mut child, kernel_readiness); - let _ = kernel.kill_process(EXECUTION_DRIVER_NAME, child.kernel_pid, SIGTERM); - let _ = signal_runtime_process(child.execution.child_pid(), SIGTERM); - child.kernel_handle.finish(0); - let _ = kernel.wait_and_reap(child.kernel_pid); - } -} - -fn service_javascript_sqlite_sync_rpc( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - match request.method.as_str() { - "sqlite.constants" => Ok(json!({})), - "sqlite.open" => sqlite_open_database(kernel, process, request), - "sqlite.close" => { - let database_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.close database id")?; - close_sqlite_database(kernel, process, database_id)?; - Ok(Value::Null) - } - "sqlite.exec" => sqlite_exec_database(kernel, process, request), - "sqlite.query" => sqlite_query_database(process, request), - "sqlite.prepare" => sqlite_prepare_statement(process, request), - "sqlite.location" => { - let database_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.location database id")?; - let database = sqlite_database(process, database_id)?; - Ok(database - .vm_path - .as_ref() - .map(|path| Value::String(path.clone())) - .unwrap_or(Value::Null)) - } - "sqlite.checkpoint" => { - let database_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.checkpoint database id")?; - let kernel_pid = process.kernel_pid; - let database = sqlite_database_mut(process, database_id)?; - sqlite_sync_database(kernel, kernel_pid, database)?; - Ok(Value::Null) - } - "sqlite.statement.run" => sqlite_run_statement(kernel, process, request), - "sqlite.statement.get" => sqlite_get_statement(process, request), - "sqlite.statement.all" | "sqlite.statement.iterate" => { - sqlite_all_statement(process, request) - } - "sqlite.statement.columns" => sqlite_statement_columns(process, request), - "sqlite.statement.setReturnArrays" => { - let statement_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "sqlite.statement.setReturnArrays statement id", - )?; - let enabled = javascript_sync_rpc_arg_bool( - &request.args, - 1, - "sqlite.statement.setReturnArrays enabled", - )?; - sqlite_statement_mut(process, statement_id)?.return_arrays = enabled; - Ok(Value::Null) - } - "sqlite.statement.setReadBigInts" => { - let statement_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "sqlite.statement.setReadBigInts statement id", - )?; - let enabled = javascript_sync_rpc_arg_bool( - &request.args, - 1, - "sqlite.statement.setReadBigInts enabled", - )?; - sqlite_statement_mut(process, statement_id)?.read_bigints = enabled; - Ok(Value::Null) - } - "sqlite.statement.setAllowBareNamedParameters" => { - let statement_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "sqlite.statement.setAllowBareNamedParameters statement id", - )?; - let enabled = javascript_sync_rpc_arg_bool( - &request.args, - 1, - "sqlite.statement.setAllowBareNamedParameters enabled", - )?; - sqlite_statement_mut(process, statement_id)?.allow_bare_named_parameters = enabled; - Ok(Value::Null) - } - "sqlite.statement.setAllowUnknownNamedParameters" => { - let statement_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "sqlite.statement.setAllowUnknownNamedParameters statement id", - )?; - let enabled = javascript_sync_rpc_arg_bool( - &request.args, - 1, - "sqlite.statement.setAllowUnknownNamedParameters enabled", - )?; - sqlite_statement_mut(process, statement_id)?.allow_unknown_named_parameters = enabled; - Ok(Value::Null) - } - "sqlite.statement.finalize" => { - let statement_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "sqlite.statement.finalize statement id", - )?; - process - .sqlite_statements - .remove(&statement_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "sqlite statement handle not found: {statement_id}" - )) - })?; - Ok(Value::Null) - } - other => Err(SidecarError::InvalidState(format!( - "unsupported JavaScript sqlite sync RPC method {other}" - ))), - } -} - -fn sqlite_open_database( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - ensure_per_process_state_handle_capacity(process.sqlite_databases.len(), "sqlite database")?; - let path = request.args.first().and_then(Value::as_str); - let vm_path = path.filter(|value| !value.is_empty() && *value != ":memory:"); - let options = request.args.get(1); - let read_only = sqlite_option_bool(options, "readOnly").unwrap_or(false); - let create = sqlite_option_bool(options, "create").unwrap_or(!read_only); - let timeout_ms = sqlite_option_u64(options, "timeout"); - - process.next_sqlite_database_id += 1; - let database_id = process.next_sqlite_database_id; - - let host_path = if vm_path.is_some() { - Some( - std::env::temp_dir() - .join(format!( - "secure-exec-sidecar-sqlite-{}-{database_id}", - process.kernel_pid - )) - .join("database.sqlite"), - ) - } else { - None - }; - - if let Some(host_path) = host_path.as_ref() { - if let Some(parent) = host_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!( - "failed to prepare sqlite temp directory {}: {error}", - parent.display() - )) - })?; - } - } - - if let (Some(vm_path), Some(host_path)) = (vm_path, host_path.as_ref()) { - if kernel - .exists_for_process(EXECUTION_DRIVER_NAME, process.kernel_pid, vm_path) - .map_err(kernel_error)? - { - let contents = kernel - .read_file_for_process(EXECUTION_DRIVER_NAME, process.kernel_pid, vm_path) - .map_err(kernel_error)?; - fs::write(host_path, contents).map_err(|error| { - SidecarError::Io(format!( - "failed to materialize sqlite database {}: {error}", - host_path.display() - )) - })?; - } else if read_only && !create { - return Err(SidecarError::InvalidState(format!( - "sqlite database does not exist: {vm_path}" - ))); - } - } - - let target = host_path - .as_ref() - .map(|path| path.to_string_lossy().into_owned()) - .unwrap_or_else(|| String::from(":memory:")); - let mut flags = if read_only { - SqliteOpenFlags::SQLITE_OPEN_READ_ONLY - } else { - SqliteOpenFlags::SQLITE_OPEN_READ_WRITE - }; - if create && !read_only { - flags |= SqliteOpenFlags::SQLITE_OPEN_CREATE; - } - - let connection = SqliteConnection::open_with_flags(&target, flags).map_err(|error| { - SidecarError::InvalidState(format!( - "sqlite database open failed for {}: {error}", - vm_path.unwrap_or(":memory:") - )) - })?; - if let Some(timeout_ms) = timeout_ms { - connection - .busy_timeout(Duration::from_millis(timeout_ms)) - .map_err(sqlite_error)?; - } - if host_path.is_some() && !read_only { - let _ = connection.pragma_update(None, "journal_mode", "WAL"); - } - - process.sqlite_databases.insert( - database_id, - ActiveSqliteDatabase { - connection, - host_path, - vm_path: vm_path.map(String::from), - dirty: false, - transaction_depth: 0, - read_only, - }, - ); - - Ok(json!(database_id)) -} - -fn sqlite_exec_database( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let database_id = javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.exec database id")?; - let sql = javascript_sync_rpc_arg_str(&request.args, 1, "sqlite.exec sql")?; - let kernel_pid = process.kernel_pid; - let database = sqlite_database_mut(process, database_id)?; - let before = database.connection.total_changes(); - database - .connection - .execute_batch(sql) - .map_err(sqlite_error)?; - mark_sqlite_mutation(database, sql); - sqlite_sync_database(kernel, kernel_pid, database)?; - Ok(json!(database - .connection - .total_changes() - .saturating_sub(before))) -} - -fn sqlite_query_database( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let database_id = javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.query database id")?; - let sql = javascript_sync_rpc_arg_str(&request.args, 1, "sqlite.query sql")?; - let params = request.args.get(2); - let options = request.args.get(3); - let return_arrays = sqlite_option_bool(options, "returnArrays").unwrap_or(false); - let read_bigints = sqlite_option_bool(options, "readBigInts").unwrap_or(false); - let database = sqlite_database_mut(process, database_id)?; - sqlite_query_rows( - &mut database.connection, - sql, - params, - return_arrays, - read_bigints, - true, - false, - ) -} - -fn sqlite_prepare_statement( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - ensure_per_process_state_handle_capacity(process.sqlite_statements.len(), "sqlite statement")?; - let database_id = javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.prepare database id")?; - let sql = javascript_sync_rpc_arg_str(&request.args, 1, "sqlite.prepare sql")?; - let _ = sqlite_database(process, database_id)?; - process.next_sqlite_statement_id += 1; - let statement_id = process.next_sqlite_statement_id; - process.sqlite_statements.insert( - statement_id, - ActiveSqliteStatement { - database_id, - sql: sql.to_owned(), - return_arrays: false, - read_bigints: false, - allow_bare_named_parameters: false, - allow_unknown_named_parameters: false, - }, - ); - Ok(json!(statement_id)) -} - -fn sqlite_run_statement( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let statement_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.statement.run statement id")?; - let params = request.args.get(1); - let statement_state = sqlite_statement(process, statement_id)?.clone(); - let kernel_pid = process.kernel_pid; - let database = sqlite_database_mut(process, statement_state.database_id)?; - let before = database.connection.total_changes(); - { - let mut statement = database - .connection - .prepare(&statement_state.sql) - .map_err(sqlite_error)?; - bind_sqlite_parameters( - &mut statement, - params, - statement_state.allow_bare_named_parameters, - statement_state.allow_unknown_named_parameters, - )?; - statement.raw_execute().map_err(sqlite_error)?; - } - let changes = database.connection.total_changes().saturating_sub(before); - let last_insert_rowid = database.connection.last_insert_rowid(); - mark_sqlite_mutation(database, &statement_state.sql); - sqlite_sync_database(kernel, kernel_pid, database)?; - let result = json!({ - "changes": changes, - "lastInsertRowid": encode_sqlite_integer(last_insert_rowid, true), - }); - Ok(result) -} - -fn sqlite_get_statement( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let statement_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.statement.get statement id")?; - let params = request.args.get(1); - let statement_state = sqlite_statement(process, statement_id)?.clone(); - let database = sqlite_database_mut(process, statement_state.database_id)?; - let rows = sqlite_query_rows( - &mut database.connection, - &statement_state.sql, - params, - statement_state.return_arrays, - statement_state.read_bigints, - statement_state.allow_bare_named_parameters, - statement_state.allow_unknown_named_parameters, - )?; - Ok(rows - .as_array() - .and_then(|rows| rows.first().cloned()) - .unwrap_or(Value::Null)) -} - -fn sqlite_all_statement( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let statement_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.statement.all statement id")?; - let params = request.args.get(1); - let statement_state = sqlite_statement(process, statement_id)?.clone(); - let database = sqlite_database_mut(process, statement_state.database_id)?; - sqlite_query_rows( - &mut database.connection, - &statement_state.sql, - params, - statement_state.return_arrays, - statement_state.read_bigints, - statement_state.allow_bare_named_parameters, - statement_state.allow_unknown_named_parameters, - ) -} - -fn sqlite_statement_columns( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let statement_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "sqlite.statement.columns statement id")?; - let statement_state = sqlite_statement(process, statement_id)?.clone(); - let database = sqlite_database_mut(process, statement_state.database_id)?; - let statement = database - .connection - .prepare(&statement_state.sql) - .map_err(sqlite_error)?; - Ok(Value::Array( - statement - .column_names() - .iter() - .map(|name| json!({ "name": name })) - .collect(), - )) -} - -fn sqlite_query_rows( - connection: &mut SqliteConnection, - sql: &str, - params: Option<&Value>, - return_arrays: bool, - read_bigints: bool, - allow_bare_named_parameters: bool, - allow_unknown_named_parameters: bool, -) -> Result { - let mut statement = connection.prepare(sql).map_err(sqlite_error)?; - let column_names = statement - .column_names() - .iter() - .map(|name| (*name).to_owned()) - .collect::>(); - let column_count = statement.column_count(); - bind_sqlite_parameters( - &mut statement, - params, - allow_bare_named_parameters, - allow_unknown_named_parameters, - )?; - let mut rows = statement.raw_query(); - let mut encoded_rows = Vec::new(); - while let Some(row) = rows.next().map_err(sqlite_error)? { - encoded_rows.push(encode_sqlite_row( - row, - &column_names, - column_count, - return_arrays, - read_bigints, - )?); - } - Ok(Value::Array(encoded_rows)) -} - -fn encode_sqlite_row( - row: &rusqlite::Row<'_>, - column_names: &[String], - column_count: usize, - return_arrays: bool, - read_bigints: bool, -) -> Result { - if return_arrays { - let mut values = Vec::with_capacity(column_count); - for index in 0..column_count { - values.push(encode_sqlite_value_ref( - row.get_ref(index).map_err(sqlite_error)?, - read_bigints, - )?); - } - return Ok(Value::Array(values)); - } - - let mut object = Map::with_capacity(column_count); - for (index, name) in column_names.iter().enumerate() { - object.insert( - name.clone(), - encode_sqlite_value_ref(row.get_ref(index).map_err(sqlite_error)?, read_bigints)?, - ); - } - Ok(Value::Object(object)) -} - -fn encode_sqlite_value_ref( - value: SqliteValueRef<'_>, - read_bigints: bool, -) -> Result { - Ok(match value { - SqliteValueRef::Null => Value::Null, - SqliteValueRef::Integer(number) => encode_sqlite_integer(number, read_bigints), - SqliteValueRef::Real(number) => json!(number), - SqliteValueRef::Text(text) => Value::String(String::from_utf8_lossy(text).into_owned()), - SqliteValueRef::Blob(bytes) => json!({ - "__agentosSqliteType": "uint8array", - "value": base64::engine::general_purpose::STANDARD.encode(bytes), - }), - }) -} - -fn encode_sqlite_integer(number: i64, read_bigints: bool) -> Value { - if read_bigints || number.abs() > SQLITE_JS_SAFE_INTEGER_MAX { - json!({ - "__agentosSqliteType": "bigint", - "value": number.to_string(), - }) - } else { - json!(number) - } -} - -fn bind_sqlite_parameters( - statement: &mut SqliteStatement<'_>, - params: Option<&Value>, - allow_bare_named_parameters: bool, - allow_unknown_named_parameters: bool, -) -> Result<(), SidecarError> { - let Some(params) = params else { - return Ok(()); - }; - match params { - Value::Null => Ok(()), - Value::Array(values) => { - for (index, value) in values.iter().enumerate() { - statement - .raw_bind_parameter(index + 1, decode_sqlite_parameter(value)?) - .map_err(sqlite_error)?; - } - Ok(()) - } - Value::Object(map) - if map - .get("__agentosSqliteType") - .and_then(Value::as_str) - .is_none() => - { - for (key, value) in map { - let index = - resolve_sqlite_parameter_index(statement, key, allow_bare_named_parameters)?; - let Some(index) = index else { - if allow_unknown_named_parameters { - continue; - } - return Err(SidecarError::InvalidState(format!( - "sqlite named parameter not found: {key}" - ))); - }; - statement - .raw_bind_parameter(index, decode_sqlite_parameter(value)?) - .map_err(sqlite_error)?; - } - Ok(()) - } - other => statement - .raw_bind_parameter(1, decode_sqlite_parameter(other)?) - .map_err(sqlite_error), - } -} - -fn resolve_sqlite_parameter_index( - statement: &mut SqliteStatement<'_>, - key: &str, - allow_bare_named_parameters: bool, -) -> Result, SidecarError> { - let mut candidates = vec![key.to_owned()]; - if allow_bare_named_parameters - && !key.starts_with(':') - && !key.starts_with('@') - && !key.starts_with('$') - { - candidates.push(format!(":{key}")); - candidates.push(format!("@{key}")); - candidates.push(format!("${key}")); - } - for candidate in candidates { - if let Some(index) = statement - .parameter_index(&candidate) - .map_err(sqlite_error)? - { - return Ok(Some(index)); - } - } - Ok(None) -} - -fn decode_sqlite_parameter(value: &Value) -> Result { - Ok(match value { - Value::Null => rusqlite::types::Value::Null, - Value::Bool(value) => rusqlite::types::Value::Integer(i64::from(*value)), - Value::Number(value) => match (value.as_i64(), value.as_f64()) { - (Some(integer), _) => rusqlite::types::Value::Integer(integer), - (_, Some(real)) => rusqlite::types::Value::Real(real), - _ => { - return Err(SidecarError::InvalidState(String::from( - "sqlite parameter number is not representable", - ))); - } - }, - Value::String(value) => rusqlite::types::Value::Text(value.clone()), - Value::Array(_) => { - return Err(SidecarError::InvalidState(String::from( - "sqlite parameters do not support nested arrays", - ))); - } - Value::Object(map) => match map.get("__agentosSqliteType").and_then(Value::as_str) { - Some("bigint") => rusqlite::types::Value::Integer( - map.get("value") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "sqlite bigint parameter missing string value", - )) - })? - .parse::() - .map_err(|error| { - SidecarError::InvalidState(format!( - "sqlite bigint parameter is not a signed 64-bit integer: {error}" - )) - })?, - ), - Some("uint8array") => rusqlite::types::Value::Blob( - base64::engine::general_purpose::STANDARD - .decode(map.get("value").and_then(Value::as_str).ok_or_else(|| { - SidecarError::InvalidState(String::from( - "sqlite blob parameter missing base64 value", - )) - })?) - .map_err(|error| { - SidecarError::InvalidState(format!( - "sqlite blob parameter contains invalid base64: {error}" - )) - })?, - ), - Some(other) => { - return Err(SidecarError::InvalidState(format!( - "unsupported sqlite tagged parameter type {other}" - ))); - } - None => { - return Err(SidecarError::InvalidState(String::from( - "sqlite named parameter objects must be passed as the top-level params object", - ))); - } - }, - }) -} - -fn close_sqlite_database( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - database_id: u64, -) -> Result<(), SidecarError> { - let mut database = process - .sqlite_databases - .remove(&database_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!("sqlite database handle not found: {database_id}")) - })?; - process - .sqlite_statements - .retain(|_, statement| statement.database_id != database_id); - sqlite_sync_database(kernel, process.kernel_pid, &mut database)?; - let host_path = database.host_path.clone(); - drop(database); - cleanup_sqlite_host_artifacts(host_path.as_deref())?; - Ok(()) -} - -fn ensure_per_process_state_handle_capacity(len: usize, label: &str) -> Result<(), SidecarError> { - if len >= MAX_PER_PROCESS_STATE_HANDLES { - return Err(SidecarError::InvalidState(format!( - "{label} handle limit exceeded: limit is {MAX_PER_PROCESS_STATE_HANDLES}" - ))); - } - Ok(()) -} - -fn sqlite_sync_database( - kernel: &mut SidecarKernel, - kernel_pid: u32, - database: &mut ActiveSqliteDatabase, -) -> Result<(), SidecarError> { - if !database.dirty - || database.transaction_depth > 0 - || database.read_only - || database.host_path.is_none() - || database.vm_path.is_none() - { - return Ok(()); - } - - let _ = database - .connection - .execute_batch("PRAGMA wal_checkpoint(TRUNCATE)"); - let host_path = database.host_path.as_ref().expect("sqlite host path"); - if !host_path.exists() { - return Ok(()); - } - ensure_vm_parent_dir( - kernel, - kernel_pid, - database.vm_path.as_deref().expect("sqlite vm path"), - )?; - let contents = fs::read(host_path).map_err(|error| { - SidecarError::Io(format!( - "failed to read sqlite temp database {}: {error}", - host_path.display() - )) - })?; - kernel - .write_file_for_process( - EXECUTION_DRIVER_NAME, - kernel_pid, - database.vm_path.as_deref().expect("sqlite vm path"), - contents, - None, - ) - .map_err(kernel_error)?; - database.dirty = false; - Ok(()) -} - -fn cleanup_sqlite_host_artifacts(host_path: Option<&Path>) -> Result<(), SidecarError> { - let Some(host_path) = host_path else { - return Ok(()); - }; - let parent = host_path.parent().map(PathBuf::from); - for suffix in ["", "-wal", "-shm"] { - let path = PathBuf::from(format!("{}{}", host_path.display(), suffix)); - if path.exists() { - fs::remove_file(&path).map_err(|error| { - SidecarError::Io(format!( - "failed to remove sqlite temp artifact {}: {error}", - path.display() - )) - })?; - } - } - if let Some(parent) = parent { - let _ = fs::remove_dir_all(parent); - } - Ok(()) -} - -fn ensure_vm_parent_dir( - kernel: &mut SidecarKernel, - kernel_pid: u32, - path: &str, -) -> Result<(), SidecarError> { - let parent = dirname(path); - if parent == "/" || parent == "." { - return Ok(()); - } - let mut current = String::new(); - for segment in parent.split('/').filter(|segment| !segment.is_empty()) { - current.push('/'); - current.push_str(segment); - if !kernel - .exists_for_process(EXECUTION_DRIVER_NAME, kernel_pid, ¤t) - .map_err(kernel_error)? - { - kernel - .mkdir_for_process(EXECUTION_DRIVER_NAME, kernel_pid, ¤t, false, None) - .map_err(kernel_error)?; - } - } - Ok(()) -} - -fn sqlite_database( - process: &ActiveProcess, - database_id: u64, -) -> Result<&ActiveSqliteDatabase, SidecarError> { - process.sqlite_databases.get(&database_id).ok_or_else(|| { - SidecarError::InvalidState(format!("sqlite database handle not found: {database_id}")) - }) -} - -fn sqlite_database_mut( - process: &mut ActiveProcess, - database_id: u64, -) -> Result<&mut ActiveSqliteDatabase, SidecarError> { - process - .sqlite_databases - .get_mut(&database_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!("sqlite database handle not found: {database_id}")) - }) -} - -fn sqlite_statement( - process: &ActiveProcess, - statement_id: u64, -) -> Result<&ActiveSqliteStatement, SidecarError> { - process.sqlite_statements.get(&statement_id).ok_or_else(|| { - SidecarError::InvalidState(format!("sqlite statement handle not found: {statement_id}")) - }) -} - -fn sqlite_statement_mut( - process: &mut ActiveProcess, - statement_id: u64, -) -> Result<&mut ActiveSqliteStatement, SidecarError> { - process - .sqlite_statements - .get_mut(&statement_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!("sqlite statement handle not found: {statement_id}")) - }) -} - -fn mark_sqlite_mutation(database: &mut ActiveSqliteDatabase, sql: &str) { - let normalized = sql.trim_start().to_ascii_lowercase(); - if normalized.starts_with("begin") || normalized.starts_with("savepoint") { - database.dirty = true; - database.transaction_depth += 1; - return; - } - if normalized.starts_with("commit") || normalized.starts_with("release savepoint") { - database.dirty = true; - database.transaction_depth = database.transaction_depth.saturating_sub(1); - return; - } - if normalized.starts_with("rollback") && !normalized.starts_with("rollback to") { - database.dirty = true; - database.transaction_depth = database.transaction_depth.saturating_sub(1); - return; - } - if normalized.starts_with("insert") - || normalized.starts_with("update") - || normalized.starts_with("delete") - || normalized.starts_with("replace") - || normalized.starts_with("create") - || normalized.starts_with("alter") - || normalized.starts_with("drop") - || normalized.starts_with("vacuum") - || normalized.starts_with("reindex") - || normalized.starts_with("analyze") - || normalized.starts_with("attach") - || normalized.starts_with("detach") - || normalized.starts_with("pragma") - { - database.dirty = true; - } -} - -fn sqlite_option_bool(options: Option<&Value>, key: &str) -> Option { - options - .and_then(|value| value.get(key)) - .and_then(Value::as_bool) -} - -fn sqlite_option_u64(options: Option<&Value>, key: &str) -> Option { - options - .and_then(|value| value.get(key)) - .and_then(Value::as_u64) -} - -fn sqlite_error(error: rusqlite::Error) -> SidecarError { - SidecarError::InvalidState(format!("sqlite error: {error}")) -} - -pub(crate) fn javascript_sync_rpc_arg_str<'a>( - args: &'a [Value], - index: usize, - label: &str, -) -> Result<&'a str, SidecarError> { - args.get(index) - .and_then(Value::as_str) - .ok_or_else(|| SidecarError::InvalidState(format!("{label} must be a string argument"))) -} - -pub(crate) fn javascript_sync_rpc_arg_bool( - args: &[Value], - index: usize, - label: &str, -) -> Result { - args.get(index) - .and_then(Value::as_bool) - .ok_or_else(|| SidecarError::InvalidState(format!("{label} must be a boolean argument"))) -} - -pub(crate) fn javascript_sync_rpc_encoding(args: &[Value]) -> Option { - args.get(1).and_then(|value| { - value.as_str().map(str::to_owned).or_else(|| { - value - .get("encoding") - .and_then(Value::as_str) - .map(str::to_owned) - }) - }) -} - -pub(crate) fn javascript_sync_rpc_option_bool( - args: &[Value], - index: usize, - key: &str, -) -> Option { - let value = args.get(index)?; - if key == "recursive" { - if let Some(boolean) = value.as_bool() { - return Some(boolean); - } - } - value.get(key).and_then(Value::as_bool) -} - -pub(crate) fn javascript_sync_rpc_option_u32( - args: &[Value], - index: usize, - key: &str, -) -> Result, SidecarError> { - let Some(value) = args.get(index).and_then(|value| { - if value.is_object() { - value.get(key) - } else if key == "mode" && value.is_number() { - Some(value) - } else { - None - } - }) else { - return Ok(None); - }; - if value.is_null() { - return Ok(None); - } - - let numeric = value - .as_u64() - .or_else(|| { - value - .as_f64() - .filter(|number| number.is_finite() && *number >= 0.0) - .map(|number| number as u64) - }) - .ok_or_else(|| SidecarError::InvalidState(format!("{key} must be numeric")))?; - - u32::try_from(numeric) - .map(Some) - .map_err(|_| SidecarError::InvalidState(format!("{key} must fit within u32"))) -} - -pub(crate) fn javascript_sync_rpc_arg_u32( - args: &[Value], - index: usize, - label: &str, -) -> Result { - let value = javascript_sync_rpc_arg_u64(args, index, label)?; - u32::try_from(value) - .map_err(|_| SidecarError::InvalidState(format!("{label} must fit within u32"))) -} - -pub(crate) fn javascript_sync_rpc_arg_i32( - args: &[Value], - index: usize, - label: &str, -) -> Result { - let Some(value) = args.get(index) else { - return Err(SidecarError::InvalidState(format!("{label} is required"))); - }; - - let numeric = value - .as_i64() - .or_else(|| { - value - .as_f64() - .filter(|number| number.is_finite()) - .map(|number| number as i64) - }) - .ok_or_else(|| SidecarError::InvalidState(format!("{label} must be a numeric argument")))?; - - i32::try_from(numeric) - .map_err(|_| SidecarError::InvalidState(format!("{label} must fit within i32"))) -} - -pub(crate) fn javascript_sync_rpc_arg_u32_optional( - args: &[Value], - index: usize, - label: &str, -) -> Result, SidecarError> { - javascript_sync_rpc_arg_u64_optional(args, index, label)? - .map(|value| { - u32::try_from(value) - .map_err(|_| SidecarError::InvalidState(format!("{label} must fit within u32"))) - }) - .transpose() -} - -pub(crate) fn javascript_sync_rpc_arg_u64( - args: &[Value], - index: usize, - label: &str, -) -> Result { - let Some(value) = args.get(index) else { - return Err(SidecarError::InvalidState(format!("{label} is required"))); - }; - - value - .as_u64() - .or_else(|| { - value - .as_f64() - .filter(|number| number.is_finite() && *number >= 0.0) - .map(|number| number as u64) - }) - .ok_or_else(|| SidecarError::InvalidState(format!("{label} must be a numeric argument"))) -} - -pub(crate) fn javascript_sync_rpc_arg_u64_optional( - args: &[Value], - index: usize, - label: &str, -) -> Result, SidecarError> { - let Some(value) = args.get(index) else { - return Ok(None); - }; - if value.is_null() { - return Ok(None); - } - javascript_sync_rpc_arg_u64(args, index, label).map(Some) -} - -pub(crate) fn javascript_sync_rpc_bytes_arg( - args: &[Value], - index: usize, - label: &str, -) -> Result, SidecarError> { - let Some(value) = args.get(index) else { - return Err(SidecarError::InvalidState(format!("{label} is required"))); - }; - - if let Some(text) = value.as_str() { - return Ok(text.as_bytes().to_vec()); - } - - decode_encoded_bytes_value(value) - .map_err(|error| SidecarError::InvalidState(format!("{label} {error}"))) -} - -pub(crate) fn javascript_sync_rpc_bytes_value(bytes: &[u8]) -> Value { - encoded_bytes_value(bytes) -} - -#[derive(Debug, Deserialize)] -pub(crate) struct KernelPollFdRequest { - fd: u32, - events: u16, -} - -#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] -struct KernelPollFdResponse { - fd: u32, - events: u16, - revents: u16, -} - -fn javascript_sync_rpc_base64_arg( - args: &[Value], - index: usize, - label: &str, -) -> Result, SidecarError> { - let value = javascript_sync_rpc_arg_str(args, index, label)?; - decode_base64(value).map_err(|error| SidecarError::InvalidState(format!("{label} {error}"))) -} - -// ── Sync-RPC round-trip counting (opt-in via AGENTOS_SYNC_RPC_TRACE=1) ── -// Each guest fs/module/net sync RPC funnels through service_javascript_sync_rpc, -// so this is the one place to measure the kernel-VFS "syscall storm" that makes -// metadata-heavy phases (resourceLoader.reload, createAgentSession) 40-90x slower -// in the VM than on bare node. Emits a perf log line every 200 calls with the -// running per-method breakdown. -static SYNC_RPC_STATS: std::sync::OnceLock< - std::sync::Mutex>, -> = std::sync::OnceLock::new(); - -#[derive(Default)] -struct ExecutePhaseStats { - calls: u64, - total_ns: u128, - max_ns: u128, -} - -static EXECUTE_PHASES: OnceLock>> = OnceLock::new(); -static EXECUTE_LIFETIMES: OnceLock>> = OnceLock::new(); -static EXECUTE_EXIT_EVENT_QUEUED: OnceLock>> = OnceLock::new(); - -fn execute_phases_enabled() -> bool { - std::env::var("AGENTOS_EXECUTE_PHASES").as_deref() == Ok("1") -} - -fn execute_phase_key(vm_id: &str, process_id: &str) -> String { - format!("{vm_id}/{process_id}") -} - -pub(crate) fn record_execute_phase(stage: &str, elapsed: Duration) { - if !execute_phases_enabled() { - return; - } - let phases = EXECUTE_PHASES.get_or_init(|| Mutex::new(BTreeMap::new())); - let Ok(mut phases) = phases.lock() else { - return; - }; - let stats = phases.entry(stage.to_string()).or_default(); - stats.calls += 1; - let elapsed_ns = elapsed.as_nanos(); - stats.total_ns += elapsed_ns; - stats.max_ns = stats.max_ns.max(elapsed_ns); - - let Some(path) = std::env::var_os("AGENTOS_EXECUTE_PHASES_FILE") else { - return; - }; - let mut output = String::new(); - for (stage, stats) in phases.iter() { - let total_us = stats.total_ns / 1_000; - let avg_us = if stats.calls == 0 { - 0 - } else { - total_us / u128::from(stats.calls) - }; - let max_us = stats.max_ns / 1_000; - output.push_str(&format!( - "stage={stage} calls={} total_us={total_us} avg_us={avg_us} max_us={max_us}\n", - stats.calls - )); - } - let _ = fs::write(path, output); -} - -fn mark_execute_response_ready(vm_id: &str, process_id: &str) { - if !execute_phases_enabled() { - return; - } - let lifetimes = EXECUTE_LIFETIMES.get_or_init(|| Mutex::new(BTreeMap::new())); - if let Ok(mut lifetimes) = lifetimes.lock() { - lifetimes.insert(execute_phase_key(vm_id, process_id), Instant::now()); - } -} - -pub(crate) fn mark_execute_exit_event_queued(vm_id: &str, process_id: &str) { - if !execute_phases_enabled() { - return; - } - let queued = EXECUTE_EXIT_EVENT_QUEUED.get_or_init(|| Mutex::new(BTreeMap::new())); - if let Ok(mut queued) = queued.lock() { - let key = execute_phase_key(vm_id, process_id); - if let std::collections::btree_map::Entry::Vacant(entry) = queued.entry(key) { - record_execute_response_to_exit_milestone( - "execute_response_to_exit_event_queued", - vm_id, - process_id, - ); - entry.insert(Instant::now()); - } - } -} - -pub(crate) fn record_execute_exit_event_queue_wait(stage: &str, vm_id: &str, process_id: &str) { - if !execute_phases_enabled() { - return; - } - let Some(queued) = EXECUTE_EXIT_EVENT_QUEUED.get() else { - return; - }; - let Ok(mut queued) = queued.lock() else { - return; - }; - if let Some(started) = queued.remove(&execute_phase_key(vm_id, process_id)) { - record_execute_phase(stage, started.elapsed()); - } -} - -pub(crate) fn record_execute_response_to_exit_milestone( - stage: &str, - vm_id: &str, - process_id: &str, -) { - if !execute_phases_enabled() { - return; - } - let Some(lifetimes) = EXECUTE_LIFETIMES.get() else { - return; - }; - let Ok(lifetimes) = lifetimes.lock() else { - return; - }; - if let Some(started) = lifetimes.get(&execute_phase_key(vm_id, process_id)) { - record_execute_phase(stage, started.elapsed()); - } -} - -fn record_execute_response_to_exit(vm_id: &str, process_id: &str) { - if !execute_phases_enabled() { - return; - } - let Some(lifetimes) = EXECUTE_LIFETIMES.get() else { - return; - }; - let Ok(mut lifetimes) = lifetimes.lock() else { - return; - }; - if let Some(started) = lifetimes.remove(&execute_phase_key(vm_id, process_id)) { - record_execute_phase("execute_response_to_exit_event", started.elapsed()); - } -} - -fn sync_rpc_trace_enabled() -> bool { - std::env::var("AGENTOS_SYNC_RPC_TRACE").as_deref() == Ok("1") -} - -fn record_sync_rpc(method: &str) { - let stats = - SYNC_RPC_STATS.get_or_init(|| std::sync::Mutex::new(std::collections::BTreeMap::new())); - let Ok(mut map) = stats.lock() else { - return; - }; - *map.entry(method.to_string()).or_insert(0) += 1; - let total: u64 = map.values().sum(); - if total == 1 || total.is_multiple_of(50) { - let mut top: Vec<(&String, &u64)> = map.iter().collect(); - top.sort_by(|a, b| b.1.cmp(a.1)); - let breakdown = top - .iter() - .take(8) - .map(|(m, c)| format!("{m}={c}")) - .collect::>() - .join(" "); - tracing::info!(target: "secure_exec_sidecar::perf", total, %breakdown, "sync_rpc count"); - } -} - -fn net_tcp_trace_enabled(env: &BTreeMap) -> bool { - env.get("AGENTOS_NET_BRIDGE_TRACE").map(String::as_str) == Some("1") -} - -fn duration_micros_u64(duration: Duration) -> u64 { - u64::try_from(duration.as_micros()).unwrap_or(u64::MAX) -} - -fn net_tcp_trace_reset() { - reset_socket_read_trace(); - set_socket_read_trace_enabled(true); - for counter in [ - &NET_TCP_TRACE_COUNTERS.socket_read_calls, - &NET_TCP_TRACE_COUNTERS.socket_read_zero_wait_calls, - &NET_TCP_TRACE_COUNTERS.socket_read_data_events, - &NET_TCP_TRACE_COUNTERS.socket_read_bytes, - &NET_TCP_TRACE_COUNTERS.socket_read_kernel_us, - &NET_TCP_TRACE_COUNTERS.socket_read_end_events, - &NET_TCP_TRACE_COUNTERS.socket_read_eagain, - &NET_TCP_TRACE_COUNTERS.socket_read_errors, - &NET_TCP_TRACE_COUNTERS.socket_read_push_attempts, - &NET_TCP_TRACE_COUNTERS.socket_read_push_sent, - &NET_TCP_TRACE_COUNTERS.socket_read_push_missing, - &NET_TCP_TRACE_COUNTERS.socket_read_push_errors, - &NET_TCP_TRACE_COUNTERS.socket_write_calls, - &NET_TCP_TRACE_COUNTERS.socket_write_bytes, - &NET_TCP_TRACE_COUNTERS.socket_write_kernel_us, - &NET_TCP_TRACE_COUNTERS.socket_write_errors, - &NET_TCP_TRACE_COUNTERS.server_accept_calls, - &NET_TCP_TRACE_COUNTERS.server_accept_zero_wait_calls, - &NET_TCP_TRACE_COUNTERS.server_accept_connections, - &NET_TCP_TRACE_COUNTERS.server_accept_eagain, - &NET_TCP_TRACE_COUNTERS.server_accept_errors, - &NET_TCP_TRACE_COUNTERS.kernel_poll_targets, - &NET_TCP_TRACE_COUNTERS.kernel_poll_zero_wait_calls, - &NET_TCP_TRACE_COUNTERS.kernel_poll_wait_us, - &NET_TCP_TRACE_COUNTERS.kernel_poll_elapsed_us, - &NET_TCP_TRACE_COUNTERS.kernel_poll_empty, - &NET_TCP_TRACE_COUNTERS.kernel_poll_ready, - &NET_TCP_TRACE_COUNTERS.kernel_poll_revents_read, - &NET_TCP_TRACE_COUNTERS.kernel_poll_revents_hup, - &NET_TCP_TRACE_COUNTERS.kernel_poll_revents_err, - &NET_TCP_TRACE_COUNTERS.kernel_poll_revents_bits_or, - ] { - counter.store(0, Ordering::Relaxed); - } -} - -fn net_tcp_trace_snapshot() -> Value { - let load = |counter: &AtomicU64| counter.load(Ordering::Relaxed); - let socket_read = socket_read_trace_snapshot(); - json!({ - "socketReadCalls": load(&NET_TCP_TRACE_COUNTERS.socket_read_calls), - "socketReadZeroWaitCalls": load(&NET_TCP_TRACE_COUNTERS.socket_read_zero_wait_calls), - "socketReadDataEvents": load(&NET_TCP_TRACE_COUNTERS.socket_read_data_events), - "socketReadBytes": load(&NET_TCP_TRACE_COUNTERS.socket_read_bytes), - "socketReadKernelUs": load(&NET_TCP_TRACE_COUNTERS.socket_read_kernel_us), - "socketReadRecordCloneCalls": socket_read.socket_record_clone_calls, - "socketReadRecordCloneUs": socket_read.socket_record_clone_us, - "socketReadRecvCalls": socket_read.read_recv_calls, - "socketReadRecvBytes": socket_read.read_recv_bytes, - "socketReadRecvChunks": socket_read.read_recv_chunks, - "socketReadRecvCopyUs": socket_read.read_recv_copy_us, - "socketReadEndEvents": load(&NET_TCP_TRACE_COUNTERS.socket_read_end_events), - "socketReadEagain": load(&NET_TCP_TRACE_COUNTERS.socket_read_eagain), - "socketReadErrors": load(&NET_TCP_TRACE_COUNTERS.socket_read_errors), - "socketReadPushAttempts": load(&NET_TCP_TRACE_COUNTERS.socket_read_push_attempts), - "socketReadPushSent": load(&NET_TCP_TRACE_COUNTERS.socket_read_push_sent), - "socketReadPushMissing": load(&NET_TCP_TRACE_COUNTERS.socket_read_push_missing), - "socketReadPushErrors": load(&NET_TCP_TRACE_COUNTERS.socket_read_push_errors), - "socketWriteCalls": load(&NET_TCP_TRACE_COUNTERS.socket_write_calls), - "socketWriteBytes": load(&NET_TCP_TRACE_COUNTERS.socket_write_bytes), - "socketWriteKernelUs": load(&NET_TCP_TRACE_COUNTERS.socket_write_kernel_us), - "socketWriteErrors": load(&NET_TCP_TRACE_COUNTERS.socket_write_errors), - "serverAcceptCalls": load(&NET_TCP_TRACE_COUNTERS.server_accept_calls), - "serverAcceptZeroWaitCalls": load(&NET_TCP_TRACE_COUNTERS.server_accept_zero_wait_calls), - "serverAcceptConnections": load(&NET_TCP_TRACE_COUNTERS.server_accept_connections), - "serverAcceptEagain": load(&NET_TCP_TRACE_COUNTERS.server_accept_eagain), - "serverAcceptErrors": load(&NET_TCP_TRACE_COUNTERS.server_accept_errors), - "kernelPollTargets": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_targets), - "kernelPollZeroWaitCalls": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_zero_wait_calls), - "kernelPollWaitUs": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_wait_us), - "kernelPollElapsedUs": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_elapsed_us), - "kernelPollEmpty": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_empty), - "kernelPollReady": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_ready), - "kernelPollReventsRead": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_revents_read), - "kernelPollReventsHup": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_revents_hup), - "kernelPollReventsErr": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_revents_err), - "kernelPollReventsBitsOr": load(&NET_TCP_TRACE_COUNTERS.kernel_poll_revents_bits_or), - }) -} - -fn record_net_tcp_kernel_poll( - enabled: bool, - wait: Duration, - elapsed: Duration, - revents: PollEvents, -) { - if !enabled { - return; - } - NET_TCP_TRACE_COUNTERS - .kernel_poll_targets - .fetch_add(1, Ordering::Relaxed); - if wait.is_zero() { - NET_TCP_TRACE_COUNTERS - .kernel_poll_zero_wait_calls - .fetch_add(1, Ordering::Relaxed); - } - NET_TCP_TRACE_COUNTERS - .kernel_poll_wait_us - .fetch_add(duration_micros_u64(wait), Ordering::Relaxed); - NET_TCP_TRACE_COUNTERS - .kernel_poll_elapsed_us - .fetch_add(duration_micros_u64(elapsed), Ordering::Relaxed); - if revents.is_empty() { - NET_TCP_TRACE_COUNTERS - .kernel_poll_empty - .fetch_add(1, Ordering::Relaxed); - } else { - NET_TCP_TRACE_COUNTERS - .kernel_poll_ready - .fetch_add(1, Ordering::Relaxed); - NET_TCP_TRACE_COUNTERS - .kernel_poll_revents_bits_or - .fetch_or(u64::from(revents.bits()), Ordering::Relaxed); - } - if revents.intersects(POLLIN) { - NET_TCP_TRACE_COUNTERS - .kernel_poll_revents_read - .fetch_add(1, Ordering::Relaxed); - } - if revents.intersects(POLLHUP) { - NET_TCP_TRACE_COUNTERS - .kernel_poll_revents_hup - .fetch_add(1, Ordering::Relaxed); - } - if revents.intersects(POLLERR) { - NET_TCP_TRACE_COUNTERS - .kernel_poll_revents_err - .fetch_add(1, Ordering::Relaxed); - } -} - -pub(crate) fn service_javascript_sync_rpc( - request: JavascriptSyncRpcServiceRequest<'_, B>, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - if sync_rpc_trace_enabled() { - record_sync_rpc(request.sync_request.method.as_str()); - } - let JavascriptSyncRpcServiceRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness, - process, - sync_request: request, - resource_limits, - network_counts, - } = request; - if request.raw_bytes_args.contains_key(&usize::MAX) && request.method == "fs.readSync" { - let kernel_pid = process.kernel_pid; - let bytes = service_javascript_fs_read_sync_rpc(kernel, process, kernel_pid, request)?; - return Ok(JavascriptSyncRpcServiceResponse::Raw(bytes)); - } - if request.method == "fs.readdirSync" { - let kernel_pid = process.kernel_pid; - let bytes = - service_javascript_fs_readdir_raw_sync_rpc(kernel, process, kernel_pid, request)?; - return Ok(JavascriptSyncRpcServiceResponse::Raw(bytes)); - } - let response = match request.method.as_str() { - "__bench.noop" => Ok(Value::Null), - "__bench.net_tcp_metrics_reset" => { - net_tcp_trace_reset(); - Ok(Value::Null) - } - "__bench.net_tcp_metrics_snapshot" => Ok(net_tcp_trace_snapshot()), - // Module resolution / loading / format detection read the kernel VFS so - // the resolver sees exactly what the guest and `kernel.readFile()` see. - "_resolveModule" - | "_resolveModuleSync" - | "__resolve_module" - | "_batchResolveModules" - | "__batch_resolve_modules" - | "_loadFile" - | "_loadFileSync" - | "__load_file" - | "_moduleFormat" - | "__module_format" => service_javascript_module_sync_rpc(kernel, process, request), - // Polyfills are static guest expressions, not VFS reads. - "_loadPolyfill" | "__load_polyfill" => { - service_javascript_internal_bridge_sync_rpc(process, request) - } - "__kernel_stdin_read" => { - // A TTY (PTY-backed) JavaScript process must read its stdin from the - // kernel PTY slave (fd 0) so cooked-mode line discipline (echo, - // VERASE/VKILL/VWERASE, ICRNL, VEOF) applies exactly as it does for - // wasm/python. Non-TTY JS keeps using the in-process local stdin - // bridge (piped stdin fed via process.execution.write_stdin). - let js_local_bridge = matches!(process.execution, ActiveExecution::Javascript(_)) - && process.tty_master_fd.is_none(); - if js_local_bridge { - match &process.execution { - ActiveExecution::Javascript(execution) => execution - .read_kernel_stdin_sync_rpc(request) - .map_err(|error| SidecarError::Execution(error.to_string())), - _ => unreachable!("js_local_bridge implies a JavaScript execution"), - } - } else { - service_javascript_kernel_stdin_sync_rpc(kernel, process, request) - } - } - "__kernel_stdio_write" => { - service_javascript_kernel_stdio_write_sync_rpc(kernel, process, request) - } - "__kernel_isatty" => service_javascript_kernel_isatty_sync_rpc(kernel, process, request), - "__kernel_tty_size" => { - service_javascript_kernel_tty_size_sync_rpc(kernel, process, request) - } - "__kernel_poll" => service_javascript_kernel_poll_sync_rpc(kernel, process, request), - "__pty_set_raw_mode" => { - service_javascript_pty_set_raw_mode_sync_rpc(kernel, process, request) - } - "crypto.hashDigest" - | "crypto.hmacDigest" - | "crypto.pbkdf2" - | "crypto.scrypt" - | "crypto.cipheriv" - | "crypto.decipheriv" - | "crypto.cipherivCreate" - | "crypto.cipherivUpdate" - | "crypto.cipherivFinal" - | "crypto.sign" - | "crypto.verify" - | "crypto.asymmetricOp" - | "crypto.createKeyObject" - | "crypto.generateKeyPairSync" - | "crypto.generateKeySync" - | "crypto.generatePrimeSync" - | "crypto.diffieHellman" - | "crypto.diffieHellmanGroup" - | "crypto.diffieHellmanSessionCreate" - | "crypto.diffieHellmanSessionCall" - | "crypto.diffieHellmanSessionDestroy" - | "crypto.subtle" => service_javascript_crypto_sync_rpc(process, request), - "dns.lookup" | "dns.resolve" | "dns.resolve4" | "dns.resolve6" => { - service_javascript_dns_sync_rpc(bridge, kernel, vm_id, dns, request) - } - "net.http_listen" | "net.http_close" | "net.http_wait" | "net.http_respond" => { - return service_javascript_net_sync_rpc_response(JavascriptNetSyncRpcServiceRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness: Arc::clone(&kernel_readiness), - process, - sync_request: request, - resource_limits, - network_counts, - }) - } - "net.http2_server_listen" - | "net.http2_server_poll" - | "net.http2_server_close" - | "net.http2_server_respond" - | "net.http2_server_wait" - | "net.http2_session_connect" - | "net.http2_session_request" - | "net.http2_session_settings" - | "net.http2_session_set_local_window_size" - | "net.http2_session_goaway" - | "net.http2_session_close" - | "net.http2_session_destroy" - | "net.http2_session_poll" - | "net.http2_session_wait" - | "net.http2_stream_respond" - | "net.http2_stream_push_stream" - | "net.http2_stream_write" - | "net.http2_stream_end" - | "net.http2_stream_close" - | "net.http2_stream_pause" - | "net.http2_stream_resume" - | "net.http2_stream_respond_with_file" => { - service_javascript_http2_sync_rpc(JavascriptHttp2SyncRpcServiceRequest { - bridge, - kernel, - vm_id, - dns, - socket_paths, - process, - sync_request: request, - resource_limits, - network_counts, - }) - } - "net.connect" - | "net.reserve_tcp_port" - | "net.release_tcp_port" - | "net.listen" - | "net.poll" - | "net.socket_wait_connect" - | "net.socket_read" - | "net.socket_set_no_delay" - | "net.socket_set_keep_alive" - | "net.socket_upgrade_tls" - | "net.socket_get_tls_client_hello" - | "net.socket_tls_query" - | "net.server_poll" - | "net.server_accept" - | "net.server_connections" - | "net.upgrade_socket_write" - | "net.upgrade_socket_end" - | "net.upgrade_socket_destroy" - | "net.write" - | "net.shutdown" - | "net.destroy" - | "net.server_close" - | "tls.get_ciphers" => { - return service_javascript_net_sync_rpc_response(JavascriptNetSyncRpcServiceRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness: Arc::clone(&kernel_readiness), - process, - sync_request: request, - resource_limits, - network_counts, - }) - } - "dgram.createSocket" - | "dgram.bind" - | "dgram.send" - | "dgram.poll" - | "dgram.close" - | "dgram.address" - | "dgram.setBufferSize" - | "dgram.getBufferSize" => { - service_javascript_dgram_sync_rpc(JavascriptDgramSyncRpcServiceRequest { - bridge, - kernel, - vm_id, - dns, - socket_paths, - process, - kernel_readiness, - sync_request: request, - resource_limits, - network_counts, - }) - } - "sqlite.constants" - | "sqlite.open" - | "sqlite.close" - | "sqlite.exec" - | "sqlite.query" - | "sqlite.prepare" - | "sqlite.location" - | "sqlite.checkpoint" - | "sqlite.statement.run" - | "sqlite.statement.get" - | "sqlite.statement.all" - | "sqlite.statement.iterate" - | "sqlite.statement.columns" - | "sqlite.statement.setReturnArrays" - | "sqlite.statement.setReadBigInts" - | "sqlite.statement.setAllowBareNamedParameters" - | "sqlite.statement.setAllowUnknownNamedParameters" - | "sqlite.statement.finalize" => { - service_javascript_sqlite_sync_rpc(kernel, process, request) - } - "process.kill" => { - let target_pid = - javascript_sync_rpc_arg_i32(&request.args, 0, "process.kill target pid")?; - let signal = javascript_sync_rpc_arg_str(&request.args, 1, "process.kill signal")?; - let parsed_signal = parse_signal(signal)?; - if parsed_signal == 0 { - kernel - .signal_process(EXECUTION_DRIVER_NAME, target_pid, parsed_signal) - .map_err(kernel_error)?; - return Ok(Value::Null.into()); - } - let process_pid = i32::try_from(process.kernel_pid) - .map_err(|_| SidecarError::InvalidState("process pid exceeds i32".into()))?; - if target_pid != process_pid { - return Err(SidecarError::InvalidState(format!( - "unknown process pid {target_pid}" - ))); - } - process.pending_self_signal_exit = None; - if parsed_signal != 0 - && !matches!( - canonical_signal_name(parsed_signal), - Some("SIGWINCH" | "SIGCHLD" | "SIGCONT" | "SIGURG") - ) - { - process.pending_self_signal_exit = Some(parsed_signal); - } - Ok(json!({ - "self": true, - "action": "default", - })) - } - "process.umask" => { - let new_mask = javascript_sync_rpc_arg_u32_optional(&request.args, 0, "process umask")?; - kernel - .umask(EXECUTION_DRIVER_NAME, process.kernel_pid, new_mask) - .map(|mask| json!(mask)) - .map_err(kernel_error) - } - "fs.chmodSync" | "fs.promises.chmod" => { - let response = - service_javascript_fs_sync_rpc(kernel, process, process.kernel_pid, request)?; - mirror_process_chmod_to_host(process, request)?; - Ok(response) - } - _ => service_javascript_fs_sync_rpc(kernel, process, process.kernel_pid, request), - }?; - Ok(response.into()) -} - -fn service_javascript_internal_bridge_sync_rpc( - process: &ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - // Module resolution / loading / format now reads the kernel VFS via - // `service_javascript_module_sync_rpc`. This host-context path only handles - // polyfills, which are static guest expressions independent of the FS. - let method = match request.method.as_str() { - "_loadPolyfill" | "__load_polyfill" => "_loadPolyfill", - other => { - return Err(SidecarError::InvalidState(format!( - "unsupported JavaScript internal bridge method {other}" - ))); - } - }; - - handle_internal_bridge_call_from_host_context( - &process.host_cwd, - &process.guest_cwd, - &process.env, - method, - &request.args, - ) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "JavaScript internal bridge method {method} returned no value" - )) - }) -} - -fn mirror_process_chmod_to_host( - process: &ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result<(), SidecarError> { - let guest_path = javascript_sync_rpc_arg_str(&request.args, 0, "filesystem chmod path")?; - let mode = javascript_sync_rpc_arg_u32(&request.args, 1, "filesystem chmod mode")? & 0o7777; - let Some(host_path) = resolve_process_guest_path_to_host(process, guest_path) else { - return Ok(()); - }; - if !host_path.exists() { - return Ok(()); - } - fs::set_permissions(&host_path, fs::Permissions::from_mode(mode)).map_err(|error| { - SidecarError::Io(format!( - "failed to mirror chmod to host path {}: {error}", - host_path.display() - )) - }) -} - -fn resolve_process_guest_path_to_host( - process: &ActiveProcess, - guest_path: &str, -) -> Option { - let normalized_guest_path = if guest_path.starts_with('/') { - normalize_path(guest_path) - } else { - normalize_path(&format!( - "{}/{}", - process.guest_cwd.trim_end_matches('/'), - guest_path - )) - }; - if let Some(host_path) = - host_path_from_runtime_guest_mappings(&process.env, &normalized_guest_path) - { - return Some(host_path); - } - let normalized_guest_cwd = normalize_path(&process.guest_cwd); - let mut host_root = normalize_host_path(&process.host_cwd); - for _ in normalized_guest_cwd - .trim_start_matches('/') - .split('/') - .filter(|segment| !segment.is_empty()) - { - host_root = host_root.parent()?.to_path_buf(); - } - if normalized_guest_path == "/" { - Some(host_root) - } else { - Some(host_root.join(normalized_guest_path.trim_start_matches('/'))) - } -} - -pub(crate) fn service_javascript_crypto_sync_rpc( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - match request.method.as_str() { - "crypto.hashDigest" => { - let algorithm = javascript_crypto_digest_algorithm( - &request.args, - 0, - "crypto.hashDigest algorithm", - )?; - let data = javascript_sync_rpc_base64_arg(&request.args, 1, "crypto.hashDigest data")?; - Ok(Value::String( - base64::engine::general_purpose::STANDARD.encode(algorithm.digest(&data)), - )) - } - "crypto.hmacDigest" => { - let algorithm = javascript_crypto_digest_algorithm( - &request.args, - 0, - "crypto.hmacDigest algorithm", - )?; - let key = javascript_sync_rpc_base64_arg(&request.args, 1, "crypto.hmacDigest key")?; - let data = javascript_sync_rpc_base64_arg(&request.args, 2, "crypto.hmacDigest data")?; - Ok(Value::String( - base64::engine::general_purpose::STANDARD.encode(algorithm.hmac(&key, &data)?), - )) - } - "crypto.pbkdf2" => { - let password = - javascript_sync_rpc_base64_arg(&request.args, 0, "crypto.pbkdf2 password")?; - let salt = javascript_sync_rpc_base64_arg(&request.args, 1, "crypto.pbkdf2 salt")?; - let iterations = - javascript_sync_rpc_arg_u32(&request.args, 2, "crypto.pbkdf2 iterations")?; - if iterations == 0 { - return Err(SidecarError::InvalidState(String::from( - "crypto.pbkdf2 iterations must be greater than zero", - ))); - } - let key_len = usize::try_from(javascript_sync_rpc_arg_u64( - &request.args, - 3, - "crypto.pbkdf2 key length", - )?) - .map_err(|_| { - SidecarError::InvalidState(String::from( - "crypto.pbkdf2 key length must fit within usize", - )) - })?; - let algorithm = - javascript_crypto_digest_algorithm(&request.args, 4, "crypto.pbkdf2 digest")?; - let mut output = vec![0u8; key_len]; - algorithm.pbkdf2(&password, &salt, iterations, &mut output); - Ok(Value::String( - base64::engine::general_purpose::STANDARD.encode(output), - )) - } - "crypto.scrypt" => { - let password = - javascript_sync_rpc_base64_arg(&request.args, 0, "crypto.scrypt password")?; - let salt = javascript_sync_rpc_base64_arg(&request.args, 1, "crypto.scrypt salt")?; - let key_len = usize::try_from(javascript_sync_rpc_arg_u64( - &request.args, - 2, - "crypto.scrypt key length", - )?) - .map_err(|_| { - SidecarError::InvalidState(String::from( - "crypto.scrypt key length must fit within usize", - )) - })?; - let options_json = - javascript_sync_rpc_arg_str(&request.args, 3, "crypto.scrypt options")?; - let options: JavascriptScryptOptions = - serde_json::from_str(options_json).map_err(|error| { - SidecarError::InvalidState(format!( - "crypto.scrypt options must be valid JSON: {error}" - )) - })?; - let cost = options.cost.unwrap_or(DEFAULT_SCRYPT_COST); - if cost == 0 || !cost.is_power_of_two() { - return Err(SidecarError::InvalidState(String::from( - "crypto.scrypt cost must be a positive power of two", - ))); - } - let log_n = u8::try_from(cost.ilog2()).map_err(|_| { - SidecarError::InvalidState(String::from( - "crypto.scrypt cost exceeds supported parameter range", - )) - })?; - let params = ScryptParams::new( - log_n, - options.block_size.unwrap_or(DEFAULT_SCRYPT_BLOCK_SIZE), - options - .parallelization - .unwrap_or(DEFAULT_SCRYPT_PARALLELIZATION), - key_len, - ) - .map_err(|error| { - SidecarError::InvalidState(format!("crypto.scrypt options are invalid: {error}")) - })?; - let mut output = vec![0u8; key_len]; - scrypt(&password, &salt, ¶ms, &mut output).map_err(|error| { - SidecarError::Execution(format!("crypto.scrypt failed: {error}")) - })?; - Ok(Value::String( - base64::engine::general_purpose::STANDARD.encode(output), - )) - } - "crypto.cipheriv" => service_javascript_crypto_cipheriv_sync_rpc(request), - "crypto.decipheriv" => service_javascript_crypto_decipheriv_sync_rpc(request), - "crypto.cipherivCreate" => { - service_javascript_crypto_cipheriv_create_sync_rpc(process, request) - } - "crypto.cipherivUpdate" => { - service_javascript_crypto_cipheriv_update_sync_rpc(process, request) - } - "crypto.cipherivFinal" => { - service_javascript_crypto_cipheriv_final_sync_rpc(process, request) - } - "crypto.sign" => service_javascript_crypto_sign_sync_rpc(request), - "crypto.verify" => service_javascript_crypto_verify_sync_rpc(request), - "crypto.asymmetricOp" => service_javascript_crypto_asymmetric_op_sync_rpc(request), - "crypto.createKeyObject" => service_javascript_crypto_create_key_object_sync_rpc(request), - "crypto.generateKeyPairSync" => { - service_javascript_crypto_generate_key_pair_sync_rpc(request) - } - "crypto.generateKeySync" => service_javascript_crypto_generate_key_sync_rpc(request), - "crypto.generatePrimeSync" => service_javascript_crypto_generate_prime_sync_rpc(request), - "crypto.diffieHellman" => service_javascript_crypto_diffie_hellman_sync_rpc(request), - "crypto.diffieHellmanGroup" => { - service_javascript_crypto_diffie_hellman_group_sync_rpc(request) - } - "crypto.diffieHellmanSessionCreate" => { - service_javascript_crypto_diffie_hellman_session_create_sync_rpc(process, request) - } - "crypto.diffieHellmanSessionCall" => { - service_javascript_crypto_diffie_hellman_session_call_sync_rpc(process, request) - } - "crypto.diffieHellmanSessionDestroy" => { - service_javascript_crypto_diffie_hellman_session_destroy_sync_rpc(process, request) - } - "crypto.subtle" => service_javascript_crypto_subtle_sync_rpc(request), - _ => Err(SidecarError::InvalidState(format!( - "unsupported JavaScript crypto sync RPC method {}", - request.method - ))), - } -} - -fn javascript_crypto_digest_algorithm( - args: &[Value], - index: usize, - label: &str, -) -> Result { - JavascriptCryptoDigestAlgorithm::parse(javascript_sync_rpc_arg_str(args, index, label)?) -} - -impl JavascriptCryptoDigestAlgorithm { - fn parse(value: &str) -> Result { - match value.trim().to_ascii_lowercase().replace('-', "").as_str() { - "md5" => Ok(Self::Md5), - "sha1" => Ok(Self::Sha1), - "sha224" => Ok(Self::Sha224), - "sha256" => Ok(Self::Sha256), - "sha384" => Ok(Self::Sha384), - "sha512" => Ok(Self::Sha512), - _ => Err(SidecarError::InvalidState(format!( - "unsupported crypto digest algorithm {value}" - ))), - } - } - - fn digest(self, data: &[u8]) -> Vec { - match self { - Self::Md5 => Md5::digest(data).to_vec(), - Self::Sha1 => Sha1::digest(data).to_vec(), - Self::Sha224 => Sha224::digest(data).to_vec(), - Self::Sha256 => Sha256::digest(data).to_vec(), - Self::Sha384 => Sha384::digest(data).to_vec(), - Self::Sha512 => Sha512::digest(data).to_vec(), - } - } - - fn hmac(self, key: &[u8], data: &[u8]) -> Result, SidecarError> { - match self { - Self::Md5 => { - let mut mac = Hmac::::new_from_slice(key).map_err(|error| { - SidecarError::InvalidState(format!("invalid HMAC key: {error}")) - })?; - mac.update(data); - Ok(mac.finalize().into_bytes().to_vec()) - } - Self::Sha1 => { - let mut mac = Hmac::::new_from_slice(key).map_err(|error| { - SidecarError::InvalidState(format!("invalid HMAC key: {error}")) - })?; - mac.update(data); - Ok(mac.finalize().into_bytes().to_vec()) - } - Self::Sha224 => { - let mut mac = Hmac::::new_from_slice(key).map_err(|error| { - SidecarError::InvalidState(format!("invalid HMAC key: {error}")) - })?; - mac.update(data); - Ok(mac.finalize().into_bytes().to_vec()) - } - Self::Sha256 => { - let mut mac = Hmac::::new_from_slice(key).map_err(|error| { - SidecarError::InvalidState(format!("invalid HMAC key: {error}")) - })?; - mac.update(data); - Ok(mac.finalize().into_bytes().to_vec()) - } - Self::Sha384 => { - let mut mac = Hmac::::new_from_slice(key).map_err(|error| { - SidecarError::InvalidState(format!("invalid HMAC key: {error}")) - })?; - mac.update(data); - Ok(mac.finalize().into_bytes().to_vec()) - } - Self::Sha512 => { - let mut mac = Hmac::::new_from_slice(key).map_err(|error| { - SidecarError::InvalidState(format!("invalid HMAC key: {error}")) - })?; - mac.update(data); - Ok(mac.finalize().into_bytes().to_vec()) - } - } - } - - fn pbkdf2(self, password: &[u8], salt: &[u8], iterations: u32, output: &mut [u8]) { - match self { - Self::Md5 => pbkdf2_hmac::(password, salt, iterations, output), - Self::Sha1 => pbkdf2_hmac::(password, salt, iterations, output), - Self::Sha224 => pbkdf2_hmac::(password, salt, iterations, output), - Self::Sha256 => pbkdf2_hmac::(password, salt, iterations, output), - Self::Sha384 => pbkdf2_hmac::(password, salt, iterations, output), - Self::Sha512 => pbkdf2_hmac::(password, salt, iterations, output), - } - } -} - -#[derive(Debug, Clone)] -enum JavascriptCryptoKeyMaterial { - Private(PKey), - Public(PKey), - Secret(Vec), -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -struct JavascriptSerializedSandboxKeyObject { - #[serde(rename = "type")] - kind: String, - #[serde(skip_serializing_if = "Option::is_none")] - pem: Option, - #[serde(skip_serializing_if = "Option::is_none")] - raw: Option, - #[serde(skip_serializing_if = "Option::is_none", rename = "asymmetricKeyType")] - asymmetric_key_type: Option, - #[serde( - skip_serializing_if = "Option::is_none", - rename = "asymmetricKeyDetails" - )] - asymmetric_key_details: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - jwk: Option, -} - -#[derive(Debug, Clone)] -struct JavascriptDirectKeyInput { - key: JavascriptCryptoKeyMaterial, - padding: Option, -} - -fn service_javascript_crypto_cipheriv_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - service_javascript_crypto_cipheriv_inner(request, false) -} - -fn service_javascript_crypto_decipheriv_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - service_javascript_crypto_cipheriv_inner(request, true) -} - -fn service_javascript_crypto_cipheriv_create_sync_rpc( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - ensure_per_process_state_handle_capacity(process.cipher_sessions.len(), "cipher session")?; - let mode = javascript_sync_rpc_arg_str(&request.args, 0, "crypto.cipherivCreate mode")?; - let decrypt = mode == "decipher"; - let algorithm = - javascript_sync_rpc_arg_str(&request.args, 1, "crypto.cipherivCreate algorithm")?; - let key = javascript_sync_rpc_base64_arg(&request.args, 2, "crypto.cipherivCreate key")?; - let iv = javascript_sync_rpc_base64_arg_optional(&request.args, 3, "crypto.cipherivCreate iv")?; - let options = - javascript_sync_rpc_json_arg_optional(&request.args, 4, "crypto.cipherivCreate options")?; - let context = javascript_crypto_build_cipher_session( - algorithm, - &key, - iv.as_deref(), - decrypt, - options.as_ref(), - )?; - process.next_cipher_session_id += 1; - let session_id = process.next_cipher_session_id; - process - .cipher_sessions - .insert(session_id, ActiveCipherSession { context }); - Ok(json!(session_id)) -} - -fn service_javascript_crypto_cipheriv_update_sync_rpc( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let session_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "crypto.cipherivUpdate session id")?; - let data = javascript_sync_rpc_base64_arg(&request.args, 1, "crypto.cipherivUpdate data")?; - let session = process - .cipher_sessions - .get_mut(&session_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!("Cipher session {session_id} not found")) - })?; - let result = javascript_crypto_cipher_update(&mut session.context, &data)?; - Ok(Value::String( - base64::engine::general_purpose::STANDARD.encode(result), - )) -} - -fn service_javascript_crypto_cipheriv_final_sync_rpc( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let session_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "crypto.cipherivFinal session id")?; - let session = process.cipher_sessions.remove(&session_id).ok_or_else(|| { - SidecarError::InvalidState(format!("Cipher session {session_id} not found")) - })?; - let outcome = session - .context - .finalize() - .map_err(javascript_crypto_cipher_error)?; - let mut response = Map::new(); - response.insert( - String::from("data"), - Value::String(base64::engine::general_purpose::STANDARD.encode(outcome.data)), - ); - if let Some(auth_tag) = outcome.auth_tag { - response.insert( - String::from("authTag"), - Value::String(base64::engine::general_purpose::STANDARD.encode(auth_tag)), - ); - } - Ok(Value::String(serde_json::to_string(&response).map_err( - |error| SidecarError::InvalidState(format!("serialize cipher final response: {error}")), - )?)) -} - -fn service_javascript_crypto_sign_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let algorithm = request.args.first().and_then(Value::as_str); - let data = javascript_sync_rpc_base64_arg(&request.args, 1, "crypto.sign data")?; - let key_json = javascript_sync_rpc_arg_str(&request.args, 2, "crypto.sign key")?; - let key_input = - javascript_crypto_parse_direct_key_input(key_json, Some("private"), "crypto.sign key")?; - let private_key = javascript_crypto_expect_private_key(key_input.key, "crypto.sign key")?; - let mut signer = javascript_crypto_new_signer(algorithm, &private_key)?; - if let Some(padding) = key_input.padding { - signer - .set_rsa_padding(padding) - .map_err(javascript_crypto_openssl_error)?; - } - signer - .update(&data) - .map_err(javascript_crypto_openssl_error)?; - Ok(Value::String( - base64::engine::general_purpose::STANDARD.encode( - signer - .sign_to_vec() - .map_err(javascript_crypto_openssl_error)?, - ), - )) -} - -fn service_javascript_crypto_verify_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let algorithm = request.args.first().and_then(Value::as_str); - let data = javascript_sync_rpc_base64_arg(&request.args, 1, "crypto.verify data")?; - let key_json = javascript_sync_rpc_arg_str(&request.args, 2, "crypto.verify key")?; - let signature = javascript_sync_rpc_base64_arg(&request.args, 3, "crypto.verify signature")?; - let key_input = - javascript_crypto_parse_direct_key_input(key_json, Some("public"), "crypto.verify key")?; - let public_key = javascript_crypto_expect_public_key(key_input.key, "crypto.verify key")?; - let mut verifier = javascript_crypto_new_verifier(algorithm, &public_key)?; - if let Some(padding) = key_input.padding { - verifier - .set_rsa_padding(padding) - .map_err(javascript_crypto_openssl_error)?; - } - verifier - .update(&data) - .map_err(javascript_crypto_openssl_error)?; - Ok(json!(verifier - .verify(&signature) - .map_err(javascript_crypto_openssl_error)?)) -} - -fn service_javascript_crypto_asymmetric_op_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let operation = javascript_sync_rpc_arg_str(&request.args, 0, "crypto.asymmetricOp operation")?; - let key_json = javascript_sync_rpc_arg_str(&request.args, 1, "crypto.asymmetricOp key")?; - let data = javascript_sync_rpc_base64_arg(&request.args, 2, "crypto.asymmetricOp data")?; - let expect_kind = match operation { - "publicEncrypt" | "publicDecrypt" => Some("public"), - "privateEncrypt" | "privateDecrypt" => Some("private"), - other => { - return Err(SidecarError::InvalidState(format!( - "Unsupported asymmetric crypto operation: {other}" - ))); - } - }; - let key_input = - javascript_crypto_parse_direct_key_input(key_json, expect_kind, "crypto.asymmetricOp key")?; - let padding = key_input.padding.unwrap_or(Padding::PKCS1); - let mut output = vec![0_u8; javascript_crypto_rsa_output_size(&key_input.key)?]; - let written = match (operation, key_input.key) { - ("publicEncrypt", JavascriptCryptoKeyMaterial::Public(key)) - | ("publicDecrypt", JavascriptCryptoKeyMaterial::Public(key)) => { - let rsa = key.rsa().map_err(javascript_crypto_openssl_error)?; - if operation == "publicEncrypt" { - rsa.public_encrypt(&data, &mut output, padding) - .map_err(javascript_crypto_openssl_error)? - } else { - rsa.public_decrypt(&data, &mut output, padding) - .map_err(javascript_crypto_openssl_error)? - } - } - ("privateEncrypt", JavascriptCryptoKeyMaterial::Private(key)) - | ("privateDecrypt", JavascriptCryptoKeyMaterial::Private(key)) => { - let rsa = key.rsa().map_err(javascript_crypto_openssl_error)?; - if operation == "privateEncrypt" { - rsa.private_encrypt(&data, &mut output, padding) - .map_err(javascript_crypto_openssl_error)? - } else { - rsa.private_decrypt(&data, &mut output, padding) - .map_err(javascript_crypto_openssl_error)? - } - } - _ => { - return Err(SidecarError::InvalidState(format!( - "{operation} requires an RSA {} key", - expect_kind.unwrap_or("asymmetric") - ))); - } - }; - output.truncate(written); - Ok(Value::String( - base64::engine::general_purpose::STANDARD.encode(output), - )) -} - -fn service_javascript_crypto_create_key_object_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let operation = - javascript_sync_rpc_arg_str(&request.args, 0, "crypto.createKeyObject operation")?; - let key_json = javascript_sync_rpc_arg_str(&request.args, 1, "crypto.createKeyObject key")?; - let expected = match operation { - "createPrivateKey" => Some("private"), - "createPublicKey" => Some("public"), - other => { - return Err(SidecarError::InvalidState(format!( - "Unsupported key creation operation: {other}" - ))); - } - }; - let key_input = - javascript_crypto_parse_direct_key_input(key_json, expected, "crypto.createKeyObject key")?; - Ok(Value::String( - serde_json::to_string(&javascript_crypto_serialize_sandbox_key_object( - &key_input.key, - )?) - .map_err(|error| { - SidecarError::InvalidState(format!("serialize crypto key object: {error}")) - })?, - )) -} - -fn service_javascript_crypto_generate_key_pair_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let key_type = - javascript_sync_rpc_arg_str(&request.args, 0, "crypto.generateKeyPairSync type")?; - let options = javascript_crypto_parse_serialized_options_arg( - &request.args, - 1, - "crypto.generateKeyPairSync options", - )? - .unwrap_or(Value::Object(Map::new())); - let public_encoding = options.get("publicKeyEncoding").cloned(); - let private_encoding = options.get("privateKeyEncoding").cloned(); - - let private_key = match key_type { - "rsa" => { - let bits = options - .get("modulusLength") - .and_then(Value::as_u64) - .unwrap_or(2048) as u32; - let exponent = options - .get("publicExponent") - .map(|value| javascript_crypto_u32_from_bridge_value(value, "rsa publicExponent")) - .transpose()? - .unwrap_or(65_537); - let exponent = BigNum::from_u32(exponent).map_err(javascript_crypto_openssl_error)?; - let rsa = - Rsa::generate_with_e(bits, &exponent).map_err(javascript_crypto_openssl_error)?; - PKey::from_rsa(rsa).map_err(javascript_crypto_openssl_error)? - } - "ec" => { - let named_curve = options - .get("namedCurve") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.generateKeyPairSync ec requires namedCurve", - )) - })?; - let group = EcGroup::from_curve_name(javascript_crypto_curve_nid(named_curve)?) - .map_err(javascript_crypto_openssl_error)?; - let key = EcKey::generate(&group).map_err(javascript_crypto_openssl_error)?; - PKey::from_ec_key(key).map_err(javascript_crypto_openssl_error)? - } - "ed25519" => PKey::generate_ed25519().map_err(javascript_crypto_openssl_error)?, - "x25519" => PKey::generate_x25519().map_err(javascript_crypto_openssl_error)?, - other => { - return Err(SidecarError::InvalidState(format!( - "unsupported crypto key pair type {other}" - ))); - } - }; - let public_key = PKey::public_key_from_pem( - &private_key - .public_key_to_pem() - .map_err(javascript_crypto_openssl_error)?, - ) - .map_err(javascript_crypto_openssl_error)?; - let response = if public_encoding.is_some() || private_encoding.is_some() { - json!({ - "publicKey": javascript_crypto_serialize_encoded_key_value_public(&public_key, public_encoding.as_ref())?, - "privateKey": javascript_crypto_serialize_encoded_key_value_private(&private_key, private_encoding.as_ref())?, - }) - } else { - json!({ - "publicKey": javascript_crypto_serialize_sandbox_key_object(&JavascriptCryptoKeyMaterial::Public(public_key))?, - "privateKey": javascript_crypto_serialize_sandbox_key_object(&JavascriptCryptoKeyMaterial::Private(private_key))?, - }) - }; - Ok(Value::String(serde_json::to_string(&response).map_err( - |error| SidecarError::InvalidState(format!("serialize generated key pair: {error}")), - )?)) -} - -fn service_javascript_crypto_generate_key_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let key_type = javascript_sync_rpc_arg_str(&request.args, 0, "crypto.generateKeySync type")?; - let options = javascript_crypto_parse_serialized_options_arg( - &request.args, - 1, - "crypto.generateKeySync options", - )? - .unwrap_or(Value::Object(Map::new())); - let bit_length = options - .get("length") - .and_then(Value::as_u64) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.generateKeySync options.length is required", - )) - })? as usize; - let mut raw = vec![0_u8; bit_length.div_ceil(8)]; - rand_bytes(&mut raw).map_err(javascript_crypto_openssl_error)?; - let serialized = match key_type { - "hmac" => javascript_crypto_serialize_sandbox_key_object( - &JavascriptCryptoKeyMaterial::Secret(raw), - )?, - "aes" => javascript_crypto_serialize_sandbox_key_object( - &JavascriptCryptoKeyMaterial::Secret(raw), - )?, - other => { - return Err(SidecarError::InvalidState(format!( - "unsupported crypto.generateKeySync type {other}" - ))); - } - }; - Ok(Value::String(serde_json::to_string(&serialized).map_err( - |error| SidecarError::InvalidState(format!("serialize generated key: {error}")), - )?)) -} - -fn service_javascript_crypto_generate_prime_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let bits = - javascript_sync_rpc_arg_u64(&request.args, 0, "crypto.generatePrimeSync size")? as i32; - let options = javascript_crypto_parse_serialized_options_arg( - &request.args, - 1, - "crypto.generatePrimeSync options", - )? - .unwrap_or(Value::Object(Map::new())); - let safe = options - .get("safe") - .and_then(Value::as_bool) - .unwrap_or(false); - let add = options - .get("add") - .map(|value| javascript_crypto_bignum_from_bridge_value(value, "prime add")) - .transpose()?; - let rem = options - .get("rem") - .map(|value| javascript_crypto_bignum_from_bridge_value(value, "prime rem")) - .transpose()?; - let mut prime = BigNum::new().map_err(javascript_crypto_openssl_error)?; - prime - .generate_prime(bits, safe, add.as_deref(), rem.as_deref()) - .map_err(javascript_crypto_openssl_error)?; - let payload = if options - .get("bigint") - .and_then(Value::as_bool) - .unwrap_or(false) - { - json!({ - "__type": "bigint", - "value": prime.to_dec_str().map_err(javascript_crypto_openssl_error)?.to_string(), - }) - } else { - json!({ - "__type": "buffer", - "value": base64::engine::general_purpose::STANDARD.encode(prime.to_vec()), - }) - }; - Ok(Value::String(serde_json::to_string(&payload).map_err( - |error| SidecarError::InvalidState(format!("serialize generated prime: {error}")), - )?)) -} - -fn service_javascript_crypto_diffie_hellman_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let options = javascript_sync_rpc_arg_str(&request.args, 0, "crypto.diffieHellman options")?; - let parsed: Value = serde_json::from_str(options).map_err(|error| { - SidecarError::InvalidState(format!( - "crypto.diffieHellman options must be valid JSON: {error}" - )) - })?; - let private_key = javascript_crypto_parse_key_material_value( - parsed.get("privateKey").ok_or_else(|| { - SidecarError::InvalidState(String::from("crypto.diffieHellman missing privateKey")) - })?, - Some("private"), - "crypto.diffieHellman privateKey", - )?; - let public_key = javascript_crypto_parse_key_material_value( - parsed.get("publicKey").ok_or_else(|| { - SidecarError::InvalidState(String::from("crypto.diffieHellman missing publicKey")) - })?, - Some("public"), - "crypto.diffieHellman publicKey", - )?; - let private_key = - javascript_crypto_expect_private_key(private_key, "crypto.diffieHellman privateKey")?; - let public_key = - javascript_crypto_expect_public_key(public_key, "crypto.diffieHellman publicKey")?; - let mut deriver = Deriver::new(&private_key).map_err(javascript_crypto_openssl_error)?; - deriver - .set_peer(&public_key) - .map_err(javascript_crypto_openssl_error)?; - let secret = deriver - .derive_to_vec() - .map_err(javascript_crypto_openssl_error)?; - Ok(Value::String( - serde_json::to_string(&json!({ - "__type": "buffer", - "value": base64::engine::general_purpose::STANDARD.encode(secret), - })) - .map_err(|error| { - SidecarError::InvalidState(format!("serialize derived secret: {error}")) - })?, - )) -} - -fn service_javascript_crypto_diffie_hellman_group_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let name = javascript_sync_rpc_arg_str(&request.args, 0, "crypto.diffieHellmanGroup name")?; - let params = javascript_crypto_named_dh_group(name)?; - let response = json!({ - "prime": { - "__type": "buffer", - "value": base64::engine::general_purpose::STANDARD.encode(params.prime_p().to_vec()), - }, - "generator": { - "__type": "buffer", - "value": base64::engine::general_purpose::STANDARD.encode(params.generator().to_vec()), - }, - }); - Ok(Value::String(serde_json::to_string(&response).map_err( - |error| { - SidecarError::InvalidState(format!("serialize diffieHellmanGroup response: {error}")) - }, - )?)) -} - -fn service_javascript_crypto_diffie_hellman_session_create_sync_rpc( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - ensure_per_process_state_handle_capacity( - process.diffie_hellman_sessions.len(), - "diffie-hellman session", - )?; - let raw = javascript_sync_rpc_arg_str( - &request.args, - 0, - "crypto.diffieHellmanSessionCreate request", - )?; - let parsed: Value = serde_json::from_str(raw).map_err(|error| { - SidecarError::InvalidState(format!( - "crypto.diffieHellmanSessionCreate request must be valid JSON: {error}" - )) - })?; - let session = match parsed.get("type").and_then(Value::as_str) { - Some("group") => { - let name = parsed.get("name").and_then(Value::as_str).ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.diffieHellmanSessionCreate group requires name", - )) - })?; - ActiveDiffieHellmanSession::Dh(ActiveDhSession { - params: javascript_crypto_named_dh_group(name)?, - key_pair: None, - }) - } - Some("dh") => { - let args = parsed - .get("args") - .and_then(Value::as_array) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.diffieHellmanSessionCreate dh requires args", - )) - })?; - let params = javascript_crypto_build_dh_params(args)?; - ActiveDiffieHellmanSession::Dh(ActiveDhSession { - params, - key_pair: None, - }) - } - Some("ecdh") => { - let curve = parsed.get("name").and_then(Value::as_str).ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.diffieHellmanSessionCreate ecdh requires name", - )) - })?; - ActiveDiffieHellmanSession::Ecdh(ActiveEcdhSession { - curve: curve.to_string(), - key_pair: None, - }) - } - other => { - return Err(SidecarError::InvalidState(format!( - "Unsupported Diffie-Hellman session type: {}", - other.unwrap_or("") - ))); - } - }; - process.next_diffie_hellman_session_id += 1; - let session_id = process.next_diffie_hellman_session_id; - process.diffie_hellman_sessions.insert(session_id, session); - Ok(json!(session_id)) -} - -fn service_javascript_crypto_diffie_hellman_session_call_sync_rpc( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let session_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "crypto.diffieHellmanSessionCall session id", - )?; - let raw = - javascript_sync_rpc_arg_str(&request.args, 1, "crypto.diffieHellmanSessionCall request")?; - let parsed: Value = serde_json::from_str(raw).map_err(|error| { - SidecarError::InvalidState(format!( - "crypto.diffieHellmanSessionCall request must be valid JSON: {error}" - )) - })?; - let method = parsed - .get("method") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.diffieHellmanSessionCall request missing method", - )) - })?; - let args = parsed - .get("args") - .and_then(Value::as_array) - .cloned() - .unwrap_or_default(); - let session = process - .diffie_hellman_sessions - .get_mut(&session_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!("Diffie-Hellman session {session_id} not found")) - })?; - let (result, has_result) = match session { - ActiveDiffieHellmanSession::Dh(session) => { - javascript_crypto_call_dh_session(session, method, &args)? - } - ActiveDiffieHellmanSession::Ecdh(session) => { - javascript_crypto_call_ecdh_session(session, method, &args)? - } - }; - Ok(Value::String( - serde_json::to_string(&json!({ - "result": result, - "hasResult": has_result, - })) - .map_err(|error| { - SidecarError::InvalidState(format!("serialize diffie session result: {error}")) - })?, - )) -} - -fn service_javascript_crypto_diffie_hellman_session_destroy_sync_rpc( - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let session_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "crypto.diffieHellmanSessionDestroy session id", - )?; - process - .diffie_hellman_sessions - .remove(&session_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!("Diffie-Hellman session {session_id} not found")) - })?; - Ok(Value::Null) -} - -fn service_javascript_crypto_subtle_sync_rpc( - request: &JavascriptSyncRpcRequest, -) -> Result { - let raw = javascript_sync_rpc_arg_str(&request.args, 0, "crypto.subtle request")?; - let parsed: Value = serde_json::from_str(raw).map_err(|error| { - SidecarError::InvalidState(format!("crypto.subtle request must be valid JSON: {error}")) - })?; - let op = parsed.get("op").and_then(Value::as_str).ok_or_else(|| { - SidecarError::InvalidState(String::from("crypto.subtle request missing op")) - })?; - match op { - "digest" => { - let algorithm = parsed - .get("algorithm") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.subtle.digest missing algorithm", - )) - })?; - let data = parsed.get("data").and_then(Value::as_str).ok_or_else(|| { - SidecarError::InvalidState(String::from("crypto.subtle.digest missing data")) - })?; - let bytes = base64::engine::general_purpose::STANDARD - .decode(data) - .map_err(|error| { - SidecarError::InvalidState(format!("crypto.subtle.digest data base64: {error}")) - })?; - let digest = JavascriptCryptoDigestAlgorithm::parse(algorithm)?.digest(&bytes); - Ok(Value::String( - serde_json::to_string(&json!({ - "data": base64::engine::general_purpose::STANDARD.encode(digest), - })) - .map_err(|error| { - SidecarError::InvalidState(format!("serialize crypto.subtle digest: {error}")) - })?, - )) - } - "generateKey" => { - let algorithm = parsed.get("algorithm").ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.subtle.generateKey missing algorithm", - )) - })?; - let name = - javascript_crypto_subtle_algorithm_name(algorithm, "crypto.subtle.generateKey")?; - if !matches!(name, "AES-GCM" | "AES-CBC" | "AES-CTR" | "AES-KW") { - return Err(SidecarError::InvalidState(format!( - "Unsupported key algorithm: {name}" - ))); - } - let length_bits = algorithm - .get("length") - .and_then(Value::as_u64) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.subtle.generateKey AES algorithm requires length", - )) - })?; - if length_bits % 8 != 0 { - return Err(SidecarError::InvalidState(String::from( - "crypto.subtle.generateKey length must be byte-aligned", - ))); - } - let length_bytes = usize::try_from(length_bits / 8).map_err(|_| { - SidecarError::InvalidState(String::from( - "crypto.subtle.generateKey length is too large", - )) - })?; - let mut raw = vec![0_u8; length_bytes]; - rand_bytes(&mut raw).map_err(javascript_crypto_openssl_error)?; - let key = javascript_crypto_serialize_subtle_secret_key( - &raw, - javascript_crypto_normalize_subtle_secret_algorithm(algorithm.clone(), &raw)?, - parsed - .get("extractable") - .and_then(Value::as_bool) - .unwrap_or(false), - parsed.get("usages").cloned().unwrap_or_else(|| json!([])), - )?; - Ok(Value::String( - serde_json::to_string(&json!({ "key": key })).map_err(|error| { - SidecarError::InvalidState(format!( - "serialize crypto.subtle generated key: {error}" - )) - })?, - )) - } - "importKey" => { - let format = parsed - .get("format") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.subtle.importKey missing format", - )) - })?; - if format != "raw" { - return Err(SidecarError::InvalidState(format!( - "Unsupported import format: {format}" - ))); - } - let key_data = parsed - .get("keyData") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.subtle.importKey missing keyData", - )) - })?; - let raw = base64::engine::general_purpose::STANDARD - .decode(key_data) - .map_err(|error| { - SidecarError::InvalidState(format!( - "crypto.subtle.importKey keyData base64: {error}" - )) - })?; - let algorithm = parsed.get("algorithm").ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.subtle.importKey missing algorithm", - )) - })?; - let key = javascript_crypto_serialize_subtle_secret_key( - &raw, - javascript_crypto_normalize_subtle_secret_algorithm(algorithm.clone(), &raw)?, - parsed - .get("extractable") - .and_then(Value::as_bool) - .unwrap_or(false), - parsed.get("usages").cloned().unwrap_or_else(|| json!([])), - )?; - Ok(Value::String( - serde_json::to_string(&json!({ "key": key })).map_err(|error| { - SidecarError::InvalidState(format!( - "serialize crypto.subtle imported key: {error}" - )) - })?, - )) - } - "exportKey" => { - let format = parsed - .get("format") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "crypto.subtle.exportKey missing format", - )) - })?; - if format != "raw" { - return Err(SidecarError::InvalidState(format!( - "Unsupported export format: {format}" - ))); - } - let raw = javascript_crypto_subtle_key_raw( - parsed.get("key").ok_or_else(|| { - SidecarError::InvalidState(String::from("crypto.subtle.exportKey missing key")) - })?, - "crypto.subtle.exportKey key", - )?; - Ok(Value::String( - serde_json::to_string(&json!({ - "data": base64::engine::general_purpose::STANDARD.encode(raw), - })) - .map_err(|error| { - SidecarError::InvalidState(format!("serialize crypto.subtle export: {error}")) - })?, - )) - } - "encrypt" | "decrypt" => service_javascript_crypto_subtle_aes_crypt_sync_rpc(op, &parsed), - _ => Err(SidecarError::InvalidState(format!( - "Unsupported subtle operation: {op}" - ))), - } -} - -fn javascript_crypto_subtle_algorithm_name<'a>( - algorithm: &'a Value, - label: &str, -) -> Result<&'a str, SidecarError> { - if let Some(name) = algorithm.as_str() { - return Ok(name); - } - algorithm - .get("name") - .and_then(Value::as_str) - .ok_or_else(|| SidecarError::InvalidState(format!("{label} algorithm missing name"))) -} - -fn javascript_crypto_normalize_subtle_secret_algorithm( - algorithm: Value, - raw: &[u8], -) -> Result { - let mut object = match algorithm { - Value::String(name) => { - let mut object = Map::new(); - object.insert(String::from("name"), Value::String(name)); - object - } - Value::Object(object) => object, - _ => { - return Err(SidecarError::InvalidState(String::from( - "crypto.subtle secret algorithm must be a string or object", - ))); - } - }; - let name = object - .get("name") - .and_then(Value::as_str) - .ok_or_else(|| { - SidecarError::InvalidState(String::from("crypto.subtle secret algorithm missing name")) - })? - .to_string(); - if matches!(name.as_str(), "AES-GCM" | "AES-CBC" | "AES-CTR" | "AES-KW") - && !object.contains_key("length") - { - object.insert(String::from("length"), json!(raw.len() * 8)); - } - Ok(Value::Object(object)) -} - -fn javascript_crypto_serialize_subtle_secret_key( - raw: &[u8], - algorithm: Value, - extractable: bool, - usages: Value, -) -> Result { - let raw_base64 = base64::engine::general_purpose::STANDARD.encode(raw); - let source_key_object_data = javascript_crypto_serialize_sandbox_key_object( - &JavascriptCryptoKeyMaterial::Secret(raw.to_vec()), - )?; - Ok(json!({ - "type": "secret", - "algorithm": algorithm, - "extractable": extractable, - "usages": usages, - "_raw": raw_base64, - "_sourceKeyObjectData": source_key_object_data, - })) -} - -fn javascript_crypto_subtle_key_raw(key: &Value, label: &str) -> Result, SidecarError> { - let raw = key.get("_raw").and_then(Value::as_str).ok_or_else(|| { - SidecarError::InvalidState(format!("{label} must be a raw secret CryptoKey")) - })?; - base64::engine::general_purpose::STANDARD - .decode(raw) - .map_err(|error| SidecarError::InvalidState(format!("{label} raw base64: {error}"))) -} - -fn service_javascript_crypto_subtle_aes_crypt_sync_rpc( - op: &str, - parsed: &Value, -) -> Result { - let algorithm = parsed.get("algorithm").ok_or_else(|| { - SidecarError::InvalidState(format!("crypto.subtle.{op} missing algorithm")) - })?; - let name = javascript_crypto_subtle_algorithm_name(algorithm, &format!("crypto.subtle.{op}"))?; - if name != "AES-GCM" { - return Err(SidecarError::InvalidState(format!( - "Unsupported subtle AES operation algorithm: {name}" - ))); - } - let key = javascript_crypto_subtle_key_raw( - parsed - .get("key") - .ok_or_else(|| SidecarError::InvalidState(format!("crypto.subtle.{op} missing key")))?, - &format!("crypto.subtle.{op} key"), - )?; - let iv = algorithm.get("iv").and_then(Value::as_str).ok_or_else(|| { - SidecarError::InvalidState(format!("crypto.subtle.{op} AES-GCM missing iv")) - })?; - let iv = base64::engine::general_purpose::STANDARD - .decode(iv) - .map_err(|error| { - SidecarError::InvalidState(format!("crypto.subtle.{op} iv base64: {error}")) - })?; - let data = parsed - .get("data") - .and_then(Value::as_str) - .ok_or_else(|| SidecarError::InvalidState(format!("crypto.subtle.{op} missing data")))?; - let mut data = base64::engine::general_purpose::STANDARD - .decode(data) - .map_err(|error| { - SidecarError::InvalidState(format!("crypto.subtle.{op} data base64: {error}")) - })?; - let tag_len = javascript_crypto_subtle_aes_gcm_tag_len(algorithm)?; - let mut options = Map::new(); - options.insert(String::from("authTagLength"), json!(tag_len)); - if let Some(additional_data) = algorithm.get("additionalData").and_then(Value::as_str) { - options.insert( - String::from("aad"), - Value::String(additional_data.to_string()), - ); - } - let decrypt = op == "decrypt"; - if decrypt { - if data.len() < tag_len { - return Err(SidecarError::InvalidState(String::from( - "crypto.subtle.decrypt AES-GCM data shorter than auth tag", - ))); - } - let auth_tag = data.split_off(data.len() - tag_len); - options.insert( - String::from("authTag"), - Value::String(base64::engine::general_purpose::STANDARD.encode(auth_tag)), - ); - } - let cipher_name = format!("aes-{}-gcm", key.len() * 8); - let mut session = javascript_crypto_build_cipher_session( - &cipher_name, - &key, - Some(&iv), - decrypt, - Some(&Value::Object(options)), - )?; - let mut output = javascript_crypto_cipher_update(&mut session, &data)?; - let outcome = session.finalize().map_err(javascript_crypto_cipher_error)?; - output.extend(outcome.data); - if !decrypt { - if let Some(auth_tag) = outcome.auth_tag { - output.extend(auth_tag); - } - } - Ok(Value::String( - serde_json::to_string(&json!({ - "data": base64::engine::general_purpose::STANDARD.encode(output), - })) - .map_err(|error| { - SidecarError::InvalidState(format!("serialize crypto.subtle {op}: {error}")) - })?, - )) -} - -fn javascript_crypto_subtle_aes_gcm_tag_len(algorithm: &Value) -> Result { - let tag_bits = algorithm - .get("tagLength") - .and_then(Value::as_u64) - .unwrap_or(128); - if !tag_bits.is_multiple_of(8) { - return Err(SidecarError::InvalidState(String::from( - "crypto.subtle AES-GCM tagLength must be byte-aligned", - ))); - } - usize::try_from(tag_bits / 8).map_err(|_| { - SidecarError::InvalidState(String::from("crypto.subtle AES-GCM tagLength too large")) - }) -} - -fn service_javascript_crypto_cipheriv_inner( - request: &JavascriptSyncRpcRequest, - decrypt: bool, -) -> Result { - let label = if decrypt { - "crypto.decipheriv" - } else { - "crypto.cipheriv" - }; - let algorithm = javascript_sync_rpc_arg_str(&request.args, 0, &format!("{label} algorithm"))?; - let key = javascript_sync_rpc_base64_arg(&request.args, 1, &format!("{label} key"))?; - let iv = javascript_sync_rpc_base64_arg_optional(&request.args, 2, &format!("{label} iv"))?; - let data = javascript_sync_rpc_base64_arg(&request.args, 3, &format!("{label} data"))?; - let options = - javascript_sync_rpc_json_arg_optional(&request.args, 4, &format!("{label} options"))?; - let mut session = javascript_crypto_build_cipher_session( - algorithm, - &key, - iv.as_deref(), - decrypt, - options.as_ref(), - )?; - let payload = javascript_crypto_cipher_update(&mut session, &data)?; - let outcome = session.finalize().map_err(javascript_crypto_cipher_error)?; - if decrypt { - let mut output = payload; - output.extend(outcome.data); - return Ok(Value::String( - base64::engine::general_purpose::STANDARD.encode(output), - )); - } - - let mut response = Map::new(); - let mut encrypted = payload; - encrypted.extend(outcome.data); - response.insert( - String::from("data"), - Value::String(base64::engine::general_purpose::STANDARD.encode(encrypted)), - ); - if let Some(auth_tag) = outcome.auth_tag { - response.insert( - String::from("authTag"), - Value::String(base64::engine::general_purpose::STANDARD.encode(auth_tag)), - ); - } - Ok(Value::String(serde_json::to_string(&response).map_err( - |error| SidecarError::InvalidState(format!("serialize {label} response: {error}")), - )?)) -} - -fn javascript_sync_rpc_base64_arg_optional( - args: &[Value], - index: usize, - label: &str, -) -> Result>, SidecarError> { - if args.get(index).is_none() || args[index].is_null() { - return Ok(None); - } - javascript_sync_rpc_base64_arg(args, index, label).map(Some) -} - -fn javascript_sync_rpc_json_arg_optional( - args: &[Value], - index: usize, - label: &str, -) -> Result, SidecarError> { - if args.get(index).is_none() || args[index].is_null() { - return Ok(None); - } - let raw = javascript_sync_rpc_arg_str(args, index, label)?; - serde_json::from_str(raw) - .map(Some) - .map_err(|error| SidecarError::InvalidState(format!("{label} must be valid JSON: {error}"))) -} - -fn javascript_crypto_parse_direct_key_input( - raw: &str, - expected: Option<&str>, - label: &str, -) -> Result { - let parsed: Value = serde_json::from_str(raw).map_err(|error| { - SidecarError::InvalidState(format!("{label} must be valid JSON: {error}")) - })?; - let padding = match parsed.as_object().and_then(|value| value.get("padding")) { - Some(value) => javascript_crypto_padding_from_value(value)?, - None => None, - }; - Ok(JavascriptDirectKeyInput { - key: javascript_crypto_parse_key_material_value(&parsed, expected, label)?, - padding, - }) -} - -fn javascript_crypto_parse_key_material_value( - value: &Value, - expected: Option<&str>, - label: &str, -) -> Result { - if let Some(object) = value.as_object() { - if object.get("__type").and_then(Value::as_str) == Some("keyObject") { - let serialized = object.get("value").ok_or_else(|| { - SidecarError::InvalidState(format!("{label} keyObject is missing a value")) - })?; - return javascript_crypto_parse_serialized_key_object(serialized, expected, label); - } - if object.contains_key("type") && (object.contains_key("pem") || object.contains_key("raw")) - { - return javascript_crypto_parse_serialized_key_object(value, expected, label); - } - if let Some(source) = object.get("key") { - return javascript_crypto_parse_key_source( - source, - object.get("format").and_then(Value::as_str), - object.get("type").and_then(Value::as_str), - expected, - label, - ); - } - } - javascript_crypto_parse_key_source(value, None, None, expected, label) -} - -fn javascript_crypto_parse_key_source( - source: &Value, - format: Option<&str>, - kind: Option<&str>, - expected: Option<&str>, - label: &str, -) -> Result { - match source { - Value::String(pem) => javascript_crypto_parse_key_from_pem(pem.as_bytes(), expected, label), - Value::Object(object) if object.get("__type").and_then(Value::as_str) == Some("buffer") => { - let data = javascript_crypto_decode_bridge_buffer(source, label)?; - javascript_crypto_parse_key_from_bytes(&data, format, kind, expected, label) - } - Value::Object(_) => { - if format == Some("jwk") { - return Err(SidecarError::InvalidState(format!( - "{label} jwk inputs are not supported yet" - ))); - } - Err(SidecarError::InvalidState(format!( - "{label} has an unsupported key shape" - ))) - } - _ => Err(SidecarError::InvalidState(format!( - "{label} has an unsupported key value" - ))), - } -} - -fn javascript_crypto_parse_key_from_pem( - pem: &[u8], - expected: Option<&str>, - label: &str, -) -> Result { - match expected { - Some("private") => PKey::private_key_from_pem(pem) - .map(JavascriptCryptoKeyMaterial::Private) - .map_err(|error| { - SidecarError::InvalidState(format!("{label} private key is invalid: {error}")) - }), - Some("public") => PKey::public_key_from_pem(pem) - .map(JavascriptCryptoKeyMaterial::Public) - .map_err(|error| { - SidecarError::InvalidState(format!("{label} public key is invalid: {error}")) - }), - _ => PKey::private_key_from_pem(pem) - .map(JavascriptCryptoKeyMaterial::Private) - .or_else(|_| PKey::public_key_from_pem(pem).map(JavascriptCryptoKeyMaterial::Public)) - .map_err(|error| { - SidecarError::InvalidState(format!("{label} PEM key is invalid: {error}")) - }), - } -} - -fn javascript_crypto_parse_key_from_bytes( - der: &[u8], - format: Option<&str>, - kind: Option<&str>, - expected: Option<&str>, - label: &str, -) -> Result { - match (format.unwrap_or("der"), kind.or(expected)) { - ("der", Some("pkcs8")) | ("der", Some("private")) => PKey::private_key_from_der(der) - .map(JavascriptCryptoKeyMaterial::Private) - .map_err(|error| { - SidecarError::InvalidState(format!("{label} private key DER is invalid: {error}")) - }), - ("der", Some("spki")) | ("der", Some("public")) => PKey::public_key_from_der(der) - .map(JavascriptCryptoKeyMaterial::Public) - .map_err(|error| { - SidecarError::InvalidState(format!("{label} public key DER is invalid: {error}")) - }), - _ => Err(SidecarError::InvalidState(format!( - "{label} unsupported key bytes format" - ))), - } -} - -fn javascript_crypto_parse_serialized_key_object( - value: &Value, - expected: Option<&str>, - label: &str, -) -> Result { - let serialized: JavascriptSerializedSandboxKeyObject = serde_json::from_value(value.clone()) - .map_err(|error| { - SidecarError::InvalidState(format!("{label} keyObject is invalid: {error}")) - })?; - match serialized.kind.as_str() { - "secret" => { - if expected == Some("public") || expected == Some("private") { - return Err(SidecarError::InvalidState(format!( - "{label} expected an asymmetric key" - ))); - } - Ok(JavascriptCryptoKeyMaterial::Secret( - base64::engine::general_purpose::STANDARD - .decode(serialized.raw.unwrap_or_default()) - .map_err(|error| { - SidecarError::InvalidState(format!( - "{label} secret key contains invalid base64: {error}" - )) - })?, - )) - } - "private" => { - let pem = serialized.pem.ok_or_else(|| { - SidecarError::InvalidState(format!("{label} private keyObject is missing pem")) - })?; - javascript_crypto_parse_key_from_pem(pem.as_bytes(), Some("private"), label) - } - "public" => { - let pem = serialized.pem.ok_or_else(|| { - SidecarError::InvalidState(format!("{label} public keyObject is missing pem")) - })?; - javascript_crypto_parse_key_from_pem(pem.as_bytes(), Some("public"), label) - } - other => Err(SidecarError::InvalidState(format!( - "{label} has unsupported keyObject type {other}" - ))), - } -} - -fn javascript_crypto_expect_private_key( - key: JavascriptCryptoKeyMaterial, - label: &str, -) -> Result, SidecarError> { - match key { - JavascriptCryptoKeyMaterial::Private(key) => Ok(key), - _ => Err(SidecarError::InvalidState(format!( - "{label} requires a private key" - ))), - } -} - -fn javascript_crypto_expect_public_key( - key: JavascriptCryptoKeyMaterial, - label: &str, -) -> Result, SidecarError> { - match key { - JavascriptCryptoKeyMaterial::Public(key) => Ok(key), - JavascriptCryptoKeyMaterial::Private(key) => { - let pem = key - .public_key_to_pem() - .map_err(javascript_crypto_openssl_error)?; - PKey::public_key_from_pem(&pem).map_err(javascript_crypto_openssl_error) - } - _ => Err(SidecarError::InvalidState(format!( - "{label} requires a public key" - ))), - } -} - -fn javascript_crypto_new_signer<'a>( - algorithm: Option<&'a str>, - key: &'a PKey, -) -> Result, SidecarError> { - if matches!(key.id(), PKeyId::ED25519 | PKeyId::ED448) || algorithm.is_none() { - return Signer::new_without_digest(key).map_err(javascript_crypto_openssl_error); - } - Signer::new( - javascript_crypto_message_digest_from_name(algorithm.ok_or_else(|| { - SidecarError::InvalidState(String::from("crypto.sign requires a digest algorithm")) - })?)?, - key, - ) - .map_err(javascript_crypto_openssl_error) -} - -fn javascript_crypto_new_verifier<'a>( - algorithm: Option<&'a str>, - key: &'a PKey, -) -> Result, SidecarError> { - if matches!(key.id(), PKeyId::ED25519 | PKeyId::ED448) || algorithm.is_none() { - return Verifier::new_without_digest(key).map_err(javascript_crypto_openssl_error); - } - Verifier::new( - javascript_crypto_message_digest_from_name(algorithm.ok_or_else(|| { - SidecarError::InvalidState(String::from("crypto.verify requires a digest algorithm")) - })?)?, - key, - ) - .map_err(javascript_crypto_openssl_error) -} - -fn javascript_crypto_message_digest_from_name(name: &str) -> Result { - match name.trim().to_ascii_lowercase().replace('-', "").as_str() { - "md5" => Ok(MessageDigest::md5()), - "sha1" => Ok(MessageDigest::sha1()), - "sha256" => Ok(MessageDigest::sha256()), - "sha384" => Ok(MessageDigest::sha384()), - "sha512" => Ok(MessageDigest::sha512()), - other => Err(SidecarError::InvalidState(format!( - "unsupported crypto digest algorithm {other}" - ))), - } -} - -fn javascript_crypto_padding_from_value(value: &Value) -> Result, SidecarError> { - let Some(number) = value.as_i64() else { - return Ok(None); - }; - let padding = match number { - 1 => Padding::PKCS1, - 3 => Padding::NONE, - 4 => Padding::PKCS1_OAEP, - 6 => Padding::PKCS1_PSS, - other => { - return Err(SidecarError::InvalidState(format!( - "unsupported RSA padding constant {other}" - ))); - } - }; - Ok(Some(padding)) -} - -fn javascript_crypto_decode_bridge_buffer( - value: &Value, - label: &str, -) -> Result, SidecarError> { - decode_bridge_buffer_value(value) - .map_err(|error| SidecarError::InvalidState(format!("{label} {error}"))) -} - -fn javascript_crypto_serialize_sandbox_key_object( - key: &JavascriptCryptoKeyMaterial, -) -> Result { - let serialized = match key { - JavascriptCryptoKeyMaterial::Private(key) => JavascriptSerializedSandboxKeyObject { - kind: String::from("private"), - pem: Some( - String::from_utf8( - key.private_key_to_pem_pkcs8() - .map_err(javascript_crypto_openssl_error)?, - ) - .map_err(|error| { - SidecarError::InvalidState(format!("private key PEM is not utf8: {error}")) - })?, - ), - raw: None, - asymmetric_key_type: javascript_crypto_pkey_type_name(key.id()), - asymmetric_key_details: None, - jwk: None, - }, - JavascriptCryptoKeyMaterial::Public(key) => JavascriptSerializedSandboxKeyObject { - kind: String::from("public"), - pem: Some( - String::from_utf8( - key.public_key_to_pem() - .map_err(javascript_crypto_openssl_error)?, - ) - .map_err(|error| { - SidecarError::InvalidState(format!("public key PEM is not utf8: {error}")) - })?, - ), - raw: None, - asymmetric_key_type: javascript_crypto_pkey_type_name(key.id()), - asymmetric_key_details: None, - jwk: None, - }, - JavascriptCryptoKeyMaterial::Secret(raw) => JavascriptSerializedSandboxKeyObject { - kind: String::from("secret"), - pem: None, - raw: Some(base64::engine::general_purpose::STANDARD.encode(raw)), - asymmetric_key_type: None, - asymmetric_key_details: None, - jwk: None, - }, - }; - serde_json::to_value(serialized) - .map_err(|error| SidecarError::InvalidState(format!("serialize key object: {error}"))) -} - -fn javascript_crypto_pkey_type_name(id: PKeyId) -> Option { - match id { - PKeyId::RSA => Some(String::from("rsa")), - PKeyId::EC => Some(String::from("ec")), - PKeyId::ED25519 => Some(String::from("ed25519")), - PKeyId::ED448 => Some(String::from("ed448")), - PKeyId::X25519 => Some(String::from("x25519")), - PKeyId::X448 => Some(String::from("x448")), - PKeyId::DH => Some(String::from("dh")), - _ => None, - } -} - -fn javascript_crypto_rsa_output_size( - key: &JavascriptCryptoKeyMaterial, -) -> Result { - match key { - JavascriptCryptoKeyMaterial::Private(key) => key - .rsa() - .map(|rsa| rsa.size() as usize) - .map_err(javascript_crypto_openssl_error), - JavascriptCryptoKeyMaterial::Public(key) => key - .rsa() - .map(|rsa| rsa.size() as usize) - .map_err(javascript_crypto_openssl_error), - JavascriptCryptoKeyMaterial::Secret(_) => Err(SidecarError::InvalidState(String::from( - "RSA operations require an asymmetric key", - ))), - } -} - -fn javascript_crypto_parse_serialized_options_arg( - args: &[Value], - index: usize, - label: &str, -) -> Result, SidecarError> { - let Some(raw) = args.get(index).and_then(Value::as_str) else { - return Ok(None); - }; - let parsed: Value = serde_json::from_str(raw).map_err(|error| { - SidecarError::InvalidState(format!("{label} must be valid JSON: {error}")) - })?; - if parsed.get("hasOptions").and_then(Value::as_bool) == Some(true) { - Ok(parsed.get("options").cloned()) - } else { - Ok(None) - } -} - -fn javascript_crypto_u32_from_bridge_value( - value: &Value, - label: &str, -) -> Result { - if let Some(number) = value.as_u64() { - return u32::try_from(number) - .map_err(|_| SidecarError::InvalidState(format!("{label} must fit within u32"))); - } - let bytes = javascript_crypto_decode_bridge_buffer(value, label)?; - if bytes.len() > 4 { - return Err(SidecarError::InvalidState(format!( - "{label} buffer is too large for u32" - ))); - } - Ok(bytes - .into_iter() - .fold(0_u32, |acc, byte| (acc << 8) | u32::from(byte))) -} - -fn javascript_crypto_bignum_from_bridge_value( - value: &Value, - label: &str, -) -> Result { - if let Some(object) = value.as_object() { - if object.get("__type").and_then(Value::as_str) == Some("bigint") { - let decimal = object.get("value").and_then(Value::as_str).ok_or_else(|| { - SidecarError::InvalidState(format!("{label} bigint is missing a value")) - })?; - return BigNum::from_dec_str(decimal).map_err(javascript_crypto_openssl_error); - } - } - let bytes = javascript_crypto_decode_bridge_buffer(value, label)?; - BigNum::from_slice(&bytes).map_err(javascript_crypto_openssl_error) -} - -fn javascript_crypto_curve_nid(name: &str) -> Result { - match name { - "prime256v1" | "P-256" => Ok(Nid::X9_62_PRIME256V1), - "secp384r1" | "P-384" => Ok(Nid::SECP384R1), - "secp521r1" | "P-521" => Ok(Nid::SECP521R1), - "secp256k1" => Ok(Nid::SECP256K1), - other => Err(SidecarError::InvalidState(format!( - "unsupported EC curve {other}" - ))), - } -} - -fn javascript_crypto_named_dh_group(name: &str) -> Result, SidecarError> { - match name { - "modp2" => Dh::get_1024_160().map_err(javascript_crypto_openssl_error), - "modp14" | "modp15" | "modp16" | "modp17" | "modp18" => { - Dh::get_2048_256().map_err(javascript_crypto_openssl_error) - } - other => Err(SidecarError::InvalidState(format!( - "unsupported Diffie-Hellman group {other}" - ))), - } -} - -fn javascript_crypto_clone_dh_params(params: &Dh) -> Result, SidecarError> { - Dh::from_pqg( - params - .prime_p() - .to_owned() - .map_err(javascript_crypto_openssl_error)?, - params - .prime_q() - .map(|value| value.to_owned().map_err(javascript_crypto_openssl_error)) - .transpose()?, - params - .generator() - .to_owned() - .map_err(javascript_crypto_openssl_error)?, - ) - .map_err(javascript_crypto_openssl_error) -} - -fn javascript_crypto_build_dh_params(args: &[Value]) -> Result, SidecarError> { - let Some(first) = args.first() else { - return Err(SidecarError::InvalidState(String::from( - "Diffie-Hellman session args are required", - ))); - }; - if let Some(bits) = first.as_u64() { - let generator = args - .get(1) - .map(|value| javascript_crypto_u32_from_bridge_value(value, "Diffie-Hellman generator")) - .transpose()? - .unwrap_or(2); - return Dh::generate_params(bits as u32, generator) - .map_err(javascript_crypto_openssl_error); - } - let prime = javascript_crypto_bignum_from_bridge_value(first, "Diffie-Hellman prime")?; - let generator = args - .get(1) - .map(|value| javascript_crypto_bignum_from_bridge_value(value, "Diffie-Hellman generator")) - .transpose()? - .unwrap_or(BigNum::from_u32(2).map_err(javascript_crypto_openssl_error)?); - Dh::from_pqg(prime, None, generator).map_err(javascript_crypto_openssl_error) -} - -fn javascript_crypto_call_dh_session( - session: &mut ActiveDhSession, - method: &str, - args: &[Value], -) -> Result<(Value, bool), SidecarError> { - match method { - "verifyError" => Ok((Value::Null, false)), - "generateKeys" => { - if session.key_pair.is_none() { - session.key_pair = Some( - javascript_crypto_clone_dh_params(&session.params)? - .generate_key() - .map_err(javascript_crypto_openssl_error)?, - ); - } - let public = session - .key_pair - .as_ref() - .expect("dh key pair") - .public_key() - .to_vec(); - Ok((javascript_crypto_bridge_buffer_value(&public), true)) - } - "computeSecret" => { - if session.key_pair.is_none() { - session.key_pair = Some( - javascript_crypto_clone_dh_params(&session.params)? - .generate_key() - .map_err(javascript_crypto_openssl_error)?, - ); - } - let peer = javascript_crypto_bignum_from_bridge_value( - args.first().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "computeSecret requires peer public key", - )) - })?, - "Diffie-Hellman peer public key", - )?; - let private_key = session - .key_pair - .as_ref() - .expect("dh key pair") - .private_key(); - let mut secret = BigNum::new().map_err(javascript_crypto_openssl_error)?; - let mut ctx = BigNumContext::new().map_err(javascript_crypto_openssl_error)?; - secret - .mod_exp(&peer, private_key, session.params.prime_p(), &mut ctx) - .map_err(javascript_crypto_openssl_error)?; - Ok(( - javascript_crypto_bridge_buffer_value( - &secret - .to_vec_padded(session.params.prime_p().num_bytes()) - .map_err(javascript_crypto_openssl_error)?, - ), - true, - )) - } - "getPrime" => Ok(( - javascript_crypto_bridge_buffer_value(&session.params.prime_p().to_vec()), - true, - )), - "getGenerator" => Ok(( - javascript_crypto_bridge_buffer_value(&session.params.generator().to_vec()), - true, - )), - "getPublicKey" => { - if session.key_pair.is_none() { - session.key_pair = Some( - javascript_crypto_clone_dh_params(&session.params)? - .generate_key() - .map_err(javascript_crypto_openssl_error)?, - ); - } - Ok(( - javascript_crypto_bridge_buffer_value( - &session - .key_pair - .as_ref() - .expect("dh key pair") - .public_key() - .to_vec(), - ), - true, - )) - } - "getPrivateKey" => { - if session.key_pair.is_none() { - session.key_pair = Some( - javascript_crypto_clone_dh_params(&session.params)? - .generate_key() - .map_err(javascript_crypto_openssl_error)?, - ); - } - Ok(( - javascript_crypto_bridge_buffer_value( - &session - .key_pair - .as_ref() - .expect("dh key pair") - .private_key() - .to_vec(), - ), - true, - )) - } - "setPrivateKey" => { - let private_key = javascript_crypto_bignum_from_bridge_value( - args.first().ok_or_else(|| { - SidecarError::InvalidState(String::from("setPrivateKey requires private key")) - })?, - "Diffie-Hellman private key", - )?; - let mut public_key = BigNum::new().map_err(javascript_crypto_openssl_error)?; - let mut ctx = BigNumContext::new().map_err(javascript_crypto_openssl_error)?; - public_key - .mod_exp( - session.params.generator(), - &private_key, - session.params.prime_p(), - &mut ctx, - ) - .map_err(javascript_crypto_openssl_error)?; - session.key_pair = Some( - javascript_crypto_clone_dh_params(&session.params)? - .set_key(public_key, private_key) - .map_err(javascript_crypto_openssl_error)?, - ); - Ok((Value::Null, false)) - } - "setPublicKey" => { - let public_key = javascript_crypto_bignum_from_bridge_value( - args.first().ok_or_else(|| { - SidecarError::InvalidState(String::from("setPublicKey requires public key")) - })?, - "Diffie-Hellman public key", - )?; - let private_key = session - .key_pair - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "setPublicKey requires private key to be set first", - )) - })? - .private_key() - .to_owned() - .map_err(javascript_crypto_openssl_error)?; - session.key_pair = Some( - javascript_crypto_clone_dh_params(&session.params)? - .set_key(public_key, private_key) - .map_err(javascript_crypto_openssl_error)?, - ); - Ok((Value::Null, false)) - } - other => Err(SidecarError::InvalidState(format!( - "Unsupported Diffie-Hellman method: {other}" - ))), - } -} - -fn javascript_crypto_call_ecdh_session( - session: &mut ActiveEcdhSession, - method: &str, - args: &[Value], -) -> Result<(Value, bool), SidecarError> { - let nid = javascript_crypto_curve_nid(&session.curve)?; - let group = EcGroup::from_curve_name(nid).map_err(javascript_crypto_openssl_error)?; - match method { - "verifyError" => Ok((Value::Null, false)), - "generateKeys" => { - if session.key_pair.is_none() { - session.key_pair = - Some(EcKey::generate(&group).map_err(javascript_crypto_openssl_error)?); - } - let mut ctx = BigNumContext::new().map_err(javascript_crypto_openssl_error)?; - let bytes = session - .key_pair - .as_ref() - .expect("ecdh key pair") - .public_key() - .to_bytes(&group, PointConversionForm::UNCOMPRESSED, &mut ctx) - .map_err(javascript_crypto_openssl_error)?; - Ok((javascript_crypto_bridge_buffer_value(&bytes), true)) - } - "computeSecret" => { - if session.key_pair.is_none() { - session.key_pair = - Some(EcKey::generate(&group).map_err(javascript_crypto_openssl_error)?); - } - let peer_bytes = javascript_crypto_decode_bridge_buffer( - args.first().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "computeSecret requires peer public key", - )) - })?, - "ECDH peer public key", - )?; - let mut ctx = BigNumContext::new().map_err(javascript_crypto_openssl_error)?; - let peer_point = EcPoint::from_bytes(&group, &peer_bytes, &mut ctx) - .map_err(javascript_crypto_openssl_error)?; - let peer_key = EcKey::from_public_key(&group, &peer_point) - .map_err(javascript_crypto_openssl_error)?; - let private = - PKey::from_ec_key(session.key_pair.as_ref().expect("ecdh key pair").to_owned()) - .map_err(javascript_crypto_openssl_error)?; - let peer = PKey::from_ec_key(peer_key).map_err(javascript_crypto_openssl_error)?; - let mut deriver = Deriver::new(&private).map_err(javascript_crypto_openssl_error)?; - deriver - .set_peer(&peer) - .map_err(javascript_crypto_openssl_error)?; - let secret = deriver - .derive_to_vec() - .map_err(javascript_crypto_openssl_error)?; - Ok((javascript_crypto_bridge_buffer_value(&secret), true)) - } - "getPublicKey" => { - if session.key_pair.is_none() { - session.key_pair = - Some(EcKey::generate(&group).map_err(javascript_crypto_openssl_error)?); - } - let mut ctx = BigNumContext::new().map_err(javascript_crypto_openssl_error)?; - let bytes = session - .key_pair - .as_ref() - .expect("ecdh key pair") - .public_key() - .to_bytes(&group, PointConversionForm::UNCOMPRESSED, &mut ctx) - .map_err(javascript_crypto_openssl_error)?; - Ok((javascript_crypto_bridge_buffer_value(&bytes), true)) - } - "getPrivateKey" => { - if session.key_pair.is_none() { - session.key_pair = - Some(EcKey::generate(&group).map_err(javascript_crypto_openssl_error)?); - } - Ok(( - javascript_crypto_bridge_buffer_value( - &session - .key_pair - .as_ref() - .expect("ecdh key pair") - .private_key() - .to_vec(), - ), - true, - )) - } - "setPrivateKey" => { - let private_key = javascript_crypto_bignum_from_bridge_value( - args.first().ok_or_else(|| { - SidecarError::InvalidState(String::from("setPrivateKey requires private key")) - })?, - "ECDH private key", - )?; - let ctx = BigNumContext::new().map_err(javascript_crypto_openssl_error)?; - let mut public_key = EcPoint::new(&group).map_err(javascript_crypto_openssl_error)?; - public_key - .mul_generator(&group, &private_key, &ctx) - .map_err(javascript_crypto_openssl_error)?; - session.key_pair = Some( - EcKey::from_private_components(&group, &private_key, &public_key) - .map_err(javascript_crypto_openssl_error)?, - ); - Ok((Value::Null, false)) - } - "setPublicKey" => { - let public_key_bytes = javascript_crypto_decode_bridge_buffer( - args.first().ok_or_else(|| { - SidecarError::InvalidState(String::from("setPublicKey requires public key")) - })?, - "ECDH public key", - )?; - let mut ctx = BigNumContext::new().map_err(javascript_crypto_openssl_error)?; - let public_key = EcPoint::from_bytes(&group, &public_key_bytes, &mut ctx) - .map_err(javascript_crypto_openssl_error)?; - let private_key = session - .key_pair - .as_ref() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "setPublicKey requires private key to be set first", - )) - })? - .private_key() - .to_owned() - .map_err(javascript_crypto_openssl_error)?; - session.key_pair = Some( - EcKey::from_private_components(&group, &private_key, &public_key) - .map_err(javascript_crypto_openssl_error)?, - ); - Ok((Value::Null, false)) - } - other => Err(SidecarError::InvalidState(format!( - "Unsupported Diffie-Hellman method: {other}" - ))), - } -} - -fn javascript_crypto_serialize_encoded_key_value_public( - key: &PKey, - encoding: Option<&Value>, -) -> Result { - if let Some(encoding) = encoding { - let format = encoding - .get("format") - .and_then(Value::as_str) - .unwrap_or("pem"); - return Ok(match format { - "der" => json!({ - "kind": "buffer", - "value": base64::engine::general_purpose::STANDARD - .encode(key.public_key_to_der().map_err(javascript_crypto_openssl_error)?), - }), - _ => json!({ - "kind": "string", - "value": String::from_utf8( - key.public_key_to_pem().map_err(javascript_crypto_openssl_error)?, - ) - .map_err(|error| SidecarError::InvalidState(format!("public key PEM utf8: {error}")))?, - }), - }); - } - javascript_crypto_serialize_sandbox_key_object(&JavascriptCryptoKeyMaterial::Public( - key.to_owned(), - )) -} - -fn javascript_crypto_serialize_encoded_key_value_private( - key: &PKey, - encoding: Option<&Value>, -) -> Result { - if let Some(encoding) = encoding { - let format = encoding - .get("format") - .and_then(Value::as_str) - .unwrap_or("pem"); - return Ok(match format { - "der" => json!({ - "kind": "buffer", - "value": base64::engine::general_purpose::STANDARD - .encode(key.private_key_to_der().map_err(javascript_crypto_openssl_error)?), - }), - _ => json!({ - "kind": "string", - "value": String::from_utf8( - key.private_key_to_pem_pkcs8().map_err(javascript_crypto_openssl_error)?, - ) - .map_err(|error| SidecarError::InvalidState(format!("private key PEM utf8: {error}")))?, - }), - }); - } - javascript_crypto_serialize_sandbox_key_object(&JavascriptCryptoKeyMaterial::Private( - key.to_owned(), - )) -} - -fn javascript_crypto_bridge_buffer_value(bytes: &[u8]) -> Value { - bridge_buffer_value(bytes) -} - -fn javascript_crypto_cipher_error(error: AesCipherError) -> SidecarError { - SidecarError::InvalidState(error.0) -} - -fn javascript_crypto_decode_cipher_option_b64( - options: Option<&Value>, - field: &str, -) -> Result>, SidecarError> { - let Some(encoded) = options - .and_then(|value| value.get(field)) - .and_then(Value::as_str) - else { - return Ok(None); - }; - base64::engine::general_purpose::STANDARD - .decode(encoded) - .map(Some) - .map_err(|error| { - SidecarError::InvalidState(format!("cipher {field} contains invalid base64: {error}")) - }) -} - -fn javascript_crypto_build_cipher_session( - algorithm: &str, - key: &[u8], - iv: Option<&[u8]>, - decrypt: bool, - options: Option<&Value>, -) -> Result { - let pad = options - .and_then(|value| value.get("autoPadding")) - .and_then(Value::as_bool) - .unwrap_or(true); - let aad = if javascript_crypto_is_aead(algorithm) { - javascript_crypto_decode_cipher_option_b64(options, "aad")? - } else { - None - }; - let auth_tag = if decrypt && javascript_crypto_is_aead(algorithm) { - javascript_crypto_decode_cipher_option_b64(options, "authTag")? - } else { - None - }; - let tag_len = javascript_crypto_requested_aead_tag_len(algorithm, options)?; - StreamCipherSession::new( - algorithm, - key, - iv, - decrypt, - pad, - aad.as_deref(), - auth_tag.as_deref(), - tag_len, - ) - .map_err(javascript_crypto_cipher_error) -} - -fn javascript_crypto_requested_aead_tag_len( - algorithm: &str, - options: Option<&Value>, -) -> Result { - if !javascript_crypto_is_aead(algorithm) { - return Ok(0); - } - let requested = options - .and_then(|value| value.get("authTagLength")) - .and_then(Value::as_u64) - .unwrap_or(javascript_crypto_aead_tag_len(algorithm) as u64); - usize::try_from(requested).map_err(|_| { - SidecarError::InvalidState(String::from("cipher authTagLength must fit within usize")) - }) -} - -fn javascript_crypto_cipher_update( - session: &mut StreamCipherSession, - data: &[u8], -) -> Result, SidecarError> { - session.update(data).map_err(javascript_crypto_cipher_error) -} - -fn javascript_crypto_is_aead(algorithm: &str) -> bool { - crate::crypto_cipher::is_aead(algorithm) -} - -fn javascript_crypto_aead_tag_len(_algorithm: &str) -> usize { - crate::crypto_cipher::default_aead_tag_len() -} - -fn javascript_crypto_openssl_error(error: openssl::error::ErrorStack) -> SidecarError { - SidecarError::Execution(format!("crypto operation failed: {error}")) -} - -fn service_javascript_kernel_stdin_sync_rpc( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let (max_bytes, timeout_ms) = parse_kernel_stdin_read_args(request)?; - kernel_stdin_read_response( - kernel, - process.kernel_pid, - max_bytes, - Duration::from_millis(timeout_ms), - ) -} - -/// Parse `__kernel_stdin_read` args: (max bytes, requested timeout ms). -pub(crate) fn parse_kernel_stdin_read_args( - request: &JavascriptSyncRpcRequest, -) -> Result<(usize, u64), SidecarError> { - let max_bytes = - javascript_sync_rpc_arg_u64_optional(&request.args, 0, "__kernel_stdin_read max bytes")? - .map(|value| value.clamp(1, DEFAULT_KERNEL_STDIN_READ_MAX_BYTES as u64) as usize) - .unwrap_or(DEFAULT_KERNEL_STDIN_READ_MAX_BYTES); - let timeout_ms = - javascript_sync_rpc_arg_u64_optional(&request.args, 1, "__kernel_stdin_read timeout ms")? - .unwrap_or(DEFAULT_KERNEL_STDIN_READ_TIMEOUT_MS); - Ok((max_bytes, timeout_ms)) -} - -/// One bounded stdin read against the kernel. `Duration::ZERO` = non-blocking -/// probe (deferred servicing re-checks readiness with this before replying). -pub(crate) fn kernel_stdin_read_response( - kernel: &mut SidecarKernel, - kernel_pid: u32, - max_bytes: usize, - timeout: Duration, -) -> Result { - match kernel - .fd_read_with_timeout_result( - EXECUTION_DRIVER_NAME, - kernel_pid, - 0, - max_bytes, - Some(timeout), - ) - .map_err(kernel_error) - { - Ok(Some(chunk)) if !chunk.is_empty() => Ok(json!({ - "dataBase64": base64::engine::general_purpose::STANDARD.encode(chunk), - })), - Ok(Some(_)) => Ok(Value::Null), - Ok(None) => Ok(json!({ - "done": true, - })), - Err(SidecarError::Kernel(error)) if error.starts_with("EAGAIN:") => Ok(Value::Null), - Err(error) => Err(error), - } -} - -fn service_javascript_pty_set_raw_mode_sync_rpc( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let enabled = javascript_sync_rpc_arg_bool(&request.args, 0, "__pty_set_raw_mode enabled")?; - kernel - .pty_set_discipline( - EXECUTION_DRIVER_NAME, - process.kernel_pid, - 0, - // Match cfmakeraw: raw mode also disables output post-processing - // (OPOST/ONLCR) so a full-screen app (vim) that drives its own - // cursor/CRLF is not mangled by the line discipline; cooked mode - // re-enables it so the line shell gets LF->CRLF. - LineDisciplineConfig { - canonical: Some(!enabled), - echo: Some(!enabled), - isig: Some(!enabled), - opost: Some(!enabled), - onlcr: Some(!enabled), - }, - ) - .map_err(kernel_error)?; - Ok(Value::Null) -} - -fn service_javascript_kernel_isatty_sync_rpc( - kernel: &mut SidecarKernel, - process: &ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "__kernel_isatty fd")?; - let is_tty = kernel - .isatty(EXECUTION_DRIVER_NAME, process.kernel_pid, fd) - .map_err(kernel_error)?; - Ok(json!(is_tty)) -} - -fn service_javascript_kernel_tty_size_sync_rpc( - kernel: &mut SidecarKernel, - process: &ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "__kernel_tty_size fd")?; - let size = kernel - .pty_window_size(EXECUTION_DRIVER_NAME, process.kernel_pid, fd) - .map_err(kernel_error)?; - Ok(json!({ - "cols": size.cols, - "rows": size.rows, - })) -} - -// TODO(double-print): The recovered pre-convergence work (94e935d0) added a -// guard here because in THAT model the sidecar owned a per-process -// `tty_master_fd`, drained the PTY master into `Stdout`/`ProcessOutput` events, -// and therefore had to suppress a TTY child's own `process_output` event to -// avoid surfacing the same bytes twice (once via the child's Stdout event, once -// via the drained master). -// -// The current "real terminal client" model on main is different and does NOT -// exhibit that bug as far as I can determine: -// * `tty_master_fd` here is only a LOCAL used to derive -// `kernel_stdin_writer_fd`; there is no `ActiveProcess::tty_master_fd` -// field and no `drain_tty_master_output` — the sidecar never surfaces the -// PTY master as host `ProcessOutput` at all. The in-guest terminal client -// reads the master itself. -// * A wasm/python CHILD of a cooked-TTY JS shell is spawned WITHOUT the -// parent's PTY slave dup2'd onto its fds (the child spawn path does no -// `open_pty`/slave dup2), so the child's stdout does not flow through the -// parent's master. It is surfaced exactly once, via the `Stdout` event -// queued below. -// So there is no second surfacing path to suppress, and porting 94e935d0's -// master-drain guard would guard against a drain that no longer exists. -// -// UNRESOLVED: I could not exercise the live JS-shell-spawns-wasm-child scenario -// end-to-end to positively confirm the host sees exactly one copy; the analysis -// above is from the code paths only. If a real double-print is later observed -// for a TTY child, the fix belongs here (or at the `ProcessOutput` emission in -// `event_frame_for_execution_event`): suppress this child `Stdout` event when -// the same bytes already reach the host through a PTY master owned by an -// ancestor. Deliberately NOT fabricating that guard now, per instructions. -/// A TTY in raw mode (no echo, no canonical) — like cfmakeraw. Full-screen apps -/// (vim) run raw and drive their own cursor/CRLF, so their output must be passed -/// through untouched, NOT round-tripped through the slave->process_output->master -/// path (which buffers/reorders escape sequences and corrupts the screen). -fn tty_is_raw_mode(kernel: &SidecarKernel, process: &ActiveProcess) -> bool { - let Some(master_fd) = process.tty_master_fd else { - return false; - }; - match kernel.tcgetattr(EXECUTION_DRIVER_NAME, process.kernel_pid, master_fd) { - Ok(termios) => !termios.echo && !termios.icanon, - Err(_) => false, - } -} - -/// Non-blocking drain of the PTY master output buffer for a TTY process. -/// -/// For a TTY (PTY-backed) process the master output buffer is the single -/// ordered output stream: it carries cooked-mode echo plus ONLCR-processed -/// guest output, already merged FIFO. A zero-timeout master read returns the -/// whole current buffer (so echo and guest output stay grouped) or EAGAIN when -/// empty, which is mapped to `Ok(None)`. Returns `Ok(None)` for non-TTY -/// processes (no master fd). -pub(crate) fn drain_tty_master_output( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, -) -> Result>, SidecarError> { - let Some(master_fd) = process.tty_master_fd else { - return Ok(None); - }; - match kernel.fd_read_with_timeout_result( - EXECUTION_DRIVER_NAME, - process.kernel_pid, - master_fd, - MAX_PTY_BUFFER_BYTES, - Some(Duration::ZERO), - ) { - Ok(Some(bytes)) if !bytes.is_empty() => Ok(Some(bytes)), - Ok(_) => Ok(None), - Err(error) if error.code() == "EAGAIN" => Ok(None), - Err(error) => Err(kernel_error(error)), - } -} - -fn service_javascript_kernel_stdio_write_sync_rpc( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "__kernel_stdio_write fd")?; - let chunk = javascript_sync_rpc_bytes_arg(&request.args, 1, "__kernel_stdio_write chunk")?; - if fd != 1 && fd != 2 { - return Err(SidecarError::InvalidState(format!( - "__kernel_stdio_write only supports fd 1/2, got {fd}" - ))); - } - - // COOKED TTY (line shell): route the write through the PTY slave so it flows - // through process_output (ONLCR) into the master output buffer interleaved - // with cooked-mode echo, then surface that single ordered master stream so - // ONLCR + echo reach the host. stderr shares the master, merging onto Stdout. - let raw_mode = tty_is_raw_mode(kernel, process); - if process.tty_master_fd.is_some() && !raw_mode { - let written = if fd == 1 { - kernel - .write_process_stdout(EXECUTION_DRIVER_NAME, process.kernel_pid, &chunk) - .map_err(kernel_error)? - } else { - kernel - .write_process_stderr(EXECUTION_DRIVER_NAME, process.kernel_pid, &chunk) - .map_err(kernel_error)? - }; - if let Some(master_bytes) = drain_tty_master_output(kernel, process)? { - process.queue_pending_execution_event(ActiveExecutionEvent::Stdout(master_bytes))?; - } - return Ok(json!(written)); - } - - // RAW TTY (full-screen app) or non-TTY: emit the guest's bytes unmodified. - // For a raw TTY we must NOT write through the slave (that would fill the - // never-drained master and corrupt rendering); for non-TTY we write to the - // underlying fd so pipes/files actually receive it. - let written = if process.tty_master_fd.is_some() { - chunk.len() - } else if fd == 1 { - kernel - .write_process_stdout(EXECUTION_DRIVER_NAME, process.kernel_pid, &chunk) - .map_err(kernel_error)? - } else { - kernel - .write_process_stderr(EXECUTION_DRIVER_NAME, process.kernel_pid, &chunk) - .map_err(kernel_error)? - }; - - let event = if fd == 1 { - ActiveExecutionEvent::Stdout(chunk) - } else { - ActiveExecutionEvent::Stderr(chunk) - }; - process.queue_pending_execution_event(event)?; - - Ok(json!(written)) -} - -fn service_javascript_kernel_poll_sync_rpc( - kernel: &mut SidecarKernel, - process: &ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let (fd_requests, timeout_ms) = parse_kernel_poll_args(request)?; - kernel_poll_response(kernel, process.kernel_pid, &fd_requests, timeout_ms) -} - -/// Parse `__kernel_poll` args: (fd list, requested timeout ms). -pub(crate) fn parse_kernel_poll_args( - request: &JavascriptSyncRpcRequest, -) -> Result<(Vec, i32), SidecarError> { - let fd_requests: Vec = serde_json::from_value( - request - .args - .first() - .cloned() - .unwrap_or_else(|| Value::Array(Vec::new())), - ) - .map_err(|error| { - SidecarError::InvalidState(format!( - "__kernel_poll fd list must be a JSON array of {{ fd, events }} objects: {error}" - )) - })?; - let timeout_ms = - javascript_sync_rpc_arg_u64_optional(&request.args, 1, "__kernel_poll timeout ms")? - .unwrap_or_default(); - let timeout_ms = i32::try_from(timeout_ms).map_err(|_| { - SidecarError::InvalidState(String::from("__kernel_poll timeout ms must fit within i32")) - })?; - Ok((fd_requests, timeout_ms)) -} - -/// One bounded kernel poll. Timeout `0` = non-blocking probe (deferred -/// servicing re-checks readiness with this before replying). -pub(crate) fn kernel_poll_response( - kernel: &SidecarKernel, - kernel_pid: u32, - fd_requests: &[KernelPollFdRequest], - timeout_ms: i32, -) -> Result { - let poll_fds = fd_requests - .iter() - .map(|entry| PollFd { - fd: entry.fd, - events: PollEvents::from_bits(entry.events), - revents: PollEvents::empty(), - }) - .collect::>(); - let result = kernel - .poll_fds(EXECUTION_DRIVER_NAME, kernel_pid, poll_fds, timeout_ms) - .map_err(kernel_error)?; - Ok(json!({ - "readyCount": result.ready_count, - "fds": result - .fds - .into_iter() - .map(|entry| KernelPollFdResponse { - fd: entry.fd, - events: entry.events.bits(), - revents: entry.revents.bits(), - }) - .collect::>(), - })) -} - -fn install_kernel_stdin_pipe(kernel: &mut SidecarKernel, pid: u32) -> Result { - let (read_fd, write_fd) = kernel - .open_pipe(EXECUTION_DRIVER_NAME, pid) - .map_err(kernel_error)?; - kernel - .fd_dup2(EXECUTION_DRIVER_NAME, pid, read_fd, 0) - .map_err(kernel_error)?; - kernel - .fd_close(EXECUTION_DRIVER_NAME, pid, read_fd) - .map_err(kernel_error)?; - Ok(write_fd) -} - -fn requested_pty_window_size(env: &BTreeMap) -> Option<(u16, u16)> { - let cols = env - .get("COLUMNS") - .and_then(|value| value.parse::().ok()) - .filter(|value| *value > 0)?; - let rows = env - .get("LINES") - .and_then(|value| value.parse::().ok()) - .filter(|value| *value > 0)?; - Some((cols, rows)) -} - -fn javascript_child_process_stdin_mode(request: &JavascriptChildProcessSpawnRequest) -> &str { - request - .options - .stdio - .first() - .map(String::as_str) - .unwrap_or("pipe") -} - -pub(crate) fn write_kernel_process_stdin( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - chunk: &[u8], -) -> Result<(), SidecarError> { - // Non-TTY JavaScript uses the in-process local stdin bridge, not a kernel - // fd; a TTY JavaScript process (tty_master_fd set) DOES route through the - // kernel PTY master, exactly like wasm/python, so line discipline + echo - // apply. - if process.runtime == GuestRuntimeKind::JavaScript && process.tty_master_fd.is_none() { - return Ok(()); - } - let Some(writer_fd) = process.kernel_stdin_writer_fd else { - return Ok(()); - }; - kernel - .fd_write(EXECUTION_DRIVER_NAME, process.kernel_pid, writer_fd, chunk) - .map_err(kernel_error)?; - // For a TTY process the master write above drives line-discipline echo into - // the master output buffer. Drain it now and surface it as the single - // ordered Stdout stream so typed-character echo reaches the host even while - // the guest is blocked in read() and not producing output of its own. - if let Some(echo) = drain_tty_master_output(kernel, process)? { - process.queue_pending_execution_event(ActiveExecutionEvent::Stdout(echo))?; - } - forward_tty_slave_input_to_javascript(kernel, process)?; - Ok(()) -} - -/// For a TTY JavaScript guest, cooked input becomes readable on the PTY slave -/// only after line discipline runs (on newline/VEOF in canonical mode; every -/// byte in raw mode). The V8 isolate has no kernel-fd read loop of its own — -/// its stdin is the stream-stdin dispatch fed by `execution.write_stdin` — so -/// right after each master write, drain whatever the discipline released on -/// the slave (fd 0) and forward it to the isolate. A `None` read is the -/// discipline's VEOF: propagate it as end-of-stdin so `process.stdin` emits -/// `end`. Wasm/python guests read the slave themselves and are skipped. -fn forward_tty_slave_input_to_javascript( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, -) -> Result<(), SidecarError> { - if process.tty_master_fd.is_none() - || !matches!(process.execution, ActiveExecution::Javascript(_)) - { - return Ok(()); - } - loop { - match kernel.fd_read_with_timeout_result( - EXECUTION_DRIVER_NAME, - process.kernel_pid, - 0, - MAX_PTY_BUFFER_BYTES, - Some(Duration::ZERO), - ) { - Ok(Some(bytes)) if !bytes.is_empty() => { - process.execution.write_stdin(&bytes)?; - } - Ok(Some(_)) => return Ok(()), - Ok(None) => { - process.execution.close_stdin()?; - return Ok(()); - } - Err(error) if error.code() == "EAGAIN" => return Ok(()), - Err(error) => return Err(kernel_error(error)), - } - } -} - -pub(crate) fn close_kernel_process_stdin( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, -) -> Result<(), SidecarError> { - let Some(writer_fd) = process.kernel_stdin_writer_fd.take() else { - return Ok(()); - }; - kernel - .fd_close(EXECUTION_DRIVER_NAME, process.kernel_pid, writer_fd) - .map_err(kernel_error) -} - -fn parse_http_header_collection( - headers: &BTreeMap, - label: &str, -) -> Result { - let mut normalized = BTreeMap::>::new(); - let mut raw_pairs = Vec::new(); - - for (raw_name, value) in headers { - let normalized_name = raw_name.to_ascii_lowercase(); - let values = match value { - Value::String(text) => vec![text.clone()], - Value::Array(values) => values - .iter() - .map(|entry| { - entry.as_str().map(str::to_owned).ok_or_else(|| { - SidecarError::InvalidState(format!( - "{label} header {raw_name} must contain only strings" - )) - }) - }) - .collect::, _>>()?, - other => { - return Err(SidecarError::InvalidState(format!( - "{label} header {raw_name} must be a string or string array, received {other}" - ))); - } - }; - raw_pairs.extend( - values - .iter() - .cloned() - .map(|entry| (raw_name.clone(), entry)), - ); - normalized - .entry(normalized_name) - .or_default() - .extend(values); - } - - Ok(HttpHeaderCollection { - normalized, - raw_pairs, - }) -} - -fn http_headers_json(headers: &HttpHeaderCollection) -> Value { - let map = headers - .normalized - .iter() - .map(|(name, values)| { - let value = if values.len() == 1 { - Value::String(values[0].clone()) - } else { - Value::Array(values.iter().cloned().map(Value::String).collect()) - }; - (name.clone(), value) - }) - .collect::>(); - Value::Object(map) -} - -fn http_raw_headers_json(headers: &HttpHeaderCollection) -> Value { - Value::Array( - headers - .raw_pairs - .iter() - .flat_map(|(name, value)| [Value::String(name.clone()), Value::String(value.clone())]) - .collect(), - ) -} - -fn is_loopback_request_host(host: &str) -> bool { - let bare = host - .strip_prefix('[') - .and_then(|value| value.strip_suffix(']')) - .unwrap_or(host); - matches!(bare, "localhost" | "127.0.0.1" | "::1") -} - -fn serialize_http_loopback_request( - url: &Url, - options: &JavascriptHttpRequestOptions, - headers: &HttpHeaderCollection, -) -> Result { - let body_base64 = options - .body - .as_ref() - .map(|body| base64::engine::general_purpose::STANDARD.encode(body.as_bytes())); - serde_json::to_string(&json!({ - "method": options.method.clone().unwrap_or_else(|| String::from("GET")), - "url": http_request_target(url), - "headers": http_headers_json(headers), - "rawHeaders": http_raw_headers_json(headers), - "bodyBase64": body_base64, - })) - .map_err(|error| SidecarError::Execution(format!("ERR_AGENTOS_NODE_SYNC_RPC: {error}"))) -} - -fn http_request_target(url: &Url) -> String { - let path = if url.path().is_empty() { - "/" - } else { - url.path() - }; - format!( - "{path}{}", - url.query() - .map(|query| format!("?{query}")) - .unwrap_or_default() - ) -} - -fn find_kernel_http_listener_process(vm: &VmState, port: u16) -> Option { - vm.active_processes - .iter() - .find_map(|(process_id, process)| { - process.tcp_listeners.values().find_map(|listener| { - let socket_id = listener.kernel_socket_id?; - let record = vm.kernel.socket_get(socket_id)?; - let local_addr = record - .local_address() - .and_then(|address| resolve_tcp_bind_addr(address.host(), address.port()).ok()) - .unwrap_or_else(|| listener.guest_local_addr()); - if local_addr.port() == port && is_vm_local_http_listener_addr(local_addr.ip()) { - Some(process_id.to_owned()) - } else { - None - } - }) - }) -} - -fn is_vm_local_http_listener_addr(ip: IpAddr) -> bool { - ip.is_loopback() || ip.is_unspecified() -} - -fn serialize_kernel_http_fetch_request( - port: u16, - path: &str, - options: &JavascriptHttpRequestOptions, - headers: &HttpHeaderCollection, -) -> Vec { - let method = options.method.as_deref().unwrap_or("GET"); - let mut lines = vec![format!("{method} {path} HTTP/1.1")]; - let mut has_host = false; - let mut has_connection = false; - let mut has_content_length = false; - for (name, values) in &headers.normalized { - match name.as_str() { - "host" => has_host = true, - "connection" => has_connection = true, - "content-length" => has_content_length = true, - _ => {} - } - lines.push(format!("{name}: {}", values.join(", "))); - } - if !has_host { - lines.push(format!("Host: 127.0.0.1:{port}")); - } - if !has_connection { - lines.push(String::from("Connection: close")); - } - let body = options.body.as_deref().unwrap_or("").as_bytes(); - if !has_content_length && !body.is_empty() { - lines.push(format!("Content-Length: {}", body.len())); - } - lines.push(String::new()); - lines.push(String::new()); - - let mut request = lines.join("\r\n").into_bytes(); - request.extend_from_slice(body); - request -} - -fn kernel_http_fetch_target_exit_code(error: &SidecarError) -> Option { - let SidecarError::Execution(message) = error else { - return None; - }; - message - .strip_prefix("vm.fetch target exited before responding (exit code ")? - .strip_suffix(')')? - .parse() - .ok() -} - -#[allow(clippy::too_many_arguments)] -fn service_host_fetch_target_event( - bridge: &SharedBridge, - vm_id: &str, - dns: &VmDnsConfig, - socket_paths: &JavascriptSocketPathContext, - kernel: &mut SidecarKernel, - kernel_readiness: &KernelSocketReadinessRegistry, - process: &mut ActiveProcess, - resource_limits: &ResourceLimits, - wait: Duration, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let Some(event) = process - .execution - .poll_event_blocking(wait) - .map_err(|error| SidecarError::Execution(error.to_string()))? - else { - return Ok(false); - }; - - match event { - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) => { - let network_counts = process.network_resource_counts(); - let response = service_javascript_sync_rpc(JavascriptSyncRpcServiceRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness: Arc::clone(kernel_readiness), - process, - sync_request: &request, - resource_limits, - network_counts, - }); - match response { - Ok(result) => process - .execution - .respond_javascript_sync_rpc_response(request.id, result) - .or_else(ignore_stale_javascript_sync_rpc_response)?, - Err(error) => process - .execution - .respond_javascript_sync_rpc_error( - request.id, - javascript_sync_rpc_error_code(&error), - error.to_string(), - ) - .or_else(ignore_stale_javascript_sync_rpc_response)?, - } - } - ActiveExecutionEvent::Exited(code) => { - return Err(SidecarError::Execution(format!( - "vm.fetch target exited before responding (exit code {code})" - ))); - } - other => { - process.queue_pending_execution_event(other)?; - } - } - Ok(true) -} - -fn drain_host_fetch_target_events( - bridge: &SharedBridge, - vm_id: &str, - vm: &mut VmState, - target_process_id: &str, - socket_paths: &JavascriptSocketPathContext, - resource_limits: &ResourceLimits, -) -> Result<(), SidecarError> -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - for _ in 0..32 { - let dns = vm.dns.clone(); - let kernel_readiness = Arc::clone(&vm.kernel_socket_readiness); - let Some(process) = vm.active_processes.get_mut(target_process_id) else { - break; - }; - let serviced = service_host_fetch_target_event( - bridge, - vm_id, - &dns, - socket_paths, - &mut vm.kernel, - &kernel_readiness, - process, - resource_limits, - Duration::from_millis(1), - )?; - if !serviced { - break; - } - } - Ok(()) -} - -#[allow(clippy::too_many_arguments)] -fn dispatch_kernel_http_fetch( - bridge: &SharedBridge, - vm_id: &str, - vm: &mut VmState, - target_process_id: &str, - port: u16, - path: &str, - options: &JavascriptHttpRequestOptions, - headers: &HttpHeaderCollection, - max_fetch_response_bytes: usize, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let socket_paths = build_javascript_socket_path_context(vm)?; - let family = JavascriptSocketFamily::Ipv4; - let local_port = allocate_guest_listen_port( - 0, - family, - &socket_paths.used_tcp_guest_ports, - socket_paths.listen_policy, - )?; - let resource_limits = vm.kernel.resource_limits().clone(); - let network_counts = vm_network_resource_counts(vm); - check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 2, - "socket", - )?; - check_network_resource_limit( - resource_limits.max_connections, - network_counts.connections, - 2, - "connection", - )?; - - let kernel_pid = vm - .active_processes - .get(target_process_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "vm.fetch target process disappeared: {target_process_id}" - )) - })? - .kernel_pid; - let socket_id = vm - .kernel - .socket_create(EXECUTION_DRIVER_NAME, kernel_pid, SocketSpec::tcp()) - .map_err(kernel_error)?; - - let result = dispatch_kernel_http_fetch_with_socket( - bridge, - vm_id, - vm, - target_process_id, - kernel_pid, - socket_id, - local_port, - port, - path, - options, - headers, - &socket_paths, - &resource_limits, - max_fetch_response_bytes, - ); - let close_result = vm - .kernel - .socket_close(EXECUTION_DRIVER_NAME, kernel_pid, socket_id) - .map_err(kernel_error); - let cleanup_result = if result.is_err() { - drain_host_fetch_target_events( - bridge, - vm_id, - vm, - target_process_id, - &socket_paths, - &resource_limits, - ) - } else { - Ok(()) - }; - match (result, close_result) { - (Ok(response), Ok(())) => cleanup_result.map(|()| response), - (Err(error), _) => Err(error), - (Ok(_), Err(error)) => Err(error), - } -} - -#[allow(clippy::too_many_arguments)] -fn dispatch_kernel_http_fetch_with_socket( - bridge: &SharedBridge, - vm_id: &str, - vm: &mut VmState, - target_process_id: &str, - kernel_pid: u32, - socket_id: SocketId, - local_port: u16, - port: u16, - path: &str, - options: &JavascriptHttpRequestOptions, - headers: &HttpHeaderCollection, - socket_paths: &JavascriptSocketPathContext, - resource_limits: &ResourceLimits, - max_fetch_response_bytes: usize, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - vm.kernel - .socket_bind_inet( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - InetSocketAddress::new("127.0.0.1", local_port), - ) - .map_err(kernel_error)?; - vm.kernel - .socket_connect_inet_loopback( - EXECUTION_DRIVER_NAME, - kernel_pid, - socket_id, - InetSocketAddress::new("127.0.0.1", port), - ) - .map_err(kernel_error)?; - - let request_bytes = serialize_kernel_http_fetch_request(port, path, options, headers); - vm.kernel - .socket_write(EXECUTION_DRIVER_NAME, kernel_pid, socket_id, &request_bytes) - .map_err(kernel_error)?; - - let mut response_buffer = Vec::new(); - let mut peer_closed = false; - let url = format!("http://127.0.0.1:{port}{path}"); - let deadline = Instant::now() + http_loopback_request_timeout(); - loop { - if let Some(response) = - parse_kernel_http_fetch_response(&response_buffer, peer_closed, &url) - .map_err(sidecar_core_execution_error)? - { - ensure_vm_fetch_response_within_limit(&response, "vm.fetch", max_fetch_response_bytes) - .map_err(sidecar_core_execution_error)?; - return Ok(response); - } - if Instant::now() >= deadline { - let preview = String::from_utf8_lossy(&response_buffer); - return Err(SidecarError::Execution(format!( - "vm.fetch timed out waiting for kernel TCP HTTP response ({} buffered bytes: {:?})", - response_buffer.len(), - preview.chars().take(200).collect::() - ))); - } - - { - let dns = vm.dns.clone(); - let kernel_readiness = Arc::clone(&vm.kernel_socket_readiness); - let process = vm - .active_processes - .get_mut(target_process_id) - .ok_or_else(|| { - SidecarError::InvalidState(format!( - "vm.fetch target process disappeared: {target_process_id}" - )) - })?; - service_host_fetch_target_event( - bridge, - vm_id, - &dns, - socket_paths, - &mut vm.kernel, - &kernel_readiness, - process, - resource_limits, - Duration::from_millis(5), - )?; - } - - let poll = vm - .kernel - .poll_targets( - EXECUTION_DRIVER_NAME, - kernel_pid, - vec![PollTargetEntry::socket( - socket_id, - POLLIN | POLLHUP | POLLERR, - )], - 5, - ) - .map_err(kernel_error)?; - let revents = poll - .targets - .first() - .map(|entry| entry.revents) - .unwrap_or_else(PollEvents::empty); - if revents.intersects(POLLERR) { - return Err(SidecarError::Execution(String::from( - "vm.fetch kernel TCP socket reported POLLERR", - ))); - } - if revents.intersects(POLLIN) { - loop { - match vm - .kernel - .socket_read(EXECUTION_DRIVER_NAME, kernel_pid, socket_id, 64 * 1024) - { - Ok(Some(bytes)) if !bytes.is_empty() => { - response_buffer.extend(bytes); - ensure_vm_fetch_raw_response_buffer_within_limit( - response_buffer.len(), - "vm.fetch", - ) - .map_err(sidecar_core_execution_error)?; - } - Ok(Some(_)) => break, - Ok(None) => { - peer_closed = true; - break; - } - Err(error) if error.code() == "EAGAIN" => break, - Err(error) => return Err(kernel_error(error)), - } - } - } - if revents.intersects(POLLHUP) { - peer_closed = true; - } - } -} - -fn outbound_http_response_json(url: &Url, response: ureq::Response) -> Result { - let status = response.status(); - let status_text = response.status_text().to_owned(); - let mut header_pairs = Vec::new(); - let mut raw_headers = Vec::new(); - for raw_name in response.headers_names() { - for value in response.all(&raw_name) { - header_pairs.push(json!([raw_name.to_ascii_lowercase(), value])); - raw_headers.push(Value::String(raw_name.clone())); - raw_headers.push(Value::String(value.to_owned())); - } - } - let mut reader = response.into_reader(); - let mut body = Vec::new(); - reader.read_to_end(&mut body).map_err(|error| { - SidecarError::Execution(format!("failed to read HTTP response: {error}")) - })?; - serde_json::to_string(&json!({ - "status": status, - "statusText": status_text, - "headers": header_pairs, - "rawHeaders": raw_headers, - "body": base64::engine::general_purpose::STANDARD.encode(body), - "bodyEncoding": "base64", - "url": url.as_str(), - })) - .map(Value::String) - .map_err(|error| SidecarError::Execution(format!("ERR_AGENTOS_NODE_SYNC_RPC: {error}"))) -} - -/// Split a ureq resolver `netloc` (`host:port`, with optional `[..]` IPv6 -/// brackets) into its host and port components. Returns `None` if the port is -/// missing or unparseable. -fn split_netloc(netloc: &str) -> Option<(&str, u16)> { - let (host, port) = netloc.rsplit_once(':')?; - let port: u16 = port.parse().ok()?; - let host = host - .strip_prefix('[') - .and_then(|rest| rest.strip_suffix(']')) - .unwrap_or(host); - Some((host, port)) -} - -fn issue_outbound_http_request( - url: &Url, - options: &JavascriptHttpRequestOptions, - headers: &HttpHeaderCollection, - pinned_addresses: &[IpAddr], -) -> Result { - let method = options.method.as_deref().unwrap_or("GET"); - // Pin the underlying resolver to the egress-vetted addresses. ureq performs - // its own DNS resolution for the TCP/TLS connect; without this override an - // https:// request would re-resolve the hostname through the host resolver - // (a rebinding DNS server could then return a private/metadata IP that the - // earlier range check would have rejected). The pinned resolver returns only - // the vetted addresses and refuses any host it was not vetted for, while the - // request URL keeps the original hostname so TLS SNI and the Host header stay - // correct. - let pinned_host = url.host_str().map(str::to_owned); - let pinned: Vec = pinned_addresses.to_vec(); - let resolver = move |netloc: &str| -> std::io::Result> { - let (host, port) = split_netloc(netloc).ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidInput, - format!("invalid network location: {netloc}"), - ) - })?; - let expected_host = pinned_host.as_deref(); - if expected_host != Some(host) { - return Err(std::io::Error::new( - std::io::ErrorKind::PermissionDenied, - format!( - "EACCES: outbound HTTP resolver pinned to {expected_host:?}, refusing {host}" - ), - )); - } - if pinned.is_empty() { - return Err(std::io::Error::new( - std::io::ErrorKind::PermissionDenied, - "EACCES: no egress-vetted address available for outbound HTTP request", - )); - } - Ok(pinned.iter().map(|ip| SocketAddr::new(*ip, port)).collect()) - }; - let mut agent_builder = ureq::AgentBuilder::new() - .resolver(resolver) - .timeout_connect(Duration::from_secs(5)) - .timeout_read(Duration::from_secs(15)) - .timeout_write(Duration::from_secs(15)); - if url.scheme() == "https" { - let tls_options = JavascriptTlsBridgeOptions { - is_server: false, - servername: url.host_str().map(str::to_owned), - alpn_protocols: Some(vec![String::from("http/1.1")]), - reject_unauthorized: options.reject_unauthorized, - ..JavascriptTlsBridgeOptions::default() - }; - agent_builder = agent_builder.tls_config(Arc::new(build_client_tls_config(&tls_options)?)); - } - let agent = agent_builder.build(); - let mut request = agent.request_url(method, url); - for (name, values) in &headers.normalized { - if name == "host" { - continue; - } - let header_value = values.join(", "); - request = request.set(name, &header_value); - } - let response = match options.body.as_deref() { - Some(body) => request.send_string(body), - None => request.call(), - }; - - match response { - Ok(response) => outbound_http_response_json(url, response), - Err(ureq::Error::Status(_, response)) => outbound_http_response_json(url, response), - Err(ureq::Error::Transport(error)) => Err(SidecarError::Execution(format!( - "ERR_HTTP_REQUEST_FAILED: {error}" - ))), - } -} - -fn wait_for_loopback_http_response( - request: LoopbackHttpResponseWaitRequest<'_, B>, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let LoopbackHttpResponseWaitRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness, - process, - resource_limits, - request_key, - } = request; - let deadline = Instant::now() + http_loopback_request_timeout(); - loop { - if let Some(response) = process - .pending_http_requests - .get(&request_key) - .and_then(|response| response.clone()) - { - process.pending_http_requests.remove(&request_key); - return Ok(response); - } - - if Instant::now() >= deadline { - process.pending_http_requests.remove(&request_key); - return Err(SidecarError::Execution(String::from( - "HTTP loopback request timed out waiting for net.http_respond", - ))); - } - - let Some(event) = process - .execution - .poll_event_blocking(Duration::from_millis(10)) - .map_err(|error| SidecarError::Execution(error.to_string()))? - else { - continue; - }; - - match event { - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) => { - let network_counts = process.network_resource_counts(); - let response = service_javascript_sync_rpc(JavascriptSyncRpcServiceRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness: Arc::clone(&kernel_readiness), - process, - sync_request: &request, - resource_limits, - network_counts, - }); - match response { - Ok(result) => process - .execution - .respond_javascript_sync_rpc_response(request.id, result) - .or_else(ignore_stale_javascript_sync_rpc_response)?, - Err(error) => process - .execution - .respond_javascript_sync_rpc_error( - request.id, - javascript_sync_rpc_error_code(&error), - error.to_string(), - ) - .or_else(ignore_stale_javascript_sync_rpc_response)?, - } - } - ActiveExecutionEvent::Exited(code) => { - process.pending_http_requests.remove(&request_key); - return Err(SidecarError::Execution(format!( - "HTTP loopback server exited before responding (exit code {code})" - ))); - } - ActiveExecutionEvent::Stdout(_) - | ActiveExecutionEvent::Stderr(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } => {} - } - } -} - -pub(crate) fn dispatch_loopback_http_request( - request: LoopbackHttpDispatchRequest<'_, B>, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let LoopbackHttpDispatchRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness, - process, - resource_limits, - server_id, - request_json, - } = request; - let request_id = { - let server = process.http_servers.get_mut(&server_id).ok_or_else(|| { - SidecarError::InvalidState(format!("HTTP target server disappeared: {server_id}")) - })?; - server.next_request_id += 1; - server.next_request_id - }; - process - .pending_http_requests - .insert((server_id, request_id), None); - process.execution.send_javascript_stream_event( - "http_request", - json!({ - "serverId": server_id, - "requestId": request_id, - "request": request_json, - }), - )?; - wait_for_loopback_http_response(LoopbackHttpResponseWaitRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness, - process, - resource_limits, - request_key: (server_id, request_id), - }) -} - -fn sidecar_core_execution_error(error: SidecarCoreError) -> SidecarError { - SidecarError::Execution(error.to_string()) -} - -pub(crate) fn ensure_vm_fetch_response_frame_within_limit( - response: &ResponseFrame, - max_frame_bytes: usize, -) -> Result<(), SidecarError> { - let max_frame_bytes = max_frame_bytes.min(VM_FETCH_BUFFER_LIMIT_BYTES); - let frame = crate::protocol::to_generated_protocol_frame( - &crate::protocol::ProtocolFrame::Response(response.clone()), - ) - .map_err(|error| SidecarError::FrameTooLarge(error.to_string()))?; - let WireProtocolFrame::ResponseFrame(_) = &frame else { - return Err(SidecarError::FrameTooLarge(String::from( - "vm fetch response converted to non-response wire frame", - ))); - }; - WireFrameCodec::new(max_frame_bytes) - .encode(&frame) - .map(|_| ()) - .map_err(|error| SidecarError::FrameTooLarge(error.to_string())) -} - -fn service_javascript_dns_sync_rpc( - bridge: &SharedBridge, - kernel: &SidecarKernel, - vm_id: &str, - dns: &VmDnsConfig, - request: &JavascriptSyncRpcRequest, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - match request.method.as_str() { - "dns.lookup" => { - let payload = request - .args - .first() - .cloned() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "dns.lookup requires a request payload", - )) - }) - .and_then(|value| { - serde_json::from_value::(value).map_err(|error| { - SidecarError::InvalidState(format!("invalid dns.lookup payload: {error}")) - }) - })?; - let addresses = filter_dns_ip_addrs( - resolve_dns_ip_addrs( - bridge, - kernel, - vm_id, - dns, - &payload.hostname, - DnsLookupPolicy::CheckPermissions, - )?, - payload.family, - )?; - let addresses = filter_dns_safe_ip_addrs(addresses, &payload.hostname)?; - Ok(Value::Array( - addresses - .into_iter() - .map(|ip| { - json!({ - "address": ip.to_string(), - "family": if ip.is_ipv6() { 6 } else { 4 }, - }) - }) - .collect(), - )) - } - "dns.resolve" | "dns.resolve4" | "dns.resolve6" => { - let payload = request - .args - .first() - .cloned() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "dns.resolve requires a request payload", - )) - }) - .and_then(|value| { - serde_json::from_value::(value).map_err(|error| { - SidecarError::InvalidState(format!("invalid dns.resolve payload: {error}")) - }) - })?; - let requested_type = match request.method.as_str() { - "dns.resolve4" => String::from("A"), - "dns.resolve6" => String::from("AAAA"), - _ => payload - .rrtype - .as_deref() - .unwrap_or("A") - .to_ascii_uppercase(), - }; - let record_type = parse_dns_record_type(&requested_type)?; - let resolution = resolve_dns_records( - bridge, - kernel, - vm_id, - dns, - &payload.hostname, - record_type, - DnsLookupPolicy::CheckPermissions, - )?; - dns_resolution_to_node_value(&resolution, &requested_type) - } - other => Err(SidecarError::InvalidState(format!( - "unsupported JavaScript dns sync RPC method {other}" - ))), - } -} - -fn service_javascript_dgram_sync_rpc( - request: JavascriptDgramSyncRpcServiceRequest<'_, B>, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let JavascriptDgramSyncRpcServiceRequest { - bridge, - kernel, - vm_id, - dns, - socket_paths, - process, - kernel_readiness, - sync_request: request, - resource_limits, - network_counts, - } = request; - match request.method.as_str() { - "dgram.createSocket" => { - check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - )?; - let payload = request - .args - .first() - .cloned() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "dgram.createSocket requires a request payload", - )) - }) - .and_then(|value| { - serde_json::from_value::(value).map_err( - |error| { - SidecarError::InvalidState(format!( - "invalid dgram.createSocket payload: {error}" - )) - }, - ) - })?; - let family = JavascriptUdpFamily::from_socket_type(&payload.socket_type)?; - let socket_id = process.allocate_udp_socket_id(); - let socket = ActiveUdpSocket::new(kernel, process.kernel_pid, family)?; - register_kernel_readiness_target( - &kernel_readiness, - socket.kernel_socket_id, - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - KernelSocketReadinessEvent::Datagram, - ); - process.udp_sockets.insert(socket_id.clone(), socket); - Ok(json!({ - "socketId": socket_id, - "type": family.socket_type(), - })) - } - "dgram.bind" => { - let socket_id = javascript_sync_rpc_arg_str(&request.args, 0, "dgram.bind socket id")?; - let payload = request - .args - .get(1) - .cloned() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "dgram.bind requires a request payload", - )) - }) - .and_then(|value| { - serde_json::from_value::(value).map_err(|error| { - SidecarError::InvalidState(format!("invalid dgram.bind payload: {error}")) - }) - })?; - let socket = process.udp_sockets.get_mut(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown UDP socket {socket_id}")) - })?; - let local_addr = socket.bind( - kernel, - process.kernel_pid, - payload.address.as_deref(), - payload.port, - socket_paths, - )?; - Ok(local_endpoint_value(&local_addr)) - } - "dgram.send" => { - let socket_id = javascript_sync_rpc_arg_str(&request.args, 0, "dgram.send socket id")?; - let chunk = javascript_sync_rpc_bytes_arg(&request.args, 1, "dgram.send payload")?; - let payload = request - .args - .get(2) - .cloned() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "dgram.send requires a request payload", - )) - }) - .and_then(|value| { - serde_json::from_value::(value).map_err(|error| { - SidecarError::InvalidState(format!("invalid dgram.send payload: {error}")) - }) - })?; - let socket = process.udp_sockets.get_mut(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown UDP socket {socket_id}")) - })?; - let (written, local_addr) = socket.send_to(ActiveUdpSendToRequest { - bridge, - kernel, - kernel_pid: process.kernel_pid, - vm_id, - dns, - host: payload.address.as_deref().unwrap_or("localhost"), - port: payload.port, - context: socket_paths, - contents: &chunk, - })?; - Ok(json!({ - "bytes": written, - "localAddress": local_addr.ip().to_string(), - "localPort": local_addr.port(), - "family": socket_addr_family(&local_addr), - })) - } - "dgram.poll" => { - let socket_id = javascript_sync_rpc_arg_str(&request.args, 0, "dgram.poll socket id")?; - let wait_ms = - javascript_sync_rpc_arg_u64_optional(&request.args, 1, "dgram.poll wait ms")? - .unwrap_or_default(); - let event = { - let socket = process.udp_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown UDP socket {socket_id}")) - })?; - socket.poll(kernel, process.kernel_pid, Duration::from_millis(wait_ms))? - }; - - match event { - Some(JavascriptUdpSocketEvent::Message { data, remote_addr }) => { - let family = JavascriptSocketFamily::from_ip(remote_addr.ip()); - let guest_remote_port = if is_loopback_ip(remote_addr.ip()) { - socket_paths - .guest_udp_port_for_host_port(family, remote_addr.port()) - .unwrap_or(remote_addr.port()) - } else { - remote_addr.port() - }; - let mut response = remote_endpoint_value(&remote_addr, guest_remote_port); - if let Value::Object(fields) = &mut response { - fields.insert(String::from("type"), Value::String(String::from("message"))); - fields.insert(String::from("data"), javascript_sync_rpc_bytes_value(&data)); - } - Ok(response) - } - Some(JavascriptUdpSocketEvent::Error { code, message }) => Ok(json!({ - "type": "error", - "code": code, - "message": message, - })), - None => Ok(Value::Null), - } - } - "dgram.close" => { - let socket_id = javascript_sync_rpc_arg_str(&request.args, 0, "dgram.close socket id")?; - let mut socket = process.udp_sockets.remove(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown UDP socket {socket_id}")) - })?; - unregister_kernel_readiness_target(&kernel_readiness, socket.kernel_socket_id); - socket.close(kernel, process.kernel_pid); - Ok(Value::Null) - } - "dgram.address" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "dgram.address socket id")?; - let socket = process.udp_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown UDP socket {socket_id}")) - })?; - let local_addr = socket.local_addr().ok_or_else(|| { - SidecarError::Execution(String::from("EBADF: bad file descriptor")) - })?; - javascript_net_json_string( - json!({ - "address": local_addr.ip().to_string(), - "port": local_addr.port(), - "family": socket_addr_family(&local_addr), - }), - "dgram.address", - ) - } - "dgram.setBufferSize" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "dgram.setBufferSize socket id")?; - let which = - javascript_sync_rpc_arg_str(&request.args, 1, "dgram.setBufferSize buffer kind")?; - let size = javascript_sync_rpc_arg_u64(&request.args, 2, "dgram.setBufferSize size")?; - let size = usize::try_from(size).map_err(|_| { - SidecarError::InvalidState(String::from( - "dgram.setBufferSize size must fit within usize", - )) - })?; - let socket = process.udp_sockets.get_mut(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown UDP socket {socket_id}")) - })?; - socket.set_buffer_size(which, size)?; - Ok(Value::Null) - } - "dgram.getBufferSize" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "dgram.getBufferSize socket id")?; - let which = - javascript_sync_rpc_arg_str(&request.args, 1, "dgram.getBufferSize buffer kind")?; - let socket = process.udp_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown UDP socket {socket_id}")) - })?; - let size = socket.get_buffer_size(which)?; - Ok(json!(size)) - } - other => Err(SidecarError::InvalidState(format!( - "unsupported JavaScript dgram sync RPC method {other}" - ))), - } -} - -#[derive(Debug)] -struct ClientHttp2StreamState { - send_stream: Option>, -} - -#[derive(Debug)] -struct ServerHttp2StreamState { - send_response: Option, - send_stream: Option>, -} - -#[derive(Debug)] -enum ServerHttp2Responder { - Regular(server::SendResponse), - Pushed(server::SendPushedResponse), -} - -const HTTP2_DEFAULT_WINDOW_SIZE: u32 = 65_535; -const HTTP2_POLL_DELAY: Duration = Duration::from_millis(10); - -fn http2_runtime_snapshot() -> Http2RuntimeSnapshot { - Http2RuntimeSnapshot { - effective_local_window_size: HTTP2_DEFAULT_WINDOW_SIZE, - local_window_size: HTTP2_DEFAULT_WINDOW_SIZE, - remote_window_size: HTTP2_DEFAULT_WINDOW_SIZE, - next_stream_id: 1, - outbound_queue_size: 1, - deflate_dynamic_table_size: 0, - inflate_dynamic_table_size: 0, - } -} - -fn http2_snapshot_json(snapshot: &Http2SessionSnapshot) -> Result { - serde_json::to_string(snapshot) - .map_err(|error| SidecarError::Execution(format!("ERR_AGENTOS_NODE_SYNC_RPC: {error}"))) -} - -fn http2_event_value(event: &Http2BridgeEvent) -> Result { - serde_json::to_string(event) - .map(Value::String) - .map_err(|error| SidecarError::Execution(format!("ERR_AGENTOS_NODE_SYNC_RPC: {error}"))) -} - -fn push_http2_server_event( - shared: &Arc>, - server_id: u64, - event: Http2BridgeEvent, -) { - let (ready, wake_session, should_wake) = if let Ok(mut state) = shared.lock() { - let queue = state.server_events.entry(server_id).or_default(); - let should_wake = queue.is_empty(); - queue.push_back(event); - ( - Some(Arc::clone(&state.ready)), - state.event_session.clone(), - should_wake, - ) - } else { - (None, None, false) - }; - if let Some(ready) = ready { - ready.notify_all(); - } - if should_wake { - push_http2_retain_wake(wake_session, "server", server_id); - } -} - -fn push_http2_session_event( - shared: &Arc>, - session_id: u64, - event: Http2BridgeEvent, -) { - let (ready, wake_session, should_wake) = if let Ok(mut state) = shared.lock() { - let queue = state.session_events.entry(session_id).or_default(); - let should_wake = queue.is_empty(); - queue.push_back(event); - ( - Some(Arc::clone(&state.ready)), - state.event_session.clone(), - should_wake, - ) - } else { - (None, None, false) - }; - if let Some(ready) = ready { - ready.notify_all(); - } - if should_wake { - push_http2_retain_wake(wake_session, "session", session_id); - } -} - -fn push_http2_retain_wake(session: Option, kind: &'static str, id: u64) { - let Some(session) = session else { - return; - }; - let payload = v8_runtime::json_to_cbor_payload(&json!({ - "event": "http2", - "kind": kind, - "id": id, - })) - .unwrap_or_default(); - let _ = session.send_stream_event("net_socket", payload); -} - -fn pop_http2_event( - queue: &mut BTreeMap>, - id: u64, -) -> Option { - queue.get_mut(&id).and_then(VecDeque::pop_front) -} - -fn wait_for_http2_event( - shared: &Arc>, - id: u64, - is_server: bool, - wait_ms: u64, -) -> Option { - let deadline = Instant::now() + Duration::from_millis(wait_ms); - let mut state = shared.lock().ok()?; - loop { - let queue = if is_server { - &mut state.server_events - } else { - &mut state.session_events - }; - if let Some(event) = pop_http2_event(queue, id) { - return Some(event); - } - if wait_ms == 0 { - return None; - } - let now = Instant::now(); - if now >= deadline { - return None; - } - let remaining = deadline.saturating_duration_since(now); - if remaining.is_zero() { - return None; - } - let ready = Arc::clone(&state.ready); - state = ready.wait_timeout(state, remaining).ok()?.0; - } -} - -fn next_http2_session_id(shared: &mut crate::state::Http2SharedState) -> u64 { - shared.next_session_id += 1; - shared.next_session_id -} - -fn next_http2_stream_id(shared: &mut crate::state::Http2SharedState) -> u64 { - shared.next_stream_id += 1; - shared.next_stream_id -} - -fn http2_reason(code: Option) -> Reason { - code.unwrap_or(Reason::NO_ERROR.into()).into() -} - -fn http2_error_payload(message: impl Into) -> String { - serde_json::to_string(&json!({ - "name": "Error", - "code": "ERR_HTTP2_ERROR", - "message": message.into(), - })) - .unwrap_or_else(|_| { - String::from( - "{\"name\":\"Error\",\"code\":\"ERR_HTTP2_ERROR\",\"message\":\"HTTP/2 bridge error\"}", - ) - }) -} - -fn http2_socket_snapshot(local_addr: SocketAddr, remote_addr: SocketAddr) -> Http2SocketSnapshot { - Http2SocketSnapshot { - encrypted: false, - allow_half_open: false, - local_address: Some(local_addr.ip().to_string()), - local_port: Some(local_addr.port()), - local_family: Some(socket_addr_family(&local_addr).to_string()), - remote_address: Some(remote_addr.ip().to_string()), - remote_port: Some(remote_addr.port()), - remote_family: Some(socket_addr_family(&remote_addr).to_string()), - servername: None, - alpn_protocol: Some(String::from("h2c")), - } -} - -fn http2_wait_result(kind: &str, id: u64) -> Value { - json!({ - "kind": kind, - "id": id, - }) -} - -fn is_http2_terminal_event(event: &Http2BridgeEvent, is_server: bool, id: u64) -> bool { - if is_server { - event.kind == "serverClose" && event.id == id - } else { - event.kind == "sessionClose" && event.id == id - } -} - -fn dispatch_http2_wait_loop( - process: &ActiveProcess, - id: u64, - is_server: bool, -) -> Result { - loop { - if let Some(event) = wait_for_http2_event(&process.http2.shared, id, is_server, 50) { - let payload = serde_json::to_value(&event).map_err(|error| { - SidecarError::Execution(format!("ERR_AGENTOS_NODE_SYNC_RPC: {error}")) - })?; - process - .execution - .send_javascript_stream_event("http2", payload.clone())?; - if is_http2_terminal_event(&event, is_server, id) { - return Ok(payload); - } - continue; - } - - let exists = process - .http2 - .shared - .lock() - .map(|state| { - if is_server { - state.servers.contains_key(&id) - } else { - state.sessions.contains_key(&id) - } - }) - .unwrap_or(false); - if !exists { - return Ok(if is_server { - http2_wait_result("serverClose", id) - } else { - http2_wait_result("sessionClose", id) - }); - } - } -} - -fn dispatch_http_wait_loop(process: &ActiveProcess, server_id: u64) -> Result { - loop { - if !process.http_servers.contains_key(&server_id) { - return Ok(json!({ - "kind": "serverClose", - "id": server_id, - })); - } - thread::sleep(Duration::from_millis(25)); - } -} - -fn http2_settings_from_value(settings: &BTreeMap) -> BTreeMap { - settings.clone() -} - -fn parse_http2_headers_json( - headers_json: &str, - label: &str, -) -> Result, SidecarError> { - serde_json::from_str::>(headers_json) - .map_err(|error| SidecarError::InvalidState(format!("{label} must be valid JSON: {error}"))) -} - -fn apply_http2_header_values( - header_map: &mut HeaderMap, - name: &str, - value: &Value, -) -> Result<(), SidecarError> { - let header_name = HeaderName::from_bytes(name.as_bytes()).map_err(|error| { - SidecarError::InvalidState(format!("invalid HTTP/2 header name {name:?}: {error}")) - })?; - match value { - Value::Array(values) => { - for value in values { - apply_http2_header_values(header_map, name, value)?; - } - } - Value::String(text) => { - let value = HeaderValue::from_str(text).map_err(|error| { - SidecarError::InvalidState(format!( - "invalid HTTP/2 header value for {name}: {error}" - )) - })?; - header_map.append(header_name.clone(), value); - } - Value::Number(number) => { - let value = HeaderValue::from_str(&number.to_string()).map_err(|error| { - SidecarError::InvalidState(format!( - "invalid HTTP/2 numeric header value for {name}: {error}" - )) - })?; - header_map.append(header_name.clone(), value); - } - Value::Bool(boolean) => { - let value = HeaderValue::from_str(if *boolean { "true" } else { "false" }).map_err( - |error| { - SidecarError::InvalidState(format!( - "invalid HTTP/2 boolean header value for {name}: {error}" - )) - }, - )?; - header_map.append(header_name.clone(), value); - } - Value::Null => {} - Value::Object(_) => { - return Err(SidecarError::InvalidState(format!( - "unsupported HTTP/2 header object value for {name}" - ))); - } - } - Ok(()) -} - -fn build_http2_request(headers_json: &str) -> Result, SidecarError> { - let headers = parse_http2_headers_json(headers_json, "HTTP/2 request headers")?; - let method = headers - .get(":method") - .and_then(Value::as_str) - .unwrap_or("GET"); - let path = headers.get(":path").and_then(Value::as_str).unwrap_or("/"); - let mut builder = Request::builder() - .method(Method::from_bytes(method.as_bytes()).map_err(|error| { - SidecarError::InvalidState(format!("invalid HTTP/2 method {method:?}: {error}")) - })?) - .uri(path.parse::().map_err(|error| { - SidecarError::InvalidState(format!("invalid HTTP/2 path {path:?}: {error}")) - })?); - { - let header_map = builder.headers_mut().expect("request header map"); - for (name, value) in &headers { - if name.starts_with(':') { - continue; - } - apply_http2_header_values(header_map, name, value)?; - } - } - builder - .body(()) - .map_err(|error| SidecarError::InvalidState(format!("invalid HTTP/2 request: {error}"))) -} - -fn build_http2_response(headers_json: &str) -> Result, SidecarError> { - let headers = parse_http2_headers_json(headers_json, "HTTP/2 response headers")?; - let status = headers - .get(":status") - .and_then(Value::as_u64) - .or_else(|| { - headers - .get(":status") - .and_then(Value::as_str) - .and_then(|value| value.parse::().ok().map(u64::from)) - }) - .unwrap_or(200); - let mut builder = Response::builder().status(status as u16); - { - let header_map = builder.headers_mut().expect("response header map"); - for (name, value) in &headers { - if name.starts_with(':') { - continue; - } - apply_http2_header_values(header_map, name, value)?; - } - } - builder.body(()).map_err(|error| { - SidecarError::InvalidState(format!("invalid HTTP/2 response headers: {error}")) - }) -} - -fn serialize_http2_headers_map( - pseudo: BTreeMap, - headers: &HeaderMap, -) -> Result { - let mut serialized = pseudo; - for (name, value) in headers { - let name = name.as_str().to_string(); - let value = Value::String( - value - .to_str() - .map_err(|error| { - SidecarError::Execution(format!("invalid HTTP/2 header value: {error}")) - })? - .to_owned(), - ); - match serialized.get_mut(&name) { - Some(Value::Array(values)) => values.push(value), - Some(existing) => { - let first = existing.clone(); - *existing = Value::Array(vec![first, value]); - } - None => { - serialized.insert(name, value); - } - } - } - serde_json::to_string(&serialized) - .map_err(|error| SidecarError::Execution(format!("ERR_AGENTOS_NODE_SYNC_RPC: {error}"))) -} - -fn serialize_http2_request_headers( - request: &Request, -) -> Result { - let mut pseudo = BTreeMap::new(); - pseudo.insert( - String::from(":method"), - Value::String(request.method().as_str().to_string()), - ); - pseudo.insert( - String::from(":path"), - Value::String( - request - .uri() - .path_and_query() - .map(|value| value.as_str().to_string()) - .unwrap_or_else(|| String::from("/")), - ), - ); - serialize_http2_headers_map(pseudo, request.headers()) -} - -fn serialize_http2_response_headers( - response: &Response, -) -> Result { - let mut pseudo = BTreeMap::new(); - pseudo.insert( - String::from(":status"), - Value::Number(serde_json::Number::from(response.status().as_u16())), - ); - serialize_http2_headers_map(pseudo, response.headers()) -} - -fn remove_http2_session_resources( - shared: &Arc>, - session_id: u64, -) { - if let Ok(mut state) = shared.lock() { - state.sessions.remove(&session_id); - state.session_events.remove(&session_id); - let stream_ids = state - .streams - .iter() - .filter_map(|(stream_id, stream)| { - (stream.session_id == session_id).then_some(*stream_id) - }) - .collect::>(); - for stream_id in stream_ids { - state.streams.remove(&stream_id); - } - } -} - -fn spawn_http2_client_session( - shared: Arc>, - session_id: u64, - remote_addr: SocketAddr, - tls: Option, - snapshot: Arc>, - mut command_rx: UnboundedReceiver, -) { - thread::spawn(move || { - let runtime = match TokioRuntimeBuilder::new_current_thread() - .enable_all() - .build() - { - Ok(runtime) => runtime, - Err(error) => { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - - runtime.block_on(async move { - let stream = match tokio::net::TcpStream::connect(remote_addr).await { - Ok(stream) => stream, - Err(error) => { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - - let local_addr = match stream.local_addr() { - Ok(addr) => addr, - Err(error) => { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - - { - let mut snapshot_guard = snapshot.lock().expect("http2 snapshot lock"); - snapshot_guard.socket = http2_socket_snapshot(local_addr, remote_addr); - if let Some(options) = tls.as_ref() { - snapshot_guard.encrypted = true; - snapshot_guard.alpn_protocol = Some(String::from("h2")); - snapshot_guard.socket.encrypted = true; - snapshot_guard.socket.servername = options.servername.clone(); - snapshot_guard.socket.alpn_protocol = Some(String::from("h2")); - } - snapshot_guard.state = http2_runtime_snapshot(); - } - if let Ok(snapshot_json) = - http2_snapshot_json(&snapshot.lock().expect("http2 snapshot lock").clone()) - { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionConnect"), - id: session_id, - data: Some(snapshot_json), - ..Http2BridgeEvent::default() - }, - ); - } - - let io: Pin> = if let Some(options) = tls.as_ref() { - let server_name = match ServerName::try_from( - options - .servername - .clone() - .unwrap_or_else(|| String::from("localhost")), - ) { - Ok(server_name) => server_name, - Err(_) => { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionError"), - id: session_id, - data: Some(http2_error_payload("invalid TLS servername")), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - let connector = match build_client_tls_config(options) { - Ok(config) => TlsConnector::from(Arc::new(config)), - Err(error) => { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - match connector.connect(server_name, stream).await { - Ok(tls_stream) => Box::pin(tls_stream), - Err(error) => { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - } - } else { - Box::pin(stream) - }; - - let (mut sender, connection) = match client::handshake(io).await { - Ok(parts) => parts, - Err(error) => { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - - let (status_tx, mut status_rx) = unbounded_channel::>(); - tokio::spawn(async move { - let _ = status_tx.send(connection.await.map_err(|error| error.to_string())); - }); - - let streams: Arc>> = - Arc::new(Mutex::new(BTreeMap::new())); - - loop { - tokio::select! { - Some(result) = status_rx.recv() => { - if let Err(message) = result { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionError"), - id: session_id, - data: Some(http2_error_payload(message)), - ..Http2BridgeEvent::default() - }, - ); - } - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionClose"), - id: session_id, - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - break; - } - Some(command) = command_rx.recv() => { - match command { - Http2SessionCommand::Request { headers_json, options_json, respond_to } => { - let request = match build_http2_request(&headers_json) { - Ok(request) => request, - Err(error) => { - let _ = respond_to.send(Err(error.to_string())); - continue; - } - }; - let options: JavascriptHttp2RequestOptions = - serde_json::from_str(&options_json).unwrap_or_default(); - let stream_id = { - let mut state = shared.lock().expect("http2 shared state"); - let stream_id = next_http2_stream_id(&mut state); - state.streams.insert( - stream_id, - ActiveHttp2Stream { - session_id, - paused: Arc::new(AtomicBool::new(false)), - resume_notify: Arc::new(tokio::sync::Notify::new()), - }, - ); - stream_id - }; - match sender.send_request(request, options.end_stream) { - Ok((response_future, send_stream)) => { - if !options.end_stream { - streams - .lock() - .expect("http2 client streams") - .insert(stream_id, ClientHttp2StreamState { send_stream: Some(send_stream) }); - } - let shared_clone = Arc::clone(&shared); - let snapshot_clone = Arc::clone(&snapshot); - tokio::spawn(async move { - match response_future.await { - Ok(response) => { - if let Ok(headers_json) = serialize_http2_response_headers(&response) { - push_http2_session_event( - &shared_clone, - session_id, - Http2BridgeEvent { - kind: String::from("clientResponseHeaders"), - id: stream_id, - data: Some(headers_json), - ..Http2BridgeEvent::default() - }, - ); - } - let mut body = response.into_body(); - while let Some(chunk) = body.data().await { - match chunk { - Ok(bytes) => { - let pause_state = { - let state = shared_clone.lock().expect("http2 shared state"); - state.streams.get(&stream_id).map(|stream| { - ( - Arc::clone(&stream.paused), - Arc::clone(&stream.resume_notify), - ) - }) - }; - if let Some((paused, resume_notify)) = pause_state { - while paused.load(Ordering::SeqCst) { - let notified = resume_notify.notified(); - tokio::pin!(notified); - notified.as_mut().enable(); - if !paused.load(Ordering::SeqCst) { break; } - let _ = tokio::time::timeout(Duration::from_millis(250), notified).await; - } - } - let _ = body.flow_control().release_capacity(bytes.len()); - push_http2_session_event( - &shared_clone, - session_id, - Http2BridgeEvent { - kind: String::from("clientData"), - id: stream_id, - data: Some(base64::engine::general_purpose::STANDARD.encode(bytes)), - ..Http2BridgeEvent::default() - }, - ); - } - Err(error) => { - push_http2_session_event( - &shared_clone, - session_id, - Http2BridgeEvent { - kind: String::from("clientError"), - id: stream_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - break; - } - } - } - { - let mut snapshot = snapshot_clone.lock().expect("http2 snapshot lock"); - snapshot.state.next_stream_id = - snapshot.state.next_stream_id.saturating_add(2); - } - push_http2_session_event( - &shared_clone, - session_id, - Http2BridgeEvent { - kind: String::from("clientEnd"), - id: stream_id, - ..Http2BridgeEvent::default() - }, - ); - push_http2_session_event( - &shared_clone, - session_id, - Http2BridgeEvent { - kind: String::from("clientClose"), - id: stream_id, - extra_number: Some(0), - ..Http2BridgeEvent::default() - }, - ); - if let Ok(mut state) = shared_clone.lock() { - state.streams.remove(&stream_id); - } - } - Err(error) => { - push_http2_session_event( - &shared_clone, - session_id, - Http2BridgeEvent { - kind: String::from("clientError"), - id: stream_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - push_http2_session_event( - &shared_clone, - session_id, - Http2BridgeEvent { - kind: String::from("clientClose"), - id: stream_id, - extra_number: Some(u32::from(Reason::INTERNAL_ERROR) as u64), - ..Http2BridgeEvent::default() - }, - ); - if let Ok(mut state) = shared_clone.lock() { - state.streams.remove(&stream_id); - } - } - } - }); - let _ = respond_to.send(Ok(json!(stream_id))); - } - Err(error) => { - if let Ok(mut state) = shared.lock() { - state.streams.remove(&stream_id); - } - let _ = respond_to.send(Err(error.to_string())); - } - } - } - Http2SessionCommand::Settings { settings_json, respond_to } => { - let settings = serde_json::from_str::>(&settings_json) - .unwrap_or_default(); - { - let mut snapshot = snapshot.lock().expect("http2 snapshot lock"); - snapshot.local_settings = http2_settings_from_value(&settings); - } - if let Ok(headers_json) = serde_json::to_string(&settings) { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionLocalSettings"), - id: session_id, - data: Some(headers_json.clone()), - ..Http2BridgeEvent::default() - }, - ); - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionSettingsAck"), - id: session_id, - ..Http2BridgeEvent::default() - }, - ); - } - let _ = respond_to.send(Ok(Value::Null)); - } - Http2SessionCommand::SetLocalWindowSize { size, respond_to } => { - { - let mut snapshot = snapshot.lock().expect("http2 snapshot lock"); - snapshot.state.local_window_size = size; - snapshot.state.effective_local_window_size = size; - } - let value = snapshot - .lock() - .ok() - .and_then(|snapshot| http2_snapshot_json(&snapshot.clone()).ok()) - .map(Value::String) - .unwrap_or(Value::Null); - let _ = respond_to.send(Ok(value)); - } - Http2SessionCommand::Goaway { error_code, last_stream_id, opaque_data, respond_to } => { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionGoaway"), - id: session_id, - data: opaque_data.map(|value| { - base64::engine::general_purpose::STANDARD.encode(value) - }), - extra_number: Some(error_code as u64), - flags: Some(last_stream_id as u64), - ..Http2BridgeEvent::default() - }, - ); - let _ = respond_to.send(Ok(Value::Null)); - } - Http2SessionCommand::Close { respond_to, .. } => { - let _ = respond_to.send(Ok(Value::Null)); - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionClose"), - id: session_id, - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - break; - } - Http2SessionCommand::StreamWrite { stream_id, chunk, end_stream, respond_to } => { - let result = streams - .lock() - .expect("http2 client streams") - .get_mut(&stream_id) - .and_then(|stream| stream.send_stream.as_mut()) - .ok_or_else(|| SidecarError::InvalidState(format!("unknown HTTP/2 client stream {stream_id}"))) - .and_then(|stream| stream.send_data(Bytes::from(chunk), end_stream).map_err(|error| SidecarError::Execution(error.to_string()))); - match result { - Ok(()) => { - if end_stream { - streams.lock().expect("http2 client streams").remove(&stream_id); - } - let _ = respond_to.send(Ok(Value::Bool(true))); - } - Err(error) => { - let _ = respond_to.send(Err(error.to_string())); - } - } - } - Http2SessionCommand::StreamClose { stream_id, error_code, respond_to } => { - let mut streams = streams.lock().expect("http2 client streams"); - let Some(mut state) = streams.remove(&stream_id) else { - let _ = respond_to.send(Err(format!("unknown HTTP/2 client stream {stream_id}"))); - continue; - }; - if let Some(stream) = state.send_stream.as_mut() { - stream.send_reset(http2_reason(error_code)); - } - if let Ok(mut state) = shared.lock() { - state.streams.remove(&stream_id); - } - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("clientClose"), - id: stream_id, - extra_number: Some(u32::from(http2_reason(error_code)) as u64), - ..Http2BridgeEvent::default() - }, - ); - let _ = respond_to.send(Ok(Value::Null)); - } - Http2SessionCommand::StreamRespond { respond_to, .. } - | Http2SessionCommand::StreamPush { respond_to, .. } - | Http2SessionCommand::StreamRespondWithFile { respond_to, .. } => { - let _ = respond_to.send(Err(String::from("HTTP/2 client streams cannot send server responses"))); - } - } - } - else => break, - } - } - }); - }); -} - -fn spawn_http2_server_session( - shared: Arc>, - server_id: u64, - session_id: u64, - stream: TcpStream, - tls: Option, - snapshot: Arc>, - mut command_rx: UnboundedReceiver, -) { - thread::spawn(move || { - let runtime = match TokioRuntimeBuilder::new_current_thread() - .enable_all() - .build() - { - Ok(runtime) => runtime, - Err(error) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - - runtime.block_on(async move { - if let Err(error) = stream.set_nonblocking(true) { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - let stream = match tokio::net::TcpStream::from_std(stream) { - Ok(stream) => stream, - Err(error) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - let local_addr = match stream.local_addr() { - Ok(addr) => addr, - Err(error) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - let remote_addr = match stream.peer_addr() { - Ok(addr) => addr, - Err(error) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - { - let mut snapshot_guard = snapshot.lock().expect("http2 snapshot lock"); - snapshot_guard.socket = http2_socket_snapshot(local_addr, remote_addr); - if tls.is_some() { - snapshot_guard.encrypted = true; - snapshot_guard.alpn_protocol = Some(String::from("h2")); - snapshot_guard.socket.encrypted = true; - snapshot_guard.socket.alpn_protocol = Some(String::from("h2")); - } - snapshot_guard.state = http2_runtime_snapshot(); - } - if let Ok(snapshot_json) = - http2_snapshot_json(&snapshot.lock().expect("http2 snapshot lock").clone()) - { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from(if tls.is_some() { - "serverSecureConnection" - } else { - "serverConnection" - }), - id: server_id, - data: Some(serde_json::to_string(&http2_socket_snapshot(local_addr, remote_addr)).unwrap_or_default()), - ..Http2BridgeEvent::default() - }, - ); - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverSession"), - id: server_id, - data: Some(snapshot_json), - extra_number: Some(session_id), - ..Http2BridgeEvent::default() - }, - ); - } - - let io: Pin> = if let Some(options) = tls.as_ref() { - let acceptor = match build_server_tls_config(options) { - Ok(config) => TlsAcceptor::from(Arc::new(config)), - Err(error) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - match acceptor.accept(stream).await { - Ok(tls_stream) => Box::pin(tls_stream), - Err(error) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - } - } else { - Box::pin(stream) - }; - - let mut connection = match server::handshake(io).await { - Ok(connection) => connection, - Err(error) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: session_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - return; - } - }; - - let streams: Arc>> = - Arc::new(Mutex::new(BTreeMap::new())); - - loop { - tokio::select! { - incoming = connection.accept() => { - match incoming { - Some(Ok((request, respond))) => { - let headers_json = match serialize_http2_request_headers(&request) { - Ok(headers) => headers, - Err(error) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: server_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - continue; - } - }; - let stream_id = { - let mut state = shared.lock().expect("http2 shared state"); - let stream_id = next_http2_stream_id(&mut state); - state.streams.insert( - stream_id, - ActiveHttp2Stream { - session_id, - paused: Arc::new(AtomicBool::new(false)), - resume_notify: Arc::new(tokio::sync::Notify::new()), - }, - ); - stream_id - }; - streams.lock().expect("http2 server streams").insert( - stream_id, - ServerHttp2StreamState { - send_response: Some(ServerHttp2Responder::Regular(respond)), - send_stream: None, - }, - ); - let snapshot_json = snapshot - .lock() - .ok() - .and_then(|snapshot| http2_snapshot_json(&snapshot.clone()).ok()); - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStream"), - id: server_id, - data: Some(stream_id.to_string()), - extra: snapshot_json, - extra_number: Some(session_id), - extra_headers: Some(headers_json), - flags: Some(0), - }, - ); - let shared_clone = Arc::clone(&shared); - tokio::spawn(async move { - let mut body = request.into_body(); - while let Some(chunk) = body.data().await { - match chunk { - Ok(bytes) => { - let pause_state = { - let state = shared_clone.lock().expect("http2 shared state"); - state.streams.get(&stream_id).map(|stream| { - ( - Arc::clone(&stream.paused), - Arc::clone(&stream.resume_notify), - ) - }) - }; - if let Some((paused, resume_notify)) = pause_state { - while paused.load(Ordering::SeqCst) { - let notified = resume_notify.notified(); - tokio::pin!(notified); - notified.as_mut().enable(); - if !paused.load(Ordering::SeqCst) { break; } - let _ = tokio::time::timeout(Duration::from_millis(250), notified).await; - } - } - let _ = body.flow_control().release_capacity(bytes.len()); - push_http2_server_event( - &shared_clone, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamData"), - id: stream_id, - data: Some(base64::engine::general_purpose::STANDARD.encode(bytes)), - ..Http2BridgeEvent::default() - }, - ); - } - Err(error) => { - push_http2_server_event( - &shared_clone, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: stream_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - break; - } - } - } - push_http2_server_event( - &shared_clone, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamEnd"), - id: stream_id, - ..Http2BridgeEvent::default() - }, - ); - }); - } - Some(Err(error)) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: server_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - break; - } - None => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("sessionClose"), - id: session_id, - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - break; - } - } - } - Some(command) = command_rx.recv() => { - match command { - Http2SessionCommand::Settings { settings_json, respond_to } => { - let settings = serde_json::from_str::>(&settings_json) - .unwrap_or_default(); - if let Some(initial_window_size) = settings - .get("initialWindowSize") - .and_then(Value::as_u64) - { - let _ = connection.set_initial_window_size(initial_window_size as u32); - } - { - let mut snapshot = snapshot.lock().expect("http2 snapshot lock"); - snapshot.local_settings = http2_settings_from_value(&settings); - } - if let Ok(headers_json) = serde_json::to_string(&settings) { - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionLocalSettings"), - id: session_id, - data: Some(headers_json), - ..Http2BridgeEvent::default() - }, - ); - } - let _ = respond_to.send(Ok(Value::Null)); - } - Http2SessionCommand::SetLocalWindowSize { size, respond_to } => { - connection.set_target_window_size(size); - { - let mut snapshot = snapshot.lock().expect("http2 snapshot lock"); - snapshot.state.local_window_size = size; - snapshot.state.effective_local_window_size = size; - } - let value = snapshot - .lock() - .ok() - .and_then(|snapshot| http2_snapshot_json(&snapshot.clone()).ok()) - .map(Value::String) - .unwrap_or(Value::Null); - let _ = respond_to.send(Ok(value)); - } - Http2SessionCommand::Goaway { error_code, last_stream_id, opaque_data, respond_to } => { - connection.abrupt_shutdown(http2_reason(Some(error_code))); - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionGoaway"), - id: session_id, - data: opaque_data.map(|value| { - base64::engine::general_purpose::STANDARD.encode(value) - }), - extra_number: Some(error_code as u64), - flags: Some(last_stream_id as u64), - ..Http2BridgeEvent::default() - }, - ); - let _ = respond_to.send(Ok(Value::Null)); - } - Http2SessionCommand::Close { abrupt, respond_to } => { - if abrupt { - connection.abrupt_shutdown(Reason::NO_ERROR); - } else { - connection.graceful_shutdown(); - } - let _ = respond_to.send(Ok(Value::Null)); - push_http2_session_event( - &shared, - session_id, - Http2BridgeEvent { - kind: String::from("sessionClose"), - id: session_id, - ..Http2BridgeEvent::default() - }, - ); - remove_http2_session_resources(&shared, session_id); - break; - } - Http2SessionCommand::StreamRespond { stream_id, headers_json, respond_to } => { - let response = match build_http2_response(&headers_json) { - Ok(response) => response, - Err(error) => { - let _ = respond_to.send(Err(error.to_string())); - continue; - } - }; - let mut streams = streams.lock().expect("http2 server streams"); - let Some(state) = streams.get_mut(&stream_id) else { - let _ = respond_to.send(Err(format!("unknown HTTP/2 server stream {stream_id}"))); - continue; - }; - let Some(send_response) = state.send_response.as_mut() else { - let _ = respond_to.send(Err(format!("HTTP/2 server stream {stream_id} already responded"))); - continue; - }; - match match send_response { - ServerHttp2Responder::Regular(send_response) => { - send_response.send_response(response, false) - } - ServerHttp2Responder::Pushed(send_response) => { - send_response.send_response(response, false) - } - } { - Ok(send_stream) => { - state.send_stream = Some(send_stream); - state.send_response = None; - let _ = respond_to.send(Ok(Value::Null)); - } - Err(error) => { - let _ = respond_to.send(Err(error.to_string())); - } - } - } - Http2SessionCommand::StreamPush { stream_id, headers_json, respond_to } => { - let request = match build_http2_request(&headers_json) { - Ok(request) => request, - Err(error) => { - let _ = respond_to.send(Err(error.to_string())); - continue; - } - }; - let mut streams_guard = streams.lock().expect("http2 server streams"); - let Some(state) = streams_guard.get_mut(&stream_id) else { - let _ = respond_to.send(Err(format!("unknown HTTP/2 server stream {stream_id}"))); - continue; - }; - let Some(send_response) = state.send_response.as_mut() else { - let _ = respond_to.send(Err(format!("HTTP/2 server stream {stream_id} cannot push after responding"))); - continue; - }; - let ServerHttp2Responder::Regular(send_response) = send_response else { - let _ = respond_to.send(Err(format!("HTTP/2 pushed stream {stream_id} cannot create nested push promises"))); - continue; - }; - match send_response.push_request(request) { - Ok(pushed) => { - let pushed_stream_id = { - let mut state = shared.lock().expect("http2 shared state"); - let pushed_stream_id = next_http2_stream_id(&mut state); - state.streams.insert( - pushed_stream_id, - ActiveHttp2Stream { - session_id, - paused: Arc::new(AtomicBool::new(false)), - resume_notify: Arc::new(tokio::sync::Notify::new()), - }, - ); - pushed_stream_id - }; - streams_guard.insert( - pushed_stream_id, - ServerHttp2StreamState { - send_response: Some(ServerHttp2Responder::Pushed(pushed)), - send_stream: None, - }, - ); - let _ = respond_to.send(Ok(json!({ - "streamId": pushed_stream_id, - "headers": headers_json, - }).to_string().into())); - } - Err(error) => { - let _ = respond_to.send(Err(error.to_string())); - } - } - } - Http2SessionCommand::StreamWrite { stream_id, chunk, end_stream, respond_to } => { - let mut streams = streams.lock().expect("http2 server streams"); - let Some(state) = streams.get_mut(&stream_id) else { - let _ = respond_to.send(Err(format!("unknown HTTP/2 server stream {stream_id}"))); - continue; - }; - let Some(send_stream) = state.send_stream.as_mut() else { - let _ = respond_to.send(Err(format!("HTTP/2 server stream {stream_id} has not sent response headers"))); - continue; - }; - match send_stream.send_data(Bytes::from(chunk), end_stream) { - Ok(()) => { - if end_stream { - streams.remove(&stream_id); - if let Ok(mut state) = shared.lock() { - state.streams.remove(&stream_id); - } - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamClose"), - id: stream_id, - extra_number: Some(0), - ..Http2BridgeEvent::default() - }, - ); - } - let _ = respond_to.send(Ok(Value::Bool(true))); - } - Err(error) => { - let _ = respond_to.send(Err(error.to_string())); - } - } - } - Http2SessionCommand::StreamClose { stream_id, error_code, respond_to } => { - let mut streams_guard = streams.lock().expect("http2 server streams"); - let Some(mut state) = streams_guard.remove(&stream_id) else { - let _ = respond_to.send(Err(format!("unknown HTTP/2 server stream {stream_id}"))); - continue; - }; - let reason = http2_reason(error_code); - if let Some(send_stream) = state.send_stream.as_mut() { - send_stream.send_reset(reason); - } - if let Some(send_response) = state.send_response.as_mut() { - match send_response { - ServerHttp2Responder::Regular(send_response) => { - send_response.send_reset(reason) - } - ServerHttp2Responder::Pushed(send_response) => { - send_response.send_reset(reason) - } - } - } - if let Ok(mut shared_guard) = shared.lock() { - shared_guard.streams.remove(&stream_id); - } - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamClose"), - id: stream_id, - extra_number: Some(u32::from(reason) as u64), - ..Http2BridgeEvent::default() - }, - ); - let _ = respond_to.send(Ok(Value::Null)); - } - Http2SessionCommand::StreamRespondWithFile { stream_id, body, headers_json, options_json, respond_to } => { - let options: JavascriptHttp2FileResponseOptions = - serde_json::from_str(&options_json).unwrap_or_default(); - let response = match build_http2_response(&headers_json) { - Ok(response) => response, - Err(error) => { - let _ = respond_to.send(Err(error.to_string())); - continue; - } - }; - let offset = usize::try_from(options.offset.unwrap_or_default()).unwrap_or(0); - let body = if offset >= body.len() { - Vec::new() - } else { - let body = &body[offset..]; - match options.length { - Some(length) if length >= 0 => { - body[..body.len().min(length as usize)].to_vec() - } - _ => body.to_vec(), - } - }; - let mut streams_guard = streams.lock().expect("http2 server streams"); - let Some(state) = streams_guard.get_mut(&stream_id) else { - let _ = respond_to.send(Err(format!("unknown HTTP/2 server stream {stream_id}"))); - continue; - }; - let Some(send_response) = state.send_response.as_mut() else { - let _ = respond_to.send(Err(format!("HTTP/2 server stream {stream_id} already responded"))); - continue; - }; - match match send_response { - ServerHttp2Responder::Regular(send_response) => { - send_response.send_response(response, body.is_empty()) - } - ServerHttp2Responder::Pushed(send_response) => { - send_response.send_response(response, body.is_empty()) - } - } { - Ok(mut send_stream) => { - state.send_response = None; - if body.is_empty() { - streams_guard.remove(&stream_id); - if let Ok(mut shared_guard) = shared.lock() { - shared_guard.streams.remove(&stream_id); - } - } else { - if let Err(error) = send_stream.send_data(Bytes::from(body), true) { - let _ = respond_to.send(Err(error.to_string())); - continue; - } - streams_guard.remove(&stream_id); - if let Ok(mut shared_guard) = shared.lock() { - shared_guard.streams.remove(&stream_id); - } - } - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamClose"), - id: stream_id, - extra_number: Some(0), - ..Http2BridgeEvent::default() - }, - ); - let _ = respond_to.send(Ok(Value::Null)); - } - Err(error) => { - let _ = respond_to.send(Err(error.to_string())); - } - } - } - Http2SessionCommand::Request { respond_to, .. } => { - let _ = respond_to.send(Err(String::from("HTTP/2 server sessions cannot initiate client requests"))); - } - } - } - else => break, - } - } - }); - }); -} - -fn spawn_http2_server_accept_loop( - shared: Arc>, - server_id: u64, - listener: TcpListener, -) { - thread::spawn(move || { - let listener = listener; - loop { - let closed = shared - .lock() - .ok() - .and_then(|state| { - state - .servers - .get(&server_id) - .map(|server| server.closed.load(Ordering::SeqCst)) - }) - .unwrap_or(true); - if closed { - break; - } - match listener.accept() { - Ok((stream, _)) => { - let (command_tx, command_rx) = unbounded_channel(); - let (guest_local_addr, secure, tls) = { - let state = shared.lock().expect("http2 shared state"); - let server = state.servers.get(&server_id).expect("http2 server state"); - (server.guest_local_addr, server.secure, server.tls.clone()) - }; - let (local_addr, remote_addr) = match (stream.local_addr(), stream.peer_addr()) - { - (Ok(local_addr), Ok(remote_addr)) => (local_addr, remote_addr), - _ => continue, - }; - let session_snapshot = Arc::new(Mutex::new(Http2SessionSnapshot { - encrypted: secure, - alpn_protocol: Some(if secure { - String::from("h2") - } else { - String::from("h2c") - }), - local_settings: BTreeMap::new(), - remote_settings: BTreeMap::new(), - state: http2_runtime_snapshot(), - socket: Http2SocketSnapshot { - local_address: Some(guest_local_addr.ip().to_string()), - local_port: Some(guest_local_addr.port()), - local_family: Some(socket_addr_family(&guest_local_addr).to_string()), - remote_address: Some(remote_addr.ip().to_string()), - remote_port: Some(remote_addr.port()), - remote_family: Some(socket_addr_family(&remote_addr).to_string()), - ..http2_socket_snapshot(local_addr, remote_addr) - }, - ..Http2SessionSnapshot::default() - })); - let session_id = { - let mut state = shared.lock().expect("http2 shared state"); - let session_id = next_http2_session_id(&mut state); - state - .sessions - .insert(session_id, ActiveHttp2Session { command_tx }); - session_id - }; - spawn_http2_server_session( - Arc::clone(&shared), - server_id, - session_id, - stream, - tls, - session_snapshot, - command_rx, - ); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - wait_fd_readable_until( - listener.as_fd(), - Instant::now() + Duration::from_millis(100), - ); - } - Err(error) => { - push_http2_server_event( - &shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverStreamError"), - id: server_id, - data: Some(http2_error_payload(error.to_string())), - ..Http2BridgeEvent::default() - }, - ); - // Persistent accept errors (e.g. EMFILE) leave the fd readable, so a - // readiness wait would return immediately and spin; keep the throttle. - thread::sleep(HTTP2_POLL_DELAY); - } - } - } - }); -} - -fn send_http2_command( - session: &ActiveHttp2Session, - command: impl FnOnce(Sender>) -> Http2SessionCommand, -) -> Result { - let (respond_to, response_rx) = mpsc::channel(); - session.command_tx.send(command(respond_to)).map_err(|_| { - SidecarError::InvalidState(String::from("HTTP/2 session command channel closed")) - })?; - response_rx - .recv_timeout(Duration::from_secs(30)) - .map_err(|_| { - SidecarError::Execution(String::from("timed out waiting for HTTP/2 session command")) - })? - .map_err(SidecarError::Execution) -} - -fn parse_http2_server_listen_payload( - request: &JavascriptSyncRpcRequest, -) -> Result { - let payload_json = - javascript_sync_rpc_arg_str(&request.args, 0, "net.http2_server_listen payload")?; - serde_json::from_str(payload_json).map_err(|error| { - SidecarError::InvalidState(format!( - "net.http2_server_listen payload must be valid JSON: {error}" - )) - }) -} - -fn parse_http2_connect_payload( - request: &JavascriptSyncRpcRequest, -) -> Result { - let payload_json = - javascript_sync_rpc_arg_str(&request.args, 0, "net.http2_session_connect payload")?; - serde_json::from_str(payload_json).map_err(|error| { - SidecarError::InvalidState(format!( - "net.http2_session_connect payload must be valid JSON: {error}" - )) - }) -} - -fn http2_session_for_id( - process: &ActiveProcess, - session_id: u64, -) -> Result { - let shared = process - .http2 - .shared - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("HTTP/2 state lock poisoned")))?; - shared - .sessions - .get(&session_id) - .cloned() - .ok_or_else(|| SidecarError::InvalidState(format!("unknown HTTP/2 session {session_id}"))) -} - -fn http2_stream_for_id( - process: &ActiveProcess, - stream_id: u64, -) -> Result { - let shared = process - .http2 - .shared - .lock() - .map_err(|_| SidecarError::InvalidState(String::from("HTTP/2 state lock poisoned")))?; - shared - .streams - .get(&stream_id) - .cloned() - .ok_or_else(|| SidecarError::InvalidState(format!("unknown HTTP/2 stream {stream_id}"))) -} - -fn service_javascript_http2_sync_rpc( - request: JavascriptHttp2SyncRpcServiceRequest<'_, B>, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let JavascriptHttp2SyncRpcServiceRequest { - bridge, - kernel, - vm_id, - dns, - socket_paths, - process, - sync_request: request, - resource_limits, - network_counts, - } = request; - match request.method.as_str() { - "net.http2_server_listen" => { - check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - )?; - let payload = parse_http2_server_listen_payload(request)?; - let (family, bind_host, guest_host) = - normalize_tcp_listen_host(payload.host.as_deref())?; - let requested_port = payload.port.unwrap_or(0); - bridge.require_network_access( - vm_id, - NetworkOperation::Listen, - format_tcp_resource(bind_host, requested_port), - )?; - let port = allocate_guest_listen_port( - requested_port, - family, - &socket_paths.used_tcp_guest_ports, - socket_paths.listen_policy, - )?; - let mut listener = - ActiveTcpListener::bind(bind_host, guest_host, port, payload.backlog)?; - let guest_local_addr = listener.guest_local_addr(); - let closed = Arc::new(AtomicBool::new(false)); - { - let mut state = process.http2.shared.lock().map_err(|_| { - SidecarError::InvalidState(String::from("HTTP/2 state lock poisoned")) - })?; - state.servers.insert( - payload.server_id, - ActiveHttp2Server { - actual_local_addr: listener.local_addr(), - guest_local_addr, - secure: payload.secure, - tls: payload.tls.clone().map(|mut tls| { - tls.is_server = payload.secure; - if payload.secure && tls.alpn_protocols.is_none() { - tls.alpn_protocols = Some(vec![String::from("h2")]); - } - tls - }), - closed: Arc::clone(&closed), - }, - ); - if state.event_session.is_none() { - state.event_session = process.execution.javascript_v8_session_handle(); - } - state.server_events.entry(payload.server_id).or_default(); - } - spawn_http2_server_accept_loop( - Arc::clone(&process.http2.shared), - payload.server_id, - listener.listener.take().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "HTTP/2 listener missing host TCP socket", - )) - })?, - ); - javascript_net_json_string( - json!({ - "address": socket_address_value(&guest_local_addr) - }), - "net.http2_server_listen", - ) - } - "net.http2_server_poll" => { - let server_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_server_poll server id")?; - let wait_ms = javascript_sync_rpc_arg_u64_optional( - &request.args, - 1, - "net.http2_server_poll wait ms", - )? - .unwrap_or_default(); - match wait_for_http2_event(&process.http2.shared, server_id, true, wait_ms) { - Some(event) => http2_event_value(&event), - None => Ok(Value::Null), - } - } - "net.http2_server_wait" => { - let server_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_server_wait server id")?; - dispatch_http2_wait_loop(process, server_id, true) - } - "net.http2_server_close" => { - let server_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_server_close server id")?; - let server = { - let mut state = process.http2.shared.lock().map_err(|_| { - SidecarError::InvalidState(String::from("HTTP/2 state lock poisoned")) - })?; - state.servers.remove(&server_id) - } - .ok_or_else(|| { - SidecarError::InvalidState(format!("unknown HTTP/2 server {server_id}")) - })?; - server.closed.store(true, Ordering::SeqCst); - push_http2_server_event( - &process.http2.shared, - server_id, - Http2BridgeEvent { - kind: String::from("serverClose"), - id: server_id, - ..Http2BridgeEvent::default() - }, - ); - Ok(Value::Null) - } - "net.http2_server_respond" => { - let server_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "net.http2_server_respond server id", - )?; - let request_id = javascript_sync_rpc_arg_u64( - &request.args, - 1, - "net.http2_server_respond request id", - )?; - let response_json = - javascript_sync_rpc_arg_str(&request.args, 2, "net.http2_server_respond payload")?; - ensure_vm_fetch_response_within_limit( - response_json, - "net.http2_server_respond", - VM_FETCH_BUFFER_LIMIT_BYTES, - ) - .map_err(sidecar_core_execution_error)?; - serde_json::from_str::(response_json).map_err(|error| { - SidecarError::Execution(format!( - "net.http2_server_respond payload must be valid JSON: {error}" - )) - })?; - let Some(pending) = process - .pending_http_requests - .get_mut(&(server_id, request_id)) - else { - return Err(SidecarError::InvalidState(format!( - "unknown pending HTTP/2 request {request_id} for server {server_id}" - ))); - }; - *pending = Some(response_json.to_owned()); - Ok(Value::Bool(true)) - } - "net.http2_session_connect" => { - check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - )?; - check_network_resource_limit( - resource_limits.max_connections, - network_counts.connections, - 1, - "connection", - )?; - let payload = parse_http2_connect_payload(request)?; - let authority = payload.authority.clone().unwrap_or_else(|| { - format!( - "{}://{}:{}", - payload.protocol.as_deref().unwrap_or("http"), - payload.host.as_deref().unwrap_or("localhost"), - payload.port.unwrap_or(80) - ) - }); - let url = Url::parse(&authority).map_err(|error| { - SidecarError::InvalidState(format!( - "invalid HTTP/2 authority {authority:?}: {error}" - )) - })?; - let secure = url.scheme() == "https" || payload.protocol.as_deref() == Some("https:"); - let host = payload - .host - .as_deref() - .or_else(|| url.host_str()) - .unwrap_or("localhost"); - let port = payload.port.or_else(|| url.port()).unwrap_or(80); - bridge.require_network_access( - vm_id, - NetworkOperation::Http, - format_tcp_resource(host, port), - )?; - let resolved = { - let shared = process.http2.shared.lock().map_err(|_| { - SidecarError::InvalidState(String::from("HTTP/2 state lock poisoned")) - })?; - shared - .servers - .values() - .find(|server| { - is_loopback_request_host(host) && server.guest_local_addr.port() == port - }) - .map(|server| ResolvedTcpConnectAddr { - actual_addr: server.actual_local_addr, - guest_remote_addr: server.guest_local_addr, - use_kernel_loopback: false, - }) - }; - let resolved = match resolved { - Some(resolved) => resolved, - None => { - resolve_tcp_connect_addr(bridge, kernel, vm_id, dns, host, port, socket_paths)? - } - }; - let (command_tx, command_rx) = unbounded_channel(); - let snapshot = Arc::new(Mutex::new(Http2SessionSnapshot { - encrypted: secure, - alpn_protocol: Some(String::from(if secure { "h2" } else { "h2c" })), - local_settings: http2_settings_from_value(&payload.settings), - remote_settings: BTreeMap::new(), - state: http2_runtime_snapshot(), - socket: Http2SocketSnapshot { - encrypted: secure, - remote_address: Some(resolved.guest_remote_addr.ip().to_string()), - remote_port: Some(resolved.guest_remote_addr.port()), - remote_family: Some( - socket_addr_family(&resolved.guest_remote_addr).to_string(), - ), - servername: if secure { - payload - .tls - .as_ref() - .and_then(|tls| tls.servername.clone()) - .or_else(|| Some(host.to_string())) - } else { - None - }, - alpn_protocol: Some(String::from(if secure { "h2" } else { "h2c" })), - ..Http2SocketSnapshot::default() - }, - ..Http2SessionSnapshot::default() - })); - let session_id = { - let mut state = process.http2.shared.lock().map_err(|_| { - SidecarError::InvalidState(String::from("HTTP/2 state lock poisoned")) - })?; - let session_id = next_http2_session_id(&mut state); - state - .sessions - .insert(session_id, ActiveHttp2Session { command_tx }); - if state.event_session.is_none() { - state.event_session = process.execution.javascript_v8_session_handle(); - } - state.session_events.entry(session_id).or_default(); - session_id - }; - spawn_http2_client_session( - Arc::clone(&process.http2.shared), - session_id, - resolved.actual_addr, - if secure { - Some(payload.tls.unwrap_or(JavascriptTlsBridgeOptions { - is_server: false, - servername: Some(host.to_string()), - alpn_protocols: Some(vec![String::from("h2")]), - ..JavascriptTlsBridgeOptions::default() - })) - } else { - None - }, - Arc::clone(&snapshot), - command_rx, - ); - let snapshot_json = - http2_snapshot_json(&snapshot.lock().expect("http2 snapshot lock").clone())?; - javascript_net_json_string( - json!({ - "sessionId": session_id, - "state": snapshot_json, - }), - "net.http2_session_connect", - ) - } - "net.http2_session_request" => { - let session_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "net.http2_session_request session id", - )?; - let headers_json = - javascript_sync_rpc_arg_str(&request.args, 1, "net.http2_session_request headers")?; - let options_json = - javascript_sync_rpc_arg_str(&request.args, 2, "net.http2_session_request options")?; - let session = http2_session_for_id(process, session_id)?; - send_http2_command(&session, |respond_to| Http2SessionCommand::Request { - headers_json: headers_json.to_owned(), - options_json: options_json.to_owned(), - respond_to, - }) - } - "net.http2_session_settings" => { - let session_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "net.http2_session_settings session id", - )?; - let settings_json = javascript_sync_rpc_arg_str( - &request.args, - 1, - "net.http2_session_settings settings", - )?; - let session = http2_session_for_id(process, session_id)?; - send_http2_command(&session, |respond_to| Http2SessionCommand::Settings { - settings_json: settings_json.to_owned(), - respond_to, - }) - } - "net.http2_session_set_local_window_size" => { - let session_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "net.http2_session_set_local_window_size session id", - )?; - let window_size = javascript_sync_rpc_arg_u64( - &request.args, - 1, - "net.http2_session_set_local_window_size window size", - )?; - let session = http2_session_for_id(process, session_id)?; - send_http2_command(&session, |respond_to| { - Http2SessionCommand::SetLocalWindowSize { - size: window_size as u32, - respond_to, - } - }) - } - "net.http2_session_goaway" => { - let session_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "net.http2_session_goaway session id", - )?; - let error_code = javascript_sync_rpc_arg_u64( - &request.args, - 1, - "net.http2_session_goaway error code", - )?; - let last_stream_id = javascript_sync_rpc_arg_u64( - &request.args, - 2, - "net.http2_session_goaway last stream id", - )?; - let opaque_data = request - .args - .get(3) - .and_then(Value::as_str) - .map(|value| { - base64::engine::general_purpose::STANDARD - .decode(value) - .map_err(|error| { - SidecarError::InvalidState(format!("invalid GOAWAY payload: {error}")) - }) - }) - .transpose()?; - let session = http2_session_for_id(process, session_id)?; - send_http2_command(&session, |respond_to| Http2SessionCommand::Goaway { - error_code: error_code as u32, - last_stream_id: last_stream_id as u32, - opaque_data, - respond_to, - }) - } - "net.http2_session_close" | "net.http2_session_destroy" => { - let session_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "net.http2_session_close session id", - )?; - let session = http2_session_for_id(process, session_id)?; - send_http2_command(&session, |respond_to| Http2SessionCommand::Close { - abrupt: request.method == "net.http2_session_destroy", - respond_to, - }) - } - "net.http2_session_poll" => { - let session_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_session_poll session id")?; - let wait_ms = javascript_sync_rpc_arg_u64_optional( - &request.args, - 1, - "net.http2_session_poll wait ms", - )? - .unwrap_or_default(); - match wait_for_http2_event(&process.http2.shared, session_id, false, wait_ms) { - Some(event) => http2_event_value(&event), - None => Ok(Value::Null), - } - } - "net.http2_session_wait" => { - let session_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_session_wait session id")?; - dispatch_http2_wait_loop(process, session_id, false) - } - "net.http2_stream_respond" => { - let stream_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "net.http2_stream_respond stream id", - )?; - let headers_json = - javascript_sync_rpc_arg_str(&request.args, 1, "net.http2_stream_respond headers")?; - let stream = http2_stream_for_id(process, stream_id)?; - let session = http2_session_for_id(process, stream.session_id)?; - send_http2_command(&session, |respond_to| Http2SessionCommand::StreamRespond { - stream_id, - headers_json: headers_json.to_owned(), - respond_to, - }) - } - "net.http2_stream_push_stream" => { - let stream_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "net.http2_stream_push_stream stream id", - )?; - let headers_json = javascript_sync_rpc_arg_str( - &request.args, - 1, - "net.http2_stream_push_stream headers", - )?; - let _options_json = javascript_sync_rpc_arg_str( - &request.args, - 2, - "net.http2_stream_push_stream options", - )?; - let stream = http2_stream_for_id(process, stream_id)?; - let session = http2_session_for_id(process, stream.session_id)?; - send_http2_command(&session, |respond_to| Http2SessionCommand::StreamPush { - stream_id, - headers_json: headers_json.to_owned(), - respond_to, - }) - } - "net.http2_stream_write" => { - let stream_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_stream_write stream id")?; - let chunk = - javascript_sync_rpc_base64_arg(&request.args, 1, "net.http2_stream_write data")?; - let stream = http2_stream_for_id(process, stream_id)?; - let session = http2_session_for_id(process, stream.session_id)?; - send_http2_command(&session, |respond_to| Http2SessionCommand::StreamWrite { - stream_id, - chunk, - end_stream: false, - respond_to, - }) - } - "net.http2_stream_end" => { - let stream_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_stream_end stream id")?; - let chunk = request - .args - .get(1) - .and_then(Value::as_str) - .map(|value| { - base64::engine::general_purpose::STANDARD - .decode(value) - .map_err(|error| { - SidecarError::InvalidState(format!( - "invalid HTTP/2 stream payload: {error}" - )) - }) - }) - .transpose()? - .unwrap_or_default(); - let stream = http2_stream_for_id(process, stream_id)?; - let session = http2_session_for_id(process, stream.session_id)?; - send_http2_command(&session, |respond_to| Http2SessionCommand::StreamWrite { - stream_id, - chunk, - end_stream: true, - respond_to, - }) - } - "net.http2_stream_close" => { - let stream_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_stream_close stream id")?; - let code = javascript_sync_rpc_arg_u64_optional( - &request.args, - 1, - "net.http2_stream_close error code", - )? - .map(|value| value as u32); - let stream = http2_stream_for_id(process, stream_id)?; - let session = http2_session_for_id(process, stream.session_id)?; - send_http2_command(&session, |respond_to| Http2SessionCommand::StreamClose { - stream_id, - error_code: code, - respond_to, - }) - } - "net.http2_stream_pause" => { - let stream_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_stream_pause stream id")?; - let stream = http2_stream_for_id(process, stream_id)?; - stream.paused.store(true, Ordering::SeqCst); - Ok(Value::Null) - } - "net.http2_stream_resume" => { - let stream_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http2_stream_resume stream id")?; - let stream = http2_stream_for_id(process, stream_id)?; - stream.paused.store(false, Ordering::SeqCst); - stream.resume_notify.notify_waiters(); - Ok(Value::Null) - } - "net.http2_stream_respond_with_file" => { - let stream_id = javascript_sync_rpc_arg_u64( - &request.args, - 0, - "net.http2_stream_respond_with_file stream id", - )?; - let path = javascript_sync_rpc_arg_str( - &request.args, - 1, - "net.http2_stream_respond_with_file path", - )?; - let headers_json = javascript_sync_rpc_arg_str( - &request.args, - 2, - "net.http2_stream_respond_with_file headers", - )?; - let options_json = javascript_sync_rpc_arg_str( - &request.args, - 3, - "net.http2_stream_respond_with_file options", - )?; - let stream = http2_stream_for_id(process, stream_id)?; - let session = http2_session_for_id(process, stream.session_id)?; - let guest_path = resolve_http2_file_response_guest_path(process, path); - let body = kernel.read_file(&guest_path).map_err(kernel_error)?; - send_http2_command(&session, |respond_to| { - Http2SessionCommand::StreamRespondWithFile { - stream_id, - body, - headers_json: headers_json.to_owned(), - options_json: options_json.to_owned(), - respond_to, - } - }) - } - other => Err(SidecarError::InvalidState(format!( - "unsupported JavaScript HTTP/2 sync RPC method {other}" - ))), - } -} - -const JAVASCRIPT_NET_POLL_MAX_WAIT: Duration = Duration::from_millis(50); -const EXITED_PROCESS_SNAPSHOT_RETENTION: Duration = Duration::from_secs(2); - -fn resolve_http2_file_response_guest_path(process: &ActiveProcess, path: &str) -> String { - if Path::new(path).is_absolute() { - normalize_path(path) - } else { - normalize_path(&format!("{}/{}", process.guest_cwd, path)) - } -} - -pub(crate) fn clamp_javascript_net_poll_wait(wait_ms: u64) -> Duration { - // WASM net.poll runs on the sidecar's sync-RPC main thread. Guest-controlled waits - // must stay bounded so one VM cannot stall dispose/shutdown or unrelated VM work. - if wait_ms == 0 { - Duration::ZERO - } else { - Duration::from_millis(wait_ms).min(JAVASCRIPT_NET_POLL_MAX_WAIT) - } -} - -fn service_javascript_net_sync_rpc_response( - request: JavascriptNetSyncRpcServiceRequest<'_, B>, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - if request.sync_request.method != "net.socket_read" { - return service_javascript_net_sync_rpc(request).map(Into::into); - } - - let JavascriptNetSyncRpcServiceRequest { - kernel, - process, - sync_request: request, - .. - } = request; - let trace_enabled = net_tcp_trace_enabled(&process.env); - let socket_id = javascript_sync_rpc_arg_str(&request.args, 0, "net.socket_read socket id")?; - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .socket_read_calls - .fetch_add(1, Ordering::Relaxed); - NET_TCP_TRACE_COUNTERS - .socket_read_zero_wait_calls - .fetch_add(1, Ordering::Relaxed); - } - - let event = if let Some(socket) = process.tcp_sockets.get_mut(socket_id) { - socket.poll(kernel, process.kernel_pid, Duration::ZERO, trace_enabled)? - } else { - let socket = process - .unix_sockets - .get_mut(socket_id) - .ok_or_else(|| SidecarError::InvalidState(format!("unknown net socket {socket_id}")))?; - socket.poll(Duration::ZERO)? - }; - - match event { - Some(JavascriptTcpSocketEvent::Data(chunk)) => { - Ok(JavascriptSyncRpcServiceResponse::Raw(chunk)) - } - other => javascript_net_read_value(other).map(Into::into), - } -} - -pub(crate) fn service_javascript_net_sync_rpc( - request: JavascriptNetSyncRpcServiceRequest<'_, B>, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let JavascriptNetSyncRpcServiceRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness, - process, - sync_request: request, - resource_limits, - network_counts, - } = request; - let trace_enabled = net_tcp_trace_enabled(&process.env); - match request.method.as_str() { - "net.http_listen" => { - check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - )?; - let payload_json = - javascript_sync_rpc_arg_str(&request.args, 0, "net.http_listen payload")?; - let payload: JavascriptHttpListenRequest = - serde_json::from_str(payload_json).map_err(|error| { - SidecarError::InvalidState(format!( - "net.http_listen payload must be valid JSON: {error}" - )) - })?; - let (family, bind_host, guest_host) = - normalize_tcp_listen_host(payload.hostname.as_deref())?; - let requested_port = payload.port.unwrap_or(0); - bridge.require_network_access( - vm_id, - NetworkOperation::Listen, - format_tcp_resource(bind_host, requested_port), - )?; - let port = allocate_guest_listen_port( - requested_port, - family, - &socket_paths.used_tcp_guest_ports, - socket_paths.listen_policy, - )?; - let mut listener = ActiveTcpListener::bind( - bind_host, - guest_host, - port, - Some(DEFAULT_JAVASCRIPT_NET_BACKLOG), - )?; - let guest_local_addr = listener.guest_local_addr(); - process.http_servers.insert( - payload.server_id, - ActiveHttpServer { - listener: listener.listener.take().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "HTTP listener missing host TCP socket", - )) - })?, - guest_local_addr, - next_request_id: 0, - }, - ); - serde_json::to_string(&json!({ - "address": socket_address_value(&guest_local_addr) - })) - .map(Value::String) - .map_err(|error| SidecarError::Execution(format!("ERR_AGENTOS_NODE_SYNC_RPC: {error}"))) - } - "net.http_close" => { - let server_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http_close server id")?; - let server = process.http_servers.remove(&server_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown HTTP server {server_id}")) - })?; - drop(server.listener); - process - .pending_http_requests - .retain(|(pending_server_id, _), _| *pending_server_id != server_id); - Ok(Value::Null) - } - "net.http_wait" => { - let server_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http_wait server id")?; - dispatch_http_wait_loop(process, server_id) - } - "net.http_respond" => { - let server_id = - javascript_sync_rpc_arg_u64(&request.args, 0, "net.http_respond server id")?; - let request_id = - javascript_sync_rpc_arg_u64(&request.args, 1, "net.http_respond request id")?; - let response_json = - javascript_sync_rpc_arg_str(&request.args, 2, "net.http_respond payload")?; - ensure_vm_fetch_response_within_limit( - response_json, - "net.http_respond", - VM_FETCH_BUFFER_LIMIT_BYTES, - ) - .map_err(sidecar_core_execution_error)?; - serde_json::from_str::(response_json).map_err(|error| { - SidecarError::Execution(format!( - "net.http_respond payload must be valid JSON: {error}" - )) - })?; - let Some(pending) = process - .pending_http_requests - .get_mut(&(server_id, request_id)) - else { - return Err(SidecarError::InvalidState(format!( - "unknown pending HTTP request {request_id} for server {server_id}" - ))); - }; - *pending = Some(response_json.to_owned()); - Ok(Value::Null) - } - "net.reserve_tcp_port" => { - let payload = request - .args - .first() - .cloned() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "net.reserve_tcp_port requires a request payload", - )) - }) - .and_then(|value| { - serde_json::from_value::(value).map_err( - |error| { - SidecarError::InvalidState(format!( - "invalid net.reserve_tcp_port payload: {error}" - )) - }, - ) - })?; - let (family, _bind_host, guest_host) = - normalize_tcp_listen_host(payload.host.as_deref())?; - let requested_port = payload.port.unwrap_or(0); - let port = allocate_guest_listen_port( - requested_port, - family, - &socket_paths.used_tcp_guest_ports, - socket_paths.listen_policy, - )?; - let reservation_id = process.allocate_tcp_port_reservation_id(); - process - .tcp_port_reservations - .insert(reservation_id.clone(), (family, port)); - Ok(json!({ - "reservationId": reservation_id, - "localAddress": guest_host, - "localPort": port, - "family": match family { - JavascriptSocketFamily::Ipv4 => "IPv4", - JavascriptSocketFamily::Ipv6 => "IPv6", - }, - })) - } - "net.release_tcp_port" => { - let reservation_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.release_tcp_port reservation")?; - process.tcp_port_reservations.remove(reservation_id); - Ok(Value::Null) - } - "net.connect" => { - check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - )?; - check_network_resource_limit( - resource_limits.max_connections, - network_counts.connections, - 1, - "connection", - )?; - let payload = request - .args - .first() - .cloned() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "net.connect requires a request payload", - )) - }) - .and_then(|value| { - serde_json::from_value::(value).map_err(|error| { - SidecarError::InvalidState(format!("invalid net.connect payload: {error}")) - }) - })?; - if let Some(path) = payload.path.as_deref() { - let guest_path = normalize_path(path); - let host_path = resolve_guest_socket_host_path(socket_paths, &guest_path); - let socket = ActiveUnixSocket::connect(&host_path, &guest_path)?; - let socket_id = process.allocate_unix_socket_id(); - socket.set_event_pusher( - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - ); - process.unix_sockets.insert(socket_id.clone(), socket); - Ok(json!({ - "socketId": socket_id, - "remotePath": guest_path, - })) - } else { - let port = payload.port.ok_or_else(|| { - SidecarError::InvalidState(String::from( - "net.connect requires either a path or port", - )) - })?; - let host = payload.host.as_deref().unwrap_or("localhost"); - let local_reservation = payload.local_reservation.as_deref().and_then(|id| { - process - .tcp_port_reservations - .remove(id) - .map(|reservation| (id.to_owned(), reservation)) - }); - bridge.require_network_access( - vm_id, - NetworkOperation::Http, - format_tcp_resource(host, port), - )?; - if is_loopback_socket_host(host) { - let families = [JavascriptSocketFamily::Ipv4, JavascriptSocketFamily::Ipv6]; - if let Some((family, target)) = families.iter().find_map(|family| { - socket_paths - .http_loopback_target(*family, port) - .map(|target| (*family, target)) - }) { - if let Some((reservation_id, reservation)) = local_reservation { - process - .tcp_port_reservations - .insert(reservation_id, reservation); - } - let remote_address = match family { - JavascriptSocketFamily::Ipv4 => "127.0.0.1", - JavascriptSocketFamily::Ipv6 => "::1", - }; - return Ok(json!({ - "loopbackHttpTarget": { - "processId": target.process_id.clone(), - "serverId": target.server_id, - "host": remote_address, - "port": port, - }, - "localAddress": match family { - JavascriptSocketFamily::Ipv4 => "127.0.0.1", - JavascriptSocketFamily::Ipv6 => "::1", - }, - "localPort": payload.local_port.unwrap_or(0), - "remoteAddress": remote_address, - "remotePort": port, - "remoteFamily": match family { - JavascriptSocketFamily::Ipv4 => "IPv4", - JavascriptSocketFamily::Ipv6 => "IPv6", - }, - })); - } - } - let connect_result = ActiveTcpSocket::connect(ActiveTcpConnectRequest { - bridge, - kernel, - kernel_pid: process.kernel_pid, - vm_id, - dns, - host, - port, - local_address: payload.local_address.as_deref(), - local_port: payload.local_port, - local_reservation: local_reservation - .as_ref() - .map(|(_, reservation)| *reservation), - context: socket_paths, - }); - if let Err(error) = connect_result { - if let Some((reservation_id, reservation)) = local_reservation { - process - .tcp_port_reservations - .insert(reservation_id, reservation); - } - return Err(error); - } - let socket = connect_result?; - let socket_id = process.allocate_tcp_socket_id(); - let local_addr = socket.guest_local_addr; - let remote_addr = socket.guest_remote_addr; - socket.set_event_pusher( - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - ); - register_kernel_readiness_target( - &kernel_readiness, - socket.kernel_socket_id, - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - KernelSocketReadinessEvent::Data, - ); - process.tcp_sockets.insert(socket_id.clone(), socket); - Ok(json!({ - "socketId": socket_id, - "localAddress": local_addr.ip().to_string(), - "localPort": local_addr.port(), - "remoteAddress": remote_addr.ip().to_string(), - "remotePort": remote_addr.port(), - "remoteFamily": socket_addr_family(&remote_addr), - })) - } - } - "net.listen" => { - check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - )?; - let payload = request - .args - .first() - .cloned() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "net.listen requires a request payload", - )) - }) - .and_then(|value| match value { - Value::String(json) => { - serde_json::from_str::(&json).map_err(|error| { - SidecarError::InvalidState(format!( - "invalid net.listen payload: {error}" - )) - }) - } - other => serde_json::from_value::(other).map_err( - |error| { - SidecarError::InvalidState(format!( - "invalid net.listen payload: {error}" - )) - }, - ), - })?; - if let Some(path) = payload.path.as_deref() { - let guest_path = normalize_path(path); - if kernel.exists(&guest_path).map_err(kernel_error)? { - return Err(sidecar_net_error(std::io::Error::from_raw_os_error( - libc::EADDRINUSE, - ))); - } - - let host_path = resolve_guest_socket_host_path(socket_paths, &guest_path); - let on_host_mount = - host_mount_path_for_guest_path_from_mounts(&socket_paths.mounts, &guest_path) - .is_some(); - let listener = ActiveUnixListener::bind(&host_path, &guest_path, payload.backlog)?; - if !on_host_mount { - ensure_kernel_parent_directories(kernel, &guest_path)?; - kernel - .write_file(&guest_path, Vec::new()) - .map_err(kernel_error)?; - } - let listener_id = process.allocate_unix_listener_id(); - process.unix_listeners.insert(listener_id.clone(), listener); - Ok(json!({ - "serverId": listener_id, - "path": guest_path, - })) - } else { - let (family, bind_host, guest_host) = - normalize_tcp_listen_host(payload.host.as_deref())?; - let requested_port = payload.port.unwrap_or(0); - bridge.require_network_access( - vm_id, - NetworkOperation::Listen, - format_tcp_resource(bind_host, requested_port), - )?; - let local_reservation = payload.local_reservation.as_deref().and_then(|id| { - process - .tcp_port_reservations - .remove(id) - .map(|reservation| (id.to_owned(), reservation)) - }); - let port = if requested_port != 0 - && local_reservation - .as_ref() - .map(|(_, reservation)| *reservation) - == Some((family, requested_port)) - { - requested_port - } else { - allocate_guest_listen_port( - requested_port, - family, - &socket_paths.used_tcp_guest_ports, - socket_paths.listen_policy, - )? - }; - let listener_result = ActiveTcpListener::bind_kernel( - kernel, - process.kernel_pid, - guest_host, - port, - payload.backlog, - ); - if let Err(error) = listener_result { - if let Some((reservation_id, reservation)) = local_reservation { - process - .tcp_port_reservations - .insert(reservation_id, reservation); - } - return Err(error); - } - let listener = listener_result?; - let listener_id = process.allocate_tcp_listener_id(); - let local_addr = listener.guest_local_addr(); - register_kernel_readiness_target( - &kernel_readiness, - listener.kernel_socket_id, - process.execution.javascript_v8_session_handle(), - listener_id.clone(), - KernelSocketReadinessEvent::Accept, - ); - process.tcp_listeners.insert(listener_id.clone(), listener); - Ok(json!({ - "serverId": listener_id, - "localAddress": local_addr.ip().to_string(), - "localPort": local_addr.port(), - "family": socket_addr_family(&local_addr), - })) - } - } - "net.poll" => { - let socket_id = javascript_sync_rpc_arg_str(&request.args, 0, "net.poll socket id")?; - let wait_ms = - javascript_sync_rpc_arg_u64_optional(&request.args, 1, "net.poll wait ms")? - .unwrap_or_default(); - let wait = clamp_javascript_net_poll_wait(wait_ms); - let event = if let Some(socket) = process.tcp_sockets.get_mut(socket_id) { - socket.poll(kernel, process.kernel_pid, wait, trace_enabled)? - } else if let Some(socket) = process.unix_sockets.get_mut(socket_id) { - socket.poll(wait)? - } else { - return Err(SidecarError::InvalidState(format!( - "unknown net socket {socket_id}" - ))); - }; - - match event { - Some(JavascriptTcpSocketEvent::Data(chunk)) => Ok(json!({ - "type": "data", - "data": javascript_sync_rpc_bytes_value(&chunk), - })), - Some(JavascriptTcpSocketEvent::End) => Ok(json!({ - "type": "end", - })), - Some(JavascriptTcpSocketEvent::Error { code, message }) => Ok(json!({ - "type": "error", - "code": code, - "message": message, - })), - Some(JavascriptTcpSocketEvent::Close { had_error }) => { - if let Some(socket) = process.tcp_sockets.remove(socket_id) { - release_tcp_socket_handle( - process, - socket_id, - socket, - kernel, - &kernel_readiness, - ); - } else if let Some(socket) = process.unix_sockets.remove(socket_id) { - release_unix_socket_handle(process, socket_id, socket); - } - Ok(json!({ - "type": "close", - "hadError": had_error, - })) - } - None => Ok(Value::Null), - } - } - "net.socket_wait_connect" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.socket_wait_connect socket id")?; - if let Some(socket) = process.tcp_sockets.get(socket_id) { - javascript_net_json_string(socket.socket_info(), "net.socket_wait_connect") - } else { - let socket = process.unix_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown net socket {socket_id}")) - })?; - javascript_net_json_string(socket.socket_info(), "net.socket_wait_connect") - } - } - "net.socket_read" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.socket_read socket id")?; - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .socket_read_calls - .fetch_add(1, Ordering::Relaxed); - NET_TCP_TRACE_COUNTERS - .socket_read_zero_wait_calls - .fetch_add(1, Ordering::Relaxed); - } - if let Some(socket) = process.tcp_sockets.get_mut(socket_id) { - javascript_net_read_value(socket.poll( - kernel, - process.kernel_pid, - Duration::ZERO, - trace_enabled, - )?) - } else { - let socket = process.unix_sockets.get_mut(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown net socket {socket_id}")) - })?; - javascript_net_read_value(socket.poll(Duration::ZERO)?) - } - } - "net.socket_set_no_delay" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.socket_set_no_delay socket id")?; - let enable = - javascript_sync_rpc_arg_bool(&request.args, 1, "net.socket_set_no_delay enabled")?; - if let Some(socket) = process.tcp_sockets.get_mut(socket_id) { - socket.set_no_delay(enable)?; - } else if !process.unix_sockets.contains_key(socket_id) { - return Err(SidecarError::InvalidState(format!( - "unknown net socket {socket_id}" - ))); - } - Ok(Value::Null) - } - "net.socket_set_keep_alive" => { - let socket_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "net.socket_set_keep_alive socket id", - )?; - let enable = javascript_sync_rpc_arg_bool( - &request.args, - 1, - "net.socket_set_keep_alive enabled", - )?; - let initial_delay_secs = javascript_sync_rpc_arg_u64_optional( - &request.args, - 2, - "net.socket_set_keep_alive initial delay seconds", - )?; - if let Some(socket) = process.tcp_sockets.get_mut(socket_id) { - socket.set_keep_alive(enable, initial_delay_secs)?; - } else if !process.unix_sockets.contains_key(socket_id) { - return Err(SidecarError::InvalidState(format!( - "unknown net socket {socket_id}" - ))); - } - Ok(Value::Null) - } - "net.socket_upgrade_tls" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.socket_upgrade_tls socket id")?; - let options_json = - javascript_sync_rpc_arg_str(&request.args, 1, "net.socket_upgrade_tls options")?; - let options: JavascriptTlsBridgeOptions = - serde_json::from_str(options_json).map_err(|error| { - SidecarError::InvalidState(format!( - "net.socket_upgrade_tls options must be valid JSON: {error}" - )) - })?; - let socket = process.tcp_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!( - "unknown TCP socket {socket_id} for TLS upgrade" - )) - })?; - socket.upgrade_tls(vm_id, kernel, options)?; - Ok(Value::Null) - } - "net.socket_get_tls_client_hello" => { - let socket_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "net.socket_get_tls_client_hello socket id", - )?; - let socket = process.tcp_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!( - "unknown TCP socket {socket_id} for TLS client hello query" - )) - })?; - socket.tls_client_hello_json(vm_id, kernel) - } - "net.socket_tls_query" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.socket_tls_query socket id")?; - let query = - javascript_sync_rpc_arg_str(&request.args, 1, "net.socket_tls_query query")?; - let detailed = request - .args - .get(2) - .and_then(Value::as_bool) - .unwrap_or(false); - let socket = process.tcp_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown TCP socket {socket_id} for TLS query")) - })?; - socket.tls_query(query, detailed) - } - "net.server_poll" => { - let listener_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.server_poll listener id")?; - let wait_ms = - javascript_sync_rpc_arg_u64_optional(&request.args, 1, "net.server_poll wait ms")? - .unwrap_or_default(); - let tcp_event = if let Some(listener) = process.tcp_listeners.get_mut(listener_id) { - Some(listener.poll( - kernel, - process.kernel_pid, - Duration::from_millis(wait_ms), - trace_enabled, - )?) - } else { - None - }; - - if let Some(event) = tcp_event { - return match event { - Some(JavascriptTcpListenerEvent::Connection(pending)) => { - let PendingTcpSocket { - stream, - kernel_socket_id, - preallocated, - guest_local_addr, - guest_remote_addr, - } = pending; - if !preallocated { - if let Err(error) = check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - ) - .and_then(|()| { - check_network_resource_limit( - resource_limits.max_connections, - network_counts.connections, - 1, - "connection", - ) - }) { - if let Some(stream) = stream { - let _ = stream.shutdown(Shutdown::Both); - } - return Ok(json!({ - "type": "error", - "code": "EAGAIN", - "message": error.to_string(), - })); - } - } - let socket = if let Some(stream) = stream { - ActiveTcpSocket::from_stream( - stream, - Some(listener_id.to_string()), - guest_local_addr, - guest_remote_addr, - )? - } else { - ActiveTcpSocket::from_kernel( - kernel_socket_id.ok_or_else(|| { - SidecarError::InvalidState(String::from( - "kernel TCP accept missing socket id", - )) - })?, - Some(listener_id.to_string()), - guest_local_addr, - guest_remote_addr, - ) - }; - let socket_id = process.allocate_tcp_socket_id(); - socket.set_event_pusher( - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - ); - register_kernel_readiness_target( - &kernel_readiness, - socket.kernel_socket_id, - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - KernelSocketReadinessEvent::Data, - ); - if let Some(listener) = process.tcp_listeners.get_mut(listener_id) { - listener.register_connection(&socket_id); - } - process.tcp_sockets.insert(socket_id.clone(), socket); - Ok(json!({ - "type": "connection", - "socketId": socket_id, - "localAddress": guest_local_addr.ip().to_string(), - "localPort": guest_local_addr.port(), - "remoteAddress": guest_remote_addr.ip().to_string(), - "remotePort": guest_remote_addr.port(), - "remoteFamily": socket_addr_family(&guest_remote_addr), - })) - } - Some(JavascriptTcpListenerEvent::Error { code, message }) => Ok(json!({ - "type": "error", - "code": code, - "message": message, - })), - None => Ok(Value::Null), - }; - } - - let event = { - let listener = process.unix_listeners.get_mut(listener_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown net listener {listener_id}")) - })?; - listener.poll(Duration::from_millis(wait_ms))? - }; - - match event { - Some(JavascriptUnixListenerEvent::Connection(pending)) => { - if let Err(error) = check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - ) - .and_then(|()| { - check_network_resource_limit( - resource_limits.max_connections, - network_counts.connections, - 1, - "connection", - ) - }) { - let _ = pending.stream.shutdown(Shutdown::Both); - return Ok(json!({ - "type": "error", - "code": "EAGAIN", - "message": error.to_string(), - })); - } - let socket = ActiveUnixSocket::from_stream( - pending.stream, - Some(listener_id.to_string()), - pending.local_path.clone(), - pending.remote_path.clone(), - )?; - let socket_id = process.allocate_unix_socket_id(); - socket.set_event_pusher( - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - ); - if let Some(listener) = process.unix_listeners.get_mut(listener_id) { - listener.register_connection(&socket_id); - } - process.unix_sockets.insert(socket_id.clone(), socket); - Ok(json!({ - "type": "connection", - "socketId": socket_id, - "localPath": pending.local_path, - "remotePath": pending.remote_path, - })) - } - Some(JavascriptUnixListenerEvent::Error { code, message }) => Ok(json!({ - "type": "error", - "code": code, - "message": message, - })), - None => Ok(Value::Null), - } - } - "net.server_accept" => { - let listener_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.server_accept listener id")?; - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .server_accept_calls - .fetch_add(1, Ordering::Relaxed); - NET_TCP_TRACE_COUNTERS - .server_accept_zero_wait_calls - .fetch_add(1, Ordering::Relaxed); - } - if let Some(listener) = process.tcp_listeners.get_mut(listener_id) { - return match listener.poll( - kernel, - process.kernel_pid, - Duration::ZERO, - trace_enabled, - )? { - Some(JavascriptTcpListenerEvent::Connection(pending)) => { - let PendingTcpSocket { - stream, - kernel_socket_id, - preallocated, - guest_local_addr, - guest_remote_addr, - } = pending; - if !preallocated { - check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - )?; - check_network_resource_limit( - resource_limits.max_connections, - network_counts.connections, - 1, - "connection", - )?; - } - let info = tcp_socket_info_value(&guest_local_addr, &guest_remote_addr); - let socket = if let Some(stream) = stream { - ActiveTcpSocket::from_stream( - stream, - Some(listener_id.to_string()), - guest_local_addr, - guest_remote_addr, - )? - } else { - ActiveTcpSocket::from_kernel( - kernel_socket_id.ok_or_else(|| { - SidecarError::InvalidState(String::from( - "kernel TCP accept missing socket id", - )) - })?, - Some(listener_id.to_string()), - guest_local_addr, - guest_remote_addr, - ) - }; - let socket_id = process.allocate_tcp_socket_id(); - socket.set_event_pusher( - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - ); - register_kernel_readiness_target( - &kernel_readiness, - socket.kernel_socket_id, - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - KernelSocketReadinessEvent::Data, - ); - if let Some(listener) = process.tcp_listeners.get_mut(listener_id) { - listener.register_connection(&socket_id); - } - process.tcp_sockets.insert(socket_id.clone(), socket); - javascript_net_json_string( - json!({ - "socketId": socket_id, - "info": info, - }), - "net.server_accept", - ) - } - Some(JavascriptTcpListenerEvent::Error { code, message }) => { - let detail = code.unwrap_or_else(|| String::from("server accept")); - Err(SidecarError::Execution(format!("{detail}: {message}"))) - } - None => Ok(javascript_net_timeout_value()), - }; - } - - let listener = process.unix_listeners.get_mut(listener_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown net listener {listener_id}")) - })?; - match listener.poll(Duration::ZERO)? { - Some(JavascriptUnixListenerEvent::Connection(pending)) => { - check_network_resource_limit( - resource_limits.max_sockets, - network_counts.sockets, - 1, - "socket", - )?; - check_network_resource_limit( - resource_limits.max_connections, - network_counts.connections, - 1, - "connection", - )?; - let info = json!({ - "localPath": pending.local_path.clone(), - "remotePath": pending.remote_path.clone(), - }); - let socket = ActiveUnixSocket::from_stream( - pending.stream, - Some(listener_id.to_string()), - pending.local_path, - pending.remote_path, - )?; - let socket_id = process.allocate_unix_socket_id(); - socket.set_event_pusher( - process.execution.javascript_v8_session_handle(), - socket_id.clone(), - ); - if let Some(listener) = process.unix_listeners.get_mut(listener_id) { - listener.register_connection(&socket_id); - } - process.unix_sockets.insert(socket_id.clone(), socket); - javascript_net_json_string( - json!({ - "socketId": socket_id, - "info": info, - }), - "net.server_accept", - ) - } - Some(JavascriptUnixListenerEvent::Error { code, message }) => { - let detail = code.unwrap_or_else(|| String::from("server accept")); - Err(SidecarError::Execution(format!("{detail}: {message}"))) - } - None => Ok(javascript_net_timeout_value()), - } - } - "net.server_connections" => { - let listener_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "net.server_connections listener id", - )?; - if let Some(listener) = process.tcp_listeners.get(listener_id) { - Ok(json!(listener.active_connection_count())) - } else { - let listener = process.unix_listeners.get(listener_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown net listener {listener_id}")) - })?; - Ok(json!(listener.active_connection_count())) - } - } - "net.upgrade_socket_write" => { - let socket_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "net.upgrade_socket_write socket id", - )?; - let chunk = - javascript_sync_rpc_base64_arg(&request.args, 1, "net.upgrade_socket_write chunk")?; - let socket = process.tcp_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown TCP socket {socket_id}")) - })?; - socket - .write_all(kernel, process.kernel_pid, &chunk) - .map(|written| json!(written)) - } - "net.upgrade_socket_end" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.upgrade_socket_end socket id")?; - let socket = process.tcp_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown TCP socket {socket_id}")) - })?; - socket.shutdown_write(kernel, process.kernel_pid)?; - Ok(Value::Null) - } - "net.upgrade_socket_destroy" => { - let socket_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "net.upgrade_socket_destroy socket id", - )?; - let socket = process.tcp_sockets.remove(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown TCP socket {socket_id}")) - })?; - release_tcp_socket_handle(process, socket_id, socket, kernel, &kernel_readiness); - Ok(Value::Null) - } - "net.write" => { - let socket_id = javascript_sync_rpc_arg_str(&request.args, 0, "net.write socket id")?; - let chunk = if let Some(bytes) = request.raw_bytes_args.get(&1) { - bytes.clone() - } else { - javascript_sync_rpc_bytes_arg(&request.args, 1, "net.write chunk")? - }; - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .socket_write_calls - .fetch_add(1, Ordering::Relaxed); - NET_TCP_TRACE_COUNTERS.socket_write_bytes.fetch_add( - u64::try_from(chunk.len()).unwrap_or(u64::MAX), - Ordering::Relaxed, - ); - } - if let Some(socket) = process.tcp_sockets.get(socket_id) { - let write_started = trace_enabled.then(Instant::now); - let write_result = socket.write_all(kernel, process.kernel_pid, &chunk); - if let Some(write_started) = write_started { - NET_TCP_TRACE_COUNTERS.socket_write_kernel_us.fetch_add( - duration_micros_u64(write_started.elapsed()), - Ordering::Relaxed, - ); - } - match write_result { - Ok(written) => Ok(json!(written)), - Err(error) => { - if trace_enabled { - NET_TCP_TRACE_COUNTERS - .socket_write_errors - .fetch_add(1, Ordering::Relaxed); - } - Err(error) - } - } - } else { - let socket = process.unix_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown net socket {socket_id}")) - })?; - socket.write_all(&chunk).map(|written| json!(written)) - } - } - "net.shutdown" => { - let socket_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.shutdown socket id")?; - if let Some(socket) = process.tcp_sockets.get(socket_id) { - socket.shutdown_write(kernel, process.kernel_pid)?; - } else { - let socket = process.unix_sockets.get(socket_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown net socket {socket_id}")) - })?; - socket.shutdown_write()?; - } - Ok(Value::Null) - } - "net.destroy" => { - let socket_id = javascript_sync_rpc_arg_str(&request.args, 0, "net.destroy socket id")?; - if let Some(socket) = process.tcp_sockets.remove(socket_id) { - release_tcp_socket_handle(process, socket_id, socket, kernel, &kernel_readiness); - Ok(Value::Null) - } else if let Some(socket) = process.unix_sockets.remove(socket_id) { - release_unix_socket_handle(process, socket_id, socket); - Ok(Value::Null) - } else { - Ok(Value::Null) - } - } - "net.server_close" => { - let listener_id = - javascript_sync_rpc_arg_str(&request.args, 0, "net.server_close listener id")?; - if let Some(listener) = process.tcp_listeners.remove(listener_id) { - unregister_kernel_readiness_target(&kernel_readiness, listener.kernel_socket_id); - listener.close(kernel, process.kernel_pid)?; - Ok(Value::Null) - } else { - let listener = process.unix_listeners.remove(listener_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown net listener {listener_id}")) - })?; - listener.close()?; - Ok(Value::Null) - } - } - "tls.get_ciphers" => javascript_net_json_string( - Value::Array( - tls_provider() - .cipher_suites - .iter() - .filter_map(|suite| { - suite - .suite() - .as_str() - .map(|value| Value::String(value.to_owned())) - }) - .collect(), - ), - "tls.get_ciphers", - ), - _ => Err(SidecarError::InvalidState(format!( - "unsupported JavaScript net sync RPC method {}", - request.method - ))), - } -} - -fn signal_name_for_stream_event(signal: i32) -> Option<&'static str> { - match signal { - libc::SIGHUP => Some("SIGHUP"), - libc::SIGINT => Some("SIGINT"), - libc::SIGUSR1 => Some("SIGUSR1"), - libc::SIGALRM => Some("SIGALRM"), - libc::SIGCONT => Some("SIGCONT"), - libc::SIGTERM => Some("SIGTERM"), - libc::SIGCHLD => Some("SIGCHLD"), - libc::SIGWINCH => Some("SIGWINCH"), - _ => None, - } -} - -pub(crate) fn canonical_signal_name(signal: i32) -> Option<&'static str> { - secure_exec_sidecar_core::canonical_signal_name(signal) -} - -fn dispatch_v8_process_signal(process: &ActiveProcess, signal: i32) -> Result { - let Some(signal_name) = signal_name_for_stream_event(signal) else { - return Ok(false); - }; - process.execution.send_javascript_stream_event( - "signal", - json!({ - "signal": signal_name, - "number": signal, - "action": "default", - }), - )?; - Ok(true) -} - -fn dispatch_v8_session_signal_async(session: V8SessionHandle, signal: i32) { - let Some(signal_name) = signal_name_for_stream_event(signal).map(str::to_owned) else { - return; - }; - thread::spawn(move || { - thread::sleep(Duration::from_millis(1)); - let payload = v8_runtime::json_to_cbor_payload(&json!({ - "signal": signal_name, - "number": signal, - "action": "default", - })) - .unwrap_or_default(); - let _ = session.send_stream_event("signal", payload); - }); -} - -pub(crate) fn parse_signal(signal: &str) -> Result { - let trimmed = signal.trim(); - if trimmed.is_empty() { - return Err(SidecarError::InvalidState(String::from( - "kill_process requires a non-empty signal", - ))); - } - - if let Ok(value) = trimmed.parse::() { - return match value { - 0..=31 => Ok(value), - _ => Err(SidecarError::InvalidState(format!( - "unsupported kill_process signal {signal}" - ))), - }; - } - - secure_exec_sidecar_core::parse_posix_signal(trimmed).ok_or_else(|| { - SidecarError::InvalidState(format!("unsupported kill_process signal {signal}")) - }) -} - -pub(crate) fn runtime_child_is_alive(child_pid: u32) -> Result { - Ok(runtime_child_exit_status(child_pid)?.is_none()) -} - -#[cfg(not(target_os = "macos"))] -fn runtime_child_exit_status(child_pid: u32) -> Result, SidecarError> { - if child_pid == 0 { - return Ok(Some(0)); - } - - let wait_flags = WaitPidFlag::WNOHANG - | WaitPidFlag::WNOWAIT - | WaitPidFlag::WEXITED - | WaitPidFlag::WUNTRACED - | WaitPidFlag::WCONTINUED; - match wait_on_child(WaitId::Pid(Pid::from_raw(child_pid as i32)), wait_flags) { - Ok(WaitStatus::StillAlive) - | Ok(WaitStatus::Stopped(_, _)) - | Ok(WaitStatus::Continued(_)) => Ok(None), - Ok(WaitStatus::Exited(_, status)) => Ok(Some(status)), - Ok(WaitStatus::Signaled(_, signal, _)) => Ok(Some(128 + signal as i32)), - #[cfg(any(target_os = "linux", target_os = "android"))] - Ok(WaitStatus::PtraceEvent(_, _, _) | WaitStatus::PtraceSyscall(_)) => Ok(None), - Err(nix::errno::Errno::ECHILD) => Ok(Some(0)), - Err(error) => Err(SidecarError::Execution(format!( - "failed to inspect guest runtime process {child_pid}: {error}" - ))), - } -} - -// macOS nix exposes no `waitid`/`WNOWAIT`, so we poll with `waitpid(WNOHANG)`. -// NOTE: unlike Linux's `waitid(WNOWAIT)`, `waitpid` REAPS an exited child rather -// than leaving it waitable. That is correct for this poll (the sidecar is the -// reaping parent), but a second status query after exit returns ECHILD → treated -// as "exited(0)" below. -#[cfg(target_os = "macos")] -fn runtime_child_exit_status(child_pid: u32) -> Result, SidecarError> { - if child_pid == 0 { - return Ok(Some(0)); - } - - match waitpid(Pid::from_raw(child_pid as i32), Some(WaitPidFlag::WNOHANG)) { - Ok(WaitStatus::StillAlive) - | Ok(WaitStatus::Stopped(_, _)) - | Ok(WaitStatus::Continued(_)) => Ok(None), - Ok(WaitStatus::Exited(_, status)) => Ok(Some(status)), - Ok(WaitStatus::Signaled(_, signal, _)) => Ok(Some(128 + signal as i32)), - Err(nix::errno::Errno::ECHILD) => Ok(Some(0)), - Err(error) => Err(SidecarError::Execution(format!( - "failed to inspect guest runtime process {child_pid}: {error}" - ))), - } -} - -pub(crate) fn signal_runtime_process(child_pid: u32, signal: i32) -> Result<(), SidecarError> { - if child_pid == 0 { - return Ok(()); - } - - if !runtime_child_is_alive(child_pid)? { - return Ok(()); - } - - if signal == 0 { - return Ok(()); - } - - let parsed = Signal::try_from(signal).map_err(|_| { - SidecarError::InvalidState(format!("unsupported kill_process signal {signal}")) - })?; - let result = send_signal(Pid::from_raw(child_pid as i32), Some(parsed)); - - match result { - Ok(()) => Ok(()), - Err(nix::errno::Errno::ESRCH) => Ok(()), - Err(error) => Err(SidecarError::Execution(format!( - "failed to signal guest runtime process {child_pid}: {error}" - ))), - } -} - -pub(crate) fn error_code(error: &SidecarError) -> &'static str { - match error { - SidecarError::InvalidState(_) => "invalid_state", - SidecarError::ProtocolVersionMismatch(_) => "protocol_version_mismatch", - SidecarError::BridgeVersionMismatch(_) => "bridge_version_mismatch", - SidecarError::Conflict(_) => "conflict", - SidecarError::Unauthorized(_) => "unauthorized", - SidecarError::Unsupported(_) => "unsupported", - SidecarError::FrameTooLarge(_) => "frame_too_large", - SidecarError::Kernel(_) => "kernel_error", - SidecarError::Plugin(_) => "plugin_error", - SidecarError::Execution(_) => "execution_error", - SidecarError::Bridge(_) => "bridge_error", - SidecarError::Io(_) => "io_error", - } -} - -fn guest_errno_code(message: &str) -> Option<&str> { - const TRUSTED_PREFIXES: &[&str] = &[ - "ERR_AGENTOS_NODE_SYNC_RPC", - "ERR_AGENTOS_PYTHON_VFS_RPC", - "ERR_AGENTOS_BRIDGE", - ]; - - let mut segments = message.split(':').map(str::trim); - let first = segments.next()?; - if is_guest_errno_segment(first) { - return Some(first); - } - - if TRUSTED_PREFIXES.contains(&first) { - let second = segments.next()?; - if is_guest_errno_segment(second) { - return Some(second); - } - } - - None -} - -fn is_guest_errno_segment(segment: &str) -> bool { - segment.len() >= 2 - && segment.starts_with('E') - && !segment.starts_with("ERR_") - && segment[1..] - .bytes() - .all(|byte| byte.is_ascii_uppercase() || byte.is_ascii_digit() || byte == b'_') -} - -pub(crate) fn javascript_sync_rpc_error_code(error: &SidecarError) -> String { - let message = error.to_string(); - if let Some(code) = guest_errno_code(&message) { - return code.to_owned(); - } - if message.starts_with("ERR_NATIVE_BINARY_NOT_SUPPORTED:") { - return String::from("ERR_NATIVE_BINARY_NOT_SUPPORTED"); - } - - let lower = message.to_ascii_lowercase(); - if lower.contains("no such file or directory") - || lower.contains("entry not found") - || lower.contains("not found") - { - return String::from("ENOENT"); - } - if lower.contains("permission denied") { - return String::from("EACCES"); - } - if lower.contains("already exists") - || lower.contains("already registered") - || lower.contains("file exists") - { - return String::from("EEXIST"); - } - if lower.contains("invalid argument") { - return String::from("EINVAL"); - } - - String::from("ERR_AGENTOS_NODE_SYNC_RPC") -} - -pub(crate) fn ignore_stale_javascript_sync_rpc_response( - error: SidecarError, -) -> Result<(), SidecarError> { - match error { - SidecarError::Execution(message) - if message.ends_with("is no longer pending") - && message.starts_with("sync RPC request ") => - { - Ok(()) - } - SidecarError::Execution(message) => { - let lower = message.to_ascii_lowercase(); - if lower.contains("sync rpc response") - && (lower.contains("broken pipe") || lower.contains("channel closed unexpectedly")) - { - Ok(()) - } else { - Err(SidecarError::Execution(message)) - } - } - other => Err(other), - } -} - -#[cfg(test)] -mod error_code_tests { - use super::{guest_errno_code, javascript_sync_rpc_error_code, SidecarError}; - - #[test] - fn guest_errno_code_rejects_guest_controlled_errno_segments() { - assert_eq!(guest_errno_code("user said 'EACCES: denied'"), None); - assert_eq!( - guest_errno_code("prefix: user said 'EPERM': more text"), - None - ); - assert_eq!(guest_errno_code("ERR_AGENTOS_FAKE: EACCES: denied"), None); - } - - #[test] - fn guest_errno_code_accepts_trusted_secure_exec_prefixes() { - assert_eq!( - guest_errno_code("ERR_AGENTOS_NODE_SYNC_RPC: EACCES: permission denied on /foo"), - Some("EACCES") - ); - assert_eq!( - guest_errno_code("ERR_AGENTOS_PYTHON_VFS_RPC: ENOENT: missing file"), - Some("ENOENT") - ); - assert_eq!(guest_errno_code("EEXIST: already exists"), Some("EEXIST")); - } - - #[test] - fn javascript_sync_rpc_error_code_ignores_spoofed_errnos() { - let error = SidecarError::Execution(String::from("user said 'EACCES: denied'")); - assert_eq!( - javascript_sync_rpc_error_code(&error), - "ERR_AGENTOS_NODE_SYNC_RPC" - ); - } - - #[test] - fn javascript_sync_rpc_error_code_preserves_real_sidecar_errnos() { - let error = SidecarError::Execution(String::from( - "ERR_AGENTOS_NODE_SYNC_RPC: EACCES: permission denied on /foo", - )); - assert_eq!(javascript_sync_rpc_error_code(&error), "EACCES"); - } - - #[test] - fn javascript_sync_rpc_error_code_maps_file_exists_messages() { - let error = SidecarError::Io(String::from( - "failed to create mapped guest directory /.next/server: File exists (os error 17)", - )); - assert_eq!(javascript_sync_rpc_error_code(&error), "EEXIST"); - } - - #[test] - fn javascript_sync_rpc_error_code_preserves_native_binary_rejections() { - let error = SidecarError::Execution(String::from( - "ERR_NATIVE_BINARY_NOT_SUPPORTED: refused to execute native ELF guest binary at /tmp/fake-rg inside the VM", - )); - assert_eq!( - javascript_sync_rpc_error_code(&error), - "ERR_NATIVE_BINARY_NOT_SUPPORTED" - ); - } -} -#[cfg(test)] -mod ssrf_egress_classifier_tests { - // F-005/006/007 (sec-sidecar T1/T7/T11): the egress classifier must treat the - // unspecified address (0.0.0.0 / ::), CGNAT (100.64.0.0/10), IPv6 spellings of - // restricted IPv4 targets (::a.b.c.d), and reserved/multicast (240/4, 224/4) as - // restricted. 0.0.0.0 routes to 127.0.0.1 on connect(), so leaving it - // unclassified let a guest bypass the loopback port-ownership gate. - // - // These are bounded SAFEGUARD tests: they exercise the classifier and the DNS - // egress filter directly (no network I/O, no Node), so they run fast and - // deterministically. See FAILURES.md#F-005, #F-006, #F-007. - use super::{ - filter_dns_safe_ip_addrs, is_loopback_ip, restricted_non_loopback_ip_range, SidecarError, - }; - use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - - fn assert_restricted(ip: IpAddr, expected_label: &str) { - let classification = restricted_non_loopback_ip_range(ip); - assert!( - classification.is_some(), - "{ip} must be classified as a restricted egress target" - ); - let (_cidr, label) = classification.unwrap(); - assert_eq!( - label, expected_label, - "{ip} should be labelled {expected_label}, got {label}" - ); - } - - fn assert_dns_denied(ip: IpAddr, label: &str) { - match filter_dns_safe_ip_addrs(vec![ip], "attacker.example") { - Err(SidecarError::Execution(message)) => assert!( - message.starts_with("EACCES:"), - "{label}: egress filter must deny with EACCES, got: {message}" - ), - other => panic!("{label}: expected EACCES denial, got {other:?}"), - } - } - - // F-005 (sec-sidecar T1). - #[test] - fn classifier_denies_unspecified_and_cgnat_targets() { - // 0.0.0.0 (IPv4 unspecified) -> would route to host loopback. - assert_restricted(IpAddr::V4(Ipv4Addr::UNSPECIFIED), "unspecified"); - // :: (IPv6 unspecified). - assert_restricted(IpAddr::V6(Ipv6Addr::UNSPECIFIED), "unspecified"); - - // CGNAT 100.64.0.0/10 spans 100.64.x.x .. 100.127.x.x. - assert_restricted( - IpAddr::V4(Ipv4Addr::new(100, 64, 0, 1)), - "carrier-grade-nat", - ); - assert_restricted( - IpAddr::V4(Ipv4Addr::new(100, 127, 255, 254)), - "carrier-grade-nat", - ); - - // Guard against over-blocking: addresses just outside 100.64/10 stay allowed. - assert!( - restricted_non_loopback_ip_range(IpAddr::V4(Ipv4Addr::new(100, 63, 255, 255))) - .is_none(), - "100.63.255.255 is outside CGNAT and must remain allowed" - ); - assert!( - restricted_non_loopback_ip_range(IpAddr::V4(Ipv4Addr::new(100, 128, 0, 0))).is_none(), - "100.128.0.0 is outside CGNAT and must remain allowed" - ); - - // The DNS egress filter must also deny these via EACCES. - assert_dns_denied(IpAddr::V4(Ipv4Addr::UNSPECIFIED), "0.0.0.0 (unspecified)"); - assert_dns_denied(IpAddr::V6(Ipv6Addr::UNSPECIFIED), ":: (unspecified)"); - assert_dns_denied( - IpAddr::V4(Ipv4Addr::new(100, 64, 0, 1)), - "100.64.0.1 (CGNAT)", - ); - } - - // F-006 (sec-sidecar T7). - #[test] - fn classifier_denies_ipv6_spelled_metadata_addresses() { - // The IPv4-mapped form (::ffff:169.254.169.254) was already handled; the - // IPv4-compatible form (::169.254.169.254) is the gap this fixes. - let mapped = "::ffff:169.254.169.254".parse::().unwrap(); - assert_restricted(IpAddr::V6(mapped), "link-local"); - - let compat = "::169.254.169.254".parse::().unwrap(); - assert_restricted(IpAddr::V6(compat), "link-local"); - - // Other IPv4-compatible private/CGNAT spellings must also be canonicalized. - assert_restricted( - IpAddr::V6("::10.0.0.1".parse::().unwrap()), - "private", - ); - assert_restricted( - IpAddr::V6("::100.64.0.1".parse::().unwrap()), - "carrier-grade-nat", - ); - - // Guard against over-blocking: the IPv6 unspecified/loopback addresses - // are not IPv4-compatible host targets, and a public IPv4-compatible - // address must remain allowed. - assert_eq!( - restricted_non_loopback_ip_range(IpAddr::V6(Ipv6Addr::UNSPECIFIED)), - Some(("::/128", "unspecified")), - ":: must classify as unspecified, not via the IPv4-compat path" - ); - assert!( - restricted_non_loopback_ip_range(IpAddr::V6(Ipv6Addr::LOCALHOST)).is_none() - || is_loopback_ip(IpAddr::V6(Ipv6Addr::LOCALHOST)), - "::1 must not be classified as a restricted IPv4-compatible target" - ); - assert!( - restricted_non_loopback_ip_range(IpAddr::V6("::8.8.8.8".parse::().unwrap())) - .is_none(), - "::8.8.8.8 (public IPv4-compatible) must remain allowed" - ); - - // The DNS egress filter must deny the IPv4-compat metadata spelling. - assert_dns_denied( - IpAddr::V6("::169.254.169.254".parse::().unwrap()), - "::169.254.169.254 (IPv4-compat metadata)", - ); - } - - // F-007 (sec-sidecar T11). - #[test] - fn classifier_denies_reserved_and_multicast_targets() { - // 224.0.0.0/4 (multicast) and 240.0.0.0/4 (reserved / future use) are not - // legitimate unicast egress targets; a guest connect to them must be - // classified as restricted and denied. - assert_restricted(IpAddr::V4(Ipv4Addr::new(224, 0, 0, 1)), "multicast"); - assert_restricted(IpAddr::V4(Ipv4Addr::new(239, 255, 255, 255)), "multicast"); - assert_restricted(IpAddr::V4(Ipv4Addr::new(240, 0, 0, 1)), "reserved"); - // 255.255.255.255 (limited broadcast) falls in 240.0.0.0/4. - assert_restricted(IpAddr::V4(Ipv4Addr::BROADCAST), "reserved"); - - // IPv4-compatible IPv6 spellings must canonicalize and be denied too. - assert_restricted( - IpAddr::V6("::224.0.0.1".parse::().unwrap()), - "multicast", - ); - assert_restricted( - IpAddr::V6("::240.0.0.1".parse::().unwrap()), - "reserved", - ); - - // Guard against over-blocking: addresses just outside 224/4 stay allowed. - assert!( - restricted_non_loopback_ip_range(IpAddr::V4(Ipv4Addr::new(223, 255, 255, 255))) - .is_none(), - "223.255.255.255 is outside 224/4 and must remain allowed" - ); - - // The DNS egress filter must also deny these via EACCES. - assert_dns_denied( - IpAddr::V4(Ipv4Addr::new(240, 0, 0, 1)), - "240.0.0.1 (reserved)", - ); - assert_dns_denied( - IpAddr::V4(Ipv4Addr::new(224, 0, 0, 1)), - "224.0.0.1 (multicast)", - ); - } -} - -/// Adversarial coverage for the DNS-rebinding gap (VECTORS.md D.3) on the -/// Python/Pyodide `httpRequestSync` outbound HTTP path. The egress range guard -/// (`filter_dns_safe_ip_addrs`) runs at resolution time, but `ureq` performs its -/// own DNS resolution for the TCP/TLS connect, so a rebinding DNS server could -/// previously make the second lookup land on a private/link-local/metadata IP -/// the first check rejected. The fix pins `ureq`'s resolver to the vetted -/// address set; these tests prove the connect is pinned and refuses any other -/// host or an empty (fully-rejected) address set. -#[cfg(test)] -mod dns_rebinding_pin_tests { - use super::{issue_outbound_http_request, split_netloc, JavascriptHttpRequestOptions}; - use std::collections::BTreeMap; - use std::io::{Read, Write}; - use std::net::{IpAddr, Ipv4Addr, TcpListener}; - use std::thread; - use url::Url; - - fn empty_headers() -> super::HttpHeaderCollection { - super::parse_http_header_collection(&BTreeMap::new(), "test headers") - .expect("empty header collection") - } - - fn options() -> JavascriptHttpRequestOptions { - JavascriptHttpRequestOptions { - method: Some(String::from("GET")), - headers: BTreeMap::new(), - body: None, - reject_unauthorized: None, - } - } - - #[test] - fn split_netloc_handles_hostnames_and_bracketed_ipv6() { - assert_eq!( - split_netloc("attacker.example:80"), - Some(("attacker.example", 80)) - ); - assert_eq!(split_netloc("[::1]:443"), Some(("::1", 443))); - assert_eq!(split_netloc("10.0.0.1:8080"), Some(("10.0.0.1", 8080))); - assert_eq!(split_netloc("no-port"), None); - assert_eq!(split_netloc("host:notaport"), None); - } - - /// A loopback HTTP server stands in for the egress-vetted target. The - /// request URL uses a *different* hostname (`attacker.example`) whose real - /// DNS would resolve elsewhere; pinning forces the connect onto the vetted - /// IP only. If the resolver were unpinned, the request would fail to reach - /// this server (and on a real host could land on a private/metadata IP). - #[test] - fn outbound_http_connect_is_pinned_to_vetted_ip() { - let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).expect("bind loopback server"); - let port = listener.local_addr().expect("local addr").port(); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept"); - let mut buf = [0u8; 1024]; - let _ = stream.read(&mut buf); - stream - .write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi") - .expect("write response"); - let _ = stream.flush(); - }); - - let url = Url::parse(&format!("http://attacker.example:{port}/")).expect("url"); - let pinned = vec![IpAddr::V4(Ipv4Addr::LOCALHOST)]; - let result = issue_outbound_http_request(&url, &options(), &empty_headers(), &pinned) - .expect("pinned request should reach the vetted loopback target"); - let payload = result.as_str().expect("string payload"); - assert!( - payload.contains("\"status\":200"), - "expected 200 from pinned target, got: {payload}" - ); - server.join().expect("server thread"); - } - - /// With no vetted address (every resolved IP was rejected by the range - /// guard, or the literal IP was a blocked range), the pinned resolver must - /// refuse rather than fall back to the host resolver. - #[test] - fn outbound_http_refuses_when_no_vetted_address() { - let url = Url::parse("https://attacker.example/").expect("url"); - let error = issue_outbound_http_request(&url, &options(), &empty_headers(), &[]) - .expect_err("empty pinned set must be refused"); - let message = error.to_string(); - assert!( - message.contains("EACCES") || message.contains("ERR_HTTP_REQUEST_FAILED"), - "expected an egress refusal, got: {message}" - ); - } -} diff --git a/crates/sidecar/src/extension.rs b/crates/sidecar/src/extension.rs deleted file mode 100644 index b2d22808d..000000000 --- a/crates/sidecar/src/extension.rs +++ /dev/null @@ -1,727 +0,0 @@ -use std::future::Future; -use std::pin::Pin; -use std::time::Duration; - -use crate::protocol::{ - CloseStdinRequest, EventFrame, EventPayload, ExecuteRequest, ExtEnvelope, - GuestFilesystemCallRequest, GuestFilesystemResultResponse, KillProcessRequest, OwnershipScope, - ProcessKilledResponse, ProcessStartedResponse, SidecarRequestPayload, SidecarResponsePayload, - StdinClosedResponse, StdinWrittenResponse, WriteStdinRequest, -}; -use crate::state::{SharedEventSink, SharedSidecarRequestClient, SidecarError}; - -pub type ExtensionFuture<'a, T> = Pin> + 'a>>; - -pub trait ExtensionHost { - fn spawn_process<'a>( - &'a mut self, - ownership: OwnershipScope, - request: ExecuteRequest, - ) -> ExtensionFuture<'a, ProcessStartedResponse>; - - fn write_stdin<'a>( - &'a mut self, - ownership: OwnershipScope, - request: WriteStdinRequest, - ) -> ExtensionFuture<'a, StdinWrittenResponse>; - - fn close_stdin<'a>( - &'a mut self, - ownership: OwnershipScope, - request: CloseStdinRequest, - ) -> ExtensionFuture<'a, StdinClosedResponse>; - - fn kill_process<'a>( - &'a mut self, - ownership: OwnershipScope, - request: KillProcessRequest, - ) -> ExtensionFuture<'a, ProcessKilledResponse>; - - fn poll_event<'a>( - &'a mut self, - ownership: OwnershipScope, - timeout: Duration, - ) -> ExtensionFuture<'a, Option>; - - fn guest_filesystem_call<'a>( - &'a mut self, - ownership: OwnershipScope, - request: GuestFilesystemCallRequest, - ) -> ExtensionFuture<'a, GuestFilesystemResultResponse>; - - fn bind_process_to_session<'a>( - &'a mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - process_id: String, - ) -> ExtensionFuture<'a, ()>; - - fn bind_vm_to_session<'a>( - &'a mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - ) -> ExtensionFuture<'a, ()>; - - fn dispose_session_resources<'a>( - &'a mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - ) -> ExtensionFuture<'a, Vec>; - - fn start_buffering_process_output<'a>( - &'a mut self, - ownership: OwnershipScope, - process_id: String, - ) -> ExtensionFuture<'a, ()>; - - fn handoff_buffered_process_output<'a>( - &'a mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - process_id: String, - timeout: Duration, - ) -> ExtensionFuture<'a, ExtensionBufferedProcessOutput>; -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct ExtensionBufferedProcessOutput { - pub stdout: Vec, - pub stderr: Vec, - pub stdout_truncated: bool, - pub stderr_truncated: bool, -} - -impl ExtensionBufferedProcessOutput { - pub(crate) fn append_stdout(&mut self, chunk: &[u8], cap: usize) { - self.stdout_truncated |= append_bounded_bytes(&mut self.stdout, chunk, cap); - } - - pub(crate) fn append_stderr(&mut self, chunk: &[u8], cap: usize) { - self.stderr_truncated |= append_bounded_bytes(&mut self.stderr, chunk, cap); - } -} - -fn append_bounded_bytes(buffer: &mut Vec, chunk: &[u8], cap: usize) -> bool { - buffer.extend_from_slice(chunk); - if buffer.len() <= cap { - return false; - } - let remove_len = buffer.len() - cap; - buffer.drain(..remove_len); - true -} - -#[derive(Debug, Clone)] -pub struct ExtensionResponse { - pub payload: Vec, - pub events: Vec, -} - -impl ExtensionResponse { - pub fn new(payload: Vec) -> Self { - Self { - payload, - events: Vec::new(), - } - } - - pub fn with_events(payload: Vec, events: Vec) -> Self { - Self { payload, events } - } - - pub fn with_wire_events( - payload: Vec, - events: Vec, - ) -> Result { - let events = events - .into_iter() - .map(crate::wire::event_frame_to_compat) - .collect::, _>>() - .map_err(wire_protocol_error)?; - Ok(Self { payload, events }) - } -} - -#[derive(Clone)] -pub struct ExtensionSnapshot { - namespace: String, - ownership: OwnershipScope, - sidecar_requests: SharedSidecarRequestClient, - event_sink: SharedEventSink, -} - -pub struct ExtensionContext<'a> { - snapshot: ExtensionSnapshot, - host: &'a mut dyn ExtensionHost, -} - -impl ExtensionSnapshot { - pub(crate) fn new( - namespace: String, - ownership: OwnershipScope, - sidecar_requests: SharedSidecarRequestClient, - event_sink: SharedEventSink, - ) -> Self { - Self { - namespace, - ownership, - sidecar_requests, - event_sink, - } - } - - pub fn namespace(&self) -> &str { - &self.namespace - } - - pub fn ownership(&self) -> &OwnershipScope { - &self.ownership - } - - pub fn ext_event(&self, payload: Vec) -> EventFrame { - EventFrame::new( - self.ownership.clone(), - EventPayload::Ext(ExtEnvelope { - namespace: self.namespace.clone(), - payload, - }), - ) - } - - pub fn ext_event_wire( - &self, - payload: Vec, - ) -> Result { - crate::wire::event_frame_from_compat(self.ext_event(payload)).map_err(wire_protocol_error) - } - - /// Emit a wire event frame to the host the instant it is produced, rather - /// than collecting it into the dispatch result and waiting for the whole - /// request to resolve. Returns `Ok(None)` when delivered live, or - /// `Ok(Some(event))` when no live sink is configured (in-process sidecar) so - /// the caller can fall back to returning it in the dispatch's batch. - pub fn emit_event_wire( - &self, - event: crate::wire::EventFrame, - ) -> Result, SidecarError> { - self.event_sink.try_emit(event) - } - - /// Build a namespaced ext-event from `payload` and emit it live (see - /// [`Self::emit_event_wire`]). - pub fn emit_ext_event( - &self, - payload: Vec, - ) -> Result, SidecarError> { - let event = self.ext_event_wire(payload)?; - self.emit_event_wire(event) - } - - pub fn invoke_callback( - &self, - payload: Vec, - timeout: Duration, - ) -> Result, SidecarError> { - let response = self.sidecar_requests.invoke( - self.ownership.clone(), - SidecarRequestPayload::Ext(ExtEnvelope { - namespace: self.namespace.clone(), - payload, - }), - timeout, - )?; - extension_callback_response_payload(&self.namespace, response) - } -} - -impl<'a> ExtensionContext<'a> { - pub(crate) fn new(snapshot: ExtensionSnapshot, host: &'a mut dyn ExtensionHost) -> Self { - Self { snapshot, host } - } - - pub fn snapshot(&self) -> ExtensionSnapshot { - self.snapshot.clone() - } - - pub fn namespace(&self) -> &str { - self.snapshot.namespace() - } - - pub fn ownership(&self) -> &OwnershipScope { - self.snapshot.ownership() - } - - pub fn ext_event(&self, payload: Vec) -> EventFrame { - self.snapshot.ext_event(payload) - } - - pub fn ext_event_wire( - &self, - payload: Vec, - ) -> Result { - self.snapshot.ext_event_wire(payload) - } - - /// Emit a wire event frame to the host live (see - /// [`ExtensionSnapshot::emit_event_wire`]). - pub fn emit_event_wire( - &self, - event: crate::wire::EventFrame, - ) -> Result, SidecarError> { - self.snapshot.emit_event_wire(event) - } - - /// Build a namespaced ext-event from `payload` and emit it live (see - /// [`ExtensionSnapshot::emit_ext_event`]). - pub fn emit_ext_event( - &self, - payload: Vec, - ) -> Result, SidecarError> { - self.snapshot.emit_ext_event(payload) - } - - pub fn invoke_callback( - &self, - payload: Vec, - timeout: Duration, - ) -> Result, SidecarError> { - self.snapshot.invoke_callback(payload, timeout) - } - - pub async fn spawn_process( - &mut self, - request: ExecuteRequest, - ) -> Result { - self.host - .spawn_process(self.snapshot.ownership.clone(), request) - .await - } - - pub async fn spawn_process_wire( - &mut self, - request: crate::wire::ExecuteRequest, - ) -> Result { - let payload = crate::wire::request_payload_to_compat( - self.snapshot.ownership(), - crate::wire::RequestPayload::ExecuteRequest(request), - ) - .map_err(wire_protocol_error)?; - let crate::protocol::RequestPayload::Execute(request) = payload else { - return Err(unexpected_wire_request_payload("execute")); - }; - let response = self.spawn_process(request).await?; - let payload = crate::wire::response_payload_from_compat( - self.snapshot.ownership(), - crate::protocol::ResponsePayload::ProcessStarted(response), - ) - .map_err(wire_protocol_error)?; - let crate::wire::ResponsePayload::ProcessStartedResponse(response) = payload else { - return Err(unexpected_wire_response_payload("process started")); - }; - Ok(response) - } - - pub async fn write_stdin( - &mut self, - request: WriteStdinRequest, - ) -> Result { - self.host - .write_stdin(self.snapshot.ownership.clone(), request) - .await - } - - pub async fn write_stdin_wire( - &mut self, - request: crate::wire::WriteStdinRequest, - ) -> Result { - let payload = crate::wire::request_payload_to_compat( - self.snapshot.ownership(), - crate::wire::RequestPayload::WriteStdinRequest(request), - ) - .map_err(wire_protocol_error)?; - let crate::protocol::RequestPayload::WriteStdin(request) = payload else { - return Err(unexpected_wire_request_payload("write stdin")); - }; - let response = self.write_stdin(request).await?; - let payload = crate::wire::response_payload_from_compat( - self.snapshot.ownership(), - crate::protocol::ResponsePayload::StdinWritten(response), - ) - .map_err(wire_protocol_error)?; - let crate::wire::ResponsePayload::StdinWrittenResponse(response) = payload else { - return Err(unexpected_wire_response_payload("stdin written")); - }; - Ok(response) - } - - pub async fn close_stdin( - &mut self, - request: CloseStdinRequest, - ) -> Result { - self.host - .close_stdin(self.snapshot.ownership.clone(), request) - .await - } - - pub async fn close_stdin_wire( - &mut self, - request: crate::wire::CloseStdinRequest, - ) -> Result { - let payload = crate::wire::request_payload_to_compat( - self.snapshot.ownership(), - crate::wire::RequestPayload::CloseStdinRequest(request), - ) - .map_err(wire_protocol_error)?; - let crate::protocol::RequestPayload::CloseStdin(request) = payload else { - return Err(unexpected_wire_request_payload("close stdin")); - }; - let response = self.close_stdin(request).await?; - let payload = crate::wire::response_payload_from_compat( - self.snapshot.ownership(), - crate::protocol::ResponsePayload::StdinClosed(response), - ) - .map_err(wire_protocol_error)?; - let crate::wire::ResponsePayload::StdinClosedResponse(response) = payload else { - return Err(unexpected_wire_response_payload("stdin closed")); - }; - Ok(response) - } - - pub async fn kill_process( - &mut self, - request: KillProcessRequest, - ) -> Result { - self.host - .kill_process(self.snapshot.ownership.clone(), request) - .await - } - - pub async fn kill_process_wire( - &mut self, - request: crate::wire::KillProcessRequest, - ) -> Result { - let payload = crate::wire::request_payload_to_compat( - self.snapshot.ownership(), - crate::wire::RequestPayload::KillProcessRequest(request), - ) - .map_err(wire_protocol_error)?; - let crate::protocol::RequestPayload::KillProcess(request) = payload else { - return Err(unexpected_wire_request_payload("kill process")); - }; - let response = self.kill_process(request).await?; - let payload = crate::wire::response_payload_from_compat( - self.snapshot.ownership(), - crate::protocol::ResponsePayload::ProcessKilled(response), - ) - .map_err(wire_protocol_error)?; - let crate::wire::ResponsePayload::ProcessKilledResponse(response) = payload else { - return Err(unexpected_wire_response_payload("process killed")); - }; - Ok(response) - } - - pub async fn poll_event( - &mut self, - timeout: Duration, - ) -> Result, SidecarError> { - self.host - .poll_event(self.snapshot.ownership.clone(), timeout) - .await - } - - pub async fn poll_event_wire( - &mut self, - timeout: Duration, - ) -> Result, SidecarError> { - self.poll_event(timeout) - .await? - .map(crate::wire::event_frame_from_compat) - .transpose() - .map_err(wire_protocol_error) - } - - pub async fn guest_filesystem_call( - &mut self, - request: GuestFilesystemCallRequest, - ) -> Result { - self.host - .guest_filesystem_call(self.snapshot.ownership.clone(), request) - .await - } - - pub async fn guest_filesystem_call_wire( - &mut self, - request: crate::wire::GuestFilesystemCallRequest, - ) -> Result { - let payload = crate::wire::request_payload_to_compat( - self.snapshot.ownership(), - crate::wire::RequestPayload::GuestFilesystemCallRequest(request), - ) - .map_err(wire_protocol_error)?; - let crate::protocol::RequestPayload::GuestFilesystemCall(request) = payload else { - return Err(unexpected_wire_request_payload("guest filesystem call")); - }; - let response = self.guest_filesystem_call(request).await?; - let payload = crate::wire::response_payload_from_compat( - self.snapshot.ownership(), - crate::protocol::ResponsePayload::GuestFilesystemResult(response), - ) - .map_err(wire_protocol_error)?; - let crate::wire::ResponsePayload::GuestFilesystemResultResponse(response) = payload else { - return Err(unexpected_wire_response_payload("guest filesystem result")); - }; - Ok(response) - } - - pub async fn bind_process_to_session( - &mut self, - ext_session_id: impl Into, - process_id: impl Into, - ) -> Result<(), SidecarError> { - self.host - .bind_process_to_session( - self.snapshot.ownership.clone(), - self.snapshot.namespace.clone(), - ext_session_id.into(), - process_id.into(), - ) - .await - } - - pub async fn bind_vm_to_session( - &mut self, - ext_session_id: impl Into, - ) -> Result<(), SidecarError> { - self.host - .bind_vm_to_session( - self.snapshot.ownership.clone(), - self.snapshot.namespace.clone(), - ext_session_id.into(), - ) - .await - } - - pub async fn dispose_session_resources( - &mut self, - ext_session_id: impl Into, - ) -> Result, SidecarError> { - self.host - .dispose_session_resources( - self.snapshot.ownership.clone(), - self.snapshot.namespace.clone(), - ext_session_id.into(), - ) - .await - } - - pub async fn dispose_session_resources_wire( - &mut self, - ext_session_id: impl Into, - ) -> Result, SidecarError> { - self.dispose_session_resources(ext_session_id) - .await? - .into_iter() - .map(crate::wire::event_frame_from_compat) - .collect::, _>>() - .map_err(wire_protocol_error) - } - - pub async fn start_buffering_process_output( - &mut self, - process_id: impl Into, - ) -> Result<(), SidecarError> { - self.host - .start_buffering_process_output(self.snapshot.ownership.clone(), process_id.into()) - .await - } - - pub async fn handoff_buffered_process_output( - &mut self, - ext_session_id: impl Into, - process_id: impl Into, - timeout: Duration, - ) -> Result { - self.host - .handoff_buffered_process_output( - self.snapshot.ownership.clone(), - self.snapshot.namespace.clone(), - ext_session_id.into(), - process_id.into(), - timeout, - ) - .await - } -} - -fn wire_protocol_error(error: crate::wire::ProtocolCodecError) -> SidecarError { - SidecarError::InvalidState(format!("invalid generated wire protocol frame: {error}")) -} - -fn unexpected_wire_request_payload(operation: &str) -> SidecarError { - SidecarError::InvalidState(format!( - "generated wire {operation} request converted to the wrong compatibility payload" - )) -} - -fn unexpected_wire_response_payload(operation: &str) -> SidecarError { - SidecarError::InvalidState(format!( - "compatibility {operation} response converted to the wrong generated wire payload" - )) -} - -fn extension_callback_response_payload( - namespace: &str, - response: SidecarResponsePayload, -) -> Result, SidecarError> { - match response { - SidecarResponsePayload::ExtResult(envelope) if envelope.namespace == namespace => { - Ok(envelope.payload) - } - SidecarResponsePayload::ExtResult(envelope) => Err(SidecarError::InvalidState(format!( - "extension callback response namespace {} did not match {}", - envelope.namespace, namespace - ))), - SidecarResponsePayload::HostCallbackResult(_) - | SidecarResponsePayload::JsBridgeResult(_) => Err(SidecarError::InvalidState( - String::from("extension callback received a non-extension response"), - )), - } -} - -pub enum ExtensionInterruptRequest<'a> { - ExtensionPayload(&'a [u8]), - KillProcess, -} - -#[derive(Debug, Clone)] -pub struct ExtensionInterruptResponse { - pub interrupted_response_payload: Vec, - pub interrupting_response_payload: Option>, -} - -pub trait Extension: Send + Sync { - fn namespace(&self) -> &str; - - fn handle_request<'a>( - &'a self, - ctx: ExtensionContext<'a>, - payload: Vec, - ) -> ExtensionFuture<'a, ExtensionResponse>; - - fn on_vm_created<'a>(&'a self, _ctx: ExtensionSnapshot) -> ExtensionFuture<'a, ()> { - Box::pin(async { Ok(()) }) - } - - /// Per-session teardown hook. The host invokes this for every registered - /// extension when a session is disposed because its connection closed - /// (`DisposeReason::ConnectionClosed`), giving the extension the disposed - /// session's ownership scope so it can release the per-session state it - /// keyed on that session. Default is a no-op. This is the only signal an - /// extension receives that a client has disconnected, so it is what lets an - /// ACP-style extension free per-session state instead of leaking it for the - /// process lifetime. - fn on_session_disposed<'a>(&'a self, _ctx: ExtensionSnapshot) -> ExtensionFuture<'a, ()> { - Box::pin(async { Ok(()) }) - } - - fn is_blocking_request(&self, _payload: &[u8]) -> bool { - false - } - - fn interrupt_blocking_request( - &self, - _blocking_payload: &[u8], - _interrupt: ExtensionInterruptRequest<'_>, - ) -> Option { - None - } - - fn on_dispose<'a>(&'a self) -> ExtensionFuture<'a, ()> { - Box::pin(async { Ok(()) }) - } -} - -#[cfg(test)] -mod live_event_tests { - use super::*; - use crate::state::EventSinkTransport; - use std::sync::{Arc, Mutex}; - - /// Records every event handed to the live sink, standing in for the stdio - /// `FrameEventTransport` that writes `ProtocolFrame::EventFrame`s to stdout. - #[derive(Default)] - struct RecordingEventSink { - events: Arc>>, - } - - impl EventSinkTransport for RecordingEventSink { - fn emit_event(&self, event: crate::wire::EventFrame) -> Result<(), SidecarError> { - self.events.lock().unwrap().push(event); - Ok(()) - } - } - - fn snapshot_with_sink(event_sink: SharedEventSink) -> ExtensionSnapshot { - ExtensionSnapshot::new( - String::from("dev.rivet.test.live-event"), - OwnershipScope::session("conn-live", "sess-live"), - SharedSidecarRequestClient::default(), - event_sink, - ) - } - - // With a transport configured (the stdio path), an ext event is emitted live - // and `emit_ext_event` reports nothing left to batch. - #[test] - fn emit_ext_event_streams_live_when_sink_configured() { - let recorded = Arc::new(Mutex::new(Vec::new())); - let mut sink = SharedEventSink::default(); - sink.set_transport(Arc::new(RecordingEventSink { - events: recorded.clone(), - })); - - let snapshot = snapshot_with_sink(sink); - let leftover = snapshot - .emit_ext_event(b"live-update".to_vec()) - .expect("emit must succeed"); - - assert!( - leftover.is_none(), - "a configured sink consumes the event live, leaving nothing to batch" - ); - let recorded = recorded.lock().unwrap(); - assert_eq!(recorded.len(), 1, "the event must reach the live transport"); - // The live frame round-trips back to the namespaced ext payload. - let compat = crate::wire::event_frame_to_compat(recorded[0].clone()) - .expect("recorded frame converts back to compat"); - match compat.payload { - EventPayload::Ext(envelope) => { - assert_eq!(envelope.namespace, "dev.rivet.test.live-event"); - assert_eq!(envelope.payload, b"live-update"); - } - other => panic!("unexpected live event payload: {other:?}"), - } - } - - // With no transport (an in-process sidecar), the event is handed back so the - // caller can fall back to the dispatch-result batch — preserving delivery. - #[test] - fn emit_ext_event_falls_back_to_batch_without_sink() { - let snapshot = snapshot_with_sink(SharedEventSink::default()); - let leftover = snapshot - .emit_ext_event(b"batched-update".to_vec()) - .expect("emit must succeed"); - - let frame = leftover.expect("without a sink the event is returned for batching"); - let compat = crate::wire::event_frame_to_compat(frame) - .expect("returned frame converts back to compat"); - match compat.payload { - EventPayload::Ext(envelope) => assert_eq!(envelope.payload, b"batched-update"), - other => panic!("unexpected batched event payload: {other:?}"), - } - } -} diff --git a/crates/sidecar/src/filesystem.rs b/crates/sidecar/src/filesystem.rs deleted file mode 100644 index 278c30baf..000000000 --- a/crates/sidecar/src/filesystem.rs +++ /dev/null @@ -1,5096 +0,0 @@ -//! Guest filesystem and VFS dispatch extracted from service.rs. - -use crate::execution::{ - host_path_from_runtime_guest_mappings, is_protected_agentos_shadow_sync_path, - sync_active_process_host_writes_to_kernel, -}; -use crate::protocol::{ - GuestFilesystemCallRequest, GuestFilesystemOperation, GuestRuntimeKind, RequestFrame, - ResponsePayload, -}; -use crate::service::{ - javascript_sync_rpc_arg_str, javascript_sync_rpc_arg_u32, javascript_sync_rpc_arg_u32_optional, - javascript_sync_rpc_arg_u64, javascript_sync_rpc_arg_u64_optional, - javascript_sync_rpc_bytes_arg, javascript_sync_rpc_bytes_value, javascript_sync_rpc_encoding, - javascript_sync_rpc_option_bool, javascript_sync_rpc_option_u32, kernel_error, - log_stale_process_event, normalize_host_path, normalize_path, path_is_within_root, -}; -use crate::state::{ - ActiveExecutionEvent, ActiveProcess, BridgeError, SidecarKernel, VmState, - EXECUTION_DRIVER_NAME, EXECUTION_SANDBOX_ROOT_ENV, PYTHON_VFS_RPC_GUEST_ROOT, -}; -use crate::{DispatchResult, NativeSidecar, NativeSidecarBridge, SidecarError}; - -use base64::Engine; -use nix::errno::Errno; -use nix::fcntl::{open, OFlag}; -#[cfg(not(target_os = "macos"))] -use nix::fcntl::{openat2, OpenHow, ResolveFlag}; -use nix::libc; - -// macOS has neither `O_PATH` (metadata-only anchor) nor `O_TMPFILE`. O_PATH -// anchors are re-opened via `/dev/fd/N`, so a read-only open stands in; no -// caller actually passes O_TMPFILE (it appears only in a defensive `intersects` -// check), so an empty flag is an exact behavioural match there. -#[cfg(not(target_os = "macos"))] -const O_PATH_ANCHOR: OFlag = OFlag::O_PATH; -#[cfg(target_os = "macos")] -const O_PATH_ANCHOR: OFlag = OFlag::O_RDONLY; -#[cfg(not(target_os = "macos"))] -const O_TMPFILE_FLAG: OFlag = OFlag::O_TMPFILE; -#[cfg(target_os = "macos")] -const O_TMPFILE_FLAG: OFlag = OFlag::empty(); -use nix::sys::stat::{utimensat, Mode, UtimensatFlags}; -use nix::sys::time::TimeSpec; -use secure_exec_execution::{ - JavascriptSyncRpcRequest, LocalResolvedModuleFormat, ModuleFsReader, ModuleResolveMode, - ModuleResolver, PythonVfsRpcMethod, PythonVfsRpcRequest, PythonVfsRpcResponsePayload, - PythonVfsRpcStat, -}; -use secure_exec_kernel::vfs::{VirtualStat, VirtualTimeSpec, VirtualUtimeSpec}; -use secure_exec_sidecar_core::{ - decode_guest_filesystem_content, handle_guest_filesystem_call as core_guest_filesystem_call, -}; -use serde::Deserialize; -use serde_json::{json, Map, Value}; -use std::collections::{BTreeMap, BTreeSet}; -use std::env; -use std::ffi::OsString; -use std::fmt; -use std::fs::{self, OpenOptions}; -use std::io::{Read, Write}; -use std::os::fd::{AsRawFd, RawFd}; -use std::os::unix::fs::{symlink, FileExt, MetadataExt, OpenOptionsExt, PermissionsExt}; -use std::path::{Path, PathBuf}; -use std::sync::{Mutex, OnceLock}; -use std::time::Instant; - -const PYTHON_PYODIDE_GUEST_ROOT: &str = "/__agentos_pyodide"; - -fn kernel_path_error( - operation: &str, - path: &str, - error: impl Into, -) -> SidecarError { - let error = error.into(); - let base = kernel_error(error); - match base { - SidecarError::Kernel(message) => { - SidecarError::Kernel(format!("{operation} {path}: {message}")) - } - other => other, - } -} - -fn filesystem_access_denied(path: &str, mode: u32) -> SidecarError { - SidecarError::Execution(format!( - "EACCES: filesystem access denied for {path} with mode {mode:o}" - )) -} - -fn filesystem_access_mode_is_allowed(file_mode: u32, requested: u32) -> bool { - const ACCESS_MASK: u32 = libc::R_OK as u32 | libc::W_OK as u32 | libc::X_OK as u32; - if requested & ACCESS_MASK == 0 { - return true; - } - if requested & libc::R_OK as u32 != 0 && file_mode & 0o444 == 0 { - return false; - } - if requested & libc::W_OK as u32 != 0 && file_mode & 0o222 == 0 { - return false; - } - if requested & libc::X_OK as u32 != 0 && file_mode & 0o111 == 0 { - return false; - } - true -} -const PYTHON_PYODIDE_CACHE_GUEST_ROOT: &str = "/__agentos_pyodide_cache"; -const UTIME_NOW_NSEC: i64 = libc::UTIME_NOW; -const UTIME_OMIT_NSEC: i64 = libc::UTIME_OMIT; - -/// Backstop bound on a guest-controlled `ftruncate` length for a mapped host fd. -/// The kernel's configured truncate-size limit is the primary enforcement for -/// paths visible in the VFS; this caps the raw host `set_len` (and covers fds -/// with no kernel-visible guest path) so a hostile length cannot create an -/// enormous sparse host file or drive an unbounded sidecar-side mirror read. -const MAX_MAPPED_TRUNCATE_BYTES: u64 = 4 * 1024 * 1024 * 1024; - -#[derive(Debug, Clone)] -struct MappedRuntimeHostPath { - guest_path: String, - host_root: PathBuf, - host_path: PathBuf, -} - -#[derive(Debug, Clone)] -enum MappedRuntimeHostAccess { - Writable(MappedRuntimeHostPath), - ReadOnly(MappedRuntimeHostPath), -} - -#[derive(Debug)] -struct AnchoredFd { - fd: RawFd, -} - -impl AnchoredFd { - #[cfg(not(target_os = "macos"))] - fn proc_path(&self) -> PathBuf { - PathBuf::from(format!("/proc/self/fd/{}", self.fd)) - } - - // macOS `/dev/fd/N` re-opens a *file* fd (the kernel dups it), standing in - // for Linux's `/proc/self/fd/N` at the file read/write/metadata call sites. - // It is NOT, however, a drop-in for directory work: `/dev/fd/N` is not a - // `readdir`-able directory and child components cannot be appended - // (`/dev/fd/N/child` fails). Directory enumeration uses [`readdir_path`]; - // child mutations use fd-relative `*at` calls. - #[cfg(target_os = "macos")] - fn proc_path(&self) -> PathBuf { - PathBuf::from(format!("/dev/fd/{}", self.fd)) - } - - // Path to enumerate this fd's directory entries. Linux can `readdir` - // `/proc/self/fd/N` directly; macOS `/dev/fd/N` is not a readdir-able - // directory (it yields `ENOTDIR`), so recover the fd's real host path via - // `fcntl(F_GETPATH)` — the same fd→path recovery used elsewhere on macOS. - #[cfg(not(target_os = "macos"))] - fn readdir_path(&self) -> std::io::Result { - Ok(self.proc_path()) - } - #[cfg(target_os = "macos")] - fn readdir_path(&self) -> std::io::Result { - crate::macos_fs::fd_real_path(self.fd) - } -} - -impl AsRawFd for AnchoredFd { - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -impl Drop for AnchoredFd { - fn drop(&mut self) { - let _ = nix::unistd::close(self.fd); - } -} - -#[derive(Debug)] -struct MappedRuntimeOpenedPath { - handle: AnchoredFd, - host_path: PathBuf, -} - -#[derive(Debug)] -struct MappedRuntimeParentPath { - directory: AnchoredFd, - host_path: PathBuf, - child_name: OsString, -} - -#[derive(Debug, Deserialize)] -struct RuntimeGuestPathMappingWire { - #[serde(rename = "guestPath")] - guest_path: String, - #[serde(rename = "hostPath")] - host_path: String, -} - -fn parse_timespec_seconds(value: f64, label: &str) -> Result { - if !value.is_finite() { - return Err(SidecarError::InvalidState(format!( - "{label} must be a finite numeric value" - ))); - } - let seconds = value.floor(); - let mut sec = seconds as i64; - let mut nanos = ((value - seconds) * 1_000_000_000.0).round() as i64; - if nanos >= 1_000_000_000 { - sec = sec.saturating_add(1); - nanos -= 1_000_000_000; - } - VirtualTimeSpec::new(sec, nanos as u32) - .map_err(|error| SidecarError::InvalidState(format!("{label}: {error}"))) -} - -fn parse_timespec_integer(value: &Value, label: &str) -> Result { - value - .as_i64() - .or_else(|| value.as_u64().and_then(|value| i64::try_from(value).ok())) - .ok_or_else(|| SidecarError::InvalidState(format!("{label} must be an integer"))) -} - -fn parse_utime_spec_value(value: &Value, label: &str) -> Result { - if let Some(number) = value.as_f64() { - return parse_timespec_seconds(number, label).map(VirtualUtimeSpec::Set); - } - - let Some(object) = value.as_object() else { - return Err(SidecarError::InvalidState(format!( - "{label} must be a numeric seconds value or {{ sec, nsec }}" - ))); - }; - - if let Some(kind) = object.get("kind").and_then(Value::as_str) { - return match kind { - "now" | "UTIME_NOW" => Ok(VirtualUtimeSpec::Now), - "omit" | "UTIME_OMIT" => Ok(VirtualUtimeSpec::Omit), - other => Err(SidecarError::InvalidState(format!( - "{label} kind must be 'now' or 'omit', got {other}" - ))), - }; - } - - let Some(nsec_value) = object.get("nsec") else { - return Err(SidecarError::InvalidState(format!( - "{label} timespec requires nsec" - ))); - }; - if let Some(text) = nsec_value.as_str() { - return match text { - "UTIME_NOW" => Ok(VirtualUtimeSpec::Now), - "UTIME_OMIT" => Ok(VirtualUtimeSpec::Omit), - _ => Err(SidecarError::InvalidState(format!( - "{label} nsec must be numeric, UTIME_NOW, or UTIME_OMIT" - ))), - }; - } - if let Some(integer) = nsec_value.as_i64().or_else(|| { - nsec_value - .as_u64() - .and_then(|value| i64::try_from(value).ok()) - }) { - if integer == UTIME_NOW_NSEC { - return Ok(VirtualUtimeSpec::Now); - } - if integer == UTIME_OMIT_NSEC { - return Ok(VirtualUtimeSpec::Omit); - } - } - - let sec_value = object - .get("sec") - .ok_or_else(|| SidecarError::InvalidState(format!("{label} timespec requires sec")))?; - let sec = parse_timespec_integer(sec_value, &format!("{label}.sec"))?; - let nsec = u32::try_from(parse_timespec_integer( - nsec_value, - &format!("{label}.nsec"), - )?) - .map_err(|_| SidecarError::InvalidState(format!("{label}.nsec must fit within u32")))?; - VirtualTimeSpec::new(sec, nsec) - .map(VirtualUtimeSpec::Set) - .map_err(|error| SidecarError::InvalidState(format!("{label}: {error}"))) -} - -fn parse_utime_arg( - args: &[Value], - index: usize, - label: &str, -) -> Result { - let value = args - .get(index) - .ok_or_else(|| SidecarError::InvalidState(format!("{label} is required")))?; - parse_utime_spec_value(value, label) -} - -fn metadata_timespec( - metadata: &fs::Metadata, - access_time: bool, -) -> Result { - let (sec, nsec) = if access_time { - (metadata.atime(), metadata.atime_nsec()) - } else { - (metadata.mtime(), metadata.mtime_nsec()) - }; - VirtualTimeSpec::new(sec, nsec.clamp(0, 999_999_999) as u32) - .map_err(|error| SidecarError::InvalidState(format!("invalid host metadata time: {error}"))) -} - -fn resolve_host_utime(spec: VirtualUtimeSpec, existing: VirtualTimeSpec) -> TimeSpec { - match spec { - VirtualUtimeSpec::Set(spec) => TimeSpec::new(spec.sec, spec.nsec as libc::c_long), - VirtualUtimeSpec::Now => TimeSpec::new(0, libc::UTIME_NOW), - VirtualUtimeSpec::Omit => TimeSpec::new(existing.sec, libc::UTIME_OMIT), - } -} - -fn apply_host_path_utimens( - host_path: &Path, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - context: &str, -) -> Result<(), SidecarError> { - let existing = match (atime, mtime) { - (VirtualUtimeSpec::Omit, _) | (_, VirtualUtimeSpec::Omit) => { - let metadata = if follow_symlinks { - fs::metadata(host_path) - } else { - fs::symlink_metadata(host_path) - } - .map_err(|error| { - SidecarError::Io(format!( - "{context}: failed to stat {}: {error}", - host_path.display() - )) - })?; - Some(( - metadata_timespec(&metadata, true)?, - metadata_timespec(&metadata, false)?, - )) - } - _ => None, - }; - let existing_atime = existing - .as_ref() - .map(|(atime, _)| *atime) - .unwrap_or(VirtualTimeSpec { sec: 0, nsec: 0 }); - let existing_mtime = existing - .as_ref() - .map(|(_, mtime)| *mtime) - .unwrap_or(VirtualTimeSpec { sec: 0, nsec: 0 }); - let times = [ - resolve_host_utime(atime, existing_atime), - resolve_host_utime(mtime, existing_mtime), - ]; - let flags = if follow_symlinks { - UtimensatFlags::FollowSymlink - } else { - UtimensatFlags::NoFollowSymlink - }; - utimensat(None, host_path, ×[0], ×[1], flags).map_err(|error| { - SidecarError::Io(format!( - "{context}: failed to update {}: {error}", - host_path.display() - )) - }) -} - -pub(crate) async fn guest_filesystem_call( - sidecar: &mut NativeSidecar, - request: &RequestFrame, - payload: GuestFilesystemCallRequest, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let (connection_id, session_id, vm_id) = sidecar.vm_scope_for(&request.ownership)?; - sidecar.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let response = { - let vm = match sidecar.vms.get_mut(&vm_id) { - Some(vm) => vm, - None => { - return Err(stale_filesystem_request_error( - sidecar, - &vm_id, - None, - "guest filesystem dispatch", - )); - } - }; - sync_guest_filesystem_shadow_before_call(vm, &payload)?; - let response = core_guest_filesystem_call(&mut vm.kernel, payload.clone()) - .map_err(native_guest_filesystem_core_error)?; - mirror_guest_filesystem_shadow_after_call(vm, &payload)?; - response - }; - - Ok(DispatchResult { - response: sidecar.respond(request, ResponsePayload::GuestFilesystemResult(response)), - events: Vec::new(), - }) -} - -fn native_guest_filesystem_core_error( - error: secure_exec_sidecar_core::SidecarCoreError, -) -> SidecarError { - let message = error.to_string(); - if message - .split_once(':') - .is_some_and(|(code, _)| is_posix_errno_code(code)) - { - SidecarError::Kernel(message) - } else { - SidecarError::InvalidState(message) - } -} - -fn is_posix_errno_code(code: &str) -> bool { - code.len() >= 2 - && code.starts_with('E') - && code[1..] - .bytes() - .all(|byte| byte.is_ascii_uppercase() || byte.is_ascii_digit() || byte == b'_') -} - -fn sync_guest_filesystem_shadow_before_call( - vm: &mut VmState, - payload: &GuestFilesystemCallRequest, -) -> Result<(), SidecarError> { - match payload.operation { - GuestFilesystemOperation::ReadFile - | GuestFilesystemOperation::Pread - | GuestFilesystemOperation::Pwrite - | GuestFilesystemOperation::Exists - | GuestFilesystemOperation::Stat - | GuestFilesystemOperation::Lstat - | GuestFilesystemOperation::ReadDirRecursive - | GuestFilesystemOperation::Remove - | GuestFilesystemOperation::Copy - | GuestFilesystemOperation::Move => { - // Pwrite is a partial write that preserves the unmodified bytes, so - // the existing shadow content must be present in the kernel before - // the call, exactly like a read. - sync_active_shadow_path_to_kernel(vm, &payload.path)?; - } - GuestFilesystemOperation::WriteFile - | GuestFilesystemOperation::CreateDir - | GuestFilesystemOperation::Mkdir - | GuestFilesystemOperation::ReadDir - | GuestFilesystemOperation::RemoveFile - | GuestFilesystemOperation::RemoveDir - | GuestFilesystemOperation::Rename - | GuestFilesystemOperation::Realpath - | GuestFilesystemOperation::Symlink - | GuestFilesystemOperation::ReadLink - | GuestFilesystemOperation::Link - | GuestFilesystemOperation::Chmod - | GuestFilesystemOperation::Chown - | GuestFilesystemOperation::Utimes - | GuestFilesystemOperation::Truncate => {} - } - Ok(()) -} - -fn mirror_guest_filesystem_shadow_after_call( - vm: &mut VmState, - payload: &GuestFilesystemCallRequest, -) -> Result<(), SidecarError> { - match payload.operation { - GuestFilesystemOperation::WriteFile => { - let bytes = decode_guest_filesystem_content( - &payload.path, - payload.content.as_deref(), - payload.encoding.clone(), - ) - .map_err(|error| SidecarError::InvalidState(error.to_string()))?; - mirror_guest_file_write_to_shadow(vm, &payload.path, &bytes)?; - } - GuestFilesystemOperation::Pwrite => { - // A positional write only carries the changed region; mirror the - // full post-write file from the kernel so the shadow stays faithful. - let bytes = vm.kernel.read_file(&payload.path).map_err(kernel_error)?; - mirror_guest_file_write_to_shadow(vm, &payload.path, &bytes)?; - } - GuestFilesystemOperation::CreateDir | GuestFilesystemOperation::Mkdir => { - mirror_guest_directory_write_to_shadow(vm, &payload.path)?; - } - GuestFilesystemOperation::RemoveFile | GuestFilesystemOperation::RemoveDir => { - remove_guest_shadow_path(vm, &payload.path)?; - } - GuestFilesystemOperation::Remove => { - remove_guest_shadow_path(vm, &payload.path)?; - } - GuestFilesystemOperation::Copy => { - let destination = payload.destination_path.as_deref().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "guest filesystem copy requires a destination_path", - )) - })?; - remove_guest_shadow_path(vm, destination)?; - mirror_guest_subtree_to_shadow(vm, destination)?; - } - GuestFilesystemOperation::Move => { - let destination = payload.destination_path.as_deref().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "guest filesystem move requires a destination_path", - )) - })?; - remove_guest_shadow_path(vm, &payload.path)?; - remove_guest_shadow_path(vm, destination)?; - mirror_guest_subtree_to_shadow(vm, destination)?; - } - GuestFilesystemOperation::Rename => { - let destination = payload.destination_path.as_deref().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "guest filesystem rename requires a destination_path", - )) - })?; - rename_guest_shadow_path(vm, &payload.path, destination)?; - } - GuestFilesystemOperation::Symlink => { - let target = payload.target.as_deref().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "guest filesystem symlink requires a target", - )) - })?; - mirror_guest_symlink_to_shadow(vm, &payload.path, target)?; - } - GuestFilesystemOperation::Link => { - let destination = payload.destination_path.as_deref().ok_or_else(|| { - SidecarError::InvalidState(String::from( - "guest filesystem link requires a destination_path", - )) - })?; - mirror_guest_link_to_shadow(vm, &payload.path, destination)?; - } - GuestFilesystemOperation::Chmod => { - let mode = payload.mode.ok_or_else(|| { - SidecarError::InvalidState(String::from("guest filesystem chmod requires a mode")) - })?; - mirror_guest_chmod_to_shadow(vm, &payload.path, mode)?; - } - GuestFilesystemOperation::Utimes => { - let atime_ms = payload.atime_ms.ok_or_else(|| { - SidecarError::InvalidState(String::from( - "guest filesystem utimes requires atime_ms", - )) - })?; - let mtime_ms = payload.mtime_ms.ok_or_else(|| { - SidecarError::InvalidState(String::from( - "guest filesystem utimes requires mtime_ms", - )) - })?; - mirror_guest_utimes_to_shadow( - vm, - &payload.path, - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(atime_ms)), - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(mtime_ms)), - true, - )?; - } - GuestFilesystemOperation::Truncate => { - let len = payload.len.ok_or_else(|| { - SidecarError::InvalidState(String::from("guest filesystem truncate requires len")) - })?; - mirror_guest_truncate_to_shadow(vm, &payload.path, len)?; - } - GuestFilesystemOperation::ReadFile - | GuestFilesystemOperation::Pread - | GuestFilesystemOperation::Exists - | GuestFilesystemOperation::Stat - | GuestFilesystemOperation::Lstat - | GuestFilesystemOperation::ReadDir - | GuestFilesystemOperation::ReadDirRecursive - | GuestFilesystemOperation::Realpath - | GuestFilesystemOperation::ReadLink - | GuestFilesystemOperation::Chown => {} - } - Ok(()) -} - -pub(crate) fn handle_python_vfs_rpc_request( - sidecar: &mut NativeSidecar, - vm_id: &str, - process_id: &str, - request: PythonVfsRpcRequest, -) -> Result<(), SidecarError> -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let Some(vm) = sidecar.vms.get(vm_id) else { - log_stale_process_event(&sidecar.bridge, vm_id, process_id, "python VFS RPC"); - return Ok(()); - }; - if !vm.active_processes.contains_key(process_id) { - log_stale_process_event(&sidecar.bridge, vm_id, process_id, "python VFS RPC"); - return Ok(()); - } - - let response = match normalize_python_vfs_rpc_path(&request.path) { - Ok(path) => { - let Some(vm) = sidecar.vms.get_mut(vm_id) else { - log_stale_process_event(&sidecar.bridge, vm_id, process_id, "python VFS RPC"); - return Ok(()); - }; - match request.method { - PythonVfsRpcMethod::Read => vm - .kernel - .read_file(&path) - .map(|content| PythonVfsRpcResponsePayload::Read { - content_base64: base64::engine::general_purpose::STANDARD.encode(content), - }) - .map_err(kernel_error), - PythonVfsRpcMethod::Write => { - let content_base64 = request.content_base64.as_deref().ok_or_else(|| { - SidecarError::InvalidState(format!( - "python VFS fsWrite for {} requires contentBase64", - path - )) - })?; - let bytes = base64::engine::general_purpose::STANDARD - .decode(content_base64) - .map_err(|error| { - SidecarError::InvalidState(format!( - "invalid base64 python VFS content for {}: {error}", - path - )) - })?; - vm.kernel - .write_file(&path, bytes) - .map(|()| PythonVfsRpcResponsePayload::Empty) - .map_err(kernel_error) - } - PythonVfsRpcMethod::Stat => vm - .kernel - .stat(&path) - .map(|stat| PythonVfsRpcResponsePayload::Stat { - stat: PythonVfsRpcStat { - mode: stat.mode, - size: stat.size, - is_directory: stat.is_directory, - is_symbolic_link: stat.is_symbolic_link, - }, - }) - .map_err(kernel_error), - // Like Stat but does NOT follow symlinks, so the runner can - // represent a host-preexisting symlink as a link node. - PythonVfsRpcMethod::Lstat => vm - .kernel - .lstat(&path) - .map(|stat| PythonVfsRpcResponsePayload::Stat { - stat: PythonVfsRpcStat { - mode: stat.mode, - size: stat.size, - is_directory: stat.is_directory, - is_symbolic_link: stat.is_symbolic_link, - }, - }) - .map_err(kernel_error), - PythonVfsRpcMethod::ReadDir => vm - .kernel - .read_dir(&path) - .map(|entries| PythonVfsRpcResponsePayload::ReadDir { entries }) - .map_err(kernel_error), - PythonVfsRpcMethod::Mkdir => vm - .kernel - .mkdir(&path, request.recursive) - .map(|()| PythonVfsRpcResponsePayload::Empty) - .map_err(kernel_error), - // Mirror the delete/rename into the host-side shadow too, the - // same way the wire `GuestFilesystemOperation` handlers do — - // otherwise a later shadow→kernel sync would resurrect the - // entry the guest just removed. - PythonVfsRpcMethod::Unlink => { - match vm.kernel.remove_file(&path).map_err(kernel_error) { - Ok(()) => remove_guest_shadow_path(vm, &path) - .map(|()| PythonVfsRpcResponsePayload::Empty), - Err(error) => Err(error), - } - } - PythonVfsRpcMethod::Rmdir => { - match vm.kernel.remove_dir(&path).map_err(kernel_error) { - Ok(()) => remove_guest_shadow_path(vm, &path) - .map(|()| PythonVfsRpcResponsePayload::Empty), - Err(error) => Err(error), - } - } - PythonVfsRpcMethod::Rename => { - let destination = request.destination.as_deref().ok_or_else(|| { - SidecarError::InvalidState(format!( - "python VFS fsRename for {} requires destination", - path - )) - })?; - let destination = normalize_python_vfs_rpc_path(destination)?; - match vm.kernel.rename(&path, &destination).map_err(kernel_error) { - Ok(()) => rename_guest_shadow_path(vm, &path, &destination) - .map(|()| PythonVfsRpcResponsePayload::Empty), - Err(error) => Err(error), - } - } - // Kernel-direct (no shadow mirror): guest Python writes/creates - // land only in the kernel VFS, so mirroring create/modify ops into - // the host-side shadow would leave empty stubs that a later - // shadow->kernel sync resurrects over real content. (Delete/rename - // still mirror — to *remove* stale wire-written shadow entries.) - PythonVfsRpcMethod::Symlink => { - let target = request.target.clone().ok_or_else(|| { - SidecarError::InvalidState(format!( - "python VFS fsSymlink for {} requires a target", - path - )) - })?; - vm.kernel - .symlink(&target, &path) - .map(|()| PythonVfsRpcResponsePayload::Empty) - .map_err(kernel_error) - } - PythonVfsRpcMethod::ReadLink => vm - .kernel - .read_link(&path) - .map(|target| PythonVfsRpcResponsePayload::SymlinkTarget { target }) - .map_err(kernel_error), - // `setattr` carries any of mode/uid/gid/atime+mtime; apply each - // present field to the host VFS. - PythonVfsRpcMethod::Setattr => { - (|| -> Result { - // Mirror metadata into the host shadow only when the entry - // already exists there (a host-mounted / wire-written file), - // so the next shadow->kernel reconcile keeps the guest's - // change. Never *create* a shadow stub for a kernel-only - // guest file (that resurrected empty content). - let mirror = shadow_host_path_for_guest(&vm.cwd, &path).exists(); - if let Some(mode) = request.mode { - vm.kernel.chmod(&path, mode).map_err(kernel_error)?; - if mirror { - mirror_guest_chmod_to_shadow(vm, &path, mode)?; - } - } - // uid/gid apply independently (`os.chown(p, uid, -1)` keeps - // the other side); fill the missing side from the current - // owner rather than dropping the whole chown. - if request.uid.is_some() || request.gid.is_some() { - let current = vm.kernel.stat(&path).map_err(kernel_error)?; - let uid = request.uid.unwrap_or(current.uid); - let gid = request.gid.unwrap_or(current.gid); - vm.kernel.chown(&path, uid, gid).map_err(kernel_error)?; - } - if let (Some(atime_ms), Some(mtime_ms)) = - (request.atime_ms, request.mtime_ms) - { - vm.kernel - .utimes(&path, atime_ms, mtime_ms) - .map_err(kernel_error)?; - if mirror { - mirror_guest_utimes_to_shadow( - vm, - &path, - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(atime_ms)), - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(mtime_ms)), - true, - )?; - } - } - Ok(PythonVfsRpcResponsePayload::Empty) - })() - } - PythonVfsRpcMethod::HttpRequest - | PythonVfsRpcMethod::DnsLookup - | PythonVfsRpcMethod::SubprocessRun - | PythonVfsRpcMethod::SocketConnect - | PythonVfsRpcMethod::SocketSend - | PythonVfsRpcMethod::SocketRecv - | PythonVfsRpcMethod::SocketClose - | PythonVfsRpcMethod::UdpCreate - | PythonVfsRpcMethod::UdpSendto - | PythonVfsRpcMethod::UdpRecvfrom => Err(SidecarError::InvalidState(String::from( - "python non-filesystem RPC reached filesystem dispatcher unexpectedly", - ))), - } - } - Err(error) => Err(error), - }; - - let Some(vm) = sidecar.vms.get_mut(vm_id) else { - log_stale_process_event(&sidecar.bridge, vm_id, process_id, "python VFS RPC"); - return Ok(()); - }; - let Some(process) = vm.active_processes.get_mut(process_id) else { - log_stale_process_event(&sidecar.bridge, vm_id, process_id, "python VFS RPC"); - return Ok(()); - }; - - match response { - Ok(payload) => process - .execution - .respond_python_vfs_rpc_success(request.id, payload), - Err(error) => process.execution.respond_python_vfs_rpc_error( - request.id, - "ERR_AGENTOS_PYTHON_VFS_RPC", - error.to_string(), - ), - } -} - -fn stale_filesystem_request_error( - sidecar: &NativeSidecar, - vm_id: &str, - process_id: Option<&str>, - context: &str, -) -> SidecarError -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let message = match process_id { - Some(process_id) => format!( - "Ignoring stale filesystem request during {context}: VM {vm_id} process {process_id} was already reaped" - ), - None => format!( - "Ignoring stale filesystem request during {context}: VM {vm_id} was already reaped" - ), - }; - let _ = sidecar.bridge.emit_log(vm_id, message.clone()); - SidecarError::InvalidState(message) -} - -pub(crate) fn normalize_python_vfs_rpc_path(path: &str) -> Result { - if !path.starts_with('/') { - return Err(SidecarError::InvalidState(format!( - "python VFS RPC path {path} must be absolute within {PYTHON_VFS_RPC_GUEST_ROOT}" - ))); - } - - // Root is `/`: Python may address the whole guest VFS. Textual `..` segments - // are resolved by `normalize_path`, and the kernel enforces fs permissions - // plus mount-confinement (openat2 RESOLVE_BENEATH refuses escaping symlinks) - // on every op — so confinement is the kernel's job, not a prefix check here. - let normalized = normalize_path(path); - debug_assert_eq!(PYTHON_VFS_RPC_GUEST_ROOT, "/"); - Ok(normalized) -} - -/// Kernel-VFS-backed reader for resolver unit tests and kernel-only callers. -#[cfg(test)] -struct KernelModuleFsReader<'a> { - kernel: &'a mut SidecarKernel, -} - -#[cfg(test)] -impl ModuleFsReader for KernelModuleFsReader<'_> { - fn canonical_guest_path(&mut self, guest_path: &str) -> Option { - self.kernel.realpath(guest_path).ok() - } - - fn read_to_string(&mut self, guest_path: &str) -> Option { - let bytes = self.kernel.read_file(guest_path).ok()?; - String::from_utf8(bytes).ok() - } - - fn path_is_dir(&mut self, guest_path: &str) -> Option { - self.kernel - .stat(guest_path) - .ok() - .map(|stat| stat.is_directory) - } - - fn path_exists(&mut self, guest_path: &str) -> bool { - self.kernel.exists(guest_path).unwrap_or(false) - } -} - -/// Module reader for live JavaScript processes. In the NodeRuntime embedding, -/// guest filesystem calls operate on the process' mapped host shadow first and -/// reconcile back to the kernel on exit. Module resolution must therefore check -/// that same process shadow before falling back to the sidecar kernel, otherwise -/// `fs.writeFileSync(...); await import(...)` observes an older filesystem. -struct ProcessModuleFsReader<'a> { - kernel: &'a mut SidecarKernel, - process: &'a ActiveProcess, -} - -impl ProcessModuleFsReader<'_> { - fn normalize_guest_path(&self, guest_path: &str) -> String { - normalize_process_filesystem_rpc_path(self.process, guest_path) - } - - fn mapped_host_path(&self, guest_path: &str) -> Option { - mapped_runtime_host_path_for_read(self.process, guest_path) - } - - fn materialize_mapped_path( - &mut self, - guest_path: &str, - mapped: &MappedRuntimeHostPath, - ) -> Result<(), SidecarError> { - materialize_mapped_host_path_from_kernel( - self.kernel, - self.process.kernel_pid, - guest_path, - mapped, - ) - } - - fn open_mapped_path( - &mut self, - guest_path: &str, - operation: &'static str, - flags: OFlag, - ) -> Option { - let mapped = self.mapped_host_path(guest_path)?; - self.materialize_mapped_path(guest_path, &mapped).ok()?; - open_mapped_runtime_beneath(&mapped, operation, flags, Mode::empty()).ok() - } -} - -impl ModuleFsReader for ProcessModuleFsReader<'_> { - fn canonical_guest_path(&mut self, guest_path: &str) -> Option { - let normalized = self.normalize_guest_path(guest_path); - if self - .open_mapped_path(&normalized, "module.realpath", O_PATH_ANCHOR) - .is_some() - { - return Some(normalized); - } - self.kernel.realpath(&normalized).ok() - } - - fn read_to_string(&mut self, guest_path: &str) -> Option { - let normalized = self.normalize_guest_path(guest_path); - if let Some(opened) = self.open_mapped_path(&normalized, "module.readFile", OFlag::O_RDONLY) - { - if let Ok(source) = fs::read_to_string(opened.handle.proc_path()) { - return Some(source); - } - } - - let bytes = self.kernel.read_file(&normalized).ok()?; - String::from_utf8(bytes).ok() - } - - fn path_is_dir(&mut self, guest_path: &str) -> Option { - let normalized = self.normalize_guest_path(guest_path); - if let Some(opened) = self.open_mapped_path(&normalized, "module.stat", O_PATH_ANCHOR) { - if let Ok(metadata) = fs::metadata(opened.handle.proc_path()) { - return Some(metadata.is_dir()); - } - } - - self.kernel - .stat(&normalized) - .ok() - .map(|stat| stat.is_directory) - } - - fn path_exists(&mut self, guest_path: &str) -> bool { - let normalized = self.normalize_guest_path(guest_path); - if self - .open_mapped_path(&normalized, "module.exists", O_PATH_ANCHOR) - .is_some() - { - return true; - } - self.kernel.exists(&normalized).unwrap_or(false) - } -} - -/// Resolve / load / format / batch-resolve module requests against the kernel -/// VFS. Routed here from `service_javascript_sync_rpc` for the -/// `__resolve_module` / `__load_file` / `__module_format` / -/// `__batch_resolve_modules` methods (mapped from the guest bridge's -/// `_resolveModule` / `_loadFile` / `_moduleFormat` / `_batchResolveModules`). -pub(crate) fn service_javascript_module_sync_rpc( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, -) -> Result { - let mut cache = std::mem::take(&mut process.module_resolution_cache); - let value = { - let reader = ProcessModuleFsReader { - kernel, - process: &*process, - }; - let mut resolver = ModuleResolver::new(reader, &mut cache); - - match request.method.as_str() { - "__resolve_module" | "_resolveModule" | "_resolveModuleSync" => { - let specifier = - javascript_sync_rpc_arg_str(&request.args, 0, "module resolve specifier")?; - let parent = request.args.get(1).and_then(Value::as_str).unwrap_or("/"); - let mode = match request.args.get(2).and_then(Value::as_str) { - Some("import") => ModuleResolveMode::Import, - Some("require") => ModuleResolveMode::Require, - // `_resolveModule` defaults to import; `_resolveModuleSync` to require. - _ if request.method == "_resolveModuleSync" => ModuleResolveMode::Require, - _ => ModuleResolveMode::Import, - }; - resolver - .resolve_module(specifier, parent, mode) - .map(Value::String) - .unwrap_or(Value::Null) - } - "__load_file" | "_loadFile" | "_loadFileSync" => { - let path = javascript_sync_rpc_arg_str(&request.args, 0, "module load path")?; - resolver - .load_file(path) - .map(Value::String) - .unwrap_or(Value::Null) - } - "__module_format" | "_moduleFormat" => { - let path = javascript_sync_rpc_arg_str(&request.args, 0, "module format path")?; - resolver - .module_format(path) - .map(|format: LocalResolvedModuleFormat| { - Value::String(String::from(format.as_str())) - }) - .unwrap_or(Value::Null) - } - "__batch_resolve_modules" | "_batchResolveModules" => { - resolver.batch_resolve_modules(&request.args) - } - other => { - process.module_resolution_cache = cache; - return Err(SidecarError::InvalidState(format!( - "unsupported JavaScript module sync RPC method {other}" - ))); - } - } - }; - process.module_resolution_cache = cache; - - Ok(value) -} - -#[derive(Clone, Copy, Default)] -struct FsSyncPhaseStats { - calls: u64, - total_ns: u128, - max_ns: u128, -} - -static FS_SYNC_PHASES: OnceLock>> = OnceLock::new(); - -struct FsSyncPhaseTimer<'a> { - method: &'a str, - start: Option, -} - -impl<'a> FsSyncPhaseTimer<'a> { - fn start(method: &'a str) -> Self { - let start = fs_sync_phases_enabled().then(Instant::now); - Self { method, start } - } -} - -impl Drop for FsSyncPhaseTimer<'_> { - fn drop(&mut self) { - let Some(start) = self.start else { return }; - record_fs_sync_phase(self.method, start.elapsed().as_nanos()); - } -} - -fn record_fs_sync_subphase(method: &str, stage: &str, start: Instant) { - if !fs_sync_phases_enabled() { - return; - } - record_fs_sync_phase(&format!("{method}:{stage}"), start.elapsed().as_nanos()); -} - -fn fs_sync_phases_enabled() -> bool { - matches!(env::var("AGENTOS_FS_SYNC_PHASES").as_deref(), Ok("1")) -} - -fn record_fs_sync_phase(method: &str, elapsed_ns: u128) { - let phases = FS_SYNC_PHASES.get_or_init(|| Mutex::new(BTreeMap::new())); - let Ok(mut phases) = phases.lock() else { - return; - }; - let stats = phases.entry(method.to_string()).or_default(); - stats.calls += 1; - stats.total_ns += elapsed_ns; - stats.max_ns = stats.max_ns.max(elapsed_ns); - - let Some(path) = env::var_os("AGENTOS_FS_SYNC_PHASES_FILE") else { - return; - }; - let mut output = String::new(); - for (method, stats) in phases.iter() { - let total_us = stats.total_ns / 1_000; - let avg_us = if stats.calls == 0 { - 0 - } else { - total_us / u128::from(stats.calls) - }; - let max_us = stats.max_ns / 1_000; - output.push_str(&format!( - "method={method} calls={} total_us={total_us} avg_us={avg_us} max_us={max_us}\n", - stats.calls - )); - } - let _ = fs::write(path, output); -} - -fn fs_sync_request_marks_host_write_dirty( - request: &JavascriptSyncRpcRequest, -) -> Result { - Ok(match request.method.as_str() { - "fs.open" | "fs.openSync" => { - let flags = javascript_sync_rpc_arg_u32(&request.args, 1, "filesystem open flags")?; - mapped_host_open_is_writable(flags) - } - "fs.write" - | "fs.writeSync" - | "fs.writevSync" - | "fs.writeFileSync" - | "fs.promises.writeFile" - | "fs.mkdirSync" - | "fs.promises.mkdir" - | "fs.copyFileSync" - | "fs.promises.copyFile" - | "fs.symlinkSync" - | "fs.promises.symlink" - | "fs.linkSync" - | "fs.promises.link" - | "fs.renameSync" - | "fs.promises.rename" - | "fs.rmdirSync" - | "fs.promises.rmdir" - | "fs.unlinkSync" - | "fs.promises.unlink" - | "fs.chmodSync" - | "fs.promises.chmod" - | "fs.chownSync" - | "fs.promises.chown" - | "fs.utimesSync" - | "fs.promises.utimes" - | "fs.lutimesSync" - | "fs.promises.lutimes" - | "fs.futimesSync" => true, - _ => false, - }) -} - -pub(crate) fn service_javascript_fs_read_sync_rpc( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - kernel_pid: u32, - request: &JavascriptSyncRpcRequest, -) -> Result, SidecarError> { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem read fd")?; - let length = usize::try_from(javascript_sync_rpc_arg_u64( - &request.args, - 1, - "filesystem read length", - )?) - .map_err(|_| { - SidecarError::InvalidState("filesystem read length must fit within usize".to_string()) - })?; - let position = - javascript_sync_rpc_arg_u64_optional(&request.args, 2, "filesystem read position")?; - if let Some(mapped) = process.mapped_host_fd_mut(fd) { - let value = read_mapped_host_fd(mapped, fd, length, position)?; - return javascript_sync_rpc_bytes_arg( - std::slice::from_ref(&value), - 0, - "filesystem mapped read response", - ); - } - match position { - Some(offset) => kernel.fd_pread(EXECUTION_DRIVER_NAME, kernel_pid, fd, length, offset), - None => kernel.fd_read(EXECUTION_DRIVER_NAME, kernel_pid, fd, length), - } - .map_err(kernel_error) -} - -pub(crate) fn service_javascript_fs_sync_rpc( - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - kernel_pid: u32, - request: &JavascriptSyncRpcRequest, -) -> Result { - let _phase_timer = FsSyncPhaseTimer::start(request.method.as_str()); - if fs_sync_request_marks_host_write_dirty(request)? { - process.mark_host_write_dirty(); - } - match request.method.as_str() { - "fs.open" | "fs.openSync" => { - let phase_start = Instant::now(); - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem open path")?; - let path = path.as_str(); - let flags = javascript_sync_rpc_arg_u32(&request.args, 1, "filesystem open flags")?; - let mode = - javascript_sync_rpc_arg_u32_optional(&request.args, 2, "filesystem open mode")?; - record_fs_sync_subphase(request.method.as_str(), "parse", phase_start); - let phase_start = Instant::now(); - match mapped_runtime_host_path(process, path, mapped_host_open_is_writable(flags)) { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { - record_fs_sync_subphase( - request.method.as_str(), - "mapped_host_match", - phase_start, - ); - let phase_start = Instant::now(); - materialize_mapped_host_path_from_kernel( - kernel, - kernel_pid, - path, - &mapped_host, - )?; - record_fs_sync_subphase( - request.method.as_str(), - "materialize_mapped_host", - phase_start, - ); - let phase_start = Instant::now(); - let opened = open_mapped_runtime_beneath( - &mapped_host, - "fs.open", - OFlag::from_bits_truncate(flags as i32), - Mode::from_bits_truncate(mode.unwrap_or(0o666) as _), - )?; - record_fs_sync_subphase( - request.method.as_str(), - "open_mapped_beneath", - phase_start, - ); - let host_path = opened.host_path.clone(); - let phase_start = Instant::now(); - return open_mapped_host_fd( - process, - host_path, - Some(path.to_string()), - opened.handle.proc_path(), - flags, - ) - .inspect(|_| { - record_fs_sync_subphase( - request.method.as_str(), - "open_mapped_fd", - phase_start, - ); - }); - } - Some(MappedRuntimeHostAccess::ReadOnly(_)) => { - return Err(read_only_mapped_runtime_host_path_error(path)); - } - None => {} - } - record_fs_sync_subphase(request.method.as_str(), "mapped_host_none", phase_start); - let phase_start = Instant::now(); - kernel - .fd_open(EXECUTION_DRIVER_NAME, kernel_pid, path, flags, mode) - .map(|fd| json!(fd)) - .map_err(|error| kernel_path_error("fs.open", path, error)) - .inspect(|_| { - record_fs_sync_subphase(request.method.as_str(), "kernel_fd_open", phase_start); - }) - } - "fs.read" | "fs.readSync" => { - service_javascript_fs_read_sync_rpc(kernel, process, kernel_pid, request) - .map(|bytes| javascript_sync_rpc_bytes_value(&bytes)) - } - "fs.write" | "fs.writeSync" => { - let phase_start = Instant::now(); - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem write fd")?; - let contents = if let Some(bytes) = request.raw_bytes_args.get(&1) { - bytes.clone() - } else { - javascript_sync_rpc_bytes_arg(&request.args, 1, "filesystem write contents")? - }; - let position = javascript_sync_rpc_arg_u64_optional( - &request.args, - 2, - "filesystem write position", - )?; - record_fs_sync_subphase(request.method.as_str(), "parse", phase_start); - let phase_start = Instant::now(); - if let Some(mapped) = process.mapped_host_fd_mut(fd) { - record_fs_sync_subphase(request.method.as_str(), "mapped_fd_match", phase_start); - return write_mapped_host_fd(mapped, fd, &contents, position); - } - record_fs_sync_subphase(request.method.as_str(), "mapped_fd_none", phase_start); - let phase_start = Instant::now(); - let written = match position { - Some(offset) => kernel - .fd_pwrite(EXECUTION_DRIVER_NAME, kernel_pid, fd, &contents, offset) - .map_err(kernel_error)?, - None => kernel - .fd_write(EXECUTION_DRIVER_NAME, kernel_pid, fd, &contents) - .map_err(kernel_error)?, - }; - record_fs_sync_subphase(request.method.as_str(), "kernel_fd_write", phase_start); - let phase_start = Instant::now(); - let surfaces_stdio = - position.is_none() && kernel_fd_surfaces_stdio_event(kernel, kernel_pid, fd)?; - record_fs_sync_subphase(request.method.as_str(), "stdio_check", phase_start); - if surfaces_stdio { - let phase_start = Instant::now(); - let event = if fd == 1 { - ActiveExecutionEvent::Stdout(contents) - } else { - ActiveExecutionEvent::Stderr(contents) - }; - process.queue_pending_execution_event(event)?; - record_fs_sync_subphase(request.method.as_str(), "queue_stdio_event", phase_start); - } else { - let phase_start = Instant::now(); - mirror_kernel_fd_contents_to_process_shadow(kernel, process, kernel_pid, fd)?; - record_fs_sync_subphase(request.method.as_str(), "mirror_shadow", phase_start); - } - Ok(json!(written)) - } - "fs.writevSync" => { - let phase_start = Instant::now(); - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem writev fd")?; - let contents = request.raw_bytes_args.get(&1).ok_or_else(|| { - SidecarError::InvalidState(String::from( - "filesystem writev requires raw byte payload", - )) - })?; - let position = javascript_sync_rpc_arg_u64_optional( - &request.args, - 2, - "filesystem writev position", - )?; - let buffers = decode_javascript_writev_raw_payload(contents)?; - record_fs_sync_subphase(request.method.as_str(), "parse", phase_start); - - let mut total_written = 0usize; - if let Some(mapped) = process.mapped_host_fd_mut(fd) { - record_fs_sync_subphase(request.method.as_str(), "mapped_fd_match", phase_start); - let mut next_position = position; - for buffer in buffers { - let written = write_all_mapped_host_fd(mapped, fd, buffer, next_position)?; - total_written = total_written.saturating_add(written); - if let Some(position) = &mut next_position { - *position = position.saturating_add(written as u64); - } - } - return Ok(json!(total_written)); - } - record_fs_sync_subphase(request.method.as_str(), "mapped_fd_none", phase_start); - - let surfaces_stdio = - position.is_none() && kernel_fd_surfaces_stdio_event(kernel, kernel_pid, fd)?; - let mut next_position = position; - let mut combined_stdio = Vec::new(); - for buffer in buffers { - let mut offset = 0usize; - while offset < buffer.len() { - let slice = &buffer[offset..]; - let written = match next_position { - Some(position) => kernel - .fd_pwrite(EXECUTION_DRIVER_NAME, kernel_pid, fd, slice, position) - .map_err(kernel_error)?, - None => kernel - .fd_write(EXECUTION_DRIVER_NAME, kernel_pid, fd, slice) - .map_err(kernel_error)?, - }; - if written == 0 { - return Err(SidecarError::Execution(format!( - "EIO: filesystem writev made no progress on fd {fd}" - ))); - } - offset += written; - total_written = total_written.saturating_add(written); - if let Some(position) = &mut next_position { - *position = position.saturating_add(written as u64); - } - } - if surfaces_stdio { - combined_stdio.extend_from_slice(buffer); - } - } - record_fs_sync_subphase(request.method.as_str(), "kernel_fd_write", phase_start); - if surfaces_stdio && !combined_stdio.is_empty() { - let event = if fd == 1 { - ActiveExecutionEvent::Stdout(combined_stdio) - } else { - ActiveExecutionEvent::Stderr(combined_stdio) - }; - process.queue_pending_execution_event(event)?; - } else { - mirror_kernel_fd_contents_to_process_shadow(kernel, process, kernel_pid, fd)?; - } - Ok(json!(total_written)) - } - "fs.close" | "fs.closeSync" => { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem close fd")?; - if process.close_mapped_host_fd(fd) { - return Ok(Value::Null); - } - kernel - .fd_close(EXECUTION_DRIVER_NAME, kernel_pid, fd) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.fstat" | "fs.fstatSync" => { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem fstat fd")?; - if let Some(mapped) = process.mapped_host_fd(fd) { - let metadata = mapped.file.metadata().map_err(|error| { - SidecarError::Io(format!( - "failed to stat mapped guest fd {fd} -> {}: {error}", - mapped.path.display() - )) - })?; - return Ok(javascript_sync_rpc_host_stat_value(&metadata)); - } - kernel - .fd_stat(EXECUTION_DRIVER_NAME, kernel_pid, fd) - .map_err(kernel_error)?; - kernel - .dev_fd_stat(EXECUTION_DRIVER_NAME, kernel_pid, fd) - .map(javascript_sync_rpc_stat_value) - .map_err(kernel_error) - } - "fs.fsyncSync" | "fs.fdatasyncSync" => { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem sync fd")?; - if let Some(mapped) = process.mapped_host_fd(fd) { - return mapped - .file - .sync_all() - .map(|()| Value::Null) - .map_err(|error| { - SidecarError::Io(format!( - "failed to sync mapped guest fd {fd} -> {}: {error}", - mapped.path.display() - )) - }); - } - kernel - .fd_stat(EXECUTION_DRIVER_NAME, kernel_pid, fd) - .map(|_| Value::Null) - .map_err(kernel_error) - } - "fs.ftruncateSync" => { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem ftruncate fd")?; - let length = javascript_sync_rpc_arg_u64_optional( - &request.args, - 1, - "filesystem ftruncate length", - )? - .unwrap_or(0); - if let Some(mapped_guest_path) = process - .mapped_host_fd_mut(fd) - .map(|mapped| mapped.guest_path.clone()) - { - // `length` is guest-controlled. Bound it before resizing the host - // file so a hostile value cannot create an enormous sparse host - // file. For a VFS-visible guest path the kernel truncate below is - // the primary (configured) size enforcement and mirrors the new - // length without reading the whole host file into sidecar memory. - if length > MAX_MAPPED_TRUNCATE_BYTES { - return Err(SidecarError::Io(format!( - "ftruncate length {length} exceeds maximum \ - {MAX_MAPPED_TRUNCATE_BYTES} for mapped guest fd {fd}" - ))); - } - if let Some(guest_path) = mapped_guest_path.as_deref() { - kernel - .truncate(guest_path, length) - .map_err(|error| kernel_path_error("fs.ftruncate", guest_path, error))?; - } - let mapped = process.mapped_host_fd_mut(fd).ok_or_else(|| { - SidecarError::Io(format!( - "mapped guest fd {fd} disappeared during ftruncate" - )) - })?; - mapped.file.set_len(length).map_err(|error| { - SidecarError::Io(format!("failed to truncate mapped guest fd {fd}: {error}")) - })?; - if let Some(guest_path) = mapped_guest_path.as_deref() { - mirror_kernel_path_to_process_shadow(kernel, process, kernel_pid, guest_path)?; - } - return Ok(Value::Null); - } - let fd_stat = kernel - .fd_stat(EXECUTION_DRIVER_NAME, kernel_pid, fd) - .map_err(kernel_error)?; - if (fd_stat.flags & libc::O_ACCMODE as u32) == libc::O_RDONLY as u32 { - return Err(SidecarError::Execution(format!( - "EBADF: file descriptor {fd} is not open for writing" - ))); - } - let path = kernel - .fd_path(EXECUTION_DRIVER_NAME, kernel_pid, fd) - .map_err(kernel_error)?; - kernel.truncate(&path, length).map_err(kernel_error)?; - mirror_kernel_path_to_process_shadow(kernel, process, kernel_pid, &path)?; - Ok(Value::Null) - } - "fs.readFileSync" | "fs.promises.readFile" => { - let path = javascript_sync_rpc_path_arg( - process, - &request.args, - 0, - "filesystem readFile path", - )?; - let path = path.as_str(); - let encoding = javascript_sync_rpc_encoding(&request.args); - if let Some(mapped_host) = mapped_runtime_host_path_for_read(process, path) { - materialize_mapped_host_path_from_kernel(kernel, kernel_pid, path, &mapped_host)?; - let opened = open_mapped_runtime_beneath( - &mapped_host, - "fs.readFile", - OFlag::O_RDONLY, - Mode::empty(), - )?; - let content = fs::read(opened.handle.proc_path()).map_err(|error| { - SidecarError::Io(format!( - "failed to read mapped guest file {} -> {}: {error}", - path, - opened.host_path.display() - )) - })?; - return Ok(match encoding.as_deref() { - Some("utf8") | Some("utf-8") => { - Value::String(String::from_utf8_lossy(&content).into_owned()) - } - _ => javascript_sync_rpc_bytes_value(&content), - }); - } - kernel - .read_file_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) - .map(|content| match encoding.as_deref() { - Some("utf8") | Some("utf-8") => { - Value::String(String::from_utf8_lossy(&content).into_owned()) - } - _ => javascript_sync_rpc_bytes_value(&content), - }) - .map_err(kernel_error) - } - "fs.writeFileSync" | "fs.promises.writeFile" => { - let path = javascript_sync_rpc_path_arg( - process, - &request.args, - 0, - "filesystem writeFile path", - )?; - let path = path.as_str(); - let contents = if let Some(bytes) = request.raw_bytes_args.get(&1) { - bytes.clone() - } else { - javascript_sync_rpc_bytes_arg(&request.args, 1, "filesystem writeFile contents")? - }; - match mapped_runtime_host_path(process, path, true) { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { - let opened = open_mapped_runtime_beneath( - &mapped_host, - "fs.writeFile", - OFlag::O_WRONLY | OFlag::O_CREAT | OFlag::O_TRUNC, - Mode::from_bits_truncate( - javascript_sync_rpc_option_u32(&request.args, 2, "mode")? - .unwrap_or(0o666) as _, - ), - )?; - fs::write(opened.handle.proc_path(), contents).map_err(|error| { - SidecarError::Io(format!( - "failed to write mapped guest file {} -> {}: {error}", - path, - opened.host_path.display() - )) - })?; - return Ok(Value::Null); - } - Some(MappedRuntimeHostAccess::ReadOnly(_)) => { - return Err(read_only_mapped_runtime_host_path_error(path)); - } - None => {} - } - kernel - .write_file_for_process( - EXECUTION_DRIVER_NAME, - kernel_pid, - path, - contents, - javascript_sync_rpc_option_u32(&request.args, 2, "mode")?, - ) - .map_err(|error| kernel_path_error("fs.writeFile", path, error))?; - mirror_kernel_path_to_process_shadow(kernel, process, kernel_pid, path)?; - Ok(Value::Null) - } - "fs.statSync" | "fs.promises.stat" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem stat path")?; - let path = path.as_str(); - if let Some(mapped_host) = mapped_runtime_host_path_for_read(process, path) { - materialize_mapped_host_path_from_kernel(kernel, kernel_pid, path, &mapped_host)?; - let opened = open_mapped_runtime_beneath( - &mapped_host, - "fs.stat", - O_PATH_ANCHOR, - Mode::empty(), - )?; - let metadata = fs::metadata(opened.handle.proc_path()).map_err(|error| { - SidecarError::Io(format!( - "failed to stat mapped guest path {} -> {}: {error}", - path, - opened.host_path.display() - )) - })?; - return Ok(javascript_sync_rpc_host_stat_value(&metadata)); - } - kernel - .stat_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) - .map(javascript_sync_rpc_stat_value) - .map_err(kernel_error) - } - "fs.lstatSync" | "fs.promises.lstat" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem lstat path")?; - let path = path.as_str(); - if let Some(mapped_host) = mapped_runtime_host_path_for_read(process, path) { - materialize_mapped_host_path_from_kernel(kernel, kernel_pid, path, &mapped_host)?; - let metadata = mapped_runtime_symlink_metadata(&mapped_host, "fs.lstat")?; - return Ok(metadata.to_value()); - } - kernel - .lstat_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) - .map(javascript_sync_rpc_stat_value) - .map_err(kernel_error) - } - "fs.readdirSync" | "fs.promises.readdir" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem readdir path")?; - let path = path.as_str(); - service_javascript_fs_readdir_entries(kernel, process, kernel_pid, path) - .map(javascript_sync_rpc_readdir_typed_value) - } - "fs.mkdirSync" | "fs.promises.mkdir" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem mkdir path")?; - let path = path.as_str(); - let recursive = - javascript_sync_rpc_option_bool(&request.args, 1, "recursive").unwrap_or(false); - match mapped_runtime_host_path(process, path, true) { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { - if mapped_runtime_relative_path(&mapped_host)? == Path::new(".") { - create_mapped_runtime_root_directory(&mapped_host, recursive)?; - } else { - if recursive { - ensure_mapped_runtime_parent_dirs(&mapped_host, "fs.mkdir")?; - let parent = - open_mapped_runtime_parent_beneath(&mapped_host, "fs.mkdir")?; - create_mapped_runtime_directory(&parent, path, true)?; - } else { - let parent = - open_mapped_runtime_parent_beneath(&mapped_host, "fs.mkdir")?; - create_mapped_runtime_directory(&parent, path, false)?; - } - } - return Ok(Value::Null); - } - Some(MappedRuntimeHostAccess::ReadOnly(_)) => { - return Err(read_only_mapped_runtime_host_path_error(path)); - } - None => {} - } - kernel - .mkdir_for_process( - EXECUTION_DRIVER_NAME, - kernel_pid, - path, - recursive, - javascript_sync_rpc_option_u32(&request.args, 1, "mode")?, - ) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.accessSync" | "fs.promises.access" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem access path")?; - let path = path.as_str(); - let mode = - javascript_sync_rpc_arg_u32_optional(&request.args, 1, "filesystem access mode")? - .unwrap_or(0); - let valid_mask = libc::R_OK as u32 | libc::W_OK as u32 | libc::X_OK as u32; - if mode & !valid_mask != 0 { - return Err(SidecarError::Execution(format!( - "EINVAL: invalid filesystem access mode {mode:o}" - ))); - } - if let Some(mapped_host) = mapped_runtime_host_path_for_read(process, path) { - materialize_mapped_host_path_from_kernel(kernel, kernel_pid, path, &mapped_host)?; - let opened = open_mapped_runtime_beneath( - &mapped_host, - "fs.access", - O_PATH_ANCHOR, - Mode::empty(), - )?; - let metadata = fs::metadata(opened.handle.proc_path()).map_err(|error| { - SidecarError::Io(format!( - "failed to access mapped guest path {} -> {}: {error}", - path, - opened.host_path.display() - )) - })?; - if !filesystem_access_mode_is_allowed(metadata.permissions().mode(), mode) { - return Err(filesystem_access_denied(path, mode)); - } - return Ok(Value::Null); - } - let stat = kernel - .stat_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) - .map_err(kernel_error)?; - if !filesystem_access_mode_is_allowed(stat.mode, mode) { - return Err(filesystem_access_denied(path, mode)); - } - Ok(Value::Null) - } - "fs.copyFileSync" | "fs.promises.copyFile" => { - let source = javascript_sync_rpc_path_arg( - process, - &request.args, - 0, - "filesystem copyFile source", - )?; - let source = source.as_str(); - let destination = javascript_sync_rpc_path_arg( - process, - &request.args, - 1, - "filesystem copyFile destination", - )?; - let destination = destination.as_str(); - let source_host = mapped_runtime_host_path(process, source, false); - let destination_host = mapped_runtime_host_path(process, destination, true); - if matches!(destination_host, Some(MappedRuntimeHostAccess::ReadOnly(_))) { - return Err(read_only_mapped_runtime_host_path_error(destination)); - } - if source_host.is_some() || destination_host.is_some() { - let contents = match source_host { - Some(MappedRuntimeHostAccess::Writable(ref mapped_host)) => { - let opened = open_mapped_runtime_beneath( - mapped_host, - "fs.copyFile source", - OFlag::O_RDONLY, - Mode::empty(), - )?; - fs::read(opened.handle.proc_path()).map_err(|error| { - SidecarError::Io(format!( - "failed to read mapped guest file {} -> {}: {error}", - source, - opened.host_path.display() - )) - })? - } - Some(MappedRuntimeHostAccess::ReadOnly(ref mapped_host)) => { - let opened = open_mapped_runtime_beneath( - mapped_host, - "fs.copyFile source", - OFlag::O_RDONLY, - Mode::empty(), - )?; - fs::read(opened.handle.proc_path()).map_err(|error| { - SidecarError::Io(format!( - "failed to read mapped guest file {} -> {}: {error}", - source, - opened.host_path.display() - )) - })? - } - None => kernel - .read_file_for_process(EXECUTION_DRIVER_NAME, kernel_pid, source) - .map_err(kernel_error)?, - }; - return match destination_host { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { - let opened = open_mapped_runtime_beneath( - &mapped_host, - "fs.copyFile destination", - OFlag::O_WRONLY | OFlag::O_CREAT | OFlag::O_TRUNC, - Mode::from_bits_truncate(0o666), - )?; - fs::write(opened.handle.proc_path(), contents) - .map(|()| Value::Null) - .map_err(|error| { - SidecarError::Io(format!( - "failed to write mapped guest file {} -> {}: {error}", - destination, - opened.host_path.display() - )) - }) - } - Some(MappedRuntimeHostAccess::ReadOnly(_)) => { - Err(read_only_mapped_runtime_host_path_error(destination)) - } - None => kernel - .write_file_for_process( - EXECUTION_DRIVER_NAME, - kernel_pid, - destination, - contents, - None, - ) - .map(|()| Value::Null) - .map_err(kernel_error), - }; - } - let contents = kernel - .read_file_for_process(EXECUTION_DRIVER_NAME, kernel_pid, source) - .map_err(kernel_error)?; - kernel - .write_file_for_process( - EXECUTION_DRIVER_NAME, - kernel_pid, - destination, - contents, - None, - ) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.existsSync" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem exists path")?; - let path = path.as_str(); - if let Some(mapped_host) = mapped_runtime_host_path_for_read(process, path) { - materialize_mapped_host_path_from_kernel(kernel, kernel_pid, path, &mapped_host)?; - let exists = match open_mapped_runtime_beneath( - &mapped_host, - "fs.exists", - O_PATH_ANCHOR, - Mode::empty(), - ) { - Ok(opened) => fs::metadata(opened.handle.proc_path()).is_ok(), - Err(_) => false, - }; - return Ok(Value::Bool(exists)); - } - kernel - .exists_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) - .map(Value::Bool) - .map_err(kernel_error) - } - "fs.readlinkSync" | "fs.promises.readlink" => { - let path = javascript_sync_rpc_path_arg( - process, - &request.args, - 0, - "filesystem readlink path", - )?; - let path = path.as_str(); - if let Some(mapped_host) = mapped_runtime_host_path_for_read(process, path) { - materialize_mapped_host_path_from_kernel(kernel, kernel_pid, path, &mapped_host)?; - let target = read_mapped_runtime_link(&mapped_host, path, "fs.readlink")?; - return Ok(Value::String(target.to_string_lossy().into_owned())); - } - kernel - .read_link_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) - .map(Value::String) - .map_err(kernel_error) - } - "fs.symlinkSync" | "fs.promises.symlink" => { - let target = - javascript_sync_rpc_arg_str(&request.args, 0, "filesystem symlink target")?; - let link_path = - javascript_sync_rpc_path_arg(process, &request.args, 1, "filesystem symlink path")?; - let link_path = link_path.as_str(); - match mapped_runtime_host_path(process, link_path, true) { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { - ensure_mapped_runtime_parent_dirs(&mapped_host, "fs.symlink")?; - let parent = open_mapped_runtime_parent_beneath(&mapped_host, "fs.symlink")?; - let host_path = parent.host_path.join(&parent.child_name); - remove_shadow_path_if_exists(&host_path, link_path)?; - mapped_child_symlink(&parent, target).map_err(|error| { - SidecarError::Io(format!( - "failed to create mapped guest symlink {} -> {} ({target}): {error}", - link_path, - host_path.display() - )) - })?; - return Ok(Value::Null); - } - Some(MappedRuntimeHostAccess::ReadOnly(_)) => { - return Err(read_only_mapped_runtime_host_path_error(link_path)); - } - None => {} - } - kernel - .symlink(target, link_path) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.linkSync" | "fs.promises.link" => { - let source = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem link source")?; - let source = source.as_str(); - let destination = - javascript_sync_rpc_path_arg(process, &request.args, 1, "filesystem link path")?; - let destination = destination.as_str(); - kernel - .link(source, destination) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.renameSync" | "fs.promises.rename" => { - let source = javascript_sync_rpc_path_arg( - process, - &request.args, - 0, - "filesystem rename source", - )?; - let source = source.as_str(); - let destination = javascript_sync_rpc_path_arg( - process, - &request.args, - 1, - "filesystem rename destination", - )?; - let destination = destination.as_str(); - let source_host = mapped_runtime_host_path(process, source, true); - let destination_host = mapped_runtime_host_path(process, destination, true); - if matches!(source_host, Some(MappedRuntimeHostAccess::ReadOnly(_))) { - return Err(read_only_mapped_runtime_host_path_error(source)); - } - if matches!(destination_host, Some(MappedRuntimeHostAccess::ReadOnly(_))) { - return Err(read_only_mapped_runtime_host_path_error(destination)); - } - if source_host.is_some() || destination_host.is_some() { - return rename_mapped_host_path(source, source_host, destination, destination_host); - } - kernel - .rename(source, destination) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.rmdirSync" | "fs.promises.rmdir" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem rmdir path")?; - let path = path.as_str(); - match mapped_runtime_host_path(process, path, true) { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { - let parent = open_mapped_runtime_parent_beneath(&mapped_host, "fs.rmdir")?; - let host_path = parent.host_path.join(&parent.child_name); - mapped_child_remove_dir(&parent).map_err(|error| { - SidecarError::Io(format!( - "failed to remove mapped guest directory {} -> {}: {error}", - path, - host_path.display() - )) - })?; - // Mirror the deletion into the kernel for the same reason as - // fs.unlink below: readdir/stat merge kernel state, so a - // kernel-backed directory would otherwise resurrect. - if let Err(error) = kernel.remove_dir(path) { - if error.code() != "ENOENT" { - return Err(kernel_error(error)); - } - } - return Ok(Value::Null); - } - Some(MappedRuntimeHostAccess::ReadOnly(_)) => { - return Err(read_only_mapped_runtime_host_path_error(path)); - } - None => {} - } - kernel - .remove_dir(path) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.unlinkSync" | "fs.promises.unlink" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem unlink path")?; - let path = path.as_str(); - match mapped_runtime_host_path(process, path, true) { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { - let parent = open_mapped_runtime_parent_beneath(&mapped_host, "fs.unlink")?; - let host_path = parent.host_path.join(&parent.child_name); - mapped_child_remove_file(&parent).map_err(|error| { - SidecarError::Io(format!( - "failed to remove mapped guest file {} -> {}: {error}", - path, - host_path.display() - )) - })?; - // The shadow cannot express deletions, and readdir/stat now - // merge kernel state into the mapped view — without a kernel - // removal a kernel-backed file (e.g. created by a wasm - // command) would resurrect in the very listing that follows - // the unlink. Best-effort: absent kernel entries are fine. - if let Err(error) = kernel.remove_file(path) { - if error.code() != "ENOENT" { - return Err(kernel_error(error)); - } - } - return Ok(Value::Null); - } - Some(MappedRuntimeHostAccess::ReadOnly(_)) => { - return Err(read_only_mapped_runtime_host_path_error(path)); - } - None => {} - } - kernel - .remove_file(path) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.chmodSync" | "fs.promises.chmod" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem chmod path")?; - let path = path.as_str(); - let mode = javascript_sync_rpc_arg_u32(&request.args, 1, "filesystem chmod mode")?; - match mapped_runtime_host_path(process, path, true) { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { - materialize_mapped_host_path_from_kernel( - kernel, - kernel_pid, - path, - &mapped_host, - )?; - let opened = open_mapped_runtime_beneath( - &mapped_host, - "fs.chmod", - O_PATH_ANCHOR, - Mode::empty(), - )?; - if kernel - .exists_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) - .map_err(kernel_error)? - { - kernel.chmod(path, mode).map_err(kernel_error)?; - } - fs::set_permissions( - opened.handle.proc_path(), - fs::Permissions::from_mode(mode & 0o7777), - ) - .map_err(|error| { - SidecarError::Io(format!( - "failed to chmod mapped guest path {} -> {}: {error}", - path, - opened.host_path.display() - )) - })?; - return Ok(Value::Null); - } - Some(MappedRuntimeHostAccess::ReadOnly(_)) => { - return Err(read_only_mapped_runtime_host_path_error(path)); - } - None => {} - } - kernel - .chmod(path, mode) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.chownSync" | "fs.promises.chown" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem chown path")?; - let path = path.as_str(); - let uid = javascript_sync_rpc_arg_u32(&request.args, 1, "filesystem chown uid")?; - let gid = javascript_sync_rpc_arg_u32(&request.args, 2, "filesystem chown gid")?; - kernel - .chown(path, uid, gid) - .map(|()| Value::Null) - .map_err(kernel_error) - } - "fs.utimesSync" | "fs.promises.utimes" | "fs.lutimesSync" | "fs.promises.lutimes" => { - let path = - javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem utimes path")?; - let path = path.as_str(); - let atime = parse_utime_arg(&request.args, 1, "filesystem utimes atime")?; - let mtime = parse_utime_arg(&request.args, 2, "filesystem utimes mtime")?; - let follow_symlinks = !matches!( - request.method.as_str(), - "fs.lutimesSync" | "fs.promises.lutimes" - ); - if let Some(shadow_path) = process_shadow_host_path(process, path) { - if fs::symlink_metadata(&shadow_path).is_ok() { - let result = if follow_symlinks { - kernel.utimes_spec(path, atime, mtime) - } else { - kernel.lutimes(path, atime, mtime) - }; - if let Err(error) = result { - if error.code() != "ENOENT" { - return Err(kernel_error(error)); - } - } - apply_host_path_utimens( - &shadow_path, - atime, - mtime, - follow_symlinks, - &format!("failed to update process shadow path times {path}"), - )?; - return Ok(Value::Null); - } - } - match mapped_runtime_host_path(process, path, true) { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { - let mapped_host_exists = match fs::symlink_metadata(&mapped_host.host_path) { - Ok(_) => true, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => { - materialize_mapped_host_path_from_kernel( - kernel, - kernel_pid, - path, - &mapped_host, - )?; - fs::symlink_metadata(&mapped_host.host_path).is_ok() - } - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to inspect mapped guest path {} -> {}: {error}", - path, - mapped_host.host_path.display() - ))); - } - }; - if mapped_host_exists { - let context = format!("failed to update mapped guest path times {path}"); - // Resolve the host target up front and hold the handle across - // the kernel update so the apply below operates on the verified - // fd. (The handle must stay alive: a `/proc/self/fd` path is - // only valid while its fd is open, and the macOS fd-relative - // path needs the live parent fd.) - let follow_handle = if follow_symlinks { - Some(open_mapped_runtime_beneath( - &mapped_host, - "fs.utimes", - O_PATH_ANCHOR, - Mode::empty(), - )?) - } else { - None - }; - let parent_handle = if follow_symlinks { - None - } else { - Some(open_mapped_runtime_parent_beneath( - &mapped_host, - "fs.lutimes", - )?) - }; - if kernel - .exists_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) - .map_err(kernel_error)? - { - let result = if follow_symlinks { - kernel.utimes_spec(path, atime, mtime) - } else { - kernel.lutimes(path, atime, mtime) - }; - if let Err(error) = result { - if error.code() != "ENOENT" { - return Err(kernel_error(error)); - } - } - } - if let Some(opened) = &follow_handle { - apply_host_path_utimens( - &opened.handle.proc_path(), - atime, - mtime, - true, - &context, - )?; - } else if let Some(parent) = &parent_handle { - apply_mapped_child_utimens(parent, atime, mtime, &context)?; - } - return Ok(Value::Null); - } - } - Some(MappedRuntimeHostAccess::ReadOnly(_)) => { - return Err(read_only_mapped_runtime_host_path_error(path)); - } - None => {} - } - if follow_symlinks { - kernel - .utimes_spec(path, atime, mtime) - .map_err(kernel_error)?; - } else { - kernel.lutimes(path, atime, mtime).map_err(kernel_error)?; - }; - Ok(Value::Null) - } - "fs.futimesSync" => { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem futimes fd")?; - let atime = parse_utime_arg(&request.args, 1, "filesystem futimes atime")?; - let mtime = parse_utime_arg(&request.args, 2, "filesystem futimes mtime")?; - kernel - .futimes(EXECUTION_DRIVER_NAME, kernel_pid, fd, atime, mtime) - .map(|()| Value::Null) - .map_err(kernel_error) - } - _ => Err(SidecarError::InvalidState(format!( - "unsupported JavaScript sync RPC method {}", - request.method - ))), - } -} - -fn kernel_fd_surfaces_stdio_event( - kernel: &SidecarKernel, - kernel_pid: u32, - fd: u32, -) -> Result { - let path = match fd { - 1 | 2 => kernel - .fd_path(EXECUTION_DRIVER_NAME, kernel_pid, fd) - .map_err(kernel_error)?, - _ => return Ok(false), - }; - Ok(matches!( - (fd, path.as_str()), - (1, "/dev/stdout") | (2, "/dev/stderr") - )) -} - -fn javascript_sync_rpc_path_arg( - process: &ActiveProcess, - args: &[Value], - index: usize, - label: &str, -) -> Result { - let path = javascript_sync_rpc_arg_str(args, index, label)?; - Ok(normalize_process_filesystem_rpc_path(process, path)) -} - -fn normalize_process_filesystem_rpc_path(process: &ActiveProcess, path: &str) -> String { - let host_path = Path::new(path); - if host_path.is_absolute() { - let normalized_host_path = normalize_host_path(host_path); - if let Some(guest_path) = - guest_path_from_runtime_host_mappings(process, &normalized_host_path) - { - return guest_path; - } - if let Some(sandbox_root) = process - .env - .get(EXECUTION_SANDBOX_ROOT_ENV) - .filter(|value| !value.is_empty()) - .map(PathBuf::from) - .map(|path| normalize_host_path(&path)) - { - if let Ok(suffix) = normalized_host_path.strip_prefix(&sandbox_root) { - let suffix = suffix.to_string_lossy(); - return normalize_path(&format!("/{}", suffix.trim_start_matches('/'))); - } - } - } - path.to_owned() -} - -fn guest_path_from_runtime_host_mappings( - process: &ActiveProcess, - host_path: &Path, -) -> Option { - runtime_guest_host_mappings(process) - .into_iter() - .filter_map(|(guest_path, host_root)| { - host_path.strip_prefix(&host_root).ok().map(|suffix| { - let suffix = suffix.to_string_lossy(); - normalize_path(&format!( - "{}/{}", - guest_path.trim_end_matches('/'), - suffix.trim_start_matches('/') - )) - }) - }) - .max_by_key(String::len) -} - -fn runtime_guest_host_mappings(process: &ActiveProcess) -> Vec<(String, PathBuf)> { - let Some(mappings) = process - .env - .get("AGENTOS_GUEST_PATH_MAPPINGS") - .and_then(|value| serde_json::from_str::>(value).ok()) - else { - return Vec::new(); - }; - mappings - .into_iter() - .filter_map(|mapping| { - if mapping.guest_path.is_empty() || mapping.host_path.is_empty() { - return None; - } - let host_root = PathBuf::from(mapping.host_path); - let normalized_host_root = if host_root.is_absolute() { - normalize_host_path(&host_root) - } else { - normalize_host_path(&std::env::current_dir().ok()?.join(host_root)) - }; - Some((normalize_path(&mapping.guest_path), normalized_host_root)) - }) - .collect() -} - -fn mirror_kernel_fd_contents_to_process_shadow( - kernel: &mut SidecarKernel, - process: &ActiveProcess, - kernel_pid: u32, - fd: u32, -) -> Result<(), SidecarError> { - let path = kernel - .fd_path(EXECUTION_DRIVER_NAME, kernel_pid, fd) - .map_err(kernel_error)?; - let path = normalize_process_filesystem_rpc_path(process, &path); - mirror_kernel_path_to_process_shadow(kernel, process, kernel_pid, &path) -} - -fn mirror_kernel_path_to_process_shadow( - kernel: &mut SidecarKernel, - process: &ActiveProcess, - kernel_pid: u32, - guest_path: &str, -) -> Result<(), SidecarError> { - let Some(shadow_path) = resolve_process_guest_path_to_host(process, guest_path) else { - return Ok(()); - }; - let bytes = kernel - .read_file_for_process(EXECUTION_DRIVER_NAME, kernel_pid, guest_path) - .map_err(kernel_error)?; - write_process_shadow_file(&shadow_path, guest_path, &bytes) -} - -fn write_process_shadow_file( - shadow_path: &Path, - guest_path: &str, - bytes: &[u8], -) -> Result<(), SidecarError> { - if let Some(parent) = shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!( - "failed to create shadow parent for {}: {error}", - normalize_path(guest_path) - )) - })?; - } - match fs::symlink_metadata(shadow_path) { - Ok(metadata) if metadata.file_type().is_symlink() => { - fs::remove_file(shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to replace shadow symlink for {}: {error}", - normalize_path(guest_path) - )) - })?; - } - Ok(metadata) if metadata.is_dir() => { - fs::remove_dir_all(shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to replace shadow directory for {}: {error}", - normalize_path(guest_path) - )) - })?; - } - Ok(_) => {} - Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to inspect shadow path for {}: {error}", - normalize_path(guest_path) - ))); - } - } - fs::write(shadow_path, bytes).map_err(|error| { - SidecarError::Io(format!( - "failed to mirror kernel file {} into process shadow: {error}", - normalize_path(guest_path) - )) - }) -} - -fn javascript_sync_rpc_stat_value(stat: VirtualStat) -> Value { - let mut value = Map::with_capacity(18); - value.insert("mode".to_string(), Value::from(stat.mode)); - value.insert("size".to_string(), Value::from(stat.size)); - value.insert("blocks".to_string(), Value::from(stat.blocks)); - value.insert("dev".to_string(), Value::from(stat.dev)); - value.insert("rdev".to_string(), Value::from(stat.rdev)); - value.insert("isDirectory".to_string(), Value::from(stat.is_directory)); - value.insert( - "isSymbolicLink".to_string(), - Value::from(stat.is_symbolic_link), - ); - value.insert("atimeMs".to_string(), Value::from(stat.atime_ms)); - value.insert("atimeNsec".to_string(), Value::from(stat.atime_nsec)); - value.insert("mtimeMs".to_string(), Value::from(stat.mtime_ms)); - value.insert("mtimeNsec".to_string(), Value::from(stat.mtime_nsec)); - value.insert("ctimeMs".to_string(), Value::from(stat.ctime_ms)); - value.insert("ctimeNsec".to_string(), Value::from(stat.ctime_nsec)); - value.insert("birthtimeMs".to_string(), Value::from(stat.birthtime_ms)); - value.insert("ino".to_string(), Value::from(stat.ino)); - value.insert("nlink".to_string(), Value::from(stat.nlink)); - value.insert("uid".to_string(), Value::from(stat.uid)); - value.insert("gid".to_string(), Value::from(stat.gid)); - Value::Object(value) -} - -fn javascript_sync_rpc_host_stat_value(metadata: &fs::Metadata) -> Value { - let mut value = Map::with_capacity(15); - value.insert("mode".to_string(), Value::from(metadata.mode())); - value.insert("size".to_string(), Value::from(metadata.size())); - value.insert("blocks".to_string(), Value::from(metadata.blocks())); - value.insert("dev".to_string(), Value::from(metadata.dev())); - value.insert("rdev".to_string(), Value::from(metadata.rdev())); - value.insert("isDirectory".to_string(), Value::from(metadata.is_dir())); - value.insert( - "isSymbolicLink".to_string(), - Value::from(metadata.file_type().is_symlink()), - ); - value.insert( - "atimeMs".to_string(), - Value::from(metadata.atime() * 1000 + (metadata.atime_nsec() / 1_000_000)), - ); - value.insert( - "mtimeMs".to_string(), - Value::from(metadata.mtime() * 1000 + (metadata.mtime_nsec() / 1_000_000)), - ); - value.insert( - "ctimeMs".to_string(), - Value::from(metadata.ctime() * 1000 + (metadata.ctime_nsec() / 1_000_000)), - ); - value.insert( - "birthtimeMs".to_string(), - Value::from(metadata.ctime() * 1000 + (metadata.ctime_nsec() / 1_000_000)), - ); - value.insert("ino".to_string(), Value::from(metadata.ino())); - value.insert("nlink".to_string(), Value::from(metadata.nlink())); - value.insert("uid".to_string(), Value::from(metadata.uid())); - value.insert("gid".to_string(), Value::from(metadata.gid())); - Value::Object(value) -} - -fn mapped_runtime_host_path( - process: &ActiveProcess, - guest_path: &str, - writable: bool, -) -> Option { - if process_prefers_kernel_fs_sync_rpc(process) { - return None; - } - - let normalized = if guest_path.starts_with('/') { - normalize_path(guest_path) - } else { - normalize_path(&format!( - "{}/{}", - process.guest_cwd.trim_end_matches('/'), - guest_path - )) - }; - let mappings = process - .env - .get("AGENTOS_GUEST_PATH_MAPPINGS") - .and_then(|value| serde_json::from_str::>(value).ok())?; - let mut sorted_mappings = mappings - .into_iter() - .filter_map(|mapping| { - (!mapping.guest_path.is_empty() && !mapping.host_path.is_empty()).then_some(( - normalize_path(&mapping.guest_path), - PathBuf::from(mapping.host_path), - )) - }) - .collect::>(); - sorted_mappings.sort_by_key(|mapping| std::cmp::Reverse(mapping.0.len())); - let readable_roots = runtime_host_access_roots(process, "AGENTOS_EXTRA_FS_READ_PATHS")?; - let writable_roots = writable - .then(|| runtime_host_access_roots(process, "AGENTOS_EXTRA_FS_WRITE_PATHS")) - .flatten() - .unwrap_or_default(); - - for (guest_root, host_root) in sorted_mappings { - if guest_root != "/" - && normalized != guest_root - && !normalized.starts_with(&format!("{guest_root}/")) - { - continue; - } - if guest_root == "/" && !normalized.starts_with('/') { - continue; - } - - let normalized_host_root = if host_root.is_absolute() { - normalize_host_path(&host_root) - } else { - normalize_host_path(&std::env::current_dir().ok()?.join(host_root)) - }; - let suffix = if guest_root == "/" { - normalized.trim_start_matches('/') - } else { - normalized - .strip_prefix(&guest_root) - .unwrap_or_default() - .trim_start_matches('/') - }; - let host_path = if suffix.is_empty() { - normalized_host_root.clone() - } else { - normalized_host_root.join(suffix) - }; - - let is_asset_path = guest_root == PYTHON_PYODIDE_GUEST_ROOT - || normalized == PYTHON_PYODIDE_GUEST_ROOT - || normalized.starts_with(&format!("{PYTHON_PYODIDE_GUEST_ROOT}/")); - let is_cache_path = guest_root == PYTHON_PYODIDE_CACHE_GUEST_ROOT - || normalized == PYTHON_PYODIDE_CACHE_GUEST_ROOT - || normalized.starts_with(&format!("{PYTHON_PYODIDE_CACHE_GUEST_ROOT}/")); - if is_asset_path && !writable { - return Some(MappedRuntimeHostAccess::Writable(MappedRuntimeHostPath { - guest_path: normalized.clone(), - host_root: normalized_host_root.clone(), - host_path, - })); - } - if is_cache_path { - return Some(MappedRuntimeHostAccess::Writable(MappedRuntimeHostPath { - guest_path: normalized.clone(), - host_root: normalized_host_root.clone(), - host_path, - })); - } - - let Some(read_root) = readable_roots - .iter() - .find(|root| path_is_within_root(&host_path, root)) - .cloned() - else { - continue; - }; - if !writable { - return Some(MappedRuntimeHostAccess::Writable(MappedRuntimeHostPath { - guest_path: normalized.clone(), - host_root: read_root.clone(), - host_path, - })); - } - if let Some(write_root) = writable_roots - .iter() - .find(|root| path_is_within_root(&host_path, root)) - .cloned() - { - return Some(MappedRuntimeHostAccess::Writable(MappedRuntimeHostPath { - guest_path: normalized.clone(), - host_root: write_root.clone(), - host_path, - })); - } - if guest_root != "/" { - return Some(MappedRuntimeHostAccess::ReadOnly(MappedRuntimeHostPath { - guest_path: normalized.clone(), - host_root: read_root.clone(), - host_path, - })); - } - } - - None -} - -fn mapped_runtime_host_path_for_read( - process: &ActiveProcess, - guest_path: &str, -) -> Option { - match mapped_runtime_host_path(process, guest_path, false) { - Some(MappedRuntimeHostAccess::Writable(mapped_host)) - | Some(MappedRuntimeHostAccess::ReadOnly(mapped_host)) => Some(mapped_host), - None => None, - } -} - -fn process_shadow_host_path(process: &ActiveProcess, guest_path: &str) -> Option { - if process_prefers_kernel_fs_sync_rpc(process) { - return None; - } - - let normalized_guest_path = normalized_process_guest_path(process, guest_path); - let normalized_guest_cwd = normalize_path(&process.guest_cwd); - let mut host_root = normalize_host_path(&process.host_cwd); - for _ in normalized_guest_cwd - .trim_start_matches('/') - .split('/') - .filter(|segment| !segment.is_empty()) - { - host_root = host_root.parent()?.to_path_buf(); - } - if normalized_guest_path == "/" { - Some(host_root) - } else { - Some(host_root.join(normalized_guest_path.trim_start_matches('/'))) - } -} - -fn normalized_process_guest_path(process: &ActiveProcess, guest_path: &str) -> String { - if guest_path.starts_with('/') { - normalize_path(guest_path) - } else { - normalize_path(&format!( - "{}/{}", - process.guest_cwd.trim_end_matches('/'), - guest_path - )) - } -} - -fn process_prefers_kernel_fs_sync_rpc(process: &ActiveProcess) -> bool { - process.runtime == GuestRuntimeKind::WebAssembly - && process - .env - .get(EXECUTION_SANDBOX_ROOT_ENV) - .is_some_and(|value| !value.is_empty()) -} - -fn runtime_host_access_roots(process: &ActiveProcess, key: &str) -> Option> { - process - .env - .get(key) - .and_then(|value| serde_json::from_str::>(value).ok()) - .map(|roots| { - roots - .into_iter() - .map(PathBuf::from) - .map(|root| normalize_host_path(&root)) - .collect() - }) -} - -fn mapped_runtime_child_mount_basenames(process: &ActiveProcess, guest_path: &str) -> Vec { - let normalized = normalize_path(guest_path); - let mappings = process - .env - .get("AGENTOS_GUEST_PATH_MAPPINGS") - .and_then(|value| serde_json::from_str::>(value).ok()) - .unwrap_or_default(); - let mut basenames = BTreeSet::new(); - for mapping in mappings { - let guest_root = normalize_path(&mapping.guest_path); - if guest_root == "/" || guest_root == normalized { - continue; - } - if mapped_runtime_parent_path(&guest_root) == normalized { - basenames.insert(mapped_runtime_basename(&guest_root)); - } - } - basenames.into_iter().collect() -} - -fn mapped_runtime_parent_path(path: &str) -> String { - let normalized = normalize_path(path); - let parent = Path::new(&normalized) - .parent() - .unwrap_or_else(|| Path::new("/")); - let value = parent.to_string_lossy(); - if value.is_empty() { - String::from("/") - } else { - value.into_owned() - } -} - -fn mapped_runtime_basename(path: &str) -> String { - let normalized = normalize_path(path); - Path::new(&normalized) - .file_name() - .map(|value| value.to_string_lossy().into_owned()) - .unwrap_or_else(|| String::from("/")) -} - -fn read_only_mapped_runtime_host_path_error(guest_path: &str) -> SidecarError { - SidecarError::Kernel(format!("EROFS: read-only filesystem: {guest_path}")) -} - -#[cfg(not(target_os = "macos"))] -fn mapped_runtime_resolve_flags() -> ResolveFlag { - ResolveFlag::RESOLVE_BENEATH | ResolveFlag::RESOLVE_NO_MAGICLINKS -} - -/// Open `relative` strictly beneath the mapped mount root, returning an owned -/// raw fd. Linux resolves with `openat2(RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS)` -/// anchored on `root_dir`; macOS has no such syscall and resolves beneath -/// `host_root` with cap-std (see [`crate::macos_fs`]). -#[cfg(not(target_os = "macos"))] -fn mapped_runtime_open_fd( - root_dir: &AnchoredFd, - _host_root: &Path, - relative: &Path, - flags: OFlag, - mode: Mode, -) -> Result { - openat2( - root_dir.as_raw_fd(), - relative, - OpenHow::new() - .flags(flags | OFlag::O_CLOEXEC) - .mode(mode) - .resolve(mapped_runtime_resolve_flags()), - ) -} - -#[cfg(target_os = "macos")] -fn mapped_runtime_open_fd( - _root_dir: &AnchoredFd, - host_root: &Path, - relative: &Path, - flags: OFlag, - mode: Mode, -) -> Result { - crate::macos_fs::resolve_beneath(host_root, relative, flags, mode) -} - -fn mapped_runtime_relative_path(mapped: &MappedRuntimeHostPath) -> Result { - let normalized_root = normalize_host_path(&mapped.host_root); - let normalized_path = normalize_host_path(&mapped.host_path); - if !path_is_within_root(&normalized_path, &normalized_root) { - return Err(mapped_runtime_host_path_escape_error( - mapped, - &normalized_path, - )); - } - let relative = normalized_path - .strip_prefix(&normalized_root) - .map_err(|error| { - SidecarError::InvalidState(format!( - "failed to relativize mapped guest path {} ({} against {}): {error}", - mapped.guest_path, - normalized_path.display(), - normalized_root.display() - )) - })?; - Ok(if relative.as_os_str().is_empty() { - PathBuf::from(".") - } else { - relative.to_path_buf() - }) -} - -fn open_mapped_runtime_root_dir( - mapped: &MappedRuntimeHostPath, - operation: &str, -) -> Result { - let fd = open( - &mapped.host_root, - OFlag::O_CLOEXEC | OFlag::O_DIRECTORY | OFlag::O_RDONLY, - Mode::empty(), - ) - .map_err(|error| { - SidecarError::Io(format!( - "{operation}: failed to open mapped host root {} for {}: {}", - mapped.host_root.display(), - mapped.guest_path, - std::io::Error::from_raw_os_error(error as i32) - )) - })?; - Ok(AnchoredFd { fd }) -} - -fn open_mapped_runtime_beneath( - mapped: &MappedRuntimeHostPath, - operation: &str, - flags: OFlag, - mode: Mode, -) -> Result { - let root_dir = open_mapped_runtime_root_dir(mapped, operation)?; - let relative = mapped_runtime_relative_path(mapped)?; - let open_mode = if flags.intersects(OFlag::O_CREAT | O_TMPFILE_FLAG) { - mode - } else { - Mode::empty() - }; - let fd = mapped_runtime_open_fd(&root_dir, &mapped.host_root, &relative, flags, open_mode) - .map_err(|error| mapped_runtime_open_error(operation, mapped, error))?; - let handle = AnchoredFd { fd }; - let host_path = mapped_runtime_host_path_from_fd(mapped, operation, &handle)?; - Ok(MappedRuntimeOpenedPath { handle, host_path }) -} - -fn open_mapped_runtime_directory_beneath( - mapped: &MappedRuntimeHostPath, - operation: &str, - relative: &Path, -) -> Result { - let root_dir = open_mapped_runtime_root_dir(mapped, operation)?; - let fd = mapped_runtime_open_fd( - &root_dir, - &mapped.host_root, - relative, - OFlag::O_DIRECTORY | OFlag::O_RDONLY, - Mode::empty(), - ) - .map_err(|error| mapped_runtime_open_error(operation, mapped, error))?; - let handle = AnchoredFd { fd }; - let host_path = mapped_runtime_host_path_from_fd(mapped, operation, &handle)?; - Ok(MappedRuntimeOpenedPath { handle, host_path }) -} - -fn open_mapped_runtime_parent_beneath( - mapped: &MappedRuntimeHostPath, - operation: &str, -) -> Result { - let relative = mapped_runtime_relative_path(mapped)?; - let child_name = relative.file_name().ok_or_else(|| { - SidecarError::InvalidState(format!( - "{operation}: mapped guest path {} has no parent-relative basename", - mapped.guest_path - )) - })?; - let parent_relative = relative - .parent() - .filter(|parent| !parent.as_os_str().is_empty()) - .unwrap_or_else(|| Path::new(".")); - let directory = open_mapped_runtime_directory_beneath(mapped, operation, parent_relative)?; - Ok(MappedRuntimeParentPath { - directory: directory.handle, - host_path: directory.host_path, - child_name: child_name.to_os_string(), - }) -} - -/// Platform-neutral lstat result. Lets the mapped-runtime lstat path produce the -/// same guest-facing stat value from either a `std::fs::Metadata` (Linux, and -/// the macOS root case) or a raw `fstatat` result (macOS fd-relative child -/// lstat), so the operation stays fd-relative on macOS without a `std::fs` -/// metadata handle. -struct HostStat { - mode: u32, - size: u64, - blocks: u64, - dev: u64, - rdev: u64, - is_directory: bool, - is_symbolic_link: bool, - atime_ms: i64, - mtime_ms: i64, - ctime_ms: i64, - ino: u64, - nlink: u64, - uid: u32, - gid: u32, -} - -impl HostStat { - #[cfg_attr(not(test), allow(dead_code))] - fn is_dir(&self) -> bool { - self.is_directory - } - - fn to_value(&self) -> Value { - json!({ - "mode": self.mode, - "size": self.size, - "blocks": self.blocks, - "dev": self.dev, - "rdev": self.rdev, - "isDirectory": self.is_directory, - "isSymbolicLink": self.is_symbolic_link, - "atimeMs": self.atime_ms, - "mtimeMs": self.mtime_ms, - "ctimeMs": self.ctime_ms, - "birthtimeMs": self.ctime_ms, - "ino": self.ino, - "nlink": self.nlink, - "uid": self.uid, - "gid": self.gid, - }) - } -} - -impl From<&fs::Metadata> for HostStat { - fn from(metadata: &fs::Metadata) -> Self { - Self { - mode: metadata.mode(), - size: metadata.size(), - blocks: metadata.blocks(), - dev: metadata.dev(), - rdev: metadata.rdev(), - is_directory: metadata.is_dir(), - is_symbolic_link: metadata.file_type().is_symlink(), - atime_ms: metadata.atime() * 1000 + (metadata.atime_nsec() / 1_000_000), - mtime_ms: metadata.mtime() * 1000 + (metadata.mtime_nsec() / 1_000_000), - ctime_ms: metadata.ctime() * 1000 + (metadata.ctime_nsec() / 1_000_000), - ino: metadata.ino(), - nlink: metadata.nlink(), - uid: metadata.uid(), - gid: metadata.gid(), - } - } -} - -#[cfg(target_os = "macos")] -impl HostStat { - fn from_filestat(stat: &nix::sys::stat::FileStat) -> Self { - use nix::sys::stat::SFlag; - let fmt = stat.st_mode & SFlag::S_IFMT.bits(); - Self { - mode: stat.st_mode as u32, - size: stat.st_size as u64, - blocks: stat.st_blocks as u64, - dev: stat.st_dev as u64, - rdev: stat.st_rdev as u64, - is_directory: fmt == SFlag::S_IFDIR.bits(), - is_symbolic_link: fmt == SFlag::S_IFLNK.bits(), - atime_ms: stat.st_atime * 1000 + (stat.st_atime_nsec / 1_000_000), - mtime_ms: stat.st_mtime * 1000 + (stat.st_mtime_nsec / 1_000_000), - ctime_ms: stat.st_ctime * 1000 + (stat.st_ctime_nsec / 1_000_000), - ino: stat.st_ino, - nlink: stat.st_nlink as u64, - uid: stat.st_uid, - gid: stat.st_gid, - } - } -} - -#[cfg(not(target_os = "macos"))] -fn mapped_child_lstat(parent: &MappedRuntimeParentPath) -> std::io::Result { - Ok(HostStat::from(&fs::symlink_metadata( - mapped_runtime_parent_child_path(parent), - )?)) -} -#[cfg(target_os = "macos")] -fn mapped_child_lstat(parent: &MappedRuntimeParentPath) -> std::io::Result { - let stat = nix::sys::stat::fstatat( - Some(parent.directory.as_raw_fd()), - parent.child_name.as_os_str(), - nix::fcntl::AtFlags::AT_SYMLINK_NOFOLLOW, - ) - .map_err(errno_to_io)?; - Ok(HostStat::from_filestat(&stat)) -} - -fn mapped_runtime_symlink_metadata( - mapped: &MappedRuntimeHostPath, - operation: &str, -) -> Result { - let relative = mapped_runtime_relative_path(mapped)?; - if relative == Path::new(".") { - return fs::symlink_metadata(&mapped.host_path) - .map(|metadata| HostStat::from(&metadata)) - .map_err(|error| { - SidecarError::Io(format!( - "failed to lstat mapped guest path {} -> {}: {error}", - mapped.guest_path, - mapped.host_path.display() - )) - }); - } - - let parent = open_mapped_runtime_parent_beneath(mapped, operation)?; - let host_path = parent.host_path.join(&parent.child_name); - mapped_child_lstat(&parent).map_err(|error| { - SidecarError::Io(format!( - "failed to lstat mapped guest path {} -> {}: {error}", - mapped.guest_path, - host_path.display() - )) - }) -} - -fn read_mapped_runtime_link( - mapped: &MappedRuntimeHostPath, - guest_path: &str, - operation: &str, -) -> Result { - if mapped_runtime_relative_path(mapped)? == Path::new(".") { - return fs::read_link(&mapped.host_path).map_err(|error| { - SidecarError::Io(format!( - "failed to read mapped guest symlink {} -> {}: {error}", - guest_path, - mapped.host_path.display() - )) - }); - } - - let parent = open_mapped_runtime_parent_beneath(mapped, operation)?; - let host_path = parent.host_path.join(&parent.child_name); - mapped_child_read_link(&parent).map_err(|error| { - SidecarError::Io(format!( - "failed to read mapped guest symlink {} -> {}: {error}", - guest_path, - host_path.display() - )) - }) -} - -fn mapped_runtime_host_path_from_fd( - mapped: &MappedRuntimeHostPath, - operation: &str, - fd: &AnchoredFd, -) -> Result { - // Linux reads the magic symlink `/proc/self/fd/N`; macOS recovers the path - // with `fcntl(F_GETPATH)` (see [`crate::macos_fs::fd_real_path`]). - #[cfg(not(target_os = "macos"))] - let resolved = fs::read_link(fd.proc_path()); - #[cfg(target_os = "macos")] - let resolved = crate::macos_fs::fd_real_path(fd.as_raw_fd()); - resolved.map_err(|error| { - SidecarError::Io(format!( - "{operation}: failed to resolve anchored mapped guest path {}: {error}", - mapped.guest_path - )) - }) -} - -#[cfg(not(target_os = "macos"))] -fn mapped_runtime_parent_child_path(parent: &MappedRuntimeParentPath) -> PathBuf { - parent.directory.proc_path().join(&parent.child_name) -} - -// --------------------------------------------------------------------------- -// Mapped-runtime child operations. -// -// On Linux these operate on the resolved parent fd by appending the child to -// `/proc/self/fd/N`. macOS cannot append path components to `/dev/fd/N`, so it -// performs the same operations with fd-relative `*at` calls anchored on the -// resolved parent fd — TOCTOU-safe, mirroring the host_dir plugin. -// --------------------------------------------------------------------------- - -#[cfg(target_os = "macos")] -fn errno_to_io(error: Errno) -> std::io::Error { - std::io::Error::from_raw_os_error(error as i32) -} - -#[cfg(not(target_os = "macos"))] -fn create_dir_at(dir: &AnchoredFd, name: &std::ffi::OsStr) -> std::io::Result<()> { - fs::create_dir(dir.proc_path().join(name)) -} -#[cfg(target_os = "macos")] -fn create_dir_at(dir: &AnchoredFd, name: &std::ffi::OsStr) -> std::io::Result<()> { - nix::sys::stat::mkdirat(Some(dir.as_raw_fd()), name, Mode::from_bits_truncate(0o777)) - .map_err(errno_to_io) -} - -fn mapped_child_create_dir(parent: &MappedRuntimeParentPath) -> std::io::Result<()> { - create_dir_at(&parent.directory, parent.child_name.as_os_str()) -} - -#[cfg(not(target_os = "macos"))] -fn mapped_child_is_dir(parent: &MappedRuntimeParentPath) -> std::io::Result { - Ok(fs::symlink_metadata(mapped_runtime_parent_child_path(parent))?.is_dir()) -} -#[cfg(target_os = "macos")] -fn mapped_child_is_dir(parent: &MappedRuntimeParentPath) -> std::io::Result { - use nix::sys::stat::SFlag; - let stat = nix::sys::stat::fstatat( - Some(parent.directory.as_raw_fd()), - parent.child_name.as_os_str(), - nix::fcntl::AtFlags::AT_SYMLINK_NOFOLLOW, - ) - .map_err(errno_to_io)?; - Ok(stat.st_mode & SFlag::S_IFMT.bits() == SFlag::S_IFDIR.bits()) -} - -#[cfg(not(target_os = "macos"))] -fn mapped_child_remove_dir(parent: &MappedRuntimeParentPath) -> std::io::Result<()> { - fs::remove_dir(mapped_runtime_parent_child_path(parent)) -} -#[cfg(target_os = "macos")] -fn mapped_child_remove_dir(parent: &MappedRuntimeParentPath) -> std::io::Result<()> { - nix::unistd::unlinkat( - Some(parent.directory.as_raw_fd()), - parent.child_name.as_os_str(), - nix::unistd::UnlinkatFlags::RemoveDir, - ) - .map_err(errno_to_io) -} - -#[cfg(not(target_os = "macos"))] -fn mapped_child_remove_file(parent: &MappedRuntimeParentPath) -> std::io::Result<()> { - fs::remove_file(mapped_runtime_parent_child_path(parent)) -} -#[cfg(target_os = "macos")] -fn mapped_child_remove_file(parent: &MappedRuntimeParentPath) -> std::io::Result<()> { - nix::unistd::unlinkat( - Some(parent.directory.as_raw_fd()), - parent.child_name.as_os_str(), - nix::unistd::UnlinkatFlags::NoRemoveDir, - ) - .map_err(errno_to_io) -} - -#[cfg(not(target_os = "macos"))] -fn mapped_child_symlink(parent: &MappedRuntimeParentPath, target: &str) -> std::io::Result<()> { - std::os::unix::fs::symlink(target, mapped_runtime_parent_child_path(parent)) -} -#[cfg(target_os = "macos")] -fn mapped_child_symlink(parent: &MappedRuntimeParentPath, target: &str) -> std::io::Result<()> { - nix::unistd::symlinkat( - target, - Some(parent.directory.as_raw_fd()), - parent.child_name.as_os_str(), - ) - .map_err(errno_to_io) -} - -#[cfg(not(target_os = "macos"))] -fn mapped_child_read_link(parent: &MappedRuntimeParentPath) -> std::io::Result { - fs::read_link(mapped_runtime_parent_child_path(parent)) -} -#[cfg(target_os = "macos")] -fn mapped_child_read_link(parent: &MappedRuntimeParentPath) -> std::io::Result { - nix::fcntl::readlinkat( - Some(parent.directory.as_raw_fd()), - parent.child_name.as_os_str(), - ) - .map(PathBuf::from) - .map_err(errno_to_io) -} - -/// Set access/modification times on a mapped child without following symlinks -/// (lutimes). Linux operates on `/proc/self/fd/N/child`; macOS uses fd-relative -/// `utimensat` anchored on the resolved parent fd. -#[cfg(not(target_os = "macos"))] -fn apply_mapped_child_utimens( - parent: &MappedRuntimeParentPath, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - context: &str, -) -> Result<(), SidecarError> { - apply_host_path_utimens( - &mapped_runtime_parent_child_path(parent), - atime, - mtime, - false, - context, - ) -} -#[cfg(target_os = "macos")] -fn apply_mapped_child_utimens( - parent: &MappedRuntimeParentPath, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - context: &str, -) -> Result<(), SidecarError> { - let existing = match (atime, mtime) { - (VirtualUtimeSpec::Omit, _) | (_, VirtualUtimeSpec::Omit) => { - let stat = nix::sys::stat::fstatat( - Some(parent.directory.as_raw_fd()), - parent.child_name.as_os_str(), - nix::fcntl::AtFlags::AT_SYMLINK_NOFOLLOW, - ) - .map_err(|error| SidecarError::Io(format!("{context}: failed to stat: {error}")))?; - Some(( - VirtualTimeSpec { - sec: stat.st_atime, - nsec: stat.st_atime_nsec.max(0) as u32, - }, - VirtualTimeSpec { - sec: stat.st_mtime, - nsec: stat.st_mtime_nsec.max(0) as u32, - }, - )) - } - _ => None, - }; - let existing_atime = existing - .as_ref() - .map(|(atime, _)| *atime) - .unwrap_or(VirtualTimeSpec { sec: 0, nsec: 0 }); - let existing_mtime = existing - .as_ref() - .map(|(_, mtime)| *mtime) - .unwrap_or(VirtualTimeSpec { sec: 0, nsec: 0 }); - let times = [ - resolve_host_utime(atime, existing_atime), - resolve_host_utime(mtime, existing_mtime), - ]; - utimensat( - Some(parent.directory.as_raw_fd()), - parent.child_name.as_os_str(), - ×[0], - ×[1], - UtimensatFlags::NoFollowSymlink, - ) - .map_err(|error| SidecarError::Io(format!("{context}: failed to set times: {error}"))) -} - -#[cfg(not(target_os = "macos"))] -fn mapped_child_rename( - source: &MappedRuntimeParentPath, - destination: &MappedRuntimeParentPath, -) -> std::io::Result<()> { - rename_mapped_host_path_with_fallback( - &mapped_runtime_parent_child_path(source), - &mapped_runtime_parent_child_path(destination), - ) -} -#[cfg(target_os = "macos")] -fn mapped_child_rename( - source: &MappedRuntimeParentPath, - destination: &MappedRuntimeParentPath, -) -> std::io::Result<()> { - // Same-filesystem rename is fd-relative (TOCTOU-safe). A cross-device rename - // (EXDEV) cannot be done fd-relative, so fall back to the path-based copy on - // the resolved real paths, exactly as the Linux fallback does. - match nix::fcntl::renameat( - Some(source.directory.as_raw_fd()), - source.child_name.as_os_str(), - Some(destination.directory.as_raw_fd()), - destination.child_name.as_os_str(), - ) { - Ok(()) => Ok(()), - Err(Errno::EXDEV) => move_mapped_host_path_across_devices( - &source.host_path.join(&source.child_name), - &destination.host_path.join(&destination.child_name), - ), - Err(error) => Err(errno_to_io(error)), - } -} - -fn create_mapped_runtime_directory( - parent: &MappedRuntimeParentPath, - guest_path: &str, - recursive: bool, -) -> Result<(), SidecarError> { - match mapped_child_create_dir(parent) { - Ok(()) => Ok(()), - Err(error) if recursive && error.kind() == std::io::ErrorKind::AlreadyExists => { - match mapped_child_is_dir(parent) { - Ok(true) => Ok(()), - Ok(false) => Err(SidecarError::Io(format!( - "failed to create mapped guest directory {} -> {}: file exists and is not a directory", - guest_path, - parent.host_path.join(&parent.child_name).display() - ))), - Err(metadata_error) => Err(SidecarError::Io(format!( - "failed to inspect existing mapped guest directory {} -> {}: {metadata_error}", - guest_path, - parent.host_path.join(&parent.child_name).display() - ))), - } - } - Err(error) => Err(SidecarError::Io(format!( - "failed to create mapped guest directory {} -> {}: {error}", - guest_path, - parent.host_path.join(&parent.child_name).display() - ))), - } -} - -fn create_mapped_runtime_root_directory( - mapped: &MappedRuntimeHostPath, - recursive: bool, -) -> Result<(), SidecarError> { - let relative = mapped_runtime_relative_path(mapped)?; - if relative != Path::new(".") { - return Err(SidecarError::InvalidState(format!( - "fs.mkdir: mapped guest path {} is not the mapped root", - mapped.guest_path - ))); - } - - if recursive { - match fs::create_dir_all(&mapped.host_path) { - Ok(()) => Ok(()), - Err(error) => Err(SidecarError::Io(format!( - "failed to create mapped guest directory {} -> {}: {error}", - mapped.guest_path, - mapped.host_path.display() - ))), - } - } else { - match fs::create_dir(&mapped.host_path) { - Ok(()) => Ok(()), - Err(error) => Err(SidecarError::Io(format!( - "failed to create mapped guest directory {} -> {}: {error}", - mapped.guest_path, - mapped.host_path.display() - ))), - } - } -} - -fn ensure_mapped_runtime_parent_dirs( - mapped: &MappedRuntimeHostPath, - operation: &str, -) -> Result<(), SidecarError> { - let relative = mapped_runtime_relative_path(mapped)?; - let Some(parent_relative) = relative - .parent() - .filter(|parent| !parent.as_os_str().is_empty()) - else { - return Ok(()); - }; - if parent_relative == Path::new(".") { - return Ok(()); - } - - for index in 0..parent_relative.components().count() { - let prefix = parent_relative - .components() - .take(index + 1) - .collect::(); - if open_mapped_runtime_directory_beneath(mapped, operation, &prefix).is_ok() { - continue; - } - - let prefix_parent = prefix - .parent() - .filter(|parent| !parent.as_os_str().is_empty()) - .unwrap_or_else(|| Path::new(".")); - let prefix_name = prefix.file_name().ok_or_else(|| { - SidecarError::InvalidState(format!( - "{operation}: invalid mapped guest directory prefix for {}", - mapped.guest_path - )) - })?; - let parent_dir = open_mapped_runtime_directory_beneath(mapped, operation, prefix_parent)?; - create_dir_at(&parent_dir.handle, prefix_name).map_err(|error| { - SidecarError::Io(format!( - "{operation}: failed to create mapped guest parent {} under {}: {error}", - mapped.guest_path, - parent_dir.host_path.display() - )) - })?; - } - - Ok(()) -} - -fn mapped_runtime_open_error( - operation: &str, - mapped: &MappedRuntimeHostPath, - error: Errno, -) -> SidecarError { - match error { - Errno::EXDEV => mapped_runtime_host_path_escape_error(mapped, &mapped.host_path), - other => SidecarError::Io(format!( - "{operation}: failed to open mapped guest path {} beneath {}: {}", - mapped.guest_path, - mapped.host_root.display(), - std::io::Error::from_raw_os_error(other as i32) - )), - } -} - -fn mapped_runtime_host_path_escape_error( - mapped: &MappedRuntimeHostPath, - resolved: &Path, -) -> SidecarError { - SidecarError::Io(format!( - "mapped guest path {} escapes mapped host root {} via {}", - mapped.guest_path, - mapped.host_root.display(), - resolved.display() - )) -} - -fn mapped_host_open_is_writable(flags: u32) -> bool { - let access_mode = flags & libc::O_ACCMODE as u32; - access_mode == libc::O_WRONLY as u32 - || access_mode == libc::O_RDWR as u32 - || flags & libc::O_APPEND as u32 != 0 - || flags & libc::O_CREAT as u32 != 0 - || flags & libc::O_TRUNC as u32 != 0 -} - -fn materialize_mapped_host_path_from_kernel( - kernel: &mut SidecarKernel, - kernel_pid: u32, - guest_path: &str, - mapped: &MappedRuntimeHostPath, -) -> Result<(), SidecarError> { - let host_path = &mapped.host_path; - match fs::symlink_metadata(host_path) { - Ok(_) => return Ok(()), - Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to inspect mapped host path for {} -> {}: {error}", - guest_path, - host_path.display() - ))); - } - } - - if !kernel - .exists_for_process(EXECUTION_DRIVER_NAME, kernel_pid, guest_path) - .map_err(kernel_error)? - { - return Ok(()); - } - - let stat = kernel - .lstat_for_process(EXECUTION_DRIVER_NAME, kernel_pid, guest_path) - .map_err(kernel_error)?; - - if stat.is_symbolic_link { - let target = kernel - .read_link_for_process(EXECUTION_DRIVER_NAME, kernel_pid, guest_path) - .map_err(kernel_error)?; - ensure_mapped_runtime_parent_dirs(mapped, "fs.materialize")?; - let parent = open_mapped_runtime_parent_beneath(mapped, "fs.materialize")?; - mapped_child_symlink(&parent, &target).map_err(|error| { - SidecarError::Io(format!( - "failed to materialize mapped guest symlink {} -> {} ({target}): {error}", - guest_path, - parent.host_path.join(&parent.child_name).display() - )) - })?; - return Ok(()); - } else if stat.is_directory { - if mapped_runtime_relative_path(mapped)? == Path::new(".") { - create_mapped_runtime_root_directory(mapped, true)?; - } else { - ensure_mapped_runtime_parent_dirs(mapped, "fs.materialize")?; - let parent = open_mapped_runtime_parent_beneath(mapped, "fs.materialize")?; - create_mapped_runtime_directory(&parent, guest_path, true)?; - } - } else { - let bytes = kernel - .read_file_for_process(EXECUTION_DRIVER_NAME, kernel_pid, guest_path) - .map_err(kernel_error)?; - ensure_mapped_runtime_parent_dirs(mapped, "fs.materialize")?; - let opened = open_mapped_runtime_beneath( - mapped, - "fs.materialize", - OFlag::O_CREAT | OFlag::O_TRUNC | OFlag::O_WRONLY, - Mode::from_bits_truncate((stat.mode & 0o7777) as _), - )?; - fs::write(opened.handle.proc_path(), bytes).map_err(|error| { - SidecarError::Io(format!( - "failed to materialize mapped guest file {} -> {}: {error}", - guest_path, - opened.host_path.display() - )) - })?; - } - - let opened = - open_mapped_runtime_beneath(mapped, "fs.materialize", O_PATH_ANCHOR, Mode::empty())?; - fs::set_permissions( - opened.handle.proc_path(), - fs::Permissions::from_mode(stat.mode & 0o7777), - ) - .map_err(|error| { - SidecarError::Io(format!( - "failed to set permissions for materialized mapped guest path {} -> {}: {error}", - guest_path, - opened.host_path.display() - )) - })?; - - Ok(()) -} - -fn open_mapped_host_fd( - process: &mut ActiveProcess, - host_path: PathBuf, - guest_path: Option, - proc_path: PathBuf, - flags: u32, -) -> Result { - let access_mode = flags & libc::O_ACCMODE as u32; - let mut options = OpenOptions::new(); - match access_mode { - x if x == libc::O_WRONLY as u32 => { - options.write(true); - } - x if x == libc::O_RDWR as u32 => { - options.read(true).write(true); - } - _ => { - options.read(true); - } - } - if flags & libc::O_APPEND as u32 != 0 { - options.append(true); - } - - let masked_flags = flags - & !(libc::O_ACCMODE as u32 - | libc::O_APPEND as u32 - | libc::O_CREAT as u32 - | libc::O_EXCL as u32 - | libc::O_TRUNC as u32); - options.custom_flags(masked_flags as i32); - - let file = options.open(&proc_path).map_err(|error| { - SidecarError::Io(format!( - "failed to open mapped guest file {}: {error}", - host_path.display() - )) - })?; - let fd = process.allocate_mapped_host_fd(crate::state::ActiveMappedHostFd { - file, - path: host_path, - guest_path, - }); - Ok(json!(fd)) -} - -fn read_mapped_host_fd( - mapped: &mut crate::state::ActiveMappedHostFd, - fd: u32, - length: usize, - position: Option, -) -> Result { - let mut bytes = vec![0_u8; length]; - let read = match position { - Some(offset) => mapped.file.read_at(&mut bytes, offset), - None => mapped.file.read(&mut bytes), - } - .map_err(|error| { - SidecarError::Io(format!( - "failed to read mapped guest fd {fd} -> {}: {error}", - mapped.path.display() - )) - })?; - bytes.truncate(read); - Ok(javascript_sync_rpc_bytes_value(&bytes)) -} - -fn write_mapped_host_fd( - mapped: &mut crate::state::ActiveMappedHostFd, - fd: u32, - contents: &[u8], - position: Option, -) -> Result { - let written = match position { - Some(offset) => mapped.file.write_at(contents, offset), - None => mapped.file.write(contents), - } - .map_err(|error| { - SidecarError::Io(format!( - "failed to write mapped guest fd {fd} -> {}: {error}", - mapped.path.display() - )) - })?; - Ok(json!(written)) -} - -fn write_all_mapped_host_fd( - mapped: &mut crate::state::ActiveMappedHostFd, - fd: u32, - contents: &[u8], - position: Option, -) -> Result { - let mut total = 0usize; - while total < contents.len() { - let write_position = position.map(|offset| offset.saturating_add(total as u64)); - let written = match write_position { - Some(offset) => mapped.file.write_at(&contents[total..], offset), - None => mapped.file.write(&contents[total..]), - } - .map_err(|error| { - SidecarError::Io(format!( - "failed to write mapped guest fd {fd} -> {}: {error}", - mapped.path.display() - )) - })?; - if written == 0 { - return Err(SidecarError::Execution(format!( - "EIO: filesystem write made no progress on mapped fd {fd}" - ))); - } - total = total.saturating_add(written); - } - Ok(total) -} - -fn read_le_u32(payload: &[u8], offset: &mut usize, label: &str) -> Result { - let end = offset - .checked_add(4) - .ok_or_else(|| SidecarError::InvalidState(format!("filesystem {label} offset overflow")))?; - let bytes = payload.get(*offset..end).ok_or_else(|| { - SidecarError::InvalidState(format!("truncated filesystem {label} payload")) - })?; - *offset = end; - Ok(u32::from_le_bytes( - bytes.try_into().expect("slice length checked"), - )) -} - -fn decode_javascript_writev_raw_payload(payload: &[u8]) -> Result, SidecarError> { - let mut offset = 0usize; - let count = read_le_u32(payload, &mut offset, "writev count")? as usize; - let mut buffers = Vec::with_capacity(count); - for _ in 0..count { - let len = read_le_u32(payload, &mut offset, "writev buffer length")? as usize; - let end = offset.checked_add(len).ok_or_else(|| { - SidecarError::InvalidState(String::from("filesystem writev payload length overflow")) - })?; - let buffer = payload.get(offset..end).ok_or_else(|| { - SidecarError::InvalidState(String::from("truncated filesystem writev payload")) - })?; - buffers.push(buffer); - offset = end; - } - if offset != payload.len() { - return Err(SidecarError::InvalidState(String::from( - "filesystem writev payload has trailing bytes", - ))); - } - Ok(buffers) -} - -fn rename_mapped_host_path( - source: &str, - source_host: Option, - destination: &str, - destination_host: Option, -) -> Result { - match (source_host, destination_host) { - ( - Some(MappedRuntimeHostAccess::Writable(source_host)), - Some(MappedRuntimeHostAccess::Writable(destination_host)), - ) => { - if normalize_host_path(&source_host.host_root) - != normalize_host_path(&destination_host.host_root) - { - return Err(SidecarError::Kernel(format!( - "EXDEV: invalid cross-device link: {source} -> {destination}" - ))); - } - let source_parent = open_mapped_runtime_parent_beneath(&source_host, "fs.rename")?; - let destination_parent = - open_mapped_runtime_parent_beneath(&destination_host, "fs.rename")?; - let source_host_path = source_parent.host_path.join(&source_parent.child_name); - let destination_host_path = destination_parent - .host_path - .join(&destination_parent.child_name); - mapped_child_rename(&source_parent, &destination_parent) - .map(|()| Value::Null) - .map_err(|error| { - SidecarError::Io(format!( - "failed to rename mapped guest path {} -> {} ({} -> {}): {error}", - source, - destination, - source_host_path.display(), - destination_host_path.display() - )) - }) - } - (Some(MappedRuntimeHostAccess::ReadOnly(_)), _) => { - Err(read_only_mapped_runtime_host_path_error(source)) - } - (_, Some(MappedRuntimeHostAccess::ReadOnly(_))) => { - Err(read_only_mapped_runtime_host_path_error(destination)) - } - _ => Err(SidecarError::Kernel(format!( - "EXDEV: invalid cross-device link: {source} -> {destination}" - ))), - } -} - -// On macOS the mapped rename is fd-relative (`renameat`); this path-based -// fallback is only used by the Linux mapped-rename helper. -#[cfg_attr(target_os = "macos", allow(dead_code))] -fn rename_mapped_host_path_with_fallback(source: &Path, destination: &Path) -> std::io::Result<()> { - if let Some(parent) = destination.parent() { - fs::create_dir_all(parent)?; - } - match fs::rename(source, destination) { - Ok(()) => Ok(()), - Err(error) if error.raw_os_error() == Some(libc::EXDEV) => { - move_mapped_host_path_across_devices(source, destination) - } - Err(error) => Err(error), - } -} - -fn move_mapped_host_path_across_devices(source: &Path, destination: &Path) -> std::io::Result<()> { - let metadata = fs::symlink_metadata(source)?; - remove_existing_mapped_host_destination(destination)?; - if let Some(parent) = destination.parent() { - fs::create_dir_all(parent)?; - } - - if metadata.file_type().is_symlink() { - let target = fs::read_link(source)?; - symlink(&target, destination)?; - fs::remove_file(source)?; - return Ok(()); - } - - if metadata.is_dir() { - fs::create_dir_all(destination)?; - for entry in fs::read_dir(source)? { - let entry = entry?; - let source_child = entry.path(); - let destination_child = destination.join(entry.file_name()); - move_mapped_host_path_across_devices(&source_child, &destination_child)?; - } - fs::set_permissions(destination, metadata.permissions())?; - fs::remove_dir(source)?; - return Ok(()); - } - - fs::copy(source, destination)?; - fs::set_permissions(destination, metadata.permissions())?; - fs::remove_file(source)?; - Ok(()) -} - -fn remove_existing_mapped_host_destination(path: &Path) -> std::io::Result<()> { - match fs::symlink_metadata(path) { - Ok(metadata) if metadata.file_type().is_symlink() || metadata.is_file() => { - fs::remove_file(path) - } - Ok(metadata) if metadata.is_dir() => fs::remove_dir(path), - Ok(_) => Ok(()), - Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()), - Err(error) => Err(error), - } -} - -fn mapped_readdir_entry_is_directory( - mapped_host: &MappedRuntimeHostPath, - directory: &MappedRuntimeOpenedPath, - guest_dir_path: &str, - entry: &fs::DirEntry, - name: &str, -) -> Option { - let file_type = entry.file_type().ok()?; - if !file_type.is_symlink() { - return Some(file_type.is_dir()); - } - - let child = MappedRuntimeHostPath { - guest_path: normalize_path(&format!( - "{}/{}", - guest_dir_path.trim_end_matches('/'), - name - )), - host_root: mapped_host.host_root.clone(), - host_path: directory.host_path.join(entry.file_name()), - }; - let opened = - open_mapped_runtime_beneath(&child, "fs.readdir entry", O_PATH_ANCHOR, Mode::empty()) - .ok()?; - fs::metadata(opened.handle.proc_path()) - .map(|metadata| metadata.is_dir()) - .ok() -} - -pub(crate) fn service_javascript_fs_readdir_entries( - kernel: &mut SidecarKernel, - process: &ActiveProcess, - kernel_pid: u32, - path: &str, -) -> Result, SidecarError> { - if let Some(MappedRuntimeHostAccess::Writable(mapped_host)) = - mapped_runtime_host_path(process, path, false) - { - let mut typed: BTreeMap = BTreeMap::new(); - match open_mapped_runtime_beneath( - &mapped_host, - "fs.readdir", - OFlag::O_DIRECTORY | OFlag::O_RDONLY, - Mode::empty(), - ) { - Ok(directory) => { - let readdir_path = directory.handle.readdir_path().map_err(|error| { - SidecarError::Io(format!( - "failed to resolve mapped guest directory {} -> {}: {error}", - path, - directory.host_path.display() - )) - })?; - for entry in fs::read_dir(readdir_path).map_err(|error| { - SidecarError::Io(format!( - "failed to read mapped guest directory {} -> {}: {error}", - path, - directory.host_path.display() - )) - })? { - let Ok(entry) = entry else { continue }; - let Ok(name) = entry.file_name().into_string() else { - continue; - }; - if let Some(is_dir) = mapped_readdir_entry_is_directory( - &mapped_host, - &directory, - path, - &entry, - &name, - ) { - typed.insert(name, is_dir); - } - } - } - Err(_) - if matches!( - fs::symlink_metadata(&mapped_host.host_path), - Err(ref metadata_error) - if metadata_error.kind() == std::io::ErrorKind::NotFound - ) => {} - Err(error) => return Err(error), - } - match kernel.read_dir_with_types_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) { - Ok(entries) => { - for entry in entries { - typed.entry(entry.name).or_insert(entry.is_directory); - } - } - Err(error) if matches!(error.code(), "ENOENT" | "ENOTDIR") => {} - Err(error) => return Err(kernel_error(error)), - } - for name in mapped_runtime_child_mount_basenames(process, path) { - typed.entry(name).or_insert(true); - } - return Ok(typed); - } - - kernel - .read_dir_with_types_for_process(EXECUTION_DRIVER_NAME, kernel_pid, path) - .map(|entries| { - entries - .into_iter() - .map(|entry| (entry.name, entry.is_directory)) - .collect() - }) - .map_err(kernel_error) -} - -pub(crate) fn service_javascript_fs_readdir_raw_sync_rpc( - kernel: &mut SidecarKernel, - process: &ActiveProcess, - kernel_pid: u32, - request: &JavascriptSyncRpcRequest, -) -> Result, SidecarError> { - let path = javascript_sync_rpc_path_arg(process, &request.args, 0, "filesystem readdir path")?; - let entries = - service_javascript_fs_readdir_entries(kernel, process, kernel_pid, path.as_str())?; - encode_javascript_readdir_raw_payload(entries) -} - -fn encode_javascript_readdir_raw_payload( - entries: BTreeMap, -) -> Result, SidecarError> { - let mut payload = Vec::new(); - for (name, is_dir) in entries - .into_iter() - .filter(|(name, _)| name != "." && name != "..") - { - let name = name.into_bytes(); - let name_len = u32::try_from(name.len()).map_err(|_| { - SidecarError::InvalidState(String::from("filesystem readdir entry name too long")) - })?; - payload.push(u8::from(is_dir)); - payload.extend_from_slice(&name_len.to_le_bytes()); - payload.extend_from_slice(&name); - } - Ok(payload) -} - -/// Like `javascript_sync_rpc_readdir_value` but carries each entry's -/// directory-ness as `{name, isDirectory}`. The guest's `normalizeReaddirEntries` -/// consumes these objects directly for `withFileTypes`, avoiding a per-entry stat -/// RPC, and extracts `.name` for the plain string form. -fn javascript_sync_rpc_readdir_typed_value(entries: BTreeMap) -> Value { - json!(entries - .into_iter() - .filter(|(name, _)| name != "." && name != "..") - .map(|(name, is_dir)| json!({ "name": name, "isDirectory": is_dir })) - .collect::>()) -} - -fn mirror_guest_file_write_to_shadow( - vm: &mut VmState, - guest_path: &str, - bytes: &[u8], -) -> Result<(), SidecarError> { - let guest_path = normalize_path(guest_path); - let shadow_path = if guest_path == "/" { - vm.cwd.clone() - } else { - vm.cwd.join(guest_path.trim_start_matches('/')) - }; - - if let Some(parent) = shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!( - "failed to create shadow parent for {}: {error}", - guest_path - )) - })?; - } - - match fs::symlink_metadata(&shadow_path) { - Ok(metadata) if metadata.file_type().is_symlink() => { - fs::remove_file(&shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to replace shadow symlink for {}: {error}", - guest_path - )) - })?; - } - Ok(metadata) if metadata.is_dir() => { - fs::remove_dir_all(&shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to replace shadow directory for {}: {error}", - guest_path - )) - })?; - } - Ok(_) => {} - Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to inspect shadow path for {}: {error}", - guest_path - ))); - } - } - fs::write(&shadow_path, bytes).map_err(|error| { - SidecarError::Io(format!( - "failed to mirror guest file {} into shadow root: {error}", - guest_path - )) - })?; - - let stat = vm.kernel.lstat(&guest_path).map_err(kernel_error)?; - fs::set_permissions(&shadow_path, fs::Permissions::from_mode(stat.mode & 0o7777)).map_err( - |error| { - SidecarError::Io(format!( - "failed to set shadow mode for {}: {error}", - guest_path - )) - }, - )?; - - Ok(()) -} - -fn mirror_guest_directory_write_to_shadow( - vm: &mut VmState, - guest_path: &str, -) -> Result<(), SidecarError> { - let guest_path = normalize_path(guest_path); - let shadow_path = shadow_host_path_for_guest(&vm.cwd, &guest_path); - - fs::create_dir_all(&shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to mirror guest directory {} into shadow root: {error}", - guest_path - )) - })?; - - let stat = vm.kernel.lstat(&guest_path).map_err(kernel_error)?; - fs::set_permissions(&shadow_path, fs::Permissions::from_mode(stat.mode & 0o7777)).map_err( - |error| { - SidecarError::Io(format!( - "failed to set shadow mode for directory {}: {error}", - guest_path - )) - }, - )?; - - Ok(()) -} - -fn ensure_guest_path_materialized_in_shadow( - vm: &mut VmState, - guest_path: &str, -) -> Result { - let guest_path = normalize_path(guest_path); - let shadow_path = shadow_host_path_for_guest(&vm.cwd, &guest_path); - if fs::symlink_metadata(&shadow_path).is_ok() { - return Ok(shadow_path); - } - - let stat = vm.kernel.lstat(&guest_path).map_err(kernel_error)?; - if stat.is_symbolic_link { - let target = vm.kernel.read_link(&guest_path).map_err(kernel_error)?; - mirror_guest_symlink_to_shadow(vm, &guest_path, &target)?; - } else if stat.is_directory { - mirror_guest_directory_write_to_shadow(vm, &guest_path)?; - } else { - let bytes = vm.kernel.read_file(&guest_path).map_err(kernel_error)?; - mirror_guest_file_write_to_shadow(vm, &guest_path, &bytes)?; - } - - Ok(shadow_path) -} - -fn mirror_guest_subtree_to_shadow(vm: &mut VmState, guest_path: &str) -> Result<(), SidecarError> { - let guest_path = normalize_path(guest_path); - ensure_guest_path_materialized_in_shadow(vm, &guest_path)?; - let stat = vm.kernel.lstat(&guest_path).map_err(kernel_error)?; - if !stat.is_directory || stat.is_symbolic_link { - return Ok(()); - } - - let entries = vm - .kernel - .read_dir_recursive(&guest_path, None) - .map_err(kernel_error)?; - for entry in entries { - ensure_guest_path_materialized_in_shadow(vm, &entry.path)?; - } - Ok(()) -} - -fn mirror_guest_symlink_to_shadow( - vm: &mut VmState, - guest_path: &str, - target: &str, -) -> Result<(), SidecarError> { - let guest_path = normalize_path(guest_path); - let shadow_path = shadow_host_path_for_guest(&vm.cwd, &guest_path); - let shadow_target = shadow_symlink_target_for_guest(&vm.cwd, &guest_path, target); - - if let Some(parent) = shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!( - "failed to create shadow parent for symlink {}: {error}", - guest_path - )) - })?; - } - - remove_shadow_path_if_exists(&shadow_path, &guest_path)?; - symlink(&shadow_target, &shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to mirror guest symlink {} into shadow root: {error}", - guest_path - )) - }) -} - -fn mirror_guest_link_to_shadow( - vm: &mut VmState, - source_path: &str, - destination_path: &str, -) -> Result<(), SidecarError> { - let source_path = normalize_path(source_path); - let destination_path = normalize_path(destination_path); - let source_shadow_path = ensure_guest_path_materialized_in_shadow(vm, &source_path)?; - let destination_shadow_path = shadow_host_path_for_guest(&vm.cwd, &destination_path); - - if let Some(parent) = destination_shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!( - "failed to create shadow parent for link {}: {error}", - destination_path - )) - })?; - } - - remove_shadow_path_if_exists(&destination_shadow_path, &destination_path)?; - fs::hard_link(&source_shadow_path, &destination_shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to mirror guest link {} -> {} into shadow root: {error}", - source_path, destination_path - )) - }) -} - -fn mirror_guest_chmod_to_shadow( - vm: &mut VmState, - guest_path: &str, - mode: u32, -) -> Result<(), SidecarError> { - let shadow_path = ensure_guest_path_materialized_in_shadow(vm, guest_path)?; - fs::set_permissions(&shadow_path, fs::Permissions::from_mode(mode & 0o7777)).map_err(|error| { - SidecarError::Io(format!( - "failed to set shadow mode for {}: {error}", - normalize_path(guest_path) - )) - }) -} - -fn mirror_guest_utimes_to_shadow( - vm: &mut VmState, - guest_path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, -) -> Result<(), SidecarError> { - let shadow_path = ensure_guest_path_materialized_in_shadow(vm, guest_path)?; - apply_host_path_utimens( - &shadow_path, - atime, - mtime, - follow_symlinks, - &format!( - "failed to mirror guest utimes for {} into shadow root", - normalize_path(guest_path) - ), - ) -} - -fn mirror_guest_truncate_to_shadow( - vm: &mut VmState, - guest_path: &str, - len: u64, -) -> Result<(), SidecarError> { - let shadow_path = ensure_guest_path_materialized_in_shadow(vm, guest_path)?; - OpenOptions::new() - .write(true) - .open(&shadow_path) - .and_then(|file| file.set_len(len)) - .map_err(|error| { - SidecarError::Io(format!( - "failed to mirror guest truncate for {} into shadow root: {error}", - normalize_path(guest_path) - )) - }) -} - -fn remove_guest_shadow_path(vm: &mut VmState, guest_path: &str) -> Result<(), SidecarError> { - let guest_path = normalize_path(guest_path); - let shadow_path = shadow_host_path_for_guest(&vm.cwd, &guest_path); - remove_shadow_path_if_exists(&shadow_path, &guest_path) -} - -fn rename_guest_shadow_path( - vm: &mut VmState, - from_path: &str, - to_path: &str, -) -> Result<(), SidecarError> { - let from_path = normalize_path(from_path); - let to_path = normalize_path(to_path); - let from_shadow_path = shadow_host_path_for_guest(&vm.cwd, &from_path); - let to_shadow_path = shadow_host_path_for_guest(&vm.cwd, &to_path); - - if !from_shadow_path.exists() { - remove_shadow_path_if_exists(&to_shadow_path, &to_path)?; - return Ok(()); - } - - if let Some(parent) = to_shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!( - "failed to create shadow parent for rename {} -> {}: {error}", - from_path, to_path - )) - })?; - } - - remove_shadow_path_if_exists(&to_shadow_path, &to_path)?; - fs::rename(&from_shadow_path, &to_shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to mirror guest rename {} -> {} into shadow root: {error}", - from_path, to_path - )) - })?; - - Ok(()) -} - -fn remove_shadow_path_if_exists(shadow_path: &Path, guest_path: &str) -> Result<(), SidecarError> { - match fs::symlink_metadata(shadow_path) { - Ok(metadata) => { - if metadata.is_dir() && !metadata.file_type().is_symlink() { - fs::remove_dir_all(shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to remove shadow directory for {}: {error}", - guest_path - )) - })?; - } else { - fs::remove_file(shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to remove shadow path for {}: {error}", - guest_path - )) - })?; - } - Ok(()) - } - Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()), - Err(error) => Err(SidecarError::Io(format!( - "failed to inspect shadow path for {}: {error}", - guest_path - ))), - } -} - -fn sync_active_shadow_path_to_kernel( - vm: &mut VmState, - guest_path: &str, -) -> Result<(), SidecarError> { - sync_active_process_host_writes_to_kernel(vm)?; - let guest_path = normalize_path(guest_path); - if is_protected_agentos_shadow_sync_path(&guest_path) { - return Ok(()); - } - let mut host_paths = active_process_shadow_host_paths_for_guest(vm, &guest_path); - if host_paths.is_empty() && !vm.kernel.exists(&guest_path).unwrap_or(false) { - host_paths.push(shadow_host_path_for_guest(&vm.cwd, &guest_path)); - } - - for host_path in host_paths { - let metadata = match fs::symlink_metadata(&host_path) { - Ok(metadata) => metadata, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => continue, - Err(error) => { - return Err(SidecarError::Io(format!( - "failed to stat host shadow path {}: {error}", - host_path.display() - ))); - } - }; - - if metadata.file_type().is_symlink() { - sync_host_symlink_to_kernel(vm, &guest_path, &host_path)?; - return Ok(()); - } - - if metadata.is_dir() { - sync_host_directory_to_kernel(vm, &guest_path, &metadata)?; - return Ok(()); - } - - if metadata.is_file() { - sync_host_file_to_kernel(vm, &guest_path, &host_path, &metadata)?; - return Ok(()); - } - } - - Ok(()) -} - -fn active_process_shadow_host_paths_for_guest(vm: &VmState, guest_path: &str) -> Vec { - let mut candidates = Vec::new(); - let mut seen = BTreeSet::new(); - - for process in vm.active_processes.values() { - if let Some(host_path) = resolve_process_guest_path_to_host(process, guest_path) { - push_unique_host_path(&mut candidates, &mut seen, host_path); - } - } - - candidates -} - -fn push_unique_host_path( - candidates: &mut Vec, - seen: &mut BTreeSet, - host_path: PathBuf, -) { - if seen.insert(host_path.clone()) { - candidates.push(host_path); - } -} - -fn shadow_host_path_for_guest(shadow_root: &Path, guest_path: &str) -> PathBuf { - if guest_path == "/" { - shadow_root.to_path_buf() - } else { - shadow_root.join(guest_path.trim_start_matches('/')) - } -} - -fn shadow_symlink_target_for_guest(shadow_root: &Path, guest_path: &str, target: &str) -> PathBuf { - if !target.starts_with('/') { - return PathBuf::from(target); - } - - let link_shadow_path = shadow_host_path_for_guest(shadow_root, guest_path); - let link_parent = link_shadow_path.parent().unwrap_or(shadow_root); - let target_shadow_path = shadow_host_path_for_guest(shadow_root, target); - relative_path_from(link_parent, &target_shadow_path) -} - -fn relative_path_from(base_dir: &Path, target: &Path) -> PathBuf { - let base_components: Vec<_> = base_dir.components().collect(); - let target_components: Vec<_> = target.components().collect(); - - let mut shared_prefix = 0; - while shared_prefix < base_components.len() - && shared_prefix < target_components.len() - && base_components[shared_prefix] == target_components[shared_prefix] - { - shared_prefix += 1; - } - - let mut relative = PathBuf::new(); - for _ in shared_prefix..base_components.len() { - relative.push(".."); - } - for component in target_components.iter().skip(shared_prefix) { - relative.push(component.as_os_str()); - } - - if relative.as_os_str().is_empty() { - PathBuf::from(".") - } else { - relative - } -} - -fn resolve_process_guest_path_to_host( - process: &ActiveProcess, - guest_path: &str, -) -> Option { - let normalized_guest_path = if guest_path.starts_with('/') { - normalize_path(guest_path) - } else { - normalize_path(&format!( - "{}/{}", - process.guest_cwd.trim_end_matches('/'), - guest_path - )) - }; - if let Some(host_path) = - host_path_from_runtime_guest_mappings(&process.env, &normalized_guest_path) - { - return Some(host_path); - } - let normalized_guest_cwd = normalize_path(&process.guest_cwd); - let mut host_root = process.host_cwd.clone(); - for _ in normalized_guest_cwd - .trim_start_matches('/') - .split('/') - .filter(|segment| !segment.is_empty()) - { - host_root = host_root.parent()?.to_path_buf(); - } - Some(shadow_host_path_for_guest( - &host_root, - &normalized_guest_path, - )) -} - -fn sync_host_directory_to_kernel( - vm: &mut VmState, - guest_path: &str, - metadata: &fs::Metadata, -) -> Result<(), SidecarError> { - vm.kernel.mkdir(guest_path, true).map_err(kernel_error)?; - vm.kernel - .chmod(guest_path, metadata.permissions().mode() & 0o7777) - .map_err(kernel_error)?; - Ok(()) -} - -fn sync_host_file_to_kernel( - vm: &mut VmState, - guest_path: &str, - host_path: &Path, - metadata: &fs::Metadata, -) -> Result<(), SidecarError> { - ensure_guest_parent_dir(vm, guest_path)?; - let bytes = fs::read(host_path).map_err(|error| { - SidecarError::Io(format!( - "failed to read host shadow file {}: {error}", - host_path.display() - )) - })?; - vm.kernel - .write_file(guest_path, bytes) - .map_err(kernel_error)?; - vm.kernel - .chmod(guest_path, metadata.permissions().mode() & 0o7777) - .map_err(kernel_error)?; - Ok(()) -} - -fn sync_host_symlink_to_kernel( - vm: &mut VmState, - guest_path: &str, - host_path: &Path, -) -> Result<(), SidecarError> { - ensure_guest_parent_dir(vm, guest_path)?; - let target = fs::read_link(host_path).map_err(|error| { - SidecarError::Io(format!( - "failed to read host shadow symlink {}: {error}", - host_path.display() - )) - })?; - - let target = restore_guest_symlink_target_from_shadow(vm, guest_path, host_path, &target) - .unwrap_or_else(|| target.to_string_lossy().into_owned()); - - replace_guest_symlink(vm, guest_path, &target) -} - -fn restore_guest_symlink_target_from_shadow( - vm: &VmState, - guest_path: &str, - host_path: &Path, - shadow_target: &Path, -) -> Option { - if shadow_target.is_absolute() { - return None; - } - - let existing_target = vm.kernel.read_link(guest_path).ok()?; - if !existing_target.starts_with('/') { - return None; - } - - let host_parent = host_path.parent().unwrap_or(&vm.cwd); - let resolved_host_target = normalize_host_path(&host_parent.join(shadow_target)); - let normalized_shadow_root = normalize_host_path(&vm.cwd); - if resolved_host_target == normalized_shadow_root { - return Some(String::from("/")); - } - - resolved_host_target - .strip_prefix(&normalized_shadow_root) - .ok() - .map(|suffix| format!("/{}", suffix.to_string_lossy().trim_start_matches('/'))) -} - -fn replace_guest_symlink( - vm: &mut VmState, - guest_path: &str, - target: &str, -) -> Result<(), SidecarError> { - if vm.kernel.symlink(target, guest_path).is_ok() { - return Ok(()); - } - - if let Ok(existing_target) = vm.kernel.read_link(guest_path) { - if existing_target == target { - return Ok(()); - } - } - - let _ = vm.kernel.remove_file(guest_path); - let _ = vm.kernel.remove_dir(guest_path); - vm.kernel - .symlink(target, guest_path) - .map_err(kernel_error)?; - Ok(()) -} - -fn ensure_guest_parent_dir(vm: &mut VmState, guest_path: &str) -> Result<(), SidecarError> { - let Some(parent) = Path::new(guest_path).parent() else { - return Ok(()); - }; - let parent = parent.to_string_lossy(); - if parent.is_empty() || parent == "/" { - return Ok(()); - } - vm.kernel - .mkdir(&normalize_path(&parent), true) - .map_err(kernel_error)?; - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::{ - create_mapped_runtime_directory, create_mapped_runtime_root_directory, - mapped_runtime_relative_path, mapped_runtime_symlink_metadata, - materialize_mapped_host_path_from_kernel, open_mapped_runtime_parent_beneath, - read_mapped_runtime_link, rename_mapped_host_path, MappedRuntimeHostAccess, - MappedRuntimeHostPath, SidecarError, - }; - use crate::execution::javascript_sync_rpc_error_code; - use crate::state::{SidecarKernel, EXECUTION_DRIVER_NAME, JAVASCRIPT_COMMAND}; - use secure_exec_kernel::command_registry::CommandDriver; - use secure_exec_kernel::kernel::{KernelVmConfig, SpawnOptions}; - use secure_exec_kernel::mount_table::MountTable; - use secure_exec_kernel::permissions::Permissions; - use secure_exec_kernel::vfs::MemoryFileSystem; - use std::fs; - use std::os::unix::fs::PermissionsExt; - use std::path::PathBuf; - use std::time::{SystemTime, UNIX_EPOCH}; - - fn writable_mapping(guest_path: &str, host_root: &str) -> MappedRuntimeHostAccess { - let host_root = PathBuf::from(host_root); - MappedRuntimeHostAccess::Writable(MappedRuntimeHostPath { - guest_path: guest_path.to_owned(), - host_path: host_root.join("file.txt"), - host_root: host_root.clone(), - }) - } - - fn temp_dir(prefix: &str) -> PathBuf { - let path = std::env::temp_dir().join(format!( - "{prefix}-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_nanos() - )); - fs::create_dir_all(&path).expect("create temp dir"); - path - } - - fn test_kernel_with_process() -> (SidecarKernel, u32) { - let mut config = KernelVmConfig::new("vm-mapped-materialize"); - config.permissions = Permissions::allow_all(); - let mut kernel = SidecarKernel::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .register_driver(CommandDriver::new( - EXECUTION_DRIVER_NAME, - [JAVASCRIPT_COMMAND], - )) - .expect("register execution driver"); - let handle = kernel - .spawn_process( - JAVASCRIPT_COMMAND, - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel process"); - (kernel, handle.pid()) - } - - #[test] - fn rename_mapped_host_path_reports_exdev_for_cross_mount_guest_errno() { - for (source_host, destination_host) in [ - ( - Some(writable_mapping( - "/mapped/file.txt", - "/tmp/secure-exec-mapped-source", - )), - None, - ), - ( - None, - Some(writable_mapping( - "/mapped-dst/file.txt", - "/tmp/secure-exec-mapped-destination", - )), - ), - ] { - let error = rename_mapped_host_path( - "/mapped/file.txt", - source_host, - "/kernel/file.txt", - destination_host, - ) - .expect_err("cross-mount rename should fail with EXDEV"); - assert!( - matches!(error, SidecarError::Kernel(ref message) if message.starts_with("EXDEV:")), - "expected EXDEV kernel error, got {error:?}" - ); - assert_eq!(javascript_sync_rpc_error_code(&error), "EXDEV"); - } - } - - #[test] - fn mapped_runtime_parent_treats_single_segment_relative_paths_as_root_children() { - let host_root = std::env::temp_dir().join(format!( - "secure-exec-sidecar-fs-parent-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_nanos() - )); - fs::create_dir_all(&host_root).expect("create mapped host root"); - let mapped = MappedRuntimeHostPath { - guest_path: String::from("/workspace"), - host_root: host_root.clone(), - host_path: host_root.join("workspace"), - }; - - assert_eq!( - mapped_runtime_relative_path(&mapped).expect("relative path"), - PathBuf::from("workspace") - ); - - let parent = open_mapped_runtime_parent_beneath(&mapped, "test") - .expect("open mapped parent for root child"); - // `host_path` is the resolved fd's real path, which is canonical (on - // macOS the temp dir resolves through the `/private` firmlink), so - // compare against the canonicalized root rather than the raw value. - assert_eq!( - parent.host_path, - fs::canonicalize(&host_root).expect("canonicalize host root") - ); - assert_eq!(parent.child_name.to_string_lossy(), "workspace"); - } - - #[test] - fn mapped_runtime_root_lstat_uses_root_metadata_without_parent_basename() { - let host_root = std::env::temp_dir().join(format!( - "secure-exec-sidecar-fs-root-lstat-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_nanos() - )); - fs::create_dir_all(&host_root).expect("create mapped host root"); - let mapped = MappedRuntimeHostPath { - guest_path: String::from("/node_modules"), - host_root: host_root.clone(), - host_path: host_root.clone(), - }; - - let metadata = mapped_runtime_symlink_metadata(&mapped, "test").expect("lstat mapped root"); - assert!(metadata.is_dir(), "expected mapped root directory metadata"); - - fs::remove_dir_all(&host_root).expect("remove mapped host root"); - } - - #[test] - fn mapped_runtime_root_readlink_uses_root_path_without_parent_basename() { - let host_parent = std::env::temp_dir().join(format!( - "secure-exec-sidecar-fs-root-readlink-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_nanos() - )); - let host_target = host_parent.join("target"); - let host_link = host_parent.join("link"); - fs::create_dir_all(&host_target).expect("create mapped host target"); - std::os::unix::fs::symlink(&host_target, &host_link).expect("create mapped host link"); - let mapped = MappedRuntimeHostPath { - guest_path: String::from("/"), - host_root: host_link.clone(), - host_path: host_link, - }; - - let target = read_mapped_runtime_link(&mapped, "/", "test").expect("read mapped root link"); - assert_eq!(target, host_target); - - fs::remove_dir_all(&host_parent).expect("remove mapped host parent"); - } - - #[test] - fn recursive_mapped_directory_create_accepts_existing_directory() { - let host_root = std::env::temp_dir().join(format!( - "secure-exec-sidecar-fs-existing-dir-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_nanos() - )); - let existing_dir = host_root.join("workspace"); - fs::create_dir_all(&existing_dir).expect("create existing mapped directory"); - let mapped = MappedRuntimeHostPath { - guest_path: String::from("/workspace"), - host_root: host_root.clone(), - host_path: existing_dir, - }; - - let parent = open_mapped_runtime_parent_beneath(&mapped, "test") - .expect("open mapped parent for root child"); - create_mapped_runtime_directory(&parent, "/workspace", true) - .expect("recursive mkdir should accept an existing directory"); - let non_recursive_error = create_mapped_runtime_directory(&parent, "/workspace", false) - .expect_err("non-recursive mkdir should keep EEXIST behavior"); - assert!( - matches!(non_recursive_error, SidecarError::Io(ref message) if message.contains("File exists")), - "expected File exists error, got {non_recursive_error:?}" - ); - - fs::remove_dir_all(&host_root).expect("remove mapped host root"); - } - - #[test] - fn recursive_mapped_root_directory_create_accepts_existing_directory() { - let host_root = std::env::temp_dir().join(format!( - "secure-exec-sidecar-fs-existing-root-dir-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_nanos() - )); - fs::create_dir_all(&host_root).expect("create mapped host root"); - let mapped = MappedRuntimeHostPath { - guest_path: String::from("/"), - host_root: host_root.clone(), - host_path: host_root.clone(), - }; - - create_mapped_runtime_root_directory(&mapped, true) - .expect("recursive root mkdir should accept an existing directory"); - let non_recursive_error = create_mapped_runtime_root_directory(&mapped, false) - .expect_err("non-recursive root mkdir should keep EEXIST behavior"); - assert!( - matches!(non_recursive_error, SidecarError::Io(ref message) if message.contains("File exists")), - "expected File exists error, got {non_recursive_error:?}" - ); - - fs::remove_dir_all(&host_root).expect("remove mapped host root"); - } - - #[test] - fn materialize_mapped_host_path_does_not_follow_symlinked_parents() { - let host_root = temp_dir("secure-exec-sidecar-fs-materialize-root"); - let outside = temp_dir("secure-exec-sidecar-fs-materialize-outside"); - std::os::unix::fs::symlink(&outside, host_root.join("link")) - .expect("create escape symlink"); - - let (mut kernel, pid) = test_kernel_with_process(); - kernel - .write_file_for_process( - EXECUTION_DRIVER_NAME, - pid, - "/workspace/link/out.txt", - b"secret".to_vec(), - Some(0o644), - ) - .expect("seed guest file"); - let mapped = MappedRuntimeHostPath { - guest_path: String::from("/workspace/link/out.txt"), - host_root: host_root.clone(), - host_path: host_root.join("link/out.txt"), - }; - - materialize_mapped_host_path_from_kernel( - &mut kernel, - pid, - "/workspace/link/out.txt", - &mapped, - ) - .expect_err("symlinked parent must not be followed during materialization"); - - assert!( - !outside.join("out.txt").exists(), - "materialization wrote through a symlinked mapped parent" - ); - - fs::remove_dir_all(&host_root).expect("remove mapped host root"); - fs::remove_dir_all(&outside).expect("remove outside dir"); - } - - #[test] - fn materialize_mapped_host_path_writes_regular_files_beneath_root() { - let host_root = temp_dir("secure-exec-sidecar-fs-materialize-file"); - let (mut kernel, pid) = test_kernel_with_process(); - kernel - .write_file_for_process( - EXECUTION_DRIVER_NAME, - pid, - "/workspace/out.txt", - b"secret".to_vec(), - Some(0o640), - ) - .expect("seed guest file"); - let mapped = MappedRuntimeHostPath { - guest_path: String::from("/workspace/out.txt"), - host_root: host_root.clone(), - host_path: host_root.join("out.txt"), - }; - - materialize_mapped_host_path_from_kernel(&mut kernel, pid, "/workspace/out.txt", &mapped) - .expect("materialize regular mapped file"); - - let host_path = host_root.join("out.txt"); - assert_eq!( - fs::read(&host_path).expect("read materialized file"), - b"secret" - ); - assert_eq!( - fs::metadata(&host_path) - .expect("materialized metadata") - .permissions() - .mode() - & 0o777, - 0o640 - ); - - fs::remove_dir_all(&host_root).expect("remove mapped host root"); - } - - // Companion to the execution-crate `faithful_pnpm_symlink_layout_*` host - // test, but resolving through the *kernel VFS* via a read-only `host_dir` - // mount at `/root/node_modules` — the real VM path. A faithful pnpm tree - // (every package in its own `.pnpm/@/node_modules/` entry, - // dependencies wired by symlink) must resolve purely by the standard - // ancestor walk + realpath, with NO `.pnpm` store scanning, and must pick - // the version the symlink points at — not an alphabetically-earlier decoy. - #[test] - fn faithful_pnpm_symlink_layout_resolves_through_kernel_vfs() { - use super::{KernelModuleFsReader, ModuleResolveMode}; - use secure_exec_execution::{LocalModuleResolutionCache, ModuleResolver}; - use secure_exec_kernel::mount_table::{MountOptions, MountedVirtualFileSystem}; - use std::os::unix::fs::symlink; - - let node_modules = temp_dir("pnpm-vfs-node-modules").join("node_modules"); - let write = |relative: &str, contents: &str| { - let path = node_modules.join(relative); - fs::create_dir_all(path.parent().expect("parent")).expect("create dirs"); - fs::write(path, contents).expect("write fixture"); - }; - // pnpm always writes *relative* symlinks; the VFS mount follows them - // with RESOLVE_BENEATH (absolute targets are treated as escaping, which - // is also why pnpm never uses them). `relative_target` is the target - // expressed relative to the link's own directory. - let link = |relative_target: &str, link_relative: &str| { - let link_path = node_modules.join(link_relative); - fs::create_dir_all(link_path.parent().expect("link parent")).expect("create dirs"); - symlink(relative_target, link_path).expect("create symlink"); - }; - - // consumer@1.0.0 in its store entry; imports `dep`. - write( - ".pnpm/consumer@1.0.0/node_modules/consumer/index.mjs", - "import { wanted } from 'dep';\nexport default wanted;", - ); - write( - ".pnpm/consumer@1.0.0/node_modules/consumer/package.json", - r#"{ "version": "1.0.0", "type": "module", "exports": { ".": "./index.mjs" } }"#, - ); - // dep@2.0.0 — the correct version — in its own store entry. - write( - ".pnpm/dep@2.0.0/node_modules/dep/index.mjs", - "export const wanted = 2;", - ); - write( - ".pnpm/dep@2.0.0/node_modules/dep/package.json", - r#"{ "version": "2.0.0", "type": "module", "exports": { ".": "./index.mjs" } }"#, - ); - // Decoy: an alphabetically-earlier store entry holding an incompatible dep@1. - write( - ".pnpm/aaa-other@1.0.0/node_modules/dep/index.js", - "module.exports = 1;", - ); - write( - ".pnpm/aaa-other@1.0.0/node_modules/dep/package.json", - r#"{ "version": "1.0.0", "main": "index.js" }"#, - ); - // pnpm's sibling symlink: consumer's `dep` -> dep@2.0.0's store entry, - // expressed relative to `.pnpm/consumer@1.0.0/node_modules/`. - link( - "../../dep@2.0.0/node_modules/dep", - ".pnpm/consumer@1.0.0/node_modules/dep", - ); - // Top-level symlink: node_modules/consumer -> consumer's store entry, - // expressed relative to `node_modules/`. - link(".pnpm/consumer@1.0.0/node_modules/consumer", "consumer"); - - // Mount the tree read-only at /root/node_modules, exactly like the live VM. - let mut config = KernelVmConfig::new("vm-pnpm-vfs"); - config.permissions = Permissions::allow_all(); - let mut kernel = SidecarKernel::new(MountTable::new(MemoryFileSystem::new()), config); - let host_dir = crate::plugins::host_dir::HostDirFilesystem::new(&node_modules) - .expect("create host_dir over node_modules"); - kernel - .mount_boxed_filesystem( - "/root/node_modules", - Box::new(MountedVirtualFileSystem::new(host_dir)), - MountOptions::new("host_dir").read_only(true), - ) - .expect("mount node_modules read-only"); - - let mut cache = LocalModuleResolutionCache::default(); - let mut resolver = ModuleResolver::new( - KernelModuleFsReader { - kernel: &mut kernel, - }, - &mut cache, - ); - - // Importer is the top-level symlink path. The ancestor walk finds `dep` - // via pnpm's sibling symlink in consumer's store dir (pointing at - // dep@2.0.0) — no `.pnpm` scan. Resolution reads entirely through the VFS. - let resolved = resolver.resolve_module( - "dep", - "/root/node_modules/consumer/index.mjs", - ModuleResolveMode::Import, - ); - assert_eq!( - resolved.as_deref(), - Some("/root/node_modules/.pnpm/consumer@1.0.0/node_modules/dep/index.mjs"), - "must resolve dep@2.0.0 via the sibling symlink, not the aaa-other decoy", - ); - - // And the resolved source loads through the VFS too. - let source = resolver - .load_file("/root/node_modules/.pnpm/consumer@1.0.0/node_modules/dep/index.mjs") - .expect("load resolved dep source via kernel VFS"); - assert_eq!(source, "export const wanted = 2;"); - - fs::remove_dir_all(node_modules.parent().expect("temp parent")).expect("remove temp tree"); - } - - // Companion to the kernel-VFS test above, but resolving through the - // `HostDirModuleReader` — the bridge-thread reader the live VM uses so module - // resolution runs concurrently with the service loop instead of serializing - // behind it. It reads the SAME read-only `host_dir` mount (anchored openat2, - // escaping-symlink refusal) and must resolve the identical pnpm layout to the - // identical guest path, with no `.pnpm` scanning and the symlink-pointed - // version winning over the decoy. - #[test] - fn faithful_pnpm_symlink_layout_resolves_through_host_dir_module_reader() { - use crate::plugins::host_dir::HostDirModuleReader; - use secure_exec_execution::{ - LocalModuleResolutionCache, ModuleResolveMode, ModuleResolver, - }; - use std::os::unix::fs::symlink; - - let node_modules = temp_dir("pnpm-reader-node-modules").join("node_modules"); - let write = |relative: &str, contents: &str| { - let path = node_modules.join(relative); - fs::create_dir_all(path.parent().expect("parent")).expect("create dirs"); - fs::write(path, contents).expect("write fixture"); - }; - let link = |relative_target: &str, link_relative: &str| { - let link_path = node_modules.join(link_relative); - fs::create_dir_all(link_path.parent().expect("link parent")).expect("create dirs"); - symlink(relative_target, link_path).expect("create symlink"); - }; - - write( - ".pnpm/consumer@1.0.0/node_modules/consumer/index.mjs", - "import { wanted } from 'dep';\nexport default wanted;", - ); - write( - ".pnpm/consumer@1.0.0/node_modules/consumer/package.json", - r#"{ "version": "1.0.0", "type": "module", "exports": { ".": "./index.mjs" } }"#, - ); - write( - ".pnpm/dep@2.0.0/node_modules/dep/index.mjs", - "export const wanted = 2;", - ); - write( - ".pnpm/dep@2.0.0/node_modules/dep/package.json", - r#"{ "version": "2.0.0", "type": "module", "exports": { ".": "./index.mjs" } }"#, - ); - write( - ".pnpm/aaa-other@1.0.0/node_modules/dep/index.js", - "module.exports = 1;", - ); - write( - ".pnpm/aaa-other@1.0.0/node_modules/dep/package.json", - r#"{ "version": "1.0.0", "main": "index.js" }"#, - ); - link( - "../../dep@2.0.0/node_modules/dep", - ".pnpm/consumer@1.0.0/node_modules/dep", - ); - link(".pnpm/consumer@1.0.0/node_modules/consumer", "consumer"); - - // The reader is anchored at the node_modules host root, mounted at the - // guest convention `/root/node_modules` — exactly what build_module_reader - // derives for the live VM. - let reader = HostDirModuleReader::from_mounts([("/root/node_modules", &node_modules)]) - .expect("build host_dir module reader"); - let mut cache = LocalModuleResolutionCache::default(); - let mut resolver = ModuleResolver::new(reader, &mut cache); - - let resolved = resolver.resolve_module( - "dep", - "/root/node_modules/consumer/index.mjs", - ModuleResolveMode::Import, - ); - assert_eq!( - resolved.as_deref(), - Some("/root/node_modules/.pnpm/consumer@1.0.0/node_modules/dep/index.mjs"), - "reader must resolve dep@2.0.0 via the sibling symlink, not the aaa-other decoy", - ); - - let source = resolver - .load_file("/root/node_modules/.pnpm/consumer@1.0.0/node_modules/dep/index.mjs") - .expect("load resolved dep source via host_dir reader"); - assert_eq!(source, "export const wanted = 2;"); - - // Escaping-symlink refusal is preserved by the mount: a link pointing - // outside the node_modules root must not read through it. - let outside = temp_dir("pnpm-reader-outside"); - fs::create_dir_all(&outside).expect("create outside dir"); - fs::write(outside.join("escaped.js"), "module.exports = 'escaped';") - .expect("write escape target"); - symlink(&outside, node_modules.join("escape-link")).expect("create escaping symlink"); - let escape_reader = - HostDirModuleReader::from_mounts([("/root/node_modules", &node_modules)]) - .expect("build host_dir module reader"); - let mut escape_cache = LocalModuleResolutionCache::default(); - let mut escape_resolver = ModuleResolver::new(escape_reader, &mut escape_cache); - let escaped = escape_resolver.load_file("/root/node_modules/escape-link/escaped.js"); - assert!( - escaped.is_none(), - "escaping symlink must not read through the mount", - ); - - fs::remove_dir_all(node_modules.parent().expect("temp parent")).expect("remove temp tree"); - fs::remove_dir_all(&outside).ok(); - } - - // Phase 0 perf gate: compare cold-start module resolution cost of the new - // kernel-VFS path against the legacy host-direct path over a representative - // node_modules closure. Run with: - // cargo test -p secure-exec-sidecar --lib module_resolution_vfs_vs_host_cold_start_perf -- --nocapture --ignored - #[test] - #[ignore = "perf microbenchmark; run explicitly with --ignored --nocapture"] - fn module_resolution_vfs_vs_host_cold_start_perf() { - use super::KernelModuleFsReader; - use secure_exec_execution::javascript::ModuleResolutionTestHarness; - use secure_exec_execution::{ - LocalModuleResolutionCache, ModuleResolveMode, ModuleResolver, - }; - use secure_exec_kernel::mount_table::{MountOptions, MountedVirtualFileSystem}; - use std::time::Instant; - - // Build a representative closure: a root entry that imports N packages, - // each a scoped/unscoped package with its own package.json + nested dep. - const PACKAGES: usize = 40; - let root = temp_dir("perf-closure"); - let write = |relative: &str, contents: &str| { - let path = root.join(relative); - fs::create_dir_all(path.parent().expect("parent")).expect("create dirs"); - fs::write(path, contents).expect("write"); - }; - - let mut imports = Vec::new(); - for i in 0..PACKAGES { - let pkg = format!("pkg{i}"); - write( - &format!("node_modules/{pkg}/package.json"), - &format!(r#"{{ "name": "{pkg}", "version": "1.0.0", "main": "lib/index.js" }}"#), - ); - write( - &format!("node_modules/{pkg}/lib/index.js"), - "module.exports = require('./helper');", - ); - write( - &format!("node_modules/{pkg}/lib/helper.js"), - "module.exports = 1;", - ); - // a nested transitive dependency - write( - &format!("node_modules/{pkg}/node_modules/dep{i}/package.json"), - &format!(r#"{{ "name": "dep{i}", "version": "1.0.0" }}"#), - ); - write( - &format!("node_modules/{pkg}/node_modules/dep{i}/index.js"), - "module.exports = 2;", - ); - imports.push(pkg); - } - write("index.js", "// root entry\n"); - - let from = "/root/index.js"; - let iterations = 50usize; - - // --- Host-direct path (legacy) --- - let host_start = Instant::now(); - for _ in 0..iterations { - let mut harness = ModuleResolutionTestHarness::new(&root); - for pkg in &imports { - let _ = harness.resolve_require(pkg, from); - } - } - let host_elapsed = host_start.elapsed(); - - // --- Kernel-VFS path (new) --- - // Mount the whole closure root so /root resolves through the VFS. - let build_kernel = || { - let mut config = KernelVmConfig::new("vm-perf"); - config.permissions = Permissions::allow_all(); - let mut kernel = SidecarKernel::new(MountTable::new(MemoryFileSystem::new()), config); - let host_dir = crate::plugins::host_dir::HostDirFilesystem::new(&root) - .expect("host_dir over closure root"); - kernel - .mount_boxed_filesystem( - "/root", - Box::new(MountedVirtualFileSystem::new(host_dir)), - MountOptions::new("host_dir").read_only(true), - ) - .expect("mount /root"); - kernel - }; - - let vfs_start = Instant::now(); - for _ in 0..iterations { - let mut kernel = build_kernel(); - let mut cache = LocalModuleResolutionCache::default(); - let mut resolver = ModuleResolver::new( - KernelModuleFsReader { - kernel: &mut kernel, - }, - &mut cache, - ); - for pkg in &imports { - let _ = resolver.resolve_module(pkg, from, ModuleResolveMode::Require); - } - } - let vfs_elapsed = vfs_start.elapsed(); - - // Exclude kernel-build cost from the VFS resolution figure by measuring - // it separately, so the comparison is resolution-vs-resolution. - let build_start = Instant::now(); - for _ in 0..iterations { - let _kernel = build_kernel(); - } - let build_elapsed = build_start.elapsed(); - let vfs_resolve_only = vfs_elapsed.saturating_sub(build_elapsed); - - let per_closure_host = host_elapsed / iterations as u32; - let per_closure_vfs = vfs_elapsed / iterations as u32; - let per_closure_vfs_resolve = vfs_resolve_only / iterations as u32; - - eprintln!("\n=== Phase 0 module-resolution cold-start perf ==="); - eprintln!("closure: {PACKAGES} packages, {iterations} cold iterations"); - eprintln!("host-direct : {host_elapsed:?} total | {per_closure_host:?} / closure"); - eprintln!( - "kernel-VFS : {vfs_elapsed:?} total | {per_closure_vfs:?} / closure (incl. mount build)" - ); - eprintln!( - "kernel-VFS : {vfs_resolve_only:?} total | {per_closure_vfs_resolve:?} / closure (resolution only)" - ); - eprintln!( - "kernel build: {build_elapsed:?} total | {:?} / closure", - build_elapsed / iterations as u32 - ); - let ratio = vfs_resolve_only.as_secs_f64() / host_elapsed.as_secs_f64().max(1e-9); - eprintln!("ratio (vfs-resolve / host): {ratio:.2}x"); - - fs::remove_dir_all(&root).expect("remove perf tree"); - } -} diff --git a/crates/sidecar/src/json_rpc.rs b/crates/sidecar/src/json_rpc.rs deleted file mode 100644 index 2da9bfaf5..000000000 --- a/crates/sidecar/src/json_rpc.rs +++ /dev/null @@ -1,448 +0,0 @@ -use serde::de::Error as _; -use serde::ser::Error as _; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serde_json::{Map, Value}; -use std::fmt; - -const JSON_RPC_VERSION: &str = "2.0"; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -#[serde(untagged)] -pub enum JsonRpcId { - Number(i64), - String(String), - Null, -} - -impl std::fmt::Display for JsonRpcId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Number(value) => write!(f, "{value}"), - Self::String(value) => f.write_str(value), - Self::Null => f.write_str("null"), - } - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct JsonRpcError { - pub code: i64, - pub message: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct JsonRpcRequest { - #[serde(default = "jsonrpc_version")] - pub jsonrpc: String, - pub id: JsonRpcId, - pub method: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub params: Option, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct JsonRpcResponse { - pub jsonrpc: String, - pub id: JsonRpcId, - result: Option, - error: Option, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct JsonRpcNotification { - #[serde(default = "jsonrpc_version")] - pub jsonrpc: String, - pub method: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub params: Option, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum JsonRpcMessage { - Request(JsonRpcRequest), - Response(JsonRpcResponse), - Notification(JsonRpcNotification), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum JsonRpcResponseShapeError { - BothResultAndError, - MissingResultAndError, -} - -impl fmt::Display for JsonRpcResponseShapeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::BothResultAndError => { - f.write_str("JSON-RPC response cannot include both result and error") - } - Self::MissingResultAndError => { - f.write_str("JSON-RPC response must include exactly one of result or error") - } - } - } -} - -impl std::error::Error for JsonRpcResponseShapeError {} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum JsonRpcParseErrorKind { - ParseError, - InvalidRequest, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct JsonRpcParseError { - kind: JsonRpcParseErrorKind, - id: JsonRpcId, - message: String, -} - -impl JsonRpcParseError { - fn parse_error(error: serde_json::Error) -> Self { - Self { - kind: JsonRpcParseErrorKind::ParseError, - id: JsonRpcId::Null, - message: format!("Parse error: {error}"), - } - } - - fn invalid_request(message: impl Into, id: Option) -> Self { - Self { - kind: JsonRpcParseErrorKind::InvalidRequest, - id: id.unwrap_or(JsonRpcId::Null), - message: message.into(), - } - } - - pub fn code(&self) -> i64 { - match self.kind { - JsonRpcParseErrorKind::ParseError => -32700, - JsonRpcParseErrorKind::InvalidRequest => -32600, - } - } - - pub fn id(&self) -> &JsonRpcId { - &self.id - } - - pub fn message(&self) -> &str { - &self.message - } - - pub fn to_response(&self) -> JsonRpcResponse { - JsonRpcResponse::error_response( - self.id.clone(), - JsonRpcError { - code: self.code(), - message: self.message.clone(), - data: None, - }, - ) - } -} - -impl fmt::Display for JsonRpcParseError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} (code {})", self.message, self.code()) - } -} - -impl std::error::Error for JsonRpcParseError {} - -impl From for JsonRpcMessage { - fn from(value: JsonRpcRequest) -> Self { - Self::Request(value) - } -} - -impl From for JsonRpcMessage { - fn from(value: JsonRpcResponse) -> Self { - Self::Response(value) - } -} - -impl From for JsonRpcMessage { - fn from(value: JsonRpcNotification) -> Self { - Self::Notification(value) - } -} - -impl JsonRpcResponse { - pub fn success(id: JsonRpcId, result: Value) -> Self { - Self { - jsonrpc: jsonrpc_version(), - id, - result: Some(result), - error: None, - } - } - - pub fn error_response(id: JsonRpcId, error: JsonRpcError) -> Self { - Self { - jsonrpc: jsonrpc_version(), - id, - result: None, - error: Some(error), - } - } - - pub fn try_from_parts( - jsonrpc: String, - id: JsonRpcId, - result: Option, - error: Option, - ) -> Result { - match (result, error) { - (Some(result), None) => Ok(Self { - jsonrpc, - id, - result: Some(result), - error: None, - }), - (None, Some(error)) => Ok(Self { - jsonrpc, - id, - result: None, - error: Some(error), - }), - (Some(_), Some(_)) => Err(JsonRpcResponseShapeError::BothResultAndError), - (None, None) => Err(JsonRpcResponseShapeError::MissingResultAndError), - } - } - - pub fn result(&self) -> Option<&Value> { - self.result.as_ref() - } - - pub fn error(&self) -> Option<&JsonRpcError> { - self.error.as_ref() - } - - pub fn into_result(self) -> Option { - self.result - } - - pub fn into_error(self) -> Option { - self.error - } - - pub fn is_error(&self) -> bool { - self.error.is_some() - } -} - -pub fn serialize_message(message: &JsonRpcMessage) -> Result { - let body = match message { - JsonRpcMessage::Request(value) => serde_json::to_string(value)?, - JsonRpcMessage::Response(value) => serde_json::to_string(value)?, - JsonRpcMessage::Notification(value) => serde_json::to_string(value)?, - }; - Ok(format!("{body}\n")) -} - -pub fn deserialize_message(line: &str) -> Result { - let value: Value = serde_json::from_str(line).map_err(JsonRpcParseError::parse_error)?; - let object = value.as_object().ok_or_else(|| { - JsonRpcParseError::invalid_request( - "Invalid Request: JSON-RPC payload must be an object", - None, - ) - })?; - parse_message_object(object) -} - -pub fn is_response(message: &JsonRpcMessage) -> bool { - matches!(message, JsonRpcMessage::Response(_)) -} - -pub fn is_request(message: &JsonRpcMessage) -> bool { - matches!(message, JsonRpcMessage::Request(_)) -} - -fn jsonrpc_version() -> String { - String::from(JSON_RPC_VERSION) -} - -impl Serialize for JsonRpcResponse { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut map = Map::new(); - map.insert(String::from("jsonrpc"), Value::String(self.jsonrpc.clone())); - map.insert( - String::from("id"), - serde_json::to_value(&self.id).map_err(S::Error::custom)?, - ); - if let Some(result) = &self.result { - map.insert(String::from("result"), result.clone()); - } else if let Some(error) = &self.error { - map.insert( - String::from("error"), - serde_json::to_value(error).map_err(S::Error::custom)?, - ); - } - map.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for JsonRpcResponse { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - struct RawJsonRpcResponse { - #[serde(default = "jsonrpc_version")] - jsonrpc: String, - id: JsonRpcId, - result: Option, - error: Option, - } - - let raw = RawJsonRpcResponse::deserialize(deserializer)?; - JsonRpcResponse::try_from_parts(raw.jsonrpc, raw.id, raw.result, raw.error) - .map_err(D::Error::custom) - } -} - -fn parse_message_object(object: &Map) -> Result { - validate_jsonrpc_version(object)?; - - if object.contains_key("method") { - validate_request_response_fields_do_not_mix(object)?; - return parse_request_or_notification(object); - } - - if object.contains_key("result") || object.contains_key("error") || object.contains_key("id") { - return parse_response(object); - } - - Err(JsonRpcParseError::invalid_request( - "Invalid Request: missing method/result/error", - parsed_id(object.get("id")), - )) -} - -fn validate_request_response_fields_do_not_mix( - object: &Map, -) -> Result<(), JsonRpcParseError> { - if object.contains_key("result") || object.contains_key("error") { - return Err(JsonRpcParseError::invalid_request( - "Invalid Request: method cannot be combined with result or error", - parsed_id(object.get("id")), - )); - } - - Ok(()) -} - -fn validate_jsonrpc_version(object: &Map) -> Result<(), JsonRpcParseError> { - let id = parsed_id(object.get("id")); - match object.get("jsonrpc").and_then(Value::as_str) { - Some(JSON_RPC_VERSION) => Ok(()), - Some(_) => Err(JsonRpcParseError::invalid_request( - "Invalid Request: jsonrpc must be \"2.0\"", - id, - )), - None => Err(JsonRpcParseError::invalid_request( - "Invalid Request: missing jsonrpc version", - id, - )), - } -} - -fn parse_request_or_notification( - object: &Map, -) -> Result { - let method = object - .get("method") - .and_then(Value::as_str) - .ok_or_else(|| { - JsonRpcParseError::invalid_request( - "Invalid Request: method must be a string", - parsed_id(object.get("id")), - ) - })?; - validate_params_shape(object)?; - - let params = object.get("params").cloned(); - if let Some(id) = parsed_required_id(object)? { - return Ok(JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: jsonrpc_version(), - id, - method: String::from(method), - params, - })); - } - - Ok(JsonRpcMessage::Notification(JsonRpcNotification { - jsonrpc: jsonrpc_version(), - method: String::from(method), - params, - })) -} - -fn parse_response(object: &Map) -> Result { - let id = parsed_required_id(object)?.ok_or_else(|| { - JsonRpcParseError::invalid_request("Invalid Request: response is missing id", None) - })?; - let result = object.get("result").cloned(); - let error = match object.get("error") { - Some(value) => Some( - serde_json::from_value::(value.clone()).map_err(|error| { - JsonRpcParseError::invalid_request( - format!("Invalid Request: malformed error payload: {error}"), - Some(id.clone()), - ) - })?, - ), - None => None, - }; - - let response = JsonRpcResponse::try_from_parts(jsonrpc_version(), id.clone(), result, error) - .map_err(|error| { - JsonRpcParseError::invalid_request(format!("Invalid Request: {error}"), Some(id)) - })?; - Ok(JsonRpcMessage::Response(response)) -} - -fn validate_params_shape(object: &Map) -> Result<(), JsonRpcParseError> { - let Some(params) = object.get("params") else { - return Ok(()); - }; - if params.is_array() || params.is_object() { - return Ok(()); - } - - Err(JsonRpcParseError::invalid_request( - "Invalid Request: params must be an object or array", - parsed_id(object.get("id")), - )) -} - -fn parsed_required_id(value: &Map) -> Result, JsonRpcParseError> { - match value.get("id") { - Some(value) => parsed_id(Some(value)) - .ok_or_else(|| { - JsonRpcParseError::invalid_request( - "Invalid Request: id must be a string, number, or null", - None, - ) - }) - .map(Some), - None => Ok(None), - } -} - -fn parsed_id(value: Option<&Value>) -> Option { - match value { - Some(Value::String(value)) => Some(JsonRpcId::String(value.clone())), - Some(Value::Number(value)) => value.as_i64().map(JsonRpcId::Number), - Some(Value::Null) => Some(JsonRpcId::Null), - _ => None, - } -} diff --git a/crates/sidecar/src/lib.rs b/crates/sidecar/src/lib.rs index b058197a5..9789e1426 100644 --- a/crates/sidecar/src/lib.rs +++ b/crates/sidecar/src/lib.rs @@ -1,65 +1,3 @@ -#![forbid(unsafe_code)] +//! Compatibility shim for `agentos-native-sidecar`. -//! Native sidecar scaffold that composes the kernel and execution crates. - -pub(crate) mod bootstrap; -pub(crate) mod bridge; -// Pure-Rust AES cipher primitives (RustCrypto) replacing the OpenSSL `Crypter`. -pub(crate) mod crypto_cipher; -pub(crate) mod execution; -pub mod extension; -pub(crate) mod filesystem; -#[allow(dead_code)] -pub(crate) mod json_rpc; -pub mod limits; -#[cfg(target_os = "macos")] -pub(crate) mod macos_fs; -pub(crate) mod metadata; -pub mod package_projection; -pub(crate) mod plugins; -pub mod service; -pub(crate) mod state; -pub mod stdio; -pub(crate) mod tools; -pub(crate) mod vm; -pub use secure_exec_sidecar_protocol::{generated_protocol, protocol, wire}; - -pub use extension::{ - Extension, ExtensionContext, ExtensionFuture, ExtensionInterruptRequest, - ExtensionInterruptResponse, ExtensionResponse, -}; -pub use service::{DispatchResult, NativeSidecar, NativeSidecarConfig, SidecarError}; -pub use state::EventSinkTransport; -pub use state::SidecarRequestTransport; - -use wire::{DEFAULT_MAX_FRAME_BYTES, PROTOCOL_NAME, PROTOCOL_VERSION}; - -pub trait NativeSidecarBridge: secure_exec_bridge::HostBridge {} - -impl NativeSidecarBridge for T where T: secure_exec_bridge::HostBridge {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct SidecarScaffold { - pub package_name: &'static str, - pub binary_name: &'static str, - pub kernel_package: &'static str, - pub execution_package: &'static str, - pub protocol_name: &'static str, - pub protocol_version: u16, - pub max_frame_bytes: usize, -} - -pub fn scaffold() -> SidecarScaffold { - let kernel = secure_exec_kernel::scaffold(); - let execution = secure_exec_execution::scaffold(); - - SidecarScaffold { - package_name: env!("CARGO_PKG_NAME"), - binary_name: env!("CARGO_PKG_NAME"), - kernel_package: kernel.package_name, - execution_package: execution.package_name, - protocol_name: PROTOCOL_NAME, - protocol_version: PROTOCOL_VERSION, - max_frame_bytes: DEFAULT_MAX_FRAME_BYTES, - } -} +pub use agentos_native_sidecar::*; diff --git a/crates/sidecar/src/limits.rs b/crates/sidecar/src/limits.rs deleted file mode 100644 index 4de5b44e3..000000000 --- a/crates/sidecar/src/limits.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Native compatibility exports for shared VM-scoped runtime limits. - -pub use secure_exec_sidecar_core::limits::{ - validate_vm_limits, AcpLimits, HttpLimits, JsRuntimeLimits, PluginLimits, PythonLimits, - ToolLimits, VmLimits, WasmLimits, DEFAULT_ACP_MAX_READ_LINE_BYTES, - DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT, DEFAULT_JS_CAPTURED_OUTPUT_LIMIT_BYTES, - DEFAULT_JS_EVENT_PAYLOAD_LIMIT_BYTES, DEFAULT_JS_STDIN_BUFFER_LIMIT_BYTES, - DEFAULT_MAX_FETCH_RESPONSE_BYTES, DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS, - DEFAULT_PYTHON_MAX_OLD_SPACE_MB, DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES, - DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS, DEFAULT_TOOL_TIMEOUT_MS, DEFAULT_V8_HEAP_LIMIT_MB, - DEFAULT_V8_IPC_MAX_FRAME_BYTES, DEFAULT_WASM_CAPTURED_OUTPUT_LIMIT_BYTES, - DEFAULT_WASM_MAX_MODULE_FILE_BYTES, DEFAULT_WASM_SYNC_READ_LIMIT_BYTES, - MAX_PERSISTED_MANIFEST_BYTES, MAX_PERSISTED_MANIFEST_FILE_BYTES, MAX_REGISTERED_TOOLKITS, - MAX_REGISTERED_TOOLS_PER_VM, MAX_TOOLS_PER_TOOLKIT, MAX_TOOL_EXAMPLES_PER_TOOL, - MAX_TOOL_EXAMPLE_INPUT_BYTES, MAX_TOOL_SCHEMA_BYTES, MAX_TOOL_TIMEOUT_MS, -}; -use secure_exec_vm_config::VmLimitsConfig; - -use crate::state::SidecarError; - -pub fn vm_limits_from_config( - config: Option<&VmLimitsConfig>, - sidecar_max_frame_bytes: usize, -) -> Result { - secure_exec_sidecar_core::limits::vm_limits_from_config(config, sidecar_max_frame_bytes) - .map_err(|error| SidecarError::InvalidState(error.to_string())) -} diff --git a/crates/sidecar/src/macos_fs.rs b/crates/sidecar/src/macos_fs.rs deleted file mode 100644 index 90591f450..000000000 --- a/crates/sidecar/src/macos_fs.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! macOS host-mount confinement shims. -//! -//! The Linux host-mount filesystem confinement relies on three primitives that -//! do not exist on macOS: -//! * `openat2(RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS)` — atomic resolve-beneath -//! path resolution (the escape boundary for host-backed mounts), -//! * `O_PATH` — a metadata-only anchor fd, -//! * `/proc/self/fd/N` — re-deriving a path/handle from an fd. -//! -//! This module provides the macOS equivalents: -//! * [`resolve_beneath`] resolves a guest-supplied relative path strictly -//! beneath the mount root using `cap-std`, whose audited userspace walk -//! (fd-relative, per-hop, symlink- and `..`-refusing) reproduces the -//! escape guarantee `openat2(RESOLVE_BENEATH)` gives atomically on Linux. -//! * [`fd_real_path`] uses `fcntl(F_GETPATH)` in place of -//! `readlink("/proc/self/fd/N")` to recover an fd's real host path. -//! -//! `O_PATH` is mapped to a read-only anchor (`O_RDONLY`) at the call sites, and -//! `/proc/self/fd/N` to `/dev/fd/N` in `AnchoredFd::proc_path`. - -use cap_std::ambient_authority; -use cap_std::fs::{Dir, OpenOptions, OpenOptionsExt}; -use nix::errno::Errno; -use nix::fcntl::{fcntl, FcntlArg, OFlag}; -use nix::sys::stat::Mode; -use std::io; -use std::os::fd::{IntoRawFd, RawFd}; -use std::path::{Path, PathBuf}; - -/// Resolve `relative` strictly beneath `root` and open it, returning an owned -/// raw fd. macOS counterpart to -/// `openat2(root, relative, RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS)`. -/// -/// `cap-std` guarantees the resolution never escapes `root` (via `..`, an -/// absolute symlink, or a symlink whose target leaves the tree), refusing such -/// attempts with an errno-less `PermissionDenied` that [`io_to_errno`] maps to -/// `EXDEV` — matching how callers already treat `openat2`'s escape error. -/// -/// `O_PATH` anchors arrive here as `O_RDONLY` (macOS has no metadata-only open); -/// the resulting fd is still only used as an anchor / re-opened via `/dev/fd/N`. -pub(crate) fn resolve_beneath( - root: &Path, - relative: &Path, - flags: OFlag, - mode: Mode, -) -> Result { - let dir = Dir::open_ambient_dir(root, ambient_authority()).map_err(io_to_errno)?; - - // Directory handles: `open_dir` is cap-std's resolve-beneath `O_DIRECTORY` - // open and returns a `Dir` we can hand back as a raw fd. - if flags.contains(OFlag::O_DIRECTORY) { - let sub = dir.open_dir(relative).map_err(io_to_errno)?; - return Ok(sub.into_raw_fd()); - } - - let acc = flags & OFlag::O_ACCMODE; - let write = acc == OFlag::O_WRONLY || acc == OFlag::O_RDWR; - - let mut opts = OpenOptions::new(); - // A pure anchor (O_PATH mapped to O_RDONLY) and any read/RDWR open needs - // read; ensure we never request neither read nor write (cap-std rejects it). - opts.read(!write) - .write(write) - .create(flags.contains(OFlag::O_CREAT)) - .create_new(flags.contains(OFlag::O_EXCL)) - .truncate(flags.contains(OFlag::O_TRUNC)); - if acc == OFlag::O_RDWR { - opts.read(true); - } - if flags.contains(OFlag::O_APPEND) { - opts.append(true); - } - opts.mode(u32::from(mode.bits())); - // Preserve a caller's request not to follow the final component. cap-std - // refuses *escaping* symlinks regardless; this additionally refuses a - // non-escaping final symlink, matching O_NOFOLLOW semantics. - if flags.contains(OFlag::O_NOFOLLOW) { - opts.custom_flags(OFlag::O_NOFOLLOW.bits()); - } - - let file = dir.open_with(relative, &opts).map_err(io_to_errno)?; - Ok(file.into_raw_fd()) -} - -/// Real filesystem path of an open fd via `fcntl(F_GETPATH)` — the macOS -/// counterpart to `readlink("/proc/self/fd/N")`. Uses nix's safe wrapper so the -/// sidecar crate's `#![forbid(unsafe_code)]` holds. -pub(crate) fn fd_real_path(fd: RawFd) -> io::Result { - let mut path = PathBuf::new(); - fcntl(fd, FcntlArg::F_GETPATH(&mut path)) - .map_err(|errno| io::Error::from_raw_os_error(errno as i32))?; - Ok(path) -} - -/// Map a `cap-std` filesystem error to an `Errno`. A resolve-beneath escape is -/// reported by cap-std as an errno-less `PermissionDenied`; translate that to -/// `EXDEV` so callers reuse their existing "path escapes mount" handling. -fn io_to_errno(error: io::Error) -> Errno { - if let Some(raw) = error.raw_os_error() { - Errno::from_raw(raw) - } else if error.kind() == io::ErrorKind::PermissionDenied { - Errno::EXDEV - } else { - Errno::EIO - } -} diff --git a/crates/sidecar/src/main.rs b/crates/sidecar/src/main.rs deleted file mode 100644 index c95c73df3..000000000 --- a/crates/sidecar/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -fn main() { - // Default to WARN so near-limit / backpressure warnings actually surface - // (they were swallowed at ERROR-only); operators can tune via SECURE_EXEC_LOG - // (e.g. `error` to quiet, `debug` for queue snapshots). Logs MUST go to stderr: - // stdout is the framed wire-protocol channel, so logging there would corrupt it. - let level = std::env::var("SECURE_EXEC_LOG") - .ok() - .and_then(|value| value.parse::().ok()) - .unwrap_or(tracing::Level::WARN); - tracing_subscriber::fmt() - .with_writer(std::io::stderr) - .with_max_level(level) - .init(); - if let Err(error) = secure_exec_sidecar::stdio::run() { - tracing::error!(?error, "secure-exec-sidecar startup failed"); - std::process::exit(1); - } -} diff --git a/crates/sidecar/src/metadata/mod.rs b/crates/sidecar/src/metadata/mod.rs deleted file mode 100644 index 51548a90c..000000000 --- a/crates/sidecar/src/metadata/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::protocol::{ExtEnvelope, OwnershipScope, SidecarRequestPayload, SidecarResponsePayload}; -use crate::state::SharedSidecarRequestClient; -use crate::SidecarError; -use secure_exec_vfs::callback_store::CallbackMetadataClient; -use std::time::Duration; - -pub(crate) use secure_exec_vfs::CallbackMetadataStore; - -impl CallbackMetadataClient for SharedSidecarRequestClient { - type Ownership = OwnershipScope; - type Error = SidecarError; - - fn invoke_metadata_callback( - &self, - ownership: Self::Ownership, - namespace: &str, - payload: Vec, - timeout: Duration, - ) -> Result<(String, Vec), Self::Error> { - let payload = SidecarRequestPayload::Ext(ExtEnvelope { - namespace: namespace.to_owned(), - payload, - }); - match self.invoke(ownership, payload, timeout)? { - SidecarResponsePayload::ExtResult(envelope) => { - Ok((envelope.namespace, envelope.payload)) - } - other => Err(SidecarError::InvalidState(format!( - "unexpected vfs metadata callback response payload: {other:?}" - ))), - } - } -} diff --git a/crates/sidecar/src/package_projection.rs b/crates/sidecar/src/package_projection.rs deleted file mode 100644 index bd4dababe..000000000 --- a/crates/sidecar/src/package_projection.rs +++ /dev/null @@ -1,613 +0,0 @@ -//! agentOS package projection. -//! -//! Packages are mounted directly from their uncompressed `package.tar` files. -//! The tar already contains every member's bytes at known offsets, so the VFS -//! indexes headers once and returns mmap-backed byte ranges instead of -//! extracting a duplicate host tree. The projection also serves `bin/*`, -//! `current`, manpage aliases, and `provides.files` as virtual mounts; it never -//! writes a physical symlink farm. -//! -//! The projection is deliberately granular. Each package version is a tar leaf -//! at `/opt/agentos/pkgs//`, and each managed command/current -//! alias is its own root-symlink leaf. The containing dirs stay writable overlay -//! dirs so user-installed commands can coexist beside managed package entries. - -use std::collections::{HashMap, HashSet}; -use std::fs; -use std::path::{Path, PathBuf}; - -use crate::state::SidecarError; -use serde::Deserialize; -use vfs::posix::{normalize_path, TarFileSystem, VirtualFileSystem}; - -/// Root of the agentOS package tree inside the VM. -pub const OPT_AGENTOS_ROOT: &str = "/opt/agentos"; -/// The symlink farm on `$PATH`. -pub const OPT_AGENTOS_BIN: &str = "/opt/agentos/bin"; -const AGENT_SNAPSHOT_BUNDLE: &str = "dist/sdk-snapshot.js"; -pub const DEFAULT_PACKAGE_TAR_NAME: &str = "package.tar"; -pub const MAX_AGENTOS_PACKAGE_MOUNTS: usize = 4096; - -/// A package to project, derived from `agentos-package.json` in a package dir or tar. -#[derive(Debug, Clone)] -pub struct PackageDescriptor { - pub name: String, - pub version: String, - pub dir: String, - pub tar_path: Option, - pub tar_digest: Option, - /// `bin/` command that speaks ACP, if this is an agent package. - pub acp_entrypoint: Option, - pub snapshot: bool, - pub provides: Option, - pub commands: Vec, - pub man_pages: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PackageCommandTarget { - pub command: String, - pub entry: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PackageManPageTarget { - pub section: String, - pub page: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PackageLeafMount { - Tar { - guest_path: String, - tar_path: String, - digest: String, - root: String, - }, - SingleSymlink { - guest_path: String, - target: String, - }, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct PackageProvidesDescriptor { - #[serde(default)] - pub env: HashMap, - #[serde(default)] - pub files: Vec, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct PackageProvidesFileDescriptor { - pub source: String, - pub target: String, -} - -#[derive(Debug, Deserialize)] -struct AgentosPackageManifest { - name: String, - version: String, - #[serde(default)] - agent: Option, - #[serde(default)] - provides: Option, -} - -#[derive(Debug, Deserialize)] -struct PackageAgentDescriptor { - #[serde(rename = "acpEntrypoint")] - acp_entrypoint: String, - #[serde(default)] - snapshot: bool, -} - -impl PackageDescriptor { - fn from_parts( - dir: String, - tar_path: Option, - tar_digest: Option, - manifest: AgentosPackageManifest, - commands: Vec, - man_pages: Vec, - ) -> Result { - if manifest.name.is_empty() { - return Err(SidecarError::InvalidState(format!( - "agentos-package.json in {dir} is missing a valid \"name\"" - ))); - } - if manifest.version.is_empty() { - return Err(SidecarError::InvalidState(format!( - "agentos-package.json in {dir} is missing a valid \"version\"" - ))); - } - let (acp_entrypoint, snapshot) = match manifest.agent { - Some(agent) => (Some(agent.acp_entrypoint), agent.snapshot), - None => (None, false), - }; - if acp_entrypoint - .as_ref() - .is_some_and(|entry| entry.is_empty()) - { - return Err(SidecarError::InvalidState(format!( - "agentos-package.json in {dir} has an empty agent.acpEntrypoint" - ))); - } - Ok(Self { - name: manifest.name, - version: manifest.version, - dir, - tar_path, - tar_digest, - acp_entrypoint, - snapshot, - provides: manifest.provides, - commands, - man_pages, - }) - } - - pub fn tar_ref(&self) -> Result<(&str, &str), SidecarError> { - let tar_path = self.tar_path.as_deref().ok_or_else(|| { - SidecarError::InvalidState(format!( - "package `{}` must include {DEFAULT_PACKAGE_TAR_NAME}; directory projection is no longer supported", - self.name - )) - })?; - let digest = self.tar_digest.as_deref().ok_or_else(|| { - SidecarError::InvalidState(format!("package `{}` is missing tar digest", self.name)) - })?; - Ok((tar_path, digest)) - } -} - -fn io_err(context: &str, error: std::io::Error) -> SidecarError { - SidecarError::Io(format!("{context}: {error}")) -} - -fn read_agentos_package_manifest(dir: &str) -> Result { - let path = Path::new(dir).join("agentos-package.json"); - if !path.exists() { - return Err(SidecarError::InvalidState(format!( - "missing required agentos-package.json in package dir {dir}" - ))); - } - let text = fs::read_to_string(&path).map_err(|e| io_err("read agentos-package.json", e))?; - serde_json::from_str(&text).map_err(|e| { - SidecarError::InvalidState(format!("invalid agentos-package.json in {dir}: {e}")) - }) -} - -/// Read the sidecar-owned package manifest from `/agentos-package.json`. -pub fn read_package_manifest(dir: &str) -> Result { - let manifest = read_agentos_package_manifest(dir)?; - let tar_path = package_tar_for_dir(dir); - let tar_digest = tar_path - .as_ref() - .map(|path| digest_file(path)) - .transpose()?; - PackageDescriptor::from_parts( - dir.to_owned(), - tar_path.map(|path| path.to_string_lossy().into_owned()), - tar_digest, - manifest, - command_targets_from_dir(dir)?, - man_pages_from_dir(dir)?, - ) -} - -/// Read the first snapshot-enabled agent package's bundled SDK snapshot source. -pub fn read_agent_snapshot_bundle( - package: &PackageDescriptor, -) -> Result, SidecarError> { - if !package.snapshot { - return Ok(None); - } - let path = Path::new(&package.dir).join(AGENT_SNAPSHOT_BUNDLE); - if !path.exists() { - return Ok(None); - } - fs::read_to_string(&path) - .map(Some) - .map_err(|e| io_err("read agent snapshot bundle", e)) -} - -/// Read the package's `version` from `agentos-package.json`. -pub fn read_package_version(dir: &str) -> Result { - Ok(read_agentos_package_manifest(dir)?.version) -} - -pub fn read_package_name(dir: &str) -> Result { - Ok(read_agentos_package_manifest(dir)?.name) -} - -fn package_tar_for_dir(dir: &str) -> Option { - let tar = Path::new(dir).join(DEFAULT_PACKAGE_TAR_NAME); - tar.is_file().then_some(tar) -} - -/// Map each command name to its entry path relative to the package root. -fn command_targets_from_dir(dir: &str) -> Result, SidecarError> { - let pkg_json = Path::new(dir).join("package.json"); - if pkg_json.exists() { - if let Ok(text) = fs::read_to_string(&pkg_json) { - if let Ok(value) = serde_json::from_str::(&text) { - if let Some(targets) = command_targets_from_package_json(&value) { - return Ok(targets); - } - } - } - } - - let bin = Path::new(dir).join("bin"); - if !bin.is_dir() { - return Ok(Vec::new()); - } - let mut targets = Vec::new(); - for entry in fs::read_dir(&bin).map_err(|e| io_err("read bin/", e))? { - let entry = entry.map_err(|e| io_err("read bin/ entry", e))?; - if let Some(name) = entry.file_name().to_str() { - if is_projectable_command_name(name) { - targets.push(PackageCommandTarget { - command: name.to_owned(), - entry: format!("bin/{name}"), - }); - } - } - } - targets.sort_by(|a, b| a.command.cmp(&b.command)); - Ok(targets) -} - -fn man_pages_from_dir(dir: &str) -> Result, SidecarError> { - let man = Path::new(dir).join("share").join("man"); - if !man.is_dir() { - return Ok(Vec::new()); - } - let mut pages = Vec::new(); - for section in fs::read_dir(&man).map_err(|e| io_err("read man/", e))? { - let section = section.map_err(|e| io_err("man section", e))?; - if !section.path().is_dir() { - continue; - } - let Some(section_name) = section.file_name().to_str().map(str::to_owned) else { - continue; - }; - for page in fs::read_dir(section.path()).map_err(|e| io_err("man pages", e))? { - let page = page.map_err(|e| io_err("man page", e))?; - if let Some(page_name) = page.file_name().to_str() { - pages.push(PackageManPageTarget { - section: section_name.clone(), - page: page_name.to_owned(), - }); - } - } - } - pages.sort_by(|a, b| (&a.section, &a.page).cmp(&(&b.section, &b.page))); - Ok(pages) -} - -fn command_targets_from_package_json( - value: &serde_json::Value, -) -> Option> { - match value.get("bin") { - Some(serde_json::Value::String(path)) => { - let name = value.get("name").and_then(|v| v.as_str())?; - let unscoped = name.rsplit('/').next().unwrap_or(name).to_owned(); - Some( - is_projectable_command_name(&unscoped) - .then(|| PackageCommandTarget { - command: unscoped, - entry: normalize_rel(path), - }) - .into_iter() - .collect(), - ) - } - Some(serde_json::Value::Object(map)) => { - let mut targets: Vec = map - .iter() - .filter_map(|(name, path)| { - is_projectable_command_name(name) - .then(|| path.as_str()) - .flatten() - .map(|path| PackageCommandTarget { - command: name.clone(), - entry: normalize_rel(path), - }) - }) - .collect(); - targets.sort_by(|a, b| a.command.cmp(&b.command)); - Some(targets) - } - _ => None, - } -} - -fn is_projectable_command_name(name: &str) -> bool { - !name.starts_with('_') && !name.starts_with('.') -} - -/// Strip a leading `./` so the resulting path is a clean in-package relative path. -fn normalize_rel(path: &str) -> String { - path.strip_prefix("./").unwrap_or(path).to_owned() -} - -/// Derive command names for the package (sorted). -pub fn derive_commands(dir: &str) -> Result, SidecarError> { - Ok(command_targets_from_dir(dir)? - .into_iter() - .map(|target| target.command) - .collect()) -} - -pub fn read_package_manifest_from_ref( - dir: Option<&str>, - tar: Option<&str>, -) -> Result { - if let Some(tar) = tar.filter(|value| !value.is_empty()) { - return read_package_manifest_from_tar(tar); - } - if let Some(dir) = dir.filter(|value| !value.is_empty()) { - let path = Path::new(dir); - if path.is_file() { - return read_package_manifest_from_tar(dir); - } - if let Some(package_tar) = package_tar_for_dir(dir) { - return read_package_manifest_from_tar_with_dir(&package_tar, dir.to_owned()); - } - return read_package_manifest(dir); - } - Err(SidecarError::InvalidState(String::from( - "package descriptor must include a package tar or dir", - ))) -} - -fn read_package_manifest_from_tar(tar: &str) -> Result { - read_package_manifest_from_tar_with_dir(Path::new(tar), tar.to_owned()) -} - -fn read_package_manifest_from_tar_with_dir( - tar: &Path, - dir: String, -) -> Result { - let digest = digest_file(tar)?; - let mut fs = TarFileSystem::open(tar, digest.clone()) - .map_err(|error| SidecarError::InvalidState(error.to_string()))?; - let manifest_bytes = fs - .read_file("/agentos-package.json") - .map_err(|error| SidecarError::InvalidState(error.to_string()))?; - let manifest = - serde_json::from_slice::(&manifest_bytes).map_err(|error| { - SidecarError::InvalidState(format!( - "invalid agentos-package.json in {}: {error}", - tar.display() - )) - })?; - let commands = command_targets_from_tar(&mut fs)?; - let man_pages = man_pages_from_tar(&mut fs)?; - PackageDescriptor::from_parts( - dir, - Some(tar.to_string_lossy().into_owned()), - Some(digest), - manifest, - commands, - man_pages, - ) -} - -fn command_targets_from_tar( - fs: &mut TarFileSystem, -) -> Result, SidecarError> { - match fs.read_file("/package.json") { - Ok(bytes) => { - if let Ok(value) = serde_json::from_slice::(&bytes) { - if let Some(targets) = command_targets_from_package_json(&value) { - return Ok(targets); - } - } - } - Err(error) if error.code() == "ENOENT" => {} - Err(error) => return Err(SidecarError::InvalidState(error.to_string())), - } - - let entries = match fs.read_dir("/bin") { - Ok(entries) => entries, - Err(error) if error.code() == "ENOENT" => return Ok(Vec::new()), - Err(error) => return Err(SidecarError::InvalidState(error.to_string())), - }; - let mut targets = entries - .into_iter() - .filter_map(|command| { - is_projectable_command_name(&command).then(|| PackageCommandTarget { - entry: format!("bin/{command}"), - command, - }) - }) - .collect::>(); - targets.sort_by(|a, b| a.command.cmp(&b.command)); - Ok(targets) -} - -fn man_pages_from_tar(fs: &mut TarFileSystem) -> Result, SidecarError> { - let sections = match fs.read_dir("/share/man") { - Ok(entries) => entries, - Err(error) if error.code() == "ENOENT" => return Ok(Vec::new()), - Err(error) => return Err(SidecarError::InvalidState(error.to_string())), - }; - let mut pages = Vec::new(); - for section in sections { - let section_path = format!("/share/man/{section}"); - let Ok(stat) = fs.stat(§ion_path) else { - continue; - }; - if !stat.is_directory { - continue; - } - for page in fs - .read_dir(§ion_path) - .map_err(|error| SidecarError::InvalidState(error.to_string()))? - { - pages.push(PackageManPageTarget { - section: section.clone(), - page, - }); - } - } - pages.sort_by(|a, b| (&a.section, &a.page).cmp(&(&b.section, &b.page))); - Ok(pages) -} - -pub fn build_package_leaf_mounts( - packages: &[PackageDescriptor], - mount_at: &str, -) -> Result, SidecarError> { - let mount_at = normalize_mount_root(mount_at); - let mut mounts = Vec::new(); - let mut command_paths = HashSet::new(); - - for package in packages { - let commands = package - .commands - .iter() - .map(|target| target.command.clone()) - .collect::>(); - if let Some(acp) = &package.acp_entrypoint { - if !commands.contains(acp) { - return Err(SidecarError::InvalidState(format!( - "agent acpEntrypoint {acp:?} is not one of {}'s commands", - package.name - ))); - } - } - - let (tar_path, digest) = package.tar_ref()?; - let package_root = package_guest_root(&mount_at, &package.name); - let version_path = normalize_path(&format!("{package_root}/{}", package.version)); - push_mount( - &mut mounts, - PackageLeafMount::Tar { - guest_path: version_path, - tar_path: tar_path.to_owned(), - digest: digest.to_owned(), - root: String::from("/"), - }, - )?; - push_mount( - &mut mounts, - PackageLeafMount::SingleSymlink { - guest_path: normalize_path(&format!("{package_root}/current")), - target: package.version.clone(), - }, - )?; - - for target in &package.commands { - let guest_path = normalize_path(&format!("{mount_at}/bin/{}", target.command)); - if !command_paths.insert(guest_path.clone()) { - return Err(SidecarError::InvalidState(format!( - "command {:?} is already provided by another package", - target.command - ))); - } - push_mount( - &mut mounts, - PackageLeafMount::SingleSymlink { - guest_path, - target: format!("../pkgs/{}/current/{}", package.name, target.entry), - }, - )?; - } - - for page in &package.man_pages { - push_mount( - &mut mounts, - PackageLeafMount::SingleSymlink { - guest_path: normalize_path(&format!( - "{mount_at}/share/man/{}/{}", - page.section, page.page - )), - target: format!( - "../../../pkgs/{}/current/share/man/{}/{}", - package.name, page.section, page.page - ), - }, - )?; - } - } - - Ok(mounts) -} - -pub fn package_provides_file_mount( - package: &PackageDescriptor, - source: &str, - target: &str, -) -> Result, SidecarError> { - let (tar_path, digest) = package.tar_ref()?; - let root = normalize_package_source(source); - let mut fs = TarFileSystem::open_at(tar_path, digest, &root) - .map_err(|error| SidecarError::InvalidState(error.to_string()))?; - match fs.stat("/") { - Ok(stat) if stat.is_directory => Ok(Some(PackageLeafMount::Tar { - guest_path: normalize_path(target), - tar_path: tar_path.to_owned(), - digest: digest.to_owned(), - root, - })), - Ok(_) => Ok(None), - Err(error) if error.code() == "ENOENT" => Err(SidecarError::InvalidState(format!( - "package provides file source is missing: package `{}` source `{source}` target `{target}`", - package.name - ))), - Err(error) => Err(SidecarError::InvalidState(error.to_string())), - } -} - -fn push_mount( - mounts: &mut Vec, - mount: PackageLeafMount, -) -> Result<(), SidecarError> { - let observed = mounts.len() + 1; - if observed > MAX_AGENTOS_PACKAGE_MOUNTS { - return Err(SidecarError::InvalidState(format!( - "agentos package mount count exceeded: {observed} mounts > {MAX_AGENTOS_PACKAGE_MOUNTS} mounts (raise via limits.agentosPackages.maxMounts)" - ))); - } - if observed * 100 / MAX_AGENTOS_PACKAGE_MOUNTS >= 80 { - tracing::warn!( - limit = "agentos_package_mounts", - observed, - capacity = MAX_AGENTOS_PACKAGE_MOUNTS, - fill_percent = observed * 100 / MAX_AGENTOS_PACKAGE_MOUNTS, - wired = "limits.agentosPackages.maxMounts", - "agentos package mount count approaching configured limit" - ); - } - mounts.push(mount); - Ok(()) -} - -fn normalize_mount_root(mount_at: &str) -> String { - if mount_at.is_empty() { - String::from(OPT_AGENTOS_ROOT) - } else { - normalize_path(mount_at) - } -} - -fn package_guest_root(mount_at: &str, name: &str) -> String { - normalize_path(&format!("{mount_at}/pkgs/{name}")) -} - -fn normalize_package_source(source: &str) -> String { - if source.trim().is_empty() { - String::from("/") - } else { - normalize_path(source) - } -} - -fn digest_file(path: impl AsRef) -> Result { - let bytes = fs::read(path.as_ref()).map_err(|error| io_err("read package tar", error))?; - Ok(blake3::hash(&bytes).to_hex().to_string()) -} diff --git a/crates/sidecar/src/plugins/agentos_packages.rs b/crates/sidecar/src/plugins/agentos_packages.rs deleted file mode 100644 index 13f3dca22..000000000 --- a/crates/sidecar/src/plugins/agentos_packages.rs +++ /dev/null @@ -1,95 +0,0 @@ -//! Guest-native `/opt/agentos` package projection. -//! -//! Package files are mounted directly from the uncompressed package tar, not -//! extracted into a host staging tree. The tar already contains every member's -//! bytes at known offsets, so the VFS scans the headers once, then serves reads -//! by mmap-backed byte range. This avoids the old full unpack, hardlink copy, -//! physical symlink farm, temp cleanup, and duplicate host-disk state. -//! -//! The crucial difference from a plain `host_dir` mount is the PLUGIN ID: module -//! resolution and path translation only treat mounts classified -//! `host_dir`/`module_access` as host-backed (`build_module_reader` / -//! `runtime_guest_path_mappings` in `execution.rs`). Because this mount is -//! `agentos_packages`, the JS runtime resolves `/opt/agentos` modules through the -//! kernel VFS — no host↔guest path translation (the `/unknown/` failure -//! mode). -//! -//! Projection uses granular leaf mounts: one tar mount for -//! `/opt/agentos/pkgs//`, one synthetic root symlink for -//! `pkgs//current`, and one synthetic root symlink per managed command or -//! manpage. The parent directories remain writable overlay directories so -//! guest-installed commands can coexist with managed package entries. - -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::{ - MountedFileSystem, MountedVirtualFileSystem, ReadOnlyFileSystem, -}; -use serde::Deserialize; - -#[derive(Debug, Deserialize)] -#[serde(tag = "kind", rename_all = "camelCase")] -enum AgentosPackagesMountConfig { - Tar { - #[serde(rename = "tarPath")] - tar_path: String, - digest: String, - #[serde(default)] - root: Option, - #[serde(rename = "readOnly")] - read_only: Option, - }, - SingleSymlink { - target: String, - #[serde(rename = "readOnly")] - read_only: Option, - }, -} - -#[derive(Debug)] -pub(crate) struct AgentosPackagesMountPlugin; - -impl FileSystemPluginFactory for AgentosPackagesMountPlugin { - fn plugin_id(&self) -> &'static str { - "agentos_packages" - } - - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - let config: AgentosPackagesMountConfig = serde_json::from_value(request.config.clone()) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - match config { - AgentosPackagesMountConfig::Tar { - tar_path, - digest, - root, - read_only, - } => { - let filesystem = vfs::posix::TarFileSystem::open_at( - &tar_path, - digest, - root.as_deref().unwrap_or("/"), - ) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - let mounted = MountedVirtualFileSystem::new(filesystem); - if read_only.unwrap_or(true) { - Ok(Box::new(ReadOnlyFileSystem::new(mounted))) - } else { - Ok(Box::new(mounted)) - } - } - AgentosPackagesMountConfig::SingleSymlink { target, read_only } => { - let mounted = - MountedVirtualFileSystem::new(vfs::posix::SingleSymlinkFileSystem::new(target)); - if read_only.unwrap_or(true) { - Ok(Box::new(ReadOnlyFileSystem::new(mounted))) - } else { - Ok(Box::new(mounted)) - } - } - } - } -} diff --git a/crates/sidecar/src/plugins/chunked_local.rs b/crates/sidecar/src/plugins/chunked_local.rs deleted file mode 100644 index 2e37b7050..000000000 --- a/crates/sidecar/src/plugins/chunked_local.rs +++ /dev/null @@ -1,91 +0,0 @@ -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::MountedFileSystem; -use secure_exec_vfs::{FileBlockStore, SqliteMetadataStore}; -use serde::Deserialize; -use vfs::adapter::MountedEngineFileSystem; -use vfs::engine::engines::{ChunkedFs, ChunkedFsOptions}; -use vfs::engine::CachedMetadataStore; - -const DEFAULT_METADATA_CACHE_ENTRIES: usize = 4096; - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -struct ChunkedLocalMountConfig { - metadata_path: String, - block_root: String, - chunk_size: Option, - inline_threshold: Option, - uid: Option, - gid: Option, - file_mode: Option, - dir_mode: Option, - metadata_cache_entries: Option, -} - -#[derive(Debug)] -pub(crate) struct ChunkedLocalMountPlugin; - -impl FileSystemPluginFactory for ChunkedLocalMountPlugin { - fn plugin_id(&self) -> &'static str { - "chunked_local" - } - - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - let config: ChunkedLocalMountConfig = serde_json::from_value(request.config.clone()) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - if config.metadata_path.trim().is_empty() { - return Err(PluginError::invalid_input( - "chunked_local mount requires metadataPath", - )); - } - if config.block_root.trim().is_empty() { - return Err(PluginError::invalid_input( - "chunked_local mount requires blockRoot", - )); - } - - let chunk_size = config.chunk_size.unwrap_or(vfs::engine::DEFAULT_CHUNK_SIZE); - if chunk_size == 0 { - return Err(PluginError::invalid_input( - "chunked_local mount requires chunkSize to be greater than zero", - )); - } - let inline_threshold = config - .inline_threshold - .unwrap_or(vfs::engine::DEFAULT_INLINE_THRESHOLD); - if inline_threshold > chunk_size as usize { - return Err(PluginError::invalid_input( - "chunked_local mount requires inlineThreshold to be less than or equal to chunkSize", - )); - } - - let metadata = SqliteMetadataStore::open(config.metadata_path) - .map_err(|error| PluginError::new(error.code(), error.message().to_owned()))?; - let metadata = CachedMetadataStore::new( - metadata, - config - .metadata_cache_entries - .unwrap_or(DEFAULT_METADATA_CACHE_ENTRIES), - ); - let blocks = FileBlockStore::new(config.block_root) - .map_err(|error| PluginError::new(error.code(), error.message().to_owned()))?; - let fs = ChunkedFs::with_options( - metadata, - blocks, - ChunkedFsOptions { - inline_threshold, - chunk_size, - uid: config.uid.unwrap_or(0), - gid: config.gid.unwrap_or(0), - file_mode: config.file_mode.unwrap_or(0o644), - dir_mode: config.dir_mode.unwrap_or(0o755), - }, - ); - Ok(Box::new(MountedEngineFileSystem::new(fs)?)) - } -} diff --git a/crates/sidecar/src/plugins/chunked_s3.rs b/crates/sidecar/src/plugins/chunked_s3.rs deleted file mode 100644 index 04f835c48..000000000 --- a/crates/sidecar/src/plugins/chunked_s3.rs +++ /dev/null @@ -1,175 +0,0 @@ -use crate::bridge::MountPluginContext; -use crate::metadata::CallbackMetadataStore; -use crate::plugins::s3_common::{ - create_s3_client, normalize_prefix, S3MountCredentials, DEFAULT_REGION, -}; -use crate::protocol::OwnershipScope; - -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::MountedFileSystem; -use secure_exec_vfs::{S3BlockStore, S3BlockStoreOptions, SqliteMetadataStore}; -use serde::Deserialize; -use vfs::adapter::MountedEngineFileSystem; -use vfs::engine::engines::{ChunkedFs, ChunkedFsOptions}; -use vfs::engine::CachedMetadataStore; - -const DEFAULT_METADATA_CACHE_ENTRIES: usize = 4096; - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -struct ChunkedS3MountConfig { - bucket: String, - prefix: Option, - region: Option, - credentials: Option, - endpoint: Option, - metadata_path: Option, - metadata_backend: Option, - mount_id: Option, - chunk_size: Option, - inline_threshold: Option, - uid: Option, - gid: Option, - file_mode: Option, - dir_mode: Option, - metadata_cache_entries: Option, -} - -#[derive(Debug)] -pub(crate) struct ChunkedS3MountPlugin; - -pub(crate) trait ChunkedS3CallbackContext { - fn chunked_s3_callback_context( - &self, - ) -> Option<(crate::state::SharedSidecarRequestClient, OwnershipScope)>; -} - -impl ChunkedS3CallbackContext for () { - fn chunked_s3_callback_context( - &self, - ) -> Option<(crate::state::SharedSidecarRequestClient, OwnershipScope)> { - None - } -} - -impl ChunkedS3CallbackContext for MountPluginContext { - fn chunked_s3_callback_context( - &self, - ) -> Option<(crate::state::SharedSidecarRequestClient, OwnershipScope)> { - Some(( - self.sidecar_requests.clone(), - OwnershipScope::vm( - self.connection_id.clone(), - self.session_id.clone(), - self.vm_id.clone(), - ), - )) - } -} - -impl FileSystemPluginFactory for ChunkedS3MountPlugin -where - Context: ChunkedS3CallbackContext, -{ - fn plugin_id(&self) -> &'static str { - "chunked_s3" - } - - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - let config: ChunkedS3MountConfig = serde_json::from_value(request.config.clone()) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - let bucket = config.bucket.trim().to_owned(); - if bucket.is_empty() { - return Err(PluginError::invalid_input( - "chunked_s3 mount requires a non-empty bucket", - )); - } - let metadata_backend = config.metadata_backend.as_deref().unwrap_or("sqlite"); - match metadata_backend { - "sqlite" | "local" | "callback" => {} - backend => { - return Err(PluginError::invalid_input(format!( - "unsupported chunked_s3 metadataBackend: {backend}" - ))); - } - } - - let chunk_size = config.chunk_size.unwrap_or(vfs::engine::DEFAULT_CHUNK_SIZE); - if chunk_size == 0 { - return Err(PluginError::invalid_input( - "chunked_s3 mount requires chunkSize to be greater than zero", - )); - } - let inline_threshold = config - .inline_threshold - .unwrap_or(vfs::engine::DEFAULT_INLINE_THRESHOLD); - if inline_threshold > chunk_size as usize { - return Err(PluginError::invalid_input( - "chunked_s3 mount requires inlineThreshold to be less than or equal to chunkSize", - )); - } - - let prefix = normalize_prefix(config.prefix.as_deref()); - let client = create_s3_client( - config.region.unwrap_or_else(|| DEFAULT_REGION.to_owned()), - config.endpoint, - config.credentials, - )?; - let block_store = S3BlockStore::with_options( - client, - bucket, - S3BlockStoreOptions { - prefix: format!("{prefix}blocks/"), - }, - ); - let cache_entries = config - .metadata_cache_entries - .unwrap_or(DEFAULT_METADATA_CACHE_ENTRIES); - let options = ChunkedFsOptions { - inline_threshold, - chunk_size, - uid: config.uid.unwrap_or(0), - gid: config.gid.unwrap_or(0), - file_mode: config.file_mode.unwrap_or(0o644), - dir_mode: config.dir_mode.unwrap_or(0o755), - }; - - match metadata_backend { - "callback" => { - let (requests, ownership) = request - .context - .chunked_s3_callback_context() - .ok_or_else(|| { - PluginError::invalid_input( - "chunked_s3 callback metadata backend requires sidecar request context", - ) - })?; - let mount_id = config - .mount_id - .unwrap_or_else(|| request.guest_path.to_owned()); - let metadata = CachedMetadataStore::new( - CallbackMetadataStore::new(requests, ownership, mount_id), - cache_entries, - ); - let fs = ChunkedFs::with_options(metadata, block_store, options); - Ok(Box::new(MountedEngineFileSystem::new(fs)?)) - } - "sqlite" | "local" => { - let metadata_path = config.metadata_path.ok_or_else(|| { - PluginError::invalid_input("chunked_s3 sqlite metadata requires metadataPath") - })?; - let metadata = SqliteMetadataStore::open(metadata_path) - .map_err(|error| PluginError::new(error.code(), error.message().to_owned()))?; - let metadata = CachedMetadataStore::new(metadata, cache_entries); - let fs = ChunkedFs::with_options(metadata, block_store, options); - Ok(Box::new(MountedEngineFileSystem::new(fs)?)) - } - _ => unreachable!("metadata backend was validated above"), - } - } -} diff --git a/crates/sidecar/src/plugins/google_drive.rs b/crates/sidecar/src/plugins/google_drive.rs deleted file mode 100644 index a77dcc310..000000000 --- a/crates/sidecar/src/plugins/google_drive.rs +++ /dev/null @@ -1,1622 +0,0 @@ -use base64::engine::general_purpose::STANDARD as BASE64; -use base64::Engine; -use jsonwebtoken::{Algorithm, EncodingKey, Header}; -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::{MountedFileSystem, MountedVirtualFileSystem}; -use secure_exec_kernel::vfs::{ - MemoryFileSystem, MemoryFileSystemSnapshot, MemoryFileSystemSnapshotInode, - MemoryFileSystemSnapshotInodeKind, VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, - VirtualStat, -}; -use serde::{Deserialize, Serialize}; -use serde_json::json; -use std::collections::{BTreeMap, BTreeSet}; -use std::io::Read; -use std::time::{SystemTime, UNIX_EPOCH}; -use url::Url; - -const DEFAULT_CHUNK_SIZE: usize = 4 * 1024 * 1024; -const DEFAULT_INLINE_THRESHOLD: usize = 64 * 1024; -const MANIFEST_FORMAT: &str = "secure_exec_google_drive_filesystem_manifest_v1"; -const LEGACY_AGENTOS_MANIFEST_FORMAT: &str = "agentos_google_drive_filesystem_manifest_v1"; -const DRIVE_SCOPE: &str = "https://www.googleapis.com/auth/drive.file"; -const DEFAULT_TOKEN_URL: &str = "https://oauth2.googleapis.com/token"; -const DEFAULT_API_BASE_URL: &str = "https://www.googleapis.com"; -const TOKEN_REFRESH_SKEW_SECONDS: u64 = 60; -const MAX_PERSISTED_MANIFEST_BYTES: usize = 64 * 1024 * 1024; -const MAX_PERSISTED_MANIFEST_FILE_BYTES: u64 = 1024 * 1024 * 1024; - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -struct GoogleDriveMountCredentials { - client_email: String, - private_key: String, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -struct GoogleDriveMountConfig { - credentials: GoogleDriveMountCredentials, - folder_id: String, - key_prefix: Option, - chunk_size: Option, - inline_threshold: Option, - #[serde(default)] - token_url: Option, - #[serde(default)] - api_base_url: Option, -} - -#[derive(Debug)] -pub(crate) struct GoogleDriveMountPlugin; - -impl FileSystemPluginFactory for GoogleDriveMountPlugin { - fn plugin_id(&self) -> &'static str { - "google_drive" - } - - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - let config: GoogleDriveMountConfig = serde_json::from_value(request.config.clone()) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - let filesystem = GoogleDriveBackedFilesystem::from_config(config)?; - Ok(Box::new(MountedVirtualFileSystem::new(filesystem))) - } -} - -struct GoogleDriveBackedFilesystem { - inner: MemoryFileSystem, - store: GoogleDriveObjectStore, - manifest_key: String, - chunk_key_prefix: String, - chunk_keys: BTreeSet, - chunk_size: usize, - inline_threshold: usize, -} - -impl GoogleDriveBackedFilesystem { - fn from_config(config: GoogleDriveMountConfig) -> Result { - let folder_id = config.folder_id.trim().to_owned(); - if folder_id.is_empty() { - return Err(PluginError::invalid_input( - "google_drive mount requires a non-empty folderId", - )); - } - - let chunk_size = config.chunk_size.unwrap_or(DEFAULT_CHUNK_SIZE); - if chunk_size == 0 { - return Err(PluginError::invalid_input( - "google_drive mount requires chunkSize to be greater than zero", - )); - } - - let inline_threshold = config.inline_threshold.unwrap_or(DEFAULT_INLINE_THRESHOLD); - if inline_threshold > chunk_size { - return Err(PluginError::invalid_input( - "google_drive mount requires inlineThreshold to be less than or equal to chunkSize", - )); - } - - let prefix = normalize_prefix(config.key_prefix.as_deref()); - let manifest_key = format!("{prefix}filesystem-manifest.json"); - let chunk_key_prefix = format!("{prefix}blocks/"); - let mut store = GoogleDriveObjectStore::new( - config.credentials, - folder_id, - config - .token_url - .unwrap_or_else(|| String::from(DEFAULT_TOKEN_URL)), - config - .api_base_url - .unwrap_or_else(|| String::from(DEFAULT_API_BASE_URL)), - )?; - - let (inner, chunk_keys) = match store.load_manifest(&manifest_key)? { - Some(manifest_bytes) => { - load_filesystem_from_manifest(&mut store, &manifest_bytes, &chunk_key_prefix)? - } - None => (MemoryFileSystem::new(), BTreeSet::new()), - }; - - Ok(Self { - inner, - store, - manifest_key, - chunk_key_prefix, - chunk_keys, - chunk_size, - inline_threshold, - }) - } - - fn persist(&mut self) -> VfsResult<()> { - let snapshot = self.inner.snapshot(); - let (manifest, next_chunk_keys) = persist_manifest_from_snapshot( - &mut self.store, - &snapshot, - &self.chunk_key_prefix, - self.chunk_size, - self.inline_threshold, - ) - .map_err(storage_error_to_vfs)?; - - let manifest_bytes = serde_json::to_vec(&manifest) - .map_err(|error| VfsError::io(format!("serialize google drive manifest: {error}")))?; - validate_persisted_manifest_bytes(&manifest_bytes).map_err(storage_error_to_vfs)?; - self.store - .put_bytes(&self.manifest_key, &manifest_bytes) - .map_err(storage_error_to_vfs)?; - - let stale_keys = self - .chunk_keys - .difference(&next_chunk_keys) - .cloned() - .collect::>(); - for key in stale_keys { - self.store - .delete_object(&key) - .map_err(storage_error_to_vfs)?; - } - - self.chunk_keys = next_chunk_keys; - Ok(()) - } -} - -impl VirtualFileSystem for GoogleDriveBackedFilesystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - self.inner.read_file(path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - self.inner.read_dir(path) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - self.inner.read_dir_with_types(path) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - self.inner.write_file(path, content.into())?; - self.persist() - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - self.inner.create_dir(path)?; - self.persist() - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - self.inner.mkdir(path, recursive)?; - self.persist() - } - - fn exists(&self, path: &str) -> bool { - self.inner.exists(path) - } - - fn stat(&mut self, path: &str) -> VfsResult { - self.inner.stat(path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - self.inner.remove_file(path)?; - self.persist() - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - self.inner.remove_dir(path)?; - self.persist() - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.inner.rename(old_path, new_path)?; - self.persist() - } - - fn realpath(&self, path: &str) -> VfsResult { - self.inner.realpath(path) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - self.inner.symlink(target, link_path)?; - self.persist() - } - - fn read_link(&self, path: &str) -> VfsResult { - self.inner.read_link(path) - } - - fn lstat(&self, path: &str) -> VfsResult { - self.inner.lstat(path) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.inner.link(old_path, new_path)?; - self.persist() - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - self.inner.chmod(path, mode)?; - self.persist() - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - self.inner.chown(path, uid, gid)?; - self.persist() - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - self.inner.utimes(path, atime_ms, mtime_ms)?; - self.persist() - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - self.inner.truncate(path, length)?; - self.persist() - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - self.inner.pread(path, offset, length) - } -} - -struct GoogleDriveObjectStore { - auth: GoogleServiceAccountAuth, - folder_id: String, - api_base_url: String, - file_id_cache: BTreeMap, -} - -impl GoogleDriveObjectStore { - fn new( - credentials: GoogleDriveMountCredentials, - folder_id: String, - token_url: String, - api_base_url: String, - ) -> Result { - let api_base_url = validate_google_drive_url(&api_base_url, "apiBaseUrl", false)?; - - Ok(Self { - auth: GoogleServiceAccountAuth::new(credentials, token_url)?, - folder_id, - api_base_url, - file_id_cache: BTreeMap::new(), - }) - } - - fn load_manifest(&mut self, key: &str) -> Result>, PluginError> { - self.load_bytes_limited(key, MAX_PERSISTED_MANIFEST_BYTES) - .map_err(|error| PluginError::new("EIO", error.to_string())) - } - - fn load_bytes_limited( - &mut self, - key: &str, - max_bytes: usize, - ) -> Result>, StorageError> { - let Some(file_id) = self.find_file_id(key)? else { - return Ok(None); - }; - - match self.download_file(&file_id, max_bytes) { - Ok(bytes) => Ok(Some(bytes)), - Err(error) if error.is_not_found() => { - self.file_id_cache.remove(key); - if let Some(file_id) = self.lookup_file_id(key)? { - let bytes = self.download_file(&file_id, max_bytes)?; - Ok(Some(bytes)) - } else { - Ok(None) - } - } - Err(error) => Err(error), - } - } - - fn put_bytes(&mut self, key: &str, bytes: &[u8]) -> Result<(), StorageError> { - if let Some(file_id) = self.find_file_id(key)? { - match self.upload_file_contents(&file_id, bytes) { - Ok(()) => return Ok(()), - Err(error) if error.is_not_found() => { - self.file_id_cache.remove(key); - } - Err(error) => return Err(error), - } - } - - let file_id = self.create_file(key)?; - self.upload_file_contents(&file_id, bytes)?; - self.file_id_cache.insert(String::from(key), file_id); - Ok(()) - } - - fn delete_object(&mut self, key: &str) -> Result<(), StorageError> { - let Some(file_id) = self.find_file_id(key)? else { - return Ok(()); - }; - - match self.delete_file(&file_id) { - Ok(()) => {} - Err(error) if error.is_not_found() => {} - Err(error) => return Err(error), - } - - self.file_id_cache.remove(key); - Ok(()) - } - - fn find_file_id(&mut self, key: &str) -> Result, StorageError> { - if let Some(file_id) = self.file_id_cache.get(key) { - return Ok(Some(file_id.clone())); - } - - let file_id = self.lookup_file_id(key)?; - if let Some(file_id) = &file_id { - self.file_id_cache - .insert(String::from(key), file_id.clone()); - } - Ok(file_id) - } - - fn lookup_file_id(&mut self, key: &str) -> Result, StorageError> { - let query = format!( - "name = '{}' and '{}' in parents and trashed = false", - escape_query_literal(key), - escape_query_literal(&self.folder_id), - ); - let token = self.auth.access_token()?; - let url = format!("{}/drive/v3/files", self.api_base_url); - - match ureq::get(&url) - .query("q", &query) - .query("fields", "files(id)") - .query("pageSize", "1") - .query("supportsAllDrives", "true") - .set("Authorization", &format!("Bearer {token}")) - .call() - { - Ok(response) => { - let payload = response - .into_json::() - .map_err(|error| { - StorageError::new(format!( - "decode google drive file lookup response: {error}" - )) - })?; - Ok(payload - .files - .and_then(|mut files| files.pop()) - .and_then(|file| file.id)) - } - Err(ureq::Error::Status(status, response)) => Err(response_error( - &format!("lookup google drive file '{key}'"), - status, - response, - )), - Err(ureq::Error::Transport(error)) => Err(StorageError::new(format!( - "lookup google drive file '{key}': {error}" - ))), - } - } - - fn download_file(&mut self, file_id: &str, max_bytes: usize) -> Result, StorageError> { - let token = self.auth.access_token()?; - let url = format!("{}/drive/v3/files/{}", self.api_base_url, file_id); - - match ureq::get(&url) - .query("alt", "media") - .query("supportsAllDrives", "true") - .set("Authorization", &format!("Bearer {token}")) - .call() - { - Ok(response) => read_response_bytes(response, max_bytes).map_err(|error| { - StorageError::new(format!("read google drive file '{file_id}': {error}")) - }), - Err(ureq::Error::Status(status, response)) => Err(response_error( - &format!("download google drive file '{file_id}'"), - status, - response, - )), - Err(ureq::Error::Transport(error)) => Err(StorageError::new(format!( - "download google drive file '{file_id}': {error}" - ))), - } - } - - fn create_file(&mut self, name: &str) -> Result { - let token = self.auth.access_token()?; - let url = format!("{}/drive/v3/files", self.api_base_url); - - match ureq::post(&url) - .query("fields", "id") - .query("supportsAllDrives", "true") - .set("Authorization", &format!("Bearer {token}")) - .send_json(json!({ - "name": name, - "parents": [self.folder_id.clone()], - "mimeType": "application/octet-stream", - })) { - Ok(response) => { - let payload = response.into_json::().map_err(|error| { - StorageError::new(format!("decode google drive file create response: {error}")) - })?; - payload.id.ok_or_else(|| { - StorageError::new(format!( - "create google drive file '{name}': missing file id in response" - )) - }) - } - Err(ureq::Error::Status(status, response)) => Err(response_error( - &format!("create google drive file '{name}'"), - status, - response, - )), - Err(ureq::Error::Transport(error)) => Err(StorageError::new(format!( - "create google drive file '{name}': {error}" - ))), - } - } - - fn upload_file_contents(&mut self, file_id: &str, bytes: &[u8]) -> Result<(), StorageError> { - let token = self.auth.access_token()?; - let url = format!("{}/upload/drive/v3/files/{}", self.api_base_url, file_id); - - match ureq::request("PATCH", &url) - .query("uploadType", "media") - .query("supportsAllDrives", "true") - .set("Authorization", &format!("Bearer {token}")) - .set("Content-Type", "application/octet-stream") - .send_bytes(bytes) - { - Ok(_) => Ok(()), - Err(ureq::Error::Status(status, response)) => Err(response_error( - &format!("upload google drive file '{file_id}'"), - status, - response, - )), - Err(ureq::Error::Transport(error)) => Err(StorageError::new(format!( - "upload google drive file '{file_id}': {error}" - ))), - } - } - - fn delete_file(&mut self, file_id: &str) -> Result<(), StorageError> { - let token = self.auth.access_token()?; - let url = format!("{}/drive/v3/files/{}", self.api_base_url, file_id); - - match ureq::delete(&url) - .query("supportsAllDrives", "true") - .set("Authorization", &format!("Bearer {token}")) - .call() - { - Ok(_) => Ok(()), - Err(ureq::Error::Status(status, response)) => Err(response_error( - &format!("delete google drive file '{file_id}'"), - status, - response, - )), - Err(ureq::Error::Transport(error)) => Err(StorageError::new(format!( - "delete google drive file '{file_id}': {error}" - ))), - } - } -} - -struct GoogleServiceAccountAuth { - client_email: String, - token_url: String, - encoding_key: EncodingKey, - cached_token: Option, -} - -#[derive(Debug, Clone)] -struct CachedAccessToken { - access_token: String, - expires_at: u64, -} - -impl GoogleServiceAccountAuth { - fn new( - credentials: GoogleDriveMountCredentials, - token_url: String, - ) -> Result { - if credentials.client_email.trim().is_empty() { - return Err(PluginError::invalid_input( - "google_drive mount requires credentials.clientEmail", - )); - } - if credentials.private_key.trim().is_empty() { - return Err(PluginError::invalid_input( - "google_drive mount requires credentials.privateKey", - )); - } - let encoding_key = - EncodingKey::from_rsa_pem(credentials.private_key.as_bytes()).map_err(|error| { - PluginError::invalid_input(format!( - "google_drive mount credentials.privateKey is not valid PEM: {error}" - )) - })?; - let token_url = validate_google_drive_url(&token_url, "tokenUrl", true)?; - - Ok(Self { - client_email: credentials.client_email, - token_url, - encoding_key, - cached_token: None, - }) - } - - fn access_token(&mut self) -> Result { - let now = now_unix_seconds(); - if let Some(token) = &self.cached_token { - if token.expires_at > now + TOKEN_REFRESH_SKEW_SECONDS { - return Ok(token.access_token.clone()); - } - } - - let iat = now as usize; - let exp = (now + 3600) as usize; - let claims = ServiceAccountClaims { - iss: &self.client_email, - scope: DRIVE_SCOPE, - aud: &self.token_url, - iat, - exp, - }; - let jwt = jsonwebtoken::encode(&Header::new(Algorithm::RS256), &claims, &self.encoding_key) - .map_err(|error| StorageError::new(format!("sign google oauth assertion: {error}")))?; - - match ureq::post(&self.token_url).send_form(&[ - ("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"), - ("assertion", jwt.as_str()), - ]) { - Ok(response) => { - let payload = response - .into_json::() - .map_err(|error| { - StorageError::new(format!("decode google oauth token response: {error}")) - })?; - let cached = CachedAccessToken { - access_token: payload.access_token, - expires_at: now + payload.expires_in, - }; - let token = cached.access_token.clone(); - self.cached_token = Some(cached); - Ok(token) - } - Err(ureq::Error::Status(status, response)) => Err(response_error( - "fetch google oauth access token", - status, - response, - )), - Err(ureq::Error::Transport(error)) => Err(StorageError::new(format!( - "fetch google oauth access token: {error}" - ))), - } - } -} - -#[derive(Debug, Deserialize)] -struct AccessTokenResponse { - access_token: String, - expires_in: u64, -} - -#[derive(Debug, Serialize)] -struct ServiceAccountClaims<'a> { - iss: &'a str, - scope: &'a str, - aud: &'a str, - iat: usize, - exp: usize, -} - -#[derive(Debug, Deserialize)] -struct DriveFileListResponse { - files: Option>, -} - -#[derive(Debug, Deserialize)] -struct DriveFileResponse { - id: Option, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum StorageErrorKind { - Other, - NotFound, -} - -#[derive(Debug, Clone)] -struct StorageError { - kind: StorageErrorKind, - message: String, -} - -impl StorageError { - fn new(message: impl Into) -> Self { - Self { - kind: StorageErrorKind::Other, - message: message.into(), - } - } - - fn not_found(message: impl Into) -> Self { - Self { - kind: StorageErrorKind::NotFound, - message: message.into(), - } - } - - fn is_not_found(&self) -> bool { - self.kind == StorageErrorKind::NotFound - } -} - -impl std::fmt::Display for StorageError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.message) - } -} - -impl std::error::Error for StorageError {} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct PersistedFilesystemManifest { - format: String, - path_index: BTreeMap, - inodes: BTreeMap, - next_ino: u64, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct PersistedFilesystemInode { - metadata: secure_exec_kernel::vfs::MemoryFileSystemSnapshotMetadata, - kind: PersistedFilesystemInodeKind, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "kind", rename_all = "camelCase")] -enum PersistedFilesystemInodeKind { - File { storage: PersistedFileStorage }, - Directory, - SymbolicLink { target: String }, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "storageMode", rename_all = "camelCase")] -enum PersistedFileStorage { - Inline { - data_base64: String, - }, - Chunked { - size: u64, - chunks: Vec, - }, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct PersistedChunkRef { - index: u64, - key: String, -} - -fn persist_manifest_from_snapshot( - store: &mut GoogleDriveObjectStore, - snapshot: &MemoryFileSystemSnapshot, - chunk_key_prefix: &str, - chunk_size: usize, - inline_threshold: usize, -) -> Result<(PersistedFilesystemManifest, BTreeSet), StorageError> { - let mut chunk_keys = BTreeSet::new(); - let mut inodes = BTreeMap::new(); - - for (ino, inode) in &snapshot.inodes { - let persisted_kind = match &inode.kind { - MemoryFileSystemSnapshotInodeKind::File { data } => { - if data.len() <= inline_threshold { - PersistedFilesystemInodeKind::File { - storage: PersistedFileStorage::Inline { - data_base64: BASE64.encode(data), - }, - } - } else { - let mut chunks = Vec::new(); - for (index, chunk) in data.chunks(chunk_size).enumerate() { - let key = format!("{chunk_key_prefix}{ino}/{index}"); - store.put_bytes(&key, chunk)?; - chunk_keys.insert(key.clone()); - chunks.push(PersistedChunkRef { - index: index as u64, - key, - }); - } - - PersistedFilesystemInodeKind::File { - storage: PersistedFileStorage::Chunked { - size: data.len() as u64, - chunks, - }, - } - } - } - MemoryFileSystemSnapshotInodeKind::Directory => PersistedFilesystemInodeKind::Directory, - MemoryFileSystemSnapshotInodeKind::SymbolicLink { target } => { - PersistedFilesystemInodeKind::SymbolicLink { - target: target.clone(), - } - } - }; - - inodes.insert( - *ino, - PersistedFilesystemInode { - metadata: inode.metadata.clone(), - kind: persisted_kind, - }, - ); - } - - Ok(( - PersistedFilesystemManifest { - format: String::from(MANIFEST_FORMAT), - path_index: snapshot.path_index.clone(), - inodes, - next_ino: snapshot.next_ino, - }, - chunk_keys, - )) -} - -fn load_filesystem_from_manifest( - store: &mut GoogleDriveObjectStore, - manifest_bytes: &[u8], - chunk_key_prefix: &str, -) -> Result<(MemoryFileSystem, BTreeSet), PluginError> { - let manifest: PersistedFilesystemManifest = - serde_json::from_slice(manifest_bytes).map_err(|error| { - PluginError::invalid_input(format!("parse google drive manifest: {error}")) - })?; - if !is_supported_manifest_format(&manifest.format) { - return Err(PluginError::invalid_input(format!( - "unsupported google drive manifest format: {}", - manifest.format - ))); - } - - let mut chunk_keys = BTreeSet::new(); - let mut inodes = BTreeMap::new(); - for (ino, inode) in manifest.inodes { - let kind = match inode.kind { - PersistedFilesystemInodeKind::File { storage } => { - let data = match storage { - PersistedFileStorage::Inline { data_base64 } => { - validate_inline_manifest_data_size(&data_base64, "google drive", ino)?; - let data = BASE64.decode(data_base64).map_err(|error| { - PluginError::invalid_input(format!( - "decode inline google drive file data for inode {ino}: {error}" - )) - })?; - validate_manifest_file_size(data.len() as u64, "google drive", ino)?; - data - } - PersistedFileStorage::Chunked { size, mut chunks } => { - chunks.sort_by_key(|chunk| chunk.index); - let expected_size = validate_manifest_file_size(size, "google drive", ino)?; - let mut data = Vec::with_capacity(expected_size); - for chunk in chunks { - validate_manifest_chunk_key(&chunk.key, chunk_key_prefix, ino)?; - let remaining = expected_size.saturating_sub(data.len()); - if remaining == 0 { - return Err(PluginError::invalid_input(format!( - "google drive manifest inode {ino} has chunk data beyond declared size {size}" - ))); - } - let bytes = store - .load_bytes_limited(&chunk.key, remaining) - .map_err(|error| PluginError::new("EIO", error.to_string()))? - .ok_or_else(|| { - PluginError::new( - "EIO", - format!( - "google drive manifest references missing chunk '{}' for inode {}", - chunk.key, ino - ), - ) - })?; - chunk_keys.insert(chunk.key); - data.extend_from_slice(&bytes); - } - if data.len() != expected_size { - return Err(PluginError::invalid_input(format!( - "google drive manifest inode {ino} restored {} bytes but declared {size}", - data.len() - ))); - } - data - } - }; - - MemoryFileSystemSnapshotInodeKind::File { data } - } - PersistedFilesystemInodeKind::Directory => MemoryFileSystemSnapshotInodeKind::Directory, - PersistedFilesystemInodeKind::SymbolicLink { target } => { - MemoryFileSystemSnapshotInodeKind::SymbolicLink { target } - } - }; - - inodes.insert( - ino, - MemoryFileSystemSnapshotInode { - metadata: inode.metadata, - kind, - }, - ); - } - - Ok(( - MemoryFileSystem::from_snapshot(MemoryFileSystemSnapshot { - path_index: manifest.path_index, - inodes, - next_ino: manifest.next_ino, - }), - chunk_keys, - )) -} - -fn is_supported_manifest_format(format: &str) -> bool { - format == MANIFEST_FORMAT || format == LEGACY_AGENTOS_MANIFEST_FORMAT -} - -fn validate_manifest_chunk_key( - key: &str, - chunk_key_prefix: &str, - ino: u64, -) -> Result<(), PluginError> { - if key.starts_with(chunk_key_prefix) { - return Ok(()); - } - - Err(PluginError::invalid_input(format!( - "google drive manifest inode {ino} references chunk outside mount prefix" - ))) -} - -fn validate_manifest_file_size(size: u64, backend: &str, ino: u64) -> Result { - if size > MAX_PERSISTED_MANIFEST_FILE_BYTES { - return Err(PluginError::invalid_input(format!( - "{backend} manifest inode {ino} declares {size} bytes, limit is {MAX_PERSISTED_MANIFEST_FILE_BYTES}" - ))); - } - - usize::try_from(size).map_err(|_| { - PluginError::invalid_input(format!( - "{backend} manifest inode {ino} size {size} does not fit on this platform" - )) - }) -} - -fn validate_inline_manifest_data_size( - data_base64: &str, - backend: &str, - ino: u64, -) -> Result<(), PluginError> { - validate_inline_manifest_data_size_with_limit( - data_base64, - backend, - ino, - MAX_PERSISTED_MANIFEST_FILE_BYTES, - ) -} - -fn validate_inline_manifest_data_size_with_limit( - data_base64: &str, - backend: &str, - ino: u64, - max_bytes: u64, -) -> Result<(), PluginError> { - let padding = data_base64 - .as_bytes() - .iter() - .rev() - .take_while(|byte| **byte == b'=') - .count() - .min(2); - let estimated_decoded = data_base64 - .len() - .div_ceil(4) - .saturating_mul(3) - .saturating_sub(padding); - if estimated_decoded as u64 > max_bytes { - return Err(PluginError::invalid_input(format!( - "{backend} manifest inode {ino} inline data may decode to {estimated_decoded} bytes, limit is {max_bytes}" - ))); - } - Ok(()) -} - -fn validate_persisted_manifest_bytes(bytes: &[u8]) -> Result<(), StorageError> { - validate_persisted_manifest_size(bytes.len(), MAX_PERSISTED_MANIFEST_BYTES) -} - -fn validate_persisted_manifest_size(size: usize, max_bytes: usize) -> Result<(), StorageError> { - if size > max_bytes { - return Err(StorageError::new(format!( - "google drive manifest is {size} bytes, limit is {max_bytes}" - ))); - } - Ok(()) -} - -fn normalize_prefix(raw: Option<&str>) -> String { - match raw { - Some(prefix) if !prefix.trim().is_empty() => { - let trimmed = prefix.trim_matches('/'); - if trimmed.is_empty() { - String::new() - } else { - format!("{trimmed}/") - } - } - _ => String::new(), - } -} - -fn normalize_base_url(raw: &str) -> Option { - let trimmed = raw.trim().trim_end_matches('/'); - if trimmed.is_empty() { - None - } else { - Some(String::from(trimmed)) - } -} - -fn validate_google_drive_url( - raw: &str, - field_name: &str, - allow_path: bool, -) -> Result { - // tokenUrl / apiBaseUrl come only from the trusted mount config, never from - // untrusted guest code, so a strict host allowlist (SSRF hardening against - // trusted input) is dropped (see root CLAUDE.md). We keep well-formedness - // plus the credential-leak guards: these endpoints receive a signed - // service-account JWT and an OAuth bearer token, so https is required and - // embedded credentials / query / fragment are rejected to avoid leaking - // those secrets to an unintended host on a config typo. - let normalized = normalize_base_url(raw).ok_or_else(|| { - PluginError::invalid_input(format!("google_drive mount requires a valid {field_name}")) - })?; - let url = Url::parse(&normalized).map_err(|error| { - PluginError::invalid_input(format!( - "google_drive mount {field_name} is not a valid URL: {error}" - )) - })?; - - if is_google_drive_test_url(&url) { - return Ok(normalized); - } - - if url.scheme() != "https" { - return Err(PluginError::invalid_input(format!( - "google_drive mount {field_name} must use https" - ))); - } - if url.host_str().is_none() { - return Err(PluginError::invalid_input(format!( - "google_drive mount {field_name} must include a host" - ))); - } - if !url.username().is_empty() || url.password().is_some() { - return Err(PluginError::invalid_input(format!( - "google_drive mount {field_name} must not include user credentials" - ))); - } - if url.query().is_some() || url.fragment().is_some() { - return Err(PluginError::invalid_input(format!( - "google_drive mount {field_name} must not include query or fragment components" - ))); - } - if !allow_path && url.path() != "/" { - return Err(PluginError::invalid_input(format!( - "google_drive mount {field_name} must not include a path" - ))); - } - - Ok(normalized) -} - -fn is_google_drive_test_url(url: &Url) -> bool { - #[cfg(test)] - { - matches!(url.scheme(), "http" | "https") - && matches!( - url.host_str(), - Some("127.0.0.1") | Some("localhost") | Some("[::1]") - ) - } - #[cfg(not(test))] - { - let _ = url; - false - } -} - -fn escape_query_literal(raw: &str) -> String { - raw.replace('\\', "\\\\").replace('\'', "\\'") -} - -fn now_unix_seconds() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_secs() -} - -fn read_response_bytes(response: ureq::Response, max_bytes: usize) -> std::io::Result> { - let mut reader = response - .into_reader() - .take(max_bytes.saturating_add(1) as u64); - let mut bytes = Vec::new(); - reader.read_to_end(&mut bytes)?; - if bytes.len() > max_bytes { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("response exceeded {max_bytes} byte limit"), - )); - } - Ok(bytes) -} - -fn response_error(context: &str, status: u16, response: ureq::Response) -> StorageError { - let body = response.into_string().unwrap_or_default(); - let message = if body.trim().is_empty() { - format!("{context}: http {status}") - } else { - format!("{context}: http {status}: {}", body.trim()) - }; - if status == 404 { - StorageError::not_found(message) - } else { - StorageError::new(message) - } -} - -fn storage_error_to_vfs(error: StorageError) -> VfsError { - VfsError::io(error.to_string()) -} - -#[cfg(test)] -pub(crate) mod test_support { - #![allow(dead_code)] - - use serde::Deserialize; - use serde_json::json; - use std::collections::BTreeMap; - use std::io::{Read, Write}; - use std::net::{TcpListener, TcpStream}; - use std::sync::atomic::{AtomicBool, Ordering}; - use std::sync::{Arc, Mutex}; - use std::thread::{self, JoinHandle}; - use std::time::Duration; - - #[derive(Clone, Debug)] - pub(crate) struct LoggedRequest { - pub method: String, - pub path: String, - } - - #[derive(Clone, Debug)] - struct MockDriveFile { - id: String, - name: String, - parents: Vec, - content: Vec, - } - - #[derive(Default)] - struct ServerState { - next_id: usize, - files: BTreeMap, - requests: Vec, - } - - #[derive(Deserialize)] - #[serde(rename_all = "camelCase")] - struct CreateFileBody { - name: String, - parents: Option>, - } - - pub(crate) struct MockGoogleDriveServer { - base_url: String, - shutdown: Arc, - state: Arc>, - handle: Option>, - } - - impl MockGoogleDriveServer { - pub(crate) fn start() -> Self { - let listener = TcpListener::bind("127.0.0.1:0").expect("bind mock google drive"); - listener - .set_nonblocking(true) - .expect("configure mock google drive listener"); - let address = listener - .local_addr() - .expect("resolve mock google drive address"); - let shutdown = Arc::new(AtomicBool::new(false)); - let state = Arc::new(Mutex::new(ServerState::default())); - let shutdown_for_thread = Arc::clone(&shutdown); - let state_for_thread = Arc::clone(&state); - - let handle = thread::spawn(move || { - while !shutdown_for_thread.load(Ordering::SeqCst) { - match listener.accept() { - Ok((stream, _)) => { - handle_stream(stream, &state_for_thread); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - thread::sleep(Duration::from_millis(10)); - } - Err(_) => break, - } - } - }); - - Self { - base_url: format!("http://{}", address), - shutdown, - state, - handle: Some(handle), - } - } - - pub(crate) fn base_url(&self) -> &str { - &self.base_url - } - - pub(crate) fn file_names(&self) -> Vec { - self.state - .lock() - .expect("lock mock google drive state") - .files - .values() - .map(|file| file.name.clone()) - .collect() - } - - pub(crate) fn insert_file(&self, name: &str, parent: &str, content: Vec) { - let mut state = self.state.lock().expect("lock mock google drive state"); - state.next_id += 1; - let file_id = format!("file-{}", state.next_id); - state.files.insert( - file_id.clone(), - MockDriveFile { - id: file_id, - name: name.to_owned(), - parents: vec![parent.to_owned()], - content, - }, - ); - } - - pub(crate) fn requests(&self) -> Vec { - self.state - .lock() - .expect("lock mock google drive state") - .requests - .clone() - } - } - - impl Drop for MockGoogleDriveServer { - fn drop(&mut self) { - self.shutdown.store(true, Ordering::SeqCst); - if let Some(handle) = self.handle.take() { - handle.join().expect("join mock google drive thread"); - } - } - } - - fn handle_stream(mut stream: TcpStream, state: &Arc>) { - stream - .set_read_timeout(Some(Duration::from_secs(2))) - .expect("set mock google drive read timeout"); - - let mut buffer = Vec::new(); - let mut header_end = None; - while header_end.is_none() { - let mut chunk = [0; 1024]; - match stream.read(&mut chunk) { - Ok(0) => return, - Ok(read) => { - buffer.extend_from_slice(&chunk[..read]); - header_end = find_header_end(&buffer); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => continue, - Err(_) => return, - } - } - - let header_end = header_end.expect("parse mock google drive headers"); - let header_text = String::from_utf8_lossy(&buffer[..header_end]); - let mut lines = header_text.split("\r\n"); - let request_line = match lines.next() { - Some(line) if !line.is_empty() => line, - _ => return, - }; - let mut request_parts = request_line.split_whitespace(); - let method = request_parts.next().unwrap_or_default().to_owned(); - let raw_target = request_parts.next().unwrap_or_default(); - let (raw_path, raw_query) = raw_target.split_once('?').unwrap_or((raw_target, "")); - let path = decode_component(raw_path); - let query = parse_query(raw_query); - - let mut headers = BTreeMap::new(); - let mut content_length = 0usize; - for line in lines { - if let Some((name, value)) = line.split_once(':') { - let header_name = name.trim().to_ascii_lowercase(); - let header_value = value.trim().to_owned(); - if header_name == "content-length" { - content_length = header_value.parse::().unwrap_or(0); - } - headers.insert(header_name, header_value); - } - } - - while buffer.len() < header_end + 4 + content_length { - let mut chunk = [0; 1024]; - match stream.read(&mut chunk) { - Ok(0) => break, - Ok(read) => buffer.extend_from_slice(&chunk[..read]), - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => continue, - Err(_) => break, - } - } - let body = buffer[header_end + 4..header_end + 4 + content_length].to_vec(); - - state - .lock() - .expect("lock mock google drive state") - .requests - .push(LoggedRequest { - method: method.clone(), - path: path.clone(), - }); - - match (method.as_str(), path.as_str()) { - ("POST", "/token") => send_json_response( - &mut stream, - 200, - json!({ - "access_token": "test-access-token", - "token_type": "Bearer", - "expires_in": 3600, - }), - ), - ("GET", "/drive/v3/files") => handle_list(&mut stream, state, &query), - ("POST", "/drive/v3/files") => handle_create(&mut stream, state, &body), - ("DELETE", file_path) if file_path.starts_with("/drive/v3/files/") => { - handle_delete(&mut stream, state, file_path) - } - ("POST", copy_path) - if copy_path.starts_with("/drive/v3/files/") && copy_path.ends_with("/copy") => - { - handle_copy(&mut stream, state, copy_path, &body) - } - ("GET", file_path) - if file_path.starts_with("/drive/v3/files/") - && query.get("alt").map(String::as_str) == Some("media") => - { - handle_download(&mut stream, state, file_path, headers.get("range")) - } - ("PATCH", upload_path) if upload_path.starts_with("/upload/drive/v3/files/") => { - handle_upload(&mut stream, state, upload_path, body) - } - _ => send_response( - &mut stream, - 405, - "Method Not Allowed", - "text/plain", - b"unsupported", - ), - } - } - - fn handle_list( - stream: &mut TcpStream, - state: &Arc>, - query: &BTreeMap, - ) { - let Some(q) = query.get("q") else { - send_response(stream, 400, "Bad Request", "text/plain", b"missing q"); - return; - }; - let Some((name, folder_id)) = parse_list_query(q) else { - send_response(stream, 400, "Bad Request", "text/plain", b"invalid q"); - return; - }; - - let file = state - .lock() - .expect("lock mock google drive state") - .files - .values() - .find(|file| { - file.name == name && file.parents.iter().any(|parent| parent == &folder_id) - }) - .cloned(); - - let response = match file { - Some(file) => json!({ "files": [{ "id": file.id }] }), - None => json!({ "files": [] }), - }; - send_json_response(stream, 200, response); - } - - fn handle_create(stream: &mut TcpStream, state: &Arc>, body: &[u8]) { - let Ok(request) = serde_json::from_slice::(body) else { - send_response(stream, 400, "Bad Request", "text/plain", b"invalid json"); - return; - }; - let mut state = state.lock().expect("lock mock google drive state"); - state.next_id += 1; - let file_id = format!("file-{}", state.next_id); - state.files.insert( - file_id.clone(), - MockDriveFile { - id: file_id.clone(), - name: request.name, - parents: request.parents.unwrap_or_default(), - content: Vec::new(), - }, - ); - send_json_response(stream, 200, json!({ "id": file_id })); - } - - fn handle_upload( - stream: &mut TcpStream, - state: &Arc>, - path: &str, - body: Vec, - ) { - let file_id = path.trim_start_matches("/upload/drive/v3/files/"); - let mut state = state.lock().expect("lock mock google drive state"); - let Some(file) = state.files.get_mut(file_id) else { - send_response( - stream, - 404, - "Not Found", - "application/json", - br#"{"error":"missing"}"#, - ); - return; - }; - file.content = body; - send_json_response(stream, 200, json!({ "id": file.id })); - } - - fn handle_download( - stream: &mut TcpStream, - state: &Arc>, - path: &str, - range_header: Option<&String>, - ) { - let file_id = path.trim_start_matches("/drive/v3/files/"); - let Some(file) = state - .lock() - .expect("lock mock google drive state") - .files - .get(file_id) - .cloned() - else { - send_response( - stream, - 404, - "Not Found", - "application/json", - br#"{"error":"missing"}"#, - ); - return; - }; - - if let Some(range_header) = range_header { - let Some((start, end)) = parse_byte_range(range_header) else { - send_response(stream, 400, "Bad Request", "text/plain", b"invalid range"); - return; - }; - if start >= file.content.len() as u64 { - send_response(stream, 416, "Range Not Satisfiable", "text/plain", b""); - return; - } - let end = end.min(file.content.len().saturating_sub(1) as u64); - let body = &file.content[start as usize..=end as usize]; - send_response( - stream, - 206, - "Partial Content", - "application/octet-stream", - body, - ); - return; - } - - send_response(stream, 200, "OK", "application/octet-stream", &file.content); - } - - fn handle_delete(stream: &mut TcpStream, state: &Arc>, path: &str) { - let file_id = path.trim_start_matches("/drive/v3/files/"); - let removed = state - .lock() - .expect("lock mock google drive state") - .files - .remove(file_id); - if removed.is_some() { - send_response(stream, 204, "No Content", "application/json", b""); - } else { - send_response( - stream, - 404, - "Not Found", - "application/json", - br#"{"error":"missing"}"#, - ); - } - } - - fn handle_copy( - stream: &mut TcpStream, - state: &Arc>, - path: &str, - body: &[u8], - ) { - let source_id = path - .trim_start_matches("/drive/v3/files/") - .trim_end_matches("/copy"); - let Ok(request) = serde_json::from_slice::(body) else { - send_response(stream, 400, "Bad Request", "text/plain", b"invalid json"); - return; - }; - let mut state = state.lock().expect("lock mock google drive state"); - let Some(source) = state.files.get(source_id).cloned() else { - send_response( - stream, - 404, - "Not Found", - "application/json", - br#"{"error":"missing"}"#, - ); - return; - }; - state.next_id += 1; - let file_id = format!("file-{}", state.next_id); - state.files.insert( - file_id.clone(), - MockDriveFile { - id: file_id.clone(), - name: request.name, - parents: request.parents.unwrap_or_default(), - content: source.content, - }, - ); - send_json_response(stream, 200, json!({ "id": file_id })); - } - - fn send_json_response(stream: &mut TcpStream, status: u16, body: serde_json::Value) { - let bytes = serde_json::to_vec(&body).expect("serialize mock google drive response"); - let reason = match status { - 200 => "OK", - 204 => "No Content", - 400 => "Bad Request", - 404 => "Not Found", - _ => "OK", - }; - send_response(stream, status, reason, "application/json", &bytes); - } - - fn send_response( - stream: &mut TcpStream, - status: u16, - reason: &str, - content_type: &str, - body: &[u8], - ) { - let response = format!( - "HTTP/1.1 {status} {reason}\r\nContent-Length: {}\r\nContent-Type: {content_type}\r\nConnection: close\r\n\r\n", - body.len() - ); - stream - .write_all(response.as_bytes()) - .expect("write mock google drive response headers"); - stream - .write_all(body) - .expect("write mock google drive response body"); - stream.flush().expect("flush mock google drive response"); - } - - fn find_header_end(buffer: &[u8]) -> Option { - buffer.windows(4).position(|window| window == b"\r\n\r\n") - } - - fn parse_query(raw: &str) -> BTreeMap { - raw.split('&') - .filter(|pair| !pair.is_empty()) - .map(|pair| { - let (name, value) = pair.split_once('=').unwrap_or((pair, "")); - (decode_component(name), decode_component(value)) - }) - .collect() - } - - fn decode_component(raw: &str) -> String { - let mut decoded = String::new(); - let bytes = raw.as_bytes(); - let mut index = 0; - while index < bytes.len() { - if bytes[index] == b'%' && index + 2 < bytes.len() { - let code = std::str::from_utf8(&bytes[index + 1..index + 3]) - .ok() - .and_then(|hex| u8::from_str_radix(hex, 16).ok()); - if let Some(code) = code { - decoded.push(code as char); - index += 3; - continue; - } - } - if bytes[index] == b'+' { - decoded.push(' '); - } else { - decoded.push(bytes[index] as char); - } - index += 1; - } - decoded - } - - fn parse_list_query(query: &str) -> Option<(String, String)> { - let name_prefix = "name = "; - let name_start = query.find(name_prefix)? + name_prefix.len(); - let (name, cursor) = parse_single_quoted_literal(query, name_start)?; - let parent_prefix = " and "; - let parent_start = query[cursor..].find(parent_prefix)? + cursor + parent_prefix.len(); - let (folder_id, _) = parse_single_quoted_literal(query, parent_start)?; - Some((name, folder_id)) - } - - fn parse_single_quoted_literal(input: &str, start: usize) -> Option<(String, usize)> { - let bytes = input.as_bytes(); - if bytes.get(start)? != &b'\'' { - return None; - } - let mut index = start + 1; - let mut decoded = String::new(); - while index < bytes.len() { - match bytes[index] { - b'\\' if index + 1 < bytes.len() => { - decoded.push(bytes[index + 1] as char); - index += 2; - } - b'\'' => return Some((decoded, index + 1)), - byte => { - decoded.push(byte as char); - index += 1; - } - } - } - None - } - - fn parse_byte_range(header: &str) -> Option<(u64, u64)> { - let value = header.strip_prefix("bytes=")?; - let (start, end) = value.split_once('-')?; - Some((start.parse().ok()?, end.parse().ok()?)) - } -} diff --git a/crates/sidecar/src/plugins/host_dir.rs b/crates/sidecar/src/plugins/host_dir.rs deleted file mode 100644 index 8c977c9f3..000000000 --- a/crates/sidecar/src/plugins/host_dir.rs +++ /dev/null @@ -1,1290 +0,0 @@ -use nix::errno::Errno; -#[cfg(not(target_os = "macos"))] -use nix::fcntl::{openat2, OpenHow, ResolveFlag}; -use nix::fcntl::{readlinkat, renameat, AtFlags, OFlag}; -use nix::libc; - -// macOS has no `O_PATH` (metadata-only anchor fd). The host-mount code only uses -// O_PATH fds as anchors that are re-opened via `/dev/fd/N`, so a read-only open -// is an adequate stand-in there; the real access mode is applied on re-open. -#[cfg(not(target_os = "macos"))] -const O_PATH_ANCHOR: OFlag = OFlag::O_PATH; -#[cfg(target_os = "macos")] -const O_PATH_ANCHOR: OFlag = OFlag::O_RDONLY; -use nix::sys::stat::{fstatat, mkdirat, utimensat, Mode, SFlag, UtimensatFlags}; -use nix::sys::time::TimeSpec; -use nix::unistd::{chown, linkat, symlinkat, unlinkat, Gid, Uid, UnlinkatFlags}; -use secure_exec_execution::{ - GuestModuleReader, LocalModuleResolutionCache, ModuleFsReader, ModuleResolveMode, - ModuleResolver, -}; -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::{ - MountedFileSystem, MountedVirtualFileSystem, ReadOnlyFileSystem, -}; -use secure_exec_kernel::resource_accounting::DEFAULT_MAX_PREAD_BYTES; -use secure_exec_kernel::vfs::{ - normalize_path, VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, - VirtualTimeSpec, VirtualUtimeSpec, -}; -use serde::Deserialize; -use std::fs::{self, File}; -use std::io::{self, Read, Write}; -use std::os::fd::{AsRawFd, RawFd}; -use std::os::unix::fs::{FileExt, MetadataExt, OpenOptionsExt, PermissionsExt}; -use std::path::{Component, Path, PathBuf}; -use std::sync::Arc; - -const MAX_HOST_DIR_READ_BYTES: usize = DEFAULT_MAX_PREAD_BYTES; - -#[derive(Debug)] -struct AnchoredFd { - fd: RawFd, -} - -impl AnchoredFd { - #[cfg(not(target_os = "macos"))] - fn proc_path(&self) -> PathBuf { - PathBuf::from(format!("/proc/self/fd/{}", self.fd)) - } - - // macOS exposes per-fd paths under `/dev/fd/N` (the kernel dups the fd), - // serving the same role as Linux's `/proc/self/fd/N` for re-opening a - // *file* fd. Unlike `/proc/self/fd/N` it is NOT a readdir-able directory, - // so directory enumeration goes through [`readdir_path`]; child mutations - // use the fd-relative `*at` syscalls below. - #[cfg(target_os = "macos")] - fn proc_path(&self) -> PathBuf { - PathBuf::from(format!("/dev/fd/{}", self.fd)) - } - - // Path to enumerate this fd's directory entries. Linux can `readdir` - // `/proc/self/fd/N` directly; macOS `/dev/fd/N` yields `ENOTDIR`, so recover - // the fd's real host path via `fcntl(F_GETPATH)` (see [`anchored_fd_real_path`]). - #[cfg(not(target_os = "macos"))] - fn readdir_path(&self) -> io::Result { - Ok(self.proc_path()) - } - #[cfg(target_os = "macos")] - fn readdir_path(&self) -> io::Result { - anchored_fd_real_path(self) - } -} - -impl AsRawFd for AnchoredFd { - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -impl Drop for AnchoredFd { - fn drop(&mut self) { - let _ = nix::unistd::close(self.fd); - } -} - -/// Recover the real host path an anchored fd points at. Linux reads the magic -/// symlink `/proc/self/fd/N`; macOS uses `fcntl(F_GETPATH)` (see -/// [`crate::macos_fs::fd_real_path`]). -#[cfg(not(target_os = "macos"))] -fn anchored_fd_real_path(fd: &AnchoredFd) -> io::Result { - fs::read_link(fd.proc_path()) -} - -#[cfg(target_os = "macos")] -fn anchored_fd_real_path(fd: &AnchoredFd) -> io::Result { - crate::macos_fs::fd_real_path(fd.as_raw_fd()) -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct HostDirMountConfig { - host_path: String, - read_only: Option, -} - -#[derive(Debug)] -pub(crate) struct HostDirMountPlugin; - -pub(crate) trait HostDirReadLimitContext { - fn host_dir_max_read_bytes(&self) -> Option; -} - -impl HostDirReadLimitContext for () { - fn host_dir_max_read_bytes(&self) -> Option { - Some(MAX_HOST_DIR_READ_BYTES) - } -} - -impl FileSystemPluginFactory for HostDirMountPlugin -where - Context: HostDirReadLimitContext, -{ - fn plugin_id(&self) -> &'static str { - "host_dir" - } - - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - let max_read_bytes = request.context.host_dir_max_read_bytes(); - self.open_with_read_limit(request, max_read_bytes) - } -} - -impl HostDirMountPlugin { - fn open_with_read_limit( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - max_read_bytes: Option, - ) -> Result, PluginError> { - let config: HostDirMountConfig = serde_json::from_value(request.config.clone()) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - let filesystem = HostDirFilesystem::new_with_read_limit(&config.host_path, max_read_bytes)?; - let mounted = MountedVirtualFileSystem::new(filesystem); - - if config.read_only.unwrap_or(false) { - Ok(Box::new(ReadOnlyFileSystem::new(mounted))) - } else { - Ok(Box::new(mounted)) - } - } -} - -#[derive(Debug, Clone)] -pub(crate) struct HostDirFilesystem { - host_root: PathBuf, - host_root_dir: Arc, - max_read_bytes: Option, -} - -impl HostDirFilesystem { - #[allow(dead_code)] - pub(crate) fn new(host_path: impl AsRef) -> VfsResult { - Self::new_with_read_limit(host_path, Some(MAX_HOST_DIR_READ_BYTES)) - } - - pub(crate) fn new_with_read_limit( - host_path: impl AsRef, - max_read_bytes: Option, - ) -> VfsResult { - let host_path_str = host_path.as_ref().to_string_lossy().into_owned(); - let canonical_root = fs::canonicalize(host_path.as_ref()) - .map_err(|error| io_error_to_vfs("open", &host_path_str, error))?; - let metadata = fs::metadata(&canonical_root) - .map_err(|error| io_error_to_vfs("stat", &host_path_str, error))?; - if !metadata.is_dir() { - return Err(VfsError::new( - "ENOTDIR", - format!( - "host_dir root is not a directory: {}", - canonical_root.display() - ), - )); - } - - Ok(Self { - host_root: canonical_root.clone(), - host_root_dir: Arc::new( - File::open(&canonical_root).map_err(|error| io_error_to_vfs("open", "/", error))?, - ), - max_read_bytes, - }) - } - - fn ensure_within_root(&self, resolved: &Path, virtual_path: &str) -> VfsResult<()> { - if resolved == self.host_root { - return Ok(()); - } - - if resolved.starts_with(&self.host_root) { - return Ok(()); - } - - Err(VfsError::access_denied( - "open", - virtual_path, - Some("path escapes host directory"), - )) - } - - fn lexical_host_path(&self, path: &str) -> VfsResult { - let normalized = normalize_path(path); - let relative = normalized.trim_start_matches('/'); - let joined = lexical_normalize_path(&self.host_root.join(relative)); - self.ensure_within_root(&joined, &normalized)?; - Ok(joined) - } - - fn relative_virtual_path(&self, path: &str) -> (String, PathBuf) { - let normalized = normalize_path(path); - let relative = normalized.trim_start_matches('/'); - let relative = if relative.is_empty() { - PathBuf::from(".") - } else { - PathBuf::from(relative) - }; - (normalized, relative) - } - - #[cfg(not(target_os = "macos"))] - fn resolve_flags() -> ResolveFlag { - ResolveFlag::RESOLVE_BENEATH | ResolveFlag::RESOLVE_NO_MAGICLINKS - } - - fn open_beneath(&self, relative: &Path, flags: OFlag, mode: Mode) -> VfsResult { - let relative_display = relative.display().to_string(); - let fd = self - .resolve_beneath_fd(relative, flags, mode) - .map_err(|error| match error { - Errno::EXDEV => VfsError::access_denied( - "open", - &relative_display, - Some("path escapes host directory"), - ), - other => io_error_to_vfs("open", &relative_display, nix_to_io(other)), - })?; - Ok(AnchoredFd { fd }) - } - - /// Open `relative` strictly beneath the mount root, returning an owned raw - /// fd. Linux uses `openat2(RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS)`; macOS - /// has no such syscall and uses cap-std's audited resolve-beneath instead - /// (see [`crate::macos_fs`]). - #[cfg(not(target_os = "macos"))] - fn resolve_beneath_fd( - &self, - relative: &Path, - flags: OFlag, - mode: Mode, - ) -> Result { - openat2( - self.host_root_dir.as_raw_fd(), - relative, - OpenHow::new() - .flags(flags | OFlag::O_CLOEXEC) - .mode(mode) - .resolve(Self::resolve_flags()), - ) - } - - #[cfg(target_os = "macos")] - fn resolve_beneath_fd( - &self, - relative: &Path, - flags: OFlag, - mode: Mode, - ) -> Result { - crate::macos_fs::resolve_beneath(&self.host_root, relative, flags, mode) - } - - fn open_directory_beneath(&self, relative: &Path) -> VfsResult { - self.open_beneath( - relative, - OFlag::O_DIRECTORY | OFlag::O_RDONLY, - Mode::empty(), - ) - } - - fn host_path_for_fd(&self, fd: &AnchoredFd, virtual_path: &str) -> VfsResult { - let host_path = anchored_fd_real_path(fd) - .map_err(|error| io_error_to_vfs("open", virtual_path, error))?; - self.ensure_within_root(&host_path, virtual_path)?; - Ok(host_path) - } - - #[cfg(not(target_os = "macos"))] - fn open_metadata_beneath(&self, path: &str, op: &'static str) -> VfsResult { - let (_, relative) = self.relative_virtual_path(path); - let handle = - self.open_beneath(&relative, O_PATH_ANCHOR | OFlag::O_NOFOLLOW, Mode::empty())?; - let metadata = - fs::metadata(handle.proc_path()).map_err(|error| io_error_to_vfs(op, path, error))?; - if metadata.file_type().is_symlink() { - return Err(VfsError::new( - "EPERM", - format!("{op} '{path}': metadata operations do not follow symlinks"), - )); - } - Ok(handle) - } - - // macOS has no `O_PATH`, and `open(O_NOFOLLOW)` on a symlink fails outright, - // so the Linux path above (open the link as an anchor, then inspect it) - // cannot run — the resolve-beneath refusal instead surfaces as `EACCES`, - // diverging from Linux's `EPERM`. Detect the symlink directly: `lstat` the - // final component through the resolved parent fd and reject it with `EPERM`; - // otherwise open the (non-symlink) target as the metadata anchor. - #[cfg(target_os = "macos")] - fn open_metadata_beneath(&self, path: &str, op: &'static str) -> VfsResult { - // The mount root has no final component to lstat and is always a - // directory (never a symlink), so open it directly as the anchor — - // matching Linux, where the `O_PATH | O_NOFOLLOW` open of the root - // succeeds. (`split_parent` would otherwise reject `/` with EINVAL.) - let (_, root_relative) = self.relative_virtual_path(path); - if root_relative.file_name().is_none() { - return self.open_beneath(&root_relative, O_PATH_ANCHOR, Mode::empty()); - } - let (parent_dir, _, name, normalized) = self.split_parent(path, false)?; - let stat = fstatat( - Some(parent_dir.as_raw_fd()), - name.as_os_str(), - AtFlags::AT_SYMLINK_NOFOLLOW, - ) - .map_err(|error| io_error_to_vfs(op, &normalized, nix_to_io(error)))?; - if stat.st_mode & SFlag::S_IFMT.bits() == SFlag::S_IFLNK.bits() { - return Err(VfsError::new( - "EPERM", - format!("{op} '{path}': metadata operations do not follow symlinks"), - )); - } - let (_, relative) = self.relative_virtual_path(path); - self.open_beneath(&relative, O_PATH_ANCHOR, Mode::empty()) - } - - fn ensure_directory_tree( - &self, - relative_dir: &Path, - virtual_path: &str, - mode: u32, - ) -> VfsResult<()> { - if relative_dir == Path::new(".") { - return Ok(()); - } - - let mut prefix = PathBuf::new(); - for component in relative_dir.components() { - match component { - Component::Normal(segment) => prefix.push(segment), - Component::CurDir => continue, - _ => { - return Err(VfsError::new( - "EINVAL", - format!("invalid host_dir component in {virtual_path}"), - )); - } - } - - if self.open_directory_beneath(&prefix).is_ok() { - continue; - } - - let parent = match prefix.parent() { - Some(parent) if !parent.as_os_str().is_empty() => parent, - _ => Path::new("."), - }; - let parent_dir = self.open_directory_beneath(parent)?; - let name = prefix.file_name().ok_or_else(|| { - VfsError::new("EINVAL", format!("invalid directory path: {virtual_path}")) - })?; - match mkdirat( - Some(parent_dir.as_raw_fd()), - name, - Mode::from_bits_truncate(mode as _), - ) { - Ok(()) => {} - Err(Errno::EEXIST) => {} - Err(error) => { - return Err(io_error_to_vfs("mkdir", virtual_path, nix_to_io(error))); - } - } - } - - Ok(()) - } - - fn split_parent( - &self, - path: &str, - create_parent_dirs: bool, - ) -> VfsResult<(AnchoredFd, PathBuf, std::ffi::OsString, String)> { - let (normalized, relative) = self.relative_virtual_path(path); - let name = relative.file_name().ok_or_else(|| { - VfsError::new( - "EINVAL", - format!("path does not reference an entry: {normalized}"), - ) - })?; - let parent = match relative.parent() { - Some(parent) if !parent.as_os_str().is_empty() => parent.to_path_buf(), - _ => PathBuf::from("."), - }; - if create_parent_dirs { - self.ensure_directory_tree(&parent, &normalized, 0o755)?; - } - let parent_dir = self.open_directory_beneath(&parent)?; - Ok((parent_dir, parent, name.to_os_string(), normalized)) - } - - fn host_to_virtual_path(&self, host_path: &Path, virtual_path: &str) -> VfsResult { - let normalized = lexical_normalize_path(host_path); - self.ensure_within_root(&normalized, virtual_path)?; - let relative = normalized.strip_prefix(&self.host_root).map_err(|_| { - VfsError::access_denied("open", virtual_path, Some("path escapes host directory")) - })?; - - if relative.as_os_str().is_empty() { - return Ok(String::from("/")); - } - - let segments = relative - .components() - .filter_map(|component| match component { - Component::Normal(segment) => Some(segment.to_string_lossy().into_owned()), - _ => None, - }) - .collect::>(); - Ok(format!("/{}", segments.join("/"))) - } - - fn existing_utime_specs( - &self, - parent_dir: &AnchoredFd, - name: &std::ffi::OsStr, - virtual_path: &str, - follow_symlinks: bool, - ) -> VfsResult<(VirtualTimeSpec, VirtualTimeSpec)> { - let flags = if follow_symlinks { - AtFlags::empty() - } else { - AtFlags::AT_SYMLINK_NOFOLLOW - }; - let stat = fstatat(Some(parent_dir.as_raw_fd()), name, flags) - .map_err(|error| io_error_to_vfs("utimes", virtual_path, nix_to_io(error)))?; - let atime = VirtualTimeSpec::new( - stat.st_atime, - stat.st_atime_nsec.clamp(0, 999_999_999) as u32, - )?; - let mtime = VirtualTimeSpec::new( - stat.st_mtime, - stat.st_mtime_nsec.clamp(0, 999_999_999) as u32, - )?; - Ok((atime, mtime)) - } - - fn resolve_utime_timespec(spec: VirtualUtimeSpec, existing: VirtualTimeSpec) -> TimeSpec { - match spec { - VirtualUtimeSpec::Set(spec) => TimeSpec::new(spec.sec, spec.nsec as libc::c_long), - VirtualUtimeSpec::Now => TimeSpec::new(0, libc::UTIME_NOW), - VirtualUtimeSpec::Omit => TimeSpec::new(existing.sec, libc::UTIME_OMIT), - } - } - - fn apply_utimens( - &self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - if follow_symlinks { - let _ = self.open_metadata_beneath(path, "utimes")?; - } - let (parent_dir, _, name, normalized) = self.split_parent(path, false)?; - let existing = match (atime, mtime) { - (VirtualUtimeSpec::Omit, _) | (_, VirtualUtimeSpec::Omit) => { - Some(self.existing_utime_specs( - &parent_dir, - name.as_os_str(), - &normalized, - follow_symlinks, - )?) - } - _ => None, - }; - let existing_atime = existing - .as_ref() - .map(|(atime, _)| *atime) - .unwrap_or(VirtualTimeSpec { sec: 0, nsec: 0 }); - let existing_mtime = existing - .as_ref() - .map(|(_, mtime)| *mtime) - .unwrap_or(VirtualTimeSpec { sec: 0, nsec: 0 }); - let times = [ - Self::resolve_utime_timespec(atime, existing_atime), - Self::resolve_utime_timespec(mtime, existing_mtime), - ]; - let flags = if follow_symlinks { - UtimensatFlags::FollowSymlink - } else { - UtimensatFlags::NoFollowSymlink - }; - utimensat( - Some(parent_dir.as_raw_fd()), - name.as_os_str(), - ×[0], - ×[1], - flags, - ) - .map_err(|error| io_error_to_vfs("utimes", &normalized, nix_to_io(error))) - } - - fn stat_from_metadata(metadata: fs::Metadata) -> VirtualStat { - let atime_ms = metadata.atime().max(0) as u64 * 1_000 - + (metadata.atime_nsec().max(0) as u64 / 1_000_000); - let atime_nsec = metadata.atime_nsec().clamp(0, 999_999_999) as u32; - let mtime_ms = metadata.mtime().max(0) as u64 * 1_000 - + (metadata.mtime_nsec().max(0) as u64 / 1_000_000); - let mtime_nsec = metadata.mtime_nsec().clamp(0, 999_999_999) as u32; - let ctime_ms = metadata.ctime().max(0) as u64 * 1_000 - + (metadata.ctime_nsec().max(0) as u64 / 1_000_000); - let ctime_nsec = metadata.ctime_nsec().clamp(0, 999_999_999) as u32; - VirtualStat { - mode: metadata.mode(), - size: metadata.size(), - blocks: metadata.blocks(), - dev: metadata.dev(), - rdev: metadata.rdev(), - is_directory: metadata.is_dir(), - is_symbolic_link: metadata.file_type().is_symlink(), - atime_ms, - atime_nsec, - mtime_ms, - mtime_nsec, - ctime_ms, - ctime_nsec, - birthtime_ms: ctime_ms, - ino: metadata.ino(), - nlink: metadata.nlink(), - uid: metadata.uid(), - gid: metadata.gid(), - } - } - - #[allow(clippy::unnecessary_cast)] - fn stat_from_file_stat(stat: nix::sys::stat::FileStat) -> VirtualStat { - let file_type = SFlag::from_bits_truncate(stat.st_mode); - let atime_ms = - stat.st_atime.max(0) as u64 * 1_000 + (stat.st_atime_nsec.max(0) as u64 / 1_000_000); - let atime_nsec = stat.st_atime_nsec.clamp(0, 999_999_999) as u32; - let mtime_ms = - stat.st_mtime.max(0) as u64 * 1_000 + (stat.st_mtime_nsec.max(0) as u64 / 1_000_000); - let mtime_nsec = stat.st_mtime_nsec.clamp(0, 999_999_999) as u32; - let ctime_ms = - stat.st_ctime.max(0) as u64 * 1_000 + (stat.st_ctime_nsec.max(0) as u64 / 1_000_000); - let ctime_nsec = stat.st_ctime_nsec.clamp(0, 999_999_999) as u32; - - VirtualStat { - // Widen for platform differences: mode_t/dev_t/nlink_t are narrower - // on macOS (u16/i32/u16) than on Linux. - mode: stat.st_mode as u32, - size: stat.st_size as u64, - blocks: stat.st_blocks as u64, - dev: stat.st_dev as u64, - rdev: stat.st_rdev as u64, - is_directory: file_type == SFlag::S_IFDIR, - is_symbolic_link: file_type == SFlag::S_IFLNK, - atime_ms, - atime_nsec, - mtime_ms, - mtime_nsec, - ctime_ms, - ctime_nsec, - birthtime_ms: ctime_ms, - ino: stat.st_ino, - // st_nlink is u64 on x86_64 but u32 on aarch64 / u16 on macOS; widen. - nlink: stat.st_nlink as u64, - uid: stat.st_uid, - gid: stat.st_gid, - } - } - - fn write_all_at( - &self, - file: &File, - content: &[u8], - mut offset: u64, - path: &str, - ) -> VfsResult<()> { - let mut written = 0usize; - while written < content.len() { - let bytes_written = file - .write_at(&content[written..], offset) - .map_err(|error| io_error_to_vfs("write", path, error))?; - if bytes_written == 0 { - return Err(io_error_to_vfs( - "write", - path, - io::Error::new(io::ErrorKind::WriteZero, "failed to write whole buffer"), - )); - } - - written += bytes_written; - offset = offset.checked_add(bytes_written as u64).ok_or_else(|| { - VfsError::new("EINVAL", format!("pwrite offset overflow: {path}")) - })?; - } - - Ok(()) - } - - fn check_read_length(&self, path: &str, length: usize) -> VfsResult<()> { - if let Some(limit) = self.max_read_bytes { - if length <= limit { - return Ok(()); - } - - return Err(VfsError::new( - "EINVAL", - format!("read length {length} exceeds host_dir limit {limit}: {path}"), - )); - } - - Ok(()) - } - - fn check_full_read_metadata(&self, path: &str, size: u64) -> VfsResult<()> { - if let Some(limit) = self.max_read_bytes { - if size <= limit as u64 { - return Ok(()); - } - - return Err(VfsError::new( - "EINVAL", - format!("file size {size} exceeds host_dir read limit {limit}: {path}"), - )); - } - - Ok(()) - } - - fn read_to_end_bounded(&self, file: &mut File, path: &str) -> VfsResult> { - let mut buffer = Vec::new(); - match self.max_read_bytes { - Some(limit) => { - Read::by_ref(file) - .take((limit as u64).saturating_add(1)) - .read_to_end(&mut buffer) - .map_err(|error| io_error_to_vfs("open", path, error))?; - } - None => { - file.read_to_end(&mut buffer) - .map_err(|error| io_error_to_vfs("open", path, error))?; - } - } - self.check_read_length(path, buffer.len())?; - Ok(buffer) - } - - fn write_file_with_creation_mode( - &mut self, - path: &str, - content: Vec, - file_mode: u32, - ) -> VfsResult<()> { - let (_, relative) = self.relative_virtual_path(path); - if let Some(parent) = relative.parent() { - self.ensure_directory_tree(parent, path, 0o755)?; - } - let handle = self.open_beneath( - &relative, - OFlag::O_WRONLY | OFlag::O_CREAT | OFlag::O_TRUNC, - Mode::from_bits_truncate(file_mode as _), - )?; - let mut file = File::options() - .write(true) - .custom_flags(libc::O_CLOEXEC) - .open(handle.proc_path()) - .map_err(|error| io_error_to_vfs("write", path, error))?; - file.write_all(&content) - .map_err(|error| io_error_to_vfs("write", path, error)) - } - - fn create_dir_with_creation_mode(&mut self, path: &str, mode: u32) -> VfsResult<()> { - let (parent_dir, _, name, normalized) = self.split_parent(path, false)?; - mkdirat( - Some(parent_dir.as_raw_fd()), - name.as_os_str(), - Mode::from_bits_truncate(mode as _), - ) - .map_err(|error| io_error_to_vfs("mkdir", &normalized, nix_to_io(error))) - } - - fn mkdir_with_creation_mode( - &mut self, - path: &str, - recursive: bool, - mode: u32, - ) -> VfsResult<()> { - if recursive { - let (normalized, relative) = self.relative_virtual_path(path); - self.ensure_directory_tree(&relative, &normalized, mode) - } else { - self.create_dir_with_creation_mode(path, mode) - } - } -} - -impl VirtualFileSystem for HostDirFilesystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - let (_, relative) = self.relative_virtual_path(path); - let handle = self.open_beneath(&relative, OFlag::O_RDONLY, Mode::empty())?; - let mut file = - File::open(handle.proc_path()).map_err(|error| io_error_to_vfs("open", path, error))?; - self.check_full_read_metadata( - path, - file.metadata() - .map_err(|error| io_error_to_vfs("open", path, error))? - .len(), - )?; - self.read_to_end_bounded(&mut file, path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - let (_, relative) = self.relative_virtual_path(path); - let directory = self.open_directory_beneath(&relative)?; - let readdir_path = directory - .readdir_path() - .map_err(|error| io_error_to_vfs("readdir", path, error))?; - let mut entries = fs::read_dir(readdir_path) - .map_err(|error| io_error_to_vfs("readdir", path, error))? - .map(|entry| { - entry - .map_err(|error| io_error_to_vfs("readdir", path, error)) - .map(|entry| entry.file_name().to_string_lossy().into_owned()) - }) - .collect::>>()?; - entries.sort(); - Ok(entries) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - let (_, relative) = self.relative_virtual_path(path); - let directory = self.open_directory_beneath(&relative)?; - let readdir_path = directory - .readdir_path() - .map_err(|error| io_error_to_vfs("readdir", path, error))?; - let mut entries = fs::read_dir(readdir_path) - .map_err(|error| io_error_to_vfs("readdir", path, error))? - .map(|entry| { - let entry = entry.map_err(|error| io_error_to_vfs("readdir", path, error))?; - let file_type = entry - .file_type() - .map_err(|error| io_error_to_vfs("readdir", path, error))?; - Ok(VirtualDirEntry { - name: entry.file_name().to_string_lossy().into_owned(), - is_directory: file_type.is_dir(), - is_symbolic_link: file_type.is_symlink(), - }) - }) - .collect::>>()?; - entries.sort_by(|left, right| left.name.cmp(&right.name)); - Ok(entries) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - self.write_file_with_creation_mode(path, content.into(), 0o644) - } - - fn write_file_with_mode( - &mut self, - path: &str, - content: impl Into>, - mode: Option, - ) -> VfsResult<()> { - self.write_file_with_creation_mode(path, content.into(), mode.unwrap_or(0o666)) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - self.create_dir_with_creation_mode(path, 0o755) - } - - fn create_dir_with_mode(&mut self, path: &str, mode: Option) -> VfsResult<()> { - self.create_dir_with_creation_mode(path, mode.unwrap_or(0o777)) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - self.mkdir_with_creation_mode(path, recursive, 0o755) - } - - fn mkdir_with_mode(&mut self, path: &str, recursive: bool, mode: Option) -> VfsResult<()> { - self.mkdir_with_creation_mode(path, recursive, mode.unwrap_or(0o777)) - } - - fn exists(&self, path: &str) -> bool { - let (_, relative) = self.relative_virtual_path(path); - self.open_beneath(&relative, O_PATH_ANCHOR, Mode::empty()) - .is_ok() - } - - fn stat(&mut self, path: &str) -> VfsResult { - let (_, relative) = self.relative_virtual_path(path); - let handle = self.open_beneath(&relative, O_PATH_ANCHOR, Mode::empty())?; - fs::metadata(handle.proc_path()) - .map(Self::stat_from_metadata) - .map_err(|error| io_error_to_vfs("stat", path, error)) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - let (parent_dir, _, name, normalized) = self.split_parent(path, false)?; - unlinkat( - Some(parent_dir.as_raw_fd()), - name.as_os_str(), - UnlinkatFlags::NoRemoveDir, - ) - .map_err(|error| io_error_to_vfs("unlink", &normalized, nix_to_io(error))) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - let (parent_dir, _, name, normalized) = self.split_parent(path, false)?; - unlinkat( - Some(parent_dir.as_raw_fd()), - name.as_os_str(), - UnlinkatFlags::RemoveDir, - ) - .map_err(|error| io_error_to_vfs("rmdir", &normalized, nix_to_io(error))) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let (old_parent_dir, _, old_name, old_normalized) = self.split_parent(old_path, false)?; - let (new_parent_dir, _, new_name, _) = self.split_parent(new_path, true)?; - renameat( - Some(old_parent_dir.as_raw_fd()), - old_name.as_os_str(), - Some(new_parent_dir.as_raw_fd()), - new_name.as_os_str(), - ) - .map_err(|error| io_error_to_vfs("rename", &old_normalized, nix_to_io(error))) - } - - fn realpath(&self, path: &str) -> VfsResult { - let (_, relative) = self.relative_virtual_path(path); - let file = self.open_beneath(&relative, O_PATH_ANCHOR, Mode::empty())?; - let resolved = self.host_path_for_fd(&file, path)?; - self.host_to_virtual_path(&resolved, path) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - let (parent_dir, _, name, normalized) = self.split_parent(link_path, true)?; - let parent_host_path = self.host_path_for_fd(&parent_dir, &normalized)?; - let host_link_path = parent_host_path.join(&name); - - let link_virtual_path = normalize_path(link_path); - let target_virtual_path = if target.starts_with('/') { - normalize_path(target) - } else { - normalize_path(&format!( - "{}/{}", - virtual_dirname(&link_virtual_path), - target - )) - }; - let host_target_path = self.lexical_host_path(&target_virtual_path)?; - let relative_target = relative_path( - host_link_path.parent().unwrap_or(self.host_root.as_path()), - &host_target_path, - ); - symlinkat( - &relative_target, - Some(parent_dir.as_raw_fd()), - name.as_os_str(), - ) - .map_err(|error| io_error_to_vfs("symlink", link_path, nix_to_io(error))) - } - - fn read_link(&self, path: &str) -> VfsResult { - let (parent_dir, _, name, normalized) = self.split_parent(path, false)?; - let parent_host_path = self.host_path_for_fd(&parent_dir, &normalized)?; - let host_link_path = parent_host_path.join(&name); - let link_target = readlinkat(Some(parent_dir.as_raw_fd()), name.as_os_str()) - .map_err(|error| io_error_to_vfs("readlink", path, nix_to_io(error)))?; - let link_target_path = PathBuf::from(&link_target); - let resolved_target = if link_target_path.is_absolute() { - lexical_normalize_path(&link_target_path) - } else { - lexical_normalize_path( - &host_link_path - .parent() - .unwrap_or(self.host_root.as_path()) - .join(link_target_path), - ) - }; - self.host_to_virtual_path(&resolved_target, path) - } - - fn lstat(&self, path: &str) -> VfsResult { - if normalize_path(path) == "/" { - return self - .host_root_dir - .metadata() - .map(Self::stat_from_metadata) - .map_err(|error| io_error_to_vfs("lstat", path, error)); - } - - let (parent_dir, _, name, normalized) = self.split_parent(path, false)?; - fstatat( - Some(parent_dir.as_raw_fd()), - name.as_os_str(), - AtFlags::AT_SYMLINK_NOFOLLOW, - ) - .map(Self::stat_from_file_stat) - .map_err(|error| io_error_to_vfs("lstat", &normalized, nix_to_io(error))) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let (old_parent_dir, _, old_name, _) = self.split_parent(old_path, false)?; - let (new_parent_dir, _, new_name, new_normalized) = self.split_parent(new_path, true)?; - linkat( - Some(old_parent_dir.as_raw_fd()), - old_name.as_os_str(), - Some(new_parent_dir.as_raw_fd()), - new_name.as_os_str(), - AtFlags::empty(), - ) - .map_err(|error| io_error_to_vfs("link", &new_normalized, nix_to_io(error))) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - let handle = self.open_metadata_beneath(path, "chmod")?; - fs::set_permissions(handle.proc_path(), fs::Permissions::from_mode(mode)) - .map_err(|error| io_error_to_vfs("chmod", path, error)) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - let handle = self.open_metadata_beneath(path, "chown")?; - chown( - handle.proc_path().as_path(), - Some(Uid::from_raw(uid)), - Some(Gid::from_raw(gid)), - ) - .map_err(|error| VfsError::new(error_code(&error), error.to_string())) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - self.apply_utimens( - path, - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(atime_ms)), - VirtualUtimeSpec::Set(VirtualTimeSpec::from_millis(mtime_ms)), - true, - ) - } - - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - self.apply_utimens(path, atime, mtime, follow_symlinks) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - let (_, relative) = self.relative_virtual_path(path); - let handle = self.open_beneath(&relative, OFlag::O_WRONLY, Mode::empty())?; - let file = File::options() - .write(true) - .open(handle.proc_path()) - .map_err(|error| io_error_to_vfs("truncate", path, error))?; - file.set_len(length) - .map_err(|error| io_error_to_vfs("truncate", path, error)) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - self.check_read_length(path, length)?; - let (_, relative) = self.relative_virtual_path(path); - let handle = self.open_beneath(&relative, OFlag::O_RDONLY, Mode::empty())?; - let file = - File::open(handle.proc_path()).map_err(|error| io_error_to_vfs("open", path, error))?; - let mut buffer = vec![0; length]; - let bytes_read = file - .read_at(&mut buffer, offset) - .map_err(|error| io_error_to_vfs("open", path, error))?; - buffer.truncate(bytes_read); - Ok(buffer) - } - - fn pwrite(&mut self, path: &str, content: impl Into>, offset: u64) -> VfsResult<()> { - let (_, relative) = self.relative_virtual_path(path); - let handle = self.open_beneath(&relative, OFlag::O_WRONLY, Mode::empty())?; - let file = File::options() - .write(true) - .open(handle.proc_path()) - .map_err(|error| io_error_to_vfs("open", path, error))?; - let content = content.into(); - self.write_all_at(&file, &content, offset, path) - } -} - -/// One read-only `host_dir`/`module_access` mount, keyed by its guest mount -/// point. The filesystem reads mount-relative virtual paths (e.g. `/foo/index.js` -/// for a mount at `/root/node_modules`). -// `dead_code` is allowed because `host_dir.rs` is also `#[path]`-included by -// `tests/host_dir.rs`, whose test compilation exercises only the filesystem -// plugin and not the module-reader path (which the real lib build does use). -#[allow(dead_code)] -#[derive(Clone)] -struct HostDirModuleMount { - /// Normalized guest mount point, e.g. `/root/node_modules`. - guest_prefix: String, - filesystem: HostDirFilesystem, -} - -#[allow(dead_code)] -impl HostDirModuleMount { - /// If `guest_path` falls under this mount, return the mount-relative virtual - /// path (always absolute, e.g. `/foo/index.js`). - fn relative_virtual_path(&self, guest_path: &str) -> Option { - if guest_path == self.guest_prefix { - return Some(String::from("/")); - } - let prefix_with_sep = if self.guest_prefix == "/" { - String::from("/") - } else { - format!("{}/", self.guest_prefix) - }; - let rest = guest_path.strip_prefix(&prefix_with_sep)?; - Some(format!("/{rest}")) - } - - /// Re-express a mount-relative virtual path (e.g. `/foo/index.js`) as a guest - /// path under this mount (e.g. `/root/node_modules/foo/index.js`). - fn guest_path_for_relative(&self, relative: &str) -> String { - let trimmed = relative.trim_start_matches('/'); - if self.guest_prefix == "/" { - if trimmed.is_empty() { - String::from("/") - } else { - format!("/{trimmed}") - } - } else if trimmed.is_empty() { - self.guest_prefix.clone() - } else { - format!("{}/{trimmed}", self.guest_prefix) - } - } -} - -/// A `Send`-able, clonable, read-only [`ModuleFsReader`] over one or more mounted -/// `host_dir`/`module_access` filesystems. It lets module resolution run on the -/// V8 bridge thread — concurrently with the sidecar service loop — while still -/// reading exactly the mounted `node_modules` tree the guest sees (anchored -/// `openat2(RESOLVE_BENEATH)` with escaping-symlink refusal), instead of the -/// host-direct path translator. -/// -/// It never touches the `&mut` kernel, so a large cold-start module graph cannot -/// serialize behind / starve work on the service-loop thread (e.g. an ACP -/// `session/new` bootstrap awaiting the adapter's response on that same loop). -#[allow(dead_code)] -#[derive(Clone)] -pub(crate) struct HostDirModuleReader { - /// Mounts sorted longest-`guest_prefix`-first so the most specific mount - /// wins (mirrors the kernel mount table's longest-prefix dispatch). - mounts: Vec, -} - -#[allow(dead_code)] -impl HostDirModuleReader { - /// Build a reader from `(guest_path, host_path)` pairs for the VM's read-only - /// `host_dir`/`module_access` mounts. Mounts whose host root cannot be opened - /// are skipped. Returns `None` if no usable mount remains, so callers fall - /// back to the service-loop kernel reader. - pub(crate) fn from_mounts(mounts: I) -> Option - where - I: IntoIterator, - G: AsRef, - H: AsRef, - { - let mut entries = mounts - .into_iter() - .filter_map(|(guest_path, host_path)| { - let filesystem = HostDirFilesystem::new_with_read_limit( - host_path.as_ref(), - Some(MAX_HOST_DIR_READ_BYTES), - ) - .ok()?; - Some(HostDirModuleMount { - guest_prefix: normalize_path(guest_path.as_ref()), - filesystem, - }) - }) - .collect::>(); - if entries.is_empty() { - return None; - } - entries.sort_by_key(|entry| std::cmp::Reverse(entry.guest_prefix.len())); - entries.dedup_by(|left, right| left.guest_prefix == right.guest_prefix); - Some(Self { mounts: entries }) - } - - /// Find the index of the most-specific mount containing `guest_path` and the - /// corresponding mount-relative virtual path. - fn mount_index_for(&self, guest_path: &str) -> Option<(usize, String)> { - let normalized = normalize_path(guest_path); - self.mounts.iter().enumerate().find_map(|(index, mount)| { - mount - .relative_virtual_path(&normalized) - .map(|rel| (index, rel)) - }) - } -} - -impl ModuleFsReader for HostDirModuleReader { - fn canonical_guest_path(&mut self, guest_path: &str) -> Option { - let (index, relative) = self.mount_index_for(guest_path)?; - let mount = &self.mounts[index]; - // `realpath` returns a mount-relative virtual path; re-express it as a - // guest path so the resolver keeps operating in the guest namespace. - let resolved = mount.filesystem.realpath(&relative).ok()?; - Some(mount.guest_path_for_relative(&resolved)) - } - - fn read_to_string(&mut self, guest_path: &str) -> Option { - let (index, relative) = self.mount_index_for(guest_path)?; - let bytes = self.mounts[index].filesystem.read_file(&relative).ok()?; - String::from_utf8(bytes).ok() - } - - fn path_is_dir(&mut self, guest_path: &str) -> Option { - let (index, relative) = self.mount_index_for(guest_path)?; - // `stat` follows symlinks (O_PATH, no O_NOFOLLOW), so a symlinked package - // directory reports as a directory just like `fs.statSync` would. - self.mounts[index] - .filesystem - .stat(&relative) - .ok() - .map(|stat| stat.is_directory) - } - - fn path_exists(&mut self, guest_path: &str) -> bool { - match self.mount_index_for(guest_path) { - Some((index, relative)) => self.mounts[index].filesystem.exists(&relative), - None => false, - } - } -} - -/// Session-thread module reader: the mounted `HostDirModuleReader` plus a -/// persistent resolution cache, so the V8 isolate thread can both resolve -/// specifiers and read source DIRECTLY (same mount + `openat2(RESOLVE_BENEATH)` -/// confinement, same `ModuleResolver` semantics as the bridge), skipping the -/// per-module `_resolveModule`/`_loadFile` bridge round-trips. -pub(crate) struct SessionModuleReader { - reader: HostDirModuleReader, - cache: LocalModuleResolutionCache, -} - -impl SessionModuleReader { - pub(crate) fn new(reader: HostDirModuleReader) -> Self { - Self { - reader, - cache: LocalModuleResolutionCache::default(), - } - } -} - -impl GuestModuleReader for SessionModuleReader { - fn read_module_source(&mut self, resolved_guest_path: &str) -> Option { - self.reader.read_to_string(resolved_guest_path) - } - - fn resolve_module(&mut self, specifier: &str, referrer: &str) -> Option { - // Mirror the bridge's `_resolveModule` exactly: import mode, same reader, - // same persisted cache. - let reader: &mut dyn ModuleFsReader = &mut self.reader; - let mut resolver = ModuleResolver::new(reader, &mut self.cache); - resolver.resolve_module(specifier, referrer, ModuleResolveMode::Import) - } -} - -fn nix_to_io(error: Errno) -> io::Error { - io::Error::from_raw_os_error(error as i32) -} - -fn io_error_to_vfs(op: &'static str, path: &str, error: io::Error) -> VfsError { - let code = match error.raw_os_error() { - Some(1) => "EPERM", - Some(2) => "ENOENT", - Some(13) => "EACCES", - Some(17) => "EEXIST", - Some(18) => "EXDEV", - Some(20) => "ENOTDIR", - Some(21) => "EISDIR", - Some(22) => "EINVAL", - Some(30) => "EROFS", - Some(39) => "ENOTEMPTY", - Some(40) => "ELOOP", - _ => match error.kind() { - io::ErrorKind::NotFound => "ENOENT", - io::ErrorKind::PermissionDenied => "EACCES", - io::ErrorKind::AlreadyExists => "EEXIST", - io::ErrorKind::InvalidInput => "EINVAL", - _ => "EIO", - }, - }; - VfsError::new(code, format!("{op} '{path}': {error}")) -} - -fn error_code(error: &nix::Error) -> &'static str { - match error { - nix::Error::EACCES => "EACCES", - nix::Error::EEXIST => "EEXIST", - nix::Error::EINVAL => "EINVAL", - nix::Error::EISDIR => "EISDIR", - nix::Error::ELOOP => "ELOOP", - nix::Error::ENOENT => "ENOENT", - nix::Error::ENOTDIR => "ENOTDIR", - nix::Error::ENOTEMPTY => "ENOTEMPTY", - nix::Error::EPERM => "EPERM", - nix::Error::EROFS => "EROFS", - _ => "EIO", - } -} - -fn lexical_normalize_path(path: &Path) -> PathBuf { - let mut normalized = PathBuf::new(); - for component in path.components() { - match component { - Component::RootDir => normalized.push(Path::new("/")), - Component::CurDir => {} - Component::ParentDir => { - normalized.pop(); - } - Component::Normal(segment) => normalized.push(segment), - Component::Prefix(prefix) => normalized.push(prefix.as_os_str()), - } - } - - if normalized.as_os_str().is_empty() { - PathBuf::from("/") - } else { - normalized - } -} - -fn relative_path(from_dir: &Path, to: &Path) -> PathBuf { - let from_components = from_dir.components().collect::>(); - let to_components = to.components().collect::>(); - let shared = from_components - .iter() - .zip(to_components.iter()) - .take_while(|(left, right)| left == right) - .count(); - - let mut relative = PathBuf::new(); - for _ in shared..from_components.len() { - relative.push(".."); - } - for component in &to_components[shared..] { - if let Component::Normal(segment) = component { - relative.push(segment); - } - } - - if relative.as_os_str().is_empty() { - PathBuf::from(".") - } else { - relative - } -} - -fn virtual_dirname(path: &str) -> String { - let normalized = normalize_path(path); - match normalized.rsplit_once('/') { - Some((head, _)) if !head.is_empty() => head.to_owned(), - _ => String::from("/"), - } -} diff --git a/crates/sidecar/src/plugins/js_bridge.rs b/crates/sidecar/src/plugins/js_bridge.rs deleted file mode 100644 index f1ed81fac..000000000 --- a/crates/sidecar/src/plugins/js_bridge.rs +++ /dev/null @@ -1,617 +0,0 @@ -use crate::bridge::MountPluginContext; -use crate::protocol::{ - JsBridgeCallRequest, JsBridgeResultResponse, OwnershipScope, SidecarRequestPayload, - SidecarResponsePayload, -}; -use crate::SidecarError; - -use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; -use base64::Engine; -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::{MountedFileSystem, MountedVirtualFileSystem}; -use secure_exec_kernel::vfs::{ - VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, -}; -use serde::Deserialize; -use serde_json::{json, Value}; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::Arc; -use std::time::Duration; - -const JS_BRIDGE_TIMEOUT: Duration = Duration::from_secs(30); - -#[derive(Debug, Default, Deserialize)] -#[serde(rename_all = "camelCase")] -struct JsBridgeMountConfig { - #[serde(default)] - mount_id: Option, -} - -#[derive(Debug)] -pub(crate) struct JsBridgeMountPlugin; - -impl FileSystemPluginFactory> for JsBridgeMountPlugin { - fn plugin_id(&self) -> &'static str { - "js_bridge" - } - - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, MountPluginContext>, - ) -> Result, PluginError> { - let config: JsBridgeMountConfig = match &request.config { - Value::Null => JsBridgeMountConfig::default(), - Value::Object(_) => serde_json::from_value(request.config.clone()) - .map_err(|error| PluginError::invalid_input(error.to_string()))?, - _ => { - return Err(PluginError::invalid_input( - "js_bridge mount config must be an object or null", - )); - } - }; - let mount_id = config - .mount_id - .unwrap_or_else(|| request.guest_path.to_owned()); - let ownership = OwnershipScope::vm( - request.context.connection_id.clone(), - request.context.session_id.clone(), - request.context.vm_id.clone(), - ); - - Ok(Box::new(MountedVirtualFileSystem::new( - JsBridgeFilesystem::new( - request.context.sidecar_requests.clone(), - ownership, - mount_id, - request.context.max_pread_bytes, - ), - ))) - } -} - -#[derive(Clone)] -struct JsBridgeFilesystem { - requests: crate::state::SharedSidecarRequestClient, - ownership: OwnershipScope, - mount_id: String, - next_call_id: Arc, - max_read_bytes: Option, -} - -impl JsBridgeFilesystem { - fn new( - requests: crate::state::SharedSidecarRequestClient, - ownership: OwnershipScope, - mount_id: String, - max_read_bytes: Option, - ) -> Self { - Self { - requests, - ownership, - mount_id, - next_call_id: Arc::new(AtomicU64::new(1)), - max_read_bytes, - } - } - - fn next_call_id(&self) -> String { - format!( - "js-bridge-call-{}", - self.next_call_id.fetch_add(1, Ordering::Relaxed) - ) - } - - fn request_path(&self, operation: &str, path: &str, args: Value) -> VfsResult> { - let args = serde_json::to_string(&args).map_err(|error| { - VfsError::io(format!( - "failed to encode js_bridge args for {operation} '{path}': {error}" - )) - })?; - let payload = SidecarRequestPayload::JsBridgeCall(JsBridgeCallRequest { - call_id: self.next_call_id(), - mount_id: self.mount_id.clone(), - operation: operation.to_owned(), - args, - }); - match self - .requests - .invoke(self.ownership.clone(), payload, JS_BRIDGE_TIMEOUT) - .map_err(|error| Self::sidecar_error_to_vfs(operation, path, error))? - { - SidecarResponsePayload::JsBridgeResult(JsBridgeResultResponse { - result, - error, - .. - }) => { - if let Some(error) = error { - return Err(Self::js_error_to_vfs(operation, path, &error)); - } - result - .map(|result| { - serde_json::from_str(&result).map_err(|error| { - VfsError::io(format!( - "invalid js_bridge result payload for {operation} '{path}': {error}" - )) - }) - }) - .transpose() - } - other => Err(VfsError::io(format!( - "unexpected js_bridge response payload: {other:?}" - ))), - } - } - - fn sidecar_error_to_vfs(operation: &str, path: &str, error: SidecarError) -> VfsError { - match error { - SidecarError::Io(message) if message.contains("timed out") => { - VfsError::io(format!("{operation} {path}: {message}")) - } - other => VfsError::io(format!("{operation} {path}: {other}")), - } - } - - fn js_error_to_vfs(operation: &str, path: &str, error: &str) -> VfsError { - let lower = error.to_ascii_lowercase(); - let code = if lower.contains("enoent") - || lower.contains("not found") - || lower.contains("no such file") - { - "ENOENT" - } else if lower.contains("eacces") - || lower.contains("eperm") - || lower.contains("permission denied") - { - "EACCES" - } else if lower.contains("eexist") || lower.contains("already exists") { - "EEXIST" - } else { - "EIO" - }; - VfsError::new(code, format!("{error}, {operation} '{path}'")) - } - - fn parse_required(&self, operation: &str, path: &str, result: Option) -> VfsResult - where - T: for<'de> Deserialize<'de>, - { - let value = result.ok_or_else(|| { - VfsError::io(format!( - "js_bridge returned no payload for {operation} '{path}'" - )) - })?; - serde_json::from_value(value).map_err(|error| { - VfsError::io(format!( - "invalid js_bridge payload for {operation} '{path}': {error}" - )) - }) - } - - fn parse_bytes( - &self, - operation: &str, - path: &str, - result: Option, - ) -> VfsResult> { - self.parse_bytes_limited(operation, path, result, None) - } - - fn parse_bytes_limited( - &self, - operation: &str, - path: &str, - result: Option, - operation_max_bytes: Option, - ) -> VfsResult> { - let max_bytes = effective_read_limit(self.max_read_bytes, operation_max_bytes); - match result.ok_or_else(|| { - VfsError::io(format!( - "js_bridge returned no payload for {operation} '{path}'" - )) - })? { - Value::String(encoded) => { - let estimated_len = estimated_base64_decoded_len(&encoded).ok_or_else(|| { - VfsError::io(format!( - "js_bridge base64 payload length overflows for {operation} '{path}'" - )) - })?; - Self::check_read_length(operation, path, estimated_len, max_bytes)?; - let decoded = BASE64_STANDARD.decode(encoded).map_err(|error| { - VfsError::io(format!( - "invalid js_bridge base64 payload for {operation} '{path}': {error}" - )) - })?; - Self::check_read_length(operation, path, decoded.len(), max_bytes)?; - Ok(decoded) - } - Value::Array(values) => { - Self::check_read_length(operation, path, values.len(), max_bytes)?; - values - .into_iter() - .map(|value| match value { - Value::Number(number) => number - .as_u64() - .and_then(|value| u8::try_from(value).ok()) - .ok_or_else(|| { - VfsError::io(format!( - "invalid js_bridge byte payload for {operation} '{path}'" - )) - }), - _ => Err(VfsError::io(format!( - "invalid js_bridge byte payload for {operation} '{path}'" - ))), - }) - .collect() - } - other => Err(VfsError::io(format!( - "unsupported js_bridge payload for {operation} '{path}': {other:?}" - ))), - } - } - - fn check_read_length( - operation: &str, - path: &str, - length: usize, - max_bytes: Option, - ) -> VfsResult<()> { - if let Some(limit) = max_bytes { - if length <= limit { - return Ok(()); - } - - return Err(VfsError::new( - "EINVAL", - format!( - "js_bridge payload length {length} exceeds configured read limit {limit}, {operation} '{path}'" - ), - )); - } - - Ok(()) - } -} - -fn effective_read_limit( - mount_max_bytes: Option, - operation_max_bytes: Option, -) -> Option { - match (mount_max_bytes, operation_max_bytes) { - (Some(left), Some(right)) => Some(left.min(right)), - (Some(limit), None) | (None, Some(limit)) => Some(limit), - (None, None) => None, - } -} - -fn estimated_base64_decoded_len(encoded: &str) -> Option { - let padding = encoded - .as_bytes() - .iter() - .rev() - .take_while(|byte| **byte == b'=') - .count() - .min(2); - encoded - .len() - .checked_add(3) - .map(|length| (length / 4).saturating_mul(3).saturating_sub(padding)) -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct JsBridgeVirtualStat { - mode: u32, - size: u64, - blocks: u64, - dev: u64, - rdev: u64, - #[serde(alias = "is_directory")] - is_directory: bool, - #[serde(alias = "is_symbolic_link")] - is_symbolic_link: bool, - #[serde(alias = "atime_ms")] - atime_ms: u64, - #[serde(default, alias = "atime_nsec")] - atime_nsec: u32, - #[serde(alias = "mtime_ms")] - mtime_ms: u64, - #[serde(default, alias = "mtime_nsec")] - mtime_nsec: u32, - #[serde(alias = "ctime_ms")] - ctime_ms: u64, - #[serde(default, alias = "ctime_nsec")] - ctime_nsec: u32, - #[serde(alias = "birthtime_ms")] - birthtime_ms: u64, - ino: u64, - nlink: u64, - uid: u32, - gid: u32, -} - -impl From for VirtualStat { - fn from(stat: JsBridgeVirtualStat) -> Self { - Self { - mode: stat.mode, - size: stat.size, - blocks: stat.blocks, - dev: stat.dev, - rdev: stat.rdev, - is_directory: stat.is_directory, - is_symbolic_link: stat.is_symbolic_link, - atime_ms: stat.atime_ms, - atime_nsec: stat.atime_nsec, - mtime_ms: stat.mtime_ms, - mtime_nsec: stat.mtime_nsec, - ctime_ms: stat.ctime_ms, - ctime_nsec: stat.ctime_nsec, - birthtime_ms: stat.birthtime_ms, - ino: stat.ino, - nlink: stat.nlink, - uid: stat.uid, - gid: stat.gid, - } - } -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct JsBridgeDirEntry { - name: String, - #[serde(alias = "is_directory")] - is_directory: bool, - #[serde(alias = "is_symbolic_link")] - is_symbolic_link: bool, -} - -impl From for VirtualDirEntry { - fn from(entry: JsBridgeDirEntry) -> Self { - Self { - name: entry.name, - is_directory: entry.is_directory, - is_symbolic_link: entry.is_symbolic_link, - } - } -} - -impl VirtualFileSystem for JsBridgeFilesystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - let result = self.request_path("readFile", path, json!({ "path": path }))?; - self.parse_bytes("readFile", path, result) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - self.parse_required( - "readDir", - path, - self.request_path("readDir", path, json!({ "path": path }))?, - ) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - let entries: Vec = self.parse_required( - "readDirWithTypes", - path, - self.request_path("readDirWithTypes", path, json!({ "path": path }))?, - )?; - Ok(entries.into_iter().map(Into::into).collect()) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - let content = BASE64_STANDARD.encode(content.into()); - self.request_path( - "writeFile", - path, - json!({ - "path": path, - "content": content, - }), - )?; - Ok(()) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - self.request_path("createDir", path, json!({ "path": path }))?; - Ok(()) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - self.request_path( - "mkdir", - path, - json!({ - "path": path, - "recursive": recursive, - }), - )?; - Ok(()) - } - - fn exists(&self, path: &str) -> bool { - let Ok(args) = serde_json::to_string(&json!({ "path": path })) else { - return false; - }; - self.requests - .invoke( - self.ownership.clone(), - SidecarRequestPayload::JsBridgeCall(JsBridgeCallRequest { - call_id: self.next_call_id(), - mount_id: self.mount_id.clone(), - operation: String::from("exists"), - args, - }), - JS_BRIDGE_TIMEOUT, - ) - .ok() - .and_then(|payload| match payload { - SidecarResponsePayload::JsBridgeResult(JsBridgeResultResponse { - result, - error, - .. - }) if error.is_none() => result, - _ => None, - }) - .and_then(|value| serde_json::from_str::(&value).ok()) - .and_then(|value| value.as_bool()) - .unwrap_or(false) - } - - fn stat(&mut self, path: &str) -> VfsResult { - let stat: JsBridgeVirtualStat = self.parse_required( - "stat", - path, - self.request_path("stat", path, json!({ "path": path }))?, - )?; - Ok(stat.into()) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - self.request_path("removeFile", path, json!({ "path": path }))?; - Ok(()) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - self.request_path("removeDir", path, json!({ "path": path }))?; - Ok(()) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.request_path( - "rename", - old_path, - json!({ - "oldPath": old_path, - "newPath": new_path, - }), - )?; - Ok(()) - } - - fn realpath(&self, path: &str) -> VfsResult { - self.parse_required( - "realpath", - path, - self.request_path("realpath", path, json!({ "path": path }))?, - ) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - self.request_path( - "symlink", - link_path, - json!({ - "target": target, - "linkPath": link_path, - }), - )?; - Ok(()) - } - - fn read_link(&self, path: &str) -> VfsResult { - self.parse_required( - "readlink", - path, - self.request_path("readlink", path, json!({ "path": path }))?, - ) - } - - fn lstat(&self, path: &str) -> VfsResult { - let stat: JsBridgeVirtualStat = self.parse_required( - "lstat", - path, - self.request_path("lstat", path, json!({ "path": path }))?, - )?; - Ok(stat.into()) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.request_path( - "link", - old_path, - json!({ - "oldPath": old_path, - "newPath": new_path, - }), - )?; - Ok(()) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - self.request_path( - "chmod", - path, - json!({ - "path": path, - "mode": mode, - }), - )?; - Ok(()) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - self.request_path( - "chown", - path, - json!({ - "path": path, - "uid": uid, - "gid": gid, - }), - )?; - Ok(()) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - self.request_path( - "utimes", - path, - json!({ - "path": path, - "atimeMs": atime_ms, - "mtimeMs": mtime_ms, - }), - )?; - Ok(()) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - self.request_path( - "truncate", - path, - json!({ - "path": path, - "length": length, - }), - )?; - Ok(()) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - let result = self.request_path( - "pread", - path, - json!({ - "path": path, - "offset": offset, - "length": length, - }), - )?; - self.parse_bytes_limited("pread", path, result, Some(length)) - } - - fn pwrite(&mut self, path: &str, content: impl Into>, offset: u64) -> VfsResult<()> { - let content = BASE64_STANDARD.encode(content.into()); - self.request_path( - "pwrite", - path, - json!({ - "path": path, - "offset": offset, - "content": content, - }), - )?; - Ok(()) - } -} diff --git a/crates/sidecar/src/plugins/mod.rs b/crates/sidecar/src/plugins/mod.rs deleted file mode 100644 index ee97f2994..000000000 --- a/crates/sidecar/src/plugins/mod.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::bridge::MountPluginContext; - -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, FileSystemPluginRegistry, PluginError, -}; - -pub(crate) mod agentos_packages; -pub(crate) mod chunked_local; -pub(crate) mod chunked_s3; -pub(crate) mod google_drive; -pub(crate) mod host_dir; -pub(crate) mod js_bridge; -pub(crate) mod module_access; -pub(crate) mod object_s3; -pub(crate) mod s3_common; -pub(crate) mod sandbox_agent; - -use agentos_packages::AgentosPackagesMountPlugin; -use chunked_local::ChunkedLocalMountPlugin; -use chunked_s3::ChunkedS3MountPlugin; -use google_drive::GoogleDriveMountPlugin; -use host_dir::HostDirMountPlugin; -use js_bridge::JsBridgeMountPlugin; -use module_access::ModuleAccessMountPlugin; -use object_s3::ObjectS3MountPlugin; -use sandbox_agent::SandboxAgentMountPlugin; - -pub(crate) trait SidecarMountPluginFactory: - FileSystemPluginFactory -{ -} - -impl SidecarMountPluginFactory for T where T: FileSystemPluginFactory {} - -fn register_plugin( - registry: &mut FileSystemPluginRegistry, - plugin: impl SidecarMountPluginFactory + 'static, -) -> Result<(), PluginError> { - registry.register(plugin) -} - -pub(crate) fn register_native_mount_plugins( - registry: &mut FileSystemPluginRegistry>, -) -> Result<(), PluginError> { - register_plugin(registry, AgentosPackagesMountPlugin)?; - register_plugin(registry, HostDirMountPlugin)?; - register_plugin(registry, ModuleAccessMountPlugin)?; - register_plugin(registry, JsBridgeMountPlugin)?; - register_plugin(registry, SandboxAgentMountPlugin)?; - register_plugin(registry, ChunkedLocalMountPlugin)?; - register_plugin(registry, ObjectS3MountPlugin)?; - register_plugin(registry, ChunkedS3MountPlugin)?; - register_plugin(registry, GoogleDriveMountPlugin)?; - Ok(()) -} diff --git a/crates/sidecar/src/plugins/module_access.rs b/crates/sidecar/src/plugins/module_access.rs deleted file mode 100644 index 087d229ad..000000000 --- a/crates/sidecar/src/plugins/module_access.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::plugins::host_dir::{HostDirFilesystem, HostDirReadLimitContext}; - -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::{ - MountedFileSystem, MountedVirtualFileSystem, ReadOnlyFileSystem, -}; -use serde::Deserialize; -use std::fs; -use std::path::{Path, PathBuf}; - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct ModuleAccessMountConfig { - host_path: String, -} - -#[derive(Debug)] -pub(crate) struct ModuleAccessMountPlugin; - -impl FileSystemPluginFactory for ModuleAccessMountPlugin -where - Context: HostDirReadLimitContext, -{ - fn plugin_id(&self) -> &'static str { - "module_access" - } - - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - let config: ModuleAccessMountConfig = serde_json::from_value(request.config.clone()) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - let host_path = validate_module_access_root(&config.host_path)?; - let filesystem = HostDirFilesystem::new_with_read_limit( - &host_path, - request.context.host_dir_max_read_bytes(), - ) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - Ok(Box::new(ReadOnlyFileSystem::new( - MountedVirtualFileSystem::new(filesystem), - ))) - } -} - -fn validate_module_access_root(path: &str) -> Result { - let root = fs::canonicalize(path).map_err(|error| { - PluginError::invalid_input(format!( - "failed to resolve module_access root {path}: {error}" - )) - })?; - if root.file_name() == Some(Path::new("node_modules").as_os_str()) { - return Ok(root); - } - - Err(PluginError::invalid_input(format!( - "module_access roots must resolve to a node_modules directory: {path}" - ))) -} diff --git a/crates/sidecar/src/plugins/object_s3.rs b/crates/sidecar/src/plugins/object_s3.rs deleted file mode 100644 index b246bc4cf..000000000 --- a/crates/sidecar/src/plugins/object_s3.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::plugins::s3_common::{ - create_s3_client, normalize_prefix, S3MountCredentials, DEFAULT_REGION, -}; - -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::MountedFileSystem; -use secure_exec_vfs::{S3ObjectBackend, S3ObjectBackendOptions}; -use serde::Deserialize; -use vfs::adapter::MountedEngineFileSystem; -use vfs::engine::engines::{ObjectFs, ObjectFsOptions}; - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -struct ObjectS3MountConfig { - bucket: String, - prefix: Option, - region: Option, - credentials: Option, - endpoint: Option, - uid: Option, - gid: Option, - file_mode: Option, - dir_mode: Option, -} - -#[derive(Debug)] -pub(crate) struct ObjectS3MountPlugin; - -impl FileSystemPluginFactory for ObjectS3MountPlugin { - fn plugin_id(&self) -> &'static str { - "object_s3" - } - - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - let config: ObjectS3MountConfig = serde_json::from_value(request.config.clone()) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - let bucket = config.bucket.trim().to_owned(); - if bucket.is_empty() { - return Err(PluginError::invalid_input( - "object_s3 mount requires a non-empty bucket", - )); - } - - let prefix = normalize_prefix(config.prefix.as_deref()); - let client = create_s3_client( - config.region.unwrap_or_else(|| DEFAULT_REGION.to_owned()), - config.endpoint, - config.credentials, - )?; - let backend = S3ObjectBackend::with_options( - client, - bucket, - S3ObjectBackendOptions { - prefix: prefix.clone(), - }, - ); - let fs = ObjectFs::with_options( - backend, - ObjectFsOptions { - prefix: String::new(), - uid: config.uid.unwrap_or(0), - gid: config.gid.unwrap_or(0), - file_mode: config.file_mode.unwrap_or(0o644), - dir_mode: config.dir_mode.unwrap_or(0o755), - }, - ); - Ok(Box::new(MountedEngineFileSystem::new(fs)?)) - } -} diff --git a/crates/sidecar/src/plugins/s3_common.rs b/crates/sidecar/src/plugins/s3_common.rs deleted file mode 100644 index 823cd41ea..000000000 --- a/crates/sidecar/src/plugins/s3_common.rs +++ /dev/null @@ -1,532 +0,0 @@ -use aws_config::BehaviorVersion; -use aws_credential_types::Credentials; -use aws_sdk_s3::config::Builder as S3ConfigBuilder; -use aws_sdk_s3::Client as S3Client; -use secure_exec_kernel::mount_plugin::PluginError; -use serde::Deserialize; -use tokio::runtime::Runtime; -use url::Url; - -pub(crate) const DEFAULT_REGION: &str = "us-east-1"; - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct S3MountCredentials { - pub(crate) access_key_id: String, - pub(crate) secret_access_key: String, -} - -pub(crate) fn normalize_prefix(raw: Option<&str>) -> String { - match raw { - Some(prefix) if !prefix.trim().is_empty() => { - let trimmed = prefix.trim_matches('/'); - if trimmed.is_empty() { - String::new() - } else { - format!("{trimmed}/") - } - } - _ => String::new(), - } -} - -pub(crate) fn create_s3_client( - region: String, - endpoint: Option, - credentials: Option, -) -> Result { - let endpoint = endpoint - .map(|endpoint| normalize_s3_endpoint(&endpoint)) - .transpose()?; - let shared_config = std::thread::spawn(move || -> Result<_, PluginError> { - let runtime = Runtime::new() - .map_err(|error| PluginError::unsupported(format!("create tokio runtime: {error}")))?; - - Ok(runtime.block_on(async move { - let mut loader = aws_config::defaults(BehaviorVersion::latest()) - .region(aws_sdk_s3::config::Region::new(region)); - if let Some(credentials) = credentials { - loader = loader.credentials_provider(Credentials::new( - credentials.access_key_id, - credentials.secret_access_key, - None, - None, - "secure-exec-s3-plugin", - )); - } - loader.load().await - })) - }) - .join() - .map_err(|_| PluginError::unsupported("s3 runtime thread panicked"))??; - - let mut builder = S3ConfigBuilder::from(&shared_config).force_path_style(true); - if let Some(endpoint) = endpoint { - builder = builder.endpoint_url(endpoint); - } - - Ok(S3Client::from_conf(builder.build())) -} - -fn normalize_s3_endpoint(raw: &str) -> Result { - let normalized = raw.trim().trim_end_matches('/').to_owned(); - if normalized.is_empty() { - return Err(PluginError::invalid_input( - "s3 mount endpoint must be a valid URL", - )); - } - - let url = Url::parse(&normalized).map_err(|error| { - PluginError::invalid_input(format!("s3 mount endpoint is not a valid URL: {error}")) - })?; - url.host_str() - .ok_or_else(|| PluginError::invalid_input("s3 mount endpoint must include a host"))?; - match url.scheme() { - "http" | "https" => {} - _ => { - return Err(PluginError::invalid_input( - "s3 mount endpoint must use http or https", - )); - } - } - - Ok(normalized) -} - -#[cfg(test)] -pub(crate) mod test_support { - #![allow(dead_code)] - - use std::collections::{BTreeMap, BTreeSet}; - use std::io::{Read, Write}; - use std::net::{TcpListener, TcpStream}; - use std::sync::atomic::{AtomicBool, Ordering}; - use std::sync::{Arc, Mutex}; - use std::thread::{self, JoinHandle}; - use std::time::Duration; - - #[derive(Clone, Debug)] - pub(crate) struct LoggedRequest { - pub method: String, - pub path: String, - } - - pub(crate) struct MockS3Server { - base_url: String, - shutdown: Arc, - objects: Arc>>>, - requests: Arc>>, - handle: Option>, - } - - impl MockS3Server { - pub(crate) fn start() -> Self { - let listener = TcpListener::bind("127.0.0.1:0").expect("bind mock s3"); - listener - .set_nonblocking(true) - .expect("configure mock s3 listener"); - let address = listener.local_addr().expect("resolve mock s3 address"); - let shutdown = Arc::new(AtomicBool::new(false)); - let objects = Arc::new(Mutex::new(BTreeMap::new())); - let requests = Arc::new(Mutex::new(Vec::new())); - let shutdown_for_thread = Arc::clone(&shutdown); - let objects_for_thread = Arc::clone(&objects); - let requests_for_thread = Arc::clone(&requests); - - let handle = thread::spawn(move || { - while !shutdown_for_thread.load(Ordering::SeqCst) { - match listener.accept() { - Ok((stream, _)) => { - handle_stream(stream, &objects_for_thread, &requests_for_thread); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - thread::sleep(Duration::from_millis(10)); - } - Err(_) => break, - } - } - }); - - Self { - base_url: format!("http://{}", address), - shutdown, - objects, - requests, - handle: Some(handle), - } - } - - pub(crate) fn base_url(&self) -> &str { - &self.base_url - } - - pub(crate) fn object_keys(&self) -> Vec { - self.objects - .lock() - .expect("lock mock s3 objects") - .keys() - .cloned() - .collect() - } - - pub(crate) fn put_object(&self, key: &str, bytes: Vec) { - self.objects - .lock() - .expect("lock mock s3 objects") - .insert(key.to_owned(), bytes); - } - - pub(crate) fn requests(&self) -> Vec { - self.requests.lock().expect("lock mock s3 requests").clone() - } - - pub(crate) fn clear_requests(&self) { - self.requests.lock().expect("lock mock s3 requests").clear(); - } - } - - impl Drop for MockS3Server { - fn drop(&mut self) { - self.shutdown.store(true, Ordering::SeqCst); - if let Some(handle) = self.handle.take() { - handle.join().expect("join mock s3 thread"); - } - } - } - - fn handle_stream( - mut stream: TcpStream, - objects: &Arc>>>, - requests: &Arc>>, - ) { - stream - .set_read_timeout(Some(Duration::from_secs(2))) - .expect("set mock s3 read timeout"); - - let mut buffer = Vec::new(); - let mut header_end = None; - while header_end.is_none() { - let mut chunk = [0; 1024]; - match stream.read(&mut chunk) { - Ok(0) => return, - Ok(read) => { - buffer.extend_from_slice(&chunk[..read]); - header_end = find_header_end(&buffer); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => continue, - Err(_) => return, - } - } - - let header_end = header_end.expect("parse mock s3 headers"); - let header_text = String::from_utf8_lossy(&buffer[..header_end]).into_owned(); - let mut lines = header_text.split("\r\n"); - let request_line = match lines.next() { - Some(line) if !line.is_empty() => line, - _ => return, - }; - let mut request_parts = request_line.split_whitespace(); - let method = request_parts.next().unwrap_or_default().to_owned(); - let raw_target = request_parts.next().unwrap_or_default(); - let (raw_path, raw_query) = raw_target.split_once('?').unwrap_or((raw_target, "")); - let raw_query = raw_query.to_owned(); - let path = decode_url_component(raw_path); - - let mut headers = BTreeMap::new(); - let mut content_length = 0usize; - for line in lines { - if let Some((name, value)) = line.split_once(':') { - let name = name.trim().to_ascii_lowercase(); - let value = value.trim().to_owned(); - if name == "content-length" { - content_length = value.parse::().unwrap_or(0); - } - headers.insert(name, value); - } - } - - while buffer.len() < header_end + 4 + content_length { - let mut chunk = [0; 1024]; - match stream.read(&mut chunk) { - Ok(0) => break, - Ok(read) => buffer.extend_from_slice(&chunk[..read]), - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => continue, - Err(_) => break, - } - } - let body = buffer[header_end + 4..header_end + 4 + content_length].to_vec(); - - requests - .lock() - .expect("lock mock s3 request log") - .push(LoggedRequest { - method: method.clone(), - path: path.clone(), - }); - - match method.as_str() { - "GET" if raw_query.contains("list-type=2") => { - let query = parse_query(&raw_query); - let xml = list_objects_xml( - &path, - query.get("prefix").map(String::as_str).unwrap_or_default(), - query.get("delimiter").map(String::as_str), - objects, - ); - send_response(&mut stream, 200, "OK", "application/xml", xml.as_bytes()); - } - "GET" => { - let key = path.trim_start_matches('/'); - if let Some(bytes) = objects - .lock() - .expect("lock mock s3 objects") - .get(key) - .cloned() - { - let bytes = apply_range(&bytes, headers.get("range").map(String::as_str)); - send_response(&mut stream, 200, "OK", "application/octet-stream", &bytes); - } else { - send_not_found(&mut stream); - } - } - "HEAD" => { - let key = path.trim_start_matches('/'); - let len = objects - .lock() - .expect("lock mock s3 objects") - .get(key) - .map(Vec::len); - match len { - Some(len) => send_head_response(&mut stream, 200, "OK", len), - None => send_head_response(&mut stream, 404, "Not Found", 0), - } - } - "PUT" => { - let key = path.trim_start_matches('/').to_owned(); - let data = if let Some(source) = headers.get("x-amz-copy-source") { - let source = decode_url_component(source) - .trim_start_matches('/') - .to_owned(); - objects - .lock() - .expect("lock mock s3 objects") - .get(&source) - .cloned() - .unwrap_or_default() - } else { - body - }; - objects - .lock() - .expect("lock mock s3 objects") - .insert(key, data); - send_response(&mut stream, 200, "OK", "application/xml", b""); - } - "DELETE" => { - objects - .lock() - .expect("lock mock s3 objects") - .remove(path.trim_start_matches('/')); - send_response(&mut stream, 204, "No Content", "application/xml", b""); - } - "POST" if raw_query.starts_with("delete") => { - let keys = parse_delete_objects_keys(&body); - let bucket = path.trim_matches('/'); - let mut objects = objects.lock().expect("lock mock s3 objects"); - if keys.is_empty() { - let bucket_prefix = format!("{bucket}/"); - objects.retain(|key, _| !key.starts_with(&bucket_prefix)); - } else { - for key in keys { - objects.remove(&format!("{bucket}/{key}")); - } - } - send_response( - &mut stream, - 200, - "OK", - "application/xml", - br#""#, - ); - } - _ => send_response( - &mut stream, - 405, - "Method Not Allowed", - "text/plain", - b"unsupported", - ), - } - } - - fn list_objects_xml( - path: &str, - prefix: &str, - delimiter: Option<&str>, - objects: &Arc>>>, - ) -> String { - let bucket = path - .trim_start_matches('/') - .split('/') - .next() - .unwrap_or_default(); - let full_prefix = format!("{bucket}/{prefix}"); - let delimiter = delimiter.unwrap_or_default(); - let mut contents = Vec::new(); - let mut common_prefixes = BTreeSet::new(); - - for (key, bytes) in objects.lock().expect("lock mock s3 objects").iter() { - let Some(relative) = key.strip_prefix(&full_prefix) else { - continue; - }; - if !delimiter.is_empty() { - if let Some((first, _)) = relative.split_once(delimiter) { - common_prefixes.insert(format!("{prefix}{first}{delimiter}")); - continue; - } - } - contents.push(( - key.strip_prefix(&format!("{bucket}/")) - .unwrap_or(key) - .to_owned(), - bytes.len(), - )); - } - - let mut xml = String::from( - r#""#, - ); - xml.push_str("false"); - for (key, len) in contents { - xml.push_str(""); - xml.push_str(&escape_xml(&key)); - xml.push_str(""); - xml.push_str(&len.to_string()); - xml.push_str(""); - } - for prefix in common_prefixes { - xml.push_str(""); - xml.push_str(&escape_xml(&prefix)); - xml.push_str(""); - } - xml.push_str(""); - xml - } - - fn apply_range(bytes: &[u8], range: Option<&str>) -> Vec { - let Some(range) = range.and_then(|range| range.strip_prefix("bytes=")) else { - return bytes.to_vec(); - }; - let Some((start, end)) = range.split_once('-') else { - return bytes.to_vec(); - }; - let start = start.parse::().unwrap_or(0); - let end = end - .parse::() - .unwrap_or(bytes.len().saturating_sub(1)) - .min(bytes.len().saturating_sub(1)); - if start >= bytes.len() || start > end { - return Vec::new(); - } - bytes[start..=end].to_vec() - } - - fn send_not_found(stream: &mut TcpStream) { - send_response( - stream, - 404, - "Not Found", - "application/xml", - br#"NoSuchKeymissing"#, - ); - } - - fn send_head_response(stream: &mut TcpStream, status: u16, reason: &str, len: usize) { - let response = format!( - "HTTP/1.1 {status} {reason}\r\nContent-Length: {len}\r\nConnection: close\r\nx-amz-request-id: test\r\n\r\n" - ); - stream - .write_all(response.as_bytes()) - .expect("write mock s3 head response"); - stream.flush().expect("flush mock s3 response"); - } - - fn send_response( - stream: &mut TcpStream, - status: u16, - reason: &str, - content_type: &str, - body: &[u8], - ) { - let response = format!( - "HTTP/1.1 {status} {reason}\r\nContent-Length: {}\r\nContent-Type: {content_type}\r\nConnection: close\r\nx-amz-request-id: test\r\n\r\n", - body.len() - ); - stream - .write_all(response.as_bytes()) - .expect("write mock s3 response headers"); - stream.write_all(body).expect("write mock s3 response body"); - stream.flush().expect("flush mock s3 response"); - } - - fn find_header_end(buffer: &[u8]) -> Option { - buffer.windows(4).position(|window| window == b"\r\n\r\n") - } - - fn parse_query(raw: &str) -> BTreeMap { - raw.split('&') - .map(|pair| { - let (name, value) = pair.split_once('=').unwrap_or((pair, "")); - (decode_url_component(name), decode_url_component(value)) - }) - .collect() - } - - fn parse_delete_objects_keys(body: &[u8]) -> Vec { - let text = String::from_utf8_lossy(body); - let mut keys = Vec::new(); - let mut rest = text.as_ref(); - while let Some((_, after_start)) = rest.split_once("") { - let Some((key, after_end)) = after_start.split_once("") else { - break; - }; - keys.push(decode_url_component(key)); - rest = after_end; - } - keys - } - - fn decode_url_component(raw: &str) -> String { - let mut decoded = String::new(); - let bytes = raw.as_bytes(); - let mut index = 0; - while index < bytes.len() { - if bytes[index] == b'%' && index + 2 < bytes.len() { - let code = std::str::from_utf8(&bytes[index + 1..index + 3]) - .ok() - .and_then(|hex| u8::from_str_radix(hex, 16).ok()); - if let Some(code) = code { - decoded.push(code as char); - index += 3; - continue; - } - } - if bytes[index] == b'+' { - decoded.push(' '); - } else { - decoded.push(bytes[index] as char); - } - index += 1; - } - decoded - } - - fn escape_xml(value: &str) -> String { - value - .replace('&', "&") - .replace('<', "<") - .replace('>', ">") - .replace('"', """) - .replace('\'', "'") - } -} diff --git a/crates/sidecar/src/plugins/sandbox_agent.rs b/crates/sidecar/src/plugins/sandbox_agent.rs deleted file mode 100644 index 2877ace43..000000000 --- a/crates/sidecar/src/plugins/sandbox_agent.rs +++ /dev/null @@ -1,2427 +0,0 @@ -use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, PluginError, -}; -use secure_exec_kernel::mount_table::{MountedFileSystem, MountedVirtualFileSystem}; -use secure_exec_kernel::vfs::{ - normalize_path, VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, S_IFDIR, - S_IFREG, -}; -use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -use std::io::Read; -use std::net::IpAddr; -use std::sync::Mutex; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use url::Url; - -const DEFAULT_TIMEOUT_MS: u64 = 30_000; -const DEFAULT_MAX_FULL_READ_BYTES: u64 = 256 * 1024; -const DEFAULT_PROCESS_TIMEOUT_MS: u64 = 10_000; - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct SandboxAgentMountConfig { - base_url: String, - token: Option, - headers: Option>, - base_path: Option, - timeout_ms: Option, - max_full_read_bytes: Option, -} - -#[derive(Debug)] -pub(crate) struct SandboxAgentMountPlugin; - -impl FileSystemPluginFactory for SandboxAgentMountPlugin { - fn plugin_id(&self) -> &'static str { - "sandbox_agent" - } - - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - let config: SandboxAgentMountConfig = serde_json::from_value(request.config.clone()) - .map_err(|error| PluginError::invalid_input(error.to_string()))?; - let filesystem = SandboxAgentFilesystem::from_config(config)?; - Ok(Box::new(MountedVirtualFileSystem::new(filesystem))) - } -} - -struct SandboxAgentFilesystem { - client: SandboxAgentFilesystemClient, - base_path: String, - max_full_read_bytes: u64, - process_runtime: Mutex>, -} - -impl SandboxAgentFilesystem { - fn from_config(config: SandboxAgentMountConfig) -> Result { - let base_url = validate_sandbox_agent_base_url(&config.base_url)?; - - let timeout_ms = config.timeout_ms.unwrap_or(DEFAULT_TIMEOUT_MS); - let timeout = Duration::from_millis(timeout_ms); - let base_path = normalize_sandbox_agent_base_path(config.base_path.as_deref()); - - Ok(Self { - client: SandboxAgentFilesystemClient::new( - base_url, - config.token, - config.headers.unwrap_or_default(), - timeout, - ), - base_path, - max_full_read_bytes: config - .max_full_read_bytes - .unwrap_or(DEFAULT_MAX_FULL_READ_BYTES), - process_runtime: Mutex::new(None), - }) - } - - fn scoped_path(&self, path: &str) -> String { - let normalized = normalize_path(path); - if self.base_path == "/" { - return normalized; - } - - let suffix = normalized.trim_start_matches('/'); - if self.base_path.starts_with('/') { - return normalize_path(&format!( - "{}/{}", - self.base_path.trim_end_matches('/'), - suffix - )); - } - - if suffix.is_empty() { - self.base_path.clone() - } else { - format!("{}/{}", self.base_path.trim_end_matches('/'), suffix) - } - } - - fn stat_from_remote(stat: &SandboxAgentFsStat) -> VirtualStat { - let modified_ms = now_ms(); - let is_directory = stat.entry_type == "directory"; - - VirtualStat { - mode: if is_directory { - S_IFDIR | 0o755 - } else { - S_IFREG | 0o644 - }, - size: stat.size, - blocks: if stat.size == 0 { - 0 - } else { - stat.size.div_ceil(512) - }, - dev: 1, - rdev: 0, - is_directory, - is_symbolic_link: false, - atime_ms: modified_ms, - atime_nsec: 0, - mtime_ms: modified_ms, - mtime_nsec: 0, - ctime_ms: modified_ms, - ctime_nsec: 0, - birthtime_ms: modified_ms, - ino: 0, - nlink: 1, - uid: 0, - gid: 0, - } - } - - fn is_virtual_mount_root(&self, path: &str) -> bool { - self.base_path != "/" && normalize_path(path) == "/" - } - - fn virtual_mount_root_stat(&self) -> VirtualStat { - let modified_ms = now_ms(); - VirtualStat { - mode: S_IFDIR | 0o755, - size: 0, - blocks: 0, - dev: 1, - rdev: 0, - is_directory: true, - is_symbolic_link: false, - atime_ms: modified_ms, - atime_nsec: 0, - mtime_ms: modified_ms, - mtime_nsec: 0, - ctime_ms: modified_ms, - ctime_nsec: 0, - birthtime_ms: modified_ms, - ino: 0, - nlink: 1, - uid: 0, - gid: 0, - } - } - - fn scoped_target(&self, target: &str) -> String { - if target.starts_with('/') { - let scoped = self.scoped_path(target); - if scoped.starts_with('/') { - scoped - } else { - format!("/{scoped}") - } - } else { - target.to_owned() - } - } - - fn strip_base_path_prefix<'a>(&self, target: &'a str) -> Option<&'a str> { - if self.base_path == "/" { - return None; - } - - let base_path = self.base_path.trim_end_matches('/'); - if target == base_path { - Some("") - } else if let Some(stripped) = target - .strip_prefix(base_path) - .filter(|stripped| stripped.starts_with('/')) - { - Some(stripped) - } else if !base_path.starts_with('/') { - let absolute_base_path = format!("/{base_path}"); - if target == absolute_base_path { - Some("") - } else { - target - .strip_prefix(&absolute_base_path) - .filter(|stripped| stripped.starts_with('/')) - } - } else { - None - } - } - - fn unscoped_target(&self, target: String) -> String { - match self.strip_base_path_prefix(&target) { - Some(stripped) => format!("/{}", stripped.trim_start_matches('/')), - None => target, - } - } - - fn process_runtimes(&self) -> Vec { - let cached = *self - .process_runtime - .lock() - .expect("lock sandbox_agent process runtime cache"); - let mut runtimes = Vec::with_capacity(3); - if let Some(runtime) = cached { - runtimes.push(runtime); - } - for runtime in [ - RemoteProcessRuntime::Python3, - RemoteProcessRuntime::Python, - RemoteProcessRuntime::Node, - ] { - if Some(runtime) != cached { - runtimes.push(runtime); - } - } - runtimes - } - - fn remember_process_runtime(&self, runtime: RemoteProcessRuntime) { - *self - .process_runtime - .lock() - .expect("lock sandbox_agent process runtime cache") = Some(runtime); - } - - fn run_fs_script( - &self, - op: &'static str, - path: &str, - python_script: &'static str, - node_script: &'static str, - args: &[String], - ) -> VfsResult> { - let mut saw_runtime_candidate = false; - - for runtime in self.process_runtimes() { - saw_runtime_candidate = true; - match self.run_fs_script_with_runtime( - runtime, - op, - path, - python_script, - node_script, - args, - ) { - Ok(result) => { - self.remember_process_runtime(runtime); - return Ok(result); - } - Err(ProcessFallbackError::RuntimeUnavailable) => continue, - Err(ProcessFallbackError::Unsupported(message)) => { - return Err(VfsError::unsupported(format!( - "sandbox_agent {op} '{path}' requires remote process execution but the sandbox-agent server does not support the process API: {message}" - ))); - } - Err(ProcessFallbackError::Operation(error)) => return Err(error), - } - } - - debug_assert!(saw_runtime_candidate); - Err(VfsError::unsupported(format!( - "sandbox_agent {op} '{path}' requires a remote `python3`, `python`, or `node` runtime via the sandbox-agent process API, but none were available" - ))) - } - - fn run_fs_script_with_runtime( - &self, - runtime: RemoteProcessRuntime, - op: &'static str, - path: &str, - python_script: &'static str, - node_script: &'static str, - args: &[String], - ) -> Result, ProcessFallbackError> { - let request = runtime.process_request(args, python_script, node_script); - let response = self - .client - .run_process(&request) - .map_err(|error| match error { - SandboxAgentClientError::Status { - status: 404 | 405 | 501, - problem, - } => ProcessFallbackError::Unsupported( - problem - .detail - .or(problem.title) - .unwrap_or_else(|| String::from("process API unavailable")), - ), - other => { - ProcessFallbackError::Operation(sandbox_client_error_to_vfs(op, path, other)) - } - })?; - - if response.timed_out { - return Err(ProcessFallbackError::Operation(VfsError::io(format!( - "{op} '{path}': remote process helper timed out after {} ms", - DEFAULT_PROCESS_TIMEOUT_MS - )))); - } - - if response.exit_code.unwrap_or_default() == 0 { - if response.stdout.is_empty() { - return Ok(None); - } - return parse_process_json_output(&response.stdout, op, path) - .map(Some) - .map_err(ProcessFallbackError::Operation); - } - - if runtime.command_missing(&response) { - return Err(ProcessFallbackError::RuntimeUnavailable); - } - - Err(ProcessFallbackError::Operation(process_response_to_vfs( - op, path, response, - ))) - } -} - -impl VirtualFileSystem for SandboxAgentFilesystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - let remote_path = self.scoped_path(path); - self.client - .read_fs_file(&remote_path) - .map_err(|error| sandbox_client_error_to_vfs("open", path, error)) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - let remote_path = self.scoped_path(path); - let mut entries = self - .client - .list_fs_entries(&remote_path) - .or_else(|error| { - if self.is_virtual_mount_root(path) && is_missing_path_error(&error) { - Ok(Vec::new()) - } else { - Err(sandbox_client_error_to_vfs("readdir", path, error)) - } - })? - .into_iter() - .map(|entry| entry.name) - .filter(|name| name != "." && name != "..") - .collect::>(); - entries.sort(); - Ok(entries) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - let remote_path = self.scoped_path(path); - let mut entries = self - .client - .list_fs_entries(&remote_path) - .or_else(|error| { - if self.is_virtual_mount_root(path) && is_missing_path_error(&error) { - Ok(Vec::new()) - } else { - Err(sandbox_client_error_to_vfs("readdir", path, error)) - } - })? - .into_iter() - .filter(|entry| entry.name != "." && entry.name != "..") - .map(|entry| VirtualDirEntry { - name: entry.name, - is_directory: entry.entry_type == "directory", - is_symbolic_link: false, - }) - .collect::>(); - entries.sort_by(|left, right| left.name.cmp(&right.name)); - Ok(entries) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - let remote_path = self.scoped_path(path); - self.client - .write_fs_file(&remote_path, &content.into()) - .map_err(|error| sandbox_client_error_to_vfs("write", path, error)) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - self.mkdir(path, false) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - if !recursive { - let parent_path = dirname(path); - if parent_path != "/" { - let parent_remote = self.scoped_path(&parent_path); - let parent = self - .client - .stat_fs(&parent_remote) - .map_err(|error| sandbox_client_error_to_vfs("mkdir", &parent_path, error))?; - if parent.entry_type != "directory" { - return Err(VfsError::new( - "ENOTDIR", - format!("not a directory, mkdir '{parent_path}'"), - )); - } - } - } - - let remote_path = self.scoped_path(path); - self.client - .mkdir_fs(&remote_path) - .map_err(|error| sandbox_client_error_to_vfs("mkdir", path, error)) - } - - fn exists(&self, path: &str) -> bool { - let remote_path = self.scoped_path(path); - match self.client.stat_fs(&remote_path) { - Ok(_) => true, - Err(error) => self.is_virtual_mount_root(path) && is_missing_path_error(&error), - } - } - - fn stat(&mut self, path: &str) -> VfsResult { - let remote_path = self.scoped_path(path); - match self.client.stat_fs(&remote_path) { - Ok(stat) => Ok(Self::stat_from_remote(&stat)), - Err(error) if self.is_virtual_mount_root(path) && is_missing_path_error(&error) => { - Ok(self.virtual_mount_root_stat()) - } - Err(error) => Err(sandbox_client_error_to_vfs("stat", path, error)), - } - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - let remote_path = self.scoped_path(path); - self.client - .delete_fs_entry(&remote_path, false) - .map_err(|error| sandbox_client_error_to_vfs("unlink", path, error)) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - let remote_path = self.scoped_path(path); - let entries = self - .client - .list_fs_entries(&remote_path) - .map_err(|error| sandbox_client_error_to_vfs("rmdir", path, error))?; - let children = entries - .into_iter() - .filter(|entry| entry.name != "." && entry.name != "..") - .count(); - if children > 0 { - return Err(VfsError::new( - "ENOTEMPTY", - format!("directory not empty, rmdir '{path}'"), - )); - } - - self.client - .delete_fs_entry(&remote_path, false) - .map_err(|error| sandbox_client_error_to_vfs("rmdir", path, error)) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let old_remote = self.scoped_path(old_path); - let new_remote = self.scoped_path(new_path); - self.client - .move_fs(&old_remote, &new_remote, true) - .map_err(|error| sandbox_client_error_to_vfs("rename", old_path, error)) - } - - fn realpath(&self, path: &str) -> VfsResult { - let remote_path = self.scoped_path(path); - let resolved = self.run_fs_script( - "realpath", - path, - PYTHON_REALPATH_SCRIPT, - NODE_REALPATH_SCRIPT, - &[remote_path], - )?; - Ok(self.unscoped_target(resolved.unwrap_or_else(|| normalize_path(path)))) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - let remote_target = self.scoped_target(target); - let remote_link = self.scoped_path(link_path); - self.run_fs_script( - "symlink", - link_path, - PYTHON_SYMLINK_SCRIPT, - NODE_SYMLINK_SCRIPT, - &[remote_target, remote_link], - )?; - Ok(()) - } - - fn read_link(&self, path: &str) -> VfsResult { - let remote_path = self.scoped_path(path); - let target = self.run_fs_script( - "readlink", - path, - PYTHON_READLINK_SCRIPT, - NODE_READLINK_SCRIPT, - &[remote_path], - )?; - Ok(match target { - Some(target) if target.starts_with('/') => self.unscoped_target(target), - Some(target) => target, - None => String::new(), - }) - } - - fn lstat(&self, path: &str) -> VfsResult { - let remote_path = self.scoped_path(path); - match self.client.stat_fs(&remote_path) { - Ok(stat) => Ok(Self::stat_from_remote(&stat)), - Err(error) if self.is_virtual_mount_root(path) && is_missing_path_error(&error) => { - Ok(self.virtual_mount_root_stat()) - } - Err(error) => Err(sandbox_client_error_to_vfs("lstat", path, error)), - } - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let old_remote = self.scoped_path(old_path); - let new_remote = self.scoped_path(new_path); - self.run_fs_script( - "link", - new_path, - PYTHON_LINK_SCRIPT, - NODE_LINK_SCRIPT, - &[old_remote, new_remote], - )?; - Ok(()) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - let remote_path = self.scoped_path(path); - self.run_fs_script( - "chmod", - path, - PYTHON_CHMOD_SCRIPT, - NODE_CHMOD_SCRIPT, - &[remote_path, mode.to_string()], - )?; - Ok(()) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - let remote_path = self.scoped_path(path); - self.run_fs_script( - "chown", - path, - PYTHON_CHOWN_SCRIPT, - NODE_CHOWN_SCRIPT, - &[remote_path, uid.to_string(), gid.to_string()], - )?; - Ok(()) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - let remote_path = self.scoped_path(path); - self.run_fs_script( - "utimes", - path, - PYTHON_UTIMES_SCRIPT, - NODE_UTIMES_SCRIPT, - &[remote_path, atime_ms.to_string(), mtime_ms.to_string()], - )?; - Ok(()) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - if length == 0 { - return self.write_file(path, Vec::::new()); - } - - let remote_path = self.scoped_path(path); - self.run_fs_script( - "truncate", - path, - PYTHON_TRUNCATE_SCRIPT, - NODE_TRUNCATE_SCRIPT, - &[remote_path, length.to_string()], - )?; - Ok(()) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - if length == 0 { - return Ok(Vec::new()); - } - - let remote_path = self.scoped_path(path); - let stat = self - .client - .stat_fs(&remote_path) - .map_err(|error| sandbox_client_error_to_vfs("open", path, error))?; - if stat.entry_type == "directory" { - return Err(VfsError::new( - "EISDIR", - format!("illegal operation on a directory, open '{path}'"), - )); - } - if offset >= stat.size { - return Ok(Vec::new()); - } - - match self - .client - .read_fs_file_range(&remote_path, offset, length, self.max_full_read_bytes) - .map_err(|error| sandbox_client_error_to_vfs("open", path, error))? - { - SandboxAgentReadResponse::Partial(content) => Ok(content), - SandboxAgentReadResponse::Full(content) => { - tracing::warn!( - path, - downloaded_bytes = content.len(), - max_full_read_bytes = self.max_full_read_bytes, - "sandbox_agent pread fell back to full-file get because remote ignored range" - ); - let start = usize::try_from(offset).unwrap_or(usize::MAX); - if start >= content.len() { - return Ok(Vec::new()); - } - let end = start.saturating_add(length).min(content.len()); - Ok(content[start..end].to_vec()) - } - } - } -} - -struct SandboxAgentFilesystemClient { - base_url: String, - token: Option, - headers: BTreeMap, - agent: ureq::Agent, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum RemoteProcessRuntime { - Python3, - Python, - Node, -} - -impl RemoteProcessRuntime { - fn command(self) -> &'static str { - match self { - Self::Python3 => "python3", - Self::Python => "python", - Self::Node => "node", - } - } - - fn process_request( - self, - args: &[String], - python_script: &'static str, - node_script: &'static str, - ) -> SandboxAgentProcessRunRequest { - match self { - Self::Python3 | Self::Python => { - let mut process_args = vec![String::from("-c"), python_script.to_owned()]; - process_args.extend(args.iter().cloned()); - SandboxAgentProcessRunRequest { - command: self.command().to_owned(), - args: process_args, - cwd: Some(String::from("/")), - env: None, - max_output_bytes: None, - timeout_ms: Some(DEFAULT_PROCESS_TIMEOUT_MS), - } - } - Self::Node => { - let mut process_args = vec![String::from("-e"), node_script.to_owned()]; - if !args.is_empty() { - process_args.push(String::from("--")); - process_args.extend(args.iter().cloned()); - } - SandboxAgentProcessRunRequest { - command: self.command().to_owned(), - args: process_args, - cwd: Some(String::from("/")), - env: None, - max_output_bytes: None, - timeout_ms: Some(DEFAULT_PROCESS_TIMEOUT_MS), - } - } - } - } - - fn command_missing(self, response: &SandboxAgentProcessRunResponse) -> bool { - if serde_json::from_str::(response.stderr.trim()).is_ok() { - return false; - } - let stderr = response.stderr.to_ascii_lowercase(); - response.exit_code == Some(127) - || stderr.contains("command not found") - || stderr.contains("executable file not found") - || stderr.contains("enoent") - } -} - -enum ProcessFallbackError { - RuntimeUnavailable, - Unsupported(String), - Operation(VfsError), -} - -impl SandboxAgentFilesystemClient { - fn new( - base_url: String, - token: Option, - headers: BTreeMap, - timeout: Duration, - ) -> Self { - let agent = ureq::AgentBuilder::new() - .timeout_connect(timeout) - .timeout_read(timeout) - .timeout_write(timeout) - .redirects(0) - .build(); - - Self { - base_url, - token, - headers, - agent, - } - } - - fn list_fs_entries( - &self, - path: &str, - ) -> Result, SandboxAgentClientError> { - self.request_json( - "GET", - "/v1/fs/entries", - vec![(String::from("path"), path.to_owned())], - RequestBody::None, - Some("application/json"), - ) - } - - fn read_fs_file(&self, path: &str) -> Result, SandboxAgentClientError> { - self.request_bytes( - "GET", - "/v1/fs/file", - vec![(String::from("path"), path.to_owned())], - Some("application/octet-stream"), - ) - } - - fn read_fs_file_range( - &self, - path: &str, - offset: u64, - length: usize, - max_full_read_bytes: u64, - ) -> Result { - let range_length = u64::try_from(length).unwrap_or(u64::MAX); - let end = offset.saturating_add(range_length.saturating_sub(1)); - let response = self.request_raw_with_headers( - "GET", - "/v1/fs/file", - vec![(String::from("path"), path.to_owned())], - RequestBody::None, - Some("application/octet-stream"), - vec![(String::from("Range"), format!("bytes={offset}-{end}"))], - )?; - let status = response.status(); - Ok(match status { - 206 => SandboxAgentReadResponse::Partial(response_into_bytes_limited( - response, - u64::try_from(length).unwrap_or(u64::MAX), - )?), - _ => SandboxAgentReadResponse::Full(response_into_bytes_limited( - response, - max_full_read_bytes, - )?), - }) - } - - fn write_fs_file(&self, path: &str, content: &[u8]) -> Result<(), SandboxAgentClientError> { - self.request_empty( - "PUT", - "/v1/fs/file", - vec![(String::from("path"), path.to_owned())], - RequestBody::Bytes(content.to_vec()), - Some("application/json"), - ) - } - - fn delete_fs_entry(&self, path: &str, recursive: bool) -> Result<(), SandboxAgentClientError> { - let mut query = vec![(String::from("path"), path.to_owned())]; - if recursive { - query.push((String::from("recursive"), String::from("true"))); - } - - self.request_empty( - "DELETE", - "/v1/fs/entry", - query, - RequestBody::None, - Some("application/json"), - ) - } - - fn mkdir_fs(&self, path: &str) -> Result<(), SandboxAgentClientError> { - self.request_empty( - "POST", - "/v1/fs/mkdir", - vec![(String::from("path"), path.to_owned())], - RequestBody::None, - Some("application/json"), - ) - } - - fn move_fs( - &self, - from: &str, - to: &str, - overwrite: bool, - ) -> Result<(), SandboxAgentClientError> { - self.request_empty( - "POST", - "/v1/fs/move", - Vec::new(), - RequestBody::Json(serde_json::json!({ - "from": from, - "to": to, - "overwrite": overwrite, - })), - Some("application/json"), - ) - } - - fn stat_fs(&self, path: &str) -> Result { - self.request_json( - "GET", - "/v1/fs/stat", - vec![(String::from("path"), path.to_owned())], - RequestBody::None, - Some("application/json"), - ) - } - - fn run_process( - &self, - request: &SandboxAgentProcessRunRequest, - ) -> Result { - self.request_json( - "POST", - "/v1/processes/run", - Vec::new(), - RequestBody::Json( - serde_json::to_value(request).expect("serialize process run request"), - ), - Some("application/json"), - ) - } - - fn request_json( - &self, - method: &str, - path: &str, - query: Vec<(String, String)>, - body: RequestBody, - accept: Option<&str>, - ) -> Result { - let response = self.request_raw(method, path, query, body, accept)?; - response - .into_json::() - .map_err(|error| SandboxAgentClientError::Decode(error.to_string())) - } - - fn request_bytes( - &self, - method: &str, - path: &str, - query: Vec<(String, String)>, - accept: Option<&str>, - ) -> Result, SandboxAgentClientError> { - let response = self.request_raw(method, path, query, RequestBody::None, accept)?; - response_into_bytes(response) - } - - fn request_empty( - &self, - method: &str, - path: &str, - query: Vec<(String, String)>, - body: RequestBody, - accept: Option<&str>, - ) -> Result<(), SandboxAgentClientError> { - self.request_raw(method, path, query, body, accept)?; - Ok(()) - } - - fn request_raw( - &self, - method: &str, - path: &str, - query: Vec<(String, String)>, - body: RequestBody, - accept: Option<&str>, - ) -> Result { - self.request_raw_with_headers(method, path, query, body, accept, Vec::new()) - } - - fn request_raw_with_headers( - &self, - method: &str, - path: &str, - query: Vec<(String, String)>, - body: RequestBody, - accept: Option<&str>, - request_headers: Vec<(String, String)>, - ) -> Result { - let mut request = self - .agent - .request(method, &format!("{}{}", self.base_url, path)); - - if let Some(token) = &self.token { - request = request.set("Authorization", &format!("Bearer {token}")); - } - - for (name, value) in &self.headers { - request = request.set(name, value); - } - - for (name, value) in request_headers { - request = request.set(&name, &value); - } - - if let Some(accept) = accept { - request = request.set("Accept", accept); - } - - for (name, value) in query { - request = request.query(&name, &value); - } - - let response = match body { - RequestBody::None => request.call(), - RequestBody::Json(value) => request.send_json(value), - RequestBody::Bytes(content) => request - .set("Content-Type", "application/octet-stream") - .send_bytes(&content), - }; - - match response { - Ok(response) if response.status() >= 300 => Err(SandboxAgentClientError::Status { - status: response.status(), - problem: read_problem_details(response), - }), - Ok(response) => Ok(response), - Err(ureq::Error::Status(status, response)) => Err(SandboxAgentClientError::Status { - status, - problem: read_problem_details(response), - }), - Err(ureq::Error::Transport(error)) => { - Err(SandboxAgentClientError::Transport(error.to_string())) - } - } - } -} - -enum SandboxAgentReadResponse { - Partial(Vec), - Full(Vec), -} - -enum RequestBody { - None, - Json(serde_json::Value), - Bytes(Vec), -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct SandboxAgentFsEntry { - name: String, - #[serde(rename = "path")] - _path: String, - entry_type: String, - #[serde(rename = "size")] - _size: u64, - #[serde(rename = "modified")] - _modified: Option, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct SandboxAgentFsStat { - #[serde(rename = "path")] - _path: String, - entry_type: String, - size: u64, - #[serde(rename = "modified")] - _modified: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct SandboxAgentProcessRunRequest { - command: String, - #[serde(default)] - args: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - cwd: Option, - #[serde(skip_serializing_if = "Option::is_none")] - env: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - max_output_bytes: Option, - #[serde(skip_serializing_if = "Option::is_none")] - timeout_ms: Option, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct SandboxAgentProcessRunResponse { - #[serde(rename = "durationMs")] - _duration_ms: u64, - exit_code: Option, - stderr: String, - #[serde(rename = "stderrTruncated")] - _stderr_truncated: bool, - stdout: String, - #[serde(rename = "stdoutTruncated")] - _stdout_truncated: bool, - timed_out: bool, -} - -#[derive(Debug, Deserialize)] -struct FsScriptJsonOutput { - result: Option, -} - -#[derive(Debug, Deserialize)] -struct FsScriptJsonError { - errno: Option, - message: Option, -} - -#[derive(Debug, Default, Deserialize)] -struct SandboxAgentProblemDetails { - title: Option, - detail: Option, - status: Option, -} - -#[derive(Debug)] -enum SandboxAgentClientError { - Status { - status: u16, - problem: SandboxAgentProblemDetails, - }, - Transport(String), - Decode(String), -} - -fn read_problem_details(response: ureq::Response) -> SandboxAgentProblemDetails { - match response.into_string() { - Ok(body) if !body.is_empty() => { - serde_json::from_str(&body).unwrap_or_else(|_| SandboxAgentProblemDetails { - detail: Some(body), - ..SandboxAgentProblemDetails::default() - }) - } - _ => SandboxAgentProblemDetails::default(), - } -} - -fn response_into_bytes(response: ureq::Response) -> Result, SandboxAgentClientError> { - let mut reader = response.into_reader(); - let mut bytes = Vec::new(); - reader - .read_to_end(&mut bytes) - .map_err(|error| SandboxAgentClientError::Decode(error.to_string()))?; - Ok(bytes) -} - -fn response_into_bytes_limited( - response: ureq::Response, - max_bytes: u64, -) -> Result, SandboxAgentClientError> { - if response - .header("Content-Length") - .and_then(|value| value.trim().parse::().ok()) - .is_some_and(|content_length| content_length > max_bytes) - { - return Err(SandboxAgentClientError::Decode(format!( - "sandbox-agent response exceeded {max_bytes} byte limit" - ))); - } - - let read_limit = max_bytes.saturating_add(1); - let mut reader = response.into_reader().take(read_limit); - let mut bytes = Vec::new(); - reader - .read_to_end(&mut bytes) - .map_err(|error| SandboxAgentClientError::Decode(error.to_string()))?; - if u64::try_from(bytes.len()).unwrap_or(u64::MAX) > max_bytes { - return Err(SandboxAgentClientError::Decode(format!( - "sandbox-agent response exceeded {max_bytes} byte limit" - ))); - } - Ok(bytes) -} - -fn validate_sandbox_agent_base_url(raw: &str) -> Result { - // The baseUrl comes only from the trusted mount config, never from untrusted - // guest code, so it is not an SSRF surface (see root CLAUDE.md): the private - // -IP denylist and DNS re-resolution are dropped. We still validate - // well-formedness (clear errors + the trailing-slash trim that request - // building relies on) and still require https for non-local hosts, because - // the client's bearer token is sent in the Authorization header and must not - // traverse plaintext http. - let normalized = raw.trim().trim_end_matches('/').to_owned(); - if normalized.is_empty() { - return Err(PluginError::invalid_input( - "sandbox_agent mount requires a non-empty baseUrl", - )); - } - - let url = Url::parse(&normalized).map_err(|error| { - PluginError::invalid_input(format!( - "sandbox_agent mount baseUrl is not a valid URL: {error}" - )) - })?; - let host = url.host_str().ok_or_else(|| { - PluginError::invalid_input("sandbox_agent mount baseUrl must include a host") - })?; - let host_for_address = host - .strip_prefix('[') - .and_then(|host| host.strip_suffix(']')) - .unwrap_or(host); - if url.query().is_some() || url.fragment().is_some() { - return Err(PluginError::invalid_input( - "sandbox_agent mount baseUrl must not include a query string or fragment", - )); - } - - let scheme = url.scheme(); - if !matches!(scheme, "http" | "https") { - return Err(PluginError::invalid_input( - "sandbox_agent mount baseUrl must use http or https", - )); - } - - let is_local = host_for_address.eq_ignore_ascii_case("localhost") - || host_for_address - .parse::() - .map(|ip| ip.is_loopback()) - .unwrap_or(false); - if scheme != "https" && !is_local { - return Err(PluginError::invalid_input( - "sandbox_agent mount baseUrl must use https unless it targets localhost", - )); - } - - Ok(normalized) -} - -fn sandbox_client_error_to_vfs( - op: &'static str, - path: &str, - error: SandboxAgentClientError, -) -> VfsError { - match error { - SandboxAgentClientError::Status { status, problem } => { - let status = problem.status.unwrap_or(status); - let detail = problem - .detail - .or(problem.title) - .unwrap_or_else(|| format!("sandbox-agent request failed with status {status}")); - - let code = if status == 401 || status == 403 { - "EACCES" - } else if status == 404 || detail.contains("path not found") { - "ENOENT" - } else if detail.contains("path is not a file") { - "EISDIR" - } else if detail.contains("destination already exists") || status == 409 { - "EEXIST" - } else if status == 400 { - "EINVAL" - } else { - "EIO" - }; - - VfsError::new(code, format!("{op} '{path}': {detail}")) - } - SandboxAgentClientError::Transport(message) | SandboxAgentClientError::Decode(message) => { - VfsError::io(format!("{op} '{path}': {message}")) - } - } -} - -fn is_missing_path_error(error: &SandboxAgentClientError) -> bool { - match error { - SandboxAgentClientError::Status { status, problem } => { - let detail = problem - .detail - .as_deref() - .or(problem.title.as_deref()) - .unwrap_or_default(); - *status == 404 || detail.contains("path not found") - } - SandboxAgentClientError::Transport(_) | SandboxAgentClientError::Decode(_) => false, - } -} - -fn parse_process_json_output(stdout: &str, op: &'static str, path: &str) -> VfsResult { - let trimmed = stdout.trim(); - let output: FsScriptJsonOutput = serde_json::from_str(trimmed).map_err(|error| { - VfsError::io(format!( - "{op} '{path}': failed to decode process helper output: {error}" - )) - })?; - Ok(output.result.unwrap_or_default()) -} - -fn process_response_to_vfs( - op: &'static str, - path: &str, - response: SandboxAgentProcessRunResponse, -) -> VfsError { - let trimmed_stderr = response.stderr.trim(); - if let Ok(error) = serde_json::from_str::(trimmed_stderr) { - let message = error - .message - .unwrap_or_else(|| String::from("remote filesystem helper failed")); - if let Some(errno) = error.errno { - return VfsError::new( - errno_to_vfs_code(errno), - format!("{op} '{path}': {message}"), - ); - } - return VfsError::io(format!("{op} '{path}': {message}")); - } - - let detail = if trimmed_stderr.is_empty() { - format!( - "remote process exited with code {}", - response - .exit_code - .map(|code| code.to_string()) - .unwrap_or_else(|| String::from("unknown")) - ) - } else { - trimmed_stderr.to_owned() - }; - VfsError::io(format!("{op} '{path}': {detail}")) -} - -fn errno_to_vfs_code(errno: i32) -> &'static str { - match errno { - nix::libc::EACCES => "EACCES", - nix::libc::EEXIST => "EEXIST", - nix::libc::EINVAL => "EINVAL", - nix::libc::EISDIR => "EISDIR", - nix::libc::ELOOP => "ELOOP", - nix::libc::ENOENT => "ENOENT", - nix::libc::ENOSYS => "ENOSYS", - nix::libc::ENOTDIR => "ENOTDIR", - nix::libc::ENOTEMPTY => "ENOTEMPTY", - nix::libc::EPERM => "EPERM", - nix::libc::EXDEV => "EXDEV", - _ => "EIO", - } -} - -fn dirname(path: &str) -> String { - let normalized = normalize_path(path); - match normalized.rsplit_once('/') { - Some((head, _)) if !head.is_empty() => head.to_owned(), - _ => String::from("/"), - } -} - -fn normalize_sandbox_agent_base_path(raw: Option<&str>) -> String { - match raw { - None | Some("") | Some("/") => String::from("/"), - Some(path) if path.starts_with('/') => normalize_path(path), - Some(path) => { - let normalized = normalize_path(&format!("/{path}")); - let relative = normalized.trim_start_matches('/'); - if relative.is_empty() { - String::from("/") - } else { - relative.to_owned() - } - } - } -} - -fn now_ms() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as u64 -} - -const PYTHON_REALPATH_SCRIPT: &str = r#"import json, os, sys -path = sys.argv[1] -try: - resolved = os.path.realpath(path) - os.stat(resolved) - print(json.dumps({"result": resolved})) -except Exception as exc: - payload = {"message": str(exc)} - if isinstance(exc, OSError): - payload["errno"] = exc.errno - print(json.dumps(payload), file=sys.stderr) - sys.exit(1) -"#; - -const NODE_REALPATH_SCRIPT: &str = r#"const fs = require("node:fs/promises"); -(async () => { - try { - const resolved = await fs.realpath(process.argv[1]); - console.log(JSON.stringify({ result: resolved })); - } catch (error) { - console.error(JSON.stringify({ errno: typeof error?.errno === "number" ? Math.abs(error.errno) : undefined, message: error?.message ?? String(error) })); - process.exit(1); - } -})();"#; - -const PYTHON_SYMLINK_SCRIPT: &str = r#"import json, os, sys -target, link_path = sys.argv[1], sys.argv[2] -try: - os.symlink(target, link_path) - print(json.dumps({"result": None})) -except Exception as exc: - payload = {"message": str(exc)} - if isinstance(exc, OSError): - payload["errno"] = exc.errno - print(json.dumps(payload), file=sys.stderr) - sys.exit(1) -"#; - -const NODE_SYMLINK_SCRIPT: &str = r#"const fs = require("node:fs/promises"); -(async () => { - try { - await fs.symlink(process.argv[1], process.argv[2]); - console.log(JSON.stringify({ result: null })); - } catch (error) { - console.error(JSON.stringify({ errno: typeof error?.errno === "number" ? Math.abs(error.errno) : undefined, message: error?.message ?? String(error) })); - process.exit(1); - } -})();"#; - -const PYTHON_READLINK_SCRIPT: &str = r#"import json, os, sys -path = sys.argv[1] -try: - print(json.dumps({"result": os.readlink(path)})) -except Exception as exc: - payload = {"message": str(exc)} - if isinstance(exc, OSError): - payload["errno"] = exc.errno - print(json.dumps(payload), file=sys.stderr) - sys.exit(1) -"#; - -const NODE_READLINK_SCRIPT: &str = r#"const fs = require("node:fs/promises"); -(async () => { - try { - const target = await fs.readlink(process.argv[1]); - console.log(JSON.stringify({ result: target })); - } catch (error) { - console.error(JSON.stringify({ errno: typeof error?.errno === "number" ? Math.abs(error.errno) : undefined, message: error?.message ?? String(error) })); - process.exit(1); - } -})();"#; - -const PYTHON_LINK_SCRIPT: &str = r#"import json, os, sys -source, destination = sys.argv[1], sys.argv[2] -try: - os.link(source, destination) - print(json.dumps({"result": None})) -except Exception as exc: - payload = {"message": str(exc)} - if isinstance(exc, OSError): - payload["errno"] = exc.errno - print(json.dumps(payload), file=sys.stderr) - sys.exit(1) -"#; - -const NODE_LINK_SCRIPT: &str = r#"const fs = require("node:fs/promises"); -(async () => { - try { - await fs.link(process.argv[1], process.argv[2]); - console.log(JSON.stringify({ result: null })); - } catch (error) { - console.error(JSON.stringify({ errno: typeof error?.errno === "number" ? Math.abs(error.errno) : undefined, message: error?.message ?? String(error) })); - process.exit(1); - } -})();"#; - -const PYTHON_CHMOD_SCRIPT: &str = r#"import json, os, sys -path, mode = sys.argv[1], int(sys.argv[2]) -try: - os.chmod(path, mode) - print(json.dumps({"result": None})) -except Exception as exc: - payload = {"message": str(exc)} - if isinstance(exc, OSError): - payload["errno"] = exc.errno - print(json.dumps(payload), file=sys.stderr) - sys.exit(1) -"#; - -const NODE_CHMOD_SCRIPT: &str = r#"const fs = require("node:fs/promises"); -(async () => { - try { - await fs.chmod(process.argv[1], Number(process.argv[2])); - console.log(JSON.stringify({ result: null })); - } catch (error) { - console.error(JSON.stringify({ errno: typeof error?.errno === "number" ? Math.abs(error.errno) : undefined, message: error?.message ?? String(error) })); - process.exit(1); - } -})();"#; - -const PYTHON_CHOWN_SCRIPT: &str = r#"import json, os, sys -path, uid, gid = sys.argv[1], int(sys.argv[2]), int(sys.argv[3]) -try: - os.chown(path, uid, gid) - print(json.dumps({"result": None})) -except Exception as exc: - payload = {"message": str(exc)} - if isinstance(exc, OSError): - payload["errno"] = exc.errno - print(json.dumps(payload), file=sys.stderr) - sys.exit(1) -"#; - -const NODE_CHOWN_SCRIPT: &str = r#"const fs = require("node:fs/promises"); -(async () => { - try { - await fs.chown(process.argv[1], Number(process.argv[2]), Number(process.argv[3])); - console.log(JSON.stringify({ result: null })); - } catch (error) { - console.error(JSON.stringify({ errno: typeof error?.errno === "number" ? Math.abs(error.errno) : undefined, message: error?.message ?? String(error) })); - process.exit(1); - } -})();"#; - -const PYTHON_UTIMES_SCRIPT: &str = r#"import json, os, sys -path, atime_ms, mtime_ms = sys.argv[1], int(sys.argv[2]), int(sys.argv[3]) -try: - os.utime(path, ns=(atime_ms * 1_000_000, mtime_ms * 1_000_000)) - print(json.dumps({"result": None})) -except Exception as exc: - payload = {"message": str(exc)} - if isinstance(exc, OSError): - payload["errno"] = exc.errno - print(json.dumps(payload), file=sys.stderr) - sys.exit(1) -"#; - -const NODE_UTIMES_SCRIPT: &str = r#"const fs = require("node:fs/promises"); -(async () => { - try { - await fs.utimes(process.argv[1], Number(process.argv[2]) / 1000, Number(process.argv[3]) / 1000); - console.log(JSON.stringify({ result: null })); - } catch (error) { - console.error(JSON.stringify({ errno: typeof error?.errno === "number" ? Math.abs(error.errno) : undefined, message: error?.message ?? String(error) })); - process.exit(1); - } -})();"#; - -const PYTHON_TRUNCATE_SCRIPT: &str = r#"import json, os, sys -path, length = sys.argv[1], int(sys.argv[2]) -try: - os.truncate(path, length) - print(json.dumps({"result": None})) -except Exception as exc: - payload = {"message": str(exc)} - if isinstance(exc, OSError): - payload["errno"] = exc.errno - print(json.dumps(payload), file=sys.stderr) - sys.exit(1) -"#; - -const NODE_TRUNCATE_SCRIPT: &str = r#"const fs = require("node:fs/promises"); -(async () => { - try { - await fs.truncate(process.argv[1], Number(process.argv[2])); - console.log(JSON.stringify({ result: null })); - } catch (error) { - console.error(JSON.stringify({ errno: typeof error?.errno === "number" ? Math.abs(error.errno) : undefined, message: error?.message ?? String(error) })); - process.exit(1); - } -})();"#; - -#[cfg(test)] -pub(crate) mod test_support { - #![allow(dead_code)] - - use serde::{Deserialize, Serialize}; - use std::collections::BTreeMap; - use std::fs; - use std::io::{Read, Write}; - use std::net::{TcpListener, TcpStream}; - use std::path::{Path, PathBuf}; - use std::process::Command; - use std::sync::atomic::{AtomicBool, Ordering}; - use std::sync::{Arc, Mutex}; - use std::thread::{self, JoinHandle}; - use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; - - #[derive(Debug, Clone)] - pub(crate) struct LoggedRequest { - pub method: String, - pub path: String, - pub query: BTreeMap, - pub headers: BTreeMap, - pub response_status: u16, - pub response_body_bytes: usize, - } - - pub(crate) struct MockSandboxAgentServer { - base_url: String, - root: PathBuf, - shutdown: Arc, - requests: Arc>>, - handle: Option>, - } - - impl MockSandboxAgentServer { - pub(crate) fn start(prefix: &str, token: Option<&str>) -> Self { - Self::start_with_options(prefix, token, true, true) - } - - pub(crate) fn start_without_process_api(prefix: &str, token: Option<&str>) -> Self { - Self::start_with_options(prefix, token, false, true) - } - - pub(crate) fn start_without_range_support(prefix: &str, token: Option<&str>) -> Self { - Self::start_with_options(prefix, token, true, false) - } - - fn start_with_options( - prefix: &str, - token: Option<&str>, - process_api_supported: bool, - range_requests_supported: bool, - ) -> Self { - let root = temp_dir(prefix); - // macOS: `temp_dir()` lives under `/var/folders/…`, but `/var` is a - // symlink to `/private/var`, and the `realpath` the process helper - // runs returns the resolved `/private/var/…` form. Canonicalize the - // mock root so its root-prefix stripping (`sanitize_process_stdout`) - // matches that output instead of leaking the absolute host path back - // to the plugin (which the plugin would then fail to unscope). - #[cfg(target_os = "macos")] - let root = fs::canonicalize(&root).expect("canonicalize mock sandbox-agent root"); - let listener = TcpListener::bind("127.0.0.1:0").expect("bind mock sandbox-agent"); - listener - .set_nonblocking(true) - .expect("configure mock sandbox-agent listener"); - let address = listener - .local_addr() - .expect("resolve mock sandbox-agent address"); - let shutdown = Arc::new(AtomicBool::new(false)); - let requests = Arc::new(Mutex::new(Vec::new())); - let token = token.map(str::to_owned); - let root_for_thread = root.clone(); - let shutdown_for_thread = Arc::clone(&shutdown); - let requests_for_thread = Arc::clone(&requests); - - let handle = thread::spawn(move || { - while !shutdown_for_thread.load(Ordering::SeqCst) { - match listener.accept() { - Ok((stream, _)) => { - handle_stream( - stream, - &root_for_thread, - token.as_deref(), - process_api_supported, - range_requests_supported, - &requests_for_thread, - ); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - thread::sleep(Duration::from_millis(10)); - } - Err(_) => break, - } - } - }); - - Self { - base_url: format!("http://{}", address), - root, - shutdown, - requests, - handle: Some(handle), - } - } - - pub(crate) fn base_url(&self) -> &str { - &self.base_url - } - - pub(crate) fn root(&self) -> &Path { - &self.root - } - - pub(crate) fn requests(&self) -> Vec { - self.requests - .lock() - .expect("lock mock sandbox-agent request log") - .clone() - } - } - - impl Drop for MockSandboxAgentServer { - fn drop(&mut self) { - self.shutdown.store(true, Ordering::SeqCst); - if let Some(handle) = self.handle.take() { - handle.join().expect("join mock sandbox-agent thread"); - } - let _ = fs::remove_dir_all(&self.root); - } - } - - #[derive(Debug, Deserialize)] - struct MoveRequest { - from: String, - to: String, - overwrite: Option, - } - - #[derive(Debug, Deserialize)] - #[serde(rename_all = "camelCase")] - struct ProcessRunRequestBody { - command: String, - args: Option>, - cwd: Option, - env: Option>, - #[serde(rename = "maxOutputBytes")] - _max_output_bytes: Option, - #[serde(rename = "timeoutMs")] - _timeout_ms: Option, - } - - #[derive(Debug, Serialize)] - #[serde(rename_all = "camelCase")] - struct ProcessRunResponseBody { - duration_ms: u64, - exit_code: Option, - stderr: String, - stderr_truncated: bool, - stdout: String, - stdout_truncated: bool, - timed_out: bool, - } - - #[derive(Debug, Serialize)] - #[serde(rename_all = "camelCase")] - struct FsEntryBody { - name: String, - path: String, - entry_type: &'static str, - size: u64, - modified: Option, - } - - #[derive(Debug, Serialize)] - #[serde(rename_all = "camelCase")] - struct FsStatBody { - path: String, - entry_type: &'static str, - size: u64, - modified: Option, - } - - fn handle_stream( - mut stream: TcpStream, - root: &Path, - token: Option<&str>, - process_api_supported: bool, - range_requests_supported: bool, - requests: &Arc>>, - ) { - stream - .set_read_timeout(Some(Duration::from_secs(2))) - .expect("set mock sandbox-agent read timeout"); - - let mut buffer = Vec::new(); - let mut header_end = None; - while header_end.is_none() { - let mut chunk = [0; 1024]; - match stream.read(&mut chunk) { - Ok(0) => return, - Ok(read) => { - buffer.extend_from_slice(&chunk[..read]); - header_end = find_header_end(&buffer); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => continue, - Err(_) => return, - } - } - - let header_end = header_end.expect("parse mock sandbox-agent headers"); - let header_text = String::from_utf8_lossy(&buffer[..header_end]); - let mut lines = header_text.split("\r\n"); - let request_line = match lines.next() { - Some(line) if !line.is_empty() => line, - _ => return, - }; - let mut request_line_parts = request_line.split_whitespace(); - let method = request_line_parts.next().unwrap_or_default().to_owned(); - let target = request_line_parts.next().unwrap_or_default().to_owned(); - let (path, query) = split_target(&target); - - let mut headers = BTreeMap::new(); - for line in lines { - if line.is_empty() { - continue; - } - let Some((name, value)) = line.split_once(':') else { - continue; - }; - headers.insert(name.trim().to_ascii_lowercase(), value.trim().to_owned()); - } - - let content_length = headers - .get("content-length") - .and_then(|value| value.parse::().ok()) - .unwrap_or(0); - while buffer.len() < header_end + 4 + content_length { - let mut chunk = [0; 1024]; - match stream.read(&mut chunk) { - Ok(0) => break, - Ok(read) => buffer.extend_from_slice(&chunk[..read]), - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => continue, - Err(_) => break, - } - } - let body = &buffer[header_end + 4..header_end + 4 + content_length]; - - let request_index = { - let mut logged_requests = requests.lock().expect("record mock sandbox-agent request"); - logged_requests.push(LoggedRequest { - method: method.clone(), - path: path.clone(), - query: query.clone(), - headers: headers.clone(), - response_status: 0, - response_body_bytes: 0, - }); - logged_requests.len() - 1 - }; - - if let Some(expected_token) = token { - let authorization = headers - .get("authorization") - .map(String::as_str) - .unwrap_or_default(); - if authorization != format!("Bearer {expected_token}") { - let outcome = - send_problem(&mut stream, 401, "Unauthorized", "authentication required"); - update_logged_request(requests, request_index, outcome); - return; - } - } - - let outcome = match (method.as_str(), path.as_str()) { - ("GET", "/v1/fs/entries") => { - let path = query - .get("path") - .cloned() - .unwrap_or_else(|| String::from(".")); - let target = resolve_fs_path(root, &path); - match fs::read_dir(&target) { - Ok(entries) => { - let mut payload = entries - .filter_map(Result::ok) - .map(|entry| { - let metadata = entry.metadata().expect("read mock entry metadata"); - FsEntryBody { - name: entry.file_name().to_string_lossy().into_owned(), - path: entry.path().to_string_lossy().into_owned(), - entry_type: if metadata.is_dir() { - "directory" - } else { - "file" - }, - size: metadata.len(), - modified: None, - } - }) - .collect::>(); - payload.sort_by(|left, right| left.name.cmp(&right.name)); - send_json(&mut stream, 200, &payload) - } - Err(error) if error.kind() == std::io::ErrorKind::NotFound => send_problem( - &mut stream, - 400, - "Bad Request", - &format!("path not found: {}", target.display()), - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - } - } - ("GET", "/v1/fs/file") => { - let path = query.get("path").cloned().unwrap_or_default(); - let target = resolve_fs_path(root, &path); - if path == "/redirect-to-private" { - return_with_logged_request( - requests, - request_index, - send_redirect(&mut stream, "http://169.254.169.254/latest"), - ); - return; - } - match fs::metadata(&target) { - Ok(metadata) if metadata.is_file() => match fs::read(&target) { - Ok(bytes) => { - if path == "/stream-over-limit" && !range_requests_supported { - return_with_logged_request( - requests, - request_index, - send_bytes_without_content_length( - &mut stream, - 200, - "application/octet-stream", - &bytes, - ), - ); - return; - } - if range_requests_supported { - if let Some(range) = headers - .get("range") - .and_then(|value| parse_range_header(value, bytes.len())) - { - let body = &bytes[range.start..=range.end]; - return_with_logged_request( - requests, - request_index, - send_bytes_with_headers( - &mut stream, - 206, - "application/octet-stream", - body, - &[ - ("Accept-Ranges", String::from("bytes")), - ( - "Content-Range", - format!( - "bytes {}-{}/{}", - range.start, - range.end, - bytes.len() - ), - ), - ], - ), - ); - return; - } - } - send_bytes(&mut stream, 200, "application/octet-stream", &bytes) - } - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - }, - Ok(_) => send_problem( - &mut stream, - 400, - "Bad Request", - &format!("path is not a file: {}", target.display()), - ), - Err(error) if error.kind() == std::io::ErrorKind::NotFound => send_problem( - &mut stream, - 400, - "Bad Request", - &format!("path not found: {}", target.display()), - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - } - } - ("PUT", "/v1/fs/file") => { - let path = query.get("path").cloned().unwrap_or_default(); - let target = resolve_fs_path(root, &path); - if let Some(parent) = target.parent() { - let _ = fs::create_dir_all(parent); - } - match fs::write(&target, body) { - Ok(()) => send_json( - &mut stream, - 200, - &serde_json::json!({ - "path": target.to_string_lossy(), - "bytesWritten": body.len(), - }), - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - } - } - ("DELETE", "/v1/fs/entry") => { - let path = query.get("path").cloned().unwrap_or_default(); - let recursive = query - .get("recursive") - .map(|value| value == "true") - .unwrap_or(false); - let target = resolve_fs_path(root, &path); - match fs::metadata(&target) { - Ok(metadata) if metadata.is_dir() => { - let result = if recursive { - fs::remove_dir_all(&target) - } else { - fs::remove_dir(&target) - }; - match result { - Ok(()) => send_json( - &mut stream, - 200, - &serde_json::json!({ "path": target.to_string_lossy() }), - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - } - } - Ok(_) => match fs::remove_file(&target) { - Ok(()) => send_json( - &mut stream, - 200, - &serde_json::json!({ "path": target.to_string_lossy() }), - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - }, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => send_problem( - &mut stream, - 400, - "Bad Request", - &format!("path not found: {}", target.display()), - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - } - } - ("POST", "/v1/fs/mkdir") => { - let path = query.get("path").cloned().unwrap_or_default(); - let target = resolve_fs_path(root, &path); - match fs::create_dir_all(&target) { - Ok(()) => send_json( - &mut stream, - 200, - &serde_json::json!({ "path": target.to_string_lossy() }), - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - } - } - ("POST", "/v1/fs/move") => { - let request: MoveRequest = - serde_json::from_slice(body).expect("parse mock move request"); - let source = resolve_fs_path(root, &request.from); - let destination = resolve_fs_path(root, &request.to); - - if destination.exists() { - if request.overwrite.unwrap_or(false) { - let metadata = - fs::metadata(&destination).expect("inspect mock destination metadata"); - let remove_result = if metadata.is_dir() { - fs::remove_dir_all(&destination) - } else { - fs::remove_file(&destination) - }; - if let Err(error) = remove_result { - send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ); - return; - } - } else { - send_problem( - &mut stream, - 400, - "Bad Request", - &format!("destination already exists: {}", destination.display()), - ); - return; - } - } - - if let Some(parent) = destination.parent() { - let _ = fs::create_dir_all(parent); - } - - match fs::rename(&source, &destination) { - Ok(()) => send_json( - &mut stream, - 200, - &serde_json::json!({ - "from": source.to_string_lossy(), - "to": destination.to_string_lossy(), - }), - ), - Err(error) if error.kind() == std::io::ErrorKind::NotFound => send_problem( - &mut stream, - 400, - "Bad Request", - &format!("path not found: {}", source.display()), - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - } - } - ("GET", "/v1/fs/stat") => { - let path = query.get("path").cloned().unwrap_or_default(); - let target = resolve_fs_path(root, &path); - match fs::metadata(&target) { - Ok(metadata) => send_json( - &mut stream, - 200, - &FsStatBody { - path: target.to_string_lossy().into_owned(), - entry_type: if metadata.is_dir() { - "directory" - } else { - "file" - }, - size: metadata.len(), - modified: None, - }, - ), - Err(error) if error.kind() == std::io::ErrorKind::NotFound => send_problem( - &mut stream, - 400, - "Bad Request", - &format!("path not found: {}", target.display()), - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - } - } - ("POST", "/v1/processes/run") => { - if !process_api_supported { - let outcome = send_problem( - &mut stream, - 501, - "Not Implemented", - "process API unsupported by mock sandbox-agent", - ); - update_logged_request(requests, request_index, outcome); - return; - } - - let request: ProcessRunRequestBody = - serde_json::from_slice(body).expect("parse mock process run request"); - let started = Instant::now(); - let mut command = Command::new(&request.command); - command.args(rewrite_process_args(root, request.args.unwrap_or_default())); - if let Some(cwd) = request.cwd { - if cwd.starts_with('/') { - command.current_dir(resolve_fs_path(root, &cwd)); - } else { - command.current_dir(cwd); - } - } - if let Some(env) = request.env { - command.envs(env); - } - - match command.output() { - Ok(output) => send_json( - &mut stream, - 200, - &ProcessRunResponseBody { - duration_ms: started.elapsed().as_millis() as u64, - exit_code: output.status.code(), - stderr: String::from_utf8_lossy(&output.stderr).into_owned(), - stderr_truncated: false, - stdout: sanitize_process_stdout( - root, - String::from_utf8_lossy(&output.stdout).into_owned(), - ), - stdout_truncated: false, - timed_out: false, - }, - ), - Err(error) if error.kind() == std::io::ErrorKind::NotFound => send_json( - &mut stream, - 200, - &ProcessRunResponseBody { - duration_ms: started.elapsed().as_millis() as u64, - exit_code: Some(127), - stderr: error.to_string(), - stderr_truncated: false, - stdout: String::new(), - stdout_truncated: false, - timed_out: false, - }, - ), - Err(error) => send_problem( - &mut stream, - 500, - "Internal Server Error", - &error.to_string(), - ), - } - } - _ => send_problem(&mut stream, 404, "Not Found", "unknown mock route"), - }; - update_logged_request(requests, request_index, outcome); - } - - fn find_header_end(buffer: &[u8]) -> Option { - buffer.windows(4).position(|window| window == b"\r\n\r\n") - } - - fn split_target(target: &str) -> (String, BTreeMap) { - let Some((path, query)) = target.split_once('?') else { - return (target.to_owned(), BTreeMap::new()); - }; - - let query = query - .split('&') - .filter(|pair| !pair.is_empty()) - .map(|pair| match pair.split_once('=') { - Some((name, value)) => (percent_decode(name), percent_decode(value)), - None => (percent_decode(pair), String::new()), - }) - .collect::>(); - (path.to_owned(), query) - } - - fn percent_decode(raw: &str) -> String { - let bytes = raw.as_bytes(); - let mut index = 0; - let mut decoded = Vec::with_capacity(bytes.len()); - while index < bytes.len() { - match bytes[index] { - b'+' => { - decoded.push(b' '); - index += 1; - } - b'%' if index + 2 < bytes.len() => { - if let Ok(value) = u8::from_str_radix(&raw[index + 1..index + 3], 16) { - decoded.push(value); - index += 3; - } else { - decoded.push(bytes[index]); - index += 1; - } - } - byte => { - decoded.push(byte); - index += 1; - } - } - } - String::from_utf8(decoded).expect("decode mock sandbox-agent query") - } - - fn resolve_fs_path(root: &Path, path: &str) -> PathBuf { - let normalized = secure_exec_kernel::vfs::normalize_path(path); - root.join(normalized.trim_start_matches('/')) - } - - fn rewrite_process_args(root: &Path, args: Vec) -> Vec { - args.into_iter() - .map(|arg| { - if arg.starts_with('/') { - resolve_fs_path(root, &arg).to_string_lossy().into_owned() - } else { - arg - } - }) - .collect() - } - - fn sanitize_process_stdout(root: &Path, stdout: String) -> String { - let trimmed = stdout.trim(); - let Ok(mut value) = serde_json::from_str::(trimmed) else { - return stdout; - }; - - if let Some(result) = value - .get("result") - .and_then(serde_json::Value::as_str) - .map(str::to_owned) - { - let root_string = root.to_string_lossy(); - if result == root_string { - value["result"] = serde_json::Value::String(String::from("/")); - } else if let Some(stripped) = result.strip_prefix(root_string.as_ref()) { - value["result"] = - serde_json::Value::String(format!("/{}", stripped.trim_start_matches('/'))); - } - } - - serde_json::to_string(&value).expect("serialize sanitized process stdout") - } - - #[derive(Clone, Copy)] - struct ResponseOutcome { - status: u16, - body_bytes: usize, - } - - #[derive(Clone, Copy)] - struct ByteRange { - start: usize, - end: usize, - } - - fn parse_range_header(raw: &str, content_len: usize) -> Option { - let spec = raw.strip_prefix("bytes=")?; - let (start_raw, end_raw) = spec.split_once('-')?; - if start_raw.is_empty() { - return None; - } - let start = start_raw.parse::().ok()?; - if start >= content_len { - return None; - } - let end = if end_raw.is_empty() { - content_len.saturating_sub(1) - } else { - end_raw - .parse::() - .ok()? - .min(content_len.saturating_sub(1)) - }; - if end < start { - return None; - } - Some(ByteRange { start, end }) - } - - fn update_logged_request( - requests: &Arc>>, - request_index: usize, - outcome: ResponseOutcome, - ) { - if let Some(request) = requests - .lock() - .expect("lock mock sandbox-agent request log") - .get_mut(request_index) - { - request.response_status = outcome.status; - request.response_body_bytes = outcome.body_bytes; - } - } - - fn return_with_logged_request( - requests: &Arc>>, - request_index: usize, - outcome: ResponseOutcome, - ) { - update_logged_request(requests, request_index, outcome); - } - - fn send_json(stream: &mut TcpStream, status: u16, value: &impl Serialize) -> ResponseOutcome { - let body = serde_json::to_vec(value).expect("serialize mock sandbox-agent response"); - send_bytes(stream, status, "application/json", &body) - } - - fn send_problem( - stream: &mut TcpStream, - status: u16, - title: &str, - detail: &str, - ) -> ResponseOutcome { - send_json( - stream, - status, - &serde_json::json!({ - "type": "about:blank", - "title": title, - "status": status, - "detail": detail, - }), - ) - } - - fn send_bytes( - stream: &mut TcpStream, - status: u16, - content_type: &str, - body: &[u8], - ) -> ResponseOutcome { - send_bytes_with_headers(stream, status, content_type, body, &[]) - } - - fn send_redirect(stream: &mut TcpStream, location: &str) -> ResponseOutcome { - send_bytes_with_headers( - stream, - 302, - "text/plain", - b"", - &[("Location", location.to_owned())], - ) - } - - fn send_bytes_without_content_length( - stream: &mut TcpStream, - status: u16, - content_type: &str, - body: &[u8], - ) -> ResponseOutcome { - let status_text = status_text(status); - let headers = format!( - "HTTP/1.1 {status} {status_text}\r\nContent-Type: {content_type}\r\nConnection: close\r\n\r\n" - ); - let _ = stream.write_all(headers.as_bytes()); - let _ = stream.write_all(body); - let _ = stream.flush(); - ResponseOutcome { - status, - body_bytes: body.len(), - } - } - - fn send_bytes_with_headers( - stream: &mut TcpStream, - status: u16, - content_type: &str, - body: &[u8], - extra_headers: &[(&str, String)], - ) -> ResponseOutcome { - let status_text = status_text(status); - let mut headers = format!( - "HTTP/1.1 {status} {status_text}\r\nContent-Length: {}\r\nContent-Type: {content_type}\r\nConnection: close\r\n", - body.len() - ); - for (name, value) in extra_headers { - headers.push_str(name); - headers.push_str(": "); - headers.push_str(value); - headers.push_str("\r\n"); - } - headers.push_str("\r\n"); - let _ = stream.write_all(headers.as_bytes()); - let _ = stream.write_all(body); - let _ = stream.flush(); - ResponseOutcome { - status, - body_bytes: body.len(), - } - } - - fn status_text(status: u16) -> &'static str { - match status { - 200 => "OK", - 206 => "Partial Content", - 302 => "Found", - 400 => "Bad Request", - 401 => "Unauthorized", - 404 => "Not Found", - 501 => "Not Implemented", - _ => "Internal Server Error", - } - } - - fn temp_dir(prefix: &str) -> PathBuf { - let suffix = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic enough for temp paths") - .as_nanos(); - let path = std::env::temp_dir().join(format!("{prefix}-{suffix}")); - fs::create_dir_all(&path).expect("create temp dir"); - path - } -} diff --git a/crates/sidecar/src/service.rs b/crates/sidecar/src/service.rs deleted file mode 100644 index 62ec2aa6d..000000000 --- a/crates/sidecar/src/service.rs +++ /dev/null @@ -1,3645 +0,0 @@ -use crate::bridge::{build_mount_plugin_registry, MountPluginContext}; -pub(crate) use crate::execution::{ - build_javascript_socket_path_context, canonical_signal_name, dispatch_loopback_http_request, - error_code, format_tcp_resource, ignore_stale_javascript_sync_rpc_response, - javascript_sync_rpc_arg_i32, javascript_sync_rpc_arg_str, javascript_sync_rpc_arg_u32, - javascript_sync_rpc_arg_u32_optional, javascript_sync_rpc_arg_u64, - javascript_sync_rpc_arg_u64_optional, javascript_sync_rpc_bytes_arg, - javascript_sync_rpc_bytes_value, javascript_sync_rpc_encoding, javascript_sync_rpc_error_code, - javascript_sync_rpc_option_bool, javascript_sync_rpc_option_u32, kernel_poll_response, - kernel_stdin_read_response, mark_execute_exit_event_queued, parse_kernel_poll_args, - parse_kernel_stdin_read_args, parse_signal, record_execute_exit_event_queue_wait, - record_execute_phase, sanitize_javascript_child_process_internal_bootstrap_env, - service_javascript_sync_rpc, vm_network_resource_counts, JavascriptSyncRpcServiceRequest, - LoopbackHttpDispatchRequest, -}; -use crate::extension::{ - Extension, ExtensionBufferedProcessOutput, ExtensionContext, ExtensionFuture, ExtensionHost, - ExtensionSnapshot, -}; -use crate::filesystem::guest_filesystem_call as filesystem_guest_filesystem_call; -use crate::limits::DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT; -use crate::protocol::{ - CloseStdinRequest, DisposeReason, EventFrame, EventPayload, ExecuteRequest, ExtEnvelope, - GuestFilesystemCallRequest, GuestFilesystemResultResponse, JavascriptChildProcessSpawnOptions, - JavascriptChildProcessSpawnRequest, KillProcessRequest, OpenSessionRequest, OwnershipScope, - ProcessKilledResponse, ProcessStartedResponse, RequestFrame, RequestId, RequestPayload, - ResponseFrame, ResponsePayload, SidecarRequestFrame, SidecarRequestPayload, - SidecarResponseFrame, SidecarResponsePayload, SidecarResponseTracker, - SidecarResponseTrackerError, SignalDispositionAction, StdinClosedResponse, - StdinWrittenResponse, VmLifecycleState, WriteStdinRequest, -}; -use crate::state::{ - ActiveExecutionEvent, BridgeError, ConnectionState, EventSinkTransport, JavascriptSocketFamily, - JavascriptSocketPathContext, ProcessEventEnvelope, SessionState, SharedBridge, SharedEventSink, - SharedSidecarRequestClient, SidecarRequestTransport, VmState, EXECUTION_DRIVER_NAME, -}; -use crate::tools::register_host_callbacks; -use crate::NativeSidecarBridge; -use secure_exec_bridge::queue_tracker::{register_queue, QueueGauge, TrackedLimit}; -use secure_exec_bridge::{ - CommandPermissionRequest, EnvironmentAccess, EnvironmentPermissionRequest, FilesystemAccess, - FilesystemPermissionRequest, LifecycleEventRecord, LifecycleState, LogLevel, LogRecord, - NetworkAccess, NetworkPermissionRequest, StructuredEventRecord, -}; -use secure_exec_execution::{ - record_sync_bridge_request_observed, JavascriptExecutionEngine, JavascriptExecutionError, - JavascriptSyncRpcRequest, PythonExecutionEngine, PythonExecutionError, WasmExecutionEngine, - WasmExecutionError, -}; -use secure_exec_kernel::kernel::KernelError; -use secure_exec_kernel::mount_plugin::{FileSystemPluginRegistry, PluginError}; -use secure_exec_kernel::permissions::{ - CommandAccessRequest, EnvAccessRequest, EnvironmentOperation, NetworkAccessRequest, - NetworkOperation, PermissionDecision, -}; -use secure_exec_sidecar_core::permissions::{ - deny_all_policy, environment_permission_capability, evaluate_permissions_policy, - filesystem_permission_capability, network_permission_capability, - permission_mode_to_kernel_decision, -}; -use secure_exec_sidecar_core::{ - apply_process_signal_state_update, authenticated_response as shared_authenticated_response, - parse_process_signal_state_request, reject as shared_reject, request_dispatch_mode, - respond as shared_respond, route_request_payload, session_opened_response, - unsupported_host_callback_direction_dispatch, validate_authenticate_versions, - vm_lifecycle_event as shared_vm_lifecycle_event, AuthenticateVersionError, RequestDispatchMode, - RequestRoute, -}; -use secure_exec_vm_config::PermissionsPolicy; -// root_fs types moved to crate::vm -use secure_exec_kernel::vfs::VfsError; -use serde::Deserialize; -use serde_json::{json, Value}; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::fmt; -use std::fs; -use std::os::unix::fs::PermissionsExt; -use std::path::{Component, Path, PathBuf}; -use std::sync::{Arc, Mutex, OnceLock}; -use std::task::{Context, Poll, Waker}; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; -use tokio::sync::mpsc::{channel, Receiver, Sender}; -use tokio::time; - -// Constants and type aliases moved to crate::state - -const INTERNAL_JAVASCRIPT_ENTRYPOINT_ENV_KEYS: &[&str] = - &["AGENTOS_ENTRYPOINT", "AGENTOS_BOOTSTRAP_MODULE"]; -const INTERNAL_WASM_ENTRYPOINT_ENV_KEYS: &[&str] = - &["AGENTOS_WASM_MODULE_PATH", "AGENTOS_WASM_MODULE_BASE64"]; -const INTERNAL_PYTHON_ENTRYPOINT_ENV_PREFIXES: &[&str] = &["AGENTOS_PYTHON_"]; -pub(crate) const MAX_PROCESS_EVENT_QUEUE: usize = 10_000; -pub(crate) const MAX_PENDING_SIDECAR_RESPONSES: usize = 10_000; -pub(crate) const MAX_OUTBOUND_SIDECAR_REQUESTS: usize = 10_000; -pub(crate) const MAX_COMPLETED_SIDECAR_RESPONSES: usize = 10_000; -static BLOCKING_DISPATCH_RUNTIME: OnceLock = OnceLock::new(); - -fn blocking_dispatch_runtime() -> &'static tokio::runtime::Runtime { - BLOCKING_DISPATCH_RUNTIME.get_or_init(|| { - tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("sidecar blocking dispatch runtime") - }) -} - -pub(crate) fn process_event_queue_overflow_error() -> SidecarError { - SidecarError::InvalidState(format!( - "process event queue exceeded {MAX_PROCESS_EVENT_QUEUE} pending events" - )) -} - -fn sidecar_response_pending_overflow_error() -> SidecarError { - SidecarError::InvalidState(format!( - "sidecar response tracker exceeded {MAX_PENDING_SIDECAR_RESPONSES} pending responses" - )) -} - -fn outbound_sidecar_request_queue_overflow_error() -> SidecarError { - SidecarError::InvalidState(format!( - "outbound sidecar request queue exceeded {MAX_OUTBOUND_SIDECAR_REQUESTS} pending requests" - )) -} - -fn wire_protocol_error(error: crate::wire::ProtocolCodecError) -> SidecarError { - SidecarError::InvalidState(format!("invalid generated wire protocol frame: {error}")) -} - -fn wire_dispatch_result( - result: DispatchResult, -) -> Result { - crate::wire::dispatch_result_from_compat(crate::wire::CompatDispatchResult { - response: result.response, - events: result.events, - }) - .map_err(wire_protocol_error) -} - -pub use secure_exec_sidecar_core::DispatchResult; -// NativeSidecarConfig and SidecarError moved to crate::state -pub use crate::state::{NativeSidecarConfig, SidecarError}; - -// SharedBridge struct and Clone impl moved to crate::state - -#[derive(Debug, Default, Deserialize)] -struct LegacyJavascriptChildProcessSpawnOptions { - #[serde(default)] - cwd: Option, - #[serde(default)] - env: BTreeMap, - #[serde(default)] - input: Option, - #[serde(default)] - shell: bool, - #[serde(default)] - detached: bool, - #[serde(default)] - stdio: Vec, - #[serde(default, rename = "maxBuffer")] - max_buffer: Option, - #[serde(default)] - timeout: Option, - #[serde(default, rename = "killSignal")] - kill_signal: Option, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct JavascriptHttpLoopbackRequest { - process_id: String, - server_id: u64, - host: String, - port: u16, - request: String, -} - -fn is_javascript_loopback_host(host: &str) -> bool { - host == "127.0.0.1" || host == "::1" || host.eq_ignore_ascii_case("localhost") -} - -pub(crate) fn parse_javascript_child_process_spawn_request( - vm: &VmState, - args: &[Value], -) -> Result<(JavascriptChildProcessSpawnRequest, Option), SidecarError> { - if let Some(value) = args.first().cloned() { - if let Ok(request) = serde_json::from_value::(value) { - return Ok((request, None)); - } - } - - let command = javascript_sync_rpc_arg_str(args, 0, "child_process.spawn command")?.to_owned(); - let raw_args = javascript_sync_rpc_arg_str(args, 1, "child_process.spawn args")?; - let raw_options = javascript_sync_rpc_arg_str(args, 2, "child_process.spawn options")?; - - let parsed_args = serde_json::from_str::>(raw_args).map_err(|error| { - SidecarError::InvalidState(format!("invalid child_process.spawn args payload: {error}")) - })?; - let parsed_options = serde_json::from_str::( - raw_options, - ) - .map_err(|error| { - SidecarError::InvalidState(format!( - "invalid child_process.spawn options payload: {error}" - )) - })?; - - Ok(( - JavascriptChildProcessSpawnRequest { - command, - args: parsed_args, - options: JavascriptChildProcessSpawnOptions { - cwd: parsed_options.cwd, - env: parsed_options.env, - internal_bootstrap_env: sanitize_javascript_child_process_internal_bootstrap_env( - &vm.guest_env, - ), - input: parsed_options.input, - shell: parsed_options.shell, - detached: parsed_options.detached, - stdio: parsed_options.stdio, - timeout: parsed_options.timeout, - kill_signal: parsed_options.kill_signal, - }, - }, - parsed_options.max_buffer, - )) -} - -impl SharedBridge { - fn new(bridge: B) -> Self { - Self { - inner: Arc::new(Mutex::new(bridge)), - permissions: Arc::new(Mutex::new(BTreeMap::new())), - #[cfg(test)] - set_vm_permissions_outcomes: Arc::new(Mutex::new(VecDeque::new())), - } - } -} - -impl SharedBridge -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - pub(crate) fn with_mut( - &self, - operation: impl FnOnce(&mut B) -> Result>, - ) -> Result { - let mut bridge = self.inner.lock().map_err(|_| { - SidecarError::Bridge(String::from("native sidecar bridge lock poisoned")) - })?; - operation(&mut bridge).map_err(|error| SidecarError::Bridge(format!("{error:?}"))) - } - - fn inspect(&self, operation: impl FnOnce(&mut B) -> T) -> Result { - let mut bridge = self.inner.lock().map_err(|_| { - SidecarError::Bridge(String::from("native sidecar bridge lock poisoned")) - })?; - Ok(operation(&mut bridge)) - } - - #[cfg(test)] - #[allow(dead_code)] - pub(crate) fn queue_set_vm_permissions_result( - &self, - result: Result<(), SidecarError>, - ) -> Result<(), SidecarError> { - let mut outcomes = self.set_vm_permissions_outcomes.lock().map_err(|_| { - SidecarError::Bridge(String::from( - "native sidecar test set_vm_permissions outcome lock poisoned", - )) - })?; - outcomes.push_back(result.err()); - Ok(()) - } - - pub(crate) fn emit_lifecycle( - &self, - vm_id: &str, - state: LifecycleState, - ) -> Result<(), SidecarError> { - self.with_mut(|bridge| { - bridge.emit_lifecycle(LifecycleEventRecord { - vm_id: vm_id.to_owned(), - state, - detail: None, - }) - }) - } - - pub(crate) fn emit_log( - &self, - vm_id: &str, - message: impl Into, - ) -> Result<(), SidecarError> { - self.with_mut(|bridge| { - bridge.emit_log(LogRecord { - vm_id: vm_id.to_owned(), - level: LogLevel::Info, - message: message.into(), - }) - }) - } - - pub(crate) fn filesystem_decision( - &self, - vm_id: &str, - path: &str, - access: FilesystemAccess, - ) -> PermissionDecision { - if let Some(decision) = self.static_permission_decision( - vm_id, - filesystem_permission_capability(access), - "fs", - Some(path), - ) { - return decision; - } - match self.with_mut(|bridge| { - bridge.check_filesystem_access(FilesystemPermissionRequest { - vm_id: vm_id.to_owned(), - path: path.to_owned(), - access, - }) - }) { - Ok(decision) => map_bridge_permission(decision), - Err(error) => PermissionDecision::deny(error.to_string()), - } - } - - pub(crate) fn command_decision( - &self, - vm_id: &str, - request: &CommandAccessRequest, - ) -> PermissionDecision { - if is_internal_runtime_command_request(request) { - return PermissionDecision::allow(); - } - if let Some(decision) = self.static_permission_decision( - vm_id, - "child_process.spawn", - "child_process", - Some(&request.command), - ) { - return decision; - } - match self.with_mut(|bridge| { - bridge.check_command_execution(CommandPermissionRequest { - vm_id: vm_id.to_owned(), - command: request.command.clone(), - args: request.args.clone(), - cwd: request.cwd.clone(), - env: request.env.clone(), - }) - }) { - Ok(decision) => map_bridge_permission(decision), - Err(error) => PermissionDecision::deny(error.to_string()), - } - } - - pub(crate) fn environment_decision( - &self, - vm_id: &str, - request: &EnvAccessRequest, - ) -> PermissionDecision { - if let Some(decision) = self.static_permission_decision( - vm_id, - environment_permission_capability(request.op), - "env", - Some(&request.key), - ) { - return decision; - } - match self.with_mut(|bridge| { - bridge.check_environment_access(EnvironmentPermissionRequest { - vm_id: vm_id.to_owned(), - access: match request.op { - EnvironmentOperation::Read => EnvironmentAccess::Read, - EnvironmentOperation::Write => EnvironmentAccess::Write, - }, - key: request.key.clone(), - value: request.value.clone(), - }) - }) { - Ok(decision) => map_bridge_permission(decision), - Err(error) => PermissionDecision::deny(error.to_string()), - } - } - - pub(crate) fn network_decision( - &self, - vm_id: &str, - request: &NetworkAccessRequest, - ) -> PermissionDecision { - if let Some(decision) = self.static_permission_decision( - vm_id, - network_permission_capability(request.op), - "network", - Some(&request.resource), - ) { - return decision; - } - match self.with_mut(|bridge| { - bridge.check_network_access(NetworkPermissionRequest { - vm_id: vm_id.to_owned(), - access: match request.op { - NetworkOperation::Fetch => NetworkAccess::Fetch, - NetworkOperation::Http => NetworkAccess::Http, - NetworkOperation::Dns => NetworkAccess::Dns, - NetworkOperation::Listen => NetworkAccess::Listen, - }, - resource: request.resource.clone(), - }) - }) { - Ok(decision) => map_bridge_permission(decision), - Err(error) => PermissionDecision::deny(error.to_string()), - } - } - - pub(crate) fn require_network_access( - &self, - vm_id: &str, - op: NetworkOperation, - resource: impl Into, - ) -> Result<(), SidecarError> { - let resource = resource.into(); - let decision = self.network_decision( - vm_id, - &NetworkAccessRequest { - vm_id: vm_id.to_owned(), - op, - resource: resource.clone(), - }, - ); - if decision.allow { - return Ok(()); - } - - let message = match decision.reason.as_deref() { - Some(reason) => format!("EACCES: permission denied, {resource}: {reason}"), - None => format!("EACCES: permission denied, {resource}"), - }; - Err(SidecarError::Execution(message)) - } - - pub(crate) fn set_vm_permissions( - &self, - vm_id: &str, - permissions: &PermissionsPolicy, - ) -> Result<(), SidecarError> { - #[cfg(test)] - { - let mut outcomes = self.set_vm_permissions_outcomes.lock().map_err(|_| { - SidecarError::Bridge(String::from( - "native sidecar test set_vm_permissions outcome lock poisoned", - )) - })?; - if let Some(Some(error)) = outcomes.pop_front() { - return Err(error); - } - } - - let mut stored = self.permissions.lock().map_err(|_| { - SidecarError::Bridge(String::from( - "native sidecar permission policy lock poisoned", - )) - })?; - stored.insert(vm_id.to_owned(), permissions.clone()); - Ok(()) - } - - pub(crate) fn restore_vm_permissions_fail_closed( - &self, - vm_id: &str, - original_permissions: &PermissionsPolicy, - context: &str, - operation_error: &SidecarError, - ) -> Result<(), SidecarError> { - match self.set_vm_permissions(vm_id, original_permissions) { - Ok(()) => Ok(()), - Err(restore_error) => { - let deny_all = deny_all_policy(); - match self.set_vm_permissions(vm_id, &deny_all) { - Ok(()) => Err(SidecarError::InvalidState(format!( - "{context} failed: {operation_error}; restoring original permissions failed: {restore_error}; applied deny-all fallback" - ))), - Err(deny_all_error) => panic!( - "{context} failed: {operation_error}; restoring original permissions failed: {restore_error}; deny-all fallback failed: {deny_all_error}" - ), - } - } - } - } - - pub(crate) fn clear_vm_permissions(&self, vm_id: &str) -> Result<(), SidecarError> { - let mut stored = self.permissions.lock().map_err(|_| { - SidecarError::Bridge(String::from( - "native sidecar permission policy lock poisoned", - )) - })?; - stored.remove(vm_id); - Ok(()) - } - - pub(crate) fn static_permission_decision( - &self, - vm_id: &str, - capability: &str, - domain: &str, - resource: Option<&str>, - ) -> Option { - let stored = self.permissions.lock().ok()?; - let permissions = stored.get(vm_id)?; - let mode = evaluate_permissions_policy(permissions, domain, capability, resource); - Some(permission_mode_to_kernel_decision(mode, capability)) - } -} - -pub(crate) fn validate_permissions_policy( - permissions: &PermissionsPolicy, -) -> Result<(), SidecarError> { - secure_exec_sidecar_core::permissions::validate_permissions_policy(permissions) - .map_err(|error| SidecarError::InvalidState(error.to_string())) -} - -fn is_internal_runtime_command_request(request: &CommandAccessRequest) -> bool { - match request.command.as_str() { - "node" => request - .env - .keys() - .any(|key| INTERNAL_JAVASCRIPT_ENTRYPOINT_ENV_KEYS.contains(&key.as_str())), - "wasm" => request - .env - .keys() - .any(|key| INTERNAL_WASM_ENTRYPOINT_ENV_KEYS.contains(&key.as_str())), - "python" => request.env.keys().any(|key| { - INTERNAL_PYTHON_ENTRYPOINT_ENV_PREFIXES - .iter() - .any(|prefix| key.starts_with(prefix)) - }), - _ => false, - } -} - -fn ownership_matches_process_event( - ownership: &OwnershipScope, - event: &ProcessEventEnvelope, -) -> bool { - match ownership { - OwnershipScope::ConnectionOwnership(inner) => inner.connection_id == event.connection_id, - OwnershipScope::SessionOwnership(inner) => { - inner.connection_id == event.connection_id && inner.session_id == event.session_id - } - OwnershipScope::VmOwnership(inner) => { - inner.connection_id == event.connection_id - && inner.session_id == event.session_id - && inner.vm_id == event.vm_id - } - } -} - -fn public_process_event_matches_ownership( - sidecar: &NativeSidecar, - ownership: &OwnershipScope, - event: &ProcessEventEnvelope, -) -> bool -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - if !ownership_matches_process_event(ownership, event) { - return false; - } - - if event.process_id.contains('/') { - return false; - } - - // Stale queued events must still be drained through handle_process_event_envelope() - // so the sidecar can emit the expected fail-closed log when teardown wins the race. - let _ = sidecar; - true -} - -fn poll_future_once(future: std::pin::Pin<&mut F>) -> Option { - let mut context = Context::from_waker(Waker::noop()); - match future.poll(&mut context) { - Poll::Ready(output) => Some(output), - Poll::Pending => None, - } -} - -// ConnectionState, SessionState, VmConfiguration, VmState moved to crate::state - -// JavascriptSocketPathContext, JavascriptSocketFamily, VmListenPolicy moved to crate::state - -impl JavascriptSocketPathContext { - pub(crate) fn loopback_port_allowed(&self, port: u16) -> bool { - self.loopback_exempt_ports.contains(&port) - || self - .tcp_loopback_guest_to_host_ports - .keys() - .any(|(_, guest_port)| *guest_port == port) - } - - pub(crate) fn translate_tcp_loopback_port( - &self, - family: JavascriptSocketFamily, - port: u16, - ) -> Option { - self.tcp_loopback_guest_to_host_ports - .get(&(family, port)) - .copied() - } - - pub(crate) fn http_loopback_target( - &self, - family: JavascriptSocketFamily, - port: u16, - ) -> Option<&crate::state::JavascriptHttpLoopbackTarget> { - self.http_loopback_targets.get(&(family, port)) - } - - pub(crate) fn translate_udp_loopback_port( - &self, - family: JavascriptSocketFamily, - port: u16, - ) -> Option { - self.udp_loopback_guest_to_host_ports - .get(&(family, port)) - .copied() - } - - pub(crate) fn guest_udp_port_for_host_port( - &self, - family: JavascriptSocketFamily, - port: u16, - ) -> Option { - self.udp_loopback_host_to_guest_ports - .get(&(family, port)) - .copied() - } -} - -// ActiveProcess, NetworkResourceCounts moved to crate::state - -pub struct NativeSidecar { - pub(crate) config: NativeSidecarConfig, - pub(crate) bridge: SharedBridge, - pub(crate) mount_plugins: FileSystemPluginRegistry>, - pub(crate) cache_root: PathBuf, - pub(crate) javascript_engine: JavascriptExecutionEngine, - pub(crate) python_engine: PythonExecutionEngine, - pub(crate) wasm_engine: WasmExecutionEngine, - pub(crate) next_connection_id: usize, - pub(crate) next_session_id: usize, - pub(crate) next_vm_id: usize, - pub(crate) next_sidecar_request_id: RequestId, - pub(crate) connections: BTreeMap, - pub(crate) sessions: BTreeMap, - pub(crate) vms: BTreeMap, - #[allow(dead_code)] - pub(crate) process_event_sender: Sender, - pub(crate) process_event_receiver: Option>, - pub(crate) pending_process_events: VecDeque, - pub(crate) pending_sidecar_responses: SidecarResponseTracker, - pub(crate) outbound_sidecar_requests: VecDeque, - pub(crate) completed_sidecar_responses: BTreeMap, - pub(crate) completed_sidecar_response_order: VecDeque, - pub(crate) completed_sidecar_responses_gauge: Arc, - pub(crate) pending_process_events_gauge: Arc, - pub(crate) pending_sidecar_responses_gauge: Arc, - pub(crate) outbound_sidecar_requests_gauge: Arc, - pub(crate) sidecar_requests: SharedSidecarRequestClient, - pub(crate) event_sink: SharedEventSink, - pub(crate) extensions: BTreeMap>, - pub(crate) extension_sessions: BTreeMap<(String, String), ExtensionSessionResources>, - pub(crate) extension_process_output_buffers: - BTreeMap<(String, String), ExtensionBufferedProcessOutput>, - /// Session scopes (connection_id, session_id) disposed since the stdio - /// transport last drained them. Lets the transport remove dead sessions from - /// its active-session set instead of iterating them forever (M5). - pub(crate) disposed_sessions: Vec<(String, String)>, -} - -#[derive(Debug)] -pub(crate) struct ExtensionSessionResources { - pub(crate) ownership: OwnershipScope, - pub(crate) process_ids: BTreeSet, - pub(crate) vm_ids: BTreeSet, -} - -impl fmt::Debug for NativeSidecar { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("NativeSidecar") - .field("config", &self.config) - .field("cache_root", &self.cache_root) - .field("next_connection_id", &self.next_connection_id) - .field("next_session_id", &self.next_session_id) - .field("next_vm_id", &self.next_vm_id) - .field("connection_count", &self.connections.len()) - .field("session_count", &self.sessions.len()) - .field("vm_count", &self.vms.len()) - .field("extension_session_count", &self.extension_sessions.len()) - .field( - "extension_process_output_buffer_count", - &self.extension_process_output_buffers.len(), - ) - .finish() - } -} - -impl NativeSidecar -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - pub fn new(bridge: B) -> Result { - Self::with_config(bridge, NativeSidecarConfig::default()) - } - - pub fn with_config(bridge: B, config: NativeSidecarConfig) -> Result { - if matches!(config.expected_auth_token.as_deref(), Some("")) { - return Err(SidecarError::InvalidState(String::from( - "native sidecar expected_auth_token must not be empty", - ))); - } - - let cache_root = config.compile_cache_root.clone().unwrap_or_else(|| { - std::env::temp_dir().join(format!( - "{}-{}", - config.sidecar_id, - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_nanos() - )) - }); - fs::create_dir_all(&cache_root).map_err(|error| { - SidecarError::Io(format!("failed to prepare sidecar cache root: {error}")) - })?; - - let bridge = SharedBridge::new(bridge); - let mount_plugins = build_mount_plugin_registry::()?; - let (process_event_sender, process_event_receiver) = channel(MAX_PROCESS_EVENT_QUEUE); - - Ok(Self { - config, - bridge, - mount_plugins, - cache_root, - javascript_engine: JavascriptExecutionEngine::default(), - python_engine: PythonExecutionEngine::default(), - wasm_engine: WasmExecutionEngine::default(), - next_connection_id: 0, - next_session_id: 0, - next_vm_id: 0, - next_sidecar_request_id: -1, - connections: BTreeMap::new(), - sessions: BTreeMap::new(), - vms: BTreeMap::new(), - process_event_sender, - process_event_receiver: Some(process_event_receiver), - pending_process_events: VecDeque::new(), - pending_sidecar_responses: SidecarResponseTracker::default(), - outbound_sidecar_requests: VecDeque::new(), - completed_sidecar_responses: BTreeMap::new(), - completed_sidecar_response_order: VecDeque::new(), - completed_sidecar_responses_gauge: register_queue( - TrackedLimit::CompletedSidecarResponses, - MAX_COMPLETED_SIDECAR_RESPONSES, - ), - pending_process_events_gauge: register_queue( - TrackedLimit::PendingProcessEvents, - MAX_PROCESS_EVENT_QUEUE, - ), - pending_sidecar_responses_gauge: register_queue( - TrackedLimit::PendingSidecarResponses, - MAX_PENDING_SIDECAR_RESPONSES, - ), - outbound_sidecar_requests_gauge: register_queue( - TrackedLimit::OutboundSidecarRequests, - MAX_OUTBOUND_SIDECAR_REQUESTS, - ), - sidecar_requests: SharedSidecarRequestClient::default(), - event_sink: SharedEventSink::default(), - extensions: BTreeMap::new(), - extension_sessions: BTreeMap::new(), - extension_process_output_buffers: BTreeMap::new(), - disposed_sessions: Vec::new(), - }) - } - - pub fn with_config_and_extensions( - bridge: B, - config: NativeSidecarConfig, - extensions: Vec>, - ) -> Result { - let mut sidecar = Self::with_config(bridge, config)?; - for extension in extensions { - sidecar.register_extension(extension)?; - } - Ok(sidecar) - } - - pub(crate) fn prune_extension_process_resource(&mut self, process_id: &str) { - self.extension_sessions.retain(|_, resources| { - resources.process_ids.remove(process_id); - !resources.process_ids.is_empty() || !resources.vm_ids.is_empty() - }); - } - - pub(crate) fn prune_extension_vm_resource(&mut self, vm_id: &str) { - self.extension_sessions.retain(|_, resources| { - if matches!( - &resources.ownership, - OwnershipScope::VmOwnership(inner) if inner.vm_id == vm_id - ) { - resources.process_ids.clear(); - } - resources.vm_ids.remove(vm_id); - !resources.process_ids.is_empty() || !resources.vm_ids.is_empty() - }); - } - - /// Reclaim every per-VM tracking entry owned by the sidecar for `vm_id`. - /// - /// Called unconditionally from `dispose_vm_internal` so that a fallible - /// teardown step (root-filesystem snapshot/flush, kernel dispose, permission - /// reset) erroring out with `?` can never strand these maps for the rest of - /// the process lifetime (H1). This also reclaims the ACP output-buffer map, - /// which was previously removed only on a successful handoff and leaked on VM - /// or session disposal (M6). - pub(crate) fn reclaim_vm_tracking(&mut self, session_id: &str, vm_id: &str) { - self.javascript_engine.dispose_vm(vm_id); - self.python_engine.dispose_vm(vm_id); - self.wasm_engine.dispose_vm(vm_id); - self.prune_extension_vm_resource(vm_id); - self.extension_process_output_buffers - .retain(|(buffer_vm_id, _process_id), _| buffer_vm_id != vm_id); - if let Some(session) = self.sessions.get_mut(session_id) { - session.vm_ids.remove(vm_id); - } - } - - pub(crate) fn capture_extension_process_output_event( - &mut self, - vm_id: &str, - process_id: &str, - event: &ActiveExecutionEvent, - ) -> bool { - let Some(buffer) = self - .extension_process_output_buffers - .get_mut(&(vm_id.to_string(), process_id.to_string())) - else { - return false; - }; - match event { - ActiveExecutionEvent::Stdout(chunk) => { - buffer.append_stdout(chunk, DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT); - true - } - ActiveExecutionEvent::Stderr(chunk) => { - buffer.append_stderr(chunk, DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT); - true - } - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } - | ActiveExecutionEvent::Exited(_) => false, - } - } - - fn bind_extension_process_resource( - &mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - process_id: String, - ) -> Result<(), SidecarError> { - if ext_session_id.is_empty() { - return Err(SidecarError::InvalidState(String::from( - "extension session id must not be empty", - ))); - } - let (connection_id, session_id, vm_id) = self.vm_scope_for(&ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - let process_exists = self - .vms - .get(&vm_id) - .is_some_and(|vm| vm.active_processes.contains_key(&process_id)); - if !process_exists { - return Err(SidecarError::InvalidState(format!( - "VM {vm_id} has no active process {process_id}" - ))); - } - - let key = (namespace, ext_session_id); - if let Some(resources) = self.extension_sessions.get_mut(&key) { - if resources.ownership != ownership { - return Err(SidecarError::InvalidState(String::from( - "extension session ownership did not match existing resources", - ))); - } - resources.process_ids.insert(process_id); - } else { - self.extension_sessions.insert( - key, - ExtensionSessionResources { - ownership, - process_ids: BTreeSet::from([process_id]), - vm_ids: BTreeSet::new(), - }, - ); - } - Ok(()) - } - - fn bind_extension_vm_resource( - &mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - ) -> Result<(), SidecarError> { - if ext_session_id.is_empty() { - return Err(SidecarError::InvalidState(String::from( - "extension session id must not be empty", - ))); - } - let (connection_id, session_id, vm_id) = self.vm_scope_for(&ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let key = (namespace, ext_session_id); - if let Some(resources) = self.extension_sessions.get_mut(&key) { - if resources.ownership != ownership { - return Err(SidecarError::InvalidState(String::from( - "extension session ownership did not match existing resources", - ))); - } - resources.vm_ids.insert(vm_id); - } else { - self.extension_sessions.insert( - key, - ExtensionSessionResources { - ownership, - process_ids: BTreeSet::new(), - vm_ids: BTreeSet::from([vm_id]), - }, - ); - } - Ok(()) - } - - pub fn sidecar_id(&self) -> &str { - &self.config.sidecar_id - } - - pub fn with_bridge_mut( - &self, - operation: impl FnOnce(&mut B) -> T, - ) -> Result { - self.bridge.inspect(operation) - } - - pub fn set_sidecar_request_transport(&mut self, transport: Arc) { - self.sidecar_requests.set_transport(transport); - } - - pub fn set_event_transport(&mut self, transport: Arc) { - self.event_sink.set_transport(transport); - } - - pub fn register_extension( - &mut self, - extension: Box, - ) -> Result<(), SidecarError> { - let namespace = extension.namespace().to_owned(); - if namespace.is_empty() { - return Err(SidecarError::InvalidState(String::from( - "extension namespace must not be empty", - ))); - } - if self.extensions.contains_key(&namespace) { - return Err(SidecarError::Conflict(format!( - "extension namespace {namespace} is already registered", - ))); - } - self.extensions.insert(namespace, Arc::from(extension)); - Ok(()) - } - - pub fn set_sidecar_request_handler(&mut self, handler: F) - where - F: Fn(SidecarRequestFrame) -> Result - + Send - + Sync - + 'static, - { - struct HandlerTransport(F); - - impl SidecarRequestTransport for HandlerTransport - where - F: Fn(SidecarRequestFrame) -> Result - + Send - + Sync - + 'static, - { - fn send_request( - &self, - request: SidecarRequestFrame, - _timeout: Duration, - ) -> Result { - let payload = (self.0)(request.clone())?; - Ok(SidecarResponseFrame::new( - request.request_id, - request.ownership, - payload, - )) - } - } - - self.set_sidecar_request_transport(Arc::new(HandlerTransport(handler))); - } - - pub fn set_wire_sidecar_request_handler(&mut self, handler: F) - where - F: Fn( - crate::wire::SidecarRequestFrame, - ) -> Result - + Send - + Sync - + 'static, - { - self.set_sidecar_request_handler(move |request| { - let request = crate::wire::sidecar_request_frame_from_compat(request) - .map_err(wire_protocol_error)?; - let response = handler(request)?; - let response = crate::wire::sidecar_response_frame_to_compat(response) - .map_err(wire_protocol_error)?; - Ok(response.payload) - }); - } - - pub(crate) fn queue_pending_process_event( - &mut self, - envelope: ProcessEventEnvelope, - ) -> Result<(), SidecarError> { - if self.pending_process_events.len() >= MAX_PROCESS_EVENT_QUEUE { - return Err(process_event_queue_overflow_error()); - } - if matches!(&envelope.event, ActiveExecutionEvent::Exited(_)) { - mark_execute_exit_event_queued(&envelope.vm_id, &envelope.process_id); - } - self.pending_process_events.push_back(envelope); - self.pending_process_events_gauge - .observe_depth(self.pending_process_events.len()); - Ok(()) - } - - pub(crate) fn queue_front_pending_process_event( - &mut self, - envelope: ProcessEventEnvelope, - ) -> Result<(), SidecarError> { - if self.pending_process_events.len() >= MAX_PROCESS_EVENT_QUEUE { - return Err(process_event_queue_overflow_error()); - } - if matches!(&envelope.event, ActiveExecutionEvent::Exited(_)) { - mark_execute_exit_event_queued(&envelope.vm_id, &envelope.process_id); - } - self.pending_process_events.push_front(envelope); - self.pending_process_events_gauge - .observe_depth(self.pending_process_events.len()); - Ok(()) - } - - pub(crate) fn pending_process_event_capacity(&self) -> usize { - MAX_PROCESS_EVENT_QUEUE.saturating_sub(self.pending_process_events.len()) - } - - pub fn dispatch_blocking( - &mut self, - request: RequestFrame, - ) -> Result { - let inside_runtime = tokio::runtime::Handle::try_current().is_ok(); - if request_dispatch_mode(&request) == RequestDispatchMode::Async && !inside_runtime { - return blocking_dispatch_runtime().block_on(self.dispatch(request)); - } - - let mut future = std::pin::pin!(self.dispatch(request)); - match poll_future_once(future.as_mut()) { - Some(result) => result, - None if inside_runtime => Err(SidecarError::InvalidState(String::from( - "dispatch_blocking cannot wait for an async sidecar request inside a Tokio runtime; use dispatch().await", - ))), - None => blocking_dispatch_runtime().block_on(future), - } - } - - pub fn dispatch_wire_blocking( - &mut self, - request: crate::wire::RequestFrame, - ) -> Result { - let request = crate::wire::request_frame_to_compat(request).map_err(wire_protocol_error)?; - let result = self.dispatch_blocking(request)?; - wire_dispatch_result(result) - } - - pub fn poll_event_blocking( - &mut self, - ownership: &OwnershipScope, - timeout: Duration, - ) -> Result, SidecarError> { - blocking_dispatch_runtime().block_on(self.poll_event(ownership, timeout)) - } - - pub fn poll_event_wire_blocking( - &mut self, - ownership: &crate::wire::OwnershipScope, - timeout: Duration, - ) -> Result, SidecarError> { - let ownership = crate::wire::ownership_scope_to_compat(ownership.clone()); - self.poll_event_blocking(&ownership, timeout)? - .map(crate::wire::event_frame_from_compat) - .transpose() - .map_err(wire_protocol_error) - } - - pub fn close_session_blocking( - &mut self, - connection_id: &str, - session_id: &str, - ) -> Result, SidecarError> { - blocking_dispatch_runtime().block_on(self.close_session(connection_id, session_id)) - } - - pub fn remove_connection_blocking( - &mut self, - connection_id: &str, - ) -> Result, SidecarError> { - blocking_dispatch_runtime().block_on(self.remove_connection(connection_id)) - } - - pub fn dispose_vm_internal_blocking( - &mut self, - connection_id: &str, - session_id: &str, - vm_id: &str, - reason: DisposeReason, - ) -> Result, SidecarError> { - blocking_dispatch_runtime().block_on(self.dispose_vm_internal( - connection_id, - session_id, - vm_id, - reason, - )) - } - - pub async fn dispatch( - &mut self, - request: RequestFrame, - ) -> Result { - if let Err(error) = self.ensure_request_within_frame_limit(&request) { - return Ok(DispatchResult { - response: self.reject(&request, error_code(&error), &error.to_string()), - events: Vec::new(), - }); - } - - let result = match route_request_payload(&request) { - RequestRoute::Authenticate(payload) => { - self.authenticate_connection(&request, payload).await - } - RequestRoute::OpenSession(payload) => self.open_session(&request, payload).await, - RequestRoute::CreateVm(payload) => self.create_vm(&request, payload).await, - RequestRoute::DisposeVm(payload) => self.dispose_vm(&request, payload).await, - RequestRoute::BootstrapRootFilesystem(payload) => { - self.bootstrap_root_filesystem(&request, payload.entries) - .await - } - RequestRoute::ConfigureVm(payload) => self.configure_vm(&request, payload).await, - RequestRoute::RegisterHostCallbacks(payload) => { - register_host_callbacks(self, &request, payload) - } - RequestRoute::CreateLayer(payload) => self.create_layer(&request, payload).await, - RequestRoute::SealLayer(payload) => self.seal_layer(&request, payload).await, - RequestRoute::ImportSnapshot(payload) => self.import_snapshot(&request, payload).await, - RequestRoute::ExportSnapshot(payload) => self.export_snapshot(&request, payload).await, - RequestRoute::CreateOverlay(payload) => self.create_overlay(&request, payload).await, - RequestRoute::GuestFilesystemCall(payload) => { - self.guest_filesystem_call(&request, payload).await - } - RequestRoute::GuestKernelCall(payload) => { - self.guest_kernel_call(&request, payload).await - } - RequestRoute::SnapshotRootFilesystem(payload) => { - self.snapshot_root_filesystem(&request, payload).await - } - RequestRoute::Execute(payload) => self.execute(&request, payload).await, - RequestRoute::WriteStdin(payload) => self.write_stdin(&request, payload).await, - RequestRoute::ResizePty(payload) => self.resize_pty(&request, payload).await, - RequestRoute::CloseStdin(payload) => self.close_stdin(&request, payload).await, - RequestRoute::KillProcess(payload) => self.kill_process(&request, payload).await, - RequestRoute::GetProcessSnapshot(payload) => { - self.get_process_snapshot(&request, payload).await - } - RequestRoute::GetResourceSnapshot(payload) => { - self.get_resource_snapshot(&request, payload).await - } - RequestRoute::FindListener(payload) => self.find_listener(&request, payload).await, - RequestRoute::FindBoundUdp(payload) => self.find_bound_udp(&request, payload).await, - RequestRoute::VmFetch(payload) => self.vm_fetch(&request, payload).await, - RequestRoute::GetSignalState(payload) => self.get_signal_state(&request, payload).await, - RequestRoute::GetZombieTimerCount(payload) => { - self.get_zombie_timer_count(&request, payload).await - } - RequestRoute::LinkPackage(payload) => self.link_package(&request, payload).await, - RequestRoute::ProvidedCommands(payload) => { - self.provided_commands(&request, payload).await - } - RequestRoute::UnsupportedHostCallbackDirection => { - Ok(unsupported_host_callback_direction_dispatch(&request)) - } - RequestRoute::Ext(payload) => self.dispatch_extension_request(&request, payload).await, - }; - - match result { - Ok(dispatch) => Ok(dispatch), - Err(error @ SidecarError::Io(_)) => Err(error), - Err(error) => Ok(DispatchResult { - response: self.reject(&request, error_code(&error), &error.to_string()), - events: Vec::new(), - }), - } - } - - pub async fn dispatch_wire( - &mut self, - request: crate::wire::RequestFrame, - ) -> Result { - let request = crate::wire::request_frame_to_compat(request).map_err(wire_protocol_error)?; - let result = self.dispatch(request).await?; - wire_dispatch_result(result) - } - - pub async fn poll_event_wire( - &mut self, - ownership: &crate::wire::OwnershipScope, - timeout: Duration, - ) -> Result, SidecarError> { - let ownership = crate::wire::ownership_scope_to_compat(ownership.clone()); - self.poll_event(&ownership, timeout) - .await? - .map(crate::wire::event_frame_from_compat) - .transpose() - .map_err(wire_protocol_error) - } - - async fn dispatch_extension_request( - &mut self, - request: &RequestFrame, - envelope: ExtEnvelope, - ) -> Result { - let namespace = envelope.namespace; - let Some(extension) = self.extensions.get(&namespace).cloned() else { - return Ok(DispatchResult { - response: self.reject( - request, - "unknown_extension", - &format!("no extension registered for namespace {namespace}"), - ), - events: Vec::new(), - }); - }; - let snapshot = ExtensionSnapshot::new( - namespace.clone(), - request.ownership.clone(), - self.sidecar_requests.clone(), - self.event_sink.clone(), - ); - let ctx = ExtensionContext::new(snapshot, self); - let response = extension.handle_request(ctx, envelope.payload).await?; - Ok(DispatchResult { - response: self.respond( - request, - ResponsePayload::ExtResult(ExtEnvelope { - namespace, - payload: response.payload, - }), - ), - events: response.events, - }) - } - - pub async fn poll_event( - &mut self, - ownership: &OwnershipScope, - timeout: Duration, - ) -> Result, SidecarError> { - let deadline = Instant::now() + timeout; - loop { - if let Some(index) = self - .pending_process_events - .iter() - .position(|event| public_process_event_matches_ownership(self, ownership, event)) - { - let Some(envelope) = self.pending_process_events.remove(index) else { - continue; - }; - if let Some(frame) = self.handle_process_event_envelope(envelope)? { - return Ok(Some(frame)); - } - continue; - } - - if !timeout.is_zero() { - let _ = self.pump_process_events(ownership).await?; - } - - let queued_envelopes = { - let pending_capacity = self.pending_process_event_capacity(); - let receiver = self.process_event_receiver.as_mut().ok_or_else(|| { - SidecarError::InvalidState(String::from("process event receiver unavailable")) - })?; - let mut queued = Vec::new(); - loop { - if queued.len() >= pending_capacity { - if receiver.is_empty() { - break; - } - return Err(process_event_queue_overflow_error()); - } - match receiver.try_recv() { - Ok(envelope) => queued.push(envelope), - Err(tokio::sync::mpsc::error::TryRecvError::Empty) => break, - Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => break, - } - } - queued - }; - - let mut matching_envelope = None; - for envelope in queued_envelopes { - if matching_envelope.is_none() - && public_process_event_matches_ownership(self, ownership, &envelope) - { - matching_envelope = Some(envelope); - } else { - self.queue_pending_process_event(envelope)?; - } - } - - if let Some(envelope) = matching_envelope { - if let Some(frame) = self.handle_process_event_envelope(envelope)? { - return Ok(Some(frame)); - } - continue; - } - - if Instant::now() >= deadline { - return Ok(None); - } - - let remaining = deadline.saturating_duration_since(Instant::now()); - time::sleep(remaining.min(Duration::from_millis(10))).await; - } - } - - pub(crate) fn handle_process_event_envelope( - &mut self, - envelope: ProcessEventEnvelope, - ) -> Result, SidecarError> { - let handle_start = Instant::now(); - let ProcessEventEnvelope { - connection_id, - session_id, - vm_id, - process_id, - event, - } = envelope; - - let is_exit_event = matches!(event, ActiveExecutionEvent::Exited(_)); - - if is_exit_event { - record_execute_exit_event_queue_wait( - "process_exit_event_queue_wait", - &vm_id, - &process_id, - ); - let mut trailing = Vec::new(); - let mut deferred = VecDeque::new(); - let phase_start = Instant::now(); - while let Some(pending) = self.pending_process_events.pop_front() { - if pending.vm_id == vm_id - && pending.process_id == process_id - && !matches!(pending.event, ActiveExecutionEvent::Exited(_)) - { - trailing.push(pending.event); - } else { - deferred.push_back(pending); - } - } - self.pending_process_events = deferred; - record_execute_phase("process_exit_trailing_pending_scan", phase_start.elapsed()); - let drain_limit = self - .pending_process_event_capacity() - .saturating_sub(trailing.len().saturating_add(1)); - let phase_start = Instant::now(); - trailing.extend( - self.drain_process_events_blocking_with_limit(&vm_id, &process_id, drain_limit)? - .into_iter() - .filter(|event| !matches!(event, ActiveExecutionEvent::Exited(_))), - ); - record_execute_phase( - "process_exit_trailing_blocking_drain", - phase_start.elapsed(), - ); - - if !trailing.is_empty() { - if self.pending_process_event_capacity() < trailing.len() { - return Err(process_event_queue_overflow_error()); - } - let emit_now = if self.pending_process_event_capacity() == trailing.len() { - Some(trailing.remove(0)) - } else { - None - }; - let phase_start = Instant::now(); - mark_execute_exit_event_queued(&vm_id, &process_id); - self.queue_front_pending_process_event(ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - process_id: process_id.clone(), - event, - })?; - for event in trailing.into_iter().rev() { - self.queue_front_pending_process_event(ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - process_id: process_id.clone(), - event, - })?; - } - record_execute_phase("process_exit_trailing_requeue", phase_start.elapsed()); - if let Some(event) = emit_now { - let result = self.handle_execution_event(&vm_id, &process_id, event); - record_execute_phase( - "process_exit_event_handle_envelope_total", - handle_start.elapsed(), - ); - return result; - } - record_execute_phase( - "process_exit_event_handle_envelope_total", - handle_start.elapsed(), - ); - return Ok(None); - } - } - - let result = self.handle_execution_event(&vm_id, &process_id, event); - if is_exit_event { - record_execute_phase( - "process_exit_event_handle_envelope_total", - handle_start.elapsed(), - ); - } - result - } - - // try_poll_event moved to crate::execution - - pub async fn close_session( - &mut self, - connection_id: &str, - session_id: &str, - ) -> Result, SidecarError> { - self.dispose_session(connection_id, session_id, DisposeReason::Requested) - .await - } - - pub async fn remove_connection( - &mut self, - connection_id: &str, - ) -> Result, SidecarError> { - self.require_authenticated_connection(connection_id)?; - - let session_ids = self - .connections - .get(connection_id) - .expect("authenticated connection should exist") - .sessions - .iter() - .cloned() - .collect::>(); - - let mut events = Vec::new(); - let mut first_error: Option = None; - for session_id in session_ids { - // Attempt EVERY session; aggregate errors instead of `?`-ing out on - // the first so one wedged session cannot abandon the rest (H1). - match self - .dispose_session(connection_id, &session_id, DisposeReason::ConnectionClosed) - .await - { - Ok(session_events) => events.extend(session_events), - Err(error) => { - if first_error.is_none() { - first_error = Some(error); - } - } - } - } - - self.connections.remove(connection_id); - if let Some(error) = first_error { - return Err(error); - } - Ok(events) - } - - async fn authenticate_connection( - &mut self, - request: &RequestFrame, - payload: crate::protocol::AuthenticateRequest, - ) -> Result { - let _ = self.connection_id_for(&request.ownership)?; - if let Err(error) = self.validate_auth_token(&payload.auth_token) { - let mut fields = audit_fields([ - (String::from("source"), payload.client_name.clone()), - (String::from("reason"), error.to_string()), - ]); - if let OwnershipScope::ConnectionOwnership(inner) = &request.ownership { - fields.insert(String::from("connection_id"), inner.connection_id.clone()); - } - emit_security_audit_event( - &self.bridge, - &self.config.sidecar_id, - "security.auth.failed", - fields, - ); - return Err(error); - } - - if let Err(error) = validate_authenticate_versions(&payload) { - return Err(match error { - AuthenticateVersionError::ProtocolVersionMismatch(message) => { - SidecarError::ProtocolVersionMismatch(message) - } - AuthenticateVersionError::BridgeVersionMismatch(message) => { - SidecarError::BridgeVersionMismatch(message) - } - }); - } - - let connection_id = self.allocate_connection_id(); - self.connections.insert( - connection_id.clone(), - ConnectionState { - auth_token: payload.auth_token, - sessions: BTreeSet::new(), - }, - ); - - let response = shared_authenticated_response( - request.request_id, - self.config.sidecar_id.clone(), - connection_id, - self.config.max_frame_bytes as u32, - ); - Ok(DispatchResult { - response, - events: Vec::new(), - }) - } - - async fn open_session( - &mut self, - request: &RequestFrame, - payload: OpenSessionRequest, - ) -> Result { - let connection_id = self.connection_id_for(&request.ownership)?; - self.require_authenticated_connection(&connection_id)?; - - self.next_session_id += 1; - let session_id = format!("session-{}", self.next_session_id); - self.sessions.insert( - session_id.clone(), - SessionState { - connection_id: connection_id.clone(), - placement: payload.placement, - metadata: payload.metadata.into_iter().collect(), - vm_ids: BTreeSet::new(), - }, - ); - self.connections - .get_mut(&connection_id) - .expect("authenticated connection should exist") - .sessions - .insert(session_id.clone()); - - Ok(DispatchResult { - response: session_opened_response(request.request_id, connection_id, session_id), - events: Vec::new(), - }) - } - - // create_vm, dispose_vm, bootstrap_root_filesystem, configure_vm moved to crate::vm - - async fn guest_filesystem_call( - &mut self, - request: &RequestFrame, - payload: GuestFilesystemCallRequest, - ) -> Result { - filesystem_guest_filesystem_call(self, request, payload).await - } - - // snapshot_root_filesystem moved to crate::vm - - // execute, write_stdin, close_stdin, kill_process, find_listener, find_bound_udp, - // get_signal_state, get_zombie_timer_count moved to crate::execution - - async fn dispose_session( - &mut self, - connection_id: &str, - session_id: &str, - reason: DisposeReason, - ) -> Result, SidecarError> { - self.require_owned_session(connection_id, session_id)?; - - let vm_ids = self - .sessions - .get(session_id) - .expect("owned session should exist") - .vm_ids - .iter() - .cloned() - .collect::>(); - - let mut events = Vec::new(); - let mut first_error: Option = None; - for vm_id in vm_ids { - // Attempt EVERY VM; aggregate errors instead of `?`-ing out on the - // first so one stuck VM cannot strand the remaining VMs' teardown and - // leave the session permanently un-reclaimed (H1). - match self - .dispose_vm_internal(connection_id, session_id, &vm_id, reason.clone()) - .await - { - Ok(vm_events) => events.extend(vm_events), - Err(error) => { - if first_error.is_none() { - first_error = Some(error); - } - } - } - } - - // On client disconnect, give every registered extension a chance to free - // the per-session state it tracks (H4): the host owns the only signal an - // extension gets that a session has gone away. - if matches!(reason, DisposeReason::ConnectionClosed) { - if let Err(error) = self - .dispose_extension_session_state(connection_id, session_id) - .await - { - if first_error.is_none() { - first_error = Some(error); - } - } - } - - self.sessions.remove(session_id); - if let Some(connection) = self.connections.get_mut(connection_id) { - connection.sessions.remove(session_id); - } - // Tell the stdio transport this session is gone so it stops iterating a - // dead entry every event-pump tick and the set stops growing (M5). - self.disposed_sessions - .push((connection_id.to_owned(), session_id.to_owned())); - - if let Some(error) = first_error { - return Err(error); - } - Ok(events) - } - - /// Invoke each registered extension's per-session teardown hook so it can - /// release the state it keyed on this host session. Errors are aggregated so - /// one misbehaving extension cannot prevent the others from cleaning up. - async fn dispose_extension_session_state( - &mut self, - connection_id: &str, - session_id: &str, - ) -> Result<(), SidecarError> { - let ownership = OwnershipScope::session(connection_id, session_id); - let extensions = self - .extensions - .values() - .cloned() - .collect::>>(); - let mut first_error: Option = None; - for extension in extensions { - let snapshot = ExtensionSnapshot::new( - extension.namespace().to_owned(), - ownership.clone(), - self.sidecar_requests.clone(), - self.event_sink.clone(), - ); - if let Err(error) = extension.on_session_disposed(snapshot).await { - if first_error.is_none() { - first_error = Some(error); - } - } - } - match first_error { - Some(error) => Err(error), - None => Ok(()), - } - } - - /// Drain the session scopes disposed since the last call so the stdio - /// transport can untrack them from its active-session set (M5). - pub(crate) fn take_disposed_sessions(&mut self) -> Vec<(String, String)> { - std::mem::take(&mut self.disposed_sessions) - } - - // dispose_vm_internal, terminate_vm_processes, wait_for_vm_processes_to_exit moved to crate::vm - - // kill_process_internal, handle_execution_event, handle_python_vfs_rpc_request, - // resolve_javascript_child_process_execution, spawn_javascript_child_process, - // poll_javascript_child_process, write_javascript_child_process_stdin, - // close_javascript_child_process_stdin, kill_javascript_child_process moved to crate::execution - - /// Whether a `__kernel_stdin_read` / `__kernel_poll` RPC may be serviced - /// via the non-blocking deferral path. Non-TTY JavaScript keeps its - /// in-process local stdin bridge (serviced inline by the fallback arm). - fn kernel_wait_rpc_is_deferrable( - &self, - vm_id: &str, - process_id: &str, - request: &JavascriptSyncRpcRequest, - ) -> bool { - let Some(vm) = self.vms.get(vm_id) else { - return false; - }; - let Some(process) = vm.active_processes.get(process_id) else { - return false; - }; - if request.method == "__kernel_stdin_read" - && matches!( - process.execution, - crate::state::ActiveExecution::Javascript(_) - ) - && process.tty_master_fd.is_none() - { - return false; - } - true - } - - /// Service `__kernel_stdin_read` / `__kernel_poll` without blocking the - /// dispatch loop. Probes readiness with a zero timeout; when not ready and - /// the requested timeout has not expired, parks the RPC on the process - /// (reply-by-token) and spawns a waiter that re-enqueues it as a process - /// event when kernel poll state changes or the deadline passes. The kernel - /// waits stay event-driven (PollNotifier), so a host stdin write wakes the - /// guest immediately instead of after a polling slice. - /// - /// Returns `Ok(Some(response))` to reply now, `Ok(None)` when parked. - fn service_deferrable_kernel_wait_rpc( - &mut self, - vm_id: &str, - process_id: &str, - request: &JavascriptSyncRpcRequest, - ) -> Result, SidecarError> { - let requested_timeout_ms = match request.method.as_str() { - "__kernel_stdin_read" => parse_kernel_stdin_read_args(request)?.1, - _ => u64::try_from(parse_kernel_poll_args(request)?.1).unwrap_or(0), - }; - let now = Instant::now(); - - let Some(vm) = self.vms.get_mut(vm_id) else { - log_stale_process_event(&self.bridge, vm_id, process_id, "deferred kernel wait RPC"); - return Ok(None); - }; - let wait_handle = vm.kernel.poll_wait_handle(); - // Snapshot BEFORE the readiness probe: a write landing between the - // probe and the waiter's wait bumps the generation, so the wait - // returns immediately instead of losing the wakeup. - let generation = wait_handle.snapshot(); - let Some(process) = vm.active_processes.get_mut(process_id) else { - log_stale_process_event(&self.bridge, vm_id, process_id, "deferred kernel wait RPC"); - return Ok(None); - }; - let kernel_pid = process.kernel_pid; - let deadline = match &process.deferred_kernel_wait_rpc { - Some((parked, parked_deadline)) if parked.id == request.id => *parked_deadline, - _ => now + Duration::from_millis(requested_timeout_ms), - }; - let probe = match request.method.as_str() { - "__kernel_stdin_read" => { - let (max_bytes, _) = parse_kernel_stdin_read_args(request)?; - kernel_stdin_read_response(&mut vm.kernel, kernel_pid, max_bytes, Duration::ZERO) - } - _ => { - let (fd_requests, _) = parse_kernel_poll_args(request)?; - kernel_poll_response(&vm.kernel, kernel_pid, &fd_requests, 0) - } - }; - let Some(process) = vm.active_processes.get_mut(process_id) else { - return Ok(None); - }; - let probe = match probe { - Ok(value) => value, - Err(error) => { - process.deferred_kernel_wait_rpc = None; - return Err(error); - } - }; - let ready = match request.method.as_str() { - "__kernel_stdin_read" => !probe.is_null(), - _ => probe.get("readyCount").and_then(Value::as_u64).unwrap_or(0) > 0, - }; - if ready || requested_timeout_ms == 0 || now >= deadline { - process.deferred_kernel_wait_rpc = None; - return Ok(Some(probe.into())); - } - - let connection_id = vm.connection_id.clone(); - let session_id = vm.session_id.clone(); - let remaining = deadline.saturating_duration_since(now); - let sender = self.process_event_sender.clone(); - let waiter_request = request.clone(); - let envelope_vm_id = vm_id.to_owned(); - let envelope_process_id = process_id.to_owned(); - let spawned = std::thread::Builder::new() - .name(String::from("kernel-wait-rpc")) - .spawn(move || { - // Wake on any kernel poll-state change or the deadline; either - // way requeue exactly once — the handler re-probes and either - // replies or re-parks. - let _ = wait_handle.wait_for_change(generation, Some(remaining)); - let _ = sender.blocking_send(ProcessEventEnvelope { - connection_id, - session_id, - vm_id: envelope_vm_id, - process_id: envelope_process_id, - event: ActiveExecutionEvent::JavascriptSyncRpcRequest(waiter_request), - }); - }); - let Some(vm) = self.vms.get_mut(vm_id) else { - return Ok(None); - }; - let Some(process) = vm.active_processes.get_mut(process_id) else { - return Ok(None); - }; - if spawned.is_err() { - // Degrade to pre-deferral behavior: reply not-ready now and let the - // guest re-issue its bounded wait. - process.deferred_kernel_wait_rpc = None; - return Ok(Some(probe.into())); - } - process.deferred_kernel_wait_rpc = Some((request.clone(), deadline)); - Ok(None) - } - - pub(crate) fn handle_javascript_sync_rpc_request( - &mut self, - vm_id: &str, - process_id: &str, - request: JavascriptSyncRpcRequest, - ) -> Result<(), SidecarError> { - record_sync_bridge_request_observed(request.id, &request.method); - let Some(vm) = self.vms.get(vm_id) else { - log_stale_process_event(&self.bridge, vm_id, process_id, "javascript sync RPC"); - return Ok(()); - }; - if !vm.active_processes.contains_key(process_id) { - log_stale_process_event(&self.bridge, vm_id, process_id, "javascript sync RPC"); - return Ok(()); - } - - let response: Result = - match request.method.as_str() { - "child_process.spawn" => { - let Some(vm) = self.vms.get(vm_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC child_process.spawn", - ); - return Ok(()); - }; - let (payload, _) = - parse_javascript_child_process_spawn_request(vm, &request.args)?; - self.spawn_javascript_child_process(vm_id, process_id, payload) - .map(Into::into) - } - "child_process.spawn_sync" => { - let Some(vm) = self.vms.get(vm_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC child_process.spawn_sync", - ); - return Ok(()); - }; - let (payload, max_buffer) = - parse_javascript_child_process_spawn_request(vm, &request.args)?; - self.spawn_javascript_child_process_sync(vm_id, process_id, payload, max_buffer) - .map(Into::into) - } - "child_process.poll" => { - let child_process_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "child_process.poll child id", - )?; - let wait_ms = javascript_sync_rpc_arg_u64_optional( - &request.args, - 1, - "child_process.poll wait ms", - )? - .unwrap_or_default(); - self.poll_javascript_child_process(vm_id, process_id, child_process_id, wait_ms) - .map(Into::into) - } - "child_process.write_stdin" => { - let child_process_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "child_process.write_stdin child id", - )?; - let chunk = javascript_sync_rpc_bytes_arg( - &request.args, - 1, - "child_process.write_stdin chunk", - )?; - self.write_javascript_child_process_stdin( - vm_id, - process_id, - child_process_id, - &chunk, - )?; - Ok(Value::Null.into()) - } - "child_process.close_stdin" => { - let child_process_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "child_process.close_stdin child id", - )?; - self.close_javascript_child_process_stdin(vm_id, process_id, child_process_id)?; - Ok(Value::Null.into()) - } - "child_process.kill" => { - let child_process_id = javascript_sync_rpc_arg_str( - &request.args, - 0, - "child_process.kill child id", - )?; - let signal = - javascript_sync_rpc_arg_str(&request.args, 1, "child_process.kill signal")?; - self.kill_javascript_child_process( - vm_id, - process_id, - child_process_id, - signal, - )?; - Ok(Value::Null.into()) - } - "process.kill" => { - let target_pid = - javascript_sync_rpc_arg_i32(&request.args, 0, "process.kill target pid")?; - let signal = - javascript_sync_rpc_arg_str(&request.args, 1, "process.kill signal")?; - let parsed_signal = parse_signal(signal)?; - if parsed_signal == 0 { - let Some(vm) = self.vms.get(vm_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC process.kill", - ); - return Ok(()); - }; - if !vm.active_processes.contains_key(process_id) { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC process.kill", - ); - return Ok(()); - } - vm.kernel - .signal_process(EXECUTION_DRIVER_NAME, target_pid, parsed_signal) - .map(|()| Value::Null.into()) - .map_err(kernel_error) - } else if target_pid < 0 { - let caller_kernel_pid = { - let Some(vm) = self.vms.get(vm_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC process.kill", - ); - return Ok(()); - }; - let Some(caller) = vm.active_processes.get(process_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC process.kill", - ); - return Ok(()); - }; - caller.kernel_pid - }; - let pgid = target_pid.unsigned_abs(); - match self.signal_vm_process_group(vm_id, caller_kernel_pid, pgid, signal) { - Ok(true) => Ok(self - .apply_self_process_kill(vm_id, process_id, parsed_signal) - .into()), - Ok(false) => Ok(Value::Null.into()), - Err(error) => Err(error), - } - } else { - enum ProcessKillTarget { - SelfProcess, - Child(String), - TopLevel(String), - KernelPid(u32), - } - let target = { - let Some(vm) = self.vms.get(vm_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC process.kill", - ); - return Ok(()); - }; - let Some(caller) = vm.active_processes.get(process_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC process.kill", - ); - return Ok(()); - }; - let caller_pid = i32::try_from(caller.kernel_pid).map_err(|_| { - SidecarError::InvalidState("caller pid exceeds i32".into()) - })?; - if caller_pid == target_pid { - ProcessKillTarget::SelfProcess - } else if let Some((child_process_id, _)) = - caller.child_processes.iter().find(|(_, child)| { - i32::try_from(child.kernel_pid) == Ok(target_pid) - }) - { - ProcessKillTarget::Child(child_process_id.clone()) - } else if let Some((target_process_id, _)) = - vm.active_processes.iter().find(|(_, process)| { - i32::try_from(process.kernel_pid) == Ok(target_pid) - }) - { - ProcessKillTarget::TopLevel(target_process_id.clone()) - } else { - let target_kernel_pid = - u32::try_from(target_pid).map_err(|_| { - SidecarError::InvalidState(format!( - "EINVAL: invalid process pid {target_pid}" - )) - })?; - ProcessKillTarget::KernelPid(target_kernel_pid) - } - }; - match target { - ProcessKillTarget::SelfProcess => Ok(self - .apply_self_process_kill(vm_id, process_id, parsed_signal) - .into()), - ProcessKillTarget::Child(child_process_id) => { - self.kill_javascript_child_process( - vm_id, - process_id, - &child_process_id, - signal, - )?; - Ok(Value::Null.into()) - } - ProcessKillTarget::TopLevel(target_process_id) => { - self.kill_process_internal(vm_id, &target_process_id, signal)?; - Ok(Value::Null.into()) - } - ProcessKillTarget::KernelPid(target_kernel_pid) => { - // Grandchildren and untracked kernel processes are - // resolved VM-wide instead of failing with an - // unknown-pid error. - self.signal_vm_kernel_pid(vm_id, target_kernel_pid, signal) - .map(|()| Value::Null.into()) - } - } - } - } - "process.signal_state" => { - let (signal, registration) = parse_process_signal_state_request(&request.args) - .map_err(|error| SidecarError::InvalidState(error.to_string()))?; - let Some(vm) = self.vms.get_mut(vm_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC process.signal_state", - ); - return Ok(()); - }; - apply_process_signal_state_update( - &mut vm.signal_states, - process_id, - signal, - registration, - ); - Ok(Value::Null.into()) - } - "net.http_request" => { - let payload = request - .args - .first() - .cloned() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "net.http_request requires a request payload", - )) - }) - .and_then(|value| { - serde_json::from_value::(value).map_err( - |error| { - SidecarError::InvalidState(format!( - "invalid net.http_request payload: {error}" - )) - }, - ) - })?; - if !is_javascript_loopback_host(&payload.host) { - return Err(SidecarError::Execution(format!( - "EACCES: HTTP loopback request requires a loopback host, got {}", - payload.host - ))); - } - self.bridge.require_network_access( - vm_id, - NetworkOperation::Http, - format_tcp_resource(&payload.host, payload.port), - )?; - let Some(vm) = self.vms.get_mut(vm_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC net.http_request", - ); - return Ok(()); - }; - let resource_limits = vm.kernel.resource_limits().clone(); - let socket_paths = build_javascript_socket_path_context(vm)?; - let target_is_current = - [JavascriptSocketFamily::Ipv4, JavascriptSocketFamily::Ipv6] - .iter() - .any(|family| { - socket_paths - .http_loopback_target(*family, payload.port) - .is_some_and(|target| { - target.process_id == payload.process_id - && target.server_id == payload.server_id - }) - }); - if !target_is_current { - return Err(SidecarError::InvalidState(format!( - "unknown HTTP loopback target {}:{} for server {} in process {}", - payload.host, payload.port, payload.server_id, payload.process_id - ))); - } - let kernel_readiness = Arc::clone(&vm.kernel_socket_readiness); - let Some(target_process) = vm.active_processes.get_mut(&payload.process_id) - else { - return Err(SidecarError::InvalidState(format!( - "unknown HTTP loopback process {}", - payload.process_id - ))); - }; - dispatch_loopback_http_request(LoopbackHttpDispatchRequest { - bridge: &self.bridge, - vm_id, - dns: &vm.dns, - socket_paths: &socket_paths, - kernel: &mut vm.kernel, - kernel_readiness, - process: target_process, - resource_limits: &resource_limits, - server_id: payload.server_id, - request_json: &payload.request, - }) - .map(Value::String) - .map(Into::into) - } - "__kernel_stdio_write" - if self - .vms - .get(vm_id) - .and_then(|vm| vm.active_processes.get(process_id)) - .is_some_and(|process| process.tty_master_owner.is_some()) => - { - let (writer_kernel_pid, owner) = { - let process = self - .vms - .get(vm_id) - .and_then(|vm| vm.active_processes.get(process_id)) - .expect("guarded by match arm"); - ( - process.kernel_pid, - process.tty_master_owner.expect("guarded by match arm"), - ) - }; - self.service_shared_tty_stdio_write(vm_id, writer_kernel_pid, owner, &request) - .map(Into::into) - } - "__kernel_stdin_read" | "__kernel_poll" - if self.kernel_wait_rpc_is_deferrable(vm_id, process_id, &request) => - { - match self.service_deferrable_kernel_wait_rpc(vm_id, process_id, &request) { - Ok(Some(response)) => Ok(response), - // Parked: an off-loop waiter re-enqueues this request as a - // process event when kernel poll state changes. - Ok(None) => return Ok(()), - Err(error) => Err(error), - } - } - _ => { - let Some(vm) = self.vms.get_mut(vm_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC bridge dispatch", - ); - return Ok(()); - }; - let resource_limits = vm.kernel.resource_limits().clone(); - let network_counts = vm_network_resource_counts(vm); - let socket_paths = build_javascript_socket_path_context(vm)?; - let kernel_readiness = Arc::clone(&vm.kernel_socket_readiness); - let Some(process) = vm.active_processes.get_mut(process_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC bridge dispatch", - ); - return Ok(()); - }; - service_javascript_sync_rpc(JavascriptSyncRpcServiceRequest { - bridge: &self.bridge, - vm_id, - dns: &vm.dns, - socket_paths: &socket_paths, - kernel: &mut vm.kernel, - kernel_readiness, - process, - sync_request: &request, - resource_limits: &resource_limits, - network_counts, - }) - } - }; - - let Some(vm) = self.vms.get_mut(vm_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC response delivery", - ); - return Ok(()); - }; - let shadow_root = vm.cwd.clone(); - let Some(process) = vm.active_processes.get_mut(process_id) else { - log_stale_process_event( - &self.bridge, - vm_id, - process_id, - "javascript sync RPC response delivery", - ); - return Ok(()); - }; - - if response.is_ok() - && matches!( - request.method.as_str(), - "fs.chmodSync" | "fs.promises.chmod" - ) - { - let guest_path = - javascript_sync_rpc_arg_str(&request.args, 0, "filesystem chmod path")?; - let mode = - javascript_sync_rpc_arg_u32(&request.args, 1, "filesystem chmod mode")? & 0o7777; - let host_path = - shadow_host_path_for_process(&shadow_root, &process.guest_cwd, guest_path); - if host_path.exists() { - fs::set_permissions(&host_path, fs::Permissions::from_mode(mode)).map_err( - |error| { - SidecarError::Io(format!( - "failed to mirror chmod to shadow path {}: {error}", - host_path.display() - )) - }, - )?; - } - } - - match response { - Ok(result) => process - .execution - .respond_javascript_sync_rpc_response(request.id, result) - .or_else(ignore_stale_javascript_sync_rpc_response), - Err(error) => process - .execution - .respond_javascript_sync_rpc_error( - request.id, - javascript_sync_rpc_error_code(&error), - error.to_string(), - ) - .or_else(ignore_stale_javascript_sync_rpc_response), - } - } - - /// Applies a `process.kill` aimed at the calling process itself and - /// returns the self-delivery action payload for the bridge. - fn apply_self_process_kill( - &mut self, - vm_id: &str, - process_id: &str, - parsed_signal: i32, - ) -> Value { - let action = self - .vms - .get(vm_id) - .and_then(|vm| vm.signal_states.get(process_id)) - .and_then(|handlers| handlers.get(&(parsed_signal as u32))) - .map(|registration| registration.action.clone()) - .unwrap_or(SignalDispositionAction::Default); - if action == SignalDispositionAction::Default - && parsed_signal != 0 - && !matches!( - canonical_signal_name(parsed_signal), - Some("SIGWINCH" | "SIGCHLD" | "SIGCONT" | "SIGURG") - ) - { - if let Some(vm) = self.vms.get_mut(vm_id) { - if let Some(process) = vm.active_processes.get_mut(process_id) { - process.pending_self_signal_exit = Some(parsed_signal); - } - } - } - json!({ - "self": true, - "action": match action { - SignalDispositionAction::Default => "default", - SignalDispositionAction::Ignore => "ignore", - SignalDispositionAction::User => "user", - }, - }) - } - - pub(crate) fn vm_ids_for_scope( - &self, - ownership: &OwnershipScope, - ) -> Result, SidecarError> { - match ownership { - OwnershipScope::SessionOwnership(inner) => { - self.require_owned_session(&inner.connection_id, &inner.session_id)?; - Ok(self - .sessions - .get(&inner.session_id) - .expect("owned session should exist") - .vm_ids - .iter() - .cloned() - .collect()) - } - OwnershipScope::VmOwnership(inner) => { - self.require_owned_vm(&inner.connection_id, &inner.session_id, &inner.vm_id)?; - Ok(vec![inner.vm_id.clone()]) - } - OwnershipScope::ConnectionOwnership(..) => Err(SidecarError::InvalidState( - String::from("event polling requires session or VM ownership scope"), - )), - } - } - - pub(crate) fn vm_ownership(&self, vm_id: &str) -> Result { - let vm = self - .vms - .get(vm_id) - .ok_or_else(|| SidecarError::InvalidState(format!("unknown sidecar VM {vm_id}")))?; - Ok(OwnershipScope::vm(&vm.connection_id, &vm.session_id, vm_id)) - } - - pub(crate) fn vm_has_active_processes(&self, vm_id: &str) -> bool { - self.vms - .get(vm_id) - .is_some_and(|vm| !vm.active_processes.is_empty()) - } - - fn require_authenticated_connection(&self, connection_id: &str) -> Result<(), SidecarError> { - if self.connections.contains_key(connection_id) { - Ok(()) - } else { - Err(SidecarError::InvalidState(format!( - "connection {connection_id} has not authenticated" - ))) - } - } - - pub(crate) fn require_owned_session( - &self, - connection_id: &str, - session_id: &str, - ) -> Result<(), SidecarError> { - self.require_authenticated_connection(connection_id)?; - let session = self.sessions.get(session_id).ok_or_else(|| { - SidecarError::InvalidState(format!("unknown sidecar session {session_id}")) - })?; - if session.connection_id == connection_id { - Ok(()) - } else { - Err(SidecarError::InvalidState(format!( - "session {session_id} is not owned by connection {connection_id}" - ))) - } - } - - pub(crate) fn require_owned_vm( - &self, - connection_id: &str, - session_id: &str, - vm_id: &str, - ) -> Result<(), SidecarError> { - self.require_owned_session(connection_id, session_id)?; - let vm = self - .vms - .get(vm_id) - .ok_or_else(|| SidecarError::InvalidState(format!("unknown sidecar VM {vm_id}")))?; - if vm.connection_id != connection_id || vm.session_id != session_id { - return Err(SidecarError::InvalidState(format!( - "VM {vm_id} is not owned by {connection_id}/{session_id}" - ))); - } - Ok(()) - } - - fn connection_id_for(&self, ownership: &OwnershipScope) -> Result { - match ownership { - OwnershipScope::ConnectionOwnership(inner) => Ok(inner.connection_id.clone()), - OwnershipScope::SessionOwnership(..) | OwnershipScope::VmOwnership(..) => { - Err(SidecarError::InvalidState(String::from( - "request requires connection ownership scope", - ))) - } - } - } - - fn validate_auth_token(&self, auth_token: &str) -> Result<(), SidecarError> { - let Some(expected_auth_token) = self.config.expected_auth_token.as_deref() else { - return Ok(()); - }; - - if auth_token == expected_auth_token { - Ok(()) - } else { - Err(SidecarError::Unauthorized(String::from( - "authenticate request provided an invalid auth token", - ))) - } - } - - fn allocate_connection_id(&mut self) -> String { - self.next_connection_id += 1; - format!("conn-{}", self.next_connection_id) - } - - fn take_matching_process_event_envelope( - &mut self, - vm_id: &str, - process_id: &str, - ) -> Result, SidecarError> { - if let Some(index) = self - .pending_process_events - .iter() - .position(|event| event.vm_id == vm_id && event.process_id == process_id) - { - return Ok(self.pending_process_events.remove(index)); - } - - let mut matching_envelope = None; - let mut deferred = Vec::new(); - { - let pending_capacity = self.pending_process_event_capacity(); - let receiver = self.process_event_receiver.as_mut().ok_or_else(|| { - SidecarError::InvalidState(String::from("process event receiver unavailable")) - })?; - loop { - if deferred.len() >= pending_capacity { - if receiver.is_empty() { - break; - } - return Err(process_event_queue_overflow_error()); - } - let envelope = match receiver.try_recv() { - Ok(envelope) => envelope, - Err(tokio::sync::mpsc::error::TryRecvError::Empty) => break, - Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => break, - }; - if matching_envelope.is_none() - && envelope.vm_id == vm_id - && envelope.process_id == process_id - { - matching_envelope = Some(envelope); - break; - } - deferred.push(envelope); - } - } - for envelope in deferred { - self.queue_pending_process_event(envelope)?; - } - - Ok(matching_envelope) - } - - fn allocate_sidecar_request_id(&mut self) -> RequestId { - let request_id = self.next_sidecar_request_id; - self.next_sidecar_request_id -= 1; - request_id - } - - pub(crate) fn session_scope_for( - &self, - ownership: &OwnershipScope, - ) -> Result<(String, String), SidecarError> { - match ownership { - OwnershipScope::SessionOwnership(inner) => { - Ok((inner.connection_id.clone(), inner.session_id.clone())) - } - OwnershipScope::ConnectionOwnership(..) | OwnershipScope::VmOwnership(..) => { - Err(SidecarError::InvalidState(String::from( - "request requires session ownership scope", - ))) - } - } - } - - pub(crate) fn vm_scope_for( - &self, - ownership: &OwnershipScope, - ) -> Result<(String, String, String), SidecarError> { - match ownership { - OwnershipScope::VmOwnership(inner) => Ok(( - inner.connection_id.clone(), - inner.session_id.clone(), - inner.vm_id.clone(), - )), - OwnershipScope::ConnectionOwnership(..) | OwnershipScope::SessionOwnership(..) => Err( - SidecarError::InvalidState(String::from("request requires VM ownership scope")), - ), - } - } - - pub(crate) fn respond( - &self, - request: &RequestFrame, - payload: ResponsePayload, - ) -> ResponseFrame { - shared_respond(request, payload) - } - - fn reject(&self, request: &RequestFrame, code: &str, message: &str) -> ResponseFrame { - shared_reject(request, code, message) - } - - pub fn queue_sidecar_request( - &mut self, - ownership: OwnershipScope, - payload: SidecarRequestPayload, - ) -> Result { - if self.outbound_sidecar_requests.len() >= MAX_OUTBOUND_SIDECAR_REQUESTS { - return Err(outbound_sidecar_request_queue_overflow_error()); - } - if self.pending_sidecar_responses.pending_count() >= MAX_PENDING_SIDECAR_RESPONSES { - return Err(sidecar_response_pending_overflow_error()); - } - let request_id = self.allocate_sidecar_request_id(); - let request = SidecarRequestFrame::new(request_id, ownership, payload); - self.pending_sidecar_responses - .register_request(&request) - .map_err(sidecar_response_tracker_error)?; - self.outbound_sidecar_requests.push_back(request); - self.outbound_sidecar_requests_gauge - .observe_depth(self.outbound_sidecar_requests.len()); - self.pending_sidecar_responses_gauge - .observe_depth(self.pending_sidecar_responses.pending_count()); - Ok(request_id) - } - - pub fn queue_wire_sidecar_request( - &mut self, - ownership: crate::wire::OwnershipScope, - payload: crate::wire::SidecarRequestPayload, - ) -> Result { - let ownership = crate::wire::ownership_scope_to_compat(ownership); - let payload = crate::wire::sidecar_request_payload_to_compat(&ownership, payload) - .map_err(wire_protocol_error)?; - self.queue_sidecar_request(ownership, payload) - } - - pub fn pop_sidecar_request(&mut self) -> Option { - let request = self.outbound_sidecar_requests.pop_front(); - self.outbound_sidecar_requests_gauge - .observe_depth(self.outbound_sidecar_requests.len()); - request - } - - pub fn pop_wire_sidecar_request( - &mut self, - ) -> Result, SidecarError> { - self.pop_sidecar_request() - .map(crate::wire::sidecar_request_frame_from_compat) - .transpose() - .map_err(wire_protocol_error) - } - - pub fn accept_sidecar_response( - &mut self, - response: SidecarResponseFrame, - ) -> Result<(), SidecarError> { - match self.pending_sidecar_responses.accept_response(&response) { - Ok(()) => {} - // A response for a request that is no longer pending (its owning VM - // was disposed, abandoning the in-flight callback) or already - // completed is a benign late/stale reply on the shared sidecar — a - // per-VM `sidecar_request` can be answered by the host after that VM - // has been torn down (multiple VMs share one sidecar process). Drop - // it instead of failing the whole sidecar over a harmless straggler. - Err( - error @ (SidecarResponseTrackerError::UnmatchedResponse { .. } - | SidecarResponseTrackerError::DuplicateResponse { .. }), - ) => { - tracing::warn!( - request_id = response.request_id, - "dropping stale sidecar response with no matching pending request: {error}" - ); - return Ok(()); - } - Err(error) => return Err(sidecar_response_tracker_error(error)), - } - self.pending_sidecar_responses_gauge - .observe_depth(self.pending_sidecar_responses.pending_count()); - self.completed_sidecar_response_order - .push_back(response.request_id); - self.completed_sidecar_responses - .insert(response.request_id, response); - self.completed_sidecar_responses_gauge - .observe_depth(self.completed_sidecar_responses.len()); - while self.completed_sidecar_responses.len() > MAX_COMPLETED_SIDECAR_RESPONSES { - match self.completed_sidecar_response_order.pop_front() { - // Only a response that was never retrieved is a real loss; an id - // already taken via take_sidecar_response leaves a stale order - // entry that removes to None and is not a dropped response. - Some(evicted) => { - if self.completed_sidecar_responses.remove(&evicted).is_some() { - tracing::warn!( - queue = "completed_sidecar_responses", - evicted_request_id = evicted, - capacity = MAX_COMPLETED_SIDECAR_RESPONSES, - "dropping an unretrieved completed sidecar response to stay within cap; the host can no longer fetch it (response lost)" - ); - self.completed_sidecar_responses_gauge - .observe_depth(self.completed_sidecar_responses.len()); - } - } - None => break, - } - } - Ok(()) - } - - pub fn accept_wire_sidecar_response( - &mut self, - response: crate::wire::SidecarResponseFrame, - ) -> Result<(), SidecarError> { - let response = - crate::wire::sidecar_response_frame_to_compat(response).map_err(wire_protocol_error)?; - self.accept_sidecar_response(response) - } - - pub fn take_sidecar_response(&mut self, request_id: RequestId) -> Option { - let response = self.completed_sidecar_responses.remove(&request_id); - if response.is_some() { - self.completed_sidecar_response_order - .retain(|completed_id| completed_id != &request_id); - self.completed_sidecar_responses_gauge - .observe_depth(self.completed_sidecar_responses.len()); - } - response - } - - pub fn take_wire_sidecar_response( - &mut self, - request_id: crate::wire::RequestId, - ) -> Result, SidecarError> { - self.take_sidecar_response(request_id) - .map(|response| { - crate::wire::sidecar_response_frame_from_compat(response) - .map_err(wire_protocol_error) - }) - .transpose() - } - - pub(crate) fn vm_lifecycle_event( - &self, - connection_id: &str, - session_id: &str, - vm_id: &str, - state: VmLifecycleState, - ) -> EventFrame { - shared_vm_lifecycle_event(connection_id, session_id, vm_id, state) - } - - fn ensure_request_within_frame_limit( - &self, - request: &RequestFrame, - ) -> Result<(), SidecarError> { - let frame = crate::protocol::to_generated_protocol_frame( - &crate::protocol::ProtocolFrame::Request(request.clone()), - ) - .map_err(|error| { - SidecarError::InvalidState(format!("failed to convert request frame: {error}")) - })?; - let crate::wire::ProtocolFrame::RequestFrame(_) = &frame else { - return Err(SidecarError::InvalidState(String::from( - "request converted to non-request wire frame", - ))); - }; - - crate::wire::WireFrameCodec::new(self.config.max_frame_bytes) - .encode(&frame) - .map(|_| ()) - .map_err(|error| SidecarError::FrameTooLarge(error.to_string())) - } -} - -impl ExtensionHost for NativeSidecar -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - fn spawn_process<'a>( - &'a mut self, - ownership: OwnershipScope, - payload: ExecuteRequest, - ) -> ExtensionFuture<'a, ProcessStartedResponse> { - Box::pin(async move { - let request = RequestFrame::new(0, ownership, RequestPayload::Execute(payload.clone())); - let dispatch = NativeSidecar::execute(self, &request, payload).await?; - match dispatch.response.payload { - ResponsePayload::ProcessStarted(response) => Ok(response), - other => Err(unexpected_extension_host_response("execute", other)), - } - }) - } - - fn write_stdin<'a>( - &'a mut self, - ownership: OwnershipScope, - payload: WriteStdinRequest, - ) -> ExtensionFuture<'a, StdinWrittenResponse> { - Box::pin(async move { - let request = - RequestFrame::new(0, ownership, RequestPayload::WriteStdin(payload.clone())); - let dispatch = NativeSidecar::write_stdin(self, &request, payload).await?; - match dispatch.response.payload { - ResponsePayload::StdinWritten(response) => Ok(response), - other => Err(unexpected_extension_host_response("write_stdin", other)), - } - }) - } - - fn close_stdin<'a>( - &'a mut self, - ownership: OwnershipScope, - payload: CloseStdinRequest, - ) -> ExtensionFuture<'a, StdinClosedResponse> { - Box::pin(async move { - let request = - RequestFrame::new(0, ownership, RequestPayload::CloseStdin(payload.clone())); - let dispatch = NativeSidecar::close_stdin(self, &request, payload).await?; - match dispatch.response.payload { - ResponsePayload::StdinClosed(response) => Ok(response), - other => Err(unexpected_extension_host_response("close_stdin", other)), - } - }) - } - - fn kill_process<'a>( - &'a mut self, - ownership: OwnershipScope, - payload: KillProcessRequest, - ) -> ExtensionFuture<'a, ProcessKilledResponse> { - Box::pin(async move { - let request = - RequestFrame::new(0, ownership, RequestPayload::KillProcess(payload.clone())); - let dispatch = NativeSidecar::kill_process(self, &request, payload).await?; - match dispatch.response.payload { - ResponsePayload::ProcessKilled(response) => Ok(response), - other => Err(unexpected_extension_host_response("kill_process", other)), - } - }) - } - - fn poll_event<'a>( - &'a mut self, - ownership: OwnershipScope, - timeout: Duration, - ) -> ExtensionFuture<'a, Option> { - Box::pin(async move { NativeSidecar::poll_event(self, &ownership, timeout).await }) - } - - fn guest_filesystem_call<'a>( - &'a mut self, - ownership: OwnershipScope, - payload: GuestFilesystemCallRequest, - ) -> ExtensionFuture<'a, GuestFilesystemResultResponse> { - Box::pin(async move { - let request = RequestFrame::new( - 0, - ownership, - RequestPayload::GuestFilesystemCall(payload.clone()), - ); - let dispatch = NativeSidecar::guest_filesystem_call(self, &request, payload).await?; - match dispatch.response.payload { - ResponsePayload::GuestFilesystemResult(response) => Ok(response), - other => Err(unexpected_extension_host_response( - "guest_filesystem_call", - other, - )), - } - }) - } - - fn bind_process_to_session<'a>( - &'a mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - process_id: String, - ) -> ExtensionFuture<'a, ()> { - Box::pin(async move { - self.bind_extension_process_resource(ownership, namespace, ext_session_id, process_id) - }) - } - - fn bind_vm_to_session<'a>( - &'a mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - ) -> ExtensionFuture<'a, ()> { - Box::pin( - async move { self.bind_extension_vm_resource(ownership, namespace, ext_session_id) }, - ) - } - - fn dispose_session_resources<'a>( - &'a mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - ) -> ExtensionFuture<'a, Vec> { - Box::pin(async move { - let key = (namespace, ext_session_id); - let Some(resources) = self.extension_sessions.get(&key) else { - return Ok(Vec::new()); - }; - if resources.ownership != ownership { - return Err(SidecarError::InvalidState(String::from( - "extension session ownership did not match dispose request", - ))); - } - let resources = self - .extension_sessions - .remove(&key) - .expect("extension resources existed before removal"); - let (connection_id, session_id, vm_id) = self.vm_scope_for(&ownership)?; - for process_id in resources.process_ids { - if self - .vms - .get(&vm_id) - .is_some_and(|vm| vm.active_processes.contains_key(&process_id)) - { - self.kill_process_internal(&vm_id, &process_id, "SIGTERM")?; - } - } - let mut events = Vec::new(); - for resource_vm_id in resources.vm_ids { - if self.vms.contains_key(&resource_vm_id) { - events.extend( - self.dispose_vm_internal( - &connection_id, - &session_id, - &resource_vm_id, - DisposeReason::Requested, - ) - .await?, - ); - } - } - Ok(events) - }) - } - - fn start_buffering_process_output<'a>( - &'a mut self, - ownership: OwnershipScope, - process_id: String, - ) -> ExtensionFuture<'a, ()> { - Box::pin(async move { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - let key = (vm_id, process_id); - if self.extension_process_output_buffers.contains_key(&key) { - return Err(SidecarError::Conflict(String::from( - "extension process output buffering already started", - ))); - } - self.extension_process_output_buffers - .insert(key, ExtensionBufferedProcessOutput::default()); - Ok(()) - }) - } - - fn handoff_buffered_process_output<'a>( - &'a mut self, - ownership: OwnershipScope, - namespace: String, - ext_session_id: String, - process_id: String, - timeout: Duration, - ) -> ExtensionFuture<'a, ExtensionBufferedProcessOutput> { - Box::pin(async move { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - let key = (vm_id.clone(), process_id.clone()); - let deadline = Instant::now() + timeout; - loop { - self.pump_process_events(&ownership).await?; - while let Some(envelope) = - self.take_matching_process_event_envelope(&vm_id, &process_id)? - { - if self.capture_extension_process_output_event( - &vm_id, - &process_id, - &envelope.event, - ) { - continue; - } - self.queue_pending_process_event(envelope)?; - break; - } - let buffered = self - .extension_process_output_buffers - .get(&key) - .is_some_and(|buffer| !buffer.stdout.is_empty() || !buffer.stderr.is_empty()); - if buffered || timeout.is_zero() || Instant::now() >= deadline { - break; - } - let remaining = deadline.saturating_duration_since(Instant::now()); - time::sleep(remaining.min(Duration::from_millis(10))).await; - } - self.bind_extension_process_resource( - ownership, - namespace, - ext_session_id, - process_id.clone(), - )?; - self.extension_process_output_buffers - .remove(&key) - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "extension process output buffering was not started", - )) - }) - }) - } -} - -fn unexpected_extension_host_response(operation: &str, payload: ResponsePayload) -> SidecarError { - match payload { - ResponsePayload::Rejected(response) => SidecarError::InvalidState(format!( - "extension {operation} rejected with {}: {}", - response.code, response.message - )), - other => SidecarError::InvalidState(format!( - "extension {operation} returned unexpected response: {other:?}" - )), - } -} - -fn shadow_host_path_for_process( - shadow_root: &Path, - process_guest_cwd: &str, - guest_path: &str, -) -> PathBuf { - let normalized_guest_path = if guest_path.starts_with('/') { - normalize_path(guest_path) - } else { - normalize_path(&format!( - "{}/{}", - process_guest_cwd.trim_end_matches('/'), - guest_path - )) - }; - if normalized_guest_path == "/" { - shadow_root.to_path_buf() - } else { - shadow_root.join(normalized_guest_path.trim_start_matches('/')) - } -} - -fn sidecar_response_tracker_error(error: SidecarResponseTrackerError) -> SidecarError { - SidecarError::InvalidState(format!( - "invalid sidecar response correlation state: {error}" - )) -} - -fn map_bridge_permission(decision: secure_exec_bridge::PermissionDecision) -> PermissionDecision { - match decision.verdict { - secure_exec_bridge::PermissionVerdict::Allow => PermissionDecision::allow(), - secure_exec_bridge::PermissionVerdict::Deny => PermissionDecision::deny( - decision - .reason - .unwrap_or_else(|| String::from("denied by host")), - ), - secure_exec_bridge::PermissionVerdict::Prompt => PermissionDecision::deny( - decision - .reason - .unwrap_or_else(|| String::from("permission prompt required")), - ), - } -} - -fn audit_timestamp() -> String { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_millis() - .to_string() -} - -pub(crate) fn audit_fields(fields: I) -> BTreeMap -where - I: IntoIterator, - K: Into, - V: Into, -{ - let mut mapped = BTreeMap::from([(String::from("timestamp"), audit_timestamp())]); - for (key, value) in fields { - mapped.insert(key.into(), value.into()); - } - mapped -} - -pub(crate) fn emit_structured_event( - bridge: &SharedBridge, - vm_id: &str, - name: &str, - fields: BTreeMap, -) -> Result<(), SidecarError> -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - bridge.with_mut(|bridge| { - bridge.emit_structured_event(StructuredEventRecord { - vm_id: vm_id.to_owned(), - name: name.to_owned(), - fields, - }) - }) -} - -pub(crate) fn emit_security_audit_event( - bridge: &SharedBridge, - vm_id: &str, - name: &str, - fields: BTreeMap, -) where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let _ = emit_structured_event(bridge, vm_id, name, fields); -} - -/// Build a wire `EventFrame` carrying a `StructuredEvent` (name + string-map -/// detail) scoped to a connection. Used to forward limit-registry warnings to the -/// host as `{type:"structured", name:"limit_warning", detail}` events without a -/// protocol schema change. Emitted directly to the host (not via the polled, -/// per-session bridge queue, which is a no-op in the stdio sidecar), so a -/// process-global signal is delivered against the active connection. -pub(crate) fn structured_event_frame( - connection_id: &str, - name: &str, - detail: std::collections::HashMap, -) -> Result { - let event = EventFrame::new( - OwnershipScope::connection(connection_id), - EventPayload::Structured(crate::protocol::StructuredEvent { - name: name.to_owned(), - detail, - }), - ); - crate::wire::event_frame_from_compat(event).map_err(|error| { - SidecarError::InvalidState(format!("invalid structured event frame: {error}")) - }) -} - -pub(crate) fn log_stale_process_event( - bridge: &SharedBridge, - vm_id: &str, - process_id: &str, - context: &str, -) where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let _ = bridge.emit_log( - vm_id, - format!( - "Ignoring stale process event during {context}: VM {vm_id} process {process_id} was already reaped" - ), - ); -} - -// filesystem_operation_label moved to crate::vm - -pub(crate) fn root_filesystem_error(error: impl std::fmt::Display) -> SidecarError { - SidecarError::InvalidState(format!("root filesystem: {error}")) -} - -pub(crate) fn normalize_path(path: &str) -> String { - let mut segments = Vec::new(); - for component in Path::new(path).components() { - match component { - Component::RootDir => segments.clear(), - Component::ParentDir => { - segments.pop(); - } - Component::CurDir => {} - Component::Normal(value) => segments.push(value.to_string_lossy().into_owned()), - Component::Prefix(prefix) => { - segments.push(prefix.as_os_str().to_string_lossy().into_owned()); - } - } - } - - let normalized = format!("/{}", segments.join("/")); - if normalized.is_empty() { - String::from("/") - } else { - normalized - } -} - -pub(crate) fn normalize_host_path(path: &Path) -> PathBuf { - let mut normalized = PathBuf::new(); - - for component in path.components() { - match component { - Component::Prefix(prefix) => normalized.push(prefix.as_os_str()), - Component::RootDir => normalized.push(Path::new("/")), - Component::CurDir => {} - Component::ParentDir => { - if normalized != Path::new("/") { - normalized.pop(); - } - } - Component::Normal(part) => normalized.push(part), - } - } - - if normalized.as_os_str().is_empty() { - if path.is_absolute() { - PathBuf::from("/") - } else { - PathBuf::from(".") - } - } else { - normalized - } -} - -pub(crate) fn path_is_within_root(path: &Path, root: &Path) -> bool { - path == root || path.starts_with(root) -} - -pub(crate) fn dirname(path: &str) -> String { - let normalized = normalize_path(path); - let parent = Path::new(&normalized) - .parent() - .unwrap_or_else(|| Path::new("/")); - let value = parent.to_string_lossy(); - if value.is_empty() { - String::from("/") - } else { - value.into_owned() - } -} - -pub(crate) fn kernel_error(error: KernelError) -> SidecarError { - SidecarError::Kernel(error.to_string()) -} - -pub(crate) fn plugin_error(error: PluginError) -> SidecarError { - SidecarError::Plugin(error.to_string()) -} - -pub(crate) fn javascript_error(error: JavascriptExecutionError) -> SidecarError { - SidecarError::Execution(error.to_string()) -} - -pub(crate) fn wasm_error(error: WasmExecutionError) -> SidecarError { - SidecarError::Execution(error.to_string()) -} - -pub(crate) fn python_error(error: PythonExecutionError) -> SidecarError { - SidecarError::Execution(error.to_string()) -} - -pub(crate) fn vfs_error(error: VfsError) -> SidecarError { - SidecarError::Kernel(error.to_string()) -} - -/// Actionable guidance shown when guest package resolution fails because the packages live in a -/// non-flat `node_modules` whose package store is not visible in the VM. Mounting host `node_modules` -/// is a bind mount, so symlinked/store layouts -/// do not resolve inside the VM: Node canonicalizes a module to its store -/// realpath (e.g. `node_modules/.pnpm/...`, `.bun/...`, `.store/...`) which lives -/// above the mounted directory and the guest `fs` cannot read. Plug'n'Play -/// (yarn-berry default) has no `node_modules` at all. A flat (hoisted) layout is -/// required. The empirically-supported package managers are captured in -/// `crates/sidecar/tests/module_layout_e2e.rs`. -#[allow(dead_code)] -const HOISTED_NODE_MODULES_GUIDANCE: &str = "secure-exec can't load mounted node_modules: the directory uses a non-flat layout (pnpm / bun / yarn workspaces store, or yarn Plug'n'Play) whose package store isn't visible inside the VM. A flat (hoisted) node_modules is required.\n - pnpm -> add `node-linker=hoisted` to .npmrc, then reinstall\n - yarn berry -> set `nodeLinker: node-modules` in .yarnrc.yml (not pnp/pnpm)\n - bun -> install dependencies outside a workspace (workspaces use a .bun store)\n - npm / yarn classic -> already flat, no change needed"; - -/// Detect, from an adapter's captured stderr, a non-flat-`node_modules` failure -/// signature. Returns the actionable guidance to fold into the surfaced error, -/// or `None` when the failure is unrelated. -/// -/// Two signatures, both kept specific so they never fire on unrelated crashes: -/// - a missing-file / cannot-resolve error referencing a package STORE path that -/// lives above the mounted project (`.pnpm`, `.bun`, `.store`, PnP `__virtual__`), -/// - a yarn Plug'n'Play fingerprint (`.pnp.cjs`, the zip cache, or PnP's -/// "isn't declared in your dependencies" resolver error). -#[allow(dead_code)] -fn symlinked_node_modules_hint(stderr: &str) -> Option<&'static str> { - // Package stores that only appear in a path when a non-flat layout is used. - // pnpm (isolated), bun (workspace), yarn-berry (nodeLinker: pnpm), and PnP - // virtual instances all keep real package files under these store dirs, which - // sit above the mounted project node_modules and so are not guest-visible. - const STORE_MARKERS: &[&str] = &[ - "node_modules/.pnpm/", - "node_modules/.bun/", - "node_modules/.store/", - "/__virtual__/", - ]; - // Yarn Plug'n'Play has no node_modules at all; resolution fails against the - // .pnp runtime / zip cache. "isn't declared in your dependencies" is PnP's - // distinctive resolver error and is specific enough to fire on its own. - const PNP_STRICT_MARKERS: &[&str] = &["isn't declared in your dependencies"]; - const PNP_PATH_MARKERS: &[&str] = &[".pnp.cjs", ".pnp.loader.mjs", "/.yarn/cache/"]; - - if PNP_STRICT_MARKERS.iter().any(|m| stderr.contains(m)) { - return Some(HOISTED_NODE_MODULES_GUIDANCE); - } - - let missing = stderr.contains("ENOENT") - || stderr.contains("no such file or directory") - || stderr.contains("Cannot find module") - || stderr.contains("MODULE_NOT_FOUND"); - if !missing { - return None; - } - if STORE_MARKERS.iter().any(|m| stderr.contains(m)) - || PNP_PATH_MARKERS.iter().any(|m| stderr.contains(m)) - { - return Some(HOISTED_NODE_MODULES_GUIDANCE); - } - None -} - -#[cfg(test)] -mod symlinked_node_modules_hint_tests { - use super::symlinked_node_modules_hint; - - // Positive cases: each non-flat package manager's store/PnP signature. - #[test] - fn matches_pnpm_store_enoent() { - // Real pi-coding-agent failure: getPackageDir() falls back to a - // dist/package.json inside the unreachable .pnpm store. - let stderr = "Error: ENOENT: no such file or directory, open '/root/node_modules/.pnpm/@mariozechner+pi-coding-agent@0.60.0_x/node_modules/@mariozechner/pi-coding-agent/dist/package.json'"; - let hint = symlinked_node_modules_hint(stderr).expect("expected hoisted guidance"); - assert!(hint.contains("secure-exec can't load mounted node_modules")); - assert!(!hint.contains("agentos")); - } - - #[test] - fn matches_bun_store_enoent() { - let stderr = "Error: ENOENT: no such file or directory, open '/root/node_modules/.bun/is-odd@3.0.1/node_modules/is-odd/package.json'"; - assert!(symlinked_node_modules_hint(stderr).is_some()); - } - - #[test] - fn matches_yarn_pnpm_store_enoent() { - let stderr = "Error: ENOENT: no such file or directory, open '/root/node_modules/.store/is-odd-npm-3.0.1-93c3c3f41b/package/package.json'"; - assert!(symlinked_node_modules_hint(stderr).is_some()); - } - - #[test] - fn matches_pnp_declared_error() { - // Yarn PnP's distinctive resolver error (no node_modules at all). - let stderr = "Error: Your application tried to access is-number, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound."; - assert!(symlinked_node_modules_hint(stderr).is_some()); - } - - #[test] - fn matches_pnp_cjs_module_not_found() { - let stderr = "Error: Cannot find module 'is-odd'\n at /root/.pnp.cjs:12345:18\n code: 'MODULE_NOT_FOUND'"; - assert!(symlinked_node_modules_hint(stderr).is_some()); - } - - #[test] - fn matches_virtual_instance() { - let stderr = "Error: ENOENT: no such file or directory, open '/root/.yarn/__virtual__/is-odd-abc/1/node_modules/is-odd/package.json'"; - assert!(symlinked_node_modules_hint(stderr).is_some()); - } - - // Negative cases: must not fire. - #[test] - fn ignores_enoent_outside_a_store() { - let stderr = "Error: ENOENT: no such file or directory, open '/tmp/scratch/config.json'"; - assert!(symlinked_node_modules_hint(stderr).is_none()); - } - - #[test] - fn ignores_store_path_without_missing_file() { - let stderr = - "loaded /root/node_modules/.pnpm/some-pkg@1.0.0/node_modules/some-pkg/index.js"; - assert!(symlinked_node_modules_hint(stderr).is_none()); - } - - #[test] - fn ignores_flat_node_modules_enoent() { - // npm / yarn-nm / pnpm-hoisted: flat, no store dir in the path. - let stderr = "Error: ENOENT: no such file or directory, open '/root/node_modules/is-odd/missing-asset.json'"; - assert!(symlinked_node_modules_hint(stderr).is_none()); - } - - #[test] - fn ignores_unrelated_failure() { - let stderr = "Error: connect ECONNREFUSED 127.0.0.1:443"; - assert!(symlinked_node_modules_hint(stderr).is_none()); - } -} - -#[cfg(test)] -mod structured_event_frame_tests { - use super::*; - - #[test] - fn structured_event_frame_round_trips_limit_warning() { - let mut detail = std::collections::HashMap::new(); - // Pin a real emitted limit name rather than a fictional string. - let limit_name = TrackedLimit::JavascriptEventChannel.as_str(); - detail.insert(String::from("limit"), String::from(limit_name)); - detail.insert(String::from("fillPercent"), String::from("82")); - - let wire = structured_event_frame("conn-1", "limit_warning", detail) - .expect("build structured event frame"); - let compat = crate::wire::event_frame_to_compat(wire).expect("convert to compat"); - - match compat.payload { - EventPayload::Structured(event) => { - assert_eq!(event.name, "limit_warning"); - assert_eq!( - event.detail.get("limit").map(String::as_str), - Some(limit_name) - ); - assert_eq!( - event.detail.get("fillPercent").map(String::as_str), - Some("82") - ); - } - other => panic!("expected structured payload, got {other:?}"), - } - match compat.ownership { - OwnershipScope::ConnectionOwnership(inner) => { - assert_eq!(inner.connection_id, "conn-1"); - } - other => panic!("expected connection ownership, got {other:?}"), - } - } -} - -#[cfg(test)] -mod dispose_lifecycle_tests { - use super::*; - use crate::extension::ExtensionResponse; - use crate::stdio::LocalBridge; - use std::sync::atomic::{AtomicUsize, Ordering}; - - fn block_on(future: F) -> F::Output { - tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("dispose lifecycle test runtime") - .block_on(future) - } - - fn test_sidecar() -> NativeSidecar { - NativeSidecar::new(LocalBridge::default()).expect("build test sidecar") - } - - // Register a connection + session directly so the dispose paths can be - // exercised without spinning up a V8-backed VM. - fn insert_session( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - vm_ids: BTreeSet, - ) { - sidecar.connections.insert( - connection_id.to_string(), - ConnectionState { - auth_token: String::new(), - sessions: BTreeSet::from([session_id.to_string()]), - }, - ); - sidecar.sessions.insert( - session_id.to_string(), - SessionState { - connection_id: connection_id.to_string(), - placement: crate::protocol::SidecarPlacement::SidecarPlacementShared( - crate::protocol::SidecarPlacementShared { pool: None }, - ), - metadata: BTreeMap::new(), - vm_ids, - }, - ); - } - - struct RecordingExtension { - namespace: String, - session_disposed: Arc, - } - - impl Extension for RecordingExtension { - fn namespace(&self) -> &str { - &self.namespace - } - - fn handle_request<'a>( - &'a self, - _ctx: ExtensionContext<'a>, - _payload: Vec, - ) -> ExtensionFuture<'a, ExtensionResponse> { - Box::pin(async { Ok(ExtensionResponse::new(Vec::new())) }) - } - - fn on_session_disposed<'a>(&'a self, _ctx: ExtensionSnapshot) -> ExtensionFuture<'a, ()> { - let counter = self.session_disposed.clone(); - Box::pin(async move { - counter.fetch_add(1, Ordering::SeqCst); - Ok(()) - }) - } - } - - fn register_recording_extension(sidecar: &mut NativeSidecar) -> Arc { - let counter = Arc::new(AtomicUsize::new(0)); - sidecar - .register_extension(Box::new(RecordingExtension { - namespace: String::from("dev.test.dispose"), - session_disposed: counter.clone(), - })) - .expect("register recording extension"); - counter - } - - // H4: the extension per-session teardown hook fires on ConnectionClosed so an - // ACP-style extension can release per-session state on client disconnect. - #[test] - fn connection_closed_dispose_invokes_extension_session_teardown() { - let mut sidecar = test_sidecar(); - let counter = register_recording_extension(&mut sidecar); - insert_session(&mut sidecar, "conn-1", "session-1", BTreeSet::new()); - - block_on(sidecar.dispose_session("conn-1", "session-1", DisposeReason::ConnectionClosed)) - .expect("dispose session on connection close"); - - assert_eq!( - counter.load(Ordering::SeqCst), - 1, - "extension session-teardown hook must fire on ConnectionClosed" - ); - assert!( - !sidecar.sessions.contains_key("session-1"), - "the disposed session must be reclaimed" - ); - } - - // H4 (negative): a client-requested dispose is not a disconnect, so the - // teardown hook must not fire. - #[test] - fn requested_dispose_does_not_invoke_extension_session_teardown() { - let mut sidecar = test_sidecar(); - let counter = register_recording_extension(&mut sidecar); - insert_session(&mut sidecar, "conn-1", "session-1", BTreeSet::new()); - - block_on(sidecar.dispose_session("conn-1", "session-1", DisposeReason::Requested)) - .expect("dispose session on request"); - - assert_eq!( - counter.load(Ordering::SeqCst), - 0, - "the teardown hook is reserved for client disconnect" - ); - } - - // M5: disposing a session records its scope for the stdio transport to drain. - #[test] - fn dispose_session_records_disposed_scope() { - let mut sidecar = test_sidecar(); - insert_session(&mut sidecar, "conn-1", "session-1", BTreeSet::new()); - - block_on(sidecar.dispose_session("conn-1", "session-1", DisposeReason::Requested)) - .expect("dispose session"); - - assert_eq!( - sidecar.take_disposed_sessions(), - vec![(String::from("conn-1"), String::from("session-1"))], - "dispose must publish the session scope so stdio can untrack it" - ); - } - - // H1 + M6: every per-VM tracking map is reclaimed for a disposed VM. The - // output-buffer map (M6) was previously only removed on a successful handoff, - // and the engine/extension maps (H1) were only reclaimed after the fallible - // teardown steps' `?`, so any failure stranded them. - #[test] - fn reclaim_vm_tracking_clears_every_per_vm_map() { - let mut sidecar = test_sidecar(); - insert_session( - &mut sidecar, - "conn-1", - "session-1", - BTreeSet::from([String::from("vm-1")]), - ); - sidecar.extension_process_output_buffers.insert( - (String::from("vm-1"), String::from("proc-1")), - ExtensionBufferedProcessOutput::default(), - ); - sidecar.extension_sessions.insert( - (String::from("ns"), String::from("ext-sess-1")), - ExtensionSessionResources { - ownership: OwnershipScope::vm("conn-1", "session-1", "vm-1"), - process_ids: BTreeSet::new(), - vm_ids: BTreeSet::from([String::from("vm-1")]), - }, - ); - - sidecar.reclaim_vm_tracking("session-1", "vm-1"); - - assert!( - sidecar.extension_process_output_buffers.is_empty(), - "M6: the output-buffer map must be reclaimed on VM disposal" - ); - assert!( - sidecar.extension_sessions.is_empty(), - "H1: an extension session bound only to the VM must be reclaimed" - ); - assert!( - !sidecar - .sessions - .get("session-1") - .expect("session present") - .vm_ids - .contains("vm-1"), - "the VM id must be removed from its session" - ); - } - - // H1: a failing VM dispose inside the loop must not abandon the session. With - // unregistered VM ids, `dispose_vm_internal` fails on `require_owned_vm`; - // pre-fix the loop `?`-ed out and left the session in `self.sessions`. - #[test] - fn dispose_session_reclaims_session_even_when_a_vm_dispose_fails() { - let mut sidecar = test_sidecar(); - insert_session( - &mut sidecar, - "conn-1", - "session-1", - BTreeSet::from([String::from("vm-a"), String::from("vm-b")]), - ); - - let result = - block_on(sidecar.dispose_session("conn-1", "session-1", DisposeReason::Requested)); - - assert!( - result.is_err(), - "a failing VM dispose must still surface an error" - ); - assert!( - !sidecar.sessions.contains_key("session-1"), - "the session must be reclaimed even though VM dispose failed" - ); - } -} diff --git a/crates/sidecar/src/state.rs b/crates/sidecar/src/state.rs deleted file mode 100644 index ba4809ebb..000000000 --- a/crates/sidecar/src/state.rs +++ /dev/null @@ -1,1126 +0,0 @@ -//! Shared state types used across sidecar domain modules. -//! -//! Contains VM state, session state, configuration types, active process/socket -//! types, and other shared data structures extracted from service.rs. - -use crate::protocol::{ - GuestRuntimeKind, MountDescriptor, ProjectedModuleDescriptor, RegisterHostCallbacksRequest, - SidecarRequestFrame, SidecarRequestPayload, SidecarResponseFrame, SidecarResponsePayload, - SignalHandlerRegistration, SoftwareDescriptor, WasmPermissionTier, -}; -use crate::wire::DEFAULT_MAX_FRAME_BYTES; -use rusqlite::Connection; -use rustls::{ClientConnection, ServerConnection, StreamOwned}; -use secure_exec_bridge::{BridgeTypes, FilesystemSnapshot}; -use secure_exec_execution::{ - v8_host::V8SessionHandle, JavascriptExecution, JavascriptSyncRpcRequest, PythonExecution, - PythonVfsRpcRequest, WasmExecution, -}; -use secure_exec_kernel::kernel::{KernelProcessHandle, KernelVm}; -use secure_exec_kernel::mount_table::MountTable; -use secure_exec_kernel::root_fs::RootFilesystemMode; -use secure_exec_kernel::socket_table::SocketId; -use secure_exec_sidecar_core::VmLayerStore; -use secure_exec_vm_config as vm_config; -use secure_exec_vm_config::PermissionsPolicy; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::error::Error; -use std::fmt; -use std::fs::File; -use std::net::{IpAddr, SocketAddr, TcpListener, TcpStream, UdpSocket}; -use std::os::unix::net::{UnixListener, UnixStream}; -use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, AtomicI64, Ordering}; -use std::sync::mpsc::{Receiver, Sender}; -use std::sync::{Arc, Condvar, Mutex}; -use std::time::{Duration, Instant}; -use tokio::sync::mpsc::UnboundedSender; - -// --------------------------------------------------------------------------- -// Type aliases -// --------------------------------------------------------------------------- - -pub(crate) type BridgeError = ::Error; -pub(crate) type SidecarKernel = KernelVm; -pub(crate) type KernelSocketReadinessRegistry = - Arc>>; - -// --------------------------------------------------------------------------- -// Constants -// --------------------------------------------------------------------------- - -pub(crate) const EXECUTION_DRIVER_NAME: &str = "secure-exec-sidecar-execution"; -pub(crate) const JAVASCRIPT_COMMAND: &str = "node"; -pub(crate) const PYTHON_COMMAND: &str = "python"; -pub(crate) const WASM_COMMAND: &str = "wasm"; -// The Python runtime addresses the whole guest VFS (the kernel enforces fs -// permissions and mount-confinement on every op, identical to what the JS/WASM -// runtimes and `vm.readFile()` see), so the VFS-RPC root is `/`, not a single -// workspace dir. -pub(crate) const PYTHON_VFS_RPC_GUEST_ROOT: &str = "/"; -pub(crate) const EXECUTION_SANDBOX_ROOT_ENV: &str = "AGENTOS_SANDBOX_ROOT"; -pub(crate) const WASM_STDIO_SYNC_RPC_ENV: &str = "AGENTOS_WASI_STDIO_SYNC_RPC"; -#[cfg(test)] -#[allow(dead_code)] -pub(crate) const HOST_REALPATH_MAX_SYMLINK_DEPTH: usize = 40; -pub(crate) const DISPOSE_VM_SIGTERM_GRACE: std::time::Duration = - std::time::Duration::from_millis(100); -pub(crate) const DISPOSE_VM_SIGKILL_GRACE: std::time::Duration = - std::time::Duration::from_millis(100); -pub(crate) const VM_DNS_SERVERS_METADATA_KEY: &str = "network.dns.servers"; -#[cfg(test)] -#[allow(dead_code)] -pub(crate) const VM_LISTEN_PORT_MIN_METADATA_KEY: &str = "network.listen.port_min"; -#[cfg(test)] -#[allow(dead_code)] -pub(crate) const VM_LISTEN_PORT_MAX_METADATA_KEY: &str = "network.listen.port_max"; -pub(crate) const VM_LISTEN_ALLOW_PRIVILEGED_METADATA_KEY: &str = "network.listen.allow_privileged"; -pub(crate) const DEFAULT_JAVASCRIPT_NET_BACKLOG: u32 = 511; -pub(crate) const LOOPBACK_EXEMPT_PORTS_ENV: &str = "AGENTOS_LOOPBACK_EXEMPT_PORTS"; -pub(crate) const TOOL_DRIVER_NAME: &str = "secure-exec-host-callbacks"; -pub(crate) const MAPPED_HOST_FD_START: u32 = 1_000_000_000; - -// --------------------------------------------------------------------------- -// Public API types -// --------------------------------------------------------------------------- - -#[derive(Debug, Clone)] -pub struct NativeSidecarConfig { - pub sidecar_id: String, - pub max_frame_bytes: usize, - pub compile_cache_root: Option, - pub expected_auth_token: Option, - pub acp_termination_grace: Duration, -} - -impl Default for NativeSidecarConfig { - fn default() -> Self { - Self { - sidecar_id: String::from("secure-exec-sidecar"), - max_frame_bytes: DEFAULT_MAX_FRAME_BYTES, - compile_cache_root: None, - expected_auth_token: None, - acp_termination_grace: Duration::from_secs(3), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum SidecarError { - InvalidState(String), - ProtocolVersionMismatch(String), - BridgeVersionMismatch(String), - Conflict(String), - Unauthorized(String), - Unsupported(String), - FrameTooLarge(String), - Kernel(String), - Plugin(String), - Execution(String), - Bridge(String), - Io(String), -} - -impl fmt::Display for SidecarError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InvalidState(message) - | Self::ProtocolVersionMismatch(message) - | Self::BridgeVersionMismatch(message) - | Self::Conflict(message) - | Self::Unauthorized(message) - | Self::Unsupported(message) - | Self::FrameTooLarge(message) - | Self::Kernel(message) - | Self::Plugin(message) - | Self::Execution(message) - | Self::Bridge(message) - | Self::Io(message) => f.write_str(message), - } - } -} - -impl Error for SidecarError {} - -pub trait SidecarRequestTransport: Send + Sync { - fn send_request( - &self, - request: SidecarRequestFrame, - timeout: Duration, - ) -> Result; -} - -#[derive(Clone)] -pub(crate) struct SharedSidecarRequestClient { - transport: Option>, - next_request_id: Arc, -} - -impl Default for SharedSidecarRequestClient { - fn default() -> Self { - Self { - transport: None, - next_request_id: Arc::new(AtomicI64::new(-1)), - } - } -} - -impl SharedSidecarRequestClient { - pub(crate) fn set_transport(&mut self, transport: Arc) { - self.transport = Some(transport); - } - - pub(crate) fn invoke( - &self, - ownership: crate::protocol::OwnershipScope, - payload: SidecarRequestPayload, - timeout: Duration, - ) -> Result { - let transport = self.transport.as_ref().ok_or_else(|| { - SidecarError::Unsupported(String::from("sidecar request transport is not configured")) - })?; - let request_id = self.next_request_id.fetch_sub(1, Ordering::Relaxed); - let request = SidecarRequestFrame::new(request_id, ownership.clone(), payload); - let response = transport.send_request(request, timeout)?; - if response.request_id != request_id { - return Err(SidecarError::InvalidState(format!( - "sidecar response {} did not match request {request_id}", - response.request_id - ))); - } - if response.ownership != ownership { - return Err(SidecarError::InvalidState(String::from( - "sidecar response ownership did not match request ownership", - ))); - } - Ok(response.payload) - } -} - -/// Fire-and-forget live event sink. Lets an extension emit a `session/update` -/// (or any other) event frame to the host *mid-dispatch*, instead of having to -/// return it from the dispatch and wait for the whole request to resolve before -/// the stdio loop flushes it. Mirrors `SidecarRequestTransport`, but events have -/// no response, no request id, and no timeout — they are written to the same -/// outbound stdout channel the batch path uses. -pub trait EventSinkTransport: Send + Sync { - fn emit_event(&self, event: crate::wire::EventFrame) -> Result<(), SidecarError>; -} - -#[derive(Clone, Default)] -pub(crate) struct SharedEventSink { - transport: Option>, -} - -impl SharedEventSink { - pub(crate) fn set_transport(&mut self, transport: Arc) { - self.transport = Some(transport); - } - - /// Emit `event` live if a transport is configured (the stdio path). Returns - /// `Ok(None)` when the event was handed to the live transport, or - /// `Ok(Some(event))` when no transport is configured (e.g. an in-process - /// `NativeSidecar` with no stdout loop) so the caller can fall back to the - /// batch path and still deliver the event when the dispatch resolves. - pub(crate) fn try_emit( - &self, - event: crate::wire::EventFrame, - ) -> Result, SidecarError> { - match self.transport.as_ref() { - Some(transport) => { - transport.emit_event(event)?; - Ok(None) - } - None => Ok(Some(event)), - } - } -} - -// --------------------------------------------------------------------------- -// Bridge wrapper -// --------------------------------------------------------------------------- - -pub(crate) struct SharedBridge { - pub(crate) inner: Arc>, - pub(crate) permissions: Arc>>, - #[cfg(test)] - pub(crate) set_vm_permissions_outcomes: Arc>>>, -} - -impl Clone for SharedBridge { - fn clone(&self) -> Self { - Self { - inner: Arc::clone(&self.inner), - permissions: Arc::clone(&self.permissions), - #[cfg(test)] - set_vm_permissions_outcomes: Arc::clone(&self.set_vm_permissions_outcomes), - } - } -} - -// --------------------------------------------------------------------------- -// Connection / session / VM state -// --------------------------------------------------------------------------- - -#[allow(dead_code)] -#[derive(Debug)] -pub(crate) struct ConnectionState { - pub(crate) auth_token: String, - pub(crate) sessions: BTreeSet, -} - -#[allow(dead_code)] -#[derive(Debug)] -pub(crate) struct SessionState { - pub(crate) connection_id: String, - pub(crate) placement: crate::protocol::SidecarPlacement, - pub(crate) metadata: BTreeMap, - pub(crate) vm_ids: BTreeSet, -} - -#[allow(dead_code)] -#[derive(Debug, Clone)] -pub(crate) struct VmConfiguration { - pub(crate) mounts: Vec, - pub(crate) software: Vec, - pub(crate) permissions: PermissionsPolicy, - pub(crate) module_access_cwd: Option, - pub(crate) instructions: Vec, - pub(crate) projected_modules: Vec, - pub(crate) command_permissions: BTreeMap, - pub(crate) provided_commands: BTreeMap>, - /// Guest JavaScript host-environment config (platform / module resolution / - /// builtin allow-list). Set at `create_vm` from `CreateVmConfig.jsRuntime` - /// and preserved across `configure_vm`. `None` => full Node.js emulation. - pub(crate) js_runtime: Option, - /// Agent SDK bundle read by the sidecar from the configured package dir and - /// evaluated into the shared V8 startup snapshot. - pub(crate) snapshot_userland_code: Option, - pub(crate) loopback_exempt_ports: Vec, -} - -impl Default for VmConfiguration { - fn default() -> Self { - Self { - mounts: Vec::new(), - software: Vec::new(), - permissions: secure_exec_sidecar_core::permissions::deny_all_policy(), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: BTreeMap::new(), - provided_commands: BTreeMap::new(), - js_runtime: None, - snapshot_userland_code: None, - loopback_exempt_ports: Vec::new(), - } - } -} - -#[allow(dead_code)] -pub(crate) struct VmState { - pub(crate) connection_id: String, - pub(crate) session_id: String, - /// Operator-tunable VM-scoped runtime limits. Immutable for the VM's lifetime; - /// `ConfigureVm` does not mutate limits. - pub(crate) limits: crate::limits::VmLimits, - pub(crate) dns: VmDnsConfig, - pub(crate) listen_policy: VmListenPolicy, - pub(crate) create_loopback_exempt_ports: BTreeSet, - pub(crate) guest_env: BTreeMap, - pub(crate) requested_runtime: GuestRuntimeKind, - pub(crate) root_filesystem_mode: RootFilesystemMode, - pub(crate) guest_cwd: String, - pub(crate) cwd: PathBuf, - pub(crate) host_cwd: PathBuf, - pub(crate) kernel: SidecarKernel, - pub(crate) kernel_socket_readiness: KernelSocketReadinessRegistry, - pub(crate) loaded_snapshot: Option, - pub(crate) configuration: VmConfiguration, - pub(crate) layers: VmLayerStore, - pub(crate) command_guest_paths: BTreeMap, - pub(crate) provided_commands: BTreeMap>, - pub(crate) command_permissions: BTreeMap, - pub(crate) toolkits: BTreeMap, - pub(crate) active_processes: BTreeMap, - pub(crate) exited_process_snapshots: VecDeque, - pub(crate) detached_child_processes: BTreeSet, - pub(crate) signal_states: BTreeMap>, - /// Legacy staging root slot retained for same-version internal state shape. - /// The current `/opt/agentos` projection mounts package tars and synthetic - /// symlink leaves directly, so this remains `None`. - pub(crate) packages_staging_root: Option, -} - -#[derive(Debug, Clone)] -pub(crate) struct ExitedProcessSnapshot { - pub(crate) captured_at: Instant, - pub(crate) process: crate::protocol::ProcessSnapshotEntry, -} - -// --------------------------------------------------------------------------- -// DNS configuration -// --------------------------------------------------------------------------- - -#[derive(Debug, Clone, Default)] -pub(crate) struct VmDnsConfig { - pub(crate) name_servers: Vec, - pub(crate) overrides: BTreeMap>, -} - -#[derive(Debug, Clone)] -pub(crate) struct JavascriptSocketPathContext { - pub(crate) sandbox_root: PathBuf, - pub(crate) mounts: Vec, - pub(crate) listen_policy: VmListenPolicy, - pub(crate) loopback_exempt_ports: BTreeSet, - pub(crate) tcp_loopback_guest_to_host_ports: BTreeMap<(JavascriptSocketFamily, u16), u16>, - pub(crate) http_loopback_targets: - BTreeMap<(JavascriptSocketFamily, u16), JavascriptHttpLoopbackTarget>, - pub(crate) udp_loopback_guest_to_host_ports: BTreeMap<(JavascriptSocketFamily, u16), u16>, - pub(crate) udp_loopback_host_to_guest_ports: BTreeMap<(JavascriptSocketFamily, u16), u16>, - pub(crate) used_tcp_guest_ports: BTreeMap>, - pub(crate) used_udp_guest_ports: BTreeMap>, -} - -#[derive(Debug, Clone)] -pub(crate) struct JavascriptHttpLoopbackTarget { - pub(crate) process_id: String, - pub(crate) server_id: u64, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum JavascriptSocketFamily { - Ipv4, - Ipv6, -} - -impl JavascriptSocketFamily { - pub(crate) fn from_ip(ip: IpAddr) -> Self { - match ip { - IpAddr::V4(_) => Self::Ipv4, - IpAddr::V6(_) => Self::Ipv6, - } - } -} - -impl From for JavascriptSocketFamily { - fn from(value: JavascriptUdpFamily) -> Self { - match value { - JavascriptUdpFamily::Ipv4 => Self::Ipv4, - JavascriptUdpFamily::Ipv6 => Self::Ipv6, - } - } -} - -#[derive(Debug, Clone, Copy)] -pub(crate) struct VmListenPolicy { - pub(crate) port_min: u16, - pub(crate) port_max: u16, - pub(crate) allow_privileged: bool, -} - -impl Default for VmListenPolicy { - fn default() -> Self { - Self { - port_min: 1, - port_max: u16::MAX, - allow_privileged: false, - } - } -} - -// --------------------------------------------------------------------------- -// Active process state -// --------------------------------------------------------------------------- - -#[allow(dead_code)] -pub(crate) struct ActiveProcess { - pub(crate) kernel_pid: u32, - pub(crate) kernel_handle: KernelProcessHandle, - pub(crate) kernel_stdin_writer_fd: Option, - /// For a TTY (PTY-backed) process, the master-end fd whose output buffer - /// carries cooked-mode echo plus ONLCR-processed guest output. When set, - /// this master output is the single ordered output stream surfaced to the - /// host (instead of the raw guest stdout/stderr execution events). - pub(crate) tty_master_fd: Option, - pub(crate) runtime: GuestRuntimeKind, - pub(crate) detached: bool, - pub(crate) execution: ActiveExecution, - pub(crate) guest_cwd: String, - pub(crate) env: BTreeMap, - pub(crate) host_cwd: PathBuf, - pub(crate) host_write_dirty: bool, - pub(crate) mapped_host_fds: BTreeMap, - pub(crate) next_mapped_host_fd: u32, - pub(crate) pending_execution_events: VecDeque, - pub(crate) pending_self_signal_exit: Option, - pub(crate) child_processes: BTreeMap, - pub(crate) next_child_process_id: usize, - pub(crate) http_servers: BTreeMap, - pub(crate) pending_http_requests: BTreeMap<(u64, u64), Option>, - pub(crate) http2: ActiveHttp2State, - pub(crate) tcp_listeners: BTreeMap, - pub(crate) next_tcp_listener_id: usize, - pub(crate) tcp_sockets: BTreeMap, - pub(crate) next_tcp_socket_id: usize, - pub(crate) tcp_port_reservations: BTreeMap, - pub(crate) next_tcp_port_reservation_id: usize, - pub(crate) unix_listeners: BTreeMap, - pub(crate) next_unix_listener_id: usize, - pub(crate) unix_sockets: BTreeMap, - pub(crate) next_unix_socket_id: usize, - pub(crate) udp_sockets: BTreeMap, - pub(crate) next_udp_socket_id: usize, - /// Synchronous host sockets opened by the guest Python `socket` bridge, - /// keyed by the handle returned to the runner. Distinct from the JS - /// runtime's event-driven `tcp_sockets`/`udp_sockets` above. - pub(crate) python_sockets: BTreeMap, - pub(crate) next_python_socket_id: u64, - pub(crate) cipher_sessions: BTreeMap, - pub(crate) next_cipher_session_id: u64, - pub(crate) diffie_hellman_sessions: BTreeMap, - pub(crate) next_diffie_hellman_session_id: u64, - pub(crate) sqlite_databases: BTreeMap, - pub(crate) next_sqlite_database_id: u64, - pub(crate) sqlite_statements: BTreeMap, - pub(crate) next_sqlite_statement_id: u64, - /// For a child process whose stdio is the SHARED terminal (its kernel fd 1 - /// is the same PTY slave as the shell's), the `(kernel pid, master fd)` of - /// the process that owns the host-facing PTY master. Set at spawn. Such a - /// child's stdio writes surface ONLY through master drains attributed to - /// the owner — never as child stdout events — exactly like a native - /// terminal reading the PTY master (a shell never relays its child's tty - /// output). - pub(crate) tty_master_owner: Option<(u32, u32)>, - /// A parked `__kernel_stdin_read` / `__kernel_poll` sync RPC awaiting - /// kernel readiness (reply-by-token deferral so servicing never blocks the - /// dispatch loop). At most one per process: the guest thread is blocked in - /// this RPC, so it cannot issue another. `(request, absolute deadline)`. - pub(crate) deferred_kernel_wait_rpc: Option<(JavascriptSyncRpcRequest, Instant)>, - /// Per-process module resolution cache, persisted across module sync-RPCs - /// (`__resolve_module` / `__load_file` / `__module_format` / - /// `__batch_resolve_modules`) for the lifetime of this process so cold-start - /// resolution does not rebuild it on every dispatch. The resolver reads the - /// kernel VFS; the node_modules tree is mounted read-only, so cached - /// stat/exists/package.json results under it stay valid for the process run. - pub(crate) module_resolution_cache: secure_exec_execution::LocalModuleResolutionCache, -} - -pub(crate) struct ActiveMappedHostFd { - pub(crate) file: File, - pub(crate) path: PathBuf, - pub(crate) guest_path: Option, -} - -pub(crate) struct ActiveCipherSession { - pub(crate) context: crate::crypto_cipher::StreamCipherSession, -} - -pub(crate) struct ActiveSqliteDatabase { - pub(crate) connection: Connection, - pub(crate) host_path: Option, - pub(crate) vm_path: Option, - pub(crate) dirty: bool, - pub(crate) transaction_depth: usize, - pub(crate) read_only: bool, -} - -#[derive(Clone)] -pub(crate) struct ActiveSqliteStatement { - pub(crate) database_id: u64, - pub(crate) sql: String, - pub(crate) return_arrays: bool, - pub(crate) read_bigints: bool, - pub(crate) allow_bare_named_parameters: bool, - pub(crate) allow_unknown_named_parameters: bool, -} - -pub(crate) enum ActiveDiffieHellmanSession { - Dh(ActiveDhSession), - Ecdh(ActiveEcdhSession), -} - -pub(crate) struct ActiveDhSession { - pub(crate) params: openssl::dh::Dh, - pub(crate) key_pair: Option>, -} - -pub(crate) struct ActiveEcdhSession { - pub(crate) curve: String, - pub(crate) key_pair: Option>, -} - -#[derive(Debug, Clone, Copy, Default)] -pub(crate) struct NetworkResourceCounts { - pub(crate) sockets: usize, - pub(crate) connections: usize, -} - -#[derive(Debug)] -pub(crate) struct ActiveHttpServer { - pub(crate) listener: TcpListener, - pub(crate) guest_local_addr: SocketAddr, - pub(crate) next_request_id: u64, -} - -#[derive(Clone, Default)] -pub(crate) struct ActiveHttp2State { - pub(crate) shared: Arc>, -} - -#[derive(Default)] -pub(crate) struct Http2SharedState { - pub(crate) next_session_id: u64, - pub(crate) next_stream_id: u64, - pub(crate) ready: Arc, - pub(crate) event_session: Option, - pub(crate) servers: BTreeMap, - pub(crate) sessions: BTreeMap, - pub(crate) streams: BTreeMap, - pub(crate) server_events: BTreeMap>, - pub(crate) session_events: BTreeMap>, -} - -#[derive(Debug)] -pub(crate) struct ActiveHttp2Server { - pub(crate) actual_local_addr: SocketAddr, - pub(crate) guest_local_addr: SocketAddr, - pub(crate) secure: bool, - pub(crate) tls: Option, - pub(crate) closed: Arc, -} - -#[derive(Debug, Clone)] -pub(crate) struct ActiveHttp2Session { - pub(crate) command_tx: UnboundedSender, -} - -#[derive(Debug, Clone)] -pub(crate) struct ActiveHttp2Stream { - pub(crate) session_id: u64, - pub(crate) paused: Arc, - pub(crate) resume_notify: Arc, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(default, rename_all = "camelCase")] -pub(crate) struct Http2SocketSnapshot { - pub(crate) encrypted: bool, - pub(crate) allow_half_open: bool, - pub(crate) local_address: Option, - pub(crate) local_port: Option, - pub(crate) local_family: Option, - pub(crate) remote_address: Option, - pub(crate) remote_port: Option, - pub(crate) remote_family: Option, - pub(crate) servername: Option, - pub(crate) alpn_protocol: Option, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(default, rename_all = "camelCase")] -pub(crate) struct Http2RuntimeSnapshot { - pub(crate) effective_local_window_size: u32, - pub(crate) local_window_size: u32, - pub(crate) remote_window_size: u32, - pub(crate) next_stream_id: u32, - pub(crate) outbound_queue_size: u32, - pub(crate) deflate_dynamic_table_size: u32, - pub(crate) inflate_dynamic_table_size: u32, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(default, rename_all = "camelCase")] -pub(crate) struct Http2SessionSnapshot { - pub(crate) encrypted: bool, - pub(crate) alpn_protocol: Option, - pub(crate) origin_set: Vec, - pub(crate) local_settings: BTreeMap, - pub(crate) remote_settings: BTreeMap, - pub(crate) state: Http2RuntimeSnapshot, - pub(crate) socket: Http2SocketSnapshot, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(default, rename_all = "camelCase")] -pub(crate) struct Http2BridgeEvent { - pub(crate) kind: String, - pub(crate) id: u64, - #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) data: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) extra: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) extra_number: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) extra_headers: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) flags: Option, -} - -pub(crate) enum Http2SessionCommand { - Request { - headers_json: String, - options_json: String, - respond_to: Sender>, - }, - Settings { - settings_json: String, - respond_to: Sender>, - }, - SetLocalWindowSize { - size: u32, - respond_to: Sender>, - }, - Goaway { - error_code: u32, - last_stream_id: u32, - opaque_data: Option>, - respond_to: Sender>, - }, - Close { - abrupt: bool, - respond_to: Sender>, - }, - StreamRespond { - stream_id: u64, - headers_json: String, - respond_to: Sender>, - }, - StreamPush { - stream_id: u64, - headers_json: String, - respond_to: Sender>, - }, - StreamWrite { - stream_id: u64, - chunk: Vec, - end_stream: bool, - respond_to: Sender>, - }, - StreamClose { - stream_id: u64, - error_code: Option, - respond_to: Sender>, - }, - StreamRespondWithFile { - stream_id: u64, - body: Vec, - headers_json: String, - options_json: String, - respond_to: Sender>, - }, -} - -// --------------------------------------------------------------------------- -// TCP types -// --------------------------------------------------------------------------- - -#[derive(Debug)] -pub(crate) enum JavascriptTcpListenerEvent { - Connection(PendingTcpSocket), - Error { - code: Option, - message: String, - }, -} - -#[derive(Debug)] -pub(crate) struct PendingTcpSocket { - pub(crate) stream: Option, - pub(crate) kernel_socket_id: Option, - pub(crate) preallocated: bool, - pub(crate) guest_local_addr: SocketAddr, - pub(crate) guest_remote_addr: SocketAddr, -} - -#[derive(Debug)] -pub(crate) enum JavascriptTcpSocketEvent { - Data(Vec), - End, - Close { - had_error: bool, - }, - Error { - code: Option, - message: String, - }, -} - -#[derive(Clone, Debug)] -pub(crate) struct JavascriptSocketEventPusher { - pub(crate) session: V8SessionHandle, - pub(crate) socket_id: String, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum KernelSocketReadinessEvent { - Data, - Datagram, - Accept, -} - -#[derive(Clone, Debug)] -pub(crate) struct KernelSocketReadinessTarget { - pub(crate) session: V8SessionHandle, - pub(crate) target_id: String, - pub(crate) event: KernelSocketReadinessEvent, -} - -#[derive(Debug)] -pub(crate) struct ActiveTcpSocket { - pub(crate) stream: Option>>, - pub(crate) pending_read_stream: Option>>>, - pub(crate) events: Option>, - pub(crate) event_sender: Option>, - pub(crate) event_pusher: Arc>>, - pub(crate) kernel_socket_id: Option, - pub(crate) no_delay: bool, - pub(crate) keep_alive: bool, - pub(crate) keep_alive_initial_delay_secs: Option, - pub(crate) guest_local_addr: SocketAddr, - pub(crate) guest_remote_addr: SocketAddr, - pub(crate) listener_id: Option, - pub(crate) tls_mode: Arc, - pub(crate) tls_stream: Arc>>, - pub(crate) tls_state: Arc>>, - pub(crate) loopback_tls_pending_write: Arc>>, - pub(crate) saw_local_shutdown: Arc, - pub(crate) saw_remote_end: Arc, - pub(crate) close_notified: Arc, -} - -#[derive(Debug)] -pub(crate) struct LoopbackTlsTransportPair { - pub(crate) state: Mutex, - pub(crate) ready: Condvar, -} - -#[derive(Debug, Default)] -pub(crate) struct LoopbackTlsTransportPairState { - pub(crate) lower_to_higher: VecDeque, - pub(crate) higher_to_lower: VecDeque, - pub(crate) lower_write_closed: bool, - pub(crate) higher_write_closed: bool, - pub(crate) lower_closed: bool, - pub(crate) higher_closed: bool, - pub(crate) lower_read_interrupt: bool, - pub(crate) higher_read_interrupt: bool, -} - -pub(crate) struct LoopbackTlsEndpoint { - pub(crate) pair: Arc, - pub(crate) is_lower_socket: bool, - pub(crate) poll_timeout: Duration, - /// Registry key (`vm_id:lower:higher`) under which this endpoint's transport - /// pair is registered in the loopback-TLS transport registry. Stored so the - /// endpoint's `Drop` can eagerly prune its own registry entry once it is the - /// last owner of the pair, instead of leaking a dead `Weak` entry until the - /// next lazy `retain()` in `loopback_tls_endpoint()`. `None` means the - /// endpoint was not registered (e.g. test-constructed) and Drop skips pruning. - pub(crate) registry_key: Option, -} - -#[derive(Debug)] -pub(crate) struct LoopbackTlsPendingWriteState { - pub(crate) buffer: Vec, - pub(crate) warned_near_cap: bool, - pub(crate) flushing: bool, - pub(crate) defer_shutdown_write: bool, - pub(crate) failure_message: Option, -} - -#[derive(Debug, Clone)] -pub(crate) struct LoopbackTlsPendingWriteHandle { - pub(crate) state: Arc>, - pub(crate) tls_handshake_complete: Arc, - pub(crate) failed: Arc, - pub(crate) pair: Arc, - pub(crate) is_lower_socket: bool, - pub(crate) handshake_started_at: Instant, -} - -impl fmt::Debug for LoopbackTlsEndpoint { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("LoopbackTlsEndpoint") - .field("is_lower_socket", &self.is_lower_socket) - .finish() - } -} - -#[derive(Debug)] -pub(crate) enum ActiveTlsStream { - Client(StreamOwned), - Server(StreamOwned), - LoopbackClient(StreamOwned), - LoopbackServer(StreamOwned), -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(default, rename_all = "camelCase")] -pub(crate) struct JavascriptTlsClientHello { - #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) servername: Option, - #[serde( - rename = "ALPNProtocols", - alias = "ALPNProtocols", - skip_serializing_if = "Option::is_none" - )] - pub(crate) alpn_protocols: Option>, -} - -#[derive(Debug, Clone, Default, Deserialize)] -#[serde(default, rename_all = "camelCase")] -pub(crate) struct JavascriptTlsBridgeOptions { - pub(crate) is_server: bool, - pub(crate) servername: Option, - pub(crate) reject_unauthorized: Option, - pub(crate) request_cert: Option, - pub(crate) session: Option, - pub(crate) key: Option, - pub(crate) cert: Option, - pub(crate) ca: Option, - pub(crate) passphrase: Option, - pub(crate) ciphers: Option, - #[serde(alias = "ALPNProtocols")] - pub(crate) alpn_protocols: Option>, - pub(crate) min_version: Option, - pub(crate) max_version: Option, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(untagged)] -pub(crate) enum JavascriptTlsMaterial { - Single(JavascriptTlsDataValue), - Many(Vec), -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(tag = "kind", rename_all = "camelCase")] -pub(crate) enum JavascriptTlsDataValue { - Buffer { data: String }, - String { data: String }, -} - -#[derive(Debug, Clone, Default)] -pub(crate) struct ActiveTlsState { - pub(crate) client_hello: Option, - pub(crate) local_certificates: Vec>, - pub(crate) session_reused: bool, -} - -#[derive(Debug, Clone, Copy)] -pub(crate) struct ResolvedTcpConnectAddr { - pub(crate) actual_addr: SocketAddr, - pub(crate) guest_remote_addr: SocketAddr, - pub(crate) use_kernel_loopback: bool, -} - -#[derive(Debug)] -pub(crate) struct ActiveTcpListener { - pub(crate) listener: Option, - pub(crate) kernel_socket_id: Option, - pub(crate) local_addr: Option, - pub(crate) guest_local_addr: SocketAddr, - pub(crate) backlog: usize, - pub(crate) active_connection_ids: BTreeSet, -} - -// --------------------------------------------------------------------------- -// Unix socket types -// --------------------------------------------------------------------------- - -#[derive(Debug)] -pub(crate) enum JavascriptUnixListenerEvent { - Connection(PendingUnixSocket), - Error { - code: Option, - message: String, - }, -} - -#[derive(Debug)] -pub(crate) struct PendingUnixSocket { - pub(crate) stream: UnixStream, - pub(crate) local_path: Option, - pub(crate) remote_path: Option, -} - -#[derive(Debug)] -pub(crate) struct ActiveUnixSocket { - pub(crate) stream: Arc>, - pub(crate) events: Receiver, - pub(crate) event_sender: Sender, - pub(crate) event_pusher: Arc>>, - pub(crate) listener_id: Option, - pub(crate) local_path: Option, - pub(crate) remote_path: Option, - pub(crate) saw_local_shutdown: Arc, - pub(crate) saw_remote_end: Arc, - pub(crate) close_notified: Arc, -} - -#[derive(Debug)] -pub(crate) struct ActiveUnixListener { - pub(crate) listener: UnixListener, - pub(crate) path: String, - pub(crate) backlog: usize, - pub(crate) active_connection_ids: BTreeSet, -} - -// --------------------------------------------------------------------------- -// UDP types -// --------------------------------------------------------------------------- - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum JavascriptUdpFamily { - Ipv4, - Ipv6, -} - -impl JavascriptUdpFamily { - pub(crate) fn from_socket_type(value: &str) -> Result { - match value { - "udp4" => Ok(Self::Ipv4), - "udp6" => Ok(Self::Ipv6), - other => Err(SidecarError::InvalidState(format!( - "unsupported dgram socket type {other}" - ))), - } - } - - pub(crate) fn socket_type(self) -> &'static str { - match self { - Self::Ipv4 => "udp4", - Self::Ipv6 => "udp6", - } - } - - pub(crate) fn matches_addr(self, addr: &SocketAddr) -> bool { - matches!( - (self, addr), - (Self::Ipv4, SocketAddr::V4(_)) | (Self::Ipv6, SocketAddr::V6(_)) - ) - } -} - -#[derive(Debug)] -pub(crate) enum JavascriptUdpSocketEvent { - Message { - data: Vec, - remote_addr: SocketAddr, - }, - Error { - code: Option, - message: String, - }, -} - -/// A blocking host socket backing one guest Python socket. Reads use a short -/// timeout (set on the socket) so a `recv`/`recvfrom` RPC never stalls the -/// shared sidecar event loop; the Python shim re-polls to emulate blocking. -#[derive(Debug)] -pub(crate) enum PythonHostSocket { - Tcp(TcpStream), - Udp(UdpSocket), -} - -#[derive(Debug)] -pub(crate) struct ActiveUdpSocket { - pub(crate) family: JavascriptUdpFamily, - pub(crate) socket: Option, - pub(crate) kernel_socket_id: Option, - pub(crate) guest_local_addr: Option, - pub(crate) recv_buffer_size: usize, - pub(crate) send_buffer_size: usize, -} - -// --------------------------------------------------------------------------- -// Execution types -// --------------------------------------------------------------------------- - -#[derive(Debug)] -pub(crate) enum ActiveExecution { - Javascript(JavascriptExecution), - Python(PythonExecution), - Wasm(Box), - Tool(ToolExecution), -} - -#[derive(Debug, Clone)] -pub(crate) struct ToolExecution { - pub(crate) cancelled: Arc, - pub(crate) pending_events: Arc>>, - pub(crate) events_overflowed: Arc, -} - -impl Default for ToolExecution { - fn default() -> Self { - Self { - cancelled: Arc::new(AtomicBool::new(false)), - pending_events: Arc::new(Mutex::new(VecDeque::new())), - events_overflowed: Arc::new(AtomicBool::new(false)), - } - } -} - -#[derive(Debug)] -pub(crate) enum ActiveExecutionEvent { - Stdout(Vec), - Stderr(Vec), - JavascriptSyncRpcRequest(JavascriptSyncRpcRequest), - PythonVfsRpcRequest(Box), - SignalState { - signal: u32, - registration: SignalHandlerRegistration, - }, - Exited(i32), -} - -#[derive(Debug)] -pub(crate) struct ProcessEventEnvelope { - pub(crate) connection_id: String, - pub(crate) session_id: String, - pub(crate) vm_id: String, - pub(crate) process_id: String, - pub(crate) event: ActiveExecutionEvent, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum SocketQueryKind { - TcpListener, - UdpBound, -} - -// --------------------------------------------------------------------------- -// Command resolution -// --------------------------------------------------------------------------- - -#[derive(Debug)] -pub(crate) struct ResolvedChildProcessExecution { - pub(crate) command: String, - pub(crate) process_args: Vec, - pub(crate) runtime: GuestRuntimeKind, - pub(crate) entrypoint: String, - pub(crate) execution_args: Vec, - pub(crate) env: BTreeMap, - pub(crate) guest_cwd: String, - pub(crate) host_cwd: PathBuf, - pub(crate) wasm_permission_tier: Option, - pub(crate) tool_command: bool, -} - -// --------------------------------------------------------------------------- -// Utility types -// --------------------------------------------------------------------------- - -#[derive(Debug)] -pub(crate) struct ProcNetEntry { - pub(crate) local_host: String, - pub(crate) local_port: u16, - pub(crate) state: String, - pub(crate) inode: u64, -} diff --git a/crates/sidecar/src/stdio.rs b/crates/sidecar/src/stdio.rs deleted file mode 100644 index 33627fde3..000000000 --- a/crates/sidecar/src/stdio.rs +++ /dev/null @@ -1,1523 +0,0 @@ -use crate::wire::{ - self, AuthenticatedResponse, ExtEnvelope, OwnershipScope, ProtocolCodecError, ProtocolFrame, - RequestFrame, RequestId, RequestPayload, ResponseFrame, ResponsePayload, SessionOpenedResponse, - SidecarResponseFrame, WireDispatchResult, WireFrameCodec, -}; -use crate::{ - EventSinkTransport, Extension, ExtensionInterruptRequest, NativeSidecar, NativeSidecarConfig, - SidecarError, SidecarRequestTransport, -}; -use secure_exec_bridge::queue_tracker::{tracked_sync_channel, TrackedLimit, TrackedSyncSender}; -use secure_exec_bridge::{ - BridgeTypes, ChmodRequest, ClockBridge, ClockRequest, CommandPermissionRequest, - CreateDirRequest, CreateJavascriptContextRequest, CreateWasmContextRequest, DiagnosticRecord, - DirectoryEntry, EnvironmentPermissionRequest, EventBridge, ExecutionBridge, ExecutionEvent, - ExecutionHandleRequest, FileMetadata, FilesystemBridge, FilesystemPermissionRequest, - FilesystemSnapshot, FlushFilesystemStateRequest, GuestContextHandle, KillExecutionRequest, - LifecycleEventRecord, LoadFilesystemStateRequest, LogRecord, NetworkPermissionRequest, - PathRequest, PermissionBridge, PermissionDecision, PersistenceBridge, - PollExecutionEventRequest, RandomBridge, RandomBytesRequest, ReadDirRequest, ReadFileRequest, - RenameRequest, ScheduleTimerRequest, ScheduledTimer, StartExecutionRequest, StartedExecution, - StructuredEventRecord, SymlinkRequest, TruncateRequest, WriteExecutionStdinRequest, - WriteFileRequest, -}; -use secure_exec_sidecar_core::{ - generated_wire_blocking_extension_interrupt, BlockingExtensionInterrupt, -}; -use std::collections::{BTreeMap, BTreeSet}; -use std::error::Error; -use std::fmt; -use std::fs::{self, OpenOptions}; -use std::io::{self, Read, Write}; -use std::os::unix::fs::{symlink as create_symlink, MetadataExt, PermissionsExt}; -use std::path::{Path, PathBuf}; -use std::sync::{mpsc, Arc, Mutex}; -use std::thread; -use std::time::{Duration, Instant, SystemTime}; -use tokio::sync::{ - mpsc::{channel, unbounded_channel, Receiver}, - Notify, -}; -use tokio::time; - -// Guest sync fs/module RPCs are serviced by `pump_process_events` on this timer, -// so a blocked guest call waits up to one interval before the host even sees it. -// At 5ms this dominated per-call latency (~5ms/stat); 250us cuts it ~11x (stat -// 7.5s -> ~0.65s over 1500 ops) and the sub-ms tokio timer is honored. Idle -// pumps are cheap no-ops (try_recv + zero-timeout poll), so the higher cadence -// costs negligible CPU when no guest is issuing RPCs. -const EVENT_PUMP_INTERVAL: Duration = Duration::from_micros(250); -const MAX_STDIN_FRAME_QUEUE: usize = 128; -const MAX_EVENT_READY_QUEUE: usize = 1; -// Defense-in-depth headroom for the host-bound frame queue: a burst of output -// frames from a busy turn should be buffered, so the writer only backpressures -// when the host genuinely stops reading stdout rather than on every spike. -const MAX_STDOUT_FRAME_QUEUE: usize = 4096; - -#[cfg(test)] -fn request_frame( - request_id: RequestId, - ownership: OwnershipScope, - payload: RequestPayload, -) -> RequestFrame { - RequestFrame { - schema: wire::protocol_schema(), - request_id, - ownership, - payload, - } -} - -fn response_frame( - request_id: RequestId, - ownership: OwnershipScope, - payload: ResponsePayload, -) -> ResponseFrame { - ResponseFrame { - schema: wire::protocol_schema(), - request_id, - ownership, - payload, - } -} - -#[cfg(test)] -fn connection_ownership(connection_id: &str) -> OwnershipScope { - OwnershipScope::ConnectionOwnership(wire::ConnectionOwnership { - connection_id: connection_id.to_owned(), - }) -} - -fn session_ownership(connection_id: &str, session_id: &str) -> OwnershipScope { - OwnershipScope::SessionOwnership(wire::SessionOwnership { - connection_id: connection_id.to_owned(), - session_id: session_id.to_owned(), - }) -} - -#[cfg(test)] -fn vm_ownership(connection_id: &str, session_id: &str, vm_id: &str) -> OwnershipScope { - OwnershipScope::VmOwnership(wire::VmOwnership { - connection_id: connection_id.to_owned(), - session_id: session_id.to_owned(), - vm_id: vm_id.to_owned(), - }) -} - -fn wire_protocol_error(error: ProtocolCodecError) -> SidecarError { - SidecarError::InvalidState(format!("invalid generated wire protocol frame: {error}")) -} - -pub fn run() -> Result<(), Box> { - run_with_extensions(Vec::new()) -} - -pub fn run_with_extensions(extensions: Vec>) -> Result<(), Box> { - // Initialize the embedded V8 runtime + platform now, on the long-lived main - // thread, so it is never first-initialized on a transient worker thread (e.g. a - // VM-create snapshot pre-warm thread that then exits — which corrupts V8's - // platform and wedges later isolate creation). Best-effort. - if let Err(error) = secure_exec_execution::v8_host::ensure_runtime_initialized() { - eprintln!("embedded V8 runtime init failed at startup: {error}"); - } - tokio::runtime::Builder::new_current_thread() - .enable_all() - .build()? - .block_on(run_async(extensions)) -} - -async fn run_async(extensions: Vec>) -> Result<(), Box> { - let config = NativeSidecarConfig { - compile_cache_root: Some(default_compile_cache_root()), - ..NativeSidecarConfig::default() - }; - let codec = WireFrameCodec::new(config.max_frame_bytes); - let mut sidecar = - NativeSidecar::with_config_and_extensions(LocalBridge::default(), config, extensions)?; - let mut active_sessions = BTreeSet::::new(); - let mut active_connections = BTreeSet::::new(); - let (stdin_tx, mut stdin_rx) = - channel::, String>>(MAX_STDIN_FRAME_QUEUE); - let stdin_gauge = secure_exec_bridge::queue_tracker::register_queue( - TrackedLimit::SidecarStdinFrames, - MAX_STDIN_FRAME_QUEUE, - ); - let (event_ready_tx, mut event_ready_rx) = channel::<()>(MAX_EVENT_READY_QUEUE); - let (write_tx, write_rx) = tracked_sync_channel::( - TrackedLimit::SidecarStdoutFrames, - MAX_STDOUT_FRAME_QUEUE, - ); - let (write_error_tx, mut write_error_rx) = unbounded_channel::(); - - // Forward limit-registry near-capacity warnings to the host: the global sink - // fires (edge-triggered, from arbitrary threads) into this channel, and the - // event loop below drains it and emits a `StructuredEvent` (name - // "limit_warning"). The unbounded sender is Send+Sync and lives for the whole - // process inside the global handler, so the receiver never sees a hangup. - let (limit_warning_tx, mut limit_warning_rx) = - unbounded_channel::(); - secure_exec_bridge::queue_tracker::set_limit_warning_handler(Box::new(move |warning| { - let _ = limit_warning_tx.send(warning.clone()); - })); - let callback_transport = Arc::new(FrameSidecarRequestTransport::new(write_tx.clone())); - sidecar.set_sidecar_request_transport(callback_transport.clone()); - // Live event sink: lets an extension stream `session/update` (and other) - // events to stdout mid-dispatch instead of batching them until the request - // resolves. Shares the same outbound `write_tx` channel as the batch path, so - // ordering and backpressure are identical. - let event_transport = Arc::new(FrameEventTransport::new(write_tx.clone())); - sidecar.set_event_transport(event_transport); - let mut event_pump = time::interval(EVENT_PUMP_INTERVAL); - let process_event_notify = Arc::new(Notify::new()); - sidecar - .javascript_engine - .set_event_notify(Some(process_event_notify.clone())); - let writer_codec = codec.clone(); - let reader_codec = codec.clone(); - let writer_error_tx = write_error_tx.clone(); - thread::spawn(move || { - let mut writer = io::BufWriter::new(io::stdout()); - while let Ok(frame) = write_rx.recv() { - if let Err(error) = write_frame(&writer_codec, &mut writer, &frame) { - let _ = writer_error_tx.send(error.to_string()); - break; - } - } - }); - - thread::spawn({ - let callback_transport = callback_transport.clone(); - let read_error_tx = write_error_tx.clone(); - move || { - let mut stdin = io::stdin(); - loop { - let frame = match read_frame(&reader_codec, &mut stdin) { - Ok(Some(ProtocolFrame::SidecarResponseFrame(response))) => { - if callback_transport.accept_response(response.clone()) { - continue; - } - Ok(Some(ProtocolFrame::SidecarResponseFrame(response))) - } - Ok(Some(frame)) => Ok(Some(frame)), - other => other, - } - .map_err(|error: Box| error.to_string()); - let should_stop = matches!(frame, Ok(None) | Err(_)); - match enqueue_stdin_frame(&stdin_tx, frame) { - Ok(()) => { - // Sample inbound queue depth so the centralized tracker - // can warn before host requests back up on the sidecar. - stdin_gauge.observe_depth( - stdin_tx.max_capacity().saturating_sub(stdin_tx.capacity()), - ); - } - Err(StdinFrameQueueError::Full(message)) => { - let _ = read_error_tx.send(message); - break; - } - Err(StdinFrameQueueError::Closed) => break, - } - if should_stop { - break; - } - } - } - }); - - flush_sidecar_requests(&mut sidecar, &write_tx)?; - let mut pending_frame: Option = None; - let mut limit_warning_closed = false; - - loop { - if let Some(frame) = pending_frame.take() { - handle_protocol_frame( - frame, - &mut sidecar, - &mut stdin_rx, - &mut pending_frame, - &write_tx, - &mut active_sessions, - &mut active_connections, - ) - .await?; - continue; - } - - tokio::select! { - maybe_frame = stdin_rx.recv() => { - let Some(frame) = maybe_frame else { - break; - }; - let Some(frame) = frame.map_err(io::Error::other)? else { - break; - }; - handle_protocol_frame( - frame, - &mut sidecar, - &mut stdin_rx, - &mut pending_frame, - &write_tx, - &mut active_sessions, - &mut active_connections, - ).await?; - } - maybe_warning = limit_warning_rx.recv(), if !limit_warning_closed => { - match maybe_warning { - Some(warning) => { - // A limit warning is process-global; deliver it ONCE. The - // stdio transport is single-client, so emit it to the first - // active connection (if any) rather than fanning out a copy - // per connection. Dropped if no client has authenticated yet - // (only the tracing log survives, which is acceptable). - if let Some(connection_id) = active_connections.iter().next() { - let mut detail = std::collections::HashMap::new(); - detail.insert(String::from("limit"), warning.name.as_str().to_string()); - detail.insert( - String::from("category"), - warning.category.as_str().to_string(), - ); - detail.insert(String::from("observed"), warning.observed.to_string()); - detail.insert(String::from("capacity"), warning.capacity.to_string()); - detail.insert( - String::from("fillPercent"), - warning.fill_percent.to_string(), - ); - let frame = crate::service::structured_event_frame( - connection_id, - "limit_warning", - detail, - )?; - send_output_frame(&write_tx, ProtocolFrame::EventFrame(frame))?; - } - } - None => { - // Sender dropped (only possible if another sidecar replaced - // the global handler in-process). Disarm this branch so the - // select! does not hot-spin on an always-ready closed - // receiver; do NOT break — that would tear down the sidecar. - limit_warning_closed = true; - } - } - } - maybe_ready = event_ready_rx.recv() => { - let Some(()) = maybe_ready else { - break; - }; - loop { - let mut emitted_frame = false; - for session in active_sessions.iter().cloned().collect::>() { - if let Some(frame) = sidecar - .poll_event_wire(&session.ownership_scope(), Duration::ZERO) - .await? - { - send_output_frame(&write_tx, ProtocolFrame::EventFrame(frame))?; - emitted_frame = true; - } - } - - if !emitted_frame { - break; - } - } - flush_sidecar_requests(&mut sidecar, &write_tx)?; - } - _ = process_event_notify.notified() => { - for session in active_sessions.iter().cloned().collect::>() { - if sidecar.pump_process_events(&session.compat_ownership_scope()).await? { - let _ = event_ready_tx.try_send(()); - } - } - flush_sidecar_requests(&mut sidecar, &write_tx)?; - } - _ = event_pump.tick() => { - for session in active_sessions.iter().cloned().collect::>() { - if sidecar.pump_process_events(&session.compat_ownership_scope()).await? { - let _ = event_ready_tx.try_send(()); - } - } - flush_sidecar_requests(&mut sidecar, &write_tx)?; - } - maybe_write_error = write_error_rx.recv() => { - if let Some(error) = maybe_write_error { - return Err(io::Error::new(io::ErrorKind::BrokenPipe, error).into()); - } - } - } - } - - cleanup_connections(&mut sidecar, &active_connections, &mut active_sessions).await; - Ok(()) -} - -async fn handle_protocol_frame( - frame: ProtocolFrame, - sidecar: &mut NativeSidecar, - stdin_rx: &mut Receiver, String>>, - pending_frame: &mut Option, - write_tx: &TrackedSyncSender, - active_sessions: &mut BTreeSet, - active_connections: &mut BTreeSet, -) -> Result<(), Box> { - match frame { - ProtocolFrame::RequestFrame(request) => { - let (dispatch, extra_responses) = - dispatch_with_prompt_interrupt(sidecar, request.clone(), stdin_rx, pending_frame) - .await?; - track_session_state( - &dispatch.response.payload, - active_sessions, - active_connections, - ); - - send_output_frame(write_tx, ProtocolFrame::ResponseFrame(dispatch.response))?; - for response in extra_responses { - send_output_frame(write_tx, ProtocolFrame::ResponseFrame(response))?; - } - for event in dispatch.events { - send_output_frame(write_tx, ProtocolFrame::EventFrame(event))?; - } - flush_sidecar_requests(sidecar, write_tx)?; - } - ProtocolFrame::SidecarResponseFrame(response) => { - sidecar.accept_wire_sidecar_response(response)?; - flush_sidecar_requests(sidecar, write_tx)?; - } - other => { - return Err(format!( - "expected request or sidecar_response frame on stdin, received {}", - frame_kind(&other) - ) - .into()); - } - } - // Drop any sessions the sidecar disposed while handling this frame from the - // active-session set so the event pump stops iterating dead sessions (M5). - untrack_disposed_sessions(&sidecar.take_disposed_sessions(), active_sessions); - Ok(()) -} - -/// Remove every disposed session scope from the stdio transport's active-session -/// set. Without this the set is insert-only (`track_session_state` adds on -/// `SessionOpenedResponse` but nothing ever removed), so it grew per session for -/// the process lifetime and the ~250us event pump iterated every dead entry (M5). -fn untrack_disposed_sessions( - disposed: &[(String, String)], - active_sessions: &mut BTreeSet, -) { - for (connection_id, session_id) in disposed { - active_sessions.remove(&SessionScope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - }); - } -} - -async fn dispatch_with_prompt_interrupt( - sidecar: &mut NativeSidecar, - request: RequestFrame, - stdin_rx: &mut Receiver, String>>, - pending_frame: &mut Option, -) -> Result<(WireDispatchResult, Vec), Box> { - let Some(blocking_request) = blocking_extension_request(sidecar, &request) else { - return Ok((sidecar.dispatch_wire(request).await?, Vec::new())); - }; - - let mut dispatch = Box::pin(sidecar.dispatch_wire(request.clone())); - tokio::select! { - result = dispatch.as_mut() => Ok((result?, Vec::new())), - maybe_frame = stdin_rx.recv() => { - let frame = decode_stdin_frame(maybe_frame)?; - if let Some(frame) = frame { - if let Some(interrupt) = extension_interrupt_response(&blocking_request, &request, &frame) { - drop(dispatch); - let mut extra_responses = Vec::new(); - if let Some(response) = interrupt.interrupting_response { - extra_responses.push(response); - } else { - *pending_frame = Some(frame); - } - return Ok((interrupt.interrupted_dispatch, extra_responses)); - } - *pending_frame = Some(frame); - } - Ok((dispatch.await?, Vec::new())) - } - } -} - -fn decode_stdin_frame( - maybe_frame: Option, String>>, -) -> Result, Box> { - let Some(frame) = maybe_frame else { - return Ok(None); - }; - Ok(frame.map_err(io::Error::other)?) -} - -struct BlockingExtensionRequest { - namespace: String, - payload: Vec, - extension: Arc, -} - -struct ExtensionInterruptDispatch { - interrupted_dispatch: WireDispatchResult, - interrupting_response: Option, -} - -fn blocking_extension_request( - sidecar: &NativeSidecar, - request: &RequestFrame, -) -> Option { - let RequestPayload::ExtEnvelope(envelope) = &request.payload else { - return None; - }; - let extension = sidecar.extensions.get(&envelope.namespace)?.clone(); - if !extension.is_blocking_request(&envelope.payload) { - return None; - } - Some(BlockingExtensionRequest { - namespace: envelope.namespace.clone(), - payload: envelope.payload.clone(), - extension, - }) -} - -fn extension_interrupt_response( - blocking_request: &BlockingExtensionRequest, - active_request: &RequestFrame, - frame: &ProtocolFrame, -) -> Option { - match frame { - ProtocolFrame::RequestFrame(request) => { - let interrupt = generated_wire_blocking_extension_interrupt( - active_request, - &blocking_request.namespace, - request, - )?; - let interrupt = blocking_request.extension.interrupt_blocking_request( - &blocking_request.payload, - match interrupt { - BlockingExtensionInterrupt::ExtensionPayload(payload) => { - ExtensionInterruptRequest::ExtensionPayload(payload) - } - BlockingExtensionInterrupt::KillProcess => { - ExtensionInterruptRequest::KillProcess - } - }, - )?; - let interrupted_dispatch = interrupted_extension_dispatch( - active_request, - &blocking_request.namespace, - interrupt.interrupted_response_payload, - ); - let interrupting_response = interrupt.interrupting_response_payload.map(|payload| { - response_frame( - request.request_id, - request.ownership.clone(), - ResponsePayload::ExtEnvelope(ExtEnvelope { - namespace: blocking_request.namespace.clone(), - payload, - }), - ) - }); - Some(ExtensionInterruptDispatch { - interrupted_dispatch, - interrupting_response, - }) - } - // Response, Event, and SidecarRequest frames are sidecar-to-host only. If one - // arrives on stdin it is requeued and rejected as a protocol error by - // handle_protocol_frame, so it must not synthesize a cancelled prompt first. - // SidecarResponse frames answer sidecar-initiated callbacks and may be the very - // response the blocked prompt dispatch is waiting on, so they never interrupt. - ProtocolFrame::ResponseFrame(_) - | ProtocolFrame::EventFrame(_) - | ProtocolFrame::SidecarRequestFrame(_) - | ProtocolFrame::SidecarResponseFrame(_) => None, - } -} - -fn interrupted_extension_dispatch( - request: &RequestFrame, - namespace: &str, - payload: Vec, -) -> WireDispatchResult { - if !matches!(request.payload, RequestPayload::ExtEnvelope(_)) { - unreachable!("interrupted extension dispatch requires an extension request"); - } - - let response = ResponsePayload::ExtEnvelope(ExtEnvelope { - namespace: namespace.to_string(), - payload, - }); - WireDispatchResult { - response: response_frame(request.request_id, request.ownership.clone(), response), - events: Vec::new(), - } -} - -async fn cleanup_connections( - sidecar: &mut NativeSidecar, - active_connections: &BTreeSet, - active_sessions: &mut BTreeSet, -) { - for connection_id in active_connections { - let _ = sidecar.remove_connection(connection_id).await; - } - untrack_disposed_sessions(&sidecar.take_disposed_sessions(), active_sessions); -} - -fn track_session_state( - payload: &ResponsePayload, - active_sessions: &mut BTreeSet, - active_connections: &mut BTreeSet, -) { - match payload { - ResponsePayload::AuthenticatedResponse(AuthenticatedResponse { connection_id, .. }) => { - active_connections.insert(connection_id.clone()); - } - ResponsePayload::SessionOpenedResponse(SessionOpenedResponse { - session_id, - owner_connection_id, - }) => { - active_sessions.insert(SessionScope { - connection_id: owner_connection_id.clone(), - session_id: session_id.clone(), - }); - } - _ => {} - } -} - -fn read_frame( - codec: &WireFrameCodec, - reader: &mut impl Read, -) -> Result, Box> { - let mut prefix = [0u8; 4]; - match reader.read_exact(&mut prefix) { - Ok(()) => {} - Err(error) if error.kind() == io::ErrorKind::UnexpectedEof => { - return Ok(None); - } - Err(error) => return Err(error.into()), - } - - let declared_len = u32::from_be_bytes(prefix) as usize; - if declared_len > codec.max_frame_bytes() { - return Err(ProtocolCodecError::FrameTooLarge { - size: declared_len, - max: codec.max_frame_bytes(), - } - .into()); - } - let total_len = prefix.len().saturating_add(declared_len); - let mut bytes = Vec::with_capacity(total_len); - bytes.extend_from_slice(&prefix); - bytes.resize(total_len, 0); - reader.read_exact(&mut bytes[prefix.len()..])?; - - Ok(Some(codec.decode(&bytes)?)) -} - -fn write_frame( - codec: &WireFrameCodec, - writer: &mut impl Write, - frame: &ProtocolFrame, -) -> Result<(), Box> { - let bytes = codec.encode(frame)?; - writer.write_all(&bytes)?; - writer.flush()?; - Ok(()) -} - -fn frame_kind(frame: &ProtocolFrame) -> &'static str { - match frame { - ProtocolFrame::RequestFrame(_) => "request", - ProtocolFrame::ResponseFrame(_) => "response", - ProtocolFrame::EventFrame(_) => "event", - ProtocolFrame::SidecarRequestFrame(_) => "sidecar_request", - ProtocolFrame::SidecarResponseFrame(_) => "sidecar_response", - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum StdinFrameQueueError { - Full(String), - Closed, -} - -fn enqueue_stdin_frame( - sender: &tokio::sync::mpsc::Sender, String>>, - frame: Result, String>, -) -> Result<(), StdinFrameQueueError> { - sender.try_send(frame).map_err(|error| match error { - tokio::sync::mpsc::error::TrySendError::Full(_) => StdinFrameQueueError::Full(format!( - "stdin frame queue exceeded {MAX_STDIN_FRAME_QUEUE} pending frames" - )), - tokio::sync::mpsc::error::TrySendError::Closed(_) => StdinFrameQueueError::Closed, - }) -} - -fn flush_sidecar_requests( - sidecar: &mut NativeSidecar, - writer: &TrackedSyncSender, -) -> Result<(), Box> { - while let Some(request) = sidecar.pop_wire_sidecar_request()? { - send_output_frame(writer, ProtocolFrame::SidecarRequestFrame(request))?; - } - Ok(()) -} - -fn send_output_frame( - writer: &TrackedSyncSender, - frame: ProtocolFrame, -) -> Result<(), io::Error> { - // Apply backpressure rather than killing the sidecar when the host reads - // stdout slowly. A full queue means the dedicated writer thread is blocked on - // the stdout pipe (the host has not drained it yet) — a transient, recoverable - // condition. Previously `try_send` turned that backlog into a `BrokenPipe` - // error that propagated up and exited the whole sidecar process (code 1), - // taking every session with it. A blocking `send` parks the producer until the - // writer drains a slot, which transitively backpressures the V8 event bridge - // and the guest. It never deadlocks: the writer thread runs independently, and - // if it dies (real broken pipe) the receiver is dropped and `send` returns - // `Disconnected`, which we still surface as a terminal `BrokenPipe`. - writer.send(frame).map_err(|_disconnected| { - io::Error::new(io::ErrorKind::BrokenPipe, "stdout writer disconnected") - }) -} - -fn default_compile_cache_root() -> PathBuf { - // Stable across sidecar processes so V8 compile-cache (cachedData) survives a - // fresh sidecar/VM and benefits cold starts. Previously keyed by PID, which - // gave every process an empty cache — cold module imports never reused - // compiled bytecode. Entries are namespaced+validated downstream by - // `stable_compile_cache_namespace_hash` + V8's source/version checks, so a - // shared root is safe; stale or mismatched entries are simply ignored. - std::env::temp_dir().join("secure-exec-sidecar-compile-cache") -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::wire::{AuthenticateRequest, KillProcessRequest}; - use crate::{ExtensionContext, ExtensionFuture, ExtensionInterruptResponse, ExtensionResponse}; - use std::io::Cursor; - - const TEST_EXTENSION_NAMESPACE: &str = "dev.rivet.secure-exec.test.blocking"; - - #[test] - fn read_frame_rejects_oversized_prefix_before_allocating_payload() { - let codec = WireFrameCodec::new(16); - let mut reader = Cursor::new((32_u32).to_be_bytes().to_vec()); - - let error = read_frame(&codec, &mut reader).expect_err("oversized frame should fail"); - let error = error - .downcast::() - .expect("protocol codec error"); - assert!(matches!( - *error, - ProtocolCodecError::FrameTooLarge { size: 32, max: 16 } - )); - } - - #[test] - fn stdio_work_queues_are_bounded() { - let (stdin_tx, _stdin_rx) = - channel::, String>>(MAX_STDIN_FRAME_QUEUE); - for _ in 0..MAX_STDIN_FRAME_QUEUE { - enqueue_stdin_frame(&stdin_tx, Ok(None)) - .expect("stdin frame queue should accept capacity"); - } - assert!(matches!( - enqueue_stdin_frame(&stdin_tx, Ok(None)), - Err(StdinFrameQueueError::Full(_)) - )); - - let (event_ready_tx, _event_ready_rx) = channel::<()>(MAX_EVENT_READY_QUEUE); - event_ready_tx - .try_send(()) - .expect("event-ready queue should accept capacity"); - assert!(matches!( - event_ready_tx.try_send(()), - Err(tokio::sync::mpsc::error::TrySendError::Full(_)) - )); - } - - // Regression: a full stdout frame queue must apply backpressure (block the - // producer until the writer drains a slot), NOT tear the sidecar down. The - // old `try_send` turned a slow host reader into a `BrokenPipe` error that - // propagated up and exited the whole sidecar process (code 1). Here a slow - // drainer forces the queue past capacity; with backpressure every send - // succeeds, and overflow only fails when the writer (receiver) is gone. - #[test] - fn stdout_frame_queue_applies_backpressure_instead_of_crashing() { - let queue_frame = |request_id: RequestId| { - ProtocolFrame::RequestFrame(request_frame( - request_id, - connection_ownership("conn-queue"), - RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("queue-test"), - auth_token: String::from("token"), - protocol_version: wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - )) - }; - - // Small fixed capacity (independent of the production constant) with a - // drainer slow enough that the queue fills and the producer is forced - // onto the blocking path. The old try_send path errored on the - // (capacity + 1)th frame; backpressure accepts all of them. - let queue_cap = 8usize; - let total_frames = queue_cap * 3; - let (stdout_tx, stdout_rx) = - tracked_sync_channel::(TrackedLimit::SidecarStdoutFrames, queue_cap); - let drainer = std::thread::spawn(move || { - let mut drained = 0usize; - while stdout_rx.recv().is_ok() { - drained += 1; - std::thread::sleep(std::time::Duration::from_millis(1)); - } - drained - }); - - for request_id in 0..total_frames { - send_output_frame(&stdout_tx, queue_frame(request_id as RequestId)) - .expect("backpressured stdout queue must accept frames, not crash"); - } - drop(stdout_tx); - let drained = drainer.join().expect("drainer thread panicked"); - assert_eq!( - drained, total_frames, - "every frame must survive the backpressured queue" - ); - - // When the writer (receiver) is gone, overflow is genuinely terminal and - // still surfaces as a BrokenPipe error rather than blocking forever. - let (closed_tx, closed_rx) = - tracked_sync_channel::(TrackedLimit::SidecarStdoutFrames, queue_cap); - drop(closed_rx); - let error = send_output_frame(&closed_tx, queue_frame(0)) - .expect_err("send to a dropped writer must error"); - assert_eq!(error.kind(), io::ErrorKind::BrokenPipe); - } - - // Regression (M5): the active-session set must shrink when a session is - // disposed. `track_session_state` is insert-only, so the transport relies on - // `untrack_disposed_sessions` draining the sidecar's disposed-session signal; - // without it a long-lived connection's set grows per session forever and the - // ~250us event pump iterates every dead entry. - #[test] - fn disposed_sessions_are_untracked_from_active_sessions() { - let mut active_sessions = BTreeSet::::new(); - let mut active_connections = BTreeSet::::new(); - track_session_state( - &ResponsePayload::SessionOpenedResponse(SessionOpenedResponse { - session_id: String::from("session-1"), - owner_connection_id: String::from("conn-1"), - }), - &mut active_sessions, - &mut active_connections, - ); - assert_eq!( - active_sessions.len(), - 1, - "opening a session should track it for the event pump" - ); - - untrack_disposed_sessions( - &[(String::from("conn-1"), String::from("session-1"))], - &mut active_sessions, - ); - assert!( - active_sessions.is_empty(), - "a disposed session must be removed from the active-session set" - ); - } - - #[test] - fn read_frame_decodes_wire_authenticate_request() { - let codec = WireFrameCodec::new(wire::DEFAULT_MAX_FRAME_BYTES); - let frame = ProtocolFrame::RequestFrame(request_frame( - 1, - connection_ownership("client-hint"), - RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: "probe".to_string(), - auth_token: "probe-token".to_string(), - protocol_version: wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - )); - let encoded = codec.encode(&frame).expect("encode wire frame"); - let mut reader = Cursor::new(encoded); - - let decoded = read_frame(&codec, &mut reader) - .expect("decode bare frame") - .expect("frame present"); - - assert_eq!(decoded, frame); - } - - #[test] - fn extension_close_interrupts_matching_blocking_request() { - let ownership = vm_ownership("conn-1", "session-1", "vm-1"); - let prompt = test_extension_request_frame(10, ownership.clone(), "prompt:ext-session-1"); - let close = ProtocolFrame::RequestFrame(test_extension_request_frame( - 11, - ownership, - "close:ext-session-1", - )); - - let blocking_request = blocking_extension_request(&prompt); - let interrupt = extension_interrupt_response(&blocking_request, &prompt, &close) - .expect("close should interrupt prompt"); - - assert_eq!(interrupt.interrupted_dispatch.response.request_id, 10); - let ResponsePayload::ExtEnvelope(envelope) = - interrupt.interrupted_dispatch.response.payload - else { - panic!("expected extension response"); - }; - assert_eq!(envelope.namespace, TEST_EXTENSION_NAMESPACE); - assert_eq!(envelope.payload, b"prompt-cancelled:ext-session-1"); - } - - #[test] - fn extension_cancel_interrupt_gets_synthetic_response() { - let ownership = vm_ownership("conn-1", "session-1", "vm-1"); - let prompt = test_extension_request_frame(10, ownership.clone(), "prompt:ext-session-1"); - let cancel = ProtocolFrame::RequestFrame(test_extension_request_frame( - 11, - ownership, - "cancel:ext-session-1", - )); - - let blocking_request = blocking_extension_request(&prompt); - let interrupt = extension_interrupt_response(&blocking_request, &prompt, &cancel) - .expect("cancel should interrupt prompt"); - let response = interrupt - .interrupting_response - .expect("cancel should get a response"); - - assert_eq!(response.request_id, 11); - let ResponsePayload::ExtEnvelope(envelope) = response.payload else { - panic!("expected extension response"); - }; - assert_eq!(envelope.namespace, TEST_EXTENSION_NAMESPACE); - assert_eq!(envelope.payload, b"cancelled:ext-session-1"); - } - - #[test] - fn kill_process_interrupts_blocking_extension_request() { - let ownership = vm_ownership("conn-1", "session-1", "vm-1"); - let prompt = test_extension_request_frame(10, ownership.clone(), "prompt:ext-session-1"); - let kill = ProtocolFrame::RequestFrame(request_frame( - 11, - ownership, - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: "adapter-process".to_string(), - signal: "SIGTERM".to_string(), - }), - )); - - let blocking_request = blocking_extension_request(&prompt); - let interrupt = extension_interrupt_response(&blocking_request, &prompt, &kill) - .expect("kill should interrupt prompt"); - - assert_eq!(interrupt.interrupted_dispatch.response.request_id, 10); - assert!(interrupt.interrupting_response.is_none()); - } - - fn test_extension_request_frame( - request_id: RequestId, - ownership: OwnershipScope, - payload: &str, - ) -> RequestFrame { - request_frame( - request_id, - ownership, - RequestPayload::ExtEnvelope(ExtEnvelope { - namespace: TEST_EXTENSION_NAMESPACE.to_string(), - payload: payload.as_bytes().to_vec(), - }), - ) - } - - fn blocking_extension_request(request: &RequestFrame) -> BlockingExtensionRequest { - let RequestPayload::ExtEnvelope(envelope) = &request.payload else { - panic!("expected extension request"); - }; - BlockingExtensionRequest { - namespace: TEST_EXTENSION_NAMESPACE.to_string(), - payload: envelope.payload.clone(), - extension: Arc::new(TestBlockingInterruptExtension), - } - } - - struct TestBlockingInterruptExtension; - - impl Extension for TestBlockingInterruptExtension { - fn namespace(&self) -> &str { - TEST_EXTENSION_NAMESPACE - } - - fn handle_request<'a>( - &'a self, - _ctx: ExtensionContext<'a>, - _payload: Vec, - ) -> ExtensionFuture<'a, ExtensionResponse> { - Box::pin(async { Ok(ExtensionResponse::new(Vec::new())) }) - } - - fn is_blocking_request(&self, payload: &[u8]) -> bool { - parse_test_payload(payload).is_some_and(|(kind, _session_id)| kind == "prompt") - } - - fn interrupt_blocking_request( - &self, - blocking_payload: &[u8], - interrupt: ExtensionInterruptRequest<'_>, - ) -> Option { - let (blocking_kind, blocking_session_id) = parse_test_payload(blocking_payload)?; - if blocking_kind != "prompt" { - return None; - } - - let interrupted_response_payload = - encode_test_response("prompt-cancelled", blocking_session_id); - match interrupt { - ExtensionInterruptRequest::KillProcess => Some(ExtensionInterruptResponse { - interrupted_response_payload, - interrupting_response_payload: None, - }), - ExtensionInterruptRequest::ExtensionPayload(payload) => { - let (interrupt_kind, interrupt_session_id) = parse_test_payload(payload)?; - match interrupt_kind { - "close" if interrupt_session_id == blocking_session_id => { - Some(ExtensionInterruptResponse { - interrupted_response_payload, - interrupting_response_payload: None, - }) - } - "cancel" if interrupt_session_id == blocking_session_id => { - Some(ExtensionInterruptResponse { - interrupted_response_payload, - interrupting_response_payload: Some(encode_test_response( - "cancelled", - interrupt_session_id, - )), - }) - } - "prompt" | "close" | "cancel" => None, - _ => None, - } - } - } - } - } - - fn parse_test_payload(payload: &[u8]) -> Option<(&str, &str)> { - let payload = std::str::from_utf8(payload).ok()?; - payload.split_once(':') - } - - fn encode_test_response(kind: &str, session_id: &str) -> Vec { - format!("{kind}:{session_id}").into_bytes() - } -} - -#[derive(Debug, Clone)] -pub(crate) struct LocalBridge { - started_at: Instant, - next_timer_id: usize, - snapshots: BTreeMap, -} - -impl Default for LocalBridge { - fn default() -> Self { - Self { - started_at: Instant::now(), - next_timer_id: 0, - snapshots: BTreeMap::new(), - } - } -} - -impl BridgeTypes for LocalBridge { - type Error = LocalBridgeError; -} - -impl FilesystemBridge for LocalBridge { - fn read_file(&mut self, request: ReadFileRequest) -> Result, Self::Error> { - fs::read(Self::host_path(&request.path)) - .map_err(|error| LocalBridgeError::io("read", &request.path, error)) - } - - fn write_file(&mut self, request: WriteFileRequest) -> Result<(), Self::Error> { - let host_path = Self::host_path(&request.path); - if let Some(parent) = host_path.parent() { - fs::create_dir_all(parent) - .map_err(|error| LocalBridgeError::io("mkdir", &request.path, error))?; - } - fs::write(host_path, request.contents) - .map_err(|error| LocalBridgeError::io("write", &request.path, error)) - } - - fn stat(&mut self, request: PathRequest) -> Result { - fs::metadata(Self::host_path(&request.path)) - .map(Self::file_metadata) - .map_err(|error| LocalBridgeError::io("stat", &request.path, error)) - } - - fn lstat(&mut self, request: PathRequest) -> Result { - fs::symlink_metadata(Self::host_path(&request.path)) - .map(Self::file_metadata) - .map_err(|error| LocalBridgeError::io("lstat", &request.path, error)) - } - - fn read_dir(&mut self, request: ReadDirRequest) -> Result, Self::Error> { - let mut entries = fs::read_dir(Self::host_path(&request.path)) - .map_err(|error| LocalBridgeError::io("readdir", &request.path, error))? - .map(|entry| { - let entry = - entry.map_err(|error| LocalBridgeError::io("readdir", &request.path, error))?; - let kind = entry - .file_type() - .map(Self::file_kind) - .map_err(|error| LocalBridgeError::io("readdir", &request.path, error))?; - Ok(DirectoryEntry { - name: entry.file_name().to_string_lossy().into_owned(), - kind, - }) - }) - .collect::, LocalBridgeError>>()?; - entries.sort_by(|left, right| left.name.cmp(&right.name)); - Ok(entries) - } - - fn create_dir(&mut self, request: CreateDirRequest) -> Result<(), Self::Error> { - let host_path = Self::host_path(&request.path); - if request.recursive { - fs::create_dir_all(host_path) - } else { - fs::create_dir(host_path) - } - .map_err(|error| LocalBridgeError::io("mkdir", &request.path, error)) - } - - fn remove_file(&mut self, request: PathRequest) -> Result<(), Self::Error> { - fs::remove_file(Self::host_path(&request.path)) - .map_err(|error| LocalBridgeError::io("unlink", &request.path, error)) - } - - fn remove_dir(&mut self, request: PathRequest) -> Result<(), Self::Error> { - fs::remove_dir(Self::host_path(&request.path)) - .map_err(|error| LocalBridgeError::io("rmdir", &request.path, error)) - } - - fn rename(&mut self, request: RenameRequest) -> Result<(), Self::Error> { - let from_path = Self::host_path(&request.from_path); - let to_path = Self::host_path(&request.to_path); - if let Some(parent) = to_path.parent() { - fs::create_dir_all(parent) - .map_err(|error| LocalBridgeError::io("mkdir", &request.to_path, error))?; - } - fs::rename(from_path, to_path).map_err(|error| { - LocalBridgeError::unsupported(format!( - "rename {} -> {}: {}", - request.from_path, request.to_path, error - )) - }) - } - - fn symlink(&mut self, request: SymlinkRequest) -> Result<(), Self::Error> { - let link_path = Self::host_path(&request.link_path); - if let Some(parent) = link_path.parent() { - fs::create_dir_all(parent) - .map_err(|error| LocalBridgeError::io("mkdir", &request.link_path, error))?; - } - create_symlink(&request.target_path, link_path) - .map_err(|error| LocalBridgeError::io("symlink", &request.link_path, error)) - } - - fn read_link(&mut self, request: PathRequest) -> Result { - fs::read_link(Self::host_path(&request.path)) - .map(|target| target.to_string_lossy().into_owned()) - .map_err(|error| LocalBridgeError::io("readlink", &request.path, error)) - } - - fn chmod(&mut self, request: ChmodRequest) -> Result<(), Self::Error> { - let permissions = fs::Permissions::from_mode(request.mode); - fs::set_permissions(Self::host_path(&request.path), permissions) - .map_err(|error| LocalBridgeError::io("chmod", &request.path, error)) - } - - fn truncate(&mut self, request: TruncateRequest) -> Result<(), Self::Error> { - OpenOptions::new() - .write(true) - .create(false) - .open(Self::host_path(&request.path)) - .and_then(|file| file.set_len(request.len)) - .map_err(|error| LocalBridgeError::io("truncate", &request.path, error)) - } - - fn exists(&mut self, request: PathRequest) -> Result { - Ok(fs::symlink_metadata(Self::host_path(&request.path)).is_ok()) - } -} - -impl PermissionBridge for LocalBridge { - fn check_filesystem_access( - &mut self, - request: FilesystemPermissionRequest, - ) -> Result { - Ok(PermissionDecision::deny(format!( - "no static filesystem policy registered for {}:{}", - request.vm_id, request.path - ))) - } - - fn check_network_access( - &mut self, - request: NetworkPermissionRequest, - ) -> Result { - Ok(PermissionDecision::deny(format!( - "no static network policy registered for {}:{}", - request.vm_id, request.resource - ))) - } - - fn check_command_execution( - &mut self, - request: CommandPermissionRequest, - ) -> Result { - Ok(PermissionDecision::deny(format!( - "no static child_process policy registered for {}:{}", - request.vm_id, request.command - ))) - } - - fn check_environment_access( - &mut self, - request: EnvironmentPermissionRequest, - ) -> Result { - Ok(PermissionDecision::deny(format!( - "no static env policy registered for {}:{}", - request.vm_id, request.key - ))) - } -} - -impl PersistenceBridge for LocalBridge { - fn load_filesystem_state( - &mut self, - request: LoadFilesystemStateRequest, - ) -> Result, Self::Error> { - Ok(self.snapshots.get(&request.vm_id).cloned()) - } - - fn flush_filesystem_state( - &mut self, - request: FlushFilesystemStateRequest, - ) -> Result<(), Self::Error> { - self.snapshots.insert(request.vm_id, request.snapshot); - Ok(()) - } -} - -impl ClockBridge for LocalBridge { - fn wall_clock(&mut self, _request: ClockRequest) -> Result { - Ok(SystemTime::now()) - } - - fn monotonic_clock(&mut self, _request: ClockRequest) -> Result { - Ok(self.started_at.elapsed()) - } - - fn schedule_timer( - &mut self, - request: ScheduleTimerRequest, - ) -> Result { - self.next_timer_id += 1; - Ok(ScheduledTimer { - timer_id: format!("timer-{}", self.next_timer_id), - delay: request.delay, - }) - } -} - -impl RandomBridge for LocalBridge { - fn fill_random_bytes(&mut self, request: RandomBytesRequest) -> Result, Self::Error> { - Ok(vec![0u8; request.len]) - } -} - -impl EventBridge for LocalBridge { - fn emit_structured_event(&mut self, _event: StructuredEventRecord) -> Result<(), Self::Error> { - Ok(()) - } - - fn emit_diagnostic(&mut self, _event: DiagnosticRecord) -> Result<(), Self::Error> { - Ok(()) - } - - fn emit_log(&mut self, _event: LogRecord) -> Result<(), Self::Error> { - Ok(()) - } - - fn emit_lifecycle(&mut self, _event: LifecycleEventRecord) -> Result<(), Self::Error> { - Ok(()) - } -} - -impl ExecutionBridge for LocalBridge { - fn create_javascript_context( - &mut self, - _request: CreateJavascriptContextRequest, - ) -> Result { - Err(LocalBridgeError::unsupported( - "execution bridge is handled internally by the native sidecar", - )) - } - - fn create_wasm_context( - &mut self, - _request: CreateWasmContextRequest, - ) -> Result { - Err(LocalBridgeError::unsupported( - "execution bridge is handled internally by the native sidecar", - )) - } - - fn start_execution( - &mut self, - _request: StartExecutionRequest, - ) -> Result { - Err(LocalBridgeError::unsupported( - "execution bridge is handled internally by the native sidecar", - )) - } - - fn write_stdin(&mut self, _request: WriteExecutionStdinRequest) -> Result<(), Self::Error> { - Err(LocalBridgeError::unsupported( - "execution bridge is handled internally by the native sidecar", - )) - } - - fn close_stdin(&mut self, _request: ExecutionHandleRequest) -> Result<(), Self::Error> { - Err(LocalBridgeError::unsupported( - "execution bridge is handled internally by the native sidecar", - )) - } - - fn kill_execution(&mut self, _request: KillExecutionRequest) -> Result<(), Self::Error> { - Err(LocalBridgeError::unsupported( - "execution bridge is handled internally by the native sidecar", - )) - } - - fn poll_execution_event( - &mut self, - _request: PollExecutionEventRequest, - ) -> Result, Self::Error> { - Ok(None) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -struct SessionScope { - connection_id: String, - session_id: String, -} - -impl SessionScope { - fn ownership_scope(&self) -> OwnershipScope { - session_ownership(&self.connection_id, &self.session_id) - } - - fn compat_ownership_scope(&self) -> crate::protocol::OwnershipScope { - wire::ownership_scope_to_compat(self.ownership_scope()) - } -} - -/// Live event sink backed by the outbound stdout channel. Writes each event as a -/// `ProtocolFrame::EventFrame` immediately, using the same blocking -/// backpressure semantics as the batch event path (`send_output_frame`): a full -/// queue parks the producer until the writer thread drains stdout rather than -/// tearing down the process. -struct FrameEventTransport { - writer: TrackedSyncSender, -} - -impl FrameEventTransport { - fn new(writer: TrackedSyncSender) -> Self { - Self { writer } - } -} - -impl EventSinkTransport for FrameEventTransport { - fn emit_event(&self, event: crate::wire::EventFrame) -> Result<(), SidecarError> { - send_output_frame(&self.writer, ProtocolFrame::EventFrame(event)) - .map_err(|error| SidecarError::Bridge(error.to_string())) - } -} - -struct FrameSidecarRequestTransport { - writer: TrackedSyncSender, - pending: Arc>>>, -} - -impl FrameSidecarRequestTransport { - fn new(writer: TrackedSyncSender) -> Self { - Self { - writer, - pending: Arc::new(Mutex::new(BTreeMap::new())), - } - } - - fn accept_response(&self, response: SidecarResponseFrame) -> bool { - let sender = { - let mut pending = match self.pending.lock() { - Ok(pending) => pending, - Err(_) => return false, - }; - pending.remove(&response.request_id) - }; - let Some(sender) = sender else { - return false; - }; - let _ = sender.send(response); - true - } -} - -impl SidecarRequestTransport for FrameSidecarRequestTransport { - fn send_request( - &self, - request: crate::protocol::SidecarRequestFrame, - timeout: Duration, - ) -> Result { - let request = - wire::sidecar_request_frame_from_compat(request).map_err(wire_protocol_error)?; - let (sender, receiver) = mpsc::sync_channel(1); - self.pending - .lock() - .map_err(|_| { - SidecarError::Bridge(String::from("sidecar callback waiter map lock poisoned")) - })? - .insert(request.request_id, sender); - // Bound the request-frame WRITE by the caller's deadline. The shared - // `send_output_frame` blocks (correct backpressure for the fire-and-forget - // event/response paths), but this request path has a `timeout` that the - // response wait below already honors — so a stalled host stdout must not - // make the *send* block past it. Poll try_send until a slot frees or the - // deadline passes. - let write_deadline = Instant::now() + timeout; - let mut frame = ProtocolFrame::SidecarRequestFrame(request.clone()); - let write_result = loop { - match self.writer.try_send(frame) { - Ok(()) => break Ok(()), - Err(mpsc::TrySendError::Disconnected(_)) => { - break Err(String::from("stdout writer disconnected")); - } - Err(mpsc::TrySendError::Full(returned)) => { - if Instant::now() >= write_deadline { - break Err(format!( - "timed out writing sidecar request frame after {}s", - timeout.as_secs() - )); - } - frame = returned; - thread::sleep(Duration::from_millis(1)); - } - } - }; - if let Err(message) = write_result { - let _ = self - .pending - .lock() - .map(|mut pending| pending.remove(&request.request_id)); - return Err(SidecarError::Io(format!( - "failed to write sidecar request frame: {message}" - ))); - } - match receiver.recv_timeout(timeout) { - Ok(response) => { - wire::sidecar_response_frame_to_compat(response).map_err(wire_protocol_error) - } - Err(mpsc::RecvTimeoutError::Timeout) => { - let _ = self - .pending - .lock() - .map(|mut pending| pending.remove(&request.request_id)); - Err(SidecarError::Io(format!( - "timed out waiting for sidecar response after {}s", - timeout.as_secs() - ))) - } - Err(mpsc::RecvTimeoutError::Disconnected) => Err(SidecarError::Io(String::from( - "sidecar response waiter disconnected", - ))), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct LocalBridgeError { - message: String, -} - -impl LocalBridgeError { - fn unsupported(message: impl Into) -> Self { - Self { - message: message.into(), - } - } - - fn io(operation: &str, path: &str, error: io::Error) -> Self { - Self::unsupported(format!("{operation} {path}: {error}")) - } -} - -impl fmt::Display for LocalBridgeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.message) - } -} - -impl Error for LocalBridgeError {} - -impl LocalBridge { - fn host_path(path: &str) -> PathBuf { - let candidate = Path::new(path); - if candidate.is_absolute() { - candidate.to_path_buf() - } else { - std::env::current_dir() - .unwrap_or_else(|_| PathBuf::from(".")) - .join(candidate) - } - } - - fn file_metadata(metadata: fs::Metadata) -> FileMetadata { - FileMetadata { - mode: metadata.permissions().mode(), - size: metadata.size(), - kind: Self::file_kind(metadata.file_type()), - } - } - - fn file_kind(file_type: fs::FileType) -> secure_exec_bridge::FileKind { - if file_type.is_file() { - secure_exec_bridge::FileKind::File - } else if file_type.is_dir() { - secure_exec_bridge::FileKind::Directory - } else if file_type.is_symlink() { - secure_exec_bridge::FileKind::SymbolicLink - } else { - secure_exec_bridge::FileKind::Other - } - } -} diff --git a/crates/sidecar/src/tools.rs b/crates/sidecar/src/tools.rs deleted file mode 100644 index a52a02a72..000000000 --- a/crates/sidecar/src/tools.rs +++ /dev/null @@ -1,933 +0,0 @@ -use crate::protocol::{ - HostCallbackRequest, HostCallbacksRegisteredResponse, RegisterHostCallbacksRequest, - RequestFrame, ResponsePayload, -}; -use crate::service::{kernel_error, normalize_path, DispatchResult}; -use crate::state::{BridgeError, VmState, TOOL_DRIVER_NAME}; -use crate::{NativeSidecar, NativeSidecarBridge, SidecarError}; -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_sidecar_core::permissions::{ - allow_all_policy, deny_all_policy, evaluate_permissions_policy, -}; -use secure_exec_sidecar_core::tools::{ - ensure_command_aliases_available as core_ensure_command_aliases_available, - ensure_toolkit_name_available as core_ensure_toolkit_name_available, - ensure_toolkit_registry_capacity as core_ensure_toolkit_registry_capacity, - registered_tool_command_names, - validate_toolkit_registration as core_validate_toolkit_registration, ToolRegistrationError, - DEFAULT_TOOL_TIMEOUT_MS, -}; -#[cfg(test)] -#[allow(unused_imports)] -pub(crate) use secure_exec_sidecar_core::tools::{ - MAX_REGISTERED_TOOLKITS, MAX_REGISTERED_TOOLS_PER_VM, MAX_TOOLS_PER_TOOLKIT, - MAX_TOOL_DESCRIPTION_LENGTH, MAX_TOOL_EXAMPLES_PER_TOOL, MAX_TOOL_EXAMPLE_INPUT_BYTES, - MAX_TOOL_SCHEMA_BYTES, MAX_TOOL_SCHEMA_DEPTH, MAX_TOOL_TIMEOUT_MS, -}; -use secure_exec_vm_config::PermissionMode; -use serde_json::{json, Map, Number, Value}; -use std::collections::{BTreeMap, BTreeSet}; -use std::fmt; -use std::path::Path; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -#[derive(Debug)] -pub(crate) enum ToolCommandResolution { - Invoke { - request: HostCallbackRequest, - timeout: Duration, - }, - Failure(String), -} - -pub(crate) fn format_tool_failure_output(message: &str) -> Vec { - let mut output = message.as_bytes().to_vec(); - if !output.ends_with(b"\n") { - output.push(b'\n'); - } - output -} - -pub(crate) fn register_host_callbacks( - sidecar: &mut NativeSidecar, - request: &RequestFrame, - payload: RegisterHostCallbacksRequest, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - let (connection_id, session_id, vm_id) = sidecar.vm_scope_for(&request.ownership)?; - sidecar.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - validate_toolkit_registration(&payload)?; - - let registered_name = payload.name.clone(); - let (original_permissions, original_toolkits, original_command_guest_paths) = { - let vm = sidecar.vms.get(&vm_id).expect("owned VM should exist"); - ( - vm.configuration.permissions.clone(), - vm.toolkits.clone(), - vm.command_guest_paths.clone(), - ) - }; - sidecar - .bridge - .set_vm_permissions(&vm_id, &allow_all_policy())?; - let registration_result = (|| -> Result<_, SidecarError> { - let vm = sidecar.vms.get_mut(&vm_id).expect("owned VM should exist"); - ensure_toolkit_name_available(&vm.toolkits, ®istered_name)?; - ensure_command_aliases_available(&vm.toolkits, &payload)?; - ensure_toolkit_registry_capacity(&vm.toolkits, &payload)?; - vm.toolkits.insert(registered_name.clone(), payload); - refresh_tool_registry(vm)?; - Ok::<_, SidecarError>(tool_command_names(vm).len() as u32) - })(); - let command_count = match registration_result { - Ok(result) => { - sidecar - .bridge - .set_vm_permissions(&vm_id, &original_permissions)?; - result - } - Err(error) => { - let vm = sidecar.vms.get_mut(&vm_id).expect("owned VM should exist"); - vm.toolkits = original_toolkits; - vm.command_guest_paths = original_command_guest_paths; - match sidecar.bridge.restore_vm_permissions_fail_closed( - &vm_id, - &original_permissions, - "toolkit registration rollback", - &error, - ) { - Ok(()) => return Err(error), - Err(rollback_error) => { - vm.configuration.permissions = deny_all_policy(); - return Err(rollback_error); - } - } - } - }; - - Ok(DispatchResult { - response: sidecar.respond( - request, - ResponsePayload::HostCallbacksRegistered(HostCallbacksRegisteredResponse { - registration: registered_name, - command_count, - }), - ), - events: Vec::new(), - }) -} - -fn refresh_tool_registry(vm: &mut VmState) -> Result<(), SidecarError> { - let commands = tool_command_names(vm); - vm.kernel - .register_driver(CommandDriver::new( - TOOL_DRIVER_NAME, - commands.iter().cloned(), - )) - .map_err(kernel_error)?; - - for command in commands { - vm.command_guest_paths - .insert(command.clone(), format!("/bin/{command}")); - } - Ok(()) -} - -pub(crate) fn resolve_tool_command( - vm: &mut VmState, - command: &str, - args: &[String], - cwd: Option<&str>, -) -> Result, SidecarError> { - let Some(kind) = identify_tool_command(vm, command) else { - return Ok(None); - }; - let guest_cwd = cwd - .map(normalize_path) - .unwrap_or_else(|| vm.guest_cwd.clone()); - let resolution = match kind { - ToolCommand::Registry(command_name) => { - resolve_registry_command(vm, &command_name, args, &guest_cwd)? - } - ToolCommand::Toolkit { toolkit_name } => { - resolve_toolkit_command(vm, &toolkit_name, args, &guest_cwd)? - } - }; - Ok(Some(resolution)) -} - -pub(crate) fn is_tool_command(vm: &VmState, command: &str) -> bool { - identify_tool_command(vm, command).is_some() -} - -pub(crate) fn normalized_tool_command_name(command: &str) -> Option { - tool_command_name_from_specifier(command).map(ToOwned::to_owned) -} - -fn identify_tool_command(vm: &VmState, command: &str) -> Option { - let command_name = tool_command_name_from_specifier(command).unwrap_or(command); - - if vm.toolkits.values().any(|toolkit| { - toolkit - .registry_command_aliases - .iter() - .any(|alias| alias == command_name) - }) { - return Some(ToolCommand::Registry(command_name.to_owned())); - } - - vm.toolkits - .iter() - .find(|(_toolkit_name, toolkit)| { - toolkit - .command_aliases - .iter() - .any(|alias| alias == command_name) - }) - .map(|(toolkit_name, _toolkit)| ToolCommand::Toolkit { - toolkit_name: toolkit_name.to_owned(), - }) -} - -fn tool_command_name_from_specifier(command: &str) -> Option<&str> { - let file_name = Path::new(command).file_name()?.to_str()?; - let normalized = normalize_path(command); - let registered_internal_path = normalized - .strip_prefix("/__secure_exec/commands/") - .and_then(|suffix| suffix.rsplit('/').next()) - .is_some_and(|name| name == file_name); - if !matches!( - normalized.as_str(), - path if path == format!("/bin/{file_name}") - || path == format!("/usr/bin/{file_name}") - || path == format!("/usr/local/bin/{file_name}") - ) && !registered_internal_path - { - return None; - } - Some(file_name) -} - -fn resolve_registry_command( - vm: &mut VmState, - command_name: &str, - args: &[String], - guest_cwd: &str, -) -> Result { - let timeout_ms = - command_callback_timeout_ms(vm, &ToolCommand::Registry(command_name.to_owned())); - Ok(build_command_callback_resolution( - command_name, - build_registry_command_input(command_name, args, guest_cwd), - timeout_ms, - )) -} - -fn resolve_toolkit_command( - vm: &mut VmState, - toolkit_name: &str, - args: &[String], - _guest_cwd: &str, -) -> Result { - let Some((tool_name, tool_args)) = args.split_first() else { - return Ok(ToolCommandResolution::Failure(format!( - "toolkit command {toolkit_name} requires a tool name" - ))); - }; - let callback_key = format!("{toolkit_name}:{tool_name}"); - let Some(tool) = vm - .toolkits - .get(toolkit_name) - .and_then(|toolkit| toolkit.callbacks.get(tool_name)) - .cloned() - else { - return Ok(ToolCommandResolution::Failure(format!( - "unknown tool callback {callback_key}" - ))); - }; - if !matches!( - evaluate_permissions_policy( - &vm.configuration.permissions, - "binding", - "binding.invoke", - Some(&callback_key), - ), - PermissionMode::Allow - ) { - return Ok(ToolCommandResolution::Failure(format!( - "blocked by binding.invoke policy for {callback_key}" - ))); - } - - let input_schema: Value = serde_json::from_str(&tool.input_schema).map_err(|error| { - SidecarError::InvalidState(format!( - "tool {callback_key} input schema is not valid JSON: {error}" - )) - })?; - let input = match parse_toolkit_command_input(vm, &input_schema, tool_args) { - Ok(input) => input, - Err(message) => return Ok(ToolCommandResolution::Failure(message)), - }; - if let Err(message) = validate_tool_input_schema(&input_schema, &input) { - return Ok(ToolCommandResolution::Failure(message)); - } - let timeout_ms = tool.timeout_ms.unwrap_or(DEFAULT_TOOL_TIMEOUT_MS); - - Ok(build_command_callback_resolution( - &callback_key, - input, - timeout_ms, - )) -} - -fn build_command_callback_resolution( - command_name: &str, - input: Value, - timeout_ms: u64, -) -> ToolCommandResolution { - let nonce = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_nanos(); - - ToolCommandResolution::Invoke { - request: HostCallbackRequest { - invocation_id: format!("{command_name}:{nonce}"), - callback_key: command_name.to_owned(), - input: input.to_string(), - timeout_ms, - }, - timeout: Duration::from_millis(timeout_ms), - } -} - -fn build_registry_command_input(command_name: &str, args: &[String], guest_cwd: &str) -> Value { - json!({ - "type": "command", - "command": command_name, - "args": args, - "cwd": guest_cwd, - }) -} - -fn parse_toolkit_command_input( - vm: &mut VmState, - schema: &Value, - args: &[String], -) -> Result { - match args { - [] => Ok(Value::Object(Map::new())), - [flag, raw] if flag == "--json" => { - serde_json::from_str(raw).map_err(|error| format!("invalid --json tool input: {error}")) - } - [flag, path] if flag == "--json-file" => { - let bytes = vm - .kernel - .read_file(path) - .map_err(|error| format!("failed to read --json-file {path}: {error}"))?; - let raw = String::from_utf8(bytes) - .map_err(|error| format!("invalid UTF-8 in --json-file {path}: {error}"))?; - serde_json::from_str(&raw) - .map_err(|error| format!("invalid JSON in --json-file {path}: {error}")) - } - _ => parse_toolkit_command_flags(schema, args), - } -} - -fn parse_toolkit_command_flags(schema: &Value, args: &[String]) -> Result { - let Some(schema_object) = schema.as_object() else { - return Ok(json!({ "args": args })); - }; - if schema_object.get("type").and_then(Value::as_str) != Some("object") { - return Ok(json!({ "args": args })); - } - let Some(properties) = schema_object.get("properties").and_then(Value::as_object) else { - return Ok(json!({ "args": args })); - }; - - let required = schema_object - .get("required") - .and_then(Value::as_array) - .map(|required| { - required - .iter() - .filter_map(Value::as_str) - .collect::>() - }) - .unwrap_or_default(); - let flag_to_field = properties - .iter() - .map(|(field_name, field_schema)| (camel_to_kebab(field_name), (field_name, field_schema))) - .collect::>(); - - let mut input = Map::new(); - let mut index = 0; - while index < args.len() { - let arg = &args[index]; - let Some(raw_flag) = arg.strip_prefix("--") else { - return Err(format!("Unexpected positional argument: \"{arg}\"")); - }; - let (negated, flag_name) = raw_flag - .strip_prefix("no-") - .map_or((false, raw_flag), |name| (true, name)); - let Some((field_name, field_schema)) = flag_to_field.get(flag_name) else { - return Err(format!("Unknown flag: --{raw_flag}")); - }; - let field_type = json_schema_type(field_schema); - - if negated { - if field_type != Some("boolean") { - return Err(format!("Unknown flag: --{raw_flag}")); - } - input.insert((*field_name).clone(), Value::Bool(false)); - index += 1; - continue; - } - - if field_type == Some("boolean") { - input.insert((*field_name).clone(), Value::Bool(true)); - index += 1; - continue; - } - - let Some(value) = args.get(index + 1) else { - return Err(format!("Flag --{raw_flag} requires a value")); - }; - let parsed_value = parse_tool_flag_value(raw_flag, field_schema, value)?; - if field_type == Some("array") { - let entry = input - .entry((*field_name).clone()) - .or_insert_with(|| Value::Array(Vec::new())); - let Some(values) = entry.as_array_mut() else { - return Err(format!("Flag --{raw_flag} cannot be repeated")); - }; - values.push(parsed_value); - } else { - input.insert((*field_name).clone(), parsed_value); - } - index += 2; - } - - for field_name in required { - if !input.contains_key(field_name) { - return Err(format!( - "Missing required flag: --{}", - camel_to_kebab(field_name) - )); - } - } - - Ok(Value::Object(input)) -} - -fn parse_tool_flag_value( - raw_flag: &str, - field_schema: &Value, - value: &str, -) -> Result { - let item_schema = field_schema - .get("items") - .filter(|_| json_schema_type(field_schema) == Some("array")) - .unwrap_or(field_schema); - match json_schema_type(item_schema) { - Some("integer") => { - let number = value - .parse::() - .map_err(|_| format!("Flag --{raw_flag} expects an integer, got \"{value}\""))?; - Ok(Value::Number(Number::from(number))) - } - Some("number") => { - let number = value - .parse::() - .map_err(|_| format!("Flag --{raw_flag} expects a number, got \"{value}\""))?; - Number::from_f64(number).map(Value::Number).ok_or_else(|| { - format!("Flag --{raw_flag} expects a finite number, got \"{value}\"") - }) - } - Some("boolean") => match value { - "true" => Ok(Value::Bool(true)), - "false" => Ok(Value::Bool(false)), - _ => Err(format!( - "Flag --{raw_flag} expects a boolean, got \"{value}\"" - )), - }, - _ => Ok(Value::String(value.to_owned())), - } -} - -fn json_schema_type(schema: &Value) -> Option<&str> { - schema.get("type").and_then(Value::as_str) -} - -fn camel_to_kebab(value: &str) -> String { - let mut output = String::with_capacity(value.len()); - for (index, ch) in value.chars().enumerate() { - if ch.is_ascii_uppercase() { - if index > 0 { - output.push('-'); - } - output.push(ch.to_ascii_lowercase()); - } else { - output.push(ch); - } - } - output -} - -fn validate_tool_input_schema(schema: &Value, input: &Value) -> Result<(), String> { - let Some(schema_object) = schema.as_object() else { - return Ok(()); - }; - if schema_object.get("type").and_then(Value::as_str) != Some("object") { - return Ok(()); - } - let Some(input_object) = input.as_object() else { - return Err(String::from( - "ToolInputSchemaViolation at $: expected object", - )); - }; - - if let Some(required) = schema_object.get("required").and_then(Value::as_array) { - for name in required.iter().filter_map(Value::as_str) { - if !input_object.contains_key(name) { - return Err(format!( - "ToolInputSchemaViolation at $.{name}: missing required property" - )); - } - } - } - - let properties = schema_object - .get("properties") - .and_then(Value::as_object) - .cloned() - .unwrap_or_default(); - for (name, property_schema) in &properties { - if let Some(value) = input_object.get(name) { - validate_tool_input_value_type(value, property_schema, &format!("$.{name}"))?; - } - } - if schema_object - .get("additionalProperties") - .and_then(Value::as_bool) - == Some(false) - { - for name in input_object.keys() { - if !properties.contains_key(name) { - return Err(format!( - "ToolInputSchemaViolation at $.{name}: unexpected property" - )); - } - } - } - - Ok(()) -} - -fn validate_tool_input_value_type(value: &Value, schema: &Value, path: &str) -> Result<(), String> { - let Some(expected) = schema.get("type").and_then(Value::as_str) else { - return Ok(()); - }; - let matches = match expected { - "array" => value.is_array(), - "boolean" => value.is_boolean(), - "integer" => value.as_i64().is_some() || value.as_u64().is_some(), - "number" => value.is_number(), - "object" => value.is_object(), - "string" => value.is_string(), - _ => true, - }; - if matches { - Ok(()) - } else { - Err(format!( - "ToolInputSchemaViolation at {path}: expected {expected}" - )) - } -} - -fn command_callback_timeout_ms(vm: &VmState, kind: &ToolCommand) -> u64 { - let callbacks = match kind { - ToolCommand::Registry(command_name) => vm - .toolkits - .values() - .filter(|toolkit| { - toolkit - .registry_command_aliases - .iter() - .any(|alias| alias == command_name) - }) - .flat_map(|toolkit| toolkit.callbacks.values()) - .collect::>(), - ToolCommand::Toolkit { toolkit_name, .. } => vm - .toolkits - .get(toolkit_name) - .map(|toolkit| toolkit.callbacks.values().collect::>()) - .unwrap_or_default(), - }; - - callbacks - .into_iter() - .filter_map(|callback| callback.timeout_ms) - .max() - .unwrap_or(DEFAULT_TOOL_TIMEOUT_MS) -} - -fn ensure_toolkit_name_available( - toolkits: &BTreeMap, - toolkit_name: &str, -) -> Result<(), SidecarError> { - core_ensure_toolkit_name_available(toolkits, toolkit_name).map_err(tool_registration_error) -} - -fn ensure_command_aliases_available( - toolkits: &BTreeMap, - payload: &RegisterHostCallbacksRequest, -) -> Result<(), SidecarError> { - core_ensure_command_aliases_available(toolkits, payload).map_err(tool_registration_error) -} - -fn ensure_toolkit_registry_capacity( - toolkits: &BTreeMap, - payload: &RegisterHostCallbacksRequest, -) -> Result<(), SidecarError> { - core_ensure_toolkit_registry_capacity(toolkits, payload).map_err(tool_registration_error) -} - -fn tool_command_names(vm: &VmState) -> Vec { - registered_tool_command_names(&vm.toolkits) -} - -fn validate_toolkit_registration( - payload: &RegisterHostCallbacksRequest, -) -> Result<(), SidecarError> { - core_validate_toolkit_registration(payload).map_err(tool_registration_error) -} - -fn tool_registration_error(error: ToolRegistrationError) -> SidecarError { - match error { - ToolRegistrationError::InvalidState(message) => SidecarError::InvalidState(message), - ToolRegistrationError::Conflict(message) => SidecarError::Conflict(message), - } -} - -enum ToolCommand { - Registry(String), - Toolkit { toolkit_name: String }, -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::protocol::RegisteredHostCallbackDefinition; - use std::collections::BTreeMap; - - fn screenshot_schema() -> Value { - json!({ - "type": "object", - "properties": { - "url": { "type": "string" }, - "fullPage": { "type": "boolean" }, - "width": { "type": "number" }, - "format": { "type": "string", "enum": ["png", "jpg"] }, - "tags": { "type": "array", "items": { "type": "string" } } - }, - "required": ["url"] - }) - } - - fn registered_tool(description: String) -> RegisteredHostCallbackDefinition { - RegisteredHostCallbackDefinition { - description, - input_schema: screenshot_schema().to_string(), - timeout_ms: None, - examples: Vec::new(), - } - } - - fn toolkit_with_descriptions( - toolkit_description: String, - tool_description: String, - ) -> RegisterHostCallbacksRequest { - toolkit_with_schema( - String::from("browser"), - toolkit_description, - String::from("screenshot"), - tool_description, - screenshot_schema(), - ) - } - - fn toolkit_with_schema( - toolkit_name: String, - toolkit_description: String, - tool_name: String, - tool_description: String, - input_schema: Value, - ) -> RegisterHostCallbacksRequest { - RegisterHostCallbacksRequest { - name: toolkit_name.clone(), - description: toolkit_description, - command_aliases: vec![format!("agentos-{toolkit_name}")], - registry_command_aliases: vec![String::from("agentos")], - callbacks: std::collections::HashMap::from([( - tool_name, - RegisteredHostCallbackDefinition { - description: tool_description, - input_schema: input_schema.to_string(), - timeout_ms: None, - examples: Vec::new(), - }, - )]), - } - } - - #[test] - fn accepts_toolkit_and_tool_descriptions_at_length_limit() { - let description = "a".repeat(MAX_TOOL_DESCRIPTION_LENGTH); - let payload = toolkit_with_descriptions(description.clone(), description); - - validate_toolkit_registration(&payload).expect("description at limit should pass"); - } - - #[test] - fn rejects_toolkit_registration_over_shape_limits() { - let too_many_tools = RegisterHostCallbacksRequest { - name: String::from("browser"), - description: String::from("Browser automation"), - command_aliases: vec![String::from("agentos-browser")], - registry_command_aliases: vec![String::from("agentos")], - callbacks: (0..=MAX_TOOLS_PER_TOOLKIT) - .map(|index| { - ( - format!("tool-{index}"), - registered_tool(String::from("Run a bounded test tool")), - ) - }) - .collect(), - }; - assert!(validate_toolkit_registration(&too_many_tools) - .expect_err("toolkit should reject too many tools") - .to_string() - .contains("max is 64")); - - let mut long_timeout = toolkit_with_descriptions( - String::from("Browser automation"), - String::from("Take a screenshot"), - ); - long_timeout - .callbacks - .get_mut("screenshot") - .expect("test tool") - .timeout_ms = Some(MAX_TOOL_TIMEOUT_MS + 1); - assert!(validate_toolkit_registration(&long_timeout) - .expect_err("toolkit should reject long timeouts") - .to_string() - .contains("timeout is")); - - let mut too_many_examples = toolkit_with_descriptions( - String::from("Browser automation"), - String::from("Take a screenshot"), - ); - too_many_examples - .callbacks - .get_mut("screenshot") - .expect("test tool") - .examples = (0..=MAX_TOOL_EXAMPLES_PER_TOOL) - .map(|index| crate::protocol::RegisteredHostCallbackExample { - description: format!("example {index}"), - input: json!({ "url": "https://example.com" }).to_string(), - }) - .collect(); - assert!(validate_toolkit_registration(&too_many_examples) - .expect_err("toolkit should reject too many examples") - .to_string() - .contains("examples")); - } - - #[test] - fn validates_host_callback_command_aliases() { - let mut payload = toolkit_with_descriptions( - String::from("Browser automation"), - String::from("Take a screenshot"), - ); - payload.command_aliases = vec![String::from("agentos-browser"), String::from("bad/path")]; - assert!(validate_toolkit_registration(&payload) - .expect_err("slashes should be rejected") - .to_string() - .contains("invalid host callback command alias")); - - payload.command_aliases = vec![String::from("agentos-browser")]; - payload.registry_command_aliases = vec![String::from("agentos-browser")]; - assert!(validate_toolkit_registration(&payload) - .expect_err("ambiguous aliases should be rejected") - .to_string() - .contains("must not also be a registry command alias")); - - payload.registry_command_aliases = vec![String::from("agentos")]; - validate_toolkit_registration(&payload).expect("distinct aliases should pass"); - - let existing = BTreeMap::from([(String::from("browser"), payload.clone())]); - let mut next = toolkit_with_schema( - String::from("files"), - String::from("File utilities"), - String::from("read"), - String::from("Read a file"), - screenshot_schema(), - ); - next.command_aliases = vec![String::from("agentos-browser")]; - assert!(ensure_command_aliases_available(&existing, &next) - .expect_err("direct command aliases should be unique") - .to_string() - .contains("already registered")); - - next.command_aliases = vec![String::from("agentos-files")]; - next.registry_command_aliases = vec![String::from("agentos")]; - ensure_command_aliases_available(&existing, &next).expect("registry aliases can be shared"); - } - - #[test] - fn parses_toolkit_command_flags_from_schema() { - let input = parse_toolkit_command_flags( - &screenshot_schema(), - &[ - String::from("--url"), - String::from("https://example.com"), - String::from("--full-page"), - String::from("--width"), - String::from("320"), - String::from("--tags"), - String::from("smoke"), - String::from("--tags"), - String::from("full"), - ], - ) - .expect("parse flags"); - - assert_eq!( - input, - json!({ - "url": "https://example.com", - "fullPage": true, - "width": 320.0, - "tags": ["smoke", "full"], - }) - ); - } - - #[test] - fn parse_toolkit_command_flags_reports_missing_required_flags() { - let error = parse_toolkit_command_flags(&screenshot_schema(), &[]) - .expect_err("missing required flag"); - - assert_eq!(error, "Missing required flag: --url"); - } - - #[test] - fn rejects_toolkit_registration_with_oversized_schema_or_example_input() { - let mut deep_schema = Value::Null; - for _ in 0..=MAX_TOOL_SCHEMA_DEPTH { - deep_schema = json!({ "items": deep_schema }); - } - let deep_schema_payload = toolkit_with_schema( - String::from("browser"), - String::from("Browser automation"), - String::from("screenshot"), - String::from("Take a screenshot"), - deep_schema, - ); - assert!(validate_toolkit_registration(&deep_schema_payload) - .expect_err("toolkit should reject deep schemas") - .to_string() - .contains("max JSON depth")); - - let mut oversized_schema_payload = toolkit_with_schema( - String::from("browser"), - String::from("Browser automation"), - String::from("screenshot"), - String::from("Take a screenshot"), - json!({ "description": "a".repeat(MAX_TOOL_SCHEMA_BYTES) }), - ); - assert!(validate_toolkit_registration(&oversized_schema_payload) - .expect_err("toolkit should reject oversized schemas") - .to_string() - .contains("input schema is")); - - oversized_schema_payload - .callbacks - .get_mut("screenshot") - .expect("test tool") - .input_schema = screenshot_schema().to_string(); - let oversized_example_input = crate::protocol::RegisteredHostCallbackExample { - description: String::from("large example"), - input: json!({ "payload": "a".repeat(MAX_TOOL_EXAMPLE_INPUT_BYTES) }).to_string(), - }; - oversized_schema_payload - .callbacks - .get_mut("screenshot") - .expect("test tool") - .examples = vec![oversized_example_input]; - assert!(validate_toolkit_registration(&oversized_schema_payload) - .expect_err("toolkit should reject oversized example inputs") - .to_string() - .contains("example 0 input is")); - } - - #[test] - fn rejects_toolkit_description_longer_than_limit() { - let payload = toolkit_with_descriptions( - "a".repeat(MAX_TOOL_DESCRIPTION_LENGTH + 1), - String::from("Take a screenshot"), - ); - - let error = validate_toolkit_registration(&payload).expect_err("long toolkit rejected"); - assert_eq!( - error.to_string(), - format!( - "Toolkit \"browser\" description is {} characters, max is {}", - MAX_TOOL_DESCRIPTION_LENGTH + 1, - MAX_TOOL_DESCRIPTION_LENGTH - ) - ); - } - - #[test] - fn rejects_tool_description_longer_than_limit() { - let payload = toolkit_with_descriptions( - String::from("Browser automation"), - "a".repeat(MAX_TOOL_DESCRIPTION_LENGTH + 1), - ); - - let error = validate_toolkit_registration(&payload).expect_err("long tool rejected"); - assert_eq!( - error.to_string(), - format!( - "Tool \"browser/screenshot\" description is {} characters, max is {}", - MAX_TOOL_DESCRIPTION_LENGTH + 1, - MAX_TOOL_DESCRIPTION_LENGTH - ) - ); - } - - #[test] - fn tools_reject_duplicate_toolkit_registration() { - let toolkits = BTreeMap::from([( - String::from("browser"), - toolkit_with_descriptions( - String::from("Browser automation"), - String::from("Take a screenshot"), - ), - )]); - - let error = - ensure_toolkit_name_available(&toolkits, "browser").expect_err("duplicate rejected"); - assert_eq!( - error, - SidecarError::Conflict(String::from("toolkit already registered: browser")) - ); - } -} diff --git a/crates/sidecar/src/vm.rs b/crates/sidecar/src/vm.rs deleted file mode 100644 index 438144444..000000000 --- a/crates/sidecar/src/vm.rs +++ /dev/null @@ -1,2494 +0,0 @@ -//! VM lifecycle functions: create, configure, dispose, bootstrap, snapshot. -//! -//! Extracted from service.rs as part of the service.rs split (Step 0a). -//! Contains VM lifecycle methods on NativeSidecar and associated helpers. - -use crate::bootstrap::{ - apply_root_filesystem_entry, discover_command_guest_paths, root_snapshot_entries, - root_snapshot_entry, root_snapshot_from_entries, -}; -use crate::bridge::{bridge_permissions, MountPluginContext}; -use crate::protocol::{ - AgentosProjectedAgent, ConfigureVmRequest, CreateLayerRequest, CreateOverlayRequest, - DisposeReason, EventFrame, ExportSnapshotRequest, ImportSnapshotRequest, LinkPackageRequest, - MountDescriptor, MountPluginDescriptor, PackageCommands, ProjectedCommand, - ProvidedCommandsRequest, RootFilesystemDescriptor, RootFilesystemEntry, - RootFilesystemEntryEncoding, RootFilesystemLowerDescriptor, SealLayerRequest, - SnapshotRootFilesystemRequest, VmLifecycleState, -}; -use crate::service::{ - audit_fields, dirname, emit_security_audit_event, emit_structured_event, kernel_error, - normalize_path, plugin_error, root_filesystem_error, validate_permissions_policy, vfs_error, -}; -use crate::state::{ - BridgeError, KernelSocketReadinessEvent, KernelSocketReadinessRegistry, - KernelSocketReadinessTarget, VmConfiguration, VmDnsConfig, VmListenPolicy, VmState, - DISPOSE_VM_SIGKILL_GRACE, DISPOSE_VM_SIGTERM_GRACE, EXECUTION_DRIVER_NAME, JAVASCRIPT_COMMAND, - PYTHON_COMMAND, WASM_COMMAND, -}; -use crate::{DispatchResult, NativeSidecar, NativeSidecarBridge, SidecarError}; - -use base64::Engine; -use secure_exec_bridge::{ - FilesystemSnapshot, FlushFilesystemStateRequest, LifecycleState, LoadFilesystemStateRequest, -}; -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig}; -use secure_exec_kernel::mount_plugin::OpenFileSystemPluginRequest; -use secure_exec_kernel::mount_table::{MountOptions, MountTable, MountedFileSystem}; -use secure_exec_kernel::permissions::filter_env; -use secure_exec_kernel::resource_accounting::ResourceLimits; -use secure_exec_kernel::root_fs::{ - decode_snapshot_with_import_limits, encode_snapshot as encode_root_snapshot, - is_supported_root_filesystem_snapshot_format, FilesystemEntryKind as KernelFilesystemEntryKind, - RootFilesystemImportLimits, ROOT_FILESYSTEM_SNAPSHOT_FORMAT, -}; -use secure_exec_kernel::socket_table::{SocketReadiness, SocketReadinessKind}; -use secure_exec_sidecar_core::permissions::{allow_all_policy, deny_all_policy}; -use secure_exec_sidecar_core::{ - layer_created_response, layer_sealed_response, overlay_created_response, - package_linked_response, protocol_root_filesystem_mode, provided_commands_response, - root_filesystem_bootstrapped_response, root_filesystem_protocol_descriptor_from_config, - root_filesystem_snapshot_response, snapshot_exported_response, snapshot_imported_response, - vm_configured_response, vm_created_response, vm_disposed_response, VmLayerStore, -}; -use secure_exec_vm_config as vm_config; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::fmt; -use std::fs; -use std::net::{IpAddr, SocketAddr}; -use std::os::unix::fs::PermissionsExt; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; - -const SHADOW_ROOT_BOOTSTRAP_DIRS: &[(&str, u32)] = &[ - ("/dev", 0o755), - ("/proc", 0o755), - ("/tmp", 0o1777), - ("/bin", 0o755), - ("/lib", 0o755), - ("/sbin", 0o755), - ("/boot", 0o755), - ("/etc", 0o755), - ("/root", 0o755), - ("/run", 0o755), - ("/srv", 0o755), - ("/sys", 0o755), - ("/opt", 0o755), - ("/mnt", 0o755), - ("/media", 0o755), - ("/home", 0o755), - ("/home/agentos", 0o755), - ("/usr", 0o755), - ("/usr/bin", 0o755), - ("/usr/games", 0o755), - ("/usr/include", 0o755), - ("/usr/lib", 0o755), - ("/usr/libexec", 0o755), - ("/usr/man", 0o755), - ("/usr/local", 0o755), - ("/usr/local/bin", 0o755), - ("/usr/sbin", 0o755), - ("/usr/share", 0o755), - ("/usr/share/man", 0o755), - ("/var", 0o755), - ("/var/cache", 0o755), - ("/var/empty", 0o755), - ("/var/lib", 0o755), - ("/var/lock", 0o755), - ("/var/log", 0o755), - ("/var/run", 0o755), - ("/var/spool", 0o755), - ("/var/tmp", 0o1777), - ("/etc/agentos", 0o755), - // Non-Alpine default agent working directory (also present in the base - // filesystem snapshot); scaffold it here so it exists even when the - // default base layer is disabled. It is the default cwd and mount root, - // kept separate from $HOME (/home/agentos). - ("/workspace", 0o755), -]; - -fn send_kernel_socket_readiness_event( - target: KernelSocketReadinessTarget, - readiness: SocketReadiness, -) { - let event = match (target.event, readiness.kind) { - (KernelSocketReadinessEvent::Accept, SocketReadinessKind::Accept) => "accept", - (KernelSocketReadinessEvent::Data, SocketReadinessKind::Data) => "data", - (KernelSocketReadinessEvent::Datagram, SocketReadinessKind::Data) => "dgram", - _ => return, - }; - let payload = match target.event { - KernelSocketReadinessEvent::Accept => { - secure_exec_execution::v8_runtime::json_to_cbor_payload(&serde_json::json!({ - "serverId": target.target_id, - "event": event, - })) - } - KernelSocketReadinessEvent::Data | KernelSocketReadinessEvent::Datagram => { - secure_exec_execution::v8_runtime::json_to_cbor_payload(&serde_json::json!({ - "socketId": target.target_id, - "event": event, - })) - } - } - .unwrap_or_default(); - let _ = target.session.send_stream_event("net_socket", payload); -} - -pub(crate) const DEFAULT_GUEST_PATH_ENV: &str = - "/usr/local/sbin:/usr/local/bin:/opt/agentos/bin:/usr/sbin:/usr/bin:/sbin:/bin"; -#[cfg(test)] -const KERNEL_COMMAND_STUB: &[u8] = b"#!/bin/sh\n# kernel command stub\n"; - -fn projected_command_guest_path(command: &str) -> String { - format!("{}/{command}", crate::package_projection::OPT_AGENTOS_BIN) -} - -fn projected_commands_from_guest_paths( - command_guest_paths: &BTreeMap, -) -> Vec { - command_guest_paths - .iter() - .filter(|(_, guest_path)| { - guest_path.starts_with(crate::package_projection::OPT_AGENTOS_BIN) - }) - .map(|(name, guest_path)| ProjectedCommand { - name: name.clone(), - guest_path: guest_path.clone(), - }) - .collect() -} -// --------------------------------------------------------------------------- -// NativeSidecar VM lifecycle methods -// --------------------------------------------------------------------------- - -impl NativeSidecar -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - pub(crate) async fn create_vm( - &mut self, - request: &crate::protocol::RequestFrame, - payload: crate::protocol::CreateVmRequest, - ) -> Result { - let __t = Instant::now(); - let (connection_id, session_id) = self.session_scope_for(&request.ownership)?; - self.require_owned_session(&connection_id, &session_id)?; - let create_config: vm_config::CreateVmConfig = serde_json::from_str(&payload.config) - .map_err(|error| { - SidecarError::InvalidState(format!("invalid create VM config JSON: {error}")) - })?; - create_config - .validate(self.config.max_frame_bytes) - .map_err(|error| { - SidecarError::InvalidState(format!("invalid create VM config: {error}")) - })?; - let root_filesystem = - root_filesystem_protocol_descriptor_from_config(&create_config.root_filesystem); - let permissions_policy = create_config - .permissions - .clone() - .unwrap_or_else(deny_all_policy); - validate_permissions_policy(&permissions_policy)?; - - self.next_vm_id += 1; - let vm_id = format!("vm-{}", self.next_vm_id); - let cwd = create_vm_shadow_root(&vm_id)?; - let (guest_cwd, host_cwd) = resolve_vm_cwds(create_config.cwd.as_ref(), &cwd)?; - fs::create_dir_all(&host_cwd) - .map_err(|error| SidecarError::Io(format!("failed to create VM cwd: {error}")))?; - let limits = crate::limits::vm_limits_from_config( - create_config.limits.as_ref(), - self.config.max_frame_bytes, - )?; - let resource_limits = limits.resources.clone(); - let dns = vm_dns_config_from_config(create_config.dns.as_ref())?; - let listen_policy = vm_listen_policy_from_config(create_config.listen.as_ref())?; - let create_loopback_exempt_ports: BTreeSet = create_config - .loopback_exempt_ports - .iter() - .copied() - .collect(); - self.bridge - .set_vm_permissions(&vm_id, &permissions_policy)?; - let permissions = bridge_permissions(self.bridge.clone(), &vm_id); - let mut guest_env = filter_env(&vm_id, &create_config.env, &permissions); - // Sidecar-owned bootstrap work still needs to reconcile command stubs and the root - // filesystem before the guest-visible policy takes effect. - self.bridge - .set_vm_permissions(&vm_id, &allow_all_policy())?; - let native_root = native_root_plugin_from_config(create_config.native_root.as_ref())?; - let loaded_snapshot = if native_root.is_some() { - None - } else { - self.bridge.with_mut(|bridge| { - bridge.load_filesystem_state(LoadFilesystemStateRequest { - vm_id: vm_id.clone(), - }) - })? - }; - if native_root.is_none() { - materialize_shadow_root_snapshot_entries( - &cwd, - &root_filesystem, - loaded_snapshot.as_ref(), - &resource_limits, - )?; - } - - let mut config = KernelVmConfig::new(vm_id.clone()); - config.cwd = guest_cwd.clone(); - config.env = guest_env.clone(); - config.permissions = permissions; - config.dns = secure_exec_kernel::dns::DnsConfig { - name_servers: dns.name_servers.clone(), - overrides: dns.overrides.clone(), - }; - config.loopback_exempt_ports = create_loopback_exempt_ports.clone(); - let root_mount_table = if let Some(native_root) = native_root.as_ref() { - build_native_root_mount_table( - &self.mount_plugins, - native_root, - &root_filesystem, - MountPluginContext { - bridge: self.bridge.clone(), - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - sidecar_requests: self.sidecar_requests.clone(), - max_pread_bytes: resource_limits.max_pread_bytes, - }, - )? - } else { - secure_exec_sidecar_core::build_root_mount_table_with_loaded_snapshot( - &create_config.root_filesystem, - loaded_snapshot.as_ref(), - &resource_limits, - ) - .map_err(|error| SidecarError::InvalidState(error.to_string()))? - }; - config.resources = resource_limits; - let mut kernel = KernelVm::new(root_mount_table, config); - let kernel_socket_readiness: KernelSocketReadinessRegistry = - Arc::new(Mutex::new(BTreeMap::new())); - let readiness_targets = Arc::clone(&kernel_socket_readiness); - kernel.set_socket_readiness_sink(Some(move |readiness: SocketReadiness| { - let target = readiness_targets - .lock() - .ok() - .and_then(|targets| targets.get(&readiness.socket_id).cloned()); - if let Some(target) = target { - send_kernel_socket_readiness_event(target, readiness); - } - })); - let command_guest_paths = discover_command_guest_paths(&mut kernel); - refresh_guest_command_path_env(&mut guest_env, &command_guest_paths); - let mut execution_commands = vec![ - String::from(JAVASCRIPT_COMMAND), - String::from(PYTHON_COMMAND), - // `python3` resolves to the same Pyodide runtime; register it so the - // guest shell can find `/bin/python3` on PATH (the command resolver - // already rewrites the alias to `python`). - String::from("python3"), - String::from(WASM_COMMAND), - ]; - if let Some(bootstrap_commands) = &create_config.bootstrap_commands { - execution_commands.extend(bootstrap_commands.iter().cloned()); - } - execution_commands.extend(command_guest_paths.keys().cloned()); - kernel - .register_driver(CommandDriver::new( - EXECUTION_DRIVER_NAME, - execution_commands, - )) - .map_err(kernel_error)?; - if let Some(root) = kernel.root_filesystem_mut() { - root.finish_bootstrap(); - } - self.bridge - .set_vm_permissions(&vm_id, &permissions_policy)?; - - self.bridge - .emit_lifecycle(&vm_id, LifecycleState::Starting)?; - self.bridge.emit_lifecycle(&vm_id, LifecycleState::Ready)?; - self.bridge.emit_log( - &vm_id, - format!("created VM {vm_id} for session {session_id}"), - )?; - - self.sessions - .get_mut(&session_id) - .expect("owned session should exist") - .vm_ids - .insert(vm_id.clone()); - self.vms.insert( - vm_id.clone(), - VmState { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - limits, - dns, - listen_policy, - create_loopback_exempt_ports, - guest_env, - requested_runtime: payload.runtime, - root_filesystem_mode: protocol_root_filesystem_mode(root_filesystem.mode), - guest_cwd, - cwd, - host_cwd, - kernel, - kernel_socket_readiness, - loaded_snapshot, - configuration: VmConfiguration { - permissions: permissions_policy, - js_runtime: create_config.js_runtime.clone(), - ..VmConfiguration::default() - }, - layers: VmLayerStore::default(), - command_guest_paths, - provided_commands: BTreeMap::new(), - command_permissions: BTreeMap::new(), - toolkits: BTreeMap::new(), - active_processes: BTreeMap::new(), - exited_process_snapshots: VecDeque::new(), - detached_child_processes: BTreeSet::new(), - signal_states: BTreeMap::new(), - packages_staging_root: None, - }, - ); - - let events = vec![ - self.vm_lifecycle_event( - &connection_id, - &session_id, - &vm_id, - VmLifecycleState::Creating, - ), - self.vm_lifecycle_event(&connection_id, &session_id, &vm_id, VmLifecycleState::Ready), - ]; - - tracing::info!(target: "secure_exec_sidecar::perf", phase = "create_vm", elapsed_ms = __t.elapsed().as_millis() as u64, "vm phase"); - Ok(DispatchResult { - response: vm_created_response(request, vm_id), - events, - }) - } - - pub(crate) async fn dispose_vm( - &mut self, - request: &crate::protocol::RequestFrame, - payload: crate::protocol::DisposeVmRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - let events = self - .dispose_vm_internal(&connection_id, &session_id, &vm_id, payload.reason) - .await?; - - Ok(DispatchResult { - response: vm_disposed_response(request, vm_id), - events, - }) - } - - pub(crate) async fn bootstrap_root_filesystem( - &mut self, - request: &crate::protocol::RequestFrame, - entries: Vec, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self.vms.get_mut(&vm_id).expect("owned VM should exist"); - let root = vm.kernel.root_filesystem_mut().ok_or_else(|| { - SidecarError::InvalidState(String::from("VM root filesystem is unavailable")) - })?; - for entry in &entries { - apply_root_filesystem_entry(root, entry)?; - } - - Ok(DispatchResult { - response: root_filesystem_bootstrapped_response(request, entries.len() as u32), - events: Vec::new(), - }) - } - - pub(crate) async fn configure_vm( - &mut self, - request: &crate::protocol::RequestFrame, - payload: ConfigureVmRequest, - ) -> Result { - let __t = Instant::now(); - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let mount_plugins = &self.mount_plugins; - let bridge = self.bridge.clone(); - let vm = self.vms.get_mut(&vm_id).expect("owned VM should exist"); - let max_pread_bytes = vm.kernel.resource_limits().max_pread_bytes; - let original_permissions = vm.configuration.permissions.clone(); - let configured_permissions = payload - .permissions - .clone() - .map(crate::wire::permissions_policy_config_from_wire) - .unwrap_or_else(|| original_permissions.clone()); - validate_permissions_policy(&configured_permissions)?; - bridge.set_vm_permissions(&vm_id, &allow_all_policy())?; - let mut effective_mounts = payload.mounts.clone(); - append_module_access_mount(&mut effective_mounts, payload.module_access_cwd.as_ref())?; - let package_descriptors = package_descriptors_from_wire(&payload.packages)?; - let mut provided_commands: BTreeMap> = BTreeMap::new(); - for descriptor in &package_descriptors { - provided_commands.insert( - descriptor.name.clone(), - descriptor - .commands - .iter() - .map(|target| target.command.clone()) - .collect(), - ); - } - let snapshot_userland_code = resolve_agent_snapshot_bundle(&package_descriptors)?; - let package_mounts = - build_packages_projection(&vm_id, &package_descriptors, &payload.packages_mount_at)?; - effective_mounts.extend(package_mounts); - apply_package_provides_env(&mut vm.guest_env, &package_descriptors); - append_package_provides_mounts(&mut effective_mounts, &package_descriptors)?; - let reconfigure_result = reconcile_mounts( - mount_plugins, - vm, - &effective_mounts, - MountPluginContext { - bridge: bridge.clone(), - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - sidecar_requests: self.sidecar_requests.clone(), - max_pread_bytes, - }, - ) - .and_then(|()| { - vm.command_guest_paths = discover_command_guest_paths(&mut vm.kernel); - // The `{ packageDir }` projection lands each package's `bin/` at - // `/opt/agentos/bin/` (on `$PATH`) but does NOT populate - // `/__secure_exec/commands`, so `discover_command_guest_paths` alone misses - // projected commands and every projected wasm/js command resolves to - // ENOEXEC (absolute path) / ENOENT (bare name). Register each projected - // command by name -> its `/opt/agentos/bin/` entrypoint so both the - // kernel command table (via `execution_commands` below) and the sidecar - // entrypoint resolver (`resolve_guest_command_entrypoint`) can find it. - for commands in provided_commands.values() { - for command in commands { - let entrypoint = - format!("{}/{command}", crate::package_projection::OPT_AGENTOS_BIN); - vm.command_guest_paths - .entry(command.clone()) - .or_insert(entrypoint); - } - } - refresh_guest_command_path_env(&mut vm.guest_env, &vm.command_guest_paths); - let mut execution_commands = - vec![String::from(JAVASCRIPT_COMMAND), String::from(WASM_COMMAND)]; - execution_commands.extend(payload.bootstrap_commands.iter().cloned()); - execution_commands.extend(payload.tool_shim_commands.iter().cloned()); - execution_commands.extend(vm.command_guest_paths.keys().cloned()); - vm.kernel - .register_driver(CommandDriver::new( - EXECUTION_DRIVER_NAME, - execution_commands, - )) - .map_err(kernel_error)?; - vm.command_permissions = payload.command_permissions.clone().into_iter().collect(); - let mut loopback_exempt_ports = vm.create_loopback_exempt_ports.clone(); - loopback_exempt_ports.extend(payload.loopback_exempt_ports.iter().copied()); - vm.kernel.set_loopback_exempt_ports(loopback_exempt_ports); - vm.configuration = VmConfiguration { - mounts: effective_mounts.clone(), - software: payload.software.clone(), - permissions: configured_permissions.clone(), - module_access_cwd: payload.module_access_cwd.clone(), - instructions: payload.instructions.clone(), - projected_modules: payload.projected_modules.clone(), - command_permissions: payload.command_permissions.clone().into_iter().collect(), - provided_commands: provided_commands.clone(), - // jsRuntime is create-time only; preserve what create_vm stored. - js_runtime: vm.configuration.js_runtime.clone(), - snapshot_userland_code: snapshot_userland_code.clone(), - loopback_exempt_ports: payload.loopback_exempt_ports.clone(), - }; - vm.provided_commands = provided_commands; - Ok(()) - }); - match reconfigure_result { - Ok(()) => { - bridge.set_vm_permissions(&vm_id, &configured_permissions)?; - } - Err(error) => { - match bridge.restore_vm_permissions_fail_closed( - &vm_id, - &original_permissions, - "configure_vm rollback", - &error, - ) { - Ok(()) => return Err(error), - Err(rollback_error) => { - self.vms - .get_mut(&vm_id) - .expect("owned VM should exist") - .configuration - .permissions = deny_all_policy(); - return Err(rollback_error); - } - } - } - } - - let applied_mounts = effective_mounts.len() as u32; - let configured_software = payload.software.len() as u32; - let projected_commands = projected_commands_from_guest_paths(&vm.command_guest_paths); - let agents = projected_agents_from_descriptors(&package_descriptors); - let _ = vm; - // Pre-warm the agent-SDK snapshot when a configured package opts in with - // `agent.snapshot`. The sidecar reads the bundle from the host package dir - // it already projects, so the first session is warm without shipping the - // source over the client wire. - if let Some(userland) = snapshot_userland_code { - let _ = tokio::task::spawn_blocking(move || { - if let Err(error) = - secure_exec_execution::v8_host::pre_warm_agent_snapshot(&userland) - { - eprintln!("agent snapshot pre-warm failed: {error}"); - } - }) - .await; - } - - tracing::info!(target: "secure_exec_sidecar::perf", phase = "configure_vm", elapsed_ms = __t.elapsed().as_millis() as u64, applied_mounts = applied_mounts as u64, "vm phase"); - Ok(DispatchResult { - response: vm_configured_response( - request, - applied_mounts, - configured_software, - projected_commands, - agents, - ), - events: Vec::new(), - }) - } - - /// Runtime dynamic `linkSoftware`: add one package's tar/current/bin leaf - /// mounts to the live VM so commands appear under `/opt/agentos/bin` - /// immediately, with no reboot. Returns the linked command names. - pub(crate) async fn link_package( - &mut self, - request: &crate::protocol::RequestFrame, - payload: LinkPackageRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self.vms.get_mut(&vm_id).expect("owned VM should exist"); - let descriptor = crate::package_projection::read_package_manifest_from_ref( - payload.package.dir.as_deref(), - payload.package.tar.as_deref(), - )?; - let new_mounts = build_packages_projection( - &vm_id, - std::slice::from_ref(&descriptor), - crate::package_projection::OPT_AGENTOS_ROOT, - )?; - for mount in &new_mounts { - if vm - .configuration - .mounts - .iter() - .any(|existing| existing.guest_path == mount.guest_path) - { - return Err(SidecarError::InvalidState(format!( - "agentos package mount already exists at {}", - mount.guest_path - ))); - } - } - let mount_context = MountPluginContext { - bridge: self.bridge.clone(), - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - sidecar_requests: self.sidecar_requests.clone(), - max_pread_bytes: vm.kernel.resource_limits().max_pread_bytes, - }; - mount_leaf_descriptors(&self.mount_plugins, vm, &new_mounts, mount_context)?; - vm.configuration.mounts.extend(new_mounts); - - let commands = descriptor - .commands - .iter() - .map(|target| target.command.clone()) - .collect::>(); - vm.provided_commands - .insert(descriptor.name.clone(), commands.clone()); - vm.configuration - .provided_commands - .insert(descriptor.name.clone(), commands.clone()); - for command in &commands { - let entrypoint = projected_command_guest_path(command); - vm.command_guest_paths - .entry(command.clone()) - .or_insert(entrypoint); - } - refresh_guest_command_path_env(&mut vm.guest_env, &vm.command_guest_paths); - let mut execution_commands = - vec![String::from(JAVASCRIPT_COMMAND), String::from(WASM_COMMAND)]; - execution_commands.extend(vm.command_guest_paths.keys().cloned()); - vm.kernel - .register_driver(CommandDriver::new( - EXECUTION_DRIVER_NAME, - execution_commands, - )) - .map_err(kernel_error)?; - let projected_commands = commands - .iter() - .map(|command| ProjectedCommand { - name: command.clone(), - guest_path: projected_command_guest_path(command), - }) - .collect(); - let agents = projected_agents_from_descriptors(std::slice::from_ref(&descriptor)); - - Ok(DispatchResult { - response: package_linked_response(request, projected_commands, agents), - events: Vec::new(), - }) - } - - pub(crate) async fn provided_commands( - &mut self, - request: &crate::protocol::RequestFrame, - _payload: ProvidedCommandsRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let packages = self - .vms - .get(&vm_id) - .map(|vm| { - vm.provided_commands - .iter() - .map(|(package_name, commands)| PackageCommands { - package_name: package_name.clone(), - commands: commands.clone(), - }) - .collect() - }) - .unwrap_or_default(); - - Ok(DispatchResult { - response: provided_commands_response(request, packages), - events: Vec::new(), - }) - } - - pub(crate) async fn create_layer( - &mut self, - request: &crate::protocol::RequestFrame, - _payload: CreateLayerRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self.vms.get_mut(&vm_id).expect("owned VM should exist"); - let layer_id = vm - .layers - .create_writable_layer() - .map_err(sidecar_core_error)?; - - Ok(DispatchResult { - response: layer_created_response(request, layer_id), - events: Vec::new(), - }) - } - - pub(crate) async fn seal_layer( - &mut self, - request: &crate::protocol::RequestFrame, - payload: SealLayerRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self.vms.get_mut(&vm_id).expect("owned VM should exist"); - let layer_id = vm - .layers - .seal_layer(&payload.layer_id) - .map_err(sidecar_core_error)?; - - Ok(DispatchResult { - response: layer_sealed_response(request, layer_id), - events: Vec::new(), - }) - } - - pub(crate) async fn import_snapshot( - &mut self, - request: &crate::protocol::RequestFrame, - payload: ImportSnapshotRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self.vms.get_mut(&vm_id).expect("owned VM should exist"); - let layer_id = vm - .layers - .import_snapshot(root_snapshot_from_entries(&payload.entries)?) - .map_err(sidecar_core_error)?; - - Ok(DispatchResult { - response: snapshot_imported_response(request, layer_id), - events: Vec::new(), - }) - } - - pub(crate) async fn export_snapshot( - &mut self, - request: &crate::protocol::RequestFrame, - payload: ExportSnapshotRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self.vms.get_mut(&vm_id).expect("owned VM should exist"); - let snapshot = vm - .layers - .export_snapshot(&payload.layer_id) - .map_err(sidecar_core_error)?; - - Ok(DispatchResult { - response: snapshot_exported_response( - request, - payload.layer_id, - root_snapshot_entries(&snapshot), - ), - events: Vec::new(), - }) - } - - pub(crate) async fn create_overlay( - &mut self, - request: &crate::protocol::RequestFrame, - payload: CreateOverlayRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self.vms.get_mut(&vm_id).expect("owned VM should exist"); - let layer_id = vm - .layers - .create_overlay_layer( - protocol_root_filesystem_mode(payload.mode), - payload.upper_layer_id, - payload.lower_layer_ids, - ) - .map_err(sidecar_core_error)?; - - Ok(DispatchResult { - response: overlay_created_response(request, layer_id), - events: Vec::new(), - }) - } - - pub(crate) async fn snapshot_root_filesystem( - &mut self, - request: &crate::protocol::RequestFrame, - _payload: SnapshotRootFilesystemRequest, - ) -> Result { - let (connection_id, session_id, vm_id) = self.vm_scope_for(&request.ownership)?; - self.require_owned_vm(&connection_id, &session_id, &vm_id)?; - - let vm = self.vms.get_mut(&vm_id).expect("owned VM should exist"); - let snapshot = vm.kernel.snapshot_root_filesystem().map_err(kernel_error)?; - - Ok(DispatchResult { - response: root_filesystem_snapshot_response( - request, - snapshot.entries.iter().map(root_snapshot_entry).collect(), - ), - events: Vec::new(), - }) - } - - pub(crate) async fn dispose_vm_internal( - &mut self, - connection_id: &str, - session_id: &str, - vm_id: &str, - _reason: DisposeReason, - ) -> Result, SidecarError> { - self.require_owned_vm(connection_id, session_id, vm_id)?; - - let mut events = vec![self.vm_lifecycle_event( - connection_id, - session_id, - vm_id, - VmLifecycleState::Disposing, - )]; - // Process termination needs the VM live in `self.vms` (it looks up and - // signals the VM's active processes). Capture its result but keep tearing - // down: a process that refuses to die must not strand the VM's tracking - // entries for the process lifetime. - let terminate_result = self.terminate_vm_processes(vm_id, &mut events).await; - - // Detach the VM from `self.vms` BEFORE the remaining fallible teardown so - // no `?` below can leave the registry entry (or any per-VM map) behind. - let mut vm = self - .vms - .remove(vm_id) - .expect("owned VM should exist before disposal"); - - // `continue_on_error = true` => `shutdown_configured_mounts` never returns - // `Err` on the dispose path (it logs and presses on), so its result is - // intentionally discarded rather than `?`-ed. - let mount_context = MountPluginContext { - bridge: self.bridge.clone(), - connection_id: connection_id.to_owned(), - session_id: session_id.to_owned(), - vm_id: vm_id.to_owned(), - sidecar_requests: self.sidecar_requests.clone(), - max_pread_bytes: vm.kernel.resource_limits().max_pread_bytes, - }; - let _ = shutdown_configured_mounts(&mut vm, &mount_context, "dispose_vm", true); - - // Snapshot/flush/kernel-dispose/permission-reset can each fail; run them - // in a helper whose result is captured so cleanup below is unconditional. - let teardown_result = self.finish_vm_teardown(vm_id, &mut vm).await; - - // Reclaim EVERY per-VM tracking entry on EVERY exit path — even when a - // teardown step above errored. Pre-fix these ran only after the fallible - // steps' `?`, so any failure stranded the engine/extension maps (H1) and - // the output-buffer map was never reclaimed at all (M6). - self.reclaim_vm_tracking(session_id, vm_id); - let _ = fs::remove_dir_all(&vm.cwd); - if let Some(staging_root) = vm.packages_staging_root.take() { - let _ = fs::remove_dir_all(&staging_root); - } - - // Surface the first failure only AFTER cleanup has completed. - terminate_result?; - teardown_result?; - - events.push(self.vm_lifecycle_event( - connection_id, - session_id, - vm_id, - VmLifecycleState::Disposed, - )); - Ok(events) - } - - /// Run the fallible second half of VM disposal (root-filesystem snapshot + - /// flush, lifecycle event, kernel dispose, permission reset) against a VM - /// that has already been detached from `self.vms`. Kept separate so its - /// `?`-propagated errors are captured by the caller and the per-VM tracking - /// maps are still reclaimed afterward. - async fn finish_vm_teardown( - &mut self, - vm_id: &str, - vm: &mut VmState, - ) -> Result<(), SidecarError> { - let snapshot = if vm.kernel.root_filesystem_mut().is_some() { - Some(FilesystemSnapshot { - format: String::from(ROOT_FILESYSTEM_SNAPSHOT_FORMAT), - bytes: encode_root_snapshot( - &vm.kernel.snapshot_root_filesystem().map_err(kernel_error)?, - ) - .map_err(root_filesystem_error)?, - }) - } else { - None - }; - - self.bridge - .emit_lifecycle(vm_id, LifecycleState::Terminated)?; - vm.kernel.dispose().map_err(kernel_error)?; - if let Some(snapshot) = snapshot { - self.bridge.with_mut(|bridge| { - bridge.flush_filesystem_state(FlushFilesystemStateRequest { - vm_id: vm_id.to_owned(), - snapshot, - }) - })?; - } - self.bridge.clear_vm_permissions(vm_id)?; - Ok(()) - } - - pub(crate) async fn terminate_vm_processes( - &mut self, - vm_id: &str, - events: &mut Vec, - ) -> Result<(), SidecarError> { - let process_ids = self - .vms - .get(vm_id) - .map(|vm| vm.active_processes.keys().cloned().collect::>()) - .unwrap_or_default(); - if process_ids.is_empty() { - return Ok(()); - } - - for process_id in process_ids { - if self - .vms - .get(vm_id) - .is_some_and(|vm| vm.active_processes.contains_key(&process_id)) - { - self.kill_process_internal(vm_id, &process_id, "SIGTERM")?; - } - } - self.wait_for_vm_processes_to_exit(vm_id, DISPOSE_VM_SIGTERM_GRACE, events) - .await?; - - if !self.vm_has_active_processes(vm_id) { - return Ok(()); - } - - let remaining = self - .vms - .get(vm_id) - .map(|vm| vm.active_processes.keys().cloned().collect::>()) - .unwrap_or_default(); - for process_id in remaining { - if self - .vms - .get(vm_id) - .is_some_and(|vm| vm.active_processes.contains_key(&process_id)) - { - self.kill_process_internal(vm_id, &process_id, "SIGKILL")?; - } - } - self.wait_for_vm_processes_to_exit(vm_id, DISPOSE_VM_SIGKILL_GRACE, events) - .await?; - - if self.vm_has_active_processes(vm_id) { - return Err(SidecarError::Execution(format!( - "failed to terminate active guest executions for VM {vm_id}" - ))); - } - - Ok(()) - } - - pub(crate) async fn wait_for_vm_processes_to_exit( - &mut self, - vm_id: &str, - timeout: Duration, - events: &mut Vec, - ) -> Result<(), SidecarError> { - let ownership = self.vm_ownership(vm_id)?; - let deadline = Instant::now() + timeout; - - while self.vm_has_active_processes(vm_id) && Instant::now() < deadline { - let remaining = deadline.saturating_duration_since(Instant::now()); - if let Some(event) = self - .poll_event(&ownership, remaining.min(Duration::from_millis(10))) - .await? - { - events.push(event); - } - } - - Ok(()) - } -} - -// --------------------------------------------------------------------------- -// Free functions — VM lifecycle helpers -// --------------------------------------------------------------------------- - -fn native_root_plugin_from_config( - config: Option<&vm_config::NativeRootFilesystemConfig>, -) -> Result, SidecarError> { - let Some(config) = config else { - return Ok(None); - }; - let plugin_config = serde_json::to_string(&config.plugin.config).map_err(|error| { - SidecarError::InvalidState(format!( - "failed to serialize nativeRoot.plugin.config: {error}" - )) - })?; - Ok(Some(NativeRootPluginConfig { - plugin: MountPluginDescriptor { - id: config.plugin.id.clone(), - config: plugin_config, - }, - read_only: config.read_only, - })) -} - -fn vm_dns_config_from_config( - config: Option<&vm_config::VmDnsConfig>, -) -> Result { - let Some(config) = config else { - return Ok(VmDnsConfig::default()); - }; - let name_servers = config - .name_servers - .iter() - .map(|entry| parse_vm_dns_nameserver(entry)) - .collect::, _>>()?; - let mut overrides = BTreeMap::new(); - for (hostname, addresses) in &config.overrides { - let normalized_hostname = normalize_dns_hostname(hostname)?; - let parsed_addresses = addresses - .iter() - .map(|entry| { - entry.parse::().map_err(|error| { - SidecarError::InvalidState(format!( - "invalid DNS override {hostname}={entry}: {error}" - )) - }) - }) - .collect::, _>>()?; - overrides.insert(normalized_hostname, parsed_addresses); - } - Ok(VmDnsConfig { - name_servers, - overrides, - }) -} - -fn vm_listen_policy_from_config( - config: Option<&vm_config::VmListenPolicyConfig>, -) -> Result { - let mut policy = VmListenPolicy::default(); - let Some(config) = config else { - return Ok(policy); - }; - if let Some(port_min) = config.port_min { - policy.port_min = port_min; - } - if let Some(port_max) = config.port_max { - policy.port_max = port_max; - } - if policy.port_min > policy.port_max { - return Err(SidecarError::InvalidState(format!( - "invalid listen port range {} exceeds {}", - policy.port_min, policy.port_max - ))); - } - if let Some(allow_privileged) = config.allow_privileged { - policy.allow_privileged = allow_privileged; - } - Ok(policy) -} - -#[derive(Debug, Clone)] -struct NativeRootPluginConfig { - plugin: MountPluginDescriptor, - read_only: bool, -} - -fn build_native_root_mount_table( - mount_plugins: &secure_exec_kernel::mount_plugin::FileSystemPluginRegistry< - MountPluginContext, - >, - native_root: &NativeRootPluginConfig, - descriptor: &RootFilesystemDescriptor, - context: MountPluginContext, -) -> Result -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - if !descriptor.lowers.is_empty() { - return Err(SidecarError::InvalidState(String::from( - "native root filesystems do not support rootFilesystem.lowers", - ))); - } - - let config_value: serde_json::Value = serde_json::from_str(&native_root.plugin.config) - .map_err(|error| { - SidecarError::InvalidState(format!( - "root native plugin config for {} is not valid JSON: {error}", - native_root.plugin.id - )) - })?; - let mut filesystem = mount_plugins - .open( - &native_root.plugin.id, - OpenFileSystemPluginRequest { - vm_id: &context.vm_id, - guest_path: "/", - read_only: native_root.read_only, - config: &config_value, - context: &context, - }, - ) - .map_err(plugin_error)?; - - bootstrap_native_root_filesystem(filesystem.as_mut(), descriptor)?; - - Ok(MountTable::new_boxed_root( - filesystem, - MountOptions::new(native_root.plugin.id.clone()).read_only(native_root.read_only), - )) -} - -fn bootstrap_native_root_filesystem( - filesystem: &mut dyn MountedFileSystem, - descriptor: &RootFilesystemDescriptor, -) -> Result<(), SidecarError> { - for (guest_path, mode) in SHADOW_ROOT_BOOTSTRAP_DIRS { - filesystem.mkdir(guest_path, true).map_err(vfs_error)?; - filesystem.chmod(guest_path, *mode).map_err(vfs_error)?; - } - - for entry in &descriptor.bootstrap_entries { - apply_native_root_filesystem_entry(filesystem, entry)?; - } - - Ok(()) -} - -fn apply_native_root_filesystem_entry( - filesystem: &mut dyn MountedFileSystem, - entry: &RootFilesystemEntry, -) -> Result<(), SidecarError> { - let snapshot = root_snapshot_from_entries(std::slice::from_ref(entry))?; - let kernel_entry = snapshot - .entries - .into_iter() - .next() - .expect("root snapshot from one entry should contain one entry"); - ensure_mounted_parent_directories(filesystem, &kernel_entry.path)?; - - match kernel_entry.kind { - KernelFilesystemEntryKind::Directory => filesystem - .mkdir(&kernel_entry.path, true) - .map_err(vfs_error)?, - KernelFilesystemEntryKind::File => filesystem - .write_file(&kernel_entry.path, kernel_entry.content.unwrap_or_default()) - .map_err(vfs_error)?, - KernelFilesystemEntryKind::Symlink => filesystem - .symlink( - kernel_entry.target.as_deref().ok_or_else(|| { - SidecarError::InvalidState(format!( - "root filesystem bootstrap for symlink {} requires a target", - entry.path - )) - })?, - &kernel_entry.path, - ) - .map_err(vfs_error)?, - } - - if !matches!(kernel_entry.kind, KernelFilesystemEntryKind::Symlink) { - filesystem - .chmod(&kernel_entry.path, kernel_entry.mode) - .map_err(vfs_error)?; - filesystem - .chown(&kernel_entry.path, kernel_entry.uid, kernel_entry.gid) - .map_err(vfs_error)?; - } - - Ok(()) -} - -fn ensure_mounted_parent_directories( - filesystem: &mut dyn MountedFileSystem, - path: &str, -) -> Result<(), SidecarError> { - let parent = dirname(path); - if parent != "/" && !filesystem.exists(&parent) { - ensure_mounted_parent_directories(filesystem, &parent)?; - filesystem.mkdir(&parent, true).map_err(vfs_error)?; - } - Ok(()) -} - -fn reconcile_mounts( - mount_plugins: &secure_exec_kernel::mount_plugin::FileSystemPluginRegistry< - MountPluginContext, - >, - vm: &mut VmState, - mounts: &[crate::protocol::MountDescriptor], - context: MountPluginContext, -) -> Result<(), SidecarError> -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - shutdown_configured_mounts(vm, &context, "configure_vm", false)?; - mount_leaf_descriptors(mount_plugins, vm, mounts, context) -} - -fn mount_leaf_descriptors( - mount_plugins: &secure_exec_kernel::mount_plugin::FileSystemPluginRegistry< - MountPluginContext, - >, - vm: &mut VmState, - mounts: &[crate::protocol::MountDescriptor], - context: MountPluginContext, -) -> Result<(), SidecarError> -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - for mount in mounts { - let config_value: serde_json::Value = - serde_json::from_str(&mount.plugin.config).map_err(|error| { - SidecarError::InvalidState(format!( - "mount plugin config for {} is not valid JSON: {error}", - mount.plugin.id - )) - })?; - let filesystem = mount_plugins - .open( - &mount.plugin.id, - OpenFileSystemPluginRequest { - vm_id: &context.vm_id, - guest_path: &mount.guest_path, - read_only: mount.read_only, - config: &config_value, - context: &context, - }, - ) - .map_err(plugin_error)?; - - vm.kernel - .mount_boxed_filesystem( - &mount.guest_path, - filesystem, - MountOptions::new(mount.plugin.id.clone()).read_only(mount.read_only), - ) - .map_err(kernel_error)?; - emit_security_audit_event( - &context.bridge, - &context.vm_id, - "security.mount.mounted", - audit_fields([ - (String::from("guest_path"), mount.guest_path.clone()), - (String::from("plugin_id"), mount.plugin.id.clone()), - (String::from("read_only"), mount.read_only.to_string()), - ]), - ); - } - - Ok(()) -} - -fn shutdown_configured_mounts( - vm: &mut VmState, - context: &MountPluginContext, - phase: &str, - continue_on_error: bool, -) -> Result<(), SidecarError> -where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, -{ - for existing in vm.configuration.mounts.clone() { - match vm.kernel.unmount_filesystem(&existing.guest_path) { - Ok(()) => emit_security_audit_event( - &context.bridge, - &context.vm_id, - "security.mount.unmounted", - audit_fields([ - (String::from("guest_path"), existing.guest_path.clone()), - (String::from("plugin_id"), existing.plugin.id.clone()), - (String::from("read_only"), existing.read_only.to_string()), - ]), - ), - Err(error) if error.code() == "EINVAL" => {} - Err(error) => { - let _ = emit_structured_event( - &context.bridge, - &context.vm_id, - "filesystem.mount.shutdown_failed", - audit_fields([ - (String::from("guest_path"), existing.guest_path.clone()), - (String::from("plugin_id"), existing.plugin.id.clone()), - (String::from("read_only"), existing.read_only.to_string()), - (String::from("phase"), String::from(phase)), - (String::from("error_code"), String::from(error.code())), - (String::from("error"), error.to_string()), - ]), - ); - - if !continue_on_error { - return Err(kernel_error(error)); - } - } - } - } - - Ok(()) -} - -/// Build the `/opt/agentos` package projection for `configure_vm`. -/// -/// The projection mounts the package tar directly and serves derived aliases as -/// synthetic symlink leaves. This eliminates extraction and the old host-disk -/// symlink farm: the tar VFS indexes member offsets once and reads mmap-backed -/// byte ranges. Each managed entry is a granular leaf mount, while parent dirs -/// such as `/opt/agentos/bin` and `/opt/agentos/pkgs/` remain writable -/// overlay dirs so guest-installed commands can coexist beside managed entries. -fn build_packages_projection( - _vm_id: &str, - packages: &[crate::package_projection::PackageDescriptor], - mount_at: &str, -) -> Result, SidecarError> { - Ok( - crate::package_projection::build_package_leaf_mounts(packages, mount_at)? - .into_iter() - .map(package_leaf_mount_to_descriptor) - .collect(), - ) -} - -fn package_leaf_mount_to_descriptor( - mount: crate::package_projection::PackageLeafMount, -) -> MountDescriptor { - match mount { - crate::package_projection::PackageLeafMount::Tar { - guest_path, - tar_path, - digest, - root, - } => MountDescriptor { - guest_path, - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("agentos_packages"), - config: serde_json::json!({ - "kind": "tar", - "tarPath": tar_path, - "digest": digest, - "root": root, - "readOnly": true, - }) - .to_string(), - }, - }, - crate::package_projection::PackageLeafMount::SingleSymlink { guest_path, target } => { - MountDescriptor { - guest_path, - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("agentos_packages"), - config: serde_json::json!({ - "kind": "singleSymlink", - "target": target, - "readOnly": true, - }) - .to_string(), - }, - } - } - } -} - -fn package_descriptors_from_wire( - packages: &[crate::protocol::PackageDescriptor], -) -> Result, SidecarError> { - packages - .iter() - .map(|package| { - crate::package_projection::read_package_manifest_from_ref( - package.dir.as_deref(), - package.tar.as_deref(), - ) - }) - .collect() -} - -fn projected_agents_from_descriptors( - packages: &[crate::package_projection::PackageDescriptor], -) -> Vec { - packages - .iter() - .flat_map(|package| { - let Some(acp_entrypoint) = package.acp_entrypoint.as_ref() else { - return Vec::new(); - }; - let mut ids = vec![package.name.clone()]; - if let Ok(package_json_name) = - crate::package_projection::read_package_name(&package.dir) - { - if package_json_name != package.name { - ids.push(package_json_name); - } - } - ids.into_iter() - .map(|id| AgentosProjectedAgent { - id, - acp_entrypoint: acp_entrypoint.clone(), - adapter_entrypoint: format!( - "{}/{}", - crate::package_projection::OPT_AGENTOS_BIN, - acp_entrypoint - ), - }) - .collect::>() - }) - .collect() -} - -fn resolve_agent_snapshot_bundle( - packages: &[crate::package_projection::PackageDescriptor], -) -> Result, SidecarError> { - for package in packages { - if let Some(bundle) = crate::package_projection::read_agent_snapshot_bundle(package)? { - return Ok(Some(bundle)); - } - } - Ok(None) -} - -fn apply_package_provides_env( - guest_env: &mut BTreeMap, - packages: &[crate::package_projection::PackageDescriptor], -) { - for package in packages { - let Some(provides) = package.provides.as_ref() else { - continue; - }; - for (key, value) in &provides.env { - guest_env - .entry(key.clone()) - .or_insert_with(|| value.clone()); - } - } -} - -fn append_package_provides_mounts( - mounts: &mut Vec, - packages: &[crate::package_projection::PackageDescriptor], -) -> Result<(), SidecarError> { - for package in packages { - let Some(provides) = package.provides.as_ref() else { - continue; - }; - for file in &provides.files { - match crate::package_projection::package_provides_file_mount( - package, - &file.source, - &file.target, - )? { - Some(mount) => mounts.push(package_leaf_mount_to_descriptor(mount)), - None => { - tracing::warn!( - package = %package.name, - source = %file.source, - target = %file.target, - "package provides file source is not a directory; skipping" - ); - } - } - } - } - Ok(()) -} - -fn append_module_access_mount( - mounts: &mut Vec, - module_access_cwd: Option<&String>, -) -> Result<(), SidecarError> { - if mounts - .iter() - .any(|mount| mount.guest_path == "/root/node_modules") - { - return Ok(()); - } - - let Some(module_access_cwd) = module_access_cwd else { - return Ok(()); - }; - let root = resolve_host_path(Some(module_access_cwd))?.join("node_modules"); - if !root.is_dir() { - return Ok(()); - } - - mounts.push(MountDescriptor { - guest_path: String::from("/root/node_modules"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("module_access"), - config: serde_json::json!({ - "hostPath": root, - }) - .to_string(), - }, - }); - append_module_access_symlink_mounts(mounts, &root)?; - Ok(()) -} - -fn append_module_access_symlink_mounts( - mounts: &mut Vec, - node_modules_root: &Path, -) -> Result<(), SidecarError> { - for entry in fs::read_dir(node_modules_root) - .map_err(|error| SidecarError::Io(format!("failed to read module_access root: {error}")))? - { - let entry = entry.map_err(|error| { - SidecarError::Io(format!("failed to inspect module_access root: {error}")) - })?; - let file_name = entry.file_name(); - let name = file_name.to_string_lossy(); - if name.starts_with('.') { - continue; - } - let path = entry.path(); - let metadata = fs::symlink_metadata(&path).map_err(|error| { - SidecarError::Io(format!("failed to stat module_access entry: {error}")) - })?; - if metadata.file_type().is_symlink() { - append_module_access_symlink_mount( - mounts, - &format!("/root/node_modules/{name}"), - &path, - )?; - continue; - } - if !metadata.is_dir() || !name.starts_with('@') { - continue; - } - for scoped_entry in fs::read_dir(&path).map_err(|error| { - SidecarError::Io(format!("failed to read module_access scope: {error}")) - })? { - let scoped_entry = scoped_entry.map_err(|error| { - SidecarError::Io(format!("failed to inspect module_access scope: {error}")) - })?; - let scoped_name = scoped_entry.file_name().to_string_lossy().into_owned(); - if scoped_name.starts_with('.') { - continue; - } - let scoped_path = scoped_entry.path(); - let scoped_metadata = fs::symlink_metadata(&scoped_path).map_err(|error| { - SidecarError::Io(format!( - "failed to stat module_access scoped entry: {error}" - )) - })?; - if scoped_metadata.file_type().is_symlink() { - append_module_access_symlink_mount( - mounts, - &format!("/root/node_modules/{name}/{scoped_name}"), - &scoped_path, - )?; - } - } - } - - Ok(()) -} - -fn append_module_access_symlink_mount( - mounts: &mut Vec, - guest_path: &str, - symlink_path: &Path, -) -> Result<(), SidecarError> { - if mounts.iter().any(|mount| mount.guest_path == guest_path) { - return Ok(()); - } - - let target = fs::canonicalize(symlink_path).map_err(|error| { - SidecarError::Io(format!( - "failed to resolve module_access package symlink {}: {error}", - symlink_path.display() - )) - })?; - if !target.is_dir() { - return Ok(()); - } - - mounts.push(MountDescriptor { - guest_path: guest_path.to_owned(), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: serde_json::json!({ - "hostPath": target, - "readOnly": true, - }) - .to_string(), - }, - }); - Ok(()) -} - -fn sidecar_core_error(error: secure_exec_sidecar_core::SidecarCoreError) -> SidecarError { - SidecarError::InvalidState(error.to_string()) -} - -fn resolve_guest_cwd(value: Option<&String>) -> String { - value - .map(|path| normalize_guest_path(path)) - .unwrap_or_else(|| String::from("/workspace")) -} - -fn resolve_vm_cwds( - metadata_cwd: Option<&String>, - shadow_root: &Path, -) -> Result<(String, PathBuf), SidecarError> { - if let Some(raw_cwd) = metadata_cwd { - let candidate = PathBuf::from(raw_cwd); - if candidate.is_absolute() || raw_cwd.starts_with('.') { - let resolved_host_cwd = resolve_host_path(Some(raw_cwd))?; - return Ok((String::from("/"), resolved_host_cwd)); - } - } - - let guest_cwd = resolve_guest_cwd(metadata_cwd); - let host_cwd = shadow_path_for_guest(shadow_root, &guest_cwd); - Ok((guest_cwd, host_cwd)) -} - -fn resolve_host_path(value: Option<&String>) -> Result { - match value { - Some(path) => { - let cwd = PathBuf::from(path); - let resolved = if cwd.is_absolute() { - cwd - } else { - std::env::current_dir() - .map_err(|error| { - SidecarError::Io(format!("failed to resolve current directory: {error}")) - })? - .join(cwd) - }; - Ok(resolved) - } - None => std::env::current_dir().map_err(|error| { - SidecarError::Io(format!("failed to resolve current directory: {error}")) - }), - } -} - -fn create_vm_shadow_root(vm_id: &str) -> Result { - let nonce = SystemTime::now() - .duration_since(UNIX_EPOCH) - .map_err(|error| SidecarError::Io(format!("failed to compute shadow-root nonce: {error}")))? - .as_nanos(); - let root = std::env::temp_dir().join(format!("secure-exec-sidecar-shadow-{vm_id}-{nonce}")); - fs::create_dir_all(&root) - .map_err(|error| SidecarError::Io(format!("failed to create VM shadow root: {error}")))?; - // macOS: `std::env::temp_dir()` lives under `/var/folders/…`, but `/var` is a - // symlink to `/private/var`, and macOS fd→path recovery (`fcntl(F_GETPATH)`) - // reports the resolved `/private/var/…` form. Canonicalize the shadow root up - // front so the stored host-root matches those resolved paths; otherwise the - // mapped-runtime confinement prefix checks (`strip_prefix(host_root)`) reject - // every child and guest `readdir` of a populated dir returns empty. host_dir - // mounts already canonicalize their root for the same reason. - #[cfg(target_os = "macos")] - let root = fs::canonicalize(&root).map_err(|error| { - SidecarError::Io(format!("failed to canonicalize VM shadow root: {error}")) - })?; - bootstrap_shadow_root(&root)?; - Ok(root) -} - -fn bootstrap_shadow_root(root: &Path) -> Result<(), SidecarError> { - for (guest_path, mode) in SHADOW_ROOT_BOOTSTRAP_DIRS { - let host_path = shadow_path_for_guest(root, guest_path); - fs::create_dir_all(&host_path).map_err(|error| { - SidecarError::Io(format!( - "failed to create shadow directory {}: {error}", - host_path.display() - )) - })?; - fs::set_permissions(&host_path, fs::Permissions::from_mode(*mode)).map_err(|error| { - SidecarError::Io(format!( - "failed to set shadow directory mode {mode:o} on {}: {error}", - host_path.display() - )) - })?; - } - Ok(()) -} - -fn materialize_shadow_root_snapshot_entries( - shadow_root: &Path, - descriptor: &RootFilesystemDescriptor, - loaded_snapshot: Option<&FilesystemSnapshot>, - resource_limits: &ResourceLimits, -) -> Result<(), SidecarError> { - let import_limits = RootFilesystemImportLimits::from_resource_limits(resource_limits); - if let Some(snapshot) = loaded_snapshot - .filter(|snapshot| is_supported_root_filesystem_snapshot_format(&snapshot.format)) - .map(|snapshot| { - decode_snapshot_with_import_limits(&snapshot.bytes, &import_limits) - .map_err(root_filesystem_error) - }) - .transpose()? - { - return materialize_shadow_entries(shadow_root, &root_snapshot_entries(&snapshot)); - } - - validate_shadow_descriptor_import_limits(descriptor, &import_limits)?; - for lower in &descriptor.lowers { - if let RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower(inner) = lower { - materialize_shadow_entries(shadow_root, &inner.entries)?; - } - } - materialize_shadow_entries(shadow_root, &descriptor.bootstrap_entries)?; - Ok(()) -} - -fn validate_shadow_descriptor_import_limits( - descriptor: &RootFilesystemDescriptor, - limits: &RootFilesystemImportLimits, -) -> Result<(), SidecarError> { - let mut explicit_entry_count = descriptor.bootstrap_entries.len(); - let mut inode_paths = BTreeSet::new(); - collect_root_protocol_entry_paths(&descriptor.bootstrap_entries, &mut inode_paths); - let mut bytes = root_protocol_entry_content_bytes(&descriptor.bootstrap_entries)?; - - for lower in &descriptor.lowers { - match lower { - RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower(inner) => { - let entries = &inner.entries; - explicit_entry_count = explicit_entry_count.saturating_add(entries.len()); - collect_root_protocol_entry_paths(entries, &mut inode_paths); - bytes = bytes.saturating_add(root_protocol_entry_content_bytes(entries)?); - } - RootFilesystemLowerDescriptor::BundledBaseFilesystemLower => {} - } - } - - if let Some(limit) = limits.max_inode_count { - if explicit_entry_count > limit { - return Err(root_filesystem_error(format!( - "root filesystem descriptor contains {explicit_entry_count} entries, exceeding limit {limit}" - ))); - } - - let entry_count = inode_paths.len(); - if entry_count > limit { - return Err(root_filesystem_error(format!( - "root filesystem descriptor contains {entry_count} entries, exceeding limit {limit}" - ))); - } - } - - if let Some(limit) = limits.max_filesystem_bytes { - if bytes > limit { - return Err(root_filesystem_error(format!( - "root filesystem descriptor contains {bytes} bytes, exceeding limit {limit}" - ))); - } - } - - Ok(()) -} - -fn collect_root_protocol_entry_paths( - entries: &[RootFilesystemEntry], - paths: &mut BTreeSet, -) { - for entry in entries { - collect_root_protocol_path(&entry.path, paths); - } -} - -fn collect_root_protocol_path(path: &str, paths: &mut BTreeSet) { - let normalized = normalize_guest_path(path); - paths.insert(normalized.clone()); - - let mut parent = String::new(); - let segments = normalized - .split('/') - .filter(|segment| !segment.is_empty()) - .collect::>(); - for segment in segments.iter().take(segments.len().saturating_sub(1)) { - parent.push('/'); - parent.push_str(segment); - paths.insert(parent.clone()); - } -} - -fn root_protocol_entry_content_bytes(entries: &[RootFilesystemEntry]) -> Result { - entries.iter().try_fold(0_u64, |total, entry| { - let bytes = match entry.kind { - crate::protocol::RootFilesystemEntryKind::Directory => 0, - crate::protocol::RootFilesystemEntryKind::File => { - root_protocol_file_content_bytes(entry)? - } - crate::protocol::RootFilesystemEntryKind::Symlink => entry - .target - .as_ref() - .map(|target| usize_to_u64(target.len())) - .unwrap_or(0), - }; - Ok(total.saturating_add(bytes)) - }) -} - -fn root_protocol_file_content_bytes(entry: &RootFilesystemEntry) -> Result { - let Some(content) = entry.content.as_deref() else { - return Ok(0); - }; - - let bytes = match entry - .encoding - .clone() - .unwrap_or(RootFilesystemEntryEncoding::Utf8) - { - RootFilesystemEntryEncoding::Utf8 => content.len(), - RootFilesystemEntryEncoding::Base64 => estimated_base64_decoded_len(content), - }; - Ok(usize_to_u64(bytes)) -} - -fn estimated_base64_decoded_len(content: &str) -> usize { - let padding = content - .as_bytes() - .iter() - .rev() - .take_while(|byte| **byte == b'=') - .count() - .min(2); - content - .len() - .div_ceil(4) - .saturating_mul(3) - .saturating_sub(padding) -} - -fn usize_to_u64(value: usize) -> u64 { - u64::try_from(value).unwrap_or(u64::MAX) -} - -fn materialize_shadow_entries( - shadow_root: &Path, - entries: &[RootFilesystemEntry], -) -> Result<(), SidecarError> { - let mut ordered = entries.iter().collect::>(); - ordered.sort_by_key(|entry| { - let depth = entry.path.matches('/').count(); - let kind_rank = match entry.kind { - crate::protocol::RootFilesystemEntryKind::Directory => 0, - crate::protocol::RootFilesystemEntryKind::File => 1, - crate::protocol::RootFilesystemEntryKind::Symlink => 2, - }; - (kind_rank, depth, entry.path.as_str()) - }); - - for entry in ordered { - let shadow_path = shadow_path_for_guest(shadow_root, &entry.path); - if let Some(parent) = shadow_path.parent() { - fs::create_dir_all(parent).map_err(|error| { - SidecarError::Io(format!( - "failed to create shadow parent for {}: {error}", - entry.path - )) - })?; - } - - match entry.kind { - crate::protocol::RootFilesystemEntryKind::Directory => { - fs::create_dir_all(&shadow_path).map_err(|error| { - SidecarError::Io(format!( - "failed to materialize shadow directory {}: {error}", - entry.path - )) - })?; - } - crate::protocol::RootFilesystemEntryKind::File => { - let bytes = decode_root_entry_content(entry)?; - fs::write(&shadow_path, bytes).map_err(|error| { - SidecarError::Io(format!( - "failed to materialize shadow file {}: {error}", - entry.path - )) - })?; - } - crate::protocol::RootFilesystemEntryKind::Symlink => { - let _ = fs::remove_file(&shadow_path); - let _ = fs::remove_dir_all(&shadow_path); - std::os::unix::fs::symlink( - entry.target.as_deref().ok_or_else(|| { - SidecarError::InvalidState(format!( - "root filesystem symlink {} requires a target", - entry.path - )) - })?, - &shadow_path, - ) - .map_err(|error| { - SidecarError::Io(format!( - "failed to materialize shadow symlink {}: {error}", - entry.path - )) - })?; - continue; - } - } - - let mode = entry.mode.unwrap_or(match entry.kind { - crate::protocol::RootFilesystemEntryKind::Directory => 0o755, - crate::protocol::RootFilesystemEntryKind::File => { - if entry.executable { - 0o755 - } else { - 0o644 - } - } - crate::protocol::RootFilesystemEntryKind::Symlink => 0o777, - }); - fs::set_permissions(&shadow_path, fs::Permissions::from_mode(mode & 0o7777)).map_err( - |error| { - SidecarError::Io(format!( - "failed to set shadow mode on {}: {error}", - entry.path - )) - }, - )?; - } - - Ok(()) -} - -fn decode_root_entry_content(entry: &RootFilesystemEntry) -> Result, SidecarError> { - let content = entry.content.as_deref().unwrap_or_default(); - match entry - .encoding - .clone() - .unwrap_or(crate::protocol::RootFilesystemEntryEncoding::Utf8) - { - crate::protocol::RootFilesystemEntryEncoding::Utf8 => Ok(content.as_bytes().to_vec()), - crate::protocol::RootFilesystemEntryEncoding::Base64 => { - base64::engine::general_purpose::STANDARD - .decode(content) - .map_err(|error| { - SidecarError::InvalidState(format!( - "invalid base64 root filesystem content for {}: {error}", - entry.path - )) - }) - } - } -} - -fn shadow_path_for_guest(shadow_root: &std::path::Path, guest_path: &str) -> PathBuf { - let normalized = normalize_guest_path(guest_path); - let relative = normalized.trim_start_matches('/'); - if relative.is_empty() { - return shadow_root.to_path_buf(); - } - shadow_root.join(relative) -} - -fn normalize_guest_path(path: &str) -> String { - let mut segments = Vec::new(); - let absolute = path.starts_with('/'); - for segment in path.split('/') { - match segment { - "" | "." => {} - ".." => { - segments.pop(); - } - other => segments.push(other), - } - } - - if !absolute { - return format!("/{}", segments.join("/")); - } - if segments.is_empty() { - String::from("/") - } else { - format!("/{}", segments.join("/")) - } -} - -fn parse_vm_dns_nameserver(value: &str) -> Result { - use crate::state::VM_DNS_SERVERS_METADATA_KEY; - - if let Ok(address) = value.parse::() { - return Ok(address); - } - if let Ok(ip) = value.parse::() { - return Ok(SocketAddr::new(ip, 53)); - } - Err(SidecarError::InvalidState(format!( - "invalid {} entry {value}; expected IP or IP:port", - VM_DNS_SERVERS_METADATA_KEY - ))) -} - -fn refresh_guest_command_path_env( - guest_env: &mut BTreeMap, - command_guest_paths: &BTreeMap, -) { - let mut merged = Vec::new(); - let mut seen = BTreeSet::new(); - - for guest_path in command_guest_paths.values() { - let Some(parent) = Path::new(guest_path) - .parent() - .and_then(|path| path.to_str()) - else { - continue; - }; - let normalized = normalize_path(parent); - if normalized == "/" { - continue; - } - if seen.insert(normalized.clone()) { - merged.push(normalized); - } - } - - for segment in DEFAULT_GUEST_PATH_ENV.split(':') { - let normalized = normalize_path(segment); - if seen.insert(normalized.clone()) { - merged.push(normalized); - } - } - - if let Some(existing_path) = guest_env.get("PATH") { - for segment in existing_path.split(':') { - let trimmed = segment.trim(); - if trimmed.is_empty() { - continue; - } - let normalized = if trimmed.starts_with('/') { - normalize_path(trimmed) - } else { - trimmed.to_owned() - }; - if seen.insert(normalized.clone()) { - merged.push(normalized); - } - } - } - - guest_env.insert(String::from("PATH"), merged.join(":")); -} - -pub(crate) fn normalize_dns_hostname(hostname: &str) -> Result { - let normalized = hostname.trim().trim_end_matches('.').to_ascii_lowercase(); - if normalized.is_empty() { - return Err(SidecarError::InvalidState(String::from( - "DNS hostname must not be empty", - ))); - } - Ok(normalized) -} - -// Retained for the native-root command-stub test; `python` is now a real -// command so production no longer prunes `/bin/python`. -#[cfg(test)] -fn prune_kernel_command_stub( - kernel: &mut KernelVm, - path: &str, -) -> Result<(), SidecarError> { - if !kernel.exists(path).map_err(kernel_error)? { - return Ok(()); - } - - let content = kernel.read_file(path).map_err(kernel_error)?; - if content == KERNEL_COMMAND_STUB { - kernel.remove_file(path).map_err(kernel_error)?; - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::{ - bootstrap_native_root_filesystem, bootstrap_shadow_root, - materialize_shadow_root_snapshot_entries, native_root_plugin_from_config, - prune_kernel_command_stub, shadow_path_for_guest, KERNEL_COMMAND_STUB, - }; - use crate::plugins::chunked_local::ChunkedLocalMountPlugin; - use crate::protocol::{ - RootFilesystemDescriptor, RootFilesystemEntry, RootFilesystemEntryKind, - RootFilesystemLowerDescriptor, - }; - use secure_exec_bridge::FilesystemSnapshot; - use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig}; - use secure_exec_kernel::mount_plugin::{FileSystemPluginFactory, OpenFileSystemPluginRequest}; - use secure_exec_kernel::mount_table::{MountOptions, MountTable}; - use secure_exec_kernel::permissions::Permissions; - use secure_exec_kernel::resource_accounting::ResourceLimits; - use secure_exec_kernel::root_fs::{encode_snapshot, FilesystemEntry, RootFilesystemSnapshot}; - use secure_exec_kernel::vfs::VirtualFileSystem; - use std::fs; - use std::os::unix::fs::PermissionsExt; - use std::time::{SystemTime, UNIX_EPOCH}; - - #[test] - fn bootstrap_shadow_root_seeds_standard_directories() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let root = std::env::temp_dir().join(format!("secure-exec-sidecar-shadow-test-{unique}")); - fs::create_dir_all(&root).expect("temp shadow root should be created"); - - bootstrap_shadow_root(&root).expect("shadow bootstrap should succeed"); - - let tmp = shadow_path_for_guest(&root, "/tmp"); - let etc_agentos = shadow_path_for_guest(&root, "/etc/agentos"); - let usr_local_bin = shadow_path_for_guest(&root, "/usr/local/bin"); - - assert!(tmp.is_dir(), "/tmp should exist in the shadow root"); - assert!( - etc_agentos.is_dir(), - "/etc/agentos should exist in the shadow root" - ); - assert!( - usr_local_bin.is_dir(), - "/usr/local/bin should exist in the shadow root" - ); - assert_eq!( - fs::metadata(&tmp) - .expect("/tmp metadata should be readable") - .permissions() - .mode() - & 0o7777, - 0o1777, - "/tmp should preserve its sticky-bit mode in the shadow root" - ); - - fs::remove_dir_all(&root).expect("temp shadow root should be removed"); - } - - #[test] - fn native_root_config_opens_chunked_local_as_persistent_root() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let database_path = - std::env::temp_dir().join(format!("secure-exec-native-root-{unique}.sqlite")); - let block_root = - std::env::temp_dir().join(format!("secure-exec-native-root-blocks-{unique}")); - let native_root = native_root_plugin_from_config(Some( - &secure_exec_vm_config::NativeRootFilesystemConfig { - plugin: secure_exec_vm_config::MountPluginDescriptor { - id: "chunked_local".to_string(), - config: serde_json::json!({ - "metadataPath": database_path.to_string_lossy(), - "blockRoot": block_root.to_string_lossy(), - }), - }, - read_only: false, - }, - )) - .expect("native root config should parse") - .expect("native root should be present"); - let config: serde_json::Value = - serde_json::from_str(&native_root.plugin.config).expect("valid plugin config"); - let plugin = ChunkedLocalMountPlugin; - let mut filesystem = plugin - .open(OpenFileSystemPluginRequest { - vm_id: "vm-test", - guest_path: "/", - read_only: false, - config: &config, - context: &(), - }) - .expect("sqlite root should open"); - bootstrap_native_root_filesystem( - filesystem.as_mut(), - &RootFilesystemDescriptor { - bootstrap_entries: vec![RootFilesystemEntry { - path: "/etc/agentos/boot.txt".to_string(), - kind: RootFilesystemEntryKind::File, - content: Some("booted".to_string()), - ..Default::default() - }], - ..Default::default() - }, - ) - .expect("native root should bootstrap"); - - let mut mount_table = MountTable::new_boxed_root( - filesystem, - MountOptions::new(native_root.plugin.id.clone()), - ); - assert!(mount_table.exists("/home/agentos")); - assert_eq!( - mount_table - .read_file("/etc/agentos/boot.txt") - .expect("bootstrap file should be readable"), - b"booted".to_vec() - ); - mount_table - .write_file("/home/agentos/persist.txt", b"persisted".to_vec()) - .expect("write through sqlite root should succeed"); - let mut kernel_config = KernelVmConfig::new("vm-test"); - kernel_config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(mount_table, kernel_config); - kernel - .write_file("/bin/python", KERNEL_COMMAND_STUB.to_vec()) - .expect("command stub should be writable"); - prune_kernel_command_stub(&mut kernel, "/bin/python") - .expect("command stub prune should support native roots"); - assert!( - !kernel.exists("/bin/python").expect("exists should succeed"), - "stub should be pruned through the mounted root" - ); - drop(kernel); - - let reopened = plugin - .open(OpenFileSystemPluginRequest { - vm_id: "vm-test", - guest_path: "/", - read_only: false, - config: &config, - context: &(), - }) - .expect("chunked local root should reopen"); - let mut reopened = MountTable::new_boxed_root(reopened, MountOptions::new("chunked_local")); - assert_eq!( - reopened - .read_file("/home/agentos/persist.txt") - .expect("persisted file should survive reopen"), - b"persisted".to_vec() - ); - - let _ = fs::remove_file(database_path); - let _ = fs::remove_dir_all(block_root); - } - - #[test] - fn materialize_shadow_root_snapshot_entries_rejects_oversized_legacy_restored_snapshots() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let root = std::env::temp_dir().join(format!("secure-exec-sidecar-shadow-limit-{unique}")); - fs::create_dir_all(&root).expect("temp shadow root should be created"); - bootstrap_shadow_root(&root).expect("shadow bootstrap should succeed"); - - let snapshot = RootFilesystemSnapshot { - entries: vec![FilesystemEntry::file("/large.txt", b"four".to_vec())], - }; - let loaded_snapshot = FilesystemSnapshot { - format: String::from("agentos_filesystem_snapshot_v1"), - bytes: encode_snapshot(&snapshot).expect("encode restored snapshot"), - }; - let resource_limits = ResourceLimits { - max_filesystem_bytes: Some(3), - ..ResourceLimits::default() - }; - - let error = materialize_shadow_root_snapshot_entries( - &root, - &RootFilesystemDescriptor::default(), - Some(&loaded_snapshot), - &resource_limits, - ) - .expect_err("oversized restored snapshot should be rejected"); - - assert!(error.to_string().contains("exceeding limit 3")); - fs::remove_dir_all(&root).expect("temp shadow root should be removed"); - } - - #[test] - fn materialize_shadow_root_snapshot_entries_rejects_oversized_descriptor_before_writes() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let root = - std::env::temp_dir().join(format!("secure-exec-sidecar-shadow-descriptor-{unique}")); - fs::create_dir_all(&root).expect("temp shadow root should be created"); - bootstrap_shadow_root(&root).expect("shadow bootstrap should succeed"); - - let descriptor = RootFilesystemDescriptor { - lowers: vec![RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - crate::protocol::SnapshotRootFilesystemLower { - entries: vec![RootFilesystemEntry { - path: String::from("/large.txt"), - kind: RootFilesystemEntryKind::File, - mode: Some(0o644), - uid: Some(0), - gid: Some(0), - content: Some(String::from("four")), - encoding: Some(crate::protocol::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - }, - )], - ..RootFilesystemDescriptor::default() - }; - let resource_limits = ResourceLimits { - max_filesystem_bytes: Some(3), - ..ResourceLimits::default() - }; - - let error = - materialize_shadow_root_snapshot_entries(&root, &descriptor, None, &resource_limits) - .expect_err("oversized descriptor should be rejected"); - - assert!(error.to_string().contains("exceeding limit 3")); - assert!( - !shadow_path_for_guest(&root, "/large.txt").exists(), - "oversized descriptor must be rejected before materializing files" - ); - fs::remove_dir_all(&root).expect("temp shadow root should be removed"); - } - - #[test] - fn materialize_shadow_root_snapshot_entries_counts_implicit_parent_directories() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let root = - std::env::temp_dir().join(format!("secure-exec-sidecar-shadow-parents-{unique}")); - fs::create_dir_all(&root).expect("temp shadow root should be created"); - bootstrap_shadow_root(&root).expect("shadow bootstrap should succeed"); - - let descriptor = RootFilesystemDescriptor { - lowers: vec![RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - crate::protocol::SnapshotRootFilesystemLower { - entries: vec![RootFilesystemEntry { - path: String::from("/deep/nested/file.txt"), - kind: RootFilesystemEntryKind::File, - mode: Some(0o644), - uid: Some(0), - gid: Some(0), - content: Some(String::from("x")), - encoding: Some(crate::protocol::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }], - }, - )], - ..RootFilesystemDescriptor::default() - }; - let resource_limits = ResourceLimits { - max_inode_count: Some(1), - ..ResourceLimits::default() - }; - - let error = - materialize_shadow_root_snapshot_entries(&root, &descriptor, None, &resource_limits) - .expect_err("implicit parents should be rejected"); - - assert!(error.to_string().contains("exceeding limit 1")); - assert!( - !shadow_path_for_guest(&root, "/deep").exists(), - "implicit parents must not be materialized after rejection" - ); - fs::remove_dir_all(&root).expect("temp shadow root should be removed"); - } - - #[test] - fn materialize_shadow_root_snapshot_entries_rejects_duplicate_descriptor_entries() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let root = - std::env::temp_dir().join(format!("secure-exec-sidecar-shadow-duplicates-{unique}")); - fs::create_dir_all(&root).expect("temp shadow root should be created"); - bootstrap_shadow_root(&root).expect("shadow bootstrap should succeed"); - - let duplicate_entry = RootFilesystemEntry { - path: String::from("/dup.txt"), - kind: RootFilesystemEntryKind::File, - mode: Some(0o644), - uid: Some(0), - gid: Some(0), - content: Some(String::new()), - encoding: Some(crate::protocol::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }; - let descriptor = RootFilesystemDescriptor { - lowers: vec![RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - crate::protocol::SnapshotRootFilesystemLower { - entries: vec![duplicate_entry.clone(), duplicate_entry], - }, - )], - ..RootFilesystemDescriptor::default() - }; - let resource_limits = ResourceLimits { - max_inode_count: Some(1), - ..ResourceLimits::default() - }; - - let error = - materialize_shadow_root_snapshot_entries(&root, &descriptor, None, &resource_limits) - .expect_err("duplicate descriptor entries should be rejected"); - - assert!(error.to_string().contains("exceeding limit 1")); - assert!( - !shadow_path_for_guest(&root, "/dup.txt").exists(), - "duplicate descriptor must be rejected before materializing files" - ); - fs::remove_dir_all(&root).expect("temp shadow root should be removed"); - } - - #[test] - fn materialize_shadow_root_snapshot_entries_copies_custom_snapshot_files() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let root = - std::env::temp_dir().join(format!("secure-exec-sidecar-shadow-snapshot-{unique}")); - fs::create_dir_all(&root).expect("temp shadow root should be created"); - bootstrap_shadow_root(&root).expect("shadow bootstrap should succeed"); - - let descriptor = RootFilesystemDescriptor { - lowers: vec![RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - crate::protocol::SnapshotRootFilesystemLower { - entries: vec![ - RootFilesystemEntry { - path: String::from("/"), - kind: RootFilesystemEntryKind::Directory, - mode: Some(0o755), - uid: Some(0), - gid: Some(0), - content: None, - encoding: None, - target: None, - executable: false, - }, - RootFilesystemEntry { - path: String::from("/hello.txt"), - kind: RootFilesystemEntryKind::File, - mode: Some(0o644), - uid: Some(0), - gid: Some(0), - content: Some(String::from("hello from snapshot\n")), - encoding: Some(crate::protocol::RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }, - ], - }, - )], - ..RootFilesystemDescriptor::default() - }; - - materialize_shadow_root_snapshot_entries( - &root, - &descriptor, - None, - &ResourceLimits::default(), - ) - .expect("snapshot entries should materialize into the shadow root"); - - assert_eq!( - fs::read_to_string(shadow_path_for_guest(&root, "/hello.txt")) - .expect("shadow file should be readable"), - "hello from snapshot\n" - ); - - fs::remove_dir_all(&root).expect("temp shadow root should be removed"); - } -} diff --git a/crates/sidecar/tests/acp/client.rs b/crates/sidecar/tests/acp/client.rs deleted file mode 100644 index 31c157d37..000000000 --- a/crates/sidecar/tests/acp/client.rs +++ /dev/null @@ -1,630 +0,0 @@ -use crate::acp::{ - deserialize_message, AcpClient, AcpClientError, AcpClientOptions, AcpClientProcessState, - InboundRequestHandler, InboundRequestOutcome, JsonRpcError, JsonRpcId, JsonRpcMessage, - JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, -}; -use serde_json::{json, Value}; -use std::collections::BTreeMap; -use std::sync::Arc; -use std::time::{Duration, Instant}; -use tokio::io::{split, AsyncBufReadExt, AsyncWriteExt, BufReader, DuplexStream}; - -fn new_client( - options: AcpClientOptions, -) -> ( - AcpClient, - tokio::io::Lines>>, - tokio::io::WriteHalf, -) { - let (client_stream, server_stream) = tokio::io::duplex(8 * 1024); - let (client_reader, client_writer) = split(client_stream); - let (server_reader, server_writer) = split(server_stream); - let client = AcpClient::new(client_reader, client_writer, options); - (client, BufReader::new(server_reader).lines(), server_writer) -} - -async fn read_message( - reader: &mut tokio::io::Lines>>, -) -> JsonRpcMessage { - let line = reader - .next_line() - .await - .expect("read line") - .expect("line should exist"); - deserialize_message(&line).expect("decode json-rpc line") -} - -async fn write_raw(writer: &mut tokio::io::WriteHalf, line: &str) { - writer - .write_all(line.as_bytes()) - .await - .expect("write raw line"); - writer.flush().await.expect("flush raw line"); -} - -async fn write_message(writer: &mut tokio::io::WriteHalf, message: &JsonRpcMessage) { - let encoded = crate::acp::serialize_message(message).expect("encode json-rpc"); - write_raw(writer, &encoded).await; -} - -async fn recv_notification( - receiver: &mut tokio::sync::broadcast::Receiver, -) -> JsonRpcNotification { - tokio::time::timeout(Duration::from_secs(1), receiver.recv()) - .await - .expect("notification timeout") - .expect("receive notification") -} - -#[tokio::test(flavor = "current_thread")] -async fn client_correlates_responses_and_forwards_notifications() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions::default()); - let mut notifications = client.subscribe_notifications(); - - let request_task = tokio::spawn({ - let client = client.clone(); - async move { - client - .request( - "session/prompt", - Some(json!({ "sessionId": "session-1", "prompt": [{ "type": "text", "text": "hi" }] })), - ) - .await - } - }); - - let request = read_message(&mut reader).await; - match request { - JsonRpcMessage::Request(message) => { - assert_eq!(message.method, "session/prompt"); - write_message( - &mut writer, - &JsonRpcMessage::Notification(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from("session/update"), - params: Some(json!({ "status": "thinking" })), - }), - ) - .await; - write_message( - &mut writer, - &JsonRpcMessage::Response(JsonRpcResponse::success( - message.id, - json!({ "status": "complete" }), - )), - ) - .await; - } - other => panic!("unexpected outbound frame: {other:?}"), - } - - let notification = recv_notification(&mut notifications).await; - assert_eq!(notification.method, "session/update"); - assert_eq!(notification.params, Some(json!({ "status": "thinking" }))); - - let response = request_task.await.expect("request task").expect("request"); - assert_eq!(response.result(), Some(&json!({ "status": "complete" }))); -} - -#[tokio::test(flavor = "current_thread")] -async fn client_shims_modern_permission_requests_to_legacy_notifications() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions::default()); - let mut notifications = client.subscribe_notifications(); - - let prompt_task = tokio::spawn({ - let client = client.clone(); - async move { - client - .request("session/prompt", Some(json!({ "sessionId": "session-1" }))) - .await - } - }); - - let prompt_request = read_message(&mut reader).await; - let prompt_id = match prompt_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "session/prompt"); - request.id - } - other => panic!("unexpected prompt frame: {other:?}"), - }; - - write_message( - &mut writer, - &JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::String(String::from("perm-modern-1")), - method: String::from("session/request_permission"), - params: Some(json!({ - "sessionId": "session-1", - "options": [ - { "optionId": "allow_once", "kind": "allow_once" }, - { "optionId": "allow_always", "kind": "allow_always" }, - { "optionId": "reject_once", "kind": "reject_once" } - ] - })), - }), - ) - .await; - - let notification = recv_notification(&mut notifications).await; - assert_eq!(notification.method, "request/permission"); - let params = notification.params.expect("permission params"); - assert_eq!(params["permissionId"], json!("perm-modern-1")); - assert_eq!(params["_acpMethod"], json!("session/request_permission")); - - let permission_response = client - .request( - "request/permission", - Some(json!({ - "permissionId": "perm-modern-1", - "reply": "always" - })), - ) - .await - .expect("permission response"); - assert_eq!( - permission_response.result(), - Some(&json!({ - "outcome": { - "outcome": "selected", - "optionId": "allow_always" - } - })) - ); - - let outbound_permission = read_message(&mut reader).await; - match outbound_permission { - JsonRpcMessage::Response(response) => { - assert_eq!( - response.id, - JsonRpcId::String(String::from("perm-modern-1")) - ); - assert_eq!( - response.result(), - Some(&json!({ - "outcome": { - "outcome": "selected", - "optionId": "allow_always" - } - })) - ); - } - other => panic!("unexpected permission response frame: {other:?}"), - } - - write_message( - &mut writer, - &JsonRpcMessage::Response(JsonRpcResponse::success( - prompt_id, - json!({ "status": "complete" }), - )), - ) - .await; - - let prompt_response = prompt_task - .await - .expect("prompt task") - .expect("prompt response"); - assert_eq!( - prompt_response.result(), - Some(&json!({ "status": "complete" })) - ); -} - -#[tokio::test(flavor = "current_thread")] -async fn client_normalizes_opencode_style_permission_option_ids() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions::default()); - let mut notifications = client.subscribe_notifications(); - - let prompt_task = tokio::spawn({ - let client = client.clone(); - async move { - client - .request("session/prompt", Some(json!({ "sessionId": "session-oc" }))) - .await - } - }); - - let prompt_request = read_message(&mut reader).await; - let prompt_id = match prompt_request { - JsonRpcMessage::Request(request) => request.id, - other => panic!("unexpected prompt frame: {other:?}"), - }; - - write_message( - &mut writer, - &JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::String(String::from("perm-opencode-1")), - method: String::from("session/request_permission"), - params: Some(json!({ - "sessionId": "session-oc", - "options": [ - { "optionId": "once", "kind": "allow_once" }, - { "optionId": "always", "kind": "allow_always" }, - { "optionId": "reject", "kind": "reject_once" } - ] - })), - }), - ) - .await; - - let _ = recv_notification(&mut notifications).await; - - client - .request( - "request/permission", - Some(json!({ - "permissionId": "perm-opencode-1", - "reply": "always" - })), - ) - .await - .expect("permission response"); - - let outbound_permission = read_message(&mut reader).await; - match outbound_permission { - JsonRpcMessage::Response(response) => { - assert_eq!( - response.result(), - Some(&json!({ - "outcome": { - "outcome": "selected", - "optionId": "always" - } - })) - ); - } - other => panic!("unexpected permission response frame: {other:?}"), - } - - write_message( - &mut writer, - &JsonRpcMessage::Response(JsonRpcResponse::success(prompt_id, json!({ "done": true }))), - ) - .await; - - let prompt_response = prompt_task - .await - .expect("prompt task") - .expect("prompt response"); - assert_eq!(prompt_response.result(), Some(&json!({ "done": true }))); -} - -#[tokio::test(flavor = "current_thread")] -async fn client_deduplicates_repeated_permission_request_ids() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions::default()); - let mut notifications = client.subscribe_notifications(); - - let prompt_task = tokio::spawn({ - let client = client.clone(); - async move { client.request("session/prompt", Some(json!({}))).await } - }); - - let prompt_request = read_message(&mut reader).await; - let prompt_id = match prompt_request { - JsonRpcMessage::Request(request) => request.id, - other => panic!("unexpected prompt frame: {other:?}"), - }; - - let permission_request = JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::String(String::from("perm-dup-1")), - method: String::from("session/request_permission"), - params: Some(json!({ - "options": [ - { "optionId": "allow_once", "kind": "allow_once" }, - { "optionId": "reject_once", "kind": "reject_once" } - ] - })), - }); - write_message(&mut writer, &permission_request).await; - write_message(&mut writer, &permission_request).await; - - let notification = recv_notification(&mut notifications).await; - assert_eq!( - notification.params.expect("permission params")["permissionId"], - json!("perm-dup-1") - ); - assert!( - tokio::time::timeout(Duration::from_millis(50), notifications.recv()) - .await - .is_err() - ); - - client - .request( - "request/permission", - Some(json!({ - "permissionId": "perm-dup-1", - "reply": "once" - })), - ) - .await - .expect("permission response"); - - let outbound_permission = read_message(&mut reader).await; - match outbound_permission { - JsonRpcMessage::Response(response) => { - assert_eq!(response.id, JsonRpcId::String(String::from("perm-dup-1"))); - } - other => panic!("unexpected permission response frame: {other:?}"), - } - - write_message( - &mut writer, - &JsonRpcMessage::Response(JsonRpcResponse::success(prompt_id, json!({ "done": true }))), - ) - .await; - - let _ = prompt_task - .await - .expect("prompt task") - .expect("prompt response"); -} - -#[tokio::test(flavor = "current_thread")] -async fn client_falls_back_to_cancel_notification_when_request_form_is_unsupported() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions::default()); - - let cancel_task = tokio::spawn({ - let client = client.clone(); - async move { - client - .request("session/cancel", Some(json!({ "sessionId": "session-1" }))) - .await - } - }); - - let outbound_request = read_message(&mut reader).await; - let request_id = match outbound_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "session/cancel"); - request.id - } - other => panic!("unexpected cancel request: {other:?}"), - }; - - write_message( - &mut writer, - &JsonRpcMessage::Response(JsonRpcResponse::error_response( - request_id, - JsonRpcError { - code: -32601, - message: String::from("Method not found: session/cancel"), - data: Some(json!({ "method": "session/cancel" })), - }, - )), - ) - .await; - - let fallback = read_message(&mut reader).await; - match fallback { - JsonRpcMessage::Notification(notification) => { - assert_eq!(notification.method, "session/cancel"); - assert_eq!( - notification.params, - Some(json!({ "sessionId": "session-1" })) - ); - } - other => panic!("unexpected fallback frame: {other:?}"), - } - - let response = cancel_task - .await - .expect("cancel task") - .expect("cancel response"); - assert_eq!( - response.result(), - Some(&json!({ - "cancelled": false, - "requested": true, - "via": "notification-fallback" - })) - ); -} - -#[tokio::test(flavor = "current_thread")] -async fn client_timeout_errors_include_recent_activity() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions { - timeout: Duration::from_millis(50), - method_timeouts: BTreeMap::new(), - request_handler: None, - process_state_provider: Some(Arc::new(|| AcpClientProcessState { - exit_code: Some(137), - killed: Some(true), - })), - max_read_line_bytes: 16 * 1024 * 1024, - }); - - let request_task = tokio::spawn({ - let client = client.clone(); - async move { - client - .request("session/prompt", Some(json!({ "sessionId": "hang" }))) - .await - } - }); - - let outbound_request = read_message(&mut reader).await; - match outbound_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "session/prompt"); - } - other => panic!("unexpected request frame: {other:?}"), - } - - write_raw(&mut writer, "[sandbox.require] start node:url /\n").await; - write_message( - &mut writer, - &JsonRpcMessage::Notification(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from("session/update"), - params: Some(json!({ "status": "thinking" })), - }), - ) - .await; - - let error = request_task - .await - .expect("request task") - .expect_err("request should time out"); - let message = error.to_string(); - assert!(message.contains("Recent ACP activity")); - assert!(message.contains("invalid_json_rpc code=-32700 Parse error")); - assert!(message.contains("received notification session/update")); - assert!(message.contains("process exitCode=137")); - assert!(message.contains("killed=true")); -} - -#[tokio::test(flavor = "current_thread")] -async fn client_rejects_adapter_lines_over_configured_limit() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions { - timeout: Duration::from_secs(1), - method_timeouts: BTreeMap::new(), - request_handler: None, - process_state_provider: None, - max_read_line_bytes: 32, - }); - - let request_task = tokio::spawn({ - let client = client.clone(); - async move { - client - .request( - "session/prompt", - Some(json!({ "sessionId": "oversized-line" })), - ) - .await - } - }); - - let outbound_request = read_message(&mut reader).await; - match outbound_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "session/prompt"); - } - other => panic!("unexpected request frame: {other:?}"), - } - - write_raw(&mut writer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n").await; - - let error = request_task - .await - .expect("request task") - .expect_err("oversized line should fail the request"); - assert!( - matches!(error, AcpClientError::Io(_)), - "unexpected error: {error:?}" - ); - assert!( - error - .to_string() - .contains("ACP adapter emitted a line longer than 32 bytes"), - "unexpected oversized-line error: {error}" - ); -} - -#[tokio::test(flavor = "current_thread")] -async fn client_waits_for_exit_drain_before_rejecting_pending_requests() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions { - timeout: Duration::from_secs(1), - method_timeouts: BTreeMap::new(), - request_handler: None, - process_state_provider: None, - max_read_line_bytes: 16 * 1024 * 1024, - }); - - let started_at = Instant::now(); - let request_task = tokio::spawn({ - let client = client.clone(); - async move { - client - .request("session/prompt", Some(json!({ "sessionId": "exit" }))) - .await - } - }); - - let outbound_request = read_message(&mut reader).await; - match outbound_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "session/prompt"); - } - other => panic!("unexpected request frame: {other:?}"), - } - - writer.shutdown().await.expect("shutdown server writer"); - drop(writer); - drop(reader); - - let error = request_task - .await - .expect("request task") - .expect_err("request should fail after exit"); - assert!( - matches!(error, AcpClientError::Closed(_)), - "unexpected error: {error:?}" - ); - assert!(started_at.elapsed() >= Duration::from_millis(45)); -} - -#[tokio::test(flavor = "current_thread")] -async fn client_handles_inbound_requests_with_registered_handler() { - let handler: InboundRequestHandler = Arc::new(|request| { - Box::pin(async move { - Ok(Some(InboundRequestOutcome { - result: Some(json!({ - "echo": request.params.unwrap_or(Value::Null) - })), - error: None, - })) - }) - }); - - let (client, mut reader, mut writer) = new_client(AcpClientOptions { - timeout: Duration::from_secs(1), - method_timeouts: BTreeMap::new(), - request_handler: Some(handler), - process_state_provider: None, - max_read_line_bytes: 16 * 1024 * 1024, - }); - let mut notifications = client.subscribe_notifications(); - - write_message( - &mut writer, - &JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(41), - method: String::from("fs/read_text_file"), - params: Some(json!({ "path": "/workspace/notes.txt" })), - }), - ) - .await; - - let notification = recv_notification(&mut notifications).await; - assert_eq!(notification.method, "fs/read_text_file"); - assert_eq!( - notification.params, - Some(json!({ - "path": "/workspace/notes.txt", - "requestId": 41 - })) - ); - - let response = read_message(&mut reader).await; - match response { - JsonRpcMessage::Response(response) => { - assert_eq!(response.id, JsonRpcId::Number(41)); - assert_eq!( - response.result(), - Some(&json!({ - "echo": { - "path": "/workspace/notes.txt" - } - })) - ); - } - other => panic!("unexpected inbound response frame: {other:?}"), - } -} diff --git a/crates/sidecar/tests/acp/json_rpc.rs b/crates/sidecar/tests/acp/json_rpc.rs deleted file mode 100644 index c495ebb08..000000000 --- a/crates/sidecar/tests/acp/json_rpc.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::acp::{ - deserialize_message, is_request, is_response, serialize_message, JsonRpcError, JsonRpcId, - JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, - JsonRpcResponseShapeError, -}; -use serde_json::json; - -#[test] -fn json_rpc_codec_round_trips_all_message_shapes() { - let request = JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(7), - method: String::from("session/prompt"), - params: Some(json!({ "sessionId": "session-1" })), - }); - let response = JsonRpcMessage::Response(JsonRpcResponse::success( - JsonRpcId::String(String::from("req-1")), - json!({ "ok": true }), - )); - let notification = JsonRpcMessage::Notification(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from("session/update"), - params: Some(json!({ "status": "thinking" })), - }); - - let encoded_request = serialize_message(&request).expect("encode request"); - let encoded_response = serialize_message(&response).expect("encode response"); - let encoded_notification = serialize_message(¬ification).expect("encode notification"); - - assert_eq!( - deserialize_message(encoded_request.trim()), - Ok(request.clone()) - ); - assert_eq!( - deserialize_message(encoded_response.trim()), - Ok(response.clone()) - ); - assert_eq!( - deserialize_message(encoded_notification.trim()), - Ok(notification.clone()) - ); - assert!(is_request(&request)); - assert!(is_response(&response)); - assert!(!is_request(¬ification)); - assert!(!is_response(¬ification)); -} - -#[test] -fn json_rpc_deserializer_rejects_invalid_lines() { - let parse_error = deserialize_message("not json").expect_err("invalid json should fail"); - assert_eq!(parse_error.code(), -32700); - assert_eq!(parse_error.id(), &JsonRpcId::Null); - - let invalid_version = deserialize_message(r#"{"jsonrpc":"1.0","id":1,"method":"initialize"}"#) - .expect_err("wrong jsonrpc version should fail"); - assert_eq!(invalid_version.code(), -32600); - assert_eq!(invalid_version.id(), &JsonRpcId::Number(1)); - - let missing_id = deserialize_message(r#"{"jsonrpc":"2.0","result":{"ok":true}}"#) - .expect_err("response without id should fail"); - assert_eq!(missing_id.code(), -32600); - assert_eq!(missing_id.id(), &JsonRpcId::Null); - - let invalid_params = - deserialize_message(r#"{"jsonrpc":"2.0","id":9,"method":"initialize","params":"bad"}"#) - .expect_err("non-object params should fail"); - assert_eq!(invalid_params.code(), -32600); - assert_eq!(invalid_params.id(), &JsonRpcId::Number(9)); -} - -#[test] -fn json_rpc_deserializer_rejects_ambiguous_request_response_shapes() { - let mixed_result = - deserialize_message(r#"{"jsonrpc":"2.0","id":11,"method":"initialize","result":{}}"#) - .expect_err("request with result field should fail"); - assert_eq!(mixed_result.code(), -32600); - assert_eq!(mixed_result.id(), &JsonRpcId::Number(11)); - assert_eq!( - mixed_result.message(), - "Invalid Request: method cannot be combined with result or error" - ); - - let mixed_error = deserialize_message( - r#"{"jsonrpc":"2.0","id":"req-12","method":"initialize","error":{"code":-32000,"message":"boom"}}"#, - ) - .expect_err("request with error field should fail"); - assert_eq!(mixed_error.code(), -32600); - assert_eq!(mixed_error.id(), &JsonRpcId::String(String::from("req-12"))); -} - -#[test] -fn json_rpc_error_serializes_optional_data() { - let response = JsonRpcMessage::Response(JsonRpcResponse::error_response( - JsonRpcId::Null, - JsonRpcError { - code: -32601, - message: String::from("Method not found"), - data: Some(json!({ "method": "session/cancel" })), - }, - )); - - let encoded = serialize_message(&response).expect("encode error response"); - assert!(encoded.contains("\"data\":{\"method\":\"session/cancel\"}")); -} - -#[test] -fn json_rpc_response_rejects_both_result_and_error() { - let error = JsonRpcResponse::try_from_parts( - String::from("2.0"), - JsonRpcId::Number(1), - Some(json!({ "ok": true })), - Some(JsonRpcError { - code: -32000, - message: String::from("boom"), - data: None, - }), - ) - .expect_err("response shape should be rejected"); - - assert_eq!(error, JsonRpcResponseShapeError::BothResultAndError); -} diff --git a/crates/sidecar/tests/acp/mod.rs b/crates/sidecar/tests/acp/mod.rs deleted file mode 100644 index c0468ef84..000000000 --- a/crates/sidecar/tests/acp/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod client; -mod json_rpc; diff --git a/crates/sidecar/tests/acp_integration.rs b/crates/sidecar/tests/acp_integration.rs deleted file mode 100644 index 8c4d8ca70..000000000 --- a/crates/sidecar/tests/acp_integration.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[allow(dead_code, unused_imports)] -#[path = "acp_legacy/mod.rs"] -mod acp; -#[allow(dead_code, unused_imports)] -#[path = "../src/json_rpc.rs"] -mod json_rpc; - -#[path = "acp/mod.rs"] -mod acp_tests; diff --git a/crates/sidecar/tests/acp_legacy/client.rs b/crates/sidecar/tests/acp_legacy/client.rs deleted file mode 100644 index c47a7111e..000000000 --- a/crates/sidecar/tests/acp_legacy/client.rs +++ /dev/null @@ -1,1271 +0,0 @@ -use crate::acp::compat::{ - PendingPermissionRequest, PendingPermissionRequests, SeenInboundRequestIds, -}; -use crate::acp::AcpTimeoutDiagnostics; -use crate::json_rpc::{ - serialize_message, JsonRpcError, JsonRpcId, JsonRpcMessage, JsonRpcNotification, - JsonRpcRequest, JsonRpcResponse, -}; -use serde_json::{json, Map, Value}; -use std::collections::{BTreeMap, VecDeque}; -use std::future::Future; -use std::pin::Pin; -use std::sync::atomic::{AtomicBool, AtomicI64, Ordering}; -use std::sync::{Arc, Mutex}; -use std::time::Duration; -use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader}; -use tokio::sync::{broadcast, oneshot, Mutex as AsyncMutex}; - -const DEFAULT_TIMEOUT_MS: Duration = Duration::from_millis(120_000); -const INITIALIZE_TIMEOUT_MS: Duration = Duration::from_millis(10_000); -const SESSION_NEW_TIMEOUT_MS: Duration = Duration::from_millis(30_000); -const SESSION_PROMPT_TIMEOUT_MS: Duration = Duration::from_millis(600_000); -const EXIT_DRAIN_GRACE_MS: Duration = Duration::from_millis(50); -const DEFAULT_MAX_READ_LINE_BYTES: usize = 16 * 1024 * 1024; -const LEGACY_PERMISSION_METHOD: &str = "request/permission"; -const ACP_PERMISSION_METHOD: &str = "session/request_permission"; -const ACP_CANCEL_METHOD: &str = "session/cancel"; -const RECENT_ACTIVITY_LIMIT: usize = 20; -const ACTIVITY_TEXT_LIMIT: usize = 240; - -pub type InboundRequestFuture = - Pin, String>> + Send + 'static>>; -pub type InboundRequestHandler = Arc InboundRequestFuture + Send + Sync>; -pub type AcpClientProcessStateProvider = - Arc AcpClientProcessState + Send + Sync + 'static>; - -#[derive(Debug, Clone, PartialEq)] -pub struct InboundRequestOutcome { - pub result: Option, - pub error: Option, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct AcpClientProcessState { - pub exit_code: Option, - pub killed: Option, -} - -#[derive(Clone)] -pub struct AcpClient { - inner: Arc, -} - -#[derive(Clone)] -pub struct AcpClientOptions { - pub timeout: Duration, - pub method_timeouts: BTreeMap, - pub request_handler: Option, - pub process_state_provider: Option, - pub max_read_line_bytes: usize, -} - -impl Default for AcpClientOptions { - fn default() -> Self { - Self { - timeout: DEFAULT_TIMEOUT_MS, - method_timeouts: AcpClient::default_method_timeouts(), - request_handler: None, - process_state_provider: None, - max_read_line_bytes: DEFAULT_MAX_READ_LINE_BYTES, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum AcpClientError { - Closed(String), - Timeout(String), - Io(String), -} - -impl std::fmt::Display for AcpClientError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Closed(message) | Self::Timeout(message) | Self::Io(message) => { - f.write_str(message) - } - } - } -} - -impl std::error::Error for AcpClientError {} - -struct AcpClientInner { - writer: AsyncMutex>>, - pending: Mutex>>>, - seen_inbound_request_ids: Mutex, - pending_permission_requests: Mutex, - request_handler: Mutex>, - notification_tx: broadcast::Sender, - recent_activity: Mutex>, - next_id: AtomicI64, - closed: AtomicBool, - terminal_error: Mutex>, - transport_state: Mutex, - timeout: Duration, - method_timeouts: BTreeMap, - process_state_provider: Option, - max_read_line_bytes: usize, -} - -impl AcpClient { - pub fn new(reader: R, writer: W, options: AcpClientOptions) -> Self - where - R: AsyncRead + Unpin + Send + 'static, - W: AsyncWrite + Unpin + Send + 'static, - { - let (notification_tx, _) = broadcast::channel(64); - let inner = Arc::new(AcpClientInner { - writer: AsyncMutex::new(Box::pin(writer)), - pending: Mutex::new(BTreeMap::new()), - seen_inbound_request_ids: Mutex::new(SeenInboundRequestIds::default()), - pending_permission_requests: Mutex::new(PendingPermissionRequests::default()), - request_handler: Mutex::new(options.request_handler), - notification_tx, - recent_activity: Mutex::new(VecDeque::with_capacity(RECENT_ACTIVITY_LIMIT)), - next_id: AtomicI64::new(1), - closed: AtomicBool::new(false), - terminal_error: Mutex::new(None), - transport_state: Mutex::new(String::from("transport_open")), - timeout: options.timeout, - method_timeouts: options.method_timeouts, - process_state_provider: options.process_state_provider, - max_read_line_bytes: options.max_read_line_bytes, - }); - - tokio::spawn(read_loop(BufReader::new(reader), Arc::clone(&inner))); - - Self { inner } - } - - pub fn subscribe_notifications(&self) -> broadcast::Receiver { - self.inner.notification_tx.subscribe() - } - - pub fn default_method_timeouts() -> BTreeMap { - BTreeMap::from([ - (String::from("initialize"), INITIALIZE_TIMEOUT_MS), - (String::from("session/new"), SESSION_NEW_TIMEOUT_MS), - (String::from("session/prompt"), SESSION_PROMPT_TIMEOUT_MS), - ]) - } - - pub fn set_request_handler(&self, handler: Option) { - *self - .inner - .request_handler - .lock() - .expect("request handler lock poisoned") = handler; - } - - pub async fn request( - &self, - method: impl Into, - params: Option, - ) -> Result { - if let Some(error) = self.inner.terminal_error() { - return Err(error); - } - - let method = method.into(); - if let Some(response) = self - .maybe_handle_permission_response(&method, params.clone()) - .await? - { - return Ok(response); - } - let request_timeout = self.inner.timeout_for_method(&method); - - let id = JsonRpcId::Number(self.inner.next_id.fetch_add(1, Ordering::Relaxed)); - let message = JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: id.clone(), - method: method.clone(), - params: params.clone(), - }; - - let (tx, rx) = oneshot::channel(); - self.inner - .pending - .lock() - .expect("pending lock poisoned") - .insert(id.clone(), tx); - - self.inner - .record_activity(format!("sent request {method} id={id}")); - if let Err(error) = self.write_message(JsonRpcMessage::Request(message)).await { - self.inner - .pending - .lock() - .expect("pending lock poisoned") - .remove(&id); - return Err(error); - } - - let response = match tokio::time::timeout(request_timeout, rx).await { - Ok(Ok(Ok(response))) => response, - Ok(Ok(Err(error))) => return Err(error), - Ok(Err(_)) => { - return Err(AcpClientError::Closed(String::from( - "ACP client request channel closed before a response arrived", - ))); - } - Err(_) => { - self.inner - .pending - .lock() - .expect("pending lock poisoned") - .remove(&id); - self.dispatch_timeout_cancel(&method, params.as_ref()).await; - return Err(self - .inner - .create_timeout_error(&method, &id, request_timeout)); - } - }; - - if method != ACP_CANCEL_METHOD || !is_cancel_method_not_found(&response) { - return Ok(response); - } - - self.notify(method.clone(), params).await?; - Ok(JsonRpcResponse::success( - response.id, - json!({ - "cancelled": false, - "requested": true, - "via": "notification-fallback", - }), - )) - } - - pub async fn notify( - &self, - method: impl Into, - params: Option, - ) -> Result<(), AcpClientError> { - if let Some(error) = self.inner.terminal_error() { - return Err(error); - } - - let method = method.into(); - self.inner - .record_activity(format!("sent notification {method}")); - self.write_message(JsonRpcMessage::Notification(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method, - params, - })) - .await - } - - pub async fn close(&self) -> Result<(), AcpClientError> { - if self.inner.closed.swap(true, Ordering::SeqCst) { - return Ok(()); - } - - { - let mut terminal_error = self - .inner - .terminal_error - .lock() - .expect("terminal error lock poisoned"); - terminal_error - .get_or_insert_with(|| AcpClientError::Closed(String::from("AcpClient closed"))); - } - - { - let mut writer = self.inner.writer.lock().await; - writer.shutdown().await.map_err(|error| { - AcpClientError::Io(format!("failed to close ACP writer: {error}")) - })?; - } - self.inner - .reject_all(AcpClientError::Closed(String::from("AcpClient closed"))); - Ok(()) - } - - async fn maybe_handle_permission_response( - &self, - method: &str, - params: Option, - ) -> Result, AcpClientError> { - if method != LEGACY_PERMISSION_METHOD && method != ACP_PERMISSION_METHOD { - return Ok(None); - } - - let payload = to_record(params); - let permission_id = match payload.get("permissionId") { - Some(Value::String(value)) => value.clone(), - Some(Value::Number(value)) => value.to_string(), - _ => return Ok(None), - }; - - let pending = self - .inner - .pending_permission_requests - .lock() - .expect("permission lock poisoned") - .remove_by_permission_id(&permission_id); - let Some(pending) = pending else { - return Ok(None); - }; - if pending.method != ACP_PERMISSION_METHOD { - return Ok(None); - } - - let result = normalize_permission_result(&payload, &pending); - let response = JsonRpcResponse::success(pending.id.clone(), result); - - self.inner - .record_activity(format!("sent permission response id={}", pending.id)); - self.write_message(JsonRpcMessage::Response(response.clone())) - .await?; - Ok(Some(response)) - } - - async fn write_message(&self, message: JsonRpcMessage) -> Result<(), AcpClientError> { - write_with_inner(&self.inner, message).await - } - - async fn dispatch_timeout_cancel(&self, method: &str, params: Option<&Value>) { - let Some(cancel_params) = timeout_cancel_params(method, params) else { - return; - }; - let _ = self.notify(ACP_CANCEL_METHOD, Some(cancel_params)).await; - } -} - -impl AcpClientInner { - fn terminal_error(&self) -> Option { - self.terminal_error - .lock() - .expect("terminal error lock poisoned") - .clone() - } - - fn record_activity(&self, entry: String) { - let mut recent = self - .recent_activity - .lock() - .expect("recent activity lock poisoned"); - recent.push_back(entry); - while recent.len() > RECENT_ACTIVITY_LIMIT { - recent.pop_front(); - } - } - - fn create_timeout_error( - &self, - method: &str, - id: &JsonRpcId, - timeout: Duration, - ) -> AcpClientError { - let transport_state = self - .transport_state - .lock() - .expect("transport state lock poisoned") - .clone(); - let recent_activity = self - .recent_activity - .lock() - .expect("recent activity lock poisoned") - .iter() - .cloned() - .collect::>(); - let process_state = self - .process_state_provider - .as_ref() - .map(|provider| provider()) - .unwrap_or_default(); - let timeout_ms = u64::try_from(timeout.as_millis()).unwrap_or(u64::MAX); - let diagnostics = AcpTimeoutDiagnostics::new( - method, - id.clone(), - timeout_ms, - process_state.exit_code, - process_state.killed, - Some(transport_state), - recent_activity, - ); - AcpClientError::Timeout(diagnostics.message()) - } - - fn timeout_for_method(&self, method: &str) -> Duration { - self.method_timeouts - .get(method) - .copied() - .unwrap_or(self.timeout) - } - - fn reject_all(&self, error: AcpClientError) { - let responders = { - let mut pending = self.pending.lock().expect("pending lock poisoned"); - std::mem::take(&mut *pending) - }; - for (_, responder) in responders { - let _ = responder.send(Err(error.clone())); - } - self.pending_permission_requests - .lock() - .expect("permission lock poisoned") - .clear(); - self.seen_inbound_request_ids - .lock() - .expect("seen request ids lock poisoned") - .clear(); - } - - fn fail_transport(&self, error: AcpClientError) -> AcpClientError { - if !self.closed.swap(true, Ordering::SeqCst) { - let mut terminal_error = self - .terminal_error - .lock() - .expect("terminal error lock poisoned"); - terminal_error.get_or_insert_with(|| error.clone()); - self.reject_all(error.clone()); - } - error - } -} - -async fn read_loop(mut reader: BufReader, inner: Arc) -where - R: AsyncRead + Unpin + Send + 'static, -{ - let max_read_line_bytes = inner.max_read_line_bytes; - loop { - match read_bounded_line(&mut reader, max_read_line_bytes).await { - Ok(Some(line)) => { - let trimmed = line.trim(); - if trimmed.is_empty() { - continue; - } - - let message = match crate::acp::deserialize_message(trimmed) { - Ok(message) => message, - Err(error) => { - inner.record_activity(format!( - "invalid_json_rpc code={} {}", - error.code(), - truncate_activity_text(error.message()) - )); - if write_with_inner(&inner, JsonRpcMessage::Response(error.to_response())) - .await - .is_err() - { - return; - } - continue; - } - }; - inner.record_activity(summarize_inbound_message(&message)); - - match message { - JsonRpcMessage::Response(response) => { - if let Some(pending) = inner - .pending - .lock() - .expect("pending lock poisoned") - .remove(&response.id) - { - let _ = pending.send(Ok(response)); - } - } - JsonRpcMessage::Request(request) => { - handle_inbound_request(Arc::clone(&inner), request).await; - } - JsonRpcMessage::Notification(notification) => { - let _ = inner.notification_tx.send(notification); - } - } - } - Ok(None) => { - *inner - .transport_state - .lock() - .expect("transport state lock poisoned") = String::from("transport_closed"); - inner.record_activity(String::from("process_exit transport_closed")); - break; - } - Err(error) => { - *inner - .transport_state - .lock() - .expect("transport state lock poisoned") = format!("transport_error {error}"); - inner.record_activity(format!("process_exit transport_error={error}")); - inner.fail_transport(AcpClientError::Io(format!( - "failed to read ACP frame: {error}" - ))); - return; - } - } - } - - tokio::time::sleep(EXIT_DRAIN_GRACE_MS).await; - if !inner.closed.load(Ordering::SeqCst) { - inner.fail_transport(AcpClientError::Closed(String::from("Agent process exited"))); - } -} - -async fn read_bounded_line( - reader: &mut BufReader, - max_read_line_bytes: usize, -) -> std::io::Result> -where - R: AsyncRead + Unpin, -{ - let mut line = Vec::new(); - - loop { - let available = reader.fill_buf().await?; - if available.is_empty() { - if line.is_empty() { - return Ok(None); - } - break; - } - - let (chunk, consume_len, line_complete) = - if let Some(newline_pos) = available.iter().position(|byte| *byte == b'\n') { - (&available[..newline_pos], newline_pos + 1, true) - } else { - (available, available.len(), false) - }; - - if line.len().saturating_add(chunk.len()) > max_read_line_bytes { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("ACP adapter emitted a line longer than {max_read_line_bytes} bytes"), - )); - } - - line.extend_from_slice(chunk); - reader.consume(consume_len); - - if line_complete { - break; - } - } - - if line.last() == Some(&b'\r') { - line.pop(); - } - - String::from_utf8(line) - .map(Some) - .map_err(|error| std::io::Error::new(std::io::ErrorKind::InvalidData, error)) -} - -async fn handle_inbound_request(inner: Arc, request: JsonRpcRequest) { - { - let mut seen = inner - .seen_inbound_request_ids - .lock() - .expect("seen request ids lock poisoned"); - if seen.contains(&request.id) { - return; - } - seen.insert(request.id.clone()); - } - - if request.method == ACP_PERMISSION_METHOD { - let params = to_record(request.params.clone()); - let permission_id = inner - .pending_permission_requests - .lock() - .expect("permission lock poisoned") - .insert(PendingPermissionRequest { - id: request.id.clone(), - method: request.method.clone(), - options: params - .get("options") - .and_then(Value::as_array) - .map(|items| { - items - .iter() - .filter_map(Value::as_object) - .cloned() - .collect::>() - }), - }); - - let mut notification_params = params; - notification_params.insert( - String::from("permissionId"), - Value::String(permission_id.clone()), - ); - notification_params.insert( - String::from("_acpMethod"), - Value::String(request.method.clone()), - ); - let _ = inner.notification_tx.send(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from(LEGACY_PERMISSION_METHOD), - params: Some(Value::Object(notification_params)), - }); - return; - } - - let mut notification_params = to_record(request.params.clone()); - notification_params.insert( - String::from("requestId"), - serde_json::to_value(&request.id).expect("serialize request id"), - ); - let _ = inner.notification_tx.send(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: request.method.clone(), - params: Some(Value::Object(notification_params)), - }); - - let handler = inner - .request_handler - .lock() - .expect("request handler lock poisoned") - .clone(); - let Some(handler) = handler else { - let response = method_not_found_response(&request); - if write_with_inner(&inner, JsonRpcMessage::Response(response)) - .await - .is_err() - { - return; - } - return; - }; - - let response = match tokio::time::timeout(inner.timeout, handler(request.clone())).await { - Ok(result) => match result { - Ok(Some(outcome)) if outcome.error.is_some() => JsonRpcResponse::error_response( - request.id, - outcome.error.expect("guard ensured error is present"), - ), - Ok(Some(outcome)) => { - JsonRpcResponse::success(request.id, outcome.result.unwrap_or(Value::Null)) - } - Ok(None) => method_not_found_response(&request), - Err(message) => JsonRpcResponse::error_response( - request.id, - JsonRpcError { - code: -32000, - message, - data: None, - }, - ), - }, - Err(_) => { - inner.record_activity(format!( - "timed out waiting for inbound host handler {} id={}", - request.method, request.id - )); - method_not_found_response(&request) - } - }; - - let _ = write_with_inner(&inner, JsonRpcMessage::Response(response)).await; -} - -#[cfg(test)] -impl AcpClient { - fn seen_inbound_request_id_count_for_tests(&self) -> usize { - self.inner - .seen_inbound_request_ids - .lock() - .expect("seen request ids lock poisoned") - .len() - } - - fn pending_permission_request_count_for_tests(&self) -> usize { - self.inner - .pending_permission_requests - .lock() - .expect("permission lock poisoned") - .len() - } - - fn recent_activity_for_tests(&self) -> Vec { - self.inner - .recent_activity - .lock() - .expect("recent activity lock poisoned") - .iter() - .cloned() - .collect() - } - - fn transport_state_for_tests(&self) -> String { - self.inner - .transport_state - .lock() - .expect("transport state lock poisoned") - .clone() - } -} - -fn method_not_found_response(request: &JsonRpcRequest) -> JsonRpcResponse { - JsonRpcResponse::error_response( - request.id.clone(), - JsonRpcError { - code: -32601, - message: format!("Method not found: {}", request.method), - data: None, - }, - ) -} - -async fn write_with_inner( - inner: &AcpClientInner, - message: JsonRpcMessage, -) -> Result<(), AcpClientError> { - let encoded = serialize_message(&message) - .map_err(|error| AcpClientError::Io(format!("failed to serialize ACP frame: {error}")))?; - let mut writer = inner.writer.lock().await; - writer - .write_all(encoded.as_bytes()) - .await - .map_err(|error| { - *inner - .transport_state - .lock() - .expect("transport state lock poisoned") = format!("transport_write_error {error}"); - inner.record_activity(format!("process_exit transport_write_error={error}")); - inner.fail_transport(AcpClientError::Io(format!( - "failed to write ACP frame: {error}" - ))) - })?; - writer.flush().await.map_err(|error| { - *inner - .transport_state - .lock() - .expect("transport state lock poisoned") = format!("transport_flush_error {error}"); - inner.record_activity(format!("process_exit transport_flush_error={error}")); - inner.fail_transport(AcpClientError::Io(format!( - "failed to flush ACP frame: {error}" - ))) - })?; - Ok(()) -} - -fn normalize_permission_result( - params: &Map, - pending: &PendingPermissionRequest, -) -> Value { - if let Some(outcome) = params.get("outcome") { - if outcome.is_object() { - return json!({ "outcome": outcome }); - } - } - - let requested_reply = params.get("reply").and_then(Value::as_str); - if let Some(selected_option_id) = - resolve_permission_option_id(&pending.options, requested_reply) - { - return json!({ - "outcome": { - "outcome": "selected", - "optionId": selected_option_id, - } - }); - } - - match requested_reply { - Some("always") => json!({ - "outcome": { - "outcome": "selected", - "optionId": "allow_always", - } - }), - Some("once") => json!({ - "outcome": { - "outcome": "selected", - "optionId": "allow_once", - } - }), - Some("reject") => json!({ - "outcome": { - "outcome": "selected", - "optionId": "reject_once", - } - }), - _ => json!({ - "outcome": { - "outcome": "cancelled", - } - }), - } -} - -fn resolve_permission_option_id( - options: &Option>>, - reply: Option<&str>, -) -> Option { - let reply = reply?; - let targets = match reply { - "always" => (["always", "allow_always"], ["allow_always"]), - "once" => (["once", "allow_once"], ["allow_once"]), - "reject" => (["reject", "reject_once"], ["reject_once"]), - _ => return None, - }; - - let options = options.as_ref()?; - let matched = options.iter().find(|option| { - let option_id_matches = option - .get("optionId") - .and_then(Value::as_str) - .map(|value| targets.0.contains(&value)) - .unwrap_or(false); - let kind_matches = option - .get("kind") - .and_then(Value::as_str) - .map(|value| targets.1.contains(&value)) - .unwrap_or(false); - option_id_matches || kind_matches - })?; - - matched - .get("optionId") - .and_then(Value::as_str) - .map(String::from) -} - -fn is_cancel_method_not_found(response: &JsonRpcResponse) -> bool { - let Some(error) = response.error() else { - return false; - }; - if error.code != -32601 { - return false; - } - - if let Some(data) = error.data.as_ref().and_then(Value::as_object) { - if data - .get("method") - .and_then(Value::as_str) - .is_some_and(|method| method == ACP_CANCEL_METHOD) - { - return true; - } - } - - error.message.contains(ACP_CANCEL_METHOD) -} - -fn to_record(value: Option) -> Map { - match value { - Some(Value::Object(map)) => map, - _ => Map::new(), - } -} - -fn timeout_cancel_params(method: &str, params: Option<&Value>) -> Option { - if method == ACP_CANCEL_METHOD { - return None; - } - - let params = params?.as_object()?; - let session_id = params.get("sessionId")?.clone(); - Some(json!({ "sessionId": session_id })) -} - -fn truncate_activity_text(value: &str) -> String { - if value.len() <= ACTIVITY_TEXT_LIMIT { - return String::from(value); - } - format!("{}...", &value[..ACTIVITY_TEXT_LIMIT]) -} - -fn summarize_inbound_message(message: &JsonRpcMessage) -> String { - match message { - JsonRpcMessage::Response(response) => match response.error() { - Some(error) => truncate_activity_text(&format!( - "received response id={} error={}:{}", - response.id, error.code, error.message - )), - None => format!("received response id={}", response.id), - }, - JsonRpcMessage::Request(request) => truncate_activity_text(&format!( - "received request {} id={}", - request.method, request.id - )), - JsonRpcMessage::Notification(notification) => { - truncate_activity_text(&format!("received notification {}", notification.method)) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use tokio::io::{split, AsyncBufReadExt, AsyncWriteExt, BufReader}; - use tokio::time::timeout; - - #[tokio::test(flavor = "current_thread")] - async fn client_seen_request_ids_stay_bounded_after_many_unique_requests() { - let (client_stream, server_stream) = tokio::io::duplex(256 * 1024); - let (client_reader, client_writer) = split(client_stream); - let (server_reader, mut server_writer) = split(server_stream); - let client = AcpClient::new(client_reader, client_writer, AcpClientOptions::default()); - - let response_drain = tokio::spawn(async move { - let mut lines = BufReader::new(server_reader).lines(); - let mut responses = 0usize; - while responses < 100_000 { - let line = lines - .next_line() - .await - .expect("read response line") - .expect("response line should exist"); - let message = crate::acp::deserialize_message(&line).expect("decode response"); - match message { - JsonRpcMessage::Response(_) => responses += 1, - other => { - panic!("unexpected outbound frame while draining responses: {other:?}") - } - } - } - }); - - for request_id in 0..100_000 { - let message = JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(request_id), - method: String::from("fs/read_text_file"), - params: Some(json!({ "path": format!("/tmp/{request_id}.txt") })), - }); - let encoded = serialize_message(&message).expect("encode request"); - server_writer - .write_all(encoded.as_bytes()) - .await - .expect("write request"); - } - server_writer.flush().await.expect("flush requests"); - - response_drain.await.expect("response drain"); - assert_eq!( - client.seen_inbound_request_id_count_for_tests(), - crate::acp::compat::SEEN_INBOUND_REQUEST_ID_RETENTION_LIMIT - ); - } - - #[tokio::test(flavor = "current_thread")] - async fn client_pending_permission_requests_stay_bounded_with_seen_request_ids() { - let (client_stream, server_stream) = tokio::io::duplex(8 * 1024); - let (client_reader, client_writer) = split(client_stream); - let (_server_reader, mut server_writer) = split(server_stream); - let client = AcpClient::new(client_reader, client_writer, AcpClientOptions::default()); - let mut notifications = client.subscribe_notifications(); - - for request_id in 0..=crate::acp::compat::PENDING_PERMISSION_REQUEST_RETENTION_LIMIT { - let message = JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(request_id as i64), - method: String::from("session/request_permission"), - params: Some(json!({ "path": format!("/tmp/{request_id}.txt") })), - }); - let encoded = serialize_message(&message).expect("encode request"); - server_writer - .write_all(encoded.as_bytes()) - .await - .expect("write request"); - server_writer.flush().await.expect("flush request"); - let notification = notifications.recv().await.expect("permission notification"); - assert_eq!(notification.method, LEGACY_PERMISSION_METHOD); - } - - assert_eq!( - client.seen_inbound_request_id_count_for_tests(), - crate::acp::compat::SEEN_INBOUND_REQUEST_ID_RETENTION_LIMIT - ); - assert_eq!( - client.pending_permission_request_count_for_tests(), - crate::acp::compat::PENDING_PERMISSION_REQUEST_RETENTION_LIMIT - ); - } - - #[tokio::test(flavor = "current_thread")] - async fn client_permission_reply_survives_unrelated_seen_request_id_eviction() { - let (client_stream, server_stream) = tokio::io::duplex(16 * 1024); - let (client_reader, client_writer) = split(client_stream); - let (server_reader, mut server_writer) = split(server_stream); - let client = AcpClient::new(client_reader, client_writer, AcpClientOptions::default()); - let mut notifications = client.subscribe_notifications(); - let mut outbound_lines = BufReader::new(server_reader).lines(); - - let permission_request = JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::String(String::from("perm-late")), - method: String::from("session/request_permission"), - params: Some(json!({ "path": "/tmp/late.txt" })), - }); - let encoded = serialize_message(&permission_request).expect("encode permission request"); - server_writer - .write_all(encoded.as_bytes()) - .await - .expect("write permission request"); - server_writer - .flush() - .await - .expect("flush permission request"); - let notification = notifications.recv().await.expect("permission notification"); - assert_eq!(notification.method, LEGACY_PERMISSION_METHOD); - - for request_id in 0..=crate::acp::compat::SEEN_INBOUND_REQUEST_ID_RETENTION_LIMIT { - let message = JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(request_id as i64), - method: String::from("fs/read_text_file"), - params: Some(json!({ "path": format!("/tmp/{request_id}.txt") })), - }); - let encoded = serialize_message(&message).expect("encode request"); - server_writer - .write_all(encoded.as_bytes()) - .await - .expect("write request"); - server_writer.flush().await.expect("flush request"); - outbound_lines - .next_line() - .await - .expect("read method-not-found response") - .expect("method-not-found response should exist"); - } - - let permission_response = client - .request( - "request/permission", - Some(json!({ - "permissionId": "perm-late", - "reply": "once", - })), - ) - .await - .expect("late permission response should still match pending request"); - assert_eq!( - permission_response.result(), - Some(&json!({ - "outcome": { - "outcome": "selected", - "optionId": "allow_once", - } - })) - ); - - let outbound_permission = outbound_lines - .next_line() - .await - .expect("read permission response") - .expect("permission response should exist"); - let outbound_permission = - crate::acp::deserialize_message(&outbound_permission).expect("decode response"); - match outbound_permission { - JsonRpcMessage::Response(response) => { - assert_eq!(response.id, JsonRpcId::String(String::from("perm-late"))); - } - other => panic!("unexpected outbound permission frame: {other:?}"), - } - } - - #[tokio::test(flavor = "current_thread")] - async fn client_permission_ids_are_collision_safe_for_string_and_number_ids() { - let (client_stream, server_stream) = tokio::io::duplex(8 * 1024); - let (client_reader, client_writer) = split(client_stream); - let (server_reader, mut server_writer) = split(server_stream); - let client = AcpClient::new(client_reader, client_writer, AcpClientOptions::default()); - let mut notifications = client.subscribe_notifications(); - let mut outbound_lines = BufReader::new(server_reader).lines(); - - for id in [JsonRpcId::Number(1), JsonRpcId::String(String::from("1"))] { - let message = JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id, - method: String::from("session/request_permission"), - params: Some(json!({ "path": "/tmp/collide.txt" })), - }); - let encoded = serialize_message(&message).expect("encode permission request"); - server_writer - .write_all(encoded.as_bytes()) - .await - .expect("write permission request"); - server_writer - .flush() - .await - .expect("flush permission request"); - } - - let first = notifications.recv().await.expect("first permission"); - let second = notifications.recv().await.expect("second permission"); - let first_permission_id = first - .params - .as_ref() - .and_then(|params| params.get("permissionId")) - .and_then(Value::as_str) - .expect("first permission id"); - let second_permission_id = second - .params - .as_ref() - .and_then(|params| params.get("permissionId")) - .and_then(Value::as_str) - .expect("second permission id"); - assert_eq!(first_permission_id, "1"); - assert_ne!(second_permission_id, "1"); - - let second_response = client - .request( - "request/permission", - Some(json!({ - "permissionId": second_permission_id, - "reply": "reject", - })), - ) - .await - .expect("second permission response should match string id"); - assert_eq!( - second_response.result(), - Some(&json!({ - "outcome": { - "outcome": "selected", - "optionId": "reject_once", - } - })) - ); - let outbound_second = outbound_lines - .next_line() - .await - .expect("read second permission response") - .expect("second permission response should exist"); - match crate::acp::deserialize_message(&outbound_second).expect("decode response") { - JsonRpcMessage::Response(response) => { - assert_eq!(response.id, JsonRpcId::String(String::from("1"))); - } - other => panic!("unexpected second permission frame: {other:?}"), - } - - client - .request( - "request/permission", - Some(json!({ - "permissionId": first_permission_id, - "reply": "reject", - })), - ) - .await - .expect("first permission response should still match number id"); - let outbound_first = outbound_lines - .next_line() - .await - .expect("read first permission response") - .expect("first permission response should exist"); - match crate::acp::deserialize_message(&outbound_first).expect("decode response") { - JsonRpcMessage::Response(response) => { - assert_eq!(response.id, JsonRpcId::Number(1)); - } - other => panic!("unexpected first permission frame: {other:?}"), - } - } - - #[tokio::test(flavor = "current_thread")] - async fn client_fails_when_adapter_emits_a_line_longer_than_the_configured_limit() { - const MAX_READ_LINE_BYTES: usize = 16 * 1024 * 1024; - const OVERSIZED_LINE_BYTES: usize = 20 * 1024 * 1024; - - let (client_stream, server_stream) = tokio::io::duplex(OVERSIZED_LINE_BYTES + 1024); - let (client_reader, client_writer) = split(client_stream); - let (server_reader, mut server_writer) = split(server_stream); - let client = AcpClient::new( - client_reader, - client_writer, - AcpClientOptions { - max_read_line_bytes: MAX_READ_LINE_BYTES, - ..AcpClientOptions::default() - }, - ); - let mut outbound_lines = BufReader::new(server_reader).lines(); - - let pending_request = tokio::spawn({ - let client = client.clone(); - async move { - client - .request( - "session/prompt", - Some(json!({ "sessionId": "oversized-line" })), - ) - .await - } - }); - - let outbound_request = outbound_lines - .next_line() - .await - .expect("read outbound request") - .expect("outbound request should exist"); - let outbound_request = - crate::acp::deserialize_message(&outbound_request).expect("decode outbound request"); - match outbound_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "session/prompt"); - } - other => panic!("unexpected outbound frame: {other:?}"), - } - - let oversized_writer = tokio::spawn(async move { - let chunk = vec![b'x'; 1024 * 1024]; - let mut remaining = OVERSIZED_LINE_BYTES; - while remaining > 0 { - let next = remaining.min(chunk.len()); - server_writer - .write_all(&chunk[..next]) - .await - .map_err(|error| error.kind())?; - remaining -= next; - } - server_writer - .write_all(b"\n") - .await - .map_err(|error| error.kind())?; - server_writer.flush().await.map_err(|error| error.kind()) - }); - - let pending_error = timeout(Duration::from_secs(5), pending_request) - .await - .expect("pending request timeout") - .expect("pending request join") - .expect_err("oversized line should fail the client"); - assert!( - matches!(pending_error, AcpClientError::Io(_)), - "unexpected error: {pending_error:?}" - ); - assert!( - pending_error - .to_string() - .contains("ACP adapter emitted a line longer than"), - "unexpected oversized-line error: {pending_error}" - ); - - let transport_state = client.transport_state_for_tests(); - assert!(transport_state.contains("transport_error")); - assert!( - client - .recent_activity_for_tests() - .iter() - .any(|entry| entry.contains("transport_error")), - "recent activity should capture a transport_error entry" - ); - - let subsequent_error = client - .request( - "session/prompt", - Some(json!({ "sessionId": "after-oversized-line" })), - ) - .await - .expect_err("subsequent request should fail immediately"); - assert_eq!(subsequent_error.to_string(), pending_error.to_string()); - - let oversized_writer_result = timeout(Duration::from_secs(1), oversized_writer) - .await - .expect("oversized writer timeout") - .expect("oversized writer join"); - assert!( - oversized_writer_result.is_ok() - || oversized_writer_result == Err(std::io::ErrorKind::BrokenPipe), - "unexpected oversized writer result: {oversized_writer_result:?}" - ); - } -} diff --git a/crates/sidecar/tests/acp_legacy/compat.rs b/crates/sidecar/tests/acp_legacy/compat.rs deleted file mode 100644 index bb1aea531..000000000 --- a/crates/sidecar/tests/acp_legacy/compat.rs +++ /dev/null @@ -1,615 +0,0 @@ -use crate::json_rpc::{JsonRpcId, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse}; -use serde_json::{json, Map, Value}; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; - -pub(crate) const LEGACY_PERMISSION_METHOD: &str = "request/permission"; -pub(crate) const ACP_PERMISSION_METHOD: &str = "session/request_permission"; -pub(crate) const ACP_CANCEL_METHOD: &str = "session/cancel"; -pub(crate) const RECENT_ACTIVITY_LIMIT: usize = 20; -pub(crate) const ACTIVITY_TEXT_LIMIT: usize = 240; -pub(crate) const SEEN_INBOUND_REQUEST_ID_RETENTION_LIMIT: usize = 4_096; -pub(crate) const PENDING_PERMISSION_REQUEST_RETENTION_LIMIT: usize = 4_096; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum AgentCompatibilityKind { - Generic, - OpenCode, -} - -#[derive(Debug, Clone)] -pub(crate) struct PendingPermissionRequest { - pub(crate) id: JsonRpcId, - pub(crate) method: String, - pub(crate) options: Option>>, -} - -#[derive(Debug, Clone)] -pub(crate) struct PendingPermissionRequests { - pending: BTreeMap, - permission_ids: BTreeMap, - order: VecDeque, - limit: usize, -} - -impl PendingPermissionRequests { - pub(crate) fn new(limit: usize) -> Self { - Self { - pending: BTreeMap::new(), - permission_ids: BTreeMap::new(), - order: VecDeque::new(), - limit, - } - } - - pub(crate) fn insert(&mut self, request: PendingPermissionRequest) -> String { - self.remove_existing_permission_id(&request.id); - if !self.pending.contains_key(&request.id) { - self.order.push_back(request.id.clone()); - } - let permission_id = self.assign_permission_id(&request.id); - let request_id = request.id.clone(); - self.pending.insert(request.id.clone(), request); - self.permission_ids - .insert(permission_id.clone(), request_id); - self.evict_oldest(); - permission_id - } - - pub(crate) fn remove_by_permission_id( - &mut self, - permission_id: &str, - ) -> Option { - let id = self.permission_ids.remove(permission_id)?; - self.order.retain(|existing| existing != &id); - self.pending.remove(&id) - } - - pub(crate) fn clear(&mut self) { - self.pending.clear(); - self.permission_ids.clear(); - self.order.clear(); - } - - #[cfg_attr(not(test), allow(dead_code))] - pub(crate) fn len(&self) -> usize { - self.pending.len() - } - - #[cfg(test)] - pub(crate) fn contains_id(&self, id: &JsonRpcId) -> bool { - self.pending.contains_key(id) - } - - fn evict_oldest(&mut self) { - while self.order.len() > self.limit { - if let Some(oldest) = self.order.pop_front() { - self.pending.remove(&oldest); - self.remove_existing_permission_id(&oldest); - } - } - } - - fn assign_permission_id(&self, id: &JsonRpcId) -> String { - let display_id = id.to_string(); - if !self.permission_ids.contains_key(&display_id) { - return display_id; - } - - let encoded = serde_json::to_string(id).expect("JSON-RPC id should serialize"); - let mut candidate = format!("jsonrpc:{encoded}"); - let mut suffix = 2usize; - while self.permission_ids.contains_key(&candidate) { - candidate = format!("jsonrpc:{encoded}:{suffix}"); - suffix += 1; - } - candidate - } - - fn remove_existing_permission_id(&mut self, id: &JsonRpcId) { - let existing = self - .permission_ids - .iter() - .find_map(|(permission_id, pending_id)| { - if pending_id == id { - Some(permission_id.clone()) - } else { - None - } - }); - if let Some(permission_id) = existing { - self.permission_ids.remove(&permission_id); - } - } -} - -impl Default for PendingPermissionRequests { - fn default() -> Self { - Self::new(PENDING_PERMISSION_REQUEST_RETENTION_LIMIT) - } -} - -#[derive(Debug, Clone)] -pub(crate) struct SeenInboundRequestIds { - seen: BTreeSet, - order: VecDeque, - limit: usize, -} - -impl SeenInboundRequestIds { - pub(crate) fn new(limit: usize) -> Self { - Self { - seen: BTreeSet::new(), - order: VecDeque::new(), - limit, - } - } - - pub(crate) fn contains(&self, id: &JsonRpcId) -> bool { - self.seen.contains(id) - } - - pub(crate) fn insert(&mut self, id: JsonRpcId) { - if !self.seen.insert(id.clone()) { - return; - } - self.order.push_back(id); - self.evict_oldest(); - } - - pub(crate) fn clear(&mut self) { - self.seen.clear(); - self.order.clear(); - } - - #[cfg_attr(not(test), allow(dead_code))] - pub(crate) fn len(&self) -> usize { - self.seen.len() - } - - fn evict_oldest(&mut self) { - while self.order.len() > self.limit { - if let Some(oldest) = self.order.pop_front() { - self.seen.remove(&oldest); - } - } - } -} - -impl Default for SeenInboundRequestIds { - fn default() -> Self { - Self::new(SEEN_INBOUND_REQUEST_ID_RETENTION_LIMIT) - } -} - -pub(crate) fn compatibility_for(agent_type: &str) -> AgentCompatibilityKind { - match agent_type { - "opencode" => AgentCompatibilityKind::OpenCode, - _ => AgentCompatibilityKind::Generic, - } -} - -pub(crate) fn normalize_inbound_permission_request( - request: &JsonRpcRequest, - seen_inbound_request_ids: &mut SeenInboundRequestIds, - pending_permission_requests: &mut PendingPermissionRequests, -) -> Option { - if request.method != ACP_PERMISSION_METHOD { - return None; - } - - if seen_inbound_request_ids.contains(&request.id) { - return None; - } - seen_inbound_request_ids.insert(request.id.clone()); - - let params = to_record(request.params.clone()); - let permission_id = pending_permission_requests.insert(PendingPermissionRequest { - id: request.id.clone(), - method: request.method.clone(), - options: params - .get("options") - .and_then(Value::as_array) - .map(|items| { - items - .iter() - .filter_map(Value::as_object) - .cloned() - .collect::>() - }), - }); - - let mut normalized = params; - normalized.insert(String::from("permissionId"), Value::String(permission_id)); - normalized.insert( - String::from("_acpMethod"), - Value::String(request.method.clone()), - ); - Some(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from(LEGACY_PERMISSION_METHOD), - params: Some(Value::Object(normalized)), - }) -} - -pub(crate) fn maybe_normalize_permission_response( - method: &str, - params: Option, - pending_permission_requests: &mut PendingPermissionRequests, -) -> Option<(JsonRpcId, Value)> { - if method != LEGACY_PERMISSION_METHOD && method != ACP_PERMISSION_METHOD { - return None; - } - - let payload = to_record(params); - let permission_id = match payload.get("permissionId") { - Some(Value::String(value)) => value.clone(), - Some(Value::Number(value)) => value.to_string(), - _ => return None, - }; - - let pending = pending_permission_requests.remove_by_permission_id(&permission_id)?; - if pending.method != ACP_PERMISSION_METHOD { - return None; - } - - Some(( - pending.id.clone(), - normalize_permission_result(&payload, &pending), - )) -} - -pub(crate) fn is_cancel_method_not_found(response: &JsonRpcResponse) -> bool { - let Some(error) = response.error() else { - return false; - }; - if error.code != -32601 { - return false; - } - - if let Some(data) = error.data.as_ref().and_then(Value::as_object) { - if data - .get("method") - .and_then(Value::as_str) - .is_some_and(|method| method == ACP_CANCEL_METHOD) - { - return true; - } - } - - error.message.contains(ACP_CANCEL_METHOD) -} - -pub(crate) fn derive_config_options( - agent_type: &str, - session_result: &Map, -) -> Vec { - let Some(models) = session_result.get("models").and_then(Value::as_object) else { - return Vec::new(); - }; - let current_model_id = models - .get("currentModelId") - .and_then(Value::as_str) - .map(String::from); - let allowed_values = models - .get("availableModels") - .and_then(Value::as_array) - .map(|models| { - models - .iter() - .filter_map(Value::as_object) - .filter_map(|model| { - let model_id = model.get("modelId")?.as_str()?; - let mut item = Map::from_iter([( - String::from("id"), - Value::String(String::from(model_id)), - )]); - if let Some(name) = model.get("name").and_then(Value::as_str) { - item.insert(String::from("label"), Value::String(String::from(name))); - } - Some(Value::Object(item)) - }) - .collect::>() - }) - .unwrap_or_default(); - if current_model_id.is_none() && allowed_values.is_empty() { - return Vec::new(); - } - - let mut option = Map::from_iter([ - (String::from("id"), Value::String(String::from("model"))), - ( - String::from("category"), - Value::String(String::from("model")), - ), - (String::from("label"), Value::String(String::from("Model"))), - (String::from("allowedValues"), Value::Array(allowed_values)), - ( - String::from("readOnly"), - Value::Bool(matches!( - compatibility_for(agent_type), - AgentCompatibilityKind::OpenCode - )), - ), - ]); - if let Some(current_model_id) = current_model_id { - option.insert( - String::from("currentValue"), - Value::String(current_model_id), - ); - } - if matches!( - compatibility_for(agent_type), - AgentCompatibilityKind::OpenCode - ) { - option.insert( - String::from("description"), - Value::String(String::from( - "Available models reported by OpenCode. Model switching must be configured before createSession() because ACP session/set_config_option is not implemented.", - )), - ); - } - - vec![Value::Object(option)] -} - -pub(crate) fn synthetic_mode_update(mode_id: &str) -> JsonRpcNotification { - JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from("session/update"), - params: Some(json!({ - "update": { - "sessionUpdate": "current_mode_update", - "currentModeId": mode_id, - } - })), - } -} - -pub(crate) fn synthetic_config_update(config_options: &[Value]) -> JsonRpcNotification { - JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from("session/update"), - params: Some(json!({ - "update": { - "sessionUpdate": "config_option_update", - "configOptions": config_options, - } - })), - } -} - -pub(crate) fn truncate_activity_text(value: &str) -> String { - if value.len() <= ACTIVITY_TEXT_LIMIT { - return String::from(value); - } - format!("{}...", &value[..ACTIVITY_TEXT_LIMIT]) -} - -pub(crate) fn summarize_inbound_notification(notification: &JsonRpcNotification) -> String { - truncate_activity_text(&format!("received notification {}", notification.method)) -} - -pub(crate) fn summarize_inbound_request(request: &JsonRpcRequest) -> String { - truncate_activity_text(&format!( - "received request {} id={}", - request.method, request.id - )) -} - -pub(crate) fn summarize_inbound_response(response: &JsonRpcResponse) -> String { - match response.error() { - Some(error) => truncate_activity_text(&format!( - "received response id={} error={}:{}", - response.id, error.code, error.message - )), - None => format!("received response id={}", response.id), - } -} - -fn normalize_permission_result( - params: &Map, - pending: &PendingPermissionRequest, -) -> Value { - if let Some(outcome) = params.get("outcome") { - if outcome.is_object() { - return json!({ "outcome": outcome }); - } - } - - let requested_reply = params.get("reply").and_then(Value::as_str); - if let Some(selected_option_id) = - resolve_permission_option_id(&pending.options, requested_reply) - { - return json!({ - "outcome": { - "outcome": "selected", - "optionId": selected_option_id, - } - }); - } - - match requested_reply { - Some("always") => { - json!({ "outcome": { "outcome": "selected", "optionId": "allow_always" } }) - } - Some("once") => json!({ "outcome": { "outcome": "selected", "optionId": "allow_once" } }), - Some("reject") => { - json!({ "outcome": { "outcome": "selected", "optionId": "reject_once" } }) - } - _ => json!({ "outcome": { "outcome": "cancelled" } }), - } -} - -fn resolve_permission_option_id( - options: &Option>>, - reply: Option<&str>, -) -> Option { - let reply = reply?; - let targets = match reply { - "always" => (["always", "allow_always"], ["allow_always"]), - "once" => (["once", "allow_once"], ["allow_once"]), - "reject" => (["reject", "reject_once"], ["reject_once"]), - _ => return None, - }; - - let options = options.as_ref()?; - let matched = options.iter().find(|option| { - let option_id_matches = option - .get("optionId") - .and_then(Value::as_str) - .map(|value| targets.0.contains(&value)) - .unwrap_or(false); - let kind_matches = option - .get("kind") - .and_then(Value::as_str) - .map(|value| targets.1.contains(&value)) - .unwrap_or(false); - option_id_matches || kind_matches - })?; - - matched - .get("optionId") - .and_then(Value::as_str) - .map(String::from) -} - -pub(crate) fn to_record(value: Option) -> Map { - match value { - Some(Value::Object(map)) => map, - _ => Map::new(), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn seen_inbound_request_ids_evict_oldest_entry_after_retention_window() { - let mut seen = SeenInboundRequestIds::new(2); - let first = JsonRpcId::Number(1); - let second = JsonRpcId::Number(2); - let third = JsonRpcId::Number(3); - - seen.insert(first.clone()); - seen.insert(second.clone()); - assert!(seen.contains(&first)); - assert!(seen.contains(&second)); - - seen.insert(third.clone()); - assert_eq!(seen.len(), 2); - assert!(!seen.contains(&first)); - assert!(seen.contains(&second)); - assert!(seen.contains(&third)); - } - - #[test] - fn permission_requests_evict_pending_entries_with_seen_request_window() { - let mut seen = SeenInboundRequestIds::new(2); - let mut pending = PendingPermissionRequests::new(2); - - for request_id in 1..=3 { - let request = JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(request_id), - method: String::from("session/request_permission"), - params: Some(json!({ "path": format!("/tmp/{request_id}.txt") })), - }; - let notification = - normalize_inbound_permission_request(&request, &mut seen, &mut pending) - .expect("permission request should normalize"); - assert_eq!(notification.method, LEGACY_PERMISSION_METHOD); - } - - assert_eq!(seen.len(), 2); - assert_eq!(pending.len(), 2); - assert!(!pending.contains_id(&JsonRpcId::Number(1))); - assert!(pending.contains_id(&JsonRpcId::Number(2))); - assert!(pending.contains_id(&JsonRpcId::Number(3))); - } - - #[test] - fn pending_permission_eviction_uses_typed_json_rpc_ids() { - let mut pending = PendingPermissionRequests::new(2); - - for id in [ - JsonRpcId::Number(1), - JsonRpcId::String(String::from("1")), - JsonRpcId::Number(2), - ] { - pending.insert(PendingPermissionRequest { - id, - method: String::from(ACP_PERMISSION_METHOD), - options: None, - }); - } - - assert_eq!(pending.len(), 2); - assert!(!pending.contains_id(&JsonRpcId::Number(1))); - assert!(pending.contains_id(&JsonRpcId::String(String::from("1")))); - assert!(pending.contains_id(&JsonRpcId::Number(2))); - } - - #[test] - fn permission_ids_are_collision_safe_for_string_and_number_ids() { - let mut seen = SeenInboundRequestIds::new(4); - let mut pending = PendingPermissionRequests::new(4); - - let number_request = JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(1), - method: String::from("session/request_permission"), - params: Some(json!({ "path": "/tmp/number.txt" })), - }; - let string_request = JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::String(String::from("1")), - method: String::from("session/request_permission"), - params: Some(json!({ "path": "/tmp/string.txt" })), - }; - - let number_notification = - normalize_inbound_permission_request(&number_request, &mut seen, &mut pending) - .expect("number permission request should normalize"); - let string_notification = - normalize_inbound_permission_request(&string_request, &mut seen, &mut pending) - .expect("string permission request should normalize"); - - let number_permission_id = number_notification - .params - .as_ref() - .and_then(|params| params.get("permissionId")) - .and_then(Value::as_str) - .expect("number permission id"); - let string_permission_id = string_notification - .params - .as_ref() - .and_then(|params| params.get("permissionId")) - .and_then(Value::as_str) - .expect("string permission id"); - assert_eq!(number_permission_id, "1"); - assert_ne!(string_permission_id, "1"); - - let (string_reply_id, _) = maybe_normalize_permission_response( - LEGACY_PERMISSION_METHOD, - Some(json!({ - "permissionId": string_permission_id, - "reply": "reject", - })), - &mut pending, - ) - .expect("string permission reply should resolve"); - assert_eq!(string_reply_id, JsonRpcId::String(String::from("1"))); - - let (number_reply_id, _) = maybe_normalize_permission_response( - LEGACY_PERMISSION_METHOD, - Some(json!({ - "permissionId": number_permission_id, - "reply": "reject", - })), - &mut pending, - ) - .expect("number permission reply should resolve"); - assert_eq!(number_reply_id, JsonRpcId::Number(1)); - } -} diff --git a/crates/sidecar/tests/acp_legacy/mod.rs b/crates/sidecar/tests/acp_legacy/mod.rs deleted file mode 100644 index d5a81eaaa..000000000 --- a/crates/sidecar/tests/acp_legacy/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -mod client; -pub(crate) mod compat; -pub(crate) mod session; -mod timeout; - -pub use crate::json_rpc::{ - deserialize_message, is_request, is_response, serialize_message, JsonRpcError, JsonRpcId, - JsonRpcMessage, JsonRpcNotification, JsonRpcParseError, JsonRpcParseErrorKind, JsonRpcRequest, - JsonRpcResponse, JsonRpcResponseShapeError, -}; -pub use client::{ - AcpClient, AcpClientError, AcpClientOptions, AcpClientProcessState, - AcpClientProcessStateProvider, InboundRequestHandler, InboundRequestOutcome, -}; -pub(crate) use timeout::AcpTimeoutDiagnostics; diff --git a/crates/sidecar/tests/acp_legacy/session.rs b/crates/sidecar/tests/acp_legacy/session.rs deleted file mode 100644 index 7a42002c2..000000000 --- a/crates/sidecar/tests/acp_legacy/session.rs +++ /dev/null @@ -1,506 +0,0 @@ -use crate::acp::compat::{ - derive_config_options, synthetic_config_update, synthetic_mode_update, - PendingPermissionRequests, SeenInboundRequestIds, RECENT_ACTIVITY_LIMIT, -}; -use crate::acp::AcpTimeoutDiagnostics; -use crate::acp::{JsonRpcError, JsonRpcId, JsonRpcNotification}; -use serde_json::{Map, Value}; -use std::collections::{BTreeMap, VecDeque}; -use std::fmt; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct SessionCreatedResponse { - pub(crate) session_id: String, - pub(crate) pid: Option, - pub(crate) modes: Option, - pub(crate) config_options: Vec, - pub(crate) agent_capabilities: Option, - pub(crate) agent_info: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct SessionStateResponse { - pub(crate) session_id: String, - pub(crate) agent_type: String, - pub(crate) process_id: String, - pub(crate) pid: Option, - pub(crate) closed: bool, - pub(crate) modes: Option, - pub(crate) config_options: Vec, - pub(crate) agent_capabilities: Option, - pub(crate) agent_info: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum AcpSessionStateError { - InvalidConfigOptionParams(String), - MalformedConfigOptionEntry { index: usize, reason: String }, - UnknownConfigOption(String), -} - -impl AcpSessionStateError { - fn invalid_config_option_params(message: impl Into) -> Self { - Self::InvalidConfigOptionParams(message.into()) - } - - fn malformed_config_option_entry(index: usize, reason: impl Into) -> Self { - Self::MalformedConfigOptionEntry { - index, - reason: reason.into(), - } - } - - fn unknown_config_option(config_id: impl Into) -> Self { - Self::UnknownConfigOption(config_id.into()) - } - - pub(crate) fn to_json_rpc_error(&self, method: &str) -> JsonRpcError { - match self { - Self::InvalidConfigOptionParams(message) => JsonRpcError { - code: -32602, - message: format!("Invalid params for {method}: {message}"), - data: Some(serde_json::json!({ - "kind": "invalid_config_option_params", - "method": method, - })), - }, - Self::MalformedConfigOptionEntry { index, reason } => JsonRpcError { - code: -32602, - message: format!( - "Invalid params for {method}: config option entry {index} is malformed: {reason}" - ), - data: Some(serde_json::json!({ - "kind": "malformed_config_option_entry", - "method": method, - "index": index, - })), - }, - Self::UnknownConfigOption(config_id) => JsonRpcError { - code: -32602, - message: format!("Invalid params for {method}: unknown config option {config_id}"), - data: Some(serde_json::json!({ - "kind": "unknown_config_option", - "method": method, - "configId": config_id, - })), - }, - } - } -} - -impl fmt::Display for AcpSessionStateError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InvalidConfigOptionParams(message) => f.write_str(message), - Self::MalformedConfigOptionEntry { index, reason } => { - write!(f, "config option entry {index} is malformed: {reason}") - } - Self::UnknownConfigOption(config_id) => { - write!(f, "unknown config option {config_id}") - } - } - } -} - -impl std::error::Error for AcpSessionStateError {} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum AcpInitializeError { - MissingProtocolVersion, - InvalidProtocolVersion, - ProtocolVersionMismatch { requested: u64, reported: u64 }, -} - -impl fmt::Display for AcpInitializeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::MissingProtocolVersion => { - f.write_str("ACP initialize response missing protocolVersion") - } - Self::InvalidProtocolVersion => { - f.write_str("ACP initialize response protocolVersion must be an unsigned integer") - } - Self::ProtocolVersionMismatch { - requested, - reported, - } => write!( - f, - "ACP initialize protocolVersion mismatch: requested {requested}, agent reported {reported}" - ), - } - } -} - -impl std::error::Error for AcpInitializeError {} - -pub(crate) fn build_initialize_request( - protocol_version: u64, - client_capabilities: Value, -) -> crate::acp::JsonRpcRequest { - crate::acp::JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(1), - method: String::from("initialize"), - params: Some(serde_json::json!({ - "protocolVersion": protocol_version, - "clientCapabilities": client_capabilities, - })), - } -} - -pub(crate) fn validate_initialize_result( - init_result: &Map, - requested_protocol_version: u64, -) -> Result { - let reported_protocol_version = init_result - .get("protocolVersion") - .ok_or(AcpInitializeError::MissingProtocolVersion)? - .as_u64() - .ok_or(AcpInitializeError::InvalidProtocolVersion)?; - - if reported_protocol_version != requested_protocol_version { - return Err(AcpInitializeError::ProtocolVersionMismatch { - requested: requested_protocol_version, - reported: reported_protocol_version, - }); - } - - Ok(reported_protocol_version) -} - -#[derive(Debug, Clone)] -pub(crate) struct AcpTerminalState { - pub(crate) process_id: String, - pub(crate) output: String, - pub(crate) truncated: bool, - pub(crate) output_byte_limit: usize, - pub(crate) exit_code: Option, - pub(crate) released: bool, -} - -impl AcpTerminalState { - pub(crate) fn new(process_id: String, output_byte_limit: usize) -> Self { - Self { - process_id, - output: String::new(), - truncated: false, - output_byte_limit, - exit_code: None, - released: false, - } - } - - pub(crate) fn append_output(&mut self, chunk: &[u8]) { - self.output.push_str(&String::from_utf8_lossy(chunk)); - if self.output_byte_limit == 0 { - self.output.clear(); - self.truncated = true; - return; - } - - while self.output.len() > self.output_byte_limit { - let remove_len = self - .output - .chars() - .next() - .map(char::len_utf8) - .unwrap_or(self.output.len()); - self.output.drain(..remove_len); - self.truncated = true; - } - } -} - -pub(crate) const ACP_STDOUT_BUFFER_BYTE_LIMIT: usize = 1024 * 1024; - -#[derive(Debug, Clone)] -pub(crate) struct AcpSessionState { - pub(crate) session_id: String, - pub(crate) vm_id: String, - pub(crate) agent_type: String, - pub(crate) process_id: String, - pub(crate) pid: Option, - pub(crate) stdout_buffer: String, - pub(crate) stdout_buffer_truncated: bool, - pub(crate) next_request_id: i64, - pub(crate) modes: Option, - pub(crate) config_options: Vec, - pub(crate) agent_capabilities: Option, - pub(crate) agent_info: Option, - pub(crate) recent_activity: VecDeque, - pub(crate) pending_permission_requests: PendingPermissionRequests, - pub(crate) seen_inbound_request_ids: SeenInboundRequestIds, - pub(crate) terminals: BTreeMap, - pub(crate) next_terminal_id: u64, - pub(crate) closed: bool, - pub(crate) exit_code: Option, - pub(crate) termination_requested: bool, -} - -impl AcpSessionState { - pub(crate) fn new( - session_id: String, - vm_id: String, - agent_type: String, - process_id: String, - pid: Option, - init_result: &Map, - session_result: &Map, - ) -> Self { - let mut config_options = init_result - .get("configOptions") - .and_then(Value::as_array) - .cloned() - .unwrap_or_default(); - if let Some(overrides) = session_result - .get("configOptions") - .and_then(Value::as_array) - { - config_options = overrides.clone(); - } - let has_model_option = config_options.iter().any(|option| { - option.as_object().is_some_and(|map| { - map.get("id") - .and_then(Value::as_str) - .is_some_and(|id| id == "model") - }) - }); - if !has_model_option { - config_options.extend(derive_config_options(&agent_type, session_result)); - } - - Self { - session_id, - vm_id, - agent_type, - process_id, - pid, - stdout_buffer: String::new(), - stdout_buffer_truncated: false, - // The sidecar already used request ids 1 and 2 on this ACP - // connection for initialize and session/new before the session - // state is created. Continue from 3 so later session RPCs never - // reuse ids on the same transport. - next_request_id: 3, - modes: session_result - .get("modes") - .cloned() - .or_else(|| init_result.get("modes").cloned()), - config_options, - agent_capabilities: init_result.get("agentCapabilities").cloned(), - agent_info: init_result.get("agentInfo").cloned(), - recent_activity: VecDeque::with_capacity(RECENT_ACTIVITY_LIMIT), - pending_permission_requests: PendingPermissionRequests::default(), - seen_inbound_request_ids: SeenInboundRequestIds::default(), - terminals: BTreeMap::new(), - next_terminal_id: 1, - closed: false, - exit_code: None, - termination_requested: false, - } - } - - pub(crate) fn created_response(&self) -> SessionCreatedResponse { - SessionCreatedResponse { - session_id: self.session_id.clone(), - pid: self.pid, - modes: self.modes.clone(), - config_options: self.config_options.clone(), - agent_capabilities: self.agent_capabilities.clone(), - agent_info: self.agent_info.clone(), - } - } - - #[allow(dead_code)] - pub(crate) fn state_response(&self) -> Result { - Ok(SessionStateResponse { - session_id: self.session_id.clone(), - agent_type: self.agent_type.clone(), - process_id: self.process_id.clone(), - pid: self.pid, - closed: self.closed, - modes: self.modes.clone(), - config_options: self.config_options.clone(), - agent_capabilities: self.agent_capabilities.clone(), - agent_info: self.agent_info.clone(), - }) - } - - pub(crate) fn record_activity(&mut self, entry: String) { - self.recent_activity.push_back(entry); - while self.recent_activity.len() > RECENT_ACTIVITY_LIMIT { - self.recent_activity.pop_front(); - } - } - - pub(crate) fn mark_termination_requested(&mut self) { - self.termination_requested = true; - self.closed = true; - } - - pub(crate) fn timeout_diagnostics( - &self, - method: &str, - id: &JsonRpcId, - timeout_ms: u64, - transport_state: Option, - ) -> AcpTimeoutDiagnostics { - AcpTimeoutDiagnostics::new( - method, - id.clone(), - timeout_ms, - self.exit_code, - self.timeout_killed_state(), - transport_state, - self.recent_activity.iter().cloned().collect(), - ) - } - - pub(crate) fn record_notification(&mut self, notification: JsonRpcNotification) { - self.apply_session_update(¬ification); - } - - pub(crate) fn allocate_terminal_id(&mut self) -> String { - let terminal_id = format!("acp-term-{}", self.next_terminal_id); - self.next_terminal_id += 1; - terminal_id - } - - pub(crate) fn apply_request_success( - &mut self, - method: &str, - params: &Map, - saw_session_update: bool, - ) -> Result, AcpSessionStateError> { - if method == "session/set_mode" { - if let Some(mode_id) = params.get("modeId").and_then(Value::as_str) { - self.apply_local_mode_update(mode_id); - if !saw_session_update { - let notification = synthetic_mode_update(mode_id); - self.record_notification(notification.clone()); - return Ok(Some(notification)); - } - } - } - - if method == "session/set_config_option" { - let config_id = params - .get("configId") - .ok_or_else(|| { - AcpSessionStateError::invalid_config_option_params("configId is required") - })? - .as_str() - .ok_or_else(|| { - AcpSessionStateError::invalid_config_option_params("configId must be a string") - })?; - let value = params.get("value").ok_or_else(|| { - AcpSessionStateError::invalid_config_option_params("value is required") - })?; - self.apply_local_config_update(config_id, value)?; - if !saw_session_update { - let notification = synthetic_config_update(&self.config_options); - self.record_notification(notification.clone()); - return Ok(Some(notification)); - } - } - - Ok(None) - } - - fn apply_session_update(&mut self, notification: &JsonRpcNotification) { - if notification.method != "session/update" { - return; - } - let Some(params) = notification - .params - .clone() - .and_then(|value| value.as_object().cloned()) - else { - return; - }; - let update = params - .get("update") - .and_then(Value::as_object) - .cloned() - .unwrap_or(params); - - if update - .get("sessionUpdate") - .and_then(Value::as_str) - .is_some_and(|value| value == "current_mode_update") - { - if let Some(current_mode_id) = update.get("currentModeId").and_then(Value::as_str) { - self.apply_local_mode_update(current_mode_id); - } - } - - if update - .get("sessionUpdate") - .and_then(Value::as_str) - .is_some_and(|value| { - value == "config_option_update" || value == "config_options_update" - }) - { - if let Some(config_options) = update.get("configOptions").and_then(Value::as_array) { - self.config_options = config_options.clone(); - } - } - } - - fn apply_local_mode_update(&mut self, mode_id: &str) { - let Some(Value::Object(modes)) = self.modes.as_mut() else { - return; - }; - modes.insert( - String::from("currentModeId"), - Value::String(String::from(mode_id)), - ); - } - - fn apply_local_config_update( - &mut self, - config_id: &str, - value: &Value, - ) -> Result<(), AcpSessionStateError> { - let mut updated = false; - let mut config_options = Vec::with_capacity(self.config_options.len()); - for (index, option) in self.config_options.iter().enumerate() { - let mut map = option.as_object().cloned().ok_or_else(|| { - AcpSessionStateError::malformed_config_option_entry(index, "expected an object") - })?; - let option_id = map.get("id").and_then(Value::as_str).ok_or_else(|| { - AcpSessionStateError::malformed_config_option_entry(index, "missing string id") - })?; - if option_id == config_id { - map.insert(String::from("currentValue"), value.clone()); - updated = true; - } - config_options.push(Value::Object(map)); - } - if !updated { - return Err(AcpSessionStateError::unknown_config_option(config_id)); - } - self.config_options = config_options; - Ok(()) - } - - fn timeout_killed_state(&self) -> Option { - if self.exit_code.is_some() { - return Some(self.termination_requested); - } - self.termination_requested.then_some(true) - } -} - -pub(crate) fn trim_acp_stdout_buffer(buffer: &mut String) -> bool { - if buffer.len() <= ACP_STDOUT_BUFFER_BYTE_LIMIT { - return false; - } - - let mut remove_len = buffer.len() - ACP_STDOUT_BUFFER_BYTE_LIMIT; - while !buffer.is_char_boundary(remove_len) { - remove_len += 1; - } - buffer.drain(..remove_len); - true -} diff --git a/crates/sidecar/tests/acp_legacy/timeout.rs b/crates/sidecar/tests/acp_legacy/timeout.rs deleted file mode 100644 index 67cc09ecd..000000000 --- a/crates/sidecar/tests/acp_legacy/timeout.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::acp::JsonRpcId; -use serde::{Deserialize, Serialize}; -use serde_json::Value; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct AcpTimeoutDiagnostics { - pub(crate) kind: String, - pub(crate) method: String, - pub(crate) id: JsonRpcId, - pub(crate) timeout_ms: u64, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub(crate) exit_code: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub(crate) killed: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub(crate) transport_state: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub(crate) recent_activity: Vec, -} - -impl AcpTimeoutDiagnostics { - pub(crate) fn new( - method: impl Into, - id: JsonRpcId, - timeout_ms: u64, - exit_code: Option, - killed: Option, - transport_state: Option, - recent_activity: Vec, - ) -> Self { - Self { - kind: String::from("acp_timeout"), - method: method.into(), - id, - timeout_ms, - exit_code, - killed, - transport_state, - recent_activity, - } - } - - pub(crate) fn message(&self) -> String { - let transport_state = self - .transport_state - .as_ref() - .map(|state| format!("{state}. ")) - .unwrap_or_default(); - let exit_code = self - .exit_code - .map(|value| value.to_string()) - .unwrap_or_else(|| String::from("unknown")); - let killed = self - .killed - .map(|value| format!(" killed={value}.")) - .unwrap_or_default(); - let activity = if self.recent_activity.is_empty() { - String::from("no recent ACP activity") - } else { - self.recent_activity.join(" | ") - }; - format!( - "ACP request {} (id={}) timed out after {}ms. {}process exitCode={exit_code}.{killed} Recent ACP activity: {activity}", - self.method, self.id, self.timeout_ms, transport_state - ) - } - - pub(crate) fn to_json(&self) -> Value { - serde_json::to_value(self).expect("serialize ACP timeout diagnostics") - } -} diff --git a/crates/sidecar/tests/acp_session.rs b/crates/sidecar/tests/acp_session.rs deleted file mode 100644 index 320ad540c..000000000 --- a/crates/sidecar/tests/acp_session.rs +++ /dev/null @@ -1,1128 +0,0 @@ -#[allow(dead_code, unused_imports)] -#[path = "acp_legacy/mod.rs"] -mod acp; -#[allow(dead_code, unused_imports)] -#[path = "../src/json_rpc.rs"] -mod json_rpc; -#[allow(dead_code, unused_imports, clippy::enum_variant_names)] -mod protocol { - pub use secure_exec_sidecar_protocol::protocol::*; -} - -use acp::compat::{ - is_cancel_method_not_found, maybe_normalize_permission_response, - normalize_inbound_permission_request, PENDING_PERMISSION_REQUEST_RETENTION_LIMIT, - SEEN_INBOUND_REQUEST_ID_RETENTION_LIMIT, -}; -use acp::session::{trim_acp_stdout_buffer, AcpSessionState, ACP_STDOUT_BUFFER_BYTE_LIMIT}; -use acp::{ - deserialize_message, serialize_message, AcpClient, AcpClientError, AcpClientOptions, - InboundRequestHandler, InboundRequestOutcome, JsonRpcError, JsonRpcId, JsonRpcMessage, - JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, -}; -use serde_json::{json, Map, Value}; -use std::collections::BTreeMap; -use std::pin::Pin; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; -use std::task::{Context, Poll}; -use std::time::{Duration, Instant}; -use tokio::io::{split, AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, DuplexStream}; - -// Timing-sensitive assertions flake under the CPU contention of a parallel test -// run (see CLAUDE.md > Testing). Gated off by default; the nightly timing lane -// sets SECURE_EXEC_RUN_TIMING_TESTS=1 to enforce them. -fn run_timing_sensitive_tests() -> bool { - std::env::var_os("SECURE_EXEC_RUN_TIMING_TESTS").is_some() -} - -fn sample_init_result() -> Map { - Map::from_iter([ - ( - String::from("agentInfo"), - json!({ "name": "Mock ACP", "version": "1.0.0" }), - ), - ( - String::from("agentCapabilities"), - json!({ - "permissions": true, - "plan_mode": true, - "tool_calls": true, - }), - ), - ( - String::from("modes"), - json!({ - "currentModeId": "build", - "availableModes": [ - { "id": "build", "label": "Build" }, - { "id": "plan", "label": "Plan" }, - ], - }), - ), - ( - String::from("configOptions"), - json!([ - { - "id": "model-opt", - "category": "model", - "label": "Model", - "currentValue": "default", - }, - { - "id": "thought-opt", - "category": "thought_level", - "label": "Thought Level", - "currentValue": "medium", - }, - ]), - ), - ]) -} - -fn sample_session_result() -> Map { - Map::from_iter([ - (String::from("sessionId"), json!("mock-agent-session")), - ( - String::from("models"), - json!({ - "currentModelId": "anthropic/claude-sonnet-4-20250514", - "availableModels": [ - { - "modelId": "anthropic/claude-sonnet-4-20250514", - "name": "Sonnet 4", - }, - { - "modelId": "anthropic/claude-opus-4-1-20250805", - "name": "Opus 4.1", - }, - ], - }), - ), - ]) -} - -fn session(agent_type: &str) -> AcpSessionState { - AcpSessionState::new( - String::from("mock-agent-session"), - String::from("vm-1"), - String::from(agent_type), - String::from("acp-agent-1"), - None, - &sample_init_result(), - &sample_session_result(), - ) -} - -fn codex_session_with_standard_model_option() -> AcpSessionState { - AcpSessionState::new( - String::from("mock-agent-session"), - String::from("vm-1"), - String::from("codex"), - String::from("acp-agent-1"), - None, - &sample_init_result(), - &Map::from_iter([ - (String::from("sessionId"), json!("mock-agent-session")), - ( - String::from("configOptions"), - json!([ - { - "id": "model", - "category": "model", - "label": "Model", - "currentValue": "gpt-5-codex", - }, - { - "id": "thought_level", - "category": "thought_level", - "label": "Thought Level", - "currentValue": "medium", - }, - ]), - ), - ( - String::from("models"), - json!({ - "currentModelId": "gpt-5-codex", - "availableModels": [ - { - "modelId": "gpt-5-codex", - "name": "Codex Default", - }, - { - "modelId": "gpt-5.4", - "name": "GPT-5.4", - }, - ], - }), - ), - ]), - ) -} - -fn new_client( - options: AcpClientOptions, -) -> ( - AcpClient, - tokio::io::Lines>>, - tokio::io::WriteHalf, -) { - let (client_stream, server_stream) = tokio::io::duplex(8 * 1024); - let (client_reader, client_writer) = split(client_stream); - let (server_reader, server_writer) = split(server_stream); - let client = AcpClient::new(client_reader, client_writer, options); - (client, BufReader::new(server_reader).lines(), server_writer) -} - -struct FailOnWrite { - inner: tokio::io::WriteHalf, - fail_writes: Arc, -} - -impl AsyncWrite for FailOnWrite { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - if self.fail_writes.load(Ordering::SeqCst) { - return Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::BrokenPipe, - "simulated hung-up peer", - ))); - } - Pin::new(&mut self.inner).poll_write(cx, buf) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.fail_writes.load(Ordering::SeqCst) { - return Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::BrokenPipe, - "simulated hung-up peer", - ))); - } - Pin::new(&mut self.inner).poll_flush(cx) - } - - fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.fail_writes.load(Ordering::SeqCst) { - return Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::BrokenPipe, - "simulated hung-up peer", - ))); - } - Pin::new(&mut self.inner).poll_shutdown(cx) - } -} - -type FailingWriterClient = ( - AcpClient, - tokio::io::Lines>>, - tokio::io::WriteHalf, - Arc, -); - -fn new_client_with_failing_writer(options: AcpClientOptions) -> FailingWriterClient { - let (client_stream, server_stream) = tokio::io::duplex(8 * 1024); - let (client_reader, client_writer) = split(client_stream); - let (server_reader, server_writer) = split(server_stream); - let fail_writes = Arc::new(AtomicBool::new(false)); - let client = AcpClient::new( - client_reader, - FailOnWrite { - inner: client_writer, - fail_writes: Arc::clone(&fail_writes), - }, - options, - ); - ( - client, - BufReader::new(server_reader).lines(), - server_writer, - fail_writes, - ) -} - -async fn read_message( - reader: &mut tokio::io::Lines>>, -) -> JsonRpcMessage { - let line = reader - .next_line() - .await - .expect("read line") - .expect("line should exist"); - deserialize_message(&line).expect("decode json-rpc line") -} - -async fn write_raw(writer: &mut tokio::io::WriteHalf, line: &str) { - writer - .write_all(line.as_bytes()) - .await - .expect("write raw json-rpc line"); - writer.flush().await.expect("flush raw json-rpc line"); -} - -async fn write_message(writer: &mut tokio::io::WriteHalf, message: &JsonRpcMessage) { - let encoded = serialize_message(message).expect("encode json-rpc"); - write_raw(writer, &encoded).await; -} - -#[test] -fn session_state_tracks_metadata_and_derived_model_option() { - let session = session("pi"); - - let created = session.created_response(); - assert_eq!(created.session_id, "mock-agent-session"); - assert_eq!( - created.agent_info.expect("agent info")["name"], - Value::String(String::from("Mock ACP")) - ); - assert_eq!( - created.modes.expect("modes")["currentModeId"], - Value::String(String::from("build")) - ); - assert!(created - .config_options - .iter() - .any(|option| { option.get("id").and_then(Value::as_str) == Some("model") })); - - let state = session.state_response().expect("session state"); - assert_eq!(state.session_id, "mock-agent-session"); - assert_eq!(state.agent_type, "pi"); - assert_eq!(state.process_id, "acp-agent-1"); - assert!(!state.closed); -} - -#[test] -fn initialize_request_uses_requested_protocol_version_and_client_capabilities() { - let client_capabilities = json!({ - "fs": { - "readTextFile": true, - "writeTextFile": false, - }, - "terminal": false, - }); - let request = acp::session::build_initialize_request(2, client_capabilities.clone()); - let params = request - .params - .expect("initialize request params") - .as_object() - .cloned() - .expect("initialize params object"); - - assert_eq!(request.method, "initialize"); - assert_eq!(params.get("protocolVersion"), Some(&json!(2))); - assert_eq!(params.get("clientCapabilities"), Some(&client_capabilities)); -} - -#[test] -fn initialize_result_accepts_matching_protocol_version() { - let init_result = Map::from_iter([(String::from("protocolVersion"), json!(1))]); - - assert_eq!( - acp::session::validate_initialize_result(&init_result, 1), - Ok(1) - ); -} - -#[test] -fn initialize_result_reports_protocol_version_mismatch() { - let init_result = Map::from_iter([(String::from("protocolVersion"), json!(2))]); - - match acp::session::validate_initialize_result(&init_result, 1) { - Err(acp::session::AcpInitializeError::ProtocolVersionMismatch { - requested, - reported, - }) => { - assert_eq!(requested, 1); - assert_eq!(reported, 2); - } - other => panic!("expected protocol version mismatch, got {other:?}"), - } -} - -#[test] -fn session_state_does_not_duplicate_existing_model_options() { - let session = codex_session_with_standard_model_option(); - let model_options = session - .created_response() - .config_options - .into_iter() - .filter(|option| { - option - .get("category") - .and_then(Value::as_str) - .is_some_and(|category| category == "model") - }) - .collect::>(); - - assert_eq!(model_options.len(), 1); - assert_eq!(model_options[0]["id"], "model"); - assert_eq!(model_options[0]["currentValue"], "gpt-5-codex"); -} - -#[test] -fn permission_requests_are_normalized_and_deduped() { - let mut session = session("pi"); - let request = JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(90), - method: String::from("session/request_permission"), - params: Some(json!({ - "sessionId": "mock-agent-session", - "options": [ - { "optionId": "once", "kind": "allow_once" }, - { "optionId": "always", "kind": "allow_always" }, - { "optionId": "reject", "kind": "reject_once" }, - ], - })), - }; - - let normalized = normalize_inbound_permission_request( - &request, - &mut session.seen_inbound_request_ids, - &mut session.pending_permission_requests, - ) - .expect("normalized permission request"); - assert_eq!(normalized.method, "request/permission"); - assert_eq!( - normalized - .params - .as_ref() - .and_then(|params| params.get("permissionId")) - .and_then(Value::as_str), - Some("90") - ); - - let duplicate = normalize_inbound_permission_request( - &request, - &mut session.seen_inbound_request_ids, - &mut session.pending_permission_requests, - ); - assert!(duplicate.is_none()); - - let (reply_id, result) = maybe_normalize_permission_response( - "request/permission", - Some(json!({ - "permissionId": "90", - "reply": "always", - })), - &mut session.pending_permission_requests, - ) - .expect("normalized permission reply"); - assert_eq!(reply_id, JsonRpcId::Number(90)); - assert_eq!(result["outcome"]["optionId"], "always"); -} - -#[test] -fn session_permission_reply_survives_unrelated_seen_request_id_eviction() { - let mut session = session("pi"); - let request = JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::String(String::from("perm-late")), - method: String::from("session/request_permission"), - params: Some(json!({ "sessionId": "mock-agent-session" })), - }; - - normalize_inbound_permission_request( - &request, - &mut session.seen_inbound_request_ids, - &mut session.pending_permission_requests, - ) - .expect("normalized permission request"); - - for request_id in 0..=SEEN_INBOUND_REQUEST_ID_RETENTION_LIMIT { - session - .seen_inbound_request_ids - .insert(JsonRpcId::Number(request_id as i64)); - } - - let (reply_id, result) = maybe_normalize_permission_response( - "request/permission", - Some(json!({ - "permissionId": "perm-late", - "reply": "once", - })), - &mut session.pending_permission_requests, - ) - .expect("permission reply should remain pending after unrelated seen-id churn"); - assert_eq!(reply_id, JsonRpcId::String(String::from("perm-late"))); - assert_eq!(result["outcome"]["optionId"], "allow_once"); -} - -#[test] -fn session_pending_permission_requests_are_bounded_independently() { - let mut session = session("pi"); - - for request_id in 0..=PENDING_PERMISSION_REQUEST_RETENTION_LIMIT { - let request = JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(request_id as i64), - method: String::from("session/request_permission"), - params: Some(json!({ "sessionId": "mock-agent-session" })), - }; - normalize_inbound_permission_request( - &request, - &mut session.seen_inbound_request_ids, - &mut session.pending_permission_requests, - ) - .expect("normalized permission request"); - } - - assert_eq!( - session.pending_permission_requests.len(), - PENDING_PERMISSION_REQUEST_RETENTION_LIMIT - ); -} - -#[test] -fn notifications_update_session_snapshot_without_retaining_replay_events() { - let mut session = session("pi"); - session.record_notification(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from("session/update"), - params: Some(json!({ - "update": { - "sessionUpdate": "config_option_update", - "configOptions": [ - { - "id": "thought-opt", - "category": "thought_level", - "label": "Thought Level", - "currentValue": "high", - }, - ], - }, - })), - }); - session.record_notification(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from("session/update"), - params: Some(json!({ - "update": { - "sessionUpdate": "agent_message_chunk", - "content": { "text": "hello from mock agent" }, - }, - })), - }); - - let state = session.state_response().expect("session state"); - assert_eq!(state.config_options.len(), 1); - assert_eq!(state.config_options[0]["currentValue"], "high"); -} - -#[test] -fn acp_stdout_buffer_trimming_keeps_newest_utf8_boundary() { - let mut buffer = format!("{}é", "a".repeat(ACP_STDOUT_BUFFER_BYTE_LIMIT)); - - assert!(trim_acp_stdout_buffer(&mut buffer)); - - assert_eq!(buffer.len(), ACP_STDOUT_BUFFER_BYTE_LIMIT); - assert!(buffer.is_char_boundary(0)); - assert!(buffer.ends_with('é')); - - let mut buffer = format!("é{}", "a".repeat(ACP_STDOUT_BUFFER_BYTE_LIMIT)); - - assert!(trim_acp_stdout_buffer(&mut buffer)); - - assert_eq!(buffer.len(), ACP_STDOUT_BUFFER_BYTE_LIMIT); - assert!(buffer.is_char_boundary(0)); - assert!(buffer.starts_with('a')); -} - -#[test] -fn mode_changes_inject_synthetic_session_update_when_agent_omits_notification() { - let mut session = session("mock-no-update-agent"); - let params = Map::from_iter([(String::from("modeId"), Value::String(String::from("plan")))]); - - let synthetic = session - .apply_request_success("session/set_mode", ¶ms, false) - .expect("mode update should succeed") - .expect("synthetic mode update"); - assert_eq!(synthetic.method, "session/update"); - assert_eq!( - session - .state_response() - .expect("session state") - .modes - .expect("modes")["currentModeId"], - Value::String(String::from("plan")) - ); -} - -#[test] -fn mode_changes_do_not_duplicate_existing_session_updates() { - let mut session = session("mock-no-update-agent"); - session.record_notification(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from("session/update"), - params: Some(json!({ - "update": { - "sessionUpdate": "current_mode_update", - "currentModeId": "plan", - }, - })), - }); - - let params = Map::from_iter([(String::from("modeId"), Value::String(String::from("plan")))]); - let synthetic = session - .apply_request_success("session/set_mode", ¶ms, true) - .expect("mode update should succeed"); - - assert!(synthetic.is_none()); - assert_eq!( - session - .state_response() - .expect("session state") - .modes - .expect("modes")["currentModeId"], - "plan" - ); -} - -#[test] -fn config_changes_inject_synthetic_session_update_when_agent_omits_notification() { - let mut session = session("mock-no-update-agent"); - let params = Map::from_iter([ - ( - String::from("configId"), - Value::String(String::from("thought-opt")), - ), - (String::from("value"), Value::String(String::from("high"))), - ]); - - let synthetic = session - .apply_request_success("session/set_config_option", ¶ms, false) - .expect("config update should succeed") - .expect("synthetic config update"); - assert_eq!(synthetic.method, "session/update"); - assert_eq!( - synthetic.params.expect("config params")["update"]["sessionUpdate"], - Value::String(String::from("config_option_update")) - ); - assert_eq!( - session - .state_response() - .expect("session state") - .config_options[1]["currentValue"], - "high" - ); -} - -#[test] -fn config_changes_do_not_duplicate_existing_session_updates() { - let mut session = session("mock-no-update-agent"); - session.record_notification(JsonRpcNotification { - jsonrpc: String::from("2.0"), - method: String::from("session/update"), - params: Some(json!({ - "update": { - "sessionUpdate": "config_option_update", - "configOptions": [ - { - "id": "model-opt", - "category": "model", - "label": "Model", - "currentValue": "default", - }, - { - "id": "thought-opt", - "category": "thought_level", - "label": "Thought Level", - "currentValue": "high", - }, - ], - }, - })), - }); - - let params = Map::from_iter([ - ( - String::from("configId"), - Value::String(String::from("thought-opt")), - ), - (String::from("value"), Value::String(String::from("high"))), - ]); - let synthetic = session - .apply_request_success("session/set_config_option", ¶ms, true) - .expect("config update should succeed"); - - assert!(synthetic.is_none()); - assert_eq!( - session - .state_response() - .expect("session state") - .config_options[1]["currentValue"], - "high" - ); -} - -#[test] -fn config_changes_accept_non_string_values() { - let mut session = session("mock-no-update-agent"); - let params = Map::from_iter([ - ( - String::from("configId"), - Value::String(String::from("thought-opt")), - ), - (String::from("value"), Value::Bool(true)), - ]); - - let synthetic = session - .apply_request_success("session/set_config_option", ¶ms, false) - .expect("config update should succeed") - .expect("synthetic config update"); - - assert_eq!(synthetic.method, "session/update"); - assert_eq!( - session - .state_response() - .expect("session state") - .config_options[1]["currentValue"], - Value::Bool(true) - ); -} - -#[test] -fn config_changes_return_typed_error_for_malformed_params() { - let mut session = session("mock-no-update-agent"); - let params = Map::from_iter([ - (String::from("configId"), Value::Bool(true)), - (String::from("value"), Value::Bool(true)), - ]); - - let error = session - .apply_request_success("session/set_config_option", ¶ms, false) - .expect_err("malformed params should fail"); - let json_rpc = error.to_json_rpc_error("session/set_config_option"); - - assert_eq!(json_rpc.code, -32602); - assert_eq!( - json_rpc.message, - "Invalid params for session/set_config_option: configId must be a string" - ); - assert_eq!( - json_rpc.data.expect("typed error data")["kind"], - json!("invalid_config_option_params") - ); -} - -#[test] -fn config_changes_return_typed_error_for_malformed_option_entries() { - let mut session = session("mock-no-update-agent"); - session - .config_options - .push(Value::String(String::from("broken"))); - let params = Map::from_iter([ - ( - String::from("configId"), - Value::String(String::from("thought-opt")), - ), - (String::from("value"), Value::Bool(true)), - ]); - - let error = session - .apply_request_success("session/set_config_option", ¶ms, false) - .expect_err("malformed config options should fail"); - let json_rpc = error.to_json_rpc_error("session/set_config_option"); - - assert_eq!(json_rpc.code, -32602); - assert_eq!( - json_rpc.message, - "Invalid params for session/set_config_option: config option entry 3 is malformed: expected an object" - ); - let data = json_rpc.data.expect("typed error data"); - assert_eq!(data["kind"], json!("malformed_config_option_entry")); - assert_eq!(data["index"], json!(3)); -} - -#[test] -fn cancel_method_not_found_detects_session_cancel_response_shape() { - let response = JsonRpcResponse::error_response( - JsonRpcId::Number(1), - JsonRpcError { - code: -32601, - message: String::from("Method not found: session/cancel"), - data: Some(json!({ "method": "session/cancel" })), - }, - ); - - assert!(is_cancel_method_not_found(&response)); -} - -#[tokio::test(flavor = "current_thread")] -async fn acp_inbound_requests_wait_for_host_response_before_falling_back() { - let handler: InboundRequestHandler = Arc::new(|request| { - Box::pin(async move { - tokio::time::sleep(Duration::from_millis(25)).await; - Ok(Some(InboundRequestOutcome { - result: Some(json!({ - "echo": request.params.unwrap_or(Value::Null) - })), - error: None, - })) - }) - }); - - let (_client, mut reader, mut writer) = new_client(AcpClientOptions { - timeout: Duration::from_millis(100), - method_timeouts: BTreeMap::new(), - request_handler: Some(handler), - process_state_provider: None, - max_read_line_bytes: 16 * 1024 * 1024, - }); - let started_at = Instant::now(); - - write_message( - &mut writer, - &JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(41), - method: String::from("fs/read_text_file"), - params: Some(json!({ "path": "/workspace/notes.txt" })), - }), - ) - .await; - - let response = read_message(&mut reader).await; - assert!(started_at.elapsed() >= Duration::from_millis(20)); - assert_eq!( - response, - JsonRpcMessage::Response(JsonRpcResponse::success( - JsonRpcId::Number(41), - json!({ - "echo": { - "path": "/workspace/notes.txt", - }, - }), - )) - ); -} - -#[tokio::test(flavor = "current_thread")] -async fn acp_inbound_requests_return_method_not_found_after_handler_timeout() { - let handler: InboundRequestHandler = Arc::new(|_request| { - Box::pin(async move { - tokio::time::sleep(Duration::from_millis(50)).await; - Ok(Some(InboundRequestOutcome { - result: Some(json!({ "late": true })), - error: None, - })) - }) - }); - - let (_client, mut reader, mut writer) = new_client(AcpClientOptions { - timeout: Duration::from_millis(10), - method_timeouts: BTreeMap::new(), - request_handler: Some(handler), - process_state_provider: None, - max_read_line_bytes: 16 * 1024 * 1024, - }); - let started_at = Instant::now(); - - write_message( - &mut writer, - &JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(42), - method: String::from("host/missing"), - params: None, - }), - ) - .await; - - let response = read_message(&mut reader).await; - assert!(started_at.elapsed() >= Duration::from_millis(10)); - assert_eq!( - response, - JsonRpcMessage::Response(JsonRpcResponse::error_response( - JsonRpcId::Number(42), - JsonRpcError { - code: -32601, - message: String::from("Method not found: host/missing"), - data: None, - }, - )) - ); -} - -#[tokio::test(flavor = "current_thread")] -async fn malformed_acp_frames_with_missing_ids_return_invalid_request_errors() { - let (_client, mut reader, mut writer) = new_client(AcpClientOptions::default()); - - write_raw(&mut writer, r#"{"jsonrpc":"2.0","result":{"ok":true}}"#).await; - write_raw(&mut writer, "\n").await; - - let response = read_message(&mut reader).await; - assert_eq!( - response, - JsonRpcMessage::Response(JsonRpcResponse::error_response( - JsonRpcId::Null, - JsonRpcError { - code: -32600, - message: String::from("Invalid Request: response is missing id"), - data: None, - }, - )) - ); -} - -#[tokio::test(flavor = "current_thread")] -async fn acp_response_write_failures_put_the_client_into_a_failed_state() { - let handler: InboundRequestHandler = Arc::new(|request| { - Box::pin(async move { - Ok(Some(InboundRequestOutcome { - result: Some(json!({ - "echo": request.params.unwrap_or(Value::Null) - })), - error: None, - })) - }) - }); - - let (client, mut reader, mut writer, fail_writes) = - new_client_with_failing_writer(AcpClientOptions { - timeout: Duration::from_secs(1), - method_timeouts: BTreeMap::new(), - request_handler: Some(handler), - process_state_provider: None, - max_read_line_bytes: 16 * 1024 * 1024, - }); - - let pending_request = tokio::spawn({ - let client = client.clone(); - async move { - client - .request("session/prompt", Some(json!({ "sessionId": "pending" }))) - .await - } - }); - - let outbound_request = read_message(&mut reader).await; - match outbound_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "session/prompt"); - } - other => panic!("unexpected outbound request: {other:?}"), - } - - fail_writes.store(true, Ordering::SeqCst); - - write_message( - &mut writer, - &JsonRpcMessage::Request(JsonRpcRequest { - jsonrpc: String::from("2.0"), - id: JsonRpcId::Number(77), - method: String::from("fs/read_text_file"), - params: Some(json!({ "path": "/workspace/notes.txt" })), - }), - ) - .await; - - let pending_error = tokio::time::timeout(Duration::from_secs(1), pending_request) - .await - .expect("pending request timeout") - .expect("pending request join") - .expect_err("pending request should fail after response write error"); - assert!( - matches!(pending_error, AcpClientError::Io(_)), - "unexpected pending error: {pending_error:?}" - ); - assert!( - pending_error - .to_string() - .contains("failed to write ACP frame"), - "unexpected pending error message: {pending_error}" - ); - - let started_at = Instant::now(); - let subsequent_error = client - .request( - "session/prompt", - Some(json!({ "sessionId": "after-failure" })), - ) - .await - .expect_err("subsequent request should fail fast"); - if run_timing_sensitive_tests() { - assert!(started_at.elapsed() < Duration::from_millis(50)); - } - assert!( - matches!(subsequent_error, AcpClientError::Io(_)), - "unexpected subsequent error: {subsequent_error:?}" - ); - assert_eq!(subsequent_error.to_string(), pending_error.to_string()); -} - -#[tokio::test(flavor = "current_thread")] -async fn acp_request_method_timeout_overrides_apply_to_initialize_and_prompt() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions { - timeout: Duration::from_millis(25), - method_timeouts: BTreeMap::from([ - (String::from("initialize"), Duration::from_millis(5)), - (String::from("session/prompt"), Duration::from_millis(80)), - ]), - request_handler: None, - process_state_provider: None, - max_read_line_bytes: 16 * 1024 * 1024, - }); - - let initialize_started = Instant::now(); - let initialize = tokio::spawn({ - let client = client.clone(); - async move { - client - .request("initialize", Some(json!({ "protocolVersion": 1 }))) - .await - } - }); - - let initialize_request = read_message(&mut reader).await; - match initialize_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "initialize"); - } - other => panic!("unexpected initialize request: {other:?}"), - } - - let initialize_error = initialize - .await - .expect("initialize join") - .expect_err("initialize should time out"); - assert!(matches!(initialize_error, AcpClientError::Timeout(_))); - if run_timing_sensitive_tests() { - assert!(initialize_started.elapsed() < Duration::from_millis(20)); - } - assert!(initialize_error - .to_string() - .contains("ACP request initialize (id=1) timed out after 5ms")); - - let prompt = tokio::spawn({ - let client = client.clone(); - async move { - client - .request("session/prompt", Some(json!({ "sessionId": "long-lived" }))) - .await - } - }); - - let prompt_request = read_message(&mut reader).await; - let prompt_id = match prompt_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "session/prompt"); - request.id - } - other => panic!("unexpected prompt request: {other:?}"), - }; - - tokio::time::sleep(Duration::from_millis(40)).await; - write_message( - &mut writer, - &JsonRpcMessage::Response(JsonRpcResponse::success( - prompt_id, - json!({ "status": "complete" }), - )), - ) - .await; - - let prompt_response = prompt.await.expect("prompt join").expect("prompt response"); - assert_eq!( - prompt_response.result(), - Some(&json!({ "status": "complete" })) - ); -} - -#[tokio::test(flavor = "current_thread")] -async fn acp_timed_out_session_prompt_sends_cancel_and_ignores_late_response() { - let (client, mut reader, mut writer) = new_client(AcpClientOptions { - timeout: Duration::from_millis(20), - method_timeouts: BTreeMap::from([(String::from("initialize"), Duration::from_millis(50))]), - request_handler: None, - process_state_provider: None, - max_read_line_bytes: 16 * 1024 * 1024, - }); - - let prompt = tokio::spawn({ - let client = client.clone(); - async move { - client - .request( - "session/prompt", - Some(json!({ "sessionId": "session-timeout" })), - ) - .await - } - }); - - let outbound_request = read_message(&mut reader).await; - let prompt_id = match outbound_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "session/prompt"); - request.id - } - other => panic!("unexpected prompt request: {other:?}"), - }; - - let cancel = read_message(&mut reader).await; - match cancel { - JsonRpcMessage::Notification(notification) => { - assert_eq!(notification.method, "session/cancel"); - assert_eq!( - notification.params, - Some(json!({ "sessionId": "session-timeout" })) - ); - } - other => panic!("unexpected timeout cancel frame: {other:?}"), - } - - let prompt_error = prompt - .await - .expect("prompt join") - .expect_err("prompt should time out"); - assert!(matches!(prompt_error, AcpClientError::Timeout(_))); - - write_message( - &mut writer, - &JsonRpcMessage::Response(JsonRpcResponse::success( - prompt_id, - json!({ "status": "late" }), - )), - ) - .await; - - let initialize = tokio::spawn({ - let client = client.clone(); - async move { - client - .request("initialize", Some(json!({ "protocolVersion": 1 }))) - .await - } - }); - - let initialize_request = read_message(&mut reader).await; - let initialize_id = match initialize_request { - JsonRpcMessage::Request(request) => { - assert_eq!(request.method, "initialize"); - request.id - } - other => panic!("unexpected initialize request: {other:?}"), - }; - - write_message( - &mut writer, - &JsonRpcMessage::Response(JsonRpcResponse::success( - initialize_id, - json!({ "protocolVersion": 1 }), - )), - ) - .await; - - let initialize_response = initialize - .await - .expect("initialize join") - .expect("initialize response"); - assert_eq!( - initialize_response.result(), - Some(&json!({ "protocolVersion": 1 })) - ); -} diff --git a/crates/sidecar/tests/architecture_guards.rs b/crates/sidecar/tests/architecture_guards.rs deleted file mode 100644 index f94afbf4d..000000000 --- a/crates/sidecar/tests/architecture_guards.rs +++ /dev/null @@ -1,601 +0,0 @@ -//! Architecture / boundary guards (CI hardening, item #2). -//! -//! This is a *chokepoint lint*: it scans the secure-exec Rust source tree and -//! FAILS if a security-sensitive host API ("banned API") appears OUTSIDE an -//! explicit allowlist of sanctioned modules. The goal is to keep host access -//! funnelled through a small, reviewable set of files so that a NEW use of -//! `std::fs`, raw sockets, `Command::new`, or process-environment reads cannot -//! be introduced without either landing in a sanctioned module or consciously -//! updating this allowlist (which forces review of the boundary). -//! -//! The four banned classes mirror the kernel/sidecar trust boundary: -//! -//! * fs -- `std::fs` / `tokio::fs` / `File::open` / `File::create` / -//! `OpenOptions` / raw `openat`. Sanctioned only in the sidecar host-FS -//! plumbing, the VFS-backed runtime modules, and runtime asset/module -//! loaders. -//! * net -- `std::net` / `tokio::net` socket constructors, `reqwest`, -//! `hyper`, `to_socket_addrs`, `UnixStream::pair`. Sanctioned only in the -//! kernel DNS/socket plane, the sidecar host-net chokepoint -//! (`sidecar::execution`), the embedded V8 runtime IPC pair, and -//! host-backed storage plugins. -//! * process -- `std::process::Command` / `tokio::process` / OS `fork`. -//! Sanctioned only where secure-exec spawns its own helper process (the -//! client transport that launches the sidecar). Guest "process" spawns are -//! dispatched through the kernel `CommandDriver` registry and never touch -//! `Command::new`. -//! * env -- `std::env::var` / `var_os` / `vars`. Sanctioned only at the -//! scrubbed env-assembly / bootstrap points that read host configuration -//! before a VM is constructed. -//! -//! IMPORTANT MAINTENANCE NOTES -//! --------------------------- -//! * The allowlist is built from the CURRENT legitimate uses so the test is -//! GREEN today; it is designed to catch only *new* uses. -//! * Build scripts (`build.rs`, `*_build_support.rs`, ...), `tests/` and -//! `benches/` directories, and inline `#[cfg(test)]` modules are excluded -//! from the scan (they are not production host-access surface). -//! * `crates/execution/src/benchmark.rs`, `crates/execution/src/bin/`, and -//! `crates/native-baseline/` hold benchmarking/dev tooling and are excluded -//! for the same reason. -//! -//! If you are adding a genuinely new sanctioned chokepoint, add its -//! repo-relative path to the relevant allowlist below WITH a comment -//! explaining why the host access is safe. If you are adding host access -//! anywhere else, route it through an existing chokepoint instead. - -use std::collections::BTreeSet; -use std::path::{Path, PathBuf}; - -/// Repo root = `/crates/sidecar` -> up two levels. -fn repo_root() -> PathBuf { - let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - manifest - .parent() - .and_then(Path::parent) - .expect("sidecar crate should live two levels under the repo root") - .to_path_buf() -} - -/// Every production Rust source file under `crates/*/src/`, repo-relative, -/// excluding build scripts, benches, bins, and `tests/` trees. -fn production_source_files(root: &Path) -> Vec { - let mut out = Vec::new(); - let crates_dir = root.join("crates"); - let mut crate_dirs: Vec = std::fs::read_dir(&crates_dir) - .expect("crates/ directory should exist") - .filter_map(|entry| entry.ok().map(|e| e.path())) - .filter(|p| p.is_dir()) - .collect(); - crate_dirs.sort(); - for crate_dir in crate_dirs { - let src = crate_dir.join("src"); - if src.is_dir() { - collect_rs(&src, root, &mut out); - } - } - out.sort(); - out -} - -fn collect_rs(dir: &Path, root: &Path, out: &mut Vec) { - let mut entries: Vec = std::fs::read_dir(dir) - .unwrap_or_else(|err| panic!("read_dir {dir:?}: {err}")) - .filter_map(|entry| entry.ok().map(|e| e.path())) - .collect(); - entries.sort(); - for path in entries { - if path.is_dir() { - // Exclude bench/dev binaries that are not production runtime. - if path.file_name().map(|n| n == "bin").unwrap_or(false) { - continue; - } - collect_rs(&path, root, out); - } else if path.extension().map(|e| e == "rs").unwrap_or(false) { - let rel = path - .strip_prefix(root) - .expect("source path under repo root") - .to_path_buf(); - out.push(rel); - } - } -} - -/// Returns true if the file is excluded from scanning entirely. -fn is_excluded_file(rel: &Path) -> bool { - let s = rel.to_string_lossy(); - s.ends_with("build.rs") - || s.ends_with("build_support.rs") - || s.ends_with("v8_bridge_build.rs") - // Benchmarking / dev tooling, not production host-access surface. - || s == "crates/execution/src/benchmark.rs" - || s.starts_with("crates/native-baseline/") - || s.contains("/src/bin/") -} - -/// Strip a trailing `//` line comment (good enough for this lint; we are not -/// trying to be a full Rust parser, only to avoid flagging commented examples). -fn strip_line_comment(line: &str) -> &str { - match line.find("//") { - Some(idx) => &line[..idx], - None => line, - } -} - -/// Track whether a line is inside a top-level `#[cfg(test)]` module so test -/// code is excluded from the scan. We watch for `#[cfg(test)]` immediately -/// followed by a `mod ... {` and then balance braces until the module closes. -struct CfgTestTracker { - pending_cfg_test: bool, - depth: u32, -} - -impl CfgTestTracker { - fn new() -> Self { - Self { - pending_cfg_test: false, - depth: 0, - } - } - - /// Feed a line. Returns true if this line is inside a `#[cfg(test)]` module. - fn in_test(&mut self, raw: &str) -> bool { - let line = strip_line_comment(raw); - let trimmed = line.trim(); - - if self.depth > 0 { - // Already inside a cfg(test) module: update brace balance. - self.depth += count_open(line); - self.depth = self.depth.saturating_sub(count_close(line)); - return true; - } - - if trimmed.starts_with("#[cfg(test)]") { - self.pending_cfg_test = true; - return false; - } - - if self.pending_cfg_test { - if trimmed.is_empty() || trimmed.starts_with("#[") || trimmed.starts_with("//") { - // Attributes/blank lines may sit between #[cfg(test)] and the item. - return false; - } - // The attribute applies to the next item. Only a `mod ... { ... }` - // creates a test *region* we must skip wholesale; a `#[cfg(test)]` - // on a `use` / `fn` / `const` is a single item and gets matched - // line-by-line, so we still skip just that line below. - self.pending_cfg_test = false; - if trimmed.starts_with("mod ") - || trimmed.starts_with("pub mod ") - || trimmed.starts_with("pub(crate) mod ") - || trimmed.starts_with("pub(super) mod ") - { - // Enter test module; balance braces starting from this line. - self.depth = count_open(line).saturating_sub(count_close(line)); - if self.depth == 0 { - // Single-line `mod x;` declaration (no body) -- nothing to skip. - } - return true; - } - // A single `#[cfg(test)]` item (use/fn/const/static). Skip this line. - return true; - } - - false - } -} - -fn count_open(s: &str) -> u32 { - s.bytes().filter(|&b| b == b'{').count() as u32 -} -fn count_close(s: &str) -> u32 { - s.bytes().filter(|&b| b == b'}').count() as u32 -} - -/// A banned-API class and the regex-free matchers describing it. -struct BannedClass { - name: &'static str, - /// Substrings; a line matches the class if it contains any of them. - needles: &'static [&'static str], - /// Files (repo-relative) where this class is sanctioned. - allowlist: &'static [&'static str], -} - -fn line_matches(line: &str, needles: &[&str]) -> bool { - needles.iter().any(|n| line.contains(n)) -} - -/// Run the chokepoint scan for one banned class and return offending -/// `path:line: text` strings that are NOT in the allowlist. -fn scan_class(root: &Path, files: &[PathBuf], class: &BannedClass) -> Vec { - let allow: BTreeSet<&str> = class.allowlist.iter().copied().collect(); - let mut violations = Vec::new(); - - for rel in files { - if is_excluded_file(rel) { - continue; - } - let rel_str = rel.to_string_lossy().replace('\\', "/"); - let allowed = allow.contains(rel_str.as_str()); - let abs = root.join(rel); - let content = - std::fs::read_to_string(&abs).unwrap_or_else(|err| panic!("read {abs:?}: {err}")); - let mut tracker = CfgTestTracker::new(); - for (idx, raw) in content.lines().enumerate() { - let in_test = tracker.in_test(raw); - if allowed { - continue; // still need to advance the tracker above - } - if in_test { - continue; - } - let code = strip_line_comment(raw); - if line_matches(code, class.needles) { - violations.push(format!("{}:{}: {}", rel_str, idx + 1, raw.trim())); - } - } - } - violations -} - -// --------------------------------------------------------------------------- -// Allowlists -- built from the CURRENT legitimate uses (green today). -// --------------------------------------------------------------------------- - -/// fs: host filesystem access. -/// -/// Sanctioned surface: the sidecar host-FS plumbing + VFS-backed runtime, the -/// JS/Python/WASM runtime asset & module loaders, the sidecar bootstrap -/// (stdio/service/state/vm), and runtime support glue. These modules read -/// real host files to seed the VFS, load runtime assets, and bridge guest FS -/// syscalls to the host-dir mount. -const FS_ALLOW: &[&str] = &[ - // sidecar host-FS chokepoint + bootstrap - "crates/sidecar/src/filesystem.rs", - "crates/sidecar/src/plugins/host_dir.rs", - // macOS host-mount confinement primitives: the cap-std resolve-beneath walk - // that stands in for Linux `openat2(RESOLVE_BENEATH)` on darwin. Same - // sanctioned boundary as host_dir.rs/filesystem.rs, macOS-only. - "crates/sidecar/src/macos_fs.rs", - "crates/sidecar/src/plugins/module_access.rs", - // agentOS package projection: the sidecar is the host-side TCB that reads a - // trusted, client-configured package's tar + `agentos-package.json` from the - // host to build the read-only `/opt/agentos` granular mounts (no extraction, - // no on-disk symlink farm). Same sanctioned read-only host-source boundary as - // filesystem.rs/host_dir.rs. - "crates/sidecar/src/package_projection.rs", - "crates/sidecar/src/stdio.rs", - "crates/sidecar/src/state.rs", - "crates/sidecar/src/vm.rs", - "crates/sidecar/src/service.rs", - "crates/sidecar/src/execution.rs", - "crates/sidecar/src/plugins/chunked_local.rs", - "crates/secure-exec-vfs/src/local/file_block_store.rs", - "crates/secure-exec-vfs/src/local/sqlite_metadata_store.rs", - // Tar-backed read-only VFS: mmaps the trusted, client-configured package - // tar from the host and serves member byte ranges without extracting. - // Same sanctioned read-only host-source boundary as host_dir.rs (the tar is - // an immutable, content-addressed mount source); reads are SIGBUS-guarded. - "crates/vfs/src/posix/tar_fs.rs", - // language-runtime asset / module loaders (read host runtime assets) - "crates/execution/src/python.rs", - "crates/execution/src/wasm.rs", - "crates/execution/src/javascript.rs", - "crates/execution/src/node_import_cache.rs", - "crates/execution/src/runtime_support.rs", - // Host-side V8 diagnostics: module-trace and sync-RPC latency profilers - // write to an operator-provided file path, and snapshot bootstrap reads the - // userland bundle from PI_SNAPSHOT_BUNDLE_PATH. Host-only, not guest-reachable. - "crates/v8-runtime/src/execution.rs", - "crates/v8-runtime/src/host_call.rs", - "crates/v8-runtime/src/snapshot.rs", - // Session-phase perf recorder writes to an operator-provided file path - // (AGENTOS_V8_SESSION_PHASES_FILE). Host-only diagnostics, same class as - // execution.rs/host_call.rs above. - "crates/v8-runtime/src/session.rs", -]; - -/// net: host network access. -/// -/// Sanctioned surface: the kernel DNS resolver plane, the sidecar host-net -/// chokepoint (`execution.rs`, which owns all guest TCP/UDP/Unix sockets), the -/// host-backed storage/agent plugins (which open egress to S3 / Google Drive / -/// the sandbox-agent control plane), the embedded V8 runtime IPC socketpair, -/// and the client transport that talks to the spawned sidecar. -const NET_ALLOW: &[&str] = &[ - // kernel network plane - "crates/kernel/src/dns.rs", - // Shared IP classifier only; no host sockets are opened here. - "crates/kernel/src/network_policy.rs", - // Shared socket-address formatting only; no host sockets are opened here. - "crates/sidecar-core/src/net.rs", - "crates/kernel/src/socket_table.rs", - "crates/kernel/src/kernel.rs", - // sidecar host-net chokepoint + bootstrap - "crates/sidecar/src/execution.rs", - "crates/sidecar/src/state.rs", - "crates/sidecar/src/vm.rs", - // host-backed storage / agent plugins (network egress) - "crates/sidecar/src/plugins/s3_common.rs", - "crates/secure-exec-vfs/src/s3/block_store.rs", - "crates/secure-exec-vfs/src/s3/object_backend.rs", - "crates/sidecar/src/plugins/google_drive.rs", - "crates/sidecar/src/plugins/sandbox_agent.rs", - // embedded runtime IPC socketpair (not external egress) - "crates/v8-runtime/src/embedded_runtime.rs", - "crates/execution/src/v8_runtime.rs", - // client spawns + connects to the sidecar helper - "crates/secure-exec-client/src/transport.rs", -]; - -/// process: OS subprocess creation. -/// -/// Sanctioned surface: only the client transport, which spawns secure-exec's -/// own sidecar helper binary. Guest "process" spawns go through the kernel -/// `CommandDriver` registry and never reach `Command::new`. -const PROCESS_ALLOW: &[&str] = &[ - "crates/secure-exec-client/src/transport.rs", - // V8 snapshot builder re-execs secure-exec's OWN binary as a helper - // (SNAPSHOT_HELPER_ENV) so snapshot creation runs in a clean process. - // Host-side bootstrap only; no guest-controlled input picks the program. - "crates/v8-runtime/src/snapshot.rs", -]; - -/// env: process-environment reads. -/// -/// Sanctioned surface: the scrubbed/bootstrap configuration readers that look -/// up host configuration (sidecar binary path, node binary path/PATH, codec -/// selection, subprocess re-exec markers, local-endpoint test escape hatch) -/// before a VM exists. -const ENV_ALLOW: &[&str] = &[ - "crates/secure-exec-client/src/transport.rs", - "crates/execution/src/host_node.rs", - // Node import cache reads an operator timeout knob before materializing - // host-side runtime assets for VM startup. - "crates/execution/src/node_import_cache.rs", - // Host-side perf phase diagnostics toggles, read from operator env and not - // guest-reachable. - "crates/execution/src/javascript.rs", - "crates/sidecar/src/filesystem.rs", - "crates/v8-runtime/src/bridge.rs", - "crates/sidecar/src/execution.rs", - "crates/sidecar/src/plugins/s3_common.rs", - // Host-process startup log-level knob, read before any VM exists. - "crates/sidecar/src/main.rs", - // Host-side V8 diagnostics toggles (module-trace + sync-RPC latency - // profiling + snapshot-bundle path), read at runtime init from operator - // env. Not guest-reachable. - "crates/v8-runtime/src/execution.rs", - "crates/v8-runtime/src/host_call.rs", - "crates/v8-runtime/src/snapshot.rs", - // Browser sidecar reads a test-only vm.fetch timeout override (bucket 1: - // process-wide test/debug knob, native-only); not VM policy. - "crates/sidecar-browser/src/service.rs", - // Warm-isolate pool sizing knob (AGENTOS_V8_WARM_ISOLATES), read at - // executor init from operator env. Not guest-reachable. - "crates/execution/src/v8_host.rs", - // Wasm runner mode/cache knobs (AGENTOS_WASM_SNAPSHOT_RUNNER, - // AGENTOS_WASM_RUNNER_NO_CACHE) + warm-pool sizing, read at executor init - // from operator env. Not guest-reachable. (wasm.rs is already a sanctioned - // FS asset-loading boundary above.) - "crates/execution/src/wasm.rs", - // Session-phase perf diagnostics toggles (AGENTOS_V8_SESSION_PHASES*), - // read from operator env. Not guest-reachable. - "crates/v8-runtime/src/session.rs", -]; - -fn fs_class() -> BannedClass { - BannedClass { - name: "fs", - needles: &[ - "std::fs", - "tokio::fs", - "File::open", - "File::create", - "OpenOptions", - "openat", - ], - allowlist: FS_ALLOW, - } -} - -fn net_class() -> BannedClass { - BannedClass { - name: "net", - needles: &[ - "std::net::", - "tokio::net::", - "reqwest::", - "reqwest ", - "hyper::", - "TcpStream::", - "TcpListener::bind", - "UdpSocket::bind", - "UnixStream::connect", - "UnixStream::pair", - "UnixListener::bind", - ".to_socket_addrs(", - "std::os::unix::net", - ], - allowlist: NET_ALLOW, - } -} - -fn process_class() -> BannedClass { - BannedClass { - name: "process", - needles: &[ - "std::process::Command", - "process::Command", - "tokio::process", - "Command::new", - "libc::fork", - "nix::unistd::fork", - ], - allowlist: PROCESS_ALLOW, - } -} - -fn env_class() -> BannedClass { - BannedClass { - name: "env", - needles: &[ - "env::var(", - "env::var_os(", - "env::vars(", - "env::vars_os(", - "std::env::var", - ], - allowlist: ENV_ALLOW, - } -} - -fn assert_green(root: &Path, files: &[PathBuf], class: BannedClass) { - let violations = scan_class(root, files, &class); - assert!( - violations.is_empty(), - "\n\nChokepoint lint ({}) found {} host-API use(s) OUTSIDE the sanctioned \ -allowlist.\nEither route the access through an existing chokepoint, or -- if this \ -is a genuinely new sanctioned boundary -- add the file to the `{}` allowlist in \ -crates/sidecar/tests/architecture_guards.rs with a justifying comment.\n\n{}\n", - class.name, - violations.len(), - match class.name { - "fs" => "FS_ALLOW", - "net" => "NET_ALLOW", - "process" => "PROCESS_ALLOW", - _ => "ENV_ALLOW", - }, - violations.join("\n"), - ); -} - -#[test] -fn fs_access_confined_to_chokepoints() { - let root = repo_root(); - let files = production_source_files(&root); - assert_green(&root, &files, fs_class()); -} - -#[test] -fn net_access_confined_to_chokepoints() { - let root = repo_root(); - let files = production_source_files(&root); - assert_green(&root, &files, net_class()); -} - -#[test] -fn process_spawn_confined_to_chokepoints() { - let root = repo_root(); - let files = production_source_files(&root); - assert_green(&root, &files, process_class()); -} - -#[test] -fn env_reads_confined_to_chokepoints() { - let root = repo_root(); - let files = production_source_files(&root); - assert_green(&root, &files, env_class()); -} - -/// Sanity: the scan actually sees source files and the allowlisted files exist. -/// Guards against a refactor silently making the lint scan nothing (which would -/// make it vacuously pass). -#[test] -fn lint_scans_real_sources_and_allowlist_paths_exist() { - let root = repo_root(); - let files = production_source_files(&root); - assert!( - files.len() > 30, - "expected to scan many source files, found {}", - files.len() - ); - - let mut missing = Vec::new(); - for class in [FS_ALLOW, NET_ALLOW, PROCESS_ALLOW, ENV_ALLOW] { - for rel in class { - if !root.join(rel).is_file() { - missing.push(rel.to_string()); - } - } - } - missing.sort(); - missing.dedup(); - assert!( - missing.is_empty(), - "allowlist references files that no longer exist (clean them up): {missing:?}" - ); -} - -// --------------------------------------------------------------------------- -// Dependency-boundary guard: no secure-exec crate may depend on an -// agent / ACP / session crate. secure-exec must remain free of Agent OS -// concerns (ACP, agent adapters, sessions). -// --------------------------------------------------------------------------- - -#[test] -fn no_secure_exec_crate_depends_on_agent_acp_session() { - let root = repo_root(); - let crates_dir = root.join("crates"); - let banned_dep_markers = ["agent", "acp", "session"]; - - let mut violations = Vec::new(); - let mut crate_dirs: Vec = std::fs::read_dir(&crates_dir) - .expect("crates/ exists") - .filter_map(|e| e.ok().map(|e| e.path())) - .filter(|p| p.is_dir()) - .collect(); - crate_dirs.sort(); - - for crate_dir in crate_dirs { - let manifest = crate_dir.join("Cargo.toml"); - if !manifest.is_file() { - continue; - } - let text = std::fs::read_to_string(&manifest) - .unwrap_or_else(|err| panic!("read {manifest:?}: {err}")); - let mut in_deps = false; - for raw in text.lines() { - let line = raw.trim(); - if line.starts_with('[') { - // Any table whose name mentions "dependencies" is a dep table. - in_deps = line.contains("dependencies"); - continue; - } - if !in_deps || line.is_empty() || line.starts_with('#') { - continue; - } - // Dependency key is the token before `=` or whitespace. - let key = line - .split(['=', ' ', '\t']) - .next() - .unwrap_or("") - .trim_matches('"') - .to_ascii_lowercase(); - if key.is_empty() { - continue; - } - // Only consider secure-exec / agentos style crate names, and skip - // false positives like "tokio" containing none of the markers. - for marker in banned_dep_markers { - if key.contains(marker) { - violations.push(format!( - "{}: depends on banned crate `{}`", - manifest - .strip_prefix(&root) - .unwrap_or(&manifest) - .to_string_lossy(), - key - )); - } - } - } - } - - assert!( - violations.is_empty(), - "\n\nsecure-exec crates must not depend on agent/acp/session crates \ -(Agent OS owns those). Offending dependencies:\n\n{}\n", - violations.join("\n") - ); -} diff --git a/crates/sidecar/tests/bidirectional_frames.rs b/crates/sidecar/tests/bidirectional_frames.rs deleted file mode 100644 index 0f82f08f7..000000000 --- a/crates/sidecar/tests/bidirectional_frames.rs +++ /dev/null @@ -1,172 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - GuestRuntimeKind, HostCallbackRequest, HostCallbackResultResponse, OwnershipScope, - SidecarRequestPayload, SidecarResponseFrame, SidecarResponsePayload, -}; -use serde_json::json; -use support::{ - authenticate_wire, create_vm_wire, new_sidecar, open_session_wire, temp_dir, wire_vm, -}; - -const SIDECAR_CALLBACK_LIMIT: usize = 10_000; - -fn host_callback(index: usize) -> SidecarRequestPayload { - SidecarRequestPayload::HostCallbackRequest(HostCallbackRequest { - invocation_id: format!("invoke-{index}"), - callback_key: "toolkit:tool".to_string(), - input: json!({ "prompt": "ping", "index": index }).to_string(), - timeout_ms: 1_000, - }) -} - -fn host_callback_response(index: usize) -> SidecarResponsePayload { - SidecarResponsePayload::HostCallbackResultResponse(HostCallbackResultResponse { - invocation_id: format!("invoke-{index}"), - result: Some(json!({ "ok": true }).to_string()), - error: None, - }) -} - -fn new_vm_scope( - name: &str, -) -> ( - secure_exec_sidecar::NativeSidecar, - OwnershipScope, -) { - let mut sidecar = new_sidecar(name); - let connection_id = authenticate_wire(&mut sidecar, "client-hint"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &temp_dir(&format!("{name}-vm")), - ); - (sidecar, wire_vm(&connection_id, &session_id, &vm_id)) -} - -#[test] -fn native_sidecar_tracks_sidecar_initiated_requests_and_responses() { - let (mut sidecar, ownership) = new_vm_scope("bidirectional-frames"); - - let request_id = sidecar - .queue_wire_sidecar_request(ownership.clone(), host_callback(1)) - .expect("queue wire sidecar request"); - assert_eq!(request_id, -1); - - let outbound = sidecar - .pop_wire_sidecar_request() - .expect("pop wire sidecar request") - .expect("pending outbound request"); - assert_eq!(outbound.request_id, -1); - - sidecar - .accept_wire_sidecar_response(SidecarResponseFrame { - schema: secure_exec_sidecar::wire::protocol_schema(), - request_id: outbound.request_id, - ownership: outbound.ownership.clone(), - payload: host_callback_response(1), - }) - .expect("accept wire sidecar response"); - - let completed = sidecar - .take_wire_sidecar_response(outbound.request_id) - .expect("take wire sidecar response") - .expect("completed sidecar response"); - assert_eq!(completed.request_id, -1); - assert!(matches!( - completed.payload, - SidecarResponsePayload::HostCallbackResultResponse(_) - )); -} - -#[test] -fn native_sidecar_bounds_undrained_outbound_sidecar_requests() { - let (mut sidecar, ownership) = new_vm_scope("bidirectional-outbound-bound"); - - for index in 0..SIDECAR_CALLBACK_LIMIT { - sidecar - .queue_wire_sidecar_request(ownership.clone(), host_callback(index)) - .expect("queue wire sidecar request within outbound limit"); - } - - let error = sidecar - .queue_wire_sidecar_request(ownership, host_callback(SIDECAR_CALLBACK_LIMIT)) - .expect_err("undrained outbound queue should be bounded"); - assert!( - error - .to_string() - .contains("outbound sidecar request queue exceeded"), - "unexpected outbound queue error: {error}" - ); -} - -#[test] -fn native_sidecar_bounds_popped_unanswered_sidecar_requests() { - let (mut sidecar, ownership) = new_vm_scope("bidirectional-pending-bound"); - - for index in 0..SIDECAR_CALLBACK_LIMIT { - sidecar - .queue_wire_sidecar_request(ownership.clone(), host_callback(index)) - .expect("queue wire sidecar request within pending limit"); - sidecar - .pop_wire_sidecar_request() - .expect("pop wire sidecar request") - .expect("pop queued sidecar request"); - } - - let error = sidecar - .queue_wire_sidecar_request(ownership, host_callback(SIDECAR_CALLBACK_LIMIT)) - .expect_err("pending response tracker should be bounded"); - assert!( - error - .to_string() - .contains("sidecar response tracker exceeded"), - "unexpected pending tracker error: {error}" - ); -} - -#[test] -fn native_sidecar_bounds_completed_sidecar_responses() { - let (mut sidecar, ownership) = new_vm_scope("bidirectional-completed-bound"); - let mut latest_request_id = 0; - - for index in 0..=SIDECAR_CALLBACK_LIMIT { - let request_id = sidecar - .queue_wire_sidecar_request(ownership.clone(), host_callback(index)) - .expect("queue wire sidecar request"); - let outbound = sidecar - .pop_wire_sidecar_request() - .expect("pop wire sidecar request") - .expect("pop queued sidecar request"); - assert_eq!(outbound.request_id, request_id); - sidecar - .accept_wire_sidecar_response(SidecarResponseFrame { - schema: secure_exec_sidecar::wire::protocol_schema(), - request_id, - ownership: ownership.clone(), - payload: host_callback_response(index), - }) - .expect("accept wire sidecar response"); - latest_request_id = request_id; - } - - assert!( - sidecar - .take_wire_sidecar_response(-1) - .expect("take evicted wire sidecar response") - .is_none(), - "oldest completed response should be evicted" - ); - assert_eq!( - sidecar - .take_wire_sidecar_response(latest_request_id) - .expect("take latest wire sidecar response") - .expect("latest completed response should remain") - .request_id, - latest_request_id - ); -} diff --git a/crates/sidecar/tests/bridge.rs b/crates/sidecar/tests/bridge.rs deleted file mode 100644 index 254d93935..000000000 --- a/crates/sidecar/tests/bridge.rs +++ /dev/null @@ -1,166 +0,0 @@ -#[path = "../../bridge/tests/support.rs"] -mod bridge_support; - -use bridge_support::RecordingBridge; -use secure_exec_bridge::{ - BridgeTypes, ClockRequest, CommandPermissionRequest, CreateJavascriptContextRequest, - DiagnosticRecord, EnvironmentAccess, EnvironmentPermissionRequest, FilesystemAccess, - FilesystemPermissionRequest, FilesystemSnapshot, FlushFilesystemStateRequest, - LifecycleEventRecord, LifecycleState, LoadFilesystemStateRequest, LogLevel, LogRecord, - NetworkAccess, NetworkPermissionRequest, PathRequest, PollExecutionEventRequest, - ReadFileRequest, StructuredEventRecord, WriteFileRequest, -}; -use secure_exec_sidecar::NativeSidecarBridge; -use std::collections::BTreeMap; -use std::fmt::Debug; - -fn assert_native_sidecar_bridge(bridge: &mut B) -where - B: NativeSidecarBridge, - ::Error: Debug, -{ - bridge - .write_file(WriteFileRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/config.json"), - contents: br#"{"ok":true}"#.to_vec(), - }) - .expect("write file"); - assert!(bridge - .exists(PathRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/config.json"), - }) - .expect("exists")); - assert_eq!( - bridge - .read_file(ReadFileRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/config.json"), - }) - .expect("read file"), - br#"{"ok":true}"#.to_vec() - ); - - assert_eq!( - bridge - .check_filesystem_access(FilesystemPermissionRequest { - vm_id: String::from("vm-1"), - path: String::from("/workspace/config.json"), - access: FilesystemAccess::Read, - }) - .expect("filesystem permission"), - secure_exec_bridge::PermissionDecision::allow() - ); - assert_eq!( - bridge - .check_network_access(NetworkPermissionRequest { - vm_id: String::from("vm-1"), - access: NetworkAccess::Fetch, - resource: String::from("https://example.test"), - }) - .expect("network permission"), - secure_exec_bridge::PermissionDecision::allow() - ); - assert_eq!( - bridge - .check_command_execution(CommandPermissionRequest { - vm_id: String::from("vm-1"), - command: String::from("node"), - args: vec![String::from("--version")], - cwd: None, - env: BTreeMap::new(), - }) - .expect("command permission"), - secure_exec_bridge::PermissionDecision::allow() - ); - assert_eq!( - bridge - .check_environment_access(EnvironmentPermissionRequest { - vm_id: String::from("vm-1"), - access: EnvironmentAccess::Read, - key: String::from("PATH"), - value: None, - }) - .expect("env permission"), - secure_exec_bridge::PermissionDecision::allow() - ); - - bridge - .flush_filesystem_state(FlushFilesystemStateRequest { - vm_id: String::from("vm-1"), - snapshot: FilesystemSnapshot { - format: String::from("tar"), - bytes: vec![1, 2, 3], - }, - }) - .expect("flush state"); - assert_eq!( - bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: String::from("vm-1"), - }) - .expect("load state") - .expect("snapshot"), - FilesystemSnapshot { - format: String::from("tar"), - bytes: vec![1, 2, 3], - } - ); - assert_eq!( - bridge - .wall_clock(ClockRequest { - vm_id: String::from("vm-1"), - }) - .expect("wall clock"), - std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_710_000_000) - ); - bridge - .emit_log(LogRecord { - vm_id: String::from("vm-1"), - level: LogLevel::Info, - message: String::from("native sidecar ready"), - }) - .expect("emit log"); - bridge - .emit_diagnostic(DiagnosticRecord { - vm_id: String::from("vm-1"), - message: String::from("snapshot flushed"), - fields: BTreeMap::new(), - }) - .expect("emit diagnostic"); - bridge - .emit_structured_event(StructuredEventRecord { - vm_id: String::from("vm-1"), - name: String::from("vm.created"), - fields: BTreeMap::new(), - }) - .expect("emit structured event"); - bridge - .emit_lifecycle(LifecycleEventRecord { - vm_id: String::from("vm-1"), - state: LifecycleState::Ready, - detail: None, - }) - .expect("emit lifecycle"); - - let context = bridge - .create_javascript_context(CreateJavascriptContextRequest { - vm_id: String::from("vm-1"), - bootstrap_module: None, - }) - .expect("create context"); - assert!(context.context_id.starts_with("js-context-")); - assert!(bridge - .poll_execution_event(PollExecutionEventRequest { - vm_id: String::from("vm-1"), - }) - .expect("poll event") - .is_none()); -} - -#[test] -fn sidecar_crate_compiles_against_composed_host_bridge() { - let mut bridge = RecordingBridge::default(); - assert_native_sidecar_bridge(&mut bridge); -} diff --git a/crates/sidecar/tests/builtin_completeness.rs b/crates/sidecar/tests/builtin_completeness.rs deleted file mode 100644 index 3268d7166..000000000 --- a/crates/sidecar/tests/builtin_completeness.rs +++ /dev/null @@ -1,528 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{EventPayload, GuestRuntimeKind, StreamChannel}; -use serde_json::Value; -use std::collections::HashMap; -use std::fmt::Write as _; -use std::path::Path; -use std::time::{Duration, Instant}; -use support::{ - authenticate_wire, create_vm_wire_with_metadata, execute_wire, new_sidecar, open_session_wire, - temp_dir, wire_session, wire_vm, write_fixture, -}; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum BuiltinStatus { - Polyfilled, - KernelBacked, - Denied, - StubOk, -} - -#[derive(Clone, Copy, Debug)] -struct BuiltinExpectation { - name: &'static str, - status: BuiltinStatus, -} - -const BUILTIN_EXPECTATIONS: &[BuiltinExpectation] = &[ - BuiltinExpectation { - name: "fs", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "fs/promises", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "path", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "path/posix", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "path/win32", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "os", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "crypto", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "http", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "https", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "http2", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "net", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "dgram", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "dns", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "dns/promises", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "tls", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "child_process", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "stream", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "events", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "buffer", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "util", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "util/types", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "url", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "querystring", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "sqlite", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "string_decoder", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "punycode", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "zlib", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "assert", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "constants", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "console", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "readline", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "tty", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "perf_hooks", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "timers", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "timers/promises", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "stream/promises", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "stream/consumers", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "stream/web", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "module", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "process", - status: BuiltinStatus::KernelBacked, - }, - BuiltinExpectation { - name: "vm", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "worker_threads", - status: BuiltinStatus::StubOk, - }, - BuiltinExpectation { - name: "inspector", - status: BuiltinStatus::Denied, - }, - BuiltinExpectation { - name: "v8", - status: BuiltinStatus::Polyfilled, - }, - BuiltinExpectation { - name: "cluster", - status: BuiltinStatus::Denied, - }, - BuiltinExpectation { - name: "async_hooks", - status: BuiltinStatus::StubOk, - }, - BuiltinExpectation { - name: "diagnostics_channel", - status: BuiltinStatus::StubOk, - }, - BuiltinExpectation { - name: "wasi", - status: BuiltinStatus::Denied, - }, - BuiltinExpectation { - name: "trace_events", - status: BuiltinStatus::Denied, - }, - BuiltinExpectation { - name: "repl", - status: BuiltinStatus::Denied, - }, - BuiltinExpectation { - name: "domain", - status: BuiltinStatus::Denied, - }, - BuiltinExpectation { - name: "sys", - status: BuiltinStatus::Polyfilled, - }, -]; - -const EXPECTED_RUNTIME_BUILTINS: &[&str] = &[ - "assert", - "async_hooks", - "buffer", - "child_process", - "cluster", - "console", - "constants", - "crypto", - "dgram", - "diagnostics_channel", - "dns", - "dns/promises", - "domain", - "events", - "fs", - "fs/promises", - "http", - "http2", - "https", - "inspector", - "module", - "net", - "os", - "path", - "path/posix", - "path/win32", - "perf_hooks", - "process", - "punycode", - "querystring", - "readline", - "repl", - "sqlite", - "stream", - "stream/consumers", - "stream/promises", - "stream/web", - "string_decoder", - "sys", - "timers", - "timers/promises", - "tls", - "trace_events", - "tty", - "url", - "util", - "util/types", - "v8", - "vm", - "wasi", - "worker_threads", - "zlib", -]; - -const COMPLETENESS_SCRIPT: &str = r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const target = process.argv[2]; -if (target === "--inventory") { - const builtinModules = require("module").builtinModules.slice().sort(); - console.log(JSON.stringify({ builtinModules })); - process.exit(0); -} - -try { - const mod = require(target); - const modType = typeof mod; - const ownKeys = - mod != null && (modType === "object" || modType === "function") - ? Array.from( - new Set([ - ...Object.keys(mod), - ...Object.getOwnPropertyNames(mod), - ]), - ).sort() - : []; - - console.log( - JSON.stringify({ - target, - ok: true, - type: modType, - isNull: mod === null, - ownKeyCount: ownKeys.length, - emptyObject: modType === "object" && mod !== null && ownKeys.length === 0, - }), - ); -} catch (error) { - console.log( - JSON.stringify({ - target, - ok: false, - code: error?.code ?? null, - name: error?.name ?? null, - message: String(error?.message ?? error), - }), - ); -} -"#; - -const PROBE_OUTPUT_BYTE_LIMIT: usize = 1024 * 1024; - -fn allowed_builtins_json() -> String { - let allowed = BUILTIN_EXPECTATIONS - .iter() - .filter(|builtin| builtin.status != BuiltinStatus::Denied) - .map(|builtin| builtin.name) - .collect::>(); - serde_json::to_string(&allowed).expect("serialize allowed builtin list") -} - -fn run_guest_probe(entrypoint: &Path, arg: &str) -> Value { - let mut sidecar = new_sidecar(&format!( - "builtin-completeness-{}", - arg.chars() - .map(|ch| if ch.is_ascii_alphanumeric() { ch } else { '-' }) - .collect::() - )); - let connection_id = authenticate_wire(&mut sidecar, &format!("conn-{arg}")); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let cwd = entrypoint.parent().expect("entrypoint parent"); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - cwd, - HashMap::from([( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - allowed_builtins_json(), - )]), - ); - - let process_id = format!( - "probe-{}", - arg.chars() - .map(|ch| if ch.is_ascii_alphanumeric() { ch } else { '-' }) - .collect::() - ); - - execute_wire( - &mut sidecar, - 100, - &connection_id, - &session_id, - &vm_id, - &process_id, - GuestRuntimeKind::JavaScript, - entrypoint, - vec![arg.to_owned()], - ); - - let ownership = wire_session(&connection_id, &session_id); - let deadline = Instant::now() + Duration::from_secs(5); - let mut stdout = String::new(); - let mut stderr = String::new(); - let mut exit = None; - - loop { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll sidecar event"); - if let Some(event) = event { - assert_eq!( - event.ownership, - wire_vm(&connection_id, &session_id, &vm_id) - ); - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == process_id => { - match output.channel { - StreamChannel::Stdout => { - append_probe_output(&mut stdout, &output.chunk, arg, "stdout") - } - StreamChannel::Stderr => { - append_probe_output(&mut stderr, &output.chunk, arg, "stderr") - } - } - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - exit = Some((exited.exit_code, Instant::now())); - } - _ => {} - } - } - - if let Some((exit_code, seen_at)) = exit { - if Instant::now().duration_since(seen_at) >= Duration::from_millis(200) { - assert_eq!( - exit_code, 0, - "guest probe failed for {arg}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stderr.trim().is_empty(), - "guest probe stderr for {arg}:\n{stderr}" - ); - return serde_json::from_str(stdout.trim()).expect("parse builtin probe JSON"); - } - } - - assert!( - Instant::now() < deadline, - "timed out waiting for process events for builtin {arg}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - } -} - -fn append_probe_output(buffer: &mut String, chunk: &[u8], arg: &str, channel: &str) { - let text = String::from_utf8_lossy(chunk); - assert!( - buffer.len().saturating_add(text.len()) <= PROBE_OUTPUT_BYTE_LIMIT, - "builtin probe {arg} exceeded {PROBE_OUTPUT_BYTE_LIMIT} bytes on {channel}" - ); - buffer.push_str(&text); -} - -#[test] -fn every_guest_builtin_is_classified_and_never_silently_missing() { - let cwd = temp_dir("builtin-completeness"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture(&entrypoint, COMPLETENESS_SCRIPT); - - let inventory = run_guest_probe(&entrypoint, "--inventory"); - let actual_inventory = inventory["builtinModules"] - .as_array() - .expect("builtinModules array") - .iter() - .map(|value| value.as_str().expect("builtin module string")) - .collect::>(); - assert_eq!( - actual_inventory, EXPECTED_RUNTIME_BUILTINS, - "guest builtin inventory changed; classify the added/removed modules in builtin_completeness.rs" - ); - - let mut failures = Vec::new(); - - for builtin in BUILTIN_EXPECTATIONS { - let result = run_guest_probe(&entrypoint, builtin.name); - - match builtin.status { - BuiltinStatus::Denied => { - let code = result["code"].as_str(); - if result["ok"].as_bool() != Some(false) || code != Some("ERR_ACCESS_DENIED") { - failures.push(format!( - "{name}: expected ERR_ACCESS_DENIED, got {result}", - name = builtin.name - )); - } - } - BuiltinStatus::Polyfilled | BuiltinStatus::KernelBacked | BuiltinStatus::StubOk => { - let ok = result["ok"].as_bool() == Some(true); - let type_ok = matches!(result["type"].as_str(), Some("object" | "function")); - let is_null = result["isNull"].as_bool() == Some(true); - let empty_object = result["emptyObject"].as_bool() == Some(true); - if !ok { - failures.push(format!( - "{name}: expected loaded module, got {result}", - name = builtin.name - )); - } else if !type_ok { - failures.push(format!( - "{name}: expected typeof object/function, got {result}", - name = builtin.name - )); - } else if is_null { - failures.push(format!( - "{name}: module resolved to null, got {result}", - name = builtin.name - )); - } else if empty_object { - failures.push(format!( - "{name}: module resolved to an empty object stub, got {result}", - name = builtin.name - )); - } - } - } - } - - if !failures.is_empty() { - let mut message = String::from("builtin completeness failures:\n"); - for failure in failures { - let _ = writeln!(&mut message, "- {failure}"); - } - panic!("{message}"); - } -} diff --git a/crates/sidecar/tests/builtin_conformance.rs b/crates/sidecar/tests/builtin_conformance.rs deleted file mode 100644 index 92dd2692a..000000000 --- a/crates/sidecar/tests/builtin_conformance.rs +++ /dev/null @@ -1,4301 +0,0 @@ -mod support; - -use hickory_resolver::proto::op::{Message, Query}; -use hickory_resolver::proto::rr::domain::Name; -use hickory_resolver::proto::rr::rdata::{A, AAAA, CAA, CNAME, MX, NAPTR, NS, PTR, SOA, SRV, TXT}; -use hickory_resolver::proto::rr::{RData, Record, RecordType}; -use secure_exec_sidecar::wire::{ - CloseStdinRequest, CreateVmRequest, DisposeReason, DisposeVmRequest, EventPayload, - GuestRuntimeKind, PatternPermissionScope, PermissionMode, PermissionsPolicy, RequestPayload, - ResponsePayload, RootFilesystemDescriptor, RootFilesystemMode, StreamChannel, - WriteStdinRequest, -}; -use serde_json::{json, Value}; -use std::collections::HashMap; -use std::io::{Read, Write}; -use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream, UdpSocket}; -use std::path::Path; -use std::process::{Command, Stdio}; -use std::sync::{ - atomic::{AtomicBool, Ordering}, - Arc, -}; -use std::thread; -use std::time::{Duration, Instant}; -use support::{ - assert_node_available, authenticate_wire, dispose_vm_and_close_session_wire, execute_wire, - new_sidecar, open_session_wire, temp_dir, wire_permissions_allow_all, wire_request, - wire_session, wire_vm, write_fixture, -}; - -// Timing-sensitive assertions flake under the CPU contention of a parallel test -// run (see CLAUDE.md > Testing). Gated off by default; the nightly timing lane -// sets SECURE_EXEC_RUN_TIMING_TESTS=1 to enforce them. -fn run_timing_sensitive_tests() -> bool { - std::env::var_os("SECURE_EXEC_RUN_TIMING_TESTS").is_some() -} - -const ALLOWED_NODE_BUILTINS: &[&str] = &[ - "assert", - "buffer", - "child_process", - "console", - "constants", - "crypto", - "events", - "fs", - "module", - "os", - "path", - "perf_hooks", - "punycode", - "querystring", - "stream", - "string_decoder", - "timers", - "tty", - "url", - "util", - "zlib", -]; - -const BUILTIN_CONFORMANCE_CASES: &[&str] = &[ - "fs", - "console", - "child_process", - "path", - "crypto", - "dns", - "events", - "stream", - "buffer", - "url", - "stdlib_polyfill", - "extended_builtin_polyfills", -]; - -const PROBE_OUTPUT_BYTE_LIMIT: usize = 1024 * 1024; - -fn run_host_probe(cwd: &Path, entrypoint: &Path) -> Value { - run_host_probe_with_env(cwd, entrypoint, &[]) -} - -fn run_host_probe_with_env(cwd: &Path, entrypoint: &Path, env: &[(&str, &str)]) -> Value { - let mut command = Command::new("node"); - command.arg(entrypoint).current_dir(cwd); - for (key, value) in env { - command.env(key, value); - } - - let mut child = command - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .expect("spawn host node probe"); - let stdout = child.stdout.take().expect("host probe stdout pipe"); - let stderr = child.stderr.take().expect("host probe stderr pipe"); - let stdout_reader = thread::spawn(move || read_probe_pipe(stdout, "stdout")); - let stderr_reader = thread::spawn(move || read_probe_pipe(stderr, "stderr")); - let status = child.wait().expect("wait host node probe"); - let stdout = stdout_reader - .join() - .expect("join host probe stdout reader") - .expect("read bounded host probe stdout"); - let stderr = stderr_reader - .join() - .expect("join host probe stderr reader") - .expect("read bounded host probe stderr"); - - assert!( - status.success(), - "host probe failed with status {:?}\nstdout:\n{}\nstderr:\n{}", - status.code(), - String::from_utf8_lossy(&stdout), - String::from_utf8_lossy(&stderr) - ); - - serde_json::from_slice(&stdout).expect("parse host probe JSON") -} - -fn read_probe_pipe(mut pipe: impl Read, channel: &str) -> Result, String> { - let mut output = Vec::new(); - let mut chunk = [0_u8; 8192]; - loop { - let read = pipe - .read(&mut chunk) - .map_err(|err| format!("read host probe {channel}: {err}"))?; - if read == 0 { - return Ok(output); - } - if output.len().saturating_add(read) > PROBE_OUTPUT_BYTE_LIMIT { - return Err(format!( - "host probe exceeded {PROBE_OUTPUT_BYTE_LIMIT} bytes on {channel}" - )); - } - output.extend_from_slice(&chunk[..read]); - } -} - -fn run_guest_probe(case_name: &str, cwd: &Path, entrypoint: &Path) -> Value { - run_guest_probe_with_config( - case_name, - cwd, - entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - ALLOWED_NODE_BUILTINS, - ) -} - -#[allow(clippy::too_many_arguments)] -fn create_vm_with_metadata_and_permissions( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: i64, - connection_id: &str, - session_id: &str, - runtime: GuestRuntimeKind, - cwd: &Path, - mut metadata: HashMap, - permissions: PermissionsPolicy, -) -> String { - metadata - .entry(String::from("cwd")) - .or_insert_with(|| cwd.to_string_lossy().into_owned()); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_session(connection_id, session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - runtime, - metadata, - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }, - Some(permissions), - )), - )) - .expect("create sidecar VM through wire"); - - match result.response.payload { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("unexpected wire vm create response: {other:?}"), - } -} - -fn collect_builtin_process_output( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) -> (String, String, i32) { - collect_builtin_process_output_with_timeout( - sidecar, - connection_id, - session_id, - vm_id, - process_id, - Duration::from_secs(10), - ) -} - -fn collect_builtin_process_output_with_timeout( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - timeout: Duration, -) -> (String, String, i32) { - let ownership = wire_session(connection_id, session_id); - let deadline = Instant::now() + timeout; - let mut stdout = String::new(); - let mut stderr = String::new(); - let mut exit = None; - - loop { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll builtin conformance wire event"); - if let Some(event) = event { - assert_eq!(event.ownership, wire_vm(connection_id, session_id, vm_id)); - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == process_id => { - match output.channel { - StreamChannel::Stdout => { - append_probe_output(&mut stdout, &output.chunk, process_id, "stdout") - } - StreamChannel::Stderr => { - append_probe_output(&mut stderr, &output.chunk, process_id, "stderr") - } - } - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - exit = Some((exited.exit_code, Instant::now())); - } - _ => {} - } - } - - if let Some((exit_code, seen_at)) = exit { - if Instant::now().duration_since(seen_at) >= Duration::from_millis(200) { - return (stdout, stderr, exit_code); - } - } - - assert!( - Instant::now() < deadline, - "timed out waiting for builtin conformance process {process_id}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - } -} - -fn append_probe_output(buffer: &mut String, chunk: &[u8], process_id: &str, channel: &str) { - let text = String::from_utf8_lossy(chunk); - assert!( - buffer.len().saturating_add(text.len()) <= PROBE_OUTPUT_BYTE_LIMIT, - "builtin conformance process {process_id} exceeded {PROBE_OUTPUT_BYTE_LIMIT} bytes on {channel}" - ); - buffer.push_str(&text); -} - -fn run_guest_probe_with_config( - case_name: &str, - cwd: &Path, - entrypoint: &Path, - mut metadata: HashMap, - permissions: PermissionsPolicy, - allowed_builtins: &[&str], -) -> Value { - let mut sidecar = new_sidecar(case_name); - let connection_id = authenticate_wire(&mut sidecar, &format!("conn-{case_name}")); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let allowed_builtins = - serde_json::to_string(allowed_builtins).expect("serialize builtin allowlist"); - metadata.insert( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - allowed_builtins, - ); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - cwd, - metadata, - permissions, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - &format!("proc-{case_name}"), - GuestRuntimeKind::JavaScript, - entrypoint, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_builtin_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - &format!("proc-{case_name}"), - ); - dispose_vm_and_close_session_wire(&mut sidecar, &connection_id, &session_id, &vm_id); - - assert_eq!( - exit_code, 0, - "guest probe failed for {case_name}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stderr.trim().is_empty(), - "guest probe stderr for {case_name}:\n{stderr}" - ); - - serde_json::from_str(stdout.trim()).expect("parse guest probe JSON") -} - -#[allow(clippy::too_many_arguments)] -fn run_guest_probe_in_existing_session( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id_base: i64, - connection_id: &str, - session_id: &str, - case_name: &str, - cwd: &Path, - entrypoint: &Path, - mut metadata: HashMap, -) -> Value { - let allowed_builtins = - serde_json::to_string(ALLOWED_NODE_BUILTINS).expect("serialize builtin allowlist"); - metadata.insert( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - allowed_builtins, - ); - - let vm_id = create_vm_with_metadata_and_permissions( - sidecar, - request_id_base, - connection_id, - session_id, - GuestRuntimeKind::JavaScript, - cwd, - metadata, - wire_permissions_allow_all(), - ); - - let process_id = format!("proc-{case_name}"); - execute_wire( - sidecar, - request_id_base + 1, - connection_id, - session_id, - &vm_id, - &process_id, - GuestRuntimeKind::JavaScript, - entrypoint, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = - collect_builtin_process_output(sidecar, connection_id, session_id, &vm_id, &process_id); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id_base + 2, - wire_vm(connection_id, session_id, &vm_id), - RequestPayload::DisposeVmRequest(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - )) - .expect("dispose sidecar VM through wire"); - - match result.response.payload { - ResponsePayload::VmDisposedResponse(response) => { - assert_eq!(response.vm_id, vm_id); - } - other => panic!("unexpected wire vm dispose response: {other:?}"), - } - - assert_eq!( - exit_code, 0, - "guest probe failed for {case_name}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stderr.trim().is_empty(), - "guest probe stderr for {case_name}:\n{stderr}" - ); - - serde_json::from_str(stdout.trim()).expect("parse guest probe JSON") -} - -fn assert_conformance(case_name: &str, script: &str) { - assert_node_available(); - - let cwd = temp_dir(&format!("builtin-conformance-{case_name}")); - let entrypoint = cwd.join("entry.mjs"); - write_fixture(&entrypoint, script); - - let host = run_host_probe(&cwd, &entrypoint); - let guest = run_guest_probe(case_name, &cwd, &entrypoint); - - assert_eq!( - guest, - host, - "guest V8 result diverged from host Node for {case_name}\nhost: {}\nguest: {}", - serde_json::to_string_pretty(&host).expect("pretty host JSON"), - serde_json::to_string_pretty(&guest).expect("pretty guest JSON") - ); -} - -fn run_isolated_builtin_conformance_test(test_name: &str) { - let current_exe = std::env::current_exe().expect("current test binary path"); - let status = Command::new(¤t_exe) - .arg("--exact") - .arg("__builtin_conformance_extra_test_runner") - .arg("--nocapture") - .env("AGENTOS_BUILTIN_CONFORMANCE_EXTRA_TEST", test_name) - .status() - .unwrap_or_else(|error| { - panic!("spawn builtin conformance extra runner for {test_name}: {error}") - }); - - assert!( - status.success(), - "builtin conformance extra test {test_name} failed with status {status}" - ); -} - -fn write_process_stdin( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: i64, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - chunk: &str, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::WriteStdinRequest(WriteStdinRequest { - process_id: process_id.to_owned(), - chunk: chunk.as_bytes().to_vec(), - }), - )) - .expect("write builtin conformance stdin through wire"); - - match result.response.payload { - ResponsePayload::StdinWrittenResponse(response) => { - assert_eq!(response.process_id, process_id); - assert_eq!(response.accepted_bytes, chunk.len() as u64); - } - other => panic!("unexpected wire stdin-written response: {other:?}"), - } -} - -fn close_process_stdin( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: i64, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::CloseStdinRequest(CloseStdinRequest { - process_id: process_id.to_owned(), - }), - )) - .expect("close builtin conformance stdin through wire"); - - match result.response.payload { - ResponsePayload::StdinClosedResponse(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected wire stdin-closed response: {other:?}"), - } -} - -struct FixtureDnsServer { - addr: SocketAddr, - running: Arc, - thread: Option>, -} - -impl FixtureDnsServer { - fn start() -> Self { - let socket = UdpSocket::bind("127.0.0.1:0").expect("bind fixture DNS server"); - socket - .set_read_timeout(Some(Duration::from_millis(100))) - .expect("set fixture DNS timeout"); - let addr = socket.local_addr().expect("fixture DNS local addr"); - let running = Arc::new(AtomicBool::new(true)); - let thread_running = Arc::clone(&running); - let thread = thread::spawn(move || { - let mut buffer = [0_u8; 2048]; - while thread_running.load(Ordering::SeqCst) { - let Ok((len, peer)) = socket.recv_from(&mut buffer) else { - continue; - }; - let Ok(request) = Message::from_vec(&buffer[..len]) else { - continue; - }; - let response = fixture_dns_response(&request); - let bytes = response.to_vec().expect("encode fixture DNS response"); - let _ = socket.send_to(&bytes, peer); - } - }); - Self { - addr, - running, - thread: Some(thread), - } - } -} - -impl Drop for FixtureDnsServer { - fn drop(&mut self) { - self.running.store(false, Ordering::SeqCst); - if let Ok(socket) = UdpSocket::bind("127.0.0.1:0") { - let _ = socket.send_to(&[0], self.addr); - } - if let Some(thread) = self.thread.take() { - thread.join().expect("join fixture DNS thread"); - } - } -} - -fn fixture_dns_response(request: &Message) -> Message { - let mut response = Message::response(request.metadata.id, request.metadata.op_code); - response.metadata.authoritative = true; - response.metadata.recursion_available = true; - response.add_queries(request.queries.iter().cloned()); - if let Some(query) = request.queries.first() { - response.add_answers(fixture_dns_answers(query)); - } - response -} - -fn fixture_dns_answers(query: &Query) -> Vec { - let name = query.name().to_ascii(); - match (name.as_str(), query.query_type()) { - ("bundle.example.test.", RecordType::A) => vec![ - fixture_dns_record("bundle.example.test.", RData::A(A::new(203, 0, 113, 10))), - fixture_dns_record("bundle.example.test.", RData::A(A::new(203, 0, 113, 11))), - ], - ("bundle.example.test.", RecordType::AAAA) => vec![ - fixture_dns_record( - "bundle.example.test.", - RData::AAAA(AAAA::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0010)), - ), - fixture_dns_record( - "bundle.example.test.", - RData::AAAA(AAAA::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0011)), - ), - ], - ("bundle.example.test.", RecordType::MX) => vec![fixture_dns_record( - "bundle.example.test.", - RData::MX(MX::new(10, fixture_dns_name("mail.example.test."))), - )], - ("bundle.example.test.", RecordType::TXT) => vec![ - fixture_dns_record( - "bundle.example.test.", - RData::TXT(TXT::new(vec![String::from("v=spf1"), String::from("-all")])), - ), - fixture_dns_record( - "bundle.example.test.", - RData::TXT(TXT::new(vec![String::from("secure-exec")])), - ), - ], - ("bundle.example.test.", RecordType::ANY) => vec![ - fixture_dns_record("bundle.example.test.", RData::A(A::new(203, 0, 113, 10))), - fixture_dns_record("bundle.example.test.", RData::A(A::new(203, 0, 113, 11))), - fixture_dns_record( - "bundle.example.test.", - RData::AAAA(AAAA::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0010)), - ), - fixture_dns_record( - "bundle.example.test.", - RData::AAAA(AAAA::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0011)), - ), - fixture_dns_record( - "bundle.example.test.", - RData::MX(MX::new(10, fixture_dns_name("mail.example.test."))), - ), - fixture_dns_record( - "bundle.example.test.", - RData::TXT(TXT::new(vec![String::from("v=spf1"), String::from("-all")])), - ), - ], - ("alias.example.test.", RecordType::CNAME) => vec![fixture_dns_record( - "alias.example.test.", - RData::CNAME(CNAME(fixture_dns_name("bundle.example.test."))), - )], - ("ptr.example.test.", RecordType::PTR) => vec![fixture_dns_record( - "ptr.example.test.", - RData::PTR(PTR(fixture_dns_name("host.example.test."))), - )], - ("zone.example.test.", RecordType::NS) => vec![fixture_dns_record( - "zone.example.test.", - RData::NS(NS(fixture_dns_name("ns1.example.test."))), - )], - ("zone.example.test.", RecordType::SOA) => vec![fixture_dns_record( - "zone.example.test.", - RData::SOA(SOA::new( - fixture_dns_name("ns1.example.test."), - fixture_dns_name("hostmaster.example.test."), - 2026041601, - 3600, - 600, - 86400, - 60, - )), - )], - ("_svc._tcp.example.test.", RecordType::SRV) => vec![fixture_dns_record( - "_svc._tcp.example.test.", - RData::SRV(SRV::new( - 1, - 5, - 8443, - fixture_dns_name("svc-target.example.test."), - )), - )], - ("naptr.example.test.", RecordType::NAPTR) => vec![fixture_dns_record( - "naptr.example.test.", - RData::NAPTR(NAPTR::new( - 10, - 20, - b"s".to_vec().into_boxed_slice(), - b"SIP+D2U".to_vec().into_boxed_slice(), - b"!^.*$!sip:service@example.test!" - .to_vec() - .into_boxed_slice(), - fixture_dns_name("_sip._udp.example.test."), - )), - )], - ("caa.example.test.", RecordType::CAA) => vec![ - fixture_dns_record( - "caa.example.test.", - RData::CAA(CAA::new_issue( - false, - Some(fixture_dns_name("letsencrypt.org.")), - vec![], - )), - ), - fixture_dns_record( - "caa.example.test.", - RData::CAA(CAA::new_iodef( - false, - url::Url::parse("https://iodef.example.test/report") - .expect("fixture CAA iodef URL"), - )), - ), - ], - _ => Vec::new(), - } -} - -fn fixture_dns_record(name: &str, data: RData) -> Record { - Record::from_rdata(fixture_dns_name(name), 60, data) -} - -fn fixture_dns_name(name: &str) -> Name { - name.parse().expect("valid fixture DNS name") -} - -fn read_http_request(stream: &mut TcpStream) -> String { - let mut request = Vec::new(); - let mut buffer = [0_u8; 1024]; - - loop { - let bytes_read = stream.read(&mut buffer).expect("read http request"); - assert!( - bytes_read > 0, - "connection closed before full HTTP request arrived" - ); - request.extend_from_slice(&buffer[..bytes_read]); - if request.windows(4).any(|window| window == b"\r\n\r\n") { - break; - } - } - - String::from_utf8(request).expect("request utf8") -} - -fn http_request_custom_agent_reuses_keepalive_socket_impl() { - assert_node_available(); - - let listener = TcpListener::bind("127.0.0.1:0").expect("bind host http listener"); - let port = listener.local_addr().expect("listener addr").port(); - let cwd = temp_dir("builtin-http-agent-keepalive"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - format!( - r#" -import http from "node:http"; - -const agent = new http.Agent({{ - keepAlive: true, - maxSockets: 1, -}}); - -function request(path) {{ - return new Promise((resolve, reject) => {{ - const req = http.request({{ - host: "127.0.0.1", - port: {port}, - path, - method: "GET", - agent, - }}, (res) => {{ - res.setEncoding("utf8"); - let body = ""; - res.on("data", (chunk) => {{ - body += chunk; - }}); - res.on("end", () => {{ - resolve({{ - body, - reusedSocket: req.reusedSocket, - socketLocalPort: req.socket?.localPort ?? null, - statusCode: res.statusCode ?? null, - }}); - }}); - }}); - req.on("error", reject); - req.end(); - }}); -}} - -const first = await request("/first"); -const second = await request("/second"); -await new Promise((resolve) => setTimeout(resolve, 0)); - -const freeSockets = Object.values(agent.freeSockets).reduce( - (total, sockets) => total + sockets.length, - 0, -); - -console.log(JSON.stringify({{ - first, - second, - freeSockets, - totalSocketCount: agent.totalSocketCount, -}})); - -agent.destroy(); -"#, - ), - ); - - let case_name = "builtin-http-agent-keepalive"; - let mut sidecar = new_sidecar(case_name); - let connection_id = authenticate_wire(&mut sidecar, &format!("conn-{case_name}")); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let allowed_builtins = serde_json::to_string(&["http"]).expect("serialize builtin allowlist"); - let guest_env = HashMap::from([ - ( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - allowed_builtins, - ), - ( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - format!("[{port}]"), - ), - ]); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - guest_env, - wire_permissions_allow_all(), - ); - - let server = thread::spawn(move || { - listener - .set_nonblocking(true) - .expect("configure nonblocking listener"); - let deadline = Instant::now() + Duration::from_secs(10); - let (mut stream, _) = loop { - match listener.accept() { - Ok(accepted) => break accepted, - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - assert!( - Instant::now() < deadline, - "timed out waiting for guest keep-alive connection" - ); - thread::sleep(Duration::from_millis(10)); - } - Err(error) => panic!("accept keep-alive connection: {error}"), - } - }; - - stream - .set_read_timeout(Some(Duration::from_secs(5))) - .expect("set read timeout"); - - let first_request = read_http_request(&mut stream); - assert!( - first_request.contains("GET /first HTTP/1.1"), - "unexpected first request: {first_request}" - ); - stream - .write_all( - b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\nConnection: keep-alive\r\n\r\nfirst", - ) - .expect("write first keep-alive response"); - stream.flush().expect("flush first keep-alive response"); - - let second_request = read_http_request(&mut stream); - assert!( - second_request.contains("GET /second HTTP/1.1"), - "unexpected second request: {second_request}" - ); - stream - .write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 6\r\nConnection: close\r\n\r\nsecond") - .expect("write second keep-alive response"); - stream.flush().expect("flush second keep-alive response"); - }); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - &format!("proc-{case_name}"), - GuestRuntimeKind::JavaScript, - &entrypoint, - Vec::new(), - ); - let (stdout, stderr, exit_code) = collect_builtin_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-builtin-http-agent-keepalive", - ); - dispose_vm_and_close_session_wire(&mut sidecar, &connection_id, &session_id, &vm_id); - - server.join().expect("join keep-alive server"); - - assert_eq!( - exit_code, 0, - "guest probe failed for {case_name}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stderr.trim().is_empty(), - "guest probe stderr for {case_name}:\n{stderr}" - ); - let guest: Value = serde_json::from_str(stdout.trim()).expect("parse guest probe JSON"); - - assert_eq!(guest["first"]["statusCode"], 200); - assert_eq!(guest["first"]["body"], "first"); - assert_eq!(guest["first"]["reusedSocket"], false); - assert_eq!(guest["second"]["statusCode"], 200); - assert_eq!(guest["second"]["body"], "second"); - assert_eq!(guest["second"]["reusedSocket"], true); - assert_eq!( - guest["first"]["socketLocalPort"], guest["second"]["socketLocalPort"], - "expected second request to reuse the first socket" - ); - assert_eq!(guest["freeSockets"], 1); -} - -fn http_request_denied_egress_returns_permission_error_impl() { - assert_node_available(); - - let cwd = temp_dir("builtin-http-agent-denied"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import http from "node:http"; - -const result = await new Promise((resolve) => { - const req = http.get("http://127.0.0.1:9/denied", (res) => { - res.resume(); - resolve({ - statusCode: res.statusCode ?? null, - unexpected: true, - }); - }); - req.on("error", (error) => { - resolve({ - code: error?.code ?? null, - message: String(error?.message ?? ""), - name: error?.name ?? null, - }); - }); -}); - -console.log(JSON.stringify(result)); -"#, - ); - - let allow_all = wire_permissions_allow_all(); - let guest = run_guest_probe_with_config( - "builtin-http-agent-denied", - &cwd, - &entrypoint, - HashMap::new(), - PermissionsPolicy { - fs: allow_all.fs, - network: Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)), - child_process: allow_all.child_process, - process: allow_all.process, - env: allow_all.env, - binding: allow_all.binding, - }, - &["http"], - ); - - assert_eq!(guest["code"], "EACCES"); - assert_eq!(guest["unexpected"], Value::Null); - assert!( - guest["message"] - .as_str() - .is_some_and(|message| message.contains("permission denied")), - "unexpected denied-egress payload: {guest}" - ); -} - -#[test] -fn http_request_custom_agent_reuses_keepalive_socket() { - run_isolated_builtin_conformance_test("http-request-keepalive"); -} - -#[test] -fn http_request_denied_egress_returns_permission_error() { - run_isolated_builtin_conformance_test("http-request-denied"); -} - -fn http_socket_writes_do_not_silently_drop_data_impl() { - assert_node_available(); - - let request_socket_listener = - TcpListener::bind("127.0.0.1:0").expect("bind host request-socket listener"); - let request_socket_port = request_socket_listener - .local_addr() - .expect("request-socket listener addr") - .port(); - let request_socket_payload = "agent-socket-payload"; - - let request_socket_server = thread::spawn(move || { - let (mut stream, _) = request_socket_listener - .accept() - .expect("accept request-socket stream"); - stream - .set_read_timeout(Some(Duration::from_secs(5))) - .expect("set request-socket read timeout"); - - let request = read_http_request(&mut stream); - assert!( - request.contains("GET /socket-write HTTP/1.1"), - "unexpected keep-alive request: {request}" - ); - - stream - .write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: keep-alive\r\n\r\nok") - .expect("write keep-alive response"); - stream.flush().expect("flush keep-alive response"); - - let mut payload = vec![0; request_socket_payload.len()]; - match stream.read(&mut payload) { - Ok(0) => {} - Ok(bytes_read) => { - let payload = payload[..bytes_read].to_vec(); - assert_eq!( - String::from_utf8(payload.clone()).expect("utf8 tunneled payload"), - request_socket_payload - ); - stream - .shutdown(Shutdown::Write) - .expect("shutdown request-socket write half"); - } - Err(error) - if matches!( - error.kind(), - std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut - ) => {} - Err(error) => panic!("read request-socket payload: {error}"), - } - }); - - let cwd = temp_dir("builtin-http-socket-writes"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - format!( - r#" -import http from "node:http"; - -const requestSocketResult = await new Promise((resolve, reject) => {{ - const agent = new http.Agent({{ keepAlive: true, maxSockets: 1 }}); - const req = http.request({{ - host: "127.0.0.1", - port: {request_socket_port}, - path: "/socket-write", - method: "GET", - agent, - headers: {{ Connection: "keep-alive" }}, - }}, (res) => {{ - res.resume(); - res.on("end", () => {{ - const payload = "{request_socket_payload}"; - const finish = (result) => {{ - agent.destroy(); - resolve(result); - }}; - - req.socket.once("error", (error) => {{ - finish({{ - outcome: error?.code ?? error?.name ?? String(error), - sameSocket: !!req.socket, - statusCode: res.statusCode ?? null, - }}); - }}); - - try {{ - let writeReturn = null; - writeReturn = req.socket.write(payload, () => {{ - finish({{ - outcome: "forwarded", - writeReturn, - sameSocket: !!req.socket, - statusCode: res.statusCode ?? null, - }}); - }}); - }} catch (error) {{ - finish({{ - outcome: error?.code ?? error?.name ?? String(error), - sameSocket: !!req.socket, - statusCode: res.statusCode ?? null, - }}); - }} - }}); - }}); - req.on("error", reject); - req.end(); -}}); - -const responseResult = (() => {{ - const res = new http.ServerResponse({{ method: "GET" }}); - const result = {{ - hasConnectionAlias: res.connection === res.socket, - socketPresent: !!res.socket, - }}; - try {{ - result.outcome = "forwarded"; - result.returnValue = res.socket.write("socket-body:"); - }} catch (error) {{ - result.outcome = error?.code ?? error?.name ?? String(error); - }} - res.end("tail"); - result.body = Buffer.concat(res._chunks ?? []).toString("utf8"); - result.headersSent = res.headersSent; - result.writableFinished = res.writableFinished; - return result; -}})(); - -console.log(JSON.stringify({{ requestSocketResult, responseResult }})); -await new Promise((resolve) => setTimeout(resolve, 0)); -process.exit(0); -"#, - ), - ); - - let guest = run_guest_probe_with_config( - "builtin-http-socket-writes", - &cwd, - &entrypoint, - HashMap::from([( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - format!("[{request_socket_port}]"), - )]), - wire_permissions_allow_all(), - &["http"], - ); - - request_socket_server - .join() - .expect("join request-socket fixture server"); - - assert_eq!(guest["requestSocketResult"]["statusCode"], 200); - assert_eq!( - guest["requestSocketResult"]["sameSocket"], - Value::Bool(true) - ); - let connect_outcome = guest["requestSocketResult"]["outcome"] - .as_str() - .expect("req.socket outcome"); - assert!( - connect_outcome == "forwarded" || connect_outcome == "ERR_NOT_IMPLEMENTED", - "unexpected req.socket.write outcome: {guest}" - ); - if connect_outcome == "forwarded" { - assert_eq!(guest["requestSocketResult"]["statusCode"], 200); - } - - assert_eq!(guest["responseResult"]["socketPresent"], Value::Bool(true)); - assert_eq!( - guest["responseResult"]["hasConnectionAlias"], - Value::Bool(true) - ); - let response_outcome = guest["responseResult"]["outcome"] - .as_str() - .expect("ServerResponse.socket outcome"); - assert!( - response_outcome == "forwarded" || response_outcome == "ERR_NOT_IMPLEMENTED", - "unexpected res.socket.write outcome: {guest}" - ); - if response_outcome == "forwarded" { - assert_eq!( - guest["responseResult"]["returnValue"], - Value::Bool(true), - "expected res.socket.write to mirror ServerResponse.write return value" - ); - assert_eq!(guest["responseResult"]["headersSent"], Value::Bool(true)); - assert_eq!( - guest["responseResult"]["writableFinished"], - Value::Bool(true) - ); - assert_eq!( - guest["responseResult"]["body"], - Value::String(String::from("socket-body:tail")) - ); - } else { - assert_eq!( - guest["responseResult"]["body"], - Value::String(String::from("tail")) - ); - } -} - -#[test] -fn http_socket_writes_do_not_silently_drop_data() { - run_isolated_builtin_conformance_test("http-socket-writes"); -} - -fn net_socket_readable_state_tracks_ssh2_writable_shape_impl() { - assert_node_available(); - - let cwd = temp_dir("builtin-net-socket-readable-state"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import net from "node:net"; - -const isWritable = (stream) => - Boolean(stream?.writable && stream?._readableState?.ended === false); - -const socket = new net.Socket(); -const open = { - ended: socket._readableState?.ended ?? null, - endEmitted: socket._readableState?.endEmitted ?? null, - writable: socket.writable ?? null, - isWritable: isWritable(socket), -}; - -socket.destroy(); - -const closed = { - ended: socket._readableState?.ended ?? null, - endEmitted: socket._readableState?.endEmitted ?? null, - writable: socket.writable ?? null, - isWritable: isWritable(socket), - destroyed: socket.destroyed ?? null, -}; - -console.log(JSON.stringify({ open, closed })); -"#, - ); - - let guest = run_guest_probe_with_config( - "net-socket-readable-state", - &cwd, - &entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - &["net"], - ); - - assert_eq!(guest["open"]["ended"], Value::Bool(false)); - assert_eq!(guest["open"]["endEmitted"], Value::Bool(false)); - assert_eq!(guest["open"]["isWritable"], Value::Bool(true)); - assert_eq!(guest["closed"]["ended"], Value::Bool(true)); - assert_eq!(guest["closed"]["endEmitted"], Value::Bool(true)); - assert_eq!(guest["closed"]["isWritable"], Value::Bool(false)); -} - -#[test] -fn net_socket_readable_state_tracks_ssh2_writable_shape() { - run_isolated_builtin_conformance_test("net-socket-readable-state"); -} - -fn readable_on_data_respects_explicit_pause_matches_host_node_impl() { - assert_conformance( - "readable-on-data-explicit-pause", - r#" -import fs from "node:fs"; - -const fixturePath = new URL("./fixture.txt", import.meta.url); -fs.writeFileSync(fixturePath, "abcdef"); - -const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); - -async function pauseThenOnDataThenResume() { - const stream = fs.createReadStream(fixturePath, { encoding: "utf8", highWaterMark: 2 }); - const chunks = []; - stream.pause(); - const afterPause = stream.readableFlowing; - stream.on("data", (chunk) => chunks.push(chunk)); - const afterOnData = stream.readableFlowing; - await delay(20); - const beforeResumeChunkCount = chunks.length; - stream.resume(); - const afterResume = stream.readableFlowing; - await new Promise((resolve, reject) => { - stream.on("end", resolve); - stream.on("error", reject); - }); - return { - afterPause, - afterOnData, - beforeResumeChunkCount, - afterResume, - chunks, - }; -} - -async function onDataAlone() { - const stream = fs.createReadStream(fixturePath, { encoding: "utf8", highWaterMark: 2 }); - const chunks = []; - const initialFlowing = stream.readableFlowing; - stream.on("data", (chunk) => chunks.push(chunk)); - const afterOnData = stream.readableFlowing; - await new Promise((resolve, reject) => { - stream.on("end", resolve); - stream.on("error", reject); - }); - return { - initialFlowing, - afterOnData, - chunks, - }; -} - -async function multiplePauseResumeCycles() { - const stream = fs.createReadStream(fixturePath, { encoding: "utf8", highWaterMark: 2 }); - const chunks = []; - const checkpoints = []; - let firstChunkSeen = false; - - stream.pause(); - checkpoints.push(["afterInitialPause", stream.readableFlowing]); - stream.on("data", (chunk) => { - chunks.push(chunk); - if (!firstChunkSeen) { - firstChunkSeen = true; - stream.pause(); - checkpoints.push(["afterMidStreamPause", stream.readableFlowing]); - setTimeout(() => { - checkpoints.push(["beforeSecondResumeChunkCount", chunks.length]); - stream.resume(); - checkpoints.push(["afterSecondResume", stream.readableFlowing]); - }, 20); - } - }); - checkpoints.push(["afterOnData", stream.readableFlowing]); - await delay(20); - checkpoints.push(["beforeFirstResumeChunkCount", chunks.length]); - stream.resume(); - checkpoints.push(["afterFirstResume", stream.readableFlowing]); - await new Promise((resolve, reject) => { - stream.on("end", resolve); - stream.on("error", reject); - }); - return { checkpoints, chunks }; -} - -console.log(JSON.stringify({ - pauseThenOnDataThenResume: await pauseThenOnDataThenResume(), - onDataAlone: await onDataAlone(), - multiplePauseResumeCycles: await multiplePauseResumeCycles(), -})); -"#, - ); -} - -#[test] -fn readable_on_data_respects_explicit_pause_matches_host_node() { - run_isolated_builtin_conformance_test("readable-on-data-explicit-pause"); -} - -fn readline_question_reads_real_stdin_impl() { - assert_node_available(); - - let cwd = temp_dir("builtin-readline-question"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import readline from "node:readline"; - -const output = { write() {} }; -const rl = readline.createInterface({ input: process.stdin, output }); -process.stdout.write("__READY__\n"); - -const callbackAnswer = await new Promise((resolve, reject) => { - const timeout = setTimeout(() => reject(new Error("callback question timed out")), 2000); - rl.question("callback> ", (answer) => { - clearTimeout(timeout); - resolve(answer); - }); -}); - -const promiseAnswer = await rl.question("promise> "); -rl.close(); - -console.log(JSON.stringify({ callbackAnswer, promiseAnswer })); -"#, - ); - - let mut sidecar = new_sidecar("builtin-readline-question"); - let connection_id = authenticate_wire(&mut sidecar, "conn-readline-question"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::from([ - ( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - serde_json::to_string(&["readline"]).expect("serialize builtin allowlist"), - ), - ( - String::from("env.SECURE_EXEC_KEEP_STDIN_OPEN"), - String::from("1"), - ), - ]), - wire_permissions_allow_all(), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-readline-question", - GuestRuntimeKind::JavaScript, - &entrypoint, - Vec::new(), - ); - let ownership = wire_session(&connection_id, &session_id); - let deadline = Instant::now() + Duration::from_secs(10); - let mut stdout = String::new(); - let mut stderr = String::new(); - let mut exit = None; - let mut stdin_sent = false; - - loop { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll readline question wire event"); - - if let Some(event) = event { - assert_eq!( - event.ownership, - wire_vm(&connection_id, &session_id, &vm_id) - ); - - match event.payload { - EventPayload::ProcessOutputEvent(output) - if output.process_id == "proc-readline-question" => - { - match output.channel { - StreamChannel::Stdout => append_probe_output( - &mut stdout, - &output.chunk, - &output.process_id, - "stdout", - ), - StreamChannel::Stderr => append_probe_output( - &mut stderr, - &output.chunk, - &output.process_id, - "stderr", - ), - } - } - EventPayload::ProcessExitedEvent(exited) - if exited.process_id == "proc-readline-question" => - { - exit = Some((exited.exit_code, Instant::now())); - } - _ => {} - } - } - - if !stdin_sent && stdout.contains("__READY__\n") { - write_process_stdin( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "proc-readline-question", - "hello\nworld\n", - ); - close_process_stdin( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-readline-question", - ); - stdin_sent = true; - } - - if let Some((exit_code, seen_at)) = exit { - if Instant::now().duration_since(seen_at) >= Duration::from_millis(200) { - let stdout = stdout.replace("__READY__\n", ""); - dispose_vm_and_close_session_wire( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - ); - - assert_eq!( - exit_code, 0, - "readline question probe failed\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!(stderr.trim().is_empty(), "unexpected stderr:\n{stderr}"); - - let payload: Value = - serde_json::from_str(stdout.trim()).expect("parse readline JSON"); - assert_eq!(payload["callbackAnswer"], "hello"); - assert_eq!(payload["promiseAnswer"], "world"); - return; - } - } - - assert!( - Instant::now() < deadline, - "timed out waiting for readline question probe\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - } -} - -#[test] -fn readline_question_reads_real_stdin() { - run_isolated_builtin_conformance_test("readline-question"); -} - -fn vm_is_context_only_accepts_create_context_tagged_sandboxes_impl() { - assert_conformance( - "vm-is-context", - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const vm = require("node:vm"); - -const safeIsContext = (value) => { - try { - return vm.isContext(value); - } catch { - return false; - } -}; - -const sandbox = {}; -const tagged = vm.createContext(sandbox); -const taggedArray = vm.createContext([]); - -console.log(JSON.stringify({ - sameReference: tagged === sandbox, - matrix: { - plainObject: safeIsContext({}), - taggedObject: safeIsContext(tagged), - plainArray: safeIsContext([]), - taggedArray: safeIsContext(taggedArray), - functionValue: safeIsContext(function demo() {}), - nullValue: safeIsContext(null), - numberValue: safeIsContext(1), - stringValue: safeIsContext("text"), - }, -})); -"#, - ); -} - -#[test] -fn vm_is_context_only_accepts_create_context_tagged_sandboxes() { - run_isolated_builtin_conformance_test("vm-is-context"); -} - -fn vm_context_isolation_and_script_options_match_host_node_impl() { - assert_conformance( - "vm-context-isolation", - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const vm = require("node:vm"); - -const sandbox = { answer: 41 }; -const context = vm.createContext(sandbox); -const runResult = vm.runInContext("answer += 1; typeof globalThis.require", context); - -let filenameLine = false; -try { - new vm.Script("throw new Error('boom')", { - filename: "named-vm.js", - lineOffset: 2, - columnOffset: 4, - }).runInNewContext({}); -} catch (error) { - filenameLine = String(error?.stack ?? error).includes("named-vm.js:3"); -} - -let invalidContextType = null; -try { - vm.runInContext("1 + 1", {}); -} catch (error) { - invalidContextType = error?.name ?? null; -} - -console.log(JSON.stringify({ - sameReference: context === sandbox, - sandboxAnswer: sandbox.answer, - newContextRequire: vm.runInNewContext("typeof globalThis.require"), - newContextBuffer: vm.runInNewContext("typeof Buffer"), - contextRequire: runResult, - filenameLine, - invalidContextType, -})); -"#, - ); -} - -#[test] -fn vm_context_isolation_and_script_options_match_host_node() { - run_isolated_builtin_conformance_test("vm-context-isolation"); -} - -fn vm_timeout_terminates_within_deadline_impl() { - let cwd = temp_dir("builtin-conformance-vm-timeout"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const vm = require("node:vm"); - -const started = Date.now(); -let timeoutCode = null; -let timeoutMessage = null; -try { - vm.runInNewContext("while (true) {}", {}, { timeout: 100 }); -} catch (error) { - timeoutCode = error?.code ?? null; - timeoutMessage = String(error?.message ?? error); -} - -console.log(JSON.stringify({ - elapsedMs: Date.now() - started, - timeoutCode, - timeoutMessage, -})); -"#, - ); - - let result = run_guest_probe("vm-timeout", &cwd, &entrypoint); - let elapsed_ms = result["elapsedMs"] - .as_u64() - .expect("vm timeout elapsed milliseconds"); - if run_timing_sensitive_tests() { - assert!( - elapsed_ms <= 200, - "vm timeout exceeded 200ms: {elapsed_ms}ms ({result})" - ); - } - assert_eq!( - result["timeoutCode"], - Value::String(String::from("ERR_SCRIPT_EXECUTION_TIMEOUT")) - ); - assert!( - result["timeoutMessage"] - .as_str() - .is_some_and(|message| message.contains("timed out")), - "vm timeout message missing timeout marker: {result}" - ); -} - -#[test] -fn vm_timeout_terminates_within_deadline() { - run_isolated_builtin_conformance_test("vm-timeout"); -} - -fn vm_optional_surface_is_implemented_or_explicitly_not_implemented_impl() { - let cwd = temp_dir("builtin-conformance-vm-optional-surface"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const vm = require("node:vm"); - -function capture(label, fn) { - try { - const value = fn(); - return typeof value?.then === "function" ? "ok" : "ok"; - } catch (error) { - return error?.code ?? `${label}-error`; - } -} - -console.log(JSON.stringify({ - compileFunction: capture("compileFunction", () => vm.compileFunction("return value;", ["value"])), - measureMemory: capture("measureMemory", () => vm.measureMemory()), -})); -"#, - ); - - let result = run_guest_probe("vm-optional-surface", &cwd, &entrypoint); - for key in ["compileFunction", "measureMemory"] { - let outcome = result[key].as_str().unwrap_or_default(); - assert!( - outcome == "ok" || outcome == "ERR_NOT_IMPLEMENTED", - "vm optional surface {key} returned unexpected outcome: {result}" - ); - } -} - -#[test] -fn vm_optional_surface_is_implemented_or_explicitly_not_implemented() { - run_isolated_builtin_conformance_test("vm-optional-surface"); -} - -fn perf_hooks_observer_and_histogram_match_host_node_impl() { - assert_conformance( - "perf-hooks-observer", - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const { PerformanceObserver, createHistogram, performance } = require("node:perf_hooks"); - -function sortEntries(entries) { - return [...entries].sort((left, right) => left.localeCompare(right)); -} - -function toEntryNames(entries) { - return entries.map((entry) => `${entry.entryType}:${entry.name}`); -} - -performance.clearMarks?.(); -performance.clearMeasures?.(); - -const callbackEntries = []; -const observer = new PerformanceObserver((list) => { - callbackEntries.push(...toEntryNames(list.getEntries())); -}); -observer.observe({ entryTypes: ["mark", "measure"] }); -performance.mark("start"); -performance.mark("end"); -performance.measure("delta", "start", "end"); -await new Promise((resolve) => setImmediate(resolve)); -const callbackObserved = sortEntries(callbackEntries); -const afterFlush = sortEntries(toEntryNames(observer.takeRecords())); -observer.disconnect(); - -performance.clearMarks?.(); -performance.clearMeasures?.(); - -const takeRecordsObserver = new PerformanceObserver(() => {}); -takeRecordsObserver.observe({ entryTypes: ["mark", "measure"] }); -performance.mark("alpha"); -performance.mark("omega"); -performance.measure("window", "alpha", "omega"); -const takeRecordsBeforeFlush = sortEntries( - toEntryNames(takeRecordsObserver.takeRecords()), -); -await new Promise((resolve) => setImmediate(resolve)); -const takeRecordsAfterFlush = sortEntries( - toEntryNames(takeRecordsObserver.takeRecords()), -); -takeRecordsObserver.disconnect(); - -const histogram = createHistogram(); -histogram.record(10); -histogram.record(20); -histogram.record(30); - -console.log(JSON.stringify({ - callbackObserved, - afterFlush, - takeRecordsBeforeFlush, - takeRecordsAfterFlush, - histogram: { - emptyP50: createHistogram().percentile(50), - p50: histogram.percentile(50), - p90: histogram.percentile(90), - }, -})); -"#, - ); -} - -#[test] -fn perf_hooks_observer_and_histogram_match_host_node() { - run_isolated_builtin_conformance_test("perf-hooks-observer"); -} - -fn run_guest_script(case_name: &str, script: &str) -> Value { - assert_node_available(); - - let cwd = temp_dir(&format!("builtin-guest-{case_name}")); - let entrypoint = cwd.join("entry.mjs"); - write_fixture(&entrypoint, script); - - run_guest_probe(case_name, &cwd, &entrypoint) -} - -fn current_openssl_version() -> String { - openssl::version::version() - .split_whitespace() - .nth(1) - .unwrap_or_else(openssl::version::version) - .to_string() -} - -fn process_runtime_stats_are_live_impl() { - let cwd = temp_dir("process-runtime-stats"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -const before = process.memoryUsage(); -const beforeCpu = process.cpuUsage(); -const retained = []; -for (let i = 0; i < 25000; i += 1) { - retained.push({ - index: i, - text: `${i}-`.padEnd(256, String(i % 10)), - }); -} -let cpuAccumulator = 0; -for (let i = 0; i < 500000; i += 1) { - cpuAccumulator += Math.sqrt(i % 1000); -} -globalThis.__retainedProcessStatsFixture = retained; -const after = process.memoryUsage(); -const deltaCpu = process.cpuUsage(beforeCpu); -const resource = process.resourceUsage(); - -console.log(JSON.stringify({ - before, - after, - deltaCpu, - resource, - versions: { - node: process.versions.node, - v8: process.versions.v8, - openssl: process.versions.openssl, - }, - retainedCount: retained.length, - cpuAccumulator, -})); -"#, - ); - let guest = run_guest_probe_with_config( - "process-runtime-stats", - &cwd, - &entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - &[], - ); - - let before_heap_used = guest["before"]["heapUsed"] - .as_u64() - .expect("before heapUsed should be a number"); - let after_heap_used = guest["after"]["heapUsed"] - .as_u64() - .expect("after heapUsed should be a number"); - assert!( - after_heap_used > before_heap_used + 512_000, - "expected heapUsed to grow by at least 512KiB after allocation, before={before_heap_used}, after={after_heap_used}, guest={guest}", - ); - - let user_cpu = guest["deltaCpu"]["user"] - .as_u64() - .expect("cpuUsage.user should be a number"); - let system_cpu = guest["deltaCpu"]["system"] - .as_u64() - .expect("cpuUsage.system should be a number"); - assert!( - user_cpu + system_cpu > 0, - "expected cpuUsage delta to report live CPU time, guest={guest}", - ); - - for field in [ - "userCPUTime", - "systemCPUTime", - "maxRSS", - "minorPageFault", - "majorPageFault", - "voluntaryContextSwitches", - "involuntaryContextSwitches", - ] { - assert!( - guest["resource"][field].is_number(), - "expected resourceUsage.{field} to be numeric, guest={guest}", - ); - } - - assert_eq!( - guest["versions"]["v8"], - Value::String(v8::V8::get_version().to_string()) - ); - assert_eq!( - guest["versions"]["openssl"], - Value::String(current_openssl_version()) - ); -} - -#[test] -fn process_runtime_stats_are_live() { - run_isolated_builtin_conformance_test("process-runtime-stats"); -} - -fn os_resource_limits_are_vm_scoped_impl() { - let cwd = temp_dir("builtin-conformance-os-resource-limits"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import os from "node:os"; - -console.log(JSON.stringify({ - availableParallelism: os.availableParallelism(), - cpusLength: os.cpus().length, - freemem: os.freemem(), - totalmem: os.totalmem(), - username: os.userInfo().username, - homedir: os.homedir(), - envUser: process.env.USER, - envHome: process.env.HOME, -})); -"#, - ); - - let mut sidecar = new_sidecar("os-resource-limits"); - let connection_id = authenticate_wire(&mut sidecar, "conn-os-resource-limits"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - - let constrained = run_guest_probe_in_existing_session( - &mut sidecar, - 3, - &connection_id, - &session_id, - "os-resource-limits-constrained", - &cwd, - &entrypoint, - HashMap::from([ - (String::from("resource.cpu_count"), String::from("2")), - ( - String::from("resource.max_wasm_memory_bytes"), - (64_u64 * 1024 * 1024).to_string(), - ), - ]), - ); - let expanded = run_guest_probe_in_existing_session( - &mut sidecar, - 5, - &connection_id, - &session_id, - "os-resource-limits-expanded", - &cwd, - &entrypoint, - HashMap::from([ - (String::from("resource.cpu_count"), String::from("5")), - ( - String::from("resource.max_wasm_memory_bytes"), - (256_u64 * 1024 * 1024).to_string(), - ), - ]), - ); - - sidecar - .close_session_blocking(&connection_id, &session_id) - .expect("close sidecar session"); - sidecar - .remove_connection_blocking(&connection_id) - .expect("remove sidecar connection"); - - // Virtual identity must reflect the configured VM (distinct from the loader's - // hardcoded root/"/root" defaults) — this is the sidecar-level coverage that - // exercises the guestOs/`import os` path, which an engine-only test does not. - assert_eq!(constrained["username"], "agentos"); - assert_eq!(constrained["homedir"], "/home/agentos"); - assert_eq!(expanded["username"], "agentos"); - assert_eq!(expanded["homedir"], "/home/agentos"); - - assert_eq!(constrained["availableParallelism"], 2); - assert_eq!(constrained["cpusLength"], 2); - assert_eq!(constrained["totalmem"], 64_u64 * 1024 * 1024); - assert_eq!(constrained["freemem"], 64_u64 * 1024 * 1024); - - assert_eq!(expanded["availableParallelism"], 5); - assert_eq!(expanded["cpusLength"], 5); - assert_eq!(expanded["totalmem"], 256_u64 * 1024 * 1024); - assert_eq!(expanded["freemem"], 256_u64 * 1024 * 1024); - - assert_ne!(constrained, expanded); -} - -#[test] -fn os_resource_limits_are_vm_scoped() { - run_isolated_builtin_conformance_test("os-resource-limits"); -} - -fn dns_conformance_matches_host_node() { - assert_node_available(); - - let dns_server = FixtureDnsServer::start(); - let dns_server_addr = dns_server.addr.to_string(); - let cwd = temp_dir("builtin-conformance-dns"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import dns from "node:dns"; - -if (process.env.AGENTOS_TEST_DNS_SERVER) { - dns.setServers([process.env.AGENTOS_TEST_DNS_SERVER]); -} - -function sortStrings(values) { - return [...values].sort((left, right) => left.localeCompare(right)); -} - -function sortObjects(values) { - return [...values].sort((left, right) => - JSON.stringify(left).localeCompare(JSON.stringify(right)), - ); -} - -function resolveWithCallback(hostname, rrtype) { - return new Promise((resolve, reject) => { - dns.resolve(hostname, rrtype, (error, records) => { - if (error) { - reject(error); - return; - } - resolve(records); - }); - }); -} - -const resolveAny = sortObjects(await dns.promises.resolveAny("bundle.example.test")); -const results = { - resolveCallbackA: sortStrings(await resolveWithCallback("bundle.example.test", "A")), - resolve4: sortStrings(await dns.promises.resolve4("bundle.example.test")), - resolve6: sortStrings(await dns.promises.resolve6("bundle.example.test")), - resolveCallbackMx: sortObjects(await resolveWithCallback("bundle.example.test", "MX")), - resolveTxt: sortObjects(await dns.promises.resolveTxt("bundle.example.test")), - resolveSrv: sortObjects(await dns.promises.resolveSrv("_svc._tcp.example.test")), - resolveCname: sortStrings(await dns.promises.resolveCname("alias.example.test")), - resolvePtr: sortStrings(await dns.promises.resolvePtr("ptr.example.test")), - resolveNs: sortStrings(await dns.promises.resolveNs("zone.example.test")), - resolveSoa: await dns.promises.resolveSoa("zone.example.test"), - resolveNaptr: sortObjects(await dns.promises.resolveNaptr("naptr.example.test")), - resolveCaa: sortObjects(await dns.promises.resolveCaa("caa.example.test")), - resolveAny, -}; - -console.log(JSON.stringify(results)); -"#, - ); - - let host = run_host_probe_with_env( - &cwd, - &entrypoint, - &[("AGENTOS_TEST_DNS_SERVER", dns_server_addr.as_str())], - ); - let guest = run_guest_probe_with_config( - "dns", - &cwd, - &entrypoint, - HashMap::from([(String::from("network.dns.servers"), dns_server_addr.clone())]), - wire_permissions_allow_all(), - &["dns"], - ); - - // `dns.resolveSrv`/`resolveCaa`/`resolve(..., "MX")` record shapes differ - // by host Node *version*, not by guest correctness: Node >= 24 attaches a - // `type` discriminator (e.g. `"type":"SRV"`) to these records, while Node - // <= 22 omits it. The guest shim always emits the modern shape with `type`. - // CI runs on Node 22 and the dev machines run Node 24, so a raw - // `guest == host` comparison flaps on the runner's Node version even though - // every actual resolved value is identical. We therefore: - // 1. strip the version-dependent `type` discriminator from both sides - // before comparing the resolved data, so the guest-vs-host conformance - // check still covers all version-stable fields (addresses, ttls, - // priorities, exchanges, ports, soa fields, ...); and - // 2. assert the guest's own `type` discriminators directly, so we keep - // testing the guest's record-shape correctness independent of the - // host Node version. - fn strip_record_type(value: &Value) -> Value { - match value { - Value::Object(map) => Value::Object( - map.iter() - .filter(|(key, _)| key.as_str() != "type") - .map(|(key, val)| (key.clone(), strip_record_type(val))) - .collect(), - ), - Value::Array(items) => Value::Array(items.iter().map(strip_record_type).collect()), - other => other.clone(), - } - } - - assert_eq!( - strip_record_type(&guest), - strip_record_type(&host), - "guest V8 result diverged from host Node for dns (ignoring host-Node-version-dependent record `type` field)\nhost: {}\nguest: {}", - serde_json::to_string_pretty(&host).expect("pretty host JSON"), - serde_json::to_string_pretty(&guest).expect("pretty guest JSON") - ); - - // Guest record-shape correctness, asserted directly so it does not depend on - // the host Node version. The modern Node shape attaches these discriminators. - let type_at = |key: &str, index: usize| -> Option { - guest[key] - .get(index) - .and_then(|record| record.get("type")) - .and_then(Value::as_str) - .map(str::to_owned) - }; - assert_eq!(type_at("resolveSrv", 0).as_deref(), Some("SRV")); - assert_eq!(type_at("resolveCallbackMx", 0).as_deref(), Some("MX")); - assert!( - guest["resolveCaa"].as_array().is_some_and(|records| records - .iter() - .all(|record| record.get("type").and_then(Value::as_str) == Some("CAA"))), - "guest resolveCaa records missing CAA type discriminator: {}", - guest["resolveCaa"] - ); - assert!( - guest["resolveAny"].as_array().is_some_and(|records| records - .iter() - .all(|record| record.get("type").and_then(Value::as_str).is_some())), - "guest resolveAny records missing type discriminator: {}", - guest["resolveAny"] - ); - - let unsupported_cwd = temp_dir("builtin-conformance-dns-unsupported"); - let unsupported_entrypoint = unsupported_cwd.join("entry.mjs"); - write_fixture( - &unsupported_entrypoint, - r#" -import dns from "node:dns"; - -try { - await dns.promises.resolve("bundle.example.test", "TLSA"); - console.log(JSON.stringify({ unexpected: true })); -} catch (error) { - console.log(JSON.stringify({ - code: error?.code ?? null, - message: String(error?.message ?? ""), - })); -} -"#, - ); - let unsupported = run_guest_probe_with_config( - "dns-unsupported", - &unsupported_cwd, - &unsupported_entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - &["dns"], - ); - - assert_eq!(unsupported["code"], "ERR_NOT_IMPLEMENTED"); - assert!( - unsupported["message"] - .as_str() - .is_some_and(|message| message.contains("TLSA")), - "unexpected unsupported rrtype payload: {unsupported}" - ); - - let resolver_cwd = temp_dir("builtin-conformance-dns-resolver"); - let resolver_entrypoint = resolver_cwd.join("entry.mjs"); - write_fixture( - &resolver_entrypoint, - r#" -import dns, { Resolver as CallbackResolver } from "node:dns"; -import dnsPromises, { Resolver as PromisesResolver } from "node:dns/promises"; - -const callbackResolver = new CallbackResolver(); -callbackResolver.setServers(["203.0.113.53:5353"]); -const callbackResult = await new Promise((resolve, reject) => { - callbackResolver.resolve4("bundle.example.test", (error, records) => { - if (error) { - reject(error); - return; - } - resolve(records); - }); -}); - -const promisesResolver = new PromisesResolver(); -promisesResolver.setServers(["203.0.113.54", "203.0.113.55:5353"]); - -console.log(JSON.stringify({ - callbackResolverIsConstructor: typeof CallbackResolver === "function", - promisesResolverIsConstructor: typeof PromisesResolver === "function", - sameCallbackResolverExport: dns.Resolver === CallbackResolver, - samePromisesResolverExport: dnsPromises.Resolver === PromisesResolver, - callbackServers: callbackResolver.getServers(), - promisesServers: promisesResolver.getServers(), - callbackResult: [...callbackResult].sort(), - promisesResult: [...(await promisesResolver.resolve4("bundle.example.test"))].sort(), -})); -"#, - ); - let resolver_probe = run_guest_probe_with_config( - "dns-resolver", - &resolver_cwd, - &resolver_entrypoint, - HashMap::from([(String::from("network.dns.servers"), dns_server_addr.clone())]), - wire_permissions_allow_all(), - &["dns"], - ); - - assert_eq!( - resolver_probe["callbackResolverIsConstructor"], - Value::Bool(true) - ); - assert_eq!( - resolver_probe["promisesResolverIsConstructor"], - Value::Bool(true) - ); - assert_eq!( - resolver_probe["sameCallbackResolverExport"], - Value::Bool(true) - ); - assert_eq!( - resolver_probe["samePromisesResolverExport"], - Value::Bool(true) - ); - assert_eq!( - resolver_probe["callbackServers"], - json!([String::from("203.0.113.53:5353")]) - ); - assert_eq!( - resolver_probe["promisesServers"], - json!([ - String::from("203.0.113.54"), - String::from("203.0.113.55:5353"), - ]) - ); - assert_eq!( - resolver_probe["callbackResult"], - json!([String::from("203.0.113.10"), String::from("203.0.113.11"),]) - ); - assert_eq!( - resolver_probe["promisesResult"], - json!([String::from("203.0.113.10"), String::from("203.0.113.11"),]) - ); -} - -fn fs_conformance_matches_host_node() { - assert_conformance( - "fs", - r#" -import fs from "node:fs"; - -fs.mkdirSync("scratchdir"); -fs.mkdirSync("scratchdir/nested"); -fs.writeFileSync("scratchdir/nested/alpha.txt", Buffer.from("alpha-sync", "utf8")); -await new Promise((resolve, reject) => { - fs.writeFile("scratchdir/beta.txt", Buffer.from("beta-async", "utf8"), (error) => { - if (error) { - reject(error); - return; - } - resolve(); - }); -}); - -let missingStatCode = null; -try { - fs.statSync("scratchdir/missing.txt"); -} catch (error) { - missingStatCode = error?.code ?? null; -} - -let missingReadCode = null; -try { - await new Promise((resolve, reject) => { - fs.readFile("scratchdir/missing.txt", "utf8", (error, value) => { - if (error) { - reject(error); - return; - } - resolve(value); - }); - }); -} catch (error) { - missingReadCode = error?.code ?? null; -} - -const asyncRead = await new Promise((resolve, reject) => { - fs.readFile("scratchdir/beta.txt", "utf8", (error, value) => { - if (error) { - reject(error); - return; - } - resolve(value); - }); -}); - -console.log(JSON.stringify({ - syncRead: fs.readFileSync("scratchdir/nested/alpha.txt", "utf8"), - asyncRead, - entries: fs.readdirSync("scratchdir").sort(), - statSize: fs.statSync("scratchdir/nested/alpha.txt").size, - existsAlpha: fs.existsSync("scratchdir/nested/alpha.txt"), - existsBeta: fs.existsSync("scratchdir/beta.txt"), - missingStatCode, - missingReadCode, -})); -"#, - ); -} - -fn console_conformance_matches_host_node() { - assert_conformance( - "console", - r#" -import * as consoleModule from "node:console"; -import { Writable } from "node:stream"; -const consoleInstance = new consoleModule.Console(process.stdout, process.stderr); -const task = consoleModule.createTask("demo-task"); -const detachedChunks = []; -const detachedErrors = []; -const createSink = (target) => - new Writable({ - write(chunk, _encoding, callback) { - target.push(String(chunk)); - callback(); - }, - }); -const detachedConsole = new consoleModule.Console( - createSink(detachedChunks), - createSink(detachedErrors), -); -const detachedLog = detachedConsole.log; -const detachedError = detachedConsole.error; -detachedLog("detached-log"); -detachedError("detached-error"); - -console.log(JSON.stringify({ - types: { - Console: typeof consoleModule.Console, - context: typeof consoleModule.context, - createTask: typeof consoleModule.createTask, - log: typeof consoleModule.log, - table: typeof consoleModule.table, - }, - taskRunType: typeof task.run, - consoleMethods: { - assert: typeof consoleInstance.assert, - clear: typeof consoleInstance.clear, - count: typeof consoleInstance.count, - countReset: typeof consoleInstance.countReset, - debug: typeof consoleInstance.debug, - dir: typeof consoleInstance.dir, - dirxml: typeof consoleInstance.dirxml, - error: typeof consoleInstance.error, - group: typeof consoleInstance.group, - groupCollapsed: typeof consoleInstance.groupCollapsed, - groupEnd: typeof consoleInstance.groupEnd, - info: typeof consoleInstance.info, - log: typeof consoleInstance.log, - profile: typeof consoleInstance.profile, - profileEnd: typeof consoleInstance.profileEnd, - table: typeof consoleInstance.table, - time: typeof consoleInstance.time, - timeEnd: typeof consoleInstance.timeEnd, - timeLog: typeof consoleInstance.timeLog, - timeStamp: typeof consoleInstance.timeStamp, - trace: typeof consoleInstance.trace, - warn: typeof consoleInstance.warn, - }, - detachedOutput: detachedChunks.join(""), - detachedErrorOutput: detachedErrors.join(""), -})); -"#, - ); -} - -fn child_process_conformance_matches_host_node() { - assert_conformance( - "child-process", - r#" -import childProcess from "node:child_process"; -const syncStdout = childProcess.spawnSync( - "node", - ["-e", "process.stdout.write(process.argv[1] ?? '')", "alpha-sync"], -); -const syncError = childProcess.spawnSync( - "node", - ["-e", "process.stderr.write('sync-error'); throw new Error('sync-fail');"], -); - -const asyncEchoResult = await new Promise((resolve, reject) => { - const child = childProcess.spawn( - "node", - [ - "-e", - "let data=''; let settled = false; const fallback = setTimeout(() => { if (!settled) process.exit(19); }, 50); process.stdin.on('data', (chunk) => { data += chunk; }); process.stdin.on('end', () => { settled = true; clearTimeout(fallback); process.exit(data === 'beta-async' ? 0 : 17); });", - ], - ); - const timer = setTimeout(() => { - reject(new Error("spawn(node async echo) did not close within 2s")); - }, 2000); - const stdout = []; - const stderr = []; - child.stdout.on("data", (chunk) => { - stdout.push(Buffer.from(chunk)); - }); - child.stderr.on("data", (chunk) => { - stderr.push(Buffer.from(chunk)); - }); - child.stdin.write(Buffer.from("beta-async")); - child.stdin.end(); - child.on("error", reject); - child.on("close", (code, signal) => { - clearTimeout(timer); - resolve({ - code, - signal, - stdoutBase64: Buffer.concat(stdout).toString("base64"), - stderrBase64: Buffer.concat(stderr).toString("base64"), - }); - }); -}); - -const asyncErrorResult = await new Promise((resolve, reject) => { - const child = childProcess.spawn( - "node", - [ - "-e", - "setTimeout(() => { process.stderr.write('async-error'); throw new Error('async-fail'); }, 10);", - ], - ); - const timer = setTimeout(() => { - reject(new Error("spawn(node async failure) did not close within 2s")); - }, 2000); - const stdout = []; - const stderr = []; - child.stdout.on("data", (chunk) => { - stdout.push(Buffer.from(chunk)); - }); - child.stderr.on("data", (chunk) => { - stderr.push(Buffer.from(chunk)); - }); - child.on("error", reject); - child.on("close", (code, signal) => { - clearTimeout(timer); - resolve({ - code, - signal, - stdoutBase64: Buffer.concat(stdout).toString("base64"), - stderrBase64: Buffer.concat(stderr).toString("base64"), - }); - }); -}); - -console.log(JSON.stringify({ - syncStdoutStatus: syncStdout.status, - syncStdoutTrimmed: Buffer.from(syncStdout.stdout ?? []).toString("utf8").trim(), - syncStdoutStderrBase64: Buffer.from(syncStdout.stderr ?? []).toString("base64"), - syncErrorStatus: syncError.status, - syncErrorStdoutBase64: Buffer.from(syncError.stdout ?? []).toString("base64"), - syncErrorHasMarker: Buffer.from(syncError.stderr ?? []).toString("utf8").includes("sync-error"), - syncErrorHasNonZeroStatus: (syncError.status ?? 0) !== 0, - asyncEchoCode: asyncEchoResult.code, - asyncEchoSignal: asyncEchoResult.signal, - asyncEchoStdoutBase64: asyncEchoResult.stdoutBase64, - asyncEchoStderrBase64: asyncEchoResult.stderrBase64, - asyncErrorCode: asyncErrorResult.code, - asyncErrorSignal: asyncErrorResult.signal, - asyncErrorStdoutBase64: asyncErrorResult.stdoutBase64, - asyncErrorHasNonZeroStatus: (asyncErrorResult.code ?? 0) !== 0, -})); -"#, - ); -} - -fn child_process_fork_supports_basic_ipc_impl() { - let cwd = temp_dir("builtin-child-process-fork-ipc"); - let entrypoint = cwd.join("entry.mjs"); - let worker = cwd.join("worker.mjs"); - write_fixture( - &worker, - r#" -process.send({ - type: "ready", - connected: process.connected, - argv: process.argv.slice(-1), -}); - -process.on("message", (message) => { - process.send({ - type: "pong", - value: message.value + 1, - connected: process.connected, - }); - process.exit(0); -}); -"#, - ); - write_fixture( - &entrypoint, - r#" -import childProcess from "node:child_process"; -import { Buffer } from "node:buffer"; - -const child = childProcess.fork("./worker.mjs", ["worker-arg"]); -const stdout = []; -const messages = []; -const errors = []; -let sendReturn = null; - -child.stdout.on("data", (chunk) => stdout.push(Buffer.from(chunk))); -child.on("error", (error) => errors.push({ - name: error?.name ?? null, - message: error?.message ?? null, - code: error?.code ?? null, -})); -child.on("message", (message) => { - messages.push(message); - if (message.type === "ready") { - sendReturn = child.send({ type: "ping", value: 41 }); - } -}); - -const exit = await new Promise((resolve) => { - child.on("close", (code, signal) => resolve({ code, signal })); -}); - -console.log(JSON.stringify({ - connectedAfterFork: child.connected, - sendReturn, - messages, - errors, - stdoutBase64: Buffer.concat(stdout).toString("base64"), - exit, -})); -"#, - ); - - let guest = run_guest_probe_with_config( - "child-process-fork-ipc", - &cwd, - &entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - &["child_process"], - ); - - let pretty_guest = serde_json::to_string_pretty(&guest).expect("pretty guest JSON"); - assert_eq!( - guest["sendReturn"], - Value::Bool(true), - "guest result:\n{pretty_guest}" - ); - assert_eq!( - guest["errors"], - Value::Array(Vec::new()), - "guest result:\n{pretty_guest}" - ); - assert_eq!(guest["stdoutBase64"], Value::String(String::new())); - assert_eq!(guest["exit"]["code"], Value::from(0)); - assert_eq!(guest["exit"]["signal"], Value::Null); - assert_eq!( - guest["messages"][0]["type"], - Value::String(String::from("ready")) - ); - assert_eq!(guest["messages"][0]["connected"], Value::Bool(true)); - assert_eq!( - guest["messages"][0]["argv"][0], - Value::String(String::from("worker-arg")) - ); - assert_eq!( - guest["messages"][1]["type"], - Value::String(String::from("pong")) - ); - assert_eq!(guest["messages"][1]["value"], Value::from(42)); - assert_eq!(guest["messages"][1]["connected"], Value::Bool(true)); -} - -#[test] -fn child_process_fork_supports_basic_ipc() { - run_isolated_builtin_conformance_test("child-process-fork-ipc"); -} - -fn child_process_exec_preserves_spawn_error_codes_impl() { - assert_node_available(); - - let cwd = temp_dir("builtin-child-process-exec-spawn-error-code"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import childProcess from "node:child_process"; - -const result = await new Promise((resolve) => { - const callbacks = []; - const closeEvents = []; - const child = childProcess.exec( - "/definitely/not/a/binary", - (err, stdout, stderr) => { - callbacks.push({ - code: err?.code ?? null, - errno: typeof err?.errno === "number" ? err.errno : null, - syscall: err?.syscall ?? null, - path: err?.path ?? null, - stdout, - stderr, - }); - setTimeout(() => resolve({ callbacks, closeEvents }), 0); - }, - ); - child.on("close", (code, signal) => { - closeEvents.push({ - code: code ?? null, - signal: signal ?? null, - }); - }); - child.on("error", () => {}); -}); - -console.log(JSON.stringify(result)); -"#, - ); - - let guest = run_guest_probe_with_config( - "child-process-exec-spawn-error-code", - &cwd, - &entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - &["child_process"], - ); - - assert_eq!( - guest["callbacks"][0]["code"], - Value::String(String::from("ENOENT")), - "guest exec() callback should preserve the original spawn error code", - ); - assert_eq!( - guest["callbacks"].as_array().map(Vec::len), - Some(1), - "guest exec() callback should not be re-fired after a spawn error" - ); - assert_eq!( - guest["callbacks"][0]["stdout"], - Value::String(String::new()) - ); - assert_eq!( - guest["callbacks"][0]["stderr"], - Value::String(String::new()) - ); -} - -#[test] -fn child_process_exec_preserves_spawn_error_codes() { - run_isolated_builtin_conformance_test("child-process-exec-spawn-error-code"); -} - -fn child_process_rejects_native_elf_binaries_before_wasm_compile_impl() { - let cwd = temp_dir("builtin-child-process-native-elf-reject"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import childProcess from "node:child_process"; -import fs from "node:fs"; - -const fakeRgPath = "/tmp/fake-rg"; -fs.writeFileSync( - fakeRgPath, - Buffer.from([0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00]), -); -fs.chmodSync(fakeRgPath, 0o755); - -const syncResult = childProcess.spawnSync(fakeRgPath, ["--version"]); - -const asyncResult = await new Promise((resolve) => { - const child = childProcess.spawn(fakeRgPath, ["--version"]); - child.once("error", (error) => { - resolve({ - code: error?.code ?? null, - message: error?.message ?? null, - }); - }); -}); - -console.log(JSON.stringify({ - sync: { - status: syncResult.status, - errorCode: syncResult.error?.code ?? null, - errorMessage: syncResult.error?.message ?? null, - stderr: Buffer.isBuffer(syncResult.stderr) - ? syncResult.stderr.toString("utf8") - : String(syncResult.stderr ?? ""), - }, - async: asyncResult, -})); -"#, - ); - - let guest = run_guest_probe_with_config( - "child-process-native-elf-reject", - &cwd, - &entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - &["child_process", "fs"], - ); - - assert_eq!(guest["sync"]["status"], Value::Number(1.into())); - assert_eq!( - guest["sync"]["errorCode"], - Value::String(String::from("ERR_NATIVE_BINARY_NOT_SUPPORTED")) - ); - let sync_stderr = guest["sync"]["stderr"] - .as_str() - .expect("sync stderr string"); - assert!( - sync_stderr.contains("ERR_NATIVE_BINARY_NOT_SUPPORTED"), - "sync stderr should expose the explicit native-binary rejection: {sync_stderr}" - ); - assert!( - sync_stderr.contains("ELF"), - "sync stderr should name the detected ELF format: {sync_stderr}" - ); - assert!( - !sync_stderr.contains("CompileError"), - "sync stderr must not fall back to the WASM compile error: {sync_stderr}" - ); - assert_eq!( - guest["async"]["code"], - Value::String(String::from("ERR_NATIVE_BINARY_NOT_SUPPORTED")) - ); - let async_message = guest["async"]["message"] - .as_str() - .expect("async error message string"); - assert!( - async_message.contains("ERR_NATIVE_BINARY_NOT_SUPPORTED"), - "async spawn error should preserve the explicit native-binary code: {async_message}" - ); - assert!( - async_message.contains("ELF"), - "async spawn error should name the detected ELF format: {async_message}" - ); - assert!( - !async_message.contains("CompileError"), - "async spawn error must not fall back to the WASM compile error: {async_message}" - ); -} - -#[test] -fn child_process_rejects_native_elf_binaries_before_wasm_compile() { - run_isolated_builtin_conformance_test("child-process-native-elf-reject"); -} - -fn child_process_kill_numeric_signals_match_host_node_impl() { - assert_node_available(); - - let cwd = temp_dir("builtin-child-process-kill-numeric-signal"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import childProcess from "node:child_process"; - -async function captureKill(signal) { - const child = childProcess.spawn("node", ["-e", "setInterval(() => {}, 1000)"]); - const killResult = child.kill(signal); - const signalCodeAfterKill = child.signalCode ?? null; - return await new Promise((resolve, reject) => { - const timer = setTimeout(() => { - reject(new Error(`spawn(node interval) kill(${String(signal)}) did not exit within 2s`)); - }, 2000); - child.on("error", reject); - child.on("exit", (code, exitSignal) => { - clearTimeout(timer); - resolve({ - killResult, - signalCodeAfterKill, - code: code ?? null, - signal: exitSignal ?? null, - signalCodeAfterExit: child.signalCode ?? null, - killed: child.killed, - }); - }); - }); -} - -console.log(JSON.stringify({ - numeric: await captureKill(11), - alias: await captureKill("SIGIOT"), -})); -"#, - ); - - let host = run_host_probe(&cwd, &entrypoint); - let guest = run_guest_probe_with_config( - "child-process-kill-numeric-signal", - &cwd, - &entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - &["child_process"], - ); - - assert_eq!( - guest, - host, - "guest child_process.kill signal mapping diverged from host Node\nhost: {}\nguest: {}", - serde_json::to_string_pretty(&host).expect("pretty host JSON"), - serde_json::to_string_pretty(&guest).expect("pretty guest JSON") - ); - assert_eq!( - guest["numeric"]["signalCodeAfterExit"], - Value::String(String::from("SIGSEGV")) - ); -} - -#[test] -fn child_process_kill_numeric_signals_match_host_node() { - run_isolated_builtin_conformance_test("child-process-kill-numeric-signal"); -} - -fn child_process_abort_reports_sigabrt_impl() { - assert_node_available(); - - let cwd = temp_dir("builtin-child-process-abort-signal"); - let entrypoint = cwd.join("entry.mjs"); - // Use an inline `node -e` child rather than spawning a child *file*. The - // previous version wrote the child script to a hardcoded host `/tmp` path - // and spawned it with `cwd: "/tmp"`; that path is written into the guest - // VFS by the parent, but the spawned guest child resolves the module - // against the runner's filesystem, so it fails with `Cannot find module` - // (exiting with code 1) before ever calling `process.abort()`. Whether the - // file happened to be visible depended on the CI runner's `/tmp` layout, - // which made this case flaky. The inline form mirrors the sibling - // `child-process-kill-numeric-signal` case and exercises the exact same - // guest behavior — `process.abort()` mapping to a SIGABRT-shaped exit — - // without any cross-runtime filesystem dependency. - write_fixture( - &entrypoint, - r#" -import childProcess from "node:child_process"; - -const child = childProcess.spawn("node", ["-e", "process.abort();"]); -const result = await new Promise((resolve, reject) => { - const timer = setTimeout(() => { - reject(new Error("spawn(node abort child) did not exit within 2s")); - }, 2000); - child.on("error", reject); - child.on("exit", (code, signal) => { - clearTimeout(timer); - resolve({ - code: code ?? null, - signal: signal ?? null, - signalCodeAfterExit: child.signalCode ?? null, - killed: child.killed, - }); - }); -}); - -console.log(JSON.stringify(result)); -"#, - ); - - let host = run_host_probe(&cwd, &entrypoint); - let guest = run_guest_probe_with_config( - "child-process-abort-signal", - &cwd, - &entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - &["child_process"], - ); - - assert_eq!(guest["code"], host["code"]); - assert_eq!(guest["signal"], host["signal"]); - assert_eq!(guest["signalCodeAfterExit"], host["signalCodeAfterExit"]); - assert_eq!(guest["killed"], host["killed"]); - assert_eq!(guest["signal"], Value::String(String::from("SIGABRT"))); - assert_eq!( - guest["signalCodeAfterExit"], - Value::String(String::from("SIGABRT")) - ); -} - -#[test] -fn child_process_abort_reports_sigabrt() { - run_isolated_builtin_conformance_test("child-process-abort-signal"); -} - -fn path_conformance_matches_host_node() { - assert_conformance( - "path", - r#" -import * as pathNs from "node:path"; - -const path = pathNs.default ?? pathNs; - -console.log(JSON.stringify({ - join: path.join("/virtual", "project", "file.txt"), - resolve: path.resolve("/virtual/root", "alpha", "..", "beta", "file.txt"), - dirname: path.dirname("/virtual/root/beta/file.txt"), - basename: path.basename("/virtual/root/beta/file.txt"), - extname: path.extname("/virtual/root/beta/file.txt"), - isAbsoluteFile: path.isAbsolute("/virtual/root/beta/file.txt"), - isAbsoluteRelative: path.isAbsolute("virtual/root/beta/file.txt"), - relative: path.relative("/virtual/root/alpha", "/virtual/root/beta/file.txt"), - normalize: path.normalize("/virtual//root/alpha/../beta//file.txt"), -})); -"#, - ); -} - -fn crypto_conformance_matches_host_node() { - assert_conformance( - "crypto", - r#" -import crypto from "node:crypto"; - -const random = crypto.randomBytes(16); -const uuid = crypto.randomUUID(); -const ciphers = crypto.getCiphers(); -const curves = crypto.getCurves(); - -console.log(JSON.stringify({ - hashesIncludeSha256: crypto.getHashes().includes("sha256"), - ciphersIncludeAes256Cbc: ciphers.includes("aes-256-cbc"), - ciphersIncludeAes256Gcm: ciphers.includes("aes-256-gcm"), - ciphersSorted: ciphers.join(",") === [...ciphers].sort().join(","), - curvesIncludePrime256v1: curves.includes("prime256v1"), - curvesIncludeSecp384r1: curves.includes("secp384r1"), - curvesSorted: curves.join(",") === [...curves].sort().join(","), - sha256: crypto.createHash("sha256").update("secure-exec").digest("hex"), - hmacSha256: crypto.createHmac("sha256", "shared-secret").update("secure-exec").digest("hex"), - randomBytesLength: random.length, - randomBytesHexLength: random.toString("hex").length, - randomBytesAllZero: Array.from(random).every((value) => value === 0), - randomUuidValid: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid), -})); -"#, - ); -} - -fn crypto_extended_surface_matches_host_node() { - assert_conformance( - "crypto-extended", - r#" -import crypto from "node:crypto"; - -const cipherKey = Buffer.alloc(32, 7); -const cipherIv = Buffer.alloc(16, 9); -const cipherPlaintext = Buffer.from("secure-exec-crypto-surface", "utf8"); -const cipher = crypto.createCipheriv("aes-256-cbc", cipherKey, cipherIv); -const encrypted = Buffer.concat([cipher.update(cipherPlaintext), cipher.final()]); -const decipher = crypto.createDecipheriv("aes-256-cbc", cipherKey, cipherIv); -const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8"); - -const pbkdf2Hex = await new Promise((resolve, reject) => { - crypto.pbkdf2("password", "salt", 10, 32, "sha256", (error, result) => { - if (error) { - reject(error); - return; - } - resolve(result.toString("hex")); - }); -}); - -const scryptHex = await new Promise((resolve, reject) => { - crypto.scrypt("password", "salt", 32, { N: 1024, r: 8, p: 1 }, (error, result) => { - if (error) { - reject(error); - return; - } - resolve(result.toString("hex")); - }); -}); - -const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { modulusLength: 1024 }); -const privatePem = privateKey.export({ format: "pem", type: "pkcs8" }); -const publicPem = publicKey.export({ format: "pem", type: "spki" }); -const importedPrivateKey = crypto.createPrivateKey(privatePem); -const importedPublicKey = crypto.createPublicKey(publicPem); - -const signer = crypto.createSign("sha256"); -signer.update("secure-exec-signature"); -const signature = signer.sign(importedPrivateKey); - -const verifier = crypto.createVerify("sha256"); -verifier.update("secure-exec-signature"); -const signatureVerified = verifier.verify(importedPublicKey, signature); - -const oneShotSignature = crypto.sign("sha256", Buffer.from("secure-exec-signature"), importedPrivateKey); -const oneShotVerified = crypto.verify( - "sha256", - Buffer.from("secure-exec-signature"), - importedPublicKey, - oneShotSignature, -); - -const rsaCiphertext = crypto.publicEncrypt( - { key: importedPublicKey, padding: crypto.constants.RSA_PKCS1_PADDING }, - Buffer.from("secure-exec-rsa", "utf8"), -); -const rsaPlaintext = crypto.privateDecrypt( - { key: importedPrivateKey, padding: crypto.constants.RSA_PKCS1_PADDING }, - rsaCiphertext, -).toString("utf8"); - -const secretKey = crypto.createSecretKey(Buffer.from("abcd", "utf8")); -const generatedHmacKey = crypto.generateKeySync("hmac", { length: 256 }); -const generatedAesKey = crypto.generateKeySync("aes", { length: 128 }); -const generatedPrime = crypto.generatePrimeSync(64, { bigint: true }); - -const groupAlice = crypto.getDiffieHellman("modp14"); -const groupBob = crypto.getDiffieHellman("modp14"); -groupAlice.generateKeys(); -groupBob.generateKeys(); -const groupSecretA = groupAlice.computeSecret(groupBob.getPublicKey()); -const groupSecretB = groupBob.computeSecret(groupAlice.getPublicKey()); - -const ecdhAlice = crypto.createECDH("prime256v1"); -const ecdhBob = crypto.createECDH("prime256v1"); -ecdhAlice.generateKeys(); -ecdhBob.generateKeys(); -const ecdhSecretA = ecdhAlice.computeSecret(ecdhBob.getPublicKey()); -const ecdhSecretB = ecdhBob.computeSecret(ecdhAlice.getPublicKey()); - -const x25519Alice = crypto.generateKeyPairSync("x25519"); -const x25519Bob = crypto.generateKeyPairSync("x25519"); -const x25519SecretA = crypto.diffieHellman({ - privateKey: x25519Alice.privateKey, - publicKey: x25519Bob.publicKey, -}); -const x25519SecretB = crypto.diffieHellman({ - privateKey: x25519Bob.privateKey, - publicKey: x25519Alice.publicKey, -}); - -const generatedAsyncPair = await new Promise((resolve, reject) => { - crypto.generateKeyPair("rsa", { modulusLength: 1024 }, (error, publicKeyValue, privateKeyValue) => { - if (error) { - reject(error); - return; - } - resolve({ - publicType: publicKeyValue.type, - privateType: privateKeyValue.type, - publicAsymmetricKeyType: publicKeyValue.asymmetricKeyType, - privateAsymmetricKeyType: privateKeyValue.asymmetricKeyType, - }); - }); -}); - -console.log(JSON.stringify({ - cipherHex: encrypted.toString("hex"), - decipheredText: decrypted, - pbkdf2SyncHex: crypto.pbkdf2Sync("password", "salt", 10, 32, "sha256").toString("hex"), - pbkdf2Hex, - scryptSyncHex: crypto.scryptSync("password", "salt", 32, { N: 1024, r: 8, p: 1 }).toString("hex"), - scryptHex, - importedPrivateType: importedPrivateKey.type, - importedPrivateAsymmetricKeyType: importedPrivateKey.asymmetricKeyType, - importedPublicType: importedPublicKey.type, - importedPublicAsymmetricKeyType: importedPublicKey.asymmetricKeyType, - importedPrivateEquals: importedPrivateKey.equals(crypto.createPrivateKey(privatePem)), - importedPublicEquals: importedPublicKey.equals(crypto.createPublicKey(publicPem)), - signatureLength: signature.length, - signatureVerified, - oneShotSignatureLength: oneShotSignature.length, - oneShotVerified, - rsaCiphertextLength: rsaCiphertext.length, - rsaPlaintext, - secretKeyType: secretKey.type, - secretKeyExportHex: secretKey.export().toString("hex"), - generatedHmacKeyType: generatedHmacKey.type, - generatedHmacKeyLength: generatedHmacKey.export().length, - generatedAesKeyType: generatedAesKey.type, - generatedAesKeyLength: generatedAesKey.export().length, - generatedPrimeType: typeof generatedPrime, - generatedPrimePositive: generatedPrime > 0n, - groupVerifyError: groupAlice.verifyError, - groupSecretMatches: groupSecretA.equals(groupSecretB), - groupPrimeLength: groupAlice.getPrime().length, - ecdhSecretMatches: ecdhSecretA.equals(ecdhSecretB), - ecdhPublicKeyLength: ecdhAlice.getPublicKey().length, - x25519SecretMatches: x25519SecretA.equals(x25519SecretB), - x25519SecretLength: x25519SecretA.length, - generatedAsyncPair, -})); -"#, - ); -} - -fn crypto_basic_fixture_matches_shared_expected_impl() { - assert_node_available(); - - let fixture_json = include_str!("../../../tests/fixtures/crypto-basic-conformance.json"); - let fixture: Value = serde_json::from_str(fixture_json).expect("parse crypto fixture"); - let script = r#" -import crypto from "node:crypto"; - -const fixture = __CRYPTO_FIXTURE__; -const pbkdf2Hex = await new Promise((resolve, reject) => { - crypto.pbkdf2(fixture.password, fixture.salt, fixture.iterations, fixture.keyLength, "sha256", (error, value) => { - if (error) reject(error); - else resolve(value.toString("hex")); - }); -}); -const pbkdf2Sha384Hex = await new Promise((resolve, reject) => { - crypto.pbkdf2(fixture.password, fixture.salt, fixture.iterations, fixture.keyLength, "sha384", (error, value) => { - if (error) reject(error); - else resolve(value.toString("hex")); - }); -}); -const scryptHex = await new Promise((resolve, reject) => { - crypto.scrypt(fixture.password, fixture.salt, fixture.keyLength, fixture.scrypt, (error, value) => { - if (error) reject(error); - else resolve(value.toString("hex")); - }); -}); -const generatedPrime = crypto.generatePrimeSync(fixture.expected.primes.bits, { bigint: true }); -const generatedSafePrime = crypto.generatePrimeSync(fixture.expected.primes.safeBits, { - bigint: true, - safe: true, -}); -const generatedPrimeBuffer = crypto.generatePrimeSync(fixture.expected.primes.bufferBits); -const bytesFromHex = (hex) => Uint8Array.from(hex.match(/../g).map((byte) => parseInt(byte, 16))); -const bytesToHex = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(""); -const aesCbcKey = Buffer.from(fixture.aesCbc.keyHex, "hex"); -const aesCbcIv = Buffer.from(fixture.aesCbc.ivHex, "hex"); -const cipher = crypto.createCipheriv(fixture.aesCbc.algorithm, aesCbcKey, aesCbcIv); -const aes256CbcCiphertext = cipher.update(fixture.aesCbc.plaintext, "utf8", "hex") + cipher.final("hex"); -const decipher = crypto.createDecipheriv(fixture.aesCbc.algorithm, aesCbcKey, aesCbcIv); -const aes256CbcPlaintext = decipher.update(aes256CbcCiphertext, "hex", "utf8") + decipher.final("utf8"); -const aesGcmKey = Buffer.from(fixture.aesGcm.keyHex, "hex"); -const aesGcmIv = Buffer.from(fixture.aesGcm.ivHex, "hex"); -const aesGcmAad = Buffer.from(fixture.aesGcm.aad); -const gcmCipher = crypto.createCipheriv(fixture.aesGcm.algorithm, aesGcmKey, aesGcmIv, { - authTagLength: fixture.aesGcm.authTagLength, -}); -gcmCipher.setAAD(aesGcmAad); -const aes256GcmCiphertext = gcmCipher.update(fixture.aesGcm.plaintext, "utf8", "hex") + gcmCipher.final("hex"); -const aes256GcmAuthTag = gcmCipher.getAuthTag().toString("hex"); -const gcmDecipher = crypto.createDecipheriv(fixture.aesGcm.algorithm, aesGcmKey, aesGcmIv, { - authTagLength: fixture.aesGcm.authTagLength, -}); -gcmDecipher.setAAD(aesGcmAad); -gcmDecipher.setAuthTag(bytesFromHex(aes256GcmAuthTag)); -const aes256GcmPlaintext = gcmDecipher.update(aes256GcmCiphertext, "hex", "utf8") + gcmDecipher.final("utf8"); -const subtleKey = await crypto.subtle.importKey("raw", aesGcmKey, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]); -const subtleAlgorithm = { - name: "AES-GCM", - iv: aesGcmIv, - additionalData: aesGcmAad, - tagLength: fixture.aesGcm.authTagLength * 8, -}; -const aes256GcmWebCryptoBytes = new Uint8Array(await crypto.subtle.encrypt( - subtleAlgorithm, - subtleKey, - Buffer.from(fixture.aesGcm.plaintext), -)); -const aes256GcmWebCryptoCiphertext = bytesToHex(aes256GcmWebCryptoBytes); -const aes256GcmWebCryptoPlaintext = Buffer.from(await crypto.subtle.decrypt( - subtleAlgorithm, - subtleKey, - aes256GcmWebCryptoBytes, -)).toString("utf8"); -const importedPrivateKey = crypto.createPrivateKey(fixture.rsa.privatePem); -const importedPublicKey = crypto.createPublicKey(fixture.rsa.publicPem); -const rsaSignature = crypto.createSign("sha256").update(fixture.rsa.message).sign(importedPrivateKey); -const rsaVerified = crypto.createVerify("sha256").update(fixture.rsa.message).verify(importedPublicKey, rsaSignature); -const rsaExpectedVerified = crypto.createVerify("sha256") - .update(fixture.rsa.message) - .verify(importedPublicKey, Buffer.from(fixture.rsa.sha256SignatureHex, "hex")); -const rsaOneShotSignature = crypto.sign("sha256", Buffer.from(fixture.rsa.message), importedPrivateKey); -const rsaOneShotVerified = crypto.verify( - "sha256", - Buffer.from(fixture.rsa.message), - importedPublicKey, - rsaOneShotSignature, -); -const dhAlice = crypto.createDiffieHellman( - Buffer.from(fixture.dh.primeHex, "hex"), - Buffer.from(fixture.dh.generatorHex, "hex"), -); -const dhBob = crypto.createDiffieHellman( - Buffer.from(fixture.dh.primeHex, "hex"), - Buffer.from(fixture.dh.generatorHex, "hex"), -); -dhAlice.setPrivateKey(Buffer.from(fixture.dh.privateAHex, "hex")); -dhAlice.setPublicKey(Buffer.from(fixture.dh.publicAHex, "hex")); -dhBob.setPrivateKey(Buffer.from(fixture.dh.privateBHex, "hex")); -dhBob.setPublicKey(Buffer.from(fixture.dh.publicBHex, "hex")); -const dhSecretA = dhAlice.computeSecret(Buffer.from(fixture.dh.publicBHex, "hex")); -const dhSecretB = dhBob.computeSecret(Buffer.from(fixture.dh.publicAHex, "hex")); -const ecdhAlice = crypto.createECDH(fixture.ecdh.curve); -const ecdhBob = crypto.createECDH(fixture.ecdh.curve); -ecdhAlice.setPrivateKey(Buffer.from(fixture.ecdh.privateAHex, "hex")); -ecdhBob.setPrivateKey(Buffer.from(fixture.ecdh.privateBHex, "hex")); -const ecdhSecretA = ecdhAlice.computeSecret(Buffer.from(fixture.ecdh.publicBHex, "hex")); -const ecdhSecretB = ecdhBob.computeSecret(Buffer.from(fixture.ecdh.publicAHex, "hex")); - -console.log(JSON.stringify({ - hashes: crypto.getHashes(), - ciphers: crypto.getCiphers(), - curves: crypto.getCurves(), - md5: crypto.createHash("md5").update(fixture.message).digest("hex"), - sha224: crypto.createHash("sha224").update(fixture.message).digest("hex"), - sha256: crypto.createHash("sha256").update(fixture.message).digest("hex"), - sha384: crypto.createHash("sha384").update(fixture.message).digest("hex"), - hmacSha256: crypto.createHmac("sha256", fixture.hmacKey).update(fixture.message).digest("hex"), - hmacSha384: crypto.createHmac("sha384", fixture.hmacKey).update(fixture.message).digest("hex"), - pbkdf2SyncHex: crypto.pbkdf2Sync(fixture.password, fixture.salt, fixture.iterations, fixture.keyLength, "sha256").toString("hex"), - pbkdf2Sha384Hex, - pbkdf2Hex, - scryptSyncHex: crypto.scryptSync(fixture.password, fixture.salt, fixture.keyLength, fixture.scrypt).toString("hex"), - scryptHex, - generatedPrimeType: typeof generatedPrime, - generatedPrimeBits: generatedPrime.toString(2).length, - generatedPrimePositive: generatedPrime > 0n, - generatedSafePrimeBits: generatedSafePrime.toString(2).length, - generatedSafePrimePositive: generatedSafePrime > 0n, - generatedPrimeBufferBits: fixture.expected.primes.bufferBits, - generatedPrimeBufferByteLength: generatedPrimeBuffer.byteLength, - aes256CbcCiphertext, - aes256CbcPlaintext, - aes256GcmCiphertext, - aes256GcmAuthTag, - aes256GcmPlaintext, - aes256GcmWebCryptoCiphertext, - aes256GcmWebCryptoPlaintext, - rsaSignatureHex: rsaSignature.toString("hex"), - rsaVerified, - rsaExpectedVerified, - rsaOneShotSignatureHex: rsaOneShotSignature.toString("hex"), - rsaOneShotVerified, - dhPublicAHex: dhAlice.getPublicKey("hex"), - dhPublicBHex: dhBob.getPublicKey("hex"), - dhSecretAHex: dhSecretA.toString("hex"), - dhSecretBHex: dhSecretB.toString("hex"), - ecdhPublicAHex: ecdhAlice.getPublicKey("hex"), - ecdhPublicBHex: ecdhBob.getPublicKey("hex"), - ecdhSecretAHex: ecdhSecretA.toString("hex"), - ecdhSecretBHex: ecdhSecretB.toString("hex"), -})); -"# - .replace("__CRYPTO_FIXTURE__", fixture_json); - - let cwd = temp_dir("builtin-conformance-crypto-basic-fixture"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture(&entrypoint, &script); - let guest = run_guest_probe("crypto-basic-fixture", &cwd, &entrypoint); - let expected = &fixture["expected"]; - let dh_expected_secret = format!( - "{:0>width$}", - fixture["dh"]["secretHex"] - .as_str() - .expect("dh secret fixture must be a string"), - width = fixture["dh"]["primeHex"] - .as_str() - .expect("dh prime fixture must be a string") - .len() - ); - - assert_eq!(guest["hashes"], expected["hashes"]); - assert_eq!(guest["ciphers"], expected["ciphers"]); - assert_eq!(guest["curves"], expected["curves"]); - assert_eq!(guest["md5"], expected["md5"]); - assert_eq!(guest["sha224"], expected["sha224"]); - assert_eq!(guest["sha256"], expected["sha256"]); - assert_eq!(guest["sha384"], expected["sha384"]); - assert_eq!(guest["hmacSha256"], expected["hmacSha256"]); - assert_eq!(guest["hmacSha384"], expected["hmacSha384"]); - assert_eq!(guest["pbkdf2SyncHex"], expected["pbkdf2Sha256"]); - assert_eq!(guest["pbkdf2Hex"], expected["pbkdf2Sha256"]); - assert_eq!(guest["pbkdf2Sha384Hex"], expected["pbkdf2Sha384"]); - assert_eq!(guest["scryptSyncHex"], expected["scrypt"]); - assert_eq!(guest["scryptHex"], expected["scrypt"]); - assert_eq!(guest["generatedPrimeType"], json!("bigint")); - assert_eq!(guest["generatedPrimeBits"], expected["primes"]["bits"]); - assert_eq!(guest["generatedPrimePositive"], json!(true)); - assert_eq!( - guest["generatedSafePrimeBits"], - expected["primes"]["safeBits"] - ); - assert_eq!(guest["generatedSafePrimePositive"], json!(true)); - assert_eq!( - guest["generatedPrimeBufferBits"], - expected["primes"]["bufferBits"] - ); - assert_eq!( - guest["generatedPrimeBufferByteLength"], - expected["primes"]["bufferByteLength"] - ); - assert_eq!( - guest["aes256CbcCiphertext"], - expected["aes256CbcCiphertext"] - ); - assert_eq!(guest["aes256CbcPlaintext"], fixture["aesCbc"]["plaintext"]); - assert_eq!( - guest["aes256GcmCiphertext"], - expected["aes256GcmCiphertext"] - ); - assert_eq!(guest["aes256GcmAuthTag"], expected["aes256GcmAuthTag"]); - assert_eq!(guest["aes256GcmPlaintext"], fixture["aesGcm"]["plaintext"]); - assert_eq!( - guest["aes256GcmWebCryptoCiphertext"], - expected["aes256GcmWebCryptoCiphertext"] - ); - assert_eq!( - guest["aes256GcmWebCryptoPlaintext"], - fixture["aesGcm"]["plaintext"] - ); - assert_eq!( - guest["rsaSignatureHex"], - fixture["rsa"]["sha256SignatureHex"] - ); - assert_eq!(guest["rsaVerified"], json!(true)); - assert_eq!(guest["rsaExpectedVerified"], json!(true)); - assert_eq!( - guest["rsaOneShotSignatureHex"], - fixture["rsa"]["sha256SignatureHex"] - ); - assert_eq!(guest["rsaOneShotVerified"], json!(true)); - assert_eq!(guest["dhPublicAHex"], fixture["dh"]["publicAHex"]); - assert_eq!(guest["dhPublicBHex"], fixture["dh"]["publicBHex"]); - assert_eq!(guest["dhSecretAHex"], json!(dh_expected_secret)); - assert_eq!(guest["dhSecretBHex"], json!(dh_expected_secret)); - assert_eq!(guest["ecdhPublicAHex"], fixture["ecdh"]["publicAHex"]); - assert_eq!(guest["ecdhPublicBHex"], fixture["ecdh"]["publicBHex"]); - assert_eq!(guest["ecdhSecretAHex"], fixture["ecdh"]["secretHex"]); - assert_eq!(guest["ecdhSecretBHex"], fixture["ecdh"]["secretHex"]); -} - -#[test] -fn crypto_basic_fixture_matches_shared_expected_isolated() { - run_isolated_builtin_conformance_test("crypto-basic-fixture"); -} - -#[test] -fn crypto_extended_surface_matches_host_node_isolated() { - run_isolated_builtin_conformance_test("crypto-extended"); -} - -fn events_conformance_matches_host_node() { - assert_conformance( - "events", - r#" -import { EventEmitter } from "node:events"; -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const events = require("events"); -const nodeEvents = require("node:events"); - -const emitter = new EventEmitter(); -class DerivedEmitter extends require("events") {} -const derived = new DerivedEmitter(); -const constructed = new (require("events"))(); -const seen = []; -const metaNew = []; -const metaRemove = []; -const constructedSeen = []; -const derivedSeen = []; -const warningEvents = []; - -function persistent(value) { - seen.push(`on:${value}`); -} - -function onTick() {} -function onceTick() {} -function prependTick() {} -function prependOnceTick() {} -function removeFirst() {} -function removeSecond() {} -function removeThird() {} -function onceVisible() {} - -emitter.on("newListener", (eventName, listener) => { - if (eventName === "newListener") { - return; - } - metaNew.push({ - eventName, - listenerName: listener.name || "anon", - tickCountBefore: emitter.listenerCount("tick"), - tickListenersBefore: emitter.listeners("tick").map((fn) => fn.name || "anon"), - }); -}); - -const removalEmitter = new EventEmitter(); -removalEmitter.on("removeListener", (eventName, listener) => { - if (eventName === "removeListener") { - return; - } - metaRemove.push({ - eventName, - listenerName: listener.name || "anon", - tickCountAfter: removalEmitter.listenerCount("tick"), - tickListenersAfter: removalEmitter.listeners("tick").map((fn) => fn.name || "anon"), - eventNamesAfter: removalEmitter.eventNames().sort(), - }); -}); - -emitter.on("tick", persistent); -emitter.once("tick", (value) => { - seen.push(`once:${value}`); -}); -emitter.on("tick", onTick); -emitter.once("tick", onceTick); -emitter.prependListener("tick", prependTick); -emitter.prependOnceListener("tick", prependOnceTick); -const listenerViewEmitter = new EventEmitter(); -listenerViewEmitter.once("visible", onceVisible); -const visibleListeners = listenerViewEmitter.listeners("visible"); -const visibleRawListeners = listenerViewEmitter.rawListeners("visible"); -emitter.emit("tick", "alpha"); -emitter.removeListener("tick", persistent); -emitter.emit("tick", "beta"); - -removalEmitter.on("tick", removeFirst); -removalEmitter.on("tick", removeSecond); -removalEmitter.on("pong", removeThird); -removalEmitter.removeListener("tick", removeSecond); -removalEmitter.removeAllListeners("tick"); -removalEmitter.removeAllListeners(); - -constructed.on("ready", (value) => { - constructedSeen.push(`constructed:${value}`); -}); -const constructedEmitHandled = constructed.emit("ready", "gamma"); - -derived.on("tick", (value) => { - derivedSeen.push(`derived:${value}`); -}); -const derivedEmitHandled = derived.emit("tick", "delta"); - -process.on("warning", (warning) => { - warningEvents.push({ - name: warning.name, - message: warning.message, - type: warning.type, - count: warning.count, - emitterMatches: warning.emitter === emitter, - }); -}); - -for (let index = 0; index < 11; index += 1) { - emitter.on("warning-check", () => {}); -} -emitter.once("warning-check", () => {}); -emitter.prependListener("warning-check", () => {}); -emitter.prependOnceListener("warning-check", () => {}); - -const zeroMaxListenersEmitter = new EventEmitter(); -zeroMaxListenersEmitter.setMaxListeners(0); -for (let index = 0; index < 12; index += 1) { - zeroMaxListenersEmitter.on("disabled-warning-check", () => {}); -} - -await new Promise((resolve) => setTimeout(resolve, 0)); - -console.log(JSON.stringify({ - bareEqualsNode: events === nodeEvents, - cjsEqualsEventEmitter: events === EventEmitter, - bareType: typeof events, - nodeType: typeof nodeEvents, - eventEmitterPropEqualsSelf: events.EventEmitter === events, - nodeEventEmitterPropEqualsSelf: nodeEvents.EventEmitter === nodeEvents, - constructedInstanceWorks: constructed instanceof EventEmitter, - constructedEmitHandled, - constructedSeen, - derivedInstanceWorks: derived instanceof EventEmitter, - derivedEmitHandled, - derivedSeen, - visibleListenersIsArray: Array.isArray(visibleListeners), - visibleRawListenersIsArray: Array.isArray(visibleRawListeners), - listenersUnwrapOnce: visibleListeners?.[0] === onceVisible, - rawListenersKeepWrapper: visibleRawListeners?.[0] !== onceVisible, - rawListenerTargetsOriginal: visibleRawListeners?.[0]?.listener === onceVisible, - metaNew, - metaRemove, - warningEvents, - seen, - listenerCount: emitter.listenerCount("tick"), -})); -"#, - ); -} - -fn stream_conformance_matches_host_node() { - assert_conformance( - "stream", - r#" -import { createRequire } from "node:module"; -import * as streamNs from "node:stream"; - -const stream = streamNs.default ?? streamNs; -const require = createRequire(import.meta.url); -const cjsStream = require("stream"); - -class Source extends stream.Readable { - constructor() { - super(); - this.sent = false; - } - - _read() { - if (this.sent) { - return; - } - this.sent = true; - this.push("alpha"); - this.push("beta"); - this.push(null); - } -} - -class Sink extends stream.Writable { - constructor(chunks) { - super(); - this.chunks = chunks; - } - - _write(chunk, _encoding, callback) { - this.chunks.push(Buffer.from(chunk).toString("utf8")); - callback(); - } -} - -class Upper extends stream.Transform { - _transform(chunk, _encoding, callback) { - callback(null, Buffer.from(chunk).toString("utf8").toUpperCase()); - } -} - -class IterableSource extends stream.Readable { - constructor(values) { - super({ objectMode: true }); - this.values = [...values]; - } - - _read() { - if (this.values.length === 0) { - this.push(null); - return; - } - this.push(this.values.shift()); - } -} - -class RequiredIterableSource extends cjsStream.Readable { - constructor(values) { - super({ objectMode: true }); - this.values = [...values]; - } - - _read() { - if (this.values.length === 0) { - this.push(null); - return; - } - this.push(this.values.shift()); - } -} - -const chunks = []; -const source = new Source(); -const sink = new Sink(chunks); -const upper = new Upper(); - -let pipelineError = null; -const pipelineResult = stream.pipeline(source, upper, sink, (error) => { - pipelineError = error ? String(error.message || error) : null; -}); -source._read(); -await new Promise((resolve) => setTimeout(resolve, 0)); - -const iteratedValues = []; -for await (const chunk of new IterableSource(["gamma", "delta"])) { - iteratedValues.push( - Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk), - ); -} - -const requiredIteratedValues = []; -for await (const chunk of new RequiredIterableSource(["theta", "lambda"])) { - requiredIteratedValues.push( - Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk), - ); -} - -const selfCheckReadable = new IterableSource(["self-check"]); -const selfCheckIterator = selfCheckReadable[Symbol.asyncIterator](); - -console.log(JSON.stringify({ - output: chunks.join("|"), - pipelineReturnedSink: pipelineResult === sink, - pipelineError, - readableIsFunction: typeof stream.Readable === "function", - writableIsFunction: typeof stream.Writable === "function", - transformIsFunction: typeof stream.Transform === "function", - prototypeHasAsyncIterator: - typeof stream.Readable.prototype[Symbol.asyncIterator] === "function", - requiredPrototypeHasAsyncIterator: - typeof cjsStream.Readable.prototype[Symbol.asyncIterator] === "function", - readableIteratorReturnsSelf: - selfCheckIterator[Symbol.asyncIterator]() === selfCheckIterator, - iteratedValues, - requiredIteratedValues, -})); -"#, - ); -} - -fn buffer_conformance_matches_host_node() { - assert_conformance( - "buffer", - r#" -const text = Buffer.from("hello", "utf8"); -const filled = Buffer.alloc(4, 0x61); -const combined = Buffer.concat([text, Buffer.from("-world", "utf8")]); - -console.log(JSON.stringify({ - fromHex: text.toString("hex"), - allocUtf8: filled.toString("utf8"), - concatUtf8: combined.toString("utf8"), - sliceUtf8: combined.slice(3, 8).toString("utf8"), -})); -"#, - ); -} - -fn buffer_concat_truncation_matches_host_node_impl() { - assert_conformance( - "buffer-concat-truncation", - r#" -function describeBuffer(value) { - return { - length: value.length, - hex: value.toString("hex"), - }; -} - -function describeError(fn) { - try { - fn(); - return { threw: false }; - } catch (error) { - return { - threw: true, - name: error?.name ?? null, - }; - } -} - -const chunks = [Buffer.from("abc"), Buffer.from("def")]; - -console.log(JSON.stringify({ - smaller: describeBuffer(Buffer.concat(chunks, 4)), - exact: describeBuffer(Buffer.concat(chunks, 6)), - larger: describeBuffer(Buffer.concat(chunks, 8)), - emptyNonZero: describeBuffer(Buffer.concat([], 3)), - invalidEntry: describeError(() => Buffer.concat([Buffer.from("a"), "x"], 1)), - invalidList: describeError(() => Buffer.concat("nope", 1)), -})); -"#, - ); -} - -#[test] -fn buffer_concat_truncation_matches_host_node() { - run_isolated_builtin_conformance_test("buffer-concat-truncation"); -} - -fn mkdtemp_sync_collision_safe_matches_host_node_impl() { - let cwd = temp_dir("mkdtemp-sync-collision-safe"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import fs from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -const root = fs.mkdtempSync(path.join(os.tmpdir(), "mkdtemp-conformance-")); -const prefix = path.join(root, "x-"); -const sampleCount = 32; -const created = await Promise.all( - Array.from({ length: sampleCount }, () => Promise.resolve().then(() => fs.mkdtempSync(prefix))) -); -const result = { - createdCount: created.length, - uniqueCount: new Set(created).size, - basenameLengths: [...new Set(created.map((value) => path.basename(value).length))].sort( - (left, right) => left - right - ), - prefixesOk: created.every((value) => value.startsWith(prefix)), -}; -fs.rmSync(root, { recursive: true, force: true }); -console.log(JSON.stringify(result)); -"#, - ); - - let guest = run_guest_probe("mkdtemp-sync-collision-safe", &cwd, &entrypoint); - - assert_eq!(guest["createdCount"], Value::from(32)); - assert_eq!(guest["uniqueCount"], Value::from(32)); - assert_eq!(guest["basenameLengths"], json!([8])); - assert_eq!(guest["prefixesOk"], Value::Bool(true)); -} - -#[test] -fn mkdtemp_sync_collision_safe_matches_host_node() { - run_isolated_builtin_conformance_test("mkdtemp-sync-collision-safe"); -} - -fn url_conformance_matches_host_node() { - assert_conformance( - "url", - r#" -import * as urlNs from "node:url"; - -const urlModule = urlNs.default ?? urlNs; -const URLSearchParamsCtor = urlNs.URLSearchParams ?? globalThis.URLSearchParams; -const url = new urlModule.URL("https://example.com/a/b?x=1&y=two#frag"); -url.searchParams.append("z", "3"); -const fileRelative = new urlModule.URL("file:.", "file:///tmp/base/entry.mjs"); -const fileRelativeNoBase = new urlModule.URL("file:./child"); -const plusDecoded = new URLSearchParamsCtor("?a=foo+bar"); -const invalidPercentDecoded = new URLSearchParamsCtor("?a=%&b=%2&c=%GG&d=%E0%A4%A"); -const sortable = new URLSearchParamsCtor([ - ["b", "1"], - ["a", "first"], - ["ä", "umlaut"], - ["a", "second"], - ["aa", "x"], -]); -sortable.sort(); -const setSemantics = new URLSearchParamsCtor("a=1&b=2&a=3&a=4&c=5"); -setSemantics.set("a", "z"); - -const parsed = urlModule.parse("https://example.com/a/b?x=1&y=two#frag", true); - -console.log(JSON.stringify({ - href: url.href, - searchParams: Array.from(url.searchParams.entries()), - plusDecoded: Array.from(plusDecoded.entries()), - plusDecodedString: plusDecoded.toString(), - invalidPercentDecoded: Array.from(invalidPercentDecoded.entries()), - invalidPercentDecodedString: invalidPercentDecoded.toString(), - sortedSearchParams: Array.from(sortable.entries()), - setSearchParams: Array.from(setSemantics.entries()), - setSearchParamsSize: setSemantics.size, - fileRelativeHref: fileRelative.href, - fileRelativeNoBaseHref: fileRelativeNoBase.href, - formatted: urlModule.format(parsed), - parsedPathname: parsed.pathname, - parsedQuery: parsed.query, -})); -"#, - ); -} - -fn stdlib_polyfill_conformance_matches_host_node() { - assert_conformance( - "stdlib-polyfills", - r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const assert = require("node:assert"); -const constants = require("node:constants"); -const path = require("node:path"); -const punycode = require("node:punycode"); -const querystring = require("node:querystring"); -const stringDecoder = require("node:string_decoder"); -const util = require("node:util"); -const utilTypes = require("node:util/types"); -const zlib = require("node:zlib"); - -assert.deepStrictEqual(path.normalize?.("/alpha/../beta"), "/beta"); -assert.notStrictEqual(1, 2); -assert.strictEqual(typeof assert.fail, "function"); - -let throwsCode = null; -assert.throws( - () => { - const error = new TypeError("boom"); - error.code = "ERR_BOOM"; - throw error; - }, - (error) => { - throwsCode = error?.code ?? null; - return true; - }, -); - -let rejectsCode = null; -await assert.rejects( - Promise.reject(Object.assign(new Error("reject"), { code: "ERR_REJECT" })), - (error) => { - rejectsCode = error?.code ?? null; - return true; - }, -); - -const decoder = new stringDecoder.StringDecoder("utf8"); -const textBytes = Buffer.from("Grüße", "utf8"); -const decoded = - decoder.write(textBytes.subarray(0, 4)) + - decoder.end(textBytes.subarray(4)); - -const formatted = util.format("value:%s count:%d json:%j", "alpha", 7, { ok: true }); -const promisified = await util.promisify((value, callback) => callback(null, value.toUpperCase()))("beta"); -const encodedLength = new util.TextEncoder().encode("Grüße").length; -const decodedText = new util.TextDecoder().decode(textBytes); - -const deflated = zlib.deflateSync(Buffer.from("secure-exec", "utf8")); -const inflated = zlib.inflateSync(deflated).toString("utf8"); - -console.log(JSON.stringify({ - constants: { - fOk: constants.F_OK ?? null, - oRdOnly: constants.O_RDONLY ?? null, - rOk: constants.R_OK ?? null, - }, - decoded, - decodedText, - deflatedBase64: deflated.toString("base64"), - encodedLength, - formatted, - inflated, - isArrayBufferView: util.types.isArrayBufferView(textBytes), - isDateViaUtilTypes: utilTypes.isDate(new Date("2024-01-01T00:00:00Z")), - isMapViaUtilTypes: utilTypes.isMap(new Map([["alpha", 1]])), - isUint8ArrayViaUtilTypes: utilTypes.isUint8Array(textBytes), - promisified, - punycodeAscii: punycode.toASCII("mañana.com"), - punycodeUnicode: punycode.toUnicode("xn--maana-pta.com"), - querystringParsed: querystring.parse("a=1&b=x&b=y"), - querystringStringified: querystring.stringify({ a: 1, b: ["x", "y"] }), - rejectsCode, - throwsCode, -})); -"#, - ); -} - -fn extended_builtin_polyfills_work_in_guest_v8() { - let result = run_guest_script( - "extended-builtins", - r#" -import os from "node:os"; -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); -const moduleBuiltin = require("node:module"); -const perfHooks = require("node:perf_hooks"); -const streamConsumers = require("node:stream/consumers"); -const streamPromises = require("node:stream/promises"); -const timersPromises = require("node:timers/promises"); -const tty = require("node:tty"); -const zlib = require("node:zlib"); -const { constants: zlibConstants } = await import("node:zlib"); - -perfHooks.performance.clearMarks?.(); -perfHooks.performance.clearMeasures?.(); -perfHooks.performance.mark("start"); -await timersPromises.setTimeout(5); -perfHooks.performance.mark("end"); -const measure = perfHooks.performance.measure("delta", "start", "end"); - -const immediateValue = await timersPromises.setImmediate("tick"); -const timeoutValue = await timersPromises.setTimeout(1, "done"); -const intervalValues = []; -const interval = timersPromises.setInterval(1, "pulse"); -intervalValues.push((await interval.next()).value); -intervalValues.push((await interval.next()).value); -await interval.return(); - -function createSink() { - const listeners = new Map(); - return { - chunks: [], - write(chunk, callback) { - this.chunks.push(Buffer.from(chunk).toString("utf8")); - callback?.(null); - }, - end(callback) { - queueMicrotask(() => { - for (const handler of listeners.get("finish") ?? []) handler(); - for (const handler of listeners.get("close") ?? []) handler(); - callback?.(null); - }); - }, - once(event, handler) { - const entries = listeners.get(event) ?? []; - listeners.set(event, [...entries, handler]); - return this; - }, - off(event, handler) { - const entries = listeners.get(event) ?? []; - listeners.set( - event, - entries.filter((candidate) => candidate !== handler), - ); - return this; - }, - }; -} - -const pipelineWritable = createSink(); -await streamPromises.pipeline( - (async function* () { - yield Buffer.from("left"); - yield Buffer.from("+"); - yield Buffer.from("right"); - })(), - pipelineWritable, -); - -const finishedWritable = createSink(); -const finishedResult = streamPromises.finished(finishedWritable).then(() => "resolved"); -finishedWritable.end(); - -function makeAsyncStream(chunks) { - return (async function* () { - for (const chunk of chunks) { - yield chunk; - } - })(); -} - -const textValue = await streamConsumers.text( - makeAsyncStream([ - Buffer.from("he"), - Buffer.from("llo"), - ]), -); -const jsonValue = await streamConsumers.json( - makeAsyncStream([Buffer.from('{"ok":true,"count":2}')]), -); -const arrayBufferValue = await streamConsumers.arrayBuffer( - makeAsyncStream([Buffer.from("AB")]), -); -const blobValue = await streamConsumers.blob( - makeAsyncStream([Buffer.from("blob")]), -); -const bufferValue = await streamConsumers.buffer( - makeAsyncStream([Buffer.from("buf")]), -); - -const deflated = zlib.deflateSync(Buffer.from("secure-exec", "utf8")); -const inflated = zlib.inflateSync(deflated).toString("utf8"); - -process.stdout.write(`${JSON.stringify({ - moduleBuiltinHasCreateRequire: - typeof moduleBuiltin.createRequire === "function", - moduleBuiltinHasBuiltinModules: - Array.isArray(moduleBuiltin.builtinModules), - moduleBuiltinHasStreamPromises: - moduleBuiltin.builtinModules.includes("stream/promises"), - os: { - arch: os.arch(), - availableParallelism: os.availableParallelism(), - cpusLength: os.cpus().length, - eol: os.EOL, - freemem: os.freemem(), - hasSignals: typeof os.constants?.signals?.SIGTERM === "number", - homedir: os.homedir(), - hostname: os.hostname(), - networkInterfaceKeys: Object.keys(os.networkInterfaces()), - platform: os.platform(), - release: os.release(), - tmpdir: os.tmpdir(), - totalmem: os.totalmem(), - type: os.type(), - userInfoHomedir: os.userInfo().homedir, - }, - perf: { - entriesByType: perfHooks.performance.getEntriesByType?.("measure")?.length ?? 0, - entriesByName: perfHooks.performance.getEntriesByName?.("delta", "measure")?.length ?? 0, - hasNow: typeof perfHooks.performance.now === "function", - hasObserver: typeof perfHooks.PerformanceObserver === "function", - measureDurationFinite: Number.isFinite(measure.duration), - }, - streamConsumers: { - arrayBufferLength: arrayBufferValue.byteLength, - blobText: await blobValue.text(), - bufferText: bufferValue.toString("utf8"), - jsonCount: jsonValue.count, - jsonOk: jsonValue.ok, - textValue, - }, - streamPromises: { - finishedResult: await finishedResult, - pipelineText: pipelineWritable.chunks.join(""), - }, - timersPromises: { - immediateValue, - intervalValues, - timeoutValue, - }, - tty: { - isatty0: tty.isatty(0), - isatty1: tty.isatty(1), - isatty2: tty.isatty(2), - readStreamType: typeof tty.ReadStream, - writeStreamType: typeof tty.WriteStream, - }, - zlib: { - constantsHasSyncFlush: typeof zlib.constants?.Z_SYNC_FLUSH === "number", - importConstantsHasSyncFlush: typeof zlibConstants?.Z_SYNC_FLUSH === "number", - createDeflateType: typeof zlib.createDeflate, - createInflateType: typeof zlib.createInflate, - inflated, - }, -})}\n`); -process.exit(0); -"#, - ); - - assert_eq!(result["moduleBuiltinHasCreateRequire"], true); - assert_eq!(result["moduleBuiltinHasBuiltinModules"], true); - assert_eq!(result["moduleBuiltinHasStreamPromises"], true); - assert_eq!(result["os"]["platform"], "linux"); - assert_eq!(result["os"]["arch"], "x64"); - assert_eq!(result["os"]["type"], "Linux"); - assert!(result["os"]["homedir"] - .as_str() - .expect("os.homedir string") - .starts_with('/')); - assert_eq!(result["os"]["tmpdir"], "/tmp"); - assert_eq!(result["os"]["userInfoHomedir"], result["os"]["homedir"]); - assert_eq!(result["os"]["eol"], "\n"); - assert_eq!(result["os"]["availableParallelism"], 1); - assert_eq!(result["os"]["cpusLength"], 1); - assert_eq!(result["os"]["totalmem"], 134_217_728u64); - assert_eq!(result["os"]["freemem"], 134_217_728u64); - assert_eq!(result["os"]["hasSignals"], true); - assert!(result["os"]["networkInterfaceKeys"] - .as_array() - .expect("network interfaces array") - .is_empty()); - assert_eq!(result["perf"]["hasNow"], true); - assert_eq!(result["perf"]["hasObserver"], true); - assert_eq!(result["perf"]["measureDurationFinite"], true); - assert_eq!(result["perf"]["entriesByType"], 1); - assert_eq!(result["perf"]["entriesByName"], 1); - assert_eq!(result["timersPromises"]["immediateValue"], "tick"); - assert_eq!(result["timersPromises"]["timeoutValue"], "done"); - assert_eq!( - result["timersPromises"]["intervalValues"] - .as_array() - .expect("interval values"), - &vec![Value::from("pulse"), Value::from("pulse")] - ); - assert_eq!(result["streamPromises"]["pipelineText"], "left+right"); - assert_eq!(result["streamPromises"]["finishedResult"], "resolved"); - assert_eq!(result["streamConsumers"]["textValue"], "hello"); - assert_eq!(result["streamConsumers"]["jsonOk"], true); - assert_eq!(result["streamConsumers"]["jsonCount"], 2); - assert_eq!(result["streamConsumers"]["arrayBufferLength"], 2); - assert_eq!(result["streamConsumers"]["blobText"], "blob"); - assert_eq!(result["streamConsumers"]["bufferText"], "buf"); - assert_eq!(result["tty"]["readStreamType"], "function"); - assert_eq!(result["tty"]["writeStreamType"], "function"); - assert_eq!(result["tty"]["isatty0"], false); - assert_eq!(result["tty"]["isatty1"], false); - assert_eq!(result["tty"]["isatty2"], false); - assert_eq!(result["zlib"]["constantsHasSyncFlush"], true); - assert_eq!(result["zlib"]["importConstantsHasSyncFlush"], true); - assert_eq!(result["zlib"]["createDeflateType"], "function"); - assert_eq!(result["zlib"]["createInflateType"], "function"); - assert_eq!(result["zlib"]["inflated"], "secure-exec"); -} - -fn timer_handle_ref_refresh_matches_host_node_impl() { - assert_node_available(); - - let cwd = temp_dir("builtin-timer-handle-ref-refresh"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -import { performance } from "node:perf_hooks"; - -const timeout = setTimeout(() => {}, 1_000); -const interval = setInterval(() => {}, 1_000); -const initial = { - timeout: timeout.hasRef(), - interval: interval.hasRef(), -}; -const unrefReturnSelf = timeout.unref() === timeout && interval.unref() === interval; -const afterUnref = { - timeout: timeout.hasRef(), - interval: interval.hasRef(), -}; -const refReturnSelf = timeout.ref() === timeout && interval.ref() === interval; -const afterRef = { - timeout: timeout.hasRef(), - interval: interval.hasRef(), -}; -clearTimeout(timeout); -clearInterval(interval); - -const refreshDelay = 80; -const refreshWait = 40; -const refreshTolerance = 20; -const refreshStart = performance.now(); -let refreshReturnSelf = false; -let refreshedAt = 0; - -await new Promise((resolve) => { - const refreshedTimeout = setTimeout(() => { - const elapsed = performance.now() - refreshStart; - console.log(JSON.stringify({ - initial, - unrefReturnSelf, - afterUnref, - refReturnSelf, - afterRef, - refreshReturnSelf, - refreshHonored: elapsed >= refreshedAt + refreshDelay - refreshTolerance, - })); - resolve(); - }, refreshDelay); - - setTimeout(() => { - refreshedAt = performance.now() - refreshStart; - refreshReturnSelf = refreshedTimeout.refresh() === refreshedTimeout; - }, refreshWait); -}); -"#, - ); - - let host = run_host_probe(&cwd, &entrypoint); - let guest = run_guest_probe_with_config( - "timer-handle-ref-refresh", - &cwd, - &entrypoint, - HashMap::new(), - wire_permissions_allow_all(), - &["perf_hooks", "timers"], - ); - - assert_eq!( - guest, - host, - "guest timer handle behavior diverged from host Node\nhost: {}\nguest: {}", - serde_json::to_string_pretty(&host).expect("pretty host JSON"), - serde_json::to_string_pretty(&guest).expect("pretty guest JSON") - ); - assert_eq!(guest["afterUnref"]["timeout"], Value::Bool(false)); - assert_eq!(guest["afterUnref"]["interval"], Value::Bool(false)); - assert_eq!(guest["afterRef"]["timeout"], Value::Bool(true)); - assert_eq!(guest["afterRef"]["interval"], Value::Bool(true)); - assert_eq!(guest["refreshHonored"], Value::Bool(true)); -} - -#[test] -fn timer_handle_ref_refresh_matches_host_node() { - run_isolated_builtin_conformance_test("timer-handle-ref-refresh"); -} - -fn unrefd_timeout_does_not_keep_guest_process_alive_impl() { - let cwd = temp_dir("builtin-timer-unref-exit"); - let entrypoint = cwd.join("entry.mjs"); - write_fixture( - &entrypoint, - r#" -const timer = setTimeout(() => { - console.error("timer-fired"); - process.exitCode = 1; -}, 10_000); - -timer.unref(); -console.log(JSON.stringify({ hasRefAfterUnref: timer.hasRef() })); -"#, - ); - - let mut sidecar = new_sidecar("timer-unref-exit"); - let connection_id = authenticate_wire(&mut sidecar, "conn-timer-unref-exit"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let allowed_builtins = - serde_json::to_string(&["timers"]).expect("serialize timer builtin allowlist"); - let mut metadata = HashMap::new(); - metadata.insert( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - allowed_builtins, - ); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - metadata, - wire_permissions_allow_all(), - ); - - let started_at = Instant::now(); - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-timer-unref-exit", - GuestRuntimeKind::JavaScript, - &entrypoint, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_builtin_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-timer-unref-exit", - Duration::from_secs(2), - ); - let elapsed = started_at.elapsed(); - dispose_vm_and_close_session_wire(&mut sidecar, &connection_id, &session_id, &vm_id); - - assert_eq!(exit_code, 0, "guest process should exit cleanly: {stderr}"); - assert!( - stderr.trim().is_empty(), - "guest process should not wait long enough to fire the timer:\n{stderr}" - ); - if run_timing_sensitive_tests() { - assert!( - elapsed < Duration::from_millis(1_500), - "guest process waited too long for an unref'd timer: {elapsed:?}" - ); - } - - let payload: Value = serde_json::from_str(stdout.trim()).expect("parse timer stdout JSON"); - assert_eq!(payload["hasRefAfterUnref"], Value::Bool(false)); -} - -#[test] -fn unrefd_timeout_does_not_keep_guest_process_alive() { - run_isolated_builtin_conformance_test("timer-unref-exit"); -} - -fn run_named_case(case_name: &str) { - match case_name { - "fs" => fs_conformance_matches_host_node(), - "console" => console_conformance_matches_host_node(), - "child_process" => child_process_conformance_matches_host_node(), - "path" => path_conformance_matches_host_node(), - "crypto" => crypto_conformance_matches_host_node(), - "dns" => dns_conformance_matches_host_node(), - "events" => events_conformance_matches_host_node(), - "stream" => stream_conformance_matches_host_node(), - "buffer" => buffer_conformance_matches_host_node(), - "url" => url_conformance_matches_host_node(), - "stdlib_polyfill" => stdlib_polyfill_conformance_matches_host_node(), - "extended_builtin_polyfills" => extended_builtin_polyfills_work_in_guest_v8(), - other => panic!("unknown builtin conformance case: {other}"), - } -} - -#[test] -fn builtin_conformance_cases() { - let current_exe = std::env::current_exe().expect("current test binary path"); - - for case_name in BUILTIN_CONFORMANCE_CASES { - let status = Command::new(¤t_exe) - .arg("--exact") - .arg("__builtin_conformance_case_runner") - .arg("--nocapture") - .env("AGENTOS_BUILTIN_CONFORMANCE_CASE", case_name) - .status() - .unwrap_or_else(|error| { - panic!("spawn builtin conformance runner for {case_name}: {error}") - }); - - assert!( - status.success(), - "builtin conformance case {case_name} failed with status {status}" - ); - } -} - -#[test] -fn __builtin_conformance_case_runner() { - let Ok(case_name) = std::env::var("AGENTOS_BUILTIN_CONFORMANCE_CASE") else { - return; - }; - - run_named_case(&case_name); -} - -#[test] -fn __builtin_conformance_extra_test_runner() { - let Ok(test_name) = std::env::var("AGENTOS_BUILTIN_CONFORMANCE_EXTRA_TEST") else { - return; - }; - - match test_name.as_str() { - "http-request-keepalive" => http_request_custom_agent_reuses_keepalive_socket_impl(), - "http-request-denied" => http_request_denied_egress_returns_permission_error_impl(), - "child-process-fork-ipc" => child_process_fork_supports_basic_ipc_impl(), - "http-socket-writes" => http_socket_writes_do_not_silently_drop_data_impl(), - "buffer-concat-truncation" => buffer_concat_truncation_matches_host_node_impl(), - "mkdtemp-sync-collision-safe" => mkdtemp_sync_collision_safe_matches_host_node_impl(), - "crypto-basic-fixture" => crypto_basic_fixture_matches_shared_expected_impl(), - "crypto-extended" => crypto_extended_surface_matches_host_node(), - "child-process-exec-spawn-error-code" => { - child_process_exec_preserves_spawn_error_codes_impl() - } - "child-process-native-elf-reject" => { - child_process_rejects_native_elf_binaries_before_wasm_compile_impl() - } - "child-process-kill-numeric-signal" => { - child_process_kill_numeric_signals_match_host_node_impl() - } - "child-process-abort-signal" => child_process_abort_reports_sigabrt_impl(), - "net-socket-readable-state" => net_socket_readable_state_tracks_ssh2_writable_shape_impl(), - "readable-on-data-explicit-pause" => { - readable_on_data_respects_explicit_pause_matches_host_node_impl() - } - "readline-question" => readline_question_reads_real_stdin_impl(), - "vm-is-context" => vm_is_context_only_accepts_create_context_tagged_sandboxes_impl(), - "vm-context-isolation" => vm_context_isolation_and_script_options_match_host_node_impl(), - "vm-optional-surface" => { - vm_optional_surface_is_implemented_or_explicitly_not_implemented_impl() - } - "vm-timeout" => vm_timeout_terminates_within_deadline_impl(), - "perf-hooks-observer" => perf_hooks_observer_and_histogram_match_host_node_impl(), - "process-runtime-stats" => process_runtime_stats_are_live_impl(), - "os-resource-limits" => os_resource_limits_are_vm_scoped_impl(), - "timer-handle-ref-refresh" => timer_handle_ref_refresh_matches_host_node_impl(), - "timer-unref-exit" => unrefd_timeout_does_not_keep_guest_process_alive_impl(), - other => panic!("unknown builtin conformance extra test: {other}"), - } -} diff --git a/crates/sidecar/tests/connection_auth.rs b/crates/sidecar/tests/connection_auth.rs deleted file mode 100644 index 03ad25330..000000000 --- a/crates/sidecar/tests/connection_auth.rs +++ /dev/null @@ -1,192 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - AuthenticateRequest, CreateVmRequest, ExtEnvelope, GuestRuntimeKind, OpenSessionRequest, - RequestPayload, ResponsePayload, RootFilesystemDescriptor, SidecarPlacement, -}; -use std::collections::HashMap; -use support::{ - authenticate_wire, authenticate_wire_with_token, new_sidecar, new_sidecar_with_auth_token, - open_session_wire, temp_dir, wire_connection, wire_request, wire_session, TEST_AUTH_TOKEN, -}; - -#[test] -fn authenticate_ignores_client_connection_hints_and_preserves_existing_owners() { - let mut sidecar = new_sidecar("connection-auth"); - - let connection_a = authenticate_wire(&mut sidecar, "client-a"); - let session_a = open_session_wire(&mut sidecar, 2, &connection_a); - - let auth_b = authenticate_wire_with_token(&mut sidecar, 3, &connection_a, TEST_AUTH_TOKEN); - let connection_b = match auth_b.response.payload { - ResponsePayload::AuthenticatedResponse(response) => { - assert_eq!( - auth_b.response.ownership, - wire_connection(&response.connection_id) - ); - assert_ne!(response.connection_id, connection_a); - response.connection_id - } - other => panic!("unexpected second auth response: {other:?}"), - }; - - let cwd = temp_dir("connection-auth-cwd"); - let create_vm = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_session(&connection_b, &session_a), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::from([(String::from("cwd"), cwd.to_string_lossy().into_owned())]), - RootFilesystemDescriptor { - mode: secure_exec_sidecar::wire::RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }, - None, - )), - )) - .expect("dispatch cross-connection create_vm"); - - match create_vm.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!(response.message.contains("not owned")); - } - other => panic!("unexpected create_vm response: {other:?}"), - } -} - -#[test] -fn authenticate_rejects_invalid_auth_tokens() { - let mut sidecar = new_sidecar_with_auth_token("connection-auth-invalid", "expected-token"); - - let rejected_connection = "client-a"; - let result = authenticate_wire_with_token(&mut sidecar, 1, rejected_connection, "wrong-token"); - - match result.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "unauthorized"); - assert!(response.message.contains("invalid auth token")); - } - other => panic!("unexpected invalid auth response: {other:?}"), - } - - assert_rejected_auth_does_not_open_connection(&mut sidecar, 2, rejected_connection); - assert_rejected_auth_does_not_open_connection(&mut sidecar, 3, "conn-1"); -} - -#[test] -fn authenticate_rejects_bridge_contract_version_mismatch() { - let mut sidecar = new_sidecar("connection-auth-bridge-version"); - let rejected_connection = "client-a"; - - let result = sidecar - .dispatch_wire_blocking(wire_request( - 1, - wire_connection(rejected_connection), - RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("bridge-version-test"), - auth_token: String::from(TEST_AUTH_TOKEN), - protocol_version: secure_exec_sidecar::wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version + 1, - }), - )) - .expect("dispatch mismatched authenticate"); - - match result.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "bridge_version_mismatch"); - assert!(response.message.contains("expected")); - assert!(response.message.contains("got")); - } - other => panic!("unexpected bridge version auth response: {other:?}"), - } - - assert_rejected_auth_does_not_open_connection(&mut sidecar, 2, rejected_connection); - assert_rejected_auth_does_not_open_connection(&mut sidecar, 3, "conn-1"); -} - -#[test] -fn authenticate_rejects_protocol_version_mismatch() { - let mut sidecar = new_sidecar("connection-auth-protocol-version"); - let rejected_connection = "client-a"; - - let result = sidecar - .dispatch_wire_blocking(wire_request( - 1, - wire_connection(rejected_connection), - RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("protocol-version-test"), - auth_token: String::from(TEST_AUTH_TOKEN), - protocol_version: secure_exec_sidecar::wire::PROTOCOL_VERSION + 1, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - )) - .expect("dispatch mismatched authenticate"); - - match result.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "protocol_version_mismatch"); - assert!(response.message.contains("expected")); - assert!(response.message.contains("got")); - } - other => panic!("unexpected protocol version auth response: {other:?}"), - } - - assert_rejected_auth_does_not_open_connection(&mut sidecar, 2, rejected_connection); - assert_rejected_auth_does_not_open_connection(&mut sidecar, 3, "conn-1"); -} - -#[test] -fn ext_requests_fail_closed_when_namespace_is_unregistered() { - let mut sidecar = new_sidecar("connection-auth-ext"); - let connection_id = authenticate_wire(&mut sidecar, "ext-client"); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - 2, - wire_connection(&connection_id), - RequestPayload::ExtEnvelope(ExtEnvelope { - namespace: "dev.rivet.secure-exec.test".to_string(), - payload: b"hello-ext".to_vec(), - }), - )) - .expect("dispatch ext request"); - - match result.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "unknown_extension"); - assert!(response.message.contains("dev.rivet.secure-exec.test")); - } - other => panic!("unexpected ext response: {other:?}"), - } -} - -fn assert_rejected_auth_does_not_open_connection( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: i64, - connection_id: &str, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_connection(connection_id), - RequestPayload::OpenSessionRequest(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared( - secure_exec_sidecar::wire::SidecarPlacementShared { pool: None }, - ), - metadata: HashMap::new(), - }), - )) - .expect("dispatch open session after rejected authenticate"); - - match result.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!(response.message.contains("has not authenticated")); - } - other => panic!("unexpected post-rejection session response: {other:?}"), - } -} diff --git a/crates/sidecar/tests/crash_isolation.rs b/crates/sidecar/tests/crash_isolation.rs deleted file mode 100644 index abc3ab625..000000000 --- a/crates/sidecar/tests/crash_isolation.rs +++ /dev/null @@ -1,246 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{EventPayload, GuestRuntimeKind, OwnershipScope, StreamChannel}; -use std::collections::BTreeMap; -use std::time::{Duration, Instant}; -use support::{ - assert_node_available, authenticate_wire, create_vm_wire, execute_wire, new_sidecar, - open_session_wire, temp_dir, wire_session, wire_vm, write_fixture, -}; - -const PROCESS_OUTPUT_BYTE_LIMIT: usize = 1024 * 1024; - -#[derive(Debug, Default)] -struct ProcessResult { - stdout: String, - stderr: String, - exit_code: Option, -} - -#[test] -fn guest_failure_in_one_vm_does_not_break_peer_vm_execution() { - assert_node_available(); - - let mut sidecar = new_sidecar("crash-isolation"); - let cwd = temp_dir("crash-isolation-cwd"); - let crash_entry = cwd.join("crash.cjs"); - let healthy_entry = cwd.join("healthy.cjs"); - - write_fixture(&crash_entry, "throw new Error(\"boom\");\n"); - write_fixture(&healthy_entry, "console.log(\"healthy\");\n"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (crash_vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - let (healthy_vm_id, _) = create_vm_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - execute_wire( - &mut sidecar, - 5, - &connection_id, - &session_id, - &crash_vm_id, - "proc-crash", - GuestRuntimeKind::JavaScript, - &crash_entry, - Vec::new(), - ); - execute_wire( - &mut sidecar, - 6, - &connection_id, - &session_id, - &healthy_vm_id, - "proc-healthy", - GuestRuntimeKind::JavaScript, - &healthy_entry, - Vec::new(), - ); - - let mut results = BTreeMap::from([ - (crash_vm_id.clone(), ProcessResult::default()), - (healthy_vm_id.clone(), ProcessResult::default()), - ]); - let deadline = Instant::now() + Duration::from_secs(10); - let ownership = wire_session(&connection_id, &session_id); - - let is_complete = |results: &BTreeMap| { - let crash = results - .get(&crash_vm_id) - .expect("crash vm result should exist"); - let healthy = results - .get(&healthy_vm_id) - .expect("healthy vm result should exist"); - - crash.exit_code == Some(1) && healthy.exit_code == Some(0) - }; - - while !is_complete(&results) { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll crash-isolation event"); - let Some(event) = event else { - assert!( - Instant::now() < deadline, - "timed out waiting for crash-isolation events" - ); - continue; - }; - - let OwnershipScope::VmOwnership(vm_ownership) = event.ownership else { - panic!("expected VM-scoped crash-isolation event"); - }; - let result = results - .get_mut(&vm_ownership.vm_id) - .unwrap_or_else(|| panic!("unexpected vm event for {}", vm_ownership.vm_id)); - - match event.payload { - EventPayload::ProcessOutputEvent(output) => match output.channel { - StreamChannel::Stdout => { - append_process_output( - &mut result.stdout, - &output.chunk, - &output.process_id, - "stdout", - ); - } - StreamChannel::Stderr => { - append_process_output( - &mut result.stderr, - &output.chunk, - &output.process_id, - "stderr", - ); - } - }, - EventPayload::ProcessExitedEvent(exited) => { - result.exit_code = Some(exited.exit_code); - } - EventPayload::VmLifecycleEvent(_) - | EventPayload::StructuredEvent(_) - | EventPayload::ExtEnvelope(_) => {} - } - } - - let crash = results.get(&crash_vm_id).expect("crash vm result"); - let healthy = results.get(&healthy_vm_id).expect("healthy vm result"); - - assert_eq!(crash.exit_code, Some(1)); - assert!( - crash.stderr.contains("boom"), - "unexpected crash stderr: {}", - crash.stderr - ); - assert_eq!(healthy.exit_code, Some(0)); - assert!( - healthy.stderr.is_empty(), - "unexpected healthy stderr: {}", - healthy.stderr - ); - - execute_wire( - &mut sidecar, - 7, - &connection_id, - &session_id, - &healthy_vm_id, - "proc-healthy-2", - GuestRuntimeKind::JavaScript, - &healthy_entry, - Vec::new(), - ); - let (_stdout, stderr, exit_code) = collect_crash_process_output( - &mut sidecar, - &connection_id, - &session_id, - &healthy_vm_id, - "proc-healthy-2", - ); - - assert_eq!(exit_code, 0); - assert!(stderr.is_empty(), "unexpected follow-up stderr: {stderr}"); -} - -fn collect_crash_process_output( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) -> (String, String, i32) { - let ownership = wire_session(connection_id, session_id); - let deadline = Instant::now() + Duration::from_secs(10); - let mut stdout = String::new(); - let mut stderr = String::new(); - let mut exit = None; - - loop { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll crash-isolation follow-up event"); - if let Some(event) = event { - assert_eq!(event.ownership, wire_vm(connection_id, session_id, vm_id)); - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == process_id => { - match output.channel { - StreamChannel::Stdout => append_process_output( - &mut stdout, - &output.chunk, - &output.process_id, - "stdout", - ), - StreamChannel::Stderr => append_process_output( - &mut stderr, - &output.chunk, - &output.process_id, - "stderr", - ), - } - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - exit = Some((exited.exit_code, Instant::now())); - } - EventPayload::ProcessOutputEvent(_) - | EventPayload::ProcessExitedEvent(_) - | EventPayload::VmLifecycleEvent(_) - | EventPayload::StructuredEvent(_) - | EventPayload::ExtEnvelope(_) => {} - } - } - - if let Some((exit_code, seen_at)) = exit { - if Instant::now().duration_since(seen_at) >= Duration::from_millis(200) { - return (stdout, stderr, exit_code); - } - } - - assert!( - Instant::now() < deadline, - "timed out waiting for crash-isolation process {process_id}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - } -} - -fn append_process_output(buffer: &mut String, chunk: &[u8], process_id: &str, channel: &str) { - let text = String::from_utf8_lossy(chunk); - assert!( - buffer.len().saturating_add(text.len()) <= PROCESS_OUTPUT_BYTE_LIMIT, - "crash-isolation process {process_id} exceeded {PROCESS_OUTPUT_BYTE_LIMIT} bytes on {channel}" - ); - buffer.push_str(&text); -} diff --git a/crates/sidecar/tests/extension.rs b/crates/sidecar/tests/extension.rs deleted file mode 100644 index ee51a76b3..000000000 --- a/crates/sidecar/tests/extension.rs +++ /dev/null @@ -1,398 +0,0 @@ -mod support; - -use std::collections::HashMap; -use std::fs; -use std::time::Duration; - -use secure_exec_bridge::{LoadFilesystemStateRequest, PersistenceBridge}; -use secure_exec_sidecar::wire::{ - EventPayload, ExecuteRequest, ExtEnvelope, GuestFilesystemCallRequest, - GuestFilesystemOperation, GuestRuntimeKind, RequestPayload, ResponsePayload, - SidecarRequestPayload, SidecarResponseFrame, SidecarResponsePayload, StreamChannel, - VmLifecycleState, -}; -use secure_exec_sidecar::{ - Extension, ExtensionContext, ExtensionFuture, ExtensionResponse, SidecarError, -}; -use support::{ - assert_node_available, authenticate_wire, create_vm_wire, new_sidecar, open_session_wire, - temp_dir, wire_request, wire_vm, RecordingBridge, -}; - -const TEST_NAMESPACE: &str = "dev.rivet.secure-exec.extension-test"; - -struct EchoExtension; -struct VmLifetimeExtension; - -impl Extension for EchoExtension { - fn namespace(&self) -> &str { - TEST_NAMESPACE - } - - fn handle_request<'a>( - &'a self, - mut ctx: ExtensionContext<'a>, - payload: Vec, - ) -> ExtensionFuture<'a, ExtensionResponse> { - Box::pin(async move { - let callback = - ctx.invoke_callback(b"callback-input".to_vec(), Duration::from_secs(1))?; - let payload = String::from_utf8(payload).map_err(|error| { - SidecarError::InvalidState(format!("invalid extension test entrypoint: {error}")) - })?; - let mut payload_lines = payload.lines(); - let entrypoint = payload_lines - .next() - .ok_or_else(|| { - SidecarError::InvalidState(String::from("missing extension process entrypoint")) - })? - .to_string(); - let lifecycle_entrypoint = payload_lines - .next() - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "missing extension lifecycle entrypoint", - )) - })? - .to_string(); - let process_id = "extension-process"; - ctx.start_buffering_process_output(process_id).await?; - ctx.guest_filesystem_call_wire(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/tmp/extension-fs.txt"), - destination_path: None, - target: None, - content: Some(String::from("extension fs primitive")), - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }) - .await?; - let fs_read = ctx - .guest_filesystem_call_wire(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/tmp/extension-fs.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }) - .await?; - assert_eq!(fs_read.content.as_deref(), Some("extension fs primitive")); - - let started = ctx - .spawn_process_wire(ExecuteRequest { - process_id: process_id.to_string(), - command: None, - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(entrypoint), - args: Vec::new(), - env: HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }) - .await?; - assert_eq!(started.process_id, process_id); - let handoff = ctx - .handoff_buffered_process_output( - "extension-buffered-session", - process_id, - Duration::from_secs(5), - ) - .await?; - assert!(String::from_utf8_lossy(&handoff.stdout).contains("extension-buffered-output")); - assert!(!handoff.stdout_truncated); - let lifecycle_process_id = "extension-lifecycle-process"; - let lifecycle_started = ctx - .spawn_process_wire(ExecuteRequest { - process_id: lifecycle_process_id.to_string(), - command: None, - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(lifecycle_entrypoint), - args: Vec::new(), - env: HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }) - .await?; - assert_eq!(lifecycle_started.process_id, lifecycle_process_id); - ctx.bind_process_to_session("extension-lifecycle-session", lifecycle_process_id) - .await?; - ctx.dispose_session_resources("extension-lifecycle-session") - .await?; - - let mut stdout = handoff.stdout; - let mut exit_code = None; - let mut lifecycle_exit_code = None; - while exit_code.is_none() || lifecycle_exit_code.is_none() { - let event = ctx - .poll_event_wire(Duration::from_secs(5)) - .await? - .ok_or_else(|| { - SidecarError::InvalidState(String::from( - "timed out waiting for extension process event", - )) - })?; - match event.payload { - EventPayload::ProcessOutputEvent(output) - if output.process_id == process_id - && output.channel == StreamChannel::Stdout => - { - stdout.extend(output.chunk); - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - exit_code = Some(exited.exit_code); - } - EventPayload::ProcessExitedEvent(exited) - if exited.process_id == lifecycle_process_id => - { - lifecycle_exit_code = Some(exited.exit_code); - } - EventPayload::ProcessOutputEvent(_) - | EventPayload::ProcessExitedEvent(_) - | EventPayload::VmLifecycleEvent(_) - | EventPayload::StructuredEvent(_) - | EventPayload::ExtEnvelope(_) => {} - } - } - - let stdout = String::from_utf8(stdout).map_err(|error| { - SidecarError::InvalidState(format!("invalid extension process stdout: {error}")) - })?; - let process_summary = format!( - "{}:{}:{}", - String::from_utf8_lossy(&callback), - stdout.trim().replace('\n', "|"), - exit_code.expect("exit code set before loop exits"), - ); - ExtensionResponse::with_wire_events( - process_summary.clone().into_bytes(), - vec![ctx.ext_event_wire(format!("extension-event:{process_summary}").into_bytes())?], - ) - }) - } -} - -impl Extension for VmLifetimeExtension { - fn namespace(&self) -> &str { - "dev.rivet.secure-exec.extension-vm-lifetime-test" - } - - fn handle_request<'a>( - &'a self, - mut ctx: ExtensionContext<'a>, - _payload: Vec, - ) -> ExtensionFuture<'a, ExtensionResponse> { - Box::pin(async move { - ctx.bind_vm_to_session("extension-vm-session").await?; - let events = ctx - .dispose_session_resources_wire("extension-vm-session") - .await?; - ExtensionResponse::with_wire_events(b"vm-disposed".to_vec(), events) - }) - } -} - -#[test] -fn registered_extension_round_trips_ext_request_callback_and_event() { - assert_node_available(); - let mut sidecar = new_sidecar("extension-roundtrip"); - sidecar - .register_extension(Box::new(EchoExtension)) - .expect("register extension"); - sidecar.set_wire_sidecar_request_handler(|frame| match frame.payload { - SidecarRequestPayload::ExtEnvelope(envelope) => { - assert_eq!(envelope.namespace, TEST_NAMESPACE); - assert_eq!(envelope.payload, b"callback-input"); - Ok(SidecarResponseFrame { - schema: frame.schema, - request_id: frame.request_id, - ownership: frame.ownership, - payload: SidecarResponsePayload::ExtEnvelope(ExtEnvelope { - namespace: envelope.namespace, - payload: b"callback-output".to_vec(), - }), - }) - } - other => panic!("unexpected sidecar request payload: {other:?}"), - }); - - let connection_id = authenticate_wire(&mut sidecar, "extension-client"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let cwd = temp_dir("extension-process-cwd"); - let entrypoint = cwd.join("extension-entrypoint.mjs"); - let lifecycle_entrypoint = cwd.join("extension-lifecycle-entrypoint.mjs"); - fs::write( - &entrypoint, - "console.log('extension-buffered-output');\nsetTimeout(() => {\n console.log('extension-process-output');\n process.exit(0);\n}, 50);\n", - ) - .expect("write extension entrypoint"); - fs::write(&lifecycle_entrypoint, "setInterval(() => {}, 1000);\n") - .expect("write extension lifecycle entrypoint"); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - let result = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExtEnvelope(ExtEnvelope { - namespace: TEST_NAMESPACE.to_string(), - payload: format!( - "{}\n{}", - entrypoint.to_string_lossy(), - lifecycle_entrypoint.to_string_lossy() - ) - .into_bytes(), - }), - )) - .expect("dispatch extension request"); - - match result.response.payload { - ResponsePayload::ExtEnvelope(envelope) => { - assert_eq!(envelope.namespace, TEST_NAMESPACE); - assert_eq!( - envelope.payload, - b"callback-output:extension-buffered-output|extension-process-output:0" - ); - } - other => panic!("unexpected extension response: {other:?}"), - } - - assert_eq!(result.events.len(), 1); - match &result.events[0].payload { - EventPayload::ExtEnvelope(envelope) => { - assert_eq!(envelope.namespace, TEST_NAMESPACE); - assert_eq!( - envelope.payload, - b"extension-event:callback-output:extension-buffered-output|extension-process-output:0", - ); - } - other => panic!("unexpected extension event: {other:?}"), - } -} - -#[test] -fn extension_session_resources_can_dispose_bound_vm() { - assert_node_available(); - let mut sidecar = new_sidecar("extension-vm-lifetime"); - sidecar - .register_extension(Box::new(VmLifetimeExtension)) - .expect("register vm lifetime extension"); - - let connection_id = authenticate_wire(&mut sidecar, "extension-vm-client"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let cwd = temp_dir("extension-vm-lifetime-cwd"); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExtEnvelope(ExtEnvelope { - namespace: String::from("dev.rivet.secure-exec.extension-vm-lifetime-test"), - payload: Vec::new(), - }), - )) - .expect("dispatch vm lifetime extension request"); - - match result.response.payload { - ResponsePayload::ExtEnvelope(envelope) => { - assert_eq!( - envelope.namespace, - "dev.rivet.secure-exec.extension-vm-lifetime-test" - ); - assert_eq!(envelope.payload, b"vm-disposed"); - } - other => panic!("unexpected extension response: {other:?}"), - } - assert!(result.events.iter().any(|event| { - matches!(&event.payload, EventPayload::VmLifecycleEvent(event) if event.state == VmLifecycleState::Disposed) - })); - - let rejected = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Exists, - path: String::from("/tmp/extension-fs.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("dispatch call against disposed vm"); - match rejected.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!(rejected.message.contains(&vm_id)); - } - other => panic!("unexpected disposed-vm response: {other:?}"), - } - - sidecar - .with_bridge_mut(|bridge: &mut RecordingBridge| { - let snapshot = bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: vm_id.clone(), - }) - .expect("load persisted snapshot"); - assert!( - snapshot.is_some(), - "extension-bound vm disposal should flush a filesystem snapshot" - ); - }) - .expect("inspect persistence bridge"); -} - -#[test] -fn duplicate_extension_namespaces_are_rejected() { - let mut sidecar = new_sidecar("extension-duplicate"); - sidecar - .register_extension(Box::new(EchoExtension)) - .expect("register first extension"); - - let error = sidecar - .register_extension(Box::new(EchoExtension)) - .expect_err("duplicate extension namespace should fail"); - assert!(matches!(error, SidecarError::Conflict(_))); -} diff --git a/crates/sidecar/tests/fetch_via_undici.rs b/crates/sidecar/tests/fetch_via_undici.rs deleted file mode 100644 index 9f7a3779a..000000000 --- a/crates/sidecar/tests/fetch_via_undici.rs +++ /dev/null @@ -1,591 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::GuestRuntimeKind; -use std::collections::HashMap; -use std::io::{Read, Write}; -use std::net::TcpListener; -use std::process::Command; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; -use std::thread; -use std::time::{Duration, Instant}; -use support::{ - assert_node_available, authenticate_wire, collect_process_output_wire_with_timeout, - create_vm_wire_with_metadata, dispose_vm_and_close_session, execute_wire, new_sidecar, - open_session_wire, temp_dir, write_fixture, -}; - -const FETCH_VIA_UNDICI_CASES: &[&str] = &["fetch", "abort", "keepalive_no_listener_leak"]; - -// Regression guard for the net-bridge socket-listener leak: a long-lived VM that -// makes many keep-alive HTTP requests over one reused bridge socket must not -// accumulate per-request socket/undici listeners. Each leaked listener trips the -// guest EventEmitter's `MaxListenersExceededWarning` via `console.error`, which -// lands on the process stderr -- so an empty stderr after N >> 10 reused requests -// proves listeners are added and removed symmetrically per request. -fn javascript_fetch_keepalive_does_not_leak_socket_listeners() { - assert_node_available(); - - // Concurrency is the trigger: with an UNBOUNDED per-origin pool, overlapping - // requests dispatched during the connect window each find every existing client - // still `kNeedDrain` and spawn a fresh Client+socket (undici pool.rs kGetDispatcher), - // accumulating their listener sets without bound. The fix bounds the agent's - // `connections`, so excess requests queue on existing clients instead of spawning - // new ones -- the host-side connection count (each guest socket = one accepted TCP - // connection) then stays a small multiple of the concurrency instead of growing - // toward the total request count. - const CONCURRENCY: usize = 8; - const ROUNDS: usize = 20; - const REQUESTS: usize = CONCURRENCY * ROUNDS; - - let mut sidecar = new_sidecar("fetch-keepalive-leak"); - let cwd = temp_dir("fetch-keepalive-leak-cwd"); - let entry = cwd.join("fetch-keepalive-entry.mjs"); - - let listener = TcpListener::bind("127.0.0.1:0").expect("bind host http listener"); - let port = listener.local_addr().expect("listener addr").port(); - let served = Arc::new(AtomicUsize::new(0)); - let connections = Arc::new(AtomicUsize::new(0)); - let served_server = served.clone(); - let connections_server = connections.clone(); - let server = thread::spawn(move || { - listener - .set_nonblocking(true) - .expect("configure nonblocking listener"); - let deadline = Instant::now() + Duration::from_secs(25); - let mut handlers = Vec::new(); - // Accept every connection the guest opens (one reused keep-alive socket in the - // common case, but robust to a fresh socket per request) and serve keep-alive - // responses on each until the guest closes it. Reading to the client's EOF - // means teardown is a clean FIN, never an ECONNRESET test artifact. - while served_server.load(Ordering::SeqCst) < REQUESTS && Instant::now() < deadline { - match listener.accept() { - Ok((mut stream, _)) => { - connections_server.fetch_add(1, Ordering::SeqCst); - let served_handler = served.clone(); - handlers.push(thread::spawn(move || { - stream - .set_read_timeout(Some(Duration::from_millis(200))) - .expect("configure read timeout"); - let handler_deadline = Instant::now() + Duration::from_secs(20); - let mut buffer: Vec = Vec::new(); - let mut chunk = [0_u8; 4096]; - while Instant::now() < handler_deadline { - match stream.read(&mut chunk) { - Ok(0) => break, // guest closed this connection - Ok(n) => { - buffer.extend_from_slice(&chunk[..n]); - // GET requests have no body: each ends at CRLFCRLF. - while let Some(pos) = buffer - .windows(4) - .position(|window| window == b"\r\n\r\n") - { - buffer.drain(..pos + 4); - if stream - .write_all( - b"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 11\r\nConnection: keep-alive\r\n\r\nhello world", - ) - .is_err() - { - return; - } - let _ = stream.flush(); - served_handler.fetch_add(1, Ordering::SeqCst); - } - } - Err(error) - if error.kind() == std::io::ErrorKind::WouldBlock - || error.kind() == std::io::ErrorKind::TimedOut => - { - continue - } - Err(_) => break, - } - } - })); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - thread::sleep(Duration::from_millis(10)); - } - Err(error) => panic!("accept http request: {error}"), - } - } - // Let in-flight handlers drain to the guest's clean close. - for handler in handlers { - let _ = handler.join(); - } - ( - served_server.load(Ordering::SeqCst), - connections_server.load(Ordering::SeqCst), - ) - }); - - write_fixture( - &entry, - format!( - r#" -const ROUNDS = {ROUNDS}; -const CONCURRENCY = {CONCURRENCY}; -// Surface Node process warnings (MaxListenersExceededWarning et al.) onto stderr so -// the host can assert on them -- there is no default "warning" handler otherwise, so a -// listener-leak warning would be emitted-and-dropped instead of observed. -process.on("warning", (warning) => {{ - console.error(`PROCESS_WARNING ${{warning.name}}: ${{warning.message}}`); -}}); -let done = 0; -// Overlapping requests per round (not strictly sequential) so they dispatch while -// the pool's clients are still connecting -- the condition that makes an unbounded -// pool spawn a fresh client+socket per request. -for (let round = 0; round < ROUNDS; round++) {{ - await Promise.all(Array.from({{ length: CONCURRENCY }}, async () => {{ - const response = await fetch("http://127.0.0.1:{port}/health", {{ - headers: {{ accept: "text/plain" }}, - }}); - const body = await response.text(); - if (response.status !== 200 || body !== "hello world") {{ - throw new Error(`request failed: status=${{response.status}} body=${{body}}`); - }} - done++; - }})); -}} -console.log(JSON.stringify({{ ok: true, count: done }})); -"#, - ), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let mut metadata = HashMap::new(); - metadata.insert( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - format!("[{port}]"), - ); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - metadata, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "fetch-keepalive-process", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "fetch-keepalive-process", - Duration::from_secs(30), - ); - dispose_vm_and_close_session(&mut sidecar, &connection_id, &session_id, &vm_id); - let server_result = server.join(); - - assert_eq!(exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - // The leak guard: a MaxListenersExceededWarning (re-surfaced via the fixture's - // process.on("warning") handler) lands on stderr. The fixture's only other stderr - // output would be an uncaught error, so stderr must be empty on the happy path. - assert!( - stderr.trim().is_empty(), - "keep-alive request loop produced unexpected stderr (possible listener leak):\n{stderr}" - ); - assert!( - !stderr.contains("MaxListenersExceededWarning"), - "socket-listener leak detected after {REQUESTS} keep-alive requests:\n{stderr}" - ); - let json_line = stdout - .lines() - .rev() - .find(|line| !line.trim().is_empty()) - .expect("stdout json line"); - let payload: serde_json::Value = - serde_json::from_str(json_line).expect("parse keepalive fetch result"); - assert_eq!(payload["ok"], true); - assert_eq!(payload["count"], REQUESTS); - let (served_count, connection_count) = server_result - .unwrap_or_else(|_| panic!("server thread failed\nstdout:\n{stdout}\nstderr:\n{stderr}")); - assert_eq!( - served_count, REQUESTS, - "server should have served every request" - ); - // The real leak guard: the per-origin pool must be BOUNDED. Each guest socket is one - // accepted TCP connection here, so an unbounded pool that spawns a fresh client+socket - // per overlapping request makes `connection_count` grow with the total request count; - // a bounded pool keeps it to a small multiple of the concurrency regardless of how - // many requests run. (The MaxListenersExceededWarning guard above is necessary but not - // sufficient -- the leaked listeners spread across many per-client emitters, so no - // single one may cross the threshold even while sockets grow unbounded.) - // With the bounded pool, connections stay at/under the cap (+ a small margin for any - // mid-run reconnect) regardless of how many requests run. Observed: 6 with the cap vs - // ~2x the concurrency (16) without it for this 8-way / 160-request load. - let connection_bound = CONCURRENCY + 2; - assert!( - connection_count <= connection_bound, - "undici client-per-request leak: {served_count} requests over {connection_count} \ - connections (expected <= {connection_bound} for concurrency {CONCURRENCY}); an \ - unbounded pool spawns a fresh client+socket per overlapping request" - ); - eprintln!( - "[keepalive-leak] served {served_count} requests over {connection_count} connection(s) \ - (bound {connection_bound})" - ); -} - -fn javascript_fetch_uses_guest_undici_over_kernel_tcp_socket() { - assert_node_available(); - - let mut sidecar = new_sidecar("fetch-via-undici"); - let cwd = temp_dir("fetch-via-undici-cwd"); - let entry = cwd.join("fetch-entry.mjs"); - - let listener = TcpListener::bind("127.0.0.1:0").expect("bind host http listener"); - let port = listener.local_addr().expect("listener addr").port(); - let server = thread::spawn(move || { - listener - .set_nonblocking(true) - .expect("configure nonblocking listener"); - let deadline = Instant::now() + Duration::from_secs(5); - let (mut stream, _) = loop { - match listener.accept() { - Ok(accepted) => break accepted, - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - assert!( - Instant::now() < deadline, - "timed out waiting for guest fetch connection" - ); - thread::sleep(Duration::from_millis(10)); - } - Err(error) => panic!("accept http request: {error}"), - } - }; - stream - .set_read_timeout(Some(Duration::from_secs(2))) - .expect("configure http request read timeout"); - let mut request = String::new(); - let mut buffer = [0_u8; 4096]; - let bytes_read = stream.read(&mut buffer).expect("read http request"); - request.push_str(&String::from_utf8_lossy(&buffer[..bytes_read])); - assert!( - request.contains("GET /health HTTP/1.1"), - "unexpected request: {request}" - ); - - stream - .write_all( - b"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 11\r\nConnection: close\r\n\r\nhello world", - ) - .expect("write http response"); - stream.flush().expect("flush http response"); - }); - - write_fixture( - &entry, - format!( - r#" -console.log("before-fetch"); -console.log(JSON.stringify({{ - fetchType: typeof fetch, - globalFetchType: typeof globalThis.fetch, -}})); -const response = await fetch("http://127.0.0.1:{port}/health", {{ - headers: {{ accept: "text/plain" }}, -}}); -if (response.status !== 200) {{ - throw new Error(`status=${{response.status}}`); -}} -if (!response.body || typeof response.body.getReader !== "function") {{ - throw new Error("expected ReadableStream body"); -}} -const reader = response.body.getReader(); -const decoder = new TextDecoder(); -let body = ""; -for (;;) {{ - const {{ value, done }} = await reader.read(); - if (done) break; - body += decoder.decode(value, {{ stream: true }}); -}} -body += decoder.decode(); -console.log(JSON.stringify({{ - status: response.status, - body, - contentType: response.headers.get("content-type"), - hasReader: true, -}})); -"#, - ), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let mut metadata = HashMap::new(); - metadata.insert( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - format!("[{port}]"), - ); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - metadata, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "fetch-process", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "fetch-process", - Duration::from_secs(10), - ); - dispose_vm_and_close_session(&mut sidecar, &connection_id, &session_id, &vm_id); - let server_result = server.join(); - - assert_eq!(exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stderr.trim().is_empty(), "unexpected stderr:\n{stderr}"); - let json_line = stdout - .lines() - .rev() - .find(|line| !line.trim().is_empty()) - .expect("stdout json line"); - let payload: serde_json::Value = serde_json::from_str(json_line).expect("parse fetch result"); - assert_eq!(payload["status"], 200); - assert_eq!(payload["body"], "hello world"); - assert_eq!(payload["contentType"], "text/plain"); - assert_eq!(payload["hasReader"], true); - server_result - .unwrap_or_else(|_| panic!("server thread failed\nstdout:\n{stdout}\nstderr:\n{stderr}")); -} - -fn javascript_fetch_honors_abortsignal_timeout_and_manual_abort() { - assert_node_available(); - - let mut sidecar = new_sidecar("fetch-abort-via-undici"); - let cwd = temp_dir("fetch-abort-via-undici-cwd"); - let entry = cwd.join("fetch-abort-entry.mjs"); - - let listener = TcpListener::bind("127.0.0.1:0").expect("bind host http listener"); - let port = listener.local_addr().expect("listener addr").port(); - let server = thread::spawn(move || { - listener - .set_nonblocking(true) - .expect("configure nonblocking listener"); - let deadline = Instant::now() + Duration::from_secs(10); - for _ in 0..2 { - let (mut stream, _) = loop { - match listener.accept() { - Ok(accepted) => break accepted, - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - assert!( - Instant::now() < deadline, - "timed out waiting for guest fetch connection" - ); - thread::sleep(Duration::from_millis(10)); - } - Err(error) => panic!("accept http request: {error}"), - } - }; - - stream - .set_read_timeout(Some(Duration::from_secs(2))) - .expect("configure abort request read timeout"); - let mut buffer = [0_u8; 4096]; - let _ = stream.read(&mut buffer); - thread::sleep(Duration::from_millis(250)); - let _ = stream.write_all( - b"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 7\r\nConnection: close\r\n\r\nignored", - ); - let _ = stream.flush(); - } - }); - - write_fixture( - &entry, - format!( - r#" -async function expectAbort(label, promiseFactory, expectedReason) {{ - try {{ - await promiseFactory(); - throw new Error(`${{label}} unexpectedly resolved`); - }} catch (error) {{ - return {{ - label, - name: error?.name ?? null, - code: error?.code ?? null, - message: String(error?.message ?? ""), - expectedReason, - }}; - }} -}} - -const timeoutSignal = AbortSignal.timeout(50); -let timeoutSignalEvents = 0; -timeoutSignal.addEventListener("abort", () => {{ - timeoutSignalEvents += 1; -}}); -const timeoutResult = await expectAbort( - "timeout", - () => fetch("http://127.0.0.1:{port}/timeout", {{ signal: timeoutSignal }}), - timeoutSignal.reason?.name ?? null, -); - -const controller = new AbortController(); -let manualSignalEvents = 0; -controller.signal.addEventListener("abort", () => {{ - manualSignalEvents += 1; -}}); -setTimeout(() => controller.abort("manual-stop"), 25); -const manualResult = await expectAbort( - "manual", - () => fetch("http://127.0.0.1:{port}/manual", {{ signal: controller.signal }}), - controller.signal.reason ?? null, -); - -console.log(JSON.stringify({{ - timeoutResult, - timeoutSignalAborted: timeoutSignal.aborted, - timeoutSignalEvents, - timeoutSignalReasonName: timeoutSignal.reason?.name ?? null, - manualResult, - manualSignalAborted: controller.signal.aborted, - manualSignalEvents, - manualSignalReason: controller.signal.reason ?? null, -}})); -"#, - ), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-abort"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let mut metadata = HashMap::new(); - metadata.insert( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - format!("[{port}]"), - ); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - metadata, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "fetch-abort-process", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "fetch-abort-process", - Duration::from_secs(10), - ); - dispose_vm_and_close_session(&mut sidecar, &connection_id, &session_id, &vm_id); - let server_result = server.join(); - - assert_eq!(exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stderr.trim().is_empty(), "unexpected stderr:\n{stderr}"); - let json_line = stdout - .lines() - .rev() - .find(|line| !line.trim().is_empty()) - .expect("stdout json line"); - let payload: serde_json::Value = serde_json::from_str(json_line).expect("parse fetch result"); - - assert_eq!(payload["timeoutSignalAborted"], true); - assert_eq!(payload["timeoutSignalEvents"], 1); - assert_eq!(payload["timeoutSignalReasonName"], "AbortError"); - assert_ne!( - payload["timeoutResult"]["message"], - "timeout unexpectedly resolved" - ); - - assert_eq!(payload["manualSignalAborted"], true); - assert_eq!(payload["manualSignalEvents"], 1); - assert_eq!(payload["manualSignalReason"], "manual-stop"); - assert_ne!( - payload["manualResult"]["message"], - "manual unexpectedly resolved" - ); - - server_result - .unwrap_or_else(|_| panic!("server thread failed\nstdout:\n{stdout}\nstderr:\n{stderr}")); -} - -fn run_named_case(case_name: &str) { - match case_name { - "fetch" => javascript_fetch_uses_guest_undici_over_kernel_tcp_socket(), - "abort" => javascript_fetch_honors_abortsignal_timeout_and_manual_abort(), - "keepalive_no_listener_leak" => javascript_fetch_keepalive_does_not_leak_socket_listeners(), - other => panic!("unknown fetch_via_undici case: {other}"), - } -} - -#[test] -fn fetch_via_undici_cases() { - let current_exe = std::env::current_exe().expect("current test binary path"); - - for case_name in FETCH_VIA_UNDICI_CASES { - let status = Command::new(¤t_exe) - .arg("--exact") - .arg("__fetch_via_undici_case_runner") - .arg("--nocapture") - .env("AGENTOS_FETCH_VIA_UNDICI_CASE", case_name) - .status() - .unwrap_or_else(|error| { - panic!("spawn fetch_via_undici runner for {case_name}: {error}") - }); - - assert!( - status.success(), - "fetch_via_undici case {case_name} failed with status {status}" - ); - } -} - -#[test] -fn __fetch_via_undici_case_runner() { - let Ok(case_name) = std::env::var("AGENTOS_FETCH_VIA_UNDICI_CASE") else { - return; - }; - - run_named_case(&case_name); -} diff --git a/crates/sidecar/tests/filesystem.rs b/crates/sidecar/tests/filesystem.rs deleted file mode 100644 index 744cf37cb..000000000 --- a/crates/sidecar/tests/filesystem.rs +++ /dev/null @@ -1,945 +0,0 @@ -mod support; - -// `host_dir.rs` is `include!`d below rather than linked from the crate, so its -// macOS-only `crate::macos_fs::…` references must resolve within this test -// binary too. Wire the same module in (macOS only; on Linux those references -// are `#[cfg]`d out and this module is unused). -#[cfg(target_os = "macos")] -#[path = "../src/macos_fs.rs"] -mod macos_fs; - -mod host_dir { - #![allow(dead_code)] - include!("../src/plugins/host_dir.rs"); - - mod tests { - use super::HostDirFilesystem; - use nix::sys::stat::{utimensat, UtimensatFlags}; - use nix::sys::time::{TimeSpec, TimeValLike}; - use secure_exec_kernel::command_registry::CommandDriver; - use secure_exec_kernel::fd_table::O_RDWR; - use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, SpawnOptions}; - use secure_exec_kernel::mount_table::{MountOptions, MountTable}; - use secure_exec_kernel::permissions::Permissions; - use secure_exec_kernel::vfs::{ - MemoryFileSystem, VirtualFileSystem, VirtualTimeSpec, VirtualUtimeSpec, - }; - use std::fs; - use std::os::unix::fs::{MetadataExt, PermissionsExt}; - use std::path::PathBuf; - use std::time::{SystemTime, UNIX_EPOCH}; - - fn temp_dir(prefix: &str) -> PathBuf { - let suffix = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic enough for temp paths") - .as_nanos(); - let path = std::env::temp_dir().join(format!("{prefix}-{suffix}")); - fs::create_dir_all(&path).expect("create temp dir"); - path - } - - fn spawn_shell_in( - kernel: &mut KernelVm, - ) -> secure_exec_kernel::kernel::KernelProcessHandle { - kernel - .spawn_process( - "sh", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("shell")), - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") - } - - #[test] - fn filesystem_host_dir_metadata_ops_reject_symlink_escape_targets() { - let host_dir = temp_dir("secure-exec-sidecar-filesystem-host-dir"); - let outside_dir = temp_dir("secure-exec-sidecar-filesystem-host-dir-outside"); - let outside_file = outside_dir.join("outside.txt"); - fs::write(&outside_file, b"outside").expect("seed outside file"); - std::os::unix::fs::symlink(&outside_file, host_dir.join("link")) - .expect("seed escape symlink"); - - let baseline = fs::metadata(&outside_file).expect("outside metadata before ops"); - let baseline_mode = baseline.permissions().mode() & 0o7777; - let baseline_uid = baseline.uid(); - let baseline_gid = baseline.gid(); - let baseline_mtime = baseline.mtime(); - let baseline_mtime_ns = baseline.mtime_nsec(); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - - let chmod_error = filesystem - .chmod("/link", 0o777) - .expect_err("chmod should reject escaped symlink target"); - assert!(matches!(chmod_error.code(), "EPERM" | "EACCES")); - - let chown_error = filesystem - .chown("/link", baseline_uid, baseline_gid) - .expect_err("chown should reject escaped symlink target"); - assert!(matches!(chown_error.code(), "EPERM" | "EACCES")); - - let utimes_error = filesystem - .utimes("/link", 1_000, 2_000) - .expect_err("utimes should reject escaped symlink target"); - assert!(matches!(utimes_error.code(), "EPERM" | "EACCES")); - - let after = fs::metadata(&outside_file).expect("outside metadata after ops"); - assert_eq!(after.permissions().mode() & 0o7777, baseline_mode); - assert_eq!(after.uid(), baseline_uid); - assert_eq!(after.gid(), baseline_gid); - assert_eq!(after.mtime(), baseline_mtime); - assert_eq!(after.mtime_nsec(), baseline_mtime_ns); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - fs::remove_dir_all(outside_dir).expect("remove outside temp dir"); - } - - #[test] - fn filesystem_host_dir_write_file_with_mode_honors_requested_permissions() { - let host_dir = temp_dir("secure-exec-sidecar-filesystem-host-dir-write-mode"); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - filesystem - .write_file_with_mode("/private.txt", b"secret".to_vec(), Some(0o600)) - .expect("write private host file"); - - let metadata = fs::metadata(host_dir.join("private.txt")).expect("read file metadata"); - assert_eq!(metadata.permissions().mode() & 0o777, 0o600); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - #[test] - fn filesystem_host_dir_recursive_mkdir_with_mode_honors_requested_permissions() { - let host_dir = temp_dir("secure-exec-sidecar-filesystem-host-dir-mkdir-mode"); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - filesystem - .mkdir_with_mode("/private/nested", true, Some(0o700)) - .expect("create private directories"); - - for relative in ["private", "private/nested"] { - let metadata = - fs::metadata(host_dir.join(relative)).expect("read directory metadata"); - assert_eq!( - metadata.permissions().mode() & 0o777, - 0o700, - "unexpected mode for {relative}" - ); - } - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - #[test] - fn filesystem_host_dir_stat_preserves_nanosecond_timestamp_precision() { - let host_dir = temp_dir("secure-exec-sidecar-filesystem-host-dir-stat"); - let tracked_file = host_dir.join("tracked.txt"); - fs::write(&tracked_file, b"tracked").expect("seed tracked file"); - - let atime = TimeSpec::nanoseconds(1_700_000_000_123_456_789); - let mtime = TimeSpec::nanoseconds(1_700_000_000_987_654_321); - utimensat( - None, - &tracked_file, - &atime, - &mtime, - UtimensatFlags::NoFollowSymlink, - ) - .expect("set tracked file timestamps"); - - let baseline = fs::metadata(&tracked_file).expect("tracked file metadata"); - assert_ne!( - baseline.mtime_nsec(), - 0, - "fixture should keep non-zero mtime nsec" - ); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - let stat = filesystem.stat("/tracked.txt").expect("stat tracked file"); - - assert_eq!( - stat.atime_ms, - baseline.atime() as u64 * 1_000 + (baseline.atime_nsec() as u64 / 1_000_000) - ); - assert_eq!(stat.atime_nsec, baseline.atime_nsec() as u32); - assert_eq!( - stat.mtime_ms, - baseline.mtime() as u64 * 1_000 + (baseline.mtime_nsec() as u64 / 1_000_000) - ); - assert_eq!(stat.mtime_nsec, baseline.mtime_nsec() as u32); - assert_eq!( - stat.ctime_ms, - baseline.ctime() as u64 * 1_000 + (baseline.ctime_nsec() as u64 / 1_000_000) - ); - assert_eq!(stat.ctime_nsec, baseline.ctime_nsec() as u32); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - #[test] - fn filesystem_host_dir_utimes_spec_honors_omit_and_now_controls() { - let host_dir = temp_dir("secure-exec-sidecar-filesystem-host-dir-utimes-spec"); - let tracked_file = host_dir.join("tracked.txt"); - fs::write(&tracked_file, b"tracked").expect("seed tracked file"); - - let baseline_atime_sec = 1_700_000_000; - let baseline_atime_nsec = 111_111_111; - let baseline_mtime_sec = 1_700_000_000; - let baseline_mtime_nsec = 222_222_222; - let baseline_atime = - TimeSpec::nanoseconds(baseline_atime_sec * 1_000_000_000 + baseline_atime_nsec); - let baseline_mtime = - TimeSpec::nanoseconds(baseline_mtime_sec * 1_000_000_000 + baseline_mtime_nsec); - utimensat( - None, - &tracked_file, - &baseline_atime, - &baseline_mtime, - UtimensatFlags::FollowSymlink, - ) - .expect("seed tracked file timestamps"); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - filesystem - .utimes_spec( - "/tracked.txt", - VirtualUtimeSpec::Set( - VirtualTimeSpec::new(1_700_000_123, 987_654_321) - .expect("valid atime timespec"), - ), - VirtualUtimeSpec::Omit, - true, - ) - .expect("utimes_spec should preserve mtime"); - - let after_omit = fs::metadata(&tracked_file).expect("tracked file metadata after omit"); - assert_eq!(after_omit.mtime(), baseline_mtime_sec); - assert_eq!(after_omit.mtime_nsec(), baseline_mtime_nsec); - assert_eq!(after_omit.atime(), 1_700_000_123); - assert_eq!(after_omit.atime_nsec(), 987_654_321); - - filesystem - .utimes_spec( - "/tracked.txt", - VirtualUtimeSpec::Now, - VirtualUtimeSpec::Omit, - true, - ) - .expect("utimes_spec should accept UTIME_NOW"); - - let after_now = fs::metadata(&tracked_file).expect("tracked file metadata after now"); - assert_eq!(after_now.mtime(), baseline_mtime_sec); - assert_eq!(after_now.mtime_nsec(), baseline_mtime_nsec); - assert!( - after_now.atime() > after_omit.atime() - || (after_now.atime() == after_omit.atime() - && after_now.atime_nsec() >= after_omit.atime_nsec()), - "UTIME_NOW should move atime forward" - ); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - #[test] - fn filesystem_host_dir_lutimes_updates_symlink_without_touching_target() { - let host_dir = temp_dir("secure-exec-sidecar-filesystem-host-dir-lutimes"); - let target = host_dir.join("target.txt"); - let link = host_dir.join("link.txt"); - fs::write(&target, b"target").expect("seed target file"); - std::os::unix::fs::symlink("target.txt", &link).expect("create symlink"); - - let baseline_target = fs::metadata(&target).expect("target metadata before lutimes"); - let baseline_target_mtime = baseline_target.mtime(); - let baseline_target_mtime_nsec = baseline_target.mtime_nsec(); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - filesystem - .utimes_spec( - "/link.txt", - VirtualUtimeSpec::Set( - VirtualTimeSpec::new(1_700_000_444, 123_456_789).expect("valid link atime"), - ), - VirtualUtimeSpec::Set( - VirtualTimeSpec::new(1_700_000_555, 987_654_321).expect("valid link mtime"), - ), - false, - ) - .expect("lutimes should update the symlink itself"); - - let link_metadata = fs::symlink_metadata(&link).expect("link metadata after lutimes"); - let target_metadata = fs::metadata(&target).expect("target metadata after lutimes"); - - assert_eq!(link_metadata.mtime(), 1_700_000_555); - assert_eq!(link_metadata.mtime_nsec(), 987_654_321); - assert_eq!(link_metadata.atime(), 1_700_000_444); - assert_eq!(link_metadata.atime_nsec(), 123_456_789); - assert_eq!(target_metadata.mtime(), baseline_target_mtime); - assert_eq!(target_metadata.mtime_nsec(), baseline_target_mtime_nsec); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - #[test] - fn kernel_futimes_updates_host_dir_mount_with_nanosecond_precision() { - let host_dir = temp_dir("secure-exec-sidecar-filesystem-host-dir-futimes"); - let tracked_file = host_dir.join("tracked.txt"); - fs::write(&tracked_file, b"tracked").expect("seed tracked file"); - - let mut config = KernelVmConfig::new("vm-host-dir-futimes"); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell driver"); - kernel - .mount_filesystem( - "/workspace", - HostDirFilesystem::new(&host_dir).expect("host dir fs"), - MountOptions::new("host_dir"), - ) - .expect("mount host dir"); - - let process = spawn_shell_in(&mut kernel); - let fd = kernel - .fd_open( - "shell", - process.pid(), - "/workspace/tracked.txt", - O_RDWR, - None, - ) - .expect("open tracked file"); - - kernel - .futimes( - "shell", - process.pid(), - fd, - VirtualUtimeSpec::Set( - VirtualTimeSpec::new(1_700_000_666, 111_222_333) - .expect("valid futimes atime"), - ), - VirtualUtimeSpec::Set( - VirtualTimeSpec::new(1_700_000_777, 444_555_666) - .expect("valid futimes mtime"), - ), - ) - .expect("futimes should update host file"); - - let metadata = fs::metadata(&tracked_file).expect("tracked metadata after futimes"); - assert_eq!(metadata.atime(), 1_700_000_666); - assert_eq!(metadata.atime_nsec(), 111_222_333); - assert_eq!(metadata.mtime(), 1_700_000_777); - assert_eq!(metadata.mtime_nsec(), 444_555_666); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - } -} - -mod shadow_root { - use secure_exec_sidecar::wire::{ - ConfigureVmRequest, DisposeReason, DisposeVmRequest, EventPayload, ExecuteRequest, - GuestFilesystemCallRequest, GuestFilesystemOperation, GuestRuntimeKind, MountDescriptor, - MountPluginDescriptor, RequestPayload, ResponsePayload, RootFilesystemEntryEncoding, - StreamChannel, - }; - use serde_json::json; - use std::collections::HashMap; - use std::fs; - use std::time::Duration; - - use crate::support::{ - self, authenticate_wire, create_vm_wire, open_session_wire, temp_dir, wire_request, - wire_vm, RecordingBridge, - }; - - const PROCESS_OUTPUT_BYTE_LIMIT: usize = 1024 * 1024; - - fn create_test_sidecar() -> secure_exec_sidecar::NativeSidecar { - support::new_sidecar("filesystem-test") - } - - fn authenticate_and_open_session( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - ) -> (String, String) { - let connection_id = authenticate_wire(sidecar, "conn-1"); - let session_id = open_session_wire(sidecar, 2, &connection_id); - (connection_id, session_id) - } - - fn create_vm_with_mounts( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - extra_mounts: Vec, - ) -> String { - let cwd = temp_dir("filesystem-vm-cwd"); - let (vm_id, _) = create_vm_wire( - sidecar, - 3, - connection_id, - session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - let command_root = registry_command_root() - .expect("registry WASM commands are required before mounting command root"); - let mut mounts = vec![MountDescriptor { - guest_path: String::from("/__secure_exec/commands/0"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: serde_json::to_string(&json!({ - "hostPath": command_root, - "readOnly": true, - })) - .expect("serialize command mount config"), - }, - }]; - mounts.extend(extra_mounts); - sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(connection_id, session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts, - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure command mount"); - - vm_id - } - - fn registry_command_root() -> Option { - let repo_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../..") - .canonicalize() - .expect("canonicalize repo root"); - let copied = repo_root.join("registry/software/coreutils/wasm"); - if copied.exists() { - return Some(copied.to_string_lossy().into_owned()); - } - - let fallback = repo_root.join("registry/native/target/wasm32-wasip1/release/commands"); - if fallback.exists() { - return Some(fallback.to_string_lossy().into_owned()); - } - - eprintln!( - "registry WASM commands are required for filesystem tests: expected {} or {}", - copied.display(), - fallback.display() - ); - None - } - - fn guest_filesystem_call( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - request_id: i64, - payload: GuestFilesystemCallRequest, - ) { - let response = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::GuestFilesystemCallRequest(payload), - )) - .expect("dispatch guest filesystem call"); - match response.response.payload { - ResponsePayload::GuestFilesystemResultResponse(_) => {} - other => panic!("expected guest_filesystem_result response, got {other:?}"), - } - } - - #[allow(clippy::too_many_arguments)] - fn execute_command( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - request_id: i64, - process_id: &str, - command: &str, - args: Vec, - ) -> (String, String, Option) { - let response = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from(process_id), - command: Some(String::from(command)), - runtime: None, - entrypoint: None, - args, - env: HashMap::new(), - cwd: Some(String::from("/workspace")), - wasm_permission_tier: None, - }), - )) - .expect("dispatch execute"); - - match response.response.payload { - ResponsePayload::ProcessStartedResponse(started) => { - assert_eq!(started.process_id, process_id); - } - other => panic!("unexpected execute response: {other:?}"), - } - - drain_process_output(sidecar, connection_id, session_id, vm_id, process_id) - } - - fn execute_javascript_entrypoint( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - request_id: i64, - process_id: &str, - entrypoint: &str, - ) -> (String, String, Option) { - let response = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from(process_id), - command: None, - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(String::from(entrypoint)), - args: Vec::new(), - env: HashMap::new(), - cwd: Some(String::from("/workspace")), - wasm_permission_tier: None, - }), - )) - .expect("dispatch execute"); - - match response.response.payload { - ResponsePayload::ProcessStartedResponse(started) => { - assert_eq!(started.process_id, process_id); - } - other => panic!("unexpected execute response: {other:?}"), - } - - drain_process_output(sidecar, connection_id, session_id, vm_id, process_id) - } - - fn drain_process_output( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - ) -> (String, String, Option) { - let ownership = wire_vm(connection_id, session_id, vm_id); - let mut stdout = String::new(); - let mut stderr = String::new(); - let mut exit_code = None; - - for _ in 0..64 { - let Some(event) = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_secs(5)) - .expect("poll wire process event") - else { - if exit_code.is_some() { - break; - } - panic!("timed out waiting for process {process_id} to exit"); - }; - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == process_id => { - match output.channel { - StreamChannel::Stdout => { - append_process_output( - &mut stdout, - &output.chunk, - &output.process_id, - "stdout", - ); - } - StreamChannel::Stderr => { - append_process_output( - &mut stderr, - &output.chunk, - &output.process_id, - "stderr", - ); - } - } - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - exit_code = Some(exited.exit_code); - break; - } - _ => {} - } - } - - (stdout, stderr, exit_code) - } - - fn append_process_output(buffer: &mut String, chunk: &[u8], process_id: &str, channel: &str) { - let text = String::from_utf8_lossy(chunk); - assert!( - buffer.len().saturating_add(text.len()) <= PROCESS_OUTPUT_BYTE_LIMIT, - "filesystem process {process_id} exceeded {PROCESS_OUTPUT_BYTE_LIMIT} bytes on {channel}" - ); - buffer.push_str(&text); - } - - fn dispose_vm_and_close_session( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - ) { - sidecar - .dispatch_wire_blocking(wire_request( - 90, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::DisposeVmRequest(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - )) - .expect("dispose vm"); - sidecar - .close_session_blocking(connection_id, session_id) - .expect("close session"); - sidecar - .remove_connection_blocking(connection_id) - .expect("remove connection"); - } - - #[test] - fn filesystem_cross_mount_rename_reports_exdev_to_js_and_falls_back_in_shell() { - if registry_command_root().is_none() { - return; - } - - let host_dir = temp_dir("secure-exec-sidecar-cross-mount-rename-js"); - fs::write(host_dir.join("source.txt"), "mapped-source\n").expect("seed mapped file"); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = authenticate_and_open_session(&mut sidecar); - let vm_id = create_vm_with_mounts( - &mut sidecar, - &connection_id, - &session_id, - vec![MountDescriptor { - guest_path: String::from("/mapped"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: serde_json::to_string(&json!({ - "hostPath": host_dir.to_string_lossy().into_owned(), - "readOnly": false, - })) - .expect("serialize mapped mount config"), - }, - }], - ); - - guest_filesystem_call( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 4, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/workspace/original.txt"), - content: Some(String::from("original\n")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - ..GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::new(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - } - }, - ); - guest_filesystem_call( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 5, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Symlink, - path: String::from("/workspace/alias.txt"), - target: Some(String::from("/workspace/original.txt")), - ..GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Symlink, - path: String::new(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - } - }, - ); - - let (stdout, stderr, exit_code) = execute_command( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 6, - "proc-ls-symlink", - "/bin/ls", - vec![String::from("-l"), String::from("/workspace")], - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - assert!( - stdout.contains("alias.txt"), - "stdout did not render mirrored symlink:\n{stdout}" - ); - - let (cat_stdout, cat_stderr, cat_exit_code) = execute_command( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 7, - "proc-cat-symlink", - "/bin/cat", - vec![String::from("/workspace/alias.txt")], - ); - assert_eq!(cat_exit_code, Some(0), "stderr: {cat_stderr}"); - assert_eq!(cat_stdout, "original\n"); - - guest_filesystem_call( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 8, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Link, - path: String::from("/workspace/original.txt"), - destination_path: Some(String::from("/workspace/linked.txt")), - ..GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Link, - path: String::new(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - } - }, - ); - - let (ls_stdout, ls_stderr, ls_exit_code) = execute_command( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 9, - "proc-ls-link", - "/bin/ls", - vec![String::from("-l"), String::from("/workspace")], - ); - assert_eq!(ls_exit_code, Some(0), "stderr: {ls_stderr}"); - assert!( - ls_stdout.contains("linked.txt"), - "stdout did not render mirrored hard link:\n{ls_stdout}" - ); - - let (cat_stdout, cat_stderr, cat_exit_code) = execute_command( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 10, - "proc-cat-link", - "/bin/cat", - vec![String::from("/workspace/linked.txt")], - ); - assert_eq!(cat_exit_code, Some(0), "stderr: {cat_stderr}"); - assert_eq!(cat_stdout, "original\n"); - - guest_filesystem_call( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 11, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Mkdir, - path: String::from("/kernel"), - recursive: false, - max_depth: None, - ..GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Mkdir, - path: String::new(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - } - }, - ); - - guest_filesystem_call( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 12, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/workspace/rename-check.js"), - content: Some(String::from( - r#"const fs = require("node:fs"); - -try { - fs.renameSync("/mapped/source.txt", "/kernel/dest.txt"); - console.log(JSON.stringify({ ok: true })); -} catch (error) { - console.log(JSON.stringify({ ok: false, code: error.code, message: error.message })); -} -"#, - )), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - ..GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::new(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - } - }, - ); - - let (stdout, stderr, exit_code) = execute_javascript_entrypoint( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 13, - "proc-js-rename-exdev", - "/workspace/rename-check.js", - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let result: serde_json::Value = - serde_json::from_str(stdout.trim()).expect("parse renameSync result"); - assert_eq!(result["ok"], false); - assert_eq!(result["code"], "EXDEV"); - assert!( - !host_dir.join("dest.txt").exists(), - "renameSync should not create a host destination during EXDEV failure" - ); - assert!( - host_dir.join("source.txt").exists(), - "renameSync should leave the mapped source in place on EXDEV" - ); - - fs::write(host_dir.join("source.txt"), "mv-fallback\n").expect("reset mapped file for mv"); - - let (stdout, stderr, exit_code) = execute_command( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 14, - "proc-mv-cross-mount", - "/bin/mv", - vec![ - String::from("/mapped/source.txt"), - String::from("/kernel/copied.txt"), - ], - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!(stderr, ""); - - let (cat_stdout, cat_stderr, cat_exit_code) = execute_command( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - 15, - "proc-cat-cross-mount", - "/bin/cat", - vec![String::from("/kernel/copied.txt")], - ); - assert_eq!(cat_exit_code, Some(0), "stderr: {cat_stderr}"); - assert_eq!(cat_stdout, "mv-fallback\n"); - assert!( - !host_dir.join("source.txt").exists(), - "mv should unlink the mapped source after copying" - ); - - dispose_vm_and_close_session(&mut sidecar, &connection_id, &session_id, &vm_id); - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } -} diff --git a/crates/sidecar/tests/fixtures/gen-pm-layouts.sh b/crates/sidecar/tests/fixtures/gen-pm-layouts.sh deleted file mode 100755 index dfb204293..000000000 --- a/crates/sidecar/tests/fixtures/gen-pm-layouts.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash -# Generate a clean, isolated node_modules layout per package manager, using -# Docker containers so each install runs with fresh caches/stores and no host -# pollution. Each layout is a workspace root + an `app` subpackage depending on -# `is-odd` (which pulls the transitive `is-number`), reproducing the real -# monorepo case where a package's store escapes the mounted project dir. -# -# Usage: -# crates/sidecar/tests/fixtures/gen-pm-layouts.sh [OUT_DIR] -# then point the layout test at it: -# PM_LAYOUTS_DIR=$OUT_DIR cargo test -p agent-os-client --test module_layout_e2e -- --nocapture -# -# The resulting per-PM store signatures (what the sidecar detector keys on): -# pnpm (isolated) app/node_modules/ -> ../../node_modules/.pnpm/... -# bun (workspace) app/node_modules/ -> ../../node_modules/.bun/... -# yarn (nodeLinker:pnpm) app/node_modules/ -> ../../node_modules/.store/... -# yarn (pnp, default) .pnp.cjs + .yarn/cache, NO node_modules -# npm / yarn-nm / pnpm-hoisted flat (hoisted to root, no store) -> work -set -uo pipefail - -OUT="${1:-$(mktemp -d /tmp/pm-layouts.XXXXXX)}" -mkdir -p "$OUT" -echo "output: $OUT" - -NODE_IMG=node:22-bookworm-slim -BUN_IMG=oven/bun:1-slim -export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 - -scaffold=' -mkdir -p app -cat > package.json < app/package.json < "$OUT/$name.log" 2>&1; then - echo "ok" - else - echo "FAILED (see $OUT/$name.log)" - fi -} - -run npm "$NODE_IMG" 'npm install --silent' -run pnpm-isolated "$NODE_IMG" 'echo "packages: [app]" > pnpm-workspace.yaml; corepack enable >/dev/null 2>&1; corepack pnpm install --config.store-dir=/work/.store --silent' -run pnpm-hoisted "$NODE_IMG" 'echo "packages: [app]" > pnpm-workspace.yaml; printf "node-linker=hoisted\n" > .npmrc; corepack enable >/dev/null 2>&1; corepack pnpm install --config.store-dir=/work/.store --silent' -run yarn-pnp "$NODE_IMG" 'corepack enable >/dev/null 2>&1; corepack yarn set version stable >/dev/null 2>&1; corepack yarn install >/dev/null 2>&1' -run yarn-nm "$NODE_IMG" 'printf "nodeLinker: node-modules\n" > .yarnrc.yml; corepack enable >/dev/null 2>&1; corepack yarn set version stable >/dev/null 2>&1; corepack yarn install >/dev/null 2>&1' -run yarn-pnpm "$NODE_IMG" 'printf "nodeLinker: pnpm\n" > .yarnrc.yml; corepack enable >/dev/null 2>&1; corepack yarn set version stable >/dev/null 2>&1; corepack yarn install >/dev/null 2>&1' -run bun "$BUN_IMG" 'bun install >/dev/null 2>&1' - -echo "" -echo "PM_LAYOUTS_DIR=$OUT" diff --git a/crates/sidecar/tests/fixtures/limits-inventory.json b/crates/sidecar/tests/fixtures/limits-inventory.json deleted file mode 100644 index 9af7c5d93..000000000 --- a/crates/sidecar/tests/fixtures/limits-inventory.json +++ /dev/null @@ -1,1118 +0,0 @@ -[ - { - "name": "MAX_SYMLINK_DEPTH", - "path": "packages/build-tools/bridge-src/builtins/fs.ts", - "class": "invariant", - "rationale": "Linux ELOOP mirror of the kernel invariant." - }, - { - "name": "MAX_REALPATH_SYMLINKS", - "path": "crates/vfs/src/posix/mount_table.rs", - "class": "invariant", - "rationale": "ELOOP bound for cross-mount symlink resolution in realpath." - }, - { - "name": "MAX_TAR_INDEX_ENTRIES", - "path": "crates/vfs/src/posix/tar_fs.rs", - "class": "invariant", - "rationale": "Caps a malformed tar's member count so the in-memory index cannot exhaust host memory." - }, - { - "name": "MAX_TAR_CACHE_ARCHIVES", - "path": "crates/vfs/src/posix/tar_fs.rs", - "class": "invariant", - "rationale": "Bounded, refcounted digest-keyed archive mmap cache; evicts with a warning." - }, - { - "name": "MAX_TAR_SYMLINKS", - "path": "crates/vfs/src/posix/tar_fs.rs", - "class": "invariant", - "rationale": "ELOOP bound for symlink resolution within a single tar archive." - }, - { - "name": "MAX_AGENTOS_PACKAGE_MOUNTS", - "path": "crates/sidecar/src/package_projection.rs", - "class": "policy-deferred", - "rationale": "Per-VM cap on granular /opt/agentos leaf mounts; not yet wired to VmLimits." - }, - { - "name": "MAX_BENCHMARK_ITERATIONS", - "path": "crates/execution/src/benchmark.rs", - "class": "invariant", - "rationale": "Dev benchmarking harness only." - }, - { - "name": "MAX_BENCHMARK_WARMUP_ITERATIONS", - "path": "crates/execution/src/benchmark.rs", - "class": "invariant", - "rationale": "Dev benchmarking harness only." - }, - { - "name": "JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES", - "path": "crates/execution/src/javascript.rs", - "class": "policy", - "rationale": "Guest JS stdout/stderr capture cap.", - "wired": "VmLimits.js_runtime.captured_output_limit_bytes" - }, - { - "name": "MAX_TIMER_DELAY_MS", - "path": "crates/execution/src/javascript.rs", - "class": "invariant", - "rationale": "Clamps a guest timer delay to the JS setTimeout ceiling (2^31-1 ms); a leak guard so a timer thread cannot outlive its session by pinning the session Arc, mirroring the standard setTimeout max rather than operator policy." - }, - { - "name": "NET_BRIDGE_MAX_RAW_WRITE_BYTES", - "path": "packages/build-tools/bridge-src/builtins/net.ts", - "class": "invariant", - "rationale": "Internal socket bridge flush granularity that preserves backpressure under the wired socket buffered-byte limit; not an operator policy cap." - }, - { - "name": "JAVASCRIPT_EVENT_CHANNEL_CAPACITY", - "path": "crates/execution/src/javascript.rs", - "class": "invariant", - "rationale": "Channel shape required by the sync-RPC protocol; flow control, not policy." - }, - { - "name": "JAVASCRIPT_EVENT_PAYLOAD_LIMIT_BYTES", - "path": "crates/execution/src/javascript.rs", - "class": "policy", - "rationale": "Per-event payload cap for the JS event channel.", - "wired": "VmLimits.js_runtime.event_payload_limit_bytes" - }, - { - "name": "KERNEL_STDIN_BUFFER_LIMIT_BYTES", - "path": "crates/execution/src/javascript.rs", - "class": "policy", - "rationale": "Guest stdin buffering cap.", - "wired": "VmLimits.js_runtime.stdin_buffer_limit_bytes" - }, - { - "name": "NODE_SYNC_RPC_RESPONSE_QUEUE_CAPACITY", - "path": "crates/execution/src/javascript.rs", - "class": "invariant", - "rationale": "Channel shape required by the sync-RPC protocol; flow control, not policy." - }, - { - "name": "DEFAULT_V8_CPU_TIME_LIMIT_MS", - "path": "crates/execution/src/javascript.rs", - "class": "policy", - "rationale": "Execution-layer active JavaScript CPU-time fallback; normal VM executions receive the wired sidecar value.", - "wired": "VmLimits.js_runtime.cpu_time_limit_ms" - }, - { - "name": "DEFAULT_V8_WALL_CLOCK_LIMIT_MS", - "path": "crates/execution/src/javascript.rs", - "class": "policy", - "rationale": "Execution-layer JavaScript wall-clock fallback; zero keeps it disabled unless the wired VM limit overrides it.", - "wired": "VmLimits.js_runtime.wall_clock_limit_ms" - }, - { - "name": "DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT_MS", - "path": "crates/execution/src/javascript.rs", - "class": "policy", - "rationale": "Execution-layer Node import-cache materialization fallback; normal VM executions receive the wired sidecar value.", - "wired": "VmLimits.js_runtime.import_cache_materialize_timeout_ms" - }, - { - "name": "DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT", - "path": "crates/execution/src/node_import_cache.rs", - "class": "invariant", - "rationale": "Standalone import-cache materialization fallback; normal VM executions use VmLimits.js_runtime.import_cache_materialize_timeout_ms." - }, - { - "name": "DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS", - "path": "crates/execution/src/python.rs", - "class": "policy", - "rationale": "Python runtime execution timeout.", - "wired": "VmLimits.python.execution_timeout_ms" - }, - { - "name": "DEFAULT_PYTHON_MAX_OLD_SPACE_MB", - "path": "crates/execution/src/python.rs", - "class": "policy", - "rationale": "Python host JS old-space heap sizing; engine-side default for the wired limit.", - "wired": "VmLimits.python.max_old_space_mb" - }, - { - "name": "DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES", - "path": "crates/execution/src/python.rs", - "class": "policy", - "rationale": "Python output buffer cap; env knob already exists.", - "wired": "VmLimits.python.output_buffer_max_bytes" - }, - { - "name": "DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS", - "path": "crates/execution/src/python.rs", - "class": "policy", - "rationale": "Python VFS RPC timeout.", - "wired": "VmLimits.python.vfs_rpc_timeout_ms" - }, - { - "name": "PYTHON_SOCKET_MAX_RECV", - "path": "crates/sidecar/src/execution.rs", - "class": "policy-deferred", - "rationale": "Guest Python socket recv request clamp for one synchronous host read; bounded by default, fold into Python/socket VmLimits if operators need to tune it." - }, - { - "name": "V8_SESSION_FRAME_CHANNEL_CAPACITY", - "path": "crates/execution/src/v8_host.rs", - "class": "invariant", - "rationale": "In-process channel backpressure." - }, - { - "name": "MAX_FRAME_SIZE", - "path": "crates/execution/src/v8_ipc.rs", - "class": "policy", - "rationale": "V8 IPC frame size; single value feeds BOTH codec sides.", - "wired": "VmLimits.js_runtime.v8_ipc_max_frame_bytes" - }, - { - "name": "DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB", - "path": "crates/execution/src/wasm.rs", - "class": "policy", - "rationale": "Wasm runner V8 heap default (2 GiB, intentionally above the 128 MiB per-guest budget so warmup stops OOMing); normal VM executions use VmLimits.wasm.runner_heap_limit_mb.", - "wired": "VmLimits.wasm.runner_heap_limit_mb" - }, - { - "name": "DEFAULT_WASM_PREWARM_TIMEOUT_MS", - "path": "crates/execution/src/wasm.rs", - "class": "policy", - "rationale": "WASM prewarm compile-cache timeout.", - "wired": "VmLimits.wasm.prewarm_timeout_ms" - }, - { - "name": "MAX_SYNC_WASM_PREWARM_MODULE_BYTES", - "path": "crates/execution/src/wasm.rs", - "class": "invariant", - "rationale": "Prewarm compile-cache heuristic bound; not guest-visible behavior." - }, - { - "name": "MAX_WASM_IMPORT_SECTION_ENTRIES", - "path": "crates/execution/src/wasm.rs", - "class": "invariant", - "rationale": "Parser DoS hardening mandated by crates/CLAUDE.md invariant 6." - }, - { - "name": "MAX_WASM_MEMORY_SECTION_ENTRIES", - "path": "crates/execution/src/wasm.rs", - "class": "invariant", - "rationale": "Parser DoS hardening mandated by crates/CLAUDE.md invariant 6." - }, - { - "name": "MAX_WASM_MODULE_FILE_BYTES", - "path": "crates/execution/src/wasm.rs", - "class": "policy", - "rationale": "Guards module load size.", - "wired": "VmLimits.wasm.max_module_file_bytes" - }, - { - "name": "MAX_WASM_VARUINT_BYTES", - "path": "crates/execution/src/wasm.rs", - "class": "invariant", - "rationale": "Parser DoS hardening mandated by crates/CLAUDE.md invariant 6." - }, - { - "name": "WASM_CAPTURED_OUTPUT_LIMIT_BYTES", - "path": "crates/execution/src/wasm.rs", - "class": "policy", - "rationale": "WASM stdout/stderr capture cap.", - "wired": "VmLimits.wasm.captured_output_limit_bytes" - }, - { - "name": "WASM_SYNC_READ_LIMIT_BYTES", - "path": "crates/execution/src/wasm.rs", - "class": "policy", - "rationale": "WASM sync read cap; also templated into the JS runner shim.", - "wired": "VmLimits.wasm.sync_read_limit_bytes" - }, - { - "name": "DEFAULT_STREAM_DEVICE_READ_BYTES", - "path": "crates/kernel/src/device_layer.rs", - "class": "invariant", - "rationale": "Internal device read chunk size; perf detail, not a guest bound." - }, - { - "name": "MAX_FDS_PER_PROCESS", - "path": "crates/kernel/src/fd_table.rs", - "class": "invariant", - "rationale": "FD table layout fixed at 0-255; max_open_fds is the policy knob above it." - }, - { - "name": "SHEBANG_LINE_MAX_BYTES", - "path": "crates/kernel/src/kernel.rs", - "class": "invariant", - "rationale": "Shebang parse guard; matches Linux BINPRM_BUF_SIZE-style bound, parser-safety." - }, - { - "name": "MAX_SNAPSHOT_DEPTH", - "path": "crates/vfs/src/posix/overlay_fs.rs", - "class": "invariant", - "rationale": "Recursion guard against cyclic/abusive layer chains; parser-safety." - }, - { - "name": "MAX_PIPE_BUFFER_BYTES", - "path": "crates/kernel/src/pipe_manager.rs", - "class": "invariant", - "rationale": "Linux default pipe capacity; guest-visible POSIX semantics, not policy." - }, - { - "name": "MAX_ALLOCATED_PID", - "path": "crates/kernel/src/process_table.rs", - "class": "invariant", - "rationale": "POSIX PID value space." - }, - { - "name": "MAX_SIGNAL", - "path": "crates/kernel/src/process_table.rs", - "class": "invariant", - "rationale": "Linux signal number space." - }, - { - "name": "MAX_CANON", - "path": "crates/kernel/src/pty.rs", - "class": "invariant", - "rationale": "POSIX MAX_CANON line-discipline constant." - }, - { - "name": "MAX_PTY_BUFFER_BYTES", - "path": "crates/kernel/src/pty.rs", - "class": "invariant", - "rationale": "Mirrors Linux PTY buffer semantics." - }, - { - "name": "DEFAULT_BLOCKING_READ_TIMEOUT_MS", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_blocking_read_ms" - }, - { - "name": "DEFAULT_MAX_CONNECTIONS", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_connections" - }, - { - "name": "DEFAULT_MAX_FD_WRITE_BYTES", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_fd_write_bytes" - }, - { - "name": "DEFAULT_MAX_FILESYSTEM_BYTES", - "path": "crates/vfs/src/posix/usage.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_filesystem_bytes" - }, - { - "name": "DEFAULT_MAX_INODE_COUNT", - "path": "crates/vfs/src/posix/usage.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_inode_count" - }, - { - "name": "DEFAULT_MAX_OPEN_FDS", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_open_fds" - }, - { - "name": "DEFAULT_MAX_PIPES", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_pipes" - }, - { - "name": "DEFAULT_MAX_PREAD_BYTES", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_pread_bytes" - }, - { - "name": "DEFAULT_MAX_PROCESS_ARGV_BYTES", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_process_argv_bytes" - }, - { - "name": "DEFAULT_MAX_PROCESS_ENV_BYTES", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_process_env_bytes" - }, - { - "name": "DEFAULT_MAX_PROCESSES", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_processes" - }, - { - "name": "DEFAULT_MAX_PTYS", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_ptys" - }, - { - "name": "DEFAULT_MAX_READDIR_ENTRIES", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_readdir_entries" - }, - { - "name": "DEFAULT_MAX_WASM_MEMORY_BYTES", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Default WASM memory envelope; guests stay bounded unless trusted VM config raises the cap.", - "wired": "VmLimits.resources.max_wasm_memory_bytes" - }, - { - "name": "DEFAULT_MAX_SOCKET_BUFFERED_BYTES", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_socket_buffered_bytes" - }, - { - "name": "DEFAULT_MAX_SOCKET_DATAGRAM_QUEUE_LEN", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_socket_datagram_queue_len" - }, - { - "name": "DEFAULT_MAX_SOCKETS", - "path": "crates/kernel/src/resource_accounting.rs", - "class": "policy", - "rationale": "Kernel resource policy surface.", - "wired": "VmLimits.resources.max_sockets" - }, - { - "name": "MAX_PATH_LENGTH", - "path": "crates/vfs/src/posix/vfs.rs", - "class": "invariant", - "rationale": "Linux PATH_MAX; changing it diverges from Linux." - }, - { - "name": "MAX_SYMLINK_DEPTH", - "path": "crates/vfs/src/posix/vfs.rs", - "class": "invariant", - "rationale": "Linux ELOOP resolution limit." - }, - { - "name": "MAX_PATH", - "path": "crates/vfs/src/engine/types.rs", - "class": "invariant", - "rationale": "Linux PATH_MAX mirror for engine-backed VFS paths." - }, - { - "name": "MAX_SYMLINK_DEPTH", - "path": "crates/vfs/src/engine/types.rs", - "class": "invariant", - "rationale": "Linux ELOOP resolution limit for engine-backed VFS paths." - }, - { - "name": "DEFAULT_METADATA_CACHE_ENTRIES", - "path": "crates/sidecar/src/plugins/chunked_local.rs", - "class": "invariant", - "rationale": "In-memory chunk metadata cache size; performance detail, not guest policy." - }, - { - "name": "DEFAULT_METADATA_CACHE_ENTRIES", - "path": "crates/sidecar/src/plugins/chunked_s3.rs", - "class": "invariant", - "rationale": "In-memory chunk metadata cache size; performance detail, not guest policy." - }, - { - "name": "CONTROL_FRAME_QUEUE_CAPACITY", - "path": "crates/secure-exec-client/src/transport.rs", - "class": "invariant", - "rationale": "Internal backpressure channel capacity." - }, - { - "name": "EVENT_CHANNEL_CAPACITY", - "path": "crates/secure-exec-client/src/transport.rs", - "class": "invariant", - "rationale": "Internal backpressure channel capacity." - }, - { - "name": "PENDING_REQUEST_LIMIT", - "path": "crates/secure-exec-client/src/transport.rs", - "class": "invariant", - "rationale": "Internal pending-request ring; fails loudly when exceeded." - }, - { - "name": "REQUEST_FRAME_QUEUE_CAPACITY", - "path": "crates/secure-exec-client/src/transport.rs", - "class": "invariant", - "rationale": "Internal backpressure channel capacity." - }, - { - "name": "DEFAULT_KERNEL_STDIN_READ_MAX_BYTES", - "path": "crates/sidecar/src/execution.rs", - "class": "invariant", - "rationale": "Internal stdin pump chunking; not a guest-visible bound." - }, - { - "name": "DEFAULT_KERNEL_STDIN_READ_TIMEOUT_MS", - "path": "crates/sidecar/src/execution.rs", - "class": "invariant", - "rationale": "Internal stdin pump poll interval; not a guest-visible bound." - }, - { - "name": "EXITED_PROCESS_SNAPSHOT_RETENTION", - "path": "crates/sidecar/src/execution.rs", - "class": "invariant", - "rationale": "Bounded exited-process snapshot ring for wait/inspect bookkeeping." - }, - { - "name": "JAVASCRIPT_NET_POLL_MAX_WAIT", - "path": "crates/sidecar/src/execution.rs", - "class": "invariant", - "rationale": "net.poll sync-RPC wait ceiling; protects the main sync-RPC thread." - }, - { - "name": "MAX_JAVASCRIPT_COMMAND_REDIRECT_DEPTH", - "path": "crates/sidecar/src/execution.rs", - "class": "invariant", - "rationale": "Command-resolution recursion guard (symlink/shim chains); safety invariant." - }, - { - "name": "MAX_PER_PROCESS_STATE_HANDLES", - "path": "crates/sidecar/src/execution.rs", - "class": "policy-deferred", - "rationale": "Crypto/state handle table cap tunable in principle; low demand, wire later." - }, - { - "name": "SQLITE_JS_SAFE_INTEGER_MAX", - "path": "crates/sidecar/src/execution.rs", - "class": "invariant", - "rationale": "JS Number.MAX_SAFE_INTEGER boundary for SQLite integer coercion, not a tunable bound." - }, - { - "name": "VM_FETCH_BUFFER_LIMIT_BYTES", - "path": "crates/sidecar-core/src/vm_fetch.rs", - "class": "policy", - "rationale": "vm.fetch() HTTP response body cap; must stay <= negotiated frame budget.", - "wired": "VmLimits.http.max_fetch_response_bytes" - }, - { - "name": "DEFAULT_ACP_MAX_READ_LINE_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "ACP adapter stdout line cap.", - "wired": "VmLimits.acp.max_read_line_bytes" - }, - { - "name": "DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Pre-session ACP stdout buffer cap.", - "wired": "VmLimits.acp.stdout_buffer_byte_limit" - }, - { - "name": "DEFAULT_JS_CAPTURED_OUTPUT_LIMIT_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Guest JS stdout/stderr capture cap.", - "wired": "VmLimits.js_runtime.captured_output_limit_bytes" - }, - { - "name": "DEFAULT_JS_EVENT_PAYLOAD_LIMIT_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Per-event payload cap for JS event channel.", - "wired": "VmLimits.js_runtime.event_payload_limit_bytes" - }, - { - "name": "DEFAULT_JS_STDIN_BUFFER_LIMIT_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Guest JS stdin buffering cap.", - "wired": "VmLimits.js_runtime.stdin_buffer_limit_bytes" - }, - { - "name": "DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT_MS", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Node import-cache materialization timeout.", - "wired": "VmLimits.js_runtime.import_cache_materialize_timeout_ms" - }, - { - "name": "DEFAULT_MAX_FETCH_RESPONSE_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Default home for vm.fetch() body cap.", - "wired": "VmLimits.http.max_fetch_response_bytes" - }, - { - "name": "DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Python execution timeout.", - "wired": "VmLimits.python.execution_timeout_ms" - }, - { - "name": "DEFAULT_PYTHON_MAX_OLD_SPACE_MB", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Python host JS old-space heap sizing; sidecar default for the wired limit.", - "wired": "VmLimits.python.max_old_space_mb" - }, - { - "name": "DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Python output buffer cap.", - "wired": "VmLimits.python.output_buffer_max_bytes" - }, - { - "name": "DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Python VFS RPC timeout.", - "wired": "VmLimits.python.vfs_rpc_timeout_ms" - }, - { - "name": "DEFAULT_TOOL_TIMEOUT_MS", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Default tool invocation timeout.", - "wired": "VmLimits.tools.default_tool_timeout_ms" - }, - { - "name": "DEFAULT_V8_HEAP_LIMIT_MB", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Default guest JS V8 heap cap.", - "wired": "VmLimits.js_runtime.v8_heap_limit_mb" - }, - { - "name": "DEFAULT_V8_CPU_TIME_LIMIT_MS", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Default active JavaScript CPU-time budget.", - "wired": "VmLimits.js_runtime.cpu_time_limit_ms" - }, - { - "name": "DEFAULT_V8_WALL_CLOCK_LIMIT_MS", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Default JavaScript wall-clock backstop; zero keeps it disabled.", - "wired": "VmLimits.js_runtime.wall_clock_limit_ms" - }, - { - "name": "DEFAULT_V8_IPC_MAX_FRAME_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "V8 IPC codec frame cap.", - "wired": "VmLimits.js_runtime.v8_ipc_max_frame_bytes" - }, - { - "name": "DEFAULT_WASM_CAPTURED_OUTPUT_LIMIT_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "WASM stdout/stderr capture cap.", - "wired": "VmLimits.wasm.captured_output_limit_bytes" - }, - { - "name": "DEFAULT_WASM_MAX_MODULE_FILE_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "WASM module load size.", - "wired": "VmLimits.wasm.max_module_file_bytes" - }, - { - "name": "DEFAULT_WASM_PREWARM_TIMEOUT_MS", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "WASM compile-cache warmup timeout.", - "wired": "VmLimits.wasm.prewarm_timeout_ms" - }, - { - "name": "DEFAULT_WASM_RUNNER_HEAP_LIMIT_MB", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "WASM runner V8 heap cap.", - "wired": "VmLimits.wasm.runner_heap_limit_mb" - }, - { - "name": "DEFAULT_WASM_SYNC_READ_LIMIT_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "WASM sync read cap.", - "wired": "VmLimits.wasm.sync_read_limit_bytes" - }, - { - "name": "MAX_PERSISTED_MANIFEST_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Mount manifest blob size.", - "wired": "VmLimits.plugins.max_persisted_manifest_bytes" - }, - { - "name": "MAX_PERSISTED_MANIFEST_FILE_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Mount manifest file size.", - "wired": "VmLimits.plugins.max_persisted_manifest_file_bytes" - }, - { - "name": "MAX_REGISTERED_TOOLKITS", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Toolkit registration capacity.", - "wired": "VmLimits.tools.max_registered_toolkits" - }, - { - "name": "MAX_REGISTERED_TOOLS_PER_VM", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Tool registration capacity.", - "wired": "VmLimits.tools.max_registered_tools_per_vm" - }, - { - "name": "MAX_TOOL_EXAMPLE_INPUT_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Tool example input size.", - "wired": "VmLimits.tools.max_tool_example_input_bytes" - }, - { - "name": "MAX_TOOL_EXAMPLES_PER_TOOL", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Tool example count.", - "wired": "VmLimits.tools.max_tool_examples_per_tool" - }, - { - "name": "MAX_TOOL_SCHEMA_BYTES", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Tool schema payload size.", - "wired": "VmLimits.tools.max_tool_schema_bytes" - }, - { - "name": "MAX_TOOL_TIMEOUT_MS", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Max tool invocation timeout.", - "wired": "VmLimits.tools.max_tool_timeout_ms" - }, - { - "name": "MAX_TOOLS_PER_TOOLKIT", - "path": "crates/sidecar-core/src/limits.rs", - "class": "policy", - "rationale": "Tools-per-toolkit capacity.", - "wired": "VmLimits.tools.max_tools_per_toolkit" - }, - { - "name": "MAX_PERSISTED_MANIFEST_BYTES", - "path": "crates/sidecar/src/plugins/google_drive.rs", - "class": "policy", - "rationale": "Mount manifest size policy.", - "wired": "VmLimits.plugins.max_persisted_manifest_bytes" - }, - { - "name": "MAX_PERSISTED_MANIFEST_FILE_BYTES", - "path": "crates/sidecar/src/plugins/google_drive.rs", - "class": "policy", - "rationale": "Mount manifest file size policy.", - "wired": "VmLimits.plugins.max_persisted_manifest_file_bytes" - }, - { - "name": "MAX_HOST_DIR_READ_BYTES", - "path": "crates/sidecar/src/plugins/host_dir.rs", - "class": "policy", - "rationale": "Reads the VM's configured max_pread_bytes resource limit.", - "wired": "VmLimits.resources.max_pread_bytes" - }, - { - "name": "DEFAULT_MAX_FULL_READ_BYTES", - "path": "crates/sidecar/src/plugins/sandbox_agent.rs", - "class": "policy-deferred", - "rationale": "Better expressed as per-mount config on the sandbox_agent descriptor; defer to a mount-config change." - }, - { - "name": "DEFAULT_PROCESS_TIMEOUT_MS", - "path": "crates/sidecar/src/plugins/sandbox_agent.rs", - "class": "policy-deferred", - "rationale": "Better expressed as per-mount config on the sandbox_agent descriptor; defer to a mount-config change." - }, - { - "name": "DEFAULT_TIMEOUT_MS", - "path": "crates/sidecar/src/plugins/sandbox_agent.rs", - "class": "policy-deferred", - "rationale": "Better expressed as per-mount config on the sandbox_agent descriptor; defer to a mount-config change." - }, - { - "name": "DEFAULT_COMPLETED_RESPONSE_CAP", - "path": "crates/sidecar-protocol/src/protocol.rs", - "class": "invariant", - "rationale": "Internal dedupe/backpressure ring; loud-fail bounded buffer." - }, - { - "name": "DEFAULT_MAX_FRAME_BYTES", - "path": "crates/sidecar-protocol/src/protocol.rs", - "class": "policy", - "rationale": "Wire frame cap; sidecar-scoped, exposed via NativeSidecarConfig and negotiated to clients.", - "wired": "NativeSidecarConfig.max_frame_bytes" - }, - { - "name": "DEFAULT_MAX_FRAME_BYTES", - "path": "crates/sidecar-protocol/src/wire.rs", - "class": "invariant", - "rationale": "Wire frame-size cap constant in its owning wire module; protocol-level frame invariant, not a per-VM policy limit." - }, - { - "name": "MAX_COMPLETED_SIDECAR_RESPONSES", - "path": "crates/sidecar/src/service.rs", - "class": "invariant", - "rationale": "Internal queue backpressure guard; fails loudly on overflow." - }, - { - "name": "MAX_OUTBOUND_SIDECAR_REQUESTS", - "path": "crates/sidecar/src/service.rs", - "class": "invariant", - "rationale": "Internal queue backpressure guard; fails loudly on overflow." - }, - { - "name": "MAX_PENDING_SIDECAR_RESPONSES", - "path": "crates/sidecar/src/service.rs", - "class": "invariant", - "rationale": "Internal queue backpressure guard; fails loudly on overflow." - }, - { - "name": "MAX_PROCESS_EVENT_QUEUE", - "path": "crates/sidecar/src/service.rs", - "class": "invariant", - "rationale": "Internal queue backpressure guard; fails loudly on overflow." - }, - { - "name": "HOST_REALPATH_MAX_SYMLINK_DEPTH", - "path": "crates/sidecar/src/state.rs", - "class": "invariant", - "rationale": "Host realpath ELOOP guard mirroring Linux symlink depth." - }, - { - "name": "VM_LISTEN_PORT_MAX_METADATA_KEY", - "path": "crates/sidecar/src/state.rs", - "class": "invariant", - "rationale": "Metadata key name string, not a numeric bound." - }, - { - "name": "MAX_EVENT_READY_QUEUE", - "path": "crates/sidecar/src/stdio.rs", - "class": "invariant", - "rationale": "Stdio pump channel capacity; internal flow control." - }, - { - "name": "MAX_STDIN_FRAME_QUEUE", - "path": "crates/sidecar/src/stdio.rs", - "class": "invariant", - "rationale": "Stdio pump channel capacity; internal flow control." - }, - { - "name": "MAX_STDOUT_FRAME_QUEUE", - "path": "crates/sidecar/src/stdio.rs", - "class": "invariant", - "rationale": "Stdio pump channel capacity; internal flow control." - }, - { - "name": "DEFAULT_TOOL_TIMEOUT_MS", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy", - "rationale": "Tool invocation timeout policy.", - "wired": "VmLimits.tools.default_tool_timeout_ms" - }, - { - "name": "MAX_REGISTERED_TOOLKITS", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy", - "rationale": "Tool registration capacity policy.", - "wired": "VmLimits.tools.max_registered_toolkits" - }, - { - "name": "MAX_REGISTERED_TOOLS_PER_VM", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy", - "rationale": "Tool registration capacity policy.", - "wired": "VmLimits.tools.max_registered_tools_per_vm" - }, - { - "name": "MAX_TOOL_DESCRIPTION_LENGTH", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy-deferred", - "rationale": "Cross-boundary contract with packages/core/src/bindings.ts; both sides must change together." - }, - { - "name": "MAX_TOOL_EXAMPLE_INPUT_BYTES", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy", - "rationale": "Example input size policy.", - "wired": "VmLimits.tools.max_tool_example_input_bytes" - }, - { - "name": "MAX_TOOL_EXAMPLES_PER_TOOL", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy", - "rationale": "Example count policy.", - "wired": "VmLimits.tools.max_tool_examples_per_tool" - }, - { - "name": "MAX_TOOL_NAME_LENGTH", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy-deferred", - "rationale": "Cross-boundary contract with packages/core/src/bindings.ts; both sides must change together." - }, - { - "name": "MAX_TOOL_SCHEMA_BYTES", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy", - "rationale": "Schema payload size policy.", - "wired": "VmLimits.tools.max_tool_schema_bytes" - }, - { - "name": "MAX_TOOL_SCHEMA_DEPTH", - "path": "crates/sidecar-core/src/tools.rs", - "class": "invariant", - "rationale": "JSON recursion guard for schema validation; parser-safety." - }, - { - "name": "MAX_TOOL_TIMEOUT_MS", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy", - "rationale": "Tool invocation timeout policy.", - "wired": "VmLimits.tools.max_tool_timeout_ms" - }, - { - "name": "MAX_TOOLKIT_NAME_LENGTH", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy-deferred", - "rationale": "Cross-boundary contract with packages/core/src/bindings.ts; both sides must change together." - }, - { - "name": "MAX_TOOLS_PER_TOOLKIT", - "path": "crates/sidecar-core/src/tools.rs", - "class": "policy", - "rationale": "Tool registration capacity policy.", - "wired": "VmLimits.tools.max_tools_per_toolkit" - }, - { - "name": "MAX_VM_LAYERS", - "path": "crates/sidecar-core/src/layers.rs", - "class": "policy-deferred", - "rationale": "Layer count cap is operator-meaningful but coupled to layer RPC validation tests; wire later." - }, - { - "name": "MAX_CBOR_BRIDGE_CONTAINER_ITEMS", - "path": "crates/v8-runtime/src/bridge.rs", - "class": "invariant", - "rationale": "Codec amplification hardening; parser-safety." - }, - { - "name": "MAX_CBOR_BRIDGE_DEPTH", - "path": "crates/v8-runtime/src/bridge.rs", - "class": "invariant", - "rationale": "Codec recursion hardening; parser-safety." - }, - { - "name": "MAX_PENDING_PROMISES", - "path": "crates/v8-runtime/src/bridge.rs", - "class": "invariant", - "rationale": "Runtime self-protection cap with typed error code; sized for safety, loud on overflow." - }, - { - "name": "MAX_VM_CONTEXTS", - "path": "crates/v8-runtime/src/bridge.rs", - "class": "invariant", - "rationale": "Runtime self-protection cap with typed error code; sized for safety, loud on overflow." - }, - { - "name": "SESSION_OUTPUT_CHANNEL_CAPACITY", - "path": "crates/v8-runtime/src/embedded_runtime.rs", - "class": "invariant", - "rationale": "In-process channel backpressure." - }, - { - "name": "MAX_CJS_NAMED_EXPORTS", - "path": "crates/v8-runtime/src/execution.rs", - "class": "invariant", - "rationale": "Module resolver parser/amplification hardening; sized as safety ceiling, not a tuning knob." - }, - { - "name": "MAX_CJS_RUNTIME_EXPORT_NAME_LEN", - "path": "crates/v8-runtime/src/execution.rs", - "class": "invariant", - "rationale": "Module resolver parser/amplification hardening; sized as safety ceiling, not a tuning knob." - }, - { - "name": "MAX_MODULE_BATCH_RESOLVE_RESPONSE_BYTES", - "path": "crates/v8-runtime/src/execution.rs", - "class": "invariant", - "rationale": "Module resolver parser/amplification hardening; sized as safety ceiling, not a tuning knob." - }, - { - "name": "MAX_MODULE_PREFETCH_BATCH_SIZE", - "path": "crates/v8-runtime/src/execution.rs", - "class": "invariant", - "rationale": "Module resolver parser/amplification hardening; sized as safety ceiling, not a tuning knob." - }, - { - "name": "MAX_MODULE_PREFETCH_GRAPH_MODULES", - "path": "crates/v8-runtime/src/execution.rs", - "class": "invariant", - "rationale": "Module resolver parser/amplification hardening; sized as safety ceiling, not a tuning knob." - }, - { - "name": "MAX_MODULE_RESOLVE_CACHE_ENTRIES", - "path": "crates/v8-runtime/src/execution.rs", - "class": "invariant", - "rationale": "Module resolver parser/amplification hardening; sized as safety ceiling, not a tuning knob." - }, - { - "name": "MAX_MODULE_RESOLVE_MODULES", - "path": "crates/v8-runtime/src/execution.rs", - "class": "invariant", - "rationale": "Module resolver parser/amplification hardening; sized as safety ceiling, not a tuning knob." - }, - { - "name": "MAX_FRAME_SIZE", - "path": "crates/v8-runtime/src/ipc_binary.rs", - "class": "policy", - "rationale": "Pair of execution/v8_ipc.rs; feeds the same V8 IPC frame field.", - "wired": "VmLimits.js_runtime.v8_ipc_max_frame_bytes" - }, - { - "name": "MAX_UNHANDLED_PROMISE_REJECTIONS", - "path": "crates/v8-runtime/src/isolate.rs", - "class": "invariant", - "rationale": "Bounded diagnostic accumulation with typed error." - }, - { - "name": "NEAR_HEAP_LIMIT_HEADROOM_BYTES", - "path": "crates/v8-runtime/src/isolate.rs", - "class": "invariant", - "rationale": "Internal V8 near-heap-limit OOM-guard headroom; runtime self-protection mechanism, not an operator bound." - }, - { - "name": "MAX_DEFERRED_SESSION_COMMANDS", - "path": "crates/v8-runtime/src/session.rs", - "class": "invariant", - "rationale": "Session channel backpressure with typed error." - }, - { - "name": "MAX_DEFERRED_SYNC_MESSAGES", - "path": "crates/v8-runtime/src/session.rs", - "class": "invariant", - "rationale": "Session channel backpressure with typed error." - }, - { - "name": "SESSION_COMMAND_CHANNEL_CAPACITY", - "path": "crates/v8-runtime/src/session.rs", - "class": "invariant", - "rationale": "Session channel backpressure with typed error." - }, - { - "name": "MAX_SNAPSHOT_BLOB_BYTES", - "path": "crates/v8-runtime/src/snapshot.rs", - "class": "invariant", - "rationale": "Build-time artifact sanity guard on first-party assets, not guest input." - }, - { - "name": "MAX_V8_BRIDGE_CODE_BYTES", - "path": "crates/v8-runtime/src/snapshot.rs", - "class": "invariant", - "rationale": "Build-time artifact sanity guard on first-party assets, not guest input." - }, - { - "name": "MAX_V8_USERLAND_CODE_BYTES", - "path": "crates/v8-runtime/src/snapshot.rs", - "class": "invariant", - "rationale": "Sanity bound on the client-configured agent-SDK userland snapshot bundle; trusted-config artifact guard, not guest input." - }, - { - "name": "DEFAULT_HEAP_LIMIT_MB", - "path": "crates/v8-runtime/src/isolate.rs", - "class": "policy", - "rationale": "Engine-side default for the wired V8 isolate heap limit (128 MiB, Cloudflare-matching); operator-raisable via the configured jsRuntime heap limit.", - "wired": "VmLimits.js_runtime.v8_heap_limit_mb" - }, - { - "name": "TRAILING_OUTPUT_DRAIN_MAX_MS", - "path": "packages/core/src/kernel-proxy.ts", - "class": "invariant", - "rationale": "Teardown drain heuristic, not a guest-visible bound." - }, - { - "name": "DEFAULT_SIDECAR_EVENT_BUFFER_CAPACITY", - "path": "packages/core/src/native-client.ts", - "class": "policy-deferred", - "rationale": "Client-side event buffer default; callers can override native client options." - }, - { - "name": "DEFAULT_SIDECAR_FRAME_TIMEOUT_MS", - "path": "packages/core/src/native-client.ts", - "class": "policy-deferred", - "rationale": "Client-side frame timeout default; callers can override native client options." - }, - { - "name": "MAX_SYMLINK_DEPTH", - "path": "packages/core/src/test-runtime.ts", - "class": "invariant", - "rationale": "Linux ELOOP mirror of the kernel invariant." - }, - { - "name": "BROWSER_MAX_FRAME_BYTES", - "path": "crates/sidecar-browser/src/wire_dispatch.rs", - "class": "policy-deferred", - "rationale": "Browser transport frame cap; fixed host transport limit until browser config exposes it." - }, - { - "name": "DEFAULT_READ_MAX_BYTES", - "path": "crates/sidecar-core/src/guest_net.rs", - "class": "policy-deferred", - "rationale": "Fallback guest network read cap when the request omits max bytes; wire to request/config if tuning is needed." - }, - { - "name": "MAX_POLL_WAIT_MS", - "path": "crates/sidecar-core/src/guest_net.rs", - "class": "invariant", - "rationale": "Guest network poll wait clamp; internal scheduling guard." - }, - { - "name": "DEFAULT_READ_MAX_BYTES", - "path": "crates/sidecar-core/src/guest_pty.rs", - "class": "policy-deferred", - "rationale": "Fallback guest PTY read cap when the request omits max bytes; wire to request/config if tuning is needed." - }, - { - "name": "MAX_PTY_READ_WAIT_MS", - "path": "crates/sidecar-core/src/guest_pty.rs", - "class": "invariant", - "rationale": "Guest PTY read wait clamp; internal scheduling guard." - }, - { - "name": "DEFAULT_SIDECAR_EVENT_BUFFER_CAPACITY", - "path": "packages/core/src/sidecar-process.ts", - "class": "policy-deferred", - "rationale": "Client-side event buffer default for spawned sidecar processes; callers can override sidecar process options." - }, - { - "name": "WASM_MODULE_BYTES_CACHE_CAPACITY", - "path": "crates/execution/src/wasm.rs", - "class": "invariant", - "rationale": "Host-side LRU entry cap for cached wasm module bytes; process-wide cache sizing, not per-VM policy." - } -] diff --git a/crates/sidecar/tests/fs_watch_and_streams.rs b/crates/sidecar/tests/fs_watch_and_streams.rs deleted file mode 100644 index 1ea32f5c8..000000000 --- a/crates/sidecar/tests/fs_watch_and_streams.rs +++ /dev/null @@ -1,190 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - CreateVmRequest, GuestRuntimeKind, RequestPayload, ResponsePayload, RootFilesystemDescriptor, - RootFilesystemEntry, RootFilesystemEntryEncoding, RootFilesystemEntryKind, RootFilesystemMode, -}; -use std::collections::HashMap; -use std::time::Duration; -use support::{ - assert_node_available, authenticate_wire, collect_process_output_wire_with_timeout, - execute_wire, new_sidecar, open_session_wire, temp_dir, wire_permissions_allow_all, - wire_request, wire_session, write_fixture, -}; - -fn root_dir(path: &str, mode: u32) -> RootFilesystemEntry { - RootFilesystemEntry { - path: path.to_owned(), - kind: RootFilesystemEntryKind::Directory, - mode: Some(mode), - uid: None, - gid: None, - content: None, - encoding: None, - target: None, - executable: false, - } -} - -fn root_file(path: &str, content: &str) -> RootFilesystemEntry { - RootFilesystemEntry { - path: path.to_owned(), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(content.to_owned()), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - } -} - -#[test] -fn javascript_fs_watch_and_streams_work_against_the_vm_kernel_filesystem() { - assert_node_available(); - - let mut sidecar = new_sidecar("fs-watch-and-streams"); - let cwd = temp_dir("fs-watch-and-streams-cwd"); - let entry = cwd.join("fs-watch-and-streams.mjs"); - - write_fixture( - &entry, - r#" -import fs from "node:fs"; -import { once } from "node:events"; - -const readChunks = []; -const reader = fs.createReadStream("/rpc/input.txt", { - encoding: "utf8", - start: 1, - end: 5, - highWaterMark: 2, -}); -reader.on("data", (chunk) => readChunks.push(chunk)); -await once(reader, "close"); - -const writer = fs.createWriteStream("/rpc/output.txt", { - start: 2, - highWaterMark: 2, -}); -writer.write("XY"); -writer.end("Z"); -await once(writer, "close"); - -const watchEvents = []; -const watchFileEvents = []; -const watcher = fs.watch("/rpc/watch.txt", (eventType, filename) => { - watchEvents.push({ - eventType, - filename: Buffer.isBuffer(filename) ? filename.toString("utf8") : filename, - }); -}); -fs.watchFile("/rpc/watch.txt", { interval: 20 }, (curr, prev) => { - watchFileEvents.push({ - currSize: curr.size, - prevSize: prev.size, - }); -}); - -setTimeout(() => { - fs.writeFileSync("/rpc/watch.txt", "after!!"); -}, 60); - -const deadline = Date.now() + 3000; -while (watchEvents.length === 0 || watchFileEvents.length === 0) { - if (Date.now() > deadline) { - watcher.close(); - fs.unwatchFile("/rpc/watch.txt"); - throw new Error( - `timed out waiting for watch events: ${JSON.stringify({ - watchEvents, - watchFileEvents, - })}`, - ); - } - await new Promise((resolve) => setTimeout(resolve, 20)); -} - -watcher.close(); -fs.unwatchFile("/rpc/watch.txt"); - -console.log( - JSON.stringify({ - readChunks, - output: fs.readFileSync("/rpc/output.txt", "utf8"), - watchEvents, - watchFileEvents, - }), -); -"#, - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-fs-watch-and-streams"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let create = sidecar - .dispatch_wire_blocking(wire_request( - 3, - wire_session(&connection_id, &session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::from([(String::from("cwd"), cwd.to_string_lossy().into_owned())]), - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: vec![ - root_dir("/rpc", 0o755), - root_file("/rpc/input.txt", "abcdefg"), - root_file("/rpc/output.txt", "hello"), - root_file("/rpc/watch.txt", "before"), - ], - }, - Some(wire_permissions_allow_all()), - )), - )) - .expect("create sidecar vm"); - let vm_id = match create.response.payload { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("unexpected create vm response: {other:?}"), - }; - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "fs-watch-and-streams", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "fs-watch-and-streams", - Duration::from_secs(10), - ); - - assert_eq!(exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!(stderr.trim().is_empty(), "unexpected stderr:\n{stderr}"); - - let json_line = stdout - .lines() - .rev() - .find(|line| !line.trim().is_empty()) - .expect("stdout json line"); - let payload: serde_json::Value = - serde_json::from_str(json_line).expect("parse fs watch and streams result"); - - assert_eq!(payload["readChunks"], serde_json::json!(["bc", "de", "f"])); - assert_eq!(payload["output"], "\u{0}\u{0}XYZ"); - assert_eq!(payload["watchEvents"][0]["eventType"], "change"); - assert_eq!(payload["watchEvents"][0]["filename"], "watch.txt"); - assert_eq!(payload["watchFileEvents"][0]["prevSize"], 6); - assert_eq!(payload["watchFileEvents"][0]["currSize"], 7); -} diff --git a/crates/sidecar/tests/generated_protocol.rs b/crates/sidecar/tests/generated_protocol.rs deleted file mode 100644 index 91ed465d4..000000000 --- a/crates/sidecar/tests/generated_protocol.rs +++ /dev/null @@ -1,336 +0,0 @@ -use secure_exec_sidecar::generated_protocol::v1::{ - AuthenticateRequest, ConfigureVmRequest, ConnectionOwnership, ExtEnvelope, FsPermissionScope, - GuestFilesystemCallRequest, GuestFilesystemOperation, MountDescriptor, MountPluginDescriptor, - OwnershipScope, PermissionMode, PermissionsPolicy, ProjectedModuleDescriptor, ProtocolFrame, - ProtocolSchema, RequestFrame, RequestPayload, ResponseFrame, ResponsePayload, - VmConfiguredResponse, VmOwnership, WasmPermissionTier, -}; -use secure_exec_sidecar::protocol as live_protocol; -use serde_json::json; -use std::collections::HashMap; - -const GENERATED_AUTH_FRAME_HEX: &str = "00137365637572652d657865632d73696465636172070007000000000000000006636f6e6e2d31000e67656e6572617465642d7465737405746f6b656e070001000000"; - -#[test] -fn generated_protocol_round_trips_request_frame() { - let frame = ProtocolFrame::RequestFrame(RequestFrame { - schema: ProtocolSchema { - name: live_protocol::PROTOCOL_NAME.to_string(), - version: live_protocol::PROTOCOL_VERSION, - }, - request_id: 7, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: "conn-1".to_string(), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: "generated-test".to_string(), - auth_token: "token".to_string(), - protocol_version: live_protocol::PROTOCOL_VERSION, - bridge_version: 1, - }), - }); - - let encoded = serde_bare::to_vec(&frame).expect("encode generated frame"); - let decoded: ProtocolFrame = serde_bare::from_slice(&encoded).expect("decode generated frame"); - - assert_eq!(decoded, frame); -} - -#[test] -fn generated_protocol_matches_cross_language_auth_frame_bytes() { - let frame = generated_auth_frame(); - - let encoded = serde_bare::to_vec(&frame).expect("encode generated frame"); - assert_eq!(hex_encode(&encoded), GENERATED_AUTH_FRAME_HEX); - - let fixture = hex_decode(GENERATED_AUTH_FRAME_HEX); - let decoded: ProtocolFrame = - serde_bare::from_slice(&fixture).expect("decode generated auth fixture"); - assert_eq!(decoded, frame); -} - -#[test] -fn live_bare_codec_matches_generated_request_bytes() { - let codec = live_protocol::NativeFrameCodec::with_payload_codec( - 1024 * 1024, - live_protocol::NativePayloadCodec::Bare, - ); - - let live_auth = live_protocol::ProtocolFrame::Request(live_protocol::RequestFrame::new( - 7, - live_protocol::OwnershipScope::connection("conn-1"), - live_protocol::RequestPayload::Authenticate(live_protocol::AuthenticateRequest { - client_name: "generated-test".to_string(), - auth_token: "token".to_string(), - protocol_version: live_protocol::PROTOCOL_VERSION, - bridge_version: 1, - }), - )); - let live_auth_payload = live_frame_payload(&codec.encode(&live_auth).expect("encode auth")); - let generated_auth_payload = - serde_bare::to_vec(&generated_auth_frame()).expect("encode generated auth"); - assert_eq!(live_auth_payload, generated_auth_payload); - - let live_configure = live_protocol::ProtocolFrame::Request(live_protocol::RequestFrame::new( - 9, - live_protocol::OwnershipScope::vm("conn-1", "session-1", "vm-1"), - live_protocol::RequestPayload::ConfigureVm(live_protocol::ConfigureVmRequest { - mounts: vec![live_protocol::MountDescriptor { - guest_path: "/node_modules".to_string(), - read_only: true, - plugin: live_protocol::MountPluginDescriptor { - id: "host_dir".to_string(), - config: json!({ - "hostPath": "/tmp/deps", - "readOnly": true, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: Some(live_protocol::PermissionsPolicy { - fs: Some(live_protocol::FsPermissionScope::PermissionMode( - live_protocol::PermissionMode::Allow, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }), - module_access_cwd: Some("/workspace".to_string()), - instructions: vec!["keep it generic".to_string()], - projected_modules: vec![live_protocol::ProjectedModuleDescriptor { - package_name: "workspace".to_string(), - entrypoint: "/workspace/index.js".to_string(), - }], - command_permissions: std::collections::HashMap::from([( - "cat".to_string(), - live_protocol::WasmPermissionTier::ReadOnly, - )]), - loopback_exempt_ports: vec![3000], - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )); - let live_configure_payload = - live_frame_payload(&codec.encode(&live_configure).expect("encode configure")); - let generated_configure_payload = - serde_bare::to_vec(&generated_configure_frame()).expect("encode generated configure"); - assert_eq!(live_configure_payload, generated_configure_payload); - - let live_ext = live_protocol::ProtocolFrame::Request(live_protocol::RequestFrame::new( - 11, - live_protocol::OwnershipScope::connection("conn-1"), - live_protocol::RequestPayload::Ext(live_protocol::ExtEnvelope { - namespace: "dev.rivet.secure-exec.test".to_string(), - payload: b"extension-bytes".to_vec(), - }), - )); - let live_ext_payload = live_frame_payload(&codec.encode(&live_ext).expect("encode ext")); - let generated_ext_payload = - serde_bare::to_vec(&generated_ext_frame()).expect("encode generated ext"); - assert_eq!(live_ext_payload, generated_ext_payload); -} - -#[test] -fn live_bare_codec_decodes_generated_response_bytes() { - let codec = live_protocol::NativeFrameCodec::with_payload_codec( - 1024 * 1024, - live_protocol::NativePayloadCodec::Bare, - ); - let generated = ProtocolFrame::ResponseFrame(ResponseFrame { - schema: protocol_schema(), - request_id: 9, - ownership: generated_vm_ownership(), - payload: ResponsePayload::VmConfiguredResponse(VmConfiguredResponse { - applied_mounts: 2, - applied_software: 0, - projected_commands: Vec::new(), - agents: Vec::new(), - }), - }); - let payload = serde_bare::to_vec(&generated).expect("encode generated response"); - let decoded = codec - .decode(&framed_payload(&payload)) - .expect("decode generated response with live codec"); - - assert_eq!( - decoded, - live_protocol::ProtocolFrame::Response(live_protocol::ResponseFrame::new( - 9, - live_protocol::OwnershipScope::vm("conn-1", "session-1", "vm-1"), - live_protocol::ResponsePayload::VmConfigured(live_protocol::VmConfiguredResponse { - applied_mounts: 2, - applied_software: 0, - projected_commands: Vec::new(), - agents: Vec::new(), - }), - )), - ); -} - -#[test] -fn generated_protocol_preserves_json_utf8_strings() { - let descriptor = MountPluginDescriptor { - id: "chunked_s3".to_string(), - config: r#"{"bucket":"demo","prefix":"workspace"}"#.to_string(), - }; - - let encoded = serde_bare::to_vec(&descriptor).expect("encode generated descriptor"); - let decoded: MountPluginDescriptor = - serde_bare::from_slice(&encoded).expect("decode generated descriptor"); - - assert_eq!(decoded, descriptor); -} - -#[test] -fn generated_protocol_preserves_guest_filesystem_call_offsets() { - let request = GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Pread, - path: "/workspace/data.bin".to_string(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: Some(12), - offset: Some(34), - }; - - let encoded = serde_bare::to_vec(&request).expect("encode generated filesystem call"); - let decoded: GuestFilesystemCallRequest = - serde_bare::from_slice(&encoded).expect("decode generated filesystem call"); - - assert_eq!(decoded, request); -} - -fn hex_encode(bytes: &[u8]) -> String { - const HEX: &[u8; 16] = b"0123456789abcdef"; - let mut output = String::with_capacity(bytes.len() * 2); - for byte in bytes { - output.push(HEX[(byte >> 4) as usize] as char); - output.push(HEX[(byte & 0x0f) as usize] as char); - } - output -} - -fn hex_decode(hex: &str) -> Vec { - assert_eq!(hex.len() % 2, 0, "hex length must be even"); - hex.as_bytes() - .chunks_exact(2) - .map(|pair| (hex_nibble(pair[0]) << 4) | hex_nibble(pair[1])) - .collect() -} - -fn generated_auth_frame() -> ProtocolFrame { - ProtocolFrame::RequestFrame(RequestFrame { - schema: protocol_schema(), - request_id: 7, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: "conn-1".to_string(), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: "generated-test".to_string(), - auth_token: "token".to_string(), - protocol_version: live_protocol::PROTOCOL_VERSION, - bridge_version: 1, - }), - }) -} - -fn generated_configure_frame() -> ProtocolFrame { - ProtocolFrame::RequestFrame(RequestFrame { - schema: protocol_schema(), - request_id: 9, - ownership: generated_vm_ownership(), - payload: RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: "/node_modules".to_string(), - read_only: true, - plugin: MountPluginDescriptor { - id: "host_dir".to_string(), - config: r#"{"hostPath":"/tmp/deps","readOnly":true}"#.to_string(), - }, - }], - software: Vec::new(), - permissions: Some(PermissionsPolicy { - fs: Some(FsPermissionScope::PermissionMode(PermissionMode::Allow)), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }), - module_access_cwd: Some("/workspace".to_string()), - instructions: vec!["keep it generic".to_string()], - projected_modules: vec![ProjectedModuleDescriptor { - package_name: "workspace".to_string(), - entrypoint: "/workspace/index.js".to_string(), - }], - command_permissions: HashMap::from([("cat".to_string(), WasmPermissionTier::ReadOnly)]), - loopback_exempt_ports: vec![3000], - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - }) -} - -fn protocol_schema() -> ProtocolSchema { - ProtocolSchema { - name: live_protocol::PROTOCOL_NAME.to_string(), - version: live_protocol::PROTOCOL_VERSION, - } -} - -fn generated_ext_frame() -> ProtocolFrame { - ProtocolFrame::RequestFrame(RequestFrame { - schema: protocol_schema(), - request_id: 11, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: "conn-1".to_string(), - }), - payload: RequestPayload::ExtEnvelope(ExtEnvelope { - namespace: "dev.rivet.secure-exec.test".to_string(), - payload: b"extension-bytes".to_vec(), - }), - }) -} - -fn generated_vm_ownership() -> OwnershipScope { - OwnershipScope::VmOwnership(VmOwnership { - connection_id: "conn-1".to_string(), - session_id: "session-1".to_string(), - vm_id: "vm-1".to_string(), - }) -} - -fn live_frame_payload(frame: &[u8]) -> Vec { - frame[4..].to_vec() -} - -fn framed_payload(payload: &[u8]) -> Vec { - let mut frame = Vec::with_capacity(4 + payload.len()); - frame.extend_from_slice(&(payload.len() as u32).to_be_bytes()); - frame.extend_from_slice(payload); - frame -} - -fn hex_nibble(byte: u8) -> u8 { - match byte { - b'0'..=b'9' => byte - b'0', - b'a'..=b'f' => byte - b'a' + 10, - b'A'..=b'F' => byte - b'A' + 10, - _ => panic!("invalid hex byte {byte}"), - } -} diff --git a/crates/sidecar/tests/google_drive.rs b/crates/sidecar/tests/google_drive.rs deleted file mode 100644 index 6e1c37aa7..000000000 --- a/crates/sidecar/tests/google_drive.rs +++ /dev/null @@ -1,510 +0,0 @@ -#[allow(dead_code)] -mod google_drive { - include!("../src/plugins/google_drive.rs"); - - mod tests { - use super::test_support::MockGoogleDriveServer; - use super::*; - - const TEST_PRIVATE_KEY: &str = "-----BEGIN RSA PRIVATE KEY-----\n\ -MIIEpAIBAAKCAQEAyRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTL\n\ -UTv4l4sggh5/CYYi/cvI+SXVT9kPWSKXxJXBXd/4LkvcPuUakBoAkfh+eiFVMh2V\n\ -rUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8H\n\ -oGfG/AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBI\n\ -Mc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi+yUod+j8MtvIj812dkS4QMiRVN/\n\ -by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQIDAQABAoIBAHREk0I0O9DvECKd\n\ -WUpAmF3mY7oY9PNQiu44Yaf+AoSuyRpRUGTMIgc3u3eivOE8ALX0BmYUO5JtuRNZ\n\ -Dpvt4SAwqCnVUinIf6C+eH/wSurCpapSM0BAHp4aOA7igptyOMgMPYBHNA1e9A7j\n\ -E0dCxKWMl3DSWNyjQTk4zeRGEAEfbNjHrq6YCtjHSZSLmWiG80hnfnYos9hOr5Jn\n\ -LnyS7ZmFE/5P3XVrxLc/tQ5zum0R4cbrgzHiQP5RgfxGJaEi7XcgherCCOgurJSS\n\ -bYH29Gz8u5fFbS+Yg8s+OiCss3cs1rSgJ9/eHZuzGEdUZVARH6hVMjSuwvqVTFaE\n\ -8AgtleECgYEA+uLMn4kNqHlJS2A5uAnCkj90ZxEtNm3E8hAxUrhssktY5XSOAPBl\n\ -xyf5RuRGIImGtUVIr4HuJSa5TX48n3Vdt9MYCprO/iYl6moNRSPt5qowIIOJmIjY\n\ -2mqPDfDt/zw+fcDD3lmCJrFlzcnh0uea1CohxEbQnL3cypeLt+WbU6kCgYEAzSp1\n\ -9m1ajieFkqgoB0YTpt/OroDx38vvI5unInJlEeOjQ+oIAQdN2wpxBvTrRorMU6P0\n\ -7mFUbt1j+Co6CbNiw+X8HcCaqYLR5clbJOOWNR36PuzOpQLkfK8woupBxzW9B8gZ\n\ -mY8rB1mbJ+/WTPrEJy6YGmIEBkWylQ2VpW8O4O0CgYEApdbvvfFBlwD9YxbrcGz7\n\ -MeNCFbMz+MucqQntIKoKJ91ImPxvtc0y6e/Rhnv0oyNlaUOwJVu0yNgNG117w0g4\n\ -t/+Q38mvVC5xV7/cn7x9UMFk6MkqVir3dYGEqIl/OP1grY2Tq9HtB5iyG9L8NIam\n\ -QOLMyUqqMUILxdthHyFmiGkCgYEAn9+PjpjGMPHxL0gj8Q8VbzsFtou6b1deIRRA\n\ -2CHmSltltR1gYVTMwXxQeUhPMmgkMqUXzs4/WijgpthY44hK1TaZEKIuoxrS70nJ\n\ -4WQLf5a9k1065fDsFZD6yGjdGxvwEmlGMZgTwqV7t1I4X0Ilqhav5hcs5apYL7gn\n\ -PYPeRz0CgYALHCj/Ji8XSsDoF/MhVhnGdIs2P99NNdmo3R2Pv0CuZbDKMU559LJH\n\ -UvrKS8WkuWRDuKrz1W/EQKApFjDGpdqToZqriUFQzwy7mR3ayIiogzNtHcvbDHx8\n\ -oFnGY0OFksX/ye0/XGpy2SFxYRwGU98HPYeBvAQQrVjdkzfy7BmXQQ==\n\ ------END RSA PRIVATE KEY-----"; - - fn test_config(server: &MockGoogleDriveServer, prefix: &str) -> GoogleDriveMountConfig { - GoogleDriveMountConfig { - credentials: GoogleDriveMountCredentials { - client_email: String::from("test-service-account@example.com"), - private_key: String::from(TEST_PRIVATE_KEY), - }, - folder_id: String::from("folder-123"), - key_prefix: Some(String::from(prefix)), - chunk_size: Some(8), - inline_threshold: Some(4), - token_url: Some(format!("{}/token", server.base_url())), - api_base_url: Some(String::from(server.base_url())), - } - } - - #[test] - fn google_drive_url_drops_host_allowlist_but_keeps_credential_guards() { - // tokenUrl/apiBaseUrl are trusted mount config, so the strict host - // allowlist (SSRF hardening over trusted input) is gone: an arbitrary - // https host is now accepted. - validate_google_drive_url("https://drive.example.com", "apiBaseUrl", false) - .expect("arbitrary https host should now be accepted"); - - // The credential-leak guards stay, because these endpoints carry the - // OAuth bearer token and signed JWT assertion: http and embedded - // credentials are still rejected. - let http = validate_google_drive_url("http://oauth2.googleapis.com", "tokenUrl", true) - .expect_err("http tokenUrl should be rejected"); - assert!( - http.to_string().contains("tokenUrl must use https"), - "unexpected error: {http}" - ); - - let creds = validate_google_drive_url( - "https://user:pass@oauth2.googleapis.com", - "tokenUrl", - true, - ) - .expect_err("tokenUrl with embedded credentials should be rejected"); - assert!( - creds - .to_string() - .contains("must not include user credentials"), - "unexpected error: {creds}" - ); - } - - #[test] - fn google_drive_query_literals_escape_backslashes_before_quotes() { - assert_eq!(escape_query_literal(r#"plain-text"#), r#"plain-text"#); - assert_eq!( - escape_query_literal(r#"with\backslash"#), - r#"with\\backslash"# - ); - assert_eq!(escape_query_literal("with'quote"), "with\\'quote"); - assert_eq!( - escape_query_literal(r#"path\with'quote"#), - r#"path\\with\'quote"# - ); - } - - fn manifest_metadata( - ino: u64, - mode: u32, - ) -> secure_exec_kernel::vfs::MemoryFileSystemSnapshotMetadata { - secure_exec_kernel::vfs::MemoryFileSystemSnapshotMetadata { - mode, - uid: 0, - gid: 0, - nlink: 1, - ino, - atime_ms: 0, - atime_nsec: 0, - mtime_ms: 0, - mtime_nsec: 0, - ctime_ms: 0, - ctime_nsec: 0, - birthtime_ms: 0, - } - } - - #[test] - fn google_drive_plugin_persists_files_across_reopen_and_preserves_links() { - let server = MockGoogleDriveServer::start(); - - let mut filesystem = - GoogleDriveBackedFilesystem::from_config(test_config(&server, "persist")) - .expect("open google drive fs"); - filesystem - .write_file("/workspace/original.txt", b"hello world".to_vec()) - .expect("write original"); - filesystem - .link("/workspace/original.txt", "/workspace/linked.txt") - .expect("link file"); - filesystem - .symlink("/workspace/original.txt", "/workspace/alias.txt") - .expect("symlink file"); - - let mut reopened = - GoogleDriveBackedFilesystem::from_config(test_config(&server, "persist")) - .expect("reopen google drive fs"); - - assert_eq!( - reopened - .read_file("/workspace/original.txt") - .expect("read reopened original"), - b"hello world".to_vec() - ); - assert_eq!( - reopened - .read_file("/workspace/linked.txt") - .expect("read reopened hard link"), - b"hello world".to_vec() - ); - assert_eq!( - reopened - .read_file("/workspace/alias.txt") - .expect("read reopened symlink"), - b"hello world".to_vec() - ); - assert_eq!( - reopened - .stat("/workspace/original.txt") - .expect("stat reopened file") - .nlink, - 2 - ); - - let chunk_files = server - .file_names() - .into_iter() - .filter(|name| name.contains("/blocks/")) - .collect::>(); - assert!( - chunk_files.len() >= 2, - "expected chunked storage to create multiple google drive block files" - ); - assert!( - server - .requests() - .iter() - .any(|request| request.method == "POST" && request.path == "/token"), - "expected oauth token requests during google drive persistence" - ); - } - - #[test] - fn google_drive_plugin_cleans_up_stale_chunk_objects_after_truncate() { - let server = MockGoogleDriveServer::start(); - - let mut filesystem = - GoogleDriveBackedFilesystem::from_config(test_config(&server, "truncate")) - .expect("open google drive fs"); - filesystem - .write_file("/large.txt", b"abcdefghijk".to_vec()) - .expect("write large file"); - - let before = server - .file_names() - .into_iter() - .filter(|name| name.contains("/blocks/")) - .collect::>(); - assert!( - before.len() >= 2, - "expected multiple google drive blocks before truncation" - ); - - filesystem - .truncate("/large.txt", 1) - .expect("truncate to inline size"); - - let after = server - .file_names() - .into_iter() - .filter(|name| name.contains("/blocks/")) - .collect::>(); - assert!( - after.is_empty(), - "truncate should remove stale google drive block files" - ); - - let mut reopened = - GoogleDriveBackedFilesystem::from_config(test_config(&server, "truncate")) - .expect("reopen truncated fs"); - assert_eq!( - reopened - .read_file("/large.txt") - .expect("read truncated file"), - b"a".to_vec() - ); - } - - #[test] - fn google_drive_plugin_rejects_oversized_manifest_entries() { - let server = MockGoogleDriveServer::start(); - let manifest = PersistedFilesystemManifest { - format: String::from(MANIFEST_FORMAT), - path_index: BTreeMap::from([ - (String::from("/"), 1), - (String::from("/huge.bin"), 2), - ]), - inodes: BTreeMap::from([ - ( - 1, - PersistedFilesystemInode { - metadata: secure_exec_kernel::vfs::MemoryFileSystemSnapshotMetadata { - mode: 0o040755, - uid: 0, - gid: 0, - nlink: 1, - ino: 1, - atime_ms: 0, - atime_nsec: 0, - mtime_ms: 0, - mtime_nsec: 0, - ctime_ms: 0, - ctime_nsec: 0, - birthtime_ms: 0, - }, - kind: PersistedFilesystemInodeKind::Directory, - }, - ), - ( - 2, - PersistedFilesystemInode { - metadata: secure_exec_kernel::vfs::MemoryFileSystemSnapshotMetadata { - mode: 0o100644, - uid: 0, - gid: 0, - nlink: 1, - ino: 2, - atime_ms: 0, - atime_nsec: 0, - mtime_ms: 0, - mtime_nsec: 0, - ctime_ms: 0, - ctime_nsec: 0, - birthtime_ms: 0, - }, - kind: PersistedFilesystemInodeKind::File { - storage: PersistedFileStorage::Chunked { - size: u64::MAX, - chunks: Vec::new(), - }, - }, - }, - ), - ]), - next_ino: 3, - }; - server.insert_file( - "oversized/filesystem-manifest.json", - "folder-123", - serde_json::to_vec(&manifest).expect("serialize malicious manifest"), - ); - - let error = - match GoogleDriveBackedFilesystem::from_config(test_config(&server, "oversized")) { - Ok(_) => panic!("oversized manifest should be rejected"), - Err(error) => error, - }; - assert_eq!(error.code(), "EINVAL"); - assert!( - error.message().contains("limit"), - "unexpected error message: {}", - error.message() - ); - } - - #[test] - fn google_drive_plugin_accepts_legacy_agentos_manifest_format() { - let server = MockGoogleDriveServer::start(); - let manifest = PersistedFilesystemManifest { - format: String::from(LEGACY_AGENTOS_MANIFEST_FORMAT), - path_index: BTreeMap::from([ - (String::from("/"), 1), - (String::from("/legacy.txt"), 2), - ]), - inodes: BTreeMap::from([ - ( - 1, - PersistedFilesystemInode { - metadata: manifest_metadata(1, 0o040755), - kind: PersistedFilesystemInodeKind::Directory, - }, - ), - ( - 2, - PersistedFilesystemInode { - metadata: manifest_metadata(2, 0o100644), - kind: PersistedFilesystemInodeKind::File { - storage: PersistedFileStorage::Inline { - data_base64: BASE64.encode(b"legacy"), - }, - }, - }, - ), - ]), - next_ino: 3, - }; - server.insert_file( - "legacy/filesystem-manifest.json", - "folder-123", - serde_json::to_vec(&manifest).expect("serialize legacy manifest"), - ); - - let mut filesystem = - GoogleDriveBackedFilesystem::from_config(test_config(&server, "legacy")) - .expect("legacy google drive manifest should load"); - assert_eq!( - filesystem - .read_file("/legacy.txt") - .expect("read legacy manifest file"), - b"legacy".to_vec() - ); - } - - #[test] - fn google_drive_manifest_rejects_oversized_inline_estimates() { - validate_inline_manifest_data_size_with_limit("AAAAAA==", "google drive", 6, 4) - .expect("padded inline data at the limit should be accepted"); - - let error = - validate_inline_manifest_data_size_with_limit("AAAAAAAAAAAA", "google drive", 7, 8) - .expect_err("inline data estimate should be bounded"); - - assert_eq!(error.code(), "EINVAL"); - assert!( - error.message().contains("inline data may decode"), - "unexpected error message: {}", - error.message() - ); - } - - #[test] - fn google_drive_persist_rejects_manifest_bytes_above_reader_limit() { - validate_persisted_manifest_size(8, 8) - .expect("manifest at reader limit should be accepted"); - - let error = validate_persisted_manifest_size(9, 8) - .expect_err("persist should reject unreadable manifest size"); - - assert!( - error - .to_string() - .contains("google drive manifest is 9 bytes, limit is 8"), - "unexpected error: {error}" - ); - } - - #[test] - fn google_drive_manifest_rejects_chunks_larger_than_declared_size() { - let server = MockGoogleDriveServer::start(); - let manifest = PersistedFilesystemManifest { - format: String::from(MANIFEST_FORMAT), - path_index: BTreeMap::from([ - (String::from("/"), 1), - (String::from("/small.bin"), 2), - ]), - inodes: BTreeMap::from([ - ( - 1, - PersistedFilesystemInode { - metadata: manifest_metadata(1, 0o040755), - kind: PersistedFilesystemInodeKind::Directory, - }, - ), - ( - 2, - PersistedFilesystemInode { - metadata: manifest_metadata(2, 0o100644), - kind: PersistedFilesystemInodeKind::File { - storage: PersistedFileStorage::Chunked { - size: 5, - chunks: vec![PersistedChunkRef { - index: 0, - key: String::from("chunk-overflow/blocks/2/0"), - }], - }, - }, - }, - ), - ]), - next_ino: 3, - }; - server.insert_file( - "chunk-overflow/filesystem-manifest.json", - "folder-123", - serde_json::to_vec(&manifest).expect("serialize malicious manifest"), - ); - server.insert_file( - "chunk-overflow/blocks/2/0", - "folder-123", - b"123456".to_vec(), - ); - - let error = match GoogleDriveBackedFilesystem::from_config(test_config( - &server, - "chunk-overflow", - )) { - Ok(_) => panic!("oversized chunk payload should be rejected"), - Err(error) => error, - }; - assert_eq!(error.code(), "EIO"); - assert!( - error.message().contains("exceeded 5 byte limit"), - "unexpected error message: {}", - error.message() - ); - } - - #[test] - fn google_drive_manifest_rejects_chunk_keys_outside_mount_prefix() { - let server = MockGoogleDriveServer::start(); - let manifest = PersistedFilesystemManifest { - format: String::from(MANIFEST_FORMAT), - path_index: BTreeMap::from([ - (String::from("/"), 1), - (String::from("/escaped.bin"), 2), - ]), - inodes: BTreeMap::from([ - ( - 1, - PersistedFilesystemInode { - metadata: manifest_metadata(1, 0o040755), - kind: PersistedFilesystemInodeKind::Directory, - }, - ), - ( - 2, - PersistedFilesystemInode { - metadata: manifest_metadata(2, 0o100644), - kind: PersistedFilesystemInodeKind::File { - storage: PersistedFileStorage::Chunked { - size: 4, - chunks: vec![PersistedChunkRef { - index: 0, - key: String::from("outside-prefix/blocks/2/0"), - }], - }, - }, - }, - ), - ]), - next_ino: 3, - }; - server.insert_file( - "safe-prefix/filesystem-manifest.json", - "folder-123", - serde_json::to_vec(&manifest).expect("serialize escaped manifest"), - ); - server.insert_file("outside-prefix/blocks/2/0", "folder-123", b"evil".to_vec()); - - let error = - match GoogleDriveBackedFilesystem::from_config(test_config(&server, "safe-prefix")) - { - Ok(_) => panic!("escaped chunk key should be rejected"), - Err(error) => error, - }; - assert_eq!(error.code(), "EINVAL"); - assert!( - error.message().contains("outside mount prefix"), - "unexpected error message: {}", - error.message() - ); - assert!( - server - .file_names() - .contains(&String::from("outside-prefix/blocks/2/0")), - "escaped chunk object should not be deleted as a stale safe-prefix chunk" - ); - } - } -} diff --git a/crates/sidecar/tests/guest_identity.rs b/crates/sidecar/tests/guest_identity.rs deleted file mode 100644 index dfdc1eec6..000000000 --- a/crates/sidecar/tests/guest_identity.rs +++ /dev/null @@ -1,587 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - CreateVmRequest, GuestRuntimeKind, RequestId, RequestPayload, ResponsePayload, - RootFilesystemDescriptor, RootFilesystemEntry, RootFilesystemEntryEncoding, - RootFilesystemEntryKind, RootFilesystemMode, -}; -use serde_json::Value; -use std::collections::{BTreeMap, BTreeSet, HashMap}; -use std::fs; -use std::process::Command; -use std::time::Duration; -use support::{ - assert_node_available, authenticate_wire, collect_process_output_wire_with_timeout, - create_vm_wire, dispose_vm_and_close_session, execute_wire, new_sidecar, open_session_wire, - temp_dir, wire_permissions_allow_all, wire_request, wire_session, -}; - -const DEFAULT_GUEST_PATH_ENV: &str = - "/usr/local/sbin:/usr/local/bin:/opt/agentos/bin:/usr/sbin:/usr/bin:/sbin:/bin"; -const GUEST_IDENTITY_CASES: &[&str] = &["javascript", "python", "wasm_identity", "wasm_env"]; - -fn create_vm_with_root_filesystem( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - runtime: GuestRuntimeKind, - cwd: &std::path::Path, - root_filesystem: RootFilesystemDescriptor, -) -> String { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_session(connection_id, session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - runtime, - HashMap::from([(String::from("cwd"), cwd.to_string_lossy().into_owned())]), - root_filesystem, - Some(wire_permissions_allow_all()), - )), - )) - .expect("create sidecar VM"); - - match result.response.payload { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("unexpected vm create response: {other:?}"), - } -} - -fn parse_json_stdout(stdout: &str) -> Value { - serde_json::from_str(stdout.trim()).expect("parse JSON stdout") -} - -fn parse_env_stdout(stdout: &str) -> BTreeMap { - stdout - .lines() - .filter_map(|line| line.split_once('=')) - .map(|(key, value)| (key.to_owned(), value.to_owned())) - .collect() -} - -fn javascript_guest_identity_uses_kernel_owned_defaults() { - let mut sidecar = new_sidecar("guest-identity-js"); - let cwd = temp_dir("guest-identity-js-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-guest-identity-js"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let entrypoint = cwd.join("identity.mjs"); - fs::write( - &entrypoint, - r#" -import os from "node:os"; - -console.log(JSON.stringify({ - envUser: process.env.USER ?? null, - envHome: process.env.HOME ?? null, - envPwd: process.env.PWD ?? null, - envShell: process.env.SHELL ?? null, - envPath: process.env.PATH ?? null, - internalKeys: Object.keys(process.env).filter((key) => - key.startsWith("AGENTOS_") || key.startsWith("NODE_SYNC_RPC_") - ), - uid: process.getuid(), - gid: process.getgid(), - euid: process.geteuid(), - egid: process.getegid(), - groups: process.getgroups(), - homedir: os.homedir(), - userInfo: os.userInfo(), - cwd: process.cwd(), -})); -"#, - ) - .expect("write JavaScript identity fixture"); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-js-identity", - GuestRuntimeKind::JavaScript, - &entrypoint, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_guest_identity_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-js-identity", - ); - dispose_vm_and_close_session(&mut sidecar, &connection_id, &session_id, &vm_id); - assert_eq!(exit_code, 0, "stderr:\n{stderr}"); - assert!( - stderr.is_empty(), - "unexpected stderr from JavaScript identity execution: {stderr}" - ); - - let parsed = parse_json_stdout(&stdout); - assert_eq!(parsed["envUser"], "agentos"); - assert_eq!(parsed["envHome"], "/home/agentos"); - assert_eq!(parsed["envPwd"], "/"); - assert_eq!(parsed["envShell"], "/bin/sh"); - assert_eq!(parsed["envPath"], DEFAULT_GUEST_PATH_ENV); - assert_eq!(parsed["internalKeys"], Value::Array(Vec::new())); - assert_eq!(parsed["uid"], 1000); - assert_eq!(parsed["gid"], 1000); - assert_eq!(parsed["euid"], 1000); - assert_eq!(parsed["egid"], 1000); - assert_eq!(parsed["groups"], Value::Array(vec![Value::from(1000)])); - assert_eq!(parsed["homedir"], "/home/agentos"); - assert_eq!(parsed["cwd"], "/"); - assert_eq!(parsed["userInfo"]["username"], "agentos"); - assert_eq!(parsed["userInfo"]["uid"], 1000); - assert_eq!(parsed["userInfo"]["gid"], 1000); - assert_eq!(parsed["userInfo"]["shell"], "/bin/sh"); - assert_eq!(parsed["userInfo"]["homedir"], "/home/agentos"); -} - -fn python_guest_identity_uses_kernel_owned_defaults() { - assert_node_available(); - - let mut sidecar = new_sidecar("guest-identity-python"); - let cwd = temp_dir("guest-identity-python-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-guest-identity-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_root_filesystem( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: vec![ - RootFilesystemEntry { - path: String::from("/workspace"), - kind: RootFilesystemEntryKind::Directory, - mode: None, - uid: None, - gid: None, - content: None, - encoding: None, - target: None, - executable: false, - }, - RootFilesystemEntry { - path: String::from("/workspace/identity.py"), - kind: RootFilesystemEntryKind::File, - mode: None, - uid: None, - gid: None, - content: Some(String::from( - r#" -import json -import os -from pathlib import Path - -print(json.dumps({ - "env_user": os.environ.get("USER"), - "env_home": os.environ.get("HOME"), - "env_pwd": os.environ.get("PWD"), - "env_shell": os.environ.get("SHELL"), - "env_path": os.environ.get("PATH"), - "internal_keys": sorted([ - key for key in os.environ - if key.startswith("AGENTOS_") or key.startswith("NODE_SYNC_RPC_") - ]), - "path_home": str(Path.home()), -})) -"#, - )), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - target: None, - executable: false, - }, - ], - }, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-identity", - GuestRuntimeKind::Python, - std::path::Path::new("/workspace/identity.py"), - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_guest_identity_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-identity", - ); - dispose_vm_and_close_session(&mut sidecar, &connection_id, &session_id, &vm_id); - assert_eq!(exit_code, 0, "stderr:\n{stderr}"); - assert!( - stderr.is_empty(), - "unexpected stderr from Python identity execution: {stderr}" - ); - - let parsed = parse_json_stdout(&stdout); - assert_eq!(parsed["env_user"], "agentos"); - assert_eq!(parsed["env_home"], "/home/agentos"); - assert_eq!(parsed["env_pwd"], "/"); - assert_eq!(parsed["env_shell"], "/bin/sh"); - assert_eq!(parsed["env_path"], DEFAULT_GUEST_PATH_ENV); - assert_eq!(parsed["internal_keys"], Value::Array(Vec::new())); - assert_eq!(parsed["path_home"], "/home/agentos"); -} - -fn wasm_guest_identity_commands_use_kernel_owned_defaults() { - assert_node_available(); - - let mut sidecar = new_sidecar("guest-identity-wasm"); - let cwd = temp_dir("guest-identity-wasm-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-guest-identity-wasm"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::WebAssembly, - &cwd, - ); - - let wasm_path = cwd.join("identity.wasm"); - fs::write( - &wasm_path, - wat::parse_str( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (type $getid_t (func (param i32) (result i32))) - (type $getpwuid_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (import "host_user" "getuid" (func $getuid (type $getid_t))) - (import "host_user" "getgid" (func $getgid (type $getid_t))) - (import "host_user" "getpwuid" (func $getpwuid (type $getpwuid_t))) - (memory (export "memory") 1) - (func $assert_zero (param $errno i32) - local.get $errno - i32.eqz - if - else - unreachable - end) - (func $assert_value (param $value i32) (param $expected i32) - local.get $value - local.get $expected - i32.eq - if - else - unreachable - end) - (func $write_stdout (param $ptr i32) (param $len i32) - i32.const 16 - local.get $ptr - i32.store - i32.const 20 - local.get $len - i32.store - i32.const 1 - i32.const 16 - i32.const 1 - i32.const 24 - call $fd_write - call $assert_zero) - (func $_start (export "_start") - i32.const 0 - call $getuid - call $assert_zero - i32.const 0 - i32.load - i32.const 1000 - call $assert_value - - i32.const 4 - call $getgid - call $assert_zero - i32.const 4 - i32.load - i32.const 1000 - call $assert_value - - i32.const 0 - i32.load - i32.const 128 - i32.const 256 - i32.const 8 - call $getpwuid - call $assert_zero - - i32.const 128 - i32.const 8 - i32.load - call $write_stdout - )) -"#, - ) - .expect("compile wasm identity fixture"), - ) - .expect("write wasm identity fixture"); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-wasm-identity", - GuestRuntimeKind::WebAssembly, - &wasm_path, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_guest_identity_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-wasm-identity", - ); - dispose_vm_and_close_session(&mut sidecar, &connection_id, &session_id, &vm_id); - assert_eq!(exit_code, 0, "stderr:\n{stderr}"); - assert!( - stderr.is_empty(), - "unexpected stderr from wasm identity execution: {stderr}" - ); - assert_eq!(stdout, "agentos:x:1000:1000::/home/agentos:/bin/sh"); -} - -fn wasm_guest_env_filters_internal_control_vars_and_uses_kernel_defaults() { - assert_node_available(); - - let mut sidecar = new_sidecar("guest-env-wasm"); - let cwd = temp_dir("guest-env-wasm-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-guest-env-wasm"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::WebAssembly, - &cwd, - ); - - let wasm_path = cwd.join("env.wasm"); - fs::write( - &wasm_path, - wat::parse_str( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (type $environ_sizes_get_t (func (param i32 i32) (result i32))) - (type $environ_get_t (func (param i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (import "wasi_snapshot_preview1" "environ_sizes_get" (func $environ_sizes_get (type $environ_sizes_get_t))) - (import "wasi_snapshot_preview1" "environ_get" (func $environ_get (type $environ_get_t))) - (memory (export "memory") 1) - (data (i32.const 16) "\n") - (func $assert_zero (param $errno i32) - local.get $errno - i32.eqz - if - else - unreachable - end) - (func $strlen (param $ptr i32) (result i32) - (local $len i32) - (loop $loop - local.get $ptr - local.get $len - i32.add - i32.load8_u - i32.eqz - if - local.get $len - return - end - local.get $len - i32.const 1 - i32.add - local.set $len - br $loop) - i32.const 0) - (func $write_buffer (param $ptr i32) (param $len i32) - i32.const 0 - local.get $ptr - i32.store - i32.const 4 - local.get $len - i32.store - i32.const 1 - i32.const 0 - i32.const 1 - i32.const 8 - call $fd_write - call $assert_zero) - (func $_start (export "_start") - (local $count i32) - (local $index i32) - (local $ptr i32) - i32.const 256 - i32.const 260 - call $environ_sizes_get - call $assert_zero - i32.const 256 - i32.load - local.set $count - i32.const 512 - i32.const 1024 - call $environ_get - call $assert_zero - (loop $env_loop - local.get $index - local.get $count - i32.lt_u - if - i32.const 512 - local.get $index - i32.const 4 - i32.mul - i32.add - i32.load - local.set $ptr - local.get $ptr - local.get $ptr - call $strlen - call $write_buffer - i32.const 16 - i32.const 1 - call $write_buffer - local.get $index - i32.const 1 - i32.add - local.set $index - br $env_loop - end))) -"#, - ) - .expect("compile wasm env fixture"), - ) - .expect("write wasm env fixture"); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-wasm-env", - GuestRuntimeKind::WebAssembly, - &wasm_path, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_guest_identity_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-wasm-env", - ); - dispose_vm_and_close_session(&mut sidecar, &connection_id, &session_id, &vm_id); - assert_eq!(exit_code, 0, "stderr:\n{stderr}"); - assert!( - stderr.is_empty(), - "unexpected stderr from wasm env execution: {stderr}" - ); - - let env = parse_env_stdout(&stdout); - let leaked_internal = env - .keys() - .filter(|key| key.starts_with("AGENTOS_") || key.starts_with("NODE_SYNC_RPC_")) - .cloned() - .collect::>(); - - assert_eq!(env.get("HOME").map(String::as_str), Some("/home/agentos")); - assert_eq!(env.get("USER").map(String::as_str), Some("agentos")); - assert_eq!( - env.get("PATH").map(String::as_str), - Some(DEFAULT_GUEST_PATH_ENV) - ); - assert!( - leaked_internal.is_empty(), - "unexpected internal env leakage: {leaked_internal:?}" - ); -} - -fn run_named_case(case_name: &str) { - match case_name { - "javascript" => javascript_guest_identity_uses_kernel_owned_defaults(), - "python" => python_guest_identity_uses_kernel_owned_defaults(), - "wasm_identity" => wasm_guest_identity_commands_use_kernel_owned_defaults(), - "wasm_env" => wasm_guest_env_filters_internal_control_vars_and_uses_kernel_defaults(), - other => panic!("unknown guest_identity case: {other}"), - } -} - -fn collect_guest_identity_process_output( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) -> (String, String, i32) { - collect_process_output_wire_with_timeout( - sidecar, - connection_id, - session_id, - vm_id, - process_id, - Duration::from_secs(10), - ) -} - -#[test] -fn guest_identity_cases() { - let current_exe = std::env::current_exe().expect("current test binary path"); - - for case_name in GUEST_IDENTITY_CASES { - let status = Command::new(¤t_exe) - .arg("--exact") - .arg("__guest_identity_case_runner") - .arg("--nocapture") - .env("AGENTOS_GUEST_IDENTITY_CASE", case_name) - .status() - .unwrap_or_else(|error| panic!("spawn guest_identity runner for {case_name}: {error}")); - - assert!( - status.success(), - "guest_identity case {case_name} failed with status {status}" - ); - } -} - -#[test] -fn __guest_identity_case_runner() { - let Ok(case_name) = std::env::var("AGENTOS_GUEST_IDENTITY_CASE") else { - return; - }; - - run_named_case(&case_name); -} diff --git a/crates/sidecar/tests/host_dir.rs b/crates/sidecar/tests/host_dir.rs deleted file mode 100644 index 9061f558b..000000000 --- a/crates/sidecar/tests/host_dir.rs +++ /dev/null @@ -1,235 +0,0 @@ -// `host_dir.rs` is `include!`d below rather than linked from the crate, so its -// macOS-only `crate::macos_fs::…` references must resolve within this test -// binary too. Wire the same module in (macOS only; on Linux those references -// are `#[cfg]`d out and this module is unused). -#[cfg(target_os = "macos")] -#[path = "../src/macos_fs.rs"] -mod macos_fs; - -// The source is `include!`d wholesale but this test only exercises the -// filesystem-plugin subset, so items used elsewhere in the crate (e.g. the -// session-thread `SessionModuleReader`) are legitimately unused here. -#[allow(dead_code)] -mod host_dir { - include!("../src/plugins/host_dir.rs"); - - mod tests { - use super::{HostDirFilesystem, HostDirMountPlugin, MAX_HOST_DIR_READ_BYTES}; - use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, - }; - use secure_exec_kernel::mount_table::MountedFileSystem; - use secure_exec_kernel::vfs::VirtualFileSystem; - use serde_json::json; - use std::fs; - use std::os::unix::fs::{MetadataExt, PermissionsExt}; - use std::path::PathBuf; - use std::time::{SystemTime, UNIX_EPOCH}; - - fn temp_dir(prefix: &str) -> PathBuf { - let suffix = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic enough for temp paths") - .as_nanos(); - let path = std::env::temp_dir().join(format!("{prefix}-{suffix}")); - fs::create_dir_all(&path).expect("create temp dir"); - path - } - - #[test] - fn filesystem_rejects_symlink_escapes_and_round_trips_writes() { - let host_dir = temp_dir("secure-exec-host-dir-plugin"); - let outside_dir = temp_dir("secure-exec-host-dir-plugin-outside"); - fs::write(host_dir.join("hello.txt"), "hello from host").expect("seed host file"); - std::os::unix::fs::symlink(&outside_dir, host_dir.join("escape")) - .expect("seed escape symlink"); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - assert_eq!( - filesystem - .read_text_file("/hello.txt") - .expect("read host file"), - "hello from host" - ); - - filesystem - .write_file("/nested/out.txt", b"written from vm".to_vec()) - .expect("write through host dir fs"); - assert_eq!( - fs::read_to_string(host_dir.join("nested/out.txt")) - .expect("read written host file"), - "written from vm" - ); - - let error = filesystem - .read_file("/escape/hostname") - .expect_err("escape symlink should fail closed"); - assert_eq!(error.code(), "EACCES"); - assert!( - !outside_dir.join("hostname").exists(), - "read should not materialize files outside the host mount" - ); - - let error = filesystem - .write_file("/escape/owned.txt", b"owned".to_vec()) - .expect_err("escape symlink write should fail closed"); - assert_eq!(error.code(), "EACCES"); - assert!( - !outside_dir.join("owned.txt").exists(), - "write should not escape the mounted host directory" - ); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - fs::remove_dir_all(outside_dir).expect("remove outside temp dir"); - } - - #[test] - fn filesystem_pwrite_updates_in_place_and_zero_fills_gaps() { - let host_dir = temp_dir("secure-exec-host-dir-plugin-pwrite"); - fs::write(host_dir.join("data.txt"), b"abcdef").expect("seed host file"); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - filesystem - .pwrite("/data.txt", b"XYZ".to_vec(), 2) - .expect("overwrite bytes in place"); - filesystem - .pwrite("/data.txt", b"!".to_vec(), 8) - .expect("extend file with zero-filled hole"); - - assert_eq!( - fs::read(host_dir.join("data.txt")).expect("read written host file"), - b"abXYZf\0\0!".to_vec() - ); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - #[test] - fn filesystem_pwrite_rejects_symlink_escape_targets() { - let host_dir = temp_dir("secure-exec-host-dir-plugin-pwrite-escape"); - let outside_dir = temp_dir("secure-exec-host-dir-plugin-pwrite-escape-outside"); - fs::write(outside_dir.join("outside.txt"), b"outside").expect("seed outside file"); - std::os::unix::fs::symlink(&outside_dir, host_dir.join("escape")) - .expect("seed escape symlink"); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - let error = filesystem - .pwrite("/escape/outside.txt", b"owned".to_vec(), 0) - .expect_err("pwrite should reject symlink escapes"); - assert_eq!(error.code(), "EACCES"); - assert_eq!( - fs::read(outside_dir.join("outside.txt")).expect("outside file should stay intact"), - b"outside".to_vec() - ); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - fs::remove_dir_all(outside_dir).expect("remove outside temp dir"); - } - - #[test] - fn filesystem_rejects_full_reads_above_host_dir_limit() { - let host_dir = temp_dir("secure-exec-host-dir-plugin-full-read-limit"); - let huge_file = fs::File::create(host_dir.join("huge.bin")).expect("create huge file"); - huge_file - .set_len(MAX_HOST_DIR_READ_BYTES as u64 + 1) - .expect("make sparse huge file"); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - let error = filesystem - .read_file("/huge.bin") - .expect_err("full read should reject oversized host file"); - assert_eq!(error.code(), "EINVAL"); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - #[test] - fn filesystem_pread_rejects_lengths_above_host_dir_limit() { - let host_dir = temp_dir("secure-exec-host-dir-plugin-pread-limit"); - fs::write(host_dir.join("small.txt"), b"small").expect("seed host file"); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - let error = filesystem - .pread("/small.txt", 0, MAX_HOST_DIR_READ_BYTES + 1) - .expect_err("pread should reject oversized allocation"); - assert_eq!(error.code(), "EINVAL"); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - #[test] - fn filesystem_metadata_ops_reject_symlink_targets() { - let host_dir = temp_dir("secure-exec-host-dir-plugin-metadata"); - let outside_dir = temp_dir("secure-exec-host-dir-plugin-metadata-outside"); - let outside_file = outside_dir.join("outside.txt"); - fs::write(&outside_file, b"outside").expect("seed outside file"); - std::os::unix::fs::symlink(&outside_file, host_dir.join("link")) - .expect("seed escape symlink"); - - let baseline = fs::metadata(&outside_file).expect("outside metadata before ops"); - let baseline_mode = baseline.permissions().mode() & 0o7777; - let baseline_uid = baseline.uid(); - let baseline_gid = baseline.gid(); - let baseline_atime_ns = baseline.atime_nsec(); - let baseline_mtime_ns = baseline.mtime_nsec(); - - let mut filesystem = HostDirFilesystem::new(&host_dir).expect("create host dir fs"); - - let chmod_error = filesystem - .chmod("/link", 0o777) - .expect_err("chmod should reject symlink targets"); - assert_eq!(chmod_error.code(), "EPERM"); - - let chown_error = filesystem - .chown("/link", baseline_uid, baseline_gid) - .expect_err("chown should reject symlink targets"); - assert_eq!(chown_error.code(), "EPERM"); - - let utimes_error = filesystem - .utimes("/link", 1_000, 2_000) - .expect_err("utimes should reject symlink targets"); - assert_eq!(utimes_error.code(), "EPERM"); - - let after = fs::metadata(&outside_file).expect("outside metadata after ops"); - assert_eq!(after.permissions().mode() & 0o7777, baseline_mode); - assert_eq!(after.uid(), baseline_uid); - assert_eq!(after.gid(), baseline_gid); - assert_eq!(after.atime_nsec(), baseline_atime_ns); - assert_eq!(after.mtime_nsec(), baseline_mtime_ns); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - fs::remove_dir_all(outside_dir).expect("remove outside temp dir"); - } - - #[test] - fn plugin_config_can_enforce_read_only_mounts() { - let host_dir = temp_dir("secure-exec-host-dir-plugin-readonly"); - fs::write(host_dir.join("hello.txt"), "hello from host").expect("seed host file"); - - let plugin = HostDirMountPlugin; - let mut mounted = plugin - .open(OpenFileSystemPluginRequest { - vm_id: "vm-1", - guest_path: "/workspace", - read_only: false, - config: &json!({ - "hostPath": host_dir, - "readOnly": true, - }), - context: &(), - }) - .expect("open host_dir plugin"); - - assert_eq!( - mounted.read_file("/hello.txt").expect("read host file"), - b"hello from host".to_vec() - ); - let error = mounted - .write_file("/blocked.txt", b"blocked".to_vec()) - .expect_err("readonly plugin config should reject writes"); - assert_eq!(error.code(), "EROFS"); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - } -} diff --git a/crates/sidecar/tests/kill_cleanup.rs b/crates/sidecar/tests/kill_cleanup.rs deleted file mode 100644 index 321ac93f2..000000000 --- a/crates/sidecar/tests/kill_cleanup.rs +++ /dev/null @@ -1,612 +0,0 @@ -mod support; - -use secure_exec_bridge::{LoadFilesystemStateRequest, PersistenceBridge}; -use secure_exec_sidecar::wire::{ - DisposeReason, DisposeVmRequest, EventPayload, GuestRuntimeKind, KillProcessRequest, - OpenSessionRequest, RequestPayload, ResponsePayload, SidecarPlacement, SidecarPlacementShared, - StreamChannel, -}; -use std::collections::HashMap; -use std::time::{Duration, Instant}; -use support::{ - assert_node_available, authenticate_wire, create_vm_wire, execute_wire, new_sidecar, - open_session_wire, temp_dir, wire_connection, wire_request, wire_session, wire_vm, - write_fixture, RecordingBridge, -}; - -const PROCESS_OUTPUT_BYTE_LIMIT: usize = 1024 * 1024; - -fn wait_for_process_exit( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) -> i32 { - let ownership = wire_vm(connection_id, session_id, vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - - loop { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll sidecar wire process exit"); - let Some(event) = event else { - assert!( - Instant::now() < deadline, - "timed out waiting for process exit" - ); - continue; - }; - - match event.payload { - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - return exited.exit_code; - } - _ => {} - } - } -} - -fn kill_process_terminates_running_guest_execution() { - assert_node_available(); - - let mut sidecar = new_sidecar("kill-process"); - let cwd = temp_dir("kill-process-cwd"); - let entry = cwd.join("hang.mjs"); - write_fixture(&entry, "setInterval(() => {}, 1000);\n"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-hang", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - let kill = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("proc-hang"), - signal: String::from("SIGTERM"), - }), - )) - .expect("kill guest process"); - - match kill.response.payload { - ResponsePayload::ProcessKilledResponse(response) => { - assert_eq!(response.process_id, "proc-hang"); - } - other => panic!("unexpected kill response: {other:?}"), - } - - let exit_code = wait_for_process_exit( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-hang", - ); - assert_ne!(exit_code, 0); - - let rerun = cwd.join("rerun.mjs"); - write_fixture(&rerun, "console.log('rerun-ok');\n"); - execute_wire( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-rerun", - GuestRuntimeKind::JavaScript, - &rerun, - Vec::new(), - ); - let (stdout, stderr, rerun_exit) = collect_kill_cleanup_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-rerun", - ); - assert_eq!(stdout, "rerun-ok\n"); - assert!(stderr.is_empty()); - assert_eq!(rerun_exit, 0); -} - -fn sigkill_synthesizes_exit_for_shared_v8_guest_execution() { - assert_node_available(); - - let mut sidecar = new_sidecar("kill-process-sigkill"); - let cwd = temp_dir("kill-process-sigkill-cwd"); - let entry = cwd.join("hang.mjs"); - write_fixture(&entry, "setInterval(() => {}, 1000);\n"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-sigkill", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - let kill = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("proc-sigkill"), - signal: String::from("SIGKILL"), - }), - )) - .expect("SIGKILL guest process"); - - match kill.response.payload { - ResponsePayload::ProcessKilledResponse(response) => { - assert_eq!(response.process_id, "proc-sigkill"); - } - other => panic!("unexpected kill response: {other:?}"), - } - - let exit_code = wait_for_process_exit( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-sigkill", - ); - assert_eq!(exit_code, 128 + 9); -} - -fn collect_kill_cleanup_process_output( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) -> (String, String, i32) { - let ownership = wire_session(connection_id, session_id); - let deadline = Instant::now() + Duration::from_secs(10); - let mut stdout = String::new(); - let mut stderr = String::new(); - let mut exit = None; - - loop { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll kill-cleanup wire process event"); - if let Some(event) = event { - assert_eq!(event.ownership, wire_vm(connection_id, session_id, vm_id)); - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == process_id => { - match output.channel { - StreamChannel::Stdout => append_process_output( - &mut stdout, - &output.chunk, - &output.process_id, - "stdout", - ), - StreamChannel::Stderr => append_process_output( - &mut stderr, - &output.chunk, - &output.process_id, - "stderr", - ), - } - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - exit = Some((exited.exit_code, Instant::now())); - } - EventPayload::ProcessOutputEvent(_) - | EventPayload::ProcessExitedEvent(_) - | EventPayload::VmLifecycleEvent(_) - | EventPayload::StructuredEvent(_) - | EventPayload::ExtEnvelope(_) => {} - } - } - - if let Some((exit_code, seen_at)) = exit { - if Instant::now().duration_since(seen_at) >= Duration::from_millis(200) { - return (stdout, stderr, exit_code); - } - } - - assert!( - Instant::now() < deadline, - "timed out waiting for kill-cleanup process {process_id}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - } -} - -fn append_process_output(buffer: &mut String, chunk: &[u8], process_id: &str, channel: &str) { - let text = String::from_utf8_lossy(chunk); - assert!( - buffer.len().saturating_add(text.len()) <= PROCESS_OUTPUT_BYTE_LIMIT, - "kill-cleanup process {process_id} exceeded {PROCESS_OUTPUT_BYTE_LIMIT} bytes on {channel}" - ); - buffer.push_str(&text); -} - -fn kill_process_terminates_running_wasm_execution() { - // Timeout-dependent: the infinite-loop wasm module's prewarm runs into the - // ~30s V8 CPU-time watchdog before the kill lands, so this case takes ~30s - // regardless. Gate it to the nightly timing lane (SECURE_EXEC_RUN_TIMING_TESTS=1) - // rather than pay 30s on every PR. See CLAUDE.md > Testing. - if std::env::var_os("SECURE_EXEC_RUN_TIMING_TESTS").is_none() { - return; - } - assert_node_available(); - - let mut sidecar = new_sidecar("kill-process-wasm"); - let cwd = temp_dir("kill-process-wasm-cwd"); - let entry = cwd.join("hang.wasm"); - write_fixture( - &entry, - wat::parse_str( - r#" -(module - (func $_start (export "_start") - (loop $loop - br $loop - ) - ) -) -"#, - ) - .expect("compile wasm hang fixture"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::WebAssembly, - &cwd, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-hang-wasm", - GuestRuntimeKind::WebAssembly, - &entry, - Vec::new(), - ); - - let kill = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("proc-hang-wasm"), - signal: String::from("SIGTERM"), - }), - )) - .expect("kill guest wasm process"); - - match kill.response.payload { - ResponsePayload::ProcessKilledResponse(response) => { - assert_eq!(response.process_id, "proc-hang-wasm"); - } - other => panic!("unexpected kill response: {other:?}"), - } - - let exit_code = wait_for_process_exit( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-hang-wasm", - ); - assert_ne!(exit_code, 0); -} - -fn dispose_vm_succeeds_even_when_a_guest_process_is_running() { - assert_node_available(); - - let mut sidecar = new_sidecar("dispose-vm-running-process"); - let cwd = temp_dir("dispose-vm-running-process-cwd"); - let entry = cwd.join("hang.mjs"); - write_fixture(&entry, "setInterval(() => {}, 1000);\n"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-hang", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - let dispose = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::DisposeVmRequest(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - )) - .expect("dispose vm with running process"); - - match dispose.response.payload { - ResponsePayload::VmDisposedResponse(response) => { - assert_eq!(response.vm_id, vm_id); - } - other => panic!("unexpected dispose response: {other:?}"), - } - assert!(dispose - .events - .iter() - .any(|event| matches!(event.payload, EventPayload::ProcessExitedEvent(_)))); - - let (_, replacement_vm) = create_vm_wire( - &mut sidecar, - 6, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - match replacement_vm.response.payload { - ResponsePayload::VmCreatedResponse(_) => {} - other => panic!("unexpected replacement vm response: {other:?}"), - } - - sidecar - .with_bridge_mut(|bridge: &mut RecordingBridge| { - let snapshot = bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: vm_id.clone(), - }) - .expect("load persisted snapshot"); - assert!( - snapshot.is_some(), - "disposed vm should flush a filesystem snapshot" - ); - }) - .expect("inspect persistence bridge"); -} - -fn close_session_removes_the_session_and_disposes_owned_vms() { - let mut sidecar = new_sidecar("close-session"); - let cwd = temp_dir("close-session-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let events = sidecar - .close_session_blocking(&connection_id, &session_id) - .expect("close owned session"); - assert!(events - .iter() - .any(|event| { format!("{:?}", event.payload).contains("Disposed") })); - - let create_after_close = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_session(&connection_id, &session_id), - RequestPayload::CreateVmRequest( - secure_exec_sidecar::wire::CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::from([(String::from("cwd"), cwd.to_string_lossy().into_owned())]), - secure_exec_sidecar::wire::RootFilesystemDescriptor { - mode: secure_exec_sidecar::wire::RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }, - None, - ), - ), - )) - .expect("dispatch closed-session create_vm"); - match create_after_close.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!(rejected.message.contains("unknown sidecar session")); - } - other => panic!("unexpected closed-session create_vm response: {other:?}"), - } - - let reopened = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_connection(&connection_id), - RequestPayload::OpenSessionRequest(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: None, - }), - metadata: HashMap::new(), - }), - )) - .expect("open replacement session"); - match reopened.response.payload { - ResponsePayload::SessionOpenedResponse(_) => {} - other => panic!("unexpected session reopen response: {other:?}"), - } - - sidecar - .with_bridge_mut(|bridge: &mut RecordingBridge| { - let snapshot = bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: vm_id.clone(), - }) - .expect("load persisted snapshot"); - assert!( - snapshot.is_some(), - "closing a session should dispose its VMs" - ); - }) - .expect("inspect persistence bridge"); -} - -fn remove_connection_disposes_owned_sessions_and_vms() { - let mut sidecar = new_sidecar("remove-connection"); - let cwd = temp_dir("remove-connection-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let events = sidecar - .remove_connection_blocking(&connection_id) - .expect("remove authenticated connection"); - assert!(events - .iter() - .any(|event| { format!("{:?}", event.payload).contains("Disposed") })); - - let reopened = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_connection(&connection_id), - RequestPayload::OpenSessionRequest(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: None, - }), - metadata: HashMap::new(), - }), - )) - .expect("attempt open session after connection removal"); - match reopened.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!(rejected.message.contains("has not authenticated")); - } - other => panic!("unexpected post-removal open-session response: {other:?}"), - } - - sidecar - .with_bridge_mut(|bridge: &mut RecordingBridge| { - let snapshot = bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: vm_id.clone(), - }) - .expect("load persisted snapshot"); - assert!( - snapshot.is_some(), - "removing a connection should dispose its VMs" - ); - }) - .expect("inspect persistence bridge"); -} - -#[test] -fn kill_cleanup_suite() { - // Multiple libtest cases in this V8-backed integration binary still trip - // teardown/init crashes, so keep the coverage in one top-level suite. - // - // cargo-nextest runs every `#[test]` in its OWN process, so that crash cannot - // occur there — `mod kill_cleanup_split` below exposes each case as a separate - // test that nextest runs in parallel across cores. Skip the collapsed run under - // nextest so the work isn't done twice; the split cases skip themselves under - // `cargo test`. nextest sets `NEXTEST=1` in each test process; libtest/`cargo - // test` does not. - if std::env::var_os("NEXTEST").is_some() { - return; - } - close_session_removes_the_session_and_disposes_owned_vms(); - dispose_vm_succeeds_even_when_a_guest_process_is_running(); - kill_process_terminates_running_guest_execution(); - sigkill_synthesizes_exit_for_shared_v8_guest_execution(); - kill_process_terminates_running_wasm_execution(); - remove_connection_disposes_owned_sessions_and_vms(); -} - -/// Per-case split of `kill_cleanup_suite` for cargo-nextest (process-per-test). -/// -/// Each `#[test]` here runs exactly one case in its own process, so the -/// shared-process V8 teardown/init crash that forces the collapsed -/// `kill_cleanup_suite` above does not apply, and the cases run in parallel across -/// cores instead of serially. Each case skips itself under plain `cargo test` -/// (where `NEXTEST` is unset) so the collapsed suite owns the run there; the -/// collapsed suite likewise skips under nextest so the work isn't duplicated. -mod kill_cleanup_split { - macro_rules! nextest_cases { - ($($case:ident),+ $(,)?) => { - $( - #[test] - fn $case() { - // Covered by the collapsed `super::kill_cleanup_suite` under `cargo test`. - if std::env::var_os("NEXTEST").is_none() { - return; - } - super::$case(); - } - )+ - }; - } - - nextest_cases!( - close_session_removes_the_session_and_disposes_owned_vms, - dispose_vm_succeeds_even_when_a_guest_process_is_running, - kill_process_terminates_running_guest_execution, - sigkill_synthesizes_exit_for_shared_v8_guest_execution, - kill_process_terminates_running_wasm_execution, - remove_connection_disposes_owned_sessions_and_vms, - ); -} diff --git a/crates/sidecar/tests/layer_management.rs b/crates/sidecar/tests/layer_management.rs deleted file mode 100644 index a8ce77626..000000000 --- a/crates/sidecar/tests/layer_management.rs +++ /dev/null @@ -1,723 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - ConfigureVmRequest, CreateOverlayRequest, CreateVmRequest, ExportSnapshotRequest, - GuestFilesystemCallRequest, GuestFilesystemOperation, GuestRuntimeKind, ImportSnapshotRequest, - RequestPayload, ResponsePayload, RootFilesystemDescriptor, RootFilesystemEntry, - RootFilesystemEntryKind, RootFilesystemLowerDescriptor, RootFilesystemMode, SealLayerRequest, - SnapshotRootFilesystemLower, -}; -use std::collections::HashMap; -use std::fs::{create_dir_all, write}; -use support::{ - authenticate_wire, create_vm_wire, new_sidecar, open_session_wire, temp_dir, - wire_permissions_allow_all, wire_request, wire_session, wire_vm, -}; - -const MAX_VM_LAYERS_UNDER_TEST: usize = 256; - -fn root_dir(path: impl Into) -> RootFilesystemEntry { - root_entry(path, RootFilesystemEntryKind::Directory, None) -} - -fn root_file(path: impl Into, content: impl Into) -> RootFilesystemEntry { - root_entry(path, RootFilesystemEntryKind::File, Some(content.into())) -} - -fn root_entry( - path: impl Into, - kind: RootFilesystemEntryKind, - content: Option, -) -> RootFilesystemEntry { - RootFilesystemEntry { - path: path.into(), - kind, - mode: None, - uid: None, - gid: None, - content, - encoding: None, - target: None, - executable: false, - } -} - -#[test] -fn vm_layer_lifecycle_round_trips_snapshots_and_invalidates_sealed_ids() { - let mut sidecar = new_sidecar("layer-lifecycle"); - let cwd = temp_dir("layer-lifecycle-cwd"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let imported_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ImportSnapshotRequest(ImportSnapshotRequest { - entries: vec![ - root_dir("/workspace"), - root_file("/workspace/note.txt", "imported"), - ], - }), - )) - .expect("import snapshot") - .response - .payload - { - ResponsePayload::SnapshotImportedResponse(response) => response.layer_id, - other => panic!("unexpected import snapshot response: {other:?}"), - }; - - let imported_entries = match sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: imported_layer_id.clone(), - }), - )) - .expect("export imported snapshot") - .response - .payload - { - ResponsePayload::SnapshotExportedResponse(response) => response.entries, - other => panic!("unexpected export snapshot response: {other:?}"), - }; - assert!(imported_entries.iter().any(|entry| { - entry.path == "/workspace/note.txt" && entry.content.as_deref() == Some("imported") - })); - - let writable_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 6, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::CreateLayerRequest, - )) - .expect("create writable layer") - .response - .payload - { - ResponsePayload::LayerCreatedResponse(response) => response.layer_id, - other => panic!("unexpected create layer response: {other:?}"), - }; - let sealed_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 7, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::SealLayerRequest(SealLayerRequest { - layer_id: writable_layer_id.clone(), - }), - )) - .expect("seal writable layer") - .response - .payload - { - ResponsePayload::LayerSealedResponse(response) => response.layer_id, - other => panic!("unexpected seal layer response: {other:?}"), - }; - assert_ne!(sealed_layer_id, writable_layer_id); - - let sealed_entries = match sidecar - .dispatch_wire_blocking(wire_request( - 8, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: sealed_layer_id, - }), - )) - .expect("export sealed layer") - .response - .payload - { - ResponsePayload::SnapshotExportedResponse(response) => response.entries, - other => panic!("unexpected export sealed snapshot response: {other:?}"), - }; - assert!(sealed_entries.iter().any(|entry| entry.path == "/")); - - let rejected = sidecar - .dispatch_wire_blocking(wire_request( - 9, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: writable_layer_id.clone(), - }), - )) - .expect("export sealed source layer should reject"); - match rejected.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!(response.message.contains("unknown layer")); - } - other => panic!("unexpected rejection response: {other:?}"), - } - - let rejected = sidecar - .dispatch_wire_blocking(wire_request( - 10, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::SealLayerRequest(SealLayerRequest { - layer_id: writable_layer_id, - }), - )) - .expect("double seal should reject"); - match rejected.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!(response.message.contains("unknown layer")); - } - other => panic!("unexpected rejection response: {other:?}"), - } -} - -#[test] -fn vm_layer_ids_are_reused_per_vm_without_cross_vm_leakage() { - let mut sidecar = new_sidecar("layer-store-isolation"); - let cwd = temp_dir("layer-store-isolation-cwd"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (first_vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - let (second_vm_id, _) = create_vm_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let first_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &first_vm_id), - RequestPayload::ImportSnapshotRequest(ImportSnapshotRequest { - entries: vec![ - root_dir("/workspace"), - root_file("/workspace/first.txt", "first-vm"), - ], - }), - )) - .expect("import snapshot into first vm") - .response - .payload - { - ResponsePayload::SnapshotImportedResponse(response) => response.layer_id, - other => panic!("unexpected first import response: {other:?}"), - }; - let second_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 6, - wire_vm(&connection_id, &session_id, &second_vm_id), - RequestPayload::ImportSnapshotRequest(ImportSnapshotRequest { - entries: vec![ - root_dir("/workspace"), - root_file("/workspace/second.txt", "second-vm"), - ], - }), - )) - .expect("import snapshot into second vm") - .response - .payload - { - ResponsePayload::SnapshotImportedResponse(response) => response.layer_id, - other => panic!("unexpected second import response: {other:?}"), - }; - - assert_eq!(first_layer_id, "layer-1"); - assert_eq!(second_layer_id, "layer-1"); - - let first_entries = match sidecar - .dispatch_wire_blocking(wire_request( - 7, - wire_vm(&connection_id, &session_id, &first_vm_id), - RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: first_layer_id, - }), - )) - .expect("export first vm snapshot") - .response - .payload - { - ResponsePayload::SnapshotExportedResponse(response) => response.entries, - other => panic!("unexpected first export response: {other:?}"), - }; - let second_entries = match sidecar - .dispatch_wire_blocking(wire_request( - 8, - wire_vm(&connection_id, &session_id, &second_vm_id), - RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: second_layer_id, - }), - )) - .expect("export second vm snapshot") - .response - .payload - { - ResponsePayload::SnapshotExportedResponse(response) => response.entries, - other => panic!("unexpected second export response: {other:?}"), - }; - - assert!(first_entries.iter().any(|entry| { - entry.path == "/workspace/first.txt" && entry.content.as_deref() == Some("first-vm") - })); - assert!(!first_entries - .iter() - .any(|entry| entry.path == "/workspace/second.txt")); - assert!(second_entries.iter().any(|entry| { - entry.path == "/workspace/second.txt" && entry.content.as_deref() == Some("second-vm") - })); - assert!(!second_entries - .iter() - .any(|entry| entry.path == "/workspace/first.txt")); -} - -#[test] -fn vm_layer_store_rejects_new_layers_at_limit() { - let mut sidecar = new_sidecar("layer-store-limit"); - let cwd = temp_dir("layer-store-limit-cwd"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let mut first_layer_id = String::new(); - for index in 0..MAX_VM_LAYERS_UNDER_TEST { - let layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 4 + index as i64, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ImportSnapshotRequest(ImportSnapshotRequest { - entries: vec![root_file( - format!("/layer-{index}.txt"), - format!("layer {index}"), - )], - }), - )) - .expect("import snapshot at layer limit") - .response - .payload - { - ResponsePayload::SnapshotImportedResponse(response) => response.layer_id, - other => panic!("unexpected import snapshot response: {other:?}"), - }; - if index == 0 { - first_layer_id = layer_id; - } - } - - for (offset, payload) in [ - ( - 0, - RequestPayload::ImportSnapshotRequest(ImportSnapshotRequest { - entries: vec![root_file("/overflow-import.txt", "overflow")], - }), - ), - (1, RequestPayload::CreateLayerRequest), - ( - 2, - RequestPayload::CreateOverlayRequest(CreateOverlayRequest { - mode: RootFilesystemMode::Ephemeral, - upper_layer_id: None, - lower_layer_ids: vec![first_layer_id.clone()], - }), - ), - ( - 3, - RequestPayload::CreateOverlayRequest(CreateOverlayRequest { - mode: RootFilesystemMode::Ephemeral, - upper_layer_id: None, - lower_layer_ids: vec![String::from("missing-layer")], - }), - ), - ] { - let rejected = sidecar - .dispatch_wire_blocking(wire_request( - 300 + offset, - wire_vm(&connection_id, &session_id, &vm_id), - payload, - )) - .expect("dispatch layer overflow request"); - match rejected.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!( - response.message.contains("VM layer limit exceeded"), - "unexpected rejection: {response:?}" - ); - } - other => panic!("expected layer limit rejection, got {other:?}"), - } - } - - let rejected = sidecar - .dispatch_wire_blocking(wire_request( - 400, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: String::from("layer-257"), - }), - )) - .expect("export overflow layer id should reject"); - match rejected.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!(response.message.contains("unknown layer")); - } - other => panic!("expected unknown overflow layer rejection, got {other:?}"), - } -} - -#[test] -fn create_vm_root_filesystem_composes_multiple_lowers_with_bootstrap_upper() { - let mut sidecar = new_sidecar("vm-root-multi-layer"); - let cwd = temp_dir("vm-root-multi-layer-cwd"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let create = sidecar - .dispatch_wire_blocking(wire_request( - 3, - wire_session(&connection_id, &session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::from([(String::from("cwd"), cwd.to_string_lossy().into_owned())]), - RootFilesystemDescriptor { - disable_default_base_layer: true, - lowers: vec![ - RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - SnapshotRootFilesystemLower { - entries: vec![ - root_dir("/workspace"), - root_file("/workspace/shared.txt", "higher"), - root_file("/workspace/higher-only.txt", "higher-only"), - ], - }, - ), - RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - SnapshotRootFilesystemLower { - entries: vec![ - root_dir("/workspace"), - root_file("/workspace/shared.txt", "lower"), - root_file("/workspace/lower-only.txt", "lower-only"), - ], - }, - ), - ], - bootstrap_entries: vec![ - root_dir("/workspace"), - root_file("/workspace/shared.txt", "upper"), - root_file("/workspace/upper-only.txt", "upper-only"), - ], - mode: RootFilesystemMode::Ephemeral, - }, - Some(wire_permissions_allow_all()), - )), - )) - .expect("create vm with multi-layer root"); - - let vm_id = match create.response.payload { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("unexpected create vm response: {other:?}"), - }; - - for (request_id, path, expected) in [ - (4, "/workspace/shared.txt", "upper"), - (5, "/workspace/higher-only.txt", "higher-only"), - (6, "/workspace/lower-only.txt", "lower-only"), - (7, "/workspace/upper-only.txt", "upper-only"), - ] { - let read = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from(path), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("read layered file"); - - match read.response.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.content.as_deref(), Some(expected)); - } - other => panic!("unexpected guest filesystem response: {other:?}"), - } - } -} - -#[test] -fn vm_layer_rpcs_and_module_access_mounts_are_scoped_per_vm() { - let mut sidecar = new_sidecar("layer-management"); - let cwd = temp_dir("layer-management-cwd"); - let module_access_cwd = temp_dir("layer-management-module-access"); - let package_root = module_access_cwd.join("node_modules/fixture-pkg"); - create_dir_all(&package_root).expect("create module access package root"); - write( - package_root.join("package.json"), - r#"{"name":"fixture-pkg","version":"1.0.0"}"#, - ) - .expect("write module access package json"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let configure = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: None, - module_access_cwd: Some(module_access_cwd.to_string_lossy().into_owned()), - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure vm"); - match configure.response.payload { - ResponsePayload::VmConfiguredResponse(response) => { - // 1 = just the module_access node_modules mount. With no packages - // configured there are no granular `/opt/agentos` leaf mounts (the - // projection adds a tar/bin/current mount per package, not a single - // always-present staging mount). - assert_eq!(response.applied_mounts, 1); - } - other => panic!("unexpected configure response: {other:?}"), - } - - let module_read = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/root/node_modules/fixture-pkg/package.json"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("read module access file"); - match module_read.response.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert!(response - .content - .expect("module access content") - .contains("\"fixture-pkg\"")); - } - other => panic!("unexpected module access response: {other:?}"), - } - - let writable_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 6, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::CreateLayerRequest, - )) - .expect("create layer") - .response - .payload - { - ResponsePayload::LayerCreatedResponse(response) => response.layer_id, - other => panic!("unexpected create layer response: {other:?}"), - }; - let sealed_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 7, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::SealLayerRequest(SealLayerRequest { - layer_id: writable_layer_id, - }), - )) - .expect("seal layer") - .response - .payload - { - ResponsePayload::LayerSealedResponse(response) => response.layer_id, - other => panic!("unexpected seal layer response: {other:?}"), - }; - let sealed_entries = match sidecar - .dispatch_wire_blocking(wire_request( - 8, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: sealed_layer_id, - }), - )) - .expect("export sealed layer") - .response - .payload - { - ResponsePayload::SnapshotExportedResponse(response) => response.entries, - other => panic!("unexpected export snapshot response: {other:?}"), - }; - assert!(sealed_entries.iter().any(|entry| entry.path == "/")); - - let lower_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 9, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ImportSnapshotRequest(ImportSnapshotRequest { - entries: vec![ - root_dir("/workspace"), - root_file("/workspace/lower.txt", "lower"), - root_file("/workspace/shared.txt", "lower"), - ], - }), - )) - .expect("import lower snapshot") - .response - .payload - { - ResponsePayload::SnapshotImportedResponse(response) => response.layer_id, - other => panic!("unexpected import snapshot response: {other:?}"), - }; - let upper_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 10, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ImportSnapshotRequest(ImportSnapshotRequest { - entries: vec![ - root_dir("/workspace"), - root_file("/workspace/upper.txt", "upper"), - root_file("/workspace/shared.txt", "upper"), - ], - }), - )) - .expect("import upper snapshot") - .response - .payload - { - ResponsePayload::SnapshotImportedResponse(response) => response.layer_id, - other => panic!("unexpected import snapshot response: {other:?}"), - }; - let overlay_layer_id = match sidecar - .dispatch_wire_blocking(wire_request( - 11, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::CreateOverlayRequest(CreateOverlayRequest { - mode: RootFilesystemMode::Ephemeral, - upper_layer_id: Some(upper_layer_id), - lower_layer_ids: vec![lower_layer_id], - }), - )) - .expect("create overlay") - .response - .payload - { - ResponsePayload::OverlayCreatedResponse(response) => response.layer_id, - other => panic!("unexpected create overlay response: {other:?}"), - }; - let overlay_entries = match sidecar - .dispatch_wire_blocking(wire_request( - 12, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: overlay_layer_id.clone(), - }), - )) - .expect("export overlay snapshot") - .response - .payload - { - ResponsePayload::SnapshotExportedResponse(response) => response.entries, - other => panic!("unexpected overlay export response: {other:?}"), - }; - assert!(overlay_entries - .iter() - .any(|entry| entry.path == "/workspace/lower.txt")); - assert!(overlay_entries - .iter() - .any(|entry| entry.path == "/workspace/upper.txt")); - assert!(overlay_entries - .iter() - .any(|entry| entry.path == "/workspace/shared.txt" - && entry.content.as_deref() == Some("upper"))); - - let (other_vm_id, _) = create_vm_wire( - &mut sidecar, - 13, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - let rejected = sidecar - .dispatch_wire_blocking(wire_request( - 14, - wire_vm(&connection_id, &session_id, &other_vm_id), - RequestPayload::ExportSnapshotRequest(ExportSnapshotRequest { - layer_id: overlay_layer_id, - }), - )) - .expect("export unknown layer should reject"); - match rejected.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!(response.message.contains("unknown layer")); - } - other => panic!("unexpected rejection response: {other:?}"), - } -} diff --git a/crates/sidecar/tests/limits.rs b/crates/sidecar/tests/limits.rs deleted file mode 100644 index 1fe9b6eb4..000000000 --- a/crates/sidecar/tests/limits.rs +++ /dev/null @@ -1,138 +0,0 @@ -//! Tests for typed create-VM limits config defaults, overrides, and validation. - -use secure_exec_sidecar::limits::{vm_limits_from_config, VmLimits}; -use secure_exec_vm_config::{ - HttpLimitsConfig, JsRuntimeLimitsConfig, PythonLimitsConfig, ResourceLimitsConfig, - ToolLimitsConfig, VmLimitsConfig, WasmLimitsConfig, -}; -use serde_json::json; - -// Must match the production sidecar wire frame cap (wire::DEFAULT_MAX_FRAME_BYTES), -// which is what vm_limits_from_config is called with at runtime (lib.rs/state.rs). -const SIDECAR_FRAME_CAP: usize = 16 * 1024 * 1024; - -#[test] -fn defaults_match_struct_default() { - let parsed = - vm_limits_from_config(None, SIDECAR_FRAME_CAP).expect("empty config parses to defaults"); - assert_eq!(parsed, VmLimits::default()); - assert_eq!( - parsed.js_runtime.v8_heap_limit_mb, - Some(128), - "JavaScript heap must be bounded by default" - ); - assert_eq!( - parsed.resources.max_wasm_memory_bytes, - Some(128 * 1024 * 1024), - "WASM memory must be bounded by default" - ); -} - -#[test] -fn overrides_only_present_keys() { - let config = VmLimitsConfig { - tools: Some(ToolLimitsConfig { - max_tool_schema_bytes: Some(4096), - ..Default::default() - }), - wasm: Some(WasmLimitsConfig { - max_module_file_bytes: Some(1_048_576), - ..Default::default() - }), - js_runtime: Some(JsRuntimeLimitsConfig { - v8_heap_limit_mb: Some(256), - ..Default::default() - }), - python: Some(PythonLimitsConfig { - execution_timeout_ms: Some(1000), - ..Default::default() - }), - http: Some(HttpLimitsConfig { - max_fetch_response_bytes: Some(65_536), - }), - ..Default::default() - }; - let parsed = vm_limits_from_config(Some(&config), SIDECAR_FRAME_CAP).expect("valid overrides"); - - assert_eq!(parsed.tools.max_tool_schema_bytes, 4096); - assert_eq!(parsed.wasm.max_module_file_bytes, 1_048_576); - assert_eq!(parsed.js_runtime.v8_heap_limit_mb, Some(256)); - assert_eq!(parsed.python.execution_timeout_ms, 1000); - assert_eq!(parsed.http.max_fetch_response_bytes, 65536); - - // Unspecified fields keep defaults. - let defaults = VmLimits::default(); - assert_eq!( - parsed.tools.max_registered_toolkits, - defaults.tools.max_registered_toolkits - ); - assert_eq!( - parsed.wasm.sync_read_limit_bytes, - defaults.wasm.sync_read_limit_bytes - ); -} - -#[test] -fn resources_subset_threads_through() { - let config = VmLimitsConfig { - resources: Some(ResourceLimitsConfig { - max_processes: Some(8), - ..Default::default() - }), - ..Default::default() - }; - let parsed = - vm_limits_from_config(Some(&config), SIDECAR_FRAME_CAP).expect("resources thread through"); - assert_eq!(parsed.resources.max_processes, Some(8)); -} - -#[test] -fn rejects_unparseable_value() { - let error = serde_json::from_value::(json!({ - "tools": { "maxToolSchemaBytes": "not-a-number" } - })) - .expect_err("unparseable value rejected"); - assert!(error.to_string().contains("invalid type")); -} - -#[test] -fn rejects_fetch_body_exceeding_frame_cap() { - let config = VmLimitsConfig { - http: Some(HttpLimitsConfig { - max_fetch_response_bytes: Some((SIDECAR_FRAME_CAP + 1) as u64), - }), - ..Default::default() - }; - let error = vm_limits_from_config(Some(&config), SIDECAR_FRAME_CAP) - .expect_err("oversized fetch body rejected"); - assert!(error.to_string().contains("wire frame cap")); -} - -#[test] -fn rejects_default_timeout_above_max() { - let config = VmLimitsConfig { - tools: Some(ToolLimitsConfig { - default_tool_timeout_ms: Some(60_000), - max_tool_timeout_ms: Some(30_000), - ..Default::default() - }), - ..Default::default() - }; - let error = - vm_limits_from_config(Some(&config), SIDECAR_FRAME_CAP).expect_err("default above max"); - assert!(error.to_string().contains("max_tool_timeout_ms")); -} - -#[test] -fn rejects_zero_buffer_cap() { - let config = VmLimitsConfig { - js_runtime: Some(JsRuntimeLimitsConfig { - captured_output_limit_bytes: Some(0), - ..Default::default() - }), - ..Default::default() - }; - let error = - vm_limits_from_config(Some(&config), SIDECAR_FRAME_CAP).expect_err("zero buffer cap"); - assert!(error.to_string().contains("captured_output_limit_bytes")); -} diff --git a/crates/sidecar/tests/limits_audit.rs b/crates/sidecar/tests/limits_audit.rs deleted file mode 100644 index 1765cb2e9..000000000 --- a/crates/sidecar/tests/limits_audit.rs +++ /dev/null @@ -1,380 +0,0 @@ -//! Audit test: every limit-shaped constant in the scanned source roots must be classified in -//! `fixtures/limits-inventory.json` as `policy`, `policy-deferred`, or `invariant`. A new -//! `MAX_*` / `*_LIMIT` / capacity / retention constant that is not classified fails this test -//! with instructions, so operator-tunable bounds cannot silently accumulate as hardcoded values. -//! -//! This is a pure filesystem test: no VM, no V8, no new dependencies (`serde_json` is already a -//! sidecar dependency). The match rule is hand-rolled string checks, asserted by its own unit -//! cases below. - -use std::collections::BTreeSet; -use std::fs; -use std::path::{Path, PathBuf}; - -use serde_json::Value; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -struct ScannedConst { - name: String, - path: String, -} - -/// Resolve the workspace root from `CARGO_MANIFEST_DIR` (which points at `crates/sidecar`). -fn workspace_root() -> PathBuf { - let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - manifest - .parent() - .and_then(Path::parent) - .expect("crates/sidecar has a workspace root two levels up") - .to_path_buf() -} - -const SKIP_DIRS: &[&str] = &["target", "node_modules", "dist", "tests", "fixtures"]; - -/// Decide whether a constant name is a limit-shaped bound that must be classified. Mirrors the -/// rule documented in `limits-config.md`. Env-var-name constants (`*_ENV`) and error-code string -/// constants (`*_ERROR_CODE`) are excluded because they name a knob or code, not a bound. -fn name_qualifies(name: &str) -> bool { - if name.ends_with("_ENV") || name.ends_with("_ERROR_CODE") { - return false; - } - if name.contains("MAX_") - || name.contains("_MAX") - || name.contains("_LIMIT") - || name.contains("LIMIT_") - || name.contains("_CAPACITY") - || name.contains("RETENTION") - { - return true; - } - if name.ends_with("_CAP") || name.contains("_CAP_") { - return true; - } - if let Some(rest) = name.strip_prefix("DEFAULT_") { - if rest.contains("BYTES") || rest.contains("TIMEOUT") || rest.contains("ENTRIES") { - return true; - } - } - false -} - -/// Extract a constant name from a Rust `const` declaration line, if present. -/// Matches `^\s*(pub(\(crate\))?\s+)?const\s+([A-Z][A-Z0-9_]*)\s*:`. -fn rust_const_name(line: &str) -> Option<&str> { - let trimmed = line.trim_start(); - let after_vis = trimmed - .strip_prefix("pub(crate) ") - .or_else(|| trimmed.strip_prefix("pub ")) - .unwrap_or(trimmed); - let after_const = after_vis.strip_prefix("const ")?; - let name = identifier_prefix(after_const); - if name.is_empty() { - return None; - } - let rest = after_const[name.len()..].trim_start(); - if !rest.starts_with(':') { - return None; - } - if is_screaming_snake(name) { - Some(name) - } else { - None - } -} - -/// Extract a constant name from a TS/JS `const` declaration line, if present. -/// Matches `^\s*(export\s+)?const\s+([A-Z][A-Z0-9_]*)\s*=`. -fn ts_const_name(line: &str) -> Option<&str> { - let trimmed = line.trim_start(); - let after_export = trimmed.strip_prefix("export ").unwrap_or(trimmed); - let after_const = after_export.strip_prefix("const ")?; - let name = identifier_prefix(after_const); - if name.is_empty() { - return None; - } - let rest = after_const[name.len()..].trim_start(); - if !rest.starts_with('=') { - return None; - } - if is_screaming_snake(name) { - Some(name) - } else { - None - } -} - -fn identifier_prefix(input: &str) -> &str { - let end = input - .char_indices() - .find(|(_, c)| !(c.is_ascii_alphanumeric() || *c == '_')) - .map(|(idx, _)| idx) - .unwrap_or(input.len()); - &input[..end] -} - -/// SCREAMING_SNAKE_CASE: starts with an uppercase ASCII letter, contains only uppercase letters, -/// digits, and underscores. -fn is_screaming_snake(name: &str) -> bool { - let mut chars = name.chars(); - match chars.next() { - Some(c) if c.is_ascii_uppercase() => {} - _ => return false, - } - name.chars() - .all(|c| c.is_ascii_uppercase() || c.is_ascii_digit() || c == '_') -} - -fn scan_file(full: &Path, rel: &str, is_ts: bool, found: &mut Vec) { - let contents = fs::read_to_string(full) - .unwrap_or_else(|error| panic!("failed to read scanned file {rel}: {error}")); - for line in contents.lines() { - let name = if is_ts { - ts_const_name(line) - } else { - rust_const_name(line) - }; - if let Some(name) = name { - if name_qualifies(name) { - found.push(ScannedConst { - name: name.to_string(), - path: rel.to_string(), - }); - } - } - } -} - -fn scan_dir(root: &Path, dir: &Path, extension: &str, is_ts: bool, found: &mut Vec) { - let entries = match fs::read_dir(dir) { - Ok(entries) => entries, - Err(_) => return, - }; - for entry in entries { - let entry = entry.expect("readable directory entry"); - let path = entry.path(); - let file_type = entry.file_type().expect("readable file type"); - if file_type.is_dir() { - let name = entry.file_name(); - let name = name.to_string_lossy(); - if SKIP_DIRS.contains(&name.as_ref()) { - continue; - } - scan_dir(root, &path, extension, is_ts, found); - } else if file_type.is_file() - && path - .extension() - .map(|ext| ext == extension) - .unwrap_or(false) - { - let rel = path - .strip_prefix(root) - .expect("scanned path under workspace root") - .to_string_lossy() - .replace('\\', "/"); - scan_file(&path, &rel, is_ts, found); - } - } -} - -fn scan_workspace() -> Vec { - let root = workspace_root(); - let mut found = Vec::new(); - - // crates/*/src/**/*.rs - let crates_dir = root.join("crates"); - let mut crate_names: Vec<_> = fs::read_dir(&crates_dir) - .expect("crates directory exists") - .map(|entry| entry.expect("readable crate entry").path()) - .collect(); - crate_names.sort(); - for crate_path in crate_names { - let src = crate_path.join("src"); - if src.is_dir() { - scan_dir(&root, &src, "rs", false, &mut found); - } - } - - // packages/core/src/**/*.ts - let core_src = root.join("packages/core/src"); - if core_src.is_dir() { - scan_dir(&root, &core_src, "ts", true, &mut found); - } - - // packages/build-tools/bridge-src/**/*.ts - let bridge_src = root.join("packages/build-tools/bridge-src"); - if bridge_src.is_dir() { - scan_dir(&root, &bridge_src, "ts", true, &mut found); - } - - found.sort(); - found.dedup(); - found -} - -#[derive(Debug, Clone)] -struct InventoryEntry { - name: String, - path: String, - class: String, - wired: Option, -} - -fn load_inventory() -> Vec { - let path = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/limits-inventory.json"); - let raw = fs::read_to_string(&path) - .unwrap_or_else(|error| panic!("failed to read limits inventory {path:?}: {error}")); - let value: Value = serde_json::from_str(&raw).expect("inventory is valid JSON"); - let array = value.as_array().expect("inventory is a JSON array"); - array - .iter() - .map(|entry| { - let name = entry["name"].as_str().expect("entry has name").to_string(); - let path = entry["path"].as_str().expect("entry has path").to_string(); - let class = entry["class"] - .as_str() - .expect("entry has class") - .to_string(); - assert!( - matches!(class.as_str(), "policy" | "policy-deferred" | "invariant"), - "inventory entry {name} ({path}) has invalid class {class}" - ); - let wired = entry - .get("wired") - .and_then(|v| v.as_str()) - .map(str::to_string); - InventoryEntry { - name, - path, - class, - wired, - } - }) - .collect() -} - -#[test] -fn limit_constants_are_classified() { - let scanned = scan_workspace(); - let inventory = load_inventory(); - - let mut failures: Vec = Vec::new(); - - // Duplicate (name, path) inventory entries are rejected. - let mut inventory_keys: BTreeSet<(String, String)> = BTreeSet::new(); - for entry in &inventory { - let key = (entry.name.clone(), entry.path.clone()); - if !inventory_keys.insert(key.clone()) { - failures.push(format!( - "duplicate inventory entry for {} in {}", - entry.name, entry.path - )); - } - } - - let scanned_keys: BTreeSet<(String, String)> = scanned - .iter() - .map(|c| (c.name.clone(), c.path.clone())) - .collect(); - - // Every scanned constant must have an inventory entry. - for c in &scanned { - let key = (c.name.clone(), c.path.clone()); - if !inventory_keys.contains(&key) { - failures.push(format!( - "unclassified limit constant {} in {}: wire it through VmLimits and mark it \ - \"policy\", or add an \"invariant\"/\"policy-deferred\" entry to \ - crates/sidecar/tests/fixtures/limits-inventory.json with a one-line rationale", - c.name, c.path - )); - } - } - - // Every inventory entry must still exist in the scanned source (no stale entries). - for entry in &inventory { - let key = (entry.name.clone(), entry.path.clone()); - if !scanned_keys.contains(&key) { - failures.push(format!( - "stale inventory entry {} in {}: the constant no longer exists in source; \ - remove or update the entry in limits-inventory.json (renames must update both)", - entry.name, entry.path - )); - } - } - - // Every policy entry names the VmLimits field it is wired through. - for entry in &inventory { - if entry.class == "policy" { - let wired_ok = entry - .wired - .as_deref() - .map(|w| !w.is_empty()) - .unwrap_or(false); - if !wired_ok { - failures.push(format!( - "policy inventory entry {} in {} must set a non-empty \"wired\" field naming \ - the config field it flows from", - entry.name, entry.path - )); - } - } - } - - if !failures.is_empty() { - panic!( - "limits inventory audit failed with {} issue(s):\n{}", - failures.len(), - failures.join("\n") - ); - } -} - -#[test] -fn match_rule_unit_assertions() { - // Qualifying names. - assert!(name_qualifies("MAX_TOOL_SCHEMA_BYTES")); - assert!(name_qualifies("VM_FETCH_BUFFER_LIMIT_BYTES")); - assert!(name_qualifies("SESSION_OUTPUT_CHANNEL_CAPACITY")); - assert!(name_qualifies("ACP_SESSION_EVENT_RETENTION_LIMIT")); - assert!(name_qualifies("DEFAULT_COMPLETED_RESPONSE_CAP")); - assert!(name_qualifies("DEFAULT_TIMEOUT_MS")); - assert!(name_qualifies("DEFAULT_MAX_PREAD_BYTES")); - assert!(name_qualifies("MAX_MODULE_RESOLVE_CACHE_ENTRIES")); - - // Non-qualifying names. - assert!(!name_qualifies("PROTOCOL_VERSION")); - assert!(!name_qualifies("EXECUTION_DRIVER_NAME")); - assert!(!name_qualifies("DEFAULT_VIRTUAL_CPU_COUNT")); - // Exclusions. - assert!(!name_qualifies("AGENTOS_WASM_MAX_FUEL_ENV")); - assert!(!name_qualifies("ERR_SESSION_DEFERRED_COMMAND_ERROR_CODE")); - - // Declaration extraction. - assert_eq!( - rust_const_name("pub(crate) const MAX_TOOL_TIMEOUT_MS: u64 = 300_000;"), - Some("MAX_TOOL_TIMEOUT_MS") - ); - assert_eq!( - rust_const_name(" const MAX_FRAME_SIZE: usize = 64 * 1024 * 1024;"), - Some("MAX_FRAME_SIZE") - ); - assert_eq!( - rust_const_name("pub const DEFAULT_MAX_PROCESSES: usize = 256;"), - Some("DEFAULT_MAX_PROCESSES") - ); - // Lowercase const is not a screaming-snake limit constant. - assert_eq!(rust_const_name("const max_value: usize = 1;"), None); - // A function, not a const. - assert_eq!(rust_const_name("fn parse_resource_limits() {}"), None); - - assert_eq!( - ts_const_name("export const ACP_SESSION_EVENT_RETENTION_LIMIT = 1024;"), - Some("ACP_SESSION_EVENT_RETENTION_LIMIT") - ); - assert_eq!( - ts_const_name("const MAX_SYMLINK_DEPTH = 40;"), - Some("MAX_SYMLINK_DEPTH") - ); - // camelCase identifiers are not constants for this rule. - assert_eq!(ts_const_name("const maxRetries = 3;"), None); -} diff --git a/crates/sidecar/tests/node_modules_host_mount_resolution.rs b/crates/sidecar/tests/node_modules_host_mount_resolution.rs deleted file mode 100644 index e196f33a0..000000000 --- a/crates/sidecar/tests/node_modules_host_mount_resolution.rs +++ /dev/null @@ -1,190 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - BootstrapRootFilesystemRequest, ConfigureVmRequest, DisposeReason, DisposeVmRequest, - GuestFilesystemCallRequest, GuestFilesystemOperation, GuestRuntimeKind, MountDescriptor, - MountPluginDescriptor, RequestPayload, ResponsePayload, RootFilesystemEntry, - RootFilesystemEntryEncoding, RootFilesystemEntryKind, -}; -use std::collections::HashMap; -use std::fs; -use std::time::Duration; -use support::{ - assert_node_available, authenticate_wire, collect_process_output_wire_with_timeout, - create_vm_wire, execute_wire, new_sidecar, open_session_wire, temp_dir, wire_request, wire_vm, -}; - -/// Regression test for GitHub issue #109: an external package living in a host -/// `node_modules` projected into the VM via the `host_dir` mount plugin must -/// resolve from guest `import`. This mirrors `NodeRuntime.create({ nodeModules })`, -/// which mounts the host `node_modules` at guest `/tmp/node_modules` and runs -/// programs under `/tmp`, so the ancestor-`node_modules` resolution walk from -/// `/tmp` reaches the mount. When this regressed, the guest reported -/// `_resolveModule returned non-string for ''`. -/// -/// This test runs a guest V8 isolate, so it lives in its own integration-test -/// binary (one isolate per process) to avoid the multi-isolate process-teardown -/// segfault that surfaces when several guest-executing tests share a binary. -#[test] -fn host_mounted_node_modules_package_resolves_from_guest_import() { - assert_node_available(); - - let mut sidecar = new_sidecar("node-modules-host-mount"); - - // Seed a host `node_modules` tree with a single package, exactly as a caller - // would prepare libraries before execution. - let host_root = temp_dir("node-modules-host-mount-host"); - let host_node_modules = host_root.join("node_modules"); - let pkg_dir = host_node_modules.join("mypkg"); - fs::create_dir_all(&pkg_dir).expect("create host package dir"); - fs::write( - pkg_dir.join("package.json"), - r#"{"name":"mypkg","version":"1.0.0","type":"module","main":"index.js"}"#, - ) - .expect("write host package.json"); - fs::write( - pkg_dir.join("index.js"), - "export default () => \"resolved-from-host-mount\";\n", - ) - .expect("write host package entry"); - - let cwd = temp_dir("node-modules-host-mount-cwd"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - // Provide the mountpoint, then project the host `node_modules` at guest - // `/tmp/node_modules` (read-only), the default `nodeModules` projection. - sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystemRequest(BootstrapRootFilesystemRequest { - entries: vec![RootFilesystemEntry { - path: String::from("/tmp/node_modules"), - kind: RootFilesystemEntryKind::Directory, - mode: None, - uid: None, - gid: None, - content: None, - encoding: None, - target: None, - executable: false, - }], - }), - )) - .expect("bootstrap mountpoint"); - - sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/tmp/node_modules"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: serde_json::to_string(&serde_json::json!({ - "hostPath": host_node_modules.to_string_lossy(), - "readOnly": true, - })) - .expect("serialize host_dir mount config"), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("mount host node_modules"); - - // Write the guest program under `/tmp` (like `NodeRuntime.exec`), so its - // module-resolution context is `/tmp` and the bare specifier `mypkg` - // resolves through `/tmp/node_modules`. - let entry_source = r#" -import greet from "mypkg"; -console.log(greet()); -"#; - let write = sidecar - .dispatch_wire_blocking(wire_request( - 6, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/tmp/entry.mjs"), - destination_path: None, - target: None, - content: Some(String::from(entry_source)), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("write guest entry"); - match write.response.payload { - ResponsePayload::GuestFilesystemResultResponse(_) => {} - other => panic!("unexpected guest write response: {other:?}"), - } - - execute_wire( - &mut sidecar, - 7, - &connection_id, - &session_id, - &vm_id, - "proc-resolve", - GuestRuntimeKind::JavaScript, - std::path::Path::new("/tmp/entry.mjs"), - Vec::new(), - ); - let (stdout, stderr, exit) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-resolve", - Duration::from_secs(10), - ); - - assert_eq!( - stdout.trim(), - "resolved-from-host-mount", - "guest import of a host-mounted package should resolve; stderr: {stderr}" - ); - assert_eq!(exit, 0, "stderr: {stderr}"); - - sidecar - .dispatch_wire_blocking(wire_request( - 8, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::DisposeVmRequest(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - )) - .expect("dispose vm"); -} diff --git a/crates/sidecar/tests/node_modules_symlink_resolution.rs b/crates/sidecar/tests/node_modules_symlink_resolution.rs deleted file mode 100644 index 3277c9bb9..000000000 --- a/crates/sidecar/tests/node_modules_symlink_resolution.rs +++ /dev/null @@ -1,229 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - BootstrapRootFilesystemRequest, ConfigureVmRequest, DisposeReason, DisposeVmRequest, - GuestFilesystemCallRequest, GuestFilesystemOperation, GuestRuntimeKind, MountDescriptor, - MountPluginDescriptor, RequestPayload, ResponsePayload, RootFilesystemEntry, - RootFilesystemEntryEncoding, RootFilesystemEntryKind, -}; -use std::collections::HashMap; -use std::fs; -use std::os::unix::fs::symlink; -use std::time::Duration; -use support::{ - authenticate_wire, collect_process_output_wire_with_timeout, create_vm_wire, execute_wire, - new_sidecar, open_session_wire, temp_dir, wire_request, wire_vm, -}; - -/// Companion to `node_modules_host_mount_resolution.rs` (issue #109): that test -/// projects a *plain* host `node_modules` (real package directories). Real -/// installs are rarely plain — pnpm (and yarn's node-linker) lay out -/// `node_modules` as symlinks into a virtual `.pnpm` store, with scoped -/// packages nested under an `@scope/` directory. This locks in that the -/// `host_dir` mount `NodeRuntime.create({ nodeModules })` projects follows those -/// in-tree relative symlinks, so a pnpm-installed package resolves from guest -/// `import` exactly like the plain layout does. -/// -/// Note the boundary this does *not* relax: the mount confines reads to its -/// root (anchored `openat2(RESOLVE_BENEATH)`), so a symlink that escapes the -/// mounted tree (a workspace/`file:` dep linked to the workspace root or an -/// external store) is deliberately not followed. The fix for that case is to -/// mount a directory that contains the symlink targets, not to widen the mount. -/// -/// One guest V8 isolate per process, so this lives in its own integration-test -/// binary (see the sibling test for the multi-isolate teardown rationale). -#[test] -fn pnpm_symlinked_packages_resolve_from_guest_import() { - support::assert_node_available(); - - let mut sidecar = new_sidecar("node-modules-symlink"); - - // Seed a host `node_modules` shaped like a pnpm install: real package - // directories live in the `.pnpm` virtual store, and the top-level entries - // are relative symlinks pointing into it. Both a plain and a scoped package - // are covered, since scoped packages take a separate `@scope/` resolution - // path. - let host_root = temp_dir("node-modules-symlink-host"); - let node_modules = host_root.join("node_modules"); - let store = node_modules.join(".pnpm"); - - let plain_real = store.join("is-number@7.0.0/node_modules/is-number"); - fs::create_dir_all(&plain_real).expect("create plain store dir"); - fs::write( - plain_real.join("package.json"), - r#"{"name":"is-number","version":"7.0.0","type":"module","main":"index.js"}"#, - ) - .expect("write plain package.json"); - fs::write( - plain_real.join("index.js"), - "export default () => \"plain-symlink-resolved\";\n", - ) - .expect("write plain entry"); - - let scoped_real = store.join("@scope+pkg@1.0.0/node_modules/@scope/pkg"); - fs::create_dir_all(&scoped_real).expect("create scoped store dir"); - fs::write( - scoped_real.join("package.json"), - r#"{"name":"@scope/pkg","version":"1.0.0","type":"module","main":"index.js"}"#, - ) - .expect("write scoped package.json"); - fs::write( - scoped_real.join("index.js"), - "export default () => \"scoped-symlink-resolved\";\n", - ) - .expect("write scoped entry"); - - // Top-level symlinks, relative and contained within `node_modules` exactly - // as pnpm writes them. - symlink( - "./.pnpm/is-number@7.0.0/node_modules/is-number", - node_modules.join("is-number"), - ) - .expect("link plain package"); - fs::create_dir_all(node_modules.join("@scope")).expect("create @scope dir"); - symlink( - "../.pnpm/@scope+pkg@1.0.0/node_modules/@scope/pkg", - node_modules.join("@scope/pkg"), - ) - .expect("link scoped package"); - - let cwd = temp_dir("node-modules-symlink-cwd"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - // Provide the mountpoint, then project the host `node_modules` at guest - // `/tmp/node_modules` (read-only) — the default `nodeModules` projection. - sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystemRequest(BootstrapRootFilesystemRequest { - entries: vec![RootFilesystemEntry { - path: String::from("/tmp/node_modules"), - kind: RootFilesystemEntryKind::Directory, - mode: None, - uid: None, - gid: None, - content: None, - encoding: None, - target: None, - executable: false, - }], - }), - )) - .expect("bootstrap mountpoint"); - - sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/tmp/node_modules"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: serde_json::to_string(&serde_json::json!({ - "hostPath": node_modules.to_string_lossy(), - "readOnly": true, - })) - .expect("serialize host_dir mount config"), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("mount host node_modules"); - - // Program under `/tmp` so the resolution walk reaches `/tmp/node_modules`, - // importing both the plain and the scoped symlinked package. - let entry_source = r#" -import plain from "is-number"; -import scoped from "@scope/pkg"; -console.log(plain()); -console.log(scoped()); -"#; - let write = sidecar - .dispatch_wire_blocking(wire_request( - 6, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/tmp/entry.mjs"), - destination_path: None, - target: None, - content: Some(String::from(entry_source)), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("write guest entry"); - match write.response.payload { - ResponsePayload::GuestFilesystemResultResponse(_) => {} - other => panic!("unexpected guest write response: {other:?}"), - } - - execute_wire( - &mut sidecar, - 7, - &connection_id, - &session_id, - &vm_id, - "proc-resolve", - GuestRuntimeKind::JavaScript, - std::path::Path::new("/tmp/entry.mjs"), - Vec::new(), - ); - let (stdout, stderr, exit) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-resolve", - Duration::from_secs(10), - ); - - assert_eq!( - stdout.trim(), - "plain-symlink-resolved\nscoped-symlink-resolved", - "guest import of pnpm-symlinked packages should resolve; stderr: {stderr}" - ); - assert_eq!(exit, 0, "stderr: {stderr}"); - - sidecar - .dispatch_wire_blocking(wire_request( - 8, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::DisposeVmRequest(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - )) - .expect("dispose vm"); -} diff --git a/crates/sidecar/tests/package_projection.rs b/crates/sidecar/tests/package_projection.rs deleted file mode 100644 index 0bb82d557..000000000 --- a/crates/sidecar/tests/package_projection.rs +++ /dev/null @@ -1,242 +0,0 @@ -use std::fs; -use std::io::Write; -use std::path::{Path, PathBuf}; - -use secure_exec_sidecar::package_projection::{ - build_package_leaf_mounts, derive_commands, package_provides_file_mount, read_package_manifest, - read_package_manifest_from_ref, read_package_version, PackageLeafMount, - DEFAULT_PACKAGE_TAR_NAME, -}; -use tar::Builder; - -fn unique_dir(tag: &str) -> PathBuf { - let nonce = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_nanos(); - let dir = std::env::temp_dir().join(format!("agentos-projtest-{tag}-{nonce}")); - fs::create_dir_all(&dir).unwrap(); - dir -} - -fn write_package(root: &Path, name: &str, version: &str, commands: &[&str]) { - fs::create_dir_all(root.join("bin")).unwrap(); - fs::write( - root.join("agentos-package.json"), - format!("{{\"name\":\"{name}\",\"version\":\"{version}\"}}"), - ) - .unwrap(); - for cmd in commands { - fs::write( - root.join("bin").join(cmd), - format!("#!/usr/bin/env node\n// {cmd}\n"), - ) - .unwrap(); - } -} - -fn finalize_package_tar(root: &Path) { - let tar_path = root.join(DEFAULT_PACKAGE_TAR_NAME); - let _ = fs::remove_file(&tar_path); - let file = fs::File::create(&tar_path).unwrap(); - let mut builder = Builder::new(file); - append_tree(&mut builder, root, root).unwrap(); - builder.finish().unwrap(); - builder.into_inner().unwrap().flush().unwrap(); -} - -fn append_tree(builder: &mut Builder, root: &Path, path: &Path) -> std::io::Result<()> { - for entry in fs::read_dir(path)? { - let entry = entry?; - let entry_path = entry.path(); - if entry_path.file_name().and_then(|name| name.to_str()) == Some(DEFAULT_PACKAGE_TAR_NAME) { - continue; - } - let name = entry_path.strip_prefix(root).unwrap(); - if entry_path.is_dir() { - builder.append_dir(name, &entry_path)?; - append_tree(builder, root, &entry_path)?; - } else { - builder.append_path_with_name(&entry_path, name)?; - } - } - Ok(()) -} - -#[test] -fn reads_version_from_agentos_package_json_and_errors_when_missing() { - let pkg = unique_dir("ver"); - write_package(&pkg, "vt", "3.1.4", &["vt"]); - assert_eq!( - read_package_version(pkg.to_str().unwrap()).unwrap(), - "3.1.4" - ); - - let empty = unique_dir("ver-missing"); - assert!(read_package_version(empty.to_str().unwrap()).is_err()); -} - -#[test] -fn reads_name_agent_and_provides_from_agentos_package_json() { - let pkg = unique_dir("manifest"); - write_package(&pkg, "package-json-name", "1.0.0", &["agent-cmd"]); - fs::create_dir_all(pkg.join("share/config")).unwrap(); - fs::write( - pkg.join("agentos-package.json"), - r#"{ - "name": "manifest-name", - "version": "1.0.0", - "agent": { "acpEntrypoint": "agent-cmd" }, - "provides": { - "env": { "FROM_MANIFEST": "yes" }, - "files": [{ "source": "share/config", "target": "/etc/manifest" }] - } - }"#, - ) - .unwrap(); - - let descriptor = read_package_manifest(pkg.to_str().unwrap()).unwrap(); - assert_eq!(descriptor.name, "manifest-name"); - assert_eq!(descriptor.version, "1.0.0"); - assert_eq!(descriptor.acp_entrypoint.as_deref(), Some("agent-cmd")); - let provides = descriptor.provides.as_ref().expect("provides"); - assert_eq!( - provides.env.get("FROM_MANIFEST").map(String::as_str), - Some("yes") - ); - assert_eq!(provides.files[0].target, "/etc/manifest"); -} - -#[test] -fn derives_commands_from_bin_dir() { - let pkg = unique_dir("cmds"); - write_package(&pkg, "tool", "1.0.0", &["foo", "bar"]); - let mut commands = derive_commands(pkg.to_str().unwrap()).unwrap(); - commands.sort(); - assert_eq!(commands, vec!["bar".to_string(), "foo".to_string()]); -} - -#[test] -fn reads_manifest_and_commands_from_package_tar_without_extracting() { - let pkg = unique_dir("tar-src"); - write_package(&pkg, "demo", "2.0.0", &["demo"]); - finalize_package_tar(&pkg); - - let descriptor = read_package_manifest_from_ref(Some(pkg.to_str().unwrap()), None).unwrap(); - assert_eq!(descriptor.name, "demo"); - assert_eq!(descriptor.version, "2.0.0"); - assert!(descriptor - .tar_path - .as_deref() - .unwrap() - .ends_with(DEFAULT_PACKAGE_TAR_NAME)); - assert_eq!(descriptor.commands[0].command, "demo"); -} - -#[test] -fn reads_symlink_commands_from_package_tar() { - let pkg = unique_dir("tar-symlink-cmd"); - write_package(&pkg, "demo", "2.0.0", &[]); - fs::write(pkg.join("adapter.mjs"), "console.log('ok');").unwrap(); - std::os::unix::fs::symlink("../adapter.mjs", pkg.join("bin/demo")).unwrap(); - finalize_package_tar(&pkg); - - let descriptor = read_package_manifest_from_ref(Some(pkg.to_str().unwrap()), None).unwrap(); - assert_eq!(descriptor.commands[0].command, "demo"); - assert_eq!(descriptor.commands[0].entry, "bin/demo"); -} - -#[test] -fn builds_tar_current_bin_and_manpage_leaf_mounts() { - let pkg = unique_dir("mounts-src"); - write_package(&pkg, "demo", "2.0.0", &["demo"]); - fs::create_dir_all(pkg.join("share/man/man1")).unwrap(); - fs::write(pkg.join("share/man/man1/demo.1"), "manual").unwrap(); - finalize_package_tar(&pkg); - let descriptor = read_package_manifest_from_ref(Some(pkg.to_str().unwrap()), None).unwrap(); - - let mounts = build_package_leaf_mounts(&[descriptor], "/opt/agentos").unwrap(); - assert!(mounts.iter().any(|mount| matches!( - mount, - PackageLeafMount::Tar { guest_path, root, .. } - if guest_path == "/opt/agentos/pkgs/demo/2.0.0" && root == "/" - ))); - assert!(mounts.iter().any(|mount| matches!( - mount, - PackageLeafMount::SingleSymlink { guest_path, target } - if guest_path == "/opt/agentos/pkgs/demo/current" && target == "2.0.0" - ))); - assert!(mounts.iter().any(|mount| matches!( - mount, - PackageLeafMount::SingleSymlink { guest_path, target } - if guest_path == "/opt/agentos/bin/demo" - && target == "../pkgs/demo/current/bin/demo" - ))); - assert!(mounts.iter().any(|mount| matches!( - mount, - PackageLeafMount::SingleSymlink { guest_path, target } - if guest_path == "/opt/agentos/share/man/man1/demo.1" - && target == "../../../pkgs/demo/current/share/man/man1/demo.1" - ))); -} - -#[test] -fn duplicate_commands_are_rejected_before_mounting() { - let pkg_a = unique_dir("dup-a"); - write_package(&pkg_a, "a", "1.0.0", &["tool"]); - finalize_package_tar(&pkg_a); - let pkg_b = unique_dir("dup-b"); - write_package(&pkg_b, "b", "1.0.0", &["tool"]); - finalize_package_tar(&pkg_b); - - let a = read_package_manifest_from_ref(Some(pkg_a.to_str().unwrap()), None).unwrap(); - let b = read_package_manifest_from_ref(Some(pkg_b.to_str().unwrap()), None).unwrap(); - let err = build_package_leaf_mounts(&[a, b], "/opt/agentos").unwrap_err(); - assert!(err.to_string().contains("already provided"), "{err}"); -} - -#[test] -fn invalid_agent_entrypoint_is_rejected() { - let pkg = unique_dir("bad-agent"); - write_package(&pkg, "agent", "1.0.0", &["real"]); - fs::write( - pkg.join("agentos-package.json"), - r#"{"name":"agent","version":"1.0.0","agent":{"acpEntrypoint":"missing"}}"#, - ) - .unwrap(); - finalize_package_tar(&pkg); - - let descriptor = read_package_manifest_from_ref(Some(pkg.to_str().unwrap()), None).unwrap(); - let err = build_package_leaf_mounts(&[descriptor], "/opt/agentos").unwrap_err(); - assert!(err.to_string().contains("acpEntrypoint"), "{err}"); -} - -#[test] -fn provides_files_mounts_tar_subtree() { - let pkg = unique_dir("provides"); - write_package(&pkg, "provider", "1.0.0", &["provider"]); - fs::create_dir_all(pkg.join("share/config")).unwrap(); - fs::write(pkg.join("share/config/settings.json"), "{}").unwrap(); - fs::write( - pkg.join("agentos-package.json"), - r#"{ - "name": "provider", - "version": "1.0.0", - "provides": { - "files": [{ "source": "share/config", "target": "/etc/provider" }] - } - }"#, - ) - .unwrap(); - finalize_package_tar(&pkg); - - let descriptor = read_package_manifest_from_ref(Some(pkg.to_str().unwrap()), None).unwrap(); - let mount = package_provides_file_mount(&descriptor, "share/config", "/etc/provider") - .unwrap() - .expect("provides dir mount"); - assert!(matches!( - mount, - PackageLeafMount::Tar { guest_path, root, .. } - if guest_path == "/etc/provider" && root == "/share/config" - )); -} diff --git a/crates/sidecar/tests/permission_flags.rs b/crates/sidecar/tests/permission_flags.rs deleted file mode 100644 index c96b44efb..000000000 --- a/crates/sidecar/tests/permission_flags.rs +++ /dev/null @@ -1,458 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - ConfigureVmRequest, CreateVmRequest, FsPermissionRule, FsPermissionRuleSet, FsPermissionScope, - GuestFilesystemCallRequest, GuestFilesystemOperation, GuestRuntimeKind, PatternPermissionRule, - PatternPermissionRuleSet, PatternPermissionScope, PermissionMode, PermissionsPolicy, - RequestPayload, ResponsePayload, RootFilesystemDescriptor, RootFilesystemEntry, - RootFilesystemEntryKind, RootFilesystemMode, -}; -use std::collections::HashMap; -use support::{ - authenticate_wire, create_vm_wire, open_session_wire, temp_dir, wire_request, wire_session, - wire_vm, -}; - -fn expect_invalid_state(payload: ResponsePayload, expected_message: &str) { - match payload { - ResponsePayload::RejectedResponse(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!( - rejected.message.contains(expected_message), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected invalid_state rejection, got {other:?}"), - } -} - -fn root_dir(path: &str, mode: u32) -> RootFilesystemEntry { - RootFilesystemEntry { - path: path.to_owned(), - kind: RootFilesystemEntryKind::Directory, - mode: Some(mode), - uid: None, - gid: None, - content: None, - encoding: None, - target: None, - executable: false, - } -} - -fn create_vm_with_fs_permissions( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - permissions: PermissionsPolicy, -) -> String { - let response = sidecar - .dispatch_wire_blocking(wire_request( - 3, - wire_session(connection_id, session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::new(), - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: vec![root_dir("/tmp", 0o755)], - }, - Some(permissions), - )), - )) - .expect("create vm with fs permissions"); - - match response.response.payload { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("expected vm create response, got {other:?}"), - } -} - -fn mkdir_request(path: &str, recursive: bool) -> GuestFilesystemCallRequest { - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Mkdir, - path: path.to_owned(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - } -} - -#[test] -fn permission_flags_reject_empty_operations_and_accept_explicit_wildcards() { - let mut sidecar = support::new_sidecar("permission-flags-create"); - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - - let rejected = sidecar - .dispatch_wire_blocking(wire_request( - 3, - wire_session(&connection_id, &session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::new(), - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }, - Some(PermissionsPolicy { - fs: Some(FsPermissionScope::FsPermissionRuleSet( - FsPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![FsPermissionRule { - mode: PermissionMode::Allow, - operations: Vec::new(), - paths: vec![String::from("/**")], - }], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }), - )), - )) - .expect("dispatch create vm rejection"); - - expect_invalid_state( - rejected.response.payload, - "fs.rules[0].operations must not be empty", - ); - - let accepted = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_session(&connection_id, &session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::new(), - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }, - Some(PermissionsPolicy { - fs: Some(FsPermissionScope::FsPermissionRuleSet( - FsPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![FsPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("*")], - paths: vec![String::from("/**")], - }], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }), - )), - )) - .expect("dispatch create vm with wildcard"); - - match accepted.response.payload { - ResponsePayload::VmCreatedResponse(_) => {} - other => panic!("expected vm creation with explicit wildcard, got {other:?}"), - } -} - -#[test] -fn permission_flags_reject_empty_paths_and_patterns_on_configure() { - let mut sidecar = support::new_sidecar("permission-flags-configure"); - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let cwd = temp_dir("permission-flags-configure-cwd"); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let empty_paths = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: Some(PermissionsPolicy { - fs: Some(FsPermissionScope::FsPermissionRuleSet( - FsPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![FsPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("read")], - paths: Vec::new(), - }], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: Default::default(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("dispatch configure vm with empty fs paths"); - - expect_invalid_state( - empty_paths.response.payload, - "fs.rules[0].paths must not be empty", - ); - - let empty_patterns = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: Some(PermissionsPolicy { - fs: None, - network: Some(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![PatternPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("*")], - patterns: Vec::new(), - }], - }, - )), - child_process: None, - process: None, - env: None, - binding: None, - }), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: Default::default(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("dispatch configure vm with empty network patterns"); - - expect_invalid_state( - empty_patterns.response.payload, - "network.rules[0].patterns must not be empty", - ); - - let empty_pattern_operations = sidecar - .dispatch_wire_blocking(wire_request( - 6, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: Some(PermissionsPolicy { - fs: None, - network: Some(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![PatternPermissionRule { - mode: PermissionMode::Allow, - operations: Vec::new(), - patterns: vec![String::from("**")], - }], - }, - )), - child_process: None, - process: None, - env: None, - binding: None, - }), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: Default::default(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("dispatch configure vm with empty network operations"); - - expect_invalid_state( - empty_pattern_operations.response.payload, - "network.rules[0].operations must not be empty", - ); -} - -#[test] -fn permission_flags_single_star_paths_do_not_cross_path_separators() { - let mut sidecar = support::new_sidecar("permission-flags-single-star"); - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_fs_permissions( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy { - fs: Some(FsPermissionScope::FsPermissionRuleSet( - FsPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![ - FsPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("read")], - paths: vec![String::from("/tmp")], - }, - FsPermissionRule { - mode: PermissionMode::Allow, - operations: vec![ - String::from("create_dir"), - String::from("read"), - String::from("stat"), - ], - paths: vec![String::from("/tmp/*")], - }, - ], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }, - ); - - let allow_direct_child = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(mkdir_request("/tmp/a", false)), - )) - .expect("create direct child directory"); - match allow_direct_child.response.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::Mkdir); - assert_eq!(response.path, "/tmp/a"); - } - other => panic!("expected guest filesystem mkdir response, got {other:?}"), - } - - let deny_nested_child = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(mkdir_request("/tmp/a/b", false)), - )) - .expect("attempt nested child directory create"); - match deny_nested_child.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - assert_eq!(rejected.code, "kernel_error"); - assert!(rejected.message.contains("EACCES")); - } - other => panic!("expected rejected nested mkdir response, got {other:?}"), - } -} - -#[test] -fn permission_flags_double_star_paths_allow_nested_descendants() { - let mut sidecar = support::new_sidecar("permission-flags-double-star"); - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_fs_permissions( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy { - fs: Some(FsPermissionScope::FsPermissionRuleSet( - FsPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![ - FsPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("read")], - paths: vec![String::from("/tmp")], - }, - FsPermissionRule { - mode: PermissionMode::Allow, - operations: vec![ - String::from("create_dir"), - String::from("read"), - String::from("stat"), - ], - paths: vec![String::from("/tmp/**")], - }, - ], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }, - ); - - let allow_direct_child = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(mkdir_request("/tmp/a", false)), - )) - .expect("create direct child directory"); - match allow_direct_child.response.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::Mkdir); - assert_eq!(response.path, "/tmp/a"); - } - other => panic!("expected guest filesystem mkdir response, got {other:?}"), - } - - let allow_nested_child = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(mkdir_request("/tmp/a/b/c", true)), - )) - .expect("create nested child directory"); - match allow_nested_child.response.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::Mkdir); - assert_eq!(response.path, "/tmp/a/b/c"); - } - other => panic!("expected guest filesystem mkdir response, got {other:?}"), - } -} diff --git a/crates/sidecar/tests/posix_compliance.rs b/crates/sidecar/tests/posix_compliance.rs deleted file mode 100644 index b0d181f82..000000000 --- a/crates/sidecar/tests/posix_compliance.rs +++ /dev/null @@ -1,555 +0,0 @@ -mod support; - -use nix::libc; -use secure_exec_kernel::command_registry::CommandDriver; -use secure_exec_kernel::fd_table::O_RDWR; -use secure_exec_kernel::kernel::{KernelVm, KernelVmConfig, SpawnOptions}; -use secure_exec_kernel::permissions::Permissions; -use secure_exec_kernel::process_table::{ - DriverProcess, ProcessContext, ProcessExitCallback, ProcessResult, ProcessTable, - ProcessWaitEvent, WaitPidFlags, SIGCHLD, SIGTERM, -}; -use secure_exec_kernel::vfs::MemoryFileSystem; -use secure_exec_sidecar::wire::{ - EventPayload, GetSignalStateRequest, GuestRuntimeKind, KillProcessRequest, RequestPayload, - ResponsePayload, SignalDispositionAction, SignalHandlerRegistration, -}; -use std::collections::BTreeMap; -use std::fmt::Debug; -use std::sync::{Arc, Condvar, Mutex}; -use std::time::{Duration, Instant}; -use support::{ - assert_node_available, authenticate_wire, create_vm_wire, execute_wire, new_sidecar, - open_session_wire, temp_dir, wire_request, wire_vm, write_fixture, -}; - -fn assert_process_error_code(result: ProcessResult, expected: &str) { - let error = result.expect_err("operation should fail"); - assert_eq!(error.code(), expected); -} - -fn assert_not_trivial_pattern(bytes: &[u8]) { - assert!(bytes.iter().any(|byte| *byte != 0)); - assert!( - bytes.windows(2).any(|window| window[0] != window[1]), - "random data should not collapse to a repeated byte" - ); -} - -fn null_separated_bytes(parts: &[&str]) -> Vec { - if parts.is_empty() { - return Vec::new(); - } - - let mut bytes = parts.join("\0").into_bytes(); - bytes.push(0); - bytes -} - -fn chunk_contains(chunk: &[u8], needle: &str) -> bool { - let needle = needle.as_bytes(); - if needle.is_empty() { - return true; - } - chunk.windows(needle.len()).any(|window| window == needle) -} - -fn new_kernel(name: &str) -> KernelVm { - let mut config = KernelVmConfig::new(name); - config.permissions = Permissions::allow_all(); - let mut kernel = KernelVm::new(MemoryFileSystem::new(), config); - kernel - .register_driver(CommandDriver::new("shell", ["sh"])) - .expect("register shell driver"); - kernel -} - -fn spawn_shell( - kernel: &mut KernelVm, - args: Vec, - cwd: &str, - env: BTreeMap, -) -> secure_exec_kernel::kernel::KernelProcessHandle { - kernel - .spawn_process( - "sh", - args, - SpawnOptions { - requester_driver: Some(String::from("shell")), - cwd: Some(String::from(cwd)), - env, - ..SpawnOptions::default() - }, - ) - .expect("spawn shell") -} - -fn wait_for_process_output( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - expected: &str, -) { - let ownership = wire_vm(connection_id, session_id, vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - - loop { - assert!( - Instant::now() < deadline, - "timed out waiting for process output" - ); - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll sidecar event"); - let Some(event) = event else { continue }; - - match event.payload { - EventPayload::ProcessOutputEvent(output) - if output.process_id == process_id && chunk_contains(&output.chunk, expected) => - { - return; - } - _ => {} - } - } -} - -#[derive(Default)] -struct MockProcessState { - kills: Vec, - exit_code: Option, - on_exit: Option, -} - -#[derive(Default)] -struct MockDriverProcess { - state: Mutex, - exited: Condvar, -} - -impl MockDriverProcess { - fn new() -> Arc { - Arc::new(Self::default()) - } - - fn kills(&self) -> Vec { - self.state - .lock() - .expect("mock process lock poisoned") - .kills - .clone() - } - - fn exit(&self, exit_code: i32) { - let callback = { - let mut state = self.state.lock().expect("mock process lock poisoned"); - if state.exit_code.is_some() { - return; - } - state.exit_code = Some(exit_code); - self.exited.notify_all(); - state.on_exit.clone() - }; - - if let Some(callback) = callback { - callback(exit_code); - } - } -} - -impl DriverProcess for MockDriverProcess { - fn kill(&self, signal: i32) { - let should_exit = { - let mut state = self.state.lock().expect("mock process lock poisoned"); - state.kills.push(signal); - signal == SIGTERM - }; - - if should_exit { - self.exit(128 + signal); - } - } - - fn wait(&self, timeout: Duration) -> Option { - let state = self.state.lock().expect("mock process lock poisoned"); - if state.exit_code.is_some() { - return state.exit_code; - } - - let (state, _) = self - .exited - .wait_timeout(state, timeout) - .expect("mock process wait lock poisoned"); - state.exit_code - } - - fn set_on_exit(&self, callback: ProcessExitCallback) { - self.state - .lock() - .expect("mock process lock poisoned") - .on_exit = Some(callback); - } -} - -fn create_context(ppid: u32) -> ProcessContext { - ProcessContext { - pid: 0, - ppid, - env: BTreeMap::new(), - cwd: String::from("/"), - ..ProcessContext::default() - } -} - -fn allocate_pid(table: &ProcessTable) -> u32 { - table.allocate_pid().expect("allocate pid") -} - -#[test] -fn proc_filesystem_reports_kernel_identity_and_sanitized_process_metadata() { - let mut kernel = new_kernel("vm-posix-procfs"); - kernel - .mkdir("/guest/work", true) - .expect("create guest working directory"); - kernel - .write_file("/guest/work/data.txt", b"hello".to_vec()) - .expect("seed guest file"); - - let env = BTreeMap::from([ - (String::from("KERNEL_ONLY_MARKER"), String::from("present")), - (String::from("SECOND_MARKER"), String::from("also-present")), - ]); - let process = spawn_shell( - &mut kernel, - vec![String::from("-lc"), String::from("echo ok")], - "/guest/work", - env, - ); - let pid = process.pid(); - let data_fd = kernel - .fd_open("shell", pid, "/guest/work/data.txt", O_RDWR, None) - .expect("open extra guest fd"); - - let self_link = kernel - .read_link_for_process("shell", pid, "/proc/self") - .expect("resolve /proc/self"); - assert_eq!(self_link, format!("/proc/{pid}")); - - let stat_text = String::from_utf8( - kernel - .read_file_for_process("shell", pid, "/proc/self/stat") - .expect("read /proc/self/stat"), - ) - .expect("proc stat should be utf8"); - let reported_pid = stat_text - .split_whitespace() - .next() - .expect("proc stat should include pid") - .parse::() - .expect("proc stat pid should be numeric"); - assert_eq!(reported_pid, pid, "proc identity should use kernel pid"); - - let cmdline = kernel - .read_file_for_process("shell", pid, &format!("/proc/{pid}/cmdline")) - .expect("read cmdline"); - assert_eq!(cmdline, null_separated_bytes(&["sh", "-lc", "echo ok"])); - - let environ = kernel - .read_file_for_process("shell", pid, &format!("/proc/{pid}/environ")) - .expect("read environ"); - assert_eq!( - environ, - null_separated_bytes(&["KERNEL_ONLY_MARKER=present", "SECOND_MARKER=also-present",]), - "proc environ should only expose kernel-managed env entries" - ); - - let cwd = kernel - .read_link_for_process("shell", pid, &format!("/proc/{pid}/cwd")) - .expect("read cwd"); - assert_eq!(cwd, "/guest/work"); - - let fd_entries = kernel - .read_dir_for_process("shell", pid, &format!("/proc/{pid}/fd")) - .expect("read fd directory"); - assert!(fd_entries.contains(&String::from("0"))); - assert!(fd_entries.contains(&String::from("1"))); - assert!(fd_entries.contains(&String::from("2"))); - assert!(fd_entries.contains(&data_fd.to_string())); - assert_eq!( - kernel - .read_link_for_process("shell", pid, &format!("/proc/{pid}/fd/{data_fd}")) - .expect("read proc fd link"), - String::from("/guest/work/data.txt") - ); - - process.finish(0); - kernel.waitpid(pid).expect("wait procfs shell"); -} - -#[test] -fn device_nodes_match_posix_special_file_semantics() { - let mut kernel = new_kernel("vm-posix-devices"); - let process = spawn_shell(&mut kernel, Vec::new(), "/", BTreeMap::new()); - let pid = process.pid(); - - let null_fd = kernel - .fd_open("shell", pid, "/dev/null", O_RDWR, None) - .expect("open /dev/null"); - let written = kernel - .fd_write("shell", pid, null_fd, b"discard-me") - .expect("write /dev/null"); - assert_eq!(written, b"discard-me".len()); - let null_bytes = kernel - .fd_read("shell", pid, null_fd, 32) - .expect("read /dev/null"); - assert!(null_bytes.is_empty(), "/dev/null should always read as EOF"); - - let zero_fd = kernel - .fd_open("shell", pid, "/dev/zero", O_RDWR, None) - .expect("open /dev/zero"); - let zeroes = kernel - .fd_read("shell", pid, zero_fd, 64) - .expect("read /dev/zero"); - assert_eq!(zeroes.len(), 64); - assert!(zeroes.iter().all(|byte| *byte == 0)); - - let random_fd = kernel - .fd_open("shell", pid, "/dev/urandom", O_RDWR, None) - .expect("open /dev/urandom"); - let first = kernel - .fd_read("shell", pid, random_fd, 1024) - .expect("read first urandom chunk"); - let second = kernel - .fd_read("shell", pid, random_fd, 1024) - .expect("read second urandom chunk"); - assert_eq!(first.len(), 1024); - assert_eq!(second.len(), 1024); - assert_not_trivial_pattern(&first); - assert_not_trivial_pattern(&second); - assert_ne!(first, second, "urandom reads should vary"); - - process.finish(0); - kernel.waitpid(pid).expect("wait device shell"); -} - -#[test] -fn v8_guest_process_receives_sigterm_delivery() { - assert_node_available(); - - let mut sidecar = new_sidecar("posix-v8-sigterm"); - let cwd = temp_dir("posix-v8-sigterm-cwd"); - let entry = cwd.join("sigterm.mjs"); - - write_fixture( - &entry, - [ - "let deliveries = 0;", - "process.on('SIGTERM', () => {", - " deliveries += 1;", - " console.log(`sigterm:${deliveries}`);", - " process.exit(0);", - "});", - "console.log('ready');", - "setInterval(() => {}, 25);", - ] - .join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-posix-sigterm"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "sigterm-guest", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - wait_for_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "sigterm-guest", - "ready", - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - let registration_deadline = Instant::now() + Duration::from_secs(10); - loop { - let signal_state = sidecar - .dispatch_wire_blocking(wire_request( - 5, - ownership.clone(), - RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("sigterm-guest"), - }), - )) - .expect("query signal state"); - let ready = match signal_state.response.payload { - ResponsePayload::SignalStateResponse(snapshot) => { - snapshot.handlers.get(&(libc::SIGTERM as u32)) - == Some(&SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![], - flags: 0, - }) - } - other => panic!("unexpected signal state response: {other:?}"), - }; - if ready { - break; - } - - let _ = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(25)) - .expect("pump signal registration"); - assert!( - Instant::now() < registration_deadline, - "timed out waiting for SIGTERM handler registration" - ); - } - - sidecar - .dispatch_wire_blocking(wire_request( - 6, - ownership.clone(), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("sigterm-guest"), - signal: String::from("SIGTERM"), - }), - )) - .expect("deliver SIGTERM"); - - let deadline = Instant::now() + Duration::from_secs(10); - let mut saw_sigterm = false; - let mut exit_code = None; - - while exit_code.is_none() { - assert!( - Instant::now() < deadline, - "timed out waiting for SIGTERM delivery" - ); - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll sigterm events"); - let Some(event) = event else { continue }; - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == "sigterm-guest" => { - saw_sigterm |= chunk_contains(&output.chunk, "sigterm:1"); - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == "sigterm-guest" => { - exit_code = Some(exited.exit_code); - } - _ => {} - } - } - - assert!(saw_sigterm, "guest should observe SIGTERM"); - assert_eq!(exit_code, Some(0)); -} - -#[test] -fn process_table_delivers_sigchld_and_reaps_zombies_via_waitpid() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let parent = MockDriverProcess::new(); - let child = MockDriverProcess::new(); - let parent_pid = allocate_pid(&table); - let child_pid = allocate_pid(&table); - - table.register( - parent_pid, - "wasmvm", - "parent", - Vec::new(), - create_context(0), - parent.clone(), - ); - table.register( - child_pid, - "wasmvm", - "child", - Vec::new(), - create_context(parent_pid), - child.clone(), - ); - - assert_eq!( - table - .waitpid_for(parent_pid, -1, WaitPidFlags::WNOHANG) - .expect("initial waitpid should succeed"), - None - ); - - table - .kill(child_pid as i32, SIGTERM) - .expect("send SIGTERM to child"); - assert_eq!(child.kills(), vec![SIGTERM]); - assert_eq!(parent.kills(), vec![SIGCHLD]); - - let waited = table - .waitpid_for(parent_pid, -1, WaitPidFlags::empty()) - .expect("waitpid should succeed") - .expect("waitpid should report exited child"); - assert_eq!(waited.pid, child_pid); - assert_eq!(waited.status, 128 + SIGTERM); - assert_eq!(waited.event, ProcessWaitEvent::Exited); - assert!( - table.get(child_pid).is_none(), - "waitpid should clean up child zombies" - ); - - assert_process_error_code(table.waitpid(child_pid), "ESRCH"); -} - -#[test] -fn process_table_negative_pid_kill_targets_entire_process_groups() { - let table = ProcessTable::with_zombie_ttl(Duration::from_secs(3600)); - let leader = MockDriverProcess::new(); - let peer = MockDriverProcess::new(); - let leader_pid = allocate_pid(&table); - let peer_pid = allocate_pid(&table); - - table.register( - leader_pid, - "wasmvm", - "leader", - Vec::new(), - create_context(0), - leader.clone(), - ); - table.register( - peer_pid, - "wasmvm", - "peer", - Vec::new(), - create_context(leader_pid), - peer.clone(), - ); - table - .setpgid(peer_pid, leader_pid) - .expect("peer should join leader process group"); - - table - .kill(-(leader_pid as i32), SIGTERM) - .expect("group kill should succeed"); - - assert_eq!(leader.kills(), vec![SIGTERM]); - assert_eq!(peer.kills(), vec![SIGTERM]); -} diff --git a/crates/sidecar/tests/posix_path_repro.rs b/crates/sidecar/tests/posix_path_repro.rs deleted file mode 100644 index 426401765..000000000 --- a/crates/sidecar/tests/posix_path_repro.rs +++ /dev/null @@ -1,560 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - ConfigureVmRequest, GuestRuntimeKind, MountDescriptor, MountPluginDescriptor, RequestPayload, -}; -use serde_json::{json, Value}; -use std::collections::HashMap; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::time::Duration; -use support::{ - assert_node_available, authenticate_wire, collect_process_output_wire_with_timeout, - create_vm_wire_with_metadata, execute_wire, new_sidecar, open_session_wire, temp_dir, - wire_request, wire_vm, write_fixture, -}; - -const ALLOWED_NODE_BUILTINS: &[&str] = &[ - "buffer", - "child_process", - "console", - "constants", - "events", - "fs", - "path", - "stream", - "string_decoder", - "timers", - "url", - "util", -]; - -fn strip_benign_child_pid_warnings(stderr: &str) -> String { - stderr - .lines() - .filter(|line| !line.contains("WARN") || !line.contains("could not retrieve pid")) - .collect::>() - .join("\n") -} - -fn registry_command_root() -> PathBuf { - let repo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../..") - .canonicalize() - .expect("canonicalize repo root"); - let copied = repo_root.join("registry/software/coreutils/wasm"); - if copied.exists() { - return copied; - } - - let fallback = repo_root.join("registry/native/target/wasm32-wasip1/release/commands"); - if fallback.exists() { - return fallback; - } - - panic!( - "registry WASM commands are required for posix path repro tests: expected {} or {}", - copied.display(), - fallback.display() - ); -} - -fn configure_mounts( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - include_registry_commands: bool, - mut mounts: Vec, -) { - if include_registry_commands { - let command_root = registry_command_root(); - mounts.insert( - 0, - MountDescriptor { - guest_path: String::from("/__secure_exec/commands/0"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: serde_json::to_string(&json!({ - "hostPath": command_root, - "readOnly": true, - })) - .expect("serialize registry command mount config"), - }, - }, - ); - } - - sidecar - .dispatch_wire_blocking(wire_request( - 10, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts, - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure registry command mount"); -} - -fn run_host_probe(cwd: &Path, entrypoint: &Path) -> Value { - let output = Command::new("node") - .arg(entrypoint) - .current_dir(cwd) - .output() - .expect("run host node probe"); - - assert!( - output.status.success(), - "host probe failed with status {:?}\nstdout:\n{}\nstderr:\n{}", - output.status.code(), - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ); - - serde_json::from_slice(&output.stdout).expect("parse host probe JSON") -} - -fn run_guest_probe_process( - case_name: &str, - cwd: &Path, - entrypoint: &Path, - mount_registry_commands: bool, - extra_metadata: HashMap, - extra_mounts: Vec, -) -> (String, String, i32) { - let mut sidecar = new_sidecar(case_name); - let connection_id = authenticate_wire(&mut sidecar, &format!("conn-{case_name}")); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let allowed_builtins = - serde_json::to_string(ALLOWED_NODE_BUILTINS).expect("serialize builtin allowlist"); - let mut metadata = HashMap::from([( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - allowed_builtins, - )]); - metadata.extend(extra_metadata); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - cwd, - metadata, - ); - - if mount_registry_commands || !extra_mounts.is_empty() { - configure_mounts( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - mount_registry_commands, - extra_mounts, - ); - } - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - &format!("proc-{case_name}"), - GuestRuntimeKind::JavaScript, - entrypoint, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - &format!("proc-{case_name}"), - Duration::from_secs(30), - ); - - (stdout, stderr, exit_code) -} - -fn run_guest_probe( - case_name: &str, - cwd: &Path, - entrypoint: &Path, - mount_registry_commands: bool, - extra_metadata: HashMap, - extra_mounts: Vec, -) -> Value { - let (stdout, stderr, exit_code) = run_guest_probe_process( - case_name, - cwd, - entrypoint, - mount_registry_commands, - extra_metadata, - extra_mounts, - ); - - assert_eq!( - exit_code, 0, - "guest probe failed for {case_name}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stderr.trim().is_empty(), - "guest probe stderr for {case_name}:\n{stderr}" - ); - - serde_json::from_str(stdout.trim()).expect("parse guest probe JSON") -} - -fn write_probe(case_name: &str, script: &str) -> (PathBuf, PathBuf) { - let cwd = temp_dir(&format!("posix-path-repro-{case_name}")); - let entrypoint = cwd.join("entry.mjs"); - write_fixture(&entrypoint, script); - (cwd, entrypoint) -} - -fn assert_guest_matches_host(case_name: &str, script: &str) { - assert_node_available(); - - let (cwd, entrypoint) = write_probe(case_name, script); - let host = run_host_probe(&cwd, &entrypoint); - let guest = run_guest_probe( - case_name, - &cwd, - &entrypoint, - false, - HashMap::new(), - Vec::new(), - ); - - assert_eq!( - guest, - host, - "guest V8 result diverged from host Node for {case_name}\nhost: {}\nguest: {}", - serde_json::to_string_pretty(&host).expect("pretty host JSON"), - serde_json::to_string_pretty(&guest).expect("pretty guest JSON") - ); -} - -fn guest_shell_relative_paths_follow_cwd_after_cd() { - assert_node_available(); - - let (cwd, entrypoint) = write_probe( - "relative-shell", - r#" -import childProcess from "node:child_process"; -import fs from "node:fs"; - -const worktree = process.env.WORKTREE; -if (!worktree) { - throw new Error("WORKTREE env missing"); -} -const notePath = `${worktree}/note.txt`; -const writtenPath = `${worktree}/written.txt`; -fs.writeFileSync(notePath, "hello from repro\n"); -const childScript = ` -const fs = require("node:fs"); -console.log(process.cwd()); -console.log(fs.readFileSync("note.txt", "utf8").trimEnd()); -fs.writeFileSync("written.txt", "hi\\n"); -console.log(fs.readFileSync("written.txt", "utf8").trimEnd()); -`; - -const result = childProcess.spawnSync( - "node", - [ - "-e", - childScript, - ], - { - cwd: worktree, - encoding: "utf8", - }, -); - -const stdoutText = Buffer.from(result.stdout ?? []).toString("utf8"); -const stderrText = Buffer.from(result.stderr ?? []).toString("utf8"); -const stdoutLines = stdoutText - .split("\n") - .map((line) => line.trimEnd()) - .filter((line) => line.length > 0); -let written = null; -let writtenReadError = null; -try { - written = fs.readFileSync(writtenPath, "utf8"); -} catch (error) { - writtenReadError = { - code: error?.code ?? null, - path: error?.path ?? null, - }; -} - -console.log(JSON.stringify({ - worktree, - notePath, - writtenPath, - status: result.status, - signal: result.signal, - stdoutLines, - stderr: stderrText, - written, - writtenReadError, -})); -"#, - ); - let guest = run_guest_probe( - "relative-shell", - &cwd, - &entrypoint, - false, - HashMap::from([(String::from("env.WORKTREE"), String::from("/workspace"))]), - vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: serde_json::to_string(&json!({ - "hostPath": cwd, - "readOnly": false, - })) - .expect("serialize relative shell mount config"), - }, - }], - ); - - assert_eq!( - guest["status"], - json!(0), - "guest repro should exit cleanly: {guest}" - ); - assert_eq!( - guest["signal"], - Value::Null, - "guest repro should not be signaled: {guest}" - ); - assert_eq!( - guest["stdoutLines"], - json!([ - guest["worktree"] - .as_str() - .expect("worktree should be a string"), - "hello from repro", - "hi" - ]), - "guest shell should resolve relative paths inside the cwd: {guest}" - ); - assert_eq!( - strip_benign_child_pid_warnings( - guest["stderr"] - .as_str() - .expect("child stderr should be encoded as a string") - ), - "", - "guest shell should not emit unexpected stderr: {guest}" - ); - assert_eq!( - guest["written"], - json!("hi\n"), - "relative write should land in the cwd: {guest}" - ); -} - -fn guest_shell_absolute_paths_still_work_after_cd() { - assert_node_available(); - - let (cwd, entrypoint) = write_probe( - "absolute-shell", - r#" -import childProcess from "node:child_process"; -import fs from "node:fs"; -import path from "node:path"; - -const worktree = process.env.WORKTREE; -if (!worktree) { - throw new Error("WORKTREE env missing"); -} -const notePath = path.join(worktree, "note.txt"); -const writtenPath = path.join(worktree, "written.txt"); -fs.writeFileSync(notePath, "hello from repro\n"); -const childScript = ` -const fs = require("node:fs"); -console.log(process.cwd()); -console.log(fs.readFileSync(${JSON.stringify(notePath)}, "utf8").trimEnd()); -fs.writeFileSync(${JSON.stringify(writtenPath)}, "hi\\n"); -console.log(fs.readFileSync(${JSON.stringify(writtenPath)}, "utf8").trimEnd()); -`; - -const result = childProcess.spawnSync( - "node", - [ - "-e", - childScript, - ], - { - cwd: worktree, - encoding: "utf8", - }, -); - -const stdoutText = Buffer.from(result.stdout ?? []).toString("utf8"); -const stderrText = Buffer.from(result.stderr ?? []).toString("utf8"); -const stdoutLines = stdoutText - .split("\n") - .map((line) => line.trimEnd()) - .filter((line) => line.length > 0); -let written = null; -let writtenReadError = null; -try { - written = fs.readFileSync(writtenPath, "utf8"); -} catch (error) { - writtenReadError = { - code: error?.code ?? null, - path: error?.path ?? null, - }; -} - -console.log(JSON.stringify({ - worktree, - notePath, - writtenPath, - status: result.status, - signal: result.signal, - stdoutLines, - stderr: stderrText, - written, - writtenReadError, -})); -"#, - ); - let guest = run_guest_probe( - "absolute-shell", - &cwd, - &entrypoint, - false, - HashMap::from([(String::from("env.WORKTREE"), String::from("/workspace"))]), - vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: serde_json::to_string(&json!({ - "hostPath": cwd, - "readOnly": false, - })) - .expect("serialize absolute shell mount config"), - }, - }], - ); - - assert_eq!( - guest["status"], - json!(0), - "guest repro should exit cleanly: {guest}" - ); - assert_eq!( - guest["signal"], - Value::Null, - "guest repro should not be signaled: {guest}" - ); - assert_eq!( - guest["stdoutLines"], - json!([ - guest["worktree"] - .as_str() - .expect("worktree should be a string"), - "hello from repro", - "hi" - ]), - "guest shell should still succeed with absolute paths: {guest}" - ); - assert_eq!( - strip_benign_child_pid_warnings( - guest["stderr"] - .as_str() - .expect("child stderr should be encoded as a string") - ), - "", - "guest shell should not emit unexpected stderr: {guest}" - ); - assert_eq!( - guest["written"], - json!("hi\n"), - "absolute write should land in the cwd: {guest}" - ); -} - -fn node_path_posix_edge_cases_match_host_node() { - assert_guest_matches_host( - "path-builtins", - r#" -import path from "node:path"; - -console.log(JSON.stringify({ - resolve: path.resolve("/workspace/project/", "./src", "../tests", "spec.ts"), - join: path.join("/workspace", "project", "..", "project", "note.txt"), - normalize: path.normalize("/workspace//project/tests/../nested//file.txt"), - relativeSibling: path.relative("/workspace/project/src/", "/workspace/project/tests/spec.ts"), - relativeSame: path.relative("/workspace/project/", "/workspace/project"), - dirname: path.dirname("/workspace/project/tests/spec.ts/"), - basename: path.basename("/workspace/project/tests/spec.ts/"), -})); -"#, - ); -} - -fn filesystem_path_edge_cases_match_host_node() { - assert_guest_matches_host( - "filesystem-paths", - r#" -import fs from "node:fs"; -import path from "node:path"; - -fs.mkdirSync("workspace/nested", { recursive: true }); -fs.writeFileSync("workspace/nested/note.txt", "hello through nested path\n"); -fs.symlinkSync("nested", "workspace/link"); - -const viaRelative = fs.readFileSync("./workspace/./nested/../nested/note.txt", "utf8"); -const viaSymlinkTraversal = fs.readFileSync("workspace/link/../nested/note.txt", "utf8"); -const realpathRelativeToCwd = path.relative( - process.cwd(), - fs.realpathSync("workspace/link/../nested/note.txt"), -); -const readlink = fs.readlinkSync("workspace/link"); -const trailingSlashEntries = fs.readdirSync("workspace/nested/"); -const trailingSlashIsDir = fs.statSync("workspace/nested/").isDirectory(); -const lstatIsSymlink = fs.lstatSync("workspace/link").isSymbolicLink(); - -console.log(JSON.stringify({ - viaRelative, - viaSymlinkTraversal, - realpathRelativeToCwd, - readlink, - trailingSlashEntries, - trailingSlashIsDir, - lstatIsSymlink, -})); -"#, - ); -} - -#[test] -fn posix_path_repro_suite() { - // Multiple libtest cases in this V8-backed integration binary still trip - // teardown/init crashes, so keep the coverage in one top-level suite. - filesystem_path_edge_cases_match_host_node(); - guest_shell_absolute_paths_still_work_after_cd(); - guest_shell_relative_paths_follow_cwd_after_cd(); - node_path_posix_edge_cases_match_host_node(); -} diff --git a/crates/sidecar/tests/process_isolation.rs b/crates/sidecar/tests/process_isolation.rs deleted file mode 100644 index 4d2bcc39b..000000000 --- a/crates/sidecar/tests/process_isolation.rs +++ /dev/null @@ -1,142 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{EventPayload, GuestRuntimeKind, OwnershipScope, StreamChannel}; -use std::collections::BTreeMap; -use std::time::{Duration, Instant}; -use support::{ - assert_node_available, authenticate_wire, create_vm_wire, execute_wire, new_sidecar, - open_session_wire, temp_dir, wire_session, write_fixture, -}; - -const MAX_PROCESS_STDERR_BYTES: usize = 1024 * 1024; - -#[derive(Debug, Default)] -struct ProcessResult { - stderr: Vec, - exit_code: Option, -} - -fn append_stderr(result: &mut ProcessResult, chunk: &[u8]) { - assert!( - result.stderr.len().saturating_add(chunk.len()) <= MAX_PROCESS_STDERR_BYTES, - "process stderr exceeded {MAX_PROCESS_STDERR_BYTES} bytes" - ); - result.stderr.extend_from_slice(chunk); -} - -#[test] -fn concurrent_vm_processes_stay_isolated_with_vm_scoped_events() { - assert_node_available(); - - let mut sidecar = new_sidecar("process-isolation"); - let cwd = temp_dir("process-isolation-cwd"); - let slow_entry = cwd.join("slow.cjs"); - let fast_entry = cwd.join("fast.cjs"); - - write_fixture(&slow_entry, "setTimeout(() => {}, 150);\n"); - write_fixture(&fast_entry, "void 0;\n"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (slow_vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - let (fast_vm_id, _) = create_vm_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - execute_wire( - &mut sidecar, - 5, - &connection_id, - &session_id, - &slow_vm_id, - "proc", - GuestRuntimeKind::JavaScript, - &slow_entry, - Vec::new(), - ); - execute_wire( - &mut sidecar, - 6, - &connection_id, - &session_id, - &fast_vm_id, - "proc", - GuestRuntimeKind::JavaScript, - &fast_entry, - Vec::new(), - ); - - let mut results = BTreeMap::from([ - (slow_vm_id.clone(), ProcessResult::default()), - (fast_vm_id.clone(), ProcessResult::default()), - ]); - let deadline = Instant::now() + Duration::from_secs(10); - let ownership = wire_session(&connection_id, &session_id); - - while results.values().any(|result| result.exit_code.is_none()) { - assert!( - Instant::now() < deadline, - "timed out waiting for isolated process events" - ); - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll process-isolation event"); - let Some(event) = event else { continue }; - - let OwnershipScope::VmOwnership(vm_ownership) = event.ownership else { - panic!("expected VM-scoped process event"); - }; - let result = results - .get_mut(&vm_ownership.vm_id) - .unwrap_or_else(|| panic!("unexpected vm event for {}", vm_ownership.vm_id)); - - match event.payload { - EventPayload::ProcessOutputEvent(output) => { - assert_eq!(output.process_id, "proc"); - match output.channel { - StreamChannel::Stdout => {} - StreamChannel::Stderr => { - append_stderr(result, &output.chunk); - } - } - } - EventPayload::ProcessExitedEvent(exited) => { - assert_eq!(exited.process_id, "proc"); - result.exit_code = Some(exited.exit_code); - } - EventPayload::VmLifecycleEvent(_) - | EventPayload::StructuredEvent(_) - | EventPayload::ExtEnvelope(_) => {} - } - } - - let slow = results.get(&slow_vm_id).expect("slow vm result"); - let fast = results.get(&fast_vm_id).expect("fast vm result"); - - assert_eq!(slow.exit_code, Some(0)); - assert_eq!(fast.exit_code, Some(0)); - let slow_stderr = String::from_utf8_lossy(&slow.stderr); - let fast_stderr = String::from_utf8_lossy(&fast.stderr); - assert!( - slow_stderr.is_empty(), - "unexpected slow stderr: {}", - slow_stderr - ); - assert!( - fast_stderr.is_empty(), - "unexpected fast stderr: {}", - fast_stderr - ); -} diff --git a/crates/sidecar/tests/promisify_module_load.rs b/crates/sidecar/tests/promisify_module_load.rs deleted file mode 100644 index b44c9cde0..000000000 --- a/crates/sidecar/tests/promisify_module_load.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! Regression guard for issue #11: `util.promisify()` throws at module load. -//! -//! Original failure mode: a hand-rolled `@secure-exec/core` `util` polyfill exposed many -//! builtin functions as `undefined`. Adapter dependencies (extract-zip, get-stream) called -//! `promisify(undefined)` at module-load time, and the polyfill's `promisify` threw a -//! `TypeError` synchronously, crashing the whole module load before any application code ran. -//! -//! The downstream fix removed the eager throw (returning a function that rejects lazily). The -//! architecture has since changed: `node:util` now comes from the real upstream `util@0.12.5` -//! bundle (which still throws eagerly on non-functions, matching real Node), and the builtin -//! surface (`node:fs`, etc.) is now backed by real complete modules rather than `undefined` -//! stubs. -//! -//! This test encodes the CORRECT expected behavior in the redesigned world: -//! 1. `util.promisify(undefined)` throwing a `TypeError` must be *containable* by user code -//! (a try/catch) and must NOT crash the guest at module load (process still exits 0). -//! 2. The real-world root cause must stay fixed: `promisify` applied to a genuine builtin -//! function that the adapters use (`fs.readFile`) must return a function, proving the -//! builtin surface is complete enough that adapter deps never receive `undefined`. - -mod support; - -use std::collections::HashMap; -use std::time::Duration; - -use serde_json::Value; -use support::{ - assert_node_available, authenticate_wire, collect_process_output_wire_with_timeout, - create_vm_wire_with_metadata, dispose_vm_and_close_session_wire, execute_wire, new_sidecar, - open_session_wire, temp_dir, write_fixture, -}; - -const ALLOWED_NODE_BUILTINS: &[&str] = &["fs", "util"]; - -const GUEST_SCRIPT: &str = r#" -import { createRequire } from "node:module"; - -const require = createRequire(import.meta.url); - -// `node:util` and `node:fs` are resolved at module load. If `util.promisify` -// throws synchronously on the eager TypeError path *outside* of a guard, this -// whole module would fail to load and the process would crash (non-zero exit), -// reproducing issue #11. -const util = require("node:util"); -const fs = require("node:fs"); - -// (1) The eager TypeError must be containable by user code rather than tearing -// down the module/process. This mirrors `promisify(undefined)` which is what -// the old incomplete polyfill handed to extract-zip / get-stream at load time. -let undefinedThrewTypeError = false; -try { - util.promisify(undefined); -} catch (error) { - undefinedThrewTypeError = error != null && error.name === "TypeError"; -} - -// (2) Root-cause regression guard: a genuine builtin function that adapters -// actually promisify must be a real function (not an `undefined` stub), so -// `promisify` yields a usable function. -const readFileIsFunction = typeof fs.readFile === "function"; -const promisifiedReadFileIsFunction = - typeof util.promisify(fs.readFile) === "function"; - -console.log( - JSON.stringify({ - undefinedThrewTypeError, - readFileIsFunction, - promisifiedReadFileIsFunction, - }), -); -"#; - -fn run_guest(case_name: &str, script: &str, allowed_builtins: &[&str]) -> (Value, String, i32) { - assert_node_available(); - - let cwd = temp_dir(&format!("promisify-{case_name}")); - let entrypoint = cwd.join("entry.mjs"); - write_fixture(&entrypoint, script); - - let mut sidecar = new_sidecar(case_name); - let connection_id = authenticate_wire(&mut sidecar, &format!("conn-{case_name}")); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - - let mut metadata = HashMap::new(); - metadata.insert( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - serde_json::to_string(allowed_builtins).expect("serialize builtin allowlist"), - ); - - let (vm_id, _create) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - secure_exec_sidecar::wire::GuestRuntimeKind::JavaScript, - &cwd, - metadata, - ); - - let process_id = format!("proc-{case_name}"); - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - &process_id, - secure_exec_sidecar::wire::GuestRuntimeKind::JavaScript, - &entrypoint, - Vec::new(), - ); - - let (stdout, stderr, exit_code) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - &process_id, - Duration::from_secs(30), - ); - - dispose_vm_and_close_session_wire(&mut sidecar, &connection_id, &session_id, &vm_id); - - let parsed = serde_json::from_str(stdout.trim()) - .unwrap_or_else(|_| panic!("parse guest JSON\nstdout:\n{stdout}\nstderr:\n{stderr}")); - (parsed, stderr, exit_code) -} - -#[test] -fn promisify_undefined_does_not_crash_module_load() { - let (parsed, stderr, exit_code) = - run_guest("promisify-module-load", GUEST_SCRIPT, ALLOWED_NODE_BUILTINS); - - // The module must have loaded and the process must have exited cleanly: the - // eager TypeError from `promisify(undefined)` must be containable, not fatal. - assert_eq!( - exit_code, 0, - "guest module load crashed (issue #11)\nstderr:\n{stderr}\nparsed:\n{parsed}" - ); - - assert_eq!( - parsed["undefinedThrewTypeError"], - Value::Bool(true), - "promisify(undefined) should raise a containable TypeError, parsed={parsed}" - ); - - // Root-cause guard: the builtin surface must be complete, so adapter deps - // never receive `undefined` to promisify. - assert_eq!( - parsed["readFileIsFunction"], - Value::Bool(true), - "fs.readFile must be a real function, parsed={parsed}" - ); - assert_eq!( - parsed["promisifiedReadFileIsFunction"], - Value::Bool(true), - "promisify(fs.readFile) must return a function, parsed={parsed}" - ); -} diff --git a/crates/sidecar/tests/protocol.rs b/crates/sidecar/tests/protocol.rs deleted file mode 100644 index a58396233..000000000 --- a/crates/sidecar/tests/protocol.rs +++ /dev/null @@ -1,1007 +0,0 @@ -use secure_exec_sidecar::protocol::{ - validate_frame, AuthenticateRequest, AuthenticatedResponse, CreateVmRequest, EventFrame, - EventPayload, ExtEnvelope, GetZombieTimerCountRequest, GuestFilesystemCallRequest, - GuestFilesystemOperation, GuestRuntimeKind, HostCallbackRequest, HostCallbackResultResponse, - JsBridgeResultResponse, NativeFrameCodec, NativePayloadCodec, OpenSessionRequest, - OwnershipScope, PatternPermissionScope, PermissionMode, PermissionsPolicy, ProcessOutputEvent, - ProcessStartedResponse, ProjectedModuleDescriptor, ProtocolCodecError, ProtocolFrame, - RequestFrame, RequestPayload, ResponseFrame, ResponsePayload, ResponseTracker, - ResponseTrackerError, RootFilesystemDescriptor, RootFilesystemEntry, RootFilesystemEntryKind, - RootFilesystemLowerDescriptor, SidecarPlacement, SidecarPlacementShared, SidecarRequestFrame, - SidecarRequestPayload, SidecarResponseFrame, SidecarResponsePayload, SidecarResponseTracker, - SidecarResponseTrackerError, SnapshotRootFilesystemLower, SoftwareDescriptor, StreamChannel, - StructuredEvent, VmLifecycleEvent, VmLifecycleState, WriteStdinRequest, -}; -use serde_json::json; -use std::hint::black_box; -use std::time::Instant; - -const BARE_SCHEMA_V1: &str = - include_str!("../../sidecar-protocol/protocol/secure_exec_sidecar_v1.bare"); -const BARE_MIGRATION_PLAN: &str = include_str!("../../sidecar-protocol/protocol/README.md"); - -#[test] -fn guest_runtime_kind_round_trips_through_generated_codec() { - // `GuestRuntimeKind` is now the generated wire type. The wire contract is BARE - // (positional tags), which is what round-trips here. The previous snake_case - // human-readable JSON form was a hand-codec artifact with no production consumer - // (the TS side keeps its own live snake_case map under the §6c facade). - let encoded = serde_bare::to_vec(&GuestRuntimeKind::Python).expect("bare encode runtime"); - let decoded: GuestRuntimeKind = serde_bare::from_slice(&encoded).expect("bare decode runtime"); - assert_eq!(decoded, GuestRuntimeKind::Python); -} - -#[test] -fn codec_round_trips_authenticated_setup_and_session_messages() { - let codec = NativeFrameCodec::default(); - let frame = ProtocolFrame::Request(RequestFrame::new( - 1, - OwnershipScope::connection("conn-1"), - RequestPayload::Authenticate(AuthenticateRequest { - client_name: "packages/core".to_string(), - auth_token: "signed-token".to_string(), - protocol_version: secure_exec_sidecar::wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - )); - - let encoded = codec.encode(&frame).expect("encode"); - let decoded = codec.decode(&encoded).expect("decode"); - - assert_eq!(decoded, frame); - - let session_frame = ProtocolFrame::Request(RequestFrame::new( - 2, - OwnershipScope::connection("conn-1"), - RequestPayload::OpenSession(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: Some("default".to_string()), - }), - metadata: std::collections::HashMap::from([( - String::from("owner"), - String::from("packages/core"), - )]), - }), - )); - - let encoded = codec.encode(&session_frame).expect("encode session"); - let decoded = codec.decode(&encoded).expect("decode session"); - - assert_eq!(decoded, session_frame); -} - -#[test] -fn codec_round_trips_vm_scoped_events_and_responses() { - let codec = NativeFrameCodec::default(); - let response = ProtocolFrame::Response(ResponseFrame::new( - 44, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - ResponsePayload::ProcessStarted(ProcessStartedResponse { - process_id: "proc-1".to_string(), - pid: None, - }), - )); - - let event = ProtocolFrame::Event(EventFrame::new( - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - secure_exec_sidecar::protocol::EventPayload::VmLifecycle(VmLifecycleEvent { - state: VmLifecycleState::Ready, - }), - )); - - assert_eq!( - codec.decode(&codec.encode(&response).unwrap()).unwrap(), - response - ); - assert_eq!(codec.decode(&codec.encode(&event).unwrap()).unwrap(), event); -} - -#[test] -#[ignore = "manual microbench for Ext envelope event encoding overhead"] -fn ext_envelope_event_encoding_microbench() { - let codec = NativeFrameCodec::with_payload_codec(1024 * 1024, NativePayloadCodec::Bare); - let ownership = OwnershipScope::vm("conn-1", "session-1", "vm-1"); - let process_output = ProcessOutputEvent { - process_id: String::from("proc-1"), - channel: StreamChannel::Stdout, - chunk: vec![b'x'; 256], - }; - let direct_frame = ProtocolFrame::Event(EventFrame::new( - ownership.clone(), - EventPayload::ProcessOutput(process_output.clone()), - )); - let iterations = 200_000; - - let direct_start = Instant::now(); - let mut direct_bytes = 0usize; - for _ in 0..iterations { - let encoded = codec - .encode(black_box(&direct_frame)) - .expect("encode direct"); - direct_bytes = direct_bytes.wrapping_add(encoded.len()); - black_box(encoded); - } - let direct_elapsed = direct_start.elapsed(); - - let ext_start = Instant::now(); - let mut ext_bytes = 0usize; - for _ in 0..iterations { - let inner = serde_bare::to_vec(black_box(&process_output)).expect("encode inner output"); - let ext_frame = ProtocolFrame::Event(EventFrame::new( - ownership.clone(), - EventPayload::Ext(ExtEnvelope { - namespace: String::from("dev.rivet.secure-exec.acp"), - payload: inner, - }), - )); - let encoded = codec.encode(black_box(&ext_frame)).expect("encode ext"); - ext_bytes = ext_bytes.wrapping_add(encoded.len()); - black_box(encoded); - } - let ext_elapsed = ext_start.elapsed(); - - let direct_ns = direct_elapsed.as_nanos() as f64 / iterations as f64; - let ext_ns = ext_elapsed.as_nanos() as f64 / iterations as f64; - println!( - "ext_envelope_event_encoding_microbench direct_ns_per_event={direct_ns:.2} ext_ns_per_event={ext_ns:.2} ratio={:.2} direct_avg_bytes={:.1} ext_avg_bytes={:.1}", - ext_ns / direct_ns, - direct_bytes as f64 / iterations as f64, - ext_bytes as f64 / iterations as f64 - ); -} - -#[test] -fn codec_round_trips_sidecar_request_and_response_frames() { - let codec = NativeFrameCodec::default(); - let request = ProtocolFrame::SidecarRequest(SidecarRequestFrame::new( - -7, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarRequestPayload::HostCallback(HostCallbackRequest { - invocation_id: "invoke-1".to_string(), - callback_key: "toolkit:tool".to_string(), - input: json!({ "prompt": "ping" }).to_string(), - timeout_ms: 5_000, - }), - )); - let response = ProtocolFrame::SidecarResponse(SidecarResponseFrame::new( - -7, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarResponsePayload::HostCallbackResult(HostCallbackResultResponse { - invocation_id: "invoke-1".to_string(), - result: Some(json!({ "ok": true }).to_string()), - error: None, - }), - )); - - assert_eq!( - codec.decode(&codec.encode(&request).unwrap()).unwrap(), - request - ); - assert_eq!( - codec.decode(&codec.encode(&response).unwrap()).unwrap(), - response - ); -} - -#[test] -fn bare_codec_round_trips_frames_with_json_utf8_fields() { - let codec = NativeFrameCodec::with_payload_codec(1024 * 1024, NativePayloadCodec::Bare); - let frame = ProtocolFrame::SidecarRequest(SidecarRequestFrame::new( - -12, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarRequestPayload::HostCallback(HostCallbackRequest { - invocation_id: "invoke-12".to_string(), - callback_key: "toolkit:search".to_string(), - input: json!({ - "cursor": "abc123", - "includeSchema": true, - }) - .to_string(), - timeout_ms: 2_000, - }), - )); - - let encoded = codec.encode(&frame).expect("encode bare frame"); - assert_eq!( - encoded[4], 3, - "BARE sidecar_request frames should start with tag 3" - ); - - let decoded = codec.decode(&encoded).expect("decode bare frame"); - assert_eq!(decoded, frame); -} - -#[test] -fn bare_codec_round_trips_authenticate_request_frames() { - let codec = NativeFrameCodec::with_payload_codec(1024 * 1024, NativePayloadCodec::Bare); - let frame = ProtocolFrame::Request(RequestFrame::new( - 1, - OwnershipScope::connection("client-hint"), - RequestPayload::Authenticate(AuthenticateRequest { - client_name: "packages-core-vitest".to_string(), - auth_token: "packages-core-vitest-token".to_string(), - protocol_version: secure_exec_sidecar::wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - )); - - let encoded = codec - .encode(&frame) - .expect("encode bare authenticate request"); - let decoded = codec - .decode(&encoded) - .expect("decode bare authenticate request"); - - assert_eq!(decoded, frame); -} - -#[test] -fn json_codec_round_trips_guest_filesystem_requests_with_optional_fields() { - let codec = NativeFrameCodec::default(); - let frame = ProtocolFrame::Request(RequestFrame::new( - 17, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - RequestPayload::GuestFilesystemCall(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Truncate, - path: String::from("/workspace/hard.txt"), - destination_path: Some(String::from("/workspace/note.txt")), - target: Some(String::from("/workspace/target.txt")), - content: Some(String::from("stdio-sidecar-fs")), - encoding: None, - recursive: true, - max_depth: None, - mode: Some(0o644), - uid: Some(1000), - gid: Some(1000), - atime_ms: Some(1_700_000_000_000), - mtime_ms: Some(1_710_000_000_000), - len: Some(5), - offset: None, - }), - )); - - let encoded = codec - .encode(&frame) - .expect("encode json guest filesystem request"); - let decoded = codec - .decode(&encoded) - .expect("decode json guest filesystem request"); - - assert_eq!(decoded, frame); -} - -#[test] -fn bare_codec_round_trips_guest_filesystem_requests_with_optional_fields() { - let codec = NativeFrameCodec::with_payload_codec(1024 * 1024, NativePayloadCodec::Bare); - let frame = ProtocolFrame::Request(RequestFrame::new( - 17, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - RequestPayload::GuestFilesystemCall(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Truncate, - path: String::from("/workspace/hard.txt"), - destination_path: Some(String::from("/workspace/note.txt")), - target: Some(String::from("/workspace/target.txt")), - content: Some(String::from("stdio-sidecar-fs")), - encoding: None, - recursive: true, - max_depth: None, - mode: Some(0o644), - uid: Some(1000), - gid: Some(1000), - atime_ms: Some(1_700_000_000_000), - mtime_ms: Some(1_710_000_000_000), - len: Some(5), - offset: None, - }), - )); - - let encoded = codec - .encode(&frame) - .expect("encode bare guest filesystem request"); - let decoded = codec - .decode(&encoded) - .expect("decode bare guest filesystem request"); - - assert_eq!(decoded, frame); -} - -#[test] -fn bare_codec_round_trips_root_filesystem_lower_descriptors() { - let lower = RootFilesystemLowerDescriptor::BundledBaseFilesystemLower; - let encoded = serde_bare::to_vec(&lower).expect("encode bare root filesystem lower"); - let decoded: RootFilesystemLowerDescriptor = - serde_bare::from_slice(&encoded).expect("decode bare root filesystem lower"); - - assert_eq!(decoded, lower); -} - -#[test] -fn bare_codec_round_trips_root_filesystem_descriptors_with_snapshot_lowers() { - let descriptor = RootFilesystemDescriptor { - disable_default_base_layer: true, - lowers: vec![ - RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - SnapshotRootFilesystemLower { - entries: vec![RootFilesystemEntry { - path: String::from("/workspace"), - kind: RootFilesystemEntryKind::Directory, - ..Default::default() - }], - }, - ), - RootFilesystemLowerDescriptor::BundledBaseFilesystemLower, - ], - ..Default::default() - }; - - let encoded = serde_bare::to_vec(&descriptor).expect("encode bare root filesystem descriptor"); - let decoded: RootFilesystemDescriptor = - serde_bare::from_slice(&encoded).expect("decode bare root filesystem descriptor"); - - assert_eq!(decoded, descriptor); -} - -#[test] -fn bare_codec_round_trips_create_vm_requests_with_snapshot_lowers() { - let codec = NativeFrameCodec::with_payload_codec(1024 * 1024, NativePayloadCodec::Bare); - let frame = ProtocolFrame::Request(RequestFrame::new( - 2, - OwnershipScope::session("conn-1", "session-1"), - RequestPayload::CreateVm(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - std::collections::HashMap::from([(String::from("cwd"), String::from("/workspace"))]), - RootFilesystemDescriptor { - disable_default_base_layer: true, - lowers: vec![ - RootFilesystemLowerDescriptor::SnapshotRootFilesystemLower( - SnapshotRootFilesystemLower { - entries: vec![RootFilesystemEntry { - path: String::from("/workspace"), - kind: RootFilesystemEntryKind::Directory, - ..Default::default() - }], - }, - ), - RootFilesystemLowerDescriptor::BundledBaseFilesystemLower, - ], - ..Default::default() - }, - None, - )), - )); - - let encoded = codec.encode(&frame).expect("encode bare create_vm request"); - let decoded = codec - .decode(&encoded) - .expect("decode bare create_vm request"); - - assert_eq!(decoded, frame); -} - -#[test] -fn codec_auto_detects_json_and_bare_payloads() { - let json_codec = NativeFrameCodec::default(); - let bare_codec = NativeFrameCodec::with_payload_codec(1024 * 1024, NativePayloadCodec::Bare); - let frame = ProtocolFrame::SidecarRequest(SidecarRequestFrame::new( - -11, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarRequestPayload::HostCallback(HostCallbackRequest { - invocation_id: "invoke-1".to_string(), - callback_key: "toolkit:search".to_string(), - input: json!({ "query": "ping" }).to_string(), - timeout_ms: 2_000, - }), - )); - - let json_encoded = json_codec.encode(&frame).expect("encode json frame"); - let bare_encoded = bare_codec.encode(&frame).expect("encode bare frame"); - - assert_eq!(json_codec.decode(&json_encoded).unwrap(), frame); - assert_eq!(json_codec.decode(&bare_encoded).unwrap(), frame); -} - -#[test] -fn codec_rejects_invalid_ownership_binding() { - let frame = ProtocolFrame::Request(RequestFrame::new( - 9, - OwnershipScope::connection("conn-1"), - RequestPayload::CreateVm(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - std::collections::HashMap::new(), - Default::default(), - None, - )), - )); - - assert_eq!( - validate_frame(&frame), - Err(ProtocolCodecError::InvalidOwnershipScope { - required: secure_exec_sidecar::protocol::OwnershipRequirement::Session, - actual: secure_exec_sidecar::protocol::OwnershipRequirement::Connection, - }), - ); -} - -#[test] -fn codec_rejects_frames_over_the_configured_limit() { - let codec = NativeFrameCodec::new(64); - let frame = ProtocolFrame::Request(RequestFrame::new( - 11, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - RequestPayload::WriteStdin(WriteStdinRequest { - process_id: "proc-1".to_string(), - chunk: "x".repeat(256).into_bytes(), - }), - )); - - assert!(matches!( - codec.encode(&frame), - Err(ProtocolCodecError::FrameTooLarge { .. }) - )); - - let oversized_declared_len = 65_u32; - let mut encoded = oversized_declared_len.to_be_bytes().to_vec(); - encoded.extend(std::iter::repeat_n(0_u8, oversized_declared_len as usize)); - assert_eq!( - codec.decode(&encoded), - Err(ProtocolCodecError::FrameTooLarge { - size: oversized_declared_len as usize, - max: 64, - }) - ); -} - -#[test] -fn response_tracker_enforces_request_response_correlation_and_duplicate_hardening() { - let mut tracker = ResponseTracker::default(); - let request = RequestFrame::new( - 77, - OwnershipScope::session("conn-1", "session-1"), - RequestPayload::CreateVm(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - std::collections::HashMap::new(), - Default::default(), - None, - )), - ); - tracker - .register_request(&request) - .expect("register request"); - - let response = ResponseFrame::new( - 77, - OwnershipScope::session("conn-1", "session-1"), - ResponsePayload::VmCreated(secure_exec_sidecar::protocol::VmCreatedResponse { - vm_id: "vm-1".to_string(), - }), - ); - tracker.accept_response(&response).expect("accept response"); - - assert_eq!( - tracker.accept_response(&response), - Err(ResponseTrackerError::DuplicateResponse { request_id: 77 }), - ); - assert_eq!( - tracker.accept_response(&ResponseFrame::new( - 88, - OwnershipScope::session("conn-1", "session-1"), - ResponsePayload::VmCreated(secure_exec_sidecar::protocol::VmCreatedResponse { - vm_id: "vm-2".to_string(), - }), - )), - Err(ResponseTrackerError::UnmatchedResponse { request_id: 88 }), - ); -} - -#[test] -fn response_tracker_rejects_kind_and_ownership_mismatches() { - let mut tracker = ResponseTracker::default(); - let request = RequestFrame::new( - 90, - OwnershipScope::session("conn-1", "session-1"), - RequestPayload::CreateVm(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::WebAssembly, - std::collections::HashMap::from([(String::from("runtime"), String::from("wasm"))]), - Default::default(), - None, - )), - ); - tracker - .register_request(&request) - .expect("register request"); - - assert_eq!( - tracker.accept_response(&ResponseFrame::new( - 90, - OwnershipScope::session("conn-1", "session-2"), - ResponsePayload::VmCreated(secure_exec_sidecar::protocol::VmCreatedResponse { - vm_id: "vm-1".to_string(), - }), - )), - Err(ResponseTrackerError::OwnershipMismatch { - request_id: 90, - expected: Box::new(OwnershipScope::session("conn-1", "session-1")), - actual: Box::new(OwnershipScope::session("conn-1", "session-2")), - }), - ); - tracker - .accept_response(&ResponseFrame::new( - 90, - OwnershipScope::session("conn-1", "session-1"), - ResponsePayload::VmCreated(secure_exec_sidecar::protocol::VmCreatedResponse { - vm_id: "vm-1".to_string(), - }), - )) - .expect("valid response should still be pending after ownership mismatch"); - - let mut tracker = ResponseTracker::default(); - tracker - .register_request(&request) - .expect("register request again"); - - assert_eq!( - tracker.accept_response(&ResponseFrame::new( - 90, - OwnershipScope::session("conn-1", "session-1"), - ResponsePayload::Authenticated(AuthenticatedResponse { - sidecar_id: "sidecar-1".to_string(), - connection_id: "conn-1".to_string(), - max_frame_bytes: 1024, - }), - )), - Err(ResponseTrackerError::ResponseKindMismatch { - request_id: 90, - expected: "vm_created".to_string(), - actual: "authenticated".to_string(), - }), - ); - tracker - .accept_response(&ResponseFrame::new( - 90, - OwnershipScope::session("conn-1", "session-1"), - ResponsePayload::VmCreated(secure_exec_sidecar::protocol::VmCreatedResponse { - vm_id: "vm-1".to_string(), - }), - )) - .expect("valid response should still be pending after kind mismatch"); -} - -#[test] -fn response_tracker_accepts_zombie_timer_count_responses() { - let mut tracker = ResponseTracker::default(); - let request = RequestFrame::new( - 91, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - RequestPayload::GetZombieTimerCount(GetZombieTimerCountRequest::default()), - ); - tracker - .register_request(&request) - .expect("register request"); - - tracker - .accept_response(&ResponseFrame::new( - 91, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - ResponsePayload::ZombieTimerCount( - secure_exec_sidecar::protocol::ZombieTimerCountResponse { count: 2 }, - ), - )) - .expect("accept response"); -} - -#[test] -fn response_tracker_caps_completed_entries() { - let mut tracker = ResponseTracker::with_completed_cap(3); - - for request_id in 1..=10 { - let request = RequestFrame::new( - request_id, - OwnershipScope::connection("conn-1"), - RequestPayload::Authenticate(AuthenticateRequest { - client_name: "packages/core".to_string(), - auth_token: format!("token-{request_id}"), - protocol_version: secure_exec_sidecar::wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - ); - tracker - .register_request(&request) - .expect("register request"); - tracker - .accept_response(&ResponseFrame::new( - request_id, - OwnershipScope::connection("conn-1"), - ResponsePayload::Authenticated(AuthenticatedResponse { - sidecar_id: "sidecar-1".to_string(), - connection_id: "conn-1".to_string(), - max_frame_bytes: 1024, - }), - )) - .expect("accept response"); - - assert!( - tracker.completed_count() <= 3, - "completed set should stay bounded" - ); - } - - assert_eq!(tracker.completed_count(), 3); -} - -#[test] -fn sidecar_response_tracker_enforces_request_response_correlation() { - let mut tracker = SidecarResponseTracker::default(); - let request = SidecarRequestFrame::new( - -9, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarRequestPayload::HostCallback(HostCallbackRequest { - invocation_id: "invoke-1".to_string(), - callback_key: "toolkit:tool".to_string(), - input: json!({ "value": 1 }).to_string(), - timeout_ms: 1_000, - }), - ); - tracker - .register_request(&request) - .expect("register sidecar request"); - - tracker - .accept_response(&SidecarResponseFrame::new( - -9, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarResponsePayload::HostCallbackResult(HostCallbackResultResponse { - invocation_id: "invoke-1".to_string(), - result: Some(json!({ "ok": true }).to_string()), - error: None, - }), - )) - .expect("accept sidecar response"); - - assert_eq!( - tracker.accept_response(&SidecarResponseFrame::new( - -9, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarResponsePayload::HostCallbackResult(HostCallbackResultResponse { - invocation_id: "invoke-1".to_string(), - result: None, - error: Some("duplicate".to_string()), - }), - )), - Err(SidecarResponseTrackerError::DuplicateResponse { request_id: -9 }), - ); -} - -#[test] -fn sidecar_response_tracker_keeps_pending_entries_after_mismatches() { - let request = SidecarRequestFrame::new( - -10, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarRequestPayload::HostCallback(HostCallbackRequest { - invocation_id: "invoke-10".to_string(), - callback_key: "toolkit:tool".to_string(), - input: json!({ "value": 10 }).to_string(), - timeout_ms: 1_000, - }), - ); - - let mut tracker = SidecarResponseTracker::default(); - tracker - .register_request(&request) - .expect("register sidecar request"); - assert_eq!( - tracker.accept_response(&SidecarResponseFrame::new( - -10, - OwnershipScope::vm("conn-1", "session-1", "vm-2"), - SidecarResponsePayload::HostCallbackResult(HostCallbackResultResponse { - invocation_id: "invoke-10".to_string(), - result: Some(json!({ "ok": true }).to_string()), - error: None, - }), - )), - Err(SidecarResponseTrackerError::OwnershipMismatch { - request_id: -10, - expected: Box::new(OwnershipScope::vm("conn-1", "session-1", "vm-1")), - actual: Box::new(OwnershipScope::vm("conn-1", "session-1", "vm-2")), - }), - ); - tracker - .accept_response(&SidecarResponseFrame::new( - -10, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarResponsePayload::HostCallbackResult(HostCallbackResultResponse { - invocation_id: "invoke-10".to_string(), - result: Some(json!({ "ok": true }).to_string()), - error: None, - }), - )) - .expect("valid sidecar response should still be pending after ownership mismatch"); - - let mut tracker = SidecarResponseTracker::default(); - tracker - .register_request(&request) - .expect("register sidecar request again"); - assert_eq!( - tracker.accept_response(&SidecarResponseFrame::new( - -10, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarResponsePayload::JsBridgeResult(JsBridgeResultResponse { - call_id: "bridge-10".to_string(), - result: Some(json!({ "ok": true }).to_string()), - error: None, - }), - )), - Err(SidecarResponseTrackerError::ResponseKindMismatch { - request_id: -10, - expected: "host_callback_result".to_string(), - actual: "js_bridge_result".to_string(), - }), - ); - tracker - .accept_response(&SidecarResponseFrame::new( - -10, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarResponsePayload::HostCallbackResult(HostCallbackResultResponse { - invocation_id: "invoke-10".to_string(), - result: Some(json!({ "ok": true }).to_string()), - error: None, - }), - )) - .expect("valid sidecar response should still be pending after kind mismatch"); -} - -#[test] -fn sidecar_response_tracker_caps_completed_entries() { - let mut tracker = SidecarResponseTracker::with_completed_cap(3); - - for sequence in 1..=10 { - let request_id = -sequence; - let request = SidecarRequestFrame::new( - request_id, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarRequestPayload::HostCallback(HostCallbackRequest { - invocation_id: format!("invoke-{sequence}"), - callback_key: "toolkit:tool".to_string(), - input: json!({ "value": sequence }).to_string(), - timeout_ms: 1_000, - }), - ); - tracker - .register_request(&request) - .expect("register sidecar request"); - tracker - .accept_response(&SidecarResponseFrame::new( - request_id, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarResponsePayload::HostCallbackResult(HostCallbackResultResponse { - invocation_id: format!("invoke-{sequence}"), - result: Some(json!({ "ok": true }).to_string()), - error: None, - }), - )) - .expect("accept sidecar response"); - - assert!( - tracker.completed_count() <= 3, - "sidecar completed set should stay bounded" - ); - } - - assert_eq!(tracker.completed_count(), 3); -} - -#[test] -fn codec_rejects_request_id_direction_mismatches() { - let zero_request = ProtocolFrame::Request(RequestFrame::new( - 0, - OwnershipScope::connection("conn-1"), - RequestPayload::Authenticate(AuthenticateRequest { - client_name: "packages/core".to_string(), - auth_token: "signed-token".to_string(), - protocol_version: secure_exec_sidecar::wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - )); - assert_eq!( - validate_frame(&zero_request), - Err(ProtocolCodecError::InvalidRequestId) - ); - - let host_response = ProtocolFrame::Response(ResponseFrame::new( - -1, - OwnershipScope::connection("conn-1"), - ResponsePayload::Authenticated(AuthenticatedResponse { - sidecar_id: "sidecar-1".to_string(), - connection_id: "conn-1".to_string(), - max_frame_bytes: 1024, - }), - )); - assert_eq!( - validate_frame(&host_response), - Err(ProtocolCodecError::InvalidRequestDirection { - request_id: -1, - expected: secure_exec_sidecar::protocol::RequestDirection::Host, - }), - ); - - let sidecar_request = ProtocolFrame::SidecarRequest(SidecarRequestFrame::new( - 1, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - SidecarRequestPayload::HostCallback(HostCallbackRequest { - invocation_id: "invoke-2".to_string(), - callback_key: "toolkit:tool".to_string(), - input: json!({}).to_string(), - timeout_ms: 100, - }), - )); - assert_eq!( - validate_frame(&sidecar_request), - Err(ProtocolCodecError::InvalidRequestDirection { - request_id: 1, - expected: secure_exec_sidecar::protocol::RequestDirection::Sidecar, - }), - ); -} - -#[test] -fn schema_supports_configuration_and_structured_events() { - let frame = ProtocolFrame::Request(RequestFrame::new( - 23, - OwnershipScope::vm("conn-1", "session-1", "vm-1"), - RequestPayload::ConfigureVm(secure_exec_sidecar::protocol::ConfigureVmRequest { - mounts: vec![secure_exec_sidecar::protocol::MountDescriptor { - guest_path: "/workspace".to_string(), - read_only: false, - plugin: secure_exec_sidecar::protocol::MountPluginDescriptor { - id: "host_dir".to_string(), - config: json!({ - "hostPath": "/tmp/project", - "readOnly": false, - }) - .to_string(), - }, - }], - software: vec![SoftwareDescriptor { - package_name: "@secure-exec/core".to_string(), - root: "/pkg".to_string(), - }], - permissions: Some(PermissionsPolicy { - fs: None, - network: Some(PatternPermissionScope::PermissionMode(PermissionMode::Ask)), - child_process: None, - process: None, - env: None, - binding: None, - }), - module_access_cwd: None, - instructions: vec!["keep timing mitigation enabled".to_string()], - projected_modules: vec![ProjectedModuleDescriptor { - package_name: "workspace".to_string(), - entrypoint: "/workspace/index.ts".to_string(), - }], - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )); - - validate_frame(&frame).expect("configuration request is valid"); - - let event = EventFrame::new( - OwnershipScope::session("conn-1", "session-1"), - secure_exec_sidecar::protocol::EventPayload::Structured(StructuredEvent { - name: "guest.lifecycle".to_string(), - detail: std::collections::HashMap::from([( - String::from("state"), - String::from("ready"), - )]), - }), - ); - validate_frame(&ProtocolFrame::Event(event)).expect("structured event is valid"); -} - -#[test] -fn checked_in_bare_schema_covers_all_top_level_frame_payload_types() { - for type_name in [ - "type ProtocolFrame union {", - "type RequestPayload union {", - "type ResponsePayload union {", - "type EventPayload union {", - "type SidecarRequestPayload union {", - "type SidecarResponsePayload union {", - "AuthenticateRequest", - "OpenSessionRequest", - "CreateVmRequest", - "DisposeVmRequest", - "BootstrapRootFilesystemRequest", - "ConfigureVmRequest", - "RegisterHostCallbacksRequest", - "CreateLayerRequest", - "SealLayerRequest", - "ImportSnapshotRequest", - "ExportSnapshotRequest", - "CreateOverlayRequest", - "GuestFilesystemCallRequest", - "SnapshotRootFilesystemRequest", - "ExecuteRequest", - "WriteStdinRequest", - "CloseStdinRequest", - "KillProcessRequest", - "GetProcessSnapshotRequest", - "GetResourceSnapshotRequest", - "FindListenerRequest", - "FindBoundUdpRequest", - "GetSignalStateRequest", - "GetZombieTimerCountRequest", - "HostFilesystemCallRequest", - "PersistenceLoadRequest", - "PersistenceFlushRequest", - "VmFetchRequest", - "ExtEnvelope", - "AuthenticatedResponse", - "SessionOpenedResponse", - "VmCreatedResponse", - "VmDisposedResponse", - "RootFilesystemBootstrappedResponse", - "VmConfiguredResponse", - "HostCallbacksRegisteredResponse", - "LayerCreatedResponse", - "LayerSealedResponse", - "SnapshotImportedResponse", - "SnapshotExportedResponse", - "OverlayCreatedResponse", - "GuestFilesystemResultResponse", - "RootFilesystemSnapshotResponse", - "ProcessStartedResponse", - "StdinWrittenResponse", - "StdinClosedResponse", - "ProcessKilledResponse", - "ProcessSnapshotResponse", - "ResourceSnapshotResponse", - "ListenerSnapshotResponse", - "BoundUdpSnapshotResponse", - "SignalStateResponse", - "ZombieTimerCountResponse", - "FilesystemResultResponse", - "PermissionDecisionResponse", - "PersistenceStateResponse", - "PersistenceFlushedResponse", - "RejectedResponse", - "VmFetchResponse", - "VmLifecycleEvent", - "ProcessOutputEvent", - "ProcessExitedEvent", - "StructuredEvent", - "HostCallbackRequest", - "JsBridgeCallRequest", - "HostCallbackResultResponse", - "JsBridgeResultResponse", - ] { - assert!( - BARE_SCHEMA_V1.contains(type_name), - "schema is missing `{type_name}`" - ); - } -} - -#[test] -fn checked_in_bare_migration_plan_documents_dual_stack_constraints() { - for needle in [ - "4-byte big-endian length prefix", - "ProtocolSchema.version", - "request_id", - "positive", - "negative", - "JsonUtf8", - "first successfully decoded frame", - "JSON frames begin with `{`", - "delete JSON encoding", - ] { - assert!( - BARE_MIGRATION_PLAN.contains(needle), - "migration plan is missing `{needle}`" - ); - } -} diff --git a/crates/sidecar/tests/python.rs b/crates/sidecar/tests/python.rs deleted file mode 100644 index 767974d68..000000000 --- a/crates/sidecar/tests/python.rs +++ /dev/null @@ -1,4031 +0,0 @@ -mod support; - -use nix::libc; -use secure_exec_sidecar::wire::{ - BootstrapRootFilesystemRequest, CloseStdinRequest, ConfigureVmRequest, CreateVmRequest, - EventPayload, ExecuteRequest, GuestFilesystemCallRequest, GuestFilesystemOperation, - GuestRuntimeKind, KillProcessRequest, MountDescriptor, MountPluginDescriptor, OwnershipScope, - PatternPermissionRule, PatternPermissionRuleSet, PatternPermissionScope, PermissionMode, - PermissionsPolicy, RequestId, RequestPayload, ResponsePayload, RootFilesystemDescriptor, - RootFilesystemEntry, RootFilesystemEntryEncoding, RootFilesystemEntryKind, RootFilesystemMode, - StreamChannel, WriteStdinRequest, -}; -use serde_json::{json, Value}; -use std::collections::HashMap; -use std::fs; -use std::io::{Read, Write}; -use std::net::{TcpListener, UdpSocket}; -use std::os::unix::fs::symlink; -use std::path::{Component, Path, PathBuf}; -use std::sync::{ - atomic::{AtomicBool, Ordering}, - Arc, -}; -use std::thread; -use std::time::{Duration, Instant}; -use support::{ - assert_node_available, authenticate_wire, create_vm_wire, new_sidecar, open_session_wire, - temp_dir, wire_permissions_allow_all, wire_request, wire_session, wire_vm, write_fixture, -}; - -const MAX_PROCESS_STREAM_BYTES: usize = 1024 * 1024; - -#[derive(Debug, Default)] -struct ProcessResult { - stdout: Vec, - stderr: Vec, - exit_code: Option, -} - -fn append_stream_chunk(stream: &mut Vec, chunk: &[u8], label: &str) { - assert!( - stream.len().saturating_add(chunk.len()) <= MAX_PROCESS_STREAM_BYTES, - "{label} exceeded {MAX_PROCESS_STREAM_BYTES} bytes" - ); - stream.extend_from_slice(chunk); -} - -fn chunk_contains(chunk: &[u8], needle: &str) -> bool { - let needle = needle.as_bytes(); - if needle.is_empty() { - return true; - } - chunk.windows(needle.len()).any(|window| window == needle) -} - -fn root_dir(path: impl Into) -> RootFilesystemEntry { - root_entry(path, RootFilesystemEntryKind::Directory, None, None) -} - -fn root_file( - path: impl Into, - content: impl Into, - encoding: Option, -) -> RootFilesystemEntry { - root_entry( - path, - RootFilesystemEntryKind::File, - Some(content.into()), - encoding, - ) -} - -fn root_entry( - path: impl Into, - kind: RootFilesystemEntryKind, - content: Option, - encoding: Option, -) -> RootFilesystemEntry { - RootFilesystemEntry { - path: path.into(), - kind, - mode: None, - uid: None, - gid: None, - content, - encoding, - target: None, - executable: false, - } -} - -fn collect_process_output( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) -> (String, String, i32) { - collect_process_output_with_timeout( - sidecar, - connection_id, - session_id, - vm_id, - process_id, - Duration::from_secs(10), - ) -} - -fn collect_process_output_with_timeout( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - timeout: Duration, -) -> (String, String, i32) { - let ownership = wire_session(connection_id, session_id); - let deadline = Instant::now() + timeout; - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit = None; - - loop { - assert!( - Instant::now() < deadline, - "timed out waiting for process events\nstdout:\n{}\nstderr:\n{}", - String::from_utf8_lossy(&stdout), - String::from_utf8_lossy(&stderr) - ); - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll sidecar wire event"); - if let Some(event) = event { - assert_eq!(event.ownership, wire_vm(connection_id, session_id, vm_id)); - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == process_id => { - match output.channel { - StreamChannel::Stdout => { - append_stream_chunk(&mut stdout, &output.chunk, "stdout"); - } - StreamChannel::Stderr => { - append_stream_chunk(&mut stderr, &output.chunk, "stderr"); - } - } - } - EventPayload::ProcessOutputEvent(_) => {} - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - exit = Some((exited.exit_code, Instant::now())); - } - EventPayload::ProcessExitedEvent(_) - | EventPayload::VmLifecycleEvent(_) - | EventPayload::StructuredEvent(_) - | EventPayload::ExtEnvelope(_) => {} - } - } - - if let Some((exit_code, seen_at)) = exit { - if Instant::now().duration_since(seen_at) >= Duration::from_millis(200) { - return ( - String::from_utf8_lossy(&stdout).into_owned(), - String::from_utf8_lossy(&stderr).into_owned(), - exit_code, - ); - } - } - } -} - -fn pyodide_asset_dir() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")) - .parent() - .expect("sidecar crate parent") - .join("execution") - .join("assets") - .join("pyodide") -} - -fn static_file_path(root: &Path, request_target: &str) -> Option { - let path = request_target.split('?').next().unwrap_or(request_target); - let mut resolved = root.to_path_buf(); - for component in Path::new(path.trim_start_matches('/')).components() { - match component { - Component::Normal(segment) => resolved.push(segment), - Component::CurDir => {} - Component::ParentDir | Component::RootDir | Component::Prefix(_) => return None, - } - } - Some(resolved) -} - -fn static_file_server_rejects_traversal_paths() { - let root = Path::new("/tmp/pyodide-assets"); - assert_eq!( - static_file_path(root, "/click-8.3.1-py3-none-any.whl?download=1"), - Some(root.join("click-8.3.1-py3-none-any.whl")) - ); - assert_eq!(static_file_path(root, "/../secret.txt"), None); - assert_eq!(static_file_path(root, "/packages/../../secret.txt"), None); -} - -fn spawn_tcp_echo_server() -> (u16, thread::JoinHandle<()>) { - let listener = TcpListener::bind("127.0.0.1:0").expect("bind tcp echo listener"); - listener - .set_nonblocking(true) - .expect("set nonblocking echo listener"); - let port = listener.local_addr().expect("echo listener address").port(); - let handle = thread::spawn(move || { - let deadline = Instant::now() + Duration::from_secs(180); - while Instant::now() < deadline { - match listener.accept() { - Ok((mut stream, _)) => { - stream.set_read_timeout(Some(Duration::from_secs(5))).ok(); - let mut buf = [0_u8; 4096]; - loop { - match stream.read(&mut buf) { - Ok(0) => break, - Ok(n) => { - if stream.write_all(&buf[..n]).is_err() { - break; - } - } - Err(_) => break, - } - } - return; - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - thread::sleep(Duration::from_millis(25)); - } - Err(_) => break, - } - } - }); - (port, handle) -} - -fn spawn_udp_echo_server() -> (u16, thread::JoinHandle<()>) { - let socket = UdpSocket::bind("127.0.0.1:0").expect("bind udp echo socket"); - socket - .set_read_timeout(Some(Duration::from_secs(1))) - .expect("set udp echo read timeout"); - let port = socket.local_addr().expect("udp echo address").port(); - let handle = thread::spawn(move || { - let deadline = Instant::now() + Duration::from_secs(180); - let mut buf = [0_u8; 4096]; - while Instant::now() < deadline { - match socket.recv_from(&mut buf) { - Ok((n, addr)) => { - let _ = socket.send_to(&buf[..n], addr); - return; - } - Err(error) - if error.kind() == std::io::ErrorKind::WouldBlock - || error.kind() == std::io::ErrorKind::TimedOut => {} - Err(_) => break, - } - } - }); - (port, handle) -} - -fn spawn_static_file_server(root: PathBuf) -> (u16, thread::JoinHandle<()>) { - let listener = TcpListener::bind("127.0.0.1:0").expect("bind static file listener"); - listener - .set_nonblocking(true) - .expect("set nonblocking listener"); - let port = listener.local_addr().expect("listener address").port(); - let handle = thread::spawn(move || { - // Generous windows so a slow/contended Pyodide boot (and micropip's - // index-then-wheel fetch gap) still lands inside the server's lifetime. - let deadline = Instant::now() + Duration::from_secs(120); - let mut served_any = false; - let mut idle_since: Option = None; - while Instant::now() < deadline { - match listener.accept() { - Ok((mut stream, _)) => { - stream - .set_read_timeout(Some(Duration::from_secs(2))) - .expect("set static file stream read timeout"); - stream - .set_write_timeout(Some(Duration::from_secs(2))) - .expect("set static file stream write timeout"); - served_any = true; - idle_since = None; - let mut request = [0_u8; 4096]; - let read = stream.read(&mut request).unwrap_or(0); - let request_text = String::from_utf8_lossy(&request[..read]); - let path = request_text - .lines() - .next() - .and_then(|line| line.split_whitespace().nth(1)) - .unwrap_or("/"); - let (status_line, body) = match static_file_path(&root, path) { - Some(file_path) => match fs::read(&file_path) { - Ok(body) => ("HTTP/1.1 200 OK", body), - Err(_) => ("HTTP/1.1 404 Not Found", b"missing".to_vec()), - }, - None => ("HTTP/1.1 400 Bad Request", b"bad request".to_vec()), - }; - let response = format!( - "{status_line}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n", - body.len() - ); - let _ = stream.write_all(response.as_bytes()); - let _ = stream.write_all(&body); - } - Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - if served_any { - match idle_since { - Some(start) if start.elapsed() >= Duration::from_secs(20) => break, - Some(_) => {} - None => idle_since = Some(Instant::now()), - } - } - thread::sleep(Duration::from_millis(25)); - } - Err(_) => break, - } - } - }); - (port, handle) -} - -fn execute_inline_python( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - code: &str, -) { - execute_python_entrypoint_with_env( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - process_id, - code, - HashMap::new(), - ); -} - -#[allow(clippy::too_many_arguments)] -fn execute_inline_python_with_env( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - code: &str, - env: HashMap, -) { - execute_python_entrypoint_with_env( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - process_id, - code, - env, - ); -} - -fn execute_python_entrypoint( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - entrypoint: &str, -) { - execute_python_entrypoint_with_env( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - process_id, - entrypoint, - HashMap::new(), - ); -} - -#[allow(clippy::too_many_arguments)] -fn execute_python_entrypoint_with_env( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - entrypoint: &str, - env: HashMap, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: process_id.to_owned(), - command: None, - runtime: Some(GuestRuntimeKind::Python), - entrypoint: Some(entrypoint.to_owned()), - args: Vec::new(), - env, - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("start python execution through wire"); - - match result.response.payload { - ResponsePayload::ProcessStartedResponse(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected wire execute response: {other:?}"), - } -} - -#[allow(clippy::too_many_arguments)] -fn execute_javascript_with_env( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - entrypoint: &Path, - args: Vec, - env: HashMap, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: process_id.to_owned(), - command: None, - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(entrypoint.to_string_lossy().into_owned()), - args, - env, - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("start JavaScript execution through wire"); - - match result.response.payload { - ResponsePayload::ProcessStartedResponse(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected wire execute response: {other:?}"), - } -} - -fn create_vm_with_root_filesystem( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - runtime: GuestRuntimeKind, - cwd: &Path, - root_filesystem: RootFilesystemDescriptor, -) -> String { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_session(connection_id, session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - runtime, - HashMap::from([(String::from("cwd"), cwd.to_string_lossy().into_owned())]), - root_filesystem, - Some(wire_permissions_allow_all()), - )), - )) - .expect("create sidecar VM through wire"); - - match result.response.payload { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("unexpected wire vm create response: {other:?}"), - } -} - -#[allow(clippy::too_many_arguments)] -fn create_vm_with_metadata_and_permissions( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - runtime: GuestRuntimeKind, - cwd: &Path, - mut metadata: HashMap, - permissions: PermissionsPolicy, -) -> String { - metadata - .entry(String::from("cwd")) - .or_insert_with(|| cwd.to_string_lossy().into_owned()); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_session(connection_id, session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - runtime, - metadata, - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }, - Some(permissions), - )), - )) - .expect("create sidecar VM through wire"); - - match result.response.payload { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("unexpected wire vm create response: {other:?}"), - } -} - -fn bootstrap_root_filesystem( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - entries: Vec, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::BootstrapRootFilesystemRequest(BootstrapRootFilesystemRequest { - entries, - }), - )) - .expect("bootstrap root filesystem through wire"); - - match result.response.payload { - ResponsePayload::RootFilesystemBootstrappedResponse(response) => { - assert!(response.entry_count > 0); - } - other => panic!("unexpected wire bootstrap response: {other:?}"), - } -} - -fn guest_filesystem_call( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - payload: GuestFilesystemCallRequest, -) -> secure_exec_sidecar::wire::GuestFilesystemResultResponse { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::GuestFilesystemCallRequest(payload), - )) - .expect("guest filesystem call through wire"); - - match result.response.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => response, - other => panic!("unexpected wire guest filesystem response: {other:?}"), - } -} - -fn guest_write_file_utf8( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - path: &str, - content: &str, -) { - let response = guest_filesystem_call( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: path.to_owned(), - destination_path: None, - target: None, - content: Some(content.to_owned()), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }, - ); - - assert_eq!(response.operation, GuestFilesystemOperation::WriteFile); - assert_eq!(response.path, path); -} - -fn guest_read_file_utf8( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - path: &str, -) -> String { - let response = guest_filesystem_call( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: path.to_owned(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }, - ); - - assert_eq!(response.operation, GuestFilesystemOperation::ReadFile); - assert_eq!(response.path, path); - assert_eq!(response.encoding, Some(RootFilesystemEntryEncoding::Utf8)); - response.content.expect("guest filesystem read content") -} - -fn guest_exists( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - path: &str, -) -> bool { - let response = guest_filesystem_call( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Exists, - path: path.to_owned(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }, - ); - - assert_eq!(response.operation, GuestFilesystemOperation::Exists); - response.exists.expect("guest filesystem exists flag") -} - -fn guest_readlink( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - path: &str, -) -> String { - let response = guest_filesystem_call( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadLink, - path: path.to_owned(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }, - ); - - assert_eq!(response.operation, GuestFilesystemOperation::ReadLink); - response.target.expect("guest filesystem readlink target") -} - -fn guest_symlink( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - link_path: &str, - target: &str, -) { - let response = guest_filesystem_call( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Symlink, - path: link_path.to_owned(), - destination_path: None, - target: Some(target.to_owned()), - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }, - ); - - assert_eq!(response.operation, GuestFilesystemOperation::Symlink); -} - -fn guest_stat_mode( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - path: &str, -) -> u32 { - let response = guest_filesystem_call( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Stat, - path: path.to_owned(), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }, - ); - - response.stat.expect("guest filesystem stat").mode -} - -fn write_process_stdin( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - chunk: &str, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::WriteStdinRequest(WriteStdinRequest { - process_id: process_id.to_owned(), - chunk: chunk.as_bytes().to_vec(), - }), - )) - .expect("write python stdin through wire"); - - match result.response.payload { - ResponsePayload::StdinWrittenResponse(response) => { - assert_eq!(response.process_id, process_id); - assert_eq!(response.accepted_bytes, chunk.len() as u64); - } - other => panic!("unexpected wire stdin-written response: {other:?}"), - } -} - -fn close_process_stdin( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::CloseStdinRequest(CloseStdinRequest { - process_id: process_id.to_owned(), - }), - )) - .expect("close python stdin through wire"); - - match result.response.payload { - ResponsePayload::StdinClosedResponse(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected wire stdin-closed response: {other:?}"), - } -} - -fn kill_process( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: process_id.to_owned(), - signal: String::from("SIGTERM"), - }), - )) - .expect("kill python process through wire"); - - match result.response.payload { - ResponsePayload::ProcessKilledResponse(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected wire process-killed response: {other:?}"), - } -} - -fn wait_for_stdout_chunk( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - needle: &str, -) { - let ownership = wire_vm(connection_id, session_id, vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - - loop { - assert!( - Instant::now() < deadline, - "timed out waiting for python stdout containing {needle:?}" - ); - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll python stdout through wire"); - let Some(event) = event else { continue }; - - match event.payload { - EventPayload::ProcessOutputEvent(output) - if output.process_id == process_id - && output.channel == StreamChannel::Stdout - && chunk_contains(&output.chunk, needle) => - { - return; - } - EventPayload::ProcessOutputEvent(_) => {} - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - panic!( - "python process exited before emitting {needle:?}: {:?}", - exited.exit_code - ); - } - EventPayload::ProcessExitedEvent(_) - | EventPayload::VmLifecycleEvent(_) - | EventPayload::StructuredEvent(_) - | EventPayload::ExtEnvelope(_) => {} - } - } -} - -fn python_runtime_executes_code_end_to_end() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-execute"); - let cwd = temp_dir("python-execute-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python", - "print('hello world')", - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!(stdout, "hello world\n"); - assert!( - stderr.is_empty(), - "unexpected stderr from successful python execution: {stderr}" - ); -} - -fn python_runtime_executes_workspace_py_file_by_path() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-file-entrypoint"); - let cwd = temp_dir("python-file-entrypoint-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_root_filesystem( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: vec![ - root_dir("/workspace"), - root_file( - "/workspace/script.py", - "print('hello from file')\n", - Some(RootFilesystemEntryEncoding::Utf8), - ), - ], - }, - ); - - execute_python_entrypoint( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-file", - "/workspace/script.py", - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-file", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!(stdout, "hello from file\n"); - assert!( - stderr.is_empty(), - "unexpected stderr from file-based Python execution: {stderr}" - ); -} - -fn python_runtime_reports_syntax_errors_over_stderr() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-syntax-error"); - let cwd = temp_dir("python-syntax-error-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-error", - "print(", - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-error", - ); - - assert_eq!(exit_code, 1); - assert!( - stdout.is_empty(), - "unexpected stdout from syntax error execution: {stdout}" - ); - assert!( - stderr.contains("SyntaxError"), - "expected SyntaxError in stderr, got: {stderr}" - ); -} - -fn python_runtime_blocks_pyodide_js_escape_hatches() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-security"); - let cwd = temp_dir("python-security-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-security", - r#" -import json -import js -import pyodide_js - -def capture(action): - try: - action() - return {"ok": True} - except Exception as error: - return { - "ok": False, - "type": type(error).__name__, - "message": str(error), - "code": getattr(error, "code", None), - } - -result = { - "js_process_env": capture(lambda: js.process.env), - "js_require": capture(lambda: js.require), - "js_process_exit": capture(lambda: js.process.exit), - "js_process_kill": capture(lambda: js.process.kill), - "pyodide_js_eval_code": capture(lambda: pyodide_js.eval_code), -} - -print(json.dumps(result)) -"#, - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-security", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stderr.is_empty(), - "unexpected stderr from python security execution: {stderr}" - ); - - let json_line = stdout - .lines() - .rev() - .find(|line| !line.trim().is_empty()) - .expect("python security stdout line"); - let parsed: Value = serde_json::from_str(json_line).expect("parse python security JSON"); - for key in [ - "js_process_env", - "js_require", - "js_process_exit", - "js_process_kill", - ] { - assert_eq!(parsed[key]["ok"], Value::Bool(false)); - assert_eq!( - parsed[key]["type"], - Value::String(String::from("RuntimeError")) - ); - assert_eq!(parsed[key]["code"], Value::Null); - assert!(parsed[key]["message"] - .as_str() - .expect("js hardening message") - .contains("js is not available")); - } - assert_eq!(parsed["pyodide_js_eval_code"]["ok"], Value::Bool(false)); - assert_eq!( - parsed["pyodide_js_eval_code"]["type"], - Value::String(String::from("RuntimeError")) - ); - assert_eq!(parsed["pyodide_js_eval_code"]["code"], Value::Null); - assert!(parsed["pyodide_js_eval_code"]["message"] - .as_str() - .expect("pyodide_js hardening message") - .contains("pyodide_js is not available")); -} - -fn concurrent_python_processes_stay_isolated_across_vms() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-process-isolation"); - let cwd = temp_dir("python-process-isolation-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (slow_vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - let (fast_vm_id, _) = create_vm_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python( - &mut sidecar, - 5, - &connection_id, - &session_id, - &slow_vm_id, - "proc", - "print('slow python')", - ); - execute_inline_python( - &mut sidecar, - 6, - &connection_id, - &session_id, - &fast_vm_id, - "proc", - "print('fast python')", - ); - - let mut results = HashMap::from([ - (slow_vm_id.clone(), ProcessResult::default()), - (fast_vm_id.clone(), ProcessResult::default()), - ]); - let deadline = Instant::now() + Duration::from_secs(15); - let ownership = wire_session(&connection_id, &session_id); - - while results.values().any(|result| result.exit_code.is_none()) { - assert!( - Instant::now() < deadline, - "timed out waiting for concurrent python process events" - ); - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll python process wire event"); - let Some(event) = event else { continue }; - - let OwnershipScope::VmOwnership(ownership) = event.ownership else { - panic!("expected vm-scoped python process event"); - }; - let result = results - .get_mut(&ownership.vm_id) - .unwrap_or_else(|| panic!("unexpected vm event for {}", ownership.vm_id)); - - match event.payload { - EventPayload::ProcessOutputEvent(output) => { - assert_eq!(output.process_id, "proc"); - match output.channel { - StreamChannel::Stdout => { - append_stream_chunk(&mut result.stdout, &output.chunk, "stdout"); - } - StreamChannel::Stderr => { - append_stream_chunk(&mut result.stderr, &output.chunk, "stderr"); - } - } - } - EventPayload::ProcessExitedEvent(exited) => { - assert_eq!(exited.process_id, "proc"); - result.exit_code = Some(exited.exit_code); - } - EventPayload::VmLifecycleEvent(_) - | EventPayload::StructuredEvent(_) - | EventPayload::ExtEnvelope(_) => {} - } - } - - let slow = results.get(&slow_vm_id).expect("slow vm result"); - let fast = results.get(&fast_vm_id).expect("fast vm result"); - - assert_eq!(slow.exit_code, Some(0)); - assert_eq!(fast.exit_code, Some(0)); - let slow_stdout = String::from_utf8_lossy(&slow.stdout); - let fast_stdout = String::from_utf8_lossy(&fast.stdout); - let slow_stderr = String::from_utf8_lossy(&slow.stderr); - let fast_stderr = String::from_utf8_lossy(&fast.stderr); - assert_eq!(slow_stdout, "slow python\n"); - assert_eq!(fast_stdout, "fast python\n"); - assert!( - slow_stderr.is_empty(), - "unexpected slow python stderr: {}", - slow_stderr - ); - assert!( - fast_stderr.is_empty(), - "unexpected fast python stderr: {}", - fast_stderr - ); -} - -fn python_runtime_mounts_workspace_over_the_kernel_vfs() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-workspace-vfs"); - let cwd = temp_dir("python-workspace-vfs-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - bootstrap_root_filesystem( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - vec![root_dir("/workspace")], - ); - guest_write_file_utf8( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "/workspace/from-kernel.txt", - "from kernel", - ); - - execute_inline_python( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-python-workspace", - r#" -import json -import os - -with open("/workspace/from-kernel.txt", "r", encoding="utf-8") as handle: - original = handle.read() - -with open("/workspace/from-python.txt", "w", encoding="utf-8") as handle: - handle.write("from python") - -print(json.dumps({ - "original": original, - "entries": sorted(os.listdir("/workspace")), -})) -"#, - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-workspace", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stderr.is_empty(), - "unexpected stderr from workspace mount execution: {stderr}" - ); - - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse workspace mount JSON"); - assert_eq!(parsed["original"], "from kernel"); - assert_eq!( - parsed["entries"], - serde_json::json!(["from-kernel.txt", "from-python.txt"]) - ); - - let python_written = guest_read_file_utf8( - &mut sidecar, - 7, - &connection_id, - &session_id, - &vm_id, - "/workspace/from-python.txt", - ); - assert_eq!(python_written, "from python"); -} - -fn python_runtime_supports_file_delete_and_rename() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-file-ops"); - let cwd = temp_dir("python-file-ops-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - bootstrap_root_filesystem( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - vec![root_dir("/workspace")], - ); - // Seed via the kernel so delete/rename exercise host-backed VFS entries. - guest_write_file_utf8( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "/workspace/seed.txt", - "seed", - ); - - execute_inline_python( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-python-file-ops", - r#" -import json -import os - -results = {} - -# delete a file -os.remove("/workspace/seed.txt") -results["seed_exists"] = os.path.exists("/workspace/seed.txt") - -# create then remove a directory -os.mkdir("/workspace/subdir") -results["subdir_made"] = os.path.isdir("/workspace/subdir") -os.rmdir("/workspace/subdir") -results["subdir_exists"] = os.path.exists("/workspace/subdir") - -# rename a file -with open("/workspace/old.txt", "w", encoding="utf-8") as handle: - handle.write("renamed body") -os.rename("/workspace/old.txt", "/workspace/new.txt") -results["old_exists"] = os.path.exists("/workspace/old.txt") -with open("/workspace/new.txt", "r", encoding="utf-8") as handle: - results["new_body"] = handle.read() - -results["entries"] = sorted(os.listdir("/workspace")) -print(json.dumps(results)) -"#, - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-file-ops", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse file-ops JSON"); - assert_eq!(parsed["seed_exists"], false, "seed.txt should be deleted"); - assert_eq!(parsed["subdir_made"], true); - assert_eq!(parsed["subdir_exists"], false, "subdir should be removed"); - assert_eq!( - parsed["old_exists"], false, - "old.txt should be renamed away" - ); - assert_eq!(parsed["new_body"], "renamed body"); - assert_eq!(parsed["entries"], serde_json::json!(["new.txt"])); - - // Cross-check the HOST kernel VFS reflects the deletes/rename. - assert!( - !guest_exists( - &mut sidecar, - 7, - &connection_id, - &session_id, - &vm_id, - "/workspace/seed.txt" - ), - "host VFS should not see deleted seed.txt" - ); - assert!( - !guest_exists( - &mut sidecar, - 8, - &connection_id, - &session_id, - &vm_id, - "/workspace/old.txt" - ), - "host VFS should not see renamed-away old.txt" - ); - assert!( - !guest_exists( - &mut sidecar, - 9, - &connection_id, - &session_id, - &vm_id, - "/workspace/subdir" - ), - "host VFS should not see removed subdir" - ); - let new_body = guest_read_file_utf8( - &mut sidecar, - 10, - &connection_id, - &session_id, - &vm_id, - "/workspace/new.txt", - ); - assert_eq!( - new_body, "renamed body", - "host VFS should see the renamed file" - ); -} - -fn python_runtime_supports_raw_tcp_and_udp_sockets() { - assert_node_available(); - - let (tcp_port, tcp_server) = spawn_tcp_echo_server(); - let (udp_port, udp_server) = spawn_udp_echo_server(); - let mut sidecar = new_sidecar("python-sockets"); - let cwd = temp_dir("python-sockets-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - HashMap::from([( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - serde_json::to_string(&vec![tcp_port.to_string(), udp_port.to_string()]) - .expect("serialize exempt ports"), - )]), - wire_permissions_allow_all(), - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-sockets", - &format!( - r#" -import json -import socket - -result = {{}} - -# Raw outbound TCP against a host echo server. -tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -tcp.settimeout(10) -tcp.connect(("127.0.0.1", {tcp_port})) -tcp.sendall(b"hello sockets") -received = b"" -while len(received) < len(b"hello sockets"): - chunk = tcp.recv(64) - if not chunk: - break - received += chunk -tcp.close() -result["tcp"] = received.decode() - -# Raw UDP against a host echo server. -udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -udp.settimeout(10) -udp.sendto(b"ping udp", ("127.0.0.1", {udp_port})) -data, _addr = udp.recvfrom(64) -udp.close() -result["udp"] = data.decode() - -print(json.dumps(result)) -"#, - ), - ); - - let (stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-sockets", - Duration::from_secs(120), - ); - - let _ = tcp_server.join(); - let _ = udp_server.join(); - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - let json_line = stdout - .lines() - .rev() - .find(|line| !line.trim().is_empty()) - .expect("python sockets stdout line"); - let parsed: Value = serde_json::from_str(json_line).expect("parse sockets JSON"); - assert_eq!(parsed["tcp"], "hello sockets"); - assert_eq!(parsed["udp"], "ping udp"); -} - -fn python_runtime_supports_symlink_readlink_and_metadata() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-fs-hooks"); - let cwd = temp_dir("python-fs-hooks-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - bootstrap_root_filesystem( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - vec![root_dir("/workspace")], - ); - - // A symlink that already exists on the host (created via the wire, not by - // Python) — exercises lstat-based detection of pre-existing links. - guest_symlink( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "/workspace/hostlink.txt", - "file.txt", - ); - - execute_inline_python( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-python-fs-hooks", - r#" -import json -import os - -result = {} - -with open("/workspace/file.txt", "w", encoding="utf-8") as handle: - handle.write("data") - -# symlink + readlink (created by Python) -os.symlink("file.txt", "/workspace/link.txt") -result["readlink"] = os.readlink("/workspace/link.txt") -result["islink"] = os.path.islink("/workspace/link.txt") - -# a symlink that pre-existed on the host is detected as a link -result["host_islink"] = os.path.islink("/workspace/hostlink.txt") -result["host_readlink"] = os.readlink("/workspace/hostlink.txt") - -# chmod (setattr -> host) -os.chmod("/workspace/file.txt", 0o640) -result["mode"] = os.stat("/workspace/file.txt").st_mode & 0o777 - -# utimes (setattr -> host) — just exercise the hook -os.utime("/workspace/file.txt", (1700000000, 1710000000)) - -print(json.dumps(result)) -"#, - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-fs-hooks", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse fs-hooks JSON"); - assert_eq!( - parsed["readlink"], "file.txt", - "os.readlink should return the target" - ); - assert_eq!(parsed["islink"], true, "os.path.islink should be true"); - assert_eq!( - parsed["host_islink"], true, - "a host-preexisting symlink should be detected as a link" - ); - assert_eq!(parsed["host_readlink"], "file.txt"); - assert_eq!(parsed["mode"], 0o640, "os.chmod should be reflected"); - - // Cross-check the host kernel VFS. - let host_target = guest_readlink( - &mut sidecar, - 7, - &connection_id, - &session_id, - &vm_id, - "/workspace/link.txt", - ); - assert_eq!( - host_target, "file.txt", - "host VFS should resolve the symlink" - ); - let host_mode = guest_stat_mode( - &mut sidecar, - 8, - &connection_id, - &session_id, - &vm_id, - "/workspace/file.txt", - ); - assert_eq!( - host_mode & 0o777, - 0o640, - "host VFS should reflect the chmod" - ); -} - -fn workspace_files_are_shared_between_javascript_and_python_runtimes() { - assert_node_available(); - - let mut sidecar = new_sidecar("cross-runtime-workspace"); - let workspace_host_dir = temp_dir("cross-runtime-workspace-host"); - let cwd = workspace_host_dir.clone(); - let js_entry = workspace_host_dir.join("cross-runtime.cjs"); - let connection_id = authenticate_wire(&mut sidecar, "conn-cross-runtime"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - write_fixture( - &js_entry, - r#" -const fs = require('node:fs'); - -const mode = process.argv[2]; - -if (mode === 'write') { - fs.writeFileSync('/workspace/from-js.txt', Buffer.from('from js')); - const result = JSON.stringify({ - entries: fs.readdirSync('/workspace').sort(), - }); - fs.writeFileSync('/workspace/js-write-result.json', Buffer.from(result)); -} else if (mode === 'read') { - const result = JSON.stringify({ - fromPython: fs.readFileSync('/workspace/from-python.txt', 'utf8'), - entries: fs.readdirSync('/workspace').sort(), - }); - fs.writeFileSync('/workspace/js-read-result.json', Buffer.from(result)); -} else { - throw new Error(`unknown mode: ${mode}`); -} -"#, - ); - - bootstrap_root_filesystem( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - vec![root_dir("/workspace")], - ); - let configure = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": workspace_host_dir.to_string_lossy().into_owned(), - "readOnly": false, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure host_dir workspace mount through wire"); - match configure.response.payload { - ResponsePayload::VmConfiguredResponse(response) => { - // 1 = just the client mount. With no packages configured there are no - // granular /opt/agentos leaf mounts (one tar/bin/current mount is added - // per package, not a single always-present staging mount). - assert_eq!(response.applied_mounts, 1); - } - other => panic!("unexpected wire configure-vm response: {other:?}"), - } - - let js_fs_env = HashMap::from([ - ( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - json!([{ - "guestPath": "/workspace", - "hostPath": workspace_host_dir.to_string_lossy().into_owned(), - }]) - .to_string(), - ), - ( - String::from("AGENTOS_EXTRA_FS_READ_PATHS"), - json!([workspace_host_dir.to_string_lossy().into_owned()]).to_string(), - ), - ( - String::from("AGENTOS_EXTRA_FS_WRITE_PATHS"), - json!([workspace_host_dir.to_string_lossy().into_owned()]).to_string(), - ), - ]); - - execute_javascript_with_env( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-js-write", - &js_entry, - vec![String::from("write")], - js_fs_env.clone(), - ); - let (js_write_stdout, js_write_stderr, js_write_exit) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-js-write", - ); - - assert_eq!( - js_write_exit, 0, - "stdout: {js_write_stdout}\nstderr: {js_write_stderr}" - ); - assert!( - js_write_stderr.is_empty(), - "unexpected stderr from JavaScript write execution: {js_write_stderr}" - ); - let js_write: Value = serde_json::from_str( - &std::fs::read_to_string(workspace_host_dir.join("js-write-result.json")) - .expect("read JavaScript write JSON"), - ) - .expect("parse JavaScript write JSON"); - assert_eq!( - js_write["entries"], - serde_json::json!(["cross-runtime.cjs", "from-js.txt"]) - ); - - execute_inline_python( - &mut sidecar, - 7, - &connection_id, - &session_id, - &vm_id, - "proc-python-cross-runtime", - r#" -import json -import os - -with open("/workspace/from-js.txt", "r", encoding="utf-8") as handle: - from_js = handle.read() - -with open("/workspace/from-python.txt", "w", encoding="utf-8") as handle: - handle.write("from python") - -print(json.dumps({ - "fromJs": from_js, - "entries": sorted(os.listdir("/workspace")), -})) -"#, - ); - let (python_stdout, python_stderr, python_exit) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-cross-runtime", - ); - - assert_eq!( - python_exit, 0, - "stdout: {python_stdout}\nstderr: {python_stderr}" - ); - assert!( - python_stderr.is_empty(), - "unexpected stderr from Python cross-runtime execution: {python_stderr}" - ); - let python_result: Value = - serde_json::from_str(python_stdout.trim()).expect("parse Python cross-runtime JSON"); - assert_eq!(python_result["fromJs"], "from js"); - assert_eq!( - python_result["entries"], - serde_json::json!([ - "cross-runtime.cjs", - "from-js.txt", - "from-python.txt", - "js-write-result.json" - ]) - ); - - execute_javascript_with_env( - &mut sidecar, - 8, - &connection_id, - &session_id, - &vm_id, - "proc-js-read", - &js_entry, - vec![String::from("read")], - js_fs_env, - ); - let (js_read_stdout, js_read_stderr, js_read_exit) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-js-read", - ); - - assert_eq!( - js_read_exit, 0, - "stdout: {js_read_stdout}\nstderr: {js_read_stderr}" - ); - assert!( - js_read_stderr.is_empty(), - "unexpected stderr from JavaScript read execution: {js_read_stderr}" - ); - let js_read: Value = serde_json::from_str( - &std::fs::read_to_string(workspace_host_dir.join("js-read-result.json")) - .expect("read JavaScript read JSON"), - ) - .expect("parse JavaScript read JSON"); - assert_eq!(js_read["fromPython"], "from python"); - assert_eq!( - js_read["entries"], - serde_json::json!([ - "cross-runtime.cjs", - "from-js.txt", - "from-python.txt", - "js-write-result.json" - ]) - ); -} - -fn python_workspace_mount_respects_read_only_root_permissions() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-workspace-readonly"); - let cwd = temp_dir("python-workspace-readonly-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_root_filesystem( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - RootFilesystemDescriptor { - mode: RootFilesystemMode::ReadOnly, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: vec![ - root_dir("/workspace"), - root_file( - "/workspace/existing.txt", - "seed", - Some(RootFilesystemEntryEncoding::Utf8), - ), - ], - }, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-workspace-readonly", - r#" -from pathlib import Path - -try: - Path("/workspace/blocked.txt").write_text("blocked", encoding="utf-8") - print("write-ok") -except Exception as error: - print(type(error).__name__) - print(str(error)) -"#, - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-workspace-readonly", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stderr.is_empty(), - "unexpected stderr from readonly workspace execution: {stderr}" - ); - assert!( - !stdout.contains("write-ok"), - "python workspace write unexpectedly succeeded: {stdout}" - ); - assert!( - stdout.contains("PermissionError") || stdout.contains("OSError"), - "expected a Python filesystem error, got: {stdout}" - ); - assert!( - stdout.to_ascii_lowercase().contains("read-only") - || stdout.to_ascii_lowercase().contains("permission denied"), - "expected readonly or permission message, got: {stdout}" - ); -} - -fn python_runtime_blocks_mapped_pyodide_cache_symlink_metadata_escape() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-pyodide-cache-symlink-escape"); - let cwd = temp_dir("python-pyodide-cache-symlink-escape-cwd"); - let mapped_cache_root = temp_dir("python-pyodide-cache-symlink-root"); - let outside_root = temp_dir("python-pyodide-cache-symlink-outside"); - let mapped_pkg_dir = mapped_cache_root.join("pkg"); - let outside_secret = outside_root.join("secret.txt"); - fs::create_dir_all(&mapped_pkg_dir).expect("create mapped cache package dir"); - write_fixture(&outside_secret, "outside secret"); - symlink(&outside_secret, mapped_pkg_dir.join("link")) - .expect("create outside symlink in mapped cache"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python_with_env( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-pyodide-cache-symlink-escape", - r#" -import json -import os - -result = {} - -try: - stat = os.stat("/__agentos_pyodide_cache/pkg/link") - result["stat"] = { - "ok": True, - "size": stat.st_size, - "dev": stat.st_dev, - "ino": stat.st_ino, - } -except OSError as error: - result["stat"] = { - "ok": False, - "errno": error.errno, - "message": str(error), - } - -try: - result["entries"] = sorted(os.listdir("/__agentos_pyodide_cache/pkg")) -except OSError as error: - result["entries"] = [] - result["entriesError"] = { - "errno": error.errno, - "message": str(error), - } -print(json.dumps(result)) -"#, - HashMap::from([( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - serde_json::to_string(&vec![json!({ - "guestPath": "/__agentos_pyodide_cache", - "hostPath": mapped_cache_root.to_string_lossy().into_owned(), - })]) - .expect("serialize mapped cache root"), - )]), - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-pyodide-cache-symlink-escape", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stderr.is_empty(), - "unexpected stderr from python execution: {stderr}" - ); - - let result_line = stdout - .lines() - .rev() - .find(|line| !line.trim().is_empty()) - .expect("python symlink-escape JSON line"); - let parsed: Value = - serde_json::from_str(result_line).expect("parse python symlink-escape JSON"); - assert_eq!(parsed["stat"]["ok"], Value::Bool(false)); - let errno = parsed["stat"]["errno"] - .as_i64() - .expect("symlink-escape errno should be numeric"); - assert!( - errno == i64::from(libc::ENOENT) - || errno == i64::from(libc::EPERM) - || errno == i64::from(libc::EACCES) - || errno == 44 - || parsed["stat"]["message"] - .as_str() - .is_some_and(|message| message.contains("No such file or directory")), - "expected ENOENT/EPERM/EACCES from escaped symlink stat, got: {parsed}" - ); - assert_eq!(parsed["entries"], Value::Array(Vec::new())); - if !parsed["entriesError"].is_null() { - let entries_errno = parsed["entriesError"]["errno"] - .as_i64() - .expect("entries errno should be numeric"); - assert!( - entries_errno == i64::from(libc::ENOENT) - || entries_errno == i64::from(libc::EPERM) - || entries_errno == i64::from(libc::EACCES) - || entries_errno == 44 - || parsed["entriesError"]["message"] - .as_str() - .is_some_and(|message| message.contains("No such file or directory")), - "expected ENOENT/EPERM/EACCES-style denial from mapped cache listing, got: {parsed}" - ); - } -} - -fn python_runtime_blocks_mapped_pyodide_cache_symlink_swap_toctou_escape() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-pyodide-cache-symlink-swap-race"); - let cwd = temp_dir("python-pyodide-cache-symlink-swap-race-cwd"); - let mapped_cache_root = temp_dir("python-pyodide-cache-symlink-swap-race-root"); - let outside_root = temp_dir("python-pyodide-cache-symlink-swap-race-outside"); - let safe_pkg_dir = mapped_cache_root.join("safe-pkg"); - let pkg_link_path = mapped_cache_root.join("pkg"); - let safe_secret = safe_pkg_dir.join("secret.txt"); - let outside_secret = outside_root.join("secret.txt"); - fs::create_dir_all(&safe_pkg_dir).expect("create mapped safe package dir"); - fs::create_dir_all(&outside_root).expect("create outside package dir"); - write_fixture(&safe_secret, "safe secret"); - write_fixture(&outside_secret, "outside secret"); - symlink(&safe_pkg_dir, &pkg_link_path).expect("create initial safe package symlink"); - - let stop = Arc::new(AtomicBool::new(false)); - let flapper_stop = Arc::clone(&stop); - let flapper_pkg_link_path = pkg_link_path.clone(); - let flapper_safe_pkg_dir = safe_pkg_dir.clone(); - let flapper_outside_root = outside_root.clone(); - let flapper = thread::spawn(move || { - let mut swap_index = 0usize; - while !flapper_stop.load(Ordering::Relaxed) { - let next_target = if swap_index.is_multiple_of(2) { - &flapper_outside_root - } else { - &flapper_safe_pkg_dir - }; - let temp_link = - flapper_pkg_link_path.with_file_name(format!(".pkg-swap-{}", swap_index % 2)); - let _ = fs::remove_file(&temp_link); - symlink(next_target, &temp_link).expect("create swap symlink"); - fs::rename(&temp_link, &flapper_pkg_link_path).expect("swap package symlink"); - swap_index += 1; - } - }); - - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python_with_env( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-pyodide-cache-symlink-swap-race", - r#" -import json - -result = {"safe": 0, "outside": 0, "errors": 0, "unexpected": []} -for _ in range(4000): - try: - with open("/__agentos_pyodide_cache/pkg/secret.txt", "r", encoding="utf-8") as handle: - value = handle.read().strip() - if value == "safe secret": - result["safe"] += 1 - elif value == "outside secret": - result["outside"] += 1 - else: - result["unexpected"].append(value) - except OSError: - result["errors"] += 1 - -print(json.dumps(result)) -"#, - HashMap::from([( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - serde_json::to_string(&vec![json!({ - "guestPath": "/__agentos_pyodide_cache", - "hostPath": mapped_cache_root.to_string_lossy().into_owned(), - })]) - .expect("serialize mapped cache root"), - )]), - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-pyodide-cache-symlink-swap-race", - ); - stop.store(true, Ordering::Relaxed); - flapper.join().expect("join package symlink flapper"); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stderr.is_empty(), - "unexpected stderr from python execution: {stderr}" - ); - - let result_line = stdout - .lines() - .rev() - .find(|line| !line.trim().is_empty()) - .expect("python symlink-swap race JSON line"); - let parsed: Value = - serde_json::from_str(result_line).expect("parse python symlink-swap race JSON"); - assert_eq!( - parsed["outside"], - Value::from(0), - "mapped cache read escaped to outside root during symlink swap race: {parsed}" - ); - assert_eq!( - parsed["unexpected"], - Value::Array(Vec::new()), - "mapped cache read returned unexpected content during symlink swap race: {parsed}" - ); - assert!( - parsed["safe"].as_i64().unwrap_or_default() > 0 - || parsed["errors"].as_i64().unwrap_or_default() > 0, - "expected safe reads or denied race windows, got: {parsed}" - ); -} - -fn python_runtime_routes_stdin_writes_and_close_to_pyodide() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-stdin"); - let cwd = temp_dir("python-stdin-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin", - r#" -import sys - -print("ready") -print(f"input:{input()}") -print(f"read:{sys.stdin.read()!r}") -"#, - ); - - wait_for_stdout_chunk( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin", - "ready", - ); - assert!( - sidecar - .poll_event_wire_blocking( - &wire_vm(&connection_id, &session_id, &vm_id), - Duration::from_millis(200) - ) - .expect("poll stalled python stdin") - .is_none(), - "python stdin execution should wait for input before exiting" - ); - - write_process_stdin( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin", - "hello\nrest", - ); - close_process_stdin( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin", - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stderr.is_empty(), - "unexpected python stdin stderr: {stderr}" - ); - assert!( - stdout.contains("input:hello"), - "unexpected stdout: {stdout}" - ); - assert!( - stdout.contains("read:'rest'"), - "unexpected stdout: {stdout}" - ); -} - -fn python_runtime_supports_interactive_input_prompts_and_multiple_streaming_writes() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-stdin-interactive"); - let cwd = temp_dir("python-stdin-interactive-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin-interactive", - r#" -import sys - -first = input("prompt-1: ") -print(f"first:{first}") -second = input("prompt-2: ") -print(f"second:{second}") -print(f"tail:{sys.stdin.read()!r}") -"#, - ); - - assert!( - sidecar - .poll_event_wire_blocking( - &wire_vm(&connection_id, &session_id, &vm_id), - Duration::from_millis(200) - ) - .expect("poll stalled python interactive stdin before first write") - .is_none(), - "python interactive stdin execution should wait for the first input" - ); - - write_process_stdin( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin-interactive", - "alpha\n", - ); - - wait_for_stdout_chunk( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin-interactive", - "first:alpha", - ); - - assert!( - sidecar - .poll_event_wire_blocking( - &wire_vm(&connection_id, &session_id, &vm_id), - Duration::from_millis(200) - ) - .expect("poll stalled python interactive stdin before second write") - .is_none(), - "python interactive stdin execution should stay blocked for the second input" - ); - - write_process_stdin( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin-interactive", - "beta\ngamma", - ); - close_process_stdin( - &mut sidecar, - 7, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin-interactive", - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-stdin-interactive", - ); - - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stderr.is_empty(), - "unexpected python interactive stdin stderr: {stderr}" - ); - assert!( - stdout.contains("second:beta"), - "unexpected stdout: {stdout}" - ); - assert!( - stdout.contains("tail:'gamma'"), - "unexpected stdout: {stdout}" - ); -} - -fn python_runtime_close_stdin_triggers_input_eof_and_empty_read() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-stdin-eof"); - let cwd = temp_dir("python-stdin-eof-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-eof", - r#" -import sys - -try: - input() -except EOFError: - print("input-eof") - -print(f"read:{sys.stdin.read()!r}") -"#, - ); - - close_process_stdin( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "proc-python-eof", - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-eof", - ); - - assert_eq!(exit_code, 0); - assert!(stderr.is_empty(), "unexpected python eof stderr: {stderr}"); - assert!(stdout.contains("input-eof"), "unexpected stdout: {stdout}"); - assert!(stdout.contains("read:''"), "unexpected stdout: {stdout}"); -} - -fn python_runtime_kill_process_terminates_blocked_stdin_reads() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-kill"); - let cwd = temp_dir("python-kill-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-kill", - r#" -import sys - -print("ready") -sys.stdin.read() -"#, - ); - - wait_for_stdout_chunk( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-kill", - "ready", - ); - - kill_process( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "proc-python-kill", - ); - - let (_stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-kill", - ); - - assert_ne!(exit_code, 0); - assert!( - stderr.is_empty() - || stderr.contains("terminated") - || stderr.contains("SIGTERM") - || stderr.contains("Error: null"), - "unexpected python kill stderr: {stderr}" - ); -} - -fn python_runtime_imports_bundled_numpy_without_network() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-numpy-package"); - let cwd = temp_dir("python-numpy-package-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python_with_env( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-numpy", - "import numpy\nprint(numpy.__version__)", - HashMap::from([( - String::from("AGENTOS_PYTHON_PRELOAD_PACKAGES"), - String::from("[\"numpy\"]"), - )]), - ); - - let (stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-numpy", - Duration::from_secs(30), - ); - - assert_eq!(exit_code, 0); - assert!( - stderr.is_empty(), - "unexpected stderr from bundled numpy import: {stderr}" - ); - assert!( - stdout.lines().any(|line| line.trim() == "2.2.5"), - "expected numpy version in stdout, got: {stdout}" - ); -} - -fn python_runtime_imports_bundled_pandas_without_network() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-pandas-package"); - let cwd = temp_dir("python-pandas-package-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python_with_env( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-pandas", - "import pandas\nprint(pandas.__version__)", - HashMap::from([( - String::from("AGENTOS_PYTHON_PRELOAD_PACKAGES"), - String::from("[\"pandas\"]"), - )]), - ); - - let (stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-pandas", - Duration::from_secs(30), - ); - - assert_eq!(exit_code, 0); - assert!( - stderr.is_empty(), - "unexpected stderr from bundled pandas import: {stderr}" - ); - assert!( - stdout.lines().any(|line| line.trim() == "2.3.3"), - "expected pandas version in stdout, got: {stdout}" - ); -} - -fn python_runtime_supports_micropip_package_installation() { - assert_node_available(); - - let (port, server) = spawn_static_file_server(pyodide_asset_dir()); - let mut sidecar = new_sidecar("python-micropip-install"); - let cwd = temp_dir("python-micropip-install-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - HashMap::from([( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - serde_json::to_string(&vec![port.to_string()]).expect("serialize exempt ports"), - )]), - wire_permissions_allow_all(), - ); - - execute_inline_python_with_env( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-micropip-install", - &format!( - r#" -import json -import micropip - -await micropip.install("http://127.0.0.1:{port}/click-8.3.1-py3-none-any.whl") - -import click -print(json.dumps({{ - "version": click.__version__, - "command_name": click.Command("demo").name, -}})) -"#, - ), - HashMap::from([( - String::from("AGENTOS_PYODIDE_PACKAGE_BASE_URL"), - format!("http://127.0.0.1:{port}/"), - )]), - ); - - let (stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-micropip-install", - Duration::from_secs(90), - ); - - let _ = server.join(); - assert_eq!(exit_code, 0, "stderr: {stderr}"); - let json_line = stdout - .lines() - .rev() - .find(|line| !line.trim().is_empty()) - .expect("micropip stdout line"); - let parsed: Value = serde_json::from_str(json_line).expect("parse micropip JSON"); - assert_eq!(parsed["version"], Value::String(String::from("8.3.1"))); - assert_eq!(parsed["command_name"], Value::String(String::from("demo"))); -} - -fn python_runtime_micropip_install_respects_network_permissions() { - assert_node_available(); - - let (port, server) = spawn_static_file_server(pyodide_asset_dir()); - let mut sidecar = new_sidecar("python-micropip-network-denied"); - let cwd = temp_dir("python-micropip-network-denied-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - HashMap::from([( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - serde_json::to_string(&vec![port.to_string()]).expect("serialize exempt ports"), - )]), - PermissionsPolicy { - fs: wire_permissions_allow_all().fs, - network: Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)), - child_process: wire_permissions_allow_all().child_process, - process: wire_permissions_allow_all().process, - env: wire_permissions_allow_all().env, - binding: wire_permissions_allow_all().binding, - }, - ); - - execute_inline_python_with_env( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-micropip-network-denied", - &format!( - r#" -import micropip -await micropip.install("http://127.0.0.1:{port}/click-8.3.1-py3-none-any.whl") -"#, - ), - HashMap::from([( - String::from("AGENTOS_PYODIDE_PACKAGE_BASE_URL"), - format!("http://127.0.0.1:{port}/"), - )]), - ); - - let (_stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-micropip-network-denied", - Duration::from_secs(30), - ); - - let _ = server.join(); - assert_ne!(exit_code, 0); - assert!( - stderr.contains("permission") || stderr.contains("denied") || stderr.contains("EACCES"), - "expected micropip permission error, got: {stderr}" - ); -} - -fn python_runtime_routes_dns_and_http_through_sidecar_bridge() { - assert_node_available(); - - let listener = TcpListener::bind("127.0.0.1:0").expect("bind http listener"); - let port = listener.local_addr().expect("listener address").port(); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept http client"); - let mut request = [0_u8; 1024]; - let _ = stream.read(&mut request).expect("read http request"); - stream - .write_all( - b"HTTP/1.1 200 OK\r\nContent-Length: 11\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nhello world", - ) - .expect("write http response"); - }); - - let mut sidecar = new_sidecar("python-network-bridge"); - let cwd = temp_dir("python-network-bridge-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - HashMap::from([ - ( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - serde_json::to_string(&vec![port.to_string()]).expect("serialize exempt ports"), - ), - ( - String::from("network.dns.override.example.test"), - String::from("127.0.0.1"), - ), - ]), - wire_permissions_allow_all(), - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-network", - &format!( - r#" -import json -import socket -import urllib.request - -lookup = socket.getaddrinfo("example.test", {port}, family=socket.AF_INET, type=socket.SOCK_STREAM) -with urllib.request.urlopen("http://example.test:{port}/urllib") as response: - urllib_status = response.status - urllib_body = response.read().decode("utf-8") - -print(json.dumps({{ - "lookup": [entry[4][0] for entry in lookup], - "urllib": {{"status": urllib_status, "body": urllib_body}}, -}})) -"#, - ), - ); - - let (stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-network", - Duration::from_secs(30), - ); - - let _ = server; - assert_eq!(exit_code, 0, "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse python network JSON"); - assert_eq!( - parsed["lookup"][0], - Value::String(String::from("127.0.0.1")) - ); - assert_eq!(parsed["urllib"]["status"], Value::from(200)); - assert_eq!( - parsed["urllib"]["body"], - Value::String(String::from("hello world")) - ); -} - -fn python_runtime_routes_requests_through_sidecar_bridge() { - assert_node_available(); - - let listener = TcpListener::bind("127.0.0.1:0").expect("bind requests listener"); - let port = listener.local_addr().expect("listener address").port(); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept requests client"); - let mut request = [0_u8; 1024]; - let _ = stream.read(&mut request).expect("read requests payload"); - stream - .write_all( - b"HTTP/1.1 200 OK\r\nContent-Length: 11\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nhello world", - ) - .expect("write requests response"); - }); - - let mut sidecar = new_sidecar("python-requests-bridge"); - let cwd = temp_dir("python-requests-bridge-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - HashMap::from([ - ( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - serde_json::to_string(&vec![port.to_string()]).expect("serialize exempt ports"), - ), - ( - String::from("network.dns.override.example.test"), - String::from("127.0.0.1"), - ), - ]), - wire_permissions_allow_all(), - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-requests", - &format!( - r#" -import json -import requests - -response = requests.get("http://example.test:{port}/requests") -print(json.dumps({{ - "status": response.status_code, - "body": response.text, -}})) -"#, - ), - ); - - let (stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-requests", - Duration::from_secs(30), - ); - - let _ = server; - assert_eq!(exit_code, 0, "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse requests JSON"); - assert_eq!(parsed["status"], Value::from(200)); - assert_eq!(parsed["body"], Value::String(String::from("hello world"))); -} - -fn python_runtime_surfaces_network_permission_errors() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-network-denied"); - let cwd = temp_dir("python-network-denied-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - HashMap::from([( - String::from("network.dns.override.example.test"), - String::from("127.0.0.1"), - )]), - PermissionsPolicy { - fs: wire_permissions_allow_all().fs, - network: Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)), - child_process: wire_permissions_allow_all().child_process, - process: wire_permissions_allow_all().process, - env: wire_permissions_allow_all().env, - binding: wire_permissions_allow_all().binding, - }, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-network-denied", - r#" -import json -import socket -import urllib.request - -result = {} -for name, operation in { - "dns": lambda: socket.getaddrinfo("example.test", 80), - "http": lambda: urllib.request.urlopen("http://example.test:80/"), -}.items(): - try: - operation() - result[name] = {"unexpected": True} - except Exception as error: - result[name] = {"type": type(error).__name__, "message": str(error)} - -print(json.dumps(result)) -"#, - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-network-denied", - ); - - assert_eq!(exit_code, 0, "stderr: {stderr}"); - let parsed: Value = - serde_json::from_str(stdout.trim()).expect("parse python network denied JSON"); - assert_eq!( - parsed["dns"]["type"], - Value::String(String::from("PermissionError")) - ); - assert!( - parsed["dns"]["message"] - .as_str() - .is_some_and(|message| message.contains("permission denied")), - "stdout: {stdout}" - ); - assert_eq!( - parsed["http"]["type"], - Value::String(String::from("PermissionError")) - ); -} - -fn python_runtime_runs_node_subprocesses_through_sidecar_bridge() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-subprocess-bridge"); - let cwd = temp_dir("python-subprocess-bridge-cwd"); - write_fixture(&cwd.join("child.mjs"), "console.log('child-ready')\n"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-subprocess", - r#" -import json -import subprocess - -result = subprocess.run(["node", "./child.mjs"], capture_output=True, text=True, check=True) -print(json.dumps({ - "code": result.returncode, - "stdout": result.stdout.strip(), - "stderr": result.stderr.strip(), -})) -"#, - ); - - let (stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-subprocess", - Duration::from_secs(30), - ); - - assert_eq!(exit_code, 0, "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse python subprocess JSON"); - assert_eq!(parsed["code"], Value::from(0)); - assert_eq!(parsed["stdout"], Value::String(String::from("child-ready"))); - assert_eq!(parsed["stderr"], Value::String(String::new())); -} - -fn python_runtime_surfaces_subprocess_permission_errors() { - assert_node_available(); - - let mut sidecar = new_sidecar("python-subprocess-denied"); - let cwd = temp_dir("python-subprocess-denied-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - HashMap::new(), - PermissionsPolicy { - fs: wire_permissions_allow_all().fs, - network: wire_permissions_allow_all().network, - child_process: Some(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: Some(PermissionMode::Allow), - rules: vec![PatternPermissionRule { - mode: PermissionMode::Deny, - operations: vec![String::from("*")], - patterns: vec![String::from("node")], - }], - }, - )), - process: wire_permissions_allow_all().process, - env: wire_permissions_allow_all().env, - binding: wire_permissions_allow_all().binding, - }, - ); - - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-python-subprocess-denied", - r#" -import json -import subprocess - -try: - subprocess.run(["node", "--version"], capture_output=True, text=True, check=True) - result = {"unexpected": True} -except Exception as error: - result = {"type": type(error).__name__, "message": str(error)} - -print(json.dumps(result)) -"#, - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-python-subprocess-denied", - ); - - assert_eq!(exit_code, 0, "stderr: {stderr}"); - let parsed: Value = - serde_json::from_str(stdout.trim()).expect("parse python subprocess denied JSON"); - assert_eq!( - parsed["type"], - Value::String(String::from("PermissionError")) - ); - assert!( - parsed["message"] - .as_str() - .is_some_and(|message| message.contains("permission denied")), - "stdout: {stdout}" - ); -} - -#[allow(clippy::too_many_arguments)] -fn execute_python_cli( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - command: &str, - args: &[&str], -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: process_id.to_owned(), - command: Some(command.to_owned()), - runtime: None, - entrypoint: None, - args: args.iter().map(|arg| (*arg).to_string()).collect(), - env: HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("start python CLI execution through wire"); - - match result.response.payload { - ResponsePayload::ProcessStartedResponse(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected wire execute response: {other:?}"), - } -} - -#[allow(clippy::too_many_arguments)] -fn execute_python_cli_with_env( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - command: &str, - args: &[&str], - env: HashMap, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: process_id.to_owned(), - command: Some(command.to_owned()), - runtime: None, - entrypoint: None, - args: args.iter().map(|arg| (*arg).to_string()).collect(), - env, - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("start python CLI execution through wire"); - - match result.response.payload { - ResponsePayload::ProcessStartedResponse(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected wire execute response: {other:?}"), - } -} - -fn python_command_pip_installs_via_micropip() { - assert_node_available(); - - let (port, server) = spawn_static_file_server(pyodide_asset_dir()); - let mut sidecar = new_sidecar("python-cli-pip"); - let cwd = temp_dir("python-cli-pip-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - HashMap::from([( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - serde_json::to_string(&vec![port.to_string()]).expect("serialize exempt ports"), - )]), - wire_permissions_allow_all(), - ); - - execute_python_cli_with_env( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-py-pip", - "pip", - &[ - "install", - &format!("http://127.0.0.1:{port}/click-8.3.1-py3-none-any.whl"), - ], - HashMap::from([( - String::from("AGENTOS_PYODIDE_PACKAGE_BASE_URL"), - format!("http://127.0.0.1:{port}/"), - )]), - ); - - let (stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-py-pip", - Duration::from_secs(90), - ); - let _ = server.join(); - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stdout.contains("Successfully installed"), - "stdout: {stdout}\nstderr: {stderr}" - ); -} - -fn python_command_runs_inline_code() { - assert_node_available(); - let mut sidecar = new_sidecar("python-cli-inline"); - let cwd = temp_dir("python-cli-inline-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_python_cli( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-py-c", - "python", - &["-c", "print(1 + 1)"], - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-py-c", - ); - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!(stdout, "2\n", "stderr: {stderr}"); -} - -fn python_command_runs_script_with_argv() { - assert_node_available(); - let mut sidecar = new_sidecar("python-cli-argv"); - let cwd = temp_dir("python-cli-argv-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_root_filesystem( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: vec![ - root_dir("/workspace"), - root_file( - "/workspace/argv.py", - "import sys\nprint(\",\".join(sys.argv))\n", - Some(RootFilesystemEntryEncoding::Utf8), - ), - ], - }, - ); - - execute_python_cli( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-py-argv", - "python", - &["/workspace/argv.py", "alpha", "beta"], - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-py-argv", - ); - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!( - stdout, "/workspace/argv.py,alpha,beta\n", - "stderr: {stderr}" - ); -} - -fn python_command_runs_module_with_dash_m() { - assert_node_available(); - let mut sidecar = new_sidecar("python-cli-module"); - let cwd = temp_dir("python-cli-module-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_python_cli( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-py-m", - "python", - &["-m", "this"], - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-py-m", - ); - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - // `python -m this` runs the stdlib `this` module as __main__, printing the Zen. - assert!( - stdout.contains("Beautiful is better than ugly"), - "stdout: {stdout}\nstderr: {stderr}" - ); -} - -fn python_command_reads_program_from_stdin() { - assert_node_available(); - let mut sidecar = new_sidecar("python-cli-stdin"); - let cwd = temp_dir("python-cli-stdin-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_python_cli( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-py-stdin", - "python", - &["-"], - ); - write_process_stdin( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "proc-py-stdin", - "print('from stdin program')\n", - ); - close_process_stdin( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-py-stdin", - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-py-stdin", - ); - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!(stdout, "from stdin program\n", "stderr: {stderr}"); -} - -fn python_command_runs_interactive_repl() { - assert_node_available(); - let mut sidecar = new_sidecar("python-cli-repl"); - let cwd = temp_dir("python-cli-repl-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - ); - - execute_python_cli( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-py-repl", - "python", - &[], - ); - write_process_stdin( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "proc-py-repl", - "print(6 * 7)\n", - ); - close_process_stdin( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-py-repl", - ); - - let (stdout, stderr, exit_code) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-py-repl", - ); - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!(stdout.contains("42"), "stdout: {stdout}\nstderr: {stderr}"); -} - -fn python_command_runs_as_nested_child_process() { - assert_node_available(); - let mut sidecar = new_sidecar("python-cli-nested"); - let workspace_host_dir = temp_dir("python-cli-nested-host"); - let cwd = workspace_host_dir.clone(); - let js_entry = workspace_host_dir.join("spawn.cjs"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python-nested"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - write_fixture( - &js_entry, - r#" -const { spawnSync } = require('node:child_process'); -const result = spawnSync('python', ['-c', 'print(2 + 3)'], { encoding: 'utf8' }); -if (result.error) { - process.stderr.write(String(result.error)); -} -process.stdout.write('status=' + result.status + ';out=' + (result.stdout || '').trim()); -"#, - ); - - bootstrap_root_filesystem( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - vec![root_dir("/workspace")], - ); - let configure = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": workspace_host_dir.to_string_lossy().into_owned(), - "readOnly": false, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure host_dir workspace mount through wire"); - match configure.response.payload { - ResponsePayload::VmConfiguredResponse(response) => { - // 1 = just the client mount. With no packages configured there are no - // granular /opt/agentos leaf mounts (one tar/bin/current mount is added - // per package, not a single always-present staging mount). - assert_eq!(response.applied_mounts, 1); - } - other => panic!("unexpected wire configure-vm response: {other:?}"), - } - - let js_fs_env = HashMap::from([ - ( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - json!([{ - "guestPath": "/workspace", - "hostPath": workspace_host_dir.to_string_lossy().into_owned(), - }]) - .to_string(), - ), - ( - String::from("AGENTOS_EXTRA_FS_READ_PATHS"), - json!([workspace_host_dir.to_string_lossy().into_owned()]).to_string(), - ), - ]); - - execute_javascript_with_env( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-js-spawn", - &js_entry, - Vec::new(), - js_fs_env, - ); - - let (stdout, stderr, exit_code) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-js-spawn", - Duration::from_secs(60), - ); - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stdout.contains("status=0;out=5"), - "stdout: {stdout}\nstderr: {stderr}" - ); -} - -fn python_reads_and_writes_arbitrary_vm_paths() { - assert_node_available(); - let mut sidecar = new_sidecar("python-rootfs-rw"); - let cwd = temp_dir("python-rootfs-rw-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_root_filesystem( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: vec![root_file( - "/etc/agentos-test.txt", - "hello-from-etc\n", - Some(RootFilesystemEntryEncoding::Utf8), - )], - }, - ); - - // Read from /etc and write to /tmp — both outside the old /workspace window. - execute_inline_python( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-rw", - "data = open('/etc/agentos-test.txt').read()\nwith open('/tmp/py-out.txt', 'w') as handle:\n handle.write('written-by-python\\n')\nprint(data.strip())\n", - ); - let (stdout, stderr, exit_code) = - collect_process_output(&mut sidecar, &connection_id, &session_id, &vm_id, "proc-rw"); - assert_eq!(exit_code, 0, "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!(stdout, "hello-from-etc\n", "stderr: {stderr}"); - - // A SEPARATE Python process (fresh Pyodide FS) sees /tmp/py-out.txt — proving - // the write landed in the kernel VFS, not the per-process in-memory FS. - execute_inline_python( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "proc-reread", - "print(open('/tmp/py-out.txt').read().strip())\n", - ); - let (stdout2, stderr2, exit2) = collect_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-reread", - ); - assert_eq!(exit2, 0, "stdout: {stdout2}\nstderr: {stderr2}"); - assert_eq!(stdout2, "written-by-python\n", "stderr: {stderr2}"); -} - -fn python_pip_installs_persist_across_invocations() { - assert_node_available(); - let (port, server) = spawn_static_file_server(pyodide_asset_dir()); - let mut sidecar = new_sidecar("python-vfs-pip"); - let cwd = temp_dir("python-vfs-pip-cwd"); - let connection_id = authenticate_wire(&mut sidecar, "conn-python"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = create_vm_with_metadata_and_permissions( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::Python, - &cwd, - HashMap::from([( - String::from("env.AGENTOS_LOOPBACK_EXEMPT_PORTS"), - serde_json::to_string(&vec![port.to_string()]).expect("serialize exempt ports"), - )]), - wire_permissions_allow_all(), - ); - - // Process 1: `pip install` a wheel — the shim copies it into the VFS-backed - // site-packages so it persists past this interpreter. - execute_python_cli_with_env( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-pip-install", - "pip", - &[ - "install", - &format!("http://127.0.0.1:{port}/click-8.3.1-py3-none-any.whl"), - ], - HashMap::from([( - String::from("AGENTOS_PYODIDE_PACKAGE_BASE_URL"), - format!("http://127.0.0.1:{port}/"), - )]), - ); - let (stdout1, stderr1, exit1) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-pip-install", - Duration::from_secs(90), - ); - assert_eq!(exit1, 0, "stdout: {stdout1}\nstderr: {stderr1}"); - assert!( - stdout1.contains("Successfully installed"), - "stdout: {stdout1}\nstderr: {stderr1}" - ); - - // Process 2: a FRESH Python interpreter imports the package from the VFS - // site-packages — proving the install persisted across invocations. - execute_python_cli( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "proc-pip-import", - "python", - &["-c", "import click; print(click.__version__)"], - ); - let (stdout2, stderr2, exit2) = collect_process_output_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-pip-import", - Duration::from_secs(60), - ); - let _ = server.join(); - assert_eq!(exit2, 0, "stdout: {stdout2}\nstderr: {stderr2}"); - assert_eq!( - stdout2.trim(), - "8.3.1", - "stdout: {stdout2}\nstderr: {stderr2}" - ); -} - -fn python_rootfs_suite() { - python_reads_and_writes_arbitrary_vm_paths(); - python_pip_installs_persist_across_invocations(); -} - -fn python_cli_suite() { - python_command_runs_inline_code(); - python_command_runs_script_with_argv(); - python_command_runs_module_with_dash_m(); - python_command_reads_program_from_stdin(); - python_command_runs_interactive_repl(); - python_command_runs_as_nested_child_process(); - python_command_pip_installs_via_micropip(); -} - -#[test] -fn python_suite() { - // Multiple libtest cases in this V8/Pyodide-backed integration binary still - // trip shared-process teardown/init crashes, so under plain `cargo test` - // (one process for the whole binary) keep the coverage in one suite. - // - // cargo-nextest runs every `#[test]` in its OWN process, so that crash - // cannot occur there — `mod python_split` below exposes each case as a - // separate test that nextest runs in parallel across cores (this suite was - // the single longest test in CI at ~400s serial). Skip the collapsed run - // under nextest so the work isn't done twice; the split cases skip - // themselves under `cargo test`. nextest sets `NEXTEST=1` in each test - // process; libtest/`cargo test` does not. - if std::env::var_os("NEXTEST").is_some() { - return; - } - static_file_server_rejects_traversal_paths(); - python_runtime_executes_code_end_to_end(); - python_runtime_executes_workspace_py_file_by_path(); - python_runtime_reports_syntax_errors_over_stderr(); - python_runtime_blocks_pyodide_js_escape_hatches(); - concurrent_python_processes_stay_isolated_across_vms(); - python_runtime_mounts_workspace_over_the_kernel_vfs(); - python_runtime_supports_file_delete_and_rename(); - python_runtime_supports_raw_tcp_and_udp_sockets(); - python_runtime_supports_symlink_readlink_and_metadata(); - workspace_files_are_shared_between_javascript_and_python_runtimes(); - python_workspace_mount_respects_read_only_root_permissions(); - python_runtime_blocks_mapped_pyodide_cache_symlink_metadata_escape(); - python_runtime_blocks_mapped_pyodide_cache_symlink_swap_toctou_escape(); - python_runtime_routes_stdin_writes_and_close_to_pyodide(); - python_runtime_supports_interactive_input_prompts_and_multiple_streaming_writes(); - python_runtime_close_stdin_triggers_input_eof_and_empty_read(); - python_runtime_kill_process_terminates_blocked_stdin_reads(); - python_runtime_imports_bundled_numpy_without_network(); - python_runtime_imports_bundled_pandas_without_network(); - python_runtime_supports_micropip_package_installation(); - python_runtime_micropip_install_respects_network_permissions(); - python_runtime_routes_dns_and_http_through_sidecar_bridge(); - python_runtime_routes_requests_through_sidecar_bridge(); - python_runtime_surfaces_network_permission_errors(); - python_runtime_runs_node_subprocesses_through_sidecar_bridge(); - python_runtime_surfaces_subprocess_permission_errors(); - python_cli_suite(); - python_rootfs_suite(); -} - -/// Per-case split of `python_suite` for cargo-nextest (process-per-test). -/// -/// Each `#[test]` here runs exactly one Pyodide case in its own process, so the -/// shared-process V8/Pyodide teardown/init crash that forces the collapsed -/// `python_suite` above does not apply, and the ~36 cases run in parallel across -/// cores instead of serially. Each case skips itself under plain `cargo test` -/// (where `NEXTEST` is unset) so the collapsed suite owns the run there; the -/// collapsed suite likewise skips under nextest so the work isn't duplicated. -mod python_split { - macro_rules! nextest_cases { - ($($case:ident),+ $(,)?) => { - $( - #[test] - fn $case() { - // Covered by the collapsed `super::python_suite` under `cargo test`. - if std::env::var_os("NEXTEST").is_none() { - return; - } - super::$case(); - } - )+ - }; - } - - nextest_cases!( - static_file_server_rejects_traversal_paths, - python_runtime_executes_code_end_to_end, - python_runtime_executes_workspace_py_file_by_path, - python_runtime_reports_syntax_errors_over_stderr, - python_runtime_blocks_pyodide_js_escape_hatches, - concurrent_python_processes_stay_isolated_across_vms, - python_runtime_mounts_workspace_over_the_kernel_vfs, - python_runtime_supports_file_delete_and_rename, - python_runtime_supports_raw_tcp_and_udp_sockets, - python_runtime_supports_symlink_readlink_and_metadata, - workspace_files_are_shared_between_javascript_and_python_runtimes, - python_workspace_mount_respects_read_only_root_permissions, - python_runtime_blocks_mapped_pyodide_cache_symlink_metadata_escape, - python_runtime_blocks_mapped_pyodide_cache_symlink_swap_toctou_escape, - python_runtime_routes_stdin_writes_and_close_to_pyodide, - python_runtime_supports_interactive_input_prompts_and_multiple_streaming_writes, - python_runtime_close_stdin_triggers_input_eof_and_empty_read, - python_runtime_kill_process_terminates_blocked_stdin_reads, - python_runtime_imports_bundled_numpy_without_network, - python_runtime_imports_bundled_pandas_without_network, - python_runtime_routes_dns_and_http_through_sidecar_bridge, - python_runtime_routes_requests_through_sidecar_bridge, - python_runtime_surfaces_network_permission_errors, - python_runtime_runs_node_subprocesses_through_sidecar_bridge, - python_runtime_surfaces_subprocess_permission_errors, - python_command_runs_inline_code, - python_command_runs_script_with_argv, - python_command_runs_module_with_dash_m, - python_command_reads_program_from_stdin, - python_command_runs_interactive_repl, - python_command_runs_as_nested_child_process, - python_command_pip_installs_via_micropip, - python_reads_and_writes_arbitrary_vm_paths, - python_pip_installs_persist_across_invocations, - ); - - // The network-DENIED micropip case can't load the micropip package on its - // own (network is denied, so the fetch hangs); it relies on micropip already - // being loaded in the same *process* by a prior network-ALLOWED install - // (Pyodide's module state is process-global). Under nextest's - // process-per-test model that shared state is gone, so pair it in one - // sequential case with a network-allowed install that loads micropip first. - // The other micropip/pip installs are self-contained (they load micropip - // themselves) and stay split for parallelism. Skips under `cargo test`, - // where the collapsed `super::python_suite` owns the run. - // Named `*_suite` so it inherits nextest.toml's 600s slow-timeout override - // for `test(/python.*_suite/)` when the denied case runs (nightly). - #[test] - fn python_micropip_suite() { - if std::env::var_os("NEXTEST").is_none() { - return; - } - // Both micropip installs are heavy COLD work under process-per-test (no - // warm micropip load to reuse): the network-allowed install is ~24s, and - // the network-denied variant is timeout-bound (~2min on the denied-op - // timeout). Neither is on the critical path, so run the whole group only in - // the nightly timing lane (SECURE_EXEC_RUN_TIMING_TESTS=1); `cargo test`'s - // collapsed `super::python_suite` still covers both locally. The denied - // case also needs the allowed install loaded in the SAME process, so they - // stay grouped. See CLAUDE.md > Testing. - if std::env::var_os("SECURE_EXEC_RUN_TIMING_TESTS").is_none() { - return; - } - super::python_runtime_supports_micropip_package_installation(); - super::python_runtime_micropip_install_respects_network_permissions(); - } -} diff --git a/crates/sidecar/tests/sandbox_agent.rs b/crates/sidecar/tests/sandbox_agent.rs deleted file mode 100644 index d6e8ccace..000000000 --- a/crates/sidecar/tests/sandbox_agent.rs +++ /dev/null @@ -1,594 +0,0 @@ -mod sandbox_agent { - include!("../src/plugins/sandbox_agent.rs"); - - mod tests { - use super::test_support::MockSandboxAgentServer; - use super::{ - validate_sandbox_agent_base_url, SandboxAgentFilesystem, SandboxAgentMountConfig, - SandboxAgentMountPlugin, - }; - use nix::unistd::{Gid, Uid}; - use secure_exec_kernel::mount_plugin::{ - FileSystemPluginFactory, OpenFileSystemPluginRequest, - }; - use secure_exec_kernel::vfs::VirtualFileSystem; - use serde_json::json; - use std::fs; - use std::os::unix::fs::{MetadataExt, PermissionsExt}; - - #[test] - fn filesystem_round_trips_small_files_and_uses_http_range_for_large_pread() { - let server = MockSandboxAgentServer::start("secure-exec-sandbox-plugin", None); - fs::write(server.root().join("hello.txt"), "hello from sandbox").expect("seed file"); - let large_file = (0..100 * 1024) - .map(|index| (index % 251) as u8) - .collect::>(); - fs::write(server.root().join("large.bin"), &large_file).expect("seed large file"); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: None, - timeout_ms: Some(5_000), - max_full_read_bytes: Some(200 * 1024), - }) - .expect("create sandbox_agent filesystem"); - - assert_eq!( - filesystem - .read_text_file("/hello.txt") - .expect("read remote file"), - "hello from sandbox" - ); - - filesystem - .write_file("/nested/from-vm.txt", b"native sandbox mount".to_vec()) - .expect("write remote file"); - assert_eq!( - fs::read_to_string(server.root().join("nested/from-vm.txt")) - .expect("read written file"), - "native sandbox mount" - ); - - let chunk = filesystem - .pread("/large.bin", 4_096, 1_024) - .expect("pread should use a byte range"); - assert_eq!(chunk, large_file[4_096..5_120].to_vec()); - - let logged_requests = server.requests(); - let pread_request = logged_requests - .iter() - .find(|request| { - request.method == "GET" - && request.path == "/v1/fs/file" - && request.query.get("path") == Some(&String::from("/large.bin")) - }) - .expect("log pread request"); - assert_eq!( - pread_request.headers.get("range"), - Some(&String::from("bytes=4096-5119")) - ); - assert_eq!(pread_request.response_status, 206); - assert_eq!(pread_request.response_body_bytes, 1_024); - } - - #[test] - fn filesystem_pread_falls_back_to_full_fetch_when_remote_ignores_range() { - let server = MockSandboxAgentServer::start_without_range_support( - "secure-exec-sandbox-plugin", - None, - ); - let large_file = (0..100 * 1024) - .map(|index| (index % 251) as u8) - .collect::>(); - fs::write(server.root().join("large.bin"), &large_file).expect("seed large file"); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: None, - timeout_ms: Some(5_000), - max_full_read_bytes: Some(200 * 1024), - }) - .expect("create sandbox_agent filesystem"); - - let chunk = filesystem - .pread("/large.bin", 4_096, 1_024) - .expect("pread should fall back to the full response"); - assert_eq!(chunk, large_file[4_096..5_120].to_vec()); - - let logged_requests = server.requests(); - let pread_request = logged_requests - .iter() - .find(|request| { - request.method == "GET" - && request.path == "/v1/fs/file" - && request.query.get("path") == Some(&String::from("/large.bin")) - }) - .expect("log pread request"); - assert_eq!( - pread_request.headers.get("range"), - Some(&String::from("bytes=4096-5119")) - ); - assert_eq!(pread_request.response_status, 200); - assert_eq!(pread_request.response_body_bytes, large_file.len()); - } - - #[test] - fn filesystem_pread_rejects_full_fetch_fallback_above_limit() { - let server = MockSandboxAgentServer::start_without_range_support( - "secure-exec-sandbox-plugin-limit", - None, - ); - fs::write(server.root().join("large.bin"), vec![b'x'; 4096]).expect("seed large file"); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: None, - timeout_ms: Some(5_000), - max_full_read_bytes: Some(128), - }) - .expect("create sandbox_agent filesystem"); - - let error = filesystem - .pread("/large.bin", 0, 64) - .expect_err("full fetch fallback should be capped"); - assert_eq!(error.code(), "EIO"); - assert!( - error.to_string().contains("exceeded 128 byte limit"), - "unexpected error: {error}" - ); - } - - #[test] - fn filesystem_pread_rejects_streamed_full_fetch_fallback_above_limit() { - let server = MockSandboxAgentServer::start_without_range_support( - "secure-exec-sandbox-plugin-stream-limit", - None, - ); - fs::write(server.root().join("stream-over-limit"), vec![b'x'; 4096]) - .expect("seed large file"); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: None, - timeout_ms: Some(5_000), - max_full_read_bytes: Some(128), - }) - .expect("create sandbox_agent filesystem"); - - let error = filesystem - .pread("/stream-over-limit", 0, 64) - .expect_err("close-delimited full fetch fallback should be capped"); - assert_eq!(error.code(), "EIO"); - assert!( - error.to_string().contains("exceeded 128 byte limit"), - "unexpected error: {error}" - ); - - let logged_requests = server.requests(); - let pread_request = logged_requests - .iter() - .find(|request| { - request.method == "GET" - && request.path == "/v1/fs/file" - && request.query.get("path") == Some(&String::from("/stream-over-limit")) - }) - .expect("log pread request"); - assert_eq!(pread_request.response_status, 200); - assert_eq!(pread_request.response_body_bytes, 4096); - } - - #[test] - fn sandbox_agent_client_does_not_follow_redirects() { - let server = MockSandboxAgentServer::start("secure-exec-sandbox-plugin-redirect", None); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: None, - timeout_ms: Some(5_000), - max_full_read_bytes: Some(128), - }) - .expect("create sandbox_agent filesystem"); - - let error = filesystem - .read_file("/redirect-to-private") - .expect_err("sandbox_agent client should not follow redirects"); - assert_eq!(error.code(), "EIO"); - assert!( - error.to_string().contains("status 302"), - "unexpected redirect error: {error}" - ); - - let logged_requests = server.requests(); - assert_eq!(logged_requests.len(), 1); - assert_eq!(logged_requests[0].response_status, 302); - } - - #[test] - fn sandbox_agent_base_url_accepts_loopback_over_http() { - for base_url in [ - "http://localhost:1234", - "http://127.0.0.1:1234", - "http://[::1]:1234", - ] { - assert_eq!( - validate_sandbox_agent_base_url(base_url) - .expect("loopback baseUrl should be accepted"), - base_url - ); - } - } - - #[test] - fn sandbox_agent_base_url_allows_private_and_public_https_hosts() { - // baseUrl is trusted mount config, not an SSRF surface, so private / - // metadata hosts are accepted as long as they are well-formed https. - for base_url in [ - "https://169.254.169.254/latest", - "https://10.0.0.1:8080", - "https://[2001:db8::1]:8080", - "https://sandbox.example.com", - "https://93.184.216.34", - ] { - validate_sandbox_agent_base_url(base_url).unwrap_or_else(|error| { - panic!("https baseUrl {base_url} should be accepted: {error}") - }); - } - // Trailing slash is trimmed (request building depends on this). - assert_eq!( - validate_sandbox_agent_base_url("https://sandbox.example.com/api/") - .expect("trailing slash trimmed"), - "https://sandbox.example.com/api" - ); - } - - #[test] - fn sandbox_agent_base_url_requires_https_for_non_local_targets() { - // The bearer token rides the Authorization header, so non-local http - // is still rejected to avoid leaking it over plaintext. - for base_url in ["http://sandbox.example.com", "http://93.184.216.34"] { - let error = validate_sandbox_agent_base_url(base_url) - .expect_err("non-local http baseUrl should be rejected"); - assert!( - error.to_string().contains("must use https"), - "unexpected error for {base_url}: {error}" - ); - } - } - - #[test] - fn sandbox_agent_base_url_rejects_malformed_urls() { - for base_url in ["", "not a url", "ftp://sandbox.example.com"] { - validate_sandbox_agent_base_url(base_url).expect_err(&format!( - "malformed baseUrl {base_url:?} should be rejected" - )); - } - } - - #[test] - fn filesystem_truncate_uses_process_api_without_full_file_buffering() { - let server = MockSandboxAgentServer::start("secure-exec-sandbox-plugin-truncate", None); - fs::write(server.root().join("large.bin"), vec![b'x'; 512]).expect("seed large file"); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: None, - timeout_ms: Some(5_000), - max_full_read_bytes: Some(128), - }) - .expect("create sandbox_agent filesystem"); - - filesystem - .truncate("/large.bin", 3) - .expect("truncate large file through process helper"); - assert_eq!( - fs::read(server.root().join("large.bin")).expect("read truncated file"), - b"xxx".to_vec() - ); - - filesystem - .truncate("/large.bin", 6) - .expect("extend file through process helper"); - assert_eq!( - fs::read(server.root().join("large.bin")).expect("read extended file"), - vec![b'x', b'x', b'x', 0, 0, 0] - ); - - filesystem - .truncate("/large.bin", 0) - .expect("truncate to zero through write_file path"); - assert_eq!( - fs::metadata(server.root().join("large.bin")) - .expect("stat zero-length file") - .len(), - 0 - ); - - let logged_requests = server.requests(); - assert!( - logged_requests.iter().any(|request| { - request.method == "POST" && request.path == "/v1/processes/run" - }), - "non-zero truncate should use process helper" - ); - assert!( - !logged_requests.iter().any(|request| { - request.method == "GET" - && request.path == "/v1/fs/file" - && request.query.get("path") == Some(&String::from("/large.bin")) - }), - "truncate should not issue a full-file GET" - ); - assert!( - logged_requests.iter().any(|request| { - request.method == "PUT" - && request.path == "/v1/fs/file" - && request.query.get("path") == Some(&String::from("/large.bin")) - }), - "truncate(path, 0) should still use the write_file path" - ); - } - - #[test] - fn plugin_scopes_base_path_and_preserves_auth_headers() { - let server = MockSandboxAgentServer::start( - "secure-exec-sandbox-plugin-auth", - Some("secret-token"), - ); - fs::create_dir_all(server.root().join("scoped")).expect("create scoped root"); - fs::write(server.root().join("scoped/hello.txt"), "scoped hello") - .expect("seed scoped file"); - - let plugin = SandboxAgentMountPlugin; - let mut mounted = plugin - .open(OpenFileSystemPluginRequest { - vm_id: "vm-1", - guest_path: "/sandbox", - read_only: false, - config: &json!({ - "baseUrl": server.base_url(), - "token": "secret-token", - "headers": { - "x-sandbox-test": "enabled" - }, - "basePath": "/scoped" - }), - context: &(), - }) - .expect("open sandbox_agent mount"); - - assert_eq!( - mounted.read_file("/hello.txt").expect("read scoped file"), - b"scoped hello".to_vec() - ); - mounted - .write_file("/from-plugin.txt", b"written through plugin".to_vec()) - .expect("write scoped file"); - assert_eq!( - fs::read_to_string(server.root().join("scoped/from-plugin.txt")) - .expect("read plugin output"), - "written through plugin" - ); - - let logged_requests = server.requests(); - assert!(logged_requests.iter().any(|request| { - request.headers.get("x-sandbox-test") == Some(&String::from("enabled")) - })); - } - - #[test] - fn plugin_normalizes_relative_base_path_before_scoping_requests() { - let server = - MockSandboxAgentServer::start("secure-exec-sandbox-plugin-base-path", None); - fs::create_dir_all(server.root().join("scoped")).expect("create scoped root"); - fs::write( - server.root().join("scoped/hello.txt"), - "relative scoped hello", - ) - .expect("seed scoped file"); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: Some(String::from("raw/../scoped/")), - timeout_ms: Some(5_000), - max_full_read_bytes: Some(128), - }) - .expect("create sandbox_agent filesystem"); - - assert_eq!( - filesystem - .read_text_file("/hello.txt") - .expect("read scoped file"), - "relative scoped hello" - ); - - let logged_requests = server.requests(); - let read_request = logged_requests - .iter() - .find(|request| request.method == "GET" && request.path == "/v1/fs/file") - .expect("log read request"); - assert_eq!( - read_request.query.get("path"), - Some(&String::from("scoped/hello.txt")) - ); - } - - #[test] - fn plugin_unscopes_process_helper_targets_for_relative_base_path() { - let server = - MockSandboxAgentServer::start("secure-exec-sandbox-plugin-relative-process", None); - fs::create_dir_all(server.root().join("scoped")).expect("create scoped root"); - fs::write( - server.root().join("scoped/original.txt"), - "relative symlink target", - ) - .expect("seed scoped file"); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: Some(String::from("raw/../scoped/")), - timeout_ms: Some(5_000), - max_full_read_bytes: Some(128), - }) - .expect("create sandbox_agent filesystem"); - - filesystem - .symlink("/original.txt", "/alias.txt") - .expect("create scoped symlink"); - assert_eq!( - filesystem.read_link("/alias.txt").expect("read symlink"), - "/original.txt" - ); - assert_eq!( - filesystem.realpath("/alias.txt").expect("resolve symlink"), - "/original.txt" - ); - - filesystem - .symlink("scoped/original.txt", "/relative-alias.txt") - .expect("create relative scoped symlink"); - assert_eq!( - filesystem - .read_link("/relative-alias.txt") - .expect("read relative symlink"), - "scoped/original.txt" - ); - } - - #[test] - fn filesystem_uses_process_api_for_symlink_and_metadata_operations() { - let server = MockSandboxAgentServer::start("secure-exec-sandbox-plugin-process", None); - fs::write(server.root().join("original.txt"), "hello from sandbox") - .expect("seed original file"); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: None, - timeout_ms: Some(5_000), - max_full_read_bytes: Some(128), - }) - .expect("create sandbox_agent filesystem"); - - filesystem - .symlink("/original.txt", "/alias.txt") - .expect("create remote symlink"); - assert_eq!( - filesystem - .read_link("/alias.txt") - .expect("read remote symlink"), - "/original.txt" - ); - assert_eq!( - filesystem - .realpath("/alias.txt") - .expect("resolve remote symlink"), - "/original.txt" - ); - - filesystem - .link("/original.txt", "/linked.txt") - .expect("create remote hard link"); - let original_metadata = - fs::metadata(server.root().join("original.txt")).expect("stat original hard link"); - let linked_metadata = - fs::metadata(server.root().join("linked.txt")).expect("stat linked hard link"); - assert_eq!(original_metadata.ino(), linked_metadata.ino()); - - filesystem - .write_file("/linked.txt", b"updated through hard link".to_vec()) - .expect("write through hard link"); - assert_eq!( - fs::read_to_string(server.root().join("original.txt")) - .expect("read original after linked write"), - "updated through hard link" - ); - - filesystem - .chmod("/original.txt", 0o600) - .expect("chmod remote file"); - assert_eq!( - fs::metadata(server.root().join("original.txt")) - .expect("stat chmod result") - .permissions() - .mode() - & 0o777, - 0o600 - ); - - let uid = Uid::current().as_raw(); - let gid = Gid::current().as_raw(); - filesystem - .chown("/original.txt", uid, gid) - .expect("chown remote file to current owner"); - let chown_metadata = - fs::metadata(server.root().join("original.txt")).expect("stat chown result"); - assert_eq!(chown_metadata.uid(), uid); - assert_eq!(chown_metadata.gid(), gid); - - let atime_ms = 1_700_000_000_000_u64; - let mtime_ms = 1_710_000_000_000_u64; - filesystem - .utimes("/original.txt", atime_ms, mtime_ms) - .expect("update remote timestamps"); - let utimes_metadata = - fs::metadata(server.root().join("original.txt")).expect("stat utimes result"); - let observed_atime_ms = - utimes_metadata.atime() * 1000 + utimes_metadata.atime_nsec() / 1_000_000; - let observed_mtime_ms = - utimes_metadata.mtime() * 1000 + utimes_metadata.mtime_nsec() / 1_000_000; - assert_eq!(observed_atime_ms, atime_ms as i64); - assert_eq!(observed_mtime_ms, mtime_ms as i64); - - let logged_requests = server.requests(); - assert!(logged_requests.iter().any(|request| { - request.method == "POST" && request.path == "/v1/processes/run" - })); - } - - #[test] - fn filesystem_reports_clear_error_when_process_api_is_unavailable() { - let server = MockSandboxAgentServer::start_without_process_api( - "secure-exec-sandbox-plugin-no-proc", - None, - ); - fs::write(server.root().join("original.txt"), "hello from sandbox") - .expect("seed original file"); - - let mut filesystem = SandboxAgentFilesystem::from_config(SandboxAgentMountConfig { - base_url: server.base_url().to_owned(), - token: None, - headers: None, - base_path: None, - timeout_ms: Some(5_000), - max_full_read_bytes: Some(128), - }) - .expect("create sandbox_agent filesystem"); - - let error = filesystem - .symlink("/original.txt", "/alias.txt") - .expect_err("symlink should fail clearly without process API"); - assert_eq!(error.code(), "ENOSYS"); - assert!( - error.to_string().contains("process API"), - "error should mention process API availability: {error}" - ); - } - } -} diff --git a/crates/sidecar/tests/security_audit.rs b/crates/sidecar/tests/security_audit.rs deleted file mode 100644 index 48f890303..000000000 --- a/crates/sidecar/tests/security_audit.rs +++ /dev/null @@ -1,396 +0,0 @@ -mod support; - -use secure_exec_bridge::StructuredEventRecord; -use secure_exec_sidecar::wire::{ - BootstrapRootFilesystemRequest, ConfigureVmRequest, FsPermissionRule, FsPermissionRuleSet, - FsPermissionScope, GuestFilesystemCallRequest, GuestFilesystemOperation, GuestRuntimeKind, - KillProcessRequest, MountDescriptor, MountPluginDescriptor, PermissionMode, PermissionsPolicy, - RequestPayload, ResponsePayload, RootFilesystemEntry, RootFilesystemEntryEncoding, - RootFilesystemEntryKind, -}; -use std::collections::HashMap; -use std::time::Duration; -use support::{ - assert_node_available, authenticate_wire, authenticate_wire_with_token, - collect_process_output_wire_with_timeout, create_vm_wire, execute_wire, open_session_wire, - temp_dir, wire_request, wire_vm, write_fixture, RecordingBridge, -}; - -fn structured_events( - sidecar: &secure_exec_sidecar::NativeSidecar, -) -> Vec { - sidecar - .with_bridge_mut(|bridge| bridge.structured_events.clone()) - .expect("inspect structured events") -} - -fn find_event<'a>(events: &'a [StructuredEventRecord], name: &str) -> &'a StructuredEventRecord { - events - .iter() - .find(|event| event.name == name) - .unwrap_or_else(|| panic!("missing structured event: {name}")) -} - -fn assert_timestamp(event: &StructuredEventRecord) { - event.fields["timestamp"] - .parse::() - .unwrap_or_else(|error| panic!("invalid audit timestamp: {error}")); -} - -fn wait_for_process_exit_bounded( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) -> i32 { - let (_, _, exit_code) = collect_process_output_wire_with_timeout( - sidecar, - connection_id, - session_id, - vm_id, - process_id, - Duration::from_secs(10), - ); - exit_code -} - -#[test] -fn auth_failures_emit_security_audit_events() { - let mut sidecar = support::new_sidecar("security-audit-auth"); - - let result = authenticate_wire_with_token(&mut sidecar, 1, "conn-hint", "wrong-token"); - match result.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - assert_eq!(rejected.code, "unauthorized"); - assert!(rejected.message.contains("invalid auth token")); - } - other => panic!("unexpected auth failure response: {other:?}"), - } - - let events = structured_events(&sidecar); - let event = find_event(&events, "security.auth.failed"); - assert_eq!(event.vm_id, "sidecar-security-audit-auth"); - assert_eq!(event.fields["source"], "sidecar-tests"); - assert_eq!(event.fields["connection_id"], "conn-hint"); - assert!(event.fields["reason"].contains("invalid auth token")); - assert_timestamp(event); -} - -#[test] -fn filesystem_permission_denials_emit_security_audit_events() { - let mut sidecar = support::new_sidecar("security-audit-permissions"); - let cwd = temp_dir("security-audit-permissions-cwd"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let denied_vm_id = vm_id.clone(); - let sidecar = &mut sidecar; - let _ = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: Some(PermissionsPolicy { - fs: Some(FsPermissionScope::FsPermissionRuleSet( - FsPermissionRuleSet { - default: Some(PermissionMode::Allow), - rules: vec![FsPermissionRule { - mode: PermissionMode::Deny, - operations: vec![String::from("read")], - paths: vec![String::from("/blocked.txt")], - }], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure vm permissions"); - - let write = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &denied_vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/blocked.txt"), - destination_path: None, - target: None, - content: Some(String::from("blocked")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("write blocked file"); - match write.response.payload { - ResponsePayload::GuestFilesystemResultResponse(_) => {} - other => panic!("unexpected write response: {other:?}"), - } - - let read = sidecar - .dispatch_wire_blocking(wire_request( - 6, - wire_vm(&connection_id, &session_id, &denied_vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/blocked.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("dispatch denied read"); - match read.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - // Which layer surfaces the denial (a POSIX-coded kernel error -> - // "kernel_error", any other message -> "invalid_state") depends on - // the host environment; the audit event below is the contract. - assert!( - rejected.code == "invalid_state" || rejected.code == "kernel_error", - "unexpected rejection code: {}", - rejected.code - ); - assert!(rejected.message.contains("EACCES")); - } - other => panic!("unexpected read response: {other:?}"), - } - - let events = structured_events(sidecar); - let event = find_event(&events, "security.permission.denied"); - assert_eq!(event.vm_id, denied_vm_id); - assert_eq!(event.fields["operation"], "read"); - assert_eq!(event.fields["path"], "/blocked.txt"); - assert_eq!(event.fields["policy"], "fs.read"); - assert!(event.fields["reason"].contains("fs.read")); - assert_timestamp(event); -} - -#[test] -fn mount_operations_emit_security_audit_events() { - let mut sidecar = support::new_sidecar("security-audit-mounts"); - let cwd = temp_dir("security-audit-mounts-cwd"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystemRequest(BootstrapRootFilesystemRequest { - entries: vec![RootFilesystemEntry { - path: String::from("/workspace"), - kind: RootFilesystemEntryKind::Directory, - mode: None, - uid: None, - gid: None, - content: None, - encoding: None, - target: None, - executable: false, - }], - }), - )) - .expect("bootstrap workspace"); - - sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("memory"), - config: serde_json::to_string(&serde_json::json!({})) - .expect("serialize memory mount config"), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("mount workspace"); - - sidecar - .dispatch_wire_blocking(wire_request( - 6, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("unmount workspace"); - - let events = structured_events(&sidecar); - // VM creation auto-mounts /opt/agentos (package projection) first; find - // the audit event for THIS test's explicit /workspace mount. - let mounted = events - .iter() - .find(|event| { - event.name == "security.mount.mounted" - && event.fields.get("guest_path").map(String::as_str) == Some("/workspace") - }) - .expect("missing /workspace mount audit event"); - assert_eq!(mounted.vm_id, vm_id); - assert_eq!(mounted.fields["guest_path"], "/workspace"); - assert_eq!(mounted.fields["plugin_id"], "memory"); - assert_eq!(mounted.fields["read_only"], "false"); - assert_timestamp(mounted); - - let unmounted = events - .iter() - .rfind(|event| { - event.name == "security.mount.unmounted" - && event.fields.get("guest_path").map(String::as_str) == Some("/workspace") - }) - .expect("missing /workspace unmount audit event"); - assert_eq!(unmounted.vm_id, vm_id); - assert_eq!(unmounted.fields["guest_path"], "/workspace"); - assert_eq!(unmounted.fields["plugin_id"], "memory"); - assert_eq!(unmounted.fields["read_only"], "false"); - assert_timestamp(unmounted); -} - -#[test] -fn kill_requests_emit_security_audit_events() { - assert_node_available(); - - let mut sidecar = support::new_sidecar("security-audit-kill"); - let cwd = temp_dir("security-audit-kill-cwd"); - let entry = cwd.join("sleep.cjs"); - write_fixture( - &entry, - "setInterval(() => { process.stdout.write('tick\\n'); }, 1000);\n", - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-kill", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("proc-kill"), - signal: String::from("SIGTERM"), - }), - )) - .expect("kill js process"); - match result.response.payload { - ResponsePayload::ProcessKilledResponse(_) => {} - other => panic!("unexpected kill response: {other:?}"), - } - - let exit_code = wait_for_process_exit_bounded( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-kill", - ); - assert_eq!(exit_code, 143); - - let events = structured_events(&sidecar); - let event = find_event(&events, "security.process.kill"); - assert_eq!(event.vm_id, vm_id); - assert_eq!(event.fields["source"], "control_plane"); - assert_eq!(event.fields["source_pid"], "0"); - assert_eq!(event.fields["process_id"], "proc-kill"); - assert_eq!(event.fields["signal"], "SIGTERM"); - assert!(event.fields.contains_key("target_pid")); - assert!(event.fields.contains_key("host_pid")); - assert_timestamp(event); -} diff --git a/crates/sidecar/tests/security_hardening.rs b/crates/sidecar/tests/security_hardening.rs deleted file mode 100644 index b7d44cdc7..000000000 --- a/crates/sidecar/tests/security_hardening.rs +++ /dev/null @@ -1,621 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - ConfigureVmRequest, CreateVmRequest, EventPayload, ExecuteRequest, GuestRuntimeKind, - RequestPayload, ResponsePayload, RootFilesystemDescriptor, RootFilesystemMode, StreamChannel, - WriteStdinRequest, -}; -use secure_exec_sidecar::{NativeSidecar, NativeSidecarConfig}; -use serde_json::Value; -use std::collections::HashMap; -use std::ffi::OsStr; -use std::fs; -use std::os::unix::fs::PermissionsExt; -use std::path::Path; -use std::time::{Duration, Instant}; -use support::{ - acquire_sidecar_runtime_test_lock, assert_node_available, authenticate_wire, create_vm_wire, - create_vm_wire_with_metadata, execute_wire, open_session_wire, temp_dir, - wire_permissions_allow_all, wire_request, wire_session, wire_vm, write_fixture, - RecordingBridge, TEST_AUTH_TOKEN, -}; - -const ARG_PREFIX: &str = "ARG="; -const INVOCATION_BREAK: &str = "--END--"; -const DEFAULT_GUEST_PATH_ENV: &str = - "/usr/local/sbin:/usr/local/bin:/opt/agentos/bin:/usr/sbin:/usr/bin:/sbin:/bin"; -const DEFAULT_GUEST_HOME: &str = "/home/agentos"; -const MAX_SECURITY_HARDENING_STREAM_BYTES: usize = 1024 * 1024; -struct EnvVarGuard { - key: &'static str, - previous: Option, -} - -impl EnvVarGuard { - fn set_value(key: &'static str, value: impl AsRef) -> Self { - let previous = std::env::var(key).ok(); - // SAFETY: These sidecar integration tests mutate process env within a single test scope. - unsafe { - std::env::set_var(key, value); - } - Self { key, previous } - } - - fn set_path(key: &'static str, value: &Path) -> Self { - Self::set_value(key, value.as_os_str()) - } -} - -impl Drop for EnvVarGuard { - fn drop(&mut self) { - match &self.previous { - Some(value) => unsafe { - std::env::set_var(self.key, value); - }, - None => unsafe { - std::env::remove_var(self.key); - }, - } - } -} - -fn write_fake_node_binary(path: &Path, log_path: &Path) { - let script = format!( - "#!/bin/sh\nset -eu\nlog=\"{}\"\nfor arg in \"$@\"; do\n printf 'ARG=%s\\n' \"$arg\" >> \"$log\"\ndone\nprintf '%s\\n' '{}' >> \"$log\"\nexit 0\n", - log_path.display(), - INVOCATION_BREAK, - ); - fs::write(path, script).expect("write fake node binary"); - let mut permissions = fs::metadata(path) - .expect("fake node metadata") - .permissions(); - permissions.set_mode(0o755); - fs::set_permissions(path, permissions).expect("chmod fake node binary"); -} - -fn parse_invocations(log_path: &Path) -> Vec> { - let contents = fs::read_to_string(log_path).expect("read invocation log"); - let separator = format!("{INVOCATION_BREAK}\n"); - contents - .split(&separator) - .filter(|block| !block.trim().is_empty()) - .map(|block| { - block - .lines() - .filter_map(|line| line.strip_prefix(ARG_PREFIX)) - .map(str::to_owned) - .collect::>() - }) - .collect() -} - -fn append_process_chunk(stream: &mut Vec, chunk: &[u8], label: &str) { - assert!( - stream.len().saturating_add(chunk.len()) <= MAX_SECURITY_HARDENING_STREAM_BYTES, - "{label} exceeded {MAX_SECURITY_HARDENING_STREAM_BYTES} bytes" - ); - stream.extend_from_slice(chunk); -} - -fn collect_process_output_bounded( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) -> (String, String, i32) { - let ownership = wire_session(connection_id, session_id); - let deadline = Instant::now() + Duration::from_secs(10); - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit = None; - - loop { - assert!( - Instant::now() < deadline, - "timed out waiting for process events; stdout bytes: {}; stderr bytes: {}", - stdout.len(), - stderr.len() - ); - - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll sidecar wire event"); - if let Some(event) = event { - assert_eq!(event.ownership, wire_vm(connection_id, session_id, vm_id)); - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == process_id => { - match output.channel { - StreamChannel::Stdout => { - append_process_chunk(&mut stdout, &output.chunk, "stdout"); - } - StreamChannel::Stderr => { - append_process_chunk(&mut stderr, &output.chunk, "stderr"); - } - } - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - exit = Some((exited.exit_code, Instant::now())); - } - EventPayload::ProcessOutputEvent(_) - | EventPayload::ProcessExitedEvent(_) - | EventPayload::VmLifecycleEvent(_) - | EventPayload::StructuredEvent(_) - | EventPayload::ExtEnvelope(_) => {} - } - } - - if let Some((exit_code, seen_at)) = exit { - if Instant::now().duration_since(seen_at) >= Duration::from_millis(200) { - return ( - String::from_utf8_lossy(&stdout).into_owned(), - String::from_utf8_lossy(&stderr).into_owned(), - exit_code, - ); - } - } - } -} - -fn sidecar_rejects_oversized_request_frames_before_dispatch() { - acquire_sidecar_runtime_test_lock(); - let root = temp_dir("frame-limit"); - let mut sidecar = NativeSidecar::with_config( - RecordingBridge::default(), - NativeSidecarConfig { - sidecar_id: String::from("sidecar-frame-limit"), - max_frame_bytes: 512, - compile_cache_root: Some(root.join("cache")), - expected_auth_token: Some(String::from(TEST_AUTH_TOKEN)), - acp_termination_grace: Duration::from_secs(3), - }, - ) - .expect("create frame-limited sidecar"); - let cwd = temp_dir("frame-limit-cwd"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let vm_id = match sidecar - .dispatch_wire_blocking(wire_request( - 3, - wire_session(&connection_id, &session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::from([ - (String::from("cwd"), cwd.to_string_lossy().into_owned()), - ( - String::from("limits.http.max_fetch_response_bytes"), - String::from("512"), - ), - ]), - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }, - None, - )), - )) - .expect("create frame-limit vm") - .response - .payload - { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("unexpected vm create response: {other:?}"), - }; - - let result = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::WriteStdinRequest(WriteStdinRequest { - process_id: String::from("proc-1"), - chunk: "x".repeat(1024).into_bytes(), - }), - )) - .expect("dispatch oversized request"); - - match result.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - assert_eq!(rejected.code, "frame_too_large"); - assert!(rejected.message.contains("limit is 512")); - } - other => panic!("unexpected oversized frame response: {other:?}"), - } -} - -fn guest_execution_clears_host_env_and_blocks_escape_paths() { - assert_node_available(); - - let _host_path = EnvVarGuard::set_value("PATH", "/host/sbin:/host/bin"); - let _host_home = EnvVarGuard::set_value("HOME", "/host/home"); - let _host_internal = EnvVarGuard::set_value("AGENTOS_ALLOWED", "host-internal"); - let mut sidecar = support::new_sidecar("security-hardening"); - let cwd = temp_dir("security-hardening-cwd"); - let entry = cwd.join("entry.cjs"); - - write_fixture( - &entry, - r#" -const result = { - path: process.env.PATH ?? null, - home: process.env.HOME ?? null, - pwd: process.env.PWD ?? null, - marker: process.env.VISIBLE_MARKER ?? null, - internalMarker: process.env.AGENTOS_ALLOWED ?? null, - guestPathMappings: process.env.AGENTOS_GUEST_PATH_MAPPINGS ?? null, - importCachePath: process.env.AGENTOS_NODE_IMPORT_CACHE_PATH ?? null, - hasInternalMarker: 'AGENTOS_ALLOWED' in process.env, - keys: Object.keys(process.env).filter((key) => key.startsWith('AGENTOS_')), -}; - -try { - process.binding('fs'); - result.binding = 'unexpected'; -} catch (error) { - result.binding = { code: error.code ?? null, message: error.message }; -} - -console.log(JSON.stringify(result)); -"#, - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::from([(String::from("env.VISIBLE_MARKER"), String::from("present"))]), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-security", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - let (_stdout, stderr, exit_code) = collect_process_output_bounded( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-security", - ); - assert_eq!(exit_code, 0, "stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected security stderr: {stderr}"); - - let parsed: Value = serde_json::from_str(_stdout.trim()).expect("parse security JSON"); - assert_eq!( - parsed["path"], - Value::String(String::from(DEFAULT_GUEST_PATH_ENV)) - ); - assert_eq!( - parsed["home"], - Value::String(String::from(DEFAULT_GUEST_HOME)) - ); - assert_eq!(parsed["pwd"], Value::String(String::from("/"))); - assert_eq!(parsed["marker"], Value::String(String::from("present"))); - assert_eq!(parsed["internalMarker"], Value::Null); - assert_eq!(parsed["guestPathMappings"], Value::Null); - assert_eq!(parsed["importCachePath"], Value::Null); - assert_eq!(parsed["hasInternalMarker"], Value::Bool(false)); - assert_eq!(parsed["keys"], Value::Array(Vec::new())); - assert_ne!( - parsed["path"], - Value::String(String::from("/host/sbin:/host/bin")) - ); - assert_ne!(parsed["home"], Value::String(String::from("/host/home"))); - assert_eq!( - parsed["binding"]["code"], - Value::String(String::from("ERR_ACCESS_DENIED")) - ); -} - -fn vm_resource_limits_cap_active_processes_without_poisoning_followup_execs() { - assert_node_available(); - - let mut sidecar = support::new_sidecar("resource-budgets"); - let cwd = temp_dir("resource-budgets-cwd"); - let slow_entry = cwd.join("slow.cjs"); - let fast_entry = cwd.join("fast.cjs"); - - write_fixture(&slow_entry, "setTimeout(() => {}, 200);\n"); - write_fixture(&fast_entry, "void 0;\n"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::from([(String::from("resource.max_processes"), String::from("1"))]), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "proc-slow", - GuestRuntimeKind::JavaScript, - &slow_entry, - Vec::new(), - ); - - let second = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from("proc-fast"), - command: None, - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(fast_entry.to_string_lossy().into_owned()), - args: Vec::new(), - env: HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch second execute"); - match second.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - assert_eq!(rejected.code, "kernel_error"); - assert!(rejected.message.contains("maximum process limit reached")); - } - other => panic!("unexpected resource-limit response: {other:?}"), - } - - let (_stdout, stderr, exit_code) = collect_process_output_bounded( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-slow", - ); - assert_eq!(exit_code, 0); - assert!(stderr.is_empty(), "unexpected slow stderr: {stderr}"); - - execute_wire( - &mut sidecar, - 6, - &connection_id, - &session_id, - &vm_id, - "proc-fast-2", - GuestRuntimeKind::JavaScript, - &fast_entry, - Vec::new(), - ); - let (_stdout, stderr, exit_code) = collect_process_output_bounded( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "proc-fast-2", - ); - assert_eq!(exit_code, 0); - assert!(stderr.is_empty(), "unexpected fast stderr: {stderr}"); -} - -fn execute_rejects_cwd_outside_vm_sandbox_root() { - let mut sidecar = support::new_sidecar("execute-cwd-validation"); - let cwd = temp_dir("execute-cwd-validation-root"); - let entry = cwd.join("entry.mjs"); - write_fixture(&entry, "console.log('ignored');\n"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from("proc-1"), - command: None, - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(entry.to_string_lossy().into_owned()), - args: Vec::new(), - env: HashMap::new(), - cwd: Some(String::from("/")), - wasm_permission_tier: None, - }), - )) - .expect("dispatch execute request"); - - match result.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!(rejected.message.contains("sandbox root")); - assert!(rejected.message.contains(cwd.to_string_lossy().as_ref())); - } - other => panic!("unexpected execute response: {other:?}"), - } -} - -fn execute_rejects_host_only_absolute_command_path() { - let mut sidecar = support::new_sidecar("execute-host-only-command"); - let cwd = temp_dir("execute-host-only-command-cwd"); - let host_only_root = temp_dir("execute-host-only-command-host"); - let host_only_command = host_only_root.join("host-only-command.sh"); - write_fixture( - &host_only_command, - "#!/bin/sh\nprintf 'host-only command should stay hidden\\n'\n", - ); - let mut permissions = fs::metadata(&host_only_command) - .expect("host-only command metadata") - .permissions(); - permissions.set_mode(0o755); - fs::set_permissions(&host_only_command, permissions).expect("chmod host-only command"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: Some(wire_permissions_allow_all()), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure host-only command permissions"); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from("proc-host-only"), - command: Some(host_only_command.to_string_lossy().into_owned()), - runtime: None, - entrypoint: None, - args: Vec::new(), - env: HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch host-only command execute"); - - match result.response.payload { - ResponsePayload::RejectedResponse(rejected) => { - assert!( - rejected.code == "kernel_error" - || rejected.code == "execution_error" - || rejected.code == "invalid_state", - "unexpected rejection code: {rejected:?}" - ); - if rejected.code == "invalid_state" { - assert!( - rejected - .message - .contains("command not found on native sidecar path"), - "unexpected invalid_state rejection: {rejected:?}" - ); - } - assert!( - !rejected - .message - .contains("host-only command should stay hidden"), - "host-only command output should not leak through the rejection: {rejected:?}" - ); - } - other => panic!("unexpected execute response: {other:?}"), - } -} - -fn execute_ignores_host_node_binary_override_for_javascript_runtime() { - let root = temp_dir("execute-cwd-permission-root"); - let fake_node_path = root.join("fake-node.sh"); - let log_path = root.join("node-args.log"); - write_fake_node_binary(&fake_node_path, &log_path); - let _node_binary = EnvVarGuard::set_path("AGENTOS_NODE_BINARY", &fake_node_path); - - let mut sidecar = support::new_sidecar("execute-cwd-permission-root"); - let cwd = root.join("workspace"); - let nested_cwd = cwd.join("nested"); - fs::create_dir_all(&nested_cwd).expect("create nested cwd"); - let entry = cwd.join("entry.mjs"); - write_fixture(&entry, "console.log('ignored');\n"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from("proc-1"), - command: None, - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(entry.to_string_lossy().into_owned()), - args: Vec::new(), - env: HashMap::new(), - cwd: Some(nested_cwd.to_string_lossy().into_owned()), - wasm_permission_tier: None, - }), - )) - .expect("dispatch execute request"); - - match result.response.payload { - ResponsePayload::ProcessStartedResponse(response) => { - assert_eq!(response.process_id, "proc-1"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (_stdout, stderr, exit_code) = - collect_process_output_bounded(&mut sidecar, &connection_id, &session_id, &vm_id, "proc-1"); - assert_eq!(exit_code, 0); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - - assert!( - !log_path.exists(), - "javascript guest execution should stay inside the V8 runtime instead of invoking host node: {:?}", - parse_invocations(&log_path) - ); -} - -#[test] -fn security_hardening_suite() { - // Multiple libtest cases in this V8-backed integration binary still trip - // teardown/init crashes, so keep the coverage in one top-level suite. - execute_ignores_host_node_binary_override_for_javascript_runtime(); - execute_rejects_cwd_outside_vm_sandbox_root(); - execute_rejects_host_only_absolute_command_path(); - guest_execution_clears_host_env_and_blocks_escape_paths(); - sidecar_rejects_oversized_request_frames_before_dispatch(); - vm_resource_limits_cap_active_processes_without_poisoning_followup_execs(); -} diff --git a/crates/sidecar/tests/service.rs b/crates/sidecar/tests/service.rs deleted file mode 100644 index fb8846f32..000000000 --- a/crates/sidecar/tests/service.rs +++ /dev/null @@ -1,21483 +0,0 @@ -pub trait NativeSidecarBridge: secure_exec_bridge::HostBridge {} -impl NativeSidecarBridge for T where T: secure_exec_bridge::HostBridge {} - -#[allow(dead_code, unused_imports)] -#[path = "acp_legacy/mod.rs"] -mod acp; -#[allow(dead_code)] -#[path = "../src/bootstrap.rs"] -mod bootstrap; -#[path = "../src/bridge.rs"] -mod bridge; -#[allow(dead_code)] -#[path = "../src/crypto_cipher.rs"] -mod crypto_cipher; -#[allow(dead_code)] -#[path = "../src/execution.rs"] -mod execution; -#[allow(dead_code)] -#[path = "../src/extension.rs"] -mod extension; -#[allow(dead_code)] -#[path = "../src/filesystem.rs"] -mod filesystem; -#[allow(dead_code, unused_imports)] -#[path = "../src/json_rpc.rs"] -mod json_rpc; -#[allow(dead_code, unused_imports)] -#[path = "../src/limits.rs"] -mod limits; -// macOS-only: `filesystem`/`plugins::host_dir` (included above) reference -// `crate::macos_fs::…`, which must resolve in this source-included test crate -// too. Unused on Linux (those references are `#[cfg]`d out there). -#[cfg(target_os = "macos")] -#[allow(dead_code)] -#[path = "../src/macos_fs.rs"] -mod macos_fs; -#[allow(dead_code)] -#[path = "../src/metadata/mod.rs"] -mod metadata; -#[allow(dead_code)] -#[path = "../src/package_projection.rs"] -mod package_projection; -#[allow(dead_code)] -#[path = "../src/plugins/mod.rs"] -mod plugins; -#[allow(dead_code, unused_imports, clippy::enum_variant_names)] -mod protocol { - pub use secure_exec_sidecar_protocol::protocol::*; -} -#[allow(dead_code)] -#[path = "../src/state.rs"] -mod state; -#[allow(dead_code)] -#[path = "../src/tools.rs"] -mod tools; -#[allow(dead_code)] -#[path = "../src/vm.rs"] -mod vm; -#[allow(dead_code, unused_imports)] -mod wire { - pub use secure_exec_sidecar_protocol::wire::*; -} - -// The unit tests include!d from src/service.rs reference crate::stdio::LocalBridge, -// and stdio.rs in turn uses these crate-root re-exports (mirrored from lib.rs) so it -// compiles inside this integration-test crate too. -use extension::{ - Extension, ExtensionContext, ExtensionFuture, ExtensionInterruptRequest, - ExtensionInterruptResponse, ExtensionResponse, -}; -use service::NativeSidecarConfig; -use state::{EventSinkTransport, SidecarRequestTransport}; - -#[allow(dead_code)] -#[path = "../src/stdio.rs"] -mod stdio; - -mod service { - include!("../src/service.rs"); - - mod tests { - mod bridge_support { - include!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/../bridge/tests/support.rs" - )); - } - - use super::*; - use crate::bridge::{bridge_permissions, HostFilesystem, ScopedHostFilesystem}; - use crate::execution::{ - clamp_javascript_net_poll_wait, format_dns_resource, format_tcp_resource, - runtime_child_is_alive, - service_javascript_net_sync_rpc as service_javascript_net_sync_rpc_inner, - signal_runtime_process, JavascriptNetSyncRpcServiceRequest, - JavascriptSyncRpcServiceRequest, JavascriptSyncRpcServiceResponse, - }; - use crate::filesystem::service_javascript_fs_sync_rpc; - use crate::plugins::s3_common::test_support::MockS3Server; - use crate::plugins::sandbox_agent::test_support::MockSandboxAgentServer; - use crate::protocol::VmCreatedResponse; - use crate::protocol::{ - AuthenticateRequest, BootstrapRootFilesystemRequest, CloseStdinRequest, - ConfigureVmRequest, CreateVmRequest, DisposeReason, DisposeVmRequest, EventPayload, - FindBoundUdpRequest, FindListenerRequest, FsPermissionRule, FsPermissionRuleSet, - FsPermissionScope, GetProcessSnapshotRequest, GetResourceSnapshotRequest, - GetZombieTimerCountRequest, GuestFilesystemCallRequest, GuestFilesystemOperation, - GuestRuntimeKind, HostCallbackResultResponse, MountDescriptor, MountPluginDescriptor, - OpenSessionRequest, OwnershipScope, PatternPermissionRule, PatternPermissionRuleSet, - PatternPermissionScope, PermissionMode, PermissionsPolicy, - RegisterHostCallbacksRequest, RegisteredHostCallbackDefinition, RejectedResponse, - RequestFrame, RequestPayload, ResponsePayload, RootFilesystemEntry, - RootFilesystemEntryEncoding, RootFilesystemEntryKind, SessionOpenedResponse, - SidecarPlacement, SidecarPlacementShared, SidecarRequestFrame, SidecarRequestPayload, - SidecarResponsePayload, WriteStdinRequest, - }; - use crate::state::{ - ActiveCipherSession, ActiveDiffieHellmanSession, ActiveEcdhSession, ActiveExecution, - ActiveExecutionEvent, ActiveProcess, ActiveSqliteDatabase, ActiveSqliteStatement, - ActiveTcpListener, ActiveUdpSocket, ProcessEventEnvelope, SidecarKernel, ToolExecution, - VmListenPolicy, EXECUTION_SANDBOX_ROOT_ENV, JAVASCRIPT_COMMAND, - LOOPBACK_EXEMPT_PORTS_ENV, PYTHON_COMMAND, VM_DNS_SERVERS_METADATA_KEY, - VM_LISTEN_ALLOW_PRIVILEGED_METADATA_KEY, VM_LISTEN_PORT_MAX_METADATA_KEY, - VM_LISTEN_PORT_MIN_METADATA_KEY, WASM_COMMAND, WASM_STDIO_SYNC_RPC_ENV, - }; - use crate::state::{NetworkResourceCounts, VmDnsConfig}; - use base64::Engine; - use bridge_support::RecordingBridge; - use hickory_resolver::proto::op::{Message, Query}; - use hickory_resolver::proto::rr::domain::Name; - use hickory_resolver::proto::rr::rdata::{ - A, AAAA, CAA, CNAME, MX, NAPTR, NS, PTR, SOA, SRV, TXT, - }; - use hickory_resolver::proto::rr::{RData, Record, RecordType}; - use nix::libc; - use rustls::client::danger::{ - HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, - }; - use rustls::crypto::aws_lc_rs; - use rustls::pki_types::{CertificateDer, ServerName}; - use rustls::{ - ClientConfig, ClientConnection, DigitallySignedStruct, RootCertStore, ServerConfig, - ServerConnection, SignatureScheme, - }; - use secure_exec_bridge::SymlinkRequest; - use secure_exec_execution::{ - CreateJavascriptContextRequest, CreatePythonContextRequest, CreateWasmContextRequest, - JavascriptSyncRpcRequest, PythonVfsRpcMethod, PythonVfsRpcRequest, - StartJavascriptExecutionRequest, StartPythonExecutionRequest, - StartWasmExecutionRequest, WasmPermissionTier, - }; - use secure_exec_kernel::command_registry::CommandDriver; - use secure_exec_kernel::kernel::{KernelVmConfig, SpawnOptions, VirtualProcessOptions}; - use secure_exec_kernel::mount_table::{MountEntry, MountOptions, MountTable}; - use secure_exec_kernel::permissions::{ - CommandAccessRequest, EnvAccessRequest, EnvironmentOperation, FsAccessRequest, - FsOperation, NetworkAccessRequest, NetworkOperation, Permissions, - }; - use secure_exec_kernel::poll::{PollTargetEntry, POLLIN}; - use secure_exec_kernel::process_table::{SIGKILL, SIGTERM}; - use secure_exec_kernel::resource_accounting::ResourceLimits; - use secure_exec_kernel::vfs::{ - MemoryFileSystem, VirtualDirEntry, VirtualFileSystem, VirtualStat, - }; - use serde_json::{json, Value}; - use std::collections::BTreeMap; - use std::fs; - use std::io::{BufReader, Read, Write}; - use std::net::{SocketAddr, TcpListener, UdpSocket}; - use std::os::unix::fs::PermissionsExt; - use std::path::{Path, PathBuf}; - use std::process::Command; - use std::sync::{ - atomic::{AtomicUsize, Ordering}, - mpsc, Arc, Barrier, Mutex, OnceLock, - }; - use std::thread; - use std::time::{Duration, SystemTime, UNIX_EPOCH}; - - const TEST_AUTH_TOKEN: &str = "sidecar-test-token"; - const ISOLATED_SERVICE_TEST_ENV: &str = "AGENTOS_SERVICE_ISOLATED_TEST"; - const ISOLATED_SERVICE_CACHE_SUFFIX_ENV: &str = "AGENTOS_SERVICE_ISOLATED_CACHE_SUFFIX"; - const MAX_SERVICE_PROCESS_STREAM_BYTES: usize = 1024 * 1024; - const TLS_TEST_KEY_PEM: &str = "-----BEGIN PRIVATE KEY-----\n\ -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQClvETzHfSyd1Y+\n\ -sjCfGkuyGxFMzwQlYjUrE0iwdMF774LYHFdpvtEo3sLOW6/b1xfXS/55jq+aggxS\n\ -v+vgtjrhGf/y33XzdrjxcVBRWIsgAtxMHsNKO4EQ/uA1g6zlbaSIu+ZWX3bkDuTi\n\ -K45VW69M0XSVyv8XFGYOcf8LTI87gTtXHuT92iej77IM2lHqLXCzQVr+NQ9yvXld\n\ -9yHlA2ZfYqhkSTLdDablqfgirrQIzZzLypSGQwZUU06nCtZ+dg6SNV4TGL4NqekD\n\ -jXR3BvmZu5l4sGAsNfFVjLx6hxsLt8uqn65sCAwBDdfucR+39+pHA+esj6NAWAFO\n\ -J9CB94sfAgMBAAECggEABQTA772x+a98aJSbvU2eCiwgp3tDTGB/bKj+U/2NGFQl\n\ -2aZuDTEugzbPnlEPb7BBNA9EiujDr4GNnvnZyimqecOASRn0J+Wp7wG35Waxe8wq\n\ -YJGz5y0LGPkmz+gHVcEusMdDz8y/PGOpEaIxAquukLxs89Y8SDYhawGPsAdm9O3F\n\ -4a+aosyQwS26mkZ/1WZOTsOVd4A1/1pxBvsANURj+pq7ed/1WqgrZBN/BG1TX5Xm\n\ -DZeYy01kTCMWtcAb4f8PxGpbkSGMvBb+Mj5XtZByvfQeC+Cs5ECXhmJtVaYVUHhT\n\ -vI0oTMGvit9ffoYNds0qTeZpEeineaDH3sD16D037QKBgQDX5b65KfIVH0/WvcbJ\n\ -Gx2Wh7knXdDBky40wdq4buKK+ImzPPRxOsQ+xEMgEaZs8gb7LBapbB0cZ+YsKBOt\n\ -4FY86XQU5V5ju2ntldIIIaugIGgvGS0jdRMH3ux6iEjPZE6Fm7/s8bjIgqB7keWh\n\ -1rcZwDrwMzqwAUoBTJX58OY/fQKBgQDEhT5U7TqgEFVSspYh8c8yVRV9udiphPH3\n\ -3XIbo9iV3xzNFdwtNHC+2eLM+4J3WKjhB0UvzrlIegSqKPIsy+0nD1uzaU+O72gg\n\ -7+NKSh0RT61UDolk+P4s/2+5tnZqSNYO7Sd/svE/rkwIEtDEI5tb1nqq75h/HDEW\n\ -k56GHAxvywKBgGmGmTdmIjZizKJYti4b+9VU15I/T8ceCmqtChw1zrNAkgWy2IPz\n\ -xnIreefV2LPNhM4GGbmL55q3yhBxMlU9nsk9DokcJ4u10ivXnAZvdrTYwjOrKZ34\n\ -HmotcwbdUEFWdO7nVuMYr0oKVyivAj+ddHe4ttYrJBddOe/yoCe/sLr9AoGBAKHL\n\ -IVpCRXXqfJStOzWPI4rIyfzMuTg3oA71XjCrYHFjUw715GPDPN+j+znQB8XCVKeP\n\ -mMKXa6vj6Vs+gsOm0QTLfC/lj/6Z1Bzp4zMSeYP7GTSPE0bySDE7y/wV4L/4X2PC\n\ -lDZqWHyZPzeWZhJVTl754dxBjkd4KmHv/x9ikEqpAoGBAJNA0u0fKhdWDz32+a2F\n\ -+plJ18kQvGuwKFWIIVHBDc0wCxLKWKr5wgkhdcAEpy4mgosiZ09DzV/OpQBBHVWZ\n\ -v/Cn/DwZyoiXIi5onf7AqWIhw+aem+oMbugbSIYqDwYkwnN79tsza0KC1ScphIuf\n\ -vKoOAdY4xOcG9BEZZoKVOa8R\n\ ------END PRIVATE KEY-----\n"; - const TLS_TEST_CERT_PEM: &str = "-----BEGIN CERTIFICATE-----\n\ -MIIDCTCCAfGgAwIBAgIUJqRgTEIlpbfqbQnyo9hxLyIn3qYwDQYJKoZIhvcNAQEL\n\ -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI2MDQwNTA3MTAwOVoXDTI2MDQw\n\ -NjA3MTAwOVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\n\ -AAOCAQ8AMIIBCgKCAQEApbxE8x30sndWPrIwnxpLshsRTM8EJWI1KxNIsHTBe++C\n\ -2BxXab7RKN7Czluv29cX10v+eY6vmoIMUr/r4LY64Rn/8t9183a48XFQUViLIALc\n\ -TB7DSjuBEP7gNYOs5W2kiLvmVl925A7k4iuOVVuvTNF0lcr/FxRmDnH/C0yPO4E7\n\ -Vx7k/dono++yDNpR6i1ws0Fa/jUPcr15Xfch5QNmX2KoZEky3Q2m5an4Iq60CM2c\n\ -y8qUhkMGVFNOpwrWfnYOkjVeExi+DanpA410dwb5mbuZeLBgLDXxVYy8eocbC7fL\n\ -qp+ubAgMAQ3X7nEft/fqRwPnrI+jQFgBTifQgfeLHwIDAQABo1MwUTAdBgNVHQ4E\n\ -FgQUwViZyKE6S2vgTAkexnZFccSwoPMwHwYDVR0jBBgwFoAUwViZyKE6S2vgTAke\n\ -xnZFccSwoPMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAadmK\n\ -3Ugrvep6glHAfgPP54um9cjJZQZDPn5I7yvgDr/Zp/u/UMW/OUKSfL1VNHlbAVLc\n\ -Yzq2RVTrJKObiTSoy99OzYkEdgfuEBBP7XBEQlqoOGYNRR+IZXBBiQ+m9CtajNwQ\n\ -G6mr9//zZtV1y2UUBgtxVpry5iOekpkr8iXyDLnGpS2gKL5dwXCzWCKVCO3qVotn\n\ -r6FBg4DCBMkwO6xOVN2yInPd6CPy/JAUPW50zWPnn4DKfeAAU0C+E75HN65jozdi\n\ -12yT4K772P8oSecGPInZhqJgOv1q0BDG8gccOxX1PA4sE00Enqlbvxz7sku9y4zp\n\ -ykAheWCsAteSEWVc0w==\n\ ------END CERTIFICATE-----\n"; - fn request( - request_id: secure_exec_sidecar::protocol::RequestId, - ownership: OwnershipScope, - payload: RequestPayload, - ) -> RequestFrame { - RequestFrame::new(request_id, ownership, payload) - } - - // Timing-sensitive assertions flake under the CPU contention of a parallel - // test run (see CLAUDE.md > Testing). Gated off by default; the nightly - // timing lane sets SECURE_EXEC_RUN_TIMING_TESTS=1 to enforce them. - fn run_timing_sensitive_tests() -> bool { - std::env::var_os("SECURE_EXEC_RUN_TIMING_TESTS").is_some() - } - - fn acquire_sidecar_runtime_test_lock() { - // No-op under cargo-nextest: each test runs in its own process, so the - // process-global V8 platform, env, and (now per-process) compile cache - // are already isolated. Previously an exclusive flock serialized - // runtime-touching tests across binaries to guard the shared fixed - // compile-cache path; that path is now unique per process. See - // CLAUDE.md > Testing. - } - - fn create_test_sidecar_with_config( - config: NativeSidecarConfig, - ) -> NativeSidecar { - // Unique compile-cache dir per test process (a re-exec child supplies an - // explicit suffix; otherwise derive one from PID + a sequence counter). - // Under cargo-nextest each test is its own process, so this gives every - // test an isolated cache instead of the old fixed shared path — no flock - // needed. See CLAUDE.md > Testing. - let cache_suffix = std::env::var(ISOLATED_SERVICE_CACHE_SUFFIX_ENV) - .ok() - .unwrap_or_else(|| { - static CACHE_SEQ: std::sync::atomic::AtomicU64 = - std::sync::atomic::AtomicU64::new(0); - format!( - "{}-{}", - std::process::id(), - CACHE_SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed) - ) - }); - let compile_cache_root = - std::env::temp_dir().join(format!("secure-exec-sidecar-test-cache-{cache_suffix}")); - NativeSidecar::with_config( - RecordingBridge::default(), - NativeSidecarConfig { - sidecar_id: String::from("sidecar-test"), - compile_cache_root: Some(compile_cache_root), - expected_auth_token: Some(String::from(TEST_AUTH_TOKEN)), - ..config - }, - ) - .expect("create sidecar") - } - fn create_test_sidecar() -> NativeSidecar { - create_test_sidecar_with_config(NativeSidecarConfig::default()) - } - - fn test_process_event(index: usize) -> ProcessEventEnvelope { - ProcessEventEnvelope { - connection_id: String::from("conn-queue"), - session_id: String::from("session-queue"), - vm_id: String::from("vm-queue"), - process_id: format!("proc-queue-{index}"), - event: ActiveExecutionEvent::Stdout(Vec::new()), - } - } - - fn insert_tool_process( - sidecar: &mut NativeSidecar, - vm_id: &str, - process_id: &str, - ) { - let kernel_handle = create_kernel_process_handle_for_tests(); - let process = ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Tool(ToolExecution::default()), - ); - sidecar - .vms - .get_mut(vm_id) - .expect("test vm") - .active_processes - .insert(process_id.to_owned(), process); - } - - fn ext_sidecar_request_payload() -> SidecarRequestPayload { - SidecarRequestPayload::Ext(crate::protocol::ExtEnvelope { - namespace: String::from("test.completion.evict"), - payload: Vec::new(), - }) - } - - fn ext_sidecar_response_frame( - request_id: crate::protocol::RequestId, - ownership: &OwnershipScope, - ) -> crate::protocol::SidecarResponseFrame { - crate::protocol::SidecarResponseFrame::new( - request_id, - ownership.clone(), - SidecarResponsePayload::ExtResult(crate::protocol::ExtEnvelope { - namespace: String::from("test.completion.evict"), - payload: Vec::new(), - }), - ) - } - - // Drive one full sidecar request -> outbound drain -> response-accept - // cycle, mirroring how the stdio loop hands a request to the host and - // then records the host's reply. Returns the request id so the caller - // can later assert whether that completed response is still retrievable. - fn complete_one_sidecar_response( - sidecar: &mut NativeSidecar, - ownership: &OwnershipScope, - ) -> crate::protocol::RequestId { - let request_id = sidecar - .queue_sidecar_request(ownership.clone(), ext_sidecar_request_payload()) - .expect("queue sidecar request"); - sidecar - .pop_sidecar_request() - .expect("outbound sidecar request should be queued for the host"); - sidecar - .accept_sidecar_response(ext_sidecar_response_frame(request_id, ownership)) - .expect("accept sidecar response"); - request_id - } - - // The completed-response map is bounded: once more responses complete - // than the cap, the oldest *unretrieved* response is evicted (and the - // host can no longer fetch it) so the map cannot grow without bound. - fn completed_sidecar_responses_evict_oldest_beyond_cap() { - let mut sidecar = create_test_sidecar(); - let ownership = OwnershipScope::connection("conn-completion-evict"); - let cap = crate::service::MAX_COMPLETED_SIDECAR_RESPONSES; - - // The first completion is the oldest; everything after it pushes the - // map past the cap and must evict from the front. - let oldest_request_id = complete_one_sidecar_response(&mut sidecar, &ownership); - for _ in 1..(cap + 5) { - complete_one_sidecar_response(&mut sidecar, &ownership); - } - - assert_eq!( - sidecar.completed_sidecar_responses.len(), - cap, - "completed sidecar responses must stay bounded at the cap" - ); - assert_eq!( - sidecar.completed_sidecar_responses_gauge.depth(), - cap, - "the completion gauge must track the bounded map depth" - ); - assert!( - sidecar.take_sidecar_response(oldest_request_id).is_none(), - "the oldest unretrieved response should be evicted once the cap is exceeded" - ); - - // A response completed after the cap was reached is still retrievable, - // proving eviction drops the front and keeps the most recent entries. - let recent_request_id = complete_one_sidecar_response(&mut sidecar, &ownership); - assert!( - sidecar.take_sidecar_response(recent_request_id).is_some(), - "a freshly completed response should remain retrievable after eviction" - ); - } - - // Retrieving completed responses must keep the gauge in sync so the - // limit registry never reports phantom backlog after the host drains. - fn taking_sidecar_responses_releases_completion_gauge() { - let mut sidecar = create_test_sidecar(); - let ownership = OwnershipScope::connection("conn-completion-drain"); - - let mut request_ids = Vec::new(); - for _ in 0..8 { - request_ids.push(complete_one_sidecar_response(&mut sidecar, &ownership)); - } - assert_eq!(sidecar.completed_sidecar_responses_gauge.depth(), 8); - - for request_id in request_ids { - assert!( - sidecar.take_sidecar_response(request_id).is_some(), - "each completed response should be retrievable exactly once" - ); - } - assert_eq!( - sidecar.completed_sidecar_responses_gauge.depth(), - 0, - "draining every completed response must return the gauge to zero" - ); - assert_eq!(sidecar.completed_sidecar_responses.len(), 0); - } - - fn process_event_sender_is_bounded() { - let sidecar = create_test_sidecar(); - - for index in 0..MAX_PROCESS_EVENT_QUEUE { - sidecar - .process_event_sender - .try_send(test_process_event(index)) - .expect("bounded process event sender should accept capacity"); - } - - assert!(matches!( - sidecar - .process_event_sender - .try_send(test_process_event(MAX_PROCESS_EVENT_QUEUE)), - Err(tokio::sync::mpsc::error::TrySendError::Full(_)) - )); - } - - fn pending_process_events_are_bounded() { - let mut sidecar = create_test_sidecar(); - - for index in 0..MAX_PROCESS_EVENT_QUEUE { - sidecar - .queue_pending_process_event(test_process_event(index)) - .expect("pending process event queue should accept capacity"); - } - - let error = sidecar - .queue_pending_process_event(test_process_event(MAX_PROCESS_EVENT_QUEUE)) - .expect_err("pending process event queue should reject overflow"); - assert!( - error.to_string().contains("process event queue exceeded"), - "unexpected overflow error: {error}" - ); - } - - fn process_event_receiver_overflow_preserves_queued_event() { - let mut sidecar = create_test_sidecar(); - - for index in 0..MAX_PROCESS_EVENT_QUEUE { - sidecar - .queue_pending_process_event(test_process_event(index)) - .expect("pending process event queue should accept capacity"); - } - - let expected_process_id = format!("proc-queue-{MAX_PROCESS_EVENT_QUEUE}"); - sidecar - .process_event_sender - .try_send(test_process_event(MAX_PROCESS_EVENT_QUEUE)) - .expect("queue process event behind full pending queue"); - - let error = sidecar - .take_matching_process_event_envelope("vm-queue", &expected_process_id) - .expect_err("receiver drain should reject overflow before consuming event"); - assert!( - error.to_string().contains("process event queue exceeded"), - "unexpected overflow error: {error}" - ); - - let preserved = sidecar - .process_event_receiver - .as_mut() - .expect("process event receiver") - .try_recv() - .expect("overflowing receiver event should remain queued"); - assert_eq!(preserved.process_id, expected_process_id); - } - - fn tool_execution_event_overflow_is_reported() { - let tool_execution = ToolExecution::default(); - for _ in 0..MAX_PROCESS_EVENT_QUEUE { - assert!(crate::execution::send_tool_process_event( - &tool_execution.pending_events, - &tool_execution.events_overflowed, - ActiveExecutionEvent::Stdout(Vec::new()), - )); - } - assert!(!crate::execution::send_tool_process_event( - &tool_execution.pending_events, - &tool_execution.events_overflowed, - ActiveExecutionEvent::Exited(0), - )); - - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("create tokio runtime"); - let local = tokio::task::LocalSet::new(); - runtime.block_on(local.run_until(async move { - let mut execution = ActiveExecution::Tool(tool_execution); - for _ in 0..MAX_PROCESS_EVENT_QUEUE { - assert!(matches!( - execution - .poll_event(Duration::ZERO) - .await - .expect("poll queued tool event"), - Some(ActiveExecutionEvent::Stdout(_)) - )); - } - let error = execution - .poll_event(Duration::ZERO) - .await - .expect_err("tool event overflow should be reported"); - assert!( - error.to_string().contains("process event queue exceeded"), - "unexpected overflow error: {error}" - ); - })); - } - - fn descendant_transfer_overflow_preserves_global_queue() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate sidecar"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::new(), - ) - .expect("create vm"); - insert_tool_process(&mut sidecar, &vm_id, "root-proc"); - let child = { - let kernel_handle = create_kernel_process_handle_for_tests(); - let mut child = ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Tool(ToolExecution::default()), - ); - for _ in 0..MAX_PROCESS_EVENT_QUEUE { - child - .queue_pending_execution_event(ActiveExecutionEvent::Stdout(Vec::new())) - .expect("fill child event queue"); - } - child - }; - sidecar - .vms - .get_mut(&vm_id) - .expect("test vm") - .active_processes - .get_mut("root-proc") - .expect("root process") - .child_processes - .insert(String::from("child-1"), child); - - sidecar - .queue_pending_process_event(ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - process_id: String::from("root-proc/child-1"), - event: ActiveExecutionEvent::Stdout(b"preserve".to_vec()), - }) - .expect("queue descendant event"); - - let error = sidecar - .drain_queued_descendant_javascript_child_process_events( - &vm_id, - "root-proc", - &["child-1"], - ) - .expect_err("full child queue should reject transfer"); - assert!( - error.to_string().contains("process event queue exceeded"), - "unexpected overflow error: {error}" - ); - assert_eq!(sidecar.pending_process_events.len(), 1); - assert_eq!( - sidecar - .pending_process_events - .front() - .expect("preserved global event") - .process_id, - "root-proc/child-1" - ); - } - - fn exit_trailing_requeue_preserves_exit_when_queue_is_full() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate sidecar"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::new(), - ) - .expect("create vm"); - insert_tool_process(&mut sidecar, &vm_id, "proc-exit"); - - for index in 0..(MAX_PROCESS_EVENT_QUEUE - 1) { - sidecar - .queue_pending_process_event(test_process_event(index)) - .expect("fill unrelated global queue"); - } - sidecar - .queue_pending_process_event(ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - process_id: String::from("proc-exit"), - event: ActiveExecutionEvent::Stdout(b"trailing".to_vec()), - }) - .expect("queue trailing process event"); - - let frame = sidecar - .handle_process_event_envelope(ProcessEventEnvelope { - connection_id, - session_id, - vm_id: vm_id.clone(), - process_id: String::from("proc-exit"), - event: ActiveExecutionEvent::Exited(0), - }) - .expect("handle exit with full queue") - .expect("trailing output should emit immediately"); - - assert!(matches!(frame.payload, EventPayload::ProcessOutput(_))); - let preserved_exit = sidecar - .pending_process_events - .iter() - .find(|envelope| envelope.process_id == "proc-exit") - .expect("exit should remain queued"); - assert!(matches!( - preserved_exit.event, - ActiveExecutionEvent::Exited(0) - )); - } - - fn assert_handle_limit_error(error: SidecarError) { - assert!( - error.to_string().contains("handle limit exceeded"), - "unexpected handle limit error: {error}" - ); - } - - fn cipher_session_handles_are_bounded() { - let mut process = create_crypto_test_process(); - for index in 0..crate::execution::MAX_PER_PROCESS_STATE_HANDLES { - let context = crate::crypto_cipher::StreamCipherSession::new( - "aes-256-cbc", - &[0_u8; 32], - Some(&[0_u8; 16]), - false, - true, - None, - None, - 16, - ) - .expect("create cipher context"); - process - .cipher_sessions - .insert(index as u64, ActiveCipherSession { context }); - } - - let error = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("crypto.cipherivCreate"), - args: vec![ - json!("cipher"), - json!("aes-256-cbc"), - json!(base64::engine::general_purpose::STANDARD.encode([9_u8; 32])), - json!(base64::engine::general_purpose::STANDARD.encode([4_u8; 16])), - json!(r#"{}"#), - ], - }, - ) - .expect_err("cipher session creation should be bounded"); - assert_handle_limit_error(error); - } - - fn diffie_hellman_session_handles_are_bounded() { - let mut process = create_crypto_test_process(); - for index in 0..crate::execution::MAX_PER_PROCESS_STATE_HANDLES { - process.diffie_hellman_sessions.insert( - index as u64, - ActiveDiffieHellmanSession::Ecdh(ActiveEcdhSession { - curve: String::from("P-256"), - key_pair: None, - }), - ); - } - process.next_diffie_hellman_session_id = - crate::execution::MAX_PER_PROCESS_STATE_HANDLES as u64; - - let error = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("crypto.diffieHellmanSessionCreate"), - args: vec![json!(r#"{"type":"ecdh","name":"P-256"}"#)], - }, - ) - .expect_err("diffie-hellman session creation should be bounded"); - assert_handle_limit_error(error); - - crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 20, - method: String::from("crypto.diffieHellmanSessionDestroy"), - args: vec![json!(0)], - }, - ) - .expect("destroy diffie-hellman session"); - let session_id = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 21, - method: String::from("crypto.diffieHellmanSessionCreate"), - args: vec![json!(r#"{"type":"ecdh","name":"P-256"}"#)], - }, - ) - .expect("diffie-hellman session creation should recover after destroy") - .as_u64() - .expect("new session id"); - assert!(session_id > crate::execution::MAX_PER_PROCESS_STATE_HANDLES as u64); - } - - fn create_sqlite_handle_test_sidecar() -> (NativeSidecar, String) { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate sidecar"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::new(), - ) - .expect("create vm"); - insert_tool_process(&mut sidecar, &vm_id, "proc-sqlite-handles"); - (sidecar, vm_id) - } - - fn sqlite_database_handles_are_bounded() { - let (mut sidecar, vm_id) = create_sqlite_handle_test_sidecar(); - { - let process = sidecar - .vms - .get_mut(&vm_id) - .expect("sqlite vm") - .active_processes - .get_mut("proc-sqlite-handles") - .expect("sqlite process"); - for index in 0..crate::execution::MAX_PER_PROCESS_STATE_HANDLES { - process.sqlite_databases.insert( - index as u64, - ActiveSqliteDatabase { - connection: rusqlite::Connection::open_in_memory() - .expect("open in-memory sqlite"), - host_path: None, - vm_path: None, - dirty: false, - transaction_depth: 0, - read_only: false, - }, - ); - } - } - - let error = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-sqlite-handles", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("sqlite.open"), - args: vec![json!(":memory:"), json!({})], - }, - ) - .expect_err("sqlite database creation should be bounded"); - assert_handle_limit_error(error); - } - - fn sqlite_statement_handles_are_bounded() { - let (mut sidecar, vm_id) = create_sqlite_handle_test_sidecar(); - { - let process = sidecar - .vms - .get_mut(&vm_id) - .expect("sqlite vm") - .active_processes - .get_mut("proc-sqlite-handles") - .expect("sqlite process"); - process.sqlite_databases.insert( - 1, - ActiveSqliteDatabase { - connection: rusqlite::Connection::open_in_memory() - .expect("open in-memory sqlite"), - host_path: None, - vm_path: None, - dirty: false, - transaction_depth: 0, - read_only: false, - }, - ); - for index in 0..crate::execution::MAX_PER_PROCESS_STATE_HANDLES { - process.sqlite_statements.insert( - index as u64, - ActiveSqliteStatement { - database_id: 1, - sql: String::from("SELECT 1"), - return_arrays: false, - read_bigints: false, - allow_bare_named_parameters: false, - allow_unknown_named_parameters: false, - }, - ); - } - } - - let error = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-sqlite-handles", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("sqlite.prepare"), - args: vec![json!(1), json!("SELECT 1")], - }, - ) - .expect_err("sqlite statement creation should be bounded"); - assert_handle_limit_error(error); - } - - fn create_kernel_process_handle_for_tests( - ) -> secure_exec_kernel::kernel::KernelProcessHandle { - let mut config = KernelVmConfig::new("vm-js-crypto-rpc"); - config.permissions = Permissions::allow_all(); - let mut kernel = SidecarKernel::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .register_driver(CommandDriver::new( - EXECUTION_DRIVER_NAME, - [JAVASCRIPT_COMMAND], - )) - .expect("register execution driver"); - kernel - .spawn_process( - JAVASCRIPT_COMMAND, - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - ..SpawnOptions::default() - }, - ) - .expect("spawn javascript kernel process") - } - - #[allow(dead_code)] - fn create_active_execution_for_tests() -> ActiveExecution { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate sidecar"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::new(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-crypto-rpc"); - write_fixture(&cwd.join("entry.mjs"), "export {};\n"); - let context = sidecar.javascript_engine.create_context( - secure_exec_execution::CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }, - ); - let execution = sidecar - .javascript_engine - .start_execution(secure_exec_execution::StartJavascriptExecutionRequest { - guest_runtime: Default::default(), - vm_id, - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd, - limits: Default::default(), - inline_code: Some(String::from("")), - wasm_module_bytes: None, - }) - .expect("start javascript execution"); - ActiveExecution::Javascript(execution) - } - - fn create_crypto_test_process() -> ActiveProcess { - let kernel_handle = create_kernel_process_handle_for_tests(); - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Tool(ToolExecution::default()), - ) - } - - #[derive(Debug, Clone, PartialEq, Eq)] - struct JsBridgeCallRecord { - ownership: OwnershipScope, - mount_id: String, - operation: String, - path: Option, - } - - fn js_bridge_result( - request: SidecarRequestFrame, - result: Option, - error: Option<&str>, - ) -> Result { - let SidecarRequestPayload::JsBridgeCall(call) = request.payload else { - return Err(SidecarError::InvalidState(String::from( - "expected js_bridge_call payload", - ))); - }; - Ok(SidecarResponsePayload::JsBridgeResult( - crate::protocol::JsBridgeResultResponse { - call_id: call.call_id, - result: result.map(|value| value.to_string()), - error: error.map(String::from), - }, - )) - } - - fn stat_json(stat: VirtualStat) -> Value { - json!({ - "mode": stat.mode, - "size": stat.size, - "blocks": stat.blocks, - "dev": stat.dev, - "rdev": stat.rdev, - "isDirectory": stat.is_directory, - "isSymbolicLink": stat.is_symbolic_link, - "atimeMs": stat.atime_ms, - "mtimeMs": stat.mtime_ms, - "ctimeMs": stat.ctime_ms, - "birthtimeMs": stat.birthtime_ms, - "ino": stat.ino, - "nlink": stat.nlink, - "uid": stat.uid, - "gid": stat.gid, - }) - } - - fn dir_entry_json(entry: VirtualDirEntry) -> Value { - json!({ - "name": entry.name, - "isDirectory": entry.is_directory, - "isSymbolicLink": entry.is_symbolic_link, - }) - } - - fn install_memory_js_bridge_handler( - sidecar: &mut NativeSidecar, - ) -> ( - Arc>, - Arc>>, - ) { - let filesystem = Arc::new(Mutex::new(MemoryFileSystem::new())); - let calls = Arc::new(Mutex::new(Vec::::new())); - let handler_filesystem = filesystem.clone(); - let handler_calls = calls.clone(); - - sidecar.set_sidecar_request_handler(move |request| { - let ownership = request.ownership.clone(); - let SidecarRequestPayload::JsBridgeCall(call) = &request.payload else { - return Err(SidecarError::InvalidState(String::from( - "expected js_bridge_call payload", - ))); - }; - let call_args: Value = - serde_json::from_str(&call.args).expect("js bridge args json"); - handler_calls - .lock() - .expect("lock js bridge calls") - .push(JsBridgeCallRecord { - ownership, - mount_id: call.mount_id.clone(), - operation: call.operation.clone(), - path: call_args - .get("path") - .and_then(Value::as_str) - .map(String::from), - }); - - let mut filesystem = handler_filesystem.lock().expect("lock js bridge fs"); - let response: Result, String> = match call.operation.as_str() { - "readFile" => { - let path = call_args["path"].as_str().expect("readFile path"); - filesystem - .read_file(path) - .map(|bytes| { - Some(Value::String( - base64::engine::general_purpose::STANDARD.encode(bytes), - )) - }) - .map_err(|error| format!("{}: {error}", error.code())) - } - "readDir" => { - let path = call_args["path"].as_str().expect("readDir path"); - filesystem - .read_dir(path) - .map(|entries| Some(json!(entries))) - .map_err(|error| format!("{}: {error}", error.code())) - } - "readDirWithTypes" => { - let path = call_args["path"].as_str().expect("readDirWithTypes path"); - filesystem - .read_dir_with_types(path) - .map(|entries| { - Some(Value::Array( - entries.into_iter().map(dir_entry_json).collect(), - )) - }) - .map_err(|error| format!("{}: {error}", error.code())) - } - "writeFile" => { - let path = call_args["path"].as_str().expect("writeFile path"); - let content = call_args["content"].as_str().expect("writeFile content"); - let bytes = base64::engine::general_purpose::STANDARD - .decode(content) - .expect("decode js bridge write content"); - filesystem - .write_file(path, bytes) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "createDir" => { - let path = call_args["path"].as_str().expect("createDir path"); - filesystem - .create_dir(path) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "mkdir" => { - let path = call_args["path"].as_str().expect("mkdir path"); - let recursive = call_args["recursive"].as_bool().unwrap_or(false); - filesystem - .mkdir(path, recursive) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "exists" => { - let path = call_args["path"].as_str().expect("exists path"); - Ok(Some(Value::Bool(filesystem.exists(path)))) - } - "stat" => { - let path = call_args["path"].as_str().expect("stat path"); - filesystem - .stat(path) - .map(|stat| Some(stat_json(stat))) - .map_err(|error| format!("{}: {error}", error.code())) - } - "removeFile" => { - let path = call_args["path"].as_str().expect("removeFile path"); - filesystem - .remove_file(path) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "removeDir" => { - let path = call_args["path"].as_str().expect("removeDir path"); - filesystem - .remove_dir(path) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "rename" => { - let old_path = call_args["oldPath"].as_str().expect("rename oldPath"); - let new_path = call_args["newPath"].as_str().expect("rename newPath"); - filesystem - .rename(old_path, new_path) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "realpath" => { - let path = call_args["path"].as_str().expect("realpath path"); - filesystem - .realpath(path) - .map(|resolved| Some(json!(resolved))) - .map_err(|error| format!("{}: {error}", error.code())) - } - "symlink" => { - let target = call_args["target"].as_str().expect("symlink target"); - let link_path = call_args["linkPath"].as_str().expect("symlink linkPath"); - filesystem - .symlink(target, link_path) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "readlink" => { - let path = call_args["path"].as_str().expect("readlink path"); - filesystem - .read_link(path) - .map(|target| Some(json!(target))) - .map_err(|error| format!("{}: {error}", error.code())) - } - "lstat" => { - let path = call_args["path"].as_str().expect("lstat path"); - filesystem - .lstat(path) - .map(|stat| Some(stat_json(stat))) - .map_err(|error| format!("{}: {error}", error.code())) - } - "link" => { - let old_path = call_args["oldPath"].as_str().expect("link oldPath"); - let new_path = call_args["newPath"].as_str().expect("link newPath"); - filesystem - .link(old_path, new_path) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "chmod" => { - let path = call_args["path"].as_str().expect("chmod path"); - let mode = call_args["mode"].as_u64().expect("chmod mode") as u32; - filesystem - .chmod(path, mode) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "chown" => { - let path = call_args["path"].as_str().expect("chown path"); - let uid = call_args["uid"].as_u64().expect("chown uid") as u32; - let gid = call_args["gid"].as_u64().expect("chown gid") as u32; - filesystem - .chown(path, uid, gid) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "utimes" => { - let path = call_args["path"].as_str().expect("utimes path"); - let atime = call_args["atimeMs"].as_u64().expect("utimes atimeMs"); - let mtime = call_args["mtimeMs"].as_u64().expect("utimes mtimeMs"); - filesystem - .utimes(path, atime, mtime) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "truncate" => { - let path = call_args["path"].as_str().expect("truncate path"); - let length = call_args["length"].as_u64().expect("truncate length"); - filesystem - .truncate(path, length) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - "pread" => { - let path = call_args["path"].as_str().expect("pread path"); - let offset = call_args["offset"].as_u64().expect("pread offset"); - let length = call_args["length"].as_u64().expect("pread length") as usize; - filesystem - .pread(path, offset, length) - .map(|bytes| { - Some(Value::String( - base64::engine::general_purpose::STANDARD.encode(bytes), - )) - }) - .map_err(|error| format!("{}: {error}", error.code())) - } - "pwrite" => { - let path = call_args["path"].as_str().expect("pwrite path"); - let offset = call_args["offset"].as_u64().expect("pwrite offset"); - let content = call_args["content"].as_str().expect("pwrite content"); - let bytes = base64::engine::general_purpose::STANDARD - .decode(content) - .expect("decode js bridge pwrite content"); - filesystem - .pwrite(path, bytes, offset) - .map(|()| None) - .map_err(|error| format!("{}: {error}", error.code())) - } - other => { - return Err(SidecarError::Unsupported(format!( - "unsupported op: {other}" - ))); - } - }; - - match response { - Ok(result) => js_bridge_result(request, result, None), - Err(error) => js_bridge_result(request, None, Some(&error)), - } - }); - - (filesystem, calls) - } - - fn unexpected_response_error(expected: &str, other: ResponsePayload) -> SidecarError { - SidecarError::InvalidState(format!("expected {expected} response, got {other:?}")) - } - - fn authenticated_connection_id(auth: DispatchResult) -> Result { - match auth.response.payload { - ResponsePayload::Authenticated(response) => { - assert_eq!( - auth.response.ownership, - OwnershipScope::connection(&response.connection_id) - ); - Ok(response.connection_id) - } - other => Err(unexpected_response_error("authenticated", other)), - } - } - - fn opened_session_id(session: DispatchResult) -> Result { - match session.response.payload { - ResponsePayload::SessionOpened(response) => Ok(response.session_id), - other => Err(unexpected_response_error("session_opened", other)), - } - } - - fn created_vm_id(response: DispatchResult) -> Result { - match response.response.payload { - ResponsePayload::VmCreated(response) => Ok(response.vm_id), - other => Err(unexpected_response_error("vm_created", other)), - } - } - - fn authenticate_and_open_session( - sidecar: &mut NativeSidecar, - ) -> Result<(String, String), SidecarError> { - let auth = sidecar - .dispatch_blocking(request( - 1, - OwnershipScope::connection("conn-1"), - RequestPayload::Authenticate(AuthenticateRequest { - client_name: String::from("service-tests"), - auth_token: String::from(TEST_AUTH_TOKEN), - protocol_version: secure_exec_sidecar::wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - )) - .expect("authenticate"); - let connection_id = authenticated_connection_id(auth)?; - - let session = sidecar - .dispatch_blocking(request( - 2, - OwnershipScope::connection(&connection_id), - RequestPayload::OpenSession(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared( - SidecarPlacementShared { pool: None }, - ), - metadata: std::collections::HashMap::new(), - }), - )) - .expect("open session"); - let session_id = opened_session_id(session)?; - Ok((connection_id, session_id)) - } - - fn create_vm( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - permissions: PermissionsPolicy, - ) -> Result { - create_vm_with_metadata( - sidecar, - connection_id, - session_id, - permissions, - BTreeMap::new(), - ) - } - - fn create_vm_with_metadata( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - permissions: PermissionsPolicy, - metadata: BTreeMap, - ) -> Result { - let response = sidecar - .dispatch_blocking(request( - 3, - OwnershipScope::session(connection_id, session_id), - RequestPayload::CreateVm(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - metadata.into_iter().collect(), - Default::default(), - Some(permissions), - )), - )) - .expect("create vm"); - - created_vm_id(response) - } - - fn registry_command_root() -> PathBuf { - let repo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../..") - .canonicalize() - .expect("canonicalize repo root"); - let copied = repo_root.join("registry/software/coreutils/wasm"); - if copied.exists() { - return copied; - } - - let fallback = repo_root.join("registry/native/target/wasm32-wasip1/release/commands"); - if fallback.exists() { - return fallback; - } - - let vendored = repo_root.join("packages/core/commands"); - if vendored.exists() { - let staged = temp_dir("secure-exec-sidecar-vendored-commands"); - for command in ["bash", "cat", "mkdir", "printf", "sh"] { - let source = vendored.join(command); - let target = staged.join(command); - fs::copy(&source, &target).unwrap_or_else(|error| { - panic!( - "copy vendored command {} -> {}: {error}", - source.display(), - target.display() - ) - }); - let mut permissions = fs::metadata(&target) - .expect("stat staged vendored command") - .permissions(); - permissions.set_mode(0o755); - fs::set_permissions(&target, permissions) - .expect("chmod staged vendored command"); - } - return staged; - } - - panic!( - "registry WASM commands are required for service fs regression tests: expected {}, {}, or {}", - copied.display(), - fallback.display(), - vendored.display() - ); - } - - fn configure_registry_command_mount( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - request_id: secure_exec_sidecar::protocol::RequestId, - ) { - let command_root = registry_command_root(); - sidecar - .dispatch_blocking(request( - request_id, - OwnershipScope::vm(connection_id, session_id, vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/__secure_exec/commands/0"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": command_root, - "readOnly": true, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure registry command mount"); - } - - #[allow(clippy::too_many_arguments)] // test helper mirroring the exec surface - fn run_guest_command( - sidecar: &mut NativeSidecar, - vm_id: &str, - connection_id: &str, - session_id: &str, - next_request_id: &mut secure_exec_sidecar::protocol::RequestId, - process_id: &str, - command: &str, - args: &[&str], - env: BTreeMap, - ) -> (String, String, Option) { - let request_id = *next_request_id; - *next_request_id += 1; - let response = sidecar - .dispatch_blocking(request( - request_id, - OwnershipScope::vm(connection_id, session_id, vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: process_id.to_owned(), - command: Some(command.to_owned()), - runtime: None, - entrypoint: None, - args: args.iter().map(|arg| (*arg).to_owned()).collect(), - env: env.into_iter().collect(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch guest command"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected execute response: {other:?}"), - } - - drain_process_output(sidecar, vm_id, process_id) - } - - fn run_guest_node_eval( - sidecar: &mut NativeSidecar, - vm_id: &str, - connection_id: &str, - session_id: &str, - next_request_id: &mut secure_exec_sidecar::protocol::RequestId, - process_id: &str, - source: &str, - ) -> (String, String, Option) { - run_guest_command( - sidecar, - vm_id, - connection_id, - session_id, - next_request_id, - process_id, - "node", - &["-e", source], - BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from("[\"buffer\",\"console\",\"fs\",\"path\"]"), - )]), - ) - } - - fn stdout_json(stdout: &str) -> Value { - let line = stdout - .lines() - .rev() - .find(|line| line.trim_start().starts_with('{')) - .unwrap_or_else(|| panic!("stdout did not contain a JSON object line: {stdout:?}")); - serde_json::from_str(line).expect("parse stdout JSON") - } - - fn isolated_service_test_spawn_lock() -> std::sync::MutexGuard<'static, ()> { - static ISOLATED_SERVICE_TEST_SPAWN_LOCK: OnceLock> = OnceLock::new(); - ISOLATED_SERVICE_TEST_SPAWN_LOCK - .get_or_init(|| Mutex::new(())) - .lock() - .expect("isolated service test spawn lock") - } - - fn run_isolated_service_test(test_name: &str) { - let _guard = isolated_service_test_spawn_lock(); - let current_exe = std::env::current_exe().expect("current service test binary path"); - let status = Command::new(¤t_exe) - .arg("--exact") - .arg("service::tests::__service_isolated_runner") - .arg("--nocapture") - .env(ISOLATED_SERVICE_TEST_ENV, test_name) - .env( - ISOLATED_SERVICE_CACHE_SUFFIX_ENV, - format!("{}-{}", std::process::id(), test_name.replace('-', "_")), - ) - .status() - .unwrap_or_else(|error| panic!("spawn isolated service test {test_name}: {error}")); - - assert!( - status.success(), - "isolated service test {test_name} failed with status {status}" - ); - } - - fn empty_permissions_policy() -> PermissionsPolicy { - PermissionsPolicy { - fs: None, - network: None, - child_process: None, - process: None, - env: None, - binding: None, - } - } - - fn capability_permissions(entries: &[(&str, PermissionMode)]) -> PermissionsPolicy { - let mut policy = empty_permissions_policy(); - - for (capability, mode) in entries { - match *capability { - "fs" => policy.fs = Some(FsPermissionScope::PermissionMode(mode.clone())), - "network" => { - policy.network = Some(PatternPermissionScope::PermissionMode(mode.clone())) - } - "child_process" => { - policy.child_process = - Some(PatternPermissionScope::PermissionMode(mode.clone())); - } - "process" => { - policy.process = Some(PatternPermissionScope::PermissionMode(mode.clone())); - } - "env" => { - policy.env = Some(PatternPermissionScope::PermissionMode(mode.clone())) - } - "binding" => { - policy.binding = Some(PatternPermissionScope::PermissionMode(mode.clone())) - } - _ if capability.starts_with("fs.") => { - append_fs_rule( - &mut policy, - capability.trim_start_matches("fs."), - mode.clone(), - ); - } - _ if capability.starts_with("network.") => { - append_pattern_rule( - &mut policy.network, - capability.trim_start_matches("network."), - mode.clone(), - ); - } - _ if capability.starts_with("child_process.") => { - append_pattern_rule( - &mut policy.child_process, - capability.trim_start_matches("child_process."), - mode.clone(), - ); - } - _ if capability.starts_with("process.") => { - append_pattern_rule( - &mut policy.process, - capability.trim_start_matches("process."), - mode.clone(), - ); - } - _ if capability.starts_with("env.") => { - append_pattern_rule( - &mut policy.env, - capability.trim_start_matches("env."), - mode.clone(), - ); - } - _ if capability.starts_with("binding.") => { - append_pattern_rule( - &mut policy.binding, - capability.trim_start_matches("binding."), - mode.clone(), - ); - } - _ => panic!("unsupported test capability {capability}"), - } - } - - policy - } - - fn test_toolkit_payload( - name: &str, - description: &str, - tool_name: &str, - ) -> RegisterHostCallbacksRequest { - test_toolkit_payload_with_schema( - name, - description, - tool_name, - json!({ - "type": "object", - "properties": {}, - "additionalProperties": false, - }), - ) - } - - fn test_toolkit_payload_with_schema( - name: &str, - description: &str, - tool_name: &str, - input_schema: Value, - ) -> RegisterHostCallbacksRequest { - RegisterHostCallbacksRequest { - name: String::from(name), - description: String::from(description), - command_aliases: vec![format!("agentos-{name}")], - registry_command_aliases: vec![String::from("agentos")], - callbacks: std::collections::HashMap::from([( - String::from(tool_name), - RegisteredHostCallbackDefinition { - description: format!("{tool_name} tool"), - input_schema: input_schema.to_string(), - timeout_ms: None, - examples: Vec::new(), - }, - )]), - } - } - - fn append_fs_rule(policy: &mut PermissionsPolicy, operation: &str, mode: PermissionMode) { - let scope = policy - .fs - .take() - .unwrap_or(FsPermissionScope::FsPermissionRuleSet( - FsPermissionRuleSet { - default: None, - rules: Vec::new(), - }, - )); - policy.fs = Some(match scope { - FsPermissionScope::PermissionMode(existing) => { - FsPermissionScope::FsPermissionRuleSet(FsPermissionRuleSet { - default: Some(existing), - rules: vec![FsPermissionRule { - mode, - operations: vec![operation.to_owned()], - paths: vec![String::from("/**")], - }], - }) - } - FsPermissionScope::FsPermissionRuleSet(mut rules) => { - rules.rules.push(FsPermissionRule { - mode, - operations: vec![operation.to_owned()], - paths: vec![String::from("/**")], - }); - FsPermissionScope::FsPermissionRuleSet(rules) - } - }); - } - - fn append_pattern_rule( - scope: &mut Option, - operation: &str, - mode: PermissionMode, - ) { - let existing = - scope - .take() - .unwrap_or(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: None, - rules: Vec::new(), - }, - )); - *scope = Some(match existing { - PatternPermissionScope::PermissionMode(default) => { - PatternPermissionScope::PatternPermissionRuleSet(PatternPermissionRuleSet { - default: Some(default), - rules: vec![PatternPermissionRule { - mode, - operations: vec![operation.to_owned()], - patterns: vec![String::from("**")], - }], - }) - } - PatternPermissionScope::PatternPermissionRuleSet(mut rules) => { - rules.rules.push(PatternPermissionRule { - mode, - operations: vec![operation.to_owned()], - patterns: vec![String::from("**")], - }); - PatternPermissionScope::PatternPermissionRuleSet(rules) - } - }); - } - - fn inspect_permissions(network: bool, process: bool) -> PermissionsPolicy { - PermissionsPolicy { - fs: None, - network: Some(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![ - PatternPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("listen")], - patterns: vec![String::from("**")], - }, - PatternPermissionRule { - mode: if network { - PermissionMode::Allow - } else { - PermissionMode::Deny - }, - operations: vec![String::from("inspect")], - patterns: vec![String::from("**")], - }, - ], - }, - )), - child_process: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - process: Some(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![PatternPermissionRule { - mode: if process { - PermissionMode::Allow - } else { - PermissionMode::Deny - }, - operations: vec![String::from("inspect")], - patterns: vec![String::from("**")], - }], - }, - )), - env: None, - binding: None, - } - } - - fn temp_dir(prefix: &str) -> PathBuf { - let suffix = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic enough for temp paths") - .as_nanos(); - let path = std::env::temp_dir().join(format!("{prefix}-{suffix}")); - fs::create_dir_all(&path).expect("create temp dir"); - path - } - - fn write_fixture(path: &Path, contents: impl AsRef<[u8]>) { - fs::write(path, contents).expect("write fixture"); - } - - fn cleanup_fake_runtime_process(process: ActiveProcess) { - let child_pid = process.execution.child_pid(); - let uses_shared_v8_runtime = match &process.execution { - ActiveExecution::Javascript(execution) => execution.uses_shared_v8_runtime(), - ActiveExecution::Python(execution) => execution.uses_shared_v8_runtime(), - ActiveExecution::Wasm(_) => false, - ActiveExecution::Tool(_) => false, - }; - if !uses_shared_v8_runtime { - let _ = signal_runtime_process(child_pid, SIGTERM); - } - } - - fn allow_synthetic_python_vfs_reply_drop(result: Result<(), SidecarError>, context: &str) { - match result { - Ok(()) => {} - Err(SidecarError::Execution(message)) - if message - .contains("failed to reply to guest Python VFS RPC request: session ") - && message.contains(" does not exist") => {} - Err(error) => panic!("{context}: {error}"), - } - } - - fn assert_node_available() { - let output = Command::new("node") - .arg("--version") - .output() - .expect("spawn node --version"); - assert!( - output.status.success(), - "node must be available for python dispatch tests" - ); - } - - fn run_javascript_entry( - sidecar: &mut NativeSidecar, - vm_id: &str, - cwd: &Path, - process_id: &str, - ) -> (String, String, Option) { - let mut env = BTreeMap::new(); - if let Ok(value) = std::env::var("SECURE_EXEC_HTTP2_RETAIN_TRACE") { - env.insert(String::from("SECURE_EXEC_HTTP2_RETAIN_TRACE"), value); - } - run_javascript_entry_with_env(sidecar, vm_id, cwd, process_id, env) - } - - fn run_javascript_entry_with_env( - sidecar: &mut NativeSidecar, - vm_id: &str, - cwd: &Path, - process_id: &str, - env: BTreeMap, - ) -> (String, String, Option) { - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.to_owned(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.to_owned(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: env.clone(), - cwd: cwd.to_path_buf(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(vm_id).expect("javascript vm"); - vm.active_processes.insert( - process_id.to_owned(), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_env(env) - .with_host_cwd(cwd.to_path_buf()), - ); - } - - let output = drain_process_output(sidecar, vm_id, process_id); - if std::env::var("SECURE_EXEC_HTTP2_RETAIN_TRACE").as_deref() == Ok("1") - && !output.1.is_empty() - { - eprint!("{}", output.1); - } - output - } - - struct FixtureDnsServer { - addr: SocketAddr, - running: Arc, - thread: Option>, - } - - impl FixtureDnsServer { - fn start() -> Self { - let socket = UdpSocket::bind("127.0.0.1:0").expect("bind fixture DNS server"); - socket - .set_read_timeout(Some(Duration::from_millis(100))) - .expect("set fixture DNS timeout"); - let addr = socket.local_addr().expect("fixture DNS local addr"); - let running = Arc::new(std::sync::atomic::AtomicBool::new(true)); - let thread_running = Arc::clone(&running); - let thread = thread::spawn(move || { - let mut buffer = [0_u8; 2048]; - while thread_running.load(Ordering::SeqCst) { - let Ok((len, peer)) = socket.recv_from(&mut buffer) else { - continue; - }; - let Ok(request) = Message::from_vec(&buffer[..len]) else { - continue; - }; - let response = fixture_dns_response(&request); - let bytes = response.to_vec().expect("encode fixture DNS response"); - let _ = socket.send_to(&bytes, peer); - } - }); - Self { - addr, - running, - thread: Some(thread), - } - } - } - - impl Drop for FixtureDnsServer { - fn drop(&mut self) { - self.running.store(false, Ordering::SeqCst); - if let Ok(socket) = UdpSocket::bind("127.0.0.1:0") { - let _ = socket.send_to(&[0], self.addr); - } - if let Some(thread) = self.thread.take() { - thread.join().expect("join fixture DNS thread"); - } - } - } - - fn fixture_dns_response(request: &Message) -> Message { - let mut response = Message::response(request.metadata.id, request.metadata.op_code); - response.metadata.authoritative = true; - response.metadata.recursion_available = true; - response.add_queries(request.queries.iter().cloned()); - if let Some(query) = request.queries.first() { - response.add_answers(fixture_dns_answers(query)); - } - response - } - - fn fixture_dns_answers(query: &Query) -> Vec { - let name = query.name().to_ascii(); - match (name.as_str(), query.query_type()) { - ("bundle.example.test.", RecordType::A) => vec![fixture_dns_record( - "bundle.example.test.", - RData::A(A::new(203, 0, 113, 10)), - )], - ("bundle.example.test.", RecordType::AAAA) => vec![fixture_dns_record( - "bundle.example.test.", - RData::AAAA(AAAA::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0010)), - )], - ("bundle.example.test.", RecordType::MX) => vec![fixture_dns_record( - "bundle.example.test.", - RData::MX(MX::new(10, fixture_dns_name("mail.example.test."))), - )], - ("bundle.example.test.", RecordType::TXT) => vec![ - fixture_dns_record( - "bundle.example.test.", - RData::TXT(TXT::new(vec![String::from("v=spf1"), String::from("-all")])), - ), - fixture_dns_record( - "bundle.example.test.", - RData::TXT(TXT::new(vec![String::from("secure-exec")])), - ), - ], - ("bundle.example.test.", RecordType::ANY) => vec![ - fixture_dns_record("bundle.example.test.", RData::A(A::new(203, 0, 113, 10))), - fixture_dns_record( - "bundle.example.test.", - RData::AAAA(AAAA::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0010)), - ), - fixture_dns_record( - "bundle.example.test.", - RData::MX(MX::new(10, fixture_dns_name("mail.example.test."))), - ), - fixture_dns_record( - "bundle.example.test.", - RData::TXT(TXT::new(vec![String::from("v=spf1"), String::from("-all")])), - ), - ], - ("alias.example.test.", RecordType::CNAME) => vec![fixture_dns_record( - "alias.example.test.", - RData::CNAME(CNAME(fixture_dns_name("bundle.example.test."))), - )], - ("ptr.example.test.", RecordType::PTR) => vec![fixture_dns_record( - "ptr.example.test.", - RData::PTR(PTR(fixture_dns_name("host.example.test."))), - )], - ("zone.example.test.", RecordType::NS) => vec![fixture_dns_record( - "zone.example.test.", - RData::NS(NS(fixture_dns_name("ns1.example.test."))), - )], - ("zone.example.test.", RecordType::SOA) => vec![fixture_dns_record( - "zone.example.test.", - RData::SOA(SOA::new( - fixture_dns_name("ns1.example.test."), - fixture_dns_name("hostmaster.example.test."), - 2026041601, - 3600, - 600, - 86400, - 60, - )), - )], - ("_svc._tcp.example.test.", RecordType::SRV) => vec![fixture_dns_record( - "_svc._tcp.example.test.", - RData::SRV(SRV::new( - 1, - 5, - 8443, - fixture_dns_name("svc-target.example.test."), - )), - )], - ("naptr.example.test.", RecordType::NAPTR) => vec![fixture_dns_record( - "naptr.example.test.", - RData::NAPTR(NAPTR::new( - 10, - 20, - b"s".to_vec().into_boxed_slice(), - b"SIP+D2U".to_vec().into_boxed_slice(), - b"!^.*$!sip:service@example.test!" - .to_vec() - .into_boxed_slice(), - fixture_dns_name("_sip._udp.example.test."), - )), - )], - ("caa.example.test.", RecordType::CAA) => vec![ - fixture_dns_record( - "caa.example.test.", - RData::CAA(CAA::new_issue( - false, - Some(fixture_dns_name("letsencrypt.org.")), - vec![], - )), - ), - fixture_dns_record( - "caa.example.test.", - RData::CAA(CAA::new_iodef( - false, - url::Url::parse("https://iodef.example.test/report") - .expect("fixture CAA iodef URL"), - )), - ), - ], - _ => Vec::new(), - } - } - - fn fixture_dns_record(name: &str, data: RData) -> Record { - Record::from_rdata(fixture_dns_name(name), 60, data) - } - - fn fixture_dns_name(name: &str) -> Name { - name.parse().expect("valid fixture DNS name") - } - - fn append_process_stream_chunk( - stream: &mut Vec, - chunk: &[u8], - process_id: &str, - stream_name: &str, - ) { - assert!( - process_stream_chunk_fits(stream.len(), chunk.len()), - "process {process_id} {stream_name} exceeded {MAX_SERVICE_PROCESS_STREAM_BYTES} bytes" - ); - stream.extend_from_slice(chunk); - } - - fn process_stream_chunk_fits(current_len: usize, chunk_len: usize) -> bool { - current_len.saturating_add(chunk_len) <= MAX_SERVICE_PROCESS_STREAM_BYTES - } - - fn process_stream_to_string(stream: &[u8]) -> String { - String::from_utf8_lossy(stream).into_owned() - } - - fn drain_process_output( - sidecar: &mut NativeSidecar, - vm_id: &str, - process_id: &str, - ) -> (String, String, Option) { - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - let deadline = Instant::now() + Duration::from_secs(30); - let mut events_drained = 0; - while events_drained < 10_000 && Instant::now() < deadline { - events_drained += 1; - pump_sibling_internal_process_events(sidecar, vm_id, process_id); - let next_event = { - let vm = sidecar.vms.get_mut(vm_id).expect("active vm"); - vm.active_processes.get_mut(process_id).and_then(|process| { - if let Some(event) = process.pending_execution_events.pop_front() { - Some(event) - } else { - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll process event") - } - }) - }; - let Some(event) = next_event else { - if exit_code.is_some() { - break; - } - panic!("process {process_id} disappeared before exit"); - }; - - match &event { - ActiveExecutionEvent::Stdout(chunk) => { - append_process_stream_chunk(&mut stdout, chunk, process_id, "stdout"); - } - ActiveExecutionEvent::Stderr(chunk) => { - append_process_stream_chunk(&mut stderr, chunk, process_id, "stderr"); - } - ActiveExecutionEvent::Exited(code) => { - exit_code = Some(*code); - } - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } => {} - } - - sidecar - .handle_execution_event(vm_id, process_id, event) - .expect("handle process event"); - pump_sibling_internal_process_events(sidecar, vm_id, process_id); - } - - ( - process_stream_to_string(&stdout), - process_stream_to_string(&stderr), - exit_code, - ) - } - - fn pump_sibling_internal_process_events( - sidecar: &mut NativeSidecar, - vm_id: &str, - target_process_id: &str, - ) { - for _ in 0..64 { - let process_ids = sidecar - .vms - .get(vm_id) - .map(|vm| vm.active_processes.keys().cloned().collect::>()) - .unwrap_or_default(); - let mut progressed = false; - - for process_id in process_ids { - if process_id == target_process_id { - continue; - } - let event = { - let Some(vm) = sidecar.vms.get_mut(vm_id) else { - continue; - }; - let Some(process) = vm.active_processes.get_mut(&process_id) else { - continue; - }; - if let Some(event) = process.pending_execution_events.pop_front() { - Some(event) - } else { - process - .execution - .poll_event_blocking(Duration::from_millis(10)) - .expect("poll sibling process event") - } - }; - let Some(event) = event else { - continue; - }; - - if matches!( - event, - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } - ) { - sidecar - .handle_execution_event(vm_id, &process_id, event) - .expect("handle sibling internal process event"); - progressed = true; - } else if let Some(process) = sidecar - .vms - .get_mut(vm_id) - .and_then(|vm| vm.active_processes.get_mut(&process_id)) - { - process - .queue_pending_execution_event(event) - .expect("requeue sibling public process event"); - } - } - - if !progressed { - break; - } - } - } - - fn wait_for_process_stdout_contains( - sidecar: &mut NativeSidecar, - vm_id: &str, - process_id: &str, - needle: &str, - ) -> String { - let mut stdout = Vec::new(); - for _ in 0..64 { - let next_event = { - let vm = sidecar.vms.get_mut(vm_id).expect("active vm"); - vm.active_processes.get_mut(process_id).and_then(|process| { - if let Some(event) = process.pending_execution_events.pop_front() { - Some(event) - } else { - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll process event") - } - }) - }; - let Some(event) = next_event else { - panic!("process {process_id} disappeared before writing {needle:?}"); - }; - if let ActiveExecutionEvent::Stdout(chunk) = &event { - append_process_stream_chunk(&mut stdout, chunk, process_id, "stdout"); - if process_stream_to_string(&stdout).contains(needle) { - sidecar - .handle_execution_event(vm_id, process_id, event) - .expect("handle process event"); - return process_stream_to_string(&stdout); - } - } - if let ActiveExecutionEvent::Exited(code) = &event { - panic!("process {process_id} exited with {code} before writing {needle:?}"); - } - sidecar - .handle_execution_event(vm_id, process_id, event) - .expect("handle process event"); - } - panic!("process {process_id} did not write {needle:?}"); - } - - fn wasm_stdout_module(message: &str) -> Vec { - wat::parse_str(format!( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) - (data (i32.const 16) "{message}\n") - (func $_start (export "_start") - (i32.store (i32.const 0) (i32.const 16)) - (i32.store (i32.const 4) (i32.const {length})) - (drop - (call $fd_write - (i32.const 1) - (i32.const 0) - (i32.const 1) - (i32.const 32) - ) - ) - ) -) -"#, - length = message.len() + 1, - )) - .expect("compile wasm stdout fixture") - } - - fn wat_escape_ascii(input: &str) -> String { - let mut escaped = String::new(); - for ch in input.chars() { - match ch { - '\\' => escaped.push_str("\\\\"), - '"' => escaped.push_str("\\\""), - '\n' => escaped.push_str("\\n"), - '\r' => escaped.push_str("\\0d"), - _ => escaped.push(ch), - } - } - escaped - } - - fn wasm_expect_read_errno_module(path: &str, expected_errno: u32) -> Vec { - wat::parse_str(format!( - r#" -(module - (type $path_open_t (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) - (type $fd_read_t (func (param i32 i32 i32 i32) (result i32))) - (type $fd_close_t (func (param i32) (result i32))) - (import "wasi_snapshot_preview1" "path_open" (func $path_open (type $path_open_t))) - (import "wasi_snapshot_preview1" "fd_read" (func $fd_read (type $fd_read_t))) - (import "wasi_snapshot_preview1" "fd_close" (func $fd_close (type $fd_close_t))) - (memory (export "memory") 1) - (data (i32.const 64) "{path}") - (func $_start (export "_start") - (local $errno i32) - (local $fd i32) - (local.set $errno - (call $path_open - (i32.const 3) - (i32.const 0) - (i32.const 64) - (i32.const {path_len}) - (i32.const 0) - (i64.const 2) - (i64.const 2) - (i32.const 0) - (i32.const 8) - ) - ) - (if - (i32.ne - (local.get $errno) - (i32.const 0) - ) - (then unreachable) - ) - (local.set $fd (i32.load (i32.const 8))) - (i32.store (i32.const 16) (i32.const 128)) - (i32.store (i32.const 20) (i32.const 8)) - (local.set $errno - (call $fd_read - (local.get $fd) - (i32.const 16) - (i32.const 1) - (i32.const 24) - ) - ) - (if - (i32.ne - (local.get $errno) - (i32.const {expected_errno}) - ) - (then unreachable) - ) - (drop (call $fd_close (local.get $fd))) - ) -) -"#, - path = wat_escape_ascii(path), - path_len = path.len(), - )) - .expect("compile wasm read errno fixture") - } - - fn wasm_expect_write_open_errno_module(path: &str, expected_errno: u32) -> Vec { - wat::parse_str(format!( - r#" -(module - (type $path_open_t (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) - (type $fd_close_t (func (param i32) (result i32))) - (import "wasi_snapshot_preview1" "path_open" (func $path_open (type $path_open_t))) - (import "wasi_snapshot_preview1" "fd_close" (func $fd_close (type $fd_close_t))) - (memory (export "memory") 1) - (data (i32.const 64) "{path}") - (func $_start (export "_start") - (local $errno i32) - (local.set $errno - (call $path_open - (i32.const 3) - (i32.const 0) - (i32.const 64) - (i32.const {path_len}) - (i32.const 1) - (i64.const 64) - (i64.const 64) - (i32.const 0) - (i32.const 8) - ) - ) - (if - (i32.ne - (local.get $errno) - (i32.const {expected_errno}) - ) - (then unreachable) - ) - (if - (i32.eq (local.get $errno) (i32.const 0)) - (then - (drop (call $fd_close (i32.load (i32.const 8)))) - ) - ) - ) -) -"#, - path = wat_escape_ascii(path), - path_len = path.len(), - )) - .expect("compile wasm write-open errno fixture") - } - - fn start_fake_wasm_process( - sidecar: &mut NativeSidecar, - vm_id: &str, - cwd: &Path, - process_id: &str, - attach_stdout_pty: bool, - ) -> Option { - let context = sidecar - .wasm_engine - .create_context(CreateWasmContextRequest { - vm_id: vm_id.to_owned(), - module_path: Some(String::from("./guest.wasm")), - }); - - let env = { - let vm = sidecar.vms.get(vm_id).expect("wasm vm"); - BTreeMap::from([ - ( - String::from(EXECUTION_SANDBOX_ROOT_ENV), - normalize_host_path(&vm.cwd).to_string_lossy().into_owned(), - ), - (String::from(WASM_STDIO_SYNC_RPC_ENV), String::from("1")), - ]) - }; - - let execution = sidecar - .wasm_engine - .start_execution(StartWasmExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: vm_id.to_owned(), - context_id: context.context_id, - argv: vec![String::from("./guest.wasm")], - env: env.clone(), - cwd: cwd.to_path_buf(), - permission_tier: WasmPermissionTier::Full, - }) - .expect("start fake wasm execution"); - - let (kernel_handle, master_fd) = { - let vm = sidecar.vms.get_mut(vm_id).expect("wasm vm"); - let kernel_handle = vm - .kernel - .spawn_process( - WASM_COMMAND, - vec![String::from("./guest.wasm")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel wasm process"); - let kernel_pid = kernel_handle.pid(); - let master_fd = if attach_stdout_pty { - let (master_fd, slave_fd, _pty_path) = vm - .kernel - .open_pty(EXECUTION_DRIVER_NAME, kernel_pid) - .expect("open kernel pty"); - vm.kernel - .fd_dup2(EXECUTION_DRIVER_NAME, kernel_pid, slave_fd, 1) - .expect("dup kernel pty slave onto fd 1"); - vm.kernel - .fd_close(EXECUTION_DRIVER_NAME, kernel_pid, slave_fd) - .expect("close extra kernel pty slave fd"); - Some(master_fd) - } else { - None - }; - (kernel_handle, master_fd) - }; - - let vm = sidecar.vms.get_mut(vm_id).expect("wasm vm"); - let kernel_pid = kernel_handle.pid(); - vm.active_processes.insert( - process_id.to_owned(), - ActiveProcess::new( - kernel_pid, - kernel_handle, - GuestRuntimeKind::WebAssembly, - ActiveExecution::Wasm(Box::new(execution)), - ) - .with_guest_cwd(String::from("/")) - .with_env(env) - .with_host_cwd(cwd.to_path_buf()), - ); - - master_fd - } - - fn start_fake_javascript_process( - sidecar: &mut NativeSidecar, - vm_id: &str, - cwd: &Path, - process_id: &str, - ) { - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.to_owned(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.to_owned(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: cwd.to_path_buf(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - let vm = sidecar.vms.get_mut(vm_id).expect("javascript vm"); - vm.active_processes.insert( - process_id.to_owned(), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.to_path_buf()), - ); - } - - fn insert_fake_javascript_parent_process( - sidecar: &mut NativeSidecar, - vm_id: &str, - cwd: &Path, - process_id: &str, - ) { - let (kernel_handle, guest_env) = { - let vm = sidecar.vms.get_mut(vm_id).expect("javascript vm"); - let handle = vm - .kernel - .create_virtual_process( - EXECUTION_DRIVER_NAME, - EXECUTION_DRIVER_NAME, - JAVASCRIPT_COMMAND, - vec![String::from(JAVASCRIPT_COMMAND)], - VirtualProcessOptions { - env: vm.guest_env.clone(), - cwd: Some(String::from("/")), - ..VirtualProcessOptions::default() - }, - ) - .expect("create virtual javascript parent"); - (handle, vm.guest_env.clone()) - }; - - let vm = sidecar.vms.get_mut(vm_id).expect("javascript vm"); - vm.active_processes.insert( - process_id.to_owned(), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Tool(ToolExecution::default()), - ) - .with_env(guest_env) - .with_host_cwd(cwd.to_path_buf()), - ); - } - - fn call_javascript_sync_rpc_response( - sidecar: &mut NativeSidecar, - vm_id: &str, - process_id: &str, - request: JavascriptSyncRpcRequest, - ) -> Result { - let bridge = sidecar.bridge.clone(); - let (dns, socket_paths, counts, limits, kernel_readiness) = { - let vm = sidecar.vms.get(vm_id).expect("javascript vm"); - ( - vm.dns.clone(), - build_javascript_socket_path_context(vm).expect("build socket path context"), - vm.active_processes - .get(process_id) - .expect("javascript process") - .network_resource_counts(), - ResourceLimits::default(), - vm.kernel_socket_readiness.clone(), - ) - }; - - let vm = sidecar.vms.get_mut(vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut(process_id) - .expect("javascript process"); - service_javascript_sync_rpc(JavascriptSyncRpcServiceRequest { - bridge: &bridge, - vm_id, - dns: &dns, - socket_paths: &socket_paths, - kernel: &mut vm.kernel, - kernel_readiness, - process, - sync_request: &request, - resource_limits: &limits, - network_counts: counts, - }) - } - - fn call_javascript_sync_rpc( - sidecar: &mut NativeSidecar, - vm_id: &str, - process_id: &str, - request: JavascriptSyncRpcRequest, - ) -> Result { - call_javascript_sync_rpc_response(sidecar, vm_id, process_id, request).and_then( - |response| match response { - JavascriptSyncRpcServiceResponse::Json(value) => Ok(value), - JavascriptSyncRpcServiceResponse::Raw(_) => Err(SidecarError::Execution( - String::from("expected JSON sync RPC response"), - )), - }, - ) - } - - fn read_javascript_socket_chunk( - sidecar: &mut NativeSidecar, - vm_id: &str, - process_id: &str, - socket_id: &str, - request_id_start: u64, - attempts: u64, - context: &str, - ) -> Vec { - for attempt in 0..attempts { - let response = call_javascript_sync_rpc_response( - sidecar, - vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: request_id_start + attempt, - method: String::from("net.socket_read"), - args: vec![json!(socket_id)], - }, - ) - .unwrap_or_else(|error| panic!("{context}: {error}")); - match response { - JavascriptSyncRpcServiceResponse::Raw(chunk) => return chunk, - JavascriptSyncRpcServiceResponse::Json(value) - if value == "__secure_exec_net_timeout__" => - { - thread::sleep(std::time::Duration::from_millis(10)); - } - JavascriptSyncRpcServiceResponse::Json(value) => { - panic!("{context}: expected socket data chunk, got {value}"); - } - } - } - - panic!("{context}: timed out waiting for socket data chunk"); - } - - #[allow(clippy::too_many_arguments)] - fn service_javascript_net_sync_rpc( - bridge: &SharedBridge, - vm_id: &str, - dns: &VmDnsConfig, - socket_paths: &JavascriptSocketPathContext, - kernel: &mut SidecarKernel, - process: &mut ActiveProcess, - request: &JavascriptSyncRpcRequest, - resource_limits: &ResourceLimits, - network_counts: NetworkResourceCounts, - ) -> Result - where - B: NativeSidecarBridge + Send + 'static, - BridgeError: fmt::Debug + Send + Sync + 'static, - { - service_javascript_net_sync_rpc_inner(JavascriptNetSyncRpcServiceRequest { - bridge, - vm_id, - dns, - socket_paths, - kernel, - kernel_readiness: Default::default(), - process, - sync_request: request, - resource_limits, - network_counts, - }) - } - - fn kernel_socket_queries_ignore_stale_sidecar_guest_addresses() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-kernel-socket-query-state"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-kernel-query"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-kernel-query", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 43111, - })], - }, - ) - .expect("listen on kernel-backed tcp socket"); - let listener_id = listen["serverId"] - .as_str() - .expect("listener id") - .to_string(); - - let udp_socket = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-kernel-query", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("dgram.createSocket"), - args: vec![json!({ "type": "udp4" })], - }, - ) - .expect("create kernel-backed udp socket"); - let udp_socket_id = udp_socket["socketId"] - .as_str() - .expect("udp socket id") - .to_string(); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-kernel-query", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("dgram.bind"), - args: vec![ - json!(udp_socket_id.clone()), - json!({ - "address": "127.0.0.1", - "port": 43112, - }), - ], - }, - ) - .expect("bind kernel-backed udp socket"); - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("vm state"); - let process = vm - .active_processes - .get_mut("proc-js-kernel-query") - .expect("javascript process"); - let listener = process - .tcp_listeners - .get_mut(&listener_id) - .expect("tcp listener state"); - listener.local_addr = Some(SocketAddr::from(([127, 0, 0, 1], 49991))); - listener.guest_local_addr = SocketAddr::from(([127, 0, 0, 1], 49991)); - - let udp_socket = process - .udp_sockets - .get_mut(&udp_socket_id) - .expect("udp socket state"); - udp_socket.guest_local_addr = Some(SocketAddr::from(([127, 0, 0, 1], 49992))); - } - - let listener_response = sidecar - .dispatch_blocking(request( - 10, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindListener(FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43111), - path: None, - }), - )) - .expect("query kernel-backed listener"); - match listener_response.response.payload { - ResponsePayload::ListenerSnapshot(snapshot) => { - let listener = snapshot.listener.expect("listener snapshot"); - assert_eq!(listener.process_id, "proc-js-kernel-query"); - assert_eq!(listener.host.as_deref(), Some("127.0.0.1")); - assert_eq!(listener.port, Some(43111)); - } - other => panic!("unexpected listener response payload: {other:?}"), - } - - let udp_response = sidecar - .dispatch_blocking(request( - 11, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindBoundUdp(FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43112), - }), - )) - .expect("query kernel-backed udp socket"); - match udp_response.response.payload { - ResponsePayload::BoundUdpSnapshot(snapshot) => { - let socket = snapshot.socket.expect("bound udp snapshot"); - assert_eq!(socket.process_id, "proc-js-kernel-query"); - assert_eq!(socket.host.as_deref(), Some("127.0.0.1")); - assert_eq!(socket.port, Some(43112)); - } - other => panic!("unexpected bound udp response payload: {other:?}"), - } - } - fn find_listener_rejects_without_network_inspect_permission() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - inspect_permissions(false, false), - ) - .expect("create vm"); - - let response = sidecar - .dispatch_blocking(request( - 12, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindListener(FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43111), - path: None, - }), - )) - .expect("dispatch listener query"); - - match response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "execution_error"); - assert!( - rejected - .message - .contains("blocked by network.inspect policy"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - } - fn find_listener_returns_listener_with_network_inspect_permission() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - inspect_permissions(true, false), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-inspect-listener"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-inspect-listener"); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-inspect-listener", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 43111, - })], - }, - ) - .expect("listen on kernel-backed tcp socket"); - - let response = sidecar - .dispatch_blocking(request( - 13, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindListener(FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43111), - path: None, - }), - )) - .expect("query listener"); - - match response.response.payload { - ResponsePayload::ListenerSnapshot(snapshot) => { - let listener = snapshot.listener.expect("listener snapshot"); - assert_eq!(listener.process_id, "proc-js-inspect-listener"); - assert_eq!(listener.host.as_deref(), Some("127.0.0.1")); - assert_eq!(listener.port, Some(43111)); - } - other => panic!("unexpected listener response payload: {other:?}"), - } - } - fn find_bound_udp_rejects_without_network_inspect_permission() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - inspect_permissions(false, false), - ) - .expect("create vm"); - - let response = sidecar - .dispatch_blocking(request( - 14, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindBoundUdp(FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43112), - }), - )) - .expect("dispatch udp query"); - - match response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "execution_error"); - assert!( - rejected - .message - .contains("blocked by network.inspect policy"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - } - fn find_bound_udp_returns_socket_with_network_inspect_permission() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - inspect_permissions(true, false), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-inspect-udp"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-inspect-udp"); - - let udp_socket = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-inspect-udp", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("dgram.createSocket"), - args: vec![json!({ "type": "udp4" })], - }, - ) - .expect("create kernel-backed udp socket"); - let udp_socket_id = udp_socket["socketId"] - .as_str() - .expect("udp socket id") - .to_string(); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-inspect-udp", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("dgram.bind"), - args: vec![ - json!(udp_socket_id), - json!({ - "address": "127.0.0.1", - "port": 43112, - }), - ], - }, - ) - .expect("bind kernel-backed udp socket"); - - let response = sidecar - .dispatch_blocking(request( - 15, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindBoundUdp(FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43112), - }), - )) - .expect("query bound udp socket"); - - match response.response.payload { - ResponsePayload::BoundUdpSnapshot(snapshot) => { - let socket = snapshot.socket.expect("bound udp snapshot"); - assert_eq!(socket.process_id, "proc-js-inspect-udp"); - assert_eq!(socket.host.as_deref(), Some("127.0.0.1")); - assert_eq!(socket.port, Some(43112)); - } - other => panic!("unexpected bound udp response payload: {other:?}"), - } - } - fn get_process_snapshot_rejects_without_process_inspect_permission() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - inspect_permissions(false, false), - ) - .expect("create vm"); - - let response = sidecar - .dispatch_blocking(request( - 16, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::GetProcessSnapshot(GetProcessSnapshotRequest {}), - )) - .expect("dispatch process snapshot"); - - match response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "execution_error"); - assert!( - rejected - .message - .contains("blocked by process.inspect policy"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - } - fn get_process_snapshot_returns_processes_with_process_inspect_permission() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - inspect_permissions(false, true), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-inspect-processes"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-inspect-processes"); - - let response = sidecar - .dispatch_blocking(request( - 17, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::GetProcessSnapshot(GetProcessSnapshotRequest {}), - )) - .expect("query process snapshot"); - - match response.response.payload { - ResponsePayload::ProcessSnapshot(snapshot) => { - assert!( - snapshot - .processes - .iter() - .any(|entry| entry.process_id == "proc-js-inspect-processes"), - "expected active process in snapshot: {:?}", - snapshot.processes - ); - } - other => panic!("unexpected process snapshot response payload: {other:?}"), - } - } - fn get_resource_snapshot_rejects_without_process_inspect_permission() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - inspect_permissions(false, false), - ) - .expect("create vm"); - - let response = sidecar - .dispatch_blocking(request( - 18, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::GetResourceSnapshot(GetResourceSnapshotRequest {}), - )) - .expect("dispatch resource snapshot"); - - match response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "execution_error"); - assert!( - rejected - .message - .contains("blocked by process.inspect policy"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - } - fn get_resource_snapshot_returns_kernel_and_queue_counts_with_process_inspect_permission() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - inspect_permissions(false, true), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-inspect-resources"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-inspect-resources"); - - let response = sidecar - .dispatch_blocking(request( - 19, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::GetResourceSnapshot(GetResourceSnapshotRequest {}), - )) - .expect("query resource snapshot"); - - match response.response.payload { - ResponsePayload::ResourceSnapshot(snapshot) => { - assert!( - snapshot.running_processes >= 1, - "expected running kernel process in snapshot: {snapshot:?}" - ); - assert!( - snapshot.fd_tables >= 1, - "expected fd table accounting in snapshot: {snapshot:?}" - ); - assert!( - snapshot - .queue_snapshots - .iter() - .any(|entry| entry.name == "pending_process_events"), - "expected sidecar queue gauges in snapshot: {snapshot:?}" - ); - } - other => panic!("unexpected resource snapshot response payload: {other:?}"), - } - } - fn vm_network_resource_counts_ignore_duplicate_sidecar_kernel_entries() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-kernel-network-counts"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-kernel-counts"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-kernel-counts", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 43121, - })], - }, - ) - .expect("listen on kernel-backed tcp socket"); - let listener_id = listen["serverId"] - .as_str() - .expect("listener id") - .to_string(); - - let udp_socket = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-kernel-counts", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("dgram.createSocket"), - args: vec![json!({ "type": "udp4" })], - }, - ) - .expect("create kernel-backed udp socket"); - let udp_socket_id = udp_socket["socketId"] - .as_str() - .expect("udp socket id") - .to_string(); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-kernel-counts", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("dgram.bind"), - args: vec![ - json!(udp_socket_id.clone()), - json!({ - "address": "127.0.0.1", - "port": 43122, - }), - ], - }, - ) - .expect("bind kernel-backed udp socket"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("vm state"); - let process = vm - .active_processes - .get_mut("proc-js-kernel-counts") - .expect("javascript process"); - - let duplicate_listener = { - let listener = process - .tcp_listeners - .get(&listener_id) - .expect("tcp listener state"); - ActiveTcpListener { - listener: None, - kernel_socket_id: listener.kernel_socket_id, - local_addr: Some(SocketAddr::from(([127, 0, 0, 1], 49993))), - guest_local_addr: SocketAddr::from(([127, 0, 0, 1], 49993)), - backlog: listener.backlog, - active_connection_ids: std::collections::BTreeSet::new(), - } - }; - process - .tcp_listeners - .insert(String::from("listener-dup"), duplicate_listener); - - let duplicate_udp = { - let socket = process - .udp_sockets - .get(&udp_socket_id) - .expect("udp socket state"); - ActiveUdpSocket { - family: socket.family, - socket: None, - kernel_socket_id: socket.kernel_socket_id, - guest_local_addr: Some(SocketAddr::from(([127, 0, 0, 1], 49994))), - recv_buffer_size: socket.recv_buffer_size, - send_buffer_size: socket.send_buffer_size, - } - }; - process - .udp_sockets - .insert(String::from("udp-socket-dup"), duplicate_udp); - - let kernel_snapshot = vm.kernel.resource_snapshot(); - assert_eq!(kernel_snapshot.sockets, 2); - assert_eq!(kernel_snapshot.socket_connections, 0); - - let counts = vm_network_resource_counts(vm); - assert_eq!(counts.sockets, 2); - assert_eq!(counts.connections, 0); - } - - fn poll_http2_event( - sidecar: &mut NativeSidecar, - vm_id: &str, - process_id: &str, - method: &str, - id: u64, - kind: &str, - ) -> Value { - for _ in 0..200 { - let value = call_javascript_sync_rpc( - sidecar, - vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 9_000, - method: String::from(method), - args: vec![json!(id), json!(25)], - }, - ) - .expect("poll http2 event"); - if value.is_null() { - thread::sleep(Duration::from_millis(10)); - continue; - } - let event: Value = serde_json::from_str(value.as_str().expect("event payload")) - .expect("parse http2 event"); - if event["kind"] == Value::String(String::from(kind)) { - return event; - } - } - panic!("timed out waiting for {method} {kind}"); - } - - fn tls_test_certificates() -> Vec> { - rustls_pemfile::certs(&mut BufReader::new(TLS_TEST_CERT_PEM.as_bytes())) - .collect::, _>>() - .expect("parse TLS test certificate") - } - - fn tls_test_private_key() -> rustls::pki_types::PrivateKeyDer<'static> { - rustls_pemfile::private_key(&mut BufReader::new(TLS_TEST_KEY_PEM.as_bytes())) - .expect("parse TLS test private key") - .expect("TLS test private key") - } - - fn tls_test_server_config(alpn: &[&str]) -> Arc { - let mut config = - ServerConfig::builder_with_provider(Arc::new(aws_lc_rs::default_provider())) - .with_safe_default_protocol_versions() - .expect("TLS server protocol versions") - .with_no_client_auth() - .with_single_cert(tls_test_certificates(), tls_test_private_key()) - .expect("build TLS test server config"); - config.alpn_protocols = alpn - .iter() - .map(|protocol| protocol.as_bytes().to_vec()) - .collect(); - Arc::new(config) - } - - #[derive(Debug)] - struct TestInsecureTlsVerifier { - supported_schemes: Vec, - } - - impl ServerCertVerifier for TestInsecureTlsVerifier { - fn verify_server_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp_response: &[u8], - _now: rustls::pki_types::UnixTime, - ) -> Result { - Ok(ServerCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result { - Ok(HandshakeSignatureValid::assertion()) - } - - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result { - Ok(HandshakeSignatureValid::assertion()) - } - - fn supported_verify_schemes(&self) -> Vec { - self.supported_schemes.clone() - } - } - - fn tls_test_client_config(trust_test_cert: bool, alpn: &[&str]) -> Arc { - let provider = Arc::new(aws_lc_rs::default_provider()); - let builder = ClientConfig::builder_with_provider(provider.clone()) - .with_safe_default_protocol_versions() - .expect("TLS client protocol versions"); - let mut config = if trust_test_cert { - let mut roots = RootCertStore::empty(); - for certificate in tls_test_certificates() { - roots.add(certificate).expect("add TLS test certificate"); - } - builder.with_root_certificates(roots).with_no_client_auth() - } else { - let verifier = Arc::new(TestInsecureTlsVerifier { - supported_schemes: provider - .signature_verification_algorithms - .supported_schemes(), - }); - builder - .dangerous() - .with_custom_certificate_verifier(verifier) - .with_no_client_auth() - }; - config.alpn_protocols = alpn - .iter() - .map(|protocol| protocol.as_bytes().to_vec()) - .collect(); - Arc::new(config) - } - - fn loopback_tls_endpoints() -> ( - crate::state::LoopbackTlsEndpoint, - crate::state::LoopbackTlsEndpoint, - ) { - let pair = Arc::new(crate::state::LoopbackTlsTransportPair { - state: Mutex::new(crate::state::LoopbackTlsTransportPairState::default()), - ready: std::sync::Condvar::new(), - }); - ( - crate::state::LoopbackTlsEndpoint { - pair: Arc::clone(&pair), - is_lower_socket: true, - poll_timeout: Duration::from_millis(100), - registry_key: None, - }, - crate::state::LoopbackTlsEndpoint { - pair, - is_lower_socket: false, - poll_timeout: Duration::from_millis(100), - registry_key: None, - }, - ) - } - - fn with_panic_counter( - operation: impl FnOnce(Arc) -> T + std::panic::UnwindSafe, - ) -> T { - static PANIC_HOOK_LOCK: OnceLock> = OnceLock::new(); - - let _hook_guard = PANIC_HOOK_LOCK - .get_or_init(|| Mutex::new(())) - .lock() - .expect("panic hook lock"); - let panic_counter = Arc::new(AtomicUsize::new(0)); - let previous_hook = Arc::new(Mutex::new(Some(std::panic::take_hook()))); - let hook_counter = Arc::clone(&panic_counter); - let hook_previous = Arc::clone(&previous_hook); - std::panic::set_hook(Box::new(move |info| { - hook_counter.fetch_add(1, Ordering::SeqCst); - if let Some(previous_hook) = hook_previous - .lock() - .expect("previous panic hook lock") - .as_ref() - { - previous_hook(info); - } - })); - - let result = std::panic::catch_unwind(|| operation(Arc::clone(&panic_counter))); - let _ = std::panic::take_hook(); - let previous_hook = previous_hook - .lock() - .expect("previous panic hook lock") - .take() - .expect("previous panic hook"); - std::panic::set_hook(previous_hook); - match result { - Ok(value) => value, - Err(payload) => std::panic::resume_unwind(payload), - } - } - - fn tls_service_test_lock() -> std::sync::MutexGuard<'static, ()> { - static TLS_TEST_LOCK: OnceLock> = OnceLock::new(); - TLS_TEST_LOCK - .get_or_init(|| Mutex::new(())) - .lock() - .expect("TLS service test lock") - } - - fn complete_loopback_tls_handshake(start: Arc) { - let (client_transport, server_transport) = loopback_tls_endpoints(); - let server_start = Arc::clone(&start); - let server = thread::spawn(move || { - server_start.wait(); - let mut stream = rustls::StreamOwned::new( - ServerConnection::new(tls_test_server_config(&["h2"])) - .expect("create loopback TLS server"), - server_transport, - ); - while stream.conn.is_handshaking() { - match stream.conn.complete_io(&mut stream.sock) { - Ok(_) => {} - Err(error) - if { - let kind = error.kind(); - kind == std::io::ErrorKind::WouldBlock - || kind == std::io::ErrorKind::TimedOut - } => - { - thread::yield_now() - } - Err(error) => panic!("complete loopback TLS server handshake: {error}"), - } - } - - let mut payload = [0_u8; 4]; - stream - .read_exact(&mut payload) - .expect("read loopback TLS client payload"); - assert_eq!(&payload, b"ping"); - stream - .write_all(b"pong") - .expect("write loopback TLS server payload"); - stream.flush().expect("flush loopback TLS server payload"); - }); - - let client = thread::spawn(move || { - start.wait(); - let mut stream = rustls::StreamOwned::new( - ClientConnection::new( - tls_test_client_config(false, &["h2"]), - ServerName::try_from("localhost").expect("loopback TLS server name"), - ) - .expect("create loopback TLS client"), - client_transport, - ); - while stream.conn.is_handshaking() { - match stream.conn.complete_io(&mut stream.sock) { - Ok(_) => {} - Err(error) - if { - let kind = error.kind(); - kind == std::io::ErrorKind::WouldBlock - || kind == std::io::ErrorKind::TimedOut - } => - { - thread::yield_now() - } - Err(error) => panic!("complete loopback TLS client handshake: {error}"), - } - } - - stream - .write_all(b"ping") - .expect("write loopback TLS client payload"); - stream.flush().expect("flush loopback TLS client payload"); - let mut payload = [0_u8; 4]; - stream - .read_exact(&mut payload) - .expect("read loopback TLS server payload"); - assert_eq!(&payload, b"pong"); - }); - - client.join().expect("join loopback TLS client"); - server.join().expect("join loopback TLS server"); - } - fn loopback_tls_transport_survives_concurrent_handshakes_without_panicking() { - let _tls_lock = tls_service_test_lock(); - with_panic_counter(|panic_counter| { - let concurrency = 4; - let start = Arc::new(Barrier::new(concurrency * 2)); - let workers = (0..concurrency) - .map(|_| { - let start = Arc::clone(&start); - thread::spawn(move || complete_loopback_tls_handshake(start)) - }) - .collect::>(); - - for worker in workers { - worker - .join() - .expect("join loopback TLS handshake stress worker"); - } - - assert_eq!( - panic_counter.load(Ordering::SeqCst), - 0, - "loopback TLS handshake stress triggered a panic" - ); - }); - } - fn loopback_tls_endpoint_read_survives_competing_drain_and_peer_drop() { - with_panic_counter(|panic_counter| { - let (reader_endpoint, peer_endpoint) = loopback_tls_endpoints(); - { - let mut state = reader_endpoint - .pair - .state - .lock() - .expect("loopback TLS state"); - state - .higher_to_lower - .extend((0..4096).map(|value| (value % 251) as u8)); - } - - let competing_reader = crate::state::LoopbackTlsEndpoint { - pair: Arc::clone(&reader_endpoint.pair), - is_lower_socket: reader_endpoint.is_lower_socket, - poll_timeout: Duration::from_millis(100), - registry_key: None, - }; - let start = Arc::new(Barrier::new(3)); - - let primary_reader = { - let start = Arc::clone(&start); - thread::spawn(move || { - start.wait(); - let mut endpoint = reader_endpoint; - let mut buffer = [0_u8; 64]; - let mut total = 0; - loop { - match endpoint.read(&mut buffer) { - Ok(0) => return total, - Ok(read) => total += read, - Err(error) - if { - let kind = error.kind(); - kind == std::io::ErrorKind::WouldBlock - || kind == std::io::ErrorKind::TimedOut - } => - { - thread::yield_now() - } - Err(error) => panic!("primary loopback TLS read failed: {error}"), - } - } - }) - }; - - let drain_racer = { - let start = Arc::clone(&start); - thread::spawn(move || { - start.wait(); - let mut endpoint = competing_reader; - let mut buffer = [0_u8; 31]; - loop { - match endpoint.read(&mut buffer) { - Ok(0) => return, - Ok(_) => thread::yield_now(), - Err(error) - if { - let kind = error.kind(); - kind == std::io::ErrorKind::WouldBlock - || kind == std::io::ErrorKind::TimedOut - } => - { - thread::yield_now() - } - Err(error) => { - panic!("competing loopback TLS read failed: {error}") - } - } - } - }) - }; - - let closer = { - let start = Arc::clone(&start); - thread::spawn(move || { - start.wait(); - thread::sleep(std::time::Duration::from_millis(5)); - drop(peer_endpoint); - }) - }; - - primary_reader.join().expect("join primary loopback reader"); - drain_racer.join().expect("join competing loopback reader"); - closer.join().expect("join loopback peer closer"); - - assert_eq!( - panic_counter.load(Ordering::SeqCst), - 0, - "loopback TLS endpoint race triggered a panic" - ); - }); - } - - fn loopback_tls_pending_write_buffer_cap_is_typed_limit_error_work() { - let (endpoint, _peer_endpoint) = loopback_tls_endpoints(); - let pending_write = crate::state::LoopbackTlsPendingWriteHandle::new(&endpoint); - let at_limit = vec![b'a'; 4 * 1024 * 1024]; - pending_write - .append_write(&at_limit) - .expect("write exactly at pending buffer limit"); - - let error = pending_write - .append_write(b"b") - .expect_err("extra byte should exceed pending write buffer limit"); - let message = error.to_string(); - assert!( - message.contains("loopback TLS pending write buffer exceeded"), - "unexpected cap error: {message}" - ); - assert!( - message.contains("4194305 bytes > 4194304 bytes"), - "unexpected cap units: {message}" - ); - } - fn javascript_net_socket_wait_connect_reports_tcp_socket_info() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-wait-connect-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-net-wait-connect"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-wait-connect", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 0, - "backlog": 1, - })], - }, - ) - .expect("listen through sidecar net RPC"); - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - let guest_port = listen["localPort"] - .as_u64() - .and_then(|value| u16::try_from(value).ok()) - .expect("guest listener port"); - - let connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-wait-connect", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect("connect to vm-owned listener"); - let socket_id = connect["socketId"].as_str().expect("socket id").to_string(); - - let info = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-wait-connect", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.socket_wait_connect"), - args: vec![json!(socket_id.clone())], - }, - ) - .expect("wait for connect"); - let parsed: Value = serde_json::from_str(info.as_str().expect("socket info string")) - .expect("parse socket info"); - assert_eq!(parsed["remoteAddress"], Value::from("127.0.0.1")); - assert_eq!(parsed["remotePort"], Value::from(guest_port)); - assert_eq!(parsed["remoteFamily"], Value::from("IPv4")); - assert_eq!(parsed["localFamily"], Value::from("IPv4")); - assert!( - parsed["localPort"].as_u64().is_some_and(|port| port > 0), - "socket info: {parsed}" - ); - - let accepted = (0..20) - .find_map(|attempt| { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-wait-connect", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4 + attempt, - method: String::from("net.server_accept"), - args: vec![json!(server_id.clone())], - }, - ) - .expect("accept connected client"); - (value != "__secure_exec_net_timeout__").then_some(value) - }) - .expect("eventually accept connected client"); - let accepted: Value = - serde_json::from_str(accepted.as_str().expect("accepted payload string")) - .expect("parse accepted payload"); - let accepted_socket_id = accepted["socketId"] - .as_str() - .expect("accepted socket id") - .to_string(); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-wait-connect", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 50, - method: String::from("net.destroy"), - args: vec![json!(socket_id)], - }, - ) - .expect("destroy connected socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-wait-connect", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 51, - method: String::from("net.destroy"), - args: vec![json!(accepted_socket_id)], - }, - ) - .expect("destroy accepted socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-wait-connect", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 52, - method: String::from("net.server_close"), - args: vec![json!(server_id)], - }, - ) - .expect("close listener"); - } - fn javascript_net_socket_read_and_socket_options_work_for_tcp_sockets() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-read-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-net-read"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 0, - "backlog": 1, - })], - }, - ) - .expect("listen through sidecar net RPC"); - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - let guest_port = listen["localPort"] - .as_u64() - .and_then(|value| u16::try_from(value).ok()) - .expect("guest listener port"); - - let connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect("connect to vm-owned listener"); - let socket_id = connect["socketId"].as_str().expect("socket id").to_string(); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.socket_set_no_delay"), - args: vec![json!(socket_id.clone()), Value::Bool(true)], - }, - ) - .expect("enable TCP_NODELAY"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("net.socket_set_keep_alive"), - args: vec![json!(socket_id.clone()), Value::Bool(true), json!(1)], - }, - ) - .expect("enable SO_KEEPALIVE"); - - let mut accepted = None; - for attempt in 0..20 { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5 + attempt, - method: String::from("net.server_accept"), - args: vec![json!(server_id.clone())], - }, - ) - .expect("accept connected client"); - if value != "__secure_exec_net_timeout__" { - accepted = Some(value); - break; - } - thread::sleep(std::time::Duration::from_millis(10)); - } - let accepted = accepted.expect("eventually accept connected client"); - let accepted: Value = - serde_json::from_str(accepted.as_str().expect("accepted payload string")) - .expect("parse accepted payload"); - let server_socket_id = accepted["socketId"] - .as_str() - .expect("accepted socket id") - .to_string(); - - { - let vm = sidecar.vms.get(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get("proc-js-net-read") - .expect("javascript process"); - let socket = process.tcp_sockets.get(&socket_id).expect("tcp socket"); - assert!( - socket.kernel_socket_id.is_some(), - "expected loopback net.connect to use kernel socket state" - ); - assert!(socket.no_delay, "expected TCP_NODELAY flag to be tracked"); - assert!( - socket.keep_alive, - "expected SO_KEEPALIVE flag to be tracked" - ); - assert_eq!(socket.keep_alive_initial_delay_secs, Some(1)); - } - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 60, - method: String::from("net.write"), - args: vec![ - json!(server_socket_id.clone()), - json!({ - "__agentOSType": "bytes", - "base64": base64::engine::general_purpose::STANDARD.encode("ping"), - }), - ], - }, - ) - .expect("write server payload"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 61, - method: String::from("net.shutdown"), - args: vec![json!(server_socket_id.clone())], - }, - ) - .expect("shutdown server write half"); - - let mut payload = None; - for attempt in 0..20 { - let response = call_javascript_sync_rpc_response( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10 + attempt, - method: String::from("net.socket_read"), - args: vec![json!(socket_id.clone())], - }, - ) - .expect("read bridged socket chunk"); - match response { - JavascriptSyncRpcServiceResponse::Raw(chunk) => { - payload = Some(chunk); - break; - } - JavascriptSyncRpcServiceResponse::Json(value) - if value == "__secure_exec_net_timeout__" => {} - JavascriptSyncRpcServiceResponse::Json(value) => { - panic!("expected bridged socket data chunk, got {value}"); - } - } - thread::sleep(std::time::Duration::from_millis(10)); - } - let payload = payload.expect("eventually receive bridged socket data"); - assert_eq!(payload, b"ping"); - - let mut end = None; - for attempt in 0..20 { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 40 + attempt, - method: String::from("net.socket_read"), - args: vec![json!(socket_id.clone())], - }, - ) - .expect("read bridged socket end"); - if value != "__secure_exec_net_timeout__" { - end = Some(value); - break; - } - thread::sleep(std::time::Duration::from_millis(10)); - } - let end = end.expect("eventually receive bridged socket EOF"); - assert_eq!(end, Value::Null); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 99, - method: String::from("net.destroy"), - args: vec![json!(socket_id)], - }, - ) - .expect("destroy connected socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 100, - method: String::from("net.destroy"), - args: vec![json!(server_socket_id)], - }, - ) - .expect("destroy accepted socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-net-read", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 101, - method: String::from("net.server_close"), - args: vec![json!(server_id)], - }, - ) - .expect("close listener"); - } - // Regression for #88: a server in one guest exec process and a client in a - // *different* guest exec process inside the SAME VM must talk over loopback. - // The fix builds the per-VM socket-path context from every concurrent exec's - // listeners (`build_javascript_socket_path_context` iterates all - // `active_processes`), so the client's `net.connect` resolves the server - // process's listener and routes through the shared kernel socket table. - fn javascript_net_cross_exec_loopback_routes_through_kernel_socket_table() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - // Two distinct guest exec processes in one VM. - let server_cwd = temp_dir("secure-exec-sidecar-js-cross-exec-server-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - "setInterval(() => {}, 1000);", - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-server"); - - let client_cwd = temp_dir("secure-exec-sidecar-js-cross-exec-client-cwd"); - write_fixture( - &client_cwd.join("entry.mjs"), - "setInterval(() => {}, 1000);", - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &client_cwd, "proc-client"); - - // Process A (server) listens on loopback. - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 0, - "backlog": 1, - })], - }, - ) - .expect("server listen through sidecar net RPC"); - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - let guest_port = listen["localPort"] - .as_u64() - .and_then(|value| u16::try_from(value).ok()) - .expect("server listener guest port"); - - // Process B (client, a SEPARATE exec) connects to A's listener. - let connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect("client connect to the other exec's listener"); - let client_socket_id = connect["socketId"] - .as_str() - .expect("client socket id") - .to_string(); - - // The client socket must be routed through the shared kernel socket - // table, not a host-only loopback shortcut. - { - let vm = sidecar.vms.get(&vm_id).expect("javascript vm"); - let client = vm - .active_processes - .get("proc-client") - .expect("client process"); - let socket = client - .tcp_sockets - .get(&client_socket_id) - .expect("client tcp socket"); - assert!( - socket.kernel_socket_id.is_some(), - "cross-exec net.connect must route through the kernel socket table" - ); - } - - // Process A accepts the connection from the other exec. - let mut accepted = None; - for attempt in 0..40 { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10 + attempt, - method: String::from("net.server_accept"), - args: vec![json!(server_id.clone())], - }, - ) - .expect("server accept client from other exec"); - if value != "__secure_exec_net_timeout__" { - accepted = Some(value); - break; - } - thread::sleep(std::time::Duration::from_millis(10)); - } - let accepted = accepted.expect("eventually accept the cross-exec connection"); - let accepted: Value = - serde_json::from_str(accepted.as_str().expect("accepted payload string")) - .expect("parse accepted payload"); - let server_socket_id = accepted["socketId"] - .as_str() - .expect("accepted socket id") - .to_string(); - - // Client (exec B) writes a byte; it must cross the exec boundary and be - // read by the server (exec A). - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 100, - method: String::from("net.write"), - args: vec![ - json!(client_socket_id.clone()), - json!({ - "__agentOSType": "bytes", - "base64": base64::engine::general_purpose::STANDARD.encode("ping"), - }), - ], - }, - ) - .expect("client write payload across exec boundary"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 101, - method: String::from("net.shutdown"), - args: vec![json!(client_socket_id.clone())], - }, - ) - .expect("client shutdown write half"); - - let payload = read_javascript_socket_chunk( - &mut sidecar, - &vm_id, - "proc-server", - &server_socket_id, - 200, - 40, - "server read bridged chunk from the other exec", - ); - assert_eq!( - payload, b"ping", - "server (exec A) must read the byte sent by client (exec B)" - ); - - // Tear everything down. - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 300, - method: String::from("net.destroy"), - args: vec![json!(client_socket_id)], - }, - ) - .expect("destroy client socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 301, - method: String::from("net.destroy"), - args: vec![json!(server_socket_id)], - }, - ) - .expect("destroy server-accepted socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 302, - method: String::from("net.server_close"), - args: vec![json!(server_id)], - }, - ) - .expect("close listener"); - } - fn javascript_net_upgrade_socket_aliases_use_tcp_socket_state() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-upgrade-socket-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-upgrade-socket"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 0, - "backlog": 1, - })], - }, - ) - .expect("listen through sidecar net RPC"); - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - let guest_port = listen["localPort"] - .as_u64() - .and_then(|value| u16::try_from(value).ok()) - .expect("guest listener port"); - - let connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect("connect to vm-owned listener"); - let client_socket_id = connect["socketId"].as_str().expect("socket id").to_string(); - - let accepted = (0..20) - .find_map(|attempt| { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10 + attempt, - method: String::from("net.server_accept"), - args: vec![json!(server_id.clone())], - }, - ) - .expect("accept connected client"); - (value != "__secure_exec_net_timeout__").then_some(value) - }) - .expect("eventually accept connected client"); - let accepted: Value = - serde_json::from_str(accepted.as_str().expect("accepted payload string")) - .expect("parse accepted payload"); - let server_socket_id = accepted["socketId"] - .as_str() - .expect("accepted socket id") - .to_string(); - - let written = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 50, - method: String::from("net.upgrade_socket_write"), - args: vec![ - json!(server_socket_id.clone()), - json!(base64::engine::general_purpose::STANDARD.encode("ping")), - ], - }, - ) - .expect("write upgrade socket payload"); - assert_eq!(written, Value::from(4)); - - let payload = read_javascript_socket_chunk( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - &client_socket_id, - 60, - 20, - "read upgrade socket payload", - ); - assert_eq!(payload, b"ping"); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 80, - method: String::from("net.upgrade_socket_end"), - args: vec![json!(server_socket_id.clone())], - }, - ) - .expect("end upgrade socket"); - - let mut end = None; - for attempt in 0..20 { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 90 + attempt, - method: String::from("net.socket_read"), - args: vec![json!(client_socket_id.clone())], - }, - ) - .expect("read upgrade socket EOF"); - if value != "__secure_exec_net_timeout__" { - end = Some(value); - break; - } - thread::sleep(std::time::Duration::from_millis(10)); - } - let end = end.expect("eventually receive upgrade socket EOF"); - assert_eq!(end, Value::Null); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 120, - method: String::from("net.upgrade_socket_destroy"), - args: vec![json!(client_socket_id)], - }, - ) - .expect("destroy client upgrade socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 121, - method: String::from("net.upgrade_socket_destroy"), - args: vec![json!(server_socket_id)], - }, - ) - .expect("destroy accepted upgrade socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-upgrade-socket", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 122, - method: String::from("net.server_close"), - args: vec![json!(server_id)], - }, - ) - .expect("close listener"); - } - fn javascript_dgram_address_and_buffer_size_sync_rpcs_work() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-dgram-options-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-dgram-options"); - - let socket = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-dgram-options", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("dgram.createSocket"), - args: vec![json!({ "type": "udp4" })], - }, - ) - .expect("create udp socket"); - let socket_id = socket["socketId"] - .as_str() - .expect("udp socket id") - .to_string(); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-dgram-options", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("dgram.bind"), - args: vec![ - json!(socket_id.clone()), - json!({ - "address": "127.0.0.1", - "port": 0, - }), - ], - }, - ) - .expect("bind udp socket"); - - let address = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-dgram-options", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("dgram.address"), - args: vec![json!(socket_id.clone())], - }, - ) - .expect("get udp socket address"); - let address: Value = - serde_json::from_str(address.as_str().expect("address payload string")) - .expect("parse address payload"); - assert_eq!(address["address"], Value::from("127.0.0.1")); - assert_eq!(address["family"], Value::from("IPv4")); - assert!( - address["port"].as_u64().is_some_and(|port| port > 0), - "socket address: {address}" - ); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-dgram-options", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("dgram.setBufferSize"), - args: vec![json!(socket_id.clone()), json!("recv"), json!(4096)], - }, - ) - .expect("set recv buffer size"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-dgram-options", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("dgram.setBufferSize"), - args: vec![json!(socket_id.clone()), json!("send"), json!(2048)], - }, - ) - .expect("set send buffer size"); - - let recv_size = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-dgram-options", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("dgram.getBufferSize"), - args: vec![json!(socket_id.clone()), json!("recv")], - }, - ) - .expect("get recv buffer size"); - assert!( - recv_size.as_u64().is_some_and(|size| size >= 4096), - "recv buffer size: {recv_size}" - ); - - let send_size = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-dgram-options", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("dgram.getBufferSize"), - args: vec![json!(socket_id.clone()), json!("send")], - }, - ) - .expect("get send buffer size"); - assert!( - send_size.as_u64().is_some_and(|size| size >= 2048), - "send buffer size: {send_size}" - ); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-dgram-options", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 8, - method: String::from("dgram.close"), - args: vec![json!(socket_id)], - }, - ) - .expect("close udp socket"); - } - fn javascript_tls_client_upgrade_query_and_cipher_list_work() { - let _tls_lock = tls_service_test_lock(); - assert_node_available(); - - let listener = TcpListener::bind("127.0.0.1:0").expect("bind TLS listener"); - let port = listener.local_addr().expect("listener address").port(); - let server = thread::spawn(move || { - let config = tls_test_server_config(&["http/1.1"]); - let (stream, _) = listener.accept().expect("accept TLS client"); - let mut stream = rustls::StreamOwned::new( - ServerConnection::new(config).expect("create TLS server connection"), - stream, - ); - while stream.conn.is_handshaking() { - stream - .conn - .complete_io(&mut stream.sock) - .expect("complete TLS server handshake"); - } - assert_eq!(stream.conn.alpn_protocol(), Some(b"http/1.1".as_slice())); - - let mut payload = [0_u8; 4]; - stream - .read_exact(&mut payload) - .expect("read client payload"); - assert_eq!(&payload, b"ping"); - stream - .write_all(b"pong") - .expect("write TLS server response"); - stream.flush().expect("flush TLS server response"); - }); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([( - format!("env.{LOOPBACK_EXEMPT_PORTS_ENV}"), - serde_json::to_string(&vec![port.to_string()]).expect("serialize exempt ports"), - )]), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-tls-client-rpc-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-tls-client"); - - let ciphers = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("tls.get_ciphers"), - args: Vec::new(), - }, - ) - .expect("list TLS ciphers"); - let ciphers: Value = serde_json::from_str(ciphers.as_str().expect("cipher JSON")) - .expect("parse ciphers"); - assert!( - ciphers - .as_array() - .is_some_and(|entries| !entries.is_empty()), - "ciphers: {ciphers}" - ); - - let connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": port, - })], - }, - ) - .expect("connect to host TLS server"); - let socket_id = connect["socketId"].as_str().expect("socket id").to_string(); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.socket_upgrade_tls"), - args: vec![ - json!(socket_id.clone()), - json!(serde_json::to_string(&json!({ - "isServer": false, - "servername": "localhost", - "rejectUnauthorized": false, - "ALPNProtocols": ["http/1.1"], - })) - .expect("serialize client TLS options")), - ], - }, - ) - .expect("upgrade client socket to TLS"); - - let protocol = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("net.socket_tls_query"), - args: vec![json!(socket_id.clone()), json!("getProtocol")], - }, - ) - .expect("query TLS protocol"); - let protocol: Value = - serde_json::from_str(protocol.as_str().expect("TLS protocol query JSON")) - .expect("parse TLS protocol"); - assert!( - protocol == Value::String(String::from("TLSv1.3")) - || protocol == Value::String(String::from("TLSv1.2")), - "protocol: {protocol}" - ); - - let cipher = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("net.socket_tls_query"), - args: vec![json!(socket_id.clone()), json!("getCipher")], - }, - ) - .expect("query TLS cipher"); - let cipher: Value = - serde_json::from_str(cipher.as_str().expect("TLS cipher query JSON")) - .expect("parse TLS cipher"); - assert_eq!(cipher["type"], Value::from("object")); - - let peer_certificate = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("net.socket_tls_query"), - args: vec![ - json!(socket_id.clone()), - json!("getPeerCertificate"), - Value::Bool(true), - ], - }, - ) - .expect("query TLS peer certificate"); - let peer_certificate: Value = serde_json::from_str( - peer_certificate - .as_str() - .expect("TLS peer certificate query JSON"), - ) - .expect("parse TLS peer certificate"); - assert_eq!(peer_certificate["type"], Value::from("object")); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("net.write"), - args: vec![ - json!(socket_id.clone()), - json!({ - "__agentOSType": "bytes", - "base64": base64::engine::general_purpose::STANDARD.encode("ping"), - }), - ], - }, - ) - .expect("write TLS client payload"); - - let payload = read_javascript_socket_chunk( - &mut sidecar, - &vm_id, - "proc-js-tls-client", - &socket_id, - 20, - 30, - "read TLS client payload", - ); - assert_eq!(payload, b"pong"); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-client", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 99, - method: String::from("net.destroy"), - args: vec![json!(socket_id)], - }, - ) - .expect("destroy TLS client socket"); - - server.join().expect("join TLS server"); - } - fn javascript_tls_server_client_hello_and_server_upgrade_work() { - let _tls_lock = tls_service_test_lock(); - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-tls-server-rpc-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-tls-server"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 0, - "backlog": 1, - })], - }, - ) - .expect("listen through sidecar net RPC"); - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - let guest_port = listen["localPort"] - .as_u64() - .and_then(|value| u16::try_from(value).ok()) - .expect("guest listener port"); - let client_connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect("connect guest TLS client"); - let client_socket_id = client_connect["socketId"] - .as_str() - .expect("client socket id") - .to_string(); - - let accepted = (0..30) - .find_map(|attempt| { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10 + attempt, - method: String::from("net.server_accept"), - args: vec![json!(server_id.clone())], - }, - ) - .expect("accept TLS client"); - if value == "__secure_exec_net_timeout__" { - thread::sleep(Duration::from_millis(10)); - None - } else { - Some(value) - } - }) - .expect("eventually accept TLS client"); - let accepted: Value = - serde_json::from_str(accepted.as_str().expect("accepted payload string")) - .expect("parse accepted payload"); - let socket_id = accepted["socketId"] - .as_str() - .expect("accepted socket id") - .to_string(); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 40, - method: String::from("net.socket_upgrade_tls"), - args: vec![ - json!(client_socket_id.clone()), - json!(serde_json::to_string(&json!({ - "isServer": false, - "servername": "localhost", - "rejectUnauthorized": false, - "ALPNProtocols": ["h2", "http/1.1"], - })) - .expect("serialize client TLS options")), - ], - }, - ) - .expect("upgrade guest TLS client socket"); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 45, - method: String::from("net.write"), - args: vec![ - json!(client_socket_id.clone()), - json!({ - "__agentOSType": "bytes", - "base64": base64::engine::general_purpose::STANDARD.encode("ping"), - }), - ], - }, - ) - .expect("buffer guest TLS client payload while handshake is pending"); - - let client_hello = (0..30) - .find_map(|attempt| { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 50 + attempt, - method: String::from("net.socket_get_tls_client_hello"), - args: vec![json!(socket_id.clone())], - }, - ) - .expect("get TLS client hello"); - let parsed: Value = - serde_json::from_str(value.as_str().expect("TLS client hello JSON")) - .expect("parse TLS client hello"); - if parsed["servername"] == "localhost" { - Some(parsed) - } else { - thread::sleep(Duration::from_millis(10)); - None - } - }) - .expect("eventually parse TLS client hello"); - assert_eq!(client_hello["servername"], Value::from("localhost")); - assert!( - client_hello["ALPNProtocols"] - .as_array() - .is_some_and(|protocols| protocols.contains(&Value::from("h2"))), - "client hello: {client_hello}" - ); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 80, - method: String::from("net.socket_upgrade_tls"), - args: vec![ - json!(socket_id.clone()), - json!(serde_json::to_string(&json!({ - "isServer": true, - "key": { "kind": "string", "data": TLS_TEST_KEY_PEM }, - "cert": { "kind": "string", "data": TLS_TEST_CERT_PEM }, - "ALPNProtocols": ["h2"], - })) - .expect("serialize server TLS options")), - ], - }, - ) - .expect("upgrade accepted socket to TLS"); - - let certificate = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 81, - method: String::from("net.socket_tls_query"), - args: vec![json!(socket_id.clone()), json!("getCertificate")], - }, - ) - .expect("query local TLS certificate"); - let certificate: Value = - serde_json::from_str(certificate.as_str().expect("TLS certificate JSON")) - .expect("parse TLS certificate"); - assert_eq!(certificate["type"], Value::from("object")); - - (0..30) - .find_map(|attempt| { - let server_protocol = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 82 + attempt * 2, - method: String::from("net.socket_tls_query"), - args: vec![json!(socket_id.clone()), json!("getProtocol")], - }, - ) - .expect("query server TLS protocol"); - let server_protocol: Value = serde_json::from_str( - server_protocol.as_str().expect("server protocol JSON"), - ) - .expect("parse server protocol"); - - let client_protocol = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 83 + attempt * 2, - method: String::from("net.socket_tls_query"), - args: vec![json!(client_socket_id.clone()), json!("getProtocol")], - }, - ) - .expect("query client TLS protocol"); - let client_protocol: Value = serde_json::from_str( - client_protocol.as_str().expect("client protocol JSON"), - ) - .expect("parse client protocol"); - - if server_protocol.is_null() || client_protocol.is_null() { - thread::sleep(Duration::from_millis(10)); - None - } else { - Some(()) - } - }) - .expect("eventually complete guest TLS handshake"); - - let payload = read_javascript_socket_chunk( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - &socket_id, - 150, - 30, - "read TLS server payload", - ); - assert_eq!(payload, b"ping"); - - let protocol = (0..30) - .find_map(|attempt| { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 190 + attempt, - method: String::from("net.socket_tls_query"), - args: vec![json!(socket_id.clone()), json!("getProtocol")], - }, - ) - .expect("query TLS protocol"); - let parsed: Value = - serde_json::from_str(value.as_str().expect("TLS protocol JSON")) - .expect("parse TLS protocol"); - if parsed.is_null() { - thread::sleep(Duration::from_millis(10)); - None - } else { - Some(parsed) - } - }) - .expect("eventually negotiate TLS protocol"); - assert!( - protocol == Value::String(String::from("TLSv1.3")) - || protocol == Value::String(String::from("TLSv1.2")), - "protocol: {protocol}" - ); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 120, - method: String::from("net.write"), - args: vec![ - json!(socket_id.clone()), - json!({ - "__agentOSType": "bytes", - "base64": base64::engine::general_purpose::STANDARD.encode("pong"), - }), - ], - }, - ) - .expect("write TLS server payload"); - - let client_payload = read_javascript_socket_chunk( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - &client_socket_id, - 220, - 30, - "read guest TLS client payload", - ); - assert_eq!(client_payload, b"pong"); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 121, - method: String::from("net.destroy"), - args: vec![json!(socket_id)], - }, - ) - .expect("destroy accepted TLS socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 122, - method: String::from("net.destroy"), - args: vec![json!(client_socket_id)], - }, - ) - .expect("destroy guest TLS client socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-tls-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 123, - method: String::from("net.server_close"), - args: vec![json!(server_id)], - }, - ) - .expect("close TLS listener"); - } - fn javascript_net_server_accept_returns_timeout_then_pending_connection() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-server-accept-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-server-accept"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server-accept", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 0, - "backlog": 1, - })], - }, - ) - .expect("listen through sidecar net RPC"); - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - let guest_port = listen["localPort"] - .as_u64() - .and_then(|value| u16::try_from(value).ok()) - .expect("guest listener port"); - let timeout = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server-accept", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.server_accept"), - args: vec![json!(server_id.clone())], - }, - ) - .expect("accept timeout sentinel"); - assert_eq!(timeout, Value::from("__secure_exec_net_timeout__")); - - let connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server-accept", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect("connect to vm-owned listener"); - let client_socket_id = connect["socketId"] - .as_str() - .expect("client socket id") - .to_string(); - - let mut accepted = None; - for attempt in 0..20 { - let value = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server-accept", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10 + attempt, - method: String::from("net.server_accept"), - args: vec![json!(server_id.clone())], - }, - ) - .expect("accept pending connection"); - if value != "__secure_exec_net_timeout__" { - accepted = Some(value); - break; - } - thread::sleep(std::time::Duration::from_millis(10)); - } - let accepted = accepted.expect("eventually accept pending TCP connection"); - let parsed: Value = - serde_json::from_str(accepted.as_str().expect("accepted payload string")) - .expect("parse accepted payload"); - assert!( - parsed["socketId"].as_str().is_some(), - "accepted payload: {parsed}" - ); - assert_eq!(parsed["info"]["localAddress"], Value::from("127.0.0.1")); - assert_eq!(parsed["info"]["localPort"], Value::from(guest_port)); - assert_eq!(parsed["info"]["localFamily"], Value::from("IPv4")); - assert_eq!(parsed["info"]["remoteFamily"], Value::from("IPv4")); - assert!( - parsed["info"]["remotePort"] - .as_u64() - .is_some_and(|port| port > 0), - "accepted payload: {parsed}" - ); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server-accept", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 40, - method: String::from("net.destroy"), - args: vec![json!(client_socket_id)], - }, - ) - .expect("destroy client socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server-accept", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 41, - method: String::from("net.destroy"), - args: vec![json!(parsed["socketId"] - .as_str() - .expect("accepted socket id"))], - }, - ) - .expect("destroy accepted socket"); - } - fn javascript_kernel_stdin_reads_buffered_input_and_reports_timeout_and_eof() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-kernel-stdin-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from( - "[\"assert\",\"buffer\",\"console\",\"events\",\"fs\",\"path\",\"readline\",\"stream\",\"string_decoder\",\"timers\",\"util\"]", - ), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - let kernel_stdin_writer_fd = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let (read_fd, write_fd) = vm - .kernel - .open_pipe(EXECUTION_DRIVER_NAME, kernel_handle.pid()) - .expect("open kernel stdin pipe"); - vm.kernel - .fd_dup2(EXECUTION_DRIVER_NAME, kernel_handle.pid(), read_fd, 0) - .expect("dup kernel stdin pipe onto fd 0"); - vm.kernel - .fd_close(EXECUTION_DRIVER_NAME, kernel_handle.pid(), read_fd) - .expect("close extra kernel stdin read fd"); - write_fd - }; - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-stdin"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_kernel_stdin_writer_fd(kernel_stdin_writer_fd) - .with_host_cwd(cwd.clone()), - ); - } - - let initial = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-stdin", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("__kernel_stdin_read"), - args: vec![json!(1024), json!(10)], - }, - ) - .expect("poll empty kernel stdin"); - assert_eq!(initial, Value::Null); - - let write = sidecar - .dispatch_blocking(request( - 11, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::WriteStdin(WriteStdinRequest { - process_id: String::from("proc-js-stdin"), - chunk: b"hello from stdin".to_vec(), - }), - )) - .expect("write stdin"); - match write.response.payload { - ResponsePayload::StdinWritten(response) => { - assert_eq!(response.process_id, "proc-js-stdin"); - assert_eq!(response.accepted_bytes, "hello from stdin".len() as u64); - } - other => panic!("unexpected stdin_written response: {other:?}"), - } - - let next = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-stdin", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("__kernel_stdin_read"), - args: vec![json!(1024), json!(10)], - }, - ) - .expect("read kernel stdin payload"); - assert_eq!( - next, - json!({ - "dataBase64": base64::engine::general_purpose::STANDARD - .encode("hello from stdin"), - }) - ); - - let close = sidecar - .dispatch_blocking(request( - 12, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::CloseStdin(CloseStdinRequest { - process_id: String::from("proc-js-stdin"), - }), - )) - .expect("close stdin"); - match close.response.payload { - ResponsePayload::StdinClosed(response) => { - assert_eq!(response.process_id, "proc-js-stdin"); - } - other => panic!("unexpected stdin_closed response: {other:?}"), - } - - let eof = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-stdin", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("__kernel_stdin_read"), - args: vec![json!(1024), json!(10)], - }, - ) - .expect("read kernel stdin eof"); - assert_eq!(eof, json!({ "done": true })); - - sidecar - .kill_process_internal(&vm_id, "proc-js-stdin", "SIGKILL") - .expect("kill javascript stdin process"); - } - fn javascript_sync_rpc_pty_set_raw_mode_toggles_kernel_tty_discipline() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-pty-raw-mode"); - write_fixture(&cwd.join("entry.mjs"), "export {};\n"); - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::new(), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let (_master_fd, slave_fd, _pty_path) = vm - .kernel - .open_pty(EXECUTION_DRIVER_NAME, kernel_handle.pid()) - .expect("open kernel pty"); - vm.kernel - .fd_dup2(EXECUTION_DRIVER_NAME, kernel_handle.pid(), slave_fd, 0) - .expect("dup kernel pty slave onto fd 0"); - vm.kernel - .fd_close(EXECUTION_DRIVER_NAME, kernel_handle.pid(), slave_fd) - .expect("close extra kernel pty slave fd"); - vm.active_processes.insert( - String::from("proc-js-pty"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.clone()), - ); - } - - { - let vm = sidecar.vms.get(&vm_id).expect("javascript vm"); - let kernel_pid = vm.active_processes["proc-js-pty"].kernel_pid; - let termios = vm - .kernel - .tcgetattr(EXECUTION_DRIVER_NAME, kernel_pid, 0) - .expect("read cooked termios"); - assert!(termios.icanon); - assert!(termios.echo); - assert!(termios.isig); - } - - let raw = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-pty", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("__pty_set_raw_mode"), - args: vec![json!(true)], - }, - ) - .expect("enable raw mode"); - assert_eq!(raw, Value::Null); - - { - let vm = sidecar.vms.get(&vm_id).expect("javascript vm"); - let kernel_pid = vm.active_processes["proc-js-pty"].kernel_pid; - let termios = vm - .kernel - .tcgetattr(EXECUTION_DRIVER_NAME, kernel_pid, 0) - .expect("read raw termios"); - assert!(!termios.icanon); - assert!(!termios.echo); - assert!(!termios.isig); - } - - let cooked = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-pty", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("__pty_set_raw_mode"), - args: vec![json!(false)], - }, - ) - .expect("disable raw mode"); - assert_eq!(cooked, Value::Null); - - { - let vm = sidecar.vms.get(&vm_id).expect("javascript vm"); - let kernel_pid = vm.active_processes["proc-js-pty"].kernel_pid; - let termios = vm - .kernel - .tcgetattr(EXECUTION_DRIVER_NAME, kernel_pid, 0) - .expect("read restored cooked termios"); - assert!(termios.icanon); - assert!(termios.echo); - assert!(termios.isig); - } - - sidecar - .kill_process_internal(&vm_id, "proc-js-pty", "SIGKILL") - .expect("kill javascript pty process"); - } - fn dispose_vm_removes_per_vm_javascript_import_cache_directory() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_a = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm a"); - let vm_b = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm b"); - - let cache_path_a = sidecar - .javascript_engine - .materialize_import_cache_for_vm(&vm_a) - .expect("materialize vm a import cache") - .to_path_buf(); - let cache_path_b = sidecar - .javascript_engine - .materialize_import_cache_for_vm(&vm_b) - .expect("materialize vm b import cache") - .to_path_buf(); - let cache_root_a = cache_path_a - .parent() - .expect("vm a cache parent") - .to_path_buf(); - let cache_root_b = cache_path_b - .parent() - .expect("vm b cache parent") - .to_path_buf(); - - assert_ne!(cache_root_a, cache_root_b); - assert!(cache_root_a.exists(), "vm a cache root should exist"); - assert!(cache_root_b.exists(), "vm b cache root should exist"); - - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &vm_a, - DisposeReason::Requested, - ) - .expect("dispose vm a"); - - assert!( - !cache_root_a.exists(), - "vm a cache root should be removed on dispose" - ); - assert!( - cache_root_b.exists(), - "vm b cache root should remain until that VM is disposed" - ); - assert!( - sidecar - .javascript_engine - .import_cache_path_for_vm(&vm_a) - .is_none(), - "vm a cache entry should be removed from the engine" - ); - assert_eq!( - sidecar.javascript_engine.import_cache_path_for_vm(&vm_b), - Some(cache_path_b.as_path()) - ); - - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &vm_b, - DisposeReason::Requested, - ) - .expect("dispose vm b"); - assert!( - !cache_root_b.exists(), - "vm b cache root should be removed on dispose" - ); - } - fn execution_dispose_vm_race_skips_stale_process_events_without_panicking() { - with_panic_counter(|panic_counter| { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = authenticate_and_open_session(&mut sidecar) - .expect("authenticate and open session"); - - for _iteration in 0..16 { - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &vm_id, - DisposeReason::Requested, - ) - .expect("dispose vm"); - - assert!(sidecar - .handle_execution_event( - &vm_id, - "proc-js-race", - crate::state::ActiveExecutionEvent::Exited(0), - ) - .expect("handle stale exited event") - .is_none()); - assert!(sidecar - .handle_execution_event( - &vm_id, - "proc-js-race", - crate::state::ActiveExecutionEvent::Stdout(b"stale stdout".to_vec(),), - ) - .expect("handle stale stdout event") - .is_none()); - assert_eq!( - panic_counter.load(Ordering::SeqCst), - 0, - "stale VM/process events should not panic after dispose" - ); - - let live_vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create live vm"); - let vm = sidecar.vms.get_mut(&live_vm_id).expect("live vm"); - vm.active_processes.remove("proc-js-race"); - assert!(sidecar - .handle_execution_event( - &live_vm_id, - "proc-js-race", - crate::state::ActiveExecutionEvent::Exited(0), - ) - .expect("handle stale process event") - .is_none()); - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &live_vm_id, - DisposeReason::Requested, - ) - .expect("dispose live vm"); - } - }); - } - fn execution_javascript_sync_rpc_handler_ignores_stale_vm_and_process_races() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let request = JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("process.kill"), - args: vec![json!(999_999u32), json!("SIGTERM")], - }; - - let disposed_vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create disposed vm"); - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &disposed_vm_id, - DisposeReason::Requested, - ) - .expect("dispose vm"); - sidecar - .handle_javascript_sync_rpc_request( - &disposed_vm_id, - "proc-js-race", - request.clone(), - ) - .expect("ignore stale vm javascript sync rpc"); - - let live_vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create live vm"); - sidecar - .handle_javascript_sync_rpc_request(&live_vm_id, "proc-js-race", request) - .expect("ignore stale process javascript sync rpc"); - } - fn execution_poll_event_smoke_skips_queued_stale_process_envelopes_after_dispose() { - with_panic_counter(|panic_counter| { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = authenticate_and_open_session(&mut sidecar) - .expect("authenticate and open session"); - - for _iteration in 0..16 { - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let ownership = OwnershipScope::vm(&connection_id, &session_id, &vm_id); - - sidecar - .process_event_sender - .try_send(crate::state::ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - process_id: String::from("proc-js-race"), - event: crate::state::ActiveExecutionEvent::Stdout( - b"stale stdout".to_vec(), - ), - }) - .expect("queue stale stdout envelope"); - sidecar - .process_event_sender - .try_send(crate::state::ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - process_id: String::from("proc-js-race"), - event: crate::state::ActiveExecutionEvent::Exited(0), - }) - .expect("queue stale exited envelope"); - - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &vm_id, - DisposeReason::Requested, - ) - .expect("dispose vm"); - - assert!(sidecar - .poll_event_blocking(&ownership, Duration::ZERO) - .expect("poll stale envelopes") - .is_none()); - assert_eq!( - panic_counter.load(Ordering::SeqCst), - 0, - "queued stale process envelopes should not panic after dispose" - ); - } - }); - } - fn execution_poll_event_concurrent_dispose_logs_stale_process_event() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - - for _iteration in 0..16 { - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let ownership = OwnershipScope::vm(&connection_id, &session_id, &vm_id); - let initial_log_count = sidecar - .with_bridge_mut(|bridge| bridge.log_events.len()) - .expect("read initial log count"); - let barrier = Arc::new(Barrier::new(2)); - let sender = sidecar.process_event_sender.clone(); - let sender_barrier = Arc::clone(&barrier); - let sender_connection_id = connection_id.clone(); - let sender_session_id = session_id.clone(); - let sender_vm_id = vm_id.clone(); - - let send_thread = thread::spawn(move || { - sender_barrier.wait(); - sender - .try_send(crate::state::ProcessEventEnvelope { - connection_id: sender_connection_id, - session_id: sender_session_id, - vm_id: sender_vm_id, - process_id: String::from("proc-js-race"), - event: crate::state::ActiveExecutionEvent::Stdout( - b"stale stdout".to_vec(), - ), - }) - .expect("queue concurrent stale stdout envelope"); - }); - - barrier.wait(); - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &vm_id, - DisposeReason::Requested, - ) - .expect("dispose vm"); - send_thread.join().expect("join sender thread"); - - assert!(sidecar - .poll_event_blocking(&ownership, Duration::ZERO) - .expect("poll concurrent stale envelope") - .is_none()); - - let stale_logs = sidecar - .with_bridge_mut(|bridge| { - bridge.log_events[initial_log_count..] - .iter() - .filter(|log| { - log.vm_id == vm_id - && log.message.contains( - "Ignoring stale process event during execution event dispatch", - ) - && log.message.contains("proc-js-race") - }) - .map(|log| log.message.clone()) - .collect::>() - }) - .expect("read stale log events"); - assert!( - !stale_logs.is_empty(), - "expected stale process event log after concurrent dispose race" - ); - } - } - fn filesystem_requests_ignore_stale_vm_and_process_races() { - with_panic_counter(|panic_counter| { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = authenticate_and_open_session(&mut sidecar) - .expect("authenticate and open session"); - - let disposed_vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create disposed vm"); - let disposed_ownership = - OwnershipScope::vm(&connection_id, &session_id, &disposed_vm_id); - - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &disposed_vm_id, - DisposeReason::Requested, - ) - .expect("dispose vm"); - - let stale_guest_request = sidecar - .dispatch_blocking(request( - 4, - disposed_ownership, - RequestPayload::GuestFilesystemCall(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/stale.txt"), - destination_path: None, - target: None, - content: Some(String::from("stale")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("dispatch stale guest filesystem request"); - match stale_guest_request.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!( - rejected.message.contains("unknown sidecar VM"), - "unexpected stale guest filesystem rejection: {rejected:?}" - ); - } - other => panic!("unexpected stale guest filesystem response: {other:?}"), - } - - let live_vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create live vm"); - - { - let vm = sidecar.vms.get(&live_vm_id).expect("live vm"); - assert!( - !vm.kernel - .exists("/tmp/stale-python-rpc") - .expect("check missing workspace before stale python rpc"), - "stale python request precondition failed" - ); - } - - sidecar - .handle_python_vfs_rpc_request( - &live_vm_id, - "proc-stale-python", - PythonVfsRpcRequest { - id: 1, - method: PythonVfsRpcMethod::Mkdir, - path: String::from("/tmp/stale-python-rpc"), - destination: None, - target: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - content_base64: None, - recursive: false, - url: None, - http_method: None, - headers: BTreeMap::new(), - body_base64: None, - hostname: None, - family: None, - port: None, - socket_id: None, - command: None, - args: Vec::new(), - cwd: None, - env: BTreeMap::new(), - shell: false, - max_buffer: None, - }, - ) - .expect("ignore stale python vfs process"); - - { - let vm = sidecar.vms.get(&live_vm_id).expect("live vm"); - assert!( - !vm.kernel - .exists("/tmp/stale-python-rpc") - .expect("check stale python rpc did not mutate kernel"), - "stale python VFS request should not mutate the kernel" - ); - } - - sidecar - .handle_python_vfs_rpc_request( - &disposed_vm_id, - "proc-stale-python", - PythonVfsRpcRequest { - id: 2, - method: PythonVfsRpcMethod::Mkdir, - path: String::from("/tmp/stale-python-rpc"), - destination: None, - target: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - content_base64: None, - recursive: false, - url: None, - http_method: None, - headers: BTreeMap::new(), - body_base64: None, - hostname: None, - family: None, - port: None, - socket_id: None, - command: None, - args: Vec::new(), - cwd: None, - env: BTreeMap::new(), - shell: false, - max_buffer: None, - }, - ) - .expect("ignore stale python vfs vm"); - - let write_response = sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &live_vm_id), - RequestPayload::GuestFilesystemCall(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/note.txt"), - destination_path: None, - target: None, - content: Some(String::from("hello from live vm")), - encoding: Some(RootFilesystemEntryEncoding::Utf8), - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("dispatch live guest filesystem write"); - match write_response.response.payload { - ResponsePayload::GuestFilesystemResult(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::WriteFile); - assert_eq!(response.path, "/note.txt"); - } - other => panic!("unexpected live guest filesystem write response: {other:?}"), - } - - let read_response = sidecar - .dispatch_blocking(request( - 6, - OwnershipScope::vm(&connection_id, &session_id, &live_vm_id), - RequestPayload::GuestFilesystemCall(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/note.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - )) - .expect("dispatch live guest filesystem read"); - match read_response.response.payload { - ResponsePayload::GuestFilesystemResult(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::ReadFile); - assert_eq!(response.path, "/note.txt"); - assert_eq!(response.content.as_deref(), Some("hello from live vm")); - assert_eq!(response.encoding, Some(RootFilesystemEntryEncoding::Utf8)); - } - other => panic!("unexpected live guest filesystem read response: {other:?}"), - } - - assert_eq!( - panic_counter.load(Ordering::SeqCst), - 0, - "stale filesystem races should not panic" - ); - }); - } - fn get_zombie_timer_count_reports_kernel_state_before_and_after_waitpid() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let zombie_pid = { - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - vm.kernel - .register_driver(CommandDriver::new("test-driver", ["test-zombie"])) - .expect("register test driver"); - let process = vm - .kernel - .spawn_process( - "test-zombie", - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from("test-driver")), - ..SpawnOptions::default() - }, - ) - .expect("spawn test process"); - process.finish(17); - assert_eq!(vm.kernel.zombie_timer_count(), 1); - process.pid() - }; - - let zombie_count = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::GetZombieTimerCount(GetZombieTimerCountRequest::default()), - )) - .expect("query zombie count"); - match zombie_count.response.payload { - ResponsePayload::ZombieTimerCount(response) => assert_eq!(response.count, 1), - other => panic!("unexpected zombie count response: {other:?}"), - } - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let waited = vm.kernel.waitpid(zombie_pid).expect("waitpid"); - assert_eq!(waited.pid, zombie_pid); - assert_eq!(waited.status, 17); - assert_eq!(vm.kernel.zombie_timer_count(), 0); - } - - let reaped_count = sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::GetZombieTimerCount(GetZombieTimerCountRequest::default()), - )) - .expect("query reaped zombie count"); - match reaped_count.response.payload { - ResponsePayload::ZombieTimerCount(response) => assert_eq!(response.count, 0), - other => panic!("unexpected zombie count response: {other:?}"), - } - } - fn parse_signal_accepts_full_guest_signal_table() { - assert_eq!(parse_signal("SIGINT").expect("parse SIGINT"), libc::SIGINT); - assert_eq!(parse_signal("kill").expect("parse SIGKILL"), SIGKILL); - assert_eq!(parse_signal("15").expect("parse numeric SIGTERM"), SIGTERM); - assert_eq!( - parse_signal("SIGCONT").expect("parse SIGCONT"), - libc::SIGCONT - ); - assert_eq!( - parse_signal("SIGSTOP").expect("parse SIGSTOP"), - libc::SIGSTOP - ); - assert_eq!(parse_signal("0").expect("parse signal 0"), 0); - assert_eq!( - parse_signal("SIGUSR1").expect("parse SIGUSR1"), - libc::SIGUSR1 - ); - assert_eq!(parse_signal("SIGIOT").expect("parse SIGIOT"), libc::SIGABRT); - assert_eq!(parse_signal("SIGPOLL").expect("parse SIGPOLL"), libc::SIGIO); - assert!(parse_signal("32").is_err()); - } - fn runtime_child_liveness_only_tracks_owned_children() { - assert!( - !runtime_child_is_alive(std::process::id()).expect("current pid is not a child"), - "current process should not be treated as a guest runtime child" - ); - - let mut child = Command::new("sh") - .arg("-c") - .arg("sleep 10") - .spawn() - .expect("spawn child process"); - let child_pid = child.id(); - - assert!( - runtime_child_is_alive(child_pid).expect("inspect running child"), - "running child should be considered alive" - ); - - signal_runtime_process(child_pid, SIGTERM).expect("signal running child"); - child.wait().expect("wait for signaled child"); - - assert!( - !runtime_child_is_alive(child_pid).expect("inspect reaped child"), - "reaped child should no longer be considered alive" - ); - signal_runtime_process(child_pid, SIGTERM).expect("ignore reaped child"); - } - fn authenticated_connection_id_returns_error_for_unexpected_response() { - let error = authenticated_connection_id(DispatchResult { - response: ResponseFrame::new( - 1, - OwnershipScope::connection("conn-1"), - ResponsePayload::SessionOpened(SessionOpenedResponse { - session_id: String::from("session-1"), - owner_connection_id: String::from("conn-1"), - }), - ), - events: Vec::new(), - }) - .expect_err("unexpected auth payload should return an error"); - - match error { - SidecarError::InvalidState(message) => { - assert!(message.contains("expected authenticated response")); - assert!(message.contains("SessionOpened")); - } - other => panic!("expected invalid_state error, got {other:?}"), - } - } - fn opened_session_id_returns_error_for_unexpected_response() { - let error = opened_session_id(DispatchResult { - response: ResponseFrame::new( - 2, - OwnershipScope::connection("conn-1"), - ResponsePayload::VmCreated(VmCreatedResponse { - vm_id: String::from("vm-1"), - }), - ), - events: Vec::new(), - }) - .expect_err("unexpected session payload should return an error"); - - match error { - SidecarError::InvalidState(message) => { - assert!(message.contains("expected session_opened response")); - assert!(message.contains("VmCreated")); - } - other => panic!("expected invalid_state error, got {other:?}"), - } - } - fn created_vm_id_returns_error_for_unexpected_response() { - let error = created_vm_id(DispatchResult { - response: ResponseFrame::new( - 3, - OwnershipScope::session("conn-1", "session-1"), - ResponsePayload::Rejected(RejectedResponse { - code: String::from("invalid_state"), - message: String::from("not owned"), - }), - ), - events: Vec::new(), - }) - .expect_err("unexpected vm payload should return an error"); - - match error { - SidecarError::InvalidState(message) => { - assert!(message.contains("expected vm_created response")); - assert!(message.contains("Rejected")); - } - other => panic!("expected invalid_state error, got {other:?}"), - } - } - fn configure_vm_instantiates_memory_mounts_through_the_plugin_registry() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystem(BootstrapRootFilesystemRequest { - entries: vec![ - RootFilesystemEntry { - path: String::from("/workspace"), - kind: RootFilesystemEntryKind::Directory, - ..Default::default() - }, - RootFilesystemEntry { - path: String::from("/workspace/root-only.txt"), - kind: RootFilesystemEntryKind::File, - content: Some(String::from("root bootstrap file")), - ..Default::default() - }, - ], - }), - )) - .expect("bootstrap root workspace"); - - sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("memory"), - config: json!({}).to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure mounts"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let hidden = vm - .kernel - .filesystem_mut() - .read_file("/workspace/root-only.txt") - .expect_err("mounted filesystem should hide root-backed file"); - assert_eq!(hidden.code(), "ENOENT"); - - vm.kernel - .filesystem_mut() - .write_file("/workspace/from-mount.txt", b"native mount".to_vec()) - .expect("write mounted file"); - assert_eq!( - vm.kernel - .filesystem_mut() - .read_file("/workspace/from-mount.txt") - .expect("read mounted file"), - b"native mount".to_vec() - ); - assert_eq!( - vm.kernel.mounted_filesystems(), - // No packages configured, so there are no granular /opt/agentos - // leaf mounts (one tar/bin/current mount is added per package). - vec![ - MountEntry { - path: String::from("/workspace"), - plugin_id: String::from("memory"), - read_only: false, - }, - MountEntry { - path: String::from("/"), - plugin_id: String::from("root"), - read_only: false, - }, - ] - ); - } - fn configure_vm_applies_read_only_mount_wrappers() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/readonly"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("memory"), - config: json!({}).to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure readonly mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let error = vm - .kernel - .filesystem_mut() - .write_file("/readonly/blocked.txt", b"nope".to_vec()) - .expect_err("readonly mount should reject writes"); - assert_eq!(error.code(), "EROFS"); - } - fn configure_vm_instantiates_host_dir_mounts_through_the_plugin_registry() { - let host_dir = temp_dir("secure-exec-sidecar-host-dir"); - fs::write(host_dir.join("hello.txt"), "hello from host").expect("seed host dir"); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystem(BootstrapRootFilesystemRequest { - entries: vec![ - RootFilesystemEntry { - path: String::from("/workspace"), - kind: RootFilesystemEntryKind::Directory, - ..Default::default() - }, - RootFilesystemEntry { - path: String::from("/workspace/root-only.txt"), - kind: RootFilesystemEntryKind::File, - content: Some(String::from("root bootstrap file")), - ..Default::default() - }, - ], - }), - )) - .expect("bootstrap root workspace"); - - sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": host_dir, - "readOnly": false, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure host_dir mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let hidden = vm - .kernel - .filesystem_mut() - .read_file("/workspace/root-only.txt") - .expect_err("mounted host dir should hide root-backed file"); - assert_eq!(hidden.code(), "ENOENT"); - assert_eq!( - vm.kernel - .filesystem_mut() - .read_file("/workspace/hello.txt") - .expect("read mounted host file"), - b"hello from host".to_vec() - ); - - vm.kernel - .filesystem_mut() - .write_file("/workspace/from-vm.txt", b"native host dir".to_vec()) - .expect("write host dir file"); - assert_eq!( - fs::read_to_string(host_dir.join("from-vm.txt")).expect("read host output"), - "native host dir" - ); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - fn configure_vm_passes_resource_read_limits_to_host_dir_mounts() { - let host_dir = temp_dir("secure-exec-sidecar-host-dir-read-limit"); - fs::write(host_dir.join("hello.txt"), "hello from host").expect("seed host dir"); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([(String::from("resource.max_pread_bytes"), String::from("4"))]), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": host_dir, - "readOnly": false, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure host_dir mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let error = vm - .kernel - .filesystem_mut() - .read_file("/workspace/hello.txt") - .expect_err("host_dir full read should honor VM read limit"); - assert_eq!(error.code(), "EINVAL"); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - - #[test] - fn configure_vm_host_dir_mount_receives_configured_read_limit() { - configure_vm_passes_resource_read_limits_to_host_dir_mounts(); - } - - fn configure_vm_passes_resource_read_limits_to_module_access_mounts() { - let module_access_cwd = temp_dir("secure-exec-sidecar-module-access-read-limit"); - let package_root = module_access_cwd.join("node_modules/fixture-pkg"); - fs::create_dir_all(&package_root).expect("create package root"); - fs::write( - package_root.join("package.json"), - r#"{"name":"fixture-pkg"}"#, - ) - .expect("seed package json"); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([(String::from("resource.max_pread_bytes"), String::from("4"))]), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: None, - module_access_cwd: Some(module_access_cwd.to_string_lossy().into_owned()), - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure module_access mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let error = vm - .kernel - .filesystem_mut() - .read_file("/root/node_modules/fixture-pkg/package.json") - .expect_err("module_access read should honor VM read limit"); - assert_eq!(error.code(), "EINVAL"); - - fs::remove_dir_all(module_access_cwd).expect("remove temp dir"); - } - - #[test] - fn configure_vm_module_access_mount_receives_configured_read_limit() { - configure_vm_passes_resource_read_limits_to_module_access_mounts(); - } - - // Regression guard for the read-side shadow-walk fix. - // - // Every read-side guest fs op (Exists/Stat/Lstat/ReadFile) reconciles the host - // shadow tree into the kernel VFS first. The reconciliation walks the whole tree - // from `vm.cwd`, but it must now SKIP files the kernel already holds an identical - // copy of (same size/mode/mtime) instead of unconditionally re-reading every - // file's bytes and re-writing them into the kernel. Without the skip a single - // `exists("/anything")` costs O(whole tree) and is super-linear as the shadow - // grows -- the session-creation/runtime latency this fixes. - // - // We prove two things: - // 1. A warm read op over an UNCHANGED tree is far cheaper than the first - // (cold) one, i.e. unchanged files are skipped, not re-copied. - // 2. The skip is self-correcting: after a file's content changes, a read still - // observes the new bytes (no stale skip). - fn read_side_ops_skip_unchanged_shadow_files_repro() { - use std::time::{Duration, Instant}; - - fn fs_payload( - operation: GuestFilesystemOperation, - path: &str, - content: Option, - ) -> RequestPayload { - RequestPayload::GuestFilesystemCall(GuestFilesystemCallRequest { - operation, - path: String::from(path), - destination_path: None, - target: None, - content, - encoding: Some(RootFilesystemEntryEncoding::Utf8), - recursive: true, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }) - } - - fn dispatch( - sidecar: &mut NativeSidecar, - ownership: &OwnershipScope, - next_id: &mut i64, - payload: RequestPayload, - ) -> ResponsePayload { - *next_id += 1; - sidecar - .dispatch_blocking(request(*next_id, ownership.clone(), payload)) - .expect("dispatch guest fs op") - .response - .payload - } - - // Seed flat files `from..to` via guest WriteFile (mirrors into the host - // shadow root). Write-side ops do not walk, so seeding is O(count). - fn seed_to( - sidecar: &mut NativeSidecar, - ownership: &OwnershipScope, - next_id: &mut i64, - body: &str, - from: usize, - to: usize, - ) { - for i in from..to { - let path = format!("/seed-{i:05}.txt"); - let payload = fs_payload( - GuestFilesystemOperation::WriteFile, - &path, - Some(String::from(body)), - ); - match dispatch(sidecar, ownership, next_id, payload) { - ResponsePayload::GuestFilesystemResult(_) => {} - other => panic!("seed write failed: {other:?}"), - } - } - } - - fn time_exists( - sidecar: &mut NativeSidecar, - ownership: &OwnershipScope, - next_id: &mut i64, - ) -> Duration { - let payload = fs_payload(GuestFilesystemOperation::Exists, "/zzz-not-here", None); - let start = Instant::now(); - match dispatch(sidecar, ownership, next_id, payload) { - ResponsePayload::GuestFilesystemResult(r) => assert_eq!(r.exists, Some(false)), - other => panic!("exists failed: {other:?}"), - } - start.elapsed() - } - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let ownership = OwnershipScope::vm(&connection_id, &session_id, &vm_id); - let mut next_id: i64 = 1000; - - let file_body = "a".repeat(8 * 1024); - const COUNT: usize = 800; - seed_to(&mut sidecar, &ownership, &mut next_id, &file_body, 0, COUNT); - - // Cold: first read op reconciles the whole tree (reads + writes every file). - let cold = time_exists(&mut sidecar, &ownership, &mut next_id); - // Warm: tree is unchanged, so every file must be skipped. - let warm = time_exists(&mut sidecar, &ownership, &mut next_id); - - eprintln!("[shadow-skip] cold={cold:?} warm={warm:?}"); - - // Symptom-1 guard: the warm walk skips unchanged files, so it is far cheaper - // than the cold walk that copied them all. (Lenient 4x; observed >>10x.) - assert!( - cold >= warm * 4, - "warm read op over an unchanged shadow tree should skip re-copying files: \ - cold={cold:?} warm={warm:?}" - ); - - // End-to-end smoke: overwrite a seeded file (different length) then read it - // back and observe the new bytes. NOTE: this is a guest WriteFile, which - // updates the kernel directly, so it does not exercise the host-shadow->kernel - // skip predicate itself -- it only guards that overwrite-then-read is coherent. - // A true stale-skip test (host-side rewrite that keeps size+mode+mtime) is not - // reachable through the public wire API and would need an in-crate unit test - // with direct shadow-root access; see the skip-limitation note in - // sync_host_directory_tree_to_kernel_inner. - let changed_path = "/seed-00042.txt"; - let new_body = "b".repeat(16 * 1024); - match dispatch( - &mut sidecar, - &ownership, - &mut next_id, - fs_payload( - GuestFilesystemOperation::WriteFile, - changed_path, - Some(new_body.clone()), - ), - ) { - ResponsePayload::GuestFilesystemResult(_) => {} - other => panic!("overwrite failed: {other:?}"), - } - match dispatch( - &mut sidecar, - &ownership, - &mut next_id, - fs_payload(GuestFilesystemOperation::ReadFile, changed_path, None), - ) { - ResponsePayload::GuestFilesystemResult(r) => { - assert_eq!( - r.content.as_deref(), - Some(new_body.as_str()), - "changed shadow file must not be served stale by the skip" - ); - } - other => panic!("read after overwrite failed: {other:?}"), - } - } - - // Expensive: seeds hundreds of files and pays one cold full-tree reconciliation - // (seconds in debug). Gated out of the default suite; run with `--ignored`. - #[test] - #[ignore = "expensive: cold shadow-tree reconciliation; run with --ignored"] - fn read_side_ops_skip_unchanged_shadow_files() { - read_side_ops_skip_unchanged_shadow_files_repro(); - } - - fn configure_vm_rejects_module_access_root_symlink_to_non_node_modules() { - let module_access_cwd = temp_dir("secure-exec-sidecar-module-access-symlink-cwd"); - let outside_root = temp_dir("secure-exec-sidecar-module-access-outside"); - std::os::unix::fs::symlink(&outside_root, module_access_cwd.join("node_modules")) - .expect("create node_modules symlink"); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let response = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: None, - module_access_cwd: Some(module_access_cwd.to_string_lossy().into_owned()), - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure module_access mount"); - - match response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "plugin_error"); - assert!( - rejected.message.contains( - "module_access roots must resolve to a node_modules directory" - ), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - - fs::remove_dir_all(module_access_cwd).expect("remove cwd temp dir"); - fs::remove_dir_all(outside_root).expect("remove outside temp dir"); - } - - #[test] - fn configure_vm_rejects_module_access_symlinked_root_escape() { - configure_vm_rejects_module_access_root_symlink_to_non_node_modules(); - } - - fn configure_vm_js_bridge_mount_dispatches_filesystem_calls_via_sidecar_requests() { - let mut sidecar = create_test_sidecar(); - let (filesystem, calls) = install_memory_js_bridge_handler(&mut sidecar); - filesystem - .lock() - .expect("lock js bridge fs") - .write_file("/original.txt", b"hello world".to_vec()) - .expect("seed js bridge fs"); - - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("js_bridge"), - config: json!({ "mountId": "mount-1" }).to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure js_bridge mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - vm.kernel - .filesystem_mut() - .link("/workspace/original.txt", "/workspace/linked.txt") - .expect("create js bridge hard link"); - vm.kernel - .filesystem_mut() - .write_file("/workspace/linked.txt", b"updated".to_vec()) - .expect("write through linked file"); - vm.kernel - .filesystem_mut() - .chown("/workspace/original.txt", 2000, 3000) - .expect("update ownership"); - vm.kernel - .filesystem_mut() - .utimes( - "/workspace/linked.txt", - 1_700_000_000_000, - 1_710_000_000_000, - ) - .expect("update timestamps"); - - let original = vm - .kernel - .filesystem_mut() - .stat("/workspace/original.txt") - .expect("stat original"); - let linked = vm - .kernel - .filesystem_mut() - .stat("/workspace/linked.txt") - .expect("stat linked"); - assert_eq!(original.ino, linked.ino); - assert_eq!(original.nlink, 2); - assert_eq!(linked.nlink, 2); - assert_eq!(original.uid, 2000); - assert_eq!(original.gid, 3000); - assert_eq!(linked.uid, 2000); - assert_eq!(linked.gid, 3000); - assert_eq!(original.atime_ms, 1_700_000_000_000); - assert_eq!(original.mtime_ms, 1_710_000_000_000); - assert_eq!( - vm.kernel - .filesystem_mut() - .read_file("/workspace/original.txt") - .expect("read original through js bridge"), - b"updated".to_vec() - ); - - let calls = calls.lock().expect("lock js bridge calls"); - assert!(calls.iter().any(|call| { - call.mount_id == "mount-1" - && call.operation == "link" - && call.path.is_none() - && call.ownership == OwnershipScope::vm(&connection_id, &session_id, &vm_id) - })); - assert!(calls.iter().any(|call| { - call.mount_id == "mount-1" - && call.operation == "writeFile" - && call.path.as_deref() == Some("/linked.txt") - })); - assert!(calls.iter().any(|call| { - call.mount_id == "mount-1" - && call.operation == "stat" - && call.path.as_deref() == Some("/original.txt") - })); - } - - fn configure_vm_js_bridge_mount_rejects_oversized_read_payloads() { - let mut sidecar = create_test_sidecar(); - sidecar.set_sidecar_request_handler(|request| { - let SidecarRequestPayload::JsBridgeCall(call) = &request.payload else { - return Err(SidecarError::InvalidState(String::from( - "expected js_bridge_call payload", - ))); - }; - let call_args: Value = - serde_json::from_str(&call.args).expect("js bridge args json"); - match call.operation.as_str() { - "exists" => js_bridge_result(request, Some(Value::Bool(true)), None), - "realpath" => { - let path = call_args - .get("path") - .and_then(Value::as_str) - .map(|path| Value::String(path.to_owned())); - js_bridge_result(request, path, None) - } - "readFile" | "pread" => js_bridge_result( - request, - Some(Value::String( - base64::engine::general_purpose::STANDARD.encode(b"hello"), - )), - None, - ), - _ => js_bridge_result(request, None, None), - } - }); - - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([(String::from("resource.max_pread_bytes"), String::from("4"))]), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("js_bridge"), - config: json!({ "mountId": "mount-sized" }).to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure js_bridge mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let read_error = vm - .kernel - .filesystem_mut() - .read_file("/workspace/too-big.txt") - .expect_err("readFile callback payload should honor VM read limit"); - assert_eq!(read_error.code(), "EINVAL", "read error: {read_error}"); - - let pread_error = vm - .kernel - .filesystem_mut() - .pread("/workspace/too-big.txt", 0, 4) - .expect_err("pread callback payload should honor VM read limit"); - assert_eq!(pread_error.code(), "EINVAL", "pread error: {pread_error}"); - } - - #[test] - fn configure_vm_js_bridge_mount_bounds_read_payloads() { - configure_vm_js_bridge_mount_rejects_oversized_read_payloads(); - } - - fn configure_vm_js_bridge_mount_rejects_pread_payloads_above_requested_length() { - let mut sidecar = create_test_sidecar(); - sidecar.set_sidecar_request_handler(|request| { - let SidecarRequestPayload::JsBridgeCall(call) = &request.payload else { - return Err(SidecarError::InvalidState(String::from( - "expected js_bridge_call payload", - ))); - }; - let call_args: Value = - serde_json::from_str(&call.args).expect("js bridge args json"); - match call.operation.as_str() { - "exists" => js_bridge_result(request, Some(Value::Bool(true)), None), - "realpath" => { - let path = call_args - .get("path") - .and_then(Value::as_str) - .map(|path| Value::String(path.to_owned())); - js_bridge_result(request, path, None) - } - "readFile" | "pread" => js_bridge_result( - request, - Some(Value::String( - base64::engine::general_purpose::STANDARD.encode(b"hello"), - )), - None, - ), - _ => js_bridge_result(request, None, None), - } - }); - - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([(String::from("resource.max_pread_bytes"), String::from("8"))]), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("js_bridge"), - config: json!({ "mountId": "mount-pread-sized" }).to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure js_bridge mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - assert_eq!( - vm.kernel - .filesystem_mut() - .read_file("/workspace/within-limit.txt") - .expect("full read should fit VM read limit"), - b"hello".to_vec() - ); - - let pread_error = vm - .kernel - .filesystem_mut() - .pread("/workspace/too-long-for-pread.txt", 0, 4) - .expect_err("pread callback payload must not exceed requested length"); - assert_eq!(pread_error.code(), "EINVAL", "pread error: {pread_error}"); - } - - #[test] - fn configure_vm_js_bridge_mount_bounds_pread_payloads_to_requested_length() { - configure_vm_js_bridge_mount_rejects_pread_payloads_above_requested_length(); - } - - fn configure_vm_js_bridge_mount_maps_callback_errors_to_errno_codes() { - let mut sidecar = create_test_sidecar(); - sidecar.set_sidecar_request_handler(|request| { - let SidecarRequestPayload::JsBridgeCall(call) = &request.payload else { - return Err(SidecarError::InvalidState(String::from( - "expected js_bridge_call payload", - ))); - }; - let call_args: Value = - serde_json::from_str(&call.args).expect("js bridge args json"); - let path = call_args.get("path").and_then(Value::as_str); - if path == Some("/") { - return match call.operation.as_str() { - "exists" => js_bridge_result(request, Some(Value::Bool(true)), None), - "stat" | "lstat" => js_bridge_result( - request, - Some(stat_json(VirtualStat { - mode: 0o755, - size: 0, - blocks: 0, - dev: 1, - rdev: 0, - is_directory: true, - is_symbolic_link: false, - atime_ms: 0, - atime_nsec: 0, - mtime_ms: 0, - mtime_nsec: 0, - ctime_ms: 0, - ctime_nsec: 0, - birthtime_ms: 0, - ino: 1, - nlink: 1, - uid: 0, - gid: 0, - })), - None, - ), - "readDir" => js_bridge_result(request, Some(json!([])), None), - "readDirWithTypes" => { - js_bridge_result(request, Some(Value::Array(Vec::new())), None) - } - "realpath" => js_bridge_result(request, Some(json!("/")), None), - _ => js_bridge_result(request, None, None), - }; - } - - let error = match (call.operation.as_str(), path) { - ("realpath", Some("/missing.txt")) | ("readFile", Some("/missing.txt")) => { - "not found" - } - ("writeFile", Some("/output.txt")) => "permission denied", - ("rename", _) => "already exists", - ("stat", Some("/anything.txt")) => "unexpected js bridge failure", - _ => return js_bridge_result(request, None, None), - }; - js_bridge_result(request, None, Some(error)) - }); - - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("js_bridge"), - config: json!({ "mountId": "mount-errors" }).to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure js_bridge mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let read_error = vm - .kernel - .filesystem_mut() - .read_file("/workspace/missing.txt") - .expect_err("read should fail"); - assert_eq!(read_error.code(), "ENOENT"); - - let write_error = vm - .kernel - .filesystem_mut() - .write_file("/workspace/output.txt", b"blocked".to_vec()) - .expect_err("write should fail"); - assert_eq!(write_error.code(), "EACCES"); - - let rename_error = vm - .kernel - .filesystem_mut() - .rename("/workspace/a.txt", "/workspace/b.txt") - .expect_err("rename should fail"); - assert_eq!(rename_error.code(), "EEXIST"); - - let stat_error = vm - .kernel - .filesystem_mut() - .stat("/workspace/anything.txt") - .expect_err("stat should fail"); - assert_eq!(stat_error.code(), "EIO"); - } - fn configure_vm_instantiates_sandbox_agent_mounts_through_the_plugin_registry() { - let server = MockSandboxAgentServer::start("secure-exec-sidecar-sandbox", None); - fs::write(server.root().join("hello.txt"), "hello from sandbox") - .expect("seed sandbox file"); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystem(BootstrapRootFilesystemRequest { - entries: vec![ - RootFilesystemEntry { - path: String::from("/sandbox"), - kind: RootFilesystemEntryKind::Directory, - ..Default::default() - }, - RootFilesystemEntry { - path: String::from("/sandbox/root-only.txt"), - kind: RootFilesystemEntryKind::File, - content: Some(String::from("root bootstrap file")), - ..Default::default() - }, - ], - }), - )) - .expect("bootstrap root sandbox dir"); - - sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/sandbox"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("sandbox_agent"), - config: json!({ - "baseUrl": server.base_url(), - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure sandbox_agent mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let hidden = vm - .kernel - .filesystem_mut() - .read_file("/sandbox/root-only.txt") - .expect_err("mounted sandbox should hide root-backed file"); - assert_eq!(hidden.code(), "ENOENT"); - assert_eq!( - vm.kernel - .filesystem_mut() - .read_file("/sandbox/hello.txt") - .expect("read mounted sandbox file"), - b"hello from sandbox".to_vec() - ); - - vm.kernel - .filesystem_mut() - .write_file("/sandbox/from-vm.txt", b"native sandbox mount".to_vec()) - .expect("write sandbox file"); - assert_eq!( - fs::read_to_string(server.root().join("from-vm.txt")).expect("read sandbox output"), - "native sandbox mount" - ); - } - fn configure_vm_instantiates_s3_mounts_through_the_plugin_registry() { - let server = MockS3Server::start(); - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock should be monotonic") - .as_nanos(); - let metadata_path = - std::env::temp_dir().join(format!("secure-exec-service-s3-{unique}.sqlite")); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystem(BootstrapRootFilesystemRequest { - entries: vec![ - RootFilesystemEntry { - path: String::from("/data"), - kind: RootFilesystemEntryKind::Directory, - ..Default::default() - }, - RootFilesystemEntry { - path: String::from("/data/root-only.txt"), - kind: RootFilesystemEntryKind::File, - content: Some(String::from("root bootstrap file")), - ..Default::default() - }, - ], - }), - )) - .expect("bootstrap root s3 dir"); - - sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/data"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("chunked_s3"), - config: json!({ - "bucket": "test-bucket", - "prefix": "service-test", - "metadataPath": metadata_path.to_string_lossy(), - "region": "us-east-1", - "endpoint": server.base_url(), - "credentials": { - "accessKeyId": "minioadmin", - "secretAccessKey": "minioadmin", - }, - "chunkSize": 8, - "inlineThreshold": 4, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure s3 mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let hidden = vm - .kernel - .filesystem_mut() - .read_file("/data/root-only.txt") - .expect_err("mounted s3 fs should hide root-backed file"); - assert_eq!(hidden.code(), "ENOENT"); - - vm.kernel - .filesystem_mut() - .write_file("/data/from-vm.txt", b"native s3 mount".to_vec()) - .expect("write s3-backed file"); - assert_eq!( - vm.kernel - .filesystem_mut() - .read_file("/data/from-vm.txt") - .expect("read s3-backed file"), - b"native s3 mount".to_vec() - ); - drop(sidecar); - - let requests = server.requests(); - assert!( - requests.iter().any(|request| request.method == "PUT"), - "expected the native plugin to persist data back to S3" - ); - assert!( - requests - .iter() - .any(|request| request.path.contains("service-test/blocks/")), - "expected the native plugin to store block objects" - ); - let _ = fs::remove_file(metadata_path); - } - fn configure_vm_instantiates_object_s3_mounts_through_the_plugin_registry() { - let server = MockS3Server::start(); - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystem(BootstrapRootFilesystemRequest { - entries: vec![RootFilesystemEntry { - path: String::from("/objects"), - kind: RootFilesystemEntryKind::Directory, - ..Default::default() - }], - }), - )) - .expect("bootstrap root object dir"); - - sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/objects"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("object_s3"), - config: json!({ - "bucket": "test-bucket", - "prefix": "object-service-test", - "region": "us-east-1", - "endpoint": server.base_url(), - "credentials": { - "accessKeyId": "minioadmin", - "secretAccessKey": "minioadmin", - }, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure object_s3 mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - vm.kernel - .filesystem_mut() - .write_file("/objects/file.txt", b"native object mount".to_vec()) - .expect("write object s3-backed file"); - assert_eq!( - vm.kernel - .filesystem_mut() - .read_file("/objects/file.txt") - .expect("read object s3-backed file"), - b"native object mount".to_vec() - ); - drop(sidecar); - - assert!(server - .object_keys() - .iter() - .any(|key| key == "test-bucket/object-service-test/file.txt")); - } - fn configure_vm_instantiates_chunked_local_mounts_through_the_plugin_registry() { - let root = temp_dir("secure-exec-sidecar-chunked-local"); - let metadata_path = root.join("metadata.sqlite"); - let block_root = root.join("blocks"); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystem(BootstrapRootFilesystemRequest { - entries: vec![RootFilesystemEntry { - path: String::from("/local"), - kind: RootFilesystemEntryKind::Directory, - ..Default::default() - }], - }), - )) - .expect("bootstrap root local dir"); - - sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/local"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("chunked_local"), - config: json!({ - "metadataPath": metadata_path, - "blockRoot": block_root, - "chunkSize": 4, - "inlineThreshold": 1, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure chunked_local mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - vm.kernel - .filesystem_mut() - .write_file("/local/file.txt", b"native local mount".to_vec()) - .expect("write chunked local file"); - assert_eq!( - vm.kernel - .filesystem_mut() - .read_file("/local/file.txt") - .expect("read chunked local file"), - b"native local mount".to_vec() - ); - drop(sidecar); - - assert!(metadata_path.exists()); - assert!( - fs::read_dir(block_root) - .expect("read block root") - .next() - .is_some(), - "chunked_local should persist block files" - ); - } - fn assert_kernel_permission_decision( - decision: secure_exec_kernel::permissions::PermissionDecision, - expected_allow: bool, - expected_reason: Option<&str>, - ) { - assert_eq!(decision.allow, expected_allow); - if let Some(expected_reason) = expected_reason { - assert!( - decision - .reason - .as_deref() - .is_some_and(|reason| reason.contains(expected_reason)), - "expected reason to contain {expected_reason:?}, got {:?}", - decision.reason - ); - } else { - assert_eq!(decision.reason, None); - } - } - - #[test] - fn bridge_permissions_map_symlink_operations_to_symlink_access() { - let bridge = SharedBridge::new(RecordingBridge::default()); - let permissions = bridge_permissions(bridge.clone(), "vm-symlink"); - let check = permissions - .filesystem - .as_ref() - .expect("filesystem permission callback"); - - let decision = check(&FsAccessRequest { - vm_id: String::from("ignored-by-bridge"), - op: FsOperation::Symlink, - path: String::from("/workspace/link.txt"), - }); - assert!(decision.allow); - - let recorded = bridge - .inspect(|bridge| bridge.filesystem_permission_requests.clone()) - .expect("inspect bridge"); - assert_eq!( - recorded, - vec![FilesystemPermissionRequest { - vm_id: String::from("vm-symlink"), - path: String::from("/workspace/link.txt"), - access: FilesystemAccess::Symlink, - }] - ); - } - - #[test] - fn bridge_permissions_map_readlink_operations_to_readlink_access() { - let bridge = SharedBridge::new(RecordingBridge::default()); - let permissions = bridge_permissions(bridge.clone(), "vm-readlink"); - let check = permissions - .filesystem - .as_ref() - .expect("filesystem permission callback"); - - let decision = check(&FsAccessRequest { - vm_id: String::from("ignored-by-bridge"), - op: FsOperation::ReadLink, - path: String::from("/workspace/link.txt"), - }); - assert!(decision.allow); - - let recorded = bridge - .inspect(|bridge| bridge.filesystem_permission_requests.clone()) - .expect("inspect bridge"); - assert_eq!( - recorded, - vec![FilesystemPermissionRequest { - vm_id: String::from("vm-readlink"), - path: String::from("/workspace/link.txt"), - access: FilesystemAccess::ReadLink, - }] - ); - } - - #[test] - fn bridge_permissions_map_truncate_operations_to_truncate_access() { - let bridge = SharedBridge::new(RecordingBridge::default()); - let permissions = bridge_permissions(bridge.clone(), "vm-truncate"); - let check = permissions - .filesystem - .as_ref() - .expect("filesystem permission callback"); - - let decision = check(&FsAccessRequest { - vm_id: String::from("ignored-by-bridge"), - op: FsOperation::Truncate, - path: String::from("/workspace/file.txt"), - }); - assert!(decision.allow); - - let recorded = bridge - .inspect(|bridge| bridge.filesystem_permission_requests.clone()) - .expect("inspect bridge"); - assert_eq!( - recorded, - vec![FilesystemPermissionRequest { - vm_id: String::from("vm-truncate"), - path: String::from("/workspace/file.txt"), - access: FilesystemAccess::Truncate, - }] - ); - } - - #[test] - fn bridge_permissions_fail_closed_for_missing_mount_sensitive_policy() { - let bridge = SharedBridge::new(RecordingBridge::default()); - let permissions = bridge_permissions(bridge, "vm-mount-sensitive"); - let check = permissions - .filesystem - .as_ref() - .expect("filesystem permission callback"); - - let decision = check(&FsAccessRequest { - vm_id: String::from("ignored-by-bridge"), - op: FsOperation::MountSensitive, - path: String::from("/workspace"), - }); - - assert_kernel_permission_decision( - decision, - false, - Some("missing fs.mount_sensitive permission policy"), - ); - } - - #[test] - fn bridge_permissions_propagate_host_permission_outcomes() { - let cases = [ - (secure_exec_bridge::PermissionDecision::allow(), true, None), - ( - secure_exec_bridge::PermissionDecision::deny("blocked by host"), - false, - Some("blocked by host"), - ), - ( - secure_exec_bridge::PermissionDecision::prompt("prompt required"), - false, - Some("prompt required"), - ), - ( - secure_exec_bridge::PermissionDecision { - verdict: secure_exec_bridge::PermissionVerdict::Deny, - reason: None, - }, - false, - Some("denied by host"), - ), - ( - secure_exec_bridge::PermissionDecision { - verdict: secure_exec_bridge::PermissionVerdict::Prompt, - reason: None, - }, - false, - Some("permission prompt required"), - ), - ]; - - for (host_decision, expected_allow, expected_reason) in cases { - let bridge = SharedBridge::new(RecordingBridge::default()); - bridge - .inspect(|bridge| { - for _ in 0..4 { - bridge.push_permission_decision(host_decision.clone()); - } - }) - .expect("seed permission decisions"); - - assert_kernel_permission_decision( - bridge.filesystem_decision( - "vm-permissions", - "/workspace/file.txt", - FilesystemAccess::Read, - ), - expected_allow, - expected_reason, - ); - assert_kernel_permission_decision( - bridge.command_decision( - "vm-permissions", - &CommandAccessRequest { - vm_id: String::from("ignored-by-bridge"), - command: String::from("node"), - args: vec![String::from("--version")], - cwd: Some(String::from("/workspace")), - env: BTreeMap::new(), - }, - ), - expected_allow, - expected_reason, - ); - assert_kernel_permission_decision( - bridge.environment_decision( - "vm-permissions", - &EnvAccessRequest { - vm_id: String::from("ignored-by-bridge"), - op: EnvironmentOperation::Read, - key: String::from("PATH"), - value: None, - }, - ), - expected_allow, - expected_reason, - ); - assert_kernel_permission_decision( - bridge.network_decision( - "vm-permissions", - &NetworkAccessRequest { - vm_id: String::from("ignored-by-bridge"), - op: NetworkOperation::Fetch, - resource: String::from("https://example.test"), - }, - ), - expected_allow, - expected_reason, - ); - } - } - - #[test] - fn bridge_permissions_fail_closed_when_host_permission_checks_error() { - let bridge = SharedBridge::new(RecordingBridge::default()); - bridge - .inspect(|bridge| { - for _ in 0..4 { - bridge.push_permission_error("permission backend unavailable"); - } - }) - .expect("seed permission errors"); - - for decision in [ - bridge.filesystem_decision( - "vm-permissions", - "/workspace/file.txt", - FilesystemAccess::Read, - ), - bridge.command_decision( - "vm-permissions", - &CommandAccessRequest { - vm_id: String::from("ignored-by-bridge"), - command: String::from("node"), - args: vec![String::from("--version")], - cwd: Some(String::from("/workspace")), - env: BTreeMap::new(), - }, - ), - bridge.environment_decision( - "vm-permissions", - &EnvAccessRequest { - vm_id: String::from("ignored-by-bridge"), - op: EnvironmentOperation::Read, - key: String::from("PATH"), - value: None, - }, - ), - bridge.network_decision( - "vm-permissions", - &NetworkAccessRequest { - vm_id: String::from("ignored-by-bridge"), - op: NetworkOperation::Fetch, - resource: String::from("https://example.test"), - }, - ), - ] { - assert_kernel_permission_decision( - decision, - false, - Some("permission backend unavailable"), - ); - } - } - #[test] - fn vm_limits_config_reads_filesystem_limits() { - let config = secure_exec_vm_config::VmLimitsConfig { - resources: Some(secure_exec_vm_config::ResourceLimitsConfig { - max_sockets: Some(8), - max_connections: Some(4), - max_socket_buffered_bytes: Some(2048), - max_socket_datagram_queue_len: Some(16), - max_filesystem_bytes: Some(4096), - max_inode_count: Some(128), - max_blocking_read_ms: Some(250), - max_pread_bytes: Some(8192), - max_fd_write_bytes: Some(4096), - max_process_argv_bytes: Some(2048), - max_process_env_bytes: Some(1024), - max_readdir_entries: Some(32), - max_wasm_fuel: Some(5000), - max_wasm_memory_bytes: Some(131_072), - max_wasm_stack_bytes: Some(262_144), - ..Default::default() - }), - ..Default::default() - }; - - let limits = crate::limits::vm_limits_from_config( - Some(&config), - crate::wire::DEFAULT_MAX_FRAME_BYTES, - ) - .expect("parse resource limits"); - let limits = limits.resources; - assert_eq!(limits.max_sockets, Some(8)); - assert_eq!(limits.max_connections, Some(4)); - assert_eq!(limits.max_socket_buffered_bytes, Some(2048)); - assert_eq!(limits.max_socket_datagram_queue_len, Some(16)); - assert_eq!(limits.max_filesystem_bytes, Some(4096)); - assert_eq!(limits.max_inode_count, Some(128)); - assert_eq!(limits.max_blocking_read_ms, Some(250)); - assert_eq!(limits.max_pread_bytes, Some(8192)); - assert_eq!(limits.max_fd_write_bytes, Some(4096)); - assert_eq!(limits.max_process_argv_bytes, Some(2048)); - assert_eq!(limits.max_process_env_bytes, Some(1024)); - assert_eq!(limits.max_readdir_entries, Some(32)); - assert_eq!(limits.max_wasm_fuel, Some(5000)); - assert_eq!(limits.max_wasm_memory_bytes, Some(131072)); - assert_eq!(limits.max_wasm_stack_bytes, Some(262144)); - } - fn create_vm_applies_filesystem_permission_descriptors_to_kernel_access() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - capability_permissions(&[ - ("fs", PermissionMode::Allow), - ("fs.read", PermissionMode::Deny), - ]), - ) - .expect("create vm"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - vm.kernel - .filesystem_mut() - .write_file("/blocked.txt", b"nope".to_vec()) - .expect("write should be allowed"); - - let read_error = vm - .kernel - .filesystem_mut() - .read_file("/blocked.txt") - .expect_err("read should be denied"); - assert_eq!(read_error.code(), "EACCES"); - } - fn create_vm_without_permissions_defaults_to_static_deny_all() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let response = sidecar - .dispatch_blocking(request( - 3, - OwnershipScope::session(&connection_id, &session_id), - RequestPayload::CreateVm(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - std::collections::HashMap::new(), - Default::default(), - None, - )), - )) - .expect("create vm"); - let vm_id = created_vm_id(response).expect("vm created"); - let permission_check_count_before_write = sidecar - .with_bridge_mut(|bridge| bridge.permission_checks.len()) - .expect("read bootstrap permission checks"); - - let write_error = sidecar - .vms - .get_mut(&vm_id) - .expect("configured vm") - .kernel - .filesystem_mut() - .write_file("/blocked.txt", b"nope".to_vec()) - .expect_err("write should be denied"); - assert_eq!(write_error.code(), "EACCES"); - - let permission_check_count_after_write = sidecar - .with_bridge_mut(|bridge| bridge.permission_checks.len()) - .expect("read bridge permission checks"); - assert_eq!( - permission_check_count_after_write, permission_check_count_before_write, - "guest writes under default-deny should not fall through to bridge callbacks" - ); - } - fn configure_vm_rollback_restore_failure_falls_back_to_static_deny_all() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - sidecar - .bridge - .queue_set_vm_permissions_result(Ok(())) - .expect("queue allow-all bootstrap permission set"); - sidecar - .bridge - .queue_set_vm_permissions_result(Err(SidecarError::Bridge(String::from( - "injected restore failure", - )))) - .expect("queue restore failure"); - - let response = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "readOnly": false, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("dispatch configure_vm failure"); - - match response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - let message = rejected.message; - assert!(message.contains("configure_vm rollback failed")); - assert!(message.contains("injected restore failure")); - assert!(message.contains("applied deny-all fallback")); - } - other => panic!("expected rejected response, got {other:?}"), - } - - let stored_permissions = sidecar - .bridge - .permissions - .lock() - .expect("read stored permissions") - .get(&vm_id) - .cloned() - .expect("vm permissions tracked"); - assert_eq!( - stored_permissions, - secure_exec_sidecar_core::permissions::deny_all_policy() - ); - assert_eq!( - sidecar - .vms - .get(&vm_id) - .expect("configured vm") - .configuration - .permissions, - secure_exec_sidecar_core::permissions::deny_all_policy() - ); - - let permission_check_count_before_write = sidecar - .with_bridge_mut(|bridge| bridge.permission_checks.len()) - .expect("read bridge permission checks"); - let write_error = sidecar - .vms - .get_mut(&vm_id) - .expect("configured vm") - .kernel - .filesystem_mut() - .write_file("/blocked.txt", b"nope".to_vec()) - .expect_err("write should be denied after failed rollback"); - assert_eq!(write_error.code(), "EACCES"); - let permission_check_count_after_write = sidecar - .with_bridge_mut(|bridge| bridge.permission_checks.len()) - .expect("read bridge permission checks"); - assert_eq!( - permission_check_count_after_write, permission_check_count_before_write, - "guest writes under deny-all fallback should not fall through to bridge callbacks" - ); - } - fn toolkit_registration_rollback_restore_failure_keeps_registry_consistent() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let original_toolkit = - test_toolkit_payload("browser", "Browser automation", "screenshot"); - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(original_toolkit.clone()), - )) - .expect("register original toolkit"); - - let (toolkits_before, command_paths_before) = { - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - (vm.toolkits.clone(), vm.command_guest_paths.clone()) - }; - - sidecar - .bridge - .queue_set_vm_permissions_result(Ok(())) - .expect("queue allow-all toolkit refresh"); - sidecar - .bridge - .queue_set_vm_permissions_result(Err(SidecarError::Bridge(String::from( - "injected restore failure", - )))) - .expect("queue toolkit restore failure"); - - let response = sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "browser", - "Replacement browser toolkit", - "click", - )), - )) - .expect("dispatch toolkit registration failure"); - - match response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - let message = rejected.message; - assert!(message.contains("toolkit registration rollback failed")); - assert!(message.contains("injected restore failure")); - assert!(message.contains("applied deny-all fallback")); - } - other => panic!("expected rejected response, got {other:?}"), - } - - let stored_permissions = sidecar - .bridge - .permissions - .lock() - .expect("read stored permissions") - .get(&vm_id) - .cloned() - .expect("vm permissions tracked"); - assert_eq!( - stored_permissions, - secure_exec_sidecar_core::permissions::deny_all_policy() - ); - - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - assert_eq!( - vm.configuration.permissions, - secure_exec_sidecar_core::permissions::deny_all_policy() - ); - assert_eq!(vm.toolkits, toolkits_before); - assert_eq!(vm.command_guest_paths, command_paths_before); - } - fn create_vm_rejects_permission_rules_with_empty_operations() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let response = sidecar - .dispatch_blocking(request( - 3, - OwnershipScope::session(&connection_id, &session_id), - RequestPayload::CreateVm(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - std::collections::HashMap::new(), - Default::default(), - Some(PermissionsPolicy { - fs: Some(FsPermissionScope::FsPermissionRuleSet( - FsPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![FsPermissionRule { - mode: PermissionMode::Allow, - operations: Vec::new(), - paths: vec![String::from("*")], - }], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }), - )), - )) - .expect("dispatch create vm"); - - match response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!( - rejected - .message - .contains("fs.rules[0].operations must not be empty"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - } - fn configure_vm_rejects_permission_rules_with_empty_paths_or_patterns() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let fs_response = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: Some(PermissionsPolicy { - fs: Some(FsPermissionScope::FsPermissionRuleSet( - FsPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![FsPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("read")], - paths: Vec::new(), - }], - }, - )), - network: None, - child_process: None, - process: None, - env: None, - binding: None, - }), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("dispatch fs configure vm"); - - match fs_response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!( - rejected - .message - .contains("fs.rules[0].paths must not be empty"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - - let network_response = sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: Some(PermissionsPolicy { - fs: None, - network: Some(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![PatternPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("dns")], - patterns: Vec::new(), - }], - }, - )), - child_process: None, - process: None, - env: None, - binding: None, - }), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("dispatch network configure vm"); - - match network_response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!( - rejected - .message - .contains("network.rules[0].patterns must not be empty"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - } - fn configure_vm_mounts_bypass_guest_fs_write_policy() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - sidecar - .bridge - .set_vm_permissions( - &vm_id, - &crate::wire::permissions_policy_config_from_wire(capability_permissions(&[( - "fs.write", - PermissionMode::Deny, - )])), - ) - .expect("set vm permissions"); - - let result = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("memory"), - config: json!({}).to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("dispatch configure vm"); - - match result.response.payload { - ResponsePayload::VmConfigured(response) => { - // 1 = just the client mount. No packages configured, so there - // are no granular /opt/agentos leaf mounts (added per package). - assert_eq!(response.applied_mounts, 1); - } - other => panic!("expected configured response, got {other:?}"), - } - } - fn guest_filesystem_link_and_truncate_preserve_hard_link_semantics() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - for (request_id, payload) in [ - ( - 4, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Mkdir, - path: String::from("/workspace"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: true, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }, - ), - ( - 5, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/workspace/note.txt"), - destination_path: None, - target: None, - content: Some(String::from("stdio-sidecar-fs")), - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }, - ), - ( - 6, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Link, - path: String::from("/workspace/note.txt"), - destination_path: Some(String::from("/workspace/hard.txt")), - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }, - ), - ( - 7, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Truncate, - path: String::from("/workspace/hard.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: Some(5), - offset: None, - }, - ), - ( - 8, - GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Utimes, - path: String::from("/workspace/note.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: Some(1_700_000_000_000), - mtime_ms: Some(1_710_000_000_000), - len: None, - offset: None, - }, - ), - ] { - sidecar - .dispatch_blocking(request( - request_id, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCall(payload), - )) - .expect("dispatch guest filesystem request"); - } - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let note_stat = vm - .kernel - .stat("/workspace/note.txt") - .expect("stat source after truncate"); - let hard_stat = vm - .kernel - .stat("/workspace/hard.txt") - .expect("stat hard link after truncate"); - let note = vm - .kernel - .read_file("/workspace/note.txt") - .expect("read source after truncate"); - let hard = vm - .kernel - .read_file("/workspace/hard.txt") - .expect("read hard link after truncate"); - - assert_eq!(note, b"stdio".to_vec()); - assert_eq!(hard, b"stdio".to_vec()); - assert_eq!(note_stat.size, 5); - assert_eq!(hard_stat.size, 5); - assert_eq!(note_stat.ino, hard_stat.ino); - assert_eq!(note_stat.nlink, 2); - assert_eq!(hard_stat.nlink, 2); - assert_eq!(note_stat.mtime_ms, 1_710_000_000_000); - assert_eq!(hard_stat.mtime_ms, 1_710_000_000_000); - } - fn configure_vm_sensitive_mounts_bypass_guest_fs_mount_sensitive_policy() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - sidecar - .bridge - .set_vm_permissions( - &vm_id, - &crate::wire::permissions_policy_config_from_wire(capability_permissions(&[ - ("fs.write", PermissionMode::Allow), - ("fs.mount_sensitive", PermissionMode::Deny), - ])), - ) - .expect("set vm permissions"); - - let result = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/etc"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("memory"), - config: json!({}).to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("dispatch configure vm"); - - match result.response.payload { - ResponsePayload::VmConfigured(response) => { - // 1 = just the client mount. No packages configured, so there - // are no granular /opt/agentos leaf mounts (added per package). - assert_eq!(response.applied_mounts, 1); - } - other => panic!("expected configured response, got {other:?}"), - } - } - fn guest_mount_request_default_deny_rejects_without_changing_operator_mounts() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let response = sidecar - .dispatch_blocking(request( - 3, - OwnershipScope::session(&connection_id, &session_id), - RequestPayload::CreateVm(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - std::collections::HashMap::new(), - Default::default(), - None, - )), - )) - .expect("create vm"); - let vm_id = created_vm_id(response).expect("vm created"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::BootstrapRootFilesystem(BootstrapRootFilesystemRequest { - entries: vec![RootFilesystemEntry { - path: String::from("/guest-mount"), - kind: RootFilesystemEntryKind::Directory, - ..Default::default() - }], - }), - )) - .expect("bootstrap guest mount directory"); - - let configure_response = sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("memory"), - config: json!({}).to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure operator mount"); - - match configure_response.response.payload { - ResponsePayload::VmConfigured(configured) => { - // 1 = just the client mount. No packages configured, so there - // are no granular /opt/agentos leaf mounts (added per package). - assert_eq!(configured.applied_mounts, 1); - } - other => panic!("expected configured response, got {other:?}"), - } - - let operator_mounts = sidecar - .vms - .get(&vm_id) - .expect("configured vm") - .kernel - .mounted_filesystems(); - assert_eq!( - operator_mounts.len(), - 2, - "root + operator-applied mount (no packages configured, so no /opt/agentos leaf mounts)" - ); - - let mount_error = sidecar - .vms - .get_mut(&vm_id) - .expect("configured vm") - .kernel - .mount_filesystem( - "/guest-mount", - MemoryFileSystem::new(), - MountOptions::new("memory"), - ) - .expect_err("guest mount under default-deny should be rejected"); - assert_eq!(mount_error.code(), "EACCES"); - - let mounts_after_guest_request = sidecar - .vms - .get(&vm_id) - .expect("configured vm") - .kernel - .mounted_filesystems(); - assert_eq!(mounts_after_guest_request, operator_mounts); - } - fn scoped_host_filesystem_unscoped_target_requires_exact_guest_root_prefix() { - let filesystem = ScopedHostFilesystem::new( - HostFilesystem::new(SharedBridge::new(RecordingBridge::default()), "vm-1"), - "/data", - ); - - assert_eq!( - filesystem.unscoped_target(String::from("/database")), - "/database" - ); - assert_eq!( - filesystem.unscoped_target(String::from("/data/nested.txt")), - "/nested.txt" - ); - assert_eq!(filesystem.unscoped_target(String::from("/data")), "/"); - } - fn scoped_host_filesystem_realpath_preserves_paths_outside_guest_root() { - let bridge = SharedBridge::new(RecordingBridge::default()); - bridge - .inspect(|bridge| { - secure_exec_bridge::FilesystemBridge::symlink( - bridge, - SymlinkRequest { - vm_id: String::from("vm-1"), - target_path: String::from("/database"), - link_path: String::from("/data/alias"), - }, - ) - .expect("seed alias symlink"); - }) - .expect("inspect bridge"); - - let filesystem = - ScopedHostFilesystem::new(HostFilesystem::new(bridge, "vm-1"), "/data"); - - assert_eq!( - filesystem.realpath("/alias").expect("resolve alias"), - "/database" - ); - } - fn host_filesystem_realpath_fails_closed_on_circular_symlinks() { - let bridge = SharedBridge::new(RecordingBridge::default()); - bridge - .inspect(|bridge| { - secure_exec_bridge::FilesystemBridge::symlink( - bridge, - SymlinkRequest { - vm_id: String::from("vm-1"), - target_path: String::from("/loop-b.txt"), - link_path: String::from("/loop-a.txt"), - }, - ) - .expect("seed loop-a symlink"); - secure_exec_bridge::FilesystemBridge::symlink( - bridge, - SymlinkRequest { - vm_id: String::from("vm-1"), - target_path: String::from("/loop-a.txt"), - link_path: String::from("/loop-b.txt"), - }, - ) - .expect("seed loop-b symlink"); - }) - .expect("inspect bridge"); - - let filesystem = HostFilesystem::new(bridge, "vm-1"); - let error = filesystem - .realpath("/loop-a.txt") - .expect_err("circular symlink chain should fail closed"); - assert_eq!(error.code(), "ELOOP"); - } - fn configure_vm_host_dir_plugin_fails_closed_for_escape_symlinks() { - let host_dir = temp_dir("secure-exec-sidecar-host-dir-escape"); - std::os::unix::fs::symlink("/etc", host_dir.join("escape")) - .expect("seed escape symlink"); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": host_dir, - "readOnly": false, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure host_dir mount"); - - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - let error = vm - .kernel - .filesystem_mut() - .read_file("/workspace/escape/hostname") - .expect_err("escape symlink should fail closed"); - assert_eq!(error.code(), "EACCES"); - - fs::remove_dir_all(host_dir).expect("remove temp dir"); - } - fn execute_starts_python_runtime_instead_of_rejecting_it() { - assert_node_available(); - - let cache_root = temp_dir("secure-exec-sidecar-python-cache"); - - acquire_sidecar_runtime_test_lock(); - let mut sidecar = NativeSidecar::with_config( - RecordingBridge::default(), - NativeSidecarConfig { - sidecar_id: String::from("sidecar-python-test"), - compile_cache_root: Some(cache_root), - expected_auth_token: Some(String::from(TEST_AUTH_TOKEN)), - ..NativeSidecarConfig::default() - }, - ) - .expect("create sidecar"); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let result = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-python"), - command: None, - runtime: Some(GuestRuntimeKind::Python), - entrypoint: Some(String::from("print('hello from python')")), - args: Vec::new(), - env: std::collections::HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch python execute"); - - match result.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, "proc-python"); - assert!( - response.pid.is_some(), - "python runtime should expose a child pid" - ); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let vm = sidecar.vms.get(&vm_id).expect("python vm"); - let process = vm - .active_processes - .get("proc-python") - .expect("python process should be tracked"); - assert_eq!(process.runtime, GuestRuntimeKind::Python); - match &process.execution { - ActiveExecution::Python(_) => {} - other => panic!("unexpected active execution variant: {other:?}"), - } - } - fn command_resolution_executes_wasm_command_from_sidecar_path() { - let command_root = temp_dir("secure-exec-sidecar-command-resolution-wasm"); - write_fixture( - &command_root.join("hello"), - wat::parse_str( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) - (data (i32.const 16) "wasm:ready\n") - (func $_start (export "_start") - (i32.store (i32.const 0) (i32.const 16)) - (i32.store (i32.const 4) (i32.const 11)) - (drop - (call $fd_write - (i32.const 1) - (i32.const 0) - (i32.const 1) - (i32.const 32) - ) - ) - ) -) -"#, - ) - .expect("compile wasm fixture"), - ); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/__secure_exec/commands/0"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": command_root, - "readOnly": true, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure command mount"); - - let response = sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-command-wasm"), - command: Some(String::from("hello")), - runtime: None, - entrypoint: None, - args: Vec::new(), - env: std::collections::HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch wasm command execute"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, "proc-command-wasm"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (stdout, stderr, exit_code) = - drain_process_output(&mut sidecar, &vm_id, "proc-command-wasm"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - assert!(stdout.contains("wasm:ready"), "stdout: {stdout}"); - } - - fn wasm_command_timeout_is_enforced_by_sidecar_poll_path() { - // Timeout-dependent: an infinite-loop wasm module whose termination is - // enforced by the sidecar poll path only after ~30s. Gate it to the - // nightly timing lane rather than pay ~30s per PR. See CLAUDE.md > Testing. - if !run_timing_sensitive_tests() { - return; - } - let command_root = temp_dir("secure-exec-sidecar-command-resolution-wasm-timeout"); - write_fixture( - &command_root.join("spin"), - wat::parse_str( - r#" -(module - (memory (export "memory") 1) - (func $_start (export "_start") - (loop $spin - br $spin - ) - ) -) -"#, - ) - .expect("compile infinite-loop wasm fixture"), - ); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([(String::from("resource.max_wasm_fuel"), String::from("25"))]), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/__secure_exec/commands/0"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": command_root, - "readOnly": true, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure command mount"); - - let response = sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-command-wasm-timeout"), - command: Some(String::from("spin")), - runtime: None, - entrypoint: None, - args: Vec::new(), - env: std::collections::HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch wasm command execute"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, "proc-command-wasm-timeout"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (stdout, stderr, exit_code) = - drain_process_output(&mut sidecar, &vm_id, "proc-command-wasm-timeout"); - - assert_eq!(exit_code, Some(124), "stdout: {stdout} stderr: {stderr}"); - assert!( - stderr.contains("fuel budget exhausted"), - "stderr should mention timeout: {stderr}" - ); - } - - fn wasm_fd_write_sync_rpc_keeps_stdout_isolated_per_vm() { - let cwd_a = temp_dir("secure-exec-sidecar-wasm-stdio-vm-a"); - let cwd_b = temp_dir("secure-exec-sidecar-wasm-stdio-vm-b"); - write_fixture(&cwd_a.join("guest.wasm"), wasm_stdout_module("VM_A_MARKER")); - write_fixture(&cwd_b.join("guest.wasm"), wasm_stdout_module("VM_B_MARKER")); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_a = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm A"); - let vm_b = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm B"); - - for (request_id, vm_id, process_id, entrypoint) in [ - (6, &vm_a, "proc-wasm-a", cwd_a.join("guest.wasm")), - (7, &vm_b, "proc-wasm-b", cwd_b.join("guest.wasm")), - ] { - let response = sidecar - .dispatch_blocking(request( - request_id, - OwnershipScope::vm(&connection_id, &session_id, vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from(process_id), - command: None, - runtime: Some(GuestRuntimeKind::WebAssembly), - entrypoint: Some(entrypoint.to_string_lossy().into_owned()), - args: Vec::new(), - env: std::collections::HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch wasm execute"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected execute response: {other:?}"), - } - } - - let (stdout_a, stderr_a, exit_a) = - drain_process_output(&mut sidecar, &vm_a, "proc-wasm-a"); - let (stdout_b, stderr_b, exit_b) = - drain_process_output(&mut sidecar, &vm_b, "proc-wasm-b"); - - assert_eq!(exit_a, Some(0), "stderr A: {stderr_a}"); - assert_eq!(exit_b, Some(0), "stderr B: {stderr_b}"); - assert!(stderr_a.is_empty(), "unexpected stderr A: {stderr_a}"); - assert!(stderr_b.is_empty(), "unexpected stderr B: {stderr_b}"); - assert!( - stdout_a.contains("VM_A_MARKER"), - "stdout A missing marker: {stdout_a:?}" - ); - assert!( - !stdout_a.contains("VM_B_MARKER"), - "stdout A leaked B marker: {stdout_a:?}" - ); - assert!( - stdout_b.contains("VM_B_MARKER"), - "stdout B missing marker: {stdout_b:?}" - ); - assert!( - !stdout_b.contains("VM_A_MARKER"), - "stdout B leaked A marker: {stdout_b:?}" - ); - } - fn wasm_path_open_read_goes_through_kernel_filesystem_permissions() { - let cwd = temp_dir("secure-exec-sidecar-wasm-fs-permissions"); - write_fixture( - &cwd.join("guest.wasm"), - wasm_expect_read_errno_module("secret.txt", 2), - ); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - capability_permissions(&[ - ("fs", PermissionMode::Allow), - ("fs.read", PermissionMode::Deny), - ("child_process.spawn", PermissionMode::Allow), - ]), - ) - .expect("create vm"); - - sidecar - .vms - .get_mut(&vm_id) - .expect("wasm vm") - .kernel - .filesystem_mut() - .write_file("/secret.txt", b"should-not-read".to_vec()) - .expect("seed denied-read fixture"); - - let response = sidecar - .dispatch_blocking(request( - 6, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-wasm-fs-permission"), - command: None, - runtime: Some(GuestRuntimeKind::WebAssembly), - entrypoint: Some(cwd.join("guest.wasm").to_string_lossy().into_owned()), - args: Vec::new(), - env: std::collections::HashMap::new(), - cwd: Some(String::from("/")), - wasm_permission_tier: None, - }), - )) - .expect("dispatch wasm execute"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, "proc-wasm-fs-permission"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (stdout, stderr, exit_code) = - drain_process_output(&mut sidecar, &vm_id, "proc-wasm-fs-permission"); - - assert_eq!(exit_code, Some(0), "stdout: {stdout} stderr: {stderr}"); - assert!(stdout.is_empty(), "unexpected stdout: {stdout}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - } - - fn wasm_path_open_write_goes_through_kernel_filesystem_permissions() { - let cwd = temp_dir("secure-exec-sidecar-wasm-fs-write-permissions"); - write_fixture( - &cwd.join("guest.wasm"), - wasm_expect_write_open_errno_module("created.txt", 2), - ); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - capability_permissions(&[ - ("fs", PermissionMode::Allow), - ("fs.read", PermissionMode::Allow), - ("fs.write", PermissionMode::Deny), - ("child_process.spawn", PermissionMode::Allow), - ]), - ) - .expect("create vm"); - - let response = sidecar - .dispatch_blocking(request( - 6, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-wasm-fs-write-permission"), - command: None, - runtime: Some(GuestRuntimeKind::WebAssembly), - entrypoint: Some(cwd.join("guest.wasm").to_string_lossy().into_owned()), - args: Vec::new(), - env: std::collections::HashMap::new(), - cwd: Some(String::from("/")), - wasm_permission_tier: None, - }), - )) - .expect("dispatch wasm execute"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, "proc-wasm-fs-write-permission"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (stdout, stderr, exit_code) = - drain_process_output(&mut sidecar, &vm_id, "proc-wasm-fs-write-permission"); - - assert_eq!(exit_code, Some(0), "stdout: {stdout} stderr: {stderr}"); - assert!(stdout.is_empty(), "unexpected stdout: {stdout}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - assert!( - !sidecar - .vms - .get_mut(&vm_id) - .expect("wasm vm") - .kernel - .filesystem_mut() - .exists("/created.txt") - .expect("check denied-created file"), - "denied WASI write open should not create a kernel file" - ); - } - - fn wasm_fd_write_sync_rpc_routes_stdout_into_kernel_pty() { - let cwd = temp_dir("secure-exec-sidecar-wasm-stdio-pty"); - write_fixture(&cwd.join("guest.wasm"), wasm_stdout_module("PTY_MARKER")); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let master_fd = - start_fake_wasm_process(&mut sidecar, &vm_id, &cwd, "proc-wasm-pty", true) - .expect("attach stdout pty"); - - let mut pty_text = None; - let mut stderr = Vec::new(); - let mut exit_code = None; - - for _ in 0..64 { - let next_event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("active vm"); - vm.active_processes - .get_mut("proc-wasm-pty") - .and_then(|process| { - if let Some(event) = process.pending_execution_events.pop_front() { - Some(event) - } else { - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll wasm pty process event") - } - }) - }; - let Some(event) = next_event else { - break; - }; - - if let ActiveExecutionEvent::Stderr(chunk) = &event { - append_process_stream_chunk(&mut stderr, chunk, "proc-wasm-pty", "stderr"); - } - if let ActiveExecutionEvent::Exited(code) = &event { - exit_code = Some(*code); - } - - sidecar - .handle_execution_event(&vm_id, "proc-wasm-pty", event) - .expect("handle wasm pty process event"); - - if pty_text.is_none() { - let maybe_pty = { - let vm = sidecar.vms.get_mut(&vm_id).expect("wasm vm"); - let kernel_pid = vm - .active_processes - .get("proc-wasm-pty") - .map(|process| process.kernel_pid) - .unwrap_or_else(|| { - panic!("proc-wasm-pty should stay active until exit is handled") - }); - let ready = vm - .kernel - .poll_targets( - EXECUTION_DRIVER_NAME, - kernel_pid, - vec![PollTargetEntry::fd(master_fd, POLLIN)], - 0, - ) - .expect("poll pty master"); - if ready.ready_count == 0 { - None - } else { - Some( - String::from_utf8( - vm.kernel - .fd_read(EXECUTION_DRIVER_NAME, kernel_pid, master_fd, 64) - .expect("read pty master"), - ) - .expect("pty output utf8"), - ) - } - }; - if maybe_pty.is_some() { - pty_text = maybe_pty; - } - } - - if exit_code.is_some() && pty_text.is_some() { - break; - } - } - - let pty_text = pty_text.expect("pty master should receive stdout"); - let stderr = process_stream_to_string(&stderr); - assert!( - pty_text.replace("\r\n", "\n").contains("PTY_MARKER\n"), - "pty output should contain routed marker: {pty_text:?}" - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); - } - fn javascript_child_process_searches_path_for_mounted_wasm_commands() { - let command_root = temp_dir("secure-exec-sidecar-command-path-root"); - for command in ["sh", "ls", "cat", "grep", "echo", "sed"] { - write_fixture(&command_root.join(command), b"placeholder"); - } - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/__secure_exec/commands/0"), - read_only: true, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": command_root, - "readOnly": true, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure command-path mounts"); - - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - let path = vm - .guest_env - .get("PATH") - .expect("configured PATH should exist"); - let path_entries = path.split(':').collect::>(); - assert!( - path_entries - .first() - .is_some_and(|entry| *entry == "/__secure_exec/commands/0"), - "PATH should prioritize mounted command root: {path}" - ); - assert!( - path_entries.contains(&"/__secure_exec/commands/0"), - "PATH should include mounted command root: {path}" - ); - - for (command, request, expected_process_args) in [ - ( - "sh", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("sh"), - args: vec![String::from("-c"), String::from("echo hello")], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - vec![ - String::from("sh"), - String::from("-c"), - String::from("cd '/workspace' && echo hello"), - ], - ), - ( - "ls", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("ls"), - args: vec![String::from("/")], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - vec![String::from("ls"), String::from("/")], - ), - ( - "cat", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("cat"), - args: vec![String::from("/tmp/file")], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - vec![String::from("cat"), String::from("/tmp/file")], - ), - ( - "grep", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("grep"), - args: vec![String::from("pattern"), String::from("/tmp/file")], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - vec![ - String::from("grep"), - String::from("pattern"), - String::from("/tmp/file"), - ], - ), - ( - "echo", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("echo"), - args: vec![String::from("hello")], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - vec![String::from("echo"), String::from("hello")], - ), - ( - "sed", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("sed"), - args: vec![String::from("s/a/b/"), String::from("/tmp/file")], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - vec![ - String::from("sed"), - String::from("s/a/b/"), - String::from("/tmp/file"), - ], - ), - ] { - let resolved = sidecar - .resolve_javascript_child_process_execution( - vm, - &vm.guest_env, - &vm.guest_cwd, - &vm.host_cwd, - &request, - ) - .unwrap_or_else(|error| panic!("failed to resolve {command}: {error}")); - assert_eq!( - resolved.runtime, - GuestRuntimeKind::WebAssembly, - "{command} should resolve as a WASM command" - ); - assert_eq!( - resolved.process_args, expected_process_args, - "{command} process args mismatch: {resolved:?}" - ); - assert!( - resolved.entrypoint.ends_with(&format!("/{command}")), - "{command} entrypoint should end with /{command}: {}", - resolved.entrypoint - ); - } - - let missing = sidecar.resolve_javascript_child_process_execution( - vm, - &vm.guest_env, - &vm.guest_cwd, - &vm.host_cwd, - &crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("definitely-not-a-command"), - args: Vec::new(), - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - ); - let error = missing.expect_err("missing command should fail"); - assert!( - error - .to_string() - .contains("command not found: definitely-not-a-command"), - "missing command error should mention the command: {error}" - ); - } - fn javascript_child_process_shell_mode_without_guest_sh_fails_loudly() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let vm = sidecar.vms.get(&vm_id).expect("created vm"); - assert!( - !vm.command_guest_paths.contains_key("sh"), - "test VM must not provide a guest sh command" - ); - - let request = crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("printf hi > out.txt"), - args: Vec::new(), - options: crate::protocol::JavascriptChildProcessSpawnOptions { - shell: true, - ..Default::default() - }, - }; - let error = sidecar - .resolve_javascript_child_process_execution( - vm, - &vm.guest_env, - &vm.guest_cwd, - &vm.host_cwd, - &request, - ) - .expect_err("shell-mode command without guest sh must fail instead of tokenizing"); - assert!( - error.to_string().contains("/bin/sh"), - "missing-sh error should mention /bin/sh: {error}" - ); - } - fn javascript_child_process_spawns_path_resolved_tool_commands() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "math", - "Math utilities", - "add", - )), - )) - .expect("register math toolkit"); - - let cwd = temp_dir("secure-exec-sidecar-tool-command-child-process"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-tool-child"); - - let spawned = sidecar - .spawn_javascript_child_process( - &vm_id, - "proc-js-tool-child", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("/usr/local/bin/agentos-math"), - args: vec![ - String::from("add"), - String::from("--a"), - String::from("2"), - String::from("--b"), - String::from("3"), - ], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - ) - .expect("spawn toolkit child process"); - - assert_eq!( - spawned["command"], - Value::String(String::from("agentos-math")) - ); - assert_eq!( - spawned["args"], - json!(["agentos-math", "add", "--a", "2", "--b", "3"]) - ); - } - fn javascript_child_process_resolves_path_resolved_tool_commands_as_tools() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 6, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "math", - "Math utilities", - "add", - )), - )) - .expect("register math toolkit"); - - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - let resolved = sidecar - .resolve_javascript_child_process_execution( - vm, - &vm.guest_env, - &vm.guest_cwd, - &vm.host_cwd, - &crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("/usr/local/bin/agentos-math"), - args: vec![ - String::from("add"), - String::from("--a"), - String::from("2"), - String::from("--b"), - String::from("3"), - ], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - ) - .expect("resolve toolkit child process"); - - assert!( - resolved.tool_command, - "tool command should stay on the tool path" - ); - assert_eq!(resolved.command, "agentos-math"); - assert_eq!( - resolved.process_args, - vec![ - String::from("agentos-math"), - String::from("add"), - String::from("--a"), - String::from("2"), - String::from("--b"), - String::from("3"), - ] - ); - } - fn javascript_child_process_spawns_internal_tool_command_paths() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 7, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "math", - "Math utilities", - "add", - )), - )) - .expect("register math toolkit"); - - let cwd = temp_dir("secure-exec-sidecar-tool-command-sync-rpc"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-tool-rpc"); - - let spawned = sidecar - .spawn_javascript_child_process( - &vm_id, - "proc-js-tool-rpc", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("/__secure_exec/commands/0/agentos-math"), - args: vec![ - String::from("add"), - String::from("--a"), - String::from("2"), - String::from("--b"), - String::from("3"), - ], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - ) - .expect("spawn toolkit child process over internal command path"); - - assert_eq!( - spawned["command"], - Value::String(String::from("agentos-math")) - ); - assert_eq!( - spawned["args"], - json!(["agentos-math", "add", "--a", "2", "--b", "3"]) - ); - } - fn javascript_child_process_resolves_internal_tool_command_paths_as_tools() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 8, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "math", - "Math utilities", - "add", - )), - )) - .expect("register math toolkit"); - - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - let resolved = sidecar - .resolve_javascript_child_process_execution( - vm, - &vm.guest_env, - &vm.guest_cwd, - &vm.host_cwd, - &crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("/__secure_exec/commands/0/agentos-math"), - args: vec![ - String::from("add"), - String::from("--a"), - String::from("2"), - String::from("--b"), - String::from("3"), - ], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - ) - .expect("resolve toolkit child process"); - - assert!( - resolved.tool_command, - "tool command should stay on the tool path" - ); - assert_eq!(resolved.command, "agentos-math"); - assert_eq!( - resolved.process_args, - vec![ - String::from("agentos-math"), - String::from("add"), - String::from("--a"), - String::from("2"), - String::from("--b"), - String::from("3"), - ] - ); - } - fn tools_register_host_callbacks_rejects_duplicate_names_without_replacing_existing_toolkit( - ) { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let original_toolkit = test_toolkit_payload("math", "Math utilities", "add"); - sidecar - .dispatch_blocking(request( - 9, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(original_toolkit.clone()), - )) - .expect("register original toolkit"); - - let duplicate_response = sidecar - .dispatch_blocking(request( - 10, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "math", - "Replacement math toolkit", - "subtract", - )), - )) - .expect("dispatch duplicate toolkit registration"); - - match duplicate_response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "conflict"); - assert!( - rejected - .message - .contains("toolkit already registered: math"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - assert_eq!(vm.toolkits.get("math"), Some(&original_toolkit)); - } - fn tools_register_host_callbacks_rejects_registry_overflow_without_mutating_vm() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - for index in 0..crate::tools::MAX_REGISTERED_TOOLKITS { - sidecar - .dispatch_blocking(request( - 20 + index as i64, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - &format!("toolkit-{index}"), - "Bounded test toolkit", - "run", - )), - )) - .expect("register toolkit"); - } - - let (toolkits_before, command_paths_before) = { - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - assert_eq!(vm.toolkits.len(), crate::tools::MAX_REGISTERED_TOOLKITS); - (vm.toolkits.clone(), vm.command_guest_paths.clone()) - }; - - let overflow_response = sidecar - .dispatch_blocking(request( - 100, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "overflow", - "Overflow toolkit", - "run", - )), - )) - .expect("dispatch overflow toolkit registration"); - - match overflow_response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!( - rejected.message.contains("registered toolkits"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - assert_eq!(vm.toolkits, toolkits_before); - assert_eq!(vm.command_guest_paths, command_paths_before); - assert!( - !vm.command_guest_paths.contains_key("agentos-overflow"), - "overflow command path should not be registered" - ); - } - fn tools_register_host_callbacks_rejects_total_tool_overflow_without_mutating_vm() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - for toolkit_index in 0..4 { - let tools = (0..crate::tools::MAX_TOOLS_PER_TOOLKIT) - .map(|tool_index| { - ( - format!("tool-{tool_index}"), - RegisteredHostCallbackDefinition { - description: format!("tool {tool_index}"), - input_schema: json!({ - "type": "object", - "properties": {}, - "additionalProperties": false, - }) - .to_string(), - timeout_ms: None, - examples: Vec::new(), - }, - ) - }) - .collect(); - - sidecar - .dispatch_blocking(request( - 120 + toolkit_index as i64, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(RegisterHostCallbacksRequest { - name: format!("toolkit-{toolkit_index}"), - description: String::from("Bounded test toolkit"), - command_aliases: vec![format!("agentos-toolkit-{toolkit_index}")], - registry_command_aliases: vec![format!("agentos-{toolkit_index}")], - callbacks: tools, - }), - )) - .expect("register toolkit"); - } - - let (toolkits_before, command_paths_before) = { - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - assert_eq!(vm.toolkits.len(), 4); - assert_eq!( - vm.toolkits - .values() - .map(|toolkit| toolkit.callbacks.len()) - .sum::(), - crate::tools::MAX_REGISTERED_TOOLS_PER_VM - ); - (vm.toolkits.clone(), vm.command_guest_paths.clone()) - }; - - let overflow_response = sidecar - .dispatch_blocking(request( - 200, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "overflow", - "Overflow toolkit", - "run", - )), - )) - .expect("dispatch total-tool overflow toolkit registration"); - - match overflow_response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!( - rejected.message.contains("registered host callbacks"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("expected rejected response, got {other:?}"), - } - - let vm = sidecar.vms.get(&vm_id).expect("configured vm"); - assert_eq!(vm.toolkits, toolkits_before); - assert_eq!(vm.command_guest_paths, command_paths_before); - assert!( - !vm.command_guest_paths.contains_key("agentos-overflow"), - "overflow command path should not be registered" - ); - } - fn tools_javascript_child_process_denies_host_callback_without_permission() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy { - fs: Some(FsPermissionScope::PermissionMode(PermissionMode::Allow)), - network: None, - child_process: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - process: None, - env: None, - binding: Some(PatternPermissionScope::PermissionMode(PermissionMode::Deny)), - }, - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 11, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "math", - "Math utilities", - "add", - )), - )) - .expect("register math toolkit"); - - let cwd = temp_dir("secure-exec-sidecar-tool-command-denied"); - insert_fake_javascript_parent_process( - &mut sidecar, - &vm_id, - &cwd, - "proc-js-tool-denied", - ); - - let result = sidecar - .spawn_javascript_child_process_sync( - &vm_id, - "proc-js-tool-denied", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("/usr/local/bin/agentos-math"), - args: vec![String::from("add")], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - None, - ) - .expect("spawn denied tool command"); - - assert_eq!(result["code"], json!(1)); - assert_eq!(result["stdout"], json!("")); - let stderr = result["stderr"] - .as_str() - .expect("stderr should be captured as a string"); - assert!( - stderr.contains("blocked by binding.invoke policy for math:add"), - "unexpected denied stderr: {stderr:?}" - ); - } - fn tools_javascript_child_process_invokes_tool_with_matching_permission() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let permissions = PermissionsPolicy { - fs: Some(FsPermissionScope::PermissionMode(PermissionMode::Allow)), - network: None, - child_process: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - process: None, - env: None, - binding: Some(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![PatternPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("invoke")], - patterns: vec![String::from("math:add")], - }], - }, - )), - }; - let vm_id = create_vm(&mut sidecar, &connection_id, &session_id, permissions) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 12, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload( - "math", - "Math utilities", - "add", - )), - )) - .expect("register math toolkit"); - - sidecar.set_sidecar_request_handler(|request| match request.payload { - SidecarRequestPayload::HostCallback(invocation) => { - assert_eq!(invocation.callback_key, "math:add"); - assert_eq!( - serde_json::from_str::(&invocation.input).expect("input json"), - json!({}) - ); - Ok(SidecarResponsePayload::HostCallbackResult( - HostCallbackResultResponse { - invocation_id: invocation.invocation_id, - result: Some(json!({ "sum": 5 }).to_string()), - error: None, - }, - )) - } - other => panic!("unexpected sidecar request payload: {other:?}"), - }); - - let cwd = temp_dir("secure-exec-sidecar-tool-command-allowed"); - insert_fake_javascript_parent_process( - &mut sidecar, - &vm_id, - &cwd, - "proc-js-tool-allowed", - ); - - let result = sidecar - .spawn_javascript_child_process_sync( - &vm_id, - "proc-js-tool-allowed", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("/usr/local/bin/agentos-math"), - args: vec![String::from("add")], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - None, - ) - .expect("spawn allowed tool command"); - - assert_eq!(result["code"], json!(0)); - assert_eq!(result["stderr"], json!("")); - let stdout = result["stdout"] - .as_str() - .expect("stdout should be captured as a string"); - let payload: Value = - serde_json::from_str(stdout).expect("parse successful tool invocation payload"); - assert_eq!( - payload, - json!({ - "ok": true, - "result": { "sum": 5 }, - }) - ); - } - fn tools_javascript_child_process_rejects_invalid_json_file_input_before_dispatch() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let permissions = PermissionsPolicy { - fs: Some(FsPermissionScope::PermissionMode(PermissionMode::Allow)), - network: None, - child_process: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - process: None, - env: None, - binding: Some(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![PatternPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("invoke")], - patterns: vec![String::from("math:add")], - }], - }, - )), - }; - let vm_id = create_vm(&mut sidecar, &connection_id, &session_id, permissions) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 13, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload_with_schema( - "math", - "Math utilities", - "add", - json!({ - "type": "object", - "properties": { - "count": { "type": "integer", "minimum": 0 }, - "label": { "type": "string" } - }, - "required": ["count", "label"], - "additionalProperties": false, - }), - )), - )) - .expect("register math toolkit"); - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("configured vm"); - vm.kernel - .write_file( - "/workspace/invalid-tool-input.json", - br#"{"count":"oops","label":4}"#.to_vec(), - ) - .expect("write invalid tool input"); - } - - let invocation_count = Arc::new(AtomicUsize::new(0)); - let seen_invocation_count = Arc::clone(&invocation_count); - sidecar.set_sidecar_request_handler(move |request| match request.payload { - SidecarRequestPayload::HostCallback(_) => { - seen_invocation_count.fetch_add(1, Ordering::SeqCst); - Err(SidecarError::InvalidState(String::from( - "tool invocation should not run for invalid JSON-file input", - ))) - } - other => panic!("unexpected sidecar request payload: {other:?}"), - }); - - let cwd = temp_dir("secure-exec-sidecar-tool-command-invalid-json-file"); - insert_fake_javascript_parent_process( - &mut sidecar, - &vm_id, - &cwd, - "proc-js-tool-invalid-json-file", - ); - - let result = sidecar - .spawn_javascript_child_process_sync( - &vm_id, - "proc-js-tool-invalid-json-file", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("/usr/local/bin/agentos-math"), - args: vec![ - String::from("add"), - String::from("--json-file"), - String::from("/workspace/invalid-tool-input.json"), - ], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - None, - ) - .expect("spawn invalid json-file tool command"); - - assert_eq!(result["code"], json!(1)); - assert_eq!(result["stdout"], json!("")); - let stderr = result["stderr"] - .as_str() - .expect("stderr should be captured as a string"); - assert!( - stderr.contains("ToolInputSchemaViolation at $.count"), - "unexpected schema violation stderr: {stderr:?}" - ); - assert!( - stderr.contains("expected integer"), - "unexpected schema violation stderr: {stderr:?}" - ); - assert_eq!(invocation_count.load(Ordering::SeqCst), 0); - } - fn tools_javascript_child_process_accepts_valid_json_input() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let permissions = PermissionsPolicy { - fs: Some(FsPermissionScope::PermissionMode(PermissionMode::Allow)), - network: None, - child_process: Some(PatternPermissionScope::PermissionMode( - PermissionMode::Allow, - )), - process: None, - env: None, - binding: Some(PatternPermissionScope::PatternPermissionRuleSet( - PatternPermissionRuleSet { - default: Some(PermissionMode::Deny), - rules: vec![PatternPermissionRule { - mode: PermissionMode::Allow, - operations: vec![String::from("invoke")], - patterns: vec![String::from("math:add")], - }], - }, - )), - }; - let vm_id = create_vm(&mut sidecar, &connection_id, &session_id, permissions) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 14, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::RegisterHostCallbacks(test_toolkit_payload_with_schema( - "math", - "Math utilities", - "add", - json!({ - "type": "object", - "properties": { - "count": { "type": "integer", "minimum": 0 }, - "label": { "type": "string" } - }, - "required": ["count", "label"], - "additionalProperties": false, - }), - )), - )) - .expect("register math toolkit"); - - let invocation_count = Arc::new(AtomicUsize::new(0)); - let seen_invocation_count = Arc::clone(&invocation_count); - sidecar.set_sidecar_request_handler(move |request| match request.payload { - SidecarRequestPayload::HostCallback(invocation) => { - seen_invocation_count.fetch_add(1, Ordering::SeqCst); - assert_eq!(invocation.callback_key, "math:add"); - assert_eq!( - serde_json::from_str::(&invocation.input).expect("input json"), - json!({ "count": 2, "label": "ok" }) - ); - Ok(SidecarResponsePayload::HostCallbackResult( - HostCallbackResultResponse { - invocation_id: invocation.invocation_id, - result: Some(json!({ "sum": 2 }).to_string()), - error: None, - }, - )) - } - other => panic!("unexpected sidecar request payload: {other:?}"), - }); - - let cwd = temp_dir("secure-exec-sidecar-tool-command-valid-json"); - insert_fake_javascript_parent_process( - &mut sidecar, - &vm_id, - &cwd, - "proc-js-tool-valid-json", - ); - - let result = sidecar - .spawn_javascript_child_process_sync( - &vm_id, - "proc-js-tool-valid-json", - crate::protocol::JavascriptChildProcessSpawnRequest { - command: String::from("/usr/local/bin/agentos-math"), - args: vec![ - String::from("add"), - String::from("--json"), - String::from(r#"{"count":2,"label":"ok"}"#), - ], - options: crate::protocol::JavascriptChildProcessSpawnOptions::default(), - }, - None, - ) - .expect("spawn valid json tool command"); - - assert_eq!(result["code"], json!(0)); - assert_eq!(result["stderr"], json!("")); - let stdout = result["stdout"] - .as_str() - .expect("stdout should be captured as a string"); - let payload: Value = - serde_json::from_str(stdout).expect("parse successful tool invocation payload"); - assert_eq!( - payload, - json!({ - "ok": true, - "result": { "sum": 2 }, - }) - ); - assert_eq!(invocation_count.load(Ordering::SeqCst), 1); - } - fn command_resolution_executes_javascript_path_command_with_sidecar_mappings() { - let workspace = temp_dir("secure-exec-sidecar-command-resolution-js"); - write_fixture( - &workspace.join("entry.js"), - r#" -const { message } = require("./message.js"); - -process.stdout.write(`${JSON.stringify({ - message, -})}\n`); -"#, - ); - write_fixture( - &workspace.join("message.js"), - r#"module.exports = { message: "resolved-from-mounted-workspace" };"#, - ); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("host_dir"), - config: json!({ - "hostPath": workspace, - "readOnly": false, - }) - .to_string(), - }, - }], - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: vec![4312], - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure workspace mount"); - - let response = sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-command-js"), - command: Some(String::from("./entry.js")), - runtime: None, - entrypoint: None, - args: Vec::new(), - env: std::collections::HashMap::new(), - cwd: Some(String::from("/workspace")), - wasm_permission_tier: None, - }), - )) - .expect("dispatch javascript command execute"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, "proc-command-js"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (stdout, stderr, exit_code) = - drain_process_output(&mut sidecar, &vm_id, "proc-command-js"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let payload: Value = - serde_json::from_str(stdout.trim()).expect("parse javascript command JSON"); - assert_eq!( - payload["message"], - Value::String(String::from("resolved-from-mounted-workspace")) - ); - } - - fn write_agentos_package_launch_fixture() -> PathBuf { - let package = temp_dir("secure-exec-sidecar-agentos-package-launch"); - fs::create_dir_all(package.join("node_modules/t1-dep")) - .expect("create bundled dependency"); - - write_fixture( - &package.join("agentos-package.json"), - r#"{"name":"t1-agent","version":"1.0.0","agent":{"acpEntrypoint":"x"}}"#, - ); - fs::create_dir_all(package.join("bin")).expect("create bin"); - std::os::unix::fs::symlink("../adapter.mjs", package.join("bin/x")) - .expect("symlink bin/x"); - write_fixture( - &package.join("node_modules/t1-dep/package.json"), - r#"{"name":"t1-dep","version":"1.0.0","type":"module","exports":"./index.mjs"}"#, - ); - write_fixture( - &package.join("node_modules/t1-dep/index.mjs"), - r#"export const marker = "dep-ok";"#, - ); - write_fixture( - &package.join("child.mjs"), - r#" -import { marker } from "t1-dep"; - -console.log(`child-ok:${marker}`); -"#, - ); - write_fixture( - &package.join("adapter.mjs"), - r#"#!/usr/bin/env node -import childProcess from "node:child_process"; -import { fileURLToPath } from "node:url"; -import { marker } from "t1-dep"; - -const entrypoint = fileURLToPath(import.meta.url); -console.log(`entrypoint:${entrypoint}`); -console.log(`adapter-ok:${marker}`); - -const child = childProcess.spawnSync("node", [ - fileURLToPath(new URL("./child.mjs", import.meta.url)), -], { - encoding: "utf8", -}); - -if (child.stdout) { - process.stdout.write(child.stdout); -} -if (child.stderr) { - process.stderr.write(child.stderr); -} -if (child.error) { - throw child.error; -} -if (child.status !== 0) { - process.exit(child.status ?? 1); -} -"#, - ); - // The command entry must be executable in the tar, exactly as the - // toolchain's pack step emits `bin/*` at 0755 (npm ships 0644). The - // tar builder follows `bin/x -> ../adapter.mjs`, so the launcher's - // mode is adapter.mjs's mode. - { - use std::os::unix::fs::PermissionsExt; - let mut perms = fs::metadata(package.join("adapter.mjs")) - .expect("stat adapter.mjs") - .permissions(); - perms.set_mode(0o755); - fs::set_permissions(package.join("adapter.mjs"), perms).expect("chmod adapter.mjs"); - } - - write_agentos_package_tar(&package); - package - } - - fn write_agentos_package_tar(package: &Path) { - let tar_path = package.join("package.tar"); - let _ = fs::remove_file(&tar_path); - let file = fs::File::create(&tar_path).expect("create package tar"); - let mut builder = tar::Builder::new(file); - // Match the toolchain's `tar -cf`, which stores symlinks as symlinks - // (e.g. `bin/x -> ../adapter.mjs`). Following them would flatten the - // launcher into a regular file and break `import.meta.url`-relative - // resolution inside the package. - builder.follow_symlinks(false); - append_agentos_package_tree(&mut builder, package, package) - .expect("append package tree"); - builder.finish().expect("finish package tar"); - builder - .into_inner() - .expect("finish package tar file") - .flush() - .expect("flush package tar"); - } - - fn append_agentos_package_tree( - builder: &mut tar::Builder, - root: &Path, - path: &Path, - ) -> std::io::Result<()> { - for entry in fs::read_dir(path)? { - let entry = entry?; - let entry_path = entry.path(); - if entry_path.file_name().and_then(|name| name.to_str()) == Some("package.tar") { - continue; - } - let name = entry_path - .strip_prefix(root) - .expect("package-relative path"); - if entry_path.is_dir() { - builder.append_dir(name, &entry_path)?; - append_agentos_package_tree(builder, root, &entry_path)?; - } else { - builder.append_path_with_name(&entry_path, name)?; - } - } - Ok(()) - } - - fn clean_legacy_agentos_projection_temps() { - let temp = std::env::temp_dir(); - if let Ok(entries) = fs::read_dir(&temp) { - for entry in entries.flatten() { - let name = entry.file_name(); - let name = name.to_string_lossy(); - if name.starts_with("agentos-pkgsrc-") || name.starts_with("agentos-opt-") { - let _ = fs::remove_dir_all(entry.path()); - } - } - } - } - - fn assert_no_legacy_agentos_projection_temps() { - let temp = std::env::temp_dir(); - let mut leftovers = Vec::new(); - if let Ok(entries) = fs::read_dir(&temp) { - for entry in entries.flatten() { - let name = entry.file_name(); - let name = name.to_string_lossy(); - if name.starts_with("agentos-pkgsrc-") || name.starts_with("agentos-opt-") { - leftovers.push(entry.path()); - } - } - } - assert!( - leftovers.is_empty(), - "legacy extraction/staging dirs should not be created: {leftovers:?}" - ); - } - - #[test] - fn agentos_packages_launch_keeps_adapter_and_child_entrypoints_guest_native() { - clean_legacy_agentos_projection_temps(); - let package = write_agentos_package_launch_fixture(); - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let applied_mounts = match sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: vec![crate::protocol::PackageDescriptor { - dir: Some(package.to_string_lossy().into_owned()), - tar: None, - }], - packages_mount_at: String::from("/opt/agentos"), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure agentos package mount") - .response - .payload - { - ResponsePayload::VmConfigured(response) => response.applied_mounts, - other => panic!("unexpected configure response: {other:?}"), - }; - assert!( - applied_mounts >= 3, - "expected package tar/current/bin leaf mounts, got {applied_mounts}" - ); - assert_no_legacy_agentos_projection_temps(); - - let response = sidecar - .dispatch_blocking(request( - 5, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-agentos-package-launch"), - command: Some(String::from("/opt/agentos/bin/x")), - runtime: None, - entrypoint: None, - args: Vec::new(), - env: std::collections::HashMap::new(), - cwd: Some(String::from("/")), - wasm_permission_tier: None, - }), - )) - .expect("dispatch agentos package execute"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, "proc-agentos-package-launch"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (stdout, stderr, exit_code) = - drain_process_output(&mut sidecar, &vm_id, "proc-agentos-package-launch"); - let combined_output = format!("{stdout}\n{stderr}"); - - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - assert!( - stdout.contains("entrypoint:/opt/agentos/"), - "stdout should report a guest-native /opt/agentos entrypoint: {stdout}" - ); - assert!( - stdout.contains("adapter-ok:dep-ok"), - "adapter did not import its bundled bare dependency: {stdout}" - ); - assert!( - stdout.contains("child-ok:dep-ok"), - "child process did not import the bundled bare dependency: {stdout}" - ); - assert!( - !combined_output.contains("/unknown"), - "launch should not translate to /unknown\nstdout: {stdout}\nstderr: {stderr}" - ); - assert!( - !stderr.contains("Cannot use import statement"), - "adapter should execute as ESM\nstderr: {stderr}" - ); - assert!( - !stderr.contains("escape the mount root"), - "package launch should stay confined within /opt/agentos\nstderr: {stderr}" - ); - } - - fn command_resolution_executes_node_eval_command() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let response = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-command-node-eval"), - command: Some(String::from("node")), - runtime: None, - entrypoint: None, - args: vec![ - String::from("-e"), - String::from("process.stdout.write('node-eval-ok\\n')"), - ], - env: std::collections::HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch node eval execute"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, "proc-command-node-eval"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (stdout, stderr, exit_code) = - drain_process_output(&mut sidecar, &vm_id, "proc-command-node-eval"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - assert!(stdout.contains("node-eval-ok"), "stdout: {stdout}"); - } - fn command_resolution_rejects_unknown_command() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let response = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-command-missing"), - command: Some(String::from("definitely-not-a-command")), - runtime: None, - entrypoint: None, - args: Vec::new(), - env: std::collections::HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch missing command execute"); - - match response.response.payload { - ResponsePayload::Rejected(rejected) => { - assert_eq!(rejected.code, "invalid_state"); - assert!( - rejected - .message - .contains("command not found on native sidecar path"), - "unexpected rejection: {rejected:?}" - ); - } - other => panic!("unexpected execute response: {other:?}"), - } - } - fn python_vfs_rpc_requests_proxy_into_the_vm_kernel_filesystem() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-python-vfs-rpc-cwd"); - let pyodide_dir = temp_dir("secure-exec-sidecar-python-vfs-rpc-pyodide"); - write_fixture( - &pyodide_dir.join("pyodide.mjs"), - r#" -export async function loadPyodide() { - return { - setStdin(_stdin) {}, - async runPythonAsync(_code) { - await new Promise(() => { - setInterval(() => {}, 1_000); - }); - }, - }; -} -"#, - ); - write_fixture( - &pyodide_dir.join("pyodide-lock.json"), - "{\"packages\":[]}\n", - ); - write_fixture(&pyodide_dir.join("python_stdlib.zip"), ""); - write_fixture(&pyodide_dir.join("pyodide.asm.js"), ""); - write_fixture(&pyodide_dir.join("pyodide.asm.wasm"), ""); - - let context = sidecar - .python_engine - .create_context(CreatePythonContextRequest { - vm_id: vm_id.clone(), - pyodide_dist_path: pyodide_dir, - }); - let execution = sidecar - .python_engine - .start_execution(StartPythonExecutionRequest { - guest_runtime: Default::default(), - limits: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - code: String::from("print('hold-open')"), - file_path: None, - env: BTreeMap::new(), - cwd: cwd.clone(), - }) - .expect("start fake python execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("python vm"); - vm.kernel - .spawn_process( - PYTHON_COMMAND, - vec![String::from("print('hold-open')")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel python process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("python vm"); - vm.active_processes.insert( - String::from("proc-python-vfs"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::Python, - ActiveExecution::Python(execution), - ), - ); - } - - for _ in 0..16 { - let event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("python vm"); - let process = vm - .active_processes - .get_mut("proc-python-vfs") - .expect("python process should be tracked"); - process - .execution - .poll_event_blocking(Duration::from_millis(100)) - .expect("poll python bootstrap event") - }; - let Some(event) = event else { - break; - }; - if let ActiveExecutionEvent::Exited(code) = &event { - panic!("python bootstrap exited unexpectedly with status {code}"); - } - sidecar - .handle_execution_event(&vm_id, "proc-python-vfs", event) - .expect("handle python bootstrap event"); - } - - allow_synthetic_python_vfs_reply_drop( - sidecar.handle_python_vfs_rpc_request( - &vm_id, - "proc-python-vfs", - PythonVfsRpcRequest { - id: 1, - method: PythonVfsRpcMethod::Mkdir, - path: String::from("/workspace"), - destination: None, - target: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - content_base64: None, - recursive: false, - url: None, - http_method: None, - headers: BTreeMap::new(), - body_base64: None, - hostname: None, - family: None, - port: None, - socket_id: None, - command: None, - args: Vec::new(), - cwd: None, - env: BTreeMap::new(), - shell: false, - max_buffer: None, - }, - ), - "handle python mkdir rpc", - ); - allow_synthetic_python_vfs_reply_drop( - sidecar.handle_python_vfs_rpc_request( - &vm_id, - "proc-python-vfs", - PythonVfsRpcRequest { - id: 2, - method: PythonVfsRpcMethod::Write, - path: String::from("/workspace/note.txt"), - destination: None, - target: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - content_base64: Some(String::from("aGVsbG8gZnJvbSBzaWRlY2FyIHJwYw==")), - recursive: false, - url: None, - http_method: None, - headers: BTreeMap::new(), - body_base64: None, - hostname: None, - family: None, - port: None, - socket_id: None, - command: None, - args: Vec::new(), - cwd: None, - env: BTreeMap::new(), - shell: false, - max_buffer: None, - }, - ), - "handle python write rpc", - ); - - let content = { - let vm = sidecar.vms.get_mut(&vm_id).expect("python vm"); - String::from_utf8( - vm.kernel - .read_file("/workspace/note.txt") - .expect("read bridged file from kernel"), - ) - .expect("utf8 file contents") - }; - assert_eq!(content, "hello from sidecar rpc"); - - let process = { - let vm = sidecar.vms.get_mut(&vm_id).expect("python vm"); - vm.active_processes - .remove("proc-python-vfs") - .expect("remove fake python process") - }; - cleanup_fake_runtime_process(process); - } - fn javascript_sync_rpc_requests_proxy_into_the_vm_kernel_filesystem() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-sync-rpc-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import fs from "node:fs"; - -fs.writeFileSync("/rpc/note.txt", "hello from sidecar rpc"); -fs.mkdirSync("/rpc/subdir", { recursive: true }); -fs.symlinkSync("/rpc/note.txt", "/rpc/link.txt"); -const linkTarget = fs.readlinkSync("/rpc/link.txt"); -const existsBefore = fs.existsSync("/rpc/note.txt"); -const lstat = fs.lstatSync("/rpc/link.txt"); -fs.linkSync("/rpc/note.txt", "/rpc/hard.txt"); -fs.renameSync("/rpc/hard.txt", "/rpc/renamed.txt"); -const contents = fs.readFileSync("/rpc/renamed.txt", "utf8"); -fs.unlinkSync("/rpc/renamed.txt"); -fs.rmdirSync("/rpc/subdir"); -console.log(JSON.stringify({ existsBefore, linkTarget, linkIsSymlink: lstat.isSymbolicLink(), contents })); -await new Promise(() => {}); -"#, - ); - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_NODE_SYNC_RPC_ENABLE"), - String::from("1"), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-sync"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.clone()), - ); - } - - let mut saw_stdout = false; - for _ in 0..16 { - let event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-sync") - .expect("javascript process should be tracked"); - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll javascript sync rpc event") - .expect("javascript sync rpc event") - }; - - if let ActiveExecutionEvent::Stdout(chunk) = &event { - let stdout = String::from_utf8(chunk.clone()).expect("stdout utf8"); - if stdout.contains("\"contents\":\"hello from sidecar rpc\"") - && stdout.contains("\"existsBefore\":true") - && stdout.contains("\"linkTarget\":\"/rpc/note.txt\"") - && stdout.contains("\"linkIsSymlink\":true") - { - saw_stdout = true; - break; - } - } - - sidecar - .handle_execution_event(&vm_id, "proc-js-sync", event) - .expect("handle javascript sync rpc event"); - } - - let content = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - String::from_utf8( - vm.kernel - .read_file("/rpc/note.txt") - .expect("read bridged file from kernel"), - ) - .expect("utf8 file contents") - }; - assert_eq!(content, "hello from sidecar rpc"); - let link_target = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .read_link("/rpc/link.txt") - .expect("read bridged symlink") - }; - assert_eq!(link_target, "/rpc/note.txt"); - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - assert!( - !vm.kernel - .exists("/rpc/renamed.txt") - .expect("renamed file should be gone"), - "expected renamed file to be removed", - ); - assert!( - !vm.kernel - .exists("/rpc/subdir") - .expect("subdir should be gone"), - "expected subdir to be removed", - ); - } - assert!(saw_stdout, "expected guest stdout after sync fs round-trip"); - - let process = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes - .remove("proc-js-sync") - .expect("remove fake javascript process") - }; - cleanup_fake_runtime_process(process); - } - - fn javascript_fs_promises_hot_metadata_ops_use_sync_semantics() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let mut next_request_id = 4; - - let (stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-promises-hot-metadata", - r#" -(async () => { - const fs = require("node:fs"); - const fsp = fs.promises; - const root = "/tmp/promises-hot-metadata"; - const file = `${root}/file.txt`; - const link = `${root}/link.txt`; - - const errorCode = async (fn) => { - try { - await fn(); - return "OK"; - } catch (error) { - return error.code; - } - }; - - await fsp.mkdir(root, { recursive: true }); - await fsp.writeFile(file, "hello"); - fs.symlinkSync("file.txt", link); - - const fileStat = await fsp.stat(file); - const dirStat = await fsp.stat(root); - const fileLstat = await fsp.lstat(file); - const dirLstat = await fsp.lstat(root); - const statMissing = await errorCode(() => fsp.stat(`${root}/missing.txt`)); - const lstatMissing = await errorCode(() => fsp.lstat(`${root}/missing.txt`)); - - await fsp.writeFile(`${root}/rename-from.txt`, "move"); - await fsp.rename(`${root}/rename-from.txt`, `${root}/rename-to.txt`); - const renamedText = await fsp.readFile(`${root}/rename-to.txt`, "utf8"); - await fsp.unlink(`${root}/rename-to.txt`); - const unlinkedMissing = await errorCode(() => fsp.stat(`${root}/rename-to.txt`)); - - await fsp.mkdir(`${root}/nested/leaf`, { recursive: true }); - const mkdirExisting = await errorCode(() => fsp.mkdir(`${root}/nested/leaf`)); - await fsp.rmdir(`${root}/nested/leaf`); - const rmdirMissing = await errorCode(() => fsp.rmdir(`${root}/nested/leaf`)); - const accessMissing = await errorCode(() => fsp.access(`${root}/missing.txt`)); - - await fsp.chmod(file, 0o600); - const chmodStat = await fsp.stat(file); - const stamp = new Date("2024-01-02T03:04:05.000Z"); - await fsp.utimes(file, stamp, stamp); - const utimesStat = await fsp.stat(file); - - const linkTarget = await fsp.readlink(link); - const realpath = await fsp.realpath(link); - - process.stdout.write(`${JSON.stringify({ - fileIsFile: fileStat.isFile(), - dirIsDirectory: dirStat.isDirectory(), - fileLstatIsFile: fileLstat.isFile(), - dirLstatIsDirectory: dirLstat.isDirectory(), - statMissing, - lstatMissing, - renamedText, - unlinkedMissing, - mkdirExisting, - rmdirMissing, - accessMissing, - chmodMode: chmodStat.mode & 0o777, - utimesMtimeMs: Math.round(utimesStat.mtimeMs), - linkTarget, - realpath, - })}\n`); -})().catch((error) => { - console.error(error && error.stack ? error.stack : String(error)); - process.exitCode = 1; -}); -"#, - ); - - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!(payload["fileIsFile"], json!(true), "stdout: {stdout}"); - assert_eq!(payload["dirIsDirectory"], json!(true), "stdout: {stdout}"); - assert_eq!(payload["fileLstatIsFile"], json!(true), "stdout: {stdout}"); - assert_eq!( - payload["dirLstatIsDirectory"], - json!(true), - "stdout: {stdout}" - ); - assert_eq!(payload["statMissing"], json!("ENOENT"), "stdout: {stdout}"); - assert_eq!(payload["lstatMissing"], json!("ENOENT"), "stdout: {stdout}"); - assert_eq!(payload["renamedText"], json!("move"), "stdout: {stdout}"); - assert_eq!( - payload["unlinkedMissing"], - json!("ENOENT"), - "stdout: {stdout}" - ); - assert_eq!( - payload["mkdirExisting"], - json!("EEXIST"), - "stdout: {stdout}" - ); - assert_eq!(payload["rmdirMissing"], json!("ENOENT"), "stdout: {stdout}"); - assert_eq!( - payload["accessMissing"], - json!("ENOENT"), - "stdout: {stdout}" - ); - assert_eq!(payload["chmodMode"], json!(0o600), "stdout: {stdout}"); - assert_eq!( - payload["utimesMtimeMs"], - json!(1704164645000i64), - "stdout: {stdout}" - ); - assert_eq!(payload["linkTarget"], json!("file.txt"), "stdout: {stdout}"); - assert_eq!( - payload["realpath"], - json!("/tmp/promises-hot-metadata/file.txt"), - "stdout: {stdout}" - ); - } - - fn python_vfs_rpc_paths_resolve_textually_and_defer_to_kernel_confinement() { - // Root is `/`: any absolute guest path is addressable and textual - // `.`/`..` segments are resolved here; confinement is enforced at the - // kernel/mount layer (openat2 RESOLVE_BENEATH), not by a prefix check. - assert_eq!( - crate::filesystem::normalize_python_vfs_rpc_path("/workspace/./note.txt") - .expect("normalize workspace path"), - String::from("/workspace/note.txt") - ); - assert_eq!( - crate::filesystem::normalize_python_vfs_rpc_path("/workspace/../etc/passwd") - .expect("normalize resolves .. textually"), - String::from("/etc/passwd") - ); - assert_eq!( - crate::filesystem::normalize_python_vfs_rpc_path("/etc/passwd") - .expect("absolute guest paths are addressable"), - String::from("/etc/passwd") - ); - assert!( - crate::filesystem::normalize_python_vfs_rpc_path("workspace/note.txt").is_err(), - "relative paths must be rejected", - ); - } - fn javascript_fs_sync_rpc_resolves_proc_self_against_the_kernel_process() { - let mut config = KernelVmConfig::new("vm-js-procfs-rpc"); - config.permissions = Permissions::allow_all(); - let mut kernel = SidecarKernel::new(MountTable::new(MemoryFileSystem::new()), config); - kernel - .register_driver(CommandDriver::new( - EXECUTION_DRIVER_NAME, - [JAVASCRIPT_COMMAND], - )) - .expect("register execution driver"); - - let kernel_handle = kernel - .spawn_process( - JAVASCRIPT_COMMAND, - Vec::new(), - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - ..SpawnOptions::default() - }, - ) - .expect("spawn javascript kernel process"); - let kernel_pid = kernel_handle.pid(); - let mut process = ActiveProcess::new( - kernel_pid, - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Tool(ToolExecution::default()), - ); - - let link = service_javascript_fs_sync_rpc( - &mut kernel, - &mut process, - kernel_pid, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("fs.readlinkSync"), - args: vec![json!("/proc/self")], - }, - ) - .expect("resolve /proc/self"); - assert_eq!(link, Value::String(format!("/proc/{kernel_pid}"))); - - let entries = service_javascript_fs_sync_rpc( - &mut kernel, - &mut process, - kernel_pid, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("fs.readdirSync"), - args: vec![json!("/proc/self/fd")], - }, - ) - .expect("read /proc/self/fd"); - let entry_names = entries - .as_array() - .expect("readdir should return an array") - .iter() - .filter_map(|entry| { - // Raw sidecar readdir RPCs may return typed entries so the JS - // bridge can implement `withFileTypes` without per-entry stat - // RPCs; plain guest `readdirSync()` normalizes these to names. - entry - .as_str() - .or_else(|| entry.get("name").and_then(Value::as_str)) - }) - .collect::>(); - assert!(entry_names.contains(&"0")); - assert!(entry_names.contains(&"1")); - assert!(entry_names.contains(&"2")); - - process.kernel_handle.finish(0); - kernel.waitpid(kernel_pid).expect("wait javascript process"); - } - fn javascript_fd_and_stream_rpc_requests_proxy_into_the_vm_kernel_filesystem() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .write_file("/rpc/input.txt", b"abcdefg") - .expect("seed input file"); - } - let cwd = temp_dir("secure-exec-sidecar-js-fd-rpc-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import fs from "node:fs"; -import { once } from "node:events"; - -const inFd = fs.openSync("/rpc/input.txt", "r"); -const buffer = Buffer.alloc(5); -const bytesRead = fs.readSync(inFd, buffer, 0, buffer.length, 1); -const stat = fs.fstatSync(inFd); -fs.closeSync(inFd); - -const defaultUmask = process.umask(); -const previousUmask = process.umask(0o027); -const outFd = fs.openSync("/rpc/output.txt", "w", 0o666); -const written = fs.writeSync(outFd, Buffer.from("kernel"), 0, 6, 0); -fs.closeSync(outFd); -fs.mkdirSync("/rpc/private", { mode: 0o777 }); -const outputStat = fs.statSync("/rpc/output.txt"); -const privateDirStat = fs.statSync("/rpc/private"); - -const asyncSummary = await new Promise((resolve, reject) => { - fs.open("/rpc/input.txt", "r", (openError, asyncFd) => { - if (openError) { - reject(openError); - return; - } - - const target = Buffer.alloc(5); - fs.read(asyncFd, target, 0, 5, 0, (readError, asyncBytesRead) => { - if (readError) { - reject(readError); - return; - } - - fs.fstat(asyncFd, (statError, asyncStat) => { - if (statError) { - reject(statError); - return; - } - - fs.close(asyncFd, (closeError) => { - if (closeError) { - reject(closeError); - return; - } - - resolve({ - asyncBytesRead, - asyncText: target.toString("utf8"), - asyncSize: asyncStat.size, - }); - }); - }); - }); - }); -}); - -const reader = fs.createReadStream("/rpc/input.txt", { - encoding: "utf8", - start: 0, - end: 4, - highWaterMark: 3, -}); -const streamChunks = []; -reader.on("data", (chunk) => streamChunks.push(chunk)); -await once(reader, "close"); - -const writer = fs.createWriteStream("/rpc/stream.txt", { start: 0 }); -writer.write("ab"); -writer.end("cd"); -await once(writer, "close"); - -let watchCode = ""; -let watchFileCode = ""; -let watchSupported = false; -let watchFileSupported = false; -try { - const watcher = fs.watch("/rpc/input.txt"); - watchSupported = typeof watcher.close === "function"; - watcher.close(); -} catch (error) { - watchCode = error.code; -} -try { - const watchFileListener = () => {}; - fs.watchFile("/rpc/input.txt", watchFileListener); - watchFileSupported = true; - fs.unwatchFile("/rpc/input.txt", watchFileListener); -} catch (error) { - watchFileCode = error.code; -} - -console.log( - JSON.stringify({ - text: buffer.toString("utf8"), - bytesRead, - size: stat.size, - blocks: stat.blocks, - dev: stat.dev, - rdev: stat.rdev, - written, - defaultUmask, - previousUmask, - outputMode: outputStat.mode & 0o777, - privateDirMode: privateDirStat.mode & 0o777, - asyncSummary, - streamChunks, - watchSupported, - watchFileSupported, - watchCode, - watchFileCode, - }), -); -"#, - ); - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from( - "[\"assert\",\"buffer\",\"child_process\",\"console\",\"crypto\",\"events\",\"fs\",\"path\",\"querystring\",\"stream\",\"string_decoder\",\"timers\",\"url\",\"util\",\"zlib\"]", - ), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-fd"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.clone()), - ); - } - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - for _ in 0..64 { - let next_event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes - .get_mut("proc-js-fd") - .and_then(|process| { - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll javascript fd rpc event") - }) - }; - let Some(event) = next_event else { - if exit_code.is_some() { - break; - } - panic!("javascript fd process disappeared before exit"); - }; - - match &event { - ActiveExecutionEvent::Stdout(chunk) => { - append_process_stream_chunk(&mut stdout, chunk, "proc-js-fd", "stdout"); - } - ActiveExecutionEvent::Stderr(chunk) => { - append_process_stream_chunk(&mut stderr, chunk, "proc-js-fd", "stderr"); - } - ActiveExecutionEvent::Exited(code) => { - exit_code = Some(*code); - } - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } => {} - } - - sidecar - .handle_execution_event(&vm_id, "proc-js-fd", event) - .expect("handle javascript fd rpc event"); - } - - let stdout = process_stream_to_string(&stdout); - let stderr = process_stream_to_string(&stderr); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let stdout_json: Value = serde_json::from_str(stdout.trim()).expect("stdout json"); - assert!(stdout.contains("\"text\":\"bcdef\""), "stdout: {stdout}"); - assert!(stdout.contains("\"bytesRead\":5"), "stdout: {stdout}"); - assert!(stdout.contains("\"size\":7"), "stdout: {stdout}"); - assert!(stdout.contains("\"blocks\":1"), "stdout: {stdout}"); - assert!( - stdout_json - .get("dev") - .and_then(Value::as_u64) - .is_some_and(|dev| dev != 0), - "stdout: {stdout}" - ); - assert!(stdout.contains("\"rdev\":0"), "stdout: {stdout}"); - assert!(stdout.contains("\"written\":6"), "stdout: {stdout}"); - assert!(stdout.contains("\"defaultUmask\":18"), "stdout: {stdout}"); - assert!(stdout.contains("\"previousUmask\":18"), "stdout: {stdout}"); - assert!(stdout.contains("\"outputMode\":416"), "stdout: {stdout}"); - assert!( - stdout.contains("\"privateDirMode\":488"), - "stdout: {stdout}" - ); - assert!( - stdout.contains("\"asyncText\":\"abcde\""), - "stdout: {stdout}" - ); - assert!(stdout.contains("\"asyncSize\":7"), "stdout: {stdout}"); - assert!( - stdout.contains("\"streamChunks\":[\"abc\",\"de\"]"), - "stdout: {stdout}" - ); - assert!( - stdout.contains("\"watchSupported\":true"), - "stdout: {stdout}" - ); - assert!( - stdout.contains("\"watchFileSupported\":true"), - "stdout: {stdout}" - ); - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let output = String::from_utf8( - vm.kernel - .read_file("/rpc/output.txt") - .expect("read fd output file"), - ) - .expect("utf8 output contents"); - assert_eq!(output, "kernel"); - - let stream = String::from_utf8( - vm.kernel - .read_file("/rpc/stream.txt") - .expect("read stream output file"), - ) - .expect("utf8 stream contents"); - assert_eq!(stream, "abcd"); - } - } - - fn javascript_mapped_tmp_open_wx_uses_exclusive_create_once() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-open-wx-cwd"); - let mapped_tmp = temp_dir("secure-exec-sidecar-js-open-wx-mapped-tmp"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import fs from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -const target = path.join(os.tmpdir(), "exclusive-mapped.lock"); -try { - fs.unlinkSync(target); -} catch {} - -const fd = fs.openSync(target, "wx", 0o600); -fs.writeSync(fd, "lock"); -fs.closeSync(fd); - -let secondOpenCode = ""; -try { - fs.openSync(target, "wx", 0o600); - secondOpenCode = "opened"; -} catch (error) { - secondOpenCode = error.code; -} - -console.log( - JSON.stringify({ - tmpdir: os.tmpdir(), - text: fs.readFileSync(target, "utf8"), - secondOpenCode, - exists: fs.existsSync(target), - }), -); -"#, - ); - - let mapped_tmp_json = serde_json::to_string(&vec![mapped_tmp.display().to_string()]) - .expect("serialize mapped tmp access roots"); - let (stdout, stderr, exit_code) = run_javascript_entry_with_env( - &mut sidecar, - &vm_id, - &cwd, - "proc-js-open-wx", - BTreeMap::from([ - ( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from("[\"buffer\",\"console\",\"fs\",\"os\",\"path\"]"), - ), - ( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - serde_json::to_string(&vec![json!({ - "guestPath": "/tmp", - "hostPath": mapped_tmp.display().to_string(), - })]) - .expect("serialize mapped tmp path"), - ), - ( - String::from("AGENTOS_EXTRA_FS_READ_PATHS"), - mapped_tmp_json.clone(), - ), - ( - String::from("AGENTOS_EXTRA_FS_WRITE_PATHS"), - mapped_tmp_json, - ), - ]), - ); - - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - assert!(stdout.contains("\"text\":\"lock\""), "stdout: {stdout}"); - assert!( - stdout.contains("\"secondOpenCode\":\"EEXIST\""), - "stdout: {stdout}" - ); - assert!(stdout.contains("\"exists\":true"), "stdout: {stdout}"); - assert_eq!( - fs::read_to_string(mapped_tmp.join("exclusive-mapped.lock")) - .expect("read mapped host lock file"), - "lock" - ); - } - - fn with_wasm_shell_redirect_vm( - test: impl FnOnce( - &mut NativeSidecar, - &str, - &str, - &str, - &mut secure_exec_sidecar::protocol::RequestId, - ), - ) { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let mut next_request_id = 4; - configure_registry_command_mount( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - next_request_id, - ); - next_request_id += 1; - - test( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - ); - } - - fn wasm_shell_external_stdout_redirect_writes_file() { - with_wasm_shell_redirect_vm( - |sidecar, vm_id, connection_id, session_id, next_request_id| { - let (_stdout, stderr, exit_code) = run_guest_command( - sidecar, - vm_id, - connection_id, - session_id, - next_request_id, - "proc-wasm-redirect-stdout", - "sh", - &[ - "-c", - "mkdir -p /tmp/rp && printf 'aaaaaaaaaa' > /tmp/rp/printf.txt", - ], - BTreeMap::new(), - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - - let (stdout, stderr, exit_code) = run_guest_node_eval( - sidecar, - vm_id, - connection_id, - session_id, - next_request_id, - "proc-js-read-redirect-stdout", - r#" -const fs = require("node:fs"); -const path = "/tmp/rp/printf.txt"; -process.stdout.write(`${JSON.stringify({ - text: fs.readFileSync(path, "utf8"), - size: fs.statSync(path).size, -})}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!(payload["text"], json!("aaaaaaaaaa"), "stdout: {stdout}"); - assert_eq!(payload["size"], json!(10), "stdout: {stdout}"); - }, - ); - } - - fn wasm_shell_external_append_redirect_creates_and_concatenates() { - with_wasm_shell_redirect_vm( - |sidecar, vm_id, connection_id, session_id, next_request_id| { - let (_stdout, stderr, exit_code) = run_guest_command( - sidecar, - vm_id, - connection_id, - session_id, - next_request_id, - "proc-wasm-redirect-append", - "sh", - &[ - "-c", - "mkdir -p /tmp/rp && printf 'abc' >> /tmp/rp/append.txt && printf 'xyz' >> /tmp/rp/append.txt", - ], - BTreeMap::new(), - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - - let (stdout, stderr, exit_code) = run_guest_node_eval( - sidecar, - vm_id, - connection_id, - session_id, - next_request_id, - "proc-js-read-redirect-append", - r#" -const fs = require("node:fs"); -const path = "/tmp/rp/append.txt"; -process.stdout.write(`${JSON.stringify({ - text: fs.readFileSync(path, "utf8"), - size: fs.statSync(path).size, -})}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!(payload["text"], json!("abcxyz"), "stdout: {stdout}"); - assert_eq!(payload["size"], json!(6), "stdout: {stdout}"); - }, - ); - } - - fn wasm_shell_external_stderr_redirect_writes_file() { - with_wasm_shell_redirect_vm( - |sidecar, vm_id, connection_id, session_id, next_request_id| { - let (_stdout, stderr, exit_code) = run_guest_command( - sidecar, - vm_id, - connection_id, - session_id, - next_request_id, - "proc-wasm-redirect-stderr", - "sh", - &[ - "-c", - "mkdir -p /tmp/rp && cat /tmp/rp/does-not-exist 2> /tmp/rp/stderr.txt || true", - ], - BTreeMap::new(), - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - - let (stdout, stderr, exit_code) = run_guest_node_eval( - sidecar, - vm_id, - connection_id, - session_id, - next_request_id, - "proc-js-read-redirect-stderr", - r#" -const fs = require("node:fs"); -const path = "/tmp/rp/stderr.txt"; -const text = fs.readFileSync(path, "utf8"); -process.stdout.write(`${JSON.stringify({ - text, - size: fs.statSync(path).size, -})}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert!( - payload["text"] - .as_str() - .is_some_and(|text| text.contains("does-not-exist")), - "stdout: {stdout}" - ); - assert!( - payload["size"].as_u64().is_some_and(|size| size > 0), - "stdout: {stdout}" - ); - }, - ); - } - - fn wasm_shell_builtin_and_external_redirects_match() { - with_wasm_shell_redirect_vm( - |sidecar, vm_id, connection_id, session_id, next_request_id| { - let (_stdout, stderr, exit_code) = run_guest_command( - sidecar, - vm_id, - connection_id, - session_id, - next_request_id, - "proc-wasm-redirect-parity", - "sh", - &[ - "-c", - "mkdir -p /tmp/rp && echo hi > /tmp/rp/builtin.txt && printf 'hi\n' > /tmp/rp/external.txt", - ], - BTreeMap::new(), - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - - let (stdout, stderr, exit_code) = run_guest_node_eval( - sidecar, - vm_id, - connection_id, - session_id, - next_request_id, - "proc-js-read-redirect-parity", - r#" -const fs = require("node:fs"); -process.stdout.write(`${JSON.stringify({ - builtin: fs.readFileSync("/tmp/rp/builtin.txt", "utf8"), - external: fs.readFileSync("/tmp/rp/external.txt", "utf8"), -})}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!(payload["builtin"], json!("hi\n"), "stdout: {stdout}"); - assert_eq!(payload["external"], json!("hi\n"), "stdout: {stdout}"); - }, - ); - } - - fn javascript_mapped_shadow_readdir_sees_wasm_created_directory() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let mut next_request_id = 4; - configure_registry_command_mount( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - next_request_id, - ); - next_request_id += 1; - - let (_stdout, stderr, exit_code) = run_guest_command( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-wasm-mkdir-x", - "mkdir", - &["/tmp/x"], - BTreeMap::new(), - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - - let client_entries = sidecar - .vms - .get_mut(&vm_id) - .expect("vm") - .kernel - .read_dir("/tmp") - .expect("client readdir /tmp"); - assert!( - client_entries.iter().any(|entry| entry == "x"), - "kernel /tmp entries should include x: {client_entries:?}" - ); - - let (stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-read-x", - r#" -const fs = require("node:fs"); -const entries = fs.readdirSync("/tmp/x"); -const isDirectory = fs.statSync("/tmp/x").isDirectory(); -process.stdout.write(`${JSON.stringify({ entries, isDirectory })}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!(payload["entries"], json!([]), "stdout: {stdout}"); - assert_eq!(payload["isDirectory"], json!(true), "stdout: {stdout}"); - } - - fn javascript_mapped_shadow_readdir_merges_wasm_created_children() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let mut next_request_id = 4; - configure_registry_command_mount( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - next_request_id, - ); - next_request_id += 1; - - let (_stdout, stderr, exit_code) = run_guest_command( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-wasm-write-y", - "sh", - &["-c", "mkdir -p /tmp/y && echo hi > /tmp/y/f.txt"], - BTreeMap::new(), - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - - let (stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-read-y", - r#" -const fs = require("node:fs"); -const entries = fs.readdirSync("/tmp/y").sort(); -const text = fs.readFileSync("/tmp/y/f.txt", "utf8"); -process.stdout.write(`${JSON.stringify({ entries, text })}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!(payload["entries"], json!(["f.txt"]), "stdout: {stdout}"); - assert_eq!(payload["text"], json!("hi\n"), "stdout: {stdout}"); - } - - fn javascript_mapped_shadow_readdir_unions_shadow_and_kernel_children() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let mut next_request_id = 4; - - let (_stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-write-z-a", - r#" -const fs = require("node:fs"); -fs.mkdirSync("/tmp/z", { recursive: true }); -fs.writeFileSync("/tmp/z/a.txt", "a\n"); -"#, - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .mkdir("/tmp/z", true) - .expect("create kernel merge dir"); - vm.kernel - .write_file("/tmp/z/b.txt", b"x\n".to_vec()) - .expect("create kernel merge child"); - } - - let (stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-read-z", - r#" -const fs = require("node:fs"); -const entries = fs.readdirSync("/tmp/z").sort(); -process.stdout.write(`${JSON.stringify({ entries })}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!( - payload["entries"], - json!(["a.txt", "b.txt"]), - "stdout: {stdout}" - ); - } - - // A kernel-backed file (created by a wasm command) unlinked from JS must - // stay deleted in the SAME process's merged readdir view and for later - // processes — the mapped unlink now mirrors the removal into the kernel, - // otherwise the readdir kernel-merge would resurrect it. - fn javascript_mapped_unlink_of_kernel_backed_file_does_not_resurrect() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let mut next_request_id = 4; - configure_registry_command_mount( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - next_request_id, - ); - next_request_id += 1; - - let (_stdout, stderr, exit_code) = run_guest_command( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-wasm-write-w", - "sh", - &["-c", "mkdir -p /tmp/w && echo hi > /tmp/w/gone.txt"], - BTreeMap::new(), - ); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - - let (stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-unlink-w", - r#" -const fs = require("node:fs"); -fs.unlinkSync("/tmp/w/gone.txt"); -const entries = fs.readdirSync("/tmp/w").sort(); -process.stdout.write(`${JSON.stringify({ entries })}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!(payload["entries"], json!([]), "stdout: {stdout}"); - - let (stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-recheck-w", - r#" -const fs = require("node:fs"); -const entries = fs.readdirSync("/tmp/w").sort(); -process.stdout.write(`${JSON.stringify({ entries })}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!(payload["entries"], json!([]), "stdout: {stdout}"); - } - - fn javascript_mapped_shadow_readdir_sees_same_process_shadow_directory() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let mut next_request_id = 4; - - let (stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-readdir-own-shadow-dir", - r#" -const fs = require("node:fs"); -const dir = "/tmp/fuzz-perf-readdir-32"; -if (!fs.existsSync(dir)) fs.mkdirSync(dir); -for (let i = 0; i < 3; i++) { - const path = `${dir}/${i}.txt`; - if (!fs.existsSync(path)) fs.writeFileSync(path, "hi"); -} -const entries = fs.readdirSync(dir).sort(); -process.stdout.write(`${JSON.stringify({ entries })}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!( - payload["entries"], - json!(["0.txt", "1.txt", "2.txt"]), - "stdout: {stdout}" - ); - } - - fn javascript_readdir_raw_payload_preserves_dirent_semantics() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let mut next_request_id = 4; - - let (_stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-seed-readdir-raw", - r#" -const fs = require("node:fs"); -const dir = "/tmp/readdir-raw-dirents"; -fs.mkdirSync(dir, { recursive: true }); -fs.mkdirSync(`${dir}/dir`); -fs.mkdirSync(`${dir}/empty`); -fs.writeFileSync(`${dir}/file.txt`, "file"); -fs.symlinkSync("dir", `${dir}/link-dir`); -fs.symlinkSync("file.txt", `${dir}/link-file`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {_stdout}\nstderr: {stderr}"); - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .mkdir("/tmp/readdir-raw-dirents", true) - .expect("create kernel merge dir"); - vm.kernel - .write_file("/tmp/readdir-raw-dirents/kernel.txt", b"kernel\n".to_vec()) - .expect("create kernel merge child"); - } - - let (stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-read-readdir-raw", - r#" -const fs = require("node:fs"); -const dir = "/tmp/readdir-raw-dirents"; -const typed = fs.readdirSync(dir, { withFileTypes: true }) - .map((entry) => ({ - name: entry.name, - isDirectory: entry.isDirectory(), - parentPath: entry.parentPath, - path: entry.path, - })) - .sort((a, b) => a.name.localeCompare(b.name)); -const plain = fs.readdirSync(dir).sort(); -const empty = fs.readdirSync(`${dir}/empty`); -process.stdout.write(`${JSON.stringify({ plain, typed, empty })}\n`); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!( - payload["plain"], - json!([ - "dir", - "empty", - "file.txt", - "kernel.txt", - "link-dir", - "link-file" - ]), - "stdout: {stdout}" - ); - assert_eq!(payload["empty"], json!([]), "stdout: {stdout}"); - let typed = payload["typed"].as_array().expect("typed entries"); - let by_name = |name: &str| { - typed - .iter() - .find(|entry| entry["name"] == json!(name)) - .unwrap_or_else(|| panic!("missing dirent {name}: {typed:?}")) - }; - assert_eq!(by_name("dir")["isDirectory"], json!(true)); - assert_eq!(by_name("empty")["isDirectory"], json!(true)); - assert_eq!(by_name("file.txt")["isDirectory"], json!(false)); - assert_eq!(by_name("kernel.txt")["isDirectory"], json!(false)); - assert_eq!(by_name("link-dir")["isDirectory"], json!(true)); - assert_eq!(by_name("link-file")["isDirectory"], json!(false)); - for entry in typed { - assert_eq!( - entry["parentPath"], - json!("/tmp/readdir-raw-dirents"), - "stdout: {stdout}" - ); - assert_eq!( - entry["path"], - json!("/tmp/readdir-raw-dirents"), - "stdout: {stdout}" - ); - } - } - - fn javascript_writev_raw_payload_preserves_stream_copy_order() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let mut next_request_id = 4; - - let (stdout, stderr, exit_code) = run_guest_node_eval( - &mut sidecar, - &vm_id, - &connection_id, - &session_id, - &mut next_request_id, - "proc-js-writev-stream-copy", - r#" -(async () => { - const fs = require("node:fs"); - const chunkSize = 16 * 1024; - const chunkCount = 64; - const chunks = []; - for (let i = 0; i < chunkCount; i++) { - chunks.push(Buffer.alloc(chunkSize, i)); - } - fs.writeFileSync("/tmp/writev-source.bin", Buffer.concat(chunks)); - - await new Promise((resolve, reject) => { - const reader = fs.createReadStream("/tmp/writev-source.bin", { highWaterMark: chunkSize }); - const writer = fs.createWriteStream("/tmp/writev-dest.bin", { highWaterMark: chunkSize }); - reader.on("data", (chunk) => { - if (!writer.write(chunk)) { - reader.pause(); - writer.once("drain", () => reader.resume()); - } - }); - reader.on("error", reject); - writer.on("error", reject); - reader.on("end", () => writer.end()); - writer.on("close", resolve); - }); - - const copied = fs.readFileSync("/tmp/writev-dest.bin"); - const source = fs.readFileSync("/tmp/writev-source.bin"); - const makePattern = (size) => { - const buffer = Buffer.alloc(size); - for (let i = 0; i < buffer.length; i++) { - buffer[i] = (i * 31 + 7) & 0xff; - } - return buffer; - }; - const readStream = (path, options = {}) => new Promise((resolve, reject) => { - const chunks = []; - const sizes = []; - const reader = fs.createReadStream(path, options); - reader.on("data", (chunk) => { - chunks.push(Buffer.from(chunk)); - sizes.push(chunk.length); - }); - reader.on("error", reject); - reader.on("end", () => resolve({ buffer: Buffer.concat(chunks), sizes })); - }); - - const bigSource = makePattern(2 * 1024 * 1024 + 12345); - fs.writeFileSync("/tmp/read-ahead-big.bin", bigSource); - const bigRead = await readStream("/tmp/read-ahead-big.bin", { highWaterMark: 64 * 1024 }); - const partialTailSource = makePattern(1024 * 1024 + 17); - fs.writeFileSync("/tmp/read-ahead-tail.bin", partialTailSource); - const partialTailRead = await readStream("/tmp/read-ahead-tail.bin", { highWaterMark: 64 * 1024 }); - const rangeStart = 12345; - const rangeEnd = 234567; - const rangeRead = await readStream("/tmp/read-ahead-big.bin", { - start: rangeStart, - end: rangeEnd, - highWaterMark: 7777, - }); - const smallSource = makePattern(123); - fs.writeFileSync("/tmp/read-ahead-small.bin", smallSource); - const smallRead = await readStream("/tmp/read-ahead-small.bin", { highWaterMark: 64 * 1024 }); - const orderedFd = fs.openSync("/tmp/writev-ordered.txt", "w"); - const orderedBytes = fs.writevSync(orderedFd, [ - Buffer.from("aa"), - Buffer.from("bb"), - Buffer.from("cc"), - ]); - fs.closeSync(orderedFd); - - const closedFd = fs.openSync("/tmp/writev-closed.txt", "w"); - fs.closeSync(closedFd); - let closedCode = null; - try { - fs.writevSync(closedFd, [Buffer.from("x")]); - } catch (error) { - closedCode = error.code; - } - - process.stdout.write(`${JSON.stringify({ - equal: copied.equals(source), - size: copied.length, - first: copied[0], - last: copied[copied.length - 1], - bigEqual: bigRead.buffer.equals(bigSource), - bigSize: bigRead.buffer.length, - bigChunks: bigRead.sizes.length, - bigLastChunk: bigRead.sizes[bigRead.sizes.length - 1], - bigFullChunks: bigRead.sizes.slice(0, -1).every((size) => size === 64 * 1024), - partialTailEqual: partialTailRead.buffer.equals(partialTailSource), - partialTailLastChunk: partialTailRead.sizes[partialTailRead.sizes.length - 1], - rangeEqual: rangeRead.buffer.equals(bigSource.subarray(rangeStart, rangeEnd + 1)), - rangeSize: rangeRead.buffer.length, - rangeMaxChunk: Math.max(...rangeRead.sizes), - smallEqual: smallRead.buffer.equals(smallSource), - smallChunks: smallRead.sizes, - ordered: fs.readFileSync("/tmp/writev-ordered.txt", "utf8"), - orderedBytes, - closedCode, - })}\n`); -})().catch((error) => { - console.error(error && error.stack ? error.stack : String(error)); - process.exit(1); -}); -"#, - ); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let payload = stdout_json(&stdout); - assert_eq!(payload["equal"], json!(true), "stdout: {stdout}"); - assert_eq!(payload["size"], json!(64 * 16 * 1024), "stdout: {stdout}"); - assert_eq!(payload["first"], json!(0), "stdout: {stdout}"); - assert_eq!(payload["last"], json!(63), "stdout: {stdout}"); - assert_eq!(payload["bigEqual"], json!(true), "stdout: {stdout}"); - assert_eq!( - payload["bigSize"], - json!(2 * 1024 * 1024 + 12345), - "stdout: {stdout}" - ); - assert_eq!(payload["bigChunks"], json!(33), "stdout: {stdout}"); - assert_eq!(payload["bigLastChunk"], json!(12345), "stdout: {stdout}"); - assert_eq!(payload["bigFullChunks"], json!(true), "stdout: {stdout}"); - assert_eq!(payload["partialTailEqual"], json!(true), "stdout: {stdout}"); - assert_eq!( - payload["partialTailLastChunk"], - json!(17), - "stdout: {stdout}" - ); - assert_eq!(payload["rangeEqual"], json!(true), "stdout: {stdout}"); - assert_eq!( - payload["rangeSize"], - json!(234567 - 12345 + 1), - "stdout: {stdout}" - ); - assert_eq!(payload["rangeMaxChunk"], json!(7777), "stdout: {stdout}"); - assert_eq!(payload["smallEqual"], json!(true), "stdout: {stdout}"); - assert_eq!(payload["smallChunks"], json!([123]), "stdout: {stdout}"); - assert_eq!(payload["ordered"], json!("aabbcc"), "stdout: {stdout}"); - assert_eq!(payload["orderedBytes"], json!(6), "stdout: {stdout}"); - assert_eq!(payload["closedCode"], json!("EBADF"), "stdout: {stdout}"); - } - - fn javascript_imports_guest_written_modules_after_miss_work() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel.mkdir("/app", true).expect("create app dir"); - vm.kernel - .mkdir("/fixtures", true) - .expect("create fixtures dir"); - vm.kernel - .write_file( - "/tmp/preexisting.mjs", - b"export const value = 'preexisting';\n".to_vec(), - ) - .expect("write preexisting module"); - vm.kernel - .write_file( - "/app/main.js", - br#" -import fs from "node:fs"; - -const seen = []; -async function expectImport(label, specifier, expected) { - const mod = await import(specifier); - if (mod.value !== expected) { - throw new Error(`${label}: expected ${expected}, got ${mod.value}`); - } - seen.push(label); -} - -await expectImport("PRE_OK", "/tmp/preexisting.mjs", "preexisting"); - -fs.writeFileSync("/tmp/fresh-path.mjs", "export const value = 'fresh-path';\n"); -await expectImport("FRESH_PATH_OK", "/tmp/fresh-path.mjs", "fresh-path"); - -fs.writeFileSync("/tmp/fresh-url.mjs", "export const value = 'fresh-url';\n"); -await expectImport("FRESH_URL_OK", "file:///tmp/fresh-url.mjs", "fresh-url"); - -let missed = false; -try { - await import("/tmp/retry-after-miss.mjs"); -} catch { - missed = true; -} -if (!missed) { - throw new Error("NEG_RETRY did not miss before write"); -} -fs.writeFileSync("/tmp/retry-after-miss.mjs", "export const value = 'retry';\n"); -await expectImport("NEG_RETRY_OK", "/tmp/retry-after-miss.mjs", "retry"); - -console.log(seen.join("\n")); -"#, - ) - .expect("write entrypoint"); - } - - let response = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::Execute(crate::protocol::ExecuteRequest { - process_id: String::from("proc-js-import-fresh"), - command: Some(String::from("node")), - runtime: None, - entrypoint: None, - args: vec![String::from("/app/main.js")], - env: std::collections::HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - )) - .expect("dispatch import fresh execute"); - - match response.response.payload { - ResponsePayload::ProcessStarted(response) => { - assert_eq!(response.process_id, "proc-js-import-fresh"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (stdout, stderr, exit_code) = - drain_process_output(&mut sidecar, &vm_id, "proc-js-import-fresh"); - - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - for marker in ["PRE_OK", "FRESH_PATH_OK", "FRESH_URL_OK", "NEG_RETRY_OK"] { - assert!( - stdout.contains(marker), - "missing {marker} in stdout: {stdout}" - ); - } - } - - fn javascript_fs_promises_batch_requests_before_waiting_on_sidecar_responses() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-promises-rpc-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import fs from "node:fs/promises"; - -await Promise.all( - Array.from({ length: 10 }, (_, index) => - fs.writeFile(`/rpc/write-${index}.txt`, `value-${index}`) - ) -); -console.log("writes-complete"); -const contents = await Promise.all( - Array.from({ length: 10 }, (_, index) => - fs.readFile(`/rpc/write-${index}.txt`, "utf8") - ) -); -console.log(JSON.stringify(contents)); -await new Promise(() => {}); -"#, - ); - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from( - "[\"assert\",\"buffer\",\"console\",\"child_process\",\"crypto\",\"events\",\"fs\",\"path\",\"querystring\",\"stream\",\"string_decoder\",\"timers\",\"url\",\"util\",\"zlib\"]", - ), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - // ActiveProcess::new defaults host_cwd to "/", which would - // identity-map the whole host filesystem for this process; - // real execute paths always set it, so mirror that here. - let mut process = ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ); - process.host_cwd = cwd.clone(); - vm.active_processes - .insert(String::from("proc-js-promises"), process); - } - - let mut saw_write_batch = false; - let mut saw_read_batch = false; - let mut saw_stdout = false; - let mut held_exit = None; - let mut pending_requests = Vec::new(); - - for _ in 0..40 { - let event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-promises") - .expect("javascript process should be tracked"); - match process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll javascript promises event") - { - Some(event) => event, - // Stream end: exit observed and trailing output done. - None => break, - } - }; - - match event { - ActiveExecutionEvent::JavascriptSyncRpcRequest(request) => { - if !request.method.starts_with("fs.promises.") { - sidecar - .handle_execution_event( - &vm_id, - "proc-js-promises", - ActiveExecutionEvent::JavascriptSyncRpcRequest(request), - ) - .expect("handle javascript promises setup rpc event"); - continue; - } - - pending_requests.push(request); - - let expected_method = if !saw_write_batch { - "fs.promises.writeFile" - } else if !saw_read_batch { - "fs.promises.readFile" - } else { - panic!("received unexpected extra fs.promises request batch"); - }; - - if pending_requests.len() == 10 { - assert!( - pending_requests - .iter() - .all(|request| request.method == expected_method), - "expected batched {expected_method} requests, got {:?}", - pending_requests - .iter() - .map(|request| request.method.as_str()) - .collect::>() - ); - - for request in pending_requests.drain(..) { - sidecar - .handle_execution_event( - &vm_id, - "proc-js-promises", - ActiveExecutionEvent::JavascriptSyncRpcRequest(request), - ) - .expect("handle batched javascript promises rpc event"); - } - - if !saw_write_batch { - saw_write_batch = true; - } else { - saw_read_batch = true; - } - } - } - ActiveExecutionEvent::Stdout(chunk) => { - let stdout = String::from_utf8(chunk).expect("stdout utf8"); - if stdout.contains(r#"["value-0","value-1","value-2","value-3","value-4","value-5","value-6","value-7","value-8","value-9"]"#) { - saw_stdout = true; - break; - } - } - // Exit can arrive ahead of trailing stdout (event-driven - // exit); hold it (the tail removes the process itself) and - // keep polling for trailing output until the stream ends. - ActiveExecutionEvent::Exited(code) => { - held_exit = Some(code); - } - other => { - let _ = sidecar - .handle_execution_event(&vm_id, "proc-js-promises", other) - .expect("handle javascript promises side event"); - } - } - } - - let content = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - (0..10) - .map(|index| { - String::from_utf8( - vm.kernel - .read_file(&format!("/rpc/write-{index}.txt")) - .expect("read bridged file from kernel"), - ) - .expect("utf8 file contents") - }) - .collect::>() - }; - assert_eq!( - content, - (0..10) - .map(|index| format!("value-{index}")) - .collect::>() - ); - assert!( - saw_write_batch, - "expected Promise.all(writeFile) to issue a full batch before the first response" - ); - assert!( - saw_read_batch, - "expected Promise.all(readFile) to issue a full batch before the first response" - ); - assert!( - saw_stdout || held_exit == Some(0), - "expected guest stdout marker or clean exit after the concurrent fs.promises round-trip (saw_stdout={saw_stdout}, exit={held_exit:?})" - ); - - let process = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes - .remove("proc-js-promises") - .expect("remove fake javascript process") - }; - cleanup_fake_runtime_process(process); - } - #[test] - fn javascript_crypto_basic_sync_rpcs_match_shared_conformance_fixture() { - #[derive(serde::Deserialize)] - struct CryptoScryptFixture { - #[serde(rename = "N")] - n: u64, - r: u32, - p: u32, - } - - #[derive(serde::Deserialize)] - struct CryptoAesCbcFixture { - algorithm: String, - plaintext: String, - #[serde(rename = "keyHex")] - key_hex: String, - #[serde(rename = "ivHex")] - iv_hex: String, - } - - #[derive(serde::Deserialize)] - struct CryptoAesGcmFixture { - algorithm: String, - plaintext: String, - aad: String, - #[serde(rename = "keyHex")] - key_hex: String, - #[serde(rename = "ivHex")] - iv_hex: String, - #[serde(rename = "authTagLength")] - auth_tag_length: usize, - } - - #[derive(serde::Deserialize)] - struct CryptoExpectedFixture { - md5: String, - sha224: String, - sha256: String, - sha384: String, - #[serde(rename = "hmacSha256")] - hmac_sha256: String, - #[serde(rename = "hmacSha384")] - hmac_sha384: String, - #[serde(rename = "pbkdf2Sha256")] - pbkdf2_sha256: String, - #[serde(rename = "pbkdf2Sha384")] - pbkdf2_sha384: String, - scrypt: String, - #[serde(rename = "aes256CbcCiphertext")] - aes256_cbc_ciphertext: String, - #[serde(rename = "aes256GcmCiphertext")] - aes256_gcm_ciphertext: String, - #[serde(rename = "aes256GcmAuthTag")] - aes256_gcm_auth_tag: String, - #[serde(rename = "aes256GcmWebCryptoCiphertext")] - aes256_gcm_web_crypto_ciphertext: String, - primes: CryptoPrimeFixture, - } - - #[derive(serde::Deserialize)] - struct CryptoPrimeFixture { - bits: u64, - #[serde(rename = "safeBits")] - safe_bits: u64, - #[serde(rename = "bufferBits")] - buffer_bits: u64, - #[serde(rename = "bufferByteLength")] - buffer_byte_length: usize, - } - - #[derive(serde::Deserialize)] - struct CryptoBasicFixture { - message: String, - #[serde(rename = "hmacKey")] - hmac_key: String, - password: String, - salt: String, - iterations: u32, - #[serde(rename = "keyLength")] - key_length: u32, - scrypt: CryptoScryptFixture, - #[serde(rename = "aesCbc")] - aes_cbc: CryptoAesCbcFixture, - #[serde(rename = "aesGcm")] - aes_gcm: CryptoAesGcmFixture, - expected: CryptoExpectedFixture, - } - - fn decode_hex(input: &str) -> Vec { - input - .as_bytes() - .chunks_exact(2) - .map(|chunk| { - u8::from_str_radix(std::str::from_utf8(chunk).expect("hex utf8"), 16) - .expect("hex byte") - }) - .collect() - } - - fn decode_base64_response(value: Value) -> String { - let bytes = base64::engine::general_purpose::STANDARD - .decode(value.as_str().expect("crypto response string")) - .expect("crypto response base64"); - bytes - .iter() - .map(|byte| format!("{byte:02x}")) - .collect::() - } - - fn base64_arg(value: &str) -> Value { - json!(base64::engine::general_purpose::STANDARD.encode(value)) - } - - fn base64_bytes_arg(value: &[u8]) -> Value { - json!(base64::engine::general_purpose::STANDARD.encode(value)) - } - - fn base64_bytes(value: &[u8]) -> String { - base64::engine::general_purpose::STANDARD.encode(value) - } - - fn parse_json_string(value: Value) -> Value { - serde_json::from_str(value.as_str().expect("crypto response string")) - .expect("crypto response json") - } - - fn bit_len_decimal(value: &Value) -> usize { - let mut number = value - .as_str() - .expect("prime decimal string") - .parse::() - .expect("prime decimal fits fixture range"); - let mut bits = 0; - while number > 0 { - bits += 1; - number >>= 1; - } - bits - } - - let fixture: CryptoBasicFixture = serde_json::from_str(include_str!( - "../../../tests/fixtures/crypto-basic-conformance.json" - )) - .expect("crypto fixture"); - let mut process = create_crypto_test_process(); - let mut next_id = 1; - - for (algorithm, expected) in [ - ("md5", fixture.expected.md5.as_str()), - ("sha224", fixture.expected.sha224.as_str()), - ("sha256", fixture.expected.sha256.as_str()), - ("sha384", fixture.expected.sha384.as_str()), - ] { - let response = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id, - method: String::from("crypto.hashDigest"), - args: vec![json!(algorithm), base64_arg(&fixture.message)], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("hashDigest response"); - next_id += 1; - assert_eq!(decode_base64_response(response), expected, "{algorithm}"); - } - - for (algorithm, expected) in [ - ("sha256", fixture.expected.hmac_sha256.as_str()), - ("sha384", fixture.expected.hmac_sha384.as_str()), - ] { - let response = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id, - method: String::from("crypto.hmacDigest"), - args: vec![ - json!(algorithm), - base64_arg(&fixture.hmac_key), - base64_arg(&fixture.message), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("hmacDigest response"); - next_id += 1; - assert_eq!(decode_base64_response(response), expected, "{algorithm}"); - } - - for (algorithm, expected) in [ - ("sha256", fixture.expected.pbkdf2_sha256.as_str()), - ("sha384", fixture.expected.pbkdf2_sha384.as_str()), - ] { - let response = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id, - method: String::from("crypto.pbkdf2"), - args: vec![ - base64_arg(&fixture.password), - base64_arg(&fixture.salt), - json!(fixture.iterations), - json!(fixture.key_length), - json!(algorithm), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("pbkdf2 response"); - next_id += 1; - assert_eq!(decode_base64_response(response), expected, "{algorithm}"); - } - - let scrypt_options = json!({ - "N": fixture.scrypt.n, - "r": fixture.scrypt.r, - "p": fixture.scrypt.p, - }) - .to_string(); - let scrypt = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id, - method: String::from("crypto.scrypt"), - args: vec![ - base64_arg(&fixture.password), - base64_arg(&fixture.salt), - json!(fixture.key_length), - json!(scrypt_options), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("scrypt response"); - assert_eq!(decode_base64_response(scrypt), fixture.expected.scrypt); - - let cipher = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 1, - method: String::from("crypto.cipheriv"), - args: vec![ - json!(fixture.aes_cbc.algorithm.clone()), - base64_bytes_arg(&decode_hex(&fixture.aes_cbc.key_hex)), - base64_bytes_arg(&decode_hex(&fixture.aes_cbc.iv_hex)), - base64_arg(&fixture.aes_cbc.plaintext), - json!("{}"), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("cipheriv response"); - let cipher_payload: Value = - serde_json::from_str(cipher.as_str().expect("cipheriv string response")) - .expect("cipheriv json"); - let ciphertext = cipher_payload["data"].as_str().expect("cipher data"); - assert_eq!( - decode_base64_response(Value::String(ciphertext.to_string())), - fixture.expected.aes256_cbc_ciphertext - ); - - let decipher = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 2, - method: String::from("crypto.decipheriv"), - args: vec![ - json!(fixture.aes_cbc.algorithm.clone()), - base64_bytes_arg(&decode_hex(&fixture.aes_cbc.key_hex)), - base64_bytes_arg(&decode_hex(&fixture.aes_cbc.iv_hex)), - json!(ciphertext), - json!("{}"), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("decipheriv response"); - let plaintext = base64::engine::general_purpose::STANDARD - .decode(decipher.as_str().expect("decipher response")) - .expect("decipher base64"); - assert_eq!(plaintext, fixture.aes_cbc.plaintext.as_bytes()); - - let gcm_options = json!({ - "aad": base64::engine::general_purpose::STANDARD.encode(&fixture.aes_gcm.aad), - "authTagLength": fixture.aes_gcm.auth_tag_length, - }) - .to_string(); - let gcm_cipher = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 3, - method: String::from("crypto.cipheriv"), - args: vec![ - json!(fixture.aes_gcm.algorithm.clone()), - base64_bytes_arg(&decode_hex(&fixture.aes_gcm.key_hex)), - base64_bytes_arg(&decode_hex(&fixture.aes_gcm.iv_hex)), - base64_arg(&fixture.aes_gcm.plaintext), - json!(gcm_options), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("gcm cipheriv response"); - let gcm_payload: Value = - serde_json::from_str(gcm_cipher.as_str().expect("gcm cipheriv string response")) - .expect("gcm cipheriv json"); - let gcm_ciphertext = gcm_payload["data"].as_str().expect("gcm cipher data"); - let gcm_auth_tag = gcm_payload["authTag"].as_str().expect("gcm auth tag"); - assert_eq!( - decode_base64_response(Value::String(gcm_ciphertext.to_string())), - fixture.expected.aes256_gcm_ciphertext - ); - assert_eq!( - decode_base64_response(Value::String(gcm_auth_tag.to_string())), - fixture.expected.aes256_gcm_auth_tag - ); - - let gcm_decipher_options = json!({ - "aad": base64::engine::general_purpose::STANDARD.encode(&fixture.aes_gcm.aad), - "authTag": gcm_auth_tag, - "authTagLength": fixture.aes_gcm.auth_tag_length, - }) - .to_string(); - let gcm_decipher = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 4, - method: String::from("crypto.decipheriv"), - args: vec![ - json!(fixture.aes_gcm.algorithm.clone()), - base64_bytes_arg(&decode_hex(&fixture.aes_gcm.key_hex)), - base64_bytes_arg(&decode_hex(&fixture.aes_gcm.iv_hex)), - json!(gcm_ciphertext), - json!(gcm_decipher_options), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("gcm decipheriv response"); - let gcm_plaintext = base64::engine::general_purpose::STANDARD - .decode(gcm_decipher.as_str().expect("gcm decipher response")) - .expect("gcm decipher base64"); - assert_eq!(gcm_plaintext, fixture.aes_gcm.plaintext.as_bytes()); - - let aes_gcm_key = decode_hex(&fixture.aes_gcm.key_hex); - let aes_gcm_iv = decode_hex(&fixture.aes_gcm.iv_hex); - let subtle_imported_key = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 5, - method: String::from("crypto.subtle"), - args: vec![json!(serde_json::to_string(&json!({ - "op": "importKey", - "format": "raw", - "keyData": base64_bytes(&aes_gcm_key), - "algorithm": { "name": "AES-GCM" }, - "extractable": false, - "usages": ["encrypt", "decrypt"], - })) - .expect("serialize subtle importKey request"))], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("fixture crypto.subtle importKey response"), - )["key"] - .clone(); - let subtle_algorithm = json!({ - "name": "AES-GCM", - "iv": base64_bytes(&aes_gcm_iv), - "additionalData": base64_bytes(fixture.aes_gcm.aad.as_bytes()), - "tagLength": fixture.aes_gcm.auth_tag_length * 8, - }); - let subtle_encrypted = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 6, - method: String::from("crypto.subtle"), - args: vec![json!(serde_json::to_string(&json!({ - "op": "encrypt", - "algorithm": subtle_algorithm, - "key": subtle_imported_key, - "data": base64_bytes(fixture.aes_gcm.plaintext.as_bytes()), - })) - .expect("serialize subtle encrypt request"))], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("fixture crypto.subtle encrypt response"), - ); - let subtle_ciphertext = subtle_encrypted["data"] - .as_str() - .expect("subtle encrypted data"); - assert_eq!( - decode_base64_response(Value::String(subtle_ciphertext.to_string())), - fixture.expected.aes256_gcm_web_crypto_ciphertext - ); - let subtle_decrypted = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 7, - method: String::from("crypto.subtle"), - args: vec![json!(serde_json::to_string(&json!({ - "op": "decrypt", - "algorithm": subtle_algorithm, - "key": subtle_imported_key, - "data": subtle_ciphertext, - })) - .expect("serialize subtle decrypt request"))], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("fixture crypto.subtle decrypt response"), - ); - let subtle_plaintext = base64::engine::general_purpose::STANDARD - .decode( - subtle_decrypted["data"] - .as_str() - .expect("subtle decrypted data"), - ) - .expect("subtle decrypt base64"); - assert_eq!(subtle_plaintext, fixture.aes_gcm.plaintext.as_bytes()); - - let generated_prime = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 8, - method: String::from("crypto.generatePrimeSync"), - args: vec![ - json!(fixture.expected.primes.bits), - json!(r#"{"hasOptions":true,"options":{"bigint":true}}"#), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("generatePrimeSync bigint response"), - ); - assert_eq!(generated_prime["__type"], json!("bigint")); - assert_eq!( - bit_len_decimal(&generated_prime["value"]), - fixture.expected.primes.bits as usize - ); - - let generated_safe_prime = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 9, - method: String::from("crypto.generatePrimeSync"), - args: vec![ - json!(fixture.expected.primes.safe_bits), - json!(r#"{"hasOptions":true,"options":{"bigint":true,"safe":true}}"#), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("generatePrimeSync safe bigint response"), - ); - assert_eq!(generated_safe_prime["__type"], json!("bigint")); - assert_eq!( - bit_len_decimal(&generated_safe_prime["value"]), - fixture.expected.primes.safe_bits as usize - ); - - let generated_prime_buffer = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: next_id + 10, - method: String::from("crypto.generatePrimeSync"), - args: vec![ - json!(fixture.expected.primes.buffer_bits), - json!(r#"{"hasOptions":true,"options":{}}"#), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("generatePrimeSync buffer response"), - ); - assert_eq!(generated_prime_buffer["__type"], json!("buffer")); - let generated_prime_buffer = base64::engine::general_purpose::STANDARD - .decode( - generated_prime_buffer["value"] - .as_str() - .expect("prime buffer base64"), - ) - .expect("prime buffer decode"); - assert_eq!( - generated_prime_buffer.len(), - fixture.expected.primes.buffer_byte_length - ); - } - - #[test] - fn javascript_crypto_basic_sync_rpcs_round_trip_through_sidecar() { - fn decode_hex(input: &str) -> Vec { - input - .as_bytes() - .chunks_exact(2) - .map(|chunk| { - u8::from_str_radix(std::str::from_utf8(chunk).expect("hex utf8"), 16) - .expect("hex byte") - }) - .collect() - } - - fn decode_base64_response(value: Value) -> Vec { - base64::engine::general_purpose::STANDARD - .decode(value.as_str().expect("crypto response string")) - .expect("crypto response base64") - } - - let mut process = create_crypto_test_process(); - - let sha256 = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("crypto.hashDigest"), - args: vec![json!("sha256"), json!("YWdlbnQtb3M=")], - }, - ) - .expect("hashDigest response"); - assert_eq!( - decode_base64_response(sha256), - decode_hex("c242c43a13eb523ec02bb1de36d3d467947790e3f005eb7a9cefff357ca54101") - ); - - let sha512 = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("crypto.hashDigest"), - args: vec![json!("sha512"), json!("YWdlbnQtb3M=")], - }, - ) - .expect("hashDigest response"); - assert_eq!( - decode_base64_response(sha512), - decode_hex( - "9a2983f6cda25d03276e1d2e4bbeff3dee90d4f549a9f4ea4894569998382be6323a7dd86bcef6f83c1b66ab5d9656da1fde2d1682438cdbe58af61fa5de0bb5", - ) - ); - - let sha1 = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("crypto.hashDigest"), - args: vec![json!("sha1"), json!("YWdlbnQtb3M=")], - }, - ) - .expect("hashDigest response"); - assert_eq!( - decode_base64_response(sha1), - decode_hex("1d43407501651ea75bc63085f352f99bdcc6e364") - ); - - let sha224 = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: 8, - method: String::from("crypto.hashDigest"), - args: vec![json!("sha224"), json!("YWdlbnQtb3M=")], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("hashDigest response"); - assert_eq!( - decode_base64_response(sha224), - decode_hex("eb0fa702ceaabc1849b424fb402cdb2a1cf07e1ec51e151873b397a0") - ); - - let sha384 = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: 9, - method: String::from("crypto.hashDigest"), - args: vec![json!("sha384"), json!("YWdlbnQtb3M=")], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("hashDigest response"); - assert_eq!( - decode_base64_response(sha384), - decode_hex( - "68c265442956e3bae3ff6698ef43570023fd1060553d4d1aeaecee42186c6f94353a107d45e680bffb7ef2ad7f81e082" - ) - ); - - let md5 = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("crypto.hashDigest"), - args: vec![json!("md5"), json!("YWdlbnQtb3M=")], - }, - ) - .expect("hashDigest response"); - assert_eq!( - decode_base64_response(md5), - decode_hex("43e0189b46f53703cf6cb1e6e93ff10d") - ); - - let hmac = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("crypto.hmacDigest"), - args: vec![ - json!("sha256"), - json!("YnJpZGdlLWtleQ=="), - json!("YWdlbnQtb3M="), - ], - }, - ) - .expect("hmacDigest response"); - assert_eq!( - decode_base64_response(hmac), - decode_hex("c24fdd6215522cb3e716855135a1dec9402a3b13be243892c2192d17c57db3a3") - ); - - let hmac_sha384 = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: 10, - method: String::from("crypto.hmacDigest"), - args: vec![ - json!("sha384"), - json!("YnJpZGdlLWtleQ=="), - json!("YWdlbnQtb3M="), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("hmacDigest response"); - assert_eq!( - decode_base64_response(hmac_sha384), - decode_hex("fe3cf09b6f8cf9b78849c4429f54eda460b8c99bb1569ae376a45bbe64386df38b16164387ee263f9fa1dc5ef24e6bcf") - ); - - let pbkdf2 = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("crypto.pbkdf2"), - args: vec![ - json!("aHVudGVyMg=="), - json!("YWdlbnQtb3Mtc2FsdA=="), - json!(1000), - json!(32), - json!("sha256"), - ], - }, - ) - .expect("pbkdf2 response"); - assert_eq!( - decode_base64_response(pbkdf2), - decode_hex("8e97a9f68ca2ebf44885a7a82d1ec3185cf2d6dcfde51a90278f793f9e57f0e8") - ); - - let pbkdf2_sha384 = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - id: 11, - method: String::from("crypto.pbkdf2"), - args: vec![ - json!("aHVudGVyMg=="), - json!("YWdlbnQtb3Mtc2FsdA=="), - json!(1000), - json!(32), - json!("sha384"), - ], - raw_bytes_args: std::collections::HashMap::new(), - }, - ) - .expect("pbkdf2 response"); - assert_eq!( - decode_base64_response(pbkdf2_sha384), - decode_hex("92c0016509e37027704e1c797e38d05d5ab49f0548e78073366889e2f7242be3") - ); - - let scrypt = crate::execution::service_javascript_crypto_sync_rpc( - &mut process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("crypto.scrypt"), - args: vec![ - json!("aHVudGVyMg=="), - json!("YWdlbnQtb3Mtc2FsdA=="), - json!(32), - json!(r#"{"cost":16384,"blockSize":8,"parallelization":1}"#), - ], - }, - ) - .expect("scrypt response"); - assert_eq!( - decode_base64_response(scrypt), - decode_hex("1d0e6ac5c075c16c94c156480f725eb1c041e531fbb7f61f294f1d4fa50c14d9") - ); - } - fn javascript_crypto_advanced_sync_rpcs_round_trip_through_sidecar() { - fn decode_base64(input: &str) -> Vec { - base64::engine::general_purpose::STANDARD - .decode(input) - .expect("base64 decode") - } - - fn parse_json_string(value: Value) -> Value { - serde_json::from_str(value.as_str().expect("json string response")) - .expect("parse json string") - } - - let cipher_response = crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10, - method: String::from("crypto.cipheriv"), - args: vec![ - json!("aes-256-gcm"), - json!(base64::engine::general_purpose::STANDARD.encode([7_u8; 32])), - json!(base64::engine::general_purpose::STANDARD.encode([3_u8; 12])), - json!(base64::engine::general_purpose::STANDARD.encode(b"secure-exec")), - json!(r#"{"aad":"YWR2YW5jZWQ=","authTagLength":16}"#), - ], - }, - ) - .expect("cipheriv response"); - let cipher_payload = parse_json_string(cipher_response); - let ciphertext = cipher_payload["data"].as_str().expect("cipher data"); - let auth_tag = cipher_payload["authTag"].as_str().expect("auth tag"); - - let decipher_response = crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 11, - method: String::from("crypto.decipheriv"), - args: vec![ - json!("aes-256-gcm"), - json!(base64::engine::general_purpose::STANDARD.encode([7_u8; 32])), - json!(base64::engine::general_purpose::STANDARD.encode([3_u8; 12])), - json!(ciphertext), - json!(format!( - r#"{{"aad":"YWR2YW5jZWQ=","authTag":"{auth_tag}","authTagLength":16}}"# - )), - ], - }, - ) - .expect("decipheriv response"); - assert_eq!( - decode_base64(decipher_response.as_str().expect("decipher response")), - b"secure-exec" - ); - - let mut streaming_process = create_crypto_test_process(); - let session_id = crate::execution::service_javascript_crypto_sync_rpc( - &mut streaming_process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 12, - method: String::from("crypto.cipherivCreate"), - args: vec![ - json!("cipher"), - json!("aes-256-cbc"), - json!(base64::engine::general_purpose::STANDARD.encode([9_u8; 32])), - json!(base64::engine::general_purpose::STANDARD.encode([4_u8; 16])), - json!(r#"{}"#), - ], - }, - ) - .expect("cipherivCreate") - .as_u64() - .expect("session id"); - let update = - crate::execution::service_javascript_crypto_sync_rpc( - &mut streaming_process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 13, - method: String::from("crypto.cipherivUpdate"), - args: vec![ - json!(session_id), - json!(base64::engine::general_purpose::STANDARD - .encode(b"hello world 1234")), - ], - }, - ) - .expect("cipherivUpdate"); - let final_payload = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut streaming_process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 14, - method: String::from("crypto.cipherivFinal"), - args: vec![json!(session_id)], - }, - ) - .expect("cipherivFinal"), - ); - assert!(!update.as_str().expect("update string").is_empty()); - assert!(!final_payload["data"] - .as_str() - .expect("final data") - .is_empty()); - - let rsa = openssl::rsa::Rsa::generate(2048).expect("generate rsa"); - let private_key = openssl::pkey::PKey::from_rsa(rsa).expect("private pkey from rsa"); - let private_pem = String::from_utf8( - private_key - .private_key_to_pem_pkcs8() - .expect("private key to pem"), - ) - .expect("private pem utf8"); - let public_pem = - String::from_utf8(private_key.public_key_to_pem().expect("public key to pem")) - .expect("public pem utf8"); - let sign_key_json = serde_json::to_string(&public_pem).expect("public pem json"); - let private_key_json = serde_json::to_string(&private_pem).expect("private pem json"); - - let signature = crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 15, - method: String::from("crypto.sign"), - args: vec![ - json!("sha256"), - json!(base64::engine::general_purpose::STANDARD.encode(b"signed")), - json!(private_key_json), - ], - }, - ) - .expect("crypto.sign"); - let verified = crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 16, - method: String::from("crypto.verify"), - args: vec![ - json!("sha256"), - json!(base64::engine::general_purpose::STANDARD.encode(b"signed")), - json!(sign_key_json), - signature, - ], - }, - ) - .expect("crypto.verify"); - assert_eq!(verified, json!(true)); - - let encrypted = crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 17, - method: String::from("crypto.asymmetricOp"), - args: vec![ - json!("publicEncrypt"), - json!(sign_key_json), - json!(base64::engine::general_purpose::STANDARD.encode(b"secret")), - ], - }, - ) - .expect("publicEncrypt"); - let decrypted = crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 18, - method: String::from("crypto.asymmetricOp"), - args: vec![json!("privateDecrypt"), json!(private_key_json), encrypted], - }, - ) - .expect("privateDecrypt"); - assert_eq!( - decode_base64(decrypted.as_str().expect("privateDecrypt string")), - b"secret" - ); - - let key_object = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 19, - method: String::from("crypto.createKeyObject"), - args: vec![json!("createPrivateKey"), json!(private_key_json)], - }, - ) - .expect("createKeyObject"), - ); - assert_eq!(key_object["type"], json!("private")); - - let generated_pair = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 20, - method: String::from("crypto.generateKeyPairSync"), - args: vec![ - json!("rsa"), - json!(r#"{"hasOptions":true,"options":{"modulusLength":1024,"publicExponent":{"__type":"buffer","value":"AQAB"},"publicKeyEncoding":{"format":"pem","type":"spki"},"privateKeyEncoding":{"format":"pem","type":"pkcs8"}}}"#), - ], - }, - ) - .expect("generateKeyPairSync"), - ); - assert_eq!(generated_pair["publicKey"]["kind"], json!("string")); - assert_eq!(generated_pair["privateKey"]["kind"], json!("string")); - - let generated_secret = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 21, - method: String::from("crypto.generateKeySync"), - args: vec![ - json!("aes"), - json!(r#"{"hasOptions":true,"options":{"length":256}}"#), - ], - }, - ) - .expect("generateKeySync"), - ); - assert_eq!(generated_secret["type"], json!("secret")); - - let generated_prime = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 22, - method: String::from("crypto.generatePrimeSync"), - args: vec![ - json!(64), - json!(r#"{"hasOptions":true,"options":{"bigint":true}}"#), - ], - }, - ) - .expect("generatePrimeSync"), - ); - assert_eq!(generated_prime["__type"], json!("bigint")); - - let mut alice = create_crypto_test_process(); - let alice_id = crate::execution::service_javascript_crypto_sync_rpc( - &mut alice, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 23, - method: String::from("crypto.diffieHellmanSessionCreate"), - args: vec![json!(r#"{"type":"ecdh","name":"P-256"}"#)], - }, - ) - .expect("alice session") - .as_u64() - .expect("alice session id"); - let mut bob = create_crypto_test_process(); - let bob_id = crate::execution::service_javascript_crypto_sync_rpc( - &mut bob, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 24, - method: String::from("crypto.diffieHellmanSessionCreate"), - args: vec![json!(r#"{"type":"ecdh","name":"P-256"}"#)], - }, - ) - .expect("bob session") - .as_u64() - .expect("bob session id"); - let alice_public = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut alice, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 25, - method: String::from("crypto.diffieHellmanSessionCall"), - args: vec![json!(alice_id), json!(r#"{"method":"generateKeys"}"#)], - }, - ) - .expect("alice generate keys"), - )["result"] - .clone(); - let bob_public = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut bob, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 26, - method: String::from("crypto.diffieHellmanSessionCall"), - args: vec![json!(bob_id), json!(r#"{"method":"generateKeys"}"#)], - }, - ) - .expect("bob generate keys"), - )["result"] - .clone(); - let alice_secret = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut alice, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 27, - method: String::from("crypto.diffieHellmanSessionCall"), - args: vec![ - json!(alice_id), - json!(format!( - r#"{{"method":"computeSecret","args":[{}]}}"#, - serde_json::to_string(&bob_public).expect("serialize bob public") - )), - ], - }, - ) - .expect("alice compute secret"), - )["result"] - .clone(); - let bob_secret = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut bob, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 28, - method: String::from("crypto.diffieHellmanSessionCall"), - args: vec![ - json!(bob_id), - json!(format!( - r#"{{"method":"computeSecret","args":[{}]}}"#, - serde_json::to_string(&alice_public) - .expect("serialize alice public") - )), - ], - }, - ) - .expect("bob compute secret"), - )["result"] - .clone(); - assert_eq!(alice_secret, bob_secret); - - let subtle_digest = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 29, - method: String::from("crypto.subtle"), - args: vec![json!( - r#"{"op":"digest","algorithm":"SHA-256","data":"YWdlbnQtb3M="}"# - )], - }, - ) - .expect("crypto.subtle digest"), - ); - assert_eq!( - decode_base64(subtle_digest["data"].as_str().expect("subtle digest")), - decode_base64("wkLEOhPrUj7AK7HeNtPUZ5R3kOPwBet6nO//NXylQQE=") - ); - - let subtle_generated_key = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 30, - method: String::from("crypto.subtle"), - args: vec![json!(serde_json::to_string(&json!({ - "op": "generateKey", - "algorithm": { "name": "AES-GCM", "length": 256 }, - "extractable": true, - "usages": ["encrypt", "decrypt"], - })) - .expect("serialize subtle generateKey request"))], - }, - ) - .expect("crypto.subtle generateKey"), - )["key"] - .clone(); - assert_eq!(subtle_generated_key["type"], json!("secret")); - assert_eq!(subtle_generated_key["algorithm"]["name"], json!("AES-GCM")); - assert_eq!(subtle_generated_key["algorithm"]["length"], json!(256)); - - let subtle_exported_key = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 31, - method: String::from("crypto.subtle"), - args: vec![json!(serde_json::to_string(&json!({ - "op": "exportKey", - "format": "raw", - "key": subtle_generated_key, - })) - .expect("serialize subtle exportKey request"))], - }, - ) - .expect("crypto.subtle exportKey"), - ); - let exported_key_bytes = - decode_base64(subtle_exported_key["data"].as_str().expect("exported key")); - assert_eq!(exported_key_bytes.len(), 32); - - let subtle_imported_key = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 32, - method: String::from("crypto.subtle"), - args: vec![json!(serde_json::to_string(&json!({ - "op": "importKey", - "format": "raw", - "keyData": subtle_exported_key["data"], - "algorithm": { "name": "AES-GCM" }, - "extractable": true, - "usages": ["encrypt", "decrypt"], - })) - .expect("serialize subtle importKey request"))], - }, - ) - .expect("crypto.subtle importKey"), - )["key"] - .clone(); - assert_eq!(subtle_imported_key["algorithm"]["length"], json!(256)); - - let subtle_encrypted = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 33, - method: String::from("crypto.subtle"), - args: vec![json!(serde_json::to_string(&json!({ - "op": "encrypt", - "algorithm": { - "name": "AES-GCM", - "iv": "AAAAAAAAAAAAAAAA", - }, - "key": subtle_imported_key, - "data": "aGVsbG8=", - })) - .expect("serialize subtle encrypt request"))], - }, - ) - .expect("crypto.subtle encrypt"), - ); - assert!( - decode_base64(subtle_encrypted["data"].as_str().expect("encrypted data")).len() - > b"hello".len() - ); - - let subtle_decrypted = parse_json_string( - crate::execution::service_javascript_crypto_sync_rpc( - &mut create_crypto_test_process(), - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 34, - method: String::from("crypto.subtle"), - args: vec![json!(serde_json::to_string(&json!({ - "op": "decrypt", - "algorithm": { - "name": "AES-GCM", - "iv": "AAAAAAAAAAAAAAAA", - }, - "key": subtle_imported_key, - "data": subtle_encrypted["data"], - })) - .expect("serialize subtle decrypt request"))], - }, - ) - .expect("crypto.subtle decrypt"), - ); - assert_eq!( - decode_base64(subtle_decrypted["data"].as_str().expect("decrypted data")), - b"hello" - ); - } - fn javascript_sqlite_sync_rpcs_round_trip_and_persist_vm_files() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-sqlite-rpc-cwd"); - let process_id = "proc-js-sqlite-rpc"; - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("sqlite vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn sqlite kernel process") - }; - let vm = sidecar.vms.get_mut(&vm_id).expect("sqlite vm"); - vm.active_processes.insert( - String::from(process_id), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Tool(ToolExecution::default()), - ) - .with_host_cwd(cwd.clone()), - ); - - let database_id = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("sqlite.open"), - args: vec![json!("/workspace/app.db"), json!({})], - }, - ) - .expect("open sqlite database") - .as_u64() - .expect("database id"); - - let created = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("sqlite.exec"), - args: vec![ - json!(database_id), - json!("CREATE TABLE items (id INTEGER PRIMARY KEY, payload BLOB NOT NULL)"), - ], - }, - ) - .expect("create sqlite table"); - assert_eq!(created, json!(0)); - - let statement_id = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("sqlite.prepare"), - args: vec![ - json!(database_id), - json!("INSERT INTO items(id, payload) VALUES (?, ?)"), - ], - }, - ) - .expect("prepare sqlite insert") - .as_u64() - .expect("statement id"); - - let insert = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("sqlite.statement.run"), - args: vec![ - json!(statement_id), - json!([ - { - "__agentosSqliteType": "bigint", - "value": "9007199254740993", - }, - { - "__agentosSqliteType": "uint8array", - "value": base64::engine::general_purpose::STANDARD.encode([1_u8, 2, 3]), - } - ]), - ], - }, - ) - .expect("run sqlite insert"); - assert_eq!(insert["changes"], json!(1)); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("sqlite.statement.finalize"), - args: vec![json!(statement_id)], - }, - ) - .expect("finalize sqlite insert"); - - let query = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("sqlite.query"), - args: vec![ - json!(database_id), - json!("SELECT id, payload FROM items"), - Value::Null, - json!({ "readBigInts": true }), - ], - }, - ) - .expect("query sqlite row"); - assert_eq!(query[0]["id"]["__agentosSqliteType"], json!("bigint")); - assert_eq!(query[0]["id"]["value"], json!("9007199254740993")); - assert_eq!( - query[0]["payload"]["value"], - json!(base64::engine::general_purpose::STANDARD.encode([1_u8, 2, 3])) - ); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("sqlite.close"), - args: vec![json!(database_id)], - }, - ) - .expect("close sqlite database"); - - let reopened_id = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 8, - method: String::from("sqlite.open"), - args: vec![json!("/workspace/app.db"), json!({})], - }, - ) - .expect("reopen sqlite database") - .as_u64() - .expect("reopened database id"); - - let reopened = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - process_id, - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 9, - method: String::from("sqlite.query"), - args: vec![ - json!(reopened_id), - json!("SELECT id, payload FROM items"), - Value::Null, - json!({ "readBigInts": true }), - ], - }, - ) - .expect("query reopened sqlite row"); - assert_eq!(reopened, query); - } - fn javascript_sqlite_builtin_round_trips_through_sidecar_sync_rpc() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-sqlite-builtins-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import { existsSync, readFileSync, statSync } from "node:fs"; -import { DatabaseSync } from "node:sqlite"; - -const dbPath = "/workspace/sqlite-builtins.db"; -const db = new DatabaseSync(dbPath); -if (db.location() !== dbPath) { - throw new Error(`unexpected sqlite location: ${String(db.location())}`); -} - -const journalModeRows = db.query("PRAGMA journal_mode = WAL"); -if (journalModeRows[0]?.journal_mode !== "wal") { - throw new Error(`unexpected journal mode rows: ${JSON.stringify(journalModeRows)}`); -} - -db.exec("CREATE TABLE items (id INTEGER PRIMARY KEY, payload BLOB NOT NULL, quantity INTEGER NOT NULL)"); -const insert = db.prepare("INSERT INTO items(id, payload, quantity) VALUES (:id, :payload, :quantity)"); -insert.setAllowBareNamedParameters(true); -const insertResult = insert.run({ - id: 9007199254740993n, - payload: new Uint8Array([7, 8, 9]), - quantity: 42, -}); -if (insertResult.changes !== 1) { - throw new Error(`unexpected insert result: ${JSON.stringify(insertResult)}`); -} -if (typeof insertResult.lastInsertRowid !== "bigint" || insertResult.lastInsertRowid !== 9007199254740993n) { - throw new Error(`unexpected lastInsertRowid: ${String(insertResult.lastInsertRowid)}`); -} - -const select = db.prepare("SELECT id, payload, quantity FROM items WHERE id = ?"); -select.setReadBigInts(true); -const row = select.get(9007199254740993n); -if (typeof row.id !== "bigint" || row.id !== 9007199254740993n) { - throw new Error(`unexpected bigint row id: ${String(row.id)}`); -} -if (!Buffer.isBuffer(row.payload) || row.payload.length !== 3 || row.payload[1] !== 8) { - throw new Error(`unexpected blob payload: ${JSON.stringify(row.payload)}`); -} -if (row.quantity !== 42n) { - throw new Error(`unexpected integer payload: id=${String(row.id)} quantity=${String(row.quantity)}`); -} - -const columns = select.columns(); -if (columns.length !== 3 || columns[0]?.name !== "id" || columns[1]?.name !== "payload") { - throw new Error(`unexpected statement columns: ${JSON.stringify(columns)}`); -} - -db.checkpoint(); -if (!existsSync(dbPath)) { - throw new Error("sqlite database file is not visible in the guest filesystem"); -} -const fileStat = statSync(dbPath); -if (fileStat.size <= 0) { - throw new Error(`unexpected sqlite file size: ${fileStat.size}`); -} -const fileHeader = readFileSync(dbPath).subarray(0, 16).toString("utf8"); -if (!fileHeader.startsWith("SQLite format 3")) { - throw new Error(`unexpected sqlite file header: ${JSON.stringify(fileHeader)}`); -} - -db.close(); - -const reopened = new DatabaseSync(dbPath); -const verify = reopened.prepare("SELECT COUNT(*) AS count, SUM(quantity) AS totalQuantity FROM items"); -verify.setReadBigInts(true); -const count = verify.get(); -if (count.count !== 1n) { - throw new Error(`unexpected persisted count: count=${String(count.count)} totalQuantity=${String(count.totalQuantity)}`); -} -if (count.totalQuantity !== 42n) { - throw new Error(`unexpected persisted quantity total: count=${String(count.count)} totalQuantity=${String(count.totalQuantity)}`); -} -reopened.close(); -console.log("sqlite-ok"); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-sqlite-builtins"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - assert!(stderr.trim().is_empty(), "stderr: {stderr}"); - assert_eq!(stdout.trim(), "sqlite-ok"); - let database_bytes = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .read_file("/workspace/sqlite-builtins.db") - .expect("read sqlite builtins database file") - }; - assert!( - !database_bytes.is_empty(), - "sqlite builtins database file should be persisted" - ); - } - fn javascript_net_rpc_connects_over_vm_loopback() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-rpc-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import net from "node:net"; - -const summary = await new Promise((resolve, reject) => { - const server = net.createServer((socket) => { - let received = ""; - socket.setEncoding("utf8"); - socket.on("data", (chunk) => { - received += chunk; - }); - socket.on("end", () => { - if (received !== "ping") { - reject(new Error(`unexpected server payload: ${received}`)); - return; - } - socket.end("pong"); - }); - socket.on("error", reject); - }); - server.on("error", reject); - server.listen(0, "127.0.0.1", () => { - const address = server.address(); - if (!address || typeof address === "string") { - reject(new Error(`unexpected listener address: ${String(address)}`)); - return; - } - const socket = net.createConnection({ host: "127.0.0.1", port: address.port }); - let data = ""; - socket.setEncoding("utf8"); - socket.on("connect", () => { - socket.end("ping"); - }); - socket.on("data", (chunk) => { - data += chunk; - }); - socket.on("error", reject); - socket.on("close", (hadError) => { - server.close(() => { - resolve({ - data, - hadError, - remoteAddress: socket.remoteAddress, - remotePort: socket.remotePort, - localPort: socket.localPort, - listenerPort: address.port, - }); - }); - }); - }); -}); - -if (summary.data !== "pong") { - throw new Error(`unexpected TCP message: ${summary.data}`); -} -if (summary.remoteAddress !== "127.0.0.1") { - throw new Error(`unexpected TCP remote address: ${JSON.stringify(summary)}`); -} -if (summary.remotePort !== summary.listenerPort) { - throw new Error(`unexpected TCP remote port: ${JSON.stringify(summary)}`); -} -if (typeof summary.localPort !== "number" || summary.localPort <= 0) { - throw new Error(`unexpected TCP local port: ${JSON.stringify(summary)}`); -} - -console.log(JSON.stringify(summary)); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-net"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - assert!( - stdout.contains("\"remoteAddress\":\"127.0.0.1\""), - "stdout: {stdout}" - ); - assert!(stdout.contains("\"listenerPort\":"), "stdout: {stdout}"); - } - fn javascript_net_loopback_socket_churn_releases_kernel_slots() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([(String::from("resource.max_sockets"), String::from("8"))]), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-churn-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import net from "node:net"; - -const iterations = 100; -let accepted = 0; -let acceptedClosed = 0; - -const server = net.createServer((socket) => { - accepted += 1; - socket.setEncoding("utf8"); - let payload = ""; - socket.on("data", (chunk) => { - payload += chunk; - }); - socket.on("end", () => { - socket.end(payload); - }); - socket.on("close", () => { - acceptedClosed += 1; - }); -}); - -await new Promise((resolve, reject) => { - server.once("error", reject); - server.listen(0, "127.0.0.1", resolve); -}); - -const address = server.address(); -if (!address || typeof address === "string") { - throw new Error(`unexpected listener address: ${String(address)}`); -} - -for (let index = 0; index < iterations; index += 1) { - const message = `x${index}`; - const response = await new Promise((resolve, reject) => { - const socket = net.createConnection({ host: "127.0.0.1", port: address.port }); - let data = ""; - socket.setEncoding("utf8"); - socket.on("connect", () => { - socket.end(message); - }); - socket.on("data", (chunk) => { - data += chunk; - }); - socket.on("error", reject); - socket.on("close", (hadError) => { - if (hadError) { - reject(new Error(`client close reported error at ${index}`)); - return; - } - resolve(data); - }); - }); - if (response !== message) { - throw new Error(`unexpected response at ${index}: ${response}`); - } -} - -await new Promise((resolve, reject) => { - server.close((error) => { - if (error) { - reject(error); - } else { - resolve(); - } - }); -}); - -if (acceptedClosed !== iterations) { - throw new Error(`expected ${iterations} accepted closes, got ${acceptedClosed}`); -} - -console.log(JSON.stringify({ iterations, accepted, acceptedClosed })); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-net-churn"); - - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse churn JSON"); - assert_eq!(parsed["iterations"], Value::from(100)); - assert_eq!(parsed["accepted"], Value::from(100)); - assert_eq!(parsed["acceptedClosed"], Value::from(100)); - } - fn javascript_net_loopback_wakes_reader_parked_before_write() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-wake-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import net from "node:net"; - -const summary = await new Promise((resolve, reject) => { - const server = net.createServer((socket) => { - socket.setEncoding("utf8"); - let received = ""; - socket.once("readable", () => { - let chunk; - while ((chunk = socket.read()) !== null) { - received += chunk; - } - }); - socket.on("end", () => { - socket.end(`echo:${received}`); - }); - socket.on("error", reject); - }); - server.on("error", reject); - server.listen(0, "127.0.0.1", () => { - const address = server.address(); - if (!address || typeof address === "string") { - reject(new Error(`unexpected listener address: ${String(address)}`)); - return; - } - const socket = net.createConnection({ host: "127.0.0.1", port: address.port }); - let data = ""; - socket.setEncoding("utf8"); - socket.on("data", (chunk) => { - data += chunk; - }); - socket.on("connect", () => { - setImmediate(() => socket.end("parked")); - }); - socket.on("error", reject); - socket.on("close", () => { - server.close(() => resolve(data)); - }); - }); -}); - -if (summary !== "echo:parked") { - throw new Error(`unexpected parked-reader echo: ${summary}`); -} -console.log(summary); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-net-wake"); - - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!(stdout.trim(), "echo:parked"); - } - fn javascript_net_loopback_reads_back_to_back_and_after_partial_drain() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-edge-wake-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import net from "node:net"; - -const summary = await new Promise((resolve, reject) => { - const server = net.createServer((socket) => { - const received = []; - socket.on("readable", () => { - let chunk; - while ((chunk = socket.read(1)) !== null) { - received.push(chunk.toString("utf8")); - if (received.join("") === "ABC") { - socket.end("done"); - } - } - }); - socket.on("error", reject); - }); - server.on("error", reject); - server.listen(0, "127.0.0.1", () => { - const address = server.address(); - if (!address || typeof address === "string") { - reject(new Error(`unexpected listener address: ${String(address)}`)); - return; - } - const socket = net.createConnection({ host: "127.0.0.1", port: address.port }); - let data = ""; - socket.setEncoding("utf8"); - socket.on("connect", () => { - socket.write("A"); - socket.write("B"); - setImmediate(() => socket.end("C")); - }); - socket.on("data", (chunk) => { - data += chunk; - }); - socket.on("error", reject); - socket.on("close", () => { - server.close(() => resolve(data)); - }); - }); -}); - -if (summary !== "done") { - throw new Error(`unexpected edge-wake response: ${summary}`); -} -console.log(summary); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-net-edge-wake"); - - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!(stdout.trim(), "done"); - } - fn javascript_dgram_rpc_sends_and_receives_vm_loopback_packets() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-dgram-rpc-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import dgram from "node:dgram"; - -const receiver = dgram.createSocket("udp4"); -const sender = dgram.createSocket("udp4"); -let receiverAddress; -const summary = await new Promise((resolve) => { - const reject = (error) => { - console.error(error.stack ?? error.message); - process.exit(1); - }; - receiver.on("error", reject); - sender.on("error", reject); - receiver.on("message", (message, rinfo) => { - receiverAddress = receiver.address(); - if (message.toString("utf8") !== "ping") { - reject(new Error(`unexpected UDP request: ${message.toString("utf8")}`)); - return; - } - receiver.send("pong", rinfo.port, rinfo.address, (error) => { - if (error) { - reject(error); - } - }); - }); - sender.on("message", (message, rinfo) => { - const senderAddress = sender.address(); - sender.close(() => { - receiver.close(() => { - resolve({ - senderAddress, - receiverAddress, - message: message.toString("utf8"), - rinfo, - }); - }); - }); - }); - receiver.bind(0, "127.0.0.1", () => { - receiverAddress = receiver.address(); - sender.bind(0, "127.0.0.1", () => { - sender.send("ping", receiverAddress.port, "127.0.0.1"); - }); - }); -}); - -if (summary.message !== "pong") { - throw new Error(`unexpected udp message: ${summary.message}`); -} -if (summary.senderAddress.address !== "127.0.0.1") { - throw new Error(`unexpected udp sender address: ${JSON.stringify(summary.senderAddress)}`); -} -if (summary.receiverAddress.address !== "127.0.0.1") { - throw new Error(`unexpected udp receiver address: ${JSON.stringify(summary.receiverAddress)}`); -} -if (summary.rinfo.address !== "127.0.0.1" || summary.rinfo.port !== summary.receiverAddress.port) { - throw new Error(`unexpected udp remote info: ${JSON.stringify(summary.rinfo)}`); -} - -console.log(JSON.stringify(summary)); -"#, - ); - let (_stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-dgram"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - } - fn javascript_net_unix_domain_echo_uses_reader_events() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-unix-echo-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import net from "node:net"; - -const path = "/tmp/secure-exec-unix-echo.sock"; -const summary = await new Promise((resolve, reject) => { - const server = net.createServer((socket) => { - socket.setEncoding("utf8"); - let data = ""; - socket.on("data", (chunk) => { - data += chunk; - }); - socket.on("end", () => { - socket.end(`unix:${data}`); - }); - socket.on("error", reject); - }); - server.on("error", reject); - server.listen(path, () => { - const socket = net.createConnection(path); - let data = ""; - socket.setEncoding("utf8"); - socket.on("connect", () => { - socket.end("ping"); - }); - socket.on("data", (chunk) => { - data += chunk; - }); - socket.on("error", reject); - socket.on("close", () => { - server.close(() => resolve(data)); - }); - }); -}); - -if (summary !== "unix:ping") { - throw new Error(`unexpected unix echo: ${summary}`); -} -console.log(summary); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-unix-echo"); - - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - assert_eq!(stdout.trim(), "unix:ping"); - } - fn javascript_dns_rpc_resolves_localhost() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-dns-rpc-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import dns from "node:dns"; - -const lookup = await dns.promises.lookup("localhost", { all: true }); -const resolve4 = await dns.promises.resolve4("localhost"); - -console.log(JSON.stringify({ lookup, resolve4 })); -"#, - ); - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from( - "[\"assert\",\"buffer\",\"console\",\"crypto\",\"dns\",\"events\",\"fs\",\"path\",\"querystring\",\"stream\",\"string_decoder\",\"timers\",\"url\",\"util\",\"zlib\"]", - ), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-dns"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.clone()), - ); - } - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - for _ in 0..64 { - let next_event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes - .get_mut("proc-js-dns") - .and_then(|process| { - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll javascript dns rpc event") - }) - }; - let Some(event) = next_event else { - if exit_code.is_some() { - break; - } - panic!("javascript dns process disappeared before exit"); - }; - - match &event { - ActiveExecutionEvent::Stdout(chunk) => { - append_process_stream_chunk(&mut stdout, chunk, "proc-js-dns", "stdout"); - } - ActiveExecutionEvent::Stderr(chunk) => { - append_process_stream_chunk(&mut stderr, chunk, "proc-js-dns", "stderr"); - } - ActiveExecutionEvent::Exited(code) => { - exit_code = Some(*code); - } - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } => {} - } - - sidecar - .handle_execution_event(&vm_id, "proc-js-dns", event) - .expect("handle javascript dns rpc event"); - } - - let stdout = process_stream_to_string(&stdout); - let stderr = process_stream_to_string(&stderr); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse dns JSON"); - assert!( - parsed["lookup"] - .as_array() - .is_some_and(|entries| !entries.is_empty()), - "stdout: {stdout}" - ); - assert!( - parsed["resolve4"] - .as_array() - .is_some_and(|entries| entries.iter().any(|entry| entry == "127.0.0.1")), - "stdout: {stdout}" - ); - } - fn javascript_network_ssrf_protection_blocks_private_dns_and_unowned_loopback_targets() { - assert_node_available(); - - let loopback_listener = - TcpListener::bind("127.0.0.1:0").expect("bind loopback listener"); - let loopback_port = loopback_listener - .local_addr() - .expect("loopback listener address") - .port(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([( - String::from("network.dns.override.metadata.test"), - String::from("169.254.169.254"), - )]), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-ssrf-protection-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - format!( - r#" -import dns from "node:dns"; -import net from "node:net"; - -const dnsLookup = await (async () => {{ - try {{ - await dns.promises.lookup("metadata.test", {{ family: 4 }}); - return {{ unexpected: true }}; - }} catch (error) {{ - return {{ code: error.code ?? null, message: error.message }}; - }} -}})(); - -const privateConnect = await new Promise((resolve) => {{ - try {{ - const socket = net.createConnection({{ host: "metadata.test", port: 80 }}); - socket.on("connect", () => {{ - socket.destroy(); - resolve({{ unexpected: true }}); - }}); - socket.on("error", (error) => {{ - resolve({{ code: error.code ?? null, message: error.message }}); - }}); - }} catch (error) {{ - resolve({{ code: error.code ?? null, message: error.message }}); - }} -}}); - -const loopbackConnect = await new Promise((resolve) => {{ - try {{ - const socket = net.createConnection({{ host: "127.0.0.1", port: {loopback_port} }}); - socket.on("connect", () => {{ - socket.destroy(); - resolve({{ unexpected: true }}); - }}); - socket.on("error", (error) => {{ - resolve({{ code: error.code ?? null, message: error.message }}); - }}); - }} catch (error) {{ - resolve({{ code: error.code ?? null, message: error.message }}); - }} -}}); - -console.log(JSON.stringify({{ dnsLookup, privateConnect, loopbackConnect }})); -process.exit(0); -"#, - ), - ); - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from( - "[\"assert\",\"buffer\",\"console\",\"crypto\",\"dns\",\"events\",\"fs\",\"net\",\"path\",\"querystring\",\"stream\",\"string_decoder\",\"timers\",\"url\",\"util\",\"zlib\"]", - ), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-ssrf-protection"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.clone()), - ); - } - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - for _ in 0..64 { - let next_event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes - .get_mut("proc-js-ssrf-protection") - .and_then(|process| { - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll javascript ssrf event") - }) - }; - let Some(event) = next_event else { - if exit_code.is_some() { - break; - } - panic!("javascript ssrf process disappeared before exit"); - }; - - match &event { - ActiveExecutionEvent::Stdout(chunk) => { - append_process_stream_chunk( - &mut stdout, - chunk, - "proc-js-ssrf-protection", - "stdout", - ); - } - ActiveExecutionEvent::Stderr(chunk) => { - append_process_stream_chunk( - &mut stderr, - chunk, - "proc-js-ssrf-protection", - "stderr", - ); - } - ActiveExecutionEvent::Exited(code) => { - exit_code = Some(*code); - } - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } => {} - } - - sidecar - .handle_execution_event(&vm_id, "proc-js-ssrf-protection", event) - .expect("handle javascript ssrf event"); - } - - let stdout = process_stream_to_string(&stdout); - let stderr = process_stream_to_string(&stderr); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse ssrf JSON"); - assert_eq!( - parsed["dnsLookup"]["code"], - Value::String(String::from("EACCES")) - ); - assert!( - parsed["dnsLookup"]["message"] - .as_str() - .is_some_and(|message| message.contains("169.254.0.0/16")), - "stdout: {stdout}" - ); - assert_eq!( - parsed["privateConnect"]["code"], - Value::String(String::from("EACCES")) - ); - assert!( - parsed["privateConnect"]["message"] - .as_str() - .is_some_and(|message| message.contains("169.254.0.0/16")), - "stdout: {stdout}" - ); - assert_eq!( - parsed["loopbackConnect"]["code"], - Value::String(String::from("EACCES")) - ); - assert!( - parsed["loopbackConnect"]["message"] - .as_str() - .is_some_and(|message| message.contains(LOOPBACK_EXEMPT_PORTS_ENV)), - "stdout: {stdout}" - ); - - drop(loopback_listener); - } - fn javascript_dns_rpc_honors_vm_dns_overrides_and_net_connect_uses_sidecar_dns() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([ - ( - String::from("network.dns.override.example.test"), - String::from("127.0.0.1"), - ), - ( - String::from(VM_DNS_SERVERS_METADATA_KEY), - String::from("203.0.113.53:5353"), - ), - ]), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-dns-override-rpc-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import dns from "node:dns"; -import net from "node:net"; - -const lookup = await dns.promises.lookup("example.test", { family: 4 }); -const resolved = await dns.promises.resolve("example.test", "A"); -const socketSummary = await new Promise((resolve, reject) => { - const server = net.createServer((socket) => { - let received = ""; - socket.setEncoding("utf8"); - socket.on("data", (chunk) => { - received += chunk; - }); - socket.on("end", () => { - if (received !== "ping") { - reject(new Error(`unexpected DNS server payload: ${received}`)); - return; - } - socket.end("pong"); - }); - socket.on("error", reject); - }); - server.on("error", reject); - server.listen(0, "127.0.0.1", () => { - const address = server.address(); - if (!address || typeof address === "string") { - reject(new Error(`unexpected DNS listener address: ${String(address)}`)); - return; - } - const socket = net.createConnection({ host: "example.test", port: address.port }); - let data = ""; - socket.setEncoding("utf8"); - socket.on("connect", () => { - socket.end("ping"); - }); - socket.on("data", (chunk) => { - data += chunk; - }); - socket.on("error", reject); - socket.on("close", (hadError) => { - server.close(() => { - resolve({ - data, - hadError, - remoteAddress: socket.remoteAddress, - remotePort: socket.remotePort, - listenerPort: address.port, - }); - }); - }); - }); -}); - -console.log(JSON.stringify({ lookup, resolved, socketSummary })); -"#, - ); - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-dns-override"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse dns JSON"); - assert_eq!(parsed["lookup"]["address"], Value::from("127.0.0.1")); - assert_eq!(parsed["lookup"]["family"], Value::from(4)); - assert_eq!(parsed["resolved"][0], Value::from("127.0.0.1")); - assert_eq!(parsed["socketSummary"]["data"], Value::from("pong")); - assert_eq!(parsed["socketSummary"]["hadError"], Value::from(false)); - assert_eq!( - parsed["socketSummary"]["remoteAddress"], - Value::from("127.0.0.1") - ); - assert_eq!( - parsed["socketSummary"]["remotePort"], - parsed["socketSummary"]["listenerPort"] - ); - - let events = sidecar - .with_bridge_mut(|bridge| bridge.structured_events.clone()) - .expect("collect structured events"); - let dns_events = events - .iter() - .filter(|event| event.name == "network.dns.resolved") - .filter(|event| { - event.fields.get("hostname").map(String::as_str) == Some("example.test") - }) - .collect::>(); - assert!( - dns_events.len() >= 3, - "expected dns events for lookup, resolve, and net.connect: {dns_events:?}" - ); - for event in dns_events { - assert_eq!(event.fields["source"], "override"); - assert_eq!(event.fields["addresses"], "127.0.0.1"); - assert_eq!(event.fields["resolver_count"], "1"); - assert_eq!(event.fields["resolvers"], "203.0.113.53:5353"); - } - } - - fn javascript_network_dns_resolve_supports_standard_rrtypes() { - assert_node_available(); - - let dns_server = FixtureDnsServer::start(); - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([( - String::from(VM_DNS_SERVERS_METADATA_KEY), - dns_server.addr.to_string(), - )]), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-dns-rrtype-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import dns from "node:dns"; - -const resolveMxCallback = await new Promise((resolve, reject) => { - dns.resolveMx("bundle.example.test", (error, records) => { - if (error) reject(error); - else resolve(records); - }); -}); - -const data = { - resolve4: await dns.promises.resolve4("bundle.example.test"), - resolve6: await dns.promises.resolve6("bundle.example.test"), - resolveMxCallback, - resolveTxt: await dns.promises.resolveTxt("bundle.example.test"), - resolveSrv: await dns.promises.resolveSrv("_svc._tcp.example.test"), - resolveCname: await dns.promises.resolve("alias.example.test", "CNAME"), - resolvePtr: await dns.promises.resolvePtr("ptr.example.test"), - resolveNs: await dns.promises.resolveNs("zone.example.test"), - resolveSoa: await dns.promises.resolveSoa("zone.example.test"), - resolveNaptr: await dns.promises.resolveNaptr("naptr.example.test"), - resolveCaa: await dns.promises.resolveCaa("caa.example.test"), - resolveAny: await dns.promises.resolveAny("bundle.example.test"), -}; - -try { - await dns.promises.resolve("bundle.example.test", "TLSA"); - data.unsupported = { unexpected: true }; -} catch (error) { - data.unsupported = { code: error.code ?? null, message: error.message }; -} - -console.log(JSON.stringify(data)); -"#, - ); - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-dns-rrtype"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse dns rrtype JSON"); - assert_eq!(parsed["resolve4"][0], Value::from("203.0.113.10")); - assert_eq!(parsed["resolve6"][0], Value::from("2001:db8::10")); - assert_eq!(parsed["resolveMxCallback"][0]["priority"], Value::from(10)); - assert_eq!( - parsed["resolveMxCallback"][0]["exchange"], - Value::from("mail.example.test") - ); - assert_eq!( - parsed["resolveTxt"][0], - json!([String::from("v=spf1"), String::from("-all")]) - ); - assert_eq!(parsed["resolveSrv"][0]["port"], Value::from(8443)); - assert_eq!( - parsed["resolveSrv"][0]["name"], - Value::from("svc-target.example.test") - ); - assert_eq!( - parsed["resolveCname"][0], - Value::from("bundle.example.test") - ); - assert_eq!(parsed["resolvePtr"][0], Value::from("host.example.test")); - assert_eq!(parsed["resolveNs"][0], Value::from("ns1.example.test")); - assert_eq!( - parsed["resolveSoa"], - json!({ - "nsname": "ns1.example.test", - "hostmaster": "hostmaster.example.test", - "serial": 2026041601_u32, - "refresh": 3600, - "retry": 600, - "expire": 86400, - "minttl": 60_u32 - }) - ); - assert_eq!( - parsed["resolveNaptr"][0], - json!({ - "flags": "s", - "service": "SIP+D2U", - "regexp": "!^.*$!sip:service@example.test!", - "replacement": "_sip._udp.example.test", - "order": 10, - "preference": 20 - }) - ); - assert_eq!(parsed["resolveCaa"][0]["critical"], Value::from(0)); - assert_eq!( - parsed["resolveCaa"][0]["issue"], - Value::from("letsencrypt.org.") - ); - assert_eq!( - parsed["resolveCaa"][1]["iodef"], - Value::from("https://iodef.example.test/report") - ); - - let any_types = parsed["resolveAny"] - .as_array() - .expect("resolveAny array") - .iter() - .filter_map(|entry| entry.get("type").and_then(Value::as_str)) - .collect::>(); - assert!(any_types.contains(&"A"), "stdout: {stdout}"); - assert!(any_types.contains(&"AAAA"), "stdout: {stdout}"); - assert!(any_types.contains(&"MX"), "stdout: {stdout}"); - assert!(any_types.contains(&"TXT"), "stdout: {stdout}"); - assert_eq!( - parsed["unsupported"]["code"], - Value::from("ERR_NOT_IMPLEMENTED") - ); - assert!( - parsed["unsupported"]["message"] - .as_str() - .is_some_and(|message| message.contains("TLSA")), - "stdout: {stdout}" - ); - } - - fn javascript_network_permission_callbacks_fire_for_dns_lookup_connect_and_listen() { - assert_node_available(); - - let listener = TcpListener::bind("127.0.0.1:0").expect("bind tcp listener"); - let port = listener.local_addr().expect("listener address").port(); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept tcp client"); - let mut received = Vec::new(); - stream - .read_to_end(&mut received) - .expect("read client payload"); - assert_eq!(String::from_utf8(received).expect("client utf8"), "ping"); - }); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([ - ( - format!("env.{LOOPBACK_EXEMPT_PORTS_ENV}"), - serde_json::to_string(&vec![port.to_string()]) - .expect("serialize exempt ports"), - ), - ( - String::from("network.dns.override.example.test"), - String::from("127.0.0.1"), - ), - ]), - ) - .expect("create vm"); - sidecar - .bridge - .clear_vm_permissions(&vm_id) - .expect("clear static vm permissions"); - let cwd = temp_dir("secure-exec-sidecar-js-network-permission-callbacks"); - write_fixture( - &cwd.join("entry.mjs"), - format!( - r#" -import dns from "node:dns"; -import net from "node:net"; - -const lookup = await dns.promises.lookup("example.test", {{ family: 4 }}); -const listenAddress = await new Promise((resolve, reject) => {{ - const server = net.createServer(); - server.on("error", reject); - server.listen(0, "127.0.0.1", () => {{ - const address = server.address(); - server.close((error) => {{ - if (error) {{ - reject(error); - return; - }} - resolve(address); - }}); - }}); -}}); -const connectResult = await new Promise((resolve, reject) => {{ - const socket = net.createConnection({{ host: "127.0.0.1", port: {port} }}); - socket.on("error", reject); - socket.on("connect", () => {{ - socket.end("ping"); - }}); - socket.on("close", (hadError) => {{ - resolve({{ hadError }}); - }}); -}}); - -console.log(JSON.stringify({{ lookup, listenAddress, connectResult }})); -process.exit(0); -"#, - ), - ); - - let (stdout, stderr, exit_code) = run_javascript_entry( - &mut sidecar, - &vm_id, - &cwd, - "proc-js-network-permission-callbacks", - ); - - server.join().expect("join tcp server"); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse callback JSON"); - assert_eq!( - parsed["lookup"]["address"], - Value::String(String::from("127.0.0.1")) - ); - assert_eq!(parsed["connectResult"]["hadError"], Value::Bool(false)); - assert!( - parsed["listenAddress"]["port"] - .as_u64() - .is_some_and(|value| value > 0), - "stdout: {stdout}" - ); - - let expected = [ - format!("net:{vm_id}:{}", format_dns_resource("example.test")), - format!("net:{vm_id}:{}", format_tcp_resource("127.0.0.1", 0)), - format!("net:{vm_id}:{}", format_tcp_resource("127.0.0.1", port)), - ]; - let checks = sidecar - .with_bridge_mut(|bridge| { - bridge - .permission_checks - .iter() - .filter(|entry| entry.starts_with("net:")) - .cloned() - .collect::>() - }) - .expect("read permission checks"); - for check in expected { - assert!( - checks.iter().any(|entry| entry == &check), - "missing permission check {check:?} in {checks:?}" - ); - } - } - fn javascript_network_permission_denials_surface_eacces_to_guest_code() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - capability_permissions(&[ - ("fs", PermissionMode::Allow), - ("env", PermissionMode::Allow), - ("child_process", PermissionMode::Allow), - ("network", PermissionMode::Allow), - ("network.dns", PermissionMode::Deny), - ("network.http", PermissionMode::Deny), - ("network.listen", PermissionMode::Deny), - ]), - BTreeMap::from([( - String::from("network.dns.override.example.test"), - String::from("127.0.0.1"), - )]), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-network-permission-denials"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import dns from "node:dns"; -import net from "node:net"; - -let dnsResult = null; -try { - dnsResult = { unexpected: await dns.promises.lookup("example.test", { family: 4 }) }; -} catch (error) { - dnsResult = { code: error.code ?? null, message: error.message }; -} -const listenResult = await new Promise((resolve) => { - const server = net.createServer(); - server.on("error", (error) => { - resolve({ code: error.code ?? null, message: error.message }); - }); - try { - server.listen(0, "127.0.0.1", () => { - resolve({ unexpected: true }); - }); - } catch (error) { - resolve({ code: error.code ?? null, message: error.message }); - } -}); -const connectResult = await new Promise((resolve) => { - try { - const socket = net.createConnection({ host: "127.0.0.1", port: 43111 }); - socket.on("connect", () => resolve({ unexpected: true })); - socket.on("error", (error) => { - resolve({ code: error.code ?? null, message: error.message }); - }); - } catch (error) { - resolve({ code: error.code ?? null, message: error.message }); - } -}); - -console.log(JSON.stringify({ dnsResult, listenResult, connectResult })); -process.exit(0); -"#, - ); - - let (stdout, stderr, exit_code) = run_javascript_entry( - &mut sidecar, - &vm_id, - &cwd, - "proc-js-network-permission-denials", - ); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse denial JSON"); - for field in ["dnsResult", "listenResult", "connectResult"] { - assert_eq!(parsed[field]["code"], Value::String(String::from("EACCES"))); - assert!( - parsed[field]["message"] - .as_str() - .is_some_and(|message| message.contains("blocked by network.")), - "missing policy detail for {field}: {stdout}" - ); - } - } - fn javascript_tls_rpc_connects_and_serves_over_guest_net() { - let _tls_lock = tls_service_test_lock(); - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-tls-rpc-cwd"); - let entry = format!( - r#" -import tls from "node:tls"; - -const key = {key:?}; -const cert = {cert:?}; - -const summary = await new Promise((resolve, reject) => {{ - const server = tls.createServer({{ key, cert }}, (socket) => {{ - let received = ""; - socket.setEncoding("utf8"); - socket.on("data", (chunk) => {{ - received += chunk; - socket.end(`pong:${{chunk}}`); - }}); - socket.on("error", reject); - socket.on("close", () => {{ - server.close(() => {{ - resolve({{ - authorized: client.authorized, - encrypted: client.encrypted, - hadError: closeState.hadError, - localPort: client.localPort, - received, - remoteAddress: client.remoteAddress, - response, - serverPort: port, - serverSecure: secureConnectionSeen, - }}); - }}); - }}); - }}); - let response = ""; - let port = null; - let secureConnectionSeen = false; - let closeState = {{ hadError: false }}; - let client = null; - - server.on("secureConnection", () => {{ - secureConnectionSeen = true; - }}); - server.on("error", reject); - server.listen(0, "127.0.0.1", () => {{ - port = server.address().port; - client = tls.connect({{ - host: "127.0.0.1", - port, - rejectUnauthorized: false, - }}, () => {{ - client.write("ping"); - }}); - client.setEncoding("utf8"); - client.on("data", (chunk) => {{ - response += chunk; - }}); - client.on("error", reject); - client.on("close", (hadError) => {{ - closeState = {{ hadError }}; - }}); - }}); -}}); - -console.log(JSON.stringify(summary)); -process.exit(0); -"#, - key = TLS_TEST_KEY_PEM, - cert = TLS_TEST_CERT_PEM, - ); - write_fixture(&cwd.join("entry.mjs"), &entry); - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from( - "[\"assert\",\"buffer\",\"console\",\"crypto\",\"events\",\"fs\",\"net\",\"path\",\"querystring\",\"stream\",\"string_decoder\",\"timers\",\"tls\",\"url\",\"util\",\"zlib\"]", - ), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-tls"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.clone()), - ); - } - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - for _ in 0..192 { - let next_event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes - .get_mut("proc-js-tls") - .and_then(|process| { - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll javascript tls rpc event") - }) - }; - let Some(event) = next_event else { - if exit_code.is_some() { - break; - } - continue; - }; - - match &event { - ActiveExecutionEvent::Stdout(chunk) => { - append_process_stream_chunk(&mut stdout, chunk, "proc-js-tls", "stdout"); - } - ActiveExecutionEvent::Stderr(chunk) => { - append_process_stream_chunk(&mut stderr, chunk, "proc-js-tls", "stderr"); - } - ActiveExecutionEvent::Exited(code) => { - exit_code = Some(*code); - } - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } => {} - } - - sidecar - .handle_execution_event(&vm_id, "proc-js-tls", event) - .expect("handle javascript tls rpc event"); - } - - let stdout = process_stream_to_string(&stdout); - let stderr = process_stream_to_string(&stderr); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse tls JSON"); - assert_eq!(parsed["response"], Value::String(String::from("pong:ping"))); - assert_eq!(parsed["received"], Value::String(String::from("ping"))); - assert_eq!(parsed["serverSecure"], Value::Bool(true)); - assert_eq!(parsed["encrypted"], Value::Bool(true)); - assert_eq!(parsed["hadError"], Value::Bool(false)); - assert_eq!( - parsed["remoteAddress"], - Value::String(String::from("127.0.0.1")) - ); - assert!( - parsed["serverPort"].as_u64().is_some_and(|port| port > 0), - "stdout: {stdout}" - ); - } - fn javascript_http_listen_and_close_registers_server() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http-listen"); - write_fixture(&cwd.join("entry.mjs"), ""); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-http-listen"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http-listen", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.http_listen"), - args: vec![Value::String(String::from( - "{\"serverId\":7,\"hostname\":\"127.0.0.1\",\"port\":0}", - ))], - }, - ) - .expect("listen via http bridge"); - - let payload: Value = - serde_json::from_str(listen.as_str().expect("listen payload string")) - .expect("parse listen payload"); - assert_eq!( - payload["address"]["family"], - Value::String(String::from("IPv4")) - ); - assert!( - payload["address"]["port"] - .as_u64() - .is_some_and(|port| port > 0), - "payload: {payload}" - ); - assert!( - sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-http-listen")) - .is_some_and(|process| process.http_servers.contains_key(&7)), - "HTTP server was not registered", - ); - - let close = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http-listen", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.http_close"), - args: vec![json!(7)], - }, - ) - .expect("close http bridge server"); - assert_eq!(close, Value::Null); - assert!( - sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-http-listen")) - .is_some_and(|process| process.http_servers.is_empty()), - "HTTP server should be removed after close", - ); - } - fn javascript_http_respond_records_pending_response() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http-respond"); - write_fixture(&cwd.join("entry.mjs"), ""); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-http-respond"); - - let response_json = String::from( - "{\"status\":200,\"headers\":[[\"content-type\",\"text/plain\"]],\"body\":\"cG9uZw==\",\"bodyEncoding\":\"base64\"}", - ); - { - let vm = sidecar.vms.get_mut(&vm_id).expect("vm"); - let process = vm - .active_processes - .get_mut("proc-js-http-respond") - .expect("javascript process"); - process.pending_http_requests.insert((7, 9), None); - } - - let response = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http-respond", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("net.http_respond"), - args: vec![json!(7), json!(9), Value::String(response_json.clone())], - }, - ) - .expect("record http response"); - assert_eq!(response, Value::Null); - assert_eq!( - sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-http-respond")) - .and_then(|process| process.pending_http_requests.get(&(7, 9))) - .cloned(), - Some(Some(response_json)), - ); - } - - fn javascript_http_respond_rejects_oversized_pending_response() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http-respond-oversized"); - write_fixture(&cwd.join("entry.mjs"), ""); - start_fake_javascript_process( - &mut sidecar, - &vm_id, - &cwd, - "proc-js-http-respond-oversized", - ); - - let oversized_body = "a".repeat(crate::wire::DEFAULT_MAX_FRAME_BYTES); - let response_json = format!(r#"{{"status":200,"body":"{oversized_body}"}}"#); - assert!(response_json.len() > crate::wire::DEFAULT_MAX_FRAME_BYTES); - { - let vm = sidecar.vms.get_mut(&vm_id).expect("vm"); - let process = vm - .active_processes - .get_mut("proc-js-http-respond-oversized") - .expect("javascript process"); - process.pending_http_requests.insert((7, 10), None); - } - - let error = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http-respond-oversized", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("net.http_respond"), - args: vec![json!(7), json!(10), Value::String(response_json)], - }, - ) - .expect_err("oversized http response should be rejected"); - assert!( - error.to_string().contains("net.http_respond payload is"), - "unexpected error: {error}" - ); - assert_eq!( - sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-http-respond-oversized")) - .and_then(|process| process.pending_http_requests.get(&(7, 10))) - .cloned(), - Some(None), - ); - } - - #[test] - fn vm_fetch_response_frame_limit_counts_protocol_overhead() { - let response = crate::protocol::ResponseFrame::new( - 1, - OwnershipScope::vm("conn", "session", "vm"), - ResponsePayload::VmFetchResult(crate::protocol::VmFetchResponse { - response_json: "a".repeat(crate::wire::DEFAULT_MAX_FRAME_BYTES), - }), - ); - - let error = crate::execution::ensure_vm_fetch_response_frame_within_limit( - &response, - crate::wire::DEFAULT_MAX_FRAME_BYTES, - ) - .expect_err("frame overhead should exceed the fetch response cap"); - assert!( - error.to_string().contains("protocol frame is"), - "unexpected error: {error}" - ); - } - - fn javascript_http_socket_backed_server_rejects_oversized_incomplete_headers() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http-oversized-incomplete-header"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import http from "node:http"; -import net from "node:net"; - -let requests = 0; -const server = http.createServer((_req, res) => { - requests += 1; - res.end("unexpected"); -}); - -await new Promise((resolve, reject) => { - server.once("error", reject); - server.listen(3000, "127.0.0.1", resolve); -}); - -const result = await new Promise((resolve, reject) => { - const client = net.connect({ host: "127.0.0.1", port: 3000 }); - let data = ""; - let error = null; - client.setEncoding("latin1"); - client.on("data", (chunk) => { - data += chunk; - if (data.startsWith("HTTP/1.1 400 Bad Request")) { - client.destroy(); - resolve({ data, error, requests }); - } - }); - client.on("error", (err) => { - error = err.code || err.name || String(err); - }); - client.on("close", () => { - resolve({ data, error, requests }); - }); - client.on("connect", () => { - client.write("GET / HTTP/1.1\r\nX-Oversized: " + "a".repeat(70 * 1024)); - }); - setTimeout(() => reject(new Error("client did not close")), 5000); -}); - -await new Promise((resolve) => server.close(resolve)); -console.log(JSON.stringify(result || { data: "", error: "missing-result", requests })); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-http-oversized-header"); - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let parsed: Value = - serde_json::from_str(stdout.trim()).expect("parse oversized header JSON"); - assert!( - parsed["data"] - .as_str() - .is_some_and(|data| data.starts_with("HTTP/1.1 400 Bad Request")), - "stdout: {stdout}" - ); - assert_eq!(parsed["requests"], Value::from(0)); - } - - #[test] - fn request_frame_limit_counts_generated_wire_overhead() { - let sidecar = create_test_sidecar_with_config(NativeSidecarConfig { - max_frame_bytes: 64, - ..NativeSidecarConfig::default() - }); - let request = RequestFrame::new( - 1, - OwnershipScope::connection("connection".repeat(16)), - RequestPayload::OpenSession(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: None, - }), - metadata: std::collections::HashMap::new(), - }), - ); - - let error = sidecar - .ensure_request_within_frame_limit(&request) - .expect_err("oversized request frame should be rejected"); - assert!( - error.to_string().contains("protocol frame is"), - "unexpected error: {error}" - ); - } - - fn javascript_http2_listen_connect_request_and_respond_round_trip() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http2-round-trip"); - write_fixture(&cwd.join("entry.mjs"), ""); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-http2"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.http2_server_listen"), - args: vec![Value::String(String::from( - "{\"serverId\":11,\"secure\":false,\"host\":\"127.0.0.1\",\"port\":0,\"backlog\":8,\"settings\":{}}", - ))], - }, - ) - .expect("listen via http2 bridge"); - let listen_payload: Value = - serde_json::from_str(listen.as_str().expect("listen payload")) - .expect("parse http2 listen payload"); - let port = listen_payload["address"]["port"] - .as_u64() - .expect("http2 listen port") as u16; - - let connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.http2_session_connect"), - args: vec![Value::String(format!( - "{{\"authority\":\"http://127.0.0.1:{port}\",\"protocol\":\"http:\",\"host\":\"127.0.0.1\",\"port\":{port},\"settings\":{{}}}}" - ))], - }, - ) - .expect("connect via http2 bridge"); - let connect_payload: Value = - serde_json::from_str(connect.as_str().expect("connect payload")) - .expect("parse http2 connect payload"); - let client_session_id = connect_payload["sessionId"] - .as_u64() - .expect("client session id"); - - let server_session = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2", - "net.http2_server_poll", - 11, - "serverSession", - ); - let server_session_id = server_session["extraNumber"] - .as_u64() - .or_else(|| server_session["id"].as_u64()) - .unwrap_or_default(); - assert!(server_session_id > 0, "event: {server_session}"); - - let stream_id = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.http2_session_request"), - args: vec![ - json!(client_session_id), - Value::String(String::from("{\":method\":\"GET\",\":path\":\"/ping\"}")), - Value::String(String::from("{\"endStream\":true}")), - ], - }, - ) - .expect("issue http2 request") - .as_u64() - .expect("client stream id"); - - let server_stream = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2", - "net.http2_server_poll", - 11, - "serverStream", - ); - let server_stream_id = server_stream["data"] - .as_str() - .expect("server stream data") - .parse::() - .expect("server stream id"); - assert!(server_stream_id > 0, "event: {server_stream}"); - let _ = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2", - "net.http2_server_poll", - 11, - "serverStreamEnd", - ); - - let respond = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("net.http2_stream_respond"), - args: vec![ - json!(server_stream_id), - Value::String(String::from( - "{\":status\":200,\"content-type\":\"text/plain\"}", - )), - ], - }, - ) - .expect("respond over http2"); - assert_eq!(respond, Value::Null); - - let wrote = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("net.http2_stream_write"), - args: vec![ - json!(server_stream_id), - json!(base64::engine::general_purpose::STANDARD.encode("pong")), - ], - }, - ) - .expect("write http2 body"); - assert_eq!(wrote, Value::Bool(true)); - - let ended = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("net.http2_stream_end"), - args: vec![json!(server_stream_id), Value::Null], - }, - ) - .expect("end http2 stream"); - assert_eq!(ended, Value::Bool(true)); - - let response_headers = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2", - "net.http2_session_poll", - client_session_id, - "clientResponseHeaders", - ); - assert_eq!( - response_headers["id"].as_u64(), - Some(stream_id), - "response event: {response_headers}" - ); - - let response_data = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2", - "net.http2_session_poll", - client_session_id, - "clientData", - ); - let body = base64::engine::general_purpose::STANDARD - .decode(response_data["data"].as_str().expect("response body")) - .expect("decode http2 body"); - assert_eq!(String::from_utf8(body).expect("utf8 body"), "pong"); - - let _ = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2", - "net.http2_session_poll", - client_session_id, - "clientEnd", - ); - - let close = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("net.http2_session_close"), - args: vec![json!(client_session_id)], - }, - ) - .expect("close http2 client session"); - assert_eq!(close, Value::Null); - - let server_close = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 8, - method: String::from("net.http2_server_close"), - args: vec![json!(11)], - }, - ) - .expect("close http2 server"); - assert_eq!(server_close, Value::Null); - } - - fn javascript_http2_guest_h2c_round_trip_does_not_deadlock() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http2-guest-h2c"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import { createRequire } from "module"; - -const require = createRequire(import.meta.url); -const http2 = require("node:http2"); -const server = http2.createServer(); - -server.on("stream", (stream, headers) => { - if (headers[":path"] !== "/") { - stream.respond({ ":status": 404 }); - stream.end("missing"); - return; - } - stream.respond({ ":status": 200, "content-type": "text/plain" }); - stream.end("hello-h2c"); -}); - -server.listen(0, "127.0.0.1", () => { - const address = server.address(); - const session = http2.connect(`http://127.0.0.1:${address.port}`); - const req = session.request({ ":path": "/" }); - let body = ""; - req.setEncoding("utf8"); - req.on("data", (chunk) => { - body += chunk; - }); - req.on("end", () => { - console.log(`BODY:${body}`); - session.close(); - server.close(() => process.exit(body === "hello-h2c" ? 0 : 2)); - }); - req.on("error", (error) => { - console.error(`REQ_ERROR:${error.message}`); - process.exit(1); - }); - session.on("error", (error) => { - console.error(`SESSION_ERROR:${error.message}`); - process.exit(1); - }); - req.end(); -}); - -setTimeout(() => { - console.error("TIMEOUT:http2 round trip did not finish"); - process.exit(3); -}, 4_000); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-http2-guest-h2c"); - assert_eq!(exit_code, Some(0), "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!( - stdout.contains("BODY:hello-h2c"), - "stdout:\n{stdout}\nstderr:\n{stderr}" - ); - } - - fn javascript_http2_request_handler_round_trip_runs_twice_in_one_vm() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http2-request-handler-twice"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import { createRequire } from "module"; - -const require = createRequire(import.meta.url); -const http2 = require("node:http2"); -const server = http2.createServer(); -const bodies = []; - -server.on("request", (req, res) => { - res.setHeader("content-type", "text/plain"); - res.end(`reply:${req.url}`); -}); - -function once(session, path) { - return new Promise((resolve, reject) => { - const req = session.request({ ":path": path }); - let body = ""; - req.setEncoding("utf8"); - req.on("data", (chunk) => { - body += chunk; - }); - req.on("end", () => resolve(body)); - req.on("error", reject); - req.end(); - }); -} - -server.listen(0, "127.0.0.1", async () => { - const address = server.address(); - const session = http2.connect(`http://127.0.0.1:${address.port}`); - session.on("error", (error) => { - console.error(`SESSION_ERROR:${error.message}`); - process.exit(1); - }); - try { - bodies.push(await once(session, "/first")); - bodies.push(await once(session, "/second")); - console.log(`BODIES:${bodies.join(",")}`); - session.close(); - server.close(() => process.exit( - bodies.join(",") === "reply:/first,reply:/second" ? 0 : 2 - )); - } catch (error) { - console.error(`REQ_ERROR:${error.message}`); - process.exit(1); - } -}); - -setTimeout(() => { - console.error("TIMEOUT:http2 request handler round trips did not finish"); - process.exit(3); -}, 4_000); -"#, - ); - - let (stdout, stderr, exit_code) = run_javascript_entry( - &mut sidecar, - &vm_id, - &cwd, - "proc-js-http2-request-handler-twice", - ); - assert_eq!(exit_code, Some(0), "stdout:\n{stdout}\nstderr:\n{stderr}"); - assert!( - stdout.contains("BODIES:reply:/first,reply:/second"), - "stdout:\n{stdout}\nstderr:\n{stderr}" - ); - } - - fn javascript_http2_settings_pause_push_and_file_response_surfaces_work() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http2-surfaces"); - write_fixture(&cwd.join("entry.mjs"), ""); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-http2-surfaces"); - sidecar - .vms - .get_mut(&vm_id) - .expect("javascript vm") - .active_processes - .get_mut("proc-js-http2-surfaces") - .expect("javascript process") - .guest_cwd = String::from("/workspace"); - let host_only_path = cwd.join("host-only-reply.txt"); - write_fixture(&host_only_path, "host-only"); - sidecar - .vms - .get_mut(&vm_id) - .expect("javascript vm") - .kernel - .write_file("/workspace/reply.txt", b"from-vm-file".to_vec()) - .expect("seed VM response file"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10, - method: String::from("net.http2_server_listen"), - args: vec![Value::String(String::from( - "{\"serverId\":22,\"secure\":false,\"host\":\"127.0.0.1\",\"port\":0,\"settings\":{}}", - ))], - }, - ) - .expect("listen via http2 bridge"); - let port = serde_json::from_str::(listen.as_str().expect("listen payload")) - .expect("parse listen payload")["address"]["port"] - .as_u64() - .expect("port") as u16; - - let connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 11, - method: String::from("net.http2_session_connect"), - args: vec![Value::String(format!( - "{{\"authority\":\"http://127.0.0.1:{port}\",\"protocol\":\"http:\",\"host\":\"127.0.0.1\",\"port\":{port},\"settings\":{{}}}}" - ))], - }, - ) - .expect("connect via http2 bridge"); - let session_id = serde_json::from_str::(connect.as_str().expect("connect")) - .expect("parse connect payload")["sessionId"] - .as_u64() - .expect("session id"); - - let _ = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - "net.http2_server_poll", - 22, - "serverSession", - ); - - let settings = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 12, - method: String::from("net.http2_session_settings"), - args: vec![ - json!(session_id), - Value::String(String::from("{\"initialWindowSize\":1234}")), - ], - }, - ) - .expect("update http2 settings"); - assert_eq!(settings, Value::Null); - let settings_event = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - "net.http2_session_poll", - session_id, - "sessionLocalSettings", - ); - assert!( - settings_event["data"] - .as_str() - .is_some_and(|payload| payload.contains("1234")), - "settings event: {settings_event}" - ); - - let local_window = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 13, - method: String::from("net.http2_session_set_local_window_size"), - args: vec![json!(session_id), json!(4096)], - }, - ) - .expect("set local window size"); - let local_window_payload: Value = - serde_json::from_str(local_window.as_str().expect("window payload")) - .expect("parse local window payload"); - assert_eq!( - local_window_payload["state"]["localWindowSize"], - json!(4096) - ); - - let stream_id = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 14, - method: String::from("net.http2_session_request"), - args: vec![ - json!(session_id), - Value::String(String::from("{\":method\":\"GET\",\":path\":\"/file\"}")), - Value::String(String::from("{\"endStream\":true}")), - ], - }, - ) - .expect("request file response") - .as_u64() - .expect("stream id"); - let server_stream = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - "net.http2_server_poll", - 22, - "serverStream", - ); - let server_stream_id = server_stream["data"] - .as_str() - .expect("server stream data") - .parse::() - .expect("server stream id"); - - let pause = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 15, - method: String::from("net.http2_stream_pause"), - args: vec![json!(server_stream_id)], - }, - ) - .expect("pause http2 stream"); - assert_eq!(pause, Value::Null); - let resume = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 16, - method: String::from("net.http2_stream_resume"), - args: vec![json!(server_stream_id)], - }, - ) - .expect("resume http2 stream"); - assert_eq!(resume, Value::Null); - - let push_result = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 17, - method: String::from("net.http2_stream_push_stream"), - args: vec![ - json!(server_stream_id), - Value::String(String::from("{\":method\":\"GET\",\":path\":\"/pushed\"}")), - Value::String(String::from("{}")), - ], - }, - ) - .expect("push http2 stream"); - let push_payload: Value = - serde_json::from_str(push_result.as_str().expect("push payload")) - .expect("parse push payload"); - let pushed_stream_id = push_payload["streamId"].as_u64().expect("pushed stream id"); - - let pushed_close = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 18, - method: String::from("net.http2_stream_close"), - args: vec![json!(pushed_stream_id), json!(0)], - }, - ) - .expect("close pushed stream"); - assert_eq!(pushed_close, Value::Null); - - let host_file_response = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 19, - method: String::from("net.http2_stream_respond_with_file"), - args: vec![ - json!(server_stream_id), - Value::String(host_only_path.to_string_lossy().into_owned()), - Value::String(String::from( - "{\":status\":200,\"content-type\":\"text/plain\"}", - )), - Value::String(String::from("{}")), - ], - }, - ) - .expect_err("host-only file path should not be readable by HTTP/2 file response"); - match host_file_response { - SidecarError::Kernel(message) => { - assert!(message.contains("ENOENT"), "{message}"); - } - other => panic!("unexpected host file response error: {other:?}"), - } - - let file_response = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 20, - method: String::from("net.http2_stream_respond_with_file"), - args: vec![ - json!(server_stream_id), - Value::String(String::from("reply.txt")), - Value::String(String::from( - "{\":status\":200,\"content-type\":\"text/plain\"}", - )), - Value::String(String::from("{}")), - ], - }, - ) - .expect("respond with file"); - assert_eq!(file_response, Value::Null); - - let response_headers = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - "net.http2_session_poll", - session_id, - "clientResponseHeaders", - ); - assert_eq!(response_headers["id"].as_u64(), Some(stream_id)); - let response_data = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - "net.http2_session_poll", - session_id, - "clientData", - ); - let body = base64::engine::general_purpose::STANDARD - .decode(response_data["data"].as_str().expect("response body")) - .expect("decode file body"); - assert_eq!(String::from_utf8(body).expect("utf8 body"), "from-vm-file"); - - let close = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 21, - method: String::from("net.http2_session_close"), - args: vec![json!(session_id), json!(0)], - }, - ) - .expect("close http2 client session"); - assert_eq!(close, Value::Null); - - let server_close = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-surfaces", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 22, - method: String::from("net.http2_server_close"), - args: vec![json!(22)], - }, - ) - .expect("close http2 server"); - assert_eq!(server_close, Value::Null); - } - fn javascript_http2_secure_listen_connect_request_and_respond_round_trip() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http2-secure-round-trip"); - write_fixture(&cwd.join("entry.mjs"), ""); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-http2-secure"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-secure", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 20, - method: String::from("net.http2_server_listen"), - args: vec![Value::String( - json!({ - "serverId": 33, - "secure": true, - "host": "127.0.0.1", - "port": 0, - "backlog": 8, - "settings": {}, - "tls": { - "isServer": true, - "key": { "kind": "string", "data": TLS_TEST_KEY_PEM }, - "cert": { "kind": "string", "data": TLS_TEST_CERT_PEM }, - "ALPNProtocols": ["h2"], - } - }) - .to_string(), - )], - }, - ) - .expect("listen via secure http2 bridge"); - let listen_payload: Value = - serde_json::from_str(listen.as_str().expect("listen payload")) - .expect("parse http2 listen payload"); - let port = listen_payload["address"]["port"] - .as_u64() - .expect("http2 secure listen port") as u16; - - let connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-secure", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 21, - method: String::from("net.http2_session_connect"), - args: vec![Value::String( - json!({ - "authority": format!("https://127.0.0.1:{port}"), - "protocol": "https:", - "host": "127.0.0.1", - "port": port, - "settings": {}, - "tls": { - "servername": "localhost", - "rejectUnauthorized": false, - "ALPNProtocols": ["h2"], - } - }) - .to_string(), - )], - }, - ) - .expect("connect via secure http2 bridge"); - let connect_payload: Value = - serde_json::from_str(connect.as_str().expect("connect payload")) - .expect("parse secure http2 connect payload"); - let client_session_id = connect_payload["sessionId"] - .as_u64() - .expect("client session id"); - - let server_session = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2-secure", - "net.http2_server_poll", - 33, - "serverSession", - ); - let server_session_id = server_session["extraNumber"] - .as_u64() - .or_else(|| server_session["id"].as_u64()) - .unwrap_or_default(); - assert!(server_session_id > 0, "event: {server_session}"); - - let stream_id = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-secure", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 22, - method: String::from("net.http2_session_request"), - args: vec![ - json!(client_session_id), - Value::String(String::from("{\":method\":\"GET\",\":path\":\"/secure\"}")), - Value::String(String::from("{\"endStream\":true}")), - ], - }, - ) - .expect("issue secure http2 request") - .as_u64() - .expect("client stream id"); - - let server_stream = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2-secure", - "net.http2_server_poll", - 33, - "serverStream", - ); - let server_stream_id = server_stream["data"] - .as_str() - .expect("server stream data") - .parse::() - .expect("server stream id"); - - let respond = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-secure", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 23, - method: String::from("net.http2_stream_respond"), - args: vec![ - json!(server_stream_id), - Value::String(String::from( - "{\":status\":200,\"content-type\":\"text/plain\"}", - )), - ], - }, - ) - .expect("respond over secure http2"); - assert_eq!(respond, Value::Null); - - let ended = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-secure", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 24, - method: String::from("net.http2_stream_end"), - args: vec![ - json!(server_stream_id), - json!(base64::engine::general_purpose::STANDARD.encode("secure-pong")), - ], - }, - ) - .expect("end secure http2 stream"); - assert_eq!(ended, Value::Bool(true)); - - let response_headers = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2-secure", - "net.http2_session_poll", - client_session_id, - "clientResponseHeaders", - ); - assert_eq!(response_headers["id"].as_u64(), Some(stream_id)); - - let response_data = poll_http2_event( - &mut sidecar, - &vm_id, - "proc-js-http2-secure", - "net.http2_session_poll", - client_session_id, - "clientData", - ); - let body = base64::engine::general_purpose::STANDARD - .decode(response_data["data"].as_str().expect("response body")) - .expect("decode secure http2 body"); - assert_eq!( - String::from_utf8(body).expect("utf8 secure http2 body"), - "secure-pong" - ); - - let session_state: Value = serde_json::from_str( - connect_payload["state"] - .as_str() - .expect("session state payload"), - ) - .expect("parse secure session state"); - assert_eq!(session_state["encrypted"], json!(true)); - assert_eq!(session_state["socket"]["encrypted"], json!(true)); - } - fn javascript_http2_server_respond_records_pending_response() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-http2-respond"); - write_fixture(&cwd.join("entry.mjs"), ""); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-http2-respond"); - - let response_json = String::from( - "{\"status\":200,\"headers\":[[\"content-type\",\"text/plain\"]],\"body\":\"c2VjdXJlLXBvbmc=\",\"bodyEncoding\":\"base64\"}", - ); - { - let vm = sidecar.vms.get_mut(&vm_id).expect("vm"); - let process = vm - .active_processes - .get_mut("proc-js-http2-respond") - .expect("javascript process"); - process.pending_http_requests.insert((33, 44), None); - } - - let response = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-http2-respond", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 25, - method: String::from("net.http2_server_respond"), - args: vec![json!(33), json!(44), Value::String(response_json.clone())], - }, - ) - .expect("record http2 response"); - assert_eq!(response, Value::Bool(true)); - assert_eq!( - sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-http2-respond")) - .and_then(|process| process.pending_http_requests.get(&(33, 44))) - .cloned(), - Some(Some(response_json)), - ); - } - fn javascript_http_rpc_requests_gets_and_serves_over_guest_net() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-http-rpc-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import http from "node:http"; - -const summary = await new Promise((resolve, reject) => { - const requests = []; - let requestResponse = ""; - let getResponse = ""; - - const server = http.createServer((req, res) => { - let body = ""; - req.setEncoding("utf8"); - req.on("data", (chunk) => { - body += chunk; - }); - req.on("end", () => { - requests.push({ - method: req.method, - url: req.url, - body, - }); - res.end(`pong:${req.method}:${body || req.url}`); - }); - }); - - let port = null; - server.on("error", reject); - server.listen(0, "127.0.0.1", () => { - port = server.address().port; - const req = http.request( - { - host: "127.0.0.1", - method: "POST", - path: "/submit", - port, - }, - (res) => { - res.setEncoding("utf8"); - res.on("data", (chunk) => { - requestResponse += chunk; - }); - res.on("end", () => { - http - .get(`http://127.0.0.1:${port}/health`, (getRes) => { - getRes.setEncoding("utf8"); - getRes.on("data", (chunk) => { - getResponse += chunk; - }); - getRes.on("end", () => { - server.close(() => { - resolve({ - getResponse, - port, - requestResponse, - requests, - }); - }); - }); - }) - .on("error", reject); - }); - }, - ); - req.on("error", reject); - req.end("ping"); - }); -}); - -console.log(JSON.stringify(summary)); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-http"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse http JSON"); - assert_eq!( - parsed["requestResponse"], - Value::String(String::from("pong:POST:ping")) - ); - assert_eq!( - parsed["getResponse"], - Value::String(String::from("pong:GET:/health")) - ); - assert_eq!( - parsed["requests"][0]["url"], - Value::String(String::from("/submit")) - ); - assert_eq!( - parsed["requests"][1]["url"], - Value::String(String::from("/health")) - ); - assert!( - parsed["port"].as_u64().is_some_and(|port| port > 0), - "stdout: {stdout}" - ); - } - - fn javascript_http_external_get_reaches_host_listener() { - assert_node_available(); - - let listener = TcpListener::bind("127.0.0.1:0").expect("bind host HTTP listener"); - let port = listener - .local_addr() - .expect("host HTTP listener address") - .port(); - let (server_done_tx, server_done_rx) = mpsc::channel(); - let server = thread::spawn(move || { - let (mut stream, _) = listener.accept().expect("accept host HTTP request"); - let mut request = [0_u8; 1024]; - let read = stream.read(&mut request).expect("read host HTTP request"); - let request_text = String::from_utf8_lossy(&request[..read]); - assert!( - request_text.starts_with("GET /external HTTP/1.1\r\n"), - "unexpected request: {request_text:?}" - ); - stream - .write_all( - b"HTTP/1.1 200 OK\r\n\ - Transfer-Encoding: chunked\r\n\ - Connection: keep-alive\r\n\ - \r\n\ - 12\r\nexternal-host-body\r\n\ - 0\r\n\ - \r\n", - ) - .expect("write host HTTP response"); - stream.flush().expect("flush host HTTP response"); - let _ = server_done_rx.recv_timeout(Duration::from_secs(5)); - }); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVm(ConfigureVmRequest { - mounts: Vec::new(), - software: Vec::new(), - permissions: None, - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: std::collections::HashMap::new(), - loopback_exempt_ports: vec![port], - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - )) - .expect("configure loopback-exempt host listener port"); - - let cwd = temp_dir("secure-exec-sidecar-js-http-external-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - format!( - r#" -import http from "node:http"; - -const result = await Promise.race([ - new Promise((resolve, reject) => {{ - const req = http.get( - {{ - host: "127.0.0.1", - port: {port}, - path: "/external", - }}, - (res) => {{ - let body = ""; - res.setEncoding("utf8"); - res.on("data", (chunk) => {{ - body += chunk; - }}); - res.on("end", () => {{ - resolve({{ status: res.statusCode, body }}); - }}); - }}, - ); - req.on("error", reject); - }}), - new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 3000)), -]); - -console.log(JSON.stringify(result)); -"# - ), - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-http-external"); - let _ = server_done_tx.send(()); - server.join().expect("join host HTTP listener"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = - serde_json::from_str(stdout.trim()).expect("parse external http JSON"); - assert_eq!(parsed["status"], json!(200)); - assert_eq!( - parsed["body"], - Value::String(String::from("external-host-body")) - ); - } - - fn javascript_fetch_posts_to_guest_loopback_http_server() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-fetch-loopback-cwd"); - write_fixture( - &cwd.join("entry.mjs"), - r#" -import http from "node:http"; - -const summary = await new Promise((resolve, reject) => { - const requests = []; - const server = http.createServer((req, res) => { - let body = ""; - req.setEncoding("utf8"); - req.on("data", (chunk) => { - body += chunk; - }); - req.on("end", () => { - requests.push({ method: req.method, url: req.url, body }); - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ ok: true, method: req.method, received: body })); - }); - }); - - server.on("error", reject); - server.listen(0, "127.0.0.1", async () => { - try { - const port = server.address().port; - const response = await fetch(`http://127.0.0.1:${port}/data`, { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ key: "value" }), - }); - const payload = await response.json(); - server.close(() => resolve({ payload, requests })); - } catch (error) { - server.close(() => reject(error)); - } - }); -}); - -console.log(JSON.stringify(summary)); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-fetch-loopback"); - - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse fetch JSON"); - assert_eq!(parsed["payload"]["ok"], Value::Bool(true)); - assert_eq!( - parsed["payload"]["received"], - Value::String(String::from("{\"key\":\"value\"}")) - ); - assert_eq!( - parsed["requests"][0]["method"], - Value::String(String::from("POST")) - ); - assert_eq!( - parsed["requests"][0]["url"], - Value::String(String::from("/data")) - ); - } - - fn javascript_fetch_reaches_http_server_in_parallel_guest_process() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-js-cross-process-server-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - r#" -import http from "node:http"; - -const server = http.createServer((req, res) => { - let body = ""; - req.setEncoding("utf8"); - req.on("data", (chunk) => { - body += chunk; - }); - req.on("end", () => { - res.writeHead(200, { "content-type": "text/plain" }); - res.end(`${req.method}:${req.url}:${body}`); - }); -}); - -server.listen(3000, "127.0.0.1", () => { - console.log("READY"); -}); - -await new Promise(() => {}); -"#, - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let client_cwd = temp_dir("secure-exec-sidecar-js-cross-process-client-cwd"); - write_fixture( - &client_cwd.join("entry.mjs"), - r#" -const response = await fetch("http://127.0.0.1:3000/from-client", { - method: "POST", - body: "hello", -}); - -console.log(JSON.stringify({ - status: response.status, - body: await response.text(), -})); -"#, - ); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &client_cwd, "proc-js-client"); - - sidecar - .kill_process_internal(&vm_id, "proc-js-server", "SIGKILL") - .expect("kill javascript server process"); - - assert_eq!(exit_code, Some(0), "stdout: {stdout}\nstderr: {stderr}"); - let parsed: Value = - serde_json::from_str(stdout.trim()).expect("parse client fetch JSON"); - assert_eq!(parsed["status"], Value::from(200)); - assert_eq!( - parsed["body"], - Value::String(String::from("POST:/from-client:hello")) - ); - } - - fn vm_network_counts( - sidecar: &NativeSidecar, - vm_id: &str, - ) -> NetworkResourceCounts { - let vm = sidecar.vms.get(vm_id).expect("vm state"); - vm_network_resource_counts(vm) - } - - fn assert_network_counts_unchanged( - before: NetworkResourceCounts, - after: NetworkResourceCounts, - ) { - assert_eq!(after.sockets, before.sockets, "socket count changed"); - assert_eq!( - after.connections, before.connections, - "connection count changed" - ); - } - - #[allow(clippy::too_many_arguments)] - fn dispatch_host_vm_fetch( - sidecar: &mut NativeSidecar, - request_id: secure_exec_sidecar::protocol::RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - port: u16, - path: &str, - body: Option<&str>, - ) -> Result { - sidecar.dispatch_blocking(request( - request_id, - OwnershipScope::vm(connection_id, session_id, vm_id), - RequestPayload::VmFetch(crate::protocol::VmFetchRequest { - port, - method: if body.is_some() { - String::from("POST") - } else { - String::from("GET") - }, - path: String::from(path), - headers_json: String::from(r#"{"content-type":"text/plain"}"#), - body: body.map(String::from), - }), - )) - } - - fn rejected_response_message(result: DispatchResult) -> String { - match result.response.payload { - ResponsePayload::Rejected(rejected) => rejected.message, - other => panic!("expected rejected response, got {other:?}"), - } - } - - #[test] - fn vm_fetch_missing_kernel_tcp_listener_does_not_open_host_network() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let before = vm_network_counts(&sidecar, &vm_id); - let rejected = dispatch_host_vm_fetch( - &mut sidecar, - 900, - &connection_id, - &session_id, - &vm_id, - 3000, - "/missing", - None, - ) - .map(rejected_response_message) - .expect("missing listener should reject vm.fetch"); - assert!( - rejected.contains("could not find a guest HTTP listener on port 3000"), - "unexpected error: {rejected}" - ); - let after = vm_network_counts(&sidecar, &vm_id); - assert_network_counts_unchanged(before, after); - } - - fn vm_fetch_reaches_javascript_http_server_over_kernel_tcp() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-host-fetch-js-server-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - r#" -import http from "node:http"; - -const server = http.createServer((req, res) => { - let body = ""; - req.setEncoding("utf8"); - req.on("data", (chunk) => { - body += chunk; - }); - req.on("end", () => { - res.writeHead(200, { "content-type": "text/plain" }); - res.end(`${req.method}:${req.url}:${body}`); - }); -}); - -server.listen(3000, "127.0.0.1", () => { - console.log("READY"); -}); - -await new Promise(() => {}); -"#, - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let process = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-server")) - .expect("server process"); - assert!( - process.http_servers.is_empty(), - "http.createServer should not register a legacy object-mode HTTP server", - ); - assert!( - process - .tcp_listeners - .values() - .any(|listener| listener.kernel_socket_id.is_some()), - "http.createServer should register a kernel TCP listener", - ); - - let response = sidecar - .dispatch_blocking(request( - 1, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::VmFetch(crate::protocol::VmFetchRequest { - port: 3000, - method: String::from("POST"), - path: String::from("/from-host"), - headers_json: String::from(r#"{"content-type":"text/plain"}"#), - body: Some(String::from("hello")), - }), - )) - .expect("host fetch reaches guest HTTP server"); - - sidecar - .kill_process_internal(&vm_id, "proc-js-server", "SIGKILL") - .expect("kill javascript server process"); - - match response.response.payload { - ResponsePayload::VmFetchResult(result) => { - let parsed: Value = - serde_json::from_str(&result.response_json).expect("parse fetch response"); - assert_eq!(parsed["status"], Value::from(200)); - assert_eq!( - parsed["body"], - Value::String( - base64::engine::general_purpose::STANDARD - .encode("POST:/from-host:hello") - ) - ); - assert_eq!( - parsed["bodyEncoding"], - Value::String(String::from("base64")) - ); - } - other => panic!("unexpected vm_fetch response payload: {other:?}"), - } - } - - fn vm_fetch_kernel_tcp_decodes_chunked_response_body() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-host-fetch-js-chunked-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - r#" -import http from "node:http"; - -const server = http.createServer((_req, res) => { - res.writeHead(200, { "content-type": "text/plain" }); - res.write("hello "); - res.write("chunked"); - res.end(); -}); - -server.listen(3000, "127.0.0.1", () => { - console.log("READY"); -}); - -await new Promise(() => {}); -"#, - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let response = dispatch_host_vm_fetch( - &mut sidecar, - 907, - &connection_id, - &session_id, - &vm_id, - 3000, - "/chunked", - None, - ) - .expect("host fetch reaches chunked guest HTTP server"); - - sidecar - .kill_process_internal(&vm_id, "proc-js-server", "SIGKILL") - .expect("kill javascript server process"); - - match response.response.payload { - ResponsePayload::VmFetchResult(result) => { - let parsed: Value = - serde_json::from_str(&result.response_json).expect("parse fetch response"); - assert_eq!(parsed["status"], Value::from(200)); - assert_eq!( - parsed["bodyEncoding"], - Value::String(String::from("base64")) - ); - let body = base64::engine::general_purpose::STANDARD - .decode(parsed["body"].as_str().expect("base64 response body")) - .expect("decode response body"); - assert_eq!(body, b"hello chunked"); - assert!( - !body.windows(3).any(|window| window == b"\r\n6"), - "chunk framing leaked into decoded body: {body:?}" - ); - } - other => panic!("unexpected vm_fetch response payload: {other:?}"), - } - } - - fn vm_fetch_kernel_tcp_rejects_chunked_with_content_length() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-host-fetch-js-chunked-cl-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - r#" -import net from "node:net"; - -const server = net.createServer((socket) => { - socket.end( - "HTTP/1.1 200 OK\r\n" + - "Transfer-Encoding: chunked\r\n" + - "Content-Length: 5\r\n" + - "\r\n" + - "5\r\nhello\r\n0\r\n\r\n" - ); -}); - -server.listen(3000, "127.0.0.1", () => { - console.log("READY"); -}); - -await new Promise(() => {}); -"#, - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let rejected = dispatch_host_vm_fetch( - &mut sidecar, - 908, - &connection_id, - &session_id, - &vm_id, - 3000, - "/invalid", - None, - ) - .map(rejected_response_message) - .expect("invalid chunked response should reject vm.fetch"); - - sidecar - .kill_process_internal(&vm_id, "proc-js-server", "SIGKILL") - .expect("kill javascript server process"); - - assert!( - rejected.contains("Transfer-Encoding: chunked") - && rejected.contains("Content-Length"), - "unexpected error: {rejected}" - ); - } - - fn vm_fetch_kernel_tcp_socket_cap_failure_closes_no_extra_resources() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([(String::from("resource.max_sockets"), String::from("1"))]), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-host-fetch-js-cap-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - r#" -import http from "node:http"; - -const server = http.createServer((_req, res) => { - res.end("ok"); -}); - -server.listen(3000, "127.0.0.1", () => { - console.log("READY"); -}); - -await new Promise(() => {}); -"#, - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let before = vm_network_counts(&sidecar, &vm_id); - assert_eq!(before.sockets, 1, "server listener should own one socket"); - let rejected = dispatch_host_vm_fetch( - &mut sidecar, - 901, - &connection_id, - &session_id, - &vm_id, - 3000, - "/cap", - None, - ) - .map(rejected_response_message) - .expect("vm.fetch should honor socket cap before creating client socket"); - assert!( - rejected.contains("EAGAIN: maximum socket count reached"), - "unexpected error: {rejected}" - ); - let after = vm_network_counts(&sidecar, &vm_id); - assert_network_counts_unchanged(before, after); - - sidecar - .kill_process_internal(&vm_id, "proc-js-server", "SIGKILL") - .expect("kill javascript server process"); - } - - fn vm_fetch_kernel_tcp_oversized_response_closes_client_socket() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-host-fetch-js-oversized-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - format!( - r#" -import http from "node:http"; - -const body = "x".repeat({}); -const server = http.createServer((_req, res) => {{ - res.writeHead(200, {{ "content-type": "text/plain" }}); - res.end(body); -}}); - -server.listen(3000, "127.0.0.1", () => {{ - console.log("READY"); -}}); - -await new Promise(() => {{}}); -"#, - crate::wire::DEFAULT_MAX_FRAME_BYTES + 1 - ), - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let before = vm_network_counts(&sidecar, &vm_id); - let rejected = dispatch_host_vm_fetch( - &mut sidecar, - 902, - &connection_id, - &session_id, - &vm_id, - 3000, - "/oversized", - None, - ) - .map(rejected_response_message) - .expect("oversized vm.fetch response should be rejected"); - assert!( - rejected.contains("vm.fetch raw response buffer is"), - "unexpected error: {rejected}" - ); - let after = vm_network_counts(&sidecar, &vm_id); - assert_eq!( - after.sockets, - before.sockets + 1, - "host-fetch client socket should close, leaving only the server's accepted socket" - ); - assert!( - after.connections <= before.connections + 1, - "host-fetch client connection leaked: before={before:?} after={after:?}" - ); - - sidecar - .kill_process_internal(&vm_id, "proc-js-server", "SIGKILL") - .expect("kill javascript server process"); - } - - fn vm_fetch_kernel_tcp_honors_configured_response_limit() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([( - String::from("limits.http.max_fetch_response_bytes"), - String::from("512"), - )]), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-host-fetch-js-config-limit-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - r#" -import http from "node:http"; - -const body = "x".repeat(1024); -const server = http.createServer((_req, res) => { - res.writeHead(200, { "content-type": "text/plain" }); - res.end(body); -}); - -server.listen(3000, "127.0.0.1", () => { - console.log("READY"); -}); - -await new Promise(() => {}); -"#, - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let before = vm_network_counts(&sidecar, &vm_id); - let rejected = dispatch_host_vm_fetch( - &mut sidecar, - 905, - &connection_id, - &session_id, - &vm_id, - 3000, - "/configured-limit", - None, - ) - .map(rejected_response_message) - .expect("configured response limit should reject vm.fetch"); - assert!( - rejected.contains("vm.fetch payload is") && rejected.contains("limit is 512"), - "unexpected error: {rejected}" - ); - let after = vm_network_counts(&sidecar, &vm_id); - assert!( - after.sockets <= before.sockets + 1, - "host-fetch client socket leaked: before={before:?} after={after:?}" - ); - assert!( - after.connections <= before.connections + 1, - "host-fetch client connection leaked: before={before:?} after={after:?}" - ); - - sidecar - .kill_process_internal(&vm_id, "proc-js-server", "SIGKILL") - .expect("kill javascript server process"); - } - - fn vm_fetch_kernel_tcp_malformed_response_closes_client_socket() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-host-fetch-js-malformed-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - r#" -import net from "node:net"; - -const server = net.createServer((socket) => { - socket.end("not-http\r\n\r\n"); -}); - -server.listen(3000, "127.0.0.1", () => { - console.log("READY"); -}); - -await new Promise(() => {}); -"#, - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let before = vm_network_counts(&sidecar, &vm_id); - let rejected = dispatch_host_vm_fetch( - &mut sidecar, - 906, - &connection_id, - &session_id, - &vm_id, - 3000, - "/malformed", - None, - ) - .map(rejected_response_message) - .expect("malformed response should reject vm.fetch"); - assert!( - rejected.contains("invalid vm.fetch HTTP response status line"), - "unexpected error: {rejected}" - ); - let after = vm_network_counts(&sidecar, &vm_id); - assert!( - after.sockets <= before.sockets + 1, - "host-fetch client socket leaked: before={before:?} after={after:?}" - ); - assert!( - after.connections <= before.connections + 1, - "host-fetch client connection leaked: before={before:?} after={after:?}" - ); - - sidecar - .kill_process_internal(&vm_id, "proc-js-server", "SIGKILL") - .expect("kill javascript server process"); - } - - fn vm_fetch_kernel_tcp_timeout_closes_client_socket() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-host-fetch-js-timeout-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - r#" -import http from "node:http"; - -const server = http.createServer(() => new Promise(() => {})); - -server.listen(3000, "127.0.0.1", () => { - console.log("READY"); -}); - -await new Promise(() => {}); -"#, - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let before = vm_network_counts(&sidecar, &vm_id); - std::env::set_var("SECURE_EXEC_TEST_HTTP_LOOPBACK_REQUEST_TIMEOUT_MS", "100"); - let rejected = dispatch_host_vm_fetch( - &mut sidecar, - 904, - &connection_id, - &session_id, - &vm_id, - 3000, - "/timeout", - None, - ) - .map(rejected_response_message) - .expect("stalled vm.fetch should reject after timeout"); - std::env::remove_var("SECURE_EXEC_TEST_HTTP_LOOPBACK_REQUEST_TIMEOUT_MS"); - assert!( - rejected.contains("vm.fetch timed out waiting for kernel TCP HTTP response"), - "unexpected error: {rejected}" - ); - let after = vm_network_counts(&sidecar, &vm_id); - assert_eq!( - after.sockets, - before.sockets + 1, - "host-fetch client socket should close, leaving only the server's stalled accepted socket" - ); - assert!( - after.connections <= before.connections + 1, - "host-fetch client connection leaked: before={before:?} after={after:?}" - ); - - sidecar - .kill_process_internal(&vm_id, "proc-js-server", "SIGKILL") - .expect("kill javascript server process"); - } - - fn vm_fetch_kernel_tcp_target_exit_cleans_up_process_resources() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let server_cwd = temp_dir("secure-exec-sidecar-host-fetch-js-target-exit-cwd"); - write_fixture( - &server_cwd.join("entry.mjs"), - r#" -import http from "node:http"; - -const server = http.createServer(() => new Promise(() => {})); - -server.listen(3000, "127.0.0.1", () => { - console.log("READY"); - setTimeout(() => { - throw new Error("target exited during vm.fetch"); - }, 10); -}); - -await new Promise(() => {}); -"#, - ); - start_fake_javascript_process(&mut sidecar, &vm_id, &server_cwd, "proc-js-server"); - wait_for_process_stdout_contains(&mut sidecar, &vm_id, "proc-js-server", "READY"); - - let rejected = dispatch_host_vm_fetch( - &mut sidecar, - 903, - &connection_id, - &session_id, - &vm_id, - 3000, - "/exit", - None, - ) - .map(rejected_response_message) - .expect("target exit should reject vm.fetch"); - assert!( - rejected.contains("vm.fetch target exited before responding (exit code 1)"), - "unexpected error: {rejected}" - ); - - let vm = sidecar.vms.get(&vm_id).expect("vm state"); - assert!( - !vm.active_processes.contains_key("proc-js-server"), - "target process should be cleaned up after exit" - ); - let after = vm_network_resource_counts(vm); - assert_eq!(after.sockets, 0, "target exit should close sockets"); - assert_eq!(after.connections, 0, "target exit should close connections"); - } - - fn javascript_https_rpc_requests_and_serves_over_guest_tls() { - let _tls_lock = tls_service_test_lock(); - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-https-rpc-cwd"); - let entry = format!( - r#" -import https from "node:https"; - -const key = {key:?}; -const cert = {cert:?}; - -const summary = await new Promise((resolve, reject) => {{ - let received = ""; - let response = ""; - const server = https.createServer({{ key, cert }}, (req, res) => {{ - req.setEncoding("utf8"); - req.on("data", (chunk) => {{ - received += chunk; - }}); - req.on("end", () => {{ - res.end(`pong:${{req.method}}:${{received}}`); - }}); - }}); - - let port = null; - server.on("error", reject); - server.listen(0, "127.0.0.1", () => {{ - port = server.address().port; - const req = https.request({{ - host: "127.0.0.1", - method: "POST", - path: "/secure", - port, - rejectUnauthorized: false, - }}, (res) => {{ - res.setEncoding("utf8"); - res.on("data", (chunk) => {{ - response += chunk; - }}); - res.on("end", () => {{ - server.close(() => {{ - resolve({{ - port, - received, - response, - }}); - }}); - }}); - }}); - req.on("error", reject); - req.end("ping"); - }}); -}}); - -console.log(JSON.stringify(summary)); -"#, - key = TLS_TEST_KEY_PEM, - cert = TLS_TEST_CERT_PEM, - ); - write_fixture(&cwd.join("entry.mjs"), &entry); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-https"); - - assert!( - !stderr.contains("ERR_AGENTOS_NODE_SYNC_RPC"), - "unexpected sync RPC error: {stderr}" - ); - let parsed: Value = serde_json::from_str(stdout.trim()).expect("parse https JSON"); - assert_eq!(parsed["received"], Value::String(String::from("ping"))); - assert_eq!( - parsed["response"], - Value::String(String::from("pong:POST:ping")) - ); - assert!( - parsed["port"].as_u64().is_some_and(|port| port > 0), - "stdout: {stdout}, exit_code: {exit_code:?}" - ); - } - - fn javascript_loopback_tls_https_get_buffers_handshake_pending_write_work() { - let _tls_lock = tls_service_test_lock(); - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-loopback-tls-get-cwd"); - let entry = format!( - r#" - import https from "node:https"; - - const key = {key:?}; - const cert = {cert:?}; - -const body = await new Promise((resolve, reject) => {{ - const server = https.createServer({{ key, cert }}, (_req, res) => {{ - res.end("hello-loopback-tls"); - }}); - - server.on("error", reject); - server.listen(0, "127.0.0.1", () => {{ - const port = server.address().port; - let response = ""; - const req = https.get({{ - agent: false, - host: "127.0.0.1", - port, - path: "/", - rejectUnauthorized: false, - }}, (res) => {{ - res.setEncoding("utf8"); - res.on("data", (chunk) => {{ - response += chunk; - }}); - res.on("end", () => {{ - server.close(() => resolve(response)); - }}); - }}); - req.on("error", reject); - }}); -}}); - -console.log(`BODY:${{body}}`); - "#, - key = TLS_TEST_KEY_PEM, - cert = TLS_TEST_CERT_PEM, - ); - write_fixture(&cwd.join("entry.mjs"), &entry); - - let (stdout, stderr, exit_code) = - run_javascript_entry(&mut sidecar, &vm_id, &cwd, "proc-js-loopback-tls-get"); - - assert!( - !stderr.contains("ERR_AGENTOS_NODE_SYNC_RPC"), - "unexpected sync RPC error: {stderr}" - ); - assert!( - stdout.contains("BODY:hello-loopback-tls"), - "unexpected stdout: {stdout}, stderr: {stderr}, exit_code: {exit_code:?}" - ); - } - fn javascript_net_rpc_listens_accepts_connections_and_reports_listener_state() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-server-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-server"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 0, - "backlog": 2, - })], - }, - ) - .expect("listen through sidecar net RPC"); - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - let guest_port = listen["localPort"] - .as_u64() - .and_then(|value| u16::try_from(value).ok()) - .expect("guest listener port"); - let response = sidecar - .dispatch_blocking(request( - 1, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindListener(FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(guest_port), - path: None, - }), - )) - .expect("query sidecar listener"); - match response.response.payload { - ResponsePayload::ListenerSnapshot(snapshot) => { - let listener = snapshot.listener.expect("listener snapshot"); - assert_eq!(listener.process_id, "proc-js-server"); - assert_eq!(listener.host.as_deref(), Some("127.0.0.1")); - assert_eq!(listener.port, Some(guest_port)); - } - other => panic!("unexpected find_listener response payload: {other:?}"), - } - - let client = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect("connect guest tcp client"); - let client_socket_id = client["socketId"] - .as_str() - .expect("client socket id") - .to_string(); - - let accepted = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.server_poll"), - args: vec![json!(server_id), json!(250)], - }, - ) - .expect("accept connection"); - assert_eq!(accepted["type"], Value::from("connection")); - assert_eq!(accepted["localAddress"], Value::from("127.0.0.1")); - assert_eq!(accepted["localPort"], Value::from(guest_port)); - let socket_id = accepted["socketId"] - .as_str() - .expect("socket id") - .to_string(); - - let written = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("net.write"), - args: vec![ - json!(client_socket_id.clone()), - json!({ - "__agentOSType": "bytes", - "base64": base64::engine::general_purpose::STANDARD.encode("ping"), - }), - ], - }, - ) - .expect("write client payload"); - assert_eq!(written, Value::from(4)); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("net.shutdown"), - args: vec![json!(client_socket_id.clone())], - }, - ) - .expect("shutdown client write half"); - - let data = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("net.poll"), - args: vec![json!(socket_id.clone()), json!(250)], - }, - ) - .expect("poll socket data"); - assert_eq!(data["type"], Value::from("data")); - - let bytes = base64::engine::general_purpose::STANDARD - .decode(data["data"]["base64"].as_str().expect("base64 payload")) - .expect("decode payload"); - assert_eq!(bytes, b"ping"); - - let written = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("net.write"), - args: vec![ - json!(socket_id.clone()), - json!({ - "__agentOSType": "bytes", - "base64": base64::engine::general_purpose::STANDARD.encode("pong:ping"), - }), - ], - }, - ) - .expect("write response"); - assert_eq!(written, Value::from(9)); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 8, - method: String::from("net.shutdown"), - args: vec![json!(socket_id)], - }, - ) - .expect("shutdown write half"); - - let client_data = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 9, - method: String::from("net.poll"), - args: vec![json!(client_socket_id.clone()), json!(250)], - }, - ) - .expect("poll client response"); - assert_eq!(client_data["type"], Value::from("data")); - let client_bytes = base64::engine::general_purpose::STANDARD - .decode( - client_data["data"]["base64"] - .as_str() - .expect("client base64 payload"), - ) - .expect("decode client payload"); - assert_eq!(client_bytes, b"pong:ping"); - - let client_end = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-server", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10, - method: String::from("net.poll"), - args: vec![json!(client_socket_id), json!(250)], - }, - ) - .expect("poll client end"); - assert_eq!(client_end["type"], Value::from("end")); - } - fn javascript_net_rpc_reports_connection_counts_and_enforces_backlog() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-backlog-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-backlog"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 0, - "backlog": 1, - })], - }, - ) - .expect("listen through sidecar net RPC"); - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - let guest_port = listen["localPort"] - .as_u64() - .and_then(|value| u16::try_from(value).ok()) - .expect("listener port"); - - let first_client = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect("queue first backlog client"); - let first_client_socket_id = first_client["socketId"] - .as_str() - .expect("first client socket id") - .to_string(); - - let second_connect = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect_err("reject second queued backlog client"); - assert!( - second_connect.to_string().contains("backlog is full"), - "{second_connect}" - ); - - let first_connection = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("net.server_poll"), - args: vec![json!(server_id.clone()), json!(250)], - }, - ) - .expect("accept first backlog connection"); - assert_eq!(first_connection["type"], Value::from("connection")); - let first_socket_id = first_connection["socketId"] - .as_str() - .expect("first socket id") - .to_string(); - - let connection_count = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("net.server_connections"), - args: vec![json!(server_id.clone())], - }, - ) - .expect("query server connections"); - assert_eq!(connection_count, json!(1)); - - let second_poll = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("net.server_poll"), - args: vec![json!(server_id.clone()), json!(50)], - }, - ) - .expect("poll second backlog connection"); - assert_eq!(second_poll, Value::Null); - - let connection_count = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("net.server_connections"), - args: vec![json!(server_id.clone())], - }, - ) - .expect("query server connections after backlog rejection"); - assert_eq!(connection_count, json!(1)); - - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 8, - method: String::from("net.destroy"), - args: vec![json!(first_socket_id)], - }, - ) - .expect("destroy first backlog socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 9, - method: String::from("net.destroy"), - args: vec![json!(first_client_socket_id)], - }, - ) - .expect("destroy first backlog client socket"); - call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-backlog", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10, - method: String::from("net.server_close"), - args: vec![json!(server_id)], - }, - ) - .expect("close backlog listener"); - - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &vm_id, - DisposeReason::Requested, - ) - .expect("dispose backlog vm"); - } - fn javascript_net_poll_clamps_guest_wait_to_sidecar_ceiling() { - assert_eq!(clamp_javascript_net_poll_wait(0), Duration::ZERO); - assert_eq!( - clamp_javascript_net_poll_wait(10), - Duration::from_millis(10) - ); - assert_eq!( - clamp_javascript_net_poll_wait(10_000), - Duration::from_millis(50) - ); - assert_eq!( - clamp_javascript_net_poll_wait(u64::MAX), - Duration::from_millis(50) - ); - } - fn javascript_net_poll_timeout_does_not_block_concurrent_vm_dispose() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let poll_vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create poll vm"); - let dispose_vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create dispose vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-poll-clamp-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - - start_fake_javascript_process(&mut sidecar, &poll_vm_id, &cwd, "proc-js-poll"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &poll_vm_id, - "proc-js-poll", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 0, - })], - }, - ) - .expect("listen for net.poll clamp test"); - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - let guest_port = listen["localPort"] - .as_u64() - .and_then(|value| u16::try_from(value).ok()) - .expect("listener port"); - - let client = call_javascript_sync_rpc( - &mut sidecar, - &poll_vm_id, - "proc-js-poll", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": guest_port, - })], - }, - ) - .expect("connect poll client"); - let client_socket_id = client["socketId"] - .as_str() - .expect("client socket id") - .to_string(); - - let accepted = call_javascript_sync_rpc( - &mut sidecar, - &poll_vm_id, - "proc-js-poll", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.server_poll"), - args: vec![json!(server_id.clone()), json!(250)], - }, - ) - .expect("accept poll client"); - let server_socket_id = accepted["socketId"] - .as_str() - .expect("accepted socket id") - .to_string(); - - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("build local runtime for net.poll clamp test"); - let local = tokio::task::LocalSet::new(); - let cleanup_connection_id = connection_id.clone(); - let cleanup_session_id = session_id.clone(); - let cleanup_poll_vm_id = poll_vm_id.clone(); - let cleanup_server_socket_id = server_socket_id.clone(); - let concurrency_elapsed = runtime.block_on(local.run_until(async move { - let sidecar = std::rc::Rc::new(std::cell::RefCell::new(sidecar)); - let dispose_sidecar = std::rc::Rc::clone(&sidecar); - let poll_sidecar = std::rc::Rc::clone(&sidecar); - let dispose_connection_id = connection_id.clone(); - let dispose_session_id = session_id.clone(); - let dispose_vm_id_for_task = dispose_vm_id.clone(); - let poll_vm_id_for_task = poll_vm_id.clone(); - let server_socket_id_for_task = server_socket_id.clone(); - - let started = std::time::Instant::now(); - let dispose = tokio::task::spawn_local(async move { - tokio::task::yield_now().await; - let mut sidecar = dispose_sidecar.borrow_mut(); - let response = sidecar - .dispatch_blocking(request( - 4, - OwnershipScope::vm( - &dispose_connection_id, - &dispose_session_id, - &dispose_vm_id_for_task, - ), - RequestPayload::DisposeVm(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - )) - .expect("dispose second vm while first net.poll waits"); - match response.response.payload { - ResponsePayload::VmDisposed(_) => {} - other => panic!("unexpected dispose response payload: {other:?}"), - } - }); - let poll = tokio::task::spawn_local(async move { - let mut sidecar = poll_sidecar.borrow_mut(); - let poll_started = std::time::Instant::now(); - let response = call_javascript_sync_rpc( - &mut sidecar, - &poll_vm_id_for_task, - "proc-js-poll", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("net.poll"), - args: vec![json!(server_socket_id_for_task), json!(u64::MAX)], - }, - ) - .expect("poll response"); - (response, poll_started.elapsed()) - }); - - let (dispose_result, poll_result) = tokio::join!(dispose, poll); - dispose_result.expect("join dispose task"); - let (poll_response, poll_elapsed) = poll_result.expect("join poll task"); - assert_eq!(poll_response, Value::Null); - if run_timing_sensitive_tests() { - assert!( - poll_elapsed <= Duration::from_millis(200), - "net.poll stayed blocked too long: {poll_elapsed:?}" - ); - } - let sidecar = std::rc::Rc::try_unwrap(sidecar) - .expect("recover sidecar after local tasks") - .into_inner(); - (sidecar, started.elapsed()) - })); - let (mut sidecar, dispose_elapsed) = concurrency_elapsed; - if run_timing_sensitive_tests() { - assert!( - dispose_elapsed <= Duration::from_millis(200), - "dispose should not wait behind guest net.poll: {dispose_elapsed:?}" - ); - } - - call_javascript_sync_rpc( - &mut sidecar, - &cleanup_poll_vm_id, - "proc-js-poll", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("net.destroy"), - args: vec![json!(cleanup_server_socket_id)], - }, - ) - .expect("destroy accepted socket"); - call_javascript_sync_rpc( - &mut sidecar, - &cleanup_poll_vm_id, - "proc-js-poll", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("net.destroy"), - args: vec![json!(client_socket_id)], - }, - ) - .expect("destroy client socket"); - call_javascript_sync_rpc( - &mut sidecar, - &cleanup_poll_vm_id, - "proc-js-poll", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("net.server_close"), - args: vec![json!(server_id)], - }, - ) - .expect("close poll listener"); - sidecar - .dispose_vm_internal_blocking( - &cleanup_connection_id, - &cleanup_session_id, - &cleanup_poll_vm_id, - DisposeReason::Requested, - ) - .expect("dispose poll vm"); - } - fn javascript_network_bind_policy_restricts_hosts_and_ports() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([ - ( - String::from(VM_LISTEN_PORT_MIN_METADATA_KEY), - String::from("49152"), - ), - ( - String::from(VM_LISTEN_PORT_MAX_METADATA_KEY), - String::from("49160"), - ), - ]), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-bind-policy-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-bind-policy"); - - let unspecified = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-bind-policy", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "0.0.0.0", - "port": 49152, - })], - }, - ) - .expect("normalize unspecified TCP listen host onto VM-local loopback"); - assert_eq!(unspecified["localAddress"], Value::from("0.0.0.0")); - assert_eq!(unspecified["localPort"], Value::from(49152)); - - let non_loopback = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-bind-policy", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.listen"), - args: vec![json!({ - "host": "192.168.1.10", - "port": 49154, - })], - }, - ) - .expect_err("deny non-loopback TCP listen host"); - assert!( - non_loopback - .to_string() - .contains("must bind to loopback or unspecified addresses"), - "{non_loopback}" - ); - - let privileged = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-bind-policy", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 80, - })], - }, - ) - .expect_err("deny privileged port"); - assert!( - privileged - .to_string() - .contains("privileged listen port 80 requires"), - "{privileged}" - ); - - let out_of_range = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-bind-policy", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 40000, - })], - }, - ) - .expect_err("deny out-of-range port"); - assert!( - out_of_range - .to_string() - .contains("outside the allowed range 49152-49160"), - "{out_of_range}" - ); - - let udp_socket = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-bind-policy", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("dgram.createSocket"), - args: vec![json!({ "type": "udp4" })], - }, - ) - .expect("create udp socket"); - let udp_socket_id = udp_socket["socketId"] - .as_str() - .expect("udp socket id") - .to_string(); - - let udp_unspecified = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-bind-policy", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("dgram.bind"), - args: vec![ - json!(udp_socket_id), - json!({ - "address": "0.0.0.0", - "port": 49153, - }), - ], - }, - ) - .expect("normalize unspecified UDP bind host onto VM-local loopback"); - assert_eq!(udp_unspecified["localAddress"], Value::from("0.0.0.0")); - assert_eq!(udp_unspecified["localPort"], Value::from(49153)); - - let success = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-bind-policy", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 49155, - })], - }, - ) - .expect("allow loopback listener inside configured range"); - assert_eq!(success["localAddress"], Value::from("127.0.0.1")); - assert_eq!(success["localPort"], Value::from(49155)); - } - fn javascript_network_bind_policy_can_allow_privileged_guest_ports() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm_with_metadata( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - BTreeMap::from([ - ( - String::from(VM_LISTEN_PORT_MIN_METADATA_KEY), - String::from("1"), - ), - ( - String::from(VM_LISTEN_PORT_MAX_METADATA_KEY), - String::from("128"), - ), - ( - String::from(VM_LISTEN_ALLOW_PRIVILEGED_METADATA_KEY), - String::from("true"), - ), - ]), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-privileged-listen-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_id, &cwd, "proc-js-privileged"); - - let listen = call_javascript_sync_rpc( - &mut sidecar, - &vm_id, - "proc-js-privileged", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 80, - })], - }, - ) - .expect("allow privileged guest port"); - assert_eq!(listen["localAddress"], Value::from("127.0.0.1")); - assert_eq!(listen["localPort"], Value::from(80)); - } - fn javascript_network_listeners_are_isolated_per_vm_even_with_same_guest_port() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_a = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm a"); - let vm_b = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm b"); - let cwd_a = temp_dir("secure-exec-sidecar-js-net-isolation-a"); - let cwd_b = temp_dir("secure-exec-sidecar-js-net-isolation-b"); - write_fixture(&cwd_a.join("entry.mjs"), "setInterval(() => {}, 1000);"); - write_fixture(&cwd_b.join("entry.mjs"), "setInterval(() => {}, 1000);"); - start_fake_javascript_process(&mut sidecar, &vm_a, &cwd_a, "proc-a"); - start_fake_javascript_process(&mut sidecar, &vm_b, &cwd_b, "proc-b"); - - let listen_a = call_javascript_sync_rpc( - &mut sidecar, - &vm_a, - "proc-a", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 43111, - })], - }, - ) - .expect("listen on vm a"); - let listen_b = call_javascript_sync_rpc( - &mut sidecar, - &vm_b, - "proc-b", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 43111, - })], - }, - ) - .expect("listen on vm b"); - assert_eq!(listen_a["localPort"], Value::from(43111)); - assert_eq!(listen_b["localPort"], Value::from(43111)); - - let connect_a = call_javascript_sync_rpc( - &mut sidecar, - &vm_a, - "proc-a", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 43111, - })], - }, - ) - .expect("connect within vm a"); - let connect_b = call_javascript_sync_rpc( - &mut sidecar, - &vm_b, - "proc-b", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 2, - method: String::from("net.connect"), - args: vec![json!({ - "host": "127.0.0.1", - "port": 43111, - })], - }, - ) - .expect("connect within vm b"); - assert_eq!(connect_a["remotePort"], Value::from(43111)); - assert_eq!(connect_b["remotePort"], Value::from(43111)); - - let server_id_a = listen_a["serverId"] - .as_str() - .expect("server id a") - .to_string(); - let server_id_b = listen_b["serverId"] - .as_str() - .expect("server id b") - .to_string(); - let accepted_a = call_javascript_sync_rpc( - &mut sidecar, - &vm_a, - "proc-a", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.server_poll"), - args: vec![json!(server_id_a), json!(250)], - }, - ) - .expect("accept vm a connection"); - let accepted_b = call_javascript_sync_rpc( - &mut sidecar, - &vm_b, - "proc-b", - JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.server_poll"), - args: vec![json!(server_id_b), json!(250)], - }, - ) - .expect("accept vm b connection"); - assert_eq!(accepted_a["type"], Value::from("connection")); - assert_eq!(accepted_b["type"], Value::from("connection")); - assert_eq!(accepted_a["localPort"], Value::from(43111)); - assert_eq!(accepted_b["localPort"], Value::from(43111)); - - let query_a = sidecar - .dispatch_blocking(request( - 50, - OwnershipScope::vm(&connection_id, &session_id, &vm_a), - RequestPayload::FindListener(FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43111), - path: None, - }), - )) - .expect("query vm a listener"); - let query_b = sidecar - .dispatch_blocking(request( - 51, - OwnershipScope::vm(&connection_id, &session_id, &vm_b), - RequestPayload::FindListener(FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43111), - path: None, - }), - )) - .expect("query vm b listener"); - match query_a.response.payload { - ResponsePayload::ListenerSnapshot(snapshot) => { - let listener = snapshot.listener.expect("vm a listener"); - assert_eq!(listener.process_id, "proc-a"); - assert_eq!(listener.host.as_deref(), Some("127.0.0.1")); - assert_eq!(listener.port, Some(43111)); - } - other => panic!("unexpected vm a listener response: {other:?}"), - } - match query_b.response.payload { - ResponsePayload::ListenerSnapshot(snapshot) => { - let listener = snapshot.listener.expect("vm b listener"); - assert_eq!(listener.process_id, "proc-b"); - assert_eq!(listener.host.as_deref(), Some("127.0.0.1")); - assert_eq!(listener.port, Some(43111)); - } - other => panic!("unexpected vm b listener response: {other:?}"), - } - } - fn javascript_net_rpc_listens_and_connects_over_unix_domain_sockets() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-net-unix-cwd"); - write_fixture(&cwd.join("entry.mjs"), "setInterval(() => {}, 1000);"); - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from( - "[\"assert\",\"buffer\",\"console\",\"crypto\",\"events\",\"fs\",\"net\",\"path\",\"querystring\",\"stream\",\"string_decoder\",\"timers\",\"url\",\"util\",\"zlib\"]", - ), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-unix"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.clone()), - ); - } - - let bridge = sidecar.bridge.clone(); - let dns = sidecar.vms.get(&vm_id).expect("javascript vm").dns.clone(); - let limits = ResourceLimits::default(); - let socket_paths = JavascriptSocketPathContext { - sandbox_root: cwd.clone(), - mounts: Vec::new(), - listen_policy: VmListenPolicy::default(), - loopback_exempt_ports: BTreeSet::new(), - tcp_loopback_guest_to_host_ports: BTreeMap::new(), - http_loopback_targets: BTreeMap::new(), - udp_loopback_guest_to_host_ports: BTreeMap::new(), - udp_loopback_host_to_guest_ports: BTreeMap::new(), - used_tcp_guest_ports: BTreeMap::new(), - used_udp_guest_ports: BTreeMap::new(), - }; - let socket_path = "/tmp/secure-exec.sock"; - let host_socket_path = cwd.join("tmp/secure-exec.sock"); - - let listen = { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 1, - method: String::from("net.listen"), - args: vec![json!({ - "path": socket_path, - "backlog": 1, - })], - }, - &limits, - counts, - ) - .expect("listen on unix socket") - }; - let server_id = listen["serverId"].as_str().expect("server id").to_string(); - assert_eq!(listen["path"], Value::String(String::from(socket_path))); - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - assert!( - vm.kernel - .exists(socket_path) - .expect("kernel socket placeholder exists"), - "kernel did not expose unix socket path" - ); - } - assert!(host_socket_path.exists(), "host unix socket path missing"); - - let listener_lookup = sidecar - .dispatch_blocking(request( - 2, - OwnershipScope::vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindListener(FindListenerRequest { - host: None, - port: None, - path: Some(String::from(socket_path)), - }), - )) - .expect("query unix listener"); - match listener_lookup.response.payload { - ResponsePayload::ListenerSnapshot(snapshot) => { - let listener = snapshot.listener.expect("listener snapshot"); - assert_eq!(listener.process_id, "proc-js-unix"); - assert_eq!(listener.path.as_deref(), Some(socket_path)); - } - other => panic!("unexpected listener response payload: {other:?}"), - } - - let connect = { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 3, - method: String::from("net.connect"), - args: vec![json!({ - "path": socket_path, - })], - }, - &limits, - counts, - ) - .expect("connect to unix listener") - }; - let client_socket_id = connect["socketId"] - .as_str() - .expect("client socket id") - .to_string(); - assert_eq!( - connect["remotePath"], - Value::String(String::from(socket_path)) - ); - - let accepted = { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 4, - method: String::from("net.server_poll"), - args: vec![json!(server_id), json!(250)], - }, - &limits, - counts, - ) - .expect("accept unix socket connection") - }; - let server_socket_id = accepted["socketId"] - .as_str() - .expect("server socket id") - .to_string(); - assert_eq!( - accepted["localPath"], - Value::String(String::from(socket_path)) - ); - - { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - let connections = service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 5, - method: String::from("net.server_connections"), - args: vec![json!(server_id)], - }, - &limits, - counts, - ) - .expect("query unix server connections"); - assert_eq!(connections, json!(1)); - } - - { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 6, - method: String::from("net.write"), - args: vec![ - json!(client_socket_id), - json!({ - "__agentOSType": "bytes", - "base64": "cGluZw==", - }), - ], - }, - &limits, - counts, - ) - .expect("write unix client payload"); - } - - { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 7, - method: String::from("net.shutdown"), - args: vec![json!(client_socket_id)], - }, - &limits, - counts, - ) - .expect("shutdown unix client write half"); - } - - let server_data = { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 8, - method: String::from("net.poll"), - args: vec![json!(server_socket_id), json!(250)], - }, - &limits, - counts, - ) - .expect("poll unix server socket data") - }; - assert_eq!( - server_data["data"]["base64"], - Value::String(String::from("cGluZw==")) - ); - - { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - let server_end = service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 9, - method: String::from("net.poll"), - args: vec![json!(server_socket_id), json!(250)], - }, - &limits, - counts, - ) - .expect("poll unix server socket end"); - assert_eq!(server_end["type"], Value::String(String::from("end"))); - } - - { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 10, - method: String::from("net.write"), - args: vec![ - json!(server_socket_id), - json!({ - "__agentOSType": "bytes", - "base64": "cG9uZw==", - }), - ], - }, - &limits, - counts, - ) - .expect("write unix server payload"); - } - - { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 11, - method: String::from("net.shutdown"), - args: vec![json!(server_socket_id)], - }, - &limits, - counts, - ) - .expect("shutdown unix server write half"); - } - - let client_data = { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 12, - method: String::from("net.poll"), - args: vec![json!(client_socket_id), json!(250)], - }, - &limits, - counts, - ) - .expect("poll unix client socket data") - }; - assert_eq!( - client_data["data"]["base64"], - Value::String(String::from("cG9uZw==")) - ); - - { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - let client_end = service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 13, - method: String::from("net.poll"), - args: vec![json!(client_socket_id), json!(250)], - }, - &limits, - counts, - ) - .expect("poll unix client socket end"); - assert_eq!(client_end["type"], Value::String(String::from("end"))); - } - - for (id, request_id) in [(&client_socket_id, 14_u64), (&server_socket_id, 15_u64)] { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: request_id, - method: String::from("net.destroy"), - args: vec![json!(id)], - }, - &limits, - counts, - ) - .expect("destroy unix socket"); - } - - { - let counts = sidecar - .vms - .get(&vm_id) - .and_then(|vm| vm.active_processes.get("proc-js-unix")) - .expect("unix process") - .network_resource_counts(); - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - let process = vm - .active_processes - .get_mut("proc-js-unix") - .expect("unix process"); - service_javascript_net_sync_rpc( - &bridge, - &vm_id, - &dns, - &socket_paths, - &mut vm.kernel, - process, - &JavascriptSyncRpcRequest { - raw_bytes_args: std::collections::HashMap::new(), - id: 16, - method: String::from("net.server_close"), - args: vec![json!(server_id)], - }, - &limits, - counts, - ) - .expect("close unix listener"); - } - - sidecar - .dispose_vm_internal_blocking( - &connection_id, - &session_id, - &vm_id, - DisposeReason::Requested, - ) - .expect("dispose unix vm"); - } - fn javascript_child_process_rpc_spawns_nested_node_processes_inside_vm_kernel() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-child-process-cwd"); - write_fixture( - &cwd.join("child.mjs"), - r#" -import fs from "node:fs"; - -const note = fs.readFileSync("/rpc/note.txt", "utf8").trim(); -console.log(`${process.argv[2]}:${process.pid}:${process.ppid}:${note}`); -"#, - ); - write_fixture( - &cwd.join("entry.mjs"), - r#" -const { execSync, spawn } = require("node:child_process"); - -const child = spawn("node", ["./child.mjs", "spawn"], { - stdio: ["ignore", "pipe", "pipe"], -}); -let spawnOutput = ""; -let spawnError = ""; -child.stdout.setEncoding("utf8"); -child.stderr.setEncoding("utf8"); -child.stdout.on("data", (chunk) => { - spawnOutput += chunk; -}); -child.stderr.on("data", (chunk) => { - spawnError += chunk; -}); -await new Promise((resolve, reject) => { - child.on("error", reject); - child.on("close", (code) => { - if (code !== 0) { - reject(new Error(`spawn exit ${code}: ${spawnError}`)); - return; - } - resolve(); - }); -}); - -const execOutput = execSync("node ./child.mjs exec", { - encoding: "utf8", -}).trim(); - -console.log(JSON.stringify({ - parentPid: process.pid, - childPid: child.pid, - spawnOutput: spawnOutput.trim(), - execOutput, -})); -"#, - ); - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .write_file("/rpc/note.txt", b"hello from nested child".to_vec()) - .expect("seed rpc note"); - vm.kernel - .write_file( - "/root/child.mjs", - fs::read(cwd.join("child.mjs")).expect("read child fixture"), - ) - .expect("seed nested child fixture"); - } - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from( - "[\"assert\",\"buffer\",\"console\",\"child_process\",\"crypto\",\"events\",\"fs\",\"path\",\"querystring\",\"stream\",\"string_decoder\",\"timers\",\"url\",\"util\",\"zlib\"]", - ), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start fake javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-child"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.clone()), - ); - } - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - for _ in 0..96 { - let next_event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes - .get_mut("proc-js-child") - .and_then(|process| { - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll javascript child_process event") - }) - }; - let Some(event) = next_event else { - if exit_code.is_some() { - break; - } - continue; - }; - - match &event { - ActiveExecutionEvent::Stdout(chunk) => { - append_process_stream_chunk(&mut stdout, chunk, "proc-js-child", "stdout"); - } - ActiveExecutionEvent::Stderr(chunk) => { - append_process_stream_chunk(&mut stderr, chunk, "proc-js-child", "stderr"); - } - ActiveExecutionEvent::Exited(code) => exit_code = Some(*code), - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } => {} - } - - sidecar - .handle_execution_event(&vm_id, "proc-js-child", event) - .expect("handle javascript child_process event"); - } - - let stdout = process_stream_to_string(&stdout); - let stderr = process_stream_to_string(&stderr); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = - serde_json::from_str(stdout.trim()).expect("parse child_process JSON"); - let parent_pid = parsed["parentPid"].as_u64().expect("parent pid") as u32; - let child_pid = parsed["childPid"].as_u64().expect("child pid") as u32; - let spawn_parts = parsed["spawnOutput"] - .as_str() - .expect("spawn output") - .split(':') - .map(str::to_owned) - .collect::>(); - let exec_parts = parsed["execOutput"] - .as_str() - .expect("exec output") - .split(':') - .map(str::to_owned) - .collect::>(); - - assert_eq!(spawn_parts[0], "spawn"); - assert_eq!(spawn_parts[1].parse::().expect("spawn pid"), child_pid); - assert_eq!( - spawn_parts[2].parse::().expect("spawn ppid"), - parent_pid - ); - assert_eq!(spawn_parts[3], "hello from nested child"); - assert_eq!(exec_parts[0], "exec"); - assert_eq!(exec_parts[2].parse::().expect("exec ppid"), parent_pid); - assert_eq!(exec_parts[3], "hello from nested child"); - } - fn javascript_child_process_rpc_preserves_nested_sigchld_registrations() { - assert_node_available(); - - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - let cwd = temp_dir("secure-exec-sidecar-js-nested-sigchld-cwd"); - write_fixture( - &cwd.join("leaf.mjs"), - [ - "await new Promise((resolve) => setTimeout(resolve, 200));", - "console.log('leaf-exit');", - ] - .join("\n"), - ); - write_fixture( - &cwd.join("child.mjs"), - [ - "import { spawn } from 'node:child_process';", - "let sigchldCount = 0;", - "process.on('SIGCHLD', () => {", - " sigchldCount += 1;", - " console.log(`nested-sigchld:${sigchldCount}`);", - "});", - "console.log('nested-sigchld-registered');", - "await new Promise((resolve) => setTimeout(resolve, 75));", - "const child = spawn('node', ['./leaf.mjs'], { stdio: ['ignore', 'ignore', 'ignore'] });", - "await new Promise((resolve, reject) => {", - " child.on('error', reject);", - " child.on('close', (code, signal) => {", - " if (code !== 0 || signal !== null) {", - " reject(new Error(`leaf exit ${code} signal ${signal}`));", - " return;", - " }", - " resolve();", - " });", - "});", - "const deadline = Date.now() + 2000;", - "while (sigchldCount === 0 && Date.now() < deadline) {", - " await new Promise((resolve) => setTimeout(resolve, 10));", - "}", - "if (sigchldCount === 0) {", - " throw new Error('nested SIGCHLD was not delivered');", - "}", - "console.log(`nested-sigchld-final:${sigchldCount}`);", - ] - .join("\n"), - ); - write_fixture( - &cwd.join("entry.mjs"), - [ - "import { spawn } from 'node:child_process';", - "const child = spawn('node', ['./child.mjs'], { stdio: ['ignore', 'pipe', 'pipe'] });", - "let childStdout = '';", - "let childStderr = '';", - "child.stdout.setEncoding('utf8');", - "child.stdout.on('data', (chunk) => {", - " childStdout += chunk;", - "});", - "child.stderr.setEncoding('utf8');", - "child.stderr.on('data', (chunk) => {", - " childStderr += chunk;", - "});", - "const result = await new Promise((resolve, reject) => {", - " child.on('error', reject);", - " child.on('close', (code, signal) => resolve({ code, signal }));", - "});", - "console.log(JSON.stringify({", - " code: result.code,", - " signal: result.signal,", - " stdout: childStdout.trim(),", - " stderr: childStderr.trim(),", - "}));", - "if (result.code !== 0 || result.signal !== null) {", - " process.exitCode = result.code ?? 1;", - "}", - ] - .join("\n"), - ); - - let context = - sidecar - .javascript_engine - .create_context(CreateJavascriptContextRequest { - vm_id: vm_id.clone(), - bootstrap_module: None, - compile_cache_root: None, - }); - let execution = sidecar - .javascript_engine - .start_execution(StartJavascriptExecutionRequest { - limits: Default::default(), - guest_runtime: Default::default(), - vm_id: vm_id.clone(), - context_id: context.context_id, - argv: vec![String::from("./entry.mjs")], - env: BTreeMap::from([( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from( - "[\"assert\",\"buffer\",\"console\",\"child_process\",\"crypto\",\"events\",\"fs\",\"path\",\"querystring\",\"stream\",\"string_decoder\",\"timers\",\"url\",\"util\",\"zlib\"]", - ), - )]), - cwd: cwd.clone(), - inline_code: None, - wasm_module_bytes: None, - }) - .expect("start nested SIGCHLD javascript execution"); - - let kernel_handle = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.kernel - .write_file( - "/root/child.mjs", - fs::read(cwd.join("child.mjs")).expect("read child fixture"), - ) - .expect("seed nested child fixture"); - vm.kernel - .write_file( - "/root/leaf.mjs", - fs::read(cwd.join("leaf.mjs")).expect("read leaf fixture"), - ) - .expect("seed nested leaf fixture"); - vm.kernel - .spawn_process( - JAVASCRIPT_COMMAND, - vec![String::from("./entry.mjs")], - SpawnOptions { - requester_driver: Some(String::from(EXECUTION_DRIVER_NAME)), - cwd: Some(String::from("/")), - ..SpawnOptions::default() - }, - ) - .expect("spawn kernel javascript process") - }; - - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-nested-sigchld"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Javascript(execution), - ) - .with_host_cwd(cwd.clone()), - ); - } - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - for _ in 0..128 { - let next_event = { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes - .get_mut("proc-js-nested-sigchld") - .and_then(|process| { - process - .execution - .poll_event_blocking(Duration::from_secs(5)) - .expect("poll nested SIGCHLD event") - }) - }; - let Some(event) = next_event else { - if exit_code.is_some() { - break; - } - continue; - }; - - match &event { - ActiveExecutionEvent::Stdout(chunk) => { - append_process_stream_chunk( - &mut stdout, - chunk, - "proc-js-nested-sigchld", - "stdout", - ); - } - ActiveExecutionEvent::Stderr(chunk) => { - append_process_stream_chunk( - &mut stderr, - chunk, - "proc-js-nested-sigchld", - "stderr", - ); - } - ActiveExecutionEvent::Exited(code) => exit_code = Some(*code), - ActiveExecutionEvent::JavascriptSyncRpcRequest(_) - | ActiveExecutionEvent::PythonVfsRpcRequest(_) - | ActiveExecutionEvent::SignalState { .. } => {} - } - - sidecar - .handle_execution_event(&vm_id, "proc-js-nested-sigchld", event) - .expect("handle nested SIGCHLD event"); - } - - let stdout = process_stream_to_string(&stdout); - let stderr = process_stream_to_string(&stderr); - assert_eq!(exit_code, Some(0), "stderr: {stderr}"); - let parsed: Value = - serde_json::from_str(stdout.trim()).expect("parse nested SIGCHLD JSON"); - assert_eq!(parsed["code"].as_i64(), Some(0), "stdout: {stdout}"); - assert!(parsed["signal"].is_null(), "stdout: {stdout}"); - - let nested_stdout = parsed["stdout"].as_str().expect("nested child stdout"); - assert!( - nested_stdout.contains("nested-sigchld-registered"), - "missing registration output: {nested_stdout}" - ); - assert!( - nested_stdout.contains("nested-sigchld:1"), - "missing nested SIGCHLD delivery: {nested_stdout}" - ); - assert!( - nested_stdout.contains("nested-sigchld-final:1"), - "missing nested SIGCHLD final count: {nested_stdout}" - ); - assert_eq!( - parsed["stderr"].as_str(), - Some(""), - "nested child stderr should stay empty" - ); - } - fn javascript_child_process_poll_reports_echild_when_child_disappears_after_drain() { - let mut sidecar = create_test_sidecar(); - let (connection_id, session_id) = - authenticate_and_open_session(&mut sidecar).expect("authenticate and open session"); - let vm_id = create_vm( - &mut sidecar, - &connection_id, - &session_id, - PermissionsPolicy::allow_all(), - ) - .expect("create vm"); - - let kernel_handle = create_kernel_process_handle_for_tests(); - { - let vm = sidecar.vms.get_mut(&vm_id).expect("javascript vm"); - vm.active_processes.insert( - String::from("proc-js-child-gone"), - ActiveProcess::new( - kernel_handle.pid(), - kernel_handle, - GuestRuntimeKind::JavaScript, - ActiveExecution::Tool(ToolExecution::default()), - ), - ); - } - - sidecar - .pending_process_events - .push_back(ProcessEventEnvelope { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - vm_id: vm_id.clone(), - process_id: String::from("proc-js-child-gone/ghost-child"), - event: ActiveExecutionEvent::Stdout(b"queued-but-undeliverable".to_vec()), - }); - - let error = sidecar - .poll_javascript_child_process(&vm_id, "proc-js-child-gone", "ghost-child", 0) - .expect_err("missing child should surface ECHILD"); - match error { - SidecarError::Execution(message) => { - assert!( - message.starts_with("ECHILD:"), - "expected ECHILD code, got {message}" - ); - assert!( - message.contains("proc-js-child-gone/ghost-child"), - "expected child label in error, got {message}" - ); - } - other => panic!("expected execution error, got {other}"), - } - - let queued = sidecar - .pending_process_events - .front() - .expect("queued event should remain deferred"); - assert_eq!(queued.process_id, "proc-js-child-gone/ghost-child"); - assert_eq!(sidecar.pending_process_events.len(), 1); - } - fn javascript_child_process_internal_bootstrap_env_is_allowlisted() { - let filtered = - sanitize_javascript_child_process_internal_bootstrap_env(&BTreeMap::from([ - ( - String::from("AGENTOS_ALLOWED_NODE_BUILTINS"), - String::from("[\"fs\"]"), - ), - ( - String::from("AGENTOS_GUEST_PATH_MAPPINGS"), - String::from("[]"), - ), - ( - String::from("AGENTOS_VIRTUAL_PROCESS_UID"), - String::from("0"), - ), - ( - String::from("AGENTOS_VIRTUAL_PROCESS_VERSION"), - String::from("v24.0.0"), - ), - ( - String::from("AGENTOS_VIRTUAL_OS_HOSTNAME"), - String::from("secure-exec-test"), - ), - ( - String::from("AGENTOS_PARENT_NODE_ALLOW_CHILD_PROCESS"), - String::from("1"), - ), - ( - String::from("VISIBLE_MARKER"), - String::from("child-visible"), - ), - ])); - - assert_eq!( - filtered.get("AGENTOS_ALLOWED_NODE_BUILTINS"), - Some(&String::from("[\"fs\"]")) - ); - assert_eq!( - filtered.get("AGENTOS_GUEST_PATH_MAPPINGS"), - Some(&String::from("[]")) - ); - assert_eq!( - filtered.get("AGENTOS_VIRTUAL_PROCESS_UID"), - Some(&String::from("0")) - ); - assert_eq!( - filtered.get("AGENTOS_VIRTUAL_PROCESS_VERSION"), - Some(&String::from("v24.0.0")) - ); - assert_eq!( - filtered.get("AGENTOS_VIRTUAL_OS_HOSTNAME"), - Some(&String::from("secure-exec-test")) - ); - assert!(!filtered.contains_key("AGENTOS_PARENT_NODE_ALLOW_CHILD_PROCESS")); - assert!(!filtered.contains_key("VISIBLE_MARKER")); - } - fn run_service_suite() { - // Multiple libtest cases in this sidecar integration binary still - // trip teardown/init crashes around V8-backed execution paths, so - // keep the broad coverage in one top-level suite. - kernel_socket_queries_ignore_stale_sidecar_guest_addresses(); - find_listener_rejects_without_network_inspect_permission(); - find_listener_returns_listener_with_network_inspect_permission(); - find_bound_udp_rejects_without_network_inspect_permission(); - find_bound_udp_returns_socket_with_network_inspect_permission(); - get_process_snapshot_rejects_without_process_inspect_permission(); - get_process_snapshot_returns_processes_with_process_inspect_permission(); - get_resource_snapshot_rejects_without_process_inspect_permission(); - get_resource_snapshot_returns_kernel_and_queue_counts_with_process_inspect_permission(); - vm_network_resource_counts_ignore_duplicate_sidecar_kernel_entries(); - loopback_tls_transport_survives_concurrent_handshakes_without_panicking(); - loopback_tls_endpoint_read_survives_competing_drain_and_peer_drop(); - javascript_net_socket_wait_connect_reports_tcp_socket_info(); - javascript_net_socket_read_and_socket_options_work_for_tcp_sockets(); - javascript_net_cross_exec_loopback_routes_through_kernel_socket_table(); - javascript_net_upgrade_socket_aliases_use_tcp_socket_state(); - javascript_dgram_address_and_buffer_size_sync_rpcs_work(); - javascript_tls_client_upgrade_query_and_cipher_list_work(); - javascript_tls_server_client_hello_and_server_upgrade_work(); - javascript_net_server_accept_returns_timeout_then_pending_connection(); - javascript_kernel_stdin_reads_buffered_input_and_reports_timeout_and_eof(); - javascript_sync_rpc_pty_set_raw_mode_toggles_kernel_tty_discipline(); - dispose_vm_removes_per_vm_javascript_import_cache_directory(); - execution_dispose_vm_race_skips_stale_process_events_without_panicking(); - execution_javascript_sync_rpc_handler_ignores_stale_vm_and_process_races(); - execution_poll_event_smoke_skips_queued_stale_process_envelopes_after_dispose(); - execution_poll_event_concurrent_dispose_logs_stale_process_event(); - filesystem_requests_ignore_stale_vm_and_process_races(); - get_zombie_timer_count_reports_kernel_state_before_and_after_waitpid(); - parse_signal_accepts_full_guest_signal_table(); - runtime_child_liveness_only_tracks_owned_children(); - authenticated_connection_id_returns_error_for_unexpected_response(); - opened_session_id_returns_error_for_unexpected_response(); - created_vm_id_returns_error_for_unexpected_response(); - configure_vm_instantiates_memory_mounts_through_the_plugin_registry(); - configure_vm_applies_read_only_mount_wrappers(); - configure_vm_instantiates_host_dir_mounts_through_the_plugin_registry(); - configure_vm_passes_resource_read_limits_to_host_dir_mounts(); - configure_vm_passes_resource_read_limits_to_module_access_mounts(); - configure_vm_rejects_module_access_root_symlink_to_non_node_modules(); - configure_vm_js_bridge_mount_dispatches_filesystem_calls_via_sidecar_requests(); - configure_vm_js_bridge_mount_rejects_oversized_read_payloads(); - configure_vm_js_bridge_mount_rejects_pread_payloads_above_requested_length(); - configure_vm_js_bridge_mount_maps_callback_errors_to_errno_codes(); - configure_vm_instantiates_sandbox_agent_mounts_through_the_plugin_registry(); - configure_vm_instantiates_s3_mounts_through_the_plugin_registry(); - configure_vm_instantiates_object_s3_mounts_through_the_plugin_registry(); - configure_vm_instantiates_chunked_local_mounts_through_the_plugin_registry(); - bridge_permissions_map_symlink_operations_to_symlink_access(); - vm_limits_config_reads_filesystem_limits(); - create_vm_applies_filesystem_permission_descriptors_to_kernel_access(); - create_vm_without_permissions_defaults_to_static_deny_all(); - configure_vm_rollback_restore_failure_falls_back_to_static_deny_all(); - toolkit_registration_rollback_restore_failure_keeps_registry_consistent(); - create_vm_rejects_permission_rules_with_empty_operations(); - configure_vm_rejects_permission_rules_with_empty_paths_or_patterns(); - configure_vm_mounts_bypass_guest_fs_write_policy(); - guest_filesystem_link_and_truncate_preserve_hard_link_semantics(); - configure_vm_sensitive_mounts_bypass_guest_fs_mount_sensitive_policy(); - guest_mount_request_default_deny_rejects_without_changing_operator_mounts(); - scoped_host_filesystem_unscoped_target_requires_exact_guest_root_prefix(); - scoped_host_filesystem_realpath_preserves_paths_outside_guest_root(); - host_filesystem_realpath_fails_closed_on_circular_symlinks(); - configure_vm_host_dir_plugin_fails_closed_for_escape_symlinks(); - execute_starts_python_runtime_instead_of_rejecting_it(); - command_resolution_executes_wasm_command_from_sidecar_path(); - wasm_command_timeout_is_enforced_by_sidecar_poll_path(); - wasm_fd_write_sync_rpc_keeps_stdout_isolated_per_vm(); - wasm_path_open_read_goes_through_kernel_filesystem_permissions(); - wasm_path_open_write_goes_through_kernel_filesystem_permissions(); - wasm_fd_write_sync_rpc_routes_stdout_into_kernel_pty(); - javascript_child_process_searches_path_for_mounted_wasm_commands(); - javascript_child_process_shell_mode_without_guest_sh_fails_loudly(); - javascript_child_process_spawns_path_resolved_tool_commands(); - javascript_child_process_resolves_path_resolved_tool_commands_as_tools(); - javascript_child_process_spawns_internal_tool_command_paths(); - javascript_child_process_resolves_internal_tool_command_paths_as_tools(); - tools_register_host_callbacks_rejects_duplicate_names_without_replacing_existing_toolkit(); - tools_register_host_callbacks_rejects_registry_overflow_without_mutating_vm(); - tools_register_host_callbacks_rejects_total_tool_overflow_without_mutating_vm(); - tools_javascript_child_process_denies_host_callback_without_permission(); - tools_javascript_child_process_invokes_tool_with_matching_permission(); - tools_javascript_child_process_rejects_invalid_json_file_input_before_dispatch(); - tools_javascript_child_process_accepts_valid_json_input(); - command_resolution_executes_javascript_path_command_with_sidecar_mappings(); - command_resolution_executes_node_eval_command(); - command_resolution_rejects_unknown_command(); - python_vfs_rpc_requests_proxy_into_the_vm_kernel_filesystem(); - javascript_sync_rpc_requests_proxy_into_the_vm_kernel_filesystem(); - javascript_fs_promises_hot_metadata_ops_use_sync_semantics(); - python_vfs_rpc_paths_resolve_textually_and_defer_to_kernel_confinement(); - javascript_fs_sync_rpc_resolves_proc_self_against_the_kernel_process(); - javascript_fd_and_stream_rpc_requests_proxy_into_the_vm_kernel_filesystem(); - javascript_mapped_tmp_open_wx_uses_exclusive_create_once(); - wasm_shell_external_stdout_redirect_writes_file(); - wasm_shell_external_append_redirect_creates_and_concatenates(); - wasm_shell_external_stderr_redirect_writes_file(); - wasm_shell_builtin_and_external_redirects_match(); - javascript_imports_guest_written_modules_after_miss_work(); - javascript_fs_promises_batch_requests_before_waiting_on_sidecar_responses(); - javascript_crypto_basic_sync_rpcs_round_trip_through_sidecar(); - javascript_crypto_advanced_sync_rpcs_round_trip_through_sidecar(); - javascript_sqlite_sync_rpcs_round_trip_and_persist_vm_files(); - javascript_sqlite_builtin_round_trips_through_sidecar_sync_rpc(); - javascript_net_rpc_connects_over_vm_loopback(); - javascript_dgram_rpc_sends_and_receives_vm_loopback_packets(); - javascript_dns_rpc_resolves_localhost(); - javascript_network_ssrf_protection_blocks_private_dns_and_unowned_loopback_targets(); - javascript_dns_rpc_honors_vm_dns_overrides_and_net_connect_uses_sidecar_dns(); - javascript_network_dns_resolve_supports_standard_rrtypes(); - javascript_network_permission_callbacks_fire_for_dns_lookup_connect_and_listen(); - javascript_network_permission_denials_surface_eacces_to_guest_code(); - javascript_tls_rpc_connects_and_serves_over_guest_net(); - javascript_http_listen_and_close_registers_server(); - javascript_http_respond_records_pending_response(); - javascript_http_respond_rejects_oversized_pending_response(); - vm_fetch_response_frame_limit_counts_protocol_overhead(); - request_frame_limit_counts_generated_wire_overhead(); - javascript_http2_listen_connect_request_and_respond_round_trip(); - javascript_http2_guest_h2c_round_trip_does_not_deadlock(); - javascript_http2_request_handler_round_trip_runs_twice_in_one_vm(); - javascript_http2_settings_pause_push_and_file_response_surfaces_work(); - javascript_http2_secure_listen_connect_request_and_respond_round_trip(); - javascript_http2_server_respond_records_pending_response(); - javascript_http_rpc_requests_gets_and_serves_over_guest_net(); - javascript_http_external_get_reaches_host_listener(); - javascript_fetch_posts_to_guest_loopback_http_server(); - javascript_fetch_reaches_http_server_in_parallel_guest_process(); - javascript_net_rpc_listens_accepts_connections_and_reports_listener_state(); - javascript_net_rpc_reports_connection_counts_and_enforces_backlog(); - javascript_network_bind_policy_restricts_hosts_and_ports(); - javascript_network_bind_policy_can_allow_privileged_guest_ports(); - javascript_network_listeners_are_isolated_per_vm_even_with_same_guest_port(); - javascript_net_rpc_listens_and_connects_over_unix_domain_sockets(); - javascript_child_process_rpc_spawns_nested_node_processes_inside_vm_kernel(); - javascript_child_process_rpc_preserves_nested_sigchld_registrations(); - process_event_sender_is_bounded(); - pending_process_events_are_bounded(); - process_event_receiver_overflow_preserves_queued_event(); - tool_execution_event_overflow_is_reported(); - descendant_transfer_overflow_preserves_global_queue(); - exit_trailing_requeue_preserves_exit_when_queue_is_full(); - javascript_child_process_poll_reports_echild_when_child_disappears_after_drain(); - javascript_child_process_internal_bootstrap_env_is_allowlisted(); - javascript_net_poll_clamps_guest_wait_to_sidecar_ceiling(); - javascript_net_poll_timeout_does_not_block_concurrent_vm_dispose(); - } - - #[test] - fn service_sidecar_response_completion_is_bounded() { - completed_sidecar_responses_evict_oldest_beyond_cap(); - taking_sidecar_responses_releases_completion_gauge(); - } - - #[test] - fn service_toolkit_registry_is_bounded() { - tools_register_host_callbacks_rejects_registry_overflow_without_mutating_vm(); - tools_register_host_callbacks_rejects_total_tool_overflow_without_mutating_vm(); - } - - #[test] - fn service_process_output_collectors_are_bounded() { - let mut stream = Vec::new(); - append_process_stream_chunk(&mut stream, &[b'a'; 16], "proc-capture-limit", "stdout"); - assert_eq!(stream.len(), 16); - - assert!( - !process_stream_chunk_fits(MAX_SERVICE_PROCESS_STREAM_BYTES, 1), - "oversized process output should fail the test harness" - ); - } - - #[test] - fn service_process_event_queues_are_bounded() { - process_event_sender_is_bounded(); - pending_process_events_are_bounded(); - process_event_receiver_overflow_preserves_queued_event(); - tool_execution_event_overflow_is_reported(); - descendant_transfer_overflow_preserves_global_queue(); - exit_trailing_requeue_preserves_exit_when_queue_is_full(); - } - - #[test] - fn service_state_handle_tables_are_bounded() { - sqlite_database_handles_are_bounded(); - sqlite_statement_handles_are_bounded(); - } - - #[test] - fn aad_javascript_network_dns_javascript_net_poll_suite() { - run_service_suite(); - } - - #[test] - fn javascript_net_loopback_socket_churn_releases_kernel_slots_regression() { - run_isolated_service_test("net-loopback-socket-churn"); - } - - #[test] - fn javascript_net_loopback_wakes_reader_parked_before_write_regression() { - run_isolated_service_test("net-loopback-parked-reader-wake"); - } - - #[test] - fn javascript_net_loopback_reads_back_to_back_and_after_partial_drain_regression() { - run_isolated_service_test("net-loopback-edge-wake"); - } - - #[test] - fn javascript_net_unix_domain_echo_uses_reader_events_regression() { - run_isolated_service_test("net-unix-domain-reader-events"); - } - - #[test] - fn javascript_dgram_rpc_sends_and_receives_vm_loopback_packets_regression() { - run_isolated_service_test("dgram-loopback-events"); - } - - #[test] - fn javascript_http_external_get_reaches_host_listener_regression() { - javascript_http_external_get_reaches_host_listener(); - } - - #[test] - fn aaa_crypto_handle_tables_are_bounded() { - run_isolated_service_test("crypto-handle-tables"); - } - - #[test] - fn aac_http2_respond_with_file_reads_vm_filesystem() { - run_isolated_service_test("http2-file-response"); - } - - #[test] - fn aac_http2_guest_h2c_round_trip_does_not_deadlock() { - run_isolated_service_test("http2-guest-h2c"); - } - - #[test] - fn aac_http2_request_handler_round_trip_runs_twice_in_one_vm() { - run_isolated_service_test("http2-request-handler-twice"); - } - - #[test] - fn aac_javascript_imports_guest_written_modules_after_miss() { - run_isolated_service_test("javascript-import-fresh"); - } - - #[test] - fn javascript_fs_promises_hot_metadata_ops_use_sync_semantics_regression() { - run_isolated_service_test("javascript-fs-promises-hot-metadata"); - } - - #[test] - fn wasm_shell_external_stdout_redirect_writes_file_regression() { - run_isolated_service_test("wasm-shell-external-stdout-redirect"); - } - - #[test] - fn wasm_shell_external_append_redirect_creates_and_concatenates_regression() { - run_isolated_service_test("wasm-shell-external-append-redirect"); - } - - #[test] - fn wasm_shell_external_stderr_redirect_writes_file_regression() { - run_isolated_service_test("wasm-shell-external-stderr-redirect"); - } - - #[test] - fn wasm_shell_builtin_and_external_redirects_match_regression() { - run_isolated_service_test("wasm-shell-builtin-external-redirect-parity"); - } - - #[test] - fn javascript_mapped_shadow_readdir_sees_wasm_created_directory_regression() { - run_isolated_service_test("mapped-shadow-readdir-wasm-directory"); - } - - #[test] - fn javascript_mapped_shadow_readdir_merges_wasm_created_children_regression() { - run_isolated_service_test("mapped-shadow-readdir-wasm-children"); - } - - #[test] - fn javascript_mapped_shadow_readdir_unions_shadow_and_kernel_children_regression() { - run_isolated_service_test("mapped-shadow-readdir-shadow-kernel-union"); - } - - #[test] - fn javascript_mapped_shadow_readdir_sees_same_process_shadow_directory_regression() { - run_isolated_service_test("mapped-shadow-readdir-same-process-shadow"); - } - - #[test] - fn javascript_mapped_unlink_kernel_backed_no_resurrect_regression() { - run_isolated_service_test("mapped-unlink-kernel-backed-no-resurrect"); - } - - #[test] - fn javascript_readdir_raw_payload_preserves_dirent_semantics_regression() { - run_isolated_service_test("javascript-readdir-raw-dirent-semantics"); - } - - #[test] - fn javascript_writev_raw_payload_preserves_stream_copy_order_regression() { - run_isolated_service_test("javascript-writev-stream-copy-order"); - } - - #[test] - fn aab_wasm_command_timeout_is_enforced_by_sidecar_poll_path() { - run_isolated_service_test("wasm-command-timeout"); - } - - #[test] - fn aab_wasm_path_open_read_uses_kernel_filesystem_permissions() { - run_isolated_service_test("wasm-fs-permissions"); - } - - #[test] - fn aab_wasm_path_open_write_uses_kernel_filesystem_permissions() { - run_isolated_service_test("wasm-fs-write-permissions"); - } - - #[test] - fn aad_http_socket_backed_server_rejects_oversized_incomplete_headers() { - run_isolated_service_test("http-oversized-incomplete-header"); - } - - #[test] - fn aae_vm_fetch_reaches_javascript_http_server_over_kernel_tcp() { - run_isolated_service_test("vm-fetch-kernel-tcp-success"); - } - - #[test] - fn aaf_vm_fetch_kernel_tcp_decodes_chunked_response_body() { - run_isolated_service_test("vm-fetch-kernel-tcp-chunked"); - } - - #[test] - fn aag_vm_fetch_kernel_tcp_rejects_chunked_with_content_length() { - run_isolated_service_test("vm-fetch-kernel-tcp-chunked-content-length"); - } - - #[test] - fn aah_vm_fetch_kernel_tcp_socket_cap_failure_closes_no_extra_resources() { - run_isolated_service_test("vm-fetch-kernel-tcp-socket-cap"); - } - - #[test] - fn aai_vm_fetch_kernel_tcp_oversized_response_closes_client_socket() { - run_isolated_service_test("vm-fetch-kernel-tcp-oversized"); - } - - #[test] - fn aaj_vm_fetch_kernel_tcp_honors_configured_response_limit() { - run_isolated_service_test("vm-fetch-kernel-tcp-configured-limit"); - } - - #[test] - fn aak_vm_fetch_kernel_tcp_malformed_response_closes_client_socket() { - run_isolated_service_test("vm-fetch-kernel-tcp-malformed"); - } - - #[test] - fn aal_vm_fetch_kernel_tcp_timeout_closes_client_socket() { - run_isolated_service_test("vm-fetch-kernel-tcp-timeout"); - } - - #[test] - fn aam_vm_fetch_kernel_tcp_target_exit_cleans_up_process_resources() { - run_isolated_service_test("vm-fetch-kernel-tcp-target-exit"); - } - - #[test] - #[ignore = "flaky: high-level HTTPS over loopback TLS can deadlock the sync RPC bridge; lower-level TLS and dedicated loopback HTTPS regression still run"] - fn javascript_https_rpc_requests_and_serves_over_guest_tls_regression() { - javascript_https_rpc_requests_and_serves_over_guest_tls(); - } - - #[test] - fn javascript_loopback_tls_https_get_buffers_handshake_pending_write() { - run_isolated_service_test("loopback-tls-https-pending-write"); - } - - #[test] - fn loopback_tls_pending_write_buffer_cap_is_typed_limit_error() { - loopback_tls_pending_write_buffer_cap_is_typed_limit_error_work(); - } - - #[test] - fn __service_isolated_runner() { - let Ok(test_name) = std::env::var(ISOLATED_SERVICE_TEST_ENV) else { - return; - }; - match test_name.as_str() { - "crypto-handle-tables" => { - cipher_session_handles_are_bounded(); - diffie_hellman_session_handles_are_bounded(); - } - "http2-file-response" => { - javascript_http2_settings_pause_push_and_file_response_surfaces_work(); - } - "http2-guest-h2c" => { - javascript_http2_guest_h2c_round_trip_does_not_deadlock(); - } - "http2-request-handler-twice" => { - javascript_http2_request_handler_round_trip_runs_twice_in_one_vm(); - } - "javascript-import-fresh" => { - javascript_imports_guest_written_modules_after_miss_work(); - } - "javascript-fs-promises-hot-metadata" => { - javascript_fs_promises_hot_metadata_ops_use_sync_semantics(); - } - "wasm-shell-external-stdout-redirect" => { - wasm_shell_external_stdout_redirect_writes_file(); - } - "wasm-shell-external-append-redirect" => { - wasm_shell_external_append_redirect_creates_and_concatenates(); - } - "wasm-shell-external-stderr-redirect" => { - wasm_shell_external_stderr_redirect_writes_file(); - } - "wasm-shell-builtin-external-redirect-parity" => { - wasm_shell_builtin_and_external_redirects_match(); - } - "mapped-shadow-readdir-wasm-directory" => { - javascript_mapped_shadow_readdir_sees_wasm_created_directory(); - } - "mapped-shadow-readdir-wasm-children" => { - javascript_mapped_shadow_readdir_merges_wasm_created_children(); - } - "mapped-shadow-readdir-shadow-kernel-union" => { - javascript_mapped_shadow_readdir_unions_shadow_and_kernel_children(); - } - "mapped-shadow-readdir-same-process-shadow" => { - javascript_mapped_shadow_readdir_sees_same_process_shadow_directory(); - } - "mapped-unlink-kernel-backed-no-resurrect" => { - javascript_mapped_unlink_of_kernel_backed_file_does_not_resurrect(); - } - "javascript-readdir-raw-dirent-semantics" => { - javascript_readdir_raw_payload_preserves_dirent_semantics(); - } - "javascript-writev-stream-copy-order" => { - javascript_writev_raw_payload_preserves_stream_copy_order(); - } - "wasm-command-timeout" => { - wasm_command_timeout_is_enforced_by_sidecar_poll_path(); - } - "wasm-fs-permissions" => { - wasm_path_open_read_goes_through_kernel_filesystem_permissions(); - } - "wasm-fs-write-permissions" => { - wasm_path_open_write_goes_through_kernel_filesystem_permissions(); - } - "http-oversized-incomplete-header" => { - javascript_http_socket_backed_server_rejects_oversized_incomplete_headers(); - } - "net-loopback-socket-churn" => { - javascript_net_loopback_socket_churn_releases_kernel_slots(); - } - "net-loopback-parked-reader-wake" => { - javascript_net_loopback_wakes_reader_parked_before_write(); - } - "net-loopback-edge-wake" => { - javascript_net_loopback_reads_back_to_back_and_after_partial_drain(); - } - "net-unix-domain-reader-events" => { - javascript_net_unix_domain_echo_uses_reader_events(); - } - "dgram-loopback-events" => { - javascript_dgram_rpc_sends_and_receives_vm_loopback_packets(); - } - "vm-fetch-kernel-tcp-success" => { - vm_fetch_reaches_javascript_http_server_over_kernel_tcp(); - } - "vm-fetch-kernel-tcp-chunked" => { - vm_fetch_kernel_tcp_decodes_chunked_response_body(); - } - "vm-fetch-kernel-tcp-chunked-content-length" => { - vm_fetch_kernel_tcp_rejects_chunked_with_content_length(); - } - "vm-fetch-kernel-tcp-socket-cap" => { - vm_fetch_kernel_tcp_socket_cap_failure_closes_no_extra_resources(); - } - "vm-fetch-kernel-tcp-oversized" => { - vm_fetch_kernel_tcp_oversized_response_closes_client_socket(); - } - "vm-fetch-kernel-tcp-configured-limit" => { - vm_fetch_kernel_tcp_honors_configured_response_limit(); - } - "vm-fetch-kernel-tcp-malformed" => { - vm_fetch_kernel_tcp_malformed_response_closes_client_socket(); - } - "vm-fetch-kernel-tcp-timeout" => { - vm_fetch_kernel_tcp_timeout_closes_client_socket(); - } - "vm-fetch-kernel-tcp-target-exit" => { - vm_fetch_kernel_tcp_target_exit_cleans_up_process_resources(); - } - "loopback-tls-https-pending-write" => { - javascript_loopback_tls_https_get_buffers_handshake_pending_write_work(); - } - other => panic!("unknown isolated service test {other}"), - } - } - } -} - -pub use crate::service::{DispatchResult, NativeSidecar, SidecarError}; diff --git a/crates/sidecar/tests/session_isolation.rs b/crates/sidecar/tests/session_isolation.rs deleted file mode 100644 index 897b852c6..000000000 --- a/crates/sidecar/tests/session_isolation.rs +++ /dev/null @@ -1,108 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - CreateVmRequest, GetSignalStateRequest, GuestRuntimeKind, RequestPayload, ResponsePayload, - RootFilesystemDescriptor, -}; -use std::collections::HashMap; -use support::{ - authenticate_wire, create_vm_wire, new_sidecar, open_session_wire, temp_dir, wire_request, - wire_session, wire_vm, -}; - -#[test] -fn sessions_and_vms_reject_cross_connection_access() { - let mut sidecar = new_sidecar("session-isolation"); - let cwd = temp_dir("session-isolation-cwd"); - - let connection_a = authenticate_wire(&mut sidecar, "conn-a"); - let connection_b = authenticate_wire(&mut sidecar, "conn-b"); - - let session_a = open_session_wire(&mut sidecar, 2, &connection_a); - let session_b = open_session_wire(&mut sidecar, 3, &connection_b); - let session_a_other = open_session_wire(&mut sidecar, 4, &connection_a); - let (vm_a, _) = create_vm_wire( - &mut sidecar, - 5, - &connection_a, - &session_a, - GuestRuntimeKind::JavaScript, - &cwd, - ); - - let session_reject = sidecar - .dispatch_wire_blocking(wire_request( - 5, - wire_session(&connection_b, &session_a), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::from([(String::from("cwd"), cwd.to_string_lossy().into_owned())]), - RootFilesystemDescriptor { - mode: secure_exec_sidecar::wire::RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }, - None, - )), - )) - .expect("dispatch mismatched session create_vm"); - match session_reject.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!(response.message.contains("not owned")); - } - other => panic!("unexpected session rejection response: {other:?}"), - } - - let vm_reject = sidecar - .dispatch_wire_blocking(wire_request( - 7, - wire_vm(&connection_b, &session_b, &vm_a), - RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("missing"), - }), - )) - .expect("dispatch mismatched vm signal-state"); - match vm_reject.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!(response.message.contains("not owned")); - } - other => panic!("unexpected vm rejection response: {other:?}"), - } - - let same_connection_vm_reject = sidecar - .dispatch_wire_blocking(wire_request( - 8, - wire_vm(&connection_a, &session_a_other, &vm_a), - RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("missing"), - }), - )) - .expect("dispatch same-connection mismatched-session signal-state"); - match same_connection_vm_reject.response.payload { - ResponsePayload::RejectedResponse(response) => { - assert_eq!(response.code, "invalid_state"); - assert!(response.message.contains("not owned")); - } - other => panic!("unexpected same-connection vm rejection response: {other:?}"), - } - - let owner_signal_state = sidecar - .dispatch_wire_blocking(wire_request( - 9, - wire_vm(&connection_a, &session_a, &vm_a), - RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("missing"), - }), - )) - .expect("dispatch owner signal-state"); - match owner_signal_state.response.payload { - ResponsePayload::SignalStateResponse(snapshot) => { - assert_eq!(snapshot.process_id, "missing"); - assert!(snapshot.handlers.is_empty()); - } - other => panic!("unexpected owner signal-state response: {other:?}"), - } -} diff --git a/crates/sidecar/tests/signal.rs b/crates/sidecar/tests/signal.rs deleted file mode 100644 index 975e827e1..000000000 --- a/crates/sidecar/tests/signal.rs +++ /dev/null @@ -1,891 +0,0 @@ -mod support; - -use nix::libc; -use secure_exec_sidecar::wire::{ - EventPayload, GetSignalStateRequest, GuestRuntimeKind, KillProcessRequest, - ProcessSnapshotStatus, RequestPayload, ResponsePayload, SignalDispositionAction, - SignalHandlerRegistration, StreamChannel, -}; -use std::collections::HashMap; -use std::time::{Duration, Instant}; -use support::{ - assert_node_available, authenticate_wire, create_vm_wire_with_metadata, execute_wire, - new_sidecar, open_session_wire, temp_dir, wire_request, wire_vm, write_fixture, -}; - -fn wait_for_process_output( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - expected: &str, -) { - let ownership = wire_vm(connection_id, session_id, vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - - loop { - assert!( - Instant::now() < deadline, - "timed out waiting for process output containing {expected:?}" - ); - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll sidecar event"); - let Some(event) = event else { - continue; - }; - if let EventPayload::ProcessOutputEvent(output) = event.payload { - if output.process_id == process_id - && String::from_utf8_lossy(&output.chunk).contains(expected) - { - return; - } - } - } -} - -fn wait_for_process_status( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - expected: ProcessSnapshotStatus, -) { - let ownership = wire_vm(connection_id, session_id, vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - - loop { - let snapshot = sidecar - .dispatch_wire_blocking(wire_request( - 1, - ownership.clone(), - RequestPayload::GetProcessSnapshotRequest, - )) - .expect("query process snapshot"); - match snapshot.response.payload { - ResponsePayload::ProcessSnapshotResponse(snapshot) => { - if snapshot - .processes - .iter() - .find(|entry| entry.process_id == process_id) - .is_some_and(|entry| entry.status == expected) - { - return; - } - } - other => panic!("unexpected process snapshot response: {other:?}"), - } - - assert!( - Instant::now() < deadline, - "timed out waiting for process status {expected:?}" - ); - let _ = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(25)) - .expect("pump process events while waiting for status"); - } -} - -fn embedded_runtime_signal_routes_sigterm_and_process_kill() { - assert_node_available(); - - let mut sidecar = new_sidecar("embedded-runtime-signal-routing"); - let cwd = temp_dir("embedded-runtime-signal-routing-cwd"); - let entry = cwd.join("signal-routing.mjs"); - - write_fixture( - &entry, - [ - "let sigtermCount = 0;", - "process.on('SIGHUP', () => {});", - "process.on('SIGWINCH', () => {});", - "process.on('SIGTERM', () => {", - " sigtermCount += 1;", - " console.log(`sigterm:${sigtermCount}`);", - " if (sigtermCount === 1) {", - " process.kill(process.pid, 'SIGTERM');", - " return;", - " }", - " process.exit(0);", - "});", - "console.log('signal-handlers-ready');", - "setInterval(() => {}, 25);", - ] - .join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-embedded-runtime-signal-routing"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::new(), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "signal-routing", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - wait_for_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "signal-routing", - "signal-handlers-ready", - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - let registration_deadline = Instant::now() + Duration::from_secs(10); - loop { - let signal_state = sidecar - .dispatch_wire_blocking(wire_request( - 5, - ownership.clone(), - RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("signal-routing"), - }), - )) - .expect("query signal state"); - let ready = match signal_state.response.payload { - ResponsePayload::SignalStateResponse(snapshot) => { - snapshot.handlers.get(&(libc::SIGTERM as u32)) - == Some(&SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![], - flags: 0, - }) - } - other => panic!("unexpected signal state response: {other:?}"), - }; - if ready { - break; - } - let _ = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(25)) - .expect("pump signal registration events"); - assert!( - Instant::now() < registration_deadline, - "timed out waiting for SIGTERM registration" - ); - } - - sidecar - .dispatch_wire_blocking(wire_request( - 6, - ownership.clone(), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("signal-routing"), - signal: String::from("SIGTERM"), - }), - )) - .expect("deliver SIGTERM"); - - let event_deadline = Instant::now() + Duration::from_secs(10); - let mut saw_first_sigterm = false; - let mut saw_second_sigterm = false; - let mut exit_code = None; - - while exit_code.is_none() { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll signal events"); - let Some(event) = event else { - assert!( - Instant::now() < event_deadline, - "timed out waiting for SIGTERM delivery" - ); - continue; - }; - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == "signal-routing" => { - let chunk = String::from_utf8_lossy(&output.chunk); - saw_first_sigterm |= chunk.contains("sigterm:1"); - saw_second_sigterm |= chunk.contains("sigterm:2"); - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == "signal-routing" => { - exit_code = Some(exited.exit_code); - } - _ => {} - } - } - - assert!(saw_first_sigterm, "expected control-plane SIGTERM delivery"); - assert!( - saw_second_sigterm, - "expected guest process.kill(SIGTERM) delivery" - ); - assert_eq!(exit_code, Some(0)); -} - -fn embedded_runtime_signal_stop_continue_updates_kernel_state_and_guest_handler() { - assert_node_available(); - - let mut sidecar = new_sidecar("embedded-runtime-signal-stop-cont"); - let cwd = temp_dir("embedded-runtime-signal-stop-cont-cwd"); - let entry = cwd.join("signal-stop-cont.mjs"); - - write_fixture( - &entry, - [ - "let sigcontCount = 0;", - "process.on('SIGCONT', () => {", - " sigcontCount += 1;", - " console.log(`sigcont:${sigcontCount}`);", - "});", - "console.log('ready');", - "setInterval(() => {}, 25);", - ] - .join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-embedded-runtime-signal-stop-cont"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::new(), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "signal-stop-cont", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - wait_for_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "signal-stop-cont", - "ready", - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - sidecar - .dispatch_wire_blocking(wire_request( - 5, - ownership.clone(), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("signal-stop-cont"), - signal: String::from("SIGSTOP"), - }), - )) - .expect("deliver SIGSTOP"); - wait_for_process_status( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "signal-stop-cont", - ProcessSnapshotStatus::Stopped, - ); - - sidecar - .dispatch_wire_blocking(wire_request( - 6, - ownership.clone(), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("signal-stop-cont"), - signal: String::from("SIGCONT"), - }), - )) - .expect("deliver SIGCONT"); - wait_for_process_status( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "signal-stop-cont", - ProcessSnapshotStatus::Running, - ); - wait_for_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "signal-stop-cont", - "sigcont:1", - ); - - sidecar - .dispatch_wire_blocking(wire_request( - 7, - ownership, - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("signal-stop-cont"), - signal: String::from("SIGTERM"), - }), - )) - .expect("terminate stopped/continued process"); -} - -fn embedded_runtime_kill_process_rejects_invalid_signal_without_killing_process() { - assert_node_available(); - - let mut sidecar = new_sidecar("embedded-runtime-invalid-signal"); - let cwd = temp_dir("embedded-runtime-invalid-signal-cwd"); - let entry = cwd.join("invalid-signal.mjs"); - - write_fixture( - &entry, - [ - "console.log('invalid-signal-ready');", - "setInterval(() => {}, 25);", - ] - .join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-embedded-runtime-invalid-signal"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::new(), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "invalid-signal", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - wait_for_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "invalid-signal", - "invalid-signal-ready", - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - let invalid_signal = sidecar - .dispatch_wire_blocking(wire_request( - 5, - ownership.clone(), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("invalid-signal"), - signal: String::from("SIGBOGUS"), - }), - )) - .expect("dispatch invalid signal"); - let ResponsePayload::RejectedResponse(response) = invalid_signal.response.payload else { - panic!("unexpected invalid signal response"); - }; - assert_eq!(response.code, "invalid_state"); - assert!( - response.message.contains("unsupported kill_process signal"), - "unexpected invalid signal rejection: {}", - response.message - ); - - wait_for_process_status( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "invalid-signal", - ProcessSnapshotStatus::Running, - ); - - sidecar - .dispatch_wire_blocking(wire_request( - 6, - ownership, - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("invalid-signal"), - signal: String::from("SIGTERM"), - }), - )) - .expect("terminate invalid-signal process"); -} - -fn embedded_runtime_process_kill_signal_zero_checks_child_liveness() { - assert_node_available(); - - let mut sidecar = new_sidecar("embedded-runtime-process-kill-sig0"); - let cwd = temp_dir("embedded-runtime-process-kill-sig0-cwd"); - let entry = cwd.join("process-kill-sig0.mjs"); - - write_fixture( - &entry, - [ - "const { spawn, spawnSync } = require('node:child_process');", - "const live = spawn(process.execPath, ['-e', 'setTimeout(() => {}, 5000)'], { stdio: 'ignore' });", - "console.log(`live:${process.kill(live.pid, 0)}`);", - "live.kill('SIGTERM');", - "const stale = spawnSync(process.execPath, ['-e', ''], { encoding: 'utf8' });", - "if (typeof stale.pid !== 'number') {", - " throw new Error('spawnSync result did not include child pid');", - "}", - "let staleResult = 'alive';", - "try {", - " process.kill(stale.pid, 0);", - "} catch (error) {", - " staleResult = error && typeof error.code === 'string' ? error.code : 'error';", - "}", - "console.log(`stale:${staleResult}`);", - "process.exit(staleResult === 'alive' ? 1 : 0);", - ] - .join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-embedded-runtime-process-kill-sig0"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::new(), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "process-kill-sig0", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - let mut saw_live = false; - let mut saw_stale_esrch = false; - let mut exit_code = None; - - while exit_code.is_none() || !saw_live || !saw_stale_esrch { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll process.kill signal-zero events"); - let Some(event) = event else { - assert!( - Instant::now() < deadline, - "timed out waiting for process.kill signal-zero output" - ); - continue; - }; - - match event.payload { - EventPayload::ProcessOutputEvent(output) - if output.process_id == "process-kill-sig0" => - { - let chunk = String::from_utf8_lossy(&output.chunk); - saw_live |= chunk.contains("live:true"); - saw_stale_esrch |= chunk.contains("stale:ESRCH"); - } - EventPayload::ProcessExitedEvent(exited) - if exited.process_id == "process-kill-sig0" => - { - exit_code = Some(exited.exit_code); - } - _ => {} - } - - assert!( - Instant::now() < deadline, - "timed out waiting for process.kill signal-zero completion" - ); - } - - assert!(saw_live, "live child should be visible to signal 0"); - assert!( - saw_stale_esrch, - "stale child PID should throw ESRCH for signal 0" - ); - assert_eq!(exit_code, Some(0)); -} - -fn embedded_runtime_process_group_kill_terminates_detached_tree() { - assert_node_available(); - - let mut sidecar = new_sidecar("embedded-runtime-process-group-kill"); - let cwd = temp_dir("embedded-runtime-process-group-kill-cwd"); - let parent_entry = cwd.join("group-parent.mjs"); - let child_entry = cwd.join("group-child.mjs"); - - write_fixture( - &child_entry, - [ - "import { spawn } from 'node:child_process';", - "const makeChild = () => spawn(", - " process.execPath,", - " ['-e', 'setTimeout(() => {}, 100000)'],", - " { stdio: ['ignore', 'ignore', 'ignore'] },", - ");", - "const first = makeChild();", - "const second = makeChild();", - "console.log(`group-ready:${first.pid}:${second.pid}`);", - "setInterval(() => {}, 1000);", - ] - .join("\n"), - ); - write_fixture( - &parent_entry, - [ - "import { spawn } from 'node:child_process';", - "const child = spawn(process.execPath, ['./group-child.mjs'], {", - " detached: true,", - " stdio: ['ignore', 'pipe', 'pipe'],", - "});", - "let buffered = '';", - "const grandchildPids = await new Promise((resolve, reject) => {", - " child.on('error', reject);", - " child.stdout.on('data', (chunk) => {", - " buffered += chunk.toString();", - " const match = buffered.match(/group-ready:(\\d+):(\\d+)/);", - " if (match) {", - " resolve([Number(match[1]), Number(match[2])]);", - " }", - " });", - "});", - "const closePromise = new Promise((resolve) => {", - " child.on('close', (code, signal) => resolve({ code, signal }));", - "});", - "const killResult = process.kill(-child.pid, 'SIGKILL');", - "console.log('kill-returned:' + killResult);", - "const closed = await closePromise;", - "console.log('group-close:' + closed.code + ':' + closed.signal);", - "const errorCode = (error) => {", - " if (error && typeof error.code === 'string' && error.syscall === 'kill') {", - " return error.code;", - " }", - " return 'missing-errno-error';", - "};", - "const probe = (pid) => {", - " try {", - " process.kill(pid, 0);", - " return 'alive';", - " } catch (error) {", - " return errorCode(error);", - " }", - "};", - "console.log('probe-child:' + probe(child.pid));", - "console.log('probe-grandchild-a:' + probe(grandchildPids[0]));", - "console.log('probe-grandchild-b:' + probe(grandchildPids[1]));", - "let missingGroup;", - "try {", - " process.kill(-999999, 'SIGKILL');", - " missingGroup = 'no-error';", - "} catch (error) {", - " missingGroup = errorCode(error);", - "}", - "console.log('probe-missing-group:' + missingGroup);", - ] - .join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-embedded-runtime-process-group-kill"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::new(), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "group-kill-parent", - GuestRuntimeKind::JavaScript, - &parent_entry, - Vec::new(), - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - let deadline = Instant::now() + Duration::from_secs(30); - let mut stdout = String::new(); - let mut stderr = String::new(); - let mut exit_code = None; - - while exit_code.is_none() { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll process group kill events"); - let Some(event) = event else { - assert!( - Instant::now() < deadline, - "timed out waiting for group kill completion\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - continue; - }; - - match event.payload { - EventPayload::ProcessOutputEvent(output) - if output.process_id == "group-kill-parent" => - { - let chunk = String::from_utf8_lossy(&output.chunk); - match output.channel { - StreamChannel::Stdout => stdout.push_str(&chunk), - StreamChannel::Stderr => stderr.push_str(&chunk), - } - } - EventPayload::ProcessExitedEvent(exited) - if exited.process_id == "group-kill-parent" => - { - exit_code = Some(exited.exit_code); - } - _ => {} - } - - assert!( - Instant::now() < deadline, - "timed out waiting for group kill completion\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - } - - assert_eq!( - exit_code, - Some(0), - "group kill parent should exit cleanly\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stdout.contains("kill-returned:true"), - "group kill should report success\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stdout.contains("group-close:"), - "detached child should emit close after group kill\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stdout.contains("probe-child:ESRCH"), - "killed group leader should probe as ESRCH\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stdout.contains("probe-grandchild-a:ESRCH"), - "first grandchild should be killed with the group\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stdout.contains("probe-grandchild-b:ESRCH"), - "second grandchild should be killed with the group\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - assert!( - stdout.contains("probe-missing-group:ESRCH"), - "missing process group should raise ESRCH\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); -} - -fn embedded_runtime_signal_delivers_sigchld_on_child_exit() { - assert_node_available(); - - let mut sidecar = new_sidecar("embedded-runtime-signal-sigchld"); - let cwd = temp_dir("embedded-runtime-signal-sigchld-cwd"); - let parent_entry = cwd.join("parent.mjs"); - let child_entry = cwd.join("child.mjs"); - - write_fixture( - &child_entry, - [ - "await new Promise((resolve) => setTimeout(resolve, 200));", - "console.log('child-exit');", - ] - .join("\n"), - ); - write_fixture( - &parent_entry, - [ - "import { spawn } from 'node:child_process';", - "let sigchldCount = 0;", - "process.on('SIGCHLD', () => {", - " sigchldCount += 1;", - " console.log(`sigchld:${sigchldCount}`);", - "});", - "console.log('sigchld-registered');", - "const child = spawn('node', ['./child.mjs'], { stdio: ['ignore', 'ignore', 'ignore'] });", - "await new Promise((resolve, reject) => {", - " child.on('error', reject);", - " child.on('close', (code) => {", - " if (code !== 0) {", - " reject(new Error(`child exit ${code}`));", - " return;", - " }", - " resolve();", - " });", - "});", - "const deadline = Date.now() + 2000;", - "while (sigchldCount === 0 && Date.now() < deadline) {", - " await new Promise((resolve) => setTimeout(resolve, 10));", - "}", - "if (sigchldCount === 0) {", - " throw new Error('SIGCHLD was not delivered');", - "}", - "console.log(`sigchld-final:${sigchldCount}`);", - ] - .join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-embedded-runtime-signal-sigchld"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let allowed_builtins = serde_json::to_string(&[ - "assert", - "buffer", - "child_process", - "console", - "crypto", - "events", - "fs", - "path", - "querystring", - "stream", - "string_decoder", - "timers", - "url", - "util", - "zlib", - ]) - .expect("serialize builtins"); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::from([( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - allowed_builtins, - )]), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "sigchld-parent", - GuestRuntimeKind::JavaScript, - &parent_entry, - Vec::new(), - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - let mut signal_registered = false; - let mut saw_registered_output = false; - let mut saw_sigchld_output = false; - let mut saw_final_output = false; - let mut exit_code = None; - - while exit_code.is_none() || !signal_registered { - let signal_state = sidecar - .dispatch_wire_blocking(wire_request( - 5, - ownership.clone(), - RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("sigchld-parent"), - }), - )) - .expect("query SIGCHLD state"); - match signal_state.response.payload { - ResponsePayload::SignalStateResponse(snapshot) => { - if snapshot.handlers.get(&(libc::SIGCHLD as u32)) - == Some(&SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![], - flags: 0, - }) - { - signal_registered = true; - } - } - other => panic!("unexpected signal state response: {other:?}"), - } - - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll SIGCHLD process"); - if let Some(event) = event { - match event.payload { - EventPayload::ProcessOutputEvent(output) - if output.process_id == "sigchld-parent" => - { - let chunk = String::from_utf8_lossy(&output.chunk); - saw_registered_output |= chunk.contains("sigchld-registered"); - saw_sigchld_output |= chunk.contains("sigchld:1"); - saw_final_output |= chunk.contains("sigchld-final:1"); - } - EventPayload::ProcessExitedEvent(exited) - if exited.process_id == "sigchld-parent" => - { - exit_code = Some(exited.exit_code); - } - _ => {} - } - } - - assert!( - Instant::now() < deadline, - "timed out waiting for SIGCHLD registration/output" - ); - } - - assert!(signal_registered, "SIGCHLD should be registered"); - assert!( - saw_registered_output, - "parent should report SIGCHLD registration" - ); - assert!(saw_sigchld_output, "parent should receive SIGCHLD output"); - assert!(saw_final_output, "parent should report final SIGCHLD count"); - assert_eq!(exit_code, Some(0)); -} - -#[test] -fn embedded_runtime_signal_suite() { - embedded_runtime_signal_routes_sigterm_and_process_kill(); - embedded_runtime_signal_stop_continue_updates_kernel_state_and_guest_handler(); - embedded_runtime_kill_process_rejects_invalid_signal_without_killing_process(); - embedded_runtime_process_kill_signal_zero_checks_child_liveness(); - embedded_runtime_process_group_kill_terminates_detached_tree(); - embedded_runtime_signal_delivers_sigchld_on_child_exit(); -} diff --git a/crates/sidecar/tests/smoke.rs b/crates/sidecar/tests/smoke.rs deleted file mode 100644 index 3d65c1b1d..000000000 --- a/crates/sidecar/tests/smoke.rs +++ /dev/null @@ -1,20 +0,0 @@ -use secure_exec_sidecar::scaffold; -use secure_exec_sidecar::wire::{DEFAULT_MAX_FRAME_BYTES, PROTOCOL_NAME, PROTOCOL_VERSION}; -use secure_exec_sidecar::NativeSidecarConfig; - -#[test] -fn native_sidecar_scaffold_tracks_kernel_and_execution_dependencies() { - let scaffold = scaffold(); - - assert_eq!(scaffold.package_name, "secure-exec-sidecar"); - assert_eq!(scaffold.binary_name, "secure-exec-sidecar"); - assert_eq!(scaffold.kernel_package, "secure-exec-kernel"); - assert_eq!(scaffold.execution_package, "secure-exec-execution"); - assert_eq!(scaffold.protocol_name, PROTOCOL_NAME); - assert_eq!(scaffold.protocol_version, PROTOCOL_VERSION); - assert_eq!(scaffold.max_frame_bytes, DEFAULT_MAX_FRAME_BYTES); - assert_eq!( - NativeSidecarConfig::default().sidecar_id, - "secure-exec-sidecar" - ); -} diff --git a/crates/sidecar/tests/socket_state_queries.rs b/crates/sidecar/tests/socket_state_queries.rs deleted file mode 100644 index dde0a4141..000000000 --- a/crates/sidecar/tests/socket_state_queries.rs +++ /dev/null @@ -1,788 +0,0 @@ -mod support; - -use nix::libc; -use secure_exec_sidecar::wire::{ - EventPayload, FindBoundUdpRequest, FindListenerRequest, GetSignalStateRequest, - GuestRuntimeKind, KillProcessRequest, ProcessSnapshotStatus, RequestPayload, ResponsePayload, - SignalDispositionAction, SignalHandlerRegistration, -}; -use std::collections::HashMap; -use std::fs; -use std::time::{Duration, Instant}; -use support::{ - assert_node_available, authenticate_wire, create_vm_wire_with_metadata, execute_wire, - new_sidecar, open_session_wire, temp_dir, wasm_signal_state_module, wire_request, wire_vm, - write_fixture, -}; - -fn wait_for_process_output( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - expected: &str, -) { - let ownership = wire_vm(connection_id, session_id, vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - - loop { - assert!( - Instant::now() < deadline, - "timed out waiting for process output" - ); - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll sidecar process output"); - let Some(event) = event else { - continue; - }; - - match event.payload { - EventPayload::ProcessOutputEvent(output) - if output.process_id == process_id - && String::from_utf8_lossy(&output.chunk).contains(expected) => - { - return; - } - _ => {} - } - } -} - -fn wait_for_process_status( - sidecar: &mut secure_exec_sidecar::NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - expected: ProcessSnapshotStatus, -) { - let ownership = wire_vm(connection_id, session_id, vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - - loop { - let snapshot = sidecar - .dispatch_wire_blocking(wire_request( - 1, - ownership.clone(), - RequestPayload::GetProcessSnapshotRequest, - )) - .expect("query process snapshot"); - match snapshot.response.payload { - ResponsePayload::ProcessSnapshotResponse(snapshot) => { - if snapshot - .processes - .iter() - .find(|entry| entry.process_id == process_id) - .is_some_and(|entry| entry.status == expected) - { - return; - } - } - other => panic!("unexpected process snapshot response: {other:?}"), - } - - assert!( - Instant::now() < deadline, - "timed out waiting for process status {expected:?}" - ); - let _ = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(25)) - .expect("pump process events while waiting for status"); - } -} - -fn v8_signal_delivery_routes_kill_process_and_process_kill() { - assert_node_available(); - - let mut sidecar = new_sidecar("v8-signal-routing"); - let cwd = temp_dir("v8-signal-routing-cwd"); - let entry = cwd.join("signal-routing.mjs"); - - write_fixture( - &entry, - [ - "let sigtermCount = 0;", - "process.on('SIGHUP', () => {});", - "process.on('SIGWINCH', () => {});", - "process.on('SIGTERM', () => {", - " sigtermCount += 1;", - " console.log(`sigterm:${sigtermCount}`);", - " if (sigtermCount === 1) {", - " process.kill(process.pid, 'SIGTERM');", - " return;", - " }", - " process.exit(0);", - "});", - "console.log('signal-handlers-ready');", - "setInterval(() => {}, 25);", - ] - .join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-v8-signal-routing"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::new(), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "signal-routing", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - wait_for_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "signal-routing", - "signal-handlers-ready", - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - let registration_deadline = Instant::now() + Duration::from_secs(10); - loop { - let signal_state = sidecar - .dispatch_wire_blocking(wire_request( - 5, - ownership.clone(), - RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("signal-routing"), - }), - )) - .expect("query V8 signal state"); - let ready = match signal_state.response.payload { - ResponsePayload::SignalStateResponse(snapshot) => { - snapshot.handlers.get(&(libc::SIGTERM as u32)) - == Some(&SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![], - flags: 0, - }) - && snapshot.handlers.get(&(libc::SIGHUP as u32)) - == Some(&SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![], - flags: 0, - }) - && snapshot.handlers.get(&(libc::SIGWINCH as u32)) - == Some(&SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![], - flags: 0, - }) - } - other => panic!("unexpected signal state response: {other:?}"), - }; - if ready { - break; - } - let _ = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(25)) - .expect("pump V8 signal registration events"); - assert!( - Instant::now() < registration_deadline, - "timed out waiting for V8 signal registrations" - ); - } - - sidecar - .dispatch_wire_blocking(wire_request( - 6, - ownership.clone(), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("signal-routing"), - signal: String::from("SIGTERM"), - }), - )) - .expect("deliver SIGTERM to V8 guest"); - - let event_deadline = Instant::now() + Duration::from_secs(10); - let mut saw_first_sigterm = false; - let mut saw_second_sigterm = false; - let mut exit_code = None; - - while exit_code.is_none() { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll V8 signal events"); - let Some(event) = event else { - assert!( - Instant::now() < event_deadline, - "timed out waiting for V8 signal delivery" - ); - continue; - }; - - match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == "signal-routing" => { - let chunk = String::from_utf8_lossy(&output.chunk); - saw_first_sigterm |= chunk.contains("sigterm:1"); - saw_second_sigterm |= chunk.contains("sigterm:2"); - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == "signal-routing" => { - exit_code = Some(exited.exit_code); - } - _ => {} - } - } - - assert!(saw_first_sigterm, "expected control-plane SIGTERM delivery"); - assert!( - saw_second_sigterm, - "expected guest process.kill(SIGTERM) delivery" - ); - assert_eq!(exit_code, Some(0)); -} - -fn v8_signal_stop_and_continue_updates_process_snapshot() { - assert_node_available(); - - let mut sidecar = new_sidecar("v8-signal-stop-cont"); - let cwd = temp_dir("v8-signal-stop-cont-cwd"); - let entry = cwd.join("signal-stop-cont.mjs"); - - write_fixture( - &entry, - ["console.log('ready');", "setInterval(() => {}, 25);"].join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-v8-signal-stop-cont"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::new(), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "signal-stop-cont", - GuestRuntimeKind::JavaScript, - &entry, - Vec::new(), - ); - - wait_for_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "signal-stop-cont", - "ready", - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - sidecar - .dispatch_wire_blocking(wire_request( - 5, - ownership.clone(), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("signal-stop-cont"), - signal: String::from("SIGSTOP"), - }), - )) - .expect("deliver SIGSTOP to V8 guest"); - wait_for_process_status( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "signal-stop-cont", - ProcessSnapshotStatus::Stopped, - ); - - sidecar - .dispatch_wire_blocking(wire_request( - 6, - ownership.clone(), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("signal-stop-cont"), - signal: String::from("SIGCONT"), - }), - )) - .expect("deliver SIGCONT to V8 guest"); - wait_for_process_status( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "signal-stop-cont", - ProcessSnapshotStatus::Running, - ); - - sidecar - .dispatch_wire_blocking(wire_request( - 7, - ownership, - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("signal-stop-cont"), - signal: String::from("SIGTERM"), - }), - )) - .expect("terminate V8 guest after stop/cont"); -} - -fn sidecar_queries_listener_udp_and_signal_state() { - assert_node_available(); - - let mut sidecar = new_sidecar("socket-state-queries"); - let cwd = temp_dir("socket-state-queries-cwd"); - let tcp_entry = cwd.join("tcp-listener.mjs"); - let udp_entry = cwd.join("udp-listener.mjs"); - let signal_entry = cwd.join("signal-state.wasm"); - - write_fixture( - &tcp_entry, - [ - "import net from 'node:net';", - "const server = net.createServer(() => {});", - "server.listen(43111, '127.0.0.1', () => {", - " console.log('tcp-listening:43111');", - "});", - ] - .join("\n"), - ); - write_fixture( - &udp_entry, - [ - "import dgram from 'node:dgram';", - "const socket = dgram.createSocket('udp4');", - "socket.bind(43112, '127.0.0.1', () => {", - " console.log('udp-bound:43112');", - "});", - ] - .join("\n"), - ); - fs::write(&signal_entry, wasm_signal_state_module()).expect("write signal-state wasm fixture"); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let allowed_builtins = serde_json::to_string(&["net", "dgram"]).expect("serialize builtins"); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::from([( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - allowed_builtins, - )]), - ); - let (wasm_vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 30, - &connection_id, - &session_id, - GuestRuntimeKind::WebAssembly, - &cwd, - HashMap::new(), - ); - let (other_vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 31, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::new(), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "tcp-listener", - GuestRuntimeKind::JavaScript, - &tcp_entry, - Vec::new(), - ); - wait_for_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "tcp-listener", - "tcp-listening:43111", - ); - - let listener_deadline = Instant::now() + Duration::from_secs(5); - loop { - let listener = sidecar - .dispatch_wire_blocking(wire_request( - 7, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindListenerRequest(FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43111), - path: None, - }), - )) - .expect("query tcp listener"); - match listener.response.payload { - ResponsePayload::ListenerSnapshotResponse(snapshot) => { - if let Some(listener) = snapshot.listener { - assert_eq!(listener.process_id, "tcp-listener"); - assert_eq!(listener.host.as_deref(), Some("127.0.0.1")); - assert_eq!(listener.port, Some(43111)); - break; - } - } - other => panic!("unexpected listener response: {other:?}"), - } - assert!( - Instant::now() < listener_deadline, - "timed out waiting for listener snapshot" - ); - std::thread::sleep(Duration::from_millis(25)); - } - - let other_vm_listener = sidecar - .dispatch_wire_blocking(wire_request( - 71, - wire_vm(&connection_id, &session_id, &other_vm_id), - RequestPayload::FindListenerRequest(FindListenerRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43111), - path: None, - }), - )) - .expect("query tcp listener from another vm"); - match other_vm_listener.response.payload { - ResponsePayload::ListenerSnapshotResponse(snapshot) => { - assert!( - snapshot.listener.is_none(), - "listener from vm {vm_id} leaked into vm {other_vm_id}: {:?}", - snapshot.listener - ); - } - other => panic!("unexpected other-vm listener response: {other:?}"), - } - - let kill_listener = sidecar - .dispatch_wire_blocking(wire_request( - 70, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::KillProcessRequest(KillProcessRequest { - process_id: String::from("tcp-listener"), - signal: String::from("SIGTERM"), - }), - )) - .expect("kill tcp listener"); - assert!(matches!( - kill_listener.response.payload, - ResponsePayload::ProcessKilledResponse(_) - )); - - execute_wire( - &mut sidecar, - 5, - &connection_id, - &session_id, - &vm_id, - "udp-listener", - GuestRuntimeKind::JavaScript, - &udp_entry, - Vec::new(), - ); - wait_for_process_output( - &mut sidecar, - &connection_id, - &session_id, - &vm_id, - "udp-listener", - "udp-bound:43112", - ); - - execute_wire( - &mut sidecar, - 6, - &connection_id, - &session_id, - &wasm_vm_id, - "signal-state", - GuestRuntimeKind::WebAssembly, - &signal_entry, - Vec::new(), - ); - let wasm_ownership = wire_vm(&connection_id, &session_id, &wasm_vm_id); - - let bound_udp = sidecar - .dispatch_wire_blocking(wire_request( - 8, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::FindBoundUdpRequest(FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43112), - }), - )) - .expect("query udp socket"); - match bound_udp.response.payload { - ResponsePayload::BoundUdpSnapshotResponse(snapshot) => { - let socket = snapshot.socket.expect("bound udp snapshot"); - assert_eq!(socket.process_id, "udp-listener"); - assert_eq!(socket.host.as_deref(), Some("127.0.0.1")); - assert_eq!(socket.port, Some(43112)); - } - other => panic!("unexpected bound udp response: {other:?}"), - } - - let other_vm_bound_udp = sidecar - .dispatch_wire_blocking(wire_request( - 72, - wire_vm(&connection_id, &session_id, &other_vm_id), - RequestPayload::FindBoundUdpRequest(FindBoundUdpRequest { - host: Some(String::from("127.0.0.1")), - port: Some(43112), - }), - )) - .expect("query udp socket from another vm"); - match other_vm_bound_udp.response.payload { - ResponsePayload::BoundUdpSnapshotResponse(snapshot) => { - assert!( - snapshot.socket.is_none(), - "udp socket from vm {vm_id} leaked into vm {other_vm_id}: {:?}", - snapshot.socket - ); - } - other => panic!("unexpected other-vm udp response: {other:?}"), - } - - let signal_deadline = Instant::now() + Duration::from_secs(5); - loop { - let _ = sidecar - .poll_event_wire_blocking(&wasm_ownership, Duration::from_millis(25)) - .expect("pump wasm signal-state events"); - let signal_state = sidecar - .dispatch_wire_blocking(wire_request( - 9, - wasm_ownership.clone(), - RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("signal-state"), - }), - )) - .expect("query signal state"); - match signal_state.response.payload { - ResponsePayload::SignalStateResponse(snapshot) => { - assert_eq!(snapshot.process_id, "signal-state"); - if snapshot.handlers.get(&2) - == Some(&SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![15], - flags: 0x1234, - }) - { - break; - } - } - other => panic!("unexpected signal state response: {other:?}"), - } - assert!( - Instant::now() < signal_deadline, - "timed out waiting for signal state" - ); - std::thread::sleep(Duration::from_millis(25)); - } -} - -fn sidecar_tracks_javascript_sigchld_and_delivers_it_on_child_exit() { - assert_node_available(); - - let mut sidecar = new_sidecar("socket-state-sigchld"); - let cwd = temp_dir("socket-state-sigchld-cwd"); - let parent_entry = cwd.join("parent.mjs"); - let child_entry = cwd.join("child.mjs"); - - write_fixture( - &child_entry, - [ - "await new Promise((resolve) => setTimeout(resolve, 200));", - "console.log('child-exit');", - ] - .join("\n"), - ); - write_fixture( - &parent_entry, - [ - "import { spawn } from 'node:child_process';", - "let sigchldCount = 0;", - "process.on('SIGCHLD', () => {", - " sigchldCount += 1;", - " console.log(`sigchld:${sigchldCount}`);", - "});", - "console.log('sigchld-registered');", - "const child = spawn('node', ['./child.mjs'], { stdio: ['ignore', 'ignore', 'ignore'] });", - "await new Promise((resolve, reject) => {", - " child.on('error', reject);", - " child.on('close', (code) => {", - " if (code !== 0) {", - " reject(new Error(`child exit ${code}`));", - " return;", - " }", - " resolve();", - " });", - "});", - "const deadline = Date.now() + 2000;", - "while (sigchldCount === 0 && Date.now() < deadline) {", - " await new Promise((resolve) => setTimeout(resolve, 10));", - "}", - "if (sigchldCount === 0) {", - " throw new Error('SIGCHLD was not delivered');", - "}", - "console.log(`sigchld-final:${sigchldCount}`);", - ] - .join("\n"), - ); - - let connection_id = authenticate_wire(&mut sidecar, "conn-sigchld"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - let allowed_builtins = serde_json::to_string(&[ - "assert", - "buffer", - "child_process", - "console", - "crypto", - "events", - "fs", - "path", - "querystring", - "stream", - "string_decoder", - "timers", - "url", - "util", - "zlib", - ]) - .expect("serialize builtins"); - let (vm_id, _) = create_vm_wire_with_metadata( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - HashMap::from([( - String::from("env.AGENTOS_ALLOWED_NODE_BUILTINS"), - allowed_builtins, - )]), - ); - - execute_wire( - &mut sidecar, - 4, - &connection_id, - &session_id, - &vm_id, - "sigchld-parent", - GuestRuntimeKind::JavaScript, - &parent_entry, - Vec::new(), - ); - - let ownership = wire_vm(&connection_id, &session_id, &vm_id); - let deadline = Instant::now() + Duration::from_secs(10); - let mut signal_registered = false; - let mut saw_registered_output = false; - let mut saw_sigchld_output = false; - let mut saw_final_output = false; - let mut exit_code = None; - - while exit_code.is_none() || !signal_registered { - let signal_state = sidecar - .dispatch_wire_blocking(wire_request( - 5, - ownership.clone(), - RequestPayload::GetSignalStateRequest(GetSignalStateRequest { - process_id: String::from("sigchld-parent"), - }), - )) - .expect("query sigchld signal state"); - match signal_state.response.payload { - ResponsePayload::SignalStateResponse(snapshot) => { - if snapshot.handlers.get(&(libc::SIGCHLD as u32)) - == Some(&SignalHandlerRegistration { - action: SignalDispositionAction::User, - mask: vec![], - flags: 0, - }) - { - signal_registered = true; - } - } - other => panic!("unexpected signal state response: {other:?}"), - } - - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll SIGCHLD process"); - if let Some(event) = event { - match event.payload { - EventPayload::ProcessOutputEvent(output) - if output.process_id == "sigchld-parent" => - { - let chunk = String::from_utf8_lossy(&output.chunk); - saw_registered_output |= chunk.contains("sigchld-registered"); - saw_sigchld_output |= chunk.contains("sigchld:1"); - saw_final_output |= chunk.contains("sigchld-final:1"); - } - EventPayload::ProcessExitedEvent(exited) - if exited.process_id == "sigchld-parent" => - { - exit_code = Some(exited.exit_code); - } - _ => {} - } - } - - assert!( - Instant::now() < deadline, - "timed out waiting for SIGCHLD registration/output" - ); - } - - assert!(signal_registered, "SIGCHLD should be registered"); - assert!( - saw_registered_output, - "parent should report SIGCHLD registration" - ); - assert!(saw_sigchld_output, "parent should receive SIGCHLD output"); - assert!(saw_final_output, "parent should report final SIGCHLD count"); - assert_eq!(exit_code, Some(0)); -} - -#[test] -fn socket_state_queries_suite() { - // Multiple libtest cases in this V8-backed integration binary still trip - // teardown/init crashes, so keep the coverage in one top-level suite. - v8_signal_delivery_routes_kill_process_and_process_kill(); - v8_signal_stop_and_continue_updates_process_snapshot(); - sidecar_queries_listener_udp_and_signal_state(); - sidecar_tracks_javascript_sigchld_and_delivers_it_on_child_exit(); -} diff --git a/crates/sidecar/tests/stdio_binary.rs b/crates/sidecar/tests/stdio_binary.rs deleted file mode 100644 index 26d116fb2..000000000 --- a/crates/sidecar/tests/stdio_binary.rs +++ /dev/null @@ -1,1096 +0,0 @@ -mod support; - -use base64::Engine; -use secure_exec_sidecar::wire::{self, *}; -use serde_json::json; -use std::collections::HashMap; -use std::fs; -use std::io::{Read, Write}; -use std::path::Path; -use std::process::{Child, ChildStdin, ChildStdout, Command, Stdio}; -use std::time::{Duration, Instant}; -use support::{ - temp_dir, wire_connection, wire_permissions_allow_all, wire_request, wire_session, wire_vm, -}; - -const MAX_STDIO_BINARY_PROCESS_STREAM_BYTES: usize = DEFAULT_MAX_FRAME_BYTES; - -fn root_filesystem_descriptor() -> RootFilesystemDescriptor { - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - } -} - -fn send_request(stdin: &mut ChildStdin, codec: &WireFrameCodec, request: RequestFrame) { - let encoded = codec - .encode(&ProtocolFrame::RequestFrame(request)) - .expect("encode request"); - stdin.write_all(&encoded).expect("write request"); - stdin.flush().expect("flush request"); -} - -fn declared_frame_payload_len(prefix: &[u8; 4], codec: &WireFrameCodec) -> usize { - let declared = u32::from_be_bytes(*prefix) as usize; - assert!( - declared <= codec.max_frame_bytes(), - "declared frame payload {declared} exceeds {} byte limit", - codec.max_frame_bytes() - ); - declared -} - -fn read_frame(stdout: &mut ChildStdout, codec: &WireFrameCodec) -> ProtocolFrame { - let mut prefix = [0u8; 4]; - stdout.read_exact(&mut prefix).expect("read length prefix"); - let declared = declared_frame_payload_len(&prefix, codec); - let mut bytes = Vec::with_capacity(4 + declared); - bytes.extend_from_slice(&prefix); - bytes.resize(4 + declared, 0); - stdout - .read_exact(&mut bytes[4..]) - .expect("read framed payload"); - codec.decode(&bytes).expect("decode frame") -} - -fn recv_response( - stdout: &mut ChildStdout, - codec: &WireFrameCodec, - request_id: RequestId, - events: &mut Vec, -) -> ResponseFrame { - loop { - match read_frame(stdout, codec) { - ProtocolFrame::ResponseFrame(response) if response.request_id == request_id => { - return response; - } - ProtocolFrame::EventFrame(event) => events.push(event.payload), - other => panic!("unexpected frame while waiting for response {request_id}: {other:?}"), - } - } -} - -fn send_sidecar_response( - stdin: &mut ChildStdin, - codec: &WireFrameCodec, - response: SidecarResponseFrame, -) { - let encoded = codec - .encode(&ProtocolFrame::SidecarResponseFrame(response)) - .expect("encode sidecar response"); - stdin - .write_all(&encoded) - .expect("write sidecar response frame"); - stdin.flush().expect("flush sidecar response frame"); -} - -fn recv_response_with_sidecar_handler( - stdin: &mut ChildStdin, - stdout: &mut ChildStdout, - codec: &WireFrameCodec, - request_id: RequestId, - events: &mut Vec, - mut handle: impl FnMut(&SidecarRequestFrame) -> SidecarResponsePayload, -) -> ResponseFrame { - loop { - match read_frame(stdout, codec) { - ProtocolFrame::ResponseFrame(response) if response.request_id == request_id => { - return response; - } - ProtocolFrame::EventFrame(event) => events.push(event.payload), - ProtocolFrame::SidecarRequestFrame(request) => { - let payload = handle(&request); - send_sidecar_response( - stdin, - codec, - SidecarResponseFrame { - schema: wire::protocol_schema(), - request_id: request.request_id, - ownership: request.ownership.clone(), - payload, - }, - ); - } - other => panic!("unexpected frame while waiting for response {request_id}: {other:?}"), - } - } -} - -fn js_bridge_args(call: &JsBridgeCallRequest) -> serde_json::Value { - serde_json::from_str(&call.args).expect("parse js bridge args") -} - -fn js_bridge_result( - call: &JsBridgeCallRequest, - result: Option, - error: Option, -) -> SidecarResponsePayload { - SidecarResponsePayload::JsBridgeResultResponse(JsBridgeResultResponse { - call_id: call.call_id.clone(), - result: result.map(|value| value.to_string()), - error, - }) -} - -fn js_bridge_root_response(call: &JsBridgeCallRequest) -> Option { - let args = js_bridge_args(call); - if args["path"].as_str() != Some("/") { - return None; - } - match call.operation.as_str() { - "exists" => Some(js_bridge_result( - call, - Some(serde_json::Value::Bool(true)), - None, - )), - "stat" | "lstat" => Some(js_bridge_result( - call, - Some(json!({ - "mode": 0o755, - "size": 0, - "blocks": 0, - "dev": 1, - "rdev": 0, - "isDirectory": true, - "isSymbolicLink": false, - "atimeMs": 0, - "mtimeMs": 0, - "ctimeMs": 0, - "birthtimeMs": 0, - "ino": 1, - "nlink": 1, - "uid": 0, - "gid": 0, - })), - None, - )), - "readDir" => Some(js_bridge_result(call, Some(json!([])), None)), - "readDirWithTypes" => Some(js_bridge_result(call, Some(json!([])), None)), - "realpath" => Some(js_bridge_result(call, Some(json!("/")), None)), - _ => None, - } -} - -fn append_process_stream_chunk(stream: &mut Vec, chunk: &[u8], stream_name: &str) { - assert!( - stream.len().saturating_add(chunk.len()) <= MAX_STDIO_BINARY_PROCESS_STREAM_BYTES, - "{stream_name} exceeded {MAX_STDIO_BINARY_PROCESS_STREAM_BYTES} bytes" - ); - stream.extend_from_slice(chunk); -} - -fn process_stream_to_string(stream: &[u8]) -> String { - String::from_utf8_lossy(stream).into_owned() -} - -fn collect_process_events( - stdout: &mut ChildStdout, - codec: &WireFrameCodec, - process_id: &str, -) -> (String, String, i32) { - let deadline = Instant::now() + Duration::from_secs(10); - let mut stdout_text = Vec::new(); - let mut stderr_text = Vec::new(); - - loop { - assert!( - Instant::now() < deadline, - "timed out waiting for process events" - ); - match read_frame(stdout, codec) { - ProtocolFrame::EventFrame(event) => match event.payload { - EventPayload::ProcessOutputEvent(output) if output.process_id == process_id => { - match output.channel { - StreamChannel::Stdout => { - append_process_stream_chunk(&mut stdout_text, &output.chunk, "stdout"); - } - StreamChannel::Stderr => { - append_process_stream_chunk(&mut stderr_text, &output.chunk, "stderr"); - } - } - } - EventPayload::ProcessExitedEvent(exited) if exited.process_id == process_id => { - return ( - process_stream_to_string(&stdout_text), - process_stream_to_string(&stderr_text), - exited.exit_code, - ); - } - _ => {} - }, - other => panic!("unexpected frame while waiting for process events: {other:?}"), - } - } -} - -fn collect_vm_lifecycle_states( - stdout: &mut ChildStdout, - codec: &WireFrameCodec, - count: usize, -) -> Vec { - let deadline = Instant::now() + Duration::from_secs(2); - let mut states = Vec::new(); - - while states.len() < count { - assert!( - Instant::now() < deadline, - "timed out waiting for VM lifecycle events" - ); - match read_frame(stdout, codec) { - ProtocolFrame::EventFrame(event) => { - if let EventPayload::VmLifecycleEvent(lifecycle) = event.payload { - states.push(lifecycle.state); - } - } - other => panic!("unexpected frame while waiting for lifecycle events: {other:?}"), - } - } - - states -} - -fn spawn_sidecar_binary() -> (Child, ChildStdin, ChildStdout) { - let mut child = Command::new(env!("CARGO_BIN_EXE_secure-exec-sidecar")) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .expect("spawn native sidecar binary"); - let stdin = child.stdin.take().expect("capture sidecar stdin"); - let stdout = child.stdout.take().expect("capture sidecar stdout"); - (child, stdin, stdout) -} - -fn write_script(root: &Path) { - fs::write(root.join("entry.mjs"), "console.log('stdio-binary-ok');\n") - .expect("write test entrypoint"); -} - -#[test] -fn stdio_binary_test_helpers_bound_frame_and_stream_buffers() { - let codec = WireFrameCodec::default(); - let max_prefix = (codec.max_frame_bytes() as u32).to_be_bytes(); - assert_eq!( - declared_frame_payload_len(&max_prefix, &codec), - codec.max_frame_bytes() - ); - - let oversized_prefix = ((codec.max_frame_bytes() + 1) as u32).to_be_bytes(); - let oversized_frame = std::panic::catch_unwind(|| { - declared_frame_payload_len(&oversized_prefix, &codec); - }); - assert!( - oversized_frame.is_err(), - "oversized frame payload should fail before allocation" - ); - - let mut stream = Vec::new(); - append_process_stream_chunk(&mut stream, &[b'a'; 16], "stdout"); - assert_eq!(stream.len(), 16); - - let oversized_stream = std::panic::catch_unwind(|| { - let mut stream = vec![b'a'; MAX_STDIO_BINARY_PROCESS_STREAM_BYTES]; - append_process_stream_chunk(&mut stream, b"!", "stdout"); - }); - assert!( - oversized_stream.is_err(), - "oversized process stream should fail before appending" - ); -} - -#[test] -fn native_sidecar_binary_runs_the_framed_protocol_over_stdio() { - let temp = temp_dir("stdio-binary"); - write_script(&temp); - - let (mut child, mut stdin, mut stdout) = spawn_sidecar_binary(); - let codec = WireFrameCodec::default(); - let mut buffered_events = Vec::new(); - - send_request( - &mut stdin, - &codec, - wire_request( - 1, - wire_connection("client-hint"), - RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("stdio-test"), - auth_token: String::from("stdio-test-token"), - protocol_version: wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - ), - ); - let authenticated = recv_response(&mut stdout, &codec, 1, &mut buffered_events); - let connection_id = match authenticated.payload { - ResponsePayload::AuthenticatedResponse(response) => response.connection_id, - other => panic!("unexpected authenticate response: {other:?}"), - }; - - send_request( - &mut stdin, - &codec, - wire_request( - 2, - wire_connection(&connection_id), - RequestPayload::OpenSessionRequest(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: None, - }), - metadata: HashMap::new(), - }), - ), - ); - let session_opened = recv_response(&mut stdout, &codec, 2, &mut buffered_events); - let session_id = match session_opened.payload { - ResponsePayload::SessionOpenedResponse(response) => response.session_id, - other => panic!("unexpected open-session response: {other:?}"), - }; - - send_request( - &mut stdin, - &codec, - wire_request( - 3, - wire_session(&connection_id, &session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::from([(String::from("cwd"), temp.to_string_lossy().into_owned())]), - root_filesystem_descriptor(), - Some(wire_permissions_allow_all()), - )), - ), - ); - let created = recv_response(&mut stdout, &codec, 3, &mut buffered_events); - let vm_id = match created.payload { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("unexpected create-vm response: {other:?}"), - }; - let lifecycle_states = collect_vm_lifecycle_states(&mut stdout, &codec, 2); - assert_eq!( - lifecycle_states, - vec![VmLifecycleState::Creating, VmLifecycleState::Ready,] - ); - - send_request( - &mut stdin, - &codec, - wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Mkdir, - path: String::from("/workspace"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: true, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - ), - ); - let mkdir = recv_response(&mut stdout, &codec, 4, &mut buffered_events); - match mkdir.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.path, "/workspace"); - assert_eq!(response.operation, GuestFilesystemOperation::Mkdir); - } - other => panic!("unexpected mkdir response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/workspace/note.txt"), - destination_path: None, - target: None, - content: Some(String::from("stdio-sidecar-fs")), - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - ), - ); - let write = recv_response(&mut stdout, &codec, 5, &mut buffered_events); - match write.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.path, "/workspace/note.txt"); - assert_eq!(response.operation, GuestFilesystemOperation::WriteFile); - } - other => panic!("unexpected write response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 6, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/workspace/note.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - ), - ); - let read = recv_response(&mut stdout, &codec, 6, &mut buffered_events); - match read.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.content.as_deref(), Some("stdio-sidecar-fs")); - } - other => panic!("unexpected read response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 7, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Symlink, - path: String::from("/workspace/link.txt"), - destination_path: None, - target: Some(String::from("/workspace/note.txt")), - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - ), - ); - let symlink = recv_response(&mut stdout, &codec, 7, &mut buffered_events); - match symlink.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::Symlink); - assert_eq!(response.target.as_deref(), Some("/workspace/note.txt")); - } - other => panic!("unexpected symlink response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 8, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Realpath, - path: String::from("/workspace/link.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - ), - ); - let realpath = recv_response(&mut stdout, &codec, 8, &mut buffered_events); - match realpath.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::Realpath); - assert_eq!(response.target.as_deref(), Some("/workspace/note.txt")); - } - other => panic!("unexpected realpath response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 9, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Link, - path: String::from("/workspace/note.txt"), - destination_path: Some(String::from("/workspace/hard.txt")), - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - ), - ); - let link = recv_response(&mut stdout, &codec, 9, &mut buffered_events); - match link.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::Link); - assert_eq!(response.target.as_deref(), Some("/workspace/hard.txt")); - } - other => panic!("unexpected link response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 10, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Truncate, - path: String::from("/workspace/hard.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: Some(5), - offset: None, - }), - ), - ); - let truncate = recv_response(&mut stdout, &codec, 10, &mut buffered_events); - match truncate.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::Truncate); - assert_eq!(response.path, "/workspace/hard.txt"); - } - other => panic!("unexpected truncate response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 11, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Utimes, - path: String::from("/workspace/note.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: Some(1_700_000_000_000), - mtime_ms: Some(1_710_000_000_000), - len: None, - offset: None, - }), - ), - ); - let utimes = recv_response(&mut stdout, &codec, 11, &mut buffered_events); - match utimes.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::Utimes); - assert_eq!(response.path, "/workspace/note.txt"); - } - other => panic!("unexpected utimes response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 12, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::Stat, - path: String::from("/workspace/note.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - ), - ); - let stat = recv_response(&mut stdout, &codec, 12, &mut buffered_events); - match stat.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - let stat = response.stat.expect("stat payload"); - assert_eq!(stat.size, 5); - assert_eq!(stat.atime_ms, 1_700_000_000_000); - assert_eq!(stat.mtime_ms, 1_710_000_000_000); - assert!(stat.nlink >= 2); - } - other => panic!("unexpected stat response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 13, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::SnapshotRootFilesystemRequest, - ), - ); - let snapshot = recv_response(&mut stdout, &codec, 13, &mut buffered_events); - match snapshot.payload { - ResponsePayload::RootFilesystemSnapshotResponse(response) => { - assert!(response - .entries - .iter() - .any(|entry| entry.path == "/workspace/note.txt")); - } - other => panic!("unexpected snapshot response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 14, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ExecuteRequest(ExecuteRequest { - process_id: String::from("proc-1"), - command: None, - runtime: Some(GuestRuntimeKind::JavaScript), - entrypoint: Some(String::from("./entry.mjs")), - args: Vec::new(), - env: HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }), - ), - ); - let started = recv_response(&mut stdout, &codec, 14, &mut buffered_events); - match started.payload { - ResponsePayload::ProcessStartedResponse(response) => { - assert_eq!(response.process_id, "proc-1"); - } - other => panic!("unexpected execute response: {other:?}"), - } - - let (stdout_text, stderr_text, exit_code) = - collect_process_events(&mut stdout, &codec, "proc-1"); - assert!( - stdout_text.contains("stdio-binary-ok"), - "stdout was {stdout_text:?}" - ); - assert_eq!(stderr_text, ""); - assert_eq!(exit_code, 0); - - send_request( - &mut stdin, - &codec, - wire_request( - 15, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::DisposeVmRequest(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - ), - ); - let disposed = recv_response(&mut stdout, &codec, 15, &mut buffered_events); - match disposed.payload { - ResponsePayload::VmDisposedResponse(response) => assert_eq!(response.vm_id, vm_id), - other => panic!("unexpected dispose response: {other:?}"), - } - - drop(stdin); - let status = child.wait().expect("wait for sidecar child"); - assert!(status.success(), "sidecar binary exited with {status}"); -} - -#[test] -fn native_sidecar_binary_supports_js_bridge_host_filesystem_access() { - let host_root = temp_dir("stdio-binary-host-bridge"); - fs::write(host_root.join("existing.txt"), "host-bridge-ok").expect("seed host file"); - - let (mut child, mut stdin, mut stdout) = spawn_sidecar_binary(); - let codec = WireFrameCodec::default(); - let mut buffered_events = Vec::new(); - - send_request( - &mut stdin, - &codec, - wire_request( - 1, - wire_connection("client-hint"), - RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("stdio-test"), - auth_token: String::from("stdio-test-token"), - protocol_version: wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - ), - ); - let authenticated = recv_response(&mut stdout, &codec, 1, &mut buffered_events); - let connection_id = match authenticated.payload { - ResponsePayload::AuthenticatedResponse(response) => response.connection_id, - other => panic!("unexpected authenticate response: {other:?}"), - }; - - send_request( - &mut stdin, - &codec, - wire_request( - 2, - wire_connection(&connection_id), - RequestPayload::OpenSessionRequest(OpenSessionRequest { - placement: SidecarPlacement::SidecarPlacementShared(SidecarPlacementShared { - pool: None, - }), - metadata: HashMap::new(), - }), - ), - ); - let session_opened = recv_response(&mut stdout, &codec, 2, &mut buffered_events); - let session_id = match session_opened.payload { - ResponsePayload::SessionOpenedResponse(response) => response.session_id, - other => panic!("unexpected open-session response: {other:?}"), - }; - - send_request( - &mut stdin, - &codec, - wire_request( - 3, - wire_session(&connection_id, &session_id), - RequestPayload::CreateVmRequest(CreateVmRequest::legacy_test_config( - GuestRuntimeKind::JavaScript, - HashMap::new(), - root_filesystem_descriptor(), - Some(wire_permissions_allow_all()), - )), - ), - ); - let created = recv_response(&mut stdout, &codec, 3, &mut buffered_events); - let vm_id = match created.payload { - ResponsePayload::VmCreatedResponse(response) => response.vm_id, - other => panic!("unexpected create-vm response: {other:?}"), - }; - let lifecycle_states = collect_vm_lifecycle_states(&mut stdout, &codec, 2); - assert_eq!( - lifecycle_states, - vec![VmLifecycleState::Creating, VmLifecycleState::Ready,] - ); - - send_request( - &mut stdin, - &codec, - wire_request( - 4, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::ConfigureVmRequest(ConfigureVmRequest { - mounts: vec![MountDescriptor { - guest_path: String::from("/workspace"), - read_only: false, - plugin: MountPluginDescriptor { - id: String::from("js_bridge"), - config: json!({ "mountId": "mount-1" }).to_string(), - }, - }], - software: Vec::new(), - permissions: Some(wire_permissions_allow_all()), - module_access_cwd: None, - instructions: Vec::new(), - projected_modules: Vec::new(), - command_permissions: HashMap::new(), - loopback_exempt_ports: Vec::new(), - packages: Vec::new(), - packages_mount_at: String::new(), - bootstrap_commands: Vec::new(), - tool_shim_commands: Vec::new(), - }), - ), - ); - let configured = recv_response(&mut stdout, &codec, 4, &mut buffered_events); - match configured.payload { - ResponsePayload::VmConfiguredResponse(response) => { - // 1 = just the client mount. With no packages configured there are no - // granular /opt/agentos leaf mounts (one tar/bin/current mount is added - // per package, not a single always-present staging mount). - assert_eq!(response.applied_mounts, 1); - assert_eq!(response.applied_software, 0); - } - other => panic!("unexpected configure response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 5, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::ReadFile, - path: String::from("/workspace/existing.txt"), - destination_path: None, - target: None, - content: None, - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - ), - ); - let read = recv_response_with_sidecar_handler( - &mut stdin, - &mut stdout, - &codec, - 5, - &mut buffered_events, - |request| { - assert_eq!( - request.ownership, - wire_vm(&connection_id, &session_id, &vm_id) - ); - let SidecarRequestPayload::JsBridgeCallRequest(call) = &request.payload else { - panic!("expected js_bridge_call payload"); - }; - assert_eq!(call.mount_id, "mount-1"); - if let Some(response) = js_bridge_root_response(call) { - return response; - } - let args = js_bridge_args(call); - match ( - call.operation.as_str(), - args["path"].as_str().expect("read path"), - ) { - ("exists", "/existing.txt") => { - js_bridge_result(call, Some(serde_json::Value::Bool(true)), None) - } - ("realpath", "/existing.txt") => { - js_bridge_result(call, Some(json!("/existing.txt")), None) - } - ("readFile", "/existing.txt") => js_bridge_result( - call, - Some(serde_json::Value::String( - base64::engine::general_purpose::STANDARD.encode( - fs::read(host_root.join("existing.txt")).expect("read host file"), - ), - )), - None, - ), - other => panic!("unexpected js bridge read callback: {other:?}"), - } - }, - ); - match read.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.content.as_deref(), Some("host-bridge-ok")); - } - other => panic!("unexpected read response: {other:?}"), - } - - send_request( - &mut stdin, - &codec, - wire_request( - 6, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::GuestFilesystemCallRequest(GuestFilesystemCallRequest { - operation: GuestFilesystemOperation::WriteFile, - path: String::from("/workspace/generated.txt"), - destination_path: None, - target: None, - content: Some(String::from("from-js-bridge")), - encoding: None, - recursive: false, - max_depth: None, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - }), - ), - ); - let write = recv_response_with_sidecar_handler( - &mut stdin, - &mut stdout, - &codec, - 6, - &mut buffered_events, - |request| { - let SidecarRequestPayload::JsBridgeCallRequest(call) = &request.payload else { - panic!("expected js_bridge_call payload"); - }; - assert_eq!(call.mount_id, "mount-1"); - if let Some(response) = js_bridge_root_response(call) { - return response; - } - let args = js_bridge_args(call); - if args["path"].as_str() == Some("/generated.txt") { - let generated_path = host_root.join("generated.txt"); - match call.operation.as_str() { - "exists" => { - return js_bridge_result( - call, - Some(serde_json::Value::Bool(generated_path.exists())), - None, - ); - } - "stat" | "lstat" => { - if let Ok(metadata) = fs::metadata(&generated_path) { - return js_bridge_result( - call, - Some(json!({ - "mode": 0o644, - "size": metadata.len(), - "blocks": 0, - "dev": 1, - "rdev": 0, - "isDirectory": false, - "isSymbolicLink": false, - "atimeMs": 0, - "mtimeMs": 0, - "ctimeMs": 0, - "birthtimeMs": 0, - "ino": 2, - "nlink": 1, - "uid": 0, - "gid": 0, - })), - None, - ); - } - return js_bridge_result(call, None, Some(String::from("not found"))); - } - "realpath" => { - return js_bridge_result(call, None, Some(String::from("not found"))); - } - _ => {} - } - } - match ( - call.operation.as_str(), - args["path"].as_str().expect("write path"), - ) { - ("realpath", "/generated.txt") => { - js_bridge_result(call, None, Some(String::from("not found"))) - } - ("writeFile", "/generated.txt") => { - let content = base64::engine::general_purpose::STANDARD - .decode(args["content"].as_str().expect("write content")) - .expect("decode js bridge write"); - fs::write(host_root.join("generated.txt"), content).expect("write host file"); - js_bridge_result(call, None, None) - } - other => panic!("unexpected js bridge write callback: {other:?}"), - } - }, - ); - match write.payload { - ResponsePayload::GuestFilesystemResultResponse(response) => { - assert_eq!(response.operation, GuestFilesystemOperation::WriteFile); - } - other => panic!("unexpected write response: {other:?}"), - } - assert_eq!( - fs::read_to_string(host_root.join("generated.txt")).expect("read generated host file"), - "from-js-bridge" - ); - - send_request( - &mut stdin, - &codec, - wire_request( - 7, - wire_vm(&connection_id, &session_id, &vm_id), - RequestPayload::DisposeVmRequest(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - ), - ); - let disposed = recv_response_with_sidecar_handler( - &mut stdin, - &mut stdout, - &codec, - 7, - &mut buffered_events, - |request| { - let SidecarRequestPayload::JsBridgeCallRequest(call) = &request.payload else { - panic!("expected js_bridge_call payload during dispose"); - }; - assert_eq!(call.mount_id, "mount-1"); - js_bridge_root_response(call) - .unwrap_or_else(|| panic!("unexpected js bridge dispose callback: {call:?}")) - }, - ); - match disposed.payload { - ResponsePayload::VmDisposedResponse(response) => assert_eq!(response.vm_id, vm_id), - other => panic!("unexpected dispose response: {other:?}"), - } - - drop(stdin); - let status = child.wait().expect("wait for sidecar child"); - assert!(status.success(), "sidecar binary exited with {status}"); -} diff --git a/crates/sidecar/tests/support/mod.rs b/crates/sidecar/tests/support/mod.rs deleted file mode 100644 index a329769fb..000000000 --- a/crates/sidecar/tests/support/mod.rs +++ /dev/null @@ -1,715 +0,0 @@ -#![allow(dead_code)] - -#[path = "../../../bridge/tests/support.rs"] -mod bridge_support; - -pub use bridge_support::RecordingBridge; -use secure_exec_sidecar::protocol::{ - DisposeReason, EventFrame, GuestRuntimeKind, OwnershipScope, RequestFrame, RequestId, - RequestPayload, ResponseFrame, -}; -use secure_exec_sidecar::{DispatchResult, NativeSidecar, NativeSidecarConfig}; -use std::collections::{BTreeMap, HashMap}; -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; - -pub const TEST_AUTH_TOKEN: &str = "sidecar-test-token"; -const MAX_COLLECTED_PROCESS_STREAM_BYTES: usize = 1024 * 1024; - -pub fn acquire_sidecar_runtime_test_lock() { - // No-op under cargo-nextest: each test runs in its own process, so the - // process-global V8 platform, env, and compile cache are already isolated. - // Previously an exclusive flock serialized runtime tests across binaries. See - // CLAUDE.md > Testing. -} - -pub fn assert_node_available() { - let output = Command::new("node") - .arg("--version") - .output() - .expect("spawn node --version"); - assert!( - output.status.success(), - "node must be available for native sidecar execution tests" - ); -} - -pub fn temp_dir(name: &str) -> PathBuf { - let root = std::env::temp_dir().join(format!( - "secure-exec-sidecar-{name}-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time before unix epoch") - .as_nanos() - )); - fs::create_dir_all(&root).expect("create temp dir"); - root -} - -pub fn new_sidecar(name: &str) -> NativeSidecar { - new_sidecar_with_auth_token(name, TEST_AUTH_TOKEN) -} - -pub fn new_sidecar_with_auth_token( - name: &str, - expected_auth_token: &str, -) -> NativeSidecar { - acquire_sidecar_runtime_test_lock(); - let root = temp_dir(name); - NativeSidecar::with_config( - RecordingBridge::default(), - NativeSidecarConfig { - sidecar_id: format!("sidecar-{name}"), - compile_cache_root: Some(root.join("cache")), - expected_auth_token: Some(expected_auth_token.to_owned()), - ..NativeSidecarConfig::default() - }, - ) - .expect("create native sidecar") -} - -pub fn request(id: RequestId, ownership: OwnershipScope, payload: RequestPayload) -> RequestFrame { - RequestFrame::new(id, ownership, payload) -} - -pub fn wire_request( - id: secure_exec_sidecar::wire::RequestId, - ownership: secure_exec_sidecar::wire::OwnershipScope, - payload: secure_exec_sidecar::wire::RequestPayload, -) -> secure_exec_sidecar::wire::RequestFrame { - secure_exec_sidecar::wire::RequestFrame { - schema: secure_exec_sidecar::wire::protocol_schema(), - request_id: id, - ownership, - payload, - } -} - -pub fn wire_connection(connection_id: &str) -> secure_exec_sidecar::wire::OwnershipScope { - secure_exec_sidecar::wire::OwnershipScope::ConnectionOwnership( - secure_exec_sidecar::wire::ConnectionOwnership { - connection_id: connection_id.to_owned(), - }, - ) -} - -pub fn wire_session( - connection_id: &str, - session_id: &str, -) -> secure_exec_sidecar::wire::OwnershipScope { - secure_exec_sidecar::wire::OwnershipScope::SessionOwnership( - secure_exec_sidecar::wire::SessionOwnership { - connection_id: connection_id.to_owned(), - session_id: session_id.to_owned(), - }, - ) -} - -pub fn wire_vm( - connection_id: &str, - session_id: &str, - vm_id: &str, -) -> secure_exec_sidecar::wire::OwnershipScope { - secure_exec_sidecar::wire::OwnershipScope::VmOwnership(secure_exec_sidecar::wire::VmOwnership { - connection_id: connection_id.to_owned(), - session_id: session_id.to_owned(), - vm_id: vm_id.to_owned(), - }) -} - -pub fn wire_permissions_allow_all() -> secure_exec_sidecar::wire::PermissionsPolicy { - secure_exec_sidecar::wire::PermissionsPolicy { - fs: Some( - secure_exec_sidecar::wire::FsPermissionScope::PermissionMode( - secure_exec_sidecar::wire::PermissionMode::Allow, - ), - ), - network: Some( - secure_exec_sidecar::wire::PatternPermissionScope::PermissionMode( - secure_exec_sidecar::wire::PermissionMode::Allow, - ), - ), - child_process: Some( - secure_exec_sidecar::wire::PatternPermissionScope::PermissionMode( - secure_exec_sidecar::wire::PermissionMode::Allow, - ), - ), - process: Some( - secure_exec_sidecar::wire::PatternPermissionScope::PermissionMode( - secure_exec_sidecar::wire::PermissionMode::Allow, - ), - ), - env: Some( - secure_exec_sidecar::wire::PatternPermissionScope::PermissionMode( - secure_exec_sidecar::wire::PermissionMode::Allow, - ), - ), - binding: Some( - secure_exec_sidecar::wire::PatternPermissionScope::PermissionMode( - secure_exec_sidecar::wire::PermissionMode::Allow, - ), - ), - } -} - -pub fn authenticate_wire( - sidecar: &mut NativeSidecar, - connection_hint: &str, -) -> String { - let result = authenticate_wire_with_token(sidecar, 1, connection_hint, TEST_AUTH_TOKEN); - - match result.response.payload { - secure_exec_sidecar::wire::ResponsePayload::AuthenticatedResponse(response) => { - assert_eq!( - result.response.ownership, - wire_connection(&response.connection_id) - ); - response.connection_id - } - other => panic!("unexpected wire auth response: {other:?}"), - } -} - -pub fn authenticate_wire_with_token( - sidecar: &mut NativeSidecar, - request_id: secure_exec_sidecar::wire::RequestId, - connection_hint: &str, - auth_token: &str, -) -> secure_exec_sidecar::wire::WireDispatchResult { - sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_connection(connection_hint), - secure_exec_sidecar::wire::RequestPayload::AuthenticateRequest( - secure_exec_sidecar::wire::AuthenticateRequest { - client_name: String::from("sidecar-tests"), - auth_token: auth_token.to_owned(), - protocol_version: secure_exec_sidecar::wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }, - ), - )) - .expect("authenticate connection through wire") -} - -pub fn open_session_wire( - sidecar: &mut NativeSidecar, - request_id: secure_exec_sidecar::wire::RequestId, - connection_id: &str, -) -> String { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_connection(connection_id), - secure_exec_sidecar::wire::RequestPayload::OpenSessionRequest( - secure_exec_sidecar::wire::OpenSessionRequest { - placement: secure_exec_sidecar::wire::SidecarPlacement::SidecarPlacementShared( - secure_exec_sidecar::wire::SidecarPlacementShared { pool: None }, - ), - metadata: HashMap::new(), - }, - ), - )) - .expect("open sidecar session through wire"); - - match result.response.payload { - secure_exec_sidecar::wire::ResponsePayload::SessionOpenedResponse(response) => { - response.session_id - } - other => panic!("unexpected wire session response: {other:?}"), - } -} - -pub fn create_vm_wire( - sidecar: &mut NativeSidecar, - request_id: secure_exec_sidecar::wire::RequestId, - connection_id: &str, - session_id: &str, - runtime: secure_exec_sidecar::wire::GuestRuntimeKind, - cwd: &Path, -) -> (String, secure_exec_sidecar::wire::WireDispatchResult) { - create_vm_wire_with_metadata( - sidecar, - request_id, - connection_id, - session_id, - runtime, - cwd, - HashMap::new(), - ) -} - -pub fn create_vm_wire_with_metadata( - sidecar: &mut NativeSidecar, - request_id: secure_exec_sidecar::wire::RequestId, - connection_id: &str, - session_id: &str, - runtime: secure_exec_sidecar::wire::GuestRuntimeKind, - cwd: &Path, - mut metadata: HashMap, -) -> (String, secure_exec_sidecar::wire::WireDispatchResult) { - metadata - .entry(String::from("cwd")) - .or_insert_with(|| cwd.to_string_lossy().into_owned()); - - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_session(connection_id, session_id), - secure_exec_sidecar::wire::RequestPayload::CreateVmRequest( - secure_exec_sidecar::wire::CreateVmRequest::legacy_test_config( - runtime, - metadata, - secure_exec_sidecar::wire::RootFilesystemDescriptor { - mode: secure_exec_sidecar::wire::RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - }, - Some(wire_permissions_allow_all()), - ), - ), - )) - .expect("create sidecar VM through wire"); - - let vm_id = match &result.response.payload { - secure_exec_sidecar::wire::ResponsePayload::VmCreatedResponse(response) => { - response.vm_id.clone() - } - other => panic!("unexpected wire vm create response: {other:?}"), - }; - (vm_id, result) -} - -#[allow(clippy::too_many_arguments)] -pub fn execute_wire( - sidecar: &mut NativeSidecar, - request_id: secure_exec_sidecar::wire::RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - runtime: secure_exec_sidecar::wire::GuestRuntimeKind, - entrypoint: &Path, - args: Vec, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - request_id, - wire_vm(connection_id, session_id, vm_id), - secure_exec_sidecar::wire::RequestPayload::ExecuteRequest( - secure_exec_sidecar::wire::ExecuteRequest { - process_id: process_id.to_owned(), - command: None, - runtime: Some(runtime), - entrypoint: Some(entrypoint.to_string_lossy().into_owned()), - args, - env: HashMap::new(), - cwd: None, - wasm_permission_tier: None, - }, - ), - )) - .expect("start sidecar execution through wire"); - - match result.response.payload { - secure_exec_sidecar::wire::ResponsePayload::ProcessStartedResponse(response) => { - assert_eq!(response.process_id, process_id); - } - other => panic!("unexpected wire execute response: {other:?}"), - } -} - -pub fn collect_process_output_wire_with_timeout( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - timeout: Duration, -) -> (String, String, i32) { - let ownership = wire_session(connection_id, session_id); - let deadline = Instant::now() + timeout; - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit = None; - - loop { - let event = sidecar - .poll_event_wire_blocking(&ownership, Duration::from_millis(100)) - .expect("poll sidecar wire event"); - if let Some(event) = event { - assert_eq!(event.ownership, wire_vm(connection_id, session_id, vm_id)); - - match event.payload { - secure_exec_sidecar::wire::EventPayload::ProcessOutputEvent(output) => { - if output.process_id == process_id { - match output.channel { - secure_exec_sidecar::wire::StreamChannel::Stdout => { - append_process_stream_chunk( - &mut stdout, - &output.chunk, - process_id, - "stdout", - ); - } - secure_exec_sidecar::wire::StreamChannel::Stderr => { - append_process_stream_chunk( - &mut stderr, - &output.chunk, - process_id, - "stderr", - ); - } - } - } - } - secure_exec_sidecar::wire::EventPayload::ProcessExitedEvent(exited) - if exited.process_id == process_id => - { - exit = Some((exited.exit_code, Instant::now())); - } - secure_exec_sidecar::wire::EventPayload::ProcessExitedEvent(_) - | secure_exec_sidecar::wire::EventPayload::VmLifecycleEvent(_) - | secure_exec_sidecar::wire::EventPayload::StructuredEvent(_) - | secure_exec_sidecar::wire::EventPayload::ExtEnvelope(_) => {} - } - } - - if let Some((exit_code, seen_at)) = exit { - if Instant::now().duration_since(seen_at) >= Duration::from_millis(200) { - return ( - process_stream_to_string(&stdout), - process_stream_to_string(&stderr), - exit_code, - ); - } - } - - assert!( - Instant::now() < deadline, - "timed out waiting for wire process events; stdout bytes: {}; stderr bytes: {}", - stdout.len(), - stderr.len() - ); - } -} - -pub fn authenticate(sidecar: &mut NativeSidecar, connection_hint: &str) -> String { - authenticate_wire(sidecar, connection_hint) -} - -pub fn authenticate_with_token( - sidecar: &mut NativeSidecar, - request_id: RequestId, - connection_hint: &str, - auth_token: &str, -) -> DispatchResult { - let result = authenticate_wire_with_token(sidecar, request_id, connection_hint, auth_token); - dispatch_result_from_wire(result) -} - -pub fn open_session( - sidecar: &mut NativeSidecar, - request_id: RequestId, - connection_id: &str, -) -> String { - open_session_wire(sidecar, request_id, connection_id) -} - -pub fn create_vm( - sidecar: &mut NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - runtime: GuestRuntimeKind, - cwd: &Path, -) -> (String, DispatchResult) { - create_vm_with_metadata( - sidecar, - request_id, - connection_id, - session_id, - runtime, - cwd, - BTreeMap::new(), - ) -} - -pub fn create_vm_with_metadata( - sidecar: &mut NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - runtime: GuestRuntimeKind, - cwd: &Path, - metadata: BTreeMap, -) -> (String, DispatchResult) { - let (vm_id, result) = create_vm_wire_with_metadata( - sidecar, - request_id, - connection_id, - session_id, - wire_runtime_kind(runtime), - cwd, - metadata.into_iter().collect(), - ); - (vm_id, dispatch_result_from_wire(result)) -} - -#[allow(clippy::too_many_arguments)] -pub fn execute( - sidecar: &mut NativeSidecar, - request_id: RequestId, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - runtime: GuestRuntimeKind, - entrypoint: &Path, - args: Vec, -) { - execute_wire( - sidecar, - request_id, - connection_id, - session_id, - vm_id, - process_id, - wire_runtime_kind(runtime), - entrypoint, - args, - ); -} - -pub fn collect_process_output( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, -) -> (String, String, i32) { - collect_process_output_with_timeout( - sidecar, - connection_id, - session_id, - vm_id, - process_id, - Duration::from_secs(10), - ) -} - -pub fn collect_process_output_with_timeout( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, - process_id: &str, - timeout: Duration, -) -> (String, String, i32) { - collect_process_output_wire_with_timeout( - sidecar, - connection_id, - session_id, - vm_id, - process_id, - timeout, - ) -} - -fn dispatch_result_from_wire( - result: secure_exec_sidecar::wire::WireDispatchResult, -) -> DispatchResult { - DispatchResult { - response: response_frame_from_wire(result.response), - events: result - .events - .into_iter() - .map(event_frame_from_wire) - .collect(), - } -} - -fn response_frame_from_wire(response: secure_exec_sidecar::wire::ResponseFrame) -> ResponseFrame { - match secure_exec_sidecar::protocol::from_generated_protocol_frame( - secure_exec_sidecar::wire::ProtocolFrame::ResponseFrame(response), - ) - .expect("convert wire response frame to compatibility frame") - { - secure_exec_sidecar::protocol::ProtocolFrame::Response(response) => response, - other => panic!("unexpected compatibility response conversion: {other:?}"), - } -} - -fn event_frame_from_wire(event: secure_exec_sidecar::wire::EventFrame) -> EventFrame { - match secure_exec_sidecar::protocol::from_generated_protocol_frame( - secure_exec_sidecar::wire::ProtocolFrame::EventFrame(event), - ) - .expect("convert wire event frame to compatibility frame") - { - secure_exec_sidecar::protocol::ProtocolFrame::Event(event) => event, - other => panic!("unexpected compatibility event conversion: {other:?}"), - } -} - -fn wire_runtime_kind(runtime: GuestRuntimeKind) -> secure_exec_sidecar::wire::GuestRuntimeKind { - match runtime { - GuestRuntimeKind::JavaScript => secure_exec_sidecar::wire::GuestRuntimeKind::JavaScript, - GuestRuntimeKind::Python => secure_exec_sidecar::wire::GuestRuntimeKind::Python, - GuestRuntimeKind::WebAssembly => secure_exec_sidecar::wire::GuestRuntimeKind::WebAssembly, - } -} - -fn append_process_stream_chunk( - stream: &mut Vec, - chunk: &[u8], - process_id: &str, - stream_name: &str, -) { - assert!( - stream.len().saturating_add(chunk.len()) <= MAX_COLLECTED_PROCESS_STREAM_BYTES, - "process {process_id} {stream_name} exceeded {MAX_COLLECTED_PROCESS_STREAM_BYTES} bytes" - ); - stream.extend_from_slice(chunk); -} - -fn process_stream_to_string(stream: &[u8]) -> String { - String::from_utf8_lossy(stream).into_owned() -} - -#[test] -fn collect_process_output_stream_append_is_bounded() { - let mut stream = Vec::new(); - append_process_stream_chunk(&mut stream, &[b'a'; 16], "proc-limit", "stdout"); - assert_eq!(stream.len(), 16); - - let overflow = std::panic::catch_unwind(|| { - let mut stream = vec![b'a'; MAX_COLLECTED_PROCESS_STREAM_BYTES]; - append_process_stream_chunk(&mut stream, b"!", "proc-limit", "stdout"); - }); - assert!( - overflow.is_err(), - "oversized process output should fail the shared test harness" - ); -} - -pub fn dispose_vm_and_close_session( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, -) { - sidecar - .dispose_vm_internal_blocking(connection_id, session_id, vm_id, DisposeReason::Requested) - .expect("dispose sidecar VM"); - sidecar - .close_session_blocking(connection_id, session_id) - .expect("close sidecar session"); - sidecar - .remove_connection_blocking(connection_id) - .expect("remove sidecar connection"); -} - -pub fn dispose_vm_and_close_session_wire( - sidecar: &mut NativeSidecar, - connection_id: &str, - session_id: &str, - vm_id: &str, -) { - let result = sidecar - .dispatch_wire_blocking(wire_request( - 900, - wire_vm(connection_id, session_id, vm_id), - secure_exec_sidecar::wire::RequestPayload::DisposeVmRequest( - secure_exec_sidecar::wire::DisposeVmRequest { - reason: secure_exec_sidecar::wire::DisposeReason::Requested, - }, - ), - )) - .expect("dispose sidecar VM through wire"); - - match result.response.payload { - secure_exec_sidecar::wire::ResponsePayload::VmDisposedResponse(response) => { - assert_eq!(response.vm_id, vm_id); - } - other => panic!("unexpected wire vm dispose response: {other:?}"), - } - sidecar - .close_session_blocking(connection_id, session_id) - .expect("close sidecar session"); - sidecar - .remove_connection_blocking(connection_id) - .expect("remove sidecar connection"); -} - -pub fn write_fixture(path: &Path, contents: impl AsRef<[u8]>) { - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).expect("create fixture parent"); - } - fs::write(path, contents).expect("write fixture"); -} - -pub fn wasm_stdout_module() -> Vec { - wat::parse_str( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (memory (export "memory") 1) - (data (i32.const 16) "wasm:ready\n") - (func $_start (export "_start") - (i32.store (i32.const 0) (i32.const 16)) - (i32.store (i32.const 4) (i32.const 11)) - (drop - (call $fd_write - (i32.const 1) - (i32.const 0) - (i32.const 1) - (i32.const 32) - ) - ) - ) -) -"#, - ) - .expect("compile wasm fixture") -} - -pub fn wasm_signal_state_module() -> Vec { - wat::parse_str( - r#" -(module - (type $fd_write_t (func (param i32 i32 i32 i32) (result i32))) - (type $proc_sigaction_t (func (param i32 i32 i32 i32 i32) (result i32))) - (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (type $fd_write_t))) - (import "host_process" "proc_sigaction" (func $proc_sigaction (type $proc_sigaction_t))) - (memory (export "memory") 1) - (data (i32.const 32) "signal:ready\n") - (func $_start (export "_start") - (drop - (call $proc_sigaction - (i32.const 2) - (i32.const 2) - (i32.const 16384) - (i32.const 0) - (i32.const 4660) - ) - ) - (i32.store (i32.const 0) (i32.const 32)) - (i32.store (i32.const 4) (i32.const 13)) - (drop - (call $fd_write - (i32.const 1) - (i32.const 0) - (i32.const 1) - (i32.const 24) - ) - ) - ) -) -"#, - ) - .expect("compile signal-state wasm fixture") -} diff --git a/crates/sidecar/tests/vm_lifecycle.rs b/crates/sidecar/tests/vm_lifecycle.rs deleted file mode 100644 index 79080ac0f..000000000 --- a/crates/sidecar/tests/vm_lifecycle.rs +++ /dev/null @@ -1,203 +0,0 @@ -mod support; - -use secure_exec_bridge::{LoadFilesystemStateRequest, PersistenceBridge}; -use secure_exec_kernel::root_fs::{ - decode_snapshot as decode_root_snapshot, ROOT_FILESYSTEM_SNAPSHOT_FORMAT, -}; -use secure_exec_sidecar::wire::{ - BootstrapRootFilesystemRequest, DisposeReason, DisposeVmRequest, GuestRuntimeKind, - RequestPayload, ResponsePayload, RootFilesystemEntry, RootFilesystemEntryKind, -}; -use std::time::Duration; -use support::{ - assert_node_available, authenticate_wire, collect_process_output_wire_with_timeout, - create_vm_wire, execute_wire, new_sidecar, open_session_wire, temp_dir, wasm_stdout_module, - wire_request, wire_vm, write_fixture, -}; - -fn root_entry(path: &str, kind: RootFilesystemEntryKind, executable: bool) -> RootFilesystemEntry { - RootFilesystemEntry { - path: path.to_owned(), - kind, - mode: None, - uid: None, - gid: None, - content: None, - encoding: None, - target: None, - executable, - } -} - -#[test] -fn native_sidecar_composes_vm_lifecycle_bridge_callbacks_and_guest_execution() { - assert_node_available(); - - let mut sidecar = new_sidecar("vm-lifecycle"); - let cwd = temp_dir("vm-lifecycle-cwd"); - let js_entry = cwd.join("entry.mjs"); - let wasm_entry = cwd.join("entry.wasm"); - - write_fixture( - &js_entry, - r#" -console.log(`js:${process.argv.slice(2).join(",")}`); -"#, - ); - write_fixture(&wasm_entry, wasm_stdout_module()); - - let connection_id = authenticate_wire(&mut sidecar, "conn-1"); - let session_id = open_session_wire(&mut sidecar, 2, &connection_id); - - let (js_vm_id, js_create) = create_vm_wire( - &mut sidecar, - 3, - &connection_id, - &session_id, - GuestRuntimeKind::JavaScript, - &cwd, - ); - assert_eq!(js_create.events.len(), 2); - - let bootstrap = sidecar - .dispatch_wire_blocking(wire_request( - 4, - wire_vm(&connection_id, &session_id, &js_vm_id), - RequestPayload::BootstrapRootFilesystemRequest(BootstrapRootFilesystemRequest { - entries: vec![ - root_entry("/workspace", RootFilesystemEntryKind::Directory, false), - root_entry("/workspace/run.sh", RootFilesystemEntryKind::File, true), - ], - }), - )) - .expect("bootstrap root filesystem"); - match bootstrap.response.payload { - ResponsePayload::RootFilesystemBootstrappedResponse(response) => { - assert_eq!(response.entry_count, 2); - } - other => panic!("unexpected bootstrap response: {other:?}"), - } - - execute_wire( - &mut sidecar, - 5, - &connection_id, - &session_id, - &js_vm_id, - "proc-js", - GuestRuntimeKind::JavaScript, - &js_entry, - vec![String::from("alpha"), String::from("beta")], - ); - let (js_stdout, js_stderr, js_exit) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &js_vm_id, - "proc-js", - Duration::from_secs(10), - ); - assert_eq!(js_stdout.trim(), "js:alpha,beta"); - assert!(js_stderr.is_empty()); - assert_eq!(js_exit, 0); - - let (wasm_vm_id, _) = create_vm_wire( - &mut sidecar, - 6, - &connection_id, - &session_id, - GuestRuntimeKind::WebAssembly, - &cwd, - ); - execute_wire( - &mut sidecar, - 7, - &connection_id, - &session_id, - &wasm_vm_id, - "proc-wasm", - GuestRuntimeKind::WebAssembly, - &wasm_entry, - Vec::new(), - ); - let (wasm_stdout, wasm_stderr, wasm_exit) = collect_process_output_wire_with_timeout( - &mut sidecar, - &connection_id, - &session_id, - &wasm_vm_id, - "proc-wasm", - Duration::from_secs(10), - ); - assert_eq!(wasm_stdout.trim(), "wasm:ready"); - assert!(wasm_stderr.is_empty()); - assert_eq!(wasm_exit, 0); - - sidecar - .dispatch_wire_blocking(wire_request( - 8, - wire_vm(&connection_id, &session_id, &js_vm_id), - RequestPayload::DisposeVmRequest(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - )) - .expect("dispose js vm"); - sidecar - .dispatch_wire_blocking(wire_request( - 9, - wire_vm(&connection_id, &session_id, &wasm_vm_id), - RequestPayload::DisposeVmRequest(DisposeVmRequest { - reason: DisposeReason::Requested, - }), - )) - .expect("dispose wasm vm"); - - sidecar - .with_bridge_mut(|bridge: &mut support::RecordingBridge| { - let command_checks = bridge - .permission_checks - .iter() - .filter(|check| check.starts_with("cmd:")) - .collect::>(); - if !command_checks.is_empty() { - assert!(command_checks.iter().any(|check| { - *check == &format!("cmd:{js_vm_id}:node") - || *check == &format!("cmd:{wasm_vm_id}:wasm") - })); - } - let js_snapshot = bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: js_vm_id.clone(), - }) - .expect("load js snapshot") - .expect("persisted js snapshot"); - assert_eq!(js_snapshot.format, ROOT_FILESYSTEM_SNAPSHOT_FORMAT); - let js_root = - decode_root_snapshot(&js_snapshot.bytes).expect("decode js root snapshot"); - assert!(js_root - .entries - .iter() - .any(|entry| entry.path == "/bin/node")); - assert!(js_root - .entries - .iter() - .any(|entry| entry.path == "/workspace/run.sh")); - - let wasm_snapshot = bridge - .load_filesystem_state(LoadFilesystemStateRequest { - vm_id: wasm_vm_id.clone(), - }) - .expect("load wasm snapshot") - .expect("persisted wasm snapshot"); - assert_eq!(wasm_snapshot.format, ROOT_FILESYSTEM_SNAPSHOT_FORMAT); - let wasm_root = - decode_root_snapshot(&wasm_snapshot.bytes).expect("decode wasm root snapshot"); - assert!(!wasm_root - .entries - .iter() - .any(|entry| entry.path == "/workspace/run.sh")); - assert!(bridge.lifecycle_events.iter().any(|event| { - event.vm_id == js_vm_id && event.state == secure_exec_bridge::LifecycleState::Busy - })); - }) - .expect("inspect bridge"); -} diff --git a/crates/sidecar/tests/wire_dispatch.rs b/crates/sidecar/tests/wire_dispatch.rs deleted file mode 100644 index 5f73c4057..000000000 --- a/crates/sidecar/tests/wire_dispatch.rs +++ /dev/null @@ -1,58 +0,0 @@ -mod support; - -use secure_exec_sidecar::wire::{ - AuthenticateRequest, ConnectionOwnership, OwnershipScope, RequestFrame, RequestPayload, - ResponsePayload, WireFrameCodec, PROTOCOL_VERSION, -}; -use support::{new_sidecar, TEST_AUTH_TOKEN}; - -#[test] -fn wire_frame_codec_round_trips_generated_request_frames() { - let codec = WireFrameCodec::default(); - let frame = authenticate_request_frame(); - - let encoded = codec - .encode(&secure_exec_sidecar::wire::ProtocolFrame::RequestFrame( - frame.clone(), - )) - .expect("encode wire frame"); - let decoded = codec.decode(&encoded).expect("decode wire frame"); - - assert_eq!( - decoded, - secure_exec_sidecar::wire::ProtocolFrame::RequestFrame(frame) - ); -} - -#[test] -fn native_sidecar_dispatches_generated_wire_request_frames() { - let mut sidecar = new_sidecar("wire-dispatch"); - - let result = sidecar - .dispatch_wire_blocking(authenticate_request_frame()) - .expect("dispatch generated wire authenticate request"); - - match result.response.payload { - ResponsePayload::AuthenticatedResponse(response) => { - assert!(!response.connection_id.is_empty()); - assert_eq!(result.events, Vec::new()); - } - other => panic!("unexpected wire response: {other:?}"), - } -} - -fn authenticate_request_frame() -> RequestFrame { - RequestFrame { - schema: secure_exec_sidecar::wire::protocol_schema(), - request_id: 1, - ownership: OwnershipScope::ConnectionOwnership(ConnectionOwnership { - connection_id: String::from("conn-1"), - }), - payload: RequestPayload::AuthenticateRequest(AuthenticateRequest { - client_name: String::from("generated-wire-test"), - auth_token: String::from(TEST_AUTH_TOKEN), - protocol_version: PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - } -} diff --git a/crates/v8-runtime/AGENTS.md b/crates/v8-runtime/AGENTS.md deleted file mode 120000 index 681311eb9..000000000 --- a/crates/v8-runtime/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/crates/v8-runtime/CLAUDE.md b/crates/v8-runtime/CLAUDE.md deleted file mode 100644 index 9afca1a2d..000000000 --- a/crates/v8-runtime/CLAUDE.md +++ /dev/null @@ -1,15 +0,0 @@ -# V8 Runtime - -- Guest WebAssembly compilation is enabled by default. Do not install a `set_allow_wasm_code_generation_callback` deny hook on fresh isolates or snapshot restores; package compatibility depends on `WebAssembly.Module` and `WebAssembly.Instance` working inside the isolate. -- WebAssembly safety still comes from V8's built-in limits. Conformance coverage should prove guest WASM works while oversized memory declarations still fail with V8 errors instead of reintroducing an embedder-level deny path. -- Async guest WASM (`await WebAssembly.instantiate(...)` / `await WebAssembly.compile(...)`) only settles once the session driver pumps both halves of V8's deferred work: `run_event_loop()` must keep calling `pump_v8_message_loop()` to drain platform foreground tasks posted by async WASM compilation, then `perform_microtask_checkpoint()` to settle the returned Promise. If either step is skipped, sync `WebAssembly.Module` still works while async WASM appears to hang until the outer wall-clock timeout. -- Keep `BinaryFrame` at the compatibility boundary only. In-process embedded-runtime session plumbing should use `runtime_protocol::{RuntimeCommand, SessionMessage, RuntimeEvent}` so bridge responses, stream events, and execution results do not bounce through IPC framing inside the same process. -- In `src/session.rs`, a session may reuse its isolate only while the effective bridge code is unchanged. Snapshot-restored contexts clone the snapshot's default context, so changing bridge code between `Execute` calls must rebuild the isolate or the session will keep restoring the old bridge snapshot. -- In `src/session.rs`, top-level `SessionMessage` handling must never silently drop late `BridgeResponse`, `StreamEvent`, or `TerminateExecution` frames after an execution finishes. If there is no active event loop to consume them, emit a structured `RuntimeEvent::Log` warning with an explicit `ERR_LATE_*` code so host-side diagnostics can see the loss. -- In `src/session.rs`, sync bridge waits need the same per-execution abort path for both CPU timeouts and explicit `TerminateExecution` requests. If a terminate signal only hits `isolate_handle.terminate_execution()` and does not also close the active bridge-wait receiver, a guest blocked inside a sync host call will hang until the host replies. -- In `src/session.rs`, `run_event_loop()` must consult `_getPendingTimerCount()` directly in its exit checks, not only pending promises or `_waitForActiveHandles()`. Some callers enter the loop without first registering the keepalive promise, and otherwise a lone ref'd `setInterval()` can let the session exit between ticks. -- Session-quota regressions now live in `src/embedded_runtime.rs`, not a removed daemon `main.rs`: keep one `SessionManager` per `EmbeddedV8Runtime`, share it across every runtime handle/connection to that instance, and cover quota behavior in `tests/embedded_runtime_session.rs`. -- In `tests/embedded_runtime_session.rs`, shared-quota assertions must saturate the runtime slots before registering any session that is supposed to stay queued. `SessionManager` acquires slots during `CreateSession`, so relying on creation order alone makes queued-session tests race with the sessions meant to hold the slots. -- Guest `process.memoryUsage()`, `process.cpuUsage()`, `process.resourceUsage()`, and live `process.versions.v8` should be resolved locally on the V8 session thread in `src/bridge.rs`, using `v8::HeapStatistics`, `getrusage(RUSAGE_THREAD)`, and the bundled library version APIs. Do not reintroduce stale JS literals or route these per-isolate values back through sidecar RPC. -- Guest crypto is served by pure-Rust crates (RustCrypto), not OpenSSL, so there is no live OpenSSL library to query. `process.versions.openssl` is therefore a pinned constant (`EMULATED_OPENSSL_VERSION`) matching the OpenSSL release bundled by the emulated Node version; keep it in sync with the browser executor's `process.versions.openssl` so both runtimes present an identical identity. -- Guest `node:vm` isolation belongs in `src/bridge.rs` local bridge calls (`_vmCreateContext`, `_vmRunInContext`, `_vmRunInThisContext`), not sidecar RPC. Those callbacks must keep sandbox-to-context mirroring, restricted-global scrubbing (`Buffer`, `require`, etc.), and timeout-driven `terminate_execution()` behavior aligned with the JavaScript-facing shims in `crates/execution`. diff --git a/crates/v8-runtime/Cargo.lock b/crates/v8-runtime/Cargo.lock deleted file mode 100644 index 86a9efc9b..000000000 --- a/crates/v8-runtime/Cargo.lock +++ /dev/null @@ -1,584 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", -] - -[[package]] -name = "bitflags" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "ciborium" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" - -[[package]] -name = "ciborium-ll" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "fslock" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "gzip-header" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95cc527b92e6029a62960ad99aa8a6660faa4555fe5f731aab13aa6a921795a2" -dependencies = [ - "crc32fast", -] - -[[package]] -name = "half" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" -dependencies = [ - "cfg-if", - "crunchy", - "zerocopy", -] - -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "libc" -version = "0.2.183" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" - -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "secure-exec-v8-runtime" -version = "0.1.0" -dependencies = [ - "ciborium", - "crossbeam-channel", - "libc", - "signal-hook", - "v8", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "v8" -version = "130.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a511192602f7b435b0a241c1947aa743eb7717f20a9195f4b5e8ed1952e01db1" -dependencies = [ - "bindgen", - "bitflags", - "fslock", - "gzip-header", - "home", - "miniz_oxide", - "once_cell", - "paste", - "which", -] - -[[package]] -name = "which" -version = "6.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" -dependencies = [ - "either", - "home", - "rustix", - "winsafe", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winsafe" -version = "0.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" - -[[package]] -name = "zerocopy" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/crates/v8-runtime/Cargo.toml b/crates/v8-runtime/Cargo.toml index 79ba49c54..be5b3b342 100644 --- a/crates/v8-runtime/Cargo.toml +++ b/crates/v8-runtime/Cargo.toml @@ -4,17 +4,10 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "V8 isolate runtime for secure-exec guest JavaScript execution" +description = "secure-exec-v8-runtime compatibility shim for agentos-v8-runtime" -[dependencies] -secure-exec-bridge = { workspace = true } -v8 = "130" -crossbeam-channel = "0.5" -signal-hook = "0.3" -libc = "0.2" -ciborium = "0.2" -serde = "1.0" -sha2 = "0.10" +[lib] +name = "secure_exec_v8_runtime" -[build-dependencies] -secure-exec-build-support = { workspace = true } +[dependencies] +agentos_v8_runtime = { package = "agentos-v8-runtime", path = "../../../agentos/crates/v8-runtime", version = "0.0.1" } diff --git a/crates/v8-runtime/assets/generated/v8-bridge-zlib.js b/crates/v8-runtime/assets/generated/v8-bridge-zlib.js deleted file mode 100644 index e1b73de4b..000000000 --- a/crates/v8-runtime/assets/generated/v8-bridge-zlib.js +++ /dev/null @@ -1,91 +0,0 @@ -if(typeof globalThis.global==="undefined"){globalThis.global=globalThis;}if(typeof globalThis.process==="undefined"){globalThis.process={env:{},argv:["node"],browser:false,version:"v22.0.0",versions:{node:"22.0.0"},nextTick(callback,...args){return Promise.resolve().then(()=>callback(...args));}};}if(typeof globalThis.TextEncoder==="undefined"){globalThis.TextEncoder=class{encode(value=""){const input=String(value??"");const encoded=unescape(encodeURIComponent(input));const out=new Uint8Array(encoded.length);for(let i=0;isum+(item?.length??0),0);const out=new __SecureExecEarlyBuffer(length);let offset=0;for(const item of list){const chunk=item instanceof Uint8Array?item:__SecureExecEarlyBuffer.from(item);out.set(chunk,offset);offset+=chunk.length;}return out;}static isBuffer(value){return value instanceof Uint8Array;}static byteLength(value,encoding="utf8"){return __SecureExecEarlyBuffer.from(value,encoding).byteLength;}toString(encoding="utf8"){if(encoding==="base64"&&typeof btoa==="function"){let binary="";for(const byte of this){binary+=String.fromCharCode(byte);}return btoa(binary);}if(encoding==="binary"||encoding==="latin1"){let binary="";for(const byte of this){binary+=String.fromCharCode(byte);}return binary;}if(__secureExecTd){return __secureExecTd.decode(this);}return Array.from(this,byte=>String.fromCharCode(byte)).join("");}}globalThis.Buffer=__SecureExecEarlyBuffer;}if(typeof globalThis.performance==="undefined"){const __secureExecPerformanceStart=Date.now();globalThis.performance={now(){if(typeof globalThis.__secureExecHrNowUs==="function"){return globalThis.__secureExecHrNowUs()/1000;}return Date.now()-__secureExecPerformanceStart;}};}if(typeof globalThis.performance.markResourceTiming!=="function"){globalThis.performance.markResourceTiming=()=>{};}if(typeof TextEncoder==="undefined"&&typeof globalThis.TextEncoder!=="undefined"){var TextEncoder=globalThis.TextEncoder;}if(typeof TextDecoder==="undefined"&&typeof globalThis.TextDecoder!=="undefined"){var TextDecoder=globalThis.TextDecoder;}if(typeof Buffer==="undefined"&&typeof globalThis.Buffer!=="undefined"){var Buffer=globalThis.Buffer;} -(()=>{var Gd=Object.create;var nn=Object.defineProperty;var $d=Object.getOwnPropertyDescriptor;var Vd=Object.getOwnPropertyNames;var Yd=Object.getPrototypeOf,Kd=Object.prototype.hasOwnProperty;var Xd=(e,r)=>()=>(e&&(r=e(e=0)),r);var y=(e,r)=>()=>(r||e((r={exports:{}}).exports,r),r.exports),Jd=(e,r)=>{for(var t in r)nn(e,t,{get:r[t],enumerable:!0})},tn=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of Vd(r))!Kd.call(e,i)&&i!==t&&nn(e,i,{get:()=>r[i],enumerable:!(n=$d(r,i))||n.enumerable});return e},re=(e,r,t)=>(tn(e,r,"default"),t&&tn(t,r,"default")),ft=(e,r,t)=>(t=e!=null?Gd(Yd(e)):{},tn(r||!e||!e.__esModule?nn(t,"default",{value:e,enumerable:!0}):t,e)),Qd=e=>tn(nn({},"__esModule",{value:!0}),e);var an=y((Um,of)=>{"use strict";of.exports=function(){if(typeof Symbol!="function"||typeof Object.getOwnPropertySymbols!="function")return!1;if(typeof Symbol.iterator=="symbol")return!0;var r={},t=Symbol("test"),n=Object(t);if(typeof t=="string"||Object.prototype.toString.call(t)!=="[object Symbol]"||Object.prototype.toString.call(n)!=="[object Symbol]")return!1;var i=42;r[t]=i;for(var a in r)return!1;if(typeof Object.keys=="function"&&Object.keys(r).length!==0||typeof Object.getOwnPropertyNames=="function"&&Object.getOwnPropertyNames(r).length!==0)return!1;var o=Object.getOwnPropertySymbols(r);if(o.length!==1||o[0]!==t||!Object.prototype.propertyIsEnumerable.call(r,t))return!1;if(typeof Object.getOwnPropertyDescriptor=="function"){var f=Object.getOwnPropertyDescriptor(r,t);if(f.value!==i||f.enumerable!==!0)return!1}return!0}});var ut=y((Cm,ff)=>{"use strict";var ey=an();ff.exports=function(){return ey()&&!!Symbol.toStringTag}});var on=y((zm,uf)=>{"use strict";uf.exports=Object});var sf=y((Zm,lf)=>{"use strict";lf.exports=Error});var hf=y((Wm,cf)=>{"use strict";cf.exports=EvalError});var df=y((Hm,pf)=>{"use strict";pf.exports=RangeError});var vf=y((Gm,yf)=>{"use strict";yf.exports=ReferenceError});var Ci=y(($m,_f)=>{"use strict";_f.exports=SyntaxError});var kr=y((Vm,gf)=>{"use strict";gf.exports=TypeError});var wf=y((Ym,bf)=>{"use strict";bf.exports=URIError});var mf=y((Km,Ef)=>{"use strict";Ef.exports=Math.abs});var xf=y((Xm,Sf)=>{"use strict";Sf.exports=Math.floor});var Rf=y((Jm,Af)=>{"use strict";Af.exports=Math.max});var Tf=y((Qm,Of)=>{"use strict";Of.exports=Math.min});var Nf=y((e1,If)=>{"use strict";If.exports=Math.pow});var Ff=y((r1,Lf)=>{"use strict";Lf.exports=Math.round});var Pf=y((t1,kf)=>{"use strict";kf.exports=Number.isNaN||function(r){return r!==r}});var Mf=y((n1,Df)=>{"use strict";var ry=Pf();Df.exports=function(r){return ry(r)||r===0?r:r<0?-1:1}});var Bf=y((i1,jf)=>{"use strict";jf.exports=Object.getOwnPropertyDescriptor});var rr=y((a1,qf)=>{"use strict";var fn=Bf();if(fn)try{fn([],"length")}catch{fn=null}qf.exports=fn});var lt=y((o1,Uf)=>{"use strict";var un=Object.defineProperty||!1;if(un)try{un({},"a",{value:1})}catch{un=!1}Uf.exports=un});var Zf=y((f1,zf)=>{"use strict";var Cf=typeof Symbol<"u"&&Symbol,ty=an();zf.exports=function(){return typeof Cf!="function"||typeof Symbol!="function"||typeof Cf("foo")!="symbol"||typeof Symbol("bar")!="symbol"?!1:ty()}});var zi=y((u1,Wf)=>{"use strict";Wf.exports=typeof Reflect<"u"&&Reflect.getPrototypeOf||null});var Zi=y((l1,Hf)=>{"use strict";var ny=on();Hf.exports=ny.getPrototypeOf||null});var Vf=y((s1,$f)=>{"use strict";var iy="Function.prototype.bind called on incompatible ",ay=Object.prototype.toString,oy=Math.max,fy="[object Function]",Gf=function(r,t){for(var n=[],i=0;i{"use strict";var sy=Vf();Yf.exports=Function.prototype.bind||sy});var ln=y((h1,Kf)=>{"use strict";Kf.exports=Function.prototype.call});var sn=y((p1,Xf)=>{"use strict";Xf.exports=Function.prototype.apply});var Qf=y((d1,Jf)=>{"use strict";Jf.exports=typeof Reflect<"u"&&Reflect&&Reflect.apply});var Wi=y((y1,eu)=>{"use strict";var cy=Pr(),hy=sn(),py=ln(),dy=Qf();eu.exports=dy||cy.call(py,hy)});var cn=y((v1,ru)=>{"use strict";var yy=Pr(),vy=kr(),_y=ln(),gy=Wi();ru.exports=function(r){if(r.length<1||typeof r[0]!="function")throw new vy("a function is required");return gy(yy,_y,r)}});var fu=y((_1,ou)=>{"use strict";var by=cn(),tu=rr(),iu;try{iu=[].__proto__===Array.prototype}catch(e){if(!e||typeof e!="object"||!("code"in e)||e.code!=="ERR_PROTO_ACCESS")throw e}var Hi=!!iu&&tu&&tu(Object.prototype,"__proto__"),au=Object,nu=au.getPrototypeOf;ou.exports=Hi&&typeof Hi.get=="function"?by([Hi.get]):typeof nu=="function"?function(r){return nu(r==null?r:au(r))}:!1});var hn=y((g1,cu)=>{"use strict";var uu=zi(),lu=Zi(),su=fu();cu.exports=uu?function(r){return uu(r)}:lu?function(r){if(!r||typeof r!="object"&&typeof r!="function")throw new TypeError("getProto: not an object");return lu(r)}:su?function(r){return su(r)}:null});var Gi=y((b1,hu)=>{"use strict";var wy=Function.prototype.call,Ey=Object.prototype.hasOwnProperty,my=Pr();hu.exports=my.call(wy,Ey)});var yn=y((w1,gu)=>{"use strict";var F,Sy=on(),xy=sf(),Ay=hf(),Ry=df(),Oy=vf(),Br=Ci(),jr=kr(),Ty=wf(),Iy=mf(),Ny=xf(),Ly=Rf(),Fy=Tf(),ky=Nf(),Py=Ff(),Dy=Mf(),vu=Function,$i=function(e){try{return vu('"use strict"; return ('+e+").constructor;")()}catch{}},st=rr(),My=lt(),Vi=function(){throw new jr},jy=st?(function(){try{return arguments.callee,Vi}catch{try{return st(arguments,"callee").get}catch{return Vi}}})():Vi,Dr=Zf()(),G=hn(),By=Zi(),qy=zi(),_u=sn(),ct=ln(),Mr={},Uy=typeof Uint8Array>"u"||!G?F:G(Uint8Array),tr={__proto__:null,"%AggregateError%":typeof AggregateError>"u"?F:AggregateError,"%Array%":Array,"%ArrayBuffer%":typeof ArrayBuffer>"u"?F:ArrayBuffer,"%ArrayIteratorPrototype%":Dr&&G?G([][Symbol.iterator]()):F,"%AsyncFromSyncIteratorPrototype%":F,"%AsyncFunction%":Mr,"%AsyncGenerator%":Mr,"%AsyncGeneratorFunction%":Mr,"%AsyncIteratorPrototype%":Mr,"%Atomics%":typeof Atomics>"u"?F:Atomics,"%BigInt%":typeof BigInt>"u"?F:BigInt,"%BigInt64Array%":typeof BigInt64Array>"u"?F:BigInt64Array,"%BigUint64Array%":typeof BigUint64Array>"u"?F:BigUint64Array,"%Boolean%":Boolean,"%DataView%":typeof DataView>"u"?F:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":xy,"%eval%":eval,"%EvalError%":Ay,"%Float16Array%":typeof Float16Array>"u"?F:Float16Array,"%Float32Array%":typeof Float32Array>"u"?F:Float32Array,"%Float64Array%":typeof Float64Array>"u"?F:Float64Array,"%FinalizationRegistry%":typeof FinalizationRegistry>"u"?F:FinalizationRegistry,"%Function%":vu,"%GeneratorFunction%":Mr,"%Int8Array%":typeof Int8Array>"u"?F:Int8Array,"%Int16Array%":typeof Int16Array>"u"?F:Int16Array,"%Int32Array%":typeof Int32Array>"u"?F:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":Dr&&G?G(G([][Symbol.iterator]())):F,"%JSON%":typeof JSON=="object"?JSON:F,"%Map%":typeof Map>"u"?F:Map,"%MapIteratorPrototype%":typeof Map>"u"||!Dr||!G?F:G(new Map()[Symbol.iterator]()),"%Math%":Math,"%Number%":Number,"%Object%":Sy,"%Object.getOwnPropertyDescriptor%":st,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":typeof Promise>"u"?F:Promise,"%Proxy%":typeof Proxy>"u"?F:Proxy,"%RangeError%":Ry,"%ReferenceError%":Oy,"%Reflect%":typeof Reflect>"u"?F:Reflect,"%RegExp%":RegExp,"%Set%":typeof Set>"u"?F:Set,"%SetIteratorPrototype%":typeof Set>"u"||!Dr||!G?F:G(new Set()[Symbol.iterator]()),"%SharedArrayBuffer%":typeof SharedArrayBuffer>"u"?F:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":Dr&&G?G(""[Symbol.iterator]()):F,"%Symbol%":Dr?Symbol:F,"%SyntaxError%":Br,"%ThrowTypeError%":jy,"%TypedArray%":Uy,"%TypeError%":jr,"%Uint8Array%":typeof Uint8Array>"u"?F:Uint8Array,"%Uint8ClampedArray%":typeof Uint8ClampedArray>"u"?F:Uint8ClampedArray,"%Uint16Array%":typeof Uint16Array>"u"?F:Uint16Array,"%Uint32Array%":typeof Uint32Array>"u"?F:Uint32Array,"%URIError%":Ty,"%WeakMap%":typeof WeakMap>"u"?F:WeakMap,"%WeakRef%":typeof WeakRef>"u"?F:WeakRef,"%WeakSet%":typeof WeakSet>"u"?F:WeakSet,"%Function.prototype.call%":ct,"%Function.prototype.apply%":_u,"%Object.defineProperty%":My,"%Object.getPrototypeOf%":By,"%Math.abs%":Iy,"%Math.floor%":Ny,"%Math.max%":Ly,"%Math.min%":Fy,"%Math.pow%":ky,"%Math.round%":Py,"%Math.sign%":Dy,"%Reflect.getPrototypeOf%":qy};if(G)try{null.error}catch(e){pu=G(G(e)),tr["%Error.prototype%"]=pu}var pu,Cy=function e(r){var t;if(r==="%AsyncFunction%")t=$i("async function () {}");else if(r==="%GeneratorFunction%")t=$i("function* () {}");else if(r==="%AsyncGeneratorFunction%")t=$i("async function* () {}");else if(r==="%AsyncGenerator%"){var n=e("%AsyncGeneratorFunction%");n&&(t=n.prototype)}else if(r==="%AsyncIteratorPrototype%"){var i=e("%AsyncGenerator%");i&&G&&(t=G(i.prototype))}return tr[r]=t,t},du={__proto__:null,"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},ht=Pr(),pn=Gi(),zy=ht.call(ct,Array.prototype.concat),Zy=ht.call(_u,Array.prototype.splice),yu=ht.call(ct,String.prototype.replace),dn=ht.call(ct,String.prototype.slice),Wy=ht.call(ct,RegExp.prototype.exec),Hy=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,Gy=/\\(\\)?/g,$y=function(r){var t=dn(r,0,1),n=dn(r,-1);if(t==="%"&&n!=="%")throw new Br("invalid intrinsic syntax, expected closing `%`");if(n==="%"&&t!=="%")throw new Br("invalid intrinsic syntax, expected opening `%`");var i=[];return yu(r,Hy,function(a,o,f,s){i[i.length]=f?yu(s,Gy,"$1"):o||a}),i},Vy=function(r,t){var n=r,i;if(pn(du,n)&&(i=du[n],n="%"+i[0]+"%"),pn(tr,n)){var a=tr[n];if(a===Mr&&(a=Cy(n)),typeof a>"u"&&!t)throw new jr("intrinsic "+r+" exists, but is not available. Please file an issue!");return{alias:i,name:n,value:a}}throw new Br("intrinsic "+r+" does not exist!")};gu.exports=function(r,t){if(typeof r!="string"||r.length===0)throw new jr("intrinsic name must be a non-empty string");if(arguments.length>1&&typeof t!="boolean")throw new jr('"allowMissing" argument must be a boolean');if(Wy(/^%?[^%]*%?$/,r)===null)throw new Br("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var n=$y(r),i=n.length>0?n[0]:"",a=Vy("%"+i+"%",t),o=a.name,f=a.value,s=!1,u=a.alias;u&&(i=u[0],Zy(n,zy([0,1],u)));for(var l=1,c=!0;l=n.length){var _=st(f,p);c=!!_,c&&"get"in _&&!("originalValue"in _.get)?f=_.get:f=f[p]}else c=pn(f,p),f=f[p];c&&!s&&(tr[o]=f)}}return f}});var nr=y((E1,Eu)=>{"use strict";var bu=yn(),wu=cn(),Yy=wu([bu("%String.prototype.indexOf%")]);Eu.exports=function(r,t){var n=bu(r,!!t);return typeof n=="function"&&Yy(r,".prototype.")>-1?wu([n]):n}});var xu=y((m1,Su)=>{"use strict";var Ky=ut()(),Xy=nr(),Yi=Xy("Object.prototype.toString"),vn=function(r){return Ky&&r&&typeof r=="object"&&Symbol.toStringTag in r?!1:Yi(r)==="[object Arguments]"},mu=function(r){return vn(r)?!0:r!==null&&typeof r=="object"&&"length"in r&&typeof r.length=="number"&&r.length>=0&&Yi(r)!=="[object Array]"&&"callee"in r&&Yi(r.callee)==="[object Function]"},Jy=(function(){return vn(arguments)})();vn.isLegacyArguments=mu;Su.exports=Jy?vn:mu});var Nu=y((S1,Iu)=>{"use strict";var Au=nr(),Qy=ut()(),e0=Gi(),r0=rr(),Ji;Qy?(Ru=Au("RegExp.prototype.exec"),Ki={},_n=function(){throw Ki},Xi={toString:_n,valueOf:_n},typeof Symbol.toPrimitive=="symbol"&&(Xi[Symbol.toPrimitive]=_n),Ji=function(r){if(!r||typeof r!="object")return!1;var t=r0(r,"lastIndex"),n=t&&e0(t,"value");if(!n)return!1;try{Ru(r,Xi)}catch(i){return i===Ki}}):(Ou=Au("Object.prototype.toString"),Tu="[object RegExp]",Ji=function(r){return!r||typeof r!="object"&&typeof r!="function"?!1:Ou(r)===Tu});var Ru,Ki,_n,Xi,Ou,Tu;Iu.exports=Ji});var Fu=y((x1,Lu)=>{"use strict";var t0=nr(),n0=Nu(),i0=t0("RegExp.prototype.exec"),a0=kr();Lu.exports=function(r){if(!n0(r))throw new a0("`regex` must be a RegExp");return function(n){return i0(r,n)!==null}}});var Pu=y((A1,ku)=>{"use strict";var o0=function*(){}.constructor;ku.exports=()=>o0});var Bu=y((R1,ju)=>{"use strict";var Mu=nr(),f0=Fu(),u0=f0(/^\s*(?:function)?\*/),l0=ut()(),Du=hn(),s0=Mu("Object.prototype.toString"),c0=Mu("Function.prototype.toString"),h0=Pu();ju.exports=function(r){if(typeof r!="function")return!1;if(u0(c0(r)))return!0;if(!l0){var t=s0(r);return t==="[object GeneratorFunction]"}if(!Du)return!1;var n=h0();return n&&Du(r)===n.prototype}});var zu=y((O1,Cu)=>{"use strict";var Uu=Function.prototype.toString,qr=typeof Reflect=="object"&&Reflect!==null&&Reflect.apply,ea,gn;if(typeof qr=="function"&&typeof Object.defineProperty=="function")try{ea=Object.defineProperty({},"length",{get:function(){throw gn}}),gn={},qr(function(){throw 42},null,ea)}catch(e){e!==gn&&(qr=null)}else qr=null;var p0=/^\s*class\b/,ra=function(r){try{var t=Uu.call(r);return p0.test(t)}catch{return!1}},Qi=function(r){try{return ra(r)?!1:(Uu.call(r),!0)}catch{return!1}},bn=Object.prototype.toString,d0="[object Object]",y0="[object Function]",v0="[object GeneratorFunction]",_0="[object HTMLAllCollection]",g0="[object HTML document.all class]",b0="[object HTMLCollection]",w0=typeof Symbol=="function"&&!!Symbol.toStringTag,E0=!(0 in[,]),ta=function(){return!1};typeof document=="object"&&(qu=document.all,bn.call(qu)===bn.call(document.all)&&(ta=function(r){if((E0||!r)&&(typeof r>"u"||typeof r=="object"))try{var t=bn.call(r);return(t===_0||t===g0||t===b0||t===d0)&&r("")==null}catch{}return!1}));var qu;Cu.exports=qr?function(r){if(ta(r))return!0;if(!r||typeof r!="function"&&typeof r!="object")return!1;try{qr(r,null,ea)}catch(t){if(t!==gn)return!1}return!ra(r)&&Qi(r)}:function(r){if(ta(r))return!0;if(!r||typeof r!="function"&&typeof r!="object")return!1;if(w0)return Qi(r);if(ra(r))return!1;var t=bn.call(r);return t!==y0&&t!==v0&&!/^\[object HTML/.test(t)?!1:Qi(r)}});var Hu=y((T1,Wu)=>{"use strict";var m0=zu(),S0=Object.prototype.toString,Zu=Object.prototype.hasOwnProperty,x0=function(r,t,n){for(var i=0,a=r.length;i=3&&(i=n),O0(r)?x0(r,t,i):typeof r=="string"?A0(r,t,i):R0(r,t,i)}});var $u=y((I1,Gu)=>{"use strict";Gu.exports=["Float16Array","Float32Array","Float64Array","Int8Array","Int16Array","Int32Array","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array"]});var Yu=y((N1,Vu)=>{"use strict";var na=$u(),T0=globalThis;Vu.exports=function(){for(var r=[],t=0;t{"use strict";var Ku=lt(),I0=Ci(),Ur=kr(),Xu=rr();Ju.exports=function(r,t,n){if(!r||typeof r!="object"&&typeof r!="function")throw new Ur("`obj` must be an object or a function`");if(typeof t!="string"&&typeof t!="symbol")throw new Ur("`property` must be a string or a symbol`");if(arguments.length>3&&typeof arguments[3]!="boolean"&&arguments[3]!==null)throw new Ur("`nonEnumerable`, if provided, must be a boolean or null");if(arguments.length>4&&typeof arguments[4]!="boolean"&&arguments[4]!==null)throw new Ur("`nonWritable`, if provided, must be a boolean or null");if(arguments.length>5&&typeof arguments[5]!="boolean"&&arguments[5]!==null)throw new Ur("`nonConfigurable`, if provided, must be a boolean or null");if(arguments.length>6&&typeof arguments[6]!="boolean")throw new Ur("`loose`, if provided, must be a boolean");var i=arguments.length>3?arguments[3]:null,a=arguments.length>4?arguments[4]:null,o=arguments.length>5?arguments[5]:null,f=arguments.length>6?arguments[6]:!1,s=!!Xu&&Xu(r,t);if(Ku)Ku(r,t,{configurable:o===null&&s?s.configurable:!o,enumerable:i===null&&s?s.enumerable:!i,value:n,writable:a===null&&s?s.writable:!a});else if(f||!i&&!a&&!o)r[t]=n;else throw new I0("This environment does not support defining a property as non-configurable, non-writable, or non-enumerable.")}});var oa=y((F1,el)=>{"use strict";var aa=lt(),Qu=function(){return!!aa};Qu.hasArrayLengthDefineBug=function(){if(!aa)return null;try{return aa([],"length",{value:1}).length!==1}catch{return!0}};el.exports=Qu});var al=y((k1,il)=>{"use strict";var N0=yn(),rl=ia(),L0=oa()(),tl=rr(),nl=kr(),F0=N0("%Math.floor%");il.exports=function(r,t){if(typeof r!="function")throw new nl("`fn` is not a function");if(typeof t!="number"||t<0||t>4294967295||F0(t)!==t)throw new nl("`length` must be a positive 32-bit integer");var n=arguments.length>2&&!!arguments[2],i=!0,a=!0;if("length"in r&&tl){var o=tl(r,"length");o&&!o.configurable&&(i=!1),o&&!o.writable&&(a=!1)}return(i||a||!n)&&(L0?rl(r,"length",t,!0,!0):rl(r,"length",t)),r}});var fl=y((P1,ol)=>{"use strict";var k0=Pr(),P0=sn(),D0=Wi();ol.exports=function(){return D0(k0,P0,arguments)}});var pt=y((D1,wn)=>{"use strict";var M0=al(),ul=lt(),j0=cn(),ll=fl();wn.exports=function(r){var t=j0(arguments),n=r.length-(arguments.length-1);return M0(t,1+(n>0?n:0),!0)};ul?ul(wn.exports,"apply",{value:ll}):wn.exports.apply=ll});var sa=y((M1,pl)=>{"use strict";var Sn=Hu(),B0=Yu(),sl=pt(),ua=nr(),mn=rr(),En=hn(),q0=ua("Object.prototype.toString"),hl=ut()(),cl=globalThis,fa=B0(),la=ua("String.prototype.slice"),U0=ua("Array.prototype.indexOf",!0)||function(r,t){for(var n=0;n-1?t:t!=="Object"?!1:z0(r)}return mn?C0(r):null}});var yl=y((j1,dl)=>{"use strict";var Z0=sa();dl.exports=function(r){return!!Z0(r)}});var Il=y(k=>{"use strict";var W0=xu(),H0=Bu(),_e=sa(),vl=yl();function Cr(e){return e.call.bind(e)}var _l=typeof BigInt<"u",gl=typeof Symbol<"u",fe=Cr(Object.prototype.toString),G0=Cr(Number.prototype.valueOf),$0=Cr(String.prototype.valueOf),V0=Cr(Boolean.prototype.valueOf);_l&&(bl=Cr(BigInt.prototype.valueOf));var bl;gl&&(wl=Cr(Symbol.prototype.valueOf));var wl;function yt(e,r){if(typeof e!="object")return!1;try{return r(e),!0}catch{return!1}}k.isArgumentsObject=W0;k.isGeneratorFunction=H0;k.isTypedArray=vl;function Y0(e){return typeof Promise<"u"&&e instanceof Promise||e!==null&&typeof e=="object"&&typeof e.then=="function"&&typeof e.catch=="function"}k.isPromise=Y0;function K0(e){return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?ArrayBuffer.isView(e):vl(e)||ml(e)}k.isArrayBufferView=K0;function X0(e){return _e(e)==="Uint8Array"}k.isUint8Array=X0;function J0(e){return _e(e)==="Uint8ClampedArray"}k.isUint8ClampedArray=J0;function Q0(e){return _e(e)==="Uint16Array"}k.isUint16Array=Q0;function ev(e){return _e(e)==="Uint32Array"}k.isUint32Array=ev;function rv(e){return _e(e)==="Int8Array"}k.isInt8Array=rv;function tv(e){return _e(e)==="Int16Array"}k.isInt16Array=tv;function nv(e){return _e(e)==="Int32Array"}k.isInt32Array=nv;function iv(e){return _e(e)==="Float32Array"}k.isFloat32Array=iv;function av(e){return _e(e)==="Float64Array"}k.isFloat64Array=av;function ov(e){return _e(e)==="BigInt64Array"}k.isBigInt64Array=ov;function fv(e){return _e(e)==="BigUint64Array"}k.isBigUint64Array=fv;function An(e){return fe(e)==="[object Map]"}An.working=typeof Map<"u"&&An(new Map);function uv(e){return typeof Map>"u"?!1:An.working?An(e):e instanceof Map}k.isMap=uv;function Rn(e){return fe(e)==="[object Set]"}Rn.working=typeof Set<"u"&&Rn(new Set);function lv(e){return typeof Set>"u"?!1:Rn.working?Rn(e):e instanceof Set}k.isSet=lv;function On(e){return fe(e)==="[object WeakMap]"}On.working=typeof WeakMap<"u"&&On(new WeakMap);function sv(e){return typeof WeakMap>"u"?!1:On.working?On(e):e instanceof WeakMap}k.isWeakMap=sv;function ha(e){return fe(e)==="[object WeakSet]"}ha.working=typeof WeakSet<"u"&&ha(new WeakSet);function cv(e){return ha(e)}k.isWeakSet=cv;function Tn(e){return fe(e)==="[object ArrayBuffer]"}Tn.working=typeof ArrayBuffer<"u"&&Tn(new ArrayBuffer);function El(e){return typeof ArrayBuffer>"u"?!1:Tn.working?Tn(e):e instanceof ArrayBuffer}k.isArrayBuffer=El;function In(e){return fe(e)==="[object DataView]"}In.working=typeof ArrayBuffer<"u"&&typeof DataView<"u"&&In(new DataView(new ArrayBuffer(1),0,1));function ml(e){return typeof DataView>"u"?!1:In.working?In(e):e instanceof DataView}k.isDataView=ml;var ca=typeof SharedArrayBuffer<"u"?SharedArrayBuffer:void 0;function dt(e){return fe(e)==="[object SharedArrayBuffer]"}function Sl(e){return typeof ca>"u"?!1:(typeof dt.working>"u"&&(dt.working=dt(new ca)),dt.working?dt(e):e instanceof ca)}k.isSharedArrayBuffer=Sl;function hv(e){return fe(e)==="[object AsyncFunction]"}k.isAsyncFunction=hv;function pv(e){return fe(e)==="[object Map Iterator]"}k.isMapIterator=pv;function dv(e){return fe(e)==="[object Set Iterator]"}k.isSetIterator=dv;function yv(e){return fe(e)==="[object Generator]"}k.isGeneratorObject=yv;function vv(e){return fe(e)==="[object WebAssembly.Module]"}k.isWebAssemblyCompiledModule=vv;function xl(e){return yt(e,G0)}k.isNumberObject=xl;function Al(e){return yt(e,$0)}k.isStringObject=Al;function Rl(e){return yt(e,V0)}k.isBooleanObject=Rl;function Ol(e){return _l&&yt(e,bl)}k.isBigIntObject=Ol;function Tl(e){return gl&&yt(e,wl)}k.isSymbolObject=Tl;function _v(e){return xl(e)||Al(e)||Rl(e)||Ol(e)||Tl(e)}k.isBoxedPrimitive=_v;function gv(e){return typeof Uint8Array<"u"&&(El(e)||Sl(e))}k.isAnyArrayBuffer=gv;["isProxy","isExternal","isModuleNamespaceObject"].forEach(function(e){Object.defineProperty(k,e,{enumerable:!1,value:function(){return!1}})})});var Ll=y((q1,Nl)=>{Nl.exports=function(r){return r&&typeof r=="object"&&typeof r.copy=="function"&&typeof r.fill=="function"&&typeof r.readUInt8=="function"}});var Be=y((U1,pa)=>{typeof Object.create=="function"?pa.exports=function(r,t){t&&(r.super_=t,r.prototype=Object.create(t.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}))}:pa.exports=function(r,t){if(t){r.super_=t;var n=function(){};n.prototype=t.prototype,r.prototype=new n,r.prototype.constructor=r}}});var Se=y(P=>{var Fl=Object.getOwnPropertyDescriptors||function(r){for(var t=Object.keys(r),n={},i=0;i=i)return f;switch(f){case"%s":return String(n[t++]);case"%d":return Number(n[t++]);case"%j":try{return JSON.stringify(n[t++])}catch{return"[Circular]"}default:return f}}),o=n[t];t"u")return function(){return P.deprecate(e,r).apply(this,arguments)};var t=!1;function n(){if(!t){if(process.throwDeprecation)throw new Error(r);process.traceDeprecation?console.trace(r):console.error(r),t=!0}return e.apply(this,arguments)}return n};var Nn={},kl=/^$/;process.env.NODE_DEBUG&&(Ln=process.env.NODE_DEBUG,Ln=Ln.replace(/[|\\{}()[\]^$+?.]/g,"\\$&").replace(/\*/g,".*").replace(/,/g,"$|^").toUpperCase(),kl=new RegExp("^"+Ln+"$","i"));var Ln;P.debuglog=function(e){if(e=e.toUpperCase(),!Nn[e])if(kl.test(e)){var r=process.pid;Nn[e]=function(){var t=P.format.apply(P,arguments);console.error("%s %d: %s",e,r,t)}}else Nn[e]=function(){};return Nn[e]};function qe(e,r){var t={seen:[],stylize:Ev};return arguments.length>=3&&(t.depth=arguments[2]),arguments.length>=4&&(t.colors=arguments[3]),_a(r)?t.showHidden=r:r&&P._extend(t,r),ar(t.showHidden)&&(t.showHidden=!1),ar(t.depth)&&(t.depth=2),ar(t.colors)&&(t.colors=!1),ar(t.customInspect)&&(t.customInspect=!0),t.colors&&(t.stylize=wv),kn(t,e,t.depth)}P.inspect=qe;qe.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]};qe.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"};function wv(e,r){var t=qe.styles[r];return t?"\x1B["+qe.colors[t][0]+"m"+e+"\x1B["+qe.colors[t][1]+"m":e}function Ev(e,r){return e}function mv(e){var r={};return e.forEach(function(t,n){r[t]=!0}),r}function kn(e,r,t){if(e.customInspect&&r&&Fn(r.inspect)&&r.inspect!==P.inspect&&!(r.constructor&&r.constructor.prototype===r)){var n=r.inspect(t,e);return Mn(n)||(n=kn(e,n,t)),n}var i=Sv(e,r);if(i)return i;var a=Object.keys(r),o=mv(a);if(e.showHidden&&(a=Object.getOwnPropertyNames(r)),_t(r)&&(a.indexOf("message")>=0||a.indexOf("description")>=0))return da(r);if(a.length===0){if(Fn(r)){var f=r.name?": "+r.name:"";return e.stylize("[Function"+f+"]","special")}if(vt(r))return e.stylize(RegExp.prototype.toString.call(r),"regexp");if(Pn(r))return e.stylize(Date.prototype.toString.call(r),"date");if(_t(r))return da(r)}var s="",u=!1,l=["{","}"];if(Pl(r)&&(u=!0,l=["[","]"]),Fn(r)){var c=r.name?": "+r.name:"";s=" [Function"+c+"]"}if(vt(r)&&(s=" "+RegExp.prototype.toString.call(r)),Pn(r)&&(s=" "+Date.prototype.toUTCString.call(r)),_t(r)&&(s=" "+da(r)),a.length===0&&(!u||r.length==0))return l[0]+s+l[1];if(t<0)return vt(r)?e.stylize(RegExp.prototype.toString.call(r),"regexp"):e.stylize("[Object]","special");e.seen.push(r);var p;return u?p=xv(e,r,t,o,a):p=a.map(function(h){return va(e,r,t,o,h,u)}),e.seen.pop(),Av(p,s,l)}function Sv(e,r){if(ar(r))return e.stylize("undefined","undefined");if(Mn(r)){var t="'"+JSON.stringify(r).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(t,"string")}if(Dl(r))return e.stylize(""+r,"number");if(_a(r))return e.stylize(""+r,"boolean");if(Dn(r))return e.stylize("null","null")}function da(e){return"["+Error.prototype.toString.call(e)+"]"}function xv(e,r,t,n,i){for(var a=[],o=0,f=r.length;o-1&&(a?f=f.split(` -`).map(function(u){return" "+u}).join(` -`).slice(2):f=` -`+f.split(` -`).map(function(u){return" "+u}).join(` -`))):f=e.stylize("[Circular]","special")),ar(o)){if(a&&i.match(/^\d+$/))return f;o=JSON.stringify(""+i),o.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(o=o.slice(1,-1),o=e.stylize(o,"name")):(o=o.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),o=e.stylize(o,"string"))}return o+": "+f}function Av(e,r,t){var n=0,i=e.reduce(function(a,o){return n++,o.indexOf(` -`)>=0&&n++,a+o.replace(/\u001b\[\d\d?m/g,"").length+1},0);return i>60?t[0]+(r===""?"":r+` - `)+" "+e.join(`, - `)+" "+t[1]:t[0]+r+" "+e.join(", ")+" "+t[1]}P.types=Il();function Pl(e){return Array.isArray(e)}P.isArray=Pl;function _a(e){return typeof e=="boolean"}P.isBoolean=_a;function Dn(e){return e===null}P.isNull=Dn;function Rv(e){return e==null}P.isNullOrUndefined=Rv;function Dl(e){return typeof e=="number"}P.isNumber=Dl;function Mn(e){return typeof e=="string"}P.isString=Mn;function Ov(e){return typeof e=="symbol"}P.isSymbol=Ov;function ar(e){return e===void 0}P.isUndefined=ar;function vt(e){return zr(e)&&ga(e)==="[object RegExp]"}P.isRegExp=vt;P.types.isRegExp=vt;function zr(e){return typeof e=="object"&&e!==null}P.isObject=zr;function Pn(e){return zr(e)&&ga(e)==="[object Date]"}P.isDate=Pn;P.types.isDate=Pn;function _t(e){return zr(e)&&(ga(e)==="[object Error]"||e instanceof Error)}P.isError=_t;P.types.isNativeError=_t;function Fn(e){return typeof e=="function"}P.isFunction=Fn;function Tv(e){return e===null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"||typeof e=="symbol"||typeof e>"u"}P.isPrimitive=Tv;P.isBuffer=Ll();function ga(e){return Object.prototype.toString.call(e)}function ya(e){return e<10?"0"+e.toString(10):e.toString(10)}var Iv=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function Nv(){var e=new Date,r=[ya(e.getHours()),ya(e.getMinutes()),ya(e.getSeconds())].join(":");return[e.getDate(),Iv[e.getMonth()],r].join(" ")}P.log=function(){console.log("%s - %s",Nv(),P.format.apply(P,arguments))};P.inherits=Be();P._extend=function(e,r){if(!r||!zr(r))return e;for(var t=Object.keys(r),n=t.length;n--;)e[t[n]]=r[t[n]];return e};function Ml(e,r){return Object.prototype.hasOwnProperty.call(e,r)}var ir=typeof Symbol<"u"?Symbol("util.promisify.custom"):void 0;P.promisify=function(r){if(typeof r!="function")throw new TypeError('The "original" argument must be of type Function');if(ir&&r[ir]){var t=r[ir];if(typeof t!="function")throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(t,ir,{value:t,enumerable:!1,writable:!1,configurable:!0}),t}function t(){for(var n,i,a=new Promise(function(s,u){n=s,i=u}),o=[],f=0;f{"use strict";function Ue(e){"@babel/helpers - typeof";return Ue=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(r){return typeof r}:function(r){return r&&typeof Symbol=="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},Ue(e)}function jl(e,r){for(var t=0;t"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function jn(e){return jn=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},jn(e)}var ql={},Zr,ba;function gt(e,r,t){t||(t=Error);function n(a,o,f){return typeof r=="string"?r:r(a,o,f)}var i=(function(a){jv(f,a);var o=Bv(f);function f(s,u,l){var c;return Mv(this,f),c=o.call(this,n(s,u,l)),c.code=e,c}return kv(f)})(t);ql[e]=i}function Bl(e,r){if(Array.isArray(e)){var t=e.length;return e=e.map(function(n){return String(n)}),t>2?"one of ".concat(r," ").concat(e.slice(0,t-1).join(", "),", or ")+e[t-1]:t===2?"one of ".concat(r," ").concat(e[0]," or ").concat(e[1]):"of ".concat(r," ").concat(e[0])}else return"of ".concat(r," ").concat(String(e))}function zv(e,r,t){return e.substr(!t||t<0?0:+t,r.length)===r}function Zv(e,r,t){return(t===void 0||t>e.length)&&(t=e.length),e.substring(t-r.length,t)===r}function Wv(e,r,t){return typeof t!="number"&&(t=0),t+r.length>e.length?!1:e.indexOf(r,t)!==-1}gt("ERR_AMBIGUOUS_ARGUMENT",'The "%s" argument is ambiguous. %s',TypeError);gt("ERR_INVALID_ARG_TYPE",function(e,r,t){Zr===void 0&&(Zr=Wr()),Zr(typeof e=="string","'name' must be a string");var n;typeof r=="string"&&zv(r,"not ")?(n="must not be",r=r.replace(/^not /,"")):n="must be";var i;if(Zv(e," argument"))i="The ".concat(e," ").concat(n," ").concat(Bl(r,"type"));else{var a=Wv(e,".")?"property":"argument";i='The "'.concat(e,'" ').concat(a," ").concat(n," ").concat(Bl(r,"type"))}return i+=". Received type ".concat(Ue(t)),i},TypeError);gt("ERR_INVALID_ARG_VALUE",function(e,r){var t=arguments.length>2&&arguments[2]!==void 0?arguments[2]:"is invalid";ba===void 0&&(ba=Se());var n=ba.inspect(r);return n.length>128&&(n="".concat(n.slice(0,128),"...")),"The argument '".concat(e,"' ").concat(t,". Received ").concat(n)},TypeError,RangeError);gt("ERR_INVALID_RETURN_VALUE",function(e,r,t){var n;return t&&t.constructor&&t.constructor.name?n="instance of ".concat(t.constructor.name):n="type ".concat(Ue(t)),"Expected ".concat(e,' to be returned from the "').concat(r,'"')+" function but got ".concat(n,".")},TypeError);gt("ERR_MISSING_ARGS",function(){for(var e=arguments.length,r=new Array(e),t=0;t0,"At least one arg needs to be specified");var n="The ",i=r.length;switch(r=r.map(function(a){return'"'.concat(a,'"')}),i){case 1:n+="".concat(r[0]," argument");break;case 2:n+="".concat(r[0]," and ").concat(r[1]," arguments");break;default:n+=r.slice(0,i-1).join(", "),n+=", and ".concat(r[i-1]," arguments");break}return"".concat(n," must be specified")},TypeError);Ul.exports.codes=ql});var Kl=y((Z1,Yl)=>{"use strict";function Cl(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),t.push.apply(t,n)}return t}function zl(e){for(var r=1;r"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function Xv(e){return Function.toString.call(e).indexOf("[native code]")!==-1}function mt(e,r){return mt=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(n,i){return n.__proto__=i,n},mt(e,r)}function St(e){return St=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},St(e)}function te(e){"@babel/helpers - typeof";return te=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(r){return typeof r}:function(r){return r&&typeof Symbol=="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},te(e)}var Jv=Se(),xa=Jv.inspect,Qv=Ea(),e_=Qv.codes.ERR_INVALID_ARG_TYPE;function Wl(e,r,t){return(t===void 0||t>e.length)&&(t=e.length),e.substring(t-r.length,t)===r}function r_(e,r){if(r=Math.floor(r),e.length==0||r==0)return"";var t=e.length*r;for(r=Math.floor(Math.log(r)/Math.log(2));r;)e+=e,r--;return e+=e.substring(0,t-e.length),e}var ge="",bt="",wt="",V="",or={deepStrictEqual:"Expected values to be strictly deep-equal:",strictEqual:"Expected values to be strictly equal:",strictEqualObject:'Expected "actual" to be reference-equal to "expected":',deepEqual:"Expected values to be loosely deep-equal:",equal:"Expected values to be loosely equal:",notDeepStrictEqual:'Expected "actual" not to be strictly deep-equal to:',notStrictEqual:'Expected "actual" to be strictly unequal to:',notStrictEqualObject:'Expected "actual" not to be reference-equal to "expected":',notDeepEqual:'Expected "actual" not to be loosely deep-equal to:',notEqual:'Expected "actual" to be loosely unequal to:',notIdentical:"Values identical but not reference-equal:"},t_=10;function Hl(e){var r=Object.keys(e),t=Object.create(Object.getPrototypeOf(e));return r.forEach(function(n){t[n]=e[n]}),Object.defineProperty(t,"message",{value:e.message}),t}function Et(e){return xa(e,{compact:!1,customInspect:!1,depth:1e3,maxArrayLength:1/0,showHidden:!1,breakLength:1/0,showProxy:!1,sorted:!0,getters:!0})}function n_(e,r,t){var n="",i="",a=0,o="",f=!1,s=Et(e),u=s.split(` -`),l=Et(r).split(` -`),c=0,p="";if(t==="strictEqual"&&te(e)==="object"&&te(r)==="object"&&e!==null&&r!==null&&(t="strictEqualObject"),u.length===1&&l.length===1&&u[0]!==l[0]){var h=u[0].length+l[0].length;if(h<=t_){if((te(e)!=="object"||e===null)&&(te(r)!=="object"||r===null)&&(e!==0||r!==0))return"".concat(or[t],` - -`)+"".concat(u[0]," !== ").concat(l[0],` -`)}else if(t!=="strictEqualObject"){var v=process.stderr&&process.stderr.isTTY?process.stderr.columns:80;if(h2&&(p=` - `.concat(r_(" ",c),"^"),c=0)}}}for(var _=u[u.length-1],m=l[l.length-1];_===m&&(c++<2?o=` - `.concat(_).concat(o):n=_,u.pop(),l.pop(),!(u.length===0||l.length===0));)_=u[u.length-1],m=l[l.length-1];var w=Math.max(u.length,l.length);if(w===0){var L=s.split(` -`);if(L.length>30)for(L[26]="".concat(ge,"...").concat(V);L.length>27;)L.pop();return"".concat(or.notIdentical,` - -`).concat(L.join(` -`),` -`)}c>3&&(o=` -`.concat(ge,"...").concat(V).concat(o),f=!0),n!==""&&(o=` - `.concat(n).concat(o),n="");var A=0,T=or[t]+` -`.concat(bt,"+ actual").concat(V," ").concat(wt,"- expected").concat(V),b=" ".concat(ge,"...").concat(V," Lines skipped");for(c=0;c1&&c>2&&(R>4?(i+=` -`.concat(ge,"...").concat(V),f=!0):R>3&&(i+=` - `.concat(l[c-2]),A++),i+=` - `.concat(l[c-1]),A++),a=c,n+=` -`.concat(wt,"-").concat(V," ").concat(l[c]),A++;else if(l.length1&&c>2&&(R>4?(i+=` -`.concat(ge,"...").concat(V),f=!0):R>3&&(i+=` - `.concat(u[c-2]),A++),i+=` - `.concat(u[c-1]),A++),a=c,i+=` -`.concat(bt,"+").concat(V," ").concat(u[c]),A++;else{var I=l[c],S=u[c],D=S!==I&&(!Wl(S,",")||S.slice(0,-1)!==I);D&&Wl(I,",")&&I.slice(0,-1)===S&&(D=!1,S+=","),D?(R>1&&c>2&&(R>4?(i+=` -`.concat(ge,"...").concat(V),f=!0):R>3&&(i+=` - `.concat(u[c-2]),A++),i+=` - `.concat(u[c-1]),A++),a=c,i+=` -`.concat(bt,"+").concat(V," ").concat(S),n+=` -`.concat(wt,"-").concat(V," ").concat(I),A+=2):(i+=n,n="",(R===1||c===0)&&(i+=` - `.concat(S),A++))}if(A>20&&c30)for(h[26]="".concat(ge,"...").concat(V);h.length>27;)h.pop();h.length===1?a=t.call(this,"".concat(p," ").concat(h[0])):a=t.call(this,"".concat(p,` - -`).concat(h.join(` -`),` -`))}else{var v=Et(u),_="",m=or[f];f==="notDeepEqual"||f==="notEqual"?(v="".concat(or[f],` - -`).concat(v),v.length>1024&&(v="".concat(v.slice(0,1021),"..."))):(_="".concat(Et(l)),v.length>512&&(v="".concat(v.slice(0,509),"...")),_.length>512&&(_="".concat(_.slice(0,509),"...")),f==="deepEqual"||f==="equal"?v="".concat(m,` - -`).concat(v,` - -should equal - -`):_=" ".concat(f," ").concat(_)),a=t.call(this,"".concat(v).concat(_))}return Error.stackTraceLimit=c,a.generatedMessage=!o,Object.defineProperty(ma(a),"name",{value:"AssertionError [ERR_ASSERTION]",enumerable:!1,writable:!0,configurable:!0}),a.code="ERR_ASSERTION",a.actual=u,a.expected=l,a.operator=f,Error.captureStackTrace&&Error.captureStackTrace(ma(a),s),a.stack,a.name="AssertionError",$l(a)}return $v(n,[{key:"toString",value:function(){return"".concat(this.name," [").concat(this.code,"]: ").concat(this.message)}},{key:r,value:function(a,o){return xa(this,zl(zl({},o),{},{customInspect:!1,depth:0}))}}]),n})(Sa(Error),xa.custom);Yl.exports=i_});var Aa=y((W1,Jl)=>{"use strict";var Xl=Object.prototype.toString;Jl.exports=function(r){var t=Xl.call(r),n=t==="[object Arguments]";return n||(n=t!=="[object Array]"&&r!==null&&typeof r=="object"&&typeof r.length=="number"&&r.length>=0&&Xl.call(r.callee)==="[object Function]"),n}});var fs=y((H1,os)=>{"use strict";var as;Object.keys||(xt=Object.prototype.hasOwnProperty,Ra=Object.prototype.toString,Ql=Aa(),Oa=Object.prototype.propertyIsEnumerable,es=!Oa.call({toString:null},"toString"),rs=Oa.call(function(){},"prototype"),At=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],qn=function(e){var r=e.constructor;return r&&r.prototype===e},ts={$applicationCache:!0,$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$onmozfullscreenchange:!0,$onmozfullscreenerror:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},ns=(function(){if(typeof window>"u")return!1;for(var e in window)try{if(!ts["$"+e]&&xt.call(window,e)&&window[e]!==null&&typeof window[e]=="object")try{qn(window[e])}catch{return!0}}catch{return!0}return!1})(),is=function(e){if(typeof window>"u"||!ns)return qn(e);try{return qn(e)}catch{return!1}},as=function(r){var t=r!==null&&typeof r=="object",n=Ra.call(r)==="[object Function]",i=Ql(r),a=t&&Ra.call(r)==="[object String]",o=[];if(!t&&!n&&!i)throw new TypeError("Object.keys called on a non-object");var f=rs&&n;if(a&&r.length>0&&!xt.call(r,0))for(var s=0;s0)for(var u=0;u{"use strict";var a_=Array.prototype.slice,o_=Aa(),us=Object.keys,Un=us?function(r){return us(r)}:fs(),ls=Object.keys;Un.shim=function(){if(Object.keys){var r=(function(){var t=Object.keys(arguments);return t&&t.length===arguments.length})(1,2);r||(Object.keys=function(n){return o_(n)?ls(a_.call(n)):ls(n)})}else Object.keys=Un;return Object.keys||Un};ss.exports=Un});var ys=y(($1,ds)=>{"use strict";var f_=Ta(),hs=an()(),ps=nr(),Cn=on(),u_=ps("Array.prototype.push"),cs=ps("Object.prototype.propertyIsEnumerable"),l_=hs?Cn.getOwnPropertySymbols:null;ds.exports=function(r,t){if(r==null)throw new TypeError("target must be an object");var n=Cn(r);if(arguments.length===1)return n;for(var i=1;i{"use strict";var Ia=ys(),s_=function(){if(!Object.assign)return!1;for(var e="abcdefghijklmnopqrst",r=e.split(""),t={},n=0;n{"use strict";var gs=function(e){return e!==e};bs.exports=function(r,t){return r===0&&t===0?1/r===1/t:!!(r===t||gs(r)&&gs(t))}});var zn=y((K1,ws)=>{"use strict";var h_=Na();ws.exports=function(){return typeof Object.is=="function"?Object.is:h_}});var xs=y((X1,Ss)=>{"use strict";var Es=yn(),ms=pt(),p_=ms(Es("String.prototype.indexOf"));Ss.exports=function(r,t){var n=Es(r,!!t);return typeof n=="function"&&p_(r,".prototype.")>-1?ms(n):n}});var Rt=y((J1,Ts)=>{"use strict";var d_=Ta(),y_=typeof Symbol=="function"&&typeof Symbol("foo")=="symbol",v_=Object.prototype.toString,__=Array.prototype.concat,As=ia(),g_=function(e){return typeof e=="function"&&v_.call(e)==="[object Function]"},Rs=oa()(),b_=function(e,r,t,n){if(r in e){if(n===!0){if(e[r]===t)return}else if(!g_(n)||!n())return}Rs?As(e,r,t,!0):As(e,r,t)},Os=function(e,r){var t=arguments.length>2?arguments[2]:{},n=d_(r);y_&&(n=__.call(n,Object.getOwnPropertySymbols(r)));for(var i=0;i{"use strict";var w_=zn(),E_=Rt();Is.exports=function(){var r=w_();return E_(Object,{is:r},{is:function(){return Object.is!==r}}),r}});var Ps=y((eS,ks)=>{"use strict";var m_=Rt(),S_=pt(),x_=Na(),Ls=zn(),A_=Ns(),Fs=S_(Ls(),Object);m_(Fs,{getPolyfill:Ls,implementation:x_,shim:A_});ks.exports=Fs});var La=y((rS,Ds)=>{"use strict";Ds.exports=function(r){return r!==r}});var Fa=y((tS,Ms)=>{"use strict";var R_=La();Ms.exports=function(){return Number.isNaN&&Number.isNaN(NaN)&&!Number.isNaN("a")?Number.isNaN:R_}});var Bs=y((nS,js)=>{"use strict";var O_=Rt(),T_=Fa();js.exports=function(){var r=T_();return O_(Number,{isNaN:r},{isNaN:function(){return Number.isNaN!==r}}),r}});var zs=y((iS,Cs)=>{"use strict";var I_=pt(),N_=Rt(),L_=La(),qs=Fa(),F_=Bs(),Us=I_(qs(),Number);N_(Us,{getPolyfill:qs,implementation:L_,shim:F_});Cs.exports=Us});var uc=y((aS,fc)=>{"use strict";function Zs(e,r){return M_(e)||D_(e,r)||P_(e,r)||k_()}function k_(){throw new TypeError(`Invalid attempt to destructure non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function P_(e,r){if(e){if(typeof e=="string")return Ws(e,r);var t=Object.prototype.toString.call(e).slice(8,-1);if(t==="Object"&&e.constructor&&(t=e.constructor.name),t==="Map"||t==="Set")return Array.from(e);if(t==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t))return Ws(e,r)}}function Ws(e,r){(r==null||r>e.length)&&(r=e.length);for(var t=0,n=new Array(r);t10)return!0;for(var r=0;r57)return!0}return e.length===10&&e>=Math.pow(2,32)}function Hn(e){return Object.keys(e).filter(H_).concat($n(e).filter(Object.prototype.propertyIsEnumerable.bind(e)))}function nc(e,r){if(e===r)return 0;for(var t=e.length,n=r.length,i=0,a=Math.min(t,n);i{"use strict";function be(e){"@babel/helpers - typeof";return be=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(r){return typeof r}:function(r){return r&&typeof Symbol=="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},be(e)}function lc(e,r){for(var t=0;t1?t-1:0),i=1;i1?t-1:0),i=1;i1?t-1:0),i=1;i1?t-1:0),i=1;i{"use strict";ri.byteLength=gg;ri.toByteArray=wg;ri.fromByteArray=Sg;var xe=[],se=[],_g=typeof Uint8Array<"u"?Uint8Array:Array,Ba="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(fr=0,Oc=Ba.length;fr0)throw new Error("Invalid string. Length must be a multiple of 4");var t=e.indexOf("=");t===-1&&(t=r);var n=t===r?0:4-t%4;return[t,n]}function gg(e){var r=Tc(e),t=r[0],n=r[1];return(t+n)*3/4-n}function bg(e,r,t){return(r+t)*3/4-t}function wg(e){var r,t=Tc(e),n=t[0],i=t[1],a=new _g(bg(e,n,i)),o=0,f=i>0?n-4:n,s;for(s=0;s>16&255,a[o++]=r>>8&255,a[o++]=r&255;return i===2&&(r=se[e.charCodeAt(s)]<<2|se[e.charCodeAt(s+1)]>>4,a[o++]=r&255),i===1&&(r=se[e.charCodeAt(s)]<<10|se[e.charCodeAt(s+1)]<<4|se[e.charCodeAt(s+2)]>>2,a[o++]=r>>8&255,a[o++]=r&255),a}function Eg(e){return xe[e>>18&63]+xe[e>>12&63]+xe[e>>6&63]+xe[e&63]}function mg(e,r,t){for(var n,i=[],a=r;af?f:o+a));return n===1?(r=e[t-1],i.push(xe[r>>2]+xe[r<<4&63]+"==")):n===2&&(r=(e[t-2]<<8)+e[t-1],i.push(xe[r>>10]+xe[r>>4&63]+xe[r<<2&63]+"=")),i.join("")}});var Nc=y(qa=>{qa.read=function(e,r,t,n,i){var a,o,f=i*8-n-1,s=(1<>1,l=-7,c=t?i-1:0,p=t?-1:1,h=e[r+c];for(c+=p,a=h&(1<<-l)-1,h>>=-l,l+=f;l>0;a=a*256+e[r+c],c+=p,l-=8);for(o=a&(1<<-l)-1,a>>=-l,l+=n;l>0;o=o*256+e[r+c],c+=p,l-=8);if(a===0)a=1-u;else{if(a===s)return o?NaN:(h?-1:1)*(1/0);o=o+Math.pow(2,n),a=a-u}return(h?-1:1)*o*Math.pow(2,a-n)};qa.write=function(e,r,t,n,i,a){var o,f,s,u=a*8-i-1,l=(1<>1,p=i===23?Math.pow(2,-24)-Math.pow(2,-77):0,h=n?0:a-1,v=n?1:-1,_=r<0||r===0&&1/r<0?1:0;for(r=Math.abs(r),isNaN(r)||r===1/0?(f=isNaN(r)?1:0,o=l):(o=Math.floor(Math.log(r)/Math.LN2),r*(s=Math.pow(2,-o))<1&&(o--,s*=2),o+c>=1?r+=p/s:r+=p*Math.pow(2,1-c),r*s>=2&&(o++,s/=2),o+c>=l?(f=0,o=l):o+c>=1?(f=(r*s-1)*Math.pow(2,i),o=o+c):(f=r*Math.pow(2,c-1)*Math.pow(2,i),o=0));i>=8;e[t+h]=f&255,h+=v,f/=256,i-=8);for(o=o<0;e[t+h]=o&255,h+=v,o/=256,u-=8);e[t+h-v]|=_*128}});var lr=y($r=>{"use strict";var Ua=Ic(),Gr=Nc(),Lc=typeof Symbol=="function"&&typeof Symbol.for=="function"?Symbol.for("nodejs.util.inspect.custom"):null;$r.Buffer=d;$r.SlowBuffer=Ig;$r.INSPECT_MAX_BYTES=50;var ti=2147483647;$r.kMaxLength=ti;d.TYPED_ARRAY_SUPPORT=xg();!d.TYPED_ARRAY_SUPPORT&&typeof console<"u"&&typeof console.error=="function"&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function xg(){try{var e=new Uint8Array(1),r={foo:function(){return 42}};return Object.setPrototypeOf(r,Uint8Array.prototype),Object.setPrototypeOf(e,r),e.foo()===42}catch{return!1}}Object.defineProperty(d.prototype,"parent",{enumerable:!0,get:function(){if(d.isBuffer(this))return this.buffer}});Object.defineProperty(d.prototype,"offset",{enumerable:!0,get:function(){if(d.isBuffer(this))return this.byteOffset}});function Pe(e){if(e>ti)throw new RangeError('The value "'+e+'" is invalid for option "size"');var r=new Uint8Array(e);return Object.setPrototypeOf(r,d.prototype),r}function d(e,r,t){if(typeof e=="number"){if(typeof r=="string")throw new TypeError('The "string" argument must be of type string. Received type number');return Wa(e)}return Pc(e,r,t)}d.poolSize=8192;function Pc(e,r,t){if(typeof e=="string")return Rg(e,r);if(ArrayBuffer.isView(e))return Og(e);if(e==null)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(Ae(e,ArrayBuffer)||e&&Ae(e.buffer,ArrayBuffer)||typeof SharedArrayBuffer<"u"&&(Ae(e,SharedArrayBuffer)||e&&Ae(e.buffer,SharedArrayBuffer)))return za(e,r,t);if(typeof e=="number")throw new TypeError('The "value" argument must not be of type number. Received type number');var n=e.valueOf&&e.valueOf();if(n!=null&&n!==e)return d.from(n,r,t);var i=Tg(e);if(i)return i;if(typeof Symbol<"u"&&Symbol.toPrimitive!=null&&typeof e[Symbol.toPrimitive]=="function")return d.from(e[Symbol.toPrimitive]("string"),r,t);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}d.from=function(e,r,t){return Pc(e,r,t)};Object.setPrototypeOf(d.prototype,Uint8Array.prototype);Object.setPrototypeOf(d,Uint8Array);function Dc(e){if(typeof e!="number")throw new TypeError('"size" argument must be of type number');if(e<0)throw new RangeError('The value "'+e+'" is invalid for option "size"')}function Ag(e,r,t){return Dc(e),e<=0?Pe(e):r!==void 0?typeof t=="string"?Pe(e).fill(r,t):Pe(e).fill(r):Pe(e)}d.alloc=function(e,r,t){return Ag(e,r,t)};function Wa(e){return Dc(e),Pe(e<0?0:Ha(e)|0)}d.allocUnsafe=function(e){return Wa(e)};d.allocUnsafeSlow=function(e){return Wa(e)};function Rg(e,r){if((typeof r!="string"||r==="")&&(r="utf8"),!d.isEncoding(r))throw new TypeError("Unknown encoding: "+r);var t=Mc(e,r)|0,n=Pe(t),i=n.write(e,r);return i!==t&&(n=n.slice(0,i)),n}function Ca(e){for(var r=e.length<0?0:Ha(e.length)|0,t=Pe(r),n=0;n=ti)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+ti.toString(16)+" bytes");return e|0}function Ig(e){return+e!=e&&(e=0),d.alloc(+e)}d.isBuffer=function(r){return r!=null&&r._isBuffer===!0&&r!==d.prototype};d.compare=function(r,t){if(Ae(r,Uint8Array)&&(r=d.from(r,r.offset,r.byteLength)),Ae(t,Uint8Array)&&(t=d.from(t,t.offset,t.byteLength)),!d.isBuffer(r)||!d.isBuffer(t))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(r===t)return 0;for(var n=r.length,i=t.length,a=0,o=Math.min(n,i);ai.length?d.from(o).copy(i,a):Uint8Array.prototype.set.call(i,o,a);else if(d.isBuffer(o))o.copy(i,a);else throw new TypeError('"list" argument must be an Array of Buffers');a+=o.length}return i};function Mc(e,r){if(d.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||Ae(e,ArrayBuffer))return e.byteLength;if(typeof e!="string")throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof e);var t=e.length,n=arguments.length>2&&arguments[2]===!0;if(!n&&t===0)return 0;for(var i=!1;;)switch(r){case"ascii":case"latin1":case"binary":return t;case"utf8":case"utf-8":return Za(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return t*2;case"hex":return t>>>1;case"base64":return zc(e).length;default:if(i)return n?-1:Za(e).length;r=(""+r).toLowerCase(),i=!0}}d.byteLength=Mc;function Ng(e,r,t){var n=!1;if((r===void 0||r<0)&&(r=0),r>this.length||((t===void 0||t>this.length)&&(t=this.length),t<=0)||(t>>>=0,r>>>=0,t<=r))return"";for(e||(e="utf8");;)switch(e){case"hex":return Ug(this,r,t);case"utf8":case"utf-8":return Bc(this,r,t);case"ascii":return Bg(this,r,t);case"latin1":case"binary":return qg(this,r,t);case"base64":return Mg(this,r,t);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Cg(this,r,t);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}d.prototype._isBuffer=!0;function ur(e,r,t){var n=e[r];e[r]=e[t],e[t]=n}d.prototype.swap16=function(){var r=this.length;if(r%2!==0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(var t=0;tt&&(r+=" ... "),""};Lc&&(d.prototype[Lc]=d.prototype.inspect);d.prototype.compare=function(r,t,n,i,a){if(Ae(r,Uint8Array)&&(r=d.from(r,r.offset,r.byteLength)),!d.isBuffer(r))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof r);if(t===void 0&&(t=0),n===void 0&&(n=r?r.length:0),i===void 0&&(i=0),a===void 0&&(a=this.length),t<0||n>r.length||i<0||a>this.length)throw new RangeError("out of range index");if(i>=a&&t>=n)return 0;if(i>=a)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,i>>>=0,a>>>=0,this===r)return 0;for(var o=a-i,f=n-t,s=Math.min(o,f),u=this.slice(i,a),l=r.slice(t,n),c=0;c2147483647?t=2147483647:t<-2147483648&&(t=-2147483648),t=+t,Ga(t)&&(t=i?0:e.length-1),t<0&&(t=e.length+t),t>=e.length){if(i)return-1;t=e.length-1}else if(t<0)if(i)t=0;else return-1;if(typeof r=="string"&&(r=d.from(r,n)),d.isBuffer(r))return r.length===0?-1:Fc(e,r,t,n,i);if(typeof r=="number")return r=r&255,typeof Uint8Array.prototype.indexOf=="function"?i?Uint8Array.prototype.indexOf.call(e,r,t):Uint8Array.prototype.lastIndexOf.call(e,r,t):Fc(e,[r],t,n,i);throw new TypeError("val must be string, number or Buffer")}function Fc(e,r,t,n,i){var a=1,o=e.length,f=r.length;if(n!==void 0&&(n=String(n).toLowerCase(),n==="ucs2"||n==="ucs-2"||n==="utf16le"||n==="utf-16le")){if(e.length<2||r.length<2)return-1;a=2,o/=2,f/=2,t/=2}function s(h,v){return a===1?h[v]:h.readUInt16BE(v*a)}var u;if(i){var l=-1;for(u=t;uo&&(t=o-f),u=t;u>=0;u--){for(var c=!0,p=0;pi&&(n=i)):n=i;var a=r.length;n>a/2&&(n=a/2);for(var o=0;o>>0,isFinite(n)?(n=n>>>0,i===void 0&&(i="utf8")):(i=n,n=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");var a=this.length-t;if((n===void 0||n>a)&&(n=a),r.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");i||(i="utf8");for(var o=!1;;)switch(i){case"hex":return Lg(this,r,t,n);case"utf8":case"utf-8":return Fg(this,r,t,n);case"ascii":case"latin1":case"binary":return kg(this,r,t,n);case"base64":return Pg(this,r,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Dg(this,r,t,n);default:if(o)throw new TypeError("Unknown encoding: "+i);i=(""+i).toLowerCase(),o=!0}};d.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function Mg(e,r,t){return r===0&&t===e.length?Ua.fromByteArray(e):Ua.fromByteArray(e.slice(r,t))}function Bc(e,r,t){t=Math.min(e.length,t);for(var n=[],i=r;i239?4:a>223?3:a>191?2:1;if(i+f<=t){var s,u,l,c;switch(f){case 1:a<128&&(o=a);break;case 2:s=e[i+1],(s&192)===128&&(c=(a&31)<<6|s&63,c>127&&(o=c));break;case 3:s=e[i+1],u=e[i+2],(s&192)===128&&(u&192)===128&&(c=(a&15)<<12|(s&63)<<6|u&63,c>2047&&(c<55296||c>57343)&&(o=c));break;case 4:s=e[i+1],u=e[i+2],l=e[i+3],(s&192)===128&&(u&192)===128&&(l&192)===128&&(c=(a&15)<<18|(s&63)<<12|(u&63)<<6|l&63,c>65535&&c<1114112&&(o=c))}}o===null?(o=65533,f=1):o>65535&&(o-=65536,n.push(o>>>10&1023|55296),o=56320|o&1023),n.push(o),i+=f}return jg(n)}var kc=4096;function jg(e){var r=e.length;if(r<=kc)return String.fromCharCode.apply(String,e);for(var t="",n=0;nn)&&(t=n);for(var i="",a=r;an&&(r=n),t<0?(t+=n,t<0&&(t=0)):t>n&&(t=n),tt)throw new RangeError("Trying to access beyond buffer length")}d.prototype.readUintLE=d.prototype.readUIntLE=function(r,t,n){r=r>>>0,t=t>>>0,n||$(r,t,this.length);for(var i=this[r],a=1,o=0;++o>>0,t=t>>>0,n||$(r,t,this.length);for(var i=this[r+--t],a=1;t>0&&(a*=256);)i+=this[r+--t]*a;return i};d.prototype.readUint8=d.prototype.readUInt8=function(r,t){return r=r>>>0,t||$(r,1,this.length),this[r]};d.prototype.readUint16LE=d.prototype.readUInt16LE=function(r,t){return r=r>>>0,t||$(r,2,this.length),this[r]|this[r+1]<<8};d.prototype.readUint16BE=d.prototype.readUInt16BE=function(r,t){return r=r>>>0,t||$(r,2,this.length),this[r]<<8|this[r+1]};d.prototype.readUint32LE=d.prototype.readUInt32LE=function(r,t){return r=r>>>0,t||$(r,4,this.length),(this[r]|this[r+1]<<8|this[r+2]<<16)+this[r+3]*16777216};d.prototype.readUint32BE=d.prototype.readUInt32BE=function(r,t){return r=r>>>0,t||$(r,4,this.length),this[r]*16777216+(this[r+1]<<16|this[r+2]<<8|this[r+3])};d.prototype.readIntLE=function(r,t,n){r=r>>>0,t=t>>>0,n||$(r,t,this.length);for(var i=this[r],a=1,o=0;++o=a&&(i-=Math.pow(2,8*t)),i};d.prototype.readIntBE=function(r,t,n){r=r>>>0,t=t>>>0,n||$(r,t,this.length);for(var i=t,a=1,o=this[r+--i];i>0&&(a*=256);)o+=this[r+--i]*a;return a*=128,o>=a&&(o-=Math.pow(2,8*t)),o};d.prototype.readInt8=function(r,t){return r=r>>>0,t||$(r,1,this.length),this[r]&128?(255-this[r]+1)*-1:this[r]};d.prototype.readInt16LE=function(r,t){r=r>>>0,t||$(r,2,this.length);var n=this[r]|this[r+1]<<8;return n&32768?n|4294901760:n};d.prototype.readInt16BE=function(r,t){r=r>>>0,t||$(r,2,this.length);var n=this[r+1]|this[r]<<8;return n&32768?n|4294901760:n};d.prototype.readInt32LE=function(r,t){return r=r>>>0,t||$(r,4,this.length),this[r]|this[r+1]<<8|this[r+2]<<16|this[r+3]<<24};d.prototype.readInt32BE=function(r,t){return r=r>>>0,t||$(r,4,this.length),this[r]<<24|this[r+1]<<16|this[r+2]<<8|this[r+3]};d.prototype.readFloatLE=function(r,t){return r=r>>>0,t||$(r,4,this.length),Gr.read(this,r,!0,23,4)};d.prototype.readFloatBE=function(r,t){return r=r>>>0,t||$(r,4,this.length),Gr.read(this,r,!1,23,4)};d.prototype.readDoubleLE=function(r,t){return r=r>>>0,t||$(r,8,this.length),Gr.read(this,r,!0,52,8)};d.prototype.readDoubleBE=function(r,t){return r=r>>>0,t||$(r,8,this.length),Gr.read(this,r,!1,52,8)};function ne(e,r,t,n,i,a){if(!d.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(r>i||re.length)throw new RangeError("Index out of range")}d.prototype.writeUintLE=d.prototype.writeUIntLE=function(r,t,n,i){if(r=+r,t=t>>>0,n=n>>>0,!i){var a=Math.pow(2,8*n)-1;ne(this,r,t,n,a,0)}var o=1,f=0;for(this[t]=r&255;++f>>0,n=n>>>0,!i){var a=Math.pow(2,8*n)-1;ne(this,r,t,n,a,0)}var o=n-1,f=1;for(this[t+o]=r&255;--o>=0&&(f*=256);)this[t+o]=r/f&255;return t+n};d.prototype.writeUint8=d.prototype.writeUInt8=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,1,255,0),this[t]=r&255,t+1};d.prototype.writeUint16LE=d.prototype.writeUInt16LE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,2,65535,0),this[t]=r&255,this[t+1]=r>>>8,t+2};d.prototype.writeUint16BE=d.prototype.writeUInt16BE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,2,65535,0),this[t]=r>>>8,this[t+1]=r&255,t+2};d.prototype.writeUint32LE=d.prototype.writeUInt32LE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,4,4294967295,0),this[t+3]=r>>>24,this[t+2]=r>>>16,this[t+1]=r>>>8,this[t]=r&255,t+4};d.prototype.writeUint32BE=d.prototype.writeUInt32BE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,4,4294967295,0),this[t]=r>>>24,this[t+1]=r>>>16,this[t+2]=r>>>8,this[t+3]=r&255,t+4};d.prototype.writeIntLE=function(r,t,n,i){if(r=+r,t=t>>>0,!i){var a=Math.pow(2,8*n-1);ne(this,r,t,n,a-1,-a)}var o=0,f=1,s=0;for(this[t]=r&255;++o>0)-s&255;return t+n};d.prototype.writeIntBE=function(r,t,n,i){if(r=+r,t=t>>>0,!i){var a=Math.pow(2,8*n-1);ne(this,r,t,n,a-1,-a)}var o=n-1,f=1,s=0;for(this[t+o]=r&255;--o>=0&&(f*=256);)r<0&&s===0&&this[t+o+1]!==0&&(s=1),this[t+o]=(r/f>>0)-s&255;return t+n};d.prototype.writeInt8=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,1,127,-128),r<0&&(r=255+r+1),this[t]=r&255,t+1};d.prototype.writeInt16LE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,2,32767,-32768),this[t]=r&255,this[t+1]=r>>>8,t+2};d.prototype.writeInt16BE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,2,32767,-32768),this[t]=r>>>8,this[t+1]=r&255,t+2};d.prototype.writeInt32LE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,4,2147483647,-2147483648),this[t]=r&255,this[t+1]=r>>>8,this[t+2]=r>>>16,this[t+3]=r>>>24,t+4};d.prototype.writeInt32BE=function(r,t,n){return r=+r,t=t>>>0,n||ne(this,r,t,4,2147483647,-2147483648),r<0&&(r=4294967295+r+1),this[t]=r>>>24,this[t+1]=r>>>16,this[t+2]=r>>>8,this[t+3]=r&255,t+4};function qc(e,r,t,n,i,a){if(t+n>e.length)throw new RangeError("Index out of range");if(t<0)throw new RangeError("Index out of range")}function Uc(e,r,t,n,i){return r=+r,t=t>>>0,i||qc(e,r,t,4,34028234663852886e22,-34028234663852886e22),Gr.write(e,r,t,n,23,4),t+4}d.prototype.writeFloatLE=function(r,t,n){return Uc(this,r,t,!0,n)};d.prototype.writeFloatBE=function(r,t,n){return Uc(this,r,t,!1,n)};function Cc(e,r,t,n,i){return r=+r,t=t>>>0,i||qc(e,r,t,8,17976931348623157e292,-17976931348623157e292),Gr.write(e,r,t,n,52,8),t+8}d.prototype.writeDoubleLE=function(r,t,n){return Cc(this,r,t,!0,n)};d.prototype.writeDoubleBE=function(r,t,n){return Cc(this,r,t,!1,n)};d.prototype.copy=function(r,t,n,i){if(!d.isBuffer(r))throw new TypeError("argument should be a Buffer");if(n||(n=0),!i&&i!==0&&(i=this.length),t>=r.length&&(t=r.length),t||(t=0),i>0&&i=this.length)throw new RangeError("Index out of range");if(i<0)throw new RangeError("sourceEnd out of bounds");i>this.length&&(i=this.length),r.length-t>>0,n=n===void 0?this.length:n>>>0,r||(r=0);var o;if(typeof r=="number")for(o=t;o55295&&t<57344){if(!i){if(t>56319){(r-=3)>-1&&a.push(239,191,189);continue}else if(o+1===n){(r-=3)>-1&&a.push(239,191,189);continue}i=t;continue}if(t<56320){(r-=3)>-1&&a.push(239,191,189),i=t;continue}t=(i-55296<<10|t-56320)+65536}else i&&(r-=3)>-1&&a.push(239,191,189);if(i=null,t<128){if((r-=1)<0)break;a.push(t)}else if(t<2048){if((r-=2)<0)break;a.push(t>>6|192,t&63|128)}else if(t<65536){if((r-=3)<0)break;a.push(t>>12|224,t>>6&63|128,t&63|128)}else if(t<1114112){if((r-=4)<0)break;a.push(t>>18|240,t>>12&63|128,t>>6&63|128,t&63|128)}else throw new Error("Invalid code point")}return a}function Wg(e){for(var r=[],t=0;t>8,i=t%256,a.push(i),a.push(n);return a}function zc(e){return Ua.toByteArray(Zg(e))}function ni(e,r,t,n){for(var i=0;i=r.length||i>=e.length);++i)r[i+t]=e[i];return i}function Ae(e,r){return e instanceof r||e!=null&&e.constructor!=null&&e.constructor.name!=null&&e.constructor.name===r.name}function Ga(e){return e!==e}var Gg=(function(){for(var e="0123456789abcdef",r=new Array(256),t=0;t<16;++t)for(var n=t*16,i=0;i<16;++i)r[n+i]=e[t]+e[i];return r})()});var oi=y((sS,$a)=>{"use strict";var Vr=typeof Reflect=="object"?Reflect:null,Zc=Vr&&typeof Vr.apply=="function"?Vr.apply:function(r,t,n){return Function.prototype.apply.call(r,t,n)},ii;Vr&&typeof Vr.ownKeys=="function"?ii=Vr.ownKeys:Object.getOwnPropertySymbols?ii=function(r){return Object.getOwnPropertyNames(r).concat(Object.getOwnPropertySymbols(r))}:ii=function(r){return Object.getOwnPropertyNames(r)};function $g(e){console&&console.warn&&console.warn(e)}var Hc=Number.isNaN||function(r){return r!==r};function q(){q.init.call(this)}$a.exports=q;$a.exports.once=Xg;q.EventEmitter=q;q.prototype._events=void 0;q.prototype._eventsCount=0;q.prototype._maxListeners=void 0;var Wc=10;function ai(e){if(typeof e!="function")throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}Object.defineProperty(q,"defaultMaxListeners",{enumerable:!0,get:function(){return Wc},set:function(e){if(typeof e!="number"||e<0||Hc(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");Wc=e}});q.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0};q.prototype.setMaxListeners=function(r){if(typeof r!="number"||r<0||Hc(r))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+r+".");return this._maxListeners=r,this};function Gc(e){return e._maxListeners===void 0?q.defaultMaxListeners:e._maxListeners}q.prototype.getMaxListeners=function(){return Gc(this)};q.prototype.emit=function(r){for(var t=[],n=1;n0&&(o=t[0]),o instanceof Error)throw o;var f=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw f.context=o,f}var s=a[r];if(s===void 0)return!1;if(typeof s=="function")Zc(s,this,t);else for(var u=s.length,l=Xc(s,u),n=0;n0&&o.length>i&&!o.warned){o.warned=!0;var f=new Error("Possible EventEmitter memory leak detected. "+o.length+" "+String(r)+" listeners added. Use emitter.setMaxListeners() to increase limit");f.name="MaxListenersExceededWarning",f.emitter=e,f.type=r,f.count=o.length,$g(f)}return e}q.prototype.addListener=function(r,t){return $c(this,r,t,!1)};q.prototype.on=q.prototype.addListener;q.prototype.prependListener=function(r,t){return $c(this,r,t,!0)};function Vg(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length===0?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function Vc(e,r,t){var n={fired:!1,wrapFn:void 0,target:e,type:r,listener:t},i=Vg.bind(n);return i.listener=t,n.wrapFn=i,i}q.prototype.once=function(r,t){return ai(t),this.on(r,Vc(this,r,t)),this};q.prototype.prependOnceListener=function(r,t){return ai(t),this.prependListener(r,Vc(this,r,t)),this};q.prototype.removeListener=function(r,t){var n,i,a,o,f;if(ai(t),i=this._events,i===void 0)return this;if(n=i[r],n===void 0)return this;if(n===t||n.listener===t)--this._eventsCount===0?this._events=Object.create(null):(delete i[r],i.removeListener&&this.emit("removeListener",r,n.listener||t));else if(typeof n!="function"){for(a=-1,o=n.length-1;o>=0;o--)if(n[o]===t||n[o].listener===t){f=n[o].listener,a=o;break}if(a<0)return this;a===0?n.shift():Yg(n,a),n.length===1&&(i[r]=n[0]),i.removeListener!==void 0&&this.emit("removeListener",r,f||t)}return this};q.prototype.off=q.prototype.removeListener;q.prototype.removeAllListeners=function(r){var t,n,i;if(n=this._events,n===void 0)return this;if(n.removeListener===void 0)return arguments.length===0?(this._events=Object.create(null),this._eventsCount=0):n[r]!==void 0&&(--this._eventsCount===0?this._events=Object.create(null):delete n[r]),this;if(arguments.length===0){var a=Object.keys(n),o;for(i=0;i=0;i--)this.removeListener(r,t[i]);return this};function Yc(e,r,t){var n=e._events;if(n===void 0)return[];var i=n[r];return i===void 0?[]:typeof i=="function"?t?[i.listener||i]:[i]:t?Kg(i):Xc(i,i.length)}q.prototype.listeners=function(r){return Yc(this,r,!0)};q.prototype.rawListeners=function(r){return Yc(this,r,!1)};q.listenerCount=function(e,r){return typeof e.listenerCount=="function"?e.listenerCount(r):Kc.call(e,r)};q.prototype.listenerCount=Kc;function Kc(e){var r=this._events;if(r!==void 0){var t=r[e];if(typeof t=="function")return 1;if(t!==void 0)return t.length}return 0}q.prototype.eventNames=function(){return this._eventsCount>0?ii(this._events):[]};function Xc(e,r){for(var t=new Array(r),n=0;n{Qc.exports=oi().EventEmitter});var ah=y((hS,ih)=>{"use strict";function eh(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),t.push.apply(t,n)}return t}function rh(e){for(var r=1;r0?this.tail.next=n:this.head=n,this.tail=n,++this.length}},{key:"unshift",value:function(t){var n={data:t,next:this.head};this.length===0&&(this.tail=n),this.head=n,++this.length}},{key:"shift",value:function(){if(this.length!==0){var t=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,t}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(t){if(this.length===0)return"";for(var n=this.head,i=""+n.data;n=n.next;)i+=t+n.data;return i}},{key:"concat",value:function(t){if(this.length===0)return fi.alloc(0);for(var n=fi.allocUnsafe(t>>>0),i=this.head,a=0;i;)ob(i.data,n,a),a+=i.data.length,i=i.next;return n}},{key:"consume",value:function(t,n){var i;return to.length?o.length:t;if(f===o.length?a+=o:a+=o.slice(0,t),t-=f,t===0){f===o.length?(++i,n.next?this.head=n.next:this.head=this.tail=null):(this.head=n,n.data=o.slice(f));break}++i}return this.length-=i,a}},{key:"_getBuffer",value:function(t){var n=fi.allocUnsafe(t),i=this.head,a=1;for(i.data.copy(n),t-=i.data.length;i=i.next;){var o=i.data,f=t>o.length?o.length:t;if(o.copy(n,n.length-t,0,f),t-=f,t===0){f===o.length?(++a,i.next?this.head=i.next:this.head=this.tail=null):(this.head=i,i.data=o.slice(f));break}++a}return this.length-=a,n}},{key:ab,value:function(t,n){return Ya(this,rh(rh({},n),{},{depth:0,customInspect:!1}))}}]),e})()});var Xa=y((pS,fh)=>{"use strict";function fb(e,r){var t=this,n=this._readableState&&this._readableState.destroyed,i=this._writableState&&this._writableState.destroyed;return n||i?(r?r(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(Ka,this,e)):process.nextTick(Ka,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(a){!r&&a?t._writableState?t._writableState.errorEmitted?process.nextTick(ui,t):(t._writableState.errorEmitted=!0,process.nextTick(oh,t,a)):process.nextTick(oh,t,a):r?(process.nextTick(ui,t),r(a)):process.nextTick(ui,t)}),this)}function oh(e,r){Ka(e,r),ui(e)}function ui(e){e._writableState&&!e._writableState.emitClose||e._readableState&&!e._readableState.emitClose||e.emit("close")}function ub(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function Ka(e,r){e.emit("error",r)}function lb(e,r){var t=e._readableState,n=e._writableState;t&&t.autoDestroy||n&&n.autoDestroy?e.destroy(r):e.emit("error",r)}fh.exports={destroy:fb,undestroy:ub,errorOrDestroy:lb}});var sr=y((dS,sh)=>{"use strict";function sb(e,r){e.prototype=Object.create(r.prototype),e.prototype.constructor=e,e.__proto__=r}var lh={};function ce(e,r,t){t||(t=Error);function n(a,o,f){return typeof r=="string"?r:r(a,o,f)}var i=(function(a){sb(o,a);function o(f,s,u){return a.call(this,n(f,s,u))||this}return o})(t);i.prototype.name=t.name,i.prototype.code=e,lh[e]=i}function uh(e,r){if(Array.isArray(e)){var t=e.length;return e=e.map(function(n){return String(n)}),t>2?"one of ".concat(r," ").concat(e.slice(0,t-1).join(", "),", or ")+e[t-1]:t===2?"one of ".concat(r," ").concat(e[0]," or ").concat(e[1]):"of ".concat(r," ").concat(e[0])}else return"of ".concat(r," ").concat(String(e))}function cb(e,r,t){return e.substr(!t||t<0?0:+t,r.length)===r}function hb(e,r,t){return(t===void 0||t>e.length)&&(t=e.length),e.substring(t-r.length,t)===r}function pb(e,r,t){return typeof t!="number"&&(t=0),t+r.length>e.length?!1:e.indexOf(r,t)!==-1}ce("ERR_INVALID_OPT_VALUE",function(e,r){return'The value "'+r+'" is invalid for option "'+e+'"'},TypeError);ce("ERR_INVALID_ARG_TYPE",function(e,r,t){var n;typeof r=="string"&&cb(r,"not ")?(n="must not be",r=r.replace(/^not /,"")):n="must be";var i;if(hb(e," argument"))i="The ".concat(e," ").concat(n," ").concat(uh(r,"type"));else{var a=pb(e,".")?"property":"argument";i='The "'.concat(e,'" ').concat(a," ").concat(n," ").concat(uh(r,"type"))}return i+=". Received type ".concat(typeof t),i},TypeError);ce("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF");ce("ERR_METHOD_NOT_IMPLEMENTED",function(e){return"The "+e+" method is not implemented"});ce("ERR_STREAM_PREMATURE_CLOSE","Premature close");ce("ERR_STREAM_DESTROYED",function(e){return"Cannot call "+e+" after a stream was destroyed"});ce("ERR_MULTIPLE_CALLBACK","Callback called multiple times");ce("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable");ce("ERR_STREAM_WRITE_AFTER_END","write after end");ce("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError);ce("ERR_UNKNOWN_ENCODING",function(e){return"Unknown encoding: "+e},TypeError);ce("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event");sh.exports.codes=lh});var Ja=y((yS,ch)=>{"use strict";var db=sr().codes.ERR_INVALID_OPT_VALUE;function yb(e,r,t){return e.highWaterMark!=null?e.highWaterMark:r?e[t]:null}function vb(e,r,t,n){var i=yb(r,n,t);if(i!=null){if(!(isFinite(i)&&Math.floor(i)===i)||i<0){var a=n?t:"highWaterMark";throw new db(a,i)}return Math.floor(i)}return e.objectMode?16:16*1024}ch.exports={getHighWaterMark:vb}});var ph=y((vS,hh)=>{hh.exports=_b;function _b(e,r){if(Qa("noDeprecation"))return e;var t=!1;function n(){if(!t){if(Qa("throwDeprecation"))throw new Error(r);Qa("traceDeprecation")?console.trace(r):console.warn(r),t=!0}return e.apply(this,arguments)}return n}function Qa(e){try{if(!globalThis.localStorage)return!1}catch{return!1}var r=globalThis.localStorage[e];return r==null?!1:String(r).toLowerCase()==="true"}});var to=y((_S,bh)=>{"use strict";bh.exports=z;function yh(e){var r=this;this.next=null,this.entry=null,this.finish=function(){Wb(r,e)}}var Yr;z.WritableState=Ft;var gb={deprecate:ph()},vh=Va(),si=lr().Buffer,bb=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function wb(e){return si.from(e)}function Eb(e){return si.isBuffer(e)||e instanceof bb}var ro=Xa(),mb=Ja(),Sb=mb.getHighWaterMark,We=sr().codes,xb=We.ERR_INVALID_ARG_TYPE,Ab=We.ERR_METHOD_NOT_IMPLEMENTED,Rb=We.ERR_MULTIPLE_CALLBACK,Ob=We.ERR_STREAM_CANNOT_PIPE,Tb=We.ERR_STREAM_DESTROYED,Ib=We.ERR_STREAM_NULL_VALUES,Nb=We.ERR_STREAM_WRITE_AFTER_END,Lb=We.ERR_UNKNOWN_ENCODING,Kr=ro.errorOrDestroy;Be()(z,vh);function Fb(){}function Ft(e,r,t){Yr=Yr||cr(),e=e||{},typeof t!="boolean"&&(t=r instanceof Yr),this.objectMode=!!e.objectMode,t&&(this.objectMode=this.objectMode||!!e.writableObjectMode),this.highWaterMark=Sb(this,e,"writableHighWaterMark",t),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var n=e.decodeStrings===!1;this.decodeStrings=!n,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(i){qb(r,i)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new yh(this)}Ft.prototype.getBuffer=function(){for(var r=this.bufferedRequest,t=[];r;)t.push(r),r=r.next;return t};(function(){try{Object.defineProperty(Ft.prototype,"buffer",{get:gb.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch{}})();var li;typeof Symbol=="function"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]=="function"?(li=Function.prototype[Symbol.hasInstance],Object.defineProperty(z,Symbol.hasInstance,{value:function(r){return li.call(this,r)?!0:this!==z?!1:r&&r._writableState instanceof Ft}})):li=function(r){return r instanceof this};function z(e){Yr=Yr||cr();var r=this instanceof Yr;if(!r&&!li.call(z,this))return new z(e);this._writableState=new Ft(e,this,r),this.writable=!0,e&&(typeof e.write=="function"&&(this._write=e.write),typeof e.writev=="function"&&(this._writev=e.writev),typeof e.destroy=="function"&&(this._destroy=e.destroy),typeof e.final=="function"&&(this._final=e.final)),vh.call(this)}z.prototype.pipe=function(){Kr(this,new Ob)};function kb(e,r){var t=new Nb;Kr(e,t),process.nextTick(r,t)}function Pb(e,r,t,n){var i;return t===null?i=new Ib:typeof t!="string"&&!r.objectMode&&(i=new xb("chunk",["string","Buffer"],t)),i?(Kr(e,i),process.nextTick(n,i),!1):!0}z.prototype.write=function(e,r,t){var n=this._writableState,i=!1,a=!n.objectMode&&Eb(e);return a&&!si.isBuffer(e)&&(e=wb(e)),typeof r=="function"&&(t=r,r=null),a?r="buffer":r||(r=n.defaultEncoding),typeof t!="function"&&(t=Fb),n.ending?kb(this,t):(a||Pb(this,n,e,t))&&(n.pendingcb++,i=Mb(this,n,a,e,r,t)),i};z.prototype.cork=function(){this._writableState.corked++};z.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&_h(this,e))};z.prototype.setDefaultEncoding=function(r){if(typeof r=="string"&&(r=r.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((r+"").toLowerCase())>-1))throw new Lb(r);return this._writableState.defaultEncoding=r,this};Object.defineProperty(z.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function Db(e,r,t){return!e.objectMode&&e.decodeStrings!==!1&&typeof r=="string"&&(r=si.from(r,t)),r}Object.defineProperty(z.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function Mb(e,r,t,n,i,a){if(!t){var o=Db(r,n,i);n!==o&&(t=!0,i="buffer",n=o)}var f=r.objectMode?1:n.length;r.length+=f;var s=r.length{"use strict";var Hb=Object.keys||function(e){var r=[];for(var t in e)r.push(t);return r};Eh.exports=Re;var wh=ao(),io=to();Be()(Re,wh);for(no=Hb(io.prototype),ci=0;ci{var pi=lr(),Oe=pi.Buffer;function mh(e,r){for(var t in e)r[t]=e[t]}Oe.from&&Oe.alloc&&Oe.allocUnsafe&&Oe.allocUnsafeSlow?Sh.exports=pi:(mh(pi,oo),oo.Buffer=hr);function hr(e,r,t){return Oe(e,r,t)}hr.prototype=Object.create(Oe.prototype);mh(Oe,hr);hr.from=function(e,r,t){if(typeof e=="number")throw new TypeError("Argument must not be a number");return Oe(e,r,t)};hr.alloc=function(e,r,t){if(typeof e!="number")throw new TypeError("Argument must be a number");var n=Oe(e);return r!==void 0?typeof t=="string"?n.fill(r,t):n.fill(r):n.fill(0),n};hr.allocUnsafe=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return Oe(e)};hr.allocUnsafeSlow=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return pi.SlowBuffer(e)}});var lo=y(Rh=>{"use strict";var uo=xh().Buffer,Ah=uo.isEncoding||function(e){switch(e=""+e,e&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function Vb(e){if(!e)return"utf8";for(var r;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(r)return;e=(""+e).toLowerCase(),r=!0}}function Yb(e){var r=Vb(e);if(typeof r!="string"&&(uo.isEncoding===Ah||!Ah(e)))throw new Error("Unknown encoding: "+e);return r||e}Rh.StringDecoder=kt;function kt(e){this.encoding=Yb(e);var r;switch(this.encoding){case"utf16le":this.text=rw,this.end=tw,r=4;break;case"utf8":this.fillLast=Jb,r=4;break;case"base64":this.text=nw,this.end=iw,r=3;break;default:this.write=aw,this.end=ow;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=uo.allocUnsafe(r)}kt.prototype.write=function(e){if(e.length===0)return"";var r,t;if(this.lastNeed){if(r=this.fillLast(e),r===void 0)return"";t=this.lastNeed,this.lastNeed=0}else t=0;return t>5===6?2:e>>4===14?3:e>>3===30?4:e>>6===2?-1:-2}function Kb(e,r,t){var n=r.length-1;if(n=0?(i>0&&(e.lastNeed=i-1),i):--n=0?(i>0&&(e.lastNeed=i-2),i):--n=0?(i>0&&(i===2?i=0:e.lastNeed=i-3),i):0))}function Xb(e,r,t){if((r[0]&192)!==128)return e.lastNeed=0,"\uFFFD";if(e.lastNeed>1&&r.length>1){if((r[1]&192)!==128)return e.lastNeed=1,"\uFFFD";if(e.lastNeed>2&&r.length>2&&(r[2]&192)!==128)return e.lastNeed=2,"\uFFFD"}}function Jb(e){var r=this.lastTotal-this.lastNeed,t=Xb(this,e,r);if(t!==void 0)return t;if(this.lastNeed<=e.length)return e.copy(this.lastChar,r,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,r,0,e.length),this.lastNeed-=e.length}function Qb(e,r){var t=Kb(this,e,r);if(!this.lastNeed)return e.toString("utf8",r);this.lastTotal=t;var n=e.length-(t-this.lastNeed);return e.copy(this.lastChar,0,n),e.toString("utf8",r,n)}function ew(e){var r=e&&e.length?this.write(e):"";return this.lastNeed?r+"\uFFFD":r}function rw(e,r){if((e.length-r)%2===0){var t=e.toString("utf16le",r);if(t){var n=t.charCodeAt(t.length-1);if(n>=55296&&n<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],t.slice(0,-1)}return t}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",r,e.length-1)}function tw(e){var r=e&&e.length?this.write(e):"";if(this.lastNeed){var t=this.lastTotal-this.lastNeed;return r+this.lastChar.toString("utf16le",0,t)}return r}function nw(e,r){var t=(e.length-r)%3;return t===0?e.toString("base64",r):(this.lastNeed=3-t,this.lastTotal=3,t===1?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",r,e.length-t))}function iw(e){var r=e&&e.length?this.write(e):"";return this.lastNeed?r+this.lastChar.toString("base64",0,3-this.lastNeed):r}function aw(e){return e.toString(this.encoding)}function ow(e){return e&&e.length?this.write(e):""}});var di=y((wS,Ih)=>{"use strict";var Oh=sr().codes.ERR_STREAM_PREMATURE_CLOSE;function fw(e){var r=!1;return function(){if(!r){r=!0;for(var t=arguments.length,n=new Array(t),i=0;i{"use strict";var yi;function He(e,r,t){return r=sw(r),r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function sw(e){var r=cw(e,"string");return typeof r=="symbol"?r:String(r)}function cw(e,r){if(typeof e!="object"||e===null)return e;var t=e[Symbol.toPrimitive];if(t!==void 0){var n=t.call(e,r||"default");if(typeof n!="object")return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return(r==="string"?String:Number)(e)}var hw=di(),Ge=Symbol("lastResolve"),pr=Symbol("lastReject"),Pt=Symbol("error"),vi=Symbol("ended"),dr=Symbol("lastPromise"),so=Symbol("handlePromise"),yr=Symbol("stream");function $e(e,r){return{value:e,done:r}}function pw(e){var r=e[Ge];if(r!==null){var t=e[yr].read();t!==null&&(e[dr]=null,e[Ge]=null,e[pr]=null,r($e(t,!1)))}}function dw(e){process.nextTick(pw,e)}function yw(e,r){return function(t,n){e.then(function(){if(r[vi]){t($e(void 0,!0));return}r[so](t,n)},n)}}var vw=Object.getPrototypeOf(function(){}),_w=Object.setPrototypeOf((yi={get stream(){return this[yr]},next:function(){var r=this,t=this[Pt];if(t!==null)return Promise.reject(t);if(this[vi])return Promise.resolve($e(void 0,!0));if(this[yr].destroyed)return new Promise(function(o,f){process.nextTick(function(){r[Pt]?f(r[Pt]):o($e(void 0,!0))})});var n=this[dr],i;if(n)i=new Promise(yw(n,this));else{var a=this[yr].read();if(a!==null)return Promise.resolve($e(a,!1));i=new Promise(this[so])}return this[dr]=i,i}},He(yi,Symbol.asyncIterator,function(){return this}),He(yi,"return",function(){var r=this;return new Promise(function(t,n){r[yr].destroy(null,function(i){if(i){n(i);return}t($e(void 0,!0))})})}),yi),vw),gw=function(r){var t,n=Object.create(_w,(t={},He(t,yr,{value:r,writable:!0}),He(t,Ge,{value:null,writable:!0}),He(t,pr,{value:null,writable:!0}),He(t,Pt,{value:null,writable:!0}),He(t,vi,{value:r._readableState.endEmitted,writable:!0}),He(t,so,{value:function(a,o){var f=n[yr].read();f?(n[dr]=null,n[Ge]=null,n[pr]=null,a($e(f,!1))):(n[Ge]=a,n[pr]=o)},writable:!0}),t));return n[dr]=null,hw(r,function(i){if(i&&i.code!=="ERR_STREAM_PREMATURE_CLOSE"){var a=n[pr];a!==null&&(n[dr]=null,n[Ge]=null,n[pr]=null,a(i)),n[Pt]=i;return}var o=n[Ge];o!==null&&(n[dr]=null,n[Ge]=null,n[pr]=null,o($e(void 0,!0))),n[vi]=!0}),r.on("readable",dw.bind(null,n)),n};Nh.exports=gw});var kh=y((mS,Fh)=>{Fh.exports=function(){throw new Error("Readable.from is not available in the browser")}});var ao=y((xS,Zh)=>{"use strict";Zh.exports=j;var Xr;j.ReadableState=jh;var SS=oi().EventEmitter,Mh=function(r,t){return r.listeners(t).length},Mt=Va(),_i=lr().Buffer,bw=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function ww(e){return _i.from(e)}function Ew(e){return _i.isBuffer(e)||e instanceof bw}var co=Se(),N;co&&co.debuglog?N=co.debuglog("stream"):N=function(){};var mw=ah(),bo=Xa(),Sw=Ja(),xw=Sw.getHighWaterMark,gi=sr().codes,Aw=gi.ERR_INVALID_ARG_TYPE,Rw=gi.ERR_STREAM_PUSH_AFTER_EOF,Ow=gi.ERR_METHOD_NOT_IMPLEMENTED,Tw=gi.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,Jr,ho,po;Be()(j,Mt);var Dt=bo.errorOrDestroy,yo=["error","close","destroy","pause","resume"];function Iw(e,r,t){if(typeof e.prependListener=="function")return e.prependListener(r,t);!e._events||!e._events[r]?e.on(r,t):Array.isArray(e._events[r])?e._events[r].unshift(t):e._events[r]=[t,e._events[r]]}function jh(e,r,t){Xr=Xr||cr(),e=e||{},typeof t!="boolean"&&(t=r instanceof Xr),this.objectMode=!!e.objectMode,t&&(this.objectMode=this.objectMode||!!e.readableObjectMode),this.highWaterMark=xw(this,e,"readableHighWaterMark",t),this.buffer=new mw,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(Jr||(Jr=lo().StringDecoder),this.decoder=new Jr(e.encoding),this.encoding=e.encoding)}function j(e){if(Xr=Xr||cr(),!(this instanceof j))return new j(e);var r=this instanceof Xr;this._readableState=new jh(e,this,r),this.readable=!0,e&&(typeof e.read=="function"&&(this._read=e.read),typeof e.destroy=="function"&&(this._destroy=e.destroy)),Mt.call(this)}Object.defineProperty(j.prototype,"destroyed",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(r){this._readableState&&(this._readableState.destroyed=r)}});j.prototype.destroy=bo.destroy;j.prototype._undestroy=bo.undestroy;j.prototype._destroy=function(e,r){r(e)};j.prototype.push=function(e,r){var t=this._readableState,n;return t.objectMode?n=!0:typeof e=="string"&&(r=r||t.defaultEncoding,r!==t.encoding&&(e=_i.from(e,r),r=""),n=!0),Bh(this,e,r,!1,n)};j.prototype.unshift=function(e){return Bh(this,e,null,!0,!1)};function Bh(e,r,t,n,i){N("readableAddChunk",r);var a=e._readableState;if(r===null)a.reading=!1,Fw(e,a);else{var o;if(i||(o=Nw(a,r)),o)Dt(e,o);else if(a.objectMode||r&&r.length>0)if(typeof r!="string"&&!a.objectMode&&Object.getPrototypeOf(r)!==_i.prototype&&(r=ww(r)),n)a.endEmitted?Dt(e,new Tw):vo(e,a,r,!0);else if(a.ended)Dt(e,new Rw);else{if(a.destroyed)return!1;a.reading=!1,a.decoder&&!t?(r=a.decoder.write(r),a.objectMode||r.length!==0?vo(e,a,r,!1):go(e,a)):vo(e,a,r,!1)}else n||(a.reading=!1,go(e,a))}return!a.ended&&(a.length=Ph?e=Ph:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function Dh(e,r){return e<=0||r.length===0&&r.ended?0:r.objectMode?1:e!==e?r.flowing&&r.length?r.buffer.head.data.length:r.length:(e>r.highWaterMark&&(r.highWaterMark=Lw(e)),e<=r.length?e:r.ended?r.length:(r.needReadable=!0,0))}j.prototype.read=function(e){N("read",e),e=parseInt(e,10);var r=this._readableState,t=e;if(e!==0&&(r.emittedReadable=!1),e===0&&r.needReadable&&((r.highWaterMark!==0?r.length>=r.highWaterMark:r.length>0)||r.ended))return N("read: emitReadable",r.length,r.ended),r.length===0&&r.ended?_o(this):bi(this),null;if(e=Dh(e,r),e===0&&r.ended)return r.length===0&&_o(this),null;var n=r.needReadable;N("need readable",n),(r.length===0||r.length-e0?i=Ch(e,r):i=null,i===null?(r.needReadable=r.length<=r.highWaterMark,e=0):(r.length-=e,r.awaitDrain=0),r.length===0&&(r.ended||(r.needReadable=!0),t!==e&&r.ended&&_o(this)),i!==null&&this.emit("data",i),i};function Fw(e,r){if(N("onEofChunk"),!r.ended){if(r.decoder){var t=r.decoder.end();t&&t.length&&(r.buffer.push(t),r.length+=r.objectMode?1:t.length)}r.ended=!0,r.sync?bi(e):(r.needReadable=!1,r.emittedReadable||(r.emittedReadable=!0,qh(e)))}}function bi(e){var r=e._readableState;N("emitReadable",r.needReadable,r.emittedReadable),r.needReadable=!1,r.emittedReadable||(N("emitReadable",r.flowing),r.emittedReadable=!0,process.nextTick(qh,e))}function qh(e){var r=e._readableState;N("emitReadable_",r.destroyed,r.length,r.ended),!r.destroyed&&(r.length||r.ended)&&(e.emit("readable"),r.emittedReadable=!1),r.needReadable=!r.flowing&&!r.ended&&r.length<=r.highWaterMark,wo(e)}function go(e,r){r.readingMore||(r.readingMore=!0,process.nextTick(kw,e,r))}function kw(e,r){for(;!r.reading&&!r.ended&&(r.length1&&zh(n.pipes,e)!==-1)&&!u&&(N("false write response, pause",n.awaitDrain),n.awaitDrain++),t.pause())}function p(m){N("onerror",m),_(),e.removeListener("error",p),Mh(e,"error")===0&&Dt(e,m)}Iw(e,"error",p);function h(){e.removeListener("finish",v),_()}e.once("close",h);function v(){N("onfinish"),e.removeListener("close",h),_()}e.once("finish",v);function _(){N("unpipe"),t.unpipe(e)}return e.emit("pipe",t),n.flowing||(N("pipe resume"),t.resume()),e};function Pw(e){return function(){var t=e._readableState;N("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,t.awaitDrain===0&&Mh(e,"data")&&(t.flowing=!0,wo(e))}}j.prototype.unpipe=function(e){var r=this._readableState,t={hasUnpiped:!1};if(r.pipesCount===0)return this;if(r.pipesCount===1)return e&&e!==r.pipes?this:(e||(e=r.pipes),r.pipes=null,r.pipesCount=0,r.flowing=!1,e&&e.emit("unpipe",this,t),this);if(!e){var n=r.pipes,i=r.pipesCount;r.pipes=null,r.pipesCount=0,r.flowing=!1;for(var a=0;a0,n.flowing!==!1&&this.resume()):e==="readable"&&!n.endEmitted&&!n.readableListening&&(n.readableListening=n.needReadable=!0,n.flowing=!1,n.emittedReadable=!1,N("on readable",n.length,n.reading),n.length?bi(this):n.reading||process.nextTick(Dw,this)),t};j.prototype.addListener=j.prototype.on;j.prototype.removeListener=function(e,r){var t=Mt.prototype.removeListener.call(this,e,r);return e==="readable"&&process.nextTick(Uh,this),t};j.prototype.removeAllListeners=function(e){var r=Mt.prototype.removeAllListeners.apply(this,arguments);return(e==="readable"||e===void 0)&&process.nextTick(Uh,this),r};function Uh(e){var r=e._readableState;r.readableListening=e.listenerCount("readable")>0,r.resumeScheduled&&!r.paused?r.flowing=!0:e.listenerCount("data")>0&&e.resume()}function Dw(e){N("readable nexttick read 0"),e.read(0)}j.prototype.resume=function(){var e=this._readableState;return e.flowing||(N("resume"),e.flowing=!e.readableListening,Mw(this,e)),e.paused=!1,this};function Mw(e,r){r.resumeScheduled||(r.resumeScheduled=!0,process.nextTick(jw,e,r))}function jw(e,r){N("resume",r.reading),r.reading||e.read(0),r.resumeScheduled=!1,e.emit("resume"),wo(e),r.flowing&&!r.reading&&e.read(0)}j.prototype.pause=function(){return N("call pause flowing=%j",this._readableState.flowing),this._readableState.flowing!==!1&&(N("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this};function wo(e){var r=e._readableState;for(N("flow",r.flowing);r.flowing&&e.read()!==null;);}j.prototype.wrap=function(e){var r=this,t=this._readableState,n=!1;e.on("end",function(){if(N("wrapped end"),t.decoder&&!t.ended){var o=t.decoder.end();o&&o.length&&r.push(o)}r.push(null)}),e.on("data",function(o){if(N("wrapped data"),t.decoder&&(o=t.decoder.write(o)),!(t.objectMode&&o==null)&&!(!t.objectMode&&(!o||!o.length))){var f=r.push(o);f||(n=!0,e.pause())}});for(var i in e)this[i]===void 0&&typeof e[i]=="function"&&(this[i]=(function(f){return function(){return e[f].apply(e,arguments)}})(i));for(var a=0;a=r.length?(r.decoder?t=r.buffer.join(""):r.buffer.length===1?t=r.buffer.first():t=r.buffer.concat(r.length),r.buffer.clear()):t=r.buffer.consume(e,r.decoder),t}function _o(e){var r=e._readableState;N("endReadable",r.endEmitted),r.endEmitted||(r.ended=!0,process.nextTick(Bw,r,e))}function Bw(e,r){if(N("endReadableNT",e.endEmitted,e.length),!e.endEmitted&&e.length===0&&(e.endEmitted=!0,r.readable=!1,r.emit("end"),e.autoDestroy)){var t=r._writableState;(!t||t.autoDestroy&&t.finished)&&r.destroy()}}typeof Symbol=="function"&&(j.from=function(e,r){return po===void 0&&(po=kh()),po(j,e,r)});function zh(e,r){for(var t=0,n=e.length;t{"use strict";Hh.exports=De;var wi=sr().codes,qw=wi.ERR_METHOD_NOT_IMPLEMENTED,Uw=wi.ERR_MULTIPLE_CALLBACK,Cw=wi.ERR_TRANSFORM_ALREADY_TRANSFORMING,zw=wi.ERR_TRANSFORM_WITH_LENGTH_0,Ei=cr();Be()(De,Ei);function Zw(e,r){var t=this._transformState;t.transforming=!1;var n=t.writecb;if(n===null)return this.emit("error",new Uw);t.writechunk=null,t.writecb=null,r!=null&&this.push(r),n(e);var i=this._readableState;i.reading=!1,(i.needReadable||i.length{"use strict";$h.exports=jt;var Gh=Eo();Be()(jt,Gh);function jt(e){if(!(this instanceof jt))return new jt(e);Gh.call(this,e)}jt.prototype._transform=function(e,r,t){t(null,e)}});var Qh=y((OS,Jh)=>{"use strict";var mo;function Hw(e){var r=!1;return function(){r||(r=!0,e.apply(void 0,arguments))}}var Xh=sr().codes,Gw=Xh.ERR_MISSING_ARGS,$w=Xh.ERR_STREAM_DESTROYED;function Yh(e){if(e)throw e}function Vw(e){return e.setHeader&&typeof e.abort=="function"}function Yw(e,r,t,n){n=Hw(n);var i=!1;e.on("close",function(){i=!0}),mo===void 0&&(mo=di()),mo(e,{readable:r,writable:t},function(o){if(o)return n(o);i=!0,n()});var a=!1;return function(o){if(!i&&!a){if(a=!0,Vw(e))return e.abort();if(typeof e.destroy=="function")return e.destroy();n(o||new $w("pipe"))}}}function Kh(e){e()}function Kw(e,r){return e.pipe(r)}function Xw(e){return!e.length||typeof e[e.length-1]!="function"?Yh:e.pop()}function Jw(){for(var e=arguments.length,r=new Array(e),t=0;t0;return Yw(o,s,u,function(l){i||(i=l),l&&a.forEach(Kh),!s&&(a.forEach(Kh),n(i))})});return r.reduce(Kw)}Jh.exports=Jw});var xo=y((TS,ep)=>{ep.exports=he;var So=oi().EventEmitter,Qw=Be();Qw(he,So);he.Readable=ao();he.Writable=to();he.Duplex=cr();he.Transform=Eo();he.PassThrough=Vh();he.finished=di();he.pipeline=Qh();he.Stream=he;function he(){So.call(this)}he.prototype.pipe=function(e,r){var t=this;function n(l){e.writable&&e.write(l)===!1&&t.pause&&t.pause()}t.on("data",n);function i(){t.readable&&t.resume&&t.resume()}e.on("drain",i),!e._isStdio&&(!r||r.end!==!1)&&(t.on("end",o),t.on("close",f));var a=!1;function o(){a||(a=!0,e.end())}function f(){a||(a=!0,typeof e.destroy=="function"&&e.destroy())}function s(l){if(u(),So.listenerCount(this,"error")===0)throw l}t.on("error",s),e.on("error",s);function u(){t.removeListener("data",n),e.removeListener("drain",i),t.removeListener("end",o),t.removeListener("close",f),t.removeListener("error",s),e.removeListener("error",s),t.removeListener("end",u),t.removeListener("close",u),e.removeListener("close",u)}return t.on("end",u),t.on("close",u),e.on("close",u),e.emit("pipe",t),e}});var K={};Jd(K,{default:()=>rE,finished:()=>np,isDisturbed:()=>op,isErrored:()=>ap,isReadable:()=>ip});var Qr,tp,rp,mi,Ao,eE,np,ip,ap,op,rE,fp=Xd(()=>{"use strict";Qr=ft(xo());re(K,ft(xo()));tp=Qr.default??Qr.default??{},rp=Qr.finished??tp.finished,mi=e=>!!e&&typeof e.getReader=="function"&&typeof e.cancel=="function",Ao=e=>!!e&&typeof e.getWriter=="function"&&typeof e.abort=="function",eE=e=>e instanceof Error?e:e==null?new Error("stream errored"):new Error(String(e)),np=(e,r,t)=>{let n=r,i=t;if(typeof n=="function"&&(i=n,n={}),!mi(e)&&!Ao(e)&&typeof rp=="function")return rp(e,n,i);let a=typeof i=="function"?i:()=>{},o=n?.readable!==!1,f=n?.writable!==!1,s=!1,u=null,l=()=>{s=!0,u!==null&&(clearTimeout(u),u=null)},c=(h=void 0)=>{s||(l(),queueMicrotask(()=>a(h)))},p=()=>{if(s)return;let h=e?._state;if(h==="errored"){c(eE(e?._storedError));return}if(h==="closed"||mi(e)&&!o||Ao(e)&&!f){c();return}u=setTimeout(p,0)};return p(),l},ip=e=>mi(e)?e._state==="readable":!!e&&e.readable!==!1&&e.destroyed!==!0,ap=e=>mi(e)||Ao(e)?e?._state==="errored":e?.errored!=null,op=e=>!!(e?.locked||e?.disturbed===!0||e?._disturbed===!0||e?.readableDidRead===!0),rE={...tp,finished:np,isReadable:ip,isErrored:ap,isDisturbed:op}});var lp=y((NS,up)=>{"use strict";function tE(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}up.exports=tE});var Bt=y(Q=>{"use strict";var nE=typeof Uint8Array<"u"&&typeof Uint16Array<"u"&&typeof Int32Array<"u";function iE(e,r){return Object.prototype.hasOwnProperty.call(e,r)}Q.assign=function(e){for(var r=Array.prototype.slice.call(arguments,1);r.length;){var t=r.shift();if(t){if(typeof t!="object")throw new TypeError(t+"must be non-object");for(var n in t)iE(t,n)&&(e[n]=t[n])}}return e};Q.shrinkBuf=function(e,r){return e.length===r?e:e.subarray?e.subarray(0,r):(e.length=r,e)};var aE={arraySet:function(e,r,t,n,i){if(r.subarray&&e.subarray){e.set(r.subarray(t,t+n),i);return}for(var a=0;a{"use strict";var fE=Bt(),uE=4,sp=0,cp=1,lE=2;function rt(e){for(var r=e.length;--r>=0;)e[r]=0}var sE=0,_p=1,cE=2,hE=3,pE=258,Fo=29,Wt=256,Ut=Wt+1+Fo,et=30,ko=19,gp=2*Ut+1,vr=15,Ro=16,dE=7,Po=256,bp=16,wp=17,Ep=18,No=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],Si=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],yE=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],mp=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],vE=512,Me=new Array((Ut+2)*2);rt(Me);var qt=new Array(et*2);rt(qt);var Ct=new Array(vE);rt(Ct);var zt=new Array(pE-hE+1);rt(zt);var Do=new Array(Fo);rt(Do);var xi=new Array(et);rt(xi);function Oo(e,r,t,n,i){this.static_tree=e,this.extra_bits=r,this.extra_base=t,this.elems=n,this.max_length=i,this.has_stree=e&&e.length}var Sp,xp,Ap;function To(e,r){this.dyn_tree=e,this.max_code=0,this.stat_desc=r}function Rp(e){return e<256?Ct[e]:Ct[256+(e>>>7)]}function Zt(e,r){e.pending_buf[e.pending++]=r&255,e.pending_buf[e.pending++]=r>>>8&255}function ie(e,r,t){e.bi_valid>Ro-t?(e.bi_buf|=r<>Ro-e.bi_valid,e.bi_valid+=t-Ro):(e.bi_buf|=r<>>=1,t<<=1;while(--r>0);return t>>>1}function _E(e){e.bi_valid===16?(Zt(e,e.bi_buf),e.bi_buf=0,e.bi_valid=0):e.bi_valid>=8&&(e.pending_buf[e.pending++]=e.bi_buf&255,e.bi_buf>>=8,e.bi_valid-=8)}function gE(e,r){var t=r.dyn_tree,n=r.max_code,i=r.stat_desc.static_tree,a=r.stat_desc.has_stree,o=r.stat_desc.extra_bits,f=r.stat_desc.extra_base,s=r.stat_desc.max_length,u,l,c,p,h,v,_=0;for(p=0;p<=vr;p++)e.bl_count[p]=0;for(t[e.heap[e.heap_max]*2+1]=0,u=e.heap_max+1;us&&(p=s,_++),t[l*2+1]=p,!(l>n)&&(e.bl_count[p]++,h=0,l>=f&&(h=o[l-f]),v=t[l*2],e.opt_len+=v*(p+h),a&&(e.static_len+=v*(i[l*2+1]+h)));if(_!==0){do{for(p=s-1;e.bl_count[p]===0;)p--;e.bl_count[p]--,e.bl_count[p+1]+=2,e.bl_count[s]--,_-=2}while(_>0);for(p=s;p!==0;p--)for(l=e.bl_count[p];l!==0;)c=e.heap[--u],!(c>n)&&(t[c*2+1]!==p&&(e.opt_len+=(p-t[c*2+1])*t[c*2],t[c*2+1]=p),l--)}}function Tp(e,r,t){var n=new Array(vr+1),i=0,a,o;for(a=1;a<=vr;a++)n[a]=i=i+t[a-1]<<1;for(o=0;o<=r;o++){var f=e[o*2+1];f!==0&&(e[o*2]=Op(n[f]++,f))}}function bE(){var e,r,t,n,i,a=new Array(vr+1);for(t=0,n=0;n>=7;n8?Zt(e,e.bi_buf):e.bi_valid>0&&(e.pending_buf[e.pending++]=e.bi_buf),e.bi_buf=0,e.bi_valid=0}function wE(e,r,t,n){Np(e),n&&(Zt(e,t),Zt(e,~t)),fE.arraySet(e.pending_buf,e.window,r,t,e.pending),e.pending+=t}function hp(e,r,t,n){var i=r*2,a=t*2;return e[i]>1;o>=1;o--)Io(e,t,o);u=a;do o=e.heap[1],e.heap[1]=e.heap[e.heap_len--],Io(e,t,1),f=e.heap[1],e.heap[--e.heap_max]=o,e.heap[--e.heap_max]=f,t[u*2]=t[o*2]+t[f*2],e.depth[u]=(e.depth[o]>=e.depth[f]?e.depth[o]:e.depth[f])+1,t[o*2+1]=t[f*2+1]=u,e.heap[1]=u++,Io(e,t,1);while(e.heap_len>=2);e.heap[--e.heap_max]=e.heap[1],gE(e,r),Tp(t,s,e.bl_count)}function dp(e,r,t){var n,i=-1,a,o=r[1],f=0,s=7,u=4;for(o===0&&(s=138,u=3),r[(t+1)*2+1]=65535,n=0;n<=t;n++)a=o,o=r[(n+1)*2+1],!(++f=3&&e.bl_tree[mp[r]*2+1]===0;r--);return e.opt_len+=3*(r+1)+5+5+4,r}function mE(e,r,t,n){var i;for(ie(e,r-257,5),ie(e,t-1,5),ie(e,n-4,4),i=0;i>>=1)if(r&1&&e.dyn_ltree[t*2]!==0)return sp;if(e.dyn_ltree[18]!==0||e.dyn_ltree[20]!==0||e.dyn_ltree[26]!==0)return cp;for(t=32;t0?(e.strm.data_type===lE&&(e.strm.data_type=SE(e)),Lo(e,e.l_desc),Lo(e,e.d_desc),o=EE(e),i=e.opt_len+3+7>>>3,a=e.static_len+3+7>>>3,a<=i&&(i=a)):i=a=t+5,t+4<=i&&r!==-1?Lp(e,r,t,n):e.strategy===uE||a===i?(ie(e,(_p<<1)+(n?1:0),3),pp(e,Me,qt)):(ie(e,(cE<<1)+(n?1:0),3),mE(e,e.l_desc.max_code+1,e.d_desc.max_code+1,o+1),pp(e,e.dyn_ltree,e.dyn_dtree)),Ip(e),n&&Np(e)}function OE(e,r,t){return e.pending_buf[e.d_buf+e.last_lit*2]=r>>>8&255,e.pending_buf[e.d_buf+e.last_lit*2+1]=r&255,e.pending_buf[e.l_buf+e.last_lit]=t&255,e.last_lit++,r===0?e.dyn_ltree[t*2]++:(e.matches++,r--,e.dyn_ltree[(zt[t]+Wt+1)*2]++,e.dyn_dtree[Rp(r)*2]++),e.last_lit===e.lit_bufsize-1}tt._tr_init=xE;tt._tr_stored_block=Lp;tt._tr_flush_block=RE;tt._tr_tally=OE;tt._tr_align=AE});var Mo=y((kS,kp)=>{"use strict";function TE(e,r,t,n){for(var i=e&65535|0,a=e>>>16&65535|0,o=0;t!==0;){o=t>2e3?2e3:t,t-=o;do i=i+r[n++]|0,a=a+i|0;while(--o);i%=65521,a%=65521}return i|a<<16|0}kp.exports=TE});var jo=y((PS,Pp)=>{"use strict";function IE(){for(var e,r=[],t=0;t<256;t++){e=t;for(var n=0;n<8;n++)e=e&1?3988292384^e>>>1:e>>>1;r[t]=e}return r}var NE=IE();function LE(e,r,t,n){var i=NE,a=n+t;e^=-1;for(var o=n;o>>8^i[(e^r[o])&255];return e^-1}Pp.exports=LE});var Mp=y((DS,Dp)=>{"use strict";Dp.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}});var Hp=y(Le=>{"use strict";var ee=Bt(),pe=Fp(),Up=Mo(),Ve=jo(),FE=Mp(),wr=0,kE=1,PE=3,Qe=4,jp=5,Ne=0,Bp=1,de=-2,DE=-3,Bo=-5,ME=-1,jE=1,Ai=2,BE=3,qE=4,UE=0,CE=2,Ii=8,zE=9,ZE=15,WE=8,HE=29,GE=256,Uo=GE+1+HE,$E=30,VE=19,YE=2*Uo+1,KE=15,M=3,Xe=258,Ee=Xe+M+1,XE=32,Ni=42,Co=69,Ri=73,Oi=91,Ti=103,_r=113,Gt=666,H=1,$t=2,gr=3,at=4,JE=3;function Je(e,r){return e.msg=FE[r],r}function qp(e){return(e<<1)-(e>4?9:0)}function Ke(e){for(var r=e.length;--r>=0;)e[r]=0}function Ye(e){var r=e.state,t=r.pending;t>e.avail_out&&(t=e.avail_out),t!==0&&(ee.arraySet(e.output,r.pending_buf,r.pending_out,t,e.next_out),e.next_out+=t,r.pending_out+=t,e.total_out+=t,e.avail_out-=t,r.pending-=t,r.pending===0&&(r.pending_out=0))}function Y(e,r){pe._tr_flush_block(e,e.block_start>=0?e.block_start:-1,e.strstart-e.block_start,r),e.block_start=e.strstart,Ye(e.strm)}function B(e,r){e.pending_buf[e.pending++]=r}function Ht(e,r){e.pending_buf[e.pending++]=r>>>8&255,e.pending_buf[e.pending++]=r&255}function QE(e,r,t,n){var i=e.avail_in;return i>n&&(i=n),i===0?0:(e.avail_in-=i,ee.arraySet(r,e.input,e.next_in,i,t),e.state.wrap===1?e.adler=Up(e.adler,r,i,t):e.state.wrap===2&&(e.adler=Ve(e.adler,r,i,t)),e.next_in+=i,e.total_in+=i,i)}function Cp(e,r){var t=e.max_chain_length,n=e.strstart,i,a,o=e.prev_length,f=e.nice_match,s=e.strstart>e.w_size-Ee?e.strstart-(e.w_size-Ee):0,u=e.window,l=e.w_mask,c=e.prev,p=e.strstart+Xe,h=u[n+o-1],v=u[n+o];e.prev_length>=e.good_match&&(t>>=2),f>e.lookahead&&(f=e.lookahead);do if(i=r,!(u[i+o]!==v||u[i+o-1]!==h||u[i]!==u[n]||u[++i]!==u[n+1])){n+=2,i++;do;while(u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&u[++n]===u[++i]&&no){if(e.match_start=r,o=a,a>=f)break;h=u[n+o-1],v=u[n+o]}}while((r=c[r&l])>s&&--t!==0);return o<=e.lookahead?o:e.lookahead}function br(e){var r=e.w_size,t,n,i,a,o;do{if(a=e.window_size-e.lookahead-e.strstart,e.strstart>=r+(r-Ee)){ee.arraySet(e.window,e.window,r,r,0),e.match_start-=r,e.strstart-=r,e.block_start-=r,n=e.hash_size,t=n;do i=e.head[--t],e.head[t]=i>=r?i-r:0;while(--n);n=r,t=n;do i=e.prev[--t],e.prev[t]=i>=r?i-r:0;while(--n);a+=r}if(e.strm.avail_in===0)break;if(n=QE(e.strm,e.window,e.strstart+e.lookahead,a),e.lookahead+=n,e.lookahead+e.insert>=M)for(o=e.strstart-e.insert,e.ins_h=e.window[o],e.ins_h=(e.ins_h<e.pending_buf_size-5&&(t=e.pending_buf_size-5);;){if(e.lookahead<=1){if(br(e),e.lookahead===0&&r===wr)return H;if(e.lookahead===0)break}e.strstart+=e.lookahead,e.lookahead=0;var n=e.block_start+t;if((e.strstart===0||e.strstart>=n)&&(e.lookahead=e.strstart-n,e.strstart=n,Y(e,!1),e.strm.avail_out===0)||e.strstart-e.block_start>=e.w_size-Ee&&(Y(e,!1),e.strm.avail_out===0))return H}return e.insert=0,r===Qe?(Y(e,!0),e.strm.avail_out===0?gr:at):(e.strstart>e.block_start&&(Y(e,!1),e.strm.avail_out===0),H)}function qo(e,r){for(var t,n;;){if(e.lookahead=M&&(e.ins_h=(e.ins_h<=M)if(n=pe._tr_tally(e,e.strstart-e.match_start,e.match_length-M),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=M){e.match_length--;do e.strstart++,e.ins_h=(e.ins_h<=M&&(e.ins_h=(e.ins_h<4096)&&(e.match_length=M-1)),e.prev_length>=M&&e.match_length<=e.prev_length){i=e.strstart+e.lookahead-M,n=pe._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-M),e.lookahead-=e.prev_length-1,e.prev_length-=2;do++e.strstart<=i&&(e.ins_h=(e.ins_h<=M&&e.strstart>0&&(i=e.strstart-1,n=o[i],n===o[++i]&&n===o[++i]&&n===o[++i])){a=e.strstart+Xe;do;while(n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&n===o[++i]&&ie.lookahead&&(e.match_length=e.lookahead)}if(e.match_length>=M?(t=pe._tr_tally(e,1,e.match_length-M),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(t=pe._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),t&&(Y(e,!1),e.strm.avail_out===0))return H}return e.insert=0,r===Qe?(Y(e,!0),e.strm.avail_out===0?gr:at):e.last_lit&&(Y(e,!1),e.strm.avail_out===0)?H:$t}function tm(e,r){for(var t;;){if(e.lookahead===0&&(br(e),e.lookahead===0)){if(r===wr)return H;break}if(e.match_length=0,t=pe._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,t&&(Y(e,!1),e.strm.avail_out===0))return H}return e.insert=0,r===Qe?(Y(e,!0),e.strm.avail_out===0?gr:at):e.last_lit&&(Y(e,!1),e.strm.avail_out===0)?H:$t}function Ie(e,r,t,n,i){this.good_length=e,this.max_lazy=r,this.nice_length=t,this.max_chain=n,this.func=i}var it;it=[new Ie(0,0,0,0,em),new Ie(4,4,8,4,qo),new Ie(4,5,16,8,qo),new Ie(4,6,32,32,qo),new Ie(4,4,16,16,nt),new Ie(8,16,32,32,nt),new Ie(8,16,128,128,nt),new Ie(8,32,128,256,nt),new Ie(32,128,258,1024,nt),new Ie(32,258,258,4096,nt)];function nm(e){e.window_size=2*e.w_size,Ke(e.head),e.max_lazy_match=it[e.level].max_lazy,e.good_match=it[e.level].good_length,e.nice_match=it[e.level].nice_length,e.max_chain_length=it[e.level].max_chain,e.strstart=0,e.block_start=0,e.lookahead=0,e.insert=0,e.match_length=e.prev_length=M-1,e.match_available=0,e.ins_h=0}function im(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=Ii,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new ee.Buf16(YE*2),this.dyn_dtree=new ee.Buf16((2*$E+1)*2),this.bl_tree=new ee.Buf16((2*VE+1)*2),Ke(this.dyn_ltree),Ke(this.dyn_dtree),Ke(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new ee.Buf16(KE+1),this.heap=new ee.Buf16(2*Uo+1),Ke(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new ee.Buf16(2*Uo+1),Ke(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function zp(e){var r;return!e||!e.state?Je(e,de):(e.total_in=e.total_out=0,e.data_type=CE,r=e.state,r.pending=0,r.pending_out=0,r.wrap<0&&(r.wrap=-r.wrap),r.status=r.wrap?Ni:_r,e.adler=r.wrap===2?0:1,r.last_flush=wr,pe._tr_init(r),Ne)}function Zp(e){var r=zp(e);return r===Ne&&nm(e.state),r}function am(e,r){return!e||!e.state||e.state.wrap!==2?de:(e.state.gzhead=r,Ne)}function Wp(e,r,t,n,i,a){if(!e)return de;var o=1;if(r===ME&&(r=6),n<0?(o=0,n=-n):n>15&&(o=2,n-=16),i<1||i>zE||t!==Ii||n<8||n>15||r<0||r>9||a<0||a>qE)return Je(e,de);n===8&&(n=9);var f=new im;return e.state=f,f.strm=e,f.wrap=o,f.gzhead=null,f.w_bits=n,f.w_size=1<jp||r<0)return e?Je(e,de):de;if(n=e.state,!e.output||!e.input&&e.avail_in!==0||n.status===Gt&&r!==Qe)return Je(e,e.avail_out===0?Bo:de);if(n.strm=e,t=n.last_flush,n.last_flush=r,n.status===Ni)if(n.wrap===2)e.adler=0,B(n,31),B(n,139),B(n,8),n.gzhead?(B(n,(n.gzhead.text?1:0)+(n.gzhead.hcrc?2:0)+(n.gzhead.extra?4:0)+(n.gzhead.name?8:0)+(n.gzhead.comment?16:0)),B(n,n.gzhead.time&255),B(n,n.gzhead.time>>8&255),B(n,n.gzhead.time>>16&255),B(n,n.gzhead.time>>24&255),B(n,n.level===9?2:n.strategy>=Ai||n.level<2?4:0),B(n,n.gzhead.os&255),n.gzhead.extra&&n.gzhead.extra.length&&(B(n,n.gzhead.extra.length&255),B(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=Ve(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=Co):(B(n,0),B(n,0),B(n,0),B(n,0),B(n,0),B(n,n.level===9?2:n.strategy>=Ai||n.level<2?4:0),B(n,JE),n.status=_r);else{var o=Ii+(n.w_bits-8<<4)<<8,f=-1;n.strategy>=Ai||n.level<2?f=0:n.level<6?f=1:n.level===6?f=2:f=3,o|=f<<6,n.strstart!==0&&(o|=XE),o+=31-o%31,n.status=_r,Ht(n,o),n.strstart!==0&&(Ht(n,e.adler>>>16),Ht(n,e.adler&65535)),e.adler=1}if(n.status===Co)if(n.gzhead.extra){for(i=n.pending;n.gzindex<(n.gzhead.extra.length&65535)&&!(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),Ye(e),i=n.pending,n.pending===n.pending_buf_size));)B(n,n.gzhead.extra[n.gzindex]&255),n.gzindex++;n.gzhead.hcrc&&n.pending>i&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=Ri)}else n.status=Ri;if(n.status===Ri)if(n.gzhead.name){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),Ye(e),i=n.pending,n.pending===n.pending_buf_size)){a=1;break}n.gzindexi&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),a===0&&(n.gzindex=0,n.status=Oi)}else n.status=Oi;if(n.status===Oi)if(n.gzhead.comment){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),Ye(e),i=n.pending,n.pending===n.pending_buf_size)){a=1;break}n.gzindexi&&(e.adler=Ve(e.adler,n.pending_buf,n.pending-i,i)),a===0&&(n.status=Ti)}else n.status=Ti;if(n.status===Ti&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&Ye(e),n.pending+2<=n.pending_buf_size&&(B(n,e.adler&255),B(n,e.adler>>8&255),e.adler=0,n.status=_r)):n.status=_r),n.pending!==0){if(Ye(e),e.avail_out===0)return n.last_flush=-1,Ne}else if(e.avail_in===0&&qp(r)<=qp(t)&&r!==Qe)return Je(e,Bo);if(n.status===Gt&&e.avail_in!==0)return Je(e,Bo);if(e.avail_in!==0||n.lookahead!==0||r!==wr&&n.status!==Gt){var s=n.strategy===Ai?tm(n,r):n.strategy===BE?rm(n,r):it[n.level].func(n,r);if((s===gr||s===at)&&(n.status=Gt),s===H||s===gr)return e.avail_out===0&&(n.last_flush=-1),Ne;if(s===$t&&(r===kE?pe._tr_align(n):r!==jp&&(pe._tr_stored_block(n,0,0,!1),r===PE&&(Ke(n.head),n.lookahead===0&&(n.strstart=0,n.block_start=0,n.insert=0))),Ye(e),e.avail_out===0))return n.last_flush=-1,Ne}return r!==Qe?Ne:n.wrap<=0?Bp:(n.wrap===2?(B(n,e.adler&255),B(n,e.adler>>8&255),B(n,e.adler>>16&255),B(n,e.adler>>24&255),B(n,e.total_in&255),B(n,e.total_in>>8&255),B(n,e.total_in>>16&255),B(n,e.total_in>>24&255)):(Ht(n,e.adler>>>16),Ht(n,e.adler&65535)),Ye(e),n.wrap>0&&(n.wrap=-n.wrap),n.pending!==0?Ne:Bp)}function um(e){var r;return!e||!e.state?de:(r=e.state.status,r!==Ni&&r!==Co&&r!==Ri&&r!==Oi&&r!==Ti&&r!==_r&&r!==Gt?Je(e,de):(e.state=null,r===_r?Je(e,DE):Ne))}function lm(e,r){var t=r.length,n,i,a,o,f,s,u,l;if(!e||!e.state||(n=e.state,o=n.wrap,o===2||o===1&&n.status!==Ni||n.lookahead))return de;for(o===1&&(e.adler=Up(e.adler,r,t,0)),n.wrap=0,t>=n.w_size&&(o===0&&(Ke(n.head),n.strstart=0,n.block_start=0,n.insert=0),l=new ee.Buf8(n.w_size),ee.arraySet(l,r,t-n.w_size,n.w_size,0),r=l,t=n.w_size),f=e.avail_in,s=e.next_in,u=e.input,e.avail_in=t,e.next_in=0,e.input=r,br(n);n.lookahead>=M;){i=n.strstart,a=n.lookahead-(M-1);do n.ins_h=(n.ins_h<{"use strict";var Li=30,sm=12;Gp.exports=function(r,t){var n,i,a,o,f,s,u,l,c,p,h,v,_,m,w,L,A,T,b,R,I,S,D,W,O;n=r.state,i=r.next_in,W=r.input,a=i+(r.avail_in-5),o=r.next_out,O=r.output,f=o-(t-r.avail_out),s=o+(r.avail_out-257),u=n.dmax,l=n.wsize,c=n.whave,p=n.wnext,h=n.window,v=n.hold,_=n.bits,m=n.lencode,w=n.distcode,L=(1<>>24,v>>>=b,_-=b,b=T>>>16&255,b===0)O[o++]=T&65535;else if(b&16){R=T&65535,b&=15,b&&(_>>=b,_-=b),_<15&&(v+=W[i++]<<_,_+=8,v+=W[i++]<<_,_+=8),T=w[v&A];t:for(;;){if(b=T>>>24,v>>>=b,_-=b,b=T>>>16&255,b&16){if(I=T&65535,b&=15,_u){r.msg="invalid distance too far back",n.mode=Li;break e}if(v>>>=b,_-=b,b=o-f,I>b){if(b=I-b,b>c&&n.sane){r.msg="invalid distance too far back",n.mode=Li;break e}if(S=0,D=h,p===0){if(S+=l-b,b2;)O[o++]=D[S++],O[o++]=D[S++],O[o++]=D[S++],R-=3;R&&(O[o++]=D[S++],R>1&&(O[o++]=D[S++]))}else{S=o-I;do O[o++]=O[S++],O[o++]=O[S++],O[o++]=O[S++],R-=3;while(R>2);R&&(O[o++]=O[S++],R>1&&(O[o++]=O[S++]))}}else if((b&64)===0){T=w[(T&65535)+(v&(1<>3,i-=R,_-=R<<3,v&=(1<<_)-1,r.next_in=i,r.next_out=o,r.avail_in=i{"use strict";var Vp=Bt(),ot=15,Yp=852,Kp=592,Xp=0,zo=1,Jp=2,cm=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],hm=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,72,78],pm=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],dm=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];Qp.exports=function(r,t,n,i,a,o,f,s){var u=s.bits,l=0,c=0,p=0,h=0,v=0,_=0,m=0,w=0,L=0,A=0,T,b,R,I,S,D=null,W=0,O,ve=new Vp.Buf16(ot+1),Jt=new Vp.Buf16(ot+1),Qt=null,nf=0,af,en,rn;for(l=0;l<=ot;l++)ve[l]=0;for(c=0;c=1&&ve[h]===0;h--);if(v>h&&(v=h),h===0)return a[o++]=1<<24|64<<16|0,a[o++]=1<<24|64<<16|0,s.bits=1,0;for(p=1;p0&&(r===Xp||h!==1))return-1;for(Jt[1]=0,l=1;lYp||r===Jp&&L>Kp)return 1;for(;;){af=l-m,f[c]O?(en=Qt[nf+f[c]],rn=D[W+f[c]]):(en=96,rn=0),T=1<>m)+b]=af<<24|en<<16|rn|0;while(b!==0);for(T=1<>=1;if(T!==0?(A&=T-1,A+=T):A=0,c++,--ve[l]===0){if(l===h)break;l=t[n+f[c]]}if(l>v&&(A&I)!==R){for(m===0&&(m=v),S+=p,_=l-m,w=1<<_;_+mYp||r===Jp&&L>Kp)return 1;R=A&I,a[R]=v<<24|_<<16|S-o|0}}return A!==0&&(a[S+A]=l-m<<24|64<<16|0),s.bits=v,0}});var Dd=y(me=>{"use strict";var ae=Bt(),Vo=Mo(),Fe=jo(),ym=$p(),Vt=ed(),vm=0,Rd=1,Od=2,rd=4,_m=5,Fi=6,Er=0,gm=1,bm=2,ye=-2,Td=-3,Yo=-4,wm=-5,td=8,Id=1,nd=2,id=3,ad=4,od=5,fd=6,ud=7,ld=8,sd=9,cd=10,Di=11,je=12,Zo=13,hd=14,Wo=15,pd=16,dd=17,yd=18,vd=19,ki=20,Pi=21,_d=22,gd=23,bd=24,wd=25,Ed=26,Ho=27,md=28,Sd=29,C=30,Ko=31,Em=32,mm=852,Sm=592,xm=15,Am=xm;function xd(e){return(e>>>24&255)+(e>>>8&65280)+((e&65280)<<8)+((e&255)<<24)}function Rm(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new ae.Buf16(320),this.work=new ae.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function Nd(e){var r;return!e||!e.state?ye:(r=e.state,e.total_in=e.total_out=r.total=0,e.msg="",r.wrap&&(e.adler=r.wrap&1),r.mode=Id,r.last=0,r.havedict=0,r.dmax=32768,r.head=null,r.hold=0,r.bits=0,r.lencode=r.lendyn=new ae.Buf32(mm),r.distcode=r.distdyn=new ae.Buf32(Sm),r.sane=1,r.back=-1,Er)}function Ld(e){var r;return!e||!e.state?ye:(r=e.state,r.wsize=0,r.whave=0,r.wnext=0,Nd(e))}function Fd(e,r){var t,n;return!e||!e.state||(n=e.state,r<0?(t=0,r=-r):(t=(r>>4)+1,r<48&&(r&=15)),r&&(r<8||r>15))?ye:(n.window!==null&&n.wbits!==r&&(n.window=null),n.wrap=t,n.wbits=r,Ld(e))}function kd(e,r){var t,n;return e?(n=new Rm,e.state=n,n.window=null,t=Fd(e,r),t!==Er&&(e.state=null),t):ye}function Om(e){return kd(e,Am)}var Ad=!0,Go,$o;function Tm(e){if(Ad){var r;for(Go=new ae.Buf32(512),$o=new ae.Buf32(32),r=0;r<144;)e.lens[r++]=8;for(;r<256;)e.lens[r++]=9;for(;r<280;)e.lens[r++]=7;for(;r<288;)e.lens[r++]=8;for(Vt(Rd,e.lens,0,288,Go,0,e.work,{bits:9}),r=0;r<32;)e.lens[r++]=5;Vt(Od,e.lens,0,32,$o,0,e.work,{bits:5}),Ad=!1}e.lencode=Go,e.lenbits=9,e.distcode=$o,e.distbits=5}function Pd(e,r,t,n){var i,a=e.state;return a.window===null&&(a.wsize=1<=a.wsize?(ae.arraySet(a.window,r,t-a.wsize,a.wsize,0),a.wnext=0,a.whave=a.wsize):(i=a.wsize-a.wnext,i>n&&(i=n),ae.arraySet(a.window,r,t-n,i,a.wnext),n-=i,n?(ae.arraySet(a.window,r,t-n,n,0),a.wnext=n,a.whave=a.wsize):(a.wnext+=i,a.wnext===a.wsize&&(a.wnext=0),a.whave>>8&255,t.check=Fe(t.check,D,2,0),u=0,l=0,t.mode=nd;break}if(t.flags=0,t.head&&(t.head.done=!1),!(t.wrap&1)||(((u&255)<<8)+(u>>8))%31){e.msg="incorrect header check",t.mode=C;break}if((u&15)!==td){e.msg="unknown compression method",t.mode=C;break}if(u>>>=4,l-=4,I=(u&15)+8,t.wbits===0)t.wbits=I;else if(I>t.wbits){e.msg="invalid window size",t.mode=C;break}t.dmax=1<>8&1),t.flags&512&&(D[0]=u&255,D[1]=u>>>8&255,t.check=Fe(t.check,D,2,0)),u=0,l=0,t.mode=id;case id:for(;l<32;){if(f===0)break e;f--,u+=n[a++]<>>8&255,D[2]=u>>>16&255,D[3]=u>>>24&255,t.check=Fe(t.check,D,4,0)),u=0,l=0,t.mode=ad;case ad:for(;l<16;){if(f===0)break e;f--,u+=n[a++]<>8),t.flags&512&&(D[0]=u&255,D[1]=u>>>8&255,t.check=Fe(t.check,D,2,0)),u=0,l=0,t.mode=od;case od:if(t.flags&1024){for(;l<16;){if(f===0)break e;f--,u+=n[a++]<>>8&255,t.check=Fe(t.check,D,2,0)),u=0,l=0}else t.head&&(t.head.extra=null);t.mode=fd;case fd:if(t.flags&1024&&(h=t.length,h>f&&(h=f),h&&(t.head&&(I=t.head.extra_len-t.length,t.head.extra||(t.head.extra=new Array(t.head.extra_len)),ae.arraySet(t.head.extra,n,a,h,I)),t.flags&512&&(t.check=Fe(t.check,n,h,a)),f-=h,a+=h,t.length-=h),t.length))break e;t.length=0,t.mode=ud;case ud:if(t.flags&2048){if(f===0)break e;h=0;do I=n[a+h++],t.head&&I&&t.length<65536&&(t.head.name+=String.fromCharCode(I));while(I&&h>9&1,t.head.done=!0),e.adler=t.check=0,t.mode=je;break;case cd:for(;l<32;){if(f===0)break e;f--,u+=n[a++]<>>=l&7,l-=l&7,t.mode=Ho;break}for(;l<3;){if(f===0)break e;f--,u+=n[a++]<>>=1,l-=1,u&3){case 0:t.mode=hd;break;case 1:if(Tm(t),t.mode=ki,r===Fi){u>>>=2,l-=2;break e}break;case 2:t.mode=dd;break;case 3:e.msg="invalid block type",t.mode=C}u>>>=2,l-=2;break;case hd:for(u>>>=l&7,l-=l&7;l<32;){if(f===0)break e;f--,u+=n[a++]<>>16^65535)){e.msg="invalid stored block lengths",t.mode=C;break}if(t.length=u&65535,u=0,l=0,t.mode=Wo,r===Fi)break e;case Wo:t.mode=pd;case pd:if(h=t.length,h){if(h>f&&(h=f),h>s&&(h=s),h===0)break e;ae.arraySet(i,n,a,h,o),f-=h,a+=h,s-=h,o+=h,t.length-=h;break}t.mode=je;break;case dd:for(;l<14;){if(f===0)break e;f--,u+=n[a++]<>>=5,l-=5,t.ndist=(u&31)+1,u>>>=5,l-=5,t.ncode=(u&15)+4,u>>>=4,l-=4,t.nlen>286||t.ndist>30){e.msg="too many length or distance symbols",t.mode=C;break}t.have=0,t.mode=yd;case yd:for(;t.have>>=3,l-=3}for(;t.have<19;)t.lens[ve[t.have++]]=0;if(t.lencode=t.lendyn,t.lenbits=7,W={bits:t.lenbits},S=Vt(vm,t.lens,0,19,t.lencode,0,t.work,W),t.lenbits=W.bits,S){e.msg="invalid code lengths set",t.mode=C;break}t.have=0,t.mode=vd;case vd:for(;t.have>>24,L=m>>>16&255,A=m&65535,!(w<=l);){if(f===0)break e;f--,u+=n[a++]<>>=w,l-=w,t.lens[t.have++]=A;else{if(A===16){for(O=w+2;l>>=w,l-=w,t.have===0){e.msg="invalid bit length repeat",t.mode=C;break}I=t.lens[t.have-1],h=3+(u&3),u>>>=2,l-=2}else if(A===17){for(O=w+3;l>>=w,l-=w,I=0,h=3+(u&7),u>>>=3,l-=3}else{for(O=w+7;l>>=w,l-=w,I=0,h=11+(u&127),u>>>=7,l-=7}if(t.have+h>t.nlen+t.ndist){e.msg="invalid bit length repeat",t.mode=C;break}for(;h--;)t.lens[t.have++]=I}}if(t.mode===C)break;if(t.lens[256]===0){e.msg="invalid code -- missing end-of-block",t.mode=C;break}if(t.lenbits=9,W={bits:t.lenbits},S=Vt(Rd,t.lens,0,t.nlen,t.lencode,0,t.work,W),t.lenbits=W.bits,S){e.msg="invalid literal/lengths set",t.mode=C;break}if(t.distbits=6,t.distcode=t.distdyn,W={bits:t.distbits},S=Vt(Od,t.lens,t.nlen,t.ndist,t.distcode,0,t.work,W),t.distbits=W.bits,S){e.msg="invalid distances set",t.mode=C;break}if(t.mode=ki,r===Fi)break e;case ki:t.mode=Pi;case Pi:if(f>=6&&s>=258){e.next_out=o,e.avail_out=s,e.next_in=a,e.avail_in=f,t.hold=u,t.bits=l,ym(e,p),o=e.next_out,i=e.output,s=e.avail_out,a=e.next_in,n=e.input,f=e.avail_in,u=t.hold,l=t.bits,t.mode===je&&(t.back=-1);break}for(t.back=0;m=t.lencode[u&(1<>>24,L=m>>>16&255,A=m&65535,!(w<=l);){if(f===0)break e;f--,u+=n[a++]<>T)],w=m>>>24,L=m>>>16&255,A=m&65535,!(T+w<=l);){if(f===0)break e;f--,u+=n[a++]<>>=T,l-=T,t.back+=T}if(u>>>=w,l-=w,t.back+=w,t.length=A,L===0){t.mode=Ed;break}if(L&32){t.back=-1,t.mode=je;break}if(L&64){e.msg="invalid literal/length code",t.mode=C;break}t.extra=L&15,t.mode=_d;case _d:if(t.extra){for(O=t.extra;l>>=t.extra,l-=t.extra,t.back+=t.extra}t.was=t.length,t.mode=gd;case gd:for(;m=t.distcode[u&(1<>>24,L=m>>>16&255,A=m&65535,!(w<=l);){if(f===0)break e;f--,u+=n[a++]<>T)],w=m>>>24,L=m>>>16&255,A=m&65535,!(T+w<=l);){if(f===0)break e;f--,u+=n[a++]<>>=T,l-=T,t.back+=T}if(u>>>=w,l-=w,t.back+=w,L&64){e.msg="invalid distance code",t.mode=C;break}t.offset=A,t.extra=L&15,t.mode=bd;case bd:if(t.extra){for(O=t.extra;l>>=t.extra,l-=t.extra,t.back+=t.extra}if(t.offset>t.dmax){e.msg="invalid distance too far back",t.mode=C;break}t.mode=wd;case wd:if(s===0)break e;if(h=p-s,t.offset>h){if(h=t.offset-h,h>t.whave&&t.sane){e.msg="invalid distance too far back",t.mode=C;break}h>t.wnext?(h-=t.wnext,v=t.wsize-h):v=t.wnext-h,h>t.length&&(h=t.length),_=t.window}else _=i,v=o-t.offset,h=t.length;h>s&&(h=s),s-=h,t.length-=h;do i[o++]=_[v++];while(--h);t.length===0&&(t.mode=Pi);break;case Ed:if(s===0)break e;i[o++]=t.length,s--,t.mode=Pi;break;case Ho:if(t.wrap){for(;l<32;){if(f===0)break e;f--,u|=n[a++]<{"use strict";Md.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}});var qd=y(g=>{"use strict";var oe=Wr(),km=lp(),Yt=Hp(),mr=Dd(),Bd=jd();for(Xo in Bd)g[Xo]=Bd[Xo];var Xo;g.NONE=0;g.DEFLATE=1;g.INFLATE=2;g.GZIP=3;g.GUNZIP=4;g.DEFLATERAW=5;g.INFLATERAW=6;g.UNZIP=7;var Pm=31,Dm=139;function X(e){if(typeof e!="number"||eg.UNZIP)throw new TypeError("Bad argument");this.dictionary=null,this.err=0,this.flush=0,this.init_done=!1,this.level=0,this.memLevel=0,this.mode=e,this.strategy=0,this.windowBits=0,this.write_in_progress=!1,this.pending_close=!1,this.gzip_id_bytes_read=0}X.prototype.close=function(){if(this.write_in_progress){this.pending_close=!0;return}this.pending_close=!1,oe(this.init_done,"close before init"),oe(this.mode<=g.UNZIP),this.mode===g.DEFLATE||this.mode===g.GZIP||this.mode===g.DEFLATERAW?Yt.deflateEnd(this.strm):(this.mode===g.INFLATE||this.mode===g.GUNZIP||this.mode===g.INFLATERAW||this.mode===g.UNZIP)&&mr.inflateEnd(this.strm),this.mode=g.NONE,this.dictionary=null};X.prototype.write=function(e,r,t,n,i,a,o){return this._write(!0,e,r,t,n,i,a,o)};X.prototype.writeSync=function(e,r,t,n,i,a,o){return this._write(!1,e,r,t,n,i,a,o)};X.prototype._write=function(e,r,t,n,i,a,o,f){if(oe.equal(arguments.length,8),oe(this.init_done,"write before init"),oe(this.mode!==g.NONE,"already finalized"),oe.equal(!1,this.write_in_progress,"write already in progress"),oe.equal(!1,this.pending_close,"close is pending"),this.write_in_progress=!0,oe.equal(!1,r===void 0,"must provide flush value"),this.write_in_progress=!0,r!==g.Z_NO_FLUSH&&r!==g.Z_PARTIAL_FLUSH&&r!==g.Z_SYNC_FLUSH&&r!==g.Z_FULL_FLUSH&&r!==g.Z_FINISH&&r!==g.Z_BLOCK)throw new Error("Invalid flush value");if(t==null&&(t=Buffer.alloc(0),i=0,n=0),this.strm.avail_in=i,this.strm.input=t,this.strm.next_in=n,this.strm.avail_out=f,this.strm.output=a,this.strm.next_out=o,this.flush=r,!e)return this._process(),this._checkError()?this._afterSync():void 0;var s=this;return process.nextTick(function(){s._process(),s._after()}),this};X.prototype._afterSync=function(){var e=this.strm.avail_out,r=this.strm.avail_in;return this.write_in_progress=!1,[r,e]};X.prototype._process=function(){var e=null;switch(this.mode){case g.DEFLATE:case g.GZIP:case g.DEFLATERAW:this.err=Yt.deflate(this.strm,this.flush);break;case g.UNZIP:switch(this.strm.avail_in>0&&(e=this.strm.next_in),this.gzip_id_bytes_read){case 0:if(e===null)break;if(this.strm.input[e]===Pm){if(this.gzip_id_bytes_read=1,e++,this.strm.avail_in===1)break}else{this.mode=g.INFLATE;break}case 1:if(e===null)break;this.strm.input[e]===Dm?(this.gzip_id_bytes_read=2,this.mode=g.GUNZIP):this.mode=g.INFLATE;break;default:throw new Error("invalid number of gzip magic number bytes read")}case g.INFLATE:case g.GUNZIP:case g.INFLATERAW:for(this.err=mr.inflate(this.strm,this.flush),this.err===g.Z_NEED_DICT&&this.dictionary&&(this.err=mr.inflateSetDictionary(this.strm,this.dictionary),this.err===g.Z_OK?this.err=mr.inflate(this.strm,this.flush):this.err===g.Z_DATA_ERROR&&(this.err=g.Z_NEED_DICT));this.strm.avail_in>0&&this.mode===g.GUNZIP&&this.err===g.Z_STREAM_END&&this.strm.next_in[0]!==0;)this.reset(),this.err=mr.inflate(this.strm,this.flush);break;default:throw new Error("Unknown mode "+this.mode)}};X.prototype._checkError=function(){switch(this.err){case g.Z_OK:case g.Z_BUF_ERROR:if(this.strm.avail_out!==0&&this.flush===g.Z_FINISH)return this._error("unexpected end of file"),!1;break;case g.Z_STREAM_END:break;case g.Z_NEED_DICT:return this.dictionary==null?this._error("Missing dictionary"):this._error("Bad dictionary"),!1;default:return this._error("Zlib error"),!1}return!0};X.prototype._after=function(){if(this._checkError()){var e=this.strm.avail_out,r=this.strm.avail_in;this.write_in_progress=!1,this.callback(r,e),this.pending_close&&this.close()}};X.prototype._error=function(e){this.strm.msg&&(e=this.strm.msg),this.onerror(e,this.err),this.write_in_progress=!1,this.pending_close&&this.close()};X.prototype.init=function(e,r,t,n,i){oe(arguments.length===4||arguments.length===5,"init(windowBits, level, memLevel, strategy, [dictionary])"),oe(e>=8&&e<=15,"invalid windowBits"),oe(r>=-1&&r<=9,"invalid compression level"),oe(t>=1&&t<=9,"invalid memlevel"),oe(n===g.Z_FILTERED||n===g.Z_HUFFMAN_ONLY||n===g.Z_RLE||n===g.Z_FIXED||n===g.Z_DEFAULT_STRATEGY,"invalid strategy"),this._init(r,e,t,n,i),this._setDictionary()};X.prototype.params=function(){throw new Error("deflateParams Not supported")};X.prototype.reset=function(){this._reset(),this._setDictionary()};X.prototype._init=function(e,r,t,n,i){switch(this.level=e,this.windowBits=r,this.memLevel=t,this.strategy=n,this.flush=g.Z_NO_FLUSH,this.err=g.Z_OK,(this.mode===g.GZIP||this.mode===g.GUNZIP)&&(this.windowBits+=16),this.mode===g.UNZIP&&(this.windowBits+=32),(this.mode===g.DEFLATERAW||this.mode===g.INFLATERAW)&&(this.windowBits=-1*this.windowBits),this.strm=new km,this.mode){case g.DEFLATE:case g.GZIP:case g.DEFLATERAW:this.err=Yt.deflateInit2(this.strm,this.level,g.Z_DEFLATED,this.windowBits,this.memLevel,this.strategy);break;case g.INFLATE:case g.GUNZIP:case g.INFLATERAW:case g.UNZIP:this.err=mr.inflateInit2(this.strm,this.windowBits);break;default:throw new Error("Unknown mode "+this.mode)}this.err!==g.Z_OK&&this._error("Init error"),this.dictionary=i,this.write_in_progress=!1,this.init_done=!0};X.prototype._setDictionary=function(){if(this.dictionary!=null){switch(this.err=g.Z_OK,this.mode){case g.DEFLATE:case g.DEFLATERAW:this.err=Yt.deflateSetDictionary(this.strm,this.dictionary);break;default:break}this.err!==g.Z_OK&&this._error("Failed to set dictionary")}};X.prototype._reset=function(){switch(this.err=g.Z_OK,this.mode){case g.DEFLATE:case g.DEFLATERAW:case g.GZIP:this.err=Yt.deflateReset(this.strm);break;case g.INFLATE:case g.INFLATERAW:case g.GUNZIP:this.err=mr.inflateReset(this.strm);break;default:break}this.err!==g.Z_OK&&this._error("Failed to reset stream")};g.Zlib=X});var Hd=y(E=>{"use strict";var ke=lr().Buffer,Zd=(fp(),Qd(K)).Transform,x=qd(),er=Se(),Kt=Wr().ok,Qo=lr().kMaxLength,Wd="Cannot create final Buffer. It would be larger than 0x"+Qo.toString(16)+" bytes";x.Z_MIN_WINDOWBITS=8;x.Z_MAX_WINDOWBITS=15;x.Z_DEFAULT_WINDOWBITS=15;x.Z_MIN_CHUNK=64;x.Z_MAX_CHUNK=1/0;x.Z_DEFAULT_CHUNK=16*1024;x.Z_MIN_MEMLEVEL=1;x.Z_MAX_MEMLEVEL=9;x.Z_DEFAULT_MEMLEVEL=8;x.Z_MIN_LEVEL=-1;x.Z_MAX_LEVEL=9;x.Z_DEFAULT_LEVEL=x.Z_DEFAULT_COMPRESSION;var Ud=Object.keys(x);for(Mi=0;Mi=Qo?u=new RangeError(Wd):s=ke.concat(n,i),n=[],e.close(),t(u,s)}}function Lr(e,r){if(typeof r=="string"&&(r=ke.from(r)),!ke.isBuffer(r))throw new TypeError("Not a string or buffer");var t=e._finishFlushFlag;return e._processChunk(r,t)}function Sr(e){if(!(this instanceof Sr))return new Sr(e);Z.call(this,e,x.DEFLATE)}function xr(e){if(!(this instanceof xr))return new xr(e);Z.call(this,e,x.INFLATE)}function Ar(e){if(!(this instanceof Ar))return new Ar(e);Z.call(this,e,x.GZIP)}function Rr(e){if(!(this instanceof Rr))return new Rr(e);Z.call(this,e,x.GUNZIP)}function Or(e){if(!(this instanceof Or))return new Or(e);Z.call(this,e,x.DEFLATERAW)}function Tr(e){if(!(this instanceof Tr))return new Tr(e);Z.call(this,e,x.INFLATERAW)}function Ir(e){if(!(this instanceof Ir))return new Ir(e);Z.call(this,e,x.UNZIP)}function zd(e){return e===x.Z_NO_FLUSH||e===x.Z_PARTIAL_FLUSH||e===x.Z_SYNC_FLUSH||e===x.Z_FULL_FLUSH||e===x.Z_FINISH||e===x.Z_BLOCK}function Z(e,r){var t=this;if(this._opts=e=e||{},this._chunkSize=e.chunkSize||E.Z_DEFAULT_CHUNK,Zd.call(this,e),e.flush&&!zd(e.flush))throw new Error("Invalid flush flag: "+e.flush);if(e.finishFlush&&!zd(e.finishFlush))throw new Error("Invalid flush flag: "+e.finishFlush);if(this._flushFlag=e.flush||x.Z_NO_FLUSH,this._finishFlushFlag=typeof e.finishFlush<"u"?e.finishFlush:x.Z_FINISH,e.chunkSize&&(e.chunkSizeE.Z_MAX_CHUNK))throw new Error("Invalid chunk size: "+e.chunkSize);if(e.windowBits&&(e.windowBitsE.Z_MAX_WINDOWBITS))throw new Error("Invalid windowBits: "+e.windowBits);if(e.level&&(e.levelE.Z_MAX_LEVEL))throw new Error("Invalid compression level: "+e.level);if(e.memLevel&&(e.memLevelE.Z_MAX_MEMLEVEL))throw new Error("Invalid memLevel: "+e.memLevel);if(e.strategy&&e.strategy!=E.Z_FILTERED&&e.strategy!=E.Z_HUFFMAN_ONLY&&e.strategy!=E.Z_RLE&&e.strategy!=E.Z_FIXED&&e.strategy!=E.Z_DEFAULT_STRATEGY)throw new Error("Invalid strategy: "+e.strategy);if(e.dictionary&&!ke.isBuffer(e.dictionary))throw new Error("Invalid dictionary: it should be a Buffer instance");this._handle=new x.Zlib(r);var n=this;this._hadError=!1,this._handle.onerror=function(o,f){Ui(n),n._hadError=!0;var s=new Error(o);s.errno=f,s.code=E.codes[f],n.emit("error",s)};var i=E.Z_DEFAULT_COMPRESSION;typeof e.level=="number"&&(i=e.level);var a=E.Z_DEFAULT_STRATEGY;typeof e.strategy=="number"&&(a=e.strategy),this._handle.init(e.windowBits||E.Z_DEFAULT_WINDOWBITS,i,e.memLevel||E.Z_DEFAULT_MEMLEVEL,a,e.dictionary),this._buffer=ke.allocUnsafe(this._chunkSize),this._offset=0,this._level=i,this._strategy=a,this.once("end",this.close),Object.defineProperty(this,"_closed",{get:function(){return!t._handle},configurable:!0,enumerable:!0})}er.inherits(Z,Zd);Z.prototype.params=function(e,r,t){if(eE.Z_MAX_LEVEL)throw new RangeError("Invalid compression level: "+e);if(r!=E.Z_FILTERED&&r!=E.Z_HUFFMAN_ONLY&&r!=E.Z_RLE&&r!=E.Z_FIXED&&r!=E.Z_DEFAULT_STRATEGY)throw new TypeError("Invalid strategy: "+r);if(this._level!==e||this._strategy!==r){var n=this;this.flush(x.Z_SYNC_FLUSH,function(){Kt(n._handle,"zlib binding closed"),n._handle.params(e,r),n._hadError||(n._level=e,n._strategy=r,t&&t())})}else process.nextTick(t)};Z.prototype.reset=function(){return Kt(this._handle,"zlib binding closed"),this._handle.reset()};Z.prototype._flush=function(e){this._transform(ke.alloc(0),"",e)};Z.prototype.flush=function(e,r){var t=this,n=this._writableState;(typeof e=="function"||e===void 0&&!r)&&(r=e,e=x.Z_FULL_FLUSH),n.ended?r&&process.nextTick(r):n.ending?r&&this.once("end",r):n.needDrain?r&&this.once("drain",function(){return t.flush(e,r)}):(this._flushFlag=e,this.write(ke.alloc(0),"",r))};Z.prototype.close=function(e){Ui(this,e),process.nextTick(Mm,this)};function Ui(e,r){r&&process.nextTick(r),e._handle&&(e._handle.close(),e._handle=null)}function Mm(e){e.emit("close")}Z.prototype._transform=function(e,r,t){var n,i=this._writableState,a=i.ending||i.ended,o=a&&(!e||i.length===e.length);if(e!==null&&!ke.isBuffer(e))return t(new Error("invalid input"));if(!this._handle)return t(new Error("zlib binding closed"));o?n=this._finishFlushFlag:(n=this._flushFlag,e.length>=i.length&&(this._flushFlag=this._opts.flush||x.Z_NO_FLUSH)),this._processChunk(e,n,t)};Z.prototype._processChunk=function(e,r,t){var n=e&&e.length,i=this._chunkSize-this._offset,a=0,o=this,f=typeof t=="function";if(!f){var s=[],u=0,l;this.on("error",function(_){l=_}),Kt(this._handle,"zlib binding closed");do var c=this._handle.writeSync(r,e,a,n,this._buffer,this._offset,i);while(!this._hadError&&v(c[0],c[1]));if(this._hadError)throw l;if(u>=Qo)throw Ui(this),new RangeError(Wd);var p=ke.concat(s,u);return Ui(this),p}Kt(this._handle,"zlib binding closed");var h=this._handle.write(r,e,a,n,this._buffer,this._offset,i);h.buffer=e,h.callback=v;function v(_,m){if(this&&(this.buffer=null,this.callback=null),!o._hadError){var w=i-m;if(Kt(w>=0,"have should not go down"),w>0){var L=o._buffer.slice(o._offset,o._offset+w);o._offset+=w,f?o.push(L):(s.push(L),u+=L.length)}if((m===0||o._offset>=o._chunkSize)&&(i=o._chunkSize,o._offset=0,o._buffer=ke.allocUnsafe(o._chunkSize)),m===0){if(a+=n-_,n=_,!f)return!0;var A=o._handle.write(r,e,a,n,o._buffer,o._offset,o._chunkSize);A.callback=v,A.buffer=e;return}if(!f)return!1;t()}}};er.inherits(Sr,Z);er.inherits(xr,Z);er.inherits(Ar,Z);er.inherits(Rr,Z);er.inherits(Or,Z);er.inherits(Tr,Z);er.inherits(Ir,Z)});var ef=ft(Wr()),rf=ft(Se()),tf=ft(Hd()),jm=ef.default??ef,Xt=rf.default??rf,Fr=tf.default??tf,Bm=typeof Fr.constants=="object"&&Fr.constants!==null?Fr.constants:Object.fromEntries(Object.entries(Fr).filter(([e,r])=>/^[A-Z0-9_]+$/.test(e)&&typeof r=="number"));typeof Fr.constants>"u"&&(Fr.constants=Bm);typeof Xt.TextEncoder>"u"&&typeof globalThis.TextEncoder=="function"&&(Xt.TextEncoder=globalThis.TextEncoder);typeof Xt.TextDecoder>"u"&&typeof globalThis.TextDecoder=="function"&&(Xt.TextDecoder=globalThis.TextDecoder);globalThis.__secureExecBuiltinAssertModule=jm;globalThis.__secureExecBuiltinUtilModule=Xt;globalThis.__secureExecBuiltinZlibModule=Fr;})(); -/*! Bundled license information: - -assert/build/internal/util/comparisons.js: - (*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) - -ieee754/index.js: - (*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh *) - -buffer/index.js: - (*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) - -safe-buffer/index.js: - (*! safe-buffer. MIT License. Feross Aboukhadijeh *) -*/ diff --git a/crates/v8-runtime/assets/generated/v8-bridge.js b/crates/v8-runtime/assets/generated/v8-bridge.js deleted file mode 100644 index ae2dc65cb..000000000 --- a/crates/v8-runtime/assets/generated/v8-bridge.js +++ /dev/null @@ -1,229 +0,0 @@ -if(typeof globalThis.global==="undefined"){globalThis.global=globalThis;}if(typeof globalThis.process==="undefined"){globalThis.process={env:{},argv:["node"],browser:false,version:"v22.0.0",versions:{node:"22.0.0"},nextTick(callback,...args){return Promise.resolve().then(()=>callback(...args));}};} -(()=>{var Ca=Object.create;var lr=Object.defineProperty;var Ta=Object.getOwnPropertyDescriptor;var Pa=Object.getOwnPropertyNames;var va=Object.getPrototypeOf,Ea=Object.prototype.hasOwnProperty;var qa=(b,s,l)=>s in b?lr(b,s,{enumerable:!0,configurable:!0,writable:!0,value:l}):b[s]=l;var Wa=(b,s)=>()=>(s||b((s={exports:{}}).exports,s),s.exports);var Aa=(b,s,l,g)=>{if(s&&typeof s=="object"||typeof s=="function")for(let c of Pa(s))!Ea.call(b,c)&&c!==l&&lr(b,c,{get:()=>s[c],enumerable:!(g=Ta(s,c))||g.enumerable});return b};var ka=(b,s,l)=>(l=b!=null?Ca(va(b)):{},Aa(s||!b||!b.__esModule?lr(l,"default",{value:b,enumerable:!0}):l,b));var L=(b,s,l)=>qa(b,typeof s!="symbol"?s+"":s,l);var kn=Wa((St,An)=>{(function(b,s){typeof St=="object"&&typeof An<"u"?s(St):typeof define=="function"&&define.amd?define(["exports"],s):(b=typeof globalThis<"u"?globalThis:b||self,s(b.WebStreamsPolyfill={}))})(St,(function(b){"use strict";function s(){}function l(e){return typeof e=="object"&&e!==null||typeof e=="function"}let g=s;function c(e,t){try{Object.defineProperty(e,"name",{value:t,configurable:!0})}catch{}}let pe=Promise,ur=Promise.prototype.then,ie=Promise.reject.bind(pe);function R(e){return new pe(e)}function p(e){return R(t=>t(e))}function d(e){return ie(e)}function I(e,t,r){return ur.call(e,t,r)}function T(e,t,r){I(I(e,t,r),void 0,g)}function Be(e,t){T(e,t)}function gt(e,t){T(e,void 0,t)}function M(e,t,r){return I(e,t,r)}function ye(e){I(e,void 0,g)}let se=e=>{if(typeof queueMicrotask=="function")se=queueMicrotask;else{let t=p(void 0);se=r=>I(t,r)}return se(e)};function le(e,t,r){if(typeof e!="function")throw new TypeError("Argument is not a function");return Function.prototype.apply.call(e,t,r)}function Z(e,t,r){try{return p(le(e,t,r))}catch(n){return d(n)}}let dr=16384;class W{constructor(){this._cursor=0,this._size=0,this._front={_elements:[],_next:void 0},this._back=this._front,this._cursor=0,this._size=0}get length(){return this._size}push(t){let r=this._back,n=r;r._elements.length===dr-1&&(n={_elements:[],_next:void 0}),r._elements.push(t),n!==r&&(this._back=n,r._next=n),++this._size}shift(){let t=this._front,r=t,n=this._cursor,o=n+1,a=t._elements,i=a[n];return o===dr&&(r=t._next,o=0),--this._size,this._cursor=o,t!==r&&(this._front=r),a[n]=void 0,i}forEach(t){let r=this._cursor,n=this._front,o=n._elements;for(;(r!==o.length||n._next!==void 0)&&!(r===o.length&&(n=n._next,o=n._elements,r=0,o.length===0));)t(o[r]),++r}peek(){let t=this._front,r=this._cursor;return t._elements[r]}}let fr=Symbol("[[AbortSteps]]"),cr=Symbol("[[ErrorSteps]]"),Rt=Symbol("[[CancelSteps]]"),wt=Symbol("[[PullSteps]]"),Ct=Symbol("[[ReleaseSteps]]");function hr(e,t){e._ownerReadableStream=t,t._reader=e,t._state==="readable"?Pt(e):t._state==="closed"?Bn(e):br(e,t._storedError)}function Tt(e,t){let r=e._ownerReadableStream;return j(r,t)}function $(e){let t=e._ownerReadableStream;t._state==="readable"?vt(e,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")):In(e,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")),t._readableStreamController[Ct](),t._reader=void 0,e._ownerReadableStream=void 0}function Ne(e){return new TypeError("Cannot "+e+" a stream using a released reader")}function Pt(e){e._closedPromise=R((t,r)=>{e._closedPromise_resolve=t,e._closedPromise_reject=r})}function br(e,t){Pt(e),vt(e,t)}function Bn(e){Pt(e),mr(e)}function vt(e,t){e._closedPromise_reject!==void 0&&(ye(e._closedPromise),e._closedPromise_reject(t),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0)}function In(e,t){br(e,t)}function mr(e){e._closedPromise_resolve!==void 0&&(e._closedPromise_resolve(void 0),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0)}let _r=Number.isFinite||function(e){return typeof e=="number"&&isFinite(e)},On=Math.trunc||function(e){return e<0?Math.ceil(e):Math.floor(e)};function jn(e){return typeof e=="object"||typeof e=="function"}function F(e,t){if(e!==void 0&&!jn(e))throw new TypeError(`${t} is not an object.`)}function A(e,t){if(typeof e!="function")throw new TypeError(`${t} is not a function.`)}function zn(e){return typeof e=="object"&&e!==null||typeof e=="function"}function pr(e,t){if(!zn(e))throw new TypeError(`${t} is not an object.`)}function U(e,t,r){if(e===void 0)throw new TypeError(`Parameter ${t} is required in '${r}'.`)}function Et(e,t,r){if(e===void 0)throw new TypeError(`${t} is required in '${r}'.`)}function qt(e){return Number(e)}function yr(e){return e===0?0:e}function Fn(e){return yr(On(e))}function Wt(e,t){let n=Number.MAX_SAFE_INTEGER,o=Number(e);if(o=yr(o),!_r(o))throw new TypeError(`${t} is not a finite number`);if(o=Fn(o),o<0||o>n)throw new TypeError(`${t} is outside the accepted range of 0 to ${n}, inclusive`);return!_r(o)||o===0?0:o}function At(e,t){if(!re(e))throw new TypeError(`${t} is not a ReadableStream.`)}function Se(e){return new X(e)}function Sr(e,t){e._reader._readRequests.push(t)}function kt(e,t,r){let o=e._reader._readRequests.shift();r?o._closeSteps():o._chunkSteps(t)}function Qe(e){return e._reader._readRequests.length}function gr(e){let t=e._reader;return!(t===void 0||!J(t))}class X{constructor(t){if(U(t,1,"ReadableStreamDefaultReader"),At(t,"First parameter"),ne(t))throw new TypeError("This stream has already been locked for exclusive reading by another reader");hr(this,t),this._readRequests=new W}get closed(){return J(this)?this._closedPromise:d(Ye("closed"))}cancel(t=void 0){return J(this)?this._ownerReadableStream===void 0?d(Ne("cancel")):Tt(this,t):d(Ye("cancel"))}read(){if(!J(this))return d(Ye("read"));if(this._ownerReadableStream===void 0)return d(Ne("read from"));let t,r,n=R((a,i)=>{t=a,r=i});return Ie(this,{_chunkSteps:a=>t({value:a,done:!1}),_closeSteps:()=>t({value:void 0,done:!0}),_errorSteps:a=>r(a)}),n}releaseLock(){if(!J(this))throw Ye("releaseLock");this._ownerReadableStream!==void 0&&Dn(this)}}Object.defineProperties(X.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),c(X.prototype.cancel,"cancel"),c(X.prototype.read,"read"),c(X.prototype.releaseLock,"releaseLock"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(X.prototype,Symbol.toStringTag,{value:"ReadableStreamDefaultReader",configurable:!0});function J(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_readRequests")?!1:e instanceof X}function Ie(e,t){let r=e._ownerReadableStream;r._disturbed=!0,r._state==="closed"?t._closeSteps():r._state==="errored"?t._errorSteps(r._storedError):r._readableStreamController[wt](t)}function Dn(e){$(e);let t=new TypeError("Reader was released");Rr(e,t)}function Rr(e,t){let r=e._readRequests;e._readRequests=new W,r.forEach(n=>{n._errorSteps(t)})}function Ye(e){return new TypeError(`ReadableStreamDefaultReader.prototype.${e} can only be used on a ReadableStreamDefaultReader`)}let Ln=Object.getPrototypeOf(Object.getPrototypeOf(async function*(){}).prototype);class wr{constructor(t,r){this._ongoingPromise=void 0,this._isFinished=!1,this._reader=t,this._preventCancel=r}next(){let t=()=>this._nextSteps();return this._ongoingPromise=this._ongoingPromise?M(this._ongoingPromise,t,t):t(),this._ongoingPromise}return(t){let r=()=>this._returnSteps(t);return this._ongoingPromise?M(this._ongoingPromise,r,r):r()}_nextSteps(){if(this._isFinished)return Promise.resolve({value:void 0,done:!0});let t=this._reader,r,n,o=R((i,u)=>{r=i,n=u});return Ie(t,{_chunkSteps:i=>{this._ongoingPromise=void 0,se(()=>r({value:i,done:!1}))},_closeSteps:()=>{this._ongoingPromise=void 0,this._isFinished=!0,$(t),r({value:void 0,done:!0})},_errorSteps:i=>{this._ongoingPromise=void 0,this._isFinished=!0,$(t),n(i)}}),o}_returnSteps(t){if(this._isFinished)return Promise.resolve({value:t,done:!0});this._isFinished=!0;let r=this._reader;if(!this._preventCancel){let n=Tt(r,t);return $(r),M(n,()=>({value:t,done:!0}))}return $(r),p({value:t,done:!0})}}let Cr={next(){return Tr(this)?this._asyncIteratorImpl.next():d(Pr("next"))},return(e){return Tr(this)?this._asyncIteratorImpl.return(e):d(Pr("return"))}};Object.setPrototypeOf(Cr,Ln);function Mn(e,t){let r=Se(e),n=new wr(r,t),o=Object.create(Cr);return o._asyncIteratorImpl=n,o}function Tr(e){if(!l(e)||!Object.prototype.hasOwnProperty.call(e,"_asyncIteratorImpl"))return!1;try{return e._asyncIteratorImpl instanceof wr}catch{return!1}}function Pr(e){return new TypeError(`ReadableStreamAsyncIterator.${e} can only be used on a ReadableSteamAsyncIterator`)}let vr=Number.isNaN||function(e){return e!==e};var Bt,It,Ot;function Oe(e){return e.slice()}function Er(e,t,r,n,o){new Uint8Array(e).set(new Uint8Array(r,n,o),t)}let N=e=>(typeof e.transfer=="function"?N=t=>t.transfer():typeof structuredClone=="function"?N=t=>structuredClone(t,{transfer:[t]}):N=t=>t,N(e)),K=e=>(typeof e.detached=="boolean"?K=t=>t.detached:K=t=>t.byteLength===0,K(e));function qr(e,t,r){if(e.slice)return e.slice(t,r);let n=r-t,o=new ArrayBuffer(n);return Er(o,0,e,t,n),o}function He(e,t){let r=e[t];if(r!=null){if(typeof r!="function")throw new TypeError(`${String(t)} is not a function`);return r}}function $n(e){let t={[Symbol.iterator]:()=>e.iterator},r=(async function*(){return yield*t})(),n=r.next;return{iterator:r,nextMethod:n,done:!1}}let jt=(Ot=(Bt=Symbol.asyncIterator)!==null&&Bt!==void 0?Bt:(It=Symbol.for)===null||It===void 0?void 0:It.call(Symbol,"Symbol.asyncIterator"))!==null&&Ot!==void 0?Ot:"@@asyncIterator";function Wr(e,t="sync",r){if(r===void 0)if(t==="async"){if(r=He(e,jt),r===void 0){let a=He(e,Symbol.iterator),i=Wr(e,"sync",a);return $n(i)}}else r=He(e,Symbol.iterator);if(r===void 0)throw new TypeError("The object is not iterable");let n=le(r,e,[]);if(!l(n))throw new TypeError("The iterator method must return an object");let o=n.next;return{iterator:n,nextMethod:o,done:!1}}function Un(e){let t=le(e.nextMethod,e.iterator,[]);if(!l(t))throw new TypeError("The iterator.next() method must return an object");return t}function Nn(e){return!!e.done}function Qn(e){return e.value}function Yn(e){return!(typeof e!="number"||vr(e)||e<0)}function Ar(e){let t=qr(e.buffer,e.byteOffset,e.byteOffset+e.byteLength);return new Uint8Array(t)}function zt(e){let t=e._queue.shift();return e._queueTotalSize-=t.size,e._queueTotalSize<0&&(e._queueTotalSize=0),t.value}function Ft(e,t,r){if(!Yn(r)||r===1/0)throw new RangeError("Size must be a finite, non-NaN, non-negative number.");e._queue.push({value:t,size:r}),e._queueTotalSize+=r}function Hn(e){return e._queue.peek().value}function x(e){e._queue=new W,e._queueTotalSize=0}function kr(e){return e===DataView}function Vn(e){return kr(e.constructor)}function Gn(e){return kr(e)?1:e.BYTES_PER_ELEMENT}class ue{constructor(){throw new TypeError("Illegal constructor")}get view(){if(!Dt(this))throw Nt("view");return this._view}respond(t){if(!Dt(this))throw Nt("respond");if(U(t,1,"respond"),t=Wt(t,"First parameter"),this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(K(this._view.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be used as a response");Xe(this._associatedReadableByteStreamController,t)}respondWithNewView(t){if(!Dt(this))throw Nt("respondWithNewView");if(U(t,1,"respondWithNewView"),!ArrayBuffer.isView(t))throw new TypeError("You can only respond with array buffer views");if(this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(K(t.buffer))throw new TypeError("The given view's buffer has been detached and so cannot be used as a response");Je(this._associatedReadableByteStreamController,t)}}Object.defineProperties(ue.prototype,{respond:{enumerable:!0},respondWithNewView:{enumerable:!0},view:{enumerable:!0}}),c(ue.prototype.respond,"respond"),c(ue.prototype.respondWithNewView,"respondWithNewView"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ue.prototype,Symbol.toStringTag,{value:"ReadableStreamBYOBRequest",configurable:!0});class Q{constructor(){throw new TypeError("Illegal constructor")}get byobRequest(){if(!de(this))throw ze("byobRequest");return Ut(this)}get desiredSize(){if(!de(this))throw ze("desiredSize");return $r(this)}close(){if(!de(this))throw ze("close");if(this._closeRequested)throw new TypeError("The stream has already been closed; do not close it again!");let t=this._controlledReadableByteStream._state;if(t!=="readable")throw new TypeError(`The stream (in ${t} state) is not in the readable state and cannot be closed`);je(this)}enqueue(t){if(!de(this))throw ze("enqueue");if(U(t,1,"enqueue"),!ArrayBuffer.isView(t))throw new TypeError("chunk must be an array buffer view");if(t.byteLength===0)throw new TypeError("chunk must have non-zero byteLength");if(t.buffer.byteLength===0)throw new TypeError("chunk's buffer must have non-zero byteLength");if(this._closeRequested)throw new TypeError("stream is closed or draining");let r=this._controlledReadableByteStream._state;if(r!=="readable")throw new TypeError(`The stream (in ${r} state) is not in the readable state and cannot be enqueued to`);Ze(this,t)}error(t=void 0){if(!de(this))throw ze("error");k(this,t)}[Rt](t){Br(this),x(this);let r=this._cancelAlgorithm(t);return Ge(this),r}[wt](t){let r=this._controlledReadableByteStream;if(this._queueTotalSize>0){Mr(this,t);return}let n=this._autoAllocateChunkSize;if(n!==void 0){let o;try{o=new ArrayBuffer(n)}catch(i){t._errorSteps(i);return}let a={buffer:o,bufferByteLength:n,byteOffset:0,byteLength:n,bytesFilled:0,minimumFill:1,elementSize:1,viewConstructor:Uint8Array,readerType:"default"};this._pendingPullIntos.push(a)}Sr(r,t),fe(this)}[Ct](){if(this._pendingPullIntos.length>0){let t=this._pendingPullIntos.peek();t.readerType="none",this._pendingPullIntos=new W,this._pendingPullIntos.push(t)}}}Object.defineProperties(Q.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},byobRequest:{enumerable:!0},desiredSize:{enumerable:!0}}),c(Q.prototype.close,"close"),c(Q.prototype.enqueue,"enqueue"),c(Q.prototype.error,"error"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Q.prototype,Symbol.toStringTag,{value:"ReadableByteStreamController",configurable:!0});function de(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledReadableByteStream")?!1:e instanceof Q}function Dt(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_associatedReadableByteStreamController")?!1:e instanceof ue}function fe(e){if(!xn(e))return;if(e._pulling){e._pullAgain=!0;return}e._pulling=!0;let r=e._pullAlgorithm();T(r,()=>(e._pulling=!1,e._pullAgain&&(e._pullAgain=!1,fe(e)),null),n=>(k(e,n),null))}function Br(e){Mt(e),e._pendingPullIntos=new W}function Lt(e,t){let r=!1;e._state==="closed"&&(r=!0);let n=Ir(t);t.readerType==="default"?kt(e,n,r):ao(e,n,r)}function Ir(e){let t=e.bytesFilled,r=e.elementSize;return new e.viewConstructor(e.buffer,e.byteOffset,t/r)}function Ve(e,t,r,n){e._queue.push({buffer:t,byteOffset:r,byteLength:n}),e._queueTotalSize+=n}function Or(e,t,r,n){let o;try{o=qr(t,r,r+n)}catch(a){throw k(e,a),a}Ve(e,o,0,n)}function jr(e,t){t.bytesFilled>0&&Or(e,t.buffer,t.byteOffset,t.bytesFilled),ge(e)}function zr(e,t){let r=Math.min(e._queueTotalSize,t.byteLength-t.bytesFilled),n=t.bytesFilled+r,o=r,a=!1,i=n%t.elementSize,u=n-i;u>=t.minimumFill&&(o=u-t.bytesFilled,a=!0);let m=e._queue;for(;o>0;){let f=m.peek(),_=Math.min(o,f.byteLength),y=t.byteOffset+t.bytesFilled;Er(t.buffer,y,f.buffer,f.byteOffset,_),f.byteLength===_?m.shift():(f.byteOffset+=_,f.byteLength-=_),e._queueTotalSize-=_,Fr(e,_,t),o-=_}return a}function Fr(e,t,r){r.bytesFilled+=t}function Dr(e){e._queueTotalSize===0&&e._closeRequested?(Ge(e),Ue(e._controlledReadableByteStream)):fe(e)}function Mt(e){e._byobRequest!==null&&(e._byobRequest._associatedReadableByteStreamController=void 0,e._byobRequest._view=null,e._byobRequest=null)}function $t(e){for(;e._pendingPullIntos.length>0;){if(e._queueTotalSize===0)return;let t=e._pendingPullIntos.peek();zr(e,t)&&(ge(e),Lt(e._controlledReadableByteStream,t))}}function Zn(e){let t=e._controlledReadableByteStream._reader;for(;t._readRequests.length>0;){if(e._queueTotalSize===0)return;let r=t._readRequests.shift();Mr(e,r)}}function Xn(e,t,r,n){let o=e._controlledReadableByteStream,a=t.constructor,i=Gn(a),{byteOffset:u,byteLength:m}=t,f=r*i,_;try{_=N(t.buffer)}catch(w){n._errorSteps(w);return}let y={buffer:_,bufferByteLength:_.byteLength,byteOffset:u,byteLength:m,bytesFilled:0,minimumFill:f,elementSize:i,viewConstructor:a,readerType:"byob"};if(e._pendingPullIntos.length>0){e._pendingPullIntos.push(y),Qr(o,n);return}if(o._state==="closed"){let w=new a(y.buffer,y.byteOffset,0);n._closeSteps(w);return}if(e._queueTotalSize>0){if(zr(e,y)){let w=Ir(y);Dr(e),n._chunkSteps(w);return}if(e._closeRequested){let w=new TypeError("Insufficient bytes to fill elements in the given buffer");k(e,w),n._errorSteps(w);return}}e._pendingPullIntos.push(y),Qr(o,n),fe(e)}function Jn(e,t){t.readerType==="none"&&ge(e);let r=e._controlledReadableByteStream;if(Qt(r))for(;Yr(r)>0;){let n=ge(e);Lt(r,n)}}function Kn(e,t,r){if(Fr(e,t,r),r.readerType==="none"){jr(e,r),$t(e);return}if(r.bytesFilled0){let o=r.byteOffset+r.bytesFilled;Or(e,r.buffer,o-n,n)}r.bytesFilled-=n,Lt(e._controlledReadableByteStream,r),$t(e)}function Lr(e,t){let r=e._pendingPullIntos.peek();Mt(e),e._controlledReadableByteStream._state==="closed"?Jn(e,r):Kn(e,t,r),fe(e)}function ge(e){return e._pendingPullIntos.shift()}function xn(e){let t=e._controlledReadableByteStream;return t._state!=="readable"||e._closeRequested||!e._started?!1:!!(gr(t)&&Qe(t)>0||Qt(t)&&Yr(t)>0||$r(e)>0)}function Ge(e){e._pullAlgorithm=void 0,e._cancelAlgorithm=void 0}function je(e){let t=e._controlledReadableByteStream;if(!(e._closeRequested||t._state!=="readable")){if(e._queueTotalSize>0){e._closeRequested=!0;return}if(e._pendingPullIntos.length>0){let r=e._pendingPullIntos.peek();if(r.bytesFilled%r.elementSize!==0){let n=new TypeError("Insufficient bytes to fill elements in the given buffer");throw k(e,n),n}}Ge(e),Ue(t)}}function Ze(e,t){let r=e._controlledReadableByteStream;if(e._closeRequested||r._state!=="readable")return;let{buffer:n,byteOffset:o,byteLength:a}=t;if(K(n))throw new TypeError("chunk's buffer is detached and so cannot be enqueued");let i=N(n);if(e._pendingPullIntos.length>0){let u=e._pendingPullIntos.peek();if(K(u.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk");Mt(e),u.buffer=N(u.buffer),u.readerType==="none"&&jr(e,u)}if(gr(r))if(Zn(e),Qe(r)===0)Ve(e,i,o,a);else{e._pendingPullIntos.length>0&&ge(e);let u=new Uint8Array(i,o,a);kt(r,u,!1)}else Qt(r)?(Ve(e,i,o,a),$t(e)):Ve(e,i,o,a);fe(e)}function k(e,t){let r=e._controlledReadableByteStream;r._state==="readable"&&(Br(e),x(e),Ge(e),_n(r,t))}function Mr(e,t){let r=e._queue.shift();e._queueTotalSize-=r.byteLength,Dr(e);let n=new Uint8Array(r.buffer,r.byteOffset,r.byteLength);t._chunkSteps(n)}function Ut(e){if(e._byobRequest===null&&e._pendingPullIntos.length>0){let t=e._pendingPullIntos.peek(),r=new Uint8Array(t.buffer,t.byteOffset+t.bytesFilled,t.byteLength-t.bytesFilled),n=Object.create(ue.prototype);to(n,e,r),e._byobRequest=n}return e._byobRequest}function $r(e){let t=e._controlledReadableByteStream._state;return t==="errored"?null:t==="closed"?0:e._strategyHWM-e._queueTotalSize}function Xe(e,t){let r=e._pendingPullIntos.peek();if(e._controlledReadableByteStream._state==="closed"){if(t!==0)throw new TypeError("bytesWritten must be 0 when calling respond() on a closed stream")}else{if(t===0)throw new TypeError("bytesWritten must be greater than 0 when calling respond() on a readable stream");if(r.bytesFilled+t>r.byteLength)throw new RangeError("bytesWritten out of range")}r.buffer=N(r.buffer),Lr(e,t)}function Je(e,t){let r=e._pendingPullIntos.peek();if(e._controlledReadableByteStream._state==="closed"){if(t.byteLength!==0)throw new TypeError("The view's length must be 0 when calling respondWithNewView() on a closed stream")}else if(t.byteLength===0)throw new TypeError("The view's length must be greater than 0 when calling respondWithNewView() on a readable stream");if(r.byteOffset+r.bytesFilled!==t.byteOffset)throw new RangeError("The region specified by view does not match byobRequest");if(r.bufferByteLength!==t.buffer.byteLength)throw new RangeError("The buffer of view has different capacity than byobRequest");if(r.bytesFilled+t.byteLength>r.byteLength)throw new RangeError("The region specified by view is larger than byobRequest");let o=t.byteLength;r.buffer=N(t.buffer),Lr(e,o)}function Ur(e,t,r,n,o,a,i){t._controlledReadableByteStream=e,t._pullAgain=!1,t._pulling=!1,t._byobRequest=null,t._queue=t._queueTotalSize=void 0,x(t),t._closeRequested=!1,t._started=!1,t._strategyHWM=a,t._pullAlgorithm=n,t._cancelAlgorithm=o,t._autoAllocateChunkSize=i,t._pendingPullIntos=new W,e._readableStreamController=t;let u=r();T(p(u),()=>(t._started=!0,fe(t),null),m=>(k(t,m),null))}function eo(e,t,r){let n=Object.create(Q.prototype),o,a,i;t.start!==void 0?o=()=>t.start(n):o=()=>{},t.pull!==void 0?a=()=>t.pull(n):a=()=>p(void 0),t.cancel!==void 0?i=m=>t.cancel(m):i=()=>p(void 0);let u=t.autoAllocateChunkSize;if(u===0)throw new TypeError("autoAllocateChunkSize must be greater than 0");Ur(e,n,o,a,i,r,u)}function to(e,t,r){e._associatedReadableByteStreamController=t,e._view=r}function Nt(e){return new TypeError(`ReadableStreamBYOBRequest.prototype.${e} can only be used on a ReadableStreamBYOBRequest`)}function ze(e){return new TypeError(`ReadableByteStreamController.prototype.${e} can only be used on a ReadableByteStreamController`)}function ro(e,t){F(e,t);let r=e?.mode;return{mode:r===void 0?void 0:no(r,`${t} has member 'mode' that`)}}function no(e,t){if(e=`${e}`,e!=="byob")throw new TypeError(`${t} '${e}' is not a valid enumeration value for ReadableStreamReaderMode`);return e}function oo(e,t){var r;F(e,t);let n=(r=e?.min)!==null&&r!==void 0?r:1;return{min:Wt(n,`${t} has member 'min' that`)}}function Nr(e){return new ee(e)}function Qr(e,t){e._reader._readIntoRequests.push(t)}function ao(e,t,r){let o=e._reader._readIntoRequests.shift();r?o._closeSteps(t):o._chunkSteps(t)}function Yr(e){return e._reader._readIntoRequests.length}function Qt(e){let t=e._reader;return!(t===void 0||!ce(t))}class ee{constructor(t){if(U(t,1,"ReadableStreamBYOBReader"),At(t,"First parameter"),ne(t))throw new TypeError("This stream has already been locked for exclusive reading by another reader");if(!de(t._readableStreamController))throw new TypeError("Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte source");hr(this,t),this._readIntoRequests=new W}get closed(){return ce(this)?this._closedPromise:d(Ke("closed"))}cancel(t=void 0){return ce(this)?this._ownerReadableStream===void 0?d(Ne("cancel")):Tt(this,t):d(Ke("cancel"))}read(t,r={}){if(!ce(this))return d(Ke("read"));if(!ArrayBuffer.isView(t))return d(new TypeError("view must be an array buffer view"));if(t.byteLength===0)return d(new TypeError("view must have non-zero byteLength"));if(t.buffer.byteLength===0)return d(new TypeError("view's buffer must have non-zero byteLength"));if(K(t.buffer))return d(new TypeError("view's buffer has been detached"));let n;try{n=oo(r,"options")}catch(f){return d(f)}let o=n.min;if(o===0)return d(new TypeError("options.min must be greater than 0"));if(Vn(t)){if(o>t.byteLength)return d(new RangeError("options.min must be less than or equal to view's byteLength"))}else if(o>t.length)return d(new RangeError("options.min must be less than or equal to view's length"));if(this._ownerReadableStream===void 0)return d(Ne("read from"));let a,i,u=R((f,_)=>{a=f,i=_});return Hr(this,t,o,{_chunkSteps:f=>a({value:f,done:!1}),_closeSteps:f=>a({value:f,done:!0}),_errorSteps:f=>i(f)}),u}releaseLock(){if(!ce(this))throw Ke("releaseLock");this._ownerReadableStream!==void 0&&io(this)}}Object.defineProperties(ee.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),c(ee.prototype.cancel,"cancel"),c(ee.prototype.read,"read"),c(ee.prototype.releaseLock,"releaseLock"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ee.prototype,Symbol.toStringTag,{value:"ReadableStreamBYOBReader",configurable:!0});function ce(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_readIntoRequests")?!1:e instanceof ee}function Hr(e,t,r,n){let o=e._ownerReadableStream;o._disturbed=!0,o._state==="errored"?n._errorSteps(o._storedError):Xn(o._readableStreamController,t,r,n)}function io(e){$(e);let t=new TypeError("Reader was released");Vr(e,t)}function Vr(e,t){let r=e._readIntoRequests;e._readIntoRequests=new W,r.forEach(n=>{n._errorSteps(t)})}function Ke(e){return new TypeError(`ReadableStreamBYOBReader.prototype.${e} can only be used on a ReadableStreamBYOBReader`)}function Fe(e,t){let{highWaterMark:r}=e;if(r===void 0)return t;if(vr(r)||r<0)throw new RangeError("Invalid highWaterMark");return r}function xe(e){let{size:t}=e;return t||(()=>1)}function et(e,t){F(e,t);let r=e?.highWaterMark,n=e?.size;return{highWaterMark:r===void 0?void 0:qt(r),size:n===void 0?void 0:so(n,`${t} has member 'size' that`)}}function so(e,t){return A(e,t),r=>qt(e(r))}function lo(e,t){F(e,t);let r=e?.abort,n=e?.close,o=e?.start,a=e?.type,i=e?.write;return{abort:r===void 0?void 0:uo(r,e,`${t} has member 'abort' that`),close:n===void 0?void 0:fo(n,e,`${t} has member 'close' that`),start:o===void 0?void 0:co(o,e,`${t} has member 'start' that`),write:i===void 0?void 0:ho(i,e,`${t} has member 'write' that`),type:a}}function uo(e,t,r){return A(e,r),n=>Z(e,t,[n])}function fo(e,t,r){return A(e,r),()=>Z(e,t,[])}function co(e,t,r){return A(e,r),n=>le(e,t,[n])}function ho(e,t,r){return A(e,r),(n,o)=>Z(e,t,[n,o])}function Gr(e,t){if(!Re(e))throw new TypeError(`${t} is not a WritableStream.`)}function bo(e){if(typeof e!="object"||e===null)return!1;try{return typeof e.aborted=="boolean"}catch{return!1}}let mo=typeof AbortController=="function";function _o(){if(mo)return new AbortController}class te{constructor(t={},r={}){t===void 0?t=null:pr(t,"First parameter");let n=et(r,"Second parameter"),o=lo(t,"First parameter");if(Xr(this),o.type!==void 0)throw new RangeError("Invalid type is specified");let i=xe(n),u=Fe(n,1);Ao(this,o,u,i)}get locked(){if(!Re(this))throw at("locked");return we(this)}abort(t=void 0){return Re(this)?we(this)?d(new TypeError("Cannot abort a stream that already has a writer")):tt(this,t):d(at("abort"))}close(){return Re(this)?we(this)?d(new TypeError("Cannot close a stream that already has a writer")):D(this)?d(new TypeError("Cannot close an already-closing stream")):Jr(this):d(at("close"))}getWriter(){if(!Re(this))throw at("getWriter");return Zr(this)}}Object.defineProperties(te.prototype,{abort:{enumerable:!0},close:{enumerable:!0},getWriter:{enumerable:!0},locked:{enumerable:!0}}),c(te.prototype.abort,"abort"),c(te.prototype.close,"close"),c(te.prototype.getWriter,"getWriter"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(te.prototype,Symbol.toStringTag,{value:"WritableStream",configurable:!0});function Zr(e){return new Y(e)}function po(e,t,r,n,o=1,a=()=>1){let i=Object.create(te.prototype);Xr(i);let u=Object.create(Ce.prototype);return nn(i,u,e,t,r,n,o,a),i}function Xr(e){e._state="writable",e._storedError=void 0,e._writer=void 0,e._writableStreamController=void 0,e._writeRequests=new W,e._inFlightWriteRequest=void 0,e._closeRequest=void 0,e._inFlightCloseRequest=void 0,e._pendingAbortRequest=void 0,e._backpressure=!1}function Re(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_writableStreamController")?!1:e instanceof te}function we(e){return e._writer!==void 0}function tt(e,t){var r;if(e._state==="closed"||e._state==="errored")return p(void 0);e._writableStreamController._abortReason=t,(r=e._writableStreamController._abortController)===null||r===void 0||r.abort(t);let n=e._state;if(n==="closed"||n==="errored")return p(void 0);if(e._pendingAbortRequest!==void 0)return e._pendingAbortRequest._promise;let o=!1;n==="erroring"&&(o=!0,t=void 0);let a=R((i,u)=>{e._pendingAbortRequest={_promise:void 0,_resolve:i,_reject:u,_reason:t,_wasAlreadyErroring:o}});return e._pendingAbortRequest._promise=a,o||Ht(e,t),a}function Jr(e){let t=e._state;if(t==="closed"||t==="errored")return d(new TypeError(`The stream (in ${t} state) is not in the writable state and cannot be closed`));let r=R((o,a)=>{let i={_resolve:o,_reject:a};e._closeRequest=i}),n=e._writer;return n!==void 0&&e._backpressure&&t==="writable"&&er(n),ko(e._writableStreamController),r}function yo(e){return R((r,n)=>{let o={_resolve:r,_reject:n};e._writeRequests.push(o)})}function Yt(e,t){if(e._state==="writable"){Ht(e,t);return}Vt(e)}function Ht(e,t){let r=e._writableStreamController;e._state="erroring",e._storedError=t;let n=e._writer;n!==void 0&&xr(n,t),!Co(e)&&r._started&&Vt(e)}function Vt(e){e._state="errored",e._writableStreamController[cr]();let t=e._storedError;if(e._writeRequests.forEach(o=>{o._reject(t)}),e._writeRequests=new W,e._pendingAbortRequest===void 0){rt(e);return}let r=e._pendingAbortRequest;if(e._pendingAbortRequest=void 0,r._wasAlreadyErroring){r._reject(t),rt(e);return}let n=e._writableStreamController[fr](r._reason);T(n,()=>(r._resolve(),rt(e),null),o=>(r._reject(o),rt(e),null))}function So(e){e._inFlightWriteRequest._resolve(void 0),e._inFlightWriteRequest=void 0}function go(e,t){e._inFlightWriteRequest._reject(t),e._inFlightWriteRequest=void 0,Yt(e,t)}function Ro(e){e._inFlightCloseRequest._resolve(void 0),e._inFlightCloseRequest=void 0,e._state==="erroring"&&(e._storedError=void 0,e._pendingAbortRequest!==void 0&&(e._pendingAbortRequest._resolve(),e._pendingAbortRequest=void 0)),e._state="closed";let r=e._writer;r!==void 0&&ln(r)}function wo(e,t){e._inFlightCloseRequest._reject(t),e._inFlightCloseRequest=void 0,e._pendingAbortRequest!==void 0&&(e._pendingAbortRequest._reject(t),e._pendingAbortRequest=void 0),Yt(e,t)}function D(e){return!(e._closeRequest===void 0&&e._inFlightCloseRequest===void 0)}function Co(e){return!(e._inFlightWriteRequest===void 0&&e._inFlightCloseRequest===void 0)}function To(e){e._inFlightCloseRequest=e._closeRequest,e._closeRequest=void 0}function Po(e){e._inFlightWriteRequest=e._writeRequests.shift()}function rt(e){e._closeRequest!==void 0&&(e._closeRequest._reject(e._storedError),e._closeRequest=void 0);let t=e._writer;t!==void 0&&Kt(t,e._storedError)}function Gt(e,t){let r=e._writer;r!==void 0&&t!==e._backpressure&&(t?Do(r):er(r)),e._backpressure=t}class Y{constructor(t){if(U(t,1,"WritableStreamDefaultWriter"),Gr(t,"First parameter"),we(t))throw new TypeError("This stream has already been locked for exclusive writing by another writer");this._ownerWritableStream=t,t._writer=this;let r=t._state;if(r==="writable")!D(t)&&t._backpressure?st(this):un(this),it(this);else if(r==="erroring")xt(this,t._storedError),it(this);else if(r==="closed")un(this),zo(this);else{let n=t._storedError;xt(this,n),sn(this,n)}}get closed(){return he(this)?this._closedPromise:d(be("closed"))}get desiredSize(){if(!he(this))throw be("desiredSize");if(this._ownerWritableStream===void 0)throw Le("desiredSize");return Wo(this)}get ready(){return he(this)?this._readyPromise:d(be("ready"))}abort(t=void 0){return he(this)?this._ownerWritableStream===void 0?d(Le("abort")):vo(this,t):d(be("abort"))}close(){if(!he(this))return d(be("close"));let t=this._ownerWritableStream;return t===void 0?d(Le("close")):D(t)?d(new TypeError("Cannot close an already-closing stream")):Kr(this)}releaseLock(){if(!he(this))throw be("releaseLock");this._ownerWritableStream!==void 0&&en(this)}write(t=void 0){return he(this)?this._ownerWritableStream===void 0?d(Le("write to")):tn(this,t):d(be("write"))}}Object.defineProperties(Y.prototype,{abort:{enumerable:!0},close:{enumerable:!0},releaseLock:{enumerable:!0},write:{enumerable:!0},closed:{enumerable:!0},desiredSize:{enumerable:!0},ready:{enumerable:!0}}),c(Y.prototype.abort,"abort"),c(Y.prototype.close,"close"),c(Y.prototype.releaseLock,"releaseLock"),c(Y.prototype.write,"write"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Y.prototype,Symbol.toStringTag,{value:"WritableStreamDefaultWriter",configurable:!0});function he(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_ownerWritableStream")?!1:e instanceof Y}function vo(e,t){let r=e._ownerWritableStream;return tt(r,t)}function Kr(e){let t=e._ownerWritableStream;return Jr(t)}function Eo(e){let t=e._ownerWritableStream,r=t._state;return D(t)||r==="closed"?p(void 0):r==="errored"?d(t._storedError):Kr(e)}function qo(e,t){e._closedPromiseState==="pending"?Kt(e,t):Fo(e,t)}function xr(e,t){e._readyPromiseState==="pending"?dn(e,t):Lo(e,t)}function Wo(e){let t=e._ownerWritableStream,r=t._state;return r==="errored"||r==="erroring"?null:r==="closed"?0:on(t._writableStreamController)}function en(e){let t=e._ownerWritableStream,r=new TypeError("Writer was released and can no longer be used to monitor the stream's closedness");xr(e,r),qo(e,r),t._writer=void 0,e._ownerWritableStream=void 0}function tn(e,t){let r=e._ownerWritableStream,n=r._writableStreamController,o=Bo(n,t);if(r!==e._ownerWritableStream)return d(Le("write to"));let a=r._state;if(a==="errored")return d(r._storedError);if(D(r)||a==="closed")return d(new TypeError("The stream is closing or closed and cannot be written to"));if(a==="erroring")return d(r._storedError);let i=yo(r);return Io(n,t,o),i}let rn={};class Ce{constructor(){throw new TypeError("Illegal constructor")}get abortReason(){if(!Zt(this))throw Jt("abortReason");return this._abortReason}get signal(){if(!Zt(this))throw Jt("signal");if(this._abortController===void 0)throw new TypeError("WritableStreamDefaultController.prototype.signal is not supported");return this._abortController.signal}error(t=void 0){if(!Zt(this))throw Jt("error");this._controlledWritableStream._state==="writable"&&an(this,t)}[fr](t){let r=this._abortAlgorithm(t);return nt(this),r}[cr](){x(this)}}Object.defineProperties(Ce.prototype,{abortReason:{enumerable:!0},signal:{enumerable:!0},error:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Ce.prototype,Symbol.toStringTag,{value:"WritableStreamDefaultController",configurable:!0});function Zt(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledWritableStream")?!1:e instanceof Ce}function nn(e,t,r,n,o,a,i,u){t._controlledWritableStream=e,e._writableStreamController=t,t._queue=void 0,t._queueTotalSize=void 0,x(t),t._abortReason=void 0,t._abortController=_o(),t._started=!1,t._strategySizeAlgorithm=u,t._strategyHWM=i,t._writeAlgorithm=n,t._closeAlgorithm=o,t._abortAlgorithm=a;let m=Xt(t);Gt(e,m);let f=r(),_=p(f);T(_,()=>(t._started=!0,ot(t),null),y=>(t._started=!0,Yt(e,y),null))}function Ao(e,t,r,n){let o=Object.create(Ce.prototype),a,i,u,m;t.start!==void 0?a=()=>t.start(o):a=()=>{},t.write!==void 0?i=f=>t.write(f,o):i=()=>p(void 0),t.close!==void 0?u=()=>t.close():u=()=>p(void 0),t.abort!==void 0?m=f=>t.abort(f):m=()=>p(void 0),nn(e,o,a,i,u,m,r,n)}function nt(e){e._writeAlgorithm=void 0,e._closeAlgorithm=void 0,e._abortAlgorithm=void 0,e._strategySizeAlgorithm=void 0}function ko(e){Ft(e,rn,0),ot(e)}function Bo(e,t){try{return e._strategySizeAlgorithm(t)}catch(r){return De(e,r),1}}function on(e){return e._strategyHWM-e._queueTotalSize}function Io(e,t,r){try{Ft(e,t,r)}catch(o){De(e,o);return}let n=e._controlledWritableStream;if(!D(n)&&n._state==="writable"){let o=Xt(e);Gt(n,o)}ot(e)}function ot(e){let t=e._controlledWritableStream;if(!e._started||t._inFlightWriteRequest!==void 0)return;if(t._state==="erroring"){Vt(t);return}if(e._queue.length===0)return;let n=Hn(e);n===rn?Oo(e):jo(e,n)}function De(e,t){e._controlledWritableStream._state==="writable"&&an(e,t)}function Oo(e){let t=e._controlledWritableStream;To(t),zt(e);let r=e._closeAlgorithm();nt(e),T(r,()=>(Ro(t),null),n=>(wo(t,n),null))}function jo(e,t){let r=e._controlledWritableStream;Po(r);let n=e._writeAlgorithm(t);T(n,()=>{So(r);let o=r._state;if(zt(e),!D(r)&&o==="writable"){let a=Xt(e);Gt(r,a)}return ot(e),null},o=>(r._state==="writable"&&nt(e),go(r,o),null))}function Xt(e){return on(e)<=0}function an(e,t){let r=e._controlledWritableStream;nt(e),Ht(r,t)}function at(e){return new TypeError(`WritableStream.prototype.${e} can only be used on a WritableStream`)}function Jt(e){return new TypeError(`WritableStreamDefaultController.prototype.${e} can only be used on a WritableStreamDefaultController`)}function be(e){return new TypeError(`WritableStreamDefaultWriter.prototype.${e} can only be used on a WritableStreamDefaultWriter`)}function Le(e){return new TypeError("Cannot "+e+" a stream using a released writer")}function it(e){e._closedPromise=R((t,r)=>{e._closedPromise_resolve=t,e._closedPromise_reject=r,e._closedPromiseState="pending"})}function sn(e,t){it(e),Kt(e,t)}function zo(e){it(e),ln(e)}function Kt(e,t){e._closedPromise_reject!==void 0&&(ye(e._closedPromise),e._closedPromise_reject(t),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0,e._closedPromiseState="rejected")}function Fo(e,t){sn(e,t)}function ln(e){e._closedPromise_resolve!==void 0&&(e._closedPromise_resolve(void 0),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0,e._closedPromiseState="resolved")}function st(e){e._readyPromise=R((t,r)=>{e._readyPromise_resolve=t,e._readyPromise_reject=r}),e._readyPromiseState="pending"}function xt(e,t){st(e),dn(e,t)}function un(e){st(e),er(e)}function dn(e,t){e._readyPromise_reject!==void 0&&(ye(e._readyPromise),e._readyPromise_reject(t),e._readyPromise_resolve=void 0,e._readyPromise_reject=void 0,e._readyPromiseState="rejected")}function Do(e){st(e)}function Lo(e,t){xt(e,t)}function er(e){e._readyPromise_resolve!==void 0&&(e._readyPromise_resolve(void 0),e._readyPromise_resolve=void 0,e._readyPromise_reject=void 0,e._readyPromiseState="fulfilled")}function Mo(){if(typeof globalThis<"u")return globalThis;if(typeof self<"u")return self;if(typeof globalThis<"u")return globalThis}let tr=Mo();function $o(e){if(!(typeof e=="function"||typeof e=="object")||e.name!=="DOMException")return!1;try{return new e,!0}catch{return!1}}function Uo(){let e=tr?.DOMException;return $o(e)?e:void 0}function No(){let e=function(r,n){this.message=r||"",this.name=n||"Error",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)};return c(e,"DOMException"),e.prototype=Object.create(Error.prototype),Object.defineProperty(e.prototype,"constructor",{value:e,writable:!0,configurable:!0}),e}let Qo=Uo()||No();function fn(e,t,r,n,o,a){let i=Se(e),u=Zr(t);e._disturbed=!0;let m=!1,f=p(void 0);return R((_,y)=>{let w;if(a!==void 0){if(w=()=>{let h=a.reason!==void 0?a.reason:new Qo("Aborted","AbortError"),S=[];n||S.push(()=>t._state==="writable"?tt(t,h):p(void 0)),o||S.push(()=>e._state==="readable"?j(e,h):p(void 0)),E(()=>Promise.all(S.map(C=>C())),!0,h)},a.aborted){w();return}a.addEventListener("abort",w)}function z(){return R((h,S)=>{function C(q){q?h():I(Ee(),C,S)}C(!1)})}function Ee(){return m?p(!0):I(u._readyPromise,()=>R((h,S)=>{Ie(i,{_chunkSteps:C=>{f=I(tn(u,C),void 0,s),h(!1)},_closeSteps:()=>h(!0),_errorSteps:S})}))}if(V(e,i._closedPromise,h=>(n?B(!0,h):E(()=>tt(t,h),!0,h),null)),V(t,u._closedPromise,h=>(o?B(!0,h):E(()=>j(e,h),!0,h),null)),v(e,i._closedPromise,()=>(r?B():E(()=>Eo(u)),null)),D(t)||t._state==="closed"){let h=new TypeError("the destination writable stream closed before all data could be piped to it");o?B(!0,h):E(()=>j(e,h),!0,h)}ye(z());function ae(){let h=f;return I(f,()=>h!==f?ae():void 0)}function V(h,S,C){h._state==="errored"?C(h._storedError):gt(S,C)}function v(h,S,C){h._state==="closed"?C():Be(S,C)}function E(h,S,C){if(m)return;m=!0,t._state==="writable"&&!D(t)?Be(ae(),q):q();function q(){return T(h(),()=>G(S,C),qe=>G(!0,qe)),null}}function B(h,S){m||(m=!0,t._state==="writable"&&!D(t)?Be(ae(),()=>G(h,S)):G(h,S))}function G(h,S){return en(u),$(i),a!==void 0&&a.removeEventListener("abort",w),h?y(S):_(void 0),null}})}class H{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!lt(this))throw dt("desiredSize");return rr(this)}close(){if(!lt(this))throw dt("close");if(!Pe(this))throw new TypeError("The stream is not in a state that permits close");me(this)}enqueue(t=void 0){if(!lt(this))throw dt("enqueue");if(!Pe(this))throw new TypeError("The stream is not in a state that permits enqueue");return Te(this,t)}error(t=void 0){if(!lt(this))throw dt("error");O(this,t)}[Rt](t){x(this);let r=this._cancelAlgorithm(t);return ut(this),r}[wt](t){let r=this._controlledReadableStream;if(this._queue.length>0){let n=zt(this);this._closeRequested&&this._queue.length===0?(ut(this),Ue(r)):Me(this),t._chunkSteps(n)}else Sr(r,t),Me(this)}[Ct](){}}Object.defineProperties(H.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},desiredSize:{enumerable:!0}}),c(H.prototype.close,"close"),c(H.prototype.enqueue,"enqueue"),c(H.prototype.error,"error"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(H.prototype,Symbol.toStringTag,{value:"ReadableStreamDefaultController",configurable:!0});function lt(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledReadableStream")?!1:e instanceof H}function Me(e){if(!cn(e))return;if(e._pulling){e._pullAgain=!0;return}e._pulling=!0;let r=e._pullAlgorithm();T(r,()=>(e._pulling=!1,e._pullAgain&&(e._pullAgain=!1,Me(e)),null),n=>(O(e,n),null))}function cn(e){let t=e._controlledReadableStream;return!Pe(e)||!e._started?!1:!!(ne(t)&&Qe(t)>0||rr(e)>0)}function ut(e){e._pullAlgorithm=void 0,e._cancelAlgorithm=void 0,e._strategySizeAlgorithm=void 0}function me(e){if(!Pe(e))return;let t=e._controlledReadableStream;e._closeRequested=!0,e._queue.length===0&&(ut(e),Ue(t))}function Te(e,t){if(!Pe(e))return;let r=e._controlledReadableStream;if(ne(r)&&Qe(r)>0)kt(r,t,!1);else{let n;try{n=e._strategySizeAlgorithm(t)}catch(o){throw O(e,o),o}try{Ft(e,t,n)}catch(o){throw O(e,o),o}}Me(e)}function O(e,t){let r=e._controlledReadableStream;r._state==="readable"&&(x(e),ut(e),_n(r,t))}function rr(e){let t=e._controlledReadableStream._state;return t==="errored"?null:t==="closed"?0:e._strategyHWM-e._queueTotalSize}function Yo(e){return!cn(e)}function Pe(e){let t=e._controlledReadableStream._state;return!e._closeRequested&&t==="readable"}function hn(e,t,r,n,o,a,i){t._controlledReadableStream=e,t._queue=void 0,t._queueTotalSize=void 0,x(t),t._started=!1,t._closeRequested=!1,t._pullAgain=!1,t._pulling=!1,t._strategySizeAlgorithm=i,t._strategyHWM=a,t._pullAlgorithm=n,t._cancelAlgorithm=o,e._readableStreamController=t;let u=r();T(p(u),()=>(t._started=!0,Me(t),null),m=>(O(t,m),null))}function Ho(e,t,r,n){let o=Object.create(H.prototype),a,i,u;t.start!==void 0?a=()=>t.start(o):a=()=>{},t.pull!==void 0?i=()=>t.pull(o):i=()=>p(void 0),t.cancel!==void 0?u=m=>t.cancel(m):u=()=>p(void 0),hn(e,o,a,i,u,r,n)}function dt(e){return new TypeError(`ReadableStreamDefaultController.prototype.${e} can only be used on a ReadableStreamDefaultController`)}function Vo(e,t){return de(e._readableStreamController)?Zo(e):Go(e)}function Go(e,t){let r=Se(e),n=!1,o=!1,a=!1,i=!1,u,m,f,_,y,w=R(v=>{y=v});function z(){return n?(o=!0,p(void 0)):(n=!0,Ie(r,{_chunkSteps:E=>{se(()=>{o=!1;let B=E,G=E;a||Te(f._readableStreamController,B),i||Te(_._readableStreamController,G),n=!1,o&&z()})},_closeSteps:()=>{n=!1,a||me(f._readableStreamController),i||me(_._readableStreamController),(!a||!i)&&y(void 0)},_errorSteps:()=>{n=!1}}),p(void 0))}function Ee(v){if(a=!0,u=v,i){let E=Oe([u,m]),B=j(e,E);y(B)}return w}function ae(v){if(i=!0,m=v,a){let E=Oe([u,m]),B=j(e,E);y(B)}return w}function V(){}return f=$e(V,z,Ee),_=$e(V,z,ae),gt(r._closedPromise,v=>(O(f._readableStreamController,v),O(_._readableStreamController,v),(!a||!i)&&y(void 0),null)),[f,_]}function Zo(e){let t=Se(e),r=!1,n=!1,o=!1,a=!1,i=!1,u,m,f,_,y,w=R(h=>{y=h});function z(h){gt(h._closedPromise,S=>(h!==t||(k(f._readableStreamController,S),k(_._readableStreamController,S),(!a||!i)&&y(void 0)),null))}function Ee(){ce(t)&&($(t),t=Se(e),z(t)),Ie(t,{_chunkSteps:S=>{se(()=>{n=!1,o=!1;let C=S,q=S;if(!a&&!i)try{q=Ar(S)}catch(qe){k(f._readableStreamController,qe),k(_._readableStreamController,qe),y(j(e,qe));return}a||Ze(f._readableStreamController,C),i||Ze(_._readableStreamController,q),r=!1,n?V():o&&v()})},_closeSteps:()=>{r=!1,a||je(f._readableStreamController),i||je(_._readableStreamController),f._readableStreamController._pendingPullIntos.length>0&&Xe(f._readableStreamController,0),_._readableStreamController._pendingPullIntos.length>0&&Xe(_._readableStreamController,0),(!a||!i)&&y(void 0)},_errorSteps:()=>{r=!1}})}function ae(h,S){J(t)&&($(t),t=Nr(e),z(t));let C=S?_:f,q=S?f:_;Hr(t,h,1,{_chunkSteps:We=>{se(()=>{n=!1,o=!1;let Ae=S?i:a;if(S?a:i)Ae||Je(C._readableStreamController,We);else{let Wn;try{Wn=Ar(We)}catch(sr){k(C._readableStreamController,sr),k(q._readableStreamController,sr),y(j(e,sr));return}Ae||Je(C._readableStreamController,We),Ze(q._readableStreamController,Wn)}r=!1,n?V():o&&v()})},_closeSteps:We=>{r=!1;let Ae=S?i:a,yt=S?a:i;Ae||je(C._readableStreamController),yt||je(q._readableStreamController),We!==void 0&&(Ae||Je(C._readableStreamController,We),!yt&&q._readableStreamController._pendingPullIntos.length>0&&Xe(q._readableStreamController,0)),(!Ae||!yt)&&y(void 0)},_errorSteps:()=>{r=!1}})}function V(){if(r)return n=!0,p(void 0);r=!0;let h=Ut(f._readableStreamController);return h===null?Ee():ae(h._view,!1),p(void 0)}function v(){if(r)return o=!0,p(void 0);r=!0;let h=Ut(_._readableStreamController);return h===null?Ee():ae(h._view,!0),p(void 0)}function E(h){if(a=!0,u=h,i){let S=Oe([u,m]),C=j(e,S);y(C)}return w}function B(h){if(i=!0,m=h,a){let S=Oe([u,m]),C=j(e,S);y(C)}return w}function G(){}return f=mn(G,V,E),_=mn(G,v,B),z(t),[f,_]}function Xo(e){return l(e)&&typeof e.getReader<"u"}function Jo(e){return Xo(e)?xo(e.getReader()):Ko(e)}function Ko(e){let t,r=Wr(e,"async"),n=s;function o(){let i;try{i=Un(r)}catch(m){return d(m)}let u=p(i);return M(u,m=>{if(!l(m))throw new TypeError("The promise returned by the iterator.next() method must fulfill with an object");if(Nn(m))me(t._readableStreamController);else{let _=Qn(m);Te(t._readableStreamController,_)}})}function a(i){let u=r.iterator,m;try{m=He(u,"return")}catch(y){return d(y)}if(m===void 0)return p(void 0);let f;try{f=le(m,u,[i])}catch(y){return d(y)}let _=p(f);return M(_,y=>{if(!l(y))throw new TypeError("The promise returned by the iterator.return() method must fulfill with an object")})}return t=$e(n,o,a,0),t}function xo(e){let t,r=s;function n(){let a;try{a=e.read()}catch(i){return d(i)}return M(a,i=>{if(!l(i))throw new TypeError("The promise returned by the reader.read() method must fulfill with an object");if(i.done)me(t._readableStreamController);else{let u=i.value;Te(t._readableStreamController,u)}})}function o(a){try{return p(e.cancel(a))}catch(i){return d(i)}}return t=$e(r,n,o,0),t}function ea(e,t){F(e,t);let r=e,n=r?.autoAllocateChunkSize,o=r?.cancel,a=r?.pull,i=r?.start,u=r?.type;return{autoAllocateChunkSize:n===void 0?void 0:Wt(n,`${t} has member 'autoAllocateChunkSize' that`),cancel:o===void 0?void 0:ta(o,r,`${t} has member 'cancel' that`),pull:a===void 0?void 0:ra(a,r,`${t} has member 'pull' that`),start:i===void 0?void 0:na(i,r,`${t} has member 'start' that`),type:u===void 0?void 0:oa(u,`${t} has member 'type' that`)}}function ta(e,t,r){return A(e,r),n=>Z(e,t,[n])}function ra(e,t,r){return A(e,r),n=>Z(e,t,[n])}function na(e,t,r){return A(e,r),n=>le(e,t,[n])}function oa(e,t){if(e=`${e}`,e!=="bytes")throw new TypeError(`${t} '${e}' is not a valid enumeration value for ReadableStreamType`);return e}function aa(e,t){return F(e,t),{preventCancel:!!e?.preventCancel}}function bn(e,t){F(e,t);let r=e?.preventAbort,n=e?.preventCancel,o=e?.preventClose,a=e?.signal;return a!==void 0&&ia(a,`${t} has member 'signal' that`),{preventAbort:!!r,preventCancel:!!n,preventClose:!!o,signal:a}}function ia(e,t){if(!bo(e))throw new TypeError(`${t} is not an AbortSignal.`)}function sa(e,t){F(e,t);let r=e?.readable;Et(r,"readable","ReadableWritablePair"),At(r,`${t} has member 'readable' that`);let n=e?.writable;return Et(n,"writable","ReadableWritablePair"),Gr(n,`${t} has member 'writable' that`),{readable:r,writable:n}}class P{constructor(t={},r={}){t===void 0?t=null:pr(t,"First parameter");let n=et(r,"Second parameter"),o=ea(t,"First parameter");if(nr(this),o.type==="bytes"){if(n.size!==void 0)throw new RangeError("The strategy for a byte stream cannot have a size function");let a=Fe(n,0);eo(this,o,a)}else{let a=xe(n),i=Fe(n,1);Ho(this,o,i,a)}}get locked(){if(!re(this))throw _e("locked");return ne(this)}cancel(t=void 0){return re(this)?ne(this)?d(new TypeError("Cannot cancel a stream that already has a reader")):j(this,t):d(_e("cancel"))}getReader(t=void 0){if(!re(this))throw _e("getReader");return ro(t,"First parameter").mode===void 0?Se(this):Nr(this)}pipeThrough(t,r={}){if(!re(this))throw _e("pipeThrough");U(t,1,"pipeThrough");let n=sa(t,"First parameter"),o=bn(r,"Second parameter");if(ne(this))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked ReadableStream");if(we(n.writable))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked WritableStream");let a=fn(this,n.writable,o.preventClose,o.preventAbort,o.preventCancel,o.signal);return ye(a),n.readable}pipeTo(t,r={}){if(!re(this))return d(_e("pipeTo"));if(t===void 0)return d("Parameter 1 is required in 'pipeTo'.");if(!Re(t))return d(new TypeError("ReadableStream.prototype.pipeTo's first argument must be a WritableStream"));let n;try{n=bn(r,"Second parameter")}catch(o){return d(o)}return ne(this)?d(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream")):we(t)?d(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream")):fn(this,t,n.preventClose,n.preventAbort,n.preventCancel,n.signal)}tee(){if(!re(this))throw _e("tee");let t=Vo(this);return Oe(t)}values(t=void 0){if(!re(this))throw _e("values");let r=aa(t,"First parameter");return Mn(this,r.preventCancel)}[jt](t){return this.values(t)}static from(t){return Jo(t)}}Object.defineProperties(P,{from:{enumerable:!0}}),Object.defineProperties(P.prototype,{cancel:{enumerable:!0},getReader:{enumerable:!0},pipeThrough:{enumerable:!0},pipeTo:{enumerable:!0},tee:{enumerable:!0},values:{enumerable:!0},locked:{enumerable:!0}}),c(P.from,"from"),c(P.prototype.cancel,"cancel"),c(P.prototype.getReader,"getReader"),c(P.prototype.pipeThrough,"pipeThrough"),c(P.prototype.pipeTo,"pipeTo"),c(P.prototype.tee,"tee"),c(P.prototype.values,"values"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(P.prototype,Symbol.toStringTag,{value:"ReadableStream",configurable:!0}),Object.defineProperty(P.prototype,jt,{value:P.prototype.values,writable:!0,configurable:!0});function $e(e,t,r,n=1,o=()=>1){let a=Object.create(P.prototype);nr(a);let i=Object.create(H.prototype);return hn(a,i,e,t,r,n,o),a}function mn(e,t,r){let n=Object.create(P.prototype);nr(n);let o=Object.create(Q.prototype);return Ur(n,o,e,t,r,0,void 0),n}function nr(e){e._state="readable",e._reader=void 0,e._storedError=void 0,e._disturbed=!1}function re(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_readableStreamController")?!1:e instanceof P}function ne(e){return e._reader!==void 0}function j(e,t){if(e._disturbed=!0,e._state==="closed")return p(void 0);if(e._state==="errored")return d(e._storedError);Ue(e);let r=e._reader;if(r!==void 0&&ce(r)){let o=r._readIntoRequests;r._readIntoRequests=new W,o.forEach(a=>{a._closeSteps(void 0)})}let n=e._readableStreamController[Rt](t);return M(n,s)}function Ue(e){e._state="closed";let t=e._reader;if(t!==void 0&&(mr(t),J(t))){let r=t._readRequests;t._readRequests=new W,r.forEach(n=>{n._closeSteps()})}}function _n(e,t){e._state="errored",e._storedError=t;let r=e._reader;r!==void 0&&(vt(r,t),J(r)?Rr(r,t):Vr(r,t))}function _e(e){return new TypeError(`ReadableStream.prototype.${e} can only be used on a ReadableStream`)}function pn(e,t){F(e,t);let r=e?.highWaterMark;return Et(r,"highWaterMark","QueuingStrategyInit"),{highWaterMark:qt(r)}}let yn=e=>e.byteLength;c(yn,"size");class ft{constructor(t){U(t,1,"ByteLengthQueuingStrategy"),t=pn(t,"First parameter"),this._byteLengthQueuingStrategyHighWaterMark=t.highWaterMark}get highWaterMark(){if(!gn(this))throw Sn("highWaterMark");return this._byteLengthQueuingStrategyHighWaterMark}get size(){if(!gn(this))throw Sn("size");return yn}}Object.defineProperties(ft.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ft.prototype,Symbol.toStringTag,{value:"ByteLengthQueuingStrategy",configurable:!0});function Sn(e){return new TypeError(`ByteLengthQueuingStrategy.prototype.${e} can only be used on a ByteLengthQueuingStrategy`)}function gn(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_byteLengthQueuingStrategyHighWaterMark")?!1:e instanceof ft}let Rn=()=>1;c(Rn,"size");class ct{constructor(t){U(t,1,"CountQueuingStrategy"),t=pn(t,"First parameter"),this._countQueuingStrategyHighWaterMark=t.highWaterMark}get highWaterMark(){if(!Cn(this))throw wn("highWaterMark");return this._countQueuingStrategyHighWaterMark}get size(){if(!Cn(this))throw wn("size");return Rn}}Object.defineProperties(ct.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ct.prototype,Symbol.toStringTag,{value:"CountQueuingStrategy",configurable:!0});function wn(e){return new TypeError(`CountQueuingStrategy.prototype.${e} can only be used on a CountQueuingStrategy`)}function Cn(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_countQueuingStrategyHighWaterMark")?!1:e instanceof ct}function la(e,t){F(e,t);let r=e?.cancel,n=e?.flush,o=e?.readableType,a=e?.start,i=e?.transform,u=e?.writableType;return{cancel:r===void 0?void 0:ca(r,e,`${t} has member 'cancel' that`),flush:n===void 0?void 0:ua(n,e,`${t} has member 'flush' that`),readableType:o,start:a===void 0?void 0:da(a,e,`${t} has member 'start' that`),transform:i===void 0?void 0:fa(i,e,`${t} has member 'transform' that`),writableType:u}}function ua(e,t,r){return A(e,r),n=>Z(e,t,[n])}function da(e,t,r){return A(e,r),n=>le(e,t,[n])}function fa(e,t,r){return A(e,r),(n,o)=>Z(e,t,[n,o])}function ca(e,t,r){return A(e,r),n=>Z(e,t,[n])}class ht{constructor(t={},r={},n={}){t===void 0&&(t=null);let o=et(r,"Second parameter"),a=et(n,"Third parameter"),i=la(t,"First parameter");if(i.readableType!==void 0)throw new RangeError("Invalid readableType specified");if(i.writableType!==void 0)throw new RangeError("Invalid writableType specified");let u=Fe(a,0),m=xe(a),f=Fe(o,1),_=xe(o),y,w=R(z=>{y=z});ha(this,w,f,_,u,m),ma(this,i),i.start!==void 0?y(i.start(this._transformStreamController)):y(void 0)}get readable(){if(!Tn(this))throw qn("readable");return this._readable}get writable(){if(!Tn(this))throw qn("writable");return this._writable}}Object.defineProperties(ht.prototype,{readable:{enumerable:!0},writable:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ht.prototype,Symbol.toStringTag,{value:"TransformStream",configurable:!0});function ha(e,t,r,n,o,a){function i(){return t}function u(w){return ya(e,w)}function m(w){return Sa(e,w)}function f(){return ga(e)}e._writable=po(i,u,f,m,r,n);function _(){return Ra(e)}function y(w){return wa(e,w)}e._readable=$e(i,_,y,o,a),e._backpressure=void 0,e._backpressureChangePromise=void 0,e._backpressureChangePromise_resolve=void 0,bt(e,!0),e._transformStreamController=void 0}function Tn(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_transformStreamController")?!1:e instanceof ht}function Pn(e,t){O(e._readable._readableStreamController,t),or(e,t)}function or(e,t){_t(e._transformStreamController),De(e._writable._writableStreamController,t),ar(e)}function ar(e){e._backpressure&&bt(e,!1)}function bt(e,t){e._backpressureChangePromise!==void 0&&e._backpressureChangePromise_resolve(),e._backpressureChangePromise=R(r=>{e._backpressureChangePromise_resolve=r}),e._backpressure=t}class oe{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!mt(this))throw pt("desiredSize");let t=this._controlledTransformStream._readable._readableStreamController;return rr(t)}enqueue(t=void 0){if(!mt(this))throw pt("enqueue");vn(this,t)}error(t=void 0){if(!mt(this))throw pt("error");_a(this,t)}terminate(){if(!mt(this))throw pt("terminate");pa(this)}}Object.defineProperties(oe.prototype,{enqueue:{enumerable:!0},error:{enumerable:!0},terminate:{enumerable:!0},desiredSize:{enumerable:!0}}),c(oe.prototype.enqueue,"enqueue"),c(oe.prototype.error,"error"),c(oe.prototype.terminate,"terminate"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(oe.prototype,Symbol.toStringTag,{value:"TransformStreamDefaultController",configurable:!0});function mt(e){return!l(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledTransformStream")?!1:e instanceof oe}function ba(e,t,r,n,o){t._controlledTransformStream=e,e._transformStreamController=t,t._transformAlgorithm=r,t._flushAlgorithm=n,t._cancelAlgorithm=o,t._finishPromise=void 0,t._finishPromise_resolve=void 0,t._finishPromise_reject=void 0}function ma(e,t){let r=Object.create(oe.prototype),n,o,a;t.transform!==void 0?n=i=>t.transform(i,r):n=i=>{try{return vn(r,i),p(void 0)}catch(u){return d(u)}},t.flush!==void 0?o=()=>t.flush(r):o=()=>p(void 0),t.cancel!==void 0?a=i=>t.cancel(i):a=()=>p(void 0),ba(e,r,n,o,a)}function _t(e){e._transformAlgorithm=void 0,e._flushAlgorithm=void 0,e._cancelAlgorithm=void 0}function vn(e,t){let r=e._controlledTransformStream,n=r._readable._readableStreamController;if(!Pe(n))throw new TypeError("Readable side is not in a state that permits enqueue");try{Te(n,t)}catch(a){throw or(r,a),r._readable._storedError}Yo(n)!==r._backpressure&&bt(r,!0)}function _a(e,t){Pn(e._controlledTransformStream,t)}function En(e,t){let r=e._transformAlgorithm(t);return M(r,void 0,n=>{throw Pn(e._controlledTransformStream,n),n})}function pa(e){let t=e._controlledTransformStream,r=t._readable._readableStreamController;me(r);let n=new TypeError("TransformStream terminated");or(t,n)}function ya(e,t){let r=e._transformStreamController;if(e._backpressure){let n=e._backpressureChangePromise;return M(n,()=>{let o=e._writable;if(o._state==="erroring")throw o._storedError;return En(r,t)})}return En(r,t)}function Sa(e,t){let r=e._transformStreamController;if(r._finishPromise!==void 0)return r._finishPromise;let n=e._readable;r._finishPromise=R((a,i)=>{r._finishPromise_resolve=a,r._finishPromise_reject=i});let o=r._cancelAlgorithm(t);return _t(r),T(o,()=>(n._state==="errored"?ve(r,n._storedError):(O(n._readableStreamController,t),ir(r)),null),a=>(O(n._readableStreamController,a),ve(r,a),null)),r._finishPromise}function ga(e){let t=e._transformStreamController;if(t._finishPromise!==void 0)return t._finishPromise;let r=e._readable;t._finishPromise=R((o,a)=>{t._finishPromise_resolve=o,t._finishPromise_reject=a});let n=t._flushAlgorithm();return _t(t),T(n,()=>(r._state==="errored"?ve(t,r._storedError):(me(r._readableStreamController),ir(t)),null),o=>(O(r._readableStreamController,o),ve(t,o),null)),t._finishPromise}function Ra(e){return bt(e,!1),e._backpressureChangePromise}function wa(e,t){let r=e._transformStreamController;if(r._finishPromise!==void 0)return r._finishPromise;let n=e._writable;r._finishPromise=R((a,i)=>{r._finishPromise_resolve=a,r._finishPromise_reject=i});let o=r._cancelAlgorithm(t);return _t(r),T(o,()=>(n._state==="errored"?ve(r,n._storedError):(De(n._writableStreamController,t),ar(e),ir(r)),null),a=>(De(n._writableStreamController,a),ar(e),ve(r,a),null)),r._finishPromise}function pt(e){return new TypeError(`TransformStreamDefaultController.prototype.${e} can only be used on a TransformStreamDefaultController`)}function ir(e){e._finishPromise_resolve!==void 0&&(e._finishPromise_resolve(),e._finishPromise_resolve=void 0,e._finishPromise_reject=void 0)}function ve(e,t){e._finishPromise_reject!==void 0&&(ye(e._finishPromise),e._finishPromise_reject(t),e._finishPromise_resolve=void 0,e._finishPromise_reject=void 0)}function qn(e){return new TypeError(`TransformStream.prototype.${e} can only be used on a TransformStream`)}b.ByteLengthQueuingStrategy=ft,b.CountQueuingStrategy=ct,b.ReadableByteStreamController=Q,b.ReadableStream=P,b.ReadableStreamBYOBReader=ee,b.ReadableStreamBYOBRequest=ue,b.ReadableStreamDefaultController=H,b.ReadableStreamDefaultReader=X,b.TransformStream=ht,b.TransformStreamDefaultController=oe,b.WritableStream=te,b.WritableStreamDefaultController=Ce,b.WritableStreamDefaultWriter=Y}))});var ke=ka(kn());typeof globalThis.ReadableStream>"u"&&(globalThis.ReadableStream=ke.ReadableStream);typeof globalThis.WritableStream>"u"&&(globalThis.WritableStream=ke.WritableStream);typeof globalThis.TransformStream>"u"&&(globalThis.TransformStream=ke.TransformStream);typeof globalThis.URLSearchParams>"u"&&(globalThis.URLSearchParams=class{constructor(s=void 0){L(this,"_entries",[]);if(typeof s=="string"){let l=s.startsWith("?")?s.slice(1):s;if(l.length>0)for(let g of l.split("&")){if(!g)continue;let[c,pe=""]=g.split("=");this.append(decodeURIComponent(c),decodeURIComponent(pe))}}else if(Array.isArray(s))for(let[l,g]of s)this.append(l,g);else if(s&&typeof s=="object")for(let[l,g]of Object.entries(s))this.append(l,g)}append(s,l){this._entries.push([String(s),String(l)])}delete(s){let l=String(s);this._entries=this._entries.filter(([g])=>g!==l)}get(s){let l=String(s),g=this._entries.find(([c])=>c===l);return g?g[1]:null}getAll(s){let l=String(s);return this._entries.filter(([g])=>g===l).map(([,g])=>g)}has(s){let l=String(s);return this._entries.some(([g])=>g===l)}set(s,l){this.delete(s),this.append(s,l)}entries(){return this._entries[Symbol.iterator]()}keys(){return this._entries.map(([s])=>s)[Symbol.iterator]()}values(){return this._entries.map(([,s])=>s)[Symbol.iterator]()}forEach(s,l=void 0){for(let[g,c]of this._entries)s.call(l,c,g,this)}toString(){return this._entries.map(([s,l])=>`${encodeURIComponent(s)}=${encodeURIComponent(l)}`).join("&")}[Symbol.iterator](){return this.entries()}},globalThis.URLSearchParams.__secureExecBootstrapStub=!0);typeof globalThis.URL>"u"&&(globalThis.URL=class{constructor(s,l=void 0){let g=String(s??""),c=/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(g),pe=c||typeof l>"u"?"":String(new globalThis.URL(l).href),ie=(c?g:pe.replace(/\/[^/]*$/,"/")+g).match(/^(\w+:)\/\/([^/:?#]+)(:\d+)?(.*)$/);if(!ie)throw new TypeError(`Invalid URL: ${g}`);this.protocol=ie[1],this.hostname=ie[2],this.port=(ie[3]||"").slice(1);let R=ie[4]||"/",p=R.indexOf("?"),d=R.indexOf("#"),I=[p,d].filter(T=>T>=0).sort((T,Be)=>T-Be)[0]??R.length;this.pathname=R.slice(0,I)||"/",this.search=p>=0?R.slice(p,d>=0&&d>p?d:R.length):"",this.hash=d>=0?R.slice(d):"",this.host=this.hostname+(this.port?`:${this.port}`:""),this.origin=`${this.protocol}//${this.host}`,this.href=`${this.origin}${this.pathname}${this.search}${this.hash}`,this.searchParams=new globalThis.URLSearchParams(this.search)}toString(){return this.href}toJSON(){return this.href}},globalThis.URL.__secureExecBootstrapStub=!0);typeof globalThis.Blob>"u"&&(globalThis.Blob=class{});typeof globalThis.AbortSignal>"u"&&(globalThis.AbortSignal=class{constructor(){L(this,"aborted",!1);L(this,"reason");L(this,"_listeners",new Set)}addEventListener(s,l){s!=="abort"||typeof l!="function"||this._listeners.add(l)}removeEventListener(s,l){s==="abort"&&this._listeners.delete(l)}dispatchEvent(s){for(let l of this._listeners)l.call(this,s);return!0}throwIfAborted(){if(this.aborted)throw this.reason instanceof Error?this.reason:new Error(String(this.reason??"AbortError"))}});typeof globalThis.AbortController>"u"&&(globalThis.AbortController=class{constructor(){this.signal=new globalThis.AbortSignal}abort(s=void 0){this.signal.aborted||(this.signal.aborted=!0,this.signal.reason=s,this.signal.dispatchEvent({type:"abort"}))}});typeof globalThis.File>"u"&&(globalThis.File=class extends Blob{constructor(l=[],g="",c={}){super(l,c);L(this,"name");L(this,"lastModified");L(this,"webkitRelativePath");this.name=String(g),this.lastModified=typeof c.lastModified=="number"?c.lastModified:Date.now(),this.webkitRelativePath=""}});typeof globalThis.FormData>"u"&&(globalThis.FormData=class{constructor(){L(this,"_entries",[])}append(s,l){this._entries.push([s,l])}get(s){let l=this._entries.find(([g])=>g===s);return l?l[1]:null}getAll(s){return this._entries.filter(([l])=>l===s).map(([,l])=>l)}has(s){return this._entries.some(([l])=>l===s)}delete(s){this._entries=this._entries.filter(([l])=>l!==s)}entries(){return this._entries[Symbol.iterator]()}[Symbol.iterator](){return this.entries()}});typeof globalThis.MessagePort>"u"&&(globalThis.MessagePort=class{constructor(){L(this,"onmessage",null)}postMessage(s){}start(){}close(){}addEventListener(){}removeEventListener(){}});typeof globalThis.MessageChannel>"u"&&(globalThis.MessageChannel=class{constructor(){this.port1=new globalThis.MessagePort,this.port2=new globalThis.MessagePort}});if(typeof globalThis.performance>"u"){let b=Date.now();globalThis.performance={now(){return typeof globalThis.__secureExecHrNowUs=="function"?globalThis.__secureExecHrNowUs()/1e3:Date.now()-b}}}typeof globalThis.performance.markResourceTiming!="function"&&(globalThis.performance.markResourceTiming=()=>{});})(); -/*! Bundled license information: - -web-streams-polyfill/dist/ponyfill.es2018.js: - (** - * @license - * web-streams-polyfill v3.3.3 - * Copyright 2024 Mattias Buelens, Diwank Singh Tomer and other contributors. - * This code is released under the MIT license. - * SPDX-License-Identifier: MIT - *) -*/ - -if(typeof globalThis.global==="undefined"){globalThis.global=globalThis;}if(typeof globalThis.process==="undefined"){globalThis.process={env:{},argv:["node"],browser:false,version:"v22.0.0",versions:{node:"22.0.0"},nextTick(callback,...args){return Promise.resolve().then(()=>callback(...args));}};}if(typeof globalThis.TextEncoder==="undefined"){globalThis.TextEncoder=class{encode(value=""){const input=String(value??"");const encoded=unescape(encodeURIComponent(input));const out=new Uint8Array(encoded.length);for(let i=0;isum+(item?.length??0),0);const out=new __SecureExecEarlyBuffer(length);let offset=0;for(const item of list){const chunk=item instanceof Uint8Array?item:__SecureExecEarlyBuffer.from(item);out.set(chunk,offset);offset+=chunk.length;}return out;}static isBuffer(value){return value instanceof Uint8Array;}static byteLength(value,encoding="utf8"){return __SecureExecEarlyBuffer.from(value,encoding).byteLength;}toString(encoding="utf8"){if(encoding==="base64"&&typeof btoa==="function"){let binary="";for(const byte of this){binary+=String.fromCharCode(byte);}return btoa(binary);}if(encoding==="binary"||encoding==="latin1"){let binary="";for(const byte of this){binary+=String.fromCharCode(byte);}return binary;}if(__secureExecTd){return __secureExecTd.decode(this);}return Array.from(this,byte=>String.fromCharCode(byte)).join("");}}globalThis.Buffer=__SecureExecEarlyBuffer;}if(typeof globalThis.performance==="undefined"){const __secureExecPerformanceStart=Date.now();globalThis.performance={now(){if(typeof globalThis.__secureExecHrNowUs==="function"){return globalThis.__secureExecHrNowUs()/1000;}return Date.now()-__secureExecPerformanceStart;}};}if(typeof globalThis.performance.markResourceTiming!=="function"){globalThis.performance.markResourceTiming=()=>{};}if(typeof TextEncoder==="undefined"&&typeof globalThis.TextEncoder!=="undefined"){var TextEncoder=globalThis.TextEncoder;}if(typeof TextDecoder==="undefined"&&typeof globalThis.TextDecoder!=="undefined"){var TextDecoder=globalThis.TextDecoder;}if(typeof Buffer==="undefined"&&typeof globalThis.Buffer!=="undefined"){var Buffer=globalThis.Buffer;} -(()=>{var Cj=Object.create;var nh=Object.defineProperty;var Qj=Object.getOwnPropertyDescriptor;var wj=Object.getOwnPropertyNames;var Sj=Object.getPrototypeOf,_j=Object.prototype.hasOwnProperty;var NI=e=>{throw TypeError(e)};var vj=(e,t,r)=>t in e?nh(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var QD=(e,t)=>()=>(e&&(t=e(e=0)),t);var x=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),MI=(e,t)=>{for(var r in t)nh(e,r,{get:t[r],enumerable:!0})},x0=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of wj(t))!_j.call(e,i)&&i!==r&&nh(e,i,{get:()=>t[i],enumerable:!(n=Qj(t,i))||n.enumerable});return e},vn=(e,t,r)=>(x0(e,t,"default"),r&&x0(r,t,"default")),hr=(e,t,r)=>(r=e!=null?Cj(Sj(e)):{},x0(t||!e||!e.__esModule?nh(r,"default",{value:e,enumerable:!0}):r,e)),Gs=e=>x0(nh({},"__esModule",{value:!0}),e);var y=(e,t,r)=>vj(e,typeof t!="symbol"?t+"":t,r),FI=(e,t,r)=>t.has(e)||NI("Cannot "+r),wD=(e,t)=>Object(t)!==t?NI('Cannot use the "in" operator on this value'):e.has(t),te=(e,t,r)=>(FI(e,t,"read from private field"),r?r.call(e):t.get(e)),St=(e,t,r)=>t.has(e)?NI("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,r),ft=(e,t,r,n)=>(FI(e,t,"write to private field"),n?n.call(e,r):t.set(e,r),r),SD=(e,t,r)=>(FI(e,t,"access private method"),r);var RD=x(U0=>{"use strict";U0.byteLength=Dj;U0.toByteArray=Nj;U0.fromByteArray=kj;var Ys=[],ci=[],Rj=typeof Uint8Array<"u"?Uint8Array:Array,kI="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(XA=0,_D=kI.length;XA<_D;++XA)Ys[XA]=kI[XA],ci[kI.charCodeAt(XA)]=XA;var XA,_D;ci[45]=62;ci[95]=63;function vD(e){var t=e.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=e.indexOf("=");r===-1&&(r=t);var n=r===t?0:4-r%4;return[r,n]}function Dj(e){var t=vD(e),r=t[0],n=t[1];return(r+n)*3/4-n}function Tj(e,t,r){return(t+r)*3/4-r}function Nj(e){var t,r=vD(e),n=r[0],i=r[1],s=new Rj(Tj(e,n,i)),o=0,a=i>0?n-4:n,A;for(A=0;A>16&255,s[o++]=t>>8&255,s[o++]=t&255;return i===2&&(t=ci[e.charCodeAt(A)]<<2|ci[e.charCodeAt(A+1)]>>4,s[o++]=t&255),i===1&&(t=ci[e.charCodeAt(A)]<<10|ci[e.charCodeAt(A+1)]<<4|ci[e.charCodeAt(A+2)]>>2,s[o++]=t>>8&255,s[o++]=t&255),s}function Mj(e){return Ys[e>>18&63]+Ys[e>>12&63]+Ys[e>>6&63]+Ys[e&63]}function Fj(e,t,r){for(var n,i=[],s=t;sa?a:o+s));return n===1?(t=e[r-1],i.push(Ys[t>>2]+Ys[t<<4&63]+"==")):n===2&&(t=(e[r-2]<<8)+e[r-1],i.push(Ys[t>>10]+Ys[t>>4&63]+Ys[t<<2&63]+"=")),i.join("")}});var DD=x(xI=>{xI.read=function(e,t,r,n,i){var s,o,a=i*8-n-1,A=(1<>1,l=-7,p=r?i-1:0,B=r?-1:1,S=e[t+p];for(p+=B,s=S&(1<<-l)-1,S>>=-l,l+=a;l>0;s=s*256+e[t+p],p+=B,l-=8);for(o=s&(1<<-l)-1,s>>=-l,l+=n;l>0;o=o*256+e[t+p],p+=B,l-=8);if(s===0)s=1-f;else{if(s===A)return o?NaN:(S?-1:1)*(1/0);o=o+Math.pow(2,n),s=s-f}return(S?-1:1)*o*Math.pow(2,s-n)};xI.write=function(e,t,r,n,i,s){var o,a,A,f=s*8-i-1,l=(1<>1,B=i===23?Math.pow(2,-24)-Math.pow(2,-77):0,S=n?0:s-1,_=n?1:-1,N=t<0||t===0&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(a=isNaN(t)?1:0,o=l):(o=Math.floor(Math.log(t)/Math.LN2),t*(A=Math.pow(2,-o))<1&&(o--,A*=2),o+p>=1?t+=B/A:t+=B*Math.pow(2,1-p),t*A>=2&&(o++,A/=2),o+p>=l?(a=0,o=l):o+p>=1?(a=(t*A-1)*Math.pow(2,i),o=o+p):(a=t*Math.pow(2,p-1)*Math.pow(2,i),o=0));i>=8;e[r+S]=a&255,S+=_,a/=256,i-=8);for(o=o<0;e[r+S]=o&255,S+=_,o/=256,f-=8);e[r+S-_]|=N*128}});var Gr=x(Yu=>{"use strict";var UI=RD(),Gu=DD(),TD=typeof Symbol=="function"&&typeof Symbol.for=="function"?Symbol.for("nodejs.util.inspect.custom"):null;Yu.Buffer=fe;Yu.SlowBuffer=Hj;Yu.INSPECT_MAX_BYTES=50;var L0=2147483647;Yu.kMaxLength=L0;fe.TYPED_ARRAY_SUPPORT=xj();!fe.TYPED_ARRAY_SUPPORT&&typeof console<"u"&&typeof console.error=="function"&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function xj(){try{var e=new Uint8Array(1),t={foo:function(){return 42}};return Object.setPrototypeOf(t,Uint8Array.prototype),Object.setPrototypeOf(e,t),e.foo()===42}catch{return!1}}Object.defineProperty(fe.prototype,"parent",{enumerable:!0,get:function(){if(fe.isBuffer(this))return this.buffer}});Object.defineProperty(fe.prototype,"offset",{enumerable:!0,get:function(){if(fe.isBuffer(this))return this.byteOffset}});function Wo(e){if(e>L0)throw new RangeError('The value "'+e+'" is invalid for option "size"');var t=new Uint8Array(e);return Object.setPrototypeOf(t,fe.prototype),t}function fe(e,t,r){if(typeof e=="number"){if(typeof t=="string")throw new TypeError('The "string" argument must be of type string. Received type number');return HI(e)}return FD(e,t,r)}fe.poolSize=8192;function FD(e,t,r){if(typeof e=="string")return Lj(e,t);if(ArrayBuffer.isView(e))return Pj(e);if(e==null)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(Ws(e,ArrayBuffer)||e&&Ws(e.buffer,ArrayBuffer)||typeof SharedArrayBuffer<"u"&&(Ws(e,SharedArrayBuffer)||e&&Ws(e.buffer,SharedArrayBuffer)))return PI(e,t,r);if(typeof e=="number")throw new TypeError('The "value" argument must not be of type number. Received type number');var n=e.valueOf&&e.valueOf();if(n!=null&&n!==e)return fe.from(n,t,r);var i=Oj(e);if(i)return i;if(typeof Symbol<"u"&&Symbol.toPrimitive!=null&&typeof e[Symbol.toPrimitive]=="function")return fe.from(e[Symbol.toPrimitive]("string"),t,r);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}fe.from=function(e,t,r){return FD(e,t,r)};Object.setPrototypeOf(fe.prototype,Uint8Array.prototype);Object.setPrototypeOf(fe,Uint8Array);function kD(e){if(typeof e!="number")throw new TypeError('"size" argument must be of type number');if(e<0)throw new RangeError('The value "'+e+'" is invalid for option "size"')}function Uj(e,t,r){return kD(e),e<=0?Wo(e):t!==void 0?typeof r=="string"?Wo(e).fill(t,r):Wo(e).fill(t):Wo(e)}fe.alloc=function(e,t,r){return Uj(e,t,r)};function HI(e){return kD(e),Wo(e<0?0:qI(e)|0)}fe.allocUnsafe=function(e){return HI(e)};fe.allocUnsafeSlow=function(e){return HI(e)};function Lj(e,t){if((typeof t!="string"||t==="")&&(t="utf8"),!fe.isEncoding(t))throw new TypeError("Unknown encoding: "+t);var r=xD(e,t)|0,n=Wo(r),i=n.write(e,t);return i!==r&&(n=n.slice(0,i)),n}function LI(e){for(var t=e.length<0?0:qI(e.length)|0,r=Wo(t),n=0;n=L0)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+L0.toString(16)+" bytes");return e|0}function Hj(e){return+e!=e&&(e=0),fe.alloc(+e)}fe.isBuffer=function(t){return t!=null&&t._isBuffer===!0&&t!==fe.prototype};fe.compare=function(t,r){if(Ws(t,Uint8Array)&&(t=fe.from(t,t.offset,t.byteLength)),Ws(r,Uint8Array)&&(r=fe.from(r,r.offset,r.byteLength)),!fe.isBuffer(t)||!fe.isBuffer(r))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(t===r)return 0;for(var n=t.length,i=r.length,s=0,o=Math.min(n,i);si.length?fe.from(o).copy(i,s):Uint8Array.prototype.set.call(i,o,s);else if(fe.isBuffer(o))o.copy(i,s);else throw new TypeError('"list" argument must be an Array of Buffers');s+=o.length}return i};function xD(e,t){if(fe.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||Ws(e,ArrayBuffer))return e.byteLength;if(typeof e!="string")throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof e);var r=e.length,n=arguments.length>2&&arguments[2]===!0;if(!n&&r===0)return 0;for(var i=!1;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":return OI(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return r*2;case"hex":return r>>>1;case"base64":return qD(e).length;default:if(i)return n?-1:OI(e).length;t=(""+t).toLowerCase(),i=!0}}fe.byteLength=xD;function qj(e,t,r){var n=!1;if((t===void 0||t<0)&&(t=0),t>this.length||((r===void 0||r>this.length)&&(r=this.length),r<=0)||(r>>>=0,t>>>=0,r<=t))return"";for(e||(e="utf8");;)switch(e){case"hex":return Zj(this,t,r);case"utf8":case"utf-8":return LD(this,t,r);case"ascii":return Kj(this,t,r);case"latin1":case"binary":return Xj(this,t,r);case"base64":return jj(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return $j(this,t,r);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}fe.prototype._isBuffer=!0;function ZA(e,t,r){var n=e[t];e[t]=e[r],e[r]=n}fe.prototype.swap16=function(){var t=this.length;if(t%2!==0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(var r=0;rr&&(t+=" ... "),""};TD&&(fe.prototype[TD]=fe.prototype.inspect);fe.prototype.compare=function(t,r,n,i,s){if(Ws(t,Uint8Array)&&(t=fe.from(t,t.offset,t.byteLength)),!fe.isBuffer(t))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof t);if(r===void 0&&(r=0),n===void 0&&(n=t?t.length:0),i===void 0&&(i=0),s===void 0&&(s=this.length),r<0||n>t.length||i<0||s>this.length)throw new RangeError("out of range index");if(i>=s&&r>=n)return 0;if(i>=s)return-1;if(r>=n)return 1;if(r>>>=0,n>>>=0,i>>>=0,s>>>=0,this===t)return 0;for(var o=s-i,a=n-r,A=Math.min(o,a),f=this.slice(i,s),l=t.slice(r,n),p=0;p2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,GI(r)&&(r=i?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(i)return-1;r=e.length-1}else if(r<0)if(i)r=0;else return-1;if(typeof t=="string"&&(t=fe.from(t,n)),fe.isBuffer(t))return t.length===0?-1:ND(e,t,r,n,i);if(typeof t=="number")return t=t&255,typeof Uint8Array.prototype.indexOf=="function"?i?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):ND(e,[t],r,n,i);throw new TypeError("val must be string, number or Buffer")}function ND(e,t,r,n,i){var s=1,o=e.length,a=t.length;if(n!==void 0&&(n=String(n).toLowerCase(),n==="ucs2"||n==="ucs-2"||n==="utf16le"||n==="utf-16le")){if(e.length<2||t.length<2)return-1;s=2,o/=2,a/=2,r/=2}function A(S,_){return s===1?S[_]:S.readUInt16BE(_*s)}var f;if(i){var l=-1;for(f=r;fo&&(r=o-a),f=r;f>=0;f--){for(var p=!0,B=0;Bi&&(n=i)):n=i;var s=t.length;n>s/2&&(n=s/2);for(var o=0;o>>0,isFinite(n)?(n=n>>>0,i===void 0&&(i="utf8")):(i=n,n=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");var s=this.length-r;if((n===void 0||n>s)&&(n=s),t.length>0&&(n<0||r<0)||r>this.length)throw new RangeError("Attempt to write outside buffer bounds");i||(i="utf8");for(var o=!1;;)switch(i){case"hex":return Gj(this,t,r,n);case"utf8":case"utf-8":return Yj(this,t,r,n);case"ascii":case"latin1":case"binary":return Wj(this,t,r,n);case"base64":return Vj(this,t,r,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Jj(this,t,r,n);default:if(o)throw new TypeError("Unknown encoding: "+i);i=(""+i).toLowerCase(),o=!0}};fe.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function jj(e,t,r){return t===0&&r===e.length?UI.fromByteArray(e):UI.fromByteArray(e.slice(t,r))}function LD(e,t,r){r=Math.min(e.length,r);for(var n=[],i=t;i239?4:s>223?3:s>191?2:1;if(i+a<=r){var A,f,l,p;switch(a){case 1:s<128&&(o=s);break;case 2:A=e[i+1],(A&192)===128&&(p=(s&31)<<6|A&63,p>127&&(o=p));break;case 3:A=e[i+1],f=e[i+2],(A&192)===128&&(f&192)===128&&(p=(s&15)<<12|(A&63)<<6|f&63,p>2047&&(p<55296||p>57343)&&(o=p));break;case 4:A=e[i+1],f=e[i+2],l=e[i+3],(A&192)===128&&(f&192)===128&&(l&192)===128&&(p=(s&15)<<18|(A&63)<<12|(f&63)<<6|l&63,p>65535&&p<1114112&&(o=p))}}o===null?(o=65533,a=1):o>65535&&(o-=65536,n.push(o>>>10&1023|55296),o=56320|o&1023),n.push(o),i+=a}return zj(n)}var MD=4096;function zj(e){var t=e.length;if(t<=MD)return String.fromCharCode.apply(String,e);for(var r="",n=0;nn)&&(r=n);for(var i="",s=t;sn&&(t=n),r<0?(r+=n,r<0&&(r=0)):r>n&&(r=n),rr)throw new RangeError("Trying to access beyond buffer length")}fe.prototype.readUintLE=fe.prototype.readUIntLE=function(t,r,n){t=t>>>0,r=r>>>0,n||Dr(t,r,this.length);for(var i=this[t],s=1,o=0;++o>>0,r=r>>>0,n||Dr(t,r,this.length);for(var i=this[t+--r],s=1;r>0&&(s*=256);)i+=this[t+--r]*s;return i};fe.prototype.readUint8=fe.prototype.readUInt8=function(t,r){return t=t>>>0,r||Dr(t,1,this.length),this[t]};fe.prototype.readUint16LE=fe.prototype.readUInt16LE=function(t,r){return t=t>>>0,r||Dr(t,2,this.length),this[t]|this[t+1]<<8};fe.prototype.readUint16BE=fe.prototype.readUInt16BE=function(t,r){return t=t>>>0,r||Dr(t,2,this.length),this[t]<<8|this[t+1]};fe.prototype.readUint32LE=fe.prototype.readUInt32LE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+this[t+3]*16777216};fe.prototype.readUint32BE=fe.prototype.readUInt32BE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),this[t]*16777216+(this[t+1]<<16|this[t+2]<<8|this[t+3])};fe.prototype.readIntLE=function(t,r,n){t=t>>>0,r=r>>>0,n||Dr(t,r,this.length);for(var i=this[t],s=1,o=0;++o=s&&(i-=Math.pow(2,8*r)),i};fe.prototype.readIntBE=function(t,r,n){t=t>>>0,r=r>>>0,n||Dr(t,r,this.length);for(var i=r,s=1,o=this[t+--i];i>0&&(s*=256);)o+=this[t+--i]*s;return s*=128,o>=s&&(o-=Math.pow(2,8*r)),o};fe.prototype.readInt8=function(t,r){return t=t>>>0,r||Dr(t,1,this.length),this[t]&128?(255-this[t]+1)*-1:this[t]};fe.prototype.readInt16LE=function(t,r){t=t>>>0,r||Dr(t,2,this.length);var n=this[t]|this[t+1]<<8;return n&32768?n|4294901760:n};fe.prototype.readInt16BE=function(t,r){t=t>>>0,r||Dr(t,2,this.length);var n=this[t+1]|this[t]<<8;return n&32768?n|4294901760:n};fe.prototype.readInt32LE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24};fe.prototype.readInt32BE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]};fe.prototype.readFloatLE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),Gu.read(this,t,!0,23,4)};fe.prototype.readFloatBE=function(t,r){return t=t>>>0,r||Dr(t,4,this.length),Gu.read(this,t,!1,23,4)};fe.prototype.readDoubleLE=function(t,r){return t=t>>>0,r||Dr(t,8,this.length),Gu.read(this,t,!0,52,8)};fe.prototype.readDoubleBE=function(t,r){return t=t>>>0,r||Dr(t,8,this.length),Gu.read(this,t,!1,52,8)};function Rn(e,t,r,n,i,s){if(!fe.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw new RangeError("Index out of range")}fe.prototype.writeUintLE=fe.prototype.writeUIntLE=function(t,r,n,i){if(t=+t,r=r>>>0,n=n>>>0,!i){var s=Math.pow(2,8*n)-1;Rn(this,t,r,n,s,0)}var o=1,a=0;for(this[r]=t&255;++a>>0,n=n>>>0,!i){var s=Math.pow(2,8*n)-1;Rn(this,t,r,n,s,0)}var o=n-1,a=1;for(this[r+o]=t&255;--o>=0&&(a*=256);)this[r+o]=t/a&255;return r+n};fe.prototype.writeUint8=fe.prototype.writeUInt8=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,1,255,0),this[r]=t&255,r+1};fe.prototype.writeUint16LE=fe.prototype.writeUInt16LE=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,2,65535,0),this[r]=t&255,this[r+1]=t>>>8,r+2};fe.prototype.writeUint16BE=fe.prototype.writeUInt16BE=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,2,65535,0),this[r]=t>>>8,this[r+1]=t&255,r+2};fe.prototype.writeUint32LE=fe.prototype.writeUInt32LE=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,4,4294967295,0),this[r+3]=t>>>24,this[r+2]=t>>>16,this[r+1]=t>>>8,this[r]=t&255,r+4};fe.prototype.writeUint32BE=fe.prototype.writeUInt32BE=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,4,4294967295,0),this[r]=t>>>24,this[r+1]=t>>>16,this[r+2]=t>>>8,this[r+3]=t&255,r+4};fe.prototype.writeIntLE=function(t,r,n,i){if(t=+t,r=r>>>0,!i){var s=Math.pow(2,8*n-1);Rn(this,t,r,n,s-1,-s)}var o=0,a=1,A=0;for(this[r]=t&255;++o>0)-A&255;return r+n};fe.prototype.writeIntBE=function(t,r,n,i){if(t=+t,r=r>>>0,!i){var s=Math.pow(2,8*n-1);Rn(this,t,r,n,s-1,-s)}var o=n-1,a=1,A=0;for(this[r+o]=t&255;--o>=0&&(a*=256);)t<0&&A===0&&this[r+o+1]!==0&&(A=1),this[r+o]=(t/a>>0)-A&255;return r+n};fe.prototype.writeInt8=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,1,127,-128),t<0&&(t=255+t+1),this[r]=t&255,r+1};fe.prototype.writeInt16LE=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,2,32767,-32768),this[r]=t&255,this[r+1]=t>>>8,r+2};fe.prototype.writeInt16BE=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,2,32767,-32768),this[r]=t>>>8,this[r+1]=t&255,r+2};fe.prototype.writeInt32LE=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,4,2147483647,-2147483648),this[r]=t&255,this[r+1]=t>>>8,this[r+2]=t>>>16,this[r+3]=t>>>24,r+4};fe.prototype.writeInt32BE=function(t,r,n){return t=+t,r=r>>>0,n||Rn(this,t,r,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),this[r]=t>>>24,this[r+1]=t>>>16,this[r+2]=t>>>8,this[r+3]=t&255,r+4};function PD(e,t,r,n,i,s){if(r+n>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function OD(e,t,r,n,i){return t=+t,r=r>>>0,i||PD(e,t,r,4,34028234663852886e22,-34028234663852886e22),Gu.write(e,t,r,n,23,4),r+4}fe.prototype.writeFloatLE=function(t,r,n){return OD(this,t,r,!0,n)};fe.prototype.writeFloatBE=function(t,r,n){return OD(this,t,r,!1,n)};function HD(e,t,r,n,i){return t=+t,r=r>>>0,i||PD(e,t,r,8,17976931348623157e292,-17976931348623157e292),Gu.write(e,t,r,n,52,8),r+8}fe.prototype.writeDoubleLE=function(t,r,n){return HD(this,t,r,!0,n)};fe.prototype.writeDoubleBE=function(t,r,n){return HD(this,t,r,!1,n)};fe.prototype.copy=function(t,r,n,i){if(!fe.isBuffer(t))throw new TypeError("argument should be a Buffer");if(n||(n=0),!i&&i!==0&&(i=this.length),r>=t.length&&(r=t.length),r||(r=0),i>0&&i=this.length)throw new RangeError("Index out of range");if(i<0)throw new RangeError("sourceEnd out of bounds");i>this.length&&(i=this.length),t.length-r>>0,n=n===void 0?this.length:n>>>0,t||(t=0);var o;if(typeof t=="number")for(o=r;o55295&&r<57344){if(!i){if(r>56319){(t-=3)>-1&&s.push(239,191,189);continue}else if(o+1===n){(t-=3)>-1&&s.push(239,191,189);continue}i=r;continue}if(r<56320){(t-=3)>-1&&s.push(239,191,189),i=r;continue}r=(i-55296<<10|r-56320)+65536}else i&&(t-=3)>-1&&s.push(239,191,189);if(i=null,r<128){if((t-=1)<0)break;s.push(r)}else if(r<2048){if((t-=2)<0)break;s.push(r>>6|192,r&63|128)}else if(r<65536){if((t-=3)<0)break;s.push(r>>12|224,r>>6&63|128,r&63|128)}else if(r<1114112){if((t-=4)<0)break;s.push(r>>18|240,r>>12&63|128,r>>6&63|128,r&63|128)}else throw new Error("Invalid code point")}return s}function rz(e){for(var t=[],r=0;r>8,i=r%256,s.push(i),s.push(n);return s}function qD(e){return UI.toByteArray(tz(e))}function P0(e,t,r,n){for(var i=0;i=t.length||i>=e.length);++i)t[i+r]=e[i];return i}function Ws(e,t){return e instanceof t||e!=null&&e.constructor!=null&&e.constructor.name!=null&&e.constructor.name===t.name}function GI(e){return e!==e}var iz=(function(){for(var e="0123456789abcdef",t=new Array(256),r=0;r<16;++r)for(var n=r*16,i=0;i<16;++i)t[n+i]=e[r]+e[i];return t})()});var Zi=x((rRe,WI)=>{"use strict";var Wu=typeof Reflect=="object"?Reflect:null,GD=Wu&&typeof Wu.apply=="function"?Wu.apply:function(t,r,n){return Function.prototype.apply.call(t,r,n)},O0;Wu&&typeof Wu.ownKeys=="function"?O0=Wu.ownKeys:Object.getOwnPropertySymbols?O0=function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:O0=function(t){return Object.getOwnPropertyNames(t)};function XZ(e){console&&console.warn&&console.warn(e)}var WD=Number.isNaN||function(t){return t!==t};function xt(){xt.init.call(this)}WI.exports=xt;WI.exports.once=t$;xt.EventEmitter=xt;xt.prototype._events=void 0;xt.prototype._eventsCount=0;xt.prototype._maxListeners=void 0;var YD=10;function H0(e){if(typeof e!="function")throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}Object.defineProperty(xt,"defaultMaxListeners",{enumerable:!0,get:function(){return YD},set:function(e){if(typeof e!="number"||e<0||WD(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");YD=e}});xt.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0};xt.prototype.setMaxListeners=function(t){if(typeof t!="number"||t<0||WD(t))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+t+".");return this._maxListeners=t,this};function VD(e){return e._maxListeners===void 0?xt.defaultMaxListeners:e._maxListeners}xt.prototype.getMaxListeners=function(){return VD(this)};xt.prototype.emit=function(t){for(var r=[],n=1;n0&&(o=r[0]),o instanceof Error)throw o;var a=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw a.context=o,a}var A=s[t];if(A===void 0)return!1;if(typeof A=="function")GD(A,this,r);else for(var f=A.length,l=XD(A,f),n=0;n0&&o.length>i&&!o.warned){o.warned=!0;var a=new Error("Possible EventEmitter memory leak detected. "+o.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");a.name="MaxListenersExceededWarning",a.emitter=e,a.type=t,a.count=o.length,XZ(a)}return e}xt.prototype.addListener=function(t,r){return JD(this,t,r,!1)};xt.prototype.on=xt.prototype.addListener;xt.prototype.prependListener=function(t,r){return JD(this,t,r,!0)};function ZZ(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length===0?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function jD(e,t,r){var n={fired:!1,wrapFn:void 0,target:e,type:t,listener:r},i=ZZ.bind(n);return i.listener=r,n.wrapFn=i,i}xt.prototype.once=function(t,r){return H0(r),this.on(t,jD(this,t,r)),this};xt.prototype.prependOnceListener=function(t,r){return H0(r),this.prependListener(t,jD(this,t,r)),this};xt.prototype.removeListener=function(t,r){var n,i,s,o,a;if(H0(r),i=this._events,i===void 0)return this;if(n=i[t],n===void 0)return this;if(n===r||n.listener===r)--this._eventsCount===0?this._events=Object.create(null):(delete i[t],i.removeListener&&this.emit("removeListener",t,n.listener||r));else if(typeof n!="function"){for(s=-1,o=n.length-1;o>=0;o--)if(n[o]===r||n[o].listener===r){a=n[o].listener,s=o;break}if(s<0)return this;s===0?n.shift():$Z(n,s),n.length===1&&(i[t]=n[0]),i.removeListener!==void 0&&this.emit("removeListener",t,a||r)}return this};xt.prototype.off=xt.prototype.removeListener;xt.prototype.removeAllListeners=function(t){var r,n,i;if(n=this._events,n===void 0)return this;if(n.removeListener===void 0)return arguments.length===0?(this._events=Object.create(null),this._eventsCount=0):n[t]!==void 0&&(--this._eventsCount===0?this._events=Object.create(null):delete n[t]),this;if(arguments.length===0){var s=Object.keys(n),o;for(i=0;i=0;i--)this.removeListener(t,r[i]);return this};function zD(e,t,r){var n=e._events;if(n===void 0)return[];var i=n[t];return i===void 0?[]:typeof i=="function"?r?[i.listener||i]:[i]:r?e$(i):XD(i,i.length)}xt.prototype.listeners=function(t){return zD(this,t,!0)};xt.prototype.rawListeners=function(t){return zD(this,t,!1)};xt.listenerCount=function(e,t){return typeof e.listenerCount=="function"?e.listenerCount(t):KD.call(e,t)};xt.prototype.listenerCount=KD;function KD(e){var t=this._events;if(t!==void 0){var r=t[e];if(typeof r=="function")return 1;if(r!==void 0)return r.length}return 0}xt.prototype.eventNames=function(){return this._eventsCount>0?O0(this._events):[]};function XD(e,t){for(var r=new Array(t),n=0;n{"use strict";function Vs(e){if(typeof e!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}function $D(e,t){for(var r="",n=0,i=-1,s=0,o,a=0;a<=e.length;++a){if(a2){var A=r.lastIndexOf("/");if(A!==r.length-1){A===-1?(r="",n=0):(r=r.slice(0,A),n=r.length-1-r.lastIndexOf("/")),i=a,s=0;continue}}else if(r.length===2||r.length===1){r="",n=0,i=a,s=0;continue}}t&&(r.length>0?r+="/..":r="..",n=2)}else r.length>0?r+="/"+e.slice(i+1,a):r=e.slice(i+1,a),n=a-i-1;i=a,s=0}else o===46&&s!==-1?++s:s=-1}return r}function n$(e,t){var r=t.dir||t.root,n=t.base||(t.name||"")+(t.ext||"");return r?r===t.root?r+n:r+e+n:n}var Vu={resolve:function(){for(var t="",r=!1,n,i=arguments.length-1;i>=-1&&!r;i--){var s;i>=0?s=arguments[i]:(n===void 0&&(n=process.cwd()),s=n),Vs(s),s.length!==0&&(t=s+"/"+t,r=s.charCodeAt(0)===47)}return t=$D(t,!r),r?t.length>0?"/"+t:"/":t.length>0?t:"."},normalize:function(t){if(Vs(t),t.length===0)return".";var r=t.charCodeAt(0)===47,n=t.charCodeAt(t.length-1)===47;return t=$D(t,!r),t.length===0&&!r&&(t="."),t.length>0&&n&&(t+="/"),r?"/"+t:t},isAbsolute:function(t){return Vs(t),t.length>0&&t.charCodeAt(0)===47},join:function(){if(arguments.length===0)return".";for(var t,r=0;r0&&(t===void 0?t=n:t+="/"+n)}return t===void 0?".":Vu.normalize(t)},relative:function(t,r){if(Vs(t),Vs(r),t===r||(t=Vu.resolve(t),r=Vu.resolve(r),t===r))return"";for(var n=1;nf){if(r.charCodeAt(o+p)===47)return r.slice(o+p+1);if(p===0)return r.slice(o+p)}else s>f&&(t.charCodeAt(n+p)===47?l=p:p===0&&(l=0));break}var B=t.charCodeAt(n+p),S=r.charCodeAt(o+p);if(B!==S)break;B===47&&(l=p)}var _="";for(p=n+l+1;p<=i;++p)(p===i||t.charCodeAt(p)===47)&&(_.length===0?_+="..":_+="/..");return _.length>0?_+r.slice(o+l):(o+=l,r.charCodeAt(o)===47&&++o,r.slice(o))},_makeLong:function(t){return t},dirname:function(t){if(Vs(t),t.length===0)return".";for(var r=t.charCodeAt(0),n=r===47,i=-1,s=!0,o=t.length-1;o>=1;--o)if(r=t.charCodeAt(o),r===47){if(!s){i=o;break}}else s=!1;return i===-1?n?"/":".":n&&i===1?"//":t.slice(0,i)},basename:function(t,r){if(r!==void 0&&typeof r!="string")throw new TypeError('"ext" argument must be a string');Vs(t);var n=0,i=-1,s=!0,o;if(r!==void 0&&r.length>0&&r.length<=t.length){if(r.length===t.length&&r===t)return"";var a=r.length-1,A=-1;for(o=t.length-1;o>=0;--o){var f=t.charCodeAt(o);if(f===47){if(!s){n=o+1;break}}else A===-1&&(s=!1,A=o+1),a>=0&&(f===r.charCodeAt(a)?--a===-1&&(i=o):(a=-1,i=A))}return n===i?i=A:i===-1&&(i=t.length),t.slice(n,i)}else{for(o=t.length-1;o>=0;--o)if(t.charCodeAt(o)===47){if(!s){n=o+1;break}}else i===-1&&(s=!1,i=o+1);return i===-1?"":t.slice(n,i)}},extname:function(t){Vs(t);for(var r=-1,n=0,i=-1,s=!0,o=0,a=t.length-1;a>=0;--a){var A=t.charCodeAt(a);if(A===47){if(!s){n=a+1;break}continue}i===-1&&(s=!1,i=a+1),A===46?r===-1?r=a:o!==1&&(o=1):r!==-1&&(o=-1)}return r===-1||i===-1||o===0||o===1&&r===i-1&&r===n+1?"":t.slice(r,i)},format:function(t){if(t===null||typeof t!="object")throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof t);return n$("/",t)},parse:function(t){Vs(t);var r={root:"",dir:"",base:"",ext:"",name:""};if(t.length===0)return r;var n=t.charCodeAt(0),i=n===47,s;i?(r.root="/",s=1):s=0;for(var o=-1,a=0,A=-1,f=!0,l=t.length-1,p=0;l>=s;--l){if(n=t.charCodeAt(l),n===47){if(!f){a=l+1;break}continue}A===-1&&(f=!1,A=l+1),n===46?o===-1?o=l:p!==1&&(p=1):o!==-1&&(p=-1)}return o===-1||A===-1||p===0||p===1&&o===A-1&&o===a+1?A!==-1&&(a===0&&i?r.base=r.name=t.slice(1,A):r.base=r.name=t.slice(a,A)):(a===0&&i?(r.name=t.slice(1,o),r.base=t.slice(1,A)):(r.name=t.slice(a,o),r.base=t.slice(a,A)),r.ext=t.slice(o,A)),a>0?r.dir=t.slice(0,a-1):i&&(r.dir="/"),r},sep:"/",delimiter:":",win32:null,posix:null};Vu.posix=Vu;eT.exports=Vu});var VI=x((Ju,ju)=>{(function(e){var t=typeof Ju=="object"&&Ju&&!Ju.nodeType&&Ju,r=typeof ju=="object"&&ju&&!ju.nodeType&&ju,n=typeof globalThis=="object"&&globalThis;(n.global===n||n.window===n||n.self===n)&&(e=n);var i,s=2147483647,o=36,a=1,A=26,f=38,l=700,p=72,B=128,S="-",_=/^xn--/,N=/[^\x20-\x7E]/,P=/[\x2E\u3002\uFF0E\uFF61]/g,U={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},G=o-a,Y=Math.floor,Z=String.fromCharCode,ee;function j(C){throw new RangeError(U[C])}function se(C,h){for(var D=C.length,M=[];D--;)M[D]=h(C[D]);return M}function ie(C,h){var D=C.split("@"),M="";D.length>1&&(M=D[0]+"@",C=D[1]),C=C.replace(P,".");var I=C.split("."),k=se(I,h).join(".");return M+k}function ce(C){for(var h=[],D=0,M=C.length,I,k;D=55296&&I<=56319&&D65535&&(h-=65536,D+=Z(h>>>10&1023|55296),h=56320|h&1023),D+=Z(h),D}).join("")}function E(C){return C-48<10?C-22:C-65<26?C-65:C-97<26?C-97:o}function v(C,h){return C+22+75*(C<26)-((h!=0)<<5)}function b(C,h,D){var M=0;for(C=D?Y(C/l):C>>1,C+=Y(C/h);C>G*A>>1;M+=o)C=Y(C/G);return Y(M+(G+1)*C/(C+f))}function c(C){var h=[],D=C.length,M,I=0,k=B,ne=p,Ae,ue,pe,he,de,wt,Ie,be,yr;for(Ae=C.lastIndexOf(S),Ae<0&&(Ae=0),ue=0;ue=128&&j("not-basic"),h.push(C.charCodeAt(ue));for(pe=Ae>0?Ae+1:0;pe=D&&j("invalid-input"),Ie=E(C.charCodeAt(pe++)),(Ie>=o||Ie>Y((s-I)/de))&&j("overflow"),I+=Ie*de,be=wt<=ne?a:wt>=ne+A?A:wt-ne,!(IeY(s/yr)&&j("overflow"),de*=yr;M=h.length+1,ne=b(I-he,M,he==0),Y(I/M)>s-k&&j("overflow"),k+=Y(I/M),I%=M,h.splice(I++,0,k)}return H(h)}function g(C){var h,D,M,I,k,ne,Ae,ue,pe,he,de,wt=[],Ie,be,yr,we;for(C=ce(C),Ie=C.length,h=B,D=0,k=p,ne=0;ne=h&&deY((s-D)/be)&&j("overflow"),D+=(Ae-h)*be,h=Ae,ne=0;nes&&j("overflow"),de==h){for(ue=D,pe=o;he=pe<=k?a:pe>=k+A?A:pe-k,!(ue{"use strict";function i$(e,t){return Object.prototype.hasOwnProperty.call(e,t)}rT.exports=function(e,t,r,n){t=t||"&",r=r||"=";var i={};if(typeof e!="string"||e.length===0)return i;var s=/\+/g;e=e.split(t);var o=1e3;n&&typeof n.maxKeys=="number"&&(o=n.maxKeys);var a=e.length;o>0&&a>o&&(a=o);for(var A=0;A=0?(p=f.substr(0,l),B=f.substr(l+1)):(p=f,B=""),S=decodeURIComponent(p),_=decodeURIComponent(B),i$(i,S)?s$(i[S])?i[S].push(_):i[S]=[i[S],_]:i[S]=_}return i};var s$=Array.isArray||function(e){return Object.prototype.toString.call(e)==="[object Array]"}});var oT=x((sRe,sT)=>{"use strict";var ih=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};sT.exports=function(e,t,r,n){return t=t||"&",r=r||"=",e===null&&(e=void 0),typeof e=="object"?iT(a$(e),function(i){var s=encodeURIComponent(ih(i))+r;return o$(e[i])?iT(e[i],function(o){return s+encodeURIComponent(ih(o))}).join(t):s+encodeURIComponent(ih(e[i]))}).join(t):n?encodeURIComponent(ih(n))+r+encodeURIComponent(ih(e)):""};var o$=Array.isArray||function(e){return Object.prototype.toString.call(e)==="[object Array]"};function iT(e,t){if(e.map)return e.map(t);for(var r=[],n=0;n{"use strict";sh.decode=sh.parse=nT();sh.encode=sh.stringify=oT()});var q0={};MI(q0,{decode:()=>ja.decode,default:()=>A$,encode:()=>ja.encode,escape:()=>aT,parse:()=>ja.parse,stringify:()=>ja.stringify,unescape:()=>AT});function aT(e){return encodeURIComponent(e)}function AT(e){return decodeURIComponent(e)}var Ja,ja,A$,jI=QD(()=>{Ja=hr(JI(),1),ja=hr(JI(),1);A$={decode:Ja.decode,encode:Ja.encode,parse:Ja.parse,stringify:Ja.stringify,escape:aT,unescape:AT}});var ze=x((aRe,zI)=>{typeof Object.create=="function"?zI.exports=function(t,r){r&&(t.super_=r,t.prototype=Object.create(r.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}))}:zI.exports=function(t,r){if(r){t.super_=r;var n=function(){};n.prototype=r.prototype,t.prototype=new n,t.prototype.constructor=t}}});var KI=x((ARe,fT)=>{fT.exports=Zi().EventEmitter});var G0=x((fRe,uT)=>{"use strict";uT.exports=function(){if(typeof Symbol!="function"||typeof Object.getOwnPropertySymbols!="function")return!1;if(typeof Symbol.iterator=="symbol")return!0;var t={},r=Symbol("test"),n=Object(r);if(typeof r=="string"||Object.prototype.toString.call(r)!=="[object Symbol]"||Object.prototype.toString.call(n)!=="[object Symbol]")return!1;var i=42;t[r]=i;for(var s in t)return!1;if(typeof Object.keys=="function"&&Object.keys(t).length!==0||typeof Object.getOwnPropertyNames=="function"&&Object.getOwnPropertyNames(t).length!==0)return!1;var o=Object.getOwnPropertySymbols(t);if(o.length!==1||o[0]!==r||!Object.prototype.propertyIsEnumerable.call(t,r))return!1;if(typeof Object.getOwnPropertyDescriptor=="function"){var a=Object.getOwnPropertyDescriptor(t,r);if(a.value!==i||a.enumerable!==!0)return!1}return!0}});var oh=x((uRe,cT)=>{"use strict";var f$=G0();cT.exports=function(){return f$()&&!!Symbol.toStringTag}});var Y0=x((cRe,lT)=>{"use strict";lT.exports=Object});var dT=x((lRe,hT)=>{"use strict";hT.exports=Error});var pT=x((hRe,gT)=>{"use strict";gT.exports=EvalError});var yT=x((dRe,ET)=>{"use strict";ET.exports=RangeError});var BT=x((gRe,mT)=>{"use strict";mT.exports=ReferenceError});var XI=x((pRe,IT)=>{"use strict";IT.exports=SyntaxError});var $i=x((ERe,bT)=>{"use strict";bT.exports=TypeError});var QT=x((yRe,CT)=>{"use strict";CT.exports=URIError});var ST=x((mRe,wT)=>{"use strict";wT.exports=Math.abs});var vT=x((BRe,_T)=>{"use strict";_T.exports=Math.floor});var DT=x((IRe,RT)=>{"use strict";RT.exports=Math.max});var NT=x((bRe,TT)=>{"use strict";TT.exports=Math.min});var FT=x((CRe,MT)=>{"use strict";MT.exports=Math.pow});var xT=x((QRe,kT)=>{"use strict";kT.exports=Math.round});var LT=x((wRe,UT)=>{"use strict";UT.exports=Number.isNaN||function(t){return t!==t}});var OT=x((SRe,PT)=>{"use strict";var u$=LT();PT.exports=function(t){return u$(t)||t===0?t:t<0?-1:1}});var qT=x((_Re,HT)=>{"use strict";HT.exports=Object.getOwnPropertyDescriptor});var $A=x((vRe,GT)=>{"use strict";var W0=qT();if(W0)try{W0([],"length")}catch{W0=null}GT.exports=W0});var ah=x((RRe,YT)=>{"use strict";var V0=Object.defineProperty||!1;if(V0)try{V0({},"a",{value:1})}catch{V0=!1}YT.exports=V0});var JT=x((DRe,VT)=>{"use strict";var WT=typeof Symbol<"u"&&Symbol,c$=G0();VT.exports=function(){return typeof WT!="function"||typeof Symbol!="function"||typeof WT("foo")!="symbol"||typeof Symbol("bar")!="symbol"?!1:c$()}});var ZI=x((TRe,jT)=>{"use strict";jT.exports=typeof Reflect<"u"&&Reflect.getPrototypeOf||null});var $I=x((NRe,zT)=>{"use strict";var l$=Y0();zT.exports=l$.getPrototypeOf||null});var ZT=x((MRe,XT)=>{"use strict";var h$="Function.prototype.bind called on incompatible ",d$=Object.prototype.toString,g$=Math.max,p$="[object Function]",KT=function(t,r){for(var n=[],i=0;i{"use strict";var m$=ZT();$T.exports=Function.prototype.bind||m$});var J0=x((kRe,eN)=>{"use strict";eN.exports=Function.prototype.call});var j0=x((xRe,tN)=>{"use strict";tN.exports=Function.prototype.apply});var nN=x((URe,rN)=>{"use strict";rN.exports=typeof Reflect<"u"&&Reflect&&Reflect.apply});var eb=x((LRe,iN)=>{"use strict";var B$=zu(),I$=j0(),b$=J0(),C$=nN();iN.exports=C$||B$.call(b$,I$)});var z0=x((PRe,sN)=>{"use strict";var Q$=zu(),w$=$i(),S$=J0(),_$=eb();sN.exports=function(t){if(t.length<1||typeof t[0]!="function")throw new w$("a function is required");return _$(Q$,S$,t)}});var cN=x((ORe,uN)=>{"use strict";var v$=z0(),oN=$A(),AN;try{AN=[].__proto__===Array.prototype}catch(e){if(!e||typeof e!="object"||!("code"in e)||e.code!=="ERR_PROTO_ACCESS")throw e}var tb=!!AN&&oN&&oN(Object.prototype,"__proto__"),fN=Object,aN=fN.getPrototypeOf;uN.exports=tb&&typeof tb.get=="function"?v$([tb.get]):typeof aN=="function"?function(t){return aN(t==null?t:fN(t))}:!1});var K0=x((HRe,gN)=>{"use strict";var lN=ZI(),hN=$I(),dN=cN();gN.exports=lN?function(t){return lN(t)}:hN?function(t){if(!t||typeof t!="object"&&typeof t!="function")throw new TypeError("getProto: not an object");return hN(t)}:dN?function(t){return dN(t)}:null});var rb=x((qRe,pN)=>{"use strict";var R$=Function.prototype.call,D$=Object.prototype.hasOwnProperty,T$=zu();pN.exports=T$.call(R$,D$)});var ec=x((GRe,bN)=>{"use strict";var gt,N$=Y0(),M$=dT(),F$=pT(),k$=yT(),x$=BT(),$u=XI(),Zu=$i(),U$=QT(),L$=ST(),P$=vT(),O$=DT(),H$=NT(),q$=FT(),G$=xT(),Y$=OT(),BN=Function,nb=function(e){try{return BN('"use strict"; return ('+e+").constructor;")()}catch{}},Ah=$A(),W$=ah(),ib=function(){throw new Zu},V$=Ah?(function(){try{return arguments.callee,ib}catch{try{return Ah(arguments,"callee").get}catch{return ib}}})():ib,Ku=JT()(),Tr=K0(),J$=$I(),j$=ZI(),IN=j0(),fh=J0(),Xu={},z$=typeof Uint8Array>"u"||!Tr?gt:Tr(Uint8Array),ef={__proto__:null,"%AggregateError%":typeof AggregateError>"u"?gt:AggregateError,"%Array%":Array,"%ArrayBuffer%":typeof ArrayBuffer>"u"?gt:ArrayBuffer,"%ArrayIteratorPrototype%":Ku&&Tr?Tr([][Symbol.iterator]()):gt,"%AsyncFromSyncIteratorPrototype%":gt,"%AsyncFunction%":Xu,"%AsyncGenerator%":Xu,"%AsyncGeneratorFunction%":Xu,"%AsyncIteratorPrototype%":Xu,"%Atomics%":typeof Atomics>"u"?gt:Atomics,"%BigInt%":typeof BigInt>"u"?gt:BigInt,"%BigInt64Array%":typeof BigInt64Array>"u"?gt:BigInt64Array,"%BigUint64Array%":typeof BigUint64Array>"u"?gt:BigUint64Array,"%Boolean%":Boolean,"%DataView%":typeof DataView>"u"?gt:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":M$,"%eval%":eval,"%EvalError%":F$,"%Float16Array%":typeof Float16Array>"u"?gt:Float16Array,"%Float32Array%":typeof Float32Array>"u"?gt:Float32Array,"%Float64Array%":typeof Float64Array>"u"?gt:Float64Array,"%FinalizationRegistry%":typeof FinalizationRegistry>"u"?gt:FinalizationRegistry,"%Function%":BN,"%GeneratorFunction%":Xu,"%Int8Array%":typeof Int8Array>"u"?gt:Int8Array,"%Int16Array%":typeof Int16Array>"u"?gt:Int16Array,"%Int32Array%":typeof Int32Array>"u"?gt:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":Ku&&Tr?Tr(Tr([][Symbol.iterator]())):gt,"%JSON%":typeof JSON=="object"?JSON:gt,"%Map%":typeof Map>"u"?gt:Map,"%MapIteratorPrototype%":typeof Map>"u"||!Ku||!Tr?gt:Tr(new Map()[Symbol.iterator]()),"%Math%":Math,"%Number%":Number,"%Object%":N$,"%Object.getOwnPropertyDescriptor%":Ah,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":typeof Promise>"u"?gt:Promise,"%Proxy%":typeof Proxy>"u"?gt:Proxy,"%RangeError%":k$,"%ReferenceError%":x$,"%Reflect%":typeof Reflect>"u"?gt:Reflect,"%RegExp%":RegExp,"%Set%":typeof Set>"u"?gt:Set,"%SetIteratorPrototype%":typeof Set>"u"||!Ku||!Tr?gt:Tr(new Set()[Symbol.iterator]()),"%SharedArrayBuffer%":typeof SharedArrayBuffer>"u"?gt:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":Ku&&Tr?Tr(""[Symbol.iterator]()):gt,"%Symbol%":Ku?Symbol:gt,"%SyntaxError%":$u,"%ThrowTypeError%":V$,"%TypedArray%":z$,"%TypeError%":Zu,"%Uint8Array%":typeof Uint8Array>"u"?gt:Uint8Array,"%Uint8ClampedArray%":typeof Uint8ClampedArray>"u"?gt:Uint8ClampedArray,"%Uint16Array%":typeof Uint16Array>"u"?gt:Uint16Array,"%Uint32Array%":typeof Uint32Array>"u"?gt:Uint32Array,"%URIError%":U$,"%WeakMap%":typeof WeakMap>"u"?gt:WeakMap,"%WeakRef%":typeof WeakRef>"u"?gt:WeakRef,"%WeakSet%":typeof WeakSet>"u"?gt:WeakSet,"%Function.prototype.call%":fh,"%Function.prototype.apply%":IN,"%Object.defineProperty%":W$,"%Object.getPrototypeOf%":J$,"%Math.abs%":L$,"%Math.floor%":P$,"%Math.max%":O$,"%Math.min%":H$,"%Math.pow%":q$,"%Math.round%":G$,"%Math.sign%":Y$,"%Reflect.getPrototypeOf%":j$};if(Tr)try{null.error}catch(e){EN=Tr(Tr(e)),ef["%Error.prototype%"]=EN}var EN,K$=function e(t){var r;if(t==="%AsyncFunction%")r=nb("async function () {}");else if(t==="%GeneratorFunction%")r=nb("function* () {}");else if(t==="%AsyncGeneratorFunction%")r=nb("async function* () {}");else if(t==="%AsyncGenerator%"){var n=e("%AsyncGeneratorFunction%");n&&(r=n.prototype)}else if(t==="%AsyncIteratorPrototype%"){var i=e("%AsyncGenerator%");i&&Tr&&(r=Tr(i.prototype))}return ef[t]=r,r},yN={__proto__:null,"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},uh=zu(),X0=rb(),X$=uh.call(fh,Array.prototype.concat),Z$=uh.call(IN,Array.prototype.splice),mN=uh.call(fh,String.prototype.replace),Z0=uh.call(fh,String.prototype.slice),$$=uh.call(fh,RegExp.prototype.exec),eee=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,tee=/\\(\\)?/g,ree=function(t){var r=Z0(t,0,1),n=Z0(t,-1);if(r==="%"&&n!=="%")throw new $u("invalid intrinsic syntax, expected closing `%`");if(n==="%"&&r!=="%")throw new $u("invalid intrinsic syntax, expected opening `%`");var i=[];return mN(t,eee,function(s,o,a,A){i[i.length]=a?mN(A,tee,"$1"):o||s}),i},nee=function(t,r){var n=t,i;if(X0(yN,n)&&(i=yN[n],n="%"+i[0]+"%"),X0(ef,n)){var s=ef[n];if(s===Xu&&(s=K$(n)),typeof s>"u"&&!r)throw new Zu("intrinsic "+t+" exists, but is not available. Please file an issue!");return{alias:i,name:n,value:s}}throw new $u("intrinsic "+t+" does not exist!")};bN.exports=function(t,r){if(typeof t!="string"||t.length===0)throw new Zu("intrinsic name must be a non-empty string");if(arguments.length>1&&typeof r!="boolean")throw new Zu('"allowMissing" argument must be a boolean');if($$(/^%?[^%]*%?$/,t)===null)throw new $u("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var n=ree(t),i=n.length>0?n[0]:"",s=nee("%"+i+"%",r),o=s.name,a=s.value,A=!1,f=s.alias;f&&(i=f[0],Z$(n,X$([0,1],f)));for(var l=1,p=!0;l=n.length){var N=Ah(a,B);p=!!N,p&&"get"in N&&!("originalValue"in N.get)?a=N.get:a=a[B]}else p=X0(a,B),a=a[B];p&&!A&&(ef[o]=a)}}return a}});var Js=x((YRe,wN)=>{"use strict";var CN=ec(),QN=z0(),iee=QN([CN("%String.prototype.indexOf%")]);wN.exports=function(t,r){var n=CN(t,!!r);return typeof n=="function"&&iee(t,".prototype.")>-1?QN([n]):n}});var vN=x((WRe,_N)=>{"use strict";var see=oh()(),oee=Js(),sb=oee("Object.prototype.toString"),$0=function(t){return see&&t&&typeof t=="object"&&Symbol.toStringTag in t?!1:sb(t)==="[object Arguments]"},SN=function(t){return $0(t)?!0:t!==null&&typeof t=="object"&&"length"in t&&typeof t.length=="number"&&t.length>=0&&sb(t)!=="[object Array]"&&"callee"in t&&sb(t.callee)==="[object Function]"},aee=(function(){return $0(arguments)})();$0.isLegacyArguments=SN;_N.exports=aee?$0:SN});var FN=x((VRe,MN)=>{"use strict";var RN=Js(),Aee=oh()(),fee=rb(),uee=$A(),Ab;Aee?(DN=RN("RegExp.prototype.exec"),ob={},ep=function(){throw ob},ab={toString:ep,valueOf:ep},typeof Symbol.toPrimitive=="symbol"&&(ab[Symbol.toPrimitive]=ep),Ab=function(t){if(!t||typeof t!="object")return!1;var r=uee(t,"lastIndex"),n=r&&fee(r,"value");if(!n)return!1;try{DN(t,ab)}catch(i){return i===ob}}):(TN=RN("Object.prototype.toString"),NN="[object RegExp]",Ab=function(t){return!t||typeof t!="object"&&typeof t!="function"?!1:TN(t)===NN});var DN,ob,ep,ab,TN,NN;MN.exports=Ab});var xN=x((JRe,kN)=>{"use strict";var cee=Js(),lee=FN(),hee=cee("RegExp.prototype.exec"),dee=$i();kN.exports=function(t){if(!lee(t))throw new dee("`regex` must be a RegExp");return function(n){return hee(t,n)!==null}}});var LN=x((jRe,UN)=>{"use strict";var gee=function*(){}.constructor;UN.exports=()=>gee});var qN=x((zRe,HN)=>{"use strict";var ON=Js(),pee=xN(),Eee=pee(/^\s*(?:function)?\*/),yee=oh()(),PN=K0(),mee=ON("Object.prototype.toString"),Bee=ON("Function.prototype.toString"),Iee=LN();HN.exports=function(t){if(typeof t!="function")return!1;if(Eee(Bee(t)))return!0;if(!yee){var r=mee(t);return r==="[object GeneratorFunction]"}if(!PN)return!1;var n=Iee();return n&&PN(t)===n.prototype}});var VN=x((KRe,WN)=>{"use strict";var YN=Function.prototype.toString,tc=typeof Reflect=="object"&&Reflect!==null&&Reflect.apply,ub,tp;if(typeof tc=="function"&&typeof Object.defineProperty=="function")try{ub=Object.defineProperty({},"length",{get:function(){throw tp}}),tp={},tc(function(){throw 42},null,ub)}catch(e){e!==tp&&(tc=null)}else tc=null;var bee=/^\s*class\b/,cb=function(t){try{var r=YN.call(t);return bee.test(r)}catch{return!1}},fb=function(t){try{return cb(t)?!1:(YN.call(t),!0)}catch{return!1}},rp=Object.prototype.toString,Cee="[object Object]",Qee="[object Function]",wee="[object GeneratorFunction]",See="[object HTMLAllCollection]",_ee="[object HTML document.all class]",vee="[object HTMLCollection]",Ree=typeof Symbol=="function"&&!!Symbol.toStringTag,Dee=!(0 in[,]),lb=function(){return!1};typeof document=="object"&&(GN=document.all,rp.call(GN)===rp.call(document.all)&&(lb=function(t){if((Dee||!t)&&(typeof t>"u"||typeof t=="object"))try{var r=rp.call(t);return(r===See||r===_ee||r===vee||r===Cee)&&t("")==null}catch{}return!1}));var GN;WN.exports=tc?function(t){if(lb(t))return!0;if(!t||typeof t!="function"&&typeof t!="object")return!1;try{tc(t,null,ub)}catch(r){if(r!==tp)return!1}return!cb(t)&&fb(t)}:function(t){if(lb(t))return!0;if(!t||typeof t!="function"&&typeof t!="object")return!1;if(Ree)return fb(t);if(cb(t))return!1;var r=rp.call(t);return r!==Qee&&r!==wee&&!/^\[object HTML/.test(r)?!1:fb(t)}});var zN=x((XRe,jN)=>{"use strict";var Tee=VN(),Nee=Object.prototype.toString,JN=Object.prototype.hasOwnProperty,Mee=function(t,r,n){for(var i=0,s=t.length;i=3&&(i=n),xee(t)?Mee(t,r,i):typeof t=="string"?Fee(t,r,i):kee(t,r,i)}});var XN=x((ZRe,KN)=>{"use strict";KN.exports=["Float16Array","Float32Array","Float64Array","Int8Array","Int16Array","Int32Array","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array"]});var $N=x(($Re,ZN)=>{"use strict";var hb=XN(),Uee=globalThis;ZN.exports=function(){for(var t=[],r=0;r{"use strict";var eM=ah(),Lee=XI(),rc=$i(),tM=$A();rM.exports=function(t,r,n){if(!t||typeof t!="object"&&typeof t!="function")throw new rc("`obj` must be an object or a function`");if(typeof r!="string"&&typeof r!="symbol")throw new rc("`property` must be a string or a symbol`");if(arguments.length>3&&typeof arguments[3]!="boolean"&&arguments[3]!==null)throw new rc("`nonEnumerable`, if provided, must be a boolean or null");if(arguments.length>4&&typeof arguments[4]!="boolean"&&arguments[4]!==null)throw new rc("`nonWritable`, if provided, must be a boolean or null");if(arguments.length>5&&typeof arguments[5]!="boolean"&&arguments[5]!==null)throw new rc("`nonConfigurable`, if provided, must be a boolean or null");if(arguments.length>6&&typeof arguments[6]!="boolean")throw new rc("`loose`, if provided, must be a boolean");var i=arguments.length>3?arguments[3]:null,s=arguments.length>4?arguments[4]:null,o=arguments.length>5?arguments[5]:null,a=arguments.length>6?arguments[6]:!1,A=!!tM&&tM(t,r);if(eM)eM(t,r,{configurable:o===null&&A?A.configurable:!o,enumerable:i===null&&A?A.enumerable:!i,value:n,writable:s===null&&A?A.writable:!s});else if(a||!i&&!s&&!o)t[r]=n;else throw new Lee("This environment does not support defining a property as non-configurable, non-writable, or non-enumerable.")}});var pb=x((tDe,iM)=>{"use strict";var gb=ah(),nM=function(){return!!gb};nM.hasArrayLengthDefineBug=function(){if(!gb)return null;try{return gb([],"length",{value:1}).length!==1}catch{return!0}};iM.exports=nM});var fM=x((rDe,AM)=>{"use strict";var Pee=ec(),sM=db(),Oee=pb()(),oM=$A(),aM=$i(),Hee=Pee("%Math.floor%");AM.exports=function(t,r){if(typeof t!="function")throw new aM("`fn` is not a function");if(typeof r!="number"||r<0||r>4294967295||Hee(r)!==r)throw new aM("`length` must be a positive 32-bit integer");var n=arguments.length>2&&!!arguments[2],i=!0,s=!0;if("length"in t&&oM){var o=oM(t,"length");o&&!o.configurable&&(i=!1),o&&!o.writable&&(s=!1)}return(i||s||!n)&&(Oee?sM(t,"length",r,!0,!0):sM(t,"length",r)),t}});var cM=x((nDe,uM)=>{"use strict";var qee=zu(),Gee=j0(),Yee=eb();uM.exports=function(){return Yee(qee,Gee,arguments)}});var ch=x((iDe,np)=>{"use strict";var Wee=fM(),lM=ah(),Vee=z0(),hM=cM();np.exports=function(t){var r=Vee(arguments),n=t.length-(arguments.length-1);return Wee(r,1+(n>0?n:0),!0)};lM?lM(np.exports,"apply",{value:hM}):np.exports.apply=hM});var Bb=x((sDe,EM)=>{"use strict";var op=zN(),Jee=$N(),dM=ch(),yb=Js(),sp=$A(),ip=K0(),jee=yb("Object.prototype.toString"),pM=oh()(),gM=globalThis,Eb=Jee(),mb=yb("String.prototype.slice"),zee=yb("Array.prototype.indexOf",!0)||function(t,r){for(var n=0;n-1?r:r!=="Object"?!1:Xee(t)}return sp?Kee(t):null}});var Ib=x((oDe,yM)=>{"use strict";var Zee=Bb();yM.exports=function(t){return!!Zee(t)}});var NM=x(pt=>{"use strict";var $ee=vN(),ete=qN(),es=Bb(),mM=Ib();function nc(e){return e.call.bind(e)}var BM=typeof BigInt<"u",IM=typeof Symbol<"u",li=nc(Object.prototype.toString),tte=nc(Number.prototype.valueOf),rte=nc(String.prototype.valueOf),nte=nc(Boolean.prototype.valueOf);BM&&(bM=nc(BigInt.prototype.valueOf));var bM;IM&&(CM=nc(Symbol.prototype.valueOf));var CM;function hh(e,t){if(typeof e!="object")return!1;try{return t(e),!0}catch{return!1}}pt.isArgumentsObject=$ee;pt.isGeneratorFunction=ete;pt.isTypedArray=mM;function ite(e){return typeof Promise<"u"&&e instanceof Promise||e!==null&&typeof e=="object"&&typeof e.then=="function"&&typeof e.catch=="function"}pt.isPromise=ite;function ste(e){return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?ArrayBuffer.isView(e):mM(e)||wM(e)}pt.isArrayBufferView=ste;function ote(e){return es(e)==="Uint8Array"}pt.isUint8Array=ote;function ate(e){return es(e)==="Uint8ClampedArray"}pt.isUint8ClampedArray=ate;function Ate(e){return es(e)==="Uint16Array"}pt.isUint16Array=Ate;function fte(e){return es(e)==="Uint32Array"}pt.isUint32Array=fte;function ute(e){return es(e)==="Int8Array"}pt.isInt8Array=ute;function cte(e){return es(e)==="Int16Array"}pt.isInt16Array=cte;function lte(e){return es(e)==="Int32Array"}pt.isInt32Array=lte;function hte(e){return es(e)==="Float32Array"}pt.isFloat32Array=hte;function dte(e){return es(e)==="Float64Array"}pt.isFloat64Array=dte;function gte(e){return es(e)==="BigInt64Array"}pt.isBigInt64Array=gte;function pte(e){return es(e)==="BigUint64Array"}pt.isBigUint64Array=pte;function Ap(e){return li(e)==="[object Map]"}Ap.working=typeof Map<"u"&&Ap(new Map);function Ete(e){return typeof Map>"u"?!1:Ap.working?Ap(e):e instanceof Map}pt.isMap=Ete;function fp(e){return li(e)==="[object Set]"}fp.working=typeof Set<"u"&&fp(new Set);function yte(e){return typeof Set>"u"?!1:fp.working?fp(e):e instanceof Set}pt.isSet=yte;function up(e){return li(e)==="[object WeakMap]"}up.working=typeof WeakMap<"u"&&up(new WeakMap);function mte(e){return typeof WeakMap>"u"?!1:up.working?up(e):e instanceof WeakMap}pt.isWeakMap=mte;function Cb(e){return li(e)==="[object WeakSet]"}Cb.working=typeof WeakSet<"u"&&Cb(new WeakSet);function Bte(e){return Cb(e)}pt.isWeakSet=Bte;function cp(e){return li(e)==="[object ArrayBuffer]"}cp.working=typeof ArrayBuffer<"u"&&cp(new ArrayBuffer);function QM(e){return typeof ArrayBuffer>"u"?!1:cp.working?cp(e):e instanceof ArrayBuffer}pt.isArrayBuffer=QM;function lp(e){return li(e)==="[object DataView]"}lp.working=typeof ArrayBuffer<"u"&&typeof DataView<"u"&&lp(new DataView(new ArrayBuffer(1),0,1));function wM(e){return typeof DataView>"u"?!1:lp.working?lp(e):e instanceof DataView}pt.isDataView=wM;var bb=typeof SharedArrayBuffer<"u"?SharedArrayBuffer:void 0;function lh(e){return li(e)==="[object SharedArrayBuffer]"}function SM(e){return typeof bb>"u"?!1:(typeof lh.working>"u"&&(lh.working=lh(new bb)),lh.working?lh(e):e instanceof bb)}pt.isSharedArrayBuffer=SM;function Ite(e){return li(e)==="[object AsyncFunction]"}pt.isAsyncFunction=Ite;function bte(e){return li(e)==="[object Map Iterator]"}pt.isMapIterator=bte;function Cte(e){return li(e)==="[object Set Iterator]"}pt.isSetIterator=Cte;function Qte(e){return li(e)==="[object Generator]"}pt.isGeneratorObject=Qte;function wte(e){return li(e)==="[object WebAssembly.Module]"}pt.isWebAssemblyCompiledModule=wte;function _M(e){return hh(e,tte)}pt.isNumberObject=_M;function vM(e){return hh(e,rte)}pt.isStringObject=vM;function RM(e){return hh(e,nte)}pt.isBooleanObject=RM;function DM(e){return BM&&hh(e,bM)}pt.isBigIntObject=DM;function TM(e){return IM&&hh(e,CM)}pt.isSymbolObject=TM;function Ste(e){return _M(e)||vM(e)||RM(e)||DM(e)||TM(e)}pt.isBoxedPrimitive=Ste;function _te(e){return typeof Uint8Array<"u"&&(QM(e)||SM(e))}pt.isAnyArrayBuffer=_te;["isProxy","isExternal","isModuleNamespaceObject"].forEach(function(e){Object.defineProperty(pt,e,{enumerable:!1,value:function(){return!1}})})});var FM=x((ADe,MM)=>{MM.exports=function(t){return t&&typeof t=="object"&&typeof t.copy=="function"&&typeof t.fill=="function"&&typeof t.readUInt8=="function"}});var Yr=x(Et=>{var kM=Object.getOwnPropertyDescriptors||function(t){for(var r=Object.keys(t),n={},i=0;i=i)return a;switch(a){case"%s":return String(n[r++]);case"%d":return Number(n[r++]);case"%j":try{return JSON.stringify(n[r++])}catch{return"[Circular]"}default:return a}}),o=n[r];r"u")return function(){return Et.deprecate(e,t).apply(this,arguments)};var r=!1;function n(){if(!r){if(process.throwDeprecation)throw new Error(t);process.traceDeprecation?console.trace(t):console.error(t),r=!0}return e.apply(this,arguments)}return n};var hp={},xM=/^$/;process.env.NODE_DEBUG&&(dp=process.env.NODE_DEBUG,dp=dp.replace(/[|\\{}()[\]^$+?.]/g,"\\$&").replace(/\*/g,".*").replace(/,/g,"$|^").toUpperCase(),xM=new RegExp("^"+dp+"$","i"));var dp;Et.debuglog=function(e){if(e=e.toUpperCase(),!hp[e])if(xM.test(e)){var t=process.pid;hp[e]=function(){var r=Et.format.apply(Et,arguments);console.error("%s %d: %s",e,t,r)}}else hp[e]=function(){};return hp[e]};function za(e,t){var r={seen:[],stylize:Dte};return arguments.length>=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),_b(t)?r.showHidden=t:t&&Et._extend(r,t),rf(r.showHidden)&&(r.showHidden=!1),rf(r.depth)&&(r.depth=2),rf(r.colors)&&(r.colors=!1),rf(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=Rte),pp(r,e,r.depth)}Et.inspect=za;za.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]};za.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"};function Rte(e,t){var r=za.styles[t];return r?"\x1B["+za.colors[r][0]+"m"+e+"\x1B["+za.colors[r][1]+"m":e}function Dte(e,t){return e}function Tte(e){var t={};return e.forEach(function(r,n){t[r]=!0}),t}function pp(e,t,r){if(e.customInspect&&t&&gp(t.inspect)&&t.inspect!==Et.inspect&&!(t.constructor&&t.constructor.prototype===t)){var n=t.inspect(r,e);return mp(n)||(n=pp(e,n,r)),n}var i=Nte(e,t);if(i)return i;var s=Object.keys(t),o=Tte(s);if(e.showHidden&&(s=Object.getOwnPropertyNames(t)),gh(t)&&(s.indexOf("message")>=0||s.indexOf("description")>=0))return Qb(t);if(s.length===0){if(gp(t)){var a=t.name?": "+t.name:"";return e.stylize("[Function"+a+"]","special")}if(dh(t))return e.stylize(RegExp.prototype.toString.call(t),"regexp");if(Ep(t))return e.stylize(Date.prototype.toString.call(t),"date");if(gh(t))return Qb(t)}var A="",f=!1,l=["{","}"];if(UM(t)&&(f=!0,l=["[","]"]),gp(t)){var p=t.name?": "+t.name:"";A=" [Function"+p+"]"}if(dh(t)&&(A=" "+RegExp.prototype.toString.call(t)),Ep(t)&&(A=" "+Date.prototype.toUTCString.call(t)),gh(t)&&(A=" "+Qb(t)),s.length===0&&(!f||t.length==0))return l[0]+A+l[1];if(r<0)return dh(t)?e.stylize(RegExp.prototype.toString.call(t),"regexp"):e.stylize("[Object]","special");e.seen.push(t);var B;return f?B=Mte(e,t,r,o,s):B=s.map(function(S){return Sb(e,t,r,o,S,f)}),e.seen.pop(),Fte(B,A,l)}function Nte(e,t){if(rf(t))return e.stylize("undefined","undefined");if(mp(t)){var r="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(r,"string")}if(LM(t))return e.stylize(""+t,"number");if(_b(t))return e.stylize(""+t,"boolean");if(yp(t))return e.stylize("null","null")}function Qb(e){return"["+Error.prototype.toString.call(e)+"]"}function Mte(e,t,r,n,i){for(var s=[],o=0,a=t.length;o-1&&(s?a=a.split(` -`).map(function(f){return" "+f}).join(` -`).slice(2):a=` -`+a.split(` -`).map(function(f){return" "+f}).join(` -`))):a=e.stylize("[Circular]","special")),rf(o)){if(s&&i.match(/^\d+$/))return a;o=JSON.stringify(""+i),o.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(o=o.slice(1,-1),o=e.stylize(o,"name")):(o=o.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),o=e.stylize(o,"string"))}return o+": "+a}function Fte(e,t,r){var n=0,i=e.reduce(function(s,o){return n++,o.indexOf(` -`)>=0&&n++,s+o.replace(/\u001b\[\d\d?m/g,"").length+1},0);return i>60?r[0]+(t===""?"":t+` - `)+" "+e.join(`, - `)+" "+r[1]:r[0]+t+" "+e.join(", ")+" "+r[1]}Et.types=NM();function UM(e){return Array.isArray(e)}Et.isArray=UM;function _b(e){return typeof e=="boolean"}Et.isBoolean=_b;function yp(e){return e===null}Et.isNull=yp;function kte(e){return e==null}Et.isNullOrUndefined=kte;function LM(e){return typeof e=="number"}Et.isNumber=LM;function mp(e){return typeof e=="string"}Et.isString=mp;function xte(e){return typeof e=="symbol"}Et.isSymbol=xte;function rf(e){return e===void 0}Et.isUndefined=rf;function dh(e){return ic(e)&&vb(e)==="[object RegExp]"}Et.isRegExp=dh;Et.types.isRegExp=dh;function ic(e){return typeof e=="object"&&e!==null}Et.isObject=ic;function Ep(e){return ic(e)&&vb(e)==="[object Date]"}Et.isDate=Ep;Et.types.isDate=Ep;function gh(e){return ic(e)&&(vb(e)==="[object Error]"||e instanceof Error)}Et.isError=gh;Et.types.isNativeError=gh;function gp(e){return typeof e=="function"}Et.isFunction=gp;function Ute(e){return e===null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"||typeof e=="symbol"||typeof e>"u"}Et.isPrimitive=Ute;Et.isBuffer=FM();function vb(e){return Object.prototype.toString.call(e)}function wb(e){return e<10?"0"+e.toString(10):e.toString(10)}var Lte=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function Pte(){var e=new Date,t=[wb(e.getHours()),wb(e.getMinutes()),wb(e.getSeconds())].join(":");return[e.getDate(),Lte[e.getMonth()],t].join(" ")}Et.log=function(){console.log("%s - %s",Pte(),Et.format.apply(Et,arguments))};Et.inherits=ze();Et._extend=function(e,t){if(!t||!ic(t))return e;for(var r=Object.keys(t),n=r.length;n--;)e[r[n]]=t[r[n]];return e};function PM(e,t){return Object.prototype.hasOwnProperty.call(e,t)}var tf=typeof Symbol<"u"?Symbol("util.promisify.custom"):void 0;Et.promisify=function(t){if(typeof t!="function")throw new TypeError('The "original" argument must be of type Function');if(tf&&t[tf]){var r=t[tf];if(typeof r!="function")throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(r,tf,{value:r,enumerable:!1,writable:!1,configurable:!0}),r}function r(){for(var n,i,s=new Promise(function(A,f){n=A,i=f}),o=[],a=0;a{"use strict";function OM(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),r.push.apply(r,n)}return r}function HM(e){for(var t=1;t0?this.tail.next=n:this.head=n,this.tail=n,++this.length}},{key:"unshift",value:function(r){var n={data:r,next:this.head};this.length===0&&(this.tail=n),this.head=n,++this.length}},{key:"shift",value:function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(r){if(this.length===0)return"";for(var n=this.head,i=""+n.data;n=n.next;)i+=r+n.data;return i}},{key:"concat",value:function(r){if(this.length===0)return Bp.alloc(0);for(var n=Bp.allocUnsafe(r>>>0),i=this.head,s=0;i;)zte(i.data,n,s),s+=i.data.length,i=i.next;return n}},{key:"consume",value:function(r,n){var i;return ro.length?o.length:r;if(a===o.length?s+=o:s+=o.slice(0,r),r-=a,r===0){a===o.length?(++i,n.next?this.head=n.next:this.head=this.tail=null):(this.head=n,n.data=o.slice(a));break}++i}return this.length-=i,s}},{key:"_getBuffer",value:function(r){var n=Bp.allocUnsafe(r),i=this.head,s=1;for(i.data.copy(n),r-=i.data.length;i=i.next;){var o=i.data,a=r>o.length?o.length:r;if(o.copy(n,n.length-r,0,a),r-=a,r===0){a===o.length?(++s,i.next?this.head=i.next:this.head=this.tail=null):(this.head=i,i.data=o.slice(a));break}++s}return this.length-=s,n}},{key:jte,value:function(r,n){return Rb(this,HM(HM({},n),{},{depth:0,customInspect:!1}))}}]),e})()});var Tb=x((cDe,JM)=>{"use strict";function Kte(e,t){var r=this,n=this._readableState&&this._readableState.destroyed,i=this._writableState&&this._writableState.destroyed;return n||i?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(Db,this,e)):process.nextTick(Db,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(s){!t&&s?r._writableState?r._writableState.errorEmitted?process.nextTick(Ip,r):(r._writableState.errorEmitted=!0,process.nextTick(VM,r,s)):process.nextTick(VM,r,s):t?(process.nextTick(Ip,r),t(s)):process.nextTick(Ip,r)}),this)}function VM(e,t){Db(e,t),Ip(e)}function Ip(e){e._writableState&&!e._writableState.emitClose||e._readableState&&!e._readableState.emitClose||e.emit("close")}function Xte(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function Db(e,t){e.emit("error",t)}function Zte(e,t){var r=e._readableState,n=e._writableState;r&&r.autoDestroy||n&&n.autoDestroy?e.destroy(t):e.emit("error",t)}JM.exports={destroy:Kte,undestroy:Xte,errorOrDestroy:Zte}});var nf=x((lDe,KM)=>{"use strict";function $te(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}var zM={};function hi(e,t,r){r||(r=Error);function n(s,o,a){return typeof t=="string"?t:t(s,o,a)}var i=(function(s){$te(o,s);function o(a,A,f){return s.call(this,n(a,A,f))||this}return o})(r);i.prototype.name=r.name,i.prototype.code=e,zM[e]=i}function jM(e,t){if(Array.isArray(e)){var r=e.length;return e=e.map(function(n){return String(n)}),r>2?"one of ".concat(t," ").concat(e.slice(0,r-1).join(", "),", or ")+e[r-1]:r===2?"one of ".concat(t," ").concat(e[0]," or ").concat(e[1]):"of ".concat(t," ").concat(e[0])}else return"of ".concat(t," ").concat(String(e))}function ere(e,t,r){return e.substr(!r||r<0?0:+r,t.length)===t}function tre(e,t,r){return(r===void 0||r>e.length)&&(r=e.length),e.substring(r-t.length,r)===t}function rre(e,t,r){return typeof r!="number"&&(r=0),r+t.length>e.length?!1:e.indexOf(t,r)!==-1}hi("ERR_INVALID_OPT_VALUE",function(e,t){return'The value "'+t+'" is invalid for option "'+e+'"'},TypeError);hi("ERR_INVALID_ARG_TYPE",function(e,t,r){var n;typeof t=="string"&&ere(t,"not ")?(n="must not be",t=t.replace(/^not /,"")):n="must be";var i;if(tre(e," argument"))i="The ".concat(e," ").concat(n," ").concat(jM(t,"type"));else{var s=rre(e,".")?"property":"argument";i='The "'.concat(e,'" ').concat(s," ").concat(n," ").concat(jM(t,"type"))}return i+=". Received type ".concat(typeof r),i},TypeError);hi("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF");hi("ERR_METHOD_NOT_IMPLEMENTED",function(e){return"The "+e+" method is not implemented"});hi("ERR_STREAM_PREMATURE_CLOSE","Premature close");hi("ERR_STREAM_DESTROYED",function(e){return"Cannot call "+e+" after a stream was destroyed"});hi("ERR_MULTIPLE_CALLBACK","Callback called multiple times");hi("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable");hi("ERR_STREAM_WRITE_AFTER_END","write after end");hi("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError);hi("ERR_UNKNOWN_ENCODING",function(e){return"Unknown encoding: "+e},TypeError);hi("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event");KM.exports.codes=zM});var Nb=x((hDe,XM)=>{"use strict";var nre=nf().codes.ERR_INVALID_OPT_VALUE;function ire(e,t,r){return e.highWaterMark!=null?e.highWaterMark:t?e[r]:null}function sre(e,t,r,n){var i=ire(t,n,r);if(i!=null){if(!(isFinite(i)&&Math.floor(i)===i)||i<0){var s=n?r:"highWaterMark";throw new nre(s,i)}return Math.floor(i)}return e.objectMode?16:16*1024}XM.exports={getHighWaterMark:sre}});var Fb=x((dDe,ZM)=>{ZM.exports=ore;function ore(e,t){if(Mb("noDeprecation"))return e;var r=!1;function n(){if(!r){if(Mb("throwDeprecation"))throw new Error(t);Mb("traceDeprecation")?console.trace(t):console.warn(t),r=!0}return e.apply(this,arguments)}return n}function Mb(e){try{if(!globalThis.localStorage)return!1}catch{return!1}var t=globalThis.localStorage[e];return t==null?!1:String(t).toLowerCase()==="true"}});var Ub=x((gDe,iF)=>{"use strict";iF.exports=Ar;function eF(e){var t=this;this.next=null,this.entry=null,this.finish=function(){Mre(t,e)}}var sc;Ar.WritableState=Eh;var are={deprecate:Fb()},tF=KI(),Cp=Gr().Buffer,Are=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function fre(e){return Cp.from(e)}function ure(e){return Cp.isBuffer(e)||e instanceof Are}var xb=Tb(),cre=Nb(),lre=cre.getHighWaterMark,Ka=nf().codes,hre=Ka.ERR_INVALID_ARG_TYPE,dre=Ka.ERR_METHOD_NOT_IMPLEMENTED,gre=Ka.ERR_MULTIPLE_CALLBACK,pre=Ka.ERR_STREAM_CANNOT_PIPE,Ere=Ka.ERR_STREAM_DESTROYED,yre=Ka.ERR_STREAM_NULL_VALUES,mre=Ka.ERR_STREAM_WRITE_AFTER_END,Bre=Ka.ERR_UNKNOWN_ENCODING,oc=xb.errorOrDestroy;ze()(Ar,tF);function Ire(){}function Eh(e,t,r){sc=sc||sf(),e=e||{},typeof r!="boolean"&&(r=t instanceof sc),this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode),this.highWaterMark=lre(this,e,"writableHighWaterMark",r),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var n=e.decodeStrings===!1;this.decodeStrings=!n,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(i){vre(t,i)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new eF(this)}Eh.prototype.getBuffer=function(){for(var t=this.bufferedRequest,r=[];t;)r.push(t),t=t.next;return r};(function(){try{Object.defineProperty(Eh.prototype,"buffer",{get:are.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch{}})();var bp;typeof Symbol=="function"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]=="function"?(bp=Function.prototype[Symbol.hasInstance],Object.defineProperty(Ar,Symbol.hasInstance,{value:function(t){return bp.call(this,t)?!0:this!==Ar?!1:t&&t._writableState instanceof Eh}})):bp=function(t){return t instanceof this};function Ar(e){sc=sc||sf();var t=this instanceof sc;if(!t&&!bp.call(Ar,this))return new Ar(e);this._writableState=new Eh(e,this,t),this.writable=!0,e&&(typeof e.write=="function"&&(this._write=e.write),typeof e.writev=="function"&&(this._writev=e.writev),typeof e.destroy=="function"&&(this._destroy=e.destroy),typeof e.final=="function"&&(this._final=e.final)),tF.call(this)}Ar.prototype.pipe=function(){oc(this,new pre)};function bre(e,t){var r=new mre;oc(e,r),process.nextTick(t,r)}function Cre(e,t,r,n){var i;return r===null?i=new yre:typeof r!="string"&&!t.objectMode&&(i=new hre("chunk",["string","Buffer"],r)),i?(oc(e,i),process.nextTick(n,i),!1):!0}Ar.prototype.write=function(e,t,r){var n=this._writableState,i=!1,s=!n.objectMode&&ure(e);return s&&!Cp.isBuffer(e)&&(e=fre(e)),typeof t=="function"&&(r=t,t=null),s?t="buffer":t||(t=n.defaultEncoding),typeof r!="function"&&(r=Ire),n.ending?bre(this,r):(s||Cre(this,n,e,r))&&(n.pendingcb++,i=wre(this,n,s,e,t,r)),i};Ar.prototype.cork=function(){this._writableState.corked++};Ar.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&rF(this,e))};Ar.prototype.setDefaultEncoding=function(t){if(typeof t=="string"&&(t=t.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((t+"").toLowerCase())>-1))throw new Bre(t);return this._writableState.defaultEncoding=t,this};Object.defineProperty(Ar.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function Qre(e,t,r){return!e.objectMode&&e.decodeStrings!==!1&&typeof t=="string"&&(t=Cp.from(t,r)),t}Object.defineProperty(Ar.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function wre(e,t,r,n,i,s){if(!r){var o=Qre(t,n,i);n!==o&&(r=!0,i="buffer",n=o)}var a=t.objectMode?1:n.length;t.length+=a;var A=t.length{"use strict";var Fre=Object.keys||function(e){var t=[];for(var r in e)t.push(r);return t};oF.exports=js;var sF=Ob(),Pb=Ub();ze()(js,sF);for(Lb=Fre(Pb.prototype),Qp=0;Qp{var Sp=Gr(),zs=Sp.Buffer;function aF(e,t){for(var r in e)t[r]=e[r]}zs.from&&zs.alloc&&zs.allocUnsafe&&zs.allocUnsafeSlow?AF.exports=Sp:(aF(Sp,Hb),Hb.Buffer=of);function of(e,t,r){return zs(e,t,r)}of.prototype=Object.create(zs.prototype);aF(zs,of);of.from=function(e,t,r){if(typeof e=="number")throw new TypeError("Argument must not be a number");return zs(e,t,r)};of.alloc=function(e,t,r){if(typeof e!="number")throw new TypeError("Argument must be a number");var n=zs(e);return t!==void 0?typeof r=="string"?n.fill(t,r):n.fill(t):n.fill(0),n};of.allocUnsafe=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return zs(e)};of.allocUnsafeSlow=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return Sp.SlowBuffer(e)}});var af=x(uF=>{"use strict";var Gb=at().Buffer,fF=Gb.isEncoding||function(e){switch(e=""+e,e&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function Ure(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}function Lre(e){var t=Ure(e);if(typeof t!="string"&&(Gb.isEncoding===fF||!fF(e)))throw new Error("Unknown encoding: "+e);return t||e}uF.StringDecoder=yh;function yh(e){this.encoding=Lre(e);var t;switch(this.encoding){case"utf16le":this.text=Yre,this.end=Wre,t=4;break;case"utf8":this.fillLast=Hre,t=4;break;case"base64":this.text=Vre,this.end=Jre,t=3;break;default:this.write=jre,this.end=zre;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=Gb.allocUnsafe(t)}yh.prototype.write=function(e){if(e.length===0)return"";var t,r;if(this.lastNeed){if(t=this.fillLast(e),t===void 0)return"";r=this.lastNeed,this.lastNeed=0}else r=0;return r>5===6?2:e>>4===14?3:e>>3===30?4:e>>6===2?-1:-2}function Pre(e,t,r){var n=t.length-1;if(n=0?(i>0&&(e.lastNeed=i-1),i):--n=0?(i>0&&(e.lastNeed=i-2),i):--n=0?(i>0&&(i===2?i=0:e.lastNeed=i-3),i):0))}function Ore(e,t,r){if((t[0]&192)!==128)return e.lastNeed=0,"\uFFFD";if(e.lastNeed>1&&t.length>1){if((t[1]&192)!==128)return e.lastNeed=1,"\uFFFD";if(e.lastNeed>2&&t.length>2&&(t[2]&192)!==128)return e.lastNeed=2,"\uFFFD"}}function Hre(e){var t=this.lastTotal-this.lastNeed,r=Ore(this,e,t);if(r!==void 0)return r;if(this.lastNeed<=e.length)return e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length}function qre(e,t){var r=Pre(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=r;var n=e.length-(r-this.lastNeed);return e.copy(this.lastChar,0,n),e.toString("utf8",t,n)}function Gre(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"\uFFFD":t}function Yre(e,t){if((e.length-t)%2===0){var r=e.toString("utf16le",t);if(r){var n=r.charCodeAt(r.length-1);if(n>=55296&&n<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function Wre(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,r)}return t}function Vre(e,t){var r=(e.length-t)%3;return r===0?e.toString("base64",t):(this.lastNeed=3-r,this.lastTotal=3,r===1?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-r))}function Jre(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function jre(e){return e.toString(this.encoding)}function zre(e){return e&&e.length?this.write(e):""}});var _p=x((yDe,hF)=>{"use strict";var cF=nf().codes.ERR_STREAM_PREMATURE_CLOSE;function Kre(e){var t=!1;return function(){if(!t){t=!0;for(var r=arguments.length,n=new Array(r),i=0;i{"use strict";var vp;function Xa(e,t,r){return t=$re(t),t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function $re(e){var t=ene(e,"string");return typeof t=="symbol"?t:String(t)}function ene(e,t){if(typeof e!="object"||e===null)return e;var r=e[Symbol.toPrimitive];if(r!==void 0){var n=r.call(e,t||"default");if(typeof n!="object")return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(e)}var tne=_p(),Za=Symbol("lastResolve"),Af=Symbol("lastReject"),mh=Symbol("error"),Rp=Symbol("ended"),ff=Symbol("lastPromise"),Yb=Symbol("handlePromise"),uf=Symbol("stream");function $a(e,t){return{value:e,done:t}}function rne(e){var t=e[Za];if(t!==null){var r=e[uf].read();r!==null&&(e[ff]=null,e[Za]=null,e[Af]=null,t($a(r,!1)))}}function nne(e){process.nextTick(rne,e)}function ine(e,t){return function(r,n){e.then(function(){if(t[Rp]){r($a(void 0,!0));return}t[Yb](r,n)},n)}}var sne=Object.getPrototypeOf(function(){}),one=Object.setPrototypeOf((vp={get stream(){return this[uf]},next:function(){var t=this,r=this[mh];if(r!==null)return Promise.reject(r);if(this[Rp])return Promise.resolve($a(void 0,!0));if(this[uf].destroyed)return new Promise(function(o,a){process.nextTick(function(){t[mh]?a(t[mh]):o($a(void 0,!0))})});var n=this[ff],i;if(n)i=new Promise(ine(n,this));else{var s=this[uf].read();if(s!==null)return Promise.resolve($a(s,!1));i=new Promise(this[Yb])}return this[ff]=i,i}},Xa(vp,Symbol.asyncIterator,function(){return this}),Xa(vp,"return",function(){var t=this;return new Promise(function(r,n){t[uf].destroy(null,function(i){if(i){n(i);return}r($a(void 0,!0))})})}),vp),sne),ane=function(t){var r,n=Object.create(one,(r={},Xa(r,uf,{value:t,writable:!0}),Xa(r,Za,{value:null,writable:!0}),Xa(r,Af,{value:null,writable:!0}),Xa(r,mh,{value:null,writable:!0}),Xa(r,Rp,{value:t._readableState.endEmitted,writable:!0}),Xa(r,Yb,{value:function(s,o){var a=n[uf].read();a?(n[ff]=null,n[Za]=null,n[Af]=null,s($a(a,!1))):(n[Za]=s,n[Af]=o)},writable:!0}),r));return n[ff]=null,tne(t,function(i){if(i&&i.code!=="ERR_STREAM_PREMATURE_CLOSE"){var s=n[Af];s!==null&&(n[ff]=null,n[Za]=null,n[Af]=null,s(i)),n[mh]=i;return}var o=n[Za];o!==null&&(n[ff]=null,n[Za]=null,n[Af]=null,o($a(void 0,!0))),n[Rp]=!0}),t.on("readable",nne.bind(null,n)),n};dF.exports=ane});var EF=x((BDe,pF)=>{pF.exports=function(){throw new Error("Readable.from is not available in the browser")}});var Ob=x((bDe,_F)=>{"use strict";_F.exports=Qt;var ac;Qt.ReadableState=IF;var IDe=Zi().EventEmitter,BF=function(t,r){return t.listeners(r).length},Ih=KI(),Dp=Gr().Buffer,Ane=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function fne(e){return Dp.from(e)}function une(e){return Dp.isBuffer(e)||e instanceof Ane}var Wb=Yr(),dt;Wb&&Wb.debuglog?dt=Wb.debuglog("stream"):dt=function(){};var cne=WM(),Zb=Tb(),lne=Nb(),hne=lne.getHighWaterMark,Tp=nf().codes,dne=Tp.ERR_INVALID_ARG_TYPE,gne=Tp.ERR_STREAM_PUSH_AFTER_EOF,pne=Tp.ERR_METHOD_NOT_IMPLEMENTED,Ene=Tp.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,Ac,Vb,Jb;ze()(Qt,Ih);var Bh=Zb.errorOrDestroy,jb=["error","close","destroy","pause","resume"];function yne(e,t,r){if(typeof e.prependListener=="function")return e.prependListener(t,r);!e._events||!e._events[t]?e.on(t,r):Array.isArray(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]}function IF(e,t,r){ac=ac||sf(),e=e||{},typeof r!="boolean"&&(r=t instanceof ac),this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.readableObjectMode),this.highWaterMark=hne(this,e,"readableHighWaterMark",r),this.buffer=new cne,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(Ac||(Ac=af().StringDecoder),this.decoder=new Ac(e.encoding),this.encoding=e.encoding)}function Qt(e){if(ac=ac||sf(),!(this instanceof Qt))return new Qt(e);var t=this instanceof ac;this._readableState=new IF(e,this,t),this.readable=!0,e&&(typeof e.read=="function"&&(this._read=e.read),typeof e.destroy=="function"&&(this._destroy=e.destroy)),Ih.call(this)}Object.defineProperty(Qt.prototype,"destroyed",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(t){this._readableState&&(this._readableState.destroyed=t)}});Qt.prototype.destroy=Zb.destroy;Qt.prototype._undestroy=Zb.undestroy;Qt.prototype._destroy=function(e,t){t(e)};Qt.prototype.push=function(e,t){var r=this._readableState,n;return r.objectMode?n=!0:typeof e=="string"&&(t=t||r.defaultEncoding,t!==r.encoding&&(e=Dp.from(e,t),t=""),n=!0),bF(this,e,t,!1,n)};Qt.prototype.unshift=function(e){return bF(this,e,null,!0,!1)};function bF(e,t,r,n,i){dt("readableAddChunk",t);var s=e._readableState;if(t===null)s.reading=!1,Ine(e,s);else{var o;if(i||(o=mne(s,t)),o)Bh(e,o);else if(s.objectMode||t&&t.length>0)if(typeof t!="string"&&!s.objectMode&&Object.getPrototypeOf(t)!==Dp.prototype&&(t=fne(t)),n)s.endEmitted?Bh(e,new Ene):zb(e,s,t,!0);else if(s.ended)Bh(e,new gne);else{if(s.destroyed)return!1;s.reading=!1,s.decoder&&!r?(t=s.decoder.write(t),s.objectMode||t.length!==0?zb(e,s,t,!1):Xb(e,s)):zb(e,s,t,!1)}else n||(s.reading=!1,Xb(e,s))}return!s.ended&&(s.length=yF?e=yF:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function mF(e,t){return e<=0||t.length===0&&t.ended?0:t.objectMode?1:e!==e?t.flowing&&t.length?t.buffer.head.data.length:t.length:(e>t.highWaterMark&&(t.highWaterMark=Bne(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}Qt.prototype.read=function(e){dt("read",e),e=parseInt(e,10);var t=this._readableState,r=e;if(e!==0&&(t.emittedReadable=!1),e===0&&t.needReadable&&((t.highWaterMark!==0?t.length>=t.highWaterMark:t.length>0)||t.ended))return dt("read: emitReadable",t.length,t.ended),t.length===0&&t.ended?Kb(this):Np(this),null;if(e=mF(e,t),e===0&&t.ended)return t.length===0&&Kb(this),null;var n=t.needReadable;dt("need readable",n),(t.length===0||t.length-e0?i=wF(e,t):i=null,i===null?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.awaitDrain=0),t.length===0&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&Kb(this)),i!==null&&this.emit("data",i),i};function Ine(e,t){if(dt("onEofChunk"),!t.ended){if(t.decoder){var r=t.decoder.end();r&&r.length&&(t.buffer.push(r),t.length+=t.objectMode?1:r.length)}t.ended=!0,t.sync?Np(e):(t.needReadable=!1,t.emittedReadable||(t.emittedReadable=!0,CF(e)))}}function Np(e){var t=e._readableState;dt("emitReadable",t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(dt("emitReadable",t.flowing),t.emittedReadable=!0,process.nextTick(CF,e))}function CF(e){var t=e._readableState;dt("emitReadable_",t.destroyed,t.length,t.ended),!t.destroyed&&(t.length||t.ended)&&(e.emit("readable"),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,$b(e)}function Xb(e,t){t.readingMore||(t.readingMore=!0,process.nextTick(bne,e,t))}function bne(e,t){for(;!t.reading&&!t.ended&&(t.length1&&SF(n.pipes,e)!==-1)&&!f&&(dt("false write response, pause",n.awaitDrain),n.awaitDrain++),r.pause())}function B(P){dt("onerror",P),N(),e.removeListener("error",B),BF(e,"error")===0&&Bh(e,P)}yne(e,"error",B);function S(){e.removeListener("finish",_),N()}e.once("close",S);function _(){dt("onfinish"),e.removeListener("close",S),N()}e.once("finish",_);function N(){dt("unpipe"),r.unpipe(e)}return e.emit("pipe",r),n.flowing||(dt("pipe resume"),r.resume()),e};function Cne(e){return function(){var r=e._readableState;dt("pipeOnDrain",r.awaitDrain),r.awaitDrain&&r.awaitDrain--,r.awaitDrain===0&&BF(e,"data")&&(r.flowing=!0,$b(e))}}Qt.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(t.pipesCount===0)return this;if(t.pipesCount===1)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r),this);if(!e){var n=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var s=0;s0,n.flowing!==!1&&this.resume()):e==="readable"&&!n.endEmitted&&!n.readableListening&&(n.readableListening=n.needReadable=!0,n.flowing=!1,n.emittedReadable=!1,dt("on readable",n.length,n.reading),n.length?Np(this):n.reading||process.nextTick(Qne,this)),r};Qt.prototype.addListener=Qt.prototype.on;Qt.prototype.removeListener=function(e,t){var r=Ih.prototype.removeListener.call(this,e,t);return e==="readable"&&process.nextTick(QF,this),r};Qt.prototype.removeAllListeners=function(e){var t=Ih.prototype.removeAllListeners.apply(this,arguments);return(e==="readable"||e===void 0)&&process.nextTick(QF,this),t};function QF(e){var t=e._readableState;t.readableListening=e.listenerCount("readable")>0,t.resumeScheduled&&!t.paused?t.flowing=!0:e.listenerCount("data")>0&&e.resume()}function Qne(e){dt("readable nexttick read 0"),e.read(0)}Qt.prototype.resume=function(){var e=this._readableState;return e.flowing||(dt("resume"),e.flowing=!e.readableListening,wne(this,e)),e.paused=!1,this};function wne(e,t){t.resumeScheduled||(t.resumeScheduled=!0,process.nextTick(Sne,e,t))}function Sne(e,t){dt("resume",t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit("resume"),$b(e),t.flowing&&!t.reading&&e.read(0)}Qt.prototype.pause=function(){return dt("call pause flowing=%j",this._readableState.flowing),this._readableState.flowing!==!1&&(dt("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this};function $b(e){var t=e._readableState;for(dt("flow",t.flowing);t.flowing&&e.read()!==null;);}Qt.prototype.wrap=function(e){var t=this,r=this._readableState,n=!1;e.on("end",function(){if(dt("wrapped end"),r.decoder&&!r.ended){var o=r.decoder.end();o&&o.length&&t.push(o)}t.push(null)}),e.on("data",function(o){if(dt("wrapped data"),r.decoder&&(o=r.decoder.write(o)),!(r.objectMode&&o==null)&&!(!r.objectMode&&(!o||!o.length))){var a=t.push(o);a||(n=!0,e.pause())}});for(var i in e)this[i]===void 0&&typeof e[i]=="function"&&(this[i]=(function(a){return function(){return e[a].apply(e,arguments)}})(i));for(var s=0;s=t.length?(t.decoder?r=t.buffer.join(""):t.buffer.length===1?r=t.buffer.first():r=t.buffer.concat(t.length),t.buffer.clear()):r=t.buffer.consume(e,t.decoder),r}function Kb(e){var t=e._readableState;dt("endReadable",t.endEmitted),t.endEmitted||(t.ended=!0,process.nextTick(_ne,t,e))}function _ne(e,t){if(dt("endReadableNT",e.endEmitted,e.length),!e.endEmitted&&e.length===0&&(e.endEmitted=!0,t.readable=!1,t.emit("end"),e.autoDestroy)){var r=t._writableState;(!r||r.autoDestroy&&r.finished)&&t.destroy()}}typeof Symbol=="function"&&(Qt.from=function(e,t){return Jb===void 0&&(Jb=EF()),Jb(Qt,e,t)});function SF(e,t){for(var r=0,n=e.length;r{"use strict";RF.exports=Vo;var Mp=nf().codes,vne=Mp.ERR_METHOD_NOT_IMPLEMENTED,Rne=Mp.ERR_MULTIPLE_CALLBACK,Dne=Mp.ERR_TRANSFORM_ALREADY_TRANSFORMING,Tne=Mp.ERR_TRANSFORM_WITH_LENGTH_0,Fp=sf();ze()(Vo,Fp);function Nne(e,t){var r=this._transformState;r.transforming=!1;var n=r.writecb;if(n===null)return this.emit("error",new Rne);r.writechunk=null,r.writecb=null,t!=null&&this.push(t),n(e);var i=this._readableState;i.reading=!1,(i.needReadable||i.length{"use strict";TF.exports=bh;var DF=eC();ze()(bh,DF);function bh(e){if(!(this instanceof bh))return new bh(e);DF.call(this,e)}bh.prototype._transform=function(e,t,r){r(null,e)}});var UF=x((wDe,xF)=>{"use strict";var tC;function Fne(e){var t=!1;return function(){t||(t=!0,e.apply(void 0,arguments))}}var kF=nf().codes,kne=kF.ERR_MISSING_ARGS,xne=kF.ERR_STREAM_DESTROYED;function MF(e){if(e)throw e}function Une(e){return e.setHeader&&typeof e.abort=="function"}function Lne(e,t,r,n){n=Fne(n);var i=!1;e.on("close",function(){i=!0}),tC===void 0&&(tC=_p()),tC(e,{readable:t,writable:r},function(o){if(o)return n(o);i=!0,n()});var s=!1;return function(o){if(!i&&!s){if(s=!0,Une(e))return e.abort();if(typeof e.destroy=="function")return e.destroy();n(o||new xne("pipe"))}}}function FF(e){e()}function Pne(e,t){return e.pipe(t)}function One(e){return!e.length||typeof e[e.length-1]!="function"?MF:e.pop()}function Hne(){for(var e=arguments.length,t=new Array(e),r=0;r0;return Lne(o,A,f,function(l){i||(i=l),l&&s.forEach(FF),!A&&(s.forEach(FF),n(i))})});return t.reduce(Pne)}xF.exports=Hne});var nC=x((SDe,LF)=>{LF.exports=di;var rC=Zi().EventEmitter,qne=ze();qne(di,rC);di.Readable=Ob();di.Writable=Ub();di.Duplex=sf();di.Transform=eC();di.PassThrough=NF();di.finished=_p();di.pipeline=UF();di.Stream=di;function di(){rC.call(this)}di.prototype.pipe=function(e,t){var r=this;function n(l){e.writable&&e.write(l)===!1&&r.pause&&r.pause()}r.on("data",n);function i(){r.readable&&r.resume&&r.resume()}e.on("drain",i),!e._isStdio&&(!t||t.end!==!1)&&(r.on("end",o),r.on("close",a));var s=!1;function o(){s||(s=!0,e.end())}function a(){s||(s=!0,typeof e.destroy=="function"&&e.destroy())}function A(l){if(f(),rC.listenerCount(this,"error")===0)throw l}r.on("error",A),e.on("error",A);function f(){r.removeListener("data",n),e.removeListener("drain",i),r.removeListener("end",o),r.removeListener("close",a),r.removeListener("error",A),e.removeListener("error",A),r.removeListener("end",f),r.removeListener("close",f),e.removeListener("close",f)}return r.on("end",f),r.on("close",f),e.on("close",f),e.emit("pipe",r),e}});var Yt={};MI(Yt,{default:()=>Yne,finished:()=>HF,isDisturbed:()=>YF,isErrored:()=>GF,isReadable:()=>qF});var fc,OF,PF,kp,iC,Gne,HF,qF,GF,YF,Yne,ts=QD(()=>{"use strict";fc=hr(nC());vn(Yt,hr(nC()));OF=fc.default??fc.default??{},PF=fc.finished??OF.finished,kp=e=>!!e&&typeof e.getReader=="function"&&typeof e.cancel=="function",iC=e=>!!e&&typeof e.getWriter=="function"&&typeof e.abort=="function",Gne=e=>e instanceof Error?e:e==null?new Error("stream errored"):new Error(String(e)),HF=(e,t,r)=>{let n=t,i=r;if(typeof n=="function"&&(i=n,n={}),!kp(e)&&!iC(e)&&typeof PF=="function")return PF(e,n,i);let s=typeof i=="function"?i:()=>{},o=n?.readable!==!1,a=n?.writable!==!1,A=!1,f=null,l=()=>{A=!0,f!==null&&(clearTimeout(f),f=null)},p=(S=void 0)=>{A||(l(),queueMicrotask(()=>s(S)))},B=()=>{if(A)return;let S=e?._state;if(S==="errored"){p(Gne(e?._storedError));return}if(S==="closed"||kp(e)&&!o||iC(e)&&!a){p();return}f=setTimeout(B,0)};return B(),l},qF=e=>kp(e)?e._state==="readable":!!e&&e.readable!==!1&&e.destroyed!==!0,GF=e=>kp(e)||iC(e)?e?._state==="errored":e?.errored!=null,YF=e=>!!(e?.locked||e?.disturbed===!0||e?._disturbed===!0||e?.readableDidRead===!0),Yne={...OF,finished:HF,isReadable:qF,isErrored:GF,isDisturbed:YF}});var WF=x(()=>{});var _h=x((DDe,ck)=>{var dC=typeof Map=="function"&&Map.prototype,sC=Object.getOwnPropertyDescriptor&&dC?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,Up=dC&&sC&&typeof sC.get=="function"?sC.get:null,VF=dC&&Map.prototype.forEach,gC=typeof Set=="function"&&Set.prototype,oC=Object.getOwnPropertyDescriptor&&gC?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,Lp=gC&&oC&&typeof oC.get=="function"?oC.get:null,JF=gC&&Set.prototype.forEach,Wne=typeof WeakMap=="function"&&WeakMap.prototype,Qh=Wne?WeakMap.prototype.has:null,Vne=typeof WeakSet=="function"&&WeakSet.prototype,wh=Vne?WeakSet.prototype.has:null,Jne=typeof WeakRef=="function"&&WeakRef.prototype,jF=Jne?WeakRef.prototype.deref:null,jne=Boolean.prototype.valueOf,zne=Object.prototype.toString,Kne=Function.prototype.toString,Xne=String.prototype.match,pC=String.prototype.slice,eA=String.prototype.replace,Zne=String.prototype.toUpperCase,zF=String.prototype.toLowerCase,ik=RegExp.prototype.test,KF=Array.prototype.concat,Ks=Array.prototype.join,$ne=Array.prototype.slice,XF=Math.floor,fC=typeof BigInt=="function"?BigInt.prototype.valueOf:null,aC=Object.getOwnPropertySymbols,uC=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Symbol.prototype.toString:null,uc=typeof Symbol=="function"&&typeof Symbol.iterator=="object",Sh=typeof Symbol=="function"&&Symbol.toStringTag&&(typeof Symbol.toStringTag===uc||!0)?Symbol.toStringTag:null,sk=Object.prototype.propertyIsEnumerable,ZF=(typeof Reflect=="function"?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(e){return e.__proto__}:null);function $F(e,t){if(e===1/0||e===-1/0||e!==e||e&&e>-1e3&&e<1e3||ik.call(/e/,t))return t;var r=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if(typeof e=="number"){var n=e<0?-XF(-e):XF(e);if(n!==e){var i=String(n),s=pC.call(t,i.length+1);return eA.call(i,r,"$&_")+"."+eA.call(eA.call(s,/([0-9]{3})/g,"$&_"),/_$/,"")}}return eA.call(t,r,"$&_")}var cC=WF(),ek=cC.custom,tk=Ak(ek)?ek:null,ok={__proto__:null,double:'"',single:"'"},eie={__proto__:null,double:/(["\\])/g,single:/(['\\])/g};ck.exports=function e(t,r,n,i){var s=r||{};if(Jo(s,"quoteStyle")&&!Jo(ok,s.quoteStyle))throw new TypeError('option "quoteStyle" must be "single" or "double"');if(Jo(s,"maxStringLength")&&(typeof s.maxStringLength=="number"?s.maxStringLength<0&&s.maxStringLength!==1/0:s.maxStringLength!==null))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var o=Jo(s,"customInspect")?s.customInspect:!0;if(typeof o!="boolean"&&o!=="symbol")throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(Jo(s,"indent")&&s.indent!==null&&s.indent!==" "&&!(parseInt(s.indent,10)===s.indent&&s.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(Jo(s,"numericSeparator")&&typeof s.numericSeparator!="boolean")throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var a=s.numericSeparator;if(typeof t>"u")return"undefined";if(t===null)return"null";if(typeof t=="boolean")return t?"true":"false";if(typeof t=="string")return uk(t,s);if(typeof t=="number"){if(t===0)return 1/0/t>0?"0":"-0";var A=String(t);return a?$F(t,A):A}if(typeof t=="bigint"){var f=String(t)+"n";return a?$F(t,f):f}var l=typeof s.depth>"u"?5:s.depth;if(typeof n>"u"&&(n=0),n>=l&&l>0&&typeof t=="object")return lC(t)?"[Array]":"[Object]";var p=yie(s,n);if(typeof i>"u")i=[];else if(fk(i,t)>=0)return"[Circular]";function B(b,c,g){if(c&&(i=$ne.call(i),i.push(c)),g){var w={depth:s.depth};return Jo(s,"quoteStyle")&&(w.quoteStyle=s.quoteStyle),e(b,w,n+1,i)}return e(b,s,n+1,i)}if(typeof t=="function"&&!rk(t)){var S=fie(t),_=xp(t,B);return"[Function"+(S?": "+S:" (anonymous)")+"]"+(_.length>0?" { "+Ks.call(_,", ")+" }":"")}if(Ak(t)){var N=uc?eA.call(String(t),/^(Symbol\(.*\))_[^)]*$/,"$1"):uC.call(t);return typeof t=="object"&&!uc?Ch(N):N}if(gie(t)){for(var P="<"+zF.call(String(t.nodeName)),U=t.attributes||[],G=0;G",P}if(lC(t)){if(t.length===0)return"[]";var Y=xp(t,B);return p&&!Eie(Y)?"["+hC(Y,p)+"]":"[ "+Ks.call(Y,", ")+" ]"}if(nie(t)){var Z=xp(t,B);return!("cause"in Error.prototype)&&"cause"in t&&!sk.call(t,"cause")?"{ ["+String(t)+"] "+Ks.call(KF.call("[cause]: "+B(t.cause),Z),", ")+" }":Z.length===0?"["+String(t)+"]":"{ ["+String(t)+"] "+Ks.call(Z,", ")+" }"}if(typeof t=="object"&&o){if(tk&&typeof t[tk]=="function"&&cC)return cC(t,{depth:l-n});if(o!=="symbol"&&typeof t.inspect=="function")return t.inspect()}if(uie(t)){var ee=[];return VF&&VF.call(t,function(b,c){ee.push(B(c,t,!0)+" => "+B(b,t))}),nk("Map",Up.call(t),ee,p)}if(hie(t)){var j=[];return JF&&JF.call(t,function(b){j.push(B(b,t))}),nk("Set",Lp.call(t),j,p)}if(cie(t))return AC("WeakMap");if(die(t))return AC("WeakSet");if(lie(t))return AC("WeakRef");if(sie(t))return Ch(B(Number(t)));if(aie(t))return Ch(B(fC.call(t)));if(oie(t))return Ch(jne.call(t));if(iie(t))return Ch(B(String(t)));if(typeof window<"u"&&t===window)return"{ [object Window] }";if(typeof globalThis<"u"&&t===globalThis||typeof globalThis<"u"&&t===globalThis)return"{ [object globalThis] }";if(!rie(t)&&!rk(t)){var se=xp(t,B),ie=ZF?ZF(t)===Object.prototype:t instanceof Object||t.constructor===Object,ce=t instanceof Object?"":"null prototype",H=!ie&&Sh&&Object(t)===t&&Sh in t?pC.call(tA(t),8,-1):ce?"Object":"",E=ie||typeof t.constructor!="function"?"":t.constructor.name?t.constructor.name+" ":"",v=E+(H||ce?"["+Ks.call(KF.call([],H||[],ce||[]),": ")+"] ":"");return se.length===0?v+"{}":p?v+"{"+hC(se,p)+"}":v+"{ "+Ks.call(se,", ")+" }"}return String(t)};function ak(e,t,r){var n=r.quoteStyle||t,i=ok[n];return i+e+i}function tie(e){return eA.call(String(e),/"/g,""")}function cf(e){return!Sh||!(typeof e=="object"&&(Sh in e||typeof e[Sh]<"u"))}function lC(e){return tA(e)==="[object Array]"&&cf(e)}function rie(e){return tA(e)==="[object Date]"&&cf(e)}function rk(e){return tA(e)==="[object RegExp]"&&cf(e)}function nie(e){return tA(e)==="[object Error]"&&cf(e)}function iie(e){return tA(e)==="[object String]"&&cf(e)}function sie(e){return tA(e)==="[object Number]"&&cf(e)}function oie(e){return tA(e)==="[object Boolean]"&&cf(e)}function Ak(e){if(uc)return e&&typeof e=="object"&&e instanceof Symbol;if(typeof e=="symbol")return!0;if(!e||typeof e!="object"||!uC)return!1;try{return uC.call(e),!0}catch{}return!1}function aie(e){if(!e||typeof e!="object"||!fC)return!1;try{return fC.call(e),!0}catch{}return!1}var Aie=Object.prototype.hasOwnProperty||function(e){return e in this};function Jo(e,t){return Aie.call(e,t)}function tA(e){return zne.call(e)}function fie(e){if(e.name)return e.name;var t=Xne.call(Kne.call(e),/^function\s*([\w$]+)/);return t?t[1]:null}function fk(e,t){if(e.indexOf)return e.indexOf(t);for(var r=0,n=e.length;rt.maxStringLength){var r=e.length-t.maxStringLength,n="... "+r+" more character"+(r>1?"s":"");return uk(pC.call(e,0,t.maxStringLength),t)+n}var i=eie[t.quoteStyle||"single"];i.lastIndex=0;var s=eA.call(eA.call(e,i,"\\$1"),/[\x00-\x1f]/g,pie);return ak(s,"single",t)}function pie(e){var t=e.charCodeAt(0),r={8:"b",9:"t",10:"n",12:"f",13:"r"}[t];return r?"\\"+r:"\\x"+(t<16?"0":"")+Zne.call(t.toString(16))}function Ch(e){return"Object("+e+")"}function AC(e){return e+" { ? }"}function nk(e,t,r,n){var i=n?hC(r,n):Ks.call(r,", ");return e+" ("+t+") {"+i+"}"}function Eie(e){for(var t=0;t=0)return!1;return!0}function yie(e,t){var r;if(e.indent===" ")r=" ";else if(typeof e.indent=="number"&&e.indent>0)r=Ks.call(Array(e.indent+1)," ");else return null;return{base:r,prev:Ks.call(Array(t+1),r)}}function hC(e,t){if(e.length===0)return"";var r=` -`+t.prev+t.base;return r+Ks.call(e,","+r)+` -`+t.prev}function xp(e,t){var r=lC(e),n=[];if(r){n.length=e.length;for(var i=0;i{"use strict";var mie=_h(),Bie=$i(),Pp=function(e,t,r){for(var n=e,i;(i=n.next)!=null;n=i)if(i.key===t)return n.next=i.next,r||(i.next=e.next,e.next=i),i},Iie=function(e,t){if(e){var r=Pp(e,t);return r&&r.value}},bie=function(e,t,r){var n=Pp(e,t);n?n.value=r:e.next={key:t,next:e.next,value:r}},Cie=function(e,t){return e?!!Pp(e,t):!1},Qie=function(e,t){if(e)return Pp(e,t,!0)};lk.exports=function(){var t,r={assert:function(n){if(!r.has(n))throw new Bie("Side channel does not contain "+mie(n))},delete:function(n){var i=t&&t.next,s=Qie(t,n);return s&&i&&i===s&&(t=void 0),!!s},get:function(n){return Iie(t,n)},has:function(n){return Cie(t,n)},set:function(n,i){t||(t={next:void 0}),bie(t,n,i)}};return r}});var EC=x((NDe,gk)=>{"use strict";var wie=ec(),vh=Js(),Sie=_h(),_ie=$i(),dk=wie("%Map%",!0),vie=vh("Map.prototype.get",!0),Rie=vh("Map.prototype.set",!0),Die=vh("Map.prototype.has",!0),Tie=vh("Map.prototype.delete",!0),Nie=vh("Map.prototype.size",!0);gk.exports=!!dk&&function(){var t,r={assert:function(n){if(!r.has(n))throw new _ie("Side channel does not contain "+Sie(n))},delete:function(n){if(t){var i=Tie(t,n);return Nie(t)===0&&(t=void 0),i}return!1},get:function(n){if(t)return vie(t,n)},has:function(n){return t?Die(t,n):!1},set:function(n,i){t||(t=new dk),Rie(t,n,i)}};return r}});var Ek=x((MDe,pk)=>{"use strict";var Mie=ec(),Hp=Js(),Fie=_h(),Op=EC(),kie=$i(),cc=Mie("%WeakMap%",!0),xie=Hp("WeakMap.prototype.get",!0),Uie=Hp("WeakMap.prototype.set",!0),Lie=Hp("WeakMap.prototype.has",!0),Pie=Hp("WeakMap.prototype.delete",!0);pk.exports=cc?function(){var t,r,n={assert:function(i){if(!n.has(i))throw new kie("Side channel does not contain "+Fie(i))},delete:function(i){if(cc&&i&&(typeof i=="object"||typeof i=="function")){if(t)return Pie(t,i)}else if(Op&&r)return r.delete(i);return!1},get:function(i){return cc&&i&&(typeof i=="object"||typeof i=="function")&&t?xie(t,i):r&&r.get(i)},has:function(i){return cc&&i&&(typeof i=="object"||typeof i=="function")&&t?Lie(t,i):!!r&&r.has(i)},set:function(i,s){cc&&i&&(typeof i=="object"||typeof i=="function")?(t||(t=new cc),Uie(t,i,s)):Op&&(r||(r=Op()),r.set(i,s))}};return n}:Op});var yC=x((FDe,yk)=>{"use strict";var Oie=$i(),Hie=_h(),qie=hk(),Gie=EC(),Yie=Ek(),Wie=Yie||Gie||qie;yk.exports=function(){var t,r={assert:function(n){if(!r.has(n))throw new Oie("Side channel does not contain "+Hie(n))},delete:function(n){return!!t&&t.delete(n)},get:function(n){return t&&t.get(n)},has:function(n){return!!t&&t.has(n)},set:function(n,i){t||(t=Wie()),t.set(n,i)}};return r}});var qp=x((kDe,mk)=>{"use strict";var Vie=String.prototype.replace,Jie=/%20/g,mC={RFC1738:"RFC1738",RFC3986:"RFC3986"};mk.exports={default:mC.RFC3986,formatters:{RFC1738:function(e){return Vie.call(e,Jie,"+")},RFC3986:function(e){return String(e)}},RFC1738:mC.RFC1738,RFC3986:mC.RFC3986}});var CC=x((xDe,Bk)=>{"use strict";var jie=qp(),zie=yC(),BC=Object.prototype.hasOwnProperty,lf=Array.isArray,Gp=zie(),lc=function(t,r){return Gp.set(t,r),t},hf=function(t){return Gp.has(t)},Rh=function(t){return Gp.get(t)},bC=function(t,r){Gp.set(t,r)},Xs=(function(){for(var e=[],t=0;t<256;++t)e[e.length]="%"+((t<16?"0":"")+t.toString(16)).toUpperCase();return e})(),Kie=function(t){for(;t.length>1;){var r=t.pop(),n=r.obj[r.prop];if(lf(n)){for(var i=[],s=0;sn.arrayLimit)return lc(Dh(t.concat(r),n),i);t[i]=r}else if(t&&typeof t=="object")if(hf(t)){var s=Rh(t)+1;t[s]=r,bC(t,s)}else{if(n&&n.strictMerge)return[t,r];(n&&(n.plainObjects||n.allowPrototypes)||!BC.call(Object.prototype,r))&&(t[r]=!0)}else return[t,r];return t}if(!t||typeof t!="object"){if(hf(r)){for(var o=Object.keys(r),a=n&&n.plainObjects?{__proto__:null,0:t}:{0:t},A=0;An.arrayLimit?lc(Dh(l,n),l.length-1):l}var p=t;return lf(t)&&!lf(r)&&(p=Dh(t,n)),lf(t)&&lf(r)?(r.forEach(function(B,S){if(BC.call(t,S)){var _=t[S];_&&typeof _=="object"&&B&&typeof B=="object"?t[S]=e(_,B,n):t[t.length]=B}else t[S]=B}),t):Object.keys(r).reduce(function(B,S){var _=r[S];if(BC.call(B,S)?B[S]=e(B[S],_,n):B[S]=_,hf(r)&&!hf(B)&&lc(B,Rh(r)),hf(B)){var N=parseInt(S,10);String(N)===S&&N>=0&&N>Rh(B)&&bC(B,N)}return B},p)},Zie=function(t,r){return Object.keys(r).reduce(function(n,i){return n[i]=r[i],n},t)},$ie=function(e,t,r){var n=e.replace(/\+/g," ");if(r==="iso-8859-1")return n.replace(/%[0-9a-f]{2}/gi,unescape);try{return decodeURIComponent(n)}catch{return n}},IC=1024,ese=function(t,r,n,i,s){if(t.length===0)return t;var o=t;if(typeof t=="symbol"?o=Symbol.prototype.toString.call(t):typeof t!="string"&&(o=String(t)),n==="iso-8859-1")return escape(o).replace(/%u[0-9a-f]{4}/gi,function(S){return"%26%23"+parseInt(S.slice(2),16)+"%3B"});for(var a="",A=0;A=IC?o.slice(A,A+IC):o,l=[],p=0;p=48&&B<=57||B>=65&&B<=90||B>=97&&B<=122||s===jie.RFC1738&&(B===40||B===41)){l[l.length]=f.charAt(p);continue}if(B<128){l[l.length]=Xs[B];continue}if(B<2048){l[l.length]=Xs[192|B>>6]+Xs[128|B&63];continue}if(B<55296||B>=57344){l[l.length]=Xs[224|B>>12]+Xs[128|B>>6&63]+Xs[128|B&63];continue}p+=1,B=65536+((B&1023)<<10|f.charCodeAt(p)&1023),l[l.length]=Xs[240|B>>18]+Xs[128|B>>12&63]+Xs[128|B>>6&63]+Xs[128|B&63]}a+=l.join("")}return a},tse=function(t){for(var r=[{obj:{o:t},prop:"o"}],n=[],i=0;in?lc(Dh(o,{plainObjects:i}),o.length-1):o},sse=function(t,r){if(lf(t)){for(var n=[],i=0;i{"use strict";var bk=yC(),Yp=CC(),Th=qp(),ose=Object.prototype.hasOwnProperty,Ck={brackets:function(t){return t+"[]"},comma:"comma",indices:function(t,r){return t+"["+r+"]"},repeat:function(t){return t}},Zs=Array.isArray,ase=Array.prototype.push,Qk=function(e,t){ase.apply(e,Zs(t)?t:[t])},Ase=Date.prototype.toISOString,Ik=Th.default,Sr={addQueryPrefix:!1,allowDots:!1,allowEmptyArrays:!1,arrayFormat:"indices",charset:"utf-8",charsetSentinel:!1,commaRoundTrip:!1,delimiter:"&",encode:!0,encodeDotInKeys:!1,encoder:Yp.encode,encodeValuesOnly:!1,filter:void 0,format:Ik,formatter:Th.formatters[Ik],indices:!1,serializeDate:function(t){return Ase.call(t)},skipNulls:!1,strictNullHandling:!1},fse=function(t){return typeof t=="string"||typeof t=="number"||typeof t=="boolean"||typeof t=="symbol"||typeof t=="bigint"},QC={},use=function e(t,r,n,i,s,o,a,A,f,l,p,B,S,_,N,P,U,G){for(var Y=t,Z=G,ee=0,j=!1;(Z=Z.get(QC))!==void 0&&!j;){var se=Z.get(t);if(ee+=1,typeof se<"u"){if(se===ee)throw new RangeError("Cyclic object value");j=!0}typeof Z.get(QC)>"u"&&(ee=0)}if(typeof l=="function"?Y=l(r,Y):Y instanceof Date?Y=S(Y):n==="comma"&&Zs(Y)&&(Y=Yp.maybeMap(Y,function(D){return D instanceof Date?S(D):D})),Y===null){if(o)return f&&!P?f(r,Sr.encoder,U,"key",_):r;Y=""}if(fse(Y)||Yp.isBuffer(Y)){if(f){var ie=P?r:f(r,Sr.encoder,U,"key",_);return[N(ie)+"="+N(f(Y,Sr.encoder,U,"value",_))]}return[N(r)+"="+N(String(Y))]}var ce=[];if(typeof Y>"u")return ce;var H;if(n==="comma"&&Zs(Y))P&&f&&(Y=Yp.maybeMap(Y,f)),H=[{value:Y.length>0?Y.join(",")||null:void 0}];else if(Zs(l))H=l;else{var E=Object.keys(Y);H=p?E.sort(p):E}var v=A?String(r).replace(/\./g,"%2E"):String(r),b=i&&Zs(Y)&&Y.length===1?v+"[]":v;if(s&&Zs(Y)&&Y.length===0)return b+"[]";for(var c=0;c"u"?t.encodeDotInKeys===!0?!0:Sr.allowDots:!!t.allowDots;return{addQueryPrefix:typeof t.addQueryPrefix=="boolean"?t.addQueryPrefix:Sr.addQueryPrefix,allowDots:a,allowEmptyArrays:typeof t.allowEmptyArrays=="boolean"?!!t.allowEmptyArrays:Sr.allowEmptyArrays,arrayFormat:o,charset:r,charsetSentinel:typeof t.charsetSentinel=="boolean"?t.charsetSentinel:Sr.charsetSentinel,commaRoundTrip:!!t.commaRoundTrip,delimiter:typeof t.delimiter>"u"?Sr.delimiter:t.delimiter,encode:typeof t.encode=="boolean"?t.encode:Sr.encode,encodeDotInKeys:typeof t.encodeDotInKeys=="boolean"?t.encodeDotInKeys:Sr.encodeDotInKeys,encoder:typeof t.encoder=="function"?t.encoder:Sr.encoder,encodeValuesOnly:typeof t.encodeValuesOnly=="boolean"?t.encodeValuesOnly:Sr.encodeValuesOnly,filter:s,format:n,formatter:i,serializeDate:typeof t.serializeDate=="function"?t.serializeDate:Sr.serializeDate,skipNulls:typeof t.skipNulls=="boolean"?t.skipNulls:Sr.skipNulls,sort:typeof t.sort=="function"?t.sort:null,strictNullHandling:typeof t.strictNullHandling=="boolean"?t.strictNullHandling:Sr.strictNullHandling}};wk.exports=function(e,t){var r=e,n=cse(t),i,s;typeof n.filter=="function"?(s=n.filter,r=s("",r)):Zs(n.filter)&&(s=n.filter,i=s);var o=[];if(typeof r!="object"||r===null)return"";var a=Ck[n.arrayFormat],A=a==="comma"&&n.commaRoundTrip;i||(i=Object.keys(r)),n.sort&&i.sort(n.sort);for(var f=bk(),l=0;l0?_+S:""}});var Rk=x((LDe,vk)=>{"use strict";var $s=CC(),Wp=Object.prototype.hasOwnProperty,wC=Array.isArray,sr={allowDots:!1,allowEmptyArrays:!1,allowPrototypes:!1,allowSparse:!1,arrayLimit:20,charset:"utf-8",charsetSentinel:!1,comma:!1,decodeDotInKeys:!1,decoder:$s.decode,delimiter:"&",depth:5,duplicates:"combine",ignoreQueryPrefix:!1,interpretNumericEntities:!1,parameterLimit:1e3,parseArrays:!0,plainObjects:!1,strictDepth:!1,strictMerge:!0,strictNullHandling:!1,throwOnLimitExceeded:!1},lse=function(e){return e.replace(/&#(\d+);/g,function(t,r){return String.fromCharCode(parseInt(r,10))})},_k=function(e,t,r){if(e&&typeof e=="string"&&t.comma&&e.indexOf(",")>-1)return e.split(",");if(t.throwOnLimitExceeded&&r>=t.arrayLimit)throw new RangeError("Array limit exceeded. Only "+t.arrayLimit+" element"+(t.arrayLimit===1?"":"s")+" allowed in an array.");return e},hse="utf8=%26%2310003%3B",dse="utf8=%E2%9C%93",gse=function(t,r){var n={__proto__:null},i=r.ignoreQueryPrefix?t.replace(/^\?/,""):t;i=i.replace(/%5B/gi,"[").replace(/%5D/gi,"]");var s=r.parameterLimit===1/0?void 0:r.parameterLimit,o=i.split(r.delimiter,r.throwOnLimitExceeded?s+1:s);if(r.throwOnLimitExceeded&&o.length>s)throw new RangeError("Parameter limit exceeded. Only "+s+" parameter"+(s===1?"":"s")+" allowed.");var a=-1,A,f=r.charset;if(r.charsetSentinel)for(A=0;A-1&&(_=wC(_)?[_]:_),r.comma&&wC(_)&&_.length>r.arrayLimit){if(r.throwOnLimitExceeded)throw new RangeError("Array limit exceeded. Only "+r.arrayLimit+" element"+(r.arrayLimit===1?"":"s")+" allowed in an array.");_=$s.combine([],_,r.arrayLimit,r.plainObjects)}if(S!==null){var N=Wp.call(n,S);N&&(r.duplicates==="combine"||l.indexOf("[]=")>-1)?n[S]=$s.combine(n[S],_,r.arrayLimit,r.plainObjects):(!N||r.duplicates==="last")&&(n[S]=_)}}return n},pse=function(e,t,r,n){var i=0;if(e.length>0&&e[e.length-1]==="[]"){var s=e.slice(0,-1).join("");i=Array.isArray(t)&&t[s]?t[s].length:0}for(var o=n?t:_k(t,r,i),a=e.length-1;a>=0;--a){var A,f=e[a];if(f==="[]"&&r.parseArrays)$s.isOverflow(o)?A=o:A=r.allowEmptyArrays&&(o===""||r.strictNullHandling&&o===null)?[]:$s.combine([],o,r.arrayLimit,r.plainObjects);else{A=r.plainObjects?{__proto__:null}:{};var l=f.charAt(0)==="["&&f.charAt(f.length-1)==="]"?f.slice(1,-1):f,p=r.decodeDotInKeys?l.replace(/%2E/g,"."):l,B=parseInt(p,10),S=!isNaN(B)&&f!==p&&String(B)===p&&B>=0&&r.parseArrays;if(!r.parseArrays&&p==="")A={0:o};else if(S&&B"u"?sr.charset:t.charset,n=typeof t.duplicates>"u"?sr.duplicates:t.duplicates;if(n!=="combine"&&n!=="first"&&n!=="last")throw new TypeError("The duplicates option must be either combine, first, or last");var i=typeof t.allowDots>"u"?t.decodeDotInKeys===!0?!0:sr.allowDots:!!t.allowDots;return{allowDots:i,allowEmptyArrays:typeof t.allowEmptyArrays=="boolean"?!!t.allowEmptyArrays:sr.allowEmptyArrays,allowPrototypes:typeof t.allowPrototypes=="boolean"?t.allowPrototypes:sr.allowPrototypes,allowSparse:typeof t.allowSparse=="boolean"?t.allowSparse:sr.allowSparse,arrayLimit:typeof t.arrayLimit=="number"?t.arrayLimit:sr.arrayLimit,charset:r,charsetSentinel:typeof t.charsetSentinel=="boolean"?t.charsetSentinel:sr.charsetSentinel,comma:typeof t.comma=="boolean"?t.comma:sr.comma,decodeDotInKeys:typeof t.decodeDotInKeys=="boolean"?t.decodeDotInKeys:sr.decodeDotInKeys,decoder:typeof t.decoder=="function"?t.decoder:sr.decoder,delimiter:typeof t.delimiter=="string"||$s.isRegExp(t.delimiter)?t.delimiter:sr.delimiter,depth:typeof t.depth=="number"||t.depth===!1?+t.depth:sr.depth,duplicates:n,ignoreQueryPrefix:t.ignoreQueryPrefix===!0,interpretNumericEntities:typeof t.interpretNumericEntities=="boolean"?t.interpretNumericEntities:sr.interpretNumericEntities,parameterLimit:typeof t.parameterLimit=="number"?t.parameterLimit:sr.parameterLimit,parseArrays:t.parseArrays!==!1,plainObjects:typeof t.plainObjects=="boolean"?t.plainObjects:sr.plainObjects,strictDepth:typeof t.strictDepth=="boolean"?!!t.strictDepth:sr.strictDepth,strictMerge:typeof t.strictMerge=="boolean"?!!t.strictMerge:sr.strictMerge,strictNullHandling:typeof t.strictNullHandling=="boolean"?t.strictNullHandling:sr.strictNullHandling,throwOnLimitExceeded:typeof t.throwOnLimitExceeded=="boolean"?t.throwOnLimitExceeded:!1}};vk.exports=function(e,t){var r=mse(t);if(e===""||e===null||typeof e>"u")return r.plainObjects?{__proto__:null}:{};for(var n=typeof e=="string"?gse(e,r):e,i=r.plainObjects?{__proto__:null}:{},s=Object.keys(n),o=0;o{"use strict";var Bse=Sk(),Ise=Rk(),bse=qp();Dk.exports={formats:bse,parse:Ise,stringify:Bse}});var kk=x(dc=>{"use strict";var Cse=VI();function gi(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}var Qse=/^([a-z0-9.+-]+:)/i,wse=/:[0-9]*$/,Sse=/^(\/\/?(?!\/)[^?\s]*)(\?[^\s]*)?$/,_se=["<",">",'"',"`"," ","\r",` -`," "],vse=["{","}","|","\\","^","`"].concat(_se),SC=["'"].concat(vse),Nk=["%","/","?",";","#"].concat(SC),Mk=["/","?","#"],Rse=255,Fk=/^[+a-z0-9A-Z_-]{0,63}$/,Dse=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,Tse={javascript:!0,"javascript:":!0},_C={javascript:!0,"javascript:":!0},hc={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},vC=Tk();function Nh(e,t,r){if(e&&typeof e=="object"&&e instanceof gi)return e;var n=new gi;return n.parse(e,t,r),n}gi.prototype.parse=function(e,t,r){if(typeof e!="string")throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var n=e.indexOf("?"),i=n!==-1&&n127?ee+="x":ee+=Z[j];if(!ee.match(Fk)){var ie=G.slice(0,S),ce=G.slice(S+1),H=Z.match(Dse);H&&(ie.push(H[1]),ce.unshift(H[2])),ce.length&&(a="/"+ce.join(".")+a),this.hostname=ie.join(".");break}}}this.hostname.length>Rse?this.hostname="":this.hostname=this.hostname.toLowerCase(),U||(this.hostname=Cse.toASCII(this.hostname));var E=this.port?":"+this.port:"",v=this.hostname||"";this.host=v+E,this.href+=this.host,U&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),a[0]!=="/"&&(a="/"+a))}if(!Tse[l])for(var S=0,Y=SC.length;S0?r.host.split("@"):!1;ee&&(r.auth=ee.shift(),r.hostname=ee.shift(),r.host=r.hostname)}return r.search=e.search,r.query=e.query,(r.pathname!==null||r.search!==null)&&(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.href=r.format(),r}if(!G.length)return r.pathname=null,r.search?r.path="/"+r.search:r.path=null,r.href=r.format(),r;for(var j=G.slice(-1)[0],se=(r.host||e.host||G.length>1)&&(j==="."||j==="..")||j==="",ie=0,ce=G.length;ce>=0;ce--)j=G[ce],j==="."?G.splice(ce,1):j===".."?(G.splice(ce,1),ie++):ie&&(G.splice(ce,1),ie--);if(!P&&!U)for(;ie--;ie)G.unshift("..");P&&G[0]!==""&&(!G[0]||G[0].charAt(0)!=="/")&&G.unshift(""),se&&G.join("/").substr(-1)!=="/"&&G.push("");var H=G[0]===""||G[0]&&G[0].charAt(0)==="/";if(Z){r.hostname=H?"":G.length?G.shift():"",r.host=r.hostname;var ee=r.host&&r.host.indexOf("@")>0?r.host.split("@"):!1;ee&&(r.auth=ee.shift(),r.hostname=ee.shift(),r.host=r.hostname)}return P=P||r.host&&G.length,P&&!H&&G.unshift(""),G.length>0?r.pathname=G.join("/"):(r.pathname=null,r.path=null),(r.pathname!==null||r.search!==null)&&(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.auth=e.auth||r.auth,r.slashes=r.slashes||e.slashes,r.href=r.format(),r};gi.prototype.parseHost=function(){var e=this.host,t=wse.exec(e);t&&(t=t[0],t!==":"&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)};dc.parse=Nh;dc.resolve=Mse;dc.resolveObject=Fse;dc.format=Nse;dc.Url=gi});var Uk=x((Vp,xk)=>{(function(e,t){typeof Vp=="object"&&typeof xk<"u"?t(Vp):typeof define=="function"&&define.amd?define(["exports"],t):(e=typeof globalThis<"u"?globalThis:e||self,t(e.WebStreamsPolyfill={}))})(Vp,(function(e){"use strict";function t(){}function r(u){return typeof u=="object"&&u!==null||typeof u=="function"}let n=t;function i(u,d){try{Object.defineProperty(u,"name",{value:d,configurable:!0})}catch{}}let s=Promise,o=Promise.prototype.then,a=Promise.reject.bind(s);function A(u){return new s(u)}function f(u){return A(d=>d(u))}function l(u){return a(u)}function p(u,d,T){return o.call(u,d,T)}function B(u,d,T){p(p(u,d,T),void 0,n)}function S(u,d){B(u,d)}function _(u,d){B(u,void 0,d)}function N(u,d,T){return p(u,d,T)}function P(u){p(u,void 0,n)}let U=u=>{if(typeof queueMicrotask=="function")U=queueMicrotask;else{let d=f(void 0);U=T=>p(d,T)}return U(u)};function G(u,d,T){if(typeof u!="function")throw new TypeError("Argument is not a function");return Function.prototype.apply.call(u,d,T)}function Y(u,d,T){try{return f(G(u,d,T))}catch(O){return l(O)}}let Z=16384;class ee{constructor(){this._cursor=0,this._size=0,this._front={_elements:[],_next:void 0},this._back=this._front,this._cursor=0,this._size=0}get length(){return this._size}push(d){let T=this._back,O=T;T._elements.length===Z-1&&(O={_elements:[],_next:void 0}),T._elements.push(d),O!==T&&(this._back=O,T._next=O),++this._size}shift(){let d=this._front,T=d,O=this._cursor,J=O+1,re=d._elements,oe=re[O];return J===Z&&(T=d._next,J=0),--this._size,this._cursor=J,d!==T&&(this._front=T),re[O]=void 0,oe}forEach(d){let T=this._cursor,O=this._front,J=O._elements;for(;(T!==J.length||O._next!==void 0)&&!(T===J.length&&(O=O._next,J=O._elements,T=0,J.length===0));)d(J[T]),++T}peek(){let d=this._front,T=this._cursor;return d._elements[T]}}let j=Symbol("[[AbortSteps]]"),se=Symbol("[[ErrorSteps]]"),ie=Symbol("[[CancelSteps]]"),ce=Symbol("[[PullSteps]]"),H=Symbol("[[ReleaseSteps]]");function E(u,d){u._ownerReadableStream=d,d._reader=u,d._state==="readable"?g(u):d._state==="closed"?R(u):w(u,d._storedError)}function v(u,d){let T=u._ownerReadableStream;return Ki(T,d)}function b(u){let d=u._ownerReadableStream;d._state==="readable"?C(u,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")):h(u,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")),d._readableStreamController[H](),d._reader=void 0,u._ownerReadableStream=void 0}function c(u){return new TypeError("Cannot "+u+" a stream using a released reader")}function g(u){u._closedPromise=A((d,T)=>{u._closedPromise_resolve=d,u._closedPromise_reject=T})}function w(u,d){g(u),C(u,d)}function R(u){g(u),D(u)}function C(u,d){u._closedPromise_reject!==void 0&&(P(u._closedPromise),u._closedPromise_reject(d),u._closedPromise_resolve=void 0,u._closedPromise_reject=void 0)}function h(u,d){w(u,d)}function D(u){u._closedPromise_resolve!==void 0&&(u._closedPromise_resolve(void 0),u._closedPromise_resolve=void 0,u._closedPromise_reject=void 0)}let M=Number.isFinite||function(u){return typeof u=="number"&&isFinite(u)},I=Math.trunc||function(u){return u<0?Math.ceil(u):Math.floor(u)};function k(u){return typeof u=="object"||typeof u=="function"}function ne(u,d){if(u!==void 0&&!k(u))throw new TypeError(`${d} is not an object.`)}function Ae(u,d){if(typeof u!="function")throw new TypeError(`${d} is not a function.`)}function ue(u){return typeof u=="object"&&u!==null||typeof u=="function"}function pe(u,d){if(!ue(u))throw new TypeError(`${d} is not an object.`)}function he(u,d,T){if(u===void 0)throw new TypeError(`Parameter ${d} is required in '${T}'.`)}function de(u,d,T){if(u===void 0)throw new TypeError(`${d} is required in '${T}'.`)}function wt(u){return Number(u)}function Ie(u){return u===0?0:u}function be(u){return Ie(I(u))}function yr(u,d){let O=Number.MAX_SAFE_INTEGER,J=Number(u);if(J=Ie(J),!M(J))throw new TypeError(`${d} is not a finite number`);if(J=be(J),J<0||J>O)throw new TypeError(`${d} is outside the accepted range of 0 to ${O}, inclusive`);return!M(J)||J===0?0:J}function we(u,d){if(!Ga(u))throw new TypeError(`${d} is not a ReadableStream.`)}function ve(u){return new Te(u)}function Ms(u,d){u._reader._readRequests.push(d)}function Ye(u,d,T){let J=u._reader._readRequests.shift();T?J._closeSteps():J._chunkSteps(d)}function xe(u){return u._reader._readRequests.length}function Fs(u){let d=u._reader;return!(d===void 0||!De(d))}class Te{constructor(d){if(he(d,1,"ReadableStreamDefaultReader"),we(d,"First parameter"),Ya(d))throw new TypeError("This stream has already been locked for exclusive reading by another reader");E(this,d),this._readRequests=new ee}get closed(){return De(this)?this._closedPromise:l(ai("closed"))}cancel(d=void 0){return De(this)?this._ownerReadableStream===void 0?l(c("cancel")):v(this,d):l(ai("cancel"))}read(){if(!De(this))return l(ai("read"));if(this._ownerReadableStream===void 0)return l(c("read from"));let d,T,O=A((re,oe)=>{d=re,T=oe});return en(this,{_chunkSteps:re=>d({value:re,done:!1}),_closeSteps:()=>d({value:void 0,done:!0}),_errorSteps:re=>T(re)}),O}releaseLock(){if(!De(this))throw ai("releaseLock");this._ownerReadableStream!==void 0&&Re(this)}}Object.defineProperties(Te.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),i(Te.prototype.cancel,"cancel"),i(Te.prototype.read,"read"),i(Te.prototype.releaseLock,"releaseLock"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Te.prototype,Symbol.toStringTag,{value:"ReadableStreamDefaultReader",configurable:!0});function De(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_readRequests")?!1:u instanceof Te}function en(u,d){let T=u._ownerReadableStream;T._disturbed=!0,T._state==="closed"?d._closeSteps():T._state==="errored"?d._errorSteps(T._storedError):T._readableStreamController[ce](d)}function Re(u){b(u);let d=new TypeError("Reader was released");He(u,d)}function He(u,d){let T=u._readRequests;u._readRequests=new ee,T.forEach(O=>{O._errorSteps(d)})}function ai(u){return new TypeError(`ReadableStreamDefaultReader.prototype.${u} can only be used on a ReadableStreamDefaultReader`)}let Ne=Object.getPrototypeOf(Object.getPrototypeOf(async function*(){}).prototype);class Je{constructor(d,T){this._ongoingPromise=void 0,this._isFinished=!1,this._reader=d,this._preventCancel=T}next(){let d=()=>this._nextSteps();return this._ongoingPromise=this._ongoingPromise?N(this._ongoingPromise,d,d):d(),this._ongoingPromise}return(d){let T=()=>this._returnSteps(d);return this._ongoingPromise?N(this._ongoingPromise,T,T):T()}_nextSteps(){if(this._isFinished)return Promise.resolve({value:void 0,done:!0});let d=this._reader,T,O,J=A((oe,me)=>{T=oe,O=me});return en(d,{_chunkSteps:oe=>{this._ongoingPromise=void 0,U(()=>T({value:oe,done:!1}))},_closeSteps:()=>{this._ongoingPromise=void 0,this._isFinished=!0,b(d),T({value:void 0,done:!0})},_errorSteps:oe=>{this._ongoingPromise=void 0,this._isFinished=!0,b(d),O(oe)}}),J}_returnSteps(d){if(this._isFinished)return Promise.resolve({value:d,done:!0});this._isFinished=!0;let T=this._reader;if(!this._preventCancel){let O=v(T,d);return b(T),N(O,()=>({value:d,done:!0}))}return b(T),f({value:d,done:!0})}}let F={next(){return Q(this)?this._asyncIteratorImpl.next():l(L("next"))},return(u){return Q(this)?this._asyncIteratorImpl.return(u):l(L("return"))}};Object.setPrototypeOf(F,Ne);function m(u,d){let T=ve(u),O=new Je(T,d),J=Object.create(F);return J._asyncIteratorImpl=O,J}function Q(u){if(!r(u)||!Object.prototype.hasOwnProperty.call(u,"_asyncIteratorImpl"))return!1;try{return u._asyncIteratorImpl instanceof Je}catch{return!1}}function L(u){return new TypeError(`ReadableStreamAsyncIterator.${u} can only be used on a ReadableSteamAsyncIterator`)}let W=Number.isNaN||function(u){return u!==u};var z,ae,le;function ye(u){return u.slice()}function Ct(u,d,T,O,J){new Uint8Array(u).set(new Uint8Array(T,O,J),d)}let Ee=u=>(typeof u.transfer=="function"?Ee=d=>d.transfer():typeof structuredClone=="function"?Ee=d=>structuredClone(d,{transfer:[d]}):Ee=d=>d,Ee(u)),ge=u=>(typeof u.detached=="boolean"?ge=d=>d.detached:ge=d=>d.byteLength===0,ge(u));function Ua(u,d,T){if(u.slice)return u.slice(d,T);let O=T-d,J=new ArrayBuffer(O);return Ct(J,0,u,d,O),J}function je(u,d){let T=u[d];if(T!=null){if(typeof T!="function")throw new TypeError(`${String(d)} is not a function`);return T}}function tt(u){let d={[Symbol.iterator]:()=>u.iterator},T=(async function*(){return yield*d})(),O=T.next;return{iterator:T,nextMethod:O,done:!1}}let Fo=(le=(z=Symbol.asyncIterator)!==null&&z!==void 0?z:(ae=Symbol.for)===null||ae===void 0?void 0:ae.call(Symbol,"Symbol.asyncIterator"))!==null&&le!==void 0?le:"@@asyncIterator";function $e(u,d="sync",T){if(T===void 0)if(d==="async"){if(T=je(u,Fo),T===void 0){let re=je(u,Symbol.iterator),oe=$e(u,"sync",re);return tt(oe)}}else T=je(u,Symbol.iterator);if(T===void 0)throw new TypeError("The object is not iterable");let O=G(T,u,[]);if(!r(O))throw new TypeError("The iterator method must return an object");let J=O.next;return{iterator:O,nextMethod:J,done:!1}}function rt(u){let d=G(u.nextMethod,u.iterator,[]);if(!r(d))throw new TypeError("The iterator.next() method must return an object");return d}function GA(u){return!!u.done}function nt(u){return u.value}function it(u){return!(typeof u!="number"||W(u)||u<0)}function La(u){let d=Ua(u.buffer,u.byteOffset,u.byteOffset+u.byteLength);return new Uint8Array(d)}function Ke(u){let d=u._queue.shift();return u._queueTotalSize-=d.size,u._queueTotalSize<0&&(u._queueTotalSize=0),d.value}function Xe(u,d,T){if(!it(T)||T===1/0)throw new RangeError("Size must be a finite, non-NaN, non-negative number.");u._queue.push({value:d,size:T}),u._queueTotalSize+=T}function YA(u){return u._queue.peek().value}function Ue(u){u._queue=new ee,u._queueTotalSize=0}function et(u){return u===DataView}function WA(u){return et(u.constructor)}function st(u){return et(u)?1:u.BYTES_PER_ELEMENT}class Le{constructor(){throw new TypeError("Illegal constructor")}get view(){if(!Ze(this))throw hI("view");return this._view}respond(d){if(!Ze(this))throw hI("respond");if(he(d,1,"respond"),d=yr(d,"First parameter"),this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(ge(this._view.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be used as a response");h0(this._associatedReadableByteStreamController,d)}respondWithNewView(d){if(!Ze(this))throw hI("respondWithNewView");if(he(d,1,"respondWithNewView"),!ArrayBuffer.isView(d))throw new TypeError("You can only respond with array buffer views");if(this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(ge(d.buffer))throw new TypeError("The given view's buffer has been detached and so cannot be used as a response");d0(this._associatedReadableByteStreamController,d)}}Object.defineProperties(Le.prototype,{respond:{enumerable:!0},respondWithNewView:{enumerable:!0},view:{enumerable:!0}}),i(Le.prototype.respond,"respond"),i(Le.prototype.respondWithNewView,"respondWithNewView"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Le.prototype,Symbol.toStringTag,{value:"ReadableStreamBYOBRequest",configurable:!0});class hn{constructor(){throw new TypeError("Illegal constructor")}get byobRequest(){if(!Pe(this))throw Kl("byobRequest");return lI(this)}get desiredSize(){if(!Pe(this))throw Kl("desiredSize");return xR(this)}close(){if(!Pe(this))throw Kl("close");if(this._closeRequested)throw new TypeError("The stream has already been closed; do not close it again!");let d=this._controlledReadableByteStream._state;if(d!=="readable")throw new TypeError(`The stream (in ${d} state) is not in the readable state and cannot be closed`);Oo(this)}enqueue(d){if(!Pe(this))throw Kl("enqueue");if(he(d,1,"enqueue"),!ArrayBuffer.isView(d))throw new TypeError("chunk must be an array buffer view");if(d.byteLength===0)throw new TypeError("chunk must have non-zero byteLength");if(d.buffer.byteLength===0)throw new TypeError("chunk's buffer must have non-zero byteLength");if(this._closeRequested)throw new TypeError("stream is closed or draining");let T=this._controlledReadableByteStream._state;if(T!=="readable")throw new TypeError(`The stream (in ${T} state) is not in the readable state and cannot be enqueued to`);Oa(this,d)}error(d=void 0){if(!Pe(this))throw Kl("error");fi(this,d)}[ie](d){Pt(this),Ue(this);let T=this._cancelAlgorithm(d);return Pa(this),T}[ce](d){let T=this._controlledReadableByteStream;if(this._queueTotalSize>0){kR(this,d);return}let O=this._autoAllocateChunkSize;if(O!==void 0){let J;try{J=new ArrayBuffer(O)}catch(oe){d._errorSteps(oe);return}let re={buffer:J,bufferByteLength:O,byteOffset:0,byteLength:O,bytesFilled:0,minimumFill:1,elementSize:1,viewConstructor:Uint8Array,readerType:"default"};this._pendingPullIntos.push(re)}Ms(T,d),wn(this)}[H](){if(this._pendingPullIntos.length>0){let d=this._pendingPullIntos.peek();d.readerType="none",this._pendingPullIntos=new ee,this._pendingPullIntos.push(d)}}}Object.defineProperties(hn.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},byobRequest:{enumerable:!0},desiredSize:{enumerable:!0}}),i(hn.prototype.close,"close"),i(hn.prototype.enqueue,"enqueue"),i(hn.prototype.error,"error"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(hn.prototype,Symbol.toStringTag,{value:"ReadableByteStreamController",configurable:!0});function Pe(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_controlledReadableByteStream")?!1:u instanceof hn}function Ze(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_associatedReadableByteStreamController")?!1:u instanceof Le}function wn(u){if(!Po(u))return;if(u._pulling){u._pullAgain=!0;return}u._pulling=!0;let T=u._pullAlgorithm();B(T,()=>(u._pulling=!1,u._pullAgain&&(u._pullAgain=!1,wn(u)),null),O=>(fi(u,O),null))}function Pt(u){Ji(u),u._pendingPullIntos=new ee}function kt(u,d){let T=!1;u._state==="closed"&&(T=!0);let O=ks(d);d.readerType==="default"?Ye(u,O,T):oJ(u,O,T)}function ks(u){let d=u.bytesFilled,T=u.elementSize;return new u.viewConstructor(u.buffer,u.byteOffset,d/T)}function Ai(u,d,T,O){u._queue.push({buffer:d,byteOffset:T,byteLength:O}),u._queueTotalSize+=O}function xs(u,d,T,O){let J;try{J=Ua(d,T,T+O)}catch(re){throw fi(u,re),re}Ai(u,J,0,O)}function Us(u,d){d.bytesFilled>0&&xs(u,d.buffer,d.byteOffset,d.bytesFilled),Sn(u)}function Ls(u,d){let T=Math.min(u._queueTotalSize,d.byteLength-d.bytesFilled),O=d.bytesFilled+T,J=T,re=!1,oe=O%d.elementSize,me=O-oe;me>=d.minimumFill&&(J=me-d.bytesFilled,re=!0);let We=u._queue;for(;J>0;){let Se=We.peek(),ot=Math.min(J,Se.byteLength),lt=d.byteOffset+d.bytesFilled;Ct(d.buffer,lt,Se.buffer,Se.byteOffset,ot),Se.byteLength===ot?We.shift():(Se.byteOffset+=ot,Se.byteLength-=ot),u._queueTotalSize-=ot,Ps(u,ot,d),J-=ot}return re}function Ps(u,d,T){T.bytesFilled+=d}function Os(u){u._queueTotalSize===0&&u._closeRequested?(Pa(u),rh(u._controlledReadableByteStream)):wn(u)}function Ji(u){u._byobRequest!==null&&(u._byobRequest._associatedReadableByteStreamController=void 0,u._byobRequest._view=null,u._byobRequest=null)}function ji(u){for(;u._pendingPullIntos.length>0;){if(u._queueTotalSize===0)return;let d=u._pendingPullIntos.peek();Ls(u,d)&&(Sn(u),kt(u._controlledReadableByteStream,d))}}function ko(u){let d=u._controlledReadableByteStream._reader;for(;d._readRequests.length>0;){if(u._queueTotalSize===0)return;let T=d._readRequests.shift();kR(u,T)}}function xo(u,d,T,O){let J=u._controlledReadableByteStream,re=d.constructor,oe=st(re),{byteOffset:me,byteLength:We}=d,Se=T*oe,ot;try{ot=Ee(d.buffer)}catch(Ot){O._errorSteps(Ot);return}let lt={buffer:ot,bufferByteLength:ot.byteLength,byteOffset:me,byteLength:We,bytesFilled:0,minimumFill:Se,elementSize:oe,viewConstructor:re,readerType:"byob"};if(u._pendingPullIntos.length>0){u._pendingPullIntos.push(lt),PR(J,O);return}if(J._state==="closed"){let Ot=new re(lt.buffer,lt.byteOffset,0);O._closeSteps(Ot);return}if(u._queueTotalSize>0){if(Ls(u,lt)){let Ot=ks(lt);Os(u),O._chunkSteps(Ot);return}if(u._closeRequested){let Ot=new TypeError("Insufficient bytes to fill elements in the given buffer");fi(u,Ot),O._errorSteps(Ot);return}}u._pendingPullIntos.push(lt),PR(J,O),wn(u)}function Uo(u,d){d.readerType==="none"&&Sn(u);let T=u._controlledReadableByteStream;if(dI(T))for(;OR(T)>0;){let O=Sn(u);kt(T,O)}}function Lo(u,d,T){if(Ps(u,d,T),T.readerType==="none"){Us(u,T),ji(u);return}if(T.bytesFilled0){let J=T.byteOffset+T.bytesFilled;xs(u,T.buffer,J-O,O)}T.bytesFilled-=O,kt(u._controlledReadableByteStream,T),ji(u)}function Hs(u,d){let T=u._pendingPullIntos.peek();Ji(u),u._controlledReadableByteStream._state==="closed"?Uo(u,T):Lo(u,d,T),wn(u)}function Sn(u){return u._pendingPullIntos.shift()}function Po(u){let d=u._controlledReadableByteStream;return d._state!=="readable"||u._closeRequested||!u._started?!1:!!(Fs(d)&&xe(d)>0||dI(d)&&OR(d)>0||xR(u)>0)}function Pa(u){u._pullAlgorithm=void 0,u._cancelAlgorithm=void 0}function Oo(u){let d=u._controlledReadableByteStream;if(!(u._closeRequested||d._state!=="readable")){if(u._queueTotalSize>0){u._closeRequested=!0;return}if(u._pendingPullIntos.length>0){let T=u._pendingPullIntos.peek();if(T.bytesFilled%T.elementSize!==0){let O=new TypeError("Insufficient bytes to fill elements in the given buffer");throw fi(u,O),O}}Pa(u),rh(d)}}function Oa(u,d){let T=u._controlledReadableByteStream;if(u._closeRequested||T._state!=="readable")return;let{buffer:O,byteOffset:J,byteLength:re}=d;if(ge(O))throw new TypeError("chunk's buffer is detached and so cannot be enqueued");let oe=Ee(O);if(u._pendingPullIntos.length>0){let me=u._pendingPullIntos.peek();if(ge(me.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk");Ji(u),me.buffer=Ee(me.buffer),me.readerType==="none"&&Us(u,me)}if(Fs(T))if(ko(u),xe(T)===0)Ai(u,oe,J,re);else{u._pendingPullIntos.length>0&&Sn(u);let me=new Uint8Array(oe,J,re);Ye(T,me,!1)}else dI(T)?(Ai(u,oe,J,re),ji(u)):Ai(u,oe,J,re);wn(u)}function fi(u,d){let T=u._controlledReadableByteStream;T._state==="readable"&&(Pt(u),Ue(u),Pa(u),uD(T,d))}function kR(u,d){let T=u._queue.shift();u._queueTotalSize-=T.byteLength,Os(u);let O=new Uint8Array(T.buffer,T.byteOffset,T.byteLength);d._chunkSteps(O)}function lI(u){if(u._byobRequest===null&&u._pendingPullIntos.length>0){let d=u._pendingPullIntos.peek(),T=new Uint8Array(d.buffer,d.byteOffset+d.bytesFilled,d.byteLength-d.bytesFilled),O=Object.create(Le.prototype);rJ(O,u,T),u._byobRequest=O}return u._byobRequest}function xR(u){let d=u._controlledReadableByteStream._state;return d==="errored"?null:d==="closed"?0:u._strategyHWM-u._queueTotalSize}function h0(u,d){let T=u._pendingPullIntos.peek();if(u._controlledReadableByteStream._state==="closed"){if(d!==0)throw new TypeError("bytesWritten must be 0 when calling respond() on a closed stream")}else{if(d===0)throw new TypeError("bytesWritten must be greater than 0 when calling respond() on a readable stream");if(T.bytesFilled+d>T.byteLength)throw new RangeError("bytesWritten out of range")}T.buffer=Ee(T.buffer),Hs(u,d)}function d0(u,d){let T=u._pendingPullIntos.peek();if(u._controlledReadableByteStream._state==="closed"){if(d.byteLength!==0)throw new TypeError("The view's length must be 0 when calling respondWithNewView() on a closed stream")}else if(d.byteLength===0)throw new TypeError("The view's length must be greater than 0 when calling respondWithNewView() on a readable stream");if(T.byteOffset+T.bytesFilled!==d.byteOffset)throw new RangeError("The region specified by view does not match byobRequest");if(T.bufferByteLength!==d.buffer.byteLength)throw new RangeError("The buffer of view has different capacity than byobRequest");if(T.bytesFilled+d.byteLength>T.byteLength)throw new RangeError("The region specified by view is larger than byobRequest");let J=d.byteLength;T.buffer=Ee(d.buffer),Hs(u,J)}function UR(u,d,T,O,J,re,oe){d._controlledReadableByteStream=u,d._pullAgain=!1,d._pulling=!1,d._byobRequest=null,d._queue=d._queueTotalSize=void 0,Ue(d),d._closeRequested=!1,d._started=!1,d._strategyHWM=re,d._pullAlgorithm=O,d._cancelAlgorithm=J,d._autoAllocateChunkSize=oe,d._pendingPullIntos=new ee,u._readableStreamController=d;let me=T();B(f(me),()=>(d._started=!0,wn(d),null),We=>(fi(d,We),null))}function tJ(u,d,T){let O=Object.create(hn.prototype),J,re,oe;d.start!==void 0?J=()=>d.start(O):J=()=>{},d.pull!==void 0?re=()=>d.pull(O):re=()=>f(void 0),d.cancel!==void 0?oe=We=>d.cancel(We):oe=()=>f(void 0);let me=d.autoAllocateChunkSize;if(me===0)throw new TypeError("autoAllocateChunkSize must be greater than 0");UR(u,O,J,re,oe,T,me)}function rJ(u,d,T){u._associatedReadableByteStreamController=d,u._view=T}function hI(u){return new TypeError(`ReadableStreamBYOBRequest.prototype.${u} can only be used on a ReadableStreamBYOBRequest`)}function Kl(u){return new TypeError(`ReadableByteStreamController.prototype.${u} can only be used on a ReadableByteStreamController`)}function nJ(u,d){ne(u,d);let T=u?.mode;return{mode:T===void 0?void 0:iJ(T,`${d} has member 'mode' that`)}}function iJ(u,d){if(u=`${u}`,u!=="byob")throw new TypeError(`${d} '${u}' is not a valid enumeration value for ReadableStreamReaderMode`);return u}function sJ(u,d){var T;ne(u,d);let O=(T=u?.min)!==null&&T!==void 0?T:1;return{min:yr(O,`${d} has member 'min' that`)}}function LR(u){return new Ha(u)}function PR(u,d){u._reader._readIntoRequests.push(d)}function oJ(u,d,T){let J=u._reader._readIntoRequests.shift();T?J._closeSteps(d):J._chunkSteps(d)}function OR(u){return u._reader._readIntoRequests.length}function dI(u){let d=u._reader;return!(d===void 0||!VA(d))}class Ha{constructor(d){if(he(d,1,"ReadableStreamBYOBReader"),we(d,"First parameter"),Ya(d))throw new TypeError("This stream has already been locked for exclusive reading by another reader");if(!Pe(d._readableStreamController))throw new TypeError("Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte source");E(this,d),this._readIntoRequests=new ee}get closed(){return VA(this)?this._closedPromise:l(g0("closed"))}cancel(d=void 0){return VA(this)?this._ownerReadableStream===void 0?l(c("cancel")):v(this,d):l(g0("cancel"))}read(d,T={}){if(!VA(this))return l(g0("read"));if(!ArrayBuffer.isView(d))return l(new TypeError("view must be an array buffer view"));if(d.byteLength===0)return l(new TypeError("view must have non-zero byteLength"));if(d.buffer.byteLength===0)return l(new TypeError("view's buffer must have non-zero byteLength"));if(ge(d.buffer))return l(new TypeError("view's buffer has been detached"));let O;try{O=sJ(T,"options")}catch(Se){return l(Se)}let J=O.min;if(J===0)return l(new TypeError("options.min must be greater than 0"));if(WA(d)){if(J>d.byteLength)return l(new RangeError("options.min must be less than or equal to view's byteLength"))}else if(J>d.length)return l(new RangeError("options.min must be less than or equal to view's length"));if(this._ownerReadableStream===void 0)return l(c("read from"));let re,oe,me=A((Se,ot)=>{re=Se,oe=ot});return HR(this,d,J,{_chunkSteps:Se=>re({value:Se,done:!1}),_closeSteps:Se=>re({value:Se,done:!0}),_errorSteps:Se=>oe(Se)}),me}releaseLock(){if(!VA(this))throw g0("releaseLock");this._ownerReadableStream!==void 0&&aJ(this)}}Object.defineProperties(Ha.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),i(Ha.prototype.cancel,"cancel"),i(Ha.prototype.read,"read"),i(Ha.prototype.releaseLock,"releaseLock"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Ha.prototype,Symbol.toStringTag,{value:"ReadableStreamBYOBReader",configurable:!0});function VA(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_readIntoRequests")?!1:u instanceof Ha}function HR(u,d,T,O){let J=u._ownerReadableStream;J._disturbed=!0,J._state==="errored"?O._errorSteps(J._storedError):xo(J._readableStreamController,d,T,O)}function aJ(u){b(u);let d=new TypeError("Reader was released");qR(u,d)}function qR(u,d){let T=u._readIntoRequests;u._readIntoRequests=new ee,T.forEach(O=>{O._errorSteps(d)})}function g0(u){return new TypeError(`ReadableStreamBYOBReader.prototype.${u} can only be used on a ReadableStreamBYOBReader`)}function Xl(u,d){let{highWaterMark:T}=u;if(T===void 0)return d;if(W(T)||T<0)throw new RangeError("Invalid highWaterMark");return T}function p0(u){let{size:d}=u;return d||(()=>1)}function E0(u,d){ne(u,d);let T=u?.highWaterMark,O=u?.size;return{highWaterMark:T===void 0?void 0:wt(T),size:O===void 0?void 0:AJ(O,`${d} has member 'size' that`)}}function AJ(u,d){return Ae(u,d),T=>wt(u(T))}function fJ(u,d){ne(u,d);let T=u?.abort,O=u?.close,J=u?.start,re=u?.type,oe=u?.write;return{abort:T===void 0?void 0:uJ(T,u,`${d} has member 'abort' that`),close:O===void 0?void 0:cJ(O,u,`${d} has member 'close' that`),start:J===void 0?void 0:lJ(J,u,`${d} has member 'start' that`),write:oe===void 0?void 0:hJ(oe,u,`${d} has member 'write' that`),type:re}}function uJ(u,d,T){return Ae(u,T),O=>Y(u,d,[O])}function cJ(u,d,T){return Ae(u,T),()=>Y(u,d,[])}function lJ(u,d,T){return Ae(u,T),O=>G(u,d,[O])}function hJ(u,d,T){return Ae(u,T),(O,J)=>Y(u,d,[O,J])}function GR(u,d){if(!Mu(u))throw new TypeError(`${d} is not a WritableStream.`)}function dJ(u){if(typeof u!="object"||u===null)return!1;try{return typeof u.aborted=="boolean"}catch{return!1}}let gJ=typeof AbortController=="function";function pJ(){if(gJ)return new AbortController}class qa{constructor(d={},T={}){d===void 0?d=null:pe(d,"First parameter");let O=E0(T,"Second parameter"),J=fJ(d,"First parameter");if(WR(this),J.type!==void 0)throw new RangeError("Invalid type is specified");let oe=p0(O),me=Xl(O,1);DJ(this,J,me,oe)}get locked(){if(!Mu(this))throw b0("locked");return Fu(this)}abort(d=void 0){return Mu(this)?Fu(this)?l(new TypeError("Cannot abort a stream that already has a writer")):y0(this,d):l(b0("abort"))}close(){return Mu(this)?Fu(this)?l(new TypeError("Cannot close a stream that already has a writer")):qs(this)?l(new TypeError("Cannot close an already-closing stream")):VR(this):l(b0("close"))}getWriter(){if(!Mu(this))throw b0("getWriter");return YR(this)}}Object.defineProperties(qa.prototype,{abort:{enumerable:!0},close:{enumerable:!0},getWriter:{enumerable:!0},locked:{enumerable:!0}}),i(qa.prototype.abort,"abort"),i(qa.prototype.close,"close"),i(qa.prototype.getWriter,"getWriter"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(qa.prototype,Symbol.toStringTag,{value:"WritableStream",configurable:!0});function YR(u){return new Ho(u)}function EJ(u,d,T,O,J=1,re=()=>1){let oe=Object.create(qa.prototype);WR(oe);let me=Object.create(ku.prototype);return ZR(oe,me,u,d,T,O,J,re),oe}function WR(u){u._state="writable",u._storedError=void 0,u._writer=void 0,u._writableStreamController=void 0,u._writeRequests=new ee,u._inFlightWriteRequest=void 0,u._closeRequest=void 0,u._inFlightCloseRequest=void 0,u._pendingAbortRequest=void 0,u._backpressure=!1}function Mu(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_writableStreamController")?!1:u instanceof qa}function Fu(u){return u._writer!==void 0}function y0(u,d){var T;if(u._state==="closed"||u._state==="errored")return f(void 0);u._writableStreamController._abortReason=d,(T=u._writableStreamController._abortController)===null||T===void 0||T.abort(d);let O=u._state;if(O==="closed"||O==="errored")return f(void 0);if(u._pendingAbortRequest!==void 0)return u._pendingAbortRequest._promise;let J=!1;O==="erroring"&&(J=!0,d=void 0);let re=A((oe,me)=>{u._pendingAbortRequest={_promise:void 0,_resolve:oe,_reject:me,_reason:d,_wasAlreadyErroring:J}});return u._pendingAbortRequest._promise=re,J||pI(u,d),re}function VR(u){let d=u._state;if(d==="closed"||d==="errored")return l(new TypeError(`The stream (in ${d} state) is not in the writable state and cannot be closed`));let T=A((J,re)=>{let oe={_resolve:J,_reject:re};u._closeRequest=oe}),O=u._writer;return O!==void 0&&u._backpressure&&d==="writable"&&QI(O),TJ(u._writableStreamController),T}function yJ(u){return A((T,O)=>{let J={_resolve:T,_reject:O};u._writeRequests.push(J)})}function gI(u,d){if(u._state==="writable"){pI(u,d);return}EI(u)}function pI(u,d){let T=u._writableStreamController;u._state="erroring",u._storedError=d;let O=u._writer;O!==void 0&&jR(O,d),!CJ(u)&&T._started&&EI(u)}function EI(u){u._state="errored",u._writableStreamController[se]();let d=u._storedError;if(u._writeRequests.forEach(J=>{J._reject(d)}),u._writeRequests=new ee,u._pendingAbortRequest===void 0){m0(u);return}let T=u._pendingAbortRequest;if(u._pendingAbortRequest=void 0,T._wasAlreadyErroring){T._reject(d),m0(u);return}let O=u._writableStreamController[j](T._reason);B(O,()=>(T._resolve(),m0(u),null),J=>(T._reject(J),m0(u),null))}function mJ(u){u._inFlightWriteRequest._resolve(void 0),u._inFlightWriteRequest=void 0}function BJ(u,d){u._inFlightWriteRequest._reject(d),u._inFlightWriteRequest=void 0,gI(u,d)}function IJ(u){u._inFlightCloseRequest._resolve(void 0),u._inFlightCloseRequest=void 0,u._state==="erroring"&&(u._storedError=void 0,u._pendingAbortRequest!==void 0&&(u._pendingAbortRequest._resolve(),u._pendingAbortRequest=void 0)),u._state="closed";let T=u._writer;T!==void 0&&rD(T)}function bJ(u,d){u._inFlightCloseRequest._reject(d),u._inFlightCloseRequest=void 0,u._pendingAbortRequest!==void 0&&(u._pendingAbortRequest._reject(d),u._pendingAbortRequest=void 0),gI(u,d)}function qs(u){return!(u._closeRequest===void 0&&u._inFlightCloseRequest===void 0)}function CJ(u){return!(u._inFlightWriteRequest===void 0&&u._inFlightCloseRequest===void 0)}function QJ(u){u._inFlightCloseRequest=u._closeRequest,u._closeRequest=void 0}function wJ(u){u._inFlightWriteRequest=u._writeRequests.shift()}function m0(u){u._closeRequest!==void 0&&(u._closeRequest._reject(u._storedError),u._closeRequest=void 0);let d=u._writer;d!==void 0&&bI(d,u._storedError)}function yI(u,d){let T=u._writer;T!==void 0&&d!==u._backpressure&&(d?LJ(T):QI(T)),u._backpressure=d}class Ho{constructor(d){if(he(d,1,"WritableStreamDefaultWriter"),GR(d,"First parameter"),Fu(d))throw new TypeError("This stream has already been locked for exclusive writing by another writer");this._ownerWritableStream=d,d._writer=this;let T=d._state;if(T==="writable")!qs(d)&&d._backpressure?Q0(this):nD(this),C0(this);else if(T==="erroring")CI(this,d._storedError),C0(this);else if(T==="closed")nD(this),xJ(this);else{let O=d._storedError;CI(this,O),tD(this,O)}}get closed(){return JA(this)?this._closedPromise:l(jA("closed"))}get desiredSize(){if(!JA(this))throw jA("desiredSize");if(this._ownerWritableStream===void 0)throw $l("desiredSize");return RJ(this)}get ready(){return JA(this)?this._readyPromise:l(jA("ready"))}abort(d=void 0){return JA(this)?this._ownerWritableStream===void 0?l($l("abort")):SJ(this,d):l(jA("abort"))}close(){if(!JA(this))return l(jA("close"));let d=this._ownerWritableStream;return d===void 0?l($l("close")):qs(d)?l(new TypeError("Cannot close an already-closing stream")):JR(this)}releaseLock(){if(!JA(this))throw jA("releaseLock");this._ownerWritableStream!==void 0&&zR(this)}write(d=void 0){return JA(this)?this._ownerWritableStream===void 0?l($l("write to")):KR(this,d):l(jA("write"))}}Object.defineProperties(Ho.prototype,{abort:{enumerable:!0},close:{enumerable:!0},releaseLock:{enumerable:!0},write:{enumerable:!0},closed:{enumerable:!0},desiredSize:{enumerable:!0},ready:{enumerable:!0}}),i(Ho.prototype.abort,"abort"),i(Ho.prototype.close,"close"),i(Ho.prototype.releaseLock,"releaseLock"),i(Ho.prototype.write,"write"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Ho.prototype,Symbol.toStringTag,{value:"WritableStreamDefaultWriter",configurable:!0});function JA(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_ownerWritableStream")?!1:u instanceof Ho}function SJ(u,d){let T=u._ownerWritableStream;return y0(T,d)}function JR(u){let d=u._ownerWritableStream;return VR(d)}function _J(u){let d=u._ownerWritableStream,T=d._state;return qs(d)||T==="closed"?f(void 0):T==="errored"?l(d._storedError):JR(u)}function vJ(u,d){u._closedPromiseState==="pending"?bI(u,d):UJ(u,d)}function jR(u,d){u._readyPromiseState==="pending"?iD(u,d):PJ(u,d)}function RJ(u){let d=u._ownerWritableStream,T=d._state;return T==="errored"||T==="erroring"?null:T==="closed"?0:$R(d._writableStreamController)}function zR(u){let d=u._ownerWritableStream,T=new TypeError("Writer was released and can no longer be used to monitor the stream's closedness");jR(u,T),vJ(u,T),d._writer=void 0,u._ownerWritableStream=void 0}function KR(u,d){let T=u._ownerWritableStream,O=T._writableStreamController,J=NJ(O,d);if(T!==u._ownerWritableStream)return l($l("write to"));let re=T._state;if(re==="errored")return l(T._storedError);if(qs(T)||re==="closed")return l(new TypeError("The stream is closing or closed and cannot be written to"));if(re==="erroring")return l(T._storedError);let oe=yJ(T);return MJ(O,d,J),oe}let XR={};class ku{constructor(){throw new TypeError("Illegal constructor")}get abortReason(){if(!mI(this))throw II("abortReason");return this._abortReason}get signal(){if(!mI(this))throw II("signal");if(this._abortController===void 0)throw new TypeError("WritableStreamDefaultController.prototype.signal is not supported");return this._abortController.signal}error(d=void 0){if(!mI(this))throw II("error");this._controlledWritableStream._state==="writable"&&eD(this,d)}[j](d){let T=this._abortAlgorithm(d);return B0(this),T}[se](){Ue(this)}}Object.defineProperties(ku.prototype,{abortReason:{enumerable:!0},signal:{enumerable:!0},error:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(ku.prototype,Symbol.toStringTag,{value:"WritableStreamDefaultController",configurable:!0});function mI(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_controlledWritableStream")?!1:u instanceof ku}function ZR(u,d,T,O,J,re,oe,me){d._controlledWritableStream=u,u._writableStreamController=d,d._queue=void 0,d._queueTotalSize=void 0,Ue(d),d._abortReason=void 0,d._abortController=pJ(),d._started=!1,d._strategySizeAlgorithm=me,d._strategyHWM=oe,d._writeAlgorithm=O,d._closeAlgorithm=J,d._abortAlgorithm=re;let We=BI(d);yI(u,We);let Se=T(),ot=f(Se);B(ot,()=>(d._started=!0,I0(d),null),lt=>(d._started=!0,gI(u,lt),null))}function DJ(u,d,T,O){let J=Object.create(ku.prototype),re,oe,me,We;d.start!==void 0?re=()=>d.start(J):re=()=>{},d.write!==void 0?oe=Se=>d.write(Se,J):oe=()=>f(void 0),d.close!==void 0?me=()=>d.close():me=()=>f(void 0),d.abort!==void 0?We=Se=>d.abort(Se):We=()=>f(void 0),ZR(u,J,re,oe,me,We,T,O)}function B0(u){u._writeAlgorithm=void 0,u._closeAlgorithm=void 0,u._abortAlgorithm=void 0,u._strategySizeAlgorithm=void 0}function TJ(u){Xe(u,XR,0),I0(u)}function NJ(u,d){try{return u._strategySizeAlgorithm(d)}catch(T){return Zl(u,T),1}}function $R(u){return u._strategyHWM-u._queueTotalSize}function MJ(u,d,T){try{Xe(u,d,T)}catch(J){Zl(u,J);return}let O=u._controlledWritableStream;if(!qs(O)&&O._state==="writable"){let J=BI(u);yI(O,J)}I0(u)}function I0(u){let d=u._controlledWritableStream;if(!u._started||d._inFlightWriteRequest!==void 0)return;if(d._state==="erroring"){EI(d);return}if(u._queue.length===0)return;let O=YA(u);O===XR?FJ(u):kJ(u,O)}function Zl(u,d){u._controlledWritableStream._state==="writable"&&eD(u,d)}function FJ(u){let d=u._controlledWritableStream;QJ(d),Ke(u);let T=u._closeAlgorithm();B0(u),B(T,()=>(IJ(d),null),O=>(bJ(d,O),null))}function kJ(u,d){let T=u._controlledWritableStream;wJ(T);let O=u._writeAlgorithm(d);B(O,()=>{mJ(T);let J=T._state;if(Ke(u),!qs(T)&&J==="writable"){let re=BI(u);yI(T,re)}return I0(u),null},J=>(T._state==="writable"&&B0(u),BJ(T,J),null))}function BI(u){return $R(u)<=0}function eD(u,d){let T=u._controlledWritableStream;B0(u),pI(T,d)}function b0(u){return new TypeError(`WritableStream.prototype.${u} can only be used on a WritableStream`)}function II(u){return new TypeError(`WritableStreamDefaultController.prototype.${u} can only be used on a WritableStreamDefaultController`)}function jA(u){return new TypeError(`WritableStreamDefaultWriter.prototype.${u} can only be used on a WritableStreamDefaultWriter`)}function $l(u){return new TypeError("Cannot "+u+" a stream using a released writer")}function C0(u){u._closedPromise=A((d,T)=>{u._closedPromise_resolve=d,u._closedPromise_reject=T,u._closedPromiseState="pending"})}function tD(u,d){C0(u),bI(u,d)}function xJ(u){C0(u),rD(u)}function bI(u,d){u._closedPromise_reject!==void 0&&(P(u._closedPromise),u._closedPromise_reject(d),u._closedPromise_resolve=void 0,u._closedPromise_reject=void 0,u._closedPromiseState="rejected")}function UJ(u,d){tD(u,d)}function rD(u){u._closedPromise_resolve!==void 0&&(u._closedPromise_resolve(void 0),u._closedPromise_resolve=void 0,u._closedPromise_reject=void 0,u._closedPromiseState="resolved")}function Q0(u){u._readyPromise=A((d,T)=>{u._readyPromise_resolve=d,u._readyPromise_reject=T}),u._readyPromiseState="pending"}function CI(u,d){Q0(u),iD(u,d)}function nD(u){Q0(u),QI(u)}function iD(u,d){u._readyPromise_reject!==void 0&&(P(u._readyPromise),u._readyPromise_reject(d),u._readyPromise_resolve=void 0,u._readyPromise_reject=void 0,u._readyPromiseState="rejected")}function LJ(u){Q0(u)}function PJ(u,d){CI(u,d)}function QI(u){u._readyPromise_resolve!==void 0&&(u._readyPromise_resolve(void 0),u._readyPromise_resolve=void 0,u._readyPromise_reject=void 0,u._readyPromiseState="fulfilled")}function OJ(){if(typeof globalThis<"u")return globalThis;if(typeof self<"u")return self;if(typeof globalThis<"u")return globalThis}let wI=OJ();function HJ(u){if(!(typeof u=="function"||typeof u=="object")||u.name!=="DOMException")return!1;try{return new u,!0}catch{return!1}}function qJ(){let u=wI?.DOMException;return HJ(u)?u:void 0}function GJ(){let u=function(T,O){this.message=T||"",this.name=O||"Error",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)};return i(u,"DOMException"),u.prototype=Object.create(Error.prototype),Object.defineProperty(u.prototype,"constructor",{value:u,writable:!0,configurable:!0}),u}let YJ=qJ()||GJ();function sD(u,d,T,O,J,re){let oe=ve(u),me=YR(d);u._disturbed=!0;let We=!1,Se=f(void 0);return A((ot,lt)=>{let Ot;if(re!==void 0){if(Ot=()=>{let Me=re.reason!==void 0?re.reason:new YJ("Aborted","AbortError"),mt=[];O||mt.push(()=>d._state==="writable"?y0(d,Me):f(void 0)),J||mt.push(()=>u._state==="readable"?Ki(u,Me):f(void 0)),_n(()=>Promise.all(mt.map(Gt=>Gt())),!0,Me)},re.aborted){Ot();return}re.addEventListener("abort",Ot)}function Xi(){return A((Me,mt)=>{function Gt(Wn){Wn?Me():p(Pu(),Gt,mt)}Gt(!1)})}function Pu(){return We?f(!0):p(me._readyPromise,()=>A((Me,mt)=>{en(oe,{_chunkSteps:Gt=>{Se=p(KR(me,Gt),void 0,t),Me(!1)},_closeSteps:()=>Me(!0),_errorSteps:mt})}))}if(Go(u,oe._closedPromise,Me=>(O?ui(!0,Me):_n(()=>y0(d,Me),!0,Me),null)),Go(d,me._closedPromise,Me=>(J?ui(!0,Me):_n(()=>Ki(u,Me),!0,Me),null)),dn(u,oe._closedPromise,()=>(T?ui():_n(()=>_J(me)),null)),qs(d)||d._state==="closed"){let Me=new TypeError("the destination writable stream closed before all data could be piped to it");J?ui(!0,Me):_n(()=>Ki(u,Me),!0,Me)}P(Xi());function Va(){let Me=Se;return p(Se,()=>Me!==Se?Va():void 0)}function Go(Me,mt,Gt){Me._state==="errored"?Gt(Me._storedError):_(mt,Gt)}function dn(Me,mt,Gt){Me._state==="closed"?Gt():S(mt,Gt)}function _n(Me,mt,Gt){if(We)return;We=!0,d._state==="writable"&&!qs(d)?S(Va(),Wn):Wn();function Wn(){return B(Me(),()=>Yo(mt,Gt),Ou=>Yo(!0,Ou)),null}}function ui(Me,mt){We||(We=!0,d._state==="writable"&&!qs(d)?S(Va(),()=>Yo(Me,mt)):Yo(Me,mt))}function Yo(Me,mt){return zR(me),b(oe),re!==void 0&&re.removeEventListener("abort",Ot),Me?lt(mt):ot(void 0),null}})}class qo{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!w0(this))throw _0("desiredSize");return SI(this)}close(){if(!w0(this))throw _0("close");if(!Uu(this))throw new TypeError("The stream is not in a state that permits close");zA(this)}enqueue(d=void 0){if(!w0(this))throw _0("enqueue");if(!Uu(this))throw new TypeError("The stream is not in a state that permits enqueue");return xu(this,d)}error(d=void 0){if(!w0(this))throw _0("error");zi(this,d)}[ie](d){Ue(this);let T=this._cancelAlgorithm(d);return S0(this),T}[ce](d){let T=this._controlledReadableStream;if(this._queue.length>0){let O=Ke(this);this._closeRequested&&this._queue.length===0?(S0(this),rh(T)):eh(this),d._chunkSteps(O)}else Ms(T,d),eh(this)}[H](){}}Object.defineProperties(qo.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},desiredSize:{enumerable:!0}}),i(qo.prototype.close,"close"),i(qo.prototype.enqueue,"enqueue"),i(qo.prototype.error,"error"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(qo.prototype,Symbol.toStringTag,{value:"ReadableStreamDefaultController",configurable:!0});function w0(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_controlledReadableStream")?!1:u instanceof qo}function eh(u){if(!oD(u))return;if(u._pulling){u._pullAgain=!0;return}u._pulling=!0;let T=u._pullAlgorithm();B(T,()=>(u._pulling=!1,u._pullAgain&&(u._pullAgain=!1,eh(u)),null),O=>(zi(u,O),null))}function oD(u){let d=u._controlledReadableStream;return!Uu(u)||!u._started?!1:!!(Ya(d)&&xe(d)>0||SI(u)>0)}function S0(u){u._pullAlgorithm=void 0,u._cancelAlgorithm=void 0,u._strategySizeAlgorithm=void 0}function zA(u){if(!Uu(u))return;let d=u._controlledReadableStream;u._closeRequested=!0,u._queue.length===0&&(S0(u),rh(d))}function xu(u,d){if(!Uu(u))return;let T=u._controlledReadableStream;if(Ya(T)&&xe(T)>0)Ye(T,d,!1);else{let O;try{O=u._strategySizeAlgorithm(d)}catch(J){throw zi(u,J),J}try{Xe(u,d,O)}catch(J){throw zi(u,J),J}}eh(u)}function zi(u,d){let T=u._controlledReadableStream;T._state==="readable"&&(Ue(u),S0(u),uD(T,d))}function SI(u){let d=u._controlledReadableStream._state;return d==="errored"?null:d==="closed"?0:u._strategyHWM-u._queueTotalSize}function WJ(u){return!oD(u)}function Uu(u){let d=u._controlledReadableStream._state;return!u._closeRequested&&d==="readable"}function aD(u,d,T,O,J,re,oe){d._controlledReadableStream=u,d._queue=void 0,d._queueTotalSize=void 0,Ue(d),d._started=!1,d._closeRequested=!1,d._pullAgain=!1,d._pulling=!1,d._strategySizeAlgorithm=oe,d._strategyHWM=re,d._pullAlgorithm=O,d._cancelAlgorithm=J,u._readableStreamController=d;let me=T();B(f(me),()=>(d._started=!0,eh(d),null),We=>(zi(d,We),null))}function VJ(u,d,T,O){let J=Object.create(qo.prototype),re,oe,me;d.start!==void 0?re=()=>d.start(J):re=()=>{},d.pull!==void 0?oe=()=>d.pull(J):oe=()=>f(void 0),d.cancel!==void 0?me=We=>d.cancel(We):me=()=>f(void 0),aD(u,J,re,oe,me,T,O)}function _0(u){return new TypeError(`ReadableStreamDefaultController.prototype.${u} can only be used on a ReadableStreamDefaultController`)}function JJ(u,d){return Pe(u._readableStreamController)?zJ(u):jJ(u)}function jJ(u,d){let T=ve(u),O=!1,J=!1,re=!1,oe=!1,me,We,Se,ot,lt,Ot=A(dn=>{lt=dn});function Xi(){return O?(J=!0,f(void 0)):(O=!0,en(T,{_chunkSteps:_n=>{U(()=>{J=!1;let ui=_n,Yo=_n;re||xu(Se._readableStreamController,ui),oe||xu(ot._readableStreamController,Yo),O=!1,J&&Xi()})},_closeSteps:()=>{O=!1,re||zA(Se._readableStreamController),oe||zA(ot._readableStreamController),(!re||!oe)&<(void 0)},_errorSteps:()=>{O=!1}}),f(void 0))}function Pu(dn){if(re=!0,me=dn,oe){let _n=ye([me,We]),ui=Ki(u,_n);lt(ui)}return Ot}function Va(dn){if(oe=!0,We=dn,re){let _n=ye([me,We]),ui=Ki(u,_n);lt(ui)}return Ot}function Go(){}return Se=th(Go,Xi,Pu),ot=th(Go,Xi,Va),_(T._closedPromise,dn=>(zi(Se._readableStreamController,dn),zi(ot._readableStreamController,dn),(!re||!oe)&<(void 0),null)),[Se,ot]}function zJ(u){let d=ve(u),T=!1,O=!1,J=!1,re=!1,oe=!1,me,We,Se,ot,lt,Ot=A(Me=>{lt=Me});function Xi(Me){_(Me._closedPromise,mt=>(Me!==d||(fi(Se._readableStreamController,mt),fi(ot._readableStreamController,mt),(!re||!oe)&<(void 0)),null))}function Pu(){VA(d)&&(b(d),d=ve(u),Xi(d)),en(d,{_chunkSteps:mt=>{U(()=>{O=!1,J=!1;let Gt=mt,Wn=mt;if(!re&&!oe)try{Wn=La(mt)}catch(Ou){fi(Se._readableStreamController,Ou),fi(ot._readableStreamController,Ou),lt(Ki(u,Ou));return}re||Oa(Se._readableStreamController,Gt),oe||Oa(ot._readableStreamController,Wn),T=!1,O?Go():J&&dn()})},_closeSteps:()=>{T=!1,re||Oo(Se._readableStreamController),oe||Oo(ot._readableStreamController),Se._readableStreamController._pendingPullIntos.length>0&&h0(Se._readableStreamController,0),ot._readableStreamController._pendingPullIntos.length>0&&h0(ot._readableStreamController,0),(!re||!oe)&<(void 0)},_errorSteps:()=>{T=!1}})}function Va(Me,mt){De(d)&&(b(d),d=LR(u),Xi(d));let Gt=mt?ot:Se,Wn=mt?Se:ot;HR(d,Me,1,{_chunkSteps:Hu=>{U(()=>{O=!1,J=!1;let qu=mt?oe:re;if(mt?re:oe)qu||d0(Gt._readableStreamController,Hu);else{let CD;try{CD=La(Hu)}catch(TI){fi(Gt._readableStreamController,TI),fi(Wn._readableStreamController,TI),lt(Ki(u,TI));return}qu||d0(Gt._readableStreamController,Hu),Oa(Wn._readableStreamController,CD)}T=!1,O?Go():J&&dn()})},_closeSteps:Hu=>{T=!1;let qu=mt?oe:re,k0=mt?re:oe;qu||Oo(Gt._readableStreamController),k0||Oo(Wn._readableStreamController),Hu!==void 0&&(qu||d0(Gt._readableStreamController,Hu),!k0&&Wn._readableStreamController._pendingPullIntos.length>0&&h0(Wn._readableStreamController,0)),(!qu||!k0)&<(void 0)},_errorSteps:()=>{T=!1}})}function Go(){if(T)return O=!0,f(void 0);T=!0;let Me=lI(Se._readableStreamController);return Me===null?Pu():Va(Me._view,!1),f(void 0)}function dn(){if(T)return J=!0,f(void 0);T=!0;let Me=lI(ot._readableStreamController);return Me===null?Pu():Va(Me._view,!0),f(void 0)}function _n(Me){if(re=!0,me=Me,oe){let mt=ye([me,We]),Gt=Ki(u,mt);lt(Gt)}return Ot}function ui(Me){if(oe=!0,We=Me,re){let mt=ye([me,We]),Gt=Ki(u,mt);lt(Gt)}return Ot}function Yo(){}return Se=fD(Yo,Go,_n),ot=fD(Yo,dn,ui),Xi(d),[Se,ot]}function KJ(u){return r(u)&&typeof u.getReader<"u"}function XJ(u){return KJ(u)?$J(u.getReader()):ZJ(u)}function ZJ(u){let d,T=$e(u,"async"),O=t;function J(){let oe;try{oe=rt(T)}catch(We){return l(We)}let me=f(oe);return N(me,We=>{if(!r(We))throw new TypeError("The promise returned by the iterator.next() method must fulfill with an object");if(GA(We))zA(d._readableStreamController);else{let ot=nt(We);xu(d._readableStreamController,ot)}})}function re(oe){let me=T.iterator,We;try{We=je(me,"return")}catch(lt){return l(lt)}if(We===void 0)return f(void 0);let Se;try{Se=G(We,me,[oe])}catch(lt){return l(lt)}let ot=f(Se);return N(ot,lt=>{if(!r(lt))throw new TypeError("The promise returned by the iterator.return() method must fulfill with an object")})}return d=th(O,J,re,0),d}function $J(u){let d,T=t;function O(){let re;try{re=u.read()}catch(oe){return l(oe)}return N(re,oe=>{if(!r(oe))throw new TypeError("The promise returned by the reader.read() method must fulfill with an object");if(oe.done)zA(d._readableStreamController);else{let me=oe.value;xu(d._readableStreamController,me)}})}function J(re){try{return f(u.cancel(re))}catch(oe){return l(oe)}}return d=th(T,O,J,0),d}function ej(u,d){ne(u,d);let T=u,O=T?.autoAllocateChunkSize,J=T?.cancel,re=T?.pull,oe=T?.start,me=T?.type;return{autoAllocateChunkSize:O===void 0?void 0:yr(O,`${d} has member 'autoAllocateChunkSize' that`),cancel:J===void 0?void 0:tj(J,T,`${d} has member 'cancel' that`),pull:re===void 0?void 0:rj(re,T,`${d} has member 'pull' that`),start:oe===void 0?void 0:nj(oe,T,`${d} has member 'start' that`),type:me===void 0?void 0:ij(me,`${d} has member 'type' that`)}}function tj(u,d,T){return Ae(u,T),O=>Y(u,d,[O])}function rj(u,d,T){return Ae(u,T),O=>Y(u,d,[O])}function nj(u,d,T){return Ae(u,T),O=>G(u,d,[O])}function ij(u,d){if(u=`${u}`,u!=="bytes")throw new TypeError(`${d} '${u}' is not a valid enumeration value for ReadableStreamType`);return u}function sj(u,d){return ne(u,d),{preventCancel:!!u?.preventCancel}}function AD(u,d){ne(u,d);let T=u?.preventAbort,O=u?.preventCancel,J=u?.preventClose,re=u?.signal;return re!==void 0&&oj(re,`${d} has member 'signal' that`),{preventAbort:!!T,preventCancel:!!O,preventClose:!!J,signal:re}}function oj(u,d){if(!dJ(u))throw new TypeError(`${d} is not an AbortSignal.`)}function aj(u,d){ne(u,d);let T=u?.readable;de(T,"readable","ReadableWritablePair"),we(T,`${d} has member 'readable' that`);let O=u?.writable;return de(O,"writable","ReadableWritablePair"),GR(O,`${d} has member 'writable' that`),{readable:T,writable:O}}class tn{constructor(d={},T={}){d===void 0?d=null:pe(d,"First parameter");let O=E0(T,"Second parameter"),J=ej(d,"First parameter");if(_I(this),J.type==="bytes"){if(O.size!==void 0)throw new RangeError("The strategy for a byte stream cannot have a size function");let re=Xl(O,0);tJ(this,J,re)}else{let re=p0(O),oe=Xl(O,1);VJ(this,J,oe,re)}}get locked(){if(!Ga(this))throw KA("locked");return Ya(this)}cancel(d=void 0){return Ga(this)?Ya(this)?l(new TypeError("Cannot cancel a stream that already has a reader")):Ki(this,d):l(KA("cancel"))}getReader(d=void 0){if(!Ga(this))throw KA("getReader");return nJ(d,"First parameter").mode===void 0?ve(this):LR(this)}pipeThrough(d,T={}){if(!Ga(this))throw KA("pipeThrough");he(d,1,"pipeThrough");let O=aj(d,"First parameter"),J=AD(T,"Second parameter");if(Ya(this))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked ReadableStream");if(Fu(O.writable))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked WritableStream");let re=sD(this,O.writable,J.preventClose,J.preventAbort,J.preventCancel,J.signal);return P(re),O.readable}pipeTo(d,T={}){if(!Ga(this))return l(KA("pipeTo"));if(d===void 0)return l("Parameter 1 is required in 'pipeTo'.");if(!Mu(d))return l(new TypeError("ReadableStream.prototype.pipeTo's first argument must be a WritableStream"));let O;try{O=AD(T,"Second parameter")}catch(J){return l(J)}return Ya(this)?l(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream")):Fu(d)?l(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream")):sD(this,d,O.preventClose,O.preventAbort,O.preventCancel,O.signal)}tee(){if(!Ga(this))throw KA("tee");let d=JJ(this);return ye(d)}values(d=void 0){if(!Ga(this))throw KA("values");let T=sj(d,"First parameter");return m(this,T.preventCancel)}[Fo](d){return this.values(d)}static from(d){return XJ(d)}}Object.defineProperties(tn,{from:{enumerable:!0}}),Object.defineProperties(tn.prototype,{cancel:{enumerable:!0},getReader:{enumerable:!0},pipeThrough:{enumerable:!0},pipeTo:{enumerable:!0},tee:{enumerable:!0},values:{enumerable:!0},locked:{enumerable:!0}}),i(tn.from,"from"),i(tn.prototype.cancel,"cancel"),i(tn.prototype.getReader,"getReader"),i(tn.prototype.pipeThrough,"pipeThrough"),i(tn.prototype.pipeTo,"pipeTo"),i(tn.prototype.tee,"tee"),i(tn.prototype.values,"values"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(tn.prototype,Symbol.toStringTag,{value:"ReadableStream",configurable:!0}),Object.defineProperty(tn.prototype,Fo,{value:tn.prototype.values,writable:!0,configurable:!0});function th(u,d,T,O=1,J=()=>1){let re=Object.create(tn.prototype);_I(re);let oe=Object.create(qo.prototype);return aD(re,oe,u,d,T,O,J),re}function fD(u,d,T){let O=Object.create(tn.prototype);_I(O);let J=Object.create(hn.prototype);return UR(O,J,u,d,T,0,void 0),O}function _I(u){u._state="readable",u._reader=void 0,u._storedError=void 0,u._disturbed=!1}function Ga(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_readableStreamController")?!1:u instanceof tn}function Ya(u){return u._reader!==void 0}function Ki(u,d){if(u._disturbed=!0,u._state==="closed")return f(void 0);if(u._state==="errored")return l(u._storedError);rh(u);let T=u._reader;if(T!==void 0&&VA(T)){let J=T._readIntoRequests;T._readIntoRequests=new ee,J.forEach(re=>{re._closeSteps(void 0)})}let O=u._readableStreamController[ie](d);return N(O,t)}function rh(u){u._state="closed";let d=u._reader;if(d!==void 0&&(D(d),De(d))){let T=d._readRequests;d._readRequests=new ee,T.forEach(O=>{O._closeSteps()})}}function uD(u,d){u._state="errored",u._storedError=d;let T=u._reader;T!==void 0&&(C(T,d),De(T)?He(T,d):qR(T,d))}function KA(u){return new TypeError(`ReadableStream.prototype.${u} can only be used on a ReadableStream`)}function cD(u,d){ne(u,d);let T=u?.highWaterMark;return de(T,"highWaterMark","QueuingStrategyInit"),{highWaterMark:wt(T)}}let lD=u=>u.byteLength;i(lD,"size");class v0{constructor(d){he(d,1,"ByteLengthQueuingStrategy"),d=cD(d,"First parameter"),this._byteLengthQueuingStrategyHighWaterMark=d.highWaterMark}get highWaterMark(){if(!dD(this))throw hD("highWaterMark");return this._byteLengthQueuingStrategyHighWaterMark}get size(){if(!dD(this))throw hD("size");return lD}}Object.defineProperties(v0.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(v0.prototype,Symbol.toStringTag,{value:"ByteLengthQueuingStrategy",configurable:!0});function hD(u){return new TypeError(`ByteLengthQueuingStrategy.prototype.${u} can only be used on a ByteLengthQueuingStrategy`)}function dD(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_byteLengthQueuingStrategyHighWaterMark")?!1:u instanceof v0}let gD=()=>1;i(gD,"size");class R0{constructor(d){he(d,1,"CountQueuingStrategy"),d=cD(d,"First parameter"),this._countQueuingStrategyHighWaterMark=d.highWaterMark}get highWaterMark(){if(!ED(this))throw pD("highWaterMark");return this._countQueuingStrategyHighWaterMark}get size(){if(!ED(this))throw pD("size");return gD}}Object.defineProperties(R0.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(R0.prototype,Symbol.toStringTag,{value:"CountQueuingStrategy",configurable:!0});function pD(u){return new TypeError(`CountQueuingStrategy.prototype.${u} can only be used on a CountQueuingStrategy`)}function ED(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_countQueuingStrategyHighWaterMark")?!1:u instanceof R0}function Aj(u,d){ne(u,d);let T=u?.cancel,O=u?.flush,J=u?.readableType,re=u?.start,oe=u?.transform,me=u?.writableType;return{cancel:T===void 0?void 0:lj(T,u,`${d} has member 'cancel' that`),flush:O===void 0?void 0:fj(O,u,`${d} has member 'flush' that`),readableType:J,start:re===void 0?void 0:uj(re,u,`${d} has member 'start' that`),transform:oe===void 0?void 0:cj(oe,u,`${d} has member 'transform' that`),writableType:me}}function fj(u,d,T){return Ae(u,T),O=>Y(u,d,[O])}function uj(u,d,T){return Ae(u,T),O=>G(u,d,[O])}function cj(u,d,T){return Ae(u,T),(O,J)=>Y(u,d,[O,J])}function lj(u,d,T){return Ae(u,T),O=>Y(u,d,[O])}class D0{constructor(d={},T={},O={}){d===void 0&&(d=null);let J=E0(T,"Second parameter"),re=E0(O,"Third parameter"),oe=Aj(d,"First parameter");if(oe.readableType!==void 0)throw new RangeError("Invalid readableType specified");if(oe.writableType!==void 0)throw new RangeError("Invalid writableType specified");let me=Xl(re,0),We=p0(re),Se=Xl(J,1),ot=p0(J),lt,Ot=A(Xi=>{lt=Xi});hj(this,Ot,Se,ot,me,We),gj(this,oe),oe.start!==void 0?lt(oe.start(this._transformStreamController)):lt(void 0)}get readable(){if(!yD(this))throw bD("readable");return this._readable}get writable(){if(!yD(this))throw bD("writable");return this._writable}}Object.defineProperties(D0.prototype,{readable:{enumerable:!0},writable:{enumerable:!0}}),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(D0.prototype,Symbol.toStringTag,{value:"TransformStream",configurable:!0});function hj(u,d,T,O,J,re){function oe(){return d}function me(Ot){return yj(u,Ot)}function We(Ot){return mj(u,Ot)}function Se(){return Bj(u)}u._writable=EJ(oe,me,Se,We,T,O);function ot(){return Ij(u)}function lt(Ot){return bj(u,Ot)}u._readable=th(oe,ot,lt,J,re),u._backpressure=void 0,u._backpressureChangePromise=void 0,u._backpressureChangePromise_resolve=void 0,T0(u,!0),u._transformStreamController=void 0}function yD(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_transformStreamController")?!1:u instanceof D0}function mD(u,d){zi(u._readable._readableStreamController,d),vI(u,d)}function vI(u,d){M0(u._transformStreamController),Zl(u._writable._writableStreamController,d),RI(u)}function RI(u){u._backpressure&&T0(u,!1)}function T0(u,d){u._backpressureChangePromise!==void 0&&u._backpressureChangePromise_resolve(),u._backpressureChangePromise=A(T=>{u._backpressureChangePromise_resolve=T}),u._backpressure=d}class Wa{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!N0(this))throw F0("desiredSize");let d=this._controlledTransformStream._readable._readableStreamController;return SI(d)}enqueue(d=void 0){if(!N0(this))throw F0("enqueue");BD(this,d)}error(d=void 0){if(!N0(this))throw F0("error");pj(this,d)}terminate(){if(!N0(this))throw F0("terminate");Ej(this)}}Object.defineProperties(Wa.prototype,{enqueue:{enumerable:!0},error:{enumerable:!0},terminate:{enumerable:!0},desiredSize:{enumerable:!0}}),i(Wa.prototype.enqueue,"enqueue"),i(Wa.prototype.error,"error"),i(Wa.prototype.terminate,"terminate"),typeof Symbol.toStringTag=="symbol"&&Object.defineProperty(Wa.prototype,Symbol.toStringTag,{value:"TransformStreamDefaultController",configurable:!0});function N0(u){return!r(u)||!Object.prototype.hasOwnProperty.call(u,"_controlledTransformStream")?!1:u instanceof Wa}function dj(u,d,T,O,J){d._controlledTransformStream=u,u._transformStreamController=d,d._transformAlgorithm=T,d._flushAlgorithm=O,d._cancelAlgorithm=J,d._finishPromise=void 0,d._finishPromise_resolve=void 0,d._finishPromise_reject=void 0}function gj(u,d){let T=Object.create(Wa.prototype),O,J,re;d.transform!==void 0?O=oe=>d.transform(oe,T):O=oe=>{try{return BD(T,oe),f(void 0)}catch(me){return l(me)}},d.flush!==void 0?J=()=>d.flush(T):J=()=>f(void 0),d.cancel!==void 0?re=oe=>d.cancel(oe):re=()=>f(void 0),dj(u,T,O,J,re)}function M0(u){u._transformAlgorithm=void 0,u._flushAlgorithm=void 0,u._cancelAlgorithm=void 0}function BD(u,d){let T=u._controlledTransformStream,O=T._readable._readableStreamController;if(!Uu(O))throw new TypeError("Readable side is not in a state that permits enqueue");try{xu(O,d)}catch(re){throw vI(T,re),T._readable._storedError}WJ(O)!==T._backpressure&&T0(T,!0)}function pj(u,d){mD(u._controlledTransformStream,d)}function ID(u,d){let T=u._transformAlgorithm(d);return N(T,void 0,O=>{throw mD(u._controlledTransformStream,O),O})}function Ej(u){let d=u._controlledTransformStream,T=d._readable._readableStreamController;zA(T);let O=new TypeError("TransformStream terminated");vI(d,O)}function yj(u,d){let T=u._transformStreamController;if(u._backpressure){let O=u._backpressureChangePromise;return N(O,()=>{let J=u._writable;if(J._state==="erroring")throw J._storedError;return ID(T,d)})}return ID(T,d)}function mj(u,d){let T=u._transformStreamController;if(T._finishPromise!==void 0)return T._finishPromise;let O=u._readable;T._finishPromise=A((re,oe)=>{T._finishPromise_resolve=re,T._finishPromise_reject=oe});let J=T._cancelAlgorithm(d);return M0(T),B(J,()=>(O._state==="errored"?Lu(T,O._storedError):(zi(O._readableStreamController,d),DI(T)),null),re=>(zi(O._readableStreamController,re),Lu(T,re),null)),T._finishPromise}function Bj(u){let d=u._transformStreamController;if(d._finishPromise!==void 0)return d._finishPromise;let T=u._readable;d._finishPromise=A((J,re)=>{d._finishPromise_resolve=J,d._finishPromise_reject=re});let O=d._flushAlgorithm();return M0(d),B(O,()=>(T._state==="errored"?Lu(d,T._storedError):(zA(T._readableStreamController),DI(d)),null),J=>(zi(T._readableStreamController,J),Lu(d,J),null)),d._finishPromise}function Ij(u){return T0(u,!1),u._backpressureChangePromise}function bj(u,d){let T=u._transformStreamController;if(T._finishPromise!==void 0)return T._finishPromise;let O=u._writable;T._finishPromise=A((re,oe)=>{T._finishPromise_resolve=re,T._finishPromise_reject=oe});let J=T._cancelAlgorithm(d);return M0(T),B(J,()=>(O._state==="errored"?Lu(T,O._storedError):(Zl(O._writableStreamController,d),RI(u),DI(T)),null),re=>(Zl(O._writableStreamController,re),RI(u),Lu(T,re),null)),T._finishPromise}function F0(u){return new TypeError(`TransformStreamDefaultController.prototype.${u} can only be used on a TransformStreamDefaultController`)}function DI(u){u._finishPromise_resolve!==void 0&&(u._finishPromise_resolve(),u._finishPromise_resolve=void 0,u._finishPromise_reject=void 0)}function Lu(u,d){u._finishPromise_reject!==void 0&&(P(u._finishPromise),u._finishPromise_reject(d),u._finishPromise_resolve=void 0,u._finishPromise_reject=void 0)}function bD(u){return new TypeError(`TransformStream.prototype.${u} can only be used on a TransformStream`)}e.ByteLengthQueuingStrategy=v0,e.CountQueuingStrategy=R0,e.ReadableByteStreamController=hn,e.ReadableStream=tn,e.ReadableStreamBYOBReader=Ha,e.ReadableStreamBYOBRequest=Le,e.ReadableStreamDefaultController=qo,e.ReadableStreamDefaultReader=Te,e.TransformStream=D0,e.TransformStreamDefaultController=Wa,e.WritableStream=qa,e.WritableStreamDefaultController=ku,e.WritableStreamDefaultWriter=Ho}))});var MC=x((qDe,Hk)=>{"use strict";function rA(e){"@babel/helpers - typeof";return rA=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},rA(e)}function Lk(e,t){for(var r=0;r"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function zp(e){return zp=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(r){return r.__proto__||Object.getPrototypeOf(r)},zp(e)}var Ok={},gc,TC;function Mh(e,t,r){r||(r=Error);function n(s,o,a){return typeof t=="string"?t:t(s,o,a)}var i=(function(s){Pse(a,s);var o=Ose(a);function a(A,f,l){var p;return Lse(this,a),p=o.call(this,n(A,f,l)),p.code=e,p}return kse(a)})(r);Ok[e]=i}function Pk(e,t){if(Array.isArray(e)){var r=e.length;return e=e.map(function(n){return String(n)}),r>2?"one of ".concat(t," ").concat(e.slice(0,r-1).join(", "),", or ")+e[r-1]:r===2?"one of ".concat(t," ").concat(e[0]," or ").concat(e[1]):"of ".concat(t," ").concat(e[0])}else return"of ".concat(t," ").concat(String(e))}function Yse(e,t,r){return e.substr(!r||r<0?0:+r,t.length)===t}function Wse(e,t,r){return(r===void 0||r>e.length)&&(r=e.length),e.substring(r-t.length,r)===t}function Vse(e,t,r){return typeof r!="number"&&(r=0),r+t.length>e.length?!1:e.indexOf(t,r)!==-1}Mh("ERR_AMBIGUOUS_ARGUMENT",'The "%s" argument is ambiguous. %s',TypeError);Mh("ERR_INVALID_ARG_TYPE",function(e,t,r){gc===void 0&&(gc=Wt()),gc(typeof e=="string","'name' must be a string");var n;typeof t=="string"&&Yse(t,"not ")?(n="must not be",t=t.replace(/^not /,"")):n="must be";var i;if(Wse(e," argument"))i="The ".concat(e," ").concat(n," ").concat(Pk(t,"type"));else{var s=Vse(e,".")?"property":"argument";i='The "'.concat(e,'" ').concat(s," ").concat(n," ").concat(Pk(t,"type"))}return i+=". Received type ".concat(rA(r)),i},TypeError);Mh("ERR_INVALID_ARG_VALUE",function(e,t){var r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:"is invalid";TC===void 0&&(TC=Yr());var n=TC.inspect(t);return n.length>128&&(n="".concat(n.slice(0,128),"...")),"The argument '".concat(e,"' ").concat(r,". Received ").concat(n)},TypeError,RangeError);Mh("ERR_INVALID_RETURN_VALUE",function(e,t,r){var n;return r&&r.constructor&&r.constructor.name?n="instance of ".concat(r.constructor.name):n="type ".concat(rA(r)),"Expected ".concat(e,' to be returned from the "').concat(t,'"')+" function but got ".concat(n,".")},TypeError);Mh("ERR_MISSING_ARGS",function(){for(var e=arguments.length,t=new Array(e),r=0;r0,"At least one arg needs to be specified");var n="The ",i=t.length;switch(t=t.map(function(s){return'"'.concat(s,'"')}),i){case 1:n+="".concat(t[0]," argument");break;case 2:n+="".concat(t[0]," and ").concat(t[1]," arguments");break;default:n+=t.slice(0,i-1).join(", "),n+=", and ".concat(t[i-1]," arguments");break}return"".concat(n," must be specified")},TypeError);Hk.exports.codes=Ok});var Xk=x((GDe,Kk)=>{"use strict";function qk(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),r.push.apply(r,n)}return r}function Gk(e){for(var t=1;t"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function $se(e){return Function.toString.call(e).indexOf("[native code]")!==-1}function Uh(e,t){return Uh=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(n,i){return n.__proto__=i,n},Uh(e,t)}function Lh(e){return Lh=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(r){return r.__proto__||Object.getPrototypeOf(r)},Lh(e)}function Dn(e){"@babel/helpers - typeof";return Dn=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Dn(e)}var eoe=Yr(),xC=eoe.inspect,toe=MC(),roe=toe.codes.ERR_INVALID_ARG_TYPE;function Wk(e,t,r){return(r===void 0||r>e.length)&&(r=e.length),e.substring(r-t.length,r)===t}function noe(e,t){if(t=Math.floor(t),e.length==0||t==0)return"";var r=e.length*t;for(t=Math.floor(Math.log(t)/Math.log(2));t;)e+=e,t--;return e+=e.substring(0,r-e.length),e}var rs="",Fh="",kh="",Vr="",df={deepStrictEqual:"Expected values to be strictly deep-equal:",strictEqual:"Expected values to be strictly equal:",strictEqualObject:'Expected "actual" to be reference-equal to "expected":',deepEqual:"Expected values to be loosely deep-equal:",equal:"Expected values to be loosely equal:",notDeepStrictEqual:'Expected "actual" not to be strictly deep-equal to:',notStrictEqual:'Expected "actual" to be strictly unequal to:',notStrictEqualObject:'Expected "actual" not to be reference-equal to "expected":',notDeepEqual:'Expected "actual" not to be loosely deep-equal to:',notEqual:'Expected "actual" to be loosely unequal to:',notIdentical:"Values identical but not reference-equal:"},ioe=10;function Vk(e){var t=Object.keys(e),r=Object.create(Object.getPrototypeOf(e));return t.forEach(function(n){r[n]=e[n]}),Object.defineProperty(r,"message",{value:e.message}),r}function xh(e){return xC(e,{compact:!1,customInspect:!1,depth:1e3,maxArrayLength:1/0,showHidden:!1,breakLength:1/0,showProxy:!1,sorted:!0,getters:!0})}function soe(e,t,r){var n="",i="",s=0,o="",a=!1,A=xh(e),f=A.split(` -`),l=xh(t).split(` -`),p=0,B="";if(r==="strictEqual"&&Dn(e)==="object"&&Dn(t)==="object"&&e!==null&&t!==null&&(r="strictEqualObject"),f.length===1&&l.length===1&&f[0]!==l[0]){var S=f[0].length+l[0].length;if(S<=ioe){if((Dn(e)!=="object"||e===null)&&(Dn(t)!=="object"||t===null)&&(e!==0||t!==0))return"".concat(df[r],` - -`)+"".concat(f[0]," !== ").concat(l[0],` -`)}else if(r!=="strictEqualObject"){var _=process.stderr&&process.stderr.isTTY?process.stderr.columns:80;if(S<_){for(;f[0][p]===l[0][p];)p++;p>2&&(B=` - `.concat(noe(" ",p),"^"),p=0)}}}for(var N=f[f.length-1],P=l[l.length-1];N===P&&(p++<2?o=` - `.concat(N).concat(o):n=N,f.pop(),l.pop(),!(f.length===0||l.length===0));)N=f[f.length-1],P=l[l.length-1];var U=Math.max(f.length,l.length);if(U===0){var G=A.split(` -`);if(G.length>30)for(G[26]="".concat(rs,"...").concat(Vr);G.length>27;)G.pop();return"".concat(df.notIdentical,` - -`).concat(G.join(` -`),` -`)}p>3&&(o=` -`.concat(rs,"...").concat(Vr).concat(o),a=!0),n!==""&&(o=` - `.concat(n).concat(o),n="");var Y=0,Z=df[r]+` -`.concat(Fh,"+ actual").concat(Vr," ").concat(kh,"- expected").concat(Vr),ee=" ".concat(rs,"...").concat(Vr," Lines skipped");for(p=0;p1&&p>2&&(j>4?(i+=` -`.concat(rs,"...").concat(Vr),a=!0):j>3&&(i+=` - `.concat(l[p-2]),Y++),i+=` - `.concat(l[p-1]),Y++),s=p,n+=` -`.concat(kh,"-").concat(Vr," ").concat(l[p]),Y++;else if(l.length1&&p>2&&(j>4?(i+=` -`.concat(rs,"...").concat(Vr),a=!0):j>3&&(i+=` - `.concat(f[p-2]),Y++),i+=` - `.concat(f[p-1]),Y++),s=p,i+=` -`.concat(Fh,"+").concat(Vr," ").concat(f[p]),Y++;else{var se=l[p],ie=f[p],ce=ie!==se&&(!Wk(ie,",")||ie.slice(0,-1)!==se);ce&&Wk(se,",")&&se.slice(0,-1)===ie&&(ce=!1,ie+=","),ce?(j>1&&p>2&&(j>4?(i+=` -`.concat(rs,"...").concat(Vr),a=!0):j>3&&(i+=` - `.concat(f[p-2]),Y++),i+=` - `.concat(f[p-1]),Y++),s=p,i+=` -`.concat(Fh,"+").concat(Vr," ").concat(ie),n+=` -`.concat(kh,"-").concat(Vr," ").concat(se),Y+=2):(i+=n,n="",(j===1||p===0)&&(i+=` - `.concat(ie),Y++))}if(Y>20&&p30)for(S[26]="".concat(rs,"...").concat(Vr);S.length>27;)S.pop();S.length===1?s=r.call(this,"".concat(B," ").concat(S[0])):s=r.call(this,"".concat(B,` - -`).concat(S.join(` -`),` -`))}else{var _=xh(f),N="",P=df[a];a==="notDeepEqual"||a==="notEqual"?(_="".concat(df[a],` - -`).concat(_),_.length>1024&&(_="".concat(_.slice(0,1021),"..."))):(N="".concat(xh(l)),_.length>512&&(_="".concat(_.slice(0,509),"...")),N.length>512&&(N="".concat(N.slice(0,509),"...")),a==="deepEqual"||a==="equal"?_="".concat(P,` - -`).concat(_,` - -should equal - -`):N=" ".concat(a," ").concat(N)),s=r.call(this,"".concat(_).concat(N))}return Error.stackTraceLimit=p,s.generatedMessage=!o,Object.defineProperty(FC(s),"name",{value:"AssertionError [ERR_ASSERTION]",enumerable:!1,writable:!0,configurable:!0}),s.code="ERR_ASSERTION",s.actual=f,s.expected=l,s.operator=a,Error.captureStackTrace&&Error.captureStackTrace(FC(s),A),s.stack,s.name="AssertionError",jk(s)}return zse(n,[{key:"toString",value:function(){return"".concat(this.name," [").concat(this.code,"]: ").concat(this.message)}},{key:t,value:function(s,o){return xC(this,Gk(Gk({},o),{},{customInspect:!1,depth:0}))}}]),n})(kC(Error),xC.custom);Kk.exports=ooe});var UC=x((YDe,$k)=>{"use strict";var Zk=Object.prototype.toString;$k.exports=function(t){var r=Zk.call(t),n=r==="[object Arguments]";return n||(n=r!=="[object Array]"&&t!==null&&typeof t=="object"&&typeof t.length=="number"&&t.length>=0&&Zk.call(t.callee)==="[object Function]"),n}});var A4=x((WDe,a4)=>{"use strict";var o4;Object.keys||(Ph=Object.prototype.hasOwnProperty,LC=Object.prototype.toString,e4=UC(),PC=Object.prototype.propertyIsEnumerable,t4=!PC.call({toString:null},"toString"),r4=PC.call(function(){},"prototype"),Oh=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],Xp=function(e){var t=e.constructor;return t&&t.prototype===e},n4={$applicationCache:!0,$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$onmozfullscreenchange:!0,$onmozfullscreenerror:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},i4=(function(){if(typeof window>"u")return!1;for(var e in window)try{if(!n4["$"+e]&&Ph.call(window,e)&&window[e]!==null&&typeof window[e]=="object")try{Xp(window[e])}catch{return!0}}catch{return!0}return!1})(),s4=function(e){if(typeof window>"u"||!i4)return Xp(e);try{return Xp(e)}catch{return!1}},o4=function(t){var r=t!==null&&typeof t=="object",n=LC.call(t)==="[object Function]",i=e4(t),s=r&&LC.call(t)==="[object String]",o=[];if(!r&&!n&&!i)throw new TypeError("Object.keys called on a non-object");var a=r4&&n;if(s&&t.length>0&&!Ph.call(t,0))for(var A=0;A0)for(var f=0;f{"use strict";var aoe=Array.prototype.slice,Aoe=UC(),f4=Object.keys,Zp=f4?function(t){return f4(t)}:A4(),u4=Object.keys;Zp.shim=function(){if(Object.keys){var t=(function(){var r=Object.keys(arguments);return r&&r.length===arguments.length})(1,2);t||(Object.keys=function(n){return Aoe(n)?u4(aoe.call(n)):u4(n)})}else Object.keys=Zp;return Object.keys||Zp};c4.exports=Zp});var p4=x((JDe,g4)=>{"use strict";var foe=OC(),h4=G0()(),d4=Js(),$p=Y0(),uoe=d4("Array.prototype.push"),l4=d4("Object.prototype.propertyIsEnumerable"),coe=h4?$p.getOwnPropertySymbols:null;g4.exports=function(t,r){if(t==null)throw new TypeError("target must be an object");var n=$p(t);if(arguments.length===1)return n;for(var i=1;i{"use strict";var HC=p4(),loe=function(){if(!Object.assign)return!1;for(var e="abcdefghijklmnopqrst",t=e.split(""),r={},n=0;n{"use strict";var m4=function(e){return e!==e};B4.exports=function(t,r){return t===0&&r===0?1/t===1/r:!!(t===r||m4(t)&&m4(r))}});var eE=x((KDe,I4)=>{"use strict";var doe=qC();I4.exports=function(){return typeof Object.is=="function"?Object.is:doe}});var w4=x((XDe,Q4)=>{"use strict";var b4=ec(),C4=ch(),goe=C4(b4("String.prototype.indexOf"));Q4.exports=function(t,r){var n=b4(t,!!r);return typeof n=="function"&&goe(t,".prototype.")>-1?C4(n):n}});var Hh=x((ZDe,R4)=>{"use strict";var poe=OC(),Eoe=typeof Symbol=="function"&&typeof Symbol("foo")=="symbol",yoe=Object.prototype.toString,moe=Array.prototype.concat,S4=db(),Boe=function(e){return typeof e=="function"&&yoe.call(e)==="[object Function]"},_4=pb()(),Ioe=function(e,t,r,n){if(t in e){if(n===!0){if(e[t]===r)return}else if(!Boe(n)||!n())return}_4?S4(e,t,r,!0):S4(e,t,r)},v4=function(e,t){var r=arguments.length>2?arguments[2]:{},n=poe(t);Eoe&&(n=moe.call(n,Object.getOwnPropertySymbols(t)));for(var i=0;i{"use strict";var boe=eE(),Coe=Hh();D4.exports=function(){var t=boe();return Coe(Object,{is:t},{is:function(){return Object.is!==t}}),t}});var k4=x((eTe,F4)=>{"use strict";var Qoe=Hh(),woe=ch(),Soe=qC(),N4=eE(),_oe=T4(),M4=woe(N4(),Object);Qoe(M4,{getPolyfill:N4,implementation:Soe,shim:_oe});F4.exports=M4});var GC=x((tTe,x4)=>{"use strict";x4.exports=function(t){return t!==t}});var YC=x((rTe,U4)=>{"use strict";var voe=GC();U4.exports=function(){return Number.isNaN&&Number.isNaN(NaN)&&!Number.isNaN("a")?Number.isNaN:voe}});var P4=x((nTe,L4)=>{"use strict";var Roe=Hh(),Doe=YC();L4.exports=function(){var t=Doe();return Roe(Number,{isNaN:t},{isNaN:function(){return Number.isNaN!==t}}),t}});var G4=x((iTe,q4)=>{"use strict";var Toe=ch(),Noe=Hh(),Moe=GC(),O4=YC(),Foe=P4(),H4=Toe(O4(),Number);Noe(H4,{getPolyfill:O4,implementation:Moe,shim:Foe});q4.exports=H4});var fx=x((sTe,Ax)=>{"use strict";function Y4(e,t){return Loe(e)||Uoe(e,t)||xoe(e,t)||koe()}function koe(){throw new TypeError(`Invalid attempt to destructure non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function xoe(e,t){if(e){if(typeof e=="string")return W4(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);if(r==="Object"&&e.constructor&&(r=e.constructor.name),r==="Map"||r==="Set")return Array.from(e);if(r==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return W4(e,t)}}function W4(e,t){(t==null||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r10)return!0;for(var t=0;t57)return!0}return e.length===10&&e>=Math.pow(2,32)}function nE(e){return Object.keys(e).filter(Joe).concat(sE(e).filter(Object.prototype.propertyIsEnumerable.bind(e)))}function ix(e,t){if(e===t)return 0;for(var r=e.length,n=t.length,i=0,s=Math.min(r,n);i{"use strict";function ns(e){"@babel/helpers - typeof";return ns=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},ns(e)}function ux(e,t){for(var r=0;r1?r-1:0),i=1;i1?r-1:0),i=1;i1?r-1:0),i=1;i1?r-1:0),i=1;i{"use strict";var KC=class{constructor(){this._enabled=!1,this._store=void 0}disable(){this._enabled=!1,this._store=void 0}enterWith(t){this._enabled=!0,this._store=t}exit(t,...r){let n=this._enabled,i=this._store;this._enabled=!1,this._store=void 0;try{return t(...r)}finally{this._enabled=n,this._store=i}}getStore(){return this._enabled?this._store:void 0}run(t,r,...n){let i=this._enabled,s=this._store;this._enabled=!0,this._store=t;try{return r(...n)}finally{this._enabled=i,this._store=s}}},XC=class{constructor(t="SecureExecAsyncResource"){this.type=t}bind(t,r=void 0){return typeof t!="function"?t:(...n)=>this.runInAsyncScope(t,r??this,...n)}emitDestroy(){}runInAsyncScope(t,r,...n){return t.apply(r,n)}};function mae(){return{enable(){return this},disable(){return this}}}function Bae(){return 0}function Iae(){return 0}vx.exports={AsyncLocalStorage:KC,AsyncResource:XC,createHook:mae,executionAsyncId:Bae,triggerAsyncId:Iae}});var mr=x((ATe,$x)=>{"use strict";var Rx=Symbol.for("undici.error.UND_ERR"),Zt=class extends Error{constructor(t,r){super(t,r),this.name="UndiciError",this.code="UND_ERR"}static[Symbol.hasInstance](t){return t&&t[Rx]===!0}get[Rx](){return!0}},Dx=Symbol.for("undici.error.UND_ERR_CONNECT_TIMEOUT"),ZC=class extends Zt{constructor(t){super(t),this.name="ConnectTimeoutError",this.message=t||"Connect Timeout Error",this.code="UND_ERR_CONNECT_TIMEOUT"}static[Symbol.hasInstance](t){return t&&t[Dx]===!0}get[Dx](){return!0}},Tx=Symbol.for("undici.error.UND_ERR_HEADERS_TIMEOUT"),$C=class extends Zt{constructor(t){super(t),this.name="HeadersTimeoutError",this.message=t||"Headers Timeout Error",this.code="UND_ERR_HEADERS_TIMEOUT"}static[Symbol.hasInstance](t){return t&&t[Tx]===!0}get[Tx](){return!0}},Nx=Symbol.for("undici.error.UND_ERR_HEADERS_OVERFLOW"),eQ=class extends Zt{constructor(t){super(t),this.name="HeadersOverflowError",this.message=t||"Headers Overflow Error",this.code="UND_ERR_HEADERS_OVERFLOW"}static[Symbol.hasInstance](t){return t&&t[Nx]===!0}get[Nx](){return!0}},Mx=Symbol.for("undici.error.UND_ERR_BODY_TIMEOUT"),tQ=class extends Zt{constructor(t){super(t),this.name="BodyTimeoutError",this.message=t||"Body Timeout Error",this.code="UND_ERR_BODY_TIMEOUT"}static[Symbol.hasInstance](t){return t&&t[Mx]===!0}get[Mx](){return!0}},Fx=Symbol.for("undici.error.UND_ERR_INVALID_ARG"),rQ=class extends Zt{constructor(t){super(t),this.name="InvalidArgumentError",this.message=t||"Invalid Argument Error",this.code="UND_ERR_INVALID_ARG"}static[Symbol.hasInstance](t){return t&&t[Fx]===!0}get[Fx](){return!0}},kx=Symbol.for("undici.error.UND_ERR_INVALID_RETURN_VALUE"),nQ=class extends Zt{constructor(t){super(t),this.name="InvalidReturnValueError",this.message=t||"Invalid Return Value Error",this.code="UND_ERR_INVALID_RETURN_VALUE"}static[Symbol.hasInstance](t){return t&&t[kx]===!0}get[kx](){return!0}},xx=Symbol.for("undici.error.UND_ERR_ABORT"),hE=class extends Zt{constructor(t){super(t),this.name="AbortError",this.message=t||"The operation was aborted",this.code="UND_ERR_ABORT"}static[Symbol.hasInstance](t){return t&&t[xx]===!0}get[xx](){return!0}},Ux=Symbol.for("undici.error.UND_ERR_ABORTED"),iQ=class extends hE{constructor(t){super(t),this.name="AbortError",this.message=t||"Request aborted",this.code="UND_ERR_ABORTED"}static[Symbol.hasInstance](t){return t&&t[Ux]===!0}get[Ux](){return!0}},Lx=Symbol.for("undici.error.UND_ERR_INFO"),sQ=class extends Zt{constructor(t){super(t),this.name="InformationalError",this.message=t||"Request information",this.code="UND_ERR_INFO"}static[Symbol.hasInstance](t){return t&&t[Lx]===!0}get[Lx](){return!0}},Px=Symbol.for("undici.error.UND_ERR_REQ_CONTENT_LENGTH_MISMATCH"),oQ=class extends Zt{constructor(t){super(t),this.name="RequestContentLengthMismatchError",this.message=t||"Request body length does not match content-length header",this.code="UND_ERR_REQ_CONTENT_LENGTH_MISMATCH"}static[Symbol.hasInstance](t){return t&&t[Px]===!0}get[Px](){return!0}},Ox=Symbol.for("undici.error.UND_ERR_RES_CONTENT_LENGTH_MISMATCH"),aQ=class extends Zt{constructor(t){super(t),this.name="ResponseContentLengthMismatchError",this.message=t||"Response body length does not match content-length header",this.code="UND_ERR_RES_CONTENT_LENGTH_MISMATCH"}static[Symbol.hasInstance](t){return t&&t[Ox]===!0}get[Ox](){return!0}},Hx=Symbol.for("undici.error.UND_ERR_DESTROYED"),AQ=class extends Zt{constructor(t){super(t),this.name="ClientDestroyedError",this.message=t||"The client is destroyed",this.code="UND_ERR_DESTROYED"}static[Symbol.hasInstance](t){return t&&t[Hx]===!0}get[Hx](){return!0}},qx=Symbol.for("undici.error.UND_ERR_CLOSED"),fQ=class extends Zt{constructor(t){super(t),this.name="ClientClosedError",this.message=t||"The client is closed",this.code="UND_ERR_CLOSED"}static[Symbol.hasInstance](t){return t&&t[qx]===!0}get[qx](){return!0}},Gx=Symbol.for("undici.error.UND_ERR_SOCKET"),uQ=class extends Zt{constructor(t,r){super(t),this.name="SocketError",this.message=t||"Socket error",this.code="UND_ERR_SOCKET",this.socket=r}static[Symbol.hasInstance](t){return t&&t[Gx]===!0}get[Gx](){return!0}},Yx=Symbol.for("undici.error.UND_ERR_NOT_SUPPORTED"),cQ=class extends Zt{constructor(t){super(t),this.name="NotSupportedError",this.message=t||"Not supported error",this.code="UND_ERR_NOT_SUPPORTED"}static[Symbol.hasInstance](t){return t&&t[Yx]===!0}get[Yx](){return!0}},Wx=Symbol.for("undici.error.UND_ERR_BPL_MISSING_UPSTREAM"),lQ=class extends Zt{constructor(t){super(t),this.name="MissingUpstreamError",this.message=t||"No upstream has been added to the BalancedPool",this.code="UND_ERR_BPL_MISSING_UPSTREAM"}static[Symbol.hasInstance](t){return t&&t[Wx]===!0}get[Wx](){return!0}},Vx=Symbol.for("undici.error.UND_ERR_HTTP_PARSER"),hQ=class extends Error{constructor(t,r,n){super(t),this.name="HTTPParserError",this.code=r?`HPE_${r}`:void 0,this.data=n?n.toString():void 0}static[Symbol.hasInstance](t){return t&&t[Vx]===!0}get[Vx](){return!0}},Jx=Symbol.for("undici.error.UND_ERR_RES_EXCEEDED_MAX_SIZE"),dQ=class extends Zt{constructor(t){super(t),this.name="ResponseExceededMaxSizeError",this.message=t||"Response content exceeded max size",this.code="UND_ERR_RES_EXCEEDED_MAX_SIZE"}static[Symbol.hasInstance](t){return t&&t[Jx]===!0}get[Jx](){return!0}},jx=Symbol.for("undici.error.UND_ERR_REQ_RETRY"),gQ=class extends Zt{constructor(t,r,{headers:n,data:i}){super(t),this.name="RequestRetryError",this.message=t||"Request retry error",this.code="UND_ERR_REQ_RETRY",this.statusCode=r,this.data=i,this.headers=n}static[Symbol.hasInstance](t){return t&&t[jx]===!0}get[jx](){return!0}},zx=Symbol.for("undici.error.UND_ERR_RESPONSE"),pQ=class extends Zt{constructor(t,r,{headers:n,body:i}){super(t),this.name="ResponseError",this.message=t||"Response error",this.code="UND_ERR_RESPONSE",this.statusCode=r,this.body=i,this.headers=n}static[Symbol.hasInstance](t){return t&&t[zx]===!0}get[zx](){return!0}},Kx=Symbol.for("undici.error.UND_ERR_PRX_TLS"),EQ=class extends Zt{constructor(t,r,n={}){super(r,{cause:t,...n}),this.name="SecureProxyConnectionError",this.message=r||"Secure Proxy Connection failed",this.code="UND_ERR_PRX_TLS",this.cause=t}static[Symbol.hasInstance](t){return t&&t[Kx]===!0}get[Kx](){return!0}},Xx=Symbol.for("undici.error.UND_ERR_MAX_ORIGINS_REACHED"),yQ=class extends Zt{constructor(t){super(t),this.name="MaxOriginsReachedError",this.message=t||"Maximum allowed origins reached",this.code="UND_ERR_MAX_ORIGINS_REACHED"}static[Symbol.hasInstance](t){return t&&t[Xx]===!0}get[Xx](){return!0}},mQ=class extends Zt{constructor(t,r){super(t),this.name="Socks5ProxyError",this.message=t||"SOCKS5 proxy error",this.code=r||"UND_ERR_SOCKS5"}},Zx=Symbol.for("undici.error.UND_ERR_WS_MESSAGE_SIZE_EXCEEDED"),BQ=class extends Zt{constructor(t){super(t),this.name="MessageSizeExceededError",this.message=t||"Max decompressed message size exceeded",this.code="UND_ERR_WS_MESSAGE_SIZE_EXCEEDED"}static[Symbol.hasInstance](t){return t&&t[Zx]===!0}get[Zx](){return!0}};$x.exports={AbortError:hE,HTTPParserError:hQ,UndiciError:Zt,HeadersTimeoutError:$C,HeadersOverflowError:eQ,BodyTimeoutError:tQ,RequestContentLengthMismatchError:oQ,ConnectTimeoutError:ZC,InvalidArgumentError:rQ,InvalidReturnValueError:nQ,RequestAbortedError:iQ,ClientDestroyedError:AQ,ClientClosedError:fQ,InformationalError:sQ,SocketError:uQ,NotSupportedError:cQ,ResponseContentLengthMismatchError:aQ,BalancedPoolMissingUpstreamError:lQ,ResponseExceededMaxSizeError:dQ,RequestRetryError:gQ,ResponseError:pQ,SecureProxyConnectionError:EQ,MaxOriginsReachedError:yQ,Socks5ProxyError:mQ,MessageSizeExceededError:BQ}});var Tn=x((fTe,eU)=>{"use strict";eU.exports={kClose:Symbol("close"),kDestroy:Symbol("destroy"),kDispatch:Symbol("dispatch"),kUrl:Symbol("url"),kWriting:Symbol("writing"),kResuming:Symbol("resuming"),kQueue:Symbol("queue"),kConnect:Symbol("connect"),kConnecting:Symbol("connecting"),kKeepAliveDefaultTimeout:Symbol("default keep alive timeout"),kKeepAliveMaxTimeout:Symbol("max keep alive timeout"),kKeepAliveTimeoutThreshold:Symbol("keep alive timeout threshold"),kKeepAliveTimeoutValue:Symbol("keep alive timeout"),kKeepAlive:Symbol("keep alive"),kHeadersTimeout:Symbol("headers timeout"),kBodyTimeout:Symbol("body timeout"),kServerName:Symbol("server name"),kLocalAddress:Symbol("local address"),kHost:Symbol("host"),kNoRef:Symbol("no ref"),kBodyUsed:Symbol("used"),kBody:Symbol("abstracted request body"),kRunning:Symbol("running"),kBlocking:Symbol("blocking"),kPending:Symbol("pending"),kSize:Symbol("size"),kBusy:Symbol("busy"),kQueued:Symbol("queued"),kFree:Symbol("free"),kConnected:Symbol("connected"),kClosed:Symbol("closed"),kNeedDrain:Symbol("need drain"),kReset:Symbol("reset"),kDestroyed:Symbol.for("nodejs.stream.destroyed"),kResume:Symbol("resume"),kOnError:Symbol("on error"),kMaxHeadersSize:Symbol("max headers size"),kRunningIdx:Symbol("running index"),kPendingIdx:Symbol("pending index"),kError:Symbol("error"),kClients:Symbol("clients"),kClient:Symbol("client"),kParser:Symbol("parser"),kOnDestroyed:Symbol("destroy callbacks"),kPipelining:Symbol("pipelining"),kSocket:Symbol("socket"),kHostHeader:Symbol("host header"),kConnector:Symbol("connector"),kStrictContentLength:Symbol("strict content length"),kMaxRedirections:Symbol("maxRedirections"),kMaxRequests:Symbol("maxRequestsPerClient"),kProxy:Symbol("proxy agent options"),kCounter:Symbol("socket request counter"),kMaxResponseSize:Symbol("max response size"),kHTTP2Session:Symbol("http2Session"),kHTTP2SessionState:Symbol("http2Session state"),kRetryHandlerDefaultRetry:Symbol("retry agent default retry"),kConstruct:Symbol("constructable"),kListeners:Symbol("listeners"),kHTTPContext:Symbol("http context"),kMaxConcurrentStreams:Symbol("max concurrent streams"),kHTTP2InitialWindowSize:Symbol("http2 initial window size"),kHTTP2ConnectionWindowSize:Symbol("http2 connection window size"),kEnableConnectProtocol:Symbol("http2session connect protocol"),kRemoteSettings:Symbol("http2session remote settings"),kHTTP2Stream:Symbol("http2session client stream"),kPingInterval:Symbol("ping interval"),kNoProxyAgent:Symbol("no proxy agent"),kHttpProxyAgent:Symbol("http proxy agent"),kHttpsProxyAgent:Symbol("https proxy agent"),kSocks5ProxyAgent:Symbol("socks5 proxy agent")}});var gE=x((uTe,tU)=>{"use strict";function gf(){if(!globalThis._httpModule)throw new Error("node:http bridge module is not available");return globalThis._httpModule}var dE=class{},IQ=class{},bQ=class{},CQ=class{},QQ=class{},bae=["CHECKOUT","CONNECT","COPY","DELETE","GET","HEAD","LOCK","M-SEARCH","MERGE","MKACTIVITY","MKCOL","MOVE","NOTIFY","OPTIONS","PATCH","POST","PROPFIND","PROPPATCH","PURGE","PUT","REPORT","SEARCH","SUBSCRIBE","TRACE","UNLOCK","UNSUBSCRIBE"];tU.exports={Agent:dE,ClientRequest:IQ,IncomingMessage:bQ,METHODS:bae,STATUS_CODES:{},Server:CQ,ServerResponse:QQ,_checkInvalidHeaderChar(e){return gf()._checkInvalidHeaderChar(e)},_checkIsHttpToken(e){return gf()._checkIsHttpToken(e)},createServer(...e){return gf().createServer(...e)},get(...e){return gf().get(...e)},globalAgent:new dE,maxHeaderSize:65535,request(...e){return gf().request(...e)},validateHeaderName(e,t){return gf().validateHeaderName(e,t)},validateHeaderValue(e,t){return gf().validateHeaderValue(e,t)}}});var pE=x((cTe,nU)=>{"use strict";function Cae(){let e=globalThis._netModule;if(!e)throw new Error("node:net bridge module is not available");return e}var rU={};for(let e of["BlockList","Socket","SocketAddress","Server","Stream","connect","createConnection","createServer","getDefaultAutoSelectFamily","getDefaultAutoSelectFamilyAttemptTimeout","isIP","isIPv4","isIPv6","setDefaultAutoSelectFamily","setDefaultAutoSelectFamilyAttemptTimeout"])Object.defineProperty(rU,e,{enumerable:!0,get(){return Cae()[e]}});nU.exports=rU});var TQ=x((lTe,AU)=>{"use strict";var yc=0,wQ=1e3,SQ=(wQ>>1)-1,oA,_Q=Symbol("kFastTimer"),jo=[],vQ=-2,RQ=-1,oU=0,iU=1;function DQ(){yc+=SQ;let e=0,t=jo.length;for(;e=r._idleStart+r._idleTimeout&&(r._state=RQ,r._idleStart=-1,r._onTimeout(r._timerArg)),r._state===RQ?(r._state=vQ,--t!==0&&(jo[e]=jo[t])):++e}jo.length=t,jo.length!==0&&aU()}function aU(){oA?.refresh?oA.refresh():(clearTimeout(oA),oA=setTimeout(DQ,SQ),oA?.unref())}var sU;sU=_Q;var EE=class{constructor(t,r,n){y(this,sU,!0);y(this,"_state",vQ);y(this,"_idleTimeout",-1);y(this,"_idleStart",-1);y(this,"_onTimeout");y(this,"_timerArg");this._onTimeout=t,this._idleTimeout=r,this._timerArg=n,this.refresh()}refresh(){this._state===vQ&&jo.push(this),(!oA||jo.length===1)&&aU(),this._state=oU}clear(){this._state=RQ,this._idleStart=-1}};AU.exports={setTimeout(e,t,r){return t<=wQ?setTimeout(e,t,r):new EE(e,t,r)},clearTimeout(e){e[_Q]?e.clear():clearTimeout(e)},setFastTimeout(e,t,r){return new EE(e,t,r)},clearFastTimeout(e){e.clear()},now(){return yc},tick(e=0){yc+=e-wQ+1,DQ(),DQ()},reset(){yc=0,jo.length=0,clearTimeout(oA),oA=null},kFastTimer:_Q}});var mE=x((dTe,uU)=>{"use strict";var NQ=["Accept","Accept-Encoding","Accept-Language","Accept-Ranges","Access-Control-Allow-Credentials","Access-Control-Allow-Headers","Access-Control-Allow-Methods","Access-Control-Allow-Origin","Access-Control-Expose-Headers","Access-Control-Max-Age","Access-Control-Request-Headers","Access-Control-Request-Method","Age","Allow","Alt-Svc","Alt-Used","Authorization","Cache-Control","Clear-Site-Data","Connection","Content-Disposition","Content-Encoding","Content-Language","Content-Length","Content-Location","Content-Range","Content-Security-Policy","Content-Security-Policy-Report-Only","Content-Type","Cookie","Cross-Origin-Embedder-Policy","Cross-Origin-Opener-Policy","Cross-Origin-Resource-Policy","Date","Device-Memory","Downlink","ECT","ETag","Expect","Expect-CT","Expires","Forwarded","From","Host","If-Match","If-Modified-Since","If-None-Match","If-Range","If-Unmodified-Since","Keep-Alive","Last-Modified","Link","Location","Max-Forwards","Origin","Permissions-Policy","Pragma","Proxy-Authenticate","Proxy-Authorization","RTT","Range","Referer","Referrer-Policy","Refresh","Retry-After","Sec-WebSocket-Accept","Sec-WebSocket-Extensions","Sec-WebSocket-Key","Sec-WebSocket-Protocol","Sec-WebSocket-Version","Server","Server-Timing","Service-Worker-Allowed","Service-Worker-Navigation-Preload","Set-Cookie","SourceMap","Strict-Transport-Security","Supports-Loading-Mode","TE","Timing-Allow-Origin","Trailer","Transfer-Encoding","Upgrade","Upgrade-Insecure-Requests","User-Agent","Vary","Via","WWW-Authenticate","X-Content-Type-Options","X-DNS-Prefetch-Control","X-Frame-Options","X-Permitted-Cross-Domain-Policies","X-Powered-By","X-Requested-With","X-XSS-Protection"],yE={};Object.setPrototypeOf(yE,null);var fU={};Object.setPrototypeOf(fU,null);function Qae(e){let t=fU[e];return t===void 0&&(t=Buffer.from(e)),t}for(let e=0;e{"use strict";var{wellknownHeaderNames:cU,headerNameLowerCasedRecord:wae}=mE(),MQ=class e{constructor(t,r,n){y(this,"value",null);y(this,"left",null);y(this,"middle",null);y(this,"right",null);y(this,"code");if(n===void 0||n>=t.length)throw new TypeError("Unreachable");if((this.code=t.charCodeAt(n))>127)throw new TypeError("key must be ascii string");t.length!==++n?this.middle=new e(t,r,n):this.value=r}add(t,r){let n=t.length;if(n===0)throw new TypeError("Unreachable");let i=0,s=this;for(;;){let o=t.charCodeAt(i);if(o>127)throw new TypeError("key must be ascii string");if(s.code===o)if(n===++i){s.value=r;break}else if(s.middle!==null)s=s.middle;else{s.middle=new e(t,r,i);break}else if(s.code=65&&(s|=32);i!==null;){if(s===i.code){if(r===++n)return i;i=i.middle;break}i=i.code{"use strict";var Vh=Wt(),{kDestroyed:yU,kBodyUsed:mc,kListeners:Bc,kBody:gU}=Tn(),{IncomingMessage:Sae}=gE(),mU=(ts(),Gs(Yt)),_ae=pE(),{stringify:vae}=(jI(),Gs(q0)),{EventEmitter:Rae}=Zi(),IE=TQ(),{InvalidArgumentError:Nr,ConnectTimeoutError:Dae}=mr(),{headerNameLowerCasedRecord:Tae}=mE(),{tree:BU}=dU(),[Nae,Mae]=process.versions.node.split(".",2).map(e=>Number(e)),CE=class{constructor(t){this[gU]=t,this[mc]=!1}async*[Symbol.asyncIterator](){Vh(!this[mc],"disturbed"),this[mc]=!0,yield*this[gU]}};function pU(){}function Fae(e){return QE(e)?(SU(e)===0&&e.on("data",function(){Vh(!1)}),typeof e.readableDidRead!="boolean"&&(e[mc]=!1,Rae.prototype.on.call(e,"data",function(){this[mc]=!0})),e):e&&typeof e.pipeTo=="function"?new CE(e):e&&TU(e)?e:e&&typeof e!="string"&&!ArrayBuffer.isView(e)&&wU(e)?new CE(e):e}function QE(e){return e&&typeof e=="object"&&typeof e.pipe=="function"&&typeof e.on=="function"}function IU(e){if(e===null)return!1;if(e instanceof Blob)return!0;if(typeof e!="object")return!1;{let t=e[Symbol.toStringTag];return(t==="Blob"||t==="File")&&("stream"in e&&typeof e.stream=="function"||"arrayBuffer"in e&&typeof e.arrayBuffer=="function")}}function bU(e){return e.includes("?")||e.includes("#")}function kae(e,t){if(bU(e))throw new Error('Query params cannot be passed when url already contains "?" or "#".');let r=vae(t);return r&&(e+="?"+r),e}function CU(e){let t=parseInt(e,10);return t===Number(e)&&t>=0&&t<=65535}function bE(e){return e!=null&&e[0]==="h"&&e[1]==="t"&&e[2]==="t"&&e[3]==="p"&&(e[4]===":"||e[4]==="s"&&e[5]===":")}function QU(e){if(typeof e=="string"){if(e=new URL(e),!bE(e.origin||e.protocol))throw new Nr("Invalid URL protocol: the URL must start with `http:` or `https:`.");return e}if(!e||typeof e!="object")throw new Nr("Invalid URL: The URL argument must be a non-null object.");if(!(e instanceof URL)){if(e.port!=null&&e.port!==""&&CU(e.port)===!1)throw new Nr("Invalid URL: port must be a valid integer or a string representation of an integer.");if(e.path!=null&&typeof e.path!="string")throw new Nr("Invalid URL path: the path must be a string or null/undefined.");if(e.pathname!=null&&typeof e.pathname!="string")throw new Nr("Invalid URL pathname: the pathname must be a string or null/undefined.");if(e.hostname!=null&&typeof e.hostname!="string")throw new Nr("Invalid URL hostname: the hostname must be a string or null/undefined.");if(e.origin!=null&&typeof e.origin!="string")throw new Nr("Invalid URL origin: the origin must be a string or null/undefined.");if(!bE(e.origin||e.protocol))throw new Nr("Invalid URL protocol: the URL must start with `http:` or `https:`.");let t=e.port!=null?e.port:e.protocol==="https:"?443:80,r=e.origin!=null?e.origin:`${e.protocol||""}//${e.hostname||""}:${t}`,n=e.path!=null?e.path:`${e.pathname||""}${e.search||""}`;return r[r.length-1]==="/"&&(r=r.slice(0,r.length-1)),n&&n[0]!=="/"&&(n=`/${n}`),new URL(`${r}${n}`)}if(!bE(e.origin||e.protocol))throw new Nr("Invalid URL protocol: the URL must start with `http:` or `https:`.");return e}function xae(e){if(e=QU(e),e.pathname!=="/"||e.search||e.hash)throw new Nr("invalid url");return e}function Uae(e){if(e[0]==="["){let r=e.indexOf("]");return Vh(r!==-1),e.substring(1,r)}let t=e.indexOf(":");return t===-1?e:e.substring(0,t)}function Lae(e){if(!e)return null;Vh(typeof e=="string");let t=Uae(e);return _ae.isIP(t)?"":t}function Pae(e){return JSON.parse(JSON.stringify(e))}function Oae(e){return e!=null&&typeof e[Symbol.asyncIterator]=="function"}function wU(e){return e!=null&&(typeof e[Symbol.iterator]=="function"||typeof e[Symbol.asyncIterator]=="function")}function Hae(e){let t=Object.getPrototypeOf(e);return Object.prototype.hasOwnProperty.call(e,Symbol.iterator)||t!=null&&t!==Object.prototype&&typeof e[Symbol.iterator]=="function"}function SU(e){if(e==null)return 0;if(QE(e)){let t=e._readableState;return t&&t.objectMode===!1&&t.ended===!0&&Number.isFinite(t.length)?t.length:null}else{if(IU(e))return e.size!=null?e.size:null;if(DU(e))return e.byteLength}return null}function _U(e){return e&&!!(e.destroyed||e[yU]||mU.isDestroyed?.(e))}function vU(e,t){e==null||!QE(e)||_U(e)||(typeof e.destroy=="function"?(Object.getPrototypeOf(e).constructor===Sae&&(e.socket=null),e.destroy(t)):t&&queueMicrotask(()=>{e.emit("error",t)}),e.destroyed!==!0&&(e[yU]=!0))}var qae=/timeout=(\d+)/;function Gae(e){let t=e.match(qae);return t?parseInt(t[1],10)*1e3:null}function RU(e){return typeof e=="string"?Tae[e]??e.toLowerCase():BU.lookup(e)??e.toString("latin1").toLowerCase()}function Yae(e){return BU.lookup(e)??e.toString("latin1").toLowerCase()}function Wae(e,t){t===void 0&&(t={});for(let r=0;ro.toString("latin1")):e[r+1].toString("latin1");n==="__proto__"?Object.defineProperty(t,n,{value:s,enumerable:!0,configurable:!0,writable:!0}):t[n]=s}else{let s=typeof e[r+1]=="string"?e[r+1]:Array.isArray(e[r+1])?e[r+1].map(o=>o.toString("latin1")):e[r+1].toString("latin1");t[n]=s}}return t}function Vae(e){let t=e.length,r=new Array(t),n,i;for(let s=0;sBuffer.from(t))}function DU(e){return e instanceof Uint8Array||Buffer.isBuffer(e)}function jae(e,t,r){if(!e||typeof e!="object")throw new Nr("handler must be an object");if(typeof e.onRequestStart!="function"){if(typeof e.onConnect!="function")throw new Nr("invalid onConnect method");if(typeof e.onError!="function")throw new Nr("invalid onError method");if(typeof e.onBodySent!="function"&&e.onBodySent!==void 0)throw new Nr("invalid onBodySent method");if(r||t==="CONNECT"){if(typeof e.onUpgrade!="function")throw new Nr("invalid onUpgrade method")}else{if(typeof e.onHeaders!="function")throw new Nr("invalid onHeaders method");if(typeof e.onData!="function")throw new Nr("invalid onData method");if(typeof e.onComplete!="function")throw new Nr("invalid onComplete method")}}}function zae(e){return!!(e&&(mU.isDisturbed(e)||e[mc]))}function Kae(e){return{localAddress:e.localAddress,localPort:e.localPort,remoteAddress:e.remoteAddress,remotePort:e.remotePort,remoteFamily:e.remoteFamily,timeout:e.timeout,bytesWritten:e.bytesWritten,bytesRead:e.bytesRead}}function Xae(e){let t;return new ReadableStream({start(){t=e[Symbol.asyncIterator]()},pull(r){return t.next().then(({done:n,value:i})=>{if(n)return queueMicrotask(()=>{r.close(),r.byobRequest?.respond(0)});{let s=Buffer.isBuffer(i)?i:Buffer.from(i);return s.byteLength?r.enqueue(new Uint8Array(s)):this.pull(r)}})},cancel(){return t.return()},type:"bytes"})}function TU(e){return e&&typeof e=="object"&&typeof e.append=="function"&&typeof e.delete=="function"&&typeof e.get=="function"&&typeof e.getAll=="function"&&typeof e.has=="function"&&typeof e.set=="function"&&e[Symbol.toStringTag]==="FormData"}function Zae(e,t){return"addEventListener"in e?(e.addEventListener("abort",t,{once:!0}),()=>e.removeEventListener("abort",t)):(e.once("abort",t),()=>e.removeListener("abort",t))}var NU=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);function $ae(e){return NU[e]===1}var eAe=/^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;function tAe(e){if(e.length>=12)return eAe.test(e);if(e.length===0)return!1;for(let t=0;t{if(!t.timeout)return pU;let r=null,n=null,i=IE.setFastTimeout(()=>{r=setImmediate(()=>{n=setImmediate(()=>EU(e.deref(),t))})},t.timeout);return()=>{IE.clearFastTimeout(i),clearImmediate(r),clearImmediate(n)}}:(e,t)=>{if(!t.timeout)return pU;let r=null,n=IE.setFastTimeout(()=>{r=setImmediate(()=>{EU(e.deref(),t)})},t.timeout);return()=>{IE.clearFastTimeout(n),clearImmediate(r)}};function EU(e,t){if(e==null)return;let r="Connect Timeout Error";Array.isArray(e.autoSelectFamilyAttemptedAddresses)?r+=` (attempted addresses: ${e.autoSelectFamilyAttemptedAddresses.join(", ")},`:r+=` (attempted address: ${t.hostname}:${t.port},`,r+=` timeout: ${t.timeout}ms)`,vU(e,new Dae(r))}function uAe(e){if(e[0]==="h"&&e[1]==="t"&&e[2]==="t"&&e[3]==="p")switch(e[4]){case":":return"http:";case"s":if(e[5]===":")return"https:"}return e.slice(0,e.indexOf(":")+1)}var MU=Object.create(null);MU.enumerable=!0;var FQ={delete:"DELETE",DELETE:"DELETE",get:"GET",GET:"GET",head:"HEAD",HEAD:"HEAD",options:"OPTIONS",OPTIONS:"OPTIONS",post:"POST",POST:"POST",put:"PUT",PUT:"PUT"},FU={...FQ,patch:"patch",PATCH:"PATCH"};Object.setPrototypeOf(FQ,null);Object.setPrototypeOf(FU,null);kU.exports={kEnumerableProperty:MU,isDisturbed:zae,isBlobLike:IU,parseOrigin:xae,parseURL:QU,getServerName:Lae,isStream:QE,isIterable:wU,hasSafeIterator:Hae,isAsyncIterable:Oae,isDestroyed:_U,headerNameToString:RU,bufferToLowerCasedHeaderName:Yae,addListener:oAe,removeAllListeners:aAe,errorRequest:AAe,parseRawHeaders:Vae,encodeRawHeaders:Jae,parseHeaders:Wae,parseKeepAliveTimeout:Gae,destroy:vU,bodyLength:SU,deepClone:Pae,ReadableStreamFrom:Xae,isBuffer:DU,assertRequestHandler:jae,getSocketInfo:Kae,isFormDataLike:TU,pathHasQueryOrFragment:bU,serializePathWithQuery:kae,addAbortListener:Zae,isValidHTTPToken:tAe,isValidHeaderValue:nAe,isTokenCharCode:$ae,parseRangeHeader:sAe,normalizedMethodRecordsBase:FQ,normalizedMethodRecords:FU,isValidPort:CU,isHttpOrHttpsPrefixed:bE,nodeMajor:Nae,nodeMinor:Mae,safeHTTPMethods:Object.freeze(["GET","HEAD","OPTIONS","TRACE"]),wrapRequestBody:Fae,setupConnectTimeout:fAe,getProtocolFromUrlString:uAe}});var YU=x((yTe,GU)=>{"use strict";var PU=Wt(),{Readable:cAe}=(ts(),Gs(Yt)),{RequestAbortedError:OU,NotSupportedError:lAe,InvalidArgumentError:hAe,AbortError:wE}=mr(),HU=$t(),{ReadableStreamFrom:dAe}=$t(),Vn=Symbol("kConsume"),SE=Symbol("kReading"),pf=Symbol("kBody"),xU=Symbol("kAbort"),qU=Symbol("kContentType"),kQ=Symbol("kContentLength"),xQ=Symbol("kUsed"),_E=Symbol("kBytesRead"),gAe=()=>{},UQ=class extends cAe{constructor({resume:t,abort:r,contentType:n="",contentLength:i,highWaterMark:s=64*1024}){super({autoDestroy:!0,read:t,highWaterMark:s}),this._readableState.dataEmitted=!1,this[xU]=r,this[Vn]=null,this[_E]=0,this[pf]=null,this[xQ]=!1,this[qU]=n,this[kQ]=Number.isFinite(i)?i:null,this[SE]=!1}_destroy(t,r){!t&&!this._readableState.endEmitted&&(t=new OU),t&&this[xU](),this[xQ]?r(t):setImmediate(r,t)}on(t,r){return(t==="data"||t==="readable")&&(this[SE]=!0,this[xQ]=!0),super.on(t,r)}addListener(t,r){return this.on(t,r)}off(t,r){let n=super.off(t,r);return(t==="data"||t==="readable")&&(this[SE]=this.listenerCount("data")>0||this.listenerCount("readable")>0),n}removeListener(t,r){return this.off(t,r)}push(t){return t&&(this[_E]+=t.length,this[Vn])?(PQ(this[Vn],t),this[SE]?super.push(t):!0):super.push(t)}text(){return Jh(this,"text")}json(){return Jh(this,"json")}blob(){return Jh(this,"blob")}bytes(){return Jh(this,"bytes")}arrayBuffer(){return Jh(this,"arrayBuffer")}async formData(){throw new lAe}get bodyUsed(){return HU.isDisturbed(this)}get body(){return this[pf]||(this[pf]=dAe(this),this[Vn]&&(this[pf].getReader(),PU(this[pf].locked))),this[pf]}dump(t){let r=t?.signal;if(r!=null&&(typeof r!="object"||!("aborted"in r)))return Promise.reject(new hAe("signal must be an AbortSignal"));let n=t?.limit&&Number.isFinite(t.limit)?t.limit:128*1024;return r?.aborted?Promise.reject(r.reason??new wE):this._readableState.closeEmitted?Promise.resolve(null):new Promise((i,s)=>{if((this[kQ]&&this[kQ]>n||this[_E]>n)&&this.destroy(new wE),r){let o=()=>{this.destroy(r.reason??new wE)};r.addEventListener("abort",o),this.on("close",function(){r.removeEventListener("abort",o),r.aborted?s(r.reason??new wE):i(null)})}else this.on("close",i);this.on("error",gAe).on("data",()=>{this[_E]>n&&this.destroy()}).resume()})}setEncoding(t){return Buffer.isEncoding(t)&&(this._readableState.encoding=t),this}};function pAe(e){return e[pf]?.locked===!0||e[Vn]!==null}function EAe(e){return HU.isDisturbed(e)||pAe(e)}function Jh(e,t){return PU(!e[Vn]),new Promise((r,n)=>{if(EAe(e)){let i=e._readableState;i.destroyed&&i.closeEmitted===!1?e.on("error",n).on("close",()=>{n(new TypeError("unusable"))}):n(i.errored??new TypeError("unusable"))}else queueMicrotask(()=>{e[Vn]={type:t,stream:e,resolve:r,reject:n,length:0,body:[]},e.on("error",function(i){OQ(this[Vn],i)}).on("close",function(){this[Vn].body!==null&&OQ(this[Vn],new OU)}),yAe(e[Vn])})})}function yAe(e){if(e.body===null)return;let{_readableState:t}=e.stream;if(t.bufferIndex){let r=t.bufferIndex,n=t.buffer.length;for(let i=r;i2&&n[0]===239&&n[1]===187&&n[2]===191?3:0;return!r||r==="utf8"||r==="utf-8"?n.utf8Slice(s,i):n.subarray(s,i).toString(r)}function UU(e,t){if(e.length===0||t===0)return new Uint8Array(0);if(e.length===1)return new Uint8Array(e[0]);let r=new Uint8Array(Buffer.allocUnsafeSlow(t).buffer),n=0;for(let i=0;i{"use strict";var mAe=Wt(),{AsyncResource:BAe}=Ec(),{Readable:IAe}=YU(),{InvalidArgumentError:Ic,RequestAbortedError:WU}=mr(),yi=$t();function jh(){}var vE=class extends BAe{constructor(t,r){if(!t||typeof t!="object")throw new Ic("invalid opts");let{signal:n,method:i,opaque:s,body:o,onInfo:a,responseHeaders:A,highWaterMark:f}=t;try{if(typeof r!="function")throw new Ic("invalid callback");if(f&&(typeof f!="number"||f<0))throw new Ic("invalid highWaterMark");if(n&&typeof n.on!="function"&&typeof n.addEventListener!="function")throw new Ic("signal must be an EventEmitter or EventTarget");if(i==="CONNECT")throw new Ic("invalid method");if(a&&typeof a!="function")throw new Ic("invalid onInfo callback");super("UNDICI_REQUEST")}catch(l){throw yi.isStream(o)&&yi.destroy(o.on("error",jh),l),l}this.method=i,this.responseHeaders=A||null,this.opaque=s||null,this.callback=r,this.res=null,this.abort=null,this.body=o,this.trailers={},this.context=null,this.onInfo=a||null,this.highWaterMark=f,this.reason=null,this.removeAbortListener=null,n?.aborted?this.reason=n.reason??new WU:n&&(this.removeAbortListener=yi.addAbortListener(n,()=>{this.reason=n.reason??new WU,this.res?yi.destroy(this.res.on("error",jh),this.reason):this.abort&&this.abort(this.reason)}))}onConnect(t,r){if(this.reason){t(this.reason);return}mAe(this.callback),this.abort=t,this.context=r}onHeaders(t,r,n,i){let{callback:s,opaque:o,abort:a,context:A,responseHeaders:f,highWaterMark:l}=this,p=f==="raw"?yi.parseRawHeaders(r):yi.parseHeaders(r);if(t<200){this.onInfo&&this.onInfo({statusCode:t,headers:p});return}let B=f==="raw"?yi.parseHeaders(r):p,S=B["content-type"],_=B["content-length"],N=new IAe({resume:n,abort:a,contentType:S,contentLength:this.method!=="HEAD"&&_?Number(_):null,highWaterMark:l});if(this.removeAbortListener&&(N.on("close",this.removeAbortListener),this.removeAbortListener=null),this.callback=null,this.res=N,s!==null)try{this.runInAsyncScope(s,null,null,{statusCode:t,statusText:i,headers:p,trailers:this.trailers,opaque:o,body:N,context:A})}catch(P){this.res=null,yi.destroy(N.on("error",jh),P),queueMicrotask(()=>{throw P})}}onData(t){return this.res.push(t)}onComplete(t){yi.parseHeaders(t,this.trailers),this.res.push(null)}onError(t){let{res:r,callback:n,body:i,opaque:s}=this;n&&(this.callback=null,queueMicrotask(()=>{this.runInAsyncScope(n,null,t,{opaque:s})})),r&&(this.res=null,queueMicrotask(()=>{yi.destroy(r.on("error",jh),t)})),i&&(this.body=null,yi.isStream(i)&&(i.on("error",jh),yi.destroy(i,t))),this.removeAbortListener&&(this.removeAbortListener(),this.removeAbortListener=null)}};function VU(e,t){if(t===void 0)return new Promise((r,n)=>{VU.call(this,e,(i,s)=>i?n(i):r(s))});try{let r=new vE(e,t);this.dispatch(e,r)}catch(r){if(typeof t!="function")throw r;let n=e?.opaque;queueMicrotask(()=>t(r,{opaque:n}))}}HQ.exports=VU;HQ.exports.RequestHandler=vE});var zh=x((BTe,KU)=>{"use strict";var{addAbortListener:bAe}=$t(),{RequestAbortedError:CAe}=mr(),bc=Symbol("kListener"),eo=Symbol("kSignal");function jU(e){e.abort?e.abort(e[eo]?.reason):e.reason=e[eo]?.reason??new CAe,zU(e)}function QAe(e,t){if(e.reason=null,e[eo]=null,e[bc]=null,!!t){if(t.aborted){jU(e);return}e[eo]=t,e[bc]=()=>{jU(e)},bAe(e[eo],e[bc])}}function zU(e){e[eo]&&("removeEventListener"in e[eo]?e[eo].removeEventListener("abort",e[bc]):e[eo].removeListener("abort",e[bc]),e[eo]=null,e[bc]=null)}KU.exports={addSignal:QAe,removeSignal:zU}});var e6=x((ITe,$U)=>{"use strict";var wAe=Wt(),{finished:SAe}=(ts(),Gs(Yt)),{AsyncResource:_Ae}=Ec(),{InvalidArgumentError:Cc,InvalidReturnValueError:vAe}=mr(),zo=$t(),{addSignal:RAe,removeSignal:XU}=zh();function DAe(){}var qQ=class extends _Ae{constructor(t,r,n){if(!t||typeof t!="object")throw new Cc("invalid opts");let{signal:i,method:s,opaque:o,body:a,onInfo:A,responseHeaders:f}=t;try{if(typeof n!="function")throw new Cc("invalid callback");if(typeof r!="function")throw new Cc("invalid factory");if(i&&typeof i.on!="function"&&typeof i.addEventListener!="function")throw new Cc("signal must be an EventEmitter or EventTarget");if(s==="CONNECT")throw new Cc("invalid method");if(A&&typeof A!="function")throw new Cc("invalid onInfo callback");super("UNDICI_STREAM")}catch(l){throw zo.isStream(a)&&zo.destroy(a.on("error",DAe),l),l}this.responseHeaders=f||null,this.opaque=o||null,this.factory=r,this.callback=n,this.res=null,this.abort=null,this.context=null,this.trailers=null,this.body=a,this.onInfo=A||null,zo.isStream(a)&&a.on("error",l=>{this.onError(l)}),RAe(this,i)}onConnect(t,r){if(this.reason){t(this.reason);return}wAe(this.callback),this.abort=t,this.context=r}onHeaders(t,r,n,i){let{factory:s,opaque:o,context:a,responseHeaders:A}=this,f=A==="raw"?zo.parseRawHeaders(r):zo.parseHeaders(r);if(t<200){this.onInfo&&this.onInfo({statusCode:t,headers:f});return}if(this.factory=null,s===null)return;let l=this.runInAsyncScope(s,null,{statusCode:t,headers:f,opaque:o,context:a});if(!l||typeof l.write!="function"||typeof l.end!="function"||typeof l.on!="function")throw new vAe("expected Writable");return SAe(l,{readable:!1},B=>{let{callback:S,res:_,opaque:N,trailers:P,abort:U}=this;this.res=null,(B||!_?.readable)&&zo.destroy(_,B),this.callback=null,this.runInAsyncScope(S,null,B||null,{opaque:N,trailers:P}),B&&U()}),l.on("drain",n),this.res=l,(l.writableNeedDrain!==void 0?l.writableNeedDrain:l._writableState?.needDrain)!==!0}onData(t){let{res:r}=this;return r?r.write(t):!0}onComplete(t){let{res:r}=this;XU(this),r&&(this.trailers=zo.parseHeaders(t),r.end())}onError(t){let{res:r,callback:n,opaque:i,body:s}=this;XU(this),this.factory=null,r?(this.res=null,zo.destroy(r,t)):n&&(this.callback=null,queueMicrotask(()=>{this.runInAsyncScope(n,null,t,{opaque:i})})),s&&(this.body=null,zo.destroy(s,t))}};function ZU(e,t,r){if(r===void 0)return new Promise((n,i)=>{ZU.call(this,e,t,(s,o)=>s?i(s):n(o))});try{let n=new qQ(e,t,r);this.dispatch(e,n)}catch(n){if(typeof r!="function")throw n;let i=e?.opaque;queueMicrotask(()=>r(n,{opaque:i}))}}$U.exports=ZU});var i6=x((bTe,n6)=>{"use strict";var{Readable:r6,Duplex:TAe,PassThrough:NAe}=(ts(),Gs(Yt)),MAe=Wt(),{AsyncResource:FAe}=Ec(),{InvalidArgumentError:Kh,InvalidReturnValueError:kAe,RequestAbortedError:GQ}=mr(),to=$t(),{addSignal:xAe,removeSignal:UAe}=zh();function t6(){}var Qc=Symbol("resume"),YQ=class extends r6{constructor(){super({autoDestroy:!0}),this[Qc]=null}_read(){let{[Qc]:t}=this;t&&(this[Qc]=null,t())}_destroy(t,r){this._read(),r(t)}},WQ=class extends r6{constructor(t){super({autoDestroy:!0}),this[Qc]=t}_read(){this[Qc]()}_destroy(t,r){!t&&!this._readableState.endEmitted&&(t=new GQ),r(t)}},VQ=class extends FAe{constructor(t,r){if(!t||typeof t!="object")throw new Kh("invalid opts");if(typeof r!="function")throw new Kh("invalid handler");let{signal:n,method:i,opaque:s,onInfo:o,responseHeaders:a}=t;if(n&&typeof n.on!="function"&&typeof n.addEventListener!="function")throw new Kh("signal must be an EventEmitter or EventTarget");if(i==="CONNECT")throw new Kh("invalid method");if(o&&typeof o!="function")throw new Kh("invalid onInfo callback");super("UNDICI_PIPELINE"),this.opaque=s||null,this.responseHeaders=a||null,this.handler=r,this.abort=null,this.context=null,this.onInfo=o||null,this.req=new YQ().on("error",t6),this.ret=new TAe({readableObjectMode:t.objectMode,autoDestroy:!0,read:()=>{let{body:A}=this;A?.resume&&A.resume()},write:(A,f,l)=>{let{req:p}=this;p.push(A,f)||p._readableState.destroyed?l():p[Qc]=l},destroy:(A,f)=>{let{body:l,req:p,res:B,ret:S,abort:_}=this;!A&&!S._readableState.endEmitted&&(A=new GQ),_&&A&&_(),to.destroy(l,A),to.destroy(p,A),to.destroy(B,A),UAe(this),f(A)}}).on("prefinish",()=>{let{req:A}=this;A.push(null)}),this.res=null,xAe(this,n)}onConnect(t,r){let{res:n}=this;if(this.reason){t(this.reason);return}MAe(!n,"pipeline cannot be retried"),this.abort=t,this.context=r}onHeaders(t,r,n){let{opaque:i,handler:s,context:o}=this;if(t<200){if(this.onInfo){let A=this.responseHeaders==="raw"?to.parseRawHeaders(r):to.parseHeaders(r);this.onInfo({statusCode:t,headers:A})}return}this.res=new WQ(n);let a;try{this.handler=null;let A=this.responseHeaders==="raw"?to.parseRawHeaders(r):to.parseHeaders(r);a=this.runInAsyncScope(s,null,{statusCode:t,headers:A,opaque:i,body:this.res,context:o})}catch(A){throw this.res.on("error",t6),A}if(!a||typeof a.on!="function")throw new kAe("expected Readable");a.on("data",A=>{let{ret:f,body:l}=this;!f.push(A)&&l.pause&&l.pause()}).on("error",A=>{let{ret:f}=this;to.destroy(f,A)}).on("end",()=>{let{ret:A}=this;A.push(null)}).on("close",()=>{let{ret:A}=this;A._readableState.ended||to.destroy(A,new GQ)}),this.body=a}onData(t){let{res:r}=this;return r.push(t)}onComplete(t){let{res:r}=this;r.push(null)}onError(t){let{ret:r}=this;this.handler=null,to.destroy(r,t)}};function LAe(e,t){try{let r=new VQ(e,t);return this.dispatch({...e,body:r.req},r),r.ret}catch(r){return new NAe().destroy(r)}}n6.exports=LAe});var u6=x((CTe,f6)=>{"use strict";var{InvalidArgumentError:JQ,SocketError:PAe}=mr(),{AsyncResource:OAe}=Ec(),s6=Wt(),o6=$t(),{kHTTP2Stream:HAe}=Tn(),{addSignal:qAe,removeSignal:a6}=zh(),jQ=class extends OAe{constructor(t,r){if(!t||typeof t!="object")throw new JQ("invalid opts");if(typeof r!="function")throw new JQ("invalid callback");let{signal:n,opaque:i,responseHeaders:s}=t;if(n&&typeof n.on!="function"&&typeof n.addEventListener!="function")throw new JQ("signal must be an EventEmitter or EventTarget");super("UNDICI_UPGRADE"),this.responseHeaders=s||null,this.opaque=i||null,this.callback=r,this.abort=null,this.context=null,qAe(this,n)}onConnect(t,r){if(this.reason){t(this.reason);return}s6(this.callback),this.abort=t,this.context=null}onHeaders(){throw new PAe("bad upgrade",null)}onUpgrade(t,r,n){s6(n[HAe]===!0?t===200:t===101);let{callback:i,opaque:s,context:o}=this;a6(this),this.callback=null;let a=this.responseHeaders==="raw"?o6.parseRawHeaders(r):o6.parseHeaders(r);this.runInAsyncScope(i,null,null,{headers:a,socket:n,opaque:s,context:o})}onError(t){let{callback:r,opaque:n}=this;a6(this),r&&(this.callback=null,queueMicrotask(()=>{this.runInAsyncScope(r,null,t,{opaque:n})}))}};function A6(e,t){if(t===void 0)return new Promise((r,n)=>{A6.call(this,e,(i,s)=>i?n(i):r(s))});try{let r=new jQ(e,t),n={...e,method:e.method||"GET",upgrade:e.protocol||"Websocket"};this.dispatch(n,r)}catch(r){if(typeof t!="function")throw r;let n=e?.opaque;queueMicrotask(()=>t(r,{opaque:n}))}}f6.exports=A6});var g6=x((QTe,d6)=>{"use strict";var GAe=Wt(),{AsyncResource:YAe}=Ec(),{InvalidArgumentError:zQ,SocketError:WAe}=mr(),c6=$t(),{addSignal:VAe,removeSignal:l6}=zh(),KQ=class extends YAe{constructor(t,r){if(!t||typeof t!="object")throw new zQ("invalid opts");if(typeof r!="function")throw new zQ("invalid callback");let{signal:n,opaque:i,responseHeaders:s}=t;if(n&&typeof n.on!="function"&&typeof n.addEventListener!="function")throw new zQ("signal must be an EventEmitter or EventTarget");super("UNDICI_CONNECT"),this.opaque=i||null,this.responseHeaders=s||null,this.callback=r,this.abort=null,VAe(this,n)}onConnect(t,r){if(this.reason){t(this.reason);return}GAe(this.callback),this.abort=t,this.context=r}onHeaders(){throw new WAe("bad connect",null)}onUpgrade(t,r,n){let{callback:i,opaque:s,context:o}=this;l6(this),this.callback=null;let a=r;a!=null&&(a=this.responseHeaders==="raw"?c6.parseRawHeaders(r):c6.parseHeaders(r)),this.runInAsyncScope(i,null,null,{statusCode:t,headers:a,socket:n,opaque:s,context:o})}onError(t){let{callback:r,opaque:n}=this;l6(this),r&&(this.callback=null,queueMicrotask(()=>{this.runInAsyncScope(r,null,t,{opaque:n})}))}};function h6(e,t){if(t===void 0)return new Promise((r,n)=>{h6.call(this,e,(i,s)=>i?n(i):r(s))});try{let r=new KQ(e,t),n={...e,method:"CONNECT"};this.dispatch(n,r)}catch(r){if(typeof t!="function")throw r;let n=e?.opaque;queueMicrotask(()=>t(r,{opaque:n}))}}d6.exports=h6});var p6=x((wTe,wc)=>{"use strict";wc.exports.request=JU();wc.exports.stream=e6();wc.exports.pipeline=i6();wc.exports.upgrade=u6();wc.exports.connect=g6()});var y6=x((STe,E6)=>{"use strict";var{InvalidArgumentError:JAe}=mr(),_r,Sc;E6.exports=(Sc=class{constructor(t){St(this,_r);ft(this,_r,t)}static wrap(t){return t.onRequestStart?t:new Sc(t)}onConnect(t,r){return te(this,_r).onConnect?.(t,r)}onResponseStarted(){return te(this,_r).onResponseStarted?.()}onHeaders(t,r,n,i){return te(this,_r).onHeaders?.(t,r,n,i)}onUpgrade(t,r,n){return te(this,_r).onUpgrade?.(t,r,n)}onData(t){return te(this,_r).onData?.(t)}onComplete(t){return te(this,_r).onComplete?.(t)}onError(t){if(!te(this,_r).onError)throw t;return te(this,_r).onError?.(t)}onRequestStart(t,r){te(this,_r).onConnect?.(n=>t.abort(n),r)}onRequestUpgrade(t,r,n,i){let s=[];for(let[o,a]of Object.entries(n))s.push(Buffer.from(o,"latin1"),XQ(a));te(this,_r).onUpgrade?.(r,s,i)}onResponseStart(t,r,n,i){let s=[];for(let[o,a]of Object.entries(n))s.push(Buffer.from(o,"latin1"),XQ(a));te(this,_r).onHeaders?.(r,s,()=>t.resume(),i)===!1&&t.pause()}onResponseData(t,r){te(this,_r).onData?.(r)===!1&&t.pause()}onResponseEnd(t,r){let n=[];for(let[i,s]of Object.entries(r))n.push(Buffer.from(i,"latin1"),XQ(s));te(this,_r).onComplete?.(n)}onResponseError(t,r){if(!te(this,_r).onError)throw new JAe("invalid onError method");te(this,_r).onError?.(r)}},_r=new WeakMap,Sc);function XQ(e){return Array.isArray(e)?e.map(t=>Buffer.from(t,"latin1")):Buffer.from(e,"latin1")}});var B6=x((vTe,m6)=>{"use strict";var jAe=Zi(),zAe=y6(),KAe=e=>(t,r)=>e(t,zAe.wrap(r)),ZQ=class extends jAe{dispatch(){throw new Error("not implemented")}close(){throw new Error("not implemented")}destroy(){throw new Error("not implemented")}compose(...t){let r=Array.isArray(t[0])?t[0]:t,n=this.dispatch.bind(this);for(let i of r)if(i!=null){if(typeof i!="function")throw new TypeError(`invalid interceptor, expected function received ${typeof i}`);if(n=i(n),n=KAe(n),n==null||typeof n!="function"||n.length!==2)throw new TypeError("invalid interceptor")}return new Proxy(this,{get:(i,s)=>s==="dispatch"?n:i[s]})}};m6.exports=ZQ});var C6=x((RTe,b6)=>{"use strict";var{parseHeaders:$Q}=$t(),{InvalidArgumentError:XAe}=mr(),ew=Symbol("resume"),I6,Ef,Xh,_c,Zh;I6=ew;var tw=class{constructor(t){St(this,Ef,!1);St(this,Xh,null);St(this,_c,!1);St(this,Zh);y(this,I6,null);ft(this,Zh,t)}pause(){ft(this,Ef,!0)}resume(){te(this,Ef)&&(ft(this,Ef,!1),this[ew]?.())}abort(t){te(this,_c)||(ft(this,_c,!0),ft(this,Xh,t),te(this,Zh).call(this,t))}get aborted(){return te(this,_c)}get reason(){return te(this,Xh)}get paused(){return te(this,Ef)}};Ef=new WeakMap,Xh=new WeakMap,_c=new WeakMap,Zh=new WeakMap;var mi,Jn,vc;b6.exports=(vc=class{constructor(t){St(this,mi);St(this,Jn);ft(this,mi,t)}static unwrap(t){return t.onRequestStart?new vc(t):t}onConnect(t,r){ft(this,Jn,new tw(t)),te(this,mi).onRequestStart?.(te(this,Jn),r)}onResponseStarted(){return te(this,mi).onResponseStarted?.()}onUpgrade(t,r,n){te(this,mi).onRequestUpgrade?.(te(this,Jn),t,$Q(r),n)}onHeaders(t,r,n,i){return te(this,Jn)[ew]=n,te(this,mi).onResponseStart?.(te(this,Jn),t,$Q(r),i),!te(this,Jn).paused}onData(t){return te(this,mi).onResponseData?.(te(this,Jn),t),!te(this,Jn).paused}onComplete(t){te(this,mi).onResponseEnd?.(te(this,Jn),$Q(t))}onError(t){if(!te(this,mi).onResponseError)throw new XAe("invalid onError method");te(this,mi).onResponseError?.(te(this,Jn),t)}},mi=new WeakMap,Jn=new WeakMap,vc)});var DE=x((TTe,R6)=>{"use strict";var ZAe=B6(),$Ae=C6(),{ClientDestroyedError:rw,ClientClosedError:efe,InvalidArgumentError:RE}=mr(),{kDestroy:tfe,kClose:rfe,kClosed:$h,kDestroyed:Rc,kDispatch:nfe}=Tn(),ro=Symbol("onDestroyed"),Ko=Symbol("onClosed"),Q6,w6,S6,_6,v6,nw=class extends(v6=ZAe,_6=Rc,S6=ro,w6=$h,Q6=Ko,v6){constructor(){super(...arguments);y(this,_6,!1);y(this,S6,null);y(this,w6,!1);y(this,Q6,null)}get destroyed(){return this[Rc]}get closed(){return this[$h]}close(r){if(r===void 0)return new Promise((i,s)=>{this.close((o,a)=>o?s(o):i(a))});if(typeof r!="function")throw new RE("invalid callback");if(this[Rc]){let i=new rw;queueMicrotask(()=>r(i,null));return}if(this[$h]){this[Ko]?this[Ko].push(r):queueMicrotask(()=>r(null,null));return}this[$h]=!0,this[Ko]??(this[Ko]=[]),this[Ko].push(r);let n=()=>{let i=this[Ko];this[Ko]=null;for(let s=0;sthis.destroy()).then(()=>queueMicrotask(n))}destroy(r,n){if(typeof r=="function"&&(n=r,r=null),n===void 0)return new Promise((s,o)=>{this.destroy(r,(a,A)=>a?o(a):s(A))});if(typeof n!="function")throw new RE("invalid callback");if(this[Rc]){this[ro]?this[ro].push(n):queueMicrotask(()=>n(null,null));return}r||(r=new rw),this[Rc]=!0,this[ro]??(this[ro]=[]),this[ro].push(n);let i=()=>{let s=this[ro];this[ro]=null;for(let o=0;oqueueMicrotask(i))}dispatch(r,n){if(!n||typeof n!="object")throw new RE("handler must be an object");n=$Ae.unwrap(n);try{if(!r||typeof r!="object")throw new RE("opts must be an object.");if(this[Rc]||this[ro])throw new rw;if(this[$h])throw new efe;return this[nfe](r,n)}catch(i){if(typeof n.onError!="function")throw i;return n.onError(i),!1}}};R6.exports=nw});var ow=x((MTe,F6)=>{"use strict";var{kConnected:D6,kPending:T6,kRunning:N6,kSize:M6,kFree:ife,kQueued:sfe}=Tn(),iw=class{constructor(t){this.connected=t[D6],this.pending=t[T6],this.running=t[N6],this.size=t[M6]}},sw=class{constructor(t){this.connected=t[D6],this.free=t[ife],this.pending=t[T6],this.queued=t[sfe],this.running=t[N6],this.size=t[M6]}};F6.exports={ClientStats:iw,PoolStats:sw}});var x6=x((kTe,k6)=>{"use strict";var TE=class{constructor(){y(this,"bottom",0);y(this,"top",0);y(this,"list",new Array(2048).fill(void 0));y(this,"next",null)}isEmpty(){return this.top===this.bottom}isFull(){return(this.top+1&2047)===this.bottom}push(t){this.list[this.top]=t,this.top=this.top+1&2047}shift(){let t=this.list[this.bottom];return t===void 0?null:(this.list[this.bottom]=void 0,this.bottom=this.bottom+1&2047,t)}};k6.exports=class{constructor(){this.head=this.tail=new TE}isEmpty(){return this.head.isEmpty()}push(t){this.head.isFull()&&(this.head=this.head.next=new TE),this.head.push(t)}shift(){let t=this.tail,r=t.shift();return t.isEmpty()&&t.next!==null&&(this.tail=t.next,t.next=null),r}}});var $6=x((UTe,Z6)=>{"use strict";var{PoolStats:ofe}=ow(),afe=DE(),Afe=x6(),{kConnected:aw,kSize:U6,kRunning:L6,kPending:P6,kQueued:ed,kBusy:ffe,kFree:ufe,kUrl:cfe,kClose:lfe,kDestroy:hfe,kDispatch:dfe}=Tn(),Mr=Symbol("clients"),pn=Symbol("needDrain"),td=Symbol("queue"),Aw=Symbol("closed resolve"),fw=Symbol("onDrain"),O6=Symbol("onConnect"),H6=Symbol("onDisconnect"),q6=Symbol("onConnectionError"),uw=Symbol("get dispatcher"),K6=Symbol("add client"),X6=Symbol("remove client"),G6,Y6,W6,V6,J6,j6,z6,cw=class extends afe{constructor(){super(...arguments);y(this,z6,new Afe);y(this,j6,0);y(this,J6,[]);y(this,V6,!1);y(this,W6,(r,n)=>{this.emit("connect",r,[this,...n])});y(this,Y6,(r,n,i)=>{this.emit("disconnect",r,[this,...n],i)});y(this,G6,(r,n,i)=>{this.emit("connectionError",r,[this,...n],i)})}[(z6=td,j6=ed,J6=Mr,V6=pn,fw)](r,n,i){let s=this[td],o=!1;for(;!o;){let a=s.shift();if(!a)break;this[ed]--,o=!r.dispatch(a.opts,a.handler)}if(r[pn]=o,!o&&this[pn]&&(this[pn]=!1,this.emit("drain",n,[this,...i])),this[Aw]&&s.isEmpty()){let a=[];for(let A=0;A{this[Aw]=r})}[hfe](r){for(;;){let i=this[td].shift();if(!i)break;i.handler.onError(r)}let n=new Array(this[Mr].length);for(let i=0;i{this[pn]&&this[fw](r,r[cfe],[r,this])}),this}[X6](r){r.close(()=>{let n=this[Mr].indexOf(r);n!==-1&&this[Mr].splice(n,1)}),this[pn]=this[Mr].some(n=>!n[pn]&&n.closed!==!0&&n.destroyed!==!0)}};Z6.exports={PoolBase:cw,kClients:Mr,kNeedDrain:pn,kAddClient:K6,kRemoveClient:X6,kGetDispatcher:uw}});var r3=x((PTe,t3)=>{"use strict";var e3=new Map,lw=new Map;function NE(e){let t=e3.get(e);return t||(t=new Set,e3.set(e,t)),t}function gfe(e){return{name:e,get hasSubscribers(){return NE(e).size>0},publish(t){for(let r of NE(e))r(t,e)},subscribe(t){return NE(e).add(t),this},unsubscribe(t){return NE(e).delete(t),this}}}function ME(e){return lw.has(e)||lw.set(e,gfe(e)),lw.get(e)}function pfe(e,t){ME(e).subscribe(t)}function Efe(e,t){ME(e).unsubscribe(t)}t3.exports={channel:ME,hasSubscribers(e){return ME(e).hasSubscribers},subscribe:pfe,unsubscribe:Efe}});var nd=x((OTe,i3)=>{"use strict";var Ft=r3(),pw=Yr(),yf=pw.debuglog("undici"),rd=pw.debuglog("fetch"),FE=pw.debuglog("websocket"),jn={beforeConnect:Ft.channel("undici:client:beforeConnect"),connected:Ft.channel("undici:client:connected"),connectError:Ft.channel("undici:client:connectError"),sendHeaders:Ft.channel("undici:client:sendHeaders"),create:Ft.channel("undici:request:create"),bodySent:Ft.channel("undici:request:bodySent"),bodyChunkSent:Ft.channel("undici:request:bodyChunkSent"),bodyChunkReceived:Ft.channel("undici:request:bodyChunkReceived"),headers:Ft.channel("undici:request:headers"),trailers:Ft.channel("undici:request:trailers"),error:Ft.channel("undici:request:error"),open:Ft.channel("undici:websocket:open"),close:Ft.channel("undici:websocket:close"),socketError:Ft.channel("undici:websocket:socket_error"),ping:Ft.channel("undici:websocket:ping"),pong:Ft.channel("undici:websocket:pong"),proxyConnected:Ft.channel("undici:proxy:connected")},hw=!1;function n3(e=yf){if(!hw){if(jn.beforeConnect.hasSubscribers||jn.connected.hasSubscribers||jn.connectError.hasSubscribers||jn.sendHeaders.hasSubscribers){hw=!0;return}hw=!0,Ft.subscribe("undici:client:beforeConnect",t=>{let{connectParams:{version:r,protocol:n,port:i,host:s}}=t;e("connecting to %s%s using %s%s",s,i?`:${i}`:"",n,r)}),Ft.subscribe("undici:client:connected",t=>{let{connectParams:{version:r,protocol:n,port:i,host:s}}=t;e("connected to %s%s using %s%s",s,i?`:${i}`:"",n,r)}),Ft.subscribe("undici:client:connectError",t=>{let{connectParams:{version:r,protocol:n,port:i,host:s},error:o}=t;e("connection to %s%s using %s%s errored - %s",s,i?`:${i}`:"",n,r,o.message)}),Ft.subscribe("undici:client:sendHeaders",t=>{let{request:{method:r,path:n,origin:i}}=t;e("sending request to %s %s%s",r,i,n)})}}var dw=!1;function yfe(e=yf){if(!dw){if(jn.headers.hasSubscribers||jn.trailers.hasSubscribers||jn.error.hasSubscribers){dw=!0;return}dw=!0,Ft.subscribe("undici:request:headers",t=>{let{request:{method:r,path:n,origin:i},response:{statusCode:s}}=t;e("received response to %s %s%s - HTTP %d",r,i,n,s)}),Ft.subscribe("undici:request:trailers",t=>{let{request:{method:r,path:n,origin:i}}=t;e("trailers received from %s %s%s",r,i,n)}),Ft.subscribe("undici:request:error",t=>{let{request:{method:r,path:n,origin:i},error:s}=t;e("request to %s %s%s errored - %s",r,i,n,s.message)})}}var gw=!1;function mfe(e=FE){if(!gw){if(jn.open.hasSubscribers||jn.close.hasSubscribers||jn.socketError.hasSubscribers||jn.ping.hasSubscribers||jn.pong.hasSubscribers){gw=!0;return}gw=!0,Ft.subscribe("undici:websocket:open",t=>{if(t.address!=null){let{address:r,port:n}=t.address;e("connection opened %s%s",r,n?`:${n}`:"")}else e("connection opened")}),Ft.subscribe("undici:websocket:close",t=>{let{websocket:r,code:n,reason:i}=t;e("closed connection to %s - %s %s",r.url,n,i)}),Ft.subscribe("undici:websocket:socket_error",t=>{e("connection errored - %s",t.message)}),Ft.subscribe("undici:websocket:ping",t=>{e("ping received")}),Ft.subscribe("undici:websocket:pong",t=>{e("pong received")})}}(yf.enabled||rd.enabled)&&(n3(rd.enabled?rd:yf),yfe(rd.enabled?rd:yf));FE.enabled&&(n3(yf.enabled?yf:FE),mfe(FE));i3.exports={channels:jn}});var a3=x((HTe,o3)=>{"use strict";var{InvalidArgumentError:Nt,NotSupportedError:Bfe}=mr(),no=Wt(),{isValidHTTPToken:Ew,isValidHeaderValue:yw,isStream:Ife,destroy:bfe,isBuffer:Cfe,isFormDataLike:Qfe,isIterable:wfe,hasSafeIterator:Sfe,isBlobLike:_fe,serializePathWithQuery:vfe,assertRequestHandler:Rfe,getServerName:Dfe,normalizedMethodRecords:Tfe,getProtocolFromUrlString:Nfe}=$t(),{channels:Nn}=nd(),{headerNameLowerCasedRecord:s3}=mE(),Mfe=/[^\u0021-\u00ff]/,Bi=Symbol("handler"),mw=class{constructor(t,{path:r,method:n,body:i,headers:s,query:o,idempotent:a,blocking:A,upgrade:f,headersTimeout:l,bodyTimeout:p,reset:B,expectContinue:S,servername:_,throwOnError:N,maxRedirections:P,typeOfService:U},G){if(typeof r!="string")throw new Nt("path must be a string");if(r[0]!=="/"&&!(r.startsWith("http://")||r.startsWith("https://"))&&n!=="CONNECT")throw new Nt("path must be an absolute URL or start with a slash");if(Mfe.test(r))throw new Nt("invalid request path");if(typeof n!="string")throw new Nt("method must be a string");if(Tfe[n]===void 0&&!Ew(n))throw new Nt("invalid request method");if(f&&typeof f!="string")throw new Nt("upgrade must be a string");if(f&&!yw(f))throw new Nt("invalid upgrade header");if(l!=null&&(!Number.isFinite(l)||l<0))throw new Nt("invalid headersTimeout");if(p!=null&&(!Number.isFinite(p)||p<0))throw new Nt("invalid bodyTimeout");if(B!=null&&typeof B!="boolean")throw new Nt("invalid reset");if(S!=null&&typeof S!="boolean")throw new Nt("invalid expectContinue");if(N!=null)throw new Nt("invalid throwOnError");if(P!=null&&P!==0)throw new Nt("maxRedirections is not supported, use the redirect interceptor");if(U!=null&&(!Number.isInteger(U)||U<0||U>255))throw new Nt("typeOfService must be an integer between 0 and 255");if(this.headersTimeout=l,this.bodyTimeout=p,this.method=n,this.typeOfService=U??0,this.abort=null,i==null)this.body=null;else if(Ife(i)){this.body=i;let Y=this.body._readableState;(!Y||!Y.autoDestroy)&&(this.endHandler=function(){bfe(this)},this.body.on("end",this.endHandler)),this.errorHandler=Z=>{this.abort?this.abort(Z):this.error=Z},this.body.on("error",this.errorHandler)}else if(Cfe(i))this.body=i.byteLength?i:null;else if(ArrayBuffer.isView(i))this.body=i.buffer.byteLength?Buffer.from(i.buffer,i.byteOffset,i.byteLength):null;else if(i instanceof ArrayBuffer)this.body=i.byteLength?Buffer.from(i):null;else if(typeof i=="string")this.body=i.length?Buffer.from(i):null;else if(Qfe(i)||wfe(i)||_fe(i))this.body=i;else throw new Nt("body must be a string, a Buffer, a Readable stream, an iterable, or an async iterable");if(this.completed=!1,this.aborted=!1,this.upgrade=f||null,this.path=o?vfe(r,o):r,this.origin=t,this.protocol=Nfe(t),this.idempotent=a??(n==="HEAD"||n==="GET"),this.blocking=A??this.method!=="HEAD",this.reset=B??null,this.host=null,this.contentLength=null,this.contentType=null,this.headers=[],this.expectContinue=S??!1,Array.isArray(s)){if(s.length%2!==0)throw new Nt("headers array must be even");for(let Y=0;Y{"use strict";function Ffe(){let e=globalThis._tlsModule;if(!e)throw new Error("node:tls bridge module is not available");return e}var A3={};for(let e of["connect","createServer","createSecureContext","TLSSocket","Server","checkServerIdentity","getCiphers","rootCertificates"])Object.defineProperty(A3,e,{enumerable:!0,get(){return Ffe()[e]}});f3.exports=A3});var Iw=x((YTe,h3)=>{"use strict";var kfe=pE(),c3=Wt(),l3=$t(),{InvalidArgumentError:xfe}=mr(),Bw,Ufe=class{constructor(t){this._maxCachedSessions=t,this._sessionCache=new Map,this._sessionRegistry=new FinalizationRegistry(r=>{if(this._sessionCache.size{"use strict";Object.defineProperty(bw,"__esModule",{value:!0});bw.enumToMap=Pfe;function Pfe(e,t=[],r=[]){let n=(t?.length??0)===0,i=(r?.length??0)===0;return Object.fromEntries(Object.entries(e).filter(([,s])=>typeof s=="number"&&(n||t.includes(s))&&(i||!r.includes(s))))}});var g3=x(q=>{"use strict";Object.defineProperty(q,"__esModule",{value:!0});q.SPECIAL_HEADERS=q.MINOR=q.MAJOR=q.HTAB_SP_VCHAR_OBS_TEXT=q.QUOTED_STRING=q.CONNECTION_TOKEN_CHARS=q.HEADER_CHARS=q.TOKEN=q.HEX=q.URL_CHAR=q.USERINFO_CHARS=q.MARK=q.ALPHANUM=q.NUM=q.HEX_MAP=q.NUM_MAP=q.ALPHA=q.STATUSES_HTTP=q.H_METHOD_MAP=q.METHOD_MAP=q.METHODS_RTSP=q.METHODS_ICE=q.METHODS_HTTP=q.HEADER_STATE=q.FINISH=q.STATUSES=q.METHODS=q.LENIENT_FLAGS=q.FLAGS=q.TYPE=q.ERROR=void 0;var Ofe=d3();q.ERROR={OK:0,INTERNAL:1,STRICT:2,CR_EXPECTED:25,LF_EXPECTED:3,UNEXPECTED_CONTENT_LENGTH:4,UNEXPECTED_SPACE:30,CLOSED_CONNECTION:5,INVALID_METHOD:6,INVALID_URL:7,INVALID_CONSTANT:8,INVALID_VERSION:9,INVALID_HEADER_TOKEN:10,INVALID_CONTENT_LENGTH:11,INVALID_CHUNK_SIZE:12,INVALID_STATUS:13,INVALID_EOF_STATE:14,INVALID_TRANSFER_ENCODING:15,CB_MESSAGE_BEGIN:16,CB_HEADERS_COMPLETE:17,CB_MESSAGE_COMPLETE:18,CB_CHUNK_HEADER:19,CB_CHUNK_COMPLETE:20,PAUSED:21,PAUSED_UPGRADE:22,PAUSED_H2_UPGRADE:23,USER:24,CB_URL_COMPLETE:26,CB_STATUS_COMPLETE:27,CB_METHOD_COMPLETE:32,CB_VERSION_COMPLETE:33,CB_HEADER_FIELD_COMPLETE:28,CB_HEADER_VALUE_COMPLETE:29,CB_CHUNK_EXTENSION_NAME_COMPLETE:34,CB_CHUNK_EXTENSION_VALUE_COMPLETE:35,CB_RESET:31,CB_PROTOCOL_COMPLETE:38};q.TYPE={BOTH:0,REQUEST:1,RESPONSE:2};q.FLAGS={CONNECTION_KEEP_ALIVE:1,CONNECTION_CLOSE:2,CONNECTION_UPGRADE:4,CHUNKED:8,UPGRADE:16,CONTENT_LENGTH:32,SKIPBODY:64,TRAILING:128,TRANSFER_ENCODING:512};q.LENIENT_FLAGS={HEADERS:1,CHUNKED_LENGTH:2,KEEP_ALIVE:4,TRANSFER_ENCODING:8,VERSION:16,DATA_AFTER_CLOSE:32,OPTIONAL_LF_AFTER_CR:64,OPTIONAL_CRLF_AFTER_CHUNK:128,OPTIONAL_CR_BEFORE_LF:256,SPACES_AFTER_CHUNK_SIZE:512};q.METHODS={DELETE:0,GET:1,HEAD:2,POST:3,PUT:4,CONNECT:5,OPTIONS:6,TRACE:7,COPY:8,LOCK:9,MKCOL:10,MOVE:11,PROPFIND:12,PROPPATCH:13,SEARCH:14,UNLOCK:15,BIND:16,REBIND:17,UNBIND:18,ACL:19,REPORT:20,MKACTIVITY:21,CHECKOUT:22,MERGE:23,"M-SEARCH":24,NOTIFY:25,SUBSCRIBE:26,UNSUBSCRIBE:27,PATCH:28,PURGE:29,MKCALENDAR:30,LINK:31,UNLINK:32,SOURCE:33,PRI:34,DESCRIBE:35,ANNOUNCE:36,SETUP:37,PLAY:38,PAUSE:39,TEARDOWN:40,GET_PARAMETER:41,SET_PARAMETER:42,REDIRECT:43,RECORD:44,FLUSH:45,QUERY:46};q.STATUSES={CONTINUE:100,SWITCHING_PROTOCOLS:101,PROCESSING:102,EARLY_HINTS:103,RESPONSE_IS_STALE:110,REVALIDATION_FAILED:111,DISCONNECTED_OPERATION:112,HEURISTIC_EXPIRATION:113,MISCELLANEOUS_WARNING:199,OK:200,CREATED:201,ACCEPTED:202,NON_AUTHORITATIVE_INFORMATION:203,NO_CONTENT:204,RESET_CONTENT:205,PARTIAL_CONTENT:206,MULTI_STATUS:207,ALREADY_REPORTED:208,TRANSFORMATION_APPLIED:214,IM_USED:226,MISCELLANEOUS_PERSISTENT_WARNING:299,MULTIPLE_CHOICES:300,MOVED_PERMANENTLY:301,FOUND:302,SEE_OTHER:303,NOT_MODIFIED:304,USE_PROXY:305,SWITCH_PROXY:306,TEMPORARY_REDIRECT:307,PERMANENT_REDIRECT:308,BAD_REQUEST:400,UNAUTHORIZED:401,PAYMENT_REQUIRED:402,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_ALLOWED:405,NOT_ACCEPTABLE:406,PROXY_AUTHENTICATION_REQUIRED:407,REQUEST_TIMEOUT:408,CONFLICT:409,GONE:410,LENGTH_REQUIRED:411,PRECONDITION_FAILED:412,PAYLOAD_TOO_LARGE:413,URI_TOO_LONG:414,UNSUPPORTED_MEDIA_TYPE:415,RANGE_NOT_SATISFIABLE:416,EXPECTATION_FAILED:417,IM_A_TEAPOT:418,PAGE_EXPIRED:419,ENHANCE_YOUR_CALM:420,MISDIRECTED_REQUEST:421,UNPROCESSABLE_ENTITY:422,LOCKED:423,FAILED_DEPENDENCY:424,TOO_EARLY:425,UPGRADE_REQUIRED:426,PRECONDITION_REQUIRED:428,TOO_MANY_REQUESTS:429,REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL:430,REQUEST_HEADER_FIELDS_TOO_LARGE:431,LOGIN_TIMEOUT:440,NO_RESPONSE:444,RETRY_WITH:449,BLOCKED_BY_PARENTAL_CONTROL:450,UNAVAILABLE_FOR_LEGAL_REASONS:451,CLIENT_CLOSED_LOAD_BALANCED_REQUEST:460,INVALID_X_FORWARDED_FOR:463,REQUEST_HEADER_TOO_LARGE:494,SSL_CERTIFICATE_ERROR:495,SSL_CERTIFICATE_REQUIRED:496,HTTP_REQUEST_SENT_TO_HTTPS_PORT:497,INVALID_TOKEN:498,CLIENT_CLOSED_REQUEST:499,INTERNAL_SERVER_ERROR:500,NOT_IMPLEMENTED:501,BAD_GATEWAY:502,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504,HTTP_VERSION_NOT_SUPPORTED:505,VARIANT_ALSO_NEGOTIATES:506,INSUFFICIENT_STORAGE:507,LOOP_DETECTED:508,BANDWIDTH_LIMIT_EXCEEDED:509,NOT_EXTENDED:510,NETWORK_AUTHENTICATION_REQUIRED:511,WEB_SERVER_UNKNOWN_ERROR:520,WEB_SERVER_IS_DOWN:521,CONNECTION_TIMEOUT:522,ORIGIN_IS_UNREACHABLE:523,TIMEOUT_OCCURED:524,SSL_HANDSHAKE_FAILED:525,INVALID_SSL_CERTIFICATE:526,RAILGUN_ERROR:527,SITE_IS_OVERLOADED:529,SITE_IS_FROZEN:530,IDENTITY_PROVIDER_AUTHENTICATION_ERROR:561,NETWORK_READ_TIMEOUT:598,NETWORK_CONNECT_TIMEOUT:599};q.FINISH={SAFE:0,SAFE_WITH_CB:1,UNSAFE:2};q.HEADER_STATE={GENERAL:0,CONNECTION:1,CONTENT_LENGTH:2,TRANSFER_ENCODING:3,UPGRADE:4,CONNECTION_KEEP_ALIVE:5,CONNECTION_CLOSE:6,CONNECTION_UPGRADE:7,TRANSFER_ENCODING_CHUNKED:8};q.METHODS_HTTP=[q.METHODS.DELETE,q.METHODS.GET,q.METHODS.HEAD,q.METHODS.POST,q.METHODS.PUT,q.METHODS.CONNECT,q.METHODS.OPTIONS,q.METHODS.TRACE,q.METHODS.COPY,q.METHODS.LOCK,q.METHODS.MKCOL,q.METHODS.MOVE,q.METHODS.PROPFIND,q.METHODS.PROPPATCH,q.METHODS.SEARCH,q.METHODS.UNLOCK,q.METHODS.BIND,q.METHODS.REBIND,q.METHODS.UNBIND,q.METHODS.ACL,q.METHODS.REPORT,q.METHODS.MKACTIVITY,q.METHODS.CHECKOUT,q.METHODS.MERGE,q.METHODS["M-SEARCH"],q.METHODS.NOTIFY,q.METHODS.SUBSCRIBE,q.METHODS.UNSUBSCRIBE,q.METHODS.PATCH,q.METHODS.PURGE,q.METHODS.MKCALENDAR,q.METHODS.LINK,q.METHODS.UNLINK,q.METHODS.PRI,q.METHODS.SOURCE,q.METHODS.QUERY];q.METHODS_ICE=[q.METHODS.SOURCE];q.METHODS_RTSP=[q.METHODS.OPTIONS,q.METHODS.DESCRIBE,q.METHODS.ANNOUNCE,q.METHODS.SETUP,q.METHODS.PLAY,q.METHODS.PAUSE,q.METHODS.TEARDOWN,q.METHODS.GET_PARAMETER,q.METHODS.SET_PARAMETER,q.METHODS.REDIRECT,q.METHODS.RECORD,q.METHODS.FLUSH,q.METHODS.GET,q.METHODS.POST];q.METHOD_MAP=(0,Ofe.enumToMap)(q.METHODS);q.H_METHOD_MAP=Object.fromEntries(Object.entries(q.METHODS).filter(([e])=>e.startsWith("H")));q.STATUSES_HTTP=[q.STATUSES.CONTINUE,q.STATUSES.SWITCHING_PROTOCOLS,q.STATUSES.PROCESSING,q.STATUSES.EARLY_HINTS,q.STATUSES.RESPONSE_IS_STALE,q.STATUSES.REVALIDATION_FAILED,q.STATUSES.DISCONNECTED_OPERATION,q.STATUSES.HEURISTIC_EXPIRATION,q.STATUSES.MISCELLANEOUS_WARNING,q.STATUSES.OK,q.STATUSES.CREATED,q.STATUSES.ACCEPTED,q.STATUSES.NON_AUTHORITATIVE_INFORMATION,q.STATUSES.NO_CONTENT,q.STATUSES.RESET_CONTENT,q.STATUSES.PARTIAL_CONTENT,q.STATUSES.MULTI_STATUS,q.STATUSES.ALREADY_REPORTED,q.STATUSES.TRANSFORMATION_APPLIED,q.STATUSES.IM_USED,q.STATUSES.MISCELLANEOUS_PERSISTENT_WARNING,q.STATUSES.MULTIPLE_CHOICES,q.STATUSES.MOVED_PERMANENTLY,q.STATUSES.FOUND,q.STATUSES.SEE_OTHER,q.STATUSES.NOT_MODIFIED,q.STATUSES.USE_PROXY,q.STATUSES.SWITCH_PROXY,q.STATUSES.TEMPORARY_REDIRECT,q.STATUSES.PERMANENT_REDIRECT,q.STATUSES.BAD_REQUEST,q.STATUSES.UNAUTHORIZED,q.STATUSES.PAYMENT_REQUIRED,q.STATUSES.FORBIDDEN,q.STATUSES.NOT_FOUND,q.STATUSES.METHOD_NOT_ALLOWED,q.STATUSES.NOT_ACCEPTABLE,q.STATUSES.PROXY_AUTHENTICATION_REQUIRED,q.STATUSES.REQUEST_TIMEOUT,q.STATUSES.CONFLICT,q.STATUSES.GONE,q.STATUSES.LENGTH_REQUIRED,q.STATUSES.PRECONDITION_FAILED,q.STATUSES.PAYLOAD_TOO_LARGE,q.STATUSES.URI_TOO_LONG,q.STATUSES.UNSUPPORTED_MEDIA_TYPE,q.STATUSES.RANGE_NOT_SATISFIABLE,q.STATUSES.EXPECTATION_FAILED,q.STATUSES.IM_A_TEAPOT,q.STATUSES.PAGE_EXPIRED,q.STATUSES.ENHANCE_YOUR_CALM,q.STATUSES.MISDIRECTED_REQUEST,q.STATUSES.UNPROCESSABLE_ENTITY,q.STATUSES.LOCKED,q.STATUSES.FAILED_DEPENDENCY,q.STATUSES.TOO_EARLY,q.STATUSES.UPGRADE_REQUIRED,q.STATUSES.PRECONDITION_REQUIRED,q.STATUSES.TOO_MANY_REQUESTS,q.STATUSES.REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL,q.STATUSES.REQUEST_HEADER_FIELDS_TOO_LARGE,q.STATUSES.LOGIN_TIMEOUT,q.STATUSES.NO_RESPONSE,q.STATUSES.RETRY_WITH,q.STATUSES.BLOCKED_BY_PARENTAL_CONTROL,q.STATUSES.UNAVAILABLE_FOR_LEGAL_REASONS,q.STATUSES.CLIENT_CLOSED_LOAD_BALANCED_REQUEST,q.STATUSES.INVALID_X_FORWARDED_FOR,q.STATUSES.REQUEST_HEADER_TOO_LARGE,q.STATUSES.SSL_CERTIFICATE_ERROR,q.STATUSES.SSL_CERTIFICATE_REQUIRED,q.STATUSES.HTTP_REQUEST_SENT_TO_HTTPS_PORT,q.STATUSES.INVALID_TOKEN,q.STATUSES.CLIENT_CLOSED_REQUEST,q.STATUSES.INTERNAL_SERVER_ERROR,q.STATUSES.NOT_IMPLEMENTED,q.STATUSES.BAD_GATEWAY,q.STATUSES.SERVICE_UNAVAILABLE,q.STATUSES.GATEWAY_TIMEOUT,q.STATUSES.HTTP_VERSION_NOT_SUPPORTED,q.STATUSES.VARIANT_ALSO_NEGOTIATES,q.STATUSES.INSUFFICIENT_STORAGE,q.STATUSES.LOOP_DETECTED,q.STATUSES.BANDWIDTH_LIMIT_EXCEEDED,q.STATUSES.NOT_EXTENDED,q.STATUSES.NETWORK_AUTHENTICATION_REQUIRED,q.STATUSES.WEB_SERVER_UNKNOWN_ERROR,q.STATUSES.WEB_SERVER_IS_DOWN,q.STATUSES.CONNECTION_TIMEOUT,q.STATUSES.ORIGIN_IS_UNREACHABLE,q.STATUSES.TIMEOUT_OCCURED,q.STATUSES.SSL_HANDSHAKE_FAILED,q.STATUSES.INVALID_SSL_CERTIFICATE,q.STATUSES.RAILGUN_ERROR,q.STATUSES.SITE_IS_OVERLOADED,q.STATUSES.SITE_IS_FROZEN,q.STATUSES.IDENTITY_PROVIDER_AUTHENTICATION_ERROR,q.STATUSES.NETWORK_READ_TIMEOUT,q.STATUSES.NETWORK_CONNECT_TIMEOUT];q.ALPHA=[];for(let e=65;e<=90;e++)q.ALPHA.push(String.fromCharCode(e)),q.ALPHA.push(String.fromCharCode(e+32));q.NUM_MAP={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9};q.HEX_MAP={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15};q.NUM=["0","1","2","3","4","5","6","7","8","9"];q.ALPHANUM=q.ALPHA.concat(q.NUM);q.MARK=["-","_",".","!","~","*","'","(",")"];q.USERINFO_CHARS=q.ALPHANUM.concat(q.MARK).concat(["%",";",":","&","=","+","$",","]);q.URL_CHAR=["!",'"',"$","%","&","'","(",")","*","+",",","-",".","/",":",";","<","=",">","@","[","\\","]","^","_","`","{","|","}","~"].concat(q.ALPHANUM);q.HEX=q.NUM.concat(["a","b","c","d","e","f","A","B","C","D","E","F"]);q.TOKEN=["!","#","$","%","&","'","*","+","-",".","^","_","`","|","~"].concat(q.ALPHANUM);q.HEADER_CHARS=[" "];for(let e=32;e<=255;e++)e!==127&&q.HEADER_CHARS.push(e);q.CONNECTION_TOKEN_CHARS=q.HEADER_CHARS.filter(e=>e!==44);q.QUOTED_STRING=[" "," "];for(let e=33;e<=255;e++)e!==34&&e!==92&&q.QUOTED_STRING.push(e);q.HTAB_SP_VCHAR_OBS_TEXT=[" "," "];for(let e=33;e<=126;e++)q.HTAB_SP_VCHAR_OBS_TEXT.push(e);for(let e=128;e<=255;e++)q.HTAB_SP_VCHAR_OBS_TEXT.push(e);q.MAJOR=q.NUM_MAP;q.MINOR=q.MAJOR;q.SPECIAL_HEADERS={connection:q.HEADER_STATE.CONNECTION,"content-length":q.HEADER_STATE.CONTENT_LENGTH,"proxy-connection":q.HEADER_STATE.CONNECTION,"transfer-encoding":q.HEADER_STATE.TRANSFER_ENCODING,upgrade:q.HEADER_STATE.UPGRADE};q.default={ERROR:q.ERROR,TYPE:q.TYPE,FLAGS:q.FLAGS,LENIENT_FLAGS:q.LENIENT_FLAGS,METHODS:q.METHODS,STATUSES:q.STATUSES,FINISH:q.FINISH,HEADER_STATE:q.HEADER_STATE,ALPHA:q.ALPHA,NUM_MAP:q.NUM_MAP,HEX_MAP:q.HEX_MAP,NUM:q.NUM,ALPHANUM:q.ALPHANUM,MARK:q.MARK,USERINFO_CHARS:q.USERINFO_CHARS,URL_CHAR:q.URL_CHAR,HEX:q.HEX,TOKEN:q.TOKEN,HEADER_CHARS:q.HEADER_CHARS,CONNECTION_TOKEN_CHARS:q.CONNECTION_TOKEN_CHARS,QUOTED_STRING:q.QUOTED_STRING,HTAB_SP_VCHAR_OBS_TEXT:q.HTAB_SP_VCHAR_OBS_TEXT,MAJOR:q.MAJOR,MINOR:q.MINOR,SPECIAL_HEADERS:q.SPECIAL_HEADERS,METHODS_HTTP:q.METHODS_HTTP,METHODS_ICE:q.METHODS_ICE,METHODS_RTSP:q.METHODS_RTSP,METHOD_MAP:q.METHOD_MAP,H_METHOD_MAP:q.H_METHOD_MAP,STATUSES_HTTP:q.STATUSES_HTTP}});var Qw=x((JTe,p3)=>{"use strict";var{Buffer:Hfe}=Gr(),qfe="AGFzbQEAAAABJwdgAX8Bf2ADf39/AX9gAn9/AGABfwBgBH9/f38Bf2AAAGADf39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQAEA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAAzU0BQYAAAMAAAAAAAADAQMAAwMDAAACAAAAAAICAgICAgICAgIBAQEBAQEBAQEBAwAAAwAAAAQFAXABExMFAwEAAgYIAX8BQcDZBAsHxQcoBm1lbW9yeQIAC19pbml0aWFsaXplAAgZX19pbmRpcmVjdF9mdW5jdGlvbl90YWJsZQEAC2xsaHR0cF9pbml0AAkYbGxodHRwX3Nob3VsZF9rZWVwX2FsaXZlADcMbGxodHRwX2FsbG9jAAsGbWFsbG9jADkLbGxodHRwX2ZyZWUADARmcmVlAAwPbGxodHRwX2dldF90eXBlAA0VbGxodHRwX2dldF9odHRwX21ham9yAA4VbGxodHRwX2dldF9odHRwX21pbm9yAA8RbGxodHRwX2dldF9tZXRob2QAEBZsbGh0dHBfZ2V0X3N0YXR1c19jb2RlABESbGxodHRwX2dldF91cGdyYWRlABIMbGxodHRwX3Jlc2V0ABMObGxodHRwX2V4ZWN1dGUAFBRsbGh0dHBfc2V0dGluZ3NfaW5pdAAVDWxsaHR0cF9maW5pc2gAFgxsbGh0dHBfcGF1c2UAFw1sbGh0dHBfcmVzdW1lABgbbGxodHRwX3Jlc3VtZV9hZnRlcl91cGdyYWRlABkQbGxodHRwX2dldF9lcnJubwAaF2xsaHR0cF9nZXRfZXJyb3JfcmVhc29uABsXbGxodHRwX3NldF9lcnJvcl9yZWFzb24AHBRsbGh0dHBfZ2V0X2Vycm9yX3BvcwAdEWxsaHR0cF9lcnJub19uYW1lAB4SbGxodHRwX21ldGhvZF9uYW1lAB8SbGxodHRwX3N0YXR1c19uYW1lACAabGxodHRwX3NldF9sZW5pZW50X2hlYWRlcnMAISFsbGh0dHBfc2V0X2xlbmllbnRfY2h1bmtlZF9sZW5ndGgAIh1sbGh0dHBfc2V0X2xlbmllbnRfa2VlcF9hbGl2ZQAjJGxsaHR0cF9zZXRfbGVuaWVudF90cmFuc2Zlcl9lbmNvZGluZwAkGmxsaHR0cF9zZXRfbGVuaWVudF92ZXJzaW9uACUjbGxodHRwX3NldF9sZW5pZW50X2RhdGFfYWZ0ZXJfY2xvc2UAJidsbGh0dHBfc2V0X2xlbmllbnRfb3B0aW9uYWxfbGZfYWZ0ZXJfY3IAJyxsbGh0dHBfc2V0X2xlbmllbnRfb3B0aW9uYWxfY3JsZl9hZnRlcl9jaHVuawAoKGxsaHR0cF9zZXRfbGVuaWVudF9vcHRpb25hbF9jcl9iZWZvcmVfbGYAKSpsbGh0dHBfc2V0X2xlbmllbnRfc3BhY2VzX2FmdGVyX2NodW5rX3NpemUAKhhsbGh0dHBfbWVzc2FnZV9uZWVkc19lb2YANgkYAQBBAQsSAQIDBAUKBgcyNDMuKy8tLDAxCq/ZAjQWAEHA1QAoAgAEQAALQcDVAEEBNgIACxQAIAAQOCAAIAI2AjggACABOgAoCxQAIAAgAC8BNCAALQAwIAAQNxAACx4BAX9BwAAQOiIBEDggAUGACDYCOCABIAA6ACggAQuPDAEHfwJAIABFDQAgAEEIayIBIABBBGsoAgAiAEF4cSIEaiEFAkAgAEEBcQ0AIABBA3FFDQEgASABKAIAIgBrIgFB1NUAKAIASQ0BIAAgBGohBAJAAkBB2NUAKAIAIAFHBEAgAEH/AU0EQCAAQQN2IQMgASgCCCIAIAEoAgwiAkYEQEHE1QBBxNUAKAIAQX4gA3dxNgIADAULIAIgADYCCCAAIAI2AgwMBAsgASgCGCEGIAEgASgCDCIARwRAIAAgASgCCCICNgIIIAIgADYCDAwDCyABQRRqIgMoAgAiAkUEQCABKAIQIgJFDQIgAUEQaiEDCwNAIAMhByACIgBBFGoiAygCACICDQAgAEEQaiEDIAAoAhAiAg0ACyAHQQA2AgAMAgsgBSgCBCIAQQNxQQNHDQIgBSAAQX5xNgIEQczVACAENgIAIAUgBDYCACABIARBAXI2AgQMAwtBACEACyAGRQ0AAkAgASgCHCICQQJ0QfTXAGoiAygCACABRgRAIAMgADYCACAADQFByNUAQcjVACgCAEF+IAJ3cTYCAAwCCyAGQRBBFCAGKAIQIAFGG2ogADYCACAARQ0BCyAAIAY2AhggASgCECICBEAgACACNgIQIAIgADYCGAsgAUEUaigCACICRQ0AIABBFGogAjYCACACIAA2AhgLIAEgBU8NACAFKAIEIgBBAXFFDQACQAJAAkACQCAAQQJxRQRAQdzVACgCACAFRgRAQdzVACABNgIAQdDVAEHQ1QAoAgAgBGoiADYCACABIABBAXI2AgQgAUHY1QAoAgBHDQZBzNUAQQA2AgBB2NUAQQA2AgAMBgtB2NUAKAIAIAVGBEBB2NUAIAE2AgBBzNUAQczVACgCACAEaiIANgIAIAEgAEEBcjYCBCAAIAFqIAA2AgAMBgsgAEF4cSAEaiEEIABB/wFNBEAgAEEDdiEDIAUoAggiACAFKAIMIgJGBEBBxNUAQcTVACgCAEF+IAN3cTYCAAwFCyACIAA2AgggACACNgIMDAQLIAUoAhghBiAFIAUoAgwiAEcEQEHU1QAoAgAaIAAgBSgCCCICNgIIIAIgADYCDAwDCyAFQRRqIgMoAgAiAkUEQCAFKAIQIgJFDQIgBUEQaiEDCwNAIAMhByACIgBBFGoiAygCACICDQAgAEEQaiEDIAAoAhAiAg0ACyAHQQA2AgAMAgsgBSAAQX5xNgIEIAEgBGogBDYCACABIARBAXI2AgQMAwtBACEACyAGRQ0AAkAgBSgCHCICQQJ0QfTXAGoiAygCACAFRgRAIAMgADYCACAADQFByNUAQcjVACgCAEF+IAJ3cTYCAAwCCyAGQRBBFCAGKAIQIAVGG2ogADYCACAARQ0BCyAAIAY2AhggBSgCECICBEAgACACNgIQIAIgADYCGAsgBUEUaigCACICRQ0AIABBFGogAjYCACACIAA2AhgLIAEgBGogBDYCACABIARBAXI2AgQgAUHY1QAoAgBHDQBBzNUAIAQ2AgAMAQsgBEH/AU0EQCAEQXhxQezVAGohAAJ/QcTVACgCACICQQEgBEEDdnQiA3FFBEBBxNUAIAIgA3I2AgAgAAwBCyAAKAIICyICIAE2AgwgACABNgIIIAEgADYCDCABIAI2AggMAQtBHyECIARB////B00EQCAEQSYgBEEIdmciAGt2QQFxIABBAXRrQT5qIQILIAEgAjYCHCABQgA3AhAgAkECdEH01wBqIQACQEHI1QAoAgAiA0EBIAJ0IgdxRQRAIAAgATYCAEHI1QAgAyAHcjYCACABIAA2AhggASABNgIIIAEgATYCDAwBCyAEQRkgAkEBdmtBACACQR9HG3QhAiAAKAIAIQACQANAIAAiAygCBEF4cSAERg0BIAJBHXYhACACQQF0IQIgAyAAQQRxakEQaiIHKAIAIgANAAsgByABNgIAIAEgAzYCGCABIAE2AgwgASABNgIIDAELIAMoAggiACABNgIMIAMgATYCCCABQQA2AhggASADNgIMIAEgADYCCAtB5NUAQeTVACgCAEEBayIAQX8gABs2AgALCwcAIAAtACgLBwAgAC0AKgsHACAALQArCwcAIAAtACkLBwAgAC8BNAsHACAALQAwC0ABBH8gACgCGCEBIAAvAS4hAiAALQAoIQMgACgCOCEEIAAQOCAAIAQ2AjggACADOgAoIAAgAjsBLiAAIAE2AhgL5YUCAgd/A34gASACaiEEAkAgACIDKAIMIgANACADKAIEBEAgAyABNgIECyMAQRBrIgkkAAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAygCHCICQQJrDvwBAfkBAgMEBQYHCAkKCwwNDg8QERL4ARP3ARQV9gEWF/UBGBkaGxwdHh8g/QH7ASH0ASIjJCUmJygpKivzASwtLi8wMTLyAfEBMzTwAe8BNTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5P+gFQUVJT7gHtAVTsAVXrAVZXWFla6gFbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHpAegBzwHnAdAB5gHRAdIB0wHUAeUB1QHWAdcB2AHZAdoB2wHcAd0B3gHfAeAB4QHiAeMBAPwBC0EADOMBC0EODOIBC0ENDOEBC0EPDOABC0EQDN8BC0ETDN4BC0EUDN0BC0EVDNwBC0EWDNsBC0EXDNoBC0EYDNkBC0EZDNgBC0EaDNcBC0EbDNYBC0EcDNUBC0EdDNQBC0EeDNMBC0EfDNIBC0EgDNEBC0EhDNABC0EIDM8BC0EiDM4BC0EkDM0BC0EjDMwBC0EHDMsBC0ElDMoBC0EmDMkBC0EnDMgBC0EoDMcBC0ESDMYBC0ERDMUBC0EpDMQBC0EqDMMBC0ErDMIBC0EsDMEBC0HeAQzAAQtBLgy/AQtBLwy+AQtBMAy9AQtBMQy8AQtBMgy7AQtBMwy6AQtBNAy5AQtB3wEMuAELQTUMtwELQTkMtgELQQwMtQELQTYMtAELQTcMswELQTgMsgELQT4MsQELQToMsAELQeABDK8BC0ELDK4BC0E/DK0BC0E7DKwBC0EKDKsBC0E8DKoBC0E9DKkBC0HhAQyoAQtBwQAMpwELQcAADKYBC0HCAAylAQtBCQykAQtBLQyjAQtBwwAMogELQcQADKEBC0HFAAygAQtBxgAMnwELQccADJ4BC0HIAAydAQtByQAMnAELQcoADJsBC0HLAAyaAQtBzAAMmQELQc0ADJgBC0HOAAyXAQtBzwAMlgELQdAADJUBC0HRAAyUAQtB0gAMkwELQdMADJIBC0HVAAyRAQtB1AAMkAELQdYADI8BC0HXAAyOAQtB2AAMjQELQdkADIwBC0HaAAyLAQtB2wAMigELQdwADIkBC0HdAAyIAQtB3gAMhwELQd8ADIYBC0HgAAyFAQtB4QAMhAELQeIADIMBC0HjAAyCAQtB5AAMgQELQeUADIABC0HiAQx/C0HmAAx+C0HnAAx9C0EGDHwLQegADHsLQQUMegtB6QAMeQtBBAx4C0HqAAx3C0HrAAx2C0HsAAx1C0HtAAx0C0EDDHMLQe4ADHILQe8ADHELQfAADHALQfIADG8LQfEADG4LQfMADG0LQfQADGwLQfUADGsLQfYADGoLQQIMaQtB9wAMaAtB+AAMZwtB+QAMZgtB+gAMZQtB+wAMZAtB/AAMYwtB/QAMYgtB/gAMYQtB/wAMYAtBgAEMXwtBgQEMXgtBggEMXQtBgwEMXAtBhAEMWwtBhQEMWgtBhgEMWQtBhwEMWAtBiAEMVwtBiQEMVgtBigEMVQtBiwEMVAtBjAEMUwtBjQEMUgtBjgEMUQtBjwEMUAtBkAEMTwtBkQEMTgtBkgEMTQtBkwEMTAtBlAEMSwtBlQEMSgtBlgEMSQtBlwEMSAtBmAEMRwtBmQEMRgtBmgEMRQtBmwEMRAtBnAEMQwtBnQEMQgtBngEMQQtBnwEMQAtBoAEMPwtBoQEMPgtBogEMPQtBowEMPAtBpAEMOwtBpQEMOgtBpgEMOQtBpwEMOAtBqAEMNwtBqQEMNgtBqgEMNQtBqwEMNAtBrAEMMwtBrQEMMgtBrgEMMQtBrwEMMAtBsAEMLwtBsQEMLgtBsgEMLQtBswEMLAtBtAEMKwtBtQEMKgtBtgEMKQtBtwEMKAtBuAEMJwtBuQEMJgtBugEMJQtBuwEMJAtBvAEMIwtBvQEMIgtBvgEMIQtBvwEMIAtBwAEMHwtBwQEMHgtBwgEMHQtBAQwcC0HDAQwbC0HEAQwaC0HFAQwZC0HGAQwYC0HHAQwXC0HIAQwWC0HJAQwVC0HKAQwUC0HLAQwTC0HMAQwSC0HNAQwRC0HOAQwQC0HPAQwPC0HQAQwOC0HRAQwNC0HSAQwMC0HTAQwLC0HUAQwKC0HVAQwJC0HWAQwIC0HjAQwHC0HXAQwGC0HYAQwFC0HZAQwEC0HaAQwDC0HbAQwCC0HdAQwBC0HcAQshAgNAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAn8CQAJAAkACQAJAAkACQAJ/AkACQAJAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAMCfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAg7jAQABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEjJCUnKCmeA5sDmgORA4oDgwOAA/0C+wL4AvIC8QLvAu0C6ALnAuYC5QLkAtwC2wLaAtkC2ALXAtYC1QLPAs4CzALLAsoCyQLIAscCxgLEAsMCvgK8AroCuQK4ArcCtgK1ArQCswKyArECsAKuAq0CqQKoAqcCpgKlAqQCowKiAqECoAKfApgCkAKMAosCigKBAv4B/QH8AfsB+gH5AfgB9wH1AfMB8AHrAekB6AHnAeYB5QHkAeMB4gHhAeAB3wHeAd0B3AHaAdkB2AHXAdYB1QHUAdMB0gHRAdABzwHOAc0BzAHLAcoByQHIAccBxgHFAcQBwwHCAcEBwAG/Ab4BvQG8AbsBugG5AbgBtwG2AbUBtAGzAbIBsQGwAa8BrgGtAawBqwGqAakBqAGnAaYBpQGkAaMBogGfAZ4BmQGYAZcBlgGVAZQBkwGSAZEBkAGPAY0BjAGHAYYBhQGEAYMBggF9fHt6eXZ1dFBRUlNUVQsgASAERw1yQf0BIQIMvgMLIAEgBEcNmAFB2wEhAgy9AwsgASAERw3xAUGOASECDLwDCyABIARHDfwBQYQBIQIMuwMLIAEgBEcNigJB/wAhAgy6AwsgASAERw2RAkH9ACECDLkDCyABIARHDZQCQfsAIQIMuAMLIAEgBEcNHkEeIQIMtwMLIAEgBEcNGUEYIQIMtgMLIAEgBEcNygJBzQAhAgy1AwsgASAERw3VAkHGACECDLQDCyABIARHDdYCQcMAIQIMswMLIAEgBEcN3AJBOCECDLIDCyADLQAwQQFGDa0DDIkDC0EAIQACQAJAAkAgAy0AKkUNACADLQArRQ0AIAMvATIiAkECcUUNAQwCCyADLwEyIgJBAXFFDQELQQEhACADLQAoQQFGDQAgAy8BNCIGQeQAa0HkAEkNACAGQcwBRg0AIAZBsAJGDQAgAkHAAHENAEEAIQAgAkGIBHFBgARGDQAgAkEocUEARyEACyADQQA7ATIgA0EAOgAxAkAgAEUEQCADQQA6ADEgAy0ALkEEcQ0BDLEDCyADQgA3AyALIANBADoAMSADQQE6ADYMSAtBACEAAkAgAygCOCICRQ0AIAIoAjAiAkUNACADIAIRAAAhAAsgAEUNSCAAQRVHDWIgA0EENgIcIAMgATYCFCADQdIbNgIQIANBFTYCDEEAIQIMrwMLIAEgBEYEQEEGIQIMrwMLIAEtAABBCkcNGSABQQFqIQEMGgsgA0IANwMgQRIhAgyUAwsgASAERw2KA0EjIQIMrAMLIAEgBEYEQEEHIQIMrAMLAkACQCABLQAAQQprDgQBGBgAGAsgAUEBaiEBQRAhAgyTAwsgAUEBaiEBIANBL2otAABBAXENF0EAIQIgA0EANgIcIAMgATYCFCADQZkgNgIQIANBGTYCDAyrAwsgAyADKQMgIgwgBCABa60iCn0iC0IAIAsgDFgbNwMgIAogDFoNGEEIIQIMqgMLIAEgBEcEQCADQQk2AgggAyABNgIEQRQhAgyRAwtBCSECDKkDCyADKQMgUA2uAgxDCyABIARGBEBBCyECDKgDCyABLQAAQQpHDRYgAUEBaiEBDBcLIANBL2otAABBAXFFDRkMJgtBACEAAkAgAygCOCICRQ0AIAIoAlAiAkUNACADIAIRAAAhAAsgAA0ZDEILQQAhAAJAIAMoAjgiAkUNACACKAJQIgJFDQAgAyACEQAAIQALIAANGgwkC0EAIQACQCADKAI4IgJFDQAgAigCUCICRQ0AIAMgAhEAACEACyAADRsMMgsgA0Evai0AAEEBcUUNHAwiC0EAIQACQCADKAI4IgJFDQAgAigCVCICRQ0AIAMgAhEAACEACyAADRwMQgtBACEAAkAgAygCOCICRQ0AIAIoAlQiAkUNACADIAIRAAAhAAsgAA0dDCALIAEgBEYEQEETIQIMoAMLAkAgAS0AACIAQQprDgQfIyMAIgsgAUEBaiEBDB8LQQAhAAJAIAMoAjgiAkUNACACKAJUIgJFDQAgAyACEQAAIQALIAANIgxCCyABIARGBEBBFiECDJ4DCyABLQAAQcDBAGotAABBAUcNIwyDAwsCQANAIAEtAABBsDtqLQAAIgBBAUcEQAJAIABBAmsOAgMAJwsgAUEBaiEBQSEhAgyGAwsgBCABQQFqIgFHDQALQRghAgydAwsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAFBAWoiARA0IgANIQxBC0EAIQACQCADKAI4IgJFDQAgAigCVCICRQ0AIAMgAhEAACEACyAADSMMKgsgASAERgRAQRwhAgybAwsgA0EKNgIIIAMgATYCBEEAIQACQCADKAI4IgJFDQAgAigCUCICRQ0AIAMgAhEAACEACyAADSVBJCECDIEDCyABIARHBEADQCABLQAAQbA9ai0AACIAQQNHBEAgAEEBaw4FGBomggMlJgsgBCABQQFqIgFHDQALQRshAgyaAwtBGyECDJkDCwNAIAEtAABBsD9qLQAAIgBBA0cEQCAAQQFrDgUPEScTJicLIAQgAUEBaiIBRw0AC0EeIQIMmAMLIAEgBEcEQCADQQs2AgggAyABNgIEQQchAgz/AgtBHyECDJcDCyABIARGBEBBICECDJcDCwJAIAEtAABBDWsOFC4/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8APwtBACECIANBADYCHCADQb8LNgIQIANBAjYCDCADIAFBAWo2AhQMlgMLIANBL2ohAgNAIAEgBEYEQEEhIQIMlwMLAkACQAJAIAEtAAAiAEEJaw4YAgApKQEpKSkpKSkpKSkpKSkpKSkpKSkCJwsgAUEBaiEBIANBL2otAABBAXFFDQoMGAsgAUEBaiEBDBcLIAFBAWohASACLQAAQQJxDQALQQAhAiADQQA2AhwgAyABNgIUIANBnxU2AhAgA0EMNgIMDJUDCyADLQAuQYABcUUNAQtBACEAAkAgAygCOCICRQ0AIAIoAlwiAkUNACADIAIRAAAhAAsgAEUN5gIgAEEVRgRAIANBJDYCHCADIAE2AhQgA0GbGzYCECADQRU2AgxBACECDJQDC0EAIQIgA0EANgIcIAMgATYCFCADQZAONgIQIANBFDYCDAyTAwtBACECIANBADYCHCADIAE2AhQgA0G+IDYCECADQQI2AgwMkgMLIAMoAgQhAEEAIQIgA0EANgIEIAMgACABIAynaiIBEDIiAEUNKyADQQc2AhwgAyABNgIUIAMgADYCDAyRAwsgAy0ALkHAAHFFDQELQQAhAAJAIAMoAjgiAkUNACACKAJYIgJFDQAgAyACEQAAIQALIABFDSsgAEEVRgRAIANBCjYCHCADIAE2AhQgA0HrGTYCECADQRU2AgxBACECDJADC0EAIQIgA0EANgIcIAMgATYCFCADQZMMNgIQIANBEzYCDAyPAwtBACECIANBADYCHCADIAE2AhQgA0GCFTYCECADQQI2AgwMjgMLQQAhAiADQQA2AhwgAyABNgIUIANB3RQ2AhAgA0EZNgIMDI0DC0EAIQIgA0EANgIcIAMgATYCFCADQeYdNgIQIANBGTYCDAyMAwsgAEEVRg09QQAhAiADQQA2AhwgAyABNgIUIANB0A82AhAgA0EiNgIMDIsDCyADKAIEIQBBACECIANBADYCBCADIAAgARAzIgBFDSggA0ENNgIcIAMgATYCFCADIAA2AgwMigMLIABBFUYNOkEAIQIgA0EANgIcIAMgATYCFCADQdAPNgIQIANBIjYCDAyJAwsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQMyIARQRAIAFBAWohAQwoCyADQQ42AhwgAyAANgIMIAMgAUEBajYCFAyIAwsgAEEVRg03QQAhAiADQQA2AhwgAyABNgIUIANB0A82AhAgA0EiNgIMDIcDCyADKAIEIQBBACECIANBADYCBCADIAAgARAzIgBFBEAgAUEBaiEBDCcLIANBDzYCHCADIAA2AgwgAyABQQFqNgIUDIYDC0EAIQIgA0EANgIcIAMgATYCFCADQeIXNgIQIANBGTYCDAyFAwsgAEEVRg0zQQAhAiADQQA2AhwgAyABNgIUIANB1gw2AhAgA0EjNgIMDIQDCyADKAIEIQBBACECIANBADYCBCADIAAgARA0IgBFDSUgA0ERNgIcIAMgATYCFCADIAA2AgwMgwMLIABBFUYNMEEAIQIgA0EANgIcIAMgATYCFCADQdYMNgIQIANBIzYCDAyCAwsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQwlCyADQRI2AhwgAyAANgIMIAMgAUEBajYCFAyBAwsgA0Evai0AAEEBcUUNAQtBFyECDOYCC0EAIQIgA0EANgIcIAMgATYCFCADQeIXNgIQIANBGTYCDAz+AgsgAEE7Rw0AIAFBAWohAQwMC0EAIQIgA0EANgIcIAMgATYCFCADQZIYNgIQIANBAjYCDAz8AgsgAEEVRg0oQQAhAiADQQA2AhwgAyABNgIUIANB1gw2AhAgA0EjNgIMDPsCCyADQRQ2AhwgAyABNgIUIAMgADYCDAz6AgsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQz1AgsgA0EVNgIcIAMgADYCDCADIAFBAWo2AhQM+QILIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDQiAEUEQCABQQFqIQEM8wILIANBFzYCHCADIAA2AgwgAyABQQFqNgIUDPgCCyAAQRVGDSNBACECIANBADYCHCADIAE2AhQgA0HWDDYCECADQSM2AgwM9wILIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDQiAEUEQCABQQFqIQEMHQsgA0EZNgIcIAMgADYCDCADIAFBAWo2AhQM9gILIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDQiAEUEQCABQQFqIQEM7wILIANBGjYCHCADIAA2AgwgAyABQQFqNgIUDPUCCyAAQRVGDR9BACECIANBADYCHCADIAE2AhQgA0HQDzYCECADQSI2AgwM9AILIAMoAgQhACADQQA2AgQgAyAAIAEQMyIARQRAIAFBAWohAQwbCyADQRw2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIM8wILIAMoAgQhACADQQA2AgQgAyAAIAEQMyIARQRAIAFBAWohAQzrAgsgA0EdNgIcIAMgADYCDCADIAFBAWo2AhRBACECDPICCyAAQTtHDQEgAUEBaiEBC0EmIQIM1wILQQAhAiADQQA2AhwgAyABNgIUIANBnxU2AhAgA0EMNgIMDO8CCyABIARHBEADQCABLQAAQSBHDYQCIAQgAUEBaiIBRw0AC0EsIQIM7wILQSwhAgzuAgsgASAERgRAQTQhAgzuAgsCQAJAA0ACQCABLQAAQQprDgQCAAADAAsgBCABQQFqIgFHDQALQTQhAgzvAgsgAygCBCEAIANBADYCBCADIAAgARAxIgBFDZ8CIANBMjYCHCADIAE2AhQgAyAANgIMQQAhAgzuAgsgAygCBCEAIANBADYCBCADIAAgARAxIgBFBEAgAUEBaiEBDJ8CCyADQTI2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIM7QILIAEgBEcEQAJAA0AgAS0AAEEwayIAQf8BcUEKTwRAQTohAgzXAgsgAykDICILQpmz5syZs+bMGVYNASADIAtCCn4iCjcDICAKIACtQv8BgyILQn+FVg0BIAMgCiALfDcDICAEIAFBAWoiAUcNAAtBwAAhAgzuAgsgAygCBCEAIANBADYCBCADIAAgAUEBaiIBEDEiAA0XDOICC0HAACECDOwCCyABIARGBEBByQAhAgzsAgsCQANAAkAgAS0AAEEJaw4YAAKiAqICqQKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogIAogILIAQgAUEBaiIBRw0AC0HJACECDOwCCyABQQFqIQEgA0Evai0AAEEBcQ2lAiADQQA2AhwgAyABNgIUIANBlxA2AhAgA0EKNgIMQQAhAgzrAgsgASAERwRAA0AgAS0AAEEgRw0VIAQgAUEBaiIBRw0AC0H4ACECDOsCC0H4ACECDOoCCyADQQI6ACgMOAtBACECIANBADYCHCADQb8LNgIQIANBAjYCDCADIAFBAWo2AhQM6AILQQAhAgzOAgtBDSECDM0CC0ETIQIMzAILQRUhAgzLAgtBFiECDMoCC0EYIQIMyQILQRkhAgzIAgtBGiECDMcCC0EbIQIMxgILQRwhAgzFAgtBHSECDMQCC0EeIQIMwwILQR8hAgzCAgtBICECDMECC0EiIQIMwAILQSMhAgy/AgtBJSECDL4CC0HlACECDL0CCyADQT02AhwgAyABNgIUIAMgADYCDEEAIQIM1QILIANBGzYCHCADIAE2AhQgA0GkHDYCECADQRU2AgxBACECDNQCCyADQSA2AhwgAyABNgIUIANBmBo2AhAgA0EVNgIMQQAhAgzTAgsgA0ETNgIcIAMgATYCFCADQZgaNgIQIANBFTYCDEEAIQIM0gILIANBCzYCHCADIAE2AhQgA0GYGjYCECADQRU2AgxBACECDNECCyADQRA2AhwgAyABNgIUIANBmBo2AhAgA0EVNgIMQQAhAgzQAgsgA0EgNgIcIAMgATYCFCADQaQcNgIQIANBFTYCDEEAIQIMzwILIANBCzYCHCADIAE2AhQgA0GkHDYCECADQRU2AgxBACECDM4CCyADQQw2AhwgAyABNgIUIANBpBw2AhAgA0EVNgIMQQAhAgzNAgtBACECIANBADYCHCADIAE2AhQgA0HdDjYCECADQRI2AgwMzAILAkADQAJAIAEtAABBCmsOBAACAgACCyAEIAFBAWoiAUcNAAtB/QEhAgzMAgsCQAJAIAMtADZBAUcNAEEAIQACQCADKAI4IgJFDQAgAigCYCICRQ0AIAMgAhEAACEACyAARQ0AIABBFUcNASADQfwBNgIcIAMgATYCFCADQdwZNgIQIANBFTYCDEEAIQIMzQILQdwBIQIMswILIANBADYCHCADIAE2AhQgA0H5CzYCECADQR82AgxBACECDMsCCwJAAkAgAy0AKEEBaw4CBAEAC0HbASECDLICC0HUASECDLECCyADQQI6ADFBACEAAkAgAygCOCICRQ0AIAIoAgAiAkUNACADIAIRAAAhAAsgAEUEQEHdASECDLECCyAAQRVHBEAgA0EANgIcIAMgATYCFCADQbQMNgIQIANBEDYCDEEAIQIMygILIANB+wE2AhwgAyABNgIUIANBgRo2AhAgA0EVNgIMQQAhAgzJAgsgASAERgRAQfoBIQIMyQILIAEtAABByABGDQEgA0EBOgAoC0HAASECDK4CC0HaASECDK0CCyABIARHBEAgA0EMNgIIIAMgATYCBEHZASECDK0CC0H5ASECDMUCCyABIARGBEBB+AEhAgzFAgsgAS0AAEHIAEcNBCABQQFqIQFB2AEhAgyrAgsgASAERgRAQfcBIQIMxAILAkACQCABLQAAQcUAaw4QAAUFBQUFBQUFBQUFBQUFAQULIAFBAWohAUHWASECDKsCCyABQQFqIQFB1wEhAgyqAgtB9gEhAiABIARGDcICIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQbrVAGotAABHDQMgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADMMCCyADKAIEIQAgA0IANwMAIAMgACAGQQFqIgEQLiIARQRAQeMBIQIMqgILIANB9QE2AhwgAyABNgIUIAMgADYCDEEAIQIMwgILQfQBIQIgASAERg3BAiADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEG41QBqLQAARw0CIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzCAgsgA0GBBDsBKCADKAIEIQAgA0IANwMAIAMgACAGQQFqIgEQLiIADQMMAgsgA0EANgIAC0EAIQIgA0EANgIcIAMgATYCFCADQeUfNgIQIANBCDYCDAy/AgtB1QEhAgylAgsgA0HzATYCHCADIAE2AhQgAyAANgIMQQAhAgy9AgtBACEAAkAgAygCOCICRQ0AIAIoAkAiAkUNACADIAIRAAAhAAsgAEUNbiAAQRVHBEAgA0EANgIcIAMgATYCFCADQYIPNgIQIANBIDYCDEEAIQIMvQILIANBjwE2AhwgAyABNgIUIANB7Bs2AhAgA0EVNgIMQQAhAgy8AgsgASAERwRAIANBDTYCCCADIAE2AgRB0wEhAgyjAgtB8gEhAgy7AgsgASAERgRAQfEBIQIMuwILAkACQAJAIAEtAABByABrDgsAAQgICAgICAgIAggLIAFBAWohAUHQASECDKMCCyABQQFqIQFB0QEhAgyiAgsgAUEBaiEBQdIBIQIMoQILQfABIQIgASAERg25AiADKAIAIgAgBCABa2ohBiABIABrQQJqIQUDQCABLQAAIABBtdUAai0AAEcNBCAAQQJGDQMgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAY2AgAMuQILQe8BIQIgASAERg24AiADKAIAIgAgBCABa2ohBiABIABrQQFqIQUDQCABLQAAIABBs9UAai0AAEcNAyAAQQFGDQIgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAY2AgAMuAILQe4BIQIgASAERg23AiADKAIAIgAgBCABa2ohBiABIABrQQJqIQUDQCABLQAAIABBsNUAai0AAEcNAiAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAY2AgAMtwILIAMoAgQhACADQgA3AwAgAyAAIAVBAWoiARArIgBFDQIgA0HsATYCHCADIAE2AhQgAyAANgIMQQAhAgy2AgsgA0EANgIACyADKAIEIQAgA0EANgIEIAMgACABECsiAEUNnAIgA0HtATYCHCADIAE2AhQgAyAANgIMQQAhAgy0AgtBzwEhAgyaAgtBACEAAkAgAygCOCICRQ0AIAIoAjQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0HqDTYCECADQSY2AgxBACECDLQCC0HOASECDJoCCyADQesBNgIcIAMgATYCFCADQYAbNgIQIANBFTYCDEEAIQIMsgILIAEgBEYEQEHrASECDLICCyABLQAAQS9GBEAgAUEBaiEBDAELIANBADYCHCADIAE2AhQgA0GyODYCECADQQg2AgxBACECDLECC0HNASECDJcCCyABIARHBEAgA0EONgIIIAMgATYCBEHMASECDJcCC0HqASECDK8CCyABIARGBEBB6QEhAgyvAgsgAS0AAEEwayIAQf8BcUEKSQRAIAMgADoAKiABQQFqIQFBywEhAgyWAgsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDZcCIANB6AE2AhwgAyABNgIUIAMgADYCDEEAIQIMrgILIAEgBEYEQEHnASECDK4CCwJAIAEtAABBLkYEQCABQQFqIQEMAQsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDZgCIANB5gE2AhwgAyABNgIUIAMgADYCDEEAIQIMrgILQcoBIQIMlAILIAEgBEYEQEHlASECDK0CC0EAIQBBASEFQQEhB0EAIQICQAJAAkACQAJAAn8CQAJAAkACQAJAAkACQCABLQAAQTBrDgoKCQABAgMEBQYICwtBAgwGC0EDDAULQQQMBAtBBQwDC0EGDAILQQcMAQtBCAshAkEAIQVBACEHDAILQQkhAkEBIQBBACEFQQAhBwwBC0EAIQVBASECCyADIAI6ACsgAUEBaiEBAkACQCADLQAuQRBxDQACQAJAAkAgAy0AKg4DAQACBAsgB0UNAwwCCyAADQEMAgsgBUUNAQsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDQIgA0HiATYCHCADIAE2AhQgAyAANgIMQQAhAgyvAgsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDZoCIANB4wE2AhwgAyABNgIUIAMgADYCDEEAIQIMrgILIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ2YAiADQeQBNgIcIAMgATYCFCADIAA2AgwMrQILQckBIQIMkwILQQAhAAJAIAMoAjgiAkUNACACKAJEIgJFDQAgAyACEQAAIQALAkAgAARAIABBFUYNASADQQA2AhwgAyABNgIUIANBpA02AhAgA0EhNgIMQQAhAgytAgtByAEhAgyTAgsgA0HhATYCHCADIAE2AhQgA0HQGjYCECADQRU2AgxBACECDKsCCyABIARGBEBB4QEhAgyrAgsCQCABLQAAQSBGBEAgA0EAOwE0IAFBAWohAQwBCyADQQA2AhwgAyABNgIUIANBmRE2AhAgA0EJNgIMQQAhAgyrAgtBxwEhAgyRAgsgASAERgRAQeABIQIMqgILAkAgAS0AAEEwa0H/AXEiAkEKSQRAIAFBAWohAQJAIAMvATQiAEGZM0sNACADIABBCmwiADsBNCAAQf7/A3EgAkH//wNzSw0AIAMgACACajsBNAwCC0EAIQIgA0EANgIcIAMgATYCFCADQZUeNgIQIANBDTYCDAyrAgsgA0EANgIcIAMgATYCFCADQZUeNgIQIANBDTYCDEEAIQIMqgILQcYBIQIMkAILIAEgBEYEQEHfASECDKkCCwJAIAEtAABBMGtB/wFxIgJBCkkEQCABQQFqIQECQCADLwE0IgBBmTNLDQAgAyAAQQpsIgA7ATQgAEH+/wNxIAJB//8Dc0sNACADIAAgAmo7ATQMAgtBACECIANBADYCHCADIAE2AhQgA0GVHjYCECADQQ02AgwMqgILIANBADYCHCADIAE2AhQgA0GVHjYCECADQQ02AgxBACECDKkCC0HFASECDI8CCyABIARGBEBB3gEhAgyoAgsCQCABLQAAQTBrQf8BcSICQQpJBEAgAUEBaiEBAkAgAy8BNCIAQZkzSw0AIAMgAEEKbCIAOwE0IABB/v8DcSACQf//A3NLDQAgAyAAIAJqOwE0DAILQQAhAiADQQA2AhwgAyABNgIUIANBlR42AhAgA0ENNgIMDKkCCyADQQA2AhwgAyABNgIUIANBlR42AhAgA0ENNgIMQQAhAgyoAgtBxAEhAgyOAgsgASAERgRAQd0BIQIMpwILAkACQAJAAkAgAS0AAEEKaw4XAgMDAAMDAwMDAwMDAwMDAwMDAwMDAwEDCyABQQFqDAULIAFBAWohAUHDASECDI8CCyABQQFqIQEgA0Evai0AAEEBcQ0IIANBADYCHCADIAE2AhQgA0GNCzYCECADQQ02AgxBACECDKcCCyADQQA2AhwgAyABNgIUIANBjQs2AhAgA0ENNgIMQQAhAgymAgsgASAERwRAIANBDzYCCCADIAE2AgRBASECDI0CC0HcASECDKUCCwJAAkADQAJAIAEtAABBCmsOBAIAAAMACyAEIAFBAWoiAUcNAAtB2wEhAgymAgsgAygCBCEAIANBADYCBCADIAAgARAtIgBFBEAgAUEBaiEBDAQLIANB2gE2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMpQILIAMoAgQhACADQQA2AgQgAyAAIAEQLSIADQEgAUEBagshAUHBASECDIoCCyADQdkBNgIcIAMgADYCDCADIAFBAWo2AhRBACECDKICC0HCASECDIgCCyADQS9qLQAAQQFxDQEgA0EANgIcIAMgATYCFCADQeQcNgIQIANBGTYCDEEAIQIMoAILIAEgBEYEQEHZASECDKACCwJAAkACQCABLQAAQQprDgQBAgIAAgsgAUEBaiEBDAILIAFBAWohAQwBCyADLQAuQcAAcUUNAQtBACEAAkAgAygCOCICRQ0AIAIoAjwiAkUNACADIAIRAAAhAAsgAEUNoAEgAEEVRgRAIANB2QA2AhwgAyABNgIUIANBtxo2AhAgA0EVNgIMQQAhAgyfAgsgA0EANgIcIAMgATYCFCADQYANNgIQIANBGzYCDEEAIQIMngILIANBADYCHCADIAE2AhQgA0HcKDYCECADQQI2AgxBACECDJ0CCyABIARHBEAgA0EMNgIIIAMgATYCBEG/ASECDIQCC0HYASECDJwCCyABIARGBEBB1wEhAgycAgsCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAEtAABBwQBrDhUAAQIDWgQFBlpaWgcICQoLDA0ODxBaCyABQQFqIQFB+wAhAgySAgsgAUEBaiEBQfwAIQIMkQILIAFBAWohAUGBASECDJACCyABQQFqIQFBhQEhAgyPAgsgAUEBaiEBQYYBIQIMjgILIAFBAWohAUGJASECDI0CCyABQQFqIQFBigEhAgyMAgsgAUEBaiEBQY0BIQIMiwILIAFBAWohAUGWASECDIoCCyABQQFqIQFBlwEhAgyJAgsgAUEBaiEBQZgBIQIMiAILIAFBAWohAUGlASECDIcCCyABQQFqIQFBpgEhAgyGAgsgAUEBaiEBQawBIQIMhQILIAFBAWohAUG0ASECDIQCCyABQQFqIQFBtwEhAgyDAgsgAUEBaiEBQb4BIQIMggILIAEgBEYEQEHWASECDJsCCyABLQAAQc4ARw1IIAFBAWohAUG9ASECDIECCyABIARGBEBB1QEhAgyaAgsCQAJAAkAgAS0AAEHCAGsOEgBKSkpKSkpKSkoBSkpKSkpKAkoLIAFBAWohAUG4ASECDIICCyABQQFqIQFBuwEhAgyBAgsgAUEBaiEBQbwBIQIMgAILQdQBIQIgASAERg2YAiADKAIAIgAgBCABa2ohBSABIABrQQdqIQYCQANAIAEtAAAgAEGo1QBqLQAARw1FIABBB0YNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyZAgsgA0EANgIAIAZBAWohAUEbDEULIAEgBEYEQEHTASECDJgCCwJAAkAgAS0AAEHJAGsOBwBHR0dHRwFHCyABQQFqIQFBuQEhAgz/AQsgAUEBaiEBQboBIQIM/gELQdIBIQIgASAERg2WAiADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGm1QBqLQAARw1DIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyXAgsgA0EANgIAIAZBAWohAUEPDEMLQdEBIQIgASAERg2VAiADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGk1QBqLQAARw1CIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyWAgsgA0EANgIAIAZBAWohAUEgDEILQdABIQIgASAERg2UAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGh1QBqLQAARw1BIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyVAgsgA0EANgIAIAZBAWohAUESDEELIAEgBEYEQEHPASECDJQCCwJAAkAgAS0AAEHFAGsODgBDQ0NDQ0NDQ0NDQ0MBQwsgAUEBaiEBQbUBIQIM+wELIAFBAWohAUG2ASECDPoBC0HOASECIAEgBEYNkgIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBntUAai0AAEcNPyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMkwILIANBADYCACAGQQFqIQFBBww/C0HNASECIAEgBEYNkQIgAygCACIAIAQgAWtqIQUgASAAa0EFaiEGAkADQCABLQAAIABBmNUAai0AAEcNPiAAQQVGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMkgILIANBADYCACAGQQFqIQFBKAw+CyABIARGBEBBzAEhAgyRAgsCQAJAAkAgAS0AAEHFAGsOEQBBQUFBQUFBQUEBQUFBQUECQQsgAUEBaiEBQbEBIQIM+QELIAFBAWohAUGyASECDPgBCyABQQFqIQFBswEhAgz3AQtBywEhAiABIARGDY8CIAMoAgAiACAEIAFraiEFIAEgAGtBBmohBgJAA0AgAS0AACAAQZHVAGotAABHDTwgAEEGRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJACCyADQQA2AgAgBkEBaiEBQRoMPAtBygEhAiABIARGDY4CIAMoAgAiACAEIAFraiEFIAEgAGtBA2ohBgJAA0AgAS0AACAAQY3VAGotAABHDTsgAEEDRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADI8CCyADQQA2AgAgBkEBaiEBQSEMOwsgASAERgRAQckBIQIMjgILAkACQCABLQAAQcEAaw4UAD09PT09PT09PT09PT09PT09PQE9CyABQQFqIQFBrQEhAgz1AQsgAUEBaiEBQbABIQIM9AELIAEgBEYEQEHIASECDI0CCwJAAkAgAS0AAEHVAGsOCwA8PDw8PDw8PDwBPAsgAUEBaiEBQa4BIQIM9AELIAFBAWohAUGvASECDPMBC0HHASECIAEgBEYNiwIgAygCACIAIAQgAWtqIQUgASAAa0EIaiEGAkADQCABLQAAIABBhNUAai0AAEcNOCAAQQhGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMjAILIANBADYCACAGQQFqIQFBKgw4CyABIARGBEBBxgEhAgyLAgsgAS0AAEHQAEcNOCABQQFqIQFBJQw3C0HFASECIAEgBEYNiQIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBgdUAai0AAEcNNiAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMigILIANBADYCACAGQQFqIQFBDgw2CyABIARGBEBBxAEhAgyJAgsgAS0AAEHFAEcNNiABQQFqIQFBqwEhAgzvAQsgASAERgRAQcMBIQIMiAILAkACQAJAAkAgAS0AAEHCAGsODwABAjk5OTk5OTk5OTk5AzkLIAFBAWohAUGnASECDPEBCyABQQFqIQFBqAEhAgzwAQsgAUEBaiEBQakBIQIM7wELIAFBAWohAUGqASECDO4BC0HCASECIAEgBEYNhgIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABB/tQAai0AAEcNMyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMhwILIANBADYCACAGQQFqIQFBFAwzC0HBASECIAEgBEYNhQIgAygCACIAIAQgAWtqIQUgASAAa0EEaiEGAkADQCABLQAAIABB+dQAai0AAEcNMiAAQQRGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMhgILIANBADYCACAGQQFqIQFBKwwyC0HAASECIAEgBEYNhAIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABB9tQAai0AAEcNMSAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMhQILIANBADYCACAGQQFqIQFBLAwxC0G/ASECIAEgBEYNgwIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBodUAai0AAEcNMCAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMhAILIANBADYCACAGQQFqIQFBEQwwC0G+ASECIAEgBEYNggIgAygCACIAIAQgAWtqIQUgASAAa0EDaiEGAkADQCABLQAAIABB8tQAai0AAEcNLyAAQQNGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMgwILIANBADYCACAGQQFqIQFBLgwvCyABIARGBEBBvQEhAgyCAgsCQAJAAkACQAJAIAEtAABBwQBrDhUANDQ0NDQ0NDQ0NAE0NAI0NAM0NAQ0CyABQQFqIQFBmwEhAgzsAQsgAUEBaiEBQZwBIQIM6wELIAFBAWohAUGdASECDOoBCyABQQFqIQFBogEhAgzpAQsgAUEBaiEBQaQBIQIM6AELIAEgBEYEQEG8ASECDIECCwJAAkAgAS0AAEHSAGsOAwAwATALIAFBAWohAUGjASECDOgBCyABQQFqIQFBBAwtC0G7ASECIAEgBEYN/wEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABB8NQAai0AAEcNLCAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMgAILIANBADYCACAGQQFqIQFBHQwsCyABIARGBEBBugEhAgz/AQsCQAJAIAEtAABByQBrDgcBLi4uLi4ALgsgAUEBaiEBQaEBIQIM5gELIAFBAWohAUEiDCsLIAEgBEYEQEG5ASECDP4BCyABLQAAQdAARw0rIAFBAWohAUGgASECDOQBCyABIARGBEBBuAEhAgz9AQsCQAJAIAEtAABBxgBrDgsALCwsLCwsLCwsASwLIAFBAWohAUGeASECDOQBCyABQQFqIQFBnwEhAgzjAQtBtwEhAiABIARGDfsBIAMoAgAiACAEIAFraiEFIAEgAGtBA2ohBgJAA0AgAS0AACAAQezUAGotAABHDSggAEEDRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPwBCyADQQA2AgAgBkEBaiEBQQ0MKAtBtgEhAiABIARGDfoBIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQaHVAGotAABHDScgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPsBCyADQQA2AgAgBkEBaiEBQQwMJwtBtQEhAiABIARGDfkBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQerUAGotAABHDSYgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPoBCyADQQA2AgAgBkEBaiEBQQMMJgtBtAEhAiABIARGDfgBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQejUAGotAABHDSUgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPkBCyADQQA2AgAgBkEBaiEBQSYMJQsgASAERgRAQbMBIQIM+AELAkACQCABLQAAQdQAaw4CAAEnCyABQQFqIQFBmQEhAgzfAQsgAUEBaiEBQZoBIQIM3gELQbIBIQIgASAERg32ASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHm1ABqLQAARw0jIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAz3AQsgA0EANgIAIAZBAWohAUEnDCMLQbEBIQIgASAERg31ASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHk1ABqLQAARw0iIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAz2AQsgA0EANgIAIAZBAWohAUEcDCILQbABIQIgASAERg30ASADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEHe1ABqLQAARw0hIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAz1AQsgA0EANgIAIAZBAWohAUEGDCELQa8BIQIgASAERg3zASADKAIAIgAgBCABa2ohBSABIABrQQRqIQYCQANAIAEtAAAgAEHZ1ABqLQAARw0gIABBBEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAz0AQsgA0EANgIAIAZBAWohAUEZDCALIAEgBEYEQEGuASECDPMBCwJAAkACQAJAIAEtAABBLWsOIwAkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJAEkJCQkJAIkJCQDJAsgAUEBaiEBQY4BIQIM3AELIAFBAWohAUGPASECDNsBCyABQQFqIQFBlAEhAgzaAQsgAUEBaiEBQZUBIQIM2QELQa0BIQIgASAERg3xASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHX1ABqLQAARw0eIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzyAQsgA0EANgIAIAZBAWohAUELDB4LIAEgBEYEQEGsASECDPEBCwJAAkAgAS0AAEHBAGsOAwAgASALIAFBAWohAUGQASECDNgBCyABQQFqIQFBkwEhAgzXAQsgASAERgRAQasBIQIM8AELAkACQCABLQAAQcEAaw4PAB8fHx8fHx8fHx8fHx8BHwsgAUEBaiEBQZEBIQIM1wELIAFBAWohAUGSASECDNYBCyABIARGBEBBqgEhAgzvAQsgAS0AAEHMAEcNHCABQQFqIQFBCgwbC0GpASECIAEgBEYN7QEgAygCACIAIAQgAWtqIQUgASAAa0EFaiEGAkADQCABLQAAIABB0dQAai0AAEcNGiAAQQVGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM7gELIANBADYCACAGQQFqIQFBHgwaC0GoASECIAEgBEYN7AEgAygCACIAIAQgAWtqIQUgASAAa0EGaiEGAkADQCABLQAAIABBytQAai0AAEcNGSAAQQZGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM7QELIANBADYCACAGQQFqIQFBFQwZC0GnASECIAEgBEYN6wEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBx9QAai0AAEcNGCAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM7AELIANBADYCACAGQQFqIQFBFwwYC0GmASECIAEgBEYN6gEgAygCACIAIAQgAWtqIQUgASAAa0EFaiEGAkADQCABLQAAIABBwdQAai0AAEcNFyAAQQVGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM6wELIANBADYCACAGQQFqIQFBGAwXCyABIARGBEBBpQEhAgzqAQsCQAJAIAEtAABByQBrDgcAGRkZGRkBGQsgAUEBaiEBQYsBIQIM0QELIAFBAWohAUGMASECDNABC0GkASECIAEgBEYN6AEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABBptUAai0AAEcNFSAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM6QELIANBADYCACAGQQFqIQFBCQwVC0GjASECIAEgBEYN5wEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABBpNUAai0AAEcNFCAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM6AELIANBADYCACAGQQFqIQFBHwwUC0GiASECIAEgBEYN5gEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBvtQAai0AAEcNEyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM5wELIANBADYCACAGQQFqIQFBAgwTC0GhASECIAEgBEYN5QEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGA0AgAS0AACAAQbzUAGotAABHDREgAEEBRg0CIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADOUBCyABIARGBEBBoAEhAgzlAQtBASABLQAAQd8ARw0RGiABQQFqIQFBhwEhAgzLAQsgA0EANgIAIAZBAWohAUGIASECDMoBC0GfASECIAEgBEYN4gEgAygCACIAIAQgAWtqIQUgASAAa0EIaiEGAkADQCABLQAAIABBhNUAai0AAEcNDyAAQQhGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM4wELIANBADYCACAGQQFqIQFBKQwPC0GeASECIAEgBEYN4QEgAygCACIAIAQgAWtqIQUgASAAa0EDaiEGAkADQCABLQAAIABBuNQAai0AAEcNDiAAQQNGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM4gELIANBADYCACAGQQFqIQFBLQwOCyABIARGBEBBnQEhAgzhAQsgAS0AAEHFAEcNDiABQQFqIQFBhAEhAgzHAQsgASAERgRAQZwBIQIM4AELAkACQCABLQAAQcwAaw4IAA8PDw8PDwEPCyABQQFqIQFBggEhAgzHAQsgAUEBaiEBQYMBIQIMxgELQZsBIQIgASAERg3eASADKAIAIgAgBCABa2ohBSABIABrQQRqIQYCQANAIAEtAAAgAEGz1ABqLQAARw0LIABBBEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzfAQsgA0EANgIAIAZBAWohAUEjDAsLQZoBIQIgASAERg3dASADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGw1ABqLQAARw0KIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzeAQsgA0EANgIAIAZBAWohAUEADAoLIAEgBEYEQEGZASECDN0BCwJAAkAgAS0AAEHIAGsOCAAMDAwMDAwBDAsgAUEBaiEBQf0AIQIMxAELIAFBAWohAUGAASECDMMBCyABIARGBEBBmAEhAgzcAQsCQAJAIAEtAABBzgBrDgMACwELCyABQQFqIQFB/gAhAgzDAQsgAUEBaiEBQf8AIQIMwgELIAEgBEYEQEGXASECDNsBCyABLQAAQdkARw0IIAFBAWohAUEIDAcLQZYBIQIgASAERg3ZASADKAIAIgAgBCABa2ohBSABIABrQQNqIQYCQANAIAEtAAAgAEGs1ABqLQAARw0GIABBA0YNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzaAQsgA0EANgIAIAZBAWohAUEFDAYLQZUBIQIgASAERg3YASADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEGm1ABqLQAARw0FIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzZAQsgA0EANgIAIAZBAWohAUEWDAULQZQBIQIgASAERg3XASADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGh1QBqLQAARw0EIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzYAQsgA0EANgIAIAZBAWohAUEQDAQLIAEgBEYEQEGTASECDNcBCwJAAkAgAS0AAEHDAGsODAAGBgYGBgYGBgYGAQYLIAFBAWohAUH5ACECDL4BCyABQQFqIQFB+gAhAgy9AQtBkgEhAiABIARGDdUBIAMoAgAiACAEIAFraiEFIAEgAGtBBWohBgJAA0AgAS0AACAAQaDUAGotAABHDQIgAEEFRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADNYBCyADQQA2AgAgBkEBaiEBQSQMAgsgA0EANgIADAILIAEgBEYEQEGRASECDNQBCyABLQAAQcwARw0BIAFBAWohAUETCzoAKSADKAIEIQAgA0EANgIEIAMgACABEC4iAA0CDAELQQAhAiADQQA2AhwgAyABNgIUIANB/h82AhAgA0EGNgIMDNEBC0H4ACECDLcBCyADQZABNgIcIAMgATYCFCADIAA2AgxBACECDM8BC0EAIQACQCADKAI4IgJFDQAgAigCQCICRQ0AIAMgAhEAACEACyAARQ0AIABBFUYNASADQQA2AhwgAyABNgIUIANBgg82AhAgA0EgNgIMQQAhAgzOAQtB9wAhAgy0AQsgA0GPATYCHCADIAE2AhQgA0HsGzYCECADQRU2AgxBACECDMwBCyABIARGBEBBjwEhAgzMAQsCQCABLQAAQSBGBEAgAUEBaiEBDAELIANBADYCHCADIAE2AhQgA0GbHzYCECADQQY2AgxBACECDMwBC0ECIQIMsgELA0AgAS0AAEEgRw0CIAQgAUEBaiIBRw0AC0GOASECDMoBCyABIARGBEBBjQEhAgzKAQsCQCABLQAAQQlrDgRKAABKAAtB9QAhAgywAQsgAy0AKUEFRgRAQfYAIQIMsAELQfQAIQIMrwELIAEgBEYEQEGMASECDMgBCyADQRA2AgggAyABNgIEDAoLIAEgBEYEQEGLASECDMcBCwJAIAEtAABBCWsOBEcAAEcAC0HzACECDK0BCyABIARHBEAgA0EQNgIIIAMgATYCBEHxACECDK0BC0GKASECDMUBCwJAIAEgBEcEQANAIAEtAABBoNAAai0AACIAQQNHBEACQCAAQQFrDgJJAAQLQfAAIQIMrwELIAQgAUEBaiIBRw0AC0GIASECDMYBC0GIASECDMUBCyADQQA2AhwgAyABNgIUIANB2yA2AhAgA0EHNgIMQQAhAgzEAQsgASAERgRAQYkBIQIMxAELAkACQAJAIAEtAABBoNIAai0AAEEBaw4DRgIAAQtB8gAhAgysAQsgA0EANgIcIAMgATYCFCADQbQSNgIQIANBBzYCDEEAIQIMxAELQeoAIQIMqgELIAEgBEcEQCABQQFqIQFB7wAhAgyqAQtBhwEhAgzCAQsgBCABIgBGBEBBhgEhAgzCAQsgAC0AACIBQS9GBEAgAEEBaiEBQe4AIQIMqQELIAFBCWsiAkEXSw0BIAAhAUEBIAJ0QZuAgARxDUEMAQsgBCABIgBGBEBBhQEhAgzBAQsgAC0AAEEvRw0AIABBAWohAQwDC0EAIQIgA0EANgIcIAMgADYCFCADQdsgNgIQIANBBzYCDAy/AQsCQAJAAkACQAJAA0AgAS0AAEGgzgBqLQAAIgBBBUcEQAJAAkAgAEEBaw4IRwUGBwgABAEIC0HrACECDK0BCyABQQFqIQFB7QAhAgysAQsgBCABQQFqIgFHDQALQYQBIQIMwwELIAFBAWoMFAsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDR4gA0HbADYCHCADIAE2AhQgAyAANgIMQQAhAgzBAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDR4gA0HdADYCHCADIAE2AhQgAyAANgIMQQAhAgzAAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDR4gA0H6ADYCHCADIAE2AhQgAyAANgIMQQAhAgy/AQsgA0EANgIcIAMgATYCFCADQfkPNgIQIANBBzYCDEEAIQIMvgELIAEgBEYEQEGDASECDL4BCwJAIAEtAABBoM4Aai0AAEEBaw4IPgQFBgAIAgMHCyABQQFqIQELQQMhAgyjAQsgAUEBagwNC0EAIQIgA0EANgIcIANB0RI2AhAgA0EHNgIMIAMgAUEBajYCFAy6AQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDRYgA0HbADYCHCADIAE2AhQgAyAANgIMQQAhAgy5AQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDRYgA0HdADYCHCADIAE2AhQgAyAANgIMQQAhAgy4AQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDRYgA0H6ADYCHCADIAE2AhQgAyAANgIMQQAhAgy3AQsgA0EANgIcIAMgATYCFCADQfkPNgIQIANBBzYCDEEAIQIMtgELQewAIQIMnAELIAEgBEYEQEGCASECDLUBCyABQQFqDAILIAEgBEYEQEGBASECDLQBCyABQQFqDAELIAEgBEYNASABQQFqCyEBQQQhAgyYAQtBgAEhAgywAQsDQCABLQAAQaDMAGotAAAiAEECRwRAIABBAUcEQEHpACECDJkBCwwxCyAEIAFBAWoiAUcNAAtB/wAhAgyvAQsgASAERgRAQf4AIQIMrwELAkAgAS0AAEEJaw43LwMGLwQGBgYGBgYGBgYGBgYGBgYGBgYFBgYCBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGAAYLIAFBAWoLIQFBBSECDJQBCyABQQFqDAYLIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0IIANB2wA2AhwgAyABNgIUIAMgADYCDEEAIQIMqwELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0IIANB3QA2AhwgAyABNgIUIAMgADYCDEEAIQIMqgELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0IIANB+gA2AhwgAyABNgIUIAMgADYCDEEAIQIMqQELIANBADYCHCADIAE2AhQgA0GNFDYCECADQQc2AgxBACECDKgBCwJAAkACQAJAA0AgAS0AAEGgygBqLQAAIgBBBUcEQAJAIABBAWsOBi4DBAUGAAYLQegAIQIMlAELIAQgAUEBaiIBRw0AC0H9ACECDKsBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNByADQdsANgIcIAMgATYCFCADIAA2AgxBACECDKoBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNByADQd0ANgIcIAMgATYCFCADIAA2AgxBACECDKkBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNByADQfoANgIcIAMgATYCFCADIAA2AgxBACECDKgBCyADQQA2AhwgAyABNgIUIANB5Ag2AhAgA0EHNgIMQQAhAgynAQsgASAERg0BIAFBAWoLIQFBBiECDIwBC0H8ACECDKQBCwJAAkACQAJAA0AgAS0AAEGgyABqLQAAIgBBBUcEQCAAQQFrDgQpAgMEBQsgBCABQQFqIgFHDQALQfsAIQIMpwELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0DIANB2wA2AhwgAyABNgIUIAMgADYCDEEAIQIMpgELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0DIANB3QA2AhwgAyABNgIUIAMgADYCDEEAIQIMpQELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0DIANB+gA2AhwgAyABNgIUIAMgADYCDEEAIQIMpAELIANBADYCHCADIAE2AhQgA0G8CjYCECADQQc2AgxBACECDKMBC0HPACECDIkBC0HRACECDIgBC0HnACECDIcBCyABIARGBEBB+gAhAgygAQsCQCABLQAAQQlrDgQgAAAgAAsgAUEBaiEBQeYAIQIMhgELIAEgBEYEQEH5ACECDJ8BCwJAIAEtAABBCWsOBB8AAB8AC0EAIQACQCADKAI4IgJFDQAgAigCOCICRQ0AIAMgAhEAACEACyAARQRAQeIBIQIMhgELIABBFUcEQCADQQA2AhwgAyABNgIUIANByQ02AhAgA0EaNgIMQQAhAgyfAQsgA0H4ADYCHCADIAE2AhQgA0HqGjYCECADQRU2AgxBACECDJ4BCyABIARHBEAgA0ENNgIIIAMgATYCBEHkACECDIUBC0H3ACECDJ0BCyABIARGBEBB9gAhAgydAQsCQAJAAkAgAS0AAEHIAGsOCwABCwsLCwsLCwsCCwsgAUEBaiEBQd0AIQIMhQELIAFBAWohAUHgACECDIQBCyABQQFqIQFB4wAhAgyDAQtB9QAhAiABIARGDZsBIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQbXVAGotAABHDQggAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJwBCyADKAIEIQAgA0IANwMAIAMgACAGQQFqIgEQKyIABEAgA0H0ADYCHCADIAE2AhQgAyAANgIMQQAhAgycAQtB4gAhAgyCAQtBACEAAkAgAygCOCICRQ0AIAIoAjQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0HqDTYCECADQSY2AgxBACECDJwBC0HhACECDIIBCyADQfMANgIcIAMgATYCFCADQYAbNgIQIANBFTYCDEEAIQIMmgELIAMtACkiAEEja0ELSQ0JAkAgAEEGSw0AQQEgAHRBygBxRQ0ADAoLQQAhAiADQQA2AhwgAyABNgIUIANB7Qk2AhAgA0EINgIMDJkBC0HyACECIAEgBEYNmAEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABBs9UAai0AAEcNBSAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMmQELIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARArIgAEQCADQfEANgIcIAMgATYCFCADIAA2AgxBACECDJkBC0HfACECDH8LQQAhAAJAIAMoAjgiAkUNACACKAI0IgJFDQAgAyACEQAAIQALAkAgAARAIABBFUYNASADQQA2AhwgAyABNgIUIANB6g02AhAgA0EmNgIMQQAhAgyZAQtB3gAhAgx/CyADQfAANgIcIAMgATYCFCADQYAbNgIQIANBFTYCDEEAIQIMlwELIAMtAClBIUYNBiADQQA2AhwgAyABNgIUIANBkQo2AhAgA0EINgIMQQAhAgyWAQtB7wAhAiABIARGDZUBIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQbDVAGotAABHDQIgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJYBCyADKAIEIQAgA0IANwMAIAMgACAGQQFqIgEQKyIARQ0CIANB7QA2AhwgAyABNgIUIAMgADYCDEEAIQIMlQELIANBADYCAAsgAygCBCEAIANBADYCBCADIAAgARArIgBFDYABIANB7gA2AhwgAyABNgIUIAMgADYCDEEAIQIMkwELQdwAIQIMeQtBACEAAkAgAygCOCICRQ0AIAIoAjQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0HqDTYCECADQSY2AgxBACECDJMBC0HbACECDHkLIANB7AA2AhwgAyABNgIUIANBgBs2AhAgA0EVNgIMQQAhAgyRAQsgAy0AKSIAQSNJDQAgAEEuRg0AIANBADYCHCADIAE2AhQgA0HJCTYCECADQQg2AgxBACECDJABC0HaACECDHYLIAEgBEYEQEHrACECDI8BCwJAIAEtAABBL0YEQCABQQFqIQEMAQsgA0EANgIcIAMgATYCFCADQbI4NgIQIANBCDYCDEEAIQIMjwELQdkAIQIMdQsgASAERwRAIANBDjYCCCADIAE2AgRB2AAhAgx1C0HqACECDI0BCyABIARGBEBB6QAhAgyNAQsgAS0AAEEwayIAQf8BcUEKSQRAIAMgADoAKiABQQFqIQFB1wAhAgx0CyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNeiADQegANgIcIAMgATYCFCADIAA2AgxBACECDIwBCyABIARGBEBB5wAhAgyMAQsCQCABLQAAQS5GBEAgAUEBaiEBDAELIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ17IANB5gA2AhwgAyABNgIUIAMgADYCDEEAIQIMjAELQdYAIQIMcgsgASAERgRAQeUAIQIMiwELQQAhAEEBIQVBASEHQQAhAgJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAIAEtAABBMGsOCgoJAAECAwQFBggLC0ECDAYLQQMMBQtBBAwEC0EFDAMLQQYMAgtBBwwBC0EICyECQQAhBUEAIQcMAgtBCSECQQEhAEEAIQVBACEHDAELQQAhBUEBIQILIAMgAjoAKyABQQFqIQECQAJAIAMtAC5BEHENAAJAAkACQCADLQAqDgMBAAIECyAHRQ0DDAILIAANAQwCCyAFRQ0BCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNAiADQeIANgIcIAMgATYCFCADIAA2AgxBACECDI0BCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNfSADQeMANgIcIAMgATYCFCADIAA2AgxBACECDIwBCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNeyADQeQANgIcIAMgATYCFCADIAA2AgwMiwELQdQAIQIMcQsgAy0AKUEiRg2GAUHTACECDHALQQAhAAJAIAMoAjgiAkUNACACKAJEIgJFDQAgAyACEQAAIQALIABFBEBB1QAhAgxwCyAAQRVHBEAgA0EANgIcIAMgATYCFCADQaQNNgIQIANBITYCDEEAIQIMiQELIANB4QA2AhwgAyABNgIUIANB0Bo2AhAgA0EVNgIMQQAhAgyIAQsgASAERgRAQeAAIQIMiAELAkACQAJAAkACQCABLQAAQQprDgQBBAQABAsgAUEBaiEBDAELIAFBAWohASADQS9qLQAAQQFxRQ0BC0HSACECDHALIANBADYCHCADIAE2AhQgA0G2ETYCECADQQk2AgxBACECDIgBCyADQQA2AhwgAyABNgIUIANBthE2AhAgA0EJNgIMQQAhAgyHAQsgASAERgRAQd8AIQIMhwELIAEtAABBCkYEQCABQQFqIQEMCQsgAy0ALkHAAHENCCADQQA2AhwgAyABNgIUIANBthE2AhAgA0ECNgIMQQAhAgyGAQsgASAERgRAQd0AIQIMhgELIAEtAAAiAkENRgRAIAFBAWohAUHQACECDG0LIAEhACACQQlrDgQFAQEFAQsgBCABIgBGBEBB3AAhAgyFAQsgAC0AAEEKRw0AIABBAWoMAgtBACECIANBADYCHCADIAA2AhQgA0HKLTYCECADQQc2AgwMgwELIAEgBEYEQEHbACECDIMBCwJAIAEtAABBCWsOBAMAAAMACyABQQFqCyEBQc4AIQIMaAsgASAERgRAQdoAIQIMgQELIAEtAABBCWsOBAABAQABC0EAIQIgA0EANgIcIANBmhI2AhAgA0EHNgIMIAMgAUEBajYCFAx/CyADQYASOwEqQQAhAAJAIAMoAjgiAkUNACACKAI4IgJFDQAgAyACEQAAIQALIABFDQAgAEEVRw0BIANB2QA2AhwgAyABNgIUIANB6ho2AhAgA0EVNgIMQQAhAgx+C0HNACECDGQLIANBADYCHCADIAE2AhQgA0HJDTYCECADQRo2AgxBACECDHwLIAEgBEYEQEHZACECDHwLIAEtAABBIEcNPSABQQFqIQEgAy0ALkEBcQ09IANBADYCHCADIAE2AhQgA0HCHDYCECADQR42AgxBACECDHsLIAEgBEYEQEHYACECDHsLAkACQAJAAkACQCABLQAAIgBBCmsOBAIDAwABCyABQQFqIQFBLCECDGULIABBOkcNASADQQA2AhwgAyABNgIUIANB5xE2AhAgA0EKNgIMQQAhAgx9CyABQQFqIQEgA0Evai0AAEEBcUUNcyADLQAyQYABcUUEQCADQTJqIQIgAxA1QQAhAAJAIAMoAjgiBkUNACAGKAIoIgZFDQAgAyAGEQAAIQALAkACQCAADhZNTEsBAQEBAQEBAQEBAQEBAQEBAQEAAQsgA0EpNgIcIAMgATYCFCADQawZNgIQIANBFTYCDEEAIQIMfgsgA0EANgIcIAMgATYCFCADQeULNgIQIANBETYCDEEAIQIMfQtBACEAAkAgAygCOCICRQ0AIAIoAlwiAkUNACADIAIRAAAhAAsgAEUNWSAAQRVHDQEgA0EFNgIcIAMgATYCFCADQZsbNgIQIANBFTYCDEEAIQIMfAtBywAhAgxiC0EAIQIgA0EANgIcIAMgATYCFCADQZAONgIQIANBFDYCDAx6CyADIAMvATJBgAFyOwEyDDsLIAEgBEcEQCADQRE2AgggAyABNgIEQcoAIQIMYAtB1wAhAgx4CyABIARGBEBB1gAhAgx4CwJAAkACQAJAIAEtAAAiAEEgciAAIABBwQBrQf8BcUEaSRtB/wFxQeMAaw4TAEBAQEBAQEBAQEBAQAFAQEACA0ALIAFBAWohAUHGACECDGELIAFBAWohAUHHACECDGALIAFBAWohAUHIACECDF8LIAFBAWohAUHJACECDF4LQdUAIQIgBCABIgBGDXYgBCABayADKAIAIgFqIQYgACABa0EFaiEHA0AgAUGQyABqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0IQQQgAUEFRg0KGiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAx2C0HUACECIAQgASIARg11IAQgAWsgAygCACIBaiEGIAAgAWtBD2ohBwNAIAFBgMgAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNB0EDIAFBD0YNCRogAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMdQtB0wAhAiAEIAEiAEYNdCAEIAFrIAMoAgAiAWohBiAAIAFrQQ5qIQcDQCABQeLHAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQYgAUEORg0HIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADHQLQdIAIQIgBCABIgBGDXMgBCABayADKAIAIgFqIQUgACABa0EBaiEGA0AgAUHgxwBqLQAAIAAtAAAiB0EgciAHIAdBwQBrQf8BcUEaSRtB/wFxRw0FIAFBAUYNAiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBTYCAAxzCyABIARGBEBB0QAhAgxzCwJAAkAgAS0AACIAQSByIAAgAEHBAGtB/wFxQRpJG0H/AXFB7gBrDgcAOTk5OTkBOQsgAUEBaiEBQcMAIQIMWgsgAUEBaiEBQcQAIQIMWQsgA0EANgIAIAZBAWohAUHFACECDFgLQdAAIQIgBCABIgBGDXAgBCABayADKAIAIgFqIQYgACABa0EJaiEHA0AgAUHWxwBqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0CQQIgAUEJRg0EGiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAxwC0HPACECIAQgASIARg1vIAQgAWsgAygCACIBaiEGIAAgAWtBBWohBwNAIAFB0McAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNASABQQVGDQIgAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMbwsgACEBIANBADYCAAwzC0EBCzoALCADQQA2AgAgB0EBaiEBC0EtIQIMUgsCQANAIAEtAABB0MUAai0AAEEBRw0BIAQgAUEBaiIBRw0AC0HNACECDGsLQcIAIQIMUQsgASAERgRAQcwAIQIMagsgAS0AAEE6RgRAIAMoAgQhACADQQA2AgQgAyAAIAEQMCIARQ0zIANBywA2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMagsgA0EANgIcIAMgATYCFCADQecRNgIQIANBCjYCDEEAIQIMaQsCQAJAIAMtACxBAmsOAgABJwsgA0Ezai0AAEECcUUNJiADLQAuQQJxDSYgA0EANgIcIAMgATYCFCADQaYUNgIQIANBCzYCDEEAIQIMaQsgAy0AMkEgcUUNJSADLQAuQQJxDSUgA0EANgIcIAMgATYCFCADQb0TNgIQIANBDzYCDEEAIQIMaAtBACEAAkAgAygCOCICRQ0AIAIoAkgiAkUNACADIAIRAAAhAAsgAEUEQEHBACECDE8LIABBFUcEQCADQQA2AhwgAyABNgIUIANBpg82AhAgA0EcNgIMQQAhAgxoCyADQcoANgIcIAMgATYCFCADQYUcNgIQIANBFTYCDEEAIQIMZwsgASAERwRAA0AgAS0AAEHAwQBqLQAAQQFHDRcgBCABQQFqIgFHDQALQcQAIQIMZwtBxAAhAgxmCyABIARHBEADQAJAIAEtAAAiAEEgciAAIABBwQBrQf8BcUEaSRtB/wFxIgBBCUYNACAAQSBGDQACQAJAAkACQCAAQeMAaw4TAAMDAwMDAwMBAwMDAwMDAwMDAgMLIAFBAWohAUE2IQIMUgsgAUEBaiEBQTchAgxRCyABQQFqIQFBOCECDFALDBULIAQgAUEBaiIBRw0AC0E8IQIMZgtBPCECDGULIAEgBEYEQEHIACECDGULIANBEjYCCCADIAE2AgQCQAJAAkACQAJAIAMtACxBAWsOBBQAAQIJCyADLQAyQSBxDQNB4AEhAgxPCwJAIAMvATIiAEEIcUUNACADLQAoQQFHDQAgAy0ALkEIcUUNAgsgAyAAQff7A3FBgARyOwEyDAsLIAMgAy8BMkEQcjsBMgwECyADQQA2AgQgAyABIAEQMSIABEAgA0HBADYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgxmCyABQQFqIQEMWAsgA0EANgIcIAMgATYCFCADQfQTNgIQIANBBDYCDEEAIQIMZAtBxwAhAiABIARGDWMgAygCACIAIAQgAWtqIQUgASAAa0EGaiEGAkADQCAAQcDFAGotAAAgAS0AAEEgckcNASAAQQZGDUogAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMZAsgA0EANgIADAULAkAgASAERwRAA0AgAS0AAEHAwwBqLQAAIgBBAUcEQCAAQQJHDQMgAUEBaiEBDAULIAQgAUEBaiIBRw0AC0HFACECDGQLQcUAIQIMYwsLIANBADoALAwBC0ELIQIMRwtBPyECDEYLAkACQANAIAEtAAAiAEEgRwRAAkAgAEEKaw4EAwUFAwALIABBLEYNAwwECyAEIAFBAWoiAUcNAAtBxgAhAgxgCyADQQg6ACwMDgsgAy0AKEEBRw0CIAMtAC5BCHENAiADKAIEIQAgA0EANgIEIAMgACABEDEiAARAIANBwgA2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMXwsgAUEBaiEBDFALQTshAgxECwJAA0AgAS0AACIAQSBHIABBCUdxDQEgBCABQQFqIgFHDQALQcMAIQIMXQsLQTwhAgxCCwJAAkAgASAERwRAA0AgAS0AACIAQSBHBEAgAEEKaw4EAwQEAwQLIAQgAUEBaiIBRw0AC0E/IQIMXQtBPyECDFwLIAMgAy8BMkEgcjsBMgwKCyADKAIEIQAgA0EANgIEIAMgACABEDEiAEUNTiADQT42AhwgAyABNgIUIAMgADYCDEEAIQIMWgsCQCABIARHBEADQCABLQAAQcDDAGotAAAiAEEBRwRAIABBAkYNAwwMCyAEIAFBAWoiAUcNAAtBNyECDFsLQTchAgxaCyABQQFqIQEMBAtBOyECIAQgASIARg1YIAQgAWsgAygCACIBaiEGIAAgAWtBBWohBwJAA0AgAUGQyABqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0BIAFBBUYEQEEHIQEMPwsgAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMWQsgA0EANgIAIAAhAQwFC0E6IQIgBCABIgBGDVcgBCABayADKAIAIgFqIQYgACABa0EIaiEHAkADQCABQbTBAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQEgAUEIRgRAQQUhAQw+CyABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAxYCyADQQA2AgAgACEBDAQLQTkhAiAEIAEiAEYNViAEIAFrIAMoAgAiAWohBiAAIAFrQQNqIQcCQANAIAFBsMEAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNASABQQNGBEBBBiEBDD0LIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADFcLIANBADYCACAAIQEMAwsCQANAIAEtAAAiAEEgRwRAIABBCmsOBAcEBAcCCyAEIAFBAWoiAUcNAAtBOCECDFYLIABBLEcNASABQQFqIQBBASEBAkACQAJAAkACQCADLQAsQQVrDgQDAQIEAAsgACEBDAQLQQIhAQwBC0EEIQELIANBAToALCADIAMvATIgAXI7ATIgACEBDAELIAMgAy8BMkEIcjsBMiAAIQELQT4hAgw7CyADQQA6ACwLQTkhAgw5CyABIARGBEBBNiECDFILAkACQAJAAkACQCABLQAAQQprDgQAAgIBAgsgAygCBCEAIANBADYCBCADIAAgARAxIgBFDQIgA0EzNgIcIAMgATYCFCADIAA2AgxBACECDFULIAMoAgQhACADQQA2AgQgAyAAIAEQMSIARQRAIAFBAWohAQwGCyADQTI2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMVAsgAy0ALkEBcQRAQd8BIQIMOwsgAygCBCEAIANBADYCBCADIAAgARAxIgANAQxJC0E0IQIMOQsgA0E1NgIcIAMgATYCFCADIAA2AgxBACECDFELQTUhAgw3CyADQS9qLQAAQQFxDQAgA0EANgIcIAMgATYCFCADQesWNgIQIANBGTYCDEEAIQIMTwtBMyECDDULIAEgBEYEQEEyIQIMTgsCQCABLQAAQQpGBEAgAUEBaiEBDAELIANBADYCHCADIAE2AhQgA0GSFzYCECADQQM2AgxBACECDE4LQTIhAgw0CyABIARGBEBBMSECDE0LAkAgAS0AACIAQQlGDQAgAEEgRg0AQQEhAgJAIAMtACxBBWsOBAYEBQANCyADIAMvATJBCHI7ATIMDAsgAy0ALkEBcUUNASADLQAsQQhHDQAgA0EAOgAsC0E9IQIMMgsgA0EANgIcIAMgATYCFCADQcIWNgIQIANBCjYCDEEAIQIMSgtBAiECDAELQQQhAgsgA0EBOgAsIAMgAy8BMiACcjsBMgwGCyABIARGBEBBMCECDEcLIAEtAABBCkYEQCABQQFqIQEMAQsgAy0ALkEBcQ0AIANBADYCHCADIAE2AhQgA0HcKDYCECADQQI2AgxBACECDEYLQTAhAgwsCyABQQFqIQFBMSECDCsLIAEgBEYEQEEvIQIMRAsgAS0AACIAQQlHIABBIEdxRQRAIAFBAWohASADLQAuQQFxDQEgA0EANgIcIAMgATYCFCADQZcQNgIQIANBCjYCDEEAIQIMRAtBASECAkACQAJAAkACQAJAIAMtACxBAmsOBwUEBAMBAgAECyADIAMvATJBCHI7ATIMAwtBAiECDAELQQQhAgsgA0EBOgAsIAMgAy8BMiACcjsBMgtBLyECDCsLIANBADYCHCADIAE2AhQgA0GEEzYCECADQQs2AgxBACECDEMLQeEBIQIMKQsgASAERgRAQS4hAgxCCyADQQA2AgQgA0ESNgIIIAMgASABEDEiAA0BC0EuIQIMJwsgA0EtNgIcIAMgATYCFCADIAA2AgxBACECDD8LQQAhAAJAIAMoAjgiAkUNACACKAJMIgJFDQAgAyACEQAAIQALIABFDQAgAEEVRw0BIANB2AA2AhwgAyABNgIUIANBsxs2AhAgA0EVNgIMQQAhAgw+C0HMACECDCQLIANBADYCHCADIAE2AhQgA0GzDjYCECADQR02AgxBACECDDwLIAEgBEYEQEHOACECDDwLIAEtAAAiAEEgRg0CIABBOkYNAQsgA0EAOgAsQQkhAgwhCyADKAIEIQAgA0EANgIEIAMgACABEDAiAA0BDAILIAMtAC5BAXEEQEHeASECDCALIAMoAgQhACADQQA2AgQgAyAAIAEQMCIARQ0CIANBKjYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgw4CyADQcsANgIcIAMgADYCDCADIAFBAWo2AhRBACECDDcLIAFBAWohAUHAACECDB0LIAFBAWohAQwsCyABIARGBEBBKyECDDULAkAgAS0AAEEKRgRAIAFBAWohAQwBCyADLQAuQcAAcUUNBgsgAy0AMkGAAXEEQEEAIQACQCADKAI4IgJFDQAgAigCXCICRQ0AIAMgAhEAACEACyAARQ0SIABBFUYEQCADQQU2AhwgAyABNgIUIANBmxs2AhAgA0EVNgIMQQAhAgw2CyADQQA2AhwgAyABNgIUIANBkA42AhAgA0EUNgIMQQAhAgw1CyADQTJqIQIgAxA1QQAhAAJAIAMoAjgiBkUNACAGKAIoIgZFDQAgAyAGEQAAIQALIAAOFgIBAAQEBAQEBAQEBAQEBAQEBAQEBAMECyADQQE6ADALIAIgAi8BAEHAAHI7AQALQSshAgwYCyADQSk2AhwgAyABNgIUIANBrBk2AhAgA0EVNgIMQQAhAgwwCyADQQA2AhwgAyABNgIUIANB5Qs2AhAgA0ERNgIMQQAhAgwvCyADQQA2AhwgAyABNgIUIANBpQs2AhAgA0ECNgIMQQAhAgwuC0EBIQcgAy8BMiIFQQhxRQRAIAMpAyBCAFIhBwsCQCADLQAwBEBBASEAIAMtAClBBUYNASAFQcAAcUUgB3FFDQELAkAgAy0AKCICQQJGBEBBASEAIAMvATQiBkHlAEYNAkEAIQAgBUHAAHENAiAGQeQARg0CIAZB5gBrQQJJDQIgBkHMAUYNAiAGQbACRg0CDAELQQAhACAFQcAAcQ0BC0ECIQAgBUEIcQ0AIAVBgARxBEACQCACQQFHDQAgAy0ALkEKcQ0AQQUhAAwCC0EEIQAMAQsgBUEgcUUEQCADEDZBAEdBAnQhAAwBC0EAQQMgAykDIFAbIQALIABBAWsOBQIABwEDBAtBESECDBMLIANBAToAMQwpC0EAIQICQCADKAI4IgBFDQAgACgCMCIARQ0AIAMgABEAACECCyACRQ0mIAJBFUYEQCADQQM2AhwgAyABNgIUIANB0hs2AhAgA0EVNgIMQQAhAgwrC0EAIQIgA0EANgIcIAMgATYCFCADQd0ONgIQIANBEjYCDAwqCyADQQA2AhwgAyABNgIUIANB+SA2AhAgA0EPNgIMQQAhAgwpC0EAIQACQCADKAI4IgJFDQAgAigCMCICRQ0AIAMgAhEAACEACyAADQELQQ4hAgwOCyAAQRVGBEAgA0ECNgIcIAMgATYCFCADQdIbNgIQIANBFTYCDEEAIQIMJwsgA0EANgIcIAMgATYCFCADQd0ONgIQIANBEjYCDEEAIQIMJgtBKiECDAwLIAEgBEcEQCADQQk2AgggAyABNgIEQSkhAgwMC0EmIQIMJAsgAyADKQMgIgwgBCABa60iCn0iC0IAIAsgDFgbNwMgIAogDFQEQEElIQIMJAsgAygCBCEAIANBADYCBCADIAAgASAMp2oiARAyIgBFDQAgA0EFNgIcIAMgATYCFCADIAA2AgxBACECDCMLQQ8hAgwJC0IAIQoCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAS0AAEEwaw43FxYAAQIDBAUGBxQUFBQUFBQICQoLDA0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFA4PEBESExQLQgIhCgwWC0IDIQoMFQtCBCEKDBQLQgUhCgwTC0IGIQoMEgtCByEKDBELQgghCgwQC0IJIQoMDwtCCiEKDA4LQgshCgwNC0IMIQoMDAtCDSEKDAsLQg4hCgwKC0IPIQoMCQtCCiEKDAgLQgshCgwHC0IMIQoMBgtCDSEKDAULQg4hCgwEC0IPIQoMAwsgA0EANgIcIAMgATYCFCADQZ8VNgIQIANBDDYCDEEAIQIMIQsgASAERgRAQSIhAgwhC0IAIQoCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAEtAABBMGsONxUUAAECAwQFBgcWFhYWFhYWCAkKCwwNFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYODxAREhMWC0ICIQoMFAtCAyEKDBMLQgQhCgwSC0IFIQoMEQtCBiEKDBALQgchCgwPC0IIIQoMDgtCCSEKDA0LQgohCgwMC0ILIQoMCwtCDCEKDAoLQg0hCgwJC0IOIQoMCAtCDyEKDAcLQgohCgwGC0ILIQoMBQtCDCEKDAQLQg0hCgwDC0IOIQoMAgtCDyEKDAELQgEhCgsgAUEBaiEBIAMpAyAiC0L//////////w9YBEAgAyALQgSGIAqENwMgDAILIANBADYCHCADIAE2AhQgA0G1CTYCECADQQw2AgxBACECDB4LQSchAgwEC0EoIQIMAwsgAyABOgAsIANBADYCACAHQQFqIQFBDCECDAILIANBADYCACAGQQFqIQFBCiECDAELIAFBAWohAUEIIQIMAAsAC0EAIQIgA0EANgIcIAMgATYCFCADQbI4NgIQIANBCDYCDAwXC0EAIQIgA0EANgIcIAMgATYCFCADQYMRNgIQIANBCTYCDAwWC0EAIQIgA0EANgIcIAMgATYCFCADQd8KNgIQIANBCTYCDAwVC0EAIQIgA0EANgIcIAMgATYCFCADQe0QNgIQIANBCTYCDAwUC0EAIQIgA0EANgIcIAMgATYCFCADQdIRNgIQIANBCTYCDAwTC0EAIQIgA0EANgIcIAMgATYCFCADQbI4NgIQIANBCDYCDAwSC0EAIQIgA0EANgIcIAMgATYCFCADQYMRNgIQIANBCTYCDAwRC0EAIQIgA0EANgIcIAMgATYCFCADQd8KNgIQIANBCTYCDAwQC0EAIQIgA0EANgIcIAMgATYCFCADQe0QNgIQIANBCTYCDAwPC0EAIQIgA0EANgIcIAMgATYCFCADQdIRNgIQIANBCTYCDAwOC0EAIQIgA0EANgIcIAMgATYCFCADQbkXNgIQIANBDzYCDAwNC0EAIQIgA0EANgIcIAMgATYCFCADQbkXNgIQIANBDzYCDAwMC0EAIQIgA0EANgIcIAMgATYCFCADQZkTNgIQIANBCzYCDAwLC0EAIQIgA0EANgIcIAMgATYCFCADQZ0JNgIQIANBCzYCDAwKC0EAIQIgA0EANgIcIAMgATYCFCADQZcQNgIQIANBCjYCDAwJC0EAIQIgA0EANgIcIAMgATYCFCADQbEQNgIQIANBCjYCDAwIC0EAIQIgA0EANgIcIAMgATYCFCADQbsdNgIQIANBAjYCDAwHC0EAIQIgA0EANgIcIAMgATYCFCADQZYWNgIQIANBAjYCDAwGC0EAIQIgA0EANgIcIAMgATYCFCADQfkYNgIQIANBAjYCDAwFC0EAIQIgA0EANgIcIAMgATYCFCADQcQYNgIQIANBAjYCDAwECyADQQI2AhwgAyABNgIUIANBqR42AhAgA0EWNgIMQQAhAgwDC0HeACECIAEgBEYNAiAJQQhqIQcgAygCACEFAkACQCABIARHBEAgBUGWyABqIQggBCAFaiABayEGIAVBf3NBCmoiBSABaiEAA0AgAS0AACAILQAARwRAQQIhCAwDCyAFRQRAQQAhCCAAIQEMAwsgBUEBayEFIAhBAWohCCAEIAFBAWoiAUcNAAsgBiEFIAQhAQsgB0EBNgIAIAMgBTYCAAwBCyADQQA2AgAgByAINgIACyAHIAE2AgQgCSgCDCEAAkACQCAJKAIIQQFrDgIEAQALIANBADYCHCADQcIeNgIQIANBFzYCDCADIABBAWo2AhRBACECDAMLIANBADYCHCADIAA2AhQgA0HXHjYCECADQQk2AgxBACECDAILIAEgBEYEQEEoIQIMAgsgA0EJNgIIIAMgATYCBEEnIQIMAQsgASAERgRAQQEhAgwBCwNAAkACQAJAIAEtAABBCmsOBAABAQABCyABQQFqIQEMAQsgAUEBaiEBIAMtAC5BIHENAEEAIQIgA0EANgIcIAMgATYCFCADQaEhNgIQIANBBTYCDAwCC0EBIQIgASAERw0ACwsgCUEQaiQAIAJFBEAgAygCDCEADAELIAMgAjYCHEEAIQAgAygCBCIBRQ0AIAMgASAEIAMoAggRAQAiAUUNACADIAQ2AhQgAyABNgIMIAEhAAsgAAu+AgECfyAAQQA6AAAgAEHkAGoiAUEBa0EAOgAAIABBADoAAiAAQQA6AAEgAUEDa0EAOgAAIAFBAmtBADoAACAAQQA6AAMgAUEEa0EAOgAAQQAgAGtBA3EiASAAaiIAQQA2AgBB5AAgAWtBfHEiAiAAaiIBQQRrQQA2AgACQCACQQlJDQAgAEEANgIIIABBADYCBCABQQhrQQA2AgAgAUEMa0EANgIAIAJBGUkNACAAQQA2AhggAEEANgIUIABBADYCECAAQQA2AgwgAUEQa0EANgIAIAFBFGtBADYCACABQRhrQQA2AgAgAUEca0EANgIAIAIgAEEEcUEYciICayIBQSBJDQAgACACaiEAA0AgAEIANwMYIABCADcDECAAQgA3AwggAEIANwMAIABBIGohACABQSBrIgFBH0sNAAsLC1YBAX8CQCAAKAIMDQACQAJAAkACQCAALQAxDgMBAAMCCyAAKAI4IgFFDQAgASgCMCIBRQ0AIAAgAREAACIBDQMLQQAPCwALIABByhk2AhBBDiEBCyABCxoAIAAoAgxFBEAgAEHeHzYCECAAQRU2AgwLCxQAIAAoAgxBFUYEQCAAQQA2AgwLCxQAIAAoAgxBFkYEQCAAQQA2AgwLCwcAIAAoAgwLBwAgACgCEAsJACAAIAE2AhALBwAgACgCFAsrAAJAIABBJ08NAEL//////wkgAK2IQgGDUA0AIABBAnRB0DhqKAIADwsACxcAIABBL08EQAALIABBAnRB7DlqKAIAC78JAQF/QfQtIQECQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAQeQAaw70A2NiAAFhYWFhYWECAwQFYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQYHCAkKCwwNDg9hYWFhYRBhYWFhYWFhYWFhYRFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWESExQVFhcYGRobYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYRwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1NmE3ODk6YWFhYWFhYWE7YWFhPGFhYWE9Pj9hYWFhYWFhYUBhYUFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFCQ0RFRkdISUpLTE1OT1BRUlNhYWFhYWFhYVRVVldYWVpbYVxdYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhXmFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYV9gYQtB6iwPC0GYJg8LQe0xDwtBoDcPC0HJKQ8LQbQpDwtBli0PC0HrKw8LQaI1DwtB2zQPC0HgKQ8LQeMkDwtB1SQPC0HuJA8LQeYlDwtByjQPC0HQNw8LQao1DwtB9SwPC0H2Jg8LQYIiDwtB8jMPC0G+KA8LQec3DwtBzSEPC0HAIQ8LQbglDwtByyUPC0GWJA8LQY80DwtBzTUPC0HdKg8LQe4zDwtBnDQPC0GeMQ8LQfQ1DwtB5SIPC0GvJQ8LQZkxDwtBsjYPC0H5Ng8LQcQyDwtB3SwPC0GCMQ8LQcExDwtBjTcPC0HJJA8LQew2DwtB5yoPC0HIIw8LQeIhDwtByTcPC0GlIg8LQZQiDwtB2zYPC0HeNQ8LQYYmDwtBvCsPC0GLMg8LQaAjDwtB9jAPC0GALA8LQYkrDwtBpCYPC0HyIw8LQYEoDwtBqzIPC0HrJw8LQcI2DwtBoiQPC0HPKg8LQdwjDwtBhycPC0HkNA8LQbciDwtBrTEPC0HVIg8LQa80DwtB3iYPC0HWMg8LQfQ0DwtBgTgPC0H0Nw8LQZI2DwtBnScPC0GCKQ8LQY0jDwtB1zEPC0G9NQ8LQbQ3DwtB2DAPC0G2Jw8LQZo4DwtBpyoPC0HEJw8LQa4jDwtB9SIPCwALQcomIQELIAELFwAgACAALwEuQf7/A3EgAUEAR3I7AS4LGgAgACAALwEuQf3/A3EgAUEAR0EBdHI7AS4LGgAgACAALwEuQfv/A3EgAUEAR0ECdHI7AS4LGgAgACAALwEuQff/A3EgAUEAR0EDdHI7AS4LGgAgACAALwEuQe//A3EgAUEAR0EEdHI7AS4LGgAgACAALwEuQd//A3EgAUEAR0EFdHI7AS4LGgAgACAALwEuQb//A3EgAUEAR0EGdHI7AS4LGgAgACAALwEuQf/+A3EgAUEAR0EHdHI7AS4LGgAgACAALwEuQf/9A3EgAUEAR0EIdHI7AS4LGgAgACAALwEuQf/7A3EgAUEAR0EJdHI7AS4LPgECfwJAIAAoAjgiA0UNACADKAIEIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEHhEjYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIIIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEH8ETYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIMIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEHsCjYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIQIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEH6HjYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIUIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEHLEDYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIYIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEG3HzYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIcIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEG/FTYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIsIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEH+CDYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIgIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEGMHTYCEEEYIQQLIAQLPgECfwJAIAAoAjgiA0UNACADKAIkIgNFDQAgACABIAIgAWsgAxEBACIEQX9HDQAgAEHmFTYCEEEYIQQLIAQLOAAgAAJ/IAAvATJBFHFBFEYEQEEBIAAtAChBAUYNARogAC8BNEHlAEYMAQsgAC0AKUEFRgs6ADALWQECfwJAIAAtAChBAUYNACAALwE0IgFB5ABrQeQASQ0AIAFBzAFGDQAgAUGwAkYNACAALwEyIgBBwABxDQBBASECIABBiARxQYAERg0AIABBKHFFIQILIAILjAEBAn8CQAJAAkAgAC0AKkUNACAALQArRQ0AIAAvATIiAUECcUUNAQwCCyAALwEyIgFBAXFFDQELQQEhAiAALQAoQQFGDQAgAC8BNCIAQeQAa0HkAEkNACAAQcwBRg0AIABBsAJGDQAgAUHAAHENAEEAIQIgAUGIBHFBgARGDQAgAUEocUEARyECCyACC1cAIABBGGpCADcDACAAQgA3AwAgAEE4akIANwMAIABBMGpCADcDACAAQShqQgA3AwAgAEEgakIANwMAIABBEGpCADcDACAAQQhqQgA3AwAgAEH9ATYCHAsGACAAEDoLmi0BC38jAEEQayIKJABB3NUAKAIAIglFBEBBnNkAKAIAIgVFBEBBqNkAQn83AgBBoNkAQoCAhICAgMAANwIAQZzZACAKQQhqQXBxQdiq1aoFcyIFNgIAQbDZAEEANgIAQYDZAEEANgIAC0GE2QBBwNkENgIAQdTVAEHA2QQ2AgBB6NUAIAU2AgBB5NUAQX82AgBBiNkAQcCmAzYCAANAIAFBgNYAaiABQfTVAGoiAjYCACACIAFB7NUAaiIDNgIAIAFB+NUAaiADNgIAIAFBiNYAaiABQfzVAGoiAzYCACADIAI2AgAgAUGQ1gBqIAFBhNYAaiICNgIAIAIgAzYCACABQYzWAGogAjYCACABQSBqIgFBgAJHDQALQczZBEGBpgM2AgBB4NUAQazZACgCADYCAEHQ1QBBgKYDNgIAQdzVAEHI2QQ2AgBBzP8HQTg2AgBByNkEIQkLAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAEHsAU0EQEHE1QAoAgAiBkEQIABBE2pBcHEgAEELSRsiBEEDdiIAdiIBQQNxBEACQCABQQFxIAByQQFzIgJBA3QiAEHs1QBqIgEgAEH01QBqKAIAIgAoAggiA0YEQEHE1QAgBkF+IAJ3cTYCAAwBCyABIAM2AgggAyABNgIMCyAAQQhqIQEgACACQQN0IgJBA3I2AgQgACACaiIAIAAoAgRBAXI2AgQMEQtBzNUAKAIAIgggBE8NASABBEACQEECIAB0IgJBACACa3IgASAAdHFoIgBBA3QiAkHs1QBqIgEgAkH01QBqKAIAIgIoAggiA0YEQEHE1QAgBkF+IAB3cSIGNgIADAELIAEgAzYCCCADIAE2AgwLIAIgBEEDcjYCBCAAQQN0IgAgBGshBSAAIAJqIAU2AgAgAiAEaiIEIAVBAXI2AgQgCARAIAhBeHFB7NUAaiEAQdjVACgCACEDAn9BASAIQQN2dCIBIAZxRQRAQcTVACABIAZyNgIAIAAMAQsgACgCCAsiASADNgIMIAAgAzYCCCADIAA2AgwgAyABNgIICyACQQhqIQFB2NUAIAQ2AgBBzNUAIAU2AgAMEQtByNUAKAIAIgtFDQEgC2hBAnRB9NcAaigCACIAKAIEQXhxIARrIQUgACECA0ACQCACKAIQIgFFBEAgAkEUaigCACIBRQ0BCyABKAIEQXhxIARrIgMgBUkhAiADIAUgAhshBSABIAAgAhshACABIQIMAQsLIAAoAhghCSAAKAIMIgMgAEcEQEHU1QAoAgAaIAMgACgCCCIBNgIIIAEgAzYCDAwQCyAAQRRqIgIoAgAiAUUEQCAAKAIQIgFFDQMgAEEQaiECCwNAIAIhByABIgNBFGoiAigCACIBDQAgA0EQaiECIAMoAhAiAQ0ACyAHQQA2AgAMDwtBfyEEIABBv39LDQAgAEETaiIBQXBxIQRByNUAKAIAIghFDQBBACAEayEFAkACQAJAAn9BACAEQYACSQ0AGkEfIARB////B0sNABogBEEmIAFBCHZnIgBrdkEBcSAAQQF0a0E+agsiBkECdEH01wBqKAIAIgJFBEBBACEBQQAhAwwBC0EAIQEgBEEZIAZBAXZrQQAgBkEfRxt0IQBBACEDA0ACQCACKAIEQXhxIARrIgcgBU8NACACIQMgByIFDQBBACEFIAIhAQwDCyABIAJBFGooAgAiByAHIAIgAEEddkEEcWpBEGooAgAiAkYbIAEgBxshASAAQQF0IQAgAg0ACwsgASADckUEQEEAIQNBAiAGdCIAQQAgAGtyIAhxIgBFDQMgAGhBAnRB9NcAaigCACEBCyABRQ0BCwNAIAEoAgRBeHEgBGsiAiAFSSEAIAIgBSAAGyEFIAEgAyAAGyEDIAEoAhAiAAR/IAAFIAFBFGooAgALIgENAAsLIANFDQAgBUHM1QAoAgAgBGtPDQAgAygCGCEHIAMgAygCDCIARwRAQdTVACgCABogACADKAIIIgE2AgggASAANgIMDA4LIANBFGoiAigCACIBRQRAIAMoAhAiAUUNAyADQRBqIQILA0AgAiEGIAEiAEEUaiICKAIAIgENACAAQRBqIQIgACgCECIBDQALIAZBADYCAAwNC0HM1QAoAgAiAyAETwRAQdjVACgCACEBAkAgAyAEayICQRBPBEAgASAEaiIAIAJBAXI2AgQgASADaiACNgIAIAEgBEEDcjYCBAwBCyABIANBA3I2AgQgASADaiIAIAAoAgRBAXI2AgRBACEAQQAhAgtBzNUAIAI2AgBB2NUAIAA2AgAgAUEIaiEBDA8LQdDVACgCACIDIARLBEAgBCAJaiIAIAMgBGsiAUEBcjYCBEHc1QAgADYCAEHQ1QAgATYCACAJIARBA3I2AgQgCUEIaiEBDA8LQQAhASAEAn9BnNkAKAIABEBBpNkAKAIADAELQajZAEJ/NwIAQaDZAEKAgISAgIDAADcCAEGc2QAgCkEMakFwcUHYqtWqBXM2AgBBsNkAQQA2AgBBgNkAQQA2AgBBgIAECyIAIARBxwBqIgVqIgZBACAAayIHcSICTwRAQbTZAEEwNgIADA8LAkBB/NgAKAIAIgFFDQBB9NgAKAIAIgggAmohACAAIAFNIAAgCEtxDQBBACEBQbTZAEEwNgIADA8LQYDZAC0AAEEEcQ0EAkACQCAJBEBBhNkAIQEDQCABKAIAIgAgCU0EQCAAIAEoAgRqIAlLDQMLIAEoAggiAQ0ACwtBABA7IgBBf0YNBSACIQZBoNkAKAIAIgFBAWsiAyAAcQRAIAIgAGsgACADakEAIAFrcWohBgsgBCAGTw0FIAZB/v///wdLDQVB/NgAKAIAIgMEQEH02AAoAgAiByAGaiEBIAEgB00NBiABIANLDQYLIAYQOyIBIABHDQEMBwsgBiADayAHcSIGQf7///8HSw0EIAYQOyEAIAAgASgCACABKAIEakYNAyAAIQELAkAgBiAEQcgAak8NACABQX9GDQBBpNkAKAIAIgAgBSAGa2pBACAAa3EiAEH+////B0sEQCABIQAMBwsgABA7QX9HBEAgACAGaiEGIAEhAAwHC0EAIAZrEDsaDAQLIAEiAEF/Rw0FDAMLQQAhAwwMC0EAIQAMCgsgAEF/Rw0CC0GA2QBBgNkAKAIAQQRyNgIACyACQf7///8HSw0BIAIQOyEAQQAQOyEBIABBf0YNASABQX9GDQEgACABTw0BIAEgAGsiBiAEQThqTQ0BC0H02ABB9NgAKAIAIAZqIgE2AgBB+NgAKAIAIAFJBEBB+NgAIAE2AgALAkACQAJAQdzVACgCACICBEBBhNkAIQEDQCAAIAEoAgAiAyABKAIEIgVqRg0CIAEoAggiAQ0ACwwCC0HU1QAoAgAiAUEARyAAIAFPcUUEQEHU1QAgADYCAAtBACEBQYjZACAGNgIAQYTZACAANgIAQeTVAEF/NgIAQejVAEGc2QAoAgA2AgBBkNkAQQA2AgADQCABQYDWAGogAUH01QBqIgI2AgAgAiABQezVAGoiAzYCACABQfjVAGogAzYCACABQYjWAGogAUH81QBqIgM2AgAgAyACNgIAIAFBkNYAaiABQYTWAGoiAjYCACACIAM2AgAgAUGM1gBqIAI2AgAgAUEgaiIBQYACRw0AC0F4IABrQQ9xIgEgAGoiAiAGQThrIgMgAWsiAUEBcjYCBEHg1QBBrNkAKAIANgIAQdDVACABNgIAQdzVACACNgIAIAAgA2pBODYCBAwCCyAAIAJNDQAgAiADSQ0AIAEoAgxBCHENAEF4IAJrQQ9xIgAgAmoiA0HQ1QAoAgAgBmoiByAAayIAQQFyNgIEIAEgBSAGajYCBEHg1QBBrNkAKAIANgIAQdDVACAANgIAQdzVACADNgIAIAIgB2pBODYCBAwBCyAAQdTVACgCAEkEQEHU1QAgADYCAAsgACAGaiEDQYTZACEBAkACQAJAA0AgAyABKAIARwRAIAEoAggiAQ0BDAILCyABLQAMQQhxRQ0BC0GE2QAhAQNAIAEoAgAiAyACTQRAIAMgASgCBGoiBSACSw0DCyABKAIIIQEMAAsACyABIAA2AgAgASABKAIEIAZqNgIEIABBeCAAa0EPcWoiCSAEQQNyNgIEIANBeCADa0EPcWoiBiAEIAlqIgRrIQEgAiAGRgRAQdzVACAENgIAQdDVAEHQ1QAoAgAgAWoiADYCACAEIABBAXI2AgQMCAtB2NUAKAIAIAZGBEBB2NUAIAQ2AgBBzNUAQczVACgCACABaiIANgIAIAQgAEEBcjYCBCAAIARqIAA2AgAMCAsgBigCBCIFQQNxQQFHDQYgBUF4cSEIIAVB/wFNBEAgBUEDdiEDIAYoAggiACAGKAIMIgJGBEBBxNUAQcTVACgCAEF+IAN3cTYCAAwHCyACIAA2AgggACACNgIMDAYLIAYoAhghByAGIAYoAgwiAEcEQCAAIAYoAggiAjYCCCACIAA2AgwMBQsgBkEUaiICKAIAIgVFBEAgBigCECIFRQ0EIAZBEGohAgsDQCACIQMgBSIAQRRqIgIoAgAiBQ0AIABBEGohAiAAKAIQIgUNAAsgA0EANgIADAQLQXggAGtBD3EiASAAaiIHIAZBOGsiAyABayIBQQFyNgIEIAAgA2pBODYCBCACIAVBNyAFa0EPcWpBP2siAyADIAJBEGpJGyIDQSM2AgRB4NUAQazZACgCADYCAEHQ1QAgATYCAEHc1QAgBzYCACADQRBqQYzZACkCADcCACADQYTZACkCADcCCEGM2QAgA0EIajYCAEGI2QAgBjYCAEGE2QAgADYCAEGQ2QBBADYCACADQSRqIQEDQCABQQc2AgAgBSABQQRqIgFLDQALIAIgA0YNACADIAMoAgRBfnE2AgQgAyADIAJrIgU2AgAgAiAFQQFyNgIEIAVB/wFNBEAgBUF4cUHs1QBqIQACf0HE1QAoAgAiAUEBIAVBA3Z0IgNxRQRAQcTVACABIANyNgIAIAAMAQsgACgCCAsiASACNgIMIAAgAjYCCCACIAA2AgwgAiABNgIIDAELQR8hASAFQf///wdNBEAgBUEmIAVBCHZnIgBrdkEBcSAAQQF0a0E+aiEBCyACIAE2AhwgAkIANwIQIAFBAnRB9NcAaiEAQcjVACgCACIDQQEgAXQiBnFFBEAgACACNgIAQcjVACADIAZyNgIAIAIgADYCGCACIAI2AgggAiACNgIMDAELIAVBGSABQQF2a0EAIAFBH0cbdCEBIAAoAgAhAwJAA0AgAyIAKAIEQXhxIAVGDQEgAUEddiEDIAFBAXQhASAAIANBBHFqQRBqIgYoAgAiAw0ACyAGIAI2AgAgAiAANgIYIAIgAjYCDCACIAI2AggMAQsgACgCCCIBIAI2AgwgACACNgIIIAJBADYCGCACIAA2AgwgAiABNgIIC0HQ1QAoAgAiASAETQ0AQdzVACgCACIAIARqIgIgASAEayIBQQFyNgIEQdDVACABNgIAQdzVACACNgIAIAAgBEEDcjYCBCAAQQhqIQEMCAtBACEBQbTZAEEwNgIADAcLQQAhAAsgB0UNAAJAIAYoAhwiAkECdEH01wBqIgMoAgAgBkYEQCADIAA2AgAgAA0BQcjVAEHI1QAoAgBBfiACd3E2AgAMAgsgB0EQQRQgBygCECAGRhtqIAA2AgAgAEUNAQsgACAHNgIYIAYoAhAiAgRAIAAgAjYCECACIAA2AhgLIAZBFGooAgAiAkUNACAAQRRqIAI2AgAgAiAANgIYCyABIAhqIQEgBiAIaiIGKAIEIQULIAYgBUF+cTYCBCABIARqIAE2AgAgBCABQQFyNgIEIAFB/wFNBEAgAUF4cUHs1QBqIQACf0HE1QAoAgAiAkEBIAFBA3Z0IgFxRQRAQcTVACABIAJyNgIAIAAMAQsgACgCCAsiASAENgIMIAAgBDYCCCAEIAA2AgwgBCABNgIIDAELQR8hBSABQf///wdNBEAgAUEmIAFBCHZnIgBrdkEBcSAAQQF0a0E+aiEFCyAEIAU2AhwgBEIANwIQIAVBAnRB9NcAaiEAQcjVACgCACICQQEgBXQiA3FFBEAgACAENgIAQcjVACACIANyNgIAIAQgADYCGCAEIAQ2AgggBCAENgIMDAELIAFBGSAFQQF2a0EAIAVBH0cbdCEFIAAoAgAhAAJAA0AgACICKAIEQXhxIAFGDQEgBUEddiEAIAVBAXQhBSACIABBBHFqQRBqIgMoAgAiAA0ACyADIAQ2AgAgBCACNgIYIAQgBDYCDCAEIAQ2AggMAQsgAigCCCIAIAQ2AgwgAiAENgIIIARBADYCGCAEIAI2AgwgBCAANgIICyAJQQhqIQEMAgsCQCAHRQ0AAkAgAygCHCIBQQJ0QfTXAGoiAigCACADRgRAIAIgADYCACAADQFByNUAIAhBfiABd3EiCDYCAAwCCyAHQRBBFCAHKAIQIANGG2ogADYCACAARQ0BCyAAIAc2AhggAygCECIBBEAgACABNgIQIAEgADYCGAsgA0EUaigCACIBRQ0AIABBFGogATYCACABIAA2AhgLAkAgBUEPTQRAIAMgBCAFaiIAQQNyNgIEIAAgA2oiACAAKAIEQQFyNgIEDAELIAMgBGoiAiAFQQFyNgIEIAMgBEEDcjYCBCACIAVqIAU2AgAgBUH/AU0EQCAFQXhxQezVAGohAAJ/QcTVACgCACIBQQEgBUEDdnQiBXFFBEBBxNUAIAEgBXI2AgAgAAwBCyAAKAIICyIBIAI2AgwgACACNgIIIAIgADYCDCACIAE2AggMAQtBHyEBIAVB////B00EQCAFQSYgBUEIdmciAGt2QQFxIABBAXRrQT5qIQELIAIgATYCHCACQgA3AhAgAUECdEH01wBqIQBBASABdCIEIAhxRQRAIAAgAjYCAEHI1QAgBCAIcjYCACACIAA2AhggAiACNgIIIAIgAjYCDAwBCyAFQRkgAUEBdmtBACABQR9HG3QhASAAKAIAIQQCQANAIAQiACgCBEF4cSAFRg0BIAFBHXYhBCABQQF0IQEgACAEQQRxakEQaiIGKAIAIgQNAAsgBiACNgIAIAIgADYCGCACIAI2AgwgAiACNgIIDAELIAAoAggiASACNgIMIAAgAjYCCCACQQA2AhggAiAANgIMIAIgATYCCAsgA0EIaiEBDAELAkAgCUUNAAJAIAAoAhwiAUECdEH01wBqIgIoAgAgAEYEQCACIAM2AgAgAw0BQcjVACALQX4gAXdxNgIADAILIAlBEEEUIAkoAhAgAEYbaiADNgIAIANFDQELIAMgCTYCGCAAKAIQIgEEQCADIAE2AhAgASADNgIYCyAAQRRqKAIAIgFFDQAgA0EUaiABNgIAIAEgAzYCGAsCQCAFQQ9NBEAgACAEIAVqIgFBA3I2AgQgACABaiIBIAEoAgRBAXI2AgQMAQsgACAEaiIHIAVBAXI2AgQgACAEQQNyNgIEIAUgB2ogBTYCACAIBEAgCEF4cUHs1QBqIQFB2NUAKAIAIQMCf0EBIAhBA3Z0IgIgBnFFBEBBxNUAIAIgBnI2AgAgAQwBCyABKAIICyICIAM2AgwgASADNgIIIAMgATYCDCADIAI2AggLQdjVACAHNgIAQczVACAFNgIACyAAQQhqIQELIApBEGokACABC0MAIABFBEA/AEEQdA8LAkAgAEH//wNxDQAgAEEASA0AIABBEHZAACIAQX9GBEBBtNkAQTA2AgBBfw8LIABBEHQPCwALC5lCIgBBgAgLDQEAAAAAAAAAAgAAAAMAQZgICwUEAAAABQBBqAgLCQYAAAAHAAAACABB5AgLwjJJbnZhbGlkIGNoYXIgaW4gdXJsIHF1ZXJ5AFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fYm9keQBDb250ZW50LUxlbmd0aCBvdmVyZmxvdwBDaHVuayBzaXplIG92ZXJmbG93AEludmFsaWQgbWV0aG9kIGZvciBIVFRQL3gueCByZXF1ZXN0AEludmFsaWQgbWV0aG9kIGZvciBSVFNQL3gueCByZXF1ZXN0AEV4cGVjdGVkIFNPVVJDRSBtZXRob2QgZm9yIElDRS94LnggcmVxdWVzdABJbnZhbGlkIGNoYXIgaW4gdXJsIGZyYWdtZW50IHN0YXJ0AEV4cGVjdGVkIGRvdABTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3N0YXR1cwBJbnZhbGlkIHJlc3BvbnNlIHN0YXR1cwBFeHBlY3RlZCBMRiBhZnRlciBoZWFkZXJzAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMAVXNlciBjYWxsYmFjayBlcnJvcgBgb25fcmVzZXRgIGNhbGxiYWNrIGVycm9yAGBvbl9jaHVua19oZWFkZXJgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2JlZ2luYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlYCBjYWxsYmFjayBlcnJvcgBgb25fc3RhdHVzX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdmVyc2lvbl9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3VybF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3Byb3RvY29sX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWV0aG9kX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX25hbWVgIGNhbGxiYWNrIGVycm9yAFVuZXhwZWN0ZWQgY2hhciBpbiB1cmwgc2VydmVyAEludmFsaWQgaGVhZGVyIHZhbHVlIGNoYXIASW52YWxpZCBoZWFkZXIgZmllbGQgY2hhcgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3ZlcnNpb24ASW52YWxpZCBtaW5vciB2ZXJzaW9uAEludmFsaWQgbWFqb3IgdmVyc2lvbgBFeHBlY3RlZCBzcGFjZSBhZnRlciB2ZXJzaW9uAEV4cGVjdGVkIENSTEYgYWZ0ZXIgdmVyc2lvbgBJbnZhbGlkIEhUVFAgdmVyc2lvbgBJbnZhbGlkIGhlYWRlciB0b2tlbgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3VybABJbnZhbGlkIGNoYXJhY3RlcnMgaW4gdXJsAFVuZXhwZWN0ZWQgc3RhcnQgY2hhciBpbiB1cmwARG91YmxlIEAgaW4gdXJsAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fcHJvdG9jb2wARW1wdHkgQ29udGVudC1MZW5ndGgASW52YWxpZCBjaGFyYWN0ZXIgaW4gQ29udGVudC1MZW5ndGgAVHJhbnNmZXItRW5jb2RpbmcgY2FuJ3QgYmUgcHJlc2VudCB3aXRoIENvbnRlbnQtTGVuZ3RoAER1cGxpY2F0ZSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXIgaW4gdXJsIHBhdGgAQ29udGVudC1MZW5ndGggY2FuJ3QgYmUgcHJlc2VudCB3aXRoIFRyYW5zZmVyLUVuY29kaW5nAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgY2h1bmsgc2l6ZQBFeHBlY3RlZCBMRiBhZnRlciBjaHVuayBzaXplAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIHNpemUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfdmFsdWUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyB2YWx1ZQBVbmV4cGVjdGVkIHdoaXRlc3BhY2UgYWZ0ZXIgaGVhZGVyIHZhbHVlAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgaGVhZGVyIHZhbHVlAE1pc3NpbmcgZXhwZWN0ZWQgTEYgYWZ0ZXIgaGVhZGVyIHZhbHVlAEludmFsaWQgYFRyYW5zZmVyLUVuY29kaW5nYCBoZWFkZXIgdmFsdWUATWlzc2luZyBleHBlY3RlZCBDUiBhZnRlciBjaHVuayBleHRlbnNpb24gdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBxdW90ZSB2YWx1ZQBJbnZhbGlkIHF1b3RlZC1wYWlyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAFBhdXNlZCBieSBvbl9oZWFkZXJzX2NvbXBsZXRlAEludmFsaWQgRU9GIHN0YXRlAG9uX3Jlc2V0IHBhdXNlAG9uX2NodW5rX2hlYWRlciBwYXVzZQBvbl9tZXNzYWdlX2JlZ2luIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl92YWx1ZSBwYXVzZQBvbl9zdGF0dXNfY29tcGxldGUgcGF1c2UAb25fdmVyc2lvbl9jb21wbGV0ZSBwYXVzZQBvbl91cmxfY29tcGxldGUgcGF1c2UAb25fcHJvdG9jb2xfY29tcGxldGUgcGF1c2UAb25fY2h1bmtfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX3ZhbHVlX2NvbXBsZXRlIHBhdXNlAG9uX21lc3NhZ2VfY29tcGxldGUgcGF1c2UAb25fbWV0aG9kX2NvbXBsZXRlIHBhdXNlAG9uX2hlYWRlcl9maWVsZF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19leHRlbnNpb25fbmFtZSBwYXVzZQBVbmV4cGVjdGVkIHNwYWNlIGFmdGVyIHN0YXJ0IGxpbmUATWlzc2luZyBleHBlY3RlZCBDUiBhZnRlciByZXNwb25zZSBsaW5lAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fY2h1bmtfZXh0ZW5zaW9uX25hbWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBuYW1lAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgY2h1bmsgZXh0ZW5zaW9uIG5hbWUASW52YWxpZCBzdGF0dXMgY29kZQBQYXVzZSBvbiBDT05ORUNUL1VwZ3JhZGUAUGF1c2Ugb24gUFJJL1VwZ3JhZGUARXhwZWN0ZWQgSFRUUC8yIENvbm5lY3Rpb24gUHJlZmFjZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX21ldGhvZABFeHBlY3RlZCBzcGFjZSBhZnRlciBtZXRob2QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfZmllbGQAUGF1c2VkAEludmFsaWQgd29yZCBlbmNvdW50ZXJlZABJbnZhbGlkIG1ldGhvZCBlbmNvdW50ZXJlZABNaXNzaW5nIGV4cGVjdGVkIENSIGFmdGVyIGNodW5rIGRhdGEARXhwZWN0ZWQgTEYgYWZ0ZXIgY2h1bmsgZGF0YQBVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNjaGVtYQBSZXF1ZXN0IGhhcyBpbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AARGF0YSBhZnRlciBgQ29ubmVjdGlvbjogY2xvc2VgAFNXSVRDSF9QUk9YWQBVU0VfUFJPWFkATUtBQ1RJVklUWQBVTlBST0NFU1NBQkxFX0VOVElUWQBRVUVSWQBDT1BZAE1PVkVEX1BFUk1BTkVOVExZAFRPT19FQVJMWQBOT1RJRlkARkFJTEVEX0RFUEVOREVOQ1kAQkFEX0dBVEVXQVkAUExBWQBQVVQAQ0hFQ0tPVVQAR0FURVdBWV9USU1FT1VUAFJFUVVFU1RfVElNRU9VVABORVRXT1JLX0NPTk5FQ1RfVElNRU9VVABDT05ORUNUSU9OX1RJTUVPVVQATE9HSU5fVElNRU9VVABORVRXT1JLX1JFQURfVElNRU9VVABQT1NUAE1JU0RJUkVDVEVEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9SRVFVRVNUAENMSUVOVF9DTE9TRURfTE9BRF9CQUxBTkNFRF9SRVFVRVNUAEJBRF9SRVFVRVNUAEhUVFBfUkVRVUVTVF9TRU5UX1RPX0hUVFBTX1BPUlQAUkVQT1JUAElNX0FfVEVBUE9UAFJFU0VUX0NPTlRFTlQATk9fQ09OVEVOVABQQVJUSUFMX0NPTlRFTlQASFBFX0lOVkFMSURfQ09OU1RBTlQASFBFX0NCX1JFU0VUAEdFVABIUEVfU1RSSUNUAENPTkZMSUNUAFRFTVBPUkFSWV9SRURJUkVDVABQRVJNQU5FTlRfUkVESVJFQ1QAQ09OTkVDVABNVUxUSV9TVEFUVVMASFBFX0lOVkFMSURfU1RBVFVTAFRPT19NQU5ZX1JFUVVFU1RTAEVBUkxZX0hJTlRTAFVOQVZBSUxBQkxFX0ZPUl9MRUdBTF9SRUFTT05TAE9QVElPTlMAU1dJVENISU5HX1BST1RPQ09MUwBWQVJJQU5UX0FMU09fTkVHT1RJQVRFUwBNVUxUSVBMRV9DSE9JQ0VTAElOVEVSTkFMX1NFUlZFUl9FUlJPUgBXRUJfU0VSVkVSX1VOS05PV05fRVJST1IAUkFJTEdVTl9FUlJPUgBJREVOVElUWV9QUk9WSURFUl9BVVRIRU5USUNBVElPTl9FUlJPUgBTU0xfQ0VSVElGSUNBVEVfRVJST1IASU5WQUxJRF9YX0ZPUldBUkRFRF9GT1IAU0VUX1BBUkFNRVRFUgBHRVRfUEFSQU1FVEVSAEhQRV9VU0VSAFNFRV9PVEhFUgBIUEVfQ0JfQ0hVTktfSEVBREVSAEV4cGVjdGVkIExGIGFmdGVyIENSAE1LQ0FMRU5EQVIAU0VUVVAAV0VCX1NFUlZFUl9JU19ET1dOAFRFQVJET1dOAEhQRV9DTE9TRURfQ09OTkVDVElPTgBIRVVSSVNUSUNfRVhQSVJBVElPTgBESVNDT05ORUNURURfT1BFUkFUSU9OAE5PTl9BVVRIT1JJVEFUSVZFX0lORk9STUFUSU9OAEhQRV9JTlZBTElEX1ZFUlNJT04ASFBFX0NCX01FU1NBR0VfQkVHSU4AU0lURV9JU19GUk9aRU4ASFBFX0lOVkFMSURfSEVBREVSX1RPS0VOAElOVkFMSURfVE9LRU4ARk9SQklEREVOAEVOSEFOQ0VfWU9VUl9DQUxNAEhQRV9JTlZBTElEX1VSTABCTE9DS0VEX0JZX1BBUkVOVEFMX0NPTlRST0wATUtDT0wAQUNMAEhQRV9JTlRFUk5BTABSRVFVRVNUX0hFQURFUl9GSUVMRFNfVE9PX0xBUkdFX1VOT0ZGSUNJQUwASFBFX09LAFVOTElOSwBVTkxPQ0sAUFJJAFJFVFJZX1dJVEgASFBFX0lOVkFMSURfQ09OVEVOVF9MRU5HVEgASFBFX1VORVhQRUNURURfQ09OVEVOVF9MRU5HVEgARkxVU0gAUFJPUFBBVENIAE0tU0VBUkNIAFVSSV9UT09fTE9ORwBQUk9DRVNTSU5HAE1JU0NFTExBTkVPVVNfUEVSU0lTVEVOVF9XQVJOSU5HAE1JU0NFTExBTkVPVVNfV0FSTklORwBIUEVfSU5WQUxJRF9UUkFOU0ZFUl9FTkNPRElORwBFeHBlY3RlZCBDUkxGAEhQRV9JTlZBTElEX0NIVU5LX1NJWkUATU9WRQBDT05USU5VRQBIUEVfQ0JfU1RBVFVTX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJTX0NPTVBMRVRFAEhQRV9DQl9WRVJTSU9OX0NPTVBMRVRFAEhQRV9DQl9VUkxfQ09NUExFVEUASFBFX0NCX1BST1RPQ09MX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19DT01QTEVURQBIUEVfQ0JfSEVBREVSX1ZBTFVFX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19FWFRFTlNJT05fVkFMVUVfQ09NUExFVEUASFBFX0NCX0NIVU5LX0VYVEVOU0lPTl9OQU1FX0NPTVBMRVRFAEhQRV9DQl9NRVNTQUdFX0NPTVBMRVRFAEhQRV9DQl9NRVRIT0RfQ09NUExFVEUASFBFX0NCX0hFQURFUl9GSUVMRF9DT01QTEVURQBERUxFVEUASFBFX0lOVkFMSURfRU9GX1NUQVRFAElOVkFMSURfU1NMX0NFUlRJRklDQVRFAFBBVVNFAE5PX1JFU1BPTlNFAFVOU1VQUE9SVEVEX01FRElBX1RZUEUAR09ORQBOT1RfQUNDRVBUQUJMRQBTRVJWSUNFX1VOQVZBSUxBQkxFAFJBTkdFX05PVF9TQVRJU0ZJQUJMRQBPUklHSU5fSVNfVU5SRUFDSEFCTEUAUkVTUE9OU0VfSVNfU1RBTEUAUFVSR0UATUVSR0UAUkVRVUVTVF9IRUFERVJfRklFTERTX1RPT19MQVJHRQBSRVFVRVNUX0hFQURFUl9UT09fTEFSR0UAUEFZTE9BRF9UT09fTEFSR0UASU5TVUZGSUNJRU5UX1NUT1JBR0UASFBFX1BBVVNFRF9VUEdSQURFAEhQRV9QQVVTRURfSDJfVVBHUkFERQBTT1VSQ0UAQU5OT1VOQ0UAVFJBQ0UASFBFX1VORVhQRUNURURfU1BBQ0UAREVTQ1JJQkUAVU5TVUJTQ1JJQkUAUkVDT1JEAEhQRV9JTlZBTElEX01FVEhPRABOT1RfRk9VTkQAUFJPUEZJTkQAVU5CSU5EAFJFQklORABVTkFVVEhPUklaRUQATUVUSE9EX05PVF9BTExPV0VEAEhUVFBfVkVSU0lPTl9OT1RfU1VQUE9SVEVEAEFMUkVBRFlfUkVQT1JURUQAQUNDRVBURUQATk9UX0lNUExFTUVOVEVEAExPT1BfREVURUNURUQASFBFX0NSX0VYUEVDVEVEAEhQRV9MRl9FWFBFQ1RFRABDUkVBVEVEAElNX1VTRUQASFBFX1BBVVNFRABUSU1FT1VUX09DQ1VSRUQAUEFZTUVOVF9SRVFVSVJFRABQUkVDT05ESVRJT05fUkVRVUlSRUQAUFJPWFlfQVVUSEVOVElDQVRJT05fUkVRVUlSRUQATkVUV09SS19BVVRIRU5USUNBVElPTl9SRVFVSVJFRABMRU5HVEhfUkVRVUlSRUQAU1NMX0NFUlRJRklDQVRFX1JFUVVJUkVEAFVQR1JBREVfUkVRVUlSRUQAUEFHRV9FWFBJUkVEAFBSRUNPTkRJVElPTl9GQUlMRUQARVhQRUNUQVRJT05fRkFJTEVEAFJFVkFMSURBVElPTl9GQUlMRUQAU1NMX0hBTkRTSEFLRV9GQUlMRUQATE9DS0VEAFRSQU5TRk9STUFUSU9OX0FQUExJRUQATk9UX01PRElGSUVEAE5PVF9FWFRFTkRFRABCQU5EV0lEVEhfTElNSVRfRVhDRUVERUQAU0lURV9JU19PVkVSTE9BREVEAEhFQUQARXhwZWN0ZWQgSFRUUC8sIFJUU1AvIG9yIElDRS8A5xUAAK8VAACkEgAAkhoAACYWAACeFAAA2xkAAHkVAAB+EgAA/hQAADYVAAALFgAA2BYAAPMSAABCGAAArBYAABIVAAAUFwAA7xcAAEgUAABxFwAAshoAAGsZAAB+GQAANRQAAIIaAABEFwAA/RYAAB4YAACHFwAAqhkAAJMSAAAHGAAALBcAAMoXAACkFwAA5xUAAOcVAABYFwAAOxgAAKASAAAtHAAAwxEAAEgRAADeEgAAQhMAAKQZAAD9EAAA9xUAAKUVAADvFgAA+BkAAEoWAABWFgAA9RUAAAoaAAAIGgAAARoAAKsVAABCEgAA1xAAAEwRAAAFGQAAVBYAAB4RAADKGQAAyBkAAE4WAAD/GAAAcRQAAPAVAADuFQAAlBkAAPwVAAC/GQAAmxkAAHwUAABDEQAAcBgAAJUUAAAnFAAAGRQAANUSAADUGQAARBYAAPcQAEG5OwsBAQBB0DsL4AEBAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBuj0LBAEAAAIAQdE9C14DBAMDAwMDAAADAwADAwADAwMDAwMDAwMDAAUAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAwADAEG6PwsEAQAAAgBB0T8LXgMAAwMDAwMAAAMDAAMDAAMDAwMDAwMDAwMABAAFAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwADAAMAQbDBAAsNbG9zZWVlcC1hbGl2ZQBBycEACwEBAEHgwQAL4AEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBycMACwEBAEHgwwAL5wEBAQEBAQEBAQEBAQECAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAWNodW5rZWQAQfHFAAteAQABAQEBAQAAAQEAAQEAAQEBAQEBAQEBAQAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQBB0McACyFlY3Rpb25lbnQtbGVuZ3Rob25yb3h5LWNvbm5lY3Rpb24AQYDIAAsgcmFuc2Zlci1lbmNvZGluZ3BncmFkZQ0KDQpTTQ0KDQoAQanIAAsFAQIAAQMAQcDIAAtfBAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAQanKAAsFAQIAAQMAQcDKAAtfBAUFBgUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAQanMAAsEAQAAAQBBwcwAC14CAgACAgICAgICAgICAgICAgICAgICAgICAgICAgIAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAEGpzgALBQECAAEDAEHAzgALXwQFAAAFBQUFBQUFBQUFBQYFBQUFBQUFBQUFBQUABQAHCAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQAFAAUABQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAAAAFAEGp0AALBQEBAAEBAEHA0AALAQEAQdrQAAtBAgAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQanSAAsFAQEAAQEAQcDSAAsBAQBBytIACwYCAAAAAAIAQeHSAAs6AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBBoNQAC50BTk9VTkNFRUNLT1VUTkVDVEVURUNSSUJFTFVTSEVURUFEU0VBUkNIUkdFQ1RJVklUWUxFTkRBUlZFT1RJRllQVElPTlNDSFNFQVlTVEFUQ0hHRVVFUllPUkRJUkVDVE9SVFJDSFBBUkFNRVRFUlVSQ0VCU0NSSUJFQVJET1dOQUNFSU5ETktDS1VCU0NSSUJFVFRQQ0VUU1BBRFRQLw==",Cw;Object.defineProperty(p3,"exports",{get:()=>Cw||(Cw=Hfe.from(qfe,"base64"))})});var y3=x((jTe,E3)=>{"use strict";var{Buffer:Gfe}=Gr(),Yfe="AGFzbQEAAAABJwdgAX8Bf2ADf39/AX9gAn9/AGABfwBgBH9/f38Bf2AAAGADf39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQAEA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAAzU0BQYAAAMAAAAAAAADAQMAAwMDAAACAAAAAAICAgICAgICAgIBAQEBAQEBAQEBAwAAAwAAAAQFAXABExMFAwEAAgYIAX8BQcDZBAsHxQcoBm1lbW9yeQIAC19pbml0aWFsaXplAAgZX19pbmRpcmVjdF9mdW5jdGlvbl90YWJsZQEAC2xsaHR0cF9pbml0AAkYbGxodHRwX3Nob3VsZF9rZWVwX2FsaXZlADcMbGxodHRwX2FsbG9jAAsGbWFsbG9jADkLbGxodHRwX2ZyZWUADARmcmVlAAwPbGxodHRwX2dldF90eXBlAA0VbGxodHRwX2dldF9odHRwX21ham9yAA4VbGxodHRwX2dldF9odHRwX21pbm9yAA8RbGxodHRwX2dldF9tZXRob2QAEBZsbGh0dHBfZ2V0X3N0YXR1c19jb2RlABESbGxodHRwX2dldF91cGdyYWRlABIMbGxodHRwX3Jlc2V0ABMObGxodHRwX2V4ZWN1dGUAFBRsbGh0dHBfc2V0dGluZ3NfaW5pdAAVDWxsaHR0cF9maW5pc2gAFgxsbGh0dHBfcGF1c2UAFw1sbGh0dHBfcmVzdW1lABgbbGxodHRwX3Jlc3VtZV9hZnRlcl91cGdyYWRlABkQbGxodHRwX2dldF9lcnJubwAaF2xsaHR0cF9nZXRfZXJyb3JfcmVhc29uABsXbGxodHRwX3NldF9lcnJvcl9yZWFzb24AHBRsbGh0dHBfZ2V0X2Vycm9yX3BvcwAdEWxsaHR0cF9lcnJub19uYW1lAB4SbGxodHRwX21ldGhvZF9uYW1lAB8SbGxodHRwX3N0YXR1c19uYW1lACAabGxodHRwX3NldF9sZW5pZW50X2hlYWRlcnMAISFsbGh0dHBfc2V0X2xlbmllbnRfY2h1bmtlZF9sZW5ndGgAIh1sbGh0dHBfc2V0X2xlbmllbnRfa2VlcF9hbGl2ZQAjJGxsaHR0cF9zZXRfbGVuaWVudF90cmFuc2Zlcl9lbmNvZGluZwAkGmxsaHR0cF9zZXRfbGVuaWVudF92ZXJzaW9uACUjbGxodHRwX3NldF9sZW5pZW50X2RhdGFfYWZ0ZXJfY2xvc2UAJidsbGh0dHBfc2V0X2xlbmllbnRfb3B0aW9uYWxfbGZfYWZ0ZXJfY3IAJyxsbGh0dHBfc2V0X2xlbmllbnRfb3B0aW9uYWxfY3JsZl9hZnRlcl9jaHVuawAoKGxsaHR0cF9zZXRfbGVuaWVudF9vcHRpb25hbF9jcl9iZWZvcmVfbGYAKSpsbGh0dHBfc2V0X2xlbmllbnRfc3BhY2VzX2FmdGVyX2NodW5rX3NpemUAKhhsbGh0dHBfbWVzc2FnZV9uZWVkc19lb2YANgkYAQBBAQsSAQIDBAUKBgcyNDMuKy8tLDAxCuzaAjQWAEHA1QAoAgAEQAALQcDVAEEBNgIACxQAIAAQOCAAIAI2AjggACABOgAoCxQAIAAgAC8BNCAALQAwIAAQNxAACx4BAX9BwAAQOiIBEDggAUGACDYCOCABIAA6ACggAQuPDAEHfwJAIABFDQAgAEEIayIBIABBBGsoAgAiAEF4cSIEaiEFAkAgAEEBcQ0AIABBA3FFDQEgASABKAIAIgBrIgFB1NUAKAIASQ0BIAAgBGohBAJAAkBB2NUAKAIAIAFHBEAgAEH/AU0EQCAAQQN2IQMgASgCCCIAIAEoAgwiAkYEQEHE1QBBxNUAKAIAQX4gA3dxNgIADAULIAIgADYCCCAAIAI2AgwMBAsgASgCGCEGIAEgASgCDCIARwRAIAAgASgCCCICNgIIIAIgADYCDAwDCyABQRRqIgMoAgAiAkUEQCABKAIQIgJFDQIgAUEQaiEDCwNAIAMhByACIgBBFGoiAygCACICDQAgAEEQaiEDIAAoAhAiAg0ACyAHQQA2AgAMAgsgBSgCBCIAQQNxQQNHDQIgBSAAQX5xNgIEQczVACAENgIAIAUgBDYCACABIARBAXI2AgQMAwtBACEACyAGRQ0AAkAgASgCHCICQQJ0QfTXAGoiAygCACABRgRAIAMgADYCACAADQFByNUAQcjVACgCAEF+IAJ3cTYCAAwCCyAGQRBBFCAGKAIQIAFGG2ogADYCACAARQ0BCyAAIAY2AhggASgCECICBEAgACACNgIQIAIgADYCGAsgAUEUaigCACICRQ0AIABBFGogAjYCACACIAA2AhgLIAEgBU8NACAFKAIEIgBBAXFFDQACQAJAAkACQCAAQQJxRQRAQdzVACgCACAFRgRAQdzVACABNgIAQdDVAEHQ1QAoAgAgBGoiADYCACABIABBAXI2AgQgAUHY1QAoAgBHDQZBzNUAQQA2AgBB2NUAQQA2AgAMBgtB2NUAKAIAIAVGBEBB2NUAIAE2AgBBzNUAQczVACgCACAEaiIANgIAIAEgAEEBcjYCBCAAIAFqIAA2AgAMBgsgAEF4cSAEaiEEIABB/wFNBEAgAEEDdiEDIAUoAggiACAFKAIMIgJGBEBBxNUAQcTVACgCAEF+IAN3cTYCAAwFCyACIAA2AgggACACNgIMDAQLIAUoAhghBiAFIAUoAgwiAEcEQEHU1QAoAgAaIAAgBSgCCCICNgIIIAIgADYCDAwDCyAFQRRqIgMoAgAiAkUEQCAFKAIQIgJFDQIgBUEQaiEDCwNAIAMhByACIgBBFGoiAygCACICDQAgAEEQaiEDIAAoAhAiAg0ACyAHQQA2AgAMAgsgBSAAQX5xNgIEIAEgBGogBDYCACABIARBAXI2AgQMAwtBACEACyAGRQ0AAkAgBSgCHCICQQJ0QfTXAGoiAygCACAFRgRAIAMgADYCACAADQFByNUAQcjVACgCAEF+IAJ3cTYCAAwCCyAGQRBBFCAGKAIQIAVGG2ogADYCACAARQ0BCyAAIAY2AhggBSgCECICBEAgACACNgIQIAIgADYCGAsgBUEUaigCACICRQ0AIABBFGogAjYCACACIAA2AhgLIAEgBGogBDYCACABIARBAXI2AgQgAUHY1QAoAgBHDQBBzNUAIAQ2AgAMAQsgBEH/AU0EQCAEQXhxQezVAGohAAJ/QcTVACgCACICQQEgBEEDdnQiA3FFBEBBxNUAIAIgA3I2AgAgAAwBCyAAKAIICyICIAE2AgwgACABNgIIIAEgADYCDCABIAI2AggMAQtBHyECIARB////B00EQCAEQSYgBEEIdmciAGt2QQFxIABBAXRrQT5qIQILIAEgAjYCHCABQgA3AhAgAkECdEH01wBqIQACQEHI1QAoAgAiA0EBIAJ0IgdxRQRAIAAgATYCAEHI1QAgAyAHcjYCACABIAA2AhggASABNgIIIAEgATYCDAwBCyAEQRkgAkEBdmtBACACQR9HG3QhAiAAKAIAIQACQANAIAAiAygCBEF4cSAERg0BIAJBHXYhACACQQF0IQIgAyAAQQRxakEQaiIHKAIAIgANAAsgByABNgIAIAEgAzYCGCABIAE2AgwgASABNgIIDAELIAMoAggiACABNgIMIAMgATYCCCABQQA2AhggASADNgIMIAEgADYCCAtB5NUAQeTVACgCAEEBayIAQX8gABs2AgALCwcAIAAtACgLBwAgAC0AKgsHACAALQArCwcAIAAtACkLBwAgAC8BNAsHACAALQAwC0ABBH8gACgCGCEBIAAvAS4hAiAALQAoIQMgACgCOCEEIAAQOCAAIAQ2AjggACADOgAoIAAgAjsBLiAAIAE2AhgLhocCAwd/A34BeyABIAJqIQQCQCAAIgMoAgwiAA0AIAMoAgQEQCADIAE2AgQLIwBBEGsiCSQAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADKAIcIgJBAmsO/AEB+QECAwQFBgcICQoLDA0ODxAREvgBE/cBFBX2ARYX9QEYGRobHB0eHyD9AfsBIfQBIiMkJSYnKCkqK/MBLC0uLzAxMvIB8QEzNPAB7wE1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk/6AVBRUlPuAe0BVOwBVesBVldYWVrqAVtcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AAYEBggGDAYQBhQGGAYcBiAGJAYoBiwGMAY0BjgGPAZABkQGSAZMBlAGVAZYBlwGYAZkBmgGbAZwBnQGeAZ8BoAGhAaIBowGkAaUBpgGnAagBqQGqAasBrAGtAa4BrwGwAbEBsgGzAbQBtQG2AbcBuAG5AboBuwG8Ab0BvgG/AcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQHOAekB6AHPAecB0AHmAdEB0gHTAdQB5QHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wEA/AELQQAM4wELQQ4M4gELQQ0M4QELQQ8M4AELQRAM3wELQRMM3gELQRQM3QELQRUM3AELQRYM2wELQRcM2gELQRgM2QELQRkM2AELQRoM1wELQRsM1gELQRwM1QELQR0M1AELQR4M0wELQR8M0gELQSAM0QELQSEM0AELQQgMzwELQSIMzgELQSQMzQELQSMMzAELQQcMywELQSUMygELQSYMyQELQScMyAELQSgMxwELQRIMxgELQREMxQELQSkMxAELQSoMwwELQSsMwgELQSwMwQELQd4BDMABC0EuDL8BC0EvDL4BC0EwDL0BC0ExDLwBC0EyDLsBC0EzDLoBC0E0DLkBC0HfAQy4AQtBNQy3AQtBOQy2AQtBDAy1AQtBNgy0AQtBNwyzAQtBOAyyAQtBPgyxAQtBOgywAQtB4AEMrwELQQsMrgELQT8MrQELQTsMrAELQQoMqwELQTwMqgELQT0MqQELQeEBDKgBC0HBAAynAQtBwAAMpgELQcIADKUBC0EJDKQBC0EtDKMBC0HDAAyiAQtBxAAMoQELQcUADKABC0HGAAyfAQtBxwAMngELQcgADJ0BC0HJAAycAQtBygAMmwELQcsADJoBC0HMAAyZAQtBzQAMmAELQc4ADJcBC0HPAAyWAQtB0AAMlQELQdEADJQBC0HSAAyTAQtB0wAMkgELQdUADJEBC0HUAAyQAQtB1gAMjwELQdcADI4BC0HYAAyNAQtB2QAMjAELQdoADIsBC0HbAAyKAQtB3AAMiQELQd0ADIgBC0HeAAyHAQtB3wAMhgELQeAADIUBC0HhAAyEAQtB4gAMgwELQeMADIIBC0HkAAyBAQtB5QAMgAELQeIBDH8LQeYADH4LQecADH0LQQYMfAtB6AAMewtBBQx6C0HpAAx5C0EEDHgLQeoADHcLQesADHYLQewADHULQe0ADHQLQQMMcwtB7gAMcgtB7wAMcQtB8AAMcAtB8gAMbwtB8QAMbgtB8wAMbQtB9AAMbAtB9QAMawtB9gAMagtBAgxpC0H3AAxoC0H4AAxnC0H5AAxmC0H6AAxlC0H7AAxkC0H8AAxjC0H9AAxiC0H+AAxhC0H/AAxgC0GAAQxfC0GBAQxeC0GCAQxdC0GDAQxcC0GEAQxbC0GFAQxaC0GGAQxZC0GHAQxYC0GIAQxXC0GJAQxWC0GKAQxVC0GLAQxUC0GMAQxTC0GNAQxSC0GOAQxRC0GPAQxQC0GQAQxPC0GRAQxOC0GSAQxNC0GTAQxMC0GUAQxLC0GVAQxKC0GWAQxJC0GXAQxIC0GYAQxHC0GZAQxGC0GaAQxFC0GbAQxEC0GcAQxDC0GdAQxCC0GeAQxBC0GfAQxAC0GgAQw/C0GhAQw+C0GiAQw9C0GjAQw8C0GkAQw7C0GlAQw6C0GmAQw5C0GnAQw4C0GoAQw3C0GpAQw2C0GqAQw1C0GrAQw0C0GsAQwzC0GtAQwyC0GuAQwxC0GvAQwwC0GwAQwvC0GxAQwuC0GyAQwtC0GzAQwsC0G0AQwrC0G1AQwqC0G2AQwpC0G3AQwoC0G4AQwnC0G5AQwmC0G6AQwlC0G7AQwkC0G8AQwjC0G9AQwiC0G+AQwhC0G/AQwgC0HAAQwfC0HBAQweC0HCAQwdC0EBDBwLQcMBDBsLQcQBDBoLQcUBDBkLQcYBDBgLQccBDBcLQcgBDBYLQckBDBULQcoBDBQLQcsBDBMLQcwBDBILQc0BDBELQc4BDBALQc8BDA8LQdABDA4LQdEBDA0LQdIBDAwLQdMBDAsLQdQBDAoLQdUBDAkLQdYBDAgLQeMBDAcLQdcBDAYLQdgBDAULQdkBDAQLQdoBDAMLQdsBDAILQd0BDAELQdwBCyECA0ACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAMCfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAAn8CQAJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAwJ/AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJ/AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCACDuMBAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISMkJScoKZ4DmwOaA5EDigODA4AD/QL7AvgC8gLxAu8C7QLoAucC5gLlAuQC3ALbAtoC2QLYAtcC1gLVAs8CzgLMAssCygLJAsgCxwLGAsQCwwK+ArwCugK5ArgCtwK2ArUCtAKzArICsQKwAq4CrQKpAqgCpwKmAqUCpAKjAqICoQKgAp8CmAKQAowCiwKKAoEC/gH9AfwB+wH6AfkB+AH3AfUB8wHwAesB6QHoAecB5gHlAeQB4wHiAeEB4AHfAd4B3QHcAdoB2QHYAdcB1gHVAdQB0wHSAdEB0AHPAc4BzQHMAcsBygHJAcgBxwHGAcUBxAHDAcIBwQHAAb8BvgG9AbwBuwG6AbkBuAG3AbYBtQG0AbMBsgGxAbABrwGuAa0BrAGrAaoBqQGoAacBpgGlAaQBowGiAZ8BngGZAZgBlwGWAZUBlAGTAZIBkQGQAY8BjQGMAYcBhgGFAYQBgwGCAX18e3p5dnV0UFFSU1RVCyABIARHDXJB/QEhAgy+AwsgASAERw2YAUHbASECDL0DCyABIARHDfEBQY4BIQIMvAMLIAEgBEcN/AFBhAEhAgy7AwsgASAERw2KAkH/ACECDLoDCyABIARHDZECQf0AIQIMuQMLIAEgBEcNlAJB+wAhAgy4AwsgASAERw0eQR4hAgy3AwsgASAERw0ZQRghAgy2AwsgASAERw3KAkHNACECDLUDCyABIARHDdUCQcYAIQIMtAMLIAEgBEcN1gJBwwAhAgyzAwsgASAERw3cAkE4IQIMsgMLIAMtADBBAUYNrQMMiQMLQQAhAAJAAkACQCADLQAqRQ0AIAMtACtFDQAgAy8BMiICQQJxRQ0BDAILIAMvATIiAkEBcUUNAQtBASEAIAMtAChBAUYNACADLwE0IgZB5ABrQeQASQ0AIAZBzAFGDQAgBkGwAkYNACACQcAAcQ0AQQAhACACQYgEcUGABEYNACACQShxQQBHIQALIANBADsBMiADQQA6ADECQCAARQRAIANBADoAMSADLQAuQQRxDQEMsQMLIANCADcDIAsgA0EAOgAxIANBAToANgxIC0EAIQACQCADKAI4IgJFDQAgAigCMCICRQ0AIAMgAhEAACEACyAARQ1IIABBFUcNYiADQQQ2AhwgAyABNgIUIANB0hs2AhAgA0EVNgIMQQAhAgyvAwsgASAERgRAQQYhAgyvAwsgAS0AAEEKRw0ZIAFBAWohAQwaCyADQgA3AyBBEiECDJQDCyABIARHDYoDQSMhAgysAwsgASAERgRAQQchAgysAwsCQAJAIAEtAABBCmsOBAEYGAAYCyABQQFqIQFBECECDJMDCyABQQFqIQEgA0Evai0AAEEBcQ0XQQAhAiADQQA2AhwgAyABNgIUIANBmSA2AhAgA0EZNgIMDKsDCyADIAMpAyAiDCAEIAFrrSIKfSILQgAgCyAMWBs3AyAgCiAMWg0YQQghAgyqAwsgASAERwRAIANBCTYCCCADIAE2AgRBFCECDJEDC0EJIQIMqQMLIAMpAyBQDa4CDEMLIAEgBEYEQEELIQIMqAMLIAEtAABBCkcNFiABQQFqIQEMFwsgA0Evai0AAEEBcUUNGQwmC0EAIQACQCADKAI4IgJFDQAgAigCUCICRQ0AIAMgAhEAACEACyAADRkMQgtBACEAAkAgAygCOCICRQ0AIAIoAlAiAkUNACADIAIRAAAhAAsgAA0aDCQLQQAhAAJAIAMoAjgiAkUNACACKAJQIgJFDQAgAyACEQAAIQALIAANGwwyCyADQS9qLQAAQQFxRQ0cDCILQQAhAAJAIAMoAjgiAkUNACACKAJUIgJFDQAgAyACEQAAIQALIAANHAxCC0EAIQACQCADKAI4IgJFDQAgAigCVCICRQ0AIAMgAhEAACEACyAADR0MIAsgASAERgRAQRMhAgygAwsCQCABLQAAIgBBCmsOBB8jIwAiCyABQQFqIQEMHwtBACEAAkAgAygCOCICRQ0AIAIoAlQiAkUNACADIAIRAAAhAAsgAA0iDEILIAEgBEYEQEEWIQIMngMLIAEtAABBwMEAai0AAEEBRw0jDIMDCwJAA0AgAS0AAEGwO2otAAAiAEEBRwRAAkAgAEECaw4CAwAnCyABQQFqIQFBISECDIYDCyAEIAFBAWoiAUcNAAtBGCECDJ0DCyADKAIEIQBBACECIANBADYCBCADIAAgAUEBaiIBEDQiAA0hDEELQQAhAAJAIAMoAjgiAkUNACACKAJUIgJFDQAgAyACEQAAIQALIAANIwwqCyABIARGBEBBHCECDJsDCyADQQo2AgggAyABNgIEQQAhAAJAIAMoAjgiAkUNACACKAJQIgJFDQAgAyACEQAAIQALIAANJUEkIQIMgQMLIAEgBEcEQANAIAEtAABBsD1qLQAAIgBBA0cEQCAAQQFrDgUYGiaCAyUmCyAEIAFBAWoiAUcNAAtBGyECDJoDC0EbIQIMmQMLA0AgAS0AAEGwP2otAAAiAEEDRwRAIABBAWsOBQ8RJxMmJwsgBCABQQFqIgFHDQALQR4hAgyYAwsgASAERwRAIANBCzYCCCADIAE2AgRBByECDP8CC0EfIQIMlwMLIAEgBEYEQEEgIQIMlwMLAkAgAS0AAEENaw4ULj8/Pz8/Pz8/Pz8/Pz8/Pz8/PwA/C0EAIQIgA0EANgIcIANBvws2AhAgA0ECNgIMIAMgAUEBajYCFAyWAwsgA0EvaiECA0AgASAERgRAQSEhAgyXAwsCQAJAAkAgAS0AACIAQQlrDhgCACkpASkpKSkpKSkpKSkpKSkpKSkpKQInCyABQQFqIQEgA0Evai0AAEEBcUUNCgwYCyABQQFqIQEMFwsgAUEBaiEBIAItAABBAnENAAtBACECIANBADYCHCADIAE2AhQgA0GfFTYCECADQQw2AgwMlQMLIAMtAC5BgAFxRQ0BC0EAIQACQCADKAI4IgJFDQAgAigCXCICRQ0AIAMgAhEAACEACyAARQ3mAiAAQRVGBEAgA0EkNgIcIAMgATYCFCADQZsbNgIQIANBFTYCDEEAIQIMlAMLQQAhAiADQQA2AhwgAyABNgIUIANBkA42AhAgA0EUNgIMDJMDC0EAIQIgA0EANgIcIAMgATYCFCADQb4gNgIQIANBAjYCDAySAwsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEgDKdqIgEQMiIARQ0rIANBBzYCHCADIAE2AhQgAyAANgIMDJEDCyADLQAuQcAAcUUNAQtBACEAAkAgAygCOCICRQ0AIAIoAlgiAkUNACADIAIRAAAhAAsgAEUNKyAAQRVGBEAgA0EKNgIcIAMgATYCFCADQesZNgIQIANBFTYCDEEAIQIMkAMLQQAhAiADQQA2AhwgAyABNgIUIANBkww2AhAgA0ETNgIMDI8DC0EAIQIgA0EANgIcIAMgATYCFCADQYIVNgIQIANBAjYCDAyOAwtBACECIANBADYCHCADIAE2AhQgA0HdFDYCECADQRk2AgwMjQMLQQAhAiADQQA2AhwgAyABNgIUIANB5h02AhAgA0EZNgIMDIwDCyAAQRVGDT1BACECIANBADYCHCADIAE2AhQgA0HQDzYCECADQSI2AgwMiwMLIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDMiAEUNKCADQQ02AhwgAyABNgIUIAMgADYCDAyKAwsgAEEVRg06QQAhAiADQQA2AhwgAyABNgIUIANB0A82AhAgA0EiNgIMDIkDCyADKAIEIQBBACECIANBADYCBCADIAAgARAzIgBFBEAgAUEBaiEBDCgLIANBDjYCHCADIAA2AgwgAyABQQFqNgIUDIgDCyAAQRVGDTdBACECIANBADYCHCADIAE2AhQgA0HQDzYCECADQSI2AgwMhwMLIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDMiAEUEQCABQQFqIQEMJwsgA0EPNgIcIAMgADYCDCADIAFBAWo2AhQMhgMLQQAhAiADQQA2AhwgAyABNgIUIANB4hc2AhAgA0EZNgIMDIUDCyAAQRVGDTNBACECIANBADYCHCADIAE2AhQgA0HWDDYCECADQSM2AgwMhAMLIAMoAgQhAEEAIQIgA0EANgIEIAMgACABEDQiAEUNJSADQRE2AhwgAyABNgIUIAMgADYCDAyDAwsgAEEVRg0wQQAhAiADQQA2AhwgAyABNgIUIANB1gw2AhAgA0EjNgIMDIIDCyADKAIEIQBBACECIANBADYCBCADIAAgARA0IgBFBEAgAUEBaiEBDCULIANBEjYCHCADIAA2AgwgAyABQQFqNgIUDIEDCyADQS9qLQAAQQFxRQ0BC0EXIQIM5gILQQAhAiADQQA2AhwgAyABNgIUIANB4hc2AhAgA0EZNgIMDP4CCyAAQTtHDQAgAUEBaiEBDAwLQQAhAiADQQA2AhwgAyABNgIUIANBkhg2AhAgA0ECNgIMDPwCCyAAQRVGDShBACECIANBADYCHCADIAE2AhQgA0HWDDYCECADQSM2AgwM+wILIANBFDYCHCADIAE2AhQgAyAANgIMDPoCCyADKAIEIQBBACECIANBADYCBCADIAAgARA0IgBFBEAgAUEBaiEBDPUCCyADQRU2AhwgAyAANgIMIAMgAUEBajYCFAz5AgsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQzzAgsgA0EXNgIcIAMgADYCDCADIAFBAWo2AhQM+AILIABBFUYNI0EAIQIgA0EANgIcIAMgATYCFCADQdYMNgIQIANBIzYCDAz3AgsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQwdCyADQRk2AhwgAyAANgIMIAMgAUEBajYCFAz2AgsgAygCBCEAQQAhAiADQQA2AgQgAyAAIAEQNCIARQRAIAFBAWohAQzvAgsgA0EaNgIcIAMgADYCDCADIAFBAWo2AhQM9QILIABBFUYNH0EAIQIgA0EANgIcIAMgATYCFCADQdAPNgIQIANBIjYCDAz0AgsgAygCBCEAIANBADYCBCADIAAgARAzIgBFBEAgAUEBaiEBDBsLIANBHDYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgzzAgsgAygCBCEAIANBADYCBCADIAAgARAzIgBFBEAgAUEBaiEBDOsCCyADQR02AhwgAyAANgIMIAMgAUEBajYCFEEAIQIM8gILIABBO0cNASABQQFqIQELQSYhAgzXAgtBACECIANBADYCHCADIAE2AhQgA0GfFTYCECADQQw2AgwM7wILIAEgBEcEQANAIAEtAABBIEcNhAIgBCABQQFqIgFHDQALQSwhAgzvAgtBLCECDO4CCyABIARGBEBBNCECDO4CCwJAAkADQAJAIAEtAABBCmsOBAIAAAMACyAEIAFBAWoiAUcNAAtBNCECDO8CCyADKAIEIQAgA0EANgIEIAMgACABEDEiAEUNnwIgA0EyNgIcIAMgATYCFCADIAA2AgxBACECDO4CCyADKAIEIQAgA0EANgIEIAMgACABEDEiAEUEQCABQQFqIQEMnwILIANBMjYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgztAgsgASAERwRAAkADQCABLQAAQTBrIgBB/wFxQQpPBEBBOiECDNcCCyADKQMgIgtCmbPmzJmz5swZVg0BIAMgC0IKfiIKNwMgIAogAK1C/wGDIgtCf4VWDQEgAyAKIAt8NwMgIAQgAUEBaiIBRw0AC0HAACECDO4CCyADKAIEIQAgA0EANgIEIAMgACABQQFqIgEQMSIADRcM4gILQcAAIQIM7AILIAEgBEYEQEHJACECDOwCCwJAA0ACQCABLQAAQQlrDhgAAqICogKpAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAgCiAgsgBCABQQFqIgFHDQALQckAIQIM7AILIAFBAWohASADQS9qLQAAQQFxDaUCIANBADYCHCADIAE2AhQgA0GXEDYCECADQQo2AgxBACECDOsCCyABIARHBEADQCABLQAAQSBHDRUgBCABQQFqIgFHDQALQfgAIQIM6wILQfgAIQIM6gILIANBAjoAKAw4C0EAIQIgA0EANgIcIANBvws2AhAgA0ECNgIMIAMgAUEBajYCFAzoAgtBACECDM4CC0ENIQIMzQILQRMhAgzMAgtBFSECDMsCC0EWIQIMygILQRghAgzJAgtBGSECDMgCC0EaIQIMxwILQRshAgzGAgtBHCECDMUCC0EdIQIMxAILQR4hAgzDAgtBHyECDMICC0EgIQIMwQILQSIhAgzAAgtBIyECDL8CC0ElIQIMvgILQeUAIQIMvQILIANBPTYCHCADIAE2AhQgAyAANgIMQQAhAgzVAgsgA0EbNgIcIAMgATYCFCADQaQcNgIQIANBFTYCDEEAIQIM1AILIANBIDYCHCADIAE2AhQgA0GYGjYCECADQRU2AgxBACECDNMCCyADQRM2AhwgAyABNgIUIANBmBo2AhAgA0EVNgIMQQAhAgzSAgsgA0ELNgIcIAMgATYCFCADQZgaNgIQIANBFTYCDEEAIQIM0QILIANBEDYCHCADIAE2AhQgA0GYGjYCECADQRU2AgxBACECDNACCyADQSA2AhwgAyABNgIUIANBpBw2AhAgA0EVNgIMQQAhAgzPAgsgA0ELNgIcIAMgATYCFCADQaQcNgIQIANBFTYCDEEAIQIMzgILIANBDDYCHCADIAE2AhQgA0GkHDYCECADQRU2AgxBACECDM0CC0EAIQIgA0EANgIcIAMgATYCFCADQd0ONgIQIANBEjYCDAzMAgsCQANAAkAgAS0AAEEKaw4EAAICAAILIAQgAUEBaiIBRw0AC0H9ASECDMwCCwJAAkAgAy0ANkEBRw0AQQAhAAJAIAMoAjgiAkUNACACKAJgIgJFDQAgAyACEQAAIQALIABFDQAgAEEVRw0BIANB/AE2AhwgAyABNgIUIANB3Bk2AhAgA0EVNgIMQQAhAgzNAgtB3AEhAgyzAgsgA0EANgIcIAMgATYCFCADQfkLNgIQIANBHzYCDEEAIQIMywILAkACQCADLQAoQQFrDgIEAQALQdsBIQIMsgILQdQBIQIMsQILIANBAjoAMUEAIQACQCADKAI4IgJFDQAgAigCACICRQ0AIAMgAhEAACEACyAARQRAQd0BIQIMsQILIABBFUcEQCADQQA2AhwgAyABNgIUIANBtAw2AhAgA0EQNgIMQQAhAgzKAgsgA0H7ATYCHCADIAE2AhQgA0GBGjYCECADQRU2AgxBACECDMkCCyABIARGBEBB+gEhAgzJAgsgAS0AAEHIAEYNASADQQE6ACgLQcABIQIMrgILQdoBIQIMrQILIAEgBEcEQCADQQw2AgggAyABNgIEQdkBIQIMrQILQfkBIQIMxQILIAEgBEYEQEH4ASECDMUCCyABLQAAQcgARw0EIAFBAWohAUHYASECDKsCCyABIARGBEBB9wEhAgzEAgsCQAJAIAEtAABBxQBrDhAABQUFBQUFBQUFBQUFBQUBBQsgAUEBaiEBQdYBIQIMqwILIAFBAWohAUHXASECDKoCC0H2ASECIAEgBEYNwgIgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABButUAai0AAEcNAyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMwwILIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARAuIgBFBEBB4wEhAgyqAgsgA0H1ATYCHCADIAE2AhQgAyAANgIMQQAhAgzCAgtB9AEhAiABIARGDcECIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQbjVAGotAABHDQIgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADMICCyADQYEEOwEoIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARAuIgANAwwCCyADQQA2AgALQQAhAiADQQA2AhwgAyABNgIUIANB5R82AhAgA0EINgIMDL8CC0HVASECDKUCCyADQfMBNgIcIAMgATYCFCADIAA2AgxBACECDL0CC0EAIQACQCADKAI4IgJFDQAgAigCQCICRQ0AIAMgAhEAACEACyAARQ1uIABBFUcEQCADQQA2AhwgAyABNgIUIANBgg82AhAgA0EgNgIMQQAhAgy9AgsgA0GPATYCHCADIAE2AhQgA0HsGzYCECADQRU2AgxBACECDLwCCyABIARHBEAgA0ENNgIIIAMgATYCBEHTASECDKMCC0HyASECDLsCCyABIARGBEBB8QEhAgy7AgsCQAJAAkAgAS0AAEHIAGsOCwABCAgICAgICAgCCAsgAUEBaiEBQdABIQIMowILIAFBAWohAUHRASECDKICCyABQQFqIQFB0gEhAgyhAgtB8AEhAiABIARGDbkCIAMoAgAiACAEIAFraiEGIAEgAGtBAmohBQNAIAEtAAAgAEG11QBqLQAARw0EIABBAkYNAyAAQQFqIQAgBCABQQFqIgFHDQALIAMgBjYCAAy5AgtB7wEhAiABIARGDbgCIAMoAgAiACAEIAFraiEGIAEgAGtBAWohBQNAIAEtAAAgAEGz1QBqLQAARw0DIABBAUYNAiAAQQFqIQAgBCABQQFqIgFHDQALIAMgBjYCAAy4AgtB7gEhAiABIARGDbcCIAMoAgAiACAEIAFraiEGIAEgAGtBAmohBQNAIAEtAAAgAEGw1QBqLQAARw0CIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBjYCAAy3AgsgAygCBCEAIANCADcDACADIAAgBUEBaiIBECsiAEUNAiADQewBNgIcIAMgATYCFCADIAA2AgxBACECDLYCCyADQQA2AgALIAMoAgQhACADQQA2AgQgAyAAIAEQKyIARQ2cAiADQe0BNgIcIAMgATYCFCADIAA2AgxBACECDLQCC0HPASECDJoCC0EAIQACQCADKAI4IgJFDQAgAigCNCICRQ0AIAMgAhEAACEACwJAIAAEQCAAQRVGDQEgA0EANgIcIAMgATYCFCADQeoNNgIQIANBJjYCDEEAIQIMtAILQc4BIQIMmgILIANB6wE2AhwgAyABNgIUIANBgBs2AhAgA0EVNgIMQQAhAgyyAgsgASAERgRAQesBIQIMsgILIAEtAABBL0YEQCABQQFqIQEMAQsgA0EANgIcIAMgATYCFCADQbI4NgIQIANBCDYCDEEAIQIMsQILQc0BIQIMlwILIAEgBEcEQCADQQ42AgggAyABNgIEQcwBIQIMlwILQeoBIQIMrwILIAEgBEYEQEHpASECDK8CCyABLQAAQTBrIgBB/wFxQQpJBEAgAyAAOgAqIAFBAWohAUHLASECDJYCCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNlwIgA0HoATYCHCADIAE2AhQgAyAANgIMQQAhAgyuAgsgASAERgRAQecBIQIMrgILAkAgAS0AAEEuRgRAIAFBAWohAQwBCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNmAIgA0HmATYCHCADIAE2AhQgAyAANgIMQQAhAgyuAgtBygEhAgyUAgsgASAERgRAQeUBIQIMrQILQQAhAEEBIQVBASEHQQAhAgJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAIAEtAABBMGsOCgoJAAECAwQFBggLC0ECDAYLQQMMBQtBBAwEC0EFDAMLQQYMAgtBBwwBC0EICyECQQAhBUEAIQcMAgtBCSECQQEhAEEAIQVBACEHDAELQQAhBUEBIQILIAMgAjoAKyABQQFqIQECQAJAIAMtAC5BEHENAAJAAkACQCADLQAqDgMBAAIECyAHRQ0DDAILIAANAQwCCyAFRQ0BCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNAiADQeIBNgIcIAMgATYCFCADIAA2AgxBACECDK8CCyADKAIEIQAgA0EANgIEIAMgACABEC8iAEUNmgIgA0HjATYCHCADIAE2AhQgAyAANgIMQQAhAgyuAgsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDZgCIANB5AE2AhwgAyABNgIUIAMgADYCDAytAgtByQEhAgyTAgtBACEAAkAgAygCOCICRQ0AIAIoAkQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0GkDTYCECADQSE2AgxBACECDK0CC0HIASECDJMCCyADQeEBNgIcIAMgATYCFCADQdAaNgIQIANBFTYCDEEAIQIMqwILIAEgBEYEQEHhASECDKsCCwJAIAEtAABBIEYEQCADQQA7ATQgAUEBaiEBDAELIANBADYCHCADIAE2AhQgA0GZETYCECADQQk2AgxBACECDKsCC0HHASECDJECCyABIARGBEBB4AEhAgyqAgsCQCABLQAAQTBrQf8BcSICQQpJBEAgAUEBaiEBAkAgAy8BNCIAQZkzSw0AIAMgAEEKbCIAOwE0IABB/v8DcSACQf//A3NLDQAgAyAAIAJqOwE0DAILQQAhAiADQQA2AhwgAyABNgIUIANBlR42AhAgA0ENNgIMDKsCCyADQQA2AhwgAyABNgIUIANBlR42AhAgA0ENNgIMQQAhAgyqAgtBxgEhAgyQAgsgASAERgRAQd8BIQIMqQILAkAgAS0AAEEwa0H/AXEiAkEKSQRAIAFBAWohAQJAIAMvATQiAEGZM0sNACADIABBCmwiADsBNCAAQf7/A3EgAkH//wNzSw0AIAMgACACajsBNAwCC0EAIQIgA0EANgIcIAMgATYCFCADQZUeNgIQIANBDTYCDAyqAgsgA0EANgIcIAMgATYCFCADQZUeNgIQIANBDTYCDEEAIQIMqQILQcUBIQIMjwILIAEgBEYEQEHeASECDKgCCwJAIAEtAABBMGtB/wFxIgJBCkkEQCABQQFqIQECQCADLwE0IgBBmTNLDQAgAyAAQQpsIgA7ATQgAEH+/wNxIAJB//8Dc0sNACADIAAgAmo7ATQMAgtBACECIANBADYCHCADIAE2AhQgA0GVHjYCECADQQ02AgwMqQILIANBADYCHCADIAE2AhQgA0GVHjYCECADQQ02AgxBACECDKgCC0HEASECDI4CCyABIARGBEBB3QEhAgynAgsCQAJAAkACQCABLQAAQQprDhcCAwMAAwMDAwMDAwMDAwMDAwMDAwMDAQMLIAFBAWoMBQsgAUEBaiEBQcMBIQIMjwILIAFBAWohASADQS9qLQAAQQFxDQggA0EANgIcIAMgATYCFCADQY0LNgIQIANBDTYCDEEAIQIMpwILIANBADYCHCADIAE2AhQgA0GNCzYCECADQQ02AgxBACECDKYCCyABIARHBEAgA0EPNgIIIAMgATYCBEEBIQIMjQILQdwBIQIMpQILAkACQANAAkAgAS0AAEEKaw4EAgAAAwALIAQgAUEBaiIBRw0AC0HbASECDKYCCyADKAIEIQAgA0EANgIEIAMgACABEC0iAEUEQCABQQFqIQEMBAsgA0HaATYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgylAgsgAygCBCEAIANBADYCBCADIAAgARAtIgANASABQQFqCyEBQcEBIQIMigILIANB2QE2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMogILQcIBIQIMiAILIANBL2otAABBAXENASADQQA2AhwgAyABNgIUIANB5Bw2AhAgA0EZNgIMQQAhAgygAgsgASAERgRAQdkBIQIMoAILAkACQAJAIAEtAABBCmsOBAECAgACCyABQQFqIQEMAgsgAUEBaiEBDAELIAMtAC5BwABxRQ0BC0EAIQACQCADKAI4IgJFDQAgAigCPCICRQ0AIAMgAhEAACEACyAARQ2gASAAQRVGBEAgA0HZADYCHCADIAE2AhQgA0G3GjYCECADQRU2AgxBACECDJ8CCyADQQA2AhwgAyABNgIUIANBgA02AhAgA0EbNgIMQQAhAgyeAgsgA0EANgIcIAMgATYCFCADQdwoNgIQIANBAjYCDEEAIQIMnQILIAEgBEcEQCADQQw2AgggAyABNgIEQb8BIQIMhAILQdgBIQIMnAILIAEgBEYEQEHXASECDJwCCwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAS0AAEHBAGsOFQABAgNaBAUGWlpaBwgJCgsMDQ4PEFoLIAFBAWohAUH7ACECDJICCyABQQFqIQFB/AAhAgyRAgsgAUEBaiEBQYEBIQIMkAILIAFBAWohAUGFASECDI8CCyABQQFqIQFBhgEhAgyOAgsgAUEBaiEBQYkBIQIMjQILIAFBAWohAUGKASECDIwCCyABQQFqIQFBjQEhAgyLAgsgAUEBaiEBQZYBIQIMigILIAFBAWohAUGXASECDIkCCyABQQFqIQFBmAEhAgyIAgsgAUEBaiEBQaUBIQIMhwILIAFBAWohAUGmASECDIYCCyABQQFqIQFBrAEhAgyFAgsgAUEBaiEBQbQBIQIMhAILIAFBAWohAUG3ASECDIMCCyABQQFqIQFBvgEhAgyCAgsgASAERgRAQdYBIQIMmwILIAEtAABBzgBHDUggAUEBaiEBQb0BIQIMgQILIAEgBEYEQEHVASECDJoCCwJAAkACQCABLQAAQcIAaw4SAEpKSkpKSkpKSgFKSkpKSkoCSgsgAUEBaiEBQbgBIQIMggILIAFBAWohAUG7ASECDIECCyABQQFqIQFBvAEhAgyAAgtB1AEhAiABIARGDZgCIAMoAgAiACAEIAFraiEFIAEgAGtBB2ohBgJAA0AgAS0AACAAQajVAGotAABHDUUgAEEHRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJkCCyADQQA2AgAgBkEBaiEBQRsMRQsgASAERgRAQdMBIQIMmAILAkACQCABLQAAQckAaw4HAEdHR0dHAUcLIAFBAWohAUG5ASECDP8BCyABQQFqIQFBugEhAgz+AQtB0gEhAiABIARGDZYCIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQabVAGotAABHDUMgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJcCCyADQQA2AgAgBkEBaiEBQQ8MQwtB0QEhAiABIARGDZUCIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQaTVAGotAABHDUIgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJYCCyADQQA2AgAgBkEBaiEBQSAMQgtB0AEhAiABIARGDZQCIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQaHVAGotAABHDUEgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADJUCCyADQQA2AgAgBkEBaiEBQRIMQQsgASAERgRAQc8BIQIMlAILAkACQCABLQAAQcUAaw4OAENDQ0NDQ0NDQ0NDQwFDCyABQQFqIQFBtQEhAgz7AQsgAUEBaiEBQbYBIQIM+gELQc4BIQIgASAERg2SAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGe1QBqLQAARw0/IABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyTAgsgA0EANgIAIAZBAWohAUEHDD8LQc0BIQIgASAERg2RAiADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEGY1QBqLQAARw0+IABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAySAgsgA0EANgIAIAZBAWohAUEoDD4LIAEgBEYEQEHMASECDJECCwJAAkACQCABLQAAQcUAaw4RAEFBQUFBQUFBQQFBQUFBQQJBCyABQQFqIQFBsQEhAgz5AQsgAUEBaiEBQbIBIQIM+AELIAFBAWohAUGzASECDPcBC0HLASECIAEgBEYNjwIgAygCACIAIAQgAWtqIQUgASAAa0EGaiEGAkADQCABLQAAIABBkdUAai0AAEcNPCAAQQZGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMkAILIANBADYCACAGQQFqIQFBGgw8C0HKASECIAEgBEYNjgIgAygCACIAIAQgAWtqIQUgASAAa0EDaiEGAkADQCABLQAAIABBjdUAai0AAEcNOyAAQQNGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMjwILIANBADYCACAGQQFqIQFBIQw7CyABIARGBEBByQEhAgyOAgsCQAJAIAEtAABBwQBrDhQAPT09PT09PT09PT09PT09PT09AT0LIAFBAWohAUGtASECDPUBCyABQQFqIQFBsAEhAgz0AQsgASAERgRAQcgBIQIMjQILAkACQCABLQAAQdUAaw4LADw8PDw8PDw8PAE8CyABQQFqIQFBrgEhAgz0AQsgAUEBaiEBQa8BIQIM8wELQccBIQIgASAERg2LAiADKAIAIgAgBCABa2ohBSABIABrQQhqIQYCQANAIAEtAAAgAEGE1QBqLQAARw04IABBCEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyMAgsgA0EANgIAIAZBAWohAUEqDDgLIAEgBEYEQEHGASECDIsCCyABLQAAQdAARw04IAFBAWohAUElDDcLQcUBIQIgASAERg2JAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGB1QBqLQAARw02IABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyKAgsgA0EANgIAIAZBAWohAUEODDYLIAEgBEYEQEHEASECDIkCCyABLQAAQcUARw02IAFBAWohAUGrASECDO8BCyABIARGBEBBwwEhAgyIAgsCQAJAAkACQCABLQAAQcIAaw4PAAECOTk5OTk5OTk5OTkDOQsgAUEBaiEBQacBIQIM8QELIAFBAWohAUGoASECDPABCyABQQFqIQFBqQEhAgzvAQsgAUEBaiEBQaoBIQIM7gELQcIBIQIgASAERg2GAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEH+1ABqLQAARw0zIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyHAgsgA0EANgIAIAZBAWohAUEUDDMLQcEBIQIgASAERg2FAiADKAIAIgAgBCABa2ohBSABIABrQQRqIQYCQANAIAEtAAAgAEH51ABqLQAARw0yIABBBEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyGAgsgA0EANgIAIAZBAWohAUErDDILQcABIQIgASAERg2EAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEH21ABqLQAARw0xIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyFAgsgA0EANgIAIAZBAWohAUEsDDELQb8BIQIgASAERg2DAiADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGh1QBqLQAARw0wIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyEAgsgA0EANgIAIAZBAWohAUERDDALQb4BIQIgASAERg2CAiADKAIAIgAgBCABa2ohBSABIABrQQNqIQYCQANAIAEtAAAgAEHy1ABqLQAARw0vIABBA0YNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyDAgsgA0EANgIAIAZBAWohAUEuDC8LIAEgBEYEQEG9ASECDIICCwJAAkACQAJAAkAgAS0AAEHBAGsOFQA0NDQ0NDQ0NDQ0ATQ0AjQ0AzQ0BDQLIAFBAWohAUGbASECDOwBCyABQQFqIQFBnAEhAgzrAQsgAUEBaiEBQZ0BIQIM6gELIAFBAWohAUGiASECDOkBCyABQQFqIQFBpAEhAgzoAQsgASAERgRAQbwBIQIMgQILAkACQCABLQAAQdIAaw4DADABMAsgAUEBaiEBQaMBIQIM6AELIAFBAWohAUEEDC0LQbsBIQIgASAERg3/ASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHw1ABqLQAARw0sIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyAAgsgA0EANgIAIAZBAWohAUEdDCwLIAEgBEYEQEG6ASECDP8BCwJAAkAgAS0AAEHJAGsOBwEuLi4uLgAuCyABQQFqIQFBoQEhAgzmAQsgAUEBaiEBQSIMKwsgASAERgRAQbkBIQIM/gELIAEtAABB0ABHDSsgAUEBaiEBQaABIQIM5AELIAEgBEYEQEG4ASECDP0BCwJAAkAgAS0AAEHGAGsOCwAsLCwsLCwsLCwBLAsgAUEBaiEBQZ4BIQIM5AELIAFBAWohAUGfASECDOMBC0G3ASECIAEgBEYN+wEgAygCACIAIAQgAWtqIQUgASAAa0EDaiEGAkADQCABLQAAIABB7NQAai0AAEcNKCAAQQNGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM/AELIANBADYCACAGQQFqIQFBDQwoC0G2ASECIAEgBEYN+gEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBodUAai0AAEcNJyAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM+wELIANBADYCACAGQQFqIQFBDAwnC0G1ASECIAEgBEYN+QEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABB6tQAai0AAEcNJiAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM+gELIANBADYCACAGQQFqIQFBAwwmC0G0ASECIAEgBEYN+AEgAygCACIAIAQgAWtqIQUgASAAa0EBaiEGAkADQCABLQAAIABB6NQAai0AAEcNJSAAQQFGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM+QELIANBADYCACAGQQFqIQFBJgwlCyABIARGBEBBswEhAgz4AQsCQAJAIAEtAABB1ABrDgIAAScLIAFBAWohAUGZASECDN8BCyABQQFqIQFBmgEhAgzeAQtBsgEhAiABIARGDfYBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQebUAGotAABHDSMgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPcBCyADQQA2AgAgBkEBaiEBQScMIwtBsQEhAiABIARGDfUBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQeTUAGotAABHDSIgAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPYBCyADQQA2AgAgBkEBaiEBQRwMIgtBsAEhAiABIARGDfQBIAMoAgAiACAEIAFraiEFIAEgAGtBBWohBgJAA0AgAS0AACAAQd7UAGotAABHDSEgAEEFRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPUBCyADQQA2AgAgBkEBaiEBQQYMIQtBrwEhAiABIARGDfMBIAMoAgAiACAEIAFraiEFIAEgAGtBBGohBgJAA0AgAS0AACAAQdnUAGotAABHDSAgAEEERg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPQBCyADQQA2AgAgBkEBaiEBQRkMIAsgASAERgRAQa4BIQIM8wELAkACQAJAAkAgAS0AAEEtaw4jACQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkASQkJCQkAiQkJAMkCyABQQFqIQFBjgEhAgzcAQsgAUEBaiEBQY8BIQIM2wELIAFBAWohAUGUASECDNoBCyABQQFqIQFBlQEhAgzZAQtBrQEhAiABIARGDfEBIAMoAgAiACAEIAFraiEFIAEgAGtBAWohBgJAA0AgAS0AACAAQdfUAGotAABHDR4gAEEBRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADPIBCyADQQA2AgAgBkEBaiEBQQsMHgsgASAERgRAQawBIQIM8QELAkACQCABLQAAQcEAaw4DACABIAsgAUEBaiEBQZABIQIM2AELIAFBAWohAUGTASECDNcBCyABIARGBEBBqwEhAgzwAQsCQAJAIAEtAABBwQBrDg8AHx8fHx8fHx8fHx8fHwEfCyABQQFqIQFBkQEhAgzXAQsgAUEBaiEBQZIBIQIM1gELIAEgBEYEQEGqASECDO8BCyABLQAAQcwARw0cIAFBAWohAUEKDBsLQakBIQIgASAERg3tASADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEHR1ABqLQAARw0aIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzuAQsgA0EANgIAIAZBAWohAUEeDBoLQagBIQIgASAERg3sASADKAIAIgAgBCABa2ohBSABIABrQQZqIQYCQANAIAEtAAAgAEHK1ABqLQAARw0ZIABBBkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAztAQsgA0EANgIAIAZBAWohAUEVDBkLQacBIQIgASAERg3rASADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEHH1ABqLQAARw0YIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzsAQsgA0EANgIAIAZBAWohAUEXDBgLQaYBIQIgASAERg3qASADKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEHB1ABqLQAARw0XIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzrAQsgA0EANgIAIAZBAWohAUEYDBcLIAEgBEYEQEGlASECDOoBCwJAAkAgAS0AAEHJAGsOBwAZGRkZGQEZCyABQQFqIQFBiwEhAgzRAQsgAUEBaiEBQYwBIQIM0AELQaQBIQIgASAERg3oASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGm1QBqLQAARw0VIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzpAQsgA0EANgIAIAZBAWohAUEJDBULQaMBIQIgASAERg3nASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGk1QBqLQAARw0UIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzoAQsgA0EANgIAIAZBAWohAUEfDBQLQaIBIQIgASAERg3mASADKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEG+1ABqLQAARw0TIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAznAQsgA0EANgIAIAZBAWohAUECDBMLQaEBIQIgASAERg3lASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYDQCABLQAAIABBvNQAai0AAEcNESAAQQFGDQIgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM5QELIAEgBEYEQEGgASECDOUBC0EBIAEtAABB3wBHDREaIAFBAWohAUGHASECDMsBCyADQQA2AgAgBkEBaiEBQYgBIQIMygELQZ8BIQIgASAERg3iASADKAIAIgAgBCABa2ohBSABIABrQQhqIQYCQANAIAEtAAAgAEGE1QBqLQAARw0PIABBCEYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAzjAQsgA0EANgIAIAZBAWohAUEpDA8LQZ4BIQIgASAERg3hASADKAIAIgAgBCABa2ohBSABIABrQQNqIQYCQANAIAEtAAAgAEG41ABqLQAARw0OIABBA0YNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAziAQsgA0EANgIAIAZBAWohAUEtDA4LIAEgBEYEQEGdASECDOEBCyABLQAAQcUARw0OIAFBAWohAUGEASECDMcBCyABIARGBEBBnAEhAgzgAQsCQAJAIAEtAABBzABrDggADw8PDw8PAQ8LIAFBAWohAUGCASECDMcBCyABQQFqIQFBgwEhAgzGAQtBmwEhAiABIARGDd4BIAMoAgAiACAEIAFraiEFIAEgAGtBBGohBgJAA0AgAS0AACAAQbPUAGotAABHDQsgAEEERg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADN8BCyADQQA2AgAgBkEBaiEBQSMMCwtBmgEhAiABIARGDd0BIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQbDUAGotAABHDQogAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADN4BCyADQQA2AgAgBkEBaiEBQQAMCgsgASAERgRAQZkBIQIM3QELAkACQCABLQAAQcgAaw4IAAwMDAwMDAEMCyABQQFqIQFB/QAhAgzEAQsgAUEBaiEBQYABIQIMwwELIAEgBEYEQEGYASECDNwBCwJAAkAgAS0AAEHOAGsOAwALAQsLIAFBAWohAUH+ACECDMMBCyABQQFqIQFB/wAhAgzCAQsgASAERgRAQZcBIQIM2wELIAEtAABB2QBHDQggAUEBaiEBQQgMBwtBlgEhAiABIARGDdkBIAMoAgAiACAEIAFraiEFIAEgAGtBA2ohBgJAA0AgAS0AACAAQazUAGotAABHDQYgAEEDRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADNoBCyADQQA2AgAgBkEBaiEBQQUMBgtBlQEhAiABIARGDdgBIAMoAgAiACAEIAFraiEFIAEgAGtBBWohBgJAA0AgAS0AACAAQabUAGotAABHDQUgAEEFRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADNkBCyADQQA2AgAgBkEBaiEBQRYMBQtBlAEhAiABIARGDdcBIAMoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQaHVAGotAABHDQQgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAyAFNgIADNgBCyADQQA2AgAgBkEBaiEBQRAMBAsgASAERgRAQZMBIQIM1wELAkACQCABLQAAQcMAaw4MAAYGBgYGBgYGBgYBBgsgAUEBaiEBQfkAIQIMvgELIAFBAWohAUH6ACECDL0BC0GSASECIAEgBEYN1QEgAygCACIAIAQgAWtqIQUgASAAa0EFaiEGAkADQCABLQAAIABBoNQAai0AAEcNAiAAQQVGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAM1gELIANBADYCACAGQQFqIQFBJAwCCyADQQA2AgAMAgsgASAERgRAQZEBIQIM1AELIAEtAABBzABHDQEgAUEBaiEBQRMLOgApIAMoAgQhACADQQA2AgQgAyAAIAEQLiIADQIMAQtBACECIANBADYCHCADIAE2AhQgA0H+HzYCECADQQY2AgwM0QELQfgAIQIMtwELIANBkAE2AhwgAyABNgIUIAMgADYCDEEAIQIMzwELQQAhAAJAIAMoAjgiAkUNACACKAJAIgJFDQAgAyACEQAAIQALIABFDQAgAEEVRg0BIANBADYCHCADIAE2AhQgA0GCDzYCECADQSA2AgxBACECDM4BC0H3ACECDLQBCyADQY8BNgIcIAMgATYCFCADQewbNgIQIANBFTYCDEEAIQIMzAELIAEgBEYEQEGPASECDMwBCwJAIAEtAABBIEYEQCABQQFqIQEMAQsgA0EANgIcIAMgATYCFCADQZsfNgIQIANBBjYCDEEAIQIMzAELQQIhAgyyAQsDQCABLQAAQSBHDQIgBCABQQFqIgFHDQALQY4BIQIMygELIAEgBEYEQEGNASECDMoBCwJAIAEtAABBCWsOBEoAAEoAC0H1ACECDLABCyADLQApQQVGBEBB9gAhAgywAQtB9AAhAgyvAQsgASAERgRAQYwBIQIMyAELIANBEDYCCCADIAE2AgQMCgsgASAERgRAQYsBIQIMxwELAkAgAS0AAEEJaw4ERwAARwALQfMAIQIMrQELIAEgBEcEQCADQRA2AgggAyABNgIEQfEAIQIMrQELQYoBIQIMxQELAkAgASAERwRAA0AgAS0AAEGg0ABqLQAAIgBBA0cEQAJAIABBAWsOAkkABAtB8AAhAgyvAQsgBCABQQFqIgFHDQALQYgBIQIMxgELQYgBIQIMxQELIANBADYCHCADIAE2AhQgA0HbIDYCECADQQc2AgxBACECDMQBCyABIARGBEBBiQEhAgzEAQsCQAJAAkAgAS0AAEGg0gBqLQAAQQFrDgNGAgABC0HyACECDKwBCyADQQA2AhwgAyABNgIUIANBtBI2AhAgA0EHNgIMQQAhAgzEAQtB6gAhAgyqAQsgASAERwRAIAFBAWohAUHvACECDKoBC0GHASECDMIBCyAEIAEiAEYEQEGGASECDMIBCyAALQAAIgFBL0YEQCAAQQFqIQFB7gAhAgypAQsgAUEJayICQRdLDQEgACEBQQEgAnRBm4CABHENQQwBCyAEIAEiAEYEQEGFASECDMEBCyAALQAAQS9HDQAgAEEBaiEBDAMLQQAhAiADQQA2AhwgAyAANgIUIANB2yA2AhAgA0EHNgIMDL8BCwJAAkACQAJAAkADQCABLQAAQaDOAGotAAAiAEEFRwRAAkACQCAAQQFrDghHBQYHCAAEAQgLQesAIQIMrQELIAFBAWohAUHtACECDKwBCyAEIAFBAWoiAUcNAAtBhAEhAgzDAQsgAUEBagwUCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNHiADQdsANgIcIAMgATYCFCADIAA2AgxBACECDMEBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNHiADQd0ANgIcIAMgATYCFCADIAA2AgxBACECDMABCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNHiADQfoANgIcIAMgATYCFCADIAA2AgxBACECDL8BCyADQQA2AhwgAyABNgIUIANB+Q82AhAgA0EHNgIMQQAhAgy+AQsgASAERgRAQYMBIQIMvgELAkAgAS0AAEGgzgBqLQAAQQFrDgg+BAUGAAgCAwcLIAFBAWohAQtBAyECDKMBCyABQQFqDA0LQQAhAiADQQA2AhwgA0HREjYCECADQQc2AgwgAyABQQFqNgIUDLoBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNFiADQdsANgIcIAMgATYCFCADIAA2AgxBACECDLkBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNFiADQd0ANgIcIAMgATYCFCADIAA2AgxBACECDLgBCyADKAIEIQAgA0EANgIEIAMgACABECwiAEUNFiADQfoANgIcIAMgATYCFCADIAA2AgxBACECDLcBCyADQQA2AhwgAyABNgIUIANB+Q82AhAgA0EHNgIMQQAhAgy2AQtB7AAhAgycAQsgASAERgRAQYIBIQIMtQELIAFBAWoMAgsgASAERgRAQYEBIQIMtAELIAFBAWoMAQsgASAERg0BIAFBAWoLIQFBBCECDJgBC0GAASECDLABCwNAIAEtAABBoMwAai0AACIAQQJHBEAgAEEBRwRAQekAIQIMmQELDDELIAQgAUEBaiIBRw0AC0H/ACECDK8BCyABIARGBEBB/gAhAgyvAQsCQCABLQAAQQlrDjcvAwYvBAYGBgYGBgYGBgYGBgYGBgYGBgUGBgIGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYABgsgAUEBagshAUEFIQIMlAELIAFBAWoMBgsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQggA0HbADYCHCADIAE2AhQgAyAANgIMQQAhAgyrAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQggA0HdADYCHCADIAE2AhQgAyAANgIMQQAhAgyqAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQggA0H6ADYCHCADIAE2AhQgAyAANgIMQQAhAgypAQsgA0EANgIcIAMgATYCFCADQY0UNgIQIANBBzYCDEEAIQIMqAELAkACQAJAAkADQCABLQAAQaDKAGotAAAiAEEFRwRAAkAgAEEBaw4GLgMEBQYABgtB6AAhAgyUAQsgBCABQQFqIgFHDQALQf0AIQIMqwELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0HIANB2wA2AhwgAyABNgIUIAMgADYCDEEAIQIMqgELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0HIANB3QA2AhwgAyABNgIUIAMgADYCDEEAIQIMqQELIAMoAgQhACADQQA2AgQgAyAAIAEQLCIARQ0HIANB+gA2AhwgAyABNgIUIAMgADYCDEEAIQIMqAELIANBADYCHCADIAE2AhQgA0HkCDYCECADQQc2AgxBACECDKcBCyABIARGDQEgAUEBagshAUEGIQIMjAELQfwAIQIMpAELAkACQAJAAkADQCABLQAAQaDIAGotAAAiAEEFRwRAIABBAWsOBCkCAwQFCyAEIAFBAWoiAUcNAAtB+wAhAgynAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQMgA0HbADYCHCADIAE2AhQgAyAANgIMQQAhAgymAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQMgA0HdADYCHCADIAE2AhQgAyAANgIMQQAhAgylAQsgAygCBCEAIANBADYCBCADIAAgARAsIgBFDQMgA0H6ADYCHCADIAE2AhQgAyAANgIMQQAhAgykAQsgA0EANgIcIAMgATYCFCADQbwKNgIQIANBBzYCDEEAIQIMowELQc8AIQIMiQELQdEAIQIMiAELQecAIQIMhwELIAEgBEYEQEH6ACECDKABCwJAIAEtAABBCWsOBCAAACAACyABQQFqIQFB5gAhAgyGAQsgASAERgRAQfkAIQIMnwELAkAgAS0AAEEJaw4EHwAAHwALQQAhAAJAIAMoAjgiAkUNACACKAI4IgJFDQAgAyACEQAAIQALIABFBEBB4gEhAgyGAQsgAEEVRwRAIANBADYCHCADIAE2AhQgA0HJDTYCECADQRo2AgxBACECDJ8BCyADQfgANgIcIAMgATYCFCADQeoaNgIQIANBFTYCDEEAIQIMngELIAEgBEcEQCADQQ02AgggAyABNgIEQeQAIQIMhQELQfcAIQIMnQELIAEgBEYEQEH2ACECDJ0BCwJAAkACQCABLQAAQcgAaw4LAAELCwsLCwsLCwILCyABQQFqIQFB3QAhAgyFAQsgAUEBaiEBQeAAIQIMhAELIAFBAWohAUHjACECDIMBC0H1ACECIAEgBEYNmwEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBtdUAai0AAEcNCCAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMnAELIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARArIgAEQCADQfQANgIcIAMgATYCFCADIAA2AgxBACECDJwBC0HiACECDIIBC0EAIQACQCADKAI4IgJFDQAgAigCNCICRQ0AIAMgAhEAACEACwJAIAAEQCAAQRVGDQEgA0EANgIcIAMgATYCFCADQeoNNgIQIANBJjYCDEEAIQIMnAELQeEAIQIMggELIANB8wA2AhwgAyABNgIUIANBgBs2AhAgA0EVNgIMQQAhAgyaAQsgAy0AKSIAQSNrQQtJDQkCQCAAQQZLDQBBASAAdEHKAHFFDQAMCgtBACECIANBADYCHCADIAE2AhQgA0HtCTYCECADQQg2AgwMmQELQfIAIQIgASAERg2YASADKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGz1QBqLQAARw0FIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAyZAQsgAygCBCEAIANCADcDACADIAAgBkEBaiIBECsiAARAIANB8QA2AhwgAyABNgIUIAMgADYCDEEAIQIMmQELQd8AIQIMfwtBACEAAkAgAygCOCICRQ0AIAIoAjQiAkUNACADIAIRAAAhAAsCQCAABEAgAEEVRg0BIANBADYCHCADIAE2AhQgA0HqDTYCECADQSY2AgxBACECDJkBC0HeACECDH8LIANB8AA2AhwgAyABNgIUIANBgBs2AhAgA0EVNgIMQQAhAgyXAQsgAy0AKUEhRg0GIANBADYCHCADIAE2AhQgA0GRCjYCECADQQg2AgxBACECDJYBC0HvACECIAEgBEYNlQEgAygCACIAIAQgAWtqIQUgASAAa0ECaiEGAkADQCABLQAAIABBsNUAai0AAEcNAiAAQQJGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyADIAU2AgAMlgELIAMoAgQhACADQgA3AwAgAyAAIAZBAWoiARArIgBFDQIgA0HtADYCHCADIAE2AhQgAyAANgIMQQAhAgyVAQsgA0EANgIACyADKAIEIQAgA0EANgIEIAMgACABECsiAEUNgAEgA0HuADYCHCADIAE2AhQgAyAANgIMQQAhAgyTAQtB3AAhAgx5C0EAIQACQCADKAI4IgJFDQAgAigCNCICRQ0AIAMgAhEAACEACwJAIAAEQCAAQRVGDQEgA0EANgIcIAMgATYCFCADQeoNNgIQIANBJjYCDEEAIQIMkwELQdsAIQIMeQsgA0HsADYCHCADIAE2AhQgA0GAGzYCECADQRU2AgxBACECDJEBCyADLQApIgBBI0kNACAAQS5GDQAgA0EANgIcIAMgATYCFCADQckJNgIQIANBCDYCDEEAIQIMkAELQdoAIQIMdgsgASAERgRAQesAIQIMjwELAkAgAS0AAEEvRgRAIAFBAWohAQwBCyADQQA2AhwgAyABNgIUIANBsjg2AhAgA0EINgIMQQAhAgyPAQtB2QAhAgx1CyABIARHBEAgA0EONgIIIAMgATYCBEHYACECDHULQeoAIQIMjQELIAEgBEYEQEHpACECDI0BCyABLQAAQTBrIgBB/wFxQQpJBEAgAyAAOgAqIAFBAWohAUHXACECDHQLIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ16IANB6AA2AhwgAyABNgIUIAMgADYCDEEAIQIMjAELIAEgBEYEQEHnACECDIwBCwJAIAEtAABBLkYEQCABQQFqIQEMAQsgAygCBCEAIANBADYCBCADIAAgARAvIgBFDXsgA0HmADYCHCADIAE2AhQgAyAANgIMQQAhAgyMAQtB1gAhAgxyCyABIARGBEBB5QAhAgyLAQtBACEAQQEhBUEBIQdBACECAkACQAJAAkACQAJ/AkACQAJAAkACQAJAAkAgAS0AAEEwaw4KCgkAAQIDBAUGCAsLQQIMBgtBAwwFC0EEDAQLQQUMAwtBBgwCC0EHDAELQQgLIQJBACEFQQAhBwwCC0EJIQJBASEAQQAhBUEAIQcMAQtBACEFQQEhAgsgAyACOgArIAFBAWohAQJAAkAgAy0ALkEQcQ0AAkACQAJAIAMtACoOAwEAAgQLIAdFDQMMAgsgAA0BDAILIAVFDQELIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ0CIANB4gA2AhwgAyABNgIUIAMgADYCDEEAIQIMjQELIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ19IANB4wA2AhwgAyABNgIUIAMgADYCDEEAIQIMjAELIAMoAgQhACADQQA2AgQgAyAAIAEQLyIARQ17IANB5AA2AhwgAyABNgIUIAMgADYCDAyLAQtB1AAhAgxxCyADLQApQSJGDYYBQdMAIQIMcAtBACEAAkAgAygCOCICRQ0AIAIoAkQiAkUNACADIAIRAAAhAAsgAEUEQEHVACECDHALIABBFUcEQCADQQA2AhwgAyABNgIUIANBpA02AhAgA0EhNgIMQQAhAgyJAQsgA0HhADYCHCADIAE2AhQgA0HQGjYCECADQRU2AgxBACECDIgBCyABIARGBEBB4AAhAgyIAQsCQAJAAkACQAJAIAEtAABBCmsOBAEEBAAECyABQQFqIQEMAQsgAUEBaiEBIANBL2otAABBAXFFDQELQdIAIQIMcAsgA0EANgIcIAMgATYCFCADQbYRNgIQIANBCTYCDEEAIQIMiAELIANBADYCHCADIAE2AhQgA0G2ETYCECADQQk2AgxBACECDIcBCyABIARGBEBB3wAhAgyHAQsgAS0AAEEKRgRAIAFBAWohAQwJCyADLQAuQcAAcQ0IIANBADYCHCADIAE2AhQgA0G2ETYCECADQQI2AgxBACECDIYBCyABIARGBEBB3QAhAgyGAQsgAS0AACICQQ1GBEAgAUEBaiEBQdAAIQIMbQsgASEAIAJBCWsOBAUBAQUBCyAEIAEiAEYEQEHcACECDIUBCyAALQAAQQpHDQAgAEEBagwCC0EAIQIgA0EANgIcIAMgADYCFCADQcotNgIQIANBBzYCDAyDAQsgASAERgRAQdsAIQIMgwELAkAgAS0AAEEJaw4EAwAAAwALIAFBAWoLIQFBzgAhAgxoCyABIARGBEBB2gAhAgyBAQsgAS0AAEEJaw4EAAEBAAELQQAhAiADQQA2AhwgA0GaEjYCECADQQc2AgwgAyABQQFqNgIUDH8LIANBgBI7ASpBACEAAkAgAygCOCICRQ0AIAIoAjgiAkUNACADIAIRAAAhAAsgAEUNACAAQRVHDQEgA0HZADYCHCADIAE2AhQgA0HqGjYCECADQRU2AgxBACECDH4LQc0AIQIMZAsgA0EANgIcIAMgATYCFCADQckNNgIQIANBGjYCDEEAIQIMfAsgASAERgRAQdkAIQIMfAsgAS0AAEEgRw09IAFBAWohASADLQAuQQFxDT0gA0EANgIcIAMgATYCFCADQcIcNgIQIANBHjYCDEEAIQIMewsgASAERgRAQdgAIQIMewsCQAJAAkACQAJAIAEtAAAiAEEKaw4EAgMDAAELIAFBAWohAUEsIQIMZQsgAEE6Rw0BIANBADYCHCADIAE2AhQgA0HnETYCECADQQo2AgxBACECDH0LIAFBAWohASADQS9qLQAAQQFxRQ1zIAMtADJBgAFxRQRAIANBMmohAiADEDVBACEAAkAgAygCOCIGRQ0AIAYoAigiBkUNACADIAYRAAAhAAsCQAJAIAAOFk1MSwEBAQEBAQEBAQEBAQEBAQEBAQABCyADQSk2AhwgAyABNgIUIANBrBk2AhAgA0EVNgIMQQAhAgx+CyADQQA2AhwgAyABNgIUIANB5Qs2AhAgA0ERNgIMQQAhAgx9C0EAIQACQCADKAI4IgJFDQAgAigCXCICRQ0AIAMgAhEAACEACyAARQ1ZIABBFUcNASADQQU2AhwgAyABNgIUIANBmxs2AhAgA0EVNgIMQQAhAgx8C0HLACECDGILQQAhAiADQQA2AhwgAyABNgIUIANBkA42AhAgA0EUNgIMDHoLIAMgAy8BMkGAAXI7ATIMOwsgASAERwRAIANBETYCCCADIAE2AgRBygAhAgxgC0HXACECDHgLIAEgBEYEQEHWACECDHgLAkACQAJAAkAgAS0AACIAQSByIAAgAEHBAGtB/wFxQRpJG0H/AXFB4wBrDhMAQEBAQEBAQEBAQEBAAUBAQAIDQAsgAUEBaiEBQcYAIQIMYQsgAUEBaiEBQccAIQIMYAsgAUEBaiEBQcgAIQIMXwsgAUEBaiEBQckAIQIMXgtB1QAhAiAEIAEiAEYNdiAEIAFrIAMoAgAiAWohBiAAIAFrQQVqIQcDQCABQZDIAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQhBBCABQQVGDQoaIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADHYLQdQAIQIgBCABIgBGDXUgBCABayADKAIAIgFqIQYgACABa0EPaiEHA0AgAUGAyABqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0HQQMgAUEPRg0JGiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAx1C0HTACECIAQgASIARg10IAQgAWsgAygCACIBaiEGIAAgAWtBDmohBwNAIAFB4scAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNBiABQQ5GDQcgAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMdAtB0gAhAiAEIAEiAEYNcyAEIAFrIAMoAgAiAWohBSAAIAFrQQFqIQYDQCABQeDHAGotAAAgAC0AACIHQSByIAcgB0HBAGtB/wFxQRpJG0H/AXFHDQUgAUEBRg0CIAFBAWohASAEIABBAWoiAEcNAAsgAyAFNgIADHMLIAEgBEYEQEHRACECDHMLAkACQCABLQAAIgBBIHIgACAAQcEAa0H/AXFBGkkbQf8BcUHuAGsOBwA5OTk5OQE5CyABQQFqIQFBwwAhAgxaCyABQQFqIQFBxAAhAgxZCyADQQA2AgAgBkEBaiEBQcUAIQIMWAtB0AAhAiAEIAEiAEYNcCAEIAFrIAMoAgAiAWohBiAAIAFrQQlqIQcDQCABQdbHAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQJBAiABQQlGDQQaIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADHALQc8AIQIgBCABIgBGDW8gBCABayADKAIAIgFqIQYgACABa0EFaiEHA0AgAUHQxwBqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0BIAFBBUYNAiABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAxvCyAAIQEgA0EANgIADDMLQQELOgAsIANBADYCACAHQQFqIQELQS0hAgxSCwJAA0AgAS0AAEHQxQBqLQAAQQFHDQEgBCABQQFqIgFHDQALQc0AIQIMawtBwgAhAgxRCyABIARGBEBBzAAhAgxqCyABLQAAQTpGBEAgAygCBCEAIANBADYCBCADIAAgARAwIgBFDTMgA0HLADYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgxqCyADQQA2AhwgAyABNgIUIANB5xE2AhAgA0EKNgIMQQAhAgxpCwJAAkAgAy0ALEECaw4CAAEnCyADQTNqLQAAQQJxRQ0mIAMtAC5BAnENJiADQQA2AhwgAyABNgIUIANBphQ2AhAgA0ELNgIMQQAhAgxpCyADLQAyQSBxRQ0lIAMtAC5BAnENJSADQQA2AhwgAyABNgIUIANBvRM2AhAgA0EPNgIMQQAhAgxoC0EAIQACQCADKAI4IgJFDQAgAigCSCICRQ0AIAMgAhEAACEACyAARQRAQcEAIQIMTwsgAEEVRwRAIANBADYCHCADIAE2AhQgA0GmDzYCECADQRw2AgxBACECDGgLIANBygA2AhwgAyABNgIUIANBhRw2AhAgA0EVNgIMQQAhAgxnCyABIARHBEAgASECA0AgBCACIgFrQRBOBEAgAUEQaiEC/Qz/////////////////////IAH9AAAAIg1BB/1sIA39DODg4ODg4ODg4ODg4ODg4OD9bv0MX19fX19fX19fX19fX19fX/0mIA39DAkJCQkJCQkJCQkJCQkJCQn9I/1Q/VL9ZEF/c2giAEEQRg0BIAAgAWohAQwYCyABIARGBEBBxAAhAgxpCyABLQAAQcDBAGotAABBAUcNFyAEIAFBAWoiAkcNAAtBxAAhAgxnC0HEACECDGYLIAEgBEcEQANAAkAgAS0AACIAQSByIAAgAEHBAGtB/wFxQRpJG0H/AXEiAEEJRg0AIABBIEYNAAJAAkACQAJAIABB4wBrDhMAAwMDAwMDAwEDAwMDAwMDAwMCAwsgAUEBaiEBQTYhAgxSCyABQQFqIQFBNyECDFELIAFBAWohAUE4IQIMUAsMFQsgBCABQQFqIgFHDQALQTwhAgxmC0E8IQIMZQsgASAERgRAQcgAIQIMZQsgA0ESNgIIIAMgATYCBAJAAkACQAJAAkAgAy0ALEEBaw4EFAABAgkLIAMtADJBIHENA0HgASECDE8LAkAgAy8BMiIAQQhxRQ0AIAMtAChBAUcNACADLQAuQQhxRQ0CCyADIABB9/sDcUGABHI7ATIMCwsgAyADLwEyQRByOwEyDAQLIANBADYCBCADIAEgARAxIgAEQCADQcEANgIcIAMgADYCDCADIAFBAWo2AhRBACECDGYLIAFBAWohAQxYCyADQQA2AhwgAyABNgIUIANB9BM2AhAgA0EENgIMQQAhAgxkC0HHACECIAEgBEYNYyADKAIAIgAgBCABa2ohBSABIABrQQZqIQYCQANAIABBwMUAai0AACABLQAAQSByRw0BIABBBkYNSiAAQQFqIQAgBCABQQFqIgFHDQALIAMgBTYCAAxkCyADQQA2AgAMBQsCQCABIARHBEADQCABLQAAQcDDAGotAAAiAEEBRwRAIABBAkcNAyABQQFqIQEMBQsgBCABQQFqIgFHDQALQcUAIQIMZAtBxQAhAgxjCwsgA0EAOgAsDAELQQshAgxHC0E/IQIMRgsCQAJAA0AgAS0AACIAQSBHBEACQCAAQQprDgQDBQUDAAsgAEEsRg0DDAQLIAQgAUEBaiIBRw0AC0HGACECDGALIANBCDoALAwOCyADLQAoQQFHDQIgAy0ALkEIcQ0CIAMoAgQhACADQQA2AgQgAyAAIAEQMSIABEAgA0HCADYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgxfCyABQQFqIQEMUAtBOyECDEQLAkADQCABLQAAIgBBIEcgAEEJR3ENASAEIAFBAWoiAUcNAAtBwwAhAgxdCwtBPCECDEILAkACQCABIARHBEADQCABLQAAIgBBIEcEQCAAQQprDgQDBAQDBAsgBCABQQFqIgFHDQALQT8hAgxdC0E/IQIMXAsgAyADLwEyQSByOwEyDAoLIAMoAgQhACADQQA2AgQgAyAAIAEQMSIARQ1OIANBPjYCHCADIAE2AhQgAyAANgIMQQAhAgxaCwJAIAEgBEcEQANAIAEtAABBwMMAai0AACIAQQFHBEAgAEECRg0DDAwLIAQgAUEBaiIBRw0AC0E3IQIMWwtBNyECDFoLIAFBAWohAQwEC0E7IQIgBCABIgBGDVggBCABayADKAIAIgFqIQYgACABa0EFaiEHAkADQCABQZDIAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQEgAUEFRgRAQQchAQw/CyABQQFqIQEgBCAAQQFqIgBHDQALIAMgBjYCAAxZCyADQQA2AgAgACEBDAULQTohAiAEIAEiAEYNVyAEIAFrIAMoAgAiAWohBiAAIAFrQQhqIQcCQANAIAFBtMEAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNASABQQhGBEBBBSEBDD4LIAFBAWohASAEIABBAWoiAEcNAAsgAyAGNgIADFgLIANBADYCACAAIQEMBAtBOSECIAQgASIARg1WIAQgAWsgAygCACIBaiEGIAAgAWtBA2ohBwJAA0AgAUGwwQBqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0BIAFBA0YEQEEGIQEMPQsgAUEBaiEBIAQgAEEBaiIARw0ACyADIAY2AgAMVwsgA0EANgIAIAAhAQwDCwJAA0AgAS0AACIAQSBHBEAgAEEKaw4EBwQEBwILIAQgAUEBaiIBRw0AC0E4IQIMVgsgAEEsRw0BIAFBAWohAEEBIQECQAJAAkACQAJAIAMtACxBBWsOBAMBAgQACyAAIQEMBAtBAiEBDAELQQQhAQsgA0EBOgAsIAMgAy8BMiABcjsBMiAAIQEMAQsgAyADLwEyQQhyOwEyIAAhAQtBPiECDDsLIANBADoALAtBOSECDDkLIAEgBEYEQEE2IQIMUgsCQAJAAkACQAJAIAEtAABBCmsOBAACAgECCyADKAIEIQAgA0EANgIEIAMgACABEDEiAEUNAiADQTM2AhwgAyABNgIUIAMgADYCDEEAIQIMVQsgAygCBCEAIANBADYCBCADIAAgARAxIgBFBEAgAUEBaiEBDAYLIANBMjYCHCADIAA2AgwgAyABQQFqNgIUQQAhAgxUCyADLQAuQQFxBEBB3wEhAgw7CyADKAIEIQAgA0EANgIEIAMgACABEDEiAA0BDEkLQTQhAgw5CyADQTU2AhwgAyABNgIUIAMgADYCDEEAIQIMUQtBNSECDDcLIANBL2otAABBAXENACADQQA2AhwgAyABNgIUIANB6xY2AhAgA0EZNgIMQQAhAgxPC0EzIQIMNQsgASAERgRAQTIhAgxOCwJAIAEtAABBCkYEQCABQQFqIQEMAQsgA0EANgIcIAMgATYCFCADQZIXNgIQIANBAzYCDEEAIQIMTgtBMiECDDQLIAEgBEYEQEExIQIMTQsCQCABLQAAIgBBCUYNACAAQSBGDQBBASECAkAgAy0ALEEFaw4EBgQFAA0LIAMgAy8BMkEIcjsBMgwMCyADLQAuQQFxRQ0BIAMtACxBCEcNACADQQA6ACwLQT0hAgwyCyADQQA2AhwgAyABNgIUIANBwhY2AhAgA0EKNgIMQQAhAgxKC0ECIQIMAQtBBCECCyADQQE6ACwgAyADLwEyIAJyOwEyDAYLIAEgBEYEQEEwIQIMRwsgAS0AAEEKRgRAIAFBAWohAQwBCyADLQAuQQFxDQAgA0EANgIcIAMgATYCFCADQdwoNgIQIANBAjYCDEEAIQIMRgtBMCECDCwLIAFBAWohAUExIQIMKwsgASAERgRAQS8hAgxECyABLQAAIgBBCUcgAEEgR3FFBEAgAUEBaiEBIAMtAC5BAXENASADQQA2AhwgAyABNgIUIANBlxA2AhAgA0EKNgIMQQAhAgxEC0EBIQICQAJAAkACQAJAAkAgAy0ALEECaw4HBQQEAwECAAQLIAMgAy8BMkEIcjsBMgwDC0ECIQIMAQtBBCECCyADQQE6ACwgAyADLwEyIAJyOwEyC0EvIQIMKwsgA0EANgIcIAMgATYCFCADQYQTNgIQIANBCzYCDEEAIQIMQwtB4QEhAgwpCyABIARGBEBBLiECDEILIANBADYCBCADQRI2AgggAyABIAEQMSIADQELQS4hAgwnCyADQS02AhwgAyABNgIUIAMgADYCDEEAIQIMPwtBACEAAkAgAygCOCICRQ0AIAIoAkwiAkUNACADIAIRAAAhAAsgAEUNACAAQRVHDQEgA0HYADYCHCADIAE2AhQgA0GzGzYCECADQRU2AgxBACECDD4LQcwAIQIMJAsgA0EANgIcIAMgATYCFCADQbMONgIQIANBHTYCDEEAIQIMPAsgASAERgRAQc4AIQIMPAsgAS0AACIAQSBGDQIgAEE6Rg0BCyADQQA6ACxBCSECDCELIAMoAgQhACADQQA2AgQgAyAAIAEQMCIADQEMAgsgAy0ALkEBcQRAQd4BIQIMIAsgAygCBCEAIANBADYCBCADIAAgARAwIgBFDQIgA0EqNgIcIAMgADYCDCADIAFBAWo2AhRBACECDDgLIANBywA2AhwgAyAANgIMIAMgAUEBajYCFEEAIQIMNwsgAUEBaiEBQcAAIQIMHQsgAUEBaiEBDCwLIAEgBEYEQEErIQIMNQsCQCABLQAAQQpGBEAgAUEBaiEBDAELIAMtAC5BwABxRQ0GCyADLQAyQYABcQRAQQAhAAJAIAMoAjgiAkUNACACKAJcIgJFDQAgAyACEQAAIQALIABFDRIgAEEVRgRAIANBBTYCHCADIAE2AhQgA0GbGzYCECADQRU2AgxBACECDDYLIANBADYCHCADIAE2AhQgA0GQDjYCECADQRQ2AgxBACECDDULIANBMmohAiADEDVBACEAAkAgAygCOCIGRQ0AIAYoAigiBkUNACADIAYRAAAhAAsgAA4WAgEABAQEBAQEBAQEBAQEBAQEBAQEAwQLIANBAToAMAsgAiACLwEAQcAAcjsBAAtBKyECDBgLIANBKTYCHCADIAE2AhQgA0GsGTYCECADQRU2AgxBACECDDALIANBADYCHCADIAE2AhQgA0HlCzYCECADQRE2AgxBACECDC8LIANBADYCHCADIAE2AhQgA0GlCzYCECADQQI2AgxBACECDC4LQQEhByADLwEyIgVBCHFFBEAgAykDIEIAUiEHCwJAIAMtADAEQEEBIQAgAy0AKUEFRg0BIAVBwABxRSAHcUUNAQsCQCADLQAoIgJBAkYEQEEBIQAgAy8BNCIGQeUARg0CQQAhACAFQcAAcQ0CIAZB5ABGDQIgBkHmAGtBAkkNAiAGQcwBRg0CIAZBsAJGDQIMAQtBACEAIAVBwABxDQELQQIhACAFQQhxDQAgBUGABHEEQAJAIAJBAUcNACADLQAuQQpxDQBBBSEADAILQQQhAAwBCyAFQSBxRQRAIAMQNkEAR0ECdCEADAELQQBBAyADKQMgUBshAAsgAEEBaw4FAgAHAQMEC0ERIQIMEwsgA0EBOgAxDCkLQQAhAgJAIAMoAjgiAEUNACAAKAIwIgBFDQAgAyAAEQAAIQILIAJFDSYgAkEVRgRAIANBAzYCHCADIAE2AhQgA0HSGzYCECADQRU2AgxBACECDCsLQQAhAiADQQA2AhwgAyABNgIUIANB3Q42AhAgA0ESNgIMDCoLIANBADYCHCADIAE2AhQgA0H5IDYCECADQQ82AgxBACECDCkLQQAhAAJAIAMoAjgiAkUNACACKAIwIgJFDQAgAyACEQAAIQALIAANAQtBDiECDA4LIABBFUYEQCADQQI2AhwgAyABNgIUIANB0hs2AhAgA0EVNgIMQQAhAgwnCyADQQA2AhwgAyABNgIUIANB3Q42AhAgA0ESNgIMQQAhAgwmC0EqIQIMDAsgASAERwRAIANBCTYCCCADIAE2AgRBKSECDAwLQSYhAgwkCyADIAMpAyAiDCAEIAFrrSIKfSILQgAgCyAMWBs3AyAgCiAMVARAQSUhAgwkCyADKAIEIQAgA0EANgIEIAMgACABIAynaiIBEDIiAEUNACADQQU2AhwgAyABNgIUIAMgADYCDEEAIQIMIwtBDyECDAkLQgAhCgJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCABLQAAQTBrDjcXFgABAgMEBQYHFBQUFBQUFAgJCgsMDRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUDg8QERITFAtCAiEKDBYLQgMhCgwVC0IEIQoMFAtCBSEKDBMLQgYhCgwSC0IHIQoMEQtCCCEKDBALQgkhCgwPC0IKIQoMDgtCCyEKDA0LQgwhCgwMC0INIQoMCwtCDiEKDAoLQg8hCgwJC0IKIQoMCAtCCyEKDAcLQgwhCgwGC0INIQoMBQtCDiEKDAQLQg8hCgwDCyADQQA2AhwgAyABNgIUIANBnxU2AhAgA0EMNgIMQQAhAgwhCyABIARGBEBBIiECDCELQgAhCgJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAS0AAEEwaw43FRQAAQIDBAUGBxYWFhYWFhYICQoLDA0WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFg4PEBESExYLQgIhCgwUC0IDIQoMEwtCBCEKDBILQgUhCgwRC0IGIQoMEAtCByEKDA8LQgghCgwOC0IJIQoMDQtCCiEKDAwLQgshCgwLC0IMIQoMCgtCDSEKDAkLQg4hCgwIC0IPIQoMBwtCCiEKDAYLQgshCgwFC0IMIQoMBAtCDSEKDAMLQg4hCgwCC0IPIQoMAQtCASEKCyABQQFqIQEgAykDICILQv//////////D1gEQCADIAtCBIYgCoQ3AyAMAgsgA0EANgIcIAMgATYCFCADQbUJNgIQIANBDDYCDEEAIQIMHgtBJyECDAQLQSghAgwDCyADIAE6ACwgA0EANgIAIAdBAWohAUEMIQIMAgsgA0EANgIAIAZBAWohAUEKIQIMAQsgAUEBaiEBQQghAgwACwALQQAhAiADQQA2AhwgAyABNgIUIANBsjg2AhAgA0EINgIMDBcLQQAhAiADQQA2AhwgAyABNgIUIANBgxE2AhAgA0EJNgIMDBYLQQAhAiADQQA2AhwgAyABNgIUIANB3wo2AhAgA0EJNgIMDBULQQAhAiADQQA2AhwgAyABNgIUIANB7RA2AhAgA0EJNgIMDBQLQQAhAiADQQA2AhwgAyABNgIUIANB0hE2AhAgA0EJNgIMDBMLQQAhAiADQQA2AhwgAyABNgIUIANBsjg2AhAgA0EINgIMDBILQQAhAiADQQA2AhwgAyABNgIUIANBgxE2AhAgA0EJNgIMDBELQQAhAiADQQA2AhwgAyABNgIUIANB3wo2AhAgA0EJNgIMDBALQQAhAiADQQA2AhwgAyABNgIUIANB7RA2AhAgA0EJNgIMDA8LQQAhAiADQQA2AhwgAyABNgIUIANB0hE2AhAgA0EJNgIMDA4LQQAhAiADQQA2AhwgAyABNgIUIANBuRc2AhAgA0EPNgIMDA0LQQAhAiADQQA2AhwgAyABNgIUIANBuRc2AhAgA0EPNgIMDAwLQQAhAiADQQA2AhwgAyABNgIUIANBmRM2AhAgA0ELNgIMDAsLQQAhAiADQQA2AhwgAyABNgIUIANBnQk2AhAgA0ELNgIMDAoLQQAhAiADQQA2AhwgAyABNgIUIANBlxA2AhAgA0EKNgIMDAkLQQAhAiADQQA2AhwgAyABNgIUIANBsRA2AhAgA0EKNgIMDAgLQQAhAiADQQA2AhwgAyABNgIUIANBux02AhAgA0ECNgIMDAcLQQAhAiADQQA2AhwgAyABNgIUIANBlhY2AhAgA0ECNgIMDAYLQQAhAiADQQA2AhwgAyABNgIUIANB+Rg2AhAgA0ECNgIMDAULQQAhAiADQQA2AhwgAyABNgIUIANBxBg2AhAgA0ECNgIMDAQLIANBAjYCHCADIAE2AhQgA0GpHjYCECADQRY2AgxBACECDAMLQd4AIQIgASAERg0CIAlBCGohByADKAIAIQUCQAJAIAEgBEcEQCAFQZbIAGohCCAEIAVqIAFrIQYgBUF/c0EKaiIFIAFqIQADQCABLQAAIAgtAABHBEBBAiEIDAMLIAVFBEBBACEIIAAhAQwDCyAFQQFrIQUgCEEBaiEIIAQgAUEBaiIBRw0ACyAGIQUgBCEBCyAHQQE2AgAgAyAFNgIADAELIANBADYCACAHIAg2AgALIAcgATYCBCAJKAIMIQACQAJAIAkoAghBAWsOAgQBAAsgA0EANgIcIANBwh42AhAgA0EXNgIMIAMgAEEBajYCFEEAIQIMAwsgA0EANgIcIAMgADYCFCADQdceNgIQIANBCTYCDEEAIQIMAgsgASAERgRAQSghAgwCCyADQQk2AgggAyABNgIEQSchAgwBCyABIARGBEBBASECDAELA0ACQAJAAkAgAS0AAEEKaw4EAAEBAAELIAFBAWohAQwBCyABQQFqIQEgAy0ALkEgcQ0AQQAhAiADQQA2AhwgAyABNgIUIANBoSE2AhAgA0EFNgIMDAILQQEhAiABIARHDQALCyAJQRBqJAAgAkUEQCADKAIMIQAMAQsgAyACNgIcQQAhACADKAIEIgFFDQAgAyABIAQgAygCCBEBACIBRQ0AIAMgBDYCFCADIAE2AgwgASEACyAAC74CAQJ/IABBADoAACAAQeQAaiIBQQFrQQA6AAAgAEEAOgACIABBADoAASABQQNrQQA6AAAgAUECa0EAOgAAIABBADoAAyABQQRrQQA6AABBACAAa0EDcSIBIABqIgBBADYCAEHkACABa0F8cSICIABqIgFBBGtBADYCAAJAIAJBCUkNACAAQQA2AgggAEEANgIEIAFBCGtBADYCACABQQxrQQA2AgAgAkEZSQ0AIABBADYCGCAAQQA2AhQgAEEANgIQIABBADYCDCABQRBrQQA2AgAgAUEUa0EANgIAIAFBGGtBADYCACABQRxrQQA2AgAgAiAAQQRxQRhyIgJrIgFBIEkNACAAIAJqIQADQCAAQgA3AxggAEIANwMQIABCADcDCCAAQgA3AwAgAEEgaiEAIAFBIGsiAUEfSw0ACwsLVgEBfwJAIAAoAgwNAAJAAkACQAJAIAAtADEOAwEAAwILIAAoAjgiAUUNACABKAIwIgFFDQAgACABEQAAIgENAwtBAA8LAAsgAEHKGTYCEEEOIQELIAELGgAgACgCDEUEQCAAQd4fNgIQIABBFTYCDAsLFAAgACgCDEEVRgRAIABBADYCDAsLFAAgACgCDEEWRgRAIABBADYCDAsLBwAgACgCDAsHACAAKAIQCwkAIAAgATYCEAsHACAAKAIUCysAAkAgAEEnTw0AQv//////CSAArYhCAYNQDQAgAEECdEHQOGooAgAPCwALFwAgAEEvTwRAAAsgAEECdEHsOWooAgALvwkBAX9B9C0hAQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIABB5ABrDvQDY2IAAWFhYWFhYQIDBAVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhBgcICQoLDA0OD2FhYWFhEGFhYWFhYWFhYWFhEWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYRITFBUWFxgZGhthYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2YTc4OTphYWFhYWFhYTthYWE8YWFhYT0+P2FhYWFhYWFhQGFhQWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYUJDREVGR0hJSktMTU5PUFFSU2FhYWFhYWFhVFVWV1hZWlthXF1hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFeYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhX2BhC0HqLA8LQZgmDwtB7TEPC0GgNw8LQckpDwtBtCkPC0GWLQ8LQesrDwtBojUPC0HbNA8LQeApDwtB4yQPC0HVJA8LQe4kDwtB5iUPC0HKNA8LQdA3DwtBqjUPC0H1LA8LQfYmDwtBgiIPC0HyMw8LQb4oDwtB5zcPC0HNIQ8LQcAhDwtBuCUPC0HLJQ8LQZYkDwtBjzQPC0HNNQ8LQd0qDwtB7jMPC0GcNA8LQZ4xDwtB9DUPC0HlIg8LQa8lDwtBmTEPC0GyNg8LQfk2DwtBxDIPC0HdLA8LQYIxDwtBwTEPC0GNNw8LQckkDwtB7DYPC0HnKg8LQcgjDwtB4iEPC0HJNw8LQaUiDwtBlCIPC0HbNg8LQd41DwtBhiYPC0G8Kw8LQYsyDwtBoCMPC0H2MA8LQYAsDwtBiSsPC0GkJg8LQfIjDwtBgSgPC0GrMg8LQesnDwtBwjYPC0GiJA8LQc8qDwtB3CMPC0GHJw8LQeQ0DwtBtyIPC0GtMQ8LQdUiDwtBrzQPC0HeJg8LQdYyDwtB9DQPC0GBOA8LQfQ3DwtBkjYPC0GdJw8LQYIpDwtBjSMPC0HXMQ8LQb01DwtBtDcPC0HYMA8LQbYnDwtBmjgPC0GnKg8LQcQnDwtBriMPC0H1Ig8LAAtByiYhAQsgAQsXACAAIAAvAS5B/v8DcSABQQBHcjsBLgsaACAAIAAvAS5B/f8DcSABQQBHQQF0cjsBLgsaACAAIAAvAS5B+/8DcSABQQBHQQJ0cjsBLgsaACAAIAAvAS5B9/8DcSABQQBHQQN0cjsBLgsaACAAIAAvAS5B7/8DcSABQQBHQQR0cjsBLgsaACAAIAAvAS5B3/8DcSABQQBHQQV0cjsBLgsaACAAIAAvAS5Bv/8DcSABQQBHQQZ0cjsBLgsaACAAIAAvAS5B//4DcSABQQBHQQd0cjsBLgsaACAAIAAvAS5B//0DcSABQQBHQQh0cjsBLgsaACAAIAAvAS5B//sDcSABQQBHQQl0cjsBLgs+AQJ/AkAgACgCOCIDRQ0AIAMoAgQiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQeESNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAggiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQfwRNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAgwiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQewKNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAhAiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQfoeNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAhQiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQcsQNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAhgiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQbcfNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAhwiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQb8VNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAiwiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQf4INgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAiAiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQYwdNgIQQRghBAsgBAs+AQJ/AkAgACgCOCIDRQ0AIAMoAiQiA0UNACAAIAEgAiABayADEQEAIgRBf0cNACAAQeYVNgIQQRghBAsgBAs4ACAAAn8gAC8BMkEUcUEURgRAQQEgAC0AKEEBRg0BGiAALwE0QeUARgwBCyAALQApQQVGCzoAMAtZAQJ/AkAgAC0AKEEBRg0AIAAvATQiAUHkAGtB5ABJDQAgAUHMAUYNACABQbACRg0AIAAvATIiAEHAAHENAEEBIQIgAEGIBHFBgARGDQAgAEEocUUhAgsgAguMAQECfwJAAkACQCAALQAqRQ0AIAAtACtFDQAgAC8BMiIBQQJxRQ0BDAILIAAvATIiAUEBcUUNAQtBASECIAAtAChBAUYNACAALwE0IgBB5ABrQeQASQ0AIABBzAFGDQAgAEGwAkYNACABQcAAcQ0AQQAhAiABQYgEcUGABEYNACABQShxQQBHIQILIAILcwAgAEEQav0MAAAAAAAAAAAAAAAAAAAAAP0LAwAgAP0MAAAAAAAAAAAAAAAAAAAAAP0LAwAgAEEwav0MAAAAAAAAAAAAAAAAAAAAAP0LAwAgAEEgav0MAAAAAAAAAAAAAAAAAAAAAP0LAwAgAEH9ATYCHAsGACAAEDoLmi0BC38jAEEQayIKJABB3NUAKAIAIglFBEBBnNkAKAIAIgVFBEBBqNkAQn83AgBBoNkAQoCAhICAgMAANwIAQZzZACAKQQhqQXBxQdiq1aoFcyIFNgIAQbDZAEEANgIAQYDZAEEANgIAC0GE2QBBwNkENgIAQdTVAEHA2QQ2AgBB6NUAIAU2AgBB5NUAQX82AgBBiNkAQcCmAzYCAANAIAFBgNYAaiABQfTVAGoiAjYCACACIAFB7NUAaiIDNgIAIAFB+NUAaiADNgIAIAFBiNYAaiABQfzVAGoiAzYCACADIAI2AgAgAUGQ1gBqIAFBhNYAaiICNgIAIAIgAzYCACABQYzWAGogAjYCACABQSBqIgFBgAJHDQALQczZBEGBpgM2AgBB4NUAQazZACgCADYCAEHQ1QBBgKYDNgIAQdzVAEHI2QQ2AgBBzP8HQTg2AgBByNkEIQkLAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAEHsAU0EQEHE1QAoAgAiBkEQIABBE2pBcHEgAEELSRsiBEEDdiIAdiIBQQNxBEACQCABQQFxIAByQQFzIgJBA3QiAEHs1QBqIgEgAEH01QBqKAIAIgAoAggiA0YEQEHE1QAgBkF+IAJ3cTYCAAwBCyABIAM2AgggAyABNgIMCyAAQQhqIQEgACACQQN0IgJBA3I2AgQgACACaiIAIAAoAgRBAXI2AgQMEQtBzNUAKAIAIgggBE8NASABBEACQEECIAB0IgJBACACa3IgASAAdHFoIgBBA3QiAkHs1QBqIgEgAkH01QBqKAIAIgIoAggiA0YEQEHE1QAgBkF+IAB3cSIGNgIADAELIAEgAzYCCCADIAE2AgwLIAIgBEEDcjYCBCAAQQN0IgAgBGshBSAAIAJqIAU2AgAgAiAEaiIEIAVBAXI2AgQgCARAIAhBeHFB7NUAaiEAQdjVACgCACEDAn9BASAIQQN2dCIBIAZxRQRAQcTVACABIAZyNgIAIAAMAQsgACgCCAsiASADNgIMIAAgAzYCCCADIAA2AgwgAyABNgIICyACQQhqIQFB2NUAIAQ2AgBBzNUAIAU2AgAMEQtByNUAKAIAIgtFDQEgC2hBAnRB9NcAaigCACIAKAIEQXhxIARrIQUgACECA0ACQCACKAIQIgFFBEAgAkEUaigCACIBRQ0BCyABKAIEQXhxIARrIgMgBUkhAiADIAUgAhshBSABIAAgAhshACABIQIMAQsLIAAoAhghCSAAKAIMIgMgAEcEQEHU1QAoAgAaIAMgACgCCCIBNgIIIAEgAzYCDAwQCyAAQRRqIgIoAgAiAUUEQCAAKAIQIgFFDQMgAEEQaiECCwNAIAIhByABIgNBFGoiAigCACIBDQAgA0EQaiECIAMoAhAiAQ0ACyAHQQA2AgAMDwtBfyEEIABBv39LDQAgAEETaiIBQXBxIQRByNUAKAIAIghFDQBBACAEayEFAkACQAJAAn9BACAEQYACSQ0AGkEfIARB////B0sNABogBEEmIAFBCHZnIgBrdkEBcSAAQQF0a0E+agsiBkECdEH01wBqKAIAIgJFBEBBACEBQQAhAwwBC0EAIQEgBEEZIAZBAXZrQQAgBkEfRxt0IQBBACEDA0ACQCACKAIEQXhxIARrIgcgBU8NACACIQMgByIFDQBBACEFIAIhAQwDCyABIAJBFGooAgAiByAHIAIgAEEddkEEcWpBEGooAgAiAkYbIAEgBxshASAAQQF0IQAgAg0ACwsgASADckUEQEEAIQNBAiAGdCIAQQAgAGtyIAhxIgBFDQMgAGhBAnRB9NcAaigCACEBCyABRQ0BCwNAIAEoAgRBeHEgBGsiAiAFSSEAIAIgBSAAGyEFIAEgAyAAGyEDIAEoAhAiAAR/IAAFIAFBFGooAgALIgENAAsLIANFDQAgBUHM1QAoAgAgBGtPDQAgAygCGCEHIAMgAygCDCIARwRAQdTVACgCABogACADKAIIIgE2AgggASAANgIMDA4LIANBFGoiAigCACIBRQRAIAMoAhAiAUUNAyADQRBqIQILA0AgAiEGIAEiAEEUaiICKAIAIgENACAAQRBqIQIgACgCECIBDQALIAZBADYCAAwNC0HM1QAoAgAiAyAETwRAQdjVACgCACEBAkAgAyAEayICQRBPBEAgASAEaiIAIAJBAXI2AgQgASADaiACNgIAIAEgBEEDcjYCBAwBCyABIANBA3I2AgQgASADaiIAIAAoAgRBAXI2AgRBACEAQQAhAgtBzNUAIAI2AgBB2NUAIAA2AgAgAUEIaiEBDA8LQdDVACgCACIDIARLBEAgBCAJaiIAIAMgBGsiAUEBcjYCBEHc1QAgADYCAEHQ1QAgATYCACAJIARBA3I2AgQgCUEIaiEBDA8LQQAhASAEAn9BnNkAKAIABEBBpNkAKAIADAELQajZAEJ/NwIAQaDZAEKAgISAgIDAADcCAEGc2QAgCkEMakFwcUHYqtWqBXM2AgBBsNkAQQA2AgBBgNkAQQA2AgBBgIAECyIAIARBxwBqIgVqIgZBACAAayIHcSICTwRAQbTZAEEwNgIADA8LAkBB/NgAKAIAIgFFDQBB9NgAKAIAIgggAmohACAAIAFNIAAgCEtxDQBBACEBQbTZAEEwNgIADA8LQYDZAC0AAEEEcQ0EAkACQCAJBEBBhNkAIQEDQCABKAIAIgAgCU0EQCAAIAEoAgRqIAlLDQMLIAEoAggiAQ0ACwtBABA7IgBBf0YNBSACIQZBoNkAKAIAIgFBAWsiAyAAcQRAIAIgAGsgACADakEAIAFrcWohBgsgBCAGTw0FIAZB/v///wdLDQVB/NgAKAIAIgMEQEH02AAoAgAiByAGaiEBIAEgB00NBiABIANLDQYLIAYQOyIBIABHDQEMBwsgBiADayAHcSIGQf7///8HSw0EIAYQOyEAIAAgASgCACABKAIEakYNAyAAIQELAkAgBiAEQcgAak8NACABQX9GDQBBpNkAKAIAIgAgBSAGa2pBACAAa3EiAEH+////B0sEQCABIQAMBwsgABA7QX9HBEAgACAGaiEGIAEhAAwHC0EAIAZrEDsaDAQLIAEiAEF/Rw0FDAMLQQAhAwwMC0EAIQAMCgsgAEF/Rw0CC0GA2QBBgNkAKAIAQQRyNgIACyACQf7///8HSw0BIAIQOyEAQQAQOyEBIABBf0YNASABQX9GDQEgACABTw0BIAEgAGsiBiAEQThqTQ0BC0H02ABB9NgAKAIAIAZqIgE2AgBB+NgAKAIAIAFJBEBB+NgAIAE2AgALAkACQAJAQdzVACgCACICBEBBhNkAIQEDQCAAIAEoAgAiAyABKAIEIgVqRg0CIAEoAggiAQ0ACwwCC0HU1QAoAgAiAUEARyAAIAFPcUUEQEHU1QAgADYCAAtBACEBQYjZACAGNgIAQYTZACAANgIAQeTVAEF/NgIAQejVAEGc2QAoAgA2AgBBkNkAQQA2AgADQCABQYDWAGogAUH01QBqIgI2AgAgAiABQezVAGoiAzYCACABQfjVAGogAzYCACABQYjWAGogAUH81QBqIgM2AgAgAyACNgIAIAFBkNYAaiABQYTWAGoiAjYCACACIAM2AgAgAUGM1gBqIAI2AgAgAUEgaiIBQYACRw0AC0F4IABrQQ9xIgEgAGoiAiAGQThrIgMgAWsiAUEBcjYCBEHg1QBBrNkAKAIANgIAQdDVACABNgIAQdzVACACNgIAIAAgA2pBODYCBAwCCyAAIAJNDQAgAiADSQ0AIAEoAgxBCHENAEF4IAJrQQ9xIgAgAmoiA0HQ1QAoAgAgBmoiByAAayIAQQFyNgIEIAEgBSAGajYCBEHg1QBBrNkAKAIANgIAQdDVACAANgIAQdzVACADNgIAIAIgB2pBODYCBAwBCyAAQdTVACgCAEkEQEHU1QAgADYCAAsgACAGaiEDQYTZACEBAkACQAJAA0AgAyABKAIARwRAIAEoAggiAQ0BDAILCyABLQAMQQhxRQ0BC0GE2QAhAQNAIAEoAgAiAyACTQRAIAMgASgCBGoiBSACSw0DCyABKAIIIQEMAAsACyABIAA2AgAgASABKAIEIAZqNgIEIABBeCAAa0EPcWoiCSAEQQNyNgIEIANBeCADa0EPcWoiBiAEIAlqIgRrIQEgAiAGRgRAQdzVACAENgIAQdDVAEHQ1QAoAgAgAWoiADYCACAEIABBAXI2AgQMCAtB2NUAKAIAIAZGBEBB2NUAIAQ2AgBBzNUAQczVACgCACABaiIANgIAIAQgAEEBcjYCBCAAIARqIAA2AgAMCAsgBigCBCIFQQNxQQFHDQYgBUF4cSEIIAVB/wFNBEAgBUEDdiEDIAYoAggiACAGKAIMIgJGBEBBxNUAQcTVACgCAEF+IAN3cTYCAAwHCyACIAA2AgggACACNgIMDAYLIAYoAhghByAGIAYoAgwiAEcEQCAAIAYoAggiAjYCCCACIAA2AgwMBQsgBkEUaiICKAIAIgVFBEAgBigCECIFRQ0EIAZBEGohAgsDQCACIQMgBSIAQRRqIgIoAgAiBQ0AIABBEGohAiAAKAIQIgUNAAsgA0EANgIADAQLQXggAGtBD3EiASAAaiIHIAZBOGsiAyABayIBQQFyNgIEIAAgA2pBODYCBCACIAVBNyAFa0EPcWpBP2siAyADIAJBEGpJGyIDQSM2AgRB4NUAQazZACgCADYCAEHQ1QAgATYCAEHc1QAgBzYCACADQRBqQYzZACkCADcCACADQYTZACkCADcCCEGM2QAgA0EIajYCAEGI2QAgBjYCAEGE2QAgADYCAEGQ2QBBADYCACADQSRqIQEDQCABQQc2AgAgBSABQQRqIgFLDQALIAIgA0YNACADIAMoAgRBfnE2AgQgAyADIAJrIgU2AgAgAiAFQQFyNgIEIAVB/wFNBEAgBUF4cUHs1QBqIQACf0HE1QAoAgAiAUEBIAVBA3Z0IgNxRQRAQcTVACABIANyNgIAIAAMAQsgACgCCAsiASACNgIMIAAgAjYCCCACIAA2AgwgAiABNgIIDAELQR8hASAFQf///wdNBEAgBUEmIAVBCHZnIgBrdkEBcSAAQQF0a0E+aiEBCyACIAE2AhwgAkIANwIQIAFBAnRB9NcAaiEAQcjVACgCACIDQQEgAXQiBnFFBEAgACACNgIAQcjVACADIAZyNgIAIAIgADYCGCACIAI2AgggAiACNgIMDAELIAVBGSABQQF2a0EAIAFBH0cbdCEBIAAoAgAhAwJAA0AgAyIAKAIEQXhxIAVGDQEgAUEddiEDIAFBAXQhASAAIANBBHFqQRBqIgYoAgAiAw0ACyAGIAI2AgAgAiAANgIYIAIgAjYCDCACIAI2AggMAQsgACgCCCIBIAI2AgwgACACNgIIIAJBADYCGCACIAA2AgwgAiABNgIIC0HQ1QAoAgAiASAETQ0AQdzVACgCACIAIARqIgIgASAEayIBQQFyNgIEQdDVACABNgIAQdzVACACNgIAIAAgBEEDcjYCBCAAQQhqIQEMCAtBACEBQbTZAEEwNgIADAcLQQAhAAsgB0UNAAJAIAYoAhwiAkECdEH01wBqIgMoAgAgBkYEQCADIAA2AgAgAA0BQcjVAEHI1QAoAgBBfiACd3E2AgAMAgsgB0EQQRQgBygCECAGRhtqIAA2AgAgAEUNAQsgACAHNgIYIAYoAhAiAgRAIAAgAjYCECACIAA2AhgLIAZBFGooAgAiAkUNACAAQRRqIAI2AgAgAiAANgIYCyABIAhqIQEgBiAIaiIGKAIEIQULIAYgBUF+cTYCBCABIARqIAE2AgAgBCABQQFyNgIEIAFB/wFNBEAgAUF4cUHs1QBqIQACf0HE1QAoAgAiAkEBIAFBA3Z0IgFxRQRAQcTVACABIAJyNgIAIAAMAQsgACgCCAsiASAENgIMIAAgBDYCCCAEIAA2AgwgBCABNgIIDAELQR8hBSABQf///wdNBEAgAUEmIAFBCHZnIgBrdkEBcSAAQQF0a0E+aiEFCyAEIAU2AhwgBEIANwIQIAVBAnRB9NcAaiEAQcjVACgCACICQQEgBXQiA3FFBEAgACAENgIAQcjVACACIANyNgIAIAQgADYCGCAEIAQ2AgggBCAENgIMDAELIAFBGSAFQQF2a0EAIAVBH0cbdCEFIAAoAgAhAAJAA0AgACICKAIEQXhxIAFGDQEgBUEddiEAIAVBAXQhBSACIABBBHFqQRBqIgMoAgAiAA0ACyADIAQ2AgAgBCACNgIYIAQgBDYCDCAEIAQ2AggMAQsgAigCCCIAIAQ2AgwgAiAENgIIIARBADYCGCAEIAI2AgwgBCAANgIICyAJQQhqIQEMAgsCQCAHRQ0AAkAgAygCHCIBQQJ0QfTXAGoiAigCACADRgRAIAIgADYCACAADQFByNUAIAhBfiABd3EiCDYCAAwCCyAHQRBBFCAHKAIQIANGG2ogADYCACAARQ0BCyAAIAc2AhggAygCECIBBEAgACABNgIQIAEgADYCGAsgA0EUaigCACIBRQ0AIABBFGogATYCACABIAA2AhgLAkAgBUEPTQRAIAMgBCAFaiIAQQNyNgIEIAAgA2oiACAAKAIEQQFyNgIEDAELIAMgBGoiAiAFQQFyNgIEIAMgBEEDcjYCBCACIAVqIAU2AgAgBUH/AU0EQCAFQXhxQezVAGohAAJ/QcTVACgCACIBQQEgBUEDdnQiBXFFBEBBxNUAIAEgBXI2AgAgAAwBCyAAKAIICyIBIAI2AgwgACACNgIIIAIgADYCDCACIAE2AggMAQtBHyEBIAVB////B00EQCAFQSYgBUEIdmciAGt2QQFxIABBAXRrQT5qIQELIAIgATYCHCACQgA3AhAgAUECdEH01wBqIQBBASABdCIEIAhxRQRAIAAgAjYCAEHI1QAgBCAIcjYCACACIAA2AhggAiACNgIIIAIgAjYCDAwBCyAFQRkgAUEBdmtBACABQR9HG3QhASAAKAIAIQQCQANAIAQiACgCBEF4cSAFRg0BIAFBHXYhBCABQQF0IQEgACAEQQRxakEQaiIGKAIAIgQNAAsgBiACNgIAIAIgADYCGCACIAI2AgwgAiACNgIIDAELIAAoAggiASACNgIMIAAgAjYCCCACQQA2AhggAiAANgIMIAIgATYCCAsgA0EIaiEBDAELAkAgCUUNAAJAIAAoAhwiAUECdEH01wBqIgIoAgAgAEYEQCACIAM2AgAgAw0BQcjVACALQX4gAXdxNgIADAILIAlBEEEUIAkoAhAgAEYbaiADNgIAIANFDQELIAMgCTYCGCAAKAIQIgEEQCADIAE2AhAgASADNgIYCyAAQRRqKAIAIgFFDQAgA0EUaiABNgIAIAEgAzYCGAsCQCAFQQ9NBEAgACAEIAVqIgFBA3I2AgQgACABaiIBIAEoAgRBAXI2AgQMAQsgACAEaiIHIAVBAXI2AgQgACAEQQNyNgIEIAUgB2ogBTYCACAIBEAgCEF4cUHs1QBqIQFB2NUAKAIAIQMCf0EBIAhBA3Z0IgIgBnFFBEBBxNUAIAIgBnI2AgAgAQwBCyABKAIICyICIAM2AgwgASADNgIIIAMgATYCDCADIAI2AggLQdjVACAHNgIAQczVACAFNgIACyAAQQhqIQELIApBEGokACABC0MAIABFBEA/AEEQdA8LAkAgAEH//wNxDQAgAEEASA0AIABBEHZAACIAQX9GBEBBtNkAQTA2AgBBfw8LIABBEHQPCwALC5lCIgBBgAgLDQEAAAAAAAAAAgAAAAMAQZgICwUEAAAABQBBqAgLCQYAAAAHAAAACABB5AgLwjJJbnZhbGlkIGNoYXIgaW4gdXJsIHF1ZXJ5AFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fYm9keQBDb250ZW50LUxlbmd0aCBvdmVyZmxvdwBDaHVuayBzaXplIG92ZXJmbG93AEludmFsaWQgbWV0aG9kIGZvciBIVFRQL3gueCByZXF1ZXN0AEludmFsaWQgbWV0aG9kIGZvciBSVFNQL3gueCByZXF1ZXN0AEV4cGVjdGVkIFNPVVJDRSBtZXRob2QgZm9yIElDRS94LnggcmVxdWVzdABJbnZhbGlkIGNoYXIgaW4gdXJsIGZyYWdtZW50IHN0YXJ0AEV4cGVjdGVkIGRvdABTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3N0YXR1cwBJbnZhbGlkIHJlc3BvbnNlIHN0YXR1cwBFeHBlY3RlZCBMRiBhZnRlciBoZWFkZXJzAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMAVXNlciBjYWxsYmFjayBlcnJvcgBgb25fcmVzZXRgIGNhbGxiYWNrIGVycm9yAGBvbl9jaHVua19oZWFkZXJgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2JlZ2luYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlYCBjYWxsYmFjayBlcnJvcgBgb25fc3RhdHVzX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdmVyc2lvbl9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3VybF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3Byb3RvY29sX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWV0aG9kX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX25hbWVgIGNhbGxiYWNrIGVycm9yAFVuZXhwZWN0ZWQgY2hhciBpbiB1cmwgc2VydmVyAEludmFsaWQgaGVhZGVyIHZhbHVlIGNoYXIASW52YWxpZCBoZWFkZXIgZmllbGQgY2hhcgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3ZlcnNpb24ASW52YWxpZCBtaW5vciB2ZXJzaW9uAEludmFsaWQgbWFqb3IgdmVyc2lvbgBFeHBlY3RlZCBzcGFjZSBhZnRlciB2ZXJzaW9uAEV4cGVjdGVkIENSTEYgYWZ0ZXIgdmVyc2lvbgBJbnZhbGlkIEhUVFAgdmVyc2lvbgBJbnZhbGlkIGhlYWRlciB0b2tlbgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3VybABJbnZhbGlkIGNoYXJhY3RlcnMgaW4gdXJsAFVuZXhwZWN0ZWQgc3RhcnQgY2hhciBpbiB1cmwARG91YmxlIEAgaW4gdXJsAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fcHJvdG9jb2wARW1wdHkgQ29udGVudC1MZW5ndGgASW52YWxpZCBjaGFyYWN0ZXIgaW4gQ29udGVudC1MZW5ndGgAVHJhbnNmZXItRW5jb2RpbmcgY2FuJ3QgYmUgcHJlc2VudCB3aXRoIENvbnRlbnQtTGVuZ3RoAER1cGxpY2F0ZSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXIgaW4gdXJsIHBhdGgAQ29udGVudC1MZW5ndGggY2FuJ3QgYmUgcHJlc2VudCB3aXRoIFRyYW5zZmVyLUVuY29kaW5nAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgY2h1bmsgc2l6ZQBFeHBlY3RlZCBMRiBhZnRlciBjaHVuayBzaXplAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIHNpemUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfdmFsdWUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyB2YWx1ZQBVbmV4cGVjdGVkIHdoaXRlc3BhY2UgYWZ0ZXIgaGVhZGVyIHZhbHVlAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgaGVhZGVyIHZhbHVlAE1pc3NpbmcgZXhwZWN0ZWQgTEYgYWZ0ZXIgaGVhZGVyIHZhbHVlAEludmFsaWQgYFRyYW5zZmVyLUVuY29kaW5nYCBoZWFkZXIgdmFsdWUATWlzc2luZyBleHBlY3RlZCBDUiBhZnRlciBjaHVuayBleHRlbnNpb24gdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBxdW90ZSB2YWx1ZQBJbnZhbGlkIHF1b3RlZC1wYWlyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAFBhdXNlZCBieSBvbl9oZWFkZXJzX2NvbXBsZXRlAEludmFsaWQgRU9GIHN0YXRlAG9uX3Jlc2V0IHBhdXNlAG9uX2NodW5rX2hlYWRlciBwYXVzZQBvbl9tZXNzYWdlX2JlZ2luIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl92YWx1ZSBwYXVzZQBvbl9zdGF0dXNfY29tcGxldGUgcGF1c2UAb25fdmVyc2lvbl9jb21wbGV0ZSBwYXVzZQBvbl91cmxfY29tcGxldGUgcGF1c2UAb25fcHJvdG9jb2xfY29tcGxldGUgcGF1c2UAb25fY2h1bmtfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX3ZhbHVlX2NvbXBsZXRlIHBhdXNlAG9uX21lc3NhZ2VfY29tcGxldGUgcGF1c2UAb25fbWV0aG9kX2NvbXBsZXRlIHBhdXNlAG9uX2hlYWRlcl9maWVsZF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19leHRlbnNpb25fbmFtZSBwYXVzZQBVbmV4cGVjdGVkIHNwYWNlIGFmdGVyIHN0YXJ0IGxpbmUATWlzc2luZyBleHBlY3RlZCBDUiBhZnRlciByZXNwb25zZSBsaW5lAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fY2h1bmtfZXh0ZW5zaW9uX25hbWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBuYW1lAE1pc3NpbmcgZXhwZWN0ZWQgQ1IgYWZ0ZXIgY2h1bmsgZXh0ZW5zaW9uIG5hbWUASW52YWxpZCBzdGF0dXMgY29kZQBQYXVzZSBvbiBDT05ORUNUL1VwZ3JhZGUAUGF1c2Ugb24gUFJJL1VwZ3JhZGUARXhwZWN0ZWQgSFRUUC8yIENvbm5lY3Rpb24gUHJlZmFjZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX21ldGhvZABFeHBlY3RlZCBzcGFjZSBhZnRlciBtZXRob2QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfZmllbGQAUGF1c2VkAEludmFsaWQgd29yZCBlbmNvdW50ZXJlZABJbnZhbGlkIG1ldGhvZCBlbmNvdW50ZXJlZABNaXNzaW5nIGV4cGVjdGVkIENSIGFmdGVyIGNodW5rIGRhdGEARXhwZWN0ZWQgTEYgYWZ0ZXIgY2h1bmsgZGF0YQBVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNjaGVtYQBSZXF1ZXN0IGhhcyBpbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AARGF0YSBhZnRlciBgQ29ubmVjdGlvbjogY2xvc2VgAFNXSVRDSF9QUk9YWQBVU0VfUFJPWFkATUtBQ1RJVklUWQBVTlBST0NFU1NBQkxFX0VOVElUWQBRVUVSWQBDT1BZAE1PVkVEX1BFUk1BTkVOVExZAFRPT19FQVJMWQBOT1RJRlkARkFJTEVEX0RFUEVOREVOQ1kAQkFEX0dBVEVXQVkAUExBWQBQVVQAQ0hFQ0tPVVQAR0FURVdBWV9USU1FT1VUAFJFUVVFU1RfVElNRU9VVABORVRXT1JLX0NPTk5FQ1RfVElNRU9VVABDT05ORUNUSU9OX1RJTUVPVVQATE9HSU5fVElNRU9VVABORVRXT1JLX1JFQURfVElNRU9VVABQT1NUAE1JU0RJUkVDVEVEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9SRVFVRVNUAENMSUVOVF9DTE9TRURfTE9BRF9CQUxBTkNFRF9SRVFVRVNUAEJBRF9SRVFVRVNUAEhUVFBfUkVRVUVTVF9TRU5UX1RPX0hUVFBTX1BPUlQAUkVQT1JUAElNX0FfVEVBUE9UAFJFU0VUX0NPTlRFTlQATk9fQ09OVEVOVABQQVJUSUFMX0NPTlRFTlQASFBFX0lOVkFMSURfQ09OU1RBTlQASFBFX0NCX1JFU0VUAEdFVABIUEVfU1RSSUNUAENPTkZMSUNUAFRFTVBPUkFSWV9SRURJUkVDVABQRVJNQU5FTlRfUkVESVJFQ1QAQ09OTkVDVABNVUxUSV9TVEFUVVMASFBFX0lOVkFMSURfU1RBVFVTAFRPT19NQU5ZX1JFUVVFU1RTAEVBUkxZX0hJTlRTAFVOQVZBSUxBQkxFX0ZPUl9MRUdBTF9SRUFTT05TAE9QVElPTlMAU1dJVENISU5HX1BST1RPQ09MUwBWQVJJQU5UX0FMU09fTkVHT1RJQVRFUwBNVUxUSVBMRV9DSE9JQ0VTAElOVEVSTkFMX1NFUlZFUl9FUlJPUgBXRUJfU0VSVkVSX1VOS05PV05fRVJST1IAUkFJTEdVTl9FUlJPUgBJREVOVElUWV9QUk9WSURFUl9BVVRIRU5USUNBVElPTl9FUlJPUgBTU0xfQ0VSVElGSUNBVEVfRVJST1IASU5WQUxJRF9YX0ZPUldBUkRFRF9GT1IAU0VUX1BBUkFNRVRFUgBHRVRfUEFSQU1FVEVSAEhQRV9VU0VSAFNFRV9PVEhFUgBIUEVfQ0JfQ0hVTktfSEVBREVSAEV4cGVjdGVkIExGIGFmdGVyIENSAE1LQ0FMRU5EQVIAU0VUVVAAV0VCX1NFUlZFUl9JU19ET1dOAFRFQVJET1dOAEhQRV9DTE9TRURfQ09OTkVDVElPTgBIRVVSSVNUSUNfRVhQSVJBVElPTgBESVNDT05ORUNURURfT1BFUkFUSU9OAE5PTl9BVVRIT1JJVEFUSVZFX0lORk9STUFUSU9OAEhQRV9JTlZBTElEX1ZFUlNJT04ASFBFX0NCX01FU1NBR0VfQkVHSU4AU0lURV9JU19GUk9aRU4ASFBFX0lOVkFMSURfSEVBREVSX1RPS0VOAElOVkFMSURfVE9LRU4ARk9SQklEREVOAEVOSEFOQ0VfWU9VUl9DQUxNAEhQRV9JTlZBTElEX1VSTABCTE9DS0VEX0JZX1BBUkVOVEFMX0NPTlRST0wATUtDT0wAQUNMAEhQRV9JTlRFUk5BTABSRVFVRVNUX0hFQURFUl9GSUVMRFNfVE9PX0xBUkdFX1VOT0ZGSUNJQUwASFBFX09LAFVOTElOSwBVTkxPQ0sAUFJJAFJFVFJZX1dJVEgASFBFX0lOVkFMSURfQ09OVEVOVF9MRU5HVEgASFBFX1VORVhQRUNURURfQ09OVEVOVF9MRU5HVEgARkxVU0gAUFJPUFBBVENIAE0tU0VBUkNIAFVSSV9UT09fTE9ORwBQUk9DRVNTSU5HAE1JU0NFTExBTkVPVVNfUEVSU0lTVEVOVF9XQVJOSU5HAE1JU0NFTExBTkVPVVNfV0FSTklORwBIUEVfSU5WQUxJRF9UUkFOU0ZFUl9FTkNPRElORwBFeHBlY3RlZCBDUkxGAEhQRV9JTlZBTElEX0NIVU5LX1NJWkUATU9WRQBDT05USU5VRQBIUEVfQ0JfU1RBVFVTX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJTX0NPTVBMRVRFAEhQRV9DQl9WRVJTSU9OX0NPTVBMRVRFAEhQRV9DQl9VUkxfQ09NUExFVEUASFBFX0NCX1BST1RPQ09MX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19DT01QTEVURQBIUEVfQ0JfSEVBREVSX1ZBTFVFX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19FWFRFTlNJT05fVkFMVUVfQ09NUExFVEUASFBFX0NCX0NIVU5LX0VYVEVOU0lPTl9OQU1FX0NPTVBMRVRFAEhQRV9DQl9NRVNTQUdFX0NPTVBMRVRFAEhQRV9DQl9NRVRIT0RfQ09NUExFVEUASFBFX0NCX0hFQURFUl9GSUVMRF9DT01QTEVURQBERUxFVEUASFBFX0lOVkFMSURfRU9GX1NUQVRFAElOVkFMSURfU1NMX0NFUlRJRklDQVRFAFBBVVNFAE5PX1JFU1BPTlNFAFVOU1VQUE9SVEVEX01FRElBX1RZUEUAR09ORQBOT1RfQUNDRVBUQUJMRQBTRVJWSUNFX1VOQVZBSUxBQkxFAFJBTkdFX05PVF9TQVRJU0ZJQUJMRQBPUklHSU5fSVNfVU5SRUFDSEFCTEUAUkVTUE9OU0VfSVNfU1RBTEUAUFVSR0UATUVSR0UAUkVRVUVTVF9IRUFERVJfRklFTERTX1RPT19MQVJHRQBSRVFVRVNUX0hFQURFUl9UT09fTEFSR0UAUEFZTE9BRF9UT09fTEFSR0UASU5TVUZGSUNJRU5UX1NUT1JBR0UASFBFX1BBVVNFRF9VUEdSQURFAEhQRV9QQVVTRURfSDJfVVBHUkFERQBTT1VSQ0UAQU5OT1VOQ0UAVFJBQ0UASFBFX1VORVhQRUNURURfU1BBQ0UAREVTQ1JJQkUAVU5TVUJTQ1JJQkUAUkVDT1JEAEhQRV9JTlZBTElEX01FVEhPRABOT1RfRk9VTkQAUFJPUEZJTkQAVU5CSU5EAFJFQklORABVTkFVVEhPUklaRUQATUVUSE9EX05PVF9BTExPV0VEAEhUVFBfVkVSU0lPTl9OT1RfU1VQUE9SVEVEAEFMUkVBRFlfUkVQT1JURUQAQUNDRVBURUQATk9UX0lNUExFTUVOVEVEAExPT1BfREVURUNURUQASFBFX0NSX0VYUEVDVEVEAEhQRV9MRl9FWFBFQ1RFRABDUkVBVEVEAElNX1VTRUQASFBFX1BBVVNFRABUSU1FT1VUX09DQ1VSRUQAUEFZTUVOVF9SRVFVSVJFRABQUkVDT05ESVRJT05fUkVRVUlSRUQAUFJPWFlfQVVUSEVOVElDQVRJT05fUkVRVUlSRUQATkVUV09SS19BVVRIRU5USUNBVElPTl9SRVFVSVJFRABMRU5HVEhfUkVRVUlSRUQAU1NMX0NFUlRJRklDQVRFX1JFUVVJUkVEAFVQR1JBREVfUkVRVUlSRUQAUEFHRV9FWFBJUkVEAFBSRUNPTkRJVElPTl9GQUlMRUQARVhQRUNUQVRJT05fRkFJTEVEAFJFVkFMSURBVElPTl9GQUlMRUQAU1NMX0hBTkRTSEFLRV9GQUlMRUQATE9DS0VEAFRSQU5TRk9STUFUSU9OX0FQUExJRUQATk9UX01PRElGSUVEAE5PVF9FWFRFTkRFRABCQU5EV0lEVEhfTElNSVRfRVhDRUVERUQAU0lURV9JU19PVkVSTE9BREVEAEhFQUQARXhwZWN0ZWQgSFRUUC8sIFJUU1AvIG9yIElDRS8A5xUAAK8VAACkEgAAkhoAACYWAACeFAAA2xkAAHkVAAB+EgAA/hQAADYVAAALFgAA2BYAAPMSAABCGAAArBYAABIVAAAUFwAA7xcAAEgUAABxFwAAshoAAGsZAAB+GQAANRQAAIIaAABEFwAA/RYAAB4YAACHFwAAqhkAAJMSAAAHGAAALBcAAMoXAACkFwAA5xUAAOcVAABYFwAAOxgAAKASAAAtHAAAwxEAAEgRAADeEgAAQhMAAKQZAAD9EAAA9xUAAKUVAADvFgAA+BkAAEoWAABWFgAA9RUAAAoaAAAIGgAAARoAAKsVAABCEgAA1xAAAEwRAAAFGQAAVBYAAB4RAADKGQAAyBkAAE4WAAD/GAAAcRQAAPAVAADuFQAAlBkAAPwVAAC/GQAAmxkAAHwUAABDEQAAcBgAAJUUAAAnFAAAGRQAANUSAADUGQAARBYAAPcQAEG5OwsBAQBB0DsL4AEBAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBuj0LBAEAAAIAQdE9C14DBAMDAwMDAAADAwADAwADAwMDAwMDAwMDAAUAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAwADAEG6PwsEAQAAAgBB0T8LXgMAAwMDAwMAAAMDAAMDAAMDAwMDAwMDAwMABAAFAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwADAAMAQbDBAAsNbG9zZWVlcC1hbGl2ZQBBycEACwEBAEHgwQAL4AEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBycMACwEBAEHgwwAL5wEBAQEBAQEBAQEBAQECAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAWNodW5rZWQAQfHFAAteAQABAQEBAQAAAQEAAQEAAQEBAQEBAQEBAQAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQBB0McACyFlY3Rpb25lbnQtbGVuZ3Rob25yb3h5LWNvbm5lY3Rpb24AQYDIAAsgcmFuc2Zlci1lbmNvZGluZ3BncmFkZQ0KDQpTTQ0KDQoAQanIAAsFAQIAAQMAQcDIAAtfBAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAQanKAAsFAQIAAQMAQcDKAAtfBAUFBgUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAQanMAAsEAQAAAQBBwcwAC14CAgACAgICAgICAgICAgICAgICAgICAgICAgICAgIAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAEGpzgALBQECAAEDAEHAzgALXwQFAAAFBQUFBQUFBQUFBQYFBQUFBQUFBQUFBQUABQAHCAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQAFAAUABQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUAAAAFAEGp0AALBQEBAAEBAEHA0AALAQEAQdrQAAtBAgAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQanSAAsFAQEAAQEAQcDSAAsBAQBBytIACwYCAAAAAAIAQeHSAAs6AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBBoNQAC50BTk9VTkNFRUNLT1VUTkVDVEVURUNSSUJFTFVTSEVURUFEU0VBUkNIUkdFQ1RJVklUWUxFTkRBUlZFT1RJRllQVElPTlNDSFNFQVlTVEFUQ0hHRVVFUllPUkRJUkVDVE9SVFJDSFBBUkFNRVRFUlVSQ0VCU0NSSUJFQVJET1dOQUNFSU5ETktDS1VCU0NSSUJFVFRQQ0VUU1BBRFRQLw==",ww;Object.defineProperty(E3,"exports",{get:()=>ww||(ww=Gfe.from(Yfe,"base64"))})});var UE=x((zTe,m3)=>{"use strict";function xE(){let e=globalThis.__secureExecBuiltinZlibModule;if(!e)throw new Error("node:zlib bridge module is not available");return e}m3.exports=new Proxy({},{get(e,t){return xE()[t]},has(e,t){return t in xE()},ownKeys(){return Reflect.ownKeys(xE())},getOwnPropertyDescriptor(e,t){let r=Object.getOwnPropertyDescriptor(xE(),t);return r||{configurable:!0,enumerable:!0,value:void 0,writable:!1}}})});var id=x((KTe,_3)=>{"use strict";var B3=["GET","HEAD","POST"],Wfe=new Set(B3),Vfe=[101,204,205,304],I3=[301,302,303,307,308],Jfe=new Set(I3),b3=["1","7","9","11","13","15","17","19","20","21","22","23","25","37","42","43","53","69","77","79","87","95","101","102","103","104","109","110","111","113","115","117","119","123","135","137","139","143","161","179","389","427","465","512","513","514","515","526","530","531","532","540","548","554","556","563","587","601","636","989","990","993","995","1719","1720","1723","2049","3659","4045","4190","5060","5061","6000","6566","6665","6666","6667","6668","6669","6679","6697","10080"],jfe=new Set(b3),C3=["no-referrer","no-referrer-when-downgrade","same-origin","origin","strict-origin","origin-when-cross-origin","strict-origin-when-cross-origin","unsafe-url"],zfe=["",...C3],Kfe=new Set(C3),Xfe=["follow","manual","error"],Q3=["GET","HEAD","OPTIONS","TRACE"],Zfe=new Set(Q3),$fe=["navigate","same-origin","no-cors","cors"],eue=["omit","same-origin","include"],tue=["default","no-store","reload","no-cache","force-cache","only-if-cached"],rue=["content-encoding","content-language","content-location","content-type","content-length"],nue=["half"],w3=["CONNECT","TRACE","TRACK"],iue=new Set(w3),S3=["audio","audioworklet","font","image","manifest","paintworklet","script","style","track","video","xslt",""],sue=new Set(S3);_3.exports={subresource:S3,forbiddenMethods:w3,requestBodyHeader:rue,referrerPolicy:zfe,requestRedirect:Xfe,requestMode:$fe,requestCredentials:eue,requestCache:tue,redirectStatus:I3,corsSafeListedMethods:B3,nullBodyStatus:Vfe,safeMethods:Q3,badPorts:b3,requestDuplex:nue,subresourceSet:sue,badPortsSet:jfe,redirectStatusSet:Jfe,corsSafeListedMethodsSet:Wfe,safeMethodsSet:Zfe,forbiddenMethodsSet:iue,referrerPolicyTokens:Kfe}});var R3=x((XTe,v3)=>{"use strict";var Sw=Symbol.for("undici.globalOrigin.1");function oue(){return globalThis[Sw]}function aue(e){if(e===void 0){Object.defineProperty(globalThis,Sw,{value:void 0,writable:!0,enumerable:!1,configurable:!1});return}let t=new URL(e);if(t.protocol!=="http:"&&t.protocol!=="https:")throw new TypeError(`Only http & https urls are allowed, received ${t.protocol}`);Object.defineProperty(globalThis,Sw,{value:t,writable:!0,enumerable:!1,configurable:!1})}v3.exports={getGlobalOrigin:oue,setGlobalOrigin:aue}});var _w=x((ZTe,D3)=>{"use strict";var Aue=new TextDecoder;function fue(e){return e.length===0?"":(e[0]===239&&e[1]===187&&e[2]===191&&(e=e.subarray(3)),Aue.decode(e))}D3.exports={utf8DecodeBytes:fue}});var mf=x(($Te,F3)=>{"use strict";var T3=Wt(),{utf8DecodeBytes:uue}=_w();function cue(e,t,r){let n="";for(;r.positiont)return String.fromCharCode.apply(null,e);let r="",n=0,i=65535;for(;nt&&(i=t-n),r+=String.fromCharCode.apply(null,e.subarray(n,n+=i));return r}var pue=/[^\x00-\xFF]/;function Eue(e){return T3(!pue.test(e)),e}function yue(e){return JSON.parse(uue(e))}function mue(e,t=!0,r=!0){return M3(e,t,r,N3)}function M3(e,t,r,n){let i=0,s=e.length-1;if(t)for(;i0&&n(e.charCodeAt(s));)s--;return i===0&&s===e.length-1?e:e.slice(i,s+1)}function Bue(e){let t=JSON.stringify(e);if(t===void 0)throw new TypeError("Value is not JSON serializable");return T3(typeof t=="string"),t}F3.exports={collectASequenceOfCodePoints:cue,collectASequenceOfCodePointsFast:lue,forgivingBase64:due,isASCIIWhitespace:N3,isomorphicDecode:gue,isomorphicEncode:Eue,parseJSONFromBytes:yue,removeASCIIWhitespace:mue,removeChars:M3,serializeJavascriptValueToJSONString:Bue}});var Bf=x((eNe,O3)=>{"use strict";var PE=Wt(),{forgivingBase64:Iue,collectASequenceOfCodePoints:vw,collectASequenceOfCodePointsFast:sd,isomorphicDecode:bue,removeASCIIWhitespace:Cue,removeChars:Que}=mf(),wue=new TextEncoder,od=/^[-!#$%&'*+.^_|~A-Za-z0-9]+$/u,Sue=/[\u000A\u000D\u0009\u0020]/u,_ue=/^[\u0009\u0020-\u007E\u0080-\u00FF]+$/u;function vue(e){PE(e.protocol==="data:");let t=U3(e,!0);t=t.slice(5);let r={position:0},n=sd(",",t,r),i=n.length;if(n=Cue(n,!0,!0),r.position>=t.length)return"failure";r.position++;let s=t.slice(i+1),o=L3(s);if(/;(?:\u0020*)base64$/ui.test(n)){let A=bue(o);if(o=Iue(A),o==="failure")return"failure";n=n.slice(0,-6),n=n.replace(/(\u0020+)$/u,""),n=n.slice(0,-1)}n.startsWith(";")&&(n="text/plain"+n);let a=Rw(n);return a==="failure"&&(a=Rw("text/plain;charset=US-ASCII")),{mimeType:a,body:o}}function U3(e,t=!1){if(!t)return e.href;let r=e.href,n=e.hash.length,i=n===0?r:r.substring(0,r.length-n);return!n&&r.endsWith("#")?i.slice(0,-1):i}function L3(e){let t=wue.encode(e);return Rue(t)}function k3(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}function x3(e){return e>=48&&e<=57?e-48:(e&223)-55}function Rue(e){let t=e.length,r=new Uint8Array(t),n=0,i=0;for(;i=e.length)return"failure";t.position++;let n=sd(";",e,t);if(n=LE(n,!1,!0),n.length===0||!od.test(n))return"failure";let i=r.toLowerCase(),s=n.toLowerCase(),o={type:i,subtype:s,parameters:new Map,essence:`${i}/${s}`};for(;t.positionSue.test(f),e,t);let a=vw(f=>f!==";"&&f!=="=",e,t);if(a=a.toLowerCase(),t.position=e.length)break;let A=null;if(e[t.position]==='"')A=P3(e,t,!0),sd(";",e,t);else if(A=sd(";",e,t),A=LE(A,!1,!0),A.length===0)continue;a.length!==0&&od.test(a)&&(A.length===0||_ue.test(A))&&!o.parameters.has(a)&&o.parameters.set(a,A)}return o}function P3(e,t,r=!1){let n=t.position,i="";for(PE(e[t.position]==='"'),t.position++;i+=vw(o=>o!=='"'&&o!=="\\",e,t),!(t.position>=e.length);){let s=e[t.position];if(t.position++,s==="\\"){if(t.position>=e.length){i+="\\";break}i+=e[t.position],t.position++}else{PE(s==='"');break}}return r?i:e.slice(n,t.position)}function Due(e){PE(e!=="failure");let{parameters:t,essence:r}=e,n=r;for(let[i,s]of t.entries())n+=";",n+=i,n+="=",od.test(s)||(s=s.replace(/[\\"]/ug,"\\$&"),s='"'+s,s+='"'),n+=s;return n}function Tue(e){return e===13||e===10||e===9||e===32}function LE(e,t=!0,r=!0){return Que(e,t,r,Tue)}function Nue(e){switch(e.essence){case"application/ecmascript":case"application/javascript":case"application/x-ecmascript":case"application/x-javascript":case"text/ecmascript":case"text/javascript":case"text/javascript1.0":case"text/javascript1.1":case"text/javascript1.2":case"text/javascript1.3":case"text/javascript1.4":case"text/javascript1.5":case"text/jscript":case"text/livescript":case"text/x-ecmascript":case"text/x-javascript":return"text/javascript";case"application/json":case"text/json":return"application/json";case"image/svg+xml":return"image/svg+xml";case"text/xml":case"application/xml":return"application/xml"}return e.subtype.endsWith("+json")?"application/json":e.subtype.endsWith("+xml")?"application/xml":""}O3.exports={dataURLProcessor:vue,URLSerializer:U3,stringPercentDecode:L3,parseMIMEType:Rw,collectAnHTTPQuotedString:P3,serializeAMimeType:Due,removeHTTPWhitespace:LE,minimizeSupportedMimeType:Nue,HTTP_TOKEN_CODEPOINTS:od}});var q3=x((tNe,H3)=>{"use strict";var Mue=globalThis.performance??{now(){return Date.now()},timeOrigin:Date.now()};H3.exports={performance:Mue}});var Dw=x((rNe,G3)=>{"use strict";function Fue(e){return e instanceof ArrayBuffer}function kue(e){return ArrayBuffer.isView(e)}function xue(e){return e instanceof Uint8Array}function Uue(e){return!1}G3.exports={isArrayBuffer:Fue,isArrayBufferView:kue,isProxy:Uue,isUint8Array:xue}});var If=x((nNe,Nw)=>{"use strict";var Tw=65536,Lue=4294967295;function Pue(){throw new Error(`Secure random number generation is not supported by this browser. -Use Chrome, Firefox or Internet Explorer 11`)}var Oue=at().Buffer,OE=globalThis.crypto||globalThis.msCrypto;OE&&OE.getRandomValues?Nw.exports=Hue:Nw.exports=Pue;function Hue(e,t){if(e>Lue)throw new RangeError("requested too many random bytes");var r=Oue.allocUnsafe(e);if(e>0)if(e>Tw)for(var n=0;n{var que={}.toString;Y3.exports=Array.isArray||function(e){return que.call(e)=="[object Array]"}});var J3=x((sNe,V3)=>{"use strict";var Gue=$i(),Yue=Js(),Wue=Yue("TypedArray.prototype.buffer",!0),Vue=Ib();V3.exports=Wue||function(t){if(!Vue(t))throw new Gue("Not a Typed Array");return t.buffer}});var ad=x((oNe,z3)=>{"use strict";var ss=at().Buffer,Jue=W3(),jue=J3(),zue=ArrayBuffer.isView||function(t){try{return jue(t),!0}catch{return!1}},Kue=typeof Uint8Array<"u",j3=typeof ArrayBuffer<"u"&&typeof Uint8Array<"u",Xue=j3&&(ss.prototype instanceof Uint8Array||ss.TYPED_ARRAY_SUPPORT);z3.exports=function(t,r){if(ss.isBuffer(t))return t.constructor&&!("isBuffer"in t)?ss.from(t):t;if(typeof t=="string")return ss.from(t,r);if(j3&&zue(t)){if(t.byteLength===0)return ss.alloc(0);if(Xue){var n=ss.from(t.buffer,t.byteOffset,t.byteLength);if(n.byteLength===t.byteLength)return n}var i=t instanceof Uint8Array?t:new Uint8Array(t.buffer,t.byteOffset,t.byteLength),s=ss.from(i);if(s.length===t.byteLength)return s}if(Kue&&t instanceof Uint8Array)return ss.from(t);var o=Jue(t);if(o)for(var a=0;a255||~~A!==A)throw new RangeError("Array items must be numbers in the range 0-255.")}if(o||ss.isBuffer(t)&&t.constructor&&typeof t.constructor.isBuffer=="function"&&t.constructor.isBuffer(t))return ss.from(t);throw new TypeError('The "data" argument must be a string, an Array, a Buffer, a Uint8Array, or a DataView.')}});var $3=x((aNe,Z3)=>{"use strict";var Zue=at().Buffer,$ue=ad(),X3=typeof Uint8Array<"u",ece=X3&&typeof ArrayBuffer<"u",K3=ece&&ArrayBuffer.isView;Z3.exports=function(e,t){if(typeof e=="string"||Zue.isBuffer(e)||X3&&e instanceof Uint8Array||K3&&K3(e))return $ue(e,t);throw new TypeError('The "data" argument must be a string, a Buffer, a Uint8Array, or a DataView')}});var Ad=x((ANe,Mw)=>{"use strict";typeof process>"u"||!process.version||process.version.indexOf("v0.")===0||process.version.indexOf("v1.")===0&&process.version.indexOf("v1.8.")!==0?Mw.exports={nextTick:tce}:Mw.exports=process;function tce(e,t,r,n){if(typeof e!="function")throw new TypeError('"callback" argument must be a function');var i=arguments.length,s,o;switch(i){case 0:case 1:return process.nextTick(e);case 2:return process.nextTick(function(){e.call(null,t)});case 3:return process.nextTick(function(){e.call(null,t,r)});case 4:return process.nextTick(function(){e.call(null,t,r,n)});default:for(s=new Array(i-1),o=0;o{var rce={}.toString;eL.exports=Array.isArray||function(e){return rce.call(e)=="[object Array]"}});var Fw=x((uNe,rL)=>{rL.exports=Zi().EventEmitter});var qE=x((kw,iL)=>{var HE=Gr(),Xo=HE.Buffer;function nL(e,t){for(var r in e)t[r]=e[r]}Xo.from&&Xo.alloc&&Xo.allocUnsafe&&Xo.allocUnsafeSlow?iL.exports=HE:(nL(HE,kw),kw.Buffer=Dc);function Dc(e,t,r){return Xo(e,t,r)}nL(Xo,Dc);Dc.from=function(e,t,r){if(typeof e=="number")throw new TypeError("Argument must not be a number");return Xo(e,t,r)};Dc.alloc=function(e,t,r){if(typeof e!="number")throw new TypeError("Argument must be a number");var n=Xo(e);return t!==void 0?typeof r=="string"?n.fill(t,r):n.fill(t):n.fill(0),n};Dc.allocUnsafe=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return Xo(e)};Dc.allocUnsafeSlow=function(e){if(typeof e!="number")throw new TypeError("Argument must be a number");return HE.SlowBuffer(e)}});var Tc=x(rn=>{function nce(e){return Array.isArray?Array.isArray(e):GE(e)==="[object Array]"}rn.isArray=nce;function ice(e){return typeof e=="boolean"}rn.isBoolean=ice;function sce(e){return e===null}rn.isNull=sce;function oce(e){return e==null}rn.isNullOrUndefined=oce;function ace(e){return typeof e=="number"}rn.isNumber=ace;function Ace(e){return typeof e=="string"}rn.isString=Ace;function fce(e){return typeof e=="symbol"}rn.isSymbol=fce;function uce(e){return e===void 0}rn.isUndefined=uce;function cce(e){return GE(e)==="[object RegExp]"}rn.isRegExp=cce;function lce(e){return typeof e=="object"&&e!==null}rn.isObject=lce;function hce(e){return GE(e)==="[object Date]"}rn.isDate=hce;function dce(e){return GE(e)==="[object Error]"||e instanceof Error}rn.isError=dce;function gce(e){return typeof e=="function"}rn.isFunction=gce;function pce(e){return e===null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"||typeof e=="symbol"||typeof e>"u"}rn.isPrimitive=pce;rn.isBuffer=Gr().Buffer.isBuffer;function GE(e){return Object.prototype.toString.call(e)}});var oL=x((lNe,xw)=>{"use strict";function Ece(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var sL=qE().Buffer,fd=Yr();function yce(e,t,r){e.copy(t,r)}xw.exports=(function(){function e(){Ece(this,e),this.head=null,this.tail=null,this.length=0}return e.prototype.push=function(r){var n={data:r,next:null};this.length>0?this.tail.next=n:this.head=n,this.tail=n,++this.length},e.prototype.unshift=function(r){var n={data:r,next:this.head};this.length===0&&(this.tail=n),this.head=n,++this.length},e.prototype.shift=function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}},e.prototype.clear=function(){this.head=this.tail=null,this.length=0},e.prototype.join=function(r){if(this.length===0)return"";for(var n=this.head,i=""+n.data;n=n.next;)i+=r+n.data;return i},e.prototype.concat=function(r){if(this.length===0)return sL.alloc(0);for(var n=sL.allocUnsafe(r>>>0),i=this.head,s=0;i;)yce(i.data,n,s),s+=i.data.length,i=i.next;return n},e})();fd&&fd.inspect&&fd.inspect.custom&&(xw.exports.prototype[fd.inspect.custom]=function(){var e=fd.inspect({length:this.length});return this.constructor.name+" "+e})});var Uw=x((hNe,aL)=>{"use strict";var YE=Ad();function mce(e,t){var r=this,n=this._readableState&&this._readableState.destroyed,i=this._writableState&&this._writableState.destroyed;return n||i?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,YE.nextTick(WE,this,e)):YE.nextTick(WE,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(s){!t&&s?r._writableState?r._writableState.errorEmitted||(r._writableState.errorEmitted=!0,YE.nextTick(WE,r,s)):YE.nextTick(WE,r,s):t&&t(s)}),this)}function Bce(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function WE(e,t){e.emit("error",t)}aL.exports={destroy:mce,undestroy:Bce}});var Pw=x((dNe,gL)=>{"use strict";var bf=Ad();gL.exports=Br;function fL(e){var t=this;this.next=null,this.entry=null,this.finish=function(){Lce(t,e)}}var Ice=!process.browser&&["v0.10","v0.9."].indexOf(process.version.slice(0,5))>-1?setImmediate:bf.nextTick,Nc;Br.WritableState=cd;var uL=Object.create(Tc());uL.inherits=ze();var bce={deprecate:Fb()},cL=Fw(),JE=qE().Buffer,Cce=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function Qce(e){return JE.from(e)}function wce(e){return JE.isBuffer(e)||e instanceof Cce}var lL=Uw();uL.inherits(Br,cL);function Sce(){}function cd(e,t){Nc=Nc||Cf(),e=e||{};var r=t instanceof Nc;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var n=e.highWaterMark,i=e.writableHighWaterMark,s=this.objectMode?16:16*1024;n||n===0?this.highWaterMark=n:r&&(i||i===0)?this.highWaterMark=i:this.highWaterMark=s,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var o=e.decodeStrings===!1;this.decodeStrings=!o,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(a){Mce(t,a)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new fL(this)}cd.prototype.getBuffer=function(){for(var t=this.bufferedRequest,r=[];t;)r.push(t),t=t.next;return r};(function(){try{Object.defineProperty(cd.prototype,"buffer",{get:bce.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch{}})();var VE;typeof Symbol=="function"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]=="function"?(VE=Function.prototype[Symbol.hasInstance],Object.defineProperty(Br,Symbol.hasInstance,{value:function(e){return VE.call(this,e)?!0:this!==Br?!1:e&&e._writableState instanceof cd}})):VE=function(e){return e instanceof this};function Br(e){if(Nc=Nc||Cf(),!VE.call(Br,this)&&!(this instanceof Nc))return new Br(e);this._writableState=new cd(e,this),this.writable=!0,e&&(typeof e.write=="function"&&(this._write=e.write),typeof e.writev=="function"&&(this._writev=e.writev),typeof e.destroy=="function"&&(this._destroy=e.destroy),typeof e.final=="function"&&(this._final=e.final)),cL.call(this)}Br.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))};function _ce(e,t){var r=new Error("write after end");e.emit("error",r),bf.nextTick(t,r)}function vce(e,t,r,n){var i=!0,s=!1;return r===null?s=new TypeError("May not write null values to stream"):typeof r!="string"&&r!==void 0&&!t.objectMode&&(s=new TypeError("Invalid non-string/buffer chunk")),s&&(e.emit("error",s),bf.nextTick(n,s),i=!1),i}Br.prototype.write=function(e,t,r){var n=this._writableState,i=!1,s=!n.objectMode&&wce(e);return s&&!JE.isBuffer(e)&&(e=Qce(e)),typeof t=="function"&&(r=t,t=null),s?t="buffer":t||(t=n.defaultEncoding),typeof r!="function"&&(r=Sce),n.ended?_ce(this,r):(s||vce(this,n,e,r))&&(n.pendingcb++,i=Dce(this,n,s,e,t,r)),i};Br.prototype.cork=function(){var e=this._writableState;e.corked++};Br.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&hL(this,e))};Br.prototype.setDefaultEncoding=function(t){if(typeof t=="string"&&(t=t.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((t+"").toLowerCase())>-1))throw new TypeError("Unknown encoding: "+t);return this._writableState.defaultEncoding=t,this};function Rce(e,t,r){return!e.objectMode&&e.decodeStrings!==!1&&typeof t=="string"&&(t=JE.from(t,r)),t}Object.defineProperty(Br.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function Dce(e,t,r,n,i,s){if(!r){var o=Rce(t,n,i);n!==o&&(r=!0,i="buffer",n=o)}var a=t.objectMode?1:n.length;t.length+=a;var A=t.length{"use strict";var pL=Ad(),Pce=Object.keys||function(e){var t=[];for(var r in e)t.push(r);return t};mL.exports=Zo;var EL=Object.create(Tc());EL.inherits=ze();var yL=qw(),Hw=Pw();EL.inherits(Zo,yL);for(Ow=Pce(Hw.prototype),jE=0;jE{"use strict";var Fc=Ad();TL.exports=er;var qce=tL(),ld;er.ReadableState=SL;var pNe=Zi().EventEmitter,CL=function(e,t){return e.listeners(t).length},Jw=Fw(),hd=qE().Buffer,Gce=(typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof self<"u"?self:{}).Uint8Array||function(){};function Yce(e){return hd.from(e)}function Wce(e){return hd.isBuffer(e)||e instanceof Gce}var QL=Object.create(Tc());QL.inherits=ze();var Gw=Yr(),_t=void 0;Gw&&Gw.debuglog?_t=Gw.debuglog("stream"):_t=function(){};var Vce=oL(),wL=Uw(),Mc;QL.inherits(er,Jw);var Yw=["error","close","destroy","pause","resume"];function Jce(e,t,r){if(typeof e.prependListener=="function")return e.prependListener(t,r);!e._events||!e._events[t]?e.on(t,r):qce(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]}function SL(e,t){ld=ld||Cf(),e=e||{};var r=t instanceof ld;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.readableObjectMode);var n=e.highWaterMark,i=e.readableHighWaterMark,s=this.objectMode?16:16*1024;n||n===0?this.highWaterMark=n:r&&(i||i===0)?this.highWaterMark=i:this.highWaterMark=s,this.highWaterMark=Math.floor(this.highWaterMark),this.buffer=new Vce,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(Mc||(Mc=af().StringDecoder),this.decoder=new Mc(e.encoding),this.encoding=e.encoding)}function er(e){if(ld=ld||Cf(),!(this instanceof er))return new er(e);this._readableState=new SL(e,this),this.readable=!0,e&&(typeof e.read=="function"&&(this._read=e.read),typeof e.destroy=="function"&&(this._destroy=e.destroy)),Jw.call(this)}Object.defineProperty(er.prototype,"destroyed",{get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){this._readableState&&(this._readableState.destroyed=e)}});er.prototype.destroy=wL.destroy;er.prototype._undestroy=wL.undestroy;er.prototype._destroy=function(e,t){this.push(null),t(e)};er.prototype.push=function(e,t){var r=this._readableState,n;return r.objectMode?n=!0:typeof e=="string"&&(t=t||r.defaultEncoding,t!==r.encoding&&(e=hd.from(e,t),t=""),n=!0),_L(this,e,t,!1,n)};er.prototype.unshift=function(e){return _L(this,e,null,!0,!1)};function _L(e,t,r,n,i){var s=e._readableState;if(t===null)s.reading=!1,Xce(e,s);else{var o;i||(o=jce(s,t)),o?e.emit("error",o):s.objectMode||t&&t.length>0?(typeof t!="string"&&!s.objectMode&&Object.getPrototypeOf(t)!==hd.prototype&&(t=Yce(t)),n?s.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):Ww(e,s,t,!0):s.ended?e.emit("error",new Error("stream.push() after EOF")):(s.reading=!1,s.decoder&&!r?(t=s.decoder.write(t),s.objectMode||t.length!==0?Ww(e,s,t,!1):vL(e,s)):Ww(e,s,t,!1))):n||(s.reading=!1)}return zce(s)}function Ww(e,t,r,n){t.flowing&&t.length===0&&!t.sync?(e.emit("data",r),e.read(0)):(t.length+=t.objectMode?1:r.length,n?t.buffer.unshift(r):t.buffer.push(r),t.needReadable&&KE(e)),vL(e,t)}function jce(e,t){var r;return!Wce(t)&&typeof t!="string"&&t!==void 0&&!e.objectMode&&(r=new TypeError("Invalid non-string/buffer chunk")),r}function zce(e){return!e.ended&&(e.needReadable||e.length=BL?e=BL:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function IL(e,t){return e<=0||t.length===0&&t.ended?0:t.objectMode?1:e!==e?t.flowing&&t.length?t.buffer.head.data.length:t.length:(e>t.highWaterMark&&(t.highWaterMark=Kce(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}er.prototype.read=function(e){_t("read",e),e=parseInt(e,10);var t=this._readableState,r=e;if(e!==0&&(t.emittedReadable=!1),e===0&&t.needReadable&&(t.length>=t.highWaterMark||t.ended))return _t("read: emitReadable",t.length,t.ended),t.length===0&&t.ended?Vw(this):KE(this),null;if(e=IL(e,t),e===0&&t.ended)return t.length===0&&Vw(this),null;var n=t.needReadable;_t("need readable",n),(t.length===0||t.length-e0?i=RL(e,t):i=null,i===null?(t.needReadable=!0,e=0):t.length-=e,t.length===0&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&Vw(this)),i!==null&&this.emit("data",i),i};function Xce(e,t){if(!t.ended){if(t.decoder){var r=t.decoder.end();r&&r.length&&(t.buffer.push(r),t.length+=t.objectMode?1:r.length)}t.ended=!0,KE(e)}}function KE(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(_t("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?Fc.nextTick(bL,e):bL(e))}function bL(e){_t("emit readable"),e.emit("readable"),jw(e)}function vL(e,t){t.readingMore||(t.readingMore=!0,Fc.nextTick(Zce,e,t))}function Zce(e,t){for(var r=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length1&&DL(n.pipes,e)!==-1)&&!f&&(_t("false write response, pause",n.awaitDrain),n.awaitDrain++,p=!0),r.pause())}function S(U){_t("onerror",U),P(),e.removeListener("error",S),CL(e,"error")===0&&e.emit("error",U)}Jce(e,"error",S);function _(){e.removeListener("finish",N),P()}e.once("close",_);function N(){_t("onfinish"),e.removeListener("close",_),P()}e.once("finish",N);function P(){_t("unpipe"),r.unpipe(e)}return e.emit("pipe",r),n.flowing||(_t("pipe resume"),r.resume()),e};function $ce(e){return function(){var t=e._readableState;_t("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,t.awaitDrain===0&&CL(e,"data")&&(t.flowing=!0,jw(e))}}er.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(t.pipesCount===0)return this;if(t.pipesCount===1)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r),this);if(!e){var n=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var s=0;s=t.length?(t.decoder?r=t.buffer.join(""):t.buffer.length===1?r=t.buffer.head.data:r=t.buffer.concat(t.length),t.buffer.clear()):r=nle(e,t.buffer,t.decoder),r}function nle(e,t,r){var n;return es.length?s.length:e;if(o===s.length?i+=s:i+=s.slice(0,e),e-=o,e===0){o===s.length?(++n,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=s.slice(o));break}++n}return t.length-=n,i}function sle(e,t){var r=hd.allocUnsafe(e),n=t.head,i=1;for(n.data.copy(r),e-=n.data.length;n=n.next;){var s=n.data,o=e>s.length?s.length:e;if(s.copy(r,r.length-e,0,o),e-=o,e===0){o===s.length?(++i,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=s.slice(o));break}++i}return t.length-=i,r}function Vw(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,Fc.nextTick(ole,t,e))}function ole(e,t){!e.endEmitted&&e.length===0&&(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function DL(e,t){for(var r=0,n=e.length;r{"use strict";FL.exports=$o;var XE=Cf(),ML=Object.create(Tc());ML.inherits=ze();ML.inherits($o,XE);function ale(e,t){var r=this._transformState;r.transforming=!1;var n=r.writecb;if(!n)return this.emit("error",new Error("write callback called multiple times"));r.writechunk=null,r.writecb=null,t!=null&&this.push(t),n(e);var i=this._readableState;i.reading=!1,(i.needReadable||i.length{"use strict";UL.exports=dd;var kL=zw(),xL=Object.create(Tc());xL.inherits=ze();xL.inherits(dd,kL);function dd(e){if(!(this instanceof dd))return new dd(e);kL.call(this,e)}dd.prototype._transform=function(e,t,r){r(null,e)}});var Kw=x((io,PL)=>{io=PL.exports=qw();io.Stream=io;io.Readable=io;io.Writable=Pw();io.Duplex=Cf();io.Transform=zw();io.PassThrough=LL()});var Xw=x((BNe,HL)=>{"use strict";var fle=at().Buffer,ule=$3(),OL=Kw().Transform,cle=ze();function aA(e){OL.call(this),this._block=fle.allocUnsafe(e),this._blockSize=e,this._blockOffset=0,this._length=[0,0,0,0],this._finalized=!1}cle(aA,OL);aA.prototype._transform=function(e,t,r){var n=null;try{this.update(e,t)}catch(i){n=i}r(n)};aA.prototype._flush=function(e){var t=null;try{this.push(this.digest())}catch(r){t=r}e(t)};aA.prototype.update=function(e,t){if(this._finalized)throw new Error("Digest already called");for(var r=ule(e,t),n=this._block,i=0;this._blockOffset+r.length-i>=this._blockSize;){for(var s=this._blockOffset;s0;++o)this._length[o]+=a,a=this._length[o]/4294967296|0,a>0&&(this._length[o]-=4294967296*a);return this};aA.prototype._update=function(){throw new Error("_update is not implemented")};aA.prototype.digest=function(e){if(this._finalized)throw new Error("Digest already called");this._finalized=!0;var t=this._digest();e!==void 0&&(t=t.toString(e)),this._block.fill(0),this._blockOffset=0;for(var r=0;r<4;++r)this._length[r]=0;return t};aA.prototype._digest=function(){throw new Error("_digest is not implemented")};HL.exports=aA});var ey=x((INe,GL)=>{"use strict";var lle=ze(),qL=Xw(),hle=at().Buffer,dle=new Array(16);function ZE(){qL.call(this,64),this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878}lle(ZE,qL);ZE.prototype._update=function(){for(var e=dle,t=0;t<16;++t)e[t]=this._block.readInt32LE(t*4);var r=this._a,n=this._b,i=this._c,s=this._d;r=nn(r,n,i,s,e[0],3614090360,7),s=nn(s,r,n,i,e[1],3905402710,12),i=nn(i,s,r,n,e[2],606105819,17),n=nn(n,i,s,r,e[3],3250441966,22),r=nn(r,n,i,s,e[4],4118548399,7),s=nn(s,r,n,i,e[5],1200080426,12),i=nn(i,s,r,n,e[6],2821735955,17),n=nn(n,i,s,r,e[7],4249261313,22),r=nn(r,n,i,s,e[8],1770035416,7),s=nn(s,r,n,i,e[9],2336552879,12),i=nn(i,s,r,n,e[10],4294925233,17),n=nn(n,i,s,r,e[11],2304563134,22),r=nn(r,n,i,s,e[12],1804603682,7),s=nn(s,r,n,i,e[13],4254626195,12),i=nn(i,s,r,n,e[14],2792965006,17),n=nn(n,i,s,r,e[15],1236535329,22),r=sn(r,n,i,s,e[1],4129170786,5),s=sn(s,r,n,i,e[6],3225465664,9),i=sn(i,s,r,n,e[11],643717713,14),n=sn(n,i,s,r,e[0],3921069994,20),r=sn(r,n,i,s,e[5],3593408605,5),s=sn(s,r,n,i,e[10],38016083,9),i=sn(i,s,r,n,e[15],3634488961,14),n=sn(n,i,s,r,e[4],3889429448,20),r=sn(r,n,i,s,e[9],568446438,5),s=sn(s,r,n,i,e[14],3275163606,9),i=sn(i,s,r,n,e[3],4107603335,14),n=sn(n,i,s,r,e[8],1163531501,20),r=sn(r,n,i,s,e[13],2850285829,5),s=sn(s,r,n,i,e[2],4243563512,9),i=sn(i,s,r,n,e[7],1735328473,14),n=sn(n,i,s,r,e[12],2368359562,20),r=on(r,n,i,s,e[5],4294588738,4),s=on(s,r,n,i,e[8],2272392833,11),i=on(i,s,r,n,e[11],1839030562,16),n=on(n,i,s,r,e[14],4259657740,23),r=on(r,n,i,s,e[1],2763975236,4),s=on(s,r,n,i,e[4],1272893353,11),i=on(i,s,r,n,e[7],4139469664,16),n=on(n,i,s,r,e[10],3200236656,23),r=on(r,n,i,s,e[13],681279174,4),s=on(s,r,n,i,e[0],3936430074,11),i=on(i,s,r,n,e[3],3572445317,16),n=on(n,i,s,r,e[6],76029189,23),r=on(r,n,i,s,e[9],3654602809,4),s=on(s,r,n,i,e[12],3873151461,11),i=on(i,s,r,n,e[15],530742520,16),n=on(n,i,s,r,e[2],3299628645,23),r=an(r,n,i,s,e[0],4096336452,6),s=an(s,r,n,i,e[7],1126891415,10),i=an(i,s,r,n,e[14],2878612391,15),n=an(n,i,s,r,e[5],4237533241,21),r=an(r,n,i,s,e[12],1700485571,6),s=an(s,r,n,i,e[3],2399980690,10),i=an(i,s,r,n,e[10],4293915773,15),n=an(n,i,s,r,e[1],2240044497,21),r=an(r,n,i,s,e[8],1873313359,6),s=an(s,r,n,i,e[15],4264355552,10),i=an(i,s,r,n,e[6],2734768916,15),n=an(n,i,s,r,e[13],1309151649,21),r=an(r,n,i,s,e[4],4149444226,6),s=an(s,r,n,i,e[11],3174756917,10),i=an(i,s,r,n,e[2],718787259,15),n=an(n,i,s,r,e[9],3951481745,21),this._a=this._a+r|0,this._b=this._b+n|0,this._c=this._c+i|0,this._d=this._d+s|0};ZE.prototype._digest=function(){this._block[this._blockOffset++]=128,this._blockOffset>56&&(this._block.fill(0,this._blockOffset,64),this._update(),this._blockOffset=0),this._block.fill(0,this._blockOffset,56),this._block.writeUInt32LE(this._length[0],56),this._block.writeUInt32LE(this._length[1],60),this._update();var e=hle.allocUnsafe(16);return e.writeInt32LE(this._a,0),e.writeInt32LE(this._b,4),e.writeInt32LE(this._c,8),e.writeInt32LE(this._d,12),e};function $E(e,t){return e<>>32-t}function nn(e,t,r,n,i,s,o){return $E(e+(t&r|~t&n)+i+s|0,o)+t|0}function sn(e,t,r,n,i,s,o){return $E(e+(t&n|r&~n)+i+s|0,o)+t|0}function on(e,t,r,n,i,s,o){return $E(e+(t^r^n)+i+s|0,o)+t|0}function an(e,t,r,n,i,s,o){return $E(e+(r^(t|~n))+i+s|0,o)+t|0}GL.exports=ZE});var ry=x((bNe,KL)=>{"use strict";var Zw=Gr().Buffer,gle=ze(),zL=Xw(),ple=new Array(16),gd=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13],pd=[5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11],Ed=[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6],yd=[8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11],md=[0,1518500249,1859775393,2400959708,2840853838],Bd=[1352829926,1548603684,1836072691,2053994217,0];function Qf(e,t){return e<>>32-t}function YL(e,t,r,n,i,s,o,a){return Qf(e+(t^r^n)+s+o|0,a)+i|0}function WL(e,t,r,n,i,s,o,a){return Qf(e+(t&r|~t&n)+s+o|0,a)+i|0}function VL(e,t,r,n,i,s,o,a){return Qf(e+((t|~r)^n)+s+o|0,a)+i|0}function JL(e,t,r,n,i,s,o,a){return Qf(e+(t&n|r&~n)+s+o|0,a)+i|0}function jL(e,t,r,n,i,s,o,a){return Qf(e+(t^(r|~n))+s+o|0,a)+i|0}function ty(){zL.call(this,64),this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520}gle(ty,zL);ty.prototype._update=function(){for(var e=ple,t=0;t<16;++t)e[t]=this._block.readInt32LE(t*4);for(var r=this._a|0,n=this._b|0,i=this._c|0,s=this._d|0,o=this._e|0,a=this._a|0,A=this._b|0,f=this._c|0,l=this._d|0,p=this._e|0,B=0;B<80;B+=1){var S,_;B<16?(S=YL(r,n,i,s,o,e[gd[B]],md[0],Ed[B]),_=jL(a,A,f,l,p,e[pd[B]],Bd[0],yd[B])):B<32?(S=WL(r,n,i,s,o,e[gd[B]],md[1],Ed[B]),_=JL(a,A,f,l,p,e[pd[B]],Bd[1],yd[B])):B<48?(S=VL(r,n,i,s,o,e[gd[B]],md[2],Ed[B]),_=VL(a,A,f,l,p,e[pd[B]],Bd[2],yd[B])):B<64?(S=JL(r,n,i,s,o,e[gd[B]],md[3],Ed[B]),_=WL(a,A,f,l,p,e[pd[B]],Bd[3],yd[B])):(S=jL(r,n,i,s,o,e[gd[B]],md[4],Ed[B]),_=YL(a,A,f,l,p,e[pd[B]],Bd[4],yd[B])),r=o,o=s,s=Qf(i,10),i=n,n=S,a=p,p=l,l=Qf(f,10),f=A,A=_}var N=this._b+i+l|0;this._b=this._c+s+p|0,this._c=this._d+o+a|0,this._d=this._e+r+A|0,this._e=this._a+n+f|0,this._a=N};ty.prototype._digest=function(){this._block[this._blockOffset]=128,this._blockOffset+=1,this._blockOffset>56&&(this._block.fill(0,this._blockOffset,64),this._update(),this._blockOffset=0),this._block.fill(0,this._blockOffset,56),this._block.writeUInt32LE(this._length[0],56),this._block.writeUInt32LE(this._length[1],60),this._update();var e=Zw.alloc?Zw.alloc(20):new Zw(20);return e.writeInt32LE(this._a,0),e.writeInt32LE(this._b,4),e.writeInt32LE(this._c,8),e.writeInt32LE(this._d,12),e.writeInt32LE(this._e,16),e};KL.exports=ty});var wf=x((CNe,XL)=>{"use strict";var Ele=at().Buffer,yle=ad();function ny(e,t){this._block=Ele.alloc(e),this._finalSize=t,this._blockSize=e,this._len=0}ny.prototype.update=function(e,t){e=yle(e,t||"utf8");for(var r=this._block,n=this._blockSize,i=e.length,s=this._len,o=0;o=this._finalSize&&(this._update(this._block),this._block.fill(0));var r=this._len*8;if(r<=4294967295)this._block.writeUInt32BE(r,this._blockSize-4);else{var n=(r&4294967295)>>>0,i=(r-n)/4294967296;this._block.writeUInt32BE(i,this._blockSize-8),this._block.writeUInt32BE(n,this._blockSize-4)}this._update(this._block);var s=this._hash();return e?s.toString(e):s};ny.prototype._update=function(){throw new Error("_update must be implemented by subclass")};XL.exports=ny});var e8=x((QNe,$L)=>{"use strict";var mle=ze(),ZL=wf(),Ble=at().Buffer,Ile=[1518500249,1859775393,-1894007588,-899497514],ble=new Array(80);function Id(){this.init(),this._w=ble,ZL.call(this,64,56)}mle(Id,ZL);Id.prototype.init=function(){return this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520,this};function Cle(e){return e<<5|e>>>27}function Qle(e){return e<<30|e>>>2}function wle(e,t,r,n){return e===0?t&r|~t&n:e===2?t&r|t&n|r&n:t^r^n}Id.prototype._update=function(e){for(var t=this._w,r=this._a|0,n=this._b|0,i=this._c|0,s=this._d|0,o=this._e|0,a=0;a<16;++a)t[a]=e.readInt32BE(a*4);for(;a<80;++a)t[a]=t[a-3]^t[a-8]^t[a-14]^t[a-16];for(var A=0;A<80;++A){var f=~~(A/20),l=Cle(r)+wle(f,n,i,s)+o+t[A]+Ile[f]|0;o=s,s=i,i=Qle(n),n=r,r=l}this._a=r+this._a|0,this._b=n+this._b|0,this._c=i+this._c|0,this._d=s+this._d|0,this._e=o+this._e|0};Id.prototype._hash=function(){var e=Ble.allocUnsafe(20);return e.writeInt32BE(this._a|0,0),e.writeInt32BE(this._b|0,4),e.writeInt32BE(this._c|0,8),e.writeInt32BE(this._d|0,12),e.writeInt32BE(this._e|0,16),e};$L.exports=Id});var n8=x((wNe,r8)=>{"use strict";var Sle=ze(),t8=wf(),_le=at().Buffer,vle=[1518500249,1859775393,-1894007588,-899497514],Rle=new Array(80);function bd(){this.init(),this._w=Rle,t8.call(this,64,56)}Sle(bd,t8);bd.prototype.init=function(){return this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520,this};function Dle(e){return e<<1|e>>>31}function Tle(e){return e<<5|e>>>27}function Nle(e){return e<<30|e>>>2}function Mle(e,t,r,n){return e===0?t&r|~t&n:e===2?t&r|t&n|r&n:t^r^n}bd.prototype._update=function(e){for(var t=this._w,r=this._a|0,n=this._b|0,i=this._c|0,s=this._d|0,o=this._e|0,a=0;a<16;++a)t[a]=e.readInt32BE(a*4);for(;a<80;++a)t[a]=Dle(t[a-3]^t[a-8]^t[a-14]^t[a-16]);for(var A=0;A<80;++A){var f=~~(A/20),l=Tle(r)+Mle(f,n,i,s)+o+t[A]+vle[f]|0;o=s,s=i,i=Nle(n),n=r,r=l}this._a=r+this._a|0,this._b=n+this._b|0,this._c=i+this._c|0,this._d=s+this._d|0,this._e=o+this._e|0};bd.prototype._hash=function(){var e=_le.allocUnsafe(20);return e.writeInt32BE(this._a|0,0),e.writeInt32BE(this._b|0,4),e.writeInt32BE(this._c|0,8),e.writeInt32BE(this._d|0,12),e.writeInt32BE(this._e|0,16),e};r8.exports=bd});var $w=x((SNe,s8)=>{"use strict";var Fle=ze(),i8=wf(),kle=at().Buffer,xle=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],Ule=new Array(64);function Cd(){this.init(),this._w=Ule,i8.call(this,64,56)}Fle(Cd,i8);Cd.prototype.init=function(){return this._a=1779033703,this._b=3144134277,this._c=1013904242,this._d=2773480762,this._e=1359893119,this._f=2600822924,this._g=528734635,this._h=1541459225,this};function Lle(e,t,r){return r^e&(t^r)}function Ple(e,t,r){return e&t|r&(e|t)}function Ole(e){return(e>>>2|e<<30)^(e>>>13|e<<19)^(e>>>22|e<<10)}function Hle(e){return(e>>>6|e<<26)^(e>>>11|e<<21)^(e>>>25|e<<7)}function qle(e){return(e>>>7|e<<25)^(e>>>18|e<<14)^e>>>3}function Gle(e){return(e>>>17|e<<15)^(e>>>19|e<<13)^e>>>10}Cd.prototype._update=function(e){for(var t=this._w,r=this._a|0,n=this._b|0,i=this._c|0,s=this._d|0,o=this._e|0,a=this._f|0,A=this._g|0,f=this._h|0,l=0;l<16;++l)t[l]=e.readInt32BE(l*4);for(;l<64;++l)t[l]=Gle(t[l-2])+t[l-7]+qle(t[l-15])+t[l-16]|0;for(var p=0;p<64;++p){var B=f+Hle(o)+Lle(o,a,A)+xle[p]+t[p]|0,S=Ole(r)+Ple(r,n,i)|0;f=A,A=a,a=o,o=s+B|0,s=i,i=n,n=r,r=B+S|0}this._a=r+this._a|0,this._b=n+this._b|0,this._c=i+this._c|0,this._d=s+this._d|0,this._e=o+this._e|0,this._f=a+this._f|0,this._g=A+this._g|0,this._h=f+this._h|0};Cd.prototype._hash=function(){var e=kle.allocUnsafe(32);return e.writeInt32BE(this._a,0),e.writeInt32BE(this._b,4),e.writeInt32BE(this._c,8),e.writeInt32BE(this._d,12),e.writeInt32BE(this._e,16),e.writeInt32BE(this._f,20),e.writeInt32BE(this._g,24),e.writeInt32BE(this._h,28),e};s8.exports=Cd});var a8=x((_Ne,o8)=>{"use strict";var Yle=ze(),Wle=$w(),Vle=wf(),Jle=at().Buffer,jle=new Array(64);function iy(){this.init(),this._w=jle,Vle.call(this,64,56)}Yle(iy,Wle);iy.prototype.init=function(){return this._a=3238371032,this._b=914150663,this._c=812702999,this._d=4144912697,this._e=4290775857,this._f=1750603025,this._g=1694076839,this._h=3204075428,this};iy.prototype._hash=function(){var e=Jle.allocUnsafe(28);return e.writeInt32BE(this._a,0),e.writeInt32BE(this._b,4),e.writeInt32BE(this._c,8),e.writeInt32BE(this._d,12),e.writeInt32BE(this._e,16),e.writeInt32BE(this._f,20),e.writeInt32BE(this._g,24),e};o8.exports=iy});var eS=x((vNe,d8)=>{"use strict";var zle=ze(),h8=wf(),Kle=at().Buffer,A8=[1116352408,3609767458,1899447441,602891725,3049323471,3964484399,3921009573,2173295548,961987163,4081628472,1508970993,3053834265,2453635748,2937671579,2870763221,3664609560,3624381080,2734883394,310598401,1164996542,607225278,1323610764,1426881987,3590304994,1925078388,4068182383,2162078206,991336113,2614888103,633803317,3248222580,3479774868,3835390401,2666613458,4022224774,944711139,264347078,2341262773,604807628,2007800933,770255983,1495990901,1249150122,1856431235,1555081692,3175218132,1996064986,2198950837,2554220882,3999719339,2821834349,766784016,2952996808,2566594879,3210313671,3203337956,3336571891,1034457026,3584528711,2466948901,113926993,3758326383,338241895,168717936,666307205,1188179964,773529912,1546045734,1294757372,1522805485,1396182291,2643833823,1695183700,2343527390,1986661051,1014477480,2177026350,1206759142,2456956037,344077627,2730485921,1290863460,2820302411,3158454273,3259730800,3505952657,3345764771,106217008,3516065817,3606008344,3600352804,1432725776,4094571909,1467031594,275423344,851169720,430227734,3100823752,506948616,1363258195,659060556,3750685593,883997877,3785050280,958139571,3318307427,1322822218,3812723403,1537002063,2003034995,1747873779,3602036899,1955562222,1575990012,2024104815,1125592928,2227730452,2716904306,2361852424,442776044,2428436474,593698344,2756734187,3733110249,3204031479,2999351573,3329325298,3815920427,3391569614,3928383900,3515267271,566280711,3940187606,3454069534,4118630271,4000239992,116418474,1914138554,174292421,2731055270,289380356,3203993006,460393269,320620315,685471733,587496836,852142971,1086792851,1017036298,365543100,1126000580,2618297676,1288033470,3409855158,1501505948,4234509866,1607167915,987167468,1816402316,1246189591],Xle=new Array(160);function Qd(){this.init(),this._w=Xle,h8.call(this,128,112)}zle(Qd,h8);Qd.prototype.init=function(){return this._ah=1779033703,this._bh=3144134277,this._ch=1013904242,this._dh=2773480762,this._eh=1359893119,this._fh=2600822924,this._gh=528734635,this._hh=1541459225,this._al=4089235720,this._bl=2227873595,this._cl=4271175723,this._dl=1595750129,this._el=2917565137,this._fl=725511199,this._gl=4215389547,this._hl=327033209,this};function f8(e,t,r){return r^e&(t^r)}function u8(e,t,r){return e&t|r&(e|t)}function c8(e,t){return(e>>>28|t<<4)^(t>>>2|e<<30)^(t>>>7|e<<25)}function l8(e,t){return(e>>>14|t<<18)^(e>>>18|t<<14)^(t>>>9|e<<23)}function Zle(e,t){return(e>>>1|t<<31)^(e>>>8|t<<24)^e>>>7}function $le(e,t){return(e>>>1|t<<31)^(e>>>8|t<<24)^(e>>>7|t<<25)}function ehe(e,t){return(e>>>19|t<<13)^(t>>>29|e<<3)^e>>>6}function the(e,t){return(e>>>19|t<<13)^(t>>>29|e<<3)^(e>>>6|t<<26)}function Fr(e,t){return e>>>0>>0?1:0}Qd.prototype._update=function(e){for(var t=this._w,r=this._ah|0,n=this._bh|0,i=this._ch|0,s=this._dh|0,o=this._eh|0,a=this._fh|0,A=this._gh|0,f=this._hh|0,l=this._al|0,p=this._bl|0,B=this._cl|0,S=this._dl|0,_=this._el|0,N=this._fl|0,P=this._gl|0,U=this._hl|0,G=0;G<32;G+=2)t[G]=e.readInt32BE(G*4),t[G+1]=e.readInt32BE(G*4+4);for(;G<160;G+=2){var Y=t[G-30],Z=t[G-30+1],ee=Zle(Y,Z),j=$le(Z,Y);Y=t[G-4],Z=t[G-4+1];var se=ehe(Y,Z),ie=the(Z,Y),ce=t[G-14],H=t[G-14+1],E=t[G-32],v=t[G-32+1],b=j+H|0,c=ee+ce+Fr(b,j)|0;b=b+ie|0,c=c+se+Fr(b,ie)|0,b=b+v|0,c=c+E+Fr(b,v)|0,t[G]=c,t[G+1]=b}for(var g=0;g<160;g+=2){c=t[g],b=t[g+1];var w=u8(r,n,i),R=u8(l,p,B),C=c8(r,l),h=c8(l,r),D=l8(o,_),M=l8(_,o),I=A8[g],k=A8[g+1],ne=f8(o,a,A),Ae=f8(_,N,P),ue=U+M|0,pe=f+D+Fr(ue,U)|0;ue=ue+Ae|0,pe=pe+ne+Fr(ue,Ae)|0,ue=ue+k|0,pe=pe+I+Fr(ue,k)|0,ue=ue+b|0,pe=pe+c+Fr(ue,b)|0;var he=h+R|0,de=C+w+Fr(he,h)|0;f=A,U=P,A=a,P=N,a=o,N=_,_=S+ue|0,o=s+pe+Fr(_,S)|0,s=i,S=B,i=n,B=p,n=r,p=l,l=ue+he|0,r=pe+de+Fr(l,ue)|0}this._al=this._al+l|0,this._bl=this._bl+p|0,this._cl=this._cl+B|0,this._dl=this._dl+S|0,this._el=this._el+_|0,this._fl=this._fl+N|0,this._gl=this._gl+P|0,this._hl=this._hl+U|0,this._ah=this._ah+r+Fr(this._al,l)|0,this._bh=this._bh+n+Fr(this._bl,p)|0,this._ch=this._ch+i+Fr(this._cl,B)|0,this._dh=this._dh+s+Fr(this._dl,S)|0,this._eh=this._eh+o+Fr(this._el,_)|0,this._fh=this._fh+a+Fr(this._fl,N)|0,this._gh=this._gh+A+Fr(this._gl,P)|0,this._hh=this._hh+f+Fr(this._hl,U)|0};Qd.prototype._hash=function(){var e=Kle.allocUnsafe(64);function t(r,n,i){e.writeInt32BE(r,i),e.writeInt32BE(n,i+4)}return t(this._ah,this._al,0),t(this._bh,this._bl,8),t(this._ch,this._cl,16),t(this._dh,this._dl,24),t(this._eh,this._el,32),t(this._fh,this._fl,40),t(this._gh,this._gl,48),t(this._hh,this._hl,56),e};d8.exports=Qd});var p8=x((RNe,g8)=>{"use strict";var rhe=ze(),nhe=eS(),ihe=wf(),she=at().Buffer,ohe=new Array(160);function sy(){this.init(),this._w=ohe,ihe.call(this,128,112)}rhe(sy,nhe);sy.prototype.init=function(){return this._ah=3418070365,this._bh=1654270250,this._ch=2438529370,this._dh=355462360,this._eh=1731405415,this._fh=2394180231,this._gh=3675008525,this._hh=1203062813,this._al=3238371032,this._bl=914150663,this._cl=812702999,this._dl=4144912697,this._el=4290775857,this._fl=1750603025,this._gl=1694076839,this._hl=3204075428,this};sy.prototype._hash=function(){var e=she.allocUnsafe(48);function t(r,n,i){e.writeInt32BE(r,i),e.writeInt32BE(n,i+4)}return t(this._ah,this._al,0),t(this._bh,this._bl,8),t(this._ch,this._cl,16),t(this._dh,this._dl,24),t(this._eh,this._el,32),t(this._fh,this._fl,40),e};g8.exports=sy});var oy=x((DNe,ea)=>{"use strict";ea.exports=function(t){var r=t.toLowerCase(),n=ea.exports[r];if(!n)throw new Error(r+" is not supported (we accept pull requests)");return new n};ea.exports.sha=e8();ea.exports.sha1=n8();ea.exports.sha224=a8();ea.exports.sha256=$w();ea.exports.sha384=p8();ea.exports.sha512=eS()});var ta=x((TNe,y8)=>{"use strict";var ahe=at().Buffer,E8=(ts(),Gs(Yt)).Transform,Ahe=af().StringDecoder,fhe=ze(),uhe=ad();function os(e){E8.call(this),this.hashMode=typeof e=="string",this.hashMode?this[e]=this._finalOrDigest:this.final=this._finalOrDigest,this._final&&(this.__final=this._final,this._final=null),this._decoder=null,this._encoding=null}fhe(os,E8);os.prototype.update=function(e,t,r){var n=uhe(e,t),i=this._update(n);return this.hashMode?this:(r&&(i=this._toString(i,r)),i)};os.prototype.setAutoPadding=function(){};os.prototype.getAuthTag=function(){throw new Error("trying to get auth tag in unsupported state")};os.prototype.setAuthTag=function(){throw new Error("trying to set auth tag in unsupported state")};os.prototype.setAAD=function(){throw new Error("trying to set aad in unsupported state")};os.prototype._transform=function(e,t,r){var n;try{this.hashMode?this._update(e):this.push(this._update(e))}catch(i){n=i}finally{r(n)}};os.prototype._flush=function(e){var t;try{this.push(this.__final())}catch(r){t=r}e(t)};os.prototype._finalOrDigest=function(e){var t=this.__final()||ahe.alloc(0);return e&&(t=this._toString(t,e,!0)),t};os.prototype._toString=function(e,t,r){if(this._decoder||(this._decoder=new Ahe(t),this._encoding=t),this._encoding!==t)throw new Error("can\u2019t switch encodings");var n=this._decoder.write(e);return r&&(n+=this._decoder.end()),n};y8.exports=os});var kc=x((NNe,B8)=>{"use strict";var che=ze(),lhe=ey(),hhe=ry(),dhe=oy(),m8=ta();function ay(e){m8.call(this,"digest"),this._hash=e}che(ay,m8);ay.prototype._update=function(e){this._hash.update(e)};ay.prototype._final=function(){return this._hash.digest()};B8.exports=function(t){return t=t.toLowerCase(),t==="md5"?new lhe:t==="rmd160"||t==="ripemd160"?new hhe:new ay(dhe(t))}});var C8=x((MNe,b8)=>{"use strict";var ghe=ze(),Sf=at().Buffer,I8=ta(),phe=Sf.alloc(128),xc=64;function Ay(e,t){I8.call(this,"digest"),typeof t=="string"&&(t=Sf.from(t)),this._alg=e,this._key=t,t.length>xc?t=e(t):t.length{var Ehe=ey();Q8.exports=function(e){return new Ehe().update(e).digest()}});var iS=x((kNe,S8)=>{"use strict";var yhe=ze(),mhe=C8(),w8=ta(),wd=at().Buffer,Bhe=tS(),rS=ry(),nS=oy(),Ihe=wd.alloc(128);function Sd(e,t){w8.call(this,"digest"),typeof t=="string"&&(t=wd.from(t));var r=e==="sha512"||e==="sha384"?128:64;if(this._alg=e,this._key=t,t.length>r){var n=e==="rmd160"?new rS:nS(e);t=n.update(t).digest()}else t.length{bhe.exports={sha224WithRSAEncryption:{sign:"rsa",hash:"sha224",id:"302d300d06096086480165030402040500041c"},"RSA-SHA224":{sign:"ecdsa/rsa",hash:"sha224",id:"302d300d06096086480165030402040500041c"},sha256WithRSAEncryption:{sign:"rsa",hash:"sha256",id:"3031300d060960864801650304020105000420"},"RSA-SHA256":{sign:"ecdsa/rsa",hash:"sha256",id:"3031300d060960864801650304020105000420"},sha384WithRSAEncryption:{sign:"rsa",hash:"sha384",id:"3041300d060960864801650304020205000430"},"RSA-SHA384":{sign:"ecdsa/rsa",hash:"sha384",id:"3041300d060960864801650304020205000430"},sha512WithRSAEncryption:{sign:"rsa",hash:"sha512",id:"3051300d060960864801650304020305000440"},"RSA-SHA512":{sign:"ecdsa/rsa",hash:"sha512",id:"3051300d060960864801650304020305000440"},"RSA-SHA1":{sign:"rsa",hash:"sha1",id:"3021300906052b0e03021a05000414"},"ecdsa-with-SHA1":{sign:"ecdsa",hash:"sha1",id:""},sha256:{sign:"ecdsa",hash:"sha256",id:""},sha224:{sign:"ecdsa",hash:"sha224",id:""},sha384:{sign:"ecdsa",hash:"sha384",id:""},sha512:{sign:"ecdsa",hash:"sha512",id:""},"DSA-SHA":{sign:"dsa",hash:"sha1",id:""},"DSA-SHA1":{sign:"dsa",hash:"sha1",id:""},DSA:{sign:"dsa",hash:"sha1",id:""},"DSA-WITH-SHA224":{sign:"dsa",hash:"sha224",id:""},"DSA-SHA224":{sign:"dsa",hash:"sha224",id:""},"DSA-WITH-SHA256":{sign:"dsa",hash:"sha256",id:""},"DSA-SHA256":{sign:"dsa",hash:"sha256",id:""},"DSA-WITH-SHA384":{sign:"dsa",hash:"sha384",id:""},"DSA-SHA384":{sign:"dsa",hash:"sha384",id:""},"DSA-WITH-SHA512":{sign:"dsa",hash:"sha512",id:""},"DSA-SHA512":{sign:"dsa",hash:"sha512",id:""},"DSA-RIPEMD160":{sign:"dsa",hash:"rmd160",id:""},ripemd160WithRSA:{sign:"rsa",hash:"rmd160",id:"3021300906052b2403020105000414"},"RSA-RIPEMD160":{sign:"rsa",hash:"rmd160",id:"3021300906052b2403020105000414"},md5WithRSAEncryption:{sign:"rsa",hash:"md5",id:"3020300c06082a864886f70d020505000410"},"RSA-MD5":{sign:"rsa",hash:"md5",id:"3020300c06082a864886f70d020505000410"}}});var v8=x((UNe,_8)=>{"use strict";_8.exports=sS()});var oS=x((LNe,R8)=>{"use strict";var Che=isFinite,Qhe=Math.pow(2,30)-1;R8.exports=function(e,t){if(typeof e!="number")throw new TypeError("Iterations not a number");if(e<0||!Che(e))throw new TypeError("Bad iterations");if(typeof t!="number")throw new TypeError("Key length not a number");if(t<0||t>Qhe||t!==t)throw new TypeError("Bad key length")}});var aS=x((PNe,T8)=>{"use strict";var fy;globalThis.process&&globalThis.process.browser?fy="utf-8":globalThis.process&&globalThis.process.version?(D8=parseInt(process.version.split(".")[0].slice(1),10),fy=D8>=6?"utf-8":"binary"):fy="utf-8";var D8;T8.exports=fy});var AS=x((ONe,F8)=>{"use strict";var whe=at().Buffer,She=ad(),M8=typeof Uint8Array<"u",_he=M8&&typeof ArrayBuffer<"u",N8=_he&&ArrayBuffer.isView;F8.exports=function(e,t,r){if(typeof e=="string"||whe.isBuffer(e)||M8&&e instanceof Uint8Array||N8&&N8(e))return She(e,t);throw new TypeError(r+" must be a string, a Buffer, a Uint8Array, or a DataView")}});var fS=x((HNe,L8)=>{"use strict";var vhe=tS(),Rhe=ry(),Dhe=oy(),_f=at().Buffer,The=oS(),k8=aS(),x8=AS(),Nhe=_f.alloc(128),uy={__proto__:null,md5:16,sha1:20,sha224:28,sha256:32,sha384:48,sha512:64,"sha512-256":32,ripemd160:20,rmd160:20},Mhe={__proto__:null,"sha-1":"sha1","sha-224":"sha224","sha-256":"sha256","sha-384":"sha384","sha-512":"sha512","ripemd-160":"ripemd160"};function Fhe(e){return new Rhe().update(e).digest()}function khe(e){function t(r){return Dhe(e).update(r).digest()}return e==="rmd160"||e==="ripemd160"?Fhe:e==="md5"?vhe:t}function U8(e,t,r){var n=khe(e),i=e==="sha512"||e==="sha384"?128:64;t.length>i?t=n(t):t.length{"use strict";var q8=at().Buffer,Uhe=oS(),P8=aS(),O8=fS(),H8=AS(),cy,_d=globalThis.crypto&&globalThis.crypto.subtle,Lhe={sha:"SHA-1","sha-1":"SHA-1",sha1:"SHA-1",sha256:"SHA-256","sha-256":"SHA-256",sha384:"SHA-384","sha-384":"SHA-384","sha-512":"SHA-512",sha512:"SHA-512"},uS=[],vf;function cS(){return vf||(globalThis.process&&globalThis.process.nextTick?vf=globalThis.process.nextTick:globalThis.queueMicrotask?vf=globalThis.queueMicrotask:globalThis.setImmediate?vf=globalThis.setImmediate:vf=globalThis.setTimeout,vf)}function G8(e,t,r,n,i){return _d.importKey("raw",e,{name:"PBKDF2"},!1,["deriveBits"]).then(function(s){return _d.deriveBits({name:"PBKDF2",salt:t,iterations:r,hash:{name:i}},s,n<<3)}).then(function(s){return q8.from(s)})}function Phe(e){if(globalThis.process&&!globalThis.process.browser||!_d||!_d.importKey||!_d.deriveBits)return Promise.resolve(!1);if(uS[e]!==void 0)return uS[e];cy=cy||q8.alloc(8);var t=G8(cy,cy,10,128,e).then(function(){return!0},function(){return!1});return uS[e]=t,t}function Ohe(e,t){e.then(function(r){cS()(function(){t(null,r)})},function(r){cS()(function(){t(r)})})}Y8.exports=function(e,t,r,n,i,s){if(typeof i=="function"&&(s=i,i=void 0),Uhe(r,n),e=H8(e,P8,"Password"),t=H8(t,P8,"Salt"),typeof s!="function")throw new Error("No callback provided to pbkdf2");i=i||"sha1";var o=Lhe[i.toLowerCase()];if(!o||typeof globalThis.Promise!="function"){cS()(function(){var a;try{a=O8(e,t,r,n,i)}catch(A){s(A);return}s(null,a)});return}Ohe(Phe(o).then(function(a){return a?G8(e,t,r,n,o):O8(e,t,r,n,i)}),s)}});var hS=x(lS=>{"use strict";lS.pbkdf2=W8();lS.pbkdf2Sync=fS()});var dS=x(Ii=>{"use strict";Ii.readUInt32BE=function(t,r){var n=t[0+r]<<24|t[1+r]<<16|t[2+r]<<8|t[3+r];return n>>>0};Ii.writeUInt32BE=function(t,r,n){t[0+n]=r>>>24,t[1+n]=r>>>16&255,t[2+n]=r>>>8&255,t[3+n]=r&255};Ii.ip=function(t,r,n,i){for(var s=0,o=0,a=6;a>=0;a-=2){for(var A=0;A<=24;A+=8)s<<=1,s|=r>>>A+a&1;for(var A=0;A<=24;A+=8)s<<=1,s|=t>>>A+a&1}for(var a=6;a>=0;a-=2){for(var A=1;A<=25;A+=8)o<<=1,o|=r>>>A+a&1;for(var A=1;A<=25;A+=8)o<<=1,o|=t>>>A+a&1}n[i+0]=s>>>0,n[i+1]=o>>>0};Ii.rip=function(t,r,n,i){for(var s=0,o=0,a=0;a<4;a++)for(var A=24;A>=0;A-=8)s<<=1,s|=r>>>A+a&1,s<<=1,s|=t>>>A+a&1;for(var a=4;a<8;a++)for(var A=24;A>=0;A-=8)o<<=1,o|=r>>>A+a&1,o<<=1,o|=t>>>A+a&1;n[i+0]=s>>>0,n[i+1]=o>>>0};Ii.pc1=function(t,r,n,i){for(var s=0,o=0,a=7;a>=5;a--){for(var A=0;A<=24;A+=8)s<<=1,s|=r>>A+a&1;for(var A=0;A<=24;A+=8)s<<=1,s|=t>>A+a&1}for(var A=0;A<=24;A+=8)s<<=1,s|=r>>A+a&1;for(var a=1;a<=3;a++){for(var A=0;A<=24;A+=8)o<<=1,o|=r>>A+a&1;for(var A=0;A<=24;A+=8)o<<=1,o|=t>>A+a&1}for(var A=0;A<=24;A+=8)o<<=1,o|=t>>A+a&1;n[i+0]=s>>>0,n[i+1]=o>>>0};Ii.r28shl=function(t,r){return t<>>28-r};var ly=[14,11,17,4,27,23,25,0,13,22,7,18,5,9,16,24,2,20,12,21,1,8,15,26,15,4,25,19,9,1,26,16,5,11,23,8,12,7,17,0,22,3,10,14,6,20,27,24];Ii.pc2=function(t,r,n,i){for(var s=0,o=0,a=ly.length>>>1,A=0;A>>ly[A]&1;for(var A=a;A>>ly[A]&1;n[i+0]=s>>>0,n[i+1]=o>>>0};Ii.expand=function(t,r,n){var i=0,s=0;i=(t&1)<<5|t>>>27;for(var o=23;o>=15;o-=4)i<<=6,i|=t>>>o&63;for(var o=11;o>=3;o-=4)s|=t>>>o&63,s<<=6;s|=(t&31)<<1|t>>>31,r[n+0]=i>>>0,r[n+1]=s>>>0};var V8=[14,0,4,15,13,7,1,4,2,14,15,2,11,13,8,1,3,10,10,6,6,12,12,11,5,9,9,5,0,3,7,8,4,15,1,12,14,8,8,2,13,4,6,9,2,1,11,7,15,5,12,11,9,3,7,14,3,10,10,0,5,6,0,13,15,3,1,13,8,4,14,7,6,15,11,2,3,8,4,14,9,12,7,0,2,1,13,10,12,6,0,9,5,11,10,5,0,13,14,8,7,10,11,1,10,3,4,15,13,4,1,2,5,11,8,6,12,7,6,12,9,0,3,5,2,14,15,9,10,13,0,7,9,0,14,9,6,3,3,4,15,6,5,10,1,2,13,8,12,5,7,14,11,12,4,11,2,15,8,1,13,1,6,10,4,13,9,0,8,6,15,9,3,8,0,7,11,4,1,15,2,14,12,3,5,11,10,5,14,2,7,12,7,13,13,8,14,11,3,5,0,6,6,15,9,0,10,3,1,4,2,7,8,2,5,12,11,1,12,10,4,14,15,9,10,3,6,15,9,0,0,6,12,10,11,1,7,13,13,8,15,9,1,4,3,5,14,11,5,12,2,7,8,2,4,14,2,14,12,11,4,2,1,12,7,4,10,7,11,13,6,1,8,5,5,0,3,15,15,10,13,3,0,9,14,8,9,6,4,11,2,8,1,12,11,7,10,1,13,14,7,2,8,13,15,6,9,15,12,0,5,9,6,10,3,4,0,5,14,3,12,10,1,15,10,4,15,2,9,7,2,12,6,9,8,5,0,6,13,1,3,13,4,14,14,0,7,11,5,3,11,8,9,4,14,3,15,2,5,12,2,9,8,5,12,15,3,10,7,11,0,14,4,1,10,7,1,6,13,0,11,8,6,13,4,13,11,0,2,11,14,7,15,4,0,9,8,1,13,10,3,14,12,3,9,5,7,12,5,2,10,15,6,8,1,6,1,6,4,11,11,13,13,8,12,1,3,4,7,10,14,7,10,9,15,5,6,0,8,15,0,14,5,2,9,3,2,12,13,1,2,15,8,13,4,8,6,10,15,3,11,7,1,4,10,12,9,5,3,6,14,11,5,0,0,14,12,9,7,2,7,2,11,1,4,14,1,7,9,4,12,10,14,8,2,13,0,15,6,12,10,9,13,0,15,3,3,5,5,6,8,11];Ii.substitute=function(t,r){for(var n=0,i=0;i<4;i++){var s=t>>>18-i*6&63,o=V8[i*64+s];n<<=4,n|=o}for(var i=0;i<4;i++){var s=r>>>18-i*6&63,o=V8[256+i*64+s];n<<=4,n|=o}return n>>>0};var J8=[16,25,12,11,3,20,4,15,31,17,9,6,27,14,1,22,30,24,8,18,0,5,29,23,13,19,2,26,10,21,28,7];Ii.permute=function(t){for(var r=0,n=0;n>>J8[n]&1;return r>>>0};Ii.padSplit=function(t,r,n){for(var i=t.toString(2);i.length{z8.exports=j8;function j8(e,t){if(!e)throw new Error(t||"Assertion failed")}j8.equal=function(t,r,n){if(t!=r)throw new Error(n||"Assertion failed: "+t+" != "+r)}});var hy=x((VNe,K8)=>{"use strict";var Hhe=zn();function bi(e){this.options=e,this.type=this.options.type,this.blockSize=8,this._init(),this.buffer=new Array(this.blockSize),this.bufferOff=0,this.padding=e.padding!==!1}K8.exports=bi;bi.prototype._init=function(){};bi.prototype.update=function(t){return t.length===0?[]:this.type==="decrypt"?this._updateDecrypt(t):this._updateEncrypt(t)};bi.prototype._buffer=function(t,r){for(var n=Math.min(this.buffer.length-this.bufferOff,t.length-r),i=0;i0;i--)r+=this._buffer(t,r),n+=this._flushBuffer(s,n);return r+=this._buffer(t,r),s};bi.prototype.final=function(t){var r;t&&(r=this.update(t));var n;return this.type==="encrypt"?n=this._finalEncrypt():n=this._finalDecrypt(),r?r.concat(n):n};bi.prototype._pad=function(t,r){if(r===0)return!1;for(;r{"use strict";var X8=zn(),qhe=ze(),vr=dS(),Z8=hy();function Ghe(){this.tmp=new Array(2),this.keys=null}function so(e){Z8.call(this,e);var t=new Ghe;this._desState=t,this.deriveKeys(t,e.key)}qhe(so,Z8);$8.exports=so;so.create=function(t){return new so(t)};var Yhe=[1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1];so.prototype.deriveKeys=function(t,r){t.keys=new Array(32),X8.equal(r.length,this.blockSize,"Invalid key length");var n=vr.readUInt32BE(r,0),i=vr.readUInt32BE(r,4);vr.pc1(n,i,t.tmp,0),n=t.tmp[0],i=t.tmp[1];for(var s=0;s>>1];n=vr.r28shl(n,o),i=vr.r28shl(i,o),vr.pc2(n,i,t.keys,s)}};so.prototype._update=function(t,r,n,i){var s=this._desState,o=vr.readUInt32BE(t,r),a=vr.readUInt32BE(t,r+4);vr.ip(o,a,s.tmp,0),o=s.tmp[0],a=s.tmp[1],this.type==="encrypt"?this._encrypt(s,o,a,s.tmp,0):this._decrypt(s,o,a,s.tmp,0),o=s.tmp[0],a=s.tmp[1],vr.writeUInt32BE(n,o,i),vr.writeUInt32BE(n,a,i+4)};so.prototype._pad=function(t,r){if(this.padding===!1)return!1;for(var n=t.length-r,i=r;i>>0,o=S}vr.rip(a,o,i,s)};so.prototype._decrypt=function(t,r,n,i,s){for(var o=n,a=r,A=t.keys.length-2;A>=0;A-=2){var f=t.keys[A],l=t.keys[A+1];vr.expand(o,t.tmp,0),f^=t.tmp[0],l^=t.tmp[1];var p=vr.substitute(f,l),B=vr.permute(p),S=o;o=(a^B)>>>0,a=S}vr.rip(o,a,i,s)}});var t5=x(e5=>{"use strict";var Whe=zn(),Vhe=ze(),dy={};function Jhe(e){Whe.equal(e.length,8,"Invalid IV length"),this.iv=new Array(8);for(var t=0;t{"use strict";var zhe=zn(),Khe=ze(),r5=hy(),AA=gS();function Xhe(e,t){zhe.equal(t.length,24,"Invalid key length");var r=t.slice(0,8),n=t.slice(8,16),i=t.slice(16,24);e==="encrypt"?this.ciphers=[AA.create({type:"encrypt",key:r}),AA.create({type:"decrypt",key:n}),AA.create({type:"encrypt",key:i})]:this.ciphers=[AA.create({type:"decrypt",key:i}),AA.create({type:"encrypt",key:n}),AA.create({type:"decrypt",key:r})]}function Rf(e){r5.call(this,e);var t=new Xhe(this.type,this.options.key);this._edeState=t}Khe(Rf,r5);n5.exports=Rf;Rf.create=function(t){return new Rf(t)};Rf.prototype._update=function(t,r,n,i){var s=this._edeState;s.ciphers[0]._update(t,r,n,i),s.ciphers[1]._update(n,i,n,i),s.ciphers[2]._update(n,i,n,i)};Rf.prototype._pad=AA.prototype._pad;Rf.prototype._unpad=AA.prototype._unpad});var s5=x(Uc=>{"use strict";Uc.utils=dS();Uc.Cipher=hy();Uc.DES=gS();Uc.CBC=t5();Uc.EDE=i5()});var A5=x((XNe,a5)=>{var o5=ta(),ra=s5(),Zhe=ze(),Df=at().Buffer,vd={"des-ede3-cbc":ra.CBC.instantiate(ra.EDE),"des-ede3":ra.EDE,"des-ede-cbc":ra.CBC.instantiate(ra.EDE),"des-ede":ra.EDE,"des-cbc":ra.CBC.instantiate(ra.DES),"des-ecb":ra.DES};vd.des=vd["des-cbc"];vd.des3=vd["des-ede3-cbc"];a5.exports=gy;Zhe(gy,o5);function gy(e){o5.call(this);var t=e.mode.toLowerCase(),r=vd[t],n;e.decrypt?n="decrypt":n="encrypt";var i=e.key;Df.isBuffer(i)||(i=Df.from(i)),(t==="des-ede"||t==="des-ede-cbc")&&(i=Df.concat([i,i.slice(0,8)]));var s=e.iv;Df.isBuffer(s)||(s=Df.from(s)),this._des=r.create({key:i,iv:s,type:n})}gy.prototype._update=function(e){return Df.from(this._des.update(e))};gy.prototype._final=function(){return Df.from(this._des.final())}});var f5=x(pS=>{pS.encrypt=function(e,t){return e._cipher.encryptBlock(t)};pS.decrypt=function(e,t){return e._cipher.decryptBlock(t)}});var Lc=x(($Ne,u5)=>{u5.exports=function(t,r){for(var n=Math.min(t.length,r.length),i=new Buffer(n),s=0;s{var c5=Lc();ES.encrypt=function(e,t){var r=c5(t,e._prev);return e._prev=e._cipher.encryptBlock(r),e._prev};ES.decrypt=function(e,t){var r=e._prev;e._prev=t;var n=e._cipher.decryptBlock(t);return c5(n,r)}});var g5=x(d5=>{var Rd=at().Buffer,$he=Lc();function h5(e,t,r){var n=t.length,i=$he(t,e._cache);return e._cache=e._cache.slice(n),e._prev=Rd.concat([e._prev,r?t:i]),i}d5.encrypt=function(e,t,r){for(var n=Rd.allocUnsafe(0),i;t.length;)if(e._cache.length===0&&(e._cache=e._cipher.encryptBlock(e._prev),e._prev=Rd.allocUnsafe(0)),e._cache.length<=t.length)i=e._cache.length,n=Rd.concat([n,h5(e,t.slice(0,i),r)]),t=t.slice(i);else{n=Rd.concat([n,h5(e,t,r)]);break}return n}});var E5=x(p5=>{var yS=at().Buffer;function ede(e,t,r){var n=e._cipher.encryptBlock(e._prev),i=n[0]^t;return e._prev=yS.concat([e._prev.slice(1),yS.from([r?t:i])]),i}p5.encrypt=function(e,t,r){for(var n=t.length,i=yS.allocUnsafe(n),s=-1;++s{var py=at().Buffer;function tde(e,t,r){for(var n,i=-1,s=8,o=0,a,A;++i>i%8,e._prev=rde(e._prev,r?a:A);return o}function rde(e,t){var r=e.length,n=-1,i=py.allocUnsafe(e.length);for(e=py.concat([e,py.from([t])]);++n>7;return i}y5.encrypt=function(e,t,r){for(var n=t.length,i=py.allocUnsafe(n),s=-1;++s{var nde=Lc();function ide(e){return e._prev=e._cipher.encryptBlock(e._prev),e._prev}B5.encrypt=function(e,t){for(;e._cache.length{function sde(e){for(var t=e.length,r;t--;)if(r=e.readUInt8(t),r===255)e.writeUInt8(0,t);else{r++,e.writeUInt8(r,t);break}}b5.exports=sde});var IS=x(Q5=>{var ode=Lc(),C5=at().Buffer,ade=mS();function Ade(e){var t=e._cipher.encryptBlockRaw(e._prev);return ade(e._prev),t}var BS=16;Q5.encrypt=function(e,t){var r=Math.ceil(t.length/BS),n=e._cache.length;e._cache=C5.concat([e._cache,C5.allocUnsafe(r*BS)]);for(var i=0;i{fde.exports={"aes-128-ecb":{cipher:"AES",key:128,iv:0,mode:"ECB",type:"block"},"aes-192-ecb":{cipher:"AES",key:192,iv:0,mode:"ECB",type:"block"},"aes-256-ecb":{cipher:"AES",key:256,iv:0,mode:"ECB",type:"block"},"aes-128-cbc":{cipher:"AES",key:128,iv:16,mode:"CBC",type:"block"},"aes-192-cbc":{cipher:"AES",key:192,iv:16,mode:"CBC",type:"block"},"aes-256-cbc":{cipher:"AES",key:256,iv:16,mode:"CBC",type:"block"},aes128:{cipher:"AES",key:128,iv:16,mode:"CBC",type:"block"},aes192:{cipher:"AES",key:192,iv:16,mode:"CBC",type:"block"},aes256:{cipher:"AES",key:256,iv:16,mode:"CBC",type:"block"},"aes-128-cfb":{cipher:"AES",key:128,iv:16,mode:"CFB",type:"stream"},"aes-192-cfb":{cipher:"AES",key:192,iv:16,mode:"CFB",type:"stream"},"aes-256-cfb":{cipher:"AES",key:256,iv:16,mode:"CFB",type:"stream"},"aes-128-cfb8":{cipher:"AES",key:128,iv:16,mode:"CFB8",type:"stream"},"aes-192-cfb8":{cipher:"AES",key:192,iv:16,mode:"CFB8",type:"stream"},"aes-256-cfb8":{cipher:"AES",key:256,iv:16,mode:"CFB8",type:"stream"},"aes-128-cfb1":{cipher:"AES",key:128,iv:16,mode:"CFB1",type:"stream"},"aes-192-cfb1":{cipher:"AES",key:192,iv:16,mode:"CFB1",type:"stream"},"aes-256-cfb1":{cipher:"AES",key:256,iv:16,mode:"CFB1",type:"stream"},"aes-128-ofb":{cipher:"AES",key:128,iv:16,mode:"OFB",type:"stream"},"aes-192-ofb":{cipher:"AES",key:192,iv:16,mode:"OFB",type:"stream"},"aes-256-ofb":{cipher:"AES",key:256,iv:16,mode:"OFB",type:"stream"},"aes-128-ctr":{cipher:"AES",key:128,iv:16,mode:"CTR",type:"stream"},"aes-192-ctr":{cipher:"AES",key:192,iv:16,mode:"CTR",type:"stream"},"aes-256-ctr":{cipher:"AES",key:256,iv:16,mode:"CTR",type:"stream"},"aes-128-gcm":{cipher:"AES",key:128,iv:12,mode:"GCM",type:"auth"},"aes-192-gcm":{cipher:"AES",key:192,iv:12,mode:"GCM",type:"auth"},"aes-256-gcm":{cipher:"AES",key:256,iv:12,mode:"GCM",type:"auth"}}});var yy=x((AMe,w5)=>{var ude={ECB:f5(),CBC:l5(),CFB:g5(),CFB8:E5(),CFB1:m5(),OFB:I5(),CTR:IS(),GCM:IS()},Ey=bS();for(CS in Ey)Ey[CS].module=ude[Ey[CS].mode];var CS;w5.exports=Ey});var Dd=x((fMe,_5)=>{var my=at().Buffer;function wS(e){my.isBuffer(e)||(e=my.from(e));for(var t=e.length/4|0,r=new Array(t),n=0;n>>24]^o[l>>>16&255]^a[p>>>8&255]^A[B&255]^t[U++],_=s[l>>>24]^o[p>>>16&255]^a[B>>>8&255]^A[f&255]^t[U++],N=s[p>>>24]^o[B>>>16&255]^a[f>>>8&255]^A[l&255]^t[U++],P=s[B>>>24]^o[f>>>16&255]^a[l>>>8&255]^A[p&255]^t[U++],f=S,l=_,p=N,B=P;return S=(n[f>>>24]<<24|n[l>>>16&255]<<16|n[p>>>8&255]<<8|n[B&255])^t[U++],_=(n[l>>>24]<<24|n[p>>>16&255]<<16|n[B>>>8&255]<<8|n[f&255])^t[U++],N=(n[p>>>24]<<24|n[B>>>16&255]<<16|n[f>>>8&255]<<8|n[l&255])^t[U++],P=(n[B>>>24]<<24|n[f>>>16&255]<<16|n[l>>>8&255]<<8|n[p&255])^t[U++],S=S>>>0,_=_>>>0,N=N>>>0,P=P>>>0,[S,_,N,P]}var cde=[0,1,2,4,8,16,32,64,128,27,54],Ir=(function(){for(var e=new Array(256),t=0;t<256;t++)t<128?e[t]=t<<1:e[t]=t<<1^283;for(var r=[],n=[],i=[[],[],[],[]],s=[[],[],[],[]],o=0,a=0,A=0;A<256;++A){var f=a^a<<1^a<<2^a<<3^a<<4;f=f>>>8^f&255^99,r[o]=f,n[f]=o;var l=e[o],p=e[l],B=e[p],S=e[f]*257^f*16843008;i[0][o]=S<<24|S>>>8,i[1][o]=S<<16|S>>>16,i[2][o]=S<<8|S>>>24,i[3][o]=S,S=B*16843009^p*65537^l*257^o*16843008,s[0][f]=S<<24|S>>>8,s[1][f]=S<<16|S>>>16,s[2][f]=S<<8|S>>>24,s[3][f]=S,o===0?o=a=1:(o=l^e[e[e[B^l]]],a^=e[e[a]])}return{SBOX:r,INV_SBOX:n,SUB_MIX:i,INV_SUB_MIX:s}})();function Ci(e){this._key=wS(e),this._reset()}Ci.blockSize=16;Ci.keySize=256/8;Ci.prototype.blockSize=Ci.blockSize;Ci.prototype.keySize=Ci.keySize;Ci.prototype._reset=function(){for(var e=this._key,t=e.length,r=t+6,n=(r+1)*4,i=[],s=0;s>>24,o=Ir.SBOX[o>>>24]<<24|Ir.SBOX[o>>>16&255]<<16|Ir.SBOX[o>>>8&255]<<8|Ir.SBOX[o&255],o^=cde[s/t|0]<<24):t>6&&s%t===4&&(o=Ir.SBOX[o>>>24]<<24|Ir.SBOX[o>>>16&255]<<16|Ir.SBOX[o>>>8&255]<<8|Ir.SBOX[o&255]),i[s]=i[s-t]^o}for(var a=[],A=0;A>>24]]^Ir.INV_SUB_MIX[1][Ir.SBOX[l>>>16&255]]^Ir.INV_SUB_MIX[2][Ir.SBOX[l>>>8&255]]^Ir.INV_SUB_MIX[3][Ir.SBOX[l&255]]}this._nRounds=r,this._keySchedule=i,this._invKeySchedule=a};Ci.prototype.encryptBlockRaw=function(e){return e=wS(e),S5(e,this._keySchedule,Ir.SUB_MIX,Ir.SBOX,this._nRounds)};Ci.prototype.encryptBlock=function(e){var t=this.encryptBlockRaw(e),r=my.allocUnsafe(16);return r.writeUInt32BE(t[0],0),r.writeUInt32BE(t[1],4),r.writeUInt32BE(t[2],8),r.writeUInt32BE(t[3],12),r};Ci.prototype.decryptBlock=function(e){e=wS(e);var t=e[1];e[1]=e[3],e[3]=t;var r=S5(e,this._invKeySchedule,Ir.INV_SUB_MIX,Ir.INV_SBOX,this._nRounds),n=my.allocUnsafe(16);return n.writeUInt32BE(r[0],0),n.writeUInt32BE(r[3],4),n.writeUInt32BE(r[2],8),n.writeUInt32BE(r[1],12),n};Ci.prototype.scrub=function(){QS(this._keySchedule),QS(this._invKeySchedule),QS(this._key)};_5.exports.AES=Ci});var D5=x((uMe,R5)=>{var Pc=at().Buffer,lde=Pc.alloc(16,0);function hde(e){return[e.readUInt32BE(0),e.readUInt32BE(4),e.readUInt32BE(8),e.readUInt32BE(12)]}function v5(e){var t=Pc.allocUnsafe(16);return t.writeUInt32BE(e[0]>>>0,0),t.writeUInt32BE(e[1]>>>0,4),t.writeUInt32BE(e[2]>>>0,8),t.writeUInt32BE(e[3]>>>0,12),t}function Td(e){this.h=e,this.state=Pc.alloc(16,0),this.cache=Pc.allocUnsafe(0)}Td.prototype.ghash=function(e){for(var t=-1;++t0;r--)e[r]=e[r]>>>1|(e[r-1]&1)<<31;e[0]=e[0]>>>1,i&&(e[0]=e[0]^225<<24)}this.state=v5(t)};Td.prototype.update=function(e){this.cache=Pc.concat([this.cache,e]);for(var t;this.cache.length>=16;)t=this.cache.slice(0,16),this.cache=this.cache.slice(16),this.ghash(t)};Td.prototype.final=function(e,t){return this.cache.length&&this.ghash(Pc.concat([this.cache,lde],16)),this.ghash(v5([0,e,0,t])),this.state};R5.exports=Td});var SS=x((cMe,M5)=>{var dde=Dd(),Mn=at().Buffer,T5=ta(),gde=ze(),N5=D5(),pde=Lc(),Ede=mS();function yde(e,t){var r=0;e.length!==t.length&&r++;for(var n=Math.min(e.length,t.length),i=0;i{var Bde=Dd(),_S=at().Buffer,F5=ta(),Ide=ze();function By(e,t,r,n){F5.call(this),this._cipher=new Bde.AES(t),this._prev=_S.from(r),this._cache=_S.allocUnsafe(0),this._secCache=_S.allocUnsafe(0),this._decrypt=n,this._mode=e}Ide(By,F5);By.prototype._update=function(e){return this._mode.encrypt(this,e,this._decrypt)};By.prototype._final=function(){this._cipher.scrub()};k5.exports=By});var Nd=x((hMe,x5)=>{var Nf=at().Buffer,bde=ey();function Cde(e,t,r,n){if(Nf.isBuffer(e)||(e=Nf.from(e,"binary")),t&&(Nf.isBuffer(t)||(t=Nf.from(t,"binary")),t.length!==8))throw new RangeError("salt should be Buffer with 8 byte length");for(var i=r/8,s=Nf.alloc(i),o=Nf.alloc(n||0),a=Nf.alloc(0);i>0||n>0;){var A=new bde;A.update(a),A.update(e),t&&A.update(t),a=A.digest();var f=0;if(i>0){var l=s.length-i;f=Math.min(i,a.length),a.copy(s,l,0,f),i-=f}if(f0){var p=o.length-n,B=Math.min(n,a.length-f);a.copy(o,p,f,f+B),n-=B}}return a.fill(0),{key:s,iv:o}}x5.exports=Cde});var O5=x(RS=>{var U5=yy(),Qde=SS(),na=at().Buffer,wde=vS(),L5=ta(),Sde=Dd(),_de=Nd(),vde=ze();function Md(e,t,r){L5.call(this),this._cache=new Iy,this._cipher=new Sde.AES(t),this._prev=na.from(r),this._mode=e,this._autopadding=!0}vde(Md,L5);Md.prototype._update=function(e){this._cache.add(e);for(var t,r,n=[];t=this._cache.get();)r=this._mode.encrypt(this,t),n.push(r);return na.concat(n)};var Rde=na.alloc(16,16);Md.prototype._final=function(){var e=this._cache.flush();if(this._autopadding)return e=this._mode.encrypt(this,e),this._cipher.scrub(),e;if(!e.equals(Rde))throw this._cipher.scrub(),new Error("data not multiple of block length")};Md.prototype.setAutoPadding=function(e){return this._autopadding=!!e,this};function Iy(){this.cache=na.allocUnsafe(0)}Iy.prototype.add=function(e){this.cache=na.concat([this.cache,e])};Iy.prototype.get=function(){if(this.cache.length>15){var e=this.cache.slice(0,16);return this.cache=this.cache.slice(16),e}return null};Iy.prototype.flush=function(){for(var e=16-this.cache.length,t=na.allocUnsafe(e),r=-1;++r{var Tde=SS(),Oc=at().Buffer,H5=yy(),Nde=vS(),q5=ta(),Mde=Dd(),Fde=Nd(),kde=ze();function Fd(e,t,r){q5.call(this),this._cache=new by,this._last=void 0,this._cipher=new Mde.AES(t),this._prev=Oc.from(r),this._mode=e,this._autopadding=!0}kde(Fd,q5);Fd.prototype._update=function(e){this._cache.add(e);for(var t,r,n=[];t=this._cache.get(this._autopadding);)r=this._mode.decrypt(this,t),n.push(r);return Oc.concat(n)};Fd.prototype._final=function(){var e=this._cache.flush();if(this._autopadding)return xde(this._mode.decrypt(this,e));if(e)throw new Error("data not multiple of block length")};Fd.prototype.setAutoPadding=function(e){return this._autopadding=!!e,this};function by(){this.cache=Oc.allocUnsafe(0)}by.prototype.add=function(e){this.cache=Oc.concat([this.cache,e])};by.prototype.get=function(e){var t;if(e){if(this.cache.length>16)return t=this.cache.slice(0,16),this.cache=this.cache.slice(16),t}else if(this.cache.length>=16)return t=this.cache.slice(0,16),this.cache=this.cache.slice(16),t;return null};by.prototype.flush=function(){if(this.cache.length)return this.cache};function xde(e){var t=e[15];if(t<1||t>16)throw new Error("unable to decrypt data");for(var r=-1;++r{var W5=O5(),V5=Y5(),Lde=bS();function Pde(){return Object.keys(Lde)}as.createCipher=as.Cipher=W5.createCipher;as.createCipheriv=as.Cipheriv=W5.createCipheriv;as.createDecipher=as.Decipher=V5.createDecipher;as.createDecipheriv=as.Decipheriv=V5.createDecipheriv;as.listCiphers=as.getCiphers=Pde});var J5=x(ia=>{ia["des-ecb"]={key:8,iv:0};ia["des-cbc"]=ia.des={key:8,iv:8};ia["des-ede3-cbc"]=ia.des3={key:24,iv:8};ia["des-ede3"]={key:24,iv:0};ia["des-ede-cbc"]={key:16,iv:8};ia["des-ede"]={key:16,iv:0}});var Z5=x(As=>{var j5=A5(),TS=Cy(),fA=yy(),sa=J5(),z5=Nd();function Ode(e,t){e=e.toLowerCase();var r,n;if(fA[e])r=fA[e].key,n=fA[e].iv;else if(sa[e])r=sa[e].key*8,n=sa[e].iv;else throw new TypeError("invalid suite type");var i=z5(t,!1,r,n);return K5(e,i.key,i.iv)}function Hde(e,t){e=e.toLowerCase();var r,n;if(fA[e])r=fA[e].key,n=fA[e].iv;else if(sa[e])r=sa[e].key*8,n=sa[e].iv;else throw new TypeError("invalid suite type");var i=z5(t,!1,r,n);return X5(e,i.key,i.iv)}function K5(e,t,r){if(e=e.toLowerCase(),fA[e])return TS.createCipheriv(e,t,r);if(sa[e])return new j5({key:t,iv:r,mode:e});throw new TypeError("invalid suite type")}function X5(e,t,r){if(e=e.toLowerCase(),fA[e])return TS.createDecipheriv(e,t,r);if(sa[e])return new j5({key:t,iv:r,mode:e,decrypt:!0});throw new TypeError("invalid suite type")}function qde(){return Object.keys(sa).concat(TS.getCiphers())}As.createCipher=As.Cipher=Ode;As.createCipheriv=As.Cipheriv=K5;As.createDecipher=As.Decipher=Hde;As.createDecipheriv=As.Decipheriv=X5;As.listCiphers=As.getCiphers=qde});var kr=x(($5,NS)=>{(function(e,t){"use strict";function r(H,E){if(!H)throw new Error(E||"Assertion failed")}function n(H,E){H.super_=E;var v=function(){};v.prototype=E.prototype,H.prototype=new v,H.prototype.constructor=H}function i(H,E,v){if(i.isBN(H))return H;this.negative=0,this.words=null,this.length=0,this.red=null,H!==null&&((E==="le"||E==="be")&&(v=E,E=10),this._init(H||0,E||10,v||"be"))}typeof e=="object"?e.exports=i:t.BN=i,i.BN=i,i.wordSize=26;var s;try{typeof window<"u"&&typeof window.Buffer<"u"?s=window.Buffer:s=Gr().Buffer}catch{}i.isBN=function(E){return E instanceof i?!0:E!==null&&typeof E=="object"&&E.constructor.wordSize===i.wordSize&&Array.isArray(E.words)},i.max=function(E,v){return E.cmp(v)>0?E:v},i.min=function(E,v){return E.cmp(v)<0?E:v},i.prototype._init=function(E,v,b){if(typeof E=="number")return this._initNumber(E,v,b);if(typeof E=="object")return this._initArray(E,v,b);v==="hex"&&(v=16),r(v===(v|0)&&v>=2&&v<=36),E=E.toString().replace(/\s+/g,"");var c=0;E[0]==="-"&&(c++,this.negative=1),c=0;c-=3)w=E[c]|E[c-1]<<8|E[c-2]<<16,this.words[g]|=w<>>26-R&67108863,R+=24,R>=26&&(R-=26,g++);else if(b==="le")for(c=0,g=0;c>>26-R&67108863,R+=24,R>=26&&(R-=26,g++);return this.strip()};function o(H,E){var v=H.charCodeAt(E);return v>=65&&v<=70?v-55:v>=97&&v<=102?v-87:v-48&15}function a(H,E,v){var b=o(H,v);return v-1>=E&&(b|=o(H,v-1)<<4),b}i.prototype._parseHex=function(E,v,b){this.length=Math.ceil((E.length-v)/6),this.words=new Array(this.length);for(var c=0;c=v;c-=2)R=a(E,v,c)<=18?(g-=18,w+=1,this.words[w]|=R>>>26):g+=8;else{var C=E.length-v;for(c=C%2===0?v+1:v;c=18?(g-=18,w+=1,this.words[w]|=R>>>26):g+=8}this.strip()};function A(H,E,v,b){for(var c=0,g=Math.min(H.length,v),w=E;w=49?c+=R-49+10:R>=17?c+=R-17+10:c+=R}return c}i.prototype._parseBase=function(E,v,b){this.words=[0],this.length=1;for(var c=0,g=1;g<=67108863;g*=v)c++;c--,g=g/v|0;for(var w=E.length-b,R=w%c,C=Math.min(w,w-R)+b,h=0,D=b;D1&&this.words[this.length-1]===0;)this.length--;return this._normSign()},i.prototype._normSign=function(){return this.length===1&&this.words[0]===0&&(this.negative=0),this},i.prototype.inspect=function(){return(this.red?""};var f=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],p=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];i.prototype.toString=function(E,v){E=E||10,v=v|0||1;var b;if(E===16||E==="hex"){b="";for(var c=0,g=0,w=0;w>>24-c&16777215,c+=2,c>=26&&(c-=26,w--),g!==0||w!==this.length-1?b=f[6-C.length]+C+b:b=C+b}for(g!==0&&(b=g.toString(16)+b);b.length%v!==0;)b="0"+b;return this.negative!==0&&(b="-"+b),b}if(E===(E|0)&&E>=2&&E<=36){var h=l[E],D=p[E];b="";var M=this.clone();for(M.negative=0;!M.isZero();){var I=M.modn(D).toString(E);M=M.idivn(D),M.isZero()?b=I+b:b=f[h-I.length]+I+b}for(this.isZero()&&(b="0"+b);b.length%v!==0;)b="0"+b;return this.negative!==0&&(b="-"+b),b}r(!1,"Base should be between 2 and 36")},i.prototype.toNumber=function(){var E=this.words[0];return this.length===2?E+=this.words[1]*67108864:this.length===3&&this.words[2]===1?E+=4503599627370496+this.words[1]*67108864:this.length>2&&r(!1,"Number can only safely store up to 53 bits"),this.negative!==0?-E:E},i.prototype.toJSON=function(){return this.toString(16)},i.prototype.toBuffer=function(E,v){return r(typeof s<"u"),this.toArrayLike(s,E,v)},i.prototype.toArray=function(E,v){return this.toArrayLike(Array,E,v)},i.prototype.toArrayLike=function(E,v,b){var c=this.byteLength(),g=b||Math.max(1,c);r(c<=g,"byte array longer than desired length"),r(g>0,"Requested array length <= 0"),this.strip();var w=v==="le",R=new E(g),C,h,D=this.clone();if(w){for(h=0;!D.isZero();h++)C=D.andln(255),D.iushrn(8),R[h]=C;for(;h=4096&&(b+=13,v>>>=13),v>=64&&(b+=7,v>>>=7),v>=8&&(b+=4,v>>>=4),v>=2&&(b+=2,v>>>=2),b+v},i.prototype._zeroBits=function(E){if(E===0)return 26;var v=E,b=0;return(v&8191)===0&&(b+=13,v>>>=13),(v&127)===0&&(b+=7,v>>>=7),(v&15)===0&&(b+=4,v>>>=4),(v&3)===0&&(b+=2,v>>>=2),(v&1)===0&&b++,b},i.prototype.bitLength=function(){var E=this.words[this.length-1],v=this._countBits(E);return(this.length-1)*26+v};function B(H){for(var E=new Array(H.bitLength()),v=0;v>>c}return E}i.prototype.zeroBits=function(){if(this.isZero())return 0;for(var E=0,v=0;vE.length?this.clone().ior(E):E.clone().ior(this)},i.prototype.uor=function(E){return this.length>E.length?this.clone().iuor(E):E.clone().iuor(this)},i.prototype.iuand=function(E){var v;this.length>E.length?v=E:v=this;for(var b=0;bE.length?this.clone().iand(E):E.clone().iand(this)},i.prototype.uand=function(E){return this.length>E.length?this.clone().iuand(E):E.clone().iuand(this)},i.prototype.iuxor=function(E){var v,b;this.length>E.length?(v=this,b=E):(v=E,b=this);for(var c=0;cE.length?this.clone().ixor(E):E.clone().ixor(this)},i.prototype.uxor=function(E){return this.length>E.length?this.clone().iuxor(E):E.clone().iuxor(this)},i.prototype.inotn=function(E){r(typeof E=="number"&&E>=0);var v=Math.ceil(E/26)|0,b=E%26;this._expand(v),b>0&&v--;for(var c=0;c0&&(this.words[c]=~this.words[c]&67108863>>26-b),this.strip()},i.prototype.notn=function(E){return this.clone().inotn(E)},i.prototype.setn=function(E,v){r(typeof E=="number"&&E>=0);var b=E/26|0,c=E%26;return this._expand(b+1),v?this.words[b]=this.words[b]|1<E.length?(b=this,c=E):(b=E,c=this);for(var g=0,w=0;w>>26;for(;g!==0&&w>>26;if(this.length=b.length,g!==0)this.words[this.length]=g,this.length++;else if(b!==this)for(;wE.length?this.clone().iadd(E):E.clone().iadd(this)},i.prototype.isub=function(E){if(E.negative!==0){E.negative=0;var v=this.iadd(E);return E.negative=1,v._normSign()}else if(this.negative!==0)return this.negative=0,this.iadd(E),this.negative=1,this._normSign();var b=this.cmp(E);if(b===0)return this.negative=0,this.length=1,this.words[0]=0,this;var c,g;b>0?(c=this,g=E):(c=E,g=this);for(var w=0,R=0;R>26,this.words[R]=v&67108863;for(;w!==0&&R>26,this.words[R]=v&67108863;if(w===0&&R>>26,M=C&67108863,I=Math.min(h,E.length-1),k=Math.max(0,h-H.length+1);k<=I;k++){var ne=h-k|0;c=H.words[ne]|0,g=E.words[k]|0,w=c*g+M,D+=w/67108864|0,M=w&67108863}v.words[h]=M|0,C=D|0}return C!==0?v.words[h]=C|0:v.length--,v.strip()}var _=function(E,v,b){var c=E.words,g=v.words,w=b.words,R=0,C,h,D,M=c[0]|0,I=M&8191,k=M>>>13,ne=c[1]|0,Ae=ne&8191,ue=ne>>>13,pe=c[2]|0,he=pe&8191,de=pe>>>13,wt=c[3]|0,Ie=wt&8191,be=wt>>>13,yr=c[4]|0,we=yr&8191,ve=yr>>>13,Ms=c[5]|0,Ye=Ms&8191,xe=Ms>>>13,Fs=c[6]|0,Te=Fs&8191,De=Fs>>>13,en=c[7]|0,Re=en&8191,He=en>>>13,ai=c[8]|0,Ne=ai&8191,Je=ai>>>13,F=c[9]|0,m=F&8191,Q=F>>>13,L=g[0]|0,W=L&8191,z=L>>>13,ae=g[1]|0,le=ae&8191,ye=ae>>>13,Ct=g[2]|0,Ee=Ct&8191,ge=Ct>>>13,Ua=g[3]|0,je=Ua&8191,tt=Ua>>>13,Fo=g[4]|0,$e=Fo&8191,rt=Fo>>>13,GA=g[5]|0,nt=GA&8191,it=GA>>>13,La=g[6]|0,Ke=La&8191,Xe=La>>>13,YA=g[7]|0,Ue=YA&8191,et=YA>>>13,WA=g[8]|0,st=WA&8191,Le=WA>>>13,hn=g[9]|0,Pe=hn&8191,Ze=hn>>>13;b.negative=E.negative^v.negative,b.length=19,C=Math.imul(I,W),h=Math.imul(I,z),h=h+Math.imul(k,W)|0,D=Math.imul(k,z);var wn=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(wn>>>26)|0,wn&=67108863,C=Math.imul(Ae,W),h=Math.imul(Ae,z),h=h+Math.imul(ue,W)|0,D=Math.imul(ue,z),C=C+Math.imul(I,le)|0,h=h+Math.imul(I,ye)|0,h=h+Math.imul(k,le)|0,D=D+Math.imul(k,ye)|0;var Pt=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Pt>>>26)|0,Pt&=67108863,C=Math.imul(he,W),h=Math.imul(he,z),h=h+Math.imul(de,W)|0,D=Math.imul(de,z),C=C+Math.imul(Ae,le)|0,h=h+Math.imul(Ae,ye)|0,h=h+Math.imul(ue,le)|0,D=D+Math.imul(ue,ye)|0,C=C+Math.imul(I,Ee)|0,h=h+Math.imul(I,ge)|0,h=h+Math.imul(k,Ee)|0,D=D+Math.imul(k,ge)|0;var kt=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(kt>>>26)|0,kt&=67108863,C=Math.imul(Ie,W),h=Math.imul(Ie,z),h=h+Math.imul(be,W)|0,D=Math.imul(be,z),C=C+Math.imul(he,le)|0,h=h+Math.imul(he,ye)|0,h=h+Math.imul(de,le)|0,D=D+Math.imul(de,ye)|0,C=C+Math.imul(Ae,Ee)|0,h=h+Math.imul(Ae,ge)|0,h=h+Math.imul(ue,Ee)|0,D=D+Math.imul(ue,ge)|0,C=C+Math.imul(I,je)|0,h=h+Math.imul(I,tt)|0,h=h+Math.imul(k,je)|0,D=D+Math.imul(k,tt)|0;var ks=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(ks>>>26)|0,ks&=67108863,C=Math.imul(we,W),h=Math.imul(we,z),h=h+Math.imul(ve,W)|0,D=Math.imul(ve,z),C=C+Math.imul(Ie,le)|0,h=h+Math.imul(Ie,ye)|0,h=h+Math.imul(be,le)|0,D=D+Math.imul(be,ye)|0,C=C+Math.imul(he,Ee)|0,h=h+Math.imul(he,ge)|0,h=h+Math.imul(de,Ee)|0,D=D+Math.imul(de,ge)|0,C=C+Math.imul(Ae,je)|0,h=h+Math.imul(Ae,tt)|0,h=h+Math.imul(ue,je)|0,D=D+Math.imul(ue,tt)|0,C=C+Math.imul(I,$e)|0,h=h+Math.imul(I,rt)|0,h=h+Math.imul(k,$e)|0,D=D+Math.imul(k,rt)|0;var Ai=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ai>>>26)|0,Ai&=67108863,C=Math.imul(Ye,W),h=Math.imul(Ye,z),h=h+Math.imul(xe,W)|0,D=Math.imul(xe,z),C=C+Math.imul(we,le)|0,h=h+Math.imul(we,ye)|0,h=h+Math.imul(ve,le)|0,D=D+Math.imul(ve,ye)|0,C=C+Math.imul(Ie,Ee)|0,h=h+Math.imul(Ie,ge)|0,h=h+Math.imul(be,Ee)|0,D=D+Math.imul(be,ge)|0,C=C+Math.imul(he,je)|0,h=h+Math.imul(he,tt)|0,h=h+Math.imul(de,je)|0,D=D+Math.imul(de,tt)|0,C=C+Math.imul(Ae,$e)|0,h=h+Math.imul(Ae,rt)|0,h=h+Math.imul(ue,$e)|0,D=D+Math.imul(ue,rt)|0,C=C+Math.imul(I,nt)|0,h=h+Math.imul(I,it)|0,h=h+Math.imul(k,nt)|0,D=D+Math.imul(k,it)|0;var xs=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(xs>>>26)|0,xs&=67108863,C=Math.imul(Te,W),h=Math.imul(Te,z),h=h+Math.imul(De,W)|0,D=Math.imul(De,z),C=C+Math.imul(Ye,le)|0,h=h+Math.imul(Ye,ye)|0,h=h+Math.imul(xe,le)|0,D=D+Math.imul(xe,ye)|0,C=C+Math.imul(we,Ee)|0,h=h+Math.imul(we,ge)|0,h=h+Math.imul(ve,Ee)|0,D=D+Math.imul(ve,ge)|0,C=C+Math.imul(Ie,je)|0,h=h+Math.imul(Ie,tt)|0,h=h+Math.imul(be,je)|0,D=D+Math.imul(be,tt)|0,C=C+Math.imul(he,$e)|0,h=h+Math.imul(he,rt)|0,h=h+Math.imul(de,$e)|0,D=D+Math.imul(de,rt)|0,C=C+Math.imul(Ae,nt)|0,h=h+Math.imul(Ae,it)|0,h=h+Math.imul(ue,nt)|0,D=D+Math.imul(ue,it)|0,C=C+Math.imul(I,Ke)|0,h=h+Math.imul(I,Xe)|0,h=h+Math.imul(k,Ke)|0,D=D+Math.imul(k,Xe)|0;var Us=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Us>>>26)|0,Us&=67108863,C=Math.imul(Re,W),h=Math.imul(Re,z),h=h+Math.imul(He,W)|0,D=Math.imul(He,z),C=C+Math.imul(Te,le)|0,h=h+Math.imul(Te,ye)|0,h=h+Math.imul(De,le)|0,D=D+Math.imul(De,ye)|0,C=C+Math.imul(Ye,Ee)|0,h=h+Math.imul(Ye,ge)|0,h=h+Math.imul(xe,Ee)|0,D=D+Math.imul(xe,ge)|0,C=C+Math.imul(we,je)|0,h=h+Math.imul(we,tt)|0,h=h+Math.imul(ve,je)|0,D=D+Math.imul(ve,tt)|0,C=C+Math.imul(Ie,$e)|0,h=h+Math.imul(Ie,rt)|0,h=h+Math.imul(be,$e)|0,D=D+Math.imul(be,rt)|0,C=C+Math.imul(he,nt)|0,h=h+Math.imul(he,it)|0,h=h+Math.imul(de,nt)|0,D=D+Math.imul(de,it)|0,C=C+Math.imul(Ae,Ke)|0,h=h+Math.imul(Ae,Xe)|0,h=h+Math.imul(ue,Ke)|0,D=D+Math.imul(ue,Xe)|0,C=C+Math.imul(I,Ue)|0,h=h+Math.imul(I,et)|0,h=h+Math.imul(k,Ue)|0,D=D+Math.imul(k,et)|0;var Ls=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ls>>>26)|0,Ls&=67108863,C=Math.imul(Ne,W),h=Math.imul(Ne,z),h=h+Math.imul(Je,W)|0,D=Math.imul(Je,z),C=C+Math.imul(Re,le)|0,h=h+Math.imul(Re,ye)|0,h=h+Math.imul(He,le)|0,D=D+Math.imul(He,ye)|0,C=C+Math.imul(Te,Ee)|0,h=h+Math.imul(Te,ge)|0,h=h+Math.imul(De,Ee)|0,D=D+Math.imul(De,ge)|0,C=C+Math.imul(Ye,je)|0,h=h+Math.imul(Ye,tt)|0,h=h+Math.imul(xe,je)|0,D=D+Math.imul(xe,tt)|0,C=C+Math.imul(we,$e)|0,h=h+Math.imul(we,rt)|0,h=h+Math.imul(ve,$e)|0,D=D+Math.imul(ve,rt)|0,C=C+Math.imul(Ie,nt)|0,h=h+Math.imul(Ie,it)|0,h=h+Math.imul(be,nt)|0,D=D+Math.imul(be,it)|0,C=C+Math.imul(he,Ke)|0,h=h+Math.imul(he,Xe)|0,h=h+Math.imul(de,Ke)|0,D=D+Math.imul(de,Xe)|0,C=C+Math.imul(Ae,Ue)|0,h=h+Math.imul(Ae,et)|0,h=h+Math.imul(ue,Ue)|0,D=D+Math.imul(ue,et)|0,C=C+Math.imul(I,st)|0,h=h+Math.imul(I,Le)|0,h=h+Math.imul(k,st)|0,D=D+Math.imul(k,Le)|0;var Ps=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ps>>>26)|0,Ps&=67108863,C=Math.imul(m,W),h=Math.imul(m,z),h=h+Math.imul(Q,W)|0,D=Math.imul(Q,z),C=C+Math.imul(Ne,le)|0,h=h+Math.imul(Ne,ye)|0,h=h+Math.imul(Je,le)|0,D=D+Math.imul(Je,ye)|0,C=C+Math.imul(Re,Ee)|0,h=h+Math.imul(Re,ge)|0,h=h+Math.imul(He,Ee)|0,D=D+Math.imul(He,ge)|0,C=C+Math.imul(Te,je)|0,h=h+Math.imul(Te,tt)|0,h=h+Math.imul(De,je)|0,D=D+Math.imul(De,tt)|0,C=C+Math.imul(Ye,$e)|0,h=h+Math.imul(Ye,rt)|0,h=h+Math.imul(xe,$e)|0,D=D+Math.imul(xe,rt)|0,C=C+Math.imul(we,nt)|0,h=h+Math.imul(we,it)|0,h=h+Math.imul(ve,nt)|0,D=D+Math.imul(ve,it)|0,C=C+Math.imul(Ie,Ke)|0,h=h+Math.imul(Ie,Xe)|0,h=h+Math.imul(be,Ke)|0,D=D+Math.imul(be,Xe)|0,C=C+Math.imul(he,Ue)|0,h=h+Math.imul(he,et)|0,h=h+Math.imul(de,Ue)|0,D=D+Math.imul(de,et)|0,C=C+Math.imul(Ae,st)|0,h=h+Math.imul(Ae,Le)|0,h=h+Math.imul(ue,st)|0,D=D+Math.imul(ue,Le)|0,C=C+Math.imul(I,Pe)|0,h=h+Math.imul(I,Ze)|0,h=h+Math.imul(k,Pe)|0,D=D+Math.imul(k,Ze)|0;var Os=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Os>>>26)|0,Os&=67108863,C=Math.imul(m,le),h=Math.imul(m,ye),h=h+Math.imul(Q,le)|0,D=Math.imul(Q,ye),C=C+Math.imul(Ne,Ee)|0,h=h+Math.imul(Ne,ge)|0,h=h+Math.imul(Je,Ee)|0,D=D+Math.imul(Je,ge)|0,C=C+Math.imul(Re,je)|0,h=h+Math.imul(Re,tt)|0,h=h+Math.imul(He,je)|0,D=D+Math.imul(He,tt)|0,C=C+Math.imul(Te,$e)|0,h=h+Math.imul(Te,rt)|0,h=h+Math.imul(De,$e)|0,D=D+Math.imul(De,rt)|0,C=C+Math.imul(Ye,nt)|0,h=h+Math.imul(Ye,it)|0,h=h+Math.imul(xe,nt)|0,D=D+Math.imul(xe,it)|0,C=C+Math.imul(we,Ke)|0,h=h+Math.imul(we,Xe)|0,h=h+Math.imul(ve,Ke)|0,D=D+Math.imul(ve,Xe)|0,C=C+Math.imul(Ie,Ue)|0,h=h+Math.imul(Ie,et)|0,h=h+Math.imul(be,Ue)|0,D=D+Math.imul(be,et)|0,C=C+Math.imul(he,st)|0,h=h+Math.imul(he,Le)|0,h=h+Math.imul(de,st)|0,D=D+Math.imul(de,Le)|0,C=C+Math.imul(Ae,Pe)|0,h=h+Math.imul(Ae,Ze)|0,h=h+Math.imul(ue,Pe)|0,D=D+Math.imul(ue,Ze)|0;var Ji=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Ji>>>26)|0,Ji&=67108863,C=Math.imul(m,Ee),h=Math.imul(m,ge),h=h+Math.imul(Q,Ee)|0,D=Math.imul(Q,ge),C=C+Math.imul(Ne,je)|0,h=h+Math.imul(Ne,tt)|0,h=h+Math.imul(Je,je)|0,D=D+Math.imul(Je,tt)|0,C=C+Math.imul(Re,$e)|0,h=h+Math.imul(Re,rt)|0,h=h+Math.imul(He,$e)|0,D=D+Math.imul(He,rt)|0,C=C+Math.imul(Te,nt)|0,h=h+Math.imul(Te,it)|0,h=h+Math.imul(De,nt)|0,D=D+Math.imul(De,it)|0,C=C+Math.imul(Ye,Ke)|0,h=h+Math.imul(Ye,Xe)|0,h=h+Math.imul(xe,Ke)|0,D=D+Math.imul(xe,Xe)|0,C=C+Math.imul(we,Ue)|0,h=h+Math.imul(we,et)|0,h=h+Math.imul(ve,Ue)|0,D=D+Math.imul(ve,et)|0,C=C+Math.imul(Ie,st)|0,h=h+Math.imul(Ie,Le)|0,h=h+Math.imul(be,st)|0,D=D+Math.imul(be,Le)|0,C=C+Math.imul(he,Pe)|0,h=h+Math.imul(he,Ze)|0,h=h+Math.imul(de,Pe)|0,D=D+Math.imul(de,Ze)|0;var ji=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(ji>>>26)|0,ji&=67108863,C=Math.imul(m,je),h=Math.imul(m,tt),h=h+Math.imul(Q,je)|0,D=Math.imul(Q,tt),C=C+Math.imul(Ne,$e)|0,h=h+Math.imul(Ne,rt)|0,h=h+Math.imul(Je,$e)|0,D=D+Math.imul(Je,rt)|0,C=C+Math.imul(Re,nt)|0,h=h+Math.imul(Re,it)|0,h=h+Math.imul(He,nt)|0,D=D+Math.imul(He,it)|0,C=C+Math.imul(Te,Ke)|0,h=h+Math.imul(Te,Xe)|0,h=h+Math.imul(De,Ke)|0,D=D+Math.imul(De,Xe)|0,C=C+Math.imul(Ye,Ue)|0,h=h+Math.imul(Ye,et)|0,h=h+Math.imul(xe,Ue)|0,D=D+Math.imul(xe,et)|0,C=C+Math.imul(we,st)|0,h=h+Math.imul(we,Le)|0,h=h+Math.imul(ve,st)|0,D=D+Math.imul(ve,Le)|0,C=C+Math.imul(Ie,Pe)|0,h=h+Math.imul(Ie,Ze)|0,h=h+Math.imul(be,Pe)|0,D=D+Math.imul(be,Ze)|0;var ko=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(ko>>>26)|0,ko&=67108863,C=Math.imul(m,$e),h=Math.imul(m,rt),h=h+Math.imul(Q,$e)|0,D=Math.imul(Q,rt),C=C+Math.imul(Ne,nt)|0,h=h+Math.imul(Ne,it)|0,h=h+Math.imul(Je,nt)|0,D=D+Math.imul(Je,it)|0,C=C+Math.imul(Re,Ke)|0,h=h+Math.imul(Re,Xe)|0,h=h+Math.imul(He,Ke)|0,D=D+Math.imul(He,Xe)|0,C=C+Math.imul(Te,Ue)|0,h=h+Math.imul(Te,et)|0,h=h+Math.imul(De,Ue)|0,D=D+Math.imul(De,et)|0,C=C+Math.imul(Ye,st)|0,h=h+Math.imul(Ye,Le)|0,h=h+Math.imul(xe,st)|0,D=D+Math.imul(xe,Le)|0,C=C+Math.imul(we,Pe)|0,h=h+Math.imul(we,Ze)|0,h=h+Math.imul(ve,Pe)|0,D=D+Math.imul(ve,Ze)|0;var xo=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(xo>>>26)|0,xo&=67108863,C=Math.imul(m,nt),h=Math.imul(m,it),h=h+Math.imul(Q,nt)|0,D=Math.imul(Q,it),C=C+Math.imul(Ne,Ke)|0,h=h+Math.imul(Ne,Xe)|0,h=h+Math.imul(Je,Ke)|0,D=D+Math.imul(Je,Xe)|0,C=C+Math.imul(Re,Ue)|0,h=h+Math.imul(Re,et)|0,h=h+Math.imul(He,Ue)|0,D=D+Math.imul(He,et)|0,C=C+Math.imul(Te,st)|0,h=h+Math.imul(Te,Le)|0,h=h+Math.imul(De,st)|0,D=D+Math.imul(De,Le)|0,C=C+Math.imul(Ye,Pe)|0,h=h+Math.imul(Ye,Ze)|0,h=h+Math.imul(xe,Pe)|0,D=D+Math.imul(xe,Ze)|0;var Uo=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Uo>>>26)|0,Uo&=67108863,C=Math.imul(m,Ke),h=Math.imul(m,Xe),h=h+Math.imul(Q,Ke)|0,D=Math.imul(Q,Xe),C=C+Math.imul(Ne,Ue)|0,h=h+Math.imul(Ne,et)|0,h=h+Math.imul(Je,Ue)|0,D=D+Math.imul(Je,et)|0,C=C+Math.imul(Re,st)|0,h=h+Math.imul(Re,Le)|0,h=h+Math.imul(He,st)|0,D=D+Math.imul(He,Le)|0,C=C+Math.imul(Te,Pe)|0,h=h+Math.imul(Te,Ze)|0,h=h+Math.imul(De,Pe)|0,D=D+Math.imul(De,Ze)|0;var Lo=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Lo>>>26)|0,Lo&=67108863,C=Math.imul(m,Ue),h=Math.imul(m,et),h=h+Math.imul(Q,Ue)|0,D=Math.imul(Q,et),C=C+Math.imul(Ne,st)|0,h=h+Math.imul(Ne,Le)|0,h=h+Math.imul(Je,st)|0,D=D+Math.imul(Je,Le)|0,C=C+Math.imul(Re,Pe)|0,h=h+Math.imul(Re,Ze)|0,h=h+Math.imul(He,Pe)|0,D=D+Math.imul(He,Ze)|0;var Hs=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Hs>>>26)|0,Hs&=67108863,C=Math.imul(m,st),h=Math.imul(m,Le),h=h+Math.imul(Q,st)|0,D=Math.imul(Q,Le),C=C+Math.imul(Ne,Pe)|0,h=h+Math.imul(Ne,Ze)|0,h=h+Math.imul(Je,Pe)|0,D=D+Math.imul(Je,Ze)|0;var Sn=(R+C|0)+((h&8191)<<13)|0;R=(D+(h>>>13)|0)+(Sn>>>26)|0,Sn&=67108863,C=Math.imul(m,Pe),h=Math.imul(m,Ze),h=h+Math.imul(Q,Pe)|0,D=Math.imul(Q,Ze);var Po=(R+C|0)+((h&8191)<<13)|0;return R=(D+(h>>>13)|0)+(Po>>>26)|0,Po&=67108863,w[0]=wn,w[1]=Pt,w[2]=kt,w[3]=ks,w[4]=Ai,w[5]=xs,w[6]=Us,w[7]=Ls,w[8]=Ps,w[9]=Os,w[10]=Ji,w[11]=ji,w[12]=ko,w[13]=xo,w[14]=Uo,w[15]=Lo,w[16]=Hs,w[17]=Sn,w[18]=Po,R!==0&&(w[19]=R,b.length++),b};Math.imul||(_=S);function N(H,E,v){v.negative=E.negative^H.negative,v.length=H.length+E.length;for(var b=0,c=0,g=0;g>>26)|0,c+=w>>>26,w&=67108863}v.words[g]=R,b=w,w=c}return b!==0?v.words[g]=b:v.length--,v.strip()}function P(H,E,v){var b=new U;return b.mulp(H,E,v)}i.prototype.mulTo=function(E,v){var b,c=this.length+E.length;return this.length===10&&E.length===10?b=_(this,E,v):c<63?b=S(this,E,v):c<1024?b=N(this,E,v):b=P(this,E,v),b};function U(H,E){this.x=H,this.y=E}U.prototype.makeRBT=function(E){for(var v=new Array(E),b=i.prototype._countBits(E)-1,c=0;c>=1;return c},U.prototype.permute=function(E,v,b,c,g,w){for(var R=0;R>>1)g++;return 1<>>13,b[2*w+1]=g&8191,g=g>>>13;for(w=2*v;w>=26,v+=c/67108864|0,v+=g>>>26,this.words[b]=g&67108863}return v!==0&&(this.words[b]=v,this.length++),this.length=E===0?1:this.length,this},i.prototype.muln=function(E){return this.clone().imuln(E)},i.prototype.sqr=function(){return this.mul(this)},i.prototype.isqr=function(){return this.imul(this.clone())},i.prototype.pow=function(E){var v=B(E);if(v.length===0)return new i(1);for(var b=this,c=0;c=0);var v=E%26,b=(E-v)/26,c=67108863>>>26-v<<26-v,g;if(v!==0){var w=0;for(g=0;g>>26-v}w&&(this.words[g]=w,this.length++)}if(b!==0){for(g=this.length-1;g>=0;g--)this.words[g+b]=this.words[g];for(g=0;g=0);var c;v?c=(v-v%26)/26:c=0;var g=E%26,w=Math.min((E-g)/26,this.length),R=67108863^67108863>>>g<w)for(this.length-=w,h=0;h=0&&(D!==0||h>=c);h--){var M=this.words[h]|0;this.words[h]=D<<26-g|M>>>g,D=M&R}return C&&D!==0&&(C.words[C.length++]=D),this.length===0&&(this.words[0]=0,this.length=1),this.strip()},i.prototype.ishrn=function(E,v,b){return r(this.negative===0),this.iushrn(E,v,b)},i.prototype.shln=function(E){return this.clone().ishln(E)},i.prototype.ushln=function(E){return this.clone().iushln(E)},i.prototype.shrn=function(E){return this.clone().ishrn(E)},i.prototype.ushrn=function(E){return this.clone().iushrn(E)},i.prototype.testn=function(E){r(typeof E=="number"&&E>=0);var v=E%26,b=(E-v)/26,c=1<=0);var v=E%26,b=(E-v)/26;if(r(this.negative===0,"imaskn works only with positive numbers"),this.length<=b)return this;if(v!==0&&b++,this.length=Math.min(b,this.length),v!==0){var c=67108863^67108863>>>v<=67108864;v++)this.words[v]-=67108864,v===this.length-1?this.words[v+1]=1:this.words[v+1]++;return this.length=Math.max(this.length,v+1),this},i.prototype.isubn=function(E){if(r(typeof E=="number"),r(E<67108864),E<0)return this.iaddn(-E);if(this.negative!==0)return this.negative=0,this.iaddn(E),this.negative=1,this;if(this.words[0]-=E,this.length===1&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var v=0;v>26)-(C/67108864|0),this.words[g+b]=w&67108863}for(;g>26,this.words[g+b]=w&67108863;if(R===0)return this.strip();for(r(R===-1),R=0,g=0;g>26,this.words[g]=w&67108863;return this.negative=1,this.strip()},i.prototype._wordDiv=function(E,v){var b=this.length-E.length,c=this.clone(),g=E,w=g.words[g.length-1]|0,R=this._countBits(w);b=26-R,b!==0&&(g=g.ushln(b),c.iushln(b),w=g.words[g.length-1]|0);var C=c.length-g.length,h;if(v!=="mod"){h=new i(null),h.length=C+1,h.words=new Array(h.length);for(var D=0;D=0;I--){var k=(c.words[g.length+I]|0)*67108864+(c.words[g.length+I-1]|0);for(k=Math.min(k/w|0,67108863),c._ishlnsubmul(g,k,I);c.negative!==0;)k--,c.negative=0,c._ishlnsubmul(g,1,I),c.isZero()||(c.negative^=1);h&&(h.words[I]=k)}return h&&h.strip(),c.strip(),v!=="div"&&b!==0&&c.iushrn(b),{div:h||null,mod:c}},i.prototype.divmod=function(E,v,b){if(r(!E.isZero()),this.isZero())return{div:new i(0),mod:new i(0)};var c,g,w;return this.negative!==0&&E.negative===0?(w=this.neg().divmod(E,v),v!=="mod"&&(c=w.div.neg()),v!=="div"&&(g=w.mod.neg(),b&&g.negative!==0&&g.iadd(E)),{div:c,mod:g}):this.negative===0&&E.negative!==0?(w=this.divmod(E.neg(),v),v!=="mod"&&(c=w.div.neg()),{div:c,mod:w.mod}):(this.negative&E.negative)!==0?(w=this.neg().divmod(E.neg(),v),v!=="div"&&(g=w.mod.neg(),b&&g.negative!==0&&g.isub(E)),{div:w.div,mod:g}):E.length>this.length||this.cmp(E)<0?{div:new i(0),mod:this}:E.length===1?v==="div"?{div:this.divn(E.words[0]),mod:null}:v==="mod"?{div:null,mod:new i(this.modn(E.words[0]))}:{div:this.divn(E.words[0]),mod:new i(this.modn(E.words[0]))}:this._wordDiv(E,v)},i.prototype.div=function(E){return this.divmod(E,"div",!1).div},i.prototype.mod=function(E){return this.divmod(E,"mod",!1).mod},i.prototype.umod=function(E){return this.divmod(E,"mod",!0).mod},i.prototype.divRound=function(E){var v=this.divmod(E);if(v.mod.isZero())return v.div;var b=v.div.negative!==0?v.mod.isub(E):v.mod,c=E.ushrn(1),g=E.andln(1),w=b.cmp(c);return w<0||g===1&&w===0?v.div:v.div.negative!==0?v.div.isubn(1):v.div.iaddn(1)},i.prototype.modn=function(E){r(E<=67108863);for(var v=(1<<26)%E,b=0,c=this.length-1;c>=0;c--)b=(v*b+(this.words[c]|0))%E;return b},i.prototype.idivn=function(E){r(E<=67108863);for(var v=0,b=this.length-1;b>=0;b--){var c=(this.words[b]|0)+v*67108864;this.words[b]=c/E|0,v=c%E}return this.strip()},i.prototype.divn=function(E){return this.clone().idivn(E)},i.prototype.egcd=function(E){r(E.negative===0),r(!E.isZero());var v=this,b=E.clone();v.negative!==0?v=v.umod(E):v=v.clone();for(var c=new i(1),g=new i(0),w=new i(0),R=new i(1),C=0;v.isEven()&&b.isEven();)v.iushrn(1),b.iushrn(1),++C;for(var h=b.clone(),D=v.clone();!v.isZero();){for(var M=0,I=1;(v.words[0]&I)===0&&M<26;++M,I<<=1);if(M>0)for(v.iushrn(M);M-- >0;)(c.isOdd()||g.isOdd())&&(c.iadd(h),g.isub(D)),c.iushrn(1),g.iushrn(1);for(var k=0,ne=1;(b.words[0]&ne)===0&&k<26;++k,ne<<=1);if(k>0)for(b.iushrn(k);k-- >0;)(w.isOdd()||R.isOdd())&&(w.iadd(h),R.isub(D)),w.iushrn(1),R.iushrn(1);v.cmp(b)>=0?(v.isub(b),c.isub(w),g.isub(R)):(b.isub(v),w.isub(c),R.isub(g))}return{a:w,b:R,gcd:b.iushln(C)}},i.prototype._invmp=function(E){r(E.negative===0),r(!E.isZero());var v=this,b=E.clone();v.negative!==0?v=v.umod(E):v=v.clone();for(var c=new i(1),g=new i(0),w=b.clone();v.cmpn(1)>0&&b.cmpn(1)>0;){for(var R=0,C=1;(v.words[0]&C)===0&&R<26;++R,C<<=1);if(R>0)for(v.iushrn(R);R-- >0;)c.isOdd()&&c.iadd(w),c.iushrn(1);for(var h=0,D=1;(b.words[0]&D)===0&&h<26;++h,D<<=1);if(h>0)for(b.iushrn(h);h-- >0;)g.isOdd()&&g.iadd(w),g.iushrn(1);v.cmp(b)>=0?(v.isub(b),c.isub(g)):(b.isub(v),g.isub(c))}var M;return v.cmpn(1)===0?M=c:M=g,M.cmpn(0)<0&&M.iadd(E),M},i.prototype.gcd=function(E){if(this.isZero())return E.abs();if(E.isZero())return this.abs();var v=this.clone(),b=E.clone();v.negative=0,b.negative=0;for(var c=0;v.isEven()&&b.isEven();c++)v.iushrn(1),b.iushrn(1);do{for(;v.isEven();)v.iushrn(1);for(;b.isEven();)b.iushrn(1);var g=v.cmp(b);if(g<0){var w=v;v=b,b=w}else if(g===0||b.cmpn(1)===0)break;v.isub(b)}while(!0);return b.iushln(c)},i.prototype.invm=function(E){return this.egcd(E).a.umod(E)},i.prototype.isEven=function(){return(this.words[0]&1)===0},i.prototype.isOdd=function(){return(this.words[0]&1)===1},i.prototype.andln=function(E){return this.words[0]&E},i.prototype.bincn=function(E){r(typeof E=="number");var v=E%26,b=(E-v)/26,c=1<>>26,R&=67108863,this.words[w]=R}return g!==0&&(this.words[w]=g,this.length++),this},i.prototype.isZero=function(){return this.length===1&&this.words[0]===0},i.prototype.cmpn=function(E){var v=E<0;if(this.negative!==0&&!v)return-1;if(this.negative===0&&v)return 1;this.strip();var b;if(this.length>1)b=1;else{v&&(E=-E),r(E<=67108863,"Number is too big");var c=this.words[0]|0;b=c===E?0:cE.length)return 1;if(this.length=0;b--){var c=this.words[b]|0,g=E.words[b]|0;if(c!==g){cg&&(v=1);break}}return v},i.prototype.gtn=function(E){return this.cmpn(E)===1},i.prototype.gt=function(E){return this.cmp(E)===1},i.prototype.gten=function(E){return this.cmpn(E)>=0},i.prototype.gte=function(E){return this.cmp(E)>=0},i.prototype.ltn=function(E){return this.cmpn(E)===-1},i.prototype.lt=function(E){return this.cmp(E)===-1},i.prototype.lten=function(E){return this.cmpn(E)<=0},i.prototype.lte=function(E){return this.cmp(E)<=0},i.prototype.eqn=function(E){return this.cmpn(E)===0},i.prototype.eq=function(E){return this.cmp(E)===0},i.red=function(E){return new ie(E)},i.prototype.toRed=function(E){return r(!this.red,"Already a number in reduction context"),r(this.negative===0,"red works only with positives"),E.convertTo(this)._forceRed(E)},i.prototype.fromRed=function(){return r(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},i.prototype._forceRed=function(E){return this.red=E,this},i.prototype.forceRed=function(E){return r(!this.red,"Already a number in reduction context"),this._forceRed(E)},i.prototype.redAdd=function(E){return r(this.red,"redAdd works only with red numbers"),this.red.add(this,E)},i.prototype.redIAdd=function(E){return r(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,E)},i.prototype.redSub=function(E){return r(this.red,"redSub works only with red numbers"),this.red.sub(this,E)},i.prototype.redISub=function(E){return r(this.red,"redISub works only with red numbers"),this.red.isub(this,E)},i.prototype.redShl=function(E){return r(this.red,"redShl works only with red numbers"),this.red.shl(this,E)},i.prototype.redMul=function(E){return r(this.red,"redMul works only with red numbers"),this.red._verify2(this,E),this.red.mul(this,E)},i.prototype.redIMul=function(E){return r(this.red,"redMul works only with red numbers"),this.red._verify2(this,E),this.red.imul(this,E)},i.prototype.redSqr=function(){return r(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},i.prototype.redISqr=function(){return r(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},i.prototype.redSqrt=function(){return r(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},i.prototype.redInvm=function(){return r(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},i.prototype.redNeg=function(){return r(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},i.prototype.redPow=function(E){return r(this.red&&!E.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,E)};var G={k256:null,p224:null,p192:null,p25519:null};function Y(H,E){this.name=H,this.p=new i(E,16),this.n=this.p.bitLength(),this.k=new i(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}Y.prototype._tmp=function(){var E=new i(null);return E.words=new Array(Math.ceil(this.n/13)),E},Y.prototype.ireduce=function(E){var v=E,b;do this.split(v,this.tmp),v=this.imulK(v),v=v.iadd(this.tmp),b=v.bitLength();while(b>this.n);var c=b0?v.isub(this.p):v.strip!==void 0?v.strip():v._strip(),v},Y.prototype.split=function(E,v){E.iushrn(this.n,0,v)},Y.prototype.imulK=function(E){return E.imul(this.k)};function Z(){Y.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}n(Z,Y),Z.prototype.split=function(E,v){for(var b=4194303,c=Math.min(E.length,9),g=0;g>>22,w=R}w>>>=22,E.words[g-10]=w,w===0&&E.length>10?E.length-=10:E.length-=9},Z.prototype.imulK=function(E){E.words[E.length]=0,E.words[E.length+1]=0,E.length+=2;for(var v=0,b=0;b>>=26,E.words[b]=g,v=c}return v!==0&&(E.words[E.length++]=v),E},i._prime=function(E){if(G[E])return G[E];var v;if(E==="k256")v=new Z;else if(E==="p224")v=new ee;else if(E==="p192")v=new j;else if(E==="p25519")v=new se;else throw new Error("Unknown prime "+E);return G[E]=v,v};function ie(H){if(typeof H=="string"){var E=i._prime(H);this.m=E.p,this.prime=E}else r(H.gtn(1),"modulus must be greater than 1"),this.m=H,this.prime=null}ie.prototype._verify1=function(E){r(E.negative===0,"red works only with positives"),r(E.red,"red works only with red numbers")},ie.prototype._verify2=function(E,v){r((E.negative|v.negative)===0,"red works only with positives"),r(E.red&&E.red===v.red,"red works only with red numbers")},ie.prototype.imod=function(E){return this.prime?this.prime.ireduce(E)._forceRed(this):E.umod(this.m)._forceRed(this)},ie.prototype.neg=function(E){return E.isZero()?E.clone():this.m.sub(E)._forceRed(this)},ie.prototype.add=function(E,v){this._verify2(E,v);var b=E.add(v);return b.cmp(this.m)>=0&&b.isub(this.m),b._forceRed(this)},ie.prototype.iadd=function(E,v){this._verify2(E,v);var b=E.iadd(v);return b.cmp(this.m)>=0&&b.isub(this.m),b},ie.prototype.sub=function(E,v){this._verify2(E,v);var b=E.sub(v);return b.cmpn(0)<0&&b.iadd(this.m),b._forceRed(this)},ie.prototype.isub=function(E,v){this._verify2(E,v);var b=E.isub(v);return b.cmpn(0)<0&&b.iadd(this.m),b},ie.prototype.shl=function(E,v){return this._verify1(E),this.imod(E.ushln(v))},ie.prototype.imul=function(E,v){return this._verify2(E,v),this.imod(E.imul(v))},ie.prototype.mul=function(E,v){return this._verify2(E,v),this.imod(E.mul(v))},ie.prototype.isqr=function(E){return this.imul(E,E.clone())},ie.prototype.sqr=function(E){return this.mul(E,E)},ie.prototype.sqrt=function(E){if(E.isZero())return E.clone();var v=this.m.andln(3);if(r(v%2===1),v===3){var b=this.m.add(new i(1)).iushrn(2);return this.pow(E,b)}for(var c=this.m.subn(1),g=0;!c.isZero()&&c.andln(1)===0;)g++,c.iushrn(1);r(!c.isZero());var w=new i(1).toRed(this),R=w.redNeg(),C=this.m.subn(1).iushrn(1),h=this.m.bitLength();for(h=new i(2*h*h).toRed(this);this.pow(h,C).cmp(R)!==0;)h.redIAdd(R);for(var D=this.pow(h,c),M=this.pow(E,c.addn(1).iushrn(1)),I=this.pow(E,c),k=g;I.cmp(w)!==0;){for(var ne=I,Ae=0;ne.cmp(w)!==0;Ae++)ne=ne.redSqr();r(Ae=0;g--){for(var D=v.words[g],M=h-1;M>=0;M--){var I=D>>M&1;if(w!==c[0]&&(w=this.sqr(w)),I===0&&R===0){C=0;continue}R<<=1,R|=I,C++,!(C!==b&&(g!==0||M!==0))&&(w=this.mul(w,c[R]),C=0,R=0)}h=26}return w},ie.prototype.convertTo=function(E){var v=E.umod(this.m);return v===E?v.clone():v},ie.prototype.convertFrom=function(E){var v=E.clone();return v.red=null,v},i.mont=function(E){return new ce(E)};function ce(H){ie.call(this,H),this.shift=this.m.bitLength(),this.shift%26!==0&&(this.shift+=26-this.shift%26),this.r=new i(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}n(ce,ie),ce.prototype.convertTo=function(E){return this.imod(E.ushln(this.shift))},ce.prototype.convertFrom=function(E){var v=this.imod(E.mul(this.rinv));return v.red=null,v},ce.prototype.imul=function(E,v){if(E.isZero()||v.isZero())return E.words[0]=0,E.length=1,E;var b=E.imul(v),c=b.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),g=b.isub(c).iushrn(this.shift),w=g;return g.cmp(this.m)>=0?w=g.isub(this.m):g.cmpn(0)<0&&(w=g.iadd(this.m)),w._forceRed(this)},ce.prototype.mul=function(E,v){if(E.isZero()||v.isZero())return new i(0)._forceRed(this);var b=E.mul(v),c=b.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),g=b.isub(c).iushrn(this.shift),w=g;return g.cmp(this.m)>=0?w=g.isub(this.m):g.cmpn(0)<0&&(w=g.iadd(this.m)),w._forceRed(this)},ce.prototype.invm=function(E){var v=this.imod(E._invmp(this.m).mul(this.r2));return v._forceRed(this)}})(typeof NS>"u"||NS,$5)});var Qy=x((mMe,kS)=>{var MS;kS.exports=function(t){return MS||(MS=new uA(null)),MS.generate(t)};function uA(e){this.rand=e}kS.exports.Rand=uA;uA.prototype.generate=function(t){return this._rand(t)};uA.prototype._rand=function(t){if(this.rand.getBytes)return this.rand.getBytes(t);for(var r=new Uint8Array(t),n=0;n{var Mf=kr(),Gde=Qy();function Ff(e){this.rand=e||new Gde.Rand}eP.exports=Ff;Ff.create=function(t){return new Ff(t)};Ff.prototype._randbelow=function(t){var r=t.bitLength(),n=Math.ceil(r/8);do var i=new Mf(this.rand.generate(n));while(i.cmp(t)>=0);return i};Ff.prototype._randrange=function(t,r){var n=r.sub(t);return t.add(this._randbelow(n))};Ff.prototype.test=function(t,r,n){var i=t.bitLength(),s=Mf.mont(t),o=new Mf(1).toRed(s);r||(r=Math.max(1,i/48|0));for(var a=t.subn(1),A=0;!a.testn(A);A++);for(var f=t.shrn(A),l=a.toRed(s),p=!0;r>0;r--){var B=this._randrange(new Mf(2),a);n&&n(B);var S=B.toRed(s).redPow(f);if(!(S.cmp(o)===0||S.cmp(l)===0)){for(var _=1;_0;r--){var l=this._randrange(new Mf(2),o),p=t.gcd(l);if(p.cmpn(1)!==0)return p;var B=l.toRed(i).redPow(A);if(!(B.cmp(s)===0||B.cmp(f)===0)){for(var S=1;S{var Yde=If();nP.exports=HS;HS.simpleSieve=PS;HS.fermatTest=OS;var Jr=kr(),Wde=new Jr(24),Vde=xS(),tP=new Vde,Jde=new Jr(1),LS=new Jr(2),jde=new Jr(5),IMe=new Jr(16),bMe=new Jr(8),zde=new Jr(10),Kde=new Jr(3),CMe=new Jr(7),Xde=new Jr(11),rP=new Jr(4),QMe=new Jr(12),US=null;function Zde(){if(US!==null)return US;var e=1048576,t=[];t[0]=2;for(var r=1,n=3;ne;)r.ishrn(1);if(r.isEven()&&r.iadd(Jde),r.testn(1)||r.iadd(LS),t.cmp(LS)){if(!t.cmp(jde))for(;r.mod(zde).cmp(Kde);)r.iadd(rP)}else for(;r.mod(Wde).cmp(Xde);)r.iadd(rP);if(n=r.shrn(1),PS(n)&&PS(r)&&OS(n)&&OS(r)&&tP.test(n)&&tP.test(r))return r}}});var iP=x((SMe,$de)=>{$de.exports={modp1:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff"},modp2:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff"},modp5:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff"},modp14:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff"},modp15:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff"},modp16:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff"},modp17:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff"},modp18:{gen:"02",prime:"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff"}}});var AP=x((_Me,aP)=>{var Qi=kr(),ege=xS(),sP=new ege,tge=new Qi(24),rge=new Qi(11),nge=new Qi(10),ige=new Qi(3),sge=new Qi(7),oP=qS(),oge=If();aP.exports=oa;function age(e,t){return t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t)),this._pub=new Qi(e),this}function Age(e,t){return t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t)),this._priv=new Qi(e),this}var wy={};function fge(e,t){var r=t.toString("hex"),n=[r,e.toString(16)].join("_");if(n in wy)return wy[n];var i=0;if(e.isEven()||!oP.simpleSieve||!oP.fermatTest(e)||!sP.test(e))return i+=1,r==="02"||r==="05"?i+=8:i+=4,wy[n]=i,i;sP.test(e.shrn(1))||(i+=2);var s;switch(r){case"02":e.mod(tge).cmp(rge)&&(i+=8);break;case"05":s=e.mod(nge),s.cmp(ige)&&s.cmp(sge)&&(i+=8);break;default:i+=4}return wy[n]=i,i}function oa(e,t,r){this.setGenerator(t),this.__prime=new Qi(e),this._prime=Qi.mont(this.__prime),this._primeLen=e.length,this._pub=void 0,this._priv=void 0,this._primeCode=void 0,r?(this.setPublicKey=age,this.setPrivateKey=Age):this._primeCode=8}Object.defineProperty(oa.prototype,"verifyError",{enumerable:!0,get:function(){return typeof this._primeCode!="number"&&(this._primeCode=fge(this.__prime,this.__gen)),this._primeCode}});oa.prototype.generateKeys=function(){return this._priv||(this._priv=new Qi(oge(this._primeLen))),this._pub=this._gen.toRed(this._prime).redPow(this._priv).fromRed(),this.getPublicKey()};oa.prototype.computeSecret=function(e){e=new Qi(e),e=e.toRed(this._prime);var t=e.redPow(this._priv).fromRed(),r=new Buffer(t.toArray()),n=this.getPrime();if(r.length{var uge=qS(),fP=iP(),GS=AP();function cge(e){var t=new Buffer(fP[e].prime,"hex"),r=new Buffer(fP[e].gen,"hex");return new GS(t,r)}var lge={binary:!0,hex:!0,base64:!0};function uP(e,t,r,n){return Buffer.isBuffer(t)||lge[t]===void 0?uP(e,"binary",t,r):(t=t||"binary",n=n||"binary",r=r||new Buffer([2]),Buffer.isBuffer(r)||(r=new Buffer(r,n)),typeof e=="number"?new GS(uge(e,r),r,!0):(Buffer.isBuffer(e)||(e=new Buffer(e,t)),new GS(e,r,!0)))}Hc.DiffieHellmanGroup=Hc.createDiffieHellmanGroup=Hc.getDiffieHellman=cge;Hc.createDiffieHellman=Hc.DiffieHellman=uP});var _y=x((lP,YS)=>{(function(e,t){"use strict";function r(b,c){if(!b)throw new Error(c||"Assertion failed")}function n(b,c){b.super_=c;var g=function(){};g.prototype=c.prototype,b.prototype=new g,b.prototype.constructor=b}function i(b,c,g){if(i.isBN(b))return b;this.negative=0,this.words=null,this.length=0,this.red=null,b!==null&&((c==="le"||c==="be")&&(g=c,c=10),this._init(b||0,c||10,g||"be"))}typeof e=="object"?e.exports=i:t.BN=i,i.BN=i,i.wordSize=26;var s;try{typeof window<"u"&&typeof window.Buffer<"u"?s=window.Buffer:s=Gr().Buffer}catch{}i.isBN=function(c){return c instanceof i?!0:c!==null&&typeof c=="object"&&c.constructor.wordSize===i.wordSize&&Array.isArray(c.words)},i.max=function(c,g){return c.cmp(g)>0?c:g},i.min=function(c,g){return c.cmp(g)<0?c:g},i.prototype._init=function(c,g,w){if(typeof c=="number")return this._initNumber(c,g,w);if(typeof c=="object")return this._initArray(c,g,w);g==="hex"&&(g=16),r(g===(g|0)&&g>=2&&g<=36),c=c.toString().replace(/\s+/g,"");var R=0;c[0]==="-"&&(R++,this.negative=1),R=0;R-=3)h=c[R]|c[R-1]<<8|c[R-2]<<16,this.words[C]|=h<>>26-D&67108863,D+=24,D>=26&&(D-=26,C++);else if(w==="le")for(R=0,C=0;R>>26-D&67108863,D+=24,D>=26&&(D-=26,C++);return this._strip()};function o(b,c){var g=b.charCodeAt(c);if(g>=48&&g<=57)return g-48;if(g>=65&&g<=70)return g-55;if(g>=97&&g<=102)return g-87;r(!1,"Invalid character in "+b)}function a(b,c,g){var w=o(b,g);return g-1>=c&&(w|=o(b,g-1)<<4),w}i.prototype._parseHex=function(c,g,w){this.length=Math.ceil((c.length-g)/6),this.words=new Array(this.length);for(var R=0;R=g;R-=2)D=a(c,g,R)<=18?(C-=18,h+=1,this.words[h]|=D>>>26):C+=8;else{var M=c.length-g;for(R=M%2===0?g+1:g;R=18?(C-=18,h+=1,this.words[h]|=D>>>26):C+=8}this._strip()};function A(b,c,g,w){for(var R=0,C=0,h=Math.min(b.length,g),D=c;D=49?C=M-49+10:M>=17?C=M-17+10:C=M,r(M>=0&&C1&&this.words[this.length-1]===0;)this.length--;return this._normSign()},i.prototype._normSign=function(){return this.length===1&&this.words[0]===0&&(this.negative=0),this},typeof Symbol<"u"&&typeof Symbol.for=="function")try{i.prototype[Symbol.for("nodejs.util.inspect.custom")]=l}catch{i.prototype.inspect=l}else i.prototype.inspect=l;function l(){return(this.red?""}var p=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],B=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],S=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];i.prototype.toString=function(c,g){c=c||10,g=g|0||1;var w;if(c===16||c==="hex"){w="";for(var R=0,C=0,h=0;h>>24-R&16777215,R+=2,R>=26&&(R-=26,h--),C!==0||h!==this.length-1?w=p[6-M.length]+M+w:w=M+w}for(C!==0&&(w=C.toString(16)+w);w.length%g!==0;)w="0"+w;return this.negative!==0&&(w="-"+w),w}if(c===(c|0)&&c>=2&&c<=36){var I=B[c],k=S[c];w="";var ne=this.clone();for(ne.negative=0;!ne.isZero();){var Ae=ne.modrn(k).toString(c);ne=ne.idivn(k),ne.isZero()?w=Ae+w:w=p[I-Ae.length]+Ae+w}for(this.isZero()&&(w="0"+w);w.length%g!==0;)w="0"+w;return this.negative!==0&&(w="-"+w),w}r(!1,"Base should be between 2 and 36")},i.prototype.toNumber=function(){var c=this.words[0];return this.length===2?c+=this.words[1]*67108864:this.length===3&&this.words[2]===1?c+=4503599627370496+this.words[1]*67108864:this.length>2&&r(!1,"Number can only safely store up to 53 bits"),this.negative!==0?-c:c},i.prototype.toJSON=function(){return this.toString(16,2)},s&&(i.prototype.toBuffer=function(c,g){return this.toArrayLike(s,c,g)}),i.prototype.toArray=function(c,g){return this.toArrayLike(Array,c,g)};var _=function(c,g){return c.allocUnsafe?c.allocUnsafe(g):new c(g)};i.prototype.toArrayLike=function(c,g,w){this._strip();var R=this.byteLength(),C=w||Math.max(1,R);r(R<=C,"byte array longer than desired length"),r(C>0,"Requested array length <= 0");var h=_(c,C),D=g==="le"?"LE":"BE";return this["_toArrayLike"+D](h,R),h},i.prototype._toArrayLikeLE=function(c,g){for(var w=0,R=0,C=0,h=0;C>8&255),w>16&255),h===6?(w>24&255),R=0,h=0):(R=D>>>24,h+=2)}if(w=0&&(c[w--]=D>>8&255),w>=0&&(c[w--]=D>>16&255),h===6?(w>=0&&(c[w--]=D>>24&255),R=0,h=0):(R=D>>>24,h+=2)}if(w>=0)for(c[w--]=R;w>=0;)c[w--]=0},Math.clz32?i.prototype._countBits=function(c){return 32-Math.clz32(c)}:i.prototype._countBits=function(c){var g=c,w=0;return g>=4096&&(w+=13,g>>>=13),g>=64&&(w+=7,g>>>=7),g>=8&&(w+=4,g>>>=4),g>=2&&(w+=2,g>>>=2),w+g},i.prototype._zeroBits=function(c){if(c===0)return 26;var g=c,w=0;return(g&8191)===0&&(w+=13,g>>>=13),(g&127)===0&&(w+=7,g>>>=7),(g&15)===0&&(w+=4,g>>>=4),(g&3)===0&&(w+=2,g>>>=2),(g&1)===0&&w++,w},i.prototype.bitLength=function(){var c=this.words[this.length-1],g=this._countBits(c);return(this.length-1)*26+g};function N(b){for(var c=new Array(b.bitLength()),g=0;g>>R&1}return c}i.prototype.zeroBits=function(){if(this.isZero())return 0;for(var c=0,g=0;gc.length?this.clone().ior(c):c.clone().ior(this)},i.prototype.uor=function(c){return this.length>c.length?this.clone().iuor(c):c.clone().iuor(this)},i.prototype.iuand=function(c){var g;this.length>c.length?g=c:g=this;for(var w=0;wc.length?this.clone().iand(c):c.clone().iand(this)},i.prototype.uand=function(c){return this.length>c.length?this.clone().iuand(c):c.clone().iuand(this)},i.prototype.iuxor=function(c){var g,w;this.length>c.length?(g=this,w=c):(g=c,w=this);for(var R=0;Rc.length?this.clone().ixor(c):c.clone().ixor(this)},i.prototype.uxor=function(c){return this.length>c.length?this.clone().iuxor(c):c.clone().iuxor(this)},i.prototype.inotn=function(c){r(typeof c=="number"&&c>=0);var g=Math.ceil(c/26)|0,w=c%26;this._expand(g),w>0&&g--;for(var R=0;R0&&(this.words[R]=~this.words[R]&67108863>>26-w),this._strip()},i.prototype.notn=function(c){return this.clone().inotn(c)},i.prototype.setn=function(c,g){r(typeof c=="number"&&c>=0);var w=c/26|0,R=c%26;return this._expand(w+1),g?this.words[w]=this.words[w]|1<c.length?(w=this,R=c):(w=c,R=this);for(var C=0,h=0;h>>26;for(;C!==0&&h>>26;if(this.length=w.length,C!==0)this.words[this.length]=C,this.length++;else if(w!==this)for(;hc.length?this.clone().iadd(c):c.clone().iadd(this)},i.prototype.isub=function(c){if(c.negative!==0){c.negative=0;var g=this.iadd(c);return c.negative=1,g._normSign()}else if(this.negative!==0)return this.negative=0,this.iadd(c),this.negative=1,this._normSign();var w=this.cmp(c);if(w===0)return this.negative=0,this.length=1,this.words[0]=0,this;var R,C;w>0?(R=this,C=c):(R=c,C=this);for(var h=0,D=0;D>26,this.words[D]=g&67108863;for(;h!==0&&D>26,this.words[D]=g&67108863;if(h===0&&D>>26,ne=M&67108863,Ae=Math.min(I,c.length-1),ue=Math.max(0,I-b.length+1);ue<=Ae;ue++){var pe=I-ue|0;R=b.words[pe]|0,C=c.words[ue]|0,h=R*C+ne,k+=h/67108864|0,ne=h&67108863}g.words[I]=ne|0,M=k|0}return M!==0?g.words[I]=M|0:g.length--,g._strip()}var U=function(c,g,w){var R=c.words,C=g.words,h=w.words,D=0,M,I,k,ne=R[0]|0,Ae=ne&8191,ue=ne>>>13,pe=R[1]|0,he=pe&8191,de=pe>>>13,wt=R[2]|0,Ie=wt&8191,be=wt>>>13,yr=R[3]|0,we=yr&8191,ve=yr>>>13,Ms=R[4]|0,Ye=Ms&8191,xe=Ms>>>13,Fs=R[5]|0,Te=Fs&8191,De=Fs>>>13,en=R[6]|0,Re=en&8191,He=en>>>13,ai=R[7]|0,Ne=ai&8191,Je=ai>>>13,F=R[8]|0,m=F&8191,Q=F>>>13,L=R[9]|0,W=L&8191,z=L>>>13,ae=C[0]|0,le=ae&8191,ye=ae>>>13,Ct=C[1]|0,Ee=Ct&8191,ge=Ct>>>13,Ua=C[2]|0,je=Ua&8191,tt=Ua>>>13,Fo=C[3]|0,$e=Fo&8191,rt=Fo>>>13,GA=C[4]|0,nt=GA&8191,it=GA>>>13,La=C[5]|0,Ke=La&8191,Xe=La>>>13,YA=C[6]|0,Ue=YA&8191,et=YA>>>13,WA=C[7]|0,st=WA&8191,Le=WA>>>13,hn=C[8]|0,Pe=hn&8191,Ze=hn>>>13,wn=C[9]|0,Pt=wn&8191,kt=wn>>>13;w.negative=c.negative^g.negative,w.length=19,M=Math.imul(Ae,le),I=Math.imul(Ae,ye),I=I+Math.imul(ue,le)|0,k=Math.imul(ue,ye);var ks=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(ks>>>26)|0,ks&=67108863,M=Math.imul(he,le),I=Math.imul(he,ye),I=I+Math.imul(de,le)|0,k=Math.imul(de,ye),M=M+Math.imul(Ae,Ee)|0,I=I+Math.imul(Ae,ge)|0,I=I+Math.imul(ue,Ee)|0,k=k+Math.imul(ue,ge)|0;var Ai=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Ai>>>26)|0,Ai&=67108863,M=Math.imul(Ie,le),I=Math.imul(Ie,ye),I=I+Math.imul(be,le)|0,k=Math.imul(be,ye),M=M+Math.imul(he,Ee)|0,I=I+Math.imul(he,ge)|0,I=I+Math.imul(de,Ee)|0,k=k+Math.imul(de,ge)|0,M=M+Math.imul(Ae,je)|0,I=I+Math.imul(Ae,tt)|0,I=I+Math.imul(ue,je)|0,k=k+Math.imul(ue,tt)|0;var xs=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(xs>>>26)|0,xs&=67108863,M=Math.imul(we,le),I=Math.imul(we,ye),I=I+Math.imul(ve,le)|0,k=Math.imul(ve,ye),M=M+Math.imul(Ie,Ee)|0,I=I+Math.imul(Ie,ge)|0,I=I+Math.imul(be,Ee)|0,k=k+Math.imul(be,ge)|0,M=M+Math.imul(he,je)|0,I=I+Math.imul(he,tt)|0,I=I+Math.imul(de,je)|0,k=k+Math.imul(de,tt)|0,M=M+Math.imul(Ae,$e)|0,I=I+Math.imul(Ae,rt)|0,I=I+Math.imul(ue,$e)|0,k=k+Math.imul(ue,rt)|0;var Us=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Us>>>26)|0,Us&=67108863,M=Math.imul(Ye,le),I=Math.imul(Ye,ye),I=I+Math.imul(xe,le)|0,k=Math.imul(xe,ye),M=M+Math.imul(we,Ee)|0,I=I+Math.imul(we,ge)|0,I=I+Math.imul(ve,Ee)|0,k=k+Math.imul(ve,ge)|0,M=M+Math.imul(Ie,je)|0,I=I+Math.imul(Ie,tt)|0,I=I+Math.imul(be,je)|0,k=k+Math.imul(be,tt)|0,M=M+Math.imul(he,$e)|0,I=I+Math.imul(he,rt)|0,I=I+Math.imul(de,$e)|0,k=k+Math.imul(de,rt)|0,M=M+Math.imul(Ae,nt)|0,I=I+Math.imul(Ae,it)|0,I=I+Math.imul(ue,nt)|0,k=k+Math.imul(ue,it)|0;var Ls=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Ls>>>26)|0,Ls&=67108863,M=Math.imul(Te,le),I=Math.imul(Te,ye),I=I+Math.imul(De,le)|0,k=Math.imul(De,ye),M=M+Math.imul(Ye,Ee)|0,I=I+Math.imul(Ye,ge)|0,I=I+Math.imul(xe,Ee)|0,k=k+Math.imul(xe,ge)|0,M=M+Math.imul(we,je)|0,I=I+Math.imul(we,tt)|0,I=I+Math.imul(ve,je)|0,k=k+Math.imul(ve,tt)|0,M=M+Math.imul(Ie,$e)|0,I=I+Math.imul(Ie,rt)|0,I=I+Math.imul(be,$e)|0,k=k+Math.imul(be,rt)|0,M=M+Math.imul(he,nt)|0,I=I+Math.imul(he,it)|0,I=I+Math.imul(de,nt)|0,k=k+Math.imul(de,it)|0,M=M+Math.imul(Ae,Ke)|0,I=I+Math.imul(Ae,Xe)|0,I=I+Math.imul(ue,Ke)|0,k=k+Math.imul(ue,Xe)|0;var Ps=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Ps>>>26)|0,Ps&=67108863,M=Math.imul(Re,le),I=Math.imul(Re,ye),I=I+Math.imul(He,le)|0,k=Math.imul(He,ye),M=M+Math.imul(Te,Ee)|0,I=I+Math.imul(Te,ge)|0,I=I+Math.imul(De,Ee)|0,k=k+Math.imul(De,ge)|0,M=M+Math.imul(Ye,je)|0,I=I+Math.imul(Ye,tt)|0,I=I+Math.imul(xe,je)|0,k=k+Math.imul(xe,tt)|0,M=M+Math.imul(we,$e)|0,I=I+Math.imul(we,rt)|0,I=I+Math.imul(ve,$e)|0,k=k+Math.imul(ve,rt)|0,M=M+Math.imul(Ie,nt)|0,I=I+Math.imul(Ie,it)|0,I=I+Math.imul(be,nt)|0,k=k+Math.imul(be,it)|0,M=M+Math.imul(he,Ke)|0,I=I+Math.imul(he,Xe)|0,I=I+Math.imul(de,Ke)|0,k=k+Math.imul(de,Xe)|0,M=M+Math.imul(Ae,Ue)|0,I=I+Math.imul(Ae,et)|0,I=I+Math.imul(ue,Ue)|0,k=k+Math.imul(ue,et)|0;var Os=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Os>>>26)|0,Os&=67108863,M=Math.imul(Ne,le),I=Math.imul(Ne,ye),I=I+Math.imul(Je,le)|0,k=Math.imul(Je,ye),M=M+Math.imul(Re,Ee)|0,I=I+Math.imul(Re,ge)|0,I=I+Math.imul(He,Ee)|0,k=k+Math.imul(He,ge)|0,M=M+Math.imul(Te,je)|0,I=I+Math.imul(Te,tt)|0,I=I+Math.imul(De,je)|0,k=k+Math.imul(De,tt)|0,M=M+Math.imul(Ye,$e)|0,I=I+Math.imul(Ye,rt)|0,I=I+Math.imul(xe,$e)|0,k=k+Math.imul(xe,rt)|0,M=M+Math.imul(we,nt)|0,I=I+Math.imul(we,it)|0,I=I+Math.imul(ve,nt)|0,k=k+Math.imul(ve,it)|0,M=M+Math.imul(Ie,Ke)|0,I=I+Math.imul(Ie,Xe)|0,I=I+Math.imul(be,Ke)|0,k=k+Math.imul(be,Xe)|0,M=M+Math.imul(he,Ue)|0,I=I+Math.imul(he,et)|0,I=I+Math.imul(de,Ue)|0,k=k+Math.imul(de,et)|0,M=M+Math.imul(Ae,st)|0,I=I+Math.imul(Ae,Le)|0,I=I+Math.imul(ue,st)|0,k=k+Math.imul(ue,Le)|0;var Ji=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Ji>>>26)|0,Ji&=67108863,M=Math.imul(m,le),I=Math.imul(m,ye),I=I+Math.imul(Q,le)|0,k=Math.imul(Q,ye),M=M+Math.imul(Ne,Ee)|0,I=I+Math.imul(Ne,ge)|0,I=I+Math.imul(Je,Ee)|0,k=k+Math.imul(Je,ge)|0,M=M+Math.imul(Re,je)|0,I=I+Math.imul(Re,tt)|0,I=I+Math.imul(He,je)|0,k=k+Math.imul(He,tt)|0,M=M+Math.imul(Te,$e)|0,I=I+Math.imul(Te,rt)|0,I=I+Math.imul(De,$e)|0,k=k+Math.imul(De,rt)|0,M=M+Math.imul(Ye,nt)|0,I=I+Math.imul(Ye,it)|0,I=I+Math.imul(xe,nt)|0,k=k+Math.imul(xe,it)|0,M=M+Math.imul(we,Ke)|0,I=I+Math.imul(we,Xe)|0,I=I+Math.imul(ve,Ke)|0,k=k+Math.imul(ve,Xe)|0,M=M+Math.imul(Ie,Ue)|0,I=I+Math.imul(Ie,et)|0,I=I+Math.imul(be,Ue)|0,k=k+Math.imul(be,et)|0,M=M+Math.imul(he,st)|0,I=I+Math.imul(he,Le)|0,I=I+Math.imul(de,st)|0,k=k+Math.imul(de,Le)|0,M=M+Math.imul(Ae,Pe)|0,I=I+Math.imul(Ae,Ze)|0,I=I+Math.imul(ue,Pe)|0,k=k+Math.imul(ue,Ze)|0;var ji=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(ji>>>26)|0,ji&=67108863,M=Math.imul(W,le),I=Math.imul(W,ye),I=I+Math.imul(z,le)|0,k=Math.imul(z,ye),M=M+Math.imul(m,Ee)|0,I=I+Math.imul(m,ge)|0,I=I+Math.imul(Q,Ee)|0,k=k+Math.imul(Q,ge)|0,M=M+Math.imul(Ne,je)|0,I=I+Math.imul(Ne,tt)|0,I=I+Math.imul(Je,je)|0,k=k+Math.imul(Je,tt)|0,M=M+Math.imul(Re,$e)|0,I=I+Math.imul(Re,rt)|0,I=I+Math.imul(He,$e)|0,k=k+Math.imul(He,rt)|0,M=M+Math.imul(Te,nt)|0,I=I+Math.imul(Te,it)|0,I=I+Math.imul(De,nt)|0,k=k+Math.imul(De,it)|0,M=M+Math.imul(Ye,Ke)|0,I=I+Math.imul(Ye,Xe)|0,I=I+Math.imul(xe,Ke)|0,k=k+Math.imul(xe,Xe)|0,M=M+Math.imul(we,Ue)|0,I=I+Math.imul(we,et)|0,I=I+Math.imul(ve,Ue)|0,k=k+Math.imul(ve,et)|0,M=M+Math.imul(Ie,st)|0,I=I+Math.imul(Ie,Le)|0,I=I+Math.imul(be,st)|0,k=k+Math.imul(be,Le)|0,M=M+Math.imul(he,Pe)|0,I=I+Math.imul(he,Ze)|0,I=I+Math.imul(de,Pe)|0,k=k+Math.imul(de,Ze)|0,M=M+Math.imul(Ae,Pt)|0,I=I+Math.imul(Ae,kt)|0,I=I+Math.imul(ue,Pt)|0,k=k+Math.imul(ue,kt)|0;var ko=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(ko>>>26)|0,ko&=67108863,M=Math.imul(W,Ee),I=Math.imul(W,ge),I=I+Math.imul(z,Ee)|0,k=Math.imul(z,ge),M=M+Math.imul(m,je)|0,I=I+Math.imul(m,tt)|0,I=I+Math.imul(Q,je)|0,k=k+Math.imul(Q,tt)|0,M=M+Math.imul(Ne,$e)|0,I=I+Math.imul(Ne,rt)|0,I=I+Math.imul(Je,$e)|0,k=k+Math.imul(Je,rt)|0,M=M+Math.imul(Re,nt)|0,I=I+Math.imul(Re,it)|0,I=I+Math.imul(He,nt)|0,k=k+Math.imul(He,it)|0,M=M+Math.imul(Te,Ke)|0,I=I+Math.imul(Te,Xe)|0,I=I+Math.imul(De,Ke)|0,k=k+Math.imul(De,Xe)|0,M=M+Math.imul(Ye,Ue)|0,I=I+Math.imul(Ye,et)|0,I=I+Math.imul(xe,Ue)|0,k=k+Math.imul(xe,et)|0,M=M+Math.imul(we,st)|0,I=I+Math.imul(we,Le)|0,I=I+Math.imul(ve,st)|0,k=k+Math.imul(ve,Le)|0,M=M+Math.imul(Ie,Pe)|0,I=I+Math.imul(Ie,Ze)|0,I=I+Math.imul(be,Pe)|0,k=k+Math.imul(be,Ze)|0,M=M+Math.imul(he,Pt)|0,I=I+Math.imul(he,kt)|0,I=I+Math.imul(de,Pt)|0,k=k+Math.imul(de,kt)|0;var xo=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(xo>>>26)|0,xo&=67108863,M=Math.imul(W,je),I=Math.imul(W,tt),I=I+Math.imul(z,je)|0,k=Math.imul(z,tt),M=M+Math.imul(m,$e)|0,I=I+Math.imul(m,rt)|0,I=I+Math.imul(Q,$e)|0,k=k+Math.imul(Q,rt)|0,M=M+Math.imul(Ne,nt)|0,I=I+Math.imul(Ne,it)|0,I=I+Math.imul(Je,nt)|0,k=k+Math.imul(Je,it)|0,M=M+Math.imul(Re,Ke)|0,I=I+Math.imul(Re,Xe)|0,I=I+Math.imul(He,Ke)|0,k=k+Math.imul(He,Xe)|0,M=M+Math.imul(Te,Ue)|0,I=I+Math.imul(Te,et)|0,I=I+Math.imul(De,Ue)|0,k=k+Math.imul(De,et)|0,M=M+Math.imul(Ye,st)|0,I=I+Math.imul(Ye,Le)|0,I=I+Math.imul(xe,st)|0,k=k+Math.imul(xe,Le)|0,M=M+Math.imul(we,Pe)|0,I=I+Math.imul(we,Ze)|0,I=I+Math.imul(ve,Pe)|0,k=k+Math.imul(ve,Ze)|0,M=M+Math.imul(Ie,Pt)|0,I=I+Math.imul(Ie,kt)|0,I=I+Math.imul(be,Pt)|0,k=k+Math.imul(be,kt)|0;var Uo=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Uo>>>26)|0,Uo&=67108863,M=Math.imul(W,$e),I=Math.imul(W,rt),I=I+Math.imul(z,$e)|0,k=Math.imul(z,rt),M=M+Math.imul(m,nt)|0,I=I+Math.imul(m,it)|0,I=I+Math.imul(Q,nt)|0,k=k+Math.imul(Q,it)|0,M=M+Math.imul(Ne,Ke)|0,I=I+Math.imul(Ne,Xe)|0,I=I+Math.imul(Je,Ke)|0,k=k+Math.imul(Je,Xe)|0,M=M+Math.imul(Re,Ue)|0,I=I+Math.imul(Re,et)|0,I=I+Math.imul(He,Ue)|0,k=k+Math.imul(He,et)|0,M=M+Math.imul(Te,st)|0,I=I+Math.imul(Te,Le)|0,I=I+Math.imul(De,st)|0,k=k+Math.imul(De,Le)|0,M=M+Math.imul(Ye,Pe)|0,I=I+Math.imul(Ye,Ze)|0,I=I+Math.imul(xe,Pe)|0,k=k+Math.imul(xe,Ze)|0,M=M+Math.imul(we,Pt)|0,I=I+Math.imul(we,kt)|0,I=I+Math.imul(ve,Pt)|0,k=k+Math.imul(ve,kt)|0;var Lo=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Lo>>>26)|0,Lo&=67108863,M=Math.imul(W,nt),I=Math.imul(W,it),I=I+Math.imul(z,nt)|0,k=Math.imul(z,it),M=M+Math.imul(m,Ke)|0,I=I+Math.imul(m,Xe)|0,I=I+Math.imul(Q,Ke)|0,k=k+Math.imul(Q,Xe)|0,M=M+Math.imul(Ne,Ue)|0,I=I+Math.imul(Ne,et)|0,I=I+Math.imul(Je,Ue)|0,k=k+Math.imul(Je,et)|0,M=M+Math.imul(Re,st)|0,I=I+Math.imul(Re,Le)|0,I=I+Math.imul(He,st)|0,k=k+Math.imul(He,Le)|0,M=M+Math.imul(Te,Pe)|0,I=I+Math.imul(Te,Ze)|0,I=I+Math.imul(De,Pe)|0,k=k+Math.imul(De,Ze)|0,M=M+Math.imul(Ye,Pt)|0,I=I+Math.imul(Ye,kt)|0,I=I+Math.imul(xe,Pt)|0,k=k+Math.imul(xe,kt)|0;var Hs=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Hs>>>26)|0,Hs&=67108863,M=Math.imul(W,Ke),I=Math.imul(W,Xe),I=I+Math.imul(z,Ke)|0,k=Math.imul(z,Xe),M=M+Math.imul(m,Ue)|0,I=I+Math.imul(m,et)|0,I=I+Math.imul(Q,Ue)|0,k=k+Math.imul(Q,et)|0,M=M+Math.imul(Ne,st)|0,I=I+Math.imul(Ne,Le)|0,I=I+Math.imul(Je,st)|0,k=k+Math.imul(Je,Le)|0,M=M+Math.imul(Re,Pe)|0,I=I+Math.imul(Re,Ze)|0,I=I+Math.imul(He,Pe)|0,k=k+Math.imul(He,Ze)|0,M=M+Math.imul(Te,Pt)|0,I=I+Math.imul(Te,kt)|0,I=I+Math.imul(De,Pt)|0,k=k+Math.imul(De,kt)|0;var Sn=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Sn>>>26)|0,Sn&=67108863,M=Math.imul(W,Ue),I=Math.imul(W,et),I=I+Math.imul(z,Ue)|0,k=Math.imul(z,et),M=M+Math.imul(m,st)|0,I=I+Math.imul(m,Le)|0,I=I+Math.imul(Q,st)|0,k=k+Math.imul(Q,Le)|0,M=M+Math.imul(Ne,Pe)|0,I=I+Math.imul(Ne,Ze)|0,I=I+Math.imul(Je,Pe)|0,k=k+Math.imul(Je,Ze)|0,M=M+Math.imul(Re,Pt)|0,I=I+Math.imul(Re,kt)|0,I=I+Math.imul(He,Pt)|0,k=k+Math.imul(He,kt)|0;var Po=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Po>>>26)|0,Po&=67108863,M=Math.imul(W,st),I=Math.imul(W,Le),I=I+Math.imul(z,st)|0,k=Math.imul(z,Le),M=M+Math.imul(m,Pe)|0,I=I+Math.imul(m,Ze)|0,I=I+Math.imul(Q,Pe)|0,k=k+Math.imul(Q,Ze)|0,M=M+Math.imul(Ne,Pt)|0,I=I+Math.imul(Ne,kt)|0,I=I+Math.imul(Je,Pt)|0,k=k+Math.imul(Je,kt)|0;var Pa=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Pa>>>26)|0,Pa&=67108863,M=Math.imul(W,Pe),I=Math.imul(W,Ze),I=I+Math.imul(z,Pe)|0,k=Math.imul(z,Ze),M=M+Math.imul(m,Pt)|0,I=I+Math.imul(m,kt)|0,I=I+Math.imul(Q,Pt)|0,k=k+Math.imul(Q,kt)|0;var Oo=(D+M|0)+((I&8191)<<13)|0;D=(k+(I>>>13)|0)+(Oo>>>26)|0,Oo&=67108863,M=Math.imul(W,Pt),I=Math.imul(W,kt),I=I+Math.imul(z,Pt)|0,k=Math.imul(z,kt);var Oa=(D+M|0)+((I&8191)<<13)|0;return D=(k+(I>>>13)|0)+(Oa>>>26)|0,Oa&=67108863,h[0]=ks,h[1]=Ai,h[2]=xs,h[3]=Us,h[4]=Ls,h[5]=Ps,h[6]=Os,h[7]=Ji,h[8]=ji,h[9]=ko,h[10]=xo,h[11]=Uo,h[12]=Lo,h[13]=Hs,h[14]=Sn,h[15]=Po,h[16]=Pa,h[17]=Oo,h[18]=Oa,D!==0&&(h[19]=D,w.length++),w};Math.imul||(U=P);function G(b,c,g){g.negative=c.negative^b.negative,g.length=b.length+c.length;for(var w=0,R=0,C=0;C>>26)|0,R+=h>>>26,h&=67108863}g.words[C]=D,w=h,h=R}return w!==0?g.words[C]=w:g.length--,g._strip()}function Y(b,c,g){return G(b,c,g)}i.prototype.mulTo=function(c,g){var w,R=this.length+c.length;return this.length===10&&c.length===10?w=U(this,c,g):R<63?w=P(this,c,g):R<1024?w=G(this,c,g):w=Y(this,c,g),w};function Z(b,c){this.x=b,this.y=c}Z.prototype.makeRBT=function(c){for(var g=new Array(c),w=i.prototype._countBits(c)-1,R=0;R>=1;return R},Z.prototype.permute=function(c,g,w,R,C,h){for(var D=0;D>>1)C++;return 1<>>13,w[2*h+1]=C&8191,C=C>>>13;for(h=2*g;h>=26,w+=C/67108864|0,w+=h>>>26,this.words[R]=h&67108863}return w!==0&&(this.words[R]=w,this.length++),this.length=c===0?1:this.length,g?this.ineg():this},i.prototype.muln=function(c){return this.clone().imuln(c)},i.prototype.sqr=function(){return this.mul(this)},i.prototype.isqr=function(){return this.imul(this.clone())},i.prototype.pow=function(c){var g=N(c);if(g.length===0)return new i(1);for(var w=this,R=0;R=0);var g=c%26,w=(c-g)/26,R=67108863>>>26-g<<26-g,C;if(g!==0){var h=0;for(C=0;C>>26-g}h&&(this.words[C]=h,this.length++)}if(w!==0){for(C=this.length-1;C>=0;C--)this.words[C+w]=this.words[C];for(C=0;C=0);var R;g?R=(g-g%26)/26:R=0;var C=c%26,h=Math.min((c-C)/26,this.length),D=67108863^67108863>>>C<h)for(this.length-=h,I=0;I=0&&(k!==0||I>=R);I--){var ne=this.words[I]|0;this.words[I]=k<<26-C|ne>>>C,k=ne&D}return M&&k!==0&&(M.words[M.length++]=k),this.length===0&&(this.words[0]=0,this.length=1),this._strip()},i.prototype.ishrn=function(c,g,w){return r(this.negative===0),this.iushrn(c,g,w)},i.prototype.shln=function(c){return this.clone().ishln(c)},i.prototype.ushln=function(c){return this.clone().iushln(c)},i.prototype.shrn=function(c){return this.clone().ishrn(c)},i.prototype.ushrn=function(c){return this.clone().iushrn(c)},i.prototype.testn=function(c){r(typeof c=="number"&&c>=0);var g=c%26,w=(c-g)/26,R=1<=0);var g=c%26,w=(c-g)/26;if(r(this.negative===0,"imaskn works only with positive numbers"),this.length<=w)return this;if(g!==0&&w++,this.length=Math.min(w,this.length),g!==0){var R=67108863^67108863>>>g<=67108864;g++)this.words[g]-=67108864,g===this.length-1?this.words[g+1]=1:this.words[g+1]++;return this.length=Math.max(this.length,g+1),this},i.prototype.isubn=function(c){if(r(typeof c=="number"),r(c<67108864),c<0)return this.iaddn(-c);if(this.negative!==0)return this.negative=0,this.iaddn(c),this.negative=1,this;if(this.words[0]-=c,this.length===1&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var g=0;g>26)-(M/67108864|0),this.words[C+w]=h&67108863}for(;C>26,this.words[C+w]=h&67108863;if(D===0)return this._strip();for(r(D===-1),D=0,C=0;C>26,this.words[C]=h&67108863;return this.negative=1,this._strip()},i.prototype._wordDiv=function(c,g){var w=this.length-c.length,R=this.clone(),C=c,h=C.words[C.length-1]|0,D=this._countBits(h);w=26-D,w!==0&&(C=C.ushln(w),R.iushln(w),h=C.words[C.length-1]|0);var M=R.length-C.length,I;if(g!=="mod"){I=new i(null),I.length=M+1,I.words=new Array(I.length);for(var k=0;k=0;Ae--){var ue=(R.words[C.length+Ae]|0)*67108864+(R.words[C.length+Ae-1]|0);for(ue=Math.min(ue/h|0,67108863),R._ishlnsubmul(C,ue,Ae);R.negative!==0;)ue--,R.negative=0,R._ishlnsubmul(C,1,Ae),R.isZero()||(R.negative^=1);I&&(I.words[Ae]=ue)}return I&&I._strip(),R._strip(),g!=="div"&&w!==0&&R.iushrn(w),{div:I||null,mod:R}},i.prototype.divmod=function(c,g,w){if(r(!c.isZero()),this.isZero())return{div:new i(0),mod:new i(0)};var R,C,h;return this.negative!==0&&c.negative===0?(h=this.neg().divmod(c,g),g!=="mod"&&(R=h.div.neg()),g!=="div"&&(C=h.mod.neg(),w&&C.negative!==0&&C.iadd(c)),{div:R,mod:C}):this.negative===0&&c.negative!==0?(h=this.divmod(c.neg(),g),g!=="mod"&&(R=h.div.neg()),{div:R,mod:h.mod}):(this.negative&c.negative)!==0?(h=this.neg().divmod(c.neg(),g),g!=="div"&&(C=h.mod.neg(),w&&C.negative!==0&&C.isub(c)),{div:h.div,mod:C}):c.length>this.length||this.cmp(c)<0?{div:new i(0),mod:this}:c.length===1?g==="div"?{div:this.divn(c.words[0]),mod:null}:g==="mod"?{div:null,mod:new i(this.modrn(c.words[0]))}:{div:this.divn(c.words[0]),mod:new i(this.modrn(c.words[0]))}:this._wordDiv(c,g)},i.prototype.div=function(c){return this.divmod(c,"div",!1).div},i.prototype.mod=function(c){return this.divmod(c,"mod",!1).mod},i.prototype.umod=function(c){return this.divmod(c,"mod",!0).mod},i.prototype.divRound=function(c){var g=this.divmod(c);if(g.mod.isZero())return g.div;var w=g.div.negative!==0?g.mod.isub(c):g.mod,R=c.ushrn(1),C=c.andln(1),h=w.cmp(R);return h<0||C===1&&h===0?g.div:g.div.negative!==0?g.div.isubn(1):g.div.iaddn(1)},i.prototype.modrn=function(c){var g=c<0;g&&(c=-c),r(c<=67108863);for(var w=(1<<26)%c,R=0,C=this.length-1;C>=0;C--)R=(w*R+(this.words[C]|0))%c;return g?-R:R},i.prototype.modn=function(c){return this.modrn(c)},i.prototype.idivn=function(c){var g=c<0;g&&(c=-c),r(c<=67108863);for(var w=0,R=this.length-1;R>=0;R--){var C=(this.words[R]|0)+w*67108864;this.words[R]=C/c|0,w=C%c}return this._strip(),g?this.ineg():this},i.prototype.divn=function(c){return this.clone().idivn(c)},i.prototype.egcd=function(c){r(c.negative===0),r(!c.isZero());var g=this,w=c.clone();g.negative!==0?g=g.umod(c):g=g.clone();for(var R=new i(1),C=new i(0),h=new i(0),D=new i(1),M=0;g.isEven()&&w.isEven();)g.iushrn(1),w.iushrn(1),++M;for(var I=w.clone(),k=g.clone();!g.isZero();){for(var ne=0,Ae=1;(g.words[0]&Ae)===0&&ne<26;++ne,Ae<<=1);if(ne>0)for(g.iushrn(ne);ne-- >0;)(R.isOdd()||C.isOdd())&&(R.iadd(I),C.isub(k)),R.iushrn(1),C.iushrn(1);for(var ue=0,pe=1;(w.words[0]&pe)===0&&ue<26;++ue,pe<<=1);if(ue>0)for(w.iushrn(ue);ue-- >0;)(h.isOdd()||D.isOdd())&&(h.iadd(I),D.isub(k)),h.iushrn(1),D.iushrn(1);g.cmp(w)>=0?(g.isub(w),R.isub(h),C.isub(D)):(w.isub(g),h.isub(R),D.isub(C))}return{a:h,b:D,gcd:w.iushln(M)}},i.prototype._invmp=function(c){r(c.negative===0),r(!c.isZero());var g=this,w=c.clone();g.negative!==0?g=g.umod(c):g=g.clone();for(var R=new i(1),C=new i(0),h=w.clone();g.cmpn(1)>0&&w.cmpn(1)>0;){for(var D=0,M=1;(g.words[0]&M)===0&&D<26;++D,M<<=1);if(D>0)for(g.iushrn(D);D-- >0;)R.isOdd()&&R.iadd(h),R.iushrn(1);for(var I=0,k=1;(w.words[0]&k)===0&&I<26;++I,k<<=1);if(I>0)for(w.iushrn(I);I-- >0;)C.isOdd()&&C.iadd(h),C.iushrn(1);g.cmp(w)>=0?(g.isub(w),R.isub(C)):(w.isub(g),C.isub(R))}var ne;return g.cmpn(1)===0?ne=R:ne=C,ne.cmpn(0)<0&&ne.iadd(c),ne},i.prototype.gcd=function(c){if(this.isZero())return c.abs();if(c.isZero())return this.abs();var g=this.clone(),w=c.clone();g.negative=0,w.negative=0;for(var R=0;g.isEven()&&w.isEven();R++)g.iushrn(1),w.iushrn(1);do{for(;g.isEven();)g.iushrn(1);for(;w.isEven();)w.iushrn(1);var C=g.cmp(w);if(C<0){var h=g;g=w,w=h}else if(C===0||w.cmpn(1)===0)break;g.isub(w)}while(!0);return w.iushln(R)},i.prototype.invm=function(c){return this.egcd(c).a.umod(c)},i.prototype.isEven=function(){return(this.words[0]&1)===0},i.prototype.isOdd=function(){return(this.words[0]&1)===1},i.prototype.andln=function(c){return this.words[0]&c},i.prototype.bincn=function(c){r(typeof c=="number");var g=c%26,w=(c-g)/26,R=1<>>26,D&=67108863,this.words[h]=D}return C!==0&&(this.words[h]=C,this.length++),this},i.prototype.isZero=function(){return this.length===1&&this.words[0]===0},i.prototype.cmpn=function(c){var g=c<0;if(this.negative!==0&&!g)return-1;if(this.negative===0&&g)return 1;this._strip();var w;if(this.length>1)w=1;else{g&&(c=-c),r(c<=67108863,"Number is too big");var R=this.words[0]|0;w=R===c?0:Rc.length)return 1;if(this.length=0;w--){var R=this.words[w]|0,C=c.words[w]|0;if(R!==C){RC&&(g=1);break}}return g},i.prototype.gtn=function(c){return this.cmpn(c)===1},i.prototype.gt=function(c){return this.cmp(c)===1},i.prototype.gten=function(c){return this.cmpn(c)>=0},i.prototype.gte=function(c){return this.cmp(c)>=0},i.prototype.ltn=function(c){return this.cmpn(c)===-1},i.prototype.lt=function(c){return this.cmp(c)===-1},i.prototype.lten=function(c){return this.cmpn(c)<=0},i.prototype.lte=function(c){return this.cmp(c)<=0},i.prototype.eqn=function(c){return this.cmpn(c)===0},i.prototype.eq=function(c){return this.cmp(c)===0},i.red=function(c){return new E(c)},i.prototype.toRed=function(c){return r(!this.red,"Already a number in reduction context"),r(this.negative===0,"red works only with positives"),c.convertTo(this)._forceRed(c)},i.prototype.fromRed=function(){return r(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},i.prototype._forceRed=function(c){return this.red=c,this},i.prototype.forceRed=function(c){return r(!this.red,"Already a number in reduction context"),this._forceRed(c)},i.prototype.redAdd=function(c){return r(this.red,"redAdd works only with red numbers"),this.red.add(this,c)},i.prototype.redIAdd=function(c){return r(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,c)},i.prototype.redSub=function(c){return r(this.red,"redSub works only with red numbers"),this.red.sub(this,c)},i.prototype.redISub=function(c){return r(this.red,"redISub works only with red numbers"),this.red.isub(this,c)},i.prototype.redShl=function(c){return r(this.red,"redShl works only with red numbers"),this.red.shl(this,c)},i.prototype.redMul=function(c){return r(this.red,"redMul works only with red numbers"),this.red._verify2(this,c),this.red.mul(this,c)},i.prototype.redIMul=function(c){return r(this.red,"redMul works only with red numbers"),this.red._verify2(this,c),this.red.imul(this,c)},i.prototype.redSqr=function(){return r(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},i.prototype.redISqr=function(){return r(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},i.prototype.redSqrt=function(){return r(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},i.prototype.redInvm=function(){return r(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},i.prototype.redNeg=function(){return r(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},i.prototype.redPow=function(c){return r(this.red&&!c.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,c)};var ee={k256:null,p224:null,p192:null,p25519:null};function j(b,c){this.name=b,this.p=new i(c,16),this.n=this.p.bitLength(),this.k=new i(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}j.prototype._tmp=function(){var c=new i(null);return c.words=new Array(Math.ceil(this.n/13)),c},j.prototype.ireduce=function(c){var g=c,w;do this.split(g,this.tmp),g=this.imulK(g),g=g.iadd(this.tmp),w=g.bitLength();while(w>this.n);var R=w0?g.isub(this.p):g.strip!==void 0?g.strip():g._strip(),g},j.prototype.split=function(c,g){c.iushrn(this.n,0,g)},j.prototype.imulK=function(c){return c.imul(this.k)};function se(){j.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}n(se,j),se.prototype.split=function(c,g){for(var w=4194303,R=Math.min(c.length,9),C=0;C>>22,h=D}h>>>=22,c.words[C-10]=h,h===0&&c.length>10?c.length-=10:c.length-=9},se.prototype.imulK=function(c){c.words[c.length]=0,c.words[c.length+1]=0,c.length+=2;for(var g=0,w=0;w>>=26,c.words[w]=C,g=R}return g!==0&&(c.words[c.length++]=g),c},i._prime=function(c){if(ee[c])return ee[c];var g;if(c==="k256")g=new se;else if(c==="p224")g=new ie;else if(c==="p192")g=new ce;else if(c==="p25519")g=new H;else throw new Error("Unknown prime "+c);return ee[c]=g,g};function E(b){if(typeof b=="string"){var c=i._prime(b);this.m=c.p,this.prime=c}else r(b.gtn(1),"modulus must be greater than 1"),this.m=b,this.prime=null}E.prototype._verify1=function(c){r(c.negative===0,"red works only with positives"),r(c.red,"red works only with red numbers")},E.prototype._verify2=function(c,g){r((c.negative|g.negative)===0,"red works only with positives"),r(c.red&&c.red===g.red,"red works only with red numbers")},E.prototype.imod=function(c){return this.prime?this.prime.ireduce(c)._forceRed(this):(f(c,c.umod(this.m)._forceRed(this)),c)},E.prototype.neg=function(c){return c.isZero()?c.clone():this.m.sub(c)._forceRed(this)},E.prototype.add=function(c,g){this._verify2(c,g);var w=c.add(g);return w.cmp(this.m)>=0&&w.isub(this.m),w._forceRed(this)},E.prototype.iadd=function(c,g){this._verify2(c,g);var w=c.iadd(g);return w.cmp(this.m)>=0&&w.isub(this.m),w},E.prototype.sub=function(c,g){this._verify2(c,g);var w=c.sub(g);return w.cmpn(0)<0&&w.iadd(this.m),w._forceRed(this)},E.prototype.isub=function(c,g){this._verify2(c,g);var w=c.isub(g);return w.cmpn(0)<0&&w.iadd(this.m),w},E.prototype.shl=function(c,g){return this._verify1(c),this.imod(c.ushln(g))},E.prototype.imul=function(c,g){return this._verify2(c,g),this.imod(c.imul(g))},E.prototype.mul=function(c,g){return this._verify2(c,g),this.imod(c.mul(g))},E.prototype.isqr=function(c){return this.imul(c,c.clone())},E.prototype.sqr=function(c){return this.mul(c,c)},E.prototype.sqrt=function(c){if(c.isZero())return c.clone();var g=this.m.andln(3);if(r(g%2===1),g===3){var w=this.m.add(new i(1)).iushrn(2);return this.pow(c,w)}for(var R=this.m.subn(1),C=0;!R.isZero()&&R.andln(1)===0;)C++,R.iushrn(1);r(!R.isZero());var h=new i(1).toRed(this),D=h.redNeg(),M=this.m.subn(1).iushrn(1),I=this.m.bitLength();for(I=new i(2*I*I).toRed(this);this.pow(I,M).cmp(D)!==0;)I.redIAdd(D);for(var k=this.pow(I,R),ne=this.pow(c,R.addn(1).iushrn(1)),Ae=this.pow(c,R),ue=C;Ae.cmp(h)!==0;){for(var pe=Ae,he=0;pe.cmp(h)!==0;he++)pe=pe.redSqr();r(he=0;C--){for(var k=g.words[C],ne=I-1;ne>=0;ne--){var Ae=k>>ne&1;if(h!==R[0]&&(h=this.sqr(h)),Ae===0&&D===0){M=0;continue}D<<=1,D|=Ae,M++,!(M!==w&&(C!==0||ne!==0))&&(h=this.mul(h,R[D]),M=0,D=0)}I=26}return h},E.prototype.convertTo=function(c){var g=c.umod(this.m);return g===c?g.clone():g},E.prototype.convertFrom=function(c){var g=c.clone();return g.red=null,g},i.mont=function(c){return new v(c)};function v(b){E.call(this,b),this.shift=this.m.bitLength(),this.shift%26!==0&&(this.shift+=26-this.shift%26),this.r=new i(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}n(v,E),v.prototype.convertTo=function(c){return this.imod(c.ushln(this.shift))},v.prototype.convertFrom=function(c){var g=this.imod(c.mul(this.rinv));return g.red=null,g},v.prototype.imul=function(c,g){if(c.isZero()||g.isZero())return c.words[0]=0,c.length=1,c;var w=c.imul(g),R=w.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),C=w.isub(R).iushrn(this.shift),h=C;return C.cmp(this.m)>=0?h=C.isub(this.m):C.cmpn(0)<0&&(h=C.iadd(this.m)),h._forceRed(this)},v.prototype.mul=function(c,g){if(c.isZero()||g.isZero())return new i(0)._forceRed(this);var w=c.mul(g),R=w.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),C=w.isub(R).iushrn(this.shift),h=C;return C.cmp(this.m)>=0?h=C.isub(this.m):C.cmpn(0)<0&&(h=C.iadd(this.m)),h._forceRed(this)},v.prototype.invm=function(c){var g=this.imod(c._invmp(this.m).mul(this.r2));return g._forceRed(this)}})(typeof YS>"u"||YS,lP)});var vy=x((RMe,gP)=>{"use strict";var qc=_y(),hge=If(),dge=at().Buffer;function hP(e){var t=e.modulus.byteLength(),r;do r=new qc(hge(t));while(r.cmp(e.modulus)>=0||!r.umod(e.prime1)||!r.umod(e.prime2));return r}function gge(e){var t=hP(e),r=t.toRed(qc.mont(e.modulus)).redPow(new qc(e.publicExponent)).fromRed();return{blinder:r,unblinder:t.invm(e.modulus)}}function dP(e,t){var r=gge(t),n=t.modulus.byteLength(),i=new qc(e).mul(r.blinder).umod(t.modulus),s=i.toRed(qc.mont(t.prime1)),o=i.toRed(qc.mont(t.prime2)),a=t.coefficient,A=t.prime1,f=t.prime2,l=s.redPow(t.exponent1).fromRed(),p=o.redPow(t.exponent2).fromRed(),B=l.isub(p).imul(a).umod(A).imul(f);return p.iadd(B).imul(r.unblinder).umod(t.modulus).toArrayLike(dge,"be",n)}dP.getr=hP;gP.exports=dP});var pP=x((DMe,pge)=>{pge.exports={name:"elliptic",version:"6.6.1",description:"EC cryptography",main:"lib/elliptic.js",files:["lib"],scripts:{lint:"eslint lib test","lint:fix":"npm run lint -- --fix",unit:"istanbul test _mocha --reporter=spec test/index.js",test:"npm run lint && npm run unit",version:"grunt dist && git add dist/"},repository:{type:"git",url:"git@github.com:indutny/elliptic"},keywords:["EC","Elliptic","curve","Cryptography"],author:"Fedor Indutny ",license:"MIT",bugs:{url:"https://github.com/indutny/elliptic/issues"},homepage:"https://github.com/indutny/elliptic",devDependencies:{brfs:"^2.0.2",coveralls:"^3.1.0",eslint:"^7.6.0",grunt:"^1.2.1","grunt-browserify":"^5.3.0","grunt-cli":"^1.3.2","grunt-contrib-connect":"^3.0.0","grunt-contrib-copy":"^1.0.0","grunt-contrib-uglify":"^5.0.0","grunt-mocha-istanbul":"^5.0.2","grunt-saucelabs":"^9.0.1",istanbul:"^0.4.5",mocha:"^8.0.1"},dependencies:{"bn.js":"^4.11.9",brorand:"^1.1.0","hash.js":"^1.0.0","hmac-drbg":"^1.0.1",inherits:"^2.0.4","minimalistic-assert":"^1.0.1","minimalistic-crypto-utils":"^1.0.1"}}});var WS=x(mP=>{"use strict";var Ry=mP;function Ege(e,t){if(Array.isArray(e))return e.slice();if(!e)return[];var r=[];if(typeof e!="string"){for(var n=0;n>8,o=i&255;s?r.push(s,o):r.push(o)}return r}Ry.toArray=Ege;function EP(e){return e.length===1?"0"+e:e}Ry.zero2=EP;function yP(e){for(var t="",r=0;r{"use strict";var fs=BP,yge=kr(),mge=zn(),Dy=WS();fs.assert=mge;fs.toArray=Dy.toArray;fs.zero2=Dy.zero2;fs.toHex=Dy.toHex;fs.encode=Dy.encode;function Bge(e,t,r){var n=new Array(Math.max(e.bitLength(),r)+1),i;for(i=0;i(s>>1)-1?a=(s>>1)-A:a=A,o.isubn(a)):a=0,n[i]=a,o.iushrn(1)}return n}fs.getNAF=Bge;function Ige(e,t){var r=[[],[]];e=e.clone(),t=t.clone();for(var n=0,i=0,s;e.cmpn(-n)>0||t.cmpn(-i)>0;){var o=e.andln(3)+n&3,a=t.andln(3)+i&3;o===3&&(o=-1),a===3&&(a=-1);var A;(o&1)===0?A=0:(s=e.andln(7)+n&7,(s===3||s===5)&&a===2?A=-o:A=o),r[0].push(A);var f;(a&1)===0?f=0:(s=t.andln(7)+i&7,(s===3||s===5)&&o===2?f=-a:f=a),r[1].push(f),2*n===A+1&&(n=1-n),2*i===f+1&&(i=1-i),e.iushrn(1),t.iushrn(1)}return r}fs.getJSF=Ige;function bge(e,t,r){var n="_"+t;e.prototype[t]=function(){return this[n]!==void 0?this[n]:this[n]=r.call(this)}}fs.cachedProperty=bge;function Cge(e){return typeof e=="string"?fs.toArray(e,"hex"):e}fs.parseBytes=Cge;function Qge(e){return new yge(e,"hex","le")}fs.intFromLE=Qge});var Ud=x((MMe,IP)=>{"use strict";var kf=kr(),xd=Kn(),Ty=xd.getNAF,wge=xd.getJSF,Ny=xd.assert;function cA(e,t){this.type=e,this.p=new kf(t.p,16),this.red=t.prime?kf.red(t.prime):kf.mont(this.p),this.zero=new kf(0).toRed(this.red),this.one=new kf(1).toRed(this.red),this.two=new kf(2).toRed(this.red),this.n=t.n&&new kf(t.n,16),this.g=t.g&&this.pointFromJSON(t.g,t.gRed),this._wnafT1=new Array(4),this._wnafT2=new Array(4),this._wnafT3=new Array(4),this._wnafT4=new Array(4),this._bitLength=this.n?this.n.bitLength():0;var r=this.n&&this.p.div(this.n);!r||r.cmpn(100)>0?this.redN=null:(this._maxwellTrick=!0,this.redN=this.n.toRed(this.red))}IP.exports=cA;cA.prototype.point=function(){throw new Error("Not implemented")};cA.prototype.validate=function(){throw new Error("Not implemented")};cA.prototype._fixedNafMul=function(t,r){Ny(t.precomputed);var n=t._getDoubles(),i=Ty(r,1,this._bitLength),s=(1<=a;f--)A=(A<<1)+i[f];o.push(A)}for(var l=this.jpoint(null,null,null),p=this.jpoint(null,null,null),B=s;B>0;B--){for(a=0;a=0;A--){for(var f=0;A>=0&&o[A]===0;A--)f++;if(A>=0&&f++,a=a.dblp(f),A<0)break;var l=o[A];Ny(l!==0),t.type==="affine"?l>0?a=a.mixedAdd(s[l-1>>1]):a=a.mixedAdd(s[-l-1>>1].neg()):l>0?a=a.add(s[l-1>>1]):a=a.add(s[-l-1>>1].neg())}return t.type==="affine"?a.toP():a};cA.prototype._wnafMulAdd=function(t,r,n,i,s){var o=this._wnafT1,a=this._wnafT2,A=this._wnafT3,f=0,l,p,B;for(l=0;l=1;l-=2){var _=l-1,N=l;if(o[_]!==1||o[N]!==1){A[_]=Ty(n[_],o[_],this._bitLength),A[N]=Ty(n[N],o[N],this._bitLength),f=Math.max(A[_].length,f),f=Math.max(A[N].length,f);continue}var P=[r[_],null,null,r[N]];r[_].y.cmp(r[N].y)===0?(P[1]=r[_].add(r[N]),P[2]=r[_].toJ().mixedAdd(r[N].neg())):r[_].y.cmp(r[N].y.redNeg())===0?(P[1]=r[_].toJ().mixedAdd(r[N]),P[2]=r[_].add(r[N].neg())):(P[1]=r[_].toJ().mixedAdd(r[N]),P[2]=r[_].toJ().mixedAdd(r[N].neg()));var U=[-3,-1,-5,-7,0,7,5,1,3],G=wge(n[_],n[N]);for(f=Math.max(G[0].length,f),A[_]=new Array(f),A[N]=new Array(f),p=0;p=0;l--){for(var se=0;l>=0;){var ie=!0;for(p=0;p=0&&se++,ee=ee.dblp(se),l<0)break;for(p=0;p0?B=a[p][ce-1>>1]:ce<0&&(B=a[p][-ce-1>>1].neg()),B.type==="affine"?ee=ee.mixedAdd(B):ee=ee.add(B))}}for(l=0;l=Math.ceil((t.bitLength()+1)/r.step):!1};wi.prototype._getDoubles=function(t,r){if(this.precomputed&&this.precomputed.doubles)return this.precomputed.doubles;for(var n=[this],i=this,s=0;s{"use strict";var Sge=Kn(),fr=kr(),VS=ze(),Gc=Ud(),_ge=Sge.assert;function Si(e){Gc.call(this,"short",e),this.a=new fr(e.a,16).toRed(this.red),this.b=new fr(e.b,16).toRed(this.red),this.tinv=this.two.redInvm(),this.zeroA=this.a.fromRed().cmpn(0)===0,this.threeA=this.a.fromRed().sub(this.p).cmpn(-3)===0,this.endo=this._getEndomorphism(e),this._endoWnafT1=new Array(4),this._endoWnafT2=new Array(4)}VS(Si,Gc);bP.exports=Si;Si.prototype._getEndomorphism=function(t){if(!(!this.zeroA||!this.g||!this.n||this.p.modn(3)!==1)){var r,n;if(t.beta)r=new fr(t.beta,16).toRed(this.red);else{var i=this._getEndoRoots(this.p);r=i[0].cmp(i[1])<0?i[0]:i[1],r=r.toRed(this.red)}if(t.lambda)n=new fr(t.lambda,16);else{var s=this._getEndoRoots(this.n);this.g.mul(s[0]).x.cmp(this.g.x.redMul(r))===0?n=s[0]:(n=s[1],_ge(this.g.mul(n).x.cmp(this.g.x.redMul(r))===0))}var o;return t.basis?o=t.basis.map(function(a){return{a:new fr(a.a,16),b:new fr(a.b,16)}}):o=this._getEndoBasis(n),{beta:r,lambda:n,basis:o}}};Si.prototype._getEndoRoots=function(t){var r=t===this.p?this.red:fr.mont(t),n=new fr(2).toRed(r).redInvm(),i=n.redNeg(),s=new fr(3).toRed(r).redNeg().redSqrt().redMul(n),o=i.redAdd(s).fromRed(),a=i.redSub(s).fromRed();return[o,a]};Si.prototype._getEndoBasis=function(t){for(var r=this.n.ushrn(Math.floor(this.n.bitLength()/2)),n=t,i=this.n.clone(),s=new fr(1),o=new fr(0),a=new fr(0),A=new fr(1),f,l,p,B,S,_,N,P=0,U,G;n.cmpn(0)!==0;){var Y=i.div(n);U=i.sub(Y.mul(n)),G=a.sub(Y.mul(s));var Z=A.sub(Y.mul(o));if(!p&&U.cmp(r)<0)f=N.neg(),l=s,p=U.neg(),B=G;else if(p&&++P===2)break;N=U,i=n,n=U,a=s,s=G,A=o,o=Z}S=U.neg(),_=G;var ee=p.sqr().add(B.sqr()),j=S.sqr().add(_.sqr());return j.cmp(ee)>=0&&(S=f,_=l),p.negative&&(p=p.neg(),B=B.neg()),S.negative&&(S=S.neg(),_=_.neg()),[{a:p,b:B},{a:S,b:_}]};Si.prototype._endoSplit=function(t){var r=this.endo.basis,n=r[0],i=r[1],s=i.b.mul(t).divRound(this.n),o=n.b.neg().mul(t).divRound(this.n),a=s.mul(n.a),A=o.mul(i.a),f=s.mul(n.b),l=o.mul(i.b),p=t.sub(a).sub(A),B=f.add(l).neg();return{k1:p,k2:B}};Si.prototype.pointFromX=function(t,r){t=new fr(t,16),t.red||(t=t.toRed(this.red));var n=t.redSqr().redMul(t).redIAdd(t.redMul(this.a)).redIAdd(this.b),i=n.redSqrt();if(i.redSqr().redSub(n).cmp(this.zero)!==0)throw new Error("invalid point");var s=i.fromRed().isOdd();return(r&&!s||!r&&s)&&(i=i.redNeg()),this.point(t,i)};Si.prototype.validate=function(t){if(t.inf)return!0;var r=t.x,n=t.y,i=this.a.redMul(r),s=r.redSqr().redMul(r).redIAdd(i).redIAdd(this.b);return n.redSqr().redISub(s).cmpn(0)===0};Si.prototype._endoWnafMulAdd=function(t,r,n){for(var i=this._endoWnafT1,s=this._endoWnafT2,o=0;o":""};xr.prototype.isInfinity=function(){return this.inf};xr.prototype.add=function(t){if(this.inf)return t;if(t.inf)return this;if(this.eq(t))return this.dbl();if(this.neg().eq(t))return this.curve.point(null,null);if(this.x.cmp(t.x)===0)return this.curve.point(null,null);var r=this.y.redSub(t.y);r.cmpn(0)!==0&&(r=r.redMul(this.x.redSub(t.x).redInvm()));var n=r.redSqr().redISub(this.x).redISub(t.x),i=r.redMul(this.x.redSub(n)).redISub(this.y);return this.curve.point(n,i)};xr.prototype.dbl=function(){if(this.inf)return this;var t=this.y.redAdd(this.y);if(t.cmpn(0)===0)return this.curve.point(null,null);var r=this.curve.a,n=this.x.redSqr(),i=t.redInvm(),s=n.redAdd(n).redIAdd(n).redIAdd(r).redMul(i),o=s.redSqr().redISub(this.x.redAdd(this.x)),a=s.redMul(this.x.redSub(o)).redISub(this.y);return this.curve.point(o,a)};xr.prototype.getX=function(){return this.x.fromRed()};xr.prototype.getY=function(){return this.y.fromRed()};xr.prototype.mul=function(t){return t=new fr(t,16),this.isInfinity()?this:this._hasDoubles(t)?this.curve._fixedNafMul(this,t):this.curve.endo?this.curve._endoWnafMulAdd([this],[t]):this.curve._wnafMul(this,t)};xr.prototype.mulAdd=function(t,r,n){var i=[this,r],s=[t,n];return this.curve.endo?this.curve._endoWnafMulAdd(i,s):this.curve._wnafMulAdd(1,i,s,2)};xr.prototype.jmulAdd=function(t,r,n){var i=[this,r],s=[t,n];return this.curve.endo?this.curve._endoWnafMulAdd(i,s,!0):this.curve._wnafMulAdd(1,i,s,2,!0)};xr.prototype.eq=function(t){return this===t||this.inf===t.inf&&(this.inf||this.x.cmp(t.x)===0&&this.y.cmp(t.y)===0)};xr.prototype.neg=function(t){if(this.inf)return this;var r=this.curve.point(this.x,this.y.redNeg());if(t&&this.precomputed){var n=this.precomputed,i=function(s){return s.neg()};r.precomputed={naf:n.naf&&{wnd:n.naf.wnd,points:n.naf.points.map(i)},doubles:n.doubles&&{step:n.doubles.step,points:n.doubles.points.map(i)}}}return r};xr.prototype.toJ=function(){if(this.inf)return this.curve.jpoint(null,null,null);var t=this.curve.jpoint(this.x,this.y,this.curve.one);return t};function jr(e,t,r,n){Gc.BasePoint.call(this,e,"jacobian"),t===null&&r===null&&n===null?(this.x=this.curve.one,this.y=this.curve.one,this.z=new fr(0)):(this.x=new fr(t,16),this.y=new fr(r,16),this.z=new fr(n,16)),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)),this.zOne=this.z===this.curve.one}VS(jr,Gc.BasePoint);Si.prototype.jpoint=function(t,r,n){return new jr(this,t,r,n)};jr.prototype.toP=function(){if(this.isInfinity())return this.curve.point(null,null);var t=this.z.redInvm(),r=t.redSqr(),n=this.x.redMul(r),i=this.y.redMul(r).redMul(t);return this.curve.point(n,i)};jr.prototype.neg=function(){return this.curve.jpoint(this.x,this.y.redNeg(),this.z)};jr.prototype.add=function(t){if(this.isInfinity())return t;if(t.isInfinity())return this;var r=t.z.redSqr(),n=this.z.redSqr(),i=this.x.redMul(r),s=t.x.redMul(n),o=this.y.redMul(r.redMul(t.z)),a=t.y.redMul(n.redMul(this.z)),A=i.redSub(s),f=o.redSub(a);if(A.cmpn(0)===0)return f.cmpn(0)!==0?this.curve.jpoint(null,null,null):this.dbl();var l=A.redSqr(),p=l.redMul(A),B=i.redMul(l),S=f.redSqr().redIAdd(p).redISub(B).redISub(B),_=f.redMul(B.redISub(S)).redISub(o.redMul(p)),N=this.z.redMul(t.z).redMul(A);return this.curve.jpoint(S,_,N)};jr.prototype.mixedAdd=function(t){if(this.isInfinity())return t.toJ();if(t.isInfinity())return this;var r=this.z.redSqr(),n=this.x,i=t.x.redMul(r),s=this.y,o=t.y.redMul(r).redMul(this.z),a=n.redSub(i),A=s.redSub(o);if(a.cmpn(0)===0)return A.cmpn(0)!==0?this.curve.jpoint(null,null,null):this.dbl();var f=a.redSqr(),l=f.redMul(a),p=n.redMul(f),B=A.redSqr().redIAdd(l).redISub(p).redISub(p),S=A.redMul(p.redISub(B)).redISub(s.redMul(l)),_=this.z.redMul(a);return this.curve.jpoint(B,S,_)};jr.prototype.dblp=function(t){if(t===0)return this;if(this.isInfinity())return this;if(!t)return this.dbl();var r;if(this.curve.zeroA||this.curve.threeA){var n=this;for(r=0;r=0)return!1;if(n.redIAdd(s),this.x.cmp(n)===0)return!0}};jr.prototype.inspect=function(){return this.isInfinity()?"":""};jr.prototype.isInfinity=function(){return this.z.cmpn(0)===0}});var SP=x((kMe,wP)=>{"use strict";var Yc=kr(),QP=ze(),My=Ud(),vge=Kn();function Wc(e){My.call(this,"mont",e),this.a=new Yc(e.a,16).toRed(this.red),this.b=new Yc(e.b,16).toRed(this.red),this.i4=new Yc(4).toRed(this.red).redInvm(),this.two=new Yc(2).toRed(this.red),this.a24=this.i4.redMul(this.a.redAdd(this.two))}QP(Wc,My);wP.exports=Wc;Wc.prototype.validate=function(t){var r=t.normalize().x,n=r.redSqr(),i=n.redMul(r).redAdd(n.redMul(this.a)).redAdd(r),s=i.redSqrt();return s.redSqr().cmp(i)===0};function Ur(e,t,r){My.BasePoint.call(this,e,"projective"),t===null&&r===null?(this.x=this.curve.one,this.z=this.curve.zero):(this.x=new Yc(t,16),this.z=new Yc(r,16),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)))}QP(Ur,My.BasePoint);Wc.prototype.decodePoint=function(t,r){return this.point(vge.toArray(t,r),1)};Wc.prototype.point=function(t,r){return new Ur(this,t,r)};Wc.prototype.pointFromJSON=function(t){return Ur.fromJSON(this,t)};Ur.prototype.precompute=function(){};Ur.prototype._encode=function(){return this.getX().toArray("be",this.curve.p.byteLength())};Ur.fromJSON=function(t,r){return new Ur(t,r[0],r[1]||t.one)};Ur.prototype.inspect=function(){return this.isInfinity()?"":""};Ur.prototype.isInfinity=function(){return this.z.cmpn(0)===0};Ur.prototype.dbl=function(){var t=this.x.redAdd(this.z),r=t.redSqr(),n=this.x.redSub(this.z),i=n.redSqr(),s=r.redSub(i),o=r.redMul(i),a=s.redMul(i.redAdd(this.curve.a24.redMul(s)));return this.curve.point(o,a)};Ur.prototype.add=function(){throw new Error("Not supported on Montgomery curve")};Ur.prototype.diffAdd=function(t,r){var n=this.x.redAdd(this.z),i=this.x.redSub(this.z),s=t.x.redAdd(t.z),o=t.x.redSub(t.z),a=o.redMul(n),A=s.redMul(i),f=r.z.redMul(a.redAdd(A).redSqr()),l=r.x.redMul(a.redISub(A).redSqr());return this.curve.point(f,l)};Ur.prototype.mul=function(t){for(var r=t.clone(),n=this,i=this.curve.point(null,null),s=this,o=[];r.cmpn(0)!==0;r.iushrn(1))o.push(r.andln(1));for(var a=o.length-1;a>=0;a--)o[a]===0?(n=n.diffAdd(i,s),i=i.dbl()):(i=n.diffAdd(i,s),n=n.dbl());return i};Ur.prototype.mulAdd=function(){throw new Error("Not supported on Montgomery curve")};Ur.prototype.jumlAdd=function(){throw new Error("Not supported on Montgomery curve")};Ur.prototype.eq=function(t){return this.getX().cmp(t.getX())===0};Ur.prototype.normalize=function(){return this.x=this.x.redMul(this.z.redInvm()),this.z=this.curve.one,this};Ur.prototype.getX=function(){return this.normalize(),this.x.fromRed()}});var RP=x((xMe,vP)=>{"use strict";var Rge=Kn(),aa=kr(),_P=ze(),Fy=Ud(),Dge=Rge.assert;function oo(e){this.twisted=(e.a|0)!==1,this.mOneA=this.twisted&&(e.a|0)===-1,this.extended=this.mOneA,Fy.call(this,"edwards",e),this.a=new aa(e.a,16).umod(this.red.m),this.a=this.a.toRed(this.red),this.c=new aa(e.c,16).toRed(this.red),this.c2=this.c.redSqr(),this.d=new aa(e.d,16).toRed(this.red),this.dd=this.d.redAdd(this.d),Dge(!this.twisted||this.c.fromRed().cmpn(1)===0),this.oneC=(e.c|0)===1}_P(oo,Fy);vP.exports=oo;oo.prototype._mulA=function(t){return this.mOneA?t.redNeg():this.a.redMul(t)};oo.prototype._mulC=function(t){return this.oneC?t:this.c.redMul(t)};oo.prototype.jpoint=function(t,r,n,i){return this.point(t,r,n,i)};oo.prototype.pointFromX=function(t,r){t=new aa(t,16),t.red||(t=t.toRed(this.red));var n=t.redSqr(),i=this.c2.redSub(this.a.redMul(n)),s=this.one.redSub(this.c2.redMul(this.d).redMul(n)),o=i.redMul(s.redInvm()),a=o.redSqrt();if(a.redSqr().redSub(o).cmp(this.zero)!==0)throw new Error("invalid point");var A=a.fromRed().isOdd();return(r&&!A||!r&&A)&&(a=a.redNeg()),this.point(t,a)};oo.prototype.pointFromY=function(t,r){t=new aa(t,16),t.red||(t=t.toRed(this.red));var n=t.redSqr(),i=n.redSub(this.c2),s=n.redMul(this.d).redMul(this.c2).redSub(this.a),o=i.redMul(s.redInvm());if(o.cmp(this.zero)===0){if(r)throw new Error("invalid point");return this.point(this.zero,t)}var a=o.redSqrt();if(a.redSqr().redSub(o).cmp(this.zero)!==0)throw new Error("invalid point");return a.fromRed().isOdd()!==r&&(a=a.redNeg()),this.point(a,t)};oo.prototype.validate=function(t){if(t.isInfinity())return!0;t.normalize();var r=t.x.redSqr(),n=t.y.redSqr(),i=r.redMul(this.a).redAdd(n),s=this.c2.redMul(this.one.redAdd(this.d.redMul(r).redMul(n)));return i.cmp(s)===0};function Jt(e,t,r,n,i){Fy.BasePoint.call(this,e,"projective"),t===null&&r===null&&n===null?(this.x=this.curve.zero,this.y=this.curve.one,this.z=this.curve.one,this.t=this.curve.zero,this.zOne=!0):(this.x=new aa(t,16),this.y=new aa(r,16),this.z=n?new aa(n,16):this.curve.one,this.t=i&&new aa(i,16),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)),this.t&&!this.t.red&&(this.t=this.t.toRed(this.curve.red)),this.zOne=this.z===this.curve.one,this.curve.extended&&!this.t&&(this.t=this.x.redMul(this.y),this.zOne||(this.t=this.t.redMul(this.z.redInvm()))))}_P(Jt,Fy.BasePoint);oo.prototype.pointFromJSON=function(t){return Jt.fromJSON(this,t)};oo.prototype.point=function(t,r,n,i){return new Jt(this,t,r,n,i)};Jt.fromJSON=function(t,r){return new Jt(t,r[0],r[1],r[2])};Jt.prototype.inspect=function(){return this.isInfinity()?"":""};Jt.prototype.isInfinity=function(){return this.x.cmpn(0)===0&&(this.y.cmp(this.z)===0||this.zOne&&this.y.cmp(this.curve.c)===0)};Jt.prototype._extDbl=function(){var t=this.x.redSqr(),r=this.y.redSqr(),n=this.z.redSqr();n=n.redIAdd(n);var i=this.curve._mulA(t),s=this.x.redAdd(this.y).redSqr().redISub(t).redISub(r),o=i.redAdd(r),a=o.redSub(n),A=i.redSub(r),f=s.redMul(a),l=o.redMul(A),p=s.redMul(A),B=a.redMul(o);return this.curve.point(f,l,B,p)};Jt.prototype._projDbl=function(){var t=this.x.redAdd(this.y).redSqr(),r=this.x.redSqr(),n=this.y.redSqr(),i,s,o,a,A,f;if(this.curve.twisted){a=this.curve._mulA(r);var l=a.redAdd(n);this.zOne?(i=t.redSub(r).redSub(n).redMul(l.redSub(this.curve.two)),s=l.redMul(a.redSub(n)),o=l.redSqr().redSub(l).redSub(l)):(A=this.z.redSqr(),f=l.redSub(A).redISub(A),i=t.redSub(r).redISub(n).redMul(f),s=l.redMul(a.redSub(n)),o=l.redMul(f))}else a=r.redAdd(n),A=this.curve._mulC(this.z).redSqr(),f=a.redSub(A).redSub(A),i=this.curve._mulC(t.redISub(a)).redMul(f),s=this.curve._mulC(a).redMul(r.redISub(n)),o=a.redMul(f);return this.curve.point(i,s,o)};Jt.prototype.dbl=function(){return this.isInfinity()?this:this.curve.extended?this._extDbl():this._projDbl()};Jt.prototype._extAdd=function(t){var r=this.y.redSub(this.x).redMul(t.y.redSub(t.x)),n=this.y.redAdd(this.x).redMul(t.y.redAdd(t.x)),i=this.t.redMul(this.curve.dd).redMul(t.t),s=this.z.redMul(t.z.redAdd(t.z)),o=n.redSub(r),a=s.redSub(i),A=s.redAdd(i),f=n.redAdd(r),l=o.redMul(a),p=A.redMul(f),B=o.redMul(f),S=a.redMul(A);return this.curve.point(l,p,S,B)};Jt.prototype._projAdd=function(t){var r=this.z.redMul(t.z),n=r.redSqr(),i=this.x.redMul(t.x),s=this.y.redMul(t.y),o=this.curve.d.redMul(i).redMul(s),a=n.redSub(o),A=n.redAdd(o),f=this.x.redAdd(this.y).redMul(t.x.redAdd(t.y)).redISub(i).redISub(s),l=r.redMul(a).redMul(f),p,B;return this.curve.twisted?(p=r.redMul(A).redMul(s.redSub(this.curve._mulA(i))),B=a.redMul(A)):(p=r.redMul(A).redMul(s.redSub(i)),B=this.curve._mulC(a).redMul(A)),this.curve.point(l,p,B)};Jt.prototype.add=function(t){return this.isInfinity()?t:t.isInfinity()?this:this.curve.extended?this._extAdd(t):this._projAdd(t)};Jt.prototype.mul=function(t){return this._hasDoubles(t)?this.curve._fixedNafMul(this,t):this.curve._wnafMul(this,t)};Jt.prototype.mulAdd=function(t,r,n){return this.curve._wnafMulAdd(1,[this,r],[t,n],2,!1)};Jt.prototype.jmulAdd=function(t,r,n){return this.curve._wnafMulAdd(1,[this,r],[t,n],2,!0)};Jt.prototype.normalize=function(){if(this.zOne)return this;var t=this.z.redInvm();return this.x=this.x.redMul(t),this.y=this.y.redMul(t),this.t&&(this.t=this.t.redMul(t)),this.z=this.curve.one,this.zOne=!0,this};Jt.prototype.neg=function(){return this.curve.point(this.x.redNeg(),this.y,this.z,this.t&&this.t.redNeg())};Jt.prototype.getX=function(){return this.normalize(),this.x.fromRed()};Jt.prototype.getY=function(){return this.normalize(),this.y.fromRed()};Jt.prototype.eq=function(t){return this===t||this.getX().cmp(t.getX())===0&&this.getY().cmp(t.getY())===0};Jt.prototype.eqXToP=function(t){var r=t.toRed(this.curve.red).redMul(this.z);if(this.x.cmp(r)===0)return!0;for(var n=t.clone(),i=this.curve.redN.redMul(this.z);;){if(n.iadd(this.curve.n),n.cmp(this.curve.p)>=0)return!1;if(r.redIAdd(i),this.x.cmp(r)===0)return!0}};Jt.prototype.toP=Jt.prototype.normalize;Jt.prototype.mixedAdd=Jt.prototype.add});var JS=x(DP=>{"use strict";var ky=DP;ky.base=Ud();ky.short=CP();ky.mont=SP();ky.edwards=RP()});var us=x(Ht=>{"use strict";var Tge=zn(),Nge=ze();Ht.inherits=Nge;function Mge(e,t){return(e.charCodeAt(t)&64512)!==55296||t<0||t+1>=e.length?!1:(e.charCodeAt(t+1)&64512)===56320}function Fge(e,t){if(Array.isArray(e))return e.slice();if(!e)return[];var r=[];if(typeof e=="string")if(t){if(t==="hex")for(e=e.replace(/[^a-z0-9]+/ig,""),e.length%2!==0&&(e="0"+e),i=0;i>6|192,r[n++]=s&63|128):Mge(e,i)?(s=65536+((s&1023)<<10)+(e.charCodeAt(++i)&1023),r[n++]=s>>18|240,r[n++]=s>>12&63|128,r[n++]=s>>6&63|128,r[n++]=s&63|128):(r[n++]=s>>12|224,r[n++]=s>>6&63|128,r[n++]=s&63|128)}else for(i=0;i>>24|e>>>8&65280|e<<8&16711680|(e&255)<<24;return t>>>0}Ht.htonl=TP;function xge(e,t){for(var r="",n=0;n>>0}return s}Ht.join32=Uge;function Lge(e,t){for(var r=new Array(e.length*4),n=0,i=0;n>>24,r[i+1]=s>>>16&255,r[i+2]=s>>>8&255,r[i+3]=s&255):(r[i+3]=s>>>24,r[i+2]=s>>>16&255,r[i+1]=s>>>8&255,r[i]=s&255)}return r}Ht.split32=Lge;function Pge(e,t){return e>>>t|e<<32-t}Ht.rotr32=Pge;function Oge(e,t){return e<>>32-t}Ht.rotl32=Oge;function Hge(e,t){return e+t>>>0}Ht.sum32=Hge;function qge(e,t,r){return e+t+r>>>0}Ht.sum32_3=qge;function Gge(e,t,r,n){return e+t+r+n>>>0}Ht.sum32_4=Gge;function Yge(e,t,r,n,i){return e+t+r+n+i>>>0}Ht.sum32_5=Yge;function Wge(e,t,r,n){var i=e[t],s=e[t+1],o=n+s>>>0,a=(o>>0,e[t+1]=o}Ht.sum64=Wge;function Vge(e,t,r,n){var i=t+n>>>0,s=(i>>0}Ht.sum64_hi=Vge;function Jge(e,t,r,n){var i=t+n;return i>>>0}Ht.sum64_lo=Jge;function jge(e,t,r,n,i,s,o,a){var A=0,f=t;f=f+n>>>0,A+=f>>0,A+=f>>0,A+=f>>0}Ht.sum64_4_hi=jge;function zge(e,t,r,n,i,s,o,a){var A=t+n+s+a;return A>>>0}Ht.sum64_4_lo=zge;function Kge(e,t,r,n,i,s,o,a,A,f){var l=0,p=t;p=p+n>>>0,l+=p>>0,l+=p>>0,l+=p>>0,l+=p>>0}Ht.sum64_5_hi=Kge;function Xge(e,t,r,n,i,s,o,a,A,f){var l=t+n+s+a+f;return l>>>0}Ht.sum64_5_lo=Xge;function Zge(e,t,r){var n=t<<32-r|e>>>r;return n>>>0}Ht.rotr64_hi=Zge;function $ge(e,t,r){var n=e<<32-r|t>>>r;return n>>>0}Ht.rotr64_lo=$ge;function e0e(e,t,r){return e>>>r}Ht.shr64_hi=e0e;function t0e(e,t,r){var n=e<<32-r|t>>>r;return n>>>0}Ht.shr64_lo=t0e});var Vc=x(kP=>{"use strict";var FP=us(),r0e=zn();function xy(){this.pending=null,this.pendingTotal=0,this.blockSize=this.constructor.blockSize,this.outSize=this.constructor.outSize,this.hmacStrength=this.constructor.hmacStrength,this.padLength=this.constructor.padLength/8,this.endian="big",this._delta8=this.blockSize/8,this._delta32=this.blockSize/32}kP.BlockHash=xy;xy.prototype.update=function(t,r){if(t=FP.toArray(t,r),this.pending?this.pending=this.pending.concat(t):this.pending=t,this.pendingTotal+=t.length,this.pending.length>=this._delta8){t=this.pending;var n=t.length%this._delta8;this.pending=t.slice(t.length-n,t.length),this.pending.length===0&&(this.pending=null),t=FP.join32(t,0,t.length-n,this.endian);for(var i=0;i>>24&255,i[s++]=t>>>16&255,i[s++]=t>>>8&255,i[s++]=t&255}else for(i[s++]=t&255,i[s++]=t>>>8&255,i[s++]=t>>>16&255,i[s++]=t>>>24&255,i[s++]=0,i[s++]=0,i[s++]=0,i[s++]=0,o=8;o{"use strict";var n0e=us(),ao=n0e.rotr32;function i0e(e,t,r,n){if(e===0)return xP(t,r,n);if(e===1||e===3)return LP(t,r,n);if(e===2)return UP(t,r,n)}Aa.ft_1=i0e;function xP(e,t,r){return e&t^~e&r}Aa.ch32=xP;function UP(e,t,r){return e&t^e&r^t&r}Aa.maj32=UP;function LP(e,t,r){return e^t^r}Aa.p32=LP;function s0e(e){return ao(e,2)^ao(e,13)^ao(e,22)}Aa.s0_256=s0e;function o0e(e){return ao(e,6)^ao(e,11)^ao(e,25)}Aa.s1_256=o0e;function a0e(e){return ao(e,7)^ao(e,18)^e>>>3}Aa.g0_256=a0e;function A0e(e){return ao(e,17)^ao(e,19)^e>>>10}Aa.g1_256=A0e});var HP=x((HMe,OP)=>{"use strict";var Jc=us(),f0e=Vc(),u0e=jS(),zS=Jc.rotl32,Ld=Jc.sum32,c0e=Jc.sum32_5,l0e=u0e.ft_1,PP=f0e.BlockHash,h0e=[1518500249,1859775393,2400959708,3395469782];function Ao(){if(!(this instanceof Ao))return new Ao;PP.call(this),this.h=[1732584193,4023233417,2562383102,271733878,3285377520],this.W=new Array(80)}Jc.inherits(Ao,PP);OP.exports=Ao;Ao.blockSize=512;Ao.outSize=160;Ao.hmacStrength=80;Ao.padLength=64;Ao.prototype._update=function(t,r){for(var n=this.W,i=0;i<16;i++)n[i]=t[r+i];for(;i{"use strict";var jc=us(),d0e=Vc(),zc=jS(),g0e=zn(),cs=jc.sum32,p0e=jc.sum32_4,E0e=jc.sum32_5,y0e=zc.ch32,m0e=zc.maj32,B0e=zc.s0_256,I0e=zc.s1_256,b0e=zc.g0_256,C0e=zc.g1_256,qP=d0e.BlockHash,Q0e=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function fo(){if(!(this instanceof fo))return new fo;qP.call(this),this.h=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],this.k=Q0e,this.W=new Array(64)}jc.inherits(fo,qP);GP.exports=fo;fo.blockSize=512;fo.outSize=256;fo.hmacStrength=192;fo.padLength=64;fo.prototype._update=function(t,r){for(var n=this.W,i=0;i<16;i++)n[i]=t[r+i];for(;i{"use strict";var XS=us(),YP=KS();function fa(){if(!(this instanceof fa))return new fa;YP.call(this),this.h=[3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428]}XS.inherits(fa,YP);WP.exports=fa;fa.blockSize=512;fa.outSize=224;fa.hmacStrength=192;fa.padLength=64;fa.prototype._digest=function(t){return t==="hex"?XS.toHex32(this.h.slice(0,7),"big"):XS.split32(this.h.slice(0,7),"big")}});var e_=x((YMe,KP)=>{"use strict";var Fn=us(),w0e=Vc(),S0e=zn(),uo=Fn.rotr64_hi,co=Fn.rotr64_lo,JP=Fn.shr64_hi,jP=Fn.shr64_lo,lA=Fn.sum64,ZS=Fn.sum64_hi,$S=Fn.sum64_lo,_0e=Fn.sum64_4_hi,v0e=Fn.sum64_4_lo,R0e=Fn.sum64_5_hi,D0e=Fn.sum64_5_lo,zP=w0e.BlockHash,T0e=[1116352408,3609767458,1899447441,602891725,3049323471,3964484399,3921009573,2173295548,961987163,4081628472,1508970993,3053834265,2453635748,2937671579,2870763221,3664609560,3624381080,2734883394,310598401,1164996542,607225278,1323610764,1426881987,3590304994,1925078388,4068182383,2162078206,991336113,2614888103,633803317,3248222580,3479774868,3835390401,2666613458,4022224774,944711139,264347078,2341262773,604807628,2007800933,770255983,1495990901,1249150122,1856431235,1555081692,3175218132,1996064986,2198950837,2554220882,3999719339,2821834349,766784016,2952996808,2566594879,3210313671,3203337956,3336571891,1034457026,3584528711,2466948901,113926993,3758326383,338241895,168717936,666307205,1188179964,773529912,1546045734,1294757372,1522805485,1396182291,2643833823,1695183700,2343527390,1986661051,1014477480,2177026350,1206759142,2456956037,344077627,2730485921,1290863460,2820302411,3158454273,3259730800,3505952657,3345764771,106217008,3516065817,3606008344,3600352804,1432725776,4094571909,1467031594,275423344,851169720,430227734,3100823752,506948616,1363258195,659060556,3750685593,883997877,3785050280,958139571,3318307427,1322822218,3812723403,1537002063,2003034995,1747873779,3602036899,1955562222,1575990012,2024104815,1125592928,2227730452,2716904306,2361852424,442776044,2428436474,593698344,2756734187,3733110249,3204031479,2999351573,3329325298,3815920427,3391569614,3928383900,3515267271,566280711,3940187606,3454069534,4118630271,4000239992,116418474,1914138554,174292421,2731055270,289380356,3203993006,460393269,320620315,685471733,587496836,852142971,1086792851,1017036298,365543100,1126000580,2618297676,1288033470,3409855158,1501505948,4234509866,1607167915,987167468,1816402316,1246189591];function ls(){if(!(this instanceof ls))return new ls;zP.call(this),this.h=[1779033703,4089235720,3144134277,2227873595,1013904242,4271175723,2773480762,1595750129,1359893119,2917565137,2600822924,725511199,528734635,4215389547,1541459225,327033209],this.k=T0e,this.W=new Array(160)}Fn.inherits(ls,zP);KP.exports=ls;ls.blockSize=1024;ls.outSize=512;ls.hmacStrength=192;ls.padLength=128;ls.prototype._prepareBlock=function(t,r){for(var n=this.W,i=0;i<32;i++)n[i]=t[r+i];for(;i{"use strict";var t_=us(),XP=e_();function ua(){if(!(this instanceof ua))return new ua;XP.call(this),this.h=[3418070365,3238371032,1654270250,914150663,2438529370,812702999,355462360,4144912697,1731405415,4290775857,2394180231,1750603025,3675008525,1694076839,1203062813,3204075428]}t_.inherits(ua,XP);ZP.exports=ua;ua.blockSize=1024;ua.outSize=384;ua.hmacStrength=192;ua.padLength=128;ua.prototype._digest=function(t){return t==="hex"?t_.toHex32(this.h.slice(0,12),"big"):t_.split32(this.h.slice(0,12),"big")}});var e9=x(Kc=>{"use strict";Kc.sha1=HP();Kc.sha224=VP();Kc.sha256=KS();Kc.sha384=$P();Kc.sha512=e_()});var o9=x(s9=>{"use strict";var xf=us(),Y0e=Vc(),Uy=xf.rotl32,t9=xf.sum32,Pd=xf.sum32_3,r9=xf.sum32_4,i9=Y0e.BlockHash;function lo(){if(!(this instanceof lo))return new lo;i9.call(this),this.h=[1732584193,4023233417,2562383102,271733878,3285377520],this.endian="little"}xf.inherits(lo,i9);s9.ripemd160=lo;lo.blockSize=512;lo.outSize=160;lo.hmacStrength=192;lo.padLength=64;lo.prototype._update=function(t,r){for(var n=this.h[0],i=this.h[1],s=this.h[2],o=this.h[3],a=this.h[4],A=n,f=i,l=s,p=o,B=a,S=0;S<80;S++){var _=t9(Uy(r9(n,n9(S,i,s,o),t[J0e[S]+r],W0e(S)),z0e[S]),a);n=a,a=o,o=Uy(s,10),s=i,i=_,_=t9(Uy(r9(A,n9(79-S,f,l,p),t[j0e[S]+r],V0e(S)),K0e[S]),B),A=B,B=p,p=Uy(l,10),l=f,f=_}_=Pd(this.h[1],s,p),this.h[1]=Pd(this.h[2],o,B),this.h[2]=Pd(this.h[3],a,A),this.h[3]=Pd(this.h[4],n,f),this.h[4]=Pd(this.h[0],i,l),this.h[0]=_};lo.prototype._digest=function(t){return t==="hex"?xf.toHex32(this.h,"little"):xf.split32(this.h,"little")};function n9(e,t,r,n){return e<=15?t^r^n:e<=31?t&r|~t&n:e<=47?(t|~r)^n:e<=63?t&n|r&~n:t^(r|~n)}function W0e(e){return e<=15?0:e<=31?1518500249:e<=47?1859775393:e<=63?2400959708:2840853838}function V0e(e){return e<=15?1352829926:e<=31?1548603684:e<=47?1836072691:e<=63?2053994217:0}var J0e=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13],j0e=[5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11],z0e=[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6],K0e=[8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]});var A9=x((jMe,a9)=>{"use strict";var X0e=us(),Z0e=zn();function Xc(e,t,r){if(!(this instanceof Xc))return new Xc(e,t,r);this.Hash=e,this.blockSize=e.blockSize/8,this.outSize=e.outSize/8,this.inner=null,this.outer=null,this._init(X0e.toArray(t,r))}a9.exports=Xc;Xc.prototype._init=function(t){t.length>this.blockSize&&(t=new this.Hash().update(t).digest()),Z0e(t.length<=this.blockSize);for(var r=t.length;r{var zr=f9;zr.utils=us();zr.common=Vc();zr.sha=e9();zr.ripemd=o9();zr.hmac=A9();zr.sha1=zr.sha.sha1;zr.sha256=zr.sha.sha256;zr.sha224=zr.sha.sha224;zr.sha384=zr.sha.sha384;zr.sha512=zr.sha.sha512;zr.ripemd160=zr.ripemd.ripemd160});var c9=x((KMe,u9)=>{u9.exports={doubles:{step:4,points:[["e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a","f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821"],["8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508","11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf"],["175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739","d3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695"],["363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640","4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9"],["8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c","4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36"],["723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda","96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f"],["eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa","5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999"],["100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0","cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09"],["e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d","9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d"],["feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d","e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088"],["da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1","9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d"],["53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0","5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8"],["8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047","10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a"],["385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862","283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453"],["6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7","7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160"],["3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd","56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0"],["85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83","7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6"],["948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a","53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589"],["6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8","bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17"],["e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d","4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda"],["e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725","7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd"],["213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754","4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2"],["4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c","17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6"],["fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6","6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f"],["76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39","c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01"],["c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891","893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3"],["d895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b","febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f"],["b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03","2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7"],["e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d","eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78"],["a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070","7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1"],["90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4","e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150"],["8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da","662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82"],["e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11","1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc"],["8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e","efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b"],["e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41","2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51"],["b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef","67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45"],["d68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8","db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120"],["324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d","648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84"],["4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96","35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d"],["9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd","ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d"],["6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5","9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8"],["a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266","40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8"],["7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71","34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac"],["928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac","c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f"],["85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751","1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962"],["ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e","493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907"],["827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241","c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec"],["eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3","be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d"],["e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f","4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414"],["1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19","aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd"],["146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be","b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0"],["fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9","6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811"],["da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2","8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1"],["a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13","7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c"],["174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c","ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73"],["959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba","2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd"],["d2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151","e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405"],["64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073","d99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589"],["8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458","38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e"],["13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b","69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27"],["bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366","d3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1"],["8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa","40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482"],["8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0","620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945"],["dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787","7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573"],["f710d79d9eb962297e4f6232b40e8f7feb2bc63814614d692c12de752408221e","ea98e67232d3b3295d3b535532115ccac8612c721851617526ae47a9c77bfc82"]]},naf:{wnd:7,points:[["f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9","388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672"],["2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4","d8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6"],["5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc","6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da"],["acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe","cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37"],["774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb","d984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b"],["f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8","ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81"],["d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e","581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58"],["defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34","4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77"],["2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c","85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a"],["352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5","321eb4075348f534d59c18259dda3e1f4a1b3b2e71b1039c67bd3d8bcf81998c"],["2fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f","2de1068295dd865b64569335bd5dd80181d70ecfc882648423ba76b532b7d67"],["9248279b09b4d68dab21a9b066edda83263c3d84e09572e269ca0cd7f5453714","73016f7bf234aade5d1aa71bdea2b1ff3fc0de2a887912ffe54a32ce97cb3402"],["daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729","a69dce4a7d6c98e8d4a1aca87ef8d7003f83c230f3afa726ab40e52290be1c55"],["c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db","2119a460ce326cdc76c45926c982fdac0e106e861edf61c5a039063f0e0e6482"],["6a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4","e022cf42c2bd4a708b3f5126f16a24ad8b33ba48d0423b6efd5e6348100d8a82"],["1697ffa6fd9de627c077e3d2fe541084ce13300b0bec1146f95ae57f0d0bd6a5","b9c398f186806f5d27561506e4557433a2cf15009e498ae7adee9d63d01b2396"],["605bdb019981718b986d0f07e834cb0d9deb8360ffb7f61df982345ef27a7479","2972d2de4f8d20681a78d93ec96fe23c26bfae84fb14db43b01e1e9056b8c49"],["62d14dab4150bf497402fdc45a215e10dcb01c354959b10cfe31c7e9d87ff33d","80fc06bd8cc5b01098088a1950eed0db01aa132967ab472235f5642483b25eaf"],["80c60ad0040f27dade5b4b06c408e56b2c50e9f56b9b8b425e555c2f86308b6f","1c38303f1cc5c30f26e66bad7fe72f70a65eed4cbe7024eb1aa01f56430bd57a"],["7a9375ad6167ad54aa74c6348cc54d344cc5dc9487d847049d5eabb0fa03c8fb","d0e3fa9eca8726909559e0d79269046bdc59ea10c70ce2b02d499ec224dc7f7"],["d528ecd9b696b54c907a9ed045447a79bb408ec39b68df504bb51f459bc3ffc9","eecf41253136e5f99966f21881fd656ebc4345405c520dbc063465b521409933"],["49370a4b5f43412ea25f514e8ecdad05266115e4a7ecb1387231808f8b45963","758f3f41afd6ed428b3081b0512fd62a54c3f3afbb5b6764b653052a12949c9a"],["77f230936ee88cbbd73df930d64702ef881d811e0e1498e2f1c13eb1fc345d74","958ef42a7886b6400a08266e9ba1b37896c95330d97077cbbe8eb3c7671c60d6"],["f2dac991cc4ce4b9ea44887e5c7c0bce58c80074ab9d4dbaeb28531b7739f530","e0dedc9b3b2f8dad4da1f32dec2531df9eb5fbeb0598e4fd1a117dba703a3c37"],["463b3d9f662621fb1b4be8fbbe2520125a216cdfc9dae3debcba4850c690d45b","5ed430d78c296c3543114306dd8622d7c622e27c970a1de31cb377b01af7307e"],["f16f804244e46e2a09232d4aff3b59976b98fac14328a2d1a32496b49998f247","cedabd9b82203f7e13d206fcdf4e33d92a6c53c26e5cce26d6579962c4e31df6"],["caf754272dc84563b0352b7a14311af55d245315ace27c65369e15f7151d41d1","cb474660ef35f5f2a41b643fa5e460575f4fa9b7962232a5c32f908318a04476"],["2600ca4b282cb986f85d0f1709979d8b44a09c07cb86d7c124497bc86f082120","4119b88753c15bd6a693b03fcddbb45d5ac6be74ab5f0ef44b0be9475a7e4b40"],["7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435","91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61"],["754e3239f325570cdbbf4a87deee8a66b7f2b33479d468fbc1a50743bf56cc18","673fb86e5bda30fb3cd0ed304ea49a023ee33d0197a695d0c5d98093c536683"],["e3e6bd1071a1e96aff57859c82d570f0330800661d1c952f9fe2694691d9b9e8","59c9e0bba394e76f40c0aa58379a3cb6a5a2283993e90c4167002af4920e37f5"],["186b483d056a033826ae73d88f732985c4ccb1f32ba35f4b4cc47fdcf04aa6eb","3b952d32c67cf77e2e17446e204180ab21fb8090895138b4a4a797f86e80888b"],["df9d70a6b9876ce544c98561f4be4f725442e6d2b737d9c91a8321724ce0963f","55eb2dafd84d6ccd5f862b785dc39d4ab157222720ef9da217b8c45cf2ba2417"],["5edd5cc23c51e87a497ca815d5dce0f8ab52554f849ed8995de64c5f34ce7143","efae9c8dbc14130661e8cec030c89ad0c13c66c0d17a2905cdc706ab7399a868"],["290798c2b6476830da12fe02287e9e777aa3fba1c355b17a722d362f84614fba","e38da76dcd440621988d00bcf79af25d5b29c094db2a23146d003afd41943e7a"],["af3c423a95d9f5b3054754efa150ac39cd29552fe360257362dfdecef4053b45","f98a3fd831eb2b749a93b0e6f35cfb40c8cd5aa667a15581bc2feded498fd9c6"],["766dbb24d134e745cccaa28c99bf274906bb66b26dcf98df8d2fed50d884249a","744b1152eacbe5e38dcc887980da38b897584a65fa06cedd2c924f97cbac5996"],["59dbf46f8c94759ba21277c33784f41645f7b44f6c596a58ce92e666191abe3e","c534ad44175fbc300f4ea6ce648309a042ce739a7919798cd85e216c4a307f6e"],["f13ada95103c4537305e691e74e9a4a8dd647e711a95e73cb62dc6018cfd87b8","e13817b44ee14de663bf4bc808341f326949e21a6a75c2570778419bdaf5733d"],["7754b4fa0e8aced06d4167a2c59cca4cda1869c06ebadfb6488550015a88522c","30e93e864e669d82224b967c3020b8fa8d1e4e350b6cbcc537a48b57841163a2"],["948dcadf5990e048aa3874d46abef9d701858f95de8041d2a6828c99e2262519","e491a42537f6e597d5d28a3224b1bc25df9154efbd2ef1d2cbba2cae5347d57e"],["7962414450c76c1689c7b48f8202ec37fb224cf5ac0bfa1570328a8a3d7c77ab","100b610ec4ffb4760d5c1fc133ef6f6b12507a051f04ac5760afa5b29db83437"],["3514087834964b54b15b160644d915485a16977225b8847bb0dd085137ec47ca","ef0afbb2056205448e1652c48e8127fc6039e77c15c2378b7e7d15a0de293311"],["d3cc30ad6b483e4bc79ce2c9dd8bc54993e947eb8df787b442943d3f7b527eaf","8b378a22d827278d89c5e9be8f9508ae3c2ad46290358630afb34db04eede0a4"],["1624d84780732860ce1c78fcbfefe08b2b29823db913f6493975ba0ff4847610","68651cf9b6da903e0914448c6cd9d4ca896878f5282be4c8cc06e2a404078575"],["733ce80da955a8a26902c95633e62a985192474b5af207da6df7b4fd5fc61cd4","f5435a2bd2badf7d485a4d8b8db9fcce3e1ef8e0201e4578c54673bc1dc5ea1d"],["15d9441254945064cf1a1c33bbd3b49f8966c5092171e699ef258dfab81c045c","d56eb30b69463e7234f5137b73b84177434800bacebfc685fc37bbe9efe4070d"],["a1d0fcf2ec9de675b612136e5ce70d271c21417c9d2b8aaaac138599d0717940","edd77f50bcb5a3cab2e90737309667f2641462a54070f3d519212d39c197a629"],["e22fbe15c0af8ccc5780c0735f84dbe9a790badee8245c06c7ca37331cb36980","a855babad5cd60c88b430a69f53a1a7a38289154964799be43d06d77d31da06"],["311091dd9860e8e20ee13473c1155f5f69635e394704eaa74009452246cfa9b3","66db656f87d1f04fffd1f04788c06830871ec5a64feee685bd80f0b1286d8374"],["34c1fd04d301be89b31c0442d3e6ac24883928b45a9340781867d4232ec2dbdf","9414685e97b1b5954bd46f730174136d57f1ceeb487443dc5321857ba73abee"],["f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63","4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1"],["d7b8740f74a8fbaab1f683db8f45de26543a5490bca627087236912469a0b448","fa77968128d9c92ee1010f337ad4717eff15db5ed3c049b3411e0315eaa4593b"],["32d31c222f8f6f0ef86f7c98d3a3335ead5bcd32abdd94289fe4d3091aa824bf","5f3032f5892156e39ccd3d7915b9e1da2e6dac9e6f26e961118d14b8462e1661"],["7461f371914ab32671045a155d9831ea8793d77cd59592c4340f86cbc18347b5","8ec0ba238b96bec0cbdddcae0aa442542eee1ff50c986ea6b39847b3cc092ff6"],["ee079adb1df1860074356a25aa38206a6d716b2c3e67453d287698bad7b2b2d6","8dc2412aafe3be5c4c5f37e0ecc5f9f6a446989af04c4e25ebaac479ec1c8c1e"],["16ec93e447ec83f0467b18302ee620f7e65de331874c9dc72bfd8616ba9da6b5","5e4631150e62fb40d0e8c2a7ca5804a39d58186a50e497139626778e25b0674d"],["eaa5f980c245f6f038978290afa70b6bd8855897f98b6aa485b96065d537bd99","f65f5d3e292c2e0819a528391c994624d784869d7e6ea67fb18041024edc07dc"],["78c9407544ac132692ee1910a02439958ae04877151342ea96c4b6b35a49f51","f3e0319169eb9b85d5404795539a5e68fa1fbd583c064d2462b675f194a3ddb4"],["494f4be219a1a77016dcd838431aea0001cdc8ae7a6fc688726578d9702857a5","42242a969283a5f339ba7f075e36ba2af925ce30d767ed6e55f4b031880d562c"],["a598a8030da6d86c6bc7f2f5144ea549d28211ea58faa70ebf4c1e665c1fe9b5","204b5d6f84822c307e4b4a7140737aec23fc63b65b35f86a10026dbd2d864e6b"],["c41916365abb2b5d09192f5f2dbeafec208f020f12570a184dbadc3e58595997","4f14351d0087efa49d245b328984989d5caf9450f34bfc0ed16e96b58fa9913"],["841d6063a586fa475a724604da03bc5b92a2e0d2e0a36acfe4c73a5514742881","73867f59c0659e81904f9a1c7543698e62562d6744c169ce7a36de01a8d6154"],["5e95bb399a6971d376026947f89bde2f282b33810928be4ded112ac4d70e20d5","39f23f366809085beebfc71181313775a99c9aed7d8ba38b161384c746012865"],["36e4641a53948fd476c39f8a99fd974e5ec07564b5315d8bf99471bca0ef2f66","d2424b1b1abe4eb8164227b085c9aa9456ea13493fd563e06fd51cf5694c78fc"],["336581ea7bfbbb290c191a2f507a41cf5643842170e914faeab27c2c579f726","ead12168595fe1be99252129b6e56b3391f7ab1410cd1e0ef3dcdcabd2fda224"],["8ab89816dadfd6b6a1f2634fcf00ec8403781025ed6890c4849742706bd43ede","6fdcef09f2f6d0a044e654aef624136f503d459c3e89845858a47a9129cdd24e"],["1e33f1a746c9c5778133344d9299fcaa20b0938e8acff2544bb40284b8c5fb94","60660257dd11b3aa9c8ed618d24edff2306d320f1d03010e33a7d2057f3b3b6"],["85b7c1dcb3cec1b7ee7f30ded79dd20a0ed1f4cc18cbcfcfa410361fd8f08f31","3d98a9cdd026dd43f39048f25a8847f4fcafad1895d7a633c6fed3c35e999511"],["29df9fbd8d9e46509275f4b125d6d45d7fbe9a3b878a7af872a2800661ac5f51","b4c4fe99c775a606e2d8862179139ffda61dc861c019e55cd2876eb2a27d84b"],["a0b1cae06b0a847a3fea6e671aaf8adfdfe58ca2f768105c8082b2e449fce252","ae434102edde0958ec4b19d917a6a28e6b72da1834aff0e650f049503a296cf2"],["4e8ceafb9b3e9a136dc7ff67e840295b499dfb3b2133e4ba113f2e4c0e121e5","cf2174118c8b6d7a4b48f6d534ce5c79422c086a63460502b827ce62a326683c"],["d24a44e047e19b6f5afb81c7ca2f69080a5076689a010919f42725c2b789a33b","6fb8d5591b466f8fc63db50f1c0f1c69013f996887b8244d2cdec417afea8fa3"],["ea01606a7a6c9cdd249fdfcfacb99584001edd28abbab77b5104e98e8e3b35d4","322af4908c7312b0cfbfe369f7a7b3cdb7d4494bc2823700cfd652188a3ea98d"],["af8addbf2b661c8a6c6328655eb96651252007d8c5ea31be4ad196de8ce2131f","6749e67c029b85f52a034eafd096836b2520818680e26ac8f3dfbcdb71749700"],["e3ae1974566ca06cc516d47e0fb165a674a3dabcfca15e722f0e3450f45889","2aeabe7e4531510116217f07bf4d07300de97e4874f81f533420a72eeb0bd6a4"],["591ee355313d99721cf6993ffed1e3e301993ff3ed258802075ea8ced397e246","b0ea558a113c30bea60fc4775460c7901ff0b053d25ca2bdeee98f1a4be5d196"],["11396d55fda54c49f19aa97318d8da61fa8584e47b084945077cf03255b52984","998c74a8cd45ac01289d5833a7beb4744ff536b01b257be4c5767bea93ea57a4"],["3c5d2a1ba39c5a1790000738c9e0c40b8dcdfd5468754b6405540157e017aa7a","b2284279995a34e2f9d4de7396fc18b80f9b8b9fdd270f6661f79ca4c81bd257"],["cc8704b8a60a0defa3a99a7299f2e9c3fbc395afb04ac078425ef8a1793cc030","bdd46039feed17881d1e0862db347f8cf395b74fc4bcdc4e940b74e3ac1f1b13"],["c533e4f7ea8555aacd9777ac5cad29b97dd4defccc53ee7ea204119b2889b197","6f0a256bc5efdf429a2fb6242f1a43a2d9b925bb4a4b3a26bb8e0f45eb596096"],["c14f8f2ccb27d6f109f6d08d03cc96a69ba8c34eec07bbcf566d48e33da6593","c359d6923bb398f7fd4473e16fe1c28475b740dd098075e6c0e8649113dc3a38"],["a6cbc3046bc6a450bac24789fa17115a4c9739ed75f8f21ce441f72e0b90e6ef","21ae7f4680e889bb130619e2c0f95a360ceb573c70603139862afd617fa9b9f"],["347d6d9a02c48927ebfb86c1359b1caf130a3c0267d11ce6344b39f99d43cc38","60ea7f61a353524d1c987f6ecec92f086d565ab687870cb12689ff1e31c74448"],["da6545d2181db8d983f7dcb375ef5866d47c67b1bf31c8cf855ef7437b72656a","49b96715ab6878a79e78f07ce5680c5d6673051b4935bd897fea824b77dc208a"],["c40747cc9d012cb1a13b8148309c6de7ec25d6945d657146b9d5994b8feb1111","5ca560753be2a12fc6de6caf2cb489565db936156b9514e1bb5e83037e0fa2d4"],["4e42c8ec82c99798ccf3a610be870e78338c7f713348bd34c8203ef4037f3502","7571d74ee5e0fb92a7a8b33a07783341a5492144cc54bcc40a94473693606437"],["3775ab7089bc6af823aba2e1af70b236d251cadb0c86743287522a1b3b0dedea","be52d107bcfa09d8bcb9736a828cfa7fac8db17bf7a76a2c42ad961409018cf7"],["cee31cbf7e34ec379d94fb814d3d775ad954595d1314ba8846959e3e82f74e26","8fd64a14c06b589c26b947ae2bcf6bfa0149ef0be14ed4d80f448a01c43b1c6d"],["b4f9eaea09b6917619f6ea6a4eb5464efddb58fd45b1ebefcdc1a01d08b47986","39e5c9925b5a54b07433a4f18c61726f8bb131c012ca542eb24a8ac07200682a"],["d4263dfc3d2df923a0179a48966d30ce84e2515afc3dccc1b77907792ebcc60e","62dfaf07a0f78feb30e30d6295853ce189e127760ad6cf7fae164e122a208d54"],["48457524820fa65a4f8d35eb6930857c0032acc0a4a2de422233eeda897612c4","25a748ab367979d98733c38a1fa1c2e7dc6cc07db2d60a9ae7a76aaa49bd0f77"],["dfeeef1881101f2cb11644f3a2afdfc2045e19919152923f367a1767c11cceda","ecfb7056cf1de042f9420bab396793c0c390bde74b4bbdff16a83ae09a9a7517"],["6d7ef6b17543f8373c573f44e1f389835d89bcbc6062ced36c82df83b8fae859","cd450ec335438986dfefa10c57fea9bcc521a0959b2d80bbf74b190dca712d10"],["e75605d59102a5a2684500d3b991f2e3f3c88b93225547035af25af66e04541f","f5c54754a8f71ee540b9b48728473e314f729ac5308b06938360990e2bfad125"],["eb98660f4c4dfaa06a2be453d5020bc99a0c2e60abe388457dd43fefb1ed620c","6cb9a8876d9cb8520609af3add26cd20a0a7cd8a9411131ce85f44100099223e"],["13e87b027d8514d35939f2e6892b19922154596941888336dc3563e3b8dba942","fef5a3c68059a6dec5d624114bf1e91aac2b9da568d6abeb2570d55646b8adf1"],["ee163026e9fd6fe017c38f06a5be6fc125424b371ce2708e7bf4491691e5764a","1acb250f255dd61c43d94ccc670d0f58f49ae3fa15b96623e5430da0ad6c62b2"],["b268f5ef9ad51e4d78de3a750c2dc89b1e626d43505867999932e5db33af3d80","5f310d4b3c99b9ebb19f77d41c1dee018cf0d34fd4191614003e945a1216e423"],["ff07f3118a9df035e9fad85eb6c7bfe42b02f01ca99ceea3bf7ffdba93c4750d","438136d603e858a3a5c440c38eccbaddc1d2942114e2eddd4740d098ced1f0d8"],["8d8b9855c7c052a34146fd20ffb658bea4b9f69e0d825ebec16e8c3ce2b526a1","cdb559eedc2d79f926baf44fb84ea4d44bcf50fee51d7ceb30e2e7f463036758"],["52db0b5384dfbf05bfa9d472d7ae26dfe4b851ceca91b1eba54263180da32b63","c3b997d050ee5d423ebaf66a6db9f57b3180c902875679de924b69d84a7b375"],["e62f9490d3d51da6395efd24e80919cc7d0f29c3f3fa48c6fff543becbd43352","6d89ad7ba4876b0b22c2ca280c682862f342c8591f1daf5170e07bfd9ccafa7d"],["7f30ea2476b399b4957509c88f77d0191afa2ff5cb7b14fd6d8e7d65aaab1193","ca5ef7d4b231c94c3b15389a5f6311e9daff7bb67b103e9880ef4bff637acaec"],["5098ff1e1d9f14fb46a210fada6c903fef0fb7b4a1dd1d9ac60a0361800b7a00","9731141d81fc8f8084d37c6e7542006b3ee1b40d60dfe5362a5b132fd17ddc0"],["32b78c7de9ee512a72895be6b9cbefa6e2f3c4ccce445c96b9f2c81e2778ad58","ee1849f513df71e32efc3896ee28260c73bb80547ae2275ba497237794c8753c"],["e2cb74fddc8e9fbcd076eef2a7c72b0ce37d50f08269dfc074b581550547a4f7","d3aa2ed71c9dd2247a62df062736eb0baddea9e36122d2be8641abcb005cc4a4"],["8438447566d4d7bedadc299496ab357426009a35f235cb141be0d99cd10ae3a8","c4e1020916980a4da5d01ac5e6ad330734ef0d7906631c4f2390426b2edd791f"],["4162d488b89402039b584c6fc6c308870587d9c46f660b878ab65c82c711d67e","67163e903236289f776f22c25fb8a3afc1732f2b84b4e95dbda47ae5a0852649"],["3fad3fa84caf0f34f0f89bfd2dcf54fc175d767aec3e50684f3ba4a4bf5f683d","cd1bc7cb6cc407bb2f0ca647c718a730cf71872e7d0d2a53fa20efcdfe61826"],["674f2600a3007a00568c1a7ce05d0816c1fb84bf1370798f1c69532faeb1a86b","299d21f9413f33b3edf43b257004580b70db57da0b182259e09eecc69e0d38a5"],["d32f4da54ade74abb81b815ad1fb3b263d82d6c692714bcff87d29bd5ee9f08f","f9429e738b8e53b968e99016c059707782e14f4535359d582fc416910b3eea87"],["30e4e670435385556e593657135845d36fbb6931f72b08cb1ed954f1e3ce3ff6","462f9bce619898638499350113bbc9b10a878d35da70740dc695a559eb88db7b"],["be2062003c51cc3004682904330e4dee7f3dcd10b01e580bf1971b04d4cad297","62188bc49d61e5428573d48a74e1c655b1c61090905682a0d5558ed72dccb9bc"],["93144423ace3451ed29e0fb9ac2af211cb6e84a601df5993c419859fff5df04a","7c10dfb164c3425f5c71a3f9d7992038f1065224f72bb9d1d902a6d13037b47c"],["b015f8044f5fcbdcf21ca26d6c34fb8197829205c7b7d2a7cb66418c157b112c","ab8c1e086d04e813744a655b2df8d5f83b3cdc6faa3088c1d3aea1454e3a1d5f"],["d5e9e1da649d97d89e4868117a465a3a4f8a18de57a140d36b3f2af341a21b52","4cb04437f391ed73111a13cc1d4dd0db1693465c2240480d8955e8592f27447a"],["d3ae41047dd7ca065dbf8ed77b992439983005cd72e16d6f996a5316d36966bb","bd1aeb21ad22ebb22a10f0303417c6d964f8cdd7df0aca614b10dc14d125ac46"],["463e2763d885f958fc66cdd22800f0a487197d0a82e377b49f80af87c897b065","bfefacdb0e5d0fd7df3a311a94de062b26b80c61fbc97508b79992671ef7ca7f"],["7985fdfd127c0567c6f53ec1bb63ec3158e597c40bfe747c83cddfc910641917","603c12daf3d9862ef2b25fe1de289aed24ed291e0ec6708703a5bd567f32ed03"],["74a1ad6b5f76e39db2dd249410eac7f99e74c59cb83d2d0ed5ff1543da7703e9","cc6157ef18c9c63cd6193d83631bbea0093e0968942e8c33d5737fd790e0db08"],["30682a50703375f602d416664ba19b7fc9bab42c72747463a71d0896b22f6da3","553e04f6b018b4fa6c8f39e7f311d3176290d0e0f19ca73f17714d9977a22ff8"],["9e2158f0d7c0d5f26c3791efefa79597654e7a2b2464f52b1ee6c1347769ef57","712fcdd1b9053f09003a3481fa7762e9ffd7c8ef35a38509e2fbf2629008373"],["176e26989a43c9cfeba4029c202538c28172e566e3c4fce7322857f3be327d66","ed8cc9d04b29eb877d270b4878dc43c19aefd31f4eee09ee7b47834c1fa4b1c3"],["75d46efea3771e6e68abb89a13ad747ecf1892393dfc4f1b7004788c50374da8","9852390a99507679fd0b86fd2b39a868d7efc22151346e1a3ca4726586a6bed8"],["809a20c67d64900ffb698c4c825f6d5f2310fb0451c869345b7319f645605721","9e994980d9917e22b76b061927fa04143d096ccc54963e6a5ebfa5f3f8e286c1"],["1b38903a43f7f114ed4500b4eac7083fdefece1cf29c63528d563446f972c180","4036edc931a60ae889353f77fd53de4a2708b26b6f5da72ad3394119daf408f9"]]}}});var Py=x(d9=>{"use strict";var n_=d9,hA=Ly(),r_=JS(),$0e=Kn(),l9=$0e.assert;function h9(e){e.type==="short"?this.curve=new r_.short(e):e.type==="edwards"?this.curve=new r_.edwards(e):this.curve=new r_.mont(e),this.g=this.curve.g,this.n=this.curve.n,this.hash=e.hash,l9(this.g.validate(),"Invalid curve"),l9(this.g.mul(this.n).isInfinity(),"Invalid curve, G*N != O")}n_.PresetCurve=h9;function dA(e,t){Object.defineProperty(n_,e,{configurable:!0,enumerable:!0,get:function(){var r=new h9(t);return Object.defineProperty(n_,e,{configurable:!0,enumerable:!0,value:r}),r}})}dA("p192",{type:"short",prime:"p192",p:"ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff",a:"ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc",b:"64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1",n:"ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831",hash:hA.sha256,gRed:!1,g:["188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012","07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811"]});dA("p224",{type:"short",prime:"p224",p:"ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001",a:"ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe",b:"b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4",n:"ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d",hash:hA.sha256,gRed:!1,g:["b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21","bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34"]});dA("p256",{type:"short",prime:null,p:"ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff",a:"ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc",b:"5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b",n:"ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551",hash:hA.sha256,gRed:!1,g:["6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296","4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5"]});dA("p384",{type:"short",prime:null,p:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe ffffffff 00000000 00000000 ffffffff",a:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe ffffffff 00000000 00000000 fffffffc",b:"b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef",n:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 f4372ddf 581a0db2 48b0a77a ecec196a ccc52973",hash:hA.sha384,gRed:!1,g:["aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7","3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f"]});dA("p521",{type:"short",prime:null,p:"000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff",a:"000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffc",b:"00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b 99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd 3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00",n:"000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409",hash:hA.sha512,gRed:!1,g:["000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66","00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 3fad0761 353c7086 a272c240 88be9476 9fd16650"]});dA("curve25519",{type:"mont",prime:"p25519",p:"7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed",a:"76d06",b:"1",n:"1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed",hash:hA.sha256,gRed:!1,g:["9"]});dA("ed25519",{type:"edwards",prime:"p25519",p:"7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed",a:"-1",c:"1",d:"52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3",n:"1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed",hash:hA.sha256,gRed:!1,g:["216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a","6666666666666666666666666666666666666666666666666666666666666658"]});var i_;try{i_=c9()}catch{i_=void 0}dA("secp256k1",{type:"short",prime:"k256",p:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f",a:"0",b:"7",n:"ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141",h:"1",hash:hA.sha256,beta:"7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee",lambda:"5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72",basis:[{a:"3086d221a7d46bcde86c90e49284eb15",b:"-e4437ed6010e88286f547fa90abfe4c3"},{a:"114ca50f7a8e2f3f657c1108d9d44cfd8",b:"3086d221a7d46bcde86c90e49284eb15"}],gRed:!1,g:["79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",i_]})});var E9=x((ZMe,p9)=>{"use strict";var epe=Ly(),Uf=WS(),g9=zn();function gA(e){if(!(this instanceof gA))return new gA(e);this.hash=e.hash,this.predResist=!!e.predResist,this.outLen=this.hash.outSize,this.minEntropy=e.minEntropy||this.hash.hmacStrength,this._reseed=null,this.reseedInterval=null,this.K=null,this.V=null;var t=Uf.toArray(e.entropy,e.entropyEnc||"hex"),r=Uf.toArray(e.nonce,e.nonceEnc||"hex"),n=Uf.toArray(e.pers,e.persEnc||"hex");g9(t.length>=this.minEntropy/8,"Not enough entropy. Minimum is: "+this.minEntropy+" bits"),this._init(t,r,n)}p9.exports=gA;gA.prototype._init=function(t,r,n){var i=t.concat(r).concat(n);this.K=new Array(this.outLen/8),this.V=new Array(this.outLen/8);for(var s=0;s=this.minEntropy/8,"Not enough entropy. Minimum is: "+this.minEntropy+" bits"),this._update(t.concat(n||[])),this._reseed=1};gA.prototype.generate=function(t,r,n,i){if(this._reseed>this.reseedInterval)throw new Error("Reseed is required");typeof r!="string"&&(i=n,n=r,r=null),n&&(n=Uf.toArray(n,i||"hex"),this._update(n));for(var s=[];s.length{"use strict";var tpe=kr(),rpe=Kn(),s_=rpe.assert;function An(e,t){this.ec=e,this.priv=null,this.pub=null,t.priv&&this._importPrivate(t.priv,t.privEnc),t.pub&&this._importPublic(t.pub,t.pubEnc)}y9.exports=An;An.fromPublic=function(t,r,n){return r instanceof An?r:new An(t,{pub:r,pubEnc:n})};An.fromPrivate=function(t,r,n){return r instanceof An?r:new An(t,{priv:r,privEnc:n})};An.prototype.validate=function(){var t=this.getPublic();return t.isInfinity()?{result:!1,reason:"Invalid public key"}:t.validate()?t.mul(this.ec.curve.n).isInfinity()?{result:!0,reason:null}:{result:!1,reason:"Public key * N != O"}:{result:!1,reason:"Public key is not a point"}};An.prototype.getPublic=function(t,r){return typeof t=="string"&&(r=t,t=null),this.pub||(this.pub=this.ec.g.mul(this.priv)),r?this.pub.encode(r,t):this.pub};An.prototype.getPrivate=function(t){return t==="hex"?this.priv.toString(16,2):this.priv};An.prototype._importPrivate=function(t,r){this.priv=new tpe(t,r||16),this.priv=this.priv.umod(this.ec.curve.n)};An.prototype._importPublic=function(t,r){if(t.x||t.y){this.ec.curve.type==="mont"?s_(t.x,"Need x coordinate"):(this.ec.curve.type==="short"||this.ec.curve.type==="edwards")&&s_(t.x&&t.y,"Need both x and y coordinate"),this.pub=this.ec.curve.point(t.x,t.y);return}this.pub=this.ec.curve.decodePoint(t,r)};An.prototype.derive=function(t){return t.validate()||s_(t.validate(),"public point not validated"),t.mul(this.priv).getX()};An.prototype.sign=function(t,r,n){return this.ec.sign(t,this,r,n)};An.prototype.verify=function(t,r,n){return this.ec.verify(t,r,this,void 0,n)};An.prototype.inspect=function(){return""}});var b9=x((eFe,I9)=>{"use strict";var Oy=kr(),A_=Kn(),npe=A_.assert;function Hy(e,t){if(e instanceof Hy)return e;this._importDER(e,t)||(npe(e.r&&e.s,"Signature without r or s"),this.r=new Oy(e.r,16),this.s=new Oy(e.s,16),e.recoveryParam===void 0?this.recoveryParam=null:this.recoveryParam=e.recoveryParam)}I9.exports=Hy;function ipe(){this.place=0}function o_(e,t){var r=e[t.place++];if(!(r&128))return r;var n=r&15;if(n===0||n>4||e[t.place]===0)return!1;for(var i=0,s=0,o=t.place;s>>=0;return i<=127?!1:(t.place=o,i)}function B9(e){for(var t=0,r=e.length-1;!e[t]&&!(e[t+1]&128)&&t>>3);for(e.push(r|128);--r;)e.push(t>>>(r<<3)&255);e.push(t)}Hy.prototype.toDER=function(t){var r=this.r.toArray(),n=this.s.toArray();for(r[0]&128&&(r=[0].concat(r)),n[0]&128&&(n=[0].concat(n)),r=B9(r),n=B9(n);!n[0]&&!(n[1]&128);)n=n.slice(1);var i=[2];a_(i,r.length),i=i.concat(r),i.push(2),a_(i,n.length);var s=i.concat(n),o=[48];return a_(o,s.length),o=o.concat(s),A_.encode(o,t)}});var w9=x((tFe,Q9)=>{"use strict";var hs=kr(),C9=E9(),spe=Kn(),f_=Py(),ope=Qy(),Lf=spe.assert,u_=m9(),qy=b9();function _i(e){if(!(this instanceof _i))return new _i(e);typeof e=="string"&&(Lf(Object.prototype.hasOwnProperty.call(f_,e),"Unknown curve "+e),e=f_[e]),e instanceof f_.PresetCurve&&(e={curve:e}),this.curve=e.curve.curve,this.n=this.curve.n,this.nh=this.n.ushrn(1),this.g=this.curve.g,this.g=e.curve.g,this.g.precompute(e.curve.n.bitLength()+1),this.hash=e.hash||e.curve.hash}Q9.exports=_i;_i.prototype.keyPair=function(t){return new u_(this,t)};_i.prototype.keyFromPrivate=function(t,r){return u_.fromPrivate(this,t,r)};_i.prototype.keyFromPublic=function(t,r){return u_.fromPublic(this,t,r)};_i.prototype.genKeyPair=function(t){t||(t={});for(var r=new C9({hash:this.hash,pers:t.pers,persEnc:t.persEnc||"utf8",entropy:t.entropy||ope(this.hash.hmacStrength),entropyEnc:t.entropy&&t.entropyEnc||"utf8",nonce:this.n.toArray()}),n=this.n.byteLength(),i=this.n.sub(new hs(2));;){var s=new hs(r.generate(n));if(!(s.cmp(i)>0))return s.iaddn(1),this.keyFromPrivate(s)}};_i.prototype._truncateToN=function(t,r,n){var i;if(hs.isBN(t)||typeof t=="number")t=new hs(t,16),i=t.byteLength();else if(typeof t=="object")i=t.length,t=new hs(t,16);else{var s=t.toString();i=s.length+1>>>1,t=new hs(s,16)}typeof n!="number"&&(n=i*8);var o=n-this.n.bitLength();return o>0&&(t=t.ushrn(o)),!r&&t.cmp(this.n)>=0?t.sub(this.n):t};_i.prototype.sign=function(t,r,n,i){if(typeof n=="object"&&(i=n,n=null),i||(i={}),typeof t!="string"&&typeof t!="number"&&!hs.isBN(t)){Lf(typeof t=="object"&&t&&typeof t.length=="number","Expected message to be an array-like, a hex string, or a BN instance"),Lf(t.length>>>0===t.length);for(var s=0;s=0)){var S=this.g.mul(B);if(!S.isInfinity()){var _=S.getX(),N=_.umod(this.n);if(N.cmpn(0)!==0){var P=B.invm(this.n).mul(N.mul(r.getPrivate()).iadd(t));if(P=P.umod(this.n),P.cmpn(0)!==0){var U=(S.getY().isOdd()?1:0)|(_.cmp(N)!==0?2:0);return i.canonical&&P.cmp(this.nh)>0&&(P=this.n.sub(P),U^=1),new qy({r:N,s:P,recoveryParam:U})}}}}}};_i.prototype.verify=function(t,r,n,i,s){s||(s={}),t=this._truncateToN(t,!1,s.msgBitLength),n=this.keyFromPublic(n,i),r=new qy(r,"hex");var o=r.r,a=r.s;if(o.cmpn(1)<0||o.cmp(this.n)>=0||a.cmpn(1)<0||a.cmp(this.n)>=0)return!1;var A=a.invm(this.n),f=A.mul(t).umod(this.n),l=A.mul(o).umod(this.n),p;return this.curve._maxwellTrick?(p=this.g.jmulAdd(f,n.getPublic(),l),p.isInfinity()?!1:p.eqXToP(o)):(p=this.g.mulAdd(f,n.getPublic(),l),p.isInfinity()?!1:p.getX().umod(this.n).cmp(o)===0)};_i.prototype.recoverPubKey=function(e,t,r,n){Lf((3&r)===r,"The recovery param is more than two bits"),t=new qy(t,n);var i=this.n,s=new hs(e),o=t.r,a=t.s,A=r&1,f=r>>1;if(o.cmp(this.curve.p.umod(this.curve.n))>=0&&f)throw new Error("Unable to find sencond key candinate");f?o=this.curve.pointFromX(o.add(this.curve.n),A):o=this.curve.pointFromX(o,A);var l=t.r.invm(i),p=i.sub(s).mul(l).umod(i),B=a.mul(l).umod(i);return this.g.mulAdd(p,o,B)};_i.prototype.getKeyRecoveryParam=function(e,t,r,n){if(t=new qy(t,n),t.recoveryParam!==null)return t.recoveryParam;for(var i=0;i<4;i++){var s;try{s=this.recoverPubKey(e,t,i)}catch{continue}if(s.eq(r))return i}throw new Error("Unable to find valid recovery factor")}});var R9=x((rFe,v9)=>{"use strict";var Od=Kn(),_9=Od.assert,S9=Od.parseBytes,Zc=Od.cachedProperty;function Lr(e,t){this.eddsa=e,this._secret=S9(t.secret),e.isPoint(t.pub)?this._pub=t.pub:this._pubBytes=S9(t.pub)}Lr.fromPublic=function(t,r){return r instanceof Lr?r:new Lr(t,{pub:r})};Lr.fromSecret=function(t,r){return r instanceof Lr?r:new Lr(t,{secret:r})};Lr.prototype.secret=function(){return this._secret};Zc(Lr,"pubBytes",function(){return this.eddsa.encodePoint(this.pub())});Zc(Lr,"pub",function(){return this._pubBytes?this.eddsa.decodePoint(this._pubBytes):this.eddsa.g.mul(this.priv())});Zc(Lr,"privBytes",function(){var t=this.eddsa,r=this.hash(),n=t.encodingLength-1,i=r.slice(0,t.encodingLength);return i[0]&=248,i[n]&=127,i[n]|=64,i});Zc(Lr,"priv",function(){return this.eddsa.decodeInt(this.privBytes())});Zc(Lr,"hash",function(){return this.eddsa.hash().update(this.secret()).digest()});Zc(Lr,"messagePrefix",function(){return this.hash().slice(this.eddsa.encodingLength)});Lr.prototype.sign=function(t){return _9(this._secret,"KeyPair can only verify"),this.eddsa.sign(t,this)};Lr.prototype.verify=function(t,r){return this.eddsa.verify(t,r,this)};Lr.prototype.getSecret=function(t){return _9(this._secret,"KeyPair is public only"),Od.encode(this.secret(),t)};Lr.prototype.getPublic=function(t){return Od.encode(this.pubBytes(),t)};v9.exports=Lr});var N9=x((nFe,T9)=>{"use strict";var ape=kr(),Gy=Kn(),D9=Gy.assert,Yy=Gy.cachedProperty,Ape=Gy.parseBytes;function Pf(e,t){this.eddsa=e,typeof t!="object"&&(t=Ape(t)),Array.isArray(t)&&(D9(t.length===e.encodingLength*2,"Signature has invalid size"),t={R:t.slice(0,e.encodingLength),S:t.slice(e.encodingLength)}),D9(t.R&&t.S,"Signature without R or S"),e.isPoint(t.R)&&(this._R=t.R),t.S instanceof ape&&(this._S=t.S),this._Rencoded=Array.isArray(t.R)?t.R:t.Rencoded,this._Sencoded=Array.isArray(t.S)?t.S:t.Sencoded}Yy(Pf,"S",function(){return this.eddsa.decodeInt(this.Sencoded())});Yy(Pf,"R",function(){return this.eddsa.decodePoint(this.Rencoded())});Yy(Pf,"Rencoded",function(){return this.eddsa.encodePoint(this.R())});Yy(Pf,"Sencoded",function(){return this.eddsa.encodeInt(this.S())});Pf.prototype.toBytes=function(){return this.Rencoded().concat(this.Sencoded())};Pf.prototype.toHex=function(){return Gy.encode(this.toBytes(),"hex").toUpperCase()};T9.exports=Pf});var U9=x((iFe,x9)=>{"use strict";var fpe=Ly(),upe=Py(),$c=Kn(),cpe=$c.assert,F9=$c.parseBytes,k9=R9(),M9=N9();function kn(e){if(cpe(e==="ed25519","only tested with ed25519 so far"),!(this instanceof kn))return new kn(e);e=upe[e].curve,this.curve=e,this.g=e.g,this.g.precompute(e.n.bitLength()+1),this.pointClass=e.point().constructor,this.encodingLength=Math.ceil(e.n.bitLength()/8),this.hash=fpe.sha512}x9.exports=kn;kn.prototype.sign=function(t,r){t=F9(t);var n=this.keyFromSecret(r),i=this.hashInt(n.messagePrefix(),t),s=this.g.mul(i),o=this.encodePoint(s),a=this.hashInt(o,n.pubBytes(),t).mul(n.priv()),A=i.add(a).umod(this.curve.n);return this.makeSignature({R:s,S:A,Rencoded:o})};kn.prototype.verify=function(t,r,n){if(t=F9(t),r=this.makeSignature(r),r.S().gte(r.eddsa.curve.n)||r.S().isNeg())return!1;var i=this.keyFromPublic(n),s=this.hashInt(r.Rencoded(),i.pubBytes(),t),o=this.g.mul(r.S()),a=r.R().add(i.pub().mul(s));return a.eq(o)};kn.prototype.hashInt=function(){for(var t=this.hash(),r=0;r{"use strict";var Of=L9;Of.version=pP().version;Of.utils=Kn();Of.rand=Qy();Of.curve=JS();Of.curves=Py();Of.ec=w9();Of.eddsa=U9()});var P9=x((exports,module)=>{var indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var r=0;r{var O9=tl(),lpe=ze(),hpe=H9;hpe.define=function(t,r){return new el(t,r)};function el(e,t){this.name=e,this.body=t,this.decoders={},this.encoders={}}el.prototype._createNamed=function(t){var r;try{r=P9().runInThisContext("(function "+this.name+`(entity) { - this._initNamed(entity); -})`)}catch{r=function(i){this._initNamed(i)}}return lpe(r,t),r.prototype._initNamed=function(i){t.call(this,i)},new r(this)};el.prototype._getDecoder=function(t){return t=t||"der",this.decoders.hasOwnProperty(t)||(this.decoders[t]=this._createNamed(O9.decoders[t])),this.decoders[t]};el.prototype.decode=function(t,r,n){return this._getDecoder(r).decode(t,n)};el.prototype._getEncoder=function(t){return t=t||"der",this.encoders.hasOwnProperty(t)||(this.encoders[t]=this._createNamed(O9.encoders[t])),this.encoders[t]};el.prototype.encode=function(t,r,n){return this._getEncoder(r).encode(t,n)}});var Y9=x(G9=>{var dpe=ze();function vi(e){this._reporterState={obj:null,path:[],options:e||{},errors:[]}}G9.Reporter=vi;vi.prototype.isError=function(t){return t instanceof rl};vi.prototype.save=function(){var t=this._reporterState;return{obj:t.obj,pathLen:t.path.length}};vi.prototype.restore=function(t){var r=this._reporterState;r.obj=t.obj,r.path=r.path.slice(0,t.pathLen)};vi.prototype.enterKey=function(t){return this._reporterState.path.push(t)};vi.prototype.exitKey=function(t){var r=this._reporterState;r.path=r.path.slice(0,t-1)};vi.prototype.leaveKey=function(t,r,n){var i=this._reporterState;this.exitKey(t),i.obj!==null&&(i.obj[r]=n)};vi.prototype.path=function(){return this._reporterState.path.join("/")};vi.prototype.enterObject=function(){var t=this._reporterState,r=t.obj;return t.obj={},r};vi.prototype.leaveObject=function(t){var r=this._reporterState,n=r.obj;return r.obj=t,n};vi.prototype.error=function(t){var r,n=this._reporterState,i=t instanceof rl;if(i?r=t:r=new rl(n.path.map(function(s){return"["+JSON.stringify(s)+"]"}).join(""),t.message||t,t.stack),!n.options.partial)throw r;return i||n.errors.push(r),r};vi.prototype.wrapResult=function(t){var r=this._reporterState;return r.options.partial?{result:this.isError(t)?null:t,errors:r.errors}:t};function rl(e,t){this.path=e,this.rethrow(t)}dpe(rl,Error);rl.prototype.rethrow=function(t){if(this.message=t+" at: "+(this.path||"(shallow)"),Error.captureStackTrace&&Error.captureStackTrace(this,rl),!this.stack)try{throw new Error(this.message)}catch(r){this.stack=r.stack}return this}});var l_=x(c_=>{var gpe=ze(),Jy=nl().Reporter,Hd=Gr().Buffer;function ho(e,t){if(Jy.call(this,t),!Hd.isBuffer(e)){this.error("Input not Buffer");return}this.base=e,this.offset=0,this.length=e.length}gpe(ho,Jy);c_.DecoderBuffer=ho;ho.prototype.save=function(){return{offset:this.offset,reporter:Jy.prototype.save.call(this)}};ho.prototype.restore=function(t){var r=new ho(this.base);return r.offset=t.offset,r.length=this.offset,this.offset=t.offset,Jy.prototype.restore.call(this,t.reporter),r};ho.prototype.isEmpty=function(){return this.offset===this.length};ho.prototype.readUInt8=function(t){return this.offset+1<=this.length?this.base.readUInt8(this.offset++,!0):this.error(t||"DecoderBuffer overrun")};ho.prototype.skip=function(t,r){if(!(this.offset+t<=this.length))return this.error(r||"DecoderBuffer overrun");var n=new ho(this.base);return n._reporterState=this._reporterState,n.offset=this.offset,n.length=this.offset+t,this.offset+=t,n};ho.prototype.raw=function(t){return this.base.slice(t?t.offset:this.offset,this.length)};function Vy(e,t){if(Array.isArray(e))this.length=0,this.value=e.map(function(r){return r instanceof Vy||(r=new Vy(r,t)),this.length+=r.length,r},this);else if(typeof e=="number"){if(!(0<=e&&e<=255))return t.error("non-byte EncoderBuffer value");this.value=e,this.length=1}else if(typeof e=="string")this.value=e,this.length=Hd.byteLength(e);else if(Hd.isBuffer(e))this.value=e,this.length=e.length;else return t.error("Unsupported type: "+typeof e)}c_.EncoderBuffer=Vy;Vy.prototype.join=function(t,r){return t||(t=new Hd(this.length)),r||(r=0),this.length===0||(Array.isArray(this.value)?this.value.forEach(function(n){n.join(t,r),r+=n.length}):(typeof this.value=="number"?t[r]=this.value:typeof this.value=="string"?t.write(this.value,r):Hd.isBuffer(this.value)&&this.value.copy(t,r),r+=this.length)),t}});var J9=x((fFe,V9)=>{var ppe=nl().Reporter,Epe=nl().EncoderBuffer,ype=nl().DecoderBuffer,En=zn(),W9=["seq","seqof","set","setof","objid","bool","gentime","utctime","null_","enum","int","objDesc","bitstr","bmpstr","charstr","genstr","graphstr","ia5str","iso646str","numstr","octstr","printstr","t61str","unistr","utf8str","videostr"],mpe=["key","obj","use","optional","explicit","implicit","def","choice","any","contains"].concat(W9),Bpe=["_peekTag","_decodeTag","_use","_decodeStr","_decodeObjid","_decodeTime","_decodeNull","_decodeInt","_decodeBool","_decodeList","_encodeComposite","_encodeStr","_encodeObjid","_encodeTime","_encodeNull","_encodeInt","_encodeBool"];function Ut(e,t){var r={};this._baseState=r,r.enc=e,r.parent=t||null,r.children=null,r.tag=null,r.args=null,r.reverseArgs=null,r.choice=null,r.optional=!1,r.any=!1,r.obj=!1,r.use=null,r.useDecoder=null,r.key=null,r.default=null,r.explicit=null,r.implicit=null,r.contains=null,r.parent||(r.children=[],this._wrap())}V9.exports=Ut;var Ipe=["enc","parent","children","tag","args","reverseArgs","choice","optional","any","obj","use","alteredUse","key","default","explicit","implicit","contains"];Ut.prototype.clone=function(){var t=this._baseState,r={};Ipe.forEach(function(i){r[i]=t[i]});var n=new this.constructor(r.parent);return n._baseState=r,n};Ut.prototype._wrap=function(){var t=this._baseState;mpe.forEach(function(r){this[r]=function(){var i=new this.constructor(this);return t.children.push(i),i[r].apply(i,arguments)}},this)};Ut.prototype._init=function(t){var r=this._baseState;En(r.parent===null),t.call(this),r.children=r.children.filter(function(n){return n._baseState.parent===this},this),En.equal(r.children.length,1,"Root node can have only one child")};Ut.prototype._useArgs=function(t){var r=this._baseState,n=t.filter(function(i){return i instanceof this.constructor},this);t=t.filter(function(i){return!(i instanceof this.constructor)},this),n.length!==0&&(En(r.children===null),r.children=n,n.forEach(function(i){i._baseState.parent=this},this)),t.length!==0&&(En(r.args===null),r.args=t,r.reverseArgs=t.map(function(i){if(typeof i!="object"||i.constructor!==Object)return i;var s={};return Object.keys(i).forEach(function(o){o==(o|0)&&(o|=0);var a=i[o];s[a]=o}),s}))};Bpe.forEach(function(e){Ut.prototype[e]=function(){var r=this._baseState;throw new Error(e+" not implemented for encoding: "+r.enc)}});W9.forEach(function(e){Ut.prototype[e]=function(){var r=this._baseState,n=Array.prototype.slice.call(arguments);return En(r.tag===null),r.tag=e,this._useArgs(n),this}});Ut.prototype.use=function(t){En(t);var r=this._baseState;return En(r.use===null),r.use=t,this};Ut.prototype.optional=function(){var t=this._baseState;return t.optional=!0,this};Ut.prototype.def=function(t){var r=this._baseState;return En(r.default===null),r.default=t,r.optional=!0,this};Ut.prototype.explicit=function(t){var r=this._baseState;return En(r.explicit===null&&r.implicit===null),r.explicit=t,this};Ut.prototype.implicit=function(t){var r=this._baseState;return En(r.explicit===null&&r.implicit===null),r.implicit=t,this};Ut.prototype.obj=function(){var t=this._baseState,r=Array.prototype.slice.call(arguments);return t.obj=!0,r.length!==0&&this._useArgs(r),this};Ut.prototype.key=function(t){var r=this._baseState;return En(r.key===null),r.key=t,this};Ut.prototype.any=function(){var t=this._baseState;return t.any=!0,this};Ut.prototype.choice=function(t){var r=this._baseState;return En(r.choice===null),r.choice=t,this._useArgs(Object.keys(t).map(function(n){return t[n]})),this};Ut.prototype.contains=function(t){var r=this._baseState;return En(r.use===null),r.contains=t,this};Ut.prototype._decode=function(t,r){var n=this._baseState;if(n.parent===null)return t.wrapResult(n.children[0]._decode(t,r));var i=n.default,s=!0,o=null;if(n.key!==null&&(o=t.enterKey(n.key)),n.optional){var a=null;if(n.explicit!==null?a=n.explicit:n.implicit!==null?a=n.implicit:n.tag!==null&&(a=n.tag),a===null&&!n.any){var A=t.save();try{n.choice===null?this._decodeGeneric(n.tag,t,r):this._decodeChoice(t,r),s=!0}catch{s=!1}t.restore(A)}else if(s=this._peekTag(t,a,n.any),t.isError(s))return s}var f;if(n.obj&&s&&(f=t.enterObject()),s){if(n.explicit!==null){var l=this._decodeTag(t,n.explicit);if(t.isError(l))return l;t=l}var p=t.offset;if(n.use===null&&n.choice===null){if(n.any)var A=t.save();var B=this._decodeTag(t,n.implicit!==null?n.implicit:n.tag,n.any);if(t.isError(B))return B;n.any?i=t.raw(A):t=B}if(r&&r.track&&n.tag!==null&&r.track(t.path(),p,t.length,"tagged"),r&&r.track&&n.tag!==null&&r.track(t.path(),t.offset,t.length,"content"),n.any?i=i:n.choice===null?i=this._decodeGeneric(n.tag,t,r):i=this._decodeChoice(t,r),t.isError(i))return i;if(!n.any&&n.choice===null&&n.children!==null&&n.children.forEach(function(N){N._decode(t,r)}),n.contains&&(n.tag==="octstr"||n.tag==="bitstr")){var S=new ype(i);i=this._getUse(n.contains,t._reporterState.obj)._decode(S,r)}}return n.obj&&s&&(i=t.leaveObject(f)),n.key!==null&&(i!==null||s===!0)?t.leaveKey(o,n.key,i):o!==null&&t.exitKey(o),i};Ut.prototype._decodeGeneric=function(t,r,n){var i=this._baseState;return t==="seq"||t==="set"?null:t==="seqof"||t==="setof"?this._decodeList(r,t,i.args[0],n):/str$/.test(t)?this._decodeStr(r,t,n):t==="objid"&&i.args?this._decodeObjid(r,i.args[0],i.args[1],n):t==="objid"?this._decodeObjid(r,null,null,n):t==="gentime"||t==="utctime"?this._decodeTime(r,t,n):t==="null_"?this._decodeNull(r,n):t==="bool"?this._decodeBool(r,n):t==="objDesc"?this._decodeStr(r,t,n):t==="int"||t==="enum"?this._decodeInt(r,i.args&&i.args[0],n):i.use!==null?this._getUse(i.use,r._reporterState.obj)._decode(r,n):r.error("unknown tag: "+t)};Ut.prototype._getUse=function(t,r){var n=this._baseState;return n.useDecoder=this._use(t,r),En(n.useDecoder._baseState.parent===null),n.useDecoder=n.useDecoder._baseState.children[0],n.implicit!==n.useDecoder._baseState.implicit&&(n.useDecoder=n.useDecoder.clone(),n.useDecoder._baseState.implicit=n.implicit),n.useDecoder};Ut.prototype._decodeChoice=function(t,r){var n=this._baseState,i=null,s=!1;return Object.keys(n.choice).some(function(o){var a=t.save(),A=n.choice[o];try{var f=A._decode(t,r);if(t.isError(f))return!1;i={type:o,value:f},s=!0}catch{return t.restore(a),!1}return!0},this),s?i:t.error("Choice not matched")};Ut.prototype._createEncoderBuffer=function(t){return new Epe(t,this.reporter)};Ut.prototype._encode=function(t,r,n){var i=this._baseState;if(!(i.default!==null&&i.default===t)){var s=this._encodeValue(t,r,n);if(s!==void 0&&!this._skipDefault(s,r,n))return s}};Ut.prototype._encodeValue=function(t,r,n){var i=this._baseState;if(i.parent===null)return i.children[0]._encode(t,r||new ppe);var A=null;if(this.reporter=r,i.optional&&t===void 0)if(i.default!==null)t=i.default;else return;var s=null,o=!1;if(i.any)A=this._createEncoderBuffer(t);else if(i.choice)A=this._encodeChoice(t,r);else if(i.contains)s=this._getUse(i.contains,n)._encode(t,r),o=!0;else if(i.children)s=i.children.map(function(p){if(p._baseState.tag==="null_")return p._encode(null,r,t);if(p._baseState.key===null)return r.error("Child should have a key");var B=r.enterKey(p._baseState.key);if(typeof t!="object")return r.error("Child expected, but input is not object");var S=p._encode(t[p._baseState.key],r,t);return r.leaveKey(B),S},this).filter(function(p){return p}),s=this._createEncoderBuffer(s);else if(i.tag==="seqof"||i.tag==="setof"){if(!(i.args&&i.args.length===1))return r.error("Too many args for : "+i.tag);if(!Array.isArray(t))return r.error("seqof/setof, but data is not Array");var a=this.clone();a._baseState.implicit=null,s=this._createEncoderBuffer(t.map(function(p){var B=this._baseState;return this._getUse(B.args[0],t)._encode(p,r)},a))}else i.use!==null?A=this._getUse(i.use,n)._encode(t,r):(s=this._encodePrimitive(i.tag,t),o=!0);var A;if(!i.any&&i.choice===null){var f=i.implicit!==null?i.implicit:i.tag,l=i.implicit===null?"universal":"context";f===null?i.use===null&&r.error("Tag could be omitted only for .use()"):i.use===null&&(A=this._encodeComposite(f,o,l,s))}return i.explicit!==null&&(A=this._encodeComposite(i.explicit,!1,"context",A)),A};Ut.prototype._encodeChoice=function(t,r){var n=this._baseState,i=n.choice[t.type];return i||En(!1,t.type+" not found in "+JSON.stringify(Object.keys(n.choice))),i._encode(t.value,r)};Ut.prototype._encodePrimitive=function(t,r){var n=this._baseState;if(/str$/.test(t))return this._encodeStr(r,t);if(t==="objid"&&n.args)return this._encodeObjid(r,n.reverseArgs[0],n.args[1]);if(t==="objid")return this._encodeObjid(r,null,null);if(t==="gentime"||t==="utctime")return this._encodeTime(r,t);if(t==="null_")return this._encodeNull();if(t==="int"||t==="enum")return this._encodeInt(r,n.args&&n.reverseArgs[0]);if(t==="bool")return this._encodeBool(r);if(t==="objDesc")return this._encodeStr(r,t);throw new Error("Unsupported tag: "+t)};Ut.prototype._isNumstr=function(t){return/^[0-9 ]*$/.test(t)};Ut.prototype._isPrintstr=function(t){return/^[A-Za-z0-9 '\(\)\+,\-\.\/:=\?]*$/.test(t)}});var nl=x(j9=>{var jy=j9;jy.Reporter=Y9().Reporter;jy.DecoderBuffer=l_().DecoderBuffer;jy.EncoderBuffer=l_().EncoderBuffer;jy.Node=J9()});var K9=x(Hf=>{var z9=h_();Hf.tagClass={0:"universal",1:"application",2:"context",3:"private"};Hf.tagClassByName=z9._reverse(Hf.tagClass);Hf.tag={0:"end",1:"bool",2:"int",3:"bitstr",4:"octstr",5:"null_",6:"objid",7:"objDesc",8:"external",9:"real",10:"enum",11:"embed",12:"utf8str",13:"relativeOid",16:"seq",17:"set",18:"numstr",19:"printstr",20:"t61str",21:"videostr",22:"ia5str",23:"utctime",24:"gentime",25:"graphstr",26:"iso646str",27:"genstr",28:"unistr",29:"charstr",30:"bmpstr"};Hf.tagByName=z9._reverse(Hf.tag)});var h_=x(Z9=>{var X9=Z9;X9._reverse=function(t){var r={};return Object.keys(t).forEach(function(n){(n|0)==n&&(n=n|0);var i=t[n];r[i]=n}),r};X9.der=K9()});var p_=x((hFe,rO)=>{var bpe=ze(),d_=tl(),zy=d_.base,Cpe=d_.bignum,$9=d_.constants.der;function eO(e){this.enc="der",this.name=e.name,this.entity=e,this.tree=new Xn,this.tree._init(e.body)}rO.exports=eO;eO.prototype.decode=function(t,r){return t instanceof zy.DecoderBuffer||(t=new zy.DecoderBuffer(t,r)),this.tree._decode(t,r)};function Xn(e){zy.Node.call(this,"der",e)}bpe(Xn,zy.Node);Xn.prototype._peekTag=function(t,r,n){if(t.isEmpty())return!1;var i=t.save(),s=g_(t,'Failed to peek tag: "'+r+'"');return t.isError(s)?s:(t.restore(i),s.tag===r||s.tagStr===r||s.tagStr+"of"===r||n)};Xn.prototype._decodeTag=function(t,r,n){var i=g_(t,'Failed to decode tag of "'+r+'"');if(t.isError(i))return i;var s=tO(t,i.primitive,'Failed to get length of "'+r+'"');if(t.isError(s))return s;if(!n&&i.tag!==r&&i.tagStr!==r&&i.tagStr+"of"!==r)return t.error('Failed to match tag: "'+r+'"');if(i.primitive||s!==null)return t.skip(s,'Failed to match body of: "'+r+'"');var o=t.save(),a=this._skipUntilEnd(t,'Failed to skip indefinite length body: "'+this.tag+'"');return t.isError(a)?a:(s=t.offset-o.offset,t.restore(o),t.skip(s,'Failed to match body of: "'+r+'"'))};Xn.prototype._skipUntilEnd=function(t,r){for(;;){var n=g_(t,r);if(t.isError(n))return n;var i=tO(t,n.primitive,r);if(t.isError(i))return i;var s;if(n.primitive||i!==null?s=t.skip(i):s=this._skipUntilEnd(t,r),t.isError(s))return s;if(n.tagStr==="end")break}};Xn.prototype._decodeList=function(t,r,n,i){for(var s=[];!t.isEmpty();){var o=this._peekTag(t,"end");if(t.isError(o))return o;var a=n.decode(t,"der",i);if(t.isError(a)&&o)break;s.push(a)}return s};Xn.prototype._decodeStr=function(t,r){if(r==="bitstr"){var n=t.readUInt8();return t.isError(n)?n:{unused:n,data:t.raw()}}else if(r==="bmpstr"){var i=t.raw();if(i.length%2===1)return t.error("Decoding of string type: bmpstr length mismatch");for(var s="",o=0;o>6],i=(r&32)===0;if((r&31)===31){var s=r;for(r=0;(s&128)===128;){if(s=e.readUInt8(t),e.isError(s))return s;r<<=7,r|=s&127}}else r&=31;var o=$9.tag[r];return{cls:n,primitive:i,tag:r,tagStr:o}}function tO(e,t,r){var n=e.readUInt8(r);if(e.isError(n))return n;if(!t&&n===128)return null;if((n&128)===0)return n;var i=n&127;if(i>4)return e.error("length octect is too long");n=0;for(var s=0;s{var Qpe=ze(),wpe=Gr().Buffer,E_=p_();function y_(e){E_.call(this,e),this.enc="pem"}Qpe(y_,E_);nO.exports=y_;y_.prototype.decode=function(t,r){for(var n=t.toString().split(/[\r\n]+/g),i=r.label.toUpperCase(),s=/^-----(BEGIN|END) ([^-]+)-----$/,o=-1,a=-1,A=0;A{var sO=oO;sO.der=p_();sO.pem=iO()});var B_=x((pFe,cO)=>{var Spe=ze(),ca=Gr().Buffer,AO=tl(),fO=AO.base,m_=AO.constants.der;function uO(e){this.enc="der",this.name=e.name,this.entity=e,this.tree=new ds,this.tree._init(e.body)}cO.exports=uO;uO.prototype.encode=function(t,r){return this.tree._encode(t,r).join()};function ds(e){fO.Node.call(this,"der",e)}Spe(ds,fO.Node);ds.prototype._encodeComposite=function(t,r,n,i){var s=_pe(t,r,n,this.reporter);if(i.length<128){var A=new ca(2);return A[0]=s,A[1]=i.length,this._createEncoderBuffer([A,i])}for(var o=1,a=i.length;a>=256;a>>=8)o++;var A=new ca(2+o);A[0]=s,A[1]=128|o;for(var a=1+o,f=i.length;f>0;a--,f>>=8)A[a]=f&255;return this._createEncoderBuffer([A,i])};ds.prototype._encodeStr=function(t,r){if(r==="bitstr")return this._createEncoderBuffer([t.unused|0,t.data]);if(r==="bmpstr"){for(var n=new ca(t.length*2),i=0;i=40)return this.reporter.error("Second objid identifier OOB");t.splice(0,2,t[0]*40+t[1])}for(var s=0,i=0;i=128;o>>=7)s++}for(var a=new ca(s),A=a.length-1,i=t.length-1;i>=0;i--){var o=t[i];for(a[A--]=o&127;(o>>=7)>0;)a[A--]=128|o&127}return this._createEncoderBuffer(a)};function Ri(e){return e<10?"0"+e:e}ds.prototype._encodeTime=function(t,r){var n,i=new Date(t);return r==="gentime"?n=[Ri(i.getFullYear()),Ri(i.getUTCMonth()+1),Ri(i.getUTCDate()),Ri(i.getUTCHours()),Ri(i.getUTCMinutes()),Ri(i.getUTCSeconds()),"Z"].join(""):r==="utctime"?n=[Ri(i.getFullYear()%100),Ri(i.getUTCMonth()+1),Ri(i.getUTCDate()),Ri(i.getUTCHours()),Ri(i.getUTCMinutes()),Ri(i.getUTCSeconds()),"Z"].join(""):this.reporter.error("Encoding "+r+" time is not supported yet"),this._encodeStr(n,"octstr")};ds.prototype._encodeNull=function(){return this._createEncoderBuffer("")};ds.prototype._encodeInt=function(t,r){if(typeof t=="string"){if(!r)return this.reporter.error("String int or enum given, but no values map");if(!r.hasOwnProperty(t))return this.reporter.error("Values map doesn't contain: "+JSON.stringify(t));t=r[t]}if(typeof t!="number"&&!ca.isBuffer(t)){var n=t.toArray();!t.sign&&n[0]&128&&n.unshift(0),t=new ca(n)}if(ca.isBuffer(t)){var i=t.length;t.length===0&&i++;var o=new ca(i);return t.copy(o),t.length===0&&(o[0]=0),this._createEncoderBuffer(o)}if(t<128)return this._createEncoderBuffer(t);if(t<256)return this._createEncoderBuffer([0,t]);for(var i=1,s=t;s>=256;s>>=8)i++;for(var o=new Array(i),s=o.length-1;s>=0;s--)o[s]=t&255,t>>=8;return o[0]&128&&o.unshift(0),this._createEncoderBuffer(new ca(o))};ds.prototype._encodeBool=function(t){return this._createEncoderBuffer(t?255:0)};ds.prototype._use=function(t,r){return typeof t=="function"&&(t=t(r)),t._getEncoder("der").tree};ds.prototype._skipDefault=function(t,r,n){var i=this._baseState,s;if(i.default===null)return!1;var o=t.join();if(i.defaultBuffer===void 0&&(i.defaultBuffer=this._encodeValue(i.default,r,n).join()),o.length!==i.defaultBuffer.length)return!1;for(s=0;s=31?n.error("Multi-octet tag encoding unsupported"):(t||(i|=32),i|=m_.tagClassByName[r||"universal"]<<6,i)}});var hO=x((EFe,lO)=>{var vpe=ze(),I_=B_();function b_(e){I_.call(this,e),this.enc="pem"}vpe(b_,I_);lO.exports=b_;b_.prototype.encode=function(t,r){for(var n=I_.prototype.encode.call(this,t),i=n.toString("base64"),s=["-----BEGIN "+r.label+"-----"],o=0;o{var dO=gO;dO.der=B_();dO.pem=hO()});var tl=x(EO=>{var il=EO;il.bignum=kr();il.define=q9().define;il.base=nl();il.constants=h_();il.decoders=aO();il.encoders=pO()});var IO=x((BFe,BO)=>{"use strict";var gs=tl(),yO=gs.define("Time",function(){this.choice({utcTime:this.utctime(),generalTime:this.gentime()})}),Rpe=gs.define("AttributeTypeValue",function(){this.seq().obj(this.key("type").objid(),this.key("value").any())}),C_=gs.define("AlgorithmIdentifier",function(){this.seq().obj(this.key("algorithm").objid(),this.key("parameters").optional(),this.key("curve").objid().optional())}),Dpe=gs.define("SubjectPublicKeyInfo",function(){this.seq().obj(this.key("algorithm").use(C_),this.key("subjectPublicKey").bitstr())}),Tpe=gs.define("RelativeDistinguishedName",function(){this.setof(Rpe)}),Npe=gs.define("RDNSequence",function(){this.seqof(Tpe)}),mO=gs.define("Name",function(){this.choice({rdnSequence:this.use(Npe)})}),Mpe=gs.define("Validity",function(){this.seq().obj(this.key("notBefore").use(yO),this.key("notAfter").use(yO))}),Fpe=gs.define("Extension",function(){this.seq().obj(this.key("extnID").objid(),this.key("critical").bool().def(!1),this.key("extnValue").octstr())}),kpe=gs.define("TBSCertificate",function(){this.seq().obj(this.key("version").explicit(0).int().optional(),this.key("serialNumber").int(),this.key("signature").use(C_),this.key("issuer").use(mO),this.key("validity").use(Mpe),this.key("subject").use(mO),this.key("subjectPublicKeyInfo").use(Dpe),this.key("issuerUniqueID").implicit(1).bitstr().optional(),this.key("subjectUniqueID").implicit(2).bitstr().optional(),this.key("extensions").explicit(3).seqof(Fpe).optional())}),xpe=gs.define("X509Certificate",function(){this.seq().obj(this.key("tbsCertificate").use(kpe),this.key("signatureAlgorithm").use(C_),this.key("signatureValue").bitstr())});BO.exports=xpe});var CO=x(Es=>{"use strict";var ps=tl();Es.certificate=IO();var Upe=ps.define("RSAPrivateKey",function(){this.seq().obj(this.key("version").int(),this.key("modulus").int(),this.key("publicExponent").int(),this.key("privateExponent").int(),this.key("prime1").int(),this.key("prime2").int(),this.key("exponent1").int(),this.key("exponent2").int(),this.key("coefficient").int())});Es.RSAPrivateKey=Upe;var Lpe=ps.define("RSAPublicKey",function(){this.seq().obj(this.key("modulus").int(),this.key("publicExponent").int())});Es.RSAPublicKey=Lpe;var bO=ps.define("AlgorithmIdentifier",function(){this.seq().obj(this.key("algorithm").objid(),this.key("none").null_().optional(),this.key("curve").objid().optional(),this.key("params").seq().obj(this.key("p").int(),this.key("q").int(),this.key("g").int()).optional())}),Ppe=ps.define("SubjectPublicKeyInfo",function(){this.seq().obj(this.key("algorithm").use(bO),this.key("subjectPublicKey").bitstr())});Es.PublicKey=Ppe;var Ope=ps.define("PrivateKeyInfo",function(){this.seq().obj(this.key("version").int(),this.key("algorithm").use(bO),this.key("subjectPrivateKey").octstr())});Es.PrivateKey=Ope;var Hpe=ps.define("EncryptedPrivateKeyInfo",function(){this.seq().obj(this.key("algorithm").seq().obj(this.key("id").objid(),this.key("decrypt").seq().obj(this.key("kde").seq().obj(this.key("id").objid(),this.key("kdeparams").seq().obj(this.key("salt").octstr(),this.key("iters").int())),this.key("cipher").seq().obj(this.key("algo").objid(),this.key("iv").octstr()))),this.key("subjectPrivateKey").octstr())});Es.EncryptedPrivateKey=Hpe;var qpe=ps.define("DSAPrivateKey",function(){this.seq().obj(this.key("version").int(),this.key("p").int(),this.key("q").int(),this.key("g").int(),this.key("pub_key").int(),this.key("priv_key").int())});Es.DSAPrivateKey=qpe;Es.DSAparam=ps.define("DSAparam",function(){this.int()});var Gpe=ps.define("ECParameters",function(){this.choice({namedCurve:this.objid()})}),Ype=ps.define("ECPrivateKey",function(){this.seq().obj(this.key("version").int(),this.key("privateKey").octstr(),this.key("parameters").optional().explicit(0).use(Gpe),this.key("publicKey").optional().explicit(1).bitstr())});Es.ECPrivateKey=Ype;Es.signature=ps.define("signature",function(){this.seq().obj(this.key("r").int(),this.key("s").int())})});var QO=x((bFe,Wpe)=>{Wpe.exports={"2.16.840.1.101.3.4.1.1":"aes-128-ecb","2.16.840.1.101.3.4.1.2":"aes-128-cbc","2.16.840.1.101.3.4.1.3":"aes-128-ofb","2.16.840.1.101.3.4.1.4":"aes-128-cfb","2.16.840.1.101.3.4.1.21":"aes-192-ecb","2.16.840.1.101.3.4.1.22":"aes-192-cbc","2.16.840.1.101.3.4.1.23":"aes-192-ofb","2.16.840.1.101.3.4.1.24":"aes-192-cfb","2.16.840.1.101.3.4.1.41":"aes-256-ecb","2.16.840.1.101.3.4.1.42":"aes-256-cbc","2.16.840.1.101.3.4.1.43":"aes-256-ofb","2.16.840.1.101.3.4.1.44":"aes-256-cfb"}});var SO=x((CFe,wO)=>{"use strict";var Vpe=/Proc-Type: 4,ENCRYPTED[\n\r]+DEK-Info: AES-((?:128)|(?:192)|(?:256))-CBC,([0-9A-H]+)[\n\r]+([0-9A-z\n\r+/=]+)[\n\r]+/m,Jpe=/^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----/m,jpe=/^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----([0-9A-z\n\r+/=]+)-----END \1-----$/m,zpe=Nd(),Kpe=Cy(),Ky=at().Buffer;wO.exports=function(e,t){var r=e.toString(),n=r.match(Vpe),i;if(n){var o="aes"+n[1],a=Ky.from(n[2],"hex"),A=Ky.from(n[3].replace(/[\r\n]/g,""),"base64"),f=zpe(t,a.slice(0,8),parseInt(n[1],10)).key,l=[],p=Kpe.createDecipheriv(o,f,a);l.push(p.update(A)),l.push(p.final()),i=Ky.concat(l)}else{var s=r.match(jpe);i=Ky.from(s[2].replace(/[\r\n]/g,""),"base64")}var B=r.match(Jpe)[1];return{tag:B,data:i}}});var qd=x((QFe,vO)=>{"use strict";var xn=CO(),Xpe=QO(),Zpe=SO(),$pe=Cy(),eEe=hS().pbkdf2Sync,Q_=at().Buffer;function tEe(e,t){var r=e.algorithm.decrypt.kde.kdeparams.salt,n=parseInt(e.algorithm.decrypt.kde.kdeparams.iters.toString(),10),i=Xpe[e.algorithm.decrypt.cipher.algo.join(".")],s=e.algorithm.decrypt.cipher.iv,o=e.subjectPrivateKey,a=parseInt(i.split("-")[1],10)/8,A=eEe(t,r,n,a,"sha1"),f=$pe.createDecipheriv(i,A,s),l=[];return l.push(f.update(o)),l.push(f.final()),Q_.concat(l)}function _O(e){var t;typeof e=="object"&&!Q_.isBuffer(e)&&(t=e.passphrase,e=e.key),typeof e=="string"&&(e=Q_.from(e));var r=Zpe(e,t),n=r.tag,i=r.data,s,o;switch(n){case"CERTIFICATE":o=xn.certificate.decode(i,"der").tbsCertificate.subjectPublicKeyInfo;case"PUBLIC KEY":switch(o||(o=xn.PublicKey.decode(i,"der")),s=o.algorithm.algorithm.join("."),s){case"1.2.840.113549.1.1.1":return xn.RSAPublicKey.decode(o.subjectPublicKey.data,"der");case"1.2.840.10045.2.1":return o.subjectPrivateKey=o.subjectPublicKey,{type:"ec",data:o};case"1.2.840.10040.4.1":return o.algorithm.params.pub_key=xn.DSAparam.decode(o.subjectPublicKey.data,"der"),{type:"dsa",data:o.algorithm.params};default:throw new Error("unknown key id "+s)}case"ENCRYPTED PRIVATE KEY":i=xn.EncryptedPrivateKey.decode(i,"der"),i=tEe(i,t);case"PRIVATE KEY":switch(o=xn.PrivateKey.decode(i,"der"),s=o.algorithm.algorithm.join("."),s){case"1.2.840.113549.1.1.1":return xn.RSAPrivateKey.decode(o.subjectPrivateKey,"der");case"1.2.840.10045.2.1":return{curve:o.algorithm.curve,privateKey:xn.ECPrivateKey.decode(o.subjectPrivateKey,"der").privateKey};case"1.2.840.10040.4.1":return o.algorithm.params.priv_key=xn.DSAparam.decode(o.subjectPrivateKey,"der"),{type:"dsa",params:o.algorithm.params};default:throw new Error("unknown key id "+s)}case"RSA PUBLIC KEY":return xn.RSAPublicKey.decode(i,"der");case"RSA PRIVATE KEY":return xn.RSAPrivateKey.decode(i,"der");case"DSA PRIVATE KEY":return{type:"dsa",params:xn.DSAPrivateKey.decode(i,"der")};case"EC PRIVATE KEY":return i=xn.ECPrivateKey.decode(i,"der"),{curve:i.parameters.value,privateKey:i.privateKey};default:throw new Error("unknown key type "+n)}}_O.signature=xn.signature;vO.exports=_O});var w_=x((wFe,rEe)=>{rEe.exports={"1.3.132.0.10":"secp256k1","1.3.132.0.33":"p224","1.2.840.10045.3.1.1":"p192","1.2.840.10045.3.1.7":"p256","1.3.132.0.34":"p384","1.3.132.0.35":"p521"}});var TO=x((SFe,Zy)=>{"use strict";var fn=at().Buffer,qf=iS(),nEe=vy(),iEe=Wy().ec,Xy=_y(),sEe=qd(),oEe=w_(),aEe=1;function AEe(e,t,r,n,i){var s=sEe(t);if(s.curve){if(n!=="ecdsa"&&n!=="ecdsa/rsa")throw new Error("wrong private key type");return fEe(e,s)}else if(s.type==="dsa"){if(n!=="dsa")throw new Error("wrong private key type");return uEe(e,s,r)}if(n!=="rsa"&&n!=="ecdsa/rsa")throw new Error("wrong private key type");if(t.padding!==void 0&&t.padding!==aEe)throw new Error("illegal or unsupported padding mode");e=fn.concat([i,e]);for(var o=s.modulus.byteLength(),a=[0,1];e.length+a.length+10&&r.ishrn(n),r}function lEe(e,t){e=S_(e,t),e=e.mod(t);var r=fn.from(e.toArray());if(r.length{"use strict";var __=at().Buffer,Gd=_y(),dEe=Wy().ec,MO=qd(),gEe=w_();function pEe(e,t,r,n,i){var s=MO(r);if(s.type==="ec"){if(n!=="ecdsa"&&n!=="ecdsa/rsa")throw new Error("wrong public key type");return EEe(e,t,s)}else if(s.type==="dsa"){if(n!=="dsa")throw new Error("wrong public key type");return yEe(e,t,s)}if(n!=="rsa"&&n!=="ecdsa/rsa")throw new Error("wrong public key type");t=__.concat([i,t]);for(var o=s.modulus.byteLength(),a=[1],A=0;t.length+a.length+2=0)throw new Error("invalid sig")}FO.exports=pEe});var HO=x((vFe,OO)=>{"use strict";var $y=at().Buffer,LO=kc(),em=Kw(),PO=ze(),mEe=TO(),BEe=kO(),Gf=sS();Object.keys(Gf).forEach(function(e){Gf[e].id=$y.from(Gf[e].id,"hex"),Gf[e.toLowerCase()]=Gf[e]});function Yd(e){em.Writable.call(this);var t=Gf[e];if(!t)throw new Error("Unknown message digest");this._hashType=t.hash,this._hash=LO(t.hash),this._tag=t.id,this._signType=t.sign}PO(Yd,em.Writable);Yd.prototype._write=function(t,r,n){this._hash.update(t),n()};Yd.prototype.update=function(t,r){return this._hash.update(typeof t=="string"?$y.from(t,r):t),this};Yd.prototype.sign=function(t,r){this.end();var n=this._hash.digest(),i=mEe(n,t,this._hashType,this._signType,this._tag);return r?i.toString(r):i};function Wd(e){em.Writable.call(this);var t=Gf[e];if(!t)throw new Error("Unknown message digest");this._hash=LO(t.hash),this._tag=t.id,this._signType=t.sign}PO(Wd,em.Writable);Wd.prototype._write=function(t,r,n){this._hash.update(t),n()};Wd.prototype.update=function(t,r){return this._hash.update(typeof t=="string"?$y.from(t,r):t),this};Wd.prototype.verify=function(t,r,n){var i=typeof r=="string"?$y.from(r,n):r;this.end();var s=this._hash.digest();return BEe(i,s,t,this._signType,this._tag)};function xO(e){return new Yd(e)}function UO(e){return new Wd(e)}OO.exports={Sign:xO,Verify:UO,createSign:xO,createVerify:UO}});var GO=x((RFe,qO)=>{var IEe=Wy(),bEe=kr();qO.exports=function(t){return new Yf(t)};var Zn={secp256k1:{name:"secp256k1",byteLength:32},secp224r1:{name:"p224",byteLength:28},prime256v1:{name:"p256",byteLength:32},prime192v1:{name:"p192",byteLength:24},ed25519:{name:"ed25519",byteLength:32},secp384r1:{name:"p384",byteLength:48},secp521r1:{name:"p521",byteLength:66}};Zn.p224=Zn.secp224r1;Zn.p256=Zn.secp256r1=Zn.prime256v1;Zn.p192=Zn.secp192r1=Zn.prime192v1;Zn.p384=Zn.secp384r1;Zn.p521=Zn.secp521r1;function Yf(e){this.curveType=Zn[e],this.curveType||(this.curveType={name:e}),this.curve=new IEe.ec(this.curveType.name),this.keys=void 0}Yf.prototype.generateKeys=function(e,t){return this.keys=this.curve.genKeyPair(),this.getPublicKey(e,t)};Yf.prototype.computeSecret=function(e,t,r){t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t));var n=this.curve.keyFromPublic(e).getPublic(),i=n.mul(this.keys.getPrivate()).getX();return v_(i,r,this.curveType.byteLength)};Yf.prototype.getPublicKey=function(e,t){var r=this.keys.getPublic(t==="compressed",!0);return t==="hybrid"&&(r[r.length-1]%2?r[0]=7:r[0]=6),v_(r,e)};Yf.prototype.getPrivateKey=function(e){return v_(this.keys.getPrivate(),e)};Yf.prototype.setPublicKey=function(e,t){return t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t)),this.keys._importPublic(e),this};Yf.prototype.setPrivateKey=function(e,t){t=t||"utf8",Buffer.isBuffer(e)||(e=new Buffer(e,t));var r=new bEe(e);return r=r.toString(16),this.keys=this.curve.genKeyPair(),this.keys._importPrivate(r),this};function v_(e,t,r){Array.isArray(e)||(e=e.toArray());var n=new Buffer(e);if(r&&n.length{var CEe=kc(),R_=at().Buffer;YO.exports=function(e,t){for(var r=R_.alloc(0),n=0,i;r.length{WO.exports=function(t,r){for(var n=t.length,i=-1;++i{var VO=kr(),wEe=at().Buffer;function SEe(e,t){return wEe.from(e.toRed(VO.mont(t.modulus)).redPow(new VO(t.publicExponent)).fromRed().toArray())}JO.exports=SEe});var XO=x((MFe,KO)=>{var _Ee=qd(),M_=If(),vEe=kc(),jO=D_(),zO=T_(),F_=kr(),REe=N_(),DEe=vy(),ys=at().Buffer;KO.exports=function(t,r,n){var i;t.padding?i=t.padding:n?i=1:i=4;var s=_Ee(t),o;if(i===4)o=TEe(s,r);else if(i===1)o=NEe(s,r,n);else if(i===3){if(o=new F_(r),o.cmp(s.modulus)>=0)throw new Error("data too long for modulus")}else throw new Error("unknown padding");return n?DEe(o,s):REe(o,s)};function TEe(e,t){var r=e.modulus.byteLength(),n=t.length,i=vEe("sha1").update(ys.alloc(0)).digest(),s=i.length,o=2*s;if(n>r-o-2)throw new Error("message too long");var a=ys.alloc(r-n-o-2),A=r-s-1,f=M_(s),l=zO(ys.concat([i,a,ys.alloc(1,1),t],A),jO(f,A)),p=zO(f,jO(l,s));return new F_(ys.concat([ys.alloc(1),p,l],r))}function NEe(e,t,r){var n=t.length,i=e.modulus.byteLength();if(n>i-11)throw new Error("message too long");var s;return r?s=ys.alloc(i-n-3,255):s=MEe(i-n-3),new F_(ys.concat([ys.from([0,r?1:2]),s,ys.alloc(1),t],i))}function MEe(e){for(var t=ys.allocUnsafe(e),r=0,n=M_(e*2),i=0,s;r{var FEe=qd(),ZO=D_(),$O=T_(),eH=kr(),kEe=vy(),xEe=kc(),UEe=N_(),Vd=at().Buffer;tH.exports=function(t,r,n){var i;t.padding?i=t.padding:n?i=1:i=4;var s=FEe(t),o=s.modulus.byteLength();if(r.length>o||new eH(r).cmp(s.modulus)>=0)throw new Error("decryption error");var a;n?a=UEe(new eH(r),s):a=kEe(r,s);var A=Vd.alloc(o-a.length);if(a=Vd.concat([A,a],o),i===4)return LEe(s,a);if(i===1)return PEe(s,a,n);if(i===3)return a;throw new Error("unknown padding")};function LEe(e,t){var r=e.modulus.byteLength(),n=xEe("sha1").update(Vd.alloc(0)).digest(),i=n.length;if(t[0]!==0)throw new Error("decryption error");var s=t.slice(1,i+1),o=t.slice(i+1),a=$O(s,ZO(o,i)),A=$O(o,ZO(a,r-i-1));if(OEe(n,A.slice(0,i)))throw new Error("decryption error");for(var f=i;A[f]===0;)f++;if(A[f++]!==1)throw new Error("decryption error");return A.slice(f)}function PEe(e,t,r){for(var n=t.slice(0,2),i=2,s=0;t[i++]!==0;)if(i>=t.length){s++;break}var o=t.slice(2,i-1);if((n.toString("hex")!=="0002"&&!r||n.toString("hex")!=="0001"&&r)&&s++,o.length<8&&s++,s)throw new Error("decryption error");return t.slice(i)}function OEe(e,t){e=Vd.from(e),t=Vd.from(t);var r=0,n=e.length;e.length!==t.length&&(r++,n=Math.min(e.length,t.length));for(var i=-1;++i{Wf.publicEncrypt=XO();Wf.privateDecrypt=rH();Wf.privateEncrypt=function(t,r){return Wf.publicEncrypt(t,r,!0)};Wf.publicDecrypt=function(t,r){return Wf.privateDecrypt(t,r,!0)}});var hH=x(Jd=>{"use strict";function iH(){throw new Error(`secure random number generation not supported by this browser -use chrome, FireFox or Internet Explorer 11`)}var oH=at(),sH=If(),aH=oH.Buffer,AH=oH.kMaxLength,k_=globalThis.crypto||globalThis.msCrypto,fH=Math.pow(2,32)-1;function uH(e,t){if(typeof e!="number"||e!==e)throw new TypeError("offset must be a number");if(e>fH||e<0)throw new TypeError("offset must be a uint32");if(e>AH||e>t)throw new RangeError("offset out of range")}function cH(e,t,r){if(typeof e!="number"||e!==e)throw new TypeError("size must be a number");if(e>fH||e<0)throw new TypeError("size must be a uint32");if(e+t>r||e>AH)throw new RangeError("buffer too small")}k_&&k_.getRandomValues||!process.browser?(Jd.randomFill=HEe,Jd.randomFillSync=qEe):(Jd.randomFill=iH,Jd.randomFillSync=iH);function HEe(e,t,r,n){if(!aH.isBuffer(e)&&!(e instanceof globalThis.Uint8Array))throw new TypeError('"buf" argument must be a Buffer or Uint8Array');if(typeof t=="function")n=t,t=0,r=e.length;else if(typeof r=="function")n=r,r=e.length-t;else if(typeof n!="function")throw new TypeError('"cb" argument must be a function');return uH(t,e.length),cH(r,t,e.length),lH(e,t,r,n)}function lH(e,t,r,n){if(process.browser){var i=e.buffer,s=new Uint8Array(i,t,r);if(k_.getRandomValues(s),n){process.nextTick(function(){n(null,e)});return}return e}if(n){sH(r,function(a,A){if(a)return n(a);A.copy(e,t),n(null,e)});return}var o=sH(r);return o.copy(e,t),e}function qEe(e,t,r){if(typeof t>"u"&&(t=0),!aH.isBuffer(e)&&!(e instanceof globalThis.Uint8Array))throw new TypeError('"buf" argument must be a Buffer or Uint8Array');return uH(t,e.length),r===void 0&&(r=e.length-t),cH(r,t,e.length),lH(e,t,r)}});var kd=x(ut=>{"use strict";ut.randomBytes=ut.rng=ut.pseudoRandomBytes=ut.prng=If();ut.createHash=ut.Hash=kc();ut.createHmac=ut.Hmac=iS();var GEe=v8(),YEe=Object.keys(GEe),WEe=["sha1","sha224","sha256","sha384","sha512","md5","rmd160"].concat(YEe);ut.getHashes=function(){return WEe};var dH=hS();ut.pbkdf2=dH.pbkdf2;ut.pbkdf2Sync=dH.pbkdf2Sync;var go=Z5();ut.Cipher=go.Cipher;ut.createCipher=go.createCipher;ut.Cipheriv=go.Cipheriv;ut.createCipheriv=go.createCipheriv;ut.Decipher=go.Decipher;ut.createDecipher=go.createDecipher;ut.Decipheriv=go.Decipheriv;ut.createDecipheriv=go.createDecipheriv;ut.getCiphers=go.getCiphers;ut.listCiphers=go.listCiphers;var jd=cP();ut.DiffieHellmanGroup=jd.DiffieHellmanGroup;ut.createDiffieHellmanGroup=jd.createDiffieHellmanGroup;ut.getDiffieHellman=jd.getDiffieHellman;ut.createDiffieHellman=jd.createDiffieHellman;ut.DiffieHellman=jd.DiffieHellman;var tm=HO();ut.createSign=tm.createSign;ut.Sign=tm.Sign;ut.createVerify=tm.createVerify;ut.Verify=tm.Verify;ut.createECDH=GO();var rm=nH();ut.publicEncrypt=rm.publicEncrypt;ut.privateEncrypt=rm.privateEncrypt;ut.publicDecrypt=rm.publicDecrypt;ut.privateDecrypt=rm.privateDecrypt;var gH=hH();ut.randomFill=gH.randomFill;ut.randomFillSync=gH.randomFillSync;ut.createCredentials=function(){throw new Error(`sorry, createCredentials is not implemented yet -we accept pull requests -https://github.com/browserify/crypto-browserify`)};ut.constants={DH_CHECK_P_NOT_SAFE_PRIME:2,DH_CHECK_P_NOT_PRIME:1,DH_UNABLE_TO_CHECK_GENERATOR:4,DH_NOT_SUITABLE_GENERATOR:8,NPN_ENABLED:1,ALPN_ENABLED:1,RSA_PKCS1_PADDING:1,RSA_SSLV23_PADDING:2,RSA_NO_PADDING:3,RSA_PKCS1_OAEP_PADDING:4,RSA_X931_PADDING:5,RSA_PKCS1_PSS_PADDING:6,POINT_CONVERSION_COMPRESSED:2,POINT_CONVERSION_UNCOMPRESSED:4,POINT_CONVERSION_HYBRID:6}});var EH=x(()=>{"use strict";var pH=new Error("No such built-in module: node:sqlite");pH.code="ERR_UNKNOWN_BUILTIN_MODULE";throw pH});var x_=x((OFe,yH)=>{"use strict";yH.exports={isMainThread:!0,parentPort:null,workerData:null}});var P_=x((_,L_)=>{"use strict";var e=new Set(["crypto","sqlite","markAsUncloneable","zstd"]),t=new Map([["crypto",!0],["sqlite",!1],["markAsUncloneable",!1],["zstd",!1]]),r={clear(){t.clear()},has(n){if(!e.has(n))throw new TypeError(`unknown feature: ${n}`);return t.get(n)??!1},set(n,i){if(!e.has(n))throw new TypeError(`unknown feature: ${n}`);t.set(n,!!i)}};L_.exports.runtimeFeatures=r;L_.exports.default=r});var po=x((GFe,wH)=>{"use strict";var XEe=Wt(),{types:ur,inspect:ZEe}=Yr(),{runtimeFeatures:$Ee}=P_(),O_=1,H_=2,im=3,sm=4,q_=5,om=6,G_=7,$n=8,QH=Function.call.bind(Function.prototype[Symbol.hasInstance]),K={converters:{},util:{},errors:{},is:{}};K.errors.exception=function(e){return new TypeError(`${e.header}: ${e.message}`)};K.errors.conversionFailed=function(e){let t=e.types.length===1?"":" one of",r=`${e.argument} could not be converted to${t}: ${e.types.join(", ")}.`;return K.errors.exception({header:e.prefix,message:r})};K.errors.invalidArgument=function(e){return K.errors.exception({header:e.prefix,message:`"${e.value}" is an invalid ${e.type}.`})};K.brandCheck=function(e,t){if(!QH(t,e)){let r=new TypeError("Illegal invocation");throw r.code="ERR_INVALID_THIS",r}};K.brandCheckMultiple=function(e){let t=e.map(r=>K.util.MakeTypeAssertion(r));return r=>{if(t.every(n=>!n(r))){let n=new TypeError("Illegal invocation");throw n.code="ERR_INVALID_THIS",n}}};K.argumentLengthCheck=function({length:e},t,r){if(eQH(e,t)};K.util.Type=function(e){switch(typeof e){case"undefined":return O_;case"boolean":return H_;case"string":return im;case"symbol":return sm;case"number":return q_;case"bigint":return om;case"function":case"object":return e===null?G_:$n}};K.util.Types={UNDEFINED:O_,BOOLEAN:H_,STRING:im,SYMBOL:sm,NUMBER:q_,BIGINT:om,NULL:G_,OBJECT:$n};K.util.TypeValueToString=function(e){switch(K.util.Type(e)){case O_:return"Undefined";case H_:return"Boolean";case im:return"String";case sm:return"Symbol";case q_:return"Number";case om:return"BigInt";case G_:return"Null";case $n:return"Object"}};K.util.markAsUncloneable=$Ee.has("markAsUncloneable")?x_().markAsUncloneable:()=>{};K.util.ConvertToInt=function(e,t,r,n){let i,s;t===64?(i=Math.pow(2,53)-1,r==="unsigned"?s=0:s=Math.pow(-2,53)+1):r==="unsigned"?(s=0,i=Math.pow(2,t)-1):(s=Math.pow(-2,t)-1,i=Math.pow(2,t-1)-1);let o=Number(e);if(o===0&&(o=0),K.util.HasFlag(n,K.attributes.EnforceRange)){if(Number.isNaN(o)||o===Number.POSITIVE_INFINITY||o===Number.NEGATIVE_INFINITY)throw K.errors.exception({header:"Integer conversion",message:`Could not convert ${K.util.Stringify(e)} to an integer.`});if(o=K.util.IntegerPart(o),oi)throw K.errors.exception({header:"Integer conversion",message:`Value must be between ${s}-${i}, got ${o}.`});return o}return!Number.isNaN(o)&&K.util.HasFlag(n,K.attributes.Clamp)?(o=Math.min(Math.max(o,s),i),Math.floor(o)%2===0?o=Math.floor(o):o=Math.ceil(o),o):Number.isNaN(o)||o===0&&Object.is(0,o)||o===Number.POSITIVE_INFINITY||o===Number.NEGATIVE_INFINITY?0:(o=K.util.IntegerPart(o),o=o%Math.pow(2,t),r==="signed"&&o>=Math.pow(2,t)-1?o-Math.pow(2,t):o)};K.util.IntegerPart=function(e){let t=Math.floor(Math.abs(e));return e<0?-1*t:t};K.util.Stringify=function(e){switch(K.util.Type(e)){case sm:return`Symbol(${e.description})`;case $n:return ZEe(e);case im:return`"${e}"`;case om:return`${e}n`;default:return`${e}`}};K.util.IsResizableArrayBuffer=function(e){if(ur.isArrayBuffer(e))return e.resizable;if(ur.isSharedArrayBuffer(e))return e.growable;throw K.errors.exception({header:"IsResizableArrayBuffer",message:`"${K.util.Stringify(e)}" is not an array buffer.`})};K.util.HasFlag=function(e,t){return typeof e=="number"&&(e&t)===t};K.sequenceConverter=function(e){return(t,r,n,i)=>{if(K.util.Type(t)!==$n)throw K.errors.exception({header:r,message:`${n} (${K.util.Stringify(t)}) is not iterable.`});let s=typeof i=="function"?i():t?.[Symbol.iterator]?.(),o=[],a=0;if(s===void 0||typeof s.next!="function")throw K.errors.exception({header:r,message:`${n} is not iterable.`});for(;;){let{done:A,value:f}=s.next();if(A)break;o.push(e(f,r,`${n}[${a++}]`))}return o}};K.recordConverter=function(e,t){return(r,n,i)=>{if(K.util.Type(r)!==$n)throw K.errors.exception({header:n,message:`${i} ("${K.util.TypeValueToString(r)}") is not an Object.`});let s={};if(!ur.isProxy(r)){let a=[...Object.getOwnPropertyNames(r),...Object.getOwnPropertySymbols(r)];for(let A of a){let f=K.util.Stringify(A),l=e(A,n,`Key ${f} in ${i}`),p=t(r[A],n,`${i}[${f}]`);s[l]=p}return s}let o=Reflect.ownKeys(r);for(let a of o)if(Reflect.getOwnPropertyDescriptor(r,a)?.enumerable){let f=e(a,n,i),l=t(r[a],n,i);s[f]=l}return s}};K.interfaceConverter=function(e,t){return(r,n,i)=>{if(!e(r))throw K.errors.exception({header:n,message:`Expected ${i} ("${K.util.Stringify(r)}") to be an instance of ${t}.`});return r}};K.dictionaryConverter=function(e){return e.sort((t,r)=>(t.key>r.key)-(t.key{let i={};if(t!=null&&K.util.Type(t)!==$n)throw K.errors.exception({header:r,message:`Expected ${t} to be one of: Null, Undefined, Object.`});for(let s of e){let{key:o,defaultValue:a,required:A,converter:f}=s;if(A===!0&&(t==null||!Object.hasOwn(t,o)))throw K.errors.exception({header:r,message:`Missing required key "${o}".`});let l=t?.[o],p=a!==void 0;if(p&&l===void 0&&(l=a()),A||p||l!==void 0){if(l=f(l,r,`${n}.${o}`),s.allowedValues&&!s.allowedValues.includes(l))throw K.errors.exception({header:r,message:`${l} is not an accepted type. Expected one of ${s.allowedValues.join(", ")}.`});i[o]=l}}return i}};K.nullableConverter=function(e){return(t,r,n)=>t===null?t:e(t,r,n)};K.is.USVString=function(e){return typeof e=="string"&&e.isWellFormed()};K.is.ReadableStream=K.util.MakeTypeAssertion(ReadableStream);K.is.Blob=K.util.MakeTypeAssertion(Blob);K.is.URLSearchParams=K.util.MakeTypeAssertion(URLSearchParams);K.is.File=K.util.MakeTypeAssertion(File);K.is.URL=K.util.MakeTypeAssertion(URL);K.is.AbortSignal=K.util.MakeTypeAssertion(AbortSignal);K.is.MessagePort=K.util.MakeTypeAssertion(MessagePort);K.is.BufferSource=function(e){return ur.isArrayBuffer(e)||ArrayBuffer.isView(e)&&ur.isArrayBuffer(e.buffer)};K.util.getCopyOfBytesHeldByBufferSource=function(e){let t=e,r=t,n=0,i=0;if(ur.isTypedArray(t)||ur.isDataView(t)?(r=t.buffer,n=t.byteOffset,i=t.byteLength):(XEe(ur.isAnyArrayBuffer(t)),i=t.byteLength),r.detached)return new Uint8Array(0);let s=new Uint8Array(i),o=new Uint8Array(r,n,i);return s.set(o),s};K.converters.DOMString=function(e,t,r,n){if(e===null&&K.util.HasFlag(n,K.attributes.LegacyNullToEmptyString))return"";if(typeof e=="symbol")throw K.errors.exception({header:t,message:`${r} is a symbol, which cannot be converted to a DOMString.`});return String(e)};K.converters.ByteString=function(e,t,r){if(typeof e=="symbol")throw K.errors.exception({header:t,message:`${r} is a symbol, which cannot be converted to a ByteString.`});let n=String(e);for(let i=0;i255)throw new TypeError(`Cannot convert argument to a ByteString because the character at index ${i} has a value of ${n.charCodeAt(i)} which is greater than 255.`);return n};K.converters.USVString=function(e){return typeof e=="string"?e.toWellFormed():`${e}`.toWellFormed()};K.converters.boolean=function(e){return!!e};K.converters.any=function(e){return e};K.converters["long long"]=function(e,t,r){return K.util.ConvertToInt(e,64,"signed",0,t,r)};K.converters["unsigned long long"]=function(e,t,r){return K.util.ConvertToInt(e,64,"unsigned",0,t,r)};K.converters["unsigned long"]=function(e,t,r){return K.util.ConvertToInt(e,32,"unsigned",0,t,r)};K.converters["unsigned short"]=function(e,t,r,n){return K.util.ConvertToInt(e,16,"unsigned",n,t,r)};K.converters.ArrayBuffer=function(e,t,r,n){if(K.util.Type(e)!==$n||!ur.isArrayBuffer(e))throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["ArrayBuffer"]});if(!K.util.HasFlag(n,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e))throw K.errors.exception({header:t,message:`${r} cannot be a resizable ArrayBuffer.`});return e};K.converters.SharedArrayBuffer=function(e,t,r,n){if(K.util.Type(e)!==$n||!ur.isSharedArrayBuffer(e))throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["SharedArrayBuffer"]});if(!K.util.HasFlag(n,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e))throw K.errors.exception({header:t,message:`${r} cannot be a resizable SharedArrayBuffer.`});return e};K.converters.TypedArray=function(e,t,r,n,i){if(K.util.Type(e)!==$n||!ur.isTypedArray(e)||e.constructor.name!==t.name)throw K.errors.conversionFailed({prefix:r,argument:`${n} ("${K.util.Stringify(e)}")`,types:[t.name]});if(!K.util.HasFlag(i,K.attributes.AllowShared)&&ur.isSharedArrayBuffer(e.buffer))throw K.errors.exception({header:r,message:`${n} cannot be a view on a shared array buffer.`});if(!K.util.HasFlag(i,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e.buffer))throw K.errors.exception({header:r,message:`${n} cannot be a view on a resizable array buffer.`});return e};K.converters.DataView=function(e,t,r,n){if(K.util.Type(e)!==$n||!ur.isDataView(e))throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["DataView"]});if(!K.util.HasFlag(n,K.attributes.AllowShared)&&ur.isSharedArrayBuffer(e.buffer))throw K.errors.exception({header:t,message:`${r} cannot be a view on a shared array buffer.`});if(!K.util.HasFlag(n,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e.buffer))throw K.errors.exception({header:t,message:`${r} cannot be a view on a resizable array buffer.`});return e};K.converters.ArrayBufferView=function(e,t,r,n){if(K.util.Type(e)!==$n||!ur.isArrayBufferView(e))throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["ArrayBufferView"]});if(!K.util.HasFlag(n,K.attributes.AllowShared)&&ur.isSharedArrayBuffer(e.buffer))throw K.errors.exception({header:t,message:`${r} cannot be a view on a shared array buffer.`});if(!K.util.HasFlag(n,K.attributes.AllowResizable)&&K.util.IsResizableArrayBuffer(e.buffer))throw K.errors.exception({header:t,message:`${r} cannot be a view on a resizable array buffer.`});return e};K.converters.BufferSource=function(e,t,r,n){if(ur.isArrayBuffer(e))return K.converters.ArrayBuffer(e,t,r,n);if(ur.isArrayBufferView(e))return n&=~K.attributes.AllowShared,K.converters.ArrayBufferView(e,t,r,n);throw ur.isSharedArrayBuffer(e)?K.errors.exception({header:t,message:`${r} cannot be a SharedArrayBuffer.`}):K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["ArrayBuffer","ArrayBufferView"]})};K.converters.AllowSharedBufferSource=function(e,t,r,n){if(ur.isArrayBuffer(e))return K.converters.ArrayBuffer(e,t,r,n);if(ur.isSharedArrayBuffer(e))return K.converters.SharedArrayBuffer(e,t,r,n);if(ur.isArrayBufferView(e))return n|=K.attributes.AllowShared,K.converters.ArrayBufferView(e,t,r,n);throw K.errors.conversionFailed({prefix:t,argument:`${r} ("${K.util.Stringify(e)}")`,types:["ArrayBuffer","SharedArrayBuffer","ArrayBufferView"]})};K.converters["sequence"]=K.sequenceConverter(K.converters.ByteString);K.converters["sequence>"]=K.sequenceConverter(K.converters["sequence"]);K.converters["record"]=K.recordConverter(K.converters.ByteString,K.converters.ByteString);K.converters.Blob=K.interfaceConverter(K.is.Blob,"Blob");K.converters.AbortSignal=K.interfaceConverter(K.is.AbortSignal,"AbortSignal");K.converters.EventHandlerNonNull=function(e){return K.util.Type(e)!==$n?null:typeof e=="function"?e:()=>{}};K.attributes={Clamp:1,EnforceRange:2,AllowShared:4,AllowResizable:8,LegacyNullToEmptyString:16};wH.exports={webidl:K}});var Kf=x((YFe,PH)=>{"use strict";var{Transform:eye}=(ts(),Gs(Yt)),SH=UE(),{redirectStatusSet:tye,referrerPolicyTokens:rye,badPortsSet:nye}=id(),{getGlobalOrigin:_H}=R3(),{collectAnHTTPQuotedString:iye,parseMIMEType:sye}=Bf(),{performance:oye}=q3(),{ReadableStreamFrom:aye,isValidHTTPToken:vH,normalizedMethodRecordsBase:Aye}=$t(),Kd=Wt(),{isUint8Array:fye}=Dw(),{webidl:pA}=po(),{isomorphicEncode:Y_,collectASequenceOfCodePoints:Jf,removeChars:uye}=mf();function RH(e){let t=e.urlList,r=t.length;return r===0?null:t[r-1].toString()}function cye(e,t){if(!tye.has(e.status))return null;let r=e.headersList.get("location",!0);return r!==null&&TH(r)&&(DH(r)||(r=lye(r)),r=new URL(r,RH(e))),r&&!r.hash&&(r.hash=t),r}function DH(e){for(let t=0;t126||r<32)return!1}return!0}function lye(e){return Buffer.from(e,"binary").toString("utf8")}function zf(e){return e.urlList[e.urlList.length-1]}function hye(e){let t=zf(e);return UH(t)&&nye.has(t.port)?"blocked":"allowed"}function dye(e){return e instanceof Error||e?.constructor?.name==="Error"||e?.constructor?.name==="DOMException"}function gye(e){for(let t=0;t=32&&r<=126||r>=128&&r<=255))return!1}return!0}var pye=vH;function TH(e){return(e[0]===" "||e[0]===" "||e[e.length-1]===" "||e[e.length-1]===" "||e.includes(` -`)||e.includes("\r")||e.includes("\0"))===!1}function Eye(e){let t=(e.headersList.get("referrer-policy",!0)??"").split(","),r="";if(t.length)for(let n=t.length;n!==0;n--){let i=t[n-1].trim();if(rye.has(i)){r=i;break}}return r}function yye(e,t){let r=Eye(t);r!==""&&(e.referrerPolicy=r)}function mye(){return"allowed"}function Bye(){return"success"}function Iye(){return"success"}function bye(e){let t=null;t=e.mode,e.headersList.set("sec-fetch-mode",t,!0)}function Cye(e){let t=e.origin;if(!(t==="client"||t===void 0)){if(e.responseTainting==="cors"||e.mode==="websocket")e.headersList.append("origin",t,!0);else if(e.method!=="GET"&&e.method!=="HEAD"){switch(e.referrerPolicy){case"no-referrer":t=null;break;case"no-referrer-when-downgrade":case"strict-origin":case"strict-origin-when-cross-origin":e.origin&&V_(e.origin)&&!V_(zf(e))&&(t=null);break;case"same-origin":zd(e,zf(e))||(t=null);break;default:}e.headersList.append("origin",t,!0)}}}function sl(e,t){return e}function Qye(e,t,r){return!e?.startTime||e.startTime4096&&(n=i),t){case"no-referrer":return"no-referrer";case"origin":return i??W_(r,!0);case"unsafe-url":return n;case"strict-origin":{let s=zf(e);return jf(n)&&!jf(s)?"no-referrer":i}case"strict-origin-when-cross-origin":{let s=zf(e);return zd(n,s)?n:jf(n)&&!jf(s)?"no-referrer":i}case"same-origin":return zd(e,n)?n:"no-referrer";case"origin-when-cross-origin":return zd(e,n)?n:i;case"no-referrer-when-downgrade":{let s=zf(e);return jf(n)&&!jf(s)?"no-referrer":n}}}function W_(e,t=!1){return Kd(pA.is.URL(e)),e=new URL(e),xH(e)?"no-referrer":(e.username="",e.password="",e.hash="",t===!0&&(e.pathname="",e.search=""),e)}var Rye=RegExp.prototype.test.bind(/^127\.(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){2}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)$/),Dye=RegExp.prototype.test.bind(/^(?:(?:0{1,4}:){7}|(?:0{1,4}:){1,6}:|::)0{0,3}1$/);function MH(e){return e.includes(":")?(e[0]==="["&&e[e.length-1]==="]"&&(e=e.slice(1,-1)),Dye(e)):Rye(e)}function Tye(e){return e==null||e==="null"?!1:(e=new URL(e),!!(e.protocol==="https:"||e.protocol==="wss:"||MH(e.hostname)||e.hostname==="localhost"||e.hostname==="localhost."||e.hostname.endsWith(".localhost")||e.hostname.endsWith(".localhost.")||e.protocol==="file:"))}function jf(e){return pA.is.URL(e)?e.href==="about:blank"||e.href==="about:srcdoc"||e.protocol==="data:"||e.protocol==="blob:"?!0:Tye(e.origin):!1}function Nye(e){}function zd(e,t){return e.origin===t.origin&&e.origin==="null"||e.protocol===t.protocol&&e.hostname===t.hostname&&e.port===t.port}function Mye(e){return e.controller.state==="aborted"}function Fye(e){return e.controller.state==="aborted"||e.controller.state==="terminated"}function kye(e){return Aye[e.toLowerCase()]??e}var xye=Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));function FH(e,t,r=0,n=1){var s,o,a;class i{constructor(f,l){St(this,s);St(this,o);St(this,a);ft(this,s,f),ft(this,o,l),ft(this,a,0)}next(){if(typeof this!="object"||this===null||!wD(s,this))throw new TypeError(`'next' called on an object that does not implement interface ${e} Iterator.`);let f=te(this,a),l=t(te(this,s)),p=l.length;if(f>=p)return{value:void 0,done:!0};let{[r]:B,[n]:S}=l[f];ft(this,a,f+1);let _;switch(te(this,o)){case"key":_=B;break;case"value":_=S;break;case"key+value":_=[B,S];break}return{value:_,done:!1}}}return s=new WeakMap,o=new WeakMap,a=new WeakMap,delete i.prototype.constructor,Object.setPrototypeOf(i.prototype,xye),Object.defineProperties(i.prototype,{[Symbol.toStringTag]:{writable:!1,enumerable:!1,configurable:!0,value:`${e} Iterator`},next:{writable:!0,enumerable:!0,configurable:!0}}),function(A,f){return new i(A,f)}}function Uye(e,t,r,n=0,i=1){let s=FH(e,r,n,i),o={keys:{writable:!0,enumerable:!0,configurable:!0,value:function(){return pA.brandCheck(this,t),s(this,"key")}},values:{writable:!0,enumerable:!0,configurable:!0,value:function(){return pA.brandCheck(this,t),s(this,"value")}},entries:{writable:!0,enumerable:!0,configurable:!0,value:function(){return pA.brandCheck(this,t),s(this,"key+value")}},forEach:{writable:!0,enumerable:!0,configurable:!0,value:function(A,f=globalThis){if(pA.brandCheck(this,t),pA.argumentLengthCheck(arguments,1,`${e}.forEach`),typeof A!="function")throw new TypeError(`Failed to execute 'forEach' on '${e}': parameter 1 is not of type 'Function'.`);for(let{0:l,1:p}of s(this,"key+value"))A.call(f,p,l,this)}}};return Object.defineProperties(t.prototype,{...o,[Symbol.iterator]:{writable:!0,enumerable:!1,configurable:!0,value:o.entries.value}})}function Lye(e,t,r){let n=t,i=r;try{let s=e.stream.getReader();kH(s,n,i)}catch(s){i(s)}}function Pye(e){try{e.close(),e.byobRequest?.respond(0)}catch(t){if(!t.message.includes("Controller is already closed")&&!t.message.includes("ReadableStream is already closed"))throw t}}async function kH(e,t,r){try{let n=[],i=0;do{let{done:s,value:o}=await e.read();if(s){t(Buffer.concat(n,i));return}if(!fye(o)){r(new TypeError("Received non-Uint8Array chunk"));return}n.push(o),i+=o.length}while(!0)}catch(n){r(n)}}function xH(e){Kd("protocol"in e);let t=e.protocol;return t==="about:"||t==="blob:"||t==="data:"}function V_(e){return typeof e=="string"&&e[5]===":"&&e[0]==="h"&&e[1]==="t"&&e[2]==="t"&&e[3]==="p"&&e[4]==="s"||e.protocol==="https:"}function UH(e){Kd("protocol"in e);let t=e.protocol;return t==="http:"||t==="https:"}function Oye(e,t){let r=e;if(!r.startsWith("bytes"))return"failure";let n={position:5};if(t&&Jf(A=>A===" "||A===" ",r,n),r.charCodeAt(n.position)!==61)return"failure";n.position++,t&&Jf(A=>A===" "||A===" ",r,n);let i=Jf(A=>{let f=A.charCodeAt(0);return f>=48&&f<=57},r,n),s=i.length?Number(i):null;if(t&&Jf(A=>A===" "||A===" ",r,n),r.charCodeAt(n.position)!==45)return"failure";n.position++,t&&Jf(A=>A===" "||A===" ",r,n);let o=Jf(A=>{let f=A.charCodeAt(0);return f>=48&&f<=57},r,n),a=o.length?Number(o):null;return n.positiona?"failure":{rangeStartValue:s,rangeEndValue:a}}function Hye(e,t,r){let n="bytes ";return n+=Y_(`${e}`),n+="-",n+=Y_(`${t}`),n+="/",n+=Y_(`${r}`),n}var ol,J_=class extends eye{constructor(r){super();St(this,ol);ft(this,ol,r)}_transform(r,n,i){if(!this._inflateStream){if(r.length===0){i();return}this._inflateStream=(r[0]&15)===8?SH.createInflate(te(this,ol)):SH.createInflateRaw(te(this,ol)),this._inflateStream.on("data",this.push.bind(this)),this._inflateStream.on("end",()=>this.push(null)),this._inflateStream.on("error",s=>this.destroy(s))}this._inflateStream.write(r,n,i)}_final(r){this._inflateStream&&(this._inflateStream.end(),this._inflateStream=null),r()}};ol=new WeakMap;function qye(e){return new J_(e)}function Gye(e){let t=null,r=null,n=null,i=LH("content-type",e);if(i===null)return"failure";for(let s of i){let o=sye(s);o==="failure"||o.essence==="*/*"||(n=o,n.essence!==r?(t=null,n.parameters.has("charset")&&(t=n.parameters.get("charset")),r=n.essence):!n.parameters.has("charset")&&t!==null&&n.parameters.set("charset",t))}return n??"failure"}function Yye(e){let t=e,r={position:0},n=[],i="";for(;r.positions!=='"'&&s!==",",t,r),r.positions===9||s===32),n.push(i),i=""}return n}function LH(e,t){let r=t.get(e,!0);return r===null?null:Yye(r)}function Wye(e){return!1}function Vye(e){return!!(e.username||e.password)}function Jye(e){return!0}var j_=class{constructor(){y(this,"policyContainer",NH())}get baseUrl(){return _H()}get origin(){return this.baseUrl?.origin}},z_=class{constructor(){y(this,"settingsObject",new j_)}},jye=new z_;PH.exports={isAborted:Mye,isCancelled:Fye,isValidEncodedURL:DH,ReadableStreamFrom:aye,tryUpgradeRequestToAPotentiallyTrustworthyURL:Nye,clampAndCoarsenConnectionTimingInfo:Qye,coarsenedSharedCurrentTime:wye,determineRequestsReferrer:vye,makePolicyContainer:NH,clonePolicyContainer:_ye,appendFetchMetadata:bye,appendRequestOriginHeader:Cye,TAOCheck:Iye,corsCheck:Bye,crossOriginResourcePolicyCheck:mye,createOpaqueTimingInfo:Sye,setRequestReferrerPolicyOnRedirect:yye,isValidHTTPToken:vH,requestBadPort:hye,requestCurrentURL:zf,responseURL:RH,responseLocationURL:cye,isURLPotentiallyTrustworthy:jf,isValidReasonPhrase:gye,sameOrigin:zd,normalizeMethod:kye,iteratorMixin:Uye,createIterator:FH,isValidHeaderName:pye,isValidHeaderValue:TH,isErrorLike:dye,fullyReadBody:Lye,readableStreamClose:Pye,urlIsLocal:xH,urlHasHttpsScheme:V_,urlIsHttpHttpsScheme:UH,readAllBytes:kH,simpleRangeHeaderValue:Oye,buildContentRange:Hye,createInflate:qye,extractMimeType:Gye,getDecodeSplit:LH,environmentSettingsObject:jye,isOriginIPPotentiallyTrustworthy:MH,hasAuthenticationEntry:Wye,includesCredentials:Vye,isTraversableNavigable:Jye}});var X_=x((VFe,HH)=>{"use strict";var{iteratorMixin:zye}=Kf(),{kEnumerableProperty:al}=$t(),{webidl:vt}=po(),OH=Yr(),Pr,EA=class EA{constructor(t=void 0){St(this,Pr,[]);if(vt.util.markAsUncloneable(this),t!==void 0)throw vt.errors.conversionFailed({prefix:"FormData constructor",argument:"Argument 1",types:["undefined"]})}append(t,r,n=void 0){vt.brandCheck(this,EA);let i="FormData.append";vt.argumentLengthCheck(arguments,2,i),t=vt.converters.USVString(t),arguments.length===3||vt.is.Blob(r)?(r=vt.converters.Blob(r,i,"value"),n!==void 0&&(n=vt.converters.USVString(n))):r=vt.converters.USVString(r);let s=K_(t,r,n);te(this,Pr).push(s)}delete(t){vt.brandCheck(this,EA),vt.argumentLengthCheck(arguments,1,"FormData.delete"),t=vt.converters.USVString(t),ft(this,Pr,te(this,Pr).filter(n=>n.name!==t))}get(t){vt.brandCheck(this,EA),vt.argumentLengthCheck(arguments,1,"FormData.get"),t=vt.converters.USVString(t);let n=te(this,Pr).findIndex(i=>i.name===t);return n===-1?null:te(this,Pr)[n].value}getAll(t){return vt.brandCheck(this,EA),vt.argumentLengthCheck(arguments,1,"FormData.getAll"),t=vt.converters.USVString(t),te(this,Pr).filter(n=>n.name===t).map(n=>n.value)}has(t){return vt.brandCheck(this,EA),vt.argumentLengthCheck(arguments,1,"FormData.has"),t=vt.converters.USVString(t),te(this,Pr).findIndex(n=>n.name===t)!==-1}set(t,r,n=void 0){vt.brandCheck(this,EA);let i="FormData.set";vt.argumentLengthCheck(arguments,2,i),t=vt.converters.USVString(t),arguments.length===3||vt.is.Blob(r)?(r=vt.converters.Blob(r,i,"value"),n!==void 0&&(n=vt.converters.USVString(n))):r=vt.converters.USVString(r);let s=K_(t,r,n),o=te(this,Pr).findIndex(a=>a.name===t);o!==-1?ft(this,Pr,[...te(this,Pr).slice(0,o),s,...te(this,Pr).slice(o+1).filter(a=>a.name!==t)]):te(this,Pr).push(s)}[OH.inspect.custom](t,r){let n=te(this,Pr).reduce((s,o)=>(s[o.name]?Array.isArray(s[o.name])?s[o.name].push(o.value):s[o.name]=[s[o.name],o.value]:s[o.name]=o.value,s),{__proto__:null});r.depth??(r.depth=t),r.colors??(r.colors=!0);let i=OH.formatWithOptions(r,n);return`FormData ${i.slice(i.indexOf("]")+2)}`}static getFormDataState(t){return te(t,Pr)}static setFormDataState(t,r){ft(t,Pr,r)}};Pr=new WeakMap;var la=EA,{getFormDataState:Kye,setFormDataState:Xye}=la;Reflect.deleteProperty(la,"getFormDataState");Reflect.deleteProperty(la,"setFormDataState");zye("FormData",la,Kye,"name","value");Object.defineProperties(la.prototype,{append:al,delete:al,get:al,getAll:al,has:al,set:al,[Symbol.toStringTag]:{value:"FormData",configurable:!0}});function K_(e,t,r){if(typeof t!="string"){if(vt.is.File(t)||(t=new File([t],"blob",{type:t.type})),r!==void 0){let n={type:t.type,lastModified:t.lastModified};t=new File([t],r,n)}}return{name:e,value:t}}vt.is.FormData=vt.util.MakeTypeAssertion(la);HH.exports={FormData:la,makeEntry:K_,setFormDataState:Xye}});var YH=x((jFe,GH)=>{"use strict";var{bufferToLowerCasedHeaderName:Zye}=$t(),{HTTP_TOKEN_CODEPOINTS:$ye}=Bf(),{makeEntry:eme}=X_(),{webidl:Z_}=po(),$_=Wt(),{isomorphicDecode:qH}=mf(),tme=Buffer.from("--"),ev=new TextDecoder,rme=new TextDecoder("utf-8",{ignoreBOM:!0});function nme(e){for(let t=0;t70)return!1;for(let r=0;r=48&&n<=57||n>=65&&n<=90||n>=97&&n<=122||n===39||n===45||n===95))return!1}return!0}function sme(e,t){$_(t!=="failure"&&t.essence==="multipart/form-data");let r=t.parameters.get("boundary");if(r===void 0)throw Un("missing boundary in content-type header");let n=Buffer.from(`--${r}`,"utf8"),i=[],s={position:0},o=e.indexOf(n);if(o===-1)throw Un("no boundary found in multipart body");for(s.position=o;;){if(e.subarray(s.position,s.position+n.length).equals(n))s.position+=n.length;else throw Un("expected a value starting with -- and the boundary");if(Ame(e,tme,s))return i;if(e[s.position]!==13||e[s.position+1]!==10)throw Un("expected CRLF");s.position+=2;let a=ame(e,s),{name:A,filename:f,contentType:l,encoding:p}=a;s.position+=2;let B;{let _=e.indexOf(n.subarray(2),s.position);if(_===-1)throw Un("expected boundary after body");B=e.subarray(s.position,_-4),s.position+=B.length,p==="base64"&&(B=Buffer.from(B.toString(),"base64"))}if(e[s.position]!==13||e[s.position+1]!==10)throw Un("expected CRLF");s.position+=2;let S;f!==null?(l??(l="text/plain"),nme(l)||(l=""),S=new File([B],f,{type:l})):S=rme.decode(Buffer.from(B)),$_(Z_.is.USVString(A)),$_(typeof S=="string"&&Z_.is.USVString(S)||Z_.is.File(S)),i.push(eme(A,S,f))}}function ome(e,t){e[t.position]===59&&t.position++,Di(o=>o===32||o===9,e,t);let r=Di(o=>rv(o)&&o!==61&&o!==42,e,t);if(r.length===0)return null;let n=r.toString("ascii").toLowerCase(),i=e[t.position]===42;if(i&&t.position++,e[t.position]!==61)return null;t.position++,Di(o=>o===32||o===9,e,t);let s;if(i){let o=Di(a=>a!==32&&a!==13&&a!==10&&a!==59,e,t);if(o[0]!==117&&o[0]!==85||o[1]!==116&&o[1]!==84||o[2]!==102&&o[2]!==70||o[3]!==45||o[4]!==56)throw Un("unknown encoding, expected utf-8''");s=decodeURIComponent(ev.decode(o.subarray(7)))}else if(e[t.position]===34){t.position++;let o=Di(a=>a!==10&&a!==13&&a!==34,e,t);if(e[t.position]!==34)throw Un("Closing quote not found");t.position++,s=ev.decode(o).replace(/%0A/ig,` -`).replace(/%0D/ig,"\r").replace(/%22/g,'"')}else{let o=Di(a=>rv(a)&&a!==59,e,t);s=ev.decode(o)}return{name:n,value:s}}function ame(e,t){let r=null,n=null,i=null,s=null;for(;;){if(e[t.position]===13&&e[t.position+1]===10){if(r===null)throw Un("header name is null");return{name:r,filename:n,contentType:i,encoding:s}}let o=Di(a=>a!==10&&a!==13&&a!==58,e,t);if(o=tv(o,!0,!0,a=>a===9||a===32),!$ye.test(o.toString()))throw Un("header name does not match the field-name token production");if(e[t.position]!==58)throw Un("expected :");switch(t.position++,Di(a=>a===32||a===9,e,t),Zye(o)){case"content-disposition":{if(r=n=null,Di(A=>rv(A),e,t).toString("ascii").toLowerCase()!=="form-data")throw Un("expected form-data for content-disposition header");for(;t.positionA!==10&&A!==13,e,t);a=tv(a,!1,!0,A=>A===9||A===32),i=qH(a);break}case"content-transfer-encoding":{let a=Di(A=>A!==10&&A!==13,e,t);a=tv(a,!1,!0,A=>A===9||A===32),s=qH(a);break}default:Di(a=>a!==10&&a!==13,e,t)}if(e[t.position]!==13&&e[t.position+1]!==10)throw Un("expected CRLF");t.position+=2}}function Di(e,t,r){let n=r.position;for(;n0&&n(e[s]);)s--;return i===0&&s===e.length-1?e:e.subarray(i,s+1)}function Ame(e,t,r){if(e.length{"use strict";function cme(){let e,t;return{promise:new Promise((n,i)=>{e=n,t=i}),resolve:e,reject:t}}WH.exports={createDeferredPromise:cme}});var sv=x((KFe,jH)=>{"use strict";var VH=new Set(["crypto","sqlite","markAsUncloneable","zstd"]),Al,iv=class{constructor(){St(this,Al,new Map([["crypto",!0],["sqlite",!1],["markAsUncloneable",!1],["zstd",!1]]))}clear(){te(this,Al).clear()}has(t){if(!VH.has(t))throw new TypeError(`unknown feature: ${t}`);return te(this,Al).get(t)??!1}set(t,r){if(!VH.has(t))throw new TypeError(`unknown feature: ${t}`);te(this,Al).set(t,!!r)}};Al=new WeakMap;var JH=new iv;jH.exports={runtimeFeatures:JH,default:JH}});var ul=x((ZFe,$H)=>{"use strict";var Av=$t(),{ReadableStreamFrom:lme,readableStreamClose:hme,fullyReadBody:dme,extractMimeType:gme}=Kf(),{FormData:zH,setFormDataState:pme}=X_(),{webidl:ms}=po(),ov=Wt(),{isErrored:av,isDisturbed:Eme}=(ts(),Gs(Yt)),{isUint8Array:yme}=Dw(),{serializeAMimeType:mme}=Bf(),{multipartFormDataParser:Bme}=YH(),{createDeferredPromise:Ime}=nv(),{parseJSONFromBytes:bme}=mf(),{utf8DecodeBytes:Cme}=_w(),{runtimeFeatures:Qme}=sv(),wme=Qme.has("crypto")?kd().randomInt:e=>Math.floor(Math.random()*e),am=new TextEncoder;function Sme(){}var _me=new FinalizationRegistry(e=>{let t=e.deref();t&&!t.locked&&!Eme(t)&&!av(t)&&t.cancel("Response object has been garbage collected").catch(Sme)});function XH(e,t=!1){let r=null,n=null;ms.is.ReadableStream(e)?r=e:ms.is.Blob(e)?r=e.stream():r=new ReadableStream({pull(){},start(f){n=f},cancel(){},type:"bytes"}),ov(ms.is.ReadableStream(r));let i=null,s=null,o=null,a=null;if(typeof e=="string")s=e,a="text/plain;charset=UTF-8";else if(ms.is.URLSearchParams(e))s=e.toString(),a="application/x-www-form-urlencoded;charset=UTF-8";else if(ms.is.BufferSource(e))s=ms.util.getCopyOfBytesHeldByBufferSource(e);else if(ms.is.FormData(e)){let f=`----formdata-undici-0${`${wme(1e11)}`.padStart(11,"0")}`,l=`--${f}\r -Content-Disposition: form-data`;let p=U=>U.replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/"/g,"%22"),B=U=>U.replace(/\r?\n|\r/g,`\r -`),S=[],_=new Uint8Array([13,10]);o=0;let N=!1;for(let[U,G]of e)if(typeof G=="string"){let Y=am.encode(l+`; name="${p(B(U))}"\r -\r -${B(G)}\r -`);S.push(Y),o+=Y.byteLength}else{let Y=am.encode(`${l}; name="${p(B(U))}"`+(G.name?`; filename="${p(G.name)}"`:"")+`\r -Content-Type: ${G.type||"application/octet-stream"}\r -\r -`);S.push(Y,G,_),typeof G.size=="number"?o+=Y.byteLength+G.size+_.byteLength:N=!0}let P=am.encode(`--${f}--\r -`);S.push(P),o+=P.byteLength,N&&(o=null),s=e,i=async function*(){for(let U of S)U.stream?yield*U.stream():yield U},a=`multipart/form-data; boundary=${f}`}else if(ms.is.Blob(e))s=e,o=e.size,e.type&&(a=e.type);else if(typeof e[Symbol.asyncIterator]=="function"){if(t)throw new TypeError("keepalive");if(Av.isDisturbed(e)||e.locked)throw new TypeError("Response body object should not be disturbed or locked");r=ms.is.ReadableStream(e)?e:lme(e)}return(typeof s=="string"||yme(s))&&(i=()=>(o=typeof s=="string"?Buffer.byteLength(s):s.length,s)),i!=null&&(async()=>{let f=i(),l=f?.[Symbol.asyncIterator]?.();if(l)for await(let p of l){if(av(r))break;p.length&&n.enqueue(new Uint8Array(p))}else f?.length&&!av(r)&&n.enqueue(typeof f=="string"?am.encode(f):new Uint8Array(f));queueMicrotask(()=>hme(n))})(),[{stream:r,source:s,length:o},a]}function vme(e,t=!1){return ms.is.ReadableStream(e)&&(ov(!Av.isDisturbed(e),"The body has already been consumed."),ov(!e.locked,"The stream is locked.")),XH(e,t)}function Rme(e){let{0:t,1:r}=e.stream.tee();return e.stream=t,{stream:r,length:e.length,source:e.source}}function Dme(e,t){return{blob(){return fl(this,n=>{let i=KH(t(this));return i===null?i="":i&&(i=mme(i)),new Blob([n],{type:i})},e,t)},arrayBuffer(){return fl(this,n=>new Uint8Array(n).buffer,e,t)},text(){return fl(this,Cme,e,t)},json(){return fl(this,bme,e,t)},formData(){return fl(this,n=>{let i=KH(t(this));if(i!==null)switch(i.essence){case"multipart/form-data":{let s=Bme(n,i),o=new zH;return pme(o,s),o}case"application/x-www-form-urlencoded":{let s=new URLSearchParams(n.toString()),o=new zH;for(let[a,A]of s)o.append(a,A);return o}}throw new TypeError('Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".')},e,t)},bytes(){return fl(this,n=>new Uint8Array(n),e,t)}}}function Tme(e,t){Object.assign(e.prototype,Dme(e,t))}function fl(e,t,r,n){try{ms.brandCheck(e,r)}catch(a){return Promise.reject(a)}if(e=n(e),ZH(e))return Promise.reject(new TypeError("Body is unusable: Body has already been read"));let i=Ime(),s=i.reject,o=a=>{try{i.resolve(t(a))}catch(A){s(A)}};return e.body==null?(o(Buffer.allocUnsafe(0)),i.promise):(dme(e.body,o,s),i.promise)}function ZH(e){let t=e.body;return t!=null&&(t.stream.locked||Av.isDisturbed(t.stream))}function KH(e){let t=e.headersList,r=gme(t);return r==="failure"?null:r}$H.exports={extractBody:XH,safelyExtractBody:vme,cloneBody:Rme,mixinBody:Tme,streamRegistry:_me,bodyUnusable:ZH}});var u7=x(($Fe,f7)=>{"use strict";var Oe=Wt(),qe=$t(),{channels:e7}=nd(),fv=TQ(),{RequestContentLengthMismatchError:Xf,ResponseContentLengthMismatchError:Nme,RequestAbortedError:o7,HeadersTimeoutError:Mme,HeadersOverflowError:Fme,SocketError:$d,InformationalError:cl,BodyTimeoutError:kme,HTTPParserError:xme,ResponseExceededMaxSizeError:Ume}=mr(),{kUrl:a7,kReset:Ln,kClient:pv,kParser:cr,kBlocking:eg,kRunning:un,kPending:Lme,kSize:t7,kWriting:mA,kQueue:Bs,kNoRef:Xd,kKeepAliveDefaultTimeout:Pme,kHostHeader:Ome,kPendingIdx:Hme,kRunningIdx:Ti,kError:Ni,kPipelining:um,kSocket:ll,kKeepAliveTimeoutValue:lm,kMaxHeadersSize:qme,kKeepAliveMaxTimeout:Gme,kKeepAliveTimeoutThreshold:Yme,kHeadersTimeout:Wme,kBodyTimeout:Vme,kStrictContentLength:lv,kMaxRequests:r7,kCounter:Jme,kMaxResponseSize:jme,kOnError:zme,kResume:yA,kHTTPContext:A7,kClosed:hv}=Tn(),Eo=g3(),Kme=Buffer.alloc(0),Am=Buffer[Symbol.species],Xme=qe.removeAllListeners,uv;function Zme(){let e=process.env.JEST_WORKER_ID?Qw():void 0,t,r=process.arch!=="ppc64";if(process.env.UNDICI_NO_WASM_SIMD==="1"?r=!0:process.env.UNDICI_NO_WASM_SIMD==="0"&&(r=!1),r)try{t=new WebAssembly.Module(y3())}catch{}return t||(t=new WebAssembly.Module(e||Qw())),new WebAssembly.Instance(t,{env:{wasm_on_url:(n,i,s)=>0,wasm_on_status:(n,i,s)=>{Oe(Rr.ptr===n);let o=i-mo+yo.byteOffset;return Rr.onStatus(new Am(yo.buffer,o,s))},wasm_on_message_begin:n=>(Oe(Rr.ptr===n),Rr.onMessageBegin()),wasm_on_header_field:(n,i,s)=>{Oe(Rr.ptr===n);let o=i-mo+yo.byteOffset;return Rr.onHeaderField(new Am(yo.buffer,o,s))},wasm_on_header_value:(n,i,s)=>{Oe(Rr.ptr===n);let o=i-mo+yo.byteOffset;return Rr.onHeaderValue(new Am(yo.buffer,o,s))},wasm_on_headers_complete:(n,i,s,o)=>(Oe(Rr.ptr===n),Rr.onHeadersComplete(i,s===1,o===1)),wasm_on_body:(n,i,s)=>{Oe(Rr.ptr===n);let o=i-mo+yo.byteOffset;return Rr.onBody(new Am(yo.buffer,o,s))},wasm_on_message_complete:n=>(Oe(Rr.ptr===n),Rr.onMessageComplete())}})}var cv=null,Rr=null,yo=null,fm=0,mo=null,$me=0,Zd=1,hl=2|Zd,cm=4|Zd,dv=8|$me,gv=class{constructor(t,r,{exports:n}){this.llhttp=n,this.ptr=this.llhttp.llhttp_alloc(Eo.TYPE.RESPONSE),this.client=t,this.socket=r,this.timeout=null,this.timeoutValue=null,this.timeoutType=null,this.statusCode=0,this.statusText="",this.upgrade=!1,this.headers=[],this.headersSize=0,this.headersMaxSize=t[qme],this.shouldKeepAlive=!1,this.paused=!1,this.resume=this.resume.bind(this),this.bytesRead=0,this.keepAlive="",this.contentLength="",this.connection="",this.maxResponseSize=t[jme]}setTimeout(t,r){t!==this.timeoutValue||r&Zd^this.timeoutType&Zd?(this.timeout&&(fv.clearTimeout(this.timeout),this.timeout=null),t&&(r&Zd?this.timeout=fv.setFastTimeout(n7,t,new WeakRef(this)):(this.timeout=setTimeout(n7,t,new WeakRef(this)),this.timeout?.unref())),this.timeoutValue=t):this.timeout&&this.timeout.refresh&&this.timeout.refresh(),this.timeoutType=r}resume(){this.socket.destroyed||!this.paused||(Oe(this.ptr!=null),Oe(Rr===null),this.llhttp.llhttp_resume(this.ptr),Oe(this.timeoutType===cm),this.timeout&&this.timeout.refresh&&this.timeout.refresh(),this.paused=!1,this.execute(this.socket.read()||Kme),this.readMore())}readMore(){for(;!this.paused&&this.ptr;){let t=this.socket.read();if(t===null)break;this.execute(t)}}execute(t){Oe(Rr===null),Oe(this.ptr!=null),Oe(!this.paused);let{socket:r,llhttp:n}=this;t.length>fm&&(mo&&n.free(mo),fm=Math.ceil(t.length/4096)*4096,mo=n.malloc(fm)),new Uint8Array(n.memory.buffer,mo,fm).set(t);try{let i;try{yo=t,Rr=this,i=n.llhttp_execute(this.ptr,mo,t.length)}finally{Rr=null,yo=null}if(i!==Eo.ERROR.OK){let s=t.subarray(n.llhttp_get_error_pos(this.ptr)-mo);if(i===Eo.ERROR.PAUSED_UPGRADE)this.onUpgrade(s);else if(i===Eo.ERROR.PAUSED)this.paused=!0,r.unshift(s);else{let o=n.llhttp_get_error_reason(this.ptr),a="";if(o){let A=new Uint8Array(n.memory.buffer,o).indexOf(0);a="Response does not match the HTTP/1.1 protocol ("+Buffer.from(n.memory.buffer,o,A).toString()+")"}throw new xme(a,Eo.ERROR[i],s)}}}catch(i){qe.destroy(r,i)}}destroy(){Oe(Rr===null),Oe(this.ptr!=null),this.llhttp.llhttp_free(this.ptr),this.ptr=null,this.timeout&&fv.clearTimeout(this.timeout),this.timeout=null,this.timeoutValue=null,this.timeoutType=null,this.paused=!1}onStatus(t){return this.statusText=t.toString(),0}onMessageBegin(){let{socket:t,client:r}=this;if(t.destroyed)return-1;let n=r[Bs][r[Ti]];return n?(n.onResponseStarted(),0):-1}onHeaderField(t){let r=this.headers.length;return(r&1)===0?this.headers.push(t):this.headers[r-1]=Buffer.concat([this.headers[r-1],t]),this.trackHeader(t.length),0}onHeaderValue(t){let r=this.headers.length;(r&1)===1?(this.headers.push(t),r+=1):this.headers[r-1]=Buffer.concat([this.headers[r-1],t]);let n=this.headers[r-2];if(n.length===10){let i=qe.bufferToLowerCasedHeaderName(n);i==="keep-alive"?this.keepAlive+=t.toString():i==="connection"&&(this.connection+=t.toString())}else n.length===14&&qe.bufferToLowerCasedHeaderName(n)==="content-length"&&(this.contentLength+=t.toString());return this.trackHeader(t.length),0}trackHeader(t){this.headersSize+=t,this.headersSize>=this.headersMaxSize&&qe.destroy(this.socket,new Fme)}onUpgrade(t){let{upgrade:r,client:n,socket:i,headers:s,statusCode:o}=this;Oe(r),Oe(n[ll]===i),Oe(!i.destroyed),Oe(!this.paused),Oe((s.length&1)===0);let a=n[Bs][n[Ti]];Oe(a),Oe(a.upgrade||a.method==="CONNECT"),this.statusCode=0,this.statusText="",this.shouldKeepAlive=!1,this.headers=[],this.headersSize=0,i.unshift(t),i[cr].destroy(),i[cr]=null,i[pv]=null,i[Ni]=null,Xme(i),n[ll]=null,n[A7]=null,n[Bs][n[Ti]++]=null,n.emit("disconnect",n[a7],[n],new cl("upgrade"));try{a.onUpgrade(o,s,i)}catch(A){qe.destroy(i,A)}n[yA]()}onHeadersComplete(t,r,n){let{client:i,socket:s,headers:o,statusText:a}=this;if(s.destroyed)return-1;let A=i[Bs][i[Ti]];if(!A)return-1;if(Oe(!this.upgrade),Oe(this.statusCode<200),t===100)return qe.destroy(s,new $d("bad response",qe.getSocketInfo(s))),-1;if(r&&!A.upgrade)return qe.destroy(s,new $d("bad upgrade",qe.getSocketInfo(s))),-1;if(Oe(this.timeoutType===hl),this.statusCode=t,this.shouldKeepAlive=n||A.method==="HEAD"&&!s[Ln]&&this.connection.toLowerCase()==="keep-alive",this.statusCode>=200){let l=A.bodyTimeout!=null?A.bodyTimeout:i[Vme];this.setTimeout(l,cm)}else this.timeout&&this.timeout.refresh&&this.timeout.refresh();if(A.method==="CONNECT")return Oe(i[un]===1),this.upgrade=!0,2;if(r)return Oe(i[un]===1),this.upgrade=!0,2;if(Oe((this.headers.length&1)===0),this.headers=[],this.headersSize=0,this.shouldKeepAlive&&i[um]){let l=this.keepAlive?qe.parseKeepAliveTimeout(this.keepAlive):null;if(l!=null){let p=Math.min(l-i[Yme],i[Gme]);p<=0?s[Ln]=!0:i[lm]=p}else i[lm]=i[Pme]}else s[Ln]=!0;let f=A.onHeaders(t,o,this.resume,a)===!1;return A.aborted?-1:A.method==="HEAD"||t<200?1:(s[eg]&&(s[eg]=!1,i[yA]()),f?Eo.ERROR.PAUSED:0)}onBody(t){let{client:r,socket:n,statusCode:i,maxResponseSize:s}=this;if(n.destroyed)return-1;let o=r[Bs][r[Ti]];return Oe(o),Oe(this.timeoutType===cm),this.timeout&&this.timeout.refresh&&this.timeout.refresh(),Oe(i>=200),s>-1&&this.bytesRead+t.length>s?(qe.destroy(n,new Ume),-1):(this.bytesRead+=t.length,o.onData(t)===!1?Eo.ERROR.PAUSED:0)}onMessageComplete(){let{client:t,socket:r,statusCode:n,upgrade:i,headers:s,contentLength:o,bytesRead:a,shouldKeepAlive:A}=this;if(r.destroyed&&(!n||A))return-1;if(i)return 0;Oe(n>=100),Oe((this.headers.length&1)===0);let f=t[Bs][t[Ti]];if(Oe(f),this.statusCode=0,this.statusText="",this.bytesRead=0,this.contentLength="",this.keepAlive="",this.connection="",this.headers=[],this.headersSize=0,n<200)return 0;if(f.method!=="HEAD"&&o&&a!==parseInt(o,10))return qe.destroy(r,new Nme),-1;if(f.onComplete(s),t[Bs][t[Ti]++]=null,r[mA])return Oe(t[un]===0),qe.destroy(r,new cl("reset")),Eo.ERROR.PAUSED;if(A){if(r[Ln]&&t[un]===0)return qe.destroy(r,new cl("reset")),Eo.ERROR.PAUSED;t[um]==null||t[um]===1?setImmediate(t[yA]):t[yA]()}else return qe.destroy(r,new cl("reset")),Eo.ERROR.PAUSED;return 0}};function n7(e){let t=e.deref();if(!t)return;let{socket:r,timeoutType:n,client:i,paused:s}=t;n===hl?(!r[mA]||r.writableNeedDrain||i[un]>1)&&(Oe(!s,"cannot be paused while waiting for headers"),qe.destroy(r,new Mme)):n===cm?s||qe.destroy(r,new kme):n===dv&&(Oe(i[un]===0&&i[lm]),qe.destroy(r,new cl("socket idle timeout")))}function eBe(e,t){if(e[ll]=t,cv||(cv=Zme()),t.errored)throw t.errored;if(t.destroyed)throw new $d("destroyed");return t[Xd]=!1,t[mA]=!1,t[Ln]=!1,t[eg]=!1,t[cr]=new gv(e,t,cv),qe.addListener(t,"error",tBe),qe.addListener(t,"readable",rBe),qe.addListener(t,"end",nBe),qe.addListener(t,"close",iBe),t[hv]=!1,t.on("close",sBe),{version:"h1",defaultPipelining:1,write(r){return ABe(e,r)},resume(){oBe(e)},destroy(r,n){t[hv]?queueMicrotask(n):(t.on("close",n),t.destroy(r))},get destroyed(){return t.destroyed},busy(r){return!!(t[mA]||t[Ln]||t[eg]||r&&(e[un]>0&&!r.idempotent||e[un]>0&&(r.upgrade||r.method==="CONNECT")||e[un]>0&&qe.bodyLength(r.body)!==0&&(qe.isStream(r.body)||qe.isAsyncIterable(r.body)||qe.isFormDataLike(r.body))))}}}function tBe(e){Oe(e.code!=="ERR_TLS_CERT_ALTNAME_INVALID");let t=this[cr];if(e.code==="ECONNRESET"&&t.statusCode&&!t.shouldKeepAlive){t.onMessageComplete();return}this[Ni]=e,this[pv][zme](e)}function rBe(){this[cr]?.readMore()}function nBe(){let e=this[cr];if(e.statusCode&&!e.shouldKeepAlive){e.onMessageComplete();return}qe.destroy(this,new $d("other side closed",qe.getSocketInfo(this)))}function iBe(){let e=this[cr];e&&(!this[Ni]&&e.statusCode&&!e.shouldKeepAlive&&e.onMessageComplete(),this[cr].destroy(),this[cr]=null);let t=this[Ni]||new $d("closed",qe.getSocketInfo(this)),r=this[pv];if(r[ll]=null,r[A7]=null,r.destroyed){Oe(r[Lme]===0);let n=r[Bs].splice(r[Ti]);for(let i=0;i0&&t.code!=="UND_ERR_INFO"){let n=r[Bs][r[Ti]];r[Bs][r[Ti]++]=null,qe.errorRequest(r,n,t)}r[Hme]=r[Ti],Oe(r[un]===0),r.emit("disconnect",r[a7],[r],t),r[yA]()}function sBe(){this[hv]=!0}function oBe(e){let t=e[ll];if(t&&!t.destroyed){if(e[t7]===0?!t[Xd]&&t.unref&&(t.unref(),t[Xd]=!0):t[Xd]&&t.ref&&(t.ref(),t[Xd]=!1),e[t7]===0)t[cr].timeoutType!==dv&&t[cr].setTimeout(e[lm],dv);else if(e[un]>0&&t[cr].statusCode<200&&t[cr].timeoutType!==hl){let r=e[Bs][e[Ti]],n=r.headersTimeout!=null?r.headersTimeout:e[Wme];t[cr].setTimeout(n,hl)}}}function aBe(e){return e!=="GET"&&e!=="HEAD"&&e!=="OPTIONS"&&e!=="TRACE"&&e!=="CONNECT"}function ABe(e,t){let{method:r,path:n,host:i,upgrade:s,blocking:o,reset:a}=t,{body:A,headers:f,contentLength:l}=t,p=r==="PUT"||r==="POST"||r==="PATCH"||r==="QUERY"||r==="PROPFIND"||r==="PROPPATCH";if(qe.isFormDataLike(A)){uv||(uv=ul().extractBody);let[P,U]=uv(A);t.contentType==null&&f.push("content-type",U),A=P.stream,l=P.length}else qe.isBlobLike(A)&&t.contentType==null&&A.type&&f.push("content-type",A.type);A&&typeof A.read=="function"&&A.read(0);let B=qe.bodyLength(A);if(l=B??l,l===null&&(l=t.contentLength),l===0&&!p&&(l=null),aBe(r)&&l>0&&t.contentLength!==null&&t.contentLength!==l){if(e[lv])return qe.errorRequest(e,t,new Xf),!1;process.emitWarning(new Xf)}let S=e[ll],_=P=>{t.aborted||t.completed||(qe.errorRequest(e,t,P||new o7),qe.destroy(A),qe.destroy(S,new cl("aborted")))};try{t.onConnect(_)}catch(P){qe.errorRequest(e,t,P)}if(t.aborted)return!1;r==="HEAD"&&(S[Ln]=!0),(s||r==="CONNECT")&&(S[Ln]=!0),a!=null&&(S[Ln]=a),e[r7]&&S[Jme]++>=e[r7]&&(S[Ln]=!0),o&&(S[eg]=!0),S.setTypeOfService&&S.setTypeOfService(t.typeOfService);let N=`${r} ${n} HTTP/1.1\r -`;if(typeof i=="string"?N+=`host: ${i}\r -`:N+=e[Ome],s?N+=`connection: upgrade\r -upgrade: ${s}\r -`:e[um]&&!S[Ln]?N+=`connection: keep-alive\r -`:N+=`connection: close\r -`,Array.isArray(f))for(let P=0;P{t.removeListener("error",S)}),!A){let _=new o7;queueMicrotask(()=>S(_))}},S=function(_){if(!A){if(A=!0,Oe(i.destroyed||i[mA]&&r[un]<=1),i.off("drain",p).off("error",S),t.removeListener("data",l).removeListener("end",S).removeListener("close",B),!_)try{f.end()}catch(N){_=N}f.destroy(_),_&&(_.code!=="UND_ERR_INFO"||_.message!=="reset")?qe.destroy(t,_):qe.destroy(t)}};t.on("data",l).on("end",S).on("error",S).on("close",B),t.resume&&t.resume(),i.on("drain",p).on("error",S),t.errorEmitted??t.errored?setImmediate(S,t.errored):(t.endEmitted??t.readableEnded)&&setImmediate(S,null),(t.closeEmitted??t.closed)&&setImmediate(B)}function i7(e,t,r,n,i,s,o,a){try{t?qe.isBuffer(t)&&(Oe(s===t.byteLength,"buffer body must have content length"),i.cork(),i.write(`${o}content-length: ${s}\r -\r -`,"latin1"),i.write(t),i.uncork(),n.onBodySent(t),!a&&n.reset!==!1&&(i[Ln]=!0)):s===0?i.write(`${o}content-length: 0\r -\r -`,"latin1"):(Oe(s===null,"no body must not have content length"),i.write(`${o}\r -`,"latin1")),n.onRequestSent(),r[yA]()}catch(A){e(A)}}async function uBe(e,t,r,n,i,s,o,a){Oe(s===t.size,"blob body must have content length");try{if(s!=null&&s!==t.size)throw new Xf;let A=Buffer.from(await t.arrayBuffer());i.cork(),i.write(`${o}content-length: ${s}\r -\r -`,"latin1"),i.write(A),i.uncork(),n.onBodySent(A),n.onRequestSent(),!a&&n.reset!==!1&&(i[Ln]=!0),r[yA]()}catch(A){e(A)}}async function s7(e,t,r,n,i,s,o,a){Oe(s!==0||r[un]===0,"iterator body cannot be pipelined");let A=null;function f(){if(A){let B=A;A=null,B()}}let l=()=>new Promise((B,S)=>{Oe(A===null),i[Ni]?S(i[Ni]):A=B});i.on("close",f).on("drain",f);let p=new hm({abort:e,socket:i,request:n,contentLength:s,client:r,expectsPayload:a,header:o});try{for await(let B of t){if(i[Ni])throw i[Ni];p.write(B)||await l()}p.end()}catch(B){p.destroy(B)}finally{i.off("close",f).off("drain",f)}}var hm=class{constructor({abort:t,socket:r,request:n,contentLength:i,client:s,expectsPayload:o,header:a}){this.socket=r,this.request=n,this.contentLength=i,this.client=s,this.bytesWritten=0,this.expectsPayload=o,this.header=a,this.abort=t,r[mA]=!0}write(t){let{socket:r,request:n,contentLength:i,client:s,bytesWritten:o,expectsPayload:a,header:A}=this;if(r[Ni])throw r[Ni];if(r.destroyed)return!1;let f=Buffer.byteLength(t);if(!f)return!0;if(i!==null&&o+f>i){if(s[lv])throw new Xf;process.emitWarning(new Xf)}r.cork(),o===0&&(!a&&n.reset!==!1&&(r[Ln]=!0),i===null?r.write(`${A}transfer-encoding: chunked\r -`,"latin1"):r.write(`${A}content-length: ${i}\r -\r -`,"latin1")),i===null&&r.write(`\r -${f.toString(16)}\r -`,"latin1"),this.bytesWritten+=f;let l=r.write(t);return r.uncork(),n.onBodySent(t),l||r[cr].timeout&&r[cr].timeoutType===hl&&r[cr].timeout.refresh&&r[cr].timeout.refresh(),l}end(){let{socket:t,contentLength:r,client:n,bytesWritten:i,expectsPayload:s,header:o,request:a}=this;if(a.onRequestSent(),t[mA]=!1,t[Ni])throw t[Ni];if(!t.destroyed){if(i===0?s?t.write(`${o}content-length: 0\r -\r -`,"latin1"):t.write(`${o}\r -`,"latin1"):r===null&&t.write(`\r -0\r -\r -`,"latin1"),r!==null&&i!==r){if(n[lv])throw new Xf;process.emitWarning(new Xf)}t[cr].timeout&&t[cr].timeoutType===hl&&t[cr].timeout.refresh&&t[cr].timeout.refresh(),n[yA]()}}destroy(t){let{socket:r,client:n,abort:i}=this;r[mA]=!1,t&&(Oe(n[un]<=1,"pipeline should only contain this request"),i(t))}};f7.exports=eBe});var h7=x((eke,l7)=>{"use strict";var c7={HTTP2_HEADER_METHOD:":method",HTTP2_HEADER_PATH:":path",HTTP2_HEADER_SCHEME:":scheme",HTTP2_HEADER_AUTHORITY:":authority",HTTP2_HEADER_STATUS:":status",HTTP2_HEADER_CONTENT_TYPE:"content-type",HTTP2_HEADER_CONTENT_LENGTH:"content-length",HTTP2_HEADER_LAST_MODIFIED:"last-modified",HTTP2_HEADER_ACCEPT:"accept",HTTP2_HEADER_ACCEPT_ENCODING:"accept-encoding",HTTP2_METHOD_GET:"GET",HTTP2_METHOD_POST:"POST",HTTP2_METHOD_PUT:"PUT",HTTP2_METHOD_DELETE:"DELETE",DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE:65535};function Ev(e){let t=new Error(`node:http2 ${e} is not available in the secure-exec bridge bootstrap`);throw t.code="ERR_NOT_IMPLEMENTED",t}function cBe(){Ev("connect")}function lBe(){Ev("createServer")}function hBe(){Ev("createSecureServer")}function dBe(){return{maxHeaderListSize:c7.DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE}}l7.exports={constants:c7,connect:cBe,createServer:lBe,createSecureServer:hBe,getDefaultSettings:dBe}});var b7=x((tke,I7)=>{"use strict";var Fi=Wt(),{pipeline:gBe}=(ts(),Gs(Yt)),ct=$t(),{RequestContentLengthMismatchError:Iv,RequestAbortedError:pBe,SocketError:ig,InformationalError:BA,InvalidArgumentError:EBe}=mr(),{kUrl:ng,kReset:Em,kClient:ei,kRunning:sg,kPending:yBe,kQueue:IA,kPendingIdx:Cv,kRunningIdx:Is,kError:ti,kSocket:or,kStrictContentLength:mBe,kOnError:dl,kMaxConcurrentStreams:gm,kPingInterval:d7,kHTTP2Session:ha,kHTTP2InitialWindowSize:BBe,kHTTP2ConnectionWindowSize:IBe,kResume:Bo,kSize:bBe,kHTTPContext:Qv,kClosed:bv,kBodyTimeout:CBe,kEnableConnectProtocol:tg,kRemoteSettings:rg,kHTTP2Stream:dm,kHTTP2SessionState:wv}=Tn(),{channels:g7}=nd(),Mi=Symbol("open streams"),p7,pm;try{pm=h7()}catch{pm={constants:{}}}var{constants:{HTTP2_HEADER_AUTHORITY:QBe,HTTP2_HEADER_METHOD:E7,HTTP2_HEADER_PATH:y7,HTTP2_HEADER_SCHEME:yv,HTTP2_HEADER_CONTENT_LENGTH:wBe,HTTP2_HEADER_EXPECT:SBe,HTTP2_HEADER_STATUS:mv,HTTP2_HEADER_PROTOCOL:_Be,NGHTTP2_REFUSED_STREAM:vBe,NGHTTP2_CANCEL:RBe}}=pm;function Bv(e){let t=[];for(let[r,n]of Object.entries(e))if(Array.isArray(n))for(let i of n)t.push(Buffer.from(r),Buffer.from(i));else t.push(Buffer.from(r),Buffer.from(n));return t}function DBe(e,t){e[or]=t;let r=e[BBe],n=e[IBe],i=pm.connect(e[ng],{createConnection:()=>t,peerMaxConcurrentStreams:e[gm],settings:{enablePush:!1,...r!=null?{initialWindowSize:r}:null}});return e[or]=t,i[Mi]=0,i[ei]=e,i[or]=t,i[wv]={ping:{interval:e[d7]===0?null:setInterval(FBe,e[d7],i).unref()}},i[tg]=!1,i[rg]=!1,n&&ct.addListener(i,"connect",NBe.bind(i,n)),ct.addListener(i,"error",kBe),ct.addListener(i,"frameError",xBe),ct.addListener(i,"end",UBe),ct.addListener(i,"goaway",LBe),ct.addListener(i,"close",PBe),ct.addListener(i,"remoteSettings",MBe),i.unref(),e[ha]=i,t[ha]=i,ct.addListener(t,"error",HBe),ct.addListener(t,"end",qBe),ct.addListener(t,"close",OBe),t[bv]=!1,t.on("close",GBe),{version:"h2",defaultPipelining:1/0,write(s){return WBe(e,s)},resume(){TBe(e)},destroy(s,o){t[bv]?queueMicrotask(o):t.destroy(s).on("close",o)},get destroyed(){return t.destroyed},busy(s){if(s!=null)if(e[sg]>0){if(s.idempotent===!1||(s.upgrade==="websocket"||s.method==="CONNECT")&&i[rg]===!1||ct.bodyLength(s.body)!==0&&(ct.isStream(s.body)||ct.isAsyncIterable(s.body)||ct.isFormDataLike(s.body)))return!0}else return(s.upgrade==="websocket"||s.method==="CONNECT")&&i[rg]===!1;return!1}}}function TBe(e){let t=e[or];t?.destroyed===!1&&(e[bBe]===0||e[gm]===0?(t.unref(),e[ha].unref()):(t.ref(),e[ha].ref()))}function NBe(e){try{typeof this.setLocalWindowSize=="function"&&this.setLocalWindowSize(e)}catch{}}function MBe(e){if(this[ei][gm]=e.maxConcurrentStreams??this[ei][gm],this[rg]===!0&&this[tg]===!0&&e.enableConnectProtocol===!1){let t=new BA("HTTP/2: Server disabled extended CONNECT protocol against RFC-8441");this[or][ti]=t,this[ei][dl](t);return}this[tg]=e.enableConnectProtocol??this[tg],this[rg]=!0,this[ei][Bo]()}function FBe(e){let t=e[wv];if((e.closed||e.destroyed)&&t.ping.interval!=null){clearInterval(t.ping.interval),t.ping.interval=null;return}e.ping(r.bind(e));function r(n,i){let s=this[ei],o=this[ei];if(n!=null){let a=new BA(`HTTP/2: "PING" errored - type ${n.message}`);o[ti]=a,s[dl](a)}else s.emit("ping",i)}}function kBe(e){Fi(e.code!=="ERR_TLS_CERT_ALTNAME_INVALID"),this[or][ti]=e,this[ei][dl](e)}function xBe(e,t,r){if(r===0){let n=new BA(`HTTP/2: "frameError" received - type ${e}, code ${t}`);this[or][ti]=n,this[ei][dl](n)}}function UBe(){let e=new ig("other side closed",ct.getSocketInfo(this[or]));this.destroy(e),ct.destroy(this[or],e)}function LBe(e){let t=this[ti]||new ig(`HTTP/2: "GOAWAY" frame received with code ${e}`,ct.getSocketInfo(this[or])),r=this[ei];if(r[or]=null,r[Qv]=null,this.close(),this[ha]=null,ct.destroy(this[or],t),r[Is]{t.aborted||t.completed||(se=se||new pBe,ct.errorRequest(e,t,se),_!=null&&(_.removeAllListeners("data"),_.close(),e[dl](se),e[Bo]()),ct.destroy(B,se))};try{t.onConnect(U)}catch(se){ct.errorRequest(e,t,se)}if(t.aborted)return!1;if(a||i==="CONNECT")return n.ref(),a==="websocket"?n[tg]===!1?(ct.errorRequest(e,t,new BA("HTTP/2: Extended CONNECT protocol not supported by server")),n.unref(),!1):(S[E7]="CONNECT",S[_Be]="websocket",S[y7]=s,l==="ws:"||l==="wss:"?S[yv]=l==="ws:"?"http":"https":S[yv]=l==="http:"?"http":"https",_=n.request(S,{endStream:!1,signal:f}),_[dm]=!0,_.once("response",(se,ie)=>{let{[mv]:ce,...H}=se;t.onUpgrade(ce,Bv(H),_),++n[Mi],e[IA][e[Is]++]=null}),_.on("error",()=>{(_.rstCode===vBe||_.rstCode===RBe)&&U(new BA(`HTTP/2: "stream error" received - code ${_.rstCode}`))}),_.once("close",()=>{n[Mi]-=1,n[Mi]===0&&n.unref()}),_.setTimeout(r),!0):(_=n.request(S,{endStream:!1,signal:f}),_[dm]=!0,_.on("response",se=>{let{[mv]:ie,...ce}=se;t.onUpgrade(ie,Bv(ce),_),++n[Mi],e[IA][e[Is]++]=null}),_.once("close",()=>{n[Mi]-=1,n[Mi]===0&&n.unref()}),_.setTimeout(r),!0);S[y7]=s,S[yv]=l==="http:"?"http":"https";let G=i==="PUT"||i==="POST"||i==="PATCH";B&&typeof B.read=="function"&&B.read(0);let Y=ct.bodyLength(B);if(ct.isFormDataLike(B)){p7??(p7=ul().extractBody);let[se,ie]=p7(B);S["content-type"]=ie,B=se.stream,Y=se.length}if(Y==null&&(Y=t.contentLength),G||(Y=null),YBe(i)&&Y>0&&t.contentLength!=null&&t.contentLength!==Y){if(e[mBe])return ct.errorRequest(e,t,new Iv),!1;process.emitWarning(new Iv)}if(Y!=null&&(Fi(B||Y===0,"no body must not have content length"),S[wBe]=`${Y}`),n.ref(),g7.sendHeaders.hasSubscribers){let se="";for(let ie in S)se+=`${ie}: ${S[ie]}\r -`;g7.sendHeaders.publish({request:t,headers:se,socket:n[or]})}let Z=i==="GET"||i==="HEAD"||B===null;A?(S[SBe]="100-continue",_=n.request(S,{endStream:Z,signal:f}),_[dm]=!0,_.once("continue",j)):(_=n.request(S,{endStream:Z,signal:f}),_[dm]=!0,j()),++n[Mi],_.setTimeout(r);let ee=!1;return _.once("response",se=>{let{[mv]:ie,...ce}=se;if(t.onResponseStarted(),ee=!0,t.aborted){_.removeAllListeners("data");return}t.onHeaders(Number(ie),Bv(ce),_.resume.bind(_),"")===!1&&_.pause(),_.on("data",H=>{t.aborted||t.completed||t.onData(H)===!1&&_.pause()})}),_.once("end",()=>{_.removeAllListeners("data"),ee?(!t.aborted&&!t.completed&&t.onComplete({}),e[IA][e[Is]++]=null,e[Bo]()):(U(new BA("HTTP/2: stream half-closed (remote)")),e[IA][e[Is]++]=null,e[Cv]=e[Is],e[Bo]())}),_.once("close",()=>{_.removeAllListeners("data"),n[Mi]-=1,n[Mi]===0&&n.unref()}),_.once("error",function(se){_.removeAllListeners("data"),U(se)}),_.once("frameError",(se,ie)=>{_.removeAllListeners("data"),U(new BA(`HTTP/2: "frameError" received - type ${se}, code ${ie}`))}),_.on("aborted",()=>{_.removeAllListeners("data")}),_.on("timeout",()=>{let se=new BA(`HTTP/2: "stream timeout after ${r}"`);_.removeAllListeners("data"),n[Mi]-=1,n[Mi]===0&&n.unref(),U(se)}),_.once("trailers",se=>{t.aborted||t.completed||(_.removeAllListeners("data"),t.onComplete(se))}),!0;function j(){!B||Y===0?m7(U,_,null,e,t,e[or],Y,G):ct.isBuffer(B)?m7(U,_,B,e,t,e[or],Y,G):ct.isBlobLike(B)?typeof B.stream=="function"?B7(U,_,B.stream(),e,t,e[or],Y,G):JBe(U,_,B,e,t,e[or],Y,G):ct.isStream(B)?VBe(U,e[or],G,_,B,e,t,Y):ct.isIterable(B)?B7(U,_,B,e,t,e[or],Y,G):Fi(!1)}}function m7(e,t,r,n,i,s,o,a){try{r!=null&&ct.isBuffer(r)&&(Fi(o===r.byteLength,"buffer body must have content length"),t.cork(),t.write(r),t.uncork(),t.end(),i.onBodySent(r)),a||(s[Em]=!0),i.onRequestSent(),n[Bo]()}catch(A){e(A)}}function VBe(e,t,r,n,i,s,o,a){Fi(a!==0||s[sg]===0,"stream body cannot be pipelined");let A=gBe(i,n,l=>{l?(ct.destroy(A,l),e(l)):(ct.removeAllListeners(A),o.onRequestSent(),r||(t[Em]=!0),s[Bo]())});ct.addListener(A,"data",f);function f(l){o.onBodySent(l)}}async function JBe(e,t,r,n,i,s,o,a){Fi(o===r.size,"blob body must have content length");try{if(o!=null&&o!==r.size)throw new Iv;let A=Buffer.from(await r.arrayBuffer());t.cork(),t.write(A),t.uncork(),t.end(),i.onBodySent(A),i.onRequestSent(),a||(s[Em]=!0),n[Bo]()}catch(A){e(A)}}async function B7(e,t,r,n,i,s,o,a){Fi(o!==0||n[sg]===0,"iterator body cannot be pipelined");let A=null;function f(){if(A){let p=A;A=null,p()}}let l=()=>new Promise((p,B)=>{Fi(A===null),s[ti]?B(s[ti]):A=p});t.on("close",f).on("drain",f);try{for await(let p of r){if(s[ti])throw s[ti];let B=t.write(p);i.onBodySent(p),B||await l()}t.end(),i.onRequestSent(),a||(s[Em]=!0),n[Bo]()}catch(p){e(p)}finally{t.off("close",f).off("drain",f)}}I7.exports=DBe});var mm=x((rke,D7)=>{"use strict";var da=Wt(),S7=pE(),og=gE(),Zf=$t(),{ClientStats:jBe}=ow(),{channels:gl}=nd(),zBe=a3(),KBe=DE(),{InvalidArgumentError:tr,InformationalError:XBe,ClientDestroyedError:ZBe}=mr(),$Be=Iw(),{kUrl:Io,kServerName:QA,kClient:eIe,kBusy:_v,kConnect:tIe,kResuming:$f,kRunning:ug,kPending:cg,kSize:ag,kQueue:bs,kConnected:rIe,kConnecting:pl,kNeedDrain:CA,kKeepAliveDefaultTimeout:C7,kHostHeader:nIe,kPendingIdx:Cs,kRunningIdx:pa,kError:iIe,kPipelining:ym,kKeepAliveTimeoutValue:sIe,kMaxHeadersSize:oIe,kKeepAliveMaxTimeout:aIe,kKeepAliveTimeoutThreshold:AIe,kHeadersTimeout:fIe,kBodyTimeout:uIe,kStrictContentLength:cIe,kConnector:Ag,kMaxRequests:vv,kCounter:lIe,kClose:hIe,kDestroy:dIe,kDispatch:gIe,kLocalAddress:fg,kMaxResponseSize:pIe,kOnError:EIe,kHTTPContext:dr,kMaxConcurrentStreams:yIe,kHTTP2InitialWindowSize:mIe,kHTTP2ConnectionWindowSize:BIe,kResume:ga,kPingInterval:IIe}=Tn(),bIe=u7(),CIe=b7(),bA=Symbol("kClosedResolve"),QIe=og&&og.maxHeaderSize&&Number.isInteger(og.maxHeaderSize)&&og.maxHeaderSize>0?()=>og.maxHeaderSize:()=>{throw new tr("http module not available or http.maxHeaderSize invalid")},Q7=()=>{};function _7(e){return e[ym]??e[dr]?.defaultPipelining??1}var Rv=class extends KBe{constructor(t,{maxHeaderSize:r,headersTimeout:n,socketTimeout:i,requestTimeout:s,connectTimeout:o,bodyTimeout:a,idleTimeout:A,keepAlive:f,keepAliveTimeout:l,maxKeepAliveTimeout:p,keepAliveMaxTimeout:B,keepAliveTimeoutThreshold:S,socketPath:_,pipelining:N,tls:P,strictContentLength:U,maxCachedSessions:G,connect:Y,maxRequestsPerClient:Z,localAddress:ee,maxResponseSize:j,autoSelectFamily:se,autoSelectFamilyAttemptTimeout:ie,maxConcurrentStreams:ce,allowH2:H,useH2c:E,initialWindowSize:v,connectionWindowSize:b,pingInterval:c}={}){if(f!==void 0)throw new tr("unsupported keepAlive, use pipelining=0 instead");if(i!==void 0)throw new tr("unsupported socketTimeout, use headersTimeout & bodyTimeout instead");if(s!==void 0)throw new tr("unsupported requestTimeout, use headersTimeout & bodyTimeout instead");if(A!==void 0)throw new tr("unsupported idleTimeout, use keepAliveTimeout instead");if(p!==void 0)throw new tr("unsupported maxKeepAliveTimeout, use keepAliveMaxTimeout instead");if(r!=null){if(!Number.isInteger(r)||r<1)throw new tr("invalid maxHeaderSize")}else r=QIe();if(_!=null&&typeof _!="string")throw new tr("invalid socketPath");if(o!=null&&(!Number.isFinite(o)||o<0))throw new tr("invalid connectTimeout");if(l!=null&&(!Number.isFinite(l)||l<=0))throw new tr("invalid keepAliveTimeout");if(B!=null&&(!Number.isFinite(B)||B<=0))throw new tr("invalid keepAliveMaxTimeout");if(S!=null&&!Number.isFinite(S))throw new tr("invalid keepAliveTimeoutThreshold");if(n!=null&&(!Number.isInteger(n)||n<0))throw new tr("headersTimeout must be a positive integer or zero");if(a!=null&&(!Number.isInteger(a)||a<0))throw new tr("bodyTimeout must be a positive integer or zero");if(Y!=null&&typeof Y!="function"&&typeof Y!="object")throw new tr("connect must be a function or an object");if(Z!=null&&(!Number.isInteger(Z)||Z<0))throw new tr("maxRequestsPerClient must be a positive number");if(ee!=null&&(typeof ee!="string"||S7.isIP(ee)===0))throw new tr("localAddress must be valid string IP address");if(j!=null&&(!Number.isInteger(j)||j<-1))throw new tr("maxResponseSize must be a positive number");if(ie!=null&&(!Number.isInteger(ie)||ie<-1))throw new tr("autoSelectFamilyAttemptTimeout must be a positive number");if(H!=null&&typeof H!="boolean")throw new tr("allowH2 must be a valid boolean value");if(ce!=null&&(typeof ce!="number"||ce<1))throw new tr("maxConcurrentStreams must be a positive integer, greater than 0");if(E!=null&&typeof E!="boolean")throw new tr("useH2c must be a valid boolean value");if(v!=null&&(!Number.isInteger(v)||v<1))throw new tr("initialWindowSize must be a positive integer, greater than 0");if(b!=null&&(!Number.isInteger(b)||b<1))throw new tr("connectionWindowSize must be a positive integer, greater than 0");if(c!=null&&(typeof c!="number"||!Number.isInteger(c)||c<0))throw new tr("pingInterval must be a positive integer, greater or equal to 0");if(super(),typeof Y!="function")Y=$Be({...P,maxCachedSessions:G,allowH2:H,useH2c:E,socketPath:_,timeout:o,...typeof se=="boolean"?{autoSelectFamily:se,autoSelectFamilyAttemptTimeout:ie}:void 0,...Y});else if(_!=null){let g=Y;Y=(w,R)=>g({...w,socketPath:_},R)}this[Io]=Zf.parseOrigin(t),this[Ag]=Y,this[ym]=N??1,this[oIe]=r,this[C7]=l??4e3,this[aIe]=B??6e5,this[AIe]=S??2e3,this[sIe]=this[C7],this[QA]=null,this[fg]=ee??null,this[$f]=0,this[CA]=0,this[nIe]=`host: ${this[Io].hostname}${this[Io].port?`:${this[Io].port}`:""}\r -`,this[uIe]=a??3e5,this[fIe]=n??3e5,this[cIe]=U??!0,this[vv]=Z,this[bA]=null,this[pIe]=j>-1?j:-1,this[dr]=null,this[yIe]=ce??100,this[mIe]=v??262144,this[BIe]=b??524288,this[IIe]=c??6e4,this[bs]=[],this[pa]=0,this[Cs]=0,this[ga]=g=>Dv(this,g),this[EIe]=g=>v7(this,g)}get pipelining(){return this[ym]}set pipelining(t){this[ym]=t,this[ga](!0)}get stats(){return new jBe(this)}get[cg](){return this[bs].length-this[Cs]}get[ug](){return this[Cs]-this[pa]}get[ag](){return this[bs].length-this[pa]}get[rIe](){return!!this[dr]&&!this[pl]&&!this[dr].destroyed}get[_v](){return!!(this[dr]?.busy(null)||this[ag]>=(_7(this)||1)||this[cg]>0)}[tIe](t){R7(this),this.once("connect",t)}[gIe](t,r){let n=new zBe(this[Io].origin,t,r);return this[bs].push(n),this[$f]||(Zf.bodyLength(n.body)==null&&Zf.isIterable(n.body)?(this[$f]=1,queueMicrotask(()=>Dv(this))):this[ga](!0)),this[$f]&&this[CA]!==2&&this[_v]&&(this[CA]=2),this[CA]<2}[hIe](){return new Promise(t=>{this[ag]?this[bA]=t:t(null)})}[dIe](t){return new Promise(r=>{let n=this[bs].splice(this[Cs]);for(let s=0;s{this[bA]&&(this[bA](),this[bA]=null),r(null)};this[dr]?(this[dr].destroy(t,i),this[dr]=null):queueMicrotask(i),this[ga]()})}};function v7(e,t){if(e[ug]===0&&t.code!=="UND_ERR_INFO"&&t.code!=="UND_ERR_SOCKET"){da(e[Cs]===e[pa]);let r=e[bs].splice(e[pa]);for(let n=0;n{if(s){Sv(e,s,{host:t,hostname:r,protocol:n,port:i}),e[ga]();return}if(e.destroyed){Zf.destroy(o.on("error",Q7),new ZBe),e[ga]();return}da(o);try{e[dr]=o.alpnProtocol==="h2"?CIe(e,o):bIe(e,o)}catch(a){o.destroy().on("error",Q7),Sv(e,a,{host:t,hostname:r,protocol:n,port:i}),e[ga]();return}e[pl]=!1,o[lIe]=0,o[vv]=e[vv],o[eIe]=e,o[iIe]=null,gl.connected.hasSubscribers&&gl.connected.publish({connectParams:{host:t,hostname:r,protocol:n,port:i,version:e[dr]?.version,servername:e[QA],localAddress:e[fg]},connector:e[Ag],socket:o}),e.emit("connect",e[Io],[e]),e[ga]()})}catch(s){Sv(e,s,{host:t,hostname:r,protocol:n,port:i}),e[ga]()}}function Sv(e,t,{host:r,hostname:n,protocol:i,port:s}){if(!e.destroyed){if(e[pl]=!1,gl.connectError.hasSubscribers&&gl.connectError.publish({connectParams:{host:r,hostname:n,protocol:i,port:s,version:e[dr]?.version,servername:e[QA],localAddress:e[fg]},connector:e[Ag],error:t}),t.code==="ERR_TLS_CERT_ALTNAME_INVALID")for(da(e[ug]===0);e[cg]>0&&e[bs][e[Cs]].servername===e[QA];){let o=e[bs][e[Cs]++];Zf.errorRequest(e,o,t)}else v7(e,t);e.emit("connectionError",e[Io],[e],t)}}function w7(e){e[CA]=0,e.emit("drain",e[Io],[e])}function Dv(e,t){e[$f]!==2&&(e[$f]=2,wIe(e,t),e[$f]=0,e[pa]>256&&(e[bs].splice(0,e[pa]),e[Cs]-=e[pa],e[pa]=0))}function wIe(e,t){for(;;){if(e.destroyed){da(e[cg]===0);return}if(e[bA]&&!e[ag]){e[bA](),e[bA]=null;return}if(e[dr]&&e[dr].resume(),e[_v])e[CA]=2;else if(e[CA]===2){t?(e[CA]=1,queueMicrotask(()=>w7(e))):w7(e);continue}if(e[cg]===0||e[ug]>=(_7(e)||1))return;let r=e[bs][e[Cs]];if(r===null)return;if(e[Io].protocol==="https:"&&e[QA]!==r.servername){if(e[ug]>0)return;e[QA]=r.servername,e[dr]?.destroy(new XBe("servername changed"),()=>{e[dr]=null,Dv(e)})}if(e[pl])return;if(!e[dr]){R7(e);return}if(e[dr].destroyed||e[dr].busy(r))return;!r.aborted&&e[dr].write(r)?e[Cs]++:e[bs].splice(e[Cs],1)}}D7.exports=Rv});var k7=x((nke,F7)=>{"use strict";var{PoolBase:SIe,kClients:Bm,kNeedDrain:_Ie,kAddClient:vIe,kGetDispatcher:RIe,kRemoveClient:DIe}=$6(),TIe=mm(),{InvalidArgumentError:Tv}=mr(),T7=$t(),{kUrl:N7}=Tn(),NIe=Iw(),Im=Symbol("options"),Nv=Symbol("connections"),M7=Symbol("factory");function MIe(e,t){return new TIe(e,t)}var Mv=class extends SIe{constructor(t,{connections:r,factory:n=MIe,connect:i,connectTimeout:s,tls:o,maxCachedSessions:a,socketPath:A,autoSelectFamily:f,autoSelectFamilyAttemptTimeout:l,allowH2:p,clientTtl:B,...S}={}){if(r!=null&&(!Number.isFinite(r)||r<0))throw new Tv("invalid connections");if(typeof n!="function")throw new Tv("factory must be a function.");if(i!=null&&typeof i!="function"&&typeof i!="object")throw new Tv("connect must be a function or an object");typeof i!="function"&&(i=NIe({...o,maxCachedSessions:a,allowH2:p,socketPath:A,timeout:s,...typeof f=="boolean"?{autoSelectFamily:f,autoSelectFamilyAttemptTimeout:l}:void 0,...i})),super(),this[Nv]=r||null,this[N7]=T7.parseOrigin(t),this[Im]={...T7.deepClone(S),connect:i,allowH2:p,clientTtl:B,socketPath:A},this[Im].interceptors=S.interceptors?{...S.interceptors}:void 0,this[M7]=n,this.on("connect",(_,N)=>{if(B!=null&&B>0)for(let P of N)Object.assign(P,{ttl:Date.now()})}),this.on("connectionError",(_,N,P)=>{for(let U of N){let G=this[Bm].indexOf(U);G!==-1&&this[Bm].splice(G,1)}})}[RIe](){let t=this[Im].clientTtl;for(let r of this[Bm])if(t!=null&&t>0&&r.ttl&&Date.now()-r.ttl>t)this[DIe](r);else if(!r[_Ie])return r;if(!this[Nv]||this[Bm].length{"use strict";var{InvalidArgumentError:bm,MaxOriginsReachedError:FIe}=mr(),{kClients:ki,kRunning:x7,kClose:kIe,kDestroy:xIe,kDispatch:UIe,kUrl:LIe}=Tn(),PIe=DE(),OIe=k7(),HIe=mm(),qIe=$t(),U7=Symbol("onConnect"),L7=Symbol("onDisconnect"),P7=Symbol("onConnectionError"),O7=Symbol("onDrain"),H7=Symbol("factory"),Fv=Symbol("options"),lg=Symbol("origins");function GIe(e,t){return t&&t.connections===1?new HIe(e,t):new OIe(e,t)}var kv=class extends PIe{constructor({factory:t=GIe,maxOrigins:r=1/0,connect:n,...i}={}){if(typeof t!="function")throw new bm("factory must be a function.");if(n!=null&&typeof n!="function"&&typeof n!="object")throw new bm("connect must be a function or an object");if(typeof r!="number"||Number.isNaN(r)||r<=0)throw new bm("maxOrigins must be a number greater than 0");super(),n&&typeof n!="function"&&(n={...n}),this[Fv]={...qIe.deepClone(i),maxOrigins:r,connect:n},this[H7]=t,this[ki]=new Map,this[lg]=new Set,this[O7]=(s,o)=>{this.emit("drain",s,[this,...o])},this[U7]=(s,o)=>{this.emit("connect",s,[this,...o])},this[L7]=(s,o,a)=>{this.emit("disconnect",s,[this,...o],a)},this[P7]=(s,o,a)=>{this.emit("connectionError",s,[this,...o],a)}}get[x7](){let t=0;for(let{dispatcher:r}of this[ki].values())t+=r[x7];return t}[UIe](t,r){let n;if(t.origin&&(typeof t.origin=="string"||t.origin instanceof URL))n=String(t.origin);else throw new bm("opts.origin must be a non-empty string or URL.");if(this[lg].size>=this[Fv].maxOrigins&&!this[lg].has(n))throw new FIe;let i=this[ki].get(n),s=i&&i.dispatcher;if(!s){let o=a=>{let A=this[ki].get(n);A&&(a&&(A.count-=1),A.count<=0&&(this[ki].delete(n),A.dispatcher.destroyed||A.dispatcher.close()),this[lg].delete(n))};s=this[H7](t.origin,this[Fv]).on("drain",this[O7]).on("connect",(a,A)=>{let f=this[ki].get(n);f&&(f.count+=1),this[U7](a,A)}).on("disconnect",(a,A,f)=>{o(!0),this[L7](a,A,f)}).on("connectionError",(a,A,f)=>{o(!1),this[P7](a,A,f)}),this[ki].set(n,{count:0,dispatcher:s}),this[lg].add(n)}return s.dispatch(t,r)}[kIe](){let t=[];for(let{dispatcher:r}of this[ki].values())t.push(r.close());return this[ki].clear(),Promise.all(t)}[xIe](t){let r=[];for(let{dispatcher:n}of this[ki].values())r.push(n.destroy(t));return this[ki].clear(),Promise.all(r)}get stats(){let t={};for(let{dispatcher:r}of this[ki].values())r.stats&&(t[r[LIe].origin]=r.stats);return t}};q7.exports=kv});var dg=x((ske,z7)=>{"use strict";var{kConstruct:YIe}=Tn(),{kEnumerableProperty:El}=$t(),{iteratorMixin:WIe,isValidHeaderName:hg,isValidHeaderValue:Y7}=Kf(),{webidl:Bt}=po(),Uv=Wt(),Cm=Yr();function G7(e){return e===10||e===13||e===9||e===32}function W7(e){let t=0,r=e.length;for(;r>t&&G7(e.charCodeAt(r-1));)--r;for(;r>t&&G7(e.charCodeAt(t));)++t;return t===0&&r===e.length?e:e.substring(t,r)}function V7(e,t){if(Array.isArray(t))for(let r=0;r>","record"]})}function Lv(e,t,r){if(r=W7(r),hg(t)){if(!Y7(r))throw Bt.errors.invalidArgument({prefix:"Headers.append",value:r,type:"header value"})}else throw Bt.errors.invalidArgument({prefix:"Headers.append",value:t,type:"header name"});if(j7(e)==="immutable")throw new TypeError("immutable");return wm(e).append(t,r,!1)}function VIe(e){let t=wm(e);if(!t)return[];if(t.sortedMap)return t.sortedMap;let r=[],n=t.toSortedArray(),i=t.cookies;if(i===null||i.length===1)return t.sortedMap=n;for(let s=0;s>1),r[f][0]<=l[0]?A=f+1:a=f;if(s!==f){for(o=s;o>A;)r[o]=r[--o];r[A]=l}}if(!n.next().done)throw new TypeError("Unreachable");return r}else{let n=0;for(let{0:i,1:{value:s}}of this.headersMap)r[n++]=[i,s],Uv(s!==null);return r.sort(J7)}}},SA,ri,wA=class wA{constructor(t=void 0){St(this,SA);St(this,ri);Bt.util.markAsUncloneable(this),t!==YIe&&(ft(this,ri,new Qm),ft(this,SA,"none"),t!==void 0&&(t=Bt.converters.HeadersInit(t,"Headers constructor","init"),V7(this,t)))}append(t,r){Bt.brandCheck(this,wA),Bt.argumentLengthCheck(arguments,2,"Headers.append");let n="Headers.append";return t=Bt.converters.ByteString(t,n,"name"),r=Bt.converters.ByteString(r,n,"value"),Lv(this,t,r)}delete(t){if(Bt.brandCheck(this,wA),Bt.argumentLengthCheck(arguments,1,"Headers.delete"),t=Bt.converters.ByteString(t,"Headers.delete","name"),!hg(t))throw Bt.errors.invalidArgument({prefix:"Headers.delete",value:t,type:"header name"});if(te(this,SA)==="immutable")throw new TypeError("immutable");te(this,ri).contains(t,!1)&&te(this,ri).delete(t,!1)}get(t){Bt.brandCheck(this,wA),Bt.argumentLengthCheck(arguments,1,"Headers.get");let r="Headers.get";if(t=Bt.converters.ByteString(t,r,"name"),!hg(t))throw Bt.errors.invalidArgument({prefix:r,value:t,type:"header name"});return te(this,ri).get(t,!1)}has(t){Bt.brandCheck(this,wA),Bt.argumentLengthCheck(arguments,1,"Headers.has");let r="Headers.has";if(t=Bt.converters.ByteString(t,r,"name"),!hg(t))throw Bt.errors.invalidArgument({prefix:r,value:t,type:"header name"});return te(this,ri).contains(t,!1)}set(t,r){Bt.brandCheck(this,wA),Bt.argumentLengthCheck(arguments,2,"Headers.set");let n="Headers.set";if(t=Bt.converters.ByteString(t,n,"name"),r=Bt.converters.ByteString(r,n,"value"),r=W7(r),hg(t)){if(!Y7(r))throw Bt.errors.invalidArgument({prefix:n,value:r,type:"header value"})}else throw Bt.errors.invalidArgument({prefix:n,value:t,type:"header name"});if(te(this,SA)==="immutable")throw new TypeError("immutable");te(this,ri).set(t,r,!1)}getSetCookie(){Bt.brandCheck(this,wA);let t=te(this,ri).cookies;return t?[...t]:[]}[Cm.inspect.custom](t,r){return r.depth??(r.depth=t),`Headers ${Cm.formatWithOptions(r,te(this,ri).entries)}`}static getHeadersGuard(t){return te(t,SA)}static setHeadersGuard(t,r){ft(t,SA,r)}static getHeadersList(t){return te(t,ri)}static setHeadersList(t,r){ft(t,ri,r)}};SA=new WeakMap,ri=new WeakMap;var Qs=wA,{getHeadersGuard:j7,setHeadersGuard:JIe,getHeadersList:wm,setHeadersList:jIe}=Qs;Reflect.deleteProperty(Qs,"getHeadersGuard");Reflect.deleteProperty(Qs,"setHeadersGuard");Reflect.deleteProperty(Qs,"getHeadersList");Reflect.deleteProperty(Qs,"setHeadersList");WIe("Headers",Qs,VIe,0,1);Object.defineProperties(Qs.prototype,{append:El,delete:El,get:El,has:El,set:El,getSetCookie:El,[Symbol.toStringTag]:{value:"Headers",configurable:!0},[Cm.inspect.custom]:{enumerable:!1}});Bt.converters.HeadersInit=function(e,t,r){if(Bt.util.Type(e)===Bt.util.Types.OBJECT){let n=Reflect.get(e,Symbol.iterator);if(!Cm.types.isProxy(e)&&n===Qs.prototype.entries)try{return wm(e).entriesList}catch{}return typeof n=="function"?Bt.converters["sequence>"](e,t,r,n.bind(e)):Bt.converters["record"](e,t,r)}throw Bt.errors.conversionFailed({prefix:"Headers constructor",argument:"Argument 1",types:["sequence>","record"]})};z7.exports={fill:V7,compareHeaderName:J7,Headers:Qs,HeadersList:Qm,getHeadersGuard:j7,setHeadersGuard:JIe,setHeadersList:jIe,getHeadersList:wm}});var Hv=x((ake,aq)=>{"use strict";var{Headers:tq,HeadersList:K7,fill:zIe,getHeadersGuard:KIe,setHeadersGuard:rq,setHeadersList:nq}=dg(),{extractBody:X7,cloneBody:XIe,mixinBody:ZIe,streamRegistry:iq,bodyUnusable:$Ie}=ul(),sq=$t(),Z7=Yr(),{kEnumerableProperty:ni}=sq,{isValidReasonPhrase:ebe,isCancelled:tbe,isAborted:rbe,isErrorLike:nbe,environmentSettingsObject:ibe}=Kf(),{redirectStatusSet:sbe,nullBodyStatus:obe}=id(),{webidl:yt}=po(),{URLSerializer:$7}=Bf(),{kConstruct:_m}=Tn(),Pv=Wt(),{isomorphicEncode:abe,serializeJavascriptValueToJSONString:Abe}=mf(),fbe=new TextEncoder("utf-8"),bo,rr,xi=class xi{constructor(t=null,r=void 0){St(this,bo);St(this,rr);if(yt.util.markAsUncloneable(this),t===_m)return;t!==null&&(t=yt.converters.BodyInit(t,"Response","body")),r=yt.converters.ResponseInit(r),ft(this,rr,yl({})),ft(this,bo,new tq(_m)),rq(te(this,bo),"response"),nq(te(this,bo),te(this,rr).headersList);let n=null;if(t!=null){let[i,s]=X7(t);n={body:i,type:s}}eq(this,r,n)}static error(){return gg(vm(),"immutable")}static json(t,r=void 0){yt.argumentLengthCheck(arguments,1,"Response.json"),r!==null&&(r=yt.converters.ResponseInit(r));let n=fbe.encode(Abe(t)),i=X7(n),s=gg(yl({}),"response");return eq(s,r,{body:i[0],type:"application/json"}),s}static redirect(t,r=302){yt.argumentLengthCheck(arguments,1,"Response.redirect"),t=yt.converters.USVString(t),r=yt.converters["unsigned short"](r);let n;try{n=new URL(t,ibe.settingsObject.baseUrl)}catch(o){throw new TypeError(`Failed to parse URL from ${t}`,{cause:o})}if(!sbe.has(r))throw new RangeError(`Invalid status code ${r}`);let i=gg(yl({}),"immutable");te(i,rr).status=r;let s=abe($7(n));return te(i,rr).headersList.append("location",s,!0),i}get type(){return yt.brandCheck(this,xi),te(this,rr).type}get url(){yt.brandCheck(this,xi);let t=te(this,rr).urlList,r=t[t.length-1]??null;return r===null?"":$7(r,!0)}get redirected(){return yt.brandCheck(this,xi),te(this,rr).urlList.length>1}get status(){return yt.brandCheck(this,xi),te(this,rr).status}get ok(){return yt.brandCheck(this,xi),te(this,rr).status>=200&&te(this,rr).status<=299}get statusText(){return yt.brandCheck(this,xi),te(this,rr).statusText}get headers(){return yt.brandCheck(this,xi),te(this,bo)}get body(){return yt.brandCheck(this,xi),te(this,rr).body?te(this,rr).body.stream:null}get bodyUsed(){return yt.brandCheck(this,xi),!!te(this,rr).body&&sq.isDisturbed(te(this,rr).body.stream)}clone(){if(yt.brandCheck(this,xi),$Ie(te(this,rr)))throw yt.errors.exception({header:"Response.clone",message:"Body has already been consumed."});let t=Ov(te(this,rr));return te(this,rr).urlList.length!==0&&te(this,rr).body?.stream&&iq.register(this,new WeakRef(te(this,rr).body.stream)),gg(t,KIe(te(this,bo)))}[Z7.inspect.custom](t,r){r.depth===null&&(r.depth=2),r.colors??(r.colors=!0);let n={status:this.status,statusText:this.statusText,headers:this.headers,body:this.body,bodyUsed:this.bodyUsed,ok:this.ok,redirected:this.redirected,type:this.type,url:this.url};return`Response ${Z7.formatWithOptions(r,n)}`}static getResponseHeaders(t){return te(t,bo)}static setResponseHeaders(t,r){ft(t,bo,r)}static getResponseState(t){return te(t,rr)}static setResponseState(t,r){ft(t,rr,r)}};bo=new WeakMap,rr=new WeakMap;var ii=xi,{getResponseHeaders:ube,setResponseHeaders:cbe,getResponseState:eu,setResponseState:lbe}=ii;Reflect.deleteProperty(ii,"getResponseHeaders");Reflect.deleteProperty(ii,"setResponseHeaders");Reflect.deleteProperty(ii,"getResponseState");Reflect.deleteProperty(ii,"setResponseState");ZIe(ii,eu);Object.defineProperties(ii.prototype,{type:ni,url:ni,status:ni,ok:ni,redirected:ni,statusText:ni,headers:ni,clone:ni,body:ni,bodyUsed:ni,[Symbol.toStringTag]:{value:"Response",configurable:!0}});Object.defineProperties(ii,{json:ni,redirect:ni,error:ni});function Ov(e){if(e.internalResponse)return oq(Ov(e.internalResponse),e.type);let t=yl({...e,body:null});return e.body!=null&&(t.body=XIe(e.body)),t}function yl(e){return{aborted:!1,rangeRequested:!1,timingAllowPassed:!1,requestIncludesCredentials:!1,type:"default",status:200,timingInfo:null,cacheState:"",statusText:"",...e,headersList:e?.headersList?new K7(e?.headersList):new K7,urlList:e?.urlList?[...e.urlList]:[]}}function vm(e){let t=nbe(e);return yl({type:"error",status:0,error:t?e:new Error(e&&String(e)),aborted:e&&e.name==="AbortError"})}function hbe(e){return e.type==="error"&&e.status===0}function Sm(e,t){return t={internalResponse:e,...t},new Proxy(e,{get(r,n){return n in t?t[n]:r[n]},set(r,n,i){return Pv(!(n in t)),r[n]=i,!0}})}function oq(e,t){if(t==="basic")return Sm(e,{type:"basic",headersList:e.headersList});if(t==="cors")return Sm(e,{type:"cors",headersList:e.headersList});if(t==="opaque")return Sm(e,{type:"opaque",urlList:[],status:0,statusText:"",body:null});if(t==="opaqueredirect")return Sm(e,{type:"opaqueredirect",status:0,statusText:"",headersList:[],body:null});Pv(!1)}function dbe(e,t=null){return Pv(tbe(e)),rbe(e)?vm(Object.assign(new DOMException("The operation was aborted.","AbortError"),{cause:t})):vm(Object.assign(new DOMException("Request was cancelled."),{cause:t}))}function eq(e,t,r){if(t.status!==null&&(t.status<200||t.status>599))throw new RangeError('init["status"] must be in the range of 200 to 599, inclusive.');if("statusText"in t&&t.statusText!=null&&!ebe(String(t.statusText)))throw new TypeError("Invalid statusText");if("status"in t&&t.status!=null&&(eu(e).status=t.status),"statusText"in t&&t.statusText!=null&&(eu(e).statusText=t.statusText),"headers"in t&&t.headers!=null&&zIe(ube(e),t.headers),r){if(obe.includes(e.status))throw yt.errors.exception({header:"Response constructor",message:`Invalid response status code ${e.status}`});eu(e).body=r.body,r.type!=null&&!eu(e).headersList.contains("content-type",!0)&&eu(e).headersList.append("content-type",r.type,!0)}}function gg(e,t){let r=new ii(_m);lbe(r,e);let n=new tq(_m);return cbe(r,n),nq(n,e.headersList),rq(n,t),e.urlList.length!==0&&e.body?.stream&&iq.register(r,new WeakRef(e.body.stream)),r}yt.converters.XMLHttpRequestBodyInit=function(e,t,r){return typeof e=="string"?yt.converters.USVString(e,t,r):yt.is.Blob(e)||yt.is.BufferSource(e)||yt.is.FormData(e)||yt.is.URLSearchParams(e)?e:yt.converters.DOMString(e,t,r)};yt.converters.BodyInit=function(e,t,r){return yt.is.ReadableStream(e)||e?.[Symbol.asyncIterator]?e:yt.converters.XMLHttpRequestBodyInit(e,t,r)};yt.converters.ResponseInit=yt.dictionaryConverter([{key:"status",converter:yt.converters["unsigned short"],defaultValue:()=>200},{key:"statusText",converter:yt.converters.ByteString,defaultValue:()=>""},{key:"headers",converter:yt.converters.HeadersInit}]);yt.is.Response=yt.util.MakeTypeAssertion(ii);aq.exports={isNetworkError:hbe,makeNetworkError:vm,makeResponse:yl,makeAppropriateNetworkError:dbe,filterResponse:oq,Response:ii,cloneResponse:Ov,fromInnerResponse:gg,getResponseState:eu}});var Yv=x((fke,Iq)=>{"use strict";var{extractBody:gbe,mixinBody:pbe,cloneBody:Ebe,bodyUnusable:Aq}=ul(),{Headers:dq,fill:ybe,HeadersList:Tm,setHeadersGuard:qv,getHeadersGuard:mbe,setHeadersList:gq,getHeadersList:fq}=dg(),Dm=$t(),uq=Yr(),{isValidHTTPToken:Bbe,sameOrigin:cq,environmentSettingsObject:Rm}=Kf(),{forbiddenMethodsSet:Ibe,corsSafeListedMethodsSet:bbe,referrerPolicy:Cbe,requestRedirect:Qbe,requestMode:wbe,requestCredentials:Sbe,requestCache:_be,requestDuplex:vbe}=id(),{kEnumerableProperty:br,normalizedMethodRecordsBase:Rbe,normalizedMethodRecords:Dbe}=Dm,{webidl:Fe}=po(),{URLSerializer:Tbe}=Bf(),{kConstruct:Nm}=Tn(),Nbe=Wt(),{getMaxListeners:pq,setMaxListeners:Mbe,defaultMaxListeners:Fbe}=Zi(),kbe=Symbol("abortController"),Eq=new FinalizationRegistry(({signal:e,abort:t})=>{e.removeEventListener("abort",t)}),Mm=new WeakMap,Gv;try{Gv=pq(new AbortController().signal)>0}catch{Gv=!1}function lq(e){return t;function t(){let r=e.deref();if(r!==void 0){Eq.unregister(t),this.removeEventListener("abort",t),r.abort(this.reason);let n=Mm.get(r.signal);if(n!==void 0){if(n.size!==0){for(let i of n){let s=i.deref();s!==void 0&&s.abort(this.reason)}n.clear()}Mm.delete(r.signal)}}}}var hq=!1,tu,Ea,Pn,Rt,gr=class gr{constructor(t,r=void 0){St(this,tu);St(this,Ea);St(this,Pn);St(this,Rt);if(Fe.util.markAsUncloneable(this),t===Nm)return;Fe.argumentLengthCheck(arguments,1,"Request constructor"),t=Fe.converters.RequestInfo(t),r=Fe.converters.RequestInit(r);let i=null,s=null,o=Rm.settingsObject.baseUrl,a=null;if(typeof t=="string"){ft(this,Ea,r.dispatcher);let U;try{U=new URL(t,o)}catch(G){throw new TypeError("Failed to parse URL from "+t,{cause:G})}if(U.username||U.password)throw new TypeError("Request cannot be constructed from a URL that includes credentials: "+t);i=Fm({urlList:[U]}),s="cors"}else Nbe(Fe.is.Request(t)),i=te(t,Rt),a=te(t,tu),ft(this,Ea,r.dispatcher||te(t,Ea));let A=Rm.settingsObject.origin,f="client";if(i.window?.constructor?.name==="EnvironmentSettingsObject"&&cq(i.window,A)&&(f=i.window),r.window!=null)throw new TypeError(`'window' option '${f}' must be null`);"window"in r&&(f="no-window"),i=Fm({method:i.method,headersList:i.headersList,unsafeRequest:i.unsafeRequest,client:Rm.settingsObject,window:f,priority:i.priority,origin:i.origin,referrer:i.referrer,referrerPolicy:i.referrerPolicy,mode:i.mode,credentials:i.credentials,cache:i.cache,redirect:i.redirect,integrity:i.integrity,keepalive:i.keepalive,reloadNavigation:i.reloadNavigation,historyNavigation:i.historyNavigation,urlList:[...i.urlList]});let l=Object.keys(r).length!==0;if(l&&(i.mode==="navigate"&&(i.mode="same-origin"),i.reloadNavigation=!1,i.historyNavigation=!1,i.origin="client",i.referrer="client",i.referrerPolicy="",i.url=i.urlList[i.urlList.length-1],i.urlList=[i.url]),r.referrer!==void 0){let U=r.referrer;if(U==="")i.referrer="no-referrer";else{let G;try{G=new URL(U,o)}catch(Y){throw new TypeError(`Referrer "${U}" is not a valid URL.`,{cause:Y})}G.protocol==="about:"&&G.hostname==="client"||A&&!cq(G,Rm.settingsObject.baseUrl)?i.referrer="client":i.referrer=G}}r.referrerPolicy!==void 0&&(i.referrerPolicy=r.referrerPolicy);let p;if(r.mode!==void 0?p=r.mode:p=s,p==="navigate")throw Fe.errors.exception({header:"Request constructor",message:"invalid request mode navigate."});if(p!=null&&(i.mode=p),r.credentials!==void 0&&(i.credentials=r.credentials),r.cache!==void 0&&(i.cache=r.cache),i.cache==="only-if-cached"&&i.mode!=="same-origin")throw new TypeError("'only-if-cached' can be set only with 'same-origin' mode");if(r.redirect!==void 0&&(i.redirect=r.redirect),r.integrity!=null&&(i.integrity=String(r.integrity)),r.keepalive!==void 0&&(i.keepalive=!!r.keepalive),r.method!==void 0){let U=r.method,G=Dbe[U];if(G!==void 0)i.method=G;else{if(!Bbe(U))throw new TypeError(`'${U}' is not a valid HTTP method.`);let Y=U.toUpperCase();if(Ibe.has(Y))throw new TypeError(`'${U}' HTTP method is unsupported.`);U=Rbe[Y]??U,i.method=U}!hq&&i.method==="patch"&&(process.emitWarning("Using `patch` is highly likely to result in a `405 Method Not Allowed`. `PATCH` is much more likely to succeed.",{code:"UNDICI-FETCH-patch"}),hq=!0)}r.signal!==void 0&&(a=r.signal),ft(this,Rt,i);let B=new AbortController;if(ft(this,tu,B.signal),a!=null)if(a.aborted)B.abort(a.reason);else{this[kbe]=B;let U=new WeakRef(B),G=lq(U);Gv&&pq(a)===Fbe&&Mbe(1500,a),Dm.addAbortListener(a,G),Eq.register(B,{signal:a,abort:G},G)}if(ft(this,Pn,new dq(Nm)),gq(te(this,Pn),i.headersList),qv(te(this,Pn),"request"),p==="no-cors"){if(!bbe.has(i.method))throw new TypeError(`'${i.method} is unsupported in no-cors mode.`);qv(te(this,Pn),"request-no-cors")}if(l){let U=fq(te(this,Pn)),G=r.headers!==void 0?r.headers:new Tm(U);if(U.clear(),G instanceof Tm){for(let{name:Y,value:Z}of G.rawValues())U.append(Y,Z,!1);U.cookies=G.cookies}else ybe(te(this,Pn),G)}let S=Fe.is.Request(t)?te(t,Rt).body:null;if((r.body!=null||S!=null)&&(i.method==="GET"||i.method==="HEAD"))throw new TypeError("Request with GET/HEAD method cannot have body.");let _=null;if(r.body!=null){let[U,G]=gbe(r.body,i.keepalive);_=U,G&&!fq(te(this,Pn)).contains("content-type",!0)&&te(this,Pn).append("content-type",G,!0)}let N=_??S;if(N!=null&&N.source==null){if(_!=null&&r.duplex==null)throw new TypeError("RequestInit: duplex option is required when sending a body.");if(i.mode!=="same-origin"&&i.mode!=="cors")throw new TypeError('If request is made from ReadableStream, mode should be "same-origin" or "cors"');i.useCORSPreflightFlag=!0}let P=N;if(_==null&&S!=null){if(Aq(te(t,Rt)))throw new TypeError("Cannot construct a Request with a Request object that has already been used.");let U=new TransformStream;S.stream.pipeThrough(U),P={source:S.source,length:S.length,stream:U.readable}}te(this,Rt).body=P}get method(){return Fe.brandCheck(this,gr),te(this,Rt).method}get url(){return Fe.brandCheck(this,gr),Tbe(te(this,Rt).url)}get headers(){return Fe.brandCheck(this,gr),te(this,Pn)}get destination(){return Fe.brandCheck(this,gr),te(this,Rt).destination}get referrer(){return Fe.brandCheck(this,gr),te(this,Rt).referrer==="no-referrer"?"":te(this,Rt).referrer==="client"?"about:client":te(this,Rt).referrer.toString()}get referrerPolicy(){return Fe.brandCheck(this,gr),te(this,Rt).referrerPolicy}get mode(){return Fe.brandCheck(this,gr),te(this,Rt).mode}get credentials(){return Fe.brandCheck(this,gr),te(this,Rt).credentials}get cache(){return Fe.brandCheck(this,gr),te(this,Rt).cache}get redirect(){return Fe.brandCheck(this,gr),te(this,Rt).redirect}get integrity(){return Fe.brandCheck(this,gr),te(this,Rt).integrity}get keepalive(){return Fe.brandCheck(this,gr),te(this,Rt).keepalive}get isReloadNavigation(){return Fe.brandCheck(this,gr),te(this,Rt).reloadNavigation}get isHistoryNavigation(){return Fe.brandCheck(this,gr),te(this,Rt).historyNavigation}get signal(){return Fe.brandCheck(this,gr),te(this,tu)}get body(){return Fe.brandCheck(this,gr),te(this,Rt).body?te(this,Rt).body.stream:null}get bodyUsed(){return Fe.brandCheck(this,gr),!!te(this,Rt).body&&Dm.isDisturbed(te(this,Rt).body.stream)}get duplex(){return Fe.brandCheck(this,gr),"half"}clone(){if(Fe.brandCheck(this,gr),Aq(te(this,Rt)))throw new TypeError("unusable");let t=mq(te(this,Rt)),r=new AbortController;if(this.signal.aborted)r.abort(this.signal.reason);else{let n=Mm.get(this.signal);n===void 0&&(n=new Set,Mm.set(this.signal,n));let i=new WeakRef(r);n.add(i),Dm.addAbortListener(r.signal,lq(i))}return Bq(t,te(this,Ea),r.signal,mbe(te(this,Pn)))}[uq.inspect.custom](t,r){r.depth===null&&(r.depth=2),r.colors??(r.colors=!0);let n={method:this.method,url:this.url,headers:this.headers,destination:this.destination,referrer:this.referrer,referrerPolicy:this.referrerPolicy,mode:this.mode,credentials:this.credentials,cache:this.cache,redirect:this.redirect,integrity:this.integrity,keepalive:this.keepalive,isReloadNavigation:this.isReloadNavigation,isHistoryNavigation:this.isHistoryNavigation,signal:this.signal};return`Request ${uq.formatWithOptions(r,n)}`}static setRequestSignal(t,r){return ft(t,tu,r),t}static getRequestDispatcher(t){return te(t,Ea)}static setRequestDispatcher(t,r){ft(t,Ea,r)}static setRequestHeaders(t,r){ft(t,Pn,r)}static getRequestState(t){return te(t,Rt)}static setRequestState(t,r){ft(t,Rt,r)}};tu=new WeakMap,Ea=new WeakMap,Pn=new WeakMap,Rt=new WeakMap;var On=gr,{setRequestSignal:xbe,getRequestDispatcher:Ube,setRequestDispatcher:Lbe,setRequestHeaders:Pbe,getRequestState:yq,setRequestState:Obe}=On;Reflect.deleteProperty(On,"setRequestSignal");Reflect.deleteProperty(On,"getRequestDispatcher");Reflect.deleteProperty(On,"setRequestDispatcher");Reflect.deleteProperty(On,"setRequestHeaders");Reflect.deleteProperty(On,"getRequestState");Reflect.deleteProperty(On,"setRequestState");pbe(On,yq);function Fm(e){return{method:e.method??"GET",localURLsOnly:e.localURLsOnly??!1,unsafeRequest:e.unsafeRequest??!1,body:e.body??null,client:e.client??null,reservedClient:e.reservedClient??null,replacesClientId:e.replacesClientId??"",window:e.window??"client",keepalive:e.keepalive??!1,serviceWorkers:e.serviceWorkers??"all",initiator:e.initiator??"",destination:e.destination??"",priority:e.priority??null,origin:e.origin??"client",policyContainer:e.policyContainer??"client",referrer:e.referrer??"client",referrerPolicy:e.referrerPolicy??"",mode:e.mode??"no-cors",useCORSPreflightFlag:e.useCORSPreflightFlag??!1,credentials:e.credentials??"same-origin",useCredentials:e.useCredentials??!1,cache:e.cache??"default",redirect:e.redirect??"follow",integrity:e.integrity??"",cryptoGraphicsNonceMetadata:e.cryptoGraphicsNonceMetadata??"",parserMetadata:e.parserMetadata??"",reloadNavigation:e.reloadNavigation??!1,historyNavigation:e.historyNavigation??!1,userActivation:e.userActivation??!1,taintedOrigin:e.taintedOrigin??!1,redirectCount:e.redirectCount??0,responseTainting:e.responseTainting??"basic",preventNoCacheCacheControlHeaderModification:e.preventNoCacheCacheControlHeaderModification??!1,done:e.done??!1,timingAllowFailed:e.timingAllowFailed??!1,useURLCredentials:e.useURLCredentials??void 0,traversableForUserPrompts:e.traversableForUserPrompts??"client",urlList:e.urlList,url:e.urlList[0],headersList:e.headersList?new Tm(e.headersList):new Tm}}function mq(e){let t=Fm({...e,body:null});return e.body!=null&&(t.body=Ebe(e.body)),t}function Bq(e,t,r,n){let i=new On(Nm);Obe(i,e),Lbe(i,t),xbe(i,r);let s=new dq(Nm);return Pbe(i,s),gq(s,e.headersList),qv(s,n),i}Object.defineProperties(On.prototype,{method:br,url:br,headers:br,redirect:br,clone:br,signal:br,duplex:br,destination:br,body:br,bodyUsed:br,isHistoryNavigation:br,isReloadNavigation:br,keepalive:br,integrity:br,cache:br,credentials:br,attribute:br,referrerPolicy:br,referrer:br,mode:br,[Symbol.toStringTag]:{value:"Request",configurable:!0}});Fe.is.Request=Fe.util.MakeTypeAssertion(On);Fe.converters.RequestInfo=function(e){return typeof e=="string"?Fe.converters.USVString(e):Fe.is.Request(e)?e:Fe.converters.USVString(e)};Fe.converters.RequestInit=Fe.dictionaryConverter([{key:"method",converter:Fe.converters.ByteString},{key:"headers",converter:Fe.converters.HeadersInit},{key:"body",converter:Fe.nullableConverter(Fe.converters.BodyInit)},{key:"referrer",converter:Fe.converters.USVString},{key:"referrerPolicy",converter:Fe.converters.DOMString,allowedValues:Cbe},{key:"mode",converter:Fe.converters.DOMString,allowedValues:wbe},{key:"credentials",converter:Fe.converters.DOMString,allowedValues:Sbe},{key:"cache",converter:Fe.converters.DOMString,allowedValues:_be},{key:"redirect",converter:Fe.converters.DOMString,allowedValues:Qbe},{key:"integrity",converter:Fe.converters.DOMString},{key:"keepalive",converter:Fe.converters.boolean},{key:"signal",converter:Fe.nullableConverter(e=>Fe.converters.AbortSignal(e,"RequestInit","signal"))},{key:"window",converter:Fe.converters.any},{key:"duplex",converter:Fe.converters.DOMString,allowedValues:vbe},{key:"dispatcher",converter:Fe.converters.any},{key:"priority",converter:Fe.converters.DOMString,allowedValues:["high","low","auto"],defaultValue:()=>"auto"}]);Iq.exports={Request:On,makeRequest:Fm,fromInnerRequest:Bq,cloneRequest:mq,getRequestDispatcher:Ube,getRequestState:yq}});var Wv=x((cke,wq)=>{"use strict";var bq=Symbol.for("undici.globalDispatcher.1"),{InvalidArgumentError:Hbe}=mr(),qbe=xv();Qq()===void 0&&Cq(new qbe);function Cq(e){if(!e||typeof e.dispatch!="function")throw new Hbe("Argument agent must implement Agent");Object.defineProperty(globalThis,bq,{value:e,writable:!0,enumerable:!1,configurable:!1})}function Qq(){return globalThis[bq]}var Gbe=["fetch","Headers","Response","Request","FormData","WebSocket","CloseEvent","ErrorEvent","MessageEvent","EventSource"];wq.exports={setGlobalDispatcher:Cq,getGlobalDispatcher:Qq,installedExports:Gbe}});var Mq=x((lke,Nq)=>{"use strict";var Ybe=Wt(),{runtimeFeatures:_q}=sv(),ru=new Map([["sha256",0],["sha384",1],["sha512",2]]),Vv;if(_q.has("crypto")){Vv=kd();let e=Vv.getHashes();e.length===0&&ru.clear();for(let t of ru.keys())e.includes(t)===!1&&ru.delete(t)}else ru.clear();var Sq=Map.prototype.get.bind(ru),Jv=Map.prototype.has.bind(ru),Wbe=_q.has("crypto")===!1||ru.size===0?()=>!0:(e,t)=>{let r=Rq(t);if(r.length===0)return!0;let n=vq(r);for(let i of n){let s=i.alg,o=i.val,a=Dq(s,e);if(Tq(a,o))return!0}return!1};function vq(e){let t=[],r=null;for(let n of e){if(Ybe(Jv(n.alg),"Invalid SRI hash algorithm token"),t.length===0){t.push(n),r=n;continue}let i=r.alg,s=Sq(i),o=n.alg,a=Sq(o);as?(r=n,t[0]=n,t.length=1):t.push(n))}return t}function Rq(e){let t=[];for(let r of e.split(" ")){let i=r.split("?",1)[0],s="",o=[i.slice(0,6),i.slice(7)],a=o[0];if(!Jv(a))continue;o[1]&&(s=o[1]);let A={alg:a,val:s};t.push(A)}return t}var Dq=(e,t)=>Vv.hash(e,t,"base64");function Tq(e,t){let r=e.length;r!==0&&e[r-1]==="="&&(r-=1),r!==0&&e[r-1]==="="&&(r-=1);let n=t.length;if(n!==0&&t[n-1]==="="&&(n-=1),n!==0&&t[n-1]==="="&&(n-=1),r!==n)return!1;for(let i=0;i{"use strict";var{makeNetworkError:Mt,makeAppropriateNetworkError:pg,filterResponse:jv,makeResponse:km,fromInnerResponse:Vbe,getResponseState:Jbe}=Hv(),{HeadersList:zv}=dg(),{Request:jbe,cloneRequest:zbe,getRequestDispatcher:Kbe,getRequestState:Xbe}=Yv(),ws=UE(),{makePolicyContainer:Zbe,clonePolicyContainer:$be,requestBadPort:eCe,TAOCheck:tCe,appendRequestOriginHeader:rCe,responseLocationURL:nCe,requestCurrentURL:si,setRequestReferrerPolicyOnRedirect:iCe,tryUpgradeRequestToAPotentiallyTrustworthyURL:sCe,createOpaqueTimingInfo:t1,appendFetchMetadata:oCe,corsCheck:aCe,crossOriginResourcePolicyCheck:ACe,determineRequestsReferrer:fCe,coarsenedSharedCurrentTime:Eg,sameOrigin:$v,isCancelled:_A,isAborted:Fq,isErrorLike:uCe,fullyReadBody:cCe,readableStreamClose:lCe,urlIsLocal:hCe,urlIsHttpHttpsScheme:Pm,urlHasHttpsScheme:dCe,clampAndCoarsenConnectionTimingInfo:gCe,simpleRangeHeaderValue:pCe,buildContentRange:ECe,createInflate:yCe,extractMimeType:mCe,hasAuthenticationEntry:BCe,includesCredentials:kq,isTraversableNavigable:ICe}=Kf(),nu=Wt(),{safelyExtractBody:Om,extractBody:xq}=ul(),{redirectStatusSet:Oq,nullBodyStatus:Hq,safeMethodsSet:bCe,requestBodyHeader:CCe,subresourceSet:QCe}=id(),wCe=Zi(),{Readable:SCe,pipeline:_Ce,finished:vCe,isErrored:RCe,isReadable:xm}=(ts(),Gs(Yt)),{addAbortListener:DCe,bufferToLowerCasedHeaderName:Uq}=$t(),{dataURLProcessor:TCe,serializeAMimeType:NCe,minimizeSupportedMimeType:MCe}=Bf(),{getGlobalDispatcher:FCe}=Wv(),{webidl:r1}=po(),{STATUS_CODES:Lq}=gE(),{bytesMatch:kCe}=Mq(),{createDeferredPromise:xCe}=nv(),{isomorphicEncode:Um}=mf(),{runtimeFeatures:UCe}=P_(),LCe=UCe.has("zstd"),PCe=["GET","HEAD"],OCe=typeof __UNDICI_IS_NODE__<"u"||typeof esbuildDetection<"u"?"node":"undici",Kv,Lm=class extends wCe{constructor(t){super(),this.dispatcher=t,this.connection=null,this.dump=!1,this.state="ongoing"}terminate(t){this.state==="ongoing"&&(this.state="terminated",this.connection?.destroy(t),this.emit("terminated",t))}abort(t){this.state==="ongoing"&&(this.state="aborted",t||(t=new DOMException("The operation was aborted.","AbortError")),this.serializedAbortReason=t,this.connection?.destroy(t),this.emit("terminated",t))}};function HCe(e){qq(e,"fetch")}function qCe(e,t=void 0){r1.argumentLengthCheck(arguments,1,"globalThis.fetch");let r=xCe(),n;try{n=new jbe(e,t)}catch(l){return r.reject(l),r.promise}let i=Xbe(n);if(n.signal.aborted)return Xv(r,i,null,n.signal.reason,null),r.promise;i.client.globalObject?.constructor?.name==="ServiceWorkerGlobalScope"&&(i.serviceWorkers="none");let o=null,a=!1,A=null;return DCe(n.signal,()=>{a=!0,nu(A!=null),A.abort(n.signal.reason);let l=o?.deref();Xv(r,i,l,n.signal.reason,A.controller)}),A=Yq({request:i,processResponseEndOfBody:HCe,processResponse:l=>{if(!a){if(l.aborted){Xv(r,i,o,A.serializedAbortReason,A.controller);return}if(l.type==="error"){r.reject(new TypeError("fetch failed",{cause:l.error}));return}o=new WeakRef(Vbe(l,"immutable")),r.resolve(o.deref()),r=null}},dispatcher:Kbe(n),requestObject:n}),r.promise}function qq(e,t="other"){if(e.type==="error"&&e.aborted||!e.urlList?.length)return;let r=e.urlList[0],n=e.timingInfo,i=e.cacheState;Pm(r)&&n!==null&&(e.timingAllowPassed||(n=t1({startTime:n.startTime}),i=""),n.endTime=Eg(),e.timingInfo=n,Gq(n,r.href,t,globalThis,i,"",e.status))}var Gq=performance.markResourceTiming;function Xv(e,t,r,n,i){if(e&&e.reject(n),t.body?.stream!=null&&xm(t.body.stream)&&t.body.stream.cancel(n).catch(o=>{if(o.code!=="ERR_INVALID_STATE")throw o}),r==null)return;let s=Jbe(r);s.body?.stream!=null&&xm(s.body.stream)&&i.error(n)}function Yq({request:e,processRequestBodyChunkLength:t,processRequestEndOfBody:r,processResponse:n,processResponseEndOfBody:i,processResponseConsumeBody:s,useParallelQueue:o=!1,dispatcher:a=FCe(),requestObject:A=null}){nu(a);let f=null,l=!1;e.client!=null&&(f=e.client.globalObject,l=e.client.crossOriginIsolatedCapability);let p=Eg(l),B=t1({startTime:p}),S={controller:new Lm(a),request:e,timingInfo:B,processRequestBodyChunkLength:t,processRequestEndOfBody:r,processResponse:n,processResponseConsumeBody:s,processResponseEndOfBody:i,taskDestination:f,crossOriginIsolatedCapability:l,requestObject:A};return nu(!e.body||e.body.stream),e.window==="client"&&(e.window=e.client?.globalObject?.constructor?.name==="Window"?e.client:"no-window"),e.origin==="client"&&(e.origin=e.client.origin),e.policyContainer==="client"&&(e.client!=null?e.policyContainer=$be(e.client.policyContainer):e.policyContainer=Zbe()),e.headersList.contains("accept",!0)||e.headersList.append("accept","*/*",!0),e.headersList.contains("accept-language",!0)||e.headersList.append("accept-language","*",!0),e.priority,QCe.has(e.destination),Wq(S,!1),S.controller}async function Wq(e,t){try{let r=e.request,n=null;if(r.localURLsOnly&&!hCe(si(r))&&(n=Mt("local URLs only")),sCe(r),eCe(r)==="blocked"&&(n=Mt("bad port")),r.referrerPolicy===""&&(r.referrerPolicy=r.policyContainer.referrerPolicy),r.referrer!=="no-referrer"&&(r.referrer=fCe(r)),n===null){let s=si(r);$v(s,r.url)&&r.responseTainting==="basic"||s.protocol==="data:"||r.mode==="navigate"||r.mode==="websocket"?(r.responseTainting="basic",n=await Pq(e)):r.mode==="same-origin"?n=Mt('request mode cannot be "same-origin"'):r.mode==="no-cors"?r.redirect!=="follow"?n=Mt('redirect mode cannot be "follow" for "no-cors" request'):(r.responseTainting="opaque",n=await Pq(e)):Pm(si(r))?(r.responseTainting="cors",n=await Vq(e)):n=Mt("URL scheme must be a HTTP(S) scheme")}if(t)return n;n.status!==0&&!n.internalResponse&&(r.responseTainting,r.responseTainting==="basic"?n=jv(n,"basic"):r.responseTainting==="cors"?n=jv(n,"cors"):r.responseTainting==="opaque"?n=jv(n,"opaque"):nu(!1));let i=n.status===0?n:n.internalResponse;if(i.urlList.length===0&&i.urlList.push(...r.urlList),r.timingAllowFailed||(n.timingAllowPassed=!0),n.type==="opaque"&&i.status===206&&i.rangeRequested&&!r.headers.contains("range",!0)&&(n=i=Mt()),n.status!==0&&(r.method==="HEAD"||r.method==="CONNECT"||Hq.includes(i.status))&&(i.body=null,e.controller.dump=!0),r.integrity){let s=a=>Zv(e,Mt(a));if(r.responseTainting==="opaque"||n.body==null){s(n.error);return}let o=a=>{if(!kCe(a,r.integrity)){s("integrity mismatch");return}n.body=Om(a)[0],Zv(e,n)};cCe(n.body,o,s)}else Zv(e,n)}catch(r){e.controller.terminate(r)}}function Pq(e){if(_A(e)&&e.request.redirectCount===0)return Promise.resolve(pg(e));let{request:t}=e,{protocol:r}=si(t);switch(r){case"about:":return Promise.resolve(Mt("about scheme is not supported"));case"blob:":{Kv||(Kv=Gr().resolveObjectURL);let n=si(t);if(n.search.length!==0)return Promise.resolve(Mt("NetworkError when attempting to fetch resource."));let i=Kv(n.toString());if(t.method!=="GET"||!r1.is.Blob(i))return Promise.resolve(Mt("invalid method"));let s=km(),o=i.size,a=Um(`${o}`),A=i.type;if(t.headersList.contains("range",!0)){s.rangeRequested=!0;let f=t.headersList.get("range",!0),l=pCe(f,!0);if(l==="failure")return Promise.resolve(Mt("failed to fetch the data URL"));let{rangeStartValue:p,rangeEndValue:B}=l;if(p===null)p=o-B,B=p+B-1;else{if(p>=o)return Promise.resolve(Mt("Range start is greater than the blob's size."));(B===null||B>=o)&&(B=o-1)}let S=i.slice(p,B+1,A),_=xq(S);s.body=_[0];let N=Um(`${S.size}`),P=ECe(p,B,o);s.status=206,s.statusText="Partial Content",s.headersList.set("content-length",N,!0),s.headersList.set("content-type",A,!0),s.headersList.set("content-range",P,!0)}else{let f=xq(i);s.statusText="OK",s.body=f[0],s.headersList.set("content-length",a,!0),s.headersList.set("content-type",A,!0)}return Promise.resolve(s)}case"data:":{let n=si(t),i=TCe(n);if(i==="failure")return Promise.resolve(Mt("failed to fetch the data URL"));let s=NCe(i.mimeType);return Promise.resolve(km({statusText:"OK",headersList:[["content-type",{name:"Content-Type",value:s}]],body:Om(i.body)[0]}))}case"file:":return Promise.resolve(Mt("not implemented... yet..."));case"http:":case"https:":return Vq(e).catch(n=>Mt(n));default:return Promise.resolve(Mt("unknown scheme"))}}function GCe(e,t){e.request.done=!0,e.processResponseDone!=null&&queueMicrotask(()=>e.processResponseDone(t))}function Zv(e,t){let r=e.timingInfo,n=()=>{let s=Date.now();e.request.destination==="document"&&(e.controller.fullTimingInfo=r),e.controller.reportTimingSteps=()=>{if(!Pm(e.request.url))return;r.endTime=s;let a=t.cacheState,A=t.bodyInfo;t.timingAllowPassed||(r=t1(r),a="");let f=0;if(e.request.mode!=="navigator"||!t.hasCrossOriginRedirects){f=t.status;let l=mCe(t.headersList);l!=="failure"&&(A.contentType=MCe(l))}e.request.initiatorType!=null&&Gq(r,e.request.url.href,e.request.initiatorType,globalThis,a,A,f)};let o=()=>{e.request.done=!0,e.processResponseEndOfBody!=null&&queueMicrotask(()=>e.processResponseEndOfBody(t)),e.request.initiatorType!=null&&e.controller.reportTimingSteps()};queueMicrotask(()=>o())};e.processResponse!=null&&queueMicrotask(()=>{e.processResponse(t),e.processResponse=null});let i=t.type==="error"?t:t.internalResponse??t;i.body==null?n():vCe(i.body.stream,()=>{n()})}async function Vq(e){let t=e.request,r=null,n=null,i=e.timingInfo;if(t.serviceWorkers,r===null){if(t.redirect==="follow"&&(t.serviceWorkers="none"),n=r=await e1(e),t.responseTainting==="cors"&&aCe(t,r)==="failure")return Mt("cors failure");tCe(t,r)==="failure"&&(t.timingAllowFailed=!0)}return(t.responseTainting==="opaque"||r.type==="opaque")&&ACe(t.origin,t.client,t.destination,n)==="blocked"?Mt("blocked"):(Oq.has(n.status)&&(t.redirect!=="manual"&&e.controller.connection.destroy(void 0,!1),t.redirect==="error"?r=Mt("unexpected redirect"):t.redirect==="manual"?r=n:t.redirect==="follow"?r=await YCe(e,r):nu(!1)),r.timingInfo=i,r)}function YCe(e,t){let r=e.request,n=t.internalResponse?t.internalResponse:t,i;try{if(i=nCe(n,si(r).hash),i==null)return t}catch(o){return Promise.resolve(Mt(o))}if(!Pm(i))return Promise.resolve(Mt("URL scheme must be a HTTP(S) scheme"));if(r.redirectCount===20)return Promise.resolve(Mt("redirect count exceeded"));if(r.redirectCount+=1,r.mode==="cors"&&(i.username||i.password)&&!$v(r,i))return Promise.resolve(Mt('cross origin not allowed for request mode "cors"'));if(r.responseTainting==="cors"&&(i.username||i.password))return Promise.resolve(Mt('URL cannot contain credentials for request mode "cors"'));if(n.status!==303&&r.body!=null&&r.body.source==null)return Promise.resolve(Mt());if([301,302].includes(n.status)&&r.method==="POST"||n.status===303&&!PCe.includes(r.method)){r.method="GET",r.body=null;for(let o of CCe)r.headersList.delete(o)}$v(si(r),i)||(r.headersList.delete("authorization",!0),r.headersList.delete("proxy-authorization",!0),r.headersList.delete("cookie",!0),r.headersList.delete("host",!0)),r.body!=null&&(nu(r.body.source!=null),r.body=Om(r.body.source)[0]);let s=e.timingInfo;return s.redirectEndTime=s.postRedirectStartTime=Eg(e.crossOriginIsolatedCapability),s.redirectStartTime===0&&(s.redirectStartTime=s.startTime),r.urlList.push(i),iCe(r,n),Wq(e,!0)}async function e1(e,t=!1,r=!1){let n=e.request,i=null,s=null,o=null,a=null,A=!1;n.window==="no-window"&&n.redirect==="error"?(i=e,s=n):(s=zbe(n),i={...e},i.request=s);let f=n.credentials==="include"||n.credentials==="same-origin"&&n.responseTainting==="basic",l=s.body?s.body.length:null,p=null;if(s.body==null&&["POST","PUT"].includes(s.method)&&(p="0"),l!=null&&(p=Um(`${l}`)),p!=null&&s.headersList.append("content-length",p,!0),l!=null&&s.keepalive,r1.is.URL(s.referrer)&&s.headersList.append("referer",Um(s.referrer.href),!0),rCe(s),oCe(s),s.headersList.contains("user-agent",!0)||s.headersList.append("user-agent",OCe,!0),s.cache==="default"&&(s.headersList.contains("if-modified-since",!0)||s.headersList.contains("if-none-match",!0)||s.headersList.contains("if-unmodified-since",!0)||s.headersList.contains("if-match",!0)||s.headersList.contains("if-range",!0))&&(s.cache="no-store"),s.cache==="no-cache"&&!s.preventNoCacheCacheControlHeaderModification&&!s.headersList.contains("cache-control",!0)&&s.headersList.append("cache-control","max-age=0",!0),(s.cache==="no-store"||s.cache==="reload")&&(s.headersList.contains("pragma",!0)||s.headersList.append("pragma","no-cache",!0),s.headersList.contains("cache-control",!0)||s.headersList.append("cache-control","no-cache",!0)),s.headersList.contains("range",!0)&&s.headersList.append("accept-encoding","identity",!0),s.headersList.contains("accept-encoding",!0)||(dCe(si(s))?s.headersList.append("accept-encoding","br, gzip, deflate",!0):s.headersList.append("accept-encoding","gzip, deflate",!0)),s.headersList.delete("host",!0),f&&!s.headersList.contains("authorization",!0)){let B=null;if(!(BCe(s)&&(s.useURLCredentials===void 0||!kq(si(s))))){if(kq(si(s))&&t){let{username:S,password:_}=si(s);B=`Basic ${Buffer.from(`${S}:${_}`).toString("base64")}`}}B!==null&&s.headersList.append("Authorization",B,!1)}if(a==null&&(s.cache="no-store"),s.cache!=="no-store"&&s.cache,o==null){if(s.cache==="only-if-cached")return Mt("only if cached");let B=await WCe(i,f,r);!bCe.has(s.method)&&B.status>=200&&B.status<=399,A&&B.status,o==null&&(o=B)}if(o.urlList=[...s.urlList],s.headersList.contains("range",!0)&&(o.rangeRequested=!0),o.requestIncludesCredentials=f,o.status===401&&s.responseTainting!=="cors"&&f&&ICe(n.traversableForUserPrompts)){if(n.body!=null){if(n.body.source==null)return Mt("expected non-null body source");n.body=Om(n.body.source)[0]}if(n.useURLCredentials===void 0||t)return _A(e)?pg(e):o;e.controller.connection.destroy(),o=await e1(e,!0)}if(o.status===407)return n.window==="no-window"?Mt():_A(e)?pg(e):Mt("proxy authentication required");if(o.status===421&&!r&&(n.body==null||n.body.source!=null)){if(_A(e))return pg(e);e.controller.connection.destroy(),o=await e1(e,t,!0)}return o}async function WCe(e,t=!1,r=!1){nu(!e.controller.connection||e.controller.connection.destroyed),e.controller.connection={abort:null,destroyed:!1,destroy(_,N=!0){this.destroyed||(this.destroyed=!0,N&&this.abort?.(_??new DOMException("The operation was aborted.","AbortError")))}};let n=e.request,i=null,s=e.timingInfo;null==null&&(n.cache="no-store");let a=r?"yes":"no";n.mode;let A=null;if(n.body==null&&e.processRequestEndOfBody)queueMicrotask(()=>e.processRequestEndOfBody());else if(n.body!=null){let _=async function*(U){_A(e)||(yield U,e.processRequestBodyChunkLength?.(U.byteLength))},N=()=>{_A(e)||e.processRequestEndOfBody&&e.processRequestEndOfBody()},P=U=>{_A(e)||(U.name==="AbortError"?e.controller.abort():e.controller.terminate(U))};A=(async function*(){try{for await(let U of n.body.stream)yield*_(U);N()}catch(U){P(U)}})()}try{let{body:_,status:N,statusText:P,headersList:U,socket:G}=await S({body:A});if(G)i=km({status:N,statusText:P,headersList:U,socket:G});else{let Y=_[Symbol.asyncIterator]();e.controller.next=()=>Y.next(),i=km({status:N,statusText:P,headersList:U})}}catch(_){return _.name==="AbortError"?(e.controller.connection.destroy(),pg(e,_)):Mt(_)}let f=()=>e.controller.resume(),l=_=>{_A(e)||e.controller.abort(_)},p=new ReadableStream({start(_){e.controller.controller=_},pull:f,cancel:l,type:"bytes"});i.body={stream:p,source:null,length:null},e.controller.resume||e.controller.on("terminated",B),e.controller.resume=async()=>{for(;;){let _,N;try{let{done:U,value:G}=await e.controller.next();if(Fq(e))break;_=U?void 0:G}catch(U){e.controller.ended&&!s.encodedBodySize?_=void 0:(_=U,N=!0)}if(_===void 0){lCe(e.controller.controller),GCe(e,i);return}if(s.decodedBodySize+=_?.byteLength??0,N){e.controller.terminate(_);return}let P=new Uint8Array(_);if(P.byteLength&&e.controller.controller.enqueue(P),RCe(p)){e.controller.terminate();return}if(e.controller.controller.desiredSize<=0)return}};function B(_){Fq(e)?(i.aborted=!0,xm(p)&&e.controller.controller.error(e.controller.serializedAbortReason)):xm(p)&&e.controller.controller.error(new TypeError("terminated",{cause:uCe(_)?_:void 0})),e.controller.connection.destroy()}return i;function S({body:_}){let N=si(n),P=e.controller.dispatcher,U=N.pathname+N.search,G=N.search.length===0&&N.href[N.href.length-N.hash.length-1]==="?";return new Promise((Y,Z)=>P.dispatch({path:G?`${U}?`:U,origin:N.origin,method:n.method,body:P.isMockActive?n.body&&(n.body.source||n.body.stream):_,headers:n.headersList.entries,maxRedirections:0,upgrade:n.mode==="websocket"?"websocket":void 0},{body:null,abort:null,onConnect(ee){let{connection:j}=e.controller;s.finalConnectionTimingInfo=gCe(void 0,s.postRedirectStartTime,e.crossOriginIsolatedCapability),j.destroyed?ee(new DOMException("The operation was aborted.","AbortError")):(e.controller.on("terminated",ee),this.abort=j.abort=ee),s.finalNetworkRequestStartTime=Eg(e.crossOriginIsolatedCapability)},onResponseStarted(){s.finalNetworkResponseStartTime=Eg(e.crossOriginIsolatedCapability)},onHeaders(ee,j,se,ie){if(ee<200)return!1;let ce=new zv;for(let c=0;cw)return Z(new Error(`too many content-encodings in response: ${g.length}, maximum allowed is ${w}`)),!0;for(let R=g.length-1;R>=0;--R){let C=g[R].trim();if(C==="x-gzip"||C==="gzip")v.push(ws.createGunzip({flush:ws.constants.Z_SYNC_FLUSH,finishFlush:ws.constants.Z_SYNC_FLUSH}));else if(C==="deflate")v.push(yCe({flush:ws.constants.Z_SYNC_FLUSH,finishFlush:ws.constants.Z_SYNC_FLUSH}));else if(C==="br")v.push(ws.createBrotliDecompress({flush:ws.constants.BROTLI_OPERATION_FLUSH,finishFlush:ws.constants.BROTLI_OPERATION_FLUSH}));else if(C==="zstd"&&LCe)v.push(ws.createZstdDecompress({flush:ws.constants.ZSTD_e_continue,finishFlush:ws.constants.ZSTD_e_end}));else{v.length=0;break}}}let b=this.onError.bind(this);return Y({status:ee,statusText:ie,headersList:ce,body:v.length?_Ce(this.body,...v,c=>{c&&this.onError(c)}).on("error",b):this.body.on("error",b)}),!0},onData(ee){if(e.controller.dump)return;let j=ee;return s.encodedBodySize+=j.byteLength,this.body.push(j)},onComplete(){this.abort&&e.controller.off("terminated",this.abort),e.controller.ended=!0,this.body.push(null)},onError(ee){this.abort&&e.controller.off("terminated",this.abort),this.body?.destroy(ee),e.controller.terminate(ee),Z(ee)},onRequestUpgrade(ee,j,se,ie){if(ie.session!=null&&j!==200||ie.session==null&&j!==101)return!1;let ce=new zv;for(let[H,E]of Object.entries(se)){if(E==null)continue;let v=H.toLowerCase();if(Array.isArray(E))for(let b of E)ce.append(v,String(b),!0);else ce.append(v,String(E),!0)}return Y({status:j,statusText:Lq[j],headersList:ce,socket:ie}),!0},onUpgrade(ee,j,se){if(se.session!=null&&ee!==200||se.session==null&&ee!==101)return!1;let ie=new zv;for(let ce=0;ceNZ,DH_CHECK_P_NOT_SAFE_PRIME:()=>TZ,DH_NOT_SUITABLE_GENERATOR:()=>FZ,DH_UNABLE_TO_CHECK_GENERATOR:()=>MZ,E2BIG:()=>Lz,EACCES:()=>Pz,EADDRINUSE:()=>Oz,EADDRNOTAVAIL:()=>Hz,EAFNOSUPPORT:()=>qz,EAGAIN:()=>Gz,EALREADY:()=>Yz,EBADF:()=>Wz,EBADMSG:()=>Vz,EBUSY:()=>Jz,ECANCELED:()=>jz,ECHILD:()=>zz,ECONNABORTED:()=>Kz,ECONNREFUSED:()=>Xz,ECONNRESET:()=>Zz,EDEADLK:()=>$z,EDESTADDRREQ:()=>eK,EDOM:()=>tK,EDQUOT:()=>rK,EEXIST:()=>nK,EFAULT:()=>iK,EFBIG:()=>sK,EHOSTUNREACH:()=>oK,EIDRM:()=>aK,EILSEQ:()=>AK,EINPROGRESS:()=>fK,EINTR:()=>uK,EINVAL:()=>cK,EIO:()=>lK,EISCONN:()=>hK,EISDIR:()=>dK,ELOOP:()=>gK,EMFILE:()=>pK,EMLINK:()=>EK,EMSGSIZE:()=>yK,EMULTIHOP:()=>mK,ENAMETOOLONG:()=>BK,ENETDOWN:()=>IK,ENETRESET:()=>bK,ENETUNREACH:()=>CK,ENFILE:()=>QK,ENGINE_METHOD_ALL:()=>RZ,ENGINE_METHOD_CIPHERS:()=>QZ,ENGINE_METHOD_DH:()=>BZ,ENGINE_METHOD_DIGESTS:()=>wZ,ENGINE_METHOD_DSA:()=>mZ,ENGINE_METHOD_ECDH:()=>bZ,ENGINE_METHOD_ECDSA:()=>CZ,ENGINE_METHOD_NONE:()=>DZ,ENGINE_METHOD_PKEY_ASN1_METHS:()=>vZ,ENGINE_METHOD_PKEY_METHS:()=>_Z,ENGINE_METHOD_RAND:()=>IZ,ENGINE_METHOD_STORE:()=>SZ,ENOBUFS:()=>wK,ENODATA:()=>SK,ENODEV:()=>_K,ENOENT:()=>vK,ENOEXEC:()=>RK,ENOLCK:()=>DK,ENOLINK:()=>TK,ENOMEM:()=>NK,ENOMSG:()=>MK,ENOPROTOOPT:()=>FK,ENOSPC:()=>kK,ENOSR:()=>xK,ENOSTR:()=>UK,ENOSYS:()=>LK,ENOTCONN:()=>PK,ENOTDIR:()=>OK,ENOTEMPTY:()=>HK,ENOTSOCK:()=>qK,ENOTSUP:()=>GK,ENOTTY:()=>YK,ENXIO:()=>WK,EOPNOTSUPP:()=>VK,EOVERFLOW:()=>JK,EPERM:()=>jK,EPIPE:()=>zK,EPROTO:()=>KK,EPROTONOSUPPORT:()=>XK,EPROTOTYPE:()=>ZK,ERANGE:()=>$K,EROFS:()=>eX,ESPIPE:()=>tX,ESRCH:()=>rX,ESTALE:()=>nX,ETIME:()=>iX,ETIMEDOUT:()=>sX,ETXTBSY:()=>oX,EWOULDBLOCK:()=>aX,EXDEV:()=>AX,F_OK:()=>WZ,NPN_ENABLED:()=>kZ,O_APPEND:()=>Bz,O_CREAT:()=>pz,O_DIRECTORY:()=>Iz,O_EXCL:()=>Ez,O_NOCTTY:()=>yz,O_NOFOLLOW:()=>bz,O_NONBLOCK:()=>wz,O_RDONLY:()=>sz,O_RDWR:()=>az,O_SYMLINK:()=>Qz,O_SYNC:()=>Cz,O_TRUNC:()=>mz,O_WRONLY:()=>oz,POINT_CONVERSION_COMPRESSED:()=>qZ,POINT_CONVERSION_HYBRID:()=>YZ,POINT_CONVERSION_UNCOMPRESSED:()=>GZ,RSA_NO_PADDING:()=>LZ,RSA_PKCS1_OAEP_PADDING:()=>PZ,RSA_PKCS1_PADDING:()=>xZ,RSA_PKCS1_PSS_PADDING:()=>HZ,RSA_SSLV23_PADDING:()=>UZ,RSA_X931_PADDING:()=>OZ,R_OK:()=>VZ,SIGABRT:()=>dX,SIGALRM:()=>CX,SIGBUS:()=>pX,SIGCHLD:()=>wX,SIGCONT:()=>SX,SIGFPE:()=>EX,SIGHUP:()=>fX,SIGILL:()=>lX,SIGINT:()=>uX,SIGIO:()=>UX,SIGIOT:()=>gX,SIGKILL:()=>yX,SIGPIPE:()=>bX,SIGPROF:()=>kX,SIGQUIT:()=>cX,SIGSEGV:()=>BX,SIGSTOP:()=>_X,SIGSYS:()=>LX,SIGTERM:()=>QX,SIGTRAP:()=>hX,SIGTSTP:()=>vX,SIGTTIN:()=>RX,SIGTTOU:()=>DX,SIGURG:()=>TX,SIGUSR1:()=>mX,SIGUSR2:()=>IX,SIGVTALRM:()=>FX,SIGWINCH:()=>xX,SIGXCPU:()=>NX,SIGXFSZ:()=>MX,SSL_OP_ALL:()=>PX,SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION:()=>OX,SSL_OP_CIPHER_SERVER_PREFERENCE:()=>HX,SSL_OP_CISCO_ANYCONNECT:()=>qX,SSL_OP_COOKIE_EXCHANGE:()=>GX,SSL_OP_CRYPTOPRO_TLSEXT_BUG:()=>YX,SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:()=>WX,SSL_OP_EPHEMERAL_RSA:()=>VX,SSL_OP_LEGACY_SERVER_CONNECT:()=>JX,SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER:()=>jX,SSL_OP_MICROSOFT_SESS_ID_BUG:()=>zX,SSL_OP_MSIE_SSLV2_RSA_PADDING:()=>KX,SSL_OP_NETSCAPE_CA_DN_BUG:()=>XX,SSL_OP_NETSCAPE_CHALLENGE_BUG:()=>ZX,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG:()=>$X,SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG:()=>eZ,SSL_OP_NO_COMPRESSION:()=>tZ,SSL_OP_NO_QUERY_MTU:()=>rZ,SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION:()=>nZ,SSL_OP_NO_SSLv2:()=>iZ,SSL_OP_NO_SSLv3:()=>sZ,SSL_OP_NO_TICKET:()=>oZ,SSL_OP_NO_TLSv1:()=>aZ,SSL_OP_NO_TLSv1_1:()=>AZ,SSL_OP_NO_TLSv1_2:()=>fZ,SSL_OP_PKCS1_CHECK_1:()=>uZ,SSL_OP_PKCS1_CHECK_2:()=>cZ,SSL_OP_SINGLE_DH_USE:()=>lZ,SSL_OP_SINGLE_ECDH_USE:()=>hZ,SSL_OP_SSLEAY_080_CLIENT_DH_BUG:()=>dZ,SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG:()=>gZ,SSL_OP_TLS_BLOCK_PADDING_BUG:()=>pZ,SSL_OP_TLS_D5_BUG:()=>EZ,SSL_OP_TLS_ROLLBACK_BUG:()=>yZ,S_IFBLK:()=>lz,S_IFCHR:()=>cz,S_IFDIR:()=>uz,S_IFIFO:()=>hz,S_IFLNK:()=>dz,S_IFMT:()=>Az,S_IFREG:()=>fz,S_IFSOCK:()=>gz,S_IRGRP:()=>Tz,S_IROTH:()=>kz,S_IRUSR:()=>_z,S_IRWXG:()=>Dz,S_IRWXO:()=>Fz,S_IRWXU:()=>Sz,S_IWGRP:()=>Nz,S_IWOTH:()=>xz,S_IWUSR:()=>vz,S_IXGRP:()=>Mz,S_IXOTH:()=>Uz,S_IXUSR:()=>Rz,UV_UDP_REUSEADDR:()=>zZ,W_OK:()=>JZ,X_OK:()=>jZ,default:()=>KZ});var sz=0,oz=1,az=2,Az=61440,fz=32768,uz=16384,cz=8192,lz=24576,hz=4096,dz=40960,gz=49152,pz=512,Ez=2048,yz=131072,mz=1024,Bz=8,Iz=1048576,bz=256,Cz=128,Qz=2097152,wz=4,Sz=448,_z=256,vz=128,Rz=64,Dz=56,Tz=32,Nz=16,Mz=8,Fz=7,kz=4,xz=2,Uz=1,Lz=7,Pz=13,Oz=48,Hz=49,qz=47,Gz=35,Yz=37,Wz=9,Vz=94,Jz=16,jz=89,zz=10,Kz=53,Xz=61,Zz=54,$z=11,eK=39,tK=33,rK=69,nK=17,iK=14,sK=27,oK=65,aK=90,AK=92,fK=36,uK=4,cK=22,lK=5,hK=56,dK=21,gK=62,pK=24,EK=31,yK=40,mK=95,BK=63,IK=50,bK=52,CK=51,QK=23,wK=55,SK=96,_K=19,vK=2,RK=8,DK=77,TK=97,NK=12,MK=91,FK=42,kK=28,xK=98,UK=99,LK=78,PK=57,OK=20,HK=66,qK=38,GK=45,YK=25,WK=6,VK=102,JK=84,jK=1,zK=32,KK=100,XK=43,ZK=41,$K=34,eX=30,tX=29,rX=3,nX=70,iX=101,sX=60,oX=26,aX=35,AX=18,fX=1,uX=2,cX=3,lX=4,hX=5,dX=6,gX=6,pX=10,EX=8,yX=9,mX=30,BX=11,IX=31,bX=13,CX=14,QX=15,wX=20,SX=19,_X=17,vX=18,RX=21,DX=22,TX=16,NX=24,MX=25,FX=26,kX=27,xX=28,UX=23,LX=12,PX=2147486719,OX=262144,HX=4194304,qX=32768,GX=8192,YX=2147483648,WX=2048,VX=0,JX=4,jX=32,zX=1,KX=0,XX=536870912,ZX=2,$X=1073741824,eZ=8,tZ=131072,rZ=4096,nZ=65536,iZ=16777216,sZ=33554432,oZ=16384,aZ=67108864,AZ=268435456,fZ=134217728,uZ=0,cZ=0,lZ=1048576,hZ=524288,dZ=128,gZ=0,pZ=512,EZ=256,yZ=8388608,mZ=2,BZ=4,IZ=8,bZ=16,CZ=32,QZ=64,wZ=128,SZ=256,_Z=512,vZ=1024,RZ=65535,DZ=0,TZ=2,NZ=1,MZ=4,FZ=8,kZ=1,xZ=1,UZ=2,LZ=3,PZ=4,OZ=5,HZ=6,qZ=2,GZ=4,YZ=6,WZ=0,VZ=4,JZ=2,jZ=1,zZ=4,KZ={O_RDONLY:sz,O_WRONLY:oz,O_RDWR:az,S_IFMT:Az,S_IFREG:fz,S_IFDIR:uz,S_IFCHR:cz,S_IFBLK:lz,S_IFIFO:hz,S_IFLNK:dz,S_IFSOCK:gz,O_CREAT:pz,O_EXCL:Ez,O_NOCTTY:yz,O_TRUNC:mz,O_APPEND:Bz,O_DIRECTORY:Iz,O_NOFOLLOW:bz,O_SYNC:Cz,O_SYMLINK:Qz,O_NONBLOCK:wz,S_IRWXU:Sz,S_IRUSR:_z,S_IWUSR:vz,S_IXUSR:Rz,S_IRWXG:Dz,S_IRGRP:Tz,S_IWGRP:Nz,S_IXGRP:Mz,S_IRWXO:Fz,S_IROTH:kz,S_IWOTH:xz,S_IXOTH:Uz,E2BIG:Lz,EACCES:Pz,EADDRINUSE:Oz,EADDRNOTAVAIL:Hz,EAFNOSUPPORT:qz,EAGAIN:Gz,EALREADY:Yz,EBADF:Wz,EBADMSG:Vz,EBUSY:Jz,ECANCELED:jz,ECHILD:zz,ECONNABORTED:Kz,ECONNREFUSED:Xz,ECONNRESET:Zz,EDEADLK:$z,EDESTADDRREQ:eK,EDOM:tK,EDQUOT:rK,EEXIST:nK,EFAULT:iK,EFBIG:sK,EHOSTUNREACH:oK,EIDRM:aK,EILSEQ:AK,EINPROGRESS:fK,EINTR:uK,EINVAL:cK,EIO:lK,EISCONN:hK,EISDIR:dK,ELOOP:gK,EMFILE:pK,EMLINK:EK,EMSGSIZE:yK,EMULTIHOP:mK,ENAMETOOLONG:BK,ENETDOWN:IK,ENETRESET:bK,ENETUNREACH:CK,ENFILE:QK,ENOBUFS:wK,ENODATA:SK,ENODEV:_K,ENOENT:vK,ENOEXEC:RK,ENOLCK:DK,ENOLINK:TK,ENOMEM:NK,ENOMSG:MK,ENOPROTOOPT:FK,ENOSPC:kK,ENOSR:xK,ENOSTR:UK,ENOSYS:LK,ENOTCONN:PK,ENOTDIR:OK,ENOTEMPTY:HK,ENOTSOCK:qK,ENOTSUP:GK,ENOTTY:YK,ENXIO:WK,EOPNOTSUPP:VK,EOVERFLOW:JK,EPERM:jK,EPIPE:zK,EPROTO:KK,EPROTONOSUPPORT:XK,EPROTOTYPE:ZK,ERANGE:$K,EROFS:eX,ESPIPE:tX,ESRCH:rX,ESTALE:nX,ETIME:iX,ETIMEDOUT:sX,ETXTBSY:oX,EWOULDBLOCK:aX,EXDEV:AX,SIGHUP:fX,SIGINT:uX,SIGQUIT:cX,SIGILL:lX,SIGTRAP:hX,SIGABRT:dX,SIGIOT:gX,SIGBUS:pX,SIGFPE:EX,SIGKILL:yX,SIGUSR1:mX,SIGSEGV:BX,SIGUSR2:IX,SIGPIPE:bX,SIGALRM:CX,SIGTERM:QX,SIGCHLD:wX,SIGCONT:SX,SIGSTOP:_X,SIGTSTP:vX,SIGTTIN:RX,SIGTTOU:DX,SIGURG:TX,SIGXCPU:NX,SIGXFSZ:MX,SIGVTALRM:FX,SIGPROF:kX,SIGWINCH:xX,SIGIO:UX,SIGSYS:LX,SSL_OP_ALL:PX,SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION:OX,SSL_OP_CIPHER_SERVER_PREFERENCE:HX,SSL_OP_CISCO_ANYCONNECT:qX,SSL_OP_COOKIE_EXCHANGE:GX,SSL_OP_CRYPTOPRO_TLSEXT_BUG:YX,SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:WX,SSL_OP_EPHEMERAL_RSA:VX,SSL_OP_LEGACY_SERVER_CONNECT:JX,SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER:jX,SSL_OP_MICROSOFT_SESS_ID_BUG:zX,SSL_OP_MSIE_SSLV2_RSA_PADDING:KX,SSL_OP_NETSCAPE_CA_DN_BUG:XX,SSL_OP_NETSCAPE_CHALLENGE_BUG:ZX,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG:$X,SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG:eZ,SSL_OP_NO_COMPRESSION:tZ,SSL_OP_NO_QUERY_MTU:rZ,SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION:nZ,SSL_OP_NO_SSLv2:iZ,SSL_OP_NO_SSLv3:sZ,SSL_OP_NO_TICKET:oZ,SSL_OP_NO_TLSv1:aZ,SSL_OP_NO_TLSv1_1:AZ,SSL_OP_NO_TLSv1_2:fZ,SSL_OP_PKCS1_CHECK_1:uZ,SSL_OP_PKCS1_CHECK_2:cZ,SSL_OP_SINGLE_DH_USE:lZ,SSL_OP_SINGLE_ECDH_USE:hZ,SSL_OP_SSLEAY_080_CLIENT_DH_BUG:dZ,SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG:gZ,SSL_OP_TLS_BLOCK_PADDING_BUG:pZ,SSL_OP_TLS_D5_BUG:EZ,SSL_OP_TLS_ROLLBACK_BUG:yZ,ENGINE_METHOD_DSA:mZ,ENGINE_METHOD_DH:BZ,ENGINE_METHOD_RAND:IZ,ENGINE_METHOD_ECDH:bZ,ENGINE_METHOD_ECDSA:CZ,ENGINE_METHOD_CIPHERS:QZ,ENGINE_METHOD_DIGESTS:wZ,ENGINE_METHOD_STORE:SZ,ENGINE_METHOD_PKEY_METHS:_Z,ENGINE_METHOD_PKEY_ASN1_METHS:vZ,ENGINE_METHOD_ALL:RZ,ENGINE_METHOD_NONE:DZ,DH_CHECK_P_NOT_SAFE_PRIME:TZ,DH_CHECK_P_NOT_PRIME:NZ,DH_UNABLE_TO_CHECK_GENERATOR:MZ,DH_NOT_SUITABLE_GENERATOR:FZ,NPN_ENABLED:kZ,RSA_PKCS1_PADDING:xZ,RSA_SSLV23_PADDING:UZ,RSA_NO_PADDING:LZ,RSA_PKCS1_OAEP_PADDING:PZ,RSA_X931_PADDING:OZ,RSA_PKCS1_PSS_PADDING:HZ,POINT_CONVERSION_COMPRESSED:qZ,POINT_CONVERSION_UNCOMPRESSED:GZ,POINT_CONVERSION_HYBRID:YZ,F_OK:WZ,R_OK:VZ,W_OK:JZ,X_OK:jZ,UV_UDP_REUSEADDR:zZ};var VCe=hr(Zi()),qg=hr(tT()),JCe=hr(VI());jI();ts();var jCe=hr(af()),wu=hr(kk()),JB=hr(Yr());var Wr=hr(Uk()),RC=class{constructor(){let t=new globalThis.TextEncoder,r=new Wr.TransformStream({transform(n,i){i.enqueue(t.encode(n))}});this.encoding="utf-8",this.readable=r.readable,this.writable=r.writable}},DC=class{constructor(t="utf-8",r=void 0){let n=new globalThis.TextDecoder(t,r),i=new Wr.TransformStream({transform(s,o){let a=n.decode(s,{stream:!0});a.length>0&&o.enqueue(a)},flush(s){let o=n.decode();o.length>0&&s.enqueue(o)}});this.encoding=n.encoding,this.fatal=n.fatal,this.ignoreBOM=n.ignoreBOM,this.readable=i.readable,this.writable=i.writable}},Jp=typeof globalThis.TextEncoderStream=="function"?globalThis.TextEncoderStream:RC,jp=typeof globalThis.TextDecoderStream=="function"?globalThis.TextDecoderStream:DC;typeof globalThis.ReadableStream>"u"&&(globalThis.ReadableStream=Wr.ReadableStream);typeof globalThis.WritableStream>"u"&&(globalThis.WritableStream=Wr.WritableStream);typeof globalThis.TransformStream>"u"&&(globalThis.TransformStream=Wr.TransformStream);typeof globalThis.TextEncoderStream>"u"&&(globalThis.TextEncoderStream=Jp);typeof globalThis.TextDecoderStream>"u"&&(globalThis.TextDecoderStream=jp);var Sg=hr(p6()),k1=hr(xv()),x1=hr(mm()),eB=hr(jq()),M2=hr(Wv()),yu=hr(dg()),mu=hr(Yv()),Bu=hr(Hv()),U1=hr(po());var BY=e=>{throw TypeError(e)},IY=(e,t,r)=>t.has(e)||BY("Cannot "+r),jt=(e,t,r)=>(IY(e,t,"read from private field"),r?r.call(e):t.get(e)),zq=(e,t,r)=>t.has(e)?BY("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,r),Kq=(e,t,r,n)=>(IY(e,t,"write to private field"),n?n.call(e,r):t.set(e,r),r),Xq=globalThis.AbortController,Zq=globalThis.AbortSignal,L1=xl.Buffer??xl.default?.Buffer??xl.default;function Hm(e){return typeof e=="string"&&e.toLowerCase()==="base64url"?"base64":e}function zCe(e){return String(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function KCe(e){if(typeof e!="function"||e.__agentOSBase64UrlPatched)return;let t=typeof e.isEncoding=="function"?e.isEncoding.bind(e):null,r=typeof e.byteLength=="function"?e.byteLength.bind(e):null,n=typeof e.prototype?.toString=="function"?e.prototype.toString:null,i=typeof e.prototype?.write=="function"?e.prototype.write:null;e.isEncoding=function(o){return typeof o=="string"&&o.toLowerCase()==="base64url"||t?.(o)===!0},r&&(e.byteLength=function(o,a,...A){return r(o,Hm(a),...A)}),n&&(e.prototype.toString=function(o,...a){return typeof o=="string"&&o.toLowerCase()==="base64url"?zCe(n.call(this,"base64",...a)):n.call(this,o,...a)}),i&&(e.prototype.write=function(o,a,A,f){return typeof a=="string"?a=Hm(a):typeof A=="string"?A=Hm(A):typeof f=="string"&&(f=Hm(f)),i.call(this,o,a,A,f)}),e.__agentOSBase64UrlPatched=!0}KCe(L1);typeof L1=="function"&&(globalThis.Buffer=L1);var ml=JB.types??JB.default?.types,XCe=new Map([["[object Int8Array]",Int8Array],["[object Uint8Array]",Uint8Array],["[object Uint8ClampedArray]",Uint8ClampedArray],["[object Int16Array]",Int16Array],["[object Uint16Array]",Uint16Array],["[object Int32Array]",Int32Array],["[object Uint32Array]",Uint32Array],["[object Float32Array]",Float32Array],["[object Float64Array]",Float64Array],["[object BigInt64Array]",BigInt64Array],["[object BigUint64Array]",BigUint64Array]]);function $q(e="The object could not be cloned."){if(typeof globalThis.DOMException=="function")return new globalThis.DOMException(e,"DataCloneError");let t=new Error(e);return t.name="DataCloneError",t.code=25,t}function ZCe(e){let t=new ArrayBuffer(e.byteLength);return new Uint8Array(t).set(new Uint8Array(e)),t}function RA(e,t){if(e===null)return e;let r=typeof e;if(r==="function"||r==="symbol")throw $q();if(r!=="object")return e;let n=t.get(e);if(n!==void 0)return n;let i=Object.prototype.toString.call(e),s=XCe.get(i);if(s){let o=RA(e.buffer,t),a=new s(o,e.byteOffset,e.length);return t.set(e,a),a}if(i==="[object ArrayBuffer]"){let o=ZCe(e);return t.set(e,o),o}if(i==="[object DataView]"){let o=RA(e.buffer,t),a=new DataView(o,e.byteOffset,e.byteLength);return t.set(e,a),a}if(i==="[object Date]"){let o=new Date(e.getTime());return t.set(e,o),o}if(i==="[object RegExp]"){let o=new RegExp(e.source,e.flags);return o.lastIndex=e.lastIndex,t.set(e,o),o}if(i==="[object Map]"){let o=new Map;t.set(e,o);for(let[a,A]of e.entries())o.set(RA(a,t),RA(A,t));return o}if(i==="[object Set]"){let o=new Set;t.set(e,o);for(let a of e.values())o.add(RA(a,t));return o}if(i==="[object Array]"){let o=new Array(e.length);t.set(e,o);for(let a of Object.keys(e))o[a]=RA(e[a],t);return o}if(i==="[object Object]"){let o=Object.getPrototypeOf(e)===null?Object.create(null):{};t.set(e,o);for(let a of Object.keys(e))o[a]=RA(e[a],t);return o}throw $q()}function $Ce(e,t=void 0){return t!=null&&typeof t=="object"&&"transfer"in t&&t.transfer,RA(e,new Map)}if(ml&&typeof ml.isProxy!="function")ml.isProxy=()=>!1;else if(ml)try{ml.isProxy({})}catch{ml.isProxy=()=>!1}function eQe(e){if(typeof e=="boolean")return{capture:e,once:!1,passive:!1};if(e==null)return{capture:!1,once:!1,passive:!1};let t=Object(e);return{capture:!!t.capture,once:!!t.once,passive:!!t.passive,signal:t.signal}}function tQe(e){return typeof e=="boolean"?e:e==null?!1:!!Object(e).capture}function rQe(e){return typeof e=="object"&&e!==null&&"aborted"in e&&typeof e.addEventListener=="function"&&typeof e.removeEventListener=="function"}var wl,bY=(wl=class{constructor(e,t){y(this,"type");y(this,"bubbles");y(this,"cancelable");y(this,"composed");y(this,"detail",null);y(this,"defaultPrevented",!1);y(this,"target",null);y(this,"currentTarget",null);y(this,"eventPhase",0);y(this,"returnValue",!0);y(this,"cancelBubble",!1);y(this,"timeStamp",Date.now());y(this,"isTrusted",!1);y(this,"srcElement",null);y(this,"inPassiveListener",!1);y(this,"propagationStopped",!1);y(this,"immediatePropagationStopped",!1);if(arguments.length===0)throw new TypeError("The event type must be provided");let r=t==null?{}:Object(t);this.type=String(e),this.bubbles=!!r.bubbles,this.cancelable=!!r.cancelable,this.composed=!!r.composed}get[Symbol.toStringTag](){return"Event"}preventDefault(){this.cancelable&&!this.inPassiveListener&&(this.defaultPrevented=!0,this.returnValue=!1)}stopPropagation(){this.propagationStopped=!0,this.cancelBubble=!0}stopImmediatePropagation(){this.propagationStopped=!0,this.immediatePropagationStopped=!0,this.cancelBubble=!0}composedPath(){return this.target?[this.target]:[]}_setPassive(e){this.inPassiveListener=e}_isPropagationStopped(){return this.propagationStopped}_isImmediatePropagationStopped(){return this.immediatePropagationStopped}},y(wl,"NONE",0),y(wl,"CAPTURING_PHASE",1),y(wl,"AT_TARGET",2),y(wl,"BUBBLING_PHASE",3),wl),nQe=class extends bY{constructor(e,t){super(e,t);let r=t==null?null:Object(t);this.detail=r&&"detail"in r?r.detail:null}get[Symbol.toStringTag](){return"CustomEvent"}},iQe=class{constructor(){y(this,"listeners",new Map)}addEventListener(e,t,r){let n=eQe(r);if(n.signal!==void 0&&!rQe(n.signal))throw new TypeError('The "signal" option must be an instance of AbortSignal.');if(t==null||typeof t!="function"&&(typeof t!="object"||t===null)||n.signal?.aborted)return;let i=this.listeners.get(e)??[];if(i.find(a=>a.listener===t&&a.capture===n.capture))return;let o={listener:t,capture:n.capture,once:n.once,passive:n.passive,kind:typeof t=="function"?"function":"object",signal:n.signal};n.signal&&(o.abortListener=()=>{this.removeEventListener(e,t,n.capture)},n.signal.addEventListener("abort",o.abortListener,{once:!0})),i.push(o),this.listeners.set(e,i)}removeEventListener(e,t,r){if(t==null)return;let n=tQe(r),i=this.listeners.get(e);if(!i)return;let s=i.filter(o=>{let a=o.listener===t&&o.capture===n;return a&&o.signal&&o.abortListener&&o.signal.removeEventListener("abort",o.abortListener),!a});if(s.length===0){this.listeners.delete(e);return}this.listeners.set(e,s)}dispatchEvent(e){if(typeof e!="object"||e===null||typeof e.type!="string")throw new TypeError("Argument 1 must be an Event");let t=e,r=(this.listeners.get(t.type)??[]).slice();t.target=this,t.currentTarget=this,t.eventPhase=2;for(let n of r)if(this.listeners.get(t.type)?.includes(n)){if(n.once&&this.removeEventListener(t.type,n.listener,n.capture),t._setPassive(n.passive),n.kind==="function")n.listener.call(this,t);else{let s=n.listener.handleEvent;typeof s=="function"&&s.call(n.listener,t)}if(t._setPassive(!1),t._isImmediatePropagationStopped()||t._isPropagationStopped())break}return t.currentTarget=null,t.eventPhase=0,!t.defaultPrevented}},Ul=bY,F2=nQe,jB=iQe,Do=typeof Zq=="function"?Zq:class extends jB{constructor(){super(),this.aborted=!1,this.reason=void 0}throwIfAborted(){if(this.aborted)throw this.reason instanceof Error?this.reason:new Error(String(this.reason??"AbortError"))}},vu=typeof Xq=="function"?Xq:class{constructor(){this.signal=new Do}abort(e){this.signal.aborted||(this.signal.aborted=!0,this.signal.reason=e,this.signal.dispatchEvent(new Ul("abort")))}};function k2(e,t){if(typeof e=="function")try{e.name!==t&&Object.defineProperty(e,"name",{configurable:!0,value:t})}catch{}}k2(Do,"AbortSignal");k2(vu,"AbortController");try{let e=Object.getPrototypeOf(new vu().signal)?.constructor;k2(e,"AbortSignal")}catch{}try{globalThis.AbortSignal=Do}catch{}try{globalThis.AbortController=vu}catch{}function CY(e){if(e!==void 0)return e;if(typeof globalThis.DOMException=="function")return new globalThis.DOMException("This operation was aborted","AbortError");let t=new Error("This operation was aborted");return t.name="AbortError",t}function sQe(e){let t=new vu;return t.abort(CY(e)),t.signal}function oQe(e){if(typeof e!="number")throw new TypeError(`The "delay" argument must be of type number. Received ${typeof e}`);if(!Number.isFinite(e)||e<0)throw new RangeError(`The value of "delay" is out of range. It must be >= 0. Received ${String(e)}`);return Math.trunc(e)}typeof Do.abort!="function"&&Object.defineProperty(Do,"abort",{configurable:!0,writable:!0,value(e=void 0){return sQe(e)}});typeof Do.timeout!="function"&&Object.defineProperty(Do,"timeout",{configurable:!0,writable:!0,value(e){let t=oQe(e),r=new vu,n=setTimeout(()=>{r.abort(CY())},t);return typeof n?.unref=="function"&&n.unref(),r.signal.addEventListener("abort",()=>{clearTimeout(n)},{once:!0}),r.signal}});typeof Do.any!="function"&&Object.defineProperty(Do,"any",{configurable:!0,writable:!0,value(e){if(!e||typeof e[Symbol.iterator]!="function")throw new TypeError('The "signals" argument must be an iterable');let t=Array.from(e),r=new vu;if(t.length===0)return r.signal;let n=[],i=s=>{for(;n.length>0;){let[o,a]=n.pop();o.removeEventListener?.("abort",a)}r.abort(s.reason)};for(let s of t){if(!s||typeof s.aborted!="boolean"||typeof s.addEventListener!="function")throw new TypeError('The "signals" argument must contain AbortSignal instances');if(s.aborted)return i(s),r.signal;let o=()=>i(s);n.push([s,o]),s.addEventListener("abort",o,{once:!0})}return r.signal}});var aQe=class{constructor(e={}){this._sink=e}getWriter(){let e=this._sink;return{write(t){return Promise.resolve(typeof e.write=="function"?e.write(t):void 0)},close(){return Promise.resolve(typeof e.close=="function"?e.close():void 0)},releaseLock(){}}}},AQe=class{constructor(e={}){this._queue=[],this._pending=[],this._closed=!1,this._error=null;let t=()=>{for(;this._pending.length>0;){let n=this._pending.shift();if(this._error){n.reject(this._error);continue}if(this._queue.length>0){n.resolve({value:this._queue.shift(),done:!1});continue}if(this._closed){n.resolve({value:void 0,done:!0});continue}this._pending.unshift(n);break}},r={enqueue:n=>{this._closed||this._error||(this._queue.push(n),t())},close:()=>{this._closed||this._error||(this._closed=!0,t())},error:n=>{this._closed||this._error||(this._error=n instanceof Error?n:new Error(String(n)),t())}};typeof e.start=="function"&&Promise.resolve().then(()=>e.start(r)).catch(n=>r.error(n))}getReader(){return{read:()=>this._error?Promise.reject(this._error):this._queue.length>0?Promise.resolve({value:this._queue.shift(),done:!1}):this._closed?Promise.resolve({value:void 0,done:!0}):new Promise((e,t)=>{this._pending.push({resolve:e,reject:t})}),releaseLock(){}}}};function x2(e,t){return e.code=t,e}function fQe(e){return x2(new RangeError(`The "${e}" encoding is not supported`),"ERR_ENCODING_NOT_SUPPORTED")}function qi(e){return x2(new TypeError(`The encoded data was not valid for encoding ${e}`),"ERR_ENCODING_INVALID_ENCODED_DATA")}function uQe(){return x2(new TypeError('The "input" argument must be an instance of ArrayBuffer, SharedArrayBuffer, or ArrayBufferView.'),"ERR_INVALID_ARG_TYPE")}function cQe(e){return e.replace(/^[\t\n\f\r ]+|[\t\n\f\r ]+$/g,"")}function lQe(e){let t=cQe(e===void 0?"utf-8":String(e)).toLowerCase();switch(t){case"utf-8":case"utf8":case"unicode-1-1-utf-8":case"unicode11utf8":case"unicode20utf8":case"x-unicode20utf8":return"utf-8";case"utf-16":case"utf-16le":case"ucs-2":case"ucs2":case"csunicode":case"iso-10646-ucs-2":case"unicode":case"unicodefeff":return"utf-16le";case"utf-16be":case"unicodefffe":return"utf-16be";default:throw fQe(t)}}function hQe(e){if(e===void 0)return new Uint8Array(0);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);if(e instanceof ArrayBuffer)return new Uint8Array(e);if(typeof SharedArrayBuffer<"u"&&e instanceof SharedArrayBuffer)return new Uint8Array(e);throw uQe()}function qm(e,t){if(e<=127){t.push(e);return}if(e<=2047){t.push(192|e>>6,128|e&63);return}if(e<=65535){t.push(224|e>>12,128|e>>6&63,128|e&63);return}t.push(240|e>>18,128|e>>12&63,128|e>>6&63,128|e&63)}function eG(e=""){let t=String(e),r=[];for(let n=0;n=55296&&i<=56319){let s=n+1;if(s=56320&&o<=57343){let a=65536+(i-55296<<10)+(o-56320);qm(a,r),n=s;continue}}qm(65533,r);continue}if(i>=56320&&i<=57343){qm(65533,r);continue}qm(i,r)}return new Uint8Array(r)}function QY(e,t){if(t<=65535){e.push(String.fromCharCode(t));return}let r=t-65536;e.push(String.fromCharCode(55296+(r>>10)),String.fromCharCode(56320+(r&1023)))}function n1(e){return e>=128&&e<=191}function dQe(e,t,r,n){let i=[];for(let s=0;s=194&&o<=223)a=1,A=o&31;else if(o>=224&&o<=239)a=2,A=o&15;else if(o>=240&&o<=244)a=3,A=o&7;else{if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}if(s+a>=e.length){if(r)return{text:i.join(""),pending:Array.from(e.slice(s))};if(t)throw qi(n);i.push("\uFFFD");break}let f=e[s+1];if(!n1(f)){if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}if(o===224&&f<160||o===237&&f>159||o===240&&f<144||o===244&&f>143){if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}if(A=A<<6|f&63,a>=2){let l=e[s+2];if(!n1(l)){if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}A=A<<6|l&63}if(a===3){let l=e[s+3];if(!n1(l)){if(t)throw qi(n);i.push("\uFFFD"),s+=1;continue}A=A<<6|l&63}if(A>=55296&&A<=57343){if(t)throw qi(n);i.push("\uFFFD"),s+=a+1;continue}QY(i,A),s+=a+1}return{text:i.join(""),pending:[]}}function gQe(e,t,r,n,i){let s=[],o=t==="utf-16be"?"be":"le";!i&&t==="utf-16le"&&e.length>=2&&e[0]===254&&e[1]===255&&(o="be");for(let a=0;a=e.length){if(n)return{text:s.join(""),pending:Array.from(e.slice(a))};if(r)throw qi(t);s.push("\uFFFD");break}let A=e[a],f=e[a+1],l=o==="le"?A|f<<8:A<<8|f;if(a+=2,l>=55296&&l<=56319){if(a+1>=e.length){if(n)return{text:s.join(""),pending:Array.from(e.slice(a-2))};if(r)throw qi(t);s.push("\uFFFD");continue}let p=e[a],B=e[a+1],S=o==="le"?p|B<<8:p<<8|B;if(S>=56320&&S<=57343){let _=65536+(l-55296<<10)+(S-56320);QY(s,_),a+=2;continue}if(r)throw qi(t);s.push("\uFFFD");continue}if(l>=56320&&l<=57343){if(r)throw qi(t);s.push("\uFFFD");continue}s.push(String.fromCharCode(l))}return{text:s.join(""),pending:[]}}var pQe=class{encode(e=""){return eG(e)}encodeInto(e,t){let r=String(e),n=0,i=0;for(let s=0;s=55296&&o<=56319&&s+1=56320&&f<=57343&&(a=r.slice(s,s+2))}a===""&&(a=r[s]??"");let A=eG(a);if(i+A.length>t.length)break;t.set(A,i),i+=A.length,n+=a.length,a.length===2&&(s+=1)}return{read:n,written:i}}get encoding(){return"utf-8"}get[Symbol.toStringTag](){return"TextEncoder"}},EQe=class{constructor(e,t){y(this,"normalizedEncoding");y(this,"fatalFlag");y(this,"ignoreBOMFlag");y(this,"pendingBytes",[]);y(this,"bomSeen",!1);let r=t==null?{}:Object(t);this.normalizedEncoding=lQe(e),this.fatalFlag=!!r.fatal,this.ignoreBOMFlag=!!r.ignoreBOM}get encoding(){return this.normalizedEncoding}get fatal(){return this.fatalFlag}get ignoreBOM(){return this.ignoreBOMFlag}get[Symbol.toStringTag](){return"TextDecoder"}decode(e,t){let n=!!(t==null?{}:Object(t)).stream,i=hQe(e),s=new Uint8Array(this.pendingBytes.length+i.length);s.set(this.pendingBytes,0),s.set(i,this.pendingBytes.length);let o=this.normalizedEncoding==="utf-8"?dQe(s,this.fatalFlag,n,this.normalizedEncoding):gQe(s,this.normalizedEncoding,this.fatalFlag,n,this.bomSeen);this.pendingBytes=o.pending;let a=o.text;if(!this.bomSeen&&a.length>0&&(!this.ignoreBOMFlag&&a.charCodeAt(0)===65279&&(a=a.slice(1)),this.bomSeen=!0),!n&&this.pendingBytes.length>0){let A=this.pendingBytes;if(this.pendingBytes=[],this.fatalFlag)throw qi(this.normalizedEncoding);return a+"\uFFFD".repeat(Math.ceil(A.length/2))}return a}},U2=pQe,Ru=EQe;function ln(e,t){globalThis[e]=t}typeof globalThis.global>"u"&&ln("global",globalThis);if(typeof globalThis.RegExp=="function"&&!("__secureExecRgiEmojiCompat"in globalThis.RegExp)){let e=globalThis.RegExp,t="^\\p{RGI_Emoji}$",r="[\\u{00A9}\\u{00AE}\\u{203C}\\u{2049}\\u{2122}\\u{2139}\\u{2194}-\\u{21AA}\\u{231A}-\\u{23FF}\\u{24C2}\\u{25AA}-\\u{27BF}\\u{2934}-\\u{2935}\\u{2B05}-\\u{2B55}\\u{3030}\\u{303D}\\u{3297}\\u{3299}\\u{1F000}-\\u{1FAFF}]",n="[#*0-9]\\uFE0F?\\u20E3",i="^(?:"+n+"|\\p{Regional_Indicator}{2}|"+r+"(?:\\uFE0F|\\u200D(?:"+n+"|"+r+")|[\\u{1F3FB}-\\u{1F3FF}])*)$";try{new e(t,"v")}catch(s){if(String(s?.message??s).includes("RGI_Emoji")){let o=function(A,f){let l=A instanceof e&&f===void 0?A.source:String(A),p=f===void 0?A instanceof e?A.flags:"":String(f);try{return new e(A,f)}catch(B){if(l===t&&p==="v")return new e(i,"u");throw B}};Object.setPrototypeOf(o,e),o.prototype=e.prototype,Object.defineProperty(o.prototype,"constructor",{value:o,writable:!0,configurable:!0}),ln("RegExp",Object.assign(o,{__secureExecRgiEmojiCompat:!0}))}}}ln("TextEncoder",U2);ln("TextDecoder",Ru);ln("Event",Ul);ln("CustomEvent",F2);ln("EventTarget",jB);ln("AbortSignal",Do);ln("AbortController",vu);ln("structuredClone",$Ce);globalThis.WebAssembly&&typeof globalThis.WebAssembly.instantiateStreaming!="function"&&(globalThis.WebAssembly.instantiateStreaming=async function(t,r){let n=await t;if(n==null||typeof n.arrayBuffer!="function")throw new TypeError("WebAssembly.instantiateStreaming requires a Response or promise for one");let i=new Uint8Array(await n.arrayBuffer());return globalThis.WebAssembly.instantiate(i,r)});ln("ReadableStream",typeof Wr.ReadableStream=="function"?Wr.ReadableStream:AQe);ln("WritableStream",typeof Wr.WritableStream=="function"?Wr.WritableStream:aQe);typeof Wr.TransformStream=="function"&&ln("TransformStream",Wr.TransformStream);typeof Jp=="function"&&ln("TextEncoderStream",Jp);typeof jp=="function"&&ln("TextDecoderStream",jp);var lu=U1.default?.webidl??U1.default;lu?.is&&(lu.is.ReadableStream=e=>e!=null&&(e instanceof globalThis.ReadableStream||typeof e.getReader=="function"),lu.is.AbortSignal=e=>e!=null&&(e instanceof globalThis.AbortSignal||typeof e.aborted=="boolean"&&typeof e.addEventListener=="function"));lu?.converters?.AbortSignal&&(lu.converters.AbortSignal=(e,...t)=>e!=null&&(e instanceof globalThis.AbortSignal||typeof e.aborted=="boolean"&&typeof e.addEventListener=="function")?e:lu.interfaceConverter(lu.is.AbortSignal,"AbortSignal")(e,...t));var wY=[{name:"_processConfig",c:"h"},{name:"__secureExecHrNowUs",c:"h"},{name:"process.cpuUsage",c:"h"},{name:"process.memoryUsage",c:"h"},{name:"process.resourceUsage",c:"h"},{name:"process.versions",c:"h"},{name:"_processKill",c:"h"},{name:"_processSignalState",c:"h"},{name:"_osConfig",c:"h"},{name:"bridge",c:"h"},{name:"_registerHandle",c:"h"},{name:"_unregisterHandle",c:"h"},{name:"_waitForActiveHandles",c:"h"},{name:"_getActiveHandles",c:"h"},{name:"_childProcessDispatch",c:"h"},{name:"_childProcessModule",c:"h"},{name:"_osModule",c:"h"},{name:"_moduleModule",c:"h"},{name:"_httpModule",c:"h"},{name:"_httpsModule",c:"h"},{name:"_http2Module",c:"h"},{name:"_dnsModule",c:"h"},{name:"_dgramModule",c:"h"},{name:"_netModule",c:"h"},{name:"_tlsModule",c:"h"},{name:"_vmCreateContext",c:"h"},{name:"_vmRunInContext",c:"h"},{name:"_vmRunInThisContext",c:"h"},{name:"_netSocketDispatch",c:"h"},{name:"_dgramSocketDispatch",c:"h"},{name:"_http2RetainDispatch",c:"h"},{name:"_httpServerDispatch",c:"h"},{name:"_httpServerUpgradeDispatch",c:"h"},{name:"_httpServerConnectDispatch",c:"h"},{name:"_http2Dispatch",c:"h"},{name:"_timerDispatch",c:"h"},{name:"_drainImmediates",c:"h"},{name:"_getPendingImmediateCount",c:"h"},{name:"_upgradeSocketData",c:"h"},{name:"_upgradeSocketEnd",c:"h"},{name:"ProcessExitError",c:"h"},{name:"_log",c:"h"},{name:"_error",c:"h"},{name:"_pythonRpc",c:"h"},{name:"_pythonStdinRead",c:"h"},{name:"_loadPolyfill",c:"h"},{name:"_resolveModule",c:"h"},{name:"_loadFile",c:"h"},{name:"_resolveModuleSync",c:"h"},{name:"_loadFileSync",c:"h"},{name:"_moduleFormat",c:"h"},{name:"_scheduleTimer",c:"h"},{name:"_cryptoRandomFill",c:"h"},{name:"_cryptoRandomUUID",c:"h"},{name:"_cryptoHashDigest",c:"h"},{name:"_cryptoHmacDigest",c:"h"},{name:"_cryptoPbkdf2",c:"h"},{name:"_cryptoScrypt",c:"h"},{name:"_cryptoCipheriv",c:"h"},{name:"_cryptoDecipheriv",c:"h"},{name:"_cryptoCipherivCreate",c:"h"},{name:"_cryptoCipherivUpdate",c:"h"},{name:"_cryptoCipherivFinal",c:"h"},{name:"_cryptoSign",c:"h"},{name:"_cryptoVerify",c:"h"},{name:"_cryptoAsymmetricOp",c:"h"},{name:"_cryptoCreateKeyObject",c:"h"},{name:"_cryptoGenerateKeyPairSync",c:"h"},{name:"_cryptoGenerateKeySync",c:"h"},{name:"_cryptoGeneratePrimeSync",c:"h"},{name:"_cryptoDiffieHellman",c:"h"},{name:"_cryptoDiffieHellmanGroup",c:"h"},{name:"_cryptoDiffieHellmanSessionCreate",c:"h"},{name:"_cryptoDiffieHellmanSessionCall",c:"h"},{name:"_cryptoDiffieHellmanSessionDestroy",c:"h"},{name:"_cryptoSubtle",c:"h"},{name:"_benchNoop",c:"h"},{name:"_fsReadFile",c:"h"},{name:"_fsReadFileAsync",c:"h"},{name:"_fsWriteFile",c:"h"},{name:"_fsWriteFileAsync",c:"h"},{name:"_fsReadFileBinary",c:"h"},{name:"_fsReadFileBinaryAsync",c:"h"},{name:"_fsWriteFileBinary",c:"h"},{name:"_fsWriteFileBinaryRaw",c:"h"},{name:"_fsWriteFileBinaryAsync",c:"h"},{name:"_fsReadDir",c:"h"},{name:"_fsReadDirAsync",c:"h"},{name:"_fsMkdir",c:"h"},{name:"_fsMkdirAsync",c:"h"},{name:"_fsRmdir",c:"h"},{name:"_fsRmdirAsync",c:"h"},{name:"_fsExists",c:"h"},{name:"_fsAccessAsync",c:"h"},{name:"_fsStat",c:"h"},{name:"_fsStatAsync",c:"h"},{name:"_fsUnlink",c:"h"},{name:"_fsUnlinkAsync",c:"h"},{name:"_fsRename",c:"h"},{name:"_fsRenameAsync",c:"h"},{name:"_fsChmod",c:"h"},{name:"_fsChmodAsync",c:"h"},{name:"_fsChown",c:"h"},{name:"_fsChownAsync",c:"h"},{name:"_fsLink",c:"h"},{name:"_fsLinkAsync",c:"h"},{name:"_fsSymlink",c:"h"},{name:"_fsSymlinkAsync",c:"h"},{name:"_fsReadlink",c:"h"},{name:"_fsReadlinkAsync",c:"h"},{name:"_fsLstat",c:"h"},{name:"_fsLstatAsync",c:"h"},{name:"_fsTruncate",c:"h"},{name:"_fsTruncateAsync",c:"h"},{name:"_fsUtimes",c:"h"},{name:"_fsLutimes",c:"h"},{name:"_fsUtimesAsync",c:"h"},{name:"_fsLutimesAsync",c:"h"},{name:"fs.futimesSync",c:"h"},{name:"fs.openSync",c:"h"},{name:"fs.closeSync",c:"h"},{name:"fs.readSync",c:"h"},{name:"_fsReadRaw",c:"h"},{name:"fs.writeSync",c:"h"},{name:"_fsWriteRaw",c:"h"},{name:"_fsWritevRaw",c:"h"},{name:"fs.fstatSync",c:"h"},{name:"_fs",c:"h"},{name:"_childProcessSpawnStart",c:"h"},{name:"_childProcessPoll",c:"h"},{name:"_childProcessStdinWrite",c:"h"},{name:"_childProcessStdinClose",c:"h"},{name:"_childProcessKill",c:"h"},{name:"_childProcessSpawnSync",c:"h"},{name:"_benchNetTcpMetricsResetRaw",c:"h"},{name:"_benchNetTcpMetricsSnapshotRaw",c:"h"},{name:"_networkDnsLookupRaw",c:"h"},{name:"_networkDnsLookupSyncRaw",c:"h"},{name:"_networkDnsResolveRaw",c:"h"},{name:"_networkHttpServerListenRaw",c:"h"},{name:"_networkHttpServerCloseRaw",c:"h"},{name:"_networkHttpServerRespondRaw",c:"h"},{name:"_networkHttpServerRequestRaw",c:"h"},{name:"_networkHttpServerWaitRaw",c:"h"},{name:"_networkHttp2ServerListenRaw",c:"h"},{name:"_networkHttp2ServerCloseRaw",c:"h"},{name:"_networkHttp2ServerWaitRaw",c:"h"},{name:"_networkHttp2SessionConnectRaw",c:"h"},{name:"_networkHttp2SessionRequestRaw",c:"h"},{name:"_networkHttp2SessionSettingsRaw",c:"h"},{name:"_networkHttp2SessionSetLocalWindowSizeRaw",c:"h"},{name:"_networkHttp2SessionGoawayRaw",c:"h"},{name:"_networkHttp2SessionCloseRaw",c:"h"},{name:"_networkHttp2SessionDestroyRaw",c:"h"},{name:"_networkHttp2SessionWaitRaw",c:"h"},{name:"_networkHttp2ServerPollRaw",c:"h"},{name:"_networkHttp2SessionPollRaw",c:"h"},{name:"_networkHttp2StreamRespondRaw",c:"h"},{name:"_networkHttp2StreamPushStreamRaw",c:"h"},{name:"_networkHttp2StreamWriteRaw",c:"h"},{name:"_networkHttp2StreamEndRaw",c:"h"},{name:"_networkHttp2StreamCloseRaw",c:"h"},{name:"_networkHttp2StreamPauseRaw",c:"h"},{name:"_networkHttp2StreamResumeRaw",c:"h"},{name:"_networkHttp2StreamRespondWithFileRaw",c:"h"},{name:"_networkHttp2ServerRespondRaw",c:"h"},{name:"_upgradeSocketWriteRaw",c:"h"},{name:"_upgradeSocketEndRaw",c:"h"},{name:"_upgradeSocketDestroyRaw",c:"h"},{name:"_netSocketConnectRaw",c:"h"},{name:"_netSocketPollRaw",c:"h"},{name:"_netSocketWaitConnectRaw",c:"h"},{name:"_netSocketReadRaw",c:"h"},{name:"_netSocketSetNoDelayRaw",c:"h"},{name:"_netSocketSetKeepAliveRaw",c:"h"},{name:"_netSocketWriteRaw",c:"h"},{name:"_netSocketEndRaw",c:"h"},{name:"_netSocketDestroyRaw",c:"h"},{name:"_netSocketUpgradeTlsRaw",c:"h"},{name:"_netSocketGetTlsClientHelloRaw",c:"h"},{name:"_netSocketTlsQueryRaw",c:"h"},{name:"_tlsGetCiphersRaw",c:"h"},{name:"_netReserveTcpPortRaw",c:"h"},{name:"_netReleaseTcpPortRaw",c:"h"},{name:"_netServerListenRaw",c:"h"},{name:"_netServerAcceptRaw",c:"h"},{name:"_netServerCloseRaw",c:"h"},{name:"_dgramSocketCreateRaw",c:"h"},{name:"_dgramSocketBindRaw",c:"h"},{name:"_dgramSocketRecvRaw",c:"h"},{name:"_dgramSocketSendRaw",c:"h"},{name:"_dgramSocketCloseRaw",c:"h"},{name:"_dgramSocketAddressRaw",c:"h"},{name:"_dgramSocketSetBufferSizeRaw",c:"h"},{name:"_dgramSocketGetBufferSizeRaw",c:"h"},{name:"_sqliteConstantsRaw",c:"h"},{name:"_sqliteDatabaseOpenRaw",c:"h"},{name:"_sqliteDatabaseCloseRaw",c:"h"},{name:"_sqliteDatabaseExecRaw",c:"h"},{name:"_sqliteDatabaseQueryRaw",c:"h"},{name:"_sqliteDatabasePrepareRaw",c:"h"},{name:"_sqliteDatabaseLocationRaw",c:"h"},{name:"_sqliteDatabaseCheckpointRaw",c:"h"},{name:"_sqliteStatementRunRaw",c:"h"},{name:"_sqliteStatementGetRaw",c:"h"},{name:"_sqliteStatementAllRaw",c:"h"},{name:"_sqliteStatementColumnsRaw",c:"h"},{name:"_sqliteStatementSetReturnArraysRaw",c:"h"},{name:"_sqliteStatementSetReadBigIntsRaw",c:"h"},{name:"_sqliteStatementSetAllowBareNamedParametersRaw",c:"h"},{name:"_sqliteStatementSetAllowUnknownNamedParametersRaw",c:"h"},{name:"_sqliteStatementFinalizeRaw",c:"h"},{name:"_batchResolveModules",c:"h"},{name:"_kernelPollRaw",c:"h"},{name:"_kernelIsattyRaw",c:"h"},{name:"_kernelTtySizeRaw",c:"h"},{name:"_kernelStdioWriteRaw",c:"h"},{name:"_kernelStdinReadRaw",c:"h"},{name:"_kernelStdinRead",c:"h"},{name:"_ptySetRawMode",c:"h"},{name:"require",c:"h"},{name:"_requireFrom",c:"h"},{name:"_dynamicImport",c:"h"},{name:"__dynamicImport",c:"h"},{name:"_moduleCache",c:"h"},{name:"_pendingModules",c:"m"},{name:"_currentModule",c:"m"},{name:"_stdinData",c:"m"},{name:"_stdinPosition",c:"m"},{name:"_stdinEnded",c:"m"},{name:"_stdinFlowMode",c:"m"},{name:"module",c:"m"},{name:"exports",c:"m"},{name:"__filename",c:"m"},{name:"__dirname",c:"m"},{name:"fetch",c:"h"},{name:"Headers",c:"h"},{name:"Request",c:"h"},{name:"Response",c:"h"},{name:"DOMException",c:"h"},{name:"__importMetaResolve",c:"h"},{name:"Blob",c:"h"},{name:"File",c:"h"},{name:"FormData",c:"h"}],gke=wY.filter(e=>e.c==="h").map(e=>e.name),pke=wY.filter(e=>e.c==="m").map(e=>e.name);function SY(e,t,r,n={}){let i=n.mutable===!0,s=n.enumerable!==!1;Object.defineProperty(e,t,{value:r,writable:i,configurable:!0,enumerable:s})}function Ge(e,t){SY(globalThis,e,t)}function Du(e,t){SY(globalThis,e,t,{mutable:!0})}function yQe(e){return JSON.stringify(e,(t,r)=>r===void 0?{__secureExecDispatchType:"undefined"}:r)}function mQe(e,t){return`__bd:${e}:${yQe(t)}`}function BQe(e){if(e===null)return;let t=JSON.parse(e);if(t.__bd_error){let r=new Error(t.__bd_error.message);throw r.name=t.__bd_error.name??"Error",t.__bd_error.code!==void 0&&(r.code=t.__bd_error.code),t.__bd_error.stack&&(r.stack=t.__bd_error.stack),r}return t.__bd_result}function IQe(){if(!_loadPolyfill)throw new Error("_loadPolyfill is not available in sandbox");return _loadPolyfill}function s0(e,...t){let r=IQe();return BQe(r.applySyncPromise(void 0,[mQe(e,t)]))}var bQe=Object.create,L2=Object.defineProperty,CQe=Object.getOwnPropertyDescriptor,_Y=Object.getOwnPropertyNames,QQe=Object.getPrototypeOf,wQe=Object.prototype.hasOwnProperty,P2=(e,t)=>function(){return t||(0,e[_Y(e)[0]])((t={exports:{}}).exports,t),t.exports},O2=(e,t)=>{for(var r in t)L2(e,r,{get:t[r],enumerable:!0})},SQe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of _Y(t))!wQe.call(e,i)&&i!==r&&L2(e,i,{get:()=>t[i],enumerable:!(n=CQe(t,i))||n.enumerable});return e},H2=(e,t,r)=>(r=e!=null?bQe(QQe(e)):{},SQe(t||!e||!e.__esModule?L2(r,"default",{value:e,enumerable:!0}):r,e));var vY=P2({"../../../tmp/buffer-build/node_modules/base64-js/index.js"(e){"use strict";e.byteLength=A,e.toByteArray=l,e.fromByteArray=S;var t=[],r=[],n=typeof Uint8Array<"u"?Uint8Array:Array,i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(s=0,o=i.length;s0)throw new Error("Invalid string. Length must be a multiple of 4");var P=_.indexOf("=");P===-1&&(P=N);var U=P===N?0:4-P%4;return[P,U]}function A(_){var N=a(_),P=N[0],U=N[1];return(P+U)*3/4-U}function f(_,N,P){return(N+P)*3/4-P}function l(_){var N,P=a(_),U=P[0],G=P[1],Y=new n(f(_,U,G)),Z=0,ee=G>0?U-4:U,j;for(j=0;j>16&255,Y[Z++]=N>>8&255,Y[Z++]=N&255;return G===2&&(N=r[_.charCodeAt(j)]<<2|r[_.charCodeAt(j+1)]>>4,Y[Z++]=N&255),G===1&&(N=r[_.charCodeAt(j)]<<10|r[_.charCodeAt(j+1)]<<4|r[_.charCodeAt(j+2)]>>2,Y[Z++]=N>>8&255,Y[Z++]=N&255),Y}function p(_){return t[_>>18&63]+t[_>>12&63]+t[_>>6&63]+t[_&63]}function B(_,N,P){for(var U,G=[],Y=N;Yee?ee:Z+Y));return U===1?(N=_[P-1],G.push(t[N>>2]+t[N<<4&63]+"==")):U===2&&(N=(_[P-2]<<8)+_[P-1],G.push(t[N>>10]+t[N>>4&63]+t[N<<2&63]+"=")),G.join("")}}}),_Qe=P2({"../../../tmp/buffer-build/node_modules/ieee754/index.js"(e){e.read=function(t,r,n,i,s){var o,a,A=s*8-i-1,f=(1<>1,p=-7,B=n?s-1:0,S=n?-1:1,_=t[r+B];for(B+=S,o=_&(1<<-p)-1,_>>=-p,p+=A;p>0;o=o*256+t[r+B],B+=S,p-=8);for(a=o&(1<<-p)-1,o>>=-p,p+=i;p>0;a=a*256+t[r+B],B+=S,p-=8);if(o===0)o=1-l;else{if(o===f)return a?NaN:(_?-1:1)*(1/0);a=a+Math.pow(2,i),o=o-l}return(_?-1:1)*a*Math.pow(2,o-i)},e.write=function(t,r,n,i,s,o){var a,A,f,l=o*8-s-1,p=(1<>1,S=s===23?Math.pow(2,-24)-Math.pow(2,-77):0,_=i?0:o-1,N=i?1:-1,P=r<0||r===0&&1/r<0?1:0;for(r=Math.abs(r),isNaN(r)||r===1/0?(A=isNaN(r)?1:0,a=p):(a=Math.floor(Math.log(r)/Math.LN2),r*(f=Math.pow(2,-a))<1&&(a--,f*=2),a+B>=1?r+=S/f:r+=S*Math.pow(2,1-B),r*f>=2&&(a++,f/=2),a+B>=p?(A=0,a=p):a+B>=1?(A=(r*f-1)*Math.pow(2,s),a=a+B):(A=r*Math.pow(2,B-1)*Math.pow(2,s),a=0));s>=8;t[n+_]=A&255,_+=N,A/=256,s-=8);for(a=a<0;t[n+_]=a&255,_+=N,a/=256,l-=8);t[n+_-N]|=P*128}}}),q2=P2({"../../../tmp/buffer-build/node_modules/buffer/index.js"(e){"use strict";var t=vY(),r=_Qe(),n=typeof Symbol=="function"&&typeof Symbol.for=="function"?Symbol.for("nodejs.util.inspect.custom"):null;e.Buffer=a,e.SlowBuffer=G,e.INSPECT_MAX_BYTES=50;var i=2147483647;e.kMaxLength=i,a.TYPED_ARRAY_SUPPORT=s(),!a.TYPED_ARRAY_SUPPORT&&typeof console<"u"&&typeof console.error=="function"&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function s(){try{let F=new Uint8Array(1),m={foo:function(){return 42}};return Object.setPrototypeOf(m,Uint8Array.prototype),Object.setPrototypeOf(F,m),F.foo()===42}catch{return!1}}Object.defineProperty(a.prototype,"parent",{enumerable:!0,get:function(){if(a.isBuffer(this))return this.buffer}}),Object.defineProperty(a.prototype,"offset",{enumerable:!0,get:function(){if(a.isBuffer(this))return this.byteOffset}});function o(F){if(F>i)throw new RangeError('The value "'+F+'" is invalid for option "size"');let m=new Uint8Array(F);return Object.setPrototypeOf(m,a.prototype),m}function a(F,m,Q){if(typeof F=="number"){if(typeof m=="string")throw new TypeError('The "string" argument must be of type string. Received type number');return p(F)}return A(F,m,Q)}a.poolSize=8192;function A(F,m,Q){if(typeof F=="string")return B(F,m);if(ArrayBuffer.isView(F))return _(F);if(F==null)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof F);if(Re(F,ArrayBuffer)||F&&Re(F.buffer,ArrayBuffer)||typeof SharedArrayBuffer<"u"&&(Re(F,SharedArrayBuffer)||F&&Re(F.buffer,SharedArrayBuffer)))return N(F,m,Q);if(typeof F=="number")throw new TypeError('The "value" argument must not be of type number. Received type number');let L=F.valueOf&&F.valueOf();if(L!=null&&L!==F)return a.from(L,m,Q);let W=P(F);if(W)return W;if(typeof Symbol<"u"&&Symbol.toPrimitive!=null&&typeof F[Symbol.toPrimitive]=="function")return a.from(F[Symbol.toPrimitive]("string"),m,Q);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof F)}a.from=function(F,m,Q){return A(F,m,Q)},Object.setPrototypeOf(a.prototype,Uint8Array.prototype),Object.setPrototypeOf(a,Uint8Array);function f(F){if(typeof F!="number")throw new TypeError('"size" argument must be of type number');if(F<0)throw new RangeError('The value "'+F+'" is invalid for option "size"')}function l(F,m,Q){return f(F),F<=0?o(F):m!==void 0?typeof Q=="string"?o(F).fill(m,Q):o(F).fill(m):o(F)}a.alloc=function(F,m,Q){return l(F,m,Q)};function p(F){return f(F),o(F<0?0:U(F)|0)}a.allocUnsafe=function(F){return p(F)},a.allocUnsafeSlow=function(F){return p(F)};function B(F,m){if((typeof m!="string"||m==="")&&(m="utf8"),!a.isEncoding(m))throw new TypeError("Unknown encoding: "+m);let Q=Y(F,m)|0,L=o(Q),W=L.write(F,m);return W!==Q&&(L=L.slice(0,W)),L}function S(F){let m=F.length<0?0:U(F.length)|0,Q=o(m);for(let L=0;L=i)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+i.toString(16)+" bytes");return F|0}function G(F){return+F!=F&&(F=0),a.alloc(+F)}a.isBuffer=function(m){return m!=null&&m._isBuffer===!0&&m!==a.prototype},a.compare=function(m,Q){if(Re(m,Uint8Array)&&(m=a.from(m,m.offset,m.byteLength)),Re(Q,Uint8Array)&&(Q=a.from(Q,Q.offset,Q.byteLength)),!a.isBuffer(m)||!a.isBuffer(Q))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(m===Q)return 0;let L=m.length,W=Q.length;for(let z=0,ae=Math.min(L,W);z=W.length)break;let le=W.length-z,ye=ae.length>le?le:ae.length;Uint8Array.prototype.set.call(W,ae.subarray(0,ye),z),z+=ye}return W};function Y(F,m){if(a.isBuffer(F))return F.length;if(ArrayBuffer.isView(F)||Re(F,ArrayBuffer))return F.byteLength;if(typeof F!="string")throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof F);let Q=F.length,L=arguments.length>2&&arguments[2]===!0;if(!L&&Q===0)return 0;let W=!1;for(;;)switch(m){case"ascii":case"latin1":case"binary":return Q;case"utf8":case"utf-8":return xe(F).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Q*2;case"hex":return Q>>>1;case"base64":case"base64url":return De(F).length;default:if(W)return L?-1:xe(F).length;m=(""+m).toLowerCase(),W=!0}}a.byteLength=Y;function Z(F,m,Q){let L=!1;if((m===void 0||m<0)&&(m=0),m>this.length||((Q===void 0||Q>this.length)&&(Q=this.length),Q<=0)||(Q>>>=0,m>>>=0,Q<=m))return"";for(F||(F="utf8");;)switch(F){case"hex":return D(this,m,Q);case"utf8":case"utf-8":return g(this,m,Q);case"ascii":return C(this,m,Q);case"latin1":case"binary":return h(this,m,Q);case"base64":return b(this,m,Q);case"base64url":return c(this,m,Q);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return M(this,m,Q);default:if(L)throw new TypeError("Unknown encoding: "+F);F=(F+"").toLowerCase(),L=!0}}a.prototype._isBuffer=!0;function ee(F,m,Q){let L=F[m];F[m]=F[Q],F[Q]=L}a.prototype.swap16=function(){let m=this.length;if(m%2!==0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let Q=0;QQ&&(m+=" ... "),""},n&&(a.prototype[n]=a.prototype.inspect),a.prototype.compare=function(m,Q,L,W,z){if(Re(m,Uint8Array)&&(m=a.from(m,m.offset,m.byteLength)),!a.isBuffer(m))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof m);if(Q===void 0&&(Q=0),L===void 0&&(L=m?m.length:0),W===void 0&&(W=0),z===void 0&&(z=this.length),Q<0||L>m.length||W<0||z>this.length)throw new RangeError("out of range index");if(W>=z&&Q>=L)return 0;if(W>=z)return-1;if(Q>=L)return 1;if(Q>>>=0,L>>>=0,W>>>=0,z>>>=0,this===m)return 0;let ae=z-W,le=L-Q,ye=Math.min(ae,le),Ct=this.slice(W,z),Ee=m.slice(Q,L);for(let ge=0;ge2147483647?Q=2147483647:Q<-2147483648&&(Q=-2147483648),Q=+Q,He(Q)&&(Q=W?0:F.length-1),Q<0&&(Q=F.length+Q),Q>=F.length){if(W)return-1;Q=F.length-1}else if(Q<0)if(W)Q=0;else return-1;if(typeof m=="string"&&(m=a.from(m,L)),a.isBuffer(m))return m.length===0?-1:se(F,m,Q,L,W);if(typeof m=="number")return m=m&255,typeof Uint8Array.prototype.indexOf=="function"?W?Uint8Array.prototype.indexOf.call(F,m,Q):Uint8Array.prototype.lastIndexOf.call(F,m,Q):se(F,[m],Q,L,W);throw new TypeError("val must be string, number or Buffer")}function se(F,m,Q,L,W){let z=1,ae=F.length,le=m.length;if(L!==void 0&&(L=String(L).toLowerCase(),L==="ucs2"||L==="ucs-2"||L==="utf16le"||L==="utf-16le")){if(F.length<2||m.length<2)return-1;z=2,ae/=2,le/=2,Q/=2}function ye(Ee,ge){return z===1?Ee[ge]:Ee.readUInt16BE(ge*z)}let Ct;if(W){let Ee=-1;for(Ct=Q;Ctae&&(Q=ae-le),Ct=Q;Ct>=0;Ct--){let Ee=!0;for(let ge=0;geW&&(L=W)):L=W;let z=m.length;L>z/2&&(L=z/2);let ae;for(ae=0;ae>>0,isFinite(L)?(L=L>>>0,W===void 0&&(W="utf8")):(W=L,L=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");let z=this.length-Q;if((L===void 0||L>z)&&(L=z),m.length>0&&(L<0||Q<0)||Q>this.length)throw new RangeError("Attempt to write outside buffer bounds");W||(W="utf8");let ae=!1;for(;;)switch(W){case"hex":return ie(this,m,Q,L);case"utf8":case"utf-8":return ce(this,m,Q,L);case"ascii":case"latin1":case"binary":return H(this,m,Q,L);case"base64":case"base64url":return E(this,m,Q,L);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return v(this,m,Q,L);default:if(ae)throw new TypeError("Unknown encoding: "+W);W=(""+W).toLowerCase(),ae=!0}},a.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function b(F,m,Q){return m===0&&Q===F.length?t.fromByteArray(F):t.fromByteArray(F.slice(m,Q))}function c(F,m,Q){return b(F,m,Q).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function g(F,m,Q){Q=Math.min(F.length,Q);let L=[],W=m;for(;W239?4:z>223?3:z>191?2:1;if(W+le<=Q){let ye,Ct,Ee,ge;switch(le){case 1:z<128&&(ae=z);break;case 2:ye=F[W+1],(ye&192)===128&&(ge=(z&31)<<6|ye&63,ge>127&&(ae=ge));break;case 3:ye=F[W+1],Ct=F[W+2],(ye&192)===128&&(Ct&192)===128&&(ge=(z&15)<<12|(ye&63)<<6|Ct&63,ge>2047&&(ge<55296||ge>57343)&&(ae=ge));break;case 4:ye=F[W+1],Ct=F[W+2],Ee=F[W+3],(ye&192)===128&&(Ct&192)===128&&(Ee&192)===128&&(ge=(z&15)<<18|(ye&63)<<12|(Ct&63)<<6|Ee&63,ge>65535&&ge<1114112&&(ae=ge))}}ae===null?(ae=65533,le=1):ae>65535&&(ae-=65536,L.push(ae>>>10&1023|55296),ae=56320|ae&1023),L.push(ae),W+=le}return R(L)}var w=4096;function R(F){let m=F.length;if(m<=w)return String.fromCharCode.apply(String,F);let Q="",L=0;for(;LL)&&(Q=L);let W="";for(let z=m;zL&&(m=L),Q<0?(Q+=L,Q<0&&(Q=0)):Q>L&&(Q=L),QQ)throw new RangeError("Trying to access beyond buffer length")}a.prototype.readUintLE=a.prototype.readUIntLE=function(m,Q,L){m=m>>>0,Q=Q>>>0,L||I(m,Q,this.length);let W=this[m],z=1,ae=0;for(;++ae>>0,Q=Q>>>0,L||I(m,Q,this.length);let W=this[m+--Q],z=1;for(;Q>0&&(z*=256);)W+=this[m+--Q]*z;return W},a.prototype.readUint8=a.prototype.readUInt8=function(m,Q){return m=m>>>0,Q||I(m,1,this.length),this[m]},a.prototype.readUint16LE=a.prototype.readUInt16LE=function(m,Q){return m=m>>>0,Q||I(m,2,this.length),this[m]|this[m+1]<<8},a.prototype.readUint16BE=a.prototype.readUInt16BE=function(m,Q){return m=m>>>0,Q||I(m,2,this.length),this[m]<<8|this[m+1]},a.prototype.readUint32LE=a.prototype.readUInt32LE=function(m,Q){return m=m>>>0,Q||I(m,4,this.length),(this[m]|this[m+1]<<8|this[m+2]<<16)+this[m+3]*16777216},a.prototype.readUint32BE=a.prototype.readUInt32BE=function(m,Q){return m=m>>>0,Q||I(m,4,this.length),this[m]*16777216+(this[m+1]<<16|this[m+2]<<8|this[m+3])},a.prototype.readBigUInt64LE=Ne(function(m){m=m>>>0,we(m,"offset");let Q=this[m],L=this[m+7];(Q===void 0||L===void 0)&&ve(m,this.length-8);let W=Q+this[++m]*2**8+this[++m]*2**16+this[++m]*2**24,z=this[++m]+this[++m]*2**8+this[++m]*2**16+L*2**24;return BigInt(W)+(BigInt(z)<>>0,we(m,"offset");let Q=this[m],L=this[m+7];(Q===void 0||L===void 0)&&ve(m,this.length-8);let W=Q*2**24+this[++m]*2**16+this[++m]*2**8+this[++m],z=this[++m]*2**24+this[++m]*2**16+this[++m]*2**8+L;return(BigInt(W)<>>0,Q=Q>>>0,L||I(m,Q,this.length);let W=this[m],z=1,ae=0;for(;++ae=z&&(W-=Math.pow(2,8*Q)),W},a.prototype.readIntBE=function(m,Q,L){m=m>>>0,Q=Q>>>0,L||I(m,Q,this.length);let W=Q,z=1,ae=this[m+--W];for(;W>0&&(z*=256);)ae+=this[m+--W]*z;return z*=128,ae>=z&&(ae-=Math.pow(2,8*Q)),ae},a.prototype.readInt8=function(m,Q){return m=m>>>0,Q||I(m,1,this.length),this[m]&128?(255-this[m]+1)*-1:this[m]},a.prototype.readInt16LE=function(m,Q){m=m>>>0,Q||I(m,2,this.length);let L=this[m]|this[m+1]<<8;return L&32768?L|4294901760:L},a.prototype.readInt16BE=function(m,Q){m=m>>>0,Q||I(m,2,this.length);let L=this[m+1]|this[m]<<8;return L&32768?L|4294901760:L},a.prototype.readInt32LE=function(m,Q){return m=m>>>0,Q||I(m,4,this.length),this[m]|this[m+1]<<8|this[m+2]<<16|this[m+3]<<24},a.prototype.readInt32BE=function(m,Q){return m=m>>>0,Q||I(m,4,this.length),this[m]<<24|this[m+1]<<16|this[m+2]<<8|this[m+3]},a.prototype.readBigInt64LE=Ne(function(m){m=m>>>0,we(m,"offset");let Q=this[m],L=this[m+7];(Q===void 0||L===void 0)&&ve(m,this.length-8);let W=this[m+4]+this[m+5]*2**8+this[m+6]*2**16+(L<<24);return(BigInt(W)<>>0,we(m,"offset");let Q=this[m],L=this[m+7];(Q===void 0||L===void 0)&&ve(m,this.length-8);let W=(Q<<24)+this[++m]*2**16+this[++m]*2**8+this[++m];return(BigInt(W)<>>0,Q||I(m,4,this.length),r.read(this,m,!0,23,4)},a.prototype.readFloatBE=function(m,Q){return m=m>>>0,Q||I(m,4,this.length),r.read(this,m,!1,23,4)},a.prototype.readDoubleLE=function(m,Q){return m=m>>>0,Q||I(m,8,this.length),r.read(this,m,!0,52,8)},a.prototype.readDoubleBE=function(m,Q){return m=m>>>0,Q||I(m,8,this.length),r.read(this,m,!1,52,8)};function k(F,m,Q,L,W,z){if(!a.isBuffer(F))throw new TypeError('"buffer" argument must be a Buffer instance');if(m>W||mF.length)throw new RangeError("Index out of range")}a.prototype.writeUintLE=a.prototype.writeUIntLE=function(m,Q,L,W){if(m=+m,Q=Q>>>0,L=L>>>0,!W){let le=Math.pow(2,8*L)-1;k(this,m,Q,L,le,0)}let z=1,ae=0;for(this[Q]=m&255;++ae>>0,L=L>>>0,!W){let le=Math.pow(2,8*L)-1;k(this,m,Q,L,le,0)}let z=L-1,ae=1;for(this[Q+z]=m&255;--z>=0&&(ae*=256);)this[Q+z]=m/ae&255;return Q+L},a.prototype.writeUint8=a.prototype.writeUInt8=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,1,255,0),this[Q]=m&255,Q+1},a.prototype.writeUint16LE=a.prototype.writeUInt16LE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,2,65535,0),this[Q]=m&255,this[Q+1]=m>>>8,Q+2},a.prototype.writeUint16BE=a.prototype.writeUInt16BE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,2,65535,0),this[Q]=m>>>8,this[Q+1]=m&255,Q+2},a.prototype.writeUint32LE=a.prototype.writeUInt32LE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,4,4294967295,0),this[Q+3]=m>>>24,this[Q+2]=m>>>16,this[Q+1]=m>>>8,this[Q]=m&255,Q+4},a.prototype.writeUint32BE=a.prototype.writeUInt32BE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,4,4294967295,0),this[Q]=m>>>24,this[Q+1]=m>>>16,this[Q+2]=m>>>8,this[Q+3]=m&255,Q+4};function ne(F,m,Q,L,W){yr(m,L,W,F,Q,7);let z=Number(m&BigInt(4294967295));F[Q++]=z,z=z>>8,F[Q++]=z,z=z>>8,F[Q++]=z,z=z>>8,F[Q++]=z;let ae=Number(m>>BigInt(32)&BigInt(4294967295));return F[Q++]=ae,ae=ae>>8,F[Q++]=ae,ae=ae>>8,F[Q++]=ae,ae=ae>>8,F[Q++]=ae,Q}function Ae(F,m,Q,L,W){yr(m,L,W,F,Q,7);let z=Number(m&BigInt(4294967295));F[Q+7]=z,z=z>>8,F[Q+6]=z,z=z>>8,F[Q+5]=z,z=z>>8,F[Q+4]=z;let ae=Number(m>>BigInt(32)&BigInt(4294967295));return F[Q+3]=ae,ae=ae>>8,F[Q+2]=ae,ae=ae>>8,F[Q+1]=ae,ae=ae>>8,F[Q]=ae,Q+8}a.prototype.writeBigUInt64LE=Ne(function(m,Q=0){return ne(this,m,Q,BigInt(0),BigInt("0xffffffffffffffff"))}),a.prototype.writeBigUInt64BE=Ne(function(m,Q=0){return Ae(this,m,Q,BigInt(0),BigInt("0xffffffffffffffff"))}),a.prototype.writeIntLE=function(m,Q,L,W){if(m=+m,Q=Q>>>0,!W){let ye=Math.pow(2,8*L-1);k(this,m,Q,L,ye-1,-ye)}let z=0,ae=1,le=0;for(this[Q]=m&255;++z>0)-le&255;return Q+L},a.prototype.writeIntBE=function(m,Q,L,W){if(m=+m,Q=Q>>>0,!W){let ye=Math.pow(2,8*L-1);k(this,m,Q,L,ye-1,-ye)}let z=L-1,ae=1,le=0;for(this[Q+z]=m&255;--z>=0&&(ae*=256);)m<0&&le===0&&this[Q+z+1]!==0&&(le=1),this[Q+z]=(m/ae>>0)-le&255;return Q+L},a.prototype.writeInt8=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,1,127,-128),m<0&&(m=255+m+1),this[Q]=m&255,Q+1},a.prototype.writeInt16LE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,2,32767,-32768),this[Q]=m&255,this[Q+1]=m>>>8,Q+2},a.prototype.writeInt16BE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,2,32767,-32768),this[Q]=m>>>8,this[Q+1]=m&255,Q+2},a.prototype.writeInt32LE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,4,2147483647,-2147483648),this[Q]=m&255,this[Q+1]=m>>>8,this[Q+2]=m>>>16,this[Q+3]=m>>>24,Q+4},a.prototype.writeInt32BE=function(m,Q,L){return m=+m,Q=Q>>>0,L||k(this,m,Q,4,2147483647,-2147483648),m<0&&(m=4294967295+m+1),this[Q]=m>>>24,this[Q+1]=m>>>16,this[Q+2]=m>>>8,this[Q+3]=m&255,Q+4},a.prototype.writeBigInt64LE=Ne(function(m,Q=0){return ne(this,m,Q,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))}),a.prototype.writeBigInt64BE=Ne(function(m,Q=0){return Ae(this,m,Q,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))});function ue(F,m,Q,L,W,z){if(Q+L>F.length)throw new RangeError("Index out of range");if(Q<0)throw new RangeError("Index out of range")}function pe(F,m,Q,L,W){return m=+m,Q=Q>>>0,W||ue(F,m,Q,4,34028234663852886e22,-34028234663852886e22),r.write(F,m,Q,L,23,4),Q+4}a.prototype.writeFloatLE=function(m,Q,L){return pe(this,m,Q,!0,L)},a.prototype.writeFloatBE=function(m,Q,L){return pe(this,m,Q,!1,L)};function he(F,m,Q,L,W){return m=+m,Q=Q>>>0,W||ue(F,m,Q,8,17976931348623157e292,-17976931348623157e292),r.write(F,m,Q,L,52,8),Q+8}a.prototype.writeDoubleLE=function(m,Q,L){return he(this,m,Q,!0,L)},a.prototype.writeDoubleBE=function(m,Q,L){return he(this,m,Q,!1,L)},a.prototype.copy=function(m,Q,L,W){if(!a.isBuffer(m))throw new TypeError("argument should be a Buffer");if(L||(L=0),!W&&W!==0&&(W=this.length),Q>=m.length&&(Q=m.length),Q||(Q=0),W>0&&W=this.length)throw new RangeError("Index out of range");if(W<0)throw new RangeError("sourceEnd out of bounds");W>this.length&&(W=this.length),m.length-Q>>0,L=L===void 0?this.length:L>>>0,m||(m=0);let z;if(typeof m=="number")for(z=Q;z2**32?W=Ie(String(Q)):typeof Q=="bigint"&&(W=String(Q),(Q>BigInt(2)**BigInt(32)||Q<-(BigInt(2)**BigInt(32)))&&(W=Ie(W)),W+="n"),L+=` It must be ${m}. Received ${W}`,L},RangeError);function Ie(F){let m="",Q=F.length,L=F[0]==="-"?1:0;for(;Q>=L+4;Q-=3)m=`_${F.slice(Q-3,Q)}${m}`;return`${F.slice(0,Q)}${m}`}function be(F,m,Q){we(m,"offset"),(F[m]===void 0||F[m+Q]===void 0)&&ve(m,F.length-(Q+1))}function yr(F,m,Q,L,W,z){if(F>Q||F3?m===0||m===BigInt(0)?le=`>= 0${ae} and < 2${ae} ** ${(z+1)*8}${ae}`:le=`>= -(2${ae} ** ${(z+1)*8-1}${ae}) and < 2 ** ${(z+1)*8-1}${ae}`:le=`>= ${m}${ae} and <= ${Q}${ae}`,new de.ERR_OUT_OF_RANGE("value",le,F)}be(L,W,z)}function we(F,m){if(typeof F!="number")throw new de.ERR_INVALID_ARG_TYPE(m,"number",F)}function ve(F,m,Q){throw Math.floor(F)!==F?(we(F,Q),new de.ERR_OUT_OF_RANGE(Q||"offset","an integer",F)):m<0?new de.ERR_BUFFER_OUT_OF_BOUNDS:new de.ERR_OUT_OF_RANGE(Q||"offset",`>= ${Q?1:0} and <= ${m}`,F)}var Ms=/[^+/0-9A-Za-z-_]/g;function Ye(F){if(F=F.split("=")[0],F=F.trim().replace(Ms,""),F.length<2)return"";for(;F.length%4!==0;)F=F+"=";return F}function xe(F,m){m=m||1/0;let Q,L=F.length,W=null,z=[];for(let ae=0;ae55295&&Q<57344){if(!W){if(Q>56319){(m-=3)>-1&&z.push(239,191,189);continue}else if(ae+1===L){(m-=3)>-1&&z.push(239,191,189);continue}W=Q;continue}if(Q<56320){(m-=3)>-1&&z.push(239,191,189),W=Q;continue}Q=(W-55296<<10|Q-56320)+65536}else W&&(m-=3)>-1&&z.push(239,191,189);if(W=null,Q<128){if((m-=1)<0)break;z.push(Q)}else if(Q<2048){if((m-=2)<0)break;z.push(Q>>6|192,Q&63|128)}else if(Q<65536){if((m-=3)<0)break;z.push(Q>>12|224,Q>>6&63|128,Q&63|128)}else if(Q<1114112){if((m-=4)<0)break;z.push(Q>>18|240,Q>>12&63|128,Q>>6&63|128,Q&63|128)}else throw new Error("Invalid code point")}return z}function Fs(F){let m=[];for(let Q=0;Q>8,W=Q%256,z.push(W),z.push(L);return z}function De(F){return t.toByteArray(Ye(F))}function en(F,m,Q,L){let W;for(W=0;W=m.length||W>=F.length);++W)m[W+Q]=F[W];return W}function Re(F,m){return F instanceof m||F!=null&&F.constructor!=null&&F.constructor.name!=null&&F.constructor.name===m.name}function He(F){return F!==F}var ai=(function(){let F="0123456789abcdef",m=new Array(256);for(let Q=0;Q<16;++Q){let L=Q*16;for(let W=0;W<16;++W)m[L+W]=F[Q]+F[W]}return m})();function Ne(F){return typeof BigInt>"u"?Je:F}function Je(){throw new Error("BigInt not supported")}}}),BB=H2(q2(),1),Yl=typeof BB.Buffer.kMaxLength=="number"?BB.Buffer.kMaxLength:2147483647,o0=typeof BB.Buffer.kStringMaxLength=="number"?BB.Buffer.kStringMaxLength:536870888,RY=Object.freeze({MAX_LENGTH:Yl,MAX_STRING_LENGTH:o0}),DY=Symbol("events.errorMonitor"),LA=10;function a0(e,t,r){return t==="newListener"&&r[0]==="newListener"||t==="removeListener"&&r[0]==="removeListener"?!1:P1(e,t,r)}function A0(e,t){HA(e);let r=e._events[t];return Array.isArray(r)?r.slice():[]}function f0(e,t,r,n=!1){HA(e);let i=e._events[t];if(!Array.isArray(i)||i.length===0)return e;let s=null,o=i.slice();for(let a=o.length-1;a>=0;a-=1){let A=o[a];if(!(A.listener!==r&&A.rawListener!==r)&&!(n&&!A.once)){s=A,o.splice(a,1);break}}return s===null||(o.length===0?delete e._events[t]:e._events[t]=o,a0(e,"removeListener",[t,s.listener])),e}function tG(e,t){let r=String(t),n=A0(e,r);for(let i=n.length-1;i>=0;i-=1)f0(e,r,n[i].listener);return e}function P1(e,t,r){let n=A0(e,t);if(n.length===0)return!1;for(let i of n){i.once&&f0(e,t,i.listener,!0);try{i.listener.apply(e,r)}catch(s){let o=jl(s);if(!o.handled&&o.rethrow!==null)throw o.rethrow;return!0}}return!0}function G2(e,t){return A0(e,t).length}function Y2(e,t){return A0(e,t).map(r=>r.listener)}function vQe(e,t){return A0(e,t).map(r=>r.rawListener??r.listener)}function TY(e,t,r){function n(...i){return f0(e,t,n,!0),r.apply(e,i)}return Object.defineProperty(n,"listener",{value:r,configurable:!0,enumerable:!1,writable:!1}),n}function NY(e){return e&&typeof e.getMaxListeners=="function"?e.getMaxListeners():LA}function MY(e,...t){for(let r of t)r&&typeof r.setMaxListeners=="function"&&r.setMaxListeners(e)}function RQe(e,t){if(!e||typeof e.addEventListener!="function")throw new TypeError("AbortSignal is required");let r=()=>t();return e.aborted?(queueMicrotask(r),{dispose(){}}):(e.addEventListener("abort",r,{once:!0}),{dispose(){e.removeEventListener("abort",r)}})}function FY(e,t){return new Promise((r,n)=>{let i=(...o)=>{typeof e.removeListener=="function"&&e.removeListener("error",s),r(o)},s=o=>{typeof e.removeListener=="function"&&e.removeListener(t,i),n(o)};e.once(t,i),t!=="error"&&typeof e.once=="function"&&e.once("error",s)})}function kY(e){e._events=Object.create(null),e._maxListeners=LA,e._maxListenersWarned=new Set}function HA(e){if(!(!e||typeof e!="object"&&typeof e!="function")){if(typeof e._events>"u"){kY(e);return}e._maxListenersWarned instanceof Set||(e._maxListenersWarned=new Set),typeof e._maxListeners!="number"&&(e._maxListeners=LA)}}function DQe(e,t,r){let n=Number.isFinite(e._maxListeners)?e._maxListeners:LA,i=new Error(`Possible EventEmitter memory leak detected. ${r} ${t} listeners added to [EventEmitter]. MaxListeners is ${n}. Use emitter.setMaxListeners() to increase limit`);return i.name="MaxListenersExceededWarning",i.emitter=e,i.type=t,i.count=r,i}function TQe(e,t,r){if(HA(e),e._maxListenersWarned instanceof Set||(e._maxListenersWarned=new Set),e._maxListeners<=0||e._maxListenersWarned.has(t)||r<=e._maxListeners)return;e._maxListenersWarned.add(t);let n=DQe(e,t,r);if(Qe&&typeof Qe.emitWarning=="function"){Qe.emitWarning(n);return}typeof _error<"u"&&_error.applySync(void 0,[`${n.name}: ${n.message}`])}function zB(e,t,r,n=!1){HA(e);let i=e._events[t]??[];n?i.unshift(r):i.push(r),e._events[t]=i,TQe(e,t,i.length)}function Xt(){if(!this||typeof this!="object"&&typeof this!="function")return new Xt;kY(this)}Xt.prototype.addListener=function(e,t){return this.on(e,t)};Xt.prototype.on=function(e,t){if(typeof t!="function")throw new TypeError("listener must be a function");let r=String(e);return a0(this,"newListener",[r,t]),zB(this,r,{listener:t,once:!1}),this};Xt.prototype.once=function(e,t){if(typeof t!="function")throw new TypeError("listener must be a function");let r=String(e);return a0(this,"newListener",[r,t]),zB(this,r,{listener:t,rawListener:TY(this,r,t),once:!0}),this};Xt.prototype.prependListener=function(e,t){if(typeof t!="function")throw new TypeError("listener must be a function");let r=String(e);return a0(this,"newListener",[r,t]),zB(this,r,{listener:t,once:!1},!0),this};Xt.prototype.prependOnceListener=function(e,t){if(typeof t!="function")throw new TypeError("listener must be a function");let r=String(e);return a0(this,"newListener",[r,t]),zB(this,r,{listener:t,rawListener:TY(this,r,t),once:!0},!0),this};Xt.prototype.removeListener=function(e,t){return f0(this,String(e),t)};Xt.prototype.off=function(e,t){return f0(this,String(e),t)};Xt.prototype.removeAllListeners=function(e){if(HA(this),typeof e>"u"){for(let t of Object.keys(this._events))t!=="removeListener"&&tG(this,t);delete this._events.removeListener}else tG(this,String(e));return this};Xt.prototype.emit=function(e,...t){let r=String(e);if(r==="error"&&G2(this,r)===0)throw t[0]instanceof Error?t[0]:new Error(String(t[0]??"Unhandled error event"));let n=P1(this,r,t);return r==="error"&&(n=P1(this,String(DY),t)||n),n};Xt.prototype.listeners=function(e){return Y2(this,String(e))};Xt.prototype.rawListeners=function(e){return vQe(this,String(e))};Xt.prototype.listenerCount=function(e){return G2(this,String(e))};Xt.prototype.eventNames=function(){return HA(this),Object.keys(this._events)};Xt.prototype.setMaxListeners=function(e){return HA(this),this._maxListeners=Number(e),this};Xt.prototype.getMaxListeners=function(){return HA(this),Number.isFinite(this._maxListeners)?this._maxListeners:LA};Xt.once=FY;Xt.on=function(t,r,n){let i=n&&n.signal;if(i&&i.aborted)throw i.reason??new Error("The operation was aborted");let s=(N,P)=>(t.off??t.removeListener).call(t,N,P),o=[],a=[],A=null,f=!1,l=()=>{s(r,B),s("error",S),i&&i.removeEventListener&&i.removeEventListener("abort",_)},p={next(){let N=o.shift();if(N!==void 0)return Promise.resolve({value:N,done:!1});if(A){let P=A;return A=null,l(),Promise.reject(P)}return f?Promise.resolve({value:void 0,done:!0}):new Promise((P,U)=>a.push({resolve:P,reject:U}))},return(){f=!0,l();for(let N of a)N.resolve({value:void 0,done:!0});return a.length=0,Promise.resolve({value:void 0,done:!0})},throw(N){return A=N,l(),Promise.reject(N)},[Symbol.asyncIterator](){return this}};function B(...N){let P=a.shift();P?P.resolve({value:N,done:!1}):o.push(N)}function S(N){let P=a.shift();P?(l(),P.reject(N)):A=N}function _(){p.return()}return t.on(r,B),t.on("error",S),i&&i.addEventListener&&i.addEventListener("abort",_,{once:!0}),p};Xt.addAbortListener=function(t,r){return t&&t.aborted?queueMicrotask(()=>r(typeof Ul=="function"?new Ul("abort"):{type:"abort"})):t&&t.addEventListener&&t.addEventListener("abort",r,{once:!0}),{[Symbol.dispose](){t&&t.removeEventListener&&t.removeEventListener("abort",r)}}};Xt.getEventListeners=Y2;Xt.getMaxListeners=NY;Xt.setMaxListeners=MY;Object.defineProperty(Xt,"defaultMaxListeners",{get(){return LA},set(e){LA=Number(e)}});var Sl={addAbortListener:RQe,defaultMaxListeners:LA,errorMonitor:DY,EventEmitter:Xt,getEventListeners:Y2,getMaxListeners:NY,listenerCount:G2,once:FY,setMaxListeners:MY};Ge("_eventsModule",Sl);var _e=H2(q2(),1),Iu=_e.Buffer;typeof Iu.kMaxLength!="number"&&(Iu.kMaxLength=Yl);typeof Iu.kStringMaxLength!="number"&&(Iu.kStringMaxLength=o0);(typeof Iu.constants!="object"||Iu.constants===null)&&(Iu.constants={MAX_LENGTH:Yl,MAX_STRING_LENGTH:o0});var yg=_e.Buffer.prototype;if(typeof yg.utf8Slice!="function"){let e=["utf8","latin1","ascii","hex","base64","ucs2","utf16le"];for(let t of e)typeof yg[t+"Slice"]!="function"&&(yg[t+"Slice"]=function(r,n){return this.toString(t,r,n)}),typeof yg[t+"Write"]!="function"&&(yg[t+"Write"]=function(r,n,i){return this.write(r,n??0,i??this.length-(n??0),t)})}var mg=_e.Buffer;if(typeof mg.allocUnsafe=="function"&&!mg.allocUnsafe._secureExecPatched){let e=mg.allocUnsafe;mg.allocUnsafe=function(r){try{return e.call(this,r)}catch(n){throw n instanceof RangeError&&typeof r=="number"&&r>Yl?new Error("Array buffer allocation failed"):n}},mg.allocUnsafe._secureExecPatched=!0}var xY=_e.Buffer,tB={scheduler:{wait(e=0,t=void 0){return tB.setTimeout(e,void 0,t)},yield(){return tB.setImmediate()}},setImmediate(e=void 0,t=void 0){return t?.signal?.aborted?Promise.reject(t.signal.reason??new Error("The operation was aborted")):new Promise((r,n)=>{let i=()=>n(t.signal.reason??new Error("The operation was aborted"));t?.signal?.addEventListener?.("abort",i,{once:!0}),globalThis.setImmediate?.(()=>{t?.signal?.removeEventListener?.("abort",i),r(e)})??globalThis.setTimeout?.(()=>{t?.signal?.removeEventListener?.("abort",i),r(e)},0)})},setInterval(e=1,t=void 0,r=void 0){let n=!0,i=r?.signal;return i?.aborted&&(n=!1),{[Symbol.asyncIterator](){return this},async next(){if(!n)return{done:!0,value:void 0};try{let s=await tB.setTimeout(e,t,{signal:i});return n?{done:!1,value:s}:{done:!0,value:void 0}}catch(s){throw n=!1,s}},async return(){return n=!1,{done:!0,value:void 0}}}},setTimeout(e=1,t=void 0,r=void 0){return r?.signal?.aborted?Promise.reject(r.signal.reason??new Error("The operation was aborted")):new Promise((n,i)=>{let s=globalThis.setTimeout?.(()=>{r?.signal?.removeEventListener?.("abort",o),n(t)},e??0),o=()=>{typeof globalThis.clearTimeout=="function"&&globalThis.clearTimeout(s),i(r.signal.reason??new Error("The operation was aborted"))};r?.signal?.addEventListener?.("abort",o,{once:!0})})}},UY=new Set;function xa(){return Array.from(UY,e=>({storage:e,hasStore:e._hasStore===!0,store:e._store}))}function rG(e){for(let t of e)t.storage._hasStore=t.hasStore,t.storage._store=t.store}function KB(e,t,r,n){if(typeof t!="function")return t;let i=xa();rG(e);try{return t.apply(r,n)}finally{rG(i)}}function Ll(e,t){return typeof e!="function"?e:function(...r){try{return KB(t,e,this,r)}catch(n){throw uI(n),n}}}var LY={AsyncLocalStorage:class{constructor(){this._hasStore=!1,this._store=void 0,UY.add(this)}disable(){this._hasStore=!1,this._store=void 0}enterWith(e){this._hasStore=!0,this._store=e}exit(e,...t){let r={hasStore:this._hasStore,store:this._store};this._hasStore=!1,this._store=void 0;let n=!0;try{let i=e(...t);return i&&typeof i.then=="function"?(n=!1,Promise.resolve(i).finally(()=>{this._hasStore=r.hasStore,this._store=r.store})):i}finally{n&&(this._hasStore=r.hasStore,this._store=r.store)}}getStore(){return this._hasStore?this._store:void 0}run(e,t,...r){let n={hasStore:this._hasStore,store:this._store};this._hasStore=!0,this._store=e;let i=!0;try{let s=t(...r);return s&&typeof s.then=="function"?(i=!1,Promise.resolve(s).finally(()=>{this._hasStore=n.hasStore,this._store=n.store})):s}finally{i&&(this._hasStore=n.hasStore,this._store=n.store)}}},AsyncResource:class{constructor(e="SecureExecAsyncResource"){this.type=e,this._asyncLocalStorageSnapshot=xa()}emitBefore(){}emitAfter(){}emitDestroy(){}asyncId(){return 0}triggerAsyncId(){return 0}runInAsyncScope(e,t,...r){return KB(this._asyncLocalStorageSnapshot,e,t,r)}},createHook(){return{enable(){return this},disable(){return this}}},executionAsyncId(){return 0},triggerAsyncId(){return 0}};if(!Promise.prototype.__agentOSAsyncLocalStoragePatched){let e=Promise.prototype.then;Promise.prototype.then=function(t,r){let n=xa(),i=typeof r=="function"?s=>{if(uI(s))throw s;return r(s)}:r;return e.call(this,Ll(t,n),Ll(i,n))},Object.defineProperty(Promise.prototype,"__agentOSAsyncLocalStoragePatched",{value:!0,configurable:!0})}var W2={create:"kernelTimerCreate",arm:"kernelTimerArm",clear:"kernelTimerClear"};Ge("_asyncHooksModule",LY);var _a=typeof queueMicrotask=="function"?queueMicrotask:function(e){Promise.resolve().then(e)};function PY(e){let t=Number(e??0);return!Number.isFinite(t)||t<=0?0:Math.floor(t)}function OY(e){if(e&&typeof e=="object"&&e._id!==void 0)return e._id;if(typeof e=="number")return e}function HY(e,t){try{return s0(W2.create,e,t)}catch(r){throw r instanceof Error&&r.message.includes("EAGAIN")?new Error("ERR_RESOURCE_BUDGET_EXCEEDED: maximum number of timers exceeded"):r}}function XB(e){s0(W2.arm,e)}var V2=class{constructor(e){y(this,"_id");y(this,"_destroyed");y(this,"_refed");this._id=e,this._destroyed=!1,this._refed=!0}ref(){return this._refed=!0,this}unref(){return this._refed=!1,this}hasRef(){return this._refed}refresh(){return!this._destroyed&&Fa.has(this._id)&&XB(this._id),this}[Symbol.toPrimitive](){return this._id}},Fa=new Map,bu=new Map,NQe=-1,rB=[];function MQe(){if(typeof Ts<"u"&&Ts)return 0;let e=0;for(let t of Fa.values())t.handle?.hasRef?.()!==!1&&(e+=1);return e}function qY(){return typeof Ts<"u"&&Ts?0:bu.size}function J2(){return MQe()+qY()}function Su(){if(J2()===0&&rB.length>0){let e=rB;rB=[],e.forEach(t=>t())}}function FQe(){return J2()}function kQe(){return qY()}function xQe(){return J2()===0?Promise.resolve():new Promise(e=>{rB.push(e),Su()})}var nB=[],O1=!1;function UQe(){for(O1=!1;nB.length>0;){let e=nB.shift();if(!e)break;try{e.callback(...e.args)}catch(t){let r=jl(t);!r.handled&&r.rethrow!==null&&(nB.length=0,PV(r.rethrow));return}}}function LQe(){if(O1)return;O1=!0;let e=xa();_a(()=>KB(e,UQe,globalThis,[]))}function PQe(e,t){let r=typeof t=="number"?t:Number(t?.timerId);if(!Number.isFinite(r))return;let n=Fa.get(r);if(n){n.repeat||(n.handle._destroyed=!0,Fa.delete(r));try{n.callback(...n.args)}catch(i){let s=jl(i);if(!s.handled&&s.rethrow!==null)throw s.rethrow;return}if(typeof Ts<"u"&&Ts){Su();return}n.repeat&&Fa.has(r)&&XB(r),Su()}}function j2(e,t,...r){let n=Math.max(1,PY(t)),i=HY(n,!1),s=new V2(i),o=xa();return Fa.set(i,{handle:s,callback:Ll(e,o),args:r,repeat:!1}),XB(i),s}function ZB(e){let t=OY(e);if(t===void 0)return;let r=Fa.get(t);r&&(r.handle._destroyed=!0,Fa.delete(t)),s0(W2.clear,t),Su()}function z2(e,t,...r){let n=Math.max(1,PY(t)),i=HY(n,!0),s=new V2(i),o=xa();return Fa.set(i,{handle:s,callback:Ll(e,o),args:r,repeat:!0}),XB(i),s}function K2(e){ZB(e)}Ge("_timerDispatch",PQe);function OQe(){let e=Array.from(bu.entries());for(let[t,r]of e)if(bu.get(t)===r){r.handle._destroyed=!0,bu.delete(t);try{r.callback(...r.args)}catch(n){let i=jl(n);if(!i.handled&&i.rethrow!==null)throw i.rethrow;return}if(typeof Ts<"u"&&Ts){Su();return}}Su()}Ge("_getPendingTimerCount",FQe);Ge("_drainImmediates",OQe);Ge("_getPendingImmediateCount",kQe);Ge("_waitForTimerDrain",xQe);function IB(e,...t){let r=NQe--,n=new V2(r),i=xa();return bu.set(r,{handle:n,callback:Ll(e,i),args:t,repeat:!1}),n}function GY(e){let t=OY(e);if(t===void 0)return;let r=bu.get(t);if(r){r.handle._destroyed=!0,bu.delete(t),Su();return}t<0||ZB(e)}var HQe={stdinIsTTY:!1,stdoutIsTTY:!1,stderrIsTTY:!1,cols:80,rows:24},Co;function i1(e){if(typeof _kernelIsattyRaw>"u")throw new Error("_kernelIsattyRaw is unavailable");return _kernelIsattyRaw.applySync(void 0,[e])===!0}function qQe(e){if(typeof _kernelTtySizeRaw>"u")throw new Error("_kernelTtySizeRaw is unavailable");let t=_kernelTtySizeRaw.applySync(void 0,[e]);if(!t||typeof t.cols!="number"||typeof t.rows!="number")throw new Error("_kernelTtySizeRaw returned an invalid size");return t}function Gg(){if(Co)return Co;if(typeof __runtimeTtyConfig<"u")return Co=__runtimeTtyConfig,Co;try{Co={stdinIsTTY:i1(0),stdoutIsTTY:i1(1),stderrIsTTY:i1(2),cols:80,rows:24}}catch{return Co=HQe,Co}for(let e of[1,0])try{let t=qQe(e);Co.cols=t.cols,Co.rows=t.rows;break}catch{}return Co}function GQe(){return Gg().stdoutIsTTY}function YQe(){return Gg().stderrIsTTY}function WQe(e,t){if(typeof e=="function")return e;if(typeof t=="function")return t}function Gm(e,t,r,n){let i=e[r]?e[r].slice():[],s=t[r]?t[r].slice():[];s.length>0&&(t[r]=[]);for(let o of i)o(...n);for(let o of s)o(...n);return i.length+s.length>0}function YY(e){let t={},r={},n=(s,o)=>{if(t[s]){let a=t[s].indexOf(o);a!==-1&&t[s].splice(a,1)}if(r[s]){let a=r[s].indexOf(o);a!==-1&&r[s].splice(a,1)}},i={write(s,o,a){s instanceof Uint8Array||typeof _e.Buffer<"u"&&_e.Buffer.isBuffer(s)?e.write(s):e.write(String(s));let A=WQe(o,a);return A&&_a(()=>A(null)),!0},end(s,o,a){return typeof s=="function"?(a=s,s=void 0):typeof o=="function"&&(a=o),s!=null&&i.write(s),i.writableEnded=!0,typeof a=="function"&&_a(()=>a()),_a(()=>Gm(t,r,"finish",[])),i},destroyed:!1,destroy(s){return i.destroyed||(i.destroyed=!0,s&&_a(()=>Gm(t,r,"error",[s])),_a(()=>Gm(t,r,"close",[]))),i},cork(){},uncork(){},setDefaultEncoding(){return i},on(s,o){return t[s]||(t[s]=[]),t[s].push(o),i},once(s,o){return r[s]||(r[s]=[]),r[s].push(o),i},off(s,o){return n(s,o),i},removeListener(s,o){return n(s,o),i},addListener(s,o){return i.on(s,o)},emit(s,...o){return Gm(t,r,s,o)},writable:!0,get isTTY(){return e.isTTY()},get columns(){return Gg().cols},get rows(){return Gg().rows}};return i}var X2=YY({write(e){typeof _log<"u"&&_log.applySync(void 0,[e])},isTTY:GQe}),Z2=YY({write(e){typeof _error<"u"&&_error.applySync(void 0,[e])},isTTY:YQe});function VQe(e){if(typeof e=="string")return e;if(typeof e=="bigint")return`${e}n`;if(e instanceof Error)return e.stack||e.message||String(e);if(typeof e=="object"&&e!==null)try{return JSON.stringify(e)}catch{}return String(e)}function H1(e){return typeof builtinUtilModule<"u"&&typeof builtinUtilModule?.formatWithOptions=="function"?builtinUtilModule.formatWithOptions({colors:!1},...e):e.map(t=>VQe(t)).join(" ")}function Bl(e){return`${H1(e)} -`}var $2=class{constructor(e=X2,t=Z2){this._stdout=e,this._stderr=t,this._counts=new Map,this._times=new Map;for(let r of["assert","clear","count","countReset","debug","dir","dirxml","error","group","groupCollapsed","groupEnd","info","log","table","time","timeEnd","timeLog","trace","warn"])this[r]=this[r].bind(this)}log(...e){this._stdout.write(Bl(e))}info(...e){this._stdout.write(Bl(e))}debug(...e){this._stdout.write(Bl(e))}warn(...e){this._stderr.write(Bl(e))}error(...e){this._stderr.write(Bl(e))}dir(e){this._stdout.write(Bl([e]))}dirxml(...e){this.log(...e)}trace(...e){let t=H1(e),r=new Error(t);this._stderr.write(`${r.stack||t} -`)}assert(e,...t){if(!e){let r=t.length>0?H1(t):"Assertion failed";this._stderr.write(`${r} -`)}}clear(){}count(e="default"){let t=(this._counts.get(e)??0)+1;this._counts.set(e,t),this.log(`${e}: ${t}`)}countReset(e="default"){this._counts.delete(e)}group(...e){e.length>0&&this.log(...e)}groupCollapsed(...e){e.length>0&&this.log(...e)}groupEnd(){}table(e){this.log(e)}time(e="default"){this._times.set(e,Date.now())}timeEnd(e="default"){if(!this._times.has(e))return;let t=this._times.get(e);this._times.delete(e),this.log(`${e}: ${Date.now()-t}ms`)}timeLog(e="default",...t){if(!this._times.has(e))return;let r=this._times.get(e);this.log(`${e}: ${Date.now()-r}ms`,...t)}},ht=new $2;globalThis.console=ht;function JQe(){return{run(e,...t){return typeof e=="function"?e(...t):void 0}}}function jQe(e=X2,t=Z2){return new $2(e,t)}var zQe={Console:$2,assert:ht.assert.bind(ht),clear:ht.clear.bind(ht),context:jQe,count:ht.count.bind(ht),countReset:ht.countReset.bind(ht),createTask:JQe,debug:ht.debug.bind(ht),dir:ht.dir.bind(ht),dirxml:ht.dirxml.bind(ht),error:ht.error.bind(ht),group:ht.group.bind(ht),groupCollapsed:ht.groupCollapsed.bind(ht),groupEnd:ht.groupEnd.bind(ht),info:ht.info.bind(ht),log:ht.log.bind(ht),profile:void 0,profileEnd:void 0,table:ht.table.bind(ht),time:ht.time.bind(ht),timeEnd:ht.timeEnd.bind(ht),timeLog:ht.timeLog.bind(ht),timeStamp:void 0,trace:ht.trace.bind(ht),warn:ht.warn.bind(ht)};function iB(e){return!e||typeof e.formatWithOptions=="function"||(e.formatWithOptions=function(r,n,...i){let s=f=>{if(typeof e.inspect=="function")return e.inspect(f,r);try{return JSON.stringify(f)}catch{return String(f)}},o=f=>typeof f=="string"?f:s(f);if(typeof n!="string")return[n,...i].map(o).join(" ");let a=0,A=n.replace(/%[sdifjoO%]/g,f=>{if(f==="%%")return"%";if(a>=i.length)return f;let l=i[a++];switch(f){case"%s":return String(l);case"%d":return Number(l).toString();case"%i":return Number.parseInt(l,10).toString();case"%f":return Number.parseFloat(l).toString();case"%j":try{return JSON.stringify(l)}catch{return"[Circular]"}case"%o":case"%O":return s(l);default:return f}});return a>=i.length?A:[A,...i.slice(a).map(o)].join(" ")}),e}function q1(e){let t=new Error(`node:worker_threads ${e} is not available in the secure-exec guest runtime`);return t.code="ERR_NOT_IMPLEMENTED",t}var G1=class extends Xt{postMessage(){}start(){}close(){this.emit("close")}unref(){return this}ref(){return this}},KQe=class{constructor(){this.port1=new G1,this.port2=new G1}},XQe=class extends Xt{constructor(){throw super(),q1("Worker")}},ZQe={BroadcastChannel:globalThis.BroadcastChannel,MessageChannel:globalThis.MessageChannel??KQe,MessagePort:globalThis.MessagePort??G1,SHARE_ENV:Symbol.for("secure-exec.worker_threads.SHARE_ENV"),Worker:XQe,getEnvironmentData(){},isMainThread:!0,markAsUncloneable(){},markAsUntransferable(){},moveMessagePortToContext(){throw q1("moveMessagePortToContext")},parentPort:null,postMessageToThread(){throw q1("postMessageToThread")},receiveMessageOnPort(){},resourceLimits:{},setEnvironmentData(){},threadId:0,workerData:null};function $Qe(e){return e===0?!!Qe.stdin?.isTTY:e===1?!!Qe.stdout?.isTTY:e===2?!!Qe.stderr?.isTTY:!1}function ewe(e){return e===0?Qe.stdin:void 0}function twe(e){if(e===1)return Qe.stdout;if(e===2)return Qe.stderr}var rwe={ReadStream:class{constructor(t){return ewe(t)}},WriteStream:class{constructor(t){return twe(t)}},isatty:$Qe};async function nG(e){let t=WY(e);if(t){let r=[];for await(let n of t)r.push(Buffer.isBuffer(n)?n:Buffer.from(n??[]));return r}if(e&&typeof e[Symbol.asyncIterator]=="function"){let r=[];for await(let n of e)r.push(Buffer.isBuffer(n)?n:Buffer.from(n??[]));return r}if(e&&typeof e.getReader=="function"){let r=e.getReader(),n=[];try{for(;;){let{value:i,done:s}=await r.read();if(s)break;n.push(Buffer.from(i??[]))}}finally{r.releaseLock?.()}return n}throw new TypeError("expected an async iterable or WHATWG ReadableStream")}function nwe(e,t=""){return{size:e.byteLength,type:t,async arrayBuffer(){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)},stream(){return new ReadableStream({start(r){r.enqueue(e),r.close()}})},async text(){return e.toString("utf8")}}}var sB={async arrayBuffer(e){let t=await nG(e),r=Buffer.concat(t);return r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength)},async blob(e){return nwe(await sB.buffer(e))},async buffer(e){return Buffer.concat(await nG(e))},async json(e){return JSON.parse(await sB.text(e))},async text(e){return(await sB.buffer(e)).toString("utf8")}};function WY(e){return!e||typeof e.on!="function"||typeof e.read!="function"&&typeof e.pipe!="function"&&typeof e.resume!="function"?null:{async*[Symbol.asyncIterator](){let t=[],r=[],n=!1,i=null,s=[],o=typeof e.off=="function"?e.off.bind(e):typeof e.removeListener=="function"?e.removeListener.bind(e):null,a=()=>{for(;r.length>0;){if(i){r.shift()?.(Promise.reject(i));continue}if(t.length>0){r.shift()?.(Promise.resolve({done:!1,value:t.shift()}));continue}if(n){r.shift()?.(Promise.resolve({done:!0,value:void 0}));continue}break}},A=(B,S)=>{e.on(B,S),s.push(()=>o?.(B,S))},f=B=>{t.push(B),a()},l=()=>{n=!0,a()},p=B=>{i=B,n=!0,a()};A("data",f),A("end",l),A("close",l),A("error",p),e.resume?.();try{for(;;){if(i)throw i;if(t.length>0){yield t.shift();continue}if(n)return;let B=await new Promise(S=>{r.push(S)});if(B.done)return;yield B.value}}finally{for(;s.length>0;)s.pop()?.()}}}}var VY={finished(e){return new Promise((t,r)=>{if(!e||typeof e!="object"){r(new TypeError("finished() expects a stream"));return}let n=[],i=(o,a)=>{e?.once?.(o,a),n.push(()=>e?.off?.(o,a))},s=o=>a=>{for(;n.length>0;)n.pop()?.();o(a)};i("finish",s(t)),i("end",s(t)),i("close",s(t)),i("error",s(r))})},async pipeline(e,t){let r=WY(e)??(e&&typeof e[Symbol.asyncIterator]=="function"?e:e&&typeof e.getReader=="function"?{async*[Symbol.asyncIterator](){let i=e.getReader();try{for(;;){let{value:s,done:o}=await i.read();if(o)break;yield Buffer.from(s??[])}}finally{i.releaseLock?.()}}}:null);if(r==null)throw new TypeError("pipeline source must be async iterable or a WHATWG ReadableStream");if(!t||typeof t.write!="function")throw new TypeError("pipeline destination must provide write()");for await(let i of r)await new Promise((s,o)=>{try{t.write(i,a=>a?o(a):s())}catch(a){o(a)}});let n=VY.finished(t);return typeof t.end=="function"&&await new Promise((i,s)=>{try{t.end(o=>o?s(o):i())}catch(o){s(o)}}),await n,t}};function ou(e){let t=String(e).replace(/^node:/,""),r=new Error(`node:${t} is not available in the secure-exec guest runtime`);return r.code="ERR_ACCESS_DENIED",r}var JY=class{constructor(e=""){this.name=String(e),this._subscribers=new Set}get hasSubscribers(){return this._subscribers.size>0}publish(e){for(let t of Array.from(this._subscribers))t(e,this.name)}subscribe(e){typeof e=="function"&&this._subscribers.add(e)}unsubscribe(e){return this._subscribers.delete(e)}runStores(e,t,r,...n){return typeof t!="function"?t:t.apply(r,n)}},iG=new Map;function va(e=""){let t=String(e),r=iG.get(t);return r||(r=new JY(t),iG.set(t,r)),r}function iwe(e=""){let t=String(e),r={start:va(`tracing:${t}:start`),end:va(`tracing:${t}:end`),asyncStart:va(`tracing:${t}:asyncStart`),asyncEnd:va(`tracing:${t}:asyncEnd`),error:va(`tracing:${t}:error`),subscribe(){},unsubscribe(){return!0},traceSync(n,i,s,...o){return typeof n!="function"?n:n.apply(s,o)},tracePromise(n,i,s,...o){return typeof n!="function"?Promise.resolve(n):Promise.resolve(n.apply(s,o))},traceCallback(n,i,s,o,...a){return typeof n!="function"?n:n.apply(o,a)}};return Object.defineProperty(r,"hasSubscribers",{get(){return r.start.hasSubscribers||r.end.hasSubscribers||r.asyncStart.hasSubscribers||r.asyncEnd.hasSubscribers||r.error.hasSubscribers},enumerable:!1,configurable:!0}),r}var swe={Channel:JY,channel:va,hasSubscribers(e=""){return va(e).hasSubscribers},subscribe(e="",t){return va(e).subscribe(t)},tracingChannel:iwe,unsubscribe(e="",t){return va(e).unsubscribe(t)}};function Il(e,t=2){return String(Math.trunc(e)).padStart(t,"0")}function owe(e){let t=e instanceof Date?e:new Date(e??Date.now());if(Number.isNaN(t.getTime()))throw new RangeError("Invalid time value");return t}function awe(e,t={}){let r=owe(e),n=t&&typeof t=="object"?t:{},i=Il(r.getUTCFullYear(),4),s=Il(r.getUTCMonth()+1),o=Il(r.getUTCDate()),a=Il(r.getUTCHours()),A=Il(r.getUTCMinutes()),f=Il(r.getUTCSeconds()),l=`${i}-${s}-${o}`,p=`${a}:${A}:${f}`,B=n.dateStyle||n.year||n.month||n.day||!n.timeStyle&&!n.hour&&!n.minute&&!n.second,S=n.timeStyle||n.hour||n.minute||n.second;return B&&S?`${l}, ${p}`:S?p:l}var Awe=class{constructor(e="en-US",t={}){this.locales=e,this.options=t&&typeof t=="object"?{...t}:{},this.format=this.format.bind(this)}format(e=Date.now()){return awe(e,this.options)}formatToParts(e=Date.now()){return[{type:"literal",value:this.format(e)}]}formatRange(e,t){return`${this.format(e)} \u2013 ${this.format(t)}`}formatRangeToParts(e,t){return[{type:"literal",value:this.formatRange(e,t),source:"shared"}]}resolvedOptions(){return{locale:Array.isArray(this.locales)?this.locales.find(t=>typeof t=="string")||"en-US":typeof this.locales=="string"?this.locales:"en-US",calendar:"gregory",numberingSystem:"latn",timeZone:"UTC",...this.options}}static supportedLocalesOf(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):typeof e=="string"?[e]:[]}};function Ym(e,t){let r=Number(e);return Number.isFinite(r)?Math.min(20,Math.max(0,Math.trunc(r))):t}function fwe(e){let[t,r]=e.split("."),n=t.startsWith("-")?"-":"",s=(n?t.slice(1):t).replace(/\B(?=(\d{3})+(?!\d))/g,",");return r===void 0?`${n}${s}`:`${n}${s}.${r}`}var uwe=class{constructor(e="en-US",t={}){this.locales=e,this.options=t&&typeof t=="object"?{...t}:{},this.format=this.format.bind(this)}format(e){let t=Number(e);if(Number.isNaN(t))return"NaN";if(t===1/0)return"\u221E";if(t===-1/0)return"-\u221E";let r=Ym(this.options.minimumFractionDigits,0),n=Math.max(r,Ym(this.options.maximumFractionDigits,Math.max(r,3))),i=t.toFixed(n);if(n>r){i=i.replace(/(\.\d*?)0+$/,"$1").replace(/\.$/,"");let s=i.includes(".")?i.length-i.indexOf(".")-1:0;stypeof t=="string")||"en-US":typeof this.locales=="string"?this.locales:"en-US",numberingSystem:"latn",style:"decimal",minimumFractionDigits:Ym(this.options.minimumFractionDigits,0),maximumFractionDigits:Ym(this.options.maximumFractionDigits,3),useGrouping:this.options.useGrouping!==!1,...this.options}}static supportedLocalesOf(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):typeof e=="string"?[e]:[]}};function cwe(e){let t=e.Intl&&typeof e.Intl=="object"?e.Intl:{};t.DateTimeFormat=Awe,t.NumberFormat=uwe,e.Intl=t,Date.prototype.toLocaleString=function(r,n){return new e.Intl.DateTimeFormat(r,n).format(this)},Date.prototype.toLocaleDateString=function(r,n){return new e.Intl.DateTimeFormat(r,{...n||{},hour:void 0,minute:void 0,second:void 0}).format(this)},Date.prototype.toLocaleTimeString=function(r,n){return new e.Intl.DateTimeFormat(r,{hour:"2-digit",minute:"2-digit",second:"2-digit",...n||{}}).format(this)},Number.prototype.toLocaleString=function(r,n){return new e.Intl.NumberFormat(r,n).format(this.valueOf())}}function s1(e,t,r){let n=new RangeError(`The value of "${e}" is out of range. It must be ${t}. Received ${String(r)}`);return n.code="ERR_OUT_OF_RANGE",n}function jY(e){return{name:String(e?.name??""),entryType:String(e?.entryType??""),startTime:Number(e?.startTime??0),duration:Number(e?.duration??0)}}function zY(e){return{getEntries(){return e.slice()},getEntriesByName(t,r=void 0){let n=String(t??""),i=e.filter(s=>s.name===n);return typeof r=="string"?i.filter(s=>s.entryType===r):i},getEntriesByType(t){let r=String(t??"");return e.filter(n=>n.entryType===r)}}}function lwe(){let e=[];return{percentile(t){let r=Number(t);if(!Number.isFinite(r)||r<=0||r>100)throw s1("percentile","> 0 && <= 100",t);if(e.length===0)return 0;let n=e.slice().sort((s,o)=>s-o),i=Math.min(n.length-1,Math.max(0,Math.ceil(r/100*n.length)-1));return n[i]},record(t){let r=Number(t);if(!Number.isInteger(r))throw s1("val","an integer",t);if(r<1||r>Number.MAX_SAFE_INTEGER)throw s1("val",`>= 1 && <= ${Number.MAX_SAFE_INTEGER}`,t);e.push(r)}}}var Wm=(()=>{let e=new Map,t=[],r=new Set,n=typeof performance<"u"&&performance&&typeof performance.now=="function"?performance:{now(){return Gl()},timeOrigin:Date.now()-Gl()};typeof n.mark!="function"&&(n.mark=function(A){let f={name:String(A??""),entryType:"mark",startTime:n.now(),duration:0},l=e.get(f.name)??[];return l.push(f),e.set(f.name,l),f}),typeof n.measure!="function"&&(n.measure=function(A,f,l){let p=String(A??""),B=0,S=n.now();if(typeof f=="string"){let N=e.get(f);if(N?.length&&(B=N[N.length-1].startTime),typeof l=="string"){let P=e.get(l);P?.length&&(S=P[P.length-1].startTime)}}else if(f&&typeof f=="object"){if(typeof f.start=="number")B=f.start;else if(typeof f.startMark=="string"){let N=e.get(f.startMark);N?.length&&(B=N[N.length-1].startTime)}if(typeof f.end=="number")S=f.end;else if(typeof f.endMark=="string"){let N=e.get(f.endMark);N?.length&&(S=N[N.length-1].startTime)}}let _={name:p,entryType:"measure",startTime:B,duration:Math.max(0,S-B)};return t.push(_),_}),typeof n.getEntriesByName!="function"&&(n.getEntriesByName=function(A,f=void 0){let l=String(A??""),B=[...e.get(l)??[],...t.filter(S=>S.name===l)];return typeof f=="string"?B.filter(S=>S.entryType===f):B}),typeof n.getEntries!="function"&&(n.getEntries=function(){return[...e.values()].flatMap(A=>[...A]).concat(t)}),typeof n.getEntriesByType!="function"&&(n.getEntriesByType=function(A){let f=String(A??"");return n.getEntries().filter(l=>l.entryType===f)}),typeof n.clearMarks!="function"&&(n.clearMarks=function(A=void 0){if(typeof A>"u"){e.clear();return}e.delete(String(A))}),typeof n.clearMeasures!="function"&&(n.clearMeasures=function(A=void 0){if(typeof A>"u"){t.length=0;return}let f=String(A);for(let l=t.length-1;l>=0;l-=1)t[l]?.name===f&&t.splice(l,1)});let i=A=>{A._deliveryQueued||(A._deliveryQueued=!0,_a(()=>{if(A._deliveryQueued=!1,!A._connected)return;let f=A.takeRecords();A._callback(zY(f),A)}))},s=A=>{let f=jY(A);for(let l of r)l._entryTypes.has(f.entryType)&&(l._records.push(f),i(l))},o=n.mark.bind(n);n.mark=function(...A){let f=o(...A);return s(f),f};let a=n.measure.bind(n);return n.measure=function(...A){let f=a(...A);return s(f),f},n.__agentOSObservers=r,n})(),hwe={PerformanceObserver:class{constructor(e){if(typeof e!="function")throw new TypeError("PerformanceObserver callback must be a function");this._callback=e,this._connected=!1,this._deliveryQueued=!1,this._entryTypes=new Set,this._records=[]}static get supportedEntryTypes(){return["mark","measure"]}observe(e={}){let t=Array.isArray(e?.entryTypes)?e.entryTypes.map(r=>String(r)):typeof e?.type=="string"?[String(e.type)]:[];if(t.length===0)throw new TypeError("PerformanceObserver.observe() requires an entryTypes array or type string");if(this.disconnect(),this._entryTypes=new Set(t),this._connected=!0,Wm.__agentOSObservers.add(this),e?.buffered){for(let r of this._entryTypes)for(let n of Wm.getEntriesByType(r))this._records.push(jY(n));this._records.length>0&&(this._deliveryQueued=!0,_a(()=>{if(this._deliveryQueued=!1,!this._connected)return;let r=this.takeRecords();this._callback(zY(r),this)}))}}disconnect(){this._connected=!1,Wm.__agentOSObservers.delete(this)}takeRecords(){let e=this._records.slice();return this._records.length=0,e}},constants:{},createHistogram(){return lwe()},performance:Wm};function KY(e){let t=JSON.stringify(e??null);return Buffer.from(t,"utf8")}function XY(e){let t=Buffer.isBuffer(e)?e:Buffer.from(e??[]);return JSON.parse(t.toString("utf8"))}var sG=class{constructor(){this._value=null}writeHeader(){}writeValue(e){this._value=e}releaseBuffer(){return KY(this._value)}transferArrayBuffer(){}},oG=class{constructor(e){this._buffer=e}readHeader(){}readValue(){return XY(this._buffer)}transferArrayBuffer(){}};function dwe(){let e=Number(globalThis.__agentOSV8HeapLimitBytes);return Number.isFinite(e)&&e>0?e:128*1024*1024}function gwe(){let e=dwe();return{total_heap_size:Math.max(64*1024*1024,Math.floor(e/2)),total_heap_size_executable:1024*1024,total_physical_size:Math.max(64*1024*1024,Math.floor(e/2)),total_available_size:Math.max(0,e-64*1024*1024),used_heap_size:Math.max(0,Math.min(e,Math.floor(e*.4))),heap_size_limit:e,malloced_memory:8192,peak_malloced_memory:16384,does_zap_garbage:0,number_of_native_contexts:1,number_of_detached_contexts:0,total_global_handles_size:16384,used_global_handles_size:8192,external_memory:0}}function pwe(){return[]}function Ewe(){return{code_and_metadata_size:0,bytecode_and_metadata_size:0,external_script_source_size:0,cpu_profiler_metadata_size:0}}function ywe(){return{committed_size_bytes:0,resident_size_bytes:0,used_size_bytes:0,space_statistics:[]}}function mwe(){return Readable.fromWeb(new ReadableStream({start(e){e.enqueue(Buffer.from("{}")),e.close()}}))}var Bwe={cachedDataVersionTag(){return 0},DefaultDeserializer:oG,DefaultSerializer:sG,Deserializer:oG,GCProfiler:class{start(){}stop(){return[]}},Serializer:sG,deserialize:XY,getCppHeapStatistics:ywe,getHeapCodeStatistics:Ewe,getHeapSnapshot:mwe,getHeapSpaceStatistics:pwe,getHeapStatistics:gwe,isStringOneByteRepresentation(e){return typeof e=="string"&&!/[^\x00-\xff]/.test(e)},promiseHooks:{},queryObjects(){return[]},serialize:KY,setFlagsFromString(){},setHeapSnapshotNearHeapLimit(){return[]},startCpuProfile(){return{stop(){return{}}}},startupSnapshot:{},stopCoverage(){return[]},takeCoverage(){return[]},writeHeapSnapshot(){return""}},Y1=typeof Symbol=="function"?Symbol.for("secure-exec.vm.context"):"__secure_exec_vm_context__",bB=typeof Symbol=="function"?Symbol.for("secure-exec.vm.context.id"):"__secure_exec_vm_context_id__";function aG(e){let t=new Error(`node:vm ${e} is not implemented in the secure-exec guest runtime`);return t.code="ERR_NOT_IMPLEMENTED",t}function eR(e){return e!==null&&(typeof e=="object"||typeof e=="function")}function Yg(e=void 0){if(typeof e=="string")return{filename:e};if(!e||typeof e!="object")return{};let t={};return typeof e.filename=="string"&&(t.filename=e.filename),Number.isInteger(e.lineOffset)&&(t.lineOffset=e.lineOffset),Number.isInteger(e.columnOffset)&&(t.columnOffset=e.columnOffset),Number.isInteger(e.timeout)&&e.timeout>0&&(t.timeout=e.timeout),e.cachedData!==void 0&&(t.cachedData=e.cachedData),e.produceCachedData===!0&&(t.produceCachedData=!0),t}function o1(e,t){let r=Yg(e),n=Yg(t);return{...r,...n}}function ZY(e={}){if(!eR(e))throw new TypeError('The "object" argument must be of type object.');if(e[Y1]===!0&&Number.isInteger(e[bB]))return e;let t=_vmCreateContext(e);return Object.defineProperty(e,Y1,{value:!0,configurable:!0,enumerable:!1,writable:!1}),Object.defineProperty(e,bB,{value:t,configurable:!1,enumerable:!1,writable:!1}),e}function $Y(e){return eR(e)&&e[Y1]===!0&&Number.isInteger(e[bB])}function Iwe(e){if(!$Y(e))throw new TypeError('The "contextifiedObject" argument must be a vm context.');return e}function eW(e,t=void 0){return _vmRunInThisContext(String(e),Yg(t))}function tR(e,t,r=void 0){let n=Iwe(t);return _vmRunInContext(n[bB],String(e),Yg(r),n)}function tW(e,t={},r=void 0){let n=eR(t),i=n?t:{},s=n?r:t;return tR(e,ZY(i),s)}var bwe=class{constructor(e,t=void 0){this.code=String(e),this.options=Yg(t),this.filename=this.options.filename??"evalmachine.",this.lineOffset=this.options.lineOffset??0,this.columnOffset=this.options.columnOffset??0,this.cachedData=this.options.cachedData,this.cachedDataProduced=!1,this.cachedDataRejected=!1}createCachedData(){return typeof Buffer=="function"?Buffer.alloc(0):new Uint8Array(0)}runInThisContext(e=void 0){return eW(this.code,o1(this.options,e))}runInContext(e,t=void 0){return tR(this.code,e,o1(this.options,t))}runInNewContext(e={},t=void 0){return tW(this.code,e,o1(this.options,t))}},Cwe={Script:bwe,compileFunction(){throw aG("compileFunction")},createContext:ZY,isContext:$Y,measureMemory(){throw aG("measureMemory")},runInContext:tR,runInNewContext:tW,runInThisContext:eW},rW=k1.default?.default??k1.default,AG=x1.default?.default??x1.default,nW=Sg.default?.request??Sg.default?.default?.request??Sg.default?.default??Sg.default,fG=eB.default?.fetch??eB.default?.default??eB.default,Qwe=yu.default?.Headers??yu.default?.default??yu.default,wwe=mu.default?.Request??mu.default?.default??mu.default,Swe=Bu.default?.Response??Bu.default?.default??Bu.default,uG=M2.default?.setGlobalDispatcher,cG=M2.default?.getGlobalDispatcher,a1=null;function _we(){return new rW({connections:6,connect(e,t){try{let r=e?.protocol==="https:"||e?.protocol==="https"?"https:":"http:",n=e?.hostname||e?.host||e?.servername||"localhost",i=e?.port;if(e?.origin){let p=new URL(String(e.origin));r=p.protocol==="https:"?"https:":"http:",n=p.hostname||n,i=p.port||i}typeof n=="string"&&n.startsWith("[")&&n.endsWith("]")&&(n=n.slice(1,-1));let s=eI({protocol:r,hostname:n,host:n,port:i?Number(i):r==="https:"?443:80,servername:e?.servername||n,rejectUnauthorized:e?.rejectUnauthorized}),o=cR(r),a=!1,A=()=>{s.off?.(o,f),s.removeListener?.(o,f),s.off?.("error",l),s.removeListener?.("error",l)},f=()=>{a||(a=!0,A(),t(null,s))},l=p=>{a||(a=!0,A(),t(p instanceof Error?p:new Error(String(p))))};return s.once(o,f),s.once("error",l),s}catch(r){return t(r instanceof Error?r:new Error(String(r))),null}}})}function W1(){return a1||(a1=_we()),a1}typeof uG=="function"&&typeof rW=="function"&&(typeof cG=="function"?cG():null)==null&&uG(W1());var rR="__secureExecNetSocket:",vwe="net-server:",Wg=new Map,CB=new Map,QB=new Map,Vg=new Map;function A1(e){return globalThis[`${rR}${e}`]}function lG(e,t){globalThis[`${rR}${e}`]=t,Wg.set(e,t)}function Rwe(e){delete globalThis[`${rR}${e}`],Wg.delete(e)}function _g(e){return!!e&&e._socketId!==0&&Wg.get(e._socketId)===e}function kg(e,t){if(e._bridgeReadPumpQueued){X("readPumpQueueCoalesced");return}e._bridgeReadPumpQueued=!0,queueMicrotask(()=>{e._bridgeReadPumpQueued=!1,!e.destroyed&&_g(e)&&e._socketId!==0&&(e._nextReadPumpOrigin=t,e._pumpBridgeReads())})}function iW(e){let t=e?._address;if(typeof t=="string")return t;let r=t?.path;return typeof r=="string"?r:void 0}function Dwe(e){e?._serverId&&Vg.set(e._serverId,e);let t=e?._address?.port;typeof t=="number"&&CB.set(t,e);let r=iW(e);typeof r=="string"&&QB.set(r,e)}function Twe(e){e?._serverId&&Vg.get(e._serverId)===e&&Vg.delete(e._serverId);let t=e?._address?.port;typeof t=="number"&&CB.get(t)===e&&CB.delete(t);let r=iW(e);typeof r=="string"&&QB.get(r)===e&&QB.delete(r)}function wB(e){if(X("readWakeAttempts"),!e||e.destroyed||e._socketId===0||e._loopbackServer||e._loopbackHttpTarget){X("readWakeInvalidTargets");return}if(e._pendingBridgeWake=!0,e._pendingBridgeWakeRetries=0,e._bridgeReadLoopRunning&&X("readWakeAlreadyRunning"),!e._bridgeReadPollTimer){X("readWakeNoTimer"),X(e._bridgeReadPumpStarted?"readWakeNoTimerAfterFirstPump":"readWakeNoTimerBeforeFirstPump"),e._connected&&X("readWakeNoTimerConnected"),e.connecting&&X("readWakeNoTimerConnecting"),X(e._refed?"readWakeNoTimerRefed":"readWakeNoTimerUnrefed");let t=(e._listeners?.data?.length??0)>0,r=(e._listeners?.readable?.length??0)>0;if(t&&X("readWakeNoTimerHasDataListener"),r&&X("readWakeNoTimerHasReadableListener"),e._bridgeWriteFlushScheduled&&(X("readWakeNoTimerPendingWriteFlush"),X("readWakeNoTimerPendingWriteBytes",e._pendingBridgeWriteBytes)),!e._bridgeReadPumpStarted&&e._firstReadNoTimerWakeAtUs===0&&It()&&(e._firstReadNoTimerWakeAtUs=At()),!e._bridgeReadPumpStarted&&e._connected&&e._refed&&(t||r))if(It()&&X("readFirstPumpScheduleCandidates"),e._bridgeReadFirstPumpBenchmarkScheduled)It()&&X("readFirstPumpScheduleAlreadyScheduled");else{It()&&X("readFirstPumpScheduleQueued"),e._bridgeReadFirstPumpBenchmarkScheduled=!0;let n=At();queueMicrotask(()=>{It()&&X("readFirstPumpScheduleRuns");let i=At(),s=Math.max(0,i-n);if(It()&&(X("readFirstPumpScheduleQueuedToRunUs",s),Qr("readFirstPumpScheduleQueuedToRunMaxUs",s)),e._bridgeReadFirstPumpBenchmarkScheduled=!1,e.destroyed){It()&&X("readFirstPumpScheduleSkipDestroyed");return}if(e._tlsUpgrading){It()&&X("readFirstPumpScheduleSkipTlsUpgrading");return}if(e._bridgeReadPumpStarted){It()&&X("readFirstPumpScheduleSkipPumpStarted");return}if(e._bridgeReadLoopRunning){It()&&X("readFirstPumpScheduleSkipLoopRunning");return}if(e._socketId===0){It()&&X("readFirstPumpScheduleSkipSocketClosed");return}It()&&X("readFirstPumpSchedulePumpCalls"),e._nextReadPumpOrigin="eventWake",e._readFirstPumpScheduleActive=!0,e._readFirstPumpScheduleQueuedAtUs=n,e._pumpBridgeReads()})}!e._bridgeReadLoopRunning&&e._connected&&e._refed&&kg(e,"eventWake");return}clearTimeout(e._bridgeReadPollTimer),e._bridgeReadPollTimer=null,X("readEventWakeups"),It()&&(e._readWakeQueuedAtUs=At()),kg(e,"eventWake")}function oB(e){if(X("peerWakeScans"),!e||e._socketId===0){X("peerWakeInvalidTargets");return}if(typeof e.remotePort=="number"&&typeof e.localPort=="number"){for(let i of Wg.values())if(!(i===e||i.destroyed)&&i.localPort===e.remotePort&&i.remotePort===e.localPort){X("peerWakeFound"),wB(i);return}X("peerWakeMiss");return}let t=typeof e.localPath=="string"?e.localPath:void 0,r=typeof e.remotePath=="string"?e.remotePath:void 0;if(t===void 0&&r===void 0){X("peerWakeInvalidTargets");return}let n=!1;for(let i of Wg.values()){if(i===e||i.destroyed)continue;let s=typeof i.localPath=="string"?i.localPath:void 0,o=typeof i.remotePath=="string"?i.remotePath:void 0;(t!==void 0&&r!==void 0&&s!==void 0&&o!==void 0&&s===r&&o===t||r!==void 0&&s!==void 0&&s===r||t!==void 0&&o!==void 0&&o===t)&&(n=!0,X("peerWakeUnixFound"),wB(i))}n||X("peerWakeUnixMiss")}function SB(e){if(X("acceptWakeAttempts"),!e||!e.listening||e._serverId===0||!e._acceptPollTimer){if(!e||!e.listening||e._serverId===0)X("acceptWakeInvalidTargets");else{e._pendingAcceptWake=!0,X("acceptWakeNoTimer"),X(e._acceptPumpStarted?"acceptWakeNoTimerAfterFirstPump":"acceptWakeNoTimerBeforeFirstPump"),e._acceptLoopRunning&&X("acceptWakeNoTimerLoopRunning"),e._acceptLoopActive&&X("acceptWakeNoTimerLoopActive"),X(e._refed?"acceptWakeNoTimerRefed":"acceptWakeNoTimerUnrefed");let t=e._connections?.size??0;X("acceptWakeNoTimerConnections",t),Qr("acceptWakeNoTimerConnectionsMax",t),!e._acceptPumpStarted&&e._firstAcceptNoTimerWakeAtUs===0&&It()&&(e._firstAcceptNoTimerWakeAtUs=At()),e._acceptLoopActive&&!e._acceptLoopRunning&&queueMicrotask(()=>{if(e.listening&&e._serverId!==0&&!e._acceptLoopRunning)return e._nextAcceptPumpOrigin="eventWake",e._pumpAccepts()})}return}e._acceptLoopRunning&&X("acceptWakeAlreadyRunning"),clearTimeout(e._acceptPollTimer),e._acceptPollTimer=null,X("acceptEventWakeups"),It()&&(e._acceptWakeQueuedAtUs=At()),queueMicrotask(()=>{if(e.listening&&e._serverId!==0)return e._nextAcceptPumpOrigin="eventWake",e._pumpAccepts()})}function Nwe(e){X("acceptWakeSocketScans");let t=e?.remotePort;if(typeof t=="number"){let i=CB.get(t);return X(i?"acceptWakeSocketFound":"acceptWakeSocketMiss"),i?._acceptLoopActive&&!i._acceptLoopRunning?(i._nextAcceptPumpOrigin="eventWake",i._pumpAccepts()):SB(i)}let r=e?.remotePath;if(typeof r!="string"){X("acceptWakeSocketInvalidTargets");return}let n=QB.get(r);return n?(X("acceptWakeSocketFound"),X("acceptWakeSocketUnixFound")):(X("acceptWakeSocketMiss"),X("acceptWakeSocketUnixMiss")),n?._acceptLoopActive&&!n._acceptLoopRunning?(n._nextAcceptPumpOrigin="eventWake",n._pumpAccepts()):SB(n)}function hG(e){return e===void 0?!0:!!e}function _B(e){return typeof e!="number"||!Number.isFinite(e)?0:Math.max(0,Math.floor(e/1e3))}function Mwe(e,t){return lr(`The "${e}" argument must be of type number. Received ${Yn(t)}`,"ERR_INVALID_ARG_TYPE")}function Pl(e,t){return lr(`The "${e}" argument must be of type function. Received ${Yn(t)}`,"ERR_INVALID_ARG_TYPE")}function Fwe(e){let t=new RangeError(`The value of "timeout" is out of range. It must be a non-negative finite number. Received ${String(e)}`);return t.code="ERR_OUT_OF_RANGE",t}function _l(e){return lr(e,"ERR_INVALID_ARG_VALUE")}function V1(e){let t=new RangeError(`options.port should be >= 0 and < 65536. Received ${Yn(e)}.`);return t.code="ERR_SOCKET_BAD_PORT",t}function J1(e){return Number.isInteger(e)&&e>=0&&e<65536}function sW(e){return/^[0-9]+$/.test(e)}function dG(e){if(e==null)return 0;if(typeof e=="string"&&e.length>0){let t=Number(e);if(J1(t))return t;throw V1(e)}if(typeof e=="number"){if(J1(e))return e;throw V1(e)}throw _l(`The argument 'options' is invalid. Received ${String(e)}`)}function oW(e,t,r,n){let i={port:0,host:"127.0.0.1",backlog:511,readableAll:!1,writableAll:!1};if(typeof e=="function")return{...i,callback:e};if(e!==null&&typeof e=="object"){let s=e,o=Object.prototype.hasOwnProperty.call(s,"port"),a=Object.prototype.hasOwnProperty.call(s,"path");if(!o&&!a)throw _l(`The argument 'options' must have the property "port" or "path". Received ${String(e)}`);if(o&&a)throw _l(`The argument 'options' is invalid. Received ${String(e)}`);if(o&&s.port!==void 0&&s.port!==null&&typeof s.port!="number"&&typeof s.port!="string")throw _l(`The argument 'options' is invalid. Received ${String(e)}`);if(a){if(typeof s.path!="string"||s.path.length===0)throw _l(`The argument 'options' is invalid. Received ${String(e)}`);return{path:s.path,backlog:typeof s.backlog=="number"&&Number.isFinite(s.backlog)?s.backlog:i.backlog,readableAll:s.readableAll===!0,writableAll:s.writableAll===!0,callback:typeof t=="function"?t:typeof r=="function"?r:n}}return{port:dG(s.port),host:typeof s.host=="string"&&s.host.length>0?s.host:i.host,backlog:typeof s.backlog=="number"&&Number.isFinite(s.backlog)?s.backlog:i.backlog,readableAll:!1,writableAll:!1,callback:typeof t=="function"?t:typeof r=="function"?r:n}}if(e!=null&&typeof e!="number"&&typeof e!="string")throw _l(`The argument 'options' is invalid. Received ${String(e)}`);return typeof e=="string"&&e.length>0&&!sW(e)?{path:e,backlog:i.backlog,readableAll:!1,writableAll:!1,callback:typeof t=="function"?t:typeof r=="function"?r:n}:{port:dG(e),host:typeof t=="string"?t:i.host,backlog:typeof r=="number"?r:i.backlog,readableAll:!1,writableAll:!1,callback:typeof t=="function"?t:typeof r=="function"?r:n}}function kwe(e,t,r){if(e!==null&&typeof e=="object"){let n=typeof e.port=="string"?Number(e.port):e.port;return{host:typeof e.host=="string"&&e.host.length>0?e.host:void 0,port:n,path:typeof e.path=="string"&&e.path.length>0?e.path:void 0,localAddress:typeof e.localAddress=="string"&&e.localAddress.length>0?e.localAddress:void 0,localPort:typeof e.localPort=="number"?e.localPort:void 0,keepAlive:e.keepAlive,keepAliveInitialDelay:e.keepAliveInitialDelay,callback:typeof t=="function"?t:r}}return typeof e=="string"&&!sW(e)?{path:e,callback:typeof t=="function"?t:r}:{port:typeof e=="number"?e:Number(e),host:typeof t=="string"?t:"127.0.0.1",callback:typeof t=="function"?t:r}}function xwe(e){if(!/^[0-9]{1,3}$/.test(e)||e.length>1&&e.startsWith("0"))return!1;let t=Number(e);return Number.isInteger(t)&&t>=0&&t<=255}function u0(e){let t=e.split(".");return t.length===4&&t.every(r=>xwe(r))}function Uwe(e){return e.length>0&&/^[0-9A-Za-z_.-]+$/.test(e)}function f1(e){if(e.length===0)return 0;let t=e.split(":"),r=0;for(let n of t){if(n.length===0)return null;if(n.includes(".")){if(n!==t[t.length-1]||!u0(n))return null;r+=2;continue}if(!/^[0-9A-Fa-f]{1,4}$/.test(n))return null;r+=1}return r}function $B(e){if(e.length===0)return!1;let t=e,r=t.indexOf("%");if(r!==-1){if(t.indexOf("%",r+1)!==-1)return!1;let s=t.slice(r+1);if(!Uwe(s))return!1;t=t.slice(0,r)}let n=t.indexOf("::");if(n!==-1){if(t.indexOf("::",n+2)!==-1)return!1;let[s,o]=t.split("::");if(s.includes("."))return!1;let a=f1(s),A=f1(o);return a===null||A===null?!1:a+A<8}return f1(t)===8}function Lwe(e){return e==null?"":String(e)}function Ml(e){let t=Lwe(e);return u0(t)?4:$B(t)?6:0}function vl(e,t){if(t==="ipv4"||t===4)return"ipv4";if(t==="ipv6"||t===6)return"ipv6";let r=Ml(e);if(r===4)return"ipv4";if(r===6)return"ipv6";throw new TypeError(`Invalid IP address: ${e}`)}function aW(e){return e.split(".").reduce((t,r)=>(t<<8n)+BigInt(Number(r)),0n)}function Pwe(e){let t=String(e),r=t.indexOf("%");if(r!==-1&&(t=t.slice(0,r)),t.includes(".")){let l=t.lastIndexOf(":"),p=t.slice(l+1),B=aW(p),S=Number(B>>16n&65535n).toString(16),_=Number(B&65535n).toString(16);t=`${t.slice(0,l)}:${S}:${_}`}let n=t.includes("::"),[i,s]=n?t.split("::"):[t,""],o=i.length>0?i.split(":"):[],a=s.length>0?s.split(":"):[],A=n?Math.max(0,8-(o.length+a.length)):0,f=[...o,...new Array(A).fill("0"),...a];if(f.length!==8)throw new TypeError(`Invalid IPv6 address: ${e}`);return f.map(l=>l.length===0?"0":l)}function Owe(e){return Pwe(e).reduce((t,r)=>(t<<16n)+BigInt(parseInt(r,16)),0n)}function Bg(e,t){return t==="ipv4"?aW(e):Owe(e)}function Hwe(e){return e.type==="address"?`Address: ${e.family==="ipv4"?"IPv4":"IPv6"} ${e.address}`:e.type==="range"?`Range: ${e.family==="ipv4"?"IPv4":"IPv6"} ${e.start}-${e.end}`:`Subnet: ${e.family==="ipv4"?"IPv4":"IPv6"} ${e.network}/${e.prefix}`}var qwe=class{constructor(){y(this,"_rules",[])}addAddress(e,t){let r=vl(e,t);return this._rules.push({type:"address",family:r,address:String(e)}),this}addRange(e,t,r){let n=vl(e,r);if(vl(t,n)!==n)throw new TypeError("BlockList range family mismatch");return this._rules.push({type:"range",family:n,start:String(e),end:String(t)}),this}addSubnet(e,t,r){let n=vl(e,r),i=Number(t),s=n==="ipv4"?32:128;if(!Number.isInteger(i)||i<0||i>s)throw new RangeError(`Invalid subnet prefix: ${t}`);return this._rules.push({type:"subnet",family:n,network:String(e),prefix:i}),this}check(e,t){let r=vl(e,t),n=Bg(String(e),r);for(let i of this._rules)if(i.family===r){if(i.type==="address"&&n===Bg(i.address,r))return!0;if(i.type==="range"){let s=Bg(i.start,r),o=Bg(i.end,r);if(n>=s&&n<=o)return!0}if(i.type==="subnet"){let s=r==="ipv4"?32n:128n,o=BigInt(i.prefix),a=s-o,A=o===0n?0n:(1n<({...e}))}fromJSON(e){if(!Array.isArray(e))throw new TypeError("BlockList JSON must be an array");return this._rules=e.map(t=>({...t})),this}get rules(){return this._rules.map(e=>Hwe(e))}},gG=!0,pG=250,Gwe=class vg{constructor(t={}){let r=String(t.address??""),n=vl(r,t.family),i=Number(t.port??0),s=Number(t.flowlabel??0);if(!Number.isInteger(i)||i<0||i>65535)throw new RangeError(`Invalid port: ${t.port}`);if(!Number.isInteger(s)||s<0)throw new RangeError(`Invalid flowlabel: ${t.flowlabel}`);this.address=r,this.port=i,this.family=n,this.flowlabel=s}toJSON(){return{address:this.address,port:this.port,family:this.family,flowlabel:this.flowlabel}}static isSocketAddress(t){return t instanceof vg}static parse(t){let r=String(t);if(r.startsWith("[")){let i=r.indexOf("]");if(i===-1)return;let s=r.slice(1,i),o=r[i+1]===":"?Number(r.slice(i+2)):0;return new vg({address:s,family:"ipv6",port:o})}let n=r.lastIndexOf(":");if(n!==-1&&r.indexOf(":")===n){let i=r.slice(0,n),s=Number(r.slice(n+1));if(Ml(i)!==0&&Number.isInteger(s))return new vg({address:i,port:s})}if(Ml(r)!==0)return new vg({address:r})}};function AW(e){if(typeof e!="number")throw Mwe("timeout",e);if(!Number.isFinite(e)||e<0)throw Fwe(e);return e}function fW(e){if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}function Ywe(e){if(!e)throw new Error("net.connect bridge returned an empty socket handle");if(typeof e=="string")return{socketId:e};if(typeof e=="object"&&(typeof e.socketId=="string"||typeof e.socketId=="number")||typeof e=="object"&&e.loopbackHttpTarget)return e;throw new Error("net.connect bridge returned an invalid socket handle")}function aB(e){if(e!=null){if(Array.isArray(e)){let t=e.map(r=>aB(r)).flatMap(r=>Array.isArray(r)?r:r?[r]:[]);return t.length>0?t:void 0}if(typeof e=="string")return{kind:"string",data:e};if(Buffer.isBuffer(e)||e instanceof Uint8Array)return{kind:"buffer",data:Buffer.from(e).toString("base64")}}}function j1(e){return!!e&&typeof e=="object"&&"__secureExecTlsContext"in e}function Wl(e,t){let n={...(j1(e?.secureContext)?e.secureContext.__secureExecTlsContext:void 0)??{},...t},i=aB(e?.key),s=aB(e?.cert),o=aB(e?.ca);if(i!==void 0&&(n.key=i),s!==void 0&&(n.cert=s),o!==void 0&&(n.ca=o),typeof e?.passphrase=="string"&&(n.passphrase=e.passphrase),typeof e?.ciphers=="string"&&(n.ciphers=e.ciphers),(Buffer.isBuffer(e?.session)||e?.session instanceof Uint8Array)&&(n.session=Buffer.from(e.session).toString("base64")),Array.isArray(e?.ALPNProtocols)){let a=e.ALPNProtocols.filter(A=>typeof A=="string");a.length>0&&(n.ALPNProtocols=a)}return typeof e?.minVersion=="string"&&(n.minVersion=e.minVersion),typeof e?.maxVersion=="string"&&(n.maxVersion=e.maxVersion),typeof e?.servername=="string"&&(n.servername=e.servername),typeof e?.rejectUnauthorized=="boolean"&&(n.rejectUnauthorized=e.rejectUnauthorized),typeof e?.requestCert=="boolean"&&(n.requestCert=e.requestCert),n}function Wwe(e){if(!e)return null;try{return JSON.parse(e)}catch{return null}}function Vwe(e){if(!e)return null;try{return JSON.parse(e)}catch{return null}}function Jwe(e){if(!e)return new Error("socket error");try{let t=JSON.parse(e),r=new Error(t.message);return t.name&&(r.name=t.name),t.code&&(r.code=t.code),t.stack&&(r.stack=t.stack),r}catch{return new Error(e)}}function z1(e,t=new Map){if(e===null||typeof e=="boolean"||typeof e=="number"||typeof e=="string")return e;if(e.type==="undefined")return;if(e.type==="buffer")return Buffer.from(e.data,"base64");if(e.type==="array")return e.value.map(n=>z1(n,t));if(e.type==="ref")return t.get(e.id);let r={};t.set(e.id,r);for(let[n,i]of Object.entries(e.value))r[n]=z1(i,t);return r}function ba(e,t,r){if(typeof _netSocketTlsQueryRaw>"u")return;let n=_netSocketTlsQueryRaw.applySync(void 0,r===void 0?[e,t]:[e,t,r]);return z1(JSON.parse(n))}function AB(e,t="secureConnect",r=!0){if(e._tlsUpgrading=!1,e.encrypted=!0,e.authorized=e.authorizationError==null,typeof e._socketId=="string"&&e._socketId.length>0){let n=ba(e._socketId,"getProtocol");(typeof n=="string"||n===null)&&(e._tlsProtocol=n);let i=ba(e._socketId,"getCipher");i!==void 0&&(e._tlsCipher=i);let s=ba(e._socketId,"isSessionReused");typeof s=="boolean"&&(e._tlsSessionReused=s)}e._touchTimeout(),e._emitNet(t),t!=="secure"&&e._emitNet("secure"),r&&!e.destroyed&&!e._bridgeReadLoopRunning&&(e._nextReadPumpOrigin="tls",e._pumpBridgeReads())}function EG(e){return{socketId:e,setNoDelay(t){return _netSocketSetNoDelayRaw?.applySync(void 0,[e,t!==!1]),this},setKeepAlive(t,r){return _netSocketSetKeepAliveRaw?.applySync(void 0,[e,t!==!1,_B(r)]),this},ref(){return this},unref(){return this}}}function jwe(e,t){return{socketId:e,info:t,setNoDelay(r){return _netSocketSetNoDelayRaw?.applySync(void 0,[e,r!==!1]),this},setKeepAlive(r,n){return _netSocketSetKeepAliveRaw?.applySync(void 0,[e,r!==!1,_B(n)]),this},ref(){return this},unref(){return this}}}var nR="__secure_exec_net_timeout__",vB=10,K1=null;function zwe(){return(typeof process<"u"?process.env:globalThis.__agentOSProcessConfigEnv)?.AGENTOS_NET_BRIDGE_TRACE==="1"}function Kwe(e){let t=Number(e);return!Number.isFinite(t)||t<0?vB:Math.trunc(t)}function iR(){return K1??vB}function Xwe(){let e=typeof process<"u"?process.env:void 0,t=globalThis.__agentOSProcessConfigEnv;return e?.AGENTOS_NET_RETAIN_OWNED_WRITE_BUFFER!=="0"&&t?.AGENTOS_NET_RETAIN_OWNED_WRITE_BUFFER!=="0"}function uW(){return{userWriteCalls:0,userWriteBytes:0,queuedWriteChunks:0,queuedWriteBytes:0,queuedWriteCopiedChunks:0,queuedWriteCopiedBytes:0,queuedWriteRetainedChunks:0,queuedWriteRetainedBytes:0,flushCalls:0,flushChunks:0,flushBytes:0,writeBufferedBytesMax:0,writeBufferedChunksMax:0,writeBase64EncodeCalls:0,writeBase64EncodeBytes:0,writeBase64EncodeUs:0,writeRawCalls:0,writeRawBytes:0,writeRawElapsedUs:0,readRawCalls:0,readRawElapsedUs:0,readPumpRuns:0,readTimeoutSentinels:0,readPollTimersScheduled:0,readPollTimerFires:0,readPollTimerFireLagUs:0,readPollTimerFireLagMaxUs:0,readDataEvents:0,readBytes:0,readBase64DecodeCalls:0,readBase64DecodeBytes:0,readBase64DecodeChars:0,readBase64DecodeUs:0,readPayloadMaterializeCalls:0,readPayloadMaterializeBytes:0,readPayloadMaterializeUs:0,readEndEvents:0,readMacrotaskYields:0,readMacrotaskYieldElapsedUs:0,readMacrotaskYieldMaxUs:0,queueReadablePayloads:0,queueReadablePayloadElapsedUs:0,queueReadablePayloadMaxUs:0,queueReadableBytes:0,queueReadableBytesMax:0,queueReadableImmediateReadCalls:0,queueReadableImmediateReadUs:0,queueReadableImmediateReadMaxUs:0,socketReadableEmits:0,socketReadableEmitUs:0,socketReadableEmitMaxUs:0,socketDataEmits:0,socketDataEmitUs:0,socketDataEmitMaxUs:0,readPostDeliveryProbeCalls:0,readPostDeliveryProbeTimeoutSentinels:0,readPostDeliveryProbeDataEvents:0,readPostDeliveryNextRawCalls:0,readPostDeliveryNextRawTimeoutSentinels:0,readPostDeliveryNextRawDataEvents:0,readPostDeliveryToProbeStartUs:0,readPostDeliveryProbeElapsedUs:0,readPostDeliveryProbeMaxUs:0,readPostDeliveryPendingWriteFlushes:0,readPostDeliveryPendingWriteBytes:0,userWriteDuringDataEmitCalls:0,dataEmitStartToUserWriteUs:0,dataEmitEndToUserWriteUs:0,writeQueuedToFlushStartUs:0,writeQueuedToFlushStartMaxUs:0,writeFlushQueuedToRawUs:0,writeFlushQueuedToRawMaxUs:0,readWakeQueuedToPumpStartUs:0,readWakeQueuedToPumpStartMaxUs:0,acceptWakeQueuedToPumpStartUs:0,acceptWakeQueuedToPumpStartMaxUs:0,socketEndEmits:0,socketCloseEmits:0,socketConnectEmits:0,acceptRawCalls:0,acceptRawElapsedUs:0,acceptPumpRuns:0,acceptLoopAlreadyRunning:0,acceptTimeoutSentinels:0,acceptPollTimersScheduled:0,acceptPollTimerFires:0,acceptPollTimerFireLagUs:0,acceptPollTimerFireLagMaxUs:0,acceptConnections:0,acceptJsonParseUs:0,acceptOnConnectionUs:0,connectionEmits:0,readEventWakeups:0,readWakeAttempts:0,readWakeInvalidTargets:0,readWakeAlreadyRunning:0,readWakeNoTimer:0,readWakeNoTimerBeforeFirstPump:0,readWakeNoTimerAfterFirstPump:0,readWakeNoTimerConnected:0,readWakeNoTimerConnecting:0,readWakeNoTimerRefed:0,readWakeNoTimerUnrefed:0,readWakeNoTimerHasDataListener:0,readWakeNoTimerHasReadableListener:0,readWakeNoTimerPendingWriteFlush:0,readWakeNoTimerPendingWriteBytes:0,readFirstPumpAfterNoTimerWakeCalls:0,readFirstPumpAfterNoTimerWakeUs:0,readFirstPumpAfterNoTimerWakeMaxUs:0,readFirstPumpOriginConnectWait:0,readFirstPumpOriginAcceptedHandle:0,readFirstPumpOriginEventWake:0,readFirstPumpOriginTimer:0,readFirstPumpOriginRef:0,readFirstPumpOriginTls:0,readFirstPumpOriginUnknown:0,readFirstPumpResultData:0,readFirstPumpResultEnd:0,readFirstPumpResultTimeout:0,readFirstPumpScheduleCandidates:0,readFirstPumpScheduleQueued:0,readFirstPumpScheduleAlreadyScheduled:0,readFirstPumpScheduleRuns:0,readFirstPumpSchedulePumpCalls:0,readFirstPumpScheduleSkipDestroyed:0,readFirstPumpScheduleSkipTlsUpgrading:0,readFirstPumpScheduleSkipPumpStarted:0,readFirstPumpScheduleSkipLoopRunning:0,readFirstPumpScheduleSkipSocketClosed:0,readFirstPumpScheduleQueuedToRunUs:0,readFirstPumpScheduleQueuedToRunMaxUs:0,readFirstPumpScheduleQueuedToPumpStartUs:0,readFirstPumpScheduleQueuedToPumpStartMaxUs:0,readFirstPumpScheduleResultData:0,readFirstPumpScheduleResultTimeout:0,readFirstPumpScheduleResultEnd:0,peerWakeScans:0,peerWakeInvalidTargets:0,peerWakeFound:0,peerWakeMiss:0,peerWakeUnixFound:0,peerWakeUnixMiss:0,peerWakeOnShutdown:0,peerWakeOnDestroy:0,acceptEventWakeups:0,acceptWakeAttempts:0,acceptWakeInvalidTargets:0,acceptWakeNoTimer:0,acceptWakeNoTimerBeforeFirstPump:0,acceptWakeNoTimerAfterFirstPump:0,acceptWakeNoTimerLoopRunning:0,acceptWakeNoTimerLoopActive:0,acceptWakeNoTimerRefed:0,acceptWakeNoTimerUnrefed:0,acceptWakeNoTimerConnections:0,acceptWakeNoTimerConnectionsMax:0,acceptFirstPumpAfterNoTimerWakeCalls:0,acceptFirstPumpAfterNoTimerWakeUs:0,acceptFirstPumpAfterNoTimerWakeMaxUs:0,acceptFirstPumpOriginListen:0,acceptFirstPumpOriginEventWake:0,acceptFirstPumpOriginTimer:0,acceptFirstPumpOriginRef:0,acceptFirstPumpOriginUnknown:0,acceptFirstPumpResultConnection:0,acceptFirstPumpResultTimeout:0,acceptFirstPumpResultEmpty:0,acceptWakeAlreadyRunning:0,acceptWakeSocketScans:0,acceptWakeSocketInvalidTargets:0,acceptWakeSocketFound:0,acceptWakeSocketMiss:0,acceptWakeSocketUnixFound:0,acceptWakeSocketUnixMiss:0,dgramWakeAttempts:0,dgramWakeInvalidTargets:0,dgramWakeAlreadyRunning:0,dgramWakeNoTimer:0,dgramEventWakeups:0,dgramWakeLoopbackHits:0,dgramWakeLoopbackMisses:0}}var X1=!1,Ol=uW();function It(){return X1||zwe()}function At(){return typeof __secureExecHrNowUs=="function"?Math.round(__secureExecHrNowUs()):typeof performance<"u"&&typeof performance.now=="function"?Math.round(performance.now()*1e3):Date.now()*1e3}function X(e,t=1){It()&&(Ol[e]=(Ol[e]??0)+t)}function Qr(e,t){if(!It())return;let r=Number(t);Number.isFinite(r)&&(Ol[e]=Math.max(Ol[e]??0,r))}function Zwe(e){switch(e){case"connectWait":X("readFirstPumpOriginConnectWait");break;case"acceptedHandle":X("readFirstPumpOriginAcceptedHandle");break;case"eventWake":X("readFirstPumpOriginEventWake");break;case"timer":X("readFirstPumpOriginTimer");break;case"ref":X("readFirstPumpOriginRef");break;case"tls":X("readFirstPumpOriginTls");break;default:X("readFirstPumpOriginUnknown");break}}function $we(e){switch(e){case"listen":X("acceptFirstPumpOriginListen");break;case"eventWake":X("acceptFirstPumpOriginEventWake");break;case"timer":X("acceptFirstPumpOriginTimer");break;case"ref":X("acceptFirstPumpOriginRef");break;default:X("acceptFirstPumpOriginUnknown");break}}Ge("__agentOSNetBridgeMetrics",{get enabled(){return It()},enable(){X1=!0},disable(){X1=!1},setPollDelayMs(e){K1=Kwe(e)},resetPollDelayMs(){K1=null},pollDelayMs(){return iR()},reset(){Ol=uW(),typeof _benchNetTcpMetricsResetRaw<"u"&&_benchNetTcpMetricsResetRaw.applySync(void 0,[])},snapshot(){let e;return typeof _benchNetTcpMetricsSnapshotRaw<"u"&&(e=_benchNetTcpMetricsSnapshotRaw.applySync(void 0,[])),{...Ol,...e?{sidecarNetTrace:e}:{}}}});function eSe(){return new Promise(e=>{typeof IB=="function"?IB(e):setTimeout(e,0)})}function tSe(e,t,r){if(e==="net_socket"&&t&&typeof t=="object"){let i=t;if(i.event==="accept"){let o=Vg.get(i.serverId);o&&SB(o);return}if(i.event==="dgram"){globalThis._dgramSocketDispatch?.(i);return}if(i.event==="http2"){globalThis._http2RetainDispatch?.(i);return}let s=A1(i.socketId);s&&(X("readEventWakeups"),wB(s));return}if(e&&typeof e=="object"){let i=e;if(i.event==="accept"){let o=Vg.get(i.serverId);o&&SB(o);return}if(i.event==="dgram"){globalThis._dgramSocketDispatch?.(i);return}if(i.event==="http2"){globalThis._http2RetainDispatch?.(i);return}let s=A1(i.socketId);s&&(X("readEventWakeups"),wB(s));return}if(e===0&&t.startsWith("http2:")){nr("http2 dispatch via netSocket",t);try{let i=r?JSON.parse(r):{};aR(t.slice(6),Number(i.id??0),i.data,i.extra,i.extraNumber,i.extraHeaders,i.flags)}catch{}return}let n=A1(e);if(n)switch(t){case"connect":{n._applySocketInfo(fW(r)),n._connected=!0,n.connecting=!1,n._touchTimeout(),n._emitNet("connect"),n._emitNet("ready");break}case"secureConnect":case"secure":{let i=Wwe(r);i&&(n.authorized=i.authorized===!0,n.authorizationError=i.authorizationError,n.alpnProtocol=i.alpnProtocol??!1,n.servername=i.servername??n.servername,n._tlsProtocol=i.protocol??null,n._tlsSessionReused=i.sessionReused===!0,n._tlsCipher=i.cipher??null),AB(n,t);break}case"data":{let i=typeof Buffer<"u"?Buffer.from(r,"base64"):new Uint8Array(0);n._touchTimeout(),n._emitNet("data",i);break}case"end":n._handleRemoteReadableEnd();break;case"session":{let i=typeof Buffer<"u"?Buffer.from(r??"","base64"):new Uint8Array(0);n._tlsSession=Buffer.from(i),n._emitNet("session",i);break}case"error":if(r)try{let i=JSON.parse(r);n.authorized=i.authorized===!0,n.authorizationError=i.authorizationError}catch{}n._emitNet("error",Jwe(r));break;case"close":n._emitSocketClose(!1);break}}Ge("_netSocketDispatch",tSe);var Vm=256*1024,To=class cW{constructor(t){y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_socketId",0);y(this,"_loopbackServer",null);y(this,"_loopbackBuffer",Buffer.alloc(0));y(this,"_loopbackDispatchRunning",!1);y(this,"_loopbackDispatchPending",!1);y(this,"_loopbackReadableEnded",!1);y(this,"_loopbackUpgradeSocket",null);y(this,"_loopbackEventQueue",Promise.resolve());y(this,"_encoding");y(this,"_noDelayState",!1);y(this,"_keepAliveState",!1);y(this,"_keepAliveDelaySeconds",0);y(this,"_refed",!0);y(this,"_bridgeReadLoopRunning",!1);y(this,"_bridgeReadPumpQueued",!1);y(this,"_bridgeReadPollTimer",null);y(this,"_pendingBridgeWake",!1);y(this,"_pendingBridgeWakeRetries",0);y(this,"_bridgeReadPumpStarted",!1);y(this,"_bridgeReadFirstPumpBenchmarkScheduled",!1);y(this,"_readFirstPumpScheduleActive",!1);y(this,"_readFirstPumpScheduleQueuedAtUs",0);y(this,"_nextReadPumpOrigin",null);y(this,"_firstReadNoTimerWakeAtUs",0);y(this,"_timeoutMs",0);y(this,"_timeoutTimer",null);y(this,"_pendingBridgeWriteChunks",null);y(this,"_pendingBridgeWriteCallbacks",null);y(this,"_pendingBridgeWriteBytes",0);y(this,"_bridgeWriteFlushScheduled",!1);y(this,"_bridgeWriteFlushQueuedAtUs",0);y(this,"_lastReadDeliveryEndUs",0);y(this,"_currentDataEmitStartUs",0);y(this,"_wroteDuringDataEmit",!1);y(this,"_lastDataEmitEndUs",0);y(this,"_readWakeQueuedAtUs",0);y(this,"_tlsUpgrading",!1);y(this,"_remoteEnded",!1);y(this,"_writableEnded",!1);y(this,"_closeEmitted",!1);y(this,"_bridgeReleased",!1);y(this,"_connected",!1);y(this,"connecting",!1);y(this,"destroyed",!1);y(this,"writable",!0);y(this,"readable",!0);y(this,"readyState","open");y(this,"readableLength",0);y(this,"writableLength",0);y(this,"remoteAddress");y(this,"remotePort");y(this,"remoteFamily");y(this,"localAddress","0.0.0.0");y(this,"localPort",0);y(this,"localFamily","IPv4");y(this,"localPath");y(this,"remotePath");y(this,"bytesRead",0);y(this,"bytesWritten",0);y(this,"bufferSize",0);y(this,"pending",!0);y(this,"allowHalfOpen",!1);y(this,"encrypted",!1);y(this,"authorized",!1);y(this,"authorizationError");y(this,"servername");y(this,"alpnProtocol",!1);y(this,"writableHighWaterMark",16*1024);y(this,"server");y(this,"_tlsCipher",null);y(this,"_tlsProtocol",null);y(this,"_tlsSession",null);y(this,"_tlsSessionReused",!1);y(this,"_readableState",{endEmitted:!1,ended:!1});y(this,"_readQueue",[]);y(this,"_handle",null);t?.allowHalfOpen&&(this.allowHalfOpen=!0),t?.handle&&(this._handle=t.handle)}connect(t,r,n){if(typeof _netSocketConnectRaw>"u")throw new Error("net.Socket is not supported in sandbox (bridge not available)");let{host:i="127.0.0.1",port:s=0,path:o,localAddress:a,localPort:A,keepAlive:f,keepAliveInitialDelay:l,callback:p}=kwe(t,r,n);p&&this.once("connect",p),this.connecting=!0,this.remoteAddress=o??i,this.remotePort=o?void 0:s,this.remotePath=o,this.pending=!1;let B;try{B=Ywe(_netSocketConnectRaw.applySync(void 0,[o?{path:o}:{host:i,port:s,localAddress:a,localPort:A}]))}catch(S){return this.connecting=!1,this.pending=!1,queueMicrotask(()=>{this.destroyed||this.destroy(S)}),this}return B.loopbackHttpTarget?(this._loopbackHttpTarget=B.loopbackHttpTarget,this._applySocketInfo(B),this._connected=!0,this.connecting=!1,queueMicrotask(()=>{this._touchTimeout(),this._emitNet("connect"),this._emitNet("ready")}),this):(nr("socket connect",B.socketId,i,s,o??null),this._socketId=B.socketId,this._handle=EG(this._socketId),this._applySocketInfo(B),lG(this._socketId,this),this._waitForConnect(),f&&this.once("connect",()=>{this.setKeepAlive(!0,l)}),this)}write(t,r,n){let i,s=!1;if(Buffer.isBuffer(t))i=t;else if(typeof t=="string"){let a=typeof r=="string"?r:"utf-8";i=Buffer.from(t,a),s=Xwe()}else i=Buffer.from(t);if(this._loopbackServer||this._loopbackHttpTarget){if(nr("socket write loopback",this._socketId,i.length),this.bytesWritten+=i.length,this._loopbackUpgradeSocket){this._touchTimeout(),this._loopbackUpgradeSocket._pushData(i);let A=typeof r=="function"?r:n;return A&&A(),!0}this._loopbackBuffer=Buffer.concat([this._loopbackBuffer,i]),this._touchTimeout(),this._dispatchLoopbackHttpRequest();let a=typeof r=="function"?r:n;return a&&a(),!0}if(typeof _netSocketWriteRaw>"u"||this.destroyed||!this._socketId)return!1;if(X("userWriteCalls"),X("userWriteBytes",i.length),It()){let a=At();this._currentDataEmitStartUs>0?(X("userWriteDuringDataEmitCalls"),X("dataEmitStartToUserWriteUs",a-this._currentDataEmitStartUs),this._wroteDuringDataEmit=!0):this._lastDataEmitEndUs>0&&X("dataEmitEndToUserWriteUs",a-this._lastDataEmitEndUs)}this.bytesWritten+=i.length;let o=typeof r=="function"?r:n;return this._queueBridgeWrite(i,o,s),!0}end(t,r,n){return typeof t=="function"?this.once("finish",t):t!=null&&this.write(t,r,n),this._writableEnded||this.destroyed?this:(this._writableEnded=!0,this.writable=!1,queueMicrotask(()=>{this.destroyed||(this._emitNet("finish"),this._remoteEnded&&this._emitSocketClose(!1))}),this._loopbackServer||this._loopbackHttpTarget?(this._loopbackUpgradeSocket?queueMicrotask(()=>{this._loopbackUpgradeSocket?._pushEnd()}):this._loopbackReadableEnded||queueMicrotask(()=>{this._closeLoopbackReadable()}),this):(typeof _netSocketEndRaw<"u"&&this._socketId&&!this.destroyed&&(this._flushBridgeWrites(),nr("socket end",this._socketId),_netSocketEndRaw.applySync(void 0,[this._socketId]),X("peerWakeOnShutdown"),oB(this),this._touchTimeout()),this))}destroy(t){return this.destroyed?this:(nr("socket destroy",this._socketId,t?.message??null),this.destroyed=!0,this._writableEnded=!0,this.writable=!1,this.readable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._clearTimeoutTimer(),this._bridgeReadPollTimer&&(clearTimeout(this._bridgeReadPollTimer),this._bridgeReadPollTimer=null),this._loopbackServer||this._loopbackHttpTarget?(this._loopbackUpgradeSocket?.destroy(t),this._loopbackUpgradeSocket=null,this._loopbackServer=null,this._loopbackHttpTarget=null,t&&this._emitNet("error",t),this._emitSocketClose(!!t),this):(this._releaseBridgeSocket(),t&&this._emitNet("error",t),this._emitSocketClose(!!t),this))}_queueBridgeWrite(t,r,n=!1){this._pendingBridgeWriteChunks||(this._pendingBridgeWriteChunks=[],this._pendingBridgeWriteCallbacks=[]);let i=n?t:Buffer.from(t);this._pendingBridgeWriteChunks.push(i),this._pendingBridgeWriteBytes+=i.length,X("queuedWriteChunks"),X("queuedWriteBytes",i.length),n?(X("queuedWriteRetainedChunks"),X("queuedWriteRetainedBytes",i.length)):(X("queuedWriteCopiedChunks"),X("queuedWriteCopiedBytes",i.length)),Qr("writeBufferedBytesMax",this._pendingBridgeWriteBytes),Qr("writeBufferedChunksMax",this._pendingBridgeWriteChunks.length),r&&this._pendingBridgeWriteCallbacks.push(r),this._currentDataEmitStartUs>0?(X("writeFlushInlineDuringDataEmit"),this._flushBridgeWrites()):this._bridgeWriteFlushScheduled||(this._bridgeWriteFlushScheduled=!0,It()&&(this._bridgeWriteFlushQueuedAtUs=At()),queueMicrotask(()=>{this._flushBridgeWrites()}))}_flushBridgeWrites(){let t=this._pendingBridgeWriteChunks;if(!t||t.length===0){this._bridgeWriteFlushScheduled=!1,this._bridgeWriteFlushQueuedAtUs=0;return}let r=this._pendingBridgeWriteCallbacks??[],n=this._pendingBridgeWriteBytes;if(this._pendingBridgeWriteChunks=null,this._pendingBridgeWriteCallbacks=null,this._pendingBridgeWriteBytes=0,this._bridgeWriteFlushScheduled=!1,this.destroyed||!this._socketId||typeof _netSocketWriteRaw>"u")return;let i=It();if(i&&this._bridgeWriteFlushQueuedAtUs>0){let f=Math.max(0,At()-this._bridgeWriteFlushQueuedAtUs);X("writeQueuedToFlushStartUs",f),Qr("writeQueuedToFlushStartMaxUs",f),X("writeFlushQueuedToRawUs",f),Qr("writeFlushQueuedToRawMaxUs",f),this._bridgeWriteFlushQueuedAtUs=0}nr("socket write",this._socketId,n,t.length),X("flushCalls"),X("flushChunks",t.length),X("flushBytes",n);let s=i?At():0,o=[],a=0,A=()=>{if(a===0)return;let f=o.length===1?o[0]:Buffer.concat(o,a);X("writeRawCalls"),X("writeRawBytes",f.length),_netSocketWriteRaw.applySync(void 0,[this._socketId,f]),o=[],a=0};for(let f of t)for(let l=0;l0&&a+p.length>Vm&&A(),o.push(p),a+=p.length,a>=Vm&&A()}A(),i&&X("writeRawElapsedUs",At()-s),oB(this),this._touchTimeout();for(let f of r)f()}_emitSocketClose(t=!1){this._closeEmitted||(this._closeEmitted=!0,this._connected=!1,this.connecting=!1,this.pending=!1,this.readable=!1,this.writable=!1,this._clearTimeoutTimer(),this._socketId&&Rwe(this._socketId),this.readableLength>0?this._deferBridgeReleaseUntilReadDrained=!0:this._releaseBridgeSocket(),this._emitNet("close",t))}_releaseDeferredBridgeSocket(){!this._deferBridgeReleaseUntilReadDrained||this.readableLength>0||(this._deferBridgeReleaseUntilReadDrained=!1,this._releaseBridgeSocket())}_releaseBridgeSocket(){if(!(this._bridgeReleased||!this._socketId||typeof _netSocketDestroyRaw>"u")){this._bridgeReleased=!0;try{_netSocketDestroyRaw.applySync(void 0,[this._socketId])}catch{}X("peerWakeOnDestroy"),oB(this)}}_handleRemoteReadableEnd(){this.destroyed||this._remoteEnded||(nr("socket remote end",this._socketId),this._remoteEnded=!0,this.readable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,queueMicrotask(()=>{if(!this.destroyed&&(this._emitNet("end"),!this.destroyed)){if(!this.allowHalfOpen&&!this._writableEnded){this.end();return}this._writableEnded&&this._emitSocketClose(!1)}}))}_applySocketInfo(t){t&&(this.localAddress=t.localAddress,this.localPort=t.localPort,this.localFamily=t.localFamily,this.localPath=t.localPath,this.remoteAddress=t.remoteAddress??this.remoteAddress,this.remotePort=t.remotePort??this.remotePort,this.remoteFamily=t.remoteFamily??this.remoteFamily,this.remotePath=t.remotePath??this.remotePath)}_applyAcceptedKeepAlive(t){this._keepAliveState=!0,this._keepAliveDelaySeconds=_B(t)}static fromAcceptedHandle(t,r){let n=new cW({allowHalfOpen:r?.allowHalfOpen});return n._socketId=t.socketId,n._handle=EG(t.socketId),n._applySocketInfo(t.info),n._connected=!0,n.connecting=!1,n.pending=!1,lG(t.socketId,n),queueMicrotask(()=>{!n.destroyed&&!n._tlsUpgrading&&(n._nextReadPumpOrigin="acceptedHandle",n._pumpBridgeReads())}),n}setKeepAlive(t,r){let n=hG(t),i=_B(r);return n===this._keepAliveState&&(!n||i===this._keepAliveDelaySeconds)?this:(this._keepAliveState=n,this._keepAliveDelaySeconds=n?i:0,nr("socket setKeepAlive",this._socketId,n,i),this._handle?.setKeepAlive?.(n,i),this)}setNoDelay(t){let r=hG(t);return r===this._noDelayState?this:(this._noDelayState=r,nr("socket setNoDelay",this._socketId,r),this._handle?.setNoDelay?.(r),this)}setTimeout(t,r){let n=AW(t);if(r!==void 0&&typeof r!="function")throw Pl("callback",r);return r&&this.once("timeout",r),this._timeoutMs=n,n===0?(this._clearTimeoutTimer(),this):(this._touchTimeout(),this)}ref(){return this._refed=!0,this._handle?.ref?.(),this._timeoutTimer&&typeof this._timeoutTimer.ref=="function"&&this._timeoutTimer.ref(),!this.destroyed&&this._connected&&!this._loopbackServer&&!this._loopbackHttpTarget&&!this._bridgeReadLoopRunning&&(this._nextReadPumpOrigin="ref",this._pumpBridgeReads()),this}unref(){return this._refed=!1,this._handle?.unref?.(),this._timeoutTimer&&typeof this._timeoutTimer.unref=="function"&&this._timeoutTimer.unref(),this._bridgeReadPollTimer&&(clearTimeout(this._bridgeReadPollTimer),this._bridgeReadPollTimer=null),this}pause(){return this}resume(){return this}read(t){if(this._readQueue.length===0)return null;let r;if(t==null||t<=0)r=this._readQueue.shift()??null,r&&(this.readableLength=Math.max(0,this.readableLength-r.length));else{let n=this._readQueue[0];if(!n)return null;n.length<=t?(this._readQueue.shift(),this.readableLength=Math.max(0,this.readableLength-n.length),r=n):(r=n.subarray(0,t),this._readQueue[0]=n.subarray(t),this.readableLength=Math.max(0,this.readableLength-r.length))}return this.readableLength===0&&this._releaseDeferredBridgeSocket(),r}unshift(t){let r=Buffer.isBuffer(t)?t:Buffer.from(t);return r.length===0?this:(this._readQueue.unshift(r),this.readableLength+=r.length,this)}cork(){}uncork(){}address(){return{port:this.localPort,family:this.localFamily,address:this.localAddress}}getCipher(){return ba(this._socketId,"getCipher")??this._tlsCipher}getSession(){let t=ba(this._socketId,"getSession");return Buffer.isBuffer(t)?(this._tlsSession=Buffer.from(t),Buffer.from(t)):this._tlsSession?Buffer.from(this._tlsSession):null}isSessionReused(){let t=ba(this._socketId,"isSessionReused");return typeof t=="boolean"?t:this._tlsSessionReused}getPeerCertificate(t){let r=ba(this._socketId,"getPeerCertificate",t===!0);return r&&typeof r=="object"?r:{}}getCertificate(){let t=ba(this._socketId,"getCertificate");return t&&typeof t=="object"?t:{}}getProtocol(){let t=ba(this._socketId,"getProtocol");return typeof t=="string"?t:this._tlsProtocol}setEncoding(t){return this._encoding=t,this}pipe(t){return t}on(t,r){return this._listeners[t]||(this._listeners[t]=[]),this._listeners[t].push(r),this}addListener(t,r){return this.on(t,r)}once(t,r){return this._onceListeners[t]||(this._onceListeners[t]=[]),this._onceListeners[t].push(r),this}removeListener(t,r){let n=this._listeners[t];if(n){let s=n.indexOf(r);s>=0&&n.splice(s,1)}let i=this._onceListeners[t];if(i){let s=i.indexOf(r);s>=0&&i.splice(s,1)}return this}off(t,r){return this.removeListener(t,r)}removeAllListeners(t){return t?(delete this._listeners[t],delete this._onceListeners[t]):(this._listeners={},this._onceListeners={}),this}listeners(t){return[...this._listeners[t]??[],...this._onceListeners[t]??[]]}listenerCount(t){return(this._listeners[t]?.length??0)+(this._onceListeners[t]?.length??0)}setMaxListeners(t){return this}getMaxListeners(){return 10}prependListener(t,r){return this._listeners[t]||(this._listeners[t]=[]),this._listeners[t].unshift(r),this}prependOnceListener(t,r){return this._onceListeners[t]||(this._onceListeners[t]=[]),this._onceListeners[t].unshift(r),this}eventNames(){return[...new Set([...Object.keys(this._listeners),...Object.keys(this._onceListeners)])]}rawListeners(t){return this.listeners(t)}emit(t,...r){return this._emitNet(t,...r)}_emitNet(t,...r){let n=It()&&(t==="readable"||t==="data"),i=n?At():0;n&&t==="data"&&(this._currentDataEmitStartUs=i),t==="readable"?X("socketReadableEmits"):t==="data"?X("socketDataEmits"):t==="end"?X("socketEndEmits"):t==="close"?X("socketCloseEmits"):t==="connect"&&X("socketConnectEmits"),t==="data"&&this._encoding&&r[0]&&Buffer.isBuffer(r[0])&&(r[0]=r[0].toString(this._encoding));let s=!1;try{let o=this._listeners[t];if(o)for(let A of[...o])A.call(this,...r),s=!0;let a=this._onceListeners[t];if(a){let A=[...a];this._onceListeners[t]=[];for(let f of A)f.call(this,...r),s=!0}}finally{if(n){let o=At()-i;t==="readable"?(X("socketReadableEmitUs",o),Qr("socketReadableEmitMaxUs",o)):t==="data"&&(X("socketDataEmitUs",o),Qr("socketDataEmitMaxUs",o),this._lastDataEmitEndUs=At(),this._currentDataEmitStartUs=0)}}return s}_queueReadablePayload(t){if(!t||t.length===0)return;let r=It(),n=r?At():0;try{if(this._readQueue.push(t),this.readableLength+=t.length,X("queueReadablePayloads"),X("queueReadableBytes",t.length),Qr("queueReadableBytesMax",this.readableLength),this._emitNet("readable"),this.listenerCount("data")>0){let i=r?At():0,s=this.read();if(r){let o=At()-i;X("queueReadableImmediateReadCalls"),X("queueReadableImmediateReadUs",o),Qr("queueReadableImmediateReadMaxUs",o)}s!==null&&this._emitNet("data",s)}}finally{if(r){let i=At()-n;X("queueReadablePayloadElapsedUs",i),Qr("queueReadablePayloadMaxUs",i)}}}async _waitForConnect(){if(!(typeof _netSocketWaitConnectRaw>"u"||this._socketId===0))try{let t=await _netSocketWaitConnectRaw.apply(void 0,[this._socketId],{result:{promise:!0}});if(this.destroyed)return;this._applySocketInfo(fW(t)),await Nwe(this),this._connected=!0,this.connecting=!1,nr("socket connected",this._socketId,this.localAddress,this.localPort,this.remoteAddress,this.remotePort),this._touchTimeout(),nr("socket emit connect",this._socketId,this.listenerCount("connect")),this._emitNet("connect"),nr("socket emit ready",this._socketId,this.listenerCount("ready")),this._emitNet("ready"),this._tlsUpgrading||(this._nextReadPumpOrigin="connectWait",await this._pumpBridgeReads())}catch(t){if(this.destroyed)return;let r=t instanceof Error?t:new Error(String(t));nr("socket connect error",this._socketId,r.message,r.stack??null),this._emitNet("error",r),this.destroy()}}async _pumpBridgeReads(){if(this._bridgeReadLoopRunning||typeof _netSocketReadRaw>"u"||!_g(this))return;X("readPumpRuns");let t=!this._bridgeReadPumpStarted,r=this._readFirstPumpScheduleActive===!0;if(t){if(Zwe(this._nextReadPumpOrigin),this._firstReadNoTimerWakeAtUs>0&&It()){let o=Math.max(0,At()-this._firstReadNoTimerWakeAtUs);X("readFirstPumpAfterNoTimerWakeCalls"),X("readFirstPumpAfterNoTimerWakeUs",o),Qr("readFirstPumpAfterNoTimerWakeMaxUs",o)}if(r&&this._readFirstPumpScheduleQueuedAtUs>0&&It()){let o=Math.max(0,At()-this._readFirstPumpScheduleQueuedAtUs);X("readFirstPumpScheduleQueuedToPumpStartUs",o),Qr("readFirstPumpScheduleQueuedToPumpStartMaxUs",o)}}this._readFirstPumpScheduleActive=!1,this._readFirstPumpScheduleQueuedAtUs=0,this._nextReadPumpOrigin=null,this._bridgeReadPumpStarted=!0;let n=!1,i=!1;if(It()&&this._readWakeQueuedAtUs>0){let o=Math.max(0,At()-this._readWakeQueuedAtUs);X("readWakeQueuedToPumpStartUs",o),Qr("readWakeQueuedToPumpStartMaxUs",o),this._readWakeQueuedAtUs=0}this._bridgeReadLoopRunning=!0;let s=0;try{for(;!this.destroyed&&_g(this);){X("readRawCalls");let o=It(),a=o&&this._lastReadDeliveryEndUs>0?At():0;if(a>0&&(X("readPostDeliveryProbeCalls"),X("readPostDeliveryNextRawCalls"),X("readPostDeliveryToProbeStartUs",a-this._lastReadDeliveryEndUs),this._bridgeWriteFlushScheduled&&(X("readPostDeliveryPendingWriteFlushes"),X("readPostDeliveryPendingWriteBytes",this._pendingBridgeWriteBytes)),this._lastReadDeliveryEndUs=0),!_g(this))return;let A=o?At():0,f=_netSocketReadRaw.applySync(void 0,[this._socketId]);if(o){let p=At()-A;X("readRawElapsedUs",p),a>0&&(X("readPostDeliveryProbeElapsedUs",p),Qr("readPostDeliveryProbeMaxUs",p))}if(this.destroyed)return;if(f===nR){if(t&&!n&&(n=!0,X("readFirstPumpResultTimeout")),r&&!i&&(i=!0,X("readFirstPumpScheduleResultTimeout")),X("readTimeoutSentinels"),a>0&&(X("readPostDeliveryProbeTimeoutSentinels"),X("readPostDeliveryNextRawTimeoutSentinels")),!this._refed)return;if(this._pendingBridgeWake){if(this._pendingBridgeWakeRetries<2){this._pendingBridgeWakeRetries++,X("readPendingWakeImmediateRetries"),this._nextReadPumpOrigin="eventWake",await Promise.resolve();continue}this._pendingBridgeWake=!1,this._pendingBridgeWakeRetries=0,X("readPendingWakeShortRetryTimers"),this._bridgeReadPollTimer=setTimeout(()=>{this._bridgeReadPollTimer=null,this._nextReadPumpOrigin="eventWake",this._pumpBridgeReads()},1);return}X("readPollTimersScheduled");let p=iR(),B=It()?At():0;this._bridgeReadPollTimer=setTimeout(()=>{if(It()){let S=Math.max(0,At()-B-p*1e3);X("readPollTimerFires"),X("readPollTimerFireLagUs",S),Qr("readPollTimerFireLagMaxUs",S)}this._bridgeReadPollTimer=null,this._nextReadPumpOrigin="timer",this._pumpBridgeReads()},p);return}if(f===null){t&&!n&&(n=!0,X("readFirstPumpResultEnd")),r&&!i&&(i=!0,X("readFirstPumpScheduleResultEnd")),X("readEndEvents"),this._pendingBridgeWake=!1,this._pendingBridgeWakeRetries=0,this._handleRemoteReadableEnd();return}a>0&&(X("readPostDeliveryProbeDataEvents"),X("readPostDeliveryNextRawDataEvents")),t&&!n&&(n=!0,X("readFirstPumpResultData")),r&&!i&&(i=!0,X("readFirstPumpScheduleResultData"));let l;if(typeof f=="string"){let p=o?At():0;l=Buffer.from(f,"base64"),o&&(X("readBase64DecodeCalls"),X("readBase64DecodeBytes",l.length),X("readBase64DecodeChars",f.length),X("readBase64DecodeUs",At()-p))}else{let p=o?At():0;l=Buffer.from(f),o&&(X("readPayloadMaterializeCalls"),X("readPayloadMaterializeBytes",l.length),X("readPayloadMaterializeUs",At()-p))}if(nr("socket data",this._socketId,l.length),X("readDataEvents"),X("readBytes",l.length),this.bytesRead+=l.length,this._touchTimeout(),s>0){X("readMacrotaskYields");let p=o?At():0;if(await eSe(),o){let B=At()-p;X("readMacrotaskYieldElapsedUs",B),Qr("readMacrotaskYieldMaxUs",B)}if(this.destroyed)return}else X("readFirstPayloadImmediateDeliveries");if(this._pendingBridgeWake=!1,this._pendingBridgeWakeRetries=0,s++,this._queueReadablePayload(l),this._wroteDuringDataEmit){this._wroteDuringDataEmit=!1,X("readPumpYieldAfterInlineDataWrite"),kg(this,"postDeliveryInlineWrite");return}if(this._bridgeWriteFlushScheduled){X("readPumpYieldToPendingWriteFlush"),kg(this,"postDeliveryWriteFlush");return}o&&(this._lastReadDeliveryEndUs=At())}}finally{this._bridgeReadLoopRunning=!1,this._pendingBridgeWake&&!this.destroyed&&_g(this)&&kg(this,"eventWake")}}_dispatchLoopbackHttpRequest(){if(!(!this._loopbackServer&&!this._loopbackHttpTarget||this.destroyed)){if(this._loopbackDispatchRunning){this._loopbackDispatchPending=!0;return}this._loopbackDispatchRunning=!0,this._processLoopbackHttpRequests().finally(()=>{this._loopbackDispatchRunning=!1,this._loopbackDispatchPending&&this._loopbackBuffer.length>0?(this._loopbackDispatchPending=!1,this._dispatchLoopbackHttpRequest()):this._loopbackDispatchPending=!1})}}async _processLoopbackHttpRequests(){let t=!1;for(;(this._loopbackServer||this._loopbackHttpTarget)&&!this.destroyed;){let r=this._loopbackServer??{listenerCount:()=>0},n=FW(this._loopbackBuffer,r);if(n.kind==="incomplete"){t&&this._closeLoopbackReadable();return}if(n.kind==="bad-request"){this._pushLoopbackData(a2()),n.closeConnection&&this._closeLoopbackReadable(),this._loopbackBuffer=Buffer.alloc(0);return}if(this._loopbackBuffer=this._loopbackBuffer.subarray(n.bytesConsumed),n.upgradeHead){this._dispatchLoopbackUpgrade(n.request,n.upgradeHead);return}let i;if(this._loopbackHttpTarget){if(typeof _networkHttpServerRequestRaw>"u")throw new Error("HTTP loopback bridge is not available");i=_networkHttpServerRequestRaw.applySync(void 0,[{...this._loopbackHttpTarget,request:JSON.stringify(n.request)}])}else({responseJson:i}=await u_e(this._loopbackServer,n.request));let s=JSON.parse(i),o=hR(s,n.request,n.closeConnection);if(!t&&o.payload.length>0&&this._pushLoopbackData(o.payload),o.closeConnection&&(t=!0,this._loopbackBuffer.length===0)){this._closeLoopbackReadable();return}}}_pushLoopbackData(t){if(t.length===0||this._loopbackReadableEnded)return;let r=Buffer.from(t);this._queueLoopbackEvent(()=>{this.destroyed||(this.bytesRead+=r.length,this._touchTimeout(),this._queueReadablePayload(r))})}_closeLoopbackReadable(){this._loopbackReadableEnded||(this._loopbackReadableEnded=!0,this.readable=!1,this.writable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._clearTimeoutTimer(),this._queueLoopbackEvent(()=>{this._emitNet("end"),this._emitNet("close")}))}_queueLoopbackEvent(t){this._loopbackEventQueue=this._loopbackEventQueue.then(()=>new Promise(r=>{queueMicrotask(()=>{try{t()}finally{r()}})}))}_dispatchLoopbackUpgrade(t,r){if(this._loopbackServer)try{let n=new GSe({host:this.remoteAddress,port:this.remotePort});n._attachPeer({_pushData:i=>this._pushLoopbackData(i),_pushEnd:()=>this._closeLoopbackReadable()}),this._loopbackUpgradeSocket=n,this._loopbackServer._emit("upgrade",new Nu(t),n,r)}catch(n){let i=n instanceof Error?n:new Error(String(n)),s=!1,o=null;if(typeof process<"u"&&typeof process.emit=="function"){let a=process;try{s=a.emit("uncaughtException",i,"uncaughtException")}catch(A){if(A&&typeof A=="object"&&A.name==="ProcessExitError"){s=!0;let f=Number(A.code);o=Number.isFinite(f)?f:0}else throw A}}if(s){o!==null&&(process.exitCode=o),this._loopbackServer?.close(),this.destroy();return}throw i}}_upgradeTls(t){if(typeof _netSocketUpgradeTlsRaw>"u")throw new Error("tls.connect is not supported in sandbox (bridge not available)");if(this._tlsUpgrading=!0,this._loopbackServer&&(typeof this._socketId!="string"||this._socketId.length===0)){queueMicrotask(()=>{this.destroyed||AB(this)});return}_netSocketUpgradeTlsRaw.applySync(void 0,[this._socketId,JSON.stringify(t??{})]);let r=()=>{this.destroyed||AB(this)};t?.isServer?queueMicrotask(r):setTimeout(()=>{this.destroyed||AB(this,"secureConnect",!1)},0)}_touchTimeout(){this._timeoutMs===0||this.destroyed||(this._clearTimeoutTimer(),this._timeoutTimer=setTimeout(()=>{this._timeoutTimer=null,!this.destroyed&&this._emitNet("timeout")},this._timeoutMs),!this._refed&&typeof this._timeoutTimer.unref=="function"&&this._timeoutTimer.unref())}_clearTimeoutTimer(){this._timeoutTimer&&(clearTimeout(this._timeoutTimer),this._timeoutTimer=null)}};function Z1(e,t,r){let n=new To;return n.connect(e,t,r),n}var Jg=class{constructor(e,t){y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_serverId",0);y(this,"_address",null);y(this,"_acceptLoopActive",!1);y(this,"_acceptLoopRunning",!1);y(this,"_acceptPollTimer",null);y(this,"_pendingAcceptWake",!1);y(this,"_acceptPumpStarted",!1);y(this,"_nextAcceptPumpOrigin",null);y(this,"_firstAcceptNoTimerWakeAtUs",0);y(this,"_acceptWakeQueuedAtUs",0);y(this,"_handleRefId",null);y(this,"_connections",new Set);y(this,"_refed",!0);y(this,"listening",!1);y(this,"keepAlive",!1);y(this,"keepAliveInitialDelay",0);y(this,"allowHalfOpen",!1);y(this,"maxConnections");y(this,"_handle");typeof e=="function"?this.on("connection",e):(this.allowHalfOpen=e?.allowHalfOpen===!0,this.keepAlive=e?.keepAlive===!0,this.keepAliveInitialDelay=e?.keepAliveInitialDelay??0,t&&this.on("connection",t)),this._handle={onconnection:(r,n)=>{if(r){this._emit("error",r);return}if(!n)return;if(typeof this.maxConnections=="number"&&this.maxConnections>=0&&this._connections.size>=this.maxConnections){this._emit("drop",{localAddress:n.info.localAddress,localPort:n.info.localPort,localFamily:n.info.localFamily,remoteAddress:n.info.remoteAddress,remotePort:n.info.remotePort,remoteFamily:n.info.remoteFamily}),_netSocketDestroyRaw?.applySync(void 0,[n.socketId]),X("peerWakeOnDestroy"),oB({_socketId:n.socketId,localPort:n.info.localPort,remotePort:n.info.remotePort,localPath:n.info.localPath,remotePath:n.info.remotePath});return}this.keepAlive&&n.setKeepAlive?.(!0,this.keepAliveInitialDelay);let i=To.fromAcceptedHandle(n,{allowHalfOpen:this.allowHalfOpen});i.server=this,this._connections.add(i),i.once("close",()=>{this._connections.delete(i)}),this.keepAlive&&i._applyAcceptedKeepAlive(this.keepAliveInitialDelay),X("connectionEmits"),this._emit("connection",i)}}}listen(e,t,r,n){if(typeof _netServerListenRaw>"u"||typeof _netServerAcceptRaw>"u")throw new Error("net.createServer is not supported in sandbox");let{port:i,host:s,path:o,backlog:a,readableAll:A,writableAll:f,callback:l}=oW(e,t,r,n);l&&this.once("listening",l);try{let p=_netServerListenRaw.applySyncPromise(void 0,[{port:i,host:s,path:o,backlog:a,readableAll:A,writableAll:f}]),B=typeof p=="string"?JSON.parse(p):p,S=B.address??B;this._serverId=B.serverId,this._address=S.localPath?S.localPath:{address:S.localAddress,family:S.localFamily??S.family,port:S.localPort},this.listening=!0,Dwe(this),this._syncHandleRef(),this._acceptLoopActive=!0,queueMicrotask(()=>{!this.listening||this._serverId===0||(this._emit("listening"),this._nextAcceptPumpOrigin="listen",this._pumpAccepts())})}catch(p){queueMicrotask(()=>{this._emit("error",p)})}return this}close(e){if(e&&this.once("close",e),!this.listening||typeof _netServerCloseRaw>"u")return queueMicrotask(()=>{this._emit("close")}),this;this.listening=!1,this._acceptLoopActive=!1,Twe(this),this._acceptPollTimer&&(clearTimeout(this._acceptPollTimer),this._acceptPollTimer=null),this._syncHandleRef();let t=this._serverId;return this._serverId=0,(async()=>{try{await _netServerCloseRaw.apply(void 0,[t],{result:{promise:!0}})}finally{this._address=null,this._emit("close")}})(),this}address(){return this._address}getConnections(e){if(typeof e!="function")throw Pl("callback",e);return queueMicrotask(()=>{e(null,this._connections.size)}),this}ref(){return this._refed=!0,this._syncHandleRef(),this.listening&&this._acceptLoopActive&&!this._acceptLoopRunning&&(this._nextAcceptPumpOrigin="ref",this._pumpAccepts()),this}unref(){return this._refed=!1,this._acceptPollTimer&&(clearTimeout(this._acceptPollTimer),this._acceptPollTimer=null),this._syncHandleRef(),this}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this}emit(e,...t){return this._emit(e,...t)}_emit(e,...t){let r=!1,n=this._listeners[e];if(n)for(let s of[...n])s.call(this,...t),r=!0;let i=this._onceListeners[e];if(i){this._onceListeners[e]=[];for(let s of[...i])s.call(this,...t),r=!0}return r}_syncHandleRef(){if(!this.listening||this._serverId===0||!this._refed){this._handleRefId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleRefId),this._handleRefId=null;return}let e=`${vwe}${this._serverId}`;this._handleRefId!==e&&(this._handleRefId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleRefId),this._handleRefId=e,typeof _registerHandle=="function"&&_registerHandle(this._handleRefId,"net server"))}async _pumpAccepts(){if(typeof _netServerAcceptRaw>"u"||this._acceptLoopRunning){this._acceptLoopRunning&&X("acceptLoopAlreadyRunning");return}X("acceptPumpRuns");let e=!this._acceptPumpStarted;if(e&&($we(this._nextAcceptPumpOrigin),this._firstAcceptNoTimerWakeAtUs>0&&It())){let r=Math.max(0,At()-this._firstAcceptNoTimerWakeAtUs);X("acceptFirstPumpAfterNoTimerWakeCalls"),X("acceptFirstPumpAfterNoTimerWakeUs",r),Qr("acceptFirstPumpAfterNoTimerWakeMaxUs",r)}this._nextAcceptPumpOrigin=null,this._acceptPumpStarted=!0;let t=!1;if(It()&&this._acceptWakeQueuedAtUs>0){let r=Math.max(0,At()-this._acceptWakeQueuedAtUs);X("acceptWakeQueuedToPumpStartUs",r),Qr("acceptWakeQueuedToPumpStartMaxUs",r),this._acceptWakeQueuedAtUs=0}this._acceptLoopRunning=!0;try{for(;this._acceptLoopActive&&this._serverId!==0;){X("acceptRawCalls");let r=It(),n=r?At():0,i=_netServerAcceptRaw.applySync(void 0,[this._serverId]);if(r&&X("acceptRawElapsedUs",At()-n),i===nR){if(e&&!t&&(t=!0,X("acceptFirstPumpResultTimeout")),X("acceptTimeoutSentinels"),!this._refed)return;if(this._pendingAcceptWake){this._pendingAcceptWake=!1,this._nextAcceptPumpOrigin="eventWake";continue}X("acceptPollTimersScheduled");let s=iR(),o=It()?At():0;this._acceptPollTimer=setTimeout(()=>{if(It()){let a=Math.max(0,At()-o-s*1e3);X("acceptPollTimerFires"),X("acceptPollTimerFireLagUs",a),Qr("acceptPollTimerFireLagMaxUs",a)}this._acceptPollTimer=null,this._nextAcceptPumpOrigin="timer",this._pumpAccepts()},s);return}if(!i){e&&!t&&(t=!0,X("acceptFirstPumpResultEmpty"));return}try{let s=r?At():0,o=JSON.parse(i);r&&X("acceptJsonParseUs",At()-s),X("acceptConnections"),e&&!t&&(t=!0,X("acceptFirstPumpResultConnection"));let a=jwe(o.socketId,o.info),A=r?At():0;this._handle.onconnection(null,a),r&&X("acceptOnConnectionUs",At()-A)}catch(s){this._emit("error",s)}}}finally{this._acceptLoopRunning=!1,this._pendingAcceptWake&&this.listening&&this._serverId!==0&&(this._pendingAcceptWake=!1,this._nextAcceptPumpOrigin="eventWake",queueMicrotask(()=>{this.listening&&this._serverId!==0&&this._pumpAccepts()}))}}};function rSe(e,t){return new Jg(e,t)}var lW={BlockList:qwe,Socket:To,SocketAddress:Gwe,Server:rSe,Stream:To,connect:Z1,createConnection:Z1,createServer(e,t){return new Jg(e,t)},getDefaultAutoSelectFamily(){return gG},getDefaultAutoSelectFamilyAttemptTimeout(){return pG},isIP(e){return Ml(e)},isIPv4(e){return Ml(e)===4},isIPv6(e){return Ml(e)===6},setDefaultAutoSelectFamily(e){gG=e!==!1},setDefaultAutoSelectFamilyAttemptTimeout(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw new RangeError(`Invalid auto-select family attempt timeout: ${e}`);pG=Math.trunc(t)}},nSe=Symbol.for("secure-exec.http2.kSocket"),yG=Symbol("options"),_s=new Map,Bn=new Map,bn=new Map,RB=new Map,u1=new Set,$1=[],e2=new Map,c1=!1,Ta=new Map,iSe=1,Tu=class{constructor(){y(this,"_listeners",{});y(this,"_onceListeners",{})}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}addListener(e,t){return this.on(e,t)}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this}removeListener(e,t){let r=n=>{if(!n)return;let i=n.indexOf(t);i!==-1&&n.splice(i,1)};return r(this._listeners[e]),r(this._onceListeners[e]),this}off(e,t){return this.removeListener(e,t)}listenerCount(e){return(this._listeners[e]?.length??0)+(this._onceListeners[e]?.length??0)}setMaxListeners(e){return this}emit(e,...t){let r=!1,n=this._listeners[e];if(n)for(let s of[...n])s.call(this,...t),r=!0;let i=this._onceListeners[e];if(i){this._onceListeners[e]=[];for(let s of[...i])s.call(this,...t),r=!0}return r}},t2=class extends Tu{constructor(t,r){super();y(this,"allowHalfOpen",!1);y(this,"encrypted",!1);y(this,"localAddress","127.0.0.1");y(this,"localPort",0);y(this,"localFamily","IPv4");y(this,"remoteAddress","127.0.0.1");y(this,"remotePort",0);y(this,"remoteFamily","IPv4");y(this,"servername");y(this,"alpnProtocol",!1);y(this,"readable",!0);y(this,"writable",!0);y(this,"destroyed",!1);y(this,"_bridgeReadPollTimer",null);y(this,"_loopbackServer",null);y(this,"_onDestroy");y(this,"_destroyCallbackInvoked",!1);this._onDestroy=r,this._applyState(t)}_applyState(t){t&&(this.allowHalfOpen=t.allowHalfOpen===!0,this.encrypted=t.encrypted===!0,this.localAddress=t.localAddress??this.localAddress,this.localPort=t.localPort??this.localPort,this.localFamily=t.localFamily??this.localFamily,this.remoteAddress=t.remoteAddress??this.remoteAddress,this.remotePort=t.remotePort??this.remotePort,this.remoteFamily=t.remoteFamily??this.remoteFamily,this.servername=t.servername,this.alpnProtocol=t.alpnProtocol??this.alpnProtocol)}_clearTimeoutTimer(){}_emitNet(t,r){if(t==="error"&&r){this.emit("error",r);return}t==="close"&&(this._destroyCallbackInvoked||(this._destroyCallbackInvoked=!0,queueMicrotask(()=>{this._onDestroy?.()})),this.emit("close"))}end(){return this.destroyed=!0,this.readable=!1,this.writable=!1,this.emit("close"),this}destroy(){return this.destroyed?this:(this.destroyed=!0,this.readable=!1,this.writable=!1,this._emitNet("close"),this)}};function Hl(e,t,r){return lr(`The "${e}" argument must be of type ${t}. Received ${Yn(r)}`,"ERR_INVALID_ARG_TYPE")}function Qo(e,t){return MB(t,e)}function Rg(e,t){let r=new RangeError(`Invalid value for setting "${e}": ${String(t)}`);return r.code="ERR_HTTP2_INVALID_SETTING_VALUE",r}function sSe(e,t){let r=new TypeError(`Invalid value for setting "${e}": ${String(t)}`);return r.code="ERR_HTTP2_INVALID_SETTING_VALUE",r}var So={NGHTTP2_NO_ERROR:0,NGHTTP2_PROTOCOL_ERROR:1,NGHTTP2_INTERNAL_ERROR:2,NGHTTP2_FLOW_CONTROL_ERROR:3,NGHTTP2_SETTINGS_TIMEOUT:4,NGHTTP2_STREAM_CLOSED:5,NGHTTP2_FRAME_SIZE_ERROR:6,NGHTTP2_REFUSED_STREAM:7,NGHTTP2_CANCEL:8,NGHTTP2_COMPRESSION_ERROR:9,NGHTTP2_CONNECT_ERROR:10,NGHTTP2_ENHANCE_YOUR_CALM:11,NGHTTP2_INADEQUATE_SECURITY:12,NGHTTP2_HTTP_1_1_REQUIRED:13,NGHTTP2_NV_FLAG_NONE:0,NGHTTP2_NV_FLAG_NO_INDEX:1,NGHTTP2_ERR_DEFERRED:-508,NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE:-509,NGHTTP2_ERR_STREAM_CLOSED:-510,NGHTTP2_ERR_INVALID_ARGUMENT:-501,NGHTTP2_ERR_FRAME_SIZE_ERROR:-522,NGHTTP2_ERR_NOMEM:-901,NGHTTP2_FLAG_NONE:0,NGHTTP2_FLAG_END_STREAM:1,NGHTTP2_FLAG_END_HEADERS:4,NGHTTP2_FLAG_ACK:1,NGHTTP2_FLAG_PADDED:8,NGHTTP2_FLAG_PRIORITY:32,NGHTTP2_DEFAULT_WEIGHT:16,NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:1,NGHTTP2_SETTINGS_ENABLE_PUSH:2,NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:3,NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:4,NGHTTP2_SETTINGS_MAX_FRAME_SIZE:5,NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:6,NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:8},oSe={[So.NGHTTP2_ERR_DEFERRED]:"Data deferred",[So.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE]:"Stream ID is not available",[So.NGHTTP2_ERR_STREAM_CLOSED]:"Stream was already closed or invalid",[So.NGHTTP2_ERR_INVALID_ARGUMENT]:"Invalid argument",[So.NGHTTP2_ERR_FRAME_SIZE_ERROR]:"Frame size error",[So.NGHTTP2_ERR_NOMEM]:"Out of memory"},hW=class extends Error{constructor(t){super(t);y(this,"code","ERR_HTTP2_ERROR");this.name="Error"}};function dW(e){return oSe[e]??`HTTP/2 error (${String(e)})`}function l1(e,t){return lr(`The property 'options.${e}' is invalid. Received ${aSe(t)}`,"ERR_INVALID_ARG_VALUE")}function aSe(e){return typeof e=="function"?`[Function${e.name?`: ${e.name}`:": function"}]`:typeof e=="symbol"?e.toString():Array.isArray(e)?"[]":e===null?"null":typeof e=="object"?"{}":String(e)}function ASe(e){return Qo("ERR_HTTP2_PAYLOAD_FORBIDDEN",`Responses with ${String(e)} status must not have a payload`)}var fSe=61440,uSe=16384,cSe=32768,lSe=4096,hSe=49152,dSe=40960;function gSe(e){let t=e.atimeMs??0,r=e.mtimeMs??t,n=e.ctimeMs??r,i=e.birthtimeMs??n,s=e.mode&fSe;return{size:e.size,mode:e.mode,atimeMs:t,mtimeMs:r,ctimeMs:n,birthtimeMs:i,atime:new Date(t),mtime:new Date(r),ctime:new Date(n),birthtime:new Date(i),isFile:()=>s===cSe,isDirectory:()=>s===uSe,isFIFO:()=>s===lSe,isSocket:()=>s===hSe,isSymbolicLink:()=>s===dSe}}function pSe(e){let t=e??{},r=t.offset;if(r!==void 0&&(typeof r!="number"||!Number.isFinite(r)))throw l1("offset",r);let n=t.length;if(n!==void 0&&(typeof n!="number"||!Number.isFinite(n)))throw l1("length",n);let i=t.statCheck;if(i!==void 0&&typeof i!="function")throw l1("statCheck",i);let s=t.onError;return{offset:r===void 0?0:Math.max(0,Math.trunc(r)),length:typeof n=="number"?Math.trunc(n):void 0,statCheck:typeof i=="function"?i:void 0,onError:typeof s=="function"?s:void 0}}function ESe(e,t,r){let n=Math.max(0,Math.min(t,e.length));return r===void 0||r<0?e.subarray(n):e.subarray(n,Math.min(e.length,n+r))}var gW=class{constructor(e){y(this,"_streamId");this._streamId=e}respond(e){if(typeof _networkHttp2StreamRespondRaw>"u")throw new Error("http2 server stream respond bridge is not available");return _networkHttp2StreamRespondRaw.applySync(void 0,[this._streamId,sR(e)]),0}},r2={headerTableSize:4096,enablePush:!0,initialWindowSize:65535,maxFrameSize:16384,maxConcurrentStreams:4294967295,maxHeaderListSize:65535,maxHeaderSize:65535,enableConnectProtocol:!1},pW={effectiveLocalWindowSize:65535,localWindowSize:65535,remoteWindowSize:65535,nextStreamID:1,outboundQueueSize:1,deflateDynamicTableSize:0,inflateDynamicTableSize:0};function Wi(e){let t={};for(let[r,n]of Object.entries(e??{})){if(r==="customSettings"&&n&&typeof n=="object"){let i={};for(let[s,o]of Object.entries(n))i[Number(s)]=Number(o);t.customSettings=i;continue}t[r]=n}return t}function mG(e){return{...pW,...e??{}}}function ySe(e){if(!e||typeof e!="object")return;let t=e,r={},n=["effectiveLocalWindowSize","localWindowSize","remoteWindowSize","nextStreamID","outboundQueueSize","deflateDynamicTableSize","inflateDynamicTableSize"];for(let i of n)typeof t[i]=="number"&&(r[i]=t[i]);return r}function EW(e,t="settings"){if(!e||typeof e!="object"||Array.isArray(e))throw Hl(t,"object",e);let r=e,n={},i={headerTableSize:[0,4294967295],initialWindowSize:[0,4294967295],maxFrameSize:[16384,16777215],maxConcurrentStreams:[0,4294967295],maxHeaderListSize:[0,4294967295],maxHeaderSize:[0,4294967295]};for(let[s,o]of Object.entries(r))if(o!==void 0){if(s==="enablePush"||s==="enableConnectProtocol"){if(typeof o!="boolean")throw sSe(s,o);n[s]=o;continue}if(s==="customSettings"){if(!o||typeof o!="object"||Array.isArray(o))throw Rg(s,o);let a={};for(let[A,f]of Object.entries(o)){let l=Number(A);if(!Number.isInteger(l)||l<0||l>65535||typeof f!="number"||!Number.isInteger(f)||f<0||f>4294967295)throw Rg(s,o);a[l]=f}n.customSettings=a;continue}if(s in i){let[a,A]=i[s];if(typeof o!="number"||!Number.isInteger(o)||oA)throw Rg(s,o);n[s]=o;continue}n[s]=o}return n}function sR(e){return JSON.stringify(e??{})}function FA(e){if(!e)return{};try{let t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}function xg(e){if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}function BG(e){if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}function DB(e){if(!e)return new Error("Unknown HTTP/2 bridge error");try{let t=JSON.parse(e),r=new Error(t.message??"Unknown HTTP/2 bridge error");return t.name&&(r.name=t.name),t.code&&(r.code=t.code),r}catch{return new Error(e)}}function yW(e){let t={};if(!e||typeof e!="object")return t;for(let[r,n]of Object.entries(e))t[String(r)]=n;return t}function mSe(e){if(!e)return;let t={endStream:"boolean",weight:"number",parent:"number",exclusive:"boolean",silent:"boolean"};for(let[r,n]of Object.entries(t)){if(!(r in e)||e[r]===void 0)continue;let i=e[r];if(n==="boolean"&&typeof i!="boolean")throw Hl(r,"boolean",i);if(n==="number"&&typeof i!="number")throw Hl(r,"number",i)}}function BSe(e){if(!e||!e.settings||typeof e.settings!="object")return;let t=e.settings;if("maxFrameSize"in t){let r=t.maxFrameSize;if(typeof r!="number"||!Number.isInteger(r)||r<16384||r>16777215)throw Rg("maxFrameSize",r)}}function oR(e,t){t&&(e.encrypted=t.encrypted===!0,e.alpnProtocol=t.alpnProtocol??(e.encrypted?"h2":"h2c"),e.originSet=Array.isArray(t.originSet)&&t.originSet.length>0?[...t.originSet]:e.encrypted?[]:void 0,t.localSettings&&typeof t.localSettings=="object"&&(e.localSettings=Wi(t.localSettings)),t.remoteSettings&&typeof t.remoteSettings=="object"&&(e.remoteSettings=Wi(t.remoteSettings)),t.state&&typeof t.state=="object"&&e._applyRuntimeState(ySe(t.state)),e.socket._applyState(t.socket))}function ISe(e,t){if(e instanceof URL)return e;if(typeof e=="string")return new URL(e);if(e&&typeof e=="object"){let r=e,n=typeof(t?.protocol??r.protocol)=="string"?String(t?.protocol??r.protocol):"http:",i=typeof(t?.host??r.host??t?.hostname??r.hostname)=="string"?String(t?.host??r.host??t?.hostname??r.hostname):"localhost",s=t?.port??r.port,o=s===void 0?"":String(s);return new URL(`${n}//${i}${o?`:${o}`:""}`)}return new URL("http://localhost")}function bSe(e,t,r){let n=typeof t=="function"?t:typeof r=="function"?r:void 0,i=typeof t=="function"?{}:t??{};return{authority:ISe(e,i),options:i,listener:n}}function CSe(e){if(!e||typeof e!="object")return;let t=e._socketId;return typeof t=="number"&&Number.isFinite(t)?t:void 0}var mW=class extends Tu{constructor(t,r,n=!1){super();y(this,"_streamId");y(this,"_encoding");y(this,"_utf8Remainder");y(this,"_isPushStream");y(this,"_session");y(this,"_receivedResponse",!1);y(this,"_needsDrain",!1);y(this,"_pendingWritableBytes",0);y(this,"_drainScheduled",!1);y(this,"_writableHighWaterMark",16*1024);y(this,"rstCode",0);y(this,"readable",!0);y(this,"writable",!0);y(this,"writableEnded",!1);y(this,"writableFinished",!1);y(this,"destroyed",!1);y(this,"_writableState",{ended:!1,finished:!1,objectMode:!1,corked:0,length:0});this._streamId=t,this._session=r,this._isPushStream=n,n||queueMicrotask(()=>{this.emit("ready")})}setEncoding(t){return this._encoding=t,this._utf8Remainder=this._encoding==="utf8"||this._encoding==="utf-8"?Buffer.alloc(0):void 0,this}close(){return this.end(),this}destroy(t){return this.destroyed?this:(this.destroyed=!0,t&&this.emit("error",t),this.end(),this)}_scheduleDrain(){!this._needsDrain||this._drainScheduled||(this._drainScheduled=!0,queueMicrotask(()=>{this._drainScheduled=!1,this._needsDrain&&(this._needsDrain=!1,this._pendingWritableBytes=0,this.emit("drain"))}))}write(t,r,n){if(typeof _networkHttp2StreamWriteRaw>"u")throw new Error("http2 session stream write bridge is not available");let i=Buffer.isBuffer(t)?t:typeof t=="string"?Buffer.from(t,typeof r=="string"?r:"utf8"):Buffer.from(t),s=_networkHttp2StreamWriteRaw.applySync(void 0,[this._streamId,i.toString("base64")]);this._pendingWritableBytes+=i.byteLength;let o=s===!1||this._pendingWritableBytes>=this._writableHighWaterMark;return o&&(this._needsDrain=!0),(typeof r=="function"?r:n)?.(),!o}end(t){if(typeof _networkHttp2StreamEndRaw>"u")throw new Error("http2 session stream end bridge is not available");let r=null;return t!==void 0&&(r=(Buffer.isBuffer(t)?t:Buffer.from(t)).toString("base64")),_networkHttp2StreamEndRaw.applySync(void 0,[this._streamId,r]),this.writableEnded=!0,this._writableState.ended=!0,queueMicrotask(()=>{this.writable=!1,this.writableFinished=!0,this._writableState.finished=!0,this.emit("finish")}),this}resume(){return this}_emitPush(t,r){process.env.SECURE_EXEC_DEBUG_HTTP2_BRIDGE==="1"&&console.error("[secure-exec http2 isolate] push",this._streamId),this.emit("push",t,r??0)}_hasReceivedResponse(){return this._receivedResponse}_belongsTo(t){return this._session===t}_emitResponseHeaders(t){this._receivedResponse=!0,process.env.SECURE_EXEC_DEBUG_HTTP2_BRIDGE==="1"&&console.error("[secure-exec http2 isolate] response headers",this._streamId,this._isPushStream),this._isPushStream||this.emit("response",t)}_emitDataChunk(t){if(!t)return;let r=Buffer.from(t,"base64");if(this._utf8Remainder!==void 0){let n=this._utf8Remainder.length>0?Buffer.concat([this._utf8Remainder,r]):r,i=QSe(n),s=n.subarray(0,i).toString("utf8");this._utf8Remainder=i0&&this.emit("data",s)}else this._encoding?this.emit("data",r.toString(this._encoding)):this.emit("data",r);this._scheduleDrain()}_emitEnd(){if(this._utf8Remainder&&this._utf8Remainder.length>0){let t=this._utf8Remainder.toString("utf8");this._utf8Remainder=Buffer.alloc(0),t.length>0&&this.emit("data",t)}this.readable=!1,this.emit("end"),this._scheduleDrain()}_emitClose(t){typeof t=="number"&&(this.rstCode=t),this.destroyed=!0,this.readable=!1,this.writable=!1,this._scheduleDrain(),this.emit("close")}};function QSe(e){if(e.length===0)return 0;let t=0;for(let r=e.length-1;r>=0&&t<3;r-=1){if((e[r]&192)!==128){let n=e.length-r,i=e[r],s=(i&128)===0?1:(i&224)===192?2:(i&240)===224?3:(i&248)===240?4:1;return n0?e.length-t:e.length}var wSe=class BW extends Tu{constructor(r,n,i,s=!1){super();y(this,"_streamId");y(this,"_binding");y(this,"_responded",!1);y(this,"_endQueued",!1);y(this,"_pendingSyntheticErrorSuppressions",0);y(this,"_requestHeaders");y(this,"_isPushStream");y(this,"session");y(this,"rstCode",0);y(this,"readable",!0);y(this,"writable",!0);y(this,"destroyed",!1);y(this,"_readableState");y(this,"_writableState");this._streamId=r,this._binding=new gW(r),this.session=n,this._requestHeaders=i,this._isPushStream=s,this._readableState={flowing:null,ended:!1,highWaterMark:16*1024},this._writableState={ended:i?.[":method"]==="HEAD"}}_closeWithCode(r){this.rstCode=r,_networkHttp2StreamCloseRaw?.applySync(void 0,[this._streamId,r])}_markSyntheticClose(){this.destroyed=!0,this.readable=!1,this.writable=!1}_shouldSuppressHostError(){return this._pendingSyntheticErrorSuppressions<=0?!1:(this._pendingSyntheticErrorSuppressions-=1,!0)}_emitNghttp2Error(r){let n=new hW(dW(r));this._pendingSyntheticErrorSuppressions+=1,this._markSyntheticClose(),this.emit("error",n),this._closeWithCode(So.NGHTTP2_INTERNAL_ERROR)}_emitInternalStreamError(){let r=Qo("ERR_HTTP2_STREAM_ERROR","Stream closed with error code NGHTTP2_INTERNAL_ERROR");this._pendingSyntheticErrorSuppressions+=1,this._markSyntheticClose(),this.emit("error",r),this._closeWithCode(So.NGHTTP2_INTERNAL_ERROR)}_submitResponse(r){this._responded=!0;let n=this._binding.respond(r);return typeof n=="number"&&n!==0?(this._emitNghttp2Error(n),!1):!0}respond(r){if(this.destroyed)throw Qo("ERR_HTTP2_INVALID_STREAM","The stream has been destroyed");if(this._responded)throw Qo("ERR_HTTP2_HEADERS_SENT","Response has already been initiated.");this._submitResponse(r)}pushStream(r,n,i){if(this._isPushStream)throw Qo("ERR_HTTP2_NESTED_PUSH","A push stream cannot initiate another push stream.");let s=typeof n=="function"?n:i;if(typeof s!="function")throw Hl("callback","function",s);if(typeof _networkHttp2StreamPushStreamRaw>"u")throw new Error("http2 server stream push bridge is not available");let o=n&&typeof n=="object"&&!Array.isArray(n)?n:{},a=_networkHttp2StreamPushStreamRaw.applySync(void 0,[this._streamId,sR(yW(r)),JSON.stringify(o??{})]),A=JSON.parse(a);if(A.error){s(DB(A.error));return}let f=new BW(Number(A.streamId),this.session,FA(A.headers),!0);bn.set(Number(A.streamId),f),s(null,f,FA(A.headers))}write(r){if(this._writableState.ended)return queueMicrotask(()=>{this.emit("error",Qo("ERR_STREAM_WRITE_AFTER_END","write after end"))}),!1;if(typeof _networkHttp2StreamWriteRaw>"u")throw new Error("http2 server stream write bridge is not available");let n=Buffer.isBuffer(r)?r:Buffer.from(r);return _networkHttp2StreamWriteRaw.applySync(void 0,[this._streamId,n.toString("base64")])}end(r){if(!this._responded&&!this._submitResponse({":status":200})||this._endQueued)return;if(typeof _networkHttp2StreamEndRaw>"u")throw new Error("http2 server stream end bridge is not available");this._writableState.ended=!0;let n=null;r!==void 0&&(n=(Buffer.isBuffer(r)?r:Buffer.from(r)).toString("base64")),this._endQueued=!0,queueMicrotask(()=>{!this._endQueued||this.destroyed||(this._endQueued=!1,_networkHttp2StreamEndRaw.applySync(void 0,[this._streamId,n]))})}pause(){return this._readableState.flowing=!1,_networkHttp2StreamPauseRaw?.applySync(void 0,[this._streamId]),this}resume(){return this._readableState.flowing=!0,_networkHttp2StreamResumeRaw?.applySync(void 0,[this._streamId]),this}respondWithFile(r,n,i){if(this.destroyed)throw Qo("ERR_HTTP2_INVALID_STREAM","The stream has been destroyed");if(this._responded)throw Qo("ERR_HTTP2_HEADERS_SENT","Response has already been initiated.");let s=pSe(i),o={...n??{}},a=o[":status"];if(a===204||a===205||a===304)throw ASe(Number(a));try{let A=Lt.stat.applySyncPromise(void 0,[r]),f=Lt.readFileBinary.applySyncPromise(void 0,[r]),l=gSe(Ma(A)),p={offset:s.offset,length:s.length??Math.max(0,l.size-s.offset)};s.statCheck?.(l,o,p);let B=Buffer.from(f,"base64"),S=ESe(B,s.offset,s.length);if(o["content-length"]===void 0&&(o["content-length"]=S.byteLength),!this._submitResponse({":status":200,...o}))return;this.end(S);return}catch{}if(typeof _networkHttp2StreamRespondWithFileRaw>"u")throw new Error("http2 server stream respondWithFile bridge is not available");this._responded=!0,_networkHttp2StreamRespondWithFileRaw.applySync(void 0,[this._streamId,r,JSON.stringify(n??{}),JSON.stringify(i??{})])}respondWithFD(r,n,i){let s=typeof r=="number"?r:typeof r?.fd=="number"?r.fd:NaN,o=Number.isFinite(s)?xA.applySync(void 0,[s]):null;if(!o){this._emitInternalStreamError();return}this.respondWithFile(o,n,i)}destroy(r){return this.destroyed?this:(this.destroyed=!0,r&&this.emit("error",r),this._closeWithCode(So.NGHTTP2_CANCEL),this)}_emitData(r){r&&this.emit("data",Buffer.from(r,"base64"))}_emitEnd(){this._readableState.ended=!0,this.emit("end")}_emitDrain(){this.emit("drain")}_emitClose(r){typeof r=="number"&&(this.rstCode=r),this.destroyed=!0,this.emit("close")}},IW=class extends Tu{constructor(t,r,n){super();y(this,"headers");y(this,"method");y(this,"url");y(this,"connection");y(this,"socket");y(this,"stream");y(this,"destroyed",!1);y(this,"readable",!0);y(this,"_readableState",{flowing:null,length:0,ended:!1,objectMode:!1});this.headers=t,this.method=typeof t[":method"]=="string"?String(t[":method"]):"GET",this.url=typeof t[":path"]=="string"?String(t[":path"]):"/",this.connection=r,this.socket=r,this.stream=n}on(t,r){return super.on(t,r),t==="data"&&this._readableState.flowing!==!1&&this.resume(),this}once(t,r){return super.once(t,r),t==="data"&&this._readableState.flowing!==!1&&this.resume(),this}resume(){return this._readableState.flowing=!0,this.stream.resume(),this}pause(){return this._readableState.flowing=!1,this.stream.pause(),this}pipe(t){return this.on("data",r=>{t.write(r)===!1&&typeof t.once=="function"&&(this.pause(),t.once("drain",()=>this.resume()))}),this.on("end",()=>t.end()),this.resume(),t}unpipe(){return this}read(){return null}isPaused(){return this._readableState.flowing===!1}setEncoding(){return this}_emitData(t){this._readableState.length+=t.byteLength,this.emit("data",t)}_emitEnd(){this._readableState.ended=!0,this.emit("end"),this.emit("close")}_emitError(t){this.emit("error",t)}destroy(t){return this.destroyed=!0,t&&this.emit("error",t),this.emit("close"),this}},bW=class extends Tu{constructor(t){super();y(this,"_stream");y(this,"_headers",{});y(this,"_statusCode",200);y(this,"headersSent",!1);y(this,"writable",!0);y(this,"writableEnded",!1);y(this,"writableFinished",!1);y(this,"socket");y(this,"connection");y(this,"stream");y(this,"_writableState",{ended:!1,finished:!1,objectMode:!1,corked:0,length:0});this._stream=t,this.stream=t,this.socket=t.session.socket,this.connection=this.socket}writeHead(t,r){return this._statusCode=t,this._headers={...this._headers,...r??{},":status":t},this._stream.respond(this._headers),this.headersSent=!0,this}setHeader(t,r){return this._headers[t]=r,this}getHeader(t){return this._headers[t]}hasHeader(t){return Object.prototype.hasOwnProperty.call(this._headers,t)}removeHeader(t){delete this._headers[t]}write(t,r,n){":status"in this._headers||(this._headers[":status"]=this._statusCode,this._stream.respond(this._headers),this.headersSent=!0);let i=this._stream.write(typeof t=="string"&&typeof r=="string"?Buffer.from(t,r):t);return(typeof r=="function"?r:n)?.(),i}end(t){return":status"in this._headers||(this._headers[":status"]=this._statusCode,this._stream.respond(this._headers),this.headersSent=!0),this.writableEnded=!0,this._writableState.ended=!0,this._stream.end(t),queueMicrotask(()=>{this.writable=!1,this.writableFinished=!0,this._writableState.finished=!0,this.emit("finish"),this.emit("close")}),this}destroy(t){return t&&this.emit("error",t),this.writable=!1,this.writableEnded=!0,this.writableFinished=!0,this.emit("close"),this}},CW=class extends Tu{constructor(t,r){super();y(this,"encrypted",!1);y(this,"alpnProtocol",!1);y(this,"originSet");y(this,"localSettings",Wi(r2));y(this,"remoteSettings",Wi(r2));y(this,"pendingSettingsAck",!1);y(this,"socket");y(this,"state",mG(pW));y(this,"_sessionId");y(this,"_waitStarted",!1);y(this,"_pendingSettingsAckCount",0);y(this,"_awaitingInitialSettingsAck",!1);y(this,"_settingsCallbacks",[]);this._sessionId=t,this.socket=new t2(r,()=>{setTimeout(()=>{this.destroy()},0)}),this[nSe]=this.socket}_retain(){this._waitStarted||typeof _networkHttp2SessionPollRaw>"u"||(this._waitStarted=!0,QW("session",this._sessionId,()=>this._waitStarted&&Bn.get(this._sessionId)===this,()=>_networkHttp2SessionPollRaw.applySyncPromise(void 0,[this._sessionId,0]),t=>this.emit("error",t instanceof Error?t:new Error(String(t)))))}_release(){this._waitStarted=!1,Ta.delete(`session:${this._sessionId}`)}_beginInitialSettingsAck(){this._awaitingInitialSettingsAck=!0,this._pendingSettingsAckCount+=1,this.pendingSettingsAck=!0}_applyLocalSettings(t){this.localSettings=Wi(t),this._awaitingInitialSettingsAck&&(this._awaitingInitialSettingsAck=!1,this._pendingSettingsAckCount=Math.max(0,this._pendingSettingsAckCount-1),this.pendingSettingsAck=this._pendingSettingsAckCount>0),this.emit("localSettings",this.localSettings)}_applyRemoteSettings(t){this.remoteSettings=Wi(t),this.emit("remoteSettings",this.remoteSettings)}_applyRuntimeState(t){this.state=mG(t)}_ackSettings(){this._pendingSettingsAckCount=Math.max(0,this._pendingSettingsAckCount-1),this.pendingSettingsAck=this._pendingSettingsAckCount>0,this._settingsCallbacks.shift()?.()}request(t,r){if(typeof _networkHttp2SessionRequestRaw>"u")throw new Error("http2 session request bridge is not available");mSe(r);let n=_networkHttp2SessionRequestRaw.applySync(void 0,[this._sessionId,sR(yW(t)),JSON.stringify(r??{})]),i=new mW(n,this);return bn.set(n,i),i}settings(t,r){if(r!==void 0&&typeof r!="function")throw Hl("callback","function",r);if(typeof _networkHttp2SessionSettingsRaw>"u")throw new Error("http2 session settings bridge is not available");let n=EW(t);_networkHttp2SessionSettingsRaw.applySync(void 0,[this._sessionId,JSON.stringify(n)]),this._pendingSettingsAckCount+=1,this.pendingSettingsAck=!0,r&&this._settingsCallbacks.push(r)}setLocalWindowSize(t){if(typeof t!="number"||Number.isNaN(t))throw Hl("windowSize","number",t);if(!Number.isInteger(t)||t<0||t>2147483647){let n=new RangeError(`The value of "windowSize" is out of range. It must be >= 0 && <= 2147483647. Received ${t}`);throw n.code="ERR_OUT_OF_RANGE",n}if(typeof _networkHttp2SessionSetLocalWindowSizeRaw>"u")throw new Error("http2 session setLocalWindowSize bridge is not available");let r=_networkHttp2SessionSetLocalWindowSizeRaw.applySync(void 0,[this._sessionId,t]);this._applyRuntimeState(xg(r)?.state)}goaway(t=0,r=0,n){let i=n===void 0?null:Buffer.isBuffer(n)?n.toString("base64"):Buffer.from(n).toString("base64");_networkHttp2SessionGoawayRaw?.applySync(void 0,[this._sessionId,t,r,i])}close(){let t=Array.from(bn.entries()).filter(([,r])=>typeof r._belongsTo=="function"&&r._belongsTo(this)&&!r._hasReceivedResponse());if(t.length>0){let r=Qo("ERR_HTTP2_GOAWAY_SESSION","The HTTP/2 session is closing before the stream could be established.");if(queueMicrotask(()=>{for(let[n,i]of t)bn.get(n)===i&&(i.emit("error",r),i.emit("close"),bn.delete(n))}),typeof _networkHttp2SessionDestroyRaw<"u"){_networkHttp2SessionDestroyRaw.applySync(void 0,[this._sessionId]);return}}_networkHttp2SessionCloseRaw?.applySync(void 0,[this._sessionId]),setTimeout(()=>{Bn.has(this._sessionId)&&(this._release(),this.emit("close"),Bn.delete(this._sessionId),_unregisterHandle?.(`http2:session:${this._sessionId}`))},50)}destroy(){if(typeof _networkHttp2SessionDestroyRaw<"u"){_networkHttp2SessionDestroyRaw.applySync(void 0,[this._sessionId]);return}this.close()}},SSe=class extends Tu{constructor(t,r,n){super();y(this,"allowHalfOpen");y(this,"allowHTTP1");y(this,"encrypted");y(this,"_serverId");y(this,"listening",!1);y(this,"_address",null);y(this,"_options");y(this,"_timeoutMs",0);y(this,"_waitStarted",!1);this.allowHalfOpen=t?.allowHalfOpen===!0,this.allowHTTP1=t?.allowHTTP1===!0,this.encrypted=n;let i=t?.settings&&typeof t.settings=="object"&&!Array.isArray(t.settings)?Wi(t.settings):{};this._options={...t??{},settings:i},this._serverId=iSe++,this[yG]={settings:Wi(i),unknownProtocolTimeout:1e4,...n?{ALPNProtocols:["h2"]}:{}},r&&this.on("request",r),_s.set(this._serverId,this)}address(){return this._address}_retain(){this._waitStarted||typeof _networkHttp2ServerPollRaw>"u"||(this._waitStarted=!0,QW("server",this._serverId,()=>this._waitStarted&&_s.get(this._serverId)===this,()=>_networkHttp2ServerPollRaw.applySyncPromise(void 0,[this._serverId,0]),t=>this.emit("error",t instanceof Error?t:new Error(String(t)))))}_release(){this._waitStarted=!1,Ta.delete(`server:${this._serverId}`)}setTimeout(t,r){return this._timeoutMs=AW(t),r&&this.on("timeout",r),this}updateSettings(t){let r=EW(t),n={...Wi(this._options.settings),...Wi(r)};this._options={...this._options,settings:n};let i=this[yG];return i.settings=Wi(n),this}listen(t,r,n,i){if(typeof _networkHttp2ServerListenRaw>"u")throw new Error(`http2.${this.encrypted?"createSecureServer":"createServer"} is not supported in sandbox`);let s=oW(t,r,n,i);s.callback&&this.once("listening",s.callback);let o={serverId:this._serverId,secure:this.encrypted,port:s.port,host:s.host,backlog:s.backlog,allowHalfOpen:this.allowHalfOpen,allowHTTP1:this._options.allowHTTP1===!0,timeout:this._timeoutMs,settings:this._options.settings,remoteCustomSettings:this._options.remoteCustomSettings,tls:this.encrypted?Wl({...this._options,...t&&typeof t=="object"?t:{}},{isServer:!0}):void 0},a=JSON.parse(_networkHttp2ServerListenRaw.applySyncPromise(void 0,[JSON.stringify(o)]));return this._address=a.address??null,this.listening=!0,this._retain(),_registerHandle?.(`http2:server:${this._serverId}`,"http2 server"),this.emit("listening"),this}close(t){return t&&this.once("close",t),this.listening?(_networkHttp2ServerCloseRaw?.apply(void 0,[this._serverId],{result:{promise:!0}}),setTimeout(()=>{this.listening&&(this.listening=!1,this._release(),this.emit("close"),_s.delete(this._serverId),_unregisterHandle?.(`http2:server:${this._serverId}`))},50),this):(this._release(),queueMicrotask(()=>this.emit("close")),this)}};function IG(e,t,r){let n=typeof t=="function"?t:r,i=t&&typeof t=="object"&&!Array.isArray(t)?t:void 0;return new SSe(i,n,e)}function _Se(e,t,r){if(typeof _networkHttp2SessionConnectRaw>"u")throw new Error("http2.connect is not supported in sandbox");let{authority:n,options:i,listener:s}=bSe(e,t,r);if(n.protocol!=="http:"&&n.protocol!=="https:")throw Qo("ERR_HTTP2_UNSUPPORTED_PROTOCOL",`protocol "${n.protocol}" is unsupported.`);BSe(i);let o=i.createConnection?CSe(i.createConnection()):void 0,a=i.port??n.port,A=a===""||a===void 0||a===null?void 0:Number(a),f=JSON.parse(_networkHttp2SessionConnectRaw.applySyncPromise(void 0,[JSON.stringify({authority:n.toString(),protocol:n.protocol,host:i.host??i.hostname??n.hostname,port:A,localAddress:i.localAddress,family:i.family,socketId:o,settings:i.settings,remoteCustomSettings:i.remoteCustomSettings,tls:n.protocol==="https:"?Wl(i,{servername:typeof i.servername=="string"?i.servername:n.hostname}):void 0})])),l=xg(f.state),p=new CW(f.sessionId,l?.socket??void 0);return oR(p,l),p._beginInitialSettingsAck(),p._retain(),s&&p.once("connect",()=>s(p)),Bn.set(f.sessionId,p),_registerHandle?.(`http2:session:${f.sessionId}`,"http2 session"),n.protocol==="https:"&&p.socket.once("secureConnect",()=>{}),p}function bG(e,t){let r=Bn.get(e);return r||(r=new CW(e,t?.socket??void 0),Bn.set(e,r)),oR(r,t),r}function bl(e,t){let r=RB.get(e)??[];r.push(t),RB.set(e,r)}function iu(e){if(u1.has(e))return;u1.add(e);let t=()=>{u1.delete(e),vSe(e)},r=globalThis.setImmediate;if(typeof r=="function"){r(t);return}setTimeout(t,0)}function vSe(e){let t=bn.get(e);if(!t||typeof t._emitResponseHeaders!="function")return;let r=RB.get(e);if(!(!r||r.length===0)){RB.delete(e);for(let n of r){if(n.kind==="push"){t._emitPush(FA(n.data),n.extraNumber);continue}if(n.kind==="responseHeaders"){t._emitResponseHeaders(FA(n.data));continue}if(n.kind==="data"){t._emitDataChunk(n.data);continue}if(n.kind==="end"){t._emitEnd();continue}if(n.kind==="error"){t.emit("error",DB(n.data));continue}typeof t._emitClose=="function"?t._emitClose(n.extraNumber):t.emit("close"),bn.delete(e)}}}function aR(e,t,r,n,i,s,o){if(e==="sessionConnect"){let a=Bn.get(t);if(!a)return;let A=xg(r);oR(a,A),a.encrypted&&a.socket.emit("secureConnect"),a.emit("connect");return}if(e==="sessionClose"){let a=Bn.get(t);if(!a)return;a._release(),a.emit("close"),Bn.delete(t),_unregisterHandle?.(`http2:session:${t}`);return}if(e==="sessionError"){let a=Bn.get(t);if(!a)return;a.emit("error",DB(r));return}if(e==="sessionLocalSettings"){let a=Bn.get(t);if(!a)return;a._applyLocalSettings(FA(r));return}if(e==="sessionRemoteSettings"){let a=Bn.get(t);if(!a)return;a._applyRemoteSettings(FA(r));return}if(e==="sessionSettingsAck"){let a=Bn.get(t);if(!a)return;a._ackSettings();return}if(e==="sessionGoaway"){let a=Bn.get(t);if(!a)return;a.emit("goaway",Number(i??0),Number(o??0),r?Buffer.from(r,"base64"):Buffer.alloc(0));return}if(e==="clientPushStream"){let a=Bn.get(t);if(!a)return;let A=Number(r),f=new mW(A,a,!0);bn.set(A,f),a.emit("stream",f,FA(s),Number(o??0)),iu(A);return}if(e==="clientPushHeaders"){bl(t,{kind:"push",data:r,extraNumber:Number(i??0)}),iu(t);return}if(e==="clientResponseHeaders"){bl(t,{kind:"responseHeaders",data:r}),iu(t);return}if(e==="clientData"){bl(t,{kind:"data",data:r}),iu(t);return}if(e==="clientEnd"){bl(t,{kind:"end"}),iu(t);return}if(e==="clientClose"){bl(t,{kind:"close",extraNumber:Number(i??0)}),iu(t);return}if(e==="clientError"){bl(t,{kind:"error",data:r}),iu(t);return}if(e==="serverStream"){let a=_s.get(t);if(!a)return;let A=xg(n),f=Number(i),l=bG(f,A),p=Number(r),B=FA(s),S=Number(o??0),_=new wSe(p,l,B);if(bn.set(p,_),a.emit("stream",_,B,S),a.listenerCount("request")>0){let N=new IW(B,l.socket,_),P=new bW(_);_.on("data",U=>{N._emitData(U)}),_.on("end",()=>{N._emitEnd()}),_.on("error",U=>{N._emitError(U)}),_.on("drain",()=>{P.emit("drain")}),a.emit("request",N,P)}return}if(e==="serverStreamData"){let a=bn.get(t);if(!a||typeof a._emitData!="function")return;a._emitData(r);return}if(e==="serverStreamEnd"){let a=bn.get(t);if(!a||typeof a._emitEnd!="function")return;a._emitEnd();return}if(e==="serverStreamDrain"){let a=bn.get(t);if(!a||typeof a._emitDrain!="function")return;a._emitDrain();return}if(e==="serverStreamError"){let a=bn.get(t);if(!a||typeof a._shouldSuppressHostError=="function"&&a._shouldSuppressHostError())return;a.emit("error",DB(r));return}if(e==="serverStreamClose"){let a=bn.get(t);if(!a||typeof a._emitClose!="function")return;a._emitClose(Number(i??0)),bn.delete(t);return}if(e==="serverSession"){let a=_s.get(t);if(!a)return;let A=Number(i),f=bG(A,xg(r));a.emit("session",f);return}if(e==="serverTimeout"){_s.get(t)?.emit("timeout");return}if(e==="serverConnection"){_s.get(t)?.emit("connection",new t2(BG(r)??void 0));return}if(e==="serverSecureConnection"){_s.get(t)?.emit("secureConnection",new t2(BG(r)??void 0));return}if(e==="serverClose"){let a=_s.get(t);if(!a)return;a.listening=!1,a._release(),a.emit("close"),_s.delete(t),_unregisterHandle?.(`http2:server:${t}`);return}e==="serverCompatRequest"&&(e2.set(Number(i),{serverId:t,requestJson:r??"{}"}),f_e(t,Number(i)))}function RSe(e){if(typeof e=="string"&&(e=JSON.parse(e)),!e||typeof e!="object"||typeof e.kind!="string")return!1;let t=Number(e.id);return Number.isFinite(t)?(aR(e.kind,t,typeof e.data=="string"?e.data:void 0,typeof e.extra=="string"?e.extra:void 0,typeof e.extraNumber=="string"||typeof e.extraNumber=="number"?e.extraNumber:void 0,typeof e.extraHeaders=="string"?e.extraHeaders:void 0,typeof e.flags=="string"||typeof e.flags=="number"?e.flags:void 0),e.kind==="serverClose"||e.kind==="sessionClose"):!1}function QW(e,t,r,n,i){let s=`${e}:${t}`,o={active:!0,running:!1,pendingWake:!1,fallbackTimer:null,poll:n,tick:null},a=()=>{o.fallbackTimer!==null&&(clearTimeout(o.fallbackTimer),o.fallbackTimer=null)},A=()=>{if(a(),!r()){o.active=!1,Ta.delete(s);return}if(o.running){o.pendingWake=!0;return}o.running=!0;try{let f=!1,l=!1;do{o.pendingWake=!1,l=!1;let p=0;for(;p<64&&r();p++){let B=n();if(!B||(f=RSe(B),f))break}l=p===64}while(!f&&o.pendingWake&&r());!f&&l&&r()?o.fallbackTimer=setTimeout(A,0):!f&&r()?o.fallbackTimer=setTimeout(A,10):f&&(o.active=!1,Ta.delete(s))}catch(f){i(f),r()?o.fallbackTimer=setTimeout(A,10):(o.active=!1,Ta.delete(s))}finally{o.running=!1,o.pendingWake&&o.active&&r()&&(a(),o.fallbackTimer=setTimeout(A,0))}};o.tick=A,Ta.set(s,o),setTimeout(A,0)}function DSe(e,t){let r=Ta.get(`${e}:${t}`);if(!(!r||!r.active)&&(r.pendingWake=!0,!r.running)){if(typeof queueMicrotask=="function"){queueMicrotask(()=>{Ta.get(`${e}:${t}`)===r&&r.tick?.()});return}setTimeout(()=>{Ta.get(`${e}:${t}`)===r&&r.tick?.()},0)}}function TSe(e){if(!e||e.event!=="http2")return;let t=e.kind==="server"?"server":e.kind==="session"?"session":null,r=Number(e.id);!t||!Number.isFinite(r)||DSe(t,r)}function NSe(){if(c1)return;c1=!0,queueMicrotask(()=>{for(c1=!1;$1.length>0;){let t=$1.shift();t&&aR(t.kind,t.id,t.data,t.extra,t.extraNumber,t.extraHeaders,t.flags)}})}function MSe(e,t){if(!t||typeof t!="object")return;let r=t;if(typeof r.kind!="string"||typeof r.id!="number")return;process.env.SECURE_EXEC_DEBUG_HTTP2_BRIDGE==="1"&&console.error("[secure-exec http2 isolate dispatch]",r.kind,r.id);let n=r.kind,i=r.id,s=typeof r.data=="string"?r.data:void 0,o=typeof r.extra=="string"?r.extra:void 0,a=typeof r.extraNumber=="string"||typeof r.extraNumber=="number"?r.extraNumber:void 0,A=typeof r.extraHeaders=="string"?r.extraHeaders:void 0,f=typeof r.flags=="string"||typeof r.flags=="number"?r.flags:void 0;$1.push({kind:n,id:i,data:s,extra:o,extraNumber:a,extraHeaders:A,flags:f}),NSe()}Ge("_http2RetainDispatch",TSe);var AR={Http2ServerRequest:IW,Http2ServerResponse:bW,Http2Stream:gW,NghttpError:hW,nghttp2ErrorString:dW,constants:{HTTP2_HEADER_METHOD:":method",HTTP2_HEADER_PATH:":path",HTTP2_HEADER_SCHEME:":scheme",HTTP2_HEADER_AUTHORITY:":authority",HTTP2_HEADER_STATUS:":status",HTTP2_HEADER_CONTENT_TYPE:"content-type",HTTP2_HEADER_CONTENT_LENGTH:"content-length",HTTP2_HEADER_LAST_MODIFIED:"last-modified",HTTP2_HEADER_ACCEPT:"accept",HTTP2_HEADER_ACCEPT_ENCODING:"accept-encoding",HTTP2_METHOD_GET:"GET",HTTP2_METHOD_POST:"POST",HTTP2_METHOD_PUT:"PUT",HTTP2_METHOD_DELETE:"DELETE",...So,DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE:65535},getDefaultSettings(){return Wi(r2)},connect:_Se,createServer:IG.bind(void 0,!1),createSecureServer:IG.bind(void 0,!0)};function FSe(e,t,r){let n={},i=r;if(typeof t=="function")i=t;else if(typeof t=="number")n={family:t};else if(t==null)n={};else if(typeof t=="object")n={...t};else throw new TypeError("dns.lookup options must be a number, object, or callback");let s=n.family===4||n.family===6?n.family:void 0;return{callback:i,options:{hostname:String(e),family:s,all:n.all===!0}}}function fB(e){let t=new Error(`${e} is not supported by the secure-exec dns polyfill`);return t.code="ERR_NOT_IMPLEMENTED",t}function kSe(e,t,r,n){let i=r,s=n;typeof r=="function"&&(s=r,i=void 0);let o=String(i??"A").toUpperCase();if(!["A","AAAA","MX","TXT","SRV","CNAME","PTR","NS","SOA","NAPTR","CAA","ANY"].includes(o))throw fB(`${e}(${o})`);return{callback:s,options:{hostname:String(t),rrtype:o}}}function xSe(e){let t=e;return typeof t=="string"&&(t=JSON.parse(t)),t&&typeof t=="object"&&Array.isArray(t.records)?t=t.records:t&&typeof t=="object"&&typeof t.address=="string"&&(t=[t]),Array.isArray(t)?t.filter(r=>r&&typeof r.address=="string").map(r=>({address:r.address,family:r.family===6?6:4})):[]}function USe(e){let t=e;return typeof t=="string"&&(t=JSON.parse(t)),t}function CG(e){let t=new TypeError(`${e} expects an array of non-empty server strings`);return t.code="ERR_INVALID_ARG_TYPE",t}function wW(e,t){if(!Array.isArray(t))throw CG(e);return t.map(r=>{if(typeof r!="string"||r.length===0)throw CG(e);return r})}function TB(e,t,r){let n=FSe(e,t,r);return _networkDnsLookupRaw.apply(void 0,[n.options],{result:{promise:!0}}).then(i=>{let s=xSe(i);if(typeof n.callback=="function")if(n.options.all)n.callback(null,s);else{let o=s[0]??{address:null,family:n.options.family??0};n.callback(null,o.address,o.family)}return n.options.all?s:s[0]??{address:"",family:n.options.family??0}})}function ke(e,t,r,n){let i=kSe(e,t,r,n);return _networkDnsResolveRaw.apply(void 0,[i.options],{result:{promise:!0}}).then(s=>{let o=USe(s);return typeof i.callback=="function"&&queueMicrotask(()=>i.callback(null,o)),o}).catch(s=>{throw typeof i.callback=="function"&&queueMicrotask(()=>i.callback(s)),s})}var LSe=class{constructor(){this._servers=[]}cancel(){}getServers(){return this._servers.slice()}lookup(e,t,r){return TB(e,t,r)}resolve(e,t,r){return ke("dns.resolve",e,t,r)}resolve4(e,t){return ke("dns.resolve4",e,"A",t)}resolve6(e,t){return ke("dns.resolve6",e,"AAAA",t)}resolveAny(e,t){return ke("dns.resolveAny",e,"ANY",t)}resolveMx(e,t){return ke("dns.resolveMx",e,"MX",t)}resolveTxt(e,t){return ke("dns.resolveTxt",e,"TXT",t)}resolveSrv(e,t){return ke("dns.resolveSrv",e,"SRV",t)}resolveCname(e,t){return ke("dns.resolveCname",e,"CNAME",t)}resolvePtr(e,t){return ke("dns.resolvePtr",e,"PTR",t)}resolveNs(e,t){return ke("dns.resolveNs",e,"NS",t)}resolveSoa(e,t){return ke("dns.resolveSoa",e,"SOA",t)}resolveNaptr(e,t){return ke("dns.resolveNaptr",e,"NAPTR",t)}resolveCaa(e,t){return ke("dns.resolveCaa",e,"CAA",t)}setServers(e){this._servers=wW("dns.Resolver.setServers",e)}},PSe=class{constructor(){this._servers=[]}cancel(){}getServers(){return this._servers.slice()}lookup(e,t){return TB(e,t)}resolve(e,t){return ke("dns.resolve",e,t)}resolve4(e){return ke("dns.resolve4",e,"A")}resolve6(e){return ke("dns.resolve6",e,"AAAA")}resolveAny(e){return ke("dns.resolveAny",e,"ANY")}resolveMx(e){return ke("dns.resolveMx",e,"MX")}resolveTxt(e){return ke("dns.resolveTxt",e,"TXT")}resolveSrv(e){return ke("dns.resolveSrv",e,"SRV")}resolveCname(e){return ke("dns.resolveCname",e,"CNAME")}resolvePtr(e){return ke("dns.resolvePtr",e,"PTR")}resolveNs(e){return ke("dns.resolveNs",e,"NS")}resolveSoa(e){return ke("dns.resolveSoa",e,"SOA")}resolveNaptr(e){return ke("dns.resolveNaptr",e,"NAPTR")}resolveCaa(e){return ke("dns.resolveCaa",e,"CAA")}setServers(e){this._servers=wW("dns.promises.Resolver.setServers",e)}},fR={lookup(e,t,r){TB(e,t,r).catch(n=>{(typeof t=="function"?t:r)?.(n)})},resolve(e,t,r){ke("dns.resolve",e,t,r).catch(()=>{})},resolve4(e,t){ke("dns.resolve4",e,"A",t).catch(()=>{})},resolve6(e,t){ke("dns.resolve6",e,"AAAA",t).catch(()=>{})},resolveAny(e,t){ke("dns.resolveAny",e,"ANY",t).catch(()=>{})},resolveMx(e,t){ke("dns.resolveMx",e,"MX",t).catch(()=>{})},resolveTxt(e,t){ke("dns.resolveTxt",e,"TXT",t).catch(()=>{})},resolveSrv(e,t){ke("dns.resolveSrv",e,"SRV",t).catch(()=>{})},resolveCname(e,t){ke("dns.resolveCname",e,"CNAME",t).catch(()=>{})},resolvePtr(e,t){ke("dns.resolvePtr",e,"PTR",t).catch(()=>{})},resolveNs(e,t){ke("dns.resolveNs",e,"NS",t).catch(()=>{})},resolveSoa(e,t){ke("dns.resolveSoa",e,"SOA",t).catch(()=>{})},resolveNaptr(e,t){ke("dns.resolveNaptr",e,"NAPTR",t).catch(()=>{})},resolveCaa(e,t){ke("dns.resolveCaa",e,"CAA",t).catch(()=>{})},promises:{Resolver:PSe,lookup(e,t){return TB(e,t)},resolve(e,t){return ke("dns.resolve",e,t||"A")},resolve4(e){return ke("dns.resolve4",e,"A")},resolve6(e){return ke("dns.resolve6",e,"AAAA")},resolveAny(e){return ke("dns.resolveAny",e,"ANY")},resolveMx(e){return ke("dns.resolveMx",e,"MX")},resolveTxt(e){return ke("dns.resolveTxt",e,"TXT")},resolveSrv(e){return ke("dns.resolveSrv",e,"SRV")},resolveCname(e){return ke("dns.resolveCname",e,"CNAME")},resolvePtr(e){return ke("dns.resolvePtr",e,"PTR")},resolveNs(e){return ke("dns.resolveNs",e,"NS")},resolveSoa(e){return ke("dns.resolveSoa",e,"SOA")},resolveNaptr(e){return ke("dns.resolveNaptr",e,"NAPTR")},resolveCaa(e){return ke("dns.resolveCaa",e,"CAA")}},Resolver:LSe,getServers(){return[]},lookupService(){throw fB("dns.lookupService")},reverse(){throw fB("dns.reverse")},setServers(){throw fB("dns.setServers")}};Ge("_http2Module",AR);function n2(e){return{__secureExecTlsContext:Wl(e),context:{}}}function OSe(e,t){if(!(e instanceof To))throw new TypeError("tls.TLSSocket requires a net.Socket instance");let r=t&&typeof t=="object"?{...t}:{};Object.setPrototypeOf(e,uR.prototype);let n=Wl(r,{isServer:r.isServer===!0,servername:r.servername??e.servername??e.remoteAddress??"127.0.0.1"});return n.isServer||(e.servername=n.servername),e._connected?e._upgradeTls(n):e.once("connect",()=>{e._upgradeTls(n)}),e}var uR=class extends To{constructor(e,t){if(e instanceof To)return super({allowHalfOpen:e.allowHalfOpen===!0}),OSe(e,t);super(e&&typeof e=="object"?e:t)}};function SW(...e){let t,r,n=[...e],i=typeof n[n.length-1]=="function"?n.pop():void 0;if(n[0]!=null&&typeof n[0]=="object")r={...n[0]},r.socket?t=r.socket:(t=new To,t.connect({host:r.host??"127.0.0.1",port:r.port,localAddress:r.localAddress,localPort:r.localPort}));else{let o={};n.length>0&&(o.port=n.shift()),typeof n[0]=="string"&&(o.host=n.shift()),r={...n[0]!=null&&typeof n[0]=="object"?{...n[0]}:{},...o},t=new To,t.connect({host:r.host??"127.0.0.1",port:r.port,localAddress:r.localAddress,localPort:r.localPort})}i&&t.once("secureConnect",i);let s=Wl(r,{isServer:!1,servername:r.servername??r.host??"127.0.0.1"});return t.servername=s.servername,t._connected?t._upgradeTls(s):t.once("connect",()=>{t._upgradeTls(s)}),t}function HSe(e,t){if(!e.startsWith("*."))return e===t;let r=e.slice(1);if(!t.endsWith(r))return!1;let n=t.slice(0,-r.length);return n.length>0&&!n.includes(".")}var _W=class{constructor(e,t){y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_server");y(this,"_tlsOptions");y(this,"_sniCallback");y(this,"_alpnCallback");y(this,"_contexts",[]);let r=typeof e=="function"||e===void 0?void 0:e,n=typeof e=="function"?e:t;if(r?.ALPNCallback&&r?.ALPNProtocols){let i=new Error("The ALPNCallback and ALPNProtocols TLS options are mutually exclusive");throw i.code="ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS",i}this._tlsOptions=Wl(r,{isServer:!0}),this._sniCallback=r?.SNICallback,this._alpnCallback=r?.ALPNCallback,this._server=new Jg(r?{allowHalfOpen:r.allowHalfOpen,keepAlive:r.keepAlive,keepAliveInitialDelay:r.keepAliveInitialDelay}:void 0,(i=>{let s=i;s.server=this,this._handleSecureSocket(s)})),n&&this.on("secureConnection",n),this._server.on("listening",(...i)=>this._emit("listening",...i)),this._server.on("close",(...i)=>this._emit("close",...i)),this._server.on("error",(...i)=>this._emit("error",...i)),this._server.on("drop",(...i)=>this._emit("drop",...i))}listen(e,t,r,n){return this._server.listen(e,t,r,n),this}close(e){return e&&this.once("close",e),this._server.close(),this}address(){return this._server.address()}getConnections(e){return this._server.getConnections(e),this}ref(){return this._server.ref(),this}unref(){return this._server.unref(),this}addContext(e,t){let r=j1(t)?t:n2(t&&typeof t=="object"?t:void 0);return this._contexts.push({servername:e,context:r}),this}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this}emit(e,...t){return this._emit(e,...t)}_emit(e,...t){let r=!1,n=this._listeners[e];if(n)for(let s of[...n])s.call(this,...t),r=!0;let i=this._onceListeners[e];if(i){this._onceListeners[e]=[];for(let s of[...i])s.call(this,...t),r=!0}return r}async _handleSecureSocket(e){let t=this._getClientHello(e),r=t?.servername;r&&(e.servername=r);try{let n=await this._resolveTlsOptions(r,t?.ALPNProtocols??[]);if(!n){this._emitTlsClientError(e,"Invalid SNI context");return}e._upgradeTls(n),e.once("secure",()=>{this._emit("secureConnection",e),this._emit("connection",e)}),e.on("error",i=>{this._emit("tlsClientError",i,e)})}catch(n){let i=n instanceof Error?n:new Error(String(n));this._emitTlsClientError(e,i.message,i),i.uncaught&&process.emit?.("uncaughtException",i,"uncaughtException")}}_getClientHello(e){if(typeof _netSocketGetTlsClientHelloRaw>"u")return null;let t=e._socketId;return typeof t!="number"||t===0?null:Vwe(_netSocketGetTlsClientHelloRaw.applySync(void 0,[t]))}async _resolveTlsOptions(e,t){let r=null,n=!1;if(e&&this._sniCallback){if(r=await new Promise((s,o)=>{this._sniCallback?.(e,(a,A)=>{if(a){o(a);return}if(A==null){s(null);return}if(j1(A)){s(A);return}if(A&&typeof A=="object"&&Object.keys(A).length>0){s(n2(A));return}n=!0,s(null)})}),n)return null}else e&&(r=this._findContext(e));let i={...this._tlsOptions,...r?.__secureExecTlsContext??{},isServer:!0};if(this._alpnCallback){let s=this._alpnCallback({servername:e,protocols:t});if(s===void 0){let o=new Error("ALPN callback rejected the client protocol list");throw o.code="ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL",o}if(!t.includes(s)){let o=new Error("The ALPNCallback callback returned an invalid protocol");throw o.code="ERR_TLS_ALPN_CALLBACK_INVALID_RESULT",o.uncaught=!0,o}i.ALPNProtocols=[s]}return i}_findContext(e){for(let t=this._contexts.length-1;t>=0;t-=1){let r=this._contexts[t];if(HSe(r.servername,e))return r.context}return null}_emitTlsClientError(e,t,r){let n=r??new Error(t);e.servername??(e.servername=this._getClientHello(e)?.servername),this._emit("tlsClientError",n,e),e.destroy()}};function qSe(e,t){return new _W(e,t)}var vW={connect:SW,TLSSocket:uR,Server:qSe,createServer(e,t){return new _W(e,t)},createSecureContext(e){return n2(e)},getCiphers(){if(typeof _tlsGetCiphersRaw>"u")throw new Error("tls.getCiphers is not supported in sandbox");try{return JSON.parse(_tlsGetCiphersRaw.applySync(void 0,[]))}catch{return[]}},DEFAULT_MIN_VERSION:"TLSv1.2",DEFAULT_MAX_VERSION:"TLSv1.3"};Ge("_netModule",lW);function Na(e="socket hang up"){let t=new Error(e);return t.code="ECONNRESET",t}function QG(){let e=new Error("The operation was aborted");return e.name="AbortError",e.code="ABORT_ERR",e}var hu=class{constructor(e){y(this,"headers");y(this,"rawHeaders");y(this,"trailers");y(this,"rawTrailers");y(this,"httpVersion");y(this,"httpVersionMajor");y(this,"httpVersionMinor");y(this,"method");y(this,"url");y(this,"statusCode");y(this,"statusMessage");y(this,"_body");y(this,"_isBinary");y(this,"_listeners");y(this,"complete");y(this,"aborted");y(this,"socket");y(this,"_bodyConsumed");y(this,"_ended");y(this,"_flowing");y(this,"readable");y(this,"readableEnded");y(this,"readableFlowing");y(this,"destroyed");y(this,"_encoding");y(this,"_closeEmitted");let t={};if(Array.isArray(e?.headers)?e.headers.forEach(([i,s])=>{vo(t,i.toLowerCase(),s)}):e?.headers&&Object.entries(e.headers).forEach(([i,s])=>{t[i]=Array.isArray(s)?[...s]:s}),this.rawHeaders=Array.isArray(e?.rawHeaders)?[...e.rawHeaders]:[],this.rawHeaders.length>0){this.headers={};for(let i=0;i{if(Array.isArray(s)){s.forEach(o=>{this.rawHeaders.push(i,o)});return}this.rawHeaders.push(i,s)}),e?.trailers&&typeof e.trailers=="object"?(this.trailers=e.trailers,this.rawTrailers=[],Object.entries(e.trailers).forEach(([i,s])=>{this.rawTrailers.push(i,s)})):(this.trailers={},this.rawTrailers=[]),this.httpVersion="1.1",this.httpVersionMajor=1,this.httpVersionMinor=1,this.method=null,this.url=e?.url||"",this.statusCode=e?.status,this.statusMessage=e?.statusText;let r=this.headers["x-body-encoding"];(e?.bodyEncoding||(Array.isArray(r)?r[0]:r))==="base64"&&e?.body&&typeof Buffer<"u"?(this._body=Buffer.from(e.body,"base64").toString("binary"),this._isBinary=!0):(this._body=e?.body||"",this._isBinary=!1),this._listeners={},this.complete=!1,this.aborted=!1,this.socket=null,this._bodyConsumed=!1,this._ended=!1,this._flowing=!1,this.readable=!0,this.readableEnded=!1,this.readableFlowing=null,this.destroyed=!1,this._closeEmitted=!1}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),e==="data"&&!this._bodyConsumed&&(this._flowing=!0,this.readableFlowing=!0,Promise.resolve().then(()=>{if(!this._bodyConsumed){if(this._bodyConsumed=!0,this._body&&this._body.length>0){let r;typeof Buffer<"u"?r=this._isBinary?Buffer.from(this._body,"binary"):Buffer.from(this._body):r=this._body,this.emit("data",r)}Promise.resolve().then(()=>{this._ended||(this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,this.emit("end"))})}})),e==="end"&&this._bodyConsumed&&!this._ended&&Promise.resolve().then(()=>{this._ended||(this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,t())}),this}once(e,t){let r=(...n)=>{this.off(e,r),t(...n)};return r._originalListener=t,this.on(e,r)}off(e,t){if(this._listeners[e]){let r=this._listeners[e].findIndex(n=>n===t||n._originalListener===t);r!==-1&&this._listeners[e].splice(r,1)}return this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e?delete this._listeners[e]:this._listeners={},this}emit(e,...t){return zl(this,this._listeners[e],t)}setEncoding(e){return this._encoding=e,this}read(e){if(this._bodyConsumed)return null;this._bodyConsumed=!0;let t;return typeof Buffer<"u"?t=this._isBinary?Buffer.from(this._body,"binary"):Buffer.from(this._body):t=this._body,Promise.resolve().then(()=>{this._ended||(this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,this.emit("end"))}),t}pipe(e){let t;return typeof Buffer<"u"?t=this._isBinary?Buffer.from(this._body||"","binary"):Buffer.from(this._body||""):t=this._body||"",typeof e.write=="function"&&t.length>0&&e.write(t),typeof e.end=="function"&&Promise.resolve().then(()=>e.end()),this._bodyConsumed=!0,this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,e}pause(){return this._flowing=!1,this.readableFlowing=!1,this}resume(){return this._flowing=!0,this.readableFlowing=!0,this._bodyConsumed||Promise.resolve().then(()=>{if(!this._bodyConsumed){if(this._bodyConsumed=!0,this._body){let e;typeof Buffer<"u"?e=this._isBinary?Buffer.from(this._body,"binary"):Buffer.from(this._body):e=this._body,this.emit("data",e)}Promise.resolve().then(()=>{this._ended||(this._ended=!0,this.complete=!0,this.readable=!1,this.readableEnded=!0,this.emit("end"))})}}),this}unpipe(e){return this}destroy(e){return this.destroyed=!0,this.readable=!1,e&&this.emit("error",e),this._emitClose(),this}_abort(e=Na("aborted")){this.aborted||(this.aborted=!0,this.complete=!1,this.destroyed=!0,this.readable=!1,this.readableEnded=!0,this.emit("aborted"),e&&this.emit("error",e),this._emitClose())}_emitClose(){this._closeEmitted||(this._closeEmitted=!0,this.emit("close"))}[Symbol.asyncIterator](){let e=this,t=!1,r=!1;return{async next(){if(r||e._ended)return{done:!0,value:void 0};if(!t&&!e._bodyConsumed){t=!0,e._bodyConsumed=!0;let n;return typeof Buffer<"u"?n=e._isBinary?Buffer.from(e._body||"","binary"):Buffer.from(e._body||""):n=e._body||"",{done:!1,value:n}}return r=!0,e._ended=!0,e.complete=!0,e.readable=!1,e.readableEnded=!0,{done:!0,value:void 0}},return(){return r=!0,Promise.resolve({done:!0,value:void 0})},throw(n){return r=!0,e.emit("error",n),Promise.resolve({done:!0,value:void 0})}}}},Ug=class{constructor(e,t){y(this,"_options");y(this,"_callback");y(this,"_listeners",{});y(this,"_headers",{});y(this,"_rawHeaderNames",new Map);y(this,"_body","");y(this,"_bodyBytes",0);y(this,"_ended",!1);y(this,"_agent");y(this,"_hostKey");y(this,"_socketEndListener",null);y(this,"_socketCloseListener",null);y(this,"_loopbackAbort");y(this,"_response",null);y(this,"_closeEmitted",!1);y(this,"_abortEmitted",!1);y(this,"_signalAbortHandler");y(this,"_signalPollTimer",null);y(this,"_skipExecute",!1);y(this,"_destroyError");y(this,"_errorEmitted",!1);y(this,"socket");y(this,"finished",!1);y(this,"aborted",!1);y(this,"destroyed",!1);y(this,"path");y(this,"method");y(this,"reusedSocket",!1);y(this,"timeoutCb");let r=zSe(e.method);this._options={...e,method:r,path:KSe(e.path)},this._callback=t,this._validateTimeoutOption(),this._setOutgoingHeaders(e.headers),this._headers.host||this._setHeaderValue("Host",XSe(this._options)),this.path=String(this._options.path||"/"),this.method=String(this._options.method||"GET").toUpperCase();let n=this._options.agent;n===!1?this._agent=null:n instanceof NB?this._agent=n:this._options._agentOSDefaultAgent instanceof NB?this._agent=this._options._agentOSDefaultAgent:this._agent=null,this._hostKey=this._agent?this._agent._getHostKey(this._options):"",this._bindAbortSignal(),typeof this._options.timeout=="number"&&this.setTimeout(this._options.timeout),Promise.resolve().then(()=>this._execute())}_assignSocket(e,t){this.socket=e,this.reusedSocket=t;let r=e;if(r._agentPermanentListenersInstalled||(r._agentPermanentListenersInstalled=!0,e.on("error",()=>{}),e.on("end",()=>{})),this._socketEndListener=()=>{},e.on("end",this._socketEndListener),this._socketCloseListener=()=>{this.destroyed=!0,this._clearTimeout(),this._emitClose()},e.on("close",this._socketCloseListener),this._applyTimeoutToSocket(e),this._emit("socket",e),this.destroyed){this._destroyError&&!this._errorEmitted&&(this._errorEmitted=!0,queueMicrotask(()=>{this._emit("error",this._destroyError)})),e.destroy();return}this._dispatchWithSocket(e)}_handleSocketError(e){this._emit("error",e)}_finalizeSocket(e,t){this._socketEndListener&&(e.off?.("end",this._socketEndListener),e.removeListener?.("end",this._socketEndListener),this._socketEndListener=null),this._socketCloseListener&&(e.off?.("close",this._socketCloseListener),e.removeListener?.("close",this._socketCloseListener),this._socketCloseListener=null),this._agent?this._agent._releaseSocket(this._hostKey,e,this._options,t):e.destroyed||e.destroy()}async _dispatchWithSocket(e){try{let t=ZSe(this._options.headers),r=String(this._options.method||"GET").toUpperCase();e instanceof To||typeof e?._socketId=="string"&&e._socketId.length>0||typeof e?._socketId=="number"&&e._socketId>0||e?._loopbackServer||$Se(r,t)||this._options.socketPath||this._agent?.keepAlive===!0?await this._dispatchRawSocketRequest(e,r,t):await this._dispatchUndiciRequest(e,r)}catch(t){this._clearTimeout(),this._emit("error",t),this._finalizeSocket(e,!1)}}async _dispatchUndiciRequest(e,t){await SG(e,this._options.protocol||"http:");let r=r_e(e,this._options),n=this._body?Buffer.from(this._body):Buffer.alloc(0),i=_G(this._headers,this._rawHeaderNames);n.length>0&&!this._headers["content-length"]&&!this._headers["transfer-encoding"]&&i.push(["Content-Length",String(n.length)]);let s=await new Promise((A,f)=>{try{nW.call(r,{path:this._options.path||"/",method:t,headers:n_e(i),body:n.length>0?n:null,signal:this._options.signal,responseHeaders:"raw"},(l,p)=>{if(l){f(l);return}A(p)})}catch(l){f(l)}}),o=await s_e(s?.body);await new Promise(A=>{queueMicrotask(A)}),this.finished=!0,this._clearTimeout();let a=new hu({status:s?.statusCode,statusText:s?.statusText,headers:Array.isArray(s?.headers)?s.headers:[],rawHeaders:Array.isArray(s?.headers)?s.headers:[],trailers:s?.trailers&&typeof s.trailers=="object"?s.trailers:{},body:o.length>0?o.toString("base64"):"",bodyEncoding:"base64",url:this._buildUrl()});this._response=a,a.socket=e,a.once("end",()=>{process.nextTick(()=>{this._finalizeSocket(e,this._agent?.keepAlive===!0&&!this.aborted)})}),this._callback&&this._callback(a),this._emit("response",a),!this._callback&&this._listenerCount("response")===0&&queueMicrotask(()=>{a.resume()})}async _dispatchRawSocketRequest(e,t,r){let n=this._options.protocol||"http:";await SG(e,n);let i=this._body?Buffer.from(this._body):Buffer.alloc(0),s=_G(this._headers,this._rawHeaderNames);i.length>0&&!r["content-length"]&&!r["transfer-encoding"]&&s.push(["Content-Length",String(i.length)]);let o=i_e(t,this._options.path||"/",s,i),a=typeof this._options.timeout=="number"&&this._options.timeout>0?this._options.timeout:3e4,A=a_e(e,t,a);e.write(o);let f=await A;if(this.finished=!0,this._clearTimeout(),f.status===101){let p=new hu({status:f.status,statusText:f.statusText,headers:f.headers,rawHeaders:f.rawHeaders,body:"",bodyEncoding:"base64",url:this._buildUrl()});this._response=p,p.socket=e;let B=f.head??Buffer.alloc(0);if(this._listenerCount("upgrade")===0){e.destroy();return}this._emit("upgrade",p,e,B);return}if(t==="CONNECT"){let p=new hu({status:f.status,statusText:f.statusText,headers:f.headers,rawHeaders:f.rawHeaders,body:"",bodyEncoding:"base64",url:this._buildUrl()});this._response=p,p.socket=e;let B=f.head??Buffer.alloc(0);this._emit("connect",p,e,B);return}let l=new hu({status:f.status,statusText:f.statusText,headers:f.headers,rawHeaders:f.rawHeaders,body:f.body&&f.body.length>0?f.body.toString("base64"):"",bodyEncoding:"base64",url:this._buildUrl()});this._response=l,l.socket=e,l.once("end",()=>{process.nextTick(()=>{this._finalizeSocket(e,this._agent?.keepAlive===!0&&!this.aborted)})}),this._callback&&this._callback(l),this._emit("response",l),!this._callback&&this._listenerCount("response")===0&&queueMicrotask(()=>{l.resume()})}_execute(){if(this._skipExecute)return;if(this._agent){this._agent.addRequest(this,this._options);return}let e=r=>{if(!r){this._handleSocketError(new Error("Failed to create socket")),this._emitClose();return}this._assignSocket(r,!1)},t=this._options.createConnection;if(typeof t=="function"){let r=t(this._options,(n,i)=>{e(i)});e(r);return}e(eI(this._options))}_buildUrl(){let e=this._options,t=e.protocol||(e.port===443?"https:":"http:"),r=e.hostname||e.host||"localhost",n=e.port?":"+e.port:"",i=e.path||"/";return t+"//"+r+n+i}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}addListener(e,t){return this.on(e,t)}once(e,t){let r=(...n)=>{this.off(e,r),t(...n)};return r.listener=t,this.on(e,r)}off(e,t){if(this._listeners[e]){let r=this._listeners[e].findIndex(n=>n===t||n.listener===t);r!==-1&&this._listeners[e].splice(r,1)}return this}removeListener(e,t){return this.off(e,t)}getHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");return this._headers[e.toLowerCase()]}getHeaders(){let e=Object.create(null);for(let[t,r]of Object.entries(this._headers))e[t]=Array.isArray(r)?[...r]:r;return e}getHeaderNames(){return Object.keys(this._headers)}getRawHeaderNames(){return Object.keys(this._headers).map(e=>this._rawHeaderNames.get(e)||e)}hasHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");return Object.prototype.hasOwnProperty.call(this._headers,e.toLowerCase())}removeHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");let t=e.toLowerCase();delete this._headers[t],this._rawHeaderNames.delete(t),this._options.headers={...this._headers}}_emit(e,...t){zl(this,this._listeners[e],t)}_listenerCount(e){return this._listeners[e]?.length||0}_setOutgoingHeaders(e){if(this._headers={},this._rawHeaderNames=new Map,!e){this._options.headers={};return}if(Array.isArray(e)){for(let t=0;t{r!==void 0&&this._setHeaderValue(t,r)})}_setHeaderValue(e,t){let r=Gi(e).toLowerCase();Yi(r,t),this._headers[r]=Array.isArray(t)?t.map(n=>String(n)):String(t),this._rawHeaderNames.has(r)||this._rawHeaderNames.set(r,e),this._options.headers={...this._headers}}write(e){let t=typeof Buffer<"u"?Buffer.byteLength(e):e.length;if(this._bodyBytes+t>ql)throw new Error("ERR_HTTP_BODY_TOO_LARGE: request body exceeds "+ql+" byte limit");return this._body+=e,this._bodyBytes+=t,!0}end(e){return e&&this.write(e),this._ended=!0,this}abort(){this.aborted||(this.aborted=!0,this._abortEmitted||(this._abortEmitted=!0,queueMicrotask(()=>{this._emit("abort")})),this._loopbackAbort?.(),this.destroy())}destroy(e){if(this.destroyed)return this;this.destroyed=!0,this._clearTimeout(),this._unbindAbortSignal(),this._loopbackAbort?.(),this._loopbackAbort=void 0,!this.socket&&e&&e.code==="ABORT_ERR"&&(this._skipExecute=!0);let t=this._response!=null,r=e??(!this.aborted&&!t?Na():void 0);return this._destroyError=r,this._response&&!this._response.complete&&!this._response.aborted&&this._response._abort(r??Na("aborted")),this.socket&&!this.socket.destroyed?(r&&!this._errorEmitted&&(this._errorEmitted=!0,queueMicrotask(()=>{this._emit("error",r)})),this.socket.destroy(r)):(r&&(this._errorEmitted=!0,queueMicrotask(()=>{this._emit("error",r)})),queueMicrotask(()=>{this._emitClose()})),this}setTimeout(e,t){if(t&&this.once("timeout",t),this.timeoutCb=()=>{this._emit("timeout")},this._clearTimeout(),e===0)return this;if(!Number.isFinite(e)||e<0)throw new TypeError(`The "timeout" argument must be of type number. Received ${String(e)}`);return this._options.timeout=e,this.socket&&this._applyTimeoutToSocket(this.socket),this}setNoDelay(){return this}setSocketKeepAlive(){return this}flushHeaders(){}_emitClose(){this._closeEmitted||(this._closeEmitted=!0,this._emit("close"))}_applyTimeoutToSocket(e){let t=this._options.timeout;typeof t!="number"||t===0||(this.timeoutCb||(this.timeoutCb=()=>{this._emit("timeout")}),e.off?.("timeout",this.timeoutCb),e.removeListener?.("timeout",this.timeoutCb),e.setTimeout?.(t,this.timeoutCb))}_validateTimeoutOption(){let e=this._options.timeout;if(e!==void 0&&typeof e!="number"){let t=e===null?"null":typeof e=="string"?`type string ('${e}')`:`type ${typeof e} (${JSON.stringify(e)})`,r=new TypeError(`The "timeout" argument must be of type number. Received ${t}`);throw r.code="ERR_INVALID_ARG_TYPE",r}}_bindAbortSignal(){let e=this._options.signal;if(!e)return;if(this._signalAbortHandler=()=>{this.destroy(QG())},e.aborted){this.destroyed=!0,this._skipExecute=!0,queueMicrotask(()=>{this._emit("error",QG()),this._emitClose()});return}if(typeof e.addEventListener=="function"){e.addEventListener("abort",this._signalAbortHandler,{once:!0});return}let t=e;t.__secureExecPrevOnAbort__=t.onabort??null,t.onabort=(r=>{t.__secureExecPrevOnAbort__?.call(e,r),this._signalAbortHandler?.()}),this._startAbortSignalPoll(e)}_unbindAbortSignal(){let e=this._options.signal;if(!e||!this._signalAbortHandler)return;if(this._signalPollTimer&&(clearTimeout(this._signalPollTimer),this._signalPollTimer=null),typeof e.removeEventListener=="function"){e.removeEventListener("abort",this._signalAbortHandler),this._signalAbortHandler=void 0;return}let t=e;(t.onabort===this._signalAbortHandler||t.__secureExecPrevOnAbort__!==void 0)&&(t.onabort=t.__secureExecPrevOnAbort__??null),delete t.__secureExecPrevOnAbort__,this._signalAbortHandler=void 0}_startAbortSignalPoll(e){let t=()=>{if(this.destroyed){this._signalPollTimer=null;return}if(e.aborted){this._signalPollTimer=null,this._signalAbortHandler?.();return}this._signalPollTimer=setTimeout(t,5)};this._signalPollTimer||(this._signalPollTimer=setTimeout(t,5))}_clearTimeout(){this.socket&&this.timeoutCb&&(this.socket.off?.("timeout",this.timeoutCb),this.socket.removeListener?.("timeout",this.timeoutCb)),this.socket?.setTimeout&&this.socket.setTimeout(0)}};var GSe=class{constructor(e){y(this,"remoteAddress");y(this,"remotePort");y(this,"localAddress","127.0.0.1");y(this,"localPort",0);y(this,"connecting",!1);y(this,"destroyed",!1);y(this,"writable",!0);y(this,"readable",!0);y(this,"readyState","open");y(this,"bytesWritten",0);y(this,"_listeners",{});y(this,"_encoding");y(this,"_peer",null);y(this,"_readableState",{endEmitted:!1,ended:!1});y(this,"_writableState",{finished:!1,errorEmitted:!1});this.remoteAddress=e?.host||"127.0.0.1",this.remotePort=e?.port||80}_attachPeer(e){this._peer=e}setTimeout(e,t){return this}setNoDelay(e){return this}setKeepAlive(e,t){return this}setEncoding(e){return this._encoding=e,this}ref(){return this}unref(){return this}cork(){}uncork(){}pause(){return this}resume(){return this}address(){return{address:this.localAddress,family:"IPv4",port:this.localPort}}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){let r=(...n)=>{this.off(e,r),t.call(this,...n)};return this.on(e,r)}off(e,t){let r=this._listeners[e];if(!r)return this;let n=r.indexOf(t);return n!==-1&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e?delete this._listeners[e]:this._listeners={},this}emit(e,...t){let r=this._listeners[e];return zl(this,r,t)}listenerCount(e){return this._listeners[e]?.length||0}write(e,t,r){if(this.destroyed||!this._peer)return!1;let n=typeof t=="function"?t:r,i=YSe(e);return this.bytesWritten+=i.length,queueMicrotask(()=>{this._peer?._pushData(i)}),n?.(),!0}end(e){return e!==void 0&&this.write(e),this.writable=!1,this._writableState.finished=!0,queueMicrotask(()=>{this._peer?._pushEnd()}),this.emit("finish"),this}destroy(e){return this.destroyed?this:(this.destroyed=!0,this.readable=!1,this.writable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._writableState.finished=!0,e&&this.emit("error",e),queueMicrotask(()=>{this._peer?._pushEnd()}),this.emit("close",!1),this)}_pushData(e){!this.readable||this.destroyed||this.emit("data",this._encoding?e.toString(this._encoding):e)}_pushEnd(){this.destroyed||(this.readable=!1,this.writable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._writableState.finished=!0,this.emit("end"),this.emit("close",!1))}};function YSe(e){return typeof Buffer<"u"&&Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):Buffer.from(String(e))}var Eu,NB=(Eu=class{constructor(t){y(this,"options");y(this,"maxSockets");y(this,"maxTotalSockets");y(this,"maxFreeSockets");y(this,"keepAlive");y(this,"keepAliveMsecs");y(this,"timeout");y(this,"requests");y(this,"sockets");y(this,"freeSockets");y(this,"totalSocketCount");y(this,"_listeners",{});this.options={...t},this._validateSocketCountOption("maxSockets",t?.maxSockets),this._validateSocketCountOption("maxFreeSockets",t?.maxFreeSockets),this._validateSocketCountOption("maxTotalSockets",t?.maxTotalSockets),this.keepAlive=t?.keepAlive??!1,this.keepAliveMsecs=t?.keepAliveMsecs??1e3,this.maxSockets=t?.maxSockets??Eu.defaultMaxSockets,this.maxTotalSockets=t?.maxTotalSockets??1/0,this.maxFreeSockets=t?.maxFreeSockets??256,this.timeout=t?.timeout??-1,this.requests={},this.sockets={},this.freeSockets={},this.totalSocketCount=0}_validateSocketCountOption(t,r){if(r!==void 0){if(typeof r!="number"){let n=typeof r=="string"?`type string ('${r}')`:`type ${typeof r} (${JSON.stringify(r)})`,i=new TypeError(`The "${t}" argument must be of type number. Received ${n}`);throw i.code="ERR_INVALID_ARG_TYPE",i}if(Number.isNaN(r)||r<=0){let n=new RangeError(`The value of "${t}" is out of range. It must be > 0. Received ${String(r)}`);throw n.code="ERR_OUT_OF_RANGE",n}}}getName(t){let r=t?.hostname||t?.host||"localhost",n=t?.port??"",i=t?.localAddress??"",s="";return t?.socketPath?s=`:${t.socketPath}`:(t?.family===4||t?.family===6)&&(s=`:${t.family}`),`${r}:${n}:${i}${s}`}_getHostKey(t){return this.getName(t)}on(t,r){return this._listeners[t]||(this._listeners[t]=[]),this._listeners[t].push(r),this}once(t,r){let n=(...i)=>{this.off(t,n),r(...i)};return this.on(t,n)}off(t,r){let n=this._listeners[t];if(!n)return this;let i=n.indexOf(r);return i!==-1&&n.splice(i,1),this}removeListener(t,r){return this.off(t,r)}emit(t,...r){let n=this._listeners[t];return zl(this,n,r)}createConnection(t,r){let n=typeof t.createConnection=="function"?t.createConnection:typeof this.options.createConnection=="function"?this.options.createConnection:null;return n?n(t,r??(()=>{})):eI(t,r)}addRequest(t,r){let n=this.getName(r),i=this._takeFreeSocket(n);if(i){this._activateSocket(n,i),t._assignSocket(i,!0);return}if(this._canCreateSocket(n)){this._createSocketForRequest(n,t,r);return}this.requests[n]||(this.requests[n]=[]),this.requests[n].push({request:t,options:r})}_releaseSocket(t,r,n,i){let s=this._removeSocket(this.sockets,t,r);if(i&&!r.destroyed){let o=this.freeSockets[t]??(this.freeSockets[t]=[]);o.length0&&(r._freeTimer=setTimeout(()=>{r._freeTimer=null,r.destroy()},this.timeout)),r.emit("free"),this.emit("free",r,n)):(s&&(this.totalSocketCount=Math.max(0,this.totalSocketCount-1)),r.destroy())}else r.destroyed||(s&&(this.totalSocketCount=Math.max(0,this.totalSocketCount-1)),r.destroy());Promise.resolve().then(()=>this._processPendingRequests())}_removeSocketCompletely(t,r){r._freeTimer&&(clearTimeout(r._freeTimer),r._freeTimer=null),(this._removeSocket(this.sockets,t,r)||this._removeSocket(this.freeSockets,t,r))&&(this.totalSocketCount=Math.max(0,this.totalSocketCount-1),Promise.resolve().then(()=>this._processPendingRequests()))}_canCreateSocket(t){return(this.sockets[t]?.length??0)>=this.maxSockets?!1:this.totalSocketCount0;){let n=r.shift();if(!n.destroyed)return n._freeTimer&&(clearTimeout(n._freeTimer),n._freeTimer=null),r.length===0&&delete this.freeSockets[t],n;this.totalSocketCount=Math.max(0,this.totalSocketCount-1)}return r&&r.length===0&&delete this.freeSockets[t],null}_activateSocket(t,r){(this.sockets[t]??(this.sockets[t]=[])).push(r)}_createSocketForRequest(t,r,n){let i=!1,s=(a,A)=>{if(!i){if(i=!0,a||!A){r._handleSocketError(a??new Error("Failed to create socket")),this._processPendingRequests();return}if(r.destroyed){this.totalSocketCount+=1,this._activateSocket(t,A),A.once("close",()=>{this._removeSocketCompletely(t,A)}),r._assignSocket(A,!1);return}this.totalSocketCount+=1,this._activateSocket(t,A),A.once("close",()=>{this._removeSocketCompletely(t,A)}),r._assignSocket(A,!1)}},o={...n,keepAlive:this.keepAlive,keepAliveInitialDelay:this.keepAliveMsecs};try{let a=this.createConnection(o,(A,f)=>{s(A,f)});a&&s(null,a)}catch(a){s(a instanceof Error?a:new Error(String(a)))}}_processPendingRequests(){for(let t of Object.keys(this.requests)){let r=this.requests[t];for(;r&&r.length>0;){let n=this._takeFreeSocket(t);if(n){let s=r.shift();if(s.request.destroyed){this._activateSocket(t,n),this._releaseSocket(t,n,s.options,!0);continue}this._activateSocket(t,n),s.request._assignSocket(n,!0);continue}if(!this._canCreateSocket(t))break;let i=r.shift();i.request.destroyed||this._createSocketForRequest(t,i.request,i.options)}(!r||r.length===0)&&delete this.requests[t]}}_removeSocket(t,r,n){let i=t[r];if(!i)return!1;let s=i.indexOf(n);return s===-1?!1:(i.splice(s,1),i.length===0&&delete t[r],!0)}_evictFreeSocket(t){let r=Object.keys(this.freeSockets),n=r.includes(t)?[...r.filter(i=>i!==t),t]:r;for(let i of n){let s=this.freeSockets[i]?.[0];if(s){s.destroy();return}}}destroy(){for(let t of Object.values(this.sockets).flat())t.destroy();for(let t of Object.values(this.freeSockets).flat())t.destroy();this.requests={},this.sockets={},this.freeSockets={},this.totalSocketCount=0}},y(Eu,"defaultMaxSockets",1/0),Eu);function nr(...e){process.env.SECURE_EXEC_DEBUG_HTTP_BRIDGE==="1"&&console.error("[secure-exec bridge network]",...e)}var WSe=1,jg=new Map,VSe=["ACL","BIND","CHECKOUT","CONNECT","COPY","DELETE","GET","HEAD","LINK","LOCK","M-SEARCH","MERGE","MKACTIVITY","MKCALENDAR","MKCOL","MOVE","NOTIFY","OPTIONS","PATCH","POST","PROPFIND","PROPPATCH","PURGE","PUT","QUERY","REBIND","REPORT","SEARCH","SOURCE","SUBSCRIBE","TRACE","UNBIND","UNLINK","UNLOCK","UNSUBSCRIBE"],JSe=/[^\u0021-\u00ff]/,jSe=new Set(["!","#","$","%","&","'","*","+","-",".","^","_","`","|","~"]);function lr(e,t){let r=new TypeError(e);return r.code=t,r}function MB(e,t){let r=new Error(e);return r.code=t,r}function Yn(e){if(e===null)return"null";if(Array.isArray(e))return"an instance of Array";let t=typeof e;return t==="function"?`function ${typeof e.name=="string"&&e.name.length>0?e.name:"anonymous"}`:t==="object"?`an instance of ${e&&typeof e=="object"&&typeof e.constructor?.name=="string"?e.constructor.name:"Object"}`:t==="string"?`type string ('${String(e)}')`:t==="symbol"?`type symbol (${String(e)})`:`type ${t} (${String(e)})`}function i2(e,t,r){return lr(`The "${e}" property must be of type ${t}. Received ${Yn(r)}`,"ERR_INVALID_ARG_TYPE")}function RW(e){if(e.length===0)return!1;for(let t=0;t=48&&n<=57||n>=65&&n<=90||n>=97&&n<=122)&&!jSe.has(r))return!1}return!0}function DW(e){for(let t=0;t255))return!0}return!1}function Gi(e,t="Header name"){let r=String(e);if(!RW(r))throw lr(`${t} must be a valid HTTP token [${JSON.stringify(r)}]`,"ERR_INVALID_HTTP_TOKEN");return r}function Yi(e,t){if(t===void 0)throw lr(`Invalid value "undefined" for header "${e}"`,"ERR_HTTP_INVALID_HEADER_VALUE");if(Array.isArray(t)){for(let r of t)Yi(e,r);return}if(DW(String(t)))throw lr(`Invalid character in header content [${JSON.stringify(e)}]`,"ERR_INVALID_CHAR")}function Cl(e){return Array.isArray(e)?e.map(t=>String(t)):String(e)}function _u(e){return Array.isArray(e)?e.join(", "):e}function wG(e){return Array.isArray(e)?[...e]:e}function vo(e,t,r){if(t==="set-cookie"){let i=e[t];i===void 0?e[t]=[r]:Array.isArray(i)?i.push(r):e[t]=[i,r];return}let n=e[t];e[t]=n===void 0?r:`${_u(n)}, ${r}`}function zSe(e){if(!(e==null||e==="")){if(typeof e!="string")throw i2("options.method","string",e);return Gi(e,"Method")}}function KSe(e){let t=e==null||e===""?"/":String(e);if(JSe.test(t))throw lr("Request path contains unescaped characters","ERR_UNESCAPED_CHARACTERS");return t}function XSe(e){let t=String(e.hostname||e.host||"localhost"),r=e.protocol==="https:"||Number(e.port)===443?443:80,n=e.port!=null?Number(e.port):r;return n===r?t:`${t}:${n}`}function s2(e){return Array.isArray(e)&&(e.length===0||typeof e[0]=="string")}function ZSe(e){if(!e)return{};if(Array.isArray(e)){let r={};for(let n=0;n{if(n===void 0)return;let i=Gi(r).toLowerCase();if(Yi(i,n),Array.isArray(n)){n.forEach(s=>vo(t,i,String(s)));return}vo(t,i,String(n))}),t}function TW(e){return _u(e.connection||"").toLowerCase().includes("upgrade")&&!!e.upgrade}function $Se(e,t){return String(e||"GET").toUpperCase()==="CONNECT"?!0:TW(t)}function cR(e){return e==="https:"?"secureConnect":"connect"}function e_e(e,t){return!e||e.destroyed===!0?!1:t==="https:"?e.encrypted===!0&&e._tlsUpgrading!==!0:e._connected===!0||e._loopbackServer?!0:typeof e._socketId=="number"?!1:e.connecting===!1}function SG(e,t){return e_e(e,t)?Promise.resolve():new Promise((r,n)=>{let i=cR(t),s=()=>{A(),r()},o=f=>{A(),n(f instanceof Error?f:new Error(String(f)))},a=()=>{A(),n(Na("socket closed before request was ready"))},A=()=>{e.off?.(i,s),e.removeListener?.(i,s),e.off?.("error",o),e.removeListener?.("error",o),e.off?.("close",a),e.removeListener?.("close",a)};e.once(i,s),e.once("error",o),e.once("close",a)})}function t_e(e){let t=e?.protocol==="https:"?"https:":"http:",r=String(e?.hostname||e?.host||"localhost"),n=t==="https:"?443:80,i=Number(e?.port)||n,s=new URL(`${t}//${r}`);return i!==n&&(s.port=String(i)),s.origin}function r_e(e,t){if(typeof AG!="function"||typeof nW!="function")throw new Error("Undici request transport is not available");let r=t_e(t);if(e._agentOSUndiciClient&&e._agentOSUndiciOrigin===r&&e._agentOSUndiciClient.destroyed!==!0)return e._agentOSUndiciClient;let n=new AG(r,{pipelining:1,connect(s,o){return o(null,e),e}}),i=()=>{e._agentOSUndiciClient===n&&(e._agentOSUndiciClient=null,e._agentOSUndiciOrigin=null)};return e.once?.("close",i),e._agentOSUndiciClient=n,e._agentOSUndiciOrigin=r,n}function eI(e,t){let r=e?.protocol==="https:"?"https:":"http:",n=String(e?.hostname||e?.host||"localhost"),i=Number(e?.port)||(r==="https:"?443:80),s=r==="https:"?SW({host:n,localAddress:e?.localAddress,localPort:e?.localPort,port:i,servername:e?.servername||n,rejectUnauthorized:e?.rejectUnauthorized,socket:e?.socket}):Z1({host:n,localAddress:e?.localAddress,localPort:e?.localPort,port:i,path:e?.socketPath,keepAlive:e?.keepAlive,keepAliveInitialDelay:e?.keepAliveInitialDelay});if(t){let o=cR(r),a=()=>{f(),t(null,s)},A=l=>{f(),t(l instanceof Error?l:new Error(String(l)))},f=()=>{s.off?.(o,a),s.removeListener?.(o,a),s.off?.("error",A),s.removeListener?.("error",A)};s.once(o,a),s.once("error",A)}return s}function n_e(e){let t=[];for(let[r,n]of e)t.push(r,n);return t}function _G(e,t){let r=[];return Object.entries(e).forEach(([n,i])=>{let s=t.get(n)||n;if(Array.isArray(i)){i.forEach(o=>{r.push([s,String(o)])});return}r.push([s,String(i)])}),r}function i_e(e,t,r,n){let i=[`${e} ${t} HTTP/1.1`];r.forEach(([o,a])=>{i.push(`${o}: ${a}`)}),i.push("","");let s=Buffer.from(i.join(`\r -`),"latin1");return!n||n.length===0?s:Buffer.concat([s,n])}async function s_e(e){if(!e)return Buffer.alloc(0);let t=[];for await(let r of e)typeof Buffer<"u"&&Buffer.isBuffer(r)?t.push(r):r instanceof Uint8Array?t.push(Buffer.from(r)):t.push(Buffer.from(String(r)));return t.length===0?Buffer.alloc(0):t.length===1?t[0]:Buffer.concat(t)}function o_e(e){let t=e.indexOf(`\r -\r -`);if(t===-1)return null;let n=e.subarray(0,t).toString("latin1").split(`\r -`),i=n.shift()||"",s=/^HTTP\/(\d)\.(\d)\s+(\d{3})(?:\s+(.*))?$/.exec(i);if(!s)throw new Error(`Invalid HTTP response status line: ${i}`);let o={},a=[],A=null;for(let f of n){if(!f)continue;if((f.startsWith(" ")||f.startsWith(" "))&&a.length>=2&&A){let S=f.trim();a[a.length-1]+=` ${S}`,o[A]=_u(o[A])+` ${S}`;continue}let l=f.indexOf(":");if(l===-1)throw new Error(`Invalid HTTP response header line: ${f}`);let p=f.slice(0,l),B=f.slice(l+1).trim();A=p.toLowerCase(),a.push(p,B),vo(o,A,B)}return{status:Number(s[3]),statusText:s[4]||"",headers:o,rawHeaders:a,head:e.subarray(t+4)}}function a_e(e,t,r){return new Promise((n,i)=>{let s=null,o=Buffer.alloc(0),a=null,A=!1,f=!1,l=!1,p=(Z,ee)=>{if(!l){if(l=!0,B(),Z){i(Z);return}n(ee)}},B=()=>{clearTimeout(Y),e.off?.("data",N),e.removeListener?.("data",N),e.off?.("error",P),e.removeListener?.("error",P),e.off?.("end",U),e.removeListener?.("end",U),e.off?.("close",G),e.removeListener?.("close",G)},S=()=>{if(!s)return!1;if(!o2(s.status,t))return p(null,{...s,body:Buffer.alloc(0)}),!0;if(A){let Z=MW(o);return Z===null?(p(new Error("Invalid chunked HTTP response body")),!0):Z.complete?(p(null,{...s,body:Z.body}),!0):!1}return a!==null?o.length{if(!s||!o2(s.status,t))return;let Z=s.headers["transfer-encoding"],ee=s.headers["content-length"];if(Z!==void 0){let j=lR(_u(Z)),se=j.filter(H=>H==="chunked").length,ie=se>0,ce=ie&&j[j.length-1]==="chunked";if(!ie||se!==1||!ce||ee!==void 0)throw new Error("Unsupported transfer-encoding in HTTP response");A=!0;return}if(ee!==void 0){let j=NW(ee);if(j===null)throw new Error("Invalid content-length in HTTP response");a=j;return}f=!0},N=Z=>{let ee=Buffer.isBuffer(Z)?Z:Buffer.from(Z);if(!s){o=Buffer.concat([o,ee]);try{let j=o_e(o);if(!j)return;s=j,o=Buffer.from(j.head),_(),S()}catch(j){p(j instanceof Error?j:new Error(String(j)))}return}o=Buffer.concat([o,ee]);try{S()}catch(j){p(j instanceof Error?j:new Error(String(j)))}},P=Z=>{p(Z instanceof Error?Z:new Error(String(Z)))},U=()=>{if(!s){p(Na("socket ended before receiving HTTP response head"));return}if(f){p(null,{...s,body:o});return}S()||p(Na("socket ended before receiving complete HTTP response body"))},G=()=>{if(!s){p(Na("socket closed before receiving HTTP response head"));return}if(f){p(null,{...s,body:o});return}S()||p(Na("socket closed before receiving complete HTTP response body"))},Y=setTimeout(()=>{p(new Error(`Timed out waiting for HTTP response after ${r}ms`))},r);e.on("data",N),e.once("error",P),e.once("end",U),e.once("close",G)})}function o2(e,t){return!(t==="HEAD"||e>=100&&e<200||e===204||e===304)}function lR(e){return e.split(",").map(t=>t.trim().toLowerCase()).filter(t=>t.length>0)}function NW(e){if(e===void 0)return 0;let t=Array.isArray(e)?e:[e],r=null;for(let n of t){if(!/^\d+$/.test(n))return null;let i=Number(n);if(!Number.isSafeInteger(i)||i<0||r!==null&&r!==i)return null;r=i}return r??0}function MW(e,t=ql){let r=0,n=0,i=[];for(;;){let s=e.indexOf(`\r -`,r);if(s===-1)return{complete:!1};let o=e.subarray(r,s).toString("latin1");if(o.length===0||/[\r\n]/.test(o))return null;let[a,A]=o.split(";",2);if(!/^[0-9A-Fa-f]+$/.test(a)||A!==void 0&&/[\r\n]/.test(A))return null;let f=Number.parseInt(a,16);if(!Number.isSafeInteger(f)||f<0||n+f>t)return null;let l=s+2;if(f===0){let S=l;if(S===e.length)return{complete:!1};if(e[S]===13&&e[S+1]===10)return{complete:!0,bytesConsumed:S+2,body:i.length>0?Buffer.concat(i):Buffer.alloc(0)};let _=e.indexOf(`\r -\r -`,S);if(_===-1)return{complete:!1};let N=e.subarray(S,_).toString("latin1");if(N.length>0){for(let P of N.split(`\r -`))if(P.length!==0&&(P.startsWith(" ")||P.startsWith(" ")||P.indexOf(":")===-1))return null}return{complete:!0,bytesConsumed:_+4,body:i.length>0?Buffer.concat(i):Buffer.alloc(0)}}let p=l+f,B=p+2;if(B>e.length)return{complete:!1};if(e[p]!==13||e[p+1]!==10)return null;n+=f,i.push(e.subarray(l,p)),r=B}}function FW(e,t){let r=0;for(;r+1RG?{kind:"bad-request",closeConnection:!0}:{kind:"incomplete"};if(n-r>RG)return{kind:"bad-request",closeConnection:!0};let i=e.subarray(r,n).toString("latin1"),[s,...o]=i.split(`\r -`);if(o.length>y_e)return{kind:"bad-request",closeConnection:!0};let a=/^([A-Z]+)\s+(\S+)\s+HTTP\/(1)\.(0|1)$/.exec(s);if(!a)return{kind:"bad-request",closeConnection:!0};let A={},f=[],l=null;try{for(let Z of o){if(Z.length===0)continue;if(Z.startsWith(" ")||Z.startsWith(" "))return{kind:"bad-request",closeConnection:!0};let ee=Z.indexOf(":");if(ee===-1)return{kind:"bad-request",closeConnection:!0};let j=Z.slice(0,ee).trim(),se=Z.slice(ee+1).trim(),ie=Gi(j).toLowerCase();Yi(ie,se),vo(A,ie,se),f.push(j,se),l=ie}}catch{return{kind:"bad-request",closeConnection:!0}}let p=a[1],B=a[2],S=Number(a[4]),_=_u(A.connection||"").toLowerCase(),N=S===0?!_.includes("keep-alive"):_.includes("close");if(TW(A)&&t.listenerCount("upgrade")>0)return{kind:"request",bytesConsumed:e.length,closeConnection:!1,request:{method:p,url:B,headers:A,rawHeaders:f,bodyBase64:n+4ce==="chunked").length,j=ee>0,se=j&&Z[Z.length-1]==="chunked";if(!j||ee!==1||!se||U!==void 0)return{kind:"bad-request",closeConnection:!0};let ie=MW(e.subarray(n+4));if(ie===null)return{kind:"bad-request",closeConnection:!0};if(!ie.complete)return{kind:"incomplete"};G=ie.body,Y=n+4+ie.bytesConsumed}else if(U!==void 0){let Z=NW(U);if(Z===null||Z>ql)return{kind:"bad-request",closeConnection:!0};let ee=n+4+Z;if(ee>e.length)return{kind:"incomplete"};G=e.subarray(n+4,ee),Y=ee}return{kind:"request",bytesConsumed:Y,closeConnection:N,request:{method:p,url:B,headers:A,rawHeaders:f,bodyBase64:G.length>0?G.toString("base64"):void 0}}}function Ig(e,t){let r={},n=new Map,i=[];if(Array.isArray(e)&&e.length>0){for(let s=0;s`${ee}: ${j}\r -`).join("");N.push(Buffer.from(`HTTP/1.1 ${G.status} ${G.statusText||zg[G.status]||""}\r -${Z}\r -`,"latin1"))}let U=h1(s,o,a).map(([G,Y])=>`${G}: ${Y}\r -`).join("");if(N.push(Buffer.from(`HTTP/1.1 ${n} ${i}\r -${U}\r -`,"latin1")),l)if(B){if(f.length>0&&(N.push(Buffer.from(f.length.toString(16)+`\r -`,"latin1")),N.push(f),N.push(Buffer.from(`\r -`,"latin1"))),N.push(Buffer.from(`0\r -`,"latin1")),Object.keys(A.headers).length>0){let G=h1(A.headers,A.rawNameMap,A.order);for(let[Y,Z]of G)N.push(Buffer.from(`${Y}: ${Z}\r -`,"latin1"))}N.push(Buffer.from(`\r -`,"latin1"))}else f.length>0&&N.push(f);return{payload:N.length===1?N[0]:Buffer.concat(N),closeConnection:_}}var zg={100:"Continue",101:"Switching Protocols",102:"Processing",103:"Early Hints",200:"OK",201:"Created",204:"No Content",301:"Moved Permanently",302:"Found",304:"Not Modified",400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"};var Nu=class{constructor(e){y(this,"headers");y(this,"rawHeaders");y(this,"method");y(this,"url");y(this,"socket");y(this,"connection");y(this,"rawBody");y(this,"destroyed",!1);y(this,"errored");y(this,"readable",!0);y(this,"httpVersion","1.1");y(this,"httpVersionMajor",1);y(this,"httpVersionMinor",1);y(this,"complete",!0);y(this,"aborted",!1);y(this,"_readableState",{flowing:null,length:0,ended:!1,objectMode:!1});y(this,"_listeners",{});this.headers=e.headers||{},this.rawHeaders=e.rawHeaders||[],(!Array.isArray(this.rawHeaders)||this.rawHeaders.length%2!==0)&&(this.rawHeaders=[]),this.method=e.method||"GET",this.url=e.url||"/";let t={encrypted:!1,remoteAddress:"127.0.0.1",remotePort:0,writable:!0,on(){return t},once(){return t},removeListener(){return t},destroy(){},end(){}};this.socket=t,this.connection=t;let r=this.headers.host;typeof r=="string"&&r.includes(",")&&(this.headers.host=r.split(",")[0].trim()),this.headers.host||(this.headers.host="127.0.0.1"),this.rawHeaders.length===0&&Object.entries(this.headers).forEach(([n,i])=>{if(Array.isArray(i)){i.forEach(s=>{this.rawHeaders.push(n,s)});return}this.rawHeaders.push(n,i)}),e.bodyBase64&&typeof Buffer<"u"&&(this.rawBody=Buffer.from(e.bodyBase64,"base64"))}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){let r=(...n)=>{this.off(e,r),t.call(this,...n)};return this.on(e,r)}off(e,t){let r=this._listeners[e];if(!r)return this;let n=r.indexOf(t);return n!==-1&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}emit(e,...t){let r=this._listeners[e];return zl(this,r,t)}unpipe(){return this}pause(){return this}resume(){return this}read(){return null}pipe(e){return e}isPaused(){return!1}setEncoding(){return this}destroy(e){return this.destroyed=!0,this.errored=e,e&&this.emit("error",e),this.emit("close"),this}_abort(){if(this.aborted)return;this.aborted=!0;let e=Na("aborted");this.emit("aborted"),this.emit("error",e),this.emit("close")}},c0=class{constructor(){y(this,"statusCode",200);y(this,"statusMessage","OK");y(this,"headersSent",!1);y(this,"writable",!0);y(this,"writableFinished",!1);y(this,"outputSize",0);y(this,"_headers",new Map);y(this,"_trailers",new Map);y(this,"_chunks",[]);y(this,"_chunksBytes",0);y(this,"_streamed",!1);y(this,"_listeners",{});y(this,"_closedPromise");y(this,"_resolveClosed",null);y(this,"_connectionEnded",!1);y(this,"_connectionReset",!1);y(this,"_rawHeaderNames",new Map);y(this,"_rawTrailerNames",new Map);y(this,"_informational",[]);y(this,"_pendingRawInfoBuffer","");y(this,"_streamSocket",null);y(this,"_streamRequest",null);y(this,"_streamedDirectly",!1);y(this,"_streamCloseConnection",!1);y(this,"_writableState",{length:0,ended:!1,finished:!1,objectMode:!1,corked:0});y(this,"socket",{writable:!0,writableCorked:0,writableHighWaterMark:16*1024,on:()=>this.socket,once:()=>this.socket,removeListener:()=>this.socket,destroy:()=>{this._connectionReset=!0,this._finalize()},end:()=>{this._connectionEnded=!0},cork:()=>{this._writableState.corked+=1,this.socket.writableCorked=this._writableState.corked},uncork:()=>{this._writableState.corked=Math.max(0,this._writableState.corked-1),this.socket.writableCorked=this._writableState.corked},write:(e,t,r)=>this.write(e,t,r)});y(this,"connection",this.socket);this._closedPromise=new Promise(e=>{this._resolveClosed=e})}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){let r=(...n)=>{this.off(e,r),t.call(this,...n)};return this.on(e,r)}off(e,t){let r=this._listeners[e];if(!r)return this;let n=r.indexOf(t);return n!==-1&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}emit(e,...t){let r=this._listeners[e];return!r||r.length===0?!1:(r.slice().forEach(n=>n.call(this,...t)),!0)}_emit(e,...t){this.emit(e,...t)}writeHead(e,t){if(e>=100&&e<200&&e!==101){let r=new Map,n=new Map;if(t)if(s2(t))for(let o=0;o{let A=Gi(o).toLowerCase();Yi(A,a),r.set(A,String(a)),n.has(A)||n.set(A,o)}):Object.entries(t).forEach(([o,a])=>{let A=Gi(o).toLowerCase();Yi(A,a),r.set(A,String(a)),n.has(A)||n.set(A,o)});let i=Array.from(r.entries()).flatMap(([o,a])=>{let A=Cl(a);return Array.isArray(A)?A.map(f=>[o,f]):[[o,A]]}),s=Array.from(r.entries()).flatMap(([o,a])=>{let A=n.get(o)||o,f=Cl(a);return Array.isArray(f)?f.flatMap(l=>[A,l]):[A,f]});return this._informational.push({status:e,statusText:zg[e],headers:i,rawHeaders:s}),this}if(this.statusCode=e,t)if(s2(t))for(let r=0;rthis.setHeader(r,n)):Object.entries(t).forEach(([r,n])=>this.setHeader(r,n));return this.headersSent=!0,this.outputSize+=64,this}setHeader(e,t){if(this.headersSent)throw MB("Cannot set headers after they are sent to the client","ERR_HTTP_HEADERS_SENT");let r=Gi(e).toLowerCase();Yi(r,t);let n=Array.isArray(t)?Array.from(t):t;return this._headers.set(r,n),this._rawHeaderNames.has(r)||this._rawHeaderNames.set(r,e),this}setHeaders(e){if(this.headersSent)throw MB("Cannot set headers after they are sent to the client","ERR_HTTP_HEADERS_SENT");if(!(e instanceof PA)&&!(e instanceof Map))throw lr(`The "headers" argument must be an instance of Headers or Map. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");if(e instanceof PA){let t=Object.create(null);return e.forEach((r,n)=>{vo(t,n.toLowerCase(),r)}),Object.entries(t).forEach(([r,n])=>{this.setHeader(r,n)}),this}return e.forEach((t,r)=>{this.setHeader(r,t)}),this}getHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");let t=this._headers.get(e.toLowerCase());return t===void 0?void 0:wG(t)}hasHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");return this._headers.has(e.toLowerCase())}removeHeader(e){if(typeof e!="string")throw lr(`The "name" argument must be of type string. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE");let t=e.toLowerCase();this._headers.delete(t),this._rawHeaderNames.delete(t)}_appendChunk(e,t,r){if(e==null)return!0;let n=typeof e=="string"?Buffer.from(e,typeof t=="string"?t:void 0):e;if(this._chunksBytes+n.byteLength>ql)throw new Error("ERR_HTTP_BODY_TOO_LARGE: response body exceeds "+ql+" byte limit");return this._chunks.push(n),this._chunksBytes+=n.byteLength,this._streamed||(this._streamed=r),this.headersSent=!0,this.outputSize+=n.byteLength,!0}write(e,t,r){this._appendChunk(e,typeof t=="string"?t:void 0,!0);let n=typeof t=="function"?t:r;return typeof n=="function"&&queueMicrotask(n),!0}end(e,t,r){let n,i;if(typeof e=="function"?i=e:(n=e,i=typeof t=="function"?t:r),this._streamSocket&&this._chunks.length===0&&!this.writableFinished&&!this._streamedDirectly){let s=typeof t=="string"?t:void 0;return this._streamEndBody(n,s),typeof i=="function"&&queueMicrotask(i),this}return n!=null&&(typeof n=="string"&&typeof t=="string"?this._appendChunk(n,t,!1):this._appendChunk(n,void 0,!1)),this._finalize(),typeof i=="function"&&queueMicrotask(i),this}_streamEndBody(e,t){let r=typeof e=="string",n=256*1024,i=0;if(e!=null)if(r)for(let a=0;a0&&this._streamSocket.write(o.payload),e!=null&&i>0)if(r)for(let a=0;athis._rawHeaderNames.get(e)||e)}getHeaders(){let e=Object.create(null);for(let[t,r]of this._headers)e[t]=wG(r);return e}assignSocket(){}detachSocket(){}writeContinue(){this.writeHead(100)}writeProcessing(){this.writeHead(102)}addTrailers(e){if(Array.isArray(e)){for(let t=0;t{let n=Gi(t).toLowerCase();Yi(n,r),this._trailers.set(n,String(r)),this._rawTrailerNames.has(n)||this._rawTrailerNames.set(n,t)})}cork(){this.socket.cork()}uncork(){this.socket.uncork()}setTimeout(e){return this}get writableCorked(){return Number(this.socket.writableCorked||0)}flushHeaders(){this.headersSent=!0}destroy(e){this._connectionReset=!0,e&&this._emit("error",e),this._finalize()}async waitForClose(){await this._closedPromise}serialize(){let e=this._chunks.length>0?Buffer.concat(this._chunks):Buffer.alloc(0),t=Array.from(this._headers.entries()).flatMap(([s,o])=>{let a=Cl(o);return Array.isArray(a)?s==="set-cookie"?a.map(A=>[s,A]):[[s,a.join(", ")]]:[[s,a]]}),r=Array.from(this._headers.entries()).flatMap(([s,o])=>{let a=this._rawHeaderNames.get(s)||s,A=Cl(o);return Array.isArray(A)?s==="set-cookie"?A.flatMap(f=>[a,f]):[a,A.join(", ")]:[a,A]}),n=Array.from(this._trailers.entries()).flatMap(([s,o])=>{let a=Cl(o);return Array.isArray(a)?a.map(A=>[s,A]):[[s,a]]}),i=Array.from(this._trailers.entries()).flatMap(([s,o])=>{let a=this._rawTrailerNames.get(s)||s,A=Cl(o);return Array.isArray(A)?A.flatMap(f=>[a,f]):[a,A]});return{status:this.statusCode,headers:t,rawHeaders:r,informational:this._informational.length>0?[...this._informational]:void 0,body:e.toString("base64"),bodyEncoding:"base64",trailers:n.length>0?n:void 0,rawTrailers:i.length>0?i:void 0,connectionEnded:this._connectionEnded,connectionReset:this._connectionReset,streamed:this._streamed}}_writeRaw(e,t){return this._pendingRawInfoBuffer+=String(e),this._flushPendingRawInformational(),typeof t=="function"&&queueMicrotask(t),!0}_finalize(){this.writableFinished||(this.writableFinished=!0,this.writable=!1,this._writableState.ended=!0,this._writableState.finished=!0,this._emit("finish"),this._emit("close"),this._resolveClosed?.(),this._resolveClosed=null)}_flushPendingRawInformational(){let e=this._pendingRawInfoBuffer.indexOf(`\r -\r -`);for(;e!==-1;){let t=this._pendingRawInfoBuffer.slice(0,e);this._pendingRawInfoBuffer=this._pendingRawInfoBuffer.slice(e+4);let[r,...n]=t.split(`\r -`),i=/^HTTP\/1\.[01]\s+(\d{3})(?:\s+(.*))?$/.exec(r);if(!i){e=this._pendingRawInfoBuffer.indexOf(`\r -\r -`);continue}let s=Number(i[1]);if(s>=100&&s<200&&s!==101){let o=[],a=[];for(let A of n){let f=A.indexOf(":");if(f===-1)continue;let l=A.slice(0,f).trim(),p=A.slice(f+1).trim();o.push([l.toLowerCase(),p]),a.push(l,p)}this._informational.push({status:s,statusText:i[2]||zg[s]||void 0,headers:o,rawHeaders:a})}e=this._pendingRawInfoBuffer.indexOf(`\r -\r -`)}}},dR=class{constructor(e,t=null){y(this,"listening",!1);y(this,"_listeners",{});y(this,"_serverId");y(this,"_netServer",null);y(this,"_listenPromise",null);y(this,"_address",null);y(this,"_handleId",null);y(this,"_hostCloseWaitStarted",!1);y(this,"_activeRequestDispatches",0);y(this,"_closePending",!1);y(this,"_closeRunning",!1);y(this,"_closeCallbacks",[]);y(this,"_tlsOptions",null);y(this,"_requestListener");y(this,"keepAliveTimeout",5e3);y(this,"requestTimeout",3e5);y(this,"headersTimeout",6e4);y(this,"timeout",0);y(this,"maxRequestsPerSocket",0);this._serverId=WSe++,this._requestListener=e??(()=>{}),this._tlsOptions=t,jg.set(this._serverId,this)}get _bridgeServerId(){return this._serverId}_emit(e,...t){let r=this._listeners[e];!r||r.length===0||r.slice().forEach(n=>n.call(this,...t))}_finishStart(e){let t=JSON.parse(e);this._address=t.address,this.listening=!0,this._handleId=`http-server:${this._serverId}`,nr("server listening",this._serverId,this._address),typeof _registerHandle=="function"&&_registerHandle(this._handleId,"http server"),this._startHostCloseWait()}_completeClose(){this.listening=!1,this._address=null,jg.delete(this._serverId),this._handleId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleId),this._handleId=null}_beginRequestDispatch(){this._activeRequestDispatches+=1}_endRequestDispatch(){this._activeRequestDispatches=Math.max(0,this._activeRequestDispatches-1),this._closePending&&this._activeRequestDispatches===0&&(this._closePending=!1,queueMicrotask(()=>{this._startClose()}))}_startHostCloseWait(){this._hostCloseWaitStarted=!0}async _start(e,t){if(typeof Jg>"u")throw new Error("http.createServer requires kernel-backed network bridge support");nr("server listen start",this._serverId,e,t);let r=new Jg({allowHalfOpen:!0});this._netServer=r,r.on("connection",n=>{if(this._tlsOptions){let i=new uR(n,{...this._tlsOptions,isServer:!0});i.server=this,i.once("secure",()=>{this._emit("secureConnection",i),this._emit("connection",i),vG(this,i)}),i.on("error",s=>{this._emit("tlsClientError",s,i)});return}this._emit("connection",n),vG(this,n)}),r.on("error",n=>{this._emit("error",n)}),await new Promise((n,i)=>{let s=!1,o=()=>{r.removeListener?.("listening",a),r.removeListener?.("error",A)},a=()=>{s||(s=!0,o(),n())},A=f=>{s||(s=!0,o(),i(f instanceof Error?f:new Error(String(f))))};r.once("listening",a),r.once("error",A),r.listen(e??0,t)}),this._address=r.address(),this.listening=!0,this._startHostCloseWait(),nr("server listening",this._serverId,this._address)}listen(e,t,r){let n=typeof e=="number"?e:void 0,i=typeof t=="string"?t:void 0,s=typeof r=="function"?r:typeof t=="function"?t:typeof e=="function"?e:void 0;return this._listenPromise||(this._listenPromise=this._start(n,i).then(()=>{this._emit("listening"),s?.call(this)}).catch(o=>{this._emit("error",o)})),this}close(e){return nr("server close requested",this._serverId,this.listening),e&&this._closeCallbacks.push(e),this._activeRequestDispatches>0?(this._closePending=!0,this):(queueMicrotask(()=>{this._startClose()}),this)}_startClose(){if(this._closeRunning)return;this._closeRunning=!0,(async()=>{try{this._listenPromise&&await this._listenPromise;let t=this._netServer;this.listening&&t&&(nr("server close net server",this._serverId),await new Promise((n,i)=>{t.close(s=>{s?i(s):n()})})),this._netServer=null,this._completeClose(),nr("server close complete",this._serverId),this._closeCallbacks.splice(0).forEach(n=>n()),this._emit("close")}catch(t){let r=t instanceof Error?t:new Error(String(t));nr("server close error",this._serverId,r.message),this._closeCallbacks.splice(0).forEach(i=>i(r)),this._emit("error",r)}finally{this._closeRunning=!1}})()}address(){return this._address}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}once(e,t){let r=(...n)=>{this.off(e,r),t.call(this,...n)};return this.on(e,r)}off(e,t){let r=this._listeners[e];if(!r)return this;let n=r.indexOf(t);return n!==-1&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e?delete this._listeners[e]:this._listeners={},this}listenerCount(e){return this._listeners[e]?.length||0}setTimeout(e,t){return typeof e=="number"&&(this.timeout=e),this}ref(){return this}unref(){return this}};function kW(e){return new dR(e)}kW.prototype=dR.prototype;async function A_e(e,t){let r=jg.get(e);if(!r)throw new Error(`Unknown HTTP server: ${e}`);let n=r._requestListener;r._beginRequestDispatch();let i=JSON.parse(t),s=new Nu(i),o=new c0;s.socket=o.socket,s.connection=o.socket;let a=[],A=[],f=new Map,l=0,p=0;try{try{let B=globalThis.setImmediate,S=globalThis.setTimeout,_=globalThis.clearTimeout;typeof B=="function"&&(globalThis.setImmediate=((N,...P)=>{let U=new Promise(G=>{queueMicrotask(()=>{try{N(...P)}finally{G()}})});return a.push(U),0})),typeof S=="function"&&(globalThis.setTimeout=((N,P,...U)=>{if(typeof N!="function")return S(N,P,...U);let G=typeof P=="number"&&Number.isFinite(P)?Math.max(0,P):0;if(G>1e3)return S(N,G,...U);let Y,Z=new Promise(j=>{Y=j}),ee;return ee=S(()=>{f.delete(ee);try{N(...U)}finally{Y()}},G),f.set(ee,Y),A.push(Z),ee})),typeof _=="function"&&(globalThis.clearTimeout=(N=>{if(N!=null){let P=f.get(N);P&&(f.delete(N),P())}return _(N)}));try{let N=n(s,o);for(s.rawBody&&s.rawBody.length>0&&s.emit("data",s.rawBody),s.emit("end"),await Promise.resolve(N);l"u")return;e2.delete(t);let n=_s.get(e);if(!n){_networkHttp2ServerRespondRaw.applySync(void 0,[e,t,JSON.stringify({status:500,headers:[["content-type","text/plain"]],body:"Unknown HTTP/2 server",bodyEncoding:"utf8"})]);return}let i=JSON.parse(r.requestJson),s=new Nu(i),o=new c0;s.socket=o.socket,s.connection=o.socket;try{n.emit("request",s,o),s.rawBody&&s.rawBody.length>0&&s.emit("data",s.rawBody),s.emit("end"),o.writableFinished||o.end(),await o.waitForClose(),_networkHttp2ServerRespondRaw.applySync(void 0,[e,t,JSON.stringify(o.serialize())])}catch(a){let A=a instanceof Error?a.message:String(a);_networkHttp2ServerRespondRaw.applySync(void 0,[e,t,JSON.stringify({status:500,headers:[["content-type","text/plain"]],body:`Error: ${A}`,bodyEncoding:"utf8"})])}}async function u_e(e,t){let r=typeof e=="number"?jg.get(e):e;if(!r)throw new Error(`Unknown HTTP server: ${typeof e=="number"?e:""}`);let n=typeof t=="string"?JSON.parse(t):t,i=new Nu(n),s=new c0;i.socket=s.socket,i.connection=s.socket;let o=[],a=[],A=new Map,f=0,l=0;r._beginRequestDispatch();try{try{let B=globalThis.setImmediate,S=globalThis.setTimeout,_=globalThis.clearTimeout;typeof B=="function"&&(globalThis.setImmediate=((N,...P)=>{let U=new Promise(G=>{queueMicrotask(()=>{try{N(...P)}finally{G()}})});return o.push(U),0})),typeof S=="function"&&(globalThis.setTimeout=((N,P,...U)=>{if(typeof N!="function")return S(N,P,...U);let G=typeof P=="number"&&Number.isFinite(P)?Math.max(0,P):0;if(G>1e3)return S(N,G,...U);let Y,Z=new Promise(j=>{Y=j}),ee;return ee=S(()=>{A.delete(ee);try{N(...U)}finally{Y()}},G),A.set(ee,Y),a.push(Z),ee})),typeof _=="function"&&(globalThis.clearTimeout=(N=>{if(N!=null){let P=A.get(N);P&&(A.delete(N),P())}return _(N)}));try{let N=r._requestListener(i,s);for(i.rawBody&&i.rawBody.length>0&&i.emit("data",i.rawBody),i.emit("end"),await Promise.resolve(N);f{p||(p=!0,i._abort())}}}finally{r._endRequestDispatch()}}async function c_e(e,t,r){let n=typeof t=="string"?JSON.parse(t):t,i=new Nu(n),s=new c0;i.socket=s.socket,i.connection=s.socket,r&&(s._streamSocket=r,s._streamRequest=n),e._beginRequestDispatch();try{try{let A=e._requestListener(i,s);i.rawBody&&i.rawBody.length>0&&i.emit("data",i.rawBody),i.emit("end"),await Promise.resolve(A)}catch(A){s.statusCode=500;try{s.end(A instanceof Error?`Error: ${A.message}`:"Error")}catch{s.writableFinished||s.end()}}s.writableFinished||s.end(),await s.waitForClose();let o=!1,a=()=>{o||(o=!0,i._abort())};return s._streamedDirectly?{streamedDirectly:!0,closeConnection:s._streamCloseConnection,abortRequest:a}:{responseJson:JSON.stringify(s.serialize()),abortRequest:a}}finally{e._endRequestDispatch()}}function vG(e,t){let r=Buffer.alloc(0),n=!1,i=!1,s=!1,o=!1,a=()=>{o||(o=!0,t.off?.("data",l),t.removeListener?.("data",l),t.off?.("end",p),t.removeListener?.("end",p),t.off?.("close",B),t.removeListener?.("close",B),t.off?.("error",S),t.removeListener?.("error",S))},A=()=>{if(n){i=!0;return}n=!0,_().finally(()=>{n=!1,i&&!o?(i=!1,A()):i=!1})},f=()=>{a(),!t.destroyed&&!t._writableEnded&&t.end()},l=N=>{let P=Buffer.isBuffer(N)?N:Buffer.from(N);r=r.length===0?P:Buffer.concat([r,P]),A()},p=()=>{if(s=!0,r.length===0){a();return}A()},B=()=>{a()},S=()=>{a()};async function _(){let N=!1;for(;!o&&!t.destroyed;){let P=FW(r,e);if(P.kind==="incomplete"){s&&r.length>0&&(t.write(a2()),f());return}if(P.kind==="bad-request"){t.write(a2()),f(),r=Buffer.alloc(0);return}if(r=r.subarray(P.bytesConsumed),P.upgradeHead){a();let Y=new Nu(P.request);Y.socket=t,Y.connection=t,e._emit("upgrade",Y,t,P.upgradeHead);return}let U=await c_e(e,P.request,t);if(o||t.destroyed)return;let G;if(U.streamedDirectly)G=U.closeConnection;else{let Y=JSON.parse(U.responseJson),Z=hR(Y,P.request,!0);!N&&Z.payload.length>0&&t.write(Z.payload),G=Z.closeConnection}if(G&&(N=!0,r.length===0)){f();return}}}t.on("data",l),t.once("end",p),t.once("close",B),t.once("error",S)}function xW(e,t,r,n,i){let s=jg.get(t);if(!s)throw new Error(`Unknown HTTP server for ${e}: ${t}`);let o=JSON.parse(r),a=new Nu(o),A=typeof Buffer<"u"?Buffer.from(n,"base64"):new Uint8Array(0),f=a.headers.host,l=new l_e(i,{host:(Array.isArray(f)?f[0]:f)?.split(":")[0]||"127.0.0.1"});Kg.set(i,l),s._emit(e,a,l,A)}var Kg=new Map,l_e=class{constructor(e,t){y(this,"remoteAddress");y(this,"remotePort");y(this,"localAddress","127.0.0.1");y(this,"localPort",0);y(this,"connecting",!1);y(this,"destroyed",!1);y(this,"writable",!0);y(this,"readable",!0);y(this,"readyState","open");y(this,"bytesWritten",0);y(this,"_listeners",{});y(this,"_socketId");y(this,"_readableState",{endEmitted:!1,ended:!1});y(this,"_writableState",{finished:!1,errorEmitted:!1});this._socketId=e,this.remoteAddress=t?.host||"127.0.0.1",this.remotePort=t?.port||80}setTimeout(e,t){return this}setNoDelay(e){return this}setKeepAlive(e,t){return this}ref(){return this}unref(){return this}cork(){}uncork(){}pause(){return this}resume(){return this}address(){return{address:this.localAddress,family:"IPv4",port:this.localPort}}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}addListener(e,t){return this.on(e,t)}once(e,t){let r=(...n)=>{this.off(e,r),t(...n)};return this.on(e,r)}off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}return this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e?delete this._listeners[e]:this._listeners={},this}emit(e,...t){let r=this._listeners[e];return zl(this,r,t)}listenerCount(e){return this._listeners[e]?.length||0}write(e,t,r){if(this.destroyed)return!1;let n=typeof t=="function"?t:r;if(typeof _upgradeSocketWriteRaw<"u"){let i;typeof Buffer<"u"&&Buffer.isBuffer(e)?i=e.toString("base64"):typeof e=="string"?i=typeof Buffer<"u"?Buffer.from(e).toString("base64"):btoa(e):e instanceof Uint8Array?i=typeof Buffer<"u"?Buffer.from(e).toString("base64"):btoa(String.fromCharCode(...e)):i=typeof Buffer<"u"?Buffer.from(String(e)).toString("base64"):btoa(String(e)),this.bytesWritten+=i.length,_upgradeSocketWriteRaw.applySync(void 0,[this._socketId,i])}return n&&n(),!0}end(e){return e&&this.write(e),typeof _upgradeSocketEndRaw<"u"&&!this.destroyed&&_upgradeSocketEndRaw.applySync(void 0,[this._socketId]),this.writable=!1,this.emit("finish"),this}destroy(e){return this.destroyed?this:(this.destroyed=!0,this.writable=!1,this.readable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._writableState.finished=!0,typeof _upgradeSocketDestroyRaw<"u"&&_upgradeSocketDestroyRaw.applySync(void 0,[this._socketId]),Kg.delete(this._socketId),e&&this.emit("error",e),this.emit("close",!1),this)}_pushData(e){this.emit("data",e)}_pushEnd(){this.readable=!1,this._readableState.endEmitted=!0,this._readableState.ended=!0,this._writableState.finished=!0,this.emit("end"),this.emit("close",!1),Kg.delete(this._socketId)}};function h_e(e,t,r,n){xW("upgrade",e,t,r,n)}function d_e(e,t,r,n){xW("connect",e,t,r,n)}function g_e(e,t){let r=Kg.get(e);if(r){let n=typeof Buffer<"u"?Buffer.from(t,"base64"):new Uint8Array(0);r._pushData(n)}}function p_e(e){let t=Kg.get(e);t&&t._pushEnd()}function A2(){this.statusCode=200,this.statusMessage="OK",this.headersSent=!1,this.writable=!0,this.writableFinished=!1,this.outputSize=0,this._headers=new Map,this._trailers=new Map,this._rawHeaderNames=new Map,this._rawTrailerNames=new Map,this._informational=[],this._pendingRawInfoBuffer="",this._chunks=[],this._chunksBytes=0,this._listeners={},this._closedPromise=new Promise(t=>{this._resolveClosed=t}),this._connectionEnded=!1,this._connectionReset=!1,this._writableState={length:0,ended:!1,finished:!1,objectMode:!1,corked:0};let e={writable:!0,writableCorked:0,writableHighWaterMark:16*1024,on(){return e},once(){return e},removeListener(){return e},destroy(){},end(){},cork(){},uncork(){},write:(t,r,n)=>this.write(t,r,n)};this.socket=e,this.connection=e}A2.prototype=Object.create(c0.prototype,{constructor:{value:A2,writable:!0,configurable:!0}});function UW(e){let t=e==="https"?"https:":"http:",r=new NB({keepAlive:!1,createConnection(s,o){return eI({...s,protocol:t},o)}});function n(s){return s.protocol?s:{...s,protocol:t}}function i(s){return s.agent!==void 0?s:{...s,_agentOSDefaultAgent:r}}return{request(s,o,a){let A,f=typeof o=="function"?o:a;if(typeof s=="string"){let l=new URL(s);A={protocol:l.protocol,hostname:l.hostname,port:l.port,path:l.pathname+l.search,...typeof o=="object"&&o?o:{}}}else s instanceof URL?A={protocol:s.protocol,hostname:s.hostname,port:s.port,path:s.pathname+s.search,...typeof o=="object"&&o?o:{}}:A={...s,...typeof o=="object"&&o?o:{}};return new Ug(i(n(A)),f)},get(s,o,a){let A,f=typeof o=="function"?o:a;if(typeof s=="string"){let p=new URL(s);A={protocol:p.protocol,hostname:p.hostname,port:p.port,path:p.pathname+p.search,method:"GET",...typeof o=="object"&&o?o:{}}}else s instanceof URL?A={protocol:s.protocol,hostname:s.hostname,port:s.port,path:s.pathname+s.search,method:"GET",...typeof o=="object"&&o?o:{}}:A={...s,...typeof o=="object"&&o?o:{},method:"GET"};let l=new Ug(i(n(A)),f);return l.end(),l},createServer(s,o){let a=typeof s=="function"?s:o,A=typeof s=="function"?null:s;return new dR(a,e==="https"?A:null)},Agent:NB,globalAgent:r,Server:kW,ServerResponse:A2,IncomingMessage:hu,ClientRequest:Ug,validateHeaderName:Gi,validateHeaderValue:Yi,_checkIsHttpToken:RW,_checkInvalidHeaderChar:DW,maxHeaderSize:65535,METHODS:[...VSe],STATUS_CODES:zg}}var gR=UW("http");Ge("_httpModule",gR);Ge("_dnsModule",fR);function E_e(e,t){if(nr("http stream event",e,t),e==="http_request"&&!(!t||t.serverId===void 0||t.requestId===void 0||typeof t.request!="string")){if(typeof _networkHttpServerRespondRaw>"u"){nr("http stream missing respond bridge");return}A_e(t.serverId,t.request).then(r=>{nr("http stream response",t.serverId,t.requestId),_networkHttpServerRespondRaw.applySync(void 0,[t.serverId,t.requestId,r])}).catch(r=>{let n=r instanceof Error?r.message:String(r);nr("http stream error",t.serverId,t.requestId,n),_networkHttpServerRespondRaw.applySync(void 0,[t.serverId,t.requestId,JSON.stringify({status:500,headers:[["content-type","text/plain"]],body:`Error: ${n}`,bodyEncoding:"utf8"})])})}}Ge("_httpServerDispatch",E_e);Ge("_httpServerUpgradeDispatch",h_e);Ge("_httpServerConnectDispatch",d_e);Ge("_http2Dispatch",MSe);Ge("_upgradeSocketData",g_e);var pR=UW("https");Ge("_httpsModule",pR);var ql=50*1024*1024,RG=64*1024,y_e=2e3,m_e=0,f2=yu.default?.Headers??yu.default?.default??yu.default,B_e=mu.default?.Request??mu.default?.default??mu.default,I_e=Bu.default?.Response??Bu.default?.default??Bu.default;function tI(e){if(!e)return{};if(e instanceof PA||typeof f2=="function"&&e instanceof f2)return Object.fromEntries(e.entries());if(s2(e)){let t={};for(let r=0;rn.toLowerCase()==="accept-encoding")||(t["accept-encoding"]="gzip, deflate"),{...e||{},headers:t}}async function rI(e,t={}){if(typeof fG!="function")throw new Error("fetch requires undici to be configured");let r=e,n=t;e instanceof ER&&(r=e.url,n={method:e.method,headers:tI(e.headers),body:e.body,...t}),n=C_e(n),n=Q_e(n);let i=typeof r=="string"?r:r?.url?String(r.url):String(r),s=typeof _registerHandle=="function"?`fetch:${++m_e}`:null;s&&_registerHandle?.(s,`fetch ${i}`);let o=n.dispatcher==null&&typeof W1=="function"?W1():null;try{return await fG(r,o?{...n,dispatcher:o}:n)}finally{s&&_unregisterHandle?.(s)}}var PA=class LW{constructor(t){y(this,"_headers",{});t&&t!==null&&(t instanceof LW?this._headers={...t._headers}:Array.isArray(t)?t.forEach(([r,n])=>{this._headers[r.toLowerCase()]=n}):typeof t=="object"&&Object.entries(t).forEach(([r,n])=>{this._headers[r.toLowerCase()]=n}))}get(t){return this._headers[t.toLowerCase()]||null}set(t,r){this._headers[t.toLowerCase()]=r}has(t){return t.toLowerCase()in this._headers}delete(t){delete this._headers[t.toLowerCase()]}entries(){return Object.entries(this._headers)[Symbol.iterator]()}[Symbol.iterator](){return this.entries()}keys(){return Object.keys(this._headers)[Symbol.iterator]()}values(){return Object.values(this._headers)[Symbol.iterator]()}append(t,r){let n=t.toLowerCase();n in this._headers?this._headers[n]=this._headers[n]+", "+r:this._headers[n]=r}forEach(t){Object.entries(this._headers).forEach(([r,n])=>t(n,r,this))}},ER=class PW{constructor(t,r={}){y(this,"url");y(this,"method");y(this,"headers");y(this,"body");y(this,"mode");y(this,"credentials");y(this,"cache");y(this,"redirect");y(this,"referrer");y(this,"integrity");this.url=typeof t=="string"?t:t.url,this.method=r.method||(typeof t!="string"?t.method:void 0)||"GET",this.headers=b_e(r.headers||(typeof t!="string"?t.headers:void 0)),this.body=r.body||null,this.mode=r.mode||"cors",this.credentials=r.credentials||"same-origin",this.cache=r.cache||"default",this.redirect=r.redirect||"follow",this.referrer=r.referrer||"about:client",this.integrity=r.integrity||""}clone(){return new PW(this.url,this)}},OW=class uB{constructor(t,r={}){y(this,"_body");y(this,"status");y(this,"statusText");y(this,"headers");y(this,"ok");y(this,"type");y(this,"url");y(this,"redirected");this._body=t||null,this.status=r.status||200,this.statusText=r.statusText||"OK",this.headers=new PA(r.headers),this.ok=this.status>=200&&this.status<300,this.type="default",this.url="",this.redirected=!1}async text(){return String(this._body||"")}async json(){return JSON.parse(this._body||"{}")}get body(){let t=this._body;return t===null?null:{getReader(){let r=!1;return{async read(){return r?{done:!0}:(r=!0,{done:!1,value:new TextEncoder().encode(t)})}}}}}clone(){return new uB(this._body,{status:this.status,statusText:this.statusText})}static error(){return new uB(null,{status:0,statusText:""})}static redirect(t,r=302){return new uB(null,{status:r,headers:{Location:t}})}};Ge("_upgradeSocketEnd",p_e);Ge("fetch",rI);Ge("Headers",f2);Ge("Request",B_e);Ge("Response",I_e);var Fl=globalThis.Blob;typeof Fl>"u"&&(Fl=class{},Ge("Blob",Fl));var d1=globalThis.File;typeof d1>"u"&&(d1=class extends Fl{constructor(r=[],n="",i={}){super(r,i);y(this,"name");y(this,"lastModified");y(this,"webkitRelativePath");this.name=String(n),this.lastModified=typeof i.lastModified=="number"?i.lastModified:Date.now(),this.webkitRelativePath=""}},Ge("File",d1));if(typeof globalThis.FormData>"u"){class e{constructor(){y(this,"_entries",[])}append(r,n){this._entries.push([r,n])}get(r){let n=this._entries.find(([i])=>i===r);return n?n[1]:null}getAll(r){return this._entries.filter(([n])=>n===r).map(([,n])=>n)}has(r){return this._entries.some(([n])=>n===r)}delete(r){this._entries=this._entries.filter(([n])=>n!==r)}entries(){return this._entries[Symbol.iterator]()}[Symbol.iterator](){return this.entries()}}Ge("FormData",e)}var w_e="dgram-socket:",Xg=new Map,FB=new Map;function S_e(e){e?._socketId&&FB.set(e._socketId,e);let t=e?._localPort;if(typeof t!="number")return;let r=Xg.get(t);r||(r=new Set,Xg.set(t,r)),r.add(e)}function __e(e){e?._socketId&&FB.get(e._socketId)===e&&FB.delete(e._socketId);let t=e?._localPort;if(typeof t!="number")return;let r=Xg.get(t);r&&(r.delete(e),r.size===0&&Xg.delete(t))}function v_e(e){return e==="127.0.0.1"||e==="::1"||e==="localhost"}function HW(e){if(X("dgramWakeAttempts"),!e||e._closed||!e._bound){X("dgramWakeInvalidTargets");return}if(e._receiveLoopRunning){X("dgramWakeAlreadyRunning"),e._pendingReceiveWake=!0;return}if(!e._receivePollTimer){X("dgramWakeNoTimer"),e._pendingReceiveWake=!0,queueMicrotask(()=>{!e._closed&&e._bound&&e._pendingReceiveWake&&!e._receiveLoopRunning&&(e._pendingReceiveWake=!1,e._nextReceivePumpOrigin="eventWake",e._pumpMessages())});return}clearTimeout(e._receivePollTimer),e._receivePollTimer=null,X("dgramEventWakeups"),queueMicrotask(()=>{!e._closed&&e._bound&&(e._nextReceivePumpOrigin="eventWake",e._pumpMessages())})}function qW(){return lr("Bad socket type specified. Valid types are: udp4, udp6","ERR_SOCKET_BAD_TYPE")}function R_e(){let e=new Error("Socket is already bound");return e.code="ERR_SOCKET_ALREADY_BOUND",e}function DG(){return new Error("getsockname EBADF")}function In(e,t,r){return lr(`The "${e}" argument must be of type ${t}. Received ${Yn(r)}`,"ERR_INVALID_ARG_TYPE")}function TG(e){return lr(`The "${e}" argument must be specified`,"ERR_MISSING_ARGS")}function bg(){return MB("Not running","ERR_SOCKET_DGRAM_NOT_RUNNING")}function D_e(e){switch(e){case"EBADF":return-9;case"EINVAL":return-22;case"EADDRNOTAVAIL":return-99;case"ENOPROTOOPT":return-92}}function Ca(e,t){let r=new Error(`${e} ${t}`);return r.code=t,r.errno=D_e(t),r.syscall=e,r}function T_e(e){return lr(`The "ttl" argument must be of type number. Received ${Yn(e)}`,"ERR_INVALID_ARG_TYPE")}function N_e(){return lr("Buffer size must be a positive integer","ERR_SOCKET_BAD_BUFFER_SIZE")}function g1(e,t){let r=`uv_${e}_buffer_size`,n={errno:t==="EBADF"?-9:-22,code:t,message:t==="EBADF"?"bad file descriptor":"invalid argument",syscall:r},i=new Error(`Could not get or set buffer size: ${r} returned ${t} (${n.message})`);i.name="SystemError [ERR_SOCKET_BUFFER_SIZE]",i.code="ERR_SOCKET_BUFFER_SIZE",i.info=n;let s=n.errno,o=r;return Object.defineProperty(i,"errno",{enumerable:!0,configurable:!0,get(){return s},set(a){s=a}}),Object.defineProperty(i,"syscall",{enumerable:!0,configurable:!0,get(){return o},set(a){o=a}}),i}function NG(e){return e<=0?e:process.platform==="linux"?e*2:e}function MG(e,t){if(typeof e!="number")throw T_e(e);if(!Number.isInteger(e)||e<=0||e>=256)throw Ca(t,"EINVAL");return e}function GW(e){if(!u0(e))return!1;let t=Number(e.split(".")[0]);return t>=224&&t<=239}function YW(e){return u0(e)&&!GW(e)&&e!=="255.255.255.255"}function WW(e){let t=e.indexOf("%"),r=t===-1?e:e.slice(0,t);return $B(e)&&r.toLowerCase().startsWith("ff")}function Jm(e,t,r){if(typeof r!="string")throw In(t==="addSourceSpecificMembership"||t==="dropSourceSpecificMembership"?"groupAddress":"multicastAddress","string",r);if(!(e==="udp6"?WW(r):GW(r)))throw Ca(t,"EINVAL");return r}function FG(e,t,r){if(typeof r!="string")throw In("sourceAddress","string",r);if(!(e==="udp6"?$B(r)&&!WW(r):YW(r)))throw Ca(t,"EINVAL");return r}function kG(e){if(e==="udp4"||e==="udp6")return e;throw qW()}function M_e(e){if(typeof e=="string")return{type:kG(e)};if(!e||typeof e!="object"||Array.isArray(e))throw qW();let t=e,r={type:kG(t.type)};if(t.recvBufferSize!==void 0){if(typeof t.recvBufferSize!="number")throw i2("options.recvBufferSize","number",t.recvBufferSize);r.recvBufferSize=t.recvBufferSize}if(t.sendBufferSize!==void 0){if(typeof t.sendBufferSize!="number")throw i2("options.sendBufferSize","number",t.sendBufferSize);r.sendBufferSize=t.sendBufferSize}return r}function u2(e,t,r){if(e==null||e==="")return r;if(typeof e!="string")throw In("address","string",e);return e==="localhost"?t==="udp6"?"::1":"127.0.0.1":e}function c2(e){if(typeof e!="number")throw In("port","number",e);if(!J1(e))throw V1(e);return e}function l2(e){if(typeof e=="string"||Buffer.isBuffer(e))return Buffer.from(e);if(ArrayBuffer.isView(e))return Buffer.from(e.buffer,e.byteOffset,e.byteLength);throw In("msg","string or Buffer or Uint8Array or DataView",e)}function F_e(e){return Array.isArray(e)?Buffer.concat(e.map(t=>l2(t))):l2(e)}function Cg(e){if(typeof e!="string")return e;try{return JSON.parse(e)}catch{return e}}function k_e(e){if(Buffer.isBuffer(e)||e instanceof Uint8Array)return Buffer.from(e);if(typeof e=="string")return Buffer.from(e,"base64");if(e&&typeof e=="object"){if(e.__type==="Buffer"&&typeof e.data=="string")return Buffer.from(e.data,"base64");if(e.__agentOSType==="bytes"&&typeof e.base64=="string")return Buffer.from(e.base64,"base64")}return Buffer.alloc(0)}function x_e(e,t){let r,n,i;if(typeof e[0]=="function")i=e[0];else if(e[0]&&typeof e[0]=="object"&&!Array.isArray(e[0])){let s=e[0];r=s.port,n=s.address,i=e[1]}else r=e[0],typeof e[1]=="function"?i=e[1]:(n=e[1],i=e[2]);if(i!==void 0&&typeof i!="function")throw Pl("callback",i);return{port:r===void 0?0:c2(r),address:u2(n,t,t==="udp6"?"::":"0.0.0.0"),callback:i}}function U_e(e,t){if(e.length===0)throw In("msg","string or Buffer or Uint8Array or DataView",void 0);let r=e[0];if(typeof e[1]=="number"&&typeof e[2]=="number"&&e.length>=4){let s=l2(r),o=e[1],a=e[2],A=typeof e[4]=="function"?e[4]:e[5];if(A!==void 0&&typeof A!="function")throw Pl("callback",A);return{data:Buffer.from(s.subarray(o,o+a)),port:c2(e[3]),address:u2(typeof e[4]=="function"?void 0:e[4],t,t==="udp6"?"::1":"127.0.0.1"),callback:A}}let i=typeof e[2]=="function"?e[2]:e[3];if(i!==void 0&&typeof i!="function")throw Pl("callback",i);return{data:F_e(r),port:c2(e[1]),address:u2(typeof e[2]=="function"?void 0:e[2],t,t==="udp6"?"::1":"127.0.0.1"),callback:i}}var xG=class{constructor(e,t){y(this,"_type");y(this,"_socketId");y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_bindPromise",null);y(this,"_receiveLoopRunning",!1);y(this,"_receivePollTimer",null);y(this,"_pendingReceiveWake",!1);y(this,"_nextReceivePumpOrigin",null);y(this,"_refed",!0);y(this,"_closed",!1);y(this,"_bound",!1);y(this,"_handleRefId",null);y(this,"_localAddress");y(this,"_localPort");y(this,"_localFamily");y(this,"_recvBufferSize");y(this,"_sendBufferSize");y(this,"_memberships",new Set);y(this,"_multicastInterface");y(this,"_broadcast",!1);y(this,"_multicastLoopback",1);y(this,"_multicastTtl",1);y(this,"_ttl",64);if(typeof _dgramSocketCreateRaw>"u")throw new Error("dgram.createSocket is not supported in sandbox");let r=M_e(e);this._type=r.type;let n=Cg(_dgramSocketCreateRaw.applySync(void 0,[{type:this._type}]));this._socketId=String(n?.socketId??n),t&&this.on("message",t),r.recvBufferSize!==void 0&&this._setBufferSize("recv",r.recvBufferSize,!1),r.sendBufferSize!==void 0&&this._setBufferSize("send",r.sendBufferSize,!1)}bind(...e){let{port:t,address:r,callback:n}=x_e(e,this._type);return this._bindInternal(t,r,n),this}send(...e){let{data:t,port:r,address:n,callback:i}=U_e(e,this._type);this._sendInternal(t,r,n,i)}sendto(...e){this.send(...e)}address(){if(typeof _dgramSocketAddressRaw>"u")throw DG();try{return Cg(_dgramSocketAddressRaw.applySync(void 0,[this._socketId]))}catch{throw DG()}}close(e){if(e!==void 0&&typeof e!="function")throw Pl("callback",e);if(e&&this.once("close",e),this._closed)return this;if(this._closed=!0,__e(this),this._bound=!1,this._clearReceivePollTimer(),this._syncHandleRef(),typeof _dgramSocketCloseRaw>"u")return queueMicrotask(()=>{this._emit("close")}),this;try{_dgramSocketCloseRaw.applySyncPromise(void 0,[this._socketId])}finally{queueMicrotask(()=>{this._emit("close")})}return this}ref(){return this._refed=!0,this._syncHandleRef(),this._receivePollTimer&&typeof this._receivePollTimer.ref=="function"&&this._receivePollTimer.ref(),this._bound&&!this._closed&&!this._receiveLoopRunning&&this._pumpMessages(),this}unref(){return this._refed=!1,this._syncHandleRef(),this._receivePollTimer&&typeof this._receivePollTimer.unref=="function"&&this._receivePollTimer.unref(),this}setRecvBufferSize(e){this._setBufferSize("recv",e)}setSendBufferSize(e){this._setBufferSize("send",e)}getRecvBufferSize(){return this._getBufferSize("recv")}getSendBufferSize(){return this._getBufferSize("send")}setBroadcast(e){this._ensureBoundForSocketOption("setBroadcast"),this._broadcast=!!e}setTTL(e){return this._ensureBoundForSocketOption("setTTL"),this._ttl=MG(e,"setTTL"),this._ttl}setMulticastTTL(e){return this._ensureBoundForSocketOption("setMulticastTTL"),this._multicastTtl=MG(e,"setMulticastTTL"),this._multicastTtl}setMulticastLoopback(e){return this._ensureBoundForSocketOption("setMulticastLoopback"),this._multicastLoopback=Number(e),this._multicastLoopback}addMembership(e,t){if(e===void 0)throw TG("multicastAddress");if(this._closed)throw bg();let r=Jm(this._type,"addMembership",e);if(t!==void 0&&typeof t!="string")throw In("multicastInterface","string",t);this._memberships.add(`${r}|${t??""}`)}dropMembership(e,t){if(e===void 0)throw TG("multicastAddress");if(this._closed)throw bg();let r=Jm(this._type,"dropMembership",e);if(t!==void 0&&typeof t!="string")throw In("multicastInterface","string",t);let n=`${r}|${t??""}`;if(!this._memberships.has(n))throw Ca("dropMembership","EADDRNOTAVAIL");this._memberships.delete(n)}addSourceSpecificMembership(e,t,r){if(this._closed)throw bg();if(typeof e!="string")throw In("sourceAddress","string",e);if(typeof t!="string")throw In("groupAddress","string",t);let n=FG(this._type,"addSourceSpecificMembership",e),i=Jm(this._type,"addSourceSpecificMembership",t);if(r!==void 0&&typeof r!="string")throw In("multicastInterface","string",r);this._memberships.add(`${n}>${i}|${r??""}`)}dropSourceSpecificMembership(e,t,r){if(this._closed)throw bg();if(typeof e!="string")throw In("sourceAddress","string",e);if(typeof t!="string")throw In("groupAddress","string",t);let n=FG(this._type,"dropSourceSpecificMembership",e),i=Jm(this._type,"dropSourceSpecificMembership",t);if(r!==void 0&&typeof r!="string")throw In("multicastInterface","string",r);let s=`${n}>${i}|${r??""}`;if(!this._memberships.has(s))throw Ca("dropSourceSpecificMembership","EADDRNOTAVAIL");this._memberships.delete(s)}setMulticastInterface(e){if(typeof e!="string")throw In("interfaceAddress","string",e);if(this._closed)throw bg();if(this._ensureBoundForSocketOption("setMulticastInterface"),this._type==="udp4"){if(e==="0.0.0.0"){this._multicastInterface=e;return}if(!u0(e))throw Ca("setMulticastInterface","ENOPROTOOPT");if(!YW(e))throw Ca("setMulticastInterface","EADDRNOTAVAIL");this._multicastInterface=e;return}if(e===""||e==="undefined"||!$B(e))throw Ca("setMulticastInterface","EINVAL");this._multicastInterface=e}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}addListener(e,t){return this.on(e,t)}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this}removeListener(e,t){let r=this._listeners[e];if(r){let i=r.indexOf(t);i>=0&&r.splice(i,1)}let n=this._onceListeners[e];if(n){let i=n.indexOf(t);i>=0&&n.splice(i,1)}return this}off(e,t){return this.removeListener(e,t)}emit(e,...t){return this._emit(e,...t)}async _bindInternal(e,t,r){if(!this._closed){if(this._bound||this._bindPromise)throw R_e();if(typeof _dgramSocketBindRaw>"u")throw new Error("dgram.bind is not supported in sandbox");return this._bindPromise=(async()=>{try{let n=Cg(_dgramSocketBindRaw.applySyncPromise(void 0,[this._socketId,{port:e,address:t}]));this._applyBoundAddress(n),this._bound=!0,S_e(this),this._applyInitialBufferSizes(),this._syncHandleRef(),queueMicrotask(()=>{this._closed||(this._emit("listening"),r?.call(this),this._nextReceivePumpOrigin="bind",this._pumpMessages())})}catch(n){throw queueMicrotask(()=>{this._emit("error",n)}),n}finally{this._bindPromise=null}})(),this._bindPromise}}async _ensureBound(){if(!this._bound){if(this._bindPromise){await this._bindPromise;return}await this._bindInternal(0,this._type==="udp6"?"::":"0.0.0.0")}}async _sendInternal(e,t,r,n){try{if(await this._ensureBound(),this._closed||typeof _dgramSocketSendRaw>"u")return;let i=Cg(_dgramSocketSendRaw.applySyncPromise(void 0,[this._socketId,e,{port:t,address:r}]));if(this._applyBoundAddress(i),v_e(r)){let s=Xg.get(t);if(s){X("dgramWakeLoopbackHits");for(let o of s)HW(o)}else X("dgramWakeLoopbackMisses")}n&&queueMicrotask(()=>{n(null,typeof i?.bytes=="number"?i.bytes:e.length)})}catch(i){if(n){queueMicrotask(()=>{n(i)});return}queueMicrotask(()=>{this._emit("error",i)})}}async _pumpMessages(){if(this._receiveLoopRunning||this._closed||!this._bound||typeof _dgramSocketRecvRaw>"u")return;let e=this._nextReceivePumpOrigin;this._nextReceivePumpOrigin=null;let t=e==="timer"?vB:0;this._receiveLoopRunning=!0;try{for(;!this._closed&&this._bound;){let r=Cg(_dgramSocketRecvRaw.applySync(void 0,[this._socketId,t]));if(r===nR||!r){if(this._pendingReceiveWake){this._pendingReceiveWake=!1,this._nextReceivePumpOrigin="eventWake";continue}this._receivePollTimer=setTimeout(()=>{this._receivePollTimer=null,this._nextReceivePumpOrigin="timer",this._pumpMessages()},vB),!this._refed&&typeof this._receivePollTimer.unref=="function"&&this._receivePollTimer.unref();return}if(r.type==="message"){let n=k_e(r.data);this._emit("message",n,{address:r.remoteAddress,family:r.remoteFamily??socketFamilyForAddress(r.remoteAddress),port:r.remotePort,size:n.length});continue}if(r.type==="error"){let n=new Error(typeof r.message=="string"?r.message:"secure-exec dgram socket error");typeof r.code=="string"&&r.code.length>0&&(n.code=r.code),this._emit("error",n)}}}catch(r){this._emit("error",r)}finally{this._receiveLoopRunning=!1,this._pendingReceiveWake&&!this._closed&&this._bound&&(this._pendingReceiveWake=!1,this._nextReceivePumpOrigin="eventWake",queueMicrotask(()=>{!this._closed&&this._bound&&this._pumpMessages()}))}}_applyBoundAddress(e){if(!e||typeof e!="object")return;let t=typeof e.localPort=="number"?e.localPort:e.port;typeof t=="number"&&(this._localPort=t);let r=typeof e.localAddress=="string"?e.localAddress:e.address;typeof r=="string"&&(this._localAddress=r);let n=typeof e.localFamily=="string"?e.localFamily:e.family;typeof n=="string"&&(this._localFamily=n)}_clearReceivePollTimer(){this._receivePollTimer&&(clearTimeout(this._receivePollTimer),this._receivePollTimer=null)}_ensureBoundForSocketOption(e){if(!this._bound||this._closed)throw Ca(e,"EBADF")}_setBufferSize(e,t,r=!0){if(!Number.isInteger(t)||t<=0||!Number.isFinite(t))throw N_e();if(t>2147483647)throw g1(e,"EINVAL");if(r&&(!this._bound||this._closed))throw g1(e,"EBADF");if(typeof _dgramSocketSetBufferSizeRaw<"u"&&this._bound&&!this._closed&&_dgramSocketSetBufferSizeRaw.applySync(void 0,[this._socketId,e,t]),e==="recv"){this._recvBufferSize=t;return}this._sendBufferSize=t}_getBufferSize(e){if(!this._bound||this._closed)throw g1(e,"EBADF");let t=e==="recv"?this._recvBufferSize??0:this._sendBufferSize??0;if(typeof _dgramSocketGetBufferSizeRaw>"u")return NG(t);let r=_dgramSocketGetBufferSizeRaw.applySync(void 0,[this._socketId,e]);return NG(r>0?r:t)}_applyInitialBufferSizes(){this._recvBufferSize!==void 0&&this._setBufferSize("recv",this._recvBufferSize),this._sendBufferSize!==void 0&&this._setBufferSize("send",this._sendBufferSize)}_syncHandleRef(){if(!this._bound||this._closed||!this._refed){this._handleRefId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleRefId),this._handleRefId=null;return}let e=`${w_e}${this._socketId}`;this._handleRefId!==e&&(this._handleRefId&&typeof _unregisterHandle=="function"&&_unregisterHandle(this._handleRefId),this._handleRefId=e,typeof _registerHandle=="function"&&_registerHandle(this._handleRefId,"dgram socket"))}_emit(e,...t){let r=!1,n=this._listeners[e];if(n)for(let s of[...n])s(...t),r=!0;let i=this._onceListeners[e];if(i){this._onceListeners[e]=[];for(let s of[...i])s(...t),r=!0}return r}},VW={Socket:xG,createSocket(e,t){return new xG(e,t)}};Ge("_tlsModule",vW);Ge("_dgramSocketDispatch",e=>{let t=FB.get(e?.socketId);t&&HW(t)});function L_e(e){if(!e||typeof e!="object"||Array.isArray(e)||Buffer.isBuffer(e)||e instanceof Uint8Array)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function kB(e){return e==null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"?e??null:typeof e=="bigint"?{__agentosSqliteType:"bigint",value:e.toString()}:Buffer.isBuffer(e)||e instanceof Uint8Array?{__agentosSqliteType:"uint8array",value:Buffer.from(e).toString("base64")}:Array.isArray(e)?e.map(t=>kB(t)):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([t,r])=>[t,kB(r)])):null}function Lg(e){return e==null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"?e??null:Array.isArray(e)?e.map(t=>Lg(t)):e&&typeof e=="object"?e.__agentosSqliteType==="bigint"&&typeof e.value=="string"?BigInt(e.value):e.__agentosSqliteType==="uint8array"&&typeof e.value=="string"?Buffer.from(e.value,"base64"):Object.fromEntries(Object.entries(e).map(([t,r])=>[t,Lg(r)])):e}function cB(e){return!Array.isArray(e)||e.length===0?null:e.length===1&&L_e(e[0])?kB(e[0]):e.map(t=>kB(t))}function Zr(e,t,r){if(typeof e=="function")return Lg(e(...t));if(!e)throw new Error(`sqlite bridge is not available for ${r}`);if(typeof e.applySync=="function")return Lg(e.applySync(void 0,t));if(typeof e.applySyncPromise=="function")return Lg(e.applySyncPromise(void 0,t));throw new Error(`sqlite bridge is not available for ${r}`)}var P_e=Ce("_sqliteConstantsRaw"),O_e=Ce("_sqliteDatabaseOpenRaw"),H_e=Ce("_sqliteDatabaseCloseRaw"),q_e=Ce("_sqliteDatabaseExecRaw"),G_e=Ce("_sqliteDatabaseQueryRaw"),Y_e=Ce("_sqliteDatabasePrepareRaw"),W_e=Ce("_sqliteDatabaseLocationRaw"),V_e=Ce("_sqliteDatabaseCheckpointRaw"),J_e=Ce("_sqliteStatementRunRaw"),j_e=Ce("_sqliteStatementGetRaw"),z_e=Ce("_sqliteStatementAllRaw"),K_e=Ce("_sqliteStatementColumnsRaw"),X_e=Ce("_sqliteStatementSetReturnArraysRaw"),Z_e=Ce("_sqliteStatementSetReadBigIntsRaw"),$_e=Ce("_sqliteStatementSetAllowBareNamedParametersRaw"),eve=Ce("_sqliteStatementSetAllowUnknownNamedParametersRaw"),tve=Ce("_sqliteStatementFinalizeRaw"),xB=class{constructor(e,t){this._database=e,this._statementId=t,this._finalized=!1}_assertOpen(){if(this._database._assertOpen(),this._finalized)throw new Error("SQLite statement is already finalized")}run(...e){return this._assertOpen(),Zr(J_e,[this._statementId,cB(e)],"statement.run")}get(...e){return this._assertOpen(),Zr(j_e,[this._statementId,cB(e)],"statement.get")}all(...e){return this._assertOpen(),Zr(z_e,[this._statementId,cB(e)],"statement.all")}iterate(...e){return this.all(...e)[Symbol.iterator]()}columns(){return this._assertOpen(),Zr(K_e,[this._statementId],"statement.columns")}setReturnArrays(e){this._assertOpen(),Zr(X_e,[this._statementId,!!e],"statement.setReturnArrays")}setReadBigInts(e){this._assertOpen(),Zr(Z_e,[this._statementId,!!e],"statement.setReadBigInts")}setAllowBareNamedParameters(e){this._assertOpen(),Zr($_e,[this._statementId,!!e],"statement.setAllowBareNamedParameters")}setAllowUnknownNamedParameters(e){this._assertOpen(),Zr(eve,[this._statementId,!!e],"statement.setAllowUnknownNamedParameters")}finalize(){return this._finalized||(this._database._assertOpen(),Zr(tve,[this._statementId],"statement.finalize"),this._finalized=!0),null}},h2=class{constructor(e=":memory:",t=void 0){this._closed=!1,this._databaseId=Zr(O_e,[typeof e=="string"?e:":memory:",t??null],"database.open")}_assertOpen(){if(this._closed)throw new Error("SQLite database is already closed")}close(){return this._closed||(Zr(H_e,[this._databaseId],"database.close"),this._closed=!0),null}exec(e){return this._assertOpen(),Zr(q_e,[this._databaseId,String(e??"")],"database.exec")}query(e,t=null,r=null){this._assertOpen();let n=t===null?null:cB(Array.isArray(t)?t:[t]);return Zr(G_e,[this._databaseId,String(e??""),n,r??null],"database.query")}prepare(e){this._assertOpen();let t=Zr(Y_e,[this._databaseId,String(e??"")],"database.prepare");return new xB(this,t)}location(){return this._assertOpen(),Zr(W_e,[this._databaseId],"database.location")}checkpoint(){return this._assertOpen(),Zr(V_e,[this._databaseId],"database.checkpoint")}};h2.prototype[Symbol.dispose]=h2.prototype.close;xB.prototype[Symbol.dispose]=xB.prototype.finalize;var p1;function rve(){return p1===void 0&&(p1=Object.freeze(Zr(P_e,[],"constants")??{})),p1}var nve={DatabaseSync:h2,StatementSync:xB,get constants(){return rve()}};Ge("_dgramModule",VW);Ge("_sqliteModule",nve);var JW={};O2(JW,{ClientRequest:()=>Ug,Headers:()=>PA,IncomingMessage:()=>hu,Request:()=>ER,Response:()=>OW,default:()=>ive,dns:()=>fR,fetch:()=>rI,http:()=>gR,http2:()=>AR,https:()=>pR});var ive={fetch:rI,Headers:PA,Request:ER,Response:OW,dns:fR,http:gR,https:pR,http2:AR,IncomingMessage:hu,ClientRequest:Ug,net:lW,tls:vW,dgram:VW},qt,Qg,ya,No=Symbol.for("nodejs.util.inspect.custom"),ka=Symbol.toStringTag,yR="ERR_INVALID_THIS",sve="ERR_MISSING_ARGS",ove="ERR_INVALID_URL",ave="ERR_ARG_NOT_ITERABLE",Ave="ERR_INVALID_TUPLE",fve="URLSearchParams",UB=Symbol("secureExecLinkedURLSearchParams"),UG=Symbol.for("secureExec.blobUrlStore"),E1=Symbol.for("secureExec.blobUrlCounter"),uve=["append","delete","get","getAll","has"],cve=["append","set"],lve={"http:":0,"https:":2,"ws:":4,"wss:":5,"file:":6,"ftp:":8},jW=new WeakSet,d2=new WeakMap,zW=new WeakSet,y1=new WeakMap;function qA(e,t){let r=new TypeError(e);return r.code=t,r}function hve(){let e=new TypeError("Invalid URL");return e.code=ove,e}function jm(){return new TypeError("Receiver must be an instance of class URL")}function Qa(e){return qA(e,sve)}function dve(){return qA("Query pairs must be iterable",ave)}function m1(){return qA("Each query pair must be an iterable [name, value] tuple",Ave)}function gve(){return new TypeError("Cannot convert a Symbol value to a string")}function pve(e){if(typeof e=="symbol")throw gve();return String(e)}function Eve(e){let t="";for(let r=0;r=55296&&n<=56319){let i=r+1;if(i=56320&&s<=57343){t+=e[r]+e[i],r=i;continue}}t+="\uFFFD";continue}if(n>=56320&&n<=57343){t+="\uFFFD";continue}t+=e[r]}return t}function Kt(e){return Eve(pve(e))}function yn(e){if(!jW.has(e))throw qA('Value of "this" must be of type URLSearchParams',yR)}function lB(e){if(!zW.has(e))throw qA('Value of "this" must be of type URLSearchParamsIterator',yR)}function Hn(e){let t=d2.get(e);if(!t)throw qA('Value of "this" must be of type URLSearchParams',yR);return t.getImpl()}function yve(e){let t=0;for(let r of e)t++;return t}function LG(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}function PG(e){return e>=48&&e<=57?e-48:e>=65&&e<=70?e-55:e-87}function mve(e,t){if(t<=127){e.push(t);return}if(t<=2047){e.push(192|t>>6,128|t&63);return}if(t<=65535){e.push(224|t>>12,128|t>>6&63,128|t&63);return}e.push(240|t>>18,128|t>>12&63,128|t>>6&63,128|t&63)}function OG(e){let t=String(e).replace(/\+/g," "),r="";for(let n=0;n0){r+=new Ru().decode(Uint8Array.from(s)),n=o-1;continue}}let i=t.codePointAt(n);r+=String.fromCodePoint(i),i>65535&&(n+=1)}return r}function HG(e){let t=String(e),r=[];for(let i=0;i65535&&(i+=1)}let n="";for(let i of r){if(i===32){n+="+";continue}if(i>=48&&i<=57||i>=65&&i<=90||i>=97&&i<=122||i===42||i===45||i===46||i===95){n+=String.fromCharCode(i);continue}n+=`%${i.toString(16).toUpperCase().padStart(2,"0")}`}return n}function Bve(e,t){let r=Math.min(e.length,t.length);for(let n=0;nn!==r)}get(t){let r=String(t),n=this._pairs.find(([i])=>i===r);return n?n[1]:null}getAll(t){let r=String(t);return this._pairs.filter(([n])=>n===r).map(([,n])=>n)}has(t){let r=String(t);return this._pairs.some(([n])=>n===r)}set(t,r){let n=String(t),i=String(r),s=[],o=!1;for(let[a,A]of this._pairs){if(a!==n){s.push([a,A]);continue}o||(o=!0,s.push([n,i]))}o||s.push([n,i]),this._pairs=s}sort(){this._pairs=this._pairs.map((t,r)=>({pair:t,index:r})).sort((t,r)=>{let n=Bve(t.pair[0],r.pair[0]);return n!==0?n:t.index-r.index}).map(({pair:t})=>t)}entries(){return this._pairs[Symbol.iterator]()}keys(){return this._pairs.map(([t])=>t)[Symbol.iterator]()}values(){return this._pairs.map(([,t])=>t)[Symbol.iterator]()}[Symbol.iterator](){return this.entries()}toString(){return this._pairs.map(([t,r])=>`${HG(t)}=${HG(r)}`).join("&")}};function bve(e){return typeof e=="string"?new B1(e):e===void 0?new B1:new B1(e)}function KW(e,t,r){if(e.length===0)return r;let n=`{ ${e.join(", ")} }`,i=t?.breakLength??1/0;return n.length<=i?n:`{ -${e.join(`, - `)} }`}function Cve(e){let t=e.href,r=t.indexOf(":")+1,n=t.indexOf("@"),i=t.indexOf("/",r+2),s=t.indexOf("?"),o=t.indexOf("#"),a=e.username.length>0?t.indexOf(":",r+2):r+2,A=n===-1?r+2:n,f=i===-1?t.length:i-(e.port.length>0?e.port.length+1:0),l=e.port.length>0?Number(e.port):null;return{href:t,protocol_end:r,username_end:a,host_start:A,host_end:f,pathname_start:i===-1?t.length:i,search_start:s===-1?t.length:s,hash_start:o===-1?t.length:o,port:l,scheme_type:lve[e.protocol]??1,hasPort:e.port.length>0,hasSearch:e.search.length>0,hasHash:e.hash.length>0}}function Qve(e,t,r){let n=Cve(e),i=typeof t=="function"?o=>t(o,r):o=>JSON.stringify(o),s=n.port===null?"null":String(n.port);return["URLContext {",` href: ${i(n.href)},`,` protocol_end: ${n.protocol_end},`,` username_end: ${n.username_end},`,` host_start: ${n.host_start},`,` host_end: ${n.host_end},`,` pathname_start: ${n.pathname_start},`,` search_start: ${n.search_start},`,` hash_start: ${n.hash_start},`,` port: ${s},`,` scheme_type: ${n.scheme_type},`," [hasPort]: [Getter],"," [hasSearch]: [Getter],"," [hasHash]: [Getter]"," }"].join(` -`)}function qG(){let e=globalThis,t=e[UG];if(t instanceof Map)return t;let r=new Map;return e[UG]=r,r}function wve(){let e=globalThis,t=typeof e[E1]=="number"?e[E1]:1;return e[E1]=t+1,t}var kA=class XW{constructor(t){zW.add(this),y1.set(this,{values:t,index:0})}next(){lB(this);let t=y1.get(this);if(t.index>=t.values.length)return{value:void 0,done:!0};let r=t.values[t.index];return t.index+=1,{value:r,done:!1}}[No](t,r,n){if(lB(this),t<0)return"[Object]";let i=y1.get(this),s=typeof n=="function"?a=>n(a,r):a=>JSON.stringify(a),o=i.values.slice(i.index).map(a=>s(a));return`URLSearchParams Iterator ${KW(o,r,"{ }")}`}get[ka](){return this!==XW.prototype&&lB(this),"URLSearchParams Iterator"}};Object.defineProperties(kA.prototype,{next:{value:kA.prototype.next,writable:!0,configurable:!0,enumerable:!0},[Symbol.iterator]:{value:function(){return lB(this),this},writable:!0,configurable:!0,enumerable:!1},[No]:{value:kA.prototype[No],writable:!0,configurable:!0,enumerable:!1},[ka]:{get:Object.getOwnPropertyDescriptor(kA.prototype,ka)?.get,configurable:!0,enumerable:!1}});Object.defineProperty(Object.getOwnPropertyDescriptor(kA.prototype,Symbol.iterator)?.value,"name",{value:"entries",configurable:!0});var Hr=class ZW{constructor(t){jW.add(this);let r=Ive(t);if(r&&typeof r=="object"&&UB in r){d2.set(this,{getImpl:r[UB]});return}let n=bve(r);d2.set(this,{getImpl:()=>n})}append(t,r){if(yn(this),arguments.length<2)throw Qa('The "name" and "value" arguments must be specified');Hn(this).append(Kt(t),Kt(r))}delete(t){if(yn(this),arguments.length<1)throw Qa('The "name" argument must be specified');Hn(this).delete(Kt(t))}get(t){if(yn(this),arguments.length<1)throw Qa('The "name" argument must be specified');return Hn(this).get(Kt(t))}getAll(t){if(yn(this),arguments.length<1)throw Qa('The "name" argument must be specified');return Hn(this).getAll(Kt(t))}has(t){if(yn(this),arguments.length<1)throw Qa('The "name" argument must be specified');return Hn(this).has(Kt(t))}set(t,r){if(yn(this),arguments.length<2)throw Qa('The "name" and "value" arguments must be specified');Hn(this).set(Kt(t),Kt(r))}sort(){yn(this),Hn(this).sort()}entries(){return yn(this),new kA(Array.from(Hn(this)))}keys(){return yn(this),new kA(Array.from(Hn(this).keys()))}values(){return yn(this),new kA(Array.from(Hn(this).values()))}forEach(t,r){if(yn(this),typeof t!="function")throw qA('The "callback" argument must be of type function. Received '+(t===void 0?"undefined":typeof t),"ERR_INVALID_ARG_TYPE");for(let[n,i]of Hn(this))t.call(r,i,n,this)}toString(){return yn(this),Hn(this).toString()}get size(){return yn(this),yve(Hn(this))}[No](t,r,n){if(yn(this),t<0)return"[Object]";let i=typeof n=="function"?o=>n(o,r):o=>JSON.stringify(o),s=Array.from(Hn(this)).map(([o,a])=>`${i(o)} => ${i(a)}`);return`URLSearchParams ${KW(s,r,"{}")}`}get[ka](){return this!==ZW.prototype&&yn(this),fve}};for(let e of uve)Object.defineProperty(Hr.prototype,e,{value:Hr.prototype[e],writable:!0,configurable:!0,enumerable:!0});for(let e of cve)Object.defineProperty(Hr.prototype,e,{value:Hr.prototype[e],writable:!0,configurable:!0,enumerable:!0});for(let e of["sort","entries","forEach","keys","values","toString"])Object.defineProperty(Hr.prototype,e,{value:Hr.prototype[e],writable:!0,configurable:!0,enumerable:!0});Object.defineProperties(Hr.prototype,{size:{get:Object.getOwnPropertyDescriptor(Hr.prototype,"size")?.get,configurable:!0,enumerable:!0},[Symbol.iterator]:{value:Hr.prototype.entries,writable:!0,configurable:!0,enumerable:!1},[No]:{value:Hr.prototype[No],writable:!0,configurable:!0,enumerable:!1},[ka]:{get:Object.getOwnPropertyDescriptor(Hr.prototype,ka)?.get,configurable:!0,enumerable:!1}});function Sve(e){if(typeof e!="function"||e.__secureExecBootstrapStub===!0)return!1;try{return String(new e("./child.mjs","file:///root/base/entry.mjs").href)==="file:///root/base/child.mjs"}catch{return!1}}function _ve(e){return e.endsWith("/")?e:`${e}/`}function vve(e,t){let r=String(e??"");if(!r.startsWith("file:"))return{input:r,base:t};let n=/^file:(\.\.?(?:\/[^?#]*)?)([?#].*)?$/.exec(r);if(!n)return{input:r,base:t};let i=n[1],s=n[2]??"",o=typeof t>"u"?"file:///":String(t);try{let a=new globalThis.URL(o);if(a.protocol!=="file:")return{input:r,base:t};let A=a.pathname||"/";A.startsWith("/")||(A=`/${A}`);let f=A.endsWith("/")?A:qr.posix.dirname(A),l=qr.posix.resolve(f,i);return{input:`file://${i==="."||i===".."||i.endsWith("/")?_ve(l):l}${s}`,base:void 0}}catch{return{input:r,base:t}}}var GG=typeof wu?.URL=="function"?wu.URL:typeof wu?.default?.URL=="function"?wu.default.URL:globalThis.URL,YG=Sve(GG)?GG:class $W{constructor(t,r){let n=String(t??""),i=/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(n);if(!i&&typeof r>"u")throw new TypeError(`Invalid URL: ${n}`);let s=n;if(!i){let N=new $W(r);if(N.protocol==="file:"){let P=n.indexOf("?"),U=n.indexOf("#"),G=P===-1?n.length:P,Y=U===-1?n.length:U,Z=Math.min(G,Y),ee=n.slice(0,Z),j=n.slice(Z),se=N.pathname||"/";se.startsWith("/")||(se=`/${se}`);let ie=se.endsWith("/")?se:qr.posix.dirname(se),ce=qr.posix.resolve(ie,ee);(ee.endsWith("/")||/(^|\/)\.\.?$/.test(ee))&&!ce.endsWith("/")&&(ce+="/"),s=`file://${ce}${j}`}else s=String(N.href).replace(/\/[^/]*$/,"/")+n}let o=s.indexOf("?"),a=s.indexOf("#"),A=o===-1?s.length:o,f=a===-1?s.length:a,l=Math.min(A,f),p=o===-1?"":s.slice(o,f),B=a===-1?"":s.slice(a);if(s.startsWith("file:")){let N=s.slice(5,l);N.startsWith("//")&&(N=/^\/\/[^/]*(.*)$/.exec(N)?.[1]||"/"),N.startsWith("/")||(N=`/${N}`),this.protocol="file:",this.hostname="",this.port="",this.pathname=N||"/",this.search=p,this.hash=B,this.host="",this.href=`file://${this.pathname}${this.search}${this.hash}`,this.origin="null",this.searchParams=new Hr(this.search);let P=()=>{let U=this.searchParams.toString();this.search=U?`?${U}`:"",this.href=`file://${this.pathname}${this.search}${this.hash}`};for(let U of["append","delete","set","sort"]){let G=this.searchParams[U]?.bind(this.searchParams);G&&(this.searchParams[U]=(...Y)=>{let Z=G(...Y);return P(),Z})}return}let S=s.match(/^(\w+:)\/\/([^/:?#]+)(:\d+)?(.*)$/);this.protocol=S?.[1]||"",this.hostname=S?.[2]||"",this.port=(S?.[3]||"").slice(1),this.pathname=(S?.[4]||"/").split("?")[0].split("#")[0]||"/",this.search=s.includes("?")?"?"+s.split("?")[1].split("#")[0]:"",this.hash=s.includes("#")?"#"+s.split("#")[1]:"",this.host=this.hostname+(this.port?":"+this.port:""),this.href=this.protocol+"//"+this.host+this.pathname+this.search+this.hash,this.origin=this.protocol+"//"+this.host,this.searchParams=new Hr(this.search);let _=()=>{let N=this.searchParams.toString();this.search=N?`?${N}`:"",this.href=this.protocol+"//"+this.host+this.pathname+this.search+this.hash};for(let N of["append","delete","set","sort"]){let P=this.searchParams[N]?.bind(this.searchParams);P&&(this.searchParams[N]=(...U)=>{let G=P(...U);return _(),G})}}toString(){return this.href}},Qn=(ya=class{constructor(e,t){if(zq(this,qt),zq(this,Qg),arguments.length<1)throw Qa('The "url" argument must be specified');let r=vve(Kt(e),arguments.length>=2?Kt(t):void 0);try{Kq(this,qt,r.base!==void 0?new YG(r.input,r.base):new YG(r.input))}catch{throw hve()}}static canParse(e,t){if(arguments.length<1)throw Qa('The "url" argument must be specified');try{return arguments.length>=2?new ya(e,t):new ya(e),!0}catch{return!1}}static createObjectURL(e){if(typeof Fl>"u"||!(e instanceof Fl))throw qA('The "obj" argument must be an instance of Blob. Received '+(e===null?"null":typeof e),"ERR_INVALID_ARG_TYPE");let t=`blob:nodedata:${wve()}`;return qG().set(t,e),t}static revokeObjectURL(e){if(arguments.length<1)throw Qa('The "url" argument must be specified');typeof e=="string"&&qG().delete(e)}get href(){if(!(this instanceof ya))throw jm();return jt(this,qt).href}set href(e){jt(this,qt).href=Kt(e)}get origin(){return jt(this,qt).origin}get protocol(){return jt(this,qt).protocol}set protocol(e){jt(this,qt).protocol=Kt(e)}get username(){return jt(this,qt).username}set username(e){jt(this,qt).username=Kt(e)}get password(){return jt(this,qt).password}set password(e){jt(this,qt).password=Kt(e)}get host(){return jt(this,qt).host}set host(e){jt(this,qt).host=Kt(e)}get hostname(){return jt(this,qt).hostname}set hostname(e){jt(this,qt).hostname=Kt(e)}get port(){return jt(this,qt).port}set port(e){jt(this,qt).port=Kt(e)}get pathname(){return jt(this,qt).pathname}set pathname(e){jt(this,qt).pathname=Kt(e)}get search(){if(!(this instanceof ya))throw jm();return jt(this,qt).search}set search(e){jt(this,qt).search=Kt(e)}get searchParams(){return jt(this,Qg)||Kq(this,Qg,new Hr({[UB]:()=>jt(this,qt).searchParams})),jt(this,Qg)}get hash(){return jt(this,qt).hash}set hash(e){jt(this,qt).hash=Kt(e)}toString(){if(!(this instanceof ya))throw jm();return jt(this,qt).href}toJSON(){if(!(this instanceof ya))throw jm();return jt(this,qt).href}[No](e,t,r){let n=this.constructor===ya?"URL":this.constructor.name;if(e<0)return`${n} {}`;let i=typeof r=="function"?o=>r(o,t):o=>JSON.stringify(o),s=[`${n} {`,` href: ${i(this.href)},`,` origin: ${i(this.origin)},`,` protocol: ${i(this.protocol)},`,` username: ${i(this.username)},`,` password: ${i(this.password)},`,` host: ${i(this.host)},`,` hostname: ${i(this.hostname)},`,` port: ${i(this.port)},`,` pathname: ${i(this.pathname)},`,` search: ${i(this.search)},`,` searchParams: ${this.searchParams[No](e-1,void 0,r)},`,` hash: ${i(this.hash)}`];return t?.showHidden&&(s[s.length-1]+=",",s.push(` [Symbol(context)]: ${Qve(this,r,t)}`)),s.push("}"),s.join(` -`)}get[ka](){return"URL"}},qt=new WeakMap,Qg=new WeakMap,ya);for(let e of["toString","toJSON"])Object.defineProperty(Qn.prototype,e,{value:Qn.prototype[e],writable:!0,configurable:!0,enumerable:!0});for(let e of["href","protocol","username","password","host","hostname","port","pathname","search","hash","origin","searchParams"]){let t=Object.getOwnPropertyDescriptor(Qn.prototype,e);t&&(t.enumerable=!0,Object.defineProperty(Qn.prototype,e,t))}Object.defineProperties(Qn.prototype,{[No]:{value:Qn.prototype[No],writable:!0,configurable:!0,enumerable:!1},[ka]:{get:Object.getOwnPropertyDescriptor(Qn.prototype,ka)?.get,configurable:!0,enumerable:!1}});for(let e of["canParse","createObjectURL","revokeObjectURL"])Object.defineProperty(Qn,e,{value:Qn[e],writable:!0,configurable:!0,enumerable:!0});function Rve(e=globalThis){Object.defineProperty(e,"URL",{value:Qn,writable:!0,configurable:!0,enumerable:!1}),Object.defineProperty(e,"URLSearchParams",{value:Hr,writable:!0,configurable:!0,enumerable:!1})}var F1,Dve=(F1=class{},y(F1,"builtinModules",["assert","async_hooks","buffer","child_process","console","cluster","constants","crypto","dgram","diagnostics_channel","domain","dns","dns/promises","events","fs","fs/promises","http","http2","https","inspector","module","net","os","path","path/posix","path/win32","perf_hooks","process","punycode","querystring","readline","repl","sqlite","stream","stream/consumers","stream/promises","stream/web","string_decoder","sys","timers","timers/promises","trace_events","tls","tty","url","util","util/types","v8","wasi","worker_threads","zlib","vm"]),F1),Tve=Dve.builtinModules,Nve={clearImmediate:globalThis.clearImmediate??function(){},clearInterval:globalThis.clearInterval??function(){},clearTimeout:globalThis.clearTimeout??function(){},setImmediate:globalThis.setImmediate??function(e,...t){return globalThis.setTimeout?.(()=>e(...t),0)},setInterval:globalThis.setInterval??function(e,t,...r){return globalThis.setTimeout?.(()=>e(...r),t??0)},setTimeout:globalThis.setTimeout??function(){}};function Mve(e){return e&&typeof e=="object"&&e.default!=null?e.default:e}function Ns(e){let t=Mve(e);return t==null||typeof t=="function"?t:typeof t=="object"?{...t}:t}function Mo(e,t,r){e!=null&&typeof e[t]>"u"&&(e[t]=r)}function Fve(e){return typeof e=="string"&&e.length>1&&e.endsWith("/")?e.slice(0,-1):e}var UA=Ns(xl);Mo(UA,"constants",RY);Mo(UA,"kMaxLength",Yl);Mo(UA,"kStringMaxLength",o0);Mo(UA,"Blob",globalThis.Blob);Mo(UA,"File",globalThis.File);var eV=Ns(YI),Ss=Ns(VCe),I1=null,WG=!1;function kve(){return WG||(WG=!0,I1=typeof Ss=="function"?Ss:Ss?.EventEmitter,typeof I1=="function"?(Object.assign(I1.prototype,Sl.EventEmitter.prototype),Object.assign(Sl.EventEmitter,Ss,Sl),Ss=Sl.EventEmitter,Ss.EventEmitter=Ss):Ss={...Ss,...Sl}),Ss}var qr=Ns(qg);qr?.posix||(qr.posix=Ns(qg?.posix??qg?.default?.posix)??qr);qr?.win32||(qr.win32=Ns(qg?.win32??qg?.default?.win32)??qr);if(qr?.normalize){let e=qr.normalize.bind(qr);qr.normalize=function(t){return Fve(e(t))}}var xve=Ns(JCe),Uve=Ns(q0),zt=Ns(Yt);typeof zt?.Stream=="function"&&(Object.assign(zt.Stream,zt),zt=zt.Stream,zt.Stream=zt,Object.defineProperty(zt,Symbol.hasInstance,{configurable:!0,value:t=>!t||typeof t!="object"&&typeof t!="function"?!1:typeof zt.Readable=="function"&&t instanceof zt.Readable||typeof zt.Writable=="function"&&t instanceof zt.Writable||typeof zt.Duplex=="function"&&t instanceof zt.Duplex||typeof zt.Transform=="function"&&t instanceof zt.Transform||typeof zt.PassThrough=="function"&&t instanceof zt.PassThrough}));function nI(e){!e||typeof e[Symbol.asyncIterator]=="function"||Object.defineProperty(e,Symbol.asyncIterator,{configurable:!0,value:function(){let t=this,r=[],n=[],i=!1,s=null,o=()=>{for(;n.length>0;){if(s){n.shift()(Promise.reject(s));continue}if(r.length>0){n.shift()(Promise.resolve({done:!1,value:r.shift()}));continue}if(i){n.shift()(Promise.resolve({done:!0,value:void 0}));continue}break}},a=l=>{r.push(l),o()},A=()=>{i=!0,o()},f=l=>{s=l,i=!0,o()};return t.on?.("data",a),t.on?.("end",A),t.on?.("close",A),t.on?.("error",f),t.resume?.(),{next(){return s?Promise.reject(s):r.length>0?Promise.resolve({done:!1,value:r.shift()}):i?Promise.resolve({done:!0,value:void 0}):new Promise(l=>{n.push(l)})},return(){return i=!0,t.off?.("data",a),t.off?.("end",A),t.off?.("close",A),t.off?.("error",f),o(),Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}}}})}nI(zt?.Readable?.prototype);nI(zt?.PassThrough?.prototype);nI(zt?.Transform?.prototype);nI(zt?.Duplex?.prototype);Mo(zt,"isReadable",e=>!!e&&e.readable!==!1&&e.destroyed!==!0);Mo(zt,"isErrored",e=>e?.errored!=null);Mo(zt,"isDisturbed",e=>!!(e?.locked||e?.disturbed===!0||e?.readableDidRead===!0));var Lve=Ns(jCe),Ui=Ns(wu),VG=!1;function Pve(){return VG||(VG=!0,Ui.URL=Qn,Ui.URLSearchParams=Hr,Ui.fileURLToPath=EY,Ui.pathToFileURL=pY,Ui?.default&&typeof Ui.default=="object"&&(Ui.default.URL=Qn,Ui.default.URLSearchParams=Hr,Ui.default.fileURLToPath=EY,Ui.default.pathToFileURL=pY)),Ui}function Ove(e){return String(e).replace(/^node:/,"")}var tV=null;function rV(e){let t=Ove(e),r=tV;if(Array.isArray(r)){let n=String(t??e).replace(/^node:/,"").split("/")[0];if(!r.includes(n))throw ou(e)}return t}Ge("__agentOSInitJsRuntime",function(e){tV=Array.isArray(e)?e.map(t=>String(t).replace(/^node:/,"").split("/")[0]):null});function Hve(e){switch(rV(e)){case"assert":return globalThis.__secureExecBuiltinAssertModule;case"async_hooks":return LY;case"buffer":return Mo(UA,"Blob",globalThis.Blob),Mo(UA,"File",globalThis.File),UA;case"cluster":throw ou(e);case"crypto":return Ra;case"diagnostics_channel":return swe;case"domain":throw ou(e);case"http":return _httpModule;case"http2":return _http2Module;case"events":return kve();case"fs":return _fsModule;case"fs/promises":return _fsModule.promises;case"os":return _osModule;case"path":return qr;case"path/posix":return qr.posix;case"path/win32":return qr.win32;case"perf_hooks":return hwe;case"process":return GV;case"punycode":return xve;case"querystring":return Uve;case"readline":return{createInterface(r={}){let n=r.input??null,i=r.output??null,s=new Map,o=!1,a=!1,A="",f=[],l=null,p=[],B=new Ru,S=(j,...se)=>{let ie=s.get(j)??[];for(let ce of[...ie])ce(...se)},_=j=>{if(p.length>0){p.shift()(j);return}if(l){let se=l;l=null,se({done:!1,value:j});return}f.push(j)},N=j=>{S("line",j),_(j)},P=()=>{let j=A.indexOf(` -`);for(;j!==-1;){let se=A.slice(0,j);se.endsWith("\r")&&(se=se.slice(0,-1)),A=A.slice(j+1),N(se),j=A.indexOf(` -`)}},U=()=>{!n||typeof n.off!="function"||(n.off("data",G),n.off("end",Y))},G=j=>{o||(typeof j=="string"?A+=j:j instanceof Uint8Array?A+=B.decode(j,{stream:!0}):j!=null&&(A+=String(j)),P())},Y=()=>{if(a)return;a=!0;let j=B.decode();j&&(A+=j),P(),A.length>0&&(N(A),A=""),ee.close()};n&&typeof n.on=="function"&&(n.on("data",G),n.on("end",Y),typeof n.resume=="function"&&n.resume());let Z={next(){return f.length>0?Promise.resolve({done:!1,value:f.shift()}):o||a?Promise.resolve({done:!0,value:void 0}):new Promise(j=>{l=j})},return(){return ee.close(),Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}},ee={addListener(j,se){return this.on(j,se)},on(j,se){let ie=s.get(j)??[];return ie.push(se),s.set(j,ie),this},once(j,se){let ie=(...ce)=>{this.off(j,ie),se(...ce)};return this.on(j,ie)},off(j,se){let ie=s.get(j)??[];return s.set(j,ie.filter(ce=>ce!==se)),this},removeListener(j,se){return this.off(j,se)},close(){if(!o){for(o=!0,U();p.length>0;)p.shift()("");if(l){let j=l;l=null,j({done:!0,value:void 0})}S("close")}},question(j,se){i&&typeof i.write=="function"&&j&&i.write(String(j));let ie=()=>f.length>0?Promise.resolve(f.shift()):o||a?Promise.resolve(""):new Promise(ce=>{p.push(ce)});if(typeof se=="function"){ie().then(ce=>{se(ce)});return}return ie()},[Symbol.asyncIterator](){return Z}};return ee}};case"repl":throw ou(e);case"stream":return zt;case"stream/consumers":return sB;case"stream/promises":return VY;case"string_decoder":return Lve;case"stream/web":return{ReadableStream:globalThis.ReadableStream,WritableStream:globalThis.WritableStream,TransformStream:globalThis.TransformStream,TextEncoderStream:globalThis.TextEncoderStream,TextDecoderStream:globalThis.TextDecoderStream,CompressionStream:globalThis.CompressionStream,DecompressionStream:globalThis.DecompressionStream};case"timers":return Nve;case"timers/promises":return tB;case"trace_events":throw ou(e);case"url":return Pve();case"sys":return iB(globalThis.__secureExecBuiltinUtilModule);case"util":return iB(globalThis.__secureExecBuiltinUtilModule);case"util/types":return iB(globalThis.__secureExecBuiltinUtilModule).types;case"child_process":return _childProcessModule;case"console":return zQe;case"constants":return eV;case"dns":return _dnsModule;case"dns/promises":return _dnsModule.promises;case"net":return _netModule;case"tls":return _tlsModule;case"tty":return rwe;case"dgram":return _dgramModule;case"sqlite":return _sqliteModule;case"https":return _httpsModule;case"inspector":throw ou(e);case"module":return _moduleModule;case"wasi":throw ou(e);case"zlib":return globalThis.__secureExecBuiltinZlibModule;case"v8":return Bwe;case"vm":return Cwe;case"worker_threads":return ZQe;default:{let r=new Error(`Cannot find module '${e}'`);throw r.code="MODULE_NOT_FOUND",r}}}function mR(e){let t=new Error(`${e} is not supported in sandbox`);return t.code="ERR_NOT_IMPLEMENTED",t}function du(e){throw mR(`crypto.${e}`)}var Pg=Symbol("secureExecCryptoKey"),BR=Symbol("secureExecCrypto"),IR=Symbol("secureExecSubtle"),nV="ERR_INVALID_THIS",iI="ERR_ILLEGAL_CONSTRUCTOR";function Vl(e,t){let r=new TypeError(e);return r.code=t,r}var qve=class extends Error{constructor(e="",t="Error"){super(e),this.name=String(t),this.code=0}};function JG(e,t,r){let n=new Error(r);return n.name=e,n.code=t,n}function b1(e){if(!(e instanceof CR)||e._token!==BR)throw Vl('Value of "this" must be of type Crypto',nV)}function Li(e){if(!(e instanceof bR)||e._token!==IR)throw Vl('Value of "this" must be of type SubtleCrypto',nV)}function Gve(e){return!ArrayBuffer.isView(e)||e instanceof DataView?!1:e instanceof Int8Array||e instanceof Int16Array||e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint16Array||e instanceof Uint32Array||e instanceof Uint8ClampedArray||e instanceof BigInt64Array||e instanceof BigUint64Array||_e.Buffer.isBuffer(e)}function Gn(e){return typeof e=="string"?_e.Buffer.from(e).toString("base64"):e instanceof ArrayBuffer?_e.Buffer.from(new Uint8Array(e)).toString("base64"):ArrayBuffer.isView(e)?_e.Buffer.from(new Uint8Array(e.buffer,e.byteOffset,e.byteLength)).toString("base64"):_e.Buffer.from(e).toString("base64")}function su(e){let t=_e.Buffer.from(e,"base64");return t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength)}function g2(e){return typeof e=="string"?{name:e}:e??{}}function Pi(e){let t={...g2(e)},r=t.hash,n=t.publicExponent,i=t.iv,s=t.additionalData,o=t.salt,a=t.info,A=t.context,f=t.label,l=t.public;return r&&(t.hash=g2(r)),n&&ArrayBuffer.isView(n)&&(t.publicExponent=_e.Buffer.from(new Uint8Array(n.buffer,n.byteOffset,n.byteLength)).toString("base64")),i&&(t.iv=Gn(i)),s&&(t.additionalData=Gn(s)),o&&(t.salt=Gn(o)),a&&(t.info=Gn(a)),A&&(t.context=Gn(A)),f&&(t.label=Gn(f)),l&&typeof l=="object"&&"_keyData"in l&&(t.public=l._keyData),t}var yY,Zg=(yY=Pg,class{constructor(e,t){y(this,"type");y(this,"extractable");y(this,"algorithm");y(this,"usages");y(this,"_keyData");y(this,"_pem");y(this,"_jwk");y(this,"_raw");y(this,"_sourceKeyObjectData");y(this,yY);if(t!==Pg||!e)throw Vl("Illegal constructor",iI);this.type=e.type,this.extractable=e.extractable,this.algorithm=e.algorithm,this.usages=e.usages,this._keyData=e,this._pem=e._pem,this._jwk=e._jwk,this._raw=e._raw,this._sourceKeyObjectData=e._sourceKeyObjectData,this[Pg]=!0}});Object.defineProperty(Zg.prototype,Symbol.toStringTag,{value:"CryptoKey",configurable:!0});Object.defineProperty(Zg,Symbol.hasInstance,{value(e){return!!(e&&typeof e=="object"&&(e[Pg]===!0||"_keyData"in e&&e[Symbol.toStringTag]==="CryptoKey"))},configurable:!0});function Ql(e){let t=globalThis.CryptoKey;if(typeof t=="function"&&t.prototype&&t.prototype!==Zg.prototype){let r=Object.create(t.prototype);return r.type=e.type,r.extractable=e.extractable,r.algorithm=e.algorithm,r.usages=e.usages,r._keyData=e,r._pem=e._pem,r._jwk=e._jwk,r._raw=e._raw,r._sourceKeyObjectData=e._sourceKeyObjectData,r}return new Zg(e,Pg)}function Oi(e){if(typeof _cryptoSubtle>"u")throw new Error("crypto.subtle is not supported in sandbox");return _cryptoSubtle.applySync(void 0,[JSON.stringify(e)])}var bR=class{constructor(e){y(this,"_token");if(e!==IR)throw Vl("Illegal constructor",iI);this._token=e}digest(e,t){return Li(this),Promise.resolve().then(()=>{let r=JSON.parse(Oi({op:"digest",algorithm:g2(e).name,data:Gn(t)}));return su(r.data)})}generateKey(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"generateKey",algorithm:Pi(e),extractable:t,usages:Array.from(r)}));return"publicKey"in n&&"privateKey"in n?{publicKey:Ql(n.publicKey),privateKey:Ql(n.privateKey)}:Ql(n.key)})}importKey(e,t,r,n,i){return Li(this),Promise.resolve().then(()=>{let s=JSON.parse(Oi({op:"importKey",format:e,keyData:e==="jwk"?t:Gn(t),algorithm:Pi(r),extractable:n,usages:Array.from(i)}));return Ql(s.key)})}exportKey(e,t){return Li(this),Promise.resolve().then(()=>{let r=JSON.parse(Oi({op:"exportKey",format:e,key:t._keyData}));return e==="jwk"?r.jwk:su(r.data??"")})}encrypt(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"encrypt",algorithm:Pi(e),key:t._keyData,data:Gn(r)}));return su(n.data)})}decrypt(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"decrypt",algorithm:Pi(e),key:t._keyData,data:Gn(r)}));return su(n.data)})}sign(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"sign",algorithm:Pi(e),key:t._keyData,data:Gn(r)}));return su(n.data)})}verify(e,t,r,n){return Li(this),Promise.resolve().then(()=>JSON.parse(Oi({op:"verify",algorithm:Pi(e),key:t._keyData,signature:Gn(r),data:Gn(n)})).result)}deriveBits(e,t,r){return Li(this),Promise.resolve().then(()=>{let n=JSON.parse(Oi({op:"deriveBits",algorithm:Pi(e),baseKey:t._keyData,length:r}));return su(n.data)})}deriveKey(e,t,r,n,i){return Li(this),Promise.resolve().then(()=>{let s=JSON.parse(Oi({op:"deriveKey",algorithm:Pi(e),baseKey:t._keyData,derivedKeyAlgorithm:Pi(r),extractable:n,usages:Array.from(i)}));return Ql(s.key)})}wrapKey(e,t,r,n){return Li(this),Promise.resolve().then(()=>{let i=JSON.parse(Oi({op:"wrapKey",format:e,key:t._keyData,wrappingKey:r._keyData,wrapAlgorithm:Pi(n)}));return su(i.data)})}unwrapKey(e,t,r,n,i,s,o){return Li(this),Promise.resolve().then(()=>{let a=JSON.parse(Oi({op:"unwrapKey",format:e,wrappedKey:Gn(t),unwrappingKey:r._keyData,unwrapAlgorithm:Pi(n),unwrappedKeyAlgorithm:Pi(i),extractable:s,usages:Array.from(o)}));return Ql(a.key)})}},iV=new bR(IR),CR=class{constructor(e){y(this,"_token");if(e!==BR)throw Vl("Illegal constructor",iI);this._token=e}get subtle(){return b1(this),iV}getRandomValues(e){if(b1(this),!Gve(e))throw JG("TypeMismatchError",17,"The data argument must be an integer-type TypedArray");if(typeof _cryptoRandomFill>"u"&&du("getRandomValues"),e.byteLength>65536)throw JG("QuotaExceededError",22,`The ArrayBufferView's byte length (${e.byteLength}) exceeds the number of bytes of entropy available via this API (65536)`);let t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);try{let r=_cryptoRandomFill.applySync(void 0,[t.byteLength]),n=_e.Buffer.from(r,"base64");if(n.byteLength!==t.byteLength)throw new Error("invalid host entropy size");return t.set(n),e}catch{du("getRandomValues")}}randomUUID(){b1(this),typeof _cryptoRandomUUID>"u"&&du("randomUUID");try{let e=_cryptoRandomUUID.applySync(void 0,[]);if(typeof e!="string")throw new Error("invalid host uuid");return e}catch{du("randomUUID")}}},Yve=new CR(BR),Rl=Yve;function Wve(e){let t=[];return{update(r,n){let i=typeof r=="string"?_e.Buffer.from(r,n||"utf8"):_e.Buffer.from(r);return t.push(i),this},digest(r){typeof _cryptoHashDigest>"u"&&du("createHash");let n=t.length===1?t[0]:_e.Buffer.concat(t),i=_cryptoHashDigest.applySync(void 0,[String(e),n.toString("base64")]),s=_e.Buffer.from(String(i||""),"base64");return r?s.toString(r):s}}}function sV(e){if(Jl(e)){if(e.type!=="secret")throw new TypeError("Symmetric crypto operations require a secret KeyObject");return _e.Buffer.from(String(e._serialized.raw||""),"base64")}return e&&typeof e=="object"&&e[Symbol.toStringTag]==="CryptoKey"&&typeof e._raw=="string"?_e.Buffer.from(String(e._raw||""),"base64"):typeof e=="string"?_e.Buffer.from(e):Dt(e)}function Vve(e,t){let r=[],n=sV(t);return{update(i,s){let o=typeof i=="string"?_e.Buffer.from(i,s||"utf8"):_e.Buffer.from(i);return r.push(o),this},digest(i){typeof _cryptoHmacDigest>"u"&&du("createHmac");let s=r.length===1?r[0]:_e.Buffer.concat(r),o=_cryptoHmacDigest.applySync(void 0,[String(e),n.toString("base64"),s.toString("base64")]),a=_e.Buffer.from(String(o||""),"base64");return i?a.toString(i):a}}}var Og=Symbol("secureExecBuiltinKeyObject");function p2(e){return _e.Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function Dt(e,t=void 0){return _e.Buffer.isBuffer(e)?_e.Buffer.from(e):typeof e=="string"?_e.Buffer.from(e,t||"utf8"):e instanceof ArrayBuffer?_e.Buffer.from(new Uint8Array(e)):ArrayBuffer.isView(e)?_e.Buffer.from(new Uint8Array(e.buffer,e.byteOffset,e.byteLength)):_e.Buffer.from(e??[])}function wa(e,t=void 0){return t?e.toString(t):e}function Jl(e){return!!(e&&typeof e=="object"&&(e[Og]===!0||e[Symbol.toStringTag]==="KeyObject"&&"_serialized"in e))}function Ds(e){if(Jl(e))return e._serialized;if(e&&typeof e=="object"&&e[Symbol.toStringTag]==="CryptoKey"&&"_keyData"in e)return e._keyData;if(typeof e=="bigint")return{__type:"bigint",value:e.toString()};if(p2(e))return{__type:"buffer",value:Dt(e).toString("base64")};if(Array.isArray(e))return e.map(t=>Ds(t));if(e&&typeof e=="object"){let t={};for(let[r,n]of Object.entries(e))n!==void 0&&(t[r]=Ds(n));return t}return e}function $g(e){if(Array.isArray(e))return e.map(r=>$g(r));if(!e||typeof e!="object")return e;if(e.__type==="buffer")return _e.Buffer.from(String(e.value||""),"base64");if(e.__type==="bigint")return BigInt(String(e.value||"0"));if(e.__type==="keyObject")return Tl(e.value);let t={};for(let[r,n]of Object.entries(e))t[r]=$g(n);return t}function oV(e){if(Jl(e))return e._serialized;if(e&&typeof e=="object"&&e[Symbol.toStringTag]==="CryptoKey"&&"_keyData"in e)return e._keyData;if(e&&typeof e=="object"&&!Array.isArray(e)&&"key"in e){let{key:t,...r}=e,n=oV(t);return n&&typeof n=="object"&&!Array.isArray(n)&&"type"in n&&("pem"in n||"raw"in n)?{...n,...Object.fromEntries(Object.entries(r).map(([i,s])=>[i,Ds(s)]))}:{...Object.fromEntries(Object.entries(r).map(([i,s])=>[i,Ds(s)])),key:Ds(t)}}return Ds(e)}function TA(e){return JSON.stringify(oV(e))}function C1(e){return JSON.stringify({hasOptions:e!==void 0,options:e===void 0?null:Ds(e)})}function aV(e){return e==null?null:typeof e=="string"?e:typeof e=="object"&&e&&typeof e.name=="string"?e.name:String(e)}function pr(e,t,r){return typeof e>"u"&&du(t),e.applySync(void 0,r)}function jG(e){return e&&typeof e=="object"&&e.kind==="buffer"?_e.Buffer.from(String(e.value||""),"base64"):e&&typeof e=="object"&&e.kind==="string"?String(e.value||""):Tl(e)}var mY,sI=(mY=Og,class{constructor(e,t){y(this,"type");y(this,"asymmetricKeyType");y(this,"asymmetricKeyDetails");y(this,"symmetricKeySize");y(this,"_serialized");y(this,mY);if(t!==Og||!e||typeof e!="object")throw Vl("Illegal constructor",iI);this.type=e.type,this.asymmetricKeyType=e.asymmetricKeyType,this.asymmetricKeyDetails=e.asymmetricKeyDetails,this.symmetricKeySize=e.raw?_e.Buffer.from(String(e.raw),"base64").length:void 0,this._serialized=e,this[Og]=!0}export(e=void 0){if(this.type==="secret")return e&&e.format==="jwk"&&this._serialized.jwk?{...this._serialized.jwk}:_e.Buffer.from(String(this._serialized.raw||""),"base64");if(e==null||typeof e!="object"){let t=new TypeError('The "options" argument must be of type object. Received undefined');throw t.code="ERR_INVALID_ARG_TYPE",t}if(e.format==="jwk"&&this._serialized.jwk)return{...this._serialized.jwk};if(e.format&&e.format!=="pem")throw mR(`crypto.KeyObject.export(${e.format})`);return String(this._serialized.pem||"")}equals(e){return Jl(e)&&JSON.stringify(this._serialized)===JSON.stringify(e._serialized)}});Object.defineProperty(sI.prototype,Symbol.toStringTag,{value:"KeyObject",configurable:!0});Object.defineProperty(sI,Symbol.hasInstance,{value(e){return Jl(e)},configurable:!0});function Tl(e){return Jl(e)?e:new sI(e,Og)}function Jve(e){if(!e||typeof e!="object")return{};let t={};return"aad"in e&&e.aad!=null&&(t.aad=Dt(e.aad).toString("base64")),"authTag"in e&&e.authTag!=null&&(t.authTag=Dt(e.authTag).toString("base64")),"authTagLength"in e&&e.authTagLength!=null&&(t.authTagLength=Number(e.authTagLength)),"autoPadding"in e&&(t.autoPadding=!!e.autoPadding),t}var zG=class{constructor(e,t,r,n,i=void 0){y(this,"_mode");y(this,"_algorithm");y(this,"_key");y(this,"_iv");y(this,"_options");y(this,"_sessionId");y(this,"_authTag");this._mode=e,this._algorithm=String(t),this._key=sV(r),this._iv=n==null?null:Dt(n),this._options=Jve(i),this._sessionId=null,this._authTag=null}_ensureSession(){return this._sessionId!=null?this._sessionId:(this._sessionId=Number(pr(_cryptoCipherivCreate,this._mode==="cipher"?"createCipheriv":"createDecipheriv",[this._mode,this._algorithm,this._key.toString("base64"),this._iv?this._iv.toString("base64"):null,Object.keys(this._options).length>0?JSON.stringify(this._options):null])),this._sessionId)}_assertMutable(e){if(this._sessionId!=null)throw mR(`crypto.${e} after update()`)}update(e,t=void 0,r=void 0){let n=Dt(e,t),i=pr(_cryptoCipherivUpdate,this._mode==="cipher"?"createCipheriv":"createDecipheriv",[this._ensureSession(),n.toString("base64")]);return wa(_e.Buffer.from(String(i||""),"base64"),r)}final(e=void 0){let t=JSON.parse(String(pr(_cryptoCipherivFinal,this._mode==="cipher"?"createCipheriv":"createDecipheriv",[this._ensureSession()])||"{}"));return t.authTag&&(this._authTag=_e.Buffer.from(String(t.authTag),"base64")),wa(_e.Buffer.from(String(t.data||""),"base64"),e)}setAAD(e,t=void 0){return this._assertMutable(this._mode==="cipher"?"createCipheriv":"createDecipheriv"),this._options.aad=Dt(e).toString("base64"),t&&typeof t=="object"&&t.authTagLength!=null&&(this._options.authTagLength=Number(t.authTagLength)),this}setAuthTag(e){return this._assertMutable("createDecipheriv"),this._authTag=Dt(e),this._options.authTag=this._authTag.toString("base64"),this}getAuthTag(){if(!this._authTag)throw new Error("Invalid state for operation getAuthTag");return _e.Buffer.from(this._authTag)}setAutoPadding(e=!0){return this._assertMutable(this._mode==="cipher"?"createCipheriv":"createDecipheriv"),this._options.autoPadding=!!e,this}},E2=class{constructor(e){y(this,"_algorithm");y(this,"_chunks");this._algorithm=e,this._chunks=[]}update(e,t=void 0){return this._chunks.push(Dt(e,t)),this}write(e,t=void 0){return this.update(e,t),!0}end(e=void 0,t=void 0){return e!==void 0&&this.update(e,t),this}_inputBuffer(){return this._chunks.length===0?_e.Buffer.alloc(0):this._chunks.length===1?this._chunks[0]:_e.Buffer.concat(this._chunks)}sign(e,t=void 0){let r=pr(_cryptoSign,"sign",[aV(this._algorithm),this._inputBuffer().toString("base64"),TA(e)]);return wa(_e.Buffer.from(String(r||""),"base64"),t)}},KG=class extends E2{verify(e,t,r=void 0){let n=Dt(t,r);return!!pr(_cryptoVerify,"verify",[aV(this._algorithm),this._inputBuffer().toString("base64"),TA(e),n.toString("base64")])}};function jve(e,t=void 0,r=void 0,n=void 0){let i=[];return typeof e=="string"?(i.push(Dt(e,typeof t=="string"?t:void 0)),r!==void 0?i.push(typeof r=="string"?Dt(r,typeof n=="string"?n:void 0):r):(typeof t=="number"||p2(t))&&i.push(t),i):(i.push(e),r!==void 0?i.push(r):(typeof t=="number"||p2(t))&&i.push(t),i)}var XG=typeof FinalizationRegistry=="function"?new FinalizationRegistry(e=>{try{pr(_cryptoDiffieHellmanSessionDestroy,"createDiffieHellman",[e])}catch{}}):null,wg=class{constructor(e){y(this,"_sessionId");this._sessionId=Number(pr(_cryptoDiffieHellmanSessionCreate,"createDiffieHellman",[JSON.stringify({type:e.type,name:e.name,args:(e.args||[]).map(t=>Ds(t))})])),XG?.register(this,this._sessionId,this)}_destroySession(){if(this._sessionId==null)return;let e=this._sessionId;this._sessionId=null,XG?.unregister(this),pr(_cryptoDiffieHellmanSessionDestroy,"createDiffieHellman",[e])}dispose(){this._destroySession()}[Symbol.dispose||Symbol.for("Symbol.dispose")](){this._destroySession()}_call(e,t=[]){if(this._sessionId==null)throw new Error("Diffie-Hellman session has been destroyed");let r=JSON.parse(String(pr(_cryptoDiffieHellmanSessionCall,"createDiffieHellman",[this._sessionId,JSON.stringify({method:e,args:t.map(n=>Ds(n))})])||"{}"));return r.hasResult?$g(r.result):void 0}get verifyError(){let e=this._call("verifyError");return e==null?0:Number(e)}generateKeys(e=void 0){return wa(Dt(this._call("generateKeys")),e)}computeSecret(e,t=void 0,r=void 0){let n=this._call("computeSecret",[Dt(e,t)]);return wa(Dt(n),r)}getPrime(e=void 0){return wa(Dt(this._call("getPrime")),e)}getGenerator(e=void 0){return wa(Dt(this._call("getGenerator")),e)}getPublicKey(e=void 0){return wa(Dt(this._call("getPublicKey")),e)}getPrivateKey(e=void 0){return wa(Dt(this._call("getPrivateKey")),e)}setPrivateKey(e,t=void 0){this._call("setPrivateKey",[Dt(e,t)])}setPublicKey(e,t=void 0){this._call("setPublicKey",[Dt(e,t)])}},Ra={KeyObject:sI,DiffieHellman:wg,ECDH:wg,randomFillSync(e,t=0,r=void 0){let n=e instanceof ArrayBuffer?new Uint8Array(e):e;if(!ArrayBuffer.isView(n))throw new TypeError('The "buffer" argument must be an instance of ArrayBuffer, Buffer, TypedArray, or DataView');let i=Number(t)||0;if(!Number.isInteger(i)||i<0||i>n.byteLength)throw new RangeError('The value of "offset" is out of range');let s=r===void 0?n.byteLength-i:Number(r);if(!Number.isInteger(s)||s<0||i+s>n.byteLength)throw new RangeError('The value of "size" is out of range');let o=new Uint8Array(n.buffer,n.byteOffset+i,s);return Rl.getRandomValues(o),e},randomFill(e,t,r,n){let i=t,s=r,o=n;if(typeof i=="function"?(o=i,i=0,s=void 0):typeof s=="function"&&(o=s,s=void 0),typeof o!="function")throw new TypeError('The "callback" argument must be of type function');try{let a=Ra.randomFillSync(e,i,s);queueMicrotask(()=>o(null,a))}catch(a){queueMicrotask(()=>o(a))}},createHash(e){return Wve(e)},createHmac(e,t){return Vve(e,t)},createCipheriv(e,t,r,n=void 0){return new zG("cipher",e,t,r,n)},createDecipheriv(e,t,r,n=void 0){return new zG("decipher",e,t,r,n)},createSign(e){return new E2(e)},createVerify(e){return new KG(e)},sign(e,t,r){let n=new E2(e);return n.update(t),n.sign(r)},verify(e,t,r,n){let i=new KG(e);return i.update(t),i.verify(r,n)},createPrivateKey(e){let t=pr(_cryptoCreateKeyObject,"createPrivateKey",["createPrivateKey",TA(e)]);return Tl(JSON.parse(String(t||"{}")))},createPublicKey(e){let t=pr(_cryptoCreateKeyObject,"createPublicKey",["createPublicKey",TA(e)]);return Tl(JSON.parse(String(t||"{}")))},createSecretKey(e){return Tl({type:"secret",raw:Dt(e).toString("base64")})},publicEncrypt(e,t){let r=pr(_cryptoAsymmetricOp,"publicEncrypt",["publicEncrypt",TA(e),Dt(t).toString("base64")]);return _e.Buffer.from(String(r||""),"base64")},publicDecrypt(e,t){let r=pr(_cryptoAsymmetricOp,"publicDecrypt",["publicDecrypt",TA(e),Dt(t).toString("base64")]);return _e.Buffer.from(String(r||""),"base64")},privateEncrypt(e,t){let r=pr(_cryptoAsymmetricOp,"privateEncrypt",["privateEncrypt",TA(e),Dt(t).toString("base64")]);return _e.Buffer.from(String(r||""),"base64")},privateDecrypt(e,t){let r=pr(_cryptoAsymmetricOp,"privateDecrypt",["privateDecrypt",TA(e),Dt(t).toString("base64")]);return _e.Buffer.from(String(r||""),"base64")},pbkdf2Sync(e,t,r,n,i){let s=pr(_cryptoPbkdf2,"pbkdf2Sync",[Dt(e).toString("base64"),Dt(t).toString("base64"),Number(r),Number(n),String(i)]);return _e.Buffer.from(String(s||""),"base64")},pbkdf2(e,t,r,n,i,s){let o=i,a=s;if(typeof o=="function"&&(a=o,o="sha1"),typeof a!="function")throw new TypeError('The "callback" argument must be of type function');queueMicrotask(()=>{try{a(null,Ra.pbkdf2Sync(e,t,r,n,o))}catch(A){a(A)}})},scryptSync(e,t,r,n=void 0){let i=pr(_cryptoScrypt,"scryptSync",[Dt(e).toString("base64"),Dt(t).toString("base64"),Number(r),JSON.stringify(Ds(n||{}))]);return _e.Buffer.from(String(i||""),"base64")},scrypt(e,t,r,n,i){let s=n,o=i;if(typeof s=="function"&&(o=s,s=void 0),typeof o!="function")throw new TypeError('The "callback" argument must be of type function');queueMicrotask(()=>{try{o(null,Ra.scryptSync(e,t,r,s))}catch(a){o(a)}})},generateKeyPairSync(e,t=void 0){let r=JSON.parse(String(pr(_cryptoGenerateKeyPairSync,"generateKeyPairSync",[String(e),C1(t)])||"{}"));return{publicKey:jG(r.publicKey),privateKey:jG(r.privateKey)}},generateKeyPair(e,t,r){let n=t,i=r;if(typeof n=="function"&&(i=n,n=void 0),typeof i!="function")throw new TypeError('The "callback" argument must be of type function');queueMicrotask(()=>{try{let s=Ra.generateKeyPairSync(e,n);i(null,s.publicKey,s.privateKey)}catch(s){i(s)}})},generateKeySync(e,t=void 0){let r=JSON.parse(String(pr(_cryptoGenerateKeySync,"generateKeySync",[String(e),C1(t)])||"{}"));return Tl(r)},generatePrimeSync(e,t=void 0){let r=JSON.parse(String(pr(_cryptoGeneratePrimeSync,"generatePrimeSync",[Number(e),C1(t)])||"null"));return $g(r)},generatePrime(e,t,r){let n=t,i=r;if(typeof n=="function"&&(i=n,n=void 0),typeof i!="function")throw new TypeError('The "callback" argument must be of type function');queueMicrotask(()=>{try{i(null,Ra.generatePrimeSync(e,n))}catch(s){i(s)}})},diffieHellman(e){let t=JSON.parse(String(pr(_cryptoDiffieHellman,"diffieHellman",[JSON.stringify(Ds(e))])||"null"));return Dt($g(t))},getDiffieHellman(e){return new wg({type:"group",name:String(e)})},createDiffieHellman(e,t=void 0,r=void 0,n=void 0){return new wg({type:"dh",args:jve(e,t,r,n)})},createECDH(e){return new wg({type:"ecdh",name:String(e)})},getFips(){return 0},getHashes(){return["md5","sha1","sha224","sha256","sha384","sha512"]},getCiphers(){return["aes-128-cbc","aes-128-ctr","aes-128-gcm","aes-192-cbc","aes-192-ctr","aes-192-gcm","aes-256-cbc","aes-256-ctr","aes-256-gcm","aes128","aes192","aes256"]},getCurves(){return["prime256v1","secp256k1","secp384r1","secp521r1"]},getRandomValues(e){return Rl.getRandomValues(e)},randomBytes(e){let t=Math.max(0,Number(e)||0),r=new Uint8Array(t);return Rl.getRandomValues(r),_e.Buffer.from(r)},randomUUID(){return Rl.randomUUID()},get constants(){return eV},subtle:iV,webcrypto:Rl},Tt=H2(q2(),1),y2=0,au=1,ma=2,qn=64,Ba=128,Au=512,fu=1024,gu=class{constructor(e){y(this,"dev");y(this,"ino");y(this,"mode");y(this,"nlink");y(this,"uid");y(this,"gid");y(this,"rdev");y(this,"size");y(this,"blksize");y(this,"blocks");y(this,"atimeMs");y(this,"mtimeMs");y(this,"ctimeMs");y(this,"birthtimeMs");y(this,"atime");y(this,"mtime");y(this,"ctime");y(this,"birthtime");this.dev=e.dev??0,this.ino=e.ino??0,this.mode=e.mode,this.nlink=e.nlink??1,this.uid=e.uid??0,this.gid=e.gid??0,this.rdev=e.rdev??0,this.size=e.size,this.blksize=e.blksize??4096,this.blocks=e.blocks??Math.ceil(e.size/512);let t=e.atimeMs??Date.now(),r=e.mtimeMs??Date.now(),n=e.ctimeMs??Date.now();this.atimeMs=t+(e.atimeNsec??0)%1e6/1e6,this.mtimeMs=r+(e.mtimeNsec??0)%1e6/1e6,this.ctimeMs=n+(e.ctimeNsec??0)%1e6/1e6,this.birthtimeMs=e.birthtimeMs??Date.now(),this.atime=new Date(this.atimeMs),this.mtime=new Date(this.mtimeMs),this.ctime=new Date(this.ctimeMs),this.birthtime=new Date(this.birthtimeMs)}isFile(){return(this.mode&61440)===32768}isDirectory(){return(this.mode&61440)===16384}isSymbolicLink(){return(this.mode&61440)===40960}isBlockDevice(){return!1}isCharacterDevice(){return!1}isFIFO(){return!1}isSocket(){return!1}},LB=class{constructor(e,t,r=""){y(this,"name");y(this,"parentPath");y(this,"path");y(this,"_isDir");this.name=e,this._isDir=t,this.parentPath=r,this.path=r}isFile(){return!this._isDir}isDirectory(){return this._isDir}isSymbolicLink(){return!1}isBlockDevice(){return!1}isCharacterDevice(){return!1}isFIFO(){return!1}isSocket(){return!1}},ZG=class{constructor(e){y(this,"path");y(this,"_entries",null);y(this,"_index",0);y(this,"_closed",!1);this.path=e}_load(){return this._entries===null&&(this._entries=$.readdirSync(this.path,{withFileTypes:!0})),this._entries}readSync(){if(this._closed)throw new Error("Directory handle was closed");let e=this._load();return this._index>=e.length?null:e[this._index++]}async read(){return this.readSync()}closeSync(){this._closed=!0}async close(){this.closeSync()}async*[Symbol.asyncIterator](){let e=this._load();for(let t of e){if(this._closed)return;yield t}this._closed=!0}},m2=64*1024,zve=16*1024,$G=2**31-1;function AV(e){let t=new Error("The operation was aborted");return t.name="AbortError",t.code="ABORT_ERR",e!==void 0&&(t.cause=e),t}function B2(e){if(e!==void 0){if(e===null||typeof e!="object"||typeof e.aborted!="boolean"||typeof e.addEventListener!="function"||typeof e.removeEventListener!="function"){let t=new TypeError('The "signal" argument must be an instance of AbortSignal');throw t.code="ERR_INVALID_ARG_TYPE",t}return e}}function Dg(e){if(e?.aborted)throw AV(e.reason)}function zm(){return new Promise(e=>process.nextTick(e))}function Kve(e){let t=new Error(e);return t.code="ERR_INTERNAL_ASSERTION",t}function Ro(e,t,r){let n=new RangeError(`The value of "${e}" is out of range. It must be ${t}. Received ${String(r)}`);return n.code="ERR_OUT_OF_RANGE",n}function fV(e){if(e===null)return"Received null";if(e===void 0)return"Received undefined";if(typeof e=="string")return`Received type string ('${e}')`;if(typeof e=="number")return`Received type number (${String(e)})`;if(typeof e=="boolean")return`Received type boolean (${String(e)})`;if(typeof e=="bigint")return`Received type bigint (${e.toString()}n)`;if(typeof e=="symbol")return`Received type symbol (${String(e)})`;if(typeof e=="function")return e.name?`Received function ${e.name}`:"Received function";if(Array.isArray(e))return"Received an instance of Array";if(e&&typeof e=="object"){let t=e.constructor?.name;if(t)return`Received an instance of ${t}`}return`Received type ${typeof e} (${String(e)})`}function bt(e,t,r){let n=new TypeError(`The "${e}" argument must be ${t}. ${fV(r)}`);return n.code="ERR_INVALID_ARG_TYPE",n}function uV(e,t){let r=new TypeError(`The argument '${e}' ${t}`);return r.code="ERR_INVALID_ARG_VALUE",r}function Xve(e){let t=typeof e=="string"?`'${e}'`:e===void 0?"undefined":e===null?"null":String(e),r=new TypeError(`The argument 'encoding' is invalid encoding. Received ${t}`);return r.code="ERR_INVALID_ARG_VALUE",r}function Q1(e,t){if(typeof e=="string")return Tt.Buffer.from(e,t??"utf8");if(Tt.Buffer.isBuffer(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);if(e instanceof Uint8Array)return e;if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);throw bt("data","a string, Buffer, TypedArray, or DataView",e)}async function*Zve(e,t){if(typeof e=="string"||ArrayBuffer.isView(e)){yield Q1(e,t);return}if(e&&typeof e[Symbol.asyncIterator]=="function"){for await(let r of e)yield Q1(r,t);return}if(e&&typeof e[Symbol.iterator]=="function"){for(let r of e)yield Q1(r,t);return}throw bt("data","a string, Buffer, TypedArray, DataView, or Iterable",e)}var pu=class mn{constructor(t){y(this,"_fd");y(this,"_closing",!1);y(this,"_closed",!1);y(this,"_listeners",new Map);this._fd=t}static _assertHandle(t){if(!(t instanceof mn))throw Kve("handle must be an instance of FileHandle");return t}_emitCloseOnce(){if(this._closed){this._fd=-1,this.emit("close");return}this._closed=!0,this._fd=-1,this.emit("close")}_resolvePath(){return this._fd<0?null:xA.applySync(void 0,[this._fd])}get fd(){return this._fd}get closed(){return this._closed}on(t,r){let n=this._listeners.get(t)??[];return n.push(r),this._listeners.set(t,n),this}once(t,r){let n=(...i)=>{this.off(t,n),r(...i)};return n._originalListener=r,this.on(t,n)}off(t,r){let n=this._listeners.get(t);if(!n)return this;let i=n.findIndex(s=>s===r||s._originalListener===r);return i!==-1&&n.splice(i,1),this}removeListener(t,r){return this.off(t,r)}emit(t,...r){let n=this._listeners.get(t);if(!n||n.length===0)return!1;for(let i of n.slice())i(...r);return!0}async close(){let t=mn._assertHandle(this);if((t._closing||t._closed)&&t._fd<0)throw Ve("EBADF","EBADF: bad file descriptor, close","close");t._closing=!0;try{$.closeSync(t._fd),t._emitCloseOnce()}finally{t._closing=!1}}async stat(){let t=mn._assertHandle(this);return $.fstatSync(t.fd)}async sync(){let t=mn._assertHandle(this);$.fsyncSync(t.fd)}async datasync(){return this.sync()}async truncate(t){let r=mn._assertHandle(this);$.ftruncateSync(r.fd,t)}async chmod(t){let n=mn._assertHandle(this)._resolvePath();if(!n)throw Ve("EBADF","EBADF: bad file descriptor","chmod");$.chmodSync(n,t)}async chown(t,r){let i=mn._assertHandle(this)._resolvePath();if(!i)throw Ve("EBADF","EBADF: bad file descriptor","chown");$.chownSync(i,t,r)}async utimes(t,r){let n=mn._assertHandle(this);$.futimesSync(n.fd,t,r)}async read(t,r,n,i){let s=mn._assertHandle(this),o=t,a=r,A=n,f=i;if(o!==null&&typeof o=="object"&&!ArrayBuffer.isView(o)&&(a=o.offset,A=o.length,f=o.position,o=o.buffer??null),o===null&&(o=Tt.Buffer.alloc(zve)),!ArrayBuffer.isView(o))throw bt("buffer","an instance of ArrayBufferView",o);let l=a??0,p=A??o.byteLength-l;return{bytesRead:$.readSync(s.fd,o,l,p,f??null),buffer:o}}async write(t,r,n,i){let s=mn._assertHandle(this);if(typeof t=="string"){let f=typeof n=="string"?n:"utf8";if(f==="hex"&&t.length%2!==0)throw uV("encoding",`is invalid for data of length ${t.length}`);return{bytesWritten:$.writeSync(s.fd,Tt.Buffer.from(t,f),0,void 0,r??null),buffer:t}}if(!ArrayBuffer.isView(t))throw bt("buffer","a string, Buffer, TypedArray, or DataView",t);let o=r??0,a=typeof n=="number"?n:void 0;return{bytesWritten:$.writeSync(s.fd,t,o,a,i??null),buffer:t}}async readFile(t){let r=mn._assertHandle(this),n=typeof t=="string"?{encoding:t}:t??void 0,i=B2(n?.signal),s=n?.encoding??void 0;if((await r.stat()).size>$G){let l=new RangeError("File size is greater than 2 GiB");throw l.code="ERR_FS_FILE_TOO_LARGE",l}await zm(),Dg(i);let a=[],A=0;for(;;){Dg(i);let l=Tt.Buffer.alloc(m2),{bytesRead:p}=await r.read(l,0,l.byteLength,null);if(p===0)break;if(a.push(l.subarray(0,p)),A+=p,A>$G){let B=new RangeError("File size is greater than 2 GiB");throw B.code="ERR_FS_FILE_TOO_LARGE",B}await zm()}let f=Tt.Buffer.concat(a,A);return s?f.toString(s):f}async writeFile(t,r){let n=mn._assertHandle(this),i=typeof r=="string"?{encoding:r}:r??void 0,s=B2(i?.signal),o=i?.encoding??void 0;await zm(),Dg(s);for await(let a of Zve(t,o))Dg(s),await n.write(a,0,a.byteLength,void 0),await zm()}async appendFile(t,r){return this.writeFile(t,r)}createReadStream(t){return mn._assertHandle(this),new aI(null,{...t??{},fd:this})}createWriteStream(t){return mn._assertHandle(this),new AI(null,{...t??{},fd:this})}};function oI(e){return ArrayBuffer.isView(e)}function $ve(e,t){let r;t===null?r="Received null":typeof t=="string"?r=`Received type string ('${t}')`:r=`Received type ${typeof t} (${String(t)})`;let n=new TypeError(`The "${e}" property must be of type function. ${r}`);return n.code="ERR_INVALID_ARG_TYPE",n}function vA(e,t="cb"){if(typeof e!="function")throw bt(t,"of type function",e)}function I2(e){if(e!=null&&(typeof e!="string"||!Tt.Buffer.isEncoding(e)))throw Xve(e)}function ir(e){if(typeof e=="string"){I2(e);return}e&&typeof e=="object"&&"encoding"in e&&I2(e.encoding)}function Be(e,t="path"){if(typeof e=="string")return e;if(Tt.Buffer.isBuffer(e))return e.toString("utf8");if(e instanceof URL){if(e.protocol==="file:")return e.pathname;throw bt(t,"of type string or an instance of Buffer or URL",e)}throw bt(t,"of type string or an instance of Buffer or URL",e)}function eY(e){try{return Be(e)}catch{return null}}function Kr(e,t,r={}){let{min:n=0,max:i=2147483647,allowNegativeOne:s=!1}=r;if(typeof t!="number")throw bt(e,"of type number",t);if(!Number.isFinite(t)||!Number.isInteger(t))throw Ro(e,"an integer",t);if(s&&t===-1||t>=n&&t<=i)return t;throw Ro(e,`>= ${n} && <= ${i}`,t)}function Sa(e,t="mode"){if(typeof e=="string"){if(!/^[0-7]+$/.test(e))throw uV(t,"must be a 32-bit unsigned integer or an octal string. Received '"+e+"'");return parseInt(e,8)}return Kr(t,e,{min:0,max:4294967295})}function tY(e){if(e!=null)return Sa(e)}function w1(e){return e&-512|e&511&~(EB&511)}function cV(e){if(e?.start!==void 0){if(typeof e.start!="number")throw bt("start","of type number",e.start);if(!Number.isFinite(e.start)||!Number.isInteger(e.start)||e.start<0)throw Ro("start",">= 0",e.start)}}function PB(e,t){if(t!==void 0){if(typeof t!="boolean")throw bt(e,"of type boolean",t);return t}}function e1e(e,t){if(t!==void 0){if(t===null||typeof t!="object"||typeof t.aborted!="boolean"||typeof t.addEventListener!="function"||typeof t.removeEventListener!="function"){let r=new TypeError(`The "${e}" property must be an instance of AbortSignal. ${fV(t)}`);throw r.code="ERR_INVALID_ARG_TYPE",r}return t}}function t1e(e,t){let r;if(e==null)r={};else if(typeof e=="string"){if(!t)throw bt("options","of type object",e);I2(e),r={encoding:e}}else if(typeof e=="object")r=e;else throw bt("options",t?"one of type string or object":"of type object",e);PB("options.persistent",r.persistent),PB("options.recursive",r.recursive),ir(r);let n=e1e("options.signal",r.signal);return{persistent:r.persistent,recursive:r.recursive,encoding:r.encoding,signal:n}}function r1e(e,t,r){let n=Be(e),i=t,s=r;if(typeof t=="function"&&(i=void 0,s=t),s!==void 0&&typeof s!="function")throw bt("listener","of type function",s);return{path:n,listener:s,options:t1e(i,!0)}}function n1e(e,t,r){let n=Be(e),i={},s=r;if(typeof t=="function")s=t;else if(t==null)i={};else if(typeof t=="object")i=t;else throw bt("listener","of type function",t);if(typeof s!="function")throw bt("listener","of type function",s);if(PB("persistent",i.persistent),PB("bigint",i.bigint),i.interval!==void 0&&typeof i.interval!="number")throw bt("interval","of type number",i.interval);return{path:n,listener:s,options:{persistent:i.persistent,bigint:i.bigint,interval:i.interval}}}function i1e(){return new gu({mode:0,size:0,dev:0,ino:0,nlink:0,uid:0,gid:0,rdev:0,blksize:0,blocks:0,atimeMs:0,mtimeMs:0,ctimeMs:0,birthtimeMs:0})}function rY(e){try{let t=$.statSync(e);return{exists:!0,stats:t,signature:JSON.stringify({dev:t.dev,ino:t.ino,mode:t.mode,nlink:t.nlink,uid:t.uid,gid:t.gid,rdev:t.rdev,size:t.size,atimeMs:t.atimeMs,mtimeMs:t.mtimeMs,ctimeMs:t.ctimeMs,birthtimeMs:t.birthtimeMs})}}catch(t){if(t?.code==="ENOENT"||t?.code==="ENOTDIR")return{exists:!1,stats:i1e(),signature:"missing"};throw t}}function s1e(e,t){let r=e==="/"?"":e.split("/").filter(Boolean).pop()??"";return t==="buffer"?Tt.Buffer.from(r):r}function o1e(e,t){return e.exists!==t.exists?"rename":"change"}var a1e=50,A1e=5007,e0=new Map,lV=class{constructor(e,t){y(this,"_path");y(this,"_intervalMs");y(this,"_onChange");y(this,"_onClose");y(this,"_listeners");y(this,"_timer");y(this,"_closed");y(this,"_signal");y(this,"_handleAbort");y(this,"_snapshot");y(this,"_poll");this._path=e,this._intervalMs=t.interval,this._onChange=t.onChange,this._onClose=t.onClose,this._listeners=new Map,this._closed=!1,this._signal=t.signal,this._snapshot=rY(e),this._poll=()=>{if(this._closed)return;let r;try{r=rY(this._path)}catch(i){this.emit("error",i);return}if(r.signature===this._snapshot.signature)return;let n=this._snapshot;this._snapshot=r,this._onChange(r,n)},this._handleAbort=()=>{this.close()},this._timer=z2(this._poll,this._intervalMs),t.persistent===!1&&this._timer?.unref?.(),this._signal&&(this._signal.aborted?queueMicrotask(()=>this.close()):this._signal.addEventListener("abort",this._handleAbort,{once:!0}))}on(e,t){let r=this._listeners.get(e)??[];return r.push(t),this._listeners.set(e,r),this}addListener(e,t){return this.on(e,t)}once(e,t){let r=(...n)=>{this.removeListener(e,r),t(...n)};return r._originalListener=t,this.on(e,r)}off(e,t){return this.removeListener(e,t)}removeListener(e,t){let r=this._listeners.get(e);if(!r)return this;let n=r.findIndex(i=>i===t||i._originalListener===t);return n>=0&&r.splice(n,1),r.length===0&&this._listeners.delete(e),this}removeAllListeners(e){return e===void 0?this._listeners.clear():this._listeners.delete(e),this}emit(e,...t){let r=this._listeners.get(e);return r?.length?(r.slice().forEach(n=>n(...t)),!0):!1}ref(){return this._timer?.ref?.(),this}unref(){return this._timer?.unref?.(),this}close(){this._closed||(this._closed=!0,this._timer!==void 0&&(K2(this._timer),this._timer=void 0),this._signal&&this._signal.removeEventListener("abort",this._handleAbort),this._onClose?.(),this.emit("close"))}};function f1e(e,t){let r=e0.get(e)??new Set;r.add(t),e0.set(e,r)}function u1e(e,t){let r=e0.get(e);r&&(r.delete(t),r.size===0&&e0.delete(e))}function c1e(e,t){let r=s1e(e,t.encoding),n=new lV(e,{interval:a1e,persistent:t.persistent,signal:t.signal,onChange(i,s){n.emit("change",o1e(s,i),r)}});return n}function l1e(e,t,r){let n=new lV(e,{interval:t.interval??A1e,persistent:t.persistent,onChange(i,s){n.emit("change",i.stats,s.stats)},onClose(){u1e(e,n)}});return n.on("change",r),f1e(e,n),n}async function*h1e(e,t){let r=[],n=null,i=!1,s=null,o=$.watch(e,t,(a,A)=>{r.push({eventType:a,filename:A}),n?.(),n=null});o.on("close",()=>{i=!0,n?.(),n=null}),o.on("error",a=>{s=a,n?.(),n=null});try{for(;;){if(r.length>0){yield r.shift();continue}if(s)throw s;if(i)return;await new Promise(a=>{n=a})}}finally{o.close()}}function b2(e){return e==null||typeof e=="object"&&!Array.isArray(e)}function Rs(e){if(e==null||e===-1)return null;if(typeof e=="bigint")return Number(e);if(typeof e!="number"||!Number.isInteger(e))throw bt("position","an integer",e);return e}function OB(e,t,r){let n=t??0;if(typeof n!="number"||!Number.isInteger(n))throw bt("offset","an integer",n);if(n<0||n>e)throw Ro("offset",`>= 0 && <= ${e}`,n);let i=e-n,s=r??i;if(typeof s!="number"||!Number.isInteger(s))throw bt("length","an integer",s);if(s<0||s>2147483647)throw Ro("length",">= 0 && <= 2147483647",s);if(n+s>e)throw Ro("length",`>= 0 && <= ${e-n}`,s);return{offset:n,length:s}}function d1e(e,t,r,n){if(!oI(e))throw bt("buffer","an instance of Buffer, TypedArray, or DataView",e);if(r===void 0&&n===void 0&&b2(t)){let o=t??{},{offset:a,length:A}=OB(e.byteLength,o.offset,o.length);return{buffer:e,offset:a,length:A,position:Rs(o.position)}}let{offset:i,length:s}=OB(e.byteLength,t,r);return{buffer:e,offset:i,length:s,position:Rs(n)}}function nY(e,t,r,n){if(typeof e=="string"){if(r===void 0&&n===void 0&&b2(t)){let o=t??{},a=typeof o.encoding=="string"?o.encoding:void 0;return{buffer:e,offset:0,length:Tt.Buffer.byteLength(e,a),position:Rs(o.position),encoding:a}}if(t!=null&&typeof t!="number")throw bt("position","an integer",t);return{buffer:e,offset:0,length:Tt.Buffer.byteLength(e,typeof r=="string"?r:void 0),position:Rs(t),encoding:typeof r=="string"?r:void 0}}if(!oI(e))throw bt("buffer","a string, Buffer, TypedArray, or DataView",e);if(r===void 0&&n===void 0&&b2(t)){let o=t??{},{offset:a,length:A}=OB(e.byteLength,o.offset,o.length);return{buffer:e,offset:a,length:A,position:Rs(o.position)}}let{offset:i,length:s}=OB(e.byteLength,t,typeof r=="number"?r:void 0);return{buffer:e,offset:i,length:s,position:Rs(n)}}function ar(e){return Kr("fd",e)}function Km(e){if(!Array.isArray(e))throw bt("buffers","an ArrayBufferView[]",e);for(let t of e)if(!oI(t))throw bt("buffers","an ArrayBufferView[]",e);return e}function C2(e,t){if(e===void 0)return;if(e===null||typeof e!="object")throw bt("options.fs","an object",e);let r=e;for(let n of t)if(typeof r[n]!="function")throw $ve(`options.fs.${String(n)}`,r[n]);return r}function HB(e){if(e!==void 0)return e instanceof pu?e:Kr("fd",e)}function iY(e,t){if(e===null){if(t===void 0)throw bt("path","of type string or an instance of Buffer or URL",e);return null}if(typeof e=="string"||Tt.Buffer.isBuffer(e))return e;if(e instanceof URL){if(e.protocol==="file:")return e.pathname;throw bt("path","of type string or an instance of Buffer or URL",e)}throw bt("path","of type string or an instance of Buffer or URL",e)}function g1e(e){let t=e?.start,r=e?.end;if(t!==void 0&&typeof t!="number")throw bt("start","of type number",t);if(r!==void 0&&typeof r!="number")throw bt("end","of type number",r);let n=t,i=r;if(n!==void 0&&(!Number.isFinite(n)||n<0))throw Ro("start",">= 0",t);if(i!==void 0&&(!Number.isFinite(i)||i<0))throw Ro("end",">= 0",r);if(n!==void 0&&i!==void 0&&n>i)throw Ro("start",`<= "end" (here: ${i})`,n);let s=e?.highWaterMark??e?.bufferSize,o=typeof s=="number"&&Number.isFinite(s)&&s>0?Math.floor(s):65536;return{start:n,end:i,highWaterMark:o,autoClose:e?.autoClose!==!1}}var aI=class{constructor(e,t){y(this,"_options");y(this,"bytesRead",0);y(this,"path");y(this,"pending",!0);y(this,"readable",!0);y(this,"readableAborted",!1);y(this,"readableDidRead",!1);y(this,"readableEncoding",null);y(this,"readableEnded",!1);y(this,"readableFlowing",null);y(this,"readableHighWaterMark",65536);y(this,"readableLength",0);y(this,"readableObjectMode",!1);y(this,"destroyed",!1);y(this,"closed",!1);y(this,"errored",null);y(this,"fd",null);y(this,"autoClose",!0);y(this,"start");y(this,"end");y(this,"_listeners",new Map);y(this,"_started",!1);y(this,"_reading",!1);y(this,"_readScheduled",!1);y(this,"_opening",!1);y(this,"_remaining",null);y(this,"_position",null);y(this,"_fileHandle",null);y(this,"_streamFs");y(this,"_signal");y(this,"_handleCloseListener");this._options=t;let r=HB(t?.fd),i=g1e(t??{});if(this.path=e,this.start=i.start,this.end=i.end,this.autoClose=i.autoClose,this.readableHighWaterMark=i.highWaterMark,this.readableEncoding=t?.encoding??null,this._position=this.start??null,this._remaining=this.end!==void 0?this.end-(this.start??0)+1:null,this._signal=B2(t?.signal),r instanceof pu){if(t?.fs!==void 0){let s=new Error("The FileHandle with fs method is not implemented");throw s.code="ERR_METHOD_NOT_IMPLEMENTED",s}this._fileHandle=r,this.fd=r.fd,this.pending=!1,this._handleCloseListener=()=>{this.closed||(this.closed=!0,this.destroyed=!0,this.readable=!1,this.emit("close"))},this._fileHandle.on("close",this._handleCloseListener)}else this._streamFs=C2(t?.fs,["open","read","close"]),typeof r=="number"&&(this.fd=r,this.pending=!1);this._signal&&(this._signal.aborted?queueMicrotask(()=>{this._abort(this._signal?.reason)}):this._signal.addEventListener("abort",()=>{this._abort(this._signal?.reason)})),this.fd===null&&queueMicrotask(()=>{this._openIfNeeded()})}_emitOpen(e){this.fd=e,this.pending=!1,this.emit("open",e),(this._started||this.readableFlowing)&&this._scheduleRead()}async _openIfNeeded(){if(this.fd!==null||this._opening||this.destroyed||this.closed)return;let e=typeof this.path=="string"?this.path:this.path instanceof Tt.Buffer?this.path.toString():null;if(!e){this._handleStreamError(Ve("EBADF","EBADF: bad file descriptor","read"));return}this._opening=!0,(this._streamFs?.open??$.open).bind(this._streamFs??$)(e,"r",438,(r,n)=>{if(this._opening=!1,r||typeof n!="number"){this._handleStreamError(r??Ve("EBADF","EBADF: bad file descriptor","open"));return}this._emitOpen(n)})}async _closeUnderlying(){if(this._fileHandle){this._fileHandle.closed||await this._fileHandle.close();return}if(this.fd!==null&&this.fd>=0){let e=this.fd,t=(this._streamFs?.close??$.close).bind(this._streamFs??$);await new Promise(r=>{t(e,()=>r())}),this.fd=-1}}_scheduleRead(){this._readScheduled||this._reading||this.readableFlowing===!1||this.destroyed||this.closed||(this._readScheduled=!0,queueMicrotask(()=>{this._readScheduled=!1,this._readNextChunk()}))}async _readNextChunk(){if(this._reading||this.destroyed||this.closed||this.readableFlowing===!1)return;if(Dg(this._signal),this.fd===null){await this._openIfNeeded();return}if(this._remaining===0){await this._finishReadable();return}let e=this._remaining===null?this.readableHighWaterMark:Math.min(this.readableHighWaterMark,this._remaining),t=Tt.Buffer.alloc(e);this._reading=!0;let r=async(i,s=0)=>{if(this._reading=!1,i){this._handleStreamError(i);return}if(s===0){await this._finishReadable();return}this.bytesRead+=s,this.readableDidRead=!0,typeof this._position=="number"&&(this._position+=s),this._remaining!==null&&(this._remaining-=s);let o=t.subarray(0,s);if(this.emit("data",this.readableEncoding?o.toString(this.readableEncoding):Tt.Buffer.from(o)),this._remaining===0){await this._finishReadable();return}this._scheduleRead()};if(this._fileHandle){try{let i=await this._fileHandle.read(t,0,e,this._position);await r(null,i.bytesRead)}catch(i){await r(i)}return}(this._streamFs?.read??$.read).bind(this._streamFs??$)(this.fd,t,0,e,this._position,(i,s)=>{r(i,s??0)})}async _finishReadable(){this.readableEnded||(this.readable=!1,this.readableEnded=!0,this.emit("end"),this.autoClose&&this.destroy())}_handleStreamError(e){this.closed||(this.errored=e,this.emit("error",e),this.autoClose?this.destroy():this.readable=!1)}async _abort(e){if(!(this.closed||this.destroyed)){if(this.readableAborted=!0,this.errored=AV(e),this.emit("error",this.errored),this._fileHandle){this.destroyed=!0,this.readable=!1,this.closed=!0,this.emit("close");return}if(this.autoClose){this.destroy();return}this.closed=!0,this.emit("close")}}async _readAllContent(){let e=[],t=0,r=this.readableFlowing;for(this.readableFlowing=!1;this._remaining!==0&&(this.fd===null&&await this._openIfNeeded(),this.fd!==null);){let n=this._remaining===null?m2:Math.min(m2,this._remaining),i=Tt.Buffer.alloc(n),s=0;if(this._fileHandle?s=(await this._fileHandle.read(i,0,n,this._position)).bytesRead:s=$.readSync(this.fd,i,0,n,this._position),s===0)break;let o=i.subarray(0,s);e.push(o),t+=s,typeof this._position=="number"&&(this._position+=s),this._remaining!==null&&(this._remaining-=s)}return this.readableFlowing=r,Tt.Buffer.concat(e,t)}on(e,t){let r=this._listeners.get(e)??[];return r.push(t),this._listeners.set(e,r),e==="data"&&(this._started=!0,this.readableFlowing!==!1&&(this.readableFlowing=!0,this._scheduleRead())),this}once(e,t){let r=(...n)=>{this.off(e,r),t(...n)};return r._originalListener=t,this.on(e,r)}off(e,t){let r=this._listeners.get(e);if(!r)return this;let n=r.findIndex(i=>i===t||i._originalListener===t);return n>=0&&r.splice(n,1),this}removeListener(e,t){return this.off(e,t)}removeAllListeners(e){return e===void 0?this._listeners.clear():this._listeners.delete(e),this}emit(e,...t){let r=this._listeners.get(e);return r?.length?(r.slice().forEach(n=>n(...t)),!0):!1}read(){return null}pipe(e,t){return this.on("data",r=>{e.write(r)}),this.on("end",()=>{e.end?.()}),this.resume(),e}unpipe(e){return this}pause(){return this.readableFlowing=!1,this}resume(){return this._started=!0,this.readableFlowing=!0,this._scheduleRead(),this}setEncoding(e){return this.readableEncoding=e,this}destroy(e){return this.destroyed?this:(this.destroyed=!0,this.readable=!1,e&&(this.errored=e,this.emit("error",e)),queueMicrotask(()=>{this._closeUnderlying().then(()=>{this.closed||(this.closed=!0,this.emit("close"))})}),this)}close(e){this.destroy(),e&&queueMicrotask(()=>e(null))}async*[Symbol.asyncIterator](){let e=await this._readAllContent();yield this.readableEncoding?e.toString(this.readableEncoding):e}},sY=16*1024*1024,AI=class{constructor(e,t){y(this,"_options");y(this,"bytesWritten",0);y(this,"path");y(this,"pending",!1);y(this,"writable",!0);y(this,"writableAborted",!1);y(this,"writableEnded",!1);y(this,"writableFinished",!1);y(this,"writableHighWaterMark",16384);y(this,"writableLength",0);y(this,"writableObjectMode",!1);y(this,"writableCorked",0);y(this,"destroyed",!1);y(this,"closed",!1);y(this,"errored",null);y(this,"writableNeedDrain",!1);y(this,"fd",null);y(this,"autoClose",!0);y(this,"_chunks",[]);y(this,"_listeners",new Map);y(this,"_fileHandle",null);y(this,"_streamFs");y(this,"_position",null);this._options=t;let r=HB(t?.fd),n=t?.start,i=t?.highWaterMark??t?.bufferSize,s=t?.flags??"w";if(this.path=e,this.autoClose=t?.autoClose!==!1,this.writableHighWaterMark=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):16384,this._position=typeof n=="number"?n:null,this._streamFs=C2(t?.fs,["open","close","write"]),t?.fs!==void 0&&C2(t?.fs,["writev"]),r instanceof pu){this._fileHandle=r,this.fd=r.fd;return}if(typeof r=="number"){this.fd=r;return}let o=typeof this.path=="string"?this.path:this.path instanceof Tt.Buffer?this.path.toString():null;if(!o)throw Ve("EBADF","EBADF: bad file descriptor","write");this.fd=$.openSync(o,s,t?.mode),queueMicrotask(()=>{this.fd!==null&&this.fd>=0&&this.emit("open",this.fd)})}async _closeUnderlying(){if(this._fileHandle){this._fileHandle.closed||await this._fileHandle.close();return}if(this.fd!==null&&this.fd>=0){let e=this.fd,t=(this._streamFs?.close??$.close).bind(this._streamFs??$);await new Promise(r=>{t(e,()=>r())}),this.fd=-1}}close(e){queueMicrotask(()=>{this._closeUnderlying().then(()=>{this.closed||(this.closed=!0,this.writable=!1,this.emit("close")),e?.(null)})})}write(e,t,r){if(this.writableEnded||this.destroyed){let s=new Error("write after end"),o=typeof t=="function"?t:r;return queueMicrotask(()=>o?.(s)),!1}let n;if(typeof e=="string")n=Tt.Buffer.from(e,typeof t=="string"?t:"utf8");else if(oI(e))n=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);else throw bt("chunk","a string, Buffer, TypedArray, or DataView",e);if(this.writableLength+n.length>sY){let s=new Error(`WriteStream buffer exceeded ${sY} bytes`);this.errored=s,this.destroyed=!0,this.writable=!1;let o=typeof t=="function"?t:r;return queueMicrotask(()=>{o?.(s),this.emit("error",s)}),!1}this._chunks.push(n),this.bytesWritten+=n.length,this.writableLength+=n.length;let i=typeof t=="function"?t:r;return queueMicrotask(()=>i?.(null)),!0}end(e,t,r){if(this.writableEnded)return this;let n;return typeof e=="function"?n=e:typeof t=="function"?(n=t,e!=null&&this.write(e)):(n=r,e!=null&&this.write(e,t)),this.writableEnded=!0,this.writable=!1,this.writableFinished=!0,this.writableLength=0,queueMicrotask(()=>{(async()=>{try{if(this._fileHandle){for(let i of this._chunks){let s=await this._fileHandle.write(i,0,i.byteLength,this._position);typeof this._position=="number"&&(this._position+=s?.bytesWritten??i.byteLength)}this.autoClose&&!this._fileHandle.closed&&await this._fileHandle.close()}else{let i=typeof this.path=="string"?this.path:this.path instanceof Tt.Buffer?this.path.toString():null;if(this.fd!==null&&this.fd>=0){let s=$.writevSync(this.fd,this._chunks,this._position);typeof this._position=="number"&&(this._position+=s),this.autoClose&&await this._closeUnderlying()}else if(i){let s=this._chunks.map(o=>Tt.Buffer.from(o));if(typeof this._position=="number"){let o=$.readFileSync(i),a=Math.max(o.length,this._position+s.reduce((l,p)=>l+p.length,0)),A=Tt.Buffer.alloc(a);o.copy(A);let f=this._position;for(let l of s)l.copy(A,f),f+=l.length;$.writeFileSync(i,A)}else $.writeFileSync(i,Tt.Buffer.concat(s));this.autoClose&&this.fd!==null&&this.fd>=0&&await this._closeUnderlying()}else throw Ve("EBADF","EBADF: bad file descriptor","write")}this.emit("finish"),this.autoClose&&!this.closed&&(this.closed=!0,this.emit("close")),n?.()}catch(i){this.errored=i,this.emit("error",i)}})()}),this}setDefaultEncoding(e){return this}cork(){this.writableCorked++}uncork(){this.writableCorked>0&&this.writableCorked--}destroy(e){return this.destroyed?this:(this.destroyed=!0,this.writable=!1,e&&(this.errored=e,this.emit("error",e)),queueMicrotask(()=>{this._closeUnderlying().then(()=>{this.closed||(this.closed=!0,this.emit("close"))})}),this)}addListener(e,t){return this.on(e,t)}on(e,t){let r=this._listeners.get(e)??[];return r.push(t),this._listeners.set(e,r),this}once(e,t){let r=(...n)=>{this.removeListener(e,r),t(...n)};return this.on(e,r)}removeListener(e,t){let r=this._listeners.get(e);if(!r)return this;let n=r.indexOf(t);return n>=0&&r.splice(n,1),this}off(e,t){return this.removeListener(e,t)}removeAllListeners(e){return e===void 0?this._listeners.clear():this._listeners.delete(e),this}emit(e,...t){let r=this._listeners.get(e);return r?.length?(r.slice().forEach(n=>n(...t)),!0):!1}pipe(e,t){return e}unpipe(e){return this}[Symbol.asyncDispose](){return Promise.resolve()}},p1e=aI,E1e=AI,hV=function(t,r){return ir(r),new p1e(t,r)};hV.prototype=aI.prototype;var dV=function(t,r){return ir(r),cV(r??{}),new E1e(t,r)};dV.prototype=AI.prototype;function y1e(e){if(typeof e=="number")return e;let t={r:y2,"r+":ma,rs:y2,"rs+":ma,w:au|qn|Au,"w+":ma|qn|Au,a:au|fu|qn,"a+":ma|fu|qn,wx:au|qn|Au|Ba,xw:au|qn|Au|Ba,"wx+":ma|qn|Au|Ba,"xw+":ma|qn|Au|Ba,ax:au|fu|qn|Ba,xa:au|fu|qn|Ba,"ax+":ma|fu|qn|Ba,"xa+":ma|fu|qn|Ba};if(e in t)return t[e];throw new Error("Unknown file flag: "+e)}var oY={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENAMETOOLONG:36,ENOSYS:38,ENOTEMPTY:39,ELOOP:40,EOVERFLOW:75,ENOTSOCK:88,EDESTADDRREQ:89,EMSGSIZE:90,EPROTOTYPE:91,ENOPROTOOPT:92,EPROTONOSUPPORT:93,ENOTSUP:95,EOPNOTSUPP:95,EAFNOSUPPORT:97,EADDRINUSE:98,EADDRNOTAVAIL:99,ENETDOWN:100,ENETUNREACH:101,ECONNABORTED:103,ECONNRESET:104,ENOBUFS:105,EISCONN:106,ENOTCONN:107,ETIMEDOUT:110,ECONNREFUSED:111,EHOSTUNREACH:113,EALREADY:114,EINPROGRESS:115};function m1e(e){return Object.prototype.hasOwnProperty.call(oY,e)?-oY[e]:-1}function Ve(e,t,r,n){let i=new Error(t);return i.code=e,i.errno=m1e(e),i.syscall=r,n&&(i.path=n),i}function B1e(e){return String(e?.message??e??"")}function Vi(e){let t=B1e(e);return t.includes("ENOENT")||t.includes("entry not found")||t.includes("no such file or directory")||t.includes("not found")?"ENOENT":t.includes("EROFS")||t.includes("read-only file system")?"EROFS":t.includes("ERR_ACCESS_DENIED")?"ERR_ACCESS_DENIED":t.includes("EACCES")||t.includes("permission denied")?"EACCES":t.includes("EEXIST")||t.includes("file already exists")?"EEXIST":t.includes("EINVAL")||t.includes("invalid argument")?"EINVAL":t.includes("EXDEV")||t.includes("cross-device link")?"EXDEV":typeof e?.code=="string"&&e.code.length>0?e.code:null}function Hi(e,t,r){try{return e()}catch(n){let i=Vi(n);throw i==="ENOENT"?Ve("ENOENT",`ENOENT: no such file or directory, ${t} '${r}'`,t,r):i==="EACCES"?Ve("EACCES",`EACCES: permission denied, ${t} '${r}'`,t,r):i==="EEXIST"?Ve("EEXIST",`EEXIST: file already exists, ${t} '${r}'`,t,r):i==="EINVAL"?Ve("EINVAL",`EINVAL: invalid argument, ${t} '${r}'`,t,r):i==="EXDEV"?Ve("EXDEV",`EXDEV: cross-device link not permitted, ${t} '${r}'`,t,r):n}}function I1e(e){let t="",r=0;for(;ro.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,"[^/]*")).join("|")+")",r=i+1}else t+="\\{",r++}else if(n==="["){let i=e.indexOf("]",r);i!==-1?(t+=e.slice(r,i+1),r=i+1):(t+="\\[",r++)}else".+^${}()|[]\\".includes(n)?(t+="\\"+n,r++):(t+=n,r++)}return new RegExp("^"+t+"$")}function b1e(e){let t=e.split("/"),r=[];for(let n of t){if(/[*?{}\[\]]/.test(n))break;r.push(n)}return r.join("/")||"/"}var C1e=100;function Q1e(e,t){let r=I1e(e),n=b1e(e),i=(s,o)=>{if(o>C1e)return;let a;try{a=gV(s)}catch{return}for(let A of a){let f=s==="/"?"/"+A:s+"/"+A;r.test(f)&&t.push(f);try{Q2(f).isDirectory()&&i(f,o+1)}catch{}}};try{if(r.test(n)&&!Q2(n).isDirectory()){t.push(n);return}i(n,0)}catch{}}var gV,Q2;function S1(e){return Be(e)}function qB(e){return typeof globalThis<"u"?globalThis[e]:void 0}function Ce(e){return{applySync(t,r){let n=qB(e);if(typeof n=="function")return n(...r||[]);if(n&&typeof n.applySync=="function")return n.applySync(t,r)},applySyncPromise(t,r){let n=qB(e);if(typeof n=="function")return n(...r||[]);if(n&&typeof n.applySync=="function")return n.applySync(t,r);if(n&&typeof n.applySyncPromise=="function")return n.applySyncPromise(t,r)}}}function Tg(e){let t=qB(e);return typeof t=="function"||!!(t&&(typeof t.applySync=="function"||typeof t.applySyncPromise=="function"))}function Cr(e){return{apply(t,r){let n=qB(e);return typeof n=="function"?n(...r||[]):n&&typeof n.apply=="function"?n.apply(t,r):Promise.resolve(void 0)}}}var Lt={readFile:Ce("_fsReadFile"),writeFile:Ce("_fsWriteFile"),readFileBinary:Ce("_fsReadFileBinary"),writeFileBinary:Ce("_fsWriteFileBinary"),writeFileBinaryRaw:Ce("_fsWriteFileBinaryRaw"),readDir:Ce("_fsReadDir"),mkdir:Ce("_fsMkdir"),rmdir:Ce("_fsRmdir"),exists:Ce("_fsExists"),stat:Ce("_fsStat"),unlink:Ce("_fsUnlink"),rename:Ce("_fsRename"),chmod:Ce("_fsChmod"),chown:Ce("_fsChown"),link:Ce("_fsLink"),symlink:Ce("_fsSymlink"),readlink:Ce("_fsReadlink"),lstat:Ce("_fsLstat"),truncate:Ce("_fsTruncate"),utimes:Ce("_fsUtimes"),lutimes:Ce("_fsLutimes")},Er={readFile:Cr("_fsReadFileAsync"),writeFile:Cr("_fsWriteFileAsync"),readFileBinary:Cr("_fsReadFileBinaryAsync"),writeFileBinary:Cr("_fsWriteFileBinaryAsync"),readDir:Cr("_fsReadDirAsync"),mkdir:Cr("_fsMkdirAsync"),rmdir:Cr("_fsRmdirAsync"),stat:Cr("_fsStatAsync"),unlink:Cr("_fsUnlinkAsync"),rename:Cr("_fsRenameAsync"),chmod:Cr("_fsChmodAsync"),chown:Cr("_fsChownAsync"),link:Cr("_fsLinkAsync"),symlink:Cr("_fsSymlinkAsync"),readlink:Cr("_fsReadlinkAsync"),lstat:Cr("_fsLstatAsync"),truncate:Cr("_fsTruncateAsync"),utimes:Cr("_fsUtimesAsync"),lutimes:Cr("_fsLutimesAsync"),access:Cr("_fsAccessAsync")},w1e=Ce("fs.openSync"),pV=Ce("fs.closeSync"),S1e=Ce("fs.readSync"),_1e=Ce("_fsReadRaw"),v1e=Ce("fs.writeSync"),R1e=Ce("_fsWriteRaw"),D1e=Ce("_fsWritevRaw"),T1e=Ce("fs.fstatSync"),N1e=Ce("fs.ftruncateSync"),aY=Ce("fs.fsyncSync"),M1e=Ce("fs.futimesSync"),xA=Ce("fs._getPathSync"),F1e=Ce("process.umask"),k1e=Ce("process.memoryUsage"),x1e=Ce("process.cpuUsage"),U1e=Ce("process.resourceUsage"),L1e=Ce("process.versions"),Qke=Ce("_kernelPollRaw"),wke=Ce("_kernelIsattyRaw"),Ske=Ce("_kernelTtySizeRaw");function Ma(e){return typeof e=="string"?JSON.parse(e):e}function t0(e){return{__agentOSType:"bytes",base64:Tt.Buffer.from(e).toString("base64")}}function hB(e,t,r){let n=Vi(e);if(n==="ENOENT")throw Ve("ENOENT",`ENOENT: no such file or directory, ${t} '${r}'`,t,r);if(n==="EROFS")throw Ve("EROFS",`EROFS: read-only file system, ${t} '${r}'`,t,r);if(n==="ERR_ACCESS_DENIED"){let i=Ve("ERR_ACCESS_DENIED",`ERR_ACCESS_DENIED: permission denied, ${t} '${r}'`,t,r);throw i.code="ERR_ACCESS_DENIED",i}throw n==="EACCES"?Ve("EACCES",`EACCES: permission denied, ${t} '${r}'`,t,r):e}function P1e(e,t){return e==="/"?`/${t}`:e.endsWith("/")?`${e}${t}`:`${e}/${t}`}function QR(e,t,r){return Array.isArray(e)?r?e.map(n=>{if(typeof n=="string"){let i=$.statSync(P1e(t,n));return new LB(n,i.isDirectory(),t)}return new LB(n.name,n.isDirectory,t)}):e.map(n=>typeof n=="string"?n:n?.name):[]}function O1e(e,t,r){if(!(e instanceof Uint8Array))return QR(e,t,r);let n=[],i=0;for(;ie.byteLength)throw new Error("Invalid raw readdir payload");let s=e[i++],o=e[i]|e[i+1]<<8|e[i+2]<<16|e[i+3]<<24;if(i+=4,o<0||i+o>e.byteLength)throw new Error("Invalid raw readdir entry");let a=Tt.Buffer.from(e.buffer,e.byteOffset+i,o).toString("utf8");i+=o,n.push(r?new LB(a,s===1,t):a)}return n}async function _1(e,t){ir(t);let r=typeof e=="number"?xA.applySync(void 0,[ar(e)]):Be(e);if(!r)throw Ve("EBADF","EBADF: bad file descriptor","read");let n=r,i=typeof t=="string"?t:t?.encoding;try{if(i)return await Er.readFile.apply(void 0,[n,i]);let s=await Er.readFileBinary.apply(void 0,[n]);return Tt.Buffer.from(s,"base64")}catch(s){throw Vi(s)==="ENOENT"?Ve("ENOENT",`ENOENT: no such file or directory, open '${r}'`,"open",r):Vi(s)==="EACCES"?Ve("EACCES",`EACCES: permission denied, open '${r}'`,"open",r):s}}async function v1(e,t,r){ir(r);let n=typeof e=="number"?xA.applySync(void 0,[ar(e)]):Be(e);if(!n)throw Ve("EBADF","EBADF: bad file descriptor","write");let i=n;try{if(typeof t=="string")return await Er.writeFile.apply(void 0,[i,t]);if(ArrayBuffer.isView(t)){let s=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return Tg("_fsWriteFileBinaryRaw")?Lt.writeFileBinaryRaw.applySyncPromise(void 0,[i,s]):await Er.writeFileBinary.apply(void 0,[i,t0(s)])}return await Er.writeFile.apply(void 0,[i,String(t)])}catch(s){hB(s,"write",n)}}async function H1e(e,t){ir(t);let r=Be(e);try{let n=await Er.readDir.apply(void 0,[r]);return QR(Ma(n),r,t?.withFileTypes)}catch(n){throw Vi(n)==="ENOENT"?Ve("ENOENT",`ENOENT: no such file or directory, scandir '${r}'`,"scandir",r):n}}async function q1e(e,t){let r=Be(e),n=typeof t=="object"?t?.recursive??!1:!1;return await Er.mkdir.apply(void 0,[r,n]),n?r:void 0}async function G1e(e){let t=Be(e);await Er.rmdir.apply(void 0,[t])}async function Y1e(e){let t=Be(e);try{let r=await Er.stat.apply(void 0,[t]);return new gu(Ma(r))}catch(r){throw Vi(r)==="ENOENT"?Ve("ENOENT",`ENOENT: no such file or directory, stat '${t}'`,"stat",t):r}}async function W1e(e){let t=Be(e),r=await Er.lstat.apply(void 0,[t]);return new gu(Ma(r))}async function V1e(e){let t=Be(e);await Er.unlink.apply(void 0,[t])}async function J1e(e,t){let r=Be(e,"oldPath"),n=Be(t,"newPath");await Er.rename.apply(void 0,[r,n])}async function j1e(e){let t=Be(e);try{await Er.access.apply(void 0,[t])}catch(r){throw Vi(r)==="ENOENT"?Ve("ENOENT",`ENOENT: no such file or directory, access '${t}'`,"access",t):r}}async function z1e(e,t){let r=Be(e),n=Sa(t,"mode");await Er.chmod.apply(void 0,[r,n])}async function K1e(e,t,r){let n=Be(e),i=Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),s=Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});await Er.chown.apply(void 0,[n,i,s])}async function X1e(e,t){let r=Be(e,"existingPath"),n=Be(t,"newPath");await Er.link.apply(void 0,[r,n])}async function Z1e(e,t){let r=Be(e,"target"),n=Be(t);await Er.symlink.apply(void 0,[r,n])}async function $1e(e){let t=Be(e);return await Er.readlink.apply(void 0,[t])}async function e2e(e,t){let r=Be(e);await Er.truncate.apply(void 0,[r,t??0])}function _o(e,t){if(e&&typeof e=="object"&&!(e instanceof Date)){let o=typeof e.kind=="string"?e.kind:null;if(o==="now"||o==="UTIME_NOW")return{kind:"now"};if(o==="omit"||o==="UTIME_OMIT")return{kind:"omit"};if("nsec"in e){if(e.nsec===$.constants.UTIME_NOW||e.nsec==="UTIME_NOW")return{kind:"now"};if(e.nsec===$.constants.UTIME_OMIT||e.nsec==="UTIME_OMIT")return{kind:"omit"}}let a=Number(e.sec),A=Number(e.nsec??0);if(!Number.isInteger(a))throw bt(t,"an integer sec field",e);if(!Number.isInteger(A)||A<0||A>=1e9)throw createRangeError(`${t}.nsec must be an integer between 0 and 999999999`);return{sec:a,nsec:A}}let r=typeof e=="number"?e:new Date(e).getTime()/1e3;if(!Number.isFinite(r))throw createRangeError(`${t} must be a finite timestamp`);let n=Math.floor(r),i=n,s=Math.round((r-n)*1e9);return s>=1e9&&(i+=1,s-=1e9),{sec:i,nsec:s}}async function t2e(e,t,r){let n=Be(e);await Er.utimes.apply(void 0,[n,_o(t,"atime"),_o(r,"mtime")])}async function r2e(e,t,r){let n=Be(e);await Er.lutimes.apply(void 0,[n,_o(t,"atime"),_o(r,"mtime")])}function n2e(e){let t=4;for(let s of e){if(s.byteLength>4294967295)throw Ro("buffer.byteLength","<= 4294967295",s.byteLength);t+=4+s.byteLength}let r=new Uint8Array(t),n=new DataView(r.buffer,r.byteOffset,r.byteLength);n.setUint32(0,e.length,!0);let i=4;for(let s of e){let o=s instanceof Uint8Array?s:new Uint8Array(s.buffer,s.byteOffset,s.byteLength);n.setUint32(i,o.byteLength,!0),i+=4,r.set(o,i),i+=o.byteLength}return r}var $={constants:{F_OK:0,R_OK:4,W_OK:2,X_OK:1,COPYFILE_EXCL:1,COPYFILE_FICLONE:2,COPYFILE_FICLONE_FORCE:4,O_RDONLY:y2,O_WRONLY:au,O_RDWR:ma,O_CREAT:qn,O_EXCL:Ba,O_NOCTTY:256,O_TRUNC:Au,O_APPEND:fu,O_DIRECTORY:65536,O_NOATIME:262144,O_NOFOLLOW:131072,O_SYNC:1052672,O_DSYNC:4096,O_SYMLINK:2097152,O_DIRECT:16384,O_NONBLOCK:2048,UTIME_NOW:1073741823,UTIME_OMIT:1073741822,S_IFMT:61440,S_IFREG:32768,S_IFDIR:16384,S_IFCHR:8192,S_IFBLK:24576,S_IFIFO:4096,S_IFLNK:40960,S_IFSOCK:49152,S_IRWXU:448,S_IRUSR:256,S_IWUSR:128,S_IXUSR:64,S_IRWXG:56,S_IRGRP:32,S_IWGRP:16,S_IXGRP:8,S_IRWXO:7,S_IROTH:4,S_IWOTH:2,S_IXOTH:1,UV_FS_O_FILEMAP:536870912},Stats:gu,Dirent:LB,Dir:ZG,readFileSync(e,t){ir(t);let r=typeof e=="number"?xA.applySync(void 0,[ar(e)]):Be(e);if(!r)throw Ve("EBADF","EBADF: bad file descriptor","read");let n=r,i=typeof t=="string"?t:t?.encoding;try{if(i)return Lt.readFile.applySyncPromise(void 0,[n,i]);{let s=Lt.readFileBinary.applySyncPromise(void 0,[n]);return Tt.Buffer.from(s,"base64")}}catch(s){throw Vi(s)==="ENOENT"?Ve("ENOENT",`ENOENT: no such file or directory, open '${r}'`,"open",r):Vi(s)==="EACCES"?Ve("EACCES",`EACCES: permission denied, open '${r}'`,"open",r):s}},writeFileSync(e,t,r){ir(r);let n=typeof e=="number"?xA.applySync(void 0,[ar(e)]):Be(e);if(!n)throw Ve("EBADF","EBADF: bad file descriptor","write");let i=n;try{if(typeof t=="string")return Lt.writeFile.applySyncPromise(void 0,[i,t]);if(ArrayBuffer.isView(t)){let s=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return Tg("_fsWriteFileBinaryRaw")?Lt.writeFileBinaryRaw.applySyncPromise(void 0,[i,s]):Lt.writeFileBinary.applySyncPromise(void 0,[i,t0(s)])}else return Lt.writeFile.applySyncPromise(void 0,[i,String(t)])}catch(s){hB(s,"write",n)}},appendFileSync(e,t,r){ir(r);let n=Be(e),i="";try{i=$.existsSync(e)?$.readFileSync(e,"utf8"):""}catch(o){hB(o,"open",n)}let s=typeof t=="string"?t:String(t);try{$.writeFileSync(e,i+s,r)}catch(o){if(!o?.code)throw Ve("EACCES",`EACCES: permission denied, write '${n}'`,"write",n);hB(o,"write",n)}},readdirSync(e,t){ir(t);let r=Be(e),n=r,i;try{i=Lt.readDir.applySyncPromise(void 0,[n])}catch(s){throw Vi(s)==="ENOENT"?Ve("ENOENT",`ENOENT: no such file or directory, scandir '${r}'`,"scandir",r):s}return i instanceof Uint8Array?O1e(i,r,t?.withFileTypes):QR(Ma(i),r,t?.withFileTypes)},mkdirSync(e,t){let r=Be(e),n=r,i=typeof t=="object"?t?.recursive??!1:!1,s=typeof t=="object"?t?.mode:t,o=s===void 0?void 0:Sa(s);return Lt.mkdir.applySyncPromise(void 0,[n,{recursive:i,mode:w1(o??511)}]),i?r:void 0},rmdirSync(e,t){let r=Be(e);Lt.rmdir.applySyncPromise(void 0,[r])},rmSync(e,t){let r=S1(e),n=t||{};try{if($.statSync(r).isDirectory())if(n.recursive){let s=$.readdirSync(r);for(let o of s){let a=r.endsWith("/")?r+o:r+"/"+o;$.statSync(a).isDirectory()?$.rmSync(a,{recursive:!0}):$.unlinkSync(a)}$.rmdirSync(r)}else $.rmdirSync(r);else $.unlinkSync(r)}catch(i){if(n.force&&i.code==="ENOENT")return;throw i}},existsSync(e){let t=eY(e);return t?t==="/dev/null"||t==="/dev/zero"||t==="/dev/urandom"||t==="/dev/stdin"||t==="/dev/stdout"||t==="/dev/stderr"?!0:Lt.exists.applySyncPromise(void 0,[t]):!1},statSync(e,t){let r=Be(e),n=r,i;try{i=Lt.stat.applySyncPromise(void 0,[n])}catch(o){throw Vi(o)==="ENOENT"?Ve("ENOENT",`ENOENT: no such file or directory, stat '${r}'`,"stat",r):o}let s=Ma(i);return new gu(s)},lstatSync(e,t){let r=Be(e),n=Hi(()=>Lt.lstat.applySyncPromise(void 0,[r]),"lstat",r),i=Ma(n);return new gu(i)},unlinkSync(e){let t=Be(e);Lt.unlink.applySyncPromise(void 0,[t])},renameSync(e,t){let r=Be(e,"oldPath"),n=Be(t,"newPath");Lt.rename.applySyncPromise(void 0,[r,n])},copyFileSync(e,t,r){let n=$.readFileSync(e);$.writeFileSync(t,n)},cpSync(e,t,r){let n=S1(e),i=S1(t),s=r||{};if($.statSync(n).isDirectory()){if(!s.recursive)throw Ve("ERR_FS_EISDIR",`Path is a directory: cp '${n}'`,"cp",n);try{$.mkdirSync(i,{recursive:!0})}catch{}let a=$.readdirSync(n);for(let A of a){let f=n.endsWith("/")?n+A:n+"/"+A,l=i.endsWith("/")?i+A:i+"/"+A;$.cpSync(f,l,s)}}else{if(s.errorOnExist&&$.existsSync(i))throw Ve("EEXIST",`EEXIST: file already exists, cp '${n}' -> '${i}'`,"cp",i);if(!s.force&&s.force!==void 0&&$.existsSync(i))return;$.copyFileSync(n,i)}},mkdtempSync(e,t){ir(t);let r=Be(e,"prefix"),n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let i=0;i<10;i+=1){let s=Ra.randomBytes(6),o="";for(let A of s)o+=n[A%n.length];let a=r+o;try{return Hi(()=>Lt.mkdir.applySyncPromise(void 0,[a,{recursive:!1,mode:w1(511)}]),"mkdir",a),a}catch(A){if(i<9&&(A?.code==="EEXIST"||Vi(A)==="EEXIST"))continue;throw A}}throw Ve("EEXIST",`EEXIST: file already exists, mkdtemp '${r}'`,"mkdtemp",r)},opendirSync(e,t){let r=Be(e);if(!$.statSync(r).isDirectory())throw Ve("ENOTDIR",`ENOTDIR: not a directory, opendir '${r}'`,"opendir",r);return new ZG(r)},openSync(e,t,r){let n=Be(e),i=y1e(t??"r"),s=tY(r),o=i&qn?w1(s??438):s;try{return w1e.applySyncPromise(void 0,[n,i,o])}catch(a){let A=a?.message??String(a);throw A.includes("ENOENT")?Ve("ENOENT",A,"open",n):A.includes("EMFILE")?Ve("EMFILE",A,"open",n):a}},closeSync(e){if(ar(e),!l2e(e))try{pV.applySyncPromise(void 0,[e])}catch(t){throw(t?.message??String(t)).includes("EBADF")?Ve("EBADF","EBADF: bad file descriptor, close","close"):t}},readSync(e,t,r,n,i){let s=d1e(t,r,n,i),o;try{if(Tg("_fsReadRaw")){let f=_1e.applySyncPromise(void 0,[e,s.length,s.position??null]);o=f instanceof Uint8Array?f:Tt.Buffer.from(f)}else{let f=S1e.applySyncPromise(void 0,[e,s.length,s.position??null]);o=Tt.Buffer.from(f,"base64")}}catch(f){let l=f?.message??String(f);throw l.includes("EBADF")?Ve("EBADF",l,"read"):f}let a=new Uint8Array(s.buffer.buffer,s.buffer.byteOffset,s.buffer.byteLength),A=Math.min(o.length,s.length);return a.set(o.subarray(0,A),s.offset),A},writeSync(e,t,r,n,i){let s=nY(t,r,n,i),o;typeof s.buffer=="string"?o=Tt.Buffer.from(s.buffer,s.encoding):o=new Uint8Array(s.buffer.buffer,s.buffer.byteOffset+s.offset,s.length);let a=s.position??null;try{return Tg("_fsWriteRaw")?R1e.applySyncPromise(void 0,[e,o,a]):v1e.applySyncPromise(void 0,[e,t0(o),a])}catch(A){let f=A?.message??String(A);throw f.includes("EBADF")?Ve("EBADF",f,"write"):A}},fstatSync(e){ar(e);let t;try{t=T1e.applySyncPromise(void 0,[e])}catch(r){throw(r?.message??String(r)).includes("EBADF")?Ve("EBADF","EBADF: bad file descriptor, fstat","fstat"):r}return new gu(Ma(t))},ftruncateSync(e,t){ar(e);try{N1e.applySyncPromise(void 0,[e,t])}catch(r){throw(r?.message??String(r)).includes("EBADF")?Ve("EBADF","EBADF: bad file descriptor, ftruncate","ftruncate"):r}},fsyncSync(e){ar(e);try{aY.applySyncPromise(void 0,[e])}catch(t){throw(t?.message??String(t)).includes("EBADF")?Ve("EBADF","EBADF: bad file descriptor, fsync","fsync"):t}},fdatasyncSync(e){ar(e);try{aY.applySyncPromise(void 0,[e])}catch(t){throw(t?.message??String(t)).includes("EBADF")?Ve("EBADF","EBADF: bad file descriptor, fdatasync","fdatasync"):t}},readvSync(e,t,r){let n=ar(e),i=Km(t),s=0,a=Rs(r);for(let A of i){let f=A instanceof Uint8Array?A:new Uint8Array(A.buffer,A.byteOffset,A.byteLength),l=$.readSync(n,f,0,f.byteLength,a);if(s+=l,a!==null&&(a+=l),lLt.chmod.applySyncPromise(void 0,[r,n]),"chmod",r)},chownSync(e,t,r){let n=Be(e),i=Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),s=Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});Hi(()=>Lt.chown.applySyncPromise(void 0,[n,i,s]),"chown",n)},fchmodSync(e,t){let r=ar(e),n=xA.applySync(void 0,[r]);if(!n)throw Ve("EBADF","EBADF: bad file descriptor","chmod");$.chmodSync(n,Sa(t))},fchownSync(e,t,r){let n=ar(e),i=xA.applySync(void 0,[n]);if(!i)throw Ve("EBADF","EBADF: bad file descriptor","chown");$.chownSync(i,t,r)},lchownSync(e,t,r){let n=Be(e),i=Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),s=Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});Hi(()=>Lt.chown.applySyncPromise(void 0,[n,i,s]),"chown",n)},linkSync(e,t){let r=Be(e,"existingPath"),n=Be(t,"newPath");Hi(()=>Lt.link.applySyncPromise(void 0,[r,n]),"link",n)},symlinkSync(e,t,r){let n=Be(e,"target"),i=Be(t);Hi(()=>Lt.symlink.applySyncPromise(void 0,[n,i]),"symlink",i)},readlinkSync(e,t){ir(t);let r=Be(e);return Hi(()=>Lt.readlink.applySyncPromise(void 0,[r]),"readlink",r)},truncateSync(e,t){let r=Be(e);Hi(()=>Lt.truncate.applySyncPromise(void 0,[r,t??0]),"truncate",r)},utimesSync(e,t,r){let n=Be(e);Hi(()=>Lt.utimes.applySyncPromise(void 0,[n,_o(t,"atime"),_o(r,"mtime")]),"utimes",n)},lutimesSync(e,t,r){let n=Be(e);Hi(()=>Lt.lutimes.applySyncPromise(void 0,[n,_o(t,"atime"),_o(r,"mtime")]),"lutimes",n)},futimesSync(e,t,r){let n=ar(e);Hi(()=>M1e.applySyncPromise(void 0,[n,_o(t,"atime"),_o(r,"mtime")]),"futimes")},readFile(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r){Be(e),ir(t);try{r(null,$.readFileSync(e,t))}catch(n){r(n)}}else return Promise.resolve($.readFileSync(e,t))},writeFile(e,t,r,n){if(typeof r=="function"&&(n=r,r=void 0),n){Be(e),ir(r);try{$.writeFileSync(e,t,r),n(null)}catch(i){n(i)}}else return Promise.resolve($.writeFileSync(e,t,r))},appendFile(e,t,r,n){if(typeof r=="function"&&(n=r,r=void 0),n){Be(e),ir(r);try{$.appendFileSync(e,t,r),n(null)}catch(i){n(i)}}else return Promise.resolve($.appendFileSync(e,t,r))},readdir(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r){Be(e),ir(t);try{r(null,$.readdirSync(e,t))}catch(n){r(n)}}else return Promise.resolve($.readdirSync(e,t))},mkdir(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r){Be(e);try{$.mkdirSync(e,t),r(null)}catch(n){r(n)}}else return $.mkdirSync(e,t),Promise.resolve()},rmdir(e,t){if(t){Be(e);let r=t;try{$.rmdirSync(e),queueMicrotask(()=>r(null))}catch(n){queueMicrotask(()=>r(n))}}else return Promise.resolve($.rmdirSync(e))},rm(e,t,r){let n={},i;typeof t=="function"?i=t:(t&&(n=t),i=r);let s=()=>{try{if($.statSync(e).isDirectory())if(n.recursive){let a=$.readdirSync(e);for(let A of a){let f=e.endsWith("/")?e+A:e+"/"+A;$.statSync(f).isDirectory()?$.rmSync(f,{recursive:!0}):$.unlinkSync(f)}$.rmdirSync(e)}else $.rmdirSync(e);else $.unlinkSync(e)}catch(o){if(n.force&&o.code==="ENOENT")return;throw o}};if(i)try{s(),queueMicrotask(()=>i(null))}catch(o){queueMicrotask(()=>i(o))}else return s(),Promise.resolve()},exists(e,t){if(vA(t,"cb"),e===void 0)throw bt("path","of type string or an instance of Buffer or URL",e);queueMicrotask(()=>t(!!(eY(e)&&$.existsSync(e))))},stat(e,t){vA(t,"cb"),Be(e);let r=t;try{let n=$.statSync(e);queueMicrotask(()=>r(null,n))}catch(n){queueMicrotask(()=>r(n))}},lstat(e,t){if(t){let r=t;try{let n=$.lstatSync(e);queueMicrotask(()=>r(null,n))}catch(n){queueMicrotask(()=>r(n))}}else return Promise.resolve($.lstatSync(e))},unlink(e,t){if(t){Be(e);let r=t;try{$.unlinkSync(e),queueMicrotask(()=>r(null))}catch(n){queueMicrotask(()=>r(n))}}else return Promise.resolve($.unlinkSync(e))},rename(e,t,r){if(r){Be(e,"oldPath"),Be(t,"newPath");let n=r;try{$.renameSync(e,t),queueMicrotask(()=>n(null))}catch(i){queueMicrotask(()=>n(i))}}else return Promise.resolve($.renameSync(e,t))},copyFile(e,t,r){if(r)try{$.copyFileSync(e,t),r(null)}catch(n){r(n)}else return Promise.resolve($.copyFileSync(e,t))},cp(e,t,r,n){if(typeof r=="function"&&(n=r,r=void 0),n)try{$.cpSync(e,t,r),n(null)}catch(i){n(i)}else return Promise.resolve($.cpSync(e,t,r))},mkdtemp(e,t,r){typeof t=="function"&&(r=t,t=void 0),vA(r,"cb"),ir(t);try{r(null,$.mkdtempSync(e,t))}catch(n){r(n)}},opendir(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r)try{r(null,$.opendirSync(e,t))}catch(n){r(n)}else return Promise.resolve($.opendirSync(e,t))},open(e,t,r,n){let i="r",s=r;typeof t=="function"?(n=t,s=void 0):i=t??"r",typeof r=="function"&&(n=r,s=void 0),vA(n,"cb"),Be(e),tY(s);let o=n;try{let a=$.openSync(e,i,s);queueMicrotask(()=>o(null,a))}catch(a){queueMicrotask(()=>o(a))}},close(e,t){ar(e),vA(t,"cb");let r=t;try{$.closeSync(e),queueMicrotask(()=>r(null))}catch(n){queueMicrotask(()=>r(n))}},read(e,t,r,n,i,s){if(s){let o=s;if(e===0&&i==null&&typeof _kernelStdinRead<"u"){let A=new Uint8Array(t.buffer,t.byteOffset+r,n),f=()=>{_kernelStdinRead.apply(void 0,[n,100],{result:{promise:!0}}).then(l=>{if(l==null){setTimeout(f,1);return}if(l?.done){queueMicrotask(()=>o(null,0,t));return}let p=String(l?.dataBase64??"");if(!p){setTimeout(f,1);return}let B=Tt.Buffer.from(p,"base64"),S=Math.min(n,B.length);A.set(B.subarray(0,S),0),queueMicrotask(()=>o(null,S,t))},l=>{queueMicrotask(()=>o(l))})};f();return}let a=()=>{try{let A=$.readSync(e,t,r,n,i);queueMicrotask(()=>o(null,A,t))}catch(A){if((A?.message??String(A)).includes("EAGAIN")){setTimeout(a,1);return}queueMicrotask(()=>o(A))}};a()}else return Promise.resolve($.readSync(e,t,r,n,i))},write(e,t,r,n,i,s){if(typeof r=="function"?(s=r,r=void 0,n=void 0,i=void 0):typeof n=="function"?(s=n,n=void 0,i=void 0):typeof i=="function"&&(s=i,i=void 0),s){let o=nY(t,r,n,i),a=s;try{let A=$.writeSync(e,t,r,n,i);queueMicrotask(()=>a(null,A))}catch(A){queueMicrotask(()=>a(A))}}else return Promise.resolve($.writeSync(e,t,r,n,i))},writev(e,t,r,n){typeof r=="function"&&(n=r,r=null);let i=ar(e),s=Km(t),o=Rs(r);if(n)try{let a=$.writevSync(i,s,o);queueMicrotask(()=>n(null,a,s))}catch(a){queueMicrotask(()=>n(a))}else return Promise.resolve($.writevSync(i,s,o))},writevSync(e,t,r){let n=ar(e),i=Km(t);if(Tg("_fsWritevRaw")){let a=Rs(r),A=n2e(i);return D1e.applySyncPromise(void 0,[n,A,a])}let s=Rs(r),o=0;for(let a of i){let A=a instanceof Uint8Array?a:new Uint8Array(a.buffer,a.byteOffset,a.byteLength);o+=$.writeSync(n,A,0,A.length,s),s!==null&&(s+=A.length)}return o},fstat(e,t){if(t)try{t(null,$.fstatSync(e))}catch(r){t(r)}else return Promise.resolve($.fstatSync(e))},fsync(e,t){ar(e),vA(t,"cb");try{$.fsyncSync(e),t(null)}catch(r){t(r)}},fdatasync(e,t){ar(e),vA(t,"cb");try{$.fdatasyncSync(e),t(null)}catch(r){t(r)}},readv(e,t,r,n){typeof r=="function"&&(n=r,r=null);let i=ar(e),s=Km(t),o=Rs(r);if(n)try{let a=$.readvSync(i,s,o);queueMicrotask(()=>n(null,a,s))}catch(a){queueMicrotask(()=>n(a))}},statfs(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r)try{r(null,$.statfsSync(e,t))}catch(n){r(n)}else return Promise.resolve($.statfsSync(e,t))},glob(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r)try{r(null,$.globSync(e,t))}catch(n){r(n)}},promises:{async readFile(e,t){return e instanceof pu?e.readFile(t):_1(e,t)},async writeFile(e,t,r){return e instanceof pu?e.writeFile(t,r):v1(e,t,r)},async appendFile(e,t,r){if(e instanceof pu)return e.appendFile(t,r);let n=await _1(e,"utf8").catch(s=>s?.code==="ENOENT"?"":Promise.reject(s)),i=typeof t=="string"?t:String(t);await v1(e,n+i,r)},async readdir(e,t){return H1e(e,t)},async mkdir(e,t){return q1e(e,t)},async rmdir(e){return G1e(e)},async stat(e){return Y1e(e)},async lstat(e){return W1e(e)},async unlink(e){return V1e(e)},async rename(e,t){return J1e(e,t)},async copyFile(e,t){let r=await _1(e);await v1(t,r)},async cp(e,t,r){return $.cpSync(e,t,r)},async mkdtemp(e,t){return $.mkdtempSync(e,t)},async opendir(e,t){return $.opendirSync(e,t)},async open(e,t,r){return new pu($.openSync(e,t??"r",r))},async statfs(e,t){return $.statfsSync(e,t)},async glob(e,t){return $.globSync(e,t)},async access(e){return j1e(e)},async rm(e,t){return $.rmSync(e,t)},async chmod(e,t){return z1e(e,t)},async chown(e,t,r){return K1e(e,t,r)},async lchown(e,t,r){return $.lchownSync(e,t,r)},async lutimes(e,t,r){return r2e(e,t,r)},async link(e,t){return X1e(e,t)},async symlink(e,t){return Z1e(e,t)},async readlink(e){return $1e(e)},async realpath(e,t){return $.realpathSync(e,t)},async truncate(e,t){return e2e(e,t)},async utimes(e,t,r){return t2e(e,t,r)},watch(e,t){return h1e(e,t)}},accessSync(e){if(!$.existsSync(e))throw Ve("ENOENT",`ENOENT: no such file or directory, access '${e}'`,"access",e)},access(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r)try{$.accessSync(e),r(null)}catch(n){r(n)}else return $.promises.access(e)},realpathSync:Object.assign(function(t,r){ir(r);let n=40,i=0,s=Be(t),o=[];for(let A of s.split("/"))!A||A==="."||(A===".."?o.length>0&&o.pop():o.push(A));let a=[];for(;o.length>0;){let A=o.shift();if(A===".")continue;if(A===".."){a.length>0&&a.pop();continue}a.push(A);let f="/"+a.join("/");try{if($.lstatSync(f).isSymbolicLink()){if(++i>n){let S=new Error(`ELOOP: too many levels of symbolic links, realpath '${s}'`);throw S.code="ELOOP",S.syscall="realpath",S.path=s,S}let p=$.readlinkSync(f),B=p.split("/").filter(Boolean);p.startsWith("/")?a.length=0:a.pop(),o.unshift(...B)}}catch(l){let p=l;if(p.code==="ELOOP")throw l;if(p.code==="ENOENT"||p.code==="ENOTDIR"){let B=new Error(`ENOENT: no such file or directory, realpath '${s}'`);throw B.code="ENOENT",B.syscall="realpath",B.path=s,B}break}}return"/"+a.join("/")||"/"},{native(e,t){return ir(t),$.realpathSync(e)}}),realpath:Object.assign(function(t,r,n){let i;if(typeof r=="function"?n=r:i=r,n)ir(i),n(null,$.realpathSync(t,i));else return Promise.resolve($.realpathSync(t,i))},{native(e,t,r){let n;if(typeof t=="function"?r=t:n=t,r)ir(n),r(null,$.realpathSync.native(e,n));else return Promise.resolve($.realpathSync.native(e,n))}}),ReadStream:hV,WriteStream:dV,createReadStream:function(t,r){let n=typeof r=="string"?{encoding:r}:r;ir(n);let i=HB(n?.fd),s=iY(t,i);return new aI(s,n)},createWriteStream:function(t,r){let n=typeof r=="string"?{encoding:r}:r;ir(n),cV(n??{});let i=HB(n?.fd),s=iY(t,i);return new AI(s,n)},watch(...e){let{path:t,listener:r,options:n}=r1e(e[0],e[1],e[2]),i=c1e(t,n);return r&&i.on("change",r),i},watchFile(...e){let{path:t,listener:r,options:n}=n1e(e[0],e[1],e[2]);return l1e(t,n,r)},unwatchFile(...e){let t=Be(e[0]),r=e[1];if(r!==void 0&&typeof r!="function")throw bt("listener","of type function",r);let n=e0.get(t);if(n)for(let i of[...n]){let s=i._listeners.get("change")??[];(r===void 0||s.some(o=>o===r||o._originalListener===r))&&i.close()}},chmod(e,t,r){if(r){Be(e),Sa(t);try{$.chmodSync(e,t),r(null)}catch(n){r(n)}}else return Promise.resolve($.chmodSync(e,t))},chown(e,t,r,n){if(n){Be(e),Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});try{$.chownSync(e,t,r),n(null)}catch(i){n(i)}}else return Promise.resolve($.chownSync(e,t,r))},fchmod(e,t,r){if(r){ar(e),Sa(t);try{$.fchmodSync(e,t),r(null)}catch(n){r(n)}}else return ar(e),Sa(t),Promise.resolve($.fchmodSync(e,t))},fchown(e,t,r,n){if(n){ar(e),Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});try{$.fchownSync(e,t,r),n(null)}catch(i){n(i)}}else return ar(e),Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0}),Promise.resolve($.fchownSync(e,t,r))},lchown(e,t,r,n){if(arguments.length>=4){vA(n,"cb"),Be(e),Kr("uid",t,{min:-1,max:4294967295,allowNegativeOne:!0}),Kr("gid",r,{min:-1,max:4294967295,allowNegativeOne:!0});try{$.lchownSync(e,t,r),n(null)}catch(i){n(i)}}else return Promise.resolve($.lchownSync(e,t,r))},link(e,t,r){if(r){Be(e,"existingPath"),Be(t,"newPath");try{$.linkSync(e,t),r(null)}catch(n){r(n)}}else return Promise.resolve($.linkSync(e,t))},symlink(e,t,r,n){if(typeof r=="function"&&(n=r),n)try{$.symlinkSync(e,t),n(null)}catch(i){n(i)}else return Promise.resolve($.symlinkSync(e,t))},readlink(e,t,r){if(typeof t=="function"&&(r=t,t=void 0),r){Be(e),ir(t);try{r(null,$.readlinkSync(e,t))}catch(n){r(n)}}else return Promise.resolve($.readlinkSync(e,t))},truncate(e,t,r){if(typeof t=="function"&&(r=t,t=0),r)try{$.truncateSync(e,t),r(null)}catch(n){r(n)}else return Promise.resolve($.truncateSync(e,t))},utimes(e,t,r,n){if(n)try{$.utimesSync(e,t,r),n(null)}catch(i){n(i)}else return Promise.resolve($.utimesSync(e,t,r))},lutimes(e,t,r,n){if(n)try{$.lutimesSync(e,t,r),n(null)}catch(i){n(i)}else return Promise.resolve($.lutimesSync(e,t,r))},futimes(e,t,r,n){if(n)try{$.futimesSync(e,t,r),n(null)}catch(i){n(i)}else return Promise.resolve($.futimesSync(e,t,r))}};gV=e=>$.readdirSync(e);Q2=e=>$.statSync(e);var wR=$;Ge("_fsModule",wR);var Ia={platform:typeof _osConfig<"u"&&_osConfig.platform||"linux",arch:typeof _osConfig<"u"&&_osConfig.arch||"x64",type:typeof _osConfig<"u"&&_osConfig.type||"Linux",release:typeof _osConfig<"u"&&_osConfig.release||"6.8.0-secure-exec",version:typeof _osConfig<"u"&&_osConfig.version||"#1 SMP PREEMPT_DYNAMIC secure-exec",homedir:typeof _osConfig<"u"&&_osConfig.homedir||"/home/user",tmpdir:typeof _osConfig<"u"&&_osConfig.tmpdir||"/tmp",hostname:typeof _osConfig<"u"&&_osConfig.hostname||"secure-exec",machine:typeof _osConfig<"u"&&_osConfig.machine||"x86_64"};function AY(){return vs("homedir",globalThis.process?.env?.HOME||Ia.homedir)}function i2e(){return vs("tmpdir",globalThis.process?.env?.TMPDIR||Ia.tmpdir)}function s2e(){return vs("user",globalThis.process?.env?.USER||globalThis.process?.env?.LOGNAME||"user")}function o2e(){return vs("shell",globalThis.process?.env?.SHELL||"/bin/sh")}function w2(){let e=globalThis.process?.uid;return Number.isFinite(e)?e:0}function dB(){let e=globalThis.process?.gid;return Number.isFinite(e)?e:0}function EV(){return globalThis.__agentOSVirtualOs||{}}function vs(e,t){let r=EV()[e];return typeof r=="string"&&r.length>0?r:t}function SR(e,t){let r=Number(EV()[e]);return Number.isSafeInteger(r)&&r>0?r:t}function fY(){return SR("cpuCount",1)}function yV(){return SR("totalmem",1073741824)}function a2e(){return Math.min(SR("freemem",536870912),yV())}var mV={SIGHUP:1,SIGINT:2,SIGQUIT:3,SIGILL:4,SIGTRAP:5,SIGABRT:6,SIGIOT:6,SIGBUS:7,SIGFPE:8,SIGKILL:9,SIGUSR1:10,SIGSEGV:11,SIGUSR2:12,SIGPIPE:13,SIGALRM:14,SIGTERM:15,SIGSTKFLT:16,SIGCHLD:17,SIGCONT:18,SIGSTOP:19,SIGTSTP:20,SIGTTIN:21,SIGTTOU:22,SIGURG:23,SIGXCPU:24,SIGXFSZ:25,SIGVTALRM:26,SIGPROF:27,SIGWINCH:28,SIGIO:29,SIGPOLL:29,SIGPWR:30,SIGSYS:31},uY={1:"SIGHUP",2:"SIGINT",3:"SIGQUIT",4:"SIGILL",5:"SIGTRAP",6:"SIGABRT",7:"SIGBUS",8:"SIGFPE",9:"SIGKILL",10:"SIGUSR1",11:"SIGSEGV",12:"SIGUSR2",13:"SIGPIPE",14:"SIGALRM",15:"SIGTERM",16:"SIGSTKFLT",17:"SIGCHLD",18:"SIGCONT",19:"SIGSTOP",20:"SIGTSTP",21:"SIGTTIN",22:"SIGTTOU",23:"SIGURG",24:"SIGXCPU",25:"SIGXFSZ",26:"SIGVTALRM",27:"SIGPROF",28:"SIGWINCH",29:"SIGIO",30:"SIGPWR",31:"SIGSYS"};function _R(e){if(e==null)return{bridgeSignal:"SIGTERM",signalCode:"SIGTERM"};if(e===0||e==="0")return{bridgeSignal:"0",signalCode:null};if(typeof e=="number"){let t=uY[e];if(t)return{bridgeSignal:t,signalCode:t};throw new Error("Unknown signal: "+e)}if(typeof e=="string"){let t=mV[e];if(t!==void 0){let r=uY[t]??e;return{bridgeSignal:r,signalCode:r}}}throw new Error("Unknown signal: "+e)}var A2e={E2BIG:7,EACCES:13,EADDRINUSE:98,EADDRNOTAVAIL:99,EAFNOSUPPORT:97,EAGAIN:11,EALREADY:114,EBADF:9,EBADMSG:74,EBUSY:16,ECANCELED:125,ECHILD:10,ECONNABORTED:103,ECONNREFUSED:111,ECONNRESET:104,EDEADLK:35,EDESTADDRREQ:89,EDOM:33,EDQUOT:122,EEXIST:17,EFAULT:14,EFBIG:27,EHOSTUNREACH:113,EIDRM:43,EILSEQ:84,EINPROGRESS:115,EINTR:4,EINVAL:22,EIO:5,EISCONN:106,EISDIR:21,ELOOP:40,EMFILE:24,EMLINK:31,EMSGSIZE:90,EMULTIHOP:72,ENAMETOOLONG:36,ENETDOWN:100,ENETRESET:102,ENETUNREACH:101,ENFILE:23,ENOBUFS:105,ENODATA:61,ENODEV:19,ENOENT:2,ENOEXEC:8,ENOLCK:37,ENOLINK:67,ENOMEM:12,ENOMSG:42,ENOPROTOOPT:92,ENOSPC:28,ENOSR:63,ENOSTR:60,ENOSYS:38,ENOTCONN:107,ENOTDIR:20,ENOTEMPTY:39,ENOTSOCK:88,ENOTSUP:95,ENOTTY:25,ENXIO:6,EOPNOTSUPP:95,EOVERFLOW:75,EPERM:1,EPIPE:32,EPROTO:71,EPROTONOSUPPORT:93,EPROTOTYPE:91,ERANGE:34,EROFS:30,ESPIPE:29,ESRCH:3,ESTALE:116,ETIME:62,ETIMEDOUT:110,ETXTBSY:26,EWOULDBLOCK:11,EXDEV:18},f2e={PRIORITY_LOW:19,PRIORITY_BELOW_NORMAL:10,PRIORITY_NORMAL:0,PRIORITY_ABOVE_NORMAL:-7,PRIORITY_HIGH:-14,PRIORITY_HIGHEST:-20},BV={platform(){return vs("platform",Ia.platform)},arch(){return vs("arch",Ia.arch)},type(){return vs("type",Ia.type)},release(){return vs("release",Ia.release)},version(){return vs("version",Ia.version)},homedir(){return AY()},tmpdir(){return i2e()},hostname(){return vs("hostname",Ia.hostname)},userInfo(e){return{username:s2e(),uid:w2(),gid:dB(),shell:o2e(),homedir:AY()}},cpus(){return Array.from({length:fY()},()=>({model:"Virtual CPU",speed:2e3,times:{user:1e5,nice:0,sys:5e4,idle:8e5,irq:0}}))},totalmem(){return yV()},freemem(){return a2e()},loadavg(){return[.1,.1,.1]},uptime(){return 3600},networkInterfaces(){return{}},endianness(){return"LE"},EOL:` -`,devNull:"/dev/null",machine(){return vs("machine",Ia.machine)},constants:{signals:mV,errno:A2e,priority:f2e,dlopen:{RTLD_LAZY:1,RTLD_NOW:2,RTLD_GLOBAL:256,RTLD_LOCAL:0},UV_UDP_REUSEADDR:4},getPriority(e){return 0},setPriority(e,t){},availableParallelism(){return fY()}};Ge("_osModule",BV);var u2e=BV,IV={};O2(IV,{ChildProcess:()=>RR,default:()=>B2e,exec:()=>_V,execFile:()=>RV,execFileSync:()=>DV,execSync:()=>vV,fork:()=>TV,spawn:()=>l0,spawnSync:()=>DR});var Cu=new Map,r0=new Map;function c2e(e){if(typeof e!="number")return;let t=r0.get(e);t?t.holders+=1:r0.set(e,{holders:1,closePending:!1})}function l2e(e){let t=r0.get(e);return t?(t.closePending=!0,!0):!1}function h2e(e){let t=r0.get(e);if(t&&(t.holders-=1,!(t.holders>0)&&(r0.delete(e),t.closePending)))try{pV.applySyncPromise(void 0,[e])}catch{}}var d2e=200,g2e=25;function p2e(e){return!e||typeof e!="object"?null:typeof e.sessionId=="string"&&e.sessionId.length>0||typeof e.sessionId=="number"&&Number.isFinite(e.sessionId)?e.sessionId:null}function vR(e){if(e&&typeof e=="object")return e;if(typeof e=="string")try{let t=JSON.parse(e);return t&&typeof t=="object"?t:e}catch{}return e}var S2="AGENTOS_IPC:";function bV(e){let t=JSON.stringify(e),r=typeof Buffer<"u"?Buffer.from(t,"utf8").toString("base64"):btoa(t);return`${S2}${r} -`}function E2e(e){let t=typeof Buffer<"u"?Buffer.from(e,"base64").toString("utf8"):atob(e);return JSON.parse(t)}function CV(e,t){let r=`${e}${typeof Buffer<"u"?Buffer.from(t).toString("utf8"):String(t)}`,n=[],i=[],s=0;for(;;){let o=r.indexOf(S2,s);if(o===-1)return i.push(r.slice(s)),{buffer:"",messages:n,output:i.join("")};i.push(r.slice(s,o));let a=o+S2.length,A=r.indexOf(` -`,a);if(A===-1)return{buffer:r.slice(o),messages:n,output:i.join("")};try{n.push(E2e(r.slice(a,A)))}catch{i.push(r.slice(o,A+1))}s=A+1}}function QV(e,t){if(!t||typeof t!="object")return!1;if(t.type==="stdout"||t.type==="stderr"){let r={sessionId:e};return typeof t.data=="string"?r.data=t.data:typeof Buffer<"u"&&Buffer.isBuffer(t.data)?r.dataBase64=t.data.toString("base64"):t.data instanceof Uint8Array||ArrayBuffer.isView(t.data)?r.dataBase64=Buffer.from(t.data.buffer,t.data.byteOffset,t.data.byteLength).toString("base64"):t.data?.__agentOSType==="bytes"&&typeof t.data.base64=="string"&&(r.dataBase64=t.data.base64),_2(`child_${t.type}`,r),!0}return t.type==="exit"?(_2("child_exit",{sessionId:e,code:t.exitCode,signal:t.signal??null}),!0):!1}function wV(e){e?._detachedBootstrapPending&&(e._detachedBootstrapPending=!1,e._detachedBootstrapPollsRemaining=0,e._detachedBootstrapTimer!=null&&(clearTimeout(e._detachedBootstrapTimer),e._detachedBootstrapTimer=null),e._pollRefed||(e._pollTimer?.unref?.(),e._handleRefed&&e._handleId&&typeof _unregisterHandle=="function"&&(_unregisterHandle(e._handleId),e._handleRefed=!1)))}function SV(e){e?._detachedBootstrapPending&&(e._detachedBootstrapPollsRemaining>0&&(e._detachedBootstrapPollsRemaining-=1),e._detachedBootstrapPollsRemaining===0&&wV(e))}function y2e(e,t=g2e){if(!e?.detached||e._sessionId==null||typeof _childProcessPoll>"u")return!1;if(!e._detachedBootstrapPending)return!0;for(let r=0;r{if(typeof e=="number"){D1(e,t,r);return}let n=(()=>{if(t&&typeof t=="object")return t;if(typeof t=="string")try{return JSON.parse(t)}catch{return null}return null})(),i=p2e(n);if(i!=null){if(e==="child_stdout"||e==="child_stderr"){let s=n?.data,o;if(typeof Buffer<"u"&&Buffer.isBuffer(s))o=Buffer.from(s);else if(s instanceof Uint8Array)o=typeof Buffer<"u"?Buffer.from(s.buffer,s.byteOffset,s.byteLength):s;else if(ArrayBuffer.isView(s))o=typeof Buffer<"u"?Buffer.from(s.buffer,s.byteOffset,s.byteLength):new Uint8Array(s.buffer,s.byteOffset,s.byteLength);else{let a=typeof n?.dataBase64=="string"?n.dataBase64:typeof s=="string"?s:s?.__agentOSType==="bytes"&&typeof s?.base64=="string"?s.base64:"";o=typeof Buffer<"u"?Buffer.from(a,"base64"):new Uint8Array(atob(a).split("").map(A=>A.charCodeAt(0)))}D1(i,e==="child_stdout"?"stdout":"stderr",o);return}if(e==="child_exit"){let s=typeof n?.code=="number"?n.code:Number(n?.code??1),o=typeof n?.signal=="string"?n.signal:null;D1(i,"exit",{code:s,signal:o})}}};Ge("_childProcessDispatch",_2);var m2e=64;function v2(e,t=0){let r=Cu.get(e);if(!r||typeof _childProcessPoll>"u"||r._pollScheduled)return;r._pollScheduled=!0;let n=setTimeout(()=>{if(r._pollTimer=null,r._pollScheduled=!1,!Cu.has(e))return;let i=0;for(;i0||(e._onceListeners[t]?.length??0)>0}function cY(e,t){let r=e._readableEncoding;return!r||typeof t=="string"?t:typeof Buffer<"u"&&Buffer.isBuffer(t)?t.toString(r):t instanceof Uint8Array?typeof Buffer<"u"?Buffer.from(t).toString(r):String(t):t}function Ng(e){e._flushScheduled||(e._flushScheduled=!0,queueMicrotask(()=>{if(e._flushScheduled=!1,e._bufferedChunks.length>0&&Nl(e,"data")){let t=e._bufferedChunks.splice(0,e._bufferedChunks.length);for(let r of t)e.emit("data",r)}e._ended&&e._bufferedChunks.length===0&&Nl(e,"end")&&e.emit("end")}))}function Xm(e,t){if(e._maxListenersWarned instanceof Set||(e._maxListenersWarned=new Set),e._maxListeners>0&&!e._maxListenersWarned.has(t)){let r=(e._listeners[t]?.length??0)+(e._onceListeners[t]?.length??0);if(r>e._maxListeners){e._maxListenersWarned.add(t);let n=`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${r} ${t} listeners added. MaxListeners is ${e._maxListeners}. Use emitter.setMaxListeners() to increase limit`;typeof console<"u"&&console.error&&console.error(n)}}}function lY(e){let t=[],r=[],n=[],i=!1,s=()=>{for(;n.length>0;){let f=n.shift();if(r.length>0){f(Promise.reject(r.shift()));continue}if(t.length>0){f(Promise.resolve({done:!1,value:t.shift()}));continue}if(i){f(Promise.resolve({done:!0,value:void 0}));continue}n.unshift(f);break}},o=f=>{t.push(f),s()},a=()=>{i=!0,s()},A=f=>{r.push(f),i=!0,s()};return e.on("data",o),e.on("end",a),e.on("close",a),e.on("error",A),Ng(e),{next(){return r.length>0?Promise.reject(r.shift()):t.length>0?Promise.resolve({done:!1,value:t.shift()}):i?Promise.resolve({done:!0,value:void 0}):new Promise(f=>{n.push(f)})},return(){return e.off("data",o),e.off("end",a),e.off("close",a),e.off("error",A),i=!0,s(),Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}}}var Dl=1e3,RR=class{constructor(){y(this,"_listeners",{});y(this,"_onceListeners",{});y(this,"_maxListeners",10);y(this,"_maxListenersWarned",new Set);y(this,"pid",Dl++);y(this,"killed",!1);y(this,"exitCode",null);y(this,"signalCode",null);y(this,"_pendingSignalCode",null);y(this,"connected",!1);y(this,"_pollScheduled",!1);y(this,"_pollRefed",!0);y(this,"_pollTimer",null);y(this,"_detachedBootstrapPending",!1);y(this,"_detachedBootstrapPollsRemaining",0);y(this,"_detachedBootstrapTimer",null);y(this,"_sessionId",null);y(this,"_handleId",null);y(this,"_handleDescription","");y(this,"_handleRefed",!1);y(this,"_ipcEnabled",!1);y(this,"_ipcStdoutBuffer","");y(this,"_ipcQueuedMessages",[]);y(this,"spawnfile","");y(this,"spawnargs",[]);y(this,"stdin");y(this,"stdout");y(this,"stderr");y(this,"stdio");this.stdin={writable:!0,destroyed:!1,_listeners:{},_onceListeners:{},write(e,t,r){let n=typeof t=="function"?t:r;return n&&queueMicrotask(()=>n(null)),!0},end(e,t,r){let n=typeof e=="function"?e:typeof t=="function"?t:r;this.writable=!1,n&&queueMicrotask(()=>n())},destroy(){return this.writable=!1,this.destroyed=!0,this.emit("close"),this},on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this},once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this},off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}if(this._onceListeners[e]){let r=this._onceListeners[e].indexOf(t);r!==-1&&this._onceListeners[e].splice(r,1)}return this},removeListener(e,t){return this.off(e,t)},emit(e,...t){let r=!1;return this._listeners[e]&&this._listeners[e].forEach(n=>{n(...t),r=!0}),this._onceListeners[e]&&(this._onceListeners[e].forEach(n=>{n(...t),r=!0}),this._onceListeners[e]=[]),r}},this.stdout={readable:!0,isTTY:!1,destroyed:!1,_listeners:{},_onceListeners:{},_bufferedChunks:[],_ended:!1,_flushScheduled:!1,_maxListeners:10,_maxListenersWarned:new Set,on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),Xm(this,e),(e==="data"||e==="end")&&Ng(this),this},once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),Xm(this,e),(e==="data"||e==="end")&&Ng(this),this},off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}if(this._onceListeners[e]){let r=this._onceListeners[e].indexOf(t);r!==-1&&this._onceListeners[e].splice(r,1)}return this},removeListener(e,t){return this.off(e,t)},emit(e,...t){return e==="data"&&(t[0]=cY(this,t[0]),!Nl(this,"data"))?(this._bufferedChunks.push(t[0]),!1):e==="end"&&(this._ended=!0,!Nl(this,"end"))?!1:(this._listeners[e]&&this._listeners[e].forEach(r=>r(...t)),this._onceListeners[e]&&(this._onceListeners[e].forEach(r=>r(...t)),this._onceListeners[e]=[]),!0)},read(){return null},setEncoding(e){return this._readableEncoding=e==null||e==="buffer"?null:String(e),this},setMaxListeners(e){return this._maxListeners=e,this},getMaxListeners(){return this._maxListeners},pipe(e){return e},pause(){return this},resume(){return this},destroy(){return this.readable=!1,this._ended=!0,this.destroyed=!0,this.emit("close"),this},[Symbol.asyncIterator](){return lY(this)}},this.stderr={readable:!0,isTTY:!1,destroyed:!1,_listeners:{},_onceListeners:{},_bufferedChunks:[],_ended:!1,_flushScheduled:!1,_maxListeners:10,_maxListenersWarned:new Set,on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),Xm(this,e),(e==="data"||e==="end")&&Ng(this),this},once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),Xm(this,e),(e==="data"||e==="end")&&Ng(this),this},off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}if(this._onceListeners[e]){let r=this._onceListeners[e].indexOf(t);r!==-1&&this._onceListeners[e].splice(r,1)}return this},removeListener(e,t){return this.off(e,t)},emit(e,...t){return e==="data"&&(t[0]=cY(this,t[0]),!Nl(this,"data"))?(this._bufferedChunks.push(t[0]),!1):e==="end"&&(this._ended=!0,!Nl(this,"end"))?!1:(this._listeners[e]&&this._listeners[e].forEach(r=>r(...t)),this._onceListeners[e]&&(this._onceListeners[e].forEach(r=>r(...t)),this._onceListeners[e]=[]),!0)},read(){return null},setEncoding(e){return this._readableEncoding=e==null||e==="buffer"?null:String(e),this},setMaxListeners(e){return this._maxListeners=e,this},getMaxListeners(){return this._maxListeners},pipe(e){return e},pause(){return this},resume(){return this},destroy(){return this.readable=!1,this._ended=!0,this.destroyed=!0,this.emit("close"),this},[Symbol.asyncIterator](){return lY(this)}},this.stdio=[this.stdin,this.stdout,this.stderr]}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this._checkMaxListeners(e),e==="message"&&this._flushQueuedIpcMessages(),this}once(e,t){return this._onceListeners[e]||(this._onceListeners[e]=[]),this._onceListeners[e].push(t),this._checkMaxListeners(e),e==="message"&&this._flushQueuedIpcMessages(),this}off(e,t){if(this._listeners[e]){let r=this._listeners[e].indexOf(t);r!==-1&&this._listeners[e].splice(r,1)}return this}removeListener(e,t){return this.off(e,t)}setMaxListeners(e){return this._maxListeners=e,this}getMaxListeners(){return this._maxListeners}_checkMaxListeners(e){if(this._maxListenersWarned instanceof Set||(this._maxListenersWarned=new Set),this._maxListeners>0&&!this._maxListenersWarned.has(e)){let t=(this._listeners[e]?.length??0)+(this._onceListeners[e]?.length??0);if(t>this._maxListeners){this._maxListenersWarned.add(e);let r=`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${t} ${e} listeners added to [ChildProcess]. MaxListeners is ${this._maxListeners}. Use emitter.setMaxListeners() to increase limit`;typeof console<"u"&&console.error&&console.error(r)}}}_hasIpcMessageListeners(){return(this._listeners.message?.length??0)>0||(this._onceListeners.message?.length??0)>0}_emitOrQueueIpcMessage(e){return this._hasIpcMessageListeners()?this.emit("message",e,void 0):(this._ipcQueuedMessages.push(e),!1)}_flushQueuedIpcMessages(){this._ipcQueuedMessages.length!==0&&queueMicrotask(()=>{for(;this._ipcQueuedMessages.length>0&&this._hasIpcMessageListeners();)this.emit("message",this._ipcQueuedMessages.shift(),void 0)})}emit(e,...t){let r=!1;return this._listeners[e]&&this._listeners[e].forEach(n=>{n(...t),r=!0}),this._onceListeners[e]&&(this._onceListeners[e].forEach(n=>{n(...t),r=!0}),this._onceListeners[e]=[]),r}kill(e){let t=_R(e);return this.killed=!0,this._pendingSignalCode=t.signalCode,!0}ref(){return this._pollRefed=!0,this._pollTimer?.ref?.(),!this._handleRefed&&this._handleId&&typeof _registerHandle=="function"&&(_registerHandle(this._handleId,this._handleDescription),this._handleRefed=!0),this}unref(){return this._pollRefed=!1,this._detachedBootstrapPending&&y2e(this),this._detachedBootstrapPending||this._pollTimer?.unref?.(),!this._detachedBootstrapPending&&this._handleRefed&&this._handleId&&typeof _unregisterHandle=="function"&&(_unregisterHandle(this._handleId),this._handleRefed=!1),this}disconnect(){this.connected=!1,this.emit("disconnect")}send(e,t,r,n){if(!this.connected||!this._ipcEnabled||this._sessionId==null)return!1;let i=typeof t=="function"?t:typeof r=="function"?r:n;try{let s=bV(e);return this.stdin.write(s,"utf8",i),!0}catch(s){return i?(queueMicrotask(()=>i(s)),!1):(this.emit("error",s),!1)}}_complete(e,t,r){let n=this._pendingSignalCode??this.signalCode;if(this._pendingSignalCode=null,this.signalCode=n??null,this.exitCode=n==null?r:null,e){let i=typeof Buffer<"u"?Buffer.from(e):e;this.stdout.emit("data",i)}if(t){let i=typeof Buffer<"u"?Buffer.from(t):t;this.stderr.emit("data",i)}this.stdout.emit("end"),this.stderr.emit("end"),this.emit("close",this.exitCode,this.signalCode),this.emit("exit",this.exitCode,this.signalCode)}};function _V(e,t,r){typeof t=="function"&&(r=t,t={});let n=l0(e,[],{...t,shell:!0});n.spawnargs=[e],n.spawnfile=e;let i=t?.maxBuffer??1024*1024,s="",o="",a=0,A=0,f=!1,l=!1,p=null,B=S=>{!r||l||(l=!0,r(S,s,o))};return n.stdout.on("data",S=>{if(f)return;let _=String(S);s+=_,a+=_.length,a>i&&(f=!0,n.kill("SIGTERM"))}),n.stderr.on("data",S=>{if(f)return;let _=String(S);o+=_,A+=_.length,A>i&&(f=!0,n.kill("SIGTERM"))}),n.on("close",(...S)=>{let _=S[0];if(r)if(f){let N=new Error("stdout maxBuffer length exceeded");N.code="ERR_CHILD_PROCESS_STDIO_MAXBUFFER",N.killed=!0,N.cmd=e,N.stdout=s,N.stderr=o,B(N)}else if(_!==0&&p==null){let N=new Error("Command failed: "+e);N.code=_,N.killed=!1,N.signal=null,N.cmd=e,N.stdout=s,N.stderr=o,B(N)}else B(null)}),n.on("error",S=>{if(r){let _=S instanceof Error?S:new Error(String(S));p=_,_.cmd=e,_.stdout=s,_.stderr=o,B(_)}}),n}function vV(e,t){let r=t||{};if(typeof _childProcessSpawnSync>"u")throw new Error("child_process.execSync requires CommandExecutor to be configured");let n=r.cwd??(typeof process<"u"?process.cwd():"/"),i=r.maxBuffer??1024*1024,s=_childProcessSpawnSync.applySyncPromise(void 0,[e,JSON.stringify([]),JSON.stringify({cwd:n,env:r.env,input:r.input==null?null:t0(r.input),maxBuffer:i,shell:!0})]),o=typeof s=="string"?JSON.parse(s):s,a=Array.isArray(r.stdio)?r.stdio:r.stdio==="inherit"?["inherit","inherit","inherit"]:[];if(GB(a[1],o.stdout)&&(o.stdout=typeof o.stdout=="string"?"":Buffer.from("")),GB(a[2],o.stderr),o.maxBufferExceeded){let A=new Error("stdout maxBuffer length exceeded");throw A.code="ERR_CHILD_PROCESS_STDIO_MAXBUFFER",A.stdout=o.stdout,A.stderr=o.stderr,A}if(o.code!==0){let A=new Error("Command failed: "+e);throw A.status=o.code,A.stdout=o.stdout,A.stderr=o.stderr,A.output=[null,o.stdout,o.stderr],A}return(r.encoding==="buffer"||!r.encoding)&&typeof Buffer<"u"?Buffer.from(o.stdout):o.stdout}function l0(e,t,r){let n=[],i={};Array.isArray(t)?(n=t,i=r||{}):i=t||{};let s=new RR;s.spawnfile=e,s.spawnargs=[e,...n],s.detached=i.detached===!0,s._detachedBootstrapPending=s.detached,s._detachedBootstrapPollsRemaining=s.detached?d2e:0;let o=Array.isArray(i.stdio)?i.stdio:i.stdio==="inherit"?["inherit","inherit","inherit"]:[];s._stdoutFd=typeof o[1]=="number"?o[1]:null,s._stderrFd=typeof o[2]=="number"?o[2]:null,s._inheritedFds=[];for(let A of[s._stdoutFd,s._stderrFd])typeof A=="number"&&(c2e(A),s._inheritedFds.push(A));if(typeof _childProcessSpawnStart<"u"){let A;try{let l=i.cwd??(typeof process<"u"?process.cwd():"/");A=vR(_childProcessSpawnStart.applySync(void 0,[e,JSON.stringify(n),JSON.stringify({cwd:l,env:i.env,shell:i.shell===!0||typeof i.shell=="string",detached:i.detached===!0})]))}catch(l){let p=l instanceof Error?l:new Error(String(l));return p.code==null&&/command not found:/i.test(String(p.message||""))?p.code="ENOENT":p.code==null&&/ERR_NATIVE_BINARY_NOT_SUPPORTED\b/i.test(String(p.message||""))&&(p.code="ERR_NATIVE_BINARY_NOT_SUPPORTED"),queueMicrotask(()=>{s.emit("error",p)}),s}let f=typeof A=="object"&&A!==null?A.childId:A;return Cu.set(f,s),s._sessionId=f,typeof _registerHandle=="function"&&(s._handleId=`child:${f}`,s._handleDescription=`child_process: ${e} ${n.join(" ")}`,_registerHandle(s._handleId,s._handleDescription),s._handleRefed=!0),s.stdin.write=(l,p,B)=>{let S=typeof p=="function"?p:B;if(typeof _childProcessStdinWrite>"u")return!1;let _=typeof l=="string"?new TextEncoder().encode(l):l;try{_childProcessStdinWrite.applySync(void 0,[f,_])}catch(N){return S?(queueMicrotask(()=>S(N)),!1):(s.stdin.emit("error",N),!1)}return S&&queueMicrotask(()=>S(null)),!0},s.stdin.end=(l,p,B)=>{let S=typeof l=="function"?l:typeof p=="function"?p:B;if(l!=null&&typeof l!="function"&&s.stdin.write(l,typeof p=="string"?p:void 0),typeof _childProcessStdinClose<"u")try{_childProcessStdinClose.applySync(void 0,[f])}catch(_){if(S){queueMicrotask(()=>S(_));return}s.stdin.emit("error",_);return}s.stdin.writable=!1,S&&queueMicrotask(()=>S())},s.stdin.destroy=()=>(s.stdin.end(),s.stdin.destroyed=!0,s.stdin.emit("close"),s.stdin),s.kill=l=>{if(typeof _childProcessKill>"u")return!1;let p=_R(l);return _childProcessKill.applySync(void 0,[f,p.bridgeSignal]),s.killed=!0,s._pendingSignalCode=p.signalCode,!0},s.pid=typeof A=="object"&&A!==null?Number(A.pid)||-1:Number(f)||-1,(o[1]==="inherit"||o[1]===1)&&s.stdout.on("data",l=>process.stdout.write(l)),(o[2]==="inherit"||o[2]===2)&&s.stderr.on("data",l=>process.stderr.write(l)),setTimeout(()=>s.emit("spawn"),0),v2(f,0),s}let a=new Error("child_process.spawn requires CommandExecutor to be configured");return setTimeout(()=>{s.emit("error",a),s._complete("",a.message,1)},0),s}function DR(e,t,r){let n=[],i={};if(Array.isArray(t)?(n=t,i=r||{}):i=t||{},typeof _childProcessSpawnSync>"u")return{pid:Dl++,output:[null,"","child_process.spawnSync requires CommandExecutor to be configured"],stdout:"",stderr:"child_process.spawnSync requires CommandExecutor to be configured",status:1,signal:null,error:new Error("child_process.spawnSync requires CommandExecutor to be configured")};try{let s=i.cwd??(typeof process<"u"?process.cwd():"/"),o=i.maxBuffer,a=i.encoding==null||i.encoding==="buffer",A=Number.isInteger(i.timeout)&&i.timeout>0?i.timeout:null,f=_R(i.killSignal).signalCode??"SIGTERM",l=_childProcessSpawnSync.applySyncPromise(void 0,[e,JSON.stringify(n),JSON.stringify({cwd:s,env:i.env,input:i.input==null?null:t0(i.input),maxBuffer:o,shell:i.shell===!0||typeof i.shell=="string",timeout:A,killSignal:f})]),p=typeof l=="string"?JSON.parse(l):l,B=Array.isArray(i.stdio)?i.stdio:i.stdio==="inherit"?["inherit","inherit","inherit"]:[],S=a&&typeof Buffer<"u"?Buffer.from(p.stdout):p.stdout,_=a&&typeof Buffer<"u"?Buffer.from(p.stderr):p.stderr;if(GB(B[1],S)&&(S=a&&typeof Buffer<"u"?Buffer.from(""):""),GB(B[2],_)&&(_=a&&typeof Buffer<"u"?Buffer.from(""):""),p.timedOut){let N=new Error(`spawnSync ${e} ETIMEDOUT`);return N.code="ETIMEDOUT",{pid:Dl++,output:[null,S,_],stdout:S,stderr:_,status:null,signal:p.signal??f,error:N}}if(p.maxBufferExceeded){let N=new Error("stdout maxBuffer length exceeded");return N.code="ERR_CHILD_PROCESS_STDIO_MAXBUFFER",{pid:Dl++,output:[null,S,_],stdout:S,stderr:_,status:p.code,signal:null,error:N}}return{pid:Dl++,output:[null,S,_],stdout:S,stderr:_,status:p.code,signal:null,error:void 0}}catch(s){s&&typeof s=="object"&&s.code==null&&/ERR_NATIVE_BINARY_NOT_SUPPORTED\b/i.test(String(s.message||s))&&(s.code="ERR_NATIVE_BINARY_NOT_SUPPORTED");let o=s instanceof Error?s.message:String(s),a=i.encoding==null||i.encoding==="buffer",A=a&&typeof Buffer<"u"?Buffer.from(""):"",f=a&&typeof Buffer<"u"?Buffer.from(o):o;return{pid:Dl++,output:[null,A,f],stdout:A,stderr:f,status:1,signal:null,error:s instanceof Error?s:new Error(String(s))}}}function RV(e,t,r,n){let i=[],s={},o;typeof t=="function"?o=t:typeof r=="function"?(i=t.slice(),o=r):(i=Array.isArray(t)?t:[],s=r||{},o=n);let a=s.maxBuffer??1024*1024,A=l0(e,i,s),f="",l="",p=0,B=0,S=!1;return A.stdout.on("data",_=>{let N=String(_);f+=N,p+=N.length,p>a&&!S&&(S=!0,A.kill("SIGTERM"))}),A.stderr.on("data",_=>{let N=String(_);l+=N,B+=N.length,B>a&&!S&&(S=!0,A.kill("SIGTERM"))}),A.on("close",(..._)=>{let N=_[0];if(o)if(S){let P=new Error("stdout maxBuffer length exceeded");P.code="ERR_CHILD_PROCESS_STDIO_MAXBUFFER",P.killed=!0,P.stdout=f,P.stderr=l,o(P,f,l)}else if(N!==0){let P=new Error("Command failed: "+e);P.code=N,P.stdout=f,P.stderr=l,o(P,f,l)}else o(null,f,l)}),A.on("error",_=>{o&&o(_,f,l)}),A}function DV(e,t,r){let n=[],i={};Array.isArray(t)?(n=t,i=r||{}):i=t||{};let s=i.maxBuffer??1024*1024,o=DR(e,n,{...i,maxBuffer:s});if(o.error&&String(o.error.code)==="ERR_CHILD_PROCESS_STDIO_MAXBUFFER")throw o.error;if(o.status!==0){let a=new Error("Command failed: "+e);throw a.status=o.status??void 0,a.stdout=String(o.stdout),a.stderr=String(o.stderr),a}return i.encoding==="buffer"||!i.encoding||typeof o.stdout=="string"?o.stdout:o.stdout.toString(i.encoding)}function TV(e,t,r){if(typeof e!="string"||e.length===0)throw new TypeError('The "modulePath" argument must be of type string');let n=[],i={};Array.isArray(t)?(n=t.slice(),i=r||{}):i=t||{};let s=i.cwd??(typeof process<"u"?process.cwd():"/"),o=Array.isArray(i.execArgv)?i.execArgv:typeof process<"u"&&Array.isArray(process.execArgv)?process.execArgv:[],a={...typeof process<"u"?process.env:{},...i.env||{},AGENTOS_NODE_IPC:"1"},A=l0(i.execPath||(typeof process<"u"?process.execPath:"node"),[...o,e,...n],{...i,cwd:s,env:a,shell:!1});return A._ipcEnabled=!0,A.connected=!0,A}var NV={ChildProcess:RR,exec:_V,execSync:vV,spawn:l0,spawnSync:DR,execFile:RV,execFileSync:DV,fork:TV};Ge("_childProcessModule",NV);var B2e=NV,oi={},Cn={},R2=new Ru,hY="process.stdin",Or="",D2=!1,Zm=!1,gB=!1,pB=!1;Du("_stdinData",typeof _processConfig<"u"&&_processConfig.stdin||"");Du("_stdinPosition",0);Du("_stdinEnded",!1);Du("_stdinFlowMode",!1);function Da(){return globalThis._stdinData}function I2e(e){globalThis._stdinData=e}function uu(){return globalThis._stdinPosition}function TR(e){globalThis._stdinPosition=e}function OA(){return globalThis._stdinEnded}function NR(e){globalThis._stdinEnded=e}function YB(){return globalThis._stdinFlowMode}function Mg(e){globalThis._stdinFlowMode=e}function b2e(e){Or="",D2=!1,R2=e,gB=!1,pB=!1}function T1(){if(!(OA()||!Da())&&YB()&&uu()0}function i0(e){if(e){if(!Zm&&typeof _registerHandle=="function")try{_registerHandle(hY,"process.stdin"),Zm=!0}catch{}return}if(Zm&&typeof _unregisterHandle=="function"){try{_unregisterHandle(hY)}catch{}Zm=!1}}function fI(){if(!YB()||Or.length===0)return;let e=Or;Or="";let t=NA.encoding?e:_e.Buffer.from(e);n0("data",t),Qu()}function Qu(){!OA()||pB||Or.length>0||gB||(gB=!0,queueMicrotask(()=>{gB=!1,!(!OA()||pB||Or.length>0)&&(pB=!0,n0("end"),n0("close"),i0(!1))}))}function MV(){OA()||(NR(!0),fI(),Qu())}function cu(){return typeof __runtimeStreamStdin<"u"&&!!__runtimeStreamStdin}function N1(){D2||!DA()&&!cu()||(D2=!0,i0(!NA.paused),!cu()&&(typeof _kernelStdinRead>"u"||(async()=>{try{for(;!OA()&&!(typeof _kernelStdinRead>"u");){let e=await _kernelStdinRead.apply(void 0,[65536,100],{result:{promise:!0}});if(e?.done)break;let t=String(e?.dataBase64??"");t&&(Or+=R2.decode(_e.Buffer.from(t,"base64"),{stream:!0}),fI())}}catch{}Or+=R2.decode(),MV()})()))}function C2e(e,t){if(e==="stdin_end"){MV();return}if(e!=="stdin"||OA())return;let r,n=!1;if(t&&typeof t=="object"&&typeof t.dataBase64=="string"){let i=_e.Buffer.from(t.dataBase64,"base64");if(i.length===0)return;if(!NA.encoding&&YB()){n0("data",i),Qu();return}r=NA.encoding?i.toString(NA.encoding):i.toString("latin1"),n=!NA.encoding}else r=typeof t=="string"?t:t==null?"":_e.Buffer.from(t).toString("utf8");if(r){if(Or+=r,n&&!NA.encoding&&YB()){let i=Or;Or="",n0("data",_e.Buffer.from(i,"latin1")),Qu();return}fI()}}var NA={readable:!0,paused:!0,encoding:null,isRaw:!1,read(e){if(Or.length>0){if(!e||e>=Or.length){let n=Or;return Or="",n}let r=Or.slice(0,e);return Or=Or.slice(e),r}if(uu()>=Da().length)return null;let t=e?Da().slice(uu(),uu()+e):Da().slice(uu());return TR(uu()+t.length),t},on(e,t){return oi[e]||(oi[e]=[]),oi[e].push(t),(DA()||cu())&&(e==="data"||e==="end"||e==="close")&&N1(),e==="data"&&this.paused&&this.resume(),(e==="end"||e==="close")&&(DA()||cu())&&Qu(),e==="end"&&Da()&&!OA()&&(Mg(!0),T1()),this},once(e,t){return Cn[e]||(Cn[e]=[]),Cn[e].push(t),(DA()||cu())&&(e==="data"||e==="end"||e==="close")&&N1(),e==="data"&&this.paused&&this.resume(),(e==="end"||e==="close")&&(DA()||cu())&&Qu(),e==="end"&&Da()&&!OA()&&(Mg(!0),T1()),this},off(e,t){if(oi[e]){let r=oi[e].indexOf(t);r!==-1&&oi[e].splice(r,1)}return this},removeListener(e,t){return this.off(e,t)},emit(e,...t){let r=[...oi[e]||[],...Cn[e]||[]];Cn[e]=[];for(let n of r)n(t[0]);return r.length>0},pause(){return this.paused=!0,Mg(!1),i0(!1),this},resume(){return(DA()||cu())&&(N1(),i0(!0)),this.paused=!1,Mg(!0),fI(),T1(),Qu(),this},setEncoding(e){return this.encoding=e,this},setRawMode(e){if(!DA())throw new Error("setRawMode is not supported when stdin is not a TTY");return typeof _ptySetRawMode<"u"&&_ptySetRawMode.applySync(void 0,[e]),this.isRaw=e,this},get isTTY(){return DA()},[Symbol.asyncIterator]:function(){let e=this,t=[],r=[],n=!1,i=null,s=()=>{for(;r.length>0;){if(i){r.shift()(Promise.reject(i));continue}if(t.length>0){r.shift()(Promise.resolve({done:!1,value:t.shift()}));continue}if(n){r.shift()(Promise.resolve({done:!0,value:void 0}));continue}break}},o=f=>{t.push(f),s()},a=()=>{n=!0,s()},A=f=>{i=f,n=!0,s()};return e.on("end",a),e.on("close",a),e.on("error",A),e.on("data",o),e.resume(),{next(){return i?Promise.reject(i):t.length>0?Promise.resolve({done:!1,value:t.shift()}):n?Promise.resolve({done:!0,value:void 0}):new Promise(f=>{r.push(f)})},return(){return n=!0,e.off?.("data",o),e.off?.("end",a),e.off?.("close",a),e.off?.("error",A),s(),Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}}}};function FV(){return{platform:typeof _processConfig<"u"&&_processConfig.platform||"linux",arch:typeof _processConfig<"u"&&_processConfig.arch||"x64",version:typeof _processConfig<"u"&&_processConfig.version||"v22.0.0",cwd:typeof _processConfig<"u"&&_processConfig.cwd||"/root",env:typeof _processConfig<"u"&&_processConfig.env||{},argv:typeof _processConfig<"u"&&_processConfig.argv||["node","script.js"],execPath:typeof _processConfig<"u"&&_processConfig.execPath||"/usr/bin/node",pid:typeof _processConfig<"u"&&_processConfig.pid||1,ppid:typeof _processConfig<"u"&&_processConfig.ppid||0,uid:typeof _processConfig<"u"&&_processConfig.uid||0,gid:typeof _processConfig<"u"&&_processConfig.gid||0,stdin:typeof _processConfig<"u"?_processConfig.stdin:void 0,timingMitigation:typeof _processConfig<"u"&&_processConfig.timingMitigation||"off",frozenTimeMs:typeof _processConfig<"u"?_processConfig.frozenTimeMs:void 0,highResolutionTime:typeof _processConfig<"u"&&_processConfig.high_resolution_time===!0}}var wr=FV(),Q2e=typeof performance<"u"&&performance&&typeof performance.now=="function"?performance.now.bind(performance):Date.now,w2e=()=>typeof __secureExecHrNowUs=="function"?__secureExecHrNowUs()/1e3:Q2e();function Gl(){return wr.timingMitigation==="freeze"&&typeof wr.frozenTimeMs=="number"?wr.frozenTimeMs:w2e()}var S2e=Gl(),$m=void 0,Ts=!1,MR=class extends Error{constructor(t){super("process.exit("+t+")");y(this,"code");y(this,"_isProcessExit");this.name="ProcessExitError",this.code=t,this._isProcessExit=!0}};Ge("ProcessExitError",MR);var FR={SIGHUP:1,SIGINT:2,SIGQUIT:3,SIGILL:4,SIGTRAP:5,SIGABRT:6,SIGBUS:7,SIGFPE:8,SIGKILL:9,SIGUSR1:10,SIGSEGV:11,SIGUSR2:12,SIGPIPE:13,SIGALRM:14,SIGTERM:15,SIGCHLD:17,SIGCONT:18,SIGSTOP:19,SIGTSTP:20,SIGTTIN:21,SIGTTOU:22,SIGURG:23,SIGXCPU:24,SIGXFSZ:25,SIGVTALRM:26,SIGPROF:27,SIGWINCH:28,SIGIO:29,SIGPWR:30,SIGSYS:31},kV=Object.fromEntries(Object.entries(FR).map(([e,t])=>[t,e])),_2e=new Set(["SIGWINCH","SIGCHLD","SIGCONT","SIGURG"]),xV=new Set(["SIGHUP","SIGINT","SIGTERM","SIGWINCH","SIGCHLD"]);function UV(e){if(e==null)return 15;if(typeof e=="number")return e;let t=FR[e];if(t!==void 0)return t;throw new Error("Unknown signal: "+e)}function v2e(e){return typeof e=="string"&&xV.has(e)}var dY={ESRCH:3,EPERM:1,EINVAL:22};function R2e(e){let t=String(e&&e.message||e||""),r=null;if(e&&typeof e.code=="string"&&Object.prototype.hasOwnProperty.call(dY,e.code)?r=e.code:/\bESRCH\b/.test(t)?r="ESRCH":/\bEINVAL\b/.test(t)?r="EINVAL":(/\bEPERM\b/.test(t)||/permission denied/i.test(t))&&(r="EPERM"),r===null)return e instanceof Error?e:new Error(t);let n=new Error(`kill ${r}`);return n.code=r,n.errno=-dY[r],n.syscall="kill",n}var cn={},$r={},Hg=10,gY=new Set;function LV(e){return(cn[e]||[]).length+($r[e]||[]).length}function kl(e){if(!v2e(e)||typeof _processSignalState>"u")return;let t=FR[e];if(typeof t!="number")return;let r=LV(e)>0?"user":"default";try{_processSignalState.applySyncPromise(void 0,[t,r,JSON.stringify([]),0])}catch{}}function D2e(){for(let e of xV)kl(e)}function T2(e,t="default"){let r=UV(e);if(r===0)return!0;let n=kV[r]??`SIG${r}`;return t==="ignore"||MA(n,n)||_2e.has(n)?!0:Qe.exit(128+r)}function T2e(e,t){if(e!=="signal"||t===null||typeof t!="object")return;let r=t.signal??t.number,n=typeof t.action=="string"?t.action:"default";T2(r,n)}function M1(e,t,r=!1){let n=r?$r:cn;if(n[e]||(n[e]=[]),n[e].push(t),Hg>0&&!gY.has(e)){let i=(cn[e]?.length??0)+($r[e]?.length??0);if(i>Hg){gY.add(e);let s=`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${i} ${e} listeners added to [process]. MaxListeners is ${Hg}. Use emitter.setMaxListeners() to increase limit`;typeof _error<"u"&&_error.applySync(void 0,[s])}}return kl(e),Qe}function N2e(e,t){if(cn[e]){let r=cn[e].indexOf(t);r!==-1&&cn[e].splice(r,1)}if($r[e]){let r=$r[e].indexOf(t);r!==-1&&$r[e].splice(r,1)}return kl(e),Qe}function MA(e,...t){let r=!1;if(cn[e])for(let n of cn[e])n.call(Qe,...t),r=!0;if($r[e]){let n=$r[e].slice();$r[e]=[];for(let i of n)i.call(Qe,...t),r=!0}return r}function uI(e){return!!(e&&typeof e=="object"&&(e._isProcessExit===!0||e.name==="ProcessExitError"))}function M2e(e){return e instanceof Error?e:new Error(String(e))}function jl(e){if(uI(e))return{handled:!1,rethrow:e};let t=M2e(e);try{if(MA("uncaughtException",t,"uncaughtException"))return{handled:!0,rethrow:null}}catch(r){return{handled:!1,rethrow:r}}return{handled:!1,rethrow:t}}function PV(e){j2(()=>{throw e},0)}function zl(e,t,r){if(!t||t.length===0)return!1;for(let n of t.slice())try{n.call(e,...r)}catch(i){let s=jl(i);if(!s.handled&&s.rethrow!==null)throw s.rethrow;return!0}return!0}function DA(){return Gg().stdinIsTTY}Ge("_stdinDispatch",C2e);Ge("_signalDispatch",T2e);function OV(e){let t=Gl(),r=Math.floor(t/1e3),n=Math.floor(t%1e3*1e6);if(e){let i=r-e[0],s=n-e[1];return s<0&&(i-=1,s+=1e9),[i,s]}return[r,n]}OV.bigint=function(){let e=Gl();return BigInt(Math.floor(e*1e6))};var N2=wr.cwd,EB=18,Fg={node:wr.version.replace(/^v/,""),v8:"11.3.244.8",uv:"1.44.2",zlib:"1.2.13",brotli:"1.0.9",ares:"1.19.0",modules:"108",nghttp2:"1.52.0",napi:"8",llhttp:"8.1.0",openssl:"3.0.8",cldr:"42.0",icu:"72.1",tz:"2022g",unicode:"15.0"};function F2e(){return{rss:50*1024*1024,heapTotal:20*1024*1024,heapUsed:10*1024*1024,external:1*1024*1024,arrayBuffers:500*1024}}function HV(){let e=F2e(),t=k1e.applySyncPromise(void 0,[]);return!t||typeof t!="object"?e:{rss:Number.isFinite(t.rss)?Number(t.rss):e.rss,heapTotal:Number.isFinite(t.heapTotal)?Number(t.heapTotal):e.heapTotal,heapUsed:Number.isFinite(t.heapUsed)?Number(t.heapUsed):e.heapUsed,external:Number.isFinite(t.external)?Number(t.external):e.external,arrayBuffers:Number.isFinite(t.arrayBuffers)?Number(t.arrayBuffers):e.arrayBuffers}}function k2e(e){let t=x1e.applySyncPromise(void 0,[e??null]);if(t&&typeof t=="object")return{user:Number.isFinite(t.user)?Number(t.user):1e6,system:Number.isFinite(t.system)?Number(t.system):5e5};let r={user:1e6,system:5e5};return e&&typeof e=="object"?{user:r.user-Number(e.user||0),system:r.system-Number(e.system||0)}:r}function x2e(){return{userCPUTime:1e6,systemCPUTime:5e5,maxRSS:50*1024,sharedMemorySize:0,unsharedDataSize:0,unsharedStackSize:0,minorPageFault:0,majorPageFault:0,swappedOut:0,fsRead:0,fsWrite:0,ipcSent:0,ipcReceived:0,signalsCount:0,voluntaryContextSwitches:0,involuntaryContextSwitches:0}}function U2e(){let e=x2e(),t=U1e.applySyncPromise(void 0,[]);return!t||typeof t!="object"?e:{userCPUTime:Number.isFinite(t.userCPUTime)?Number(t.userCPUTime):e.userCPUTime,systemCPUTime:Number.isFinite(t.systemCPUTime)?Number(t.systemCPUTime):e.systemCPUTime,maxRSS:Number.isFinite(t.maxRSS)?Number(t.maxRSS):e.maxRSS,sharedMemorySize:Number.isFinite(t.sharedMemorySize)?Number(t.sharedMemorySize):e.sharedMemorySize,unsharedDataSize:Number.isFinite(t.unsharedDataSize)?Number(t.unsharedDataSize):e.unsharedDataSize,unsharedStackSize:Number.isFinite(t.unsharedStackSize)?Number(t.unsharedStackSize):e.unsharedStackSize,minorPageFault:Number.isFinite(t.minorPageFault)?Number(t.minorPageFault):e.minorPageFault,majorPageFault:Number.isFinite(t.majorPageFault)?Number(t.majorPageFault):e.majorPageFault,swappedOut:Number.isFinite(t.swappedOut)?Number(t.swappedOut):e.swappedOut,fsRead:Number.isFinite(t.fsRead)?Number(t.fsRead):e.fsRead,fsWrite:Number.isFinite(t.fsWrite)?Number(t.fsWrite):e.fsWrite,ipcSent:Number.isFinite(t.ipcSent)?Number(t.ipcSent):e.ipcSent,ipcReceived:Number.isFinite(t.ipcReceived)?Number(t.ipcReceived):e.ipcReceived,signalsCount:Number.isFinite(t.signalsCount)?Number(t.signalsCount):e.signalsCount,voluntaryContextSwitches:Number.isFinite(t.voluntaryContextSwitches)?Number(t.voluntaryContextSwitches):e.voluntaryContextSwitches,involuntaryContextSwitches:Number.isFinite(t.involuntaryContextSwitches)?Number(t.involuntaryContextSwitches):e.involuntaryContextSwitches}}function L2e(){Fg.node=wr.version.replace(/^v/,"");let e=L1e.applySyncPromise(void 0,[]);return e&&typeof e=="object"&&(Object.assign(Fg,e),Fg.node=wr.version.replace(/^v/,"")),Fg}var Qe={platform:wr.platform,arch:wr.arch,version:wr.version,get versions(){return L2e()},pid:wr.pid,ppid:wr.ppid,execPath:wr.execPath,execArgv:[],argv:wr.argv,argv0:wr.argv[0]||"node",title:"node",env:wr.env,config:{target_defaults:{cflags:[],default_configuration:"Release",defines:[],include_dirs:[],libraries:[]},variables:{node_prefix:"/usr",node_shared_libuv:!1}},release:{name:"node",sourceUrl:"https://nodejs.org/download/release/v20.0.0/node-v20.0.0.tar.gz",headersUrl:"https://nodejs.org/download/release/v20.0.0/node-v20.0.0-headers.tar.gz"},features:{inspector:!1,debug:!1,uv:!0,ipv6:!0,tls_alpn:!0,tls_sni:!0,tls_ocsp:!0,tls:!0},cwd(){return N2},chdir(e){let t;try{t=Lt.stat.applySyncPromise(void 0,[e])}catch{let n=new Error(`ENOENT: no such file or directory, chdir '${e}'`);throw n.code="ENOENT",n.errno=-2,n.syscall="chdir",n.path=e,n}if(!Ma(t).isDirectory){let n=new Error(`ENOTDIR: not a directory, chdir '${e}'`);throw n.code="ENOTDIR",n.errno=-20,n.syscall="chdir",n.path=e,n}N2=e},get exitCode(){return $m},set exitCode(e){$m=e??void 0},exit(e){let t=e!==void 0?e:$m??0;$m=t,Ts=!0;try{MA("exit",t)}catch{}throw new MR(t)},abort(){return Qe.kill(Qe.pid,"SIGABRT")},nextTick(e,...t){let r=xa();nB.push({callback:Ll(e,r),args:t}),LQe()},hrtime:OV,getuid(){return w2()},getgid(){return dB()},geteuid(){let e=globalThis.process?.euid;return Number.isFinite(e)?e:w2()},getegid(){let e=globalThis.process?.egid;return Number.isFinite(e)?e:dB()},getgroups(){return Array.isArray(globalThis.process?.groups)&&globalThis.process.groups.length>0?[...globalThis.process.groups]:[dB()]},setuid(){},setgid(){},seteuid(){},setegid(){},setgroups(){},umask(e){let t=e===void 0?void 0:Sa(e,"mask"),r=Number(F1e.applySyncPromise(void 0,[t??null]));if(Number.isFinite(r))return EB=t??r,r;let n=EB;return t!==void 0&&(EB=t),n},uptime(){return(Gl()-S2e)/1e3},memoryUsage(){return HV()},cpuUsage(e){return k2e(e)},resourceUsage(){return U2e()},kill(e,t){if(typeof e!="number"||!Number.isFinite(e)||!Number.isInteger(e))throw new TypeError(`The "pid" argument must be an integer. Received ${String(e)}`);let r=UV(t),n=kV[r]??`SIG${r}`;if(typeof _processKill<"u"){let i;try{i=_processKill.applySyncPromise(void 0,[e,n])}catch(o){throw R2e(o)}let s=i;if(typeof s=="string")try{s=JSON.parse(s)}catch{s=null}if(s&&typeof s=="object"&&s.self===!0){let o=typeof s.action=="string"?s.action:"default";return T2(r,o)}return!0}if(e!==Qe.pid){let i=new Error("Operation not permitted");throw i.code="EPERM",i.errno=-1,i.syscall="kill",i}return T2(r,"default")},on(e,t){return M1(e,t)},once(e,t){return M1(e,t,!0)},removeListener(e,t){return N2e(e,t)},off:null,removeAllListeners(e){return e?(delete cn[e],delete $r[e],kl(e)):(Object.keys(cn).forEach(t=>delete cn[t]),Object.keys($r).forEach(t=>delete $r[t]),D2e()),Qe},addListener(e,t){return M1(e,t)},emit(e,...t){return MA(e,...t)},listeners(e){return[...cn[e]||[],...$r[e]||[]]},listenerCount(e){return LV(e)},prependListener(e,t){return cn[e]||(cn[e]=[]),cn[e].unshift(t),kl(e),Qe},prependOnceListener(e,t){return $r[e]||($r[e]=[]),$r[e].unshift(t),kl(e),Qe},eventNames(){return[...new Set([...Object.keys(cn),...Object.keys($r)])]},setMaxListeners(e){return Hg=e,Qe},getMaxListeners(){return Hg},rawListeners(e){return Qe.listeners(e)},stdout:X2,stderr:Z2,stdin:NA,connected:wr.env?.AGENTOS_NODE_IPC==="1",mainModule:void 0,emitWarning(e){if(e&&typeof e=="object"){typeof e.message!="string"&&(e.message=String(e.message??"")),(typeof e.name!="string"||e.name.length===0)&&(e.name="Warning"),MA("warning",e);return}MA("warning",{message:String(e??""),name:"Warning"})},binding(e){let t=new Error("process.binding is not supported in sandbox");throw t.code="ERR_ACCESS_DENIED",t},_linkedBinding(e){let t=new Error("process._linkedBinding is not supported in sandbox");throw t.code="ERR_ACCESS_DENIED",t},dlopen(){throw new Error("process.dlopen is not supported")},hasUncaughtExceptionCaptureCallback(){return!1},setUncaughtExceptionCaptureCallback(){},send(e,t,r,n){let i=typeof t=="function"?t:typeof r=="function"?r:n;if(!Qe.connected)return!1;try{return Qe.stdout.write(bV(e)),i&&queueMicrotask(()=>i(null)),!0}catch(s){if(i)return queueMicrotask(()=>i(s)),!1;throw s}},disconnect(){Qe.connected&&(Qe.connected=!1,Qe._agentOSIpcHandleId&&typeof _unregisterHandle=="function"&&(_unregisterHandle(Qe._agentOSIpcHandleId),Qe._agentOSIpcHandleId=null),MA("disconnect"))},report:{directory:"",filename:"",compact:!1,signal:"SIGUSR2",reportOnFatalError:!1,reportOnSignal:!1,reportOnUncaughtException:!1,getReport(){return{}},writeReport(){return""}},debugPort:9229,_cwd:wr.cwd,_umask:18};function qV(){if(!(wr.env?.AGENTOS_NODE_IPC==="1"||globalThis.__agentOSProcessConfigEnv?.AGENTOS_NODE_IPC==="1")||Qe._agentOSIpcInstalled)return;Qe._agentOSIpcInstalled=!0,Qe.connected=!0,!Qe._agentOSIpcHandleId&&typeof _registerHandle=="function"&&(Qe._agentOSIpcHandleId=`process-ipc:${Qe.pid}`,_registerHandle(Qe._agentOSIpcHandleId,"child_process IPC channel"));let t="";Qe.stdin.on("data",r=>{let n=CV(t,r);t=n.buffer;for(let i of n.messages)MA("message",i,void 0)})}function P2e(e){i0(!1),b2e(new Ru);for(let t of Object.keys(oi))oi[t]=[];for(let t of Object.keys(Cn))Cn[t]=[];I2e(e.stdin??""),TR(0),NR(!1),Mg(!1),wr=e,N2=e.cwd,Qe.platform=e.platform,Qe.arch=e.arch,Qe.version=e.version,Qe.pid=e.pid,Qe.ppid=e.ppid,Qe.execPath=e.execPath,Qe.argv=e.argv,Qe.argv0=e.argv[0]||"node",Qe.env=e.env,Qe.connected=e.env?.AGENTOS_NODE_IPC==="1",Qe._cwd=e.cwd,Qe.stdin.paused=!0,Qe.stdin.encoding=null,Qe.stdin.isRaw=!1,Fg.node=e.version.replace(/^v/,"")}Ge("__runtimeRefreshProcessConfig",()=>{P2e(FV())});Qe.off=Qe.removeListener;Ge("__runtimeInstallProcessIpcBridge",qV);qV();Qe.memoryUsage.rss=function(){return HV().rss};Object.defineProperty(Qe,Symbol.toStringTag,{value:"process",writable:!1,configurable:!0,enumerable:!1});var GV=Qe;function O2e(e){return encodeURIComponent(String(e)).replace(/%2F/g,"/")}function pY(e){let t=qr.posix.resolve(String(e||"/")),r=O2e(t);return new Qn(`file://${r.startsWith("/")?r:`/${r}`}`)}function EY(e){let t=e instanceof Qn?e.href:String(e??"");if(!t.startsWith("file:"))throw new TypeError("The URL must be of scheme file");let r=t.slice(5);return r.startsWith("//")&&(r=/^\/\/[^/]*(.*)$/.exec(r)?.[1]||"/"),r=r.split(/[?#]/,1)[0]||"/",r=decodeURIComponent(r),r.startsWith("/")||(r=`/${r}`),r}function YV(){let e=globalThis;e.process=Qe,e.setTimeout=j2,e.clearTimeout=ZB,e.setInterval=z2,e.clearInterval=K2,e.setImmediate=IB,e.clearImmediate=GY;let t=typeof e.queueMicrotask=="function"?e.queueMicrotask.bind(e):_a;e.queueMicrotask=i=>{let s=xa();return t(()=>KB(s,i,e,[]))},Rve(e),e.TextEncoder=U2,e.TextDecoder=Ru,e.Event=Ul,e.CustomEvent=F2,e.EventTarget=jB,typeof e.Buffer>"u"&&(e.Buffer=xY);let r=e.Buffer;typeof r.kMaxLength!="number"&&(r.kMaxLength=Yl),typeof r.kStringMaxLength!="number"&&(r.kStringMaxLength=o0),(typeof r.constants!="object"||r.constants===null)&&(r.constants=RY);let n=globalThis.__secureExecBuiltinUtilModule;if(n?.types&&(n.types.isProxy=()=>!1),iB(n),typeof e.atob>"u"||typeof e.btoa>"u"){let i=vY();typeof e.atob>"u"&&(e.atob=s=>{let o=i.toByteArray(String(s)),a="";for(let A of o)a+=String.fromCharCode(A);return a}),typeof e.btoa>"u"&&(e.btoa=s=>{let o=String(s),a=new Uint8Array(o.length);for(let A=0;A255)throw new TypeError("Invalid character");a[A]=f}return i.fromByteArray(a)})}if(typeof e.Crypto>"u"&&(e.Crypto=CR),typeof e.SubtleCrypto>"u"&&(e.SubtleCrypto=bR),typeof e.CryptoKey>"u"&&(e.CryptoKey=Zg),typeof e.DOMException>"u"&&(e.DOMException=qve),typeof e.crypto>"u")e.crypto=Ra;else{let i=e.crypto;for(let[s,o]of Object.entries(Ra))typeof i[s]>"u"&&(i[s]=o)}e.fetch=rI,e.Headers=Qwe,e.Request=wwe,e.Response=Swe,cwe(e)}var WV={register:"kernelHandleRegister",unregister:"kernelHandleUnregister",list:"kernelHandleList"},WB=new Map,yB=[];function VV(e,t){try{s0(WV.register,e,t)}catch(r){throw r instanceof Error&&r.message.includes("EAGAIN")?new Error("ERR_RESOURCE_BUDGET_EXCEEDED: maximum active handles exceeded"):r}WB.set(e,t)}function JV(e){WB.delete(e);let t=WB.size;try{s0(WV.unregister,e)}catch{}if(t===0&&yB.length>0){let r=yB;yB=[],r.forEach(n=>n())}}function jV(){if(typeof Ts<"u"&&Ts)return Promise.resolve();let e=globalThis._getPendingTimerCount,t=globalThis._waitForTimerDrain,r=VB().length>0,n=typeof e=="function"&&e()>0;if(!r&&!n)return Promise.resolve();let i=[];return r&&i.push(new Promise(s=>{let o=!1,a=()=>{o||(o=!0,s())};yB.push(a),VB().length===0&&a()})),n&&typeof t=="function"&&i.push(t()),Promise.all(i).then(()=>{})}function VB(){return Array.from(WB.values())}Ge("_registerHandle",VV);Ge("_unregisterHandle",JV);Ge("_waitForActiveHandles",jV);Ge("_getActiveHandles",VB);var H2e={},q2e={},G2e={id:"/.js",filename:"/.js",dirname:"/",exports:{},loaded:!1};Du("_moduleCache",H2e);Du("_pendingModules",q2e);Du("_currentModule",G2e);function mB(e){let t=e.lastIndexOf("/");return t===-1?".":t===0?"/":e.slice(0,t)}function Y2e(e){if(e.startsWith("file://")){let t=e.slice(7);return t.startsWith("/")?t:"/"+t}return e}function W2e(e,t){return Xr.isBuiltin(t)?null:t.startsWith("./")||t.startsWith("../")||t.startsWith("/")?[e]:Xr._nodeModulePaths(e)}function zV(e){let t=function(r,n){let i=_resolveModule.applySyncPromise(void 0,[r,e,"require"]);if(i===null){let s=new Error("Cannot find module '"+r+"'");throw s.code="MODULE_NOT_FOUND",s}return i};return t.paths=function(r){return W2e(e,r)},t}var KV={".js":function(e,t){},".json":function(e,t){},".node":function(e,t){throw new Error(".node extensions are not supported in sandbox")}};function XV(e){return e.cache=_moduleCache,e.main=globalThis.process?.mainModule,e.extensions=KV,e}function V2e(e){let t=new Error(`require() of ES Module ${e} is not supported.`);return t.code="ERR_REQUIRE_ESM",t}function J2e(e){let t=new Error(`secure-exec module format bridge is not registered; cannot require ${e}.`);return t.code="ERR_AGENTOS_MODULE_FORMAT_BRIDGE_MISSING",t}function ZV(e){if(typeof _moduleFormat>"u"||typeof _moduleFormat.applySyncPromise!="function")throw J2e(e);if(_moduleFormat.applySyncPromise(void 0,[e])==="module")throw V2e(e)}function cI(e){if(typeof e!="string"&&!(e instanceof URL))throw new TypeError("filename must be a string or URL");let t=Y2e(String(e)),r=mB(t),n=zV(r),i=function(o){},s=function(o){return i(o),_requireFrom(o,r)};return s.resolve=n,XV(s)}ln("__secureExecGuestCreateRequire",cI);var wo,Xr=(wo=class{constructor(t,r){y(this,"id");y(this,"path");y(this,"exports");y(this,"filename");y(this,"loaded");y(this,"children");y(this,"paths");y(this,"parent");y(this,"isPreloading");this.id=t,this.path=mB(t),this.exports={},this.filename=t,this.loaded=!1,this.children=[],this.paths=[],this.parent=r,this.isPreloading=!1;let n=this.path;for(;n!=="/";)this.paths.push(n+"/node_modules"),n=mB(n);this.paths.push("/node_modules")}require(t){return _requireFrom(t,this.path)}_compile(t,r){let n=String(t)+` -//# sourceURL=`+String(r),i=new Function("exports","require","module","__filename","__dirname",n),s=a=>(rV(a),_requireFrom(a,this.path));s.resolve=zV(this.path),XV(s);let o=globalThis._currentModule;globalThis._currentModule=this;try{return i(this.exports,s,this,r,this.path),this.loaded=!0,this.exports}finally{globalThis._currentModule=o}}static _resolveFilename(t,r,n,i){let s=r&&r.path?r.path:"/",o=_resolveModule.applySyncPromise(void 0,[t,s,"require"]);if(o===null){let a=new Error("Cannot find module '"+t+"'");throw a.code="MODULE_NOT_FOUND",a}return o}static wrap(t){return"(function (exports, require, module, __filename, __dirname) { "+t+` -});`}static isBuiltin(t){let r=t.replace(/^node:/,"");return wo.builtinModules.includes(r)}static syncBuiltinESMExports(){}static findSourceMap(t){}static _nodeModulePaths(t){let r=[],n=t;for(;n!=="/"&&(r.push(n+"/node_modules"),n=mB(n),n!=="."););return r.push("/node_modules"),r}static _load(t,r,n){let i=r&&r.path?r.path:"/";return _requireFrom(t,i)}static runMain(){}},y(wo,"_extensions",{...KV,".js":function(t,r){ZV(r);let n=typeof _loadFile<"u"?_loadFile.applySyncPromise(void 0,[r]):_requireFrom("fs","/").readFileSync(r,"utf8");t._compile(n,r)},".json":function(t,r){let n=typeof _loadFile<"u"?_loadFile.applySyncPromise(void 0,[r]):_requireFrom("fs","/").readFileSync(r,"utf8");t.exports=JSON.parse(n)}}),y(wo,"_cache",typeof _moduleCache<"u"?_moduleCache:{}),y(wo,"builtinModules",Tve),y(wo,"createRequire",cI),wo),$V=class{constructor(e){throw new Error("SourceMap is not implemented in sandbox")}get payload(){throw new Error("SourceMap is not implemented in sandbox")}set payload(e){throw new Error("SourceMap is not implemented in sandbox")}findEntry(e,t){throw new Error("SourceMap is not implemented in sandbox")}},eJ=Object.assign(Xr,{Module:Xr,createRequire:cI,_extensions:Xr._extensions,_cache:Xr._cache,builtinModules:Xr.builtinModules,isBuiltin:Xr.isBuiltin,_resolveFilename:Xr._resolveFilename,wrap:Xr.wrap,syncBuiltinESMExports:Xr.syncBuiltinESMExports,findSourceMap:Xr.findSourceMap,SourceMap:$V});Ge("_moduleModule",eJ);function j2e(e,t){let r=typeof t=="string"?t:"/";if(Xr.isBuiltin(e))try{return Hve(e)}catch(s){if(s?.code!=="MODULE_NOT_FOUND")throw s}let n=_resolveModule.applySyncPromise(void 0,[e,r,"require"]);if(n===null){let s=new Error(`Cannot find module '${e}'`);throw s.code="MODULE_NOT_FOUND",s}if(Object.prototype.hasOwnProperty.call(_moduleCache,n))return _moduleCache[n].exports;ZV(n);let i=new Xr(n,{path:r});_moduleCache[n]=i;try{let s=n.endsWith(".json")?".json":n.endsWith(".node")?".node":".js";return(Xr._extensions[s]??Xr._extensions[".js"])(i,n),i.loaded=!0,i.exports}catch(s){throw delete _moduleCache[n],s}}Ge("_requireFrom",j2e);var z2e=eJ,K2e={};O2(K2e,{Buffer:()=>xY,CustomEvent:()=>F2,Event:()=>Ul,EventTarget:()=>jB,Module:()=>Xr,ProcessExitError:()=>MR,SourceMap:()=>$V,TextDecoder:()=>Ru,TextEncoder:()=>U2,URL:()=>Qn,URLSearchParams:()=>Hr,_getActiveHandles:()=>VB,_registerHandle:()=>VV,_unregisterHandle:()=>JV,_waitForActiveHandles:()=>jV,childProcess:()=>IV,clearImmediate:()=>GY,clearInterval:()=>K2,clearTimeout:()=>ZB,createRequire:()=>cI,cryptoPolyfill:()=>Rl,default:()=>X2e,fs:()=>wR,module:()=>z2e,network:()=>JW,os:()=>u2e,process:()=>GV,setImmediate:()=>IB,setInterval:()=>z2,setTimeout:()=>j2,setupGlobals:()=>YV});var X2e=wR;YV();})(); -/*! Bundled license information: - -ieee754/index.js: -(*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh *) - -buffer/index.js: -(*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) -*/ -/*! Bundled license information: - -ieee754/index.js: - (*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh *) - -buffer/index.js: - (*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) - -punycode/punycode.js: - (*! https://mths.be/punycode v1.4.1 by @mathias *) - -safe-buffer/index.js: - (*! safe-buffer. MIT License. Feross Aboukhadijeh *) - -web-streams-polyfill/dist/ponyfill.es2018.js: - (** - * @license - * web-streams-polyfill v3.3.3 - * Copyright 2024 Mattias Buelens, Diwank Singh Tomer and other contributors. - * This code is released under the MIT license. - * SPDX-License-Identifier: MIT - *) - -assert/build/internal/util/comparisons.js: - (*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - *) - -undici/lib/web/fetch/body.js: - (*! formdata-polyfill. MIT License. Jimmy Wärting *) -*/ diff --git a/crates/v8-runtime/build.rs b/crates/v8-runtime/build.rs deleted file mode 100644 index 13f4d29d5..000000000 --- a/crates/v8-runtime/build.rs +++ /dev/null @@ -1,95 +0,0 @@ -use std::env; -use std::fs; -use std::path::{Path, PathBuf}; - -fn cargo_home() -> PathBuf { - if let Some(home) = env::var_os("CARGO_HOME") { - return PathBuf::from(home); - } - - let home = env::var_os("HOME").expect("HOME must be set when CARGO_HOME is unset"); - PathBuf::from(home).join(".cargo") -} - -fn read_v8_version(lock_path: &Path) -> String { - let lock = fs::read_to_string(lock_path) - .unwrap_or_else(|error| panic!("failed to read {}: {}", lock_path.display(), error)); - - let mut in_v8_package = false; - for line in lock.lines() { - match line.trim() { - "[[package]]" => in_v8_package = false, - "name = \"v8\"" => in_v8_package = true, - _ if in_v8_package && line.trim_start().starts_with("version = \"") => { - let version = line - .trim() - .trim_start_matches("version = \"") - .trim_end_matches('"'); - return version.to_owned(); - } - _ => {} - } - } - - panic!("failed to locate v8 version in {}", lock_path.display()); -} - -fn find_v8_icu_data(v8_version: &str) -> PathBuf { - let registry_src = cargo_home().join("registry").join("src"); - let candidates = [ - Path::new("third_party/icu/common/icudtl.dat"), - Path::new("third_party/icu/flutter_desktop/icudtl.dat"), - Path::new("third_party/icu/chromecast_video/icudtl.dat"), - ]; - - let entries = fs::read_dir(®istry_src).unwrap_or_else(|error| { - panic!( - "failed to read cargo registry src {}: {}", - registry_src.display(), - error - ) - }); - - for entry in entries { - let entry = entry - .unwrap_or_else(|error| panic!("failed to inspect cargo registry entry: {}", error)); - let crate_root = entry.path().join(format!("v8-{}", v8_version)); - for relative in candidates { - let candidate = crate_root.join(relative); - if candidate.exists() { - return candidate; - } - } - } - - panic!( - "failed to locate ICU data for v8-{} under {}", - v8_version, - registry_src.display(), - ); -} - -fn main() { - let manifest_dir = - PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set")); - let lock_path = manifest_dir.join("Cargo.lock"); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR must be set")); - - println!("cargo:rerun-if-changed={}", lock_path.display()); - println!("cargo:rerun-if-changed=build.rs"); - - secure_exec_build_support::build_v8_bridge(&manifest_dir, &out_dir); - - let v8_version = read_v8_version(&lock_path); - let icu_data = find_v8_icu_data(&v8_version); - let dest_path = out_dir.join("icudtl.dat"); - - fs::copy(&icu_data, &dest_path).unwrap_or_else(|error| { - panic!( - "failed to copy ICU data from {} to {}: {}", - icu_data.display(), - dest_path.display(), - error, - ) - }); -} diff --git a/crates/v8-runtime/npm/.gitignore b/crates/v8-runtime/npm/.gitignore deleted file mode 100644 index c37406f79..000000000 --- a/crates/v8-runtime/npm/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Platform binaries are placed here by CI, not committed -*/secure-exec-v8 -*/secure-exec-v8.exe diff --git a/crates/v8-runtime/npm/linux-x64-gnu/README.md b/crates/v8-runtime/npm/linux-x64-gnu/README.md deleted file mode 100644 index 92e31968e..000000000 --- a/crates/v8-runtime/npm/linux-x64-gnu/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# @secure-exec/v8-linux-x64-gnu - -Linux x64 (glibc) binary for [@secure-exec/v8](https://secureexec.dev). - -This package is installed automatically by `@secure-exec/v8` as a platform-specific optional dependency. - -- Website: https://secureexec.dev -- Docs: https://secureexec.dev/docs -- GitHub: https://github.com/rivet-dev/secure-exec diff --git a/crates/v8-runtime/rust-toolchain.toml b/crates/v8-runtime/rust-toolchain.toml deleted file mode 100644 index c1bc0a694..000000000 --- a/crates/v8-runtime/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "1.85.0" diff --git a/crates/v8-runtime/src/bridge.rs b/crates/v8-runtime/src/bridge.rs deleted file mode 100644 index 4fbae2cf9..000000000 --- a/crates/v8-runtime/src/bridge.rs +++ /dev/null @@ -1,2671 +0,0 @@ -// Host function injection via v8::FunctionTemplate - -use std::cell::{Cell, RefCell}; -use std::collections::{HashMap, HashSet}; -use std::ffi::c_void; -use std::mem::MaybeUninit; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::OnceLock; - -use serde::de; -use v8::MapFnTo; -use v8::ValueDeserializerHelper; -use v8::ValueSerializerHelper; - -use crate::host_call::BridgeCallContext; - -// CBOR codec flag: when true, use CBOR (via ciborium) instead of V8 -// ValueSerializer/ValueDeserializer for IPC payloads. Activated by -// SECURE_EXEC_V8_CODEC=cbor for runtimes whose node:v8 module doesn't -// produce real V8 serialization format (e.g. Bun). -static USE_CBOR_CODEC: AtomicBool = AtomicBool::new(false); -static EMBEDDED_CBOR_USERS: AtomicUsize = AtomicUsize::new(0); -const MAX_CBOR_BRIDGE_DEPTH: usize = 64; -const MAX_CBOR_BRIDGE_CONTAINER_ITEMS: usize = 100_000; -const MAX_VM_CONTEXTS: usize = 1024; -const MAX_PENDING_PROMISES: usize = 1024; - -/// Initialize the codec from the SECURE_EXEC_V8_CODEC environment variable. -/// Call once at process startup before any sessions are created. -pub fn init_codec() { - USE_CBOR_CODEC.store(configured_cbor_codec_enabled(), Ordering::Relaxed); -} - -pub fn enable_cbor_codec() { - USE_CBOR_CODEC.store(true, Ordering::Relaxed); -} - -pub fn acquire_embedded_cbor_codec() { - EMBEDDED_CBOR_USERS.fetch_add(1, Ordering::AcqRel); - USE_CBOR_CODEC.store(true, Ordering::Relaxed); -} - -pub fn release_embedded_cbor_codec() { - let previous = EMBEDDED_CBOR_USERS.fetch_sub(1, Ordering::AcqRel); - if previous <= 1 { - USE_CBOR_CODEC.store(configured_cbor_codec_enabled(), Ordering::Relaxed); - } -} - -/// Returns true if the CBOR codec is active. -pub fn is_cbor_codec() -> bool { - USE_CBOR_CODEC.load(Ordering::Relaxed) -} - -fn configured_cbor_codec_enabled() -> bool { - std::env::var("SECURE_EXEC_V8_CODEC") - .map(|val| val == "cbor") - .unwrap_or(false) -} - -/// External references for V8 snapshot serialization. -/// Maps function pointer indices in the snapshot to current addresses. -/// Must be identical at snapshot creation and restore time. -pub fn external_refs() -> &'static v8::ExternalReferences { - static REFS: OnceLock = OnceLock::new(); - REFS.get_or_init(|| { - v8::ExternalReferences::new(&[ - v8::ExternalReference { - function: sync_bridge_callback.map_fn_to(), - }, - v8::ExternalReference { - function: async_bridge_callback.map_fn_to(), - }, - ]) - }) -} - -// Minimal delegate for V8 ValueSerializer — throws DataCloneError as a V8 exception -struct DefaultSerializerDelegate; - -impl v8::ValueSerializerImpl for DefaultSerializerDelegate { - fn throw_data_clone_error<'s>( - &self, - scope: &mut v8::HandleScope<'s>, - message: v8::Local<'s, v8::String>, - ) { - let exc = v8::Exception::error(scope, message); - scope.throw_exception(exc); - } -} - -// Minimal delegate for V8 ValueDeserializer — default callbacks are sufficient -struct DefaultDeserializerDelegate; - -impl v8::ValueDeserializerImpl for DefaultDeserializerDelegate {} - -/// Serialize a V8 value to bytes using V8's built-in ValueSerializer. -/// Handles all V8 types natively: primitives, strings, arrays, objects, -/// Uint8Array, Date, Map, Set, RegExp, Error, and circular references. -/// When CBOR codec is active, uses ciborium instead. -pub fn serialize_v8_value( - scope: &mut v8::HandleScope, - value: v8::Local, -) -> Result, String> { - if is_cbor_codec() { - return serialize_cbor_value(scope, value); - } - serialize_v8_wire_value(scope, value) -} - -/// Serialize a V8 value to bytes using V8's native wire format regardless of -/// the process-wide codec toggle. -pub fn serialize_v8_wire_value( - scope: &mut v8::HandleScope, - value: v8::Local, -) -> Result, String> { - let context = scope.get_current_context(); - let serializer = v8::ValueSerializer::new(scope, Box::new(DefaultSerializerDelegate)); - serializer.write_header(); - serializer - .write_value(context, value) - .ok_or_else(|| "V8 ValueSerializer: failed to serialize value".to_string())?; - Ok(serializer.release()) -} - -/// Deserialize bytes back to a V8 value using V8's built-in ValueDeserializer. -/// The bytes must have been produced by serialize_v8_value() or node:v8.serialize(). -pub fn deserialize_v8_value<'s>( - scope: &mut v8::HandleScope<'s>, - data: &[u8], -) -> Result, String> { - if is_cbor_codec() { - return deserialize_cbor_value(scope, data); - } - deserialize_v8_wire_value(scope, data) -} - -/// Deserialize bytes from V8's native wire format regardless of the -/// process-wide codec toggle. -pub fn deserialize_v8_wire_value<'s>( - scope: &mut v8::HandleScope<'s>, - data: &[u8], -) -> Result, String> { - let context = scope.get_current_context(); - let deserializer = - v8::ValueDeserializer::new(scope, Box::new(DefaultDeserializerDelegate), data); - deserializer - .read_header(context) - .ok_or_else(|| "V8 ValueDeserializer: invalid header".to_string())?; - deserializer - .read_value(context) - .ok_or_else(|| "V8 ValueDeserializer: failed to deserialize value".to_string()) -} - -// ── CBOR codec ── - -/// Convert a V8 value to a ciborium::Value for CBOR serialization. -fn v8_to_cbor( - scope: &mut v8::HandleScope, - value: v8::Local, -) -> Result { - let mut object_stack = Vec::new(); - v8_to_cbor_inner(scope, value, 0, &mut object_stack) -} - -fn v8_to_cbor_inner( - scope: &mut v8::HandleScope, - value: v8::Local, - depth: usize, - object_stack: &mut Vec>, -) -> Result { - if depth > MAX_CBOR_BRIDGE_DEPTH { - return Err(format!( - "CBOR encode depth exceeds limit of {MAX_CBOR_BRIDGE_DEPTH}" - )); - } - - if value.is_null_or_undefined() { - return Ok(ciborium::Value::Null); - } - if value.is_boolean() { - return Ok(ciborium::Value::Bool(value.boolean_value(scope))); - } - if value.is_int32() { - return Ok(ciborium::Value::Integer( - value.int32_value(scope).unwrap_or(0).into(), - )); - } - if value.is_number() { - return Ok(ciborium::Value::Float( - value.number_value(scope).unwrap_or(0.0), - )); - } - if value.is_string() { - let s = value.to_rust_string_lossy(scope); - return Ok(ciborium::Value::Text(s)); - } - if value.is_array_buffer_view() { - let view = v8::Local::::try_from(value).unwrap(); - let len = view.byte_length(); - let mut buf = vec![0u8; len]; - view.copy_contents(&mut buf); - return Ok(ciborium::Value::Bytes(buf)); - } - if value.is_array() { - let obj = value - .to_object(scope) - .ok_or_else(|| "CBOR encode failed to convert array to object".to_string())?; - enter_cbor_object(scope, object_stack, obj)?; - let arr = v8::Local::::try_from(value).unwrap(); - let len = arr.length(); - let item_count = cbor_container_item_count("array", len as usize)?; - let mut items = Vec::with_capacity(item_count); - let result = (|| { - for i in 0..len { - if let Some(elem) = arr.get_index(scope, i) { - items.push(v8_to_cbor_inner(scope, elem, depth + 1, object_stack)?); - } else { - items.push(ciborium::Value::Null); - } - } - Ok(ciborium::Value::Array(items)) - })(); - object_stack.pop(); - return result; - } - if value.is_object() { - let obj = value.to_object(scope).unwrap(); - enter_cbor_object(scope, object_stack, obj)?; - let names = obj - .get_own_property_names(scope, v8::GetPropertyNamesArgs::default()) - .unwrap_or_else(|| v8::Array::new(scope, 0)); - let len = names.length(); - let item_count = cbor_container_item_count("object", len as usize)?; - let mut entries = Vec::with_capacity(item_count); - let result = (|| { - for i in 0..len { - let key = names.get_index(scope, i).unwrap(); - let key_str = key.to_rust_string_lossy(scope); - let val = obj - .get(scope, key) - .unwrap_or_else(|| v8::undefined(scope).into()); - entries.push(( - ciborium::Value::Text(key_str), - v8_to_cbor_inner(scope, val, depth + 1, object_stack)?, - )); - } - Ok(ciborium::Value::Map(entries)) - })(); - object_stack.pop(); - return result; - } - Ok(ciborium::Value::Null) -} - -fn enter_cbor_object( - scope: &mut v8::HandleScope, - object_stack: &mut Vec>, - object: v8::Local, -) -> Result<(), String> { - for previous in object_stack.iter() { - let previous = v8::Local::new(scope, previous); - if previous.strict_equals(object.into()) { - return Err("CBOR encode rejected circular object graph".to_string()); - } - } - object_stack.push(v8::Global::new(scope, object)); - Ok(()) -} - -fn cbor_container_item_count(kind: &str, item_count: usize) -> Result { - if item_count > MAX_CBOR_BRIDGE_CONTAINER_ITEMS { - return Err(format!( - "CBOR {kind} item count {item_count} exceeds limit of {MAX_CBOR_BRIDGE_CONTAINER_ITEMS}" - )); - } - Ok(item_count) -} - -struct LimitedCborValue(ciborium::Value); - -impl<'de> de::Deserialize<'de> for LimitedCborValue { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - deserializer.deserialize_any(LimitedCborVisitor).map(Self) - } -} - -struct LimitedCborSeed; - -impl<'de> de::DeserializeSeed<'de> for LimitedCborSeed { - type Value = ciborium::Value; - - fn deserialize(self, deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - deserializer.deserialize_any(LimitedCborVisitor) - } -} - -struct LimitedCborVisitor; - -impl<'de> de::Visitor<'de> for LimitedCborVisitor { - type Value = ciborium::Value; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("a bounded CBOR bridge value") - } - - fn visit_bool(self, value: bool) -> Result { - Ok(ciborium::Value::Bool(value)) - } - - fn visit_f32(self, value: f32) -> Result { - Ok(ciborium::Value::Float(value.into())) - } - - fn visit_f64(self, value: f64) -> Result { - Ok(ciborium::Value::Float(value)) - } - - fn visit_i8(self, value: i8) -> Result { - Ok(value.into()) - } - - fn visit_i16(self, value: i16) -> Result { - Ok(value.into()) - } - - fn visit_i32(self, value: i32) -> Result { - Ok(value.into()) - } - - fn visit_i64(self, value: i64) -> Result { - Ok(value.into()) - } - - fn visit_i128(self, value: i128) -> Result { - Ok(value.into()) - } - - fn visit_u8(self, value: u8) -> Result { - Ok(value.into()) - } - - fn visit_u16(self, value: u16) -> Result { - Ok(value.into()) - } - - fn visit_u32(self, value: u32) -> Result { - Ok(value.into()) - } - - fn visit_u64(self, value: u64) -> Result { - Ok(value.into()) - } - - fn visit_u128(self, value: u128) -> Result { - Ok(value.into()) - } - - fn visit_char(self, value: char) -> Result { - Ok(value.into()) - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - Ok(value.into()) - } - - fn visit_borrowed_str(self, value: &'de str) -> Result - where - E: de::Error, - { - Ok(value.into()) - } - - fn visit_string(self, value: String) -> Result { - Ok(value.into()) - } - - fn visit_bytes(self, value: &[u8]) -> Result - where - E: de::Error, - { - Ok(value.into()) - } - - fn visit_borrowed_bytes(self, value: &'de [u8]) -> Result - where - E: de::Error, - { - Ok(value.into()) - } - - fn visit_byte_buf(self, value: Vec) -> Result { - Ok(value.into()) - } - - fn visit_none(self) -> Result { - Ok(ciborium::Value::Null) - } - - fn visit_some(self, deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - deserializer.deserialize_any(self) - } - - fn visit_unit(self) -> Result { - Ok(ciborium::Value::Null) - } - - fn visit_newtype_struct(self, deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - deserializer.deserialize_any(self) - } - - fn visit_seq(self, mut access: A) -> Result - where - A: de::SeqAccess<'de>, - { - if let Some(item_count) = access.size_hint() { - limited_cbor_item_count("array", item_count)?; - } - - let mut items = Vec::new(); - while let Some(item) = access.next_element_seed(LimitedCborSeed)? { - limited_cbor_item_count("array", items.len() + 1)?; - items.push(item); - } - Ok(ciborium::Value::Array(items)) - } - - fn visit_map(self, mut access: A) -> Result - where - A: de::MapAccess<'de>, - { - if let Some(item_count) = access.size_hint() { - limited_cbor_item_count("map", item_count)?; - } - - let mut entries = Vec::new(); - while let Some(key) = access.next_key_seed(LimitedCborSeed)? { - limited_cbor_item_count("map", entries.len() + 1)?; - let value = access.next_value_seed(LimitedCborSeed)?; - entries.push((key, value)); - } - Ok(ciborium::Value::Map(entries)) - } - - fn visit_enum(self, access: A) -> Result - where - A: de::EnumAccess<'de>, - { - use serde::de::VariantAccess; - - struct TaggedValueVisitor; - - impl<'de> de::Visitor<'de> for TaggedValueVisitor { - type Value = ciborium::Value; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("a tagged CBOR bridge value") - } - - fn visit_seq(self, mut access: A) -> Result - where - A: de::SeqAccess<'de>, - { - let tag = access - .next_element()? - .ok_or_else(|| de::Error::custom("expected tag"))?; - let value = access - .next_element_seed(LimitedCborSeed)? - .ok_or_else(|| de::Error::custom("expected tagged value"))?; - Ok(ciborium::Value::Tag(tag, Box::new(value))) - } - } - - let (name, data): (String, _) = access.variant()?; - if name != "@@TAGGED@@" { - return Err(de::Error::custom("expected CBOR tag")); - } - data.tuple_variant(2, TaggedValueVisitor) - } -} - -fn limited_cbor_item_count(kind: &str, item_count: usize) -> Result { - cbor_container_item_count(kind, item_count).map_err(de::Error::custom) -} - -/// Convert a ciborium::Value to a V8 value. -fn cbor_to_v8<'s>( - scope: &mut v8::HandleScope<'s>, - value: &ciborium::Value, -) -> Result, String> { - cbor_to_v8_inner(scope, value, 0) -} - -fn cbor_to_v8_inner<'s>( - scope: &mut v8::HandleScope<'s>, - value: &ciborium::Value, - depth: usize, -) -> Result, String> { - if depth > MAX_CBOR_BRIDGE_DEPTH { - return Err(format!( - "CBOR decode depth exceeds limit of {MAX_CBOR_BRIDGE_DEPTH}" - )); - } - - match value { - ciborium::Value::Null => Ok(v8::null(scope).into()), - ciborium::Value::Bool(b) => Ok(v8::Boolean::new(scope, *b).into()), - ciborium::Value::Integer(n) => { - let n: i128 = (*n).into(); - if n >= i32::MIN as i128 && n <= i32::MAX as i128 { - Ok(v8::Integer::new(scope, n as i32).into()) - } else { - Ok(v8::Number::new(scope, n as f64).into()) - } - } - ciborium::Value::Float(f) => Ok(v8::Number::new(scope, *f).into()), - ciborium::Value::Text(s) => Ok(v8::String::new(scope, s) - .ok_or_else(|| "CBOR decode failed to allocate string".to_string())? - .into()), - ciborium::Value::Bytes(b) => { - let len = b.len(); - let ab = v8::ArrayBuffer::new(scope, len); - if len > 0 { - let bs = ab.get_backing_store(); - unsafe { - std::ptr::copy_nonoverlapping( - b.as_ptr(), - bs.data().unwrap().as_ptr() as *mut u8, - len, - ); - } - } - Ok(v8::Uint8Array::new(scope, ab, 0, len) - .ok_or_else(|| "CBOR decode failed to allocate byte array".to_string())? - .into()) - } - ciborium::Value::Array(items) => { - cbor_container_item_count("array", items.len())?; - let arr = v8::Array::new(scope, items.len() as i32); - for (i, item) in items.iter().enumerate() { - let val = cbor_to_v8_inner(scope, item, depth + 1)?; - arr.set_index(scope, i as u32, val); - } - Ok(arr.into()) - } - ciborium::Value::Map(entries) => { - cbor_container_item_count("map", entries.len())?; - let obj = v8::Object::new(scope); - for (k, v) in entries { - let key = cbor_to_v8_inner(scope, k, depth + 1)?; - let val = cbor_to_v8_inner(scope, v, depth + 1)?; - obj.set(scope, key, val); - } - Ok(obj.into()) - } - ciborium::Value::Tag(_, inner) => cbor_to_v8_inner(scope, inner, depth + 1), - _ => Ok(v8::undefined(scope).into()), - } -} - -fn raw_bytes_to_uint8array<'s>( - scope: &mut v8::HandleScope<'s>, - bytes: &[u8], -) -> Option> { - let len = bytes.len(); - let ab = v8::ArrayBuffer::new(scope, len); - if len > 0 { - let bs = ab.get_backing_store(); - unsafe { - std::ptr::copy_nonoverlapping(bytes.as_ptr(), bs.data()?.as_ptr() as *mut u8, len); - } - } - v8::Uint8Array::new(scope, ab, 0, len).map(Into::into) -} - -fn bridge_response_payload_to_v8<'s>( - scope: &mut v8::HandleScope<'s>, - status: u8, - payload: &[u8], -) -> Option> { - if status == 2 { - return raw_bytes_to_uint8array(scope, payload); - } - - let v8_val = { - let tc = &mut v8::TryCatch::new(scope); - deserialize_v8_value(tc, payload).ok() - }; - if v8_val.is_some() { - return v8_val; - } - - // Preserve the historical compatibility fallback for malformed/non-native - // status=0 responses, but never let status=2 raw bytes take this path. - raw_bytes_to_uint8array(scope, payload) -} - -/// Serialize a V8 value to CBOR bytes. -pub fn serialize_cbor_value( - scope: &mut v8::HandleScope, - value: v8::Local, -) -> Result, String> { - let cbor_val = v8_to_cbor(scope, value)?; - let mut buf = Vec::new(); - ciborium::into_writer(&cbor_val, &mut buf).map_err(|e| format!("CBOR encode failed: {}", e))?; - Ok(buf) -} - -/// Deserialize CBOR bytes to a V8 value. -pub fn deserialize_cbor_value<'s>( - scope: &mut v8::HandleScope<'s>, - data: &[u8], -) -> Result, String> { - let LimitedCborValue(cbor_val) = - ciborium::de::from_reader_with_recursion_limit(data, MAX_CBOR_BRIDGE_DEPTH) - .map_err(|e| format!("CBOR decode failed: {}", e))?; - cbor_to_v8(scope, &cbor_val) -} - -/// Data attached to each sync bridge function via v8::External. -/// BridgeFnStore keeps these heap allocations alive for the session. -struct SyncBridgeFnData { - ctx: *const BridgeCallContext, - method: String, -} - -/// Opaque store that keeps bridge function data alive. -/// Must be held for the lifetime of the V8 context. -pub struct BridgeFnStore { - // Box ensures stable pointer address for v8::External data when Vec grows - #[allow(clippy::vec_box)] - _data: Vec>, -} - -/// Data attached to each async bridge function via v8::External. -struct AsyncBridgeFnData { - ctx: *const BridgeCallContext, - pending: *const PendingPromises, - method: String, -} - -/// Opaque store that keeps async bridge function data alive. -/// Must be held for the lifetime of the V8 context. -pub struct AsyncBridgeFnStore { - // Box ensures stable pointer address for v8::External data when Vec grows - #[allow(clippy::vec_box)] - _data: Vec>, -} - -/// Stores pending promise resolvers keyed by call_id. -/// Single-threaded: only accessed from the session thread. -pub struct PendingPromises { - map: RefCell>>, - reserved: Cell, -} - -impl PendingPromises { - pub fn new() -> Self { - PendingPromises { - map: RefCell::new(HashMap::new()), - reserved: Cell::new(0), - } - } - - fn capacity_error(&self) -> Option { - let len = self.map.borrow().len().saturating_add(self.reserved.get()); - if len >= MAX_PENDING_PROMISES { - return Some(format!( - "async bridge pending promise registry exceeded limit of {MAX_PENDING_PROMISES} promises" - )); - } - None - } - - fn reserve(&self) -> Result, String> { - if let Some(error) = self.capacity_error() { - return Err(error); - } - self.reserved.set(self.reserved.get().saturating_add(1)); - Ok(PendingPromiseReservation { - pending: self, - active: true, - }) - } - - fn release_reservation(&self) { - self.reserved.set(self.reserved.get().saturating_sub(1)); - } - - fn insert_reserved( - &self, - call_id: u64, - resolver: v8::Global, - mut reservation: PendingPromiseReservation<'_>, - ) { - self.map.borrow_mut().insert(call_id, resolver); - reservation.active = false; - self.release_reservation(); - } - - /// Remove and return the resolver for a given call_id. - pub fn remove(&self, call_id: u64) -> Option> { - self.map.borrow_mut().remove(&call_id) - } - - /// Number of pending promises. - pub fn len(&self) -> usize { - self.map.borrow().len() - } - - /// Whether there are no pending promises. - pub fn is_empty(&self) -> bool { - self.map.borrow().is_empty() - } -} - -impl Default for PendingPromises { - fn default() -> Self { - Self::new() - } -} - -struct PendingPromiseReservation<'a> { - pending: &'a PendingPromises, - active: bool, -} - -impl Drop for PendingPromiseReservation<'_> { - fn drop(&mut self) { - if self.active { - self.pending.release_reservation(); - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct ThreadResourceUsageSnapshot { - user_cpu_us: u64, - system_cpu_us: u64, - max_rss_kib: i64, - shared_memory_size: i64, - unshared_data_size: i64, - unshared_stack_size: i64, - minor_page_faults: i64, - major_page_faults: i64, - swapped_out: i64, - fs_read: i64, - fs_write: i64, - ipc_sent: i64, - ipc_received: i64, - signals_count: i64, - voluntary_context_switches: i64, - involuntary_context_switches: i64, -} - -fn non_negative_c_long(value: libc::c_long) -> i64 { - let normalized = i128::from(value).max(0); - normalized.min(i128::from(i64::MAX)) as i64 -} - -// Used only by the non-macOS `getrusage(RUSAGE_THREAD)` path; macOS reads CPU -// time from Mach `time_value_t` instead. -#[cfg(not(target_os = "macos"))] -fn timeval_to_micros(value: libc::timeval) -> u64 { - let seconds = i128::from(value.tv_sec).max(0); - let micros = i128::from(value.tv_usec).max(0); - (seconds - .saturating_mul(1_000_000) - .saturating_add(micros) - .min(i128::from(u64::MAX))) as u64 -} - -#[cfg(not(target_os = "macos"))] -fn current_thread_resource_usage() -> Result { - let mut usage = MaybeUninit::::uninit(); - let result = unsafe { libc::getrusage(libc::RUSAGE_THREAD, usage.as_mut_ptr()) }; - if result != 0 { - return Err(format!( - "getrusage(RUSAGE_THREAD) failed: {}", - std::io::Error::last_os_error() - )); - } - let usage = unsafe { usage.assume_init() }; - Ok(ThreadResourceUsageSnapshot { - user_cpu_us: timeval_to_micros(usage.ru_utime), - system_cpu_us: timeval_to_micros(usage.ru_stime), - max_rss_kib: non_negative_c_long(usage.ru_maxrss), - shared_memory_size: non_negative_c_long(usage.ru_ixrss), - unshared_data_size: non_negative_c_long(usage.ru_idrss), - unshared_stack_size: non_negative_c_long(usage.ru_isrss), - minor_page_faults: non_negative_c_long(usage.ru_minflt), - major_page_faults: non_negative_c_long(usage.ru_majflt), - swapped_out: non_negative_c_long(usage.ru_nswap), - fs_read: non_negative_c_long(usage.ru_inblock), - fs_write: non_negative_c_long(usage.ru_oublock), - ipc_sent: non_negative_c_long(usage.ru_msgsnd), - ipc_received: non_negative_c_long(usage.ru_msgrcv), - signals_count: non_negative_c_long(usage.ru_nsignals), - voluntary_context_switches: non_negative_c_long(usage.ru_nvcsw), - involuntary_context_switches: non_negative_c_long(usage.ru_nivcsw), - }) -} - -// macOS has no `RUSAGE_THREAD`, so per-thread CPU time comes from the Mach -// `thread_info(THREAD_BASIC_INFO)` call. The remaining rusage fields have no -// per-thread source on Apple platforms, so they are filled best-effort from the -// process-wide `getrusage(RUSAGE_SELF)` (mirroring libuv's macOS behaviour). -#[cfg(target_os = "macos")] -fn macos_thread_cpu_micros() -> Result<(u64, u64), String> { - // SAFETY: `pthread_mach_thread_np` yields the calling thread's Mach port; - // `thread_info` fully initialises `info` on KERN_SUCCESS. - unsafe { - let port = libc::pthread_mach_thread_np(libc::pthread_self()); - if port == 0 { - return Err("pthread_mach_thread_np returned MACH_PORT_NULL".to_string()); - } - let mut info = MaybeUninit::::zeroed(); - let mut count = (std::mem::size_of::() - / std::mem::size_of::()) - as libc::mach_msg_type_number_t; - let rc = libc::thread_info( - port, - libc::THREAD_BASIC_INFO as libc::thread_flavor_t, - info.as_mut_ptr() as libc::thread_info_t, - &mut count, - ); - if rc != libc::KERN_SUCCESS { - return Err(format!("thread_info(THREAD_BASIC_INFO) failed: {rc}")); - } - let info = info.assume_init(); - let to_micros = |t: libc::time_value_t| -> u64 { - let secs = i128::from(t.seconds).max(0); - let micros = i128::from(t.microseconds).max(0); - (secs - .saturating_mul(1_000_000) - .saturating_add(micros) - .min(i128::from(u64::MAX))) as u64 - }; - Ok((to_micros(info.user_time), to_micros(info.system_time))) - } -} - -#[cfg(target_os = "macos")] -fn current_thread_resource_usage() -> Result { - let (user_cpu_us, system_cpu_us) = macos_thread_cpu_micros()?; - - let mut usage = MaybeUninit::::uninit(); - let result = unsafe { libc::getrusage(libc::RUSAGE_SELF, usage.as_mut_ptr()) }; - if result != 0 { - return Err(format!( - "getrusage(RUSAGE_SELF) failed: {}", - std::io::Error::last_os_error() - )); - } - let usage = unsafe { usage.assume_init() }; - Ok(ThreadResourceUsageSnapshot { - // Per-thread CPU time (accurate, from Mach thread_info). - user_cpu_us, - system_cpu_us, - // macOS reports ru_maxrss in bytes; normalise to KiB to match Linux. - max_rss_kib: non_negative_c_long(usage.ru_maxrss) / 1024, - // Process-wide best-effort: no per-thread source on macOS. - shared_memory_size: non_negative_c_long(usage.ru_ixrss), - unshared_data_size: non_negative_c_long(usage.ru_idrss), - unshared_stack_size: non_negative_c_long(usage.ru_isrss), - minor_page_faults: non_negative_c_long(usage.ru_minflt), - major_page_faults: non_negative_c_long(usage.ru_majflt), - swapped_out: non_negative_c_long(usage.ru_nswap), - fs_read: non_negative_c_long(usage.ru_inblock), - fs_write: non_negative_c_long(usage.ru_oublock), - ipc_sent: non_negative_c_long(usage.ru_msgsnd), - ipc_received: non_negative_c_long(usage.ru_msgrcv), - signals_count: non_negative_c_long(usage.ru_nsignals), - voluntary_context_switches: non_negative_c_long(usage.ru_nvcsw), - involuntary_context_switches: non_negative_c_long(usage.ru_nivcsw), - }) -} - -// Guest crypto is served by pure-Rust crates (RustCrypto), not OpenSSL, so there -// is no live OpenSSL library to query. We still surface a `process.versions.openssl` -// string for guest compatibility, pinned to the OpenSSL release vendored by the -// sidecar (openssl-sys 300.6.0+3.6.2). The browser executor reports the same -// constant so both runtimes present an identical identity. -const EMULATED_OPENSSL_VERSION: &str = "3.6.2"; - -fn set_object_string_property<'s>( - scope: &mut v8::HandleScope<'s>, - object: v8::Local<'s, v8::Object>, - key: &str, - value: &str, -) { - let key = v8::String::new(scope, key).expect("V8 string key"); - let value = v8::String::new(scope, value).expect("V8 string value"); - let _ = object.set(scope, key.into(), value.into()); -} - -fn set_object_number_property<'s>( - scope: &mut v8::HandleScope<'s>, - object: v8::Local<'s, v8::Object>, - key: &str, - value: f64, -) { - let key = v8::String::new(scope, key).expect("V8 string key"); - let value = v8::Number::new(scope, value); - let _ = object.set(scope, key.into(), value.into()); -} - -fn number_property_or_zero<'s>( - scope: &mut v8::HandleScope<'s>, - object: v8::Local<'s, v8::Object>, - key: &str, -) -> u64 { - let key = v8::String::new(scope, key).expect("V8 string key"); - object - .get(scope, key.into()) - .and_then(|value| value.integer_value(scope)) - .and_then(|value| u64::try_from(value).ok()) - .unwrap_or_default() -} - -fn process_memory_usage_value<'s>(scope: &mut v8::HandleScope<'s>) -> v8::Local<'s, v8::Value> { - let mut stats = v8::HeapStatistics::default(); - scope.get_heap_statistics(&mut stats); - - let object = v8::Object::new(scope); - set_object_number_property(scope, object, "rss", stats.total_physical_size() as f64); - set_object_number_property(scope, object, "heapTotal", stats.total_heap_size() as f64); - set_object_number_property(scope, object, "heapUsed", stats.used_heap_size() as f64); - set_object_number_property(scope, object, "external", stats.external_memory() as f64); - set_object_number_property( - scope, - object, - "arrayBuffers", - stats.external_memory() as f64, - ); - object.into() -} - -fn process_cpu_usage_value<'s>( - scope: &mut v8::HandleScope<'s>, - args: &v8::FunctionCallbackArguments, -) -> Result, String> { - let usage = current_thread_resource_usage()?; - let current_user = usage.user_cpu_us; - let current_system = usage.system_cpu_us; - - let (user, system) = if args.length() > 0 { - let prev = args.get(0); - if prev.is_null_or_undefined() { - (current_user, current_system) - } else if let Some(prev) = prev.to_object(scope) { - let previous_user = number_property_or_zero(scope, prev, "user"); - let previous_system = number_property_or_zero(scope, prev, "system"); - ( - current_user.saturating_sub(previous_user), - current_system.saturating_sub(previous_system), - ) - } else { - (current_user, current_system) - } - } else { - (current_user, current_system) - }; - - let object = v8::Object::new(scope); - set_object_number_property(scope, object, "user", user as f64); - set_object_number_property(scope, object, "system", system as f64); - Ok(object.into()) -} - -fn process_resource_usage_value<'s>( - scope: &mut v8::HandleScope<'s>, -) -> Result, String> { - let usage = current_thread_resource_usage()?; - let object = v8::Object::new(scope); - set_object_number_property(scope, object, "userCPUTime", usage.user_cpu_us as f64); - set_object_number_property(scope, object, "systemCPUTime", usage.system_cpu_us as f64); - set_object_number_property(scope, object, "maxRSS", usage.max_rss_kib as f64); - set_object_number_property( - scope, - object, - "sharedMemorySize", - usage.shared_memory_size as f64, - ); - set_object_number_property( - scope, - object, - "unsharedDataSize", - usage.unshared_data_size as f64, - ); - set_object_number_property( - scope, - object, - "unsharedStackSize", - usage.unshared_stack_size as f64, - ); - set_object_number_property( - scope, - object, - "minorPageFault", - usage.minor_page_faults as f64, - ); - set_object_number_property( - scope, - object, - "majorPageFault", - usage.major_page_faults as f64, - ); - set_object_number_property(scope, object, "swappedOut", usage.swapped_out as f64); - set_object_number_property(scope, object, "fsRead", usage.fs_read as f64); - set_object_number_property(scope, object, "fsWrite", usage.fs_write as f64); - set_object_number_property(scope, object, "ipcSent", usage.ipc_sent as f64); - set_object_number_property(scope, object, "ipcReceived", usage.ipc_received as f64); - set_object_number_property(scope, object, "signalsCount", usage.signals_count as f64); - set_object_number_property( - scope, - object, - "voluntaryContextSwitches", - usage.voluntary_context_switches as f64, - ); - set_object_number_property( - scope, - object, - "involuntaryContextSwitches", - usage.involuntary_context_switches as f64, - ); - Ok(object.into()) -} - -fn process_versions_value<'s>(scope: &mut v8::HandleScope<'s>) -> v8::Local<'s, v8::Value> { - let object = v8::Object::new(scope); - set_object_string_property(scope, object, "v8", v8::V8::get_version()); - set_object_string_property(scope, object, "openssl", EMULATED_OPENSSL_VERSION); - object.into() -} - -#[derive(Clone)] -struct VmContextState { - context: v8::Global, - baseline_keys: HashSet, - mirrored_keys: HashSet, -} - -#[derive(Clone, Debug)] -struct VmRunOptions { - filename: String, - line_offset: i32, - column_offset: i32, - timeout_ms: Option, -} - -impl Default for VmRunOptions { - fn default() -> Self { - Self { - filename: String::from("evalmachine."), - line_offset: 0, - column_offset: 0, - timeout_ms: None, - } - } -} - -thread_local! { - static VM_CONTEXTS: RefCell> = RefCell::new(HashMap::new()); - static NEXT_VM_CONTEXT_ID: Cell = const { Cell::new(1) }; -} - -fn vm_context_capacity_error(current_contexts: usize) -> Option { - if current_contexts >= MAX_VM_CONTEXTS { - return Some(format!( - "node:vm context registry exceeded limit of {MAX_VM_CONTEXTS} contexts" - )); - } - None -} - -fn reserve_vm_context_slot<'s>( - scope: &mut v8::HandleScope<'s>, - context: v8::Local<'s, v8::Context>, -) -> Result { - VM_CONTEXTS.with(|contexts| { - let mut contexts = contexts.borrow_mut(); - if let Some(error) = vm_context_capacity_error(contexts.len()) { - return Err(error); - } - - let context_id = next_vm_context_id(); - contexts.insert( - context_id, - VmContextState { - context: v8::Global::new(scope, context), - baseline_keys: HashSet::new(), - mirrored_keys: HashSet::new(), - }, - ); - Ok(context_id) - }) -} - -fn update_vm_context_slot( - context_id: u32, - baseline_keys: HashSet, - mirrored_keys: HashSet, -) { - VM_CONTEXTS.with(|contexts| { - if let Some(state) = contexts.borrow_mut().get_mut(&context_id) { - state.baseline_keys = baseline_keys; - state.mirrored_keys = mirrored_keys; - } - }); -} - -fn remove_vm_context_slot(context_id: u32) { - VM_CONTEXTS.with(|contexts| { - contexts.borrow_mut().remove(&context_id); - }); -} - -/// Evict every `node:vm` context slot held by the current isolate thread and -/// reset the id counter. -/// -/// `VM_CONTEXTS` is a thread-local that lives for the lifetime of the (reused) -/// isolate thread, not a single execution. `reserve_vm_context_slot` adds a slot -/// for every `vm.createContext()`, but the success path -/// (`update_vm_context_slot`) never removes it — only the sandbox-mirroring error -/// path does. Without a teardown sweep, slots reserved by one execution survive -/// into every later execution on the same isolate, so the registry grows -/// monotonically until it hits the hard cap `MAX_VM_CONTEXTS` and all subsequent -/// `createContext()` calls fail (freed only on thread exit). This sweep releases -/// those slots at a session boundary so the registry returns to empty between -/// executions. See `VmContextRegistryGuard`. -fn reset_vm_context_registry() { - VM_CONTEXTS.with(|contexts| contexts.borrow_mut().clear()); - NEXT_VM_CONTEXT_ID.with(|next_id| next_id.set(1)); -} - -/// RAII owner of the thread-local `node:vm` context registry for one session. -/// -/// Mirrors the per-session ownership of [`PendingPromises`] (created fresh per -/// session, dropped at teardown): a session holds one guard, and dropping it -/// evicts every context slot the session reserved. Because `Drop` runs on *every* -/// termination path of the frame that holds the guard — normal return, `?` error, -/// early return, and panic unwinding — the slots are reclaimed unconditionally, -/// not only on the happy path. This prevents a reused isolate thread from -/// accumulating `vm.createContext()` slots across executions toward -/// `MAX_VM_CONTEXTS`. -#[must_use = "hold the guard for the session lifetime; dropping it evicts the vm context registry"] -pub struct VmContextRegistryGuard { - _private: (), -} - -impl VmContextRegistryGuard { - /// Begin a session's ownership of the vm context registry, sweeping any slots - /// a prior session left on this (reused) isolate thread so the new session - /// starts from an empty registry. - pub fn new() -> Self { - reset_vm_context_registry(); - VmContextRegistryGuard { _private: () } - } -} - -impl Default for VmContextRegistryGuard { - fn default() -> Self { - Self::new() - } -} - -impl Drop for VmContextRegistryGuard { - fn drop(&mut self) { - reset_vm_context_registry(); - } -} - -#[cfg(test)] -fn clear_vm_context_registry_for_test() { - reset_vm_context_registry(); -} - -#[cfg(test)] -fn fill_vm_context_registry_for_test<'s>( - scope: &mut v8::HandleScope<'s>, - context: v8::Local<'s, v8::Context>, - count: usize, -) { - clear_vm_context_registry_for_test(); - for _ in 0..count { - reserve_vm_context_slot(scope, context).expect("fill vm context test registry"); - } -} - -#[cfg(test)] -fn vm_context_registry_len_for_test() -> usize { - VM_CONTEXTS.with(|contexts| contexts.borrow().len()) -} - -fn next_vm_context_id() -> u32 { - NEXT_VM_CONTEXT_ID.with(|next_id| { - let id = next_id.get(); - let next = id.checked_add(1).unwrap_or(1); - next_id.set(next.max(1)); - id - }) -} - -fn vm_collect_object_keys<'s>( - scope: &mut v8::HandleScope<'s>, - object: v8::Local<'s, v8::Object>, -) -> HashSet { - let names = object - .get_own_property_names(scope, v8::GetPropertyNamesArgs::default()) - .unwrap_or_else(|| v8::Array::new(scope, 0)); - let mut keys = HashSet::new(); - for index in 0..names.length() { - let Some(name) = names.get_index(scope, index) else { - continue; - }; - if name.is_string() { - keys.insert(name.to_rust_string_lossy(scope)); - } - } - keys -} - -fn vm_set_property<'s>( - scope: &mut v8::HandleScope<'s>, - object: v8::Local<'s, v8::Object>, - key: &str, - value: v8::Local<'s, v8::Value>, -) { - let Some(key_value) = v8::String::new(scope, key) else { - return; - }; - let _ = object.set(scope, key_value.into(), value); -} - -fn vm_delete_property<'s>( - scope: &mut v8::HandleScope<'s>, - object: v8::Local<'s, v8::Object>, - key: &str, -) { - let Some(key_value) = v8::String::new(scope, key) else { - return; - }; - let _ = object.delete(scope, key_value.into()); -} - -fn vm_copy_sandbox_into_context<'s>( - scope: &mut v8::HandleScope<'s>, - sandbox: v8::Local<'s, v8::Object>, - context_global: v8::Local<'s, v8::Object>, - previous_mirrored_keys: &HashSet, -) -> HashSet { - let current_keys = vm_collect_object_keys(scope, sandbox); - for key in current_keys.iter() { - let Some(key_value) = v8::String::new(scope, key) else { - continue; - }; - let value = sandbox - .get(scope, key_value.into()) - .unwrap_or_else(|| v8::undefined(scope).into()); - vm_set_property(scope, context_global, key, value); - } - for key in previous_mirrored_keys { - if !current_keys.contains(key) { - vm_delete_property(scope, context_global, key); - } - } - current_keys -} - -fn vm_copy_context_into_sandbox<'s>( - scope: &mut v8::HandleScope<'s>, - context_global: v8::Local<'s, v8::Object>, - sandbox: v8::Local<'s, v8::Object>, - baseline_keys: &HashSet, - previous_mirrored_keys: &HashSet, -) -> HashSet { - let current_keys = vm_collect_object_keys(scope, context_global) - .into_iter() - .filter(|key| !baseline_keys.contains(key)) - .collect::>(); - for key in current_keys.iter() { - let Some(key_value) = v8::String::new(scope, key) else { - continue; - }; - let value = context_global - .get(scope, key_value.into()) - .unwrap_or_else(|| v8::undefined(scope).into()); - vm_set_property(scope, sandbox, key, value); - } - for key in previous_mirrored_keys { - if !current_keys.contains(key) { - vm_delete_property(scope, sandbox, key); - } - } - current_keys -} - -fn vm_options_from_value<'s>( - scope: &mut v8::HandleScope<'s>, - value: v8::Local<'s, v8::Value>, -) -> VmRunOptions { - if value.is_null_or_undefined() { - return VmRunOptions::default(); - } - if value.is_string() { - return VmRunOptions { - filename: value.to_rust_string_lossy(scope), - ..VmRunOptions::default() - }; - } - let Some(options) = value.to_object(scope) else { - return VmRunOptions::default(); - }; - let mut result = VmRunOptions::default(); - let read_string = |scope: &mut v8::HandleScope<'s>, key: &str| { - let key_value = v8::String::new(scope, key).expect("V8 string key"); - options - .get(scope, key_value.into()) - .filter(|value| value.is_string()) - .map(|value| value.to_rust_string_lossy(scope)) - }; - let read_i32 = |scope: &mut v8::HandleScope<'s>, key: &str| { - let key_value = v8::String::new(scope, key).expect("V8 string key"); - options - .get(scope, key_value.into()) - .and_then(|value| value.int32_value(scope)) - }; - let read_u32 = |scope: &mut v8::HandleScope<'s>, key: &str| { - let key_value = v8::String::new(scope, key).expect("V8 string key"); - options - .get(scope, key_value.into()) - .and_then(|value| value.integer_value(scope)) - .and_then(|value| u32::try_from(value).ok()) - }; - - if let Some(filename) = read_string(scope, "filename") { - result.filename = filename; - } - if let Some(line_offset) = read_i32(scope, "lineOffset") { - result.line_offset = line_offset; - } - if let Some(column_offset) = read_i32(scope, "columnOffset") { - result.column_offset = column_offset; - } - result.timeout_ms = read_u32(scope, "timeout").filter(|timeout_ms| *timeout_ms > 0); - result -} - -fn vm_throw_error<'s>( - scope: &mut v8::HandleScope<'s>, - message: &str, - code: Option<&str>, - type_error: bool, -) -> v8::Local<'s, v8::Value> { - let message_value = v8::String::new(scope, message).expect("V8 error message"); - let exception = if type_error { - v8::Exception::type_error(scope, message_value) - } else { - v8::Exception::error(scope, message_value) - }; - if let Some(code) = code { - if let Some(exception_object) = exception.to_object(scope) { - let code_key = v8::String::new(scope, "code").expect("V8 code key"); - let code_value = v8::String::new(scope, code).expect("V8 code value"); - let _ = exception_object.set(scope, code_key.into(), code_value.into()); - } - } - scope.throw_exception(exception); - exception -} - -fn vm_throw_execution_error<'s>( - scope: &mut v8::HandleScope<'s>, - error: &crate::ipc::ExecutionError, -) -> v8::Local<'s, v8::Value> { - let message_value = v8::String::new(scope, &error.message).expect("V8 error message"); - let exception = match error.error_type.as_str() { - "TypeError" => v8::Exception::type_error(scope, message_value), - _ => v8::Exception::error(scope, message_value), - }; - if let Some(exception_object) = exception.to_object(scope) { - if let Some(code) = error.code.as_deref() { - let code_key = v8::String::new(scope, "code").expect("V8 code key"); - let code_value = v8::String::new(scope, code).expect("V8 code value"); - let _ = exception_object.set(scope, code_key.into(), code_value.into()); - } - if !error.stack.is_empty() { - let stack_key = v8::String::new(scope, "stack").expect("V8 stack key"); - let stack_value = v8::String::new(scope, &error.stack).expect("V8 stack value"); - let _ = exception_object.set(scope, stack_key.into(), stack_value.into()); - } - } - scope.throw_exception(exception); - exception -} - -fn vm_apply_script_origin_to_error( - mut error: crate::ipc::ExecutionError, - options: &VmRunOptions, -) -> crate::ipc::ExecutionError { - let display_line = options.line_offset.saturating_add(1).max(1); - let display_column = options.column_offset.saturating_add(1).max(1); - let marker = format!("{}:{}", options.filename, display_line); - if !error.stack.contains(&marker) { - error.stack = format!( - "{}: {}\n at {}:{}:{}", - error.error_type, error.message, options.filename, display_line, display_column - ); - } - error -} - -fn vm_run_script_in_context<'s>( - scope: &mut v8::HandleScope<'s>, - isolate_handle: v8::IsolateHandle, - context: v8::Local<'s, v8::Context>, - code: &str, - options: &VmRunOptions, -) -> Result, String> { - let mut timeout_guard = match options.timeout_ms { - Some(timeout_ms) => { - let (abort_tx, _abort_rx) = crossbeam_channel::bounded::<()>(0); - Some(crate::timeout::TimeoutGuard::new( - timeout_ms, - isolate_handle.clone(), - abort_tx, - )?) - } - None => None, - }; - - let mut result = None; - let mut exception = None; - { - let context_scope = &mut v8::ContextScope::new(scope, context); - let tc = &mut v8::TryCatch::new(context_scope); - let source = v8::String::new(tc, code) - .ok_or_else(|| String::from("vm source string too large for V8"))?; - let filename = v8::String::new(tc, &options.filename) - .ok_or_else(|| String::from("vm filename too large for V8"))?; - let origin = v8::ScriptOrigin::new( - tc, - filename.into(), - options.line_offset.saturating_sub(1), - options.column_offset, - false, - -1, - None, - false, - false, - false, - None, - ); - match v8::Script::compile(tc, source, Some(&origin)) { - Some(script) => match script.run(tc) { - Some(value) => { - tc.perform_microtask_checkpoint(); - if let Some(thrown) = tc.exception() { - exception = Some(vm_apply_script_origin_to_error( - crate::execution::extract_error_info(tc, thrown), - options, - )); - } else { - result = Some(v8::Global::new(tc, value)); - } - } - None => { - let failure_message = v8::String::new(tc, "vm script execution failed") - .expect("vm failure message"); - let thrown = tc - .exception() - .unwrap_or_else(|| v8::Exception::error(tc, failure_message)); - exception = Some(vm_apply_script_origin_to_error( - crate::execution::extract_error_info(tc, thrown), - options, - )); - } - }, - None => { - let failure_message = v8::String::new(tc, "vm script compilation failed") - .expect("vm failure message"); - let thrown = tc - .exception() - .unwrap_or_else(|| v8::Exception::error(tc, failure_message)); - exception = Some(vm_apply_script_origin_to_error( - crate::execution::extract_error_info(tc, thrown), - options, - )); - } - } - } - - let timed_out = if let Some(ref mut guard) = timeout_guard { - guard.cancel(); - guard.timed_out() - } else { - false - }; - - if timed_out { - isolate_handle.cancel_terminate_execution(); - return Ok(vm_throw_error( - scope, - &format!( - "Script execution timed out after {}ms", - options.timeout_ms.unwrap_or_default() - ), - Some("ERR_SCRIPT_EXECUTION_TIMEOUT"), - false, - )); - } - - if let Some(exception) = exception { - return Ok(vm_throw_execution_error(scope, &exception)); - } - - Ok(result - .map(|result| v8::Local::new(scope, &result)) - .unwrap_or_else(|| v8::undefined(scope).into())) -} - -fn vm_create_context_value<'s>( - scope: &mut v8::HandleScope<'s>, - args: &mut v8::FunctionCallbackArguments<'s>, -) -> Result, String> { - let sandbox_value = args.get(0); - if !(sandbox_value.is_object() || sandbox_value.is_function()) { - return Ok(vm_throw_error( - scope, - "The \"object\" argument must be of type object.", - None, - true, - )); - } - let sandbox = sandbox_value - .to_object(scope) - .ok_or_else(|| String::from("vm.createContext expected an object sandbox"))?; - let context = v8::Context::new(scope, Default::default()); - let context_id = match reserve_vm_context_slot(scope, context) { - Ok(context_id) => context_id, - Err(message) => { - return Ok(vm_throw_error( - scope, - &message, - Some("ERR_AGENTOS_VM_CONTEXT_LIMIT"), - false, - )); - } - }; - { - let context_scope = &mut v8::ContextScope::new(scope, context); - let global = context.global(context_scope); - for key in [ - "Buffer", - "require", - "process", - "module", - "exports", - "__dirname", - "__filename", - ] { - vm_delete_property(context_scope, global, key); - let undefined = v8::undefined(context_scope).into(); - vm_set_property(context_scope, global, key, undefined); - } - } - let baseline_keys = { - let context_scope = &mut v8::ContextScope::new(scope, context); - let global = context.global(context_scope); - vm_collect_object_keys(context_scope, global) - }; - let mirrored_keys_result = { - let tc = &mut v8::TryCatch::new(scope); - let mirrored_keys = { - let context_scope = &mut v8::ContextScope::new(tc, context); - let global = context.global(context_scope); - vm_copy_sandbox_into_context(context_scope, sandbox, global, &HashSet::new()) - }; - if tc.has_caught() { - Err(tc - .exception() - .map(|exception| v8::Global::new(tc, exception))) - } else { - Ok(mirrored_keys) - } - }; - let mirrored_keys = match mirrored_keys_result { - Ok(mirrored_keys) => mirrored_keys, - Err(exception) => { - remove_vm_context_slot(context_id); - if let Some(exception) = exception { - let exception = v8::Local::new(scope, &exception); - scope.throw_exception(exception); - return Ok(exception); - } - return Ok(vm_throw_error( - scope, - "vm.createContext failed while mirroring sandbox properties", - None, - false, - )); - } - }; - - update_vm_context_slot(context_id, baseline_keys, mirrored_keys); - Ok(v8::Integer::new_from_unsigned(scope, context_id).into()) -} - -fn vm_run_in_context_value<'s>( - scope: &mut v8::HandleScope<'s>, - args: &mut v8::FunctionCallbackArguments<'s>, -) -> Result, String> { - let context_id = args - .get(0) - .uint32_value(scope) - .ok_or_else(|| String::from("vm.runInContext missing context id"))?; - let code = args.get(1).to_rust_string_lossy(scope); - let options_value = args.get(2); - let options = vm_options_from_value(scope, options_value); - let sandbox = args - .get(3) - .to_object(scope) - .ok_or_else(|| String::from("vm.runInContext missing sandbox object"))?; - let isolate_handle = unsafe { args.get_isolate() }.thread_safe_handle(); - - let Some((context_global, baseline_keys, mirrored_keys)) = VM_CONTEXTS.with(|contexts| { - contexts.borrow().get(&context_id).map(|state| { - ( - state.context.clone(), - state.baseline_keys.clone(), - state.mirrored_keys.clone(), - ) - }) - }) else { - return Ok(vm_throw_error( - scope, - "The \"contextifiedObject\" argument must be a vm context.", - Some("ERR_INVALID_ARG_TYPE"), - true, - )); - }; - - let context = v8::Local::new(scope, &context_global); - { - let context_scope = &mut v8::ContextScope::new(scope, context); - let global = context.global(context_scope); - vm_copy_sandbox_into_context(context_scope, sandbox, global, &mirrored_keys); - } - let result = vm_run_script_in_context(scope, isolate_handle, context, &code, &options)?; - let updated_keys = { - let context_scope = &mut v8::ContextScope::new(scope, context); - let global = context.global(context_scope); - vm_copy_context_into_sandbox( - context_scope, - global, - sandbox, - &baseline_keys, - &mirrored_keys, - ) - }; - VM_CONTEXTS.with(|contexts| { - if let Some(state) = contexts.borrow_mut().get_mut(&context_id) { - state.mirrored_keys = updated_keys; - } - }); - Ok(result) -} - -fn vm_run_in_this_context_value<'s>( - scope: &mut v8::HandleScope<'s>, - args: &mut v8::FunctionCallbackArguments<'s>, -) -> Result, String> { - let code = args.get(0).to_rust_string_lossy(scope); - let options_value = args.get(1); - let options = vm_options_from_value(scope, options_value); - let context = scope.get_current_context(); - let isolate_handle = unsafe { args.get_isolate() }.thread_safe_handle(); - vm_run_script_in_context(scope, isolate_handle, context, &code, &options) -} - -fn handle_local_bridge_call<'s>( - scope: &mut v8::HandleScope<'s>, - method: &str, - args: &mut v8::FunctionCallbackArguments<'s>, -) -> Result>, String> { - match method { - "process.memoryUsage" => Ok(Some(process_memory_usage_value(scope))), - "process.cpuUsage" => process_cpu_usage_value(scope, args).map(Some), - "process.resourceUsage" => process_resource_usage_value(scope).map(Some), - "process.versions" => Ok(Some(process_versions_value(scope))), - "_vmCreateContext" => vm_create_context_value(scope, args).map(Some), - "_vmRunInContext" => vm_run_in_context_value(scope, args).map(Some), - "_vmRunInThisContext" => vm_run_in_this_context_value(scope, args).map(Some), - _ => Ok(None), - } -} - -/// Register sync-blocking bridge functions on the V8 global object. -/// -/// Each registered function, when called from V8: -/// 1. Serializes arguments as a V8 Array via ValueSerializer -/// 2. Sends a BridgeCall over IPC via BridgeCallContext -/// 3. Blocks on read() for the BridgeResponse -/// 4. Returns the V8-deserialized result or throws a V8 exception -/// -/// The BridgeCallContext pointer must remain valid for the lifetime of the V8 context. -/// The returned BridgeFnStore must also be kept alive. -pub fn register_sync_bridge_fns( - scope: &mut v8::HandleScope, - ctx: *const BridgeCallContext, - methods: &[&str], -) -> BridgeFnStore { - let context = scope.get_current_context(); - let global = context.global(scope); - let mut data = Vec::with_capacity(methods.len()); - - for &method_name in methods { - let boxed = Box::new(SyncBridgeFnData { - ctx, - method: method_name.to_string(), - }); - // Pointer to heap allocation — stable while Box exists in data vec - let ptr = &*boxed as *const SyncBridgeFnData as *mut c_void; - data.push(boxed); - - let external = v8::External::new(scope, ptr); - let template = v8::FunctionTemplate::builder(sync_bridge_callback) - .data(external.into()) - .build(scope); - let func = template.get_function(scope).unwrap(); - attach_bridge_function_aliases(scope, func, &["applySync", "applySyncPromise"]); - - let key = v8::String::new(scope, method_name).unwrap(); - global.set(scope, key.into(), func.into()); - } - - BridgeFnStore { _data: data } -} - -/// V8 FunctionTemplate callback for sync-blocking bridge calls. -fn sync_bridge_callback<'s>( - scope: &mut v8::HandleScope<'s>, - args: v8::FunctionCallbackArguments<'s>, - mut rv: v8::ReturnValue, -) { - let mut args = args; - // Extract SyncBridgeFnData from External - let external = match v8::Local::::try_from(args.data()) { - Ok(ext) => ext, - Err(_) => { - let msg = - v8::String::new(scope, "internal error: missing bridge function data").unwrap(); - let exc = v8::Exception::error(scope, msg); - scope.throw_exception(exc); - return; - } - }; - // SAFETY: pointer is valid while BridgeFnStore is alive (same session lifetime) - let data = unsafe { &*(external.value() as *const SyncBridgeFnData) }; - let ctx = unsafe { &*data.ctx }; - - { - let tc = &mut v8::TryCatch::new(scope); - match handle_local_bridge_call(tc, &data.method, &mut args) { - Ok(Some(value)) => { - if tc.has_caught() { - let _ = tc.rethrow(); - return; - } - rv.set(value); - return; - } - Ok(None) => {} - Err(err) => { - if tc.has_caught() { - let _ = tc.rethrow(); - return; - } - let msg = v8::String::new(tc, &format!("bridge runtime error: {err}")).unwrap(); - let exc = v8::Exception::error(tc, msg); - tc.throw_exception(exc); - return; - } - } - } - - // Serialize V8 arguments using the Vec released by V8's serializer directly. - let encoded_args = match serialize_v8_args(scope, &args) { - Ok(encoded_args) => encoded_args, - Err(err) => { - let msg = - v8::String::new(scope, &format!("bridge serialization error: {}", err)).unwrap(); - let exc = v8::Exception::error(scope, msg); - scope.throw_exception(exc); - return; - } - }; - - // Perform sync-blocking bridge call - match ctx.sync_call_response(&data.method, encoded_args) { - Ok(Some(response)) => { - let v8_val = bridge_response_payload_to_v8(scope, response.status, &response.payload); - if let Some(val) = v8_val { - rv.set(val); - } else { - let msg = v8::String::new(scope, "bridge response conversion failed").unwrap(); - let exc = v8::Exception::error(scope, msg); - scope.throw_exception(exc); - } - } - Ok(None) => { - rv.set_undefined(); - } - Err(err_msg) => { - let msg = v8::String::new(scope, &err_msg).unwrap(); - let exc = v8::Exception::error(scope, msg); - if let Some(code) = bridge_error_code(&err_msg) { - let exc_object = exc.to_object(scope).unwrap(); - let code_key = v8::String::new(scope, "code").unwrap(); - let code_value = v8::String::new(scope, code).unwrap(); - let _ = exc_object.set(scope, code_key.into(), code_value.into()); - } - scope.throw_exception(exc); - } - } -} - -/// Register async promise-returning bridge functions on the V8 global object. -/// -/// Each registered function, when called from V8: -/// 1. Creates a v8::PromiseResolver -/// 2. Stores the resolver + call_id in PendingPromises -/// 3. Sends a BridgeCall over IPC (non-blocking write) -/// 4. Returns the promise to V8 -/// -/// The BridgeCallContext and PendingPromises pointers must remain valid -/// for the lifetime of the V8 context. -pub fn register_async_bridge_fns( - scope: &mut v8::HandleScope, - ctx: *const BridgeCallContext, - pending: *const PendingPromises, - methods: &[&str], -) -> AsyncBridgeFnStore { - let context = scope.get_current_context(); - let global = context.global(scope); - let mut data = Vec::with_capacity(methods.len()); - - for &method_name in methods { - let boxed = Box::new(AsyncBridgeFnData { - ctx, - pending, - method: method_name.to_string(), - }); - // Pointer to heap allocation — stable while Box exists in data vec - let ptr = &*boxed as *const AsyncBridgeFnData as *mut c_void; - data.push(boxed); - - let external = v8::External::new(scope, ptr); - let template = v8::FunctionTemplate::builder(async_bridge_callback) - .data(external.into()) - .build(scope); - let func = template.get_function(scope).unwrap(); - attach_bridge_function_aliases(scope, func, &["apply"]); - - let key = v8::String::new(scope, method_name).unwrap(); - global.set(scope, key.into(), func.into()); - } - - AsyncBridgeFnStore { _data: data } -} - -fn attach_bridge_function_aliases<'s>( - scope: &mut v8::HandleScope<'s>, - func: v8::Local<'s, v8::Function>, - aliases: &[&str], -) { - let func_object = func.to_object(scope).unwrap(); - for alias in aliases { - let key = v8::String::new(scope, alias).unwrap(); - let Some(wrapper) = build_bridge_apply_wrapper(scope, func) else { - continue; - }; - let _ = func_object.set(scope, key.into(), wrapper.into()); - } -} - -fn build_bridge_apply_wrapper<'s>( - scope: &mut v8::HandleScope<'s>, - func: v8::Local<'s, v8::Function>, -) -> Option> { - let source = v8::String::new( - scope, - "(function (fn) { return function (_thisArg, args) { return fn(...(Array.isArray(args) ? args : [])); }; })", - )?; - let script = v8::Script::compile(scope, source, None)?; - let factory = script.run(scope)?; - let factory = v8::Local::::try_from(factory).ok()?; - let argv = [func.into()]; - let receiver = v8::undefined(scope).into(); - factory - .call(scope, receiver, &argv) - .and_then(|value| v8::Local::::try_from(value).ok()) -} - -fn reject_promise_with_error( - scope: &mut v8::HandleScope, - resolver: v8::Local, - message: &str, - code: Option<&str>, -) { - let msg = v8::String::new(scope, message).unwrap(); - let exc = v8::Exception::error(scope, msg); - if let Some(code) = code { - let exc_object = exc.to_object(scope).unwrap(); - let code_key = v8::String::new(scope, "code").unwrap(); - let code_value = v8::String::new(scope, code).unwrap(); - let _ = exc_object.set(scope, code_key.into(), code_value.into()); - } - resolver.reject(scope, exc); -} - -/// V8 FunctionTemplate callback for async promise-returning bridge calls. -fn async_bridge_callback( - scope: &mut v8::HandleScope, - args: v8::FunctionCallbackArguments, - mut rv: v8::ReturnValue, -) { - // Extract AsyncBridgeFnData from External - let external = match v8::Local::::try_from(args.data()) { - Ok(ext) => ext, - Err(_) => { - let msg = v8::String::new(scope, "internal error: missing async bridge function data") - .unwrap(); - let exc = v8::Exception::error(scope, msg); - scope.throw_exception(exc); - return; - } - }; - // SAFETY: pointer is valid while AsyncBridgeFnStore is alive (same session lifetime) - let data = unsafe { &*(external.value() as *const AsyncBridgeFnData) }; - let ctx = unsafe { &*data.ctx }; - let pending = unsafe { &*data.pending }; - - // Create PromiseResolver - let resolver = match v8::PromiseResolver::new(scope) { - Some(r) => r, - None => { - let msg = v8::String::new(scope, "failed to create PromiseResolver").unwrap(); - let exc = v8::Exception::error(scope, msg); - scope.throw_exception(exc); - return; - } - }; - - // Get the promise to return to V8 - let promise = resolver.get_promise(scope); - - let reservation = match pending.reserve() { - Ok(reservation) => reservation, - Err(err_msg) => { - reject_promise_with_error( - scope, - resolver, - &err_msg, - Some("ERR_AGENTOS_BRIDGE_PENDING_PROMISE_LIMIT"), - ); - rv.set(promise.into()); - return; - } - }; - - // Serialize V8 arguments using the Vec released by V8's serializer directly. - let encoded_args = match serialize_v8_args(scope, &args) { - Ok(encoded_args) => encoded_args, - Err(err) => { - let msg = - v8::String::new(scope, &format!("bridge serialization error: {}", err)).unwrap(); - let exc = v8::Exception::error(scope, msg); - scope.throw_exception(exc); - return; - } - }; - - // Send BridgeCall (non-blocking write) - match ctx.async_send(&data.method, encoded_args) { - Ok(call_id) => { - // Store resolver in pending promises map - let global_resolver = v8::Global::new(scope, resolver); - pending.insert_reserved(call_id, global_resolver, reservation); - } - Err(err_msg) => { - // Reject the promise immediately if send fails - reject_promise_with_error(scope, resolver, &err_msg, None); - } - } - - // Return the promise - rv.set(promise.into()); -} - -/// Replace stub bridge functions on a snapshot-restored context with real -/// session-local bridge functions. Overwrites the 38 stub globals with -/// functions backed by session-local BridgeCallContext. -/// -/// Returns (BridgeFnStore, AsyncBridgeFnStore) that must be kept alive -/// for the lifetime of the V8 context. -pub fn replace_bridge_fns( - scope: &mut v8::HandleScope, - ctx: *const BridgeCallContext, - pending: *const PendingPromises, - sync_fns: &[&str], - async_fns: &[&str], -) -> (BridgeFnStore, AsyncBridgeFnStore) { - // Per-session bridge installation runs once, before any user code executes in - // this context, so the only `node:vm` context slots present are leftovers from - // a prior session that reused this isolate thread. Sweep them here so a new - // session never inherits another session's contexts and the registry can never - // accumulate across executions toward `MAX_VM_CONTEXTS`. The session should - // also hold a `VmContextRegistryGuard` to evict its own slots at teardown. - reset_vm_context_registry(); - let sync_store = register_sync_bridge_fns(scope, ctx, sync_fns); - let async_store = register_async_bridge_fns(scope, ctx, pending, async_fns); - (sync_store, async_store) -} - -/// Register stub bridge functions on the V8 global for snapshot creation. -/// -/// Uses the same sync_bridge_callback / async_bridge_callback as real -/// functions (required for ExternalReferences in snapshot serialization) -/// but WITHOUT v8::External data. If a stub is accidentally called during -/// snapshot creation, the callback gracefully throws a V8 exception -/// (args.data() is not External -> "missing bridge function data" error). -/// -/// After snapshot restore, these stubs are replaced with real functions -/// that have proper External data pointing to a session-local BridgeCallContext. -pub fn register_stub_bridge_fns( - scope: &mut v8::HandleScope, - sync_fns: &[&str], - async_fns: &[&str], -) { - let context = scope.get_current_context(); - let global = context.global(scope); - - // Register sync bridge functions as stubs (no External data) - for &method_name in sync_fns { - let template = v8::FunctionTemplate::builder(sync_bridge_callback).build(scope); - let func = template.get_function(scope).unwrap(); - let key = v8::String::new(scope, method_name).unwrap(); - global.set(scope, key.into(), func.into()); - } - - // Register async bridge functions as stubs (no External data) - for &method_name in async_fns { - let template = v8::FunctionTemplate::builder(async_bridge_callback).build(scope); - let func = template.get_function(scope).unwrap(); - let key = v8::String::new(scope, method_name).unwrap(); - global.set(scope, key.into(), func.into()); - } -} - -/// Serialize V8 function arguments as an array. -fn serialize_v8_args( - scope: &mut v8::HandleScope, - args: &v8::FunctionCallbackArguments, -) -> Result, String> { - let count = args.length(); - let array = v8::Array::new(scope, count); - for i in 0..count { - array.set_index(scope, i as u32, args.get(i)); - } - serialize_v8_value(scope, array.into()) -} - -/// Resolve or reject a pending async bridge promise by call_id. -/// -/// Called when a BridgeResponse arrives during the session event loop. -/// Flushes microtasks after resolution to process .then() handlers. -pub fn resolve_pending_promise( - scope: &mut v8::HandleScope, - pending: &PendingPromises, - call_id: u64, - status: u8, - result: Option>, - error: Option, -) -> Result<(), String> { - let resolver_global = pending - .remove(call_id) - .ok_or_else(|| format!("no pending promise for call_id {}", call_id))?; - let resolver = v8::Local::new(scope, &resolver_global); - - if let Some(err_msg) = error { - let msg = v8::String::new(scope, &err_msg).unwrap(); - let exc = v8::Exception::error(scope, msg); - if let Some(code) = bridge_error_code(&err_msg) { - let exc_object = exc.to_object(scope).unwrap(); - let code_key = v8::String::new(scope, "code").unwrap(); - let code_value = v8::String::new(scope, code).unwrap(); - let _ = exc_object.set(scope, code_key.into(), code_value.into()); - } - resolver.reject(scope, exc); - } else if let Some(result_bytes) = result { - let v8_val = bridge_response_payload_to_v8(scope, status, &result_bytes); - if let Some(val) = v8_val { - resolver.resolve(scope, val); - } else { - let msg = v8::String::new(scope, "bridge response conversion failed").unwrap(); - let exc = v8::Exception::error(scope, msg); - resolver.reject(scope, exc); - } - } else { - let undef = v8::undefined(scope); - resolver.resolve(scope, undef.into()); - } - - // Flush microtasks after resolution - scope.perform_microtask_checkpoint(); - - Ok(()) -} - -fn bridge_error_code(message: &str) -> Option<&str> { - const TRUSTED_PREFIXES: &[&str] = &[ - "ERR_AGENTOS_NODE_SYNC_RPC", - "ERR_AGENTOS_PYTHON_VFS_RPC", - "ERR_AGENTOS_BRIDGE", - ]; - - let mut segments = message.split(':').map(str::trim); - let first = segments.next()?; - if is_errno_segment(first) { - return Some(first); - } - - if TRUSTED_PREFIXES.contains(&first) { - let second = segments.next()?; - if is_errno_segment(second) { - return Some(second); - } - } - - None -} - -fn is_errno_segment(segment: &str) -> bool { - segment.len() >= 2 - && segment.starts_with('E') - && !segment.starts_with("ERR_") - && segment[1..] - .bytes() - .all(|byte| byte.is_ascii_uppercase() || byte.is_ascii_digit() || byte == b'_') -} - -#[cfg(test)] -mod tests { - use super::{ - bridge_error_code, clear_vm_context_registry_for_test, deserialize_cbor_value, - fill_vm_context_registry_for_test, register_async_bridge_fns, register_sync_bridge_fns, - reserve_vm_context_slot, reset_vm_context_registry, serialize_cbor_value, - vm_context_capacity_error, vm_context_registry_len_for_test, PendingPromises, - VmContextRegistryGuard, MAX_CBOR_BRIDGE_CONTAINER_ITEMS, MAX_CBOR_BRIDGE_DEPTH, - MAX_PENDING_PROMISES, MAX_VM_CONTEXTS, - }; - use crate::host_call::BridgeCallContext; - use crate::ipc_binary::{self, BinaryFrame}; - use crate::isolate; - use std::io::{Cursor, Write}; - use std::process::Command; - use std::sync::{Arc, Mutex}; - - struct SharedWriter(Arc>>); - - impl Write for SharedWriter { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.0.lock().unwrap().write(buf) - } - - fn flush(&mut self) -> std::io::Result<()> { - self.0.lock().unwrap().flush() - } - } - - fn bridge_call_count(bytes: &[u8]) -> usize { - let mut cursor = Cursor::new(bytes); - let mut count = 0; - while let Ok(frame) = ipc_binary::read_frame(&mut cursor) { - if matches!(frame, BinaryFrame::BridgeCall { .. }) { - count += 1; - } - } - count - } - - #[test] - fn bridge_error_code_rejects_guest_controlled_errno_segments() { - assert_eq!(bridge_error_code("user said 'EACCES: denied'"), None); - assert_eq!( - bridge_error_code("prefix: user said 'EPERM': more text"), - None - ); - assert_eq!(bridge_error_code("ERR_AGENTOS_FAKE: EACCES: denied"), None); - } - - #[test] - fn bridge_error_code_accepts_trusted_secure_exec_prefixes() { - assert_eq!( - bridge_error_code("ERR_AGENTOS_NODE_SYNC_RPC: EACCES: permission denied on /foo"), - Some("EACCES") - ); - assert_eq!( - bridge_error_code("ERR_AGENTOS_PYTHON_VFS_RPC: ENOENT: missing file"), - Some("ENOENT") - ); - assert_eq!(bridge_error_code("EEXIST: already exists"), Some("EEXIST")); - } - - #[test] - fn bridge_v8_hardening_rejects_cbor_abuse_and_vm_context_reentry_overflow() { - const SUBPROCESS_ENV: &str = "AGENTOS_V8_BRIDGE_HARDENING_SUBPROCESS"; - if std::env::var_os(SUBPROCESS_ENV).is_none() { - let output = Command::new(std::env::current_exe().expect("current test binary")) - .arg("bridge::tests::bridge_v8_hardening_rejects_cbor_abuse_and_vm_context_reentry_overflow") - .arg("--exact") - .arg("--nocapture") - .env(SUBPROCESS_ENV, "1") - .output() - .expect("spawn bridge hardening subprocess"); - assert!( - output.status.success(), - "bridge hardening subprocess failed with status {:?}\nstdout:\n{}\nstderr:\n{}", - output.status.code(), - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ); - return; - } - - isolate::init_v8_platform(); - - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, context); - - let object = v8::Object::new(scope); - let self_key = v8::String::new(scope, "self").unwrap(); - assert!(object.set(scope, self_key.into(), object.into()).is_some()); - - let error = serialize_cbor_value(scope, object.into()).expect_err("cycle rejected"); - assert!( - error.contains("circular object graph"), - "unexpected error: {error}" - ); - - let source = v8::String::new( - scope, - &format!( - "const sparse = []; sparse.length = {}; sparse", - MAX_CBOR_BRIDGE_CONTAINER_ITEMS + 1 - ), - ) - .unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let sparse = script.run(scope).unwrap(); - let error = serialize_cbor_value(scope, sparse).expect_err("sparse array rejected"); - assert!( - error.contains(&format!( - "item count {} exceeds limit", - MAX_CBOR_BRIDGE_CONTAINER_ITEMS + 1 - )), - "unexpected error: {error}" - ); - - let mut value = ciborium::Value::Null; - for _ in 0..=MAX_CBOR_BRIDGE_DEPTH { - value = ciborium::Value::Array(vec![value]); - } - let mut encoded = Vec::new(); - ciborium::into_writer(&value, &mut encoded).unwrap(); - let error = deserialize_cbor_value(scope, &encoded).expect_err("depth rejected"); - assert!( - error.contains("CBOR decode failed"), - "unexpected error: {error}" - ); - - let oversized_len = (MAX_CBOR_BRIDGE_CONTAINER_ITEMS + 1) as u32; - let oversized_array_header = [ - 0x9a, - (oversized_len >> 24) as u8, - (oversized_len >> 16) as u8, - (oversized_len >> 8) as u8, - oversized_len as u8, - ]; - let error = deserialize_cbor_value(scope, &oversized_array_header) - .expect_err("oversized array rejected before element allocation"); - assert!( - error.contains(&format!( - "item count {} exceeds limit", - MAX_CBOR_BRIDGE_CONTAINER_ITEMS + 1 - )), - "unexpected error: {error}" - ); - - fill_vm_context_registry_for_test(scope, context, MAX_VM_CONTEXTS - 1); - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - String::from("test-session"), - ); - let _bridge_fns = register_sync_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &["_vmCreateContext"], - ); - - let source = r#" - let innerCode; - const sandbox = {}; - Object.defineProperty(sandbox, "x", { - get() { - try { - _vmCreateContext({}); - } catch (error) { - innerCode = error && error.code; - } - return 1; - }, - enumerable: true, - }); - - const outerId = _vmCreateContext(sandbox); - let limitCode; - try { - _vmCreateContext({}); - } catch (error) { - limitCode = error && error.code; - } - - JSON.stringify({ - innerCode, - limitCode, - outerIsInteger: Number.isInteger(outerId), - }) - "#; - { - let tc = &mut v8::TryCatch::new(scope); - let source = v8::String::new(tc, source).unwrap(); - let script = v8::Script::compile(tc, source, None).unwrap(); - let result = script.run(tc); - assert!( - !tc.has_caught(), - "unexpected exception while testing vm cap" - ); - let details = result - .expect("vm context cap script result") - .to_rust_string_lossy(tc); - assert_eq!( - details, - r#"{"innerCode":"ERR_AGENTOS_VM_CONTEXT_LIMIT","limitCode":"ERR_AGENTOS_VM_CONTEXT_LIMIT","outerIsInteger":true}"#, - "vm context cap script should observe limit errors" - ); - } - assert_eq!(vm_context_registry_len_for_test(), MAX_VM_CONTEXTS); - clear_vm_context_registry_for_test(); - - let source = r#" - (() => { - let thrownMessage; - const sandbox = {}; - Object.defineProperty(sandbox, "x", { - get() { - throw new Error("sandbox getter failed"); - }, - enumerable: true, - }); - try { - _vmCreateContext(sandbox); - } catch (error) { - thrownMessage = error && error.message; - } - - const nextId = _vmCreateContext({}); - return JSON.stringify({ - thrownMessage, - nextIsInteger: Number.isInteger(nextId), - }); - })() - "#; - { - let tc = &mut v8::TryCatch::new(scope); - let source = v8::String::new(tc, source).unwrap(); - let script = v8::Script::compile(tc, source, None).unwrap(); - let result = script.run(tc); - if tc.has_caught() { - let exception = tc - .exception() - .map(|exception| exception.to_rust_string_lossy(tc)) - .unwrap_or_else(|| String::from("")); - panic!("unexpected exception while testing vm rollback: {exception}"); - } - let details = result - .expect("vm context rollback script result") - .to_rust_string_lossy(tc); - assert_eq!( - details, r#"{"thrownMessage":"sandbox getter failed","nextIsInteger":true}"#, - "vm context rollback script should preserve the getter exception and keep registry usable" - ); - } - assert_eq!(vm_context_registry_len_for_test(), 1); - clear_vm_context_registry_for_test(); - - let async_writer = Arc::new(Mutex::new(Vec::new())); - let async_bridge_ctx = BridgeCallContext::new( - Box::new(SharedWriter(Arc::clone(&async_writer))), - Box::new(Cursor::new(Vec::new())), - String::from("test-session"), - ); - let async_pending = PendingPromises::new(); - let _async_bridge_fns = register_async_bridge_fns( - scope, - &async_bridge_ctx as *const BridgeCallContext, - &async_pending as *const PendingPromises, - &["_asyncFn"], - ); - let source = format!( - r#" - for (let i = 0; i < {fill_count}; i++) {{ - _asyncFn(i); - }} - globalThis.__overflowPromise = _asyncFn("overflow"); - "#, - fill_count = MAX_PENDING_PROMISES, - ); - { - let tc = &mut v8::TryCatch::new(scope); - let source = v8::String::new(tc, &source).unwrap(); - let script = v8::Script::compile(tc, source, None).unwrap(); - assert!(script.run(tc).is_some()); - assert!(!tc.has_caught(), "async overflow should reject, not throw"); - } - assert_eq!(async_pending.len(), MAX_PENDING_PROMISES); - assert_eq!( - bridge_call_count(&async_writer.lock().unwrap()), - MAX_PENDING_PROMISES - ); - { - let key = v8::String::new(scope, "__overflowPromise").unwrap(); - let value = context.global(scope).get(scope, key.into()).unwrap(); - let promise = v8::Local::::try_from(value).unwrap(); - assert_eq!(promise.state(), v8::PromiseState::Rejected); - let rejection = promise.result(scope); - let rejection = v8::Local::::try_from(rejection).unwrap(); - let code_key = v8::String::new(scope, "code").unwrap(); - let code = rejection.get(scope, code_key.into()).unwrap(); - assert_eq!( - code.to_rust_string_lossy(scope), - "ERR_AGENTOS_BRIDGE_PENDING_PROMISE_LIMIT" - ); - } - - let reentrant_writer = Arc::new(Mutex::new(Vec::new())); - let reentrant_bridge_ctx = BridgeCallContext::new( - Box::new(SharedWriter(Arc::clone(&reentrant_writer))), - Box::new(Cursor::new(Vec::new())), - String::from("test-session"), - ); - let reentrant_pending = PendingPromises::new(); - let _reentrant_async_bridge_fns = register_async_bridge_fns( - scope, - &reentrant_bridge_ctx as *const BridgeCallContext, - &reentrant_pending as *const PendingPromises, - &["_asyncFn"], - ); - let source = format!( - r#" - for (let i = 0; i < {fill_count}; i++) {{ - _asyncFn(i); - }} - let innerPromise; - const reentrantArg = {{}}; - Object.defineProperty(reentrantArg, "x", {{ - get() {{ - innerPromise = _asyncFn("inner"); - return 1; - }}, - enumerable: true, - }}); - globalThis.__reentrantOuterPromise = _asyncFn(reentrantArg); - globalThis.__reentrantInnerPromise = innerPromise; - "#, - fill_count = MAX_PENDING_PROMISES - 1, - ); - { - let tc = &mut v8::TryCatch::new(scope); - let source = v8::String::new(tc, &source).unwrap(); - let script = v8::Script::compile(tc, source, None).unwrap(); - assert!(script.run(tc).is_some()); - assert!(!tc.has_caught(), "async reentry should reject, not throw"); - } - assert_eq!(reentrant_pending.len(), MAX_PENDING_PROMISES); - assert_eq!( - bridge_call_count(&reentrant_writer.lock().unwrap()), - MAX_PENDING_PROMISES - ); - { - let key = v8::String::new(scope, "__reentrantInnerPromise").unwrap(); - let value = context.global(scope).get(scope, key.into()).unwrap(); - let promise = v8::Local::::try_from(value).unwrap(); - assert_eq!(promise.state(), v8::PromiseState::Rejected); - let rejection = promise.result(scope); - let rejection = v8::Local::::try_from(rejection).unwrap(); - let code_key = v8::String::new(scope, "code").unwrap(); - let code = rejection.get(scope, code_key.into()).unwrap(); - assert_eq!( - code.to_rust_string_lossy(scope), - "ERR_AGENTOS_BRIDGE_PENDING_PROMISE_LIMIT" - ); - } - - let buffer_reentry_writer = Arc::new(Mutex::new(Vec::new())); - let buffer_reentry_bridge_ctx = BridgeCallContext::new( - Box::new(SharedWriter(Arc::clone(&buffer_reentry_writer))), - Box::new(Cursor::new(Vec::new())), - String::from("test-session"), - ); - let buffer_reentry_pending = PendingPromises::new(); - let _buffer_reentry_async_bridge_fns = register_async_bridge_fns( - scope, - &buffer_reentry_bridge_ctx as *const BridgeCallContext, - &buffer_reentry_pending as *const PendingPromises, - &["_asyncFn"], - ); - let source = r#" - let bufferInnerPromise; - const bufferReentrantArg = {}; - Object.defineProperty(bufferReentrantArg, "x", { - get() { - bufferInnerPromise = _asyncFn("inner"); - return 1; - }, - enumerable: true, - }); - globalThis.__bufferOuterPromise = _asyncFn(bufferReentrantArg); - globalThis.__bufferInnerPromise = bufferInnerPromise; - "#; - { - let tc = &mut v8::TryCatch::new(scope); - let source = v8::String::new(tc, source).unwrap(); - let script = v8::Script::compile(tc, source, None).unwrap(); - assert!(script.run(tc).is_some()); - assert!( - !tc.has_caught(), - "async serialization reentry should not panic or throw" - ); - } - assert_eq!(buffer_reentry_pending.len(), 2); - assert_eq!(bridge_call_count(&buffer_reentry_writer.lock().unwrap()), 2); - } - - #[test] - fn vm_context_capacity_error_trips_at_registry_limit() { - assert!(vm_context_capacity_error(MAX_VM_CONTEXTS - 1).is_none()); - - let error = vm_context_capacity_error(MAX_VM_CONTEXTS).expect("limit error"); - assert!( - error.contains(&format!("limit of {MAX_VM_CONTEXTS} contexts")), - "unexpected error: {error}" - ); - } - - // Regression test for the `VM_CONTEXTS` leak: `reserve_vm_context_slot` adds a - // slot per `vm.createContext()`, but the success path never removes it. On a - // reused isolate thread that made the registry grow without bound across - // executions until it hit `MAX_VM_CONTEXTS` and every later `createContext()` - // failed. With the fix, a session's `VmContextRegistryGuard` evicts the slots - // at teardown, so the registry returns to empty between executions and the cap - // is never reached. This asserts the safeguard FIRING (slots reclaimed), it - // does not saturate any resource, so it stays in the default suite. - // - // Runs in a subprocess to match the V8-initializing test convention in this - // module (one isolate per process, no cross-test V8 interference). - #[test] - fn vm_context_registry_evicts_slots_on_finalize() { - const SUBPROCESS_ENV: &str = "AGENTOS_V8_VM_CONTEXT_FINALIZE_SUBPROCESS"; - if std::env::var_os(SUBPROCESS_ENV).is_none() { - let output = Command::new(std::env::current_exe().expect("current test binary")) - .arg("bridge::tests::vm_context_registry_evicts_slots_on_finalize") - .arg("--exact") - .arg("--nocapture") - .env(SUBPROCESS_ENV, "1") - .output() - .expect("spawn vm context finalize subprocess"); - assert!( - output.status.success(), - "vm context finalize subprocess failed with status {:?}\nstdout:\n{}\nstderr:\n{}", - output.status.code(), - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ); - return; - } - - isolate::init_v8_platform(); - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, context); - - reset_vm_context_registry(); - assert_eq!( - vm_context_registry_len_for_test(), - 0, - "registry starts empty" - ); - - // Simulate many executions on the same reused isolate. Each execution - // reserves several contexts and then finalizes (its session guard drops). - // Run far past the hard cap: a leaked slot per createContext would exhaust - // MAX_VM_CONTEXTS within the first ~341 executions and the `.expect` on the - // next reservation would panic. - const CONTEXTS_PER_EXECUTION: usize = 3; - let executions = MAX_VM_CONTEXTS * 4; - for execution in 0..executions { - { - let _guard = VmContextRegistryGuard::new(); - for _ in 0..CONTEXTS_PER_EXECUTION { - reserve_vm_context_slot(scope, context) - .expect("reserve vm context slot below cap; a leak would hit the cap"); - } - assert_eq!( - vm_context_registry_len_for_test(), - CONTEXTS_PER_EXECUTION, - "slots reserved during execution {execution} must be live" - ); - } - // Guard dropped above -> finalize. Asserting here, before the next - // execution's guard is constructed, proves the Drop sweep (not the - // start-of-session sweep) reclaimed the slots. - assert_eq!( - vm_context_registry_len_for_test(), - 0, - "registry must be empty after execution {execution} finalizes" - ); - } - - // After 4x the cap worth of reservations, a fresh createContext still - // succeeds because nothing leaked across executions. - let _guard = VmContextRegistryGuard::new(); - assert!( - reserve_vm_context_slot(scope, context).is_ok(), - "createContext must keep succeeding; leaked slots would have hit MAX_VM_CONTEXTS" - ); - } -} diff --git a/crates/v8-runtime/src/embedded_runtime.rs b/crates/v8-runtime/src/embedded_runtime.rs deleted file mode 100644 index 7c027ae9f..000000000 --- a/crates/v8-runtime/src/embedded_runtime.rs +++ /dev/null @@ -1,1338 +0,0 @@ -use std::collections::HashMap; -use std::collections::HashSet; -use std::io::{self, Write}; -use std::net::Shutdown; -use std::os::unix::net::UnixStream; -use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use std::sync::{mpsc, Arc, Mutex, OnceLock, Weak}; -use std::thread; -use std::time::Instant; - -use crate::host_call::{ - record_sync_bridge_host_phase, record_sync_bridge_response_channel_send_start, CallIdRouter, -}; -use crate::ipc_binary::BinaryFrame; -use crate::runtime_protocol::{ - validate_bridge_response_status, BridgeResponse, ModuleReaderHandle, RuntimeCommand, - RuntimeEvent, SessionMessage, StreamEvent, -}; -use crate::session::{RuntimeEventEnvelope, SessionCommand, SessionManager}; -use crate::snapshot::SnapshotCache; -use crate::{bridge, isolate}; - -static NEXT_CONNECTION_ID: AtomicU64 = AtomicU64::new(1); -const SESSION_OUTPUT_CHANNEL_CAPACITY: usize = 1024; - -pub struct EmbeddedV8Runtime { - session_mgr: Arc>, - session_outputs: Arc>>, - snapshot_cache: Arc, - alive: Arc, - dispatch_shutdown_tx: crossbeam_channel::Sender<()>, - dispatch_thread: Mutex>>, - next_output_generation: AtomicU64, -} - -#[derive(Clone)] -struct SessionOutput { - generation: u64, - sender: mpsc::SyncSender, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EmbeddedV8SessionOutputRegistration { - session_id: String, - generation: u64, -} - -impl EmbeddedV8Runtime { - pub fn new(max_concurrency: Option) -> io::Result { - bridge::init_codec(); - bridge::acquire_embedded_cbor_codec(); - isolate::init_v8_platform(); - - // Keep bridge-only, agent-SDK, and wasm-runner userland variants warm - // without immediately evicting each other. - let snapshot_cache = Arc::new(SnapshotCache::new(8)); - let (event_tx, event_rx) = crossbeam_channel::bounded::(1024); - let (dispatch_shutdown_tx, dispatch_shutdown_rx) = crossbeam_channel::bounded::<()>(1); - let call_id_router: CallIdRouter = Arc::new(Mutex::new(HashMap::new())); - let session_mgr = Arc::new(Mutex::new(SessionManager::new( - max_concurrency.unwrap_or_else(default_max_concurrency), - event_tx, - call_id_router, - Arc::clone(&snapshot_cache), - ))); - let session_outputs = Arc::new(Mutex::new(HashMap::new())); - let alive = Arc::new(AtomicBool::new(true)); - let alive_for_thread = Arc::clone(&alive); - let session_outputs_for_thread = Arc::clone(&session_outputs); - let session_mgr_for_thread = Arc::clone(&session_mgr); - - let dispatch_thread = thread::Builder::new() - .name(String::from("secure-exec-v8-runtime-dispatch")) - .spawn(move || { - loop { - crossbeam_channel::select! { - recv(event_rx) -> event => { - let Ok(event) = event else { - break; - }; - route_outbound_event( - event, - &session_outputs_for_thread, - &session_mgr_for_thread, - ); - } - recv(dispatch_shutdown_rx) -> _ => { - break; - } - } - } - alive_for_thread.store(false, Ordering::Release); - }) - .inspect_err(|_| bridge::release_embedded_cbor_codec())?; - - Ok(Self { - session_mgr, - session_outputs, - snapshot_cache, - alive, - dispatch_shutdown_tx, - dispatch_thread: Mutex::new(Some(dispatch_thread)), - next_output_generation: AtomicU64::new(1), - }) - } - - pub fn is_alive(&self) -> bool { - self.alive.load(Ordering::Acquire) - } - - pub fn snapshot_ready(&self, bridge_code: &str, userland_code: &str) -> bool { - if userland_code.is_empty() { - return true; - } - self.snapshot_cache - .try_get_with_userland(bridge_code, Some(userland_code)) - .is_some() - } - - pub fn pre_warm_workers( - &self, - bridge_code: String, - userland_code: String, - heap_limit_mb: Option, - count: usize, - ) { - self.session_mgr - .lock() - .expect("embedded runtime session manager lock poisoned") - .pre_warm_workers(bridge_code, userland_code, heap_limit_mb, count); - } - - pub fn register_session(&self, session_id: &str) -> io::Result> { - self.register_session_with_output_registration(session_id) - .map(|(receiver, _registration)| receiver) - } - - pub fn register_session_with_output_registration( - &self, - session_id: &str, - ) -> io::Result<( - mpsc::Receiver, - EmbeddedV8SessionOutputRegistration, - )> { - self.register_session_with_capacity(session_id, SESSION_OUTPUT_CHANNEL_CAPACITY) - } - - fn register_session_with_capacity( - &self, - session_id: &str, - capacity: usize, - ) -> io::Result<( - mpsc::Receiver, - EmbeddedV8SessionOutputRegistration, - )> { - let (sender, receiver) = mpsc::sync_channel(capacity); - let mut outputs = self - .session_outputs - .lock() - .expect("embedded runtime session outputs lock poisoned"); - if outputs.contains_key(session_id) { - return Err(io::Error::new( - io::ErrorKind::AlreadyExists, - format!("session output {session_id} already exists"), - )); - } - let generation = self.next_output_generation.fetch_add(1, Ordering::Relaxed); - outputs.insert(session_id.to_owned(), SessionOutput { generation, sender }); - Ok(( - receiver, - EmbeddedV8SessionOutputRegistration { - session_id: session_id.to_owned(), - generation, - }, - )) - } - - pub fn unregister_session(&self, session_id: &str) { - self.session_outputs - .lock() - .expect("embedded runtime session outputs lock poisoned") - .remove(session_id); - } - - pub fn destroy_session_if_output_current( - &self, - registration: &EmbeddedV8SessionOutputRegistration, - ) -> io::Result { - if !remove_session_output_if_current( - &self.session_outputs, - ®istration.session_id, - registration.generation, - ) { - return Ok(false); - } - - let shutdown = { - let mut mgr = self - .session_mgr - .lock() - .expect("session manager lock poisoned"); - mgr.begin_destroy_session_if_output_generation( - ®istration.session_id, - registration.generation, - ) - .map_err(other_io_error)? - }; - match shutdown { - Some(shutdown) => { - shutdown.finish(); - Ok(true) - } - None => Ok(false), - } - } - - pub fn session_handle(self: &Arc, session_id: String) -> EmbeddedV8SessionHandle { - EmbeddedV8SessionHandle { - session_id, - runtime: Arc::clone(self), - } - } - - pub fn dispatch(&self, command: RuntimeCommand) -> io::Result<()> { - match command { - RuntimeCommand::CreateSession { - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - warm_hint, - } => { - let output_generation = self - .session_outputs - .lock() - .expect("embedded runtime session outputs lock poisoned") - .get(&session_id) - .map(|output| output.generation); - let mut mgr = self - .session_mgr - .lock() - .expect("session manager lock poisoned"); - mgr.create_session_with_output_generation( - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - output_generation, - warm_hint, - ) - .map_err(other_io_error) - } - command => dispatch_runtime_command(&self.session_mgr, &self.snapshot_cache, command), - } - } - - pub fn session_count(&self) -> usize { - self.session_mgr - .lock() - .expect("embedded runtime session manager lock poisoned") - .session_count() - } - - pub fn active_slot_count(&self) -> usize { - self.session_mgr - .lock() - .expect("embedded runtime session manager lock poisoned") - .active_slot_count() - } -} - -impl Drop for EmbeddedV8Runtime { - fn drop(&mut self) { - let session_handles = self - .session_mgr - .lock() - .map(|mut mgr| mgr.take_session_shutdown_handles()) - .unwrap_or_default(); - for handle in session_handles { - let _ = handle.join(); - } - if let Ok(mut outputs) = self.session_outputs.lock() { - outputs.clear(); - } - let _ = self.dispatch_shutdown_tx.try_send(()); - if let Some(handle) = self.dispatch_thread.get_mut().ok().and_then(Option::take) { - let _ = handle.join(); - } - bridge::release_embedded_cbor_codec(); - } -} - -pub struct EmbeddedV8SessionHandle { - session_id: String, - runtime: Arc, -} - -impl EmbeddedV8SessionHandle { - // In-process runtime protocol call; the arg list mirrors the Execute frame. - #[allow(clippy::too_many_arguments)] - pub fn execute( - &self, - mode: u8, - file_path: String, - bridge_code: String, - post_restore_script: String, - userland_code: String, - high_resolution_time: bool, - user_code: String, - wasm_module_bytes: Option>>, - ) -> io::Result<()> { - validate_execute_mode(mode)?; - self.runtime.dispatch(RuntimeCommand::SendToSession { - session_id: self.session_id.clone(), - message: SessionMessage::Execute { - mode, - file_path, - bridge_code, - post_restore_script, - userland_code, - high_resolution_time, - user_code, - wasm_module_bytes, - }, - }) - } - - pub fn send_bridge_response( - &self, - call_id: u64, - status: u8, - payload: Vec, - ) -> io::Result<()> { - validate_bridge_response_status(status)?; - self.runtime.dispatch(RuntimeCommand::SendToSession { - session_id: self.session_id.clone(), - message: SessionMessage::BridgeResponse(BridgeResponse { - call_id, - status, - payload, - }), - }) - } - - pub fn send_stream_event(&self, event_type: &str, payload: Vec) -> io::Result<()> { - self.runtime.dispatch(RuntimeCommand::SendToSession { - session_id: self.session_id.clone(), - message: SessionMessage::StreamEvent(StreamEvent { - event_type: event_type.to_owned(), - payload, - }), - }) - } - - /// Install a direct module-source reader on this session's thread so module - /// loads read source directly instead of round-tripping the bridge. Routed - /// through the dispatch thread (which owns the session manager). - pub fn set_module_reader( - &self, - reader: Box, - ) -> io::Result<()> { - self.runtime - .dispatch(RuntimeCommand::SetSessionModuleReader { - session_id: self.session_id.clone(), - reader: ModuleReaderHandle::new(reader), - }) - } - - pub fn terminate(&self) -> io::Result<()> { - self.runtime.dispatch(RuntimeCommand::SendToSession { - session_id: self.session_id.clone(), - message: SessionMessage::TerminateExecution, - }) - } - - pub fn destroy(&self) -> io::Result<()> { - self.runtime.unregister_session(&self.session_id); - self.runtime.dispatch(RuntimeCommand::DestroySession { - session_id: self.session_id.clone(), - }) - } - - pub fn session_id(&self) -> &str { - &self.session_id - } -} - -fn validate_execute_mode(mode: u8) -> io::Result<()> { - if mode > 1 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("unknown Execute mode: {mode}"), - )); - } - Ok(()) -} - -impl Clone for EmbeddedV8SessionHandle { - fn clone(&self) -> Self { - Self { - session_id: self.session_id.clone(), - runtime: Arc::clone(&self.runtime), - } - } -} - -pub fn shared_embedded_runtime() -> io::Result> { - static SHARED_RUNTIME: OnceLock>> = OnceLock::new(); - - let shared_slot = SHARED_RUNTIME.get_or_init(|| Mutex::new(Weak::new())); - let mut shared_guard = shared_slot - .lock() - .expect("shared embedded runtime init lock poisoned"); - if let Some(shared) = shared_guard.upgrade() { - return Ok(shared); - } - - let shared = Arc::new(EmbeddedV8Runtime::new(None)?); - *shared_guard = Arc::downgrade(&shared); - Ok(shared) -} - -pub struct EmbeddedRuntimeHandle { - alive: Arc, - codec_released: AtomicBool, - shutdown_stream: UnixStream, - join_handle: Mutex>>, -} - -impl EmbeddedRuntimeHandle { - pub fn is_alive(&self) -> bool { - self.alive.load(Ordering::Acquire) - } - - pub fn shutdown(&self) { - let _ = self.shutdown_stream.shutdown(Shutdown::Both); - if let Ok(mut guard) = self.join_handle.lock() { - if let Some(handle) = guard.take() { - let _ = handle.join(); - } - } - self.release_codec(); - } - - fn release_codec(&self) { - if !self.codec_released.swap(true, Ordering::AcqRel) { - bridge::release_embedded_cbor_codec(); - } - } -} - -impl Drop for EmbeddedRuntimeHandle { - fn drop(&mut self) { - let _ = self.shutdown_stream.shutdown(Shutdown::Both); - if let Some(handle) = self.join_handle.get_mut().ok().and_then(Option::take) { - let _ = handle.join(); - } - self.release_codec(); - } -} - -pub fn spawn_embedded_runtime_ipc( - max_concurrency: Option, -) -> io::Result<(UnixStream, EmbeddedRuntimeHandle)> { - bridge::init_codec(); - bridge::acquire_embedded_cbor_codec(); - isolate::init_v8_platform(); - - let (host_stream, runtime_stream) = UnixStream::pair()?; - let shutdown_stream = host_stream.try_clone()?; - let alive = Arc::new(AtomicBool::new(true)); - let alive_for_thread = Arc::clone(&alive); - let max_concurrency = max_concurrency.unwrap_or_else(default_max_concurrency); - - let join_handle = thread::Builder::new() - .name(String::from("secure-exec-v8-runtime")) - .spawn(move || { - run_embedded_runtime(runtime_stream, max_concurrency); - alive_for_thread.store(false, Ordering::Release); - }) - .inspect_err(|_| bridge::release_embedded_cbor_codec())?; - - Ok(( - host_stream, - EmbeddedRuntimeHandle { - alive, - codec_released: AtomicBool::new(false), - shutdown_stream, - join_handle: Mutex::new(Some(join_handle)), - }, - )) -} - -fn default_max_concurrency() -> usize { - thread::available_parallelism() - .map(|count| count.get()) - .unwrap_or(4) -} - -fn run_embedded_runtime(stream: UnixStream, max_concurrency: usize) { - // Keep bridge-only, agent-SDK, and wasm-runner userland variants warm - // without immediately evicting each other. - let snapshot_cache = Arc::new(SnapshotCache::new(8)); - let writer_stream = match stream.try_clone() { - Ok(writer_stream) => writer_stream, - Err(error) => { - eprintln!("embedded V8 runtime failed to clone stream: {error}"); - return; - } - }; - let (event_tx, event_rx) = crossbeam_channel::bounded::(1024); - let call_id_router: CallIdRouter = Arc::new(Mutex::new(HashMap::new())); - let connection_id = NEXT_CONNECTION_ID.fetch_add(1, Ordering::Relaxed); - - let writer_handle = match thread::Builder::new() - .name(format!("v8-ipc-writer-{connection_id}")) - .spawn(move || ipc_writer_thread(event_rx, writer_stream)) - { - Ok(handle) => handle, - Err(error) => { - eprintln!("embedded V8 runtime failed to spawn writer thread: {error}"); - return; - } - }; - - let session_mgr = Arc::new(Mutex::new(SessionManager::new( - max_concurrency, - event_tx, - call_id_router, - Arc::clone(&snapshot_cache), - ))); - - handle_connection(stream, connection_id, session_mgr, snapshot_cache); - let _ = writer_handle.join(); -} - -fn ipc_writer_thread( - rx: crossbeam_channel::Receiver, - mut writer: UnixStream, -) { - while let Ok(envelope) = rx.recv() { - let frame: BinaryFrame = envelope.event.into(); - let bytes = match crate::ipc_binary::frame_to_bytes(&frame) { - Ok(bytes) => bytes, - Err(error) => { - eprintln!("embedded V8 runtime writer encode error: {error}"); - break; - } - }; - if let Err(error) = writer.write_all(&bytes) { - eprintln!("embedded V8 runtime writer error: {error}"); - break; - } - } -} - -fn handle_connection( - mut stream: UnixStream, - connection_id: u64, - session_mgr: Arc>, - snapshot_cache: Arc, -) { - let mut session_ids = HashSet::new(); - - loop { - let frame = match crate::ipc_binary::read_frame(&mut stream) { - Ok(frame) => frame, - Err(ref error) if error.kind() == io::ErrorKind::UnexpectedEof => break, - Err(error) => { - eprintln!("embedded V8 runtime read error on connection {connection_id}: {error}"); - break; - } - }; - - let command = match RuntimeCommand::try_from(frame) { - Ok(command) => command, - Err(error) => { - eprintln!( - "embedded V8 runtime dispatch error on connection {connection_id}: {error}" - ); - continue; - } - }; - - if let RuntimeCommand::CreateSession { session_id, .. } = &command { - session_ids.insert(session_id.clone()); - } else if let RuntimeCommand::DestroySession { session_id } = &command { - session_ids.remove(session_id); - } - - if let Err(error) = dispatch_runtime_command(&session_mgr, &snapshot_cache, command) { - eprintln!("embedded V8 runtime dispatch error on connection {connection_id}: {error}"); - } - } - - let shutdowns = { - let mut mgr = session_mgr.lock().expect("session manager lock poisoned"); - mgr.begin_destroy_sessions(session_ids) - }; - for shutdown in shutdowns { - shutdown.finish(); - } -} - -fn dispatch_runtime_command( - session_mgr: &Arc>, - snapshot_cache: &Arc, - command: RuntimeCommand, -) -> io::Result<()> { - match command { - RuntimeCommand::CreateSession { - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - warm_hint, - } => { - let mut mgr = session_mgr.lock().expect("session manager lock poisoned"); - mgr.create_session_with_output_generation( - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - None, - warm_hint, - ) - .map_err(other_io_error) - } - RuntimeCommand::DestroySession { session_id } => { - let shutdown = { - let mut mgr = session_mgr.lock().expect("session manager lock poisoned"); - mgr.begin_destroy_session(&session_id) - .map_err(other_io_error)? - }; - shutdown.finish(); - Ok(()) - } - RuntimeCommand::SendToSession { - session_id, - message, - } => { - // Resolve the sender and apply terminate side effects under the - // lock, then send after releasing it so a full session command - // channel cannot block the manager mutex. - let is_bridge_response = matches!(&message, SessionMessage::BridgeResponse(_)); - let sender = { - let mgr = session_mgr.lock().expect("session manager lock poisoned"); - let routed_session_id = match &message { - SessionMessage::BridgeResponse(response) => { - let phase_start = Instant::now(); - let routed_session_id = mgr - .call_id_router() - .lock() - .expect("call_id router lock poisoned") - .remove(&response.call_id) - .unwrap_or(session_id); - record_sync_bridge_host_phase( - "sync_rpc_dispatch", - "dispatch_route_lookup", - phase_start.elapsed(), - ); - routed_session_id - } - SessionMessage::InjectGlobals { .. } - | SessionMessage::Execute { .. } - | SessionMessage::StreamEvent(_) - | SessionMessage::TerminateExecution => session_id, - }; - let phase_start = Instant::now(); - let sender = mgr - .session_command_sender(&routed_session_id, &message) - .map_err(other_io_error)?; - if is_bridge_response { - record_sync_bridge_host_phase( - "sync_rpc_dispatch", - "dispatch_sender_lookup", - phase_start.elapsed(), - ); - } - sender - }; - if let SessionMessage::BridgeResponse(response) = &message { - record_sync_bridge_response_channel_send_start(response.call_id); - } - let phase_start = Instant::now(); - let result = sender - .send(SessionCommand::Message(message)) - .map_err(|e| other_io_error(format!("session thread disconnected: {}", e))); - if is_bridge_response { - record_sync_bridge_host_phase( - "sync_rpc_dispatch", - "dispatch_channel_send", - phase_start.elapsed(), - ); - } - result - } - RuntimeCommand::SetSessionModuleReader { session_id, reader } => { - // Resolve the sender under the lock, release, then forward the live - // reader as a SetModuleReader command to the session thread. - let sender = { - let mgr = session_mgr.lock().expect("session manager lock poisoned"); - mgr.session_sender(&session_id) - }; - let sender = sender.map_err(other_io_error)?; - match reader.take() { - Some(reader) => sender - .send(SessionCommand::SetModuleReader(reader)) - .map_err(|e| other_io_error(format!("session thread disconnected: {}", e))), - None => Ok(()), - } - } - RuntimeCommand::WarmSnapshot { - bridge_code, - userland_code, - } => snapshot_cache - .get_or_create_with_userland( - &bridge_code, - (!userland_code.is_empty()).then_some(userland_code.as_str()), - ) - .map(|_| ()) - .map_err(other_io_error), - } -} - -fn route_outbound_event( - envelope: RuntimeEventEnvelope, - session_outputs: &Arc>>, - session_mgr: &Arc>, -) -> bool { - let RuntimeEventEnvelope { - output_generation, - event, - } = envelope; - let session_id = event.session_id().to_owned(); - - let output = session_outputs - .lock() - .expect("embedded runtime session outputs lock poisoned") - .get(&session_id) - .cloned(); - - let Some(output) = output else { - clear_dropped_bridge_call_route(&event, session_mgr); - return false; - }; - - if output_generation != Some(output.generation) { - clear_dropped_bridge_call_route(&event, session_mgr); - return false; - } - - match output.sender.try_send(event) { - Ok(()) => {} - Err(mpsc::TrySendError::Full(_)) | Err(mpsc::TrySendError::Disconnected(_)) => { - if remove_session_output_if_current(session_outputs, &session_id, output.generation) { - return session_mgr - .lock() - .expect("session manager lock poisoned") - .detach_session_if_output_generation(&session_id, output.generation) - .unwrap_or(false); - } - } - } - false -} - -fn clear_dropped_bridge_call_route(event: &RuntimeEvent, session_mgr: &Arc>) { - if let RuntimeEvent::BridgeCall { call_id, .. } = event { - session_mgr - .lock() - .expect("session manager lock poisoned") - .clear_call_route(*call_id); - } -} - -fn remove_session_output_if_current( - session_outputs: &Arc>>, - session_id: &str, - generation: u64, -) -> bool { - let mut outputs = session_outputs - .lock() - .expect("embedded runtime session outputs lock poisoned"); - if outputs - .get(session_id) - .is_some_and(|output| output.generation == generation) - { - outputs.remove(session_id); - return true; - } - false -} - -fn other_io_error(message: String) -> io::Error { - io::Error::other(message) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::runtime_protocol::{BridgeResponse, RuntimeCommand, RuntimeEvent, SessionMessage}; - use std::time::Duration; - - static EMBEDDED_RUNTIME_CODEC_TEST_LOCK: Mutex<()> = Mutex::new(()); - - #[test] - fn embedded_runtime_handle_reports_liveness_and_shutdown() { - let _codec_guard = EMBEDDED_RUNTIME_CODEC_TEST_LOCK - .lock() - .expect("embedded runtime codec test lock poisoned"); - let (_stream, handle) = - spawn_embedded_runtime_ipc(Some(1)).expect("spawn embedded runtime"); - assert!( - handle.is_alive(), - "embedded runtime should be alive after spawn" - ); - handle.shutdown(); - assert!( - !handle.is_alive(), - "embedded runtime should report not alive after shutdown" - ); - } - - #[test] - fn embedded_runtime_session_shared_runtime_is_lazy() { - let _codec_guard = EMBEDDED_RUNTIME_CODEC_TEST_LOCK - .lock() - .expect("embedded runtime codec test lock poisoned"); - let first = shared_embedded_runtime().expect("shared embedded runtime"); - let second = shared_embedded_runtime().expect("shared embedded runtime"); - assert!( - Arc::ptr_eq(&first, &second), - "shared_embedded_runtime() should reuse the same runtime instance" - ); - } - - #[test] - fn embedded_runtime_drop_releases_codec_after_destroying_sessions() { - let _codec_guard = EMBEDDED_RUNTIME_CODEC_TEST_LOCK - .lock() - .expect("embedded runtime codec test lock poisoned"); - let codec_before = bridge::is_cbor_codec(); - let alive = { - let runtime = EmbeddedV8Runtime::new(Some(1)).expect("embedded runtime"); - let alive = Arc::clone(&runtime.alive); - assert!( - bridge::is_cbor_codec(), - "embedded runtime should enable the CBOR bridge codec while alive" - ); - let (_receiver, _registration) = runtime - .register_session_with_output_registration("drop-lifecycle") - .expect("register session output"); - runtime - .dispatch(RuntimeCommand::CreateSession { - session_id: "drop-lifecycle".into(), - heap_limit_mb: None, - cpu_time_limit_ms: None, - wall_clock_limit_ms: None, - warm_hint: None, - }) - .expect("create session"); - assert_eq!( - runtime.session_count(), - 1, - "test should drop a runtime with a live session" - ); - alive - }; - - assert!( - !alive.load(Ordering::Acquire), - "dropping embedded runtime should stop the dispatch thread" - ); - assert_eq!( - bridge::is_cbor_codec(), - codec_before, - "dropping embedded runtime should restore the prior codec state" - ); - } - - #[test] - fn embedded_runtime_stream_bridge_response_routing_prefers_call_id_router() { - let snapshot_cache = Arc::new(SnapshotCache::new(1)); - let (event_tx, _event_rx) = crossbeam_channel::unbounded::(); - let call_id_router: CallIdRouter = Arc::new(Mutex::new(HashMap::new())); - let session_mgr = Arc::new(Mutex::new(SessionManager::new( - 1, - event_tx, - Arc::clone(&call_id_router), - Arc::clone(&snapshot_cache), - ))); - - { - let mut mgr = session_mgr.lock().expect("session manager"); - mgr.create_session("stream-target".into(), None, None, None) - .expect("create target session"); - } - call_id_router - .lock() - .expect("call_id router") - .insert(41, "stream-target".into()); - - dispatch_runtime_command( - &session_mgr, - &snapshot_cache, - RuntimeCommand::SendToSession { - session_id: "wrong-session".into(), - message: SessionMessage::BridgeResponse(BridgeResponse { - call_id: 41, - status: 0, - payload: vec![0xAB], - }), - }, - ) - .expect("bridge response should route via call_id table"); - - assert!( - call_id_router - .lock() - .expect("call_id router") - .get(&41) - .is_none(), - "bridge response routing should consume the call_id entry" - ); - - session_mgr - .lock() - .expect("session manager") - .destroy_session("stream-target") - .expect("destroy target session"); - } - - #[test] - fn embedded_runtime_session_handle_rejects_unknown_bridge_response_status() { - let _codec_guard = EMBEDDED_RUNTIME_CODEC_TEST_LOCK - .lock() - .expect("embedded runtime codec test lock poisoned"); - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1)).expect("embedded runtime")); - let handle = runtime.session_handle("missing-session".into()); - - let err = handle - .send_bridge_response(1, 3, Vec::new()) - .expect_err("unknown bridge response status should be rejected"); - - assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - assert!(err.to_string().contains("unknown BridgeResponse status")); - } - - #[test] - fn embedded_runtime_stream_events_preserve_order_per_session() { - let (sender, receiver) = mpsc::sync_channel(SESSION_OUTPUT_CHANNEL_CAPACITY); - let session_outputs = Arc::new(Mutex::new(HashMap::from([( - String::from("stream-order"), - SessionOutput { - generation: 1, - sender, - }, - )]))); - let session_mgr = test_session_manager(); - - route_outbound_event( - runtime_envelope( - 1, - RuntimeEvent::Log { - session_id: "stream-order".into(), - channel: 0, - message: "first".into(), - }, - ), - &session_outputs, - &session_mgr, - ); - route_outbound_event( - runtime_envelope( - 1, - RuntimeEvent::StreamCallback { - session_id: "stream-order".into(), - callback_type: "stdin".into(), - payload: vec![1, 2, 3], - }, - ), - &session_outputs, - &session_mgr, - ); - - let first = receiver - .recv_timeout(Duration::from_millis(100)) - .expect("first event"); - let second = receiver - .recv_timeout(Duration::from_millis(100)) - .expect("second event"); - - assert!(matches!( - first, - RuntimeEvent::Log { ref message, .. } if message == "first" - )); - assert!(matches!( - second, - RuntimeEvent::StreamCallback { ref callback_type, ref payload, .. } - if callback_type == "stdin" && payload == &vec![1, 2, 3] - )); - } - - #[test] - fn embedded_runtime_stream_termination_race_drops_late_events_after_receiver_close() { - let (sender, receiver) = mpsc::sync_channel(SESSION_OUTPUT_CHANNEL_CAPACITY); - let session_outputs = Arc::new(Mutex::new(HashMap::from([( - String::from("stream-race"), - SessionOutput { - generation: 1, - sender, - }, - )]))); - let session_mgr = test_session_manager(); - drop(receiver); - - route_outbound_event( - runtime_envelope( - 1, - RuntimeEvent::ExecutionResult { - session_id: "stream-race".into(), - exit_code: 0, - exports: None, - error: None, - }, - ), - &session_outputs, - &session_mgr, - ); - - assert!( - session_outputs - .lock() - .expect("session outputs") - .get("stream-race") - .is_none(), - "late events should drop stale receiver registrations during teardown races" - ); - } - - #[test] - fn embedded_runtime_stream_backpressure_drops_full_session_output() { - let (sender, receiver) = mpsc::sync_channel(1); - let session_outputs = Arc::new(Mutex::new(HashMap::from([( - String::from("stream-full"), - SessionOutput { - generation: 1, - sender, - }, - )]))); - let session_mgr = test_session_manager_with_session("stream-full"); - - route_outbound_event( - runtime_envelope( - 1, - RuntimeEvent::Log { - session_id: "stream-full".into(), - channel: 0, - message: "first".into(), - }, - ), - &session_outputs, - &session_mgr, - ); - let cleaned_up = route_outbound_event( - runtime_envelope( - 1, - RuntimeEvent::Log { - session_id: "stream-full".into(), - channel: 0, - message: "second".into(), - }, - ), - &session_outputs, - &session_mgr, - ); - assert!(cleaned_up, "full session output should detach the session"); - - let first = receiver - .recv_timeout(Duration::from_millis(100)) - .expect("first event"); - assert!(matches!( - first, - RuntimeEvent::Log { ref message, .. } if message == "first" - )); - assert!( - receiver.recv_timeout(Duration::from_millis(20)).is_err(), - "full session output should drop the overflowing event" - ); - assert!( - session_outputs - .lock() - .expect("session outputs") - .get("stream-full") - .is_none(), - "full session output should remove the stale registration" - ); - assert_eq!( - session_mgr.lock().expect("session manager").session_count(), - 0, - "full session output should destroy the runtime session" - ); - } - - #[test] - fn embedded_runtime_drops_stale_generation_events_for_reused_session_id() { - let (sender, receiver) = mpsc::sync_channel(SESSION_OUTPUT_CHANNEL_CAPACITY); - let session_outputs = Arc::new(Mutex::new(HashMap::from([( - String::from("stream-reused"), - SessionOutput { - generation: 2, - sender, - }, - )]))); - let session_mgr = test_session_manager_with_generation("stream-reused", 2); - session_mgr - .lock() - .expect("session manager") - .call_id_router() - .lock() - .expect("call_id router") - .insert(99, "stream-reused".into()); - - let routed = route_outbound_event( - runtime_envelope( - 1, - RuntimeEvent::BridgeCall { - session_id: "stream-reused".into(), - call_id: 99, - method: "_stale".into(), - payload: Vec::new(), - }, - ), - &session_outputs, - &session_mgr, - ); - - assert!(!routed, "stale generation event should not trigger cleanup"); - assert!( - receiver.recv_timeout(Duration::from_millis(20)).is_err(), - "stale generation event should not reach reused session output" - ); - assert_eq!( - session_mgr.lock().expect("session manager").session_count(), - 1, - "stale generation event must leave reused session alive" - ); - assert!( - session_mgr - .lock() - .expect("session manager") - .call_id_router() - .lock() - .expect("call_id router") - .get(&99) - .is_none(), - "stale bridge calls should clear their call route" - ); - } - - #[test] - fn embedded_runtime_clears_bridge_route_when_output_is_missing() { - let session_outputs = Arc::new(Mutex::new(HashMap::new())); - let session_mgr = test_session_manager(); - session_mgr - .lock() - .expect("session manager") - .call_id_router() - .lock() - .expect("call_id router") - .insert(123, "stream-detached".into()); - - let routed = route_outbound_event( - runtime_envelope( - 1, - RuntimeEvent::BridgeCall { - session_id: "stream-detached".into(), - call_id: 123, - method: "_detached".into(), - payload: Vec::new(), - }, - ), - &session_outputs, - &session_mgr, - ); - - assert!(!routed, "missing output should not route the bridge call"); - assert!( - session_mgr - .lock() - .expect("session manager") - .call_id_router() - .lock() - .expect("call_id router") - .get(&123) - .is_none(), - "bridge calls dropped with no output should clear their call route" - ); - } - - #[test] - fn embedded_runtime_stale_output_registration_cannot_destroy_reused_session_id() { - let _codec_guard = EMBEDDED_RUNTIME_CODEC_TEST_LOCK - .lock() - .expect("embedded runtime codec test lock poisoned"); - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1)).expect("embedded runtime")); - let session_id = "stream-generation-reuse"; - let (_first_receiver, first_registration) = runtime - .register_session_with_capacity(session_id, 1) - .expect("register first session output"); - runtime - .dispatch(RuntimeCommand::CreateSession { - session_id: session_id.into(), - heap_limit_mb: None, - cpu_time_limit_ms: None, - wall_clock_limit_ms: None, - warm_hint: None, - }) - .expect("create first session"); - runtime - .session_handle(session_id.into()) - .destroy() - .expect("destroy first session"); - - let (_second_receiver, _second_registration) = runtime - .register_session_with_capacity(session_id, 1) - .expect("register reused session output"); - runtime - .dispatch(RuntimeCommand::CreateSession { - session_id: session_id.into(), - heap_limit_mb: None, - cpu_time_limit_ms: None, - wall_clock_limit_ms: None, - warm_hint: None, - }) - .expect("create reused session"); - - assert!( - !runtime - .destroy_session_if_output_current(&first_registration) - .expect("stale destroy should be ignored"), - "stale registration should not match the reused session output" - ); - assert_eq!( - runtime.session_count(), - 1, - "stale registration must not destroy the reused session" - ); - - runtime - .session_handle(session_id.into()) - .destroy() - .expect("destroy reused session"); - } - - #[test] - fn session_cleanup_generation_guard_does_not_destroy_reused_session_id() { - let session_mgr = test_session_manager(); - { - let mut mgr = session_mgr.lock().expect("session manager"); - mgr.create_session_with_output_generation( - "reused".into(), - None, - None, - None, - Some(1), - None, - ) - .expect("create first session"); - mgr.destroy_session("reused") - .expect("destroy first session"); - mgr.create_session_with_output_generation( - "reused".into(), - None, - None, - None, - Some(2), - None, - ) - .expect("create reused session"); - - assert!( - !mgr.destroy_session_if_output_generation("reused", 1) - .expect("stale generation destroy should be ignored"), - "stale cleanup generation should not match reused session" - ); - assert_eq!( - mgr.session_count(), - 1, - "stale cleanup generation must leave reused session alive" - ); - mgr.destroy_session("reused") - .expect("destroy reused session"); - } - } - - fn test_session_manager() -> Arc> { - let (event_tx, _event_rx) = crossbeam_channel::bounded::(1); - Arc::new(Mutex::new(SessionManager::new( - 1, - event_tx, - Arc::new(Mutex::new(HashMap::new())), - Arc::new(SnapshotCache::new(1)), - ))) - } - - fn runtime_envelope(output_generation: u64, event: RuntimeEvent) -> RuntimeEventEnvelope { - RuntimeEventEnvelope { - output_generation: Some(output_generation), - event, - } - } - - fn test_session_manager_with_session(session_id: &str) -> Arc> { - test_session_manager_with_generation(session_id, 1) - } - - fn test_session_manager_with_generation( - session_id: &str, - output_generation: u64, - ) -> Arc> { - let session_mgr = test_session_manager(); - session_mgr - .lock() - .expect("session manager") - .create_session_with_output_generation( - session_id.into(), - None, - None, - None, - Some(output_generation), - None, - ) - .expect("create test session"); - session_mgr - } -} diff --git a/crates/v8-runtime/src/execution.rs b/crates/v8-runtime/src/execution.rs deleted file mode 100644 index 0e811ad3a..000000000 --- a/crates/v8-runtime/src/execution.rs +++ /dev/null @@ -1,7903 +0,0 @@ -// Script compilation, CJS/ESM execution, module loading - -use std::cell::RefCell; -use std::collections::{HashMap, HashSet}; -use std::ffi::c_void; -use std::num::NonZeroI32; -use std::time::Instant; - -// ── Module-load read/compile split (opt-in via AGENTOS_MODULE_TRACE=1) ── -// Per module miss: resolve IPC + load (read) IPC + format IPC + V8 compile. -// Accumulates ns per category and writes a running total to -// AGENTOS_MODULE_TRACE_FILE so we can see whether the VM module-load tax is -// IPC (read) or V8 compile bound. Index: 0=count 1=resolve 2=load 3=format 4=compile. -static MOD_TRACE: std::sync::OnceLock> = std::sync::OnceLock::new(); - -fn mod_trace_enabled() -> bool { - std::env::var("AGENTOS_MODULE_TRACE").as_deref() == Ok("1") -} - -fn record_mod(idx: usize, ns: u64) { - let m = MOD_TRACE.get_or_init(|| std::sync::Mutex::new([0u64; 5])); - let Ok(mut a) = m.lock() else { - return; - }; - a[idx] = a[idx].wrapping_add(ns); - if idx == 4 { - a[0] += 1; - if a[0] % 25 == 0 { - if let Ok(path) = std::env::var("AGENTOS_MODULE_TRACE_FILE") { - let _ = std::fs::write( - &path, - format!( - "modules={} resolve_ms={} load_ms={} format_ms={} compile_ms={}\n", - a[0], - a[1] / 1_000_000, - a[2] / 1_000_000, - a[3] / 1_000_000, - a[4] / 1_000_000, - ), - ); - } - } - } -} - -use crate::bridge::{deserialize_v8_value, serialize_v8_value}; -use crate::host_call::BridgeCallContext; -use crate::ipc::ExecutionError; -#[cfg(test)] -use crate::ipc::{OsConfig, ProcessConfig}; - -/// Cached V8 code cache data for bridge code compilation. -/// -/// Stores the compiled bytecode from V8's ScriptCompiler::CreateCodeCache -/// along with a hash of the source for invalidation. On subsequent -/// compilations with the same bridge code, the cache is consumed via -/// CompileOptions::ConsumeCodeCache, skipping parsing and initial compilation. -pub struct BridgeCodeCache { - /// FNV-1a hash of the bridge code source string - source_hash: u64, - /// Raw code cache bytes from UnboundScript::create_code_cache() - cached_data: Vec, -} - -impl BridgeCodeCache { - /// Compute FNV-1a hash of bridge code source - fn hash_source(source: &str) -> u64 { - let mut hash: u64 = 0xcbf29ce484222325; - for byte in source.as_bytes() { - hash ^= *byte as u64; - hash = hash.wrapping_mul(0x100000001b3); - } - hash - } -} - -/// Inject `_processConfig` and `_osConfig` as frozen, non-writable, non-configurable -/// global properties, and harden the context (remove SharedArrayBuffer in freeze mode). -/// -/// Must be called within a ContextScope. -#[cfg(test)] -pub fn inject_globals( - scope: &mut v8::HandleScope, - process_config: &ProcessConfig, - os_config: &OsConfig, -) { - let context = scope.get_current_context(); - let global = context.global(scope); - // Build and freeze _processConfig - let pc_obj = build_process_config(scope, process_config); - pc_obj.set_integrity_level(scope, v8::IntegrityLevel::Frozen); - let pc_key = v8::String::new(scope, "_processConfig").unwrap(); - let attr = v8::PropertyAttribute::READ_ONLY | v8::PropertyAttribute::DONT_DELETE; - global.define_own_property(scope, pc_key.into(), pc_obj.into(), attr); - - // Build and freeze _osConfig - let os_obj = build_os_config(scope, os_config); - os_obj.set_integrity_level(scope, v8::IntegrityLevel::Frozen); - let os_key = v8::String::new(scope, "_osConfig").unwrap(); - let attr = v8::PropertyAttribute::READ_ONLY | v8::PropertyAttribute::DONT_DELETE; - global.define_own_property(scope, os_key.into(), os_obj.into(), attr); - - // SharedArrayBuffer removal for timing mitigation is handled by the JS-side - // bridge code (applyTimingMitigationFreeze), which runs AFTER the bridge bundle - // loads. The bridge bundle depends on SharedArrayBuffer being available during - // its initialization (whatwg-url/webidl-conversions uses it). -} - -pub fn install_high_resolution_time_global(scope: &mut v8::HandleScope, origin: *const Instant) { - let context = scope.get_current_context(); - let global = context.global(scope); - let external = v8::External::new(scope, origin as *mut c_void); - let template = v8::FunctionTemplate::builder(high_resolution_time_callback) - .data(external.into()) - .build(scope); - let Some(func) = template.get_function(scope) else { - return; - }; - let key = v8::String::new(scope, "__secureExecHrNowUs").unwrap(); - let attr = v8::PropertyAttribute::READ_ONLY | v8::PropertyAttribute::DONT_DELETE; - global.define_own_property(scope, key.into(), func.into(), attr); -} - -fn high_resolution_time_callback( - scope: &mut v8::HandleScope, - args: v8::FunctionCallbackArguments, - mut rv: v8::ReturnValue, -) { - let external = match v8::Local::::try_from(args.data()) { - Ok(ext) => ext, - Err(_) => { - let msg = v8::String::new(scope, "internal error: missing hrtime origin").unwrap(); - let exc = v8::Exception::error(scope, msg); - scope.throw_exception(exc); - return; - } - }; - // SAFETY: the pointer targets the session thread's per-isolate Instant, - // which is kept alive for the lifetime of the V8 session thread. - let origin = unsafe { &*(external.value() as *const Instant) }; - let micros = origin.elapsed().as_secs_f64() * 1_000_000.0; - rv.set(v8::Number::new(scope, micros).into()); -} - -/// Inject globals from a V8-serialized payload containing { processConfig, osConfig }. -/// -/// The payload is produced by node:v8.serialize() on the host side. -/// Deserializes into V8, extracts processConfig and osConfig, freezes them, -/// and sets them as non-writable, non-configurable global properties. -pub fn inject_globals_from_payload( - scope: &mut v8::HandleScope, - payload: &[u8], -) -> Result<(), ExecutionError> { - let context = scope.get_current_context(); - let global = context.global(scope); - - // Deserialize the V8 payload { processConfig, osConfig } - let config_val = deserialize_v8_value(scope, payload) - .map_err(|err| invalid_globals_payload_error(format!("decode failed: {err}")))?; - - if !config_val.is_object() { - return Err(invalid_globals_payload_error("payload is not an object")); - } - let config_obj = v8::Local::::try_from(config_val) - .map_err(|_| invalid_globals_payload_error("payload is not an object"))?; - if !is_plain_config_object(scope, config_obj) { - return Err(invalid_globals_payload_error( - "payload is not a plain object", - )); - } - - // Validate both config objects before mutating globals so malformed payloads - // cannot leave a partially injected execution context. - let (pc_val, pc_obj) = required_object_property(scope, config_obj, "processConfig")?; - let (oc_val, oc_obj) = required_object_property(scope, config_obj, "osConfig")?; - - let (_env_val, env_obj) = - required_object_property_with_label(scope, pc_obj, "env", "processConfig.env")?; - freeze_config_object(scope, env_obj, "processConfig.env")?; - freeze_config_object(scope, pc_obj, "processConfig")?; - freeze_config_object(scope, oc_obj, "osConfig")?; - let global_key = v8::String::new(scope, "_processConfig").unwrap(); - let attr = v8::PropertyAttribute::READ_ONLY | v8::PropertyAttribute::DONT_DELETE; - global.define_own_property(scope, global_key.into(), pc_val, attr); - - let global_key = v8::String::new(scope, "_osConfig").unwrap(); - let attr = v8::PropertyAttribute::READ_ONLY | v8::PropertyAttribute::DONT_DELETE; - global.define_own_property(scope, global_key.into(), oc_val, attr); - - Ok(()) -} - -fn required_object_property<'s>( - scope: &mut v8::HandleScope<'s>, - obj: v8::Local<'s, v8::Object>, - name: &str, -) -> Result<(v8::Local<'s, v8::Value>, v8::Local<'s, v8::Object>), ExecutionError> { - required_object_property_with_label(scope, obj, name, name) -} - -fn required_object_property_with_label<'s>( - scope: &mut v8::HandleScope<'s>, - obj: v8::Local<'s, v8::Object>, - name: &str, - error_label: &str, -) -> Result<(v8::Local<'s, v8::Value>, v8::Local<'s, v8::Object>), ExecutionError> { - let key = v8::String::new(scope, name).unwrap(); - let value = obj - .get(scope, key.into()) - .filter(|value| !value.is_null_or_undefined()) - .ok_or_else(|| invalid_globals_payload_error(format!("missing {error_label}")))?; - if !value.is_object() { - return Err(invalid_globals_payload_error(format!( - "{error_label} is not an object" - ))); - } - let object = v8::Local::::try_from(value) - .map_err(|_| invalid_globals_payload_error(format!("{error_label} is not an object")))?; - if !is_plain_config_object(scope, object) { - return Err(invalid_globals_payload_error(format!( - "{error_label} is not a plain object" - ))); - } - Ok((value, object)) -} - -fn is_plain_config_object(scope: &mut v8::HandleScope, object: v8::Local) -> bool { - let Some(prototype) = object.get_prototype(scope) else { - return false; - }; - if prototype.is_null() { - return true; - } - if !prototype.is_object() { - return false; - } - let Ok(prototype_object) = v8::Local::::try_from(prototype) else { - return false; - }; - prototype_object - .get_prototype(scope) - .is_some_and(|parent| parent.is_null()) -} - -fn freeze_config_object( - scope: &mut v8::HandleScope, - object: v8::Local, - label: &str, -) -> Result<(), ExecutionError> { - match object.set_integrity_level(scope, v8::IntegrityLevel::Frozen) { - Some(true) => Ok(()), - Some(false) | None => Err(invalid_globals_payload_error(format!( - "failed to freeze {label}" - ))), - } -} - -fn invalid_globals_payload_error(message: impl Into) -> ExecutionError { - ExecutionError { - error_type: "Error".into(), - message: format!("invalid InjectGlobals payload: {}", message.into()), - stack: String::new(), - code: Some("ERR_INVALID_GLOBALS_PAYLOAD".into()), - } -} - -/// Compile and run bridge code as a V8 Script, using code cache if available. -/// -/// On cache miss (first compilation or hash mismatch): compiles with -/// NoCompileOptions and creates a code cache from the resulting UnboundScript. -/// On cache hit: compiles with ConsumeCodeCache using the cached bytecode. -/// Creates its own TryCatch scope internally so the caller's scope is released. -/// Returns (exit_code, error) — exit code 0 on success. -fn run_bridge_cached( - scope: &mut v8::HandleScope, - bridge_code: &str, - cache: &mut Option, -) -> (i32, Option) { - let tc = &mut v8::TryCatch::new(scope); - - let v8_source = match v8::String::new(tc, bridge_code) { - Some(s) => s, - None => { - return ( - 1, - Some(ExecutionError { - error_type: "Error".into(), - message: "bridge code string too large for V8".into(), - stack: String::new(), - code: None, - }), - ); - } - }; - - // Resource name for bridge code (needed for code cache to work) - let resource_name = v8::String::new(tc, "").unwrap(); - let origin = v8::ScriptOrigin::new( - tc, - resource_name.into(), - 0, - 0, - false, - -1, - None, - false, - false, - false, - None, - ); - - let source_hash = BridgeCodeCache::hash_source(bridge_code); - - // Check if cache is valid for this bridge code - let cache_hit = cache.as_ref().is_some_and(|c| c.source_hash == source_hash); - - let script = if cache_hit { - // Consume cached bytecode - let cached_bytes = &cache.as_ref().unwrap().cached_data; - let cached_data = v8::script_compiler::CachedData::new(cached_bytes); - let mut source = v8::script_compiler::Source::new_with_cached_data( - v8_source, - Some(&origin), - cached_data, - ); - let compiled = v8::script_compiler::compile( - tc, - &mut source, - v8::script_compiler::CompileOptions::ConsumeCodeCache, - v8::script_compiler::NoCacheReason::NoReason, - ); - // If cache was rejected, invalidate it (will be regenerated next time) - if source.get_cached_data().is_some_and(|cd| cd.rejected()) { - *cache = None; - } - compiled - } else { - // First compilation or cache invalidated — compile without cache - let mut source = v8::script_compiler::Source::new(v8_source, Some(&origin)); - let compiled = v8::script_compiler::compile( - tc, - &mut source, - v8::script_compiler::CompileOptions::NoCompileOptions, - v8::script_compiler::NoCacheReason::NoReason, - ); - // Generate code cache from the compiled script - if let Some(ref script) = compiled { - let unbound = script.get_unbound_script(tc); - if let Some(code_cache) = unbound.create_code_cache() { - *cache = Some(BridgeCodeCache { - source_hash, - cached_data: code_cache.to_vec(), - }); - } - } - compiled - }; - - // Run the compiled script - let script = match script { - Some(s) => s, - None => { - return match tc.exception() { - Some(e) => { - let (c, err) = exception_to_result(tc, e); - (c, Some(err)) - } - None => (1, None), - }; - } - }; - - if script.run(tc).is_none() { - return match tc.exception() { - Some(e) => { - let (c, err) = exception_to_result(tc, e); - (c, Some(err)) - } - None => (1, None), - }; - } - - (0, None) -} - -/// Run a short init script (e.g. post-restore config). Compiles and executes -/// via v8::Script, returning (exit_code, error) on failure. No code caching. -#[cfg(not(test))] -pub fn run_init_script(scope: &mut v8::HandleScope, code: &str) -> (i32, Option) { - if code.is_empty() { - return (0, None); - } - let tc = &mut v8::TryCatch::new(scope); - let source = match v8::String::new(tc, code) { - Some(s) => s, - None => { - return ( - 1, - Some(ExecutionError { - error_type: "Error".into(), - message: "init script string too large for V8".into(), - stack: String::new(), - code: None, - }), - ); - } - }; - let script = match v8::Script::compile(tc, source, None) { - Some(s) => s, - None => { - return match tc.exception() { - Some(e) => { - let (c, err) = exception_to_result(tc, e); - (c, Some(err)) - } - None => (1, None), - }; - } - }; - if script.run(tc).is_none() { - return match tc.exception() { - Some(e) => { - let (c, err) = exception_to_result(tc, e); - (c, Some(err)) - } - None => (1, None), - }; - } - (0, None) -} - -/// Execute user code as a CJS script (mode='exec'). -/// -/// Runs bridge_code as IIFE first (if non-empty), then compiles and runs user_code -/// via v8::Script. Returns (exit_code, error) — exit code 0 on success, 1 on error. -/// The `bridge_cache` parameter enables code caching for repeated bridge compilations. -pub fn execute_script( - scope: &mut v8::HandleScope, - bridge_code: &str, - user_code: &str, - bridge_cache: &mut Option, -) -> (i32, Option) { - execute_script_with_options(scope, None, bridge_code, user_code, None, bridge_cache) -} - -pub fn execute_script_with_options( - scope: &mut v8::HandleScope, - bridge_ctx: Option<&BridgeCallContext>, - bridge_code: &str, - user_code: &str, - file_path: Option<&str>, - bridge_cache: &mut Option, -) -> (i32, Option) { - if let Some(bridge_ctx) = bridge_ctx { - MODULE_RESOLVE_STATE.with(|cell| { - *cell.borrow_mut() = Some(ModuleResolveState { - bridge_ctx: bridge_ctx as *const BridgeCallContext, - module_names: HashMap::new(), - module_cache: HashMap::new(), - guest_reader: None, - }); - }); - } - - // Run bridge code IIFE (with code caching) - if !bridge_code.is_empty() { - let (code, err) = run_bridge_cached(scope, bridge_code, bridge_cache); - if code != 0 { - if bridge_ctx.is_some() { - clear_module_state(); - } - return (code, err); - } - } - - // Run user code - { - let tc = &mut v8::TryCatch::new(scope); - let source = match v8::String::new(tc, user_code) { - Some(s) => s, - None => { - if bridge_ctx.is_some() { - clear_module_state(); - } - return ( - 1, - Some(ExecutionError { - error_type: "Error".into(), - message: "user code string too large for V8".into(), - stack: String::new(), - code: None, - }), - ); - } - }; - let origin = file_path.and_then(|path| { - let resource = v8::String::new(tc, path)?; - Some(v8::ScriptOrigin::new( - tc, - resource.into(), - 0, - 0, - false, - -1, - None, - false, - false, - false, - None, - )) - }); - let script = match v8::Script::compile(tc, source, origin.as_ref()) { - Some(s) => s, - None => { - if bridge_ctx.is_some() { - clear_module_state(); - } - return match tc.exception() { - Some(e) => { - let (c, err) = exception_to_result(tc, e); - (c, Some(err)) - } - None => (1, None), - }; - } - }; - let completion = match script.run(tc) { - Some(result) => result, - None => { - if bridge_ctx.is_some() { - clear_module_state(); - } - return match tc.exception() { - Some(e) => { - let (c, err) = exception_to_result(tc, e); - (c, Some(err)) - } - None => (1, None), - }; - } - }; - - // Flush microtasks once after every exec()-style script so process.nextTick() - // and zero-delay bridge callbacks run before we decide whether more event-loop - // work is pending. - tc.perform_microtask_checkpoint(); - - if let Some(exception) = tc.exception() { - if bridge_ctx.is_some() { - clear_module_state(); - } - let (c, err) = exception_to_result(tc, exception); - return (c, Some(err)); - } - - if let Some(err) = take_unhandled_promise_rejection(tc) { - if bridge_ctx.is_some() { - clear_module_state(); - } - return (1, Some(err)); - } - - // Surface rejected async completions for exec()-style scripts that - // return a Promise (for example an async IIFE ending in await import()). - if completion.is_promise() { - let promise = v8::Local::::try_from(completion).unwrap(); - match promise.state() { - v8::PromiseState::Pending => { - set_pending_script_evaluation(tc, promise); - return (0, None); - } - v8::PromiseState::Rejected => { - let rejection = promise.result(tc); - if bridge_ctx.is_some() { - clear_module_state(); - } - let (c, err) = exception_to_result(tc, rejection); - return (c, Some(err)); - } - v8::PromiseState::Fulfilled => { - return (extract_global_process_exit_code(tc).unwrap_or(0), None); - } - } - } - } - - (extract_global_process_exit_code(scope).unwrap_or(0), None) -} - -/// Check if a V8 exception is a ProcessExitError (has `_isProcessExit: true` sentinel). -/// Returns `Some(exit_code)` if detected, `None` otherwise. -/// -/// ProcessExitError is detected by sentinel property, not by regex matching on the -/// error message or constructor name. -pub fn extract_process_exit_code( - scope: &mut v8::HandleScope, - exception: v8::Local, -) -> Option { - if !exception.is_object() { - return None; - } - let obj = v8::Local::::try_from(exception).ok()?; - let sentinel_key = v8::String::new(scope, "_isProcessExit")?; - let sentinel_val = obj.get(scope, sentinel_key.into())?; - if !sentinel_val.is_true() { - return None; - } - // Extract numeric exit code from .code property - let code_key = v8::String::new(scope, "code")?; - let code_val = obj.get(scope, code_key.into())?; - if code_val.is_undefined() || code_val.is_null() { - Some(0) - } else if code_val.is_number() { - Some(code_val.int32_value(scope).unwrap_or(0)) - } else { - Some(1) - } -} - -fn extract_global_process_exit_code(scope: &mut v8::HandleScope) -> Option { - let context = scope.get_current_context(); - let global = context.global(scope); - let process_key = v8::String::new(scope, "process")?; - let process_val = global.get(scope, process_key.into())?; - if !process_val.is_object() { - return None; - } - - let process_obj = v8::Local::::try_from(process_val).ok()?; - let exit_code_key = v8::String::new(scope, "exitCode")?; - let exit_code_val = process_obj.get(scope, exit_code_key.into())?; - if exit_code_val.is_undefined() || exit_code_val.is_null() { - None - } else if exit_code_val.is_number() { - Some(exit_code_val.int32_value(scope).unwrap_or(0)) - } else { - None - } -} - -/// Extract error info and exit code from a V8 exception. -/// For ProcessExitError (detected via _isProcessExit sentinel), returns the error's exit code. -/// For other errors, returns exit code 1. -pub(crate) fn exception_to_result( - scope: &mut v8::HandleScope, - exception: v8::Local, -) -> (i32, ExecutionError) { - let error = extract_error_info(scope, exception); - let exit_code = extract_process_exit_code(scope, exception) - .or_else(|| parse_process_exit_code_from_error(&error)) - .unwrap_or(1); - (exit_code, error) -} - -fn parse_process_exit_code_from_error(error: &ExecutionError) -> Option { - if error.error_type != "ProcessExitError" && !error.message.starts_with("process.exit(") { - return None; - } - let code = error - .message - .strip_prefix("process.exit(")? - .strip_suffix(')')?; - code.parse::().ok() -} - -/// Extract structured error information from a V8 exception value. -/// -/// Reads constructor.name for error type, .message for the message, -/// .stack for the stack trace, and optional .code for Node-style error codes. -pub(crate) fn extract_error_info( - scope: &mut v8::HandleScope, - exception: v8::Local, -) -> ExecutionError { - if !exception.is_object() { - // Non-object throw (e.g., `throw "string"`) - return ExecutionError { - error_type: "Error".into(), - message: exception.to_rust_string_lossy(scope), - stack: String::new(), - code: None, - }; - } - - let obj = v8::Local::::try_from(exception).unwrap(); - - // Error type from constructor.name - let error_type = { - let ctor_key = v8::String::new(scope, "constructor").unwrap(); - let name_key = v8::String::new(scope, "name").unwrap(); - obj.get(scope, ctor_key.into()) - .filter(|v| v.is_object()) - .and_then(|ctor| { - let ctor_obj = v8::Local::::try_from(ctor).ok()?; - ctor_obj.get(scope, name_key.into()) - }) - .filter(|v| v.is_string()) - .map(|v| v.to_rust_string_lossy(scope)) - .filter(|n| !n.is_empty()) - .unwrap_or_else(|| "Error".into()) - }; - - // Message from error.message property - let message = { - let msg_key = v8::String::new(scope, "message").unwrap(); - obj.get(scope, msg_key.into()) - .filter(|v| v.is_string()) - .map(|v| v.to_rust_string_lossy(scope)) - .unwrap_or_else(|| exception.to_rust_string_lossy(scope)) - }; - - // Stack trace from error.stack property - let stack = { - let stack_key = v8::String::new(scope, "stack").unwrap(); - obj.get(scope, stack_key.into()) - .filter(|v| v.is_string()) - .map(|v| v.to_rust_string_lossy(scope)) - .unwrap_or_default() - }; - - // Optional error code (e.g., ERR_MODULE_NOT_FOUND) - let code = { - let code_key = v8::String::new(scope, "code").unwrap(); - obj.get(scope, code_key.into()) - .filter(|v| v.is_string()) - .map(|v| v.to_rust_string_lossy(scope)) - }; - - ExecutionError { - error_type, - message, - stack, - code, - } -} - -/// Build the _processConfig JS object: { cwd, env, timing_mitigation, frozen_time_ms, high_resolution_time } -#[cfg(test)] -fn build_process_config<'s>( - scope: &mut v8::HandleScope<'s>, - config: &ProcessConfig, -) -> v8::Local<'s, v8::Object> { - let obj = v8::Object::new(scope); - - // cwd - let key = v8::String::new(scope, "cwd").unwrap(); - let val = v8::String::new(scope, &config.cwd).unwrap(); - obj.set(scope, key.into(), val.into()); - - // env (frozen sub-object) - let env_key = v8::String::new(scope, "env").unwrap(); - let env_obj = v8::Object::new(scope); - for (k, v) in &config.env { - let ek = v8::String::new(scope, k).unwrap(); - let ev = v8::String::new(scope, v).unwrap(); - env_obj.set(scope, ek.into(), ev.into()); - } - env_obj.set_integrity_level(scope, v8::IntegrityLevel::Frozen); - obj.set(scope, env_key.into(), env_obj.into()); - - // timing_mitigation - let key = v8::String::new(scope, "timing_mitigation").unwrap(); - let val = v8::String::new(scope, &config.timing_mitigation).unwrap(); - obj.set(scope, key.into(), val.into()); - - // frozen_time_ms (number or null) - let key = v8::String::new(scope, "frozen_time_ms").unwrap(); - let val: v8::Local = match config.frozen_time_ms { - Some(ms) => v8::Number::new(scope, ms).into(), - None => v8::null(scope).into(), - }; - obj.set(scope, key.into(), val); - - // high_resolution_time - let key = v8::String::new(scope, "high_resolution_time").unwrap(); - let val = v8::Boolean::new(scope, config.high_resolution_time); - obj.set(scope, key.into(), val.into()); - - obj -} - -/// Build the _osConfig JS object: { homedir, tmpdir, platform, arch } -#[cfg(test)] -fn build_os_config<'s>( - scope: &mut v8::HandleScope<'s>, - config: &OsConfig, -) -> v8::Local<'s, v8::Object> { - let obj = v8::Object::new(scope); - - for (name, value) in [ - ("homedir", config.homedir.as_str()), - ("tmpdir", config.tmpdir.as_str()), - ("platform", config.platform.as_str()), - ("arch", config.arch.as_str()), - ] { - let key = v8::String::new(scope, name).unwrap(); - let val = v8::String::new(scope, value).unwrap(); - obj.set(scope, key.into(), val.into()); - } - - obj -} - -// --- ESM module loading --- - -/// Thread-local state for module resolution during execute_module. -/// Avoids passing user data through V8's ResolveModuleCallback (which is a plain fn pointer). -/// Direct, in-process module source reader living on the V8 session thread. -/// -/// The V8 module callback (resolve_or_compile_module) runs in this crate -/// (v8-runtime), but the module reader/resolver lives in the higher `execution` -/// crate, so a direct call would be a circular dependency — today every module -/// resolve/load/format is a sync bridge round-trip (~139us × ~5,100 calls ≈ all -/// of loadPiSdkRuntime). This trait is owned here and implemented in the higher -/// crate over the mounted `HostDirModuleReader`, then handed down to the session -/// thread so module source can be read directly, skipping the round-trip. It is -/// confined to the same mounts the guest sees (the impl keeps the reader's -/// `openat2(RESOLVE_BENEATH)` confinement). -pub trait GuestModuleReader: Send { - /// Read the source for an already-resolved guest module path, or `None` if - /// the path isn't served by this reader (caller falls back to the bridge IPC). - fn read_module_source(&mut self, resolved_guest_path: &str) -> Option; - - /// Resolve a module specifier (import mode) to a resolved guest path directly, - /// skipping the bridge `_resolveModule` round-trip. `None` => fall back to IPC. - /// Implementations must match the bridge resolver exactly (same cache, same - /// ESM/CJS/exports/symlink semantics). - fn resolve_module(&mut self, specifier: &str, referrer: &str) -> Option { - let _ = (specifier, referrer); - None - } -} - -/// Install (or clear) the direct module reader for the current session thread. -/// Called by the session thread when it receives a `SetModuleReader` command; the -/// next `execute_module` moves it into the resolve state. Must be called on the -/// session/isolate thread. -pub fn install_session_guest_reader(reader: Option>) { - SESSION_GUEST_READER.with(|cell| *cell.borrow_mut() = reader); -} - -struct ModuleResolveState { - bridge_ctx: *const BridgeCallContext, - /// identity_hash → resource_name for referrer lookup - module_names: HashMap, - /// resolved_path and referrer-qualified request keys → Global cache - module_cache: HashMap>, - /// Optional direct module-source reader (session-thread local). When present, - /// module loads read source directly instead of via the bridge round-trip. - guest_reader: Option>, -} - -// SAFETY: ModuleResolveState is only accessed from the session thread -// (single-threaded per session). The raw pointer is valid for the -// duration of execute_module. -unsafe impl Send for ModuleResolveState {} - -/// Deferred root-module completion state for async ESM evaluation. -/// -/// When `module.evaluate()` returns a pending promise (for example because the -/// entry module or one of its dependencies uses top-level `await`), the session -/// thread keeps the module + promise alive across the bridge event loop and -/// finalizes exports only after the promise settles. -#[cfg_attr(test, allow(dead_code))] -struct PendingModuleEvaluation { - module: v8::Global, - promise: v8::Global, -} - -// SAFETY: PendingModuleEvaluation is only accessed from the session thread -// (single-threaded per session). -unsafe impl Send for PendingModuleEvaluation {} - -struct PendingScriptEvaluation { - promise: v8::Global, -} - -unsafe impl Send for PendingScriptEvaluation {} - -thread_local! { - static MODULE_RESOLVE_STATE: RefCell> = const { RefCell::new(None) }; - /// Session-thread-local handoff: a SetModuleReader command stashes the reader - /// here, and the next execute_module moves it into ModuleResolveState so module - /// source loads read directly on this thread instead of round-tripping the bridge. - static SESSION_GUEST_READER: RefCell>> = const { RefCell::new(None) }; - static PENDING_MODULE_EVALUATION: RefCell> = const { RefCell::new(None) }; - static PENDING_SCRIPT_EVALUATION: RefCell> = const { RefCell::new(None) }; - static CJS_RUNTIME_EXTRACTION_IN_PROGRESS: RefCell> = - RefCell::new(HashSet::new()); -} - -const MAX_MODULE_RESOLVE_MODULES: usize = 1024; -const MAX_MODULE_RESOLVE_CACHE_ENTRIES: usize = 4096; -const MAX_MODULE_PREFETCH_GRAPH_MODULES: usize = 1024; -const MAX_MODULE_PREFETCH_BATCH_SIZE: usize = 256; -const MAX_MODULE_BATCH_RESOLVE_RESPONSE_BYTES: usize = 16 * 1024 * 1024; -const MAX_CJS_NAMED_EXPORTS: usize = 1024; -const MAX_CJS_RUNTIME_EXPORT_NAME_LEN: usize = 512; - -fn module_request_cache_key(specifier: &str, referrer_name: &str) -> String { - format!("{}\0{}", referrer_name, specifier) -} - -#[cfg_attr(test, allow(dead_code))] -pub fn clear_module_state() { - MODULE_RESOLVE_STATE.with(|cell| { - *cell.borrow_mut() = None; - }); -} - -pub fn clear_pending_module_evaluation() { - PENDING_MODULE_EVALUATION.with(|cell| { - *cell.borrow_mut() = None; - }); -} - -pub fn clear_pending_script_evaluation() { - PENDING_SCRIPT_EVALUATION.with(|cell| { - *cell.borrow_mut() = None; - }); -} - -#[cfg_attr(test, allow(dead_code))] -pub fn has_pending_module_evaluation() -> bool { - PENDING_MODULE_EVALUATION.with(|cell| cell.borrow().is_some()) -} - -pub fn has_pending_script_evaluation() -> bool { - PENDING_SCRIPT_EVALUATION.with(|cell| cell.borrow().is_some()) -} - -pub fn pending_module_evaluation_needs_wait(scope: &mut v8::HandleScope) -> bool { - PENDING_MODULE_EVALUATION.with(|cell| { - let borrow = cell.borrow(); - let Some(pending) = borrow.as_ref() else { - return false; - }; - let promise = v8::Local::new(scope, &pending.promise); - promise.state() == v8::PromiseState::Pending - }) -} - -pub fn pending_script_evaluation_needs_wait(scope: &mut v8::HandleScope) -> bool { - PENDING_SCRIPT_EVALUATION.with(|cell| { - let borrow = cell.borrow(); - let Some(pending) = borrow.as_ref() else { - return false; - }; - let promise = v8::Local::new(scope, &pending.promise); - promise.state() == v8::PromiseState::Pending - }) -} - -fn set_pending_module_evaluation( - scope: &mut v8::HandleScope, - module: v8::Local, - promise: v8::Local, -) { - PENDING_MODULE_EVALUATION.with(|cell| { - *cell.borrow_mut() = Some(PendingModuleEvaluation { - module: v8::Global::new(scope, module), - promise: v8::Global::new(scope, promise), - }); - }); -} - -pub fn set_pending_script_evaluation(scope: &mut v8::HandleScope, promise: v8::Local) { - PENDING_SCRIPT_EVALUATION.with(|cell| { - *cell.borrow_mut() = Some(PendingScriptEvaluation { - promise: v8::Global::new(scope, promise), - }); - }); -} - -pub(crate) fn take_unhandled_promise_rejection( - scope: &mut v8::HandleScope, -) -> Option { - scope - .get_slot_mut::() - .and_then(|state| state.take_next_unhandled()) -} - -pub fn finalize_pending_script_evaluation( - scope: &mut v8::HandleScope, -) -> Option<(i32, Option)> { - let pending = PENDING_SCRIPT_EVALUATION.with(|cell| cell.borrow_mut().take())?; - let tc = &mut v8::TryCatch::new(scope); - let promise = v8::Local::new(tc, &pending.promise); - - tc.perform_microtask_checkpoint(); - - if let Some(exception) = tc.exception() { - let (code, err) = exception_to_result(tc, exception); - return Some((code, Some(err))); - } - - if let Some(err) = take_unhandled_promise_rejection(tc) { - return Some((1, Some(err))); - } - - match promise.state() { - v8::PromiseState::Pending => { - PENDING_SCRIPT_EVALUATION.with(|cell| { - *cell.borrow_mut() = Some(pending); - }); - None - } - v8::PromiseState::Rejected => { - let rejection = promise.result(tc); - let (code, err) = exception_to_result(tc, rejection); - Some((code, Some(err))) - } - v8::PromiseState::Fulfilled => { - Some((extract_global_process_exit_code(tc).unwrap_or(0), None)) - } - } -} - -fn serialize_module_exports( - scope: &mut v8::HandleScope, - module: v8::Local, -) -> Result, ExecutionError> { - // Serialize module namespace (exports) - // If the ESM namespace is empty, fall back to globalThis.module.exports - // for CJS compatibility (code using module.exports = {...}). - // The module namespace is a V8 exotic object that ValueSerializer can't - // handle directly, so we copy its properties into a plain object. - let namespace = module.get_module_namespace(); - let namespace_obj = namespace.to_object(scope).unwrap(); - let prop_names = namespace_obj - .get_own_property_names(scope, v8::GetPropertyNamesArgs::default()) - .unwrap(); - let exports_val: v8::Local = if prop_names.length() == 0 { - // No ESM exports — check CJS module.exports fallback - let ctx = scope.get_current_context(); - let global = ctx.global(scope); - let module_key = v8::String::new(scope, "module").unwrap(); - let cjs_exports = global - .get(scope, module_key.into()) - .and_then(|m| m.to_object(scope)) - .and_then(|m| { - let exports_key = v8::String::new(scope, "exports").unwrap(); - m.get(scope, exports_key.into()) - }) - .filter(|v| !v.is_undefined() && !v.is_null_or_undefined()); - match cjs_exports { - Some(val) => val, - None => v8::Object::new(scope).into(), - } - } else { - let plain = v8::Object::new(scope); - for i in 0..prop_names.length() { - let key = prop_names.get_index(scope, i).unwrap(); - let val = namespace_obj - .get(scope, key) - .unwrap_or_else(|| v8::undefined(scope).into()); - plain.set(scope, key, val); - } - plain.into() - }; - - serialize_v8_value(scope, exports_val).map_err(|err| ExecutionError { - error_type: "Error".into(), - message: format!("failed to serialize exports: {}", err), - stack: String::new(), - code: None, - }) -} - -#[cfg_attr(test, allow(dead_code))] -pub fn finalize_pending_module_evaluation( - scope: &mut v8::HandleScope, -) -> Option<(i32, Option>, Option)> { - let pending = PENDING_MODULE_EVALUATION.with(|cell| cell.borrow_mut().take())?; - let tc = &mut v8::TryCatch::new(scope); - let module = v8::Local::new(tc, &pending.module); - let promise = v8::Local::new(tc, &pending.promise); - - tc.perform_microtask_checkpoint(); - - if let Some(exception) = tc.exception() { - let (code, err) = exception_to_result(tc, exception); - return Some((code, None, Some(err))); - } - - if let Some(err) = take_unhandled_promise_rejection(tc) { - return Some((1, None, Some(err))); - } - - match promise.state() { - v8::PromiseState::Pending => { - PENDING_MODULE_EVALUATION.with(|cell| { - *cell.borrow_mut() = Some(pending); - }); - None - } - v8::PromiseState::Rejected => { - let rejection = promise.result(tc); - let (code, err) = exception_to_result(tc, rejection); - Some((code, None, Some(err))) - } - v8::PromiseState::Fulfilled => { - if module.get_status() == v8::ModuleStatus::Errored { - let exc = module.get_exception(); - let (code, err) = exception_to_result(tc, exc); - return Some((code, None, Some(err))); - } - - match serialize_module_exports(tc, module) { - Ok(exports) => Some((0, Some(exports), None)), - Err(err) => Some((1, None, Some(err))), - } - } - } -} - -/// Execute user code as an ES module (mode='run'). -/// -/// Runs bridge_code as CJS IIFE first (if non-empty), then compiles and runs -/// user_code as a v8::Module. The ResolveModuleCallback sends sync-blocking IPC -/// calls via BridgeCallContext to resolve import specifiers and load sources. -/// Returns (exit_code, serialized_exports, error). -/// The `bridge_cache` parameter enables code caching for repeated bridge compilations. -pub fn execute_module( - scope: &mut v8::HandleScope, - bridge_ctx: &BridgeCallContext, - bridge_code: &str, - user_code: &str, - file_path: Option<&str>, - bridge_cache: &mut Option, -) -> (i32, Option>, Option) { - clear_pending_module_evaluation(); - - // Set up thread-local resolve state, taking any reader the session thread - // stashed via a SetModuleReader command so module loads read source directly. - let guest_reader = SESSION_GUEST_READER.with(|cell| cell.borrow_mut().take()); - MODULE_RESOLVE_STATE.with(|cell| { - *cell.borrow_mut() = Some(ModuleResolveState { - bridge_ctx: bridge_ctx as *const BridgeCallContext, - module_names: HashMap::new(), - module_cache: HashMap::new(), - guest_reader, - }); - }); - - // Run bridge code IIFE (same as CJS mode, with code caching) - if !bridge_code.is_empty() { - let (code, err) = run_bridge_cached(scope, bridge_code, bridge_cache); - if code != 0 { - clear_module_state(); - return (code, None, err); - } - } - - // Compile and evaluate as ES module - { - let tc = &mut v8::TryCatch::new(scope); - let resource_name_str = file_path.unwrap_or(""); - let resource = v8::String::new(tc, resource_name_str).unwrap(); - let origin = v8::ScriptOrigin::new( - tc, - resource.into(), - 0, - 0, - false, - -1, - None, - false, - false, - true, // is_module - None, - ); - - let effective_user_code = add_esm_runtime_prelude(user_code); - let v8_source = match v8::String::new(tc, &effective_user_code) { - Some(s) => s, - None => { - clear_module_state(); - return ( - 1, - None, - Some(ExecutionError { - error_type: "Error".into(), - message: "user code string too large for V8".into(), - stack: String::new(), - code: None, - }), - ); - } - }; - - let mut source = v8::script_compiler::Source::new(v8_source, Some(&origin)); - let module = match v8::script_compiler::compile_module(tc, &mut source) { - Some(m) => m, - None => { - clear_module_state(); - return match tc.exception() { - Some(e) => { - let (c, err) = exception_to_result(tc, e); - (c, None, Some(err)) - } - None => (1, None, None), - }; - } - }; - - // Store root module name for referrer lookup in resolve callback - MODULE_RESOLVE_STATE.with(|cell| { - if let Some(state) = cell.borrow_mut().as_mut() { - state - .module_names - .insert(module.get_identity_hash(), resource_name_str.to_string()); - } - }); - - // Batch-prefetch static imports (BFS) to reduce IPC round-trips. - // Each level collects uncached specifiers and resolves+loads them in one batch call. - // The resolve callback then finds everything pre-cached during instantiation. - prefetch_module_imports(tc, bridge_ctx, module, resource_name_str); - - // Instantiate (calls resolve callback for each import — mostly cache hits now) - let inst_result = module.instantiate_module(tc, module_resolve_callback); - if inst_result.is_none() { - clear_module_state(); - return match tc.exception() { - Some(e) => { - let (c, err) = exception_to_result(tc, e); - (c, None, Some(err)) - } - None => (1, None, None), - }; - } - - // Evaluate - let eval_result = module.evaluate(tc); - if eval_result.is_none() { - clear_module_state(); - return match tc.exception() { - Some(e) => { - let (c, err) = exception_to_result(tc, e); - (c, None, Some(err)) - } - None => (1, None, None), - }; - } - - // Always flush microtasks after module evaluation so that async - // operations started during evaluation (e.g. process.stdin listeners, - // timers) can create their pending bridge promises. Without this, - // modules without top-level await exit immediately because the session - // event loop sees no pending work. - if eval_result.unwrap().is_promise() { - let promise = v8::Local::::try_from(eval_result.unwrap()).unwrap(); - tc.perform_microtask_checkpoint(); - - if let Some(exception) = tc.exception() { - clear_module_state(); - let (c, err) = exception_to_result(tc, exception); - return (c, None, Some(err)); - } - - if let Some(err) = take_unhandled_promise_rejection(tc) { - clear_module_state(); - return (1, None, Some(err)); - } - - match promise.state() { - v8::PromiseState::Pending => { - set_pending_module_evaluation(tc, module, promise); - return (0, None, None); - } - v8::PromiseState::Rejected => { - let rejection = promise.result(tc); - clear_module_state(); - let (exit_code, err) = exception_to_result(tc, rejection); - return (exit_code, None, Some(err)); - } - v8::PromiseState::Fulfilled => {} - } - } else { - // Non-TLA module: still flush microtasks so bridge-initiated - // async work (stdin reads, handle registration) becomes visible - // to the session event loop. - tc.perform_microtask_checkpoint(); - - if let Some(exception) = tc.exception() { - clear_module_state(); - let (c, err) = exception_to_result(tc, exception); - return (c, None, Some(err)); - } - - if let Some(err) = take_unhandled_promise_rejection(tc) { - clear_module_state(); - return (1, None, Some(err)); - } - } - - // Check module status for errors (handles TLA rejection case) - if module.get_status() == v8::ModuleStatus::Errored { - let exc = module.get_exception(); - clear_module_state(); - let (exit_code, err) = exception_to_result(tc, exc); - return (exit_code, None, Some(err)); - } - - let exports_bytes = match serialize_module_exports(tc, module) { - Ok(bytes) => bytes, - Err(err) => { - clear_module_state(); - return (1, None, Some(err)); - } - }; - - // Keep module resolve state available after the initial module finishes. - // Dynamic imports can still fire later on the same session event loop. - (0, Some(exports_bytes), None) - } -} - -/// Extract static import specifiers from a compiled module. -/// -/// Returns a list of (specifier, referrer_name) pairs for all imports -/// that are not already in the module cache. -fn extract_uncached_imports( - scope: &mut v8::HandleScope, - module: v8::Local, - referrer_name: &str, -) -> Vec<(String, String)> { - let requests = module.get_module_requests(); - let mut uncached = Vec::new(); - for i in 0..requests.length() { - if uncached.len() >= MAX_MODULE_PREFETCH_BATCH_SIZE { - break; - } - let data = requests.get(scope, i).unwrap(); - let request: v8::Local = data.cast(); - let specifier = request.get_specifier().to_rust_string_lossy(scope); - let cache_key = module_request_cache_key(&specifier, referrer_name); - - // Skip if already cached for this referrer-qualified request. - let already_cached = MODULE_RESOLVE_STATE.with(|cell| { - let borrow = cell.borrow(); - let state = borrow.as_ref().unwrap(); - state.module_cache.contains_key(&cache_key) - }); - if !already_cached { - uncached.push((specifier, referrer_name.to_string())); - } - } - uncached -} - -/// Batch-prefetch module imports via a single IPC round-trip. -/// -/// Sends _batchResolveModules with all uncached specifiers, receives resolved -/// paths + source code, compiles and caches each module, then recurses (BFS) -/// for any newly discovered imports. Falls back silently if the host doesn't -/// support batch resolution (the resolve callback handles individual resolution). -fn prefetch_module_imports( - scope: &mut v8::HandleScope, - bridge_ctx: &BridgeCallContext, - root_module: v8::Local, - root_name: &str, -) { - // BFS queue: modules whose imports we need to prefetch - let mut pending: Vec<(v8::Global, String)> = - vec![(v8::Global::new(scope, root_module), root_name.to_string())]; - let mut visited_modules = 0usize; - - while !pending.is_empty() && visited_modules < MAX_MODULE_PREFETCH_GRAPH_MODULES { - let remaining_modules = MAX_MODULE_PREFETCH_GRAPH_MODULES - visited_modules; - let current_len = pending.len().min(remaining_modules); - let current: Vec<_> = pending.drain(..current_len).collect(); - visited_modules += current.len(); - - // Collect all uncached imports from pending modules - let mut batch: Vec<(String, String)> = Vec::new(); - for (global_mod, referrer) in ¤t { - let local_mod = v8::Local::new(scope, global_mod); - let imports = extract_uncached_imports(scope, local_mod, referrer); - for (spec, ref_name) in imports { - if batch.len() >= MAX_MODULE_PREFETCH_BATCH_SIZE { - break; - } - // Deduplicate within this batch by the full request identity. - if !batch.iter().any(|(s, r)| s == &spec && r == &ref_name) { - batch.push((spec, ref_name)); - } - } - if batch.len() >= MAX_MODULE_PREFETCH_BATCH_SIZE { - break; - } - } - - if batch.is_empty() { - break; - } - - // Send batch resolve+load via IPC - let results = match batch_resolve_via_ipc(scope, bridge_ctx, &batch) { - Some(r) => r, - None => break, // Host doesn't support batch or IPC error — fall back to individual - }; - - // Compile and cache each result, collect newly compiled modules for next BFS level - let mut next_pending: Vec<(v8::Global, String)> = Vec::new(); - for (i, result) in results.iter().enumerate() { - if i >= batch.len() { - break; - } - if let Some((resolved_path, source_code)) = result { - // Check cache again (another entry in this batch may have resolved the same path) - let already_cached = MODULE_RESOLVE_STATE.with(|cell| { - let borrow = cell.borrow(); - let state = borrow.as_ref().unwrap(); - state.module_cache.contains_key(resolved_path) - }); - if already_cached { - continue; - } - - let module_format = lookup_module_format_via_ipc(scope, bridge_ctx, resolved_path); - let effective_source = - build_module_source(scope, source_code, resolved_path, module_format); - - // Compile the module - let resource = match v8::String::new(scope, resolved_path) { - Some(s) => s, - None => continue, - }; - let origin = v8::ScriptOrigin::new( - scope, - resource.into(), - 0, - 0, - false, - -1, - None, - false, - false, - true, // is_module - None, - ); - let v8_source = match v8::String::new(scope, &effective_source) { - Some(s) => s, - None => continue, - }; - let mut compiled = v8::script_compiler::Source::new(v8_source, Some(&origin)); - let module = match v8::script_compiler::compile_module(scope, &mut compiled) { - Some(m) => m, - None => continue, - }; - - // Cache the module - let global = v8::Global::new(scope, module); - if !cache_resolved_module( - module, - global, - resolved_path.clone(), - Some(module_request_cache_key(&batch[i].0, &batch[i].1)), - ) { - return; - } - - if visited_modules + next_pending.len() < MAX_MODULE_PREFETCH_GRAPH_MODULES { - next_pending.push((v8::Global::new(scope, module), resolved_path.clone())); - } - } - } - - pending = next_pending; - } -} - -fn resolve_or_compile_module<'s>( - scope: &mut v8::HandleScope<'s>, - specifier_str: &str, - referrer_name: &str, -) -> Option> { - let request_cache_key = module_request_cache_key(specifier_str, referrer_name); - - // Phase 1: Check cache by referrer-qualified request. - let cached_global = MODULE_RESOLVE_STATE.with(|cell| { - let borrow = cell.borrow(); - let state = borrow.as_ref()?; - state.module_cache.get(&request_cache_key).cloned() - }); - if let Some(cached) = cached_global { - return Some(v8::Local::new(scope, &cached)); - } - - // Phase 2: Get bridge context. - let bridge_ctx_ptr = MODULE_RESOLVE_STATE.with(|cell| { - let borrow = cell.borrow(); - borrow.as_ref().map(|state| state.bridge_ctx) - }); - let bridge_ctx_ptr = bridge_ctx_ptr?; - let ctx = unsafe { &*bridge_ctx_ptr }; - - // Phase 3: Resolve module path — directly on this thread via the session - // reader when present (skips the bridge `_resolveModule` round-trip), else IPC. - let trace = mod_trace_enabled(); - let t = trace.then(Instant::now); - let direct_resolved = MODULE_RESOLVE_STATE.with(|cell| { - cell.borrow_mut() - .as_mut() - .and_then(|state| state.guest_reader.as_mut()) - .and_then(|reader| reader.resolve_module(specifier_str, referrer_name)) - }); - let resolved_path = match direct_resolved { - Some(path) => path, - None => resolve_module_via_ipc(scope, ctx, specifier_str, referrer_name)?, - }; - if let Some(t) = t { - record_mod(1, t.elapsed().as_nanos() as u64); - } - - // Phase 4: Check cache by resolved path. - let cached_global = MODULE_RESOLVE_STATE.with(|cell| { - let borrow = cell.borrow(); - let state = borrow.as_ref()?; - state.module_cache.get(&resolved_path).cloned() - }); - if let Some(cached) = cached_global { - return Some(v8::Local::new(scope, &cached)); - } - - // Phase 5: Load the module source — directly via the session-thread reader - // when present (skips the ~139us bridge round-trip), else via the bridge IPC. - // guest_reader is None until the higher crate plumbs the reader down, so this - // is currently a no-op fall-through to the IPC path (zero behavior change). - let t = trace.then(Instant::now); - let direct_source = MODULE_RESOLVE_STATE.with(|cell| { - cell.borrow_mut() - .as_mut() - .and_then(|state| state.guest_reader.as_mut()) - .and_then(|reader| reader.read_module_source(&resolved_path)) - }); - let raw_source = match direct_source { - Some(source) => source, - None => load_module_via_ipc(scope, ctx, &resolved_path)?, - }; - if let Some(t) = t { - record_mod(2, t.elapsed().as_nanos() as u64); - } - let t = trace.then(Instant::now); - let module_format = lookup_module_format_via_ipc(scope, ctx, &resolved_path); - if let Some(t) = t { - record_mod(3, t.elapsed().as_nanos() as u64); - } - let source_code = build_module_source(scope, &raw_source, &resolved_path, module_format); - - let resource = v8::String::new(scope, &resolved_path)?; - let origin = v8::ScriptOrigin::new( - scope, - resource.into(), - 0, - 0, - false, - -1, - None, - false, - false, - true, - None, - ); - let v8_source = match v8::String::new(scope, &source_code) { - Some(s) => s, - None => { - throw_module_error(scope, "module source too large for V8"); - return None; - } - }; - let mut compiled = v8::script_compiler::Source::new(v8_source, Some(&origin)); - let t = trace.then(Instant::now); - let module = v8::script_compiler::compile_module(scope, &mut compiled)?; - if let Some(t) = t { - record_mod(4, t.elapsed().as_nanos() as u64); - } - let global = v8::Global::new(scope, module); - if !cache_resolved_module(module, global, resolved_path, Some(request_cache_key)) { - throw_module_error(scope, "module resolution cache limit exceeded"); - return None; - } - - Some(module) -} - -fn cache_resolved_module( - module: v8::Local, - global: v8::Global, - resolved_path: String, - request_cache_key: Option, -) -> bool { - MODULE_RESOLVE_STATE.with(|cell| { - let mut borrow = cell.borrow_mut(); - let Some(state) = borrow.as_mut() else { - return true; - }; - - let identity_hash = module.get_identity_hash(); - let new_module_name = !state.module_names.contains_key(&identity_hash); - let new_resolved_path = !state.module_cache.contains_key(&resolved_path); - let new_request_key = request_cache_key - .as_ref() - .is_some_and(|key| !state.module_cache.contains_key(key)); - - let next_module_count = state.module_names.len() + usize::from(new_module_name); - let next_cache_count = state.module_cache.len() - + usize::from(new_resolved_path) - + usize::from(new_request_key); - if next_module_count > MAX_MODULE_RESOLVE_MODULES - || next_cache_count > MAX_MODULE_RESOLVE_CACHE_ENTRIES - { - return false; - } - - state - .module_names - .insert(identity_hash, resolved_path.clone()); - state - .module_cache - .insert(resolved_path.clone(), global.clone()); - if let Some(request_cache_key) = request_cache_key { - state.module_cache.insert(request_cache_key, global); - } - true - }) -} - -/// Callback invoked by V8 when `import.meta` is accessed in an ES module. -/// Sets `import.meta.url` to a `file://` URL derived from the module's resource name. -#[cfg_attr(test, allow(dead_code))] -pub extern "C" fn import_meta_object_callback( - context: v8::Local, - module: v8::Local, - meta: v8::Local, -) { - let scope = &mut unsafe { v8::CallbackScope::new(context) }; - - // Look up the module's resource name from MODULE_RESOLVE_STATE.module_names - // which maps identity_hash → resource_name. - let identity_hash = module.get_identity_hash(); - let url_str = MODULE_RESOLVE_STATE.with(|cell| { - let state_opt = cell.borrow(); - if let Some(ref state) = *state_opt { - if let Some(name) = state.module_names.get(&identity_hash) { - let n = name.clone(); - if n.starts_with("file://") { - return Some(n); - } else if n.starts_with("/") { - return Some(format!("file://{}", n)); - } else { - return Some(n); - } - } - } - None - }); - - if let Some(url) = url_str { - let key = v8::String::new(scope, "url").unwrap(); - let value = v8::String::new(scope, &url).unwrap(); - meta.set(scope, key.into(), value.into()); - } -} - -#[cfg_attr(test, allow(dead_code))] -fn dynamic_import_namespace_callback( - _scope: &mut v8::HandleScope, - args: v8::FunctionCallbackArguments, - mut rv: v8::ReturnValue, -) { - rv.set(args.data()); -} - -#[cfg_attr(test, allow(dead_code))] -fn dynamic_import_reject_callback( - scope: &mut v8::HandleScope, - args: v8::FunctionCallbackArguments, - mut rv: v8::ReturnValue, -) { - let reason = args.get(0); - scope.throw_exception(reason); - rv.set(reason); -} - -#[cfg_attr(test, allow(dead_code))] -pub fn dynamic_import_callback<'a>( - scope: &mut v8::HandleScope<'a>, - _host_defined_options: v8::Local<'a, v8::Data>, - resource_name: v8::Local<'a, v8::Value>, - specifier: v8::Local<'a, v8::String>, - _import_attributes: v8::Local<'a, v8::FixedArray>, -) -> Option> { - let tc = &mut v8::TryCatch::new(scope); - - let specifier_str = specifier.to_rust_string_lossy(tc); - let referrer_name = resolve_dynamic_import_referrer_name(tc, resource_name); - let module = match resolve_or_compile_module(tc, &specifier_str, &referrer_name) { - Some(module) => module, - None => { - let reason = if let Some(exception) = tc.exception() { - exception - } else { - let msg = v8::String::new(tc, "Cannot dynamically import module").unwrap(); - v8::Exception::error(tc, msg) - }; - return rejected_promise(tc, reason); - } - }; - - if module.get_status() == v8::ModuleStatus::Uninstantiated - && module - .instantiate_module(tc, module_resolve_callback) - .is_none() - { - let reason = if let Some(exception) = tc.exception() { - exception - } else { - let msg = - v8::String::new(tc, "Cannot instantiate dynamically imported module").unwrap(); - v8::Exception::error(tc, msg) - }; - return rejected_promise(tc, reason); - } - - if module.get_status() == v8::ModuleStatus::Errored { - let exception = v8::Global::new(tc, module.get_exception()); - let exception = v8::Local::new(tc, &exception); - return rejected_promise(tc, exception); - } - - if module.get_status() == v8::ModuleStatus::Evaluated { - let namespace = v8::Global::new(tc, module.get_module_namespace()); - let namespace = v8::Local::new(tc, &namespace); - return resolved_promise(tc, namespace); - } - - let eval_result = match module.evaluate(tc) { - Some(result) => result, - None => { - let reason = if let Some(exception) = tc.exception() { - exception - } else { - let msg = - v8::String::new(tc, "Cannot evaluate dynamically imported module").unwrap(); - v8::Exception::error(tc, msg) - }; - return rejected_promise(tc, reason); - } - }; - - let namespace = v8::Global::new(tc, module.get_module_namespace()); - let namespace = v8::Local::new(tc, &namespace); - if eval_result.is_promise() { - let eval_promise = v8::Local::::try_from(eval_result).ok()?; - let on_fulfilled = v8::FunctionTemplate::builder(dynamic_import_namespace_callback) - .data(namespace) - .build(tc) - .get_function(tc)?; - let on_rejected = v8::FunctionTemplate::builder(dynamic_import_reject_callback) - .build(tc) - .get_function(tc)?; - return eval_promise.then2(tc, on_fulfilled, on_rejected); - } - - resolved_promise(tc, namespace) -} - -fn resolve_dynamic_import_referrer_name( - scope: &mut v8::HandleScope, - resource_name: v8::Local, -) -> String { - let candidate = resource_name.to_rust_string_lossy(scope); - if candidate.starts_with('/') || candidate.starts_with("file://") { - return candidate; - } - - let context = scope.get_current_context(); - let global = context.global(scope); - let key = match v8::String::new(scope, "_currentModule") { - Some(key) => key, - None => return candidate, - }; - let current_module = match global.get(scope, key.into()) { - Some(value) if value.is_object() => value, - _ => return candidate, - }; - let current_module = match v8::Local::::try_from(current_module) { - Ok(object) => object, - Err(_) => return candidate, - }; - let filename_key = match v8::String::new(scope, "filename") { - Some(key) => key, - None => return candidate, - }; - match current_module.get(scope, filename_key.into()) { - Some(value) if value.is_string() => value.to_rust_string_lossy(scope), - _ => candidate, - } -} - -#[cfg_attr(test, allow(dead_code))] -fn resolved_promise<'s>( - scope: &mut v8::HandleScope<'s>, - value: v8::Local<'s, v8::Value>, -) -> Option> { - let resolver = v8::PromiseResolver::new(scope)?; - resolver.resolve(scope, value); - Some(resolver.get_promise(scope)) -} - -#[cfg_attr(test, allow(dead_code))] -fn rejected_promise<'s>( - scope: &mut v8::HandleScope<'s>, - reason: v8::Local<'s, v8::Value>, -) -> Option> { - let resolver = v8::PromiseResolver::new(scope)?; - resolver.reject(scope, reason); - Some(resolver.get_promise(scope)) -} - -/// Send _batchResolveModules via sync-blocking IPC. -/// -/// Sends an array of {specifier, referrer} pairs, receives an array of -/// {resolved, source} results (null entries for unresolvable modules). -/// Returns None if the host doesn't support batch resolution or on IPC error. -fn batch_resolve_via_ipc( - scope: &mut v8::HandleScope, - ctx: &BridgeCallContext, - batch: &[(String, String)], -) -> Option>> { - // Build V8 array of [specifier, referrer] pairs, wrapped in an outer array - // so the host handler receives the batch as a single argument (args are spread). - let inner = v8::Array::new(scope, batch.len() as i32); - for (i, (specifier, referrer)) in batch.iter().enumerate() { - let pair = v8::Array::new(scope, 2); - let spec_v8 = v8::String::new(scope, specifier)?; - let ref_v8 = v8::String::new(scope, referrer)?; - pair.set_index(scope, 0, spec_v8.into()); - pair.set_index(scope, 1, ref_v8.into()); - inner.set_index(scope, i as u32, pair.into()); - } - let outer = v8::Array::new(scope, 1); - outer.set_index(scope, 0, inner.into()); - let args = serialize_v8_value(scope, outer.into()).ok()?; - - let response = ctx.sync_call("_batchResolveModules", args).ok()??; - if response.len() > MAX_MODULE_BATCH_RESOLVE_RESPONSE_BYTES { - return None; - } - let val = deserialize_v8_value(scope, &response).ok()?; - - // Parse response: array of {resolved, source} or null - let result_arr = v8::Local::::try_from(val).ok()?; - let mut results = Vec::with_capacity(batch.len()); - for i in 0..result_arr.length().min(batch.len() as u32) { - let entry = result_arr.get_index(scope, i); - match entry { - Some(v) if !v.is_null() && !v.is_undefined() => { - let obj = v8::Local::::try_from(v).ok(); - if let Some(obj) = obj { - let r_key = v8::String::new(scope, "resolved").unwrap(); - let s_key = v8::String::new(scope, "source").unwrap(); - let resolved = obj - .get(scope, r_key.into()) - .filter(|v| v.is_string()) - .map(|v| v.to_rust_string_lossy(scope)); - let source = obj - .get(scope, s_key.into()) - .filter(|v| v.is_string()) - .map(|v| v.to_rust_string_lossy(scope)); - match (resolved, source) { - (Some(r), Some(s)) => results.push(Some((r, s))), - _ => results.push(None), - } - } else { - results.push(None); - } - } - _ => results.push(None), - } - } - Some(results) -} - -/// V8 ResolveModuleCallback — called during instantiate_module for each import. -/// -/// Sends sync-blocking IPC calls to resolve specifiers and load source code, -/// compiles resolved modules, and caches them. -fn module_resolve_callback<'a>( - context: v8::Local<'a, v8::Context>, - specifier: v8::Local<'a, v8::String>, - _import_attributes: v8::Local<'a, v8::FixedArray>, - referrer: v8::Local<'a, v8::Module>, -) -> Option> { - // SAFETY: CallbackScope can be constructed from Local within a V8 callback - let scope = &mut unsafe { v8::CallbackScope::new(context) }; - - let specifier_str = specifier.to_rust_string_lossy(scope); - let referrer_hash = referrer.get_identity_hash(); - - let referrer_name = MODULE_RESOLVE_STATE.with(|cell| { - let borrow = cell.borrow(); - let state = borrow.as_ref()?; - state.module_names.get(&referrer_hash).cloned() - }); - let referrer_name = referrer_name?; - resolve_or_compile_module(scope, &specifier_str, &referrer_name) -} - -/// Send _resolveModule(specifier, referrer_path) via sync-blocking IPC. -fn resolve_module_via_ipc( - scope: &mut v8::HandleScope, - ctx: &BridgeCallContext, - specifier: &str, - referrer: &str, -) -> Option { - // Serialize [specifier, referrer] as V8 Array - let spec_v8 = v8::String::new(scope, specifier).unwrap(); - let ref_v8 = v8::String::new(scope, referrer).unwrap(); - let arr = v8::Array::new(scope, 2); - arr.set_index(scope, 0, spec_v8.into()); - arr.set_index(scope, 1, ref_v8.into()); - let args = match serialize_v8_value(scope, arr.into()) { - Ok(bytes) => bytes, - Err(e) => { - throw_module_error(scope, &format!("_resolveModule serialize error: {}", e)); - return None; - } - }; - - match ctx.sync_call("_resolveModule", args) { - Ok(Some(bytes)) => match deserialize_v8_value(scope, &bytes) { - Ok(val) => { - if val.is_string() { - Some(val.to_rust_string_lossy(scope)) - } else { - // A non-string (null) return means the host resolver found no - // match — i.e. the module could not be located, NOT a type error. - // Name the importer so node_modules layout/discovery problems are - // diagnosable (e.g. a bare package installed off the importer's - // ancestor chain), since that is the common real cause here. - // - // Call out the host-mounted node_modules case too: a host_dir - // mount (what NodeRuntime `nodeModules` projects) confines reads - // to the mount root, so a package symlinked OUT of the mounted - // tree (pnpm/yarn workspace or `file:` deps that link to the - // workspace root or an external store) cannot be followed and - // surfaces here as not-found. - throw_module_error( - scope, - &format!( - "Cannot resolve module '{specifier}' (imported from \ - '{referrer}'): not found. For a bare package, ensure it is \ - installed in a node_modules directory on an ancestor of the \ - importer (or bundle the entrypoint). If you mounted a host \ - node_modules, point it at a directory that contains every \ - symlink target (e.g. the workspace root): symlinks that \ - escape the mount root are not followed." - ), - ); - None - } - } - Err(e) => { - throw_module_error(scope, &format!("_resolveModule decode error: {}", e)); - None - } - }, - Ok(None) => { - throw_module_error(scope, &format!("Cannot resolve module '{}'", specifier)); - None - } - Err(e) => { - throw_module_error(scope, &e); - None - } - } -} - -/// Send _loadFile(resolved_path) via sync-blocking IPC. -fn load_module_via_ipc( - scope: &mut v8::HandleScope, - ctx: &BridgeCallContext, - resolved_path: &str, -) -> Option { - // Serialize [resolved_path] as V8 Array - let path_v8 = v8::String::new(scope, resolved_path).unwrap(); - let arr = v8::Array::new(scope, 1); - arr.set_index(scope, 0, path_v8.into()); - let args = match serialize_v8_value(scope, arr.into()) { - Ok(bytes) => bytes, - Err(e) => { - throw_module_error(scope, &format!("_loadFile serialize error: {}", e)); - return None; - } - }; - - let ipc_result = ctx.sync_call("_loadFile", args); - match ipc_result { - Ok(Some(bytes)) => match deserialize_v8_value(scope, &bytes) { - Ok(val) => { - if val.is_string() { - Some(val.to_rust_string_lossy(scope)) - } else { - throw_module_error( - scope, - &format!("_loadFile returned non-string for '{}'", resolved_path), - ); - None - } - } - Err(e) => { - throw_module_error(scope, &format!("_loadFile decode error: {}", e)); - None - } - }, - Ok(None) => { - throw_module_error(scope, &format!("Cannot load module '{}'", resolved_path)); - None - } - Err(e) => { - throw_module_error(scope, &e); - None - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum ResolvedModuleFormat { - Module, - Commonjs, - Json, -} - -fn lookup_module_format_via_ipc( - scope: &mut v8::HandleScope, - ctx: &BridgeCallContext, - resolved_path: &str, -) -> Option { - let path_v8 = v8::String::new(scope, resolved_path).unwrap(); - let arr = v8::Array::new(scope, 1); - arr.set_index(scope, 0, path_v8.into()); - let args = match serialize_v8_value(scope, arr.into()) { - Ok(bytes) => bytes, - Err(e) => { - throw_module_error(scope, &format!("_moduleFormat serialize error: {}", e)); - return None; - } - }; - - match ctx.sync_call("_moduleFormat", args) { - Ok(Some(bytes)) => match deserialize_v8_value(scope, &bytes) { - Ok(val) if val.is_string() => match val.to_rust_string_lossy(scope).as_str() { - "module" => Some(ResolvedModuleFormat::Module), - "commonjs" => Some(ResolvedModuleFormat::Commonjs), - "json" => Some(ResolvedModuleFormat::Json), - _ => None, - }, - Ok(val) if val.is_null_or_undefined() => None, - Ok(_) => { - throw_module_error( - scope, - &format!("_moduleFormat returned non-string for '{}'", resolved_path), - ); - None - } - Err(e) => { - throw_module_error(scope, &format!("_moduleFormat decode error: {}", e)); - None - } - }, - Ok(None) => None, - Err(e) => { - throw_module_error(scope, &e); - None - } - } -} - -/// Throw a V8 exception for module resolution errors. -fn throw_module_error(scope: &mut v8::HandleScope, message: &str) { - let msg = v8::String::new(scope, message).unwrap(); - let exc = v8::Exception::error(scope, msg); - scope.throw_exception(exc); -} - -/// Detect if source code is likely CommonJS (not ESM). -/// Checks for module.exports, exports.X, or require() patterns without ESM import/export. -/// Node strips a leading shebang (`#!`) line before parsing a module. The guest -/// loader must match, or modules shipped as executables (CLI/SDK bundles that -/// begin with `#!/usr/bin/env node`) fail with "Invalid or unexpected token" on -/// the `#`. The newline is preserved so line numbers in stack traces stay aligned. -fn strip_leading_shebang(source: &str) -> &str { - match source.strip_prefix("#!") { - Some(rest) => match rest.find('\n') { - Some(idx) => &rest[idx..], - None => "", - }, - None => source, - } -} - -fn build_module_source( - scope: &mut v8::HandleScope, - raw_source: &str, - resolved_path: &str, - module_format: Option, -) -> String { - let raw_source = strip_leading_shebang(raw_source); - let normalized_path = resolved_path.to_ascii_lowercase(); - if normalized_path.ends_with(".json") || module_format == Some(ResolvedModuleFormat::Json) { - return build_json_esm_shim(resolved_path); - } - if (module_format == Some(ResolvedModuleFormat::Commonjs) - && !has_probable_esm_syntax(raw_source)) - || is_likely_cjs(raw_source, resolved_path, module_format) - { - return build_cjs_esm_shim(scope, raw_source, resolved_path); - } - add_esm_runtime_prelude(raw_source) -} - -fn build_json_esm_shim(resolved_path: &str) -> String { - format!( - "const _jsonModule = globalThis._requireFrom({}, \"/\");\nexport default _jsonModule;\n", - quoted_module_path(resolved_path) - ) -} - -fn build_cjs_esm_shim( - scope: &mut v8::HandleScope, - raw_source: &str, - resolved_path: &str, -) -> String { - // Static scanning only sees exports assigned with literal `exports.X =` / - // `Object.defineProperty(exports, "X", ...)` patterns in this file. It misses names introduced at - // runtime, e.g. tsc's `__exportStar(require("./sub"), exports)` re-export helper (used by - // `@sinclair/typebox/compiler` to surface `TypeCompiler`) or `Object.assign(exports, ...)`. When - // such a dynamic re-export pattern is present the static set is provably incomplete, so fall back - // to runtime extraction (require the module and enumerate the real `Object.keys(module.exports)`) - // and union the two. Only do this when static finds nothing or a dynamic re-export is detected: - // eagerly requiring every CJS module would add avoidable work and trigger side effects earlier - // than intended (see crates/execution/CLAUDE.md). Static still back-fills names that a - // partially-evaluated circular require may not have added to the exports object yet. - let mut names = extract_cjs_export_names(raw_source) - .into_iter() - .collect::>(); - if names.is_empty() || source_has_dynamic_cjs_reexports(raw_source) { - names.extend(extract_runtime_cjs_export_names(scope, resolved_path)); - } - - let mut exports = names.into_iter().collect::>(); - exports.sort(); - exports.truncate(MAX_CJS_NAMED_EXPORTS); - - let mut shim = format!( - "const _cjsModule = globalThis._requireFrom({}, \"/\");\nexport default _cjsModule;\n", - quoted_module_path(resolved_path) - ); - for name in exports { - shim.push_str(&format!( - "export const {} = _cjsModule[\"{}\"];\n", - name, name - )); - } - shim -} - -/// Runtime fallback for CJS named export extraction. Evaluates the module via -/// `globalThis._requireFrom` and enumerates `Object.keys(module.exports)` so -/// dynamically computed exports still support named ESM imports. A thread-local -/// in-progress set guards against pathological reentrancy: if shim construction -/// for a path somehow re-enters extraction for the same path, the inner call -/// returns an empty list instead of recursing. -fn extract_runtime_cjs_export_names( - scope: &mut v8::HandleScope, - resolved_path: &str, -) -> Vec { - let already_in_progress = CJS_RUNTIME_EXTRACTION_IN_PROGRESS.with(|cell| { - let mut in_progress = cell.borrow_mut(); - !in_progress.insert(resolved_path.to_string()) - }); - if already_in_progress { - return Vec::new(); - } - let names = extract_runtime_cjs_export_names_inner(scope, resolved_path); - CJS_RUNTIME_EXTRACTION_IN_PROGRESS.with(|cell| { - cell.borrow_mut().remove(resolved_path); - }); - names -} - -fn extract_runtime_cjs_export_names_inner( - scope: &mut v8::HandleScope, - resolved_path: &str, -) -> Vec { - let tc = &mut v8::TryCatch::new(scope); - let context = tc.get_current_context(); - let global = context.global(tc); - - let require_key = match v8::String::new(tc, "_requireFrom") { - Some(key) => key, - None => return Vec::new(), - }; - let require_fn = match global - .get(tc, require_key.into()) - .and_then(|value| v8::Local::::try_from(value).ok()) - { - Some(function) => function, - None => return Vec::new(), - }; - - let module_path = match v8::String::new(tc, resolved_path) { - Some(path) => path, - None => return Vec::new(), - }; - let root = match v8::String::new(tc, "/") { - Some(path) => path, - None => return Vec::new(), - }; - let require_args = [module_path.into(), root.into()]; - let receiver = v8::undefined(tc).into(); - let required_module = match require_fn.call(tc, receiver, &require_args) { - Some(value) => value, - None => return Vec::new(), - }; - if required_module.is_null_or_undefined() || !required_module.is_object() { - return Vec::new(); - } - - let object_key = match v8::String::new(tc, "Object") { - Some(key) => key, - None => return Vec::new(), - }; - let object_ctor = match global - .get(tc, object_key.into()) - .and_then(|value| v8::Local::::try_from(value).ok()) - { - Some(object) => object, - None => return Vec::new(), - }; - - let keys_key = match v8::String::new(tc, "keys") { - Some(key) => key, - None => return Vec::new(), - }; - let keys_fn = match object_ctor - .get(tc, keys_key.into()) - .and_then(|value| v8::Local::::try_from(value).ok()) - { - Some(function) => function, - None => return Vec::new(), - }; - - let keys_args = [required_module]; - let keys = match keys_fn - .call(tc, object_ctor.into(), &keys_args) - .and_then(|value| v8::Local::::try_from(value).ok()) - { - Some(array) => array, - None => return Vec::new(), - }; - - let mut names = Vec::new(); - for index in 0..keys.length() { - if names.len() >= MAX_CJS_NAMED_EXPORTS { - break; - } - let Some(value) = keys.get_index(tc, index) else { - continue; - }; - if !value.is_string() { - continue; - } - let name = value.to_rust_string_lossy(tc); - if name.len() > MAX_CJS_RUNTIME_EXPORT_NAME_LEN { - continue; - } - if is_valid_js_ident(&name) && name != "default" && name != "__esModule" { - names.push(name); - } - } - names.sort(); - names.dedup(); - names -} - -fn quoted_module_path(resolved_path: &str) -> String { - format!( - "\"{}\"", - resolved_path.replace('\\', "\\\\").replace('"', "\\\"") - ) -} - -fn is_likely_cjs( - source: &str, - resolved_path: &str, - module_format: Option, -) -> bool { - let normalized_path = resolved_path.to_ascii_lowercase(); - if normalized_path.ends_with(".mjs") || normalized_path.ends_with(".mts") { - return false; - } - if normalized_path.ends_with(".cjs") || normalized_path.ends_with(".cts") { - return true; - } - if module_format == Some(ResolvedModuleFormat::Module) { - return false; - } - if has_probable_esm_syntax(source) { - return false; - } - // CJS indicators - source.contains("module.exports") || source.contains("exports.") || source.contains("require(") -} - -fn has_probable_esm_syntax(source: &str) -> bool { - #[derive(Clone, Copy, PartialEq, Eq)] - enum ScanState { - Code, - LineComment, - BlockComment, - SingleQuote, - DoubleQuote, - Template, - } - - let bytes = source.as_bytes(); - let mut state = ScanState::Code; - let mut index = 0usize; - let mut brace_depth = 0u32; - let mut paren_depth = 0u32; - let mut bracket_depth = 0u32; - - while index < bytes.len() { - let byte = bytes[index]; - let next = bytes.get(index + 1).copied(); - - match state { - ScanState::Code => { - if index == 0 && byte == b'#' && next == Some(b'!') { - state = ScanState::LineComment; - index += 2; - continue; - } - if byte == b'/' && next == Some(b'/') { - state = ScanState::LineComment; - index += 2; - continue; - } - if byte == b'/' && next == Some(b'*') { - state = ScanState::BlockComment; - index += 2; - continue; - } - if byte == b'\'' { - state = ScanState::SingleQuote; - index += 1; - continue; - } - if byte == b'"' { - state = ScanState::DoubleQuote; - index += 1; - continue; - } - if byte == b'`' { - state = ScanState::Template; - index += 1; - continue; - } - - match byte { - b'{' => brace_depth = brace_depth.saturating_add(1), - b'}' => brace_depth = brace_depth.saturating_sub(1), - b'(' => paren_depth = paren_depth.saturating_add(1), - b')' => paren_depth = paren_depth.saturating_sub(1), - b'[' => bracket_depth = bracket_depth.saturating_add(1), - b']' => bracket_depth = bracket_depth.saturating_sub(1), - _ => {} - } - - if brace_depth == 0 - && paren_depth == 0 - && bracket_depth == 0 - && is_js_ident_start(byte) - { - let start = index; - index += 1; - while index < bytes.len() && is_js_ident_continue(bytes[index]) { - index += 1; - } - - let token = &source[start..index]; - if token == "export" { - return true; - } - if token == "import" { - let mut cursor = index; - while cursor < bytes.len() && bytes[cursor].is_ascii_whitespace() { - cursor += 1; - } - if bytes.get(cursor).copied() != Some(b'(') { - return true; - } - } - - continue; - } - - index += 1; - } - ScanState::LineComment => { - if byte == b'\n' { - state = ScanState::Code; - } - index += 1; - } - ScanState::BlockComment => { - if byte == b'*' && next == Some(b'/') { - state = ScanState::Code; - index += 2; - } else { - index += 1; - } - } - ScanState::SingleQuote => { - if byte == b'\\' { - index += 2; - } else if byte == b'\'' { - state = ScanState::Code; - index += 1; - } else { - index += 1; - } - } - ScanState::DoubleQuote => { - if byte == b'\\' { - index += 2; - } else if byte == b'"' { - state = ScanState::Code; - index += 1; - } else { - index += 1; - } - } - ScanState::Template => { - if byte == b'\\' { - index += 2; - } else if byte == b'`' { - state = ScanState::Code; - index += 1; - } else { - index += 1; - } - } - } - } - - false -} - -fn is_js_ident_start(byte: u8) -> bool { - byte.is_ascii_alphabetic() || byte == b'_' || byte == b'$' -} - -fn is_js_ident_continue(byte: u8) -> bool { - is_js_ident_start(byte) || byte.is_ascii_digit() -} - -/// Extract named export names from CJS source by scanning for `exports.X =` and -/// `module.exports = { X: ... }` patterns. Returns a list of valid JS identifiers. -fn extract_cjs_export_names(source: &str) -> Vec { - let mut names = HashSet::new(); - - collect_cjs_property_assignment_names(source, &mut names); - collect_cjs_define_property_names(source, &mut names); - collect_cjs_object_literal_export_names(source, &mut names); - - let mut result: Vec = names.into_iter().collect(); - result.sort(); - result -} - -fn collect_cjs_property_assignment_names( - source: &str, - names: &mut std::collections::HashSet, -) { - for prefix in ["exports.", "module.exports."] { - let mut cursor = 0usize; - while names.len() < MAX_CJS_NAMED_EXPORTS { - let Some(start) = find_code_pattern(source, prefix, cursor) else { - break; - }; - let name_start = start + prefix.len(); - let mut index = name_start; - while source - .as_bytes() - .get(index) - .is_some_and(|byte| is_js_ident_continue(*byte)) - { - index += 1; - } - let name = &source[name_start..index]; - let next = skip_ascii_whitespace(source, index); - if source.as_bytes().get(next) == Some(&b'=') - && is_valid_js_ident(name) - && name != "default" - && name != "__esModule" - { - names.insert(name.to_string()); - } - cursor = index.max(start + prefix.len()); - } - } -} - -fn collect_cjs_define_property_names(source: &str, names: &mut std::collections::HashSet) { - let mut cursor = 0usize; - while names.len() < MAX_CJS_NAMED_EXPORTS { - let Some(start) = find_code_pattern(source, "Object.defineProperty", cursor) else { - break; - }; - let mut index = skip_ascii_whitespace(source, start + "Object.defineProperty".len()); - if source.as_bytes().get(index) != Some(&b'(') { - cursor = start + "Object.defineProperty".len(); - continue; - } - index = skip_ascii_whitespace(source, index + 1); - if !source.as_bytes()[index..].starts_with(b"exports") { - cursor = start + "Object.defineProperty".len(); - continue; - } - index = skip_ascii_whitespace(source, index + "exports".len()); - if source.as_bytes().get(index) != Some(&b',') { - cursor = start + "Object.defineProperty".len(); - continue; - } - index = skip_ascii_whitespace(source, index + 1); - if let Some((name, end)) = parse_quoted_string_literal(source, index) { - if is_valid_js_ident(name) && name != "default" && name != "__esModule" { - names.insert(name.to_string()); - cursor = end; - continue; - } - } - cursor = start + "Object.defineProperty".len(); - } -} - -fn collect_cjs_object_literal_export_names( - source: &str, - names: &mut std::collections::HashSet, -) { - collect_module_exports_assignments(source, names); - collect_object_assign_module_exports(source, names); -} - -fn collect_module_exports_assignments(source: &str, names: &mut std::collections::HashSet) { - let mut cursor = 0usize; - while names.len() < MAX_CJS_NAMED_EXPORTS { - let Some(start) = find_code_pattern(source, "module.exports", cursor) else { - break; - }; - let mut index = skip_ascii_whitespace(source, start + "module.exports".len()); - if source.as_bytes().get(index) != Some(&b'=') { - cursor = start + "module.exports".len(); - continue; - } - index = skip_ascii_whitespace(source, index + 1); - cursor = if source.as_bytes().get(index) == Some(&b'{') { - collect_object_literal_keys(source, index, names) - } else { - index.saturating_add(1) - }; - } -} - -fn collect_object_assign_module_exports( - source: &str, - names: &mut std::collections::HashSet, -) { - let mut cursor = 0usize; - while names.len() < MAX_CJS_NAMED_EXPORTS { - let Some(start) = find_code_pattern(source, "Object.assign", cursor) else { - break; - }; - let mut index = skip_ascii_whitespace(source, start + "Object.assign".len()); - if source.as_bytes().get(index) != Some(&b'(') { - cursor = start + "Object.assign".len(); - continue; - } - index = skip_ascii_whitespace(source, index + 1); - if !source.as_bytes()[index..].starts_with(b"module.exports") { - cursor = start + "Object.assign".len(); - continue; - } - index = skip_ascii_whitespace(source, index + "module.exports".len()); - if source.as_bytes().get(index) != Some(&b',') { - cursor = start + "Object.assign".len(); - continue; - } - index = skip_ascii_whitespace(source, index + 1); - cursor = if source.as_bytes().get(index) == Some(&b'{') { - collect_object_literal_keys(source, index, names) - } else { - index.saturating_add(1) - }; - } -} - -#[derive(Clone, Copy, PartialEq, Eq)] -enum CjsScanState { - Code, - LineComment, - BlockComment, - SingleQuote, - DoubleQuote, - Template, - Regex, - RegexClass, -} - -fn find_code_pattern(source: &str, pattern: &str, cursor: usize) -> Option { - let bytes = source.as_bytes(); - let mut state = CjsScanState::Code; - let mut index = cursor; - while index < bytes.len() { - let byte = bytes[index]; - let next = bytes.get(index + 1).copied(); - - match state { - CjsScanState::Code => { - if byte == b'/' && next == Some(b'/') { - state = CjsScanState::LineComment; - index += 2; - continue; - } - if byte == b'/' && next == Some(b'*') { - state = CjsScanState::BlockComment; - index += 2; - continue; - } - if byte == b'\'' { - state = CjsScanState::SingleQuote; - index += 1; - continue; - } - if byte == b'"' { - state = CjsScanState::DoubleQuote; - index += 1; - continue; - } - if byte == b'`' { - state = CjsScanState::Template; - index += 1; - continue; - } - if byte == b'/' && slash_starts_regex_literal(source, index) { - state = CjsScanState::Regex; - index += 1; - continue; - } - if bytes[index..].starts_with(pattern.as_bytes()) - && has_code_pattern_boundary(source, index, pattern) - { - return Some(index); - } - index += 1; - } - CjsScanState::LineComment => { - if byte == b'\n' { - state = CjsScanState::Code; - } - index += 1; - } - CjsScanState::BlockComment => { - if byte == b'*' && next == Some(b'/') { - state = CjsScanState::Code; - index += 2; - } else { - index += 1; - } - } - CjsScanState::SingleQuote => { - if byte == b'\\' { - index += 2; - } else if byte == b'\'' { - state = CjsScanState::Code; - index += 1; - } else { - index += 1; - } - } - CjsScanState::DoubleQuote => { - if byte == b'\\' { - index += 2; - } else if byte == b'"' { - state = CjsScanState::Code; - index += 1; - } else { - index += 1; - } - } - CjsScanState::Template => { - if byte == b'\\' { - index += 2; - } else if byte == b'`' { - state = CjsScanState::Code; - index += 1; - } else { - index += 1; - } - } - CjsScanState::Regex => { - if byte == b'\\' { - index += 2; - } else if byte == b'[' { - state = CjsScanState::RegexClass; - index += 1; - } else if byte == b'/' { - state = CjsScanState::Code; - index += 1; - } else { - index += 1; - } - } - CjsScanState::RegexClass => { - if byte == b'\\' { - index += 2; - } else if byte == b']' { - state = CjsScanState::Regex; - index += 1; - } else { - index += 1; - } - } - } - } - None -} - -fn slash_starts_regex_literal(source: &str, slash_index: usize) -> bool { - let bytes = source.as_bytes(); - let mut cursor = slash_index; - while cursor > 0 { - cursor -= 1; - if bytes[cursor].is_ascii_whitespace() { - continue; - } - return match bytes[cursor] { - b'(' | b')' | b'[' | b'{' | b'}' | b':' | b',' | b';' | b'=' | b'!' | b'?' | b'&' - | b'|' | b'+' | b'-' | b'*' | b'%' | b'^' | b'~' | b'<' => true, - b'>' => cursor > 0 && bytes[cursor - 1] == b'=', - byte if is_js_ident_continue(byte) => { - let end = cursor + 1; - let mut start = cursor; - while start > 0 && is_js_ident_continue(bytes[start - 1]) { - start -= 1; - } - matches!( - &source[start..end], - "await" - | "case" - | "delete" - | "do" - | "else" - | "in" - | "instanceof" - | "of" - | "return" - | "throw" - | "typeof" - | "void" - | "yield" - ) - } - _ => false, - }; - } - true -} - -fn has_code_pattern_boundary(source: &str, index: usize, pattern: &str) -> bool { - let bytes = source.as_bytes(); - let before_ok = index == 0 - || bytes - .get(index - 1) - .is_none_or(|byte| !is_js_ident_continue(*byte) && *byte != b'.'); - let end = index + pattern.len(); - let after_ok = pattern.ends_with('.') - || bytes - .get(end) - .is_none_or(|byte| !is_js_ident_continue(*byte)); - before_ok && after_ok -} - -fn skip_ascii_whitespace(source: &str, mut index: usize) -> usize { - while source - .as_bytes() - .get(index) - .is_some_and(u8::is_ascii_whitespace) - { - index += 1; - } - index -} - -fn collect_object_literal_keys( - source: &str, - open_brace: usize, - names: &mut std::collections::HashSet, -) -> usize { - let mut depth = 0usize; - let mut state = CjsScanState::Code; - let mut entry_start = open_brace + 1; - let bytes = source.as_bytes(); - let mut iter = source[open_brace..].char_indices().peekable(); - while let Some((offset, ch)) = iter.next() { - let index = open_brace + offset; - let byte = bytes[index]; - let next = bytes.get(index + 1).copied(); - - match state { - CjsScanState::Code => { - if byte == b'/' && next == Some(b'/') { - state = CjsScanState::LineComment; - continue; - } - if byte == b'/' && next == Some(b'*') { - state = CjsScanState::BlockComment; - continue; - } - if byte == b'\'' { - state = CjsScanState::SingleQuote; - continue; - } - if byte == b'"' { - state = CjsScanState::DoubleQuote; - continue; - } - if byte == b'`' { - state = CjsScanState::Template; - continue; - } - if byte == b'/' && slash_starts_regex_literal(source, index) { - state = CjsScanState::Regex; - continue; - } - match ch { - '{' | '[' | '(' => depth += 1, - '}' | ']' | ')' => { - depth = depth.saturating_sub(1); - if depth == 0 && ch == '}' { - collect_object_literal_entry(&source[entry_start..index], names); - return index + ch.len_utf8(); - } - } - ',' if depth == 1 => { - collect_object_literal_entry(&source[entry_start..index], names); - if names.len() >= MAX_CJS_NAMED_EXPORTS { - return index + ch.len_utf8(); - } - entry_start = index + ch.len_utf8(); - } - _ => {} - } - } - CjsScanState::LineComment => { - if byte == b'\n' { - state = CjsScanState::Code; - } - } - CjsScanState::BlockComment => { - if byte == b'*' && next == Some(b'/') { - state = CjsScanState::Code; - iter.next(); - } - } - CjsScanState::SingleQuote => { - if byte == b'\\' { - iter.next(); - } else if byte == b'\'' { - state = CjsScanState::Code; - } - } - CjsScanState::DoubleQuote => { - if byte == b'\\' { - iter.next(); - } else if byte == b'"' { - state = CjsScanState::Code; - } - } - CjsScanState::Template => { - if byte == b'\\' { - iter.next(); - } else if byte == b'`' { - state = CjsScanState::Code; - } - } - CjsScanState::Regex => { - if byte == b'\\' { - iter.next(); - } else if byte == b'[' { - state = CjsScanState::RegexClass; - } else if byte == b'/' { - state = CjsScanState::Code; - } - } - CjsScanState::RegexClass => { - if byte == b'\\' { - iter.next(); - } else if byte == b']' { - state = CjsScanState::Regex; - } - } - } - } - source.len() -} - -fn collect_object_literal_entry(entry: &str, names: &mut std::collections::HashSet) { - let key = entry_key(entry); - if is_valid_js_ident(key) && key != "default" && key != "__esModule" { - names.insert(key.to_string()); - } -} - -fn entry_key(entry: &str) -> &str { - let trimmed = entry.trim(); - if let Some((quoted, end)) = parse_quoted_string_literal(trimmed, 0) { - let next = skip_ascii_whitespace(trimmed, end); - if trimmed.as_bytes().get(next) == Some(&b':') { - return quoted; - } - return ""; - } - trimmed - .find(':') - .map(|separator| &trimmed[..separator]) - .unwrap_or(trimmed) - .trim() -} - -fn parse_quoted_string_literal(source: &str, index: usize) -> Option<(&str, usize)> { - let quote = *source.as_bytes().get(index)?; - if quote != b'\'' && quote != b'"' { - return None; - } - let mut cursor = index + 1; - while cursor < source.len() { - let byte = source.as_bytes()[cursor]; - if byte == b'\\' { - cursor = cursor.saturating_add(2); - continue; - } - if byte == quote { - let value = &source[index + 1..cursor]; - return Some((value, cursor + 1)); - } - cursor += 1; - } - None -} - -/// Whether CJS `source` re-exports names through a runtime pattern that static scanning in -/// [`extract_cjs_export_names`] cannot resolve, so the named-export set is provably incomplete -/// without evaluating the module. Covers tsc/tslib's `__exportStar(require("./sub"), exports)` -/// helper (which copies a submodule's enumerable keys onto `exports` at runtime) and -/// bulk exports whose final enumerable keys can depend on runtime values. -fn source_has_dynamic_cjs_reexports(source: &str) -> bool { - source.contains("__exportStar") - || source.contains("Object.assign(exports") - || source.contains("Object.assign(module.exports") - || source.contains("Object.defineProperties(exports") - || source.contains("Object.defineProperties(module.exports") - || source_has_module_exports_object_spread(source) -} - -fn source_has_module_exports_object_spread(source: &str) -> bool { - let mut cursor = 0usize; - while let Some(start) = find_code_pattern(source, "module.exports", cursor) { - let mut index = skip_ascii_whitespace(source, start + "module.exports".len()); - if source.as_bytes().get(index) != Some(&b'=') { - cursor = start + "module.exports".len(); - continue; - } - index = skip_ascii_whitespace(source, index + 1); - if source.as_bytes().get(index) != Some(&b'{') { - cursor = index.saturating_add(1); - continue; - } - let end = collect_object_literal_keys(source, index, &mut HashSet::new()); - if source[index..end.min(source.len())].contains("...") { - return true; - } - cursor = end; - } - false -} - -fn add_esm_runtime_prelude(source: &str) -> String { - let mut prelude = String::new(); - - if source.contains("require(") - && !source.contains("createRequire(import.meta.url)") - && !source.contains("createRequire(") - && !source.contains("const require =") - && !source.contains("let require =") - && !source.contains("var require =") - && !source.contains("function require(") - { - prelude - .push_str("const require = globalThis._moduleModule.createRequire(import.meta.url);\n"); - } - - for (name, triggers) in [ - ("fetch", &["fetch("][..]), - ("Headers", &["Headers", "new Headers("][..]), - ("Request", &["Request", "new Request("][..]), - ("Response", &["Response", "new Response("][..]), - ("Blob", &["Blob", "new Blob("][..]), - ("File", &["File", "new File("][..]), - ("FormData", &["FormData", "new FormData("][..]), - ] { - if needs_esm_global_alias(source, name, triggers) { - prelude.push_str(&format!("const {name} = globalThis.{name};\n")); - } - } - - if prelude.is_empty() { - source.to_owned() - } else { - format!("{prelude}{source}") - } -} - -fn needs_esm_global_alias(source: &str, name: &str, triggers: &[&str]) -> bool { - if !triggers.iter().any(|trigger| source.contains(trigger)) { - return false; - } - - if has_named_import_binding(source, name) { - return false; - } - - for pattern in [ - format!("const {name}"), - format!("let {name}"), - format!("var {name}"), - format!("function {name}"), - format!("class {name}"), - format!("import {name} from"), - format!("import * as {name}"), - ] { - if source.contains(&pattern) { - return false; - } - } - - true -} - -fn has_named_import_binding(source: &str, name: &str) -> bool { - #[derive(Clone, Copy, PartialEq, Eq)] - enum ScanState { - Code, - LineComment, - BlockComment, - SingleQuote, - DoubleQuote, - Template, - } - - let bytes = source.as_bytes(); - let mut state = ScanState::Code; - let mut index = 0usize; - - while index < bytes.len() { - let byte = bytes[index]; - let next = bytes.get(index + 1).copied(); - - match state { - ScanState::Code => { - if byte == b'/' && next == Some(b'/') { - state = ScanState::LineComment; - index += 2; - continue; - } - if byte == b'/' && next == Some(b'*') { - state = ScanState::BlockComment; - index += 2; - continue; - } - if byte == b'\'' { - state = ScanState::SingleQuote; - index += 1; - continue; - } - if byte == b'"' { - state = ScanState::DoubleQuote; - index += 1; - continue; - } - if byte == b'`' { - state = ScanState::Template; - index += 1; - continue; - } - if !is_js_ident_start(byte) { - index += 1; - continue; - } - - let start = index; - index += 1; - while index < bytes.len() && is_js_ident_continue(bytes[index]) { - index += 1; - } - if &source[start..index] != "import" { - continue; - } - - let mut cursor = index; - while cursor < bytes.len() && bytes[cursor].is_ascii_whitespace() { - cursor += 1; - } - if bytes.get(cursor).copied() != Some(b'{') { - continue; - } - cursor += 1; - let imports_start = cursor; - while cursor < bytes.len() && bytes[cursor] != b'}' { - cursor += 1; - } - if cursor >= bytes.len() { - return false; - } - if named_imports_bind_name(&source[imports_start..cursor], name) { - return true; - } - index = cursor + 1; - } - ScanState::LineComment => { - if byte == b'\n' { - state = ScanState::Code; - } - index += 1; - } - ScanState::BlockComment => { - if byte == b'*' && next == Some(b'/') { - state = ScanState::Code; - index += 2; - } else { - index += 1; - } - } - ScanState::SingleQuote => { - if byte == b'\\' { - index += 2; - } else if byte == b'\'' { - state = ScanState::Code; - index += 1; - } else { - index += 1; - } - } - ScanState::DoubleQuote => { - if byte == b'\\' { - index += 2; - } else if byte == b'"' { - state = ScanState::Code; - index += 1; - } else { - index += 1; - } - } - ScanState::Template => { - if byte == b'\\' { - index += 2; - } else if byte == b'`' { - state = ScanState::Code; - index += 1; - } else { - index += 1; - } - } - } - } - false -} - -fn named_imports_bind_name(imports: &str, name: &str) -> bool { - imports.split(',').any(|part| { - let local = part - .split_once(" as ") - .map(|(_, alias)| alias) - .unwrap_or(part); - local.trim() == name - }) -} - -fn is_valid_js_ident(s: &str) -> bool { - if s.is_empty() { - return false; - } - if is_js_reserved_word(s) { - return false; - } - let mut chars = s.chars(); - let first = chars.next().unwrap(); - if !first.is_alphabetic() && first != '_' && first != '$' { - return false; - } - chars.all(|c| c.is_alphanumeric() || c == '_' || c == '$') -} - -fn is_js_reserved_word(s: &str) -> bool { - matches!( - s, - "arguments" - | "as" - | "async" - | "await" - | "break" - | "case" - | "catch" - | "class" - | "const" - | "continue" - | "debugger" - | "default" - | "delete" - | "do" - | "else" - | "enum" - | "eval" - | "export" - | "extends" - | "false" - | "finally" - | "for" - | "from" - | "function" - | "get" - | "if" - | "implements" - | "import" - | "in" - | "instanceof" - | "interface" - | "let" - | "new" - | "null" - | "of" - | "package" - | "private" - | "protected" - | "public" - | "return" - | "set" - | "static" - | "super" - | "switch" - | "target" - | "this" - | "throw" - | "true" - | "try" - | "typeof" - | "var" - | "void" - | "while" - | "with" - | "yield" - ) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::bridge; - use crate::host_call::BridgeCallContext; - use crate::isolate; - use std::collections::HashMap; - use std::io::{Cursor, Write}; - use std::sync::{Arc, Mutex}; - - #[test] - fn strip_leading_shebang_matches_node() { - // Shebang stripped (newline preserved so line numbers hold). - assert_eq!( - strip_leading_shebang("#!/usr/bin/env node\nexport const x = 1;\n"), - "\nexport const x = 1;\n" - ); - // No shebang -> untouched. - assert_eq!( - strip_leading_shebang("export const x = 1;\n"), - "export const x = 1;\n" - ); - // `#` not at byte 0 -> untouched (only a leading shebang is special). - assert_eq!(strip_leading_shebang(" #!nope\n"), " #!nope\n"); - // Whole file is just a shebang. - assert_eq!(strip_leading_shebang("#!/usr/bin/env node"), ""); - } - - /// Shared writer that captures output for test inspection - struct SharedWriter(Arc>>); - - impl Write for SharedWriter { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.0.lock().unwrap().write(buf) - } - fn flush(&mut self) -> std::io::Result<()> { - self.0.lock().unwrap().flush() - } - } - - #[test] - fn esm_global_alias_detection_handles_multiline_named_imports() { - let source = r#" -import { - Blob, - File, - FormData -} from "fetch-blob/from.js"; - -export { File }; -"#; - - assert!(!needs_esm_global_alias(source, "File", &["File"])); - } - - #[test] - fn esm_global_alias_detection_handles_named_import_aliases() { - let source = r#" -import { - File as RuntimeFile -} from "fetch-blob/from.js"; - -export const file = RuntimeFile; -"#; - - assert!(!needs_esm_global_alias( - source, - "RuntimeFile", - &["RuntimeFile"] - )); - } - - #[test] - fn esm_global_alias_detection_ignores_commented_named_imports() { - let source = r#" -// import { File } from "fetch-blob/from.js"; -/* -import { - Blob, - File -} from "fetch-blob/from.js"; -*/ -export function makeFile() { - return new File([], "empty.txt"); -} -"#; - - assert!(needs_esm_global_alias(source, "File", &["new File("])); - } - - #[test] - fn esm_global_alias_detection_ignores_string_named_imports() { - let source = r#" -const example = "import { File } from 'fetch-blob/from.js'"; -const singleQuoteExample = 'import { File } from "fetch-blob/from.js"'; -const template = `import { - File -} from "fetch-blob/from.js"`; - -export const file = new File([], "empty.txt"); -"#; - - assert!(needs_esm_global_alias(source, "File", &["new File("])); - } - - /// Helper: serialize a V8 string value for test BridgeResponse payloads - fn v8_serialize_str( - iso: &mut v8::OwnedIsolate, - ctx: &v8::Global, - s: &str, - ) -> Vec { - let scope = &mut v8::HandleScope::new(iso); - let local = v8::Local::new(scope, ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = v8::String::new(scope, s).unwrap(); - crate::bridge::serialize_v8_value(scope, val.into()).unwrap() - } - - /// Helper: serialize a V8 integer value for test BridgeResponse payloads - fn v8_serialize_int( - iso: &mut v8::OwnedIsolate, - ctx: &v8::Global, - n: i64, - ) -> Vec { - let scope = &mut v8::HandleScope::new(iso); - let local = v8::Local::new(scope, ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = v8::Number::new(scope, n as f64); - crate::bridge::serialize_v8_value(scope, val.into()).unwrap() - } - - /// Helper: serialize a V8 null value for test BridgeResponse payloads - fn v8_serialize_null(iso: &mut v8::OwnedIsolate, ctx: &v8::Global) -> Vec { - let scope = &mut v8::HandleScope::new(iso); - let local = v8::Local::new(scope, ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = v8::null(scope); - crate::bridge::serialize_v8_value(scope, val.into()).unwrap() - } - - /// Helper: serialize a V8 object (from JS expression) for test BridgeResponse payloads - fn v8_serialize_eval( - iso: &mut v8::OwnedIsolate, - ctx: &v8::Global, - expr: &str, - ) -> Vec { - let scope = &mut v8::HandleScope::new(iso); - let local = v8::Local::new(scope, ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let source = v8::String::new(scope, expr).unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let val = script.run(scope).unwrap(); - crate::bridge::serialize_v8_value(scope, val).unwrap() - } - - /// Enter a context, run JS, return the string result. - fn eval( - isolate: &mut v8::OwnedIsolate, - context: &v8::Global, - code: &str, - ) -> String { - let scope = &mut v8::HandleScope::new(isolate); - let local = v8::Local::new(scope, context); - let scope = &mut v8::ContextScope::new(scope, local); - let source = v8::String::new(scope, code).unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - result.to_rust_string_lossy(scope) - } - - /// Enter a context, run JS, return true if the result is truthy. - fn eval_bool( - isolate: &mut v8::OwnedIsolate, - context: &v8::Global, - code: &str, - ) -> bool { - let scope = &mut v8::HandleScope::new(isolate); - let local = v8::Local::new(scope, context); - let scope = &mut v8::ContextScope::new(scope, local); - let source = v8::String::new(scope, code).unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - result.boolean_value(scope) - } - - /// Enter a context, run JS, return true if an exception was thrown. - fn eval_throws( - isolate: &mut v8::OwnedIsolate, - context: &v8::Global, - code: &str, - ) -> bool { - let scope = &mut v8::HandleScope::new(isolate); - let local = v8::Local::new(scope, context); - let scope = &mut v8::ContextScope::new(scope, local); - let tc = &mut v8::TryCatch::new(scope); - let source = v8::String::new(tc, code).unwrap(); - if let Some(script) = v8::Script::compile(tc, source, None) { - script.run(tc); - } - tc.has_caught() - } - - #[test] - fn v8_consolidated_tests() { - isolate::init_v8_platform(); - - // --- Isolate lifecycle (moved from isolate::tests to consolidate V8 tests) --- - // Create and destroy 3 isolates sequentially without crash - for i in 0..3 { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let result = eval(&mut isolate, &context, &format!("{} + 1", i)); - assert_eq!(result, format!("{}", i + 1)); - } - // Isolate with heap limit - { - let mut isolate = isolate::create_isolate(Some(16)); - let context = isolate::create_context(&mut isolate); - assert_eq!(eval(&mut isolate, &context, "1 + 2"), "3"); - } - // Isolate without heap limit - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - assert_eq!( - eval(&mut isolate, &context, "'hello' + ' world'"), - "hello world" - ); - } - // Global context handle persists state - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - eval(&mut isolate, &context, "var x = 42;"); - assert_eq!(eval(&mut isolate, &context, "x"), "42"); - } - // Unhandled rejection tracking is bounded within a microtask checkpoint. - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - execute_script( - scope, - "", - "for (let i = 0; i < 1100; i++) Promise.reject(new Error('boom ' + i));", - &mut None, - ) - }; - assert_eq!(code, 1); - let error = error.expect("unhandled rejection limit error"); - assert_eq!( - error.code.as_deref(), - Some("ERR_AGENTOS_UNHANDLED_REJECTION_LIMIT") - ); - assert!(error - .message - .contains("unhandled promise rejection registry exceeded limit")); - } - // Over-cap rejections that are handled before the drain should not fail. - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - execute_script( - scope, - "", - r#" - const promises = []; - for (let i = 0; i < 1100; i++) promises.push(Promise.reject(new Error('boom ' + i))); - for (const promise of promises) promise.catch(() => {}); - "#, - &mut None, - ) - }; - assert_eq!(code, 0); - assert!( - error.is_none(), - "handled over-cap rejections should not surface a limit error" - ); - } - - // --- Part 1: InjectGlobals sets _processConfig and _osConfig --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - - let mut env = HashMap::new(); - env.insert("HOME".into(), "/home/agentos".into()); - env.insert("PATH".into(), "/usr/bin".into()); - - let process_config = ProcessConfig { - cwd: "/app".into(), - env, - timing_mitigation: "none".into(), - frozen_time_ms: Some(1700000000000.0), - high_resolution_time: true, - }; - let os_config = OsConfig { - homedir: "/home/agentos".into(), - tmpdir: "/tmp".into(), - platform: "linux".into(), - arch: "x64".into(), - }; - - // Inject globals - { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals(scope, &process_config, &os_config); - } - - // Verify _processConfig values - assert_eq!(eval(&mut isolate, &context, "_processConfig.cwd"), "/app"); - assert_eq!( - eval(&mut isolate, &context, "_processConfig.timing_mitigation"), - "none" - ); - assert_eq!( - eval(&mut isolate, &context, "_processConfig.frozen_time_ms"), - "1700000000000" - ); - assert_eq!( - eval( - &mut isolate, - &context, - "_processConfig.high_resolution_time" - ), - "true" - ); - assert_eq!( - eval(&mut isolate, &context, "_processConfig.env.HOME"), - "/home/agentos" - ); - assert_eq!( - eval(&mut isolate, &context, "_processConfig.env.PATH"), - "/usr/bin" - ); - - // Verify _osConfig values - assert_eq!( - eval(&mut isolate, &context, "_osConfig.homedir"), - "/home/agentos" - ); - assert_eq!(eval(&mut isolate, &context, "_osConfig.tmpdir"), "/tmp"); - assert_eq!(eval(&mut isolate, &context, "_osConfig.platform"), "linux"); - assert_eq!(eval(&mut isolate, &context, "_osConfig.arch"), "x64"); - } - - // --- Part 1a: InjectGlobals payload injection fails closed on invalid payload --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let payload = v8_serialize_eval( - &mut isolate, - &context, - r#"({ - processConfig: { - cwd: "/app", - env: { HOME: "/home/agentos" }, - timing_mitigation: "none", - frozen_time_ms: null - } - })"#, - ); - - let err = { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals_from_payload(scope, &payload).expect_err("missing osConfig") - }; - - assert_eq!(err.code.as_deref(), Some("ERR_INVALID_GLOBALS_PAYLOAD")); - assert!( - err.message.contains("missing osConfig"), - "unexpected error message: {}", - err.message - ); - assert_eq!( - eval(&mut isolate, &context, "typeof _processConfig"), - "undefined", - "invalid payload must not partially inject process config" - ); - assert_eq!( - eval(&mut isolate, &context, "typeof _osConfig"), - "undefined", - "invalid payload must not inject os config" - ); - } - - // --- Part 1b: InjectGlobals payload injection rejects primitive configs --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let payload = v8_serialize_eval( - &mut isolate, - &context, - r#"({ - processConfig: "not-an-object", - osConfig: { - homedir: "/home/agentos", - tmpdir: "/tmp", - platform: "linux", - arch: "x64" - } - })"#, - ); - - let err = { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals_from_payload(scope, &payload).expect_err("primitive processConfig") - }; - - assert_eq!(err.code.as_deref(), Some("ERR_INVALID_GLOBALS_PAYLOAD")); - assert!( - err.message.contains("processConfig is not an object"), - "unexpected error message: {}", - err.message - ); - assert_eq!( - eval(&mut isolate, &context, "typeof _processConfig"), - "undefined", - "wrong-type payload must not inject primitive process config" - ); - } - - // --- Part 1c: InjectGlobals payload injection freezes configs and env --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let payload = v8_serialize_eval( - &mut isolate, - &context, - r#"({ - processConfig: { - cwd: "/app", - env: "not-an-object", - timing_mitigation: "none", - frozen_time_ms: null - }, - osConfig: { - homedir: "/home/agentos", - tmpdir: "/tmp", - platform: "linux", - arch: "x64" - } - })"#, - ); - - let err = { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals_from_payload(scope, &payload).expect_err("primitive env") - }; - - assert_eq!(err.code.as_deref(), Some("ERR_INVALID_GLOBALS_PAYLOAD")); - assert!( - err.message.contains("processConfig.env is not an object"), - "unexpected error message: {}", - err.message - ); - assert_eq!( - eval(&mut isolate, &context, "typeof _processConfig"), - "undefined", - "wrong-type env payload must not partially inject process config" - ); - } - - // --- Part 1d: InjectGlobals payload injection rejects missing env --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let payload = v8_serialize_eval( - &mut isolate, - &context, - r#"({ - processConfig: { - cwd: "/app", - timing_mitigation: "none", - frozen_time_ms: null - }, - osConfig: { - homedir: "/home/agentos", - tmpdir: "/tmp", - platform: "linux", - arch: "x64" - } - })"#, - ); - - let err = { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals_from_payload(scope, &payload).expect_err("missing env") - }; - - assert_eq!(err.code.as_deref(), Some("ERR_INVALID_GLOBALS_PAYLOAD")); - assert!( - err.message.contains("missing processConfig.env"), - "unexpected error message: {}", - err.message - ); - assert_eq!( - eval(&mut isolate, &context, "typeof _processConfig"), - "undefined", - "missing env payload must not partially inject process config" - ); - } - - // --- Part 1e: InjectGlobals payload injection rejects non-plain object env --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let payload = v8_serialize_eval( - &mut isolate, - &context, - r#"({ - processConfig: { - cwd: "/app", - env: new Uint8Array([1]), - timing_mitigation: "none", - frozen_time_ms: null - }, - osConfig: { - homedir: "/home/agentos", - tmpdir: "/tmp", - platform: "linux", - arch: "x64" - } - })"#, - ); - - let err = { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals_from_payload(scope, &payload).expect_err("typed array env") - }; - - assert_eq!(err.code.as_deref(), Some("ERR_INVALID_GLOBALS_PAYLOAD")); - assert!( - err.message - .contains("processConfig.env is not a plain object"), - "unexpected error message: {}", - err.message - ); - assert_eq!( - eval(&mut isolate, &context, "typeof _processConfig"), - "undefined", - "typed-array env payload must not partially inject process config" - ); - } - - // --- Part 1f: InjectGlobals payload injection freezes configs and env --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let payload = v8_serialize_eval( - &mut isolate, - &context, - r#"({ - processConfig: { - cwd: "/app", - env: { HOME: "/home/agentos" }, - timing_mitigation: "none", - frozen_time_ms: null - }, - osConfig: { - homedir: "/home/agentos", - tmpdir: "/tmp", - platform: "linux", - arch: "x64" - } - })"#, - ); - - { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals_from_payload(scope, &payload).expect("valid globals payload"); - } - - assert_eq!(eval(&mut isolate, &context, "_processConfig.cwd"), "/app"); - assert_eq!( - eval(&mut isolate, &context, "_processConfig.env.HOME"), - "/home/agentos" - ); - assert!(eval_bool( - &mut isolate, - &context, - "Object.isFrozen(_processConfig) && Object.isFrozen(_processConfig.env) && Object.isFrozen(_osConfig)" - )); - } - - // --- Part 2: frozen_time_ms null when None --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - - let process_config = ProcessConfig { - cwd: "/".into(), - env: HashMap::new(), - timing_mitigation: "none".into(), - frozen_time_ms: None, - high_resolution_time: false, - }; - let os_config = OsConfig { - homedir: "/root".into(), - tmpdir: "/tmp".into(), - platform: "linux".into(), - arch: "x64".into(), - }; - - { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals(scope, &process_config, &os_config); - } - - assert_eq!( - eval( - &mut isolate, - &context, - "_processConfig.frozen_time_ms === null" - ), - "true" - ); - } - - // --- Part 3: Objects are frozen (immutable) --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - - let process_config = ProcessConfig { - cwd: "/app".into(), - env: HashMap::new(), - timing_mitigation: "none".into(), - frozen_time_ms: None, - high_resolution_time: false, - }; - let os_config = OsConfig { - homedir: "/home".into(), - tmpdir: "/tmp".into(), - platform: "linux".into(), - arch: "x64".into(), - }; - - { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals(scope, &process_config, &os_config); - } - - // Verify Object.isFrozen - assert!(eval_bool( - &mut isolate, - &context, - "Object.isFrozen(_processConfig)" - )); - assert!(eval_bool( - &mut isolate, - &context, - "Object.isFrozen(_osConfig)" - )); - assert!(eval_bool( - &mut isolate, - &context, - "Object.isFrozen(_processConfig.env)" - )); - - // Verify non-writable: assignment in strict mode throws - assert!(eval_throws( - &mut isolate, - &context, - "'use strict'; _processConfig.cwd = '/hacked'" - )); - assert!(eval_throws( - &mut isolate, - &context, - "'use strict'; _osConfig.platform = 'hacked'" - )); - - // Verify non-configurable: cannot delete or redefine - assert!(eval_throws( - &mut isolate, - &context, - "'use strict'; delete _processConfig" - )); - assert!(eval_throws( - &mut isolate, - &context, - "Object.defineProperty(globalThis, '_processConfig', { value: {} })" - )); - assert!(eval_throws( - &mut isolate, - &context, - "Object.defineProperty(globalThis, '_osConfig', { value: {} })" - )); - } - - // --- Part 4: SharedArrayBuffer NOT removed by inject_globals --- - // SharedArrayBuffer removal is handled by JS bridge code (applyTimingMitigationFreeze), - // not by inject_globals. The bridge bundle depends on SharedArrayBuffer being available - // during initialization. inject_globals stores timing_mitigation in _processConfig - // for the bridge to read. - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - - let process_config = ProcessConfig { - cwd: "/".into(), - env: HashMap::new(), - timing_mitigation: "freeze".into(), - frozen_time_ms: None, - high_resolution_time: false, - }; - let os_config = OsConfig { - homedir: "/root".into(), - tmpdir: "/tmp".into(), - platform: "linux".into(), - arch: "x64".into(), - }; - - { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals(scope, &process_config, &os_config); - } - - // SharedArrayBuffer should still exist — removal is done by JS bridge - assert!(eval_bool( - &mut isolate, - &context, - "typeof SharedArrayBuffer !== 'undefined'" - )); - // timing_mitigation is stored for the bridge to act on - assert_eq!( - eval(&mut isolate, &context, "_processConfig.timing_mitigation"), - "freeze" - ); - } - - // --- Part 5: SharedArrayBuffer preserved when timing_mitigation is 'none' --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - - let process_config = ProcessConfig { - cwd: "/".into(), - env: HashMap::new(), - timing_mitigation: "none".into(), - frozen_time_ms: None, - high_resolution_time: false, - }; - let os_config = OsConfig { - homedir: "/root".into(), - tmpdir: "/tmp".into(), - platform: "linux".into(), - arch: "x64".into(), - }; - - { - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - inject_globals(scope, &process_config, &os_config); - } - - // SharedArrayBuffer should still exist - assert!(eval_bool( - &mut isolate, - &context, - "typeof SharedArrayBuffer !== 'undefined'" - )); - } - - // --- Part 6: Guest WebAssembly compilation stays enabled by default --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - - assert!(!eval_throws( - &mut isolate, - &context, - "new WebAssembly.Module(new Uint8Array([0,97,115,109,1,0,0,0]))" - )); - } - - // --- Part 7: Guest WebAssembly modules can instantiate and execute --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - - let result = eval( - &mut isolate, - &context, - r#" - (function() { - var bytes = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, - 0x03, 0x02, 0x01, 0x00, - 0x07, 0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, - 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b, - ]); - var module = new WebAssembly.Module(bytes); - var instance = new WebAssembly.Instance(module, {}); - return String(instance.exports.add(19, 23)); - })() - "#, - ); - assert_eq!(result, "42"); - } - - // --- Part 8: V8 still enforces its own WebAssembly memory limits --- - { - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - - let limit_report = eval( - &mut isolate, - &context, - r#" - (function() { - function capture(fn) { - try { - fn(); - return "ALLOWED"; - } catch (error) { - return error.name + ":" + error.message; - } - } - - var moduleLimit = capture(function() { - var bytes = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, - 0x05, 0x06, 0x01, 0x01, 0x01, 0x81, 0x80, 0x04, - ]); - new WebAssembly.Module(bytes); - }); - var memoryLimit = capture(function() { - new WebAssembly.Memory({ initial: 1, maximum: 65537 }); - }); - return JSON.stringify({ moduleLimit: moduleLimit, memoryLimit: memoryLimit }); - })() - "#, - ); - - assert!( - limit_report.contains(r#""moduleLimit":"CompileError:"#), - "unexpected module limit report: {limit_report}" - ); - assert!( - limit_report.contains(r#""memoryLimit":"RangeError:"#), - "unexpected memory limit report: {limit_report}" - ); - assert!( - limit_report.contains("65536"), - "unexpected limit report: {limit_report}" - ); - } - - // --- Part 8: Sync bridge call returns value --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - // Prepare BridgeResponse: call_id=1, result="hello world" - let result_v8 = v8_serialize_str(&mut iso, &ctx, "hello world"); - - let mut response_buf = Vec::new(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 0, - payload: result_v8, - }, - ) - .unwrap(); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_sync_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &["_testBridge"], - ); - } - - assert_eq!(eval(&mut iso, &ctx, "_testBridge('arg1')"), "hello world"); - } - - // --- Part 9: Bridge call error throws V8 exception --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let mut response_buf = Vec::new(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 1, - payload: "ENOENT: file not found".as_bytes().to_vec(), - }, - ) - .unwrap(); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_sync_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &["_testBridge"], - ); - } - - assert!(eval_throws(&mut iso, &ctx, "_testBridge('arg')")); - } - - // --- Part 10: Multiple bridge functions with argument passing --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - // Prepare two BridgeResponses (call_id=1 for _fn1, call_id=2 for _fn2) - let r1_bytes = v8_serialize_str(&mut iso, &ctx, "result-one"); - let r2_bytes = v8_serialize_int(&mut iso, &ctx, 42); - - let mut response_buf = Vec::new(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 0, - payload: r1_bytes, - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 2, - status: 0, - payload: r2_bytes, - }, - ) - .unwrap(); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_sync_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &["_fn1", "_fn2"], - ); - } - - assert_eq!(eval(&mut iso, &ctx, "_fn1('x')"), "result-one"); - assert_eq!(eval(&mut iso, &ctx, "_fn2(1, 2, 3)"), "42"); - } - - // --- Part 11: Bridge call with null result returns undefined --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let mut response_buf = Vec::new(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 0, - payload: vec![], - }, - ) - .unwrap(); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_sync_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &["_testBridge"], - ); - } - - assert!(eval_bool(&mut iso, &ctx, "_testBridge() === undefined")); - } - - // --- Part 12: Async bridge call returns pending promise, resolved successfully --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let writer_buf = Arc::new(Mutex::new(Vec::new())); - let bridge_ctx = BridgeCallContext::new( - Box::new(SharedWriter(Arc::clone(&writer_buf))), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - // Call the async function - eval(&mut iso, &ctx, "var _promise = _asyncFn('arg1')"); - - // Verify a BridgeCall was sent - { - let written = writer_buf.lock().unwrap(); - let call = crate::ipc_binary::read_frame(&mut Cursor::new(&*written)).unwrap(); - match call { - crate::ipc_binary::BinaryFrame::BridgeCall { - call_id, method, .. - } => { - assert_eq!(call_id, 1); - assert_eq!(method, "_asyncFn"); - } - _ => panic!("expected BridgeCall"), - } - } - - // Promise should be pending with 1 pending promise - assert_eq!(pending.len(), 1); - assert!(eval_bool(&mut iso, &ctx, "_promise instanceof Promise")); - - // Resolve the promise - let result_v8 = v8_serialize_str(&mut iso, &ctx, "async result"); - - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - bridge::resolve_pending_promise(scope, &pending, 1, 0, Some(result_v8), None) - .unwrap(); - } - - assert_eq!(pending.len(), 0); - - // Verify promise is fulfilled with correct value - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let source = v8::String::new(scope, "_promise").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - let promise = v8::Local::::try_from(result).unwrap(); - assert_eq!(promise.state(), v8::PromiseState::Fulfilled); - assert_eq!( - promise.result(scope).to_rust_string_lossy(scope), - "async result" - ); - } - } - - // --- Part 13: Async bridge call promise rejected on error --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - eval(&mut iso, &ctx, "var _promise = _asyncFn('arg')"); - assert_eq!(pending.len(), 1); - - // Reject the promise - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - bridge::resolve_pending_promise( - scope, - &pending, - 1, - 0, - None, - Some("ENOENT: file not found".into()), - ) - .unwrap(); - } - - assert_eq!(pending.len(), 0); - - // Verify promise is rejected with error - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let source = v8::String::new(scope, "_promise").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - let promise = v8::Local::::try_from(result).unwrap(); - assert_eq!(promise.state(), v8::PromiseState::Rejected); - let rejection = promise.result(scope); - let obj = v8::Local::::try_from(rejection).unwrap(); - let msg_key = v8::String::new(scope, "message").unwrap(); - let msg_val = obj.get(scope, msg_key.into()).unwrap(); - assert_eq!( - msg_val.to_rust_string_lossy(scope), - "ENOENT: file not found" - ); - } - } - - // --- Part 14: Multiple async functions with out-of-order resolution --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_fetch", "_dns"], - ); - } - - eval( - &mut iso, - &ctx, - "var _p1 = _fetch('url'); var _p2 = _dns('host')", - ); - assert_eq!(pending.len(), 2); - - // Resolve in reverse order (p2 first, then p1) - let r2 = v8_serialize_str(&mut iso, &ctx, "dns-result"); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - bridge::resolve_pending_promise(scope, &pending, 2, 0, Some(r2), None).unwrap(); - } - assert_eq!(pending.len(), 1); - - let r1 = v8_serialize_str(&mut iso, &ctx, "fetch-result"); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - bridge::resolve_pending_promise(scope, &pending, 1, 0, Some(r1), None).unwrap(); - } - assert_eq!(pending.len(), 0); - - // Verify both promises fulfilled correctly - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let source = v8::String::new(scope, "_p1").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - let promise = v8::Local::::try_from(result).unwrap(); - assert_eq!(promise.state(), v8::PromiseState::Fulfilled); - assert_eq!( - promise.result(scope).to_rust_string_lossy(scope), - "fetch-result" - ); - - let source = v8::String::new(scope, "_p2").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - let promise = v8::Local::::try_from(result).unwrap(); - assert_eq!(promise.state(), v8::PromiseState::Fulfilled); - assert_eq!( - promise.result(scope).to_rust_string_lossy(scope), - "dns-result" - ); - } - } - - // --- Part 15: Async bridge call with null result resolves to undefined --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - eval(&mut iso, &ctx, "var _promise = _asyncFn()"); - - // Resolve with None (null result) - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - bridge::resolve_pending_promise(scope, &pending, 1, 0, None, None).unwrap(); - } - - // Promise should be fulfilled with undefined - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let source = v8::String::new(scope, "_promise").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - let promise = v8::Local::::try_from(result).unwrap(); - assert_eq!(promise.state(), v8::PromiseState::Fulfilled); - assert!(promise.result(scope).is_undefined()); - } - } - - // --- Part 16: Microtasks flushed after promise resolution --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - // Set up .then handler that sets a global variable - eval( - &mut iso, - &ctx, - "var _thenRan = false; _asyncFn().then(function() { _thenRan = true; })", - ); - - // Before resolution, _thenRan should be false - assert!(eval_bool(&mut iso, &ctx, "_thenRan === false")); - - // Resolve the promise (microtasks flushed inside resolve_pending_promise) - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - bridge::resolve_pending_promise(scope, &pending, 1, 0, None, None).unwrap(); - } - - // After resolution + microtask flush, _thenRan should be true - assert!(eval_bool(&mut iso, &ctx, "_thenRan === true")); - } - - // --- Part 17: CJS execution — successful execution returns exit code 0 --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "", "var x = 1 + 2;", &mut None) - }; - - assert_eq!(code, 0); - assert!(error.is_none()); - // Verify the code actually ran - assert_eq!(eval(&mut iso, &ctx, "x"), "3"); - } - - // --- Part 18: Bridge code IIFE executed before user code --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge = "(function() { globalThis._bridgeReady = true; })()"; - let user = "var _sawBridge = _bridgeReady;"; - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, bridge, user, &mut None) - }; - - assert_eq!(code, 0); - assert!(error.is_none()); - assert!(eval_bool(&mut iso, &ctx, "_sawBridge === true")); - assert!(eval_bool(&mut iso, &ctx, "_bridgeReady === true")); - } - - // --- Part 18b: Rejected async script completion returns structured error --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script( - scope, - "", - "(async function () { throw new Error('async failure'); })()", - &mut None, - ) - }; - - assert_eq!(code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "Error"); - assert_eq!(err.message, "async failure"); - } - - // --- Part 19: SyntaxError in user code returns structured error --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "", "var x = {;", &mut None) - }; - - assert_eq!(code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "SyntaxError"); - assert!(!err.message.is_empty()); - } - - // --- Part 20: Runtime TypeError returns structured error --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "", "null.foo", &mut None) - }; - - assert_eq!(code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "TypeError"); - assert!(!err.message.is_empty()); - assert!(!err.stack.is_empty()); - } - - // --- Part 21: SyntaxError in bridge code returns error --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "function {", "var x = 1;", &mut None) - }; - - assert_eq!(code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "SyntaxError"); - // User code should NOT have run - assert!(eval_bool(&mut iso, &ctx, "typeof x === 'undefined'")); - } - - // --- Part 22: Empty bridge code is skipped --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "", "'hello'", &mut None) - }; - - assert_eq!(code, 0); - assert!(error.is_none()); - } - - // --- Part 23: Runtime error with error code --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script( - scope, - "", - "var e = new Error('not found'); e.code = 'ERR_MODULE_NOT_FOUND'; throw e;", - &mut None, - ) - }; - - assert_eq!(code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "Error"); - assert_eq!(err.message, "not found"); - assert_eq!(err.code, Some("ERR_MODULE_NOT_FOUND".into())); - } - - // --- Part 24: Thrown string (non-Error object) handled --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "", "throw 'raw string error';", &mut None) - }; - - assert_eq!(code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "Error"); - assert_eq!(err.message, "raw string error"); - assert!(err.stack.is_empty()); - assert!(err.code.is_none()); - } - - // --- Part 25: ESM — simple module with exports --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - - let user_code = "export const x = 42;\nexport const msg = 'hello';"; - let (code, exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module(scope, &bridge_ctx, "", user_code, None, &mut None) - }; - - assert_eq!(code, 0); - assert!(error.is_none()); - let exports = exports.unwrap(); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = crate::bridge::deserialize_v8_value(scope, &exports).unwrap(); - assert!(val.is_object()); - let obj = v8::Local::::try_from(val).unwrap(); - let k = v8::String::new(scope, "x").unwrap(); - assert_eq!( - obj.get(scope, k.into()) - .unwrap() - .int32_value(scope) - .unwrap(), - 42 - ); - let k = v8::String::new(scope, "msg").unwrap(); - assert_eq!( - obj.get(scope, k.into()) - .unwrap() - .to_rust_string_lossy(scope), - "hello" - ); - } - } - - // --- Part 25a: ESM root modules receive fetch globals from the runtime prelude --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - - let bridge_code = r#" - globalThis.fetch = async function () { return "ok"; }; - "#; - let user_code = r#" - const result = await fetch(); - export const fetchType = typeof fetch; - export default result; - "#; - let (code, exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module(scope, &bridge_ctx, bridge_code, user_code, None, &mut None) - }; - - assert_eq!(code, 0, "error: {:?}", error); - assert!(error.is_none()); - let exports = exports.unwrap(); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = crate::bridge::deserialize_v8_value(scope, &exports).unwrap(); - let obj = v8::Local::::try_from(val).unwrap(); - - let fetch_type_key = v8::String::new(scope, "fetchType").unwrap(); - assert_eq!( - obj.get(scope, fetch_type_key.into()) - .unwrap() - .to_rust_string_lossy(scope), - "function" - ); - - let default_key = v8::String::new(scope, "default").unwrap(); - assert_eq!( - obj.get(scope, default_key.into()) - .unwrap() - .to_rust_string_lossy(scope), - "ok" - ); - } - } - - // --- Part 26: ESM — default export --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - - let (code, exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - "", - "export default 'world';", - None, - &mut None, - ) - }; - - assert_eq!(code, 0); - assert!(error.is_none()); - let exports = exports.unwrap(); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = crate::bridge::deserialize_v8_value(scope, &exports).unwrap(); - assert!(val.is_object()); - let obj = v8::Local::::try_from(val).unwrap(); - let k = v8::String::new(scope, "default").unwrap(); - assert_eq!( - obj.get(scope, k.into()) - .unwrap() - .to_rust_string_lossy(scope), - "world" - ); - } - } - - // --- Part 27: ESM — SyntaxError --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - - let (code, _exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - "", - "export const x = {;", - None, - &mut None, - ) - }; - - assert_eq!(code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "SyntaxError"); - } - - // --- Part 28: ESM — runtime TypeError --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - - let (code, _exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - "", - "const x = null; x.foo;", - None, - &mut None, - ) - }; - - assert_eq!(code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "TypeError"); - } - - // --- Part 29: ESM — bridge code IIFE runs before module --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - - let bridge = "(function() { globalThis._bridgeReady = true; })()"; - let user = "export const saw = _bridgeReady;"; - let (code, exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module(scope, &bridge_ctx, bridge, user, None, &mut None) - }; - - assert_eq!(code, 0); - assert!(error.is_none()); - let exports = exports.unwrap(); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = crate::bridge::deserialize_v8_value(scope, &exports).unwrap(); - assert!(val.is_object()); - let obj = v8::Local::::try_from(val).unwrap(); - let k = v8::String::new(scope, "saw").unwrap(); - assert!(obj.get(scope, k.into()).unwrap().is_true()); - } - } - - // --- Part 30: ESM — import from dependency via batch resolve --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - // Prepare BridgeResponse for _batchResolveModules (batch prefetch). - // The batch call (call_id=1) returns an array of {resolved, source}. - let mut response_buf = Vec::new(); - - let batch_result = v8_serialize_eval( - &mut iso, - &ctx, - "[{resolved: '/dep.mjs', source: 'export const dep_val = 99;'}]", - ); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 0, - payload: batch_result, - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 2, - status: 0, - payload: v8_serialize_str(&mut iso, &ctx, "module"), - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 3, - status: 0, - payload: v8_serialize_str(&mut iso, &ctx, "module"), - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 2, - status: 0, - payload: v8_serialize_str(&mut iso, &ctx, "module"), - }, - ) - .unwrap(); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let user_code = - "import { dep_val } from './dep.mjs';\nexport const result = dep_val + 1;"; - let (code, exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - "", - user_code, - Some("/app/main.mjs"), - &mut None, - ) - }; - - assert_eq!(code, 0, "error: {:?}", error); - assert!(error.is_none()); - let exports = exports.unwrap(); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = crate::bridge::deserialize_v8_value(scope, &exports).unwrap(); - assert!(val.is_object()); - let obj = v8::Local::::try_from(val).unwrap(); - let k = v8::String::new(scope, "result").unwrap(); - assert_eq!( - obj.get(scope, k.into()) - .unwrap() - .int32_value(scope) - .unwrap(), - 100 - ); - } - } - - // --- Part 31: Event loop — BridgeResponse resolves pending promise --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - // Register async bridge function - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - // Call async function from V8 — creates pending promise - eval( - &mut iso, - &ctx, - "var _eventLoopResult = 'pending'; _asyncFn('test').then(function(v) { _eventLoopResult = v; })", - ); - assert_eq!(pending.len(), 1); - assert_eq!(eval(&mut iso, &ctx, "_eventLoopResult"), "pending"); - - // Create channel and send BridgeResponse - let (tx, rx) = crossbeam_channel::unbounded(); - let result_v8 = v8_serialize_str(&mut iso, &ctx, "event-loop-resolved"); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 1, - status: 0, - payload: result_v8, - }, - ), - )) - .unwrap(); - - // Run event loop - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!( - matches!(completed, crate::session::EventLoopStatus::Completed), - "event loop should complete normally" - ); - assert_eq!(pending.len(), 0); - assert_eq!( - eval(&mut iso, &ctx, "_eventLoopResult"), - "event-loop-resolved" - ); - } - - // --- Part 32: Event loop — multiple BridgeResponses resolved in sequence --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_fetch", "_dns"], - ); - } - - // Create two pending promises - eval( - &mut iso, - &ctx, - "var _r1 = 'pending'; var _r2 = 'pending'; \ - _fetch('url').then(function(v) { _r1 = v; }); \ - _dns('host').then(function(v) { _r2 = v; })", - ); - assert_eq!(pending.len(), 2); - - // Create channel and send both responses - let (tx, rx) = crossbeam_channel::unbounded(); - // Resolve in reverse order - let r2 = v8_serialize_str(&mut iso, &ctx, "dns-result"); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 2, - status: 0, - payload: r2, - }, - ), - )) - .unwrap(); - let r1 = v8_serialize_str(&mut iso, &ctx, "fetch-result"); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 1, - status: 0, - payload: r1, - }, - ), - )) - .unwrap(); - - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!(matches!( - completed, - crate::session::EventLoopStatus::Completed - )); - assert_eq!(pending.len(), 0); - assert_eq!(eval(&mut iso, &ctx, "_r1"), "fetch-result"); - assert_eq!(eval(&mut iso, &ctx, "_r2"), "dns-result"); - } - - // --- Part 33: Event loop — TerminateExecution breaks loop --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - eval(&mut iso, &ctx, "_asyncFn('test')"); - assert_eq!(pending.len(), 1); - - // Send TerminateExecution - let (tx, rx) = crossbeam_channel::unbounded(); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::TerminateExecution, - )) - .unwrap(); - - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!( - matches!(completed, crate::session::EventLoopStatus::Terminated), - "event loop should return terminated status on termination" - ); - // Promise is still pending (not resolved) - assert_eq!(pending.len(), 1); - - // Cancel termination so isolate is usable again - iso.cancel_terminate_execution(); - } - - // --- Part 34: Event loop — Shutdown breaks loop --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - eval(&mut iso, &ctx, "_asyncFn('test')"); - assert_eq!(pending.len(), 1); - - // Send Shutdown - let (tx, rx) = crossbeam_channel::unbounded(); - tx.send(crate::session::SessionCommand::Shutdown).unwrap(); - - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!( - matches!(completed, crate::session::EventLoopStatus::Terminated), - "event loop should return terminated status on shutdown" - ); - } - - // --- Part 35: Event loop — exits immediately when no pending promises --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let pending = bridge::PendingPromises::new(); - - let (_tx, rx) = crossbeam_channel::unbounded::(); - - // No pending promises — event loop should exit immediately - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!(matches!( - completed, - crate::session::EventLoopStatus::Completed - )); - } - - // --- Part 36: Event loop — StreamEvent dispatches to V8 callback --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - // Register dispatch callback and create pending promise - eval( - &mut iso, - &ctx, - "var _streamEvents = []; \ - globalThis._childProcessDispatch = function(eventType, payload) { \ - _streamEvents.push({ type: eventType, data: payload }); \ - }; \ - _asyncFn('keep-alive')", - ); - assert_eq!(pending.len(), 1); - - // Send StreamEvent followed by BridgeResponse - let (tx, rx) = crossbeam_channel::unbounded(); - - // Encode payload as V8-serialized string - let payload_bytes = v8_serialize_str(&mut iso, &ctx, "hello from child"); - - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::StreamEvent( - crate::runtime_protocol::StreamEvent { - event_type: "child_stdout".into(), - payload: payload_bytes, - }, - ), - )) - .unwrap(); - - // Resolve the pending promise to exit the event loop - let r = v8_serialize_null(&mut iso, &ctx); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 1, - status: 0, - payload: r, - }, - ), - )) - .unwrap(); - - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!(matches!( - completed, - crate::session::EventLoopStatus::Completed - )); - assert_eq!(pending.len(), 0); - - // Verify stream event was dispatched - assert_eq!(eval(&mut iso, &ctx, "_streamEvents.length"), "1"); - assert_eq!( - eval(&mut iso, &ctx, "_streamEvents[0].type"), - "child_stdout" - ); - assert_eq!( - eval(&mut iso, &ctx, "_streamEvents[0].data"), - "hello from child" - ); - } - - // --- Part 37: Event loop — microtasks flushed after BridgeResponse --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - // Set up .then handler that mutates global state - eval( - &mut iso, - &ctx, - "var _microtaskRan = false; \ - _asyncFn('test').then(function() { _microtaskRan = true; })", - ); - assert!(eval_bool(&mut iso, &ctx, "_microtaskRan === false")); - - let (tx, rx) = crossbeam_channel::unbounded(); - let r = v8_serialize_null(&mut iso, &ctx); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 1, - status: 0, - payload: r, - }, - ), - )) - .unwrap(); - - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None); - } - - // .then handler should have run (microtasks flushed) - assert!(eval_bool(&mut iso, &ctx, "_microtaskRan === true")); - } - - // --- Part 38: StreamEvent dispatches child_stderr and child_exit --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - // Register child process dispatch and create pending promise - eval( - &mut iso, - &ctx, - "var _childEvents = []; \ - globalThis._childProcessDispatch = function(eventType, payload) { \ - _childEvents.push({ type: eventType, data: payload }); \ - }; \ - _asyncFn('keep-alive')", - ); - assert_eq!(pending.len(), 1); - - let (tx, rx) = crossbeam_channel::unbounded(); - - // Send child_stderr event - let stderr_payload = v8_serialize_str(&mut iso, &ctx, "error output"); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::StreamEvent( - crate::runtime_protocol::StreamEvent { - event_type: "child_stderr".into(), - payload: stderr_payload, - }, - ), - )) - .unwrap(); - - // Send child_exit event with exit code - let exit_payload = v8_serialize_int(&mut iso, &ctx, 1); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::StreamEvent( - crate::runtime_protocol::StreamEvent { - event_type: "child_exit".into(), - payload: exit_payload, - }, - ), - )) - .unwrap(); - - // Resolve the pending promise to exit the event loop - let r = v8_serialize_null(&mut iso, &ctx); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 1, - status: 0, - payload: r, - }, - ), - )) - .unwrap(); - - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!(matches!( - completed, - crate::session::EventLoopStatus::Completed - )); - assert_eq!(eval(&mut iso, &ctx, "_childEvents.length"), "2"); - assert_eq!(eval(&mut iso, &ctx, "_childEvents[0].type"), "child_stderr"); - assert_eq!(eval(&mut iso, &ctx, "_childEvents[0].data"), "error output"); - assert_eq!(eval(&mut iso, &ctx, "_childEvents[1].type"), "child_exit"); - assert_eq!(eval(&mut iso, &ctx, "_childEvents[1].data"), "1"); - } - - // --- Part 39: StreamEvent dispatches http_request to _httpServerDispatch --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - // Register HTTP dispatch and create pending promise - eval( - &mut iso, - &ctx, - "var _httpEvents = []; \ - globalThis._httpServerDispatch = function(eventType, payload) { \ - _httpEvents.push({ type: eventType, data: payload }); \ - }; \ - _asyncFn('keep-alive')", - ); - assert_eq!(pending.len(), 1); - - let (tx, rx) = crossbeam_channel::unbounded(); - - // Send http_request event with request data - let http_payload = - v8_serialize_eval(&mut iso, &ctx, "({method: 'GET', url: '/api/test'})"); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::StreamEvent( - crate::runtime_protocol::StreamEvent { - event_type: "http_request".into(), - payload: http_payload, - }, - ), - )) - .unwrap(); - - // Resolve the pending promise to exit the event loop - let r = v8_serialize_null(&mut iso, &ctx); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 1, - status: 0, - payload: r, - }, - ), - )) - .unwrap(); - - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!(matches!( - completed, - crate::session::EventLoopStatus::Completed - )); - assert_eq!(eval(&mut iso, &ctx, "_httpEvents.length"), "1"); - assert_eq!(eval(&mut iso, &ctx, "_httpEvents[0].type"), "http_request"); - assert_eq!(eval(&mut iso, &ctx, "_httpEvents[0].data.method"), "GET"); - assert_eq!(eval(&mut iso, &ctx, "_httpEvents[0].data.url"), "/api/test"); - } - - // --- Part 40: StreamEvent with unknown event_type is ignored --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - eval( - &mut iso, - &ctx, - "var _anyDispatched = false; \ - globalThis._childProcessDispatch = function() { _anyDispatched = true; }; \ - globalThis._httpServerDispatch = function() { _anyDispatched = true; }; \ - _asyncFn('keep-alive')", - ); - assert_eq!(pending.len(), 1); - - let (tx, rx) = crossbeam_channel::unbounded(); - - // Send unknown event type - let payload = v8_serialize_null(&mut iso, &ctx); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::StreamEvent( - crate::runtime_protocol::StreamEvent { - event_type: "unknown_event".into(), - payload, - }, - ), - )) - .unwrap(); - - // Resolve pending promise to exit loop - let r = v8_serialize_null(&mut iso, &ctx); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 1, - status: 0, - payload: r, - }, - ), - )) - .unwrap(); - - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!(matches!( - completed, - crate::session::EventLoopStatus::Completed - )); - // Unknown event should NOT have dispatched to any handler - assert!(eval_bool(&mut iso, &ctx, "_anyDispatched === false")); - } - - // --- Part 41: StreamEvent dispatch with missing callback is safe (no crash) --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - // No dispatch functions registered, just create a pending promise - eval(&mut iso, &ctx, "_asyncFn('keep-alive')"); - assert_eq!(pending.len(), 1); - - let (tx, rx) = crossbeam_channel::unbounded(); - - // Send child_stdout without _childProcessDispatch registered - let payload = v8_serialize_str(&mut iso, &ctx, "data"); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::StreamEvent( - crate::runtime_protocol::StreamEvent { - event_type: "child_stdout".into(), - payload, - }, - ), - )) - .unwrap(); - - // Resolve pending promise - let r = v8_serialize_null(&mut iso, &ctx); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 1, - status: 0, - payload: r, - }, - ), - )) - .unwrap(); - - // Should not crash even without dispatch function registered - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None) - }; - - assert!(matches!( - completed, - crate::session::EventLoopStatus::Completed - )); - } - - // --- Part 42: StreamEvent microtasks flushed after dispatch --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - let pending = bridge::PendingPromises::new(); - - let _fn_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _fn_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_asyncFn"], - ); - } - - // Set up dispatch that enqueues a microtask via Promise.resolve().then() - eval( - &mut iso, - &ctx, - "var _microtaskRanFromStream = false; \ - globalThis._childProcessDispatch = function(eventType, payload) { \ - Promise.resolve().then(function() { _microtaskRanFromStream = true; }); \ - }; \ - _asyncFn('keep-alive')", - ); - assert_eq!(pending.len(), 1); - - let (tx, rx) = crossbeam_channel::unbounded(); - - let payload = v8_serialize_str(&mut iso, &ctx, "data"); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::StreamEvent( - crate::runtime_protocol::StreamEvent { - event_type: "child_stdout".into(), - payload, - }, - ), - )) - .unwrap(); - - // Resolve pending promise - let r = v8_serialize_null(&mut iso, &ctx); - tx.send(crate::session::SessionCommand::Message( - crate::runtime_protocol::SessionMessage::BridgeResponse( - crate::runtime_protocol::BridgeResponse { - call_id: 1, - status: 0, - payload: r, - }, - ), - )) - .unwrap(); - - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &rx, &pending, None, None); - } - - // Microtask enqueued by the dispatch callback should have run - assert!(eval_bool( - &mut iso, - &ctx, - "_microtaskRanFromStream === true" - )); - } - - // --- Part 43: Timeout terminates infinite loop --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - // Create abort channel for timeout - let (abort_tx, _abort_rx) = crossbeam_channel::bounded::<()>(0); - - // Get isolate handle for the timeout guard - let iso_handle = iso.thread_safe_handle(); - - // Start a 50ms timeout - let mut guard = crate::timeout::TimeoutGuard::new(50, iso_handle, abort_tx) - .expect("timeout guard should start"); - - // Run an infinite loop — timeout should terminate it - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "", "while(true) {}", &mut None) - }; - - assert!(guard.timed_out(), "timeout should have fired"); - // V8 termination causes an error - assert_eq!(code, 1); - assert!(error.is_some()); - - guard.cancel(); - } - - // --- Part 44: Timeout cancelled when execution completes before deadline --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let (abort_tx, _abort_rx) = crossbeam_channel::bounded::<()>(0); - let iso_handle = iso.thread_safe_handle(); - - // 5 second timeout — execution completes well before - let mut guard = crate::timeout::TimeoutGuard::new(5000, iso_handle, abort_tx) - .expect("timeout guard should start"); - - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "", "1 + 1", &mut None) - }; - - assert!(!guard.timed_out(), "timeout should not have fired"); - assert_eq!(code, 0); - assert!(error.is_none()); - - guard.cancel(); - } - - // --- Part 45: Timeout fires during sync bridge call (unblocks channel reader) --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - // Set up abort channel for timeout - let (abort_tx, abort_rx) = crossbeam_channel::bounded::<()>(0); - let iso_handle = iso.thread_safe_handle(); - - // Create a BridgeCallContext with a channel reader that monitors abort_rx - // Simulate: JS calls a sync bridge function, but no response comes back. - // The timeout should unblock the reader via abort channel. - let (cmd_tx, cmd_rx) = crossbeam_channel::unbounded::(); - - // Writer goes to a buffer (we don't care about outgoing messages) - let writer_buf = Arc::new(Mutex::new(Vec::new())); - - // Create the bridge context with a channel-based reader - // We can't use ChannelMessageReader directly (it's #[cfg(not(test))]) - // Instead, test the abort_rx behavior through run_event_loop - - let pending = bridge::PendingPromises::new(); - - // Register an async bridge function that sends a BridgeCall - let bridge_ctx = BridgeCallContext::new( - Box::new(SharedWriter(Arc::clone(&writer_buf))), - Box::new(Cursor::new(Vec::new())), // unused for async - "test-session".into(), - ); - let _async_store; - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - _async_store = bridge::register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - &["_slowFn"], - ); - } - - // Execute code that calls async bridge function (creates a pending promise) - let (_code, _error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "", "_slowFn('never-responds')", &mut None) - }; - - assert_eq!(pending.len(), 1, "should have 1 pending promise"); - - // Start a 50ms timeout - let mut guard = crate::timeout::TimeoutGuard::new(50, iso_handle, abort_tx) - .expect("timeout guard should start"); - - // Run event loop — it should be terminated by the timeout - // (no messages on cmd_rx, so it blocks until abort_rx fires) - let completed = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - crate::session::run_event_loop(scope, &cmd_rx, &pending, Some(&abort_rx), None) - }; - - assert!( - matches!(completed, crate::session::EventLoopStatus::Terminated), - "event loop should have been terminated" - ); - assert!(guard.timed_out(), "timeout should have fired"); - - guard.cancel(); - drop(cmd_tx); // clean up - } - - // --- Part 46: Timeout error message structure --- - { - // Verify that the timeout error produced by the session matches expectations. - // This tests the ipc::ExecutionError structure, not V8 directly. - let err = crate::ipc::ExecutionError { - error_type: "Error".into(), - message: "Script execution timed out".into(), - stack: String::new(), - code: Some("ERR_SCRIPT_EXECUTION_TIMEOUT".into()), - }; - assert_eq!(err.error_type, "Error"); - assert_eq!(err.message, "Script execution timed out"); - assert_eq!(err.code, Some("ERR_SCRIPT_EXECUTION_TIMEOUT".into())); - } - - // --- Part 47: ProcessExitError detected via _isProcessExit sentinel --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // Simulate ProcessExitError: an Error object with _isProcessExit: true and code: 42 - let code = r#" - var err = new Error("process.exit(42)"); - err._isProcessExit = true; - err.code = 42; - throw err; - "#; - - let (exit_code, error) = execute_script(scope, "", code, &mut None); - assert_eq!( - exit_code, 42, - "ProcessExitError should return the error's exit code" - ); - let err = error.unwrap(); - assert_eq!(err.error_type, "Error"); - assert!(err.message.contains("process.exit(42)")); - // Numeric .code should NOT appear in the string code field - assert_eq!(err.code, None); - } - - // --- Part 48: ProcessExitError with exit code 0 --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let code = r#" - var err = new Error("process.exit(0)"); - err._isProcessExit = true; - err.code = 0; - throw err; - "#; - - let (exit_code, error) = execute_script(scope, "", code, &mut None); - assert_eq!( - exit_code, 0, - "ProcessExitError code 0 should return exit code 0" - ); - assert!(error.is_some()); - } - - // --- Part 49: Non-ProcessExitError returns exit code 1 --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // Regular error without _isProcessExit sentinel - let code = r#"throw new TypeError("not a process exit")"#; - - let (exit_code, error) = execute_script(scope, "", code, &mut None); - assert_eq!(exit_code, 1, "Regular errors should return exit code 1"); - let err = error.unwrap(); - assert_eq!(err.error_type, "TypeError"); - assert_eq!(err.message, "not a process exit"); - } - - // --- Part 50: ProcessExitError with custom constructor name --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // Custom ProcessExitError class - let code = r#" - class ProcessExitError extends Error { - constructor(exitCode) { - super("process exited with code " + exitCode); - this._isProcessExit = true; - this.code = exitCode; - } - } - throw new ProcessExitError(7); - "#; - - let (exit_code, error) = execute_script(scope, "", code, &mut None); - assert_eq!(exit_code, 7); - let err = error.unwrap(); - assert_eq!(err.error_type, "ProcessExitError"); - assert!(err.message.contains("process exited with code 7")); - } - - // --- Part 51: extract_process_exit_code returns None for non-objects --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // Thrown string — not an object, should not be detected as ProcessExitError - let code = r#"throw "just a string""#; - let (exit_code, error) = execute_script(scope, "", code, &mut None); - assert_eq!(exit_code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "Error"); - assert_eq!(err.message, "just a string"); - - // Object without _isProcessExit sentinel - let code2 = r#" - var obj = new Error("no sentinel"); - obj._isProcessExit = false; - obj.code = 99; - throw obj; - "#; - let (exit_code2, error2) = execute_script(scope, "", code2, &mut None); - assert_eq!(exit_code2, 1, "_isProcessExit:false should not be detected"); - assert!(error2.is_some()); - } - - // --- Part 52: Error with string code field (Node-style) preserved --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let code = r#" - var err = new Error("Cannot find module './missing'"); - err.code = "ERR_MODULE_NOT_FOUND"; - throw err; - "#; - - let (exit_code, error) = execute_script(scope, "", code, &mut None); - assert_eq!(exit_code, 1); - let err = error.unwrap(); - assert_eq!(err.error_type, "Error"); - assert_eq!(err.code, Some("ERR_MODULE_NOT_FOUND".into())); - } - - // --- Part 53: Error type from constructor name for standard errors --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // SyntaxError - let (_, err) = execute_script(scope, "", "eval('function(')", &mut None); - let err = err.unwrap(); - assert_eq!(err.error_type, "SyntaxError"); - - // RangeError - let (_, err2) = execute_script(scope, "", "new Array(-1)", &mut None); - let err2 = err2.unwrap(); - assert_eq!(err2.error_type, "RangeError"); - - // ReferenceError - let (_, err3) = execute_script(scope, "", "undefinedVariable", &mut None); - let err3 = err3.unwrap(); - assert_eq!(err3.error_type, "ReferenceError"); - } - - // --- Part 54: process.exitCode is honored for synchronous completion --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script( - scope, - "", - "globalThis.process = { exitCode: 0 };", - &mut None, - ); - - let (exit_code, error) = execute_script(scope, "", "process.exitCode = 3;", &mut None); - assert_eq!(exit_code, 3); - assert!(error.is_none()); - } - - // --- Part 55: process.exitCode is honored for fulfilled async completion --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script( - scope, - "", - "globalThis.process = { exitCode: 0 };", - &mut None, - ); - - let (exit_code, error) = execute_script( - scope, - "", - "(async () => { process.exitCode = 4; })()", - &mut None, - ); - assert_eq!(exit_code, 4); - assert!(error.is_none()); - } - - // --- Part 54: Stack trace extracted from error.stack property --- - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let code = r#" - function innerFn() { throw new Error("deep error"); } - function outerFn() { innerFn(); } - outerFn(); - "#; - - let (_, error) = execute_script(scope, "", code, &mut None); - let err = error.unwrap(); - assert_eq!(err.error_type, "Error"); - assert_eq!(err.message, "deep error"); - assert!( - err.stack.contains("innerFn"), - "stack should contain innerFn" - ); - assert!( - err.stack.contains("outerFn"), - "stack should contain outerFn" - ); - } - - // --- V8 ValueSerializer/ValueDeserializer round-trip tests --- - - // Part 55: Primitives round-trip (null, undefined, true, false, integers, floats) - { - use crate::bridge::{ - deserialize_v8_wire_value as deserialize_v8_value, - serialize_v8_wire_value as serialize_v8_value, - }; - - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // null - let null_val = v8::null(scope).into(); - let bytes = serialize_v8_value(scope, null_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_null()); - - // undefined - let undef_val = v8::undefined(scope).into(); - let bytes = serialize_v8_value(scope, undef_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_undefined()); - - // true - let bool_val = v8::Boolean::new(scope, true).into(); - let bytes = serialize_v8_value(scope, bool_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_true()); - - // false - let bool_val = v8::Boolean::new(scope, false).into(); - let bytes = serialize_v8_value(scope, bool_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_false()); - - // integer - let num_val: v8::Local = v8::Integer::new(scope, 42).into(); - let bytes = serialize_v8_value(scope, num_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert_eq!(out.int32_value(scope).unwrap(), 42); - - // negative integer - let num_val: v8::Local = v8::Integer::new(scope, -7).into(); - let bytes = serialize_v8_value(scope, num_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert_eq!(out.int32_value(scope).unwrap(), -7); - - // float - let num_val: v8::Local = v8::Number::new(scope, 3.125).into(); - let bytes = serialize_v8_value(scope, num_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!((out.number_value(scope).unwrap() - 3.125).abs() < 1e-10); - } - - // Part 56: Strings round-trip - { - use crate::bridge::{ - deserialize_v8_wire_value as deserialize_v8_value, - serialize_v8_wire_value as serialize_v8_value, - }; - - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // ASCII string - let s = v8::String::new(scope, "hello world").unwrap(); - let bytes = serialize_v8_value(scope, s.into()).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_string()); - assert_eq!(out.to_rust_string_lossy(scope), "hello world"); - - // Empty string - let s = v8::String::new(scope, "").unwrap(); - let bytes = serialize_v8_value(scope, s.into()).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_string()); - assert_eq!(out.to_rust_string_lossy(scope), ""); - - // Unicode string - let s = v8::String::new(scope, "hello 🌍 world").unwrap(); - let bytes = serialize_v8_value(scope, s.into()).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert_eq!(out.to_rust_string_lossy(scope), "hello 🌍 world"); - } - - // Part 57: Arrays round-trip - { - use crate::bridge::{ - deserialize_v8_wire_value as deserialize_v8_value, - serialize_v8_wire_value as serialize_v8_value, - }; - - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // [1, "two", true, null] - let arr = v8::Array::new(scope, 4); - let v1: v8::Local = v8::Integer::new(scope, 1).into(); - let v2: v8::Local = v8::String::new(scope, "two").unwrap().into(); - let v3: v8::Local = v8::Boolean::new(scope, true).into(); - let v4: v8::Local = v8::null(scope).into(); - arr.set_index(scope, 0, v1); - arr.set_index(scope, 1, v2); - arr.set_index(scope, 2, v3); - arr.set_index(scope, 3, v4); - - let bytes = serialize_v8_value(scope, arr.into()).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_array()); - let out_arr = v8::Local::::try_from(out).unwrap(); - assert_eq!(out_arr.length(), 4); - assert_eq!( - out_arr - .get_index(scope, 0) - .unwrap() - .int32_value(scope) - .unwrap(), - 1 - ); - assert_eq!( - out_arr - .get_index(scope, 1) - .unwrap() - .to_rust_string_lossy(scope), - "two" - ); - assert!(out_arr.get_index(scope, 2).unwrap().is_true()); - assert!(out_arr.get_index(scope, 3).unwrap().is_null()); - - // Empty array - let empty_arr = v8::Array::new(scope, 0); - let bytes = serialize_v8_value(scope, empty_arr.into()).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_array()); - assert_eq!(v8::Local::::try_from(out).unwrap().length(), 0); - } - - // Part 58: Objects round-trip - { - use crate::bridge::{ - deserialize_v8_wire_value as deserialize_v8_value, - serialize_v8_wire_value as serialize_v8_value, - }; - - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // { name: "test", count: 42, active: true } - let obj = v8::Object::new(scope); - let k1 = v8::String::new(scope, "name").unwrap(); - let v1: v8::Local = v8::String::new(scope, "test").unwrap().into(); - let k2 = v8::String::new(scope, "count").unwrap(); - let v2: v8::Local = v8::Integer::new(scope, 42).into(); - let k3 = v8::String::new(scope, "active").unwrap(); - let v3: v8::Local = v8::Boolean::new(scope, true).into(); - obj.set(scope, k1.into(), v1); - obj.set(scope, k2.into(), v2); - obj.set(scope, k3.into(), v3); - - let bytes = serialize_v8_value(scope, obj.into()).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_object()); - let out_obj = v8::Local::::try_from(out).unwrap(); - let k = v8::String::new(scope, "name").unwrap(); - assert_eq!( - out_obj - .get(scope, k.into()) - .unwrap() - .to_rust_string_lossy(scope), - "test" - ); - let k = v8::String::new(scope, "count").unwrap(); - assert_eq!( - out_obj - .get(scope, k.into()) - .unwrap() - .int32_value(scope) - .unwrap(), - 42 - ); - let k = v8::String::new(scope, "active").unwrap(); - assert!(out_obj.get(scope, k.into()).unwrap().is_true()); - } - - // Part 59: Uint8Array round-trip - { - use crate::bridge::{ - deserialize_v8_wire_value as deserialize_v8_value, - serialize_v8_wire_value as serialize_v8_value, - }; - - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let data = [0u8, 1, 2, 255, 128, 64]; - let ab = v8::ArrayBuffer::new(scope, data.len()); - { - let bs = ab.get_backing_store(); - unsafe { - std::ptr::copy_nonoverlapping( - data.as_ptr(), - bs.data().unwrap().as_ptr() as *mut u8, - data.len(), - ); - } - } - let u8arr = v8::Uint8Array::new(scope, ab, 0, data.len()).unwrap(); - - let bytes = serialize_v8_value(scope, u8arr.into()).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_uint8_array()); - let out_arr = v8::Local::::try_from(out).unwrap(); - assert_eq!(out_arr.byte_length(), 6); - let mut buf = vec![0u8; 6]; - out_arr.copy_contents(&mut buf); - assert_eq!(buf, vec![0, 1, 2, 255, 128, 64]); - } - - // Part 60: Nested structures round-trip - { - use crate::bridge::{ - deserialize_v8_wire_value as deserialize_v8_value, - serialize_v8_wire_value as serialize_v8_value, - }; - - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // Build via JS: { items: [1, { nested: "value" }], flag: false } - let code = r#" - ({ - items: [1, { nested: "value" }], - flag: false - }) - "#; - let source = v8::String::new(scope, code).unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let val = script.run(scope).unwrap(); - - let bytes = serialize_v8_value(scope, val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_object()); - let out_obj = v8::Local::::try_from(out).unwrap(); - - // Check items array - let k = v8::String::new(scope, "items").unwrap(); - let items = out_obj.get(scope, k.into()).unwrap(); - assert!(items.is_array()); - let items_arr = v8::Local::::try_from(items).unwrap(); - assert_eq!(items_arr.length(), 2); - assert_eq!( - items_arr - .get_index(scope, 0) - .unwrap() - .int32_value(scope) - .unwrap(), - 1 - ); - let inner = items_arr.get_index(scope, 1).unwrap(); - assert!(inner.is_object()); - let inner_obj = v8::Local::::try_from(inner).unwrap(); - let k = v8::String::new(scope, "nested").unwrap(); - assert_eq!( - inner_obj - .get(scope, k.into()) - .unwrap() - .to_rust_string_lossy(scope), - "value" - ); - - // Check flag - let k = v8::String::new(scope, "flag").unwrap(); - assert!(out_obj.get(scope, k.into()).unwrap().is_false()); - } - - // Part 61: Date, RegExp, Map, Set, Error round-trip via JS eval - { - use crate::bridge::{ - deserialize_v8_wire_value as deserialize_v8_value, - serialize_v8_wire_value as serialize_v8_value, - }; - - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // Date - let source = v8::String::new(scope, "new Date(1700000000000)").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let date_val = script.run(scope).unwrap(); - let bytes = serialize_v8_value(scope, date_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_date()); - let date = v8::Local::::try_from(out).unwrap(); - assert_eq!(date.value_of(), 1700000000000.0); - - // RegExp - let source = v8::String::new(scope, "/abc/gi").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let re_val = script.run(scope).unwrap(); - let bytes = serialize_v8_value(scope, re_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_reg_exp()); - - // Map - let source = v8::String::new(scope, "new Map([['a', 1], ['b', 2]])").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let map_val = script.run(scope).unwrap(); - let bytes = serialize_v8_value(scope, map_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_map()); - let map = v8::Local::::try_from(out).unwrap(); - assert_eq!(map.size(), 2); - - // Set - let source = v8::String::new(scope, "new Set([10, 20, 30])").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let set_val = script.run(scope).unwrap(); - let bytes = serialize_v8_value(scope, set_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_set()); - let set = v8::Local::::try_from(out).unwrap(); - assert_eq!(set.size(), 3); - - // Error - let source = v8::String::new(scope, "new TypeError('oops')").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let err_val = script.run(scope).unwrap(); - let bytes = serialize_v8_value(scope, err_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - // Error is serialized as a plain object with message property - assert!(out.is_object()); - let out_obj = v8::Local::::try_from(out).unwrap(); - let k = v8::String::new(scope, "message").unwrap(); - let msg = out_obj.get(scope, k.into()).unwrap(); - assert_eq!(msg.to_rust_string_lossy(scope), "oops"); - } - - // Part 62: Circular references round-trip - { - use crate::bridge::{ - deserialize_v8_wire_value as deserialize_v8_value, - serialize_v8_wire_value as serialize_v8_value, - }; - - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - // Build circular reference via JS - let source = v8::String::new(scope, "var o = { a: 1 }; o.self = o; o").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let circ_val = script.run(scope).unwrap(); - - let bytes = serialize_v8_value(scope, circ_val).unwrap(); - let out = deserialize_v8_value(scope, &bytes).unwrap(); - assert!(out.is_object()); - let out_obj = v8::Local::::try_from(out).unwrap(); - - // Verify the self-reference resolves - let k = v8::String::new(scope, "a").unwrap(); - assert_eq!( - out_obj - .get(scope, k.into()) - .unwrap() - .int32_value(scope) - .unwrap(), - 1 - ); - let k = v8::String::new(scope, "self").unwrap(); - let self_ref = out_obj.get(scope, k.into()).unwrap(); - assert!(self_ref.is_object()); - // The self reference should point back to the same structure - let self_obj = v8::Local::::try_from(self_ref).unwrap(); - let k = v8::String::new(scope, "a").unwrap(); - assert_eq!( - self_obj - .get(scope, k.into()) - .unwrap() - .int32_value(scope) - .unwrap(), - 1 - ); - } - - // --- V8 Code Caching tests --- - - // Part 60: First execution populates the cache - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let mut cache: Option = None; - - let bridge = "(function() { globalThis._cached = 'yes'; })()"; - let (code, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, bridge, "var _saw = _cached;", &mut cache) - }; - - assert_eq!(code, 0); - assert!(error.is_none()); - assert_eq!(eval(&mut iso, &ctx, "_saw"), "yes"); - // Cache should be populated after first compile - assert!( - cache.is_some(), - "cache should be populated after first execution" - ); - assert!(!cache.as_ref().unwrap().cached_data.is_empty()); - } - - // Part 61: Second execution uses the cache and produces correct results - { - let mut iso = isolate::create_isolate(None); - let mut cache: Option = None; - let bridge = "(function() { globalThis._counter = (globalThis._counter || 0) + 1; })()"; - - // First execution — populates cache - { - let ctx = isolate::create_context(&mut iso); - let (code, _) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, bridge, "", &mut cache) - }; - assert_eq!(code, 0); - assert!(cache.is_some()); - } - - let cached_data_len = cache.as_ref().unwrap().cached_data.len(); - - // Second execution — consumes cache (fresh context) - { - let ctx = isolate::create_context(&mut iso); - let (code, _) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, bridge, "", &mut cache) - }; - assert_eq!(code, 0); - // Cache should still be present (not invalidated) - assert!( - cache.is_some(), - "cache should persist after second execution" - ); - // Cached data should be same size (same code, same cache) - assert_eq!(cache.as_ref().unwrap().cached_data.len(), cached_data_len); - // Bridge code executed correctly - assert_eq!(eval(&mut iso, &ctx, "String(_counter)"), "1"); - } - } - - // Part 62: Cache is invalidated when bridge code changes - { - let mut iso = isolate::create_isolate(None); - let mut cache: Option = None; - - // Populate cache with bridge A - { - let ctx = isolate::create_context(&mut iso); - let (code, _) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script( - scope, - "(function() { globalThis.x = 'A'; })()", - "", - &mut cache, - ) - }; - assert_eq!(code, 0); - assert!(cache.is_some()); - } - - let hash_a = cache.as_ref().unwrap().source_hash; - - // Execute with different bridge code — cache should be replaced - { - let ctx = isolate::create_context(&mut iso); - let (code, _) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script( - scope, - "(function() { globalThis.x = 'B'; })()", - "", - &mut cache, - ) - }; - assert_eq!(code, 0); - assert!(cache.is_some()); - // Hash should be different - assert_ne!(cache.as_ref().unwrap().source_hash, hash_a); - // Code should have executed correctly - assert_eq!(eval(&mut iso, &ctx, "x"), "B"); - } - } - - // Part 63: Code caching works with execute_module - { - let mut iso = isolate::create_isolate(None); - let mut cache: Option = None; - - let output = Arc::new(Mutex::new(Vec::new())); - let writer = SharedWriter(Arc::clone(&output)); - let reader = Cursor::new(Vec::new()); - let bridge_ctx = - BridgeCallContext::new(Box::new(writer), Box::new(reader), "test-session".into()); - - let bridge = "(function() { globalThis._moduleBridge = true; })()"; - - // First execution populates cache - { - let ctx = isolate::create_context(&mut iso); - let (code, _, _) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - bridge, - "export const a = 1;", - None, - &mut cache, - ) - }; - assert_eq!(code, 0); - assert!(cache.is_some()); - } - - // Second execution consumes cache - { - let ctx = isolate::create_context(&mut iso); - let (code, exports, _) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - bridge, - "export const b = 2;", - None, - &mut cache, - ) - }; - assert_eq!(code, 0); - assert!(exports.is_some()); - assert!(cache.is_some()); - } - } - - // Part 64: Empty bridge code does not populate cache - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let mut cache: Option = None; - - let (code, _) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_script(scope, "", "var x = 1;", &mut cache) - }; - - assert_eq!(code, 0); - assert!( - cache.is_none(), - "cache should not be populated for empty bridge code" - ); - } - - // Part 65: Batch resolve — multiple imports prefetched in one round-trip - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let mut response_buf = Vec::new(); - - // Batch response (call_id=1): two resolved modules - let batch_result = v8_serialize_eval( - &mut iso, - &ctx, - "[{resolved: '/a.mjs', source: 'export const a = 1;'}, {resolved: '/b.mjs', source: 'export const b = 2;'}]", - ); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 0, - payload: batch_result, - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 2, - status: 0, - payload: v8_serialize_str(&mut iso, &ctx, "module"), - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 3, - status: 0, - payload: v8_serialize_str(&mut iso, &ctx, "module"), - }, - ) - .unwrap(); - - let writer_buf = Arc::new(Mutex::new(Vec::new())); - let bridge_ctx = BridgeCallContext::new( - Box::new(SharedWriter(Arc::clone(&writer_buf))), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let user_code = "import { a } from './a.mjs';\nimport { b } from './b.mjs';\nexport const sum = a + b;"; - let (code, exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - "", - user_code, - Some("/app/main.mjs"), - &mut None, - ) - }; - - assert_eq!(code, 0, "error: {:?}", error); - assert!(error.is_none()); - let exports = exports.unwrap(); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = crate::bridge::deserialize_v8_value(scope, &exports).unwrap(); - let obj = v8::Local::::try_from(val).unwrap(); - let k = v8::String::new(scope, "sum").unwrap(); - assert_eq!( - obj.get(scope, k.into()) - .unwrap() - .int32_value(scope) - .unwrap(), - 3 - ); - } - - // Verify only one BridgeCall was sent (the batch call, not individual calls) - let written = writer_buf.lock().unwrap(); - let call = crate::ipc_binary::read_frame(&mut Cursor::new(&*written)).unwrap(); - match call { - crate::ipc_binary::BinaryFrame::BridgeCall { method, .. } => { - assert_eq!(method, "_batchResolveModules"); - } - _ => panic!("expected BridgeCall for _batchResolveModules"), - } - } - - // Part 66: Batch resolve — fallback to individual resolution when batch fails - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let mut response_buf = Vec::new(); - - // Batch response (call_id=1): error (simulating unsupported batch method) - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 1, - payload: "No handler for bridge method: _batchResolveModules" - .as_bytes() - .to_vec(), - }, - ) - .unwrap(); - - // Individual fallback: _resolveModule (call_id=2) returns "/dep.mjs" - let resolve_result = v8_serialize_str(&mut iso, &ctx, "/dep.mjs"); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 2, - status: 0, - payload: resolve_result, - }, - ) - .unwrap(); - - // Individual fallback: _loadFile (call_id=3) returns source - let load_result = v8_serialize_str(&mut iso, &ctx, "export const val = 42;"); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 3, - status: 0, - payload: load_result, - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 4, - status: 0, - payload: v8_serialize_str(&mut iso, &ctx, "module"), - }, - ) - .unwrap(); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let user_code = "import { val } from './dep.mjs';\nexport const result = val;"; - let (code, exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - "", - user_code, - Some("/app/main.mjs"), - &mut None, - ) - }; - - assert_eq!(code, 0, "error: {:?}", error); - assert!(error.is_none()); - let exports = exports.unwrap(); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = crate::bridge::deserialize_v8_value(scope, &exports).unwrap(); - let obj = v8::Local::::try_from(val).unwrap(); - let k = v8::String::new(scope, "result").unwrap(); - assert_eq!( - obj.get(scope, k.into()) - .unwrap() - .int32_value(scope) - .unwrap(), - 42 - ); - } - } - - // Part 67: Batch resolve — nested imports resolved via BFS prefetch - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let mut response_buf = Vec::new(); - - // Level 1 batch (call_id=1): root imports ./a.mjs which imports ./b.mjs - let batch1 = v8_serialize_eval( - &mut iso, - &ctx, - "[{resolved: '/a.mjs', source: \"import { b } from './b.mjs'; export const a = b + 1;\"}]", - ); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 0, - payload: batch1, - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 2, - status: 0, - payload: v8_serialize_str(&mut iso, &ctx, "module"), - }, - ) - .unwrap(); - - // Level 2 batch (call_id=3): ./b.mjs has no further imports - let batch2 = v8_serialize_eval( - &mut iso, - &ctx, - "[{resolved: '/b.mjs', source: 'export const b = 10;'}]", - ); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 3, - status: 0, - payload: batch2, - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 4, - status: 0, - payload: v8_serialize_str(&mut iso, &ctx, "module"), - }, - ) - .unwrap(); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let user_code = "import { a } from './a.mjs';\nexport const result = a;"; - let (code, exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - "", - user_code, - Some("/app/main.mjs"), - &mut None, - ) - }; - - assert_eq!(code, 0, "error: {:?}", error); - assert!(error.is_none()); - let exports = exports.unwrap(); - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let val = crate::bridge::deserialize_v8_value(scope, &exports).unwrap(); - let obj = v8::Local::::try_from(val).unwrap(); - let k = v8::String::new(scope, "result").unwrap(); - assert_eq!( - obj.get(scope, k.into()) - .unwrap() - .int32_value(scope) - .unwrap(), - 11 - ); - } - } - - // Part 68: Batch resolve — module with no imports skips batch call - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let writer_buf = Arc::new(Mutex::new(Vec::new())); - let bridge_ctx = BridgeCallContext::new( - Box::new(SharedWriter(Arc::clone(&writer_buf))), - Box::new(Cursor::new(Vec::new())), - "test-session".into(), - ); - - let user_code = "export const x = 42;"; - let (code, _exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module(scope, &bridge_ctx, "", user_code, None, &mut None) - }; - - assert_eq!(code, 0, "error: {:?}", error); - assert!(error.is_none()); - - // No BridgeCall should have been sent (no imports to resolve) - let written = writer_buf.lock().unwrap(); - assert!( - written.is_empty(), - "no IPC calls expected for module with no imports" - ); - } - - // Part 68a: Batch prefetch extraction is capped per batch - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let mut source_code = String::new(); - for i in 0..(MAX_MODULE_PREFETCH_BATCH_SIZE + 1) { - source_code.push_str(&format!("import './dep-{i}.mjs';\n")); - } - source_code.push_str("export const ok = true;"); - - let resource = v8::String::new(scope, "/app/main.mjs").unwrap(); - let origin = v8::ScriptOrigin::new( - scope, - resource.into(), - 0, - 0, - false, - -1, - None, - false, - false, - true, - None, - ); - let source = v8::String::new(scope, &source_code).unwrap(); - let mut compiled = v8::script_compiler::Source::new(source, Some(&origin)); - let module = v8::script_compiler::compile_module(scope, &mut compiled).unwrap(); - - MODULE_RESOLVE_STATE.with(|cell| { - *cell.borrow_mut() = Some(ModuleResolveState { - bridge_ctx: std::ptr::null(), - module_names: HashMap::new(), - module_cache: HashMap::new(), - guest_reader: None, - }); - }); - let imports = extract_uncached_imports(scope, module, "/app/main.mjs"); - assert_eq!( - imports.len(), - MAX_MODULE_PREFETCH_BATCH_SIZE, - "static import extraction should stop at the prefetch batch cap" - ); - clear_module_state(); - } - - // Part 68b: Module cache insertion refuses to exceed the cache cap - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let resource = v8::String::new(scope, "/overflow.mjs").unwrap(); - let origin = v8::ScriptOrigin::new( - scope, - resource.into(), - 0, - 0, - false, - -1, - None, - false, - false, - true, - None, - ); - let source = v8::String::new(scope, "export const value = 1;").unwrap(); - let mut compiled = v8::script_compiler::Source::new(source, Some(&origin)); - let module = v8::script_compiler::compile_module(scope, &mut compiled).unwrap(); - let global = v8::Global::new(scope, module); - - let mut module_cache = HashMap::new(); - for i in 0..(MAX_MODULE_RESOLVE_CACHE_ENTRIES - 1) { - module_cache.insert(format!("/cached-{i}.mjs"), global.clone()); - } - MODULE_RESOLVE_STATE.with(|cell| { - *cell.borrow_mut() = Some(ModuleResolveState { - bridge_ctx: std::ptr::null(), - module_names: HashMap::new(), - module_cache, - guest_reader: None, - }); - }); - - assert!( - !cache_resolved_module( - module, - global, - "/overflow.mjs".into(), - Some(module_request_cache_key("./overflow.mjs", "/app/main.mjs")), - ), - "cache insert should fail instead of exceeding the cache entry cap" - ); - let cache_len = MODULE_RESOLVE_STATE.with(|cell| { - cell.borrow() - .as_ref() - .expect("module state") - .module_cache - .len() - }); - assert_eq!( - cache_len, - MAX_MODULE_RESOLVE_CACHE_ENTRIES - 1, - "failed cache insert must not partially insert entries" - ); - clear_module_state(); - } - - // Part 68c: Batch resolve response parsing is bounded to request length - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - - let oversized_response = v8_serialize_eval( - &mut iso, - &ctx, - "[{resolved: '/a.mjs', source: 'export const a = 1;'}, {resolved: '/extra.mjs', source: 'export const extra = 1;'}]", - ); - let mut response_buf = Vec::new(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 0, - payload: oversized_response, - }, - ) - .unwrap(); - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let results = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - batch_resolve_via_ipc( - scope, - &bridge_ctx, - &[("./a.mjs".to_string(), "/app/main.mjs".to_string())], - ) - .expect("batch resolve response") - }; - assert_eq!( - results.len(), - 1, - "batch response parser must not retain entries beyond the request length" - ); - assert_eq!( - results[0] - .as_ref() - .map(|(resolved, _source)| resolved.as_str()), - Some("/a.mjs") - ); - - let mut capped_response_buf = Vec::new(); - crate::ipc_binary::write_frame( - &mut capped_response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 0, - payload: vec![0; MAX_MODULE_BATCH_RESOLVE_RESPONSE_BYTES + 1], - }, - ) - .unwrap(); - let capped_bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(capped_response_buf)), - "test-session".into(), - ); - let capped_result = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - batch_resolve_via_ipc( - scope, - &capped_bridge_ctx, - &[("./large.mjs".to_string(), "/app/main.mjs".to_string())], - ) - }; - assert!( - capped_result.is_none(), - "batch response payloads over the byte cap should be rejected before deserialization" - ); - } - - // Part 68d: CJS named export extraction is capped - { - let mut source = String::new(); - for i in 0..(MAX_CJS_NAMED_EXPORTS + 1) { - source.push_str(&format!("exports.name{i} = {i};\n")); - } - - let exports = extract_cjs_export_names(&source); - assert_eq!( - exports.len(), - MAX_CJS_NAMED_EXPORTS, - "static CJS export extraction should stop at the named export cap" - ); - assert!( - !exports.contains(&format!("name{}", MAX_CJS_NAMED_EXPORTS)), - "exports beyond the cap must not be retained" - ); - - let object_literal_exports = - extract_cjs_export_names("module.exports = { foo: 1, shorthand, default: 2 };"); - assert!( - object_literal_exports.contains(&"foo".to_string()), - "module.exports object literal keys should be statically extracted" - ); - assert!( - object_literal_exports.contains(&"shorthand".to_string()), - "module.exports shorthand keys should be statically extracted" - ); - assert!( - !object_literal_exports.contains(&"default".to_string()), - "default should not be emitted as a named CJS export" - ); - - let object_assign_exports = - extract_cjs_export_names("Object.assign(module.exports, { bar: 1, baz });"); - assert!( - object_assign_exports.contains(&"bar".to_string()) - && object_assign_exports.contains(&"baz".to_string()), - "Object.assign(module.exports, object literal) keys should be extracted" - ); - - let multiline_exports = extract_cjs_export_names( - r#" - module.exports = { - multiFoo: 1, - multiBar, - }; - - Object.assign(module.exports, { - multiBaz: 2, - }); - "#, - ); - assert!( - multiline_exports.contains(&"multiFoo".to_string()) - && multiline_exports.contains(&"multiBar".to_string()) - && multiline_exports.contains(&"multiBaz".to_string()), - "multiline CJS object literal export keys should be extracted" - ); - - let false_positive_exports = extract_cjs_export_names( - r#" - module.exports.foo = { fakeOne: 1 }; - Object.assign(otherTarget, { fakeTwo: 2 }); - // module.exports = { fakeThree: 3 }; - const text = "Object.assign(module.exports, { fakeFour: 4 })"; - /* exports.fakeFive = 5; */ - const tpl = `Object.defineProperty(exports, "fakeSix", {})`; - module.exports = { "fake:seven": 7 }; - const re = /module.exports = { fakeEight: 8 }/; - function f() { return /module.exports = { fakeNine: 9 }/; } - const g = () => /exports.fakeTen = 10/; - const h = /[/]module.exports = { fakeEleven: 11 }/; - if (ok) /exports.fakeTwelve = 12/.test(input); - if (ok) {} /exports.fakeThirteen = 13/.test(input); - "#, - ); - assert!( - !false_positive_exports.contains(&"fakeOne".to_string()) - && !false_positive_exports.contains(&"fakeTwo".to_string()) - && !false_positive_exports.contains(&"fakeThree".to_string()) - && !false_positive_exports.contains(&"fakeFour".to_string()) - && !false_positive_exports.contains(&"fakeFive".to_string()) - && !false_positive_exports.contains(&"fakeSix".to_string()) - && !false_positive_exports.contains(&"fake".to_string()) - && !false_positive_exports.contains(&"fakeEight".to_string()) - && !false_positive_exports.contains(&"fakeNine".to_string()) - && !false_positive_exports.contains(&"fakeTen".to_string()) - && !false_positive_exports.contains(&"fakeEleven".to_string()) - && !false_positive_exports.contains(&"fakeTwelve".to_string()) - && !false_positive_exports.contains(&"fakeThirteen".to_string()), - "object literal extraction should not emit keys from unrelated objects" - ); - - let mut malformed_literals = String::new(); - for i in 0..2048 { - malformed_literals.push_str(&format!("module.exports = {{ fake{i}: ")); - } - let malformed_exports = extract_cjs_export_names(&malformed_literals); - assert!( - malformed_exports.is_empty(), - "malformed object literals should be skipped without collecting fake keys" - ); - - let regex_value_exports = - extract_cjs_export_names("module.exports = { real: /}/, alsoReal: /[,]}/ };"); - assert!( - regex_value_exports.contains(&"real".to_string()) - && regex_value_exports.contains(&"alsoReal".to_string()), - "regex values inside CJS object literals should not terminate the object scan" - ); - - let division_exports = extract_cjs_export_names("const n = 4 / 2; exports.after = n;"); - assert!( - division_exports.contains(&"after".to_string()), - "ordinary division should not hide later CJS export assignments" - ); - - let reserved_exports = extract_cjs_export_names( - r#" - exports.arguments = 1; - exports.class = 1; - module.exports = { await: 2 }; - module.exports = { let: 3, static: 4, eval: 5 }; - Object.assign(module.exports, { - implements: 6, - interface: 7, - package: 8, - private: 9, - protected: 10, - public: 11, - }); - Object.defineProperty(exports, "return", {}); - "#, - ); - assert!( - reserved_exports.is_empty(), - "reserved words should not be emitted as generated ESM bindings" - ); - - let mut huge_literal = String::from("module.exports = {\n"); - for i in 0..(MAX_CJS_NAMED_EXPORTS + 1) { - huge_literal.push_str(&format!("literalName{i}: {i},\n")); - } - huge_literal.push_str("};"); - let huge_literal_exports = extract_cjs_export_names(&huge_literal); - assert_eq!( - huge_literal_exports.len(), - MAX_CJS_NAMED_EXPORTS, - "object literal export extraction should stop at the named export cap" - ); - assert!( - !huge_literal_exports.contains(&format!("literalName{}", MAX_CJS_NAMED_EXPORTS)), - "object literal exports beyond the cap must not be retained" - ); - - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let shim = - build_cjs_esm_shim(scope, "module.exports = { foo: 1 };", "/object-literal.cjs"); - assert!( - shim.contains("export const foo = _cjsModule[\"foo\"];"), - "CJS shim should preserve statically extractable named exports" - ); - } - - // Part 68e: CJS shim degrades to default-only when runtime extraction is unavailable - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let shim = build_cjs_esm_shim( - scope, - "module.exports = makeExportsDynamically();", - "/runtime.cjs", - ); - - assert!( - shim.contains("export default _cjsModule;"), - "CJS shim should preserve default import support" - ); - assert!( - !shim.contains("export const name0"), - "CJS shim must degrade to default-only when runtime extraction is unavailable" - ); - } - - // Part 68f: CJS shim runtime fallback enumerates dynamically computed exports - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let setup = v8::String::new( - scope, - "globalThis._requireFrom = function (path, referrer) { return { dynamicA: 1, dynamicB: 2, default: 3, __esModule: true }; };", - ) - .unwrap(); - let script = v8::Script::compile(scope, setup, None).unwrap(); - script.run(scope).unwrap(); - - let shim = build_cjs_esm_shim( - scope, - "module.exports = makeExportsDynamically();", - "/dynamic.cjs", - ); - - assert!( - shim.contains("export const dynamicA = _cjsModule[\"dynamicA\"];"), - "runtime fallback should surface dynamically computed named exports" - ); - assert!( - shim.contains("export const dynamicB = _cjsModule[\"dynamicB\"];"), - "runtime fallback should surface every dynamically computed named export" - ); - assert!( - shim.contains("export default _cjsModule;"), - "CJS shim should preserve default import support" - ); - assert!( - !shim.contains("export const default"), - "runtime fallback must not emit a named export for default" - ); - assert!( - !shim.contains("__esModule"), - "runtime fallback must not emit a named export for __esModule" - ); - } - - // Part 68g: CJS shim runtime fallback bounds export count and name length - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let setup = v8::String::new( - scope, - "globalThis._requireFrom = function () { const o = {}; for (let i = 0; i < 1025; i++) o[\"k\" + String(i).padStart(4, \"0\")] = i; o[\"x\".repeat(600)] = 1; return o; };", - ) - .unwrap(); - let script = v8::Script::compile(scope, setup, None).unwrap(); - script.run(scope).unwrap(); - - let shim = build_cjs_esm_shim( - scope, - "module.exports = makeExportsDynamically();", - "/bounded.cjs", - ); - - let export_count = shim.matches("export const ").count(); - assert_eq!( - export_count, MAX_CJS_NAMED_EXPORTS, - "runtime fallback should stop collecting names at the named export cap" - ); - assert!( - !shim.contains("export const k1024"), - "runtime fallback exports beyond the cap must not be retained" - ); - let longest_export_name = shim - .lines() - .filter_map(|line| line.strip_prefix("export const ")) - .filter_map(|rest| rest.split(' ').next()) - .map(str::len) - .max() - .unwrap_or(0); - assert!( - longest_export_name <= MAX_CJS_RUNTIME_EXPORT_NAME_LEN, - "runtime fallback must skip export names longer than the length cap" - ); - } - - // Part 68h: CJS shim runtime fallback tolerates guest evaluation failure - { - let mut iso = isolate::create_isolate(None); - let ctx = isolate::create_context(&mut iso); - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - - let setup = v8::String::new( - scope, - "globalThis._requireFrom = function () { throw new Error(\"boom\"); };", - ) - .unwrap(); - let script = v8::Script::compile(scope, setup, None).unwrap(); - script.run(scope).unwrap(); - - let shim = build_cjs_esm_shim( - scope, - "module.exports = makeExportsDynamically();", - "/throwing.cjs", - ); - - assert!( - shim.contains("export default _cjsModule;"), - "CJS shim should preserve default import support after a guest throw" - ); - assert!( - !shim.contains("export const "), - "runtime fallback should yield no named exports when module evaluation throws" - ); - } - - // Part 69: Dynamic import works after execute_module returns - { - let mut iso = isolate::create_isolate(None); - iso.set_host_import_module_dynamically_callback(dynamic_import_callback); - iso.set_host_initialize_import_meta_object_callback(import_meta_object_callback); - let ctx = isolate::create_context(&mut iso); - - let mut response_buf = Vec::new(); - - let resolve_result = v8_serialize_str(&mut iso, &ctx, "/dep.mjs"); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 1, - status: 0, - payload: resolve_result, - }, - ) - .unwrap(); - - let load_result = v8_serialize_str(&mut iso, &ctx, "export const value = 42;"); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 2, - status: 0, - payload: load_result, - }, - ) - .unwrap(); - crate::ipc_binary::write_frame( - &mut response_buf, - &crate::ipc_binary::BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id: 3, - status: 0, - payload: v8_serialize_str(&mut iso, &ctx, "module"), - }, - ) - .unwrap(); - - let bridge_ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_buf)), - "test-session".into(), - ); - - let user_code = r#" - globalThis.loadDep = async () => (await import("./dep.mjs")).value; - export const ready = true; - "#; - let (code, exports, error) = { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - execute_module( - scope, - &bridge_ctx, - "", - user_code, - Some("/app/main.mjs"), - &mut None, - ) - }; - - assert_eq!(code, 0, "error: {:?}", error); - assert!(error.is_none()); - assert!(exports.is_some()); - - { - let scope = &mut v8::HandleScope::new(&mut iso); - let local = v8::Local::new(scope, &ctx); - let scope = &mut v8::ContextScope::new(scope, local); - let tc = &mut v8::TryCatch::new(scope); - let source = v8::String::new( - tc, - "globalThis.__depPromise = globalThis.loadDep().then((value) => { globalThis.__depValue = value; return value; });", - ) - .unwrap(); - let script = v8::Script::compile(tc, source, None).unwrap(); - assert!(script.run(tc).is_some()); - tc.perform_microtask_checkpoint(); - assert!(tc.exception().is_none()); - } - - assert_eq!(eval(&mut iso, &ctx, "String(globalThis.__depValue)"), "42"); - clear_module_state(); - } - } -} diff --git a/crates/v8-runtime/src/host_call.rs b/crates/v8-runtime/src/host_call.rs deleted file mode 100644 index 6ff00c0f5..000000000 --- a/crates/v8-runtime/src/host_call.rs +++ /dev/null @@ -1,967 +0,0 @@ -// Sync-blocking bridge call: serialize, write to socket, block on read, deserialize - -use std::cell::RefCell; -use std::collections::{BTreeMap, HashMap, HashSet}; -use std::io::{Read, Write}; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, Instant}; - -use crate::ipc_binary::{self, BinaryFrame}; -use crate::runtime_protocol::{BridgeResponse, RuntimeEvent}; -use crate::session::RuntimeEventEnvelope; - -// ── Sync bridge-call round-trip latency (opt-in via AGENTOS_SYNCRPC_LAT=1) ── -// Measures the guest-observed cost of one host_call round trip (send + block on -// response). If this is ~ms per call, the embedded-V8 IPC floor is a big part of -// the evaluate-phase VM tax (~50 fs sync RPCs during SDK init). Writes running -// (count, total_us, max_us) to AGENTOS_SYNCRPC_LAT_FILE. -static SYNCRPC_LAT: std::sync::OnceLock> = - std::sync::OnceLock::new(); - -fn syncrpc_lat_enabled() -> bool { - std::env::var("AGENTOS_SYNCRPC_LAT").as_deref() == Ok("1") -} - -fn record_syncrpc_lat(ns: u64) { - let m = SYNCRPC_LAT.get_or_init(|| std::sync::Mutex::new((0, 0, 0))); - let Ok(mut a) = m.lock() else { - return; - }; - a.0 += 1; - a.1 = a.1.wrapping_add(ns / 1000); - a.2 = a.2.max(ns / 1000); - if a.0 % 25 == 0 { - if let Ok(path) = std::env::var("AGENTOS_SYNCRPC_LAT_FILE") { - let _ = std::fs::write( - &path, - format!( - "calls={} total_us={} avg_us={} max_us={}\n", - a.0, - a.1, - a.1 / a.0, - a.2 - ), - ); - } - } -} - -#[derive(Debug, Default, Clone)] -struct SyncBridgeHostPhaseStats { - calls: u64, - total_us: u64, - max_us: u64, -} - -static SYNC_BRIDGE_HOST_PHASES: std::sync::OnceLock< - std::sync::Mutex>, -> = std::sync::OnceLock::new(); -static SYNC_BRIDGE_CALL_METHODS: std::sync::OnceLock>> = - std::sync::OnceLock::new(); -static SYNC_BRIDGE_RESPONSE_CHANNEL_SENDS: std::sync::OnceLock< - std::sync::Mutex>, -> = std::sync::OnceLock::new(); - -fn sync_bridge_host_phases_enabled() -> bool { - std::env::var("AGENTOS_SYNC_BRIDGE_HOST_PHASES").as_deref() == Ok("1") -} - -pub(crate) fn record_sync_bridge_host_phase(method: &str, stage: &str, elapsed: Duration) { - if !sync_bridge_host_phases_enabled() { - return; - } - let stats = SYNC_BRIDGE_HOST_PHASES.get_or_init(|| std::sync::Mutex::new(BTreeMap::new())); - let Ok(mut stats) = stats.lock() else { - return; - }; - let elapsed_us = elapsed.as_micros() as u64; - let key = format!("{method}:{stage}"); - let entry = stats.entry(key).or_default(); - entry.calls += 1; - entry.total_us = entry.total_us.wrapping_add(elapsed_us); - entry.max_us = entry.max_us.max(elapsed_us); - - if let Ok(path) = std::env::var("AGENTOS_SYNC_BRIDGE_HOST_PHASES_FILE") { - let mut lines = String::new(); - for (key, value) in stats.iter() { - let Some((method, stage)) = key.split_once(':') else { - continue; - }; - let avg_us = value.total_us.checked_div(value.calls).unwrap_or(0); - lines.push_str(&format!( - "method={method} stage={stage} calls={} total_us={} avg_us={} max_us={}\n", - value.calls, value.total_us, avg_us, value.max_us - )); - } - let _ = std::fs::write(path, lines); - } -} - -fn track_sync_bridge_call_method(call_id: u64, method: &str) { - if !sync_bridge_host_phases_enabled() { - return; - } - let methods = SYNC_BRIDGE_CALL_METHODS.get_or_init(|| std::sync::Mutex::new(HashMap::new())); - let Ok(mut methods) = methods.lock() else { - return; - }; - if methods.len() > 4096 { - methods.clear(); - } - methods.insert(call_id, method.to_owned()); -} - -fn cleanup_sync_bridge_call_tracking(call_id: u64) { - if let Some(methods) = SYNC_BRIDGE_CALL_METHODS.get() { - if let Ok(mut methods) = methods.lock() { - methods.remove(&call_id); - } - } - if let Some(starts) = SYNC_BRIDGE_RESPONSE_CHANNEL_SENDS.get() { - if let Ok(mut starts) = starts.lock() { - starts.remove(&call_id); - } - } -} - -pub(crate) fn record_sync_bridge_response_channel_send_start(call_id: u64) { - if !sync_bridge_host_phases_enabled() { - return; - } - let method = SYNC_BRIDGE_CALL_METHODS - .get() - .and_then(|methods| methods.lock().ok()?.get(&call_id).cloned()) - .unwrap_or_else(|| String::from("sync_rpc_response")); - let starts = - SYNC_BRIDGE_RESPONSE_CHANNEL_SENDS.get_or_init(|| std::sync::Mutex::new(HashMap::new())); - let Ok(mut starts) = starts.lock() else { - return; - }; - if starts.len() > 4096 { - starts.clear(); - } - starts.insert(call_id, (method, Instant::now())); -} - -pub(crate) fn record_sync_bridge_response_channel_received(call_id: u64) { - if !sync_bridge_host_phases_enabled() { - return; - } - let Some(starts) = SYNC_BRIDGE_RESPONSE_CHANNEL_SENDS.get() else { - return; - }; - let Ok(mut starts) = starts.lock() else { - return; - }; - let Some((method, started)) = starts.remove(&call_id) else { - return; - }; - record_sync_bridge_host_phase(&method, "host_response_channel_recv", started.elapsed()); -} - -/// Trait for sending serialized frames to the host without holding a shared mutex. -/// Production code uses ChannelRuntimeEventSender (lock-free MPSC); tests use WriterRuntimeEventSender. -pub trait RuntimeEventSender: Send { - fn send_event(&self, event: RuntimeEvent) -> Result<(), String>; -} - -/// Sends frames via a crossbeam channel to a dedicated writer thread. -/// Maintains a reusable frame buffer that grows to high-water mark, -/// avoiding per-call allocation for frame construction. -pub struct ChannelRuntimeEventSender { - pub tx: crossbeam_channel::Sender, - output_generation: Option, - /// Pre-allocated frame buffer reused across send_frame calls. - /// Grows to high-water mark; cleared (not deallocated) between calls. - #[allow(dead_code)] - frame_buf: RefCell>, -} - -impl ChannelRuntimeEventSender { - pub fn new( - tx: crossbeam_channel::Sender, - output_generation: Option, - ) -> Self { - ChannelRuntimeEventSender { - tx, - output_generation, - frame_buf: RefCell::new(Vec::with_capacity(256)), - } - } -} - -impl RuntimeEventSender for ChannelRuntimeEventSender { - fn send_event(&self, event: RuntimeEvent) -> Result<(), String> { - self.tx - .send(RuntimeEventEnvelope { - output_generation: self.output_generation, - event, - }) - .map_err(|e| format!("channel send failed: {}", e)) - } -} - -/// Sends frames directly to a Write impl (used by tests). -#[allow(dead_code)] -pub struct WriterRuntimeEventSender { - writer: Mutex>, -} - -impl RuntimeEventSender for WriterRuntimeEventSender { - fn send_event(&self, event: RuntimeEvent) -> Result<(), String> { - let mut w = self.writer.lock().unwrap(); - let frame: BinaryFrame = event.into(); - ipc_binary::write_frame(&mut *w, &frame).map_err(|e| format!("write error: {}", e)) - } -} - -/// Trait for receiving a BridgeResponse directly without re-serialization. -/// Production code uses a channel-based implementation; tests use a buffer-based one. -pub trait BridgeResponseReceiver: Send { - fn recv_response(&self, expected_call_id: u64) -> Result; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SyncBridgeCallResponse { - pub status: u8, - pub payload: Vec, -} - -/// ResponseReceiver that reads frames from a byte buffer via ipc_binary::read_frame. -/// Used by tests and any code that has a pre-serialized byte stream. -#[allow(dead_code)] -pub struct ReaderBridgeResponseReceiver { - reader: Mutex>, -} - -impl ReaderBridgeResponseReceiver { - #[allow(dead_code)] - pub fn new(reader: Box) -> Self { - ReaderBridgeResponseReceiver { - reader: Mutex::new(reader), - } - } -} - -impl BridgeResponseReceiver for ReaderBridgeResponseReceiver { - fn recv_response(&self, expected_call_id: u64) -> Result { - let mut reader = self.reader.lock().unwrap(); - let frame = ipc_binary::read_frame(&mut *reader) - .map_err(|e| format!("failed to read BridgeResponse: {}", e))?; - match frame { - BinaryFrame::BridgeResponse { - call_id, - status, - payload, - .. - } => { - if call_id != expected_call_id { - return Err(format!( - "call_id mismatch: expected {}, got {}", - expected_call_id, call_id - )); - } - Ok(BridgeResponse { - call_id, - status, - payload, - }) - } - _ => Err("expected BridgeResponse, got different message type".into()), - } - } -} - -/// Shared routing table: maps call_id → session_id for BridgeResponse routing. -/// The connection handler uses this to determine which session a BridgeResponse -/// belongs to (since BridgeResponse has call_id but no session_id). -pub type CallIdRouter = Arc>>; - -/// Shared call_id counter type. Sessions sharing a CallIdRouter must use the same -/// counter to prevent call_id collisions that cause BridgeResponses to be delivered -/// to the wrong session. -pub type SharedCallIdCounter = Arc; - -/// Context for sync-blocking bridge calls from a V8 session. -/// -/// Holds the frame sender and response receiver, session ID, call_id counter, -/// and pending-call tracking. Used by V8 FunctionTemplate callbacks to -/// implement the sync-blocking bridge pattern. -pub struct BridgeCallContext { - /// Sender for serialized frames to the host (channel-based in production) - sender: Box, - /// Receiver for BridgeResponse frames (no re-serialization needed) - response_rx: Mutex>, - /// Session ID included in every BridgeCall - pub session_id: String, - /// Monotonically increasing call_id counter. Sessions sharing a CallIdRouter - /// must share the same counter (via Arc) to prevent call_id collisions. - next_call_id: Arc, - /// Set of in-flight call_ids (for duplicate rejection) - pending_calls: Mutex>, - /// Opt-in diagnostic tracking for sync call_ids. The atomic call_id counter - /// plus recv_response(call_id) validation are the correctness path; this set - /// is only needed when inspecting in-flight calls. - track_pending_calls: bool, - /// Optional routing table for call_id → session_id mapping. - /// When set, call_ids are registered here so the connection handler - /// can route BridgeResponse messages to the correct session. - call_id_router: Option, -} - -/// No-op FrameSender for snapshot stub functions. -/// Panics if called — stubs must never be invoked during snapshot creation. -#[allow(dead_code)] -struct StubRuntimeEventSender; - -impl RuntimeEventSender for StubRuntimeEventSender { - fn send_event(&self, _event: RuntimeEvent) -> Result<(), String> { - panic!( - "stub bridge function called during snapshot creation — bridge IIFE must not call bridge functions at setup time" - ) - } -} - -/// No-op ResponseReceiver for snapshot stub functions. -/// Panics if called — stubs must never be invoked during snapshot creation. -#[allow(dead_code)] -struct StubBridgeResponseReceiver; - -impl BridgeResponseReceiver for StubBridgeResponseReceiver { - fn recv_response(&self, _expected_call_id: u64) -> Result { - panic!( - "stub bridge function called during snapshot creation — bridge IIFE must not call bridge functions at setup time" - ) - } -} - -#[allow(dead_code)] -impl BridgeCallContext { - /// Create a no-op BridgeCallContext for snapshot stub functions. - /// Panics if sync_call or async_send is called — stubs exist only for - /// the bridge IIFE to reference (not call) during snapshot creation. - pub fn stub() -> Self { - BridgeCallContext { - sender: Box::new(StubRuntimeEventSender), - response_rx: Mutex::new(Box::new(StubBridgeResponseReceiver)), - session_id: "stub".into(), - next_call_id: Arc::new(AtomicU64::new(1)), - pending_calls: Mutex::new(HashSet::new()), - track_pending_calls: should_track_pending_sync_calls(), - call_id_router: None, - } - } - - /// Create a BridgeCallContext with a byte writer and reader (wraps in WriterFrameSender - /// and ReaderResponseReceiver). Convenient for tests that pre-serialize BridgeResponse bytes. - pub fn new( - writer: Box, - reader: Box, - session_id: String, - ) -> Self { - BridgeCallContext { - sender: Box::new(WriterRuntimeEventSender { - writer: Mutex::new(writer), - }), - response_rx: Mutex::new(Box::new(ReaderBridgeResponseReceiver::new(reader))), - session_id, - next_call_id: Arc::new(AtomicU64::new(1)), - pending_calls: Mutex::new(HashSet::new()), - track_pending_calls: should_track_pending_sync_calls(), - call_id_router: None, - } - } - - /// Create a BridgeCallContext with a FrameSender, ResponseReceiver, call_id routing table, - /// and shared call_id counter. All sessions sharing the same CallIdRouter must share - /// the same counter to prevent call_id collisions in the routing table. - pub fn with_receiver( - sender: Box, - response_rx: Box, - session_id: String, - router: CallIdRouter, - shared_call_id: SharedCallIdCounter, - ) -> Self { - BridgeCallContext { - sender, - response_rx: Mutex::new(response_rx), - session_id, - next_call_id: shared_call_id, - pending_calls: Mutex::new(HashSet::new()), - track_pending_calls: should_track_pending_sync_calls(), - call_id_router: Some(router), - } - } - - /// Perform a sync-blocking bridge call. - /// - /// Generates a unique call_id, sends a BridgeCall message over IPC, - /// blocks on read() for the BridgeResponse, and returns the result. - /// Error responses from the host are returned as Err. - pub fn sync_call_response( - &self, - method: &str, - args: Vec, - ) -> Result, String> { - let call_id = self.next_call_id.fetch_add(1, Ordering::Relaxed); - track_sync_bridge_call_method(call_id, method); - - // Optional diagnostic tracking. Correctness comes from the atomic - // counter and recv_response(call_id) identity validation. - if self.track_pending_calls { - let mut pending = self.pending_calls.lock().unwrap(); - if !pending.insert(call_id) { - return Err(format!("duplicate call_id: {}", call_id)); - } - } - - // Register call_id → session_id for BridgeResponse routing - if let Some(ref router) = self.call_id_router { - let phase_start = Instant::now(); - router - .lock() - .unwrap() - .insert(call_id, self.session_id.clone()); - record_sync_bridge_host_phase(method, "host_register_route", phase_start.elapsed()); - } - - // Send BridgeCall to host - let bridge_call = RuntimeEvent::BridgeCall { - session_id: self.session_id.clone(), - call_id, - method: method.to_string(), - payload: args, - }; - - let __lat = syncrpc_lat_enabled().then(Instant::now); - let phase_start = Instant::now(); - if let Err(e) = self.sender.send_event(bridge_call) { - self.remove_pending_call(call_id); - self.remove_call_route(call_id); - return Err(format!("failed to write BridgeCall: {}", e)); - } - record_sync_bridge_host_phase(method, "host_send_event", phase_start.elapsed()); - - // Receive BridgeResponse directly (no re-serialization) - let response = { - let rx = self.response_rx.lock().unwrap(); - let phase_start = Instant::now(); - match rx.recv_response(call_id) { - Ok(frame) => { - record_sync_bridge_host_phase( - method, - "host_recv_response", - phase_start.elapsed(), - ); - frame - } - Err(e) => { - self.remove_pending_call(call_id); - self.remove_call_route(call_id); - return Err(e); - } - } - }; - if let Some(t) = __lat { - record_syncrpc_lat(t.elapsed().as_nanos() as u64); - } - - let phase_start = Instant::now(); - self.remove_pending_call(call_id); - self.remove_call_route(call_id); - record_sync_bridge_host_phase(method, "host_cleanup", phase_start.elapsed()); - - // Validate and extract BridgeResponse - let phase_start = Instant::now(); - if response.status == 1 { - let result = Err(String::from_utf8_lossy(&response.payload).to_string()); - record_sync_bridge_host_phase(method, "host_extract_response", phase_start.elapsed()); - result - } else if response.payload.is_empty() && response.status != 2 { - record_sync_bridge_host_phase(method, "host_extract_response", phase_start.elapsed()); - Ok(None) - } else { - let result = Ok(Some(SyncBridgeCallResponse { - status: response.status, - payload: response.payload, - })); - record_sync_bridge_host_phase(method, "host_extract_response", phase_start.elapsed()); - result - } - } - - pub fn sync_call(&self, method: &str, args: Vec) -> Result>, String> { - self.sync_call_response(method, args) - .map(|response| response.map(|response| response.payload)) - } - - /// Send a BridgeCall without blocking for a response. - /// Returns the call_id for later matching with BridgeResponse. - /// Used by async promise-returning bridge functions. - pub fn async_send(&self, method: &str, args: Vec) -> Result { - let call_id = self.next_call_id.fetch_add(1, Ordering::Relaxed); - - // Register call_id → session_id for BridgeResponse routing - if let Some(ref router) = self.call_id_router { - router - .lock() - .unwrap() - .insert(call_id, self.session_id.clone()); - } - - let bridge_call = RuntimeEvent::BridgeCall { - session_id: self.session_id.clone(), - call_id, - method: method.to_string(), - payload: args, - }; - - if let Err(e) = self.sender.send_event(bridge_call) { - self.remove_call_route(call_id); - return Err(format!("failed to write BridgeCall: {}", e)); - } - - Ok(call_id) - } - - fn remove_call_route(&self, call_id: u64) { - if let Some(ref router) = self.call_id_router { - router.lock().unwrap().remove(&call_id); - } - } - - fn remove_pending_call(&self, call_id: u64) { - cleanup_sync_bridge_call_tracking(call_id); - if self.track_pending_calls { - self.pending_calls.lock().unwrap().remove(&call_id); - } - } - - /// Check if a call_id is currently pending. - pub fn is_call_pending(&self, call_id: u64) -> bool { - if !self.track_pending_calls { - return false; - } - self.pending_calls.lock().unwrap().contains(&call_id) - } - - /// Number of pending calls. - pub fn pending_count(&self) -> usize { - if !self.track_pending_calls { - return 0; - } - self.pending_calls.lock().unwrap().len() - } -} - -fn should_track_pending_sync_calls() -> bool { - std::env::var("AGENTOS_TRACK_PENDING_SYNC_CALLS").as_deref() == Ok("1") -} - -#[cfg(test)] -mod tests { - use super::*; - use std::io::Cursor; - use std::sync::Arc; - - /// Shared writer that captures output for test inspection - struct SharedWriter(Arc>>); - - impl Write for SharedWriter { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.0.lock().unwrap().write(buf) - } - fn flush(&mut self) -> std::io::Result<()> { - self.0.lock().unwrap().flush() - } - } - - /// Serialize a BridgeResponse into length-prefixed binary frame bytes - fn make_response_bytes( - call_id: u64, - result: Option>, - error: Option, - ) -> Vec { - let mut buf = Vec::new(); - let (status, payload) = if let Some(err) = error { - (1u8, err.into_bytes()) - } else if let Some(res) = result { - (0u8, res) - } else { - (0u8, vec![]) - }; - ipc_binary::write_frame( - &mut buf, - &BinaryFrame::BridgeResponse { - session_id: String::new(), - call_id, - status, - payload, - }, - ) - .unwrap(); - buf - } - - #[test] - fn sync_call_success_with_result() { - let response_bytes = make_response_bytes(1, Some(vec![0x93, 0x01, 0x02, 0x03]), None); - let writer_buf = Arc::new(Mutex::new(Vec::new())); - - let ctx = BridgeCallContext::new( - Box::new(SharedWriter(Arc::clone(&writer_buf))), - Box::new(Cursor::new(response_bytes)), - "test-session-abc".into(), - ); - - let result = ctx.sync_call("_fsReadFile", vec![0x91, 0xa3, 0x66, 0x6f, 0x6f]); - assert!(result.is_ok()); - assert_eq!(result.unwrap(), Some(vec![0x93, 0x01, 0x02, 0x03])); - - // Verify the BridgeCall was written correctly - let written = writer_buf.lock().unwrap(); - let call = ipc_binary::read_frame(&mut Cursor::new(&*written)).unwrap(); - match call { - BinaryFrame::BridgeCall { - call_id, - session_id, - method, - payload, - .. - } => { - assert_eq!(call_id, 1); - assert_eq!(session_id, "test-session-abc"); - assert_eq!(method, "_fsReadFile"); - assert_eq!(payload, vec![0x91, 0xa3, 0x66, 0x6f, 0x6f]); - } - _ => panic!("expected BridgeCall"), - } - } - - #[test] - fn sync_call_success_null_result() { - let response_bytes = make_response_bytes(1, None, None); - let ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_bytes)), - "session-1".into(), - ); - - let result = ctx.sync_call("_log", vec![0xc0]).unwrap(); - assert_eq!(result, None); - } - - #[test] - fn sync_call_error_response() { - let response_bytes = make_response_bytes(1, None, Some("ENOENT: no such file".into())); - let ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_bytes)), - "session-1".into(), - ); - - let result = ctx.sync_call("_fsReadFile", vec![0xc0]); - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), "ENOENT: no such file"); - } - - #[test] - fn sync_call_call_id_increments() { - // Prepare two sequential responses - let mut response_bytes = make_response_bytes(1, Some(vec![0xa1, 0x61]), None); - response_bytes.extend_from_slice(&make_response_bytes(2, Some(vec![0xa1, 0x62]), None)); - - let ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_bytes)), - "session-1".into(), - ); - - let r1 = ctx.sync_call("_fn1", vec![]).unwrap(); - let r2 = ctx.sync_call("_fn2", vec![]).unwrap(); - assert_eq!(r1, Some(vec![0xa1, 0x61])); - assert_eq!(r2, Some(vec![0xa1, 0x62])); - } - - #[test] - fn sync_call_pending_cleanup_on_read_error() { - // Empty reader = EOF error; call_id should be cleaned up - let ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "session-1".into(), - ); - - assert_eq!(ctx.pending_count(), 0); - let _ = ctx.sync_call("_fn", vec![]); - assert_eq!(ctx.pending_count(), 0); - } - - #[test] - fn sync_call_id_mismatch_rejected() { - // Response has call_id=99 but expected call_id=1 - let response_bytes = make_response_bytes(99, Some(vec![0xc0]), None); - let ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_bytes)), - "session-1".into(), - ); - - let result = ctx.sync_call("_fn", vec![]); - assert!(result.is_err()); - assert!(result.unwrap_err().contains("call_id mismatch")); - } - - #[test] - fn sync_call_unexpected_message_type_rejected() { - // Response is not a BridgeResponse - let mut response_bytes = Vec::new(); - ipc_binary::write_frame( - &mut response_bytes, - &BinaryFrame::TerminateExecution { - session_id: "session-1".into(), - }, - ) - .unwrap(); - - let ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_bytes)), - "session-1".into(), - ); - - let result = ctx.sync_call("_fn", vec![]); - assert!(result.is_err()); - assert!(result.unwrap_err().contains("expected BridgeResponse")); - } - - #[test] - fn async_send_writes_bridge_call() { - let writer_buf = Arc::new(Mutex::new(Vec::new())); - let ctx = BridgeCallContext::new( - Box::new(SharedWriter(Arc::clone(&writer_buf))), - Box::new(Cursor::new(Vec::new())), - "test-session-abc".into(), - ); - - let call_id = ctx - .async_send("_asyncFn", vec![0x91, 0xa3, 0x66, 0x6f, 0x6f]) - .unwrap(); - assert_eq!(call_id, 1); - - // Verify the BridgeCall was written correctly - let written = writer_buf.lock().unwrap(); - let call = ipc_binary::read_frame(&mut Cursor::new(&*written)).unwrap(); - match call { - BinaryFrame::BridgeCall { - call_id, - session_id, - method, - payload, - .. - } => { - assert_eq!(call_id, 1); - assert_eq!(session_id, "test-session-abc"); - assert_eq!(method, "_asyncFn"); - assert_eq!(payload, vec![0x91, 0xa3, 0x66, 0x6f, 0x6f]); - } - _ => panic!("expected BridgeCall"), - } - } - - #[test] - fn async_send_increments_call_id() { - let ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(Vec::new())), - "session-1".into(), - ); - - let id1 = ctx.async_send("_fn1", vec![]).unwrap(); - let id2 = ctx.async_send("_fn2", vec![]).unwrap(); - assert_eq!(id1, 1); - assert_eq!(id2, 2); - } - - #[test] - fn async_send_shares_counter_with_sync() { - // Sync call uses call_id=1, async_send should get call_id=2 - let response_bytes = make_response_bytes(1, Some(vec![0xc0]), None); - let ctx = BridgeCallContext::new( - Box::new(Vec::new()), - Box::new(Cursor::new(response_bytes)), - "session-1".into(), - ); - - let _ = ctx.sync_call("_sync", vec![]); - let id = ctx.async_send("_async", vec![]).unwrap(); - assert_eq!(id, 2); - } - - #[test] - fn channel_runtime_event_sender_delivers_frames() { - let (tx, rx) = crossbeam_channel::unbounded(); - let sender = super::ChannelRuntimeEventSender::new(tx, None); - - let event = RuntimeEvent::BridgeCall { - session_id: "sess-1".into(), - call_id: 42, - method: "_fsReadFile".into(), - payload: vec![0x01, 0x02], - }; - sender.send_event(event.clone()).expect("send_event"); - - // Verify the received event matches without any BinaryFrame hop. - let received = rx.recv().expect("recv"); - assert_eq!(received.output_generation, None); - assert_eq!(received.event, event); - } - - #[test] - fn channel_runtime_event_sender_no_mutex_contention() { - // Multiple senders can send concurrently without blocking each other - let (tx, rx) = crossbeam_channel::unbounded(); - let handles: Vec<_> = (0..4) - .map(|i| { - let sender = super::ChannelRuntimeEventSender::new(tx.clone(), None); - std::thread::spawn(move || { - for j in 0..10 { - let event = RuntimeEvent::BridgeCall { - session_id: format!("sess-{}", i), - call_id: (i * 100 + j) as u64, - method: "_fn".into(), - payload: vec![], - }; - sender.send_event(event).expect("send_event"); - } - }) - }) - .collect(); - drop(tx); // Drop original sender so rx closes when threads finish - - for h in handles { - h.join().expect("thread join"); - } - - // All 40 frames should arrive and be decodable - let mut count = 0; - while rx.try_recv().is_ok() { - count += 1; - } - assert_eq!(count, 40); - } - - #[test] - fn channel_runtime_event_sender_with_bridge_context() { - // Verify BridgeCallContext works with ChannelRuntimeEventSender end-to-end - let (tx, rx) = crossbeam_channel::unbounded(); - - // Pre-serialize a BridgeResponse for the reader - let response_bytes = make_response_bytes(1, Some(vec![0xAB, 0xCD]), None); - let router: super::CallIdRouter = Arc::new(Mutex::new(HashMap::new())); - - let ctx = BridgeCallContext::with_receiver( - Box::new(super::ChannelRuntimeEventSender::new(tx, None)), - Box::new(super::ReaderBridgeResponseReceiver::new(Box::new( - Cursor::new(response_bytes), - ))), - "test-session".into(), - router, - Arc::new(std::sync::atomic::AtomicU64::new(1)), - ); - - let result = ctx.sync_call("_fsReadFile", vec![0x01]).unwrap(); - assert_eq!(result, Some(vec![0xAB, 0xCD])); - - // Verify the BridgeCall went through the channel - let event = rx.recv().expect("recv bridge call"); - match event.event { - RuntimeEvent::BridgeCall { method, .. } => assert_eq!(method, "_fsReadFile"), - _ => panic!("expected BridgeCall"), - } - } - - #[test] - fn sync_call_success_clears_call_id_route() { - let (tx, _rx) = crossbeam_channel::unbounded(); - let response_bytes = make_response_bytes(1, Some(vec![0xAB, 0xCD]), None); - let router: super::CallIdRouter = Arc::new(Mutex::new(HashMap::new())); - - let ctx = BridgeCallContext::with_receiver( - Box::new(super::ChannelRuntimeEventSender::new(tx, None)), - Box::new(super::ReaderBridgeResponseReceiver::new(Box::new( - Cursor::new(response_bytes), - ))), - "test-session".into(), - Arc::clone(&router), - Arc::new(std::sync::atomic::AtomicU64::new(1)), - ); - - let result = ctx.sync_call("_fsReadFile", vec![0x01]).unwrap(); - assert_eq!(result, Some(vec![0xAB, 0xCD])); - assert!( - router.lock().unwrap().is_empty(), - "sync bridge response completion should clear the call_id route" - ); - } - - #[test] - fn writer_runtime_event_sender_serializes_events() { - let (tx, rx) = crossbeam_channel::unbounded(); - let sender = super::ChannelRuntimeEventSender::new(tx, None); - - // Send multiple frames — buffer grows to high-water mark - for i in 0..5 { - let event = RuntimeEvent::BridgeCall { - session_id: "sess-1".into(), - call_id: i, - method: "_fn".into(), - payload: vec![0xAA; 100 * (i as usize + 1)], - }; - sender.send_event(event).expect("send_event"); - } - - // Verify all events arrive with their payload intact. - for i in 0..5u64 { - let decoded = rx.recv().expect("recv"); - match decoded.event { - RuntimeEvent::BridgeCall { - call_id, payload, .. - } => { - assert_eq!(call_id, i); - assert_eq!(payload.len(), 100 * (i as usize + 1)); - } - _ => panic!("expected BridgeCall"), - } - } - - // Small follow-up events still go through the same sender. - let small = RuntimeEvent::Log { - session_id: "s".into(), - channel: 0, - message: "x".into(), - }; - sender.send_event(small.clone()).expect("send_event"); - let decoded = rx.recv().expect("recv"); - assert_eq!(decoded.event, small); - } - - #[test] - fn stub_context_panics_on_sync_call() { - let ctx = BridgeCallContext::stub(); - let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - let _ = ctx.sync_call("_fsReadFile", vec![]); - })); - assert!(result.is_err(), "stub sync_call should panic"); - } - - #[test] - fn stub_context_panics_on_async_send() { - let ctx = BridgeCallContext::stub(); - let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - let _ = ctx.async_send("_asyncFn", vec![]); - })); - assert!(result.is_err(), "stub async_send should panic"); - } -} diff --git a/crates/v8-runtime/src/ipc.rs b/crates/v8-runtime/src/ipc.rs deleted file mode 100644 index 6b7562060..000000000 --- a/crates/v8-runtime/src/ipc.rs +++ /dev/null @@ -1,34 +0,0 @@ -// IPC message types used by the execution engine. -// -// The binary header wire format (ipc_binary.rs) handles serialization; -// these types are used in-process only (no serde needed). - -use std::collections::HashMap; - -/// Process configuration injected into the V8 global as _processConfig -#[derive(Debug, Clone, PartialEq)] -pub struct ProcessConfig { - pub cwd: String, - pub env: HashMap, - pub timing_mitigation: String, - pub frozen_time_ms: Option, - pub high_resolution_time: bool, -} - -/// OS configuration injected into the V8 global as _osConfig -#[derive(Debug, Clone, PartialEq)] -pub struct OsConfig { - pub homedir: String, - pub tmpdir: String, - pub platform: String, - pub arch: String, -} - -/// Structured error information from V8 execution -#[derive(Debug, Clone, PartialEq)] -pub struct ExecutionError { - pub error_type: String, - pub message: String, - pub stack: String, - pub code: Option, -} diff --git a/crates/v8-runtime/src/ipc_binary.rs b/crates/v8-runtime/src/ipc_binary.rs deleted file mode 100644 index f86bd0d6a..000000000 --- a/crates/v8-runtime/src/ipc_binary.rs +++ /dev/null @@ -1,1577 +0,0 @@ -// Binary header IPC framing — custom wire format for all message types. -// -// Wire format per frame: -// [4B total_len (u32 BE, excludes self)] -// [1B msg_type] -// [1B sid_len (N)] -// [N bytes session_id (UTF-8)] -// [... type-specific fixed fields ...] -// [M bytes payload (rest of frame)] -// -// Existing ipc.rs (MessagePack framing) is left unchanged. - -use std::io::{self, Read, Write}; - -/// Maximum frame payload: 64 MB (same limit as MessagePack framing). -const MAX_FRAME_SIZE: u32 = 64 * 1024 * 1024; - -// Host → Rust message type codes -const MSG_AUTHENTICATE: u8 = 0x01; -const MSG_CREATE_SESSION: u8 = 0x02; -const MSG_DESTROY_SESSION: u8 = 0x03; -const MSG_INJECT_GLOBALS: u8 = 0x04; -const MSG_EXECUTE: u8 = 0x05; -const MSG_BRIDGE_RESPONSE: u8 = 0x06; -const MSG_STREAM_EVENT: u8 = 0x07; -const MSG_TERMINATE_EXECUTION: u8 = 0x08; -const MSG_WARM_SNAPSHOT: u8 = 0x09; - -// Rust → Host message type codes -const MSG_BRIDGE_CALL: u8 = 0x81; -const MSG_EXECUTION_RESULT: u8 = 0x82; -const MSG_LOG: u8 = 0x83; -const MSG_STREAM_CALLBACK: u8 = 0x84; - -// ExecutionResult flags -const FLAG_HAS_EXPORTS: u8 = 0x01; -const FLAG_HAS_ERROR: u8 = 0x02; - -/// A decoded binary frame — all fields are borrowed or owned depending on use. -#[derive(Debug, Clone, PartialEq)] -pub enum BinaryFrame { - // Host → Rust - Authenticate { - token: String, - }, - CreateSession { - session_id: String, - heap_limit_mb: u32, - cpu_time_limit_ms: u32, - wall_clock_limit_ms: u32, - }, - DestroySession { - session_id: String, - }, - InjectGlobals { - session_id: String, - payload: Vec, // V8-serialized { processConfig, osConfig } - }, - Execute { - session_id: String, - mode: u8, // 0 = exec, 1 = run - file_path: String, - bridge_code: String, - post_restore_script: String, - // Optional agent-SDK bundle evaluated into the per-sidecar snapshot alongside - // the bridge (empty = bridge-only snapshot, unchanged behavior). The snapshot - // is cached process-wide keyed by sha256(bridge_code + userland_code). - userland_code: String, - high_resolution_time: bool, - user_code: String, - }, - BridgeResponse { - session_id: String, - call_id: u64, - status: u8, // 0 = success, 1 = error - payload: Vec, // V8-serialized result OR UTF-8 error message - }, - StreamEvent { - session_id: String, - event_type: String, - payload: Vec, // V8-serialized payload - }, - TerminateExecution { - session_id: String, - }, - WarmSnapshot { - bridge_code: String, - // Optional agent-SDK bundle to pre-warm into the snapshot (empty = bridge-only). - userland_code: String, - }, - - // Rust → Host - BridgeCall { - session_id: String, - call_id: u64, - method: String, - payload: Vec, // V8-serialized args - }, - ExecutionResult { - session_id: String, - exit_code: i32, - exports: Option>, - error: Option, - }, - Log { - session_id: String, - channel: u8, // 0 = stdout, 1 = stderr - message: String, - }, - StreamCallback { - session_id: String, - callback_type: String, - payload: Vec, // V8-serialized payload - }, -} - -/// Structured error in binary format. -#[derive(Debug, Clone, PartialEq)] -pub struct ExecutionErrorBin { - pub error_type: String, - pub message: String, - pub stack: String, - pub code: String, // empty string = no code -} - -/// Encode a binary frame into a provided buffer (length prefix + body). -/// The buffer is cleared first; capacity is preserved across calls. -/// Used by per-session buffering to avoid per-call allocation. -pub fn encode_frame_into(buf: &mut Vec, frame: &BinaryFrame) -> io::Result<()> { - buf.clear(); - // Reserve 4 bytes for the length prefix (filled after body) - buf.extend_from_slice(&[0, 0, 0, 0]); - encode_body(buf, frame)?; - - let total_len = buf.len() - 4; - if total_len > MAX_FRAME_SIZE as usize { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("frame size {total_len} exceeds maximum {MAX_FRAME_SIZE}"), - )); - } - buf[..4].copy_from_slice(&(total_len as u32).to_be_bytes()); - Ok(()) -} - -/// Serialize a binary frame to a complete byte vector (length prefix + body). -/// Used by per-session buffering to build the frame without holding any shared lock. -pub fn frame_to_bytes(frame: &BinaryFrame) -> io::Result> { - let mut buf = Vec::new(); - encode_frame_into(&mut buf, frame)?; - Ok(buf) -} - -/// Write a binary frame to a writer. -pub fn write_frame(writer: &mut W, frame: &BinaryFrame) -> io::Result<()> { - let bytes = frame_to_bytes(frame)?; - writer.write_all(&bytes)?; - Ok(()) -} - -/// Read a binary frame from a reader. -pub fn read_frame(reader: &mut R) -> io::Result { - let mut len_buf = [0u8; 4]; - reader.read_exact(&mut len_buf)?; - let total_len = u32::from_be_bytes(len_buf); - - if total_len > MAX_FRAME_SIZE { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("frame size {total_len} exceeds maximum {MAX_FRAME_SIZE}"), - )); - } - - let mut buf = vec![0u8; total_len as usize]; - reader.read_exact(&mut buf)?; - decode_body(&buf) -} - -/// Extract session_id from raw frame bytes without full deserialization. -/// `raw` starts at the first byte after the 4-byte length prefix (i.e. the msg_type byte). -/// Returns None for Authenticate (which has no session_id). -#[allow(dead_code)] -pub fn extract_session_id(raw: &[u8]) -> io::Result> { - if raw.len() < 2 { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "frame too short", - )); - } - let msg_type = raw[0]; - if msg_type == MSG_AUTHENTICATE || msg_type == MSG_WARM_SNAPSHOT { - return Ok(None); - } - let sid_len = raw[1] as usize; - if raw.len() < 2 + sid_len { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "frame too short for session_id", - )); - } - let sid = std::str::from_utf8(&raw[2..2 + sid_len]) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - Ok(Some(sid)) -} - -// -- Internal encode/decode -- - -fn encode_body(buf: &mut Vec, frame: &BinaryFrame) -> io::Result<()> { - match frame { - BinaryFrame::Authenticate { token } => { - buf.push(MSG_AUTHENTICATE); - // Authenticate has no session_id — sid_len = 0 - buf.push(0); - buf.extend_from_slice(token.as_bytes()); - } - BinaryFrame::CreateSession { - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - } => { - buf.push(MSG_CREATE_SESSION); - write_session_id(buf, session_id)?; - buf.extend_from_slice(&heap_limit_mb.to_be_bytes()); - buf.extend_from_slice(&cpu_time_limit_ms.to_be_bytes()); - buf.extend_from_slice(&wall_clock_limit_ms.to_be_bytes()); - } - BinaryFrame::DestroySession { session_id } => { - buf.push(MSG_DESTROY_SESSION); - write_session_id(buf, session_id)?; - } - BinaryFrame::InjectGlobals { - session_id, - payload, - } => { - buf.push(MSG_INJECT_GLOBALS); - write_session_id(buf, session_id)?; - buf.extend_from_slice(payload); - } - BinaryFrame::Execute { - session_id, - mode, - file_path, - bridge_code, - post_restore_script, - userland_code, - high_resolution_time, - user_code, - } => { - buf.push(MSG_EXECUTE); - write_session_id(buf, session_id)?; - buf.push(*mode); - // file_path length (u16 BE) - write_len_prefixed_u16(buf, file_path)?; - // bridge_code length (u32 BE) - let bc_bytes = bridge_code.as_bytes(); - buf.extend_from_slice(&(bc_bytes.len() as u32).to_be_bytes()); - buf.extend_from_slice(bc_bytes); - // post_restore_script length (u32 BE) - let prs_bytes = post_restore_script.as_bytes(); - buf.extend_from_slice(&(prs_bytes.len() as u32).to_be_bytes()); - buf.extend_from_slice(prs_bytes); - // userland_code length (u32 BE) - let ul_bytes = userland_code.as_bytes(); - buf.extend_from_slice(&(ul_bytes.len() as u32).to_be_bytes()); - buf.extend_from_slice(ul_bytes); - buf.push(u8::from(*high_resolution_time)); - // user_code (rest of frame) - buf.extend_from_slice(user_code.as_bytes()); - } - BinaryFrame::BridgeResponse { - session_id, - call_id, - status, - payload, - } => { - buf.push(MSG_BRIDGE_RESPONSE); - write_session_id(buf, session_id)?; - buf.extend_from_slice(&call_id.to_be_bytes()); - buf.push(*status); - buf.extend_from_slice(payload); - } - BinaryFrame::StreamEvent { - session_id, - event_type, - payload, - } => { - buf.push(MSG_STREAM_EVENT); - write_session_id(buf, session_id)?; - write_len_prefixed_u16(buf, event_type)?; - buf.extend_from_slice(payload); - } - BinaryFrame::TerminateExecution { session_id } => { - buf.push(MSG_TERMINATE_EXECUTION); - write_session_id(buf, session_id)?; - } - BinaryFrame::WarmSnapshot { - bridge_code, - userland_code, - } => { - buf.push(MSG_WARM_SNAPSHOT); - buf.push(0); // no session_id - let bc_bytes = bridge_code.as_bytes(); - buf.extend_from_slice(&(bc_bytes.len() as u32).to_be_bytes()); - buf.extend_from_slice(bc_bytes); - // userland_code length (u32 BE) + bytes (rest) - let ul_bytes = userland_code.as_bytes(); - buf.extend_from_slice(&(ul_bytes.len() as u32).to_be_bytes()); - buf.extend_from_slice(ul_bytes); - } - BinaryFrame::BridgeCall { - session_id, - call_id, - method, - payload, - } => { - buf.push(MSG_BRIDGE_CALL); - write_session_id(buf, session_id)?; - buf.extend_from_slice(&call_id.to_be_bytes()); - write_len_prefixed_u16(buf, method)?; - buf.extend_from_slice(payload); - } - BinaryFrame::ExecutionResult { - session_id, - exit_code, - exports, - error, - } => { - buf.push(MSG_EXECUTION_RESULT); - write_session_id(buf, session_id)?; - buf.extend_from_slice(&exit_code.to_be_bytes()); - let mut flags: u8 = 0; - if exports.is_some() { - flags |= FLAG_HAS_EXPORTS; - } - if error.is_some() { - flags |= FLAG_HAS_ERROR; - } - buf.push(flags); - if let Some(exp) = exports { - buf.extend_from_slice(&(exp.len() as u32).to_be_bytes()); - buf.extend_from_slice(exp); - } - if let Some(err) = error { - write_len_prefixed_u16(buf, &err.error_type)?; - write_len_prefixed_u16(buf, &err.message)?; - write_len_prefixed_u16(buf, &err.stack)?; - write_len_prefixed_u16(buf, &err.code)?; - } - } - BinaryFrame::Log { - session_id, - channel, - message, - } => { - buf.push(MSG_LOG); - write_session_id(buf, session_id)?; - buf.push(*channel); - buf.extend_from_slice(message.as_bytes()); - } - BinaryFrame::StreamCallback { - session_id, - callback_type, - payload, - } => { - buf.push(MSG_STREAM_CALLBACK); - write_session_id(buf, session_id)?; - write_len_prefixed_u16(buf, callback_type)?; - buf.extend_from_slice(payload); - } - } - Ok(()) -} - -fn decode_body(buf: &[u8]) -> io::Result { - if buf.is_empty() { - return Err(io::Error::new(io::ErrorKind::InvalidData, "empty frame")); - } - - let msg_type = buf[0]; - let mut pos = 1; - - // Read the session_id field uniformly. Sessionless frame types validate - // that it is empty after the message type is known. - let sid_len = read_u8(buf, &mut pos)? as usize; - let session_id = read_utf8(buf, &mut pos, sid_len)?; - - match msg_type { - MSG_AUTHENTICATE => { - ensure_no_session_id(&session_id, "Authenticate")?; - // Token is rest of frame after sid (sid is empty for Authenticate) - let remaining = buf.len() - pos; - let token = read_utf8(buf, &mut pos, remaining)?; - Ok(BinaryFrame::Authenticate { token }) - } - MSG_CREATE_SESSION => { - let heap_limit_mb = read_u32(buf, &mut pos)?; - let cpu_time_limit_ms = read_u32(buf, &mut pos)?; - let wall_clock_limit_ms = read_u32(buf, &mut pos)?; - ensure_frame_consumed(buf, pos)?; - Ok(BinaryFrame::CreateSession { - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - }) - } - MSG_DESTROY_SESSION => { - ensure_frame_consumed(buf, pos)?; - Ok(BinaryFrame::DestroySession { session_id }) - } - MSG_INJECT_GLOBALS => { - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::InjectGlobals { - session_id, - payload, - }) - } - MSG_EXECUTE => { - let mode = read_u8(buf, &mut pos)?; - let fp_len = read_u16(buf, &mut pos)? as usize; - let file_path = read_utf8(buf, &mut pos, fp_len)?; - let bc_len = read_u32(buf, &mut pos)? as usize; - let bridge_code = read_utf8(buf, &mut pos, bc_len)?; - let prs_len = read_u32(buf, &mut pos)? as usize; - let post_restore_script = read_utf8(buf, &mut pos, prs_len)?; - let ul_len = read_u32(buf, &mut pos)? as usize; - let userland_code = read_utf8(buf, &mut pos, ul_len)?; - let high_resolution_time = read_u8(buf, &mut pos)? != 0; - let remaining = buf.len() - pos; - let user_code = read_utf8(buf, &mut pos, remaining)?; - Ok(BinaryFrame::Execute { - session_id, - mode, - file_path, - bridge_code, - post_restore_script, - userland_code, - high_resolution_time, - user_code, - }) - } - MSG_BRIDGE_RESPONSE => { - let call_id = read_u64(buf, &mut pos)?; - let status = read_u8(buf, &mut pos)?; - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::BridgeResponse { - session_id, - call_id, - status, - payload, - }) - } - MSG_STREAM_EVENT => { - let et_len = read_u16(buf, &mut pos)? as usize; - let event_type = read_utf8(buf, &mut pos, et_len)?; - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::StreamEvent { - session_id, - event_type, - payload, - }) - } - MSG_TERMINATE_EXECUTION => { - ensure_frame_consumed(buf, pos)?; - Ok(BinaryFrame::TerminateExecution { session_id }) - } - MSG_WARM_SNAPSHOT => { - ensure_no_session_id(&session_id, "WarmSnapshot")?; - let bc_len = read_u32(buf, &mut pos)? as usize; - let bridge_code = read_utf8(buf, &mut pos, bc_len)?; - let ul_len = read_u32(buf, &mut pos)? as usize; - let userland_code = read_utf8(buf, &mut pos, ul_len)?; - ensure_frame_consumed(buf, pos)?; - Ok(BinaryFrame::WarmSnapshot { - bridge_code, - userland_code, - }) - } - MSG_BRIDGE_CALL => { - let call_id = read_u64(buf, &mut pos)?; - let m_len = read_u16(buf, &mut pos)? as usize; - let method = read_utf8(buf, &mut pos, m_len)?; - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::BridgeCall { - session_id, - call_id, - method, - payload, - }) - } - MSG_EXECUTION_RESULT => { - let exit_code = read_i32(buf, &mut pos)?; - let flags = read_u8(buf, &mut pos)?; - if flags & !(FLAG_HAS_EXPORTS | FLAG_HAS_ERROR) != 0 { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("unknown ExecutionResult flags: 0x{flags:02x}"), - )); - } - let exports = if flags & FLAG_HAS_EXPORTS != 0 { - let exp_len = read_u32(buf, &mut pos)? as usize; - let data = read_bytes(buf, &mut pos, exp_len)?; - Some(data) - } else { - None - }; - let error = if flags & FLAG_HAS_ERROR != 0 { - let error_type = read_len_prefixed_u16(buf, &mut pos)?; - let message = read_len_prefixed_u16(buf, &mut pos)?; - let stack = read_len_prefixed_u16(buf, &mut pos)?; - let code = read_len_prefixed_u16(buf, &mut pos)?; - Some(ExecutionErrorBin { - error_type, - message, - stack, - code, - }) - } else { - None - }; - ensure_frame_consumed(buf, pos)?; - Ok(BinaryFrame::ExecutionResult { - session_id, - exit_code, - exports, - error, - }) - } - MSG_LOG => { - let channel = read_u8(buf, &mut pos)?; - let remaining = buf.len() - pos; - let message = read_utf8(buf, &mut pos, remaining)?; - Ok(BinaryFrame::Log { - session_id, - channel, - message, - }) - } - MSG_STREAM_CALLBACK => { - let ct_len = read_u16(buf, &mut pos)? as usize; - let callback_type = read_utf8(buf, &mut pos, ct_len)?; - let payload = buf[pos..].to_vec(); - Ok(BinaryFrame::StreamCallback { - session_id, - callback_type, - payload, - }) - } - _ => Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("unknown message type: 0x{msg_type:02x}"), - )), - } -} - -// -- Primitive read/write helpers -- - -fn write_session_id(buf: &mut Vec, sid: &str) -> io::Result<()> { - let bytes = sid.as_bytes(); - if bytes.len() > 255 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("session ID byte length {} exceeds u8 max 255", bytes.len()), - )); - } - buf.push(bytes.len() as u8); - buf.extend_from_slice(bytes); - Ok(()) -} - -fn write_len_prefixed_u16(buf: &mut Vec, s: &str) -> io::Result<()> { - let bytes = s.as_bytes(); - if bytes.len() > 0xFFFF { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("string byte length {} exceeds u16 max 65535", bytes.len()), - )); - } - buf.extend_from_slice(&(bytes.len() as u16).to_be_bytes()); - buf.extend_from_slice(bytes); - Ok(()) -} - -fn ensure_no_session_id(session_id: &str, frame_name: &str) -> io::Result<()> { - if session_id.is_empty() { - return Ok(()); - } - Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("{frame_name} frame must not include a session_id"), - )) -} - -fn ensure_frame_consumed(buf: &[u8], pos: usize) -> io::Result<()> { - if pos == buf.len() { - return Ok(()); - } - Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("frame has {} trailing byte(s)", buf.len() - pos), - )) -} - -fn read_u8(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos >= buf.len() { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "unexpected end of frame", - )); - } - let v = buf[*pos]; - *pos += 1; - Ok(v) -} - -fn read_u16(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos + 2 > buf.len() { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "unexpected end of frame", - )); - } - let v = u16::from_be_bytes([buf[*pos], buf[*pos + 1]]); - *pos += 2; - Ok(v) -} - -fn read_u32(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos + 4 > buf.len() { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "unexpected end of frame", - )); - } - let v = u32::from_be_bytes([buf[*pos], buf[*pos + 1], buf[*pos + 2], buf[*pos + 3]]); - *pos += 4; - Ok(v) -} - -fn read_u64(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos + 8 > buf.len() { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "unexpected end of frame", - )); - } - let v = u64::from_be_bytes([ - buf[*pos], - buf[*pos + 1], - buf[*pos + 2], - buf[*pos + 3], - buf[*pos + 4], - buf[*pos + 5], - buf[*pos + 6], - buf[*pos + 7], - ]); - *pos += 8; - Ok(v) -} - -fn read_i32(buf: &[u8], pos: &mut usize) -> io::Result { - if *pos + 4 > buf.len() { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "unexpected end of frame", - )); - } - let v = i32::from_be_bytes([buf[*pos], buf[*pos + 1], buf[*pos + 2], buf[*pos + 3]]); - *pos += 4; - Ok(v) -} - -fn read_bytes(buf: &[u8], pos: &mut usize, len: usize) -> io::Result> { - if *pos + len > buf.len() { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "unexpected end of frame", - )); - } - let v = buf[*pos..*pos + len].to_vec(); - *pos += len; - Ok(v) -} - -fn read_utf8(buf: &[u8], pos: &mut usize, len: usize) -> io::Result { - let bytes = read_bytes(buf, pos, len)?; - String::from_utf8(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) -} - -fn read_len_prefixed_u16(buf: &[u8], pos: &mut usize) -> io::Result { - let len = read_u16(buf, pos)? as usize; - read_utf8(buf, pos, len) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn roundtrip(frame: &BinaryFrame) { - let mut buf = Vec::new(); - write_frame(&mut buf, frame).expect("write_frame"); - let mut cursor = std::io::Cursor::new(&buf); - let decoded = read_frame(&mut cursor).expect("read_frame"); - assert_eq!(&decoded, frame); - } - - fn read_raw_body(body: Vec) -> io::Result { - let mut buf = Vec::new(); - buf.extend_from_slice(&(body.len() as u32).to_be_bytes()); - buf.extend_from_slice(&body); - read_frame(&mut std::io::Cursor::new(buf)) - } - - // -- Host → Rust message types -- - - #[test] - fn roundtrip_authenticate() { - roundtrip(&BinaryFrame::Authenticate { - token: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4".into(), - }); - } - - #[test] - fn roundtrip_create_session() { - roundtrip(&BinaryFrame::CreateSession { - session_id: "sess-abc-123".into(), - heap_limit_mb: 128, - cpu_time_limit_ms: 5000, - wall_clock_limit_ms: 9000, - }); - } - - #[test] - fn roundtrip_create_session_no_limits() { - roundtrip(&BinaryFrame::CreateSession { - session_id: "sess-1".into(), - heap_limit_mb: 0, - cpu_time_limit_ms: 0, - wall_clock_limit_ms: 0, - }); - } - - #[test] - fn roundtrip_destroy_session() { - roundtrip(&BinaryFrame::DestroySession { - session_id: "sess-7".into(), - }); - } - - #[test] - fn roundtrip_inject_globals() { - roundtrip(&BinaryFrame::InjectGlobals { - session_id: "sess-3".into(), - payload: vec![0x01, 0x02, 0x03, 0x04, 0x05], - }); - } - - #[test] - fn roundtrip_execute_exec_mode() { - roundtrip(&BinaryFrame::Execute { - session_id: "sess-1".into(), - mode: 0, - file_path: "".into(), - bridge_code: "(function(){ /* bridge */ })()".into(), - post_restore_script: "".into(), - userland_code: String::new(), - high_resolution_time: false, - user_code: "console.log('hello')".into(), - }); - } - - #[test] - fn roundtrip_execute_run_mode() { - roundtrip(&BinaryFrame::Execute { - session_id: "sess-2".into(), - mode: 1, - file_path: "/app/index.mjs".into(), - bridge_code: "(function(){ /* bridge */ })()".into(), - post_restore_script: "__runtimeApplyConfig({})".into(), - userland_code: String::new(), - high_resolution_time: false, - user_code: "export default 42".into(), - }); - } - - #[test] - fn roundtrip_bridge_response_success() { - roundtrip(&BinaryFrame::BridgeResponse { - session_id: "sess-4".into(), - call_id: 100, - status: 0, - payload: vec![0x93, 0x01, 0x02, 0x03], - }); - } - - #[test] - fn roundtrip_bridge_response_error() { - roundtrip(&BinaryFrame::BridgeResponse { - session_id: "sess-5".into(), - call_id: 101, - status: 1, - payload: b"ENOENT: no such file".to_vec(), - }); - } - - #[test] - fn roundtrip_stream_event() { - roundtrip(&BinaryFrame::StreamEvent { - session_id: "sess-5".into(), - event_type: "child_stdout".into(), - payload: vec![0x48, 0x65, 0x6c, 0x6c, 0x6f], - }); - } - - #[test] - fn roundtrip_terminate_execution() { - roundtrip(&BinaryFrame::TerminateExecution { - session_id: "sess-6".into(), - }); - } - - // -- Rust → Host message types -- - - #[test] - fn roundtrip_bridge_call() { - roundtrip(&BinaryFrame::BridgeCall { - session_id: "sess-1".into(), - call_id: 200, - method: "_fsReadFile".into(), - payload: vec![0x91, 0xa5, 0x2f, 0x74, 0x6d, 0x70], - }); - } - - #[test] - fn roundtrip_execution_result_success() { - roundtrip(&BinaryFrame::ExecutionResult { - session_id: "sess-1".into(), - exit_code: 0, - exports: Some(vec![0xc0]), - error: None, - }); - } - - #[test] - fn roundtrip_execution_result_error() { - roundtrip(&BinaryFrame::ExecutionResult { - session_id: "sess-2".into(), - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "TypeError".into(), - message: "Cannot read properties of undefined".into(), - stack: "TypeError: Cannot read properties of undefined\n at main.js:1:5".into(), - code: "".into(), - }), - }); - } - - #[test] - fn roundtrip_execution_result_error_with_code() { - roundtrip(&BinaryFrame::ExecutionResult { - session_id: "sess-3".into(), - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message: "Cannot find module './missing'".into(), - stack: "Error: Cannot find module './missing'\n at resolve (node:internal)" - .into(), - code: "ERR_MODULE_NOT_FOUND".into(), - }), - }); - } - - #[test] - fn roundtrip_execution_result_exports_and_error() { - roundtrip(&BinaryFrame::ExecutionResult { - session_id: "sess-4".into(), - exit_code: 1, - exports: Some(vec![0x01, 0x02]), - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message: "partial failure".into(), - stack: "".into(), - code: "".into(), - }), - }); - } - - #[test] - fn roundtrip_execution_result_no_exports_no_error() { - roundtrip(&BinaryFrame::ExecutionResult { - session_id: "sess-5".into(), - exit_code: 0, - exports: None, - error: None, - }); - } - - #[test] - fn roundtrip_log_stdout() { - roundtrip(&BinaryFrame::Log { - session_id: "sess-1".into(), - channel: 0, - message: "hello world\n".into(), - }); - } - - #[test] - fn roundtrip_log_stderr() { - roundtrip(&BinaryFrame::Log { - session_id: "sess-1".into(), - channel: 1, - message: "warning: deprecated API\n".into(), - }); - } - - #[test] - fn roundtrip_stream_callback() { - roundtrip(&BinaryFrame::StreamCallback { - session_id: "sess-1".into(), - callback_type: "child_dispatch".into(), - payload: vec![0x92, 0x01, 0xa3, 0x66, 0x6f, 0x6f], - }); - } - - // -- WarmSnapshot -- - - #[test] - fn roundtrip_warm_snapshot() { - roundtrip(&BinaryFrame::WarmSnapshot { - bridge_code: "(function(){ /* bridge IIFE */ })()".into(), - userland_code: String::new(), - }); - } - - #[test] - fn roundtrip_warm_snapshot_empty_bridge_code() { - roundtrip(&BinaryFrame::WarmSnapshot { - bridge_code: "".into(), - userland_code: String::new(), - }); - } - - #[test] - fn roundtrip_warm_snapshot_large_bridge_code() { - roundtrip(&BinaryFrame::WarmSnapshot { - bridge_code: "x".repeat(100_000), - userland_code: String::new(), - }); - } - - #[test] - fn extract_session_id_warm_snapshot_returns_none() { - let frame = BinaryFrame::WarmSnapshot { - bridge_code: "bridge()".into(), - userland_code: String::new(), - }; - let mut buf = Vec::new(); - write_frame(&mut buf, &frame).expect("write"); - let raw = &buf[4..]; - let result = extract_session_id(raw).expect("extract"); - assert_eq!(result, None); - } - - // -- Edge cases -- - - #[test] - fn roundtrip_empty_payloads() { - roundtrip(&BinaryFrame::BridgeResponse { - session_id: "s".into(), - call_id: 0, - status: 0, - payload: vec![], - }); - roundtrip(&BinaryFrame::StreamEvent { - session_id: "s".into(), - event_type: "".into(), - payload: vec![], - }); - roundtrip(&BinaryFrame::BridgeCall { - session_id: "s".into(), - call_id: 0, - method: "".into(), - payload: vec![], - }); - roundtrip(&BinaryFrame::InjectGlobals { - session_id: "s".into(), - payload: vec![], - }); - } - - #[test] - fn roundtrip_empty_session_id() { - roundtrip(&BinaryFrame::DestroySession { - session_id: "".into(), - }); - } - - #[test] - fn roundtrip_large_binary_payload() { - roundtrip(&BinaryFrame::BridgeResponse { - session_id: "sess-big".into(), - call_id: 42, - status: 0, - payload: vec![0xAA; 1024], - }); - } - - // -- Framing validation -- - - #[test] - fn frame_length_prefix_is_big_endian() { - let frame = BinaryFrame::DestroySession { - session_id: "x".into(), - }; - let mut buf = Vec::new(); - write_frame(&mut buf, &frame).expect("write"); - let len = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]); - assert_eq!(len as usize, buf.len() - 4); - } - - #[test] - fn multiple_frames_in_stream() { - let frames = vec![ - BinaryFrame::CreateSession { - session_id: "a".into(), - heap_limit_mb: 64, - cpu_time_limit_ms: 1000, - wall_clock_limit_ms: 0, - }, - BinaryFrame::Execute { - session_id: "a".into(), - mode: 0, - file_path: "".into(), - bridge_code: "bridge()".into(), - post_restore_script: "".into(), - userland_code: String::new(), - high_resolution_time: false, - user_code: "1+1".into(), - }, - BinaryFrame::DestroySession { - session_id: "a".into(), - }, - ]; - let mut buf = Vec::new(); - for f in &frames { - write_frame(&mut buf, f).expect("write"); - } - let mut cursor = std::io::Cursor::new(&buf); - for f in &frames { - let decoded = read_frame(&mut cursor).expect("read"); - assert_eq!(&decoded, f); - } - } - - #[test] - fn reject_oversized_frame() { - let oversized_len: u32 = 64 * 1024 * 1024 + 1; - let mut buf = Vec::new(); - buf.extend_from_slice(&oversized_len.to_be_bytes()); - buf.extend_from_slice(&[0u8; 16]); - let mut cursor = std::io::Cursor::new(&buf); - let result = read_frame(&mut cursor); - assert!(result.is_err()); - let err = result.unwrap_err(); - assert_eq!(err.kind(), io::ErrorKind::InvalidData); - assert!(err.to_string().contains("exceeds maximum")); - } - - #[test] - fn reject_unknown_message_type() { - // Craft a frame with unknown message type 0xFF - let body = vec![0xFF, 0x00]; // msg_type=0xFF, sid_len=0 - let result = read_raw_body(body); - assert!(result.is_err()); - assert!(result - .unwrap_err() - .to_string() - .contains("unknown message type")); - } - - #[test] - fn reject_session_id_on_sessionless_frames() { - let authenticate = read_raw_body(vec![MSG_AUTHENTICATE, 1, b's', b't']); - assert!(authenticate.is_err()); - assert!(authenticate - .unwrap_err() - .to_string() - .contains("must not include a session_id")); - - let warm_snapshot = read_raw_body(vec![MSG_WARM_SNAPSHOT, 1, b's', 0, 0, 0, 0]); - assert!(warm_snapshot.is_err()); - assert!(warm_snapshot - .unwrap_err() - .to_string() - .contains("must not include a session_id")); - } - - #[test] - fn reject_trailing_bytes_on_fixed_shape_frames() { - let mut create_session = vec![MSG_CREATE_SESSION, 1, b's']; - create_session.extend_from_slice(&0u32.to_be_bytes()); - create_session.extend_from_slice(&0u32.to_be_bytes()); - create_session.extend_from_slice(&0u32.to_be_bytes()); - create_session.push(0xAA); - - let destroy_session = vec![MSG_DESTROY_SESSION, 1, b's', 0xAA]; - let terminate_execution = vec![MSG_TERMINATE_EXECUTION, 1, b's', 0xAA]; - // WarmSnapshot body: no-session-id flag, bridge_code (u32 len = 0), then - // userland_code (u32 len = 0); a single trailing 0xAA must be rejected. - let warm_snapshot = vec![MSG_WARM_SNAPSHOT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xAA]; - - for body in [ - create_session, - destroy_session, - terminate_execution, - warm_snapshot, - ] { - let result = read_raw_body(body); - assert!(result.is_err()); - assert!(result.unwrap_err().to_string().contains("trailing byte")); - } - } - - #[test] - fn reject_unknown_execution_result_flags() { - let mut body = vec![MSG_EXECUTION_RESULT, 1, b's']; - body.extend_from_slice(&0i32.to_be_bytes()); - body.push(0x80); - - let result = read_raw_body(body); - assert!(result.is_err()); - assert!(result - .unwrap_err() - .to_string() - .contains("unknown ExecutionResult flags")); - } - - #[test] - fn empty_input_returns_eof() { - let buf: Vec = Vec::new(); - let mut cursor = std::io::Cursor::new(&buf); - let result = read_frame(&mut cursor); - assert!(result.is_err()); - assert_eq!(result.unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - } - - // -- Session ID routing -- - - #[test] - fn extract_session_id_from_raw_bytes() { - // Build a BridgeCall frame and verify we can extract session_id from raw bytes - let frame = BinaryFrame::BridgeCall { - session_id: "my-session-42".into(), - call_id: 7, - method: "_fsReadFile".into(), - payload: vec![0x01, 0x02], - }; - let mut buf = Vec::new(); - write_frame(&mut buf, &frame).expect("write"); - - // Raw bytes start after the 4-byte length prefix - let raw = &buf[4..]; - let sid = extract_session_id(raw) - .expect("extract") - .expect("should have sid"); - assert_eq!(sid, "my-session-42"); - } - - #[test] - fn extract_session_id_from_various_types() { - let test_cases: Vec = vec![ - BinaryFrame::CreateSession { - session_id: "sess-create".into(), - heap_limit_mb: 0, - cpu_time_limit_ms: 0, - wall_clock_limit_ms: 0, - }, - BinaryFrame::DestroySession { - session_id: "sess-destroy".into(), - }, - BinaryFrame::Execute { - session_id: "sess-exec".into(), - mode: 0, - file_path: "".into(), - bridge_code: "".into(), - post_restore_script: "".into(), - userland_code: String::new(), - high_resolution_time: false, - user_code: "".into(), - }, - BinaryFrame::BridgeResponse { - session_id: "sess-resp".into(), - call_id: 1, - status: 0, - payload: vec![], - }, - BinaryFrame::ExecutionResult { - session_id: "sess-result".into(), - exit_code: 0, - exports: None, - error: None, - }, - BinaryFrame::Log { - session_id: "sess-log".into(), - channel: 0, - message: "hi".into(), - }, - ]; - - for frame in &test_cases { - let mut buf = Vec::new(); - write_frame(&mut buf, frame).expect("write"); - let raw = &buf[4..]; - let sid = extract_session_id(raw) - .expect("extract") - .expect("should have sid"); - // Verify it matches the expected session_id - let expected = match frame { - BinaryFrame::CreateSession { session_id, .. } - | BinaryFrame::DestroySession { session_id } - | BinaryFrame::Execute { session_id, .. } - | BinaryFrame::BridgeResponse { session_id, .. } - | BinaryFrame::ExecutionResult { session_id, .. } - | BinaryFrame::Log { session_id, .. } => session_id.as_str(), - _ => unreachable!(), - }; - assert_eq!(sid, expected, "session_id mismatch for frame: {:?}", frame); - } - } - - #[test] - fn extract_session_id_authenticate_returns_none() { - let frame = BinaryFrame::Authenticate { - token: "secret-token".into(), - }; - let mut buf = Vec::new(); - write_frame(&mut buf, &frame).expect("write"); - let raw = &buf[4..]; - let result = extract_session_id(raw).expect("extract"); - assert_eq!(result, None); - } - - #[test] - fn extract_session_id_too_short() { - let result = extract_session_id(&[0x02]); // msg_type only, no sid_len - assert!(result.is_err()); - } - - // -- Wire format byte-level verification -- - - #[test] - fn wire_format_message_type_bytes() { - let cases: Vec<(BinaryFrame, u8)> = vec![ - (BinaryFrame::Authenticate { token: "t".into() }, 0x01), - ( - BinaryFrame::CreateSession { - session_id: "s".into(), - heap_limit_mb: 0, - cpu_time_limit_ms: 0, - wall_clock_limit_ms: 0, - }, - 0x02, - ), - ( - BinaryFrame::DestroySession { - session_id: "s".into(), - }, - 0x03, - ), - ( - BinaryFrame::InjectGlobals { - session_id: "s".into(), - payload: vec![], - }, - 0x04, - ), - ( - BinaryFrame::Execute { - session_id: "s".into(), - mode: 0, - file_path: "".into(), - bridge_code: "".into(), - post_restore_script: "".into(), - userland_code: String::new(), - high_resolution_time: false, - user_code: "".into(), - }, - 0x05, - ), - ( - BinaryFrame::BridgeResponse { - session_id: "s".into(), - call_id: 0, - status: 0, - payload: vec![], - }, - 0x06, - ), - ( - BinaryFrame::StreamEvent { - session_id: "s".into(), - event_type: "".into(), - payload: vec![], - }, - 0x07, - ), - ( - BinaryFrame::TerminateExecution { - session_id: "s".into(), - }, - 0x08, - ), - ( - BinaryFrame::WarmSnapshot { - bridge_code: "bridge()".into(), - userland_code: String::new(), - }, - 0x09, - ), - ( - BinaryFrame::BridgeCall { - session_id: "s".into(), - call_id: 0, - method: "".into(), - payload: vec![], - }, - 0x81, - ), - ( - BinaryFrame::ExecutionResult { - session_id: "s".into(), - exit_code: 0, - exports: None, - error: None, - }, - 0x82, - ), - ( - BinaryFrame::Log { - session_id: "s".into(), - channel: 0, - message: "".into(), - }, - 0x83, - ), - ( - BinaryFrame::StreamCallback { - session_id: "s".into(), - callback_type: "".into(), - payload: vec![], - }, - 0x84, - ), - ]; - for (frame, expected_type) in &cases { - let mut buf = Vec::new(); - write_frame(&mut buf, frame).expect("write"); - // Byte 4 (after 4-byte length prefix) is the message type - assert_eq!(buf[4], *expected_type, "type mismatch for: {:?}", frame); - } - } - - // -- frame_to_bytes tests -- - - #[test] - fn frame_to_bytes_matches_write_frame() { - let frame = BinaryFrame::BridgeCall { - session_id: "sess-42".into(), - call_id: 123, - method: "_fsReadFile".into(), - payload: vec![0x01, 0x02, 0x03], - }; - let bytes = frame_to_bytes(&frame).expect("frame_to_bytes"); - let mut buf = Vec::new(); - write_frame(&mut buf, &frame).expect("write_frame"); - assert_eq!(bytes, buf); - } - - #[test] - fn frame_to_bytes_roundtrip() { - let frame = BinaryFrame::ExecutionResult { - session_id: "sess-1".into(), - exit_code: 0, - exports: Some(vec![0xAA, 0xBB]), - error: None, - }; - let bytes = frame_to_bytes(&frame).expect("frame_to_bytes"); - let mut cursor = std::io::Cursor::new(&bytes); - let decoded = read_frame(&mut cursor).expect("read_frame"); - assert_eq!(decoded, frame); - } - - #[test] - fn frame_to_bytes_atomic_no_interleaving() { - // Verify frame_to_bytes produces a single contiguous byte vector - // (no intermediate writes that could interleave) - let frame = BinaryFrame::BridgeCall { - session_id: "s".into(), - call_id: 1, - method: "_fn".into(), - payload: vec![0xFF; 1024], - }; - let bytes = frame_to_bytes(&frame).expect("frame_to_bytes"); - // Length prefix matches body - let len = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize; - assert_eq!(len, bytes.len() - 4); - } - - #[test] - fn encode_frame_into_reuses_buffer_capacity() { - let mut buf = Vec::new(); - let frame = BinaryFrame::BridgeCall { - session_id: "s1".into(), - call_id: 1, - method: "_fn".into(), - payload: vec![0xAA; 512], - }; - - // First encode grows the buffer - encode_frame_into(&mut buf, &frame).expect("encode"); - let first_bytes = buf.clone(); - let cap_after_first = buf.capacity(); - assert!(cap_after_first >= buf.len()); - - // Second encode reuses capacity (no new allocation if same size) - let frame2 = BinaryFrame::BridgeCall { - session_id: "s1".into(), - call_id: 2, - method: "_fn".into(), - payload: vec![0xBB; 256], - }; - encode_frame_into(&mut buf, &frame2).expect("encode"); - assert!( - buf.capacity() >= cap_after_first, - "capacity should not shrink" - ); - - // Verify round-trip correctness - let decoded = read_frame(&mut std::io::Cursor::new(&first_bytes)).expect("decode"); - assert_eq!(decoded, frame); - let decoded2 = read_frame(&mut std::io::Cursor::new(&buf)).expect("decode"); - assert_eq!(decoded2, frame2); - } - - #[test] - fn encode_frame_into_matches_frame_to_bytes() { - let frame = BinaryFrame::ExecutionResult { - session_id: "sess-1".into(), - exit_code: 0, - exports: Some(vec![0x01, 0x02]), - error: None, - }; - let expected = frame_to_bytes(&frame).expect("frame_to_bytes"); - let mut buf = Vec::new(); - encode_frame_into(&mut buf, &frame).expect("encode_frame_into"); - assert_eq!(buf, expected); - } - - #[test] - fn encode_frame_into_grows_to_high_water_mark() { - let mut buf = Vec::new(); - - // Small frame - let small = BinaryFrame::Log { - session_id: "s".into(), - channel: 0, - message: "hi".into(), - }; - encode_frame_into(&mut buf, &small).expect("encode"); - let small_cap = buf.capacity(); - - // Large frame grows buffer - let large = BinaryFrame::BridgeCall { - session_id: "s".into(), - call_id: 1, - method: "_fn".into(), - payload: vec![0xFF; 4096], - }; - encode_frame_into(&mut buf, &large).expect("encode"); - let large_cap = buf.capacity(); - assert!(large_cap > small_cap); - - // Small frame again — capacity stays at high-water mark - encode_frame_into(&mut buf, &small).expect("encode"); - assert_eq!( - buf.capacity(), - large_cap, - "capacity should stay at high-water mark" - ); - } - - // -- Overflow guard tests -- - - #[test] - fn write_session_id_rejects_oversized() { - // Session ID > 255 bytes must be rejected - let long_sid = "x".repeat(256); - let frame = BinaryFrame::DestroySession { - session_id: long_sid, - }; - let result = frame_to_bytes(&frame); - assert!(result.is_err()); - let err = result.unwrap_err(); - assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - assert!(err.to_string().contains("session ID byte length")); - assert!(err.to_string().contains("255")); - } - - #[test] - fn write_session_id_accepts_max() { - // Session ID of exactly 255 bytes must succeed - let max_sid = "a".repeat(255); - let frame = BinaryFrame::DestroySession { - session_id: max_sid.clone(), - }; - let bytes = frame_to_bytes(&frame).expect("should accept 255-byte session ID"); - let decoded = read_frame(&mut std::io::Cursor::new(&bytes)).expect("decode"); - assert_eq!(decoded, frame); - } - - #[test] - fn write_len_prefixed_u16_rejects_oversized() { - // String > 65535 bytes in a u16-prefixed field must be rejected - let long_method = "m".repeat(65536); - let frame = BinaryFrame::BridgeCall { - session_id: "s".into(), - call_id: 1, - method: long_method, - payload: vec![], - }; - let result = frame_to_bytes(&frame); - assert!(result.is_err()); - let err = result.unwrap_err(); - assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - assert!(err.to_string().contains("string byte length")); - assert!(err.to_string().contains("65535")); - } - - #[test] - fn write_len_prefixed_u16_accepts_max() { - // String of exactly 65535 bytes in a u16-prefixed field must succeed - let max_method = "m".repeat(65535); - let frame = BinaryFrame::BridgeCall { - session_id: "s".into(), - call_id: 1, - method: max_method.clone(), - payload: vec![], - }; - let bytes = frame_to_bytes(&frame).expect("should accept 65535-byte method"); - let decoded = read_frame(&mut std::io::Cursor::new(&bytes)).expect("decode"); - assert_eq!(decoded, frame); - } - - #[test] - fn execute_file_path_rejects_oversized() { - // file_path > 65535 bytes must be rejected (encoded as u16) - let long_path = "/".repeat(65536); - let frame = BinaryFrame::Execute { - session_id: "s".into(), - mode: 0, - file_path: long_path, - bridge_code: "".into(), - post_restore_script: "".into(), - userland_code: String::new(), - high_resolution_time: false, - user_code: "".into(), - }; - let result = frame_to_bytes(&frame); - assert!(result.is_err()); - let err = result.unwrap_err(); - assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - assert!(err.to_string().contains("65535")); - } -} diff --git a/crates/v8-runtime/src/isolate.rs b/crates/v8-runtime/src/isolate.rs deleted file mode 100644 index 891d8b3a1..000000000 --- a/crates/v8-runtime/src/isolate.rs +++ /dev/null @@ -1,221 +0,0 @@ -// V8 isolate lifecycle: platform init, create, configure, destroy - -use std::collections::HashMap; -use std::ffi::c_void; -use std::sync::{Mutex, Once}; - -use crate::ipc::ExecutionError; -use secure_exec_bridge::queue_tracker::{warn_limit_exhausted, TrackedLimit}; - -static V8_INIT: Once = Once::new(); -static V8_ISOLATE_LIFECYCLE: Mutex<()> = Mutex::new(()); -const MAX_UNHANDLED_PROMISE_REJECTIONS: usize = 1024; - -#[repr(align(16))] -struct AlignedBytes([u8; N]); - -static ICU_COMMON_DATA: AlignedBytes< - { include_bytes!(concat!(env!("OUT_DIR"), "/icudtl.dat")).len() }, -> = AlignedBytes(*include_bytes!(concat!(env!("OUT_DIR"), "/icudtl.dat"))); - -#[derive(Default)] -pub struct PromiseRejectState { - pub unhandled: HashMap, - overflow_count: usize, -} - -impl PromiseRejectState { - fn record_unhandled(&mut self, promise_id: i32, error: ExecutionError) { - use std::collections::hash_map::Entry; - // Cache the length before taking the entry, since `Entry` borrows the - // map mutably and we cannot read `len()` while it is held. - let under_limit = self.unhandled.len() < MAX_UNHANDLED_PROMISE_REJECTIONS; - match self.unhandled.entry(promise_id) { - // Existing rejection for this promise — overwrite with latest error. - Entry::Occupied(mut entry) => { - entry.insert(error); - } - // New rejection: store it if under the cap, otherwise count overflow. - Entry::Vacant(entry) => { - if under_limit { - entry.insert(error); - } else { - self.overflow_count = self.overflow_count.saturating_add(1); - } - } - } - } - - fn mark_handled(&mut self, promise_id: i32) { - if self.unhandled.remove(&promise_id).is_none() && self.overflow_count > 0 { - self.overflow_count -= 1; - } - } - - pub fn take_next_unhandled(&mut self) -> Option { - if self.overflow_count > 0 { - self.overflow_count = 0; - self.unhandled.clear(); - return Some(ExecutionError { - error_type: "Error".into(), - message: format!( - "unhandled promise rejection registry exceeded limit of {MAX_UNHANDLED_PROMISE_REJECTIONS} rejections" - ), - stack: String::new(), - code: Some("ERR_AGENTOS_UNHANDLED_REJECTION_LIMIT".into()), - }); - } - self.unhandled.drain().next().map(|(_, err)| err) - } -} - -extern "C" fn promise_reject_callback(msg: v8::PromiseRejectMessage) { - let scope = &mut unsafe { v8::CallbackScope::new(&msg) }; - let promise_id = msg.get_promise().get_identity_hash().get(); - match msg.get_event() { - v8::PromiseRejectEvent::PromiseRejectWithNoHandler => { - let error = { - let scope = &mut v8::HandleScope::new(scope); - let value = msg - .get_value() - .unwrap_or_else(|| v8::undefined(scope).into()); - crate::execution::extract_error_info(scope, value) - }; - if let Some(state) = scope.get_slot_mut::() { - state.record_unhandled(promise_id, error); - } - } - v8::PromiseRejectEvent::PromiseHandlerAddedAfterReject => { - if let Some(state) = scope.get_slot_mut::() { - state.mark_handled(promise_id); - } - } - _ => {} - } -} - -pub fn configure_isolate(isolate: &mut v8::OwnedIsolate) { - isolate.set_slot(PromiseRejectState::default()); - isolate.set_promise_reject_callback(promise_reject_callback); -} - -/// Initialize the V8 platform (once per process). -/// Safe to call multiple times; only the first call takes effect. -pub fn init_v8_platform() { - V8_INIT.call_once(|| { - v8::icu::set_common_data_74(&ICU_COMMON_DATA.0) - .expect("failed to initialize V8 ICU common data"); - let platform = v8::new_default_platform(0, false).make_shared(); - v8::V8::initialize_platform(platform); - v8::V8::initialize(); - }); -} - -// Headroom granted to V8 when the near-heap-limit callback fires. V8 fatal-aborts -// the whole process (SIGTRAP) if the callback does not raise the limit, so we must -// hand back a larger limit to give the engine room to unwind. Termination has -// already been requested, so this extra budget only covers propagation of the -// uncatchable termination exception, not continued guest allocation. -const NEAR_HEAP_LIMIT_HEADROOM_BYTES: usize = 16 * 1024 * 1024; - -/// Default per-isolate heap cap applied when the caller passes no explicit limit. -/// -/// Resource limits must be bounded by default (never unbounded for memory): a -/// guest with no configured `heap_limit_mb` must NOT be able to grow the heap until -/// V8 fatal-aborts the process-global runtime and takes down every co-tenant -/// isolate. 128 MiB matches the Cloudflare Workers per-isolate budget we mirror for -/// isolation semantics; operators may raise it via the configured limit. -pub const DEFAULT_HEAP_LIMIT_MB: u32 = 128; - -/// Invoked by V8 when heap usage approaches the configured limit. Instead of -/// letting V8 fatal-abort the (process-global) runtime, request termination of the -/// offending isolate and return a raised limit so V8 can propagate the uncatchable -/// termination exception cleanly. `data` is a leaked `Box` for -/// the isolate this callback was registered on. -extern "C" fn near_heap_limit_callback( - data: *mut c_void, - current_heap_limit: usize, - initial_heap_limit: usize, -) -> usize { - if !data.is_null() { - // Safety: `data` is the pointer produced by `Box::into_raw` in - // `install_heap_limit_guard` and lives for the entire lifetime of the - // isolate. - let handle = unsafe { &*(data as *const v8::IsolateHandle) }; - // Terminate any JS currently running on this isolate. This unwinds the - // guest with an uncatchable exception rather than crashing the process. - handle.terminate_execution(); - } - warn_limit_exhausted( - TrackedLimit::V8HeapBytes, - current_heap_limit, - initial_heap_limit.max(1), - ); - // Grant headroom so V8 does not immediately fatal-abort before the termination - // takes effect. We never shrink below the current limit. - current_heap_limit - .max(initial_heap_limit) - .saturating_add(NEAR_HEAP_LIMIT_HEADROOM_BYTES) -} - -/// Register the near-heap-limit OOM guard on an isolate that was created with a -/// configured heap cap. Without this guard, V8 fatal-aborts the whole (process- -/// global) runtime with a SIGTRAP when the cap is reached, taking down every -/// concurrent tenant; with it, the offending isolate is terminated instead. -/// -/// Must be called for every isolate created with a non-`None` heap limit, -/// regardless of whether it was built fresh or restored from a snapshot. -pub fn install_heap_limit_guard(isolate: &mut v8::OwnedIsolate) { - // The callback needs a thread-safe handle to request termination of this very - // isolate. The handle is leaked so it outlives the callback registration; the - // number of isolates per process is bounded, so this is not an unbounded leak, - // and the memory is reclaimed when the process exits. - let handle = Box::new(isolate.thread_safe_handle()); - let data = Box::into_raw(handle) as *mut c_void; - isolate.add_near_heap_limit_callback(near_heap_limit_callback, data); -} - -/// Create a new V8 isolate with an optional heap limit in MB. `None` applies the -/// bounded-by-default cap (`DEFAULT_HEAP_LIMIT_MB`) — an isolate is NEVER created -/// with an unbounded heap, so a guest heap bomb terminates its own isolate rather -/// than fatal-aborting the shared process. -pub fn create_isolate(heap_limit_mb: Option) -> v8::OwnedIsolate { - let limit = heap_limit_mb.unwrap_or(DEFAULT_HEAP_LIMIT_MB); - let mut params = v8::CreateParams::default(); - let limit_bytes = (limit as usize) * 1024 * 1024; - params = params.heap_limits(0, limit_bytes); - let mut isolate = with_isolate_lifecycle_lock(|| v8::Isolate::new(params)); - configure_isolate(&mut isolate); - install_heap_limit_guard(&mut isolate); - isolate -} - -/// Run V8 isolate create/drop work under a process-wide lifecycle lock. -/// -/// rusty_v8 130.0.7 embeds a V8 13.0-era process-wide WebAssembly code pointer -/// table. Isolate construction allocates wasm builtin handles from that table and -/// isolate destruction frees them again, so create/drop must not overlap across -/// session threads. -pub fn with_isolate_lifecycle_lock(f: impl FnOnce() -> T) -> T { - let _guard = V8_ISOLATE_LIFECYCLE - .lock() - .expect("V8 isolate lifecycle lock poisoned"); - f() -} - -pub fn drop_isolate(isolate: Option) { - if let Some(isolate) = isolate { - with_isolate_lifecycle_lock(|| drop(isolate)); - } -} - -/// Create a new V8 context on the given isolate. -/// Returns a Global handle so the context can be reused across scopes. -pub fn create_context(isolate: &mut v8::OwnedIsolate) -> v8::Global { - let scope = &mut v8::HandleScope::new(isolate); - let context = v8::Context::new(scope, Default::default()); - v8::Global::new(scope, context) -} - -// V8 lifecycle tests are consolidated in execution::tests to avoid -// inter-test SIGSEGV from V8 global state issues. diff --git a/crates/v8-runtime/src/lib.rs b/crates/v8-runtime/src/lib.rs index f788f0dfd..126c49fbf 100644 --- a/crates/v8-runtime/src/lib.rs +++ b/crates/v8-runtime/src/lib.rs @@ -1,12 +1,3 @@ -pub mod bridge; -pub mod embedded_runtime; -pub mod execution; -pub mod host_call; -pub mod ipc; -pub mod ipc_binary; -pub mod isolate; -pub mod runtime_protocol; -pub mod session; -pub mod snapshot; -pub mod stream; -pub mod timeout; +//! Compatibility shim for `agentos-v8-runtime`. + +pub use agentos_v8_runtime::*; diff --git a/crates/v8-runtime/src/runtime_protocol.rs b/crates/v8-runtime/src/runtime_protocol.rs deleted file mode 100644 index 1291905e4..000000000 --- a/crates/v8-runtime/src/runtime_protocol.rs +++ /dev/null @@ -1,371 +0,0 @@ -use crate::ipc_binary::{BinaryFrame, ExecutionErrorBin}; -use std::io; -use std::sync::Arc; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct WarmSessionHint { - pub bridge_code: String, - pub userland_code: String, - pub heap_limit_mb: Option, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum RuntimeCommand { - CreateSession { - session_id: String, - heap_limit_mb: Option, - cpu_time_limit_ms: Option, - wall_clock_limit_ms: Option, - warm_hint: Option, - }, - DestroySession { - session_id: String, - }, - WarmSnapshot { - bridge_code: String, - userland_code: String, - }, - SendToSession { - session_id: String, - message: SessionMessage, - }, - /// Install a direct module-source reader on a session thread. Carries the live - /// reader (not serialized) so module loads skip the bridge round-trip. Routed - /// through the dispatch thread (which owns the session manager) like - /// `SendToSession`, then forwarded as a `SessionCommand::SetModuleReader`. - SetSessionModuleReader { - session_id: String, - reader: ModuleReaderHandle, - }, -} - -/// Wrapper that lets a live `GuestModuleReader` ride `RuntimeCommand` despite its -/// `derive(Debug, Clone, PartialEq)`: the trait object lives behind an -/// `Arc>>`, and the dispatch thread `take()`s it out exactly once. -#[derive(Clone)] -pub struct ModuleReaderHandle( - std::sync::Arc>>>, -); - -impl ModuleReaderHandle { - pub fn new(reader: Box) -> Self { - ModuleReaderHandle(std::sync::Arc::new(std::sync::Mutex::new(Some(reader)))) - } - - /// Take the reader out (dispatch-thread side); `None` if already taken. - pub fn take(&self) -> Option> { - self.0.lock().ok().and_then(|mut guard| guard.take()) - } -} - -impl std::fmt::Debug for ModuleReaderHandle { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("ModuleReaderHandle(..)") - } -} - -impl PartialEq for ModuleReaderHandle { - fn eq(&self, other: &Self) -> bool { - std::sync::Arc::ptr_eq(&self.0, &other.0) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum SessionMessage { - InjectGlobals { - payload: Vec, - }, - Execute { - mode: u8, - file_path: String, - bridge_code: String, - post_restore_script: String, - userland_code: String, - high_resolution_time: bool, - user_code: String, - wasm_module_bytes: Option>>, - }, - BridgeResponse(BridgeResponse), - StreamEvent(StreamEvent), - TerminateExecution, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct BridgeResponse { - pub call_id: u64, - pub status: u8, - pub payload: Vec, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct StreamEvent { - pub event_type: String, - pub payload: Vec, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum RuntimeEvent { - BridgeCall { - session_id: String, - call_id: u64, - method: String, - payload: Vec, - }, - ExecutionResult { - session_id: String, - exit_code: i32, - exports: Option>, - error: Option, - }, - Log { - session_id: String, - channel: u8, - message: String, - }, - StreamCallback { - session_id: String, - callback_type: String, - payload: Vec, - }, -} - -impl RuntimeEvent { - pub fn session_id(&self) -> &str { - match self { - RuntimeEvent::BridgeCall { session_id, .. } - | RuntimeEvent::ExecutionResult { session_id, .. } - | RuntimeEvent::Log { session_id, .. } - | RuntimeEvent::StreamCallback { session_id, .. } => session_id, - } - } -} - -impl TryFrom for RuntimeCommand { - type Error = io::Error; - - fn try_from(frame: BinaryFrame) -> Result { - match frame { - BinaryFrame::CreateSession { - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - } => Ok(RuntimeCommand::CreateSession { - session_id, - heap_limit_mb: non_zero_option(heap_limit_mb), - cpu_time_limit_ms: non_zero_option(cpu_time_limit_ms), - wall_clock_limit_ms: non_zero_option(wall_clock_limit_ms), - warm_hint: None, - }), - BinaryFrame::DestroySession { session_id } => { - Ok(RuntimeCommand::DestroySession { session_id }) - } - BinaryFrame::InjectGlobals { - session_id, - payload, - } => Ok(RuntimeCommand::SendToSession { - session_id, - message: SessionMessage::InjectGlobals { payload }, - }), - BinaryFrame::Execute { - session_id, - mode, - file_path, - bridge_code, - post_restore_script, - userland_code, - high_resolution_time, - user_code, - } => { - if mode > 1 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("unknown Execute mode: {mode}"), - )); - } - Ok(RuntimeCommand::SendToSession { - session_id, - message: SessionMessage::Execute { - mode, - file_path, - bridge_code, - post_restore_script, - userland_code, - high_resolution_time, - user_code, - wasm_module_bytes: None, - }, - }) - } - BinaryFrame::BridgeResponse { - session_id, - call_id, - status, - payload, - } => { - validate_bridge_response_status(status)?; - Ok(RuntimeCommand::SendToSession { - session_id, - message: SessionMessage::BridgeResponse(BridgeResponse { - call_id, - status, - payload, - }), - }) - } - BinaryFrame::StreamEvent { - session_id, - event_type, - payload, - } => Ok(RuntimeCommand::SendToSession { - session_id, - message: SessionMessage::StreamEvent(StreamEvent { - event_type, - payload, - }), - }), - BinaryFrame::TerminateExecution { session_id } => Ok(RuntimeCommand::SendToSession { - session_id, - message: SessionMessage::TerminateExecution, - }), - BinaryFrame::WarmSnapshot { - bridge_code, - userland_code, - } => Ok(RuntimeCommand::WarmSnapshot { - bridge_code, - userland_code, - }), - BinaryFrame::Authenticate { .. } => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Authenticate is not supported by the embedded runtime", - )), - _ => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "host-output frames cannot be sent into the embedded runtime", - )), - } - } -} - -impl From for BinaryFrame { - fn from(event: RuntimeEvent) -> Self { - match event { - RuntimeEvent::BridgeCall { - session_id, - call_id, - method, - payload, - } => BinaryFrame::BridgeCall { - session_id, - call_id, - method, - payload, - }, - RuntimeEvent::ExecutionResult { - session_id, - exit_code, - exports, - error, - } => BinaryFrame::ExecutionResult { - session_id, - exit_code, - exports, - error, - }, - RuntimeEvent::Log { - session_id, - channel, - message, - } => BinaryFrame::Log { - session_id, - channel, - message, - }, - RuntimeEvent::StreamCallback { - session_id, - callback_type, - payload, - } => BinaryFrame::StreamCallback { - session_id, - callback_type, - payload, - }, - } - } -} - -fn non_zero_option(value: u32) -> Option { - if value == 0 { - None - } else { - Some(value) - } -} - -pub fn validate_bridge_response_status(status: u8) -> io::Result<()> { - if status <= 2 { - return Ok(()); - } - Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("unknown BridgeResponse status: {status}"), - )) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn rejects_unknown_execute_mode() { - let err = RuntimeCommand::try_from(BinaryFrame::Execute { - session_id: "s".into(), - mode: 2, - file_path: "/app/main.mjs".into(), - bridge_code: String::new(), - post_restore_script: String::new(), - userland_code: String::new(), - high_resolution_time: false, - user_code: String::new(), - }) - .expect_err("unknown execute mode should be rejected"); - - assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - assert!(err.to_string().contains("unknown Execute mode")); - } - - #[test] - fn rejects_unknown_bridge_response_status() { - let err = RuntimeCommand::try_from(BinaryFrame::BridgeResponse { - session_id: "s".into(), - call_id: 1, - status: 3, - payload: Vec::new(), - }) - .expect_err("unknown bridge response status should be rejected"); - - assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - assert!(err.to_string().contains("unknown BridgeResponse status")); - } - - #[test] - fn accepts_known_bridge_response_statuses() { - for status in 0..=2 { - let command = RuntimeCommand::try_from(BinaryFrame::BridgeResponse { - session_id: "s".into(), - call_id: 1, - status, - payload: Vec::new(), - }) - .expect("known bridge response status should be accepted"); - - assert!(matches!( - command, - RuntimeCommand::SendToSession { - message: SessionMessage::BridgeResponse(BridgeResponse { status: s, .. }), - .. - } if s == status - )); - } - } -} diff --git a/crates/v8-runtime/src/session.rs b/crates/v8-runtime/src/session.rs deleted file mode 100644 index 1219aee44..000000000 --- a/crates/v8-runtime/src/session.rs +++ /dev/null @@ -1,3193 +0,0 @@ -// Session management: create/destroy sessions with V8 isolates on dedicated threads - -#[cfg(not(test))] -use std::collections::BTreeMap; -use std::collections::{HashMap, HashSet, VecDeque}; -use std::sync::atomic::AtomicU64; -use std::sync::{Arc, Condvar, Mutex, OnceLock}; -use std::thread; -#[cfg(not(test))] -use std::time::{Duration, Instant}; - -use crossbeam_channel::{Receiver, Sender}; -#[cfg(not(test))] -use secure_exec_bridge::queue_tracker::{warn_limit_exhausted, TrackedLimit}; -use secure_exec_bridge::{bridge_contract, BridgeCallConvention}; - -use crate::execution; -#[cfg(not(test))] -use crate::host_call::{BridgeCallContext, ChannelRuntimeEventSender}; -use crate::host_call::{CallIdRouter, SharedCallIdCounter}; -use crate::ipc::ExecutionError; -#[cfg(not(test))] -use crate::ipc_binary::ExecutionErrorBin; -use crate::runtime_protocol::{ - BridgeResponse, RuntimeEvent, SessionMessage, StreamEvent, WarmSessionHint, -}; -use crate::snapshot::{snapshot_cache_key, SnapshotCache, SnapshotCacheKey}; -#[cfg(not(test))] -use crate::{bridge, isolate, snapshot}; - -/// Commands sent to a session thread -pub enum SessionCommand { - /// Shut down the session and destroy the isolate - Shutdown, - /// Forward a typed session message to the session thread for processing - Message(SessionMessage), - /// Install a direct module-source reader on the session thread. Carried as a - /// live object over the in-process command channel (NOT a serialized frame), - /// so subsequent module loads on this thread read source directly instead of - /// round-tripping the bridge. Sent just before an Execute message. - SetModuleReader(Box), -} - -#[cfg(not(test))] -type SharedIsolateHandle = Arc>>; -#[cfg(test)] -type SharedIsolateHandle = Arc>>; - -/// Sender for typed runtime events produced by session threads. -pub type RuntimeEventSender = crossbeam_channel::Sender; - -#[derive(Debug, Clone, PartialEq)] -pub struct RuntimeEventEnvelope { - pub output_generation: Option, - pub event: RuntimeEvent, -} - -const LATE_TERMINATE_EXECUTION_ERROR_CODE: &str = "ERR_LATE_TERMINATE_EXECUTION"; -const LATE_STREAM_EVENT_ERROR_CODE: &str = "ERR_LATE_STREAM_EVENT"; -const LATE_BRIDGE_RESPONSE_ERROR_CODE: &str = "ERR_LATE_BRIDGE_RESPONSE"; -const DEFERRED_COMMAND_LIMIT_ERROR_CODE: &str = "ERR_SESSION_DEFERRED_COMMAND_LIMIT"; -const SESSION_COMMAND_CHANNEL_CAPACITY: usize = 256; -const MAX_DEFERRED_SESSION_COMMANDS: usize = SESSION_COMMAND_CHANNEL_CAPACITY; -const MAX_DEFERRED_SYNC_MESSAGES: usize = SESSION_COMMAND_CHANNEL_CAPACITY; - -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -struct WarmPoolKey { - snapshot_key_digest: SnapshotCacheKey, - heap_limit_mb: u32, -} - -struct ParkedWorker { - assignment_tx: Sender, - join_handle: thread::JoinHandle<()>, -} - -#[derive(Default)] -struct WarmWorkerPoolState { - workers: HashMap>, - refilling: HashSet, -} - -#[derive(Default)] -struct WarmWorkerPool { - state: Mutex, -} - -struct SessionAssignment { - heap_limit_mb: Option, - cpu_time_limit_ms: Option, - wall_clock_limit_ms: Option, - rx: Receiver, - slot_control: SlotControl, - max_concurrency: usize, - event_tx: RuntimeEventSender, - call_id_router: CallIdRouter, - shared_call_id: SharedCallIdCounter, - snapshot_cache: Arc, - isolate_handle: SharedIsolateHandle, - execution_abort: SharedExecutionAbort, - session_id: String, - output_generation: Option, -} - -#[cfg(not(test))] -struct PrecreatedIsolate { - isolate: v8::OwnedIsolate, - context: v8::Global, - bridge_code: String, - userland_code: String, -} - -#[cfg(test)] -struct PrecreatedIsolate; - -#[cfg(not(test))] -#[derive(Default)] -struct V8SessionPhaseStats { - calls: u64, - total_ns: u128, - max_ns: u128, -} - -#[cfg(not(test))] -static V8_SESSION_PHASES: OnceLock>> = OnceLock::new(); - -#[cfg(not(test))] -fn v8_session_phases_enabled() -> bool { - std::env::var("AGENTOS_V8_SESSION_PHASES").as_deref() == Ok("1") -} - -#[cfg(not(test))] -fn record_v8_session_phase(stage: &str, elapsed: Duration) { - if !v8_session_phases_enabled() { - return; - } - let phases = V8_SESSION_PHASES.get_or_init(|| Mutex::new(BTreeMap::new())); - let Ok(mut phases) = phases.lock() else { - return; - }; - let stats = phases.entry(stage.to_string()).or_default(); - stats.calls += 1; - let elapsed_ns = elapsed.as_nanos(); - stats.total_ns += elapsed_ns; - stats.max_ns = stats.max_ns.max(elapsed_ns); - - let Some(path) = std::env::var_os("AGENTOS_V8_SESSION_PHASES_FILE") else { - return; - }; - let mut output = String::new(); - for (stage, stats) in phases.iter() { - let total_us = stats.total_ns / 1_000; - let avg_us = if stats.calls == 0 { - 0 - } else { - total_us / u128::from(stats.calls) - }; - let max_us = stats.max_ns / 1_000; - output.push_str(&format!( - "stage={stage} calls={} total_us={total_us} avg_us={avg_us} max_us={max_us}\n", - stats.calls - )); - } - let _ = std::fs::write(path, output); -} - -#[cfg(not(test))] -fn record_warm_worker_hit() { - record_v8_session_phase("warm_worker_hit", Duration::ZERO); -} - -#[cfg(test)] -fn record_warm_worker_hit() {} - -#[cfg(not(test))] -fn record_warm_worker_miss() { - record_v8_session_phase("warm_worker_miss", Duration::ZERO); -} - -#[cfg(test)] -fn record_warm_worker_miss() {} - -fn warm_worker_capacity_per_key() -> usize { - std::env::var("AGENTOS_V8_WARM_ISOLATES") - .ok() - .and_then(|value| value.parse::().ok()) - .unwrap_or(2) -} - -fn effective_heap_limit_mb(heap_limit_mb: Option) -> u32 { - heap_limit_mb.unwrap_or(crate::isolate::DEFAULT_HEAP_LIMIT_MB) -} - -fn warm_pool_key( - bridge_code: &str, - userland_code: &str, - heap_limit_mb: Option, -) -> WarmPoolKey { - WarmPoolKey { - snapshot_key_digest: snapshot_cache_key( - bridge_code, - (!userland_code.is_empty()).then_some(userland_code), - ), - heap_limit_mb: effective_heap_limit_mb(heap_limit_mb), - } -} - -fn warm_key_prefix(key: &WarmPoolKey) -> String { - key.snapshot_key_digest[..4] - .iter() - .map(|byte| format!("{byte:02x}")) - .collect() -} - -impl WarmWorkerPool { - fn claim(&self, key: &WarmPoolKey) -> Option { - let mut state = self.state.lock().expect("warm worker pool lock poisoned"); - state.workers.get_mut(key).and_then(Vec::pop) - } - - fn shutdown_handles(&self) -> Vec> { - let mut state = self.state.lock().expect("warm worker pool lock poisoned"); - state.refilling.clear(); - state - .workers - .drain() - .flat_map(|(_, workers)| workers) - .map(|worker| { - drop(worker.assignment_tx); - worker.join_handle - }) - .collect() - } - - fn ensure_count( - self: &Arc, - snapshot_cache: Arc, - slot_control: SlotControl, - bridge_code: String, - userland_code: String, - heap_limit_mb: Option, - requested_count: usize, - ) { - let capacity = warm_worker_capacity_per_key(); - if capacity == 0 || requested_count == 0 { - return; - } - - let target_count = requested_count.min(capacity); - let key = warm_pool_key(&bridge_code, &userland_code, heap_limit_mb); - { - let mut state = self.state.lock().expect("warm worker pool lock poisoned"); - let current = state.workers.get(&key).map_or(0, Vec::len); - if current >= target_count || state.refilling.contains(&key) { - return; - } - state.refilling.insert(key.clone()); - } - - let pool = Arc::clone(self); - let spawn_key = key.clone(); - let _ = thread::Builder::new() - .name(String::from("secure-exec-v8-warm-refill")) - .spawn(move || { - pool.refill_until( - snapshot_cache, - slot_control, - spawn_key, - bridge_code, - userland_code, - heap_limit_mb, - target_count, - ); - }) - .map_err(|error| { - eprintln!("secure-exec-v8-runtime: warm worker refill spawn failed: {error}"); - self.state - .lock() - .expect("warm worker pool lock poisoned") - .refilling - .remove(&key); - }); - } - - // Internal pool-refill plumbing; args mirror the parked-worker construction. - #[allow(clippy::too_many_arguments)] - fn refill_until( - &self, - snapshot_cache: Arc, - slot_control: SlotControl, - key: WarmPoolKey, - bridge_code: String, - userland_code: String, - heap_limit_mb: Option, - target_count: usize, - ) { - loop { - let capacity = warm_worker_capacity_per_key(); - if capacity == 0 { - break; - } - let desired = target_count.min(capacity); - { - let state = self.state.lock().expect("warm worker pool lock poisoned"); - if state.workers.get(&key).map_or(0, Vec::len) >= desired { - break; - } - } - - let Some(worker) = spawn_warm_worker( - Arc::clone(&snapshot_cache), - Arc::clone(&slot_control), - key.clone(), - bridge_code.clone(), - userland_code.clone(), - heap_limit_mb, - ) else { - break; - }; - - let mut state = self.state.lock().expect("warm worker pool lock poisoned"); - let workers = state.workers.entry(key.clone()).or_default(); - if workers.len() >= desired { - drop(worker.assignment_tx); - let _ = worker.join_handle.join(); - break; - } - workers.push(worker); - eprintln!( - "secure-exec-v8-runtime: warm worker refilled key={} heap={} pool_size={}", - warm_key_prefix(&key), - key.heap_limit_mb, - workers.len() - ); - } - - self.state - .lock() - .expect("warm worker pool lock poisoned") - .refilling - .remove(&key); - } -} - -#[cfg(not(test))] -fn spawn_warm_worker( - snapshot_cache: Arc, - slot_control: SlotControl, - key: WarmPoolKey, - bridge_code: String, - userland_code: String, - heap_limit_mb: Option, -) -> Option { - let (assignment_tx, assignment_rx) = crossbeam_channel::bounded::(1); - let (ready_tx, ready_rx) = crossbeam_channel::bounded::>(1); - let worker_bridge_code = bridge_code.clone(); - let worker_userland_code = userland_code.clone(); - let join_handle = match thread::Builder::new() - .name(String::from("secure-exec-v8-warm-worker")) - .spawn(move || { - let precreated = precreate_warm_isolate( - snapshot_cache, - slot_control, - worker_bridge_code, - worker_userland_code, - heap_limit_mb, - ); - match precreated { - Ok(precreated) => { - let _ = ready_tx.send(Ok(())); - if let Ok(assignment) = assignment_rx.recv() { - session_thread(assignment, Some(precreated)); - } - } - Err(error) => { - let _ = ready_tx.send(Err(error)); - } - } - }) { - Ok(handle) => handle, - Err(error) => { - eprintln!("secure-exec-v8-runtime: warm worker spawn failed: {error}"); - return None; - } - }; - - match ready_rx.recv() { - Ok(Ok(())) => Some(ParkedWorker { - assignment_tx, - join_handle, - }), - Ok(Err(error)) => { - eprintln!( - "secure-exec-v8-runtime: warm worker refill failed key={} heap={}: {error}", - warm_key_prefix(&key), - key.heap_limit_mb - ); - let _ = join_handle.join(); - None - } - Err(error) => { - eprintln!( - "secure-exec-v8-runtime: warm worker refill failed key={} heap={}: {error}", - warm_key_prefix(&key), - key.heap_limit_mb - ); - let _ = join_handle.join(); - None - } - } -} - -#[cfg(test)] -fn spawn_warm_worker( - _snapshot_cache: Arc, - _slot_control: SlotControl, - _key: WarmPoolKey, - _bridge_code: String, - _userland_code: String, - _heap_limit_mb: Option, -) -> Option { - None -} - -#[cfg(not(test))] -fn precreate_warm_isolate( - snapshot_cache: Arc, - slot_control: SlotControl, - bridge_code: String, - userland_code: String, - heap_limit_mb: Option, -) -> Result { - isolate::init_v8_platform(); - let snapshot_blob = snapshot_cache.get_or_create_with_userland( - &bridge_code, - (!userland_code.is_empty()).then_some(userland_code.as_str()), - )?; - let snapshot_blob = (*snapshot_blob).clone(); - let _idle_slots = lock_idle_slots(&slot_control); - let mut isolate = snapshot::create_isolate_from_snapshot(snapshot_blob, heap_limit_mb); - isolate.set_host_import_module_dynamically_callback(execution::dynamic_import_callback); - isolate.set_host_initialize_import_meta_object_callback(execution::import_meta_object_callback); - let context = isolate::create_context(&mut isolate); - Ok(PrecreatedIsolate { - isolate, - context, - bridge_code, - userland_code, - }) -} - -#[cfg(not(test))] -fn lock_idle_slots(slot_control: &SlotControl) -> std::sync::MutexGuard<'_, usize> { - let (lock, cvar) = &**slot_control; - let mut count = lock.lock().unwrap(); - while *count != 0 { - count = cvar.wait(count).unwrap(); - } - count -} - -/// Normalize an opt-in CPU-time budget: `Some(0)` means "disabled" and folds to -/// `None` so the CPU-budget watchdog is NOT armed. The runtime layer does not -/// invent a default here: secure-exec sidecar VM executions pass the typed -/// `limits.jsRuntime.cpuTimeLimitMs` default, while lower-level callers can pass -/// `None`/`0` deliberately. -fn normalize_cpu_time_limit_ms(cpu_time_limit_ms: Option) -> Option { - cpu_time_limit_ms.filter(|budget_ms| *budget_ms > 0) -} - -/// Normalize an opt-in WALL-CLOCK backstop: `Some(0)` means "disabled" and folds -/// to `None` so the wall-clock `TimeoutGuard` is NOT armed. There is no default — -/// when the caller passes `None`/`0`, the guest runs with no wall-clock limit -/// (opt-in by design, so long-lived ACP adapters are never killed by a default). -/// This is INDEPENDENT of the CPU-time budget: setting one does not arm the other. -fn normalize_wall_clock_limit_ms(wall_clock_limit_ms: Option) -> Option { - wall_clock_limit_ms.filter(|limit_ms| *limit_ms > 0) -} - -/// Internal entry for a running session -struct SessionEntry { - /// Output receiver generation current when this session was created. - output_generation: Option, - /// Channel to send commands to the session thread - tx: Sender, - /// Thread join handle - join_handle: Option>, - /// Thread-safe V8 isolate handle for out-of-band termination. - #[cfg_attr(test, allow(dead_code))] - isolate_handle: SharedIsolateHandle, - /// Current execution abort handle used to wake sync bridge waits. - execution_abort: SharedExecutionAbort, -} - -/// Deferred shutdown work for a session that has already been removed from -/// the manager. `finish()` joins the session thread and clears any call -/// routes the thread registered while shutting down. Callers must release -/// the SessionManager lock before calling `finish()`. Joining under the lock -/// deadlocks: the dispatch thread needs the lock to drain the event channel, -/// and the joined thread can be parked on a full event channel send. -pub struct SessionShutdown { - session_id: String, - join_handle: Option>, - call_id_router: CallIdRouter, -} - -impl SessionShutdown { - pub fn finish(mut self) { - if let Some(handle) = self.join_handle.take() { - let _ = handle.join(); - } - self.call_id_router - .lock() - .expect("call_id router lock poisoned") - .retain(|_, routed_session_id| routed_session_id != &self.session_id); - } -} - -/// Concurrency slot tracker shared across session threads -type SlotControl = Arc<(Mutex, Condvar)>; - -/// Shared deferred message queue for non-BridgeResponse frames consumed by -/// sync bridge calls. The event loop drains these before blocking on the channel. -pub(crate) type DeferredQueue = Arc>>; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub(crate) enum ExecutionAbortReason { - /// Caller explicitly terminated the execution (e.g. session destroy). - Terminated, - /// The opt-in WALL-CLOCK backstop (`TimeoutGuard`) elapsed. Counts elapsed - /// real time INCLUDING idle/await, so it can cap a guest that blocks/awaits - /// indefinitely. Armed only when `limits.jsRuntime.wallClockLimitMs` is set; - /// independent of the CPU-time budget. - #[cfg_attr(test, allow(dead_code))] - WallClockTimedOut, - /// The TRUE CPU-TIME budget (`CpuBudgetGuard`) was exhausted by active JS CPU. - #[cfg_attr(test, allow(dead_code))] - CpuBudgetExceeded, -} - -struct ExecutionAbortState { - sender: Option>, - reason: Option, -} - -pub(crate) struct SharedExecutionAbort(Arc>>); - -impl Clone for SharedExecutionAbort { - fn clone(&self) -> Self { - Self(Arc::clone(&self.0)) - } -} - -/// Create a new empty deferred queue. -pub(crate) fn new_deferred_queue() -> DeferredQueue { - Arc::new(Mutex::new(VecDeque::new())) -} - -pub(crate) fn new_execution_abort() -> SharedExecutionAbort { - SharedExecutionAbort(Arc::new(Mutex::new(None))) -} - -pub(crate) struct ActiveExecutionAbort { - shared: SharedExecutionAbort, -} - -impl ActiveExecutionAbort { - pub(crate) fn arm(shared: &SharedExecutionAbort) -> (Self, crossbeam_channel::Receiver<()>) { - let (tx, rx) = crossbeam_channel::bounded::<()>(0); - let mut guard = shared.0.lock().unwrap(); - *guard = Some(ExecutionAbortState { - sender: Some(tx), - reason: None, - }); - ( - Self { - shared: shared.clone(), - }, - rx, - ) - } -} - -impl Drop for ActiveExecutionAbort { - fn drop(&mut self) { - *self.shared.0.lock().unwrap() = None; - } -} - -pub(crate) fn signal_execution_abort(shared: &SharedExecutionAbort, reason: ExecutionAbortReason) { - if let Some(state) = shared.0.lock().unwrap().as_mut() { - state.reason.get_or_insert(reason); - state.sender.take(); - } -} - -#[cfg(not(test))] -fn execution_abort_reason(shared: &SharedExecutionAbort) -> Option { - shared - .0 - .lock() - .unwrap() - .as_ref() - .and_then(|state| state.reason) -} - -/// Manages V8 sessions with concurrency limiting. -/// Each session runs on a dedicated OS thread with its own V8 isolate. -pub struct SessionManager { - sessions: HashMap, - max_concurrency: usize, - slot_control: SlotControl, - /// Typed runtime event sender shared across session threads. - event_tx: RuntimeEventSender, - /// Call_id → session_id routing table for BridgeResponse dispatch - call_id_router: CallIdRouter, - /// Shared call_id counter — all sessions use this to generate globally unique - /// call_ids, preventing collisions in the call_id_router - shared_call_id: SharedCallIdCounter, - /// Shared snapshot cache for fast isolate creation from pre-compiled bridge code - snapshot_cache: Arc, - /// Ready-to-claim isolate workers keyed by snapshot digest and heap cap. - warm_pool: Arc, -} - -impl SessionManager { - pub fn new( - max_concurrency: usize, - event_tx: RuntimeEventSender, - call_id_router: CallIdRouter, - snapshot_cache: Arc, - ) -> Self { - SessionManager { - sessions: HashMap::new(), - max_concurrency, - slot_control: Arc::new((Mutex::new(0), Condvar::new())), - event_tx, - call_id_router, - shared_call_id: Arc::new(AtomicU64::new(1)), - snapshot_cache, - warm_pool: Arc::new(WarmWorkerPool::default()), - } - } - - /// Get the snapshot cache for pre-warming from WarmSnapshot messages. - #[allow(dead_code)] - pub fn snapshot_cache(&self) -> &Arc { - &self.snapshot_cache - } - - pub fn pre_warm_workers( - &self, - bridge_code: String, - userland_code: String, - heap_limit_mb: Option, - count: usize, - ) { - self.warm_pool.ensure_count( - Arc::clone(&self.snapshot_cache), - Arc::clone(&self.slot_control), - bridge_code, - userland_code, - heap_limit_mb, - count, - ); - } - - /// Create a new session. - /// Spawns a dedicated thread with a V8 isolate. If max concurrency is - /// reached, the session thread will block until a slot becomes available. - pub fn create_session( - &mut self, - session_id: String, - heap_limit_mb: Option, - cpu_time_limit_ms: Option, - wall_clock_limit_ms: Option, - ) -> Result<(), String> { - self.create_session_with_output_generation( - session_id, - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - None, - None, - ) - } - - pub fn create_session_with_output_generation( - &mut self, - session_id: String, - heap_limit_mb: Option, - cpu_time_limit_ms: Option, - wall_clock_limit_ms: Option, - output_generation: Option, - warm_hint: Option, - ) -> Result<(), String> { - if self.sessions.contains_key(&session_id) { - return Err(format!("session {} already exists", session_id)); - } - - let cpu_time_limit_ms = normalize_cpu_time_limit_ms(cpu_time_limit_ms); - let wall_clock_limit_ms = normalize_wall_clock_limit_ms(wall_clock_limit_ms); - let (tx, rx) = crossbeam_channel::bounded(SESSION_COMMAND_CHANNEL_CAPACITY); - let isolate_handle = Arc::new(Mutex::new(None)); - let execution_abort = new_execution_abort(); - let assignment = SessionAssignment { - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - rx, - slot_control: Arc::clone(&self.slot_control), - max_concurrency: self.max_concurrency, - event_tx: self.event_tx.clone(), - call_id_router: Arc::clone(&self.call_id_router), - shared_call_id: Arc::clone(&self.shared_call_id), - snapshot_cache: Arc::clone(&self.snapshot_cache), - isolate_handle: Arc::clone(&isolate_handle), - execution_abort: execution_abort.clone(), - session_id: session_id.clone(), - output_generation, - }; - - let join_handle = match self.claim_warm_worker(warm_hint.as_ref(), assignment) { - Ok((join_handle, true)) => { - if let Some(hint) = warm_hint { - self.warm_pool.ensure_count( - Arc::clone(&self.snapshot_cache), - Arc::clone(&self.slot_control), - hint.bridge_code, - hint.userland_code, - hint.heap_limit_mb, - warm_worker_capacity_per_key(), - ); - } - join_handle - } - Ok((join_handle, false)) => join_handle, - Err(assignment) => spawn_session_thread(assignment) - .map_err(|e| format!("failed to spawn session thread: {}", e))?, - }; - - self.sessions.insert( - session_id, - SessionEntry { - output_generation, - tx, - join_handle: Some(join_handle), - isolate_handle, - execution_abort, - }, - ); - - Ok(()) - } - - // The Err variant intentionally carries the whole SessionAssignment back to - // the caller for the fallback spawn path — it is moved, not copied. - #[allow(clippy::result_large_err)] - fn claim_warm_worker( - &self, - warm_hint: Option<&WarmSessionHint>, - assignment: SessionAssignment, - ) -> Result<(thread::JoinHandle<()>, bool), SessionAssignment> { - let Some(hint) = warm_hint else { - return Err(assignment); - }; - if warm_worker_capacity_per_key() == 0 { - record_warm_worker_miss(); - return Err(assignment); - } - - let key = warm_pool_key(&hint.bridge_code, &hint.userland_code, hint.heap_limit_mb); - let Some(worker) = self.warm_pool.claim(&key) else { - record_warm_worker_miss(); - eprintln!( - "secure-exec-v8-runtime: warm worker pool-empty key={} heap={}", - warm_key_prefix(&key), - key.heap_limit_mb - ); - return Err(assignment); - }; - - match worker.assignment_tx.send(assignment) { - Ok(()) => { - record_warm_worker_hit(); - eprintln!( - "secure-exec-v8-runtime: warm worker claimed key={} heap={}", - warm_key_prefix(&key), - key.heap_limit_mb - ); - Ok((worker.join_handle, true)) - } - Err(error) => { - record_warm_worker_miss(); - let _ = worker.join_handle.join(); - Err(error.0) - } - } - } - - pub fn destroy_session_if_output_generation( - &mut self, - session_id: &str, - output_generation: u64, - ) -> Result { - match self.begin_destroy_session_if_output_generation(session_id, output_generation)? { - Some(shutdown) => { - shutdown.finish(); - Ok(true) - } - None => Ok(false), - } - } - - pub fn begin_destroy_session_if_output_generation( - &mut self, - session_id: &str, - output_generation: u64, - ) -> Result, String> { - if self - .sessions - .get(session_id) - .is_none_or(|entry| entry.output_generation != Some(output_generation)) - { - return Ok(None); - } - - self.begin_destroy_session(session_id).map(Some) - } - - pub fn detach_session_if_output_generation( - &mut self, - session_id: &str, - output_generation: u64, - ) -> Result { - if self - .sessions - .get(session_id) - .is_none_or(|entry| entry.output_generation != Some(output_generation)) - { - return Ok(false); - } - - self.detach_session(session_id)?; - Ok(true) - } - - fn detach_session(&mut self, session_id: &str) -> Result<(), String> { - let entry = self - .sessions - .get(session_id) - .ok_or_else(|| format!("session {} does not exist", session_id))?; - - #[cfg(not(test))] - if let Some(handle) = entry - .isolate_handle - .lock() - .ok() - .and_then(|guard| guard.as_ref().cloned()) - { - handle.terminate_execution(); - } - signal_execution_abort(&entry.execution_abort, ExecutionAbortReason::Terminated); - self.clear_call_routes_for_session(session_id); - let mut entry = self.sessions.remove(session_id).unwrap(); - let _ = entry.tx.try_send(SessionCommand::Shutdown); - drop(entry.tx); - let _ = entry.join_handle.take(); - Ok(()) - } - - /// Destroy a session inline. Joins the session thread before returning, so - /// this must not be called while a shared lock on the manager is held. Lock - /// holders use `begin_destroy_session` and call `finish()` after unlocking. - pub fn destroy_session(&mut self, session_id: &str) -> Result<(), String> { - self.begin_destroy_session(session_id)?.finish(); - Ok(()) - } - - /// First phase of destroying a session: terminate execution, signal abort, - /// send shutdown, clear call routes, and remove the entry. The returned - /// shutdown joins the session thread and must be finished after the - /// SessionManager lock is released. - pub fn begin_destroy_session(&mut self, session_id: &str) -> Result { - if !self.sessions.contains_key(session_id) { - return Err(format!("session {} does not exist", session_id)); - } - - self.clear_call_routes_for_session(session_id); - let mut entry = self - .sessions - .remove(session_id) - .expect("checked session exists"); - - #[cfg(not(test))] - if let Some(handle) = entry - .isolate_handle - .lock() - .ok() - .and_then(|guard| guard.as_ref().cloned()) - { - handle.terminate_execution(); - } - signal_execution_abort(&entry.execution_abort, ExecutionAbortReason::Terminated); - // Send shutdown, then drop the entry (and with it the sender) so the - // session thread's rx.recv() returns Err if Shutdown was consumed by - // an inner loop. - let _ = entry.tx.try_send(SessionCommand::Shutdown); - let join_handle = entry.join_handle.take(); - drop(entry); - Ok(SessionShutdown { - session_id: session_id.to_owned(), - join_handle, - call_id_router: Arc::clone(&self.call_id_router), - }) - } - - pub(crate) fn take_session_shutdown_handles(&mut self) -> Vec> { - self.call_id_router - .lock() - .expect("call_id router lock poisoned") - .clear(); - - let mut handles: Vec<_> = self - .sessions - .drain() - .filter_map(|(_, mut entry)| { - #[cfg(not(test))] - if let Some(handle) = entry - .isolate_handle - .lock() - .ok() - .and_then(|guard| guard.as_ref().cloned()) - { - handle.terminate_execution(); - } - signal_execution_abort(&entry.execution_abort, ExecutionAbortReason::Terminated); - let _ = entry.tx.try_send(SessionCommand::Shutdown); - drop(entry.tx); - entry.join_handle.take() - }) - .collect(); - handles.extend(self.warm_pool.shutdown_handles()); - handles - } - - pub(crate) fn clear_call_route(&self, call_id: u64) { - self.call_id_router - .lock() - .expect("call_id router lock poisoned") - .remove(&call_id); - } - - fn clear_call_routes_for_session(&self, session_id: &str) { - self.call_id_router - .lock() - .expect("call_id router lock poisoned") - .retain(|_, routed_session_id| routed_session_id != session_id); - } - - /// Resolve a session's command sender and apply message side effects that - /// must happen under the manager lock (isolate termination, abort signal). - /// The caller sends on the returned channel after releasing the lock so a - /// full command channel cannot block the manager mutex. - pub fn session_command_sender( - &self, - session_id: &str, - msg: &SessionMessage, - ) -> Result, String> { - let entry = self - .sessions - .get(session_id) - .ok_or_else(|| format!("session {} does not exist", session_id))?; - - #[cfg(not(test))] - if matches!(msg, SessionMessage::TerminateExecution) { - if let Some(handle) = entry - .isolate_handle - .lock() - .ok() - .and_then(|guard| guard.as_ref().cloned()) - { - handle.terminate_execution(); - } - } - if matches!(msg, SessionMessage::TerminateExecution) { - signal_execution_abort(&entry.execution_abort, ExecutionAbortReason::Terminated); - } - - Ok(entry.tx.clone()) - } - - /// Get a session's command sender without a message (used for control commands - /// like SetModuleReader that aren't a SessionMessage). Dispatch-thread only. - pub fn session_sender(&self, session_id: &str) -> Result, String> { - self.sessions - .get(session_id) - .map(|entry| entry.tx.clone()) - .ok_or_else(|| format!("session {} does not exist", session_id)) - } - - /// Send a message to a session. Blocks on the session command channel, so - /// this must not be called while a shared lock on the manager is held. - pub fn send_to_session(&self, session_id: &str, msg: SessionMessage) -> Result<(), String> { - let sender = self.session_command_sender(session_id, &msg)?; - sender - .send(SessionCommand::Message(msg)) - .map_err(|e| format!("session thread disconnected: {}", e)) - } - - /// Destroy a set of sessions inline, ignoring sessions that were already - /// removed. Joins session threads, so this must not be called while a - /// shared lock on the manager is held. - pub fn destroy_sessions(&mut self, session_ids: I) - where - I: IntoIterator, - { - for shutdown in self.begin_destroy_sessions(session_ids) { - shutdown.finish(); - } - } - - /// Begin destroying a set of sessions, ignoring sessions that were already - /// removed. Finish each returned shutdown after releasing the manager lock. - pub fn begin_destroy_sessions(&mut self, session_ids: I) -> Vec - where - I: IntoIterator, - { - session_ids - .into_iter() - .filter_map(|sid| self.begin_destroy_session(&sid).ok()) - .collect() - } - - /// Number of registered sessions (including those waiting for a slot). - #[allow(dead_code)] - pub fn session_count(&self) -> usize { - self.sessions.len() - } - - /// Return all session IDs. - #[allow(dead_code)] - pub fn all_sessions(&self) -> Vec { - self.sessions.keys().cloned().collect() - } - - /// Number of sessions that have acquired a concurrency slot. - #[allow(dead_code)] - pub fn active_slot_count(&self) -> usize { - let (lock, _) = &*self.slot_control; - *lock.lock().unwrap() - } - - /// Get the call_id routing table for BridgeResponse dispatch. - pub fn call_id_router(&self) -> &CallIdRouter { - &self.call_id_router - } -} - -/// Send a typed runtime event without re-serializing it on the session thread. -#[cfg(not(test))] -fn send_event_with_generation( - event_tx: &RuntimeEventSender, - output_generation: Option, - event: RuntimeEvent, -) { - if let Err(error) = event_tx.send(RuntimeEventEnvelope { - output_generation, - event, - }) { - eprintln!("failed to send runtime event: {error}"); - } -} - -fn send_late_message_warning( - event_tx: &RuntimeEventSender, - session_id: &str, - output_generation: Option, - error_code: &str, - detail: String, -) { - let warning = RuntimeEvent::Log { - session_id: session_id.to_string(), - channel: 1, - message: format!("[{error_code}] {detail}"), - }; - if let Err(error) = event_tx.send(RuntimeEventEnvelope { - output_generation, - event: warning, - }) { - eprintln!("failed to send late-session warning: {error}"); - } -} - -fn handle_late_session_message( - event_tx: &RuntimeEventSender, - session_id: &str, - output_generation: Option, - message: SessionMessage, -) { - match message { - SessionMessage::BridgeResponse(BridgeResponse { - call_id, - status, - payload, - }) => send_late_message_warning( - event_tx, - session_id, - output_generation, - LATE_BRIDGE_RESPONSE_ERROR_CODE, - format!( - "dropping BridgeResponse after execution completed (call_id={call_id}, status={status}, payload_len={})", - payload.len() - ), - ), - SessionMessage::StreamEvent(StreamEvent { - event_type, - payload, - }) => { - // Timer and socket-readiness events are wake hints, not data; both - // race execution completion by design (edge-triggered readiness can - // fire as the guest finishes) and carry nothing to lose, so drop - // them silently instead of warning. - if event_type == "timer" || event_type == "net_socket" { - return; - } - send_late_message_warning( - event_tx, - session_id, - output_generation, - LATE_STREAM_EVENT_ERROR_CODE, - format!( - "dropping StreamEvent after execution completed (event_type={event_type}, payload_len={})", - payload.len() - ), - ) - } - SessionMessage::TerminateExecution => send_late_message_warning( - event_tx, - session_id, - output_generation, - LATE_TERMINATE_EXECUTION_ERROR_CODE, - String::from("dropping TerminateExecution after execution completed"), - ), - SessionMessage::InjectGlobals { .. } | SessionMessage::Execute { .. } => {} - } -} - -fn defer_session_command_before_slot( - deferred_commands: &mut VecDeque, - event_tx: &RuntimeEventSender, - session_id: &str, - output_generation: Option, - command: SessionCommand, -) -> bool { - if deferred_commands.len() < MAX_DEFERRED_SESSION_COMMANDS { - deferred_commands.push_back(command); - return true; - } - - send_late_message_warning( - event_tx, - session_id, - output_generation, - DEFERRED_COMMAND_LIMIT_ERROR_CODE, - format!( - "dropping queued session before slot acquisition because deferred command queue exceeded limit of {MAX_DEFERRED_SESSION_COMMANDS}" - ), - ); - false -} - -#[cfg(not(test))] -fn install_wasm_module_bytes_global<'s>(scope: &mut v8::HandleScope<'s>, bytes: &[u8]) -> bool { - let global = scope.get_current_context().global(scope); - let Some(name) = v8::String::new(scope, "__agentOSWasmModuleBytes") else { - return false; - }; - let len = bytes.len(); - let backing_store = v8::ArrayBuffer::new_backing_store_from_bytes(bytes.to_vec()); - let array_buffer = v8::ArrayBuffer::with_backing_store(scope, &backing_store.make_shared()); - let Some(bytes_value) = v8::Uint8Array::new(scope, array_buffer, 0, len) else { - return false; - }; - global.set(scope, name.into(), bytes_value.into()).is_some() -} - -/// Session thread: acquires a concurrency slot, defers V8 isolate creation -/// to first Execute (when bridge code is known for snapshot lookup), and -/// processes commands until shutdown. -fn spawn_session_thread(assignment: SessionAssignment) -> std::io::Result> { - let name_prefix = if assignment.session_id.len() > 8 { - assignment.session_id[..8].to_string() - } else { - assignment.session_id.clone() - }; - thread::Builder::new() - .name(format!("session-{}", name_prefix)) - .spawn(move || session_thread(assignment, None)) -} - -#[allow(clippy::too_many_arguments)] -fn session_thread( - assignment: SessionAssignment, - #[cfg_attr(test, allow(unused_variables))] precreated_isolate: Option, -) { - let SessionAssignment { - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - rx, - slot_control, - max_concurrency, - event_tx, - call_id_router, - shared_call_id, - snapshot_cache, - isolate_handle, - execution_abort, - session_id, - output_generation, - } = assignment; - #[cfg(test)] - let _ = ( - heap_limit_mb, - cpu_time_limit_ms, - wall_clock_limit_ms, - call_id_router, - shared_call_id, - snapshot_cache, - isolate_handle, - execution_abort, - ); - - // Acquire concurrency slot, but keep polling the session channel so a queued - // session can still shut down cleanly before it ever gets a slot. - let mut deferred_commands = VecDeque::new(); - let acquired_slot = { - let (lock, cvar) = &*slot_control; - let mut count = lock.lock().unwrap(); - loop { - if *count < max_concurrency { - *count += 1; - break true; - } - - let (next_count, _) = cvar - .wait_timeout(count, std::time::Duration::from_millis(50)) - .unwrap(); - count = next_count; - - match rx.try_recv() { - Ok(SessionCommand::Shutdown) - | Err(crossbeam_channel::TryRecvError::Disconnected) => { - break false; - } - Ok(command) => { - if !defer_session_command_before_slot( - &mut deferred_commands, - &event_tx, - &session_id, - output_generation, - command, - ) { - break false; - } - } - Err(crossbeam_channel::TryRecvError::Empty) => {} - } - } - }; - - if !acquired_slot { - return; - } - - // Capture THIS session thread's per-thread CPU clock once. The clock id is - // stable for the thread's lifetime and can be polled from the watchdog - // thread; this is what lets the CPU-budget guard measure active JS CPU time - // (excluding idle/await) without running on the execution thread itself. - // Guest JS always runs on this thread, so this clock is the execution clock. - #[cfg(all(not(test), unix))] - let exec_thread_cpu_clock = crate::timeout::current_thread_cpu_clock(); - #[cfg(all(not(test), not(unix)))] - let exec_thread_cpu_clock: Option = None; - - // Isolate creation is normally deferred to first Execute (when bridge code is - // known for snapshot cache lookup). A claimed warm worker enters here with - // the snapshot isolate already created on this same thread. - #[cfg(not(test))] - let ( - mut v8_isolate, - mut _v8_context, - mut from_snapshot, - mut isolate_bridge_code, - mut isolate_userland_code, - ) = match precreated_isolate { - Some(precreated) => ( - Some(precreated.isolate), - Some(precreated.context), - true, - Some(precreated.bridge_code), - Some(precreated.userland_code), - ), - None => (None, None, false, None, None), - }; - - #[cfg(not(test))] - let mut pending = bridge::PendingPromises::new(); - - // Store latest InjectGlobals V8 payload for re-injection into fresh contexts - #[cfg(not(test))] - let mut last_globals_payload: Option> = None; - - // Bridge code cache for V8 code caching across executions - #[cfg(not(test))] - let mut bridge_cache: Option = None; - - // Cached bridge code string to skip resending over IPC - #[cfg(not(test))] - let mut last_bridge_code: Option = None; - // Cached agent-SDK userland bundle (same 0-length = use cached convention). - #[cfg(not(test))] - let mut last_userland_code: Option = None; - - // A session can reuse its isolate across Executes only while the effective - // bridge code stays the same. Fresh contexts cloned from a snapshot inherit - // the snapshot's bridge IIFE, so a bridge-code change must rebuild the - // isolate before the next execution or the session will keep restoring the - // old snapshot forever. The userland bundle is part of the same guard. - #[cfg(not(test))] - let mut high_resolution_time_origin = Instant::now(); - - #[cfg(not(test))] - if let Some(iso) = v8_isolate.as_mut() { - *isolate_handle - .lock() - .expect("session isolate handle lock poisoned") = Some(iso.thread_safe_handle()); - } - - // Process commands until shutdown or channel close - loop { - let next_command = if let Some(command) = deferred_commands.pop_front() { - Ok(command) - } else { - rx.recv() - }; - - match next_command { - Ok(SessionCommand::Shutdown) | Err(_) => break, - Ok(SessionCommand::SetModuleReader(reader)) => { - execution::install_session_guest_reader(Some(reader)); - } - Ok(SessionCommand::Message(msg)) => match msg { - SessionMessage::InjectGlobals { payload } => { - #[cfg(not(test))] - { - // Store V8-serialized config for injection into fresh context at Execute time - last_globals_payload = Some(payload); - } - #[cfg(test)] - { - let _ = payload; - } - } - SessionMessage::Execute { - mode, - file_path, - bridge_code, - post_restore_script, - userland_code, - high_resolution_time, - user_code, - wasm_module_bytes, - } => { - // `userland_code` is consumed only by the non-test snapshot - // path below; keep it bound (without a warning) under `test`. - #[cfg(test)] - let _ = &userland_code; - #[cfg(test)] - let _ = high_resolution_time; - #[cfg(test)] - let _ = &wasm_module_bytes; - #[cfg(not(test))] - { - let session_id = session_id.clone(); - // Use cached bridge code when host sends empty (0-length = use cached) - let should_update_cached_bridge_code = !bridge_code.is_empty(); - let effective_bridge_code = if bridge_code.is_empty() { - last_bridge_code.as_deref().unwrap_or("").to_string() - } else { - bridge_code - }; - // Same 0-length = use-cached convention for the userland bundle. - let should_update_cached_userland_code = !userland_code.is_empty(); - let effective_userland_code = if userland_code.is_empty() { - last_userland_code.as_deref().unwrap_or("").to_string() - } else { - userland_code - }; - - if let Err(message) = - snapshot::validate_bridge_code_size(&effective_bridge_code) - { - let result_frame = RuntimeEvent::ExecutionResult { - session_id, - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message, - stack: String::new(), - code: snapshot::V8_BRIDGE_CODE_LIMIT_ERROR_CODE.into(), - }), - }; - send_event_with_generation(&event_tx, output_generation, result_frame); - continue; - } - - if should_update_cached_bridge_code { - last_bridge_code = Some(effective_bridge_code.clone()); - } - if should_update_cached_userland_code { - last_userland_code = Some(effective_userland_code.clone()); - } - - if v8_isolate.is_some() - && (isolate_bridge_code.as_deref() - != Some(effective_bridge_code.as_str()) - || isolate_userland_code.as_deref() - != Some(effective_userland_code.as_str())) - { - *isolate_handle - .lock() - .expect("session isolate handle lock poisoned") = None; - // Reset pending promise-resolver Globals BEFORE this - // isolate is dropped. The registry is reused across - // isolate rebuilds, and a prior execution that was - // terminated early (Shutdown / timeout-abort) can - // leave resolvers registered, so they would otherwise - // outlive the isolate that created them. - reset_pending_promises(&mut pending); - drop(_v8_context.take()); - isolate::drop_isolate(v8_isolate.take()); - from_snapshot = false; - isolate_bridge_code = None; - isolate_userland_code = None; - } - - // Deferred isolate creation: create on first Execute using snapshot cache - if v8_isolate.is_none() { - isolate::init_v8_platform(); - // The snapshot captures the bridge AND (when present) the - // agent-SDK userland bundle, keyed process-wide by both, so - // the SDK is evaluated once per sidecar and reused here. - let phase_start = Instant::now(); - let snapshot_blob = match snapshot_cache.get_or_create_with_userland( - &effective_bridge_code, - (!effective_userland_code.is_empty()) - .then_some(effective_userland_code.as_str()), - ) { - Ok(blob) => Some(blob), - Err(message) => { - // Snapshot creation runs in a helper subprocess; if - // that fails (unsupported platform, spawn failure), - // degrade to a fresh isolate that evaluates the - // bridge in-context rather than failing the session. - eprintln!( - "secure-exec-v8-runtime: snapshot creation failed, \ - falling back to fresh isolate: {message}" - ); - None - } - }; - record_v8_session_phase("snapshot_get", phase_start.elapsed()); - let mut iso = match snapshot_blob { - Some(blob) => { - from_snapshot = true; - eprintln!( - "secure-exec-v8-runtime: restored session isolate from_snapshot=true" - ); - let phase_start = Instant::now(); - // rusty_v8 0.130's CreateParams::snapshot_blob - // takes owned 'static data, so this copy remains - // per exec until the API can accept cached bytes. - let snapshot_blob = (*blob).clone(); - record_v8_session_phase("blob_clone", phase_start.elapsed()); - let phase_start = Instant::now(); - let isolate = snapshot::create_isolate_from_snapshot( - snapshot_blob, - heap_limit_mb, - ); - record_v8_session_phase("isolate_new", phase_start.elapsed()); - isolate - } - None => { - from_snapshot = false; - let phase_start = Instant::now(); - let isolate = isolate::create_isolate(heap_limit_mb); - record_v8_session_phase("isolate_new", phase_start.elapsed()); - isolate - } - }; - iso.set_host_import_module_dynamically_callback( - execution::dynamic_import_callback, - ); - iso.set_host_initialize_import_meta_object_callback( - execution::import_meta_object_callback, - ); - high_resolution_time_origin = Instant::now(); - *isolate_handle - .lock() - .expect("session isolate handle lock poisoned") = - Some(iso.thread_safe_handle()); - let ctx = isolate::create_context(&mut iso); - _v8_context = Some(ctx); - v8_isolate = Some(iso); - isolate_bridge_code = Some(effective_bridge_code.clone()); - isolate_userland_code = Some(effective_userland_code.clone()); - } - - let iso = v8_isolate.as_mut().unwrap(); - iso.cancel_terminate_execution(); - - // Create execution context: Context::new on a snapshot-restored - // isolate gives a fresh clone of the snapshot's default context - // (bridge IIFE already executed, all infrastructure set up). - // On a non-snapshot isolate, this gives a blank context. - let exec_context = isolate::create_context(iso); - - if high_resolution_time { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - execution::install_high_resolution_time_global( - scope, - &high_resolution_time_origin as *const Instant, - ); - } - - // Inject globals from last InjectGlobals payload - if let Some(ref payload) = last_globals_payload { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - if let Err(error) = - execution::inject_globals_from_payload(scope, payload) - { - let result_frame = RuntimeEvent::ExecutionResult { - session_id, - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: error.error_type, - message: error.message, - stack: error.stack, - code: error.code.unwrap_or_default(), - }), - }; - send_event_with_generation( - &event_tx, - output_generation, - result_frame, - ); - continue; - } - } - - // Arm a per-execution abort channel so timeouts and external - // terminate requests can unblock sync bridge waits. - let (_active_execution_abort, abort_rx) = - ActiveExecutionAbort::arm(&execution_abort); - - // Create deferred queue for sync bridge call filtering - let deferred_queue = new_deferred_queue(); - - // Create BridgeCallContext with channel sender (no shared mutex) - let channel_rx = ChannelResponseReceiver::with_abort( - rx.clone(), - abort_rx.clone(), - Arc::clone(&deferred_queue), - ); - let bridge_ctx = BridgeCallContext::with_receiver( - Box::new(ChannelRuntimeEventSender::new( - event_tx.clone(), - output_generation, - )), - Box::new(channel_rx), - session_id.clone(), - Arc::clone(&call_id_router), - Arc::clone(&shared_call_id), - ); - - // Replace stub bridge functions with real session-local ones - // (on snapshot context) or register from scratch (on fresh context). - // Both paths use the same function — global.set() works for both. - let _sync_store; - let _async_store; - let sync_bridge_fns = sync_bridge_fns(); - let async_bridge_fns = async_bridge_fns(); - { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - - (_sync_store, _async_store) = bridge::replace_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const bridge::PendingPromises, - sync_bridge_fns, - async_bridge_fns, - ); - } - - // Run post-restore init script (config, mutable state reset) - // after bridge fn replacement but before user code - if !post_restore_script.is_empty() { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - let (prs_code, prs_err) = - execution::run_init_script(scope, &post_restore_script); - if prs_code != 0 { - let result_frame = RuntimeEvent::ExecutionResult { - session_id, - exit_code: prs_code, - exports: None, - error: prs_err.map(|e| ExecutionErrorBin { - error_type: e.error_type, - message: e.message, - stack: e.stack, - code: e.code.unwrap_or_default(), - }), - }; - send_event_with_generation( - &event_tx, - output_generation, - result_frame, - ); - continue; - } - } - - if let Some(wasm_module_bytes) = wasm_module_bytes.as_ref() { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - if !install_wasm_module_bytes_global(scope, wasm_module_bytes) { - let result_frame = RuntimeEvent::ExecutionResult { - session_id, - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message: "failed to install __agentOSWasmModuleBytes" - .into(), - stack: String::new(), - code: String::new(), - }), - }; - send_event_with_generation( - &event_tx, - output_generation, - result_frame, - ); - continue; - } - } - - // Arm the TRUE CPU-TIME budget watchdog before running - // guest code when the caller passes a nonzero - // `limits.jsRuntime.cpuTimeLimitMs` (normalized: `0`/unset => - // `None` => not armed at this runtime layer). The sidecar - // supplies the bounded default for VM executions. - // - // The watchdog counts ACTIVE JS CPU only (idle/await - // excluded) by polling the execution thread's CPU clock, so - // a guest that mostly awaits is NOT killed by it. The - // INDEPENDENT wall-clock backstop (armed just below) covers - // the idle/await case when the operator opts into it. - let mut cpu_budget_guard = match cpu_time_limit_ms { - Some(budget_ms) => { - // Enforcing a CPU budget requires the execution - // thread's CPU clock captured at session start. If - // it is unavailable we cannot honor the operator's - // requested cap — surface that rather than silently - // running uncapped. - let cpu_clock = match exec_thread_cpu_clock { - Some(clock) => clock, - None => { - let result_frame = RuntimeEvent::ExecutionResult { - session_id, - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message: format!( - "{}: per-thread CPU clock unavailable; cannot enforce limits.jsRuntime.cpuTimeLimitMs", - crate::timeout::CPU_BUDGET_GUARD_START_ERROR_CODE - ), - stack: String::new(), - code: crate::timeout::CPU_BUDGET_GUARD_START_ERROR_CODE - .into(), - }), - }; - send_event_with_generation( - &event_tx, - output_generation, - result_frame, - ); - continue; - } - }; - let handle = iso.thread_safe_handle(); - match crate::timeout::CpuBudgetGuard::new( - budget_ms, - cpu_clock, - handle, - execution_abort.clone(), - ) { - Ok(guard) => Some(guard), - Err(message) => { - let result_frame = RuntimeEvent::ExecutionResult { - session_id, - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message, - stack: String::new(), - code: - crate::timeout::CPU_BUDGET_GUARD_START_ERROR_CODE - .into(), - }), - }; - send_event_with_generation( - &event_tx, - output_generation, - result_frame, - ); - continue; - } - } - } - _ => None, - }; - - // Arm the INDEPENDENT, opt-in WALL-CLOCK backstop alongside - // the CPU budget. Unlike the CPU budget, this counts elapsed - // real time INCLUDING idle/await, so it can cap a guest that - // blocks or awaits indefinitely. Armed only when the operator - // opts in via `limits.jsRuntime.wallClockLimitMs` (normalized: - // `0`/unset => `None` => not armed => NO wall-clock limit, so - // long-lived ACP adapters are never killed by a default). - // Whichever guard fires first calls `terminate_execution` and - // records its abort reason; the result frame reports which. - let mut wall_clock_guard = match wall_clock_limit_ms { - Some(limit_ms) => { - let handle = iso.thread_safe_handle(); - match crate::timeout::TimeoutGuard::with_execution_abort( - limit_ms, - handle, - execution_abort.clone(), - ) { - Ok(guard) => Some(guard), - Err(message) => { - let result_frame = RuntimeEvent::ExecutionResult { - session_id, - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message, - stack: String::new(), - code: - crate::timeout::TIMEOUT_GUARD_START_ERROR_CODE - .into(), - }), - }; - send_event_with_generation( - &event_tx, - output_generation, - result_frame, - ); - continue; - } - } - } - _ => None, - }; - - // On snapshot-restored context, skip bridge IIFE (already in - // snapshot) and run user code only. On fresh context, run full - // bridge code + user code as before. - let bridge_code_for_exec = if from_snapshot { - "" - } else { - &effective_bridge_code - }; - let file_path_opt = if file_path.is_empty() { - None - } else { - Some(file_path.as_str()) - }; - let phase_start = Instant::now(); - let (mut code, mut exports, mut error) = if mode == 0 { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - let (c, e) = execution::execute_script_with_options( - scope, - Some(&bridge_ctx), - bridge_code_for_exec, - &user_code, - file_path_opt, - &mut bridge_cache, - ); - (c, None, e) - } else { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - execution::execute_module( - scope, - &bridge_ctx, - bridge_code_for_exec, - &user_code, - file_path_opt, - &mut bridge_cache, - ) - }; - - // Re-check async ESM completion once immediately so - // pure-microtask top-level await settles without - // needing a bridge event-loop round-trip. - if mode != 0 && error.is_none() { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - if let Some((next_code, next_exports, next_error)) = - execution::finalize_pending_module_evaluation(scope) - { - code = next_code; - exports = next_exports; - error = next_error; - } - } - record_v8_session_phase("user_code_execute", phase_start.elapsed()); - - // Run event loop while bridge work or async ESM - // evaluation is still pending. For ESM modules (mode != 0), - // always enter the event loop even if no pending promises - // are visible yet — the module body may have registered - // timers, stdin listeners, or child_process handles that - // need event loop pumping to deliver their callbacks. - let should_enter_event_loop = !pending.is_empty() - || execution::has_pending_module_evaluation() - || execution::has_pending_script_evaluation() - || !deferred_queue.lock().unwrap().is_empty(); - let event_loop_status = if should_enter_event_loop { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - run_event_loop( - scope, - &rx, - &pending, - Some(&abort_rx), - Some(&deferred_queue), - ) - } else { - EventLoopStatus::Completed - }; - - let mut terminated = - matches!(event_loop_status, EventLoopStatus::Terminated); - if let EventLoopStatus::Failed(next_code, next_error) = event_loop_status { - code = next_code; - error = Some(next_error); - } - - // Finalize any entry-module top-level await that was - // waiting on bridge-driven async work (timers/network). - if !terminated && mode != 0 && error.is_none() { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - if let Some((next_code, next_exports, next_error)) = - execution::finalize_pending_module_evaluation(scope) - { - code = next_code; - exports = next_exports; - error = next_error; - } - } - - // Keep the session alive while handles (timers, child - // processes, stdin listeners) are active. Long-lived - // ACP adapters often run as plain scripts, so this - // cannot be limited to ESM entrypoints. - if !terminated && error.is_none() { - // Phase 1: call _waitForActiveHandles() to register a pending promise - { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - let global = ctx.global(scope); - let key = v8::String::new(scope, "_waitForActiveHandles").unwrap(); - if let Some(func) = global.get(scope, key.into()) { - if func.is_function() { - let func = - v8::Local::::try_from(func).unwrap(); - let recv = v8::undefined(scope).into(); - if let Some(result) = func.call(scope, recv, &[]) { - if result.is_promise() { - let promise = - v8::Local::::try_from(result) - .unwrap(); - if promise.state() == v8::PromiseState::Pending { - execution::set_pending_script_evaluation( - scope, promise, - ); - } - } - } - } - } - } - - // Phase 2: pump event loop for active handles - if !pending.is_empty() - || execution::has_pending_script_evaluation() - || !deferred_queue.lock().unwrap().is_empty() - { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - let event_loop_status = run_event_loop( - scope, - &rx, - &pending, - Some(&abort_rx), - Some(&deferred_queue), - ); - - if matches!(event_loop_status, EventLoopStatus::Terminated) { - terminated = true; - } - if let EventLoopStatus::Failed(next_code, next_error) = - event_loop_status - { - code = next_code; - error = Some(next_error); - } - } - } - - if !terminated && mode == 0 && error.is_none() { - let scope = &mut v8::HandleScope::new(iso); - let ctx = v8::Local::new(scope, &exec_context); - let scope = &mut v8::ContextScope::new(scope, ctx); - if let Some((next_code, next_error)) = - execution::finalize_pending_script_evaluation(scope) - { - code = next_code; - error = next_error; - } - } - - // Determine which execution budget (if any) fired. Both the - // CPU-time budget and the wall-clock backstop can be armed; - // whichever fired first recorded its abort reason. Prefer the - // recorded abort reason (first-writer-wins) so the result - // attributes termination to the guard that actually fired. - let abort_reason = execution_abort_reason(&execution_abort); - let wall_clock_timed_out = - wall_clock_guard.as_ref().is_some_and(|g| g.timed_out()) - || matches!( - abort_reason, - Some(ExecutionAbortReason::WallClockTimedOut) - ); - let cpu_budget_exceeded = - cpu_budget_guard.as_ref().is_some_and(|g| g.exceeded()) - || matches!( - abort_reason, - Some(ExecutionAbortReason::CpuBudgetExceeded) - ); - // If both happened to fire, the recorded abort reason is the - // authoritative first-fired guard; fall back to wall-clock - // only when no CPU-budget reason was recorded. - let cpu_budget_exceeded = cpu_budget_exceeded - && !matches!( - abort_reason, - Some(ExecutionAbortReason::WallClockTimedOut) - ); - let wall_clock_timed_out = wall_clock_timed_out && !cpu_budget_exceeded; - - // Cancel both watchdogs (joins their threads). - if let Some(ref mut guard) = cpu_budget_guard { - guard.cancel(); - } - drop(cpu_budget_guard); - if let Some(ref mut guard) = wall_clock_guard { - guard.cancel(); - } - drop(wall_clock_guard); - - if matches!(abort_reason, Some(ExecutionAbortReason::Terminated)) { - terminated = true; - code = 1; - exports = None; - error = None; - } - if terminated || cpu_budget_exceeded || wall_clock_timed_out { - iso.cancel_terminate_execution(); - } - - // Send ExecutionResult - let result_frame = if cpu_budget_exceeded { - if let Some(budget_ms) = cpu_time_limit_ms { - let capacity = budget_ms as usize; - warn_limit_exhausted(TrackedLimit::V8CpuTimeMs, capacity, capacity); - } - RuntimeEvent::ExecutionResult { - session_id, - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message: "Script execution exceeded the CPU-time budget \ - (limits.jsRuntime.cpuTimeLimitMs)" - .into(), - stack: String::new(), - code: "ERR_SCRIPT_CPU_BUDGET_EXCEEDED".into(), - }), - } - } else if wall_clock_timed_out { - if let Some(limit_ms) = wall_clock_limit_ms { - let capacity = limit_ms as usize; - warn_limit_exhausted( - TrackedLimit::V8WallClockMs, - capacity, - capacity, - ); - } - RuntimeEvent::ExecutionResult { - session_id, - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message: "Script execution exceeded the wall-clock limit \ - (limits.jsRuntime.wallClockLimitMs)" - .into(), - stack: String::new(), - code: "ERR_SCRIPT_WALL_CLOCK_EXCEEDED".into(), - }), - } - } else if terminated { - RuntimeEvent::ExecutionResult { - session_id, - exit_code: 1, - exports: None, - error: Some(ExecutionErrorBin { - error_type: "Error".into(), - message: "Execution terminated".into(), - stack: String::new(), - code: String::new(), - }), - } - } else { - RuntimeEvent::ExecutionResult { - session_id, - exit_code: code, - exports, - error: error.map(|e| ExecutionErrorBin { - error_type: e.error_type, - message: e.message, - stack: e.stack, - code: e.code.unwrap_or_default(), - }), - } - }; - - execution::clear_pending_module_evaluation(); - execution::clear_pending_script_evaluation(); - execution::clear_module_state(); - - send_event_with_generation(&event_tx, output_generation, result_frame); - } - #[cfg(test)] - { - let _ = (mode, file_path, bridge_code, post_restore_script, user_code); - } - } - SessionMessage::BridgeResponse(_) - | SessionMessage::StreamEvent(_) - | SessionMessage::TerminateExecution => { - handle_late_session_message(&event_tx, &session_id, output_generation, msg); - } - }, - } - } - - // Drop V8 resources (only present in non-test mode) - #[cfg(not(test))] - { - *isolate_handle - .lock() - .expect("session isolate handle lock poisoned") = None; - // Reset pending promise-resolver Globals BEFORE the isolate is dropped on - // thread teardown. run_event_loop can exit early (Shutdown / timeout-abort) - // with resolvers still registered, so without this the Globals would drop - // after their isolate — leaking across session create/destroy churn and - // violating the V8 lifetime contract. - reset_pending_promises(&mut pending); - drop(_v8_context.take()); - isolate::drop_isolate(v8_isolate.take()); - } - - // Release concurrency slot - { - let (lock, cvar) = &*slot_control; - let mut count = lock.lock().unwrap(); - *count -= 1; - cvar.notify_one(); - } -} - -/// Sync bridge functions block V8 while the host processes the call -/// (applySync/applySyncPromise). Async bridge functions return a Promise to V8. -struct BridgeFnPartitions { - sync: Vec<&'static str>, - async_fns: Vec<&'static str>, -} - -pub(crate) fn sync_bridge_fns() -> &'static [&'static str] { - &bridge_fn_partitions().sync -} - -pub(crate) fn async_bridge_fns() -> &'static [&'static str] { - &bridge_fn_partitions().async_fns -} - -fn bridge_fn_partitions() -> &'static BridgeFnPartitions { - static PARTITIONS: OnceLock = OnceLock::new(); - PARTITIONS.get_or_init(|| BridgeFnPartitions { - sync: bridge_fns_for(|convention| { - matches!( - convention, - BridgeCallConvention::Sync | BridgeCallConvention::SyncPromise - ) - }), - async_fns: bridge_fns_for(|convention| convention == BridgeCallConvention::Async), - }) -} - -fn bridge_fns_for(filter: impl Fn(BridgeCallConvention) -> bool) -> Vec<&'static str> { - bridge_contract() - .groups - .iter() - .filter(|group| filter(group.convention)) - .flat_map(|group| group.names.iter().map(String::as_str)) - .collect() -} - -/// Reset every pending promise-resolver `v8::Global` handle held by `pending`. -/// -/// `v8::Global` handles MUST be reset/dropped *before* the `v8::Isolate` that -/// created them is torn down. The session reuses a single `PendingPromises` -/// registry across executions and across isolate rebuilds, and `run_event_loop` -/// can exit early (Shutdown at the `SessionCommand::Shutdown` arm, or -/// timeout-abort via the `abort_rx` branch) while resolvers are still -/// registered. On those paths the registry can outlive an isolate. Call this -/// immediately before every isolate drop (rebuild and thread teardown) so the -/// `Global` handles are dropped while their isolate is still -/// alive — preventing both a leak across session create/destroy churn (bounded -/// by `MAX_PENDING_PROMISES`) and a V8 lifetime-contract violation. -#[doc(hidden)] -pub fn reset_pending_promises(pending: &mut crate::bridge::PendingPromises) { - // Swap in an empty registry and drop the populated one in place. Dropping a - // `PendingPromises` resets all of its `Global` handles. - drop(std::mem::take(pending)); -} - -/// Run the session event loop: dispatch incoming messages to V8. -/// -/// Called after script/module execution when there are pending async promises. -/// Polls the session channel for BridgeResponse, StreamEvent, and -/// TerminateExecution messages, dispatching each into V8 with microtask flush. -/// -/// When `deferred` is provided, drains queued messages from sync bridge calls -/// before blocking on the channel. This prevents StreamEvent loss when sync -/// bridge calls consume non-BridgeResponse messages from the shared channel. -/// -/// When `abort_rx` is provided (timeout is configured), uses `select!` to -/// also monitor the abort channel — if the timeout fires and drops the sender, -/// the abort channel unblocks and terminates execution. -/// -/// Returns true if execution completed normally, false if terminated. -#[doc(hidden)] -pub fn run_event_loop( - scope: &mut v8::HandleScope, - rx: &Receiver, - pending: &crate::bridge::PendingPromises, - abort_rx: Option<&crossbeam_channel::Receiver<()>>, - deferred: Option<&DeferredQueue>, -) -> EventLoopStatus { - while !pending.is_empty() - || execution::pending_module_evaluation_needs_wait(scope) - || execution::pending_script_evaluation_needs_wait(scope) - || pending_guest_timer_count(scope) > 0 - || pending_guest_immediate_count(scope) > 0 - || deferred - .map(|dq| !dq.lock().unwrap().is_empty()) - .unwrap_or(false) - { - pump_v8_message_loop(scope); - - // Drain deferred messages queued by sync bridge calls before blocking - if let Some(dq) = deferred { - let frames: Vec = dq.lock().unwrap().drain(..).collect(); - for frame in frames { - let status = dispatch_event_loop_frame(scope, frame, pending); - if !matches!(status, EventLoopStatus::Completed) { - return status; - } - } - if pending.is_empty() - && !execution::pending_module_evaluation_needs_wait(scope) - && !execution::pending_script_evaluation_needs_wait(scope) - && pending_guest_timer_count(scope) == 0 - && pending_guest_immediate_count(scope) == 0 - { - break; - } - } - - // Flush microtasks before blocking. Run in a loop to drain the full - // microtask queue -- each checkpoint may resolve Promises that schedule - // new microtasks (e.g., async function await chains). - for _ in 0..100 { - scope.perform_microtask_checkpoint(); - pump_v8_message_loop(scope); - // Check if new deferred work appeared from microtask processing - if let Some(dq) = deferred { - if !dq.lock().unwrap().is_empty() { - break; // New bridge work to process - } - } - } - - if pending_guest_immediate_count(scope) > 0 { - match try_recv_session_command(scope, rx, abort_rx) { - Ok(Some(cmd)) => { - let status = dispatch_session_command(scope, cmd, pending); - if !matches!(status, EventLoopStatus::Completed) { - return status; - } - } - Ok(None) => { - let status = drain_guest_immediates(scope); - if !matches!(status, EventLoopStatus::Completed) { - return status; - } - } - Err(status) => return status, - } - scope.perform_microtask_checkpoint(); - pump_v8_message_loop(scope); - } - - // Re-check exit conditions after microtask flush — the microtask may - // have resolved all pending promises or registered new handles. - if pending.is_empty() - && !execution::pending_module_evaluation_needs_wait(scope) - && !execution::pending_script_evaluation_needs_wait(scope) - && pending_guest_timer_count(scope) == 0 - && pending_guest_immediate_count(scope) == 0 - && deferred - .map(|dq| dq.lock().unwrap().is_empty()) - .unwrap_or(true) - { - break; - } - - // Receive next command with interleaved microtask processing. - // Instead of blocking indefinitely, use a short timeout so we can - // periodically flush microtasks (like Node.js's libuv + DrainTasks pattern). - let cmd = loop { - if pending_guest_immediate_count(scope) > 0 { - match try_recv_session_command(scope, rx, abort_rx) { - Ok(Some(cmd)) => break cmd, - Ok(None) => { - let status = drain_guest_immediates(scope); - if !matches!(status, EventLoopStatus::Completed) { - return status; - } - scope.perform_microtask_checkpoint(); - pump_v8_message_loop(scope); - continue; - } - Err(status) => return status, - } - } - let recv_result = if let Some(abort) = abort_rx { - crossbeam_channel::select! { - recv(rx) -> result => result.ok(), - recv(abort) -> _ => { - scope.terminate_execution(); - return EventLoopStatus::Terminated; - }, - default(std::time::Duration::from_millis(1)) => None, - } - } else { - rx.recv_timeout(std::time::Duration::from_millis(1)).ok() - }; - if let Some(cmd) = recv_result { - break cmd; - } - // No command received — flush microtasks and check deferred queue - scope.perform_microtask_checkpoint(); - pump_v8_message_loop(scope); - if let Some(dq) = deferred { - if !dq.lock().unwrap().is_empty() { - // New deferred work appeared — drain it in the outer loop - let frames: Vec = dq.lock().unwrap().drain(..).collect(); - for frame in frames { - let status = dispatch_event_loop_frame(scope, frame, pending); - if !matches!(status, EventLoopStatus::Completed) { - return status; - } - } - } - } - // Check if we should exit - if pending.is_empty() - && !execution::pending_module_evaluation_needs_wait(scope) - && !execution::pending_script_evaluation_needs_wait(scope) - && pending_guest_timer_count(scope) == 0 - && pending_guest_immediate_count(scope) == 0 - && deferred - .map(|dq| dq.lock().unwrap().is_empty()) - .unwrap_or(true) - { - return EventLoopStatus::Completed; - } - }; - - let status = dispatch_session_command(scope, cmd, pending); - if !matches!(status, EventLoopStatus::Completed) { - return status; - } - } - EventLoopStatus::Completed -} - -fn try_recv_session_command( - scope: &mut v8::HandleScope, - rx: &Receiver, - abort_rx: Option<&crossbeam_channel::Receiver<()>>, -) -> Result, EventLoopStatus> { - if let Some(abort) = abort_rx { - crossbeam_channel::select! { - recv(abort) -> _ => { - scope.terminate_execution(); - Err(EventLoopStatus::Terminated) - }, - recv(rx) -> result => Ok(result.ok()), - default => Ok(None), - } - } else { - match rx.try_recv() { - Ok(cmd) => Ok(Some(cmd)), - Err(crossbeam_channel::TryRecvError::Empty) => Ok(None), - Err(crossbeam_channel::TryRecvError::Disconnected) => Ok(None), - } - } -} - -fn dispatch_session_command( - scope: &mut v8::HandleScope, - cmd: SessionCommand, - pending: &crate::bridge::PendingPromises, -) -> EventLoopStatus { - match cmd { - SessionCommand::Message(frame) => dispatch_event_loop_frame(scope, frame, pending), - SessionCommand::SetModuleReader(reader) => { - execution::install_session_guest_reader(Some(reader)); - EventLoopStatus::Completed - } - SessionCommand::Shutdown => EventLoopStatus::Terminated, - } -} - -fn pending_guest_timer_count(scope: &mut v8::HandleScope) -> usize { - let tc = &mut v8::TryCatch::new(scope); - let context = tc.get_current_context(); - let global = context.global(tc); - let key = match v8::String::new(tc, "_getPendingTimerCount") { - Some(key) => key, - None => return 0, - }; - let Some(func_value) = global.get(tc, key.into()) else { - return 0; - }; - let Ok(func) = v8::Local::::try_from(func_value) else { - return 0; - }; - let Some(result) = func.call(tc, global.into(), &[]) else { - return 0; - }; - - result - .integer_value(tc) - .and_then(|count| usize::try_from(count).ok()) - .unwrap_or(0) -} - -fn pending_guest_immediate_count(scope: &mut v8::HandleScope) -> usize { - let tc = &mut v8::TryCatch::new(scope); - let context = tc.get_current_context(); - let global = context.global(tc); - let key = match v8::String::new(tc, "_getPendingImmediateCount") { - Some(key) => key, - None => return 0, - }; - let Some(func_value) = global.get(tc, key.into()) else { - return 0; - }; - let Ok(func) = v8::Local::::try_from(func_value) else { - return 0; - }; - let Some(result) = func.call(tc, global.into(), &[]) else { - return 0; - }; - - result - .integer_value(tc) - .and_then(|count| usize::try_from(count).ok()) - .unwrap_or(0) -} - -fn drain_guest_immediates(scope: &mut v8::HandleScope) -> EventLoopStatus { - let tc = &mut v8::TryCatch::new(scope); - let context = tc.get_current_context(); - let global = context.global(tc); - let key = match v8::String::new(tc, "_drainImmediates") { - Some(key) => key, - None => return EventLoopStatus::Completed, - }; - let Some(func_value) = global.get(tc, key.into()) else { - return EventLoopStatus::Completed; - }; - let Ok(func) = v8::Local::::try_from(func_value) else { - return EventLoopStatus::Completed; - }; - let _ = func.call(tc, global.into(), &[]); - tc.perform_microtask_checkpoint(); - if let Some(exception) = tc.exception() { - let (code, err) = execution::exception_to_result(tc, exception); - return EventLoopStatus::Failed(code, err); - } - if let Some(err) = execution::take_unhandled_promise_rejection(tc) { - return EventLoopStatus::Failed(1, err); - } - EventLoopStatus::Completed -} - -fn pump_v8_message_loop(scope: &mut v8::HandleScope) { - let platform = v8::V8::get_current_platform(); - while v8::Platform::pump_message_loop(&platform, scope, false) { - scope.perform_microtask_checkpoint(); - } -} - -/// Dispatch a single session message within the event loop. -/// Returns the event-loop status after handling the frame. -#[derive(Debug)] -#[doc(hidden)] -pub enum EventLoopStatus { - Completed, - Terminated, - Failed(i32, ExecutionError), -} - -fn dispatch_event_loop_frame( - scope: &mut v8::HandleScope, - frame: SessionMessage, - pending: &crate::bridge::PendingPromises, -) -> EventLoopStatus { - match frame { - SessionMessage::BridgeResponse(BridgeResponse { - call_id, - status, - payload, - }) => { - let (result, error) = if status == 1 { - (None, Some(String::from_utf8_lossy(&payload).to_string())) - } else if status == 2 || !payload.is_empty() { - // status=0: V8-serialized, status=2: raw binary (Uint8Array) - (Some(payload), None) - } else { - (None, None) - }; - let _ = crate::bridge::resolve_pending_promise( - scope, pending, call_id, status, result, error, - ); - // Microtasks already flushed in resolve_pending_promise - EventLoopStatus::Completed - } - SessionMessage::StreamEvent(StreamEvent { - event_type, - payload, - }) => { - let tc = &mut v8::TryCatch::new(scope); - crate::stream::dispatch_stream_event(tc, &event_type, &payload); - tc.perform_microtask_checkpoint(); - if let Some(exception) = tc.exception() { - let (code, err) = execution::exception_to_result(tc, exception); - return EventLoopStatus::Failed(code, err); - } - if let Some(err) = execution::take_unhandled_promise_rejection(tc) { - return EventLoopStatus::Failed(1, err); - } - EventLoopStatus::Completed - } - SessionMessage::TerminateExecution => { - scope.terminate_execution(); - EventLoopStatus::Terminated - } - _ => { - // Ignore other messages during event loop - EventLoopStatus::Completed - } - } -} - -/// ResponseReceiver that receives typed session messages directly from the session channel. -/// -/// Only returns BridgeResponse frames from recv_response(). Non-BridgeResponse -/// messages (StreamEvent, TerminateExecution) consumed during sync bridge calls -/// are queued in the deferred queue for later processing by the event loop. -/// -/// When `abort_rx` is set (timeout configured), uses `select!` to also monitor -/// the abort channel. If the timeout fires, the abort sender is dropped, which -/// unblocks the select and returns a timeout error. -pub(crate) struct ChannelResponseReceiver { - rx: Receiver, - abort_rx: Option>, - deferred: DeferredQueue, -} - -impl ChannelResponseReceiver { - #[allow(dead_code)] - pub(crate) fn new(rx: Receiver, deferred: DeferredQueue) -> Self { - ChannelResponseReceiver { - rx, - abort_rx: None, - deferred, - } - } - - pub(crate) fn with_abort( - rx: Receiver, - abort_rx: crossbeam_channel::Receiver<()>, - deferred: DeferredQueue, - ) -> Self { - ChannelResponseReceiver { - rx, - abort_rx: Some(abort_rx), - deferred, - } - } -} - -impl crate::host_call::BridgeResponseReceiver for ChannelResponseReceiver { - fn recv_response(&self, expected_call_id: u64) -> Result { - loop { - // Wait for next command, with optional abort monitoring - let cmd = if let Some(ref abort) = self.abort_rx { - crossbeam_channel::select! { - recv(self.rx) -> result => match result { - Ok(cmd) => cmd, - Err(_) => return Err("channel closed".into()), - }, - recv(abort) -> _ => { - return Err("execution aborted".into()); - }, - } - } else { - match self.rx.recv() { - Ok(cmd) => cmd, - Err(_) => return Err("channel closed".into()), - } - }; - - match cmd { - SessionCommand::Message(frame) => { - if let SessionMessage::BridgeResponse(response) = &frame { - let call_id = response.call_id; - if call_id == expected_call_id { - crate::host_call::record_sync_bridge_response_channel_received(call_id); - return Ok(response.clone()); - } - push_deferred_sync_message(&self.deferred, frame)?; - continue; - } - // Queue non-BridgeResponse for later event loop processing - push_deferred_sync_message(&self.deferred, frame)?; - } - SessionCommand::SetModuleReader(reader) => { - execution::install_session_guest_reader(Some(reader)); - } - SessionCommand::Shutdown => return Err("session shutdown".into()), - } - } - } -} - -fn push_deferred_sync_message( - deferred: &DeferredQueue, - frame: SessionMessage, -) -> Result<(), String> { - let mut queue = deferred.lock().unwrap(); - if queue.len() >= MAX_DEFERRED_SYNC_MESSAGES { - return Err(format!( - "sync bridge deferred message queue exceeded limit of {MAX_DEFERRED_SYNC_MESSAGES}" - )); - } - queue.push_back(frame); - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use std::collections::{HashMap, HashSet}; - - /// Helper to create a SessionManager for tests - fn test_manager(max: usize) -> SessionManager { - test_manager_with_events(max).0 - } - - fn test_manager_with_events(max: usize) -> (SessionManager, Receiver) { - let (tx, _rx) = crossbeam_channel::unbounded(); - let router: CallIdRouter = Arc::new(Mutex::new(HashMap::new())); - let snap_cache = Arc::new(SnapshotCache::new(4)); - let manager = SessionManager::new(max, tx, router, snap_cache); - (manager, _rx) - } - - #[test] - fn zero_cpu_time_limit_is_normalized_to_no_timeout() { - assert_eq!(normalize_cpu_time_limit_ms(None), None); - assert_eq!(normalize_cpu_time_limit_ms(Some(0)), None); - assert_eq!(normalize_cpu_time_limit_ms(Some(1)), Some(1)); - } - - fn expect_late_message_warning( - rx: &Receiver, - session_id: &str, - error_code: &str, - detail_fragment: &str, - ) { - let event = rx - .recv_timeout(std::time::Duration::from_millis(200)) - .expect("late-message warning"); - match event.event { - RuntimeEvent::Log { - session_id: observed_session_id, - channel, - message, - } => { - assert_eq!(observed_session_id, session_id); - assert_eq!(channel, 1, "late warnings should use stderr channel"); - assert!( - message.contains(error_code), - "warning should contain error code {error_code}, got {message}" - ); - assert!( - message.contains(detail_fragment), - "warning should mention {detail_fragment}, got {message}" - ); - } - other => panic!("expected late-message warning log, got {other:?}"), - } - } - - #[test] - fn bridge_contract_function_partitions_cover_contract() { - let contract = bridge_contract(); - - let expected_sync = contract - .groups - .iter() - .filter(|group| { - matches!( - group.convention, - BridgeCallConvention::Sync | BridgeCallConvention::SyncPromise - ) - }) - .flat_map(|group| group.names.iter().map(String::as_str)) - .collect::>(); - let expected_async = contract - .groups - .iter() - .filter(|group| group.convention == BridgeCallConvention::Async) - .flat_map(|group| group.names.iter().map(String::as_str)) - .collect::>(); - - let sync_names = sync_bridge_fns(); - let async_names = async_bridge_fns(); - let registered_sync = sync_names.iter().copied().collect::>(); - let registered_async = async_names.iter().copied().collect::>(); - - assert_eq!( - registered_sync, expected_sync, - "sync bridge function partition drifted from crates/bridge/bridge-contract.json" - ); - assert_eq!( - registered_async, expected_async, - "async bridge function partition drifted from crates/bridge/bridge-contract.json" - ); - assert!( - registered_sync.is_disjoint(®istered_async), - "sync and async bridge function partitions must not overlap" - ); - } - - #[test] - fn session_management() { - // Consolidated test to avoid V8 inter-test SIGSEGV issues. - // Covers: lifecycle and concurrency queuing. - - // --- Part 1: Single session create/destroy --- - { - let mut mgr = test_manager(4); - - mgr.create_session("session-aaa".into(), None, None, None) - .expect("create session A"); - assert_eq!(mgr.session_count(), 1); - - // Wait for thread to acquire slot and create isolate - std::thread::sleep(std::time::Duration::from_millis(200)); - - // Destroy session A - mgr.destroy_session("session-aaa") - .expect("destroy session A"); - assert_eq!(mgr.session_count(), 0); - } - - // --- Part 2: Multiple sessions --- - { - let mut mgr = test_manager(4); - - mgr.create_session("session-bbb".into(), None, None, None) - .expect("create session B"); - mgr.create_session("session-ccc".into(), Some(16), None, None) - .expect("create session C"); - assert_eq!(mgr.session_count(), 2); - - std::thread::sleep(std::time::Duration::from_millis(200)); - - // Duplicate session ID is rejected - let err = mgr.create_session("session-bbb".into(), None, None, None); - assert!(err.is_err()); - assert!(err.unwrap_err().contains("already exists")); - - // Sending to a missing session still fails. - let err = mgr.send_to_session("missing", SessionMessage::TerminateExecution); - assert!(err.is_err()); - assert!(err.unwrap_err().contains("does not exist")); - - // Destroy non-existent session - let err = mgr.destroy_session("no-such-session"); - assert!(err.is_err()); - assert!(err.unwrap_err().contains("does not exist")); - - mgr.destroy_sessions(["session-bbb".into(), "session-ccc".into()]); - assert_eq!(mgr.session_count(), 0); - } - - // --- Part 3: Max concurrency queuing --- - { - let mut mgr = test_manager(2); - - mgr.create_session("s1".into(), None, None, None) - .expect("create s1"); - mgr.create_session("s2".into(), None, None, None) - .expect("create s2"); - mgr.create_session("s3".into(), None, None, None) - .expect("create s3"); - - // Allow threads to acquire slots - std::thread::sleep(std::time::Duration::from_millis(300)); - - // Only 2 slots active (s3 is queued) - assert_eq!(mgr.active_slot_count(), 2); - assert_eq!(mgr.session_count(), 3); - - // Destroy s1 — releases slot, s3 acquires it - mgr.destroy_session("s1").expect("destroy s1"); - std::thread::sleep(std::time::Duration::from_millis(300)); - assert_eq!(mgr.active_slot_count(), 2); - assert_eq!(mgr.session_count(), 2); - - // Destroy remaining - mgr.destroy_sessions(["s2".into(), "s3".into()]); - std::thread::sleep(std::time::Duration::from_millis(100)); - assert_eq!(mgr.session_count(), 0); - assert_eq!(mgr.active_slot_count(), 0); - } - } - - #[test] - fn detach_session_clears_call_id_routes_for_session() { - let mut mgr = test_manager(1); - mgr.create_session_with_output_generation( - "session-route".into(), - None, - None, - None, - Some(7), - None, - ) - .expect("create session"); - mgr.call_id_router() - .lock() - .expect("call_id router") - .insert(42, "session-route".into()); - - assert!( - mgr.detach_session_if_output_generation("session-route", 7) - .expect("detach session"), - "matching output generation should detach session" - ); - assert!( - mgr.call_id_router() - .lock() - .expect("call_id router") - .get(&42) - .is_none(), - "detach should clear stale bridge call routes for the session" - ); - } - - #[test] - fn begin_destroy_session_removes_entry_before_finish() { - let mut mgr = test_manager(1); - mgr.create_session("two-phase".into(), None, None, None) - .expect("create session"); - - let first_shutdown = mgr - .begin_destroy_session("two-phase") - .expect("begin destroy session"); - assert_eq!( - mgr.session_count(), - 0, - "entry should be removed before the shutdown is finished" - ); - - // A same-id create during the unfinished shutdown window must succeed - // because the entry was removed up front. - mgr.create_session("two-phase".into(), None, None, None) - .expect("re-create session while first shutdown is unfinished"); - - let second_shutdown = mgr - .begin_destroy_session("two-phase") - .expect("begin destroy re-created session"); - first_shutdown.finish(); - second_shutdown.finish(); - assert_eq!(mgr.session_count(), 0); - } - - #[test] - fn session_shutdown_finish_clears_late_call_routes() { - let mut mgr = test_manager(1); - mgr.create_session("late-route".into(), None, None, None) - .expect("create session"); - - let shutdown = mgr - .begin_destroy_session("late-route") - .expect("begin destroy session"); - // Simulate a route the session thread registered between the pre-join - // route clear and thread exit. - mgr.call_id_router() - .lock() - .expect("call_id router") - .insert(42, "late-route".into()); - - shutdown.finish(); - assert!( - mgr.call_id_router() - .lock() - .expect("call_id router") - .get(&42) - .is_none(), - "finish should clear call routes registered during shutdown" - ); - } - - #[test] - fn channel_response_receiver_filters_bridge_response() { - use crate::host_call::BridgeResponseReceiver; - - // Sync bridge call interleaved with StreamEvent does not drop the StreamEvent - let (tx, rx) = crossbeam_channel::bounded(10); - let deferred = new_deferred_queue(); - let receiver = ChannelResponseReceiver::new(rx, Arc::clone(&deferred)); - - // Send: StreamEvent, TerminateExecution, then BridgeResponse - tx.send(SessionCommand::Message(SessionMessage::StreamEvent( - StreamEvent { - event_type: "child_stdout".into(), - payload: vec![0x01, 0x02], - }, - ))) - .unwrap(); - tx.send(SessionCommand::Message(SessionMessage::TerminateExecution)) - .unwrap(); - tx.send(SessionCommand::Message(SessionMessage::BridgeResponse( - BridgeResponse { - call_id: 1, - status: 0, - payload: vec![0xAB], - }, - ))) - .unwrap(); - - // recv_response should skip StreamEvent and TerminateExecution, return BridgeResponse - let frame = receiver.recv_response(1).unwrap(); - assert!( - frame.call_id == 1, - "expected BridgeResponse with call_id=1, got {:?}", - frame - ); - - // Deferred queue should contain the StreamEvent and TerminateExecution - let dq = deferred.lock().unwrap(); - assert_eq!(dq.len(), 2, "expected 2 deferred messages"); - assert!( - matches!(&dq[0], SessionMessage::StreamEvent(StreamEvent { event_type, .. }) if event_type == "child_stdout"), - "first deferred should be StreamEvent" - ); - assert!( - matches!(&dq[1], SessionMessage::TerminateExecution), - "second deferred should be TerminateExecution" - ); - } - - #[test] - fn channel_response_receiver_rejects_deferred_queue_overflow() { - use crate::host_call::BridgeResponseReceiver; - - let (tx, rx) = crossbeam_channel::bounded(MAX_DEFERRED_SYNC_MESSAGES + 1); - let deferred = new_deferred_queue(); - let receiver = ChannelResponseReceiver::new(rx, Arc::clone(&deferred)); - - for index in 0..=MAX_DEFERRED_SYNC_MESSAGES { - tx.send(SessionCommand::Message(SessionMessage::StreamEvent( - StreamEvent { - event_type: format!("child_stdout_{index}"), - payload: Vec::new(), - }, - ))) - .unwrap(); - } - - let error = receiver - .recv_response(1) - .expect_err("deferred queue overflow should reject sync bridge wait"); - assert!(error.contains("deferred message queue exceeded limit")); - assert_eq!(deferred.lock().unwrap().len(), MAX_DEFERRED_SYNC_MESSAGES); - } - - #[test] - fn pre_slot_deferred_command_overflow_is_bounded_and_logged() { - let (event_tx, event_rx) = crossbeam_channel::unbounded(); - let mut deferred_commands = VecDeque::new(); - - for _ in 0..MAX_DEFERRED_SESSION_COMMANDS { - assert!(defer_session_command_before_slot( - &mut deferred_commands, - &event_tx, - "queued-session", - Some(3), - SessionCommand::Message(SessionMessage::TerminateExecution), - )); - } - - assert!(!defer_session_command_before_slot( - &mut deferred_commands, - &event_tx, - "queued-session", - Some(3), - SessionCommand::Message(SessionMessage::TerminateExecution), - )); - assert_eq!(deferred_commands.len(), MAX_DEFERRED_SESSION_COMMANDS); - - let warning = event_rx.recv().expect("overflow warning"); - assert_eq!(warning.output_generation, Some(3)); - match warning.event { - RuntimeEvent::Log { - session_id, - channel, - message, - } => { - assert_eq!(session_id, "queued-session"); - assert_eq!(channel, 1); - assert!(message.contains(DEFERRED_COMMAND_LIMIT_ERROR_CODE)); - } - other => panic!("expected overflow warning log, got {other:?}"), - } - } - - #[test] - fn late_terminate_execution_is_logged_instead_of_silently_dropped() { - let (mut mgr, rx) = test_manager_with_events(1); - mgr.create_session("late-terminate".into(), None, None, None) - .expect("create session"); - - mgr.send_to_session("late-terminate", SessionMessage::TerminateExecution) - .expect("send late terminate"); - - expect_late_message_warning( - &rx, - "late-terminate", - LATE_TERMINATE_EXECUTION_ERROR_CODE, - "TerminateExecution", - ); - - mgr.destroy_session("late-terminate") - .expect("destroy session"); - } - - #[test] - fn channel_response_receiver_abort_unblocks_waiting_sync_call() { - use crate::host_call::BridgeResponseReceiver; - - let (_tx, rx) = crossbeam_channel::bounded(1); - let deferred = new_deferred_queue(); - let execution_abort = new_execution_abort(); - let (_active_abort, abort_rx) = ActiveExecutionAbort::arm(&execution_abort); - let receiver = ChannelResponseReceiver::with_abort(rx, abort_rx, deferred); - - let (result_tx, result_rx) = std::sync::mpsc::channel(); - let join_handle = std::thread::spawn(move || { - let _ = result_tx.send(receiver.recv_response(1)); - }); - - std::thread::sleep(std::time::Duration::from_millis(25)); - signal_execution_abort(&execution_abort, ExecutionAbortReason::Terminated); - - let result = result_rx - .recv_timeout(std::time::Duration::from_secs(1)) - .expect("abort should unblock the waiting receiver"); - assert_eq!( - result.expect_err("abort should not yield a bridge response"), - "execution aborted" - ); - - join_handle - .join() - .expect("receiver thread should exit cleanly"); - } - - #[test] - fn late_bridge_response_is_logged_instead_of_silently_dropped() { - let (mut mgr, rx) = test_manager_with_events(1); - mgr.create_session("late-bridge".into(), None, None, None) - .expect("create session"); - - mgr.send_to_session( - "late-bridge", - SessionMessage::BridgeResponse(BridgeResponse { - call_id: 41, - status: 0, - payload: vec![0xAA, 0xBB], - }), - ) - .expect("send late bridge response"); - - expect_late_message_warning( - &rx, - "late-bridge", - LATE_BRIDGE_RESPONSE_ERROR_CODE, - "BridgeResponse", - ); - - mgr.destroy_session("late-bridge").expect("destroy session"); - } - - /// Regression test for the pending-promise-resolver leak / V8 lifetime-contract - /// violation: when `run_event_loop` exits early (Shutdown or timeout-abort) the - /// `PendingPromises` registry can still hold `Global` handles, - /// and the session-thread teardown must reset them *before* dropping the isolate. - /// - /// This drives the real cleanup seam (`reset_pending_promises`) used on every - /// isolate-drop path. It populates the registry with live resolver Globals (as a - /// terminated execution would leave behind), runs the cleanup while the isolate - /// is still alive, and asserts the registry is empty (every Global dropped). - /// - /// Fast + bounded (a handful of resolvers, then the safeguard fires) — it asserts - /// the cleanup happens, it does not saturate `MAX_PENDING_PROMISES`. - #[test] - fn reset_pending_promises_drops_resolver_globals_before_isolate_teardown() { - use crate::bridge::{register_async_bridge_fns, PendingPromises}; - use crate::host_call::BridgeCallContext; - use crate::isolate; - use std::process::Command; - - // V8 isolates must be created in an isolated process: doing it inline in a - // parallel `cargo test` thread races the process-global V8 platform and - // segfaults. Re-exec this one test as a subprocess (matching the crate's - // bridge_v8_hardening_* / vm_context_registry convention). - const SUBPROCESS_ENV: &str = "AGENTOS_V8_RESET_PENDING_PROMISES_SUBPROCESS"; - if std::env::var_os(SUBPROCESS_ENV).is_none() { - let output = Command::new(std::env::current_exe().expect("current test binary")) - .arg("session::tests::reset_pending_promises_drops_resolver_globals_before_isolate_teardown") - .arg("--exact") - .arg("--nocapture") - .env(SUBPROCESS_ENV, "1") - .output() - .expect("spawn reset-pending-promises subprocess"); - assert!( - output.status.success(), - "reset-pending-promises subprocess failed with status {:?}\nstdout:\n{}\nstderr:\n{}", - output.status.code(), - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ); - return; - } - - isolate::init_v8_platform(); - - let mut v8_isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut v8_isolate); - let scope = &mut v8::HandleScope::new(&mut v8_isolate); - let context = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, context); - - let bridge_ctx = BridgeCallContext::new( - Box::new(std::io::sink()), - Box::new(std::io::empty()), - String::from("reset-pending-test"), - ); - let mut pending = PendingPromises::new(); - - // Each `_asyncFn(i)` call synchronously registers a pending promise - // resolver Global in `pending` and returns an unresolved Promise — - // exactly what remains registered when the event loop exits early on - // Shutdown / timeout-abort. - const REGISTERED: usize = 8; - let _async_fns = register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const PendingPromises, - &["_asyncFn"], - ); - let source = format!("for (let i = 0; i < {REGISTERED}; i++) {{ _asyncFn(i); }}"); - { - let tc = &mut v8::TryCatch::new(scope); - let code = v8::String::new(tc, &source).unwrap(); - let script = v8::Script::compile(tc, code, None).unwrap(); - assert!( - script.run(tc).is_some(), - "async bridge calls should register resolvers, not throw" - ); - assert!(!tc.has_caught(), "async bridge calls should not throw"); - } - assert_eq!( - pending.len(), - REGISTERED, - "each _asyncFn call must register a pending resolver Global" - ); - - // The cleanup invoked on every session-thread isolate-drop path. It must - // empty the registry (resetting every Global) while the - // isolate is still alive. - reset_pending_promises(&mut pending); - - assert_eq!( - pending.len(), - 0, - "reset_pending_promises must drop all pending resolver Globals before isolate teardown" - ); - - // Isolate is still alive here: the Globals were reset above, so dropping - // the scope/isolate below honors the V8 lifetime contract. - } -} diff --git a/crates/v8-runtime/src/snapshot.rs b/crates/v8-runtime/src/snapshot.rs deleted file mode 100644 index 1f11a6104..000000000 --- a/crates/v8-runtime/src/snapshot.rs +++ /dev/null @@ -1,2114 +0,0 @@ -// V8 startup snapshots: fast isolate creation from pre-compiled bridge code - -use std::collections::HashMap; -use std::io::{Read, Write}; -use std::process::{Command, Stdio}; -use std::sync::{Arc, Condvar, Mutex}; - -use sha2::{Digest, Sha256}; - -use crate::bridge::{external_refs, register_stub_bridge_fns}; -use crate::isolate::init_v8_platform; -use crate::session::{async_bridge_fns, sync_bridge_fns}; - -/// Maximum allowed snapshot blob size (50MB). -/// Prevents resource exhaustion from degenerate bridge code. -const MAX_SNAPSHOT_BLOB_BYTES: usize = 50 * 1024 * 1024; -const MAX_V8_BRIDGE_CODE_BYTES: usize = 16 * 1024 * 1024; -/// Userland (agent-SDK) bundles are whole dependency graphs flattened into one -/// IIFE, so they are larger than the bridge. Bounded so a degenerate bundle cannot -/// exhaust memory, but generous enough for a real SDK (the pi bundle is ~7.6 MB). -const MAX_V8_USERLAND_CODE_BYTES: usize = 32 * 1024 * 1024; -pub(crate) const V8_BRIDGE_CODE_LIMIT_ERROR_CODE: &str = "ERR_V8_BRIDGE_CODE_LIMIT"; -pub(crate) const V8_USERLAND_CODE_LIMIT_ERROR_CODE: &str = "ERR_V8_USERLAND_CODE_LIMIT"; - -const SNAPSHOT_HELPER_ENV: &str = "SECURE_EXEC_V8_SNAPSHOT_HELPER"; -const SNAPSHOT_HELPER_MAGIC: &[u8; 8] = b"SEV8SNP1"; -const SNAPSHOT_HELPER_OK: &[u8; 2] = b"OK"; -const SNAPSHOT_HELPER_ERR: &[u8; 3] = b"ERR"; -const SNAPSHOT_HELPER_NONE_LEN: u64 = u64::MAX; - -#[cfg(any(target_os = "linux", target_os = "android"))] -#[used] -#[link_section = ".init_array"] -static SNAPSHOT_HELPER_CTOR: extern "C" fn() = snapshot_helper_ctor; - -// Same pre-main hook on macOS: the darwin sidecar build ships this crate, and -// without the constructor the helper child would fall through to the normal -// main and the parent's snapshot request would fail. -#[cfg(target_os = "macos")] -#[used] -#[link_section = "__DATA,__mod_init_func"] -static SNAPSHOT_HELPER_CTOR: extern "C" fn() = snapshot_helper_ctor; - -#[cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))] -extern "C" fn snapshot_helper_ctor() { - if std::env::var_os(SNAPSHOT_HELPER_ENV).is_some() { - let code = run_snapshot_helper_from_stdio(); - std::process::exit(code); - } -} - -pub(crate) fn validate_bridge_code_size(bridge_code: &str) -> Result<(), String> { - if bridge_code.len() > MAX_V8_BRIDGE_CODE_BYTES { - return Err(format!( - "{V8_BRIDGE_CODE_LIMIT_ERROR_CODE}: bridge code too large for V8 bridge setup: {} bytes (max {})", - bridge_code.len(), - MAX_V8_BRIDGE_CODE_BYTES - )); - } - - Ok(()) -} - -pub(crate) fn validate_userland_code_size(userland_code: &str) -> Result<(), String> { - if userland_code.len() > MAX_V8_USERLAND_CODE_BYTES { - return Err(format!( - "{V8_USERLAND_CODE_LIMIT_ERROR_CODE}: userland snapshot code too large: {} bytes (max {})", - userland_code.len(), - MAX_V8_USERLAND_CODE_BYTES - )); - } - - Ok(()) -} - -/// Runs after the bridge but before the userland (agent-SDK) IIFE during snapshot -/// creation. Replaces bridge-backed lazy getters that would dispatch a host call -/// (unavailable when bridge fns are stubs) with static, snapshot-safe values. These -/// are environment-identity values (not per-session config), so baking them is -/// correct; per-session config is still injected post-restore. -const SNAPSHOT_USERLAND_PREP: &str = r#" -(function () { - // Agent-SDK bundles are esbuild IIFEs that expect a global CJS `require` for - // their node-builtin imports, but the bridge exposes require only via module - // wrappers. Bind one from the bridge's namespaced createRequire so the bundle's - // __require resolves builtins (via the in-context loadBuiltinModule) during - // snapshot eval; it also works post-restore (resolution flows through the real - // bridge fns swapped in after restore). - if (typeof globalThis.require === "undefined" && - typeof globalThis.__secureExecGuestCreateRequire === "function") { - try { - globalThis.require = globalThis.__secureExecGuestCreateRequire("/root/index.js"); - } catch (e) {} - } - // `process.versions` is a bridge-backed lazy getter: it derives `.node` from the - // per-session `config2.version` and merges a host bridge call. During snapshot - // creation the bridge fns are stubs AND the default `_processConfig` has no - // `version`, so the live getter THROWS — an agent SDK that reads it at - // module-init would fail. Rather than REPLACE the getter with a static value - // (which would permanently shadow the real per-session version for every - // restored session — they'd all read a frozen, fabricated identity), WRAP it: - // defer to the live getter so that post-restore — once the real bridge fns and - // per-session config are injected — sessions read accurate per-session versions, - // and fall back to the static, snapshot-safe identity only while the live getter - // throws (i.e. during snapshot creation, before any real config exists). - if (typeof process !== "undefined" && process) { - var staticVersions = { node: "20.0.0", v8: "12.0.0", uv: "1.0.0", modules: "115" }; - try { - var __verDesc = Object.getOwnPropertyDescriptor(process, "versions"); - var __liveVersions = __verDesc && __verDesc.get; - Object.defineProperty(process, "versions", { - configurable: true, - enumerable: true, - get: function () { - if (__liveVersions) { - try { - var v = __liveVersions.call(this); - // A real per-session result has a node version; during - // snapshot creation the live getter throws before here. - if (v && typeof v === "object" && v.node) return v; - } catch (e) {} - } - return staticVersions; - }, - }); - } catch (e) {} - } -})(); -"#; - -/// Compile and run a Script in the snapshot-creation context, returning a -/// descriptive error (with the V8 exception message) on failure. `label` -/// identifies the phase (e.g. "bridge code" / "userland code") in error text. -fn run_snapshot_script( - scope: &mut v8::HandleScope, - code: &str, - label: &str, - eager_compile: bool, -) -> Result<(), String> { - let try_catch = &mut v8::TryCatch::new(scope); - let source = match v8::String::new(try_catch, code) { - Some(source) => source, - None => return Err(format!("failed to create V8 string for {label}")), - }; - // NOTE(perf, measured 2026-07-02): EagerCompile moves cost into the snapshot - // blob: user_code_execute dropped 8.9ms -> 7.9ms on the wasm-runner floor, - // but isolate_new rose 4.0ms -> 7.4ms when isolate creation was still - // per-exec. Parked warm workers now prepay snapshot deserialization off-path, - // so only the userland script opts into eager compilation; bridge code and - // userland prep stay lazy. - let script = if eager_compile { - let resource_name = v8::String::new(try_catch, label).unwrap(); - let origin = v8::ScriptOrigin::new( - try_catch, - resource_name.into(), - 0, - 0, - false, - 0, - None, - false, - false, - false, - None, - ); - let mut source = v8::script_compiler::Source::new(source, Some(&origin)); - v8::script_compiler::compile( - try_catch, - &mut source, - v8::script_compiler::CompileOptions::EagerCompile, - v8::script_compiler::NoCacheReason::NoReason, - ) - } else { - v8::Script::compile(try_catch, source, None) - }; - let Some(script) = script else { - let message = try_catch - .exception() - .map(|exception| exception.to_rust_string_lossy(try_catch)) - .unwrap_or_else(|| format!("{label} compilation failed during snapshot creation")); - return Err(format!( - "{label} compilation failed during snapshot creation: {message}" - )); - }; - if script.run(try_catch).is_none() { - let message = try_catch - .exception() - .map(|exception| exception.to_rust_string_lossy(try_catch)) - .unwrap_or_else(|| format!("{label} execution failed during snapshot creation")); - return Err(format!( - "{label} execution failed during snapshot creation: {message}" - )); - } - Ok(()) -} - -/// Create a V8 startup snapshot with a fully-initialized bridge context. -/// -/// Registers stub bridge functions on the global, injects default config -/// globals, then compiles and executes the bridge IIFE. The resulting -/// context — with all bridge infrastructure set up — is snapshotted. -/// -/// After restore, stub bridge functions are replaced with real session-local -/// ones, and per-session config is injected via a post-restore script. -/// -/// Returns an error if the bridge code fails to compile or the resulting -/// snapshot exceeds MAX_SNAPSHOT_BLOB_BYTES. -pub fn create_snapshot(bridge_code: &str) -> Result, String> { - create_snapshot_inner(bridge_code, None) -} - -/// Create a V8 startup snapshot whose default context has BOTH the bridge -/// infrastructure AND an evaluated userland module graph (e.g. a bundled agent -/// SDK) captured into it. -/// -/// `userland_code` is an IIFE (esbuild `format:'iife'`) that runs after the bridge -/// in the same context and publishes its evaluated exports on `globalThis`. Because -/// the bridge has already installed node-builtin polyfills and stub bridge fns at -/// this point, the userland code can `require`/reference them while it evaluates. -/// The whole post-evaluation heap is frozen into the blob, so restoring a fresh -/// isolate skips re-evaluating the SDK entirely — collapsing the per-session -/// module-load/eval tax. Per-session bridge fns and config are still swapped/injected -/// post-restore exactly as for the bridge-only snapshot. -pub fn create_snapshot_with_userland( - bridge_code: &str, - userland_code: &str, -) -> Result, String> { - create_snapshot_inner(bridge_code, Some(userland_code)) -} - -fn create_snapshot_inner( - bridge_code: &str, - userland_code: Option<&str>, -) -> Result, String> { - validate_bridge_code_size(bridge_code)?; - if let Some(userland_code) = userland_code { - validate_userland_code_size(userland_code)?; - } - - create_snapshot_in_subprocess(bridge_code, userland_code) -} - -fn create_snapshot_inner_in_process( - bridge_code: &str, - userland_code: Option<&str>, -) -> Result, String> { - validate_bridge_code_size(bridge_code)?; - if let Some(userland_code) = userland_code { - validate_userland_code_size(userland_code)?; - } - - init_v8_platform(); - - crate::isolate::with_isolate_lifecycle_lock(|| { - let mut isolate = v8::Isolate::snapshot_creator(Some(external_refs()), None); - let bridge_result = { - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - // Register stub bridge functions so the IIFE can reference them. - let sync_bridge_fns = sync_bridge_fns(); - let async_bridge_fns = async_bridge_fns(); - register_stub_bridge_fns(scope, sync_bridge_fns, async_bridge_fns); - - // Inject default config globals for bridge IIFE setup - inject_snapshot_defaults(scope); - - // Compile and run bridge code — context captures fully-initialized state. - // Then, if present, run the userland (agent-SDK) IIFE in the SAME context so - // its evaluated graph is captured alongside the bridge. - let result = (|| -> Result<(), String> { - run_snapshot_script(scope, bridge_code, "bridge code", false)?; - if let Some(userland_code) = userland_code { - // Some bridge-backed globals (e.g. `process.versions`) are lazy - // getters that dispatch a host bridge call on first access. During - // snapshot creation the bridge fns are stubs, so an agent SDK that - // reads them at module-init would fail. Freeze them to static values - // first; per-session config is still injected post-restore. - run_snapshot_script(scope, SNAPSHOT_USERLAND_PREP, "userland prep", false)?; - run_snapshot_script(scope, userland_code, "userland code", true)?; - } - Ok(()) - })(); - - scope.set_default_context(context); - result - }; - let blob = isolate - .create_blob(v8::FunctionCodeHandling::Keep) - .ok_or_else(|| "V8 snapshot creation failed".to_string())?; - bridge_result?; - - // Reject oversized snapshots - if blob.len() > MAX_SNAPSHOT_BLOB_BYTES { - return Err(format!( - "snapshot blob too large: {} bytes (max {})", - blob.len(), - MAX_SNAPSHOT_BLOB_BYTES - )); - } - - Ok(blob.to_vec()) - }) -} - -fn create_snapshot_in_subprocess( - bridge_code: &str, - userland_code: Option<&str>, -) -> Result, String> { - let current_exe = - std::env::current_exe().map_err(|error| format!("snapshot helper path: {error}"))?; - let mut child = Command::new(current_exe) - .env(SNAPSHOT_HELPER_ENV, "1") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .map_err(|error| format!("spawn snapshot helper: {error}"))?; - - { - let mut stdin = child - .stdin - .take() - .ok_or_else(|| String::from("snapshot helper stdin unavailable"))?; - write_snapshot_helper_request(&mut stdin, bridge_code, userland_code)?; - } - - let output = child - .wait_with_output() - .map_err(|error| format!("wait for snapshot helper: {error}"))?; - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - return Err(format!( - "snapshot helper exited with status {}: {}", - output.status, stderr - )); - } - - parse_snapshot_helper_response(&output.stdout, &output.stderr) -} - -fn write_snapshot_helper_request( - writer: &mut impl Write, - bridge_code: &str, - userland_code: Option<&str>, -) -> Result<(), String> { - writer - .write_all(SNAPSHOT_HELPER_MAGIC) - .map_err(|error| format!("write snapshot helper magic: {error}"))?; - write_u64(writer, bridge_code.len() as u64)?; - write_u64( - writer, - userland_code - .map(|code| code.len() as u64) - .unwrap_or(SNAPSHOT_HELPER_NONE_LEN), - )?; - writer - .write_all(bridge_code.as_bytes()) - .map_err(|error| format!("write snapshot helper bridge code: {error}"))?; - if let Some(userland_code) = userland_code { - writer - .write_all(userland_code.as_bytes()) - .map_err(|error| format!("write snapshot helper userland code: {error}"))?; - } - Ok(()) -} - -fn parse_snapshot_helper_response(stdout: &[u8], stderr: &[u8]) -> Result, String> { - if stdout.starts_with(SNAPSHOT_HELPER_OK) { - let payload = &stdout[SNAPSHOT_HELPER_OK.len()..]; - let (len, rest) = read_u64_from_slice(payload)?; - let len = usize::try_from(len) - .map_err(|_| String::from("snapshot helper OK payload length overflows usize"))?; - if rest.len() != len { - return Err(format!( - "snapshot helper OK payload length mismatch: declared {}, got {}", - len, - rest.len() - )); - } - return Ok(rest.to_vec()); - } - - if stdout.starts_with(SNAPSHOT_HELPER_ERR) { - let payload = &stdout[SNAPSHOT_HELPER_ERR.len()..]; - let (len, rest) = read_u64_from_slice(payload)?; - let len = usize::try_from(len) - .map_err(|_| String::from("snapshot helper error length overflows usize"))?; - if rest.len() != len { - return Err(format!( - "snapshot helper error length mismatch: declared {}, got {}", - len, - rest.len() - )); - } - let message = String::from_utf8_lossy(rest); - return Err(message.into_owned()); - } - - Err(format!( - "snapshot helper returned invalid response (stdout {} bytes, stderr: {})", - stdout.len(), - String::from_utf8_lossy(stderr) - )) -} - -fn run_snapshot_helper_from_stdio() -> i32 { - let mut input = Vec::new(); - if let Err(error) = std::io::stdin().read_to_end(&mut input) { - let _ = write_snapshot_helper_error(format!("read snapshot helper request: {error}")); - return 2; - } - - let result = (|| -> Result, String> { - let (bridge_code, userland_code) = parse_snapshot_helper_request(&input)?; - create_snapshot_inner_in_process(&bridge_code, userland_code.as_deref()) - })(); - - match result { - Ok(blob) => match write_snapshot_helper_ok(&blob) { - Ok(()) => 0, - Err(error) => { - eprintln!("write snapshot helper response: {error}"); - 2 - } - }, - Err(error) => match write_snapshot_helper_error(error) { - Ok(()) => 0, - Err(error) => { - eprintln!("write snapshot helper error response: {error}"); - 2 - } - }, - } -} - -fn parse_snapshot_helper_request(input: &[u8]) -> Result<(String, Option), String> { - let Some(rest) = input.strip_prefix(SNAPSHOT_HELPER_MAGIC) else { - return Err(String::from("snapshot helper request missing magic")); - }; - let (bridge_len, rest) = read_u64_from_slice(rest)?; - let (userland_len, rest) = read_u64_from_slice(rest)?; - let bridge_len = usize::try_from(bridge_len) - .map_err(|_| String::from("snapshot helper bridge length overflows usize"))?; - if rest.len() < bridge_len { - return Err(format!( - "snapshot helper bridge length mismatch: declared {}, got {}", - bridge_len, - rest.len() - )); - } - let (bridge_bytes, rest) = rest.split_at(bridge_len); - let userland_code = if userland_len == SNAPSHOT_HELPER_NONE_LEN { - if !rest.is_empty() { - return Err(format!( - "snapshot helper request has {} trailing bytes after bridge-only payload", - rest.len() - )); - } - None - } else { - let userland_len = usize::try_from(userland_len) - .map_err(|_| String::from("snapshot helper userland length overflows usize"))?; - if rest.len() != userland_len { - return Err(format!( - "snapshot helper userland length mismatch: declared {}, got {}", - userland_len, - rest.len() - )); - } - Some( - String::from_utf8(rest.to_vec()) - .map_err(|error| format!("snapshot helper userland is not UTF-8: {error}"))?, - ) - }; - let bridge_code = String::from_utf8(bridge_bytes.to_vec()) - .map_err(|error| format!("snapshot helper bridge is not UTF-8: {error}"))?; - Ok((bridge_code, userland_code)) -} - -fn write_snapshot_helper_ok(blob: &[u8]) -> std::io::Result<()> { - let mut stdout = std::io::stdout().lock(); - stdout.write_all(SNAPSHOT_HELPER_OK)?; - write_u64_io(&mut stdout, blob.len() as u64)?; - stdout.write_all(blob)?; - stdout.flush() -} - -fn write_snapshot_helper_error(message: String) -> std::io::Result<()> { - let mut stdout = std::io::stdout().lock(); - stdout.write_all(SNAPSHOT_HELPER_ERR)?; - write_u64_io(&mut stdout, message.len() as u64)?; - stdout.write_all(message.as_bytes())?; - stdout.flush() -} - -fn write_u64(writer: &mut impl Write, value: u64) -> Result<(), String> { - write_u64_io(writer, value).map_err(|error| format!("write snapshot helper length: {error}")) -} - -fn write_u64_io(writer: &mut impl Write, value: u64) -> std::io::Result<()> { - writer.write_all(&value.to_le_bytes()) -} - -fn read_u64_from_slice(input: &[u8]) -> Result<(u64, &[u8]), String> { - let bytes = input - .get(..8) - .ok_or_else(|| String::from("snapshot helper payload ended before u64"))?; - let mut value = [0_u8; 8]; - value.copy_from_slice(bytes); - Ok((u64::from_le_bytes(value), &input[8..])) -} - -/// Inject default config globals needed by the bridge IIFE during snapshot creation. -/// -/// These are placeholder values so bridge code that reads _processConfig or -/// _osConfig at setup time doesn't fail. They're overwritten per-session -/// after snapshot restore via inject_globals_from_payload. -/// -/// Properties are set as READ_ONLY (not DONT_DELETE) so they remain -/// configurable — inject_globals_from_payload can redefine them with -/// READ_ONLY | DONT_DELETE after restore. -fn inject_snapshot_defaults(scope: &mut v8::HandleScope) { - let context = scope.get_current_context(); - let global = context.global(scope); - - // _processConfig: default placeholder (overwritten per-session) - let pc_code = r#"({ - cwd: "/", - env: {}, - timing_mitigation: "off", - frozen_time_ms: null, - high_resolution_time: false - })"#; - let pc_source = v8::String::new(scope, pc_code).unwrap(); - let pc_script = v8::Script::compile(scope, pc_source, None).unwrap(); - let pc_val = pc_script.run(scope).unwrap(); - if let Some(pc_obj) = pc_val.to_object(scope) { - pc_obj.set_integrity_level(scope, v8::IntegrityLevel::Frozen); - } - let pc_key = v8::String::new(scope, "_processConfig").unwrap(); - // READ_ONLY only — no DONT_DELETE so the property remains configurable - // for override after snapshot restore - let attr = v8::PropertyAttribute::READ_ONLY; - global.define_own_property(scope, pc_key.into(), pc_val, attr); - - // _osConfig: default placeholder (overwritten per-session) - let oc_code = r#"({ - homedir: "/root", - tmpdir: "/tmp", - platform: "linux", - arch: "x64" - })"#; - let oc_source = v8::String::new(scope, oc_code).unwrap(); - let oc_script = v8::Script::compile(scope, oc_source, None).unwrap(); - let oc_val = oc_script.run(scope).unwrap(); - if let Some(oc_obj) = oc_val.to_object(scope) { - oc_obj.set_integrity_level(scope, v8::IntegrityLevel::Frozen); - } - let oc_key = v8::String::new(scope, "_osConfig").unwrap(); - // READ_ONLY only — no DONT_DELETE so the property remains configurable - let attr2 = v8::PropertyAttribute::READ_ONLY; - global.define_own_property(scope, oc_key.into(), oc_val, attr2); -} - -/// Create a V8 isolate restored from a snapshot blob. -/// -/// The external references must match those used during snapshot creation -/// (provided by bridge::external_refs()). -/// -/// `blob` must be owned or 'static data — `Vec`, `Box<[u8]>`, or -/// `v8::StartupData` all work. The data is copied into the isolate during -/// creation; V8 does not retain a reference after `Isolate::new()` returns. -pub fn create_isolate_from_snapshot(blob: B, heap_limit_mb: Option) -> v8::OwnedIsolate -where - B: std::ops::Deref + std::borrow::Borrow<[u8]> + 'static, -{ - init_v8_platform(); - - // `None` applies the bounded-by-default cap (`DEFAULT_HEAP_LIMIT_MB`), same as - // the fresh-isolate path — a snapshot-restored isolate is never unbounded. - let limit = heap_limit_mb.unwrap_or(crate::isolate::DEFAULT_HEAP_LIMIT_MB); - let limit_bytes = (limit as usize) * 1024 * 1024; - let params = v8::CreateParams::default() - .snapshot_blob(blob) - .external_references(&**external_refs()) - .heap_limits(0, limit_bytes); - let mut isolate = crate::isolate::with_isolate_lifecycle_lock(|| v8::Isolate::new(params)); - crate::isolate::configure_isolate(&mut isolate); - // Same OOM guard as the fresh-isolate path: terminate this isolate on heap - // exhaustion instead of fatal-aborting the shared process (F-003). - crate::isolate::install_heap_limit_guard(&mut isolate); - isolate -} - -pub type SnapshotCacheKey = [u8; 32]; - -/// Thread-safe snapshot cache keyed by bridge code digest. -/// -/// Uses two-phase locking with per-key in-flight tracking so concurrent -/// callers requesting different bridge code variants are not blocked by -/// each other. Callers requesting the same variant wait on a condvar -/// instead of creating duplicate snapshots. -pub struct SnapshotCache { - inner: Mutex, - max_entries: usize, -} - -struct CacheInner { - entries: Vec, - /// Per-key in-flight tracking: callers for the same digest wait on the - /// condvar instead of creating duplicate snapshots. - in_flight: HashMap>, -} - -struct CacheEntry { - key: SnapshotCacheKey, - /// Snapshot blob bytes (copied from v8::StartupData). - /// Stored as Vec rather than StartupData because StartupData - /// contains raw pointers that are not Send/Sync. - blob: Arc>, -} - -/// Shared state for an in-flight snapshot creation. The creator thread -/// populates `result` and notifies all waiters via `done`. -struct InFlightEntry { - result: Mutex>, String>>>, - done: Condvar, -} - -impl SnapshotCache { - pub fn new(max_entries: usize) -> Self { - SnapshotCache { - inner: Mutex::new(CacheInner { - entries: Vec::new(), - in_flight: HashMap::new(), - }), - max_entries, - } - } - - /// Get or create a snapshot for the given bridge code. - /// - /// Two-phase locking: the cache mutex is held only for lookups and - /// inserts, never during snapshot creation. Per-key in-flight tracking - /// prevents duplicate snapshot creation for the same bridge code. - pub fn get_or_create(&self, bridge_code: &str) -> Result>, String> { - self.get_or_create_with_userland(bridge_code, None) - } - - /// Return a cached snapshot if present. This never creates a snapshot or - /// waits on in-flight creation. - pub fn try_get_with_userland( - &self, - bridge_code: &str, - userland_code: Option<&str>, - ) -> Option>> { - let key = snapshot_cache_key(bridge_code, userland_code); - let mut inner = self.inner.lock().unwrap(); - if let Some(pos) = inner.entries.iter().position(|e| e.key == key) { - let entry = inner.entries.remove(pos); - let blob = Arc::clone(&entry.blob); - inner.entries.push(entry); - Some(blob) - } else { - None - } - } - - /// Like [`get_or_create`], but the snapshot also captures an evaluated userland - /// (agent-SDK) graph. The cache key is the digest of BOTH `bridge_code` and - /// `userland_code`, so a change to either — i.e. any change in the bundled - /// dependency graph — invalidates the entry and triggers exactly one rebuild. - pub fn get_or_create_with_userland( - &self, - bridge_code: &str, - userland_code: Option<&str>, - ) -> Result>, String> { - let key = snapshot_cache_key(bridge_code, userland_code); - - // Phase 1: short lock — check cache, check in-flight, or claim creation - let in_flight = { - let mut inner = self.inner.lock().unwrap(); - - // Cache hit — move to end (most recently used) - if let Some(pos) = inner.entries.iter().position(|e| e.key == key) { - let entry = inner.entries.remove(pos); - let blob = Arc::clone(&entry.blob); - inner.entries.push(entry); - return Ok(blob); - } - - // Another thread is already creating this snapshot — wait on it - if let Some(entry) = inner.in_flight.get(&key) { - Some(Arc::clone(entry)) - } else { - // We're the creator — register in-flight and release the lock - let entry = Arc::new(InFlightEntry { - result: Mutex::new(None), - done: Condvar::new(), - }); - inner.in_flight.insert(key, Arc::clone(&entry)); - None - } - }; - - // Wait path: another thread is creating this snapshot - if let Some(entry) = in_flight { - let mut result = entry.result.lock().unwrap(); - while result.is_none() { - result = entry.done.wait(result).unwrap(); - } - return result.as_ref().unwrap().clone(); - } - - // Phase 2: create snapshot without holding the cache lock - let creation_result = create_snapshot_inner(bridge_code, userland_code).map(Arc::new); - - // Phase 3: short lock — insert result, notify waiters, clean up - { - let mut inner = self.inner.lock().unwrap(); - - if let Ok(ref arc) = creation_result { - // LRU eviction: remove oldest (front) entry when at capacity - if inner.entries.len() >= self.max_entries { - inner.entries.remove(0); - } - inner.entries.push(CacheEntry { - key, - blob: Arc::clone(arc), - }); - } - - // Publish result to waiters and remove in-flight entry - if let Some(entry) = inner.in_flight.remove(&key) { - let mut result = entry.result.lock().unwrap(); - *result = Some(creation_result.clone()); - entry.done.notify_all(); - } - } - - creation_result - } -} - -/// Cache key over bridge + optional userland code. With no userland this is just -/// the sha256 of the bridge code (a NUL separator is only added when userland is -/// present), so existing bridge-only entries keep their historical keys. -pub fn snapshot_cache_key(bridge_code: &str, userland_code: Option<&str>) -> SnapshotCacheKey { - match userland_code { - None => { - let mut hasher = Sha256::new(); - hasher.update(bridge_code.as_bytes()); - hasher.finalize().into() - } - Some(userland_code) => { - let mut buf = Vec::with_capacity(bridge_code.len() + 1 + userland_code.len()); - buf.extend_from_slice(bridge_code.as_bytes()); - buf.push(0); - buf.extend_from_slice(userland_code.as_bytes()); - let mut hasher = Sha256::new(); - hasher.update(&buf); - hasher.finalize().into() - } - } -} - -#[doc(hidden)] -pub fn run_snapshot_consolidated_checks() { - fn eval(isolate: &mut v8::OwnedIsolate, code: &str) -> String { - let scope = &mut v8::HandleScope::new(isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - let source = v8::String::new(scope, code).unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - result.to_rust_string_lossy(scope) - } - - // Keep snapshot coverage in a dedicated integration-test process. - // Running it in the shared unit-test binary still triggers a V8 teardown - // SIGSEGV after the test completes. - init_v8_platform(); - let _ = external_refs(); - - // --- Part 1: Snapshot creation returns non-empty blob --- - { - let bridge_code = "(function() { globalThis.__bridge_init = true; })();"; - let blob = create_snapshot(bridge_code).expect("snapshot creation should succeed"); - assert!(!blob.is_empty(), "snapshot blob should be non-empty"); - } - - // --- Part 2: Restored isolate executes JS correctly --- - { - let bridge_code = "(function() { globalThis.__testValue = 42; })();"; - let blob = create_snapshot(bridge_code).expect("snapshot creation should succeed"); - let mut isolate = create_isolate_from_snapshot(blob, None); - // Fresh context on restored isolate — bridge globals are in snapshot's - // default context, not in a new context. Verify isolate is functional. - assert_eq!(eval(&mut isolate, "1 + 1"), "2"); - } - - // --- Part 3: Restored isolate respects heap_limit_mb --- - { - let bridge_code = "/* empty bridge */"; - let blob = create_snapshot(bridge_code).expect("snapshot creation should succeed"); - let mut isolate = create_isolate_from_snapshot(blob, Some(8)); - assert_eq!(eval(&mut isolate, "'heap ok'"), "heap ok"); - } - - // --- Part 4: Normal blob is under 50MB limit --- - { - let bridge_code = "(function() { globalThis.x = 1; })();"; - let blob = create_snapshot(bridge_code).expect("snapshot creation should succeed"); - assert!( - blob.len() < MAX_SNAPSHOT_BLOB_BYTES, - "normal bridge code should produce blob under 50MB limit" - ); - } - - // --- Part 5: Three sequential restores from same snapshot data --- - { - let bridge_code = "(function() { globalThis.__counter = 0; })();"; - let blob = create_snapshot(bridge_code).expect("snapshot creation should succeed"); - let blob_bytes: Vec = blob.to_vec(); - - for i in 0..3 { - let mut isolate = create_isolate_from_snapshot(blob_bytes.clone(), None); - let result = eval(&mut isolate, &format!("{} + 1", i)); - assert_eq!(result, format!("{}", i + 1)); - } - } - - // --- Part 6: Cache hit returns same Arc --- - { - let cache = SnapshotCache::new(4); - let bridge_code = "(function() { globalThis.__cached = 1; })();"; - - let arc1 = cache - .get_or_create(bridge_code) - .expect("first get_or_create"); - let arc2 = cache - .get_or_create(bridge_code) - .expect("second get_or_create"); - - // Same Arc (same pointer) — cache hit, not a new snapshot - assert!( - Arc::ptr_eq(&arc1, &arc2), - "cache hit should return same Arc" - ); - } - - // --- Part 7: Cache miss creates new snapshot --- - { - let cache = SnapshotCache::new(4); - let code_a = "(function() { globalThis.__a = 1; })();"; - let code_b = "(function() { globalThis.__b = 2; })();"; - - let arc_a = cache.get_or_create(code_a).expect("create A"); - let arc_b = cache.get_or_create(code_b).expect("create B"); - - // Different bridge code → different Arc - assert!( - !Arc::ptr_eq(&arc_a, &arc_b), - "different code should produce different Arc" - ); - - // Verify both are usable - let mut iso_a = create_isolate_from_snapshot((*arc_a).clone(), None); - assert_eq!(eval(&mut iso_a, "1 + 1"), "2"); - - let mut iso_b = create_isolate_from_snapshot((*arc_b).clone(), None); - assert_eq!(eval(&mut iso_b, "2 + 2"), "4"); - } - - // --- Part 8: LRU eviction removes oldest entry --- - { - let cache = SnapshotCache::new(2); - let code_1 = "(function() { globalThis.__v1 = 1; })();"; - let code_2 = "(function() { globalThis.__v2 = 2; })();"; - let code_3 = "(function() { globalThis.__v3 = 3; })();"; - - let arc_1 = cache.get_or_create(code_1).expect("create 1"); - let _arc_2 = cache.get_or_create(code_2).expect("create 2"); - - // Cache is full (2 entries). Adding a third should evict code_1. - let _arc_3 = cache.get_or_create(code_3).expect("create 3"); - - // code_1 should be evicted — re-requesting it should return a new Arc - let arc_1_new = cache.get_or_create(code_1).expect("re-create 1"); - assert!( - !Arc::ptr_eq(&arc_1, &arc_1_new), - "evicted entry should produce a new Arc on re-creation" - ); - - // code_2 should still be cached (it was accessed before code_3 but not evicted) - // After eviction of code_1, cache had [code_2, code_3], then adding code_1 evicts code_2 - // Actually: after inserting code_3, cache was [code_2, code_3] (code_1 evicted). - // Then inserting code_1 again: cache is full (2), evicts code_2 → cache is [code_3, code_1]. - } - - // --- Part 9: Concurrent get_or_create creates only one snapshot --- - { - use std::sync::atomic::{AtomicUsize, Ordering}; - - let cache = Arc::new(SnapshotCache::new(4)); - let bridge_code = "(function() { globalThis.__concurrent = 1; })();"; - - // Pre-warm — to avoid measuring snapshot creation races, verify - // that after one creation, N threads all get the same Arc - let first = cache.get_or_create(bridge_code).expect("pre-warm"); - - let num_threads = 4; - let barrier = Arc::new(std::sync::Barrier::new(num_threads)); - let same_count = Arc::new(AtomicUsize::new(0)); - - let mut handles = vec![]; - for _ in 0..num_threads { - let cache = Arc::clone(&cache); - let barrier = Arc::clone(&barrier); - let first = Arc::clone(&first); - let same_count = Arc::clone(&same_count); - let code = bridge_code.to_string(); - - handles.push(std::thread::spawn(move || { - barrier.wait(); - let arc = cache.get_or_create(&code).expect("concurrent get"); - if Arc::ptr_eq(&arc, &first) { - same_count.fetch_add(1, Ordering::Relaxed); - } - })); - } - - for h in handles { - h.join().expect("thread join"); - } - - assert_eq!( - same_count.load(Ordering::Relaxed), - num_threads, - "all concurrent callers should get the same cached Arc" - ); - } - - // --- Part 10: Guest WebAssembly remains available after snapshot restore --- - { - let bridge_code = "(function() { globalThis.__wasm_test = true; })();"; - let blob = create_snapshot(bridge_code).expect("snapshot creation"); - let mut isolate = create_isolate_from_snapshot(blob, None); - - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - let wasm_test_code = r#" - (function() { - var bytes = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, - 0x03, 0x02, 0x01, 0x00, - 0x07, 0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, - 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b, - ]); - var module = new WebAssembly.Module(bytes); - var instance = new WebAssembly.Instance(module, {}); - return String(instance.exports.add(2, 3)); - })() - "#; - let source = v8::String::new(scope, wasm_test_code).unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - let result_str = result.to_rust_string_lossy(scope); - - assert_eq!( - result_str, "5", - "WASM should remain enabled after snapshot restore" - ); - } - - // --- Part 11: Session isolation — fresh contexts from same snapshot --- - // Verifies that state set in one session's context does not leak - // to another session's context (fresh context per session). - { - let bridge_code = "(function() { globalThis.__shared_bridge = 'ok'; })();"; - let blob = create_snapshot(bridge_code).expect("snapshot creation"); - let blob_bytes: Vec = blob.to_vec(); - - // "Session A": set a global variable - { - let mut isolate = create_isolate_from_snapshot(blob_bytes.clone(), None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - let source = - v8::String::new(scope, "globalThis.__session_secret = 'session-a-data';").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - script.run(scope); - - // Verify session A can see its own data - let check = v8::String::new(scope, "globalThis.__session_secret").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!(result.to_rust_string_lossy(scope), "session-a-data"); - } - - // "Session B": fresh context from same snapshot should NOT see session A's data - { - let mut isolate = create_isolate_from_snapshot(blob_bytes.clone(), None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - let source = v8::String::new(scope, "typeof globalThis.__session_secret").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "undefined", - "session B should not see session A's global state" - ); - } - } - - // --- Part 12: External references survive snapshot restore --- - // Verifies that FunctionTemplates registered on a restored isolate - // correctly dispatch to Rust bridge callbacks via external_refs(). - { - use crate::bridge::{register_async_bridge_fns, register_sync_bridge_fns, PendingPromises}; - use crate::host_call::BridgeCallContext; - - let bridge_code = "(function() { globalThis.__ext_ref_test = true; })();"; - let blob = create_snapshot(bridge_code).expect("snapshot creation"); - let mut isolate = create_isolate_from_snapshot(blob, None); - - // Create minimal BridgeCallContext (sync call will fail but we - // test that the FunctionTemplate dispatches without crash) - let (event_tx, _event_rx) = - crossbeam_channel::unbounded::(); - let (_cmd_tx, _cmd_rx) = crossbeam_channel::unbounded::(); - let call_id_router: crate::host_call::CallIdRouter = - Arc::new(Mutex::new(std::collections::HashMap::new())); - - let receiver = crate::host_call::ReaderBridgeResponseReceiver::new(Box::new( - std::io::Cursor::new(Vec::::new()), - )); - let sender = crate::host_call::ChannelRuntimeEventSender::new(event_tx, None); - let bridge_ctx = BridgeCallContext::with_receiver( - Box::new(sender), - Box::new(receiver), - "test-session".to_string(), - call_id_router, - Arc::new(std::sync::atomic::AtomicU64::new(1)), - ); - let pending = PendingPromises::new(); - - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - // Register bridge functions on the restored isolate - let _sync_store = register_sync_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &["_testSync"], - ); - let _async_store = register_async_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const PendingPromises, - &["_testAsync"], - ); - - // Verify the functions exist as globals - let check = v8::String::new(scope, "typeof _testSync").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "function", - "_testSync should be a function on restored isolate" - ); - - let check = v8::String::new(scope, "typeof _testAsync").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "function", - "_testAsync should be a function on restored isolate" - ); - } - - // --- Part 13: Register stub bridge functions on V8 global --- - // Verifies that register_stub_bridge_fns places functions on the global - // and that they have the correct typeof without calling them. - { - use crate::bridge::register_stub_bridge_fns; - - // Use a snapshot-based isolate (consistent with other parts) - let bridge_code = "/* stub test */"; - let blob = create_snapshot(bridge_code).expect("snapshot creation"); - let mut isolate = create_isolate_from_snapshot(blob, None); - - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - register_stub_bridge_fns( - scope, - &["_log", "_error", "_fsReadFile", "_loadPolyfill"], - &["_scheduleTimer", "_dynamicImport"], - ); - - let check = v8::String::new( - scope, - r#" - (function() { - var names = ['_log', '_error', '_fsReadFile', '_loadPolyfill', - '_scheduleTimer', '_dynamicImport']; - for (var i = 0; i < names.length; i++) { - if (typeof globalThis[names[i]] !== 'function') { - return 'FAIL: ' + names[i] + ' is ' + typeof globalThis[names[i]]; - } - } - return 'OK'; - })() - "#, - ) - .unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "OK", - "all stub bridge functions should be registered as functions" - ); - } - - // --- Part 14: Bridge IIFE executes against stubs + snapshot creation --- - // Verifies that setup-time code can reference stub functions (typeof, - // closure wrapping, getter facade) without calling them, and that the - // resulting context can be snapshotted. - { - use crate::bridge::register_stub_bridge_fns; - - let mut snapshot_isolate = v8::Isolate::snapshot_creator(Some(external_refs()), None); - { - let scope = &mut v8::HandleScope::new(&mut snapshot_isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - // Register bridge functions as stubs (no External data). - let sync_bridge_fns = sync_bridge_fns(); - let async_bridge_fns = async_bridge_fns(); - register_stub_bridge_fns(scope, sync_bridge_fns, async_bridge_fns); - - // Simulate bridge IIFE: reference all bridge functions, set up - // closures and getter facade, but never call any bridge function - let iife_code = r#" - (function() { - // Verify bridge functions exist (like ivm-compat shim) - var syncKeys = ['_log', '_error', '_resolveModule', '_loadFile', '_moduleFormat', - '_cryptoRandomFill', '_fsReadFile', '_fsWriteFile', - '_childProcessSpawnStart', '_childProcessPoll', '_childProcessSpawnSync']; - var asyncKeys = ['_dynamicImport', '_scheduleTimer', - '_networkHttpServerListenRaw']; - - for (var i = 0; i < syncKeys.length; i++) { - if (typeof globalThis[syncKeys[i]] !== 'function') { - throw new Error('Missing sync: ' + syncKeys[i]); - } - } - for (var i = 0; i < asyncKeys.length; i++) { - if (typeof globalThis[asyncKeys[i]] !== 'function') { - throw new Error('Missing async: ' + asyncKeys[i]); - } - } - - // Simulate getter-based fs facade (setup only, no calls) - var _fs = {}; - Object.defineProperties(_fs, { - readFile: { get: function() { return globalThis._fsReadFile; }, enumerable: true }, - writeFile: { get: function() { return globalThis._fsWriteFile; }, enumerable: true }, - }); - globalThis._fs = _fs; - - // Verify getter returns function reference without calling it - if (typeof _fs.readFile !== 'function') { - throw new Error('Getter should return function, got ' + typeof _fs.readFile); - } - - // Simulate closure wrapping (setup only, no calls) - globalThis.__wrappedLog = function() { - return globalThis._log.apply(null, arguments); - }; - - globalThis.__bridge_setup_complete = true; - })(); - "#; - let source = v8::String::new(scope, iife_code).unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope); - assert!( - result.is_some(), - "bridge IIFE should execute without error against stub functions" - ); - - // Verify setup completed - let check = - v8::String::new(scope, "String(globalThis.__bridge_setup_complete)").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let val = script.run(scope).unwrap(); - assert_eq!( - val.to_rust_string_lossy(scope), - "true", - "bridge setup should complete with stub functions" - ); - - scope.set_default_context(context); - } - - let blob = snapshot_isolate.create_blob(v8::FunctionCodeHandling::Keep); - assert!( - blob.is_some(), - "snapshot creation should succeed with stub bridge functions" - ); - assert!( - !blob.unwrap().is_empty(), - "snapshot blob should be non-empty" - ); - } - - // --- Part 15: create_snapshot() auto-registers stubs and injects defaults --- - // Verifies that create_snapshot() registers all bridge function stubs - // and injects _processConfig/_osConfig defaults before running bridge code. - { - // Bridge IIFE that verifies stubs and config globals exist - let iife_code = r#" - (function() { - // Verify all sync bridge functions are registered as stubs - var syncFns = ['_log', '_error', '_resolveModule', '_loadFile', - '_moduleFormat', '_loadPolyfill', '_cryptoRandomFill', '_cryptoRandomUUID', - '_fsReadFile', '_fsWriteFile', '_fsReadFileBinary', - '_fsWriteFileBinary', '_fsReadDir', '_fsMkdir', '_fsRmdir', - '_fsExists', '_fsStat', '_fsUnlink', '_fsRename', '_fsChmod', - '_fsChown', '_fsLink', '_fsSymlink', '_fsReadlink', '_fsLstat', - '_fsTruncate', '_fsUtimes', '_childProcessSpawnStart', - '_childProcessPoll', '_childProcessStdinWrite', '_childProcessStdinClose', - '_childProcessKill', '_childProcessSpawnSync']; - for (var i = 0; i < syncFns.length; i++) { - if (typeof globalThis[syncFns[i]] !== 'function') { - throw new Error('Missing sync stub: ' + syncFns[i] + - ' (typeof=' + typeof globalThis[syncFns[i]] + ')'); - } - } - - // Verify all async bridge functions are registered as stubs - var asyncFns = ['_dynamicImport', '_scheduleTimer', - '_networkDnsLookupRaw', - '_networkDnsResolveRaw', - '_networkHttpServerListenRaw', - '_networkHttpServerCloseRaw', '_networkHttpServerWaitRaw', - '_networkHttp2ServerWaitRaw', '_networkHttp2SessionWaitRaw']; - for (var i = 0; i < asyncFns.length; i++) { - if (typeof globalThis[asyncFns[i]] !== 'function') { - throw new Error('Missing async stub: ' + asyncFns[i] + - ' (typeof=' + typeof globalThis[asyncFns[i]] + ')'); - } - } - - // Verify _processConfig default was injected - if (typeof _processConfig !== 'object' || _processConfig === null) { - throw new Error('_processConfig not injected: ' + typeof _processConfig); - } - if (_processConfig.cwd !== '/') { - throw new Error('_processConfig.cwd should be "/", got: ' + _processConfig.cwd); - } - - // Verify _osConfig default was injected - if (typeof _osConfig !== 'object' || _osConfig === null) { - throw new Error('_osConfig not injected: ' + typeof _osConfig); - } - if (_osConfig.platform !== 'linux') { - throw new Error('_osConfig.platform should be "linux", got: ' + _osConfig.platform); - } - - globalThis.__part15_ok = true; - })(); - "#; - let blob = create_snapshot(iife_code).expect( - "create_snapshot should succeed with bridge code that checks stubs and defaults", - ); - assert!(!blob.is_empty(), "snapshot blob should be non-empty"); - - // Verify the snapshot can be restored - let mut isolate = create_isolate_from_snapshot(blob, None); - assert_eq!(eval(&mut isolate, "1 + 1"), "2"); - } - - // --- Part 16: create_snapshot() with getter facade and closures --- - // Verifies that the full bridge pattern (stubs, closures, getter facade, - // config globals) works through create_snapshot() and the context is - // correctly snapshotted via set_default_context. - { - let iife_code = r#" - (function() { - // Set up getter-based fs facade referencing bridge stubs - var _fs = {}; - Object.defineProperties(_fs, { - readFile: { get: function() { return globalThis._fsReadFile; }, enumerable: true }, - writeFile: { get: function() { return globalThis._fsWriteFile; }, enumerable: true }, - }); - globalThis._fs = _fs; - - // Set up closure wrapping a bridge stub - globalThis.myLog = function() { - return globalThis._log.apply(null, arguments); - }; - - // Set up a require-like function (doesn't call _loadPolyfill at setup) - globalThis.require = function(name) { - return globalThis._loadPolyfill(name); - }; - - // Set up a console-like object - globalThis.console = { - log: function() { globalThis._log.apply(null, arguments); }, - error: function() { globalThis._error.apply(null, arguments); }, - }; - - // Read _processConfig at setup time (like process.cwd initialization) - globalThis.__initialCwd = _processConfig.cwd; - - globalThis.__part16_setup = true; - })(); - "#; - let blob = create_snapshot(iife_code) - .expect("create_snapshot should succeed with full bridge IIFE pattern"); - assert!(!blob.is_empty()); - - // Restore and verify default context has the bridge infrastructure - let blob_bytes: Vec = blob.to_vec(); - let mut isolate = create_isolate_from_snapshot(blob_bytes, None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - // Check that bridge infrastructure from the IIFE is in the default context - let check_code = r#" - (function() { - var results = []; - results.push('_fs=' + (typeof _fs === 'object')); - results.push('_fs.readFile=' + (typeof _fs.readFile === 'function')); - results.push('myLog=' + (typeof myLog === 'function')); - results.push('require=' + (typeof require === 'function')); - results.push('console.log=' + (typeof console.log === 'function')); - results.push('console.error=' + (typeof console.error === 'function')); - results.push('__initialCwd=' + __initialCwd); - results.push('__part16_setup=' + __part16_setup); - return results.join(';'); - })() - "#; - let source = v8::String::new(scope, check_code).unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - let result_str = result.to_rust_string_lossy(scope); - - assert_eq!( - result_str, - "_fs=true;_fs.readFile=true;myLog=true;require=true;console.log=true;console.error=true;__initialCwd=/;__part16_setup=true", - "restored context should have all bridge infrastructure from the IIFE" - ); - } - - // --- Part 17: SnapshotCache works with context-snapshot create_snapshot --- - // Verifies cache hit/miss still works now that create_snapshot registers stubs. - { - let cache = SnapshotCache::new(4); - let code = r#" - (function() { - // Verify stubs are present (create_snapshot registers them) - if (typeof _log !== 'function') throw new Error('no _log stub'); - if (typeof _processConfig !== 'object') throw new Error('no _processConfig'); - globalThis.__cached_context = true; - })(); - "#; - - let arc1 = cache.get_or_create(code).expect("first get_or_create"); - let arc2 = cache.get_or_create(code).expect("second get_or_create"); - assert!( - Arc::ptr_eq(&arc1, &arc2), - "cache hit should return same Arc" - ); - - // Verify blob is usable - let mut isolate = create_isolate_from_snapshot((*arc1).clone(), None); - assert_eq!(eval(&mut isolate, "1 + 1"), "2"); - } - - // --- Part 18: Context restore + replace_bridge_fns dispatches correctly --- - // Verifies the full context snapshot restore flow: create snapshot with - // stubs, restore, replace stubs with real bridge functions, verify the - // replaced functions dispatch to the real Rust callbacks. - { - use crate::bridge::{replace_bridge_fns, PendingPromises}; - use crate::host_call::BridgeCallContext; - - // Create snapshot with stubs + simple bridge IIFE - let bridge_code = r#" - (function() { - // Getter-based facade referencing globalThis._fsReadFile - var _fs = {}; - Object.defineProperties(_fs, { - readFile: { get: function() { return globalThis._fsReadFile; }, enumerable: true }, - }); - globalThis._fs = _fs; - globalThis.__bridge_ready = true; - })(); - "#; - let blob = create_snapshot(bridge_code).expect("snapshot creation"); - let mut isolate = create_isolate_from_snapshot(blob, None); - - // Create BridgeCallContext (sync calls will fail but we verify dispatch) - let (event_tx, _event_rx) = - crossbeam_channel::unbounded::(); - let call_id_router: crate::host_call::CallIdRouter = - Arc::new(Mutex::new(std::collections::HashMap::new())); - let receiver = crate::host_call::ReaderBridgeResponseReceiver::new(Box::new( - std::io::Cursor::new(Vec::::new()), - )); - let sender = crate::host_call::ChannelRuntimeEventSender::new(event_tx, None); - let bridge_ctx = BridgeCallContext::with_receiver( - Box::new(sender), - Box::new(receiver), - "test-session".to_string(), - call_id_router, - Arc::new(std::sync::atomic::AtomicU64::new(1)), - ); - let pending = PendingPromises::new(); - - // Restore context and replace bridge functions - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - let (_sync_store, _async_store) = replace_bridge_fns( - scope, - &bridge_ctx as *const BridgeCallContext, - &pending as *const PendingPromises, - &["_log", "_fsReadFile"], - &["_scheduleTimer"], - ); - - // Verify bridge infrastructure from IIFE survives restore - let check = v8::String::new( - scope, - r#" - (function() { - var results = []; - results.push('__bridge_ready=' + globalThis.__bridge_ready); - results.push('_fs_exists=' + (typeof _fs === 'object')); - // Getter should resolve to the REPLACED function (not stub) - results.push('_fs.readFile_type=' + typeof _fs.readFile); - // Direct global should also be the replaced function - results.push('_log_type=' + typeof _log); - results.push('_scheduleTimer_type=' + typeof _scheduleTimer); - return results.join(';'); - })() - "#, - ) - .unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "__bridge_ready=true;_fs_exists=true;_fs.readFile_type=function;_log_type=function;_scheduleTimer_type=function", - "restored context should have bridge IIFE state + replaced functions" - ); - } - - // --- Part 19: _processConfig is overridable after restore --- - // Verifies that inject_snapshot_defaults uses configurable properties - // so inject_globals_from_payload can override them per session. - { - use crate::bridge::serialize_v8_value; - - let bridge_code = r#" - (function() { - // Verify default _processConfig from snapshot - globalThis.__snapshotCwd = _processConfig.cwd; - })(); - "#; - let blob = create_snapshot(bridge_code).expect("snapshot creation"); - let mut isolate = create_isolate_from_snapshot(blob, None); - - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - // Verify snapshot defaults are present - let check = v8::String::new(scope, "__snapshotCwd").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!(result.to_rust_string_lossy(scope), "/"); - - // Create a V8 payload to override _processConfig - let payload_code = r#"({ - processConfig: { cwd: "/app", env: { FOO: "bar" }, timing_mitigation: "off", frozen_time_ms: null }, - osConfig: { homedir: "/home/agentos", tmpdir: "/tmp", platform: "linux", arch: "arm64" } - })"#; - let payload_source = v8::String::new(scope, payload_code).unwrap(); - let payload_script = v8::Script::compile(scope, payload_source, None).unwrap(); - let payload_val = payload_script.run(scope).unwrap(); - let payload_bytes = serialize_v8_value(scope, payload_val).expect("serialize payload"); - - // Inject per-session globals (overrides snapshot defaults) - crate::execution::inject_globals_from_payload(scope, &payload_bytes) - .expect("inject globals payload"); - - // Verify _processConfig was overridden - let check = v8::String::new(scope, "_processConfig.cwd").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "/app", - "_processConfig.cwd should be overridden from '/' to '/app'" - ); - - // Verify _osConfig was overridden - let check = v8::String::new(scope, "_osConfig.arch").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "arm64", - "_osConfig.arch should be overridden to 'arm64'" - ); - } - - // --- Part 19a: function globals survive snapshot restore --- - { - let bridge_code = r#" - (function() { - globalThis.__snapshotFn = async function () { return "ok"; }; - })(); - "#; - let blob = create_snapshot(bridge_code).expect("snapshot creation"); - let mut isolate = create_isolate_from_snapshot(blob, None); - - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - let check = v8::String::new( - scope, - r#"(function() { - return JSON.stringify({ - fnType: typeof globalThis.__snapshotFn, - promiseType: typeof globalThis.__snapshotFn?.(), - }); - })()"#, - ) - .unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - r#"{"fnType":"function","promiseType":"object"}"#, - "function-valued globals should survive snapshot restore" - ); - } - - // --- Part 19b: bundled bridge installs fetch globals before snapshot restore --- - { - let bridge_code = concat!( - include_str!(concat!(env!("OUT_DIR"), "/v8-bridge.js")), - "\n", - include_str!(concat!(env!("OUT_DIR"), "/v8-bridge-zlib.js")) - ); - let blob = create_snapshot(bridge_code).expect("snapshot creation"); - let mut isolate = create_isolate_from_snapshot(blob, None); - - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - let check = v8::String::new( - scope, - r#"(function() { - return JSON.stringify({ - fetchType: typeof globalThis.fetch, - headersType: typeof globalThis.Headers, - requestType: typeof globalThis.Request, - responseType: typeof globalThis.Response, - }); - })()"#, - ) - .unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - r#"{"fetchType":"function","headersType":"function","requestType":"function","responseType":"function"}"#, - "bundled bridge should expose fetch globals in restored contexts" - ); - } - - // --- Part 20a: Concurrent get_or_create with different bridge codes --- - // Verifies that concurrent callers requesting different bridge code - // variants are not blocked by each other (two-phase locking). - { - use std::sync::atomic::{AtomicBool, Ordering}; - use std::time::Instant; - - let cache = Arc::new(SnapshotCache::new(4)); - let codes: Vec = (0..3) - .map(|i| { - format!( - "(function() {{ globalThis.__concurrent_{} = {}; }})();", - i, i - ) - }) - .collect(); - - let barrier = Arc::new(std::sync::Barrier::new(codes.len())); - let all_ok = Arc::new(AtomicBool::new(true)); - - let mut handles = vec![]; - for code in &codes { - let cache = Arc::clone(&cache); - let barrier = Arc::clone(&barrier); - let all_ok = Arc::clone(&all_ok); - let code = code.clone(); - - handles.push(std::thread::spawn(move || { - barrier.wait(); - let start = Instant::now(); - match cache.get_or_create(&code) { - Ok(arc) => { - assert!(!arc.is_empty()); - } - Err(e) => { - eprintln!("get_or_create failed: {}", e); - all_ok.store(false, Ordering::Relaxed); - } - } - start.elapsed() - })); - } - - let mut durations = vec![]; - for h in handles { - durations.push(h.join().expect("thread join")); - } - - assert!( - all_ok.load(Ordering::Relaxed), - "all concurrent get_or_create calls should succeed" - ); - - // Verify all entries are cached (cache hits on second request) - for code in &codes { - let arc1 = cache.get_or_create(code).unwrap(); - let arc2 = cache.get_or_create(code).unwrap(); - assert!( - Arc::ptr_eq(&arc1, &arc2), - "should be cache hit after creation" - ); - } - } - - // --- Part 20: Multiple restores from same snapshot are independent --- - // Verifies that user code in one restored context does not leak to another. - { - let bridge_code = r#" - (function() { - globalThis.__bridge_ok = true; - })(); - "#; - let blob = create_snapshot(bridge_code).expect("snapshot creation"); - let blob_bytes: Vec = blob.to_vec(); - - // Restore A: set a session-specific global - { - let mut isolate = create_isolate_from_snapshot(blob_bytes.clone(), None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - // Bridge state from snapshot should be present - let check = v8::String::new(scope, "String(__bridge_ok)").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!(result.to_rust_string_lossy(scope), "true"); - - // Set session-specific state - let code = v8::String::new(scope, "globalThis.__user_data = 'session-a';").unwrap(); - let script = v8::Script::compile(scope, code, None).unwrap(); - script.run(scope); - } - - // Restore B: session A's state should not be visible - { - let mut isolate = create_isolate_from_snapshot(blob_bytes.clone(), None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - // Bridge state should still be present - let check = v8::String::new(scope, "String(__bridge_ok)").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!(result.to_rust_string_lossy(scope), "true"); - - // Session A's data should NOT be visible - let check = v8::String::new(scope, "typeof __user_data").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "undefined", - "session B should not see session A's user data" - ); - } - } - - // --- Part 21: Userland snapshot — evaluated graph captured, ZERO re-eval on - // restore, isolation preserved (2b acceptance). --- - { - // Evaluate a string in a fresh context on a restored isolate. Unlike the - // function-level `eval`, this takes an existing ContextScope so successive - // checks observe globals set by earlier scripts in the SAME context. - fn run_in(scope: &mut v8::ContextScope, code: &str) -> String { - let source = v8::String::new(scope, code).unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - result.to_rust_string_lossy(scope) - } - - // `userland` stands in for an esbuild IIFE bundle: it evaluates a small - // module graph, references a bridge-provided global (proving the bridge is - // available when userland runs), publishes exports on globalThis, and bumps - // a side-effect counter so we can prove the top-level runs exactly once. - let bridge_code = "(function(){ globalThis.__bridge_ok = true; })();"; - let userland = r#" - (function () { - if (typeof globalThis._fsReadFile !== "function") { - throw new Error("bridge fns missing during userland eval"); - } - globalThis.__sideEffectCount = (globalThis.__sideEffectCount || 0) + 1; - var secret = 42; - globalThis.__x = { f: function () { return secret; } }; - })(); - "#; - - let blob = create_snapshot_with_userland(bridge_code, userland) - .expect("userland snapshot creation should succeed"); - let blob_bytes: Vec = blob.to_vec(); - - // Restore A: fresh isolate + fresh context cloned from the snapshot default - // context. The userland top-level must NOT run again here. - { - let mut isolate = create_isolate_from_snapshot(blob_bytes.clone(), None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - assert_eq!( - run_in(scope, "String(globalThis.__x.f())"), - "42", - "userland export __x.f() should return 42 from the snapshot" - ); - assert_eq!( - run_in(scope, "String(globalThis.__sideEffectCount)"), - "1", - "userland top-level must run exactly once (zero re-eval on restore)" - ); - assert_eq!( - run_in(scope, "String(globalThis.__bridge_ok)"), - "true", - "bridge state should coexist with userland state in the snapshot" - ); - - // Mutate a global in session A. - run_in(scope, "globalThis.__leak = 'session-a'; ''"); - } - - // Restore B: a separate fresh isolate from the SAME blob must see the - // captured userland state but NOT session A's mutation (isolation). - { - let mut isolate = create_isolate_from_snapshot(blob_bytes.clone(), None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - assert_eq!( - run_in(scope, "String(globalThis.__x.f())"), - "42", - "session B should see the captured userland export" - ); - assert_eq!( - run_in(scope, "String(globalThis.__sideEffectCount)"), - "1", - "session B counter must still be 1 (no re-eval, no cross-session bump)" - ); - assert_eq!( - run_in(scope, "typeof globalThis.__leak"), - "undefined", - "session B must NOT observe session A's mutation" - ); - } - - // Cache: identical (bridge, userland) → same Arc; changed userland → new Arc. - { - let cache = SnapshotCache::new(4); - let a = cache - .get_or_create_with_userland(bridge_code, Some(userland)) - .expect("userland cache create"); - let b = cache - .get_or_create_with_userland(bridge_code, Some(userland)) - .expect("userland cache hit"); - assert!( - Arc::ptr_eq(&a, &b), - "identical userland should hit the cache" - ); - - let userland2 = "(function(){ globalThis.__x = { f: function(){ return 7; } }; })();"; - let c = cache - .get_or_create_with_userland(bridge_code, Some(userland2)) - .expect("changed userland create"); - assert!( - !Arc::ptr_eq(&a, &c), - "changed userland (dep-graph change) should rebuild" - ); - } - } - - // --- Part 22: REAL agent-SDK bundle snapshots + restores (env-gated). --- - // End-to-end primitive validation against the actual pi SDK snapshot bundle: - // the real bridge bundle + the real esbuild IIFE evaluate together into the - // snapshot, and a fresh restored isolate exposes the SDK runtime global with a - // working createAgentSession. Gated on PI_SNAPSHOT_BUNDLE_PATH so CI without the - // bundle skips it; run with that env var pointing at dist/pi-sdk-snapshot.js. - if let Ok(bundle_path) = std::env::var("PI_SNAPSHOT_BUNDLE_PATH") { - let userland = std::fs::read_to_string(&bundle_path) - .unwrap_or_else(|e| panic!("read pi bundle at {bundle_path}: {e}")); - let bridge_code = concat!( - include_str!(concat!(env!("OUT_DIR"), "/v8-bridge.js")), - "\n", - include_str!(concat!(env!("OUT_DIR"), "/v8-bridge-zlib.js")) - ); - - let blob = create_snapshot_with_userland(bridge_code, &userland) - .expect("real pi SDK bundle should snapshot cleanly (pure-JS, no top-level I/O)"); - let mut isolate = create_isolate_from_snapshot(blob, None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - let check = v8::String::new( - scope, - "(function(){ var r = globalThis.__PI_SDK_RUNTIME__; \ - return r && typeof r.createAgentSession === 'function' && \ - typeof r.createAllTools === 'function' ? 'ok' : 'missing'; })()", - ) - .unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "ok", - "restored isolate must expose the pi SDK runtime global from the snapshot" - ); - } - - // --- Part 23: cross-thread snapshot build → restore (diagnoses pre-warm). --- - // Build a userland snapshot on a SEPARATE spawned+joined thread, then restore and - // eval it on the main thread. If V8 fundamentally forbids restoring a blob built - // on a different thread (the suspected cause of the pre-warm wedge), this aborts. - { - let bridge_code = "(function(){ globalThis.__xt_bridge = true; })();"; - let userland = "(function(){ globalThis.__xt = { f: function(){ return 99; } }; })();"; - let blob_bytes: Vec = std::thread::spawn(move || { - create_snapshot_with_userland(bridge_code, userland) - .expect("cross-thread snapshot build should succeed") - .to_vec() - }) - .join() - .expect("build thread join"); - - let mut isolate = create_isolate_from_snapshot(blob_bytes, None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - let check = v8::String::new(scope, "String(globalThis.__xt.f())").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "99", - "a snapshot built on another thread must restore correctly on this thread" - ); - } - - // --- Part 24: session-level isolation (global AND prototype). --- - // Each agent session leases a FRESH context cloned from the same snapshot's - // default context. This is the isolation unit: a global or built-in-prototype - // mutation in "session A" must NOT be observable in "session B". - { - let bridge_code = "(function(){ globalThis.__iso_ok = true; })();"; - let userland = "(function(){ globalThis.__sdk = { v: 1 }; })();"; - let blob_bytes: Vec = create_snapshot_with_userland(bridge_code, userland) - .expect("isolation snapshot") - .to_vec(); - - // Session A: mutate a global, the captured SDK object, AND a built-in prototype. - { - let mut isolate = create_isolate_from_snapshot(blob_bytes.clone(), None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - let src = v8::String::new( - scope, - "globalThis.__leakG = 'A'; globalThis.__sdk.v = 999; \ - Array.prototype.__leakP = 'A'; ''", - ) - .unwrap(); - let script = v8::Script::compile(scope, src, None).unwrap(); - script.run(scope); - } - - // Session B: a separate fresh context from the SAME blob sees the captured - // snapshot state but NONE of session A's mutations. - { - let mut isolate = create_isolate_from_snapshot(blob_bytes.clone(), None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - let check = v8::String::new( - scope, - "(function(){ return [ \ - String(globalThis.__iso_ok), \ - typeof globalThis.__leakG, \ - String(globalThis.__sdk.v), \ - typeof ([].__leakP) \ - ].join(','); })()", - ) - .unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "true,undefined,1,undefined", - "session B must see snapshot state but NOT session A's global/SDK/prototype mutations" - ); - } - } - - // --- Part 25: H-1 regression — the userland-prep `process.versions` wrapper - // DEFERS to the bridge's live getter post-restore instead of freezing a static - // identity. --- - // `SNAPSHOT_USERLAND_PREP` wraps (does not replace) the bridge's lazy - // `process.versions` getter: during snapshot creation the live getter throws - // (bridge fns are stubs) so a static identity is used, but post-restore — once - // the real bridge fns + per-session config are injected — sessions must read the - // LIVE per-session value. A plain static pin (the prior bug) permanently shadowed - // it. This models the deferral with a getter whose result depends on the - // post-restore-injected `_processConfig`, so a regression back to a static pin - // fails here. - { - use crate::bridge::serialize_v8_value; - - // Bridge installs a lazy `process.versions` getter that derives its value from - // the per-session `_processConfig` (resolved live on each access). During - // snapshot creation `_processConfig` is the default (no `version`), so the - // getter throws — exactly the case the prep wraps. A userland is required so - // SNAPSHOT_USERLAND_PREP runs. - let bridge_code = r#" - (function () { - globalThis.process = { - get versions() { - // Throws during creation (default _processConfig has no - // version); returns the live per-session value post-restore. - return { node: _processConfig.version.replace(/^v/, "") }; - }, - }; - })(); - "#; - let userland = "(function(){ globalThis.__sdk_ready = true; })();"; - let blob = create_snapshot_with_userland(bridge_code, userland) - .expect("userland snapshot with a lazy process.versions getter"); - - let mut isolate = create_isolate_from_snapshot(blob, None); - let scope = &mut v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); - - // Inject a per-session config carrying a distinctive version (as the sidecar - // does post-restore via inject_globals_from_payload). - let payload_code = r#"({ - processConfig: { cwd: "/", env: {}, version: "v99.1.2", timing_mitigation: "off", frozen_time_ms: null }, - osConfig: { homedir: "/root", tmpdir: "/tmp", platform: "linux", arch: "x64" } - })"#; - let payload_source = v8::String::new(scope, payload_code).unwrap(); - let payload_script = v8::Script::compile(scope, payload_source, None).unwrap(); - let payload_val = payload_script.run(scope).unwrap(); - let payload_bytes = serialize_v8_value(scope, payload_val).expect("serialize payload"); - crate::execution::inject_globals_from_payload(scope, &payload_bytes) - .expect("inject per-session config"); - - // The wrapper must defer to the live getter → per-session "99.1.2", NOT the - // snapshot-build-time static identity "20.0.0". - let check = v8::String::new(scope, "String(process.versions.node)").unwrap(); - let script = v8::Script::compile(scope, check, None).unwrap(); - let result = script.run(scope).unwrap(); - assert_eq!( - result.to_rust_string_lossy(scope), - "99.1.2", - "process.versions must defer to the live per-session getter post-restore, \ - not the frozen snapshot-build-time static identity (H-1 regression)" - ); - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn bridge_cache_key_uses_full_sha256_digest() { - // With no userland the key is the plain sha256 of the bridge code, so - // bridge-only snapshot entries keep their historical keys. - assert_eq!( - snapshot_cache_key("abc", None), - [ - 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, - 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, - 0xf2, 0x00, 0x15, 0xad, - ] - ); - } - - #[test] - fn create_snapshot_rejects_oversized_bridge_code_before_v8_creation() { - let bridge_code = " ".repeat(MAX_V8_BRIDGE_CODE_BYTES + 1); - let error = match create_snapshot(&bridge_code) { - Ok(_) => panic!("oversized bridge code should be rejected"), - Err(error) => error, - }; - - assert!(error.contains(V8_BRIDGE_CODE_LIMIT_ERROR_CODE)); - assert!(error.contains("bridge code too large for V8 bridge setup")); - assert!(error.contains(&MAX_V8_BRIDGE_CODE_BYTES.to_string())); - } - - #[test] - fn snapshot_cache_rejects_oversized_bridge_code_without_retaining_in_flight_state() { - let cache = SnapshotCache::new(1); - let bridge_code = " ".repeat(MAX_V8_BRIDGE_CODE_BYTES + 1); - - for _ in 0..2 { - let error = match cache.get_or_create(&bridge_code) { - Ok(_) => panic!("oversized bridge code should be rejected"), - Err(error) => error, - }; - - assert!(error.contains(V8_BRIDGE_CODE_LIMIT_ERROR_CODE)); - } - } - - #[test] - fn snapshot_cache_key_is_dep_keyed_over_bridge_and_userland() { - let bridge = "bridge-a"; - // Userland presence changes the key vs bridge-only. - assert_ne!( - snapshot_cache_key(bridge, None), - snapshot_cache_key(bridge, Some("user-1")), - "adding userland must change the key" - ); - // Different userland → different key (any dep-graph change invalidates). - assert_ne!( - snapshot_cache_key(bridge, Some("user-1")), - snapshot_cache_key(bridge, Some("user-2")), - "different userland must produce a different key" - ); - // Identical inputs → identical key (cache hit). - assert_eq!( - snapshot_cache_key(bridge, Some("user-1")), - snapshot_cache_key(bridge, Some("user-1")), - ); - // The NUL separator prevents bridge/userland boundary collisions. - assert_ne!( - snapshot_cache_key("ab", Some("c")), - snapshot_cache_key("a", Some("bc")), - "the bridge/userland split must be unambiguous" - ); - } - - #[test] - fn create_snapshot_with_userland_rejects_oversized_userland_code() { - let bridge_code = "(function(){})();"; - let userland = " ".repeat(MAX_V8_USERLAND_CODE_BYTES + 1); - let error = match create_snapshot_with_userland(bridge_code, &userland) { - Ok(_) => panic!("oversized userland code should be rejected"), - Err(error) => error, - }; - - assert!(error.contains(V8_USERLAND_CODE_LIMIT_ERROR_CODE)); - assert!(error.contains("userland snapshot code too large")); - } -} diff --git a/crates/v8-runtime/src/stream.rs b/crates/v8-runtime/src/stream.rs deleted file mode 100644 index c9fe70073..000000000 --- a/crates/v8-runtime/src/stream.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Async event dispatch for child process and HTTP server streams - -/// Dispatch a stream event into V8 by calling the registered callback function. -/// -/// Stream events are sent by the host when async operations (child processes, -/// HTTP servers) produce data. The event_type determines which V8 dispatch -/// function is called: -/// - "child_stdout", "child_stderr", "child_exit" → _childProcessDispatch -/// - "http_request" → _httpServerDispatch -/// - "http2" → _http2Dispatch -/// - "stdin", "stdin_end" → _stdinDispatch -/// - "net_socket" → _netSocketDispatch -/// - "signal" → __secureExecWasmSignalDispatch or _signalDispatch -/// - "timer" → _timerDispatch -pub fn dispatch_stream_event(scope: &mut v8::HandleScope, event_type: &str, payload: &[u8]) { - // Look up the dispatch function on the global object - let context = scope.get_current_context(); - let global = context.global(scope); - - let dispatch_names: &[&str] = match event_type { - "child_stdout" | "child_stderr" | "child_exit" => &["_childProcessDispatch"], - "http_request" => &["_httpServerDispatch"], - "http2" => &["_http2Dispatch"], - "stdin" | "stdin_end" => &["_stdinDispatch"], - "net_socket" => &["_netSocketDispatch"], - "signal" => &["__secureExecWasmSignalDispatch", "_signalDispatch"], - "timer" => &["_timerDispatch"], - _ => return, // Unknown event type — ignore - }; - - for dispatch_name in dispatch_names { - let key = v8::String::new(scope, dispatch_name).unwrap(); - let maybe_fn = global.get(scope, key.into()); - - if let Some(func_val) = maybe_fn { - if func_val.is_function() { - let func = v8::Local::::try_from(func_val).unwrap(); - - // Pass event_type and payload as arguments. - let event_str = v8::String::new(scope, event_type).unwrap(); - let payload_val = if !payload.is_empty() { - let maybe_v8_payload = { - let tc = &mut v8::TryCatch::new(scope); - crate::bridge::deserialize_v8_value(tc, payload).ok() - }; - match maybe_v8_payload { - Some(v) => v, - None => match std::str::from_utf8(payload) { - Ok(text) => match v8::String::new(scope, text) { - Some(json_text) => v8::json::parse(scope, json_text) - .unwrap_or_else(|| json_text.into()), - None => v8::null(scope).into(), - }, - Err(_) => v8::null(scope).into(), - }, - } - } else { - v8::null(scope).into() - }; - - let undefined = v8::undefined(scope); - let args: &[v8::Local] = &[event_str.into(), payload_val]; - func.call(scope, undefined.into(), args); - return; - } - } - } -} diff --git a/crates/v8-runtime/src/timeout.rs b/crates/v8-runtime/src/timeout.rs deleted file mode 100644 index faff93817..000000000 --- a/crates/v8-runtime/src/timeout.rs +++ /dev/null @@ -1,446 +0,0 @@ -// Execution budget enforcement via dedicated watchdog threads. -// -// Two INDEPENDENT mechanisms live here: -// -// * `TimeoutGuard` — a WALL-CLOCK timer. It counts elapsed real time -// INCLUDING idle/await, so it can cap a guest that blocks or awaits -// indefinitely. It is an INDEPENDENT, opt-in backstop armed only when the -// operator sets `limits.jsRuntime.wallClockLimitMs` (off by default so -// long-lived ACP adapters are never killed by a default). -// -// * `CpuBudgetGuard` — a TRUE CPU-TIME budget. It samples the EXECUTION -// thread's per-thread CPU clock (`pthread_getcpuclockid` + -// `clock_gettime`). Because a thread's CPU clock does not advance while the -// thread is parked/awaiting I/O, this counts ONLY active JS CPU time and -// EXCLUDES idle/await. V8 has no native budget primitive, so this poll + -// `terminate_execution()` approach is the standard embedder pattern. Armed -// when the caller passes a nonzero `limits.jsRuntime.cpuTimeLimitMs`. -// secure-exec sidecar VM executions supply a bounded default; lower-level -// embedders may pass `None`/`0` to leave the guard disabled. -// -// The two guards are independent: setting one typed limit arms only that guard, -// and when both are set whichever fires first terminates execution. - -use secure_exec_bridge::queue_tracker::{register_limit, TrackedLimit}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; -use std::thread; -use std::time::Duration; - -pub(crate) const TIMEOUT_GUARD_START_ERROR_CODE: &str = "ERR_TIMEOUT_GUARD_START"; -#[cfg_attr(test, allow(dead_code))] -pub(crate) const CPU_BUDGET_GUARD_START_ERROR_CODE: &str = "ERR_CPU_BUDGET_GUARD_START"; - -/// How often the CPU-budget watchdog samples the execution thread's CPU clock. -#[cfg_attr(test, allow(dead_code))] -const CPU_BUDGET_POLL_INTERVAL: Duration = Duration::from_millis(50); - -/// An opaque handle to a specific thread's CPU-time clock, captured ON that -/// thread and safe to read from another (watchdog) thread. -/// -/// The POSIX per-thread CPU clock id is derived from the thread's `pthread_t` -/// and remains valid for the lifetime of that thread, so the watchdog can poll -/// it via `clock_gettime` without running on the execution thread itself. -/// -/// macOS has no `pthread_getcpuclockid`/per-thread POSIX clock, so it uses a -/// separate Mach-based implementation below (`pthread_mach_thread_np` + -/// `thread_info`) that exposes the same opaque `ThreadCpuClock` interface. -#[cfg(all(unix, not(target_os = "macos")))] -#[cfg_attr(test, allow(dead_code))] -#[derive(Clone, Copy)] -pub(crate) struct ThreadCpuClock { - clockid: libc::clockid_t, -} - -/// Capture the CALLING thread's CPU-time clock. Must be invoked on the thread -/// whose CPU time should be measured (i.e. the execution thread). -/// -/// Returns `None` if the platform refuses to expose a per-thread CPU clock, in -/// which case no CPU budget can be enforced. -#[cfg(all(unix, not(target_os = "macos")))] -#[cfg_attr(test, allow(dead_code))] -pub(crate) fn current_thread_cpu_clock() -> Option { - // SAFETY: `pthread_self` is always callable; `pthread_getcpuclockid` writes - // a valid clockid into `clockid` on success (return 0). - unsafe { - let mut clockid: libc::clockid_t = 0; - let rc = libc::pthread_getcpuclockid(libc::pthread_self(), &mut clockid); - if rc == 0 { - Some(ThreadCpuClock { clockid }) - } else { - None - } - } -} - -#[cfg(all(unix, not(target_os = "macos")))] -impl ThreadCpuClock { - /// Read accumulated CPU time for the captured thread, in milliseconds. - /// Returns `None` if the clock read fails. - #[cfg_attr(test, allow(dead_code))] - fn elapsed_ms(self) -> Option { - // SAFETY: `clockid` came from a successful `pthread_getcpuclockid`; the - // timespec is fully written by `clock_gettime` on success. - unsafe { - let mut ts: libc::timespec = std::mem::zeroed(); - if libc::clock_gettime(self.clockid, &mut ts) == 0 { - let ms = (ts.tv_sec as i128) * 1_000 + (ts.tv_nsec as i128) / 1_000_000; - Some(ms.max(0) as u64) - } else { - None - } - } - } -} - -/// macOS per-thread CPU clock. There is no `pthread_getcpuclockid` on Apple -/// platforms, so the thread's CPU time is read through the Mach -/// `thread_info(THREAD_BASIC_INFO)` call. The Mach thread port obtained via -/// `pthread_mach_thread_np` stays valid for the thread's lifetime and may be -/// inspected from another (watchdog) thread, matching the opaque-handle -/// contract above. -#[cfg(target_os = "macos")] -#[cfg_attr(test, allow(dead_code))] -#[derive(Clone, Copy)] -pub(crate) struct ThreadCpuClock { - port: libc::mach_port_t, -} - -#[cfg(target_os = "macos")] -#[cfg_attr(test, allow(dead_code))] -pub(crate) fn current_thread_cpu_clock() -> Option { - // SAFETY: `pthread_mach_thread_np` returns the Mach thread port for the - // calling pthread; the port is valid for the thread's lifetime. - let port = unsafe { libc::pthread_mach_thread_np(libc::pthread_self()) }; - // MACH_PORT_NULL is 0. - if port == 0 { - None - } else { - Some(ThreadCpuClock { port }) - } -} - -#[cfg(target_os = "macos")] -impl ThreadCpuClock { - /// Read accumulated CPU time (user + system) for the captured thread, in - /// milliseconds. Returns `None` if the Mach query fails. - #[cfg_attr(test, allow(dead_code))] - fn elapsed_ms(self) -> Option { - // SAFETY: `thread_info` fully initialises `info` when it returns - // KERN_SUCCESS; the count is the documented THREAD_BASIC_INFO length. - unsafe { - let mut info = std::mem::MaybeUninit::::zeroed(); - let mut count = (std::mem::size_of::() - / std::mem::size_of::()) - as libc::mach_msg_type_number_t; - let rc = libc::thread_info( - self.port, - libc::THREAD_BASIC_INFO as libc::thread_flavor_t, - info.as_mut_ptr() as libc::thread_info_t, - &mut count, - ); - if rc != libc::KERN_SUCCESS { - return None; - } - let info = info.assume_init(); - let ms = (info.user_time.seconds as i128 + info.system_time.seconds as i128) * 1_000 - + (info.user_time.microseconds as i128 + info.system_time.microseconds as i128) - / 1_000; - Some(ms.max(0) as u64) - } - } -} - -/// Guard for per-execution TRUE CPU-time budget enforcement. -/// -/// Spawns a watchdog thread that polls the execution thread's CPU clock every -/// [`CPU_BUDGET_POLL_INTERVAL`]. When accumulated active-JS CPU time exceeds the -/// budget, it calls `v8::Isolate::terminate_execution()` and signals the -/// execution abort with [`crate::session::ExecutionAbortReason::CpuBudgetExceeded`]. -/// A guest that mostly awaits/idles accrues little CPU time and is NOT killed. -/// -/// Drop or call `cancel()` to stop the watchdog (execution completed normally). -pub(crate) struct CpuBudgetGuard { - cancel_tx: Option>, - fired: Arc, - join_handle: Option>, -} - -#[cfg(unix)] -impl CpuBudgetGuard { - /// Spawn the CPU-budget watchdog. - /// - /// - `budget_ms`: TRUE CPU-time budget in milliseconds (active JS only) - /// - `cpu_clock`: the execution thread's CPU clock (captured on that thread) - /// - `isolate_handle`: V8 isolate handle for `terminate_execution()` - /// - `execution_abort`: signalled with `CpuBudgetExceeded` when the budget is exhausted - #[cfg_attr(test, allow(dead_code))] - pub(crate) fn new( - budget_ms: u32, - cpu_clock: ThreadCpuClock, - isolate_handle: v8::IsolateHandle, - execution_abort: crate::session::SharedExecutionAbort, - ) -> Result { - let (cancel_tx, cancel_rx) = crossbeam_channel::bounded::<()>(1); - let fired = Arc::new(AtomicBool::new(false)); - let fired_clone = Arc::clone(&fired); - - // Snapshot the thread's CPU time at arm so the budget measures CPU - // consumed DURING this execution, not cumulative thread lifetime. - let baseline_ms = cpu_clock.elapsed_ms().unwrap_or(0); - let budget_ms = budget_ms as u64; - - // Sample CPU consumption into a registry gauge every poll so the operator - // gets an edge-triggered ~80% approach warning BEFORE the budget is - // exhausted and the isolate is terminated (the terminal edge is reported - // separately by `warn_limit_exhausted`). - let cpu_gauge = register_limit(TrackedLimit::V8CpuTimeMs, budget_ms as usize); - - let handle = thread::Builder::new() - .name("cpu-budget".into()) - .spawn(move || { - let ticker = crossbeam_channel::tick(CPU_BUDGET_POLL_INTERVAL); - loop { - crossbeam_channel::select! { - recv(cancel_rx) -> _ => { - // Cancelled — execution completed normally. - return; - } - recv(ticker) -> _ => { - let used = cpu_clock - .elapsed_ms() - .unwrap_or(baseline_ms) - .saturating_sub(baseline_ms); - cpu_gauge.observe_depth(used as usize); - if used >= budget_ms { - fired_clone.store(true, Ordering::SeqCst); - isolate_handle.terminate_execution(); - crate::session::signal_execution_abort( - &execution_abort, - crate::session::ExecutionAbortReason::CpuBudgetExceeded, - ); - return; - } - } - } - } - }) - .map_err(|error| { - format!( - "{CPU_BUDGET_GUARD_START_ERROR_CODE}: failed to spawn cpu-budget thread: {error}" - ) - })?; - - Ok(CpuBudgetGuard { - cancel_tx: Some(cancel_tx), - fired, - join_handle: Some(handle), - }) - } - - /// Cancel the watchdog (execution completed normally). Blocks until the - /// watchdog thread exits. - pub(crate) fn cancel(&mut self) { - self.cancel_tx.take(); - if let Some(h) = self.join_handle.take() { - let _ = h.join(); - } - } - - /// Check whether the CPU budget was exhausted. - #[cfg_attr(test, allow(dead_code))] - pub(crate) fn exceeded(&self) -> bool { - self.fired.load(Ordering::SeqCst) - } -} - -#[cfg(unix)] -impl Drop for CpuBudgetGuard { - fn drop(&mut self) { - self.cancel(); - } -} - -// Non-unix fallback: there is no portable per-thread CPU clock, so the -// CPU-budget watchdog cannot be enforced. `current_thread_cpu_clock` returns -// `None`, which makes the session surface a clear "cannot enforce" error if a -// CPU budget is requested, rather than silently running uncapped. -#[cfg(not(unix))] -#[derive(Clone, Copy)] -pub(crate) struct ThreadCpuClock; - -#[cfg(not(unix))] -pub(crate) fn current_thread_cpu_clock() -> Option { - None -} - -#[cfg(not(unix))] -impl CpuBudgetGuard { - pub(crate) fn new( - _budget_ms: u32, - _cpu_clock: ThreadCpuClock, - _isolate_handle: v8::IsolateHandle, - _execution_abort: crate::session::SharedExecutionAbort, - ) -> Result { - Err(format!( - "{CPU_BUDGET_GUARD_START_ERROR_CODE}: per-thread CPU clock not supported on this platform" - )) - } - - pub(crate) fn cancel(&mut self) {} - - #[cfg_attr(test, allow(dead_code))] - pub(crate) fn exceeded(&self) -> bool { - self.fired.load(Ordering::SeqCst) - } -} - -/// Guard for per-session CPU timeout enforcement. -/// -/// Spawns a timer thread that calls `v8::Isolate::terminate_execution()` -/// and closes the active execution abort channel to unblock any channel-based -/// readers when the timeout elapses. Drop or call `cancel()` to prevent firing. -pub struct TimeoutGuard { - /// Sender side of cancellation channel — dropped to cancel the timer - cancel_tx: Option>, - /// Set to true when the timeout fired - fired: Arc, - /// Timer thread handle - join_handle: Option>, -} - -impl TimeoutGuard { - /// Spawn a timeout timer thread. - /// - /// - `timeout_ms`: wall-clock time limit in milliseconds - /// - `isolate_handle`: V8 isolate handle for `terminate_execution()` - /// - `abort_tx`: dropped on timeout to unblock channel readers via `select!` - pub(crate) fn new( - timeout_ms: u32, - isolate_handle: v8::IsolateHandle, - abort_tx: crossbeam_channel::Sender<()>, - ) -> Result { - Self::spawn(timeout_ms, isolate_handle, move || { - drop(abort_tx); - }) - } - - /// Spawn a wall-clock backstop that signals the execution abort with - /// [`crate::session::ExecutionAbortReason::WallClockTimedOut`] when the limit - /// elapses. Unlike the CPU budget, this counts elapsed real time INCLUDING - /// idle/await. Armed only when the operator opts in via - /// `limits.jsRuntime.wallClockLimitMs`. - #[cfg_attr(test, allow(dead_code))] - pub(crate) fn with_execution_abort( - timeout_ms: u32, - isolate_handle: v8::IsolateHandle, - execution_abort: crate::session::SharedExecutionAbort, - ) -> Result { - Self::spawn(timeout_ms, isolate_handle, move || { - crate::session::signal_execution_abort( - &execution_abort, - crate::session::ExecutionAbortReason::WallClockTimedOut, - ); - }) - } - - fn spawn( - timeout_ms: u32, - isolate_handle: v8::IsolateHandle, - on_timeout: impl FnOnce() + Send + 'static, - ) -> Result { - let (cancel_tx, cancel_rx) = crossbeam_channel::bounded::<()>(1); - let fired = Arc::new(AtomicBool::new(false)); - let fired_clone = Arc::clone(&fired); - - // Emit an edge-triggered ~80% approach warning before the wall-clock - // budget is exhausted and the isolate is terminated. Observing the gauge - // once at the threshold reuses the registry's warn + host-forward path. - let wall_gauge = register_limit(TrackedLimit::V8WallClockMs, timeout_ms as usize); - let warn_at_ms = - timeout_ms as u64 * secure_exec_bridge::queue_tracker::WARN_FILL_PERCENT as u64 / 100; - - let handle = thread::Builder::new() - .name("timeout".into()) - .spawn(move || { - let warn_timer = crossbeam_channel::after(Duration::from_millis(warn_at_ms)); - let timer = crossbeam_channel::after(Duration::from_millis(timeout_ms as u64)); - - loop { - crossbeam_channel::select! { - recv(warn_timer) -> _ => { - // Crossed the approach threshold — warn once. The full - // timer (and cancel) are still pending; `after` fires - // only once, so the next select waits on those. - wall_gauge.observe_depth(warn_at_ms as usize); - } - recv(timer) -> _ => { - // Timeout elapsed — terminate V8 execution - fired_clone.store(true, Ordering::SeqCst); - isolate_handle.terminate_execution(); - on_timeout(); - return; - } - recv(cancel_rx) -> _ => { - // Cancelled — execution completed normally - return; - } - } - } - }) - .map_err(|error| { - format!("{TIMEOUT_GUARD_START_ERROR_CODE}: failed to spawn timeout thread: {error}") - })?; - - Ok(TimeoutGuard { - cancel_tx: Some(cancel_tx), - fired, - join_handle: Some(handle), - }) - } - - /// Cancel the timeout (execution completed normally). - /// Blocks until the timer thread exits. - pub fn cancel(&mut self) { - // Drop the cancel sender to unblock the timer thread's select! - self.cancel_tx.take(); - if let Some(h) = self.join_handle.take() { - let _ = h.join(); - } - } - - /// Check if the timeout fired. - pub fn timed_out(&self) -> bool { - self.fired.load(Ordering::SeqCst) - } -} - -impl Drop for TimeoutGuard { - fn drop(&mut self) { - self.cancel(); - } -} - -#[cfg(test)] -mod tests { - #[test] - fn timeout_guard_cancel_before_fire() { - // Timer set to 5 seconds, cancelled immediately — should not fire - let (abort_tx, abort_rx) = crossbeam_channel::bounded::<()>(0); - - // Create a minimal V8 platform + isolate just for the handle - // We avoid actual V8 in tests — use a different approach - // Instead, test the cancellation logic without V8 - - // We can't easily get a v8::IsolateHandle without V8 init, - // so we test the TimeoutGuard flow via integration in execution::tests - drop(abort_tx); - drop(abort_rx); - } - - #[test] - fn timeout_guard_fires_on_expiry() { - // Tested via V8 integration tests in execution::tests - // This placeholder confirms the module compiles correctly - } -} diff --git a/crates/v8-runtime/tests/embedded_runtime_session.rs b/crates/v8-runtime/tests/embedded_runtime_session.rs deleted file mode 100644 index a39b55296..000000000 --- a/crates/v8-runtime/tests/embedded_runtime_session.rs +++ /dev/null @@ -1,632 +0,0 @@ -use secure_exec_v8_runtime::embedded_runtime::{shared_embedded_runtime, EmbeddedV8Runtime}; -use secure_exec_v8_runtime::runtime_protocol::{RuntimeCommand, RuntimeEvent, SessionMessage}; -use std::io; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::mpsc; -use std::sync::Arc; -use std::thread; -use std::time::{Duration, Instant}; - -// Timing-sensitive assertions flake under the CPU contention of a parallel test -// run (see CLAUDE.md > Testing). Gated off by default; the nightly timing lane -// sets SECURE_EXEC_RUN_TIMING_TESTS=1 to enforce them. -fn run_timing_sensitive_tests() -> bool { - std::env::var_os("SECURE_EXEC_RUN_TIMING_TESTS").is_some() -} - -static NEXT_TEST_SESSION_ID: AtomicU64 = AtomicU64::new(1); - -fn next_session_id() -> String { - format!( - "embedded-runtime-session-{}", - NEXT_TEST_SESSION_ID.fetch_add(1, Ordering::Relaxed) - ) -} - -fn register_and_create_session( - runtime: &Arc, - session_id: &str, -) -> io::Result> { - let receiver = runtime.register_session(session_id)?; - runtime.dispatch(RuntimeCommand::CreateSession { - session_id: session_id.to_owned(), - heap_limit_mb: None, - cpu_time_limit_ms: None, - wall_clock_limit_ms: None, - warm_hint: None, - })?; - Ok(receiver) -} - -fn register_and_create_session_with_cpu_time_limit( - runtime: &Arc, - session_id: &str, - cpu_time_limit_ms: Option, -) -> io::Result> { - let receiver = runtime.register_session(session_id)?; - runtime.dispatch(RuntimeCommand::CreateSession { - session_id: session_id.to_owned(), - heap_limit_mb: None, - cpu_time_limit_ms, - wall_clock_limit_ms: None, - warm_hint: None, - })?; - Ok(receiver) -} - -fn dispatch_execute( - runtime: &EmbeddedV8Runtime, - session_id: &str, - mode: u8, - bridge_code: &str, - user_code: &str, -) -> io::Result<()> { - runtime.dispatch(RuntimeCommand::SendToSession { - session_id: session_id.to_owned(), - message: SessionMessage::Execute { - mode, - file_path: String::new(), - bridge_code: bridge_code.to_owned(), - post_restore_script: String::new(), - userland_code: String::new(), - high_resolution_time: false, - user_code: user_code.to_owned(), - wasm_module_bytes: None, - }, - }) -} - -fn wait_for_execution_result( - receiver: &mpsc::Receiver, - session_id: &str, -) -> RuntimeEvent { - let deadline = Instant::now() + Duration::from_secs(5); - loop { - let remaining = deadline - .checked_duration_since(Instant::now()) - .expect("timed out waiting for execution result"); - let event = receiver - .recv_timeout(remaining) - .expect("runtime event should arrive before timeout"); - if matches!( - &event, - RuntimeEvent::ExecutionResult { - session_id: event_session_id, - .. - } if event_session_id == session_id - ) { - return event; - } - } -} - -fn wait_for_bridge_call(receiver: &mpsc::Receiver, session_id: &str) -> RuntimeEvent { - let deadline = Instant::now() + Duration::from_secs(5); - loop { - let remaining = deadline - .checked_duration_since(Instant::now()) - .expect("timed out waiting for bridge call"); - let event = receiver - .recv_timeout(remaining) - .expect("bridge call should arrive before timeout"); - if matches!( - &event, - RuntimeEvent::BridgeCall { - session_id: event_session_id, - .. - } if event_session_id == session_id - ) { - return event; - } - } -} - -fn assert_execution_ok(receiver: &mpsc::Receiver, session_id: &str) { - let event = wait_for_execution_result(receiver, session_id); - match event { - RuntimeEvent::ExecutionResult { - exit_code, - error, - exports, - .. - } => { - assert_eq!(exit_code, 0, "expected successful execution result"); - assert!(error.is_none(), "unexpected execution error: {error:?}"); - assert!( - exports.is_none(), - "script execution should not export values" - ); - } - other => panic!("expected execution result, got {other:?}"), - } -} - -fn wait_until(message: &str, predicate: impl Fn() -> bool) { - let deadline = Instant::now() + Duration::from_secs(5); - while Instant::now() < deadline { - if predicate() { - return; - } - thread::sleep(Duration::from_millis(10)); - } - panic!("{message}"); -} - -fn assert_create_destroy_reuses_session_ids() -> io::Result<()> { - let runtime = shared_embedded_runtime()?; - let session_id = next_session_id(); - - let _receiver = register_and_create_session(&runtime, &session_id)?; - assert!( - runtime.session_count() >= 1, - "embedded runtime should track created sessions" - ); - - let duplicate_error = runtime - .dispatch(RuntimeCommand::CreateSession { - session_id: session_id.clone(), - heap_limit_mb: None, - cpu_time_limit_ms: None, - wall_clock_limit_ms: None, - warm_hint: None, - }) - .expect_err("duplicate sessions should be rejected"); - assert_eq!(duplicate_error.kind(), io::ErrorKind::Other); - - runtime.session_handle(session_id.clone()).destroy()?; - assert_eq!( - runtime.session_count(), - 0, - "destroying the only test session should return the runtime to zero sessions" - ); - - let _receiver = register_and_create_session(&runtime, &session_id)?; - runtime.session_handle(session_id).destroy()?; - assert_eq!( - runtime.session_count(), - 0, - "recreated sessions should also tear down cleanly" - ); - - Ok(()) -} - -fn assert_warmed_snapshot_bridge_state() -> io::Result<()> { - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1))?); - let session_id = next_session_id(); - let receiver = register_and_create_session(&runtime, &session_id)?; - let bridge_code = "(function() { globalThis.__snapshotMarker = 'warm'; })();"; - - runtime.dispatch(RuntimeCommand::WarmSnapshot { - bridge_code: bridge_code.to_owned(), - userland_code: String::new(), - })?; - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - bridge_code, - "if (globalThis.__snapshotMarker !== 'warm') { throw new Error(`saw ${globalThis.__snapshotMarker}`); }", - )?; - assert_execution_ok(&receiver, &session_id); - - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_id.clone(), - })?; - runtime.unregister_session(&session_id); - Ok(()) -} - -fn assert_snapshot_rebuild_on_bridge_change() -> io::Result<()> { - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1))?); - let session_id = next_session_id(); - let receiver = register_and_create_session(&runtime, &session_id)?; - let bridge_a = "(function() { globalThis.__bridgeSnapshot = 'A'; })();"; - let bridge_b = "(function() { globalThis.__bridgeSnapshot = 'B'; })();"; - - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - bridge_a, - "if (globalThis.__bridgeSnapshot !== 'A') { throw new Error(`saw ${globalThis.__bridgeSnapshot}`); }", - )?; - assert_execution_ok(&receiver, &session_id); - - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - bridge_b, - "if (globalThis.__bridgeSnapshot !== 'B') { throw new Error(`saw ${globalThis.__bridgeSnapshot}`); }", - )?; - assert_execution_ok(&receiver, &session_id); - - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_id.clone(), - })?; - runtime.unregister_session(&session_id); - Ok(()) -} - -fn assert_execute_rejects_oversized_bridge_code() -> io::Result<()> { - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1))?); - let session_id = next_session_id(); - let receiver = register_and_create_session(&runtime, &session_id)?; - let oversized_bridge_code = " ".repeat(16 * 1024 * 1024 + 1); - - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - &oversized_bridge_code, - "globalThis.__should_not_run = true;", - )?; - - let event = wait_for_execution_result(&receiver, &session_id); - match event { - RuntimeEvent::ExecutionResult { - exit_code, - error: Some(error), - .. - } => { - assert_eq!(exit_code, 1); - assert_eq!(error.code, "ERR_V8_BRIDGE_CODE_LIMIT"); - assert!(error - .message - .contains("bridge code too large for V8 bridge setup")); - } - other => panic!("expected bridge-code limit execution error, got {other:?}"), - } - - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_id.clone(), - })?; - runtime.unregister_session(&session_id); - wait_until( - "expected oversized-bridge session to drain after rejection", - || runtime.session_count() == 0 && runtime.active_slot_count() == 0, - ); - Ok(()) -} - -fn assert_direct_zero_cpu_time_limit_disables_timeout() -> io::Result<()> { - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1))?); - let session_id = next_session_id(); - let receiver = register_and_create_session_with_cpu_time_limit(&runtime, &session_id, Some(0))?; - - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - "", - "let total = 0; for (let i = 0; i < 100000; i++) { total += i; }", - )?; - assert_execution_ok(&receiver, &session_id); - - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_id.clone(), - })?; - runtime.unregister_session(&session_id); - wait_until( - "expected zero-timeout session to drain after successful execution", - || runtime.session_count() == 0 && runtime.active_slot_count() == 0, - ); - Ok(()) -} - -fn assert_queued_work_waits_for_slot_release() -> io::Result<()> { - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1))?); - let session_a = next_session_id(); - let session_b = next_session_id(); - let receiver_a = register_and_create_session(&runtime, &session_a)?; - - wait_until( - "expected the first embedded session to occupy the only slot before the second session is created", - || runtime.active_slot_count() == 1 && runtime.session_count() == 1, - ); - - dispatch_execute( - runtime.as_ref(), - &session_a, - 1, - "", - "await new Promise(() => {});", - )?; - - let receiver_b = register_and_create_session(&runtime, &session_b)?; - dispatch_execute( - runtime.as_ref(), - &session_b, - 0, - "(function() { globalThis.__queuedSession = 'released'; })();", - "if (globalThis.__queuedSession !== 'released') { throw new Error(`saw ${globalThis.__queuedSession}`); }", - )?; - - wait_until( - "expected one active slot with the second session still queued", - || runtime.active_slot_count() == 1 && runtime.session_count() == 2, - ); - if run_timing_sensitive_tests() { - assert!( - receiver_b.recv_timeout(Duration::from_millis(150)).is_err(), - "queued session should not emit an execution result before the first slot is released" - ); - } - - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_a.clone(), - })?; - let terminated = wait_for_execution_result(&receiver_a, &session_a); - assert!( - matches!( - terminated, - RuntimeEvent::ExecutionResult { - exit_code: 1, - ref error, - .. - } if error.as_ref().is_some_and(|error| error.message == "Execution terminated") - ), - "destroying the in-flight session should terminate its pending execution" - ); - - assert_execution_ok(&receiver_b, &session_b); - - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_b.clone(), - })?; - runtime.unregister_session(&session_a); - runtime.unregister_session(&session_b); - wait_until( - "expected all embedded sessions and slots to drain after teardown", - || runtime.session_count() == 0 && runtime.active_slot_count() == 0, - ); - Ok(()) -} - -fn assert_shared_runtime_handles_share_concurrency_quota() -> io::Result<()> { - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(3))?); - let clients = (0..4) - .map(|_| Arc::clone(&runtime)) - .collect::>>(); - let session_ids = (0..4).map(|_| next_session_id()).collect::>(); - let mut receivers = clients - .iter() - .zip(session_ids.iter()) - .take(3) - .map(|(client, session_id)| register_and_create_session(client, session_id)) - .collect::>>()?; - - wait_until( - "expected the first three embedded sessions to occupy the shared slots before the fourth session is created", - || runtime.active_slot_count() == 3 && runtime.session_count() == 3, - ); - - receivers.push(register_and_create_session(&clients[3], &session_ids[3])?); - - for (client, session_id) in clients.iter().zip(session_ids.iter()).take(3) { - dispatch_execute( - client.as_ref(), - session_id, - 1, - "", - "await new Promise(() => {});", - )?; - } - dispatch_execute( - clients[3].as_ref(), - &session_ids[3], - 0, - "(function() { globalThis.__sharedQuota = 'released'; })();", - "if (globalThis.__sharedQuota !== 'released') { throw new Error(`saw ${globalThis.__sharedQuota}`); }", - )?; - - wait_until( - "expected one runtime-wide slot budget shared across all embedded runtime handles", - || runtime.active_slot_count() == 3 && runtime.session_count() == 4, - ); - if run_timing_sensitive_tests() { - assert!( - receivers[3] - .recv_timeout(Duration::from_millis(150)) - .is_err(), - "the fourth client should stay queued while the first three handles occupy the shared slots" - ); - } - - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_ids[0].clone(), - })?; - let terminated = wait_for_execution_result(&receivers[0], &session_ids[0]); - assert!( - matches!( - terminated, - RuntimeEvent::ExecutionResult { - exit_code: 1, - ref error, - .. - } if error.as_ref().is_some_and(|error| error.message == "Execution terminated") - ), - "destroying one in-flight session should release a shared slot for queued handles" - ); - - assert_execution_ok(&receivers[3], &session_ids[3]); - - for session_id in session_ids.iter().skip(1) { - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_id.clone(), - })?; - } - for session_id in &session_ids { - runtime.unregister_session(session_id); - } - wait_until( - "expected all shared-runtime sessions and slots to drain after teardown", - || runtime.session_count() == 0 && runtime.active_slot_count() == 0, - ); - Ok(()) -} - -fn assert_terminate_interrupts_sync_bridge_wait() -> io::Result<()> { - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1))?); - let session_id = next_session_id(); - let receiver = register_and_create_session(&runtime, &session_id)?; - - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - "", - "_loadFileSync('/never-responds');", - )?; - - let bridge_call = wait_for_bridge_call(&receiver, &session_id); - assert!( - matches!( - bridge_call, - RuntimeEvent::BridgeCall { ref method, .. } if method == "_loadFileSync" - ), - "expected the blocked sync bridge call to be visible before termination" - ); - - let terminate_started = Instant::now(); - runtime.session_handle(session_id.clone()).terminate()?; - let terminated = wait_for_execution_result(&receiver, &session_id); - - if run_timing_sensitive_tests() { - assert!( - terminate_started.elapsed() < Duration::from_secs(1), - "terminate() should return promptly while the sync bridge call is blocked" - ); - } - assert!( - matches!( - terminated, - RuntimeEvent::ExecutionResult { - exit_code: 1, - ref error, - .. - } if error.as_ref().is_some_and(|error| error.message == "Execution terminated") - ), - "terminate() should interrupt a blocked sync bridge call instead of waiting for a host response" - ); - - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - "", - "globalThis.__afterExplicitTerminate = 'ok';", - )?; - assert_execution_ok(&receiver, &session_id); - - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_id.clone(), - })?; - runtime.unregister_session(&session_id); - wait_until( - "expected the terminated sync-bridge session to drain cleanly", - || runtime.session_count() == 0 && runtime.active_slot_count() == 0, - ); - Ok(()) -} - -fn assert_cpu_terminated_session_can_execute_again() -> io::Result<()> { - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1))?); - let session_id = next_session_id(); - let receiver = - register_and_create_session_with_cpu_time_limit(&runtime, &session_id, Some(25))?; - - dispatch_execute(runtime.as_ref(), &session_id, 0, "", "while (true) {}")?; - let terminated = wait_for_execution_result(&receiver, &session_id); - assert!( - matches!( - terminated, - RuntimeEvent::ExecutionResult { - exit_code: 1, - ref error, - .. - } if error - .as_ref() - .is_some_and(|error| error.code == "ERR_SCRIPT_CPU_BUDGET_EXCEEDED") - ), - "CPU-budget termination should be attributed before reuse" - ); - - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - "", - "globalThis.__afterCpuTerminate = 'ok';", - )?; - assert_execution_ok(&receiver, &session_id); - - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_id.clone(), - })?; - runtime.unregister_session(&session_id); - wait_until( - "expected CPU-terminated session to drain cleanly after reuse", - || runtime.session_count() == 0 && runtime.active_slot_count() == 0, - ); - Ok(()) -} - -fn assert_isolate_churn_recreates_embedded_sessions_without_segv() -> io::Result<()> { - let runtime = Arc::new(EmbeddedV8Runtime::new(Some(1))?); - let bridge_code = "(function() { globalThis.__churnBridgeReady = true; })();"; - - for _ in 0..32 { - let session_id = next_session_id(); - let receiver = register_and_create_session(&runtime, &session_id)?; - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - bridge_code, - "if (globalThis.__churnBridgeReady !== true) { throw new Error('missing bridge'); }", - )?; - assert_execution_ok(&receiver, &session_id); - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_id.clone(), - })?; - runtime.unregister_session(&session_id); - } - - let session_id = next_session_id(); - let receiver = register_and_create_session(&runtime, &session_id)?; - dispatch_execute( - runtime.as_ref(), - &session_id, - 0, - bridge_code, - "globalThis.__afterChurn = 42;", - )?; - assert_execution_ok(&receiver, &session_id); - runtime.dispatch(RuntimeCommand::DestroySession { - session_id: session_id.clone(), - })?; - runtime.unregister_session(&session_id); - wait_until("expected isolate churn sessions to drain", || { - runtime.session_count() == 0 && runtime.active_slot_count() == 0 - }); - Ok(()) -} - -#[test] -fn embedded_runtime_session_consolidated_behaviors() -> io::Result<()> { - // Keep the embedded-runtime coverage in one test process. V8 teardown across - // multiple integration tests still trips intermittent SIGSEGVs in this crate. - assert_create_destroy_reuses_session_ids()?; - assert_warmed_snapshot_bridge_state()?; - assert_snapshot_rebuild_on_bridge_change()?; - assert_execute_rejects_oversized_bridge_code()?; - assert_direct_zero_cpu_time_limit_disables_timeout()?; - assert_queued_work_waits_for_slot_release()?; - assert_shared_runtime_handles_share_concurrency_quota()?; - assert_terminate_interrupts_sync_bridge_wait()?; - assert_cpu_terminated_session_can_execute_again()?; - assert_isolate_churn_recreates_embedded_sessions_without_segv()?; - Ok(()) -} diff --git a/crates/v8-runtime/tests/event_loop.rs b/crates/v8-runtime/tests/event_loop.rs deleted file mode 100644 index 8ceab0886..000000000 --- a/crates/v8-runtime/tests/event_loop.rs +++ /dev/null @@ -1,371 +0,0 @@ -use crossbeam_channel::Receiver; -use secure_exec_v8_runtime::bridge::PendingPromises; -use secure_exec_v8_runtime::execution; -use secure_exec_v8_runtime::isolate; -use secure_exec_v8_runtime::runtime_protocol::{SessionMessage, StreamEvent}; -use secure_exec_v8_runtime::session::{run_event_loop, EventLoopStatus, SessionCommand}; -use std::thread; -use std::thread::JoinHandle; -use std::time::{Duration, Instant}; - -const WASM_FORTY_TWO_BYTES: &str = "0,97,115,109,1,0,0,0,1,5,1,96,0,1,127,3,2,1,0,7,12,1,8,102,111,114,116,121,84,119,111,0,0,10,6,1,4,0,65,42,11"; -const EVENT_LOOP_WATCHDOG_TIMEOUT: Duration = Duration::from_secs(6); - -// Timing-sensitive assertions flake under the CPU contention of a parallel test -// run (see CLAUDE.md > Testing). Gated off by default; the nightly timing lane -// sets SECURE_EXEC_RUN_TIMING_TESTS=1 to enforce them. -fn run_timing_sensitive_tests() -> bool { - std::env::var_os("SECURE_EXEC_RUN_TIMING_TESTS").is_some() -} - -struct EventLoopWatchdog { - cancel_tx: Option>, - join_handle: Option>, -} - -impl EventLoopWatchdog { - fn start() -> (Self, Receiver<()>) { - let (abort_tx, abort_rx) = crossbeam_channel::bounded::<()>(0); - let (cancel_tx, cancel_rx) = crossbeam_channel::bounded::<()>(0); - let join_handle = thread::Builder::new() - .name("event-loop-test-watchdog".into()) - .spawn(move || { - crossbeam_channel::select! { - recv(cancel_rx) -> _ => {} - default(EVENT_LOOP_WATCHDOG_TIMEOUT) => { - drop(abort_tx); - } - } - }) - .expect("watchdog thread should start"); - - ( - Self { - cancel_tx: Some(cancel_tx), - join_handle: Some(join_handle), - }, - abort_rx, - ) - } - - fn cancel(mut self) { - self.cancel_tx.take(); - if let Some(join_handle) = self.join_handle.take() { - join_handle.join().expect("watchdog thread should join"); - } - } -} - -impl Drop for EventLoopWatchdog { - fn drop(&mut self) { - self.cancel_tx.take(); - if let Some(join_handle) = self.join_handle.take() { - join_handle.join().expect("watchdog thread should join"); - } - } -} - -fn run_event_loop_with_watchdog( - scope: &mut v8::HandleScope, - rx: &Receiver, - pending: &PendingPromises, -) -> EventLoopStatus { - let (watchdog, abort_rx) = EventLoopWatchdog::start(); - let status = run_event_loop(scope, rx, pending, Some(&abort_rx), None); - watchdog.cancel(); - status -} - -fn assert_event_loop_watchdog_did_not_fire(status: &EventLoopStatus) { - assert!( - !matches!(status, EventLoopStatus::Terminated), - "event loop watchdog fired after {:?}", - EVENT_LOOP_WATCHDOG_TIMEOUT - ); -} - -fn event_loop_pumps_v8_platform_tasks_for_native_wasm_promises() { - isolate::init_v8_platform(); - - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let pending = PendingPromises::new(); - let (_tx, rx) = crossbeam_channel::unbounded::(); - let mut bridge_cache = None; - - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - - let (code, error) = execution::execute_script( - scope, - "", - "globalThis.__wasmDone = false; \ - (async () => { \ - await WebAssembly.compile(new Uint8Array([0,97,115,109,1,0,0,0])); \ - globalThis.__wasmDone = true; \ - })();", - &mut bridge_cache, - ); - assert_eq!(code, 0, "unexpected execute_script exit code"); - assert!( - error.is_none(), - "unexpected execute_script error: {error:?}" - ); - assert!( - execution::has_pending_script_evaluation(), - "expected pending script evaluation for native wasm promise" - ); - - let status = run_event_loop_with_watchdog(scope, &rx, &pending); - assert_event_loop_watchdog_did_not_fire(&status); - assert!( - matches!(status, EventLoopStatus::Completed), - "unexpected event loop status: {:?}", - status - ); - - if let Some((next_code, next_error)) = execution::finalize_pending_script_evaluation(scope) { - assert_eq!(next_code, 0, "unexpected finalize exit code"); - assert!( - next_error.is_none(), - "unexpected finalize error: {next_error:?}" - ); - } - - let source = v8::String::new(scope, "globalThis.__wasmDone === true").unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - assert!( - result.boolean_value(scope), - "expected wasm promise to resolve" - ); -} - -fn event_loop_completes_native_async_wasm_instantiate_promises() { - isolate::init_v8_platform(); - - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let pending = PendingPromises::new(); - let (_tx, rx) = crossbeam_channel::unbounded::(); - let mut bridge_cache = None; - - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - - let source = format!( - "globalThis.__wasmInstantiateResult = null; \ - (async () => {{ \ - const bytes = new Uint8Array([{bytes}]); \ - const result = await WebAssembly.instantiate(bytes, {{}}); \ - globalThis.__wasmInstantiateResult = {{ \ - hasModule: !!result?.module, \ - hasInstance: !!result?.instance, \ - value: result.instance.exports.fortyTwo(), \ - }}; \ - }})();", - bytes = WASM_FORTY_TWO_BYTES - ); - - let (code, error) = execution::execute_script(scope, "", &source, &mut bridge_cache); - assert_eq!(code, 0, "unexpected execute_script exit code"); - assert!( - error.is_none(), - "unexpected execute_script error: {error:?}" - ); - assert!( - execution::has_pending_script_evaluation(), - "expected pending script evaluation for native wasm instantiate promise" - ); - - let status = run_event_loop_with_watchdog(scope, &rx, &pending); - assert_event_loop_watchdog_did_not_fire(&status); - assert!( - matches!(status, EventLoopStatus::Completed), - "unexpected event loop status: {:?}", - status - ); - - if let Some((next_code, next_error)) = execution::finalize_pending_script_evaluation(scope) { - assert_eq!(next_code, 0, "unexpected finalize exit code"); - assert!( - next_error.is_none(), - "unexpected finalize error: {next_error:?}" - ); - } - - let source = v8::String::new( - scope, - "globalThis.__wasmInstantiateResult?.hasModule === true && \ - globalThis.__wasmInstantiateResult?.hasInstance === true && \ - globalThis.__wasmInstantiateResult?.value === 42", - ) - .unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - assert!( - result.boolean_value(scope), - "expected async WebAssembly.instantiate() to resolve with module+instance" - ); -} - -fn event_loop_surfaces_native_async_wasm_compile_errors_without_hanging() { - isolate::init_v8_platform(); - - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let pending = PendingPromises::new(); - let (_tx, rx) = crossbeam_channel::unbounded::(); - let mut bridge_cache = None; - - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - - let (code, error) = execution::execute_script( - scope, - "", - "globalThis.__wasmCompileErrorName = null; \ - (async () => { \ - try { \ - await WebAssembly.instantiate(new Uint8Array([0,97,115,109,1,0,0]), {}); \ - } catch (error) { \ - globalThis.__wasmCompileErrorName = error?.constructor?.name ?? null; \ - throw error; \ - } \ - })();", - &mut bridge_cache, - ); - assert_eq!(code, 0, "unexpected execute_script exit code"); - assert!( - error.is_none(), - "unexpected execute_script error: {error:?}" - ); - assert!( - execution::has_pending_script_evaluation(), - "expected pending script evaluation for native wasm instantiate rejection" - ); - - let status = run_event_loop_with_watchdog(scope, &rx, &pending); - assert_event_loop_watchdog_did_not_fire(&status); - assert!( - matches!(status, EventLoopStatus::Completed), - "unexpected event loop status: {:?}", - status - ); - - let (next_code, next_error) = execution::finalize_pending_script_evaluation(scope) - .expect("expected rejected async wasm instantiate promise"); - assert_eq!(next_code, 1, "unexpected finalize exit code"); - let next_error = next_error.expect("expected compile error"); - assert_eq!(next_error.error_type, "CompileError"); - - let source = v8::String::new( - scope, - "globalThis.__wasmCompileErrorName === 'CompileError'", - ) - .unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - assert!( - result.boolean_value(scope), - "expected async WebAssembly.instantiate() rejection to surface CompileError" - ); -} - -fn event_loop_waits_for_refed_guest_timers_between_interval_ticks() { - isolate::init_v8_platform(); - - let mut isolate = isolate::create_isolate(None); - let context = isolate::create_context(&mut isolate); - let pending = PendingPromises::new(); - let (tx, rx) = crossbeam_channel::unbounded::(); - let mut bridge_cache = None; - - let scope = &mut v8::HandleScope::new(&mut isolate); - let ctx = v8::Local::new(scope, &context); - let scope = &mut v8::ContextScope::new(scope, ctx); - - let (code, error) = execution::execute_script( - scope, - "", - "globalThis.__intervalTicks = 0; \ - globalThis.__pendingTimers = 1; \ - globalThis._getPendingTimerCount = () => globalThis.__pendingTimers; \ - globalThis._timerDispatch = () => { \ - globalThis.__intervalTicks += 1; \ - if (globalThis.__intervalTicks >= 4) { \ - globalThis.__pendingTimers = 0; \ - } \ - };", - &mut bridge_cache, - ); - assert_eq!(code, 0, "unexpected execute_script exit code"); - assert!( - error.is_none(), - "unexpected execute_script error: {error:?}" - ); - - let timer_thread = thread::spawn(move || { - for _ in 0..4 { - thread::sleep(Duration::from_millis(500)); - tx.send(SessionCommand::Message(SessionMessage::StreamEvent( - StreamEvent { - event_type: "timer".into(), - payload: Vec::new(), - }, - ))) - .unwrap(); - } - }); - - let started = Instant::now(); - let status = run_event_loop_with_watchdog(scope, &rx, &pending); - let elapsed = started.elapsed(); - - timer_thread.join().unwrap(); - - assert_event_loop_watchdog_did_not_fire(&status); - assert!( - matches!(status, EventLoopStatus::Completed), - "unexpected event loop status: {:?}", - status - ); - assert!( - elapsed >= Duration::from_millis(1900), - "event loop exited before four 500ms timer ticks elapsed: {:?}", - elapsed - ); - if run_timing_sensitive_tests() { - assert!( - elapsed < Duration::from_secs(5), - "event loop did not exit promptly after timers drained: {:?}", - elapsed - ); - } - - let source = v8::String::new( - scope, - "globalThis.__intervalTicks === 4 && globalThis.__pendingTimers === 0", - ) - .unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - let result = script.run(scope).unwrap(); - assert!( - result.boolean_value(scope), - "expected timer-backed event loop to stay alive until the fourth tick" - ); -} - -#[test] -fn event_loop_handles_native_async_wasm_paths_without_hanging() { - // Keep the async WASM event-loop coverage inside one top-level libtest case. - // Splitting these into separate tests in the same binary still trips the - // V8 init/teardown SIGSEGV boundary that affects other consolidated suites. - event_loop_pumps_v8_platform_tasks_for_native_wasm_promises(); - event_loop_completes_native_async_wasm_instantiate_promises(); - event_loop_surfaces_native_async_wasm_compile_errors_without_hanging(); - event_loop_waits_for_refed_guest_timers_between_interval_ticks(); -} diff --git a/crates/v8-runtime/tests/snapshot.rs b/crates/v8-runtime/tests/snapshot.rs deleted file mode 100644 index 84d2d5b21..000000000 --- a/crates/v8-runtime/tests/snapshot.rs +++ /dev/null @@ -1,6 +0,0 @@ -use secure_exec_v8_runtime::snapshot::run_snapshot_consolidated_checks; - -#[test] -fn snapshot_consolidated_tests() { - run_snapshot_consolidated_checks(); -} diff --git a/crates/vfs-core/Cargo.toml b/crates/vfs-core/Cargo.toml new file mode 100644 index 000000000..1e16b8725 --- /dev/null +++ b/crates/vfs-core/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "secure-exec-vfs-core" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +description = "secure-exec-vfs-core compatibility shim for agentos-vfs-core" + +[lib] +name = "secure_exec_vfs_core" + +[dependencies] +vfs = { package = "agentos-vfs-core", path = "../../../agentos/crates/vfs", version = "0.0.1" } diff --git a/crates/vfs-core/src/lib.rs b/crates/vfs-core/src/lib.rs new file mode 100644 index 000000000..a4bba17ab --- /dev/null +++ b/crates/vfs-core/src/lib.rs @@ -0,0 +1,3 @@ +//! Compatibility shim for `agentos-vfs-core`. + +pub use vfs::*; diff --git a/crates/vfs/AGENTS.md b/crates/vfs/AGENTS.md deleted file mode 120000 index 681311eb9..000000000 --- a/crates/vfs/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/crates/vfs/CLAUDE.md b/crates/vfs/CLAUDE.md deleted file mode 100644 index b36abbf79..000000000 --- a/crates/vfs/CLAUDE.md +++ /dev/null @@ -1,8 +0,0 @@ -# vfs - -- `vfs` is generic filesystem infrastructure only. Do not add secure-exec sidecar, bridge, S3, SQLite, host-disk, or registry coupling here. -- The crate intentionally contains separate filesystem type universes under explicit modules while the consolidation is in progress. Do not glob-merge names that would confuse those boundaries. -- Concrete environment-bound backends belong in `secure-exec-vfs`. -- The `chunked` engine deliberately decouples the `MetadataStore` from the `BlockStore`: blocks are content-addressed, opaque, and self-describing only as a set, while the directory tree, inode table, chunk map, and refcounts live entirely in the metadata store. The engine makes **no self-containment promise** about either half. Pairing a block store with a metadata store, and ensuring the metadata store is durable and co-located with whatever lifecycle the blocks need, is the **caller's responsibility** (the sidecar plugin / client config that wires the backends), not the engine's. So e.g. an `S3BlockStore` backed by a local `SqliteMetadataStore` is a valid, intended configuration; the engine does not assume blocks carry enough information to reconstruct the tree, and "the metadata lives elsewhere than the blocks" is by design, not a defect. If a deployment needs the tree to survive loss of the local metadata, it must choose a durable metadata store (e.g. the callback backend) — that is a wiring decision, not an engine concern. -- The engine data plane (`chunked`/`object` engines, `MetadataStore`/`BlockStore`/`ObjectBackend` impls, `CachedMetadataStore`, and the `MountedEngineFileSystem` adapter) assumes **single-writer semantics**: one writer owns a given filesystem/mount at a time. Block refcounting, cache invalidation, and read-modify-write chunk edits are correct only under that assumption. There is no cross-process coordination, locking, or conflict resolution; concurrent writers against the same metadata/block backing store (e.g. two sidecars sharing one S3 prefix + SQLite file, or a shared callback store) can corrupt refcounts and orphan or double-free blocks. Do not rely on these engines for multi-writer/shared-storage scenarios without adding an external coordination layer. -- `MetadataStore::snapshot`/`fork` are intentionally not production-GC-ready yet. There is no snapshot deletion API, so snapshot-pinned block refs are permanent for now. Do not wire snapshot/fork into plugins that need block reclamation until snapshot lifecycle and persistent snapshot rows are implemented. diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index 56e87f943..54ecf2de6 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -1,32 +1,13 @@ [package] -name = "secure-exec-vfs-core" +name = "secure-exec-vfs" version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Generic async virtual filesystem primitives" +description = "secure-exec-vfs compatibility shim for agentos-vfs" -# Published as `secure-exec-vfs-core`, but the lib is named `vfs` so the -# workspace-wide `vfs = { package = "secure-exec-vfs-core" }` alias and this -# crate's own `tests/*.rs` (`use vfs::...`) resolve it by that name. [lib] -name = "vfs" +name = "secure_exec_vfs" [dependencies] -async-trait = "0.1" -base64 = "0.22" -blake3 = "1" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -# Drop-in std::time replacement: re-exports std on native, uses js_sys::Date / -# performance.now() on wasm32 (where std SystemTime/Instant abort). -web-time = "1.1" - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -memmap2 = "0.9" -tar = "0.4" -tokio = { version = "1", features = ["rt", "rt-multi-thread"] } -tracing = "0.1" - -[dev-dependencies] -tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] } +agentos_vfs = { package = "agentos-vfs", path = "../../../agentos/crates/vfs-store", version = "0.0.1" } diff --git a/crates/vfs/assets/base-filesystem.json b/crates/vfs/assets/base-filesystem.json deleted file mode 100644 index 64e03bfa5..000000000 --- a/crates/vfs/assets/base-filesystem.json +++ /dev/null @@ -1,536 +0,0 @@ -{ - "source": { - "snapshotPath": "alpine-defaults.json", - "image": "alpine:3.22", - "snapshotCreatedAt": "2026-06-22T19:45:20.529Z", - "builtAt": "2026-06-23T03:47:12.644Z", - "transforms": [ - "Normalize HOSTNAME to secure-exec", - "Preserve the captured user-level environment and filesystem layout as the secure-exec base layer", - "Add the non-Alpine /workspace directory (default agent working directory) owned by the base user" - ] - }, - "environment": { - "env": { - "CHARSET": "UTF-8", - "HOME": "/home/agentos", - "HOSTNAME": "secure-exec", - "LANG": "C.UTF-8", - "LC_COLLATE": "C", - "LOGNAME": "agentos", - "PAGER": "less", - "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "SHELL": "/bin/sh", - "USER": "agentos" - }, - "prompt": "\\h:\\w\\$ " - }, - "filesystem": { - "entries": [ - { - "path": "/", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/bin", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/alpine-release", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "3.22.4\n" - }, - { - "path": "/etc/apk", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/busybox-paths.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/crontabs", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/group", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "root:x:0:root\nbin:x:1:root,bin,daemon\ndaemon:x:2:root,bin,daemon\nsys:x:3:root,bin\nadm:x:4:root,daemon\ntty:x:5:\ndisk:x:6:root\nlp:x:7:lp\nkmem:x:9:\nwheel:x:10:root\nfloppy:x:11:root\nmail:x:12:mail\nnews:x:13:news\nuucp:x:14:uucp\ncron:x:16:cron\naudio:x:18:\ncdrom:x:19:\ndialout:x:20:root\nftp:x:21:\nsshd:x:22:\ninput:x:23:\ntape:x:26:root\nvideo:x:27:root\nnetdev:x:28:\nkvm:x:34:kvm\ngames:x:35:\nshadow:x:42:\nwww-data:x:82:\nusers:x:100:games\nntp:x:123:\nabuild:x:300:\nutmp:x:406:\nping:x:999:\nnogroup:x:65533:\nnobody:x:65534:\nagentos:x:1000:\n" - }, - { - "path": "/etc/hostname", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "secure-exec\n" - }, - { - "path": "/etc/logrotate.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/modprobe.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/modules-load.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/network", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/nsswitch.conf", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "# musl itself does not support NSS, however some third-party DNS\n# implementations use the nsswitch.conf file to determine what\n# policy to follow.\n# Editing this file is not recommended.\nhosts: files dns\n" - }, - { - "path": "/etc/opt", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/os-release", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "../usr/lib/os-release" - }, - { - "path": "/etc/passwd", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "root:x:0:0:root:/root:/bin/sh\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\nlp:x:4:7:lp:/var/spool/lpd:/sbin/nologin\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/mail:/sbin/nologin\nnews:x:9:13:news:/usr/lib/news:/sbin/nologin\nuucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin\ncron:x:16:16:cron:/var/spool/cron:/sbin/nologin\nftp:x:21:21::/var/lib/ftp:/sbin/nologin\nsshd:x:22:22:sshd:/dev/null:/sbin/nologin\ngames:x:35:35:games:/usr/games:/sbin/nologin\nntp:x:123:123:NTP:/var/empty:/sbin/nologin\nguest:x:405:100:guest:/dev/null:/sbin/nologin\nnobody:x:65534:65534:nobody:/:/sbin/nologin\nagentos:x:1000:1000::/home/agentos:/bin/sh\n" - }, - { - "path": "/etc/periodic", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/profile", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "export PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\nexport PAGER=less\numask 022\n\n# use nicer PS1 for bash and busybox ash\nif [ -n \"$BASH_VERSION\" -o \"$BB_ASH_VERSION\" ]; then\n\tPS1='\\h:\\w\\$ '\n# use nicer PS1 for zsh\nelif [ -n \"$ZSH_VERSION\" ]; then\n\tPS1='%m:%~%# '\n# set up fallback default PS1\nelse\n\t: \"${HOSTNAME:=$(hostname)}\"\n\tPS1='${HOSTNAME%%.*}:$PWD'\n\t[ \"$(id -u)\" -eq 0 ] && PS1=\"${PS1}# \" || PS1=\"${PS1}\\$ \"\nfi\n\nfor script in /etc/profile.d/*.sh ; do\n\tif [ -r \"$script\" ] ; then\n\t\t. \"$script\"\n\tfi\ndone\nunset script\n" - }, - { - "path": "/etc/profile.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/secfixes.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/shadow", - "type": "file", - "mode": "640", - "uid": 0, - "gid": 42, - "content": "root:*::0:::::\nbin:!::0:::::\ndaemon:!::0:::::\nlp:!::0:::::\nsync:!::0:::::\nshutdown:!::0:::::\nhalt:!::0:::::\nmail:!::0:::::\nnews:!::0:::::\nuucp:!::0:::::\ncron:!::0:::::\nftp:!::0:::::\nsshd:!::0:::::\ngames:!::0:::::\nntp:!::0:::::\nguest:!::0:::::\nnobody:!::0:::::\nagentos:!:20626:0:99999:7:::\n" - }, - { - "path": "/etc/shells", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "# valid login shells\n/bin/sh\n/bin/ash\n" - }, - { - "path": "/etc/ssl", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/ssl1.1", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/sysctl.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/etc/udhcpc", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/home", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/home/agentos", - "type": "directory", - "mode": "2755", - "uid": 1000, - "gid": 1000 - }, - { - "path": "/lib", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/lib/apk", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/lib/firmware", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/lib/modules-load.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/lib/sysctl.d", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/media", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/media/cdrom", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/media/floppy", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/media/usb", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/mnt", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/opt", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/root", - "type": "directory", - "mode": "700", - "uid": 0, - "gid": 0 - }, - { - "path": "/run", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/run/lock", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/sbin", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/srv", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/sys", - "type": "directory", - "mode": "555", - "uid": 0, - "gid": 0 - }, - { - "path": "/tmp", - "type": "directory", - "mode": "1777", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/bin", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/bin/env", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "/bin/busybox" - }, - { - "path": "/usr/lib", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/lib/os-release", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "NAME=\"Alpine Linux\"\nID=alpine\nVERSION_ID=3.22.4\nPRETTY_NAME=\"Alpine Linux v3.22\"\nHOME_URL=\"https://alpinelinux.org/\"\nBUG_REPORT_URL=\"https://gitlab.alpinelinux.org/alpine/aports/-/issues\"\n" - }, - { - "path": "/usr/local", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/sbin", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/usr/share", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/cache", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/empty", - "type": "directory", - "mode": "555", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/lib", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/local", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/lock", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "../run/lock" - }, - { - "path": "/var/log", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/mail", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/opt", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/run", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "../run" - }, - { - "path": "/var/spool", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/spool/cron", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/var/spool/cron/crontabs", - "type": "symlink", - "mode": "777", - "uid": 0, - "gid": 0, - "target": "../../../etc/crontabs" - }, - { - "path": "/var/tmp", - "type": "directory", - "mode": "1777", - "uid": 0, - "gid": 0 - }, - { - "path": "/workspace", - "type": "directory", - "mode": "755", - "uid": 1000, - "gid": 1000 - } - ] - } -} diff --git a/crates/vfs/build.rs b/crates/vfs/build.rs deleted file mode 100644 index 955b501ed..000000000 --- a/crates/vfs/build.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::{env, fs, path::PathBuf}; - -// Stage the base filesystem fixture into OUT_DIR. In-tree builds use the -// canonical secure-exec package fixture from the current workspace; the -// published crate falls back to the vendored `assets/base-filesystem.json` copy. -fn main() { - let manifest_dir = - PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set")); - let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR must be set")); - - println!("cargo:rerun-if-changed=build.rs"); - - let workspace_fixtures = [ - manifest_dir.join("../../packages/secure-exec-core/fixtures/base-filesystem.json"), - manifest_dir.join("../../packages/core/fixtures/base-filesystem.json"), - ]; - let vendored = manifest_dir.join("assets/base-filesystem.json"); - let src = workspace_fixtures - .into_iter() - .find(|fixture| fixture.exists()) - .unwrap_or(vendored); - - println!("cargo:rerun-if-changed={}", src.display()); - - let dest = out_dir.join("base-filesystem.json"); - fs::copy(&src, &dest).unwrap_or_else(|error| { - panic!( - "failed to stage base-filesystem.json from {} to {}: {}", - src.display(), - dest.display(), - error - ) - }); -} diff --git a/crates/vfs/src/adapter/mod.rs b/crates/vfs/src/adapter/mod.rs deleted file mode 100644 index a3942ebb7..000000000 --- a/crates/vfs/src/adapter/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod mounted_fs; - -pub use mounted_fs::MountedEngineFileSystem; diff --git a/crates/vfs/src/adapter/mounted_fs.rs b/crates/vfs/src/adapter/mounted_fs.rs deleted file mode 100644 index 42d396d4b..000000000 --- a/crates/vfs/src/adapter/mounted_fs.rs +++ /dev/null @@ -1,287 +0,0 @@ -use crate::posix::{ - MountedFileSystem, VfsError as PosixVfsError, VfsResult as PosixVfsResult, VirtualDirEntry, - VirtualStat, -}; -use std::any::Any; -use std::sync::atomic::{AtomicU64, Ordering}; -use tokio::runtime::{Builder, Runtime}; - -static NEXT_ENGINE_DEVICE_ID: AtomicU64 = AtomicU64::new(4096); - -pub struct MountedEngineFileSystem { - inner: F, - runtime: Runtime, - device_id: u64, -} - -impl MountedEngineFileSystem { - pub fn new(inner: F) -> PosixVfsResult { - Ok(Self { - inner, - runtime: Builder::new_current_thread() - .enable_all() - .build() - .map_err(|error| { - PosixVfsError::io(format!("create vfs engine runtime: {error}")) - })?, - device_id: NEXT_ENGINE_DEVICE_ID.fetch_add(1, Ordering::Relaxed), - }) - } - - fn block_on( - &self, - future: impl std::future::Future>, - ) -> PosixVfsResult { - self.runtime.block_on(future).map_err(convert_error) - } -} - -impl MountedFileSystem for MountedEngineFileSystem -where - F: crate::engine::VirtualFileSystem + 'static, -{ - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } - - fn read_file(&mut self, path: &str) -> PosixVfsResult> { - self.block_on(self.inner.read_file(path)) - } - - fn read_dir(&mut self, path: &str) -> PosixVfsResult> { - self.block_on(self.inner.read_dir(path)) - } - - fn read_dir_with_types(&mut self, path: &str) -> PosixVfsResult> { - self.block_on(self.inner.read_dir_with_types(path)) - .map(|entries| { - entries - .into_iter() - .map(|entry| VirtualDirEntry { - name: entry.name, - is_directory: entry.kind == crate::engine::InodeType::Directory, - is_symbolic_link: entry.kind == crate::engine::InodeType::Symlink, - }) - .collect() - }) - } - - fn write_file(&mut self, path: &str, content: Vec) -> PosixVfsResult<()> { - self.block_on(self.inner.write_file(path, &content)) - } - - fn write_file_with_mode( - &mut self, - path: &str, - content: Vec, - mode: Option, - ) -> PosixVfsResult<()> { - self.write_file(path, content)?; - if let Some(mode) = mode { - self.chmod(path, mode)?; - } - Ok(()) - } - - fn create_file_exclusive(&mut self, path: &str, content: Vec) -> PosixVfsResult<()> { - if self.exists(path) { - return Err(PosixVfsError::new( - "EEXIST", - format!("file already exists, open '{path}'"), - )); - } - self.write_file(path, content) - } - - fn create_file_exclusive_with_mode( - &mut self, - path: &str, - content: Vec, - mode: Option, - ) -> PosixVfsResult<()> { - self.create_file_exclusive(path, content)?; - if let Some(mode) = mode { - self.chmod(path, mode)?; - } - Ok(()) - } - - fn append_file(&mut self, path: &str, content: Vec) -> PosixVfsResult { - self.block_on(self.inner.append(path, &content)) - } - - fn create_dir(&mut self, path: &str) -> PosixVfsResult<()> { - self.block_on(self.inner.create_dir(path)) - } - - fn create_dir_with_mode(&mut self, path: &str, mode: Option) -> PosixVfsResult<()> { - self.create_dir(path)?; - if let Some(mode) = mode { - self.chmod(path, mode)?; - } - Ok(()) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> PosixVfsResult<()> { - self.block_on(self.inner.mkdir(path, recursive)) - } - - fn mkdir_with_mode( - &mut self, - path: &str, - recursive: bool, - mode: Option, - ) -> PosixVfsResult<()> { - self.mkdir(path, recursive)?; - if let Some(mode) = mode { - self.chmod(path, mode)?; - } - Ok(()) - } - - fn exists(&self, path: &str) -> bool { - self.runtime.block_on(self.inner.exists(path)) - } - - fn stat(&mut self, path: &str) -> PosixVfsResult { - let stat = self.block_on(self.inner.stat(path))?; - Ok(convert_stat(stat, self.device_id)) - } - - fn remove_file(&mut self, path: &str) -> PosixVfsResult<()> { - self.block_on(self.inner.remove_file(path)) - } - - fn remove_dir(&mut self, path: &str) -> PosixVfsResult<()> { - self.block_on(self.inner.remove_dir(path)) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> PosixVfsResult<()> { - self.block_on(self.inner.rename(old_path, new_path)) - } - - fn realpath(&self, path: &str) -> PosixVfsResult { - self.block_on(self.inner.realpath(path)) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> PosixVfsResult<()> { - self.block_on(self.inner.symlink(target, link_path)) - } - - fn read_link(&self, path: &str) -> PosixVfsResult { - self.block_on(self.inner.readlink(path)) - } - - fn lstat(&self, path: &str) -> PosixVfsResult { - let stat = self.block_on(self.inner.lstat(path))?; - Ok(convert_stat(stat, self.device_id)) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> PosixVfsResult<()> { - self.block_on(self.inner.link(old_path, new_path)) - } - - fn chmod(&mut self, path: &str, mode: u32) -> PosixVfsResult<()> { - self.block_on(self.inner.chmod(path, mode)) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> PosixVfsResult<()> { - self.block_on(self.inner.chown(path, uid, gid)) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> PosixVfsResult<()> { - self.block_on(self.inner.utimes(path, atime_ms, mtime_ms)) - } - - fn truncate(&mut self, path: &str, length: u64) -> PosixVfsResult<()> { - self.block_on(self.inner.truncate(path, length)) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> PosixVfsResult> { - self.block_on(self.inner.pread(path, offset, length)) - } -} - -fn convert_error(error: crate::engine::VfsError) -> PosixVfsError { - PosixVfsError::new(error.code(), error.message().to_owned()) -} - -fn convert_stat(stat: crate::engine::VirtualStat, device_id: u64) -> VirtualStat { - VirtualStat { - mode: stat.mode, - size: stat.size, - blocks: stat.blocks, - dev: device_id, - rdev: 0, - is_directory: stat.is_directory, - is_symbolic_link: stat.is_symbolic_link, - atime_ms: timespec_ms(stat.atime), - atime_nsec: stat.atime.nsec, - mtime_ms: timespec_ms(stat.mtime), - mtime_nsec: stat.mtime.nsec, - ctime_ms: timespec_ms(stat.ctime), - ctime_nsec: stat.ctime.nsec, - birthtime_ms: timespec_ms(stat.birthtime), - ino: stat.ino, - nlink: stat.nlink, - uid: stat.uid, - gid: stat.gid, - } -} - -fn timespec_ms(time: crate::engine::Timespec) -> u64 { - if time.sec < 0 { - return 0; - } - (time.sec as u64).saturating_mul(1_000) + u64::from(time.nsec / 1_000_000) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::engine::engines::{ChunkedFs, ChunkedFsOptions}; - use crate::engine::mem::{InMemoryMetadataStore, MemoryBlockStore}; - use crate::posix::S_IFREG; - - #[test] - fn mounted_engine_filesystem_bridges_sync_posix_calls() { - let fs = ChunkedFs::with_options( - InMemoryMetadataStore::new(), - MemoryBlockStore::new(), - ChunkedFsOptions { - inline_threshold: 2, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - let mut mounted = MountedEngineFileSystem::new(fs).expect("create mounted engine fs"); - - mounted - .mkdir("/work/nested", true) - .expect("create nested dir"); - mounted - .write_file_with_mode("/work/nested/file.txt", b"hello".to_vec(), Some(0o600)) - .expect("write file"); - assert_eq!( - mounted - .pread("/work/nested/file.txt", 1, 3) - .expect("pread file"), - b"ell" - ); - let entries = mounted - .read_dir_with_types("/work/nested") - .expect("read typed dir"); - assert_eq!(entries.len(), 1); - assert_eq!(entries[0].name, "file.txt"); - assert!(!entries[0].is_directory); - - let stat = mounted.stat("/work/nested/file.txt").expect("stat file"); - assert_eq!(stat.mode & 0o777, 0o600); - assert_eq!(stat.mode & S_IFREG, S_IFREG); - assert_eq!(stat.size, 5); - } -} diff --git a/crates/vfs/src/engine/block.rs b/crates/vfs/src/engine/block.rs deleted file mode 100644 index 6b88eaac2..000000000 --- a/crates/vfs/src/engine/block.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::engine::error::VfsResult; -use crate::engine::types::{BlockKey, ObjectEntry, ObjectMeta}; -use async_trait::async_trait; - -#[async_trait] -pub trait BlockStore: Send + Sync { - async fn get(&self, key: &BlockKey) -> VfsResult>; - async fn get_range(&self, key: &BlockKey, off: u64, len: u64) -> VfsResult>; - async fn put(&self, key: &BlockKey, data: &[u8]) -> VfsResult<()>; - async fn exists(&self, key: &BlockKey) -> VfsResult; - async fn delete_many(&self, keys: &[BlockKey]) -> VfsResult<()>; - async fn copy(&self, src: &BlockKey, dst: &BlockKey) -> VfsResult<()>; -} - -#[async_trait] -pub trait ObjectBackend: Send + Sync { - async fn list(&self, prefix: &str) -> VfsResult>; - async fn head(&self, key: &str) -> VfsResult>; - async fn get_range(&self, key: &str, off: u64, len: u64) -> VfsResult>; - async fn put(&self, key: &str, data: &[u8], meta: ObjectMeta) -> VfsResult<()>; - async fn copy(&self, src: &str, dst: &str) -> VfsResult<()>; - async fn delete(&self, key: &str) -> VfsResult<()>; -} diff --git a/crates/vfs/src/engine/cache.rs b/crates/vfs/src/engine/cache.rs deleted file mode 100644 index bf051d99b..000000000 --- a/crates/vfs/src/engine/cache.rs +++ /dev/null @@ -1,214 +0,0 @@ -use crate::engine::error::VfsResult; -use crate::engine::metadata::MetadataStore; -use crate::engine::types::{ - BlockKey, ChunkEdit, ChunkRange, ChunkRef, CreateInodeAttrs, DentryStat, InodeMeta, InodePatch, - SnapshotId, -}; -use async_trait::async_trait; -use std::collections::{BTreeMap, VecDeque}; -use std::sync::Mutex; - -pub struct CachedMetadataStore { - inner: M, - cache: Mutex, -} - -#[derive(Debug)] -struct CacheState { - capacity: usize, - generation: u64, - resolve: BTreeMap>, - lstat: BTreeMap>, - list_dir: BTreeMap>, - order: VecDeque, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum CacheKey { - Resolve(String), - Lstat(String), - ListDir(u64), -} - -impl CachedMetadataStore { - pub fn new(inner: M, capacity: usize) -> Self { - Self { - inner, - cache: Mutex::new(CacheState { - capacity, - generation: 0, - resolve: BTreeMap::new(), - lstat: BTreeMap::new(), - list_dir: BTreeMap::new(), - order: VecDeque::new(), - }), - } - } - - pub fn into_inner(self) -> M { - self.inner - } - - fn clear_after_mutation(&self) { - let mut cache = self.cache.lock().expect("cache mutex poisoned"); - cache.generation = cache.generation.wrapping_add(1); - cache.resolve.clear(); - cache.lstat.clear(); - cache.list_dir.clear(); - cache.order.clear(); - } -} - -impl CacheState { - fn remember(&mut self, key: CacheKey) { - if self.capacity == 0 { - self.resolve.clear(); - self.lstat.clear(); - self.list_dir.clear(); - self.order.clear(); - return; - } - self.order.push_back(key); - while self.order.len() > self.capacity { - if let Some(evicted) = self.order.pop_front() { - match evicted { - CacheKey::Resolve(path) => { - self.resolve.remove(&path); - } - CacheKey::Lstat(path) => { - self.lstat.remove(&path); - } - CacheKey::ListDir(ino) => { - self.list_dir.remove(&ino); - } - } - } - } - } -} - -#[async_trait] -impl MetadataStore for CachedMetadataStore { - async fn resolve(&self, path: &str) -> VfsResult { - let generation = { - let cache = self.cache.lock().expect("cache mutex poisoned"); - if let Some(cached) = cache.resolve.get(path).cloned() { - return cached.ok_or_else(|| crate::engine::error::VfsError::enoent(path)); - } - cache.generation - }; - let result = self.inner.resolve(path).await; - let mut cache = self.cache.lock().expect("cache mutex poisoned"); - if cache.generation == generation { - cache.resolve.insert(path.to_string(), result.clone().ok()); - cache.remember(CacheKey::Resolve(path.to_string())); - } - result - } - - async fn resolve_parent(&self, path: &str) -> VfsResult<(InodeMeta, String)> { - self.inner.resolve_parent(path).await - } - - async fn lstat(&self, path: &str) -> VfsResult { - let generation = { - let cache = self.cache.lock().expect("cache mutex poisoned"); - if let Some(cached) = cache.lstat.get(path).cloned() { - return cached.ok_or_else(|| crate::engine::error::VfsError::enoent(path)); - } - cache.generation - }; - let result = self.inner.lstat(path).await; - let mut cache = self.cache.lock().expect("cache mutex poisoned"); - if cache.generation == generation { - cache.lstat.insert(path.to_string(), result.clone().ok()); - cache.remember(CacheKey::Lstat(path.to_string())); - } - result - } - - async fn list_dir(&self, ino: u64) -> VfsResult> { - let generation = { - let cache = self.cache.lock().expect("cache mutex poisoned"); - if let Some(cached) = cache.list_dir.get(&ino).cloned() { - return Ok(cached); - } - cache.generation - }; - let entries = self.inner.list_dir(ino).await?; - let mut cache = self.cache.lock().expect("cache mutex poisoned"); - if cache.generation == generation { - cache.list_dir.insert(ino, entries.clone()); - cache.remember(CacheKey::ListDir(ino)); - } - Ok(entries) - } - - async fn create( - &self, - parent: u64, - name: &str, - attrs: CreateInodeAttrs, - ) -> VfsResult { - let result = self.inner.create(parent, name, attrs).await; - self.clear_after_mutation(); - result - } - - async fn link(&self, parent: u64, name: &str, target: u64) -> VfsResult<()> { - let result = self.inner.link(parent, name, target).await; - self.clear_after_mutation(); - result - } - - async fn remove(&self, parent: u64, name: &str) -> VfsResult> { - let result = self.inner.remove(parent, name).await; - self.clear_after_mutation(); - result - } - - async fn rename( - &self, - src_parent: u64, - src: &str, - dst_parent: u64, - dst: &str, - ) -> VfsResult> { - let result = self.inner.rename(src_parent, src, dst_parent, dst).await; - self.clear_after_mutation(); - result - } - - async fn set_attr(&self, ino: u64, patch: InodePatch) -> VfsResult> { - let result = self.inner.set_attr(ino, patch).await; - self.clear_after_mutation(); - result - } - - async fn commit_write( - &self, - ino: u64, - edits: Vec, - new_size: u64, - ) -> VfsResult> { - let result = self.inner.commit_write(ino, edits, new_size).await; - self.clear_after_mutation(); - result - } - - async fn get_chunks(&self, ino: u64, range: ChunkRange) -> VfsResult> { - self.inner.get_chunks(ino, range).await - } - - async fn snapshot(&self, root: u64) -> VfsResult { - self.inner.snapshot(root).await - } - - async fn fork(&self, snap: SnapshotId) -> VfsResult { - self.inner.fork(snap).await - } - - async fn gc(&self) -> VfsResult> { - self.inner.gc().await - } -} diff --git a/crates/vfs/src/engine/engines/chunked.rs b/crates/vfs/src/engine/engines/chunked.rs deleted file mode 100644 index 15cee897a..000000000 --- a/crates/vfs/src/engine/engines/chunked.rs +++ /dev/null @@ -1,701 +0,0 @@ -use crate::engine::block::BlockStore; -use crate::engine::error::{VfsError, VfsResult}; -use crate::engine::metadata::MetadataStore; -use crate::engine::types::{ - normalize_path, BlockKey, ChunkEdit, ChunkRange, CreateInodeAttrs, Dentry, InodeMeta, - InodePatch, InodeType, SnapshotId, Storage, Timespec, VirtualStat, DEFAULT_CHUNK_SIZE, - DEFAULT_INLINE_THRESHOLD, -}; -use crate::engine::vfs::{Snapshottable, VirtualFileSystem}; -use async_trait::async_trait; -use std::collections::BTreeMap; - -#[derive(Debug, Clone)] -pub struct ChunkedFsOptions { - pub inline_threshold: usize, - pub chunk_size: u32, - pub uid: u32, - pub gid: u32, - pub file_mode: u32, - pub dir_mode: u32, -} - -impl Default for ChunkedFsOptions { - fn default() -> Self { - Self { - inline_threshold: DEFAULT_INLINE_THRESHOLD, - chunk_size: DEFAULT_CHUNK_SIZE, - uid: 0, - gid: 0, - file_mode: 0o644, - dir_mode: 0o755, - } - } -} - -#[derive(Debug, Clone)] -pub struct ChunkedFs { - metadata: M, - blocks: B, - options: ChunkedFsOptions, -} - -impl ChunkedFs { - pub fn new(metadata: M, blocks: B) -> Self { - Self::with_options(metadata, blocks, ChunkedFsOptions::default()) - } - - pub fn with_options(metadata: M, blocks: B, options: ChunkedFsOptions) -> Self { - Self { - metadata, - blocks, - options, - } - } - - pub fn metadata(&self) -> &M { - &self.metadata - } - - pub fn blocks(&self) -> &B { - &self.blocks - } -} - -impl ChunkedFs { - async fn write_existing_or_create(&self, path: &str, content: &[u8]) -> VfsResult<()> { - let (parent, name) = self.metadata.resolve_parent(path).await?; - let existing = self.metadata.lstat(path).await.ok(); - let ino = match existing { - Some(meta) => { - if meta.kind == InodeType::Directory { - return Err(VfsError::eisdir(path)); - } - meta.ino - } - None => { - let storage = if content.len() <= self.options.inline_threshold { - Storage::Inline(content.to_vec()) - } else { - Storage::Chunked { - chunk_size: self.options.chunk_size, - } - }; - let meta = self - .metadata - .create( - parent.ino, - &name, - CreateInodeAttrs::file( - self.options.file_mode, - self.options.uid, - self.options.gid, - storage, - ), - ) - .await?; - if content.len() <= self.options.inline_threshold { - return Ok(()); - } - meta.ino - } - }; - - if content.len() <= self.options.inline_threshold { - let freed = self - .metadata - .set_attr( - ino, - InodePatch { - storage: Some(Storage::Inline(content.to_vec())), - size: Some(content.len() as u64), - ..InodePatch::default() - }, - ) - .await?; - self.blocks.delete_many(&freed).await?; - return Ok(()); - } - - let mut edits = Vec::new(); - for (index, chunk) in content.chunks(self.options.chunk_size as usize).enumerate() { - let key = BlockKey::from_content(chunk); - if !self.blocks.exists(&key).await? { - self.blocks.put(&key, chunk).await?; - } - edits.push(ChunkEdit { - index: index as u64, - key, - len: chunk.len() as u32, - }); - } - self.metadata - .set_attr( - ino, - InodePatch { - storage: Some(Storage::Chunked { - chunk_size: self.options.chunk_size, - }), - size: Some(content.len() as u64), - ..InodePatch::default() - }, - ) - .await?; - let freed = self - .metadata - .commit_write(ino, edits, content.len() as u64) - .await?; - self.blocks.delete_many(&freed).await?; - Ok(()) - } - - fn file_chunk_size(&self, storage: &Storage) -> u32 { - match storage { - Storage::Chunked { chunk_size } => *chunk_size, - Storage::Inline(_) | Storage::None => self.options.chunk_size, - } - } - - fn ensure_file<'a>(&self, path: &str, meta: &'a InodeMeta) -> VfsResult<&'a InodeMeta> { - match meta.kind { - InodeType::File => Ok(meta), - InodeType::Directory => Err(VfsError::eisdir(path)), - InodeType::Symlink => Err(VfsError::eopnotsupp("resolved symlink without target file")), - } - } - - async fn read_file_range( - &self, - meta: &InodeMeta, - offset: u64, - length: usize, - ) -> VfsResult> { - if length == 0 || offset >= meta.size { - return Ok(Vec::new()); - } - let available = meta.size.saturating_sub(offset).min(length as u64); - let output_len = usize::try_from(available) - .map_err(|_| VfsError::einval(format!("range length is too large: {available}")))?; - - match &meta.storage { - Storage::Inline(data) => { - let start = usize::try_from(offset).map_err(|_| { - VfsError::einval(format!("range offset is too large: {offset}")) - })?; - if start >= data.len() { - return Ok(vec![0; output_len]); - } - let end = start.saturating_add(output_len).min(data.len()); - let mut output = vec![0; output_len]; - output[..end - start].copy_from_slice(&data[start..end]); - Ok(output) - } - Storage::None => Ok(vec![0; output_len]), - Storage::Chunked { chunk_size } => { - let chunk_size = u64::from(*chunk_size); - let end_offset = offset - .checked_add(available) - .ok_or_else(|| VfsError::einval("range end overflows"))?; - let start_index = offset / chunk_size; - let end_index = end_offset.div_ceil(chunk_size); - let chunks = self - .metadata - .get_chunks( - meta.ino, - ChunkRange { - start: start_index, - end: Some(end_index), - }, - ) - .await?; - let mut output = vec![0; output_len]; - for chunk in chunks { - let chunk_start = chunk.index.saturating_mul(chunk_size); - let block = self.blocks.get(&chunk.key).await?; - let copy_start = offset.max(chunk_start); - let copy_end = end_offset.min(chunk_start.saturating_add(block.len() as u64)); - if copy_start >= copy_end { - continue; - } - let output_start = usize::try_from(copy_start - offset) - .map_err(|_| VfsError::einval("range output offset is too large"))?; - let block_start = usize::try_from(copy_start - chunk_start) - .map_err(|_| VfsError::einval("range block offset is too large"))?; - let len = usize::try_from(copy_end - copy_start) - .map_err(|_| VfsError::einval("range copy length is too large"))?; - output[output_start..output_start + len] - .copy_from_slice(&block[block_start..block_start + len]); - } - Ok(output) - } - } - } - - async fn put_chunk_edit(&self, index: u64, data: Vec) -> VfsResult { - let len = u32::try_from(data.len()) - .map_err(|_| VfsError::einval(format!("chunk is too large: {}", data.len())))?; - let key = BlockKey::from_content(&data); - if !self.blocks.exists(&key).await? { - self.blocks.put(&key, &data).await?; - } - Ok(ChunkEdit { index, key, len }) - } - - async fn write_chunked_range( - &self, - meta: &InodeMeta, - content: &[u8], - offset: u64, - ) -> VfsResult { - if content.is_empty() { - return Ok(meta.size); - } - let content_len = u64::try_from(content.len()).map_err(|_| { - VfsError::einval(format!("pwrite content is too large: {}", content.len())) - })?; - let end_offset = offset - .checked_add(content_len) - .ok_or_else(|| VfsError::einval("pwrite end offset overflows"))?; - let new_size = meta.size.max(end_offset); - - if !matches!(meta.storage, Storage::Chunked { .. }) - && usize::try_from(new_size) - .ok() - .is_some_and(|len| len <= self.options.inline_threshold) - { - let old_len = usize::try_from(meta.size) - .map_err(|_| VfsError::einval(format!("file is too large: {}", meta.size)))?; - let mut data = self.read_file_range(meta, 0, old_len).await?; - let start = usize::try_from(offset) - .map_err(|_| VfsError::einval(format!("pwrite offset is too large: {offset}")))?; - let end = start.saturating_add(content.len()); - if start > data.len() { - data.resize(start, 0); - } - if end > data.len() { - data.resize(end, 0); - } - data[start..end].copy_from_slice(content); - let freed = self - .metadata - .set_attr( - meta.ino, - InodePatch { - storage: Some(Storage::Inline(data)), - size: Some(new_size), - ..InodePatch::default() - }, - ) - .await?; - self.blocks.delete_many(&freed).await?; - return Ok(new_size); - } - - let chunk_size = u64::from(self.file_chunk_size(&meta.storage)); - let start_index = offset / chunk_size; - let end_index = end_offset.div_ceil(chunk_size); - let existing_chunks = if matches!(meta.storage, Storage::Chunked { .. }) { - self.metadata - .get_chunks( - meta.ino, - ChunkRange { - start: start_index, - end: Some(end_index), - }, - ) - .await? - .into_iter() - .map(|chunk| (chunk.index, chunk.key)) - .collect::>() - } else { - BTreeMap::new() - }; - - let mut edits = Vec::new(); - for index in start_index..end_index { - let chunk_start = index.saturating_mul(chunk_size); - let chunk_len = chunk_size.min(new_size.saturating_sub(chunk_start)); - let mut chunk_data = vec![ - 0; - usize::try_from(chunk_len).map_err(|_| { - VfsError::einval("chunk length is too large") - })? - ]; - - match &meta.storage { - Storage::Inline(data) => { - let copy_start = chunk_start.min(data.len() as u64); - let copy_end = chunk_start.saturating_add(chunk_len).min(data.len() as u64); - if copy_start < copy_end { - let dst = usize::try_from(copy_start - chunk_start) - .map_err(|_| VfsError::einval("inline chunk offset is too large"))?; - let src = usize::try_from(copy_start) - .map_err(|_| VfsError::einval("inline source offset is too large"))?; - let len = usize::try_from(copy_end - copy_start) - .map_err(|_| VfsError::einval("inline copy length is too large"))?; - chunk_data[dst..dst + len].copy_from_slice(&data[src..src + len]); - } - } - Storage::Chunked { .. } => { - if let Some(key) = existing_chunks.get(&index) { - let old = self.blocks.get(key).await?; - let len = old.len().min(chunk_data.len()); - chunk_data[..len].copy_from_slice(&old[..len]); - } - } - Storage::None => {} - } - - let write_start = offset.max(chunk_start); - let write_end = end_offset.min(chunk_start.saturating_add(chunk_len)); - if write_start < write_end { - let dst = usize::try_from(write_start - chunk_start) - .map_err(|_| VfsError::einval("chunk write offset is too large"))?; - let src = usize::try_from(write_start - offset) - .map_err(|_| VfsError::einval("content write offset is too large"))?; - let len = usize::try_from(write_end - write_start) - .map_err(|_| VfsError::einval("chunk write length is too large"))?; - chunk_data[dst..dst + len].copy_from_slice(&content[src..src + len]); - } - - edits.push(self.put_chunk_edit(index, chunk_data).await?); - } - - if !matches!(meta.storage, Storage::Chunked { .. }) { - self.metadata - .set_attr( - meta.ino, - InodePatch { - storage: Some(Storage::Chunked { - chunk_size: self.options.chunk_size, - }), - size: Some(new_size), - ..InodePatch::default() - }, - ) - .await?; - } - let freed = self - .metadata - .commit_write(meta.ino, edits, new_size) - .await?; - self.blocks.delete_many(&freed).await?; - Ok(new_size) - } -} - -#[async_trait] -impl VirtualFileSystem for ChunkedFs { - async fn read_file(&self, path: &str) -> VfsResult> { - let meta = self.metadata.resolve(path).await?; - self.ensure_file(path, &meta)?; - let len = usize::try_from(meta.size) - .map_err(|_| VfsError::einval(format!("file is too large: {}", meta.size)))?; - self.read_file_range(&meta, 0, len).await - } - - async fn read_dir(&self, path: &str) -> VfsResult> { - let meta = self.metadata.resolve(path).await?; - Ok(self - .metadata - .list_dir(meta.ino) - .await? - .into_iter() - .map(|entry| entry.name) - .collect()) - } - - async fn read_dir_with_types(&self, path: &str) -> VfsResult> { - let meta = self.metadata.resolve(path).await?; - Ok(self - .metadata - .list_dir(meta.ino) - .await? - .into_iter() - .map(|entry| Dentry { - name: entry.name, - ino: entry.meta.ino, - kind: entry.meta.kind, - }) - .collect()) - } - - async fn write_file(&self, path: &str, content: &[u8]) -> VfsResult<()> { - self.write_existing_or_create(path, content).await - } - - async fn create_dir(&self, path: &str) -> VfsResult<()> { - let (parent, name) = self.metadata.resolve_parent(path).await?; - self.metadata - .create( - parent.ino, - &name, - CreateInodeAttrs::directory( - self.options.dir_mode, - self.options.uid, - self.options.gid, - ), - ) - .await?; - Ok(()) - } - - async fn mkdir(&self, path: &str, recursive: bool) -> VfsResult<()> { - if !recursive { - return self.create_dir(path).await; - } - let normalized = normalize_path(path)?; - let mut current = String::new(); - for part in normalized - .trim_start_matches('/') - .split('/') - .filter(|p| !p.is_empty()) - { - current.push('/'); - current.push_str(part); - if !self.exists(¤t).await { - self.create_dir(¤t).await?; - } - } - Ok(()) - } - - async fn exists(&self, path: &str) -> bool { - self.metadata.resolve(path).await.is_ok() - } - - async fn stat(&self, path: &str) -> VfsResult { - Ok(self.metadata.resolve(path).await?.to_stat()) - } - - async fn lstat(&self, path: &str) -> VfsResult { - Ok(self.metadata.lstat(path).await?.to_stat()) - } - - async fn remove_file(&self, path: &str) -> VfsResult<()> { - let meta = self.metadata.lstat(path).await?; - if meta.kind == InodeType::Directory { - return Err(VfsError::eisdir(path)); - } - let (parent, name) = self.metadata.resolve_parent(path).await?; - let freed = self.metadata.remove(parent.ino, &name).await?; - self.blocks.delete_many(&freed).await - } - - async fn remove_dir(&self, path: &str) -> VfsResult<()> { - let meta = self.metadata.lstat(path).await?; - if meta.kind != InodeType::Directory { - return Err(VfsError::enotdir(path)); - } - let (parent, name) = self.metadata.resolve_parent(path).await?; - let freed = self.metadata.remove(parent.ino, &name).await?; - self.blocks.delete_many(&freed).await - } - - async fn rename(&self, old_path: &str, new_path: &str) -> VfsResult<()> { - let (src_parent, src) = self.metadata.resolve_parent(old_path).await?; - let (dst_parent, dst) = self.metadata.resolve_parent(new_path).await?; - let freed = self - .metadata - .rename(src_parent.ino, &src, dst_parent.ino, &dst) - .await?; - self.blocks.delete_many(&freed).await - } - - async fn realpath(&self, path: &str) -> VfsResult { - self.metadata.resolve(path).await?; - normalize_path(path) - } - - async fn symlink(&self, target: &str, link_path: &str) -> VfsResult<()> { - let (parent, name) = self.metadata.resolve_parent(link_path).await?; - self.metadata - .create( - parent.ino, - &name, - CreateInodeAttrs::symlink(target.to_string(), self.options.uid, self.options.gid), - ) - .await?; - Ok(()) - } - - async fn readlink(&self, path: &str) -> VfsResult { - let meta = self.metadata.lstat(path).await?; - if meta.kind != InodeType::Symlink { - return Err(VfsError::einval(format!("not a symlink: {path}"))); - } - Ok(meta.symlink_target.unwrap_or_default()) - } - - async fn link(&self, old_path: &str, new_path: &str) -> VfsResult<()> { - let target = self.metadata.resolve(old_path).await?; - let (parent, name) = self.metadata.resolve_parent(new_path).await?; - self.metadata.link(parent.ino, &name, target.ino).await - } - - async fn chmod(&self, path: &str, mode: u32) -> VfsResult<()> { - let meta = self.metadata.resolve(path).await?; - self.metadata - .set_attr( - meta.ino, - InodePatch { - mode: Some(mode), - ..InodePatch::default() - }, - ) - .await?; - Ok(()) - } - - async fn chown(&self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - let meta = self.metadata.resolve(path).await?; - self.metadata - .set_attr( - meta.ino, - InodePatch { - uid: Some(uid), - gid: Some(gid), - ..InodePatch::default() - }, - ) - .await?; - Ok(()) - } - - async fn utimes(&self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - let meta = self.metadata.resolve(path).await?; - self.metadata - .set_attr( - meta.ino, - InodePatch { - atime: Some(ms_to_timespec(atime_ms)), - mtime: Some(ms_to_timespec(mtime_ms)), - ..InodePatch::default() - }, - ) - .await?; - Ok(()) - } - - async fn truncate(&self, path: &str, length: u64) -> VfsResult<()> { - let meta = self.metadata.resolve(path).await?; - self.ensure_file(path, &meta)?; - if length == meta.size { - return Ok(()); - } - - if usize::try_from(length) - .ok() - .is_some_and(|len| len <= self.options.inline_threshold) - { - let data = self - .read_file_range(&meta, 0, usize::try_from(length).unwrap_or(0)) - .await?; - let freed = self - .metadata - .set_attr( - meta.ino, - InodePatch { - storage: Some(Storage::Inline(data)), - size: Some(length), - ..InodePatch::default() - }, - ) - .await?; - self.blocks.delete_many(&freed).await?; - return Ok(()); - } - - let chunk_size = u64::from(self.file_chunk_size(&meta.storage)); - let mut edits = Vec::new(); - if !matches!(meta.storage, Storage::Chunked { .. }) { - let existing_len = meta.size.min(length); - let mut offset = 0; - while offset < existing_len { - let len = (existing_len - offset).min(chunk_size); - let data = self - .read_file_range( - &meta, - offset, - usize::try_from(len) - .map_err(|_| VfsError::einval("truncate chunk is too large"))?, - ) - .await?; - edits.push(self.put_chunk_edit(offset / chunk_size, data).await?); - offset = offset.saturating_add(len); - } - self.metadata - .set_attr( - meta.ino, - InodePatch { - storage: Some(Storage::Chunked { - chunk_size: self.options.chunk_size, - }), - size: Some(length), - ..InodePatch::default() - }, - ) - .await?; - } else if length < meta.size && !length.is_multiple_of(chunk_size) { - let final_index = length / chunk_size; - let final_start = final_index.saturating_mul(chunk_size); - let final_len = length - final_start; - let data = self - .read_file_range( - &meta, - final_start, - usize::try_from(final_len) - .map_err(|_| VfsError::einval("truncate final chunk is too large"))?, - ) - .await?; - edits.push(self.put_chunk_edit(final_index, data).await?); - } - - let freed = self.metadata.commit_write(meta.ino, edits, length).await?; - self.blocks.delete_many(&freed).await - } - - async fn pread(&self, path: &str, offset: u64, length: usize) -> VfsResult> { - let meta = self.metadata.resolve(path).await?; - self.ensure_file(path, &meta)?; - self.read_file_range(&meta, offset, length).await - } - - async fn pwrite(&self, path: &str, content: &[u8], offset: u64) -> VfsResult<()> { - let meta = self.metadata.resolve(path).await?; - self.ensure_file(path, &meta)?; - self.write_chunked_range(&meta, content, offset).await?; - Ok(()) - } - - async fn append(&self, path: &str, content: &[u8]) -> VfsResult { - let meta = self.metadata.resolve(path).await?; - self.ensure_file(path, &meta)?; - let len = meta - .size - .checked_add(u64::try_from(content.len()).map_err(|_| { - VfsError::einval(format!("append content is too large: {}", content.len())) - })?) - .ok_or_else(|| VfsError::einval("append size overflows"))?; - self.write_chunked_range(&meta, content, meta.size).await?; - Ok(len) - } -} - -#[async_trait] -impl Snapshottable for ChunkedFs { - async fn snapshot(&self, root: u64) -> VfsResult { - self.metadata.snapshot(root).await - } - - async fn fork(&self, snap: SnapshotId) -> VfsResult { - self.metadata.fork(snap).await - } -} - -fn ms_to_timespec(ms: u64) -> Timespec { - Timespec { - sec: (ms / 1_000) as i64, - nsec: ((ms % 1_000) * 1_000_000) as u32, - } -} diff --git a/crates/vfs/src/engine/engines/mod.rs b/crates/vfs/src/engine/engines/mod.rs deleted file mode 100644 index 115bc103e..000000000 --- a/crates/vfs/src/engine/engines/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod chunked; -pub mod object; - -pub use chunked::{ChunkedFs, ChunkedFsOptions}; -pub use object::{ObjectFs, ObjectFsOptions}; diff --git a/crates/vfs/src/engine/engines/object.rs b/crates/vfs/src/engine/engines/object.rs deleted file mode 100644 index e03a98f60..000000000 --- a/crates/vfs/src/engine/engines/object.rs +++ /dev/null @@ -1,361 +0,0 @@ -use crate::engine::block::ObjectBackend; -use crate::engine::error::{VfsError, VfsResult}; -use crate::engine::types::{normalize_path, Dentry, InodeType, ObjectMeta, Timespec, VirtualStat}; -use crate::engine::vfs::VirtualFileSystem; -use async_trait::async_trait; - -#[derive(Debug, Clone)] -pub struct ObjectFsOptions { - pub prefix: String, - pub uid: u32, - pub gid: u32, - pub file_mode: u32, - pub dir_mode: u32, -} - -impl Default for ObjectFsOptions { - fn default() -> Self { - Self { - prefix: String::new(), - uid: 0, - gid: 0, - file_mode: 0o644, - dir_mode: 0o755, - } - } -} - -#[derive(Debug, Clone)] -pub struct ObjectFs { - backend: B, - options: ObjectFsOptions, -} - -impl ObjectFs { - pub fn new(backend: B) -> Self { - Self::with_options(backend, ObjectFsOptions::default()) - } - - pub fn with_options(backend: B, options: ObjectFsOptions) -> Self { - Self { backend, options } - } - - fn key_for(&self, path: &str) -> VfsResult { - let normalized = normalize_path(path)?; - let relative = normalized.trim_start_matches('/'); - Ok(format!("{}{}", self.options.prefix, relative)) - } - - fn dir_prefix_for(&self, path: &str) -> VfsResult { - let mut key = self.key_for(path)?; - if !key.is_empty() && !key.ends_with('/') { - key.push('/'); - } - Ok(key) - } - - fn file_meta(&self, size: u64) -> ObjectMeta { - ObjectMeta { - size, - mtime: Timespec::now(), - mode: self.options.file_mode, - uid: self.options.uid, - gid: self.options.gid, - kind: InodeType::File, - symlink_target: None, - } - } - - fn dir_meta(&self) -> ObjectMeta { - ObjectMeta { - size: 0, - mtime: Timespec::now(), - mode: self.options.dir_mode, - uid: self.options.uid, - gid: self.options.gid, - kind: InodeType::Directory, - symlink_target: None, - } - } -} - -impl ObjectFs { - async fn collect_objects_under(&self, prefix: &str) -> VfsResult> { - let mut pending = vec![prefix.to_string()]; - let mut objects = Vec::new(); - while let Some(current) = pending.pop() { - for entry in self.backend.list(¤t).await? { - if entry.is_prefix { - pending.push(entry.name); - } else { - objects.push(entry.name); - } - } - } - Ok(objects) - } -} - -#[async_trait] -impl VirtualFileSystem for ObjectFs { - async fn read_file(&self, path: &str) -> VfsResult> { - let key = self.key_for(path)?; - let meta = self - .backend - .head(&key) - .await? - .ok_or_else(|| VfsError::enoent(path))?; - if meta.kind == InodeType::Directory { - return Err(VfsError::eisdir(path)); - } - if meta.kind == InodeType::Symlink { - let target = meta.symlink_target.ok_or_else(|| VfsError::enoent(path))?; - return self.read_file(&target).await; - } - self.backend.get_range(&key, 0, meta.size).await - } - - async fn read_dir(&self, path: &str) -> VfsResult> { - Ok(self - .read_dir_with_types(path) - .await? - .into_iter() - .map(|entry| entry.name) - .collect()) - } - - async fn read_dir_with_types(&self, path: &str) -> VfsResult> { - let prefix = self.dir_prefix_for(path)?; - let entries = self.backend.list(&prefix).await?; - let mut result = Vec::new(); - for entry in entries { - let name = entry - .name - .trim_start_matches(&prefix) - .trim_end_matches('/') - .to_string(); - if name.is_empty() || name.contains('/') { - continue; - } - result.push(Dentry { - name, - ino: 0, - kind: if entry.is_prefix { - InodeType::Directory - } else { - InodeType::File - }, - }); - } - Ok(result) - } - - async fn write_file(&self, path: &str, content: &[u8]) -> VfsResult<()> { - let key = self.key_for(path)?; - self.backend - .put(&key, content, self.file_meta(content.len() as u64)) - .await - } - - async fn create_dir(&self, path: &str) -> VfsResult<()> { - let key = self.dir_prefix_for(path)?; - self.backend.put(&key, &[], self.dir_meta()).await - } - - async fn mkdir(&self, path: &str, recursive: bool) -> VfsResult<()> { - if !recursive { - return self.create_dir(path).await; - } - let normalized = normalize_path(path)?; - let mut current = String::new(); - for part in normalized - .trim_start_matches('/') - .split('/') - .filter(|p| !p.is_empty()) - { - current.push('/'); - current.push_str(part); - self.create_dir(¤t).await?; - } - Ok(()) - } - - async fn exists(&self, path: &str) -> bool { - let Ok(key) = self.key_for(path) else { - return false; - }; - if self.backend.head(&key).await.ok().flatten().is_some() { - return true; - } - let Ok(prefix) = self.dir_prefix_for(path) else { - return false; - }; - self.backend - .list(&prefix) - .await - .map(|entries| !entries.is_empty()) - .unwrap_or(false) - } - - async fn stat(&self, path: &str) -> VfsResult { - let key = self.key_for(path)?; - if let Some(meta) = self.backend.head(&key).await? { - return Ok(object_stat(meta)); - } - let entries = self.backend.list(&self.dir_prefix_for(path)?).await?; - if entries.is_empty() { - return Err(VfsError::enoent(path)); - } - Ok(object_stat(self.dir_meta())) - } - - async fn lstat(&self, path: &str) -> VfsResult { - self.stat(path).await - } - - async fn remove_file(&self, path: &str) -> VfsResult<()> { - self.backend.delete(&self.key_for(path)?).await - } - - async fn remove_dir(&self, path: &str) -> VfsResult<()> { - let prefix = self.dir_prefix_for(path)?; - let entries = self.backend.list(&prefix).await?; - if entries.iter().any(|entry| entry.name != prefix) { - return Err(VfsError::enotempty(path)); - } - self.backend.delete(&prefix).await - } - - async fn rename(&self, old_path: &str, new_path: &str) -> VfsResult<()> { - let old_key = self.key_for(old_path)?; - if self.backend.head(&old_key).await?.is_some() { - let new_key = self.key_for(new_path)?; - self.backend.copy(&old_key, &new_key).await?; - self.backend.delete(&old_key).await?; - return Ok(()); - } - let old_prefix = self.dir_prefix_for(old_path)?; - let new_prefix = self.dir_prefix_for(new_path)?; - let objects = self.collect_objects_under(&old_prefix).await?; - if objects.is_empty() { - return Err(VfsError::enoent(old_path)); - } - for key in &objects { - let dst = format!("{new_prefix}{}", key.trim_start_matches(&old_prefix)); - self.backend.copy(key, &dst).await?; - } - for key in objects { - self.backend.delete(&key).await?; - } - Ok(()) - } - - async fn realpath(&self, path: &str) -> VfsResult { - if !self.exists(path).await { - return Err(VfsError::enoent(path)); - } - normalize_path(path) - } - - async fn symlink(&self, target: &str, link_path: &str) -> VfsResult<()> { - let key = self.key_for(link_path)?; - let meta = ObjectMeta { - size: 0, - mtime: Timespec::now(), - mode: 0o777, - uid: self.options.uid, - gid: self.options.gid, - kind: InodeType::Symlink, - symlink_target: Some(target.to_string()), - }; - self.backend.put(&key, &[], meta).await - } - - async fn readlink(&self, path: &str) -> VfsResult { - let key = self.key_for(path)?; - let meta = self - .backend - .head(&key) - .await? - .ok_or_else(|| VfsError::enoent(path))?; - if meta.kind != InodeType::Symlink { - return Err(VfsError::einval(format!("not a symlink: {path}"))); - } - Ok(meta.symlink_target.unwrap_or_default()) - } - - async fn link(&self, _old_path: &str, _new_path: &str) -> VfsResult<()> { - Err(VfsError::eopnotsupp("ObjectFs does not support hard links")) - } - - async fn chmod(&self, _path: &str, _mode: u32) -> VfsResult<()> { - Ok(()) - } - - async fn chown(&self, _path: &str, _uid: u32, _gid: u32) -> VfsResult<()> { - Ok(()) - } - - async fn utimes(&self, _path: &str, _atime_ms: u64, _mtime_ms: u64) -> VfsResult<()> { - Ok(()) - } - - async fn truncate(&self, path: &str, length: u64) -> VfsResult<()> { - let mut data = self.read_file(path).await?; - let length = usize::try_from(length) - .map_err(|_| VfsError::einval(format!("truncate length is too large: {length}")))?; - data.resize(length, 0); - self.write_file(path, &data).await - } - - async fn pread(&self, path: &str, offset: u64, length: usize) -> VfsResult> { - let key = self.key_for(path)?; - self.backend.get_range(&key, offset, length as u64).await - } - - async fn pwrite(&self, path: &str, content: &[u8], offset: u64) -> VfsResult<()> { - let mut data = self.read_file(path).await?; - let start = usize::try_from(offset) - .map_err(|_| VfsError::einval(format!("pwrite offset is too large: {offset}")))?; - if start > data.len() { - data.resize(start, 0); - } - let end = start.saturating_add(content.len()); - if end > data.len() { - data.resize(end, 0); - } - data[start..end].copy_from_slice(content); - self.write_file(path, &data).await - } - - async fn append(&self, path: &str, content: &[u8]) -> VfsResult { - let mut data = self.read_file(path).await?; - data.extend_from_slice(content); - let len = data.len() as u64; - self.write_file(path, &data).await?; - Ok(len) - } -} - -fn object_stat(meta: ObjectMeta) -> VirtualStat { - let type_bits = match meta.kind { - InodeType::File => crate::engine::types::S_IFREG, - InodeType::Directory => crate::engine::types::S_IFDIR, - InodeType::Symlink => crate::engine::types::S_IFLNK, - }; - VirtualStat { - mode: type_bits | (meta.mode & 0o7777), - size: meta.size, - blocks: meta.size.div_ceil(512), - is_directory: meta.kind == InodeType::Directory, - is_symbolic_link: meta.kind == InodeType::Symlink, - atime: meta.mtime, - mtime: meta.mtime, - ctime: meta.mtime, - birthtime: meta.mtime, - ino: 0, - nlink: 1, - uid: meta.uid, - gid: meta.gid, - } -} diff --git a/crates/vfs/src/engine/error.rs b/crates/vfs/src/engine/error.rs deleted file mode 100644 index 2cd4e26f7..000000000 --- a/crates/vfs/src/engine/error.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::error::Error; -use std::fmt; - -pub type VfsResult = Result; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VfsError { - code: &'static str, - message: String, -} - -impl VfsError { - pub fn new(code: &'static str, message: impl Into) -> Self { - Self { - code, - message: message.into(), - } - } - - pub fn code(&self) -> &'static str { - self.code - } - - pub fn message(&self) -> &str { - &self.message - } - - pub fn enoent(path: impl AsRef) -> Self { - Self::new( - "ENOENT", - format!("no such file or directory: {}", path.as_ref()), - ) - } - - pub fn eexist(path: impl AsRef) -> Self { - Self::new("EEXIST", format!("file exists: {}", path.as_ref())) - } - - pub fn enotdir(path: impl AsRef) -> Self { - Self::new("ENOTDIR", format!("not a directory: {}", path.as_ref())) - } - - pub fn eisdir(path: impl AsRef) -> Self { - Self::new("EISDIR", format!("is a directory: {}", path.as_ref())) - } - - pub fn eloop(path: impl AsRef) -> Self { - Self::new( - "ELOOP", - format!("too many symbolic links: {}", path.as_ref()), - ) - } - - pub fn enametoolong(path: impl AsRef) -> Self { - Self::new("ENAMETOOLONG", format!("path too long: {}", path.as_ref())) - } - - pub fn enotempty(path: impl AsRef) -> Self { - Self::new( - "ENOTEMPTY", - format!("directory not empty: {}", path.as_ref()), - ) - } - - pub fn eopnotsupp(message: impl Into) -> Self { - Self::new("EOPNOTSUPP", message) - } - - pub fn erofs(message: impl Into) -> Self { - Self::new("EROFS", message) - } - - pub fn einval(message: impl Into) -> Self { - Self::new("EINVAL", message) - } - - pub fn eio(message: impl Into) -> Self { - Self::new("EIO", message) - } -} - -impl fmt::Display for VfsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for VfsError {} diff --git a/crates/vfs/src/engine/mem/block_store.rs b/crates/vfs/src/engine/mem/block_store.rs deleted file mode 100644 index ca0153e80..000000000 --- a/crates/vfs/src/engine/mem/block_store.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::engine::block::BlockStore; -use crate::engine::error::{VfsError, VfsResult}; -use crate::engine::types::BlockKey; -use async_trait::async_trait; -use std::collections::BTreeMap; -use std::sync::{Arc, Mutex}; - -#[derive(Debug, Clone, Default)] -pub struct MemoryBlockStore { - blocks: Arc>>>, -} - -impl MemoryBlockStore { - pub fn new() -> Self { - Self::default() - } - - pub fn len(&self) -> usize { - self.blocks.lock().expect("block mutex poisoned").len() - } - - pub fn is_empty(&self) -> bool { - self.blocks.lock().expect("block mutex poisoned").is_empty() - } -} - -#[async_trait] -impl BlockStore for MemoryBlockStore { - async fn get(&self, key: &BlockKey) -> VfsResult> { - self.blocks - .lock() - .expect("block mutex poisoned") - .get(key) - .cloned() - .ok_or_else(|| VfsError::enoent(&key.0)) - } - - async fn get_range(&self, key: &BlockKey, off: u64, len: u64) -> VfsResult> { - let data = self.get(key).await?; - let start = usize::try_from(off) - .map_err(|_| VfsError::einval(format!("range offset is too large: {off}")))?; - let len = usize::try_from(len) - .map_err(|_| VfsError::einval(format!("range length is too large: {len}")))?; - if start >= data.len() { - return Ok(Vec::new()); - } - let end = start.saturating_add(len).min(data.len()); - Ok(data[start..end].to_vec()) - } - - async fn put(&self, key: &BlockKey, data: &[u8]) -> VfsResult<()> { - self.blocks - .lock() - .expect("block mutex poisoned") - .insert(key.clone(), data.to_vec()); - Ok(()) - } - - async fn exists(&self, key: &BlockKey) -> VfsResult { - Ok(self - .blocks - .lock() - .expect("block mutex poisoned") - .contains_key(key)) - } - - async fn delete_many(&self, keys: &[BlockKey]) -> VfsResult<()> { - let mut blocks = self.blocks.lock().expect("block mutex poisoned"); - for key in keys { - blocks.remove(key); - } - Ok(()) - } - - async fn copy(&self, src: &BlockKey, dst: &BlockKey) -> VfsResult<()> { - let data = self.get(src).await?; - self.put(dst, &data).await - } -} diff --git a/crates/vfs/src/engine/mem/metadata_store.rs b/crates/vfs/src/engine/mem/metadata_store.rs deleted file mode 100644 index 76936b688..000000000 --- a/crates/vfs/src/engine/mem/metadata_store.rs +++ /dev/null @@ -1,641 +0,0 @@ -use crate::engine::error::{VfsError, VfsResult}; -use crate::engine::metadata::MetadataStore; -use crate::engine::types::{ - normalize_path, parent_and_name, BlockKey, ChunkEdit, ChunkRange, ChunkRef, CreateInodeAttrs, - DentryStat, InodeMeta, InodePatch, InodeType, SnapshotId, Storage, Timespec, - DEFAULT_CHUNK_SIZE, MAX_SYMLINK_DEPTH, -}; -use async_trait::async_trait; -use std::collections::{BTreeMap, BTreeSet}; -use std::sync::{Arc, Mutex}; - -#[derive(Debug, Clone)] -pub struct InMemoryMetadataStore { - state: Arc>, -} - -#[derive(Debug, Clone)] -pub struct MetadataDump { - pub next_ino: u64, - pub inodes: BTreeMap, - pub dentries: BTreeMap<(u64, String), u64>, - pub chunks: BTreeMap<(u64, u64), ChunkRef>, - pub block_refs: BTreeMap, -} - -#[derive(Debug, Clone)] -struct State { - next_ino: u64, - next_snapshot_id: u64, - inodes: BTreeMap, - dentries: BTreeMap<(u64, String), u64>, - chunks: BTreeMap<(u64, u64), ChunkRef>, - block_refs: BTreeMap, - snapshots: BTreeMap, -} - -#[derive(Debug, Clone)] -struct Snapshot { - root_ino: u64, - inodes: BTreeMap, - dentries: BTreeMap<(u64, String), u64>, - chunks: BTreeMap<(u64, u64), ChunkRef>, -} - -impl Default for InMemoryMetadataStore { - fn default() -> Self { - Self::new() - } -} - -impl InMemoryMetadataStore { - pub const ROOT_INO: u64 = 1; - - pub fn new() -> Self { - let now = Timespec::now(); - let root = InodeMeta { - ino: Self::ROOT_INO, - kind: InodeType::Directory, - mode: 0o755, - uid: 0, - gid: 0, - size: 0, - nlink: 2, - atime: now, - mtime: now, - ctime: now, - birthtime: now, - storage: Storage::None, - symlink_target: None, - }; - let mut inodes = BTreeMap::new(); - inodes.insert(Self::ROOT_INO, root); - Self { - state: Arc::new(Mutex::new(State { - next_ino: 2, - next_snapshot_id: 1, - inodes, - dentries: BTreeMap::new(), - chunks: BTreeMap::new(), - block_refs: BTreeMap::new(), - snapshots: BTreeMap::new(), - })), - } - } - - pub fn refcount(&self, key: &BlockKey) -> u64 { - self.state - .lock() - .expect("metadata mutex poisoned") - .block_refs - .get(key) - .copied() - .unwrap_or(0) - } - - pub fn dump(&self) -> MetadataDump { - let state = self.state.lock().expect("metadata mutex poisoned"); - MetadataDump { - next_ino: state.next_ino, - inodes: state.inodes.clone(), - dentries: state.dentries.clone(), - chunks: state.chunks.clone(), - block_refs: state.block_refs.clone(), - } - } - - pub fn from_dump(dump: MetadataDump) -> Self { - Self { - state: Arc::new(Mutex::new(State { - next_ino: dump.next_ino, - next_snapshot_id: 1, - inodes: dump.inodes, - dentries: dump.dentries, - chunks: dump.chunks, - block_refs: dump.block_refs, - snapshots: BTreeMap::new(), - })), - } - } -} - -impl State { - fn now_touch(meta: &mut InodeMeta) { - let now = Timespec::now(); - meta.mtime = now; - meta.ctime = now; - } - - fn inode(&self, ino: u64) -> VfsResult { - self.inodes - .get(&ino) - .cloned() - .ok_or_else(|| VfsError::enoent(format!("inode {ino}"))) - } - - fn alloc_inode(&mut self, attrs: CreateInodeAttrs) -> InodeMeta { - let ino = self.next_ino; - self.next_ino += 1; - let now = Timespec::now(); - let size = match &attrs.storage { - Storage::Inline(data) => data.len() as u64, - Storage::Chunked { .. } | Storage::None => attrs - .symlink_target - .as_ref() - .map(|target| target.len() as u64) - .unwrap_or(0), - }; - InodeMeta { - ino, - kind: attrs.kind, - mode: attrs.mode, - uid: attrs.uid, - gid: attrs.gid, - size, - nlink: if attrs.kind == InodeType::Directory { - 2 - } else { - 1 - }, - atime: now, - mtime: now, - ctime: now, - birthtime: now, - storage: attrs.storage, - symlink_target: attrs.symlink_target, - } - } - - fn name_child(&self, parent: u64, name: &str) -> VfsResult { - self.dentries - .get(&(parent, name.to_string())) - .copied() - .ok_or_else(|| VfsError::enoent(name)) - } - - fn resolve_path(&self, path: &str, follow_final: bool) -> VfsResult { - self.resolve_path_depth(path, follow_final, 0) - } - - fn resolve_path_depth( - &self, - path: &str, - follow_final: bool, - depth: usize, - ) -> VfsResult { - if depth > MAX_SYMLINK_DEPTH { - return Err(VfsError::eloop(path)); - } - let normalized = normalize_path(path)?; - if normalized == "/" { - return self.inode(InMemoryMetadataStore::ROOT_INO); - } - - let parts: Vec<&str> = normalized.trim_start_matches('/').split('/').collect(); - let mut current = InMemoryMetadataStore::ROOT_INO; - let mut prefix = String::new(); - for (idx, part) in parts.iter().enumerate() { - let parent_meta = self.inode(current)?; - if parent_meta.kind != InodeType::Directory { - return Err(VfsError::enotdir(&prefix)); - } - let child = self.name_child(current, part)?; - let meta = self.inode(child)?; - let final_component = idx == parts.len() - 1; - if meta.kind == InodeType::Symlink && (!final_component || follow_final) { - let target = meta.symlink_target.clone().unwrap_or_default(); - let rest = parts[idx + 1..].join("/"); - let base = if prefix.is_empty() { "/" } else { &prefix }; - let next_path = resolve_symlink_target(base, &target, &rest)?; - return self.resolve_path_depth(&next_path, follow_final, depth + 1); - } - current = child; - if prefix == "/" || prefix.is_empty() { - prefix = format!("/{part}"); - } else { - prefix.push('/'); - prefix.push_str(part); - } - } - self.inode(current) - } - - fn collect_subtree(&self, root: u64) -> VfsResult> { - let mut seen = BTreeSet::new(); - self.collect_subtree_into(root, &mut seen)?; - Ok(seen) - } - - fn collect_subtree_into(&self, ino: u64, seen: &mut BTreeSet) -> VfsResult<()> { - if !seen.insert(ino) { - return Ok(()); - } - let meta = self.inode(ino)?; - if meta.kind == InodeType::Directory { - for ((parent, _), child) in self.dentries.range((ino, String::new())..) { - if *parent != ino { - break; - } - self.collect_subtree_into(*child, seen)?; - } - } - Ok(()) - } - - fn dec_block_ref(&mut self, key: &BlockKey, freed: &mut Vec) { - if let Some(refcount) = self.block_refs.get_mut(key) { - *refcount = refcount.saturating_sub(1); - if *refcount == 0 { - self.block_refs.remove(key); - freed.push(key.clone()); - } - } - } - - fn inc_block_ref(&mut self, key: &BlockKey) { - *self.block_refs.entry(key.clone()).or_insert(0) += 1; - } - - fn drop_inode_content(&mut self, ino: u64, freed: &mut Vec) { - let keys: Vec = self - .chunks - .range((ino, 0)..) - .take_while(|((chunk_ino, _), _)| *chunk_ino == ino) - .map(|(_, chunk)| chunk.key.clone()) - .collect(); - self.chunks.retain(|(chunk_ino, _), _| *chunk_ino != ino); - for key in keys { - self.dec_block_ref(&key, freed); - } - } - - fn remove_child(&mut self, parent: u64, name: &str) -> VfsResult> { - let child = self.name_child(parent, name)?; - let meta = self.inode(child)?; - if meta.kind == InodeType::Directory - && self - .dentries - .range((child, String::new())..) - .next() - .is_some_and(|((candidate_parent, _), _)| *candidate_parent == child) - { - return Err(VfsError::enotempty(name)); - } - self.dentries.remove(&(parent, name.to_string())); - let mut freed = Vec::new(); - if let Some(child_meta) = self.inodes.get_mut(&child) { - child_meta.nlink = child_meta.nlink.saturating_sub(1); - child_meta.ctime = Timespec::now(); - if child_meta.nlink > 0 { - return Ok(freed); - } - } - self.drop_inode_content(child, &mut freed); - self.inodes.remove(&child); - Ok(freed) - } -} - -fn resolve_symlink_target(base: &str, target: &str, rest: &str) -> VfsResult { - let mut path = if target.starts_with('/') { - target.to_string() - } else if base == "/" { - format!("/{target}") - } else { - format!("{base}/{target}") - }; - if !rest.is_empty() { - if path != "/" { - path.push('/'); - } - path.push_str(rest); - } - normalize_path(&path) -} - -#[async_trait] -impl MetadataStore for InMemoryMetadataStore { - async fn resolve(&self, path: &str) -> VfsResult { - self.state - .lock() - .expect("metadata mutex poisoned") - .resolve_path(path, true) - } - - async fn resolve_parent(&self, path: &str) -> VfsResult<(InodeMeta, String)> { - let (parent, name) = parent_and_name(path)?; - let parent_meta = self - .state - .lock() - .expect("metadata mutex poisoned") - .resolve_path(&parent, true)?; - if parent_meta.kind != InodeType::Directory { - return Err(VfsError::enotdir(parent)); - } - Ok((parent_meta, name)) - } - - async fn lstat(&self, path: &str) -> VfsResult { - self.state - .lock() - .expect("metadata mutex poisoned") - .resolve_path(path, false) - } - - async fn list_dir(&self, ino: u64) -> VfsResult> { - let state = self.state.lock().expect("metadata mutex poisoned"); - let meta = state.inode(ino)?; - if meta.kind != InodeType::Directory { - return Err(VfsError::enotdir(format!("inode {ino}"))); - } - let mut entries = Vec::new(); - for ((parent, name), child) in state.dentries.range((ino, String::new())..) { - if *parent != ino { - break; - } - entries.push(DentryStat { - name: name.clone(), - meta: state.inode(*child)?, - }); - } - Ok(entries) - } - - async fn create( - &self, - parent: u64, - name: &str, - attrs: CreateInodeAttrs, - ) -> VfsResult { - let mut state = self.state.lock().expect("metadata mutex poisoned"); - let mut parent_meta = state.inode(parent)?; - if parent_meta.kind != InodeType::Directory { - return Err(VfsError::enotdir(format!("inode {parent}"))); - } - if state.dentries.contains_key(&(parent, name.to_string())) { - return Err(VfsError::eexist(name)); - } - let meta = state.alloc_inode(attrs); - let ino = meta.ino; - state.inodes.insert(ino, meta.clone()); - state.dentries.insert((parent, name.to_string()), ino); - State::now_touch(&mut parent_meta); - state.inodes.insert(parent, parent_meta); - Ok(meta) - } - - async fn link(&self, parent: u64, name: &str, target: u64) -> VfsResult<()> { - let mut state = self.state.lock().expect("metadata mutex poisoned"); - let parent_meta = state.inode(parent)?; - if parent_meta.kind != InodeType::Directory { - return Err(VfsError::enotdir(format!("inode {parent}"))); - } - if state.dentries.contains_key(&(parent, name.to_string())) { - return Err(VfsError::eexist(name)); - } - let target_meta = state - .inodes - .get_mut(&target) - .ok_or_else(|| VfsError::enoent(format!("inode {target}")))?; - if target_meta.kind == InodeType::Directory { - return Err(VfsError::eopnotsupp( - "hard links to directories are not supported", - )); - } - target_meta.nlink += 1; - target_meta.ctime = Timespec::now(); - state.dentries.insert((parent, name.to_string()), target); - Ok(()) - } - - async fn remove(&self, parent: u64, name: &str) -> VfsResult> { - self.state - .lock() - .expect("metadata mutex poisoned") - .remove_child(parent, name) - } - - async fn rename( - &self, - src_parent: u64, - src: &str, - dst_parent: u64, - dst: &str, - ) -> VfsResult> { - let mut state = self.state.lock().expect("metadata mutex poisoned"); - let child = state.name_child(src_parent, src)?; - let source_meta = state.inode(child)?; - if source_meta.kind == InodeType::Directory { - let descendant = state.collect_subtree(child)?.contains(&dst_parent); - if descendant { - return Err(VfsError::einval("cannot move a directory into itself")); - } - } - let mut freed = Vec::new(); - if state.dentries.contains_key(&(dst_parent, dst.to_string())) { - freed = state.remove_child(dst_parent, dst)?; - } - state.dentries.remove(&(src_parent, src.to_string())); - state.dentries.insert((dst_parent, dst.to_string()), child); - Ok(freed) - } - - async fn set_attr(&self, ino: u64, patch: InodePatch) -> VfsResult> { - let mut state = self.state.lock().expect("metadata mutex poisoned"); - let mut freed = Vec::new(); - if let Some(storage) = &patch.storage { - if matches!(storage, Storage::Inline(_) | Storage::None) { - state.drop_inode_content(ino, &mut freed); - } - } - let meta = state - .inodes - .get_mut(&ino) - .ok_or_else(|| VfsError::enoent(format!("inode {ino}")))?; - if let Some(mode) = patch.mode { - meta.mode = mode; - } - if let Some(uid) = patch.uid { - meta.uid = uid; - } - if let Some(gid) = patch.gid { - meta.gid = gid; - } - if let Some(atime) = patch.atime { - meta.atime = atime; - } - if let Some(mtime) = patch.mtime { - meta.mtime = mtime; - } - if let Some(storage) = patch.storage { - meta.size = match &storage { - Storage::Inline(data) => data.len() as u64, - Storage::Chunked { .. } => patch.size.unwrap_or(meta.size), - Storage::None => meta - .symlink_target - .as_ref() - .map_or(0, |target| target.len() as u64), - }; - meta.storage = storage; - } - if let Some(size) = patch.size { - meta.size = size; - } - meta.ctime = Timespec::now(); - Ok(freed) - } - - async fn commit_write( - &self, - ino: u64, - edits: Vec, - new_size: u64, - ) -> VfsResult> { - let mut state = self.state.lock().expect("metadata mutex poisoned"); - let meta = state.inode(ino)?; - let chunk_size = match meta.storage { - Storage::Chunked { chunk_size } => u64::from(chunk_size), - Storage::Inline(_) | Storage::None => DEFAULT_CHUNK_SIZE as u64, - }; - let mut freed = Vec::new(); - let keep_chunks = if new_size == 0 { - 0 - } else { - new_size.div_ceil(chunk_size) - }; - let truncated: Vec<(u64, BlockKey)> = state - .chunks - .range((ino, 0)..) - .take_while(|((chunk_ino, _), _)| *chunk_ino == ino) - .filter(|((_, index), _)| *index >= keep_chunks) - .map(|((_, index), chunk)| (*index, chunk.key.clone())) - .collect(); - for (index, key) in truncated { - state.chunks.remove(&(ino, index)); - state.dec_block_ref(&key, &mut freed); - } - for edit in edits { - if edit.index >= keep_chunks { - continue; - } - let key = edit.key.clone(); - if let Some(previous) = state.chunks.insert( - (ino, edit.index), - ChunkRef { - index: edit.index, - key: edit.key, - len: edit.len, - }, - ) { - if previous.key != key { - state.dec_block_ref(&previous.key, &mut freed); - state.inc_block_ref(&key); - } - } else { - state.inc_block_ref(&key); - } - } - let meta = state - .inodes - .get_mut(&ino) - .ok_or_else(|| VfsError::enoent(format!("inode {ino}")))?; - meta.size = new_size; - meta.ctime = Timespec::now(); - meta.mtime = meta.ctime; - Ok(freed) - } - - async fn get_chunks(&self, ino: u64, range: ChunkRange) -> VfsResult> { - let state = self.state.lock().expect("metadata mutex poisoned"); - state.inode(ino)?; - let mut chunks = Vec::new(); - for ((chunk_ino, index), chunk) in state.chunks.range((ino, range.start)..) { - if *chunk_ino != ino { - break; - } - if let Some(end) = range.end { - if *index >= end { - break; - } - } - chunks.push(chunk.clone()); - } - Ok(chunks) - } - - async fn snapshot(&self, root: u64) -> VfsResult { - let mut state = self.state.lock().expect("metadata mutex poisoned"); - let reachable = state.collect_subtree(root)?; - let mut inodes = BTreeMap::new(); - let mut dentries = BTreeMap::new(); - let mut chunks = BTreeMap::new(); - let mut keys_to_inc = Vec::new(); - for ino in reachable { - inodes.insert(ino, state.inode(ino)?); - for ((parent, name), child) in state.dentries.range((ino, String::new())..) { - if *parent != ino { - break; - } - dentries.insert((*parent, name.clone()), *child); - } - for ((chunk_ino, index), chunk) in &state.chunks { - if *chunk_ino == ino { - chunks.insert((*chunk_ino, *index), chunk.clone()); - keys_to_inc.push(chunk.key.clone()); - } - } - } - for key in keys_to_inc { - state.inc_block_ref(&key); - } - let id = SnapshotId(state.next_snapshot_id); - state.next_snapshot_id += 1; - state.snapshots.insert( - id, - Snapshot { - root_ino: root, - inodes, - dentries, - chunks, - }, - ); - Ok(id) - } - - async fn fork(&self, snap: SnapshotId) -> VfsResult { - let mut state = self.state.lock().expect("metadata mutex poisoned"); - let snapshot = state - .snapshots - .get(&snap) - .cloned() - .ok_or_else(|| VfsError::enoent(format!("snapshot {}", snap.0)))?; - let mut map = BTreeMap::new(); - for old_ino in snapshot.inodes.keys() { - let new_ino = state.next_ino; - state.next_ino += 1; - map.insert(*old_ino, new_ino); - } - for (old_ino, mut meta) in snapshot.inodes { - meta.ino = map[&old_ino]; - state.inodes.insert(meta.ino, meta); - } - for ((old_parent, name), old_child) in snapshot.dentries { - if let (Some(parent), Some(child)) = (map.get(&old_parent), map.get(&old_child)) { - state.dentries.insert((*parent, name), *child); - } - } - for ((old_ino, index), mut chunk) in snapshot.chunks { - if let Some(new_ino) = map.get(&old_ino) { - let key = chunk.key.clone(); - chunk.index = index; - state.chunks.insert((*new_ino, index), chunk); - state.inc_block_ref(&key); - } - } - Ok(map[&snapshot.root_ino]) - } - - async fn gc(&self) -> VfsResult> { - Ok(Vec::new()) - } -} diff --git a/crates/vfs/src/engine/mem/mod.rs b/crates/vfs/src/engine/mem/mod.rs deleted file mode 100644 index af731d266..000000000 --- a/crates/vfs/src/engine/mem/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod block_store; -pub mod metadata_store; -pub mod object_backend; - -pub use block_store::MemoryBlockStore; -pub use metadata_store::InMemoryMetadataStore; -pub use object_backend::MemoryObjectBackend; diff --git a/crates/vfs/src/engine/mem/object_backend.rs b/crates/vfs/src/engine/mem/object_backend.rs deleted file mode 100644 index 54b9fbf09..000000000 --- a/crates/vfs/src/engine/mem/object_backend.rs +++ /dev/null @@ -1,117 +0,0 @@ -use crate::engine::block::ObjectBackend; -use crate::engine::error::{VfsError, VfsResult}; -use crate::engine::types::{ObjectEntry, ObjectMeta}; -use async_trait::async_trait; -use std::collections::{BTreeMap, BTreeSet}; -use std::sync::{Arc, Mutex}; - -#[derive(Debug, Clone)] -struct StoredObject { - data: Vec, - meta: ObjectMeta, -} - -#[derive(Debug, Clone, Default)] -pub struct MemoryObjectBackend { - objects: Arc>>, -} - -impl MemoryObjectBackend { - pub fn new() -> Self { - Self::default() - } -} - -#[async_trait] -impl ObjectBackend for MemoryObjectBackend { - async fn list(&self, prefix: &str) -> VfsResult> { - let objects = self.objects.lock().expect("object mutex poisoned"); - let mut entries = Vec::new(); - let mut prefixes = BTreeSet::new(); - for (key, object) in objects.range(prefix.to_string()..) { - if !key.starts_with(prefix) { - break; - } - let rest = &key[prefix.len()..]; - if rest.is_empty() { - entries.push(ObjectEntry { - name: key.clone(), - size: object.meta.size, - mtime: object.meta.mtime, - is_prefix: false, - }); - continue; - } - if let Some((head, _)) = rest.split_once('/') { - prefixes.insert(format!("{prefix}{head}/")); - } else { - entries.push(ObjectEntry { - name: key.clone(), - size: object.meta.size, - mtime: object.meta.mtime, - is_prefix: false, - }); - } - } - entries.extend(prefixes.into_iter().map(|name| ObjectEntry { - name, - size: 0, - mtime: crate::engine::types::Timespec::now(), - is_prefix: true, - })); - Ok(entries) - } - - async fn head(&self, key: &str) -> VfsResult> { - Ok(self - .objects - .lock() - .expect("object mutex poisoned") - .get(key) - .map(|object| object.meta.clone())) - } - - async fn get_range(&self, key: &str, off: u64, len: u64) -> VfsResult> { - let objects = self.objects.lock().expect("object mutex poisoned"); - let object = objects.get(key).ok_or_else(|| VfsError::enoent(key))?; - let start = usize::try_from(off) - .map_err(|_| VfsError::einval(format!("range offset is too large: {off}")))?; - let len = usize::try_from(len) - .map_err(|_| VfsError::einval(format!("range length is too large: {len}")))?; - if start >= object.data.len() { - return Ok(Vec::new()); - } - let end = start.saturating_add(len).min(object.data.len()); - Ok(object.data[start..end].to_vec()) - } - - async fn put(&self, key: &str, data: &[u8], mut meta: ObjectMeta) -> VfsResult<()> { - meta.size = data.len() as u64; - self.objects.lock().expect("object mutex poisoned").insert( - key.to_string(), - StoredObject { - data: data.to_vec(), - meta, - }, - ); - Ok(()) - } - - async fn copy(&self, src: &str, dst: &str) -> VfsResult<()> { - let mut objects = self.objects.lock().expect("object mutex poisoned"); - let object = objects - .get(src) - .cloned() - .ok_or_else(|| VfsError::enoent(src))?; - objects.insert(dst.to_string(), object); - Ok(()) - } - - async fn delete(&self, key: &str) -> VfsResult<()> { - self.objects - .lock() - .expect("object mutex poisoned") - .remove(key); - Ok(()) - } -} diff --git a/crates/vfs/src/engine/metadata.rs b/crates/vfs/src/engine/metadata.rs deleted file mode 100644 index e56b9c5bd..000000000 --- a/crates/vfs/src/engine/metadata.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::engine::error::VfsResult; -use crate::engine::types::{ - BlockKey, ChunkEdit, ChunkRange, ChunkRef, CreateInodeAttrs, DentryStat, InodeMeta, InodePatch, - SnapshotId, -}; -use async_trait::async_trait; - -#[async_trait] -pub trait MetadataStore: Send + Sync { - async fn resolve(&self, path: &str) -> VfsResult; - async fn resolve_parent(&self, path: &str) -> VfsResult<(InodeMeta, String)>; - async fn lstat(&self, path: &str) -> VfsResult; - async fn list_dir(&self, ino: u64) -> VfsResult>; - - async fn create( - &self, - parent: u64, - name: &str, - attrs: CreateInodeAttrs, - ) -> VfsResult; - async fn link(&self, parent: u64, name: &str, target: u64) -> VfsResult<()>; - async fn remove(&self, parent: u64, name: &str) -> VfsResult>; - async fn rename( - &self, - src_parent: u64, - src: &str, - dst_parent: u64, - dst: &str, - ) -> VfsResult>; - async fn set_attr(&self, ino: u64, patch: InodePatch) -> VfsResult>; - async fn commit_write( - &self, - ino: u64, - edits: Vec, - new_size: u64, - ) -> VfsResult>; - - async fn get_chunks(&self, ino: u64, range: ChunkRange) -> VfsResult>; - - async fn snapshot(&self, root: u64) -> VfsResult; - async fn fork(&self, snap: SnapshotId) -> VfsResult; - async fn gc(&self) -> VfsResult>; -} diff --git a/crates/vfs/src/engine/mod.rs b/crates/vfs/src/engine/mod.rs deleted file mode 100644 index 0187fff4b..000000000 --- a/crates/vfs/src/engine/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod block; -pub mod cache; -pub mod engines; -pub mod error; -pub mod mem; -pub mod metadata; -pub mod types; -pub mod vfs; - -pub use block::{BlockStore, ObjectBackend}; -pub use cache::CachedMetadataStore; -pub use error::{VfsError, VfsResult}; -pub use mem::{InMemoryMetadataStore, MemoryBlockStore, MemoryObjectBackend}; -pub use metadata::MetadataStore; -pub use types::*; -pub use vfs::{Snapshottable, VirtualFileSystem}; diff --git a/crates/vfs/src/engine/types.rs b/crates/vfs/src/engine/types.rs deleted file mode 100644 index 77823f6b4..000000000 --- a/crates/vfs/src/engine/types.rs +++ /dev/null @@ -1,273 +0,0 @@ -use crate::engine::error::{VfsError, VfsResult}; -use serde::{Deserialize, Serialize}; -use web_time::{SystemTime, UNIX_EPOCH}; - -pub const MAX_PATH: usize = 4096; -pub const MAX_SYMLINK_DEPTH: usize = 40; -pub const DEFAULT_INLINE_THRESHOLD: usize = 64 * 1024; -pub const DEFAULT_CHUNK_SIZE: u32 = 4 * 1024 * 1024; - -pub const S_IFREG: u32 = 0o100000; -pub const S_IFDIR: u32 = 0o040000; -pub const S_IFLNK: u32 = 0o120000; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct Timespec { - pub sec: i64, - pub nsec: u32, -} - -impl Timespec { - pub fn now() -> Self { - let duration = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default(); - Self { - sec: duration.as_secs() as i64, - nsec: duration.subsec_nanos(), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub enum InodeType { - File, - Directory, - Symlink, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub enum Storage { - Inline(Vec), - Chunked { chunk_size: u32 }, - None, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct InodeMeta { - pub ino: u64, - pub kind: InodeType, - pub mode: u32, - pub uid: u32, - pub gid: u32, - pub size: u64, - pub nlink: u64, - pub atime: Timespec, - pub mtime: Timespec, - pub ctime: Timespec, - pub birthtime: Timespec, - pub storage: Storage, - pub symlink_target: Option, -} - -impl InodeMeta { - pub fn to_stat(&self) -> VirtualStat { - let type_bits = match self.kind { - InodeType::File => S_IFREG, - InodeType::Directory => S_IFDIR, - InodeType::Symlink => S_IFLNK, - }; - VirtualStat { - mode: type_bits | (self.mode & 0o7777), - size: self.size, - blocks: self.size.div_ceil(512), - is_directory: self.kind == InodeType::Directory, - is_symbolic_link: self.kind == InodeType::Symlink, - atime: self.atime, - mtime: self.mtime, - ctime: self.ctime, - birthtime: self.birthtime, - ino: self.ino, - nlink: self.nlink, - uid: self.uid, - gid: self.gid, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct Dentry { - pub name: String, - pub ino: u64, - pub kind: InodeType, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct DentryStat { - pub name: String, - pub meta: InodeMeta, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct VirtualStat { - pub mode: u32, - pub size: u64, - pub blocks: u64, - pub is_directory: bool, - pub is_symbolic_link: bool, - pub atime: Timespec, - pub mtime: Timespec, - pub ctime: Timespec, - pub birthtime: Timespec, - pub ino: u64, - pub nlink: u64, - pub uid: u32, - pub gid: u32, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct SnapshotId(pub u64); - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct BlockKey(pub String); - -impl BlockKey { - pub fn from_content(data: &[u8]) -> Self { - Self(blake3::hash(data).to_hex().to_string()) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -pub struct ChunkRange { - pub start: u64, - pub end: Option, -} - -impl ChunkRange { - pub fn all() -> Self { - Self { - start: 0, - end: None, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct ChunkRef { - pub index: u64, - pub key: BlockKey, - pub len: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct ChunkEdit { - pub index: u64, - pub key: BlockKey, - pub len: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct CreateInodeAttrs { - pub kind: InodeType, - pub mode: u32, - pub uid: u32, - pub gid: u32, - pub storage: Storage, - pub symlink_target: Option, -} - -impl CreateInodeAttrs { - pub fn file(mode: u32, uid: u32, gid: u32, storage: Storage) -> Self { - Self { - kind: InodeType::File, - mode, - uid, - gid, - storage, - symlink_target: None, - } - } - - pub fn directory(mode: u32, uid: u32, gid: u32) -> Self { - Self { - kind: InodeType::Directory, - mode, - uid, - gid, - storage: Storage::None, - symlink_target: None, - } - } - - pub fn symlink(target: String, uid: u32, gid: u32) -> Self { - Self { - kind: InodeType::Symlink, - mode: 0o777, - uid, - gid, - storage: Storage::None, - symlink_target: Some(target), - } - } -} - -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub struct InodePatch { - pub mode: Option, - pub uid: Option, - pub gid: Option, - pub atime: Option, - pub mtime: Option, - pub size: Option, - pub storage: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct ObjectMeta { - pub size: u64, - pub mtime: Timespec, - pub mode: u32, - pub uid: u32, - pub gid: u32, - pub kind: InodeType, - pub symlink_target: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct ObjectEntry { - pub name: String, - pub size: u64, - pub mtime: Timespec, - pub is_prefix: bool, -} - -pub fn validate_path(path: &str) -> VfsResult<()> { - if path.is_empty() || !path.starts_with('/') { - return Err(VfsError::einval(format!("path must be absolute: {path}"))); - } - if path.len() > MAX_PATH { - return Err(VfsError::enametoolong(path)); - } - Ok(()) -} - -pub fn normalize_path(path: &str) -> VfsResult { - validate_path(path)?; - let mut parts = Vec::new(); - for part in path.split('/') { - match part { - "" | "." => {} - ".." => { - parts.pop(); - } - name => parts.push(name), - } - } - if parts.is_empty() { - Ok("/".to_string()) - } else { - Ok(format!("/{}", parts.join("/"))) - } -} - -pub fn parent_and_name(path: &str) -> VfsResult<(String, String)> { - let normalized = normalize_path(path)?; - if normalized == "/" { - return Err(VfsError::einval("root has no parent")); - } - let (parent, name) = normalized - .rsplit_once('/') - .ok_or_else(|| VfsError::einval(format!("invalid path: {path}")))?; - let parent = if parent.is_empty() { "/" } else { parent }; - Ok((parent.to_string(), name.to_string())) -} diff --git a/crates/vfs/src/engine/vfs.rs b/crates/vfs/src/engine/vfs.rs deleted file mode 100644 index 43123b1de..000000000 --- a/crates/vfs/src/engine/vfs.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::engine::error::{VfsError, VfsResult}; -use crate::engine::types::{Dentry, SnapshotId, VirtualStat}; -use async_trait::async_trait; - -#[async_trait] -pub trait VirtualFileSystem: Send + Sync { - async fn read_file(&self, path: &str) -> VfsResult>; - - async fn read_text(&self, path: &str) -> VfsResult { - String::from_utf8(self.read_file(path).await?) - .map_err(|_| VfsError::einval(format!("file is not valid UTF-8: {path}"))) - } - - async fn read_dir(&self, path: &str) -> VfsResult>; - async fn read_dir_with_types(&self, path: &str) -> VfsResult>; - async fn write_file(&self, path: &str, content: &[u8]) -> VfsResult<()>; - async fn create_dir(&self, path: &str) -> VfsResult<()>; - async fn mkdir(&self, path: &str, recursive: bool) -> VfsResult<()>; - async fn exists(&self, path: &str) -> bool; - async fn stat(&self, path: &str) -> VfsResult; - async fn lstat(&self, path: &str) -> VfsResult; - async fn remove_file(&self, path: &str) -> VfsResult<()>; - async fn remove_dir(&self, path: &str) -> VfsResult<()>; - async fn rename(&self, old_path: &str, new_path: &str) -> VfsResult<()>; - async fn realpath(&self, path: &str) -> VfsResult; - async fn symlink(&self, target: &str, link_path: &str) -> VfsResult<()>; - async fn readlink(&self, path: &str) -> VfsResult; - async fn link(&self, old_path: &str, new_path: &str) -> VfsResult<()>; - async fn chmod(&self, path: &str, mode: u32) -> VfsResult<()>; - async fn chown(&self, path: &str, uid: u32, gid: u32) -> VfsResult<()>; - async fn utimes(&self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()>; - async fn truncate(&self, path: &str, length: u64) -> VfsResult<()>; - async fn pread(&self, path: &str, offset: u64, length: usize) -> VfsResult>; - async fn pwrite(&self, path: &str, content: &[u8], offset: u64) -> VfsResult<()>; - async fn append(&self, path: &str, content: &[u8]) -> VfsResult; -} - -#[async_trait] -pub trait Snapshottable: Send + Sync { - async fn snapshot(&self, root: u64) -> VfsResult; - async fn fork(&self, snap: SnapshotId) -> VfsResult; -} diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 69756f19a..fbbeb54da 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -1,6 +1,3 @@ -#![deny(unsafe_code)] +//! Compatibility shim for `agentos-vfs`. -#[cfg(not(target_arch = "wasm32"))] -pub mod adapter; -pub mod engine; -pub mod posix; +pub use agentos_vfs::*; diff --git a/crates/vfs/src/posix/mod.rs b/crates/vfs/src/posix/mod.rs deleted file mode 100644 index 05e376bd6..000000000 --- a/crates/vfs/src/posix/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -pub mod mount_plugin; -pub mod mount_table; -pub mod overlay_fs; -pub mod root_fs; -pub mod single_symlink_fs; -#[cfg(not(target_arch = "wasm32"))] -pub mod tar_fs; -pub mod usage; -pub mod vfs; - -pub use mount_plugin::{ - FileSystemPluginFactory, FileSystemPluginRegistry, OpenFileSystemPluginRequest, PluginError, -}; -pub use mount_table::{ - MountEntry, MountOptions, MountTable, MountedFileSystem, MountedVirtualFileSystem, - ReadOnlyFileSystem, -}; -pub use overlay_fs::{OverlayFileSystem, OverlayMode}; -pub use root_fs::*; -pub use single_symlink_fs::SingleSymlinkFileSystem; -#[cfg(not(target_arch = "wasm32"))] -pub use tar_fs::TarFileSystem; -pub use usage::{ - measure_filesystem_usage, FileSystemUsage, RootFilesystemResourceLimits, - DEFAULT_MAX_FILESYSTEM_BYTES, DEFAULT_MAX_INODE_COUNT, -}; -pub use vfs::*; diff --git a/crates/vfs/src/posix/mount_plugin.rs b/crates/vfs/src/posix/mount_plugin.rs deleted file mode 100644 index 5c475fe78..000000000 --- a/crates/vfs/src/posix/mount_plugin.rs +++ /dev/null @@ -1,139 +0,0 @@ -use super::mount_table::MountedFileSystem; -use super::vfs::VfsError; -use serde_json::Value; -use std::collections::BTreeMap; -use std::error::Error; -use std::fmt; - -#[derive(Debug)] -pub struct OpenFileSystemPluginRequest<'a, Context> { - pub vm_id: &'a str, - pub guest_path: &'a str, - pub read_only: bool, - pub config: &'a Value, - pub context: &'a Context, -} - -pub trait FileSystemPluginFactory: Send + Sync { - fn plugin_id(&self) -> &'static str; - fn open( - &self, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError>; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PluginError { - code: &'static str, - message: String, -} - -impl PluginError { - pub fn code(&self) -> &'static str { - self.code - } - - pub fn message(&self) -> &str { - &self.message - } - - pub fn new(code: &'static str, message: impl Into) -> Self { - Self { - code, - message: message.into(), - } - } - - pub fn unsupported(message: impl Into) -> Self { - Self::new("ENOSYS", message) - } - - pub fn invalid_input(message: impl Into) -> Self { - Self::new("EINVAL", message) - } - - pub fn already_exists(message: impl Into) -> Self { - Self::new("EEXIST", message) - } -} - -impl fmt::Display for PluginError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for PluginError {} - -impl From for PluginError { - fn from(error: VfsError) -> Self { - Self::new(error.code(), error.message().to_owned()) - } -} - -pub struct FileSystemPluginRegistry { - factories: BTreeMap>>, -} - -impl Default for FileSystemPluginRegistry { - fn default() -> Self { - Self::new() - } -} - -impl FileSystemPluginRegistry { - pub fn new() -> Self { - Self { - factories: BTreeMap::new(), - } - } - - pub fn register( - &mut self, - factory: impl FileSystemPluginFactory + 'static, - ) -> Result<(), PluginError> { - let plugin_id = factory.plugin_id(); - validate_plugin_id(plugin_id)?; - if self.factories.contains_key(plugin_id) { - return Err(PluginError::already_exists(format!( - "filesystem plugin already registered: {plugin_id}" - ))); - } - - self.factories - .insert(plugin_id.to_owned(), Box::new(factory)); - Ok(()) - } - - pub fn open( - &self, - plugin_id: &str, - request: OpenFileSystemPluginRequest<'_, Context>, - ) -> Result, PluginError> { - let Some(factory) = self.factories.get(plugin_id) else { - return Err(PluginError::unsupported(format!( - "filesystem plugin is not registered: {plugin_id}" - ))); - }; - - factory.open(request) - } - - pub fn plugin_ids(&self) -> Vec { - self.factories.keys().cloned().collect() - } -} - -fn validate_plugin_id(plugin_id: &str) -> Result<(), PluginError> { - if plugin_id.is_empty() - || !plugin_id - .bytes() - .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-')) - { - return Err(PluginError::invalid_input(format!( - "invalid filesystem plugin id {plugin_id:?}" - ))); - } - - Ok(()) -} diff --git a/crates/vfs/src/posix/mount_table.rs b/crates/vfs/src/posix/mount_table.rs deleted file mode 100644 index 9f556970a..000000000 --- a/crates/vfs/src/posix/mount_table.rs +++ /dev/null @@ -1,1356 +0,0 @@ -use super::root_fs::RootFileSystem; -use super::usage::FileSystemUsage; -use super::vfs::{ - VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, VirtualUtimeSpec, -}; -use std::any::Any; -use std::collections::BTreeSet; -use std::collections::VecDeque; -use std::path::{Component, Path}; -use web_time::{SystemTime, UNIX_EPOCH}; - -const MAX_REALPATH_SYMLINKS: usize = 40; - -pub trait MountedFileSystem: Any { - fn as_any(&self) -> &dyn Any; - fn as_any_mut(&mut self) -> &mut dyn Any; - fn read_file(&mut self, path: &str) -> VfsResult>; - fn read_dir(&mut self, path: &str) -> VfsResult>; - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - let entries = self.read_dir(path)?; - if entries.len() > max_entries { - return Err(VfsError::new( - "ENOMEM", - format!( - "directory listing for '{path}' exceeds configured limit of {max_entries} entries" - ), - )); - } - Ok(entries) - } - fn read_dir_with_types(&mut self, path: &str) -> VfsResult>; - fn write_file(&mut self, path: &str, content: Vec) -> VfsResult<()>; - fn write_file_with_mode( - &mut self, - path: &str, - content: Vec, - mode: Option, - ) -> VfsResult<()> { - let _ = mode; - self.write_file(path, content) - } - fn create_file_exclusive(&mut self, path: &str, content: Vec) -> VfsResult<()> { - if self.exists(path) { - return Err(VfsError::new( - "EEXIST", - format!("file already exists, open '{path}'"), - )); - } - self.write_file(path, content) - } - fn create_file_exclusive_with_mode( - &mut self, - path: &str, - content: Vec, - mode: Option, - ) -> VfsResult<()> { - let _ = mode; - self.create_file_exclusive(path, content) - } - fn append_file(&mut self, path: &str, content: Vec) -> VfsResult { - let mut existing = self.read_file(path)?; - existing.extend_from_slice(&content); - let new_len = existing.len() as u64; - self.write_file(path, existing)?; - Ok(new_len) - } - fn create_dir(&mut self, path: &str) -> VfsResult<()>; - fn create_dir_with_mode(&mut self, path: &str, mode: Option) -> VfsResult<()> { - let _ = mode; - self.create_dir(path) - } - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()>; - fn mkdir_with_mode(&mut self, path: &str, recursive: bool, mode: Option) -> VfsResult<()> { - let _ = mode; - self.mkdir(path, recursive) - } - fn exists(&self, path: &str) -> bool; - fn stat(&mut self, path: &str) -> VfsResult; - fn remove_file(&mut self, path: &str) -> VfsResult<()>; - fn remove_dir(&mut self, path: &str) -> VfsResult<()>; - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()>; - fn realpath(&self, path: &str) -> VfsResult; - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()>; - fn read_link(&self, path: &str) -> VfsResult; - fn lstat(&self, path: &str) -> VfsResult; - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()>; - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()>; - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()>; - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()>; - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - if !follow_symlinks { - return Err(VfsError::unsupported(format!( - "lutimes is not supported for mount path '{path}'" - ))); - } - let existing = match (atime, mtime) { - (VirtualUtimeSpec::Omit, _) | (_, VirtualUtimeSpec::Omit) => Some(self.stat(path)?), - _ => None, - }; - let now_ms = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as u64; - let atime_ms = match atime { - VirtualUtimeSpec::Set(spec) => spec.to_truncated_millis()?, - VirtualUtimeSpec::Now => now_ms, - VirtualUtimeSpec::Omit => { - existing - .as_ref() - .ok_or_else(|| { - VfsError::new("EINVAL", "UTIME_OMIT requires existing metadata") - })? - .atime_ms - } - }; - let mtime_ms = match mtime { - VirtualUtimeSpec::Set(spec) => spec.to_truncated_millis()?, - VirtualUtimeSpec::Now => now_ms, - VirtualUtimeSpec::Omit => { - existing - .as_ref() - .ok_or_else(|| { - VfsError::new("EINVAL", "UTIME_OMIT requires existing metadata") - })? - .mtime_ms - } - }; - self.utimes(path, atime_ms, mtime_ms) - } - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()>; - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult>; - fn shutdown(&mut self) -> VfsResult<()> { - Ok(()) - } -} - -pub struct MountedVirtualFileSystem { - inner: F, -} - -impl MountedVirtualFileSystem { - pub fn new(inner: F) -> Self { - Self { inner } - } - - pub fn inner(&self) -> &F { - &self.inner - } - - pub fn inner_mut(&mut self) -> &mut F { - &mut self.inner - } -} - -impl MountedFileSystem for MountedVirtualFileSystem -where - F: VirtualFileSystem + 'static, -{ - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } - - fn read_file(&mut self, path: &str) -> VfsResult> { - VirtualFileSystem::read_file(&mut self.inner, path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - VirtualFileSystem::read_dir(&mut self.inner, path) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - VirtualFileSystem::read_dir_limited(&mut self.inner, path, max_entries) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - VirtualFileSystem::read_dir_with_types(&mut self.inner, path) - } - - fn write_file(&mut self, path: &str, content: Vec) -> VfsResult<()> { - VirtualFileSystem::write_file(&mut self.inner, path, content) - } - - fn write_file_with_mode( - &mut self, - path: &str, - content: Vec, - mode: Option, - ) -> VfsResult<()> { - VirtualFileSystem::write_file_with_mode(&mut self.inner, path, content, mode) - } - - fn create_file_exclusive(&mut self, path: &str, content: Vec) -> VfsResult<()> { - VirtualFileSystem::create_file_exclusive(&mut self.inner, path, content) - } - - fn create_file_exclusive_with_mode( - &mut self, - path: &str, - content: Vec, - mode: Option, - ) -> VfsResult<()> { - VirtualFileSystem::create_file_exclusive_with_mode(&mut self.inner, path, content, mode) - } - - fn append_file(&mut self, path: &str, content: Vec) -> VfsResult { - VirtualFileSystem::append_file(&mut self.inner, path, content) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - VirtualFileSystem::create_dir(&mut self.inner, path) - } - - fn create_dir_with_mode(&mut self, path: &str, mode: Option) -> VfsResult<()> { - VirtualFileSystem::create_dir_with_mode(&mut self.inner, path, mode) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - VirtualFileSystem::mkdir(&mut self.inner, path, recursive) - } - - fn mkdir_with_mode(&mut self, path: &str, recursive: bool, mode: Option) -> VfsResult<()> { - VirtualFileSystem::mkdir_with_mode(&mut self.inner, path, recursive, mode) - } - - fn exists(&self, path: &str) -> bool { - VirtualFileSystem::exists(&self.inner, path) - } - - fn stat(&mut self, path: &str) -> VfsResult { - VirtualFileSystem::stat(&mut self.inner, path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - VirtualFileSystem::remove_file(&mut self.inner, path) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - VirtualFileSystem::remove_dir(&mut self.inner, path) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - VirtualFileSystem::rename(&mut self.inner, old_path, new_path) - } - - fn realpath(&self, path: &str) -> VfsResult { - VirtualFileSystem::realpath(&self.inner, path) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - VirtualFileSystem::symlink(&mut self.inner, target, link_path) - } - - fn read_link(&self, path: &str) -> VfsResult { - VirtualFileSystem::read_link(&self.inner, path) - } - - fn lstat(&self, path: &str) -> VfsResult { - VirtualFileSystem::lstat(&self.inner, path) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - VirtualFileSystem::link(&mut self.inner, old_path, new_path) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - VirtualFileSystem::chmod(&mut self.inner, path, mode) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - VirtualFileSystem::chown(&mut self.inner, path, uid, gid) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - VirtualFileSystem::utimes(&mut self.inner, path, atime_ms, mtime_ms) - } - - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - VirtualFileSystem::utimes_spec(&mut self.inner, path, atime, mtime, follow_symlinks) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - VirtualFileSystem::truncate(&mut self.inner, path, length) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - VirtualFileSystem::pread(&mut self.inner, path, offset, length) - } -} - -impl MountedFileSystem for Box -where - T: MountedFileSystem + ?Sized + 'static, -{ - fn as_any(&self) -> &dyn Any { - (**self).as_any() - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - (**self).as_any_mut() - } - - fn read_file(&mut self, path: &str) -> VfsResult> { - (**self).read_file(path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - (**self).read_dir(path) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - (**self).read_dir_limited(path, max_entries) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - (**self).read_dir_with_types(path) - } - - fn write_file(&mut self, path: &str, content: Vec) -> VfsResult<()> { - (**self).write_file(path, content) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - (**self).create_dir(path) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - (**self).mkdir(path, recursive) - } - - fn exists(&self, path: &str) -> bool { - (**self).exists(path) - } - - fn stat(&mut self, path: &str) -> VfsResult { - (**self).stat(path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - (**self).remove_file(path) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - (**self).remove_dir(path) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - (**self).rename(old_path, new_path) - } - - fn realpath(&self, path: &str) -> VfsResult { - (**self).realpath(path) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - (**self).symlink(target, link_path) - } - - fn read_link(&self, path: &str) -> VfsResult { - (**self).read_link(path) - } - - fn lstat(&self, path: &str) -> VfsResult { - (**self).lstat(path) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - (**self).link(old_path, new_path) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - (**self).chmod(path, mode) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - (**self).chown(path, uid, gid) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - (**self).utimes(path, atime_ms, mtime_ms) - } - - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - (**self).utimes_spec(path, atime, mtime, follow_symlinks) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - (**self).truncate(path, length) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - (**self).pread(path, offset, length) - } - - fn shutdown(&mut self) -> VfsResult<()> { - (**self).shutdown() - } -} - -pub struct ReadOnlyFileSystem { - inner: F, -} - -impl ReadOnlyFileSystem { - pub fn new(inner: F) -> Self { - Self { inner } - } -} - -impl MountedFileSystem for ReadOnlyFileSystem -where - F: MountedFileSystem + 'static, -{ - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } - - fn read_file(&mut self, path: &str) -> VfsResult> { - self.inner.read_file(path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - self.inner.read_dir(path) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - self.inner.read_dir_limited(path, max_entries) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - self.inner.read_dir_with_types(path) - } - - fn write_file(&mut self, path: &str, _content: Vec) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn mkdir(&mut self, path: &str, _recursive: bool) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn exists(&self, path: &str) -> bool { - self.inner.exists(path) - } - - fn stat(&mut self, path: &str) -> VfsResult { - self.inner.stat(path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn rename(&mut self, old_path: &str, _new_path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {old_path}"), - )) - } - - fn realpath(&self, path: &str) -> VfsResult { - self.inner.realpath(path) - } - - fn symlink(&mut self, _target: &str, link_path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {link_path}"), - )) - } - - fn read_link(&self, path: &str) -> VfsResult { - self.inner.read_link(path) - } - - fn lstat(&self, path: &str) -> VfsResult { - self.inner.lstat(path) - } - - fn link(&mut self, _old_path: &str, new_path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {new_path}"), - )) - } - - fn chmod(&mut self, path: &str, _mode: u32) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn chown(&mut self, path: &str, _uid: u32, _gid: u32) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn utimes(&mut self, path: &str, _atime_ms: u64, _mtime_ms: u64) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn utimes_spec( - &mut self, - path: &str, - _atime: VirtualUtimeSpec, - _mtime: VirtualUtimeSpec, - _follow_symlinks: bool, - ) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn truncate(&mut self, path: &str, _length: u64) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only filesystem: {path}"), - )) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - self.inner.pread(path, offset, length) - } - - fn shutdown(&mut self) -> VfsResult<()> { - self.inner.shutdown() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MountEntry { - pub path: String, - pub plugin_id: String, - pub read_only: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MountOptions { - pub plugin_id: String, - pub read_only: bool, -} - -impl MountOptions { - pub fn new(plugin_id: impl Into) -> Self { - Self { - plugin_id: plugin_id.into(), - read_only: false, - } - } - - pub fn read_only(mut self, read_only: bool) -> Self { - self.read_only = read_only; - self - } -} - -struct MountRegistration { - path: String, - plugin_id: String, - read_only: bool, - filesystem: Box, -} - -pub struct MountTable { - mounts: Vec, -} - -impl MountTable { - pub fn new(root_fs: impl VirtualFileSystem + 'static) -> Self { - Self { - mounts: vec![MountRegistration { - path: String::from("/"), - plugin_id: String::from("root"), - read_only: false, - filesystem: Box::new(MountedVirtualFileSystem::new(root_fs)), - }], - } - } - - pub fn new_boxed_root(filesystem: Box, options: MountOptions) -> Self { - let filesystem = if options.read_only { - Box::new(ReadOnlyFileSystem::new(filesystem)) as Box - } else { - filesystem - }; - - Self { - mounts: vec![MountRegistration { - path: String::from("/"), - plugin_id: options.plugin_id, - read_only: options.read_only, - filesystem, - }], - } - } - - pub fn mount( - &mut self, - path: &str, - filesystem: impl VirtualFileSystem + 'static, - options: MountOptions, - ) -> VfsResult<()> { - self.mount_boxed( - path, - Box::new(MountedVirtualFileSystem::new(filesystem)), - options, - ) - } - - pub fn mount_boxed( - &mut self, - path: &str, - mut filesystem: Box, - options: MountOptions, - ) -> VfsResult<()> { - let normalized = normalize_path(path); - if normalized == "/" { - return Err(VfsError::new("EINVAL", "cannot mount over root")); - } - if self.mounts.iter().any(|mount| mount.path == normalized) { - return Err(VfsError::new( - "EEXIST", - format!("already mounted at {normalized}"), - )); - } - - let (parent_index, relative_path) = self.resolve_index(&normalized)?; - let parent_mount = &mut self.mounts[parent_index]; - if !parent_mount.filesystem.exists(&relative_path) { - // Materializing the mountpoint directory on the parent is - // cosmetic: child mounts resolve by path prefix before the parent - // is consulted. A read-only parent (for example a read-only - // module-access mount hosting nested package mounts) cannot - // materialize the entry, but the mount must still succeed. - if let Err(error) = parent_mount.filesystem.mkdir(&relative_path, true) { - if error.code() != "EROFS" { - if let Err(shutdown_error) = filesystem.shutdown() { - return Err(VfsError::new( - shutdown_error.code(), - format!( - "failed to shut down filesystem after mount failure ({error}): {}", - shutdown_error.message() - ), - )); - } - - return Err(error); - } - } - } - - let filesystem = if options.read_only { - Box::new(ReadOnlyFileSystem::new(filesystem)) as Box - } else { - filesystem - }; - - self.mounts.push(MountRegistration { - path: normalized, - plugin_id: options.plugin_id, - read_only: options.read_only, - filesystem, - }); - self.mounts - .sort_by_key(|mount| std::cmp::Reverse(mount.path.len())); - Ok(()) - } - - pub fn unmount(&mut self, path: &str) -> VfsResult<()> { - let normalized = normalize_path(path); - if normalized == "/" { - return Err(VfsError::new("EINVAL", "cannot unmount root")); - } - - let child_mount_prefix = format!("{normalized}/"); - if self - .mounts - .iter() - .any(|mount| mount.path.starts_with(&child_mount_prefix)) - { - return Err(VfsError::new( - "EBUSY", - format!("mount point has child mounts: {normalized}"), - )); - } - - let Some(index) = self - .mounts - .iter() - .position(|mount| mount.path == normalized) - else { - return Err(VfsError::new( - "EINVAL", - format!("not a mount point: {normalized}"), - )); - }; - - let mut mount = self.mounts.remove(index); - mount.filesystem.shutdown()?; - Ok(()) - } - - pub fn get_mounts(&self) -> Vec { - self.mounts - .iter() - .map(|mount| MountEntry { - path: mount.path.clone(), - plugin_id: mount.plugin_id.clone(), - read_only: mount.read_only, - }) - .collect() - } - - pub fn root_virtual_filesystem_mut( - &mut self, - ) -> Option<&mut T> { - let root = self.mounts.iter_mut().find(|mount| mount.path == "/")?; - root.filesystem - .as_any_mut() - .downcast_mut::>() - .map(MountedVirtualFileSystem::inner_mut) - } - - pub fn check_rename_copy_up_limits( - &mut self, - old_path: &str, - new_path: &str, - max_bytes: Option, - max_inodes: Option, - ) -> VfsResult<()> { - let (old_index, old_relative_path) = self.resolve_index(old_path)?; - let (new_index, new_relative_path) = self.resolve_index(new_path)?; - if old_index != new_index { - return Ok(()); - } - - let filesystem = &mut self.mounts[old_index].filesystem; - if let Some(root) = filesystem - .as_any_mut() - .downcast_mut::>() - { - root.inner_mut().check_rename_copy_up_limits( - &old_relative_path, - &new_relative_path, - max_bytes, - max_inodes, - )?; - } - - Ok(()) - } - - pub fn root_usage(&mut self) -> VfsResult { - let root = self - .mounts - .iter_mut() - .find(|mount| mount.path == "/") - .ok_or_else(|| VfsError::new("ENOENT", "missing root mount"))?; - measure_mounted_filesystem_usage(root.filesystem.as_mut(), "/", &mut BTreeSet::new()) - } - - fn resolve_index(&self, full_path: &str) -> VfsResult<(usize, String)> { - let normalized = normalize_path(full_path); - for (index, mount) in self.mounts.iter().enumerate() { - if mount.path == "/" { - return Ok((index, normalized)); - } - if normalized == mount.path { - return Ok((index, String::from("/"))); - } - let mount_prefix = format!("{}/", mount.path); - if let Some(suffix) = normalized.strip_prefix(&mount_prefix) { - // Strip exactly the mount prefix once. `trim_start_matches` would - // strip every leading repetition of `mount.path`, so a path like - // `/data/data/file` under mount `/data` would alias to `/file` - // instead of `/data/file`, routing reads/writes to the wrong file. - return Ok((index, format!("/{suffix}"))); - } - } - - Err(VfsError::new( - "ENOENT", - format!("no such file or directory, resolve '{full_path}'"), - )) - } - - /// Resolve a path for a CONTENT operation (read_file/stat/pread/read_dir) - /// that must follow symlinks like POSIX `open()`. `resolve_index` is purely - /// lexical, so a path that descends through a symlink whose target lives in a - /// *different* mount (e.g. `/opt/agentos/pkgs//current -> `, - /// where `current` is its own single-symlink leaf mount) would route into the - /// symlink mount and fail. `realpath` follows those cross-mount symlinks, so - /// resolve it first, then route the resolved path. Falls back to the raw path - /// when realpath can't resolve it (e.g. a genuinely missing file) so callers - /// still receive the mount's own ENOENT. - /// True only for the tar-vfs single-symlink-root leaf mount (`/current -> - /// ` and the `bin/` links), whose root inode IS a symlink. Only - /// these mounts need cross-mount realpath resolution for content ops and the - /// ENOENT->component-walk fallback; every other mount serves its own paths and - /// MUST keep its native error semantics (e.g. a js_bridge mount's ENOENT/EIO), - /// so gating on the concrete leaf type leaves normal mounts untouched. - fn mount_is_symlink_leaf(&self, index: usize) -> bool { - // Behavioral check (robust through the ReadOnly/MountedVirtual wrappers the - // projection applies): a leaf whose root inode is itself a symbolic link. - // Only the tar-vfs `/current -> ` and `bin/` single-symlink - // mounts satisfy this; every normal mount's root is a directory. - self.mounts[index] - .filesystem - .lstat("/") - .map(|stat| stat.is_symbolic_link) - .unwrap_or(false) - } - - fn resolve_content_index(&self, path: &str) -> VfsResult<(usize, String)> { - let raw = self.resolve_index(&normalize_path(path))?; - if !self.mount_is_symlink_leaf(raw.0) { - return Ok(raw); - } - // The leaf's root is a symlink, so a descendant path must be followed across - // the mount boundary to the real version tree before the content op runs. - match self.realpath(path) { - Ok(resolved) => self.resolve_index(&resolved), - Err(_) => Ok(raw), - } - } - - fn child_mount_basenames(&self, path: &str) -> Vec { - let normalized = normalize_path(path); - let mut basenames = BTreeSet::new(); - for mount in &self.mounts { - if mount.path == "/" || mount.path == normalized { - continue; - } - - if parent_path(&mount.path) == normalized { - basenames.insert(basename(&mount.path)); - } - } - basenames.into_iter().collect() - } - - fn realpath_in_mount(&self, index: usize, relative_path: &str) -> VfsResult { - let mount = &self.mounts[index]; - let resolved = mount.filesystem.realpath(relative_path)?; - if mount.path == "/" { - return Ok(normalize_path(&resolved)); - } - if resolved == "/" { - return Ok(mount.path.clone()); - } - Ok(normalize_path(&format!( - "{}/{}", - mount.path, - resolved.trim_start_matches('/') - ))) - } -} - -fn measure_mounted_filesystem_usage( - filesystem: &mut dyn MountedFileSystem, - path: &str, - visited: &mut BTreeSet, -) -> VfsResult { - let stat = filesystem.lstat(path)?; - let mut usage = FileSystemUsage::default(); - - if visited.insert(stat.ino) { - usage.inode_count += 1; - if !stat.is_directory { - usage.total_bytes = usage.total_bytes.saturating_add(stat.size); - } - } - - if !stat.is_directory || stat.is_symbolic_link { - return Ok(usage); - } - - for entry in filesystem.read_dir_with_types(path)? { - if matches!(entry.name.as_str(), "." | "..") { - continue; - } - - let child_path = if path == "/" { - format!("/{}", entry.name) - } else { - format!("{path}/{}", entry.name) - }; - let child_usage = measure_mounted_filesystem_usage(filesystem, &child_path, visited)?; - usage.total_bytes = usage.total_bytes.saturating_add(child_usage.total_bytes); - usage.inode_count = usage.inode_count.saturating_add(child_usage.inode_count); - } - - Ok(usage) -} - -impl Drop for MountTable { - fn drop(&mut self) { - for mount in self.mounts.iter_mut().rev() { - let _ = mount.filesystem.shutdown(); - } - } -} - -impl VirtualFileSystem for MountTable { - fn read_file(&mut self, path: &str) -> VfsResult> { - let (index, relative_path) = self.resolve_content_index(path)?; - self.mounts[index].filesystem.read_file(&relative_path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - let normalized = normalize_path(path); - let (index, relative_path) = self.resolve_index(&normalized)?; - let mut entries = self.mounts[index].filesystem.read_dir(&relative_path)?; - let child_mounts = self.child_mount_basenames(&normalized); - if child_mounts.is_empty() { - return Ok(entries); - } - - let mut merged = BTreeSet::new(); - merged.extend(entries.drain(..)); - merged.extend(child_mounts); - Ok(merged.into_iter().collect()) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - let normalized = normalize_path(path); - let (index, relative_path) = self.resolve_index(&normalized)?; - let mut entries = self.mounts[index] - .filesystem - .read_dir_limited(&relative_path, max_entries)?; - let child_mounts = self.child_mount_basenames(&normalized); - if child_mounts.is_empty() { - return Ok(entries); - } - - let mut merged = BTreeSet::new(); - merged.extend(entries.drain(..)); - merged.extend(child_mounts); - if merged.len() > max_entries { - return Err(VfsError::new( - "ENOMEM", - format!( - "directory listing for '{path}' exceeds configured limit of {max_entries} entries" - ), - )); - } - Ok(merged.into_iter().collect()) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - let normalized = normalize_path(path); - let (index, relative_path) = self.resolve_index(&normalized)?; - let mut entries = self.mounts[index] - .filesystem - .read_dir_with_types(&relative_path)?; - let child_mounts = self.child_mount_basenames(&normalized); - if child_mounts.is_empty() { - return Ok(entries); - } - - let existing = entries - .iter() - .map(|entry| entry.name.clone()) - .collect::>(); - for mount_name in child_mounts { - if existing.contains(&mount_name) { - continue; - } - entries.push(VirtualDirEntry { - name: mount_name, - is_directory: true, - is_symbolic_link: false, - }); - } - Ok(entries) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .write_file(&relative_path, content.into()) - } - - fn write_file_with_mode( - &mut self, - path: &str, - content: impl Into>, - mode: Option, - ) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .write_file_with_mode(&relative_path, content.into(), mode) - } - - fn create_file_exclusive(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .create_file_exclusive(&relative_path, content.into()) - } - - fn create_file_exclusive_with_mode( - &mut self, - path: &str, - content: impl Into>, - mode: Option, - ) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .create_file_exclusive_with_mode(&relative_path, content.into(), mode) - } - - fn append_file(&mut self, path: &str, content: impl Into>) -> VfsResult { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .append_file(&relative_path, content.into()) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index].filesystem.create_dir(&relative_path) - } - - fn create_dir_with_mode(&mut self, path: &str, mode: Option) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .create_dir_with_mode(&relative_path, mode) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .mkdir(&relative_path, recursive) - } - - fn mkdir_with_mode(&mut self, path: &str, recursive: bool, mode: Option) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .mkdir_with_mode(&relative_path, recursive, mode) - } - - fn exists(&self, path: &str) -> bool { - self.resolve_index(path) - .map(|(index, relative_path)| self.mounts[index].filesystem.exists(&relative_path)) - .unwrap_or(false) - } - - fn stat(&mut self, path: &str) -> VfsResult { - let (index, relative_path) = self.resolve_content_index(path)?; - self.mounts[index].filesystem.stat(&relative_path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index].filesystem.remove_file(&relative_path) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index].filesystem.remove_dir(&relative_path) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let (old_index, old_relative_path) = self.resolve_index(old_path)?; - let (new_index, new_relative_path) = self.resolve_index(new_path)?; - if old_index != new_index { - return Err(VfsError::new( - "EXDEV", - format!("rename across mounts: {old_path} -> {new_path}"), - )); - } - - self.mounts[old_index] - .filesystem - .rename(&old_relative_path, &new_relative_path) - } - - fn realpath(&self, path: &str) -> VfsResult { - let normalized = normalize_path(path); - let (index, relative_path) = self.resolve_index(&normalized)?; - match self.realpath_in_mount(index, &relative_path) { - Ok(resolved) => return Ok(resolved), - // Always fall back to the component walk on ELOOP. Fall back on ENOENT - // ONLY for a single-symlink LEAF mount (e.g. `/current -> `): - // it cannot resolve a descendant path itself — its root IS the symlink, so - // a subpath resolves into it and ENOENTs; the walk then follows that - // symlink across mounts. For every OTHER mount an ENOENT is a genuine - // "missing file" that must propagate unchanged (walking it would rewrite a - // mount's native ENOENT into a spurious success/EIO — see the js_bridge - // errno-mapping mount). Non-leaf within-mount paths resolve via - // `realpath_in_mount` above and return early, so pnpm resolution is - // unaffected either way. - Err(error) if error.code() == "ELOOP" => {} - Err(error) if error.code() == "ENOENT" && self.mount_is_symlink_leaf(index) => {} - Err(error) => return Err(error), - } - - let mut pending = path_components(&normalized); - let mut current = String::from("/"); - let mut followed_symlinks = 0usize; - - while let Some(component) = pending.pop_front() { - let candidate = join_path(¤t, &component); - let stat = self.lstat(&candidate)?; - - if stat.is_symbolic_link { - followed_symlinks += 1; - if followed_symlinks > MAX_REALPATH_SYMLINKS { - return Err(VfsError::new( - "ELOOP", - format!("too many levels of symbolic links, '{path}'"), - )); - } - - let target = self.read_link(&candidate)?; - let target_path = if target.starts_with('/') { - normalize_path(&target) - } else { - normalize_path(&format!("{}/{}", parent_path(&candidate), target)) - }; - let mut resolved_target = path_components(&target_path); - resolved_target.extend(pending); - pending = resolved_target; - current = String::from("/"); - continue; - } - - if !pending.is_empty() && !stat.is_directory { - return Err(VfsError::new( - "ENOTDIR", - format!("not a directory, realpath '{candidate}'"), - )); - } - - current = candidate; - } - - Ok(current) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - let normalized_link_path = normalize_path(link_path); - let link_parent = parent_path(&normalized_link_path); - let absolute_target = if target.starts_with('/') { - normalize_path(target) - } else { - normalize_path(&format!("{link_parent}/{target}")) - }; - - let (index, relative_path) = self.resolve_index(&normalized_link_path)?; - let (target_index, _) = self.resolve_index(&absolute_target)?; - if index != target_index { - return Err(VfsError::new( - "EXDEV", - format!("symlink across mounts: {link_path} -> {target}"), - )); - } - - self.mounts[index] - .filesystem - .symlink(target, &relative_path) - } - - fn read_link(&self, path: &str) -> VfsResult { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index].filesystem.read_link(&relative_path) - } - - fn lstat(&self, path: &str) -> VfsResult { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index].filesystem.lstat(&relative_path) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let (old_index, old_relative_path) = self.resolve_index(old_path)?; - let (new_index, new_relative_path) = self.resolve_index(new_path)?; - if old_index != new_index { - return Err(VfsError::new( - "EXDEV", - format!("link across mounts: {old_path} -> {new_path}"), - )); - } - - self.mounts[old_index] - .filesystem - .link(&old_relative_path, &new_relative_path) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index].filesystem.chmod(&relative_path, mode) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .chown(&relative_path, uid, gid) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .utimes(&relative_path, atime_ms, mtime_ms) - } - - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .utimes_spec(&relative_path, atime, mtime, follow_symlinks) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - let (index, relative_path) = self.resolve_index(path)?; - self.mounts[index] - .filesystem - .truncate(&relative_path, length) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - let (index, relative_path) = self.resolve_content_index(path)?; - self.mounts[index] - .filesystem - .pread(&relative_path, offset, length) - } -} - -fn normalize_path(path: &str) -> String { - let mut segments = Vec::new(); - for component in Path::new(path).components() { - match component { - Component::RootDir => segments.clear(), - Component::ParentDir => { - segments.pop(); - } - Component::CurDir => {} - Component::Normal(value) => segments.push(value.to_string_lossy().into_owned()), - Component::Prefix(prefix) => { - segments.push(prefix.as_os_str().to_string_lossy().into_owned()); - } - } - } - - if segments.is_empty() { - String::from("/") - } else { - format!("/{}", segments.join("/")) - } -} - -fn path_components(path: &str) -> VecDeque { - normalize_path(path) - .split('/') - .filter(|part| !part.is_empty()) - .map(String::from) - .collect() -} - -fn join_path(parent: &str, child: &str) -> String { - if parent == "/" { - format!("/{child}") - } else { - format!("{parent}/{child}") - } -} - -fn parent_path(path: &str) -> String { - let normalized = normalize_path(path); - let parent = Path::new(&normalized) - .parent() - .unwrap_or_else(|| Path::new("/")); - let value = parent.to_string_lossy(); - if value.is_empty() { - String::from("/") - } else { - value.into_owned() - } -} - -fn basename(path: &str) -> String { - let normalized = normalize_path(path); - Path::new(&normalized) - .file_name() - .map(|name| name.to_string_lossy().into_owned()) - .unwrap_or_else(|| String::from("/")) -} diff --git a/crates/vfs/src/posix/overlay_fs.rs b/crates/vfs/src/posix/overlay_fs.rs deleted file mode 100644 index 25aa86b9e..000000000 --- a/crates/vfs/src/posix/overlay_fs.rs +++ /dev/null @@ -1,2005 +0,0 @@ -use super::vfs::{ - normalize_path, MemoryFileSystem, VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, - VirtualStat, VirtualUtimeSpec, -}; -use base64::Engine; -use std::collections::BTreeSet; - -const MAX_SNAPSHOT_DEPTH: usize = 1024; -const OVERLAY_METADATA_ROOT: &str = "/.secure-exec-overlay"; -const OVERLAY_WHITEOUT_DIR: &str = "/.secure-exec-overlay/whiteouts"; -const OVERLAY_OPAQUE_DIR: &str = "/.secure-exec-overlay/opaque"; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum OverlayMode { - Ephemeral, - ReadOnly, -} - -#[derive(Debug)] -pub struct OverlayFileSystem { - lowers: Vec, - upper: Option, - writes_locked: bool, -} - -#[derive(Debug, Clone, Copy)] -enum OverlayMarkerKind { - Whiteout, - Opaque, -} - -#[derive(Debug)] -enum OverlaySnapshotKind { - Directory, - File(Vec), - Symlink(String), -} - -#[derive(Debug)] -struct OverlaySnapshotEntry { - path: String, - stat: VirtualStat, - kind: OverlaySnapshotKind, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -struct OverlayCopyUpUsage { - total_bytes: u64, - inode_count: usize, -} - -impl OverlayFileSystem { - pub fn new(lowers: Vec, mode: OverlayMode) -> Self { - let mut effective_lowers = lowers; - if effective_lowers.is_empty() { - effective_lowers.push(MemoryFileSystem::new()); - } - - let mut upper = match mode { - OverlayMode::Ephemeral => Some(MemoryFileSystem::new()), - OverlayMode::ReadOnly => None, - }; - if let Some(upper_filesystem) = upper.as_mut() { - sync_upper_root_metadata(upper_filesystem, &effective_lowers); - } - - Self { - lowers: effective_lowers, - upper, - writes_locked: matches!(mode, OverlayMode::ReadOnly), - } - } - - pub fn with_upper(lowers: Vec, upper: MemoryFileSystem) -> Self { - let mut effective_lowers = lowers; - if effective_lowers.is_empty() { - effective_lowers.push(MemoryFileSystem::new()); - } - - Self { - lowers: effective_lowers, - upper: Some(upper), - writes_locked: false, - } - } - - pub fn lock_writes(&mut self) { - self.writes_locked = true; - } - - fn normalized(path: &str) -> String { - normalize_path(path) - } - - fn parent_path(path: &str) -> String { - let normalized = Self::normalized(path); - if normalized == "/" { - return String::from("/"); - } - - match normalized.rsplit_once('/') { - Some(("", _)) | None => String::from("/"), - Some((parent, _)) => String::from(parent), - } - } - - fn basename(path: &str) -> String { - let normalized = Self::normalized(path); - if normalized == "/" { - return String::from("/"); - } - normalized - .rsplit('/') - .find(|component| !component.is_empty()) - .unwrap_or("") - .to_owned() - } - - fn validate_destination_parent(&mut self, path: &str) -> VfsResult<()> { - let parent = Self::parent_path(path); - let resolved_parent = self.resolve_merged_path(&parent, true, 0)?; - let stat = self.merged_lstat(&resolved_parent)?; - if !stat.is_directory { - return Err(Self::not_directory(&parent)); - } - Ok(()) - } - - fn resolved_destination_path(&self, path: &str) -> VfsResult { - let parent = Self::parent_path(path); - let resolved_parent = self.resolve_merged_path(&parent, true, 0)?; - Ok(Self::join_path(&resolved_parent, &Self::basename(path))) - } - - fn resolve_merged_path( - &self, - path: &str, - follow_final_symlink: bool, - depth: usize, - ) -> VfsResult { - if depth > MAX_SNAPSHOT_DEPTH { - return Err(VfsError::new( - "ELOOP", - format!("too many symbolic links while resolving '{path}'"), - )); - } - - let normalized = Self::normalized(path); - if normalized == "/" { - return Ok(normalized); - } - - let components: Vec<&str> = normalized - .split('/') - .filter(|component| !component.is_empty()) - .collect(); - let mut current = String::from("/"); - - for (index, component) in components.iter().enumerate() { - let candidate = Self::join_path(¤t, component); - let is_final = index + 1 == components.len(); - let should_follow = !is_final || follow_final_symlink; - - if should_follow { - if let Ok(stat) = self.merged_lstat(&candidate) { - if stat.is_symbolic_link { - let target = self.read_link_inner(&candidate)?; - let target_path = if target.starts_with('/') { - Self::normalized(&target) - } else { - Self::normalized(&Self::join_path( - &Self::parent_path(&candidate), - &target, - )) - }; - let remainder = components[index + 1..].join("/"); - let next_path = if remainder.is_empty() { - target_path - } else { - Self::normalized(&Self::join_path(&target_path, &remainder)) - }; - return self.resolve_merged_path( - &next_path, - follow_final_symlink, - depth + 1, - ); - } - - if !is_final && !stat.is_directory { - return Err(Self::not_directory(&candidate)); - } - } - } else if let Ok(stat) = self.merged_lstat(&candidate) { - if !is_final && !stat.is_directory { - return Err(Self::not_directory(&candidate)); - } - } - - current = candidate; - } - - Ok(current) - } - - fn destination_parent_copy_up_paths(&self, path: &str) -> VfsResult> { - let parent = Self::parent_path(path); - let mut paths = Vec::new(); - let mut seen = BTreeSet::new(); - self.collect_destination_parent_copy_up_paths(&parent, &mut paths, &mut seen, 0)?; - Ok(paths) - } - - fn collect_destination_parent_copy_up_paths( - &self, - parent: &str, - paths: &mut Vec, - seen: &mut BTreeSet, - depth: usize, - ) -> VfsResult<()> { - if depth > MAX_SNAPSHOT_DEPTH { - return Err(VfsError::new( - "ELOOP", - format!("too many symbolic links while resolving '{parent}'"), - )); - } - - let normalized = Self::normalized(parent); - if normalized == "/" { - return Ok(()); - } - - let components: Vec<&str> = normalized - .split('/') - .filter(|component| !component.is_empty()) - .collect(); - let mut current = String::from("/"); - for (index, component) in components.iter().enumerate() { - current = Self::join_path(¤t, component); - let stat = self.merged_lstat(¤t)?; - - if stat.is_symbolic_link { - if !self.has_entry_in_upper(¤t) && seen.insert(current.clone()) { - paths.push(current.clone()); - } - - let target = self.read_link_inner(¤t)?; - let target_path = if target.starts_with('/') { - Self::normalized(&target) - } else { - Self::normalized(&Self::join_path(&Self::parent_path(¤t), &target)) - }; - let remainder = components[index + 1..].join("/"); - let next_parent = if remainder.is_empty() { - target_path - } else { - Self::normalized(&Self::join_path(&target_path, &remainder)) - }; - return self.collect_destination_parent_copy_up_paths( - &next_parent, - paths, - seen, - depth + 1, - ); - } - - if self.find_lower_by_entry(¤t).is_some() - && !self.has_entry_in_upper(¤t) - && seen.insert(current.clone()) - { - paths.push(current.clone()); - } - } - - Ok(()) - } - - fn encode_marker_path(path: &str) -> String { - base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(path) - } - - fn marker_directory(kind: OverlayMarkerKind) -> &'static str { - match kind { - OverlayMarkerKind::Whiteout => OVERLAY_WHITEOUT_DIR, - OverlayMarkerKind::Opaque => OVERLAY_OPAQUE_DIR, - } - } - - fn marker_path(kind: OverlayMarkerKind, path: &str) -> String { - format!( - "{}/{}", - Self::marker_directory(kind), - Self::encode_marker_path(&Self::normalized(path)) - ) - } - - fn is_internal_metadata_path(path: &str) -> bool { - let normalized = Self::normalized(path); - normalized == OVERLAY_METADATA_ROOT - || normalized.starts_with(&(String::from(OVERLAY_METADATA_ROOT) + "/")) - } - - /// Returns true if `path`, or the location it resolves to through symlinks, - /// lands in the reserved overlay metadata namespace. - /// - /// The lexical [`is_internal_metadata_path`] check alone is bypassable: the - /// underlying `MemoryFileSystem` follows symlinks, so a guest-created symlink - /// whose resolved target enters `/.secure-exec-overlay` (directly, or via a - /// symlink to an ancestor such as `/`) would slip past a purely lexical guard - /// and let the guest read or tamper with whiteout/opaque markers (e.g. - /// resurrecting a deleted lower-layer file). Resolving before the check - /// closes that hole while leaving ordinary symlinks unaffected. - fn touches_internal_metadata(&self, path: &str) -> bool { - if Self::is_internal_metadata_path(path) { - return true; - } - if let Ok(resolved) = self.resolve_merged_path(path, true, 0) { - if Self::is_internal_metadata_path(&resolved) { - return true; - } - } - if let Ok(resolved) = self.resolved_destination_path(path) { - if Self::is_internal_metadata_path(&resolved) { - return true; - } - } - false - } - - fn hidden_root_entry_name() -> &'static str { - ".secure-exec-overlay" - } - - fn should_hide_directory_entry(path: &str, entry: &str) -> bool { - let normalized = Self::normalized(path); - normalized == "/" && entry == Self::hidden_root_entry_name() - } - - fn should_ignore_raw_directory_entry( - upper: Option<&MemoryFileSystem>, - path: &str, - entry: &str, - ) -> bool { - if entry == "." || entry == ".." || Self::should_hide_directory_entry(path, entry) { - return true; - } - - let entry_path = Self::join_path(path, entry); - Self::marker_exists_in_upper(upper, OverlayMarkerKind::Whiteout, &entry_path) - } - - fn check_copy_up_usage_limits( - usage: &OverlayCopyUpUsage, - max_bytes: Option, - max_inodes: Option, - ) -> VfsResult<()> { - if let Some(limit) = max_bytes { - if usage.total_bytes > limit { - return Err(VfsError::new( - "ENOSPC", - format!( - "overlay rename copy-up bytes {} exceed configured limit {}", - usage.total_bytes, limit - ), - )); - } - } - - if let Some(limit) = max_inodes { - if usage.inode_count > limit { - return Err(VfsError::new( - "ENOSPC", - format!( - "overlay rename copy-up inodes {} exceed configured limit {}", - usage.inode_count, limit - ), - )); - } - } - - Ok(()) - } - - fn add_copy_up_usage( - usage: &mut OverlayCopyUpUsage, - bytes: u64, - inodes: usize, - max_bytes: Option, - max_inodes: Option, - ) -> VfsResult<()> { - usage.total_bytes = usage.total_bytes.saturating_add(bytes); - usage.inode_count = usage.inode_count.saturating_add(inodes); - Self::check_copy_up_usage_limits(usage, max_bytes, max_inodes) - } - - fn remaining_inode_budget( - usage: &OverlayCopyUpUsage, - max_inodes: Option, - ) -> Option { - max_inodes.map(|limit| limit.saturating_sub(usage.inode_count)) - } - - fn copy_up_directory_entries_limited( - &mut self, - path: &str, - max_entries: Option, - ) -> VfsResult> { - let Some(max_entries) = max_entries else { - return self.read_dir(path); - }; - - match self.read_dir_limited(path, max_entries) { - Ok(entries) => Ok(entries), - Err(error) if error.code() == "ENOMEM" => Err(VfsError::new( - "ENOSPC", - format!("overlay rename copy-up directory '{path}' exceeds configured inode limit"), - )), - Err(error) => Err(error), - } - } - - fn directory_has_visible_entries_limited(&mut self, path: &str) -> VfsResult { - match self.read_dir_limited(path, 1) { - Ok(entries) => Ok(!entries.is_empty()), - Err(error) if error.code() == "ENOMEM" => Ok(true), - Err(error) => Err(error), - } - } - - fn memory_subtree_usage_limited( - filesystem: &mut MemoryFileSystem, - path: &str, - max_bytes: Option, - max_inodes: Option, - ) -> VfsResult { - let mut usage = OverlayCopyUpUsage::default(); - let mut visited = BTreeSet::new(); - let mut pending = vec![Self::normalized(path)]; - while let Some(current_path) = pending.pop() { - let stat = filesystem.lstat(¤t_path)?; - if visited.insert(stat.ino) { - let bytes = if stat.is_directory && !stat.is_symbolic_link { - 0 - } else { - stat.size - }; - Self::add_copy_up_usage(&mut usage, bytes, 1, max_bytes, max_inodes)?; - } - - if stat.is_directory && !stat.is_symbolic_link { - let remaining = Self::remaining_inode_budget(&usage, max_inodes); - let children = if let Some(max_entries) = remaining { - filesystem.read_dir_limited(¤t_path, max_entries)? - } else { - filesystem.read_dir(¤t_path)? - }; - for entry in children.into_iter().rev() { - if matches!(entry.as_str(), "." | "..") { - continue; - } - if Self::should_hide_directory_entry(¤t_path, &entry) { - continue; - } - pending.push(Self::join_path(¤t_path, &entry)); - } - } - } - - Ok(usage) - } - - fn memory_subtree_released_usage( - filesystem: &mut MemoryFileSystem, - path: &str, - ) -> VfsResult { - let mut usage = OverlayCopyUpUsage::default(); - let mut visited = BTreeSet::new(); - let mut pending = vec![Self::normalized(path)]; - while let Some(current_path) = pending.pop() { - let stat = filesystem.lstat(¤t_path)?; - if visited.insert(stat.ino) { - let subtree_links = filesystem.link_count_in_subtree(stat.ino, path) as u64; - if stat.is_directory || stat.nlink <= subtree_links { - let bytes = if stat.is_directory && !stat.is_symbolic_link { - 0 - } else { - stat.size - }; - Self::add_copy_up_usage(&mut usage, bytes, 1, None, None)?; - } - } - - if stat.is_directory && !stat.is_symbolic_link { - for entry in filesystem.read_dir(¤t_path)?.into_iter().rev() { - if matches!(entry.as_str(), "." | "..") { - continue; - } - if Self::should_hide_directory_entry(¤t_path, &entry) { - continue; - } - pending.push(Self::join_path(¤t_path, &entry)); - } - } - } - - Ok(usage) - } - - fn upper_usage_limited( - &mut self, - max_bytes: Option, - max_inodes: Option, - ) -> VfsResult { - let Some(upper) = self.upper.as_mut() else { - return Ok(OverlayCopyUpUsage::default()); - }; - - Self::memory_subtree_usage_limited(upper, "/", max_bytes, max_inodes) - } - - fn upper_subtree_released_usage(&mut self, path: &str) -> VfsResult { - let Some(upper) = self.upper.as_mut() else { - return Ok(OverlayCopyUpUsage::default()); - }; - - if !upper.exists(path) { - return Ok(OverlayCopyUpUsage::default()); - } - - Self::memory_subtree_released_usage(upper, path) - } - - fn collect_copy_up_usage_limited( - &mut self, - path: &str, - usage: &mut OverlayCopyUpUsage, - max_bytes: Option, - max_inodes: Option, - ) -> VfsResult<()> { - let mut pending = vec![(Self::normalized(path), 0usize)]; - while let Some((current_path, depth)) = pending.pop() { - if depth > MAX_SNAPSHOT_DEPTH { - return Err(VfsError::new( - "EINVAL", - format!("overlay snapshot depth limit exceeded at '{current_path}'"), - )); - } - - let stat = self.merged_lstat(¤t_path)?; - if !self.has_entry_in_upper(¤t_path) { - let bytes = if stat.is_symbolic_link { - self.read_link_inner(¤t_path)?.len() as u64 - } else if stat.is_directory { - 0 - } else { - stat.size - }; - Self::add_copy_up_usage(usage, bytes, 1, max_bytes, max_inodes)?; - } - - if stat.is_directory && !stat.is_symbolic_link { - let children = self.copy_up_directory_entries_limited(¤t_path, max_inodes)?; - for entry in children.into_iter().rev() { - pending.push((Self::join_path(¤t_path, &entry), depth + 1)); - } - } - } - - Ok(()) - } - - fn collect_single_copy_up_usage_limited( - &mut self, - path: &str, - usage: &mut OverlayCopyUpUsage, - max_bytes: Option, - max_inodes: Option, - ) -> VfsResult<()> { - if self.has_entry_in_upper(path) { - return Ok(()); - } - - let stat = self.merged_lstat(path)?; - let bytes = if stat.is_symbolic_link { - self.read_link_inner(path)?.len() as u64 - } else if stat.is_directory { - 0 - } else { - stat.size - }; - Self::add_copy_up_usage(usage, bytes, 1, max_bytes, max_inodes) - } - - pub fn check_rename_copy_up_limits( - &mut self, - old_path: &str, - new_path: &str, - max_bytes: Option, - max_inodes: Option, - ) -> VfsResult<()> { - let old_normalized = Self::normalized(old_path); - let new_normalized = Self::normalized(new_path); - if Self::is_internal_metadata_path(&old_normalized) - || Self::is_internal_metadata_path(&new_normalized) - { - return Err(VfsError::permission_denied("rename", old_path)); - } - - if old_normalized == "/" { - return Err(VfsError::permission_denied("rename", old_path)); - } - - if old_normalized == new_normalized { - return Ok(()); - } - - let source_stat = self.merged_lstat(old_path)?; - if self.writes_locked { - self.writable_upper(&old_normalized)?; - } - self.validate_destination_parent(&new_normalized)?; - let resolved_new_normalized = self.resolved_destination_path(&new_normalized)?; - - if old_normalized == resolved_new_normalized { - return Ok(()); - } - - if source_stat.is_directory - && resolved_new_normalized.starts_with(&(old_normalized.clone() + "/")) - { - return Err(VfsError::new( - "EINVAL", - format!( - "cannot move '{}' into its own descendant '{}'", - old_path, new_path - ), - )); - } - - let destination_parent_copy_up_paths = - self.destination_parent_copy_up_paths(&new_normalized)?; - - if let Ok(destination_stat) = self.merged_lstat(&resolved_new_normalized) { - if destination_stat.is_directory - && !destination_stat.is_symbolic_link - && self.directory_has_visible_entries_limited(&resolved_new_normalized)? - { - return Err(Self::not_empty(&resolved_new_normalized)); - } - } - - let mut usage = self.upper_usage_limited(None, None)?; - if self.has_entry_in_upper(&resolved_new_normalized) { - let destination_usage = self.upper_subtree_released_usage(&resolved_new_normalized)?; - usage.total_bytes = usage - .total_bytes - .saturating_sub(destination_usage.total_bytes); - usage.inode_count = usage - .inode_count - .saturating_sub(destination_usage.inode_count); - } - Self::check_copy_up_usage_limits(&usage, max_bytes, max_inodes)?; - for path in destination_parent_copy_up_paths { - self.collect_single_copy_up_usage_limited(&path, &mut usage, max_bytes, max_inodes)?; - } - self.collect_copy_up_usage_limited(&old_normalized, &mut usage, max_bytes, max_inodes)?; - - Self::check_copy_up_usage_limits(&usage, max_bytes, max_inodes) - } - - fn marker_exists(&self, kind: OverlayMarkerKind, path: &str) -> bool { - Self::marker_exists_in_upper(self.upper.as_ref(), kind, path) - } - - fn marker_exists_in_upper( - upper: Option<&MemoryFileSystem>, - kind: OverlayMarkerKind, - path: &str, - ) -> bool { - upper.is_some_and(|filesystem| filesystem.exists(&Self::marker_path(kind, path))) - } - - fn is_whited_out(&self, path: &str) -> bool { - self.marker_exists(OverlayMarkerKind::Whiteout, path) - } - - fn ensure_metadata_directories_in_upper(&mut self, path: &str) -> VfsResult<()> { - let upper = self.writable_upper(path)?; - upper.mkdir(OVERLAY_METADATA_ROOT, true)?; - upper.mkdir(OVERLAY_WHITEOUT_DIR, true)?; - upper.mkdir(OVERLAY_OPAQUE_DIR, true)?; - Ok(()) - } - - fn set_marker(&mut self, kind: OverlayMarkerKind, path: &str, present: bool) -> VfsResult<()> { - let marker_path = Self::marker_path(kind, path); - if present { - self.ensure_metadata_directories_in_upper(path)?; - self.writable_upper(path)? - .write_file(&marker_path, Self::normalized(path).into_bytes())?; - return Ok(()); - } - - if self - .upper - .as_ref() - .is_some_and(|upper| upper.exists(&marker_path)) - { - self.writable_upper(path)?.remove_file(&marker_path)?; - } - Ok(()) - } - - fn add_whiteout(&mut self, path: &str) -> VfsResult<()> { - self.set_marker(OverlayMarkerKind::Whiteout, path, true) - } - - fn remove_whiteout(&mut self, path: &str) -> VfsResult<()> { - self.set_marker(OverlayMarkerKind::Whiteout, path, false) - } - - fn mark_opaque_directory(&mut self, path: &str) -> VfsResult<()> { - self.set_marker(OverlayMarkerKind::Opaque, path, true) - } - - fn clear_opaque_directory(&mut self, path: &str) -> VfsResult<()> { - self.set_marker(OverlayMarkerKind::Opaque, path, false) - } - - fn clear_path_metadata(&mut self, path: &str) -> VfsResult<()> { - self.remove_whiteout(path)?; - self.clear_opaque_directory(path) - } - - fn join_path(base: &str, name: &str) -> String { - if base == "/" { - format!("/{name}") - } else { - format!("{base}/{name}") - } - } - - fn rebase_path(path: &str, old_root: &str, new_root: &str) -> String { - if path == old_root { - return String::from(new_root); - } - - format!("{new_root}{}", &path[old_root.len()..]) - } - - fn read_only_error(path: &str) -> VfsError { - VfsError::new("EROFS", format!("read-only filesystem: {path}")) - } - - fn entry_not_found(path: &str) -> VfsError { - VfsError::new("ENOENT", format!("no such file: {path}")) - } - - fn directory_not_found(path: &str) -> VfsError { - VfsError::new("ENOENT", format!("no such directory: {path}")) - } - - fn already_exists(path: &str) -> VfsError { - VfsError::new("EEXIST", format!("file exists: {path}")) - } - - fn not_directory(path: &str) -> VfsError { - VfsError::new("ENOTDIR", format!("not a directory: {path}")) - } - - fn writable_upper(&mut self, path: &str) -> VfsResult<&mut MemoryFileSystem> { - if self.writes_locked { - return Err(Self::read_only_error(path)); - } - self.upper - .as_mut() - .ok_or_else(|| Self::read_only_error(path)) - } - - fn path_exists_in_filesystem(filesystem: &MemoryFileSystem, path: &str) -> bool { - filesystem.exists(path) - } - - fn has_entry_in_filesystem(filesystem: &MemoryFileSystem, path: &str) -> bool { - filesystem.lstat(path).is_ok() - } - - fn exists_in_upper(&self, path: &str) -> bool { - self.upper - .as_ref() - .is_some_and(|upper| Self::path_exists_in_filesystem(upper, path)) - } - - fn has_entry_in_upper(&self, path: &str) -> bool { - self.upper - .as_ref() - .is_some_and(|upper| Self::has_entry_in_filesystem(upper, path)) - } - - fn find_lower_by_exists(&self, path: &str) -> Option { - self.lowers - .iter() - .position(|lower| Self::path_exists_in_filesystem(lower, path)) - } - - fn find_lower_by_entry(&self, path: &str) -> Option<(usize, VirtualStat)> { - self.lowers - .iter() - .enumerate() - .find_map(|(index, lower)| lower.lstat(path).ok().map(|stat| (index, stat))) - } - - fn merged_lstat(&self, path: &str) -> VfsResult { - if Self::is_internal_metadata_path(path) { - return Err(Self::entry_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if self.has_entry_in_upper(path) { - return self - .upper - .as_ref() - .expect("upper must exist when entry exists") - .lstat(path); - } - self.find_lower_by_entry(path) - .map(|(_, stat)| stat) - .ok_or_else(|| Self::entry_not_found(path)) - } - - /// `read_link` body without the resolving metadata guard, for use by the - /// internal symlink-resolution helpers (`resolve_merged_path` and friends). - /// The public `read_link` wraps this with `touches_internal_metadata`; - /// resolution must not call back into that wrapper or it would recurse on a - /// symlink that points at itself's resolution path. - fn read_link_inner(&self, path: &str) -> VfsResult { - if Self::is_internal_metadata_path(path) { - return Err(Self::entry_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if self.has_entry_in_upper(path) { - return self - .upper - .as_ref() - .expect("upper must exist when path exists") - .read_link(path); - } - let Some((index, _)) = self.find_lower_by_entry(path) else { - return Err(Self::entry_not_found(path)); - }; - self.lowers[index].read_link(path) - } - - fn ensure_ancestor_directories_in_upper(&mut self, path: &str) -> VfsResult<()> { - if Self::is_internal_metadata_path(path) { - return Err(VfsError::permission_denied("mkdir", path)); - } - let normalized = Self::normalized(path); - let parts = normalized - .split('/') - .filter(|part| !part.is_empty()) - .collect::>(); - - let mut current = String::new(); - for part in parts.iter().take(parts.len().saturating_sub(1)) { - current.push('/'); - current.push_str(part); - - if self.exists_in_upper(¤t) { - continue; - } - - if let Some(index) = self.find_lower_by_exists(¤t) { - let stat = self.lowers[index].stat(¤t)?; - if !stat.is_directory { - return Err(Self::not_directory(¤t)); - } - - let upper = self.writable_upper(¤t)?; - upper.mkdir(¤t, false)?; - upper.chmod(¤t, stat.mode)?; - upper.chown(¤t, stat.uid, stat.gid)?; - continue; - } - - let upper = self.writable_upper(¤t)?; - upper.mkdir(¤t, false)?; - } - - Ok(()) - } - - fn copy_up_path(&mut self, path: &str) -> VfsResult<()> { - if self.has_entry_in_upper(path) { - return Ok(()); - } - - self.ensure_ancestor_directories_in_upper(path)?; - - let (lower_index, stat) = self - .find_lower_by_entry(path) - .ok_or_else(|| Self::entry_not_found(path))?; - - if stat.is_symbolic_link { - let target = self.lowers[lower_index].read_link(path)?; - let upper = self.writable_upper(path)?; - upper.symlink(&target, path)?; - return Ok(()); - } - - if stat.is_directory { - let upper = self.writable_upper(path)?; - upper.mkdir(path, false)?; - upper.chmod(path, stat.mode)?; - upper.chown(path, stat.uid, stat.gid)?; - self.mark_opaque_directory(path)?; - return Ok(()); - } - - let data = self.lowers[lower_index].read_file(path)?; - let upper = self.writable_upper(path)?; - upper.write_file(path, data)?; - upper.chmod(path, stat.mode)?; - upper.chown(path, stat.uid, stat.gid)?; - Ok(()) - } - - fn materialize_destination_parent_in_upper(&mut self, path: &str) -> VfsResult<()> { - if self.has_entry_in_upper(path) { - return Ok(()); - } - - if self - .merged_lstat(path) - .is_ok_and(|stat| stat.is_symbolic_link) - { - return self.copy_up_path(path); - } - - self.ensure_ancestor_directories_in_upper(path)?; - let stat = self.merged_lstat(path)?; - if !stat.is_directory || stat.is_symbolic_link { - return Err(Self::not_directory(path)); - } - - let upper = self.writable_upper(path)?; - upper.create_dir(path)?; - upper.chmod(path, stat.mode)?; - upper.chown(path, stat.uid, stat.gid)?; - Ok(()) - } - - fn path_exists_in_merged_view(&self, path: &str) -> bool { - if self.is_whited_out(path) { - return false; - } - if self.has_entry_in_upper(path) { - return true; - } - self.find_lower_by_entry(path).is_some() - } - - fn not_empty(path: &str) -> VfsError { - VfsError::new("ENOTEMPTY", format!("directory not empty, rmdir '{path}'")) - } - - fn collect_snapshot_entries( - &mut self, - path: &str, - entries: &mut Vec, - ) -> VfsResult<()> { - let mut pending = vec![(Self::normalized(path), 0usize)]; - while let Some((current_path, depth)) = pending.pop() { - if depth > MAX_SNAPSHOT_DEPTH { - return Err(VfsError::new( - "EINVAL", - format!("overlay snapshot depth limit exceeded at '{current_path}'"), - )); - } - - let stat = self.merged_lstat(¤t_path)?; - - if stat.is_symbolic_link { - entries.push(OverlaySnapshotEntry { - path: current_path.clone(), - stat, - kind: OverlaySnapshotKind::Symlink(self.read_link_inner(¤t_path)?), - }); - continue; - } - - if stat.is_directory { - entries.push(OverlaySnapshotEntry { - path: current_path.clone(), - stat, - kind: OverlaySnapshotKind::Directory, - }); - - let children = self.read_dir_with_types_inner(¤t_path)?; - for entry in children.into_iter().rev() { - pending.push((Self::join_path(¤t_path, &entry.name), depth + 1)); - } - continue; - } - - entries.push(OverlaySnapshotEntry { - path: current_path.clone(), - stat, - kind: OverlaySnapshotKind::File(self.read_file(¤t_path)?), - }); - } - Ok(()) - } - - fn remove_snapshot_entries(&mut self, entries: &[OverlaySnapshotEntry]) -> VfsResult<()> { - for entry in entries.iter().rev() { - if self.has_entry_in_upper(&entry.path) { - match entry.kind { - OverlaySnapshotKind::Directory => { - self.writable_upper(&entry.path)?.remove_dir(&entry.path)?; - } - OverlaySnapshotKind::File(_) | OverlaySnapshotKind::Symlink(_) => { - self.writable_upper(&entry.path)?.remove_file(&entry.path)?; - } - } - } - - if self.find_lower_by_entry(&entry.path).is_some() { - self.clear_opaque_directory(&entry.path)?; - self.add_whiteout(&entry.path)?; - } else { - self.clear_path_metadata(&entry.path)?; - } - } - - Ok(()) - } - - fn directory_has_raw_children(&mut self, path: &str) -> VfsResult { - let normalized = Self::normalized(path); - let mut directory_exists = false; - - if let Some(upper) = self.upper.as_mut() { - if let Ok(entries) = upper.read_dir(&normalized) { - directory_exists = true; - if entries.into_iter().any(|entry| { - !Self::should_ignore_raw_directory_entry(Some(&*upper), &normalized, &entry) - }) { - return Ok(true); - } - } - } - - let upper = self.upper.as_ref(); - for lower in self.lowers.iter_mut().rev() { - if let Ok(entries) = lower.read_dir(&normalized) { - directory_exists = true; - if entries.into_iter().any(|entry| { - !Self::should_ignore_raw_directory_entry(upper, &normalized, &entry) - }) { - return Ok(true); - } - } - } - - if !directory_exists { - return Err(Self::directory_not_found(path)); - } - - Ok(false) - } - - fn read_dir_with_types_inner(&mut self, path: &str) -> VfsResult> { - if self.is_whited_out(path) { - return Err(Self::directory_not_found(path)); - } - - let normalized = Self::normalized(path); - let mut directory_exists = false; - let mut entries = Vec::::new(); - let mut seen = BTreeSet::::new(); - let upper = self.upper.as_ref(); - let include_lowers = !Self::marker_exists_in_upper(upper, OverlayMarkerKind::Opaque, path); - - if include_lowers { - for lower in self.lowers.iter_mut().rev() { - if let Ok(lower_entries) = lower.read_dir_with_types(path) { - directory_exists = true; - for entry in lower_entries { - if entry.name == "." - || entry.name == ".." - || Self::should_hide_directory_entry(path, &entry.name) - { - continue; - } - let child_path = if normalized == "/" { - format!("/{}", entry.name) - } else { - format!("{normalized}/{}", entry.name) - }; - if Self::marker_exists_in_upper( - upper, - OverlayMarkerKind::Whiteout, - &child_path, - ) || seen.contains(&entry.name) - { - continue; - } - seen.insert(entry.name.clone()); - entries.push(entry); - } - } - } - } - - if let Some(upper) = self.upper.as_mut() { - if let Ok(upper_entries) = upper.read_dir_with_types(path) { - directory_exists = true; - for entry in upper_entries { - if entry.name == "." - || entry.name == ".." - || Self::should_hide_directory_entry(path, &entry.name) - { - continue; - } - if let Some(index) = entries - .iter() - .position(|existing| existing.name == entry.name) - { - entries[index] = entry; - } else { - seen.insert(entry.name.clone()); - entries.push(entry); - } - } - } - } - - if !directory_exists { - return Err(Self::directory_not_found(path)); - } - - Ok(entries) - } - - fn marker_paths_in_upper(&mut self, kind: OverlayMarkerKind) -> VfsResult> { - let Some(upper) = self.upper.as_mut() else { - return Ok(Vec::new()); - }; - - let marker_dir = Self::marker_directory(kind); - let entries = match upper.read_dir(marker_dir) { - Ok(entries) => entries, - Err(error) if error.code() == "ENOENT" => return Ok(Vec::new()), - Err(error) => return Err(error), - }; - - let mut marker_paths = Vec::new(); - for entry in entries { - if entry == "." || entry == ".." { - continue; - } - - let marker_file = Self::join_path(marker_dir, &entry); - let marker_path = - String::from_utf8(upper.read_file(&marker_file).map_err(|_| { - VfsError::io(format!("invalid overlay marker '{marker_file}'")) - })?) - .map_err(|_| VfsError::io(format!("invalid overlay marker '{marker_file}'")))?; - marker_paths.push(Self::normalized(&marker_path)); - } - - Ok(marker_paths) - } - - fn path_in_subtree(path: &str, root: &str) -> bool { - path == root || path.starts_with(&(String::from(root) + "/")) - } - - fn clear_subtree_metadata(&mut self, path: &str) -> VfsResult<()> { - let normalized = Self::normalized(path); - for kind in [OverlayMarkerKind::Whiteout, OverlayMarkerKind::Opaque] { - for marker_path in self.marker_paths_in_upper(kind)? { - if Self::path_in_subtree(&marker_path, &normalized) { - self.set_marker(kind, &marker_path, false)?; - } - } - } - Ok(()) - } - - fn copy_subtree_metadata(&mut self, old_root: &str, new_root: &str) -> VfsResult<()> { - let old_normalized = Self::normalized(old_root); - let new_normalized = Self::normalized(new_root); - - for kind in [OverlayMarkerKind::Whiteout, OverlayMarkerKind::Opaque] { - for marker_path in self.marker_paths_in_upper(kind)? { - if Self::path_in_subtree(&marker_path, &old_normalized) { - let destination = - Self::rebase_path(&marker_path, &old_normalized, &new_normalized); - self.set_marker(kind, &destination, true)?; - } - } - } - - Ok(()) - } - - fn stage_snapshot_entries_in_upper( - &mut self, - entries: &[OverlaySnapshotEntry], - ) -> VfsResult<()> { - for entry in entries { - match &entry.kind { - OverlaySnapshotKind::Directory => { - if !self.has_entry_in_upper(&entry.path) { - self.ensure_ancestor_directories_in_upper(&entry.path)?; - self.writable_upper(&entry.path)?.create_dir(&entry.path)?; - } - self.writable_upper(&entry.path)? - .chmod(&entry.path, entry.stat.mode)?; - self.writable_upper(&entry.path)?.chown( - &entry.path, - entry.stat.uid, - entry.stat.gid, - )?; - self.mark_opaque_directory(&entry.path)?; - } - OverlaySnapshotKind::File(data) => { - if self.has_entry_in_upper(&entry.path) { - continue; - } - self.ensure_ancestor_directories_in_upper(&entry.path)?; - self.writable_upper(&entry.path)? - .write_file(&entry.path, data.clone())?; - self.writable_upper(&entry.path)? - .chmod(&entry.path, entry.stat.mode)?; - self.writable_upper(&entry.path)?.chown( - &entry.path, - entry.stat.uid, - entry.stat.gid, - )?; - } - OverlaySnapshotKind::Symlink(target) => { - if self.has_entry_in_upper(&entry.path) { - continue; - } - self.ensure_ancestor_directories_in_upper(&entry.path)?; - self.writable_upper(&entry.path)? - .symlink(target, &entry.path)?; - } - } - } - - Ok(()) - } -} - -fn sync_upper_root_metadata(upper: &mut MemoryFileSystem, lowers: &[MemoryFileSystem]) { - let Some(root_stat) = lowers.iter().find_map(|lower| lower.lstat("/").ok()) else { - return; - }; - - upper - .chmod("/", root_stat.mode) - .expect("overlay upper root should exist"); - upper - .chown("/", root_stat.uid, root_stat.gid) - .expect("overlay upper root should exist"); -} - -impl VirtualFileSystem for OverlayFileSystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - if self.touches_internal_metadata(path) { - return Err(Self::entry_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if self.exists_in_upper(path) { - return self - .upper - .as_mut() - .expect("upper must exist when path exists") - .read_file(path); - } - let Some(index) = self.find_lower_by_exists(path) else { - return Err(Self::entry_not_found(path)); - }; - self.lowers[index].read_file(path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - if self.touches_internal_metadata(path) { - return Err(Self::directory_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::directory_not_found(path)); - } - - let normalized = Self::normalized(path); - let mut directory_exists = false; - let mut entries = BTreeSet::new(); - let upper = self.upper.as_ref(); - let include_lowers = !Self::marker_exists_in_upper(upper, OverlayMarkerKind::Opaque, path); - - if include_lowers { - for lower in self.lowers.iter_mut().rev() { - if let Ok(lower_entries) = lower.read_dir(path) { - directory_exists = true; - for entry in lower_entries { - if entry == "." - || entry == ".." - || Self::should_hide_directory_entry(path, &entry) - { - continue; - } - let child_path = if normalized == "/" { - format!("/{entry}") - } else { - format!("{normalized}/{entry}") - }; - if !Self::marker_exists_in_upper( - upper, - OverlayMarkerKind::Whiteout, - &child_path, - ) { - entries.insert(entry); - } - } - } - } - } - - if let Some(upper) = self.upper.as_mut() { - if let Ok(upper_entries) = upper.read_dir(path) { - directory_exists = true; - for entry in upper_entries { - if entry == "." - || entry == ".." - || Self::should_hide_directory_entry(path, &entry) - { - continue; - } - entries.insert(entry); - } - } - } - - if !directory_exists { - return Err(Self::directory_not_found(path)); - } - - Ok(entries.into_iter().collect()) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - if self.touches_internal_metadata(path) { - return Err(Self::directory_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::directory_not_found(path)); - } - - let normalized = Self::normalized(path); - let mut directory_exists = false; - let mut entries = BTreeSet::new(); - let upper = self.upper.as_ref(); - let include_lowers = !Self::marker_exists_in_upper(upper, OverlayMarkerKind::Opaque, path); - - if include_lowers { - for lower in self.lowers.iter_mut().rev() { - let lower_entries = match lower.read_dir_filtered_limited( - path, - max_entries.saturating_sub(entries.len()), - |entry| { - if entry == "." - || entry == ".." - || Self::should_hide_directory_entry(path, entry) - { - return false; - } - let child_path = if normalized == "/" { - format!("/{entry}") - } else { - format!("{normalized}/{entry}") - }; - !Self::marker_exists_in_upper( - upper, - OverlayMarkerKind::Whiteout, - &child_path, - ) && !entries.contains(entry) - }, - ) { - Ok(entries) => entries, - Err(error) if error.code() == "ENOENT" || error.code() == "ENOTDIR" => { - continue; - } - Err(error) => return Err(error), - }; - directory_exists = true; - for entry in lower_entries { - entries.insert(entry); - if entries.len() > max_entries { - return Err(VfsError::new( - "ENOMEM", - format!( - "directory listing for '{path}' exceeds configured limit of {max_entries} entries" - ), - )); - } - } - } - } - - if let Some(upper) = self.upper.as_mut() { - let upper_entries = match upper.read_dir_filtered_limited( - path, - max_entries.saturating_sub(entries.len()), - |entry| { - entry != "." - && entry != ".." - && !Self::should_hide_directory_entry(path, entry) - && !entries.contains(entry) - }, - ) { - Ok(entries) => entries, - Err(error) if error.code() == "ENOENT" => Vec::new(), - Err(error) => return Err(error), - }; - directory_exists = directory_exists || upper.exists(path); - for entry in upper_entries { - if entry == "." || entry == ".." || Self::should_hide_directory_entry(path, &entry) - { - continue; - } - entries.insert(entry); - if entries.len() > max_entries { - return Err(VfsError::new( - "ENOMEM", - format!( - "directory listing for '{path}' exceeds configured limit of {max_entries} entries" - ), - )); - } - } - } - - if !directory_exists { - return Err(Self::directory_not_found(path)); - } - - Ok(entries.into_iter().collect()) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - if self.touches_internal_metadata(path) { - return Err(Self::directory_not_found(path)); - } - self.read_dir_with_types_inner(path) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("open", path)); - } - self.clear_path_metadata(path)?; - if self.find_lower_by_entry(path).is_some() { - self.copy_up_path(path)?; - } else { - self.ensure_ancestor_directories_in_upper(path)?; - } - self.writable_upper(path)?.write_file(path, content.into()) - } - - fn create_file_exclusive(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("open", path)); - } - self.clear_path_metadata(path)?; - if self.path_exists_in_merged_view(path) { - return Err(Self::already_exists(path)); - } - self.ensure_ancestor_directories_in_upper(path)?; - self.writable_upper(path)? - .create_file_exclusive(path, content.into()) - } - - fn append_file(&mut self, path: &str, content: impl Into>) -> VfsResult { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("open", path)); - } - self.clear_path_metadata(path)?; - if self.find_lower_by_entry(path).is_some() { - self.copy_up_path(path)?; - } else { - self.ensure_ancestor_directories_in_upper(path)?; - } - self.writable_upper(path)?.append_file(path, content.into()) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("mkdir", path)); - } - self.clear_path_metadata(path)?; - if self.path_exists_in_merged_view(path) { - return Err(Self::already_exists(path)); - } - self.ensure_ancestor_directories_in_upper(path)?; - self.writable_upper(path)?.create_dir(path) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("mkdir", path)); - } - self.clear_path_metadata(path)?; - if self.path_exists_in_merged_view(path) { - let stat = self.merged_lstat(path)?; - if recursive && stat.is_directory && !stat.is_symbolic_link { - return Ok(()); - } - return Err(Self::already_exists(path)); - } - self.ensure_ancestor_directories_in_upper(path)?; - self.writable_upper(path)?.mkdir(path, recursive) - } - - fn exists(&self, path: &str) -> bool { - if self.touches_internal_metadata(path) { - return false; - } - self.path_exists_in_merged_view(path) - } - - fn stat(&mut self, path: &str) -> VfsResult { - if self.touches_internal_metadata(path) { - return Err(Self::entry_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if self.exists_in_upper(path) { - return self - .upper - .as_mut() - .expect("upper must exist when path exists") - .stat(path); - } - let Some(index) = self.find_lower_by_exists(path) else { - return Err(Self::entry_not_found(path)); - }; - self.lowers[index].stat(path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("unlink", path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - let lower_exists = self.find_lower_by_exists(path).is_some(); - let upper_exists = self.exists_in_upper(path); - if !lower_exists && !upper_exists { - return Err(Self::entry_not_found(path)); - } - if upper_exists { - self.writable_upper(path)?.remove_file(path)?; - } else { - self.writable_upper(path)?; - } - self.clear_opaque_directory(path)?; - self.add_whiteout(path)?; - Ok(()) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - let normalized = Self::normalized(path); - if self.touches_internal_metadata(&normalized) { - return Err(VfsError::permission_denied("rmdir", path)); - } - if normalized == "/" { - return Err(VfsError::permission_denied("rmdir", path)); - } - - let stat = match self.merged_lstat(path) { - Ok(stat) => stat, - Err(error) if error.code() == "ENOENT" => return Err(Self::directory_not_found(path)), - Err(error) => return Err(error), - }; - - if !stat.is_directory || stat.is_symbolic_link { - return Err(Self::not_directory(path)); - } - - if self.directory_has_raw_children(path)? { - return Err(Self::not_empty(path)); - } - - let lower_exists = self.find_lower_by_entry(path).is_some(); - let upper_exists = self.has_entry_in_upper(path); - if upper_exists { - self.writable_upper(path)?.remove_dir(&normalized)?; - } else { - self.writable_upper(path)?; - } - if lower_exists { - self.clear_opaque_directory(path)?; - self.add_whiteout(path)?; - } else { - self.clear_path_metadata(path)?; - } - Ok(()) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let old_normalized = Self::normalized(old_path); - let new_normalized = Self::normalized(new_path); - if self.touches_internal_metadata(&old_normalized) - || self.touches_internal_metadata(&new_normalized) - { - return Err(VfsError::permission_denied("rename", old_path)); - } - - if old_normalized == "/" { - return Err(VfsError::permission_denied("rename", old_path)); - } - - if old_normalized == new_normalized { - return Ok(()); - } - - let source_stat = self.merged_lstat(old_path)?; - self.validate_destination_parent(&new_normalized)?; - let resolved_new_normalized = self.resolved_destination_path(&new_normalized)?; - - if old_normalized == resolved_new_normalized { - return Ok(()); - } - - if source_stat.is_directory - && resolved_new_normalized.starts_with(&(old_normalized.clone() + "/")) - { - return Err(VfsError::new( - "EINVAL", - format!( - "cannot move '{}' into its own descendant '{}'", - old_path, new_path - ), - )); - } - - for path in self.destination_parent_copy_up_paths(&new_normalized)? { - self.materialize_destination_parent_in_upper(&path)?; - } - - let mut snapshot_entries = Vec::new(); - self.collect_snapshot_entries(&old_normalized, &mut snapshot_entries)?; - - if let Ok(destination_stat) = self.merged_lstat(&resolved_new_normalized) { - if destination_stat.is_directory - && !destination_stat.is_symbolic_link - && self.directory_has_visible_entries_limited(&resolved_new_normalized)? - { - return Err(Self::not_empty(&resolved_new_normalized)); - } - - if self.has_entry_in_upper(&resolved_new_normalized) { - if destination_stat.is_directory && !destination_stat.is_symbolic_link { - self.writable_upper(&resolved_new_normalized)? - .remove_dir(&resolved_new_normalized)?; - } else { - self.writable_upper(&resolved_new_normalized)? - .remove_file(&resolved_new_normalized)?; - } - } - self.clear_subtree_metadata(&resolved_new_normalized)?; - } - - self.stage_snapshot_entries_in_upper(&snapshot_entries)?; - self.copy_subtree_metadata(&old_normalized, &resolved_new_normalized)?; - self.writable_upper(&old_normalized)? - .rename(&old_normalized, &resolved_new_normalized)?; - self.remove_snapshot_entries(&snapshot_entries) - } - - fn realpath(&self, path: &str) -> VfsResult { - if self.touches_internal_metadata(path) { - return Err(Self::entry_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if self.exists_in_upper(path) { - return self - .upper - .as_ref() - .expect("upper must exist when path exists") - .realpath(path); - } - let Some(index) = self.find_lower_by_exists(path) else { - return Err(Self::entry_not_found(path)); - }; - self.lowers[index].realpath(path) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - if self.touches_internal_metadata(link_path) { - return Err(VfsError::permission_denied("symlink", link_path)); - } - self.clear_path_metadata(link_path)?; - self.ensure_ancestor_directories_in_upper(link_path)?; - self.writable_upper(link_path)?.symlink(target, link_path) - } - - fn read_link(&self, path: &str) -> VfsResult { - if self.touches_internal_metadata(path) { - return Err(Self::entry_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if self.has_entry_in_upper(path) { - return self - .upper - .as_ref() - .expect("upper must exist when path exists") - .read_link(path); - } - let Some((index, _)) = self.find_lower_by_entry(path) else { - return Err(Self::entry_not_found(path)); - }; - self.lowers[index].read_link(path) - } - - fn lstat(&self, path: &str) -> VfsResult { - if self.touches_internal_metadata(path) { - return Err(Self::entry_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if self.has_entry_in_upper(path) { - return self - .upper - .as_ref() - .expect("upper must exist when path exists") - .lstat(path); - } - self.find_lower_by_entry(path) - .map(|(_, stat)| stat) - .ok_or_else(|| Self::entry_not_found(path)) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - if self.touches_internal_metadata(old_path) || self.touches_internal_metadata(new_path) { - return Err(VfsError::permission_denied("link", new_path)); - } - self.clear_path_metadata(new_path)?; - self.copy_up_path(old_path)?; - self.ensure_ancestor_directories_in_upper(new_path)?; - self.writable_upper(new_path)?.link(old_path, new_path) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("chmod", path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if !self.exists_in_upper(path) { - self.copy_up_path(path)?; - } - self.writable_upper(path)?.chmod(path, mode) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("chown", path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if !self.exists_in_upper(path) { - self.copy_up_path(path)?; - } - self.writable_upper(path)?.chown(path, uid, gid) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("utime", path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if !self.exists_in_upper(path) { - self.copy_up_path(path)?; - } - self.writable_upper(path)?.utimes(path, atime_ms, mtime_ms) - } - - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("utime", path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if !self.exists_in_upper(path) { - self.copy_up_path(path)?; - } - self.writable_upper(path)? - .utimes_spec(path, atime, mtime, follow_symlinks) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - if self.touches_internal_metadata(path) { - return Err(VfsError::permission_denied("truncate", path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if !self.exists_in_upper(path) { - self.copy_up_path(path)?; - } - self.writable_upper(path)?.truncate(path, length) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - if self.touches_internal_metadata(path) { - return Err(Self::entry_not_found(path)); - } - if self.is_whited_out(path) { - return Err(Self::entry_not_found(path)); - } - if self.exists_in_upper(path) { - return self - .upper - .as_mut() - .expect("upper must exist when path exists") - .pread(path, offset, length); - } - let Some(index) = self.find_lower_by_exists(path) else { - return Err(Self::entry_not_found(path)); - }; - self.lowers[index].pread(path, offset, length) - } -} - -#[cfg(test)] -mod tests { - use super::{OverlayFileSystem, OverlayMode}; - use crate::posix::vfs::{MemoryFileSystem, VfsResult, VirtualFileSystem}; - - #[test] - fn symlink_into_metadata_namespace_cannot_read_or_resurrect_whiteouts() { - let mut lower = MemoryFileSystem::new(); - lower.mkdir("/data", true).expect("create lower directory"); - lower - .write_file("/data/secret.txt", b"secret".to_vec()) - .expect("seed lower file"); - - let mut overlay = OverlayFileSystem::with_upper(vec![lower], MemoryFileSystem::new()); - - // Delete a lower-layer file: a whiteout marker is written under the - // reserved metadata root and the file disappears from the merged view. - overlay - .remove_file("/data/secret.txt") - .expect("whiteout lower file"); - assert!(!overlay.exists("/data/secret.txt")); - - // A guest symlink whose target is the metadata root must not become a - // window into the reserved namespace. - overlay - .symlink("/.secure-exec-overlay/whiteouts", "/escape") - .expect("creating the symlink itself is allowed"); - - // Listing through the symlink must be denied, not disclose markers. - assert!( - overlay.read_dir("/escape").is_err(), - "listing the metadata namespace via a symlink must be denied" - ); - - // Removing the whiteout marker through the symlink must be denied, so the - // deleted lower-layer file cannot be resurrected. - assert!( - overlay.remove_file("/escape/anything").is_err(), - "tampering with metadata via a symlink must be denied" - ); - assert!( - !overlay.exists("/data/secret.txt"), - "deleted lower-layer file must stay deleted" - ); - - // The same bypass via a symlink to an ancestor (e.g. `/`) is also closed. - overlay - .symlink("/", "/rootlink") - .expect("symlink to root is allowed"); - assert!( - overlay - .read_dir("/rootlink/.secure-exec-overlay/whiteouts") - .is_err(), - "metadata must be unreachable via an ancestor symlink too" - ); - } - - #[test] - fn whiteouts_persist_when_overlay_reopens_with_same_upper() { - let mut lower = MemoryFileSystem::new(); - lower.mkdir("/data", true).expect("create lower directory"); - lower - .write_file("/data/base.txt", b"base".to_vec()) - .expect("seed lower file"); - let lower_snapshot = lower.snapshot(); - - let mut overlay = OverlayFileSystem::with_upper( - vec![MemoryFileSystem::from_snapshot(lower_snapshot.clone())], - MemoryFileSystem::new(), - ); - overlay - .remove_file("/data/base.txt") - .expect("whiteout lower file"); - - let upper = overlay.upper.take().expect("overlay upper"); - let restored_lower = MemoryFileSystem::from_snapshot(lower_snapshot); - let mut restored = OverlayFileSystem::with_upper(vec![restored_lower], upper); - - assert!(!restored.exists("/data/base.txt")); - assert_eq!( - restored.read_dir("/data").expect("read merged directory"), - Vec::::new() - ); - } - - #[test] - fn copied_up_directories_become_opaque_and_hide_overlay_metadata() { - let mut lower = MemoryFileSystem::new(); - lower.mkdir("/data", true).expect("create lower directory"); - lower - .write_file("/data/base.txt", b"base".to_vec()) - .expect("seed lower file"); - - let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); - overlay - .chmod("/data", 0o700) - .expect("copy up lower directory"); - - assert_eq!( - overlay.read_dir("/data").expect("read opaque directory"), - Vec::::new() - ); - let root_entries = overlay.read_dir("/").expect("read root"); - assert!(!root_entries - .iter() - .any(|entry| entry == ".secure-exec-overlay")); - } - - #[test] - fn remove_dir_succeeds_when_only_lower_children_are_whited_out() { - let mut lower = MemoryFileSystem::new(); - lower.mkdir("/a", true).expect("create lower directory"); - lower - .write_file("/a/c", b"child".to_vec()) - .expect("seed lower child"); - - let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); - overlay.remove_file("/a/c").expect("whiteout lower child"); - overlay - .remove_dir("/a") - .expect("remove merged-empty directory"); - - assert!(!overlay.exists("/a")); - assert_error_code(overlay.read_dir("/a"), "ENOENT"); - } - - #[test] - fn remove_dir_still_rejects_visible_children() { - let mut lower = MemoryFileSystem::new(); - lower.mkdir("/a", true).expect("create lower directory"); - lower - .write_file("/a/c", b"child".to_vec()) - .expect("seed lower child"); - - let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); - assert_error_code(overlay.remove_dir("/a"), "ENOTEMPTY"); - assert!(overlay.exists("/a/c")); - } - - fn assert_error_code(result: VfsResult, expected: &str) { - let error = result.expect_err("expected operation to fail"); - assert_eq!(error.code(), expected); - } -} diff --git a/crates/vfs/src/posix/root_fs.rs b/crates/vfs/src/posix/root_fs.rs deleted file mode 100644 index bcfa06b31..000000000 --- a/crates/vfs/src/posix/root_fs.rs +++ /dev/null @@ -1,1014 +0,0 @@ -use super::overlay_fs::{OverlayFileSystem, OverlayMode}; -use super::usage::{ - RootFilesystemResourceLimits, DEFAULT_MAX_FILESYSTEM_BYTES, DEFAULT_MAX_INODE_COUNT, -}; -use super::vfs::{ - normalize_path, MemoryFileSystem, VfsError, VfsResult, VirtualFileSystem, VirtualStat, - VirtualUtimeSpec, MAX_PATH_LENGTH, -}; -use crate::posix::vfs::VirtualDirEntry; -use base64::Engine; -use serde::Deserialize; -use std::collections::BTreeSet; - -// The base filesystem fixture is staged into OUT_DIR by build.rs: copied from -// the canonical `packages/secure-exec-core/fixtures/base-filesystem.json` -// during in-tree builds, or from the vendored `assets/base-filesystem.json` -// copy bundled in the published crate. -const BUNDLED_BASE_FILESYSTEM_JSON: &str = - include_str!(concat!(env!("OUT_DIR"), "/base-filesystem.json")); -pub const ROOT_FILESYSTEM_SNAPSHOT_FORMAT: &str = "secure_exec_filesystem_snapshot_v1"; -const LEGACY_AGENTOS_ROOT_FILESYSTEM_SNAPSHOT_FORMAT: &str = "agentos_filesystem_snapshot_v1"; -const ROOT_FILESYSTEM_SNAPSHOT_FIXED_OVERHEAD_BYTES: usize = 4 * 1024; -const ROOT_FILESYSTEM_SNAPSHOT_ENTRY_OVERHEAD_BYTES: usize = MAX_PATH_LENGTH + 1024; -const DEFAULT_ROOT_DIRECTORIES: &[&str] = &[ - "/", - "/dev", - "/proc", - "/tmp", - "/bin", - "/lib", - "/sbin", - "/boot", - "/etc", - "/root", - "/run", - "/srv", - "/sys", - "/opt", - "/mnt", - "/media", - "/home", - "/usr", - "/usr/bin", - "/usr/games", - "/usr/include", - "/usr/lib", - "/usr/libexec", - "/usr/man", - "/usr/local", - "/usr/local/bin", - "/usr/sbin", - "/usr/share", - "/usr/share/man", - "/var", - "/var/cache", - "/var/empty", - "/var/lib", - "/var/lock", - "/var/log", - "/var/run", - "/var/spool", - "/var/tmp", - "/etc/agentos", -]; -const KERNEL_RESERVED_BOOTSTRAP_PATH_PREFIXES: &[&str] = &["/dev", "/proc", "/sys"]; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RootFilesystemError { - message: String, -} - -impl RootFilesystemError { - fn new(message: impl Into) -> Self { - Self { - message: message.into(), - } - } -} - -impl std::fmt::Display for RootFilesystemError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.message) - } -} - -impl std::error::Error for RootFilesystemError {} - -impl From for RootFilesystemError { - fn from(error: VfsError) -> Self { - Self::new(error.to_string()) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum FilesystemEntryKind { - File, - Directory, - Symlink, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FilesystemEntry { - pub path: String, - pub kind: FilesystemEntryKind, - pub mode: u32, - pub uid: u32, - pub gid: u32, - pub content: Option>, - pub target: Option, -} - -impl FilesystemEntry { - pub fn directory(path: impl Into) -> Self { - Self { - path: path.into(), - kind: FilesystemEntryKind::Directory, - mode: 0o755, - uid: 0, - gid: 0, - content: None, - target: None, - } - } - - pub fn file(path: impl Into, content: impl Into>) -> Self { - Self { - path: path.into(), - kind: FilesystemEntryKind::File, - mode: 0o644, - uid: 0, - gid: 0, - content: Some(content.into()), - target: None, - } - } - - pub fn symlink(path: impl Into, target: impl Into) -> Self { - Self { - path: path.into(), - kind: FilesystemEntryKind::Symlink, - mode: 0o777, - uid: 0, - gid: 0, - content: None, - target: Some(target.into()), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RootFilesystemSnapshot { - pub entries: Vec, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct RootFilesystemImportLimits { - pub max_encoded_snapshot_bytes: Option, - pub max_filesystem_bytes: Option, - pub max_inode_count: Option, -} - -impl RootFilesystemImportLimits { - pub fn from_resource_limits(limits: &impl RootFilesystemResourceLimits) -> Self { - Self { - max_encoded_snapshot_bytes: encoded_snapshot_limit( - limits.max_filesystem_bytes(), - limits.max_inode_count(), - ), - max_filesystem_bytes: limits.max_filesystem_bytes(), - max_inode_count: limits.max_inode_count(), - } - } -} - -impl Default for RootFilesystemImportLimits { - fn default() -> Self { - Self { - max_encoded_snapshot_bytes: encoded_snapshot_limit( - Some(DEFAULT_MAX_FILESYSTEM_BYTES), - Some(DEFAULT_MAX_INODE_COUNT), - ), - max_filesystem_bytes: Some(DEFAULT_MAX_FILESYSTEM_BYTES), - max_inode_count: Some(DEFAULT_MAX_INODE_COUNT), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum RootFilesystemMode { - Ephemeral, - ReadOnly, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RootFilesystemDescriptor { - pub mode: RootFilesystemMode, - pub disable_default_base_layer: bool, - pub lowers: Vec, - pub bootstrap_entries: Vec, -} - -impl Default for RootFilesystemDescriptor { - fn default() -> Self { - Self { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - } - } -} - -#[derive(Debug)] -pub struct RootFileSystem { - overlay: OverlayFileSystem, - mode: RootFilesystemMode, - bootstrap_finished: bool, -} - -impl RootFileSystem { - pub fn from_descriptor( - descriptor: RootFilesystemDescriptor, - ) -> Result { - Self::from_descriptor_with_import_limits(descriptor, &RootFilesystemImportLimits::default()) - } - - pub fn from_descriptor_with_import_limits( - descriptor: RootFilesystemDescriptor, - limits: &RootFilesystemImportLimits, - ) -> Result { - let mut lower_snapshots = descriptor.lowers.clone(); - if !descriptor.disable_default_base_layer { - lower_snapshots.push(load_bundled_base_snapshot_with_limits(limits)?); - } else if lower_snapshots.is_empty() { - lower_snapshots.push(minimal_root_snapshot()); - } - validate_descriptor_import_limits( - &lower_snapshots, - &descriptor.bootstrap_entries, - limits, - "root filesystem descriptor", - )?; - - let lowers = lower_snapshots - .iter() - .map(snapshot_to_memory_filesystem) - .collect::, _>>()?; - - let mut root = Self { - overlay: OverlayFileSystem::new(lowers, OverlayMode::Ephemeral), - mode: descriptor.mode, - bootstrap_finished: false, - }; - root.apply_bootstrap_entries(&descriptor.bootstrap_entries)?; - Ok(root) - } - - pub fn apply_bootstrap_entries( - &mut self, - entries: &[FilesystemEntry], - ) -> Result<(), RootFilesystemError> { - if self.bootstrap_finished { - return Err(RootFilesystemError::new( - "root filesystem bootstrap is already finished", - )); - } - - for entry in sort_entries(entries.to_vec()) { - if is_kernel_reserved_bootstrap_path(&entry.path) { - continue; - } - apply_entry(&mut self.overlay, &entry)?; - } - Ok(()) - } - - pub fn finish_bootstrap(&mut self) { - if self.bootstrap_finished { - return; - } - self.bootstrap_finished = true; - if self.mode == RootFilesystemMode::ReadOnly { - self.overlay.lock_writes(); - } - } - - pub fn snapshot(&mut self) -> Result { - Ok(RootFilesystemSnapshot { - entries: snapshot_virtual_filesystem(&mut self.overlay, "/")?, - }) - } - - pub fn check_rename_copy_up_limits( - &mut self, - old_path: &str, - new_path: &str, - max_bytes: Option, - max_inodes: Option, - ) -> VfsResult<()> { - self.overlay - .check_rename_copy_up_limits(old_path, new_path, max_bytes, max_inodes) - } -} - -impl VirtualFileSystem for RootFileSystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - self.overlay.read_file(path) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - self.overlay.read_dir(path) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - self.overlay.read_dir_limited(path, max_entries) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - self.overlay.read_dir_with_types(path) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - self.overlay.write_file(path, content.into()) - } - - fn create_file_exclusive(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - self.overlay.create_file_exclusive(path, content.into()) - } - - fn append_file(&mut self, path: &str, content: impl Into>) -> VfsResult { - self.overlay.append_file(path, content.into()) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - self.overlay.create_dir(path) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - self.overlay.mkdir(path, recursive) - } - - fn exists(&self, path: &str) -> bool { - self.overlay.exists(path) - } - - fn stat(&mut self, path: &str) -> VfsResult { - self.overlay.stat(path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - self.overlay.remove_file(path) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - self.overlay.remove_dir(path) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.overlay.rename(old_path, new_path) - } - - fn realpath(&self, path: &str) -> VfsResult { - self.overlay.realpath(path) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - self.overlay.symlink(target, link_path) - } - - fn read_link(&self, path: &str) -> VfsResult { - self.overlay.read_link(path) - } - - fn lstat(&self, path: &str) -> VfsResult { - self.overlay.lstat(path) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - self.overlay.link(old_path, new_path) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - self.overlay.chmod(path, mode) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - self.overlay.chown(path, uid, gid) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - self.overlay.utimes(path, atime_ms, mtime_ms) - } - - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - self.overlay - .utimes_spec(path, atime, mtime, follow_symlinks) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - self.overlay.truncate(path, length) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - self.overlay.pread(path, offset, length) - } -} - -#[derive(Debug, Deserialize)] -struct RawBaseFilesystemSnapshot { - filesystem: RawFilesystemEntries, -} - -#[derive(Debug, Deserialize)] -struct RawFilesystemEntries { - entries: Vec, -} - -#[derive(Debug, Deserialize)] -struct RawFilesystemEntry { - path: String, - #[serde(rename = "type")] - kind: RawFilesystemEntryKind, - mode: String, - uid: u32, - gid: u32, - #[serde(default)] - content: Option, - #[serde(default)] - encoding: Option, - #[serde(default)] - target: Option, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "snake_case")] -enum RawFilesystemEntryKind { - File, - Directory, - Symlink, -} - -#[derive(Debug, Deserialize)] -struct RawSnapshotExport { - format: String, - filesystem: RawFilesystemEntries, -} - -#[derive(Debug, serde::Serialize)] -struct SnapshotExport<'a> { - format: &'static str, - filesystem: SnapshotFilesystem<'a>, -} - -#[derive(Debug, serde::Serialize)] -struct SnapshotFilesystem<'a> { - entries: Vec>, -} - -#[derive(Debug, serde::Serialize)] -struct SerializedFilesystemEntry<'a> { - path: &'a str, - #[serde(rename = "type")] - kind: &'static str, - mode: String, - uid: u32, - gid: u32, - #[serde(skip_serializing_if = "Option::is_none")] - content: Option, - #[serde(skip_serializing_if = "Option::is_none")] - encoding: Option<&'static str>, - #[serde(skip_serializing_if = "Option::is_none")] - target: Option<&'a str>, -} - -pub fn encode_snapshot(snapshot: &RootFilesystemSnapshot) -> Result, RootFilesystemError> { - let serialized_entries = snapshot - .entries - .iter() - .map(|entry| SerializedFilesystemEntry { - path: &entry.path, - kind: match entry.kind { - FilesystemEntryKind::File => "file", - FilesystemEntryKind::Directory => "directory", - FilesystemEntryKind::Symlink => "symlink", - }, - mode: format!("{:o}", entry.mode), - uid: entry.uid, - gid: entry.gid, - content: entry - .content - .as_ref() - .map(|bytes| base64::engine::general_purpose::STANDARD.encode(bytes)), - encoding: entry.content.as_ref().map(|_| "base64"), - target: entry.target.as_deref(), - }) - .collect::>(); - - serde_json::to_vec(&SnapshotExport { - format: ROOT_FILESYSTEM_SNAPSHOT_FORMAT, - filesystem: SnapshotFilesystem { - entries: serialized_entries, - }, - }) - .map_err(|error| RootFilesystemError::new(format!("serialize root snapshot: {error}"))) -} - -pub fn decode_snapshot(bytes: &[u8]) -> Result { - decode_snapshot_with_import_limits(bytes, &RootFilesystemImportLimits::default()) -} - -pub fn decode_snapshot_with_import_limits( - bytes: &[u8], - limits: &RootFilesystemImportLimits, -) -> Result { - validate_encoded_snapshot_size(bytes, limits, "root snapshot")?; - let raw: RawSnapshotExport = serde_json::from_slice(bytes) - .map_err(|error| RootFilesystemError::new(format!("parse root snapshot: {error}")))?; - if !is_supported_root_filesystem_snapshot_format(&raw.format) { - return Err(RootFilesystemError::new(format!( - "unsupported root snapshot format: {}", - raw.format - ))); - } - raw_entries_to_snapshot(raw.filesystem.entries, limits, "root snapshot") -} - -pub fn is_supported_root_filesystem_snapshot_format(format: &str) -> bool { - format == ROOT_FILESYSTEM_SNAPSHOT_FORMAT - || format == LEGACY_AGENTOS_ROOT_FILESYSTEM_SNAPSHOT_FORMAT -} - -pub fn load_bundled_base_snapshot_with_limits( - limits: &RootFilesystemImportLimits, -) -> Result { - validate_encoded_snapshot_size( - BUNDLED_BASE_FILESYSTEM_JSON.as_bytes(), - limits, - "bundled base filesystem", - )?; - let raw: RawBaseFilesystemSnapshot = serde_json::from_str(BUNDLED_BASE_FILESYSTEM_JSON) - .map_err(|error| { - RootFilesystemError::new(format!("parse bundled base filesystem: {error}")) - })?; - raw_entries_to_snapshot(raw.filesystem.entries, limits, "bundled base filesystem") -} - -fn minimal_root_snapshot() -> RootFilesystemSnapshot { - let mut entries = DEFAULT_ROOT_DIRECTORIES - .iter() - .map(|path| FilesystemEntry::directory(*path)) - .collect::>(); - entries.push(FilesystemEntry::file("/usr/bin/env", Vec::new())); - RootFilesystemSnapshot { entries } -} - -fn convert_raw_entry(raw: RawFilesystemEntry) -> Result { - let content = match raw.content { - Some(content) => match raw.encoding.as_deref() { - Some("base64") => Some( - base64::engine::general_purpose::STANDARD - .decode(content) - .map_err(|error| { - RootFilesystemError::new(format!( - "decode base64 content for {}: {error}", - raw.path - )) - })?, - ), - Some("utf8") | None => Some(content.into_bytes()), - Some(other) => { - return Err(RootFilesystemError::new(format!( - "unsupported content encoding for {}: {other}", - raw.path - ))); - } - }, - None => None, - }; - - Ok(FilesystemEntry { - path: raw.path, - kind: match raw.kind { - RawFilesystemEntryKind::File => FilesystemEntryKind::File, - RawFilesystemEntryKind::Directory => FilesystemEntryKind::Directory, - RawFilesystemEntryKind::Symlink => FilesystemEntryKind::Symlink, - }, - mode: u32::from_str_radix(&raw.mode, 8).map_err(|error| { - RootFilesystemError::new(format!("parse mode {}: {error}", raw.mode)) - })?, - uid: raw.uid, - gid: raw.gid, - content, - target: raw.target, - }) -} - -fn raw_entries_to_snapshot( - raw_entries: Vec, - limits: &RootFilesystemImportLimits, - context: &str, -) -> Result { - if let Some(limit) = limits.max_inode_count { - if raw_entries.len() > limit { - return Err(RootFilesystemError::new(format!( - "{context} contains {} entries, exceeding limit {limit}", - raw_entries.len() - ))); - } - } - - let entries = raw_entries - .into_iter() - .map(convert_raw_entry) - .collect::, _>>()?; - validate_entry_import_limits(&entries, limits, context)?; - Ok(RootFilesystemSnapshot { entries }) -} - -pub fn validate_snapshot_import_limits( - snapshot: &RootFilesystemSnapshot, - limits: &RootFilesystemImportLimits, - context: &str, -) -> Result<(), RootFilesystemError> { - validate_entry_import_limits(&snapshot.entries, limits, context) -} - -fn validate_descriptor_import_limits( - lowers: &[RootFilesystemSnapshot], - bootstrap_entries: &[FilesystemEntry], - limits: &RootFilesystemImportLimits, - context: &str, -) -> Result<(), RootFilesystemError> { - let explicit_entry_count = lowers - .iter() - .map(|snapshot| snapshot.entries.len()) - .sum::() - .saturating_add(bootstrap_entries.len()); - let mut inode_paths = BTreeSet::new(); - for snapshot in lowers { - collect_materialized_entry_paths(&snapshot.entries, &mut inode_paths); - } - collect_materialized_entry_paths(bootstrap_entries, &mut inode_paths); - let inode_count = inode_paths.len(); - if let Some(limit) = limits.max_inode_count { - if explicit_entry_count > limit { - return Err(RootFilesystemError::new(format!( - "{context} contains {explicit_entry_count} entries, exceeding limit {limit}" - ))); - } - - if inode_count > limit { - return Err(RootFilesystemError::new(format!( - "{context} contains {inode_count} entries, exceeding limit {limit}" - ))); - } - } - - let mut bytes = 0_u64; - for snapshot in lowers { - bytes = bytes.saturating_add(entry_content_bytes(&snapshot.entries)); - } - bytes = bytes.saturating_add(entry_content_bytes(bootstrap_entries)); - if let Some(limit) = limits.max_filesystem_bytes { - if bytes > limit { - return Err(RootFilesystemError::new(format!( - "{context} contains {bytes} bytes, exceeding limit {limit}" - ))); - } - } - Ok(()) -} - -fn validate_entry_import_limits( - entries: &[FilesystemEntry], - limits: &RootFilesystemImportLimits, - context: &str, -) -> Result<(), RootFilesystemError> { - if let Some(limit) = limits.max_inode_count { - if entries.len() > limit { - return Err(RootFilesystemError::new(format!( - "{context} contains {} entries, exceeding limit {limit}", - entries.len() - ))); - } - - let inode_count = materialized_entry_inode_count(entries); - if inode_count > limit { - return Err(RootFilesystemError::new(format!( - "{context} contains {inode_count} entries, exceeding limit {limit}" - ))); - } - } - - let bytes = entry_content_bytes(entries); - if let Some(limit) = limits.max_filesystem_bytes { - if bytes > limit { - return Err(RootFilesystemError::new(format!( - "{context} contains {bytes} bytes, exceeding limit {limit}" - ))); - } - } - Ok(()) -} - -fn validate_encoded_snapshot_size( - bytes: &[u8], - limits: &RootFilesystemImportLimits, - context: &str, -) -> Result<(), RootFilesystemError> { - if let Some(limit) = limits.max_encoded_snapshot_bytes { - if bytes.len() > limit { - return Err(RootFilesystemError::new(format!( - "{context} contains {} encoded bytes, exceeding limit {limit}", - bytes.len() - ))); - } - } - Ok(()) -} - -fn entry_content_bytes(entries: &[FilesystemEntry]) -> u64 { - entries.iter().fold(0_u64, |total, entry| { - total.saturating_add(match entry.kind { - FilesystemEntryKind::File => entry - .content - .as_ref() - .map(|content| usize_to_u64(content.len())) - .unwrap_or(0), - FilesystemEntryKind::Directory => 0, - FilesystemEntryKind::Symlink => entry - .target - .as_ref() - .map(|target| usize_to_u64(target.len())) - .unwrap_or(0), - }) - }) -} - -fn materialized_entry_inode_count(entries: &[FilesystemEntry]) -> usize { - let mut paths = BTreeSet::new(); - collect_materialized_entry_paths(entries, &mut paths); - paths.len() -} - -fn collect_materialized_entry_paths(entries: &[FilesystemEntry], paths: &mut BTreeSet) { - for entry in entries { - collect_materialized_path(&entry.path, paths); - } -} - -fn collect_materialized_path(path: &str, paths: &mut BTreeSet) { - let normalized = normalize_path(path); - paths.insert(normalized.clone()); - - let mut parent = String::new(); - let segments = normalized - .split('/') - .filter(|segment| !segment.is_empty()) - .collect::>(); - for segment in segments.iter().take(segments.len().saturating_sub(1)) { - parent.push('/'); - parent.push_str(segment); - paths.insert(parent.clone()); - } -} - -fn usize_to_u64(value: usize) -> u64 { - u64::try_from(value).unwrap_or(u64::MAX) -} - -const fn u64_limit_to_usize(value: u64) -> usize { - if value > usize::MAX as u64 { - usize::MAX - } else { - value as usize - } -} - -const fn encoded_snapshot_limit( - max_filesystem_bytes: Option, - max_inode_count: Option, -) -> Option { - let Some(max_filesystem_bytes) = max_filesystem_bytes else { - return None; - }; - - Some( - u64_limit_to_usize(max_filesystem_bytes) - .saturating_mul(2) - .saturating_add(match max_inode_count { - Some(max_inode_count) => { - max_inode_count.saturating_mul(ROOT_FILESYSTEM_SNAPSHOT_ENTRY_OVERHEAD_BYTES) - } - None => 0, - }) - .saturating_add(ROOT_FILESYSTEM_SNAPSHOT_FIXED_OVERHEAD_BYTES), - ) -} - -fn snapshot_to_memory_filesystem( - snapshot: &RootFilesystemSnapshot, -) -> Result { - let mut filesystem = MemoryFileSystem::new(); - for entry in sort_entries(snapshot.entries.clone()) { - apply_entry_to_memory_filesystem(&mut filesystem, &entry)?; - } - Ok(filesystem) -} - -fn apply_entry_to_memory_filesystem( - filesystem: &mut MemoryFileSystem, - entry: &FilesystemEntry, -) -> Result<(), RootFilesystemError> { - ensure_parent_directories(filesystem, &entry.path)?; - - match entry.kind { - FilesystemEntryKind::Directory => { - filesystem.mkdir(&entry.path, true)?; - filesystem.chmod(&entry.path, entry.mode)?; - filesystem.chown(&entry.path, entry.uid, entry.gid)?; - } - FilesystemEntryKind::File => { - filesystem.write_file(&entry.path, entry.content.clone().unwrap_or_default())?; - filesystem.chmod(&entry.path, entry.mode)?; - filesystem.chown(&entry.path, entry.uid, entry.gid)?; - } - FilesystemEntryKind::Symlink => { - let Some(target) = entry.target.as_deref() else { - return Err(RootFilesystemError::new(format!( - "missing symlink target for {}", - entry.path - ))); - }; - filesystem.symlink_with_metadata( - target, - &entry.path, - entry.mode, - entry.uid, - entry.gid, - )?; - } - } - - Ok(()) -} - -fn apply_entry( - filesystem: &mut impl VirtualFileSystem, - entry: &FilesystemEntry, -) -> Result<(), RootFilesystemError> { - ensure_parent_directories(filesystem, &entry.path)?; - - match entry.kind { - FilesystemEntryKind::Directory => { - filesystem.mkdir(&entry.path, true)?; - filesystem.chmod(&entry.path, entry.mode)?; - filesystem.chown(&entry.path, entry.uid, entry.gid)?; - } - FilesystemEntryKind::File => { - filesystem.write_file(&entry.path, entry.content.clone().unwrap_or_default())?; - filesystem.chmod(&entry.path, entry.mode)?; - filesystem.chown(&entry.path, entry.uid, entry.gid)?; - } - FilesystemEntryKind::Symlink => { - let Some(target) = entry.target.as_deref() else { - return Err(RootFilesystemError::new(format!( - "missing symlink target for {}", - entry.path - ))); - }; - filesystem.symlink(target, &entry.path)?; - } - } - - Ok(()) -} - -fn ensure_parent_directories( - filesystem: &mut impl VirtualFileSystem, - path: &str, -) -> Result<(), RootFilesystemError> { - let normalized = normalize_path(path); - let mut current = String::new(); - let segments = normalized - .split('/') - .filter(|segment| !segment.is_empty()) - .collect::>(); - - for segment in segments.iter().take(segments.len().saturating_sub(1)) { - current.push('/'); - current.push_str(segment); - - if filesystem.exists(¤t) { - continue; - } - - filesystem.create_dir(¤t)?; - filesystem.chmod(¤t, 0o755)?; - filesystem.chown(¤t, 0, 0)?; - } - - Ok(()) -} - -fn sort_entries(mut entries: Vec) -> Vec { - entries.sort_by(|left, right| { - let depth_left = if left.path == "/" { - 0 - } else { - left.path.split('/').filter(|part| !part.is_empty()).count() - }; - let depth_right = if right.path == "/" { - 0 - } else { - right - .path - .split('/') - .filter(|part| !part.is_empty()) - .count() - }; - depth_left - .cmp(&depth_right) - .then_with(|| left.path.cmp(&right.path)) - }); - entries -} - -fn snapshot_virtual_filesystem( - filesystem: &mut impl VirtualFileSystem, - root_path: &str, -) -> Result, RootFilesystemError> { - let mut entries = Vec::new(); - snapshot_path(filesystem, root_path, &mut entries)?; - Ok(entries) -} - -fn snapshot_path( - filesystem: &mut impl VirtualFileSystem, - path: &str, - entries: &mut Vec, -) -> Result<(), RootFilesystemError> { - let stat = if path == "/" { - filesystem.stat(path)? - } else { - filesystem.lstat(path)? - }; - - if stat.is_symbolic_link { - entries.push(FilesystemEntry { - path: path.to_owned(), - kind: FilesystemEntryKind::Symlink, - mode: stat.mode, - uid: stat.uid, - gid: stat.gid, - content: None, - target: Some(filesystem.read_link(path)?), - }); - return Ok(()); - } - - if stat.is_directory { - entries.push(FilesystemEntry { - path: path.to_owned(), - kind: FilesystemEntryKind::Directory, - mode: stat.mode, - uid: stat.uid, - gid: stat.gid, - content: None, - target: None, - }); - - let mut children = filesystem - .read_dir_with_types(path)? - .into_iter() - .map(|entry| entry.name) - .filter(|name| name != "." && name != "..") - .collect::>(); - children.sort(); - - for child in children { - let child_path = if path == "/" { - format!("/{child}") - } else { - format!("{path}/{child}") - }; - snapshot_path(filesystem, &child_path, entries)?; - } - return Ok(()); - } - - entries.push(FilesystemEntry { - path: path.to_owned(), - kind: FilesystemEntryKind::File, - mode: stat.mode, - uid: stat.uid, - gid: stat.gid, - content: Some(filesystem.read_file(path)?), - target: None, - }); - Ok(()) -} - -fn is_kernel_reserved_bootstrap_path(path: &str) -> bool { - let normalized = normalize_path(path); - KERNEL_RESERVED_BOOTSTRAP_PATH_PREFIXES - .iter() - .any(|prefix| normalized == *prefix || normalized.starts_with(&format!("{prefix}/"))) -} diff --git a/crates/vfs/src/posix/single_symlink_fs.rs b/crates/vfs/src/posix/single_symlink_fs.rs deleted file mode 100644 index a4c239119..000000000 --- a/crates/vfs/src/posix/single_symlink_fs.rs +++ /dev/null @@ -1,187 +0,0 @@ -use super::vfs::{ - VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, VirtualUtimeSpec, S_IFLNK, -}; - -/// Tiny read-only filesystem whose root inode is a single symbolic link. -/// -/// Package projection uses this for managed leaves such as -/// `/opt/agentos/bin/` and `/opt/agentos/pkgs//current`. A normal -/// `MemoryFileSystem` cannot model that shape because its root inode is always -/// a directory. Keeping each managed symlink as its own leaf mount lets the -/// parent directories remain writable overlay directories, so user-installed -/// commands and packages can coexist beside managed entries. -#[derive(Debug, Clone)] -pub struct SingleSymlinkFileSystem { - target: String, -} - -impl SingleSymlinkFileSystem { - pub fn new(target: impl Into) -> Self { - Self { - target: target.into(), - } - } - - pub fn target(&self) -> &str { - &self.target - } - - fn root_stat(&self) -> VirtualStat { - VirtualStat { - mode: S_IFLNK | 0o777, - size: self.target.len() as u64, - blocks: 0, - dev: 9101, - rdev: 0, - is_directory: false, - is_symbolic_link: true, - atime_ms: 0, - atime_nsec: 0, - mtime_ms: 0, - mtime_nsec: 0, - ctime_ms: 0, - ctime_nsec: 0, - birthtime_ms: 0, - ino: 1, - nlink: 1, - uid: 1000, - gid: 1000, - } - } - - fn not_found(path: &str) -> VfsError { - VfsError::new("ENOENT", format!("no such file or directory, '{path}'")) - } - - fn readonly(op: &str, path: &str) -> VfsError { - VfsError::new( - "EROFS", - format!("read-only single-symlink filesystem, {op} '{path}'"), - ) - } -} - -impl VirtualFileSystem for SingleSymlinkFileSystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - Err(Self::not_found(path)) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - Err(VfsError::new( - "ENOTDIR", - format!("not a directory, readdir '{path}'"), - )) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - Err(VfsError::new( - "ENOTDIR", - format!("not a directory, readdir '{path}'"), - )) - } - - fn write_file(&mut self, path: &str, _content: impl Into>) -> VfsResult<()> { - Err(Self::readonly("write", path)) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - Err(Self::readonly("mkdir", path)) - } - - fn mkdir(&mut self, path: &str, _recursive: bool) -> VfsResult<()> { - Err(Self::readonly("mkdir", path)) - } - - fn exists(&self, path: &str) -> bool { - path == "/" - } - - fn stat(&mut self, path: &str) -> VfsResult { - self.lstat(path) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - Err(Self::readonly("unlink", path)) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - Err(Self::readonly("rmdir", path)) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only single-symlink filesystem, rename '{old_path}' to '{new_path}'"), - )) - } - - fn realpath(&self, path: &str) -> VfsResult { - if path == "/" { - return Err(VfsError::new( - "ELOOP", - "single-symlink root must be resolved by the mount table", - )); - } - Err(Self::not_found(path)) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only single-symlink filesystem, symlink '{link_path}' -> '{target}'"), - )) - } - - fn read_link(&self, path: &str) -> VfsResult { - if path == "/" { - Ok(self.target.clone()) - } else { - Err(Self::not_found(path)) - } - } - - fn lstat(&self, path: &str) -> VfsResult { - if path == "/" { - Ok(self.root_stat()) - } else { - Err(Self::not_found(path)) - } - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only single-symlink filesystem, link '{old_path}' to '{new_path}'"), - )) - } - - fn chmod(&mut self, path: &str, _mode: u32) -> VfsResult<()> { - Err(Self::readonly("chmod", path)) - } - - fn chown(&mut self, path: &str, _uid: u32, _gid: u32) -> VfsResult<()> { - Err(Self::readonly("chown", path)) - } - - fn utimes(&mut self, path: &str, _atime_ms: u64, _mtime_ms: u64) -> VfsResult<()> { - Err(Self::readonly("utimes", path)) - } - - fn utimes_spec( - &mut self, - path: &str, - _atime: VirtualUtimeSpec, - _mtime: VirtualUtimeSpec, - _follow_symlinks: bool, - ) -> VfsResult<()> { - Err(Self::readonly("utimes", path)) - } - - fn truncate(&mut self, path: &str, _length: u64) -> VfsResult<()> { - Err(Self::readonly("truncate", path)) - } - - fn pread(&mut self, path: &str, _offset: u64, _length: usize) -> VfsResult> { - Err(Self::not_found(path)) - } -} diff --git a/crates/vfs/src/posix/tar_fs.rs b/crates/vfs/src/posix/tar_fs.rs deleted file mode 100644 index cc4eeaf8b..000000000 --- a/crates/vfs/src/posix/tar_fs.rs +++ /dev/null @@ -1,793 +0,0 @@ -#![allow(unsafe_code)] - -use super::vfs::{ - normalize_path, VfsError, VfsResult, VirtualDirEntry, VirtualFileSystem, VirtualStat, - VirtualUtimeSpec, S_IFDIR, S_IFLNK, S_IFREG, -}; -use memmap2::Mmap; -use std::collections::{BTreeMap, BTreeSet}; -use std::fs::File; -use std::hash::{Hash, Hasher}; -use std::io; -use std::path::{Component, Path, PathBuf}; -use std::sync::{Arc, Mutex, OnceLock, Weak}; -use tar::EntryType; - -const MAX_TAR_INDEX_ENTRIES: usize = 200_000; -const MAX_TAR_CACHE_ARCHIVES: usize = 64; -const MAX_TAR_SYMLINKS: usize = 40; - -/// Read-only filesystem backed directly by an uncompressed package tar. -/// -/// The package tar already contains each file's bytes at a stable byte range, -/// so mounting it is cheaper and simpler than extracting it: we scan headers -/// once, store `path -> offset/size/metadata`, and serve reads from a shared -/// `mmap` slice. Extraction would create a duplicate host tree, thousands of -/// physical inodes, and a cleanup problem before reading the same bytes again. -/// -/// Performance is intentionally front-loaded into a small index scan over tar -/// headers. File reads are an O(1) map lookup plus a page-cache-backed memory -/// slice; metadata and directory listings come from the in-memory index. The -/// mmap is keyed by content digest and shared across VMs, so RSS follows the -/// pages actually touched rather than the full archive size. The caller must -/// pass an immutable registry/package file: replacing by rename is fine because -/// this filesystem holds the opened file, but truncating the same inode during -/// a live VM would violate the mmap lifecycle and can SIGBUS on Unix. -/// -/// This filesystem is mounted only as a granular package-version leaf such as -/// `/opt/agentos/pkgs//`. Managed commands and `current` aliases -/// are separate symlink leaf mounts, while parent directories stay writable -/// overlay directories so user-installed files can coexist with managed ones. -pub struct TarFileSystem { - archive: Arc, - root: String, -} - -impl TarFileSystem { - pub fn open(path: impl AsRef, digest: impl Into) -> VfsResult { - Self::open_at(path, digest, "/") - } - - pub fn open_at( - path: impl AsRef, - digest: impl Into, - root: &str, - ) -> VfsResult { - let digest = digest.into(); - let path = path.as_ref().to_path_buf(); - let archive = cached_archive(path, digest)?; - let root = normalize_path(root); - let node = archive.node(&root)?; - if !matches!(node.kind, TarNodeKind::Directory) { - return Err(VfsError::new( - "ENOTDIR", - format!("tar mount root is not a directory: {root}"), - )); - } - Ok(Self { archive, root }) - } - - pub fn digest(&self) -> &str { - &self.archive.digest - } - - pub fn source_path(&self) -> &Path { - &self.archive.path - } - - pub fn archive_root(&self) -> &str { - &self.root - } - - fn to_archive_path(&self, path: &str) -> String { - let normalized = normalize_path(path); - if self.root == "/" { - normalized - } else if normalized == "/" { - self.root.clone() - } else { - normalize_path(&format!( - "{}/{}", - self.root, - normalized.trim_start_matches('/') - )) - } - } - - fn to_guest_path(&self, archive_path: &str) -> VfsResult { - if self.root == "/" { - return Ok(archive_path.to_owned()); - } - if archive_path == self.root { - return Ok(String::from("/")); - } - let prefix = format!("{}/", self.root.trim_end_matches('/')); - let suffix = archive_path.strip_prefix(&prefix).ok_or_else(|| { - VfsError::new( - "EXDEV", - format!("tar symlink resolved outside mounted subtree: {archive_path}"), - ) - })?; - Ok(format!("/{suffix}")) - } - - fn ensure_within_root(&self, archive_path: &str) -> VfsResult<()> { - if self.root == "/" || archive_path == self.root { - return Ok(()); - } - let prefix = format!("{}/", self.root.trim_end_matches('/')); - if archive_path.starts_with(&prefix) { - Ok(()) - } else { - Err(VfsError::new( - "EXDEV", - format!("tar path resolved outside mounted subtree: {archive_path}"), - )) - } - } - - fn resolve_path(&self, path: &str, follow_final_symlink: bool) -> VfsResult { - let normalized = self.to_archive_path(path); - if normalized == "/" { - return Ok(normalized); - } - - let mut pending = path_components(&normalized); - let mut current = String::from("/"); - let mut followed = 0usize; - - while let Some(component) = pending.pop_front() { - let candidate = join_path(¤t, &component); - let node = self.archive.node(&candidate)?; - let should_follow = follow_final_symlink || !pending.is_empty(); - - if should_follow { - if let TarNodeKind::Symlink { target } = &node.kind { - followed += 1; - if followed > MAX_TAR_SYMLINKS { - return Err(VfsError::new( - "ELOOP", - format!("too many levels of symbolic links, '{path}'"), - )); - } - let target_path = if target.starts_with('/') { - normalize_path(target) - } else { - normalize_path(&format!("{}/{}", parent_path(&candidate), target)) - }; - ensure_archive_path(&target_path)?; - let mut target_components = path_components(&target_path); - target_components.extend(pending); - pending = target_components; - current = String::from("/"); - continue; - } - } - - if !pending.is_empty() && !matches!(node.kind, TarNodeKind::Directory) { - return Err(VfsError::new( - "ENOTDIR", - format!("not a directory, realpath '{candidate}'"), - )); - } - - current = candidate; - } - - self.ensure_within_root(¤t)?; - Ok(current) - } - - fn readonly_error(op: &str, path: &str) -> VfsError { - VfsError::new("EROFS", format!("read-only tar filesystem, {op} '{path}'")) - } -} - -impl VirtualFileSystem for TarFileSystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - let resolved = self.resolve_path(path, true)?; - let node = self.archive.node(&resolved)?; - let TarNodeKind::File { offset, size } = node.kind else { - return Err(if matches!(node.kind, TarNodeKind::Directory) { - VfsError::new( - "EISDIR", - format!("illegal operation on a directory, read '{path}'"), - ) - } else { - VfsError::new("EINVAL", format!("not a regular file, read '{path}'")) - }); - }; - self.archive.validate_backing_file()?; - let start = usize::try_from(offset) - .map_err(|_| VfsError::new("EOVERFLOW", format!("tar offset too large: {offset}")))?; - let len = usize::try_from(size) - .map_err(|_| VfsError::new("EOVERFLOW", format!("tar member too large: {size}")))?; - let end = start - .checked_add(len) - .ok_or_else(|| VfsError::new("EOVERFLOW", "tar member byte range overflows usize"))?; - if end > self.archive.mmap.len() { - return Err(VfsError::new( - "EIO", - format!( - "tar member range exceeds archive size: offset {offset} bytes + size {size} bytes > {} bytes", - self.archive.mmap.len() - ), - )); - } - Ok(self.archive.mmap[start..end].to_vec()) - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - Ok(self - .read_dir_with_types(path)? - .into_iter() - .map(|entry| entry.name) - .collect()) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - let resolved = self.resolve_path(path, true)?; - let node = self.archive.node(&resolved)?; - if !matches!(node.kind, TarNodeKind::Directory) { - return Err(VfsError::new( - "ENOTDIR", - format!("not a directory, readdir '{path}'"), - )); - } - - let children = self - .archive - .children - .get(&resolved) - .cloned() - .unwrap_or_default(); - Ok(children - .into_iter() - .filter_map(|name| { - let child_path = join_path(&resolved, &name); - self.archive - .nodes - .get(&child_path) - .map(|child| VirtualDirEntry { - name, - is_directory: matches!(child.kind, TarNodeKind::Directory), - is_symbolic_link: matches!(child.kind, TarNodeKind::Symlink { .. }), - }) - }) - .collect()) - } - - fn write_file(&mut self, path: &str, _content: impl Into>) -> VfsResult<()> { - Err(Self::readonly_error("write", path)) - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - Err(Self::readonly_error("mkdir", path)) - } - - fn mkdir(&mut self, path: &str, _recursive: bool) -> VfsResult<()> { - Err(Self::readonly_error("mkdir", path)) - } - - fn exists(&self, path: &str) -> bool { - self.resolve_path(path, true) - .map(|resolved| self.archive.nodes.contains_key(&resolved)) - .unwrap_or(false) - } - - fn stat(&mut self, path: &str) -> VfsResult { - let resolved = self.resolve_path(path, true)?; - Ok(self.archive.node(&resolved)?.stat()) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - Err(Self::readonly_error("unlink", path)) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - Err(Self::readonly_error("rmdir", path)) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only tar filesystem, rename '{old_path}' to '{new_path}'"), - )) - } - - fn realpath(&self, path: &str) -> VfsResult { - let resolved = self.resolve_path(path, true)?; - self.to_guest_path(&resolved) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only tar filesystem, symlink '{link_path}' -> '{target}'"), - )) - } - - fn read_link(&self, path: &str) -> VfsResult { - let normalized = self.resolve_path(path, false)?; - match &self.archive.node(&normalized)?.kind { - TarNodeKind::Symlink { target } => Ok(target.clone()), - _ => Err(VfsError::new( - "EINVAL", - format!("not a symlink, readlink '{path}'"), - )), - } - } - - fn lstat(&self, path: &str) -> VfsResult { - let normalized = self.resolve_path(path, false)?; - Ok(self.archive.node(&normalized)?.stat()) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - Err(VfsError::new( - "EROFS", - format!("read-only tar filesystem, link '{old_path}' to '{new_path}'"), - )) - } - - fn chmod(&mut self, path: &str, _mode: u32) -> VfsResult<()> { - Err(Self::readonly_error("chmod", path)) - } - - fn chown(&mut self, path: &str, _uid: u32, _gid: u32) -> VfsResult<()> { - Err(Self::readonly_error("chown", path)) - } - - fn utimes(&mut self, path: &str, _atime_ms: u64, _mtime_ms: u64) -> VfsResult<()> { - Err(Self::readonly_error("utimes", path)) - } - - fn utimes_spec( - &mut self, - path: &str, - _atime: VirtualUtimeSpec, - _mtime: VirtualUtimeSpec, - _follow_symlinks: bool, - ) -> VfsResult<()> { - Err(Self::readonly_error("utimes", path)) - } - - fn truncate(&mut self, path: &str, _length: u64) -> VfsResult<()> { - Err(Self::readonly_error("truncate", path)) - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - let content = self.read_file(path)?; - let start = usize::try_from(offset) - .map_err(|_| VfsError::new("EOVERFLOW", format!("pread offset too large: {offset}")))?; - if start >= content.len() { - return Ok(Vec::new()); - } - let end = start.saturating_add(length).min(content.len()); - Ok(content[start..end].to_vec()) - } -} - -struct CachedTarArchive { - digest: String, - path: PathBuf, - file: File, - mmap: Mmap, - identity: FileIdentity, - nodes: BTreeMap, - children: BTreeMap>, -} - -impl CachedTarArchive { - fn node(&self, path: &str) -> VfsResult<&TarNode> { - self.nodes - .get(path) - .ok_or_else(|| VfsError::new("ENOENT", format!("no such file or directory, '{path}'"))) - } - - fn validate_backing_file(&self) -> VfsResult<()> { - let current = FileIdentity::from_file(&self.file)?; - if current != self.identity { - return Err(VfsError::new( - "ESTALE", - format!( - "tar archive backing file changed while mounted: {}", - self.path.display() - ), - )); - } - Ok(()) - } -} - -#[derive(Debug, Clone)] -struct TarNode { - kind: TarNodeKind, - mode: u32, - uid: u32, - gid: u32, - mtime_ms: u64, - ino: u64, - dev: u64, -} - -impl TarNode { - fn stat(&self) -> VirtualStat { - let size = match &self.kind { - TarNodeKind::File { size, .. } => *size, - TarNodeKind::Directory => 4096, - TarNodeKind::Symlink { target } => target.len() as u64, - }; - VirtualStat { - mode: self.mode, - size, - blocks: size.div_ceil(512), - dev: self.dev, - rdev: 0, - is_directory: matches!(self.kind, TarNodeKind::Directory), - is_symbolic_link: matches!(self.kind, TarNodeKind::Symlink { .. }), - atime_ms: self.mtime_ms, - atime_nsec: 0, - mtime_ms: self.mtime_ms, - mtime_nsec: 0, - ctime_ms: self.mtime_ms, - ctime_nsec: 0, - birthtime_ms: self.mtime_ms, - ino: self.ino, - nlink: 1, - uid: self.uid, - gid: self.gid, - } - } -} - -#[derive(Debug, Clone)] -enum TarNodeKind { - File { offset: u64, size: u64 }, - Directory, - Symlink { target: String }, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct FileIdentity { - len: u64, - modified_ms: u128, - #[cfg(unix)] - dev: u64, - #[cfg(unix)] - ino: u64, -} - -impl FileIdentity { - fn from_file(file: &File) -> VfsResult { - Self::from_metadata(file.metadata().map_err(io_to_vfs)?) - } - - fn from_metadata(metadata: std::fs::Metadata) -> VfsResult { - let modified_ms = metadata - .modified() - .ok() - .and_then(|time| time.duration_since(std::time::UNIX_EPOCH).ok()) - .map(|duration| duration.as_millis()) - .unwrap_or_default(); - Ok(Self { - len: metadata.len(), - modified_ms, - #[cfg(unix)] - dev: { - use std::os::unix::fs::MetadataExt; - metadata.dev() - }, - #[cfg(unix)] - ino: { - use std::os::unix::fs::MetadataExt; - metadata.ino() - }, - }) - } -} - -fn cached_archive(path: PathBuf, digest: String) -> VfsResult> { - let cache = archive_cache(); - let mut guard = cache - .lock() - .map_err(|_| VfsError::new("EIO", "tar archive cache mutex poisoned"))?; - - if let Some(existing) = guard.archives.get(&digest).and_then(Weak::upgrade) { - if existing.path == path { - return Ok(existing); - } - return Err(VfsError::new( - "EINVAL", - format!( - "tar digest collision or moved source: digest {digest} already maps to {} not {}", - existing.path.display(), - path.display() - ), - )); - } - - guard.archives.retain(|key, weak| { - let live = weak.strong_count() > 0; - if !live { - tracing::warn!( - digest = key.as_str(), - "evicting unused tar archive cache entry" - ); - } - live - }); - - if guard.archives.len() >= MAX_TAR_CACHE_ARCHIVES { - return Err(VfsError::new( - "ENOMEM", - format!( - "tar archive cache entries exceeded: {} entries > {} entries (raise via invariant.tarArchiveCacheEntries)", - guard.archives.len() + 1, - MAX_TAR_CACHE_ARCHIVES - ), - )); - } - - let archive = Arc::new(load_archive(&path, digest.clone())?); - guard.archives.insert(digest, Arc::downgrade(&archive)); - Ok(archive) -} - -fn archive_cache() -> &'static Mutex { - static CACHE: OnceLock> = OnceLock::new(); - CACHE.get_or_init(|| Mutex::new(TarArchiveCache::default())) -} - -#[derive(Default)] -struct TarArchiveCache { - archives: BTreeMap>, -} - -fn load_archive(path: &Path, digest: String) -> VfsResult { - let file = File::open(path).map_err(io_to_vfs)?; - let identity = FileIdentity::from_file(&file)?; - let mmap = unsafe { - // SAFETY: TarFileSystem is only constructed for immutable package tar - // artifacts. We hold the opened file for the lifetime of the mmap and - // validate size/identity before reading from mapped member ranges. A - // caller that truncates the same inode while a VM is live violates the - // package-store lifecycle documented on TarFileSystem. - Mmap::map(&file) - } - .map_err(io_to_vfs)?; - - let mut archive = tar::Archive::new(file.try_clone().map_err(io_to_vfs)?); - let mut nodes = BTreeMap::new(); - let mut children = BTreeMap::>::new(); - let dev = digest_device(&digest); - let mut next_ino = 1u64; - - nodes.insert( - String::from("/"), - TarNode { - kind: TarNodeKind::Directory, - mode: S_IFDIR | 0o755, - uid: 0, - gid: 0, - mtime_ms: 0, - ino: next_ino, - dev, - }, - ); - next_ino += 1; - children.entry(String::from("/")).or_default(); - - let entries = archive.entries().map_err(io_to_vfs)?; - for entry in entries { - let entry = entry.map_err(io_to_vfs)?; - let path = normalize_tar_member_path(&entry)?; - if path == "/" { - continue; - } - ensure_index_capacity(nodes.len() + 1)?; - synthesize_parent_dirs(&path, dev, &mut next_ino, &mut nodes, &mut children)?; - - let header = entry.header(); - let entry_type = header.entry_type(); - let mode = header.mode().unwrap_or(0o755); - let uid = header.uid().unwrap_or(0) as u32; - let gid = header.gid().unwrap_or(0) as u32; - let mtime_ms = header.mtime().unwrap_or(0).saturating_mul(1_000); - let kind = if entry_type.is_dir() { - TarNodeKind::Directory - } else if entry_type.is_symlink() { - let target = entry - .link_name() - .map_err(io_to_vfs)? - .ok_or_else(|| VfsError::new("EINVAL", format!("missing linkname for {path}")))? - .to_string_lossy() - .into_owned(); - TarNodeKind::Symlink { target } - } else if entry_type.is_file() || entry_type == EntryType::Continuous { - TarNodeKind::File { - offset: entry.raw_file_position(), - size: header.size().map_err(io_to_vfs)?, - } - } else { - continue; - }; - - let mode = match kind { - TarNodeKind::Directory => S_IFDIR | (mode & 0o7777), - TarNodeKind::File { .. } => S_IFREG | (mode & 0o7777), - TarNodeKind::Symlink { .. } => S_IFLNK | (mode & 0o7777).max(0o777), - }; - nodes.insert( - path.clone(), - TarNode { - kind, - mode, - uid, - gid, - mtime_ms, - ino: next_ino, - dev, - }, - ); - next_ino += 1; - add_child(&path, &mut children); - if matches!( - nodes.get(&path).map(|node| &node.kind), - Some(TarNodeKind::Directory) - ) { - children.entry(path).or_default(); - } - } - - Ok(CachedTarArchive { - digest, - path: path.to_path_buf(), - file, - mmap, - identity, - nodes, - children, - }) -} - -fn synthesize_parent_dirs( - path: &str, - dev: u64, - next_ino: &mut u64, - nodes: &mut BTreeMap, - children: &mut BTreeMap>, -) -> VfsResult<()> { - let mut current = String::from("/"); - let components = path_components(path); - let parent_count = components.len().saturating_sub(1); - for component in components.into_iter().take(parent_count) { - let parent = current.clone(); - current = join_path(¤t, &component); - if !nodes.contains_key(¤t) { - ensure_index_capacity(nodes.len() + 1)?; - nodes.insert( - current.clone(), - TarNode { - kind: TarNodeKind::Directory, - mode: S_IFDIR | 0o755, - uid: 0, - gid: 0, - mtime_ms: 0, - ino: *next_ino, - dev, - }, - ); - *next_ino += 1; - } - children.entry(parent).or_default().insert(component); - children.entry(current.clone()).or_default(); - } - Ok(()) -} - -fn add_child(path: &str, children: &mut BTreeMap>) { - let parent = parent_path(path); - let name = basename(path); - children.entry(parent).or_default().insert(name); -} - -fn ensure_index_capacity(observed: usize) -> VfsResult<()> { - if observed > MAX_TAR_INDEX_ENTRIES { - return Err(VfsError::new( - "ENOMEM", - format!( - "tar filesystem index entries exceeded: {observed} entries > {MAX_TAR_INDEX_ENTRIES} entries (raise via invariant.tarFilesystemIndexEntries)" - ), - )); - } - Ok(()) -} - -fn normalize_tar_member_path(entry: &tar::Entry<'_, File>) -> VfsResult { - let path = entry.path().map_err(io_to_vfs)?; - let mut parts = Vec::new(); - for component in path.components() { - match component { - Component::Normal(value) => parts.push(value.to_string_lossy().into_owned()), - Component::CurDir => {} - Component::RootDir | Component::Prefix(_) | Component::ParentDir => { - return Err(VfsError::new( - "EINVAL", - format!("tar member path escapes archive root: {}", path.display()), - )); - } - } - } - if parts.is_empty() { - Ok(String::from("/")) - } else { - Ok(format!("/{}", parts.join("/"))) - } -} - -fn ensure_archive_path(path: &str) -> VfsResult<()> { - let normalized = normalize_path(path); - if normalized != path { - return Err(VfsError::new( - "EINVAL", - format!("path normalization mismatch in tar filesystem: {path}"), - )); - } - Ok(()) -} - -fn path_components(path: &str) -> std::collections::VecDeque { - normalize_path(path) - .split('/') - .filter(|part| !part.is_empty()) - .map(String::from) - .collect() -} - -fn join_path(parent: &str, child: &str) -> String { - if parent == "/" { - format!("/{child}") - } else { - format!("{parent}/{child}") - } -} - -fn parent_path(path: &str) -> String { - let normalized = normalize_path(path); - let parent = Path::new(&normalized) - .parent() - .unwrap_or_else(|| Path::new("/")); - let value = parent.to_string_lossy(); - if value.is_empty() { - String::from("/") - } else { - value.into_owned() - } -} - -fn basename(path: &str) -> String { - let normalized = normalize_path(path); - Path::new(&normalized) - .file_name() - .map(|name| name.to_string_lossy().into_owned()) - .unwrap_or_else(|| String::from("/")) -} - -fn digest_device(digest: &str) -> u64 { - let mut hasher = std::collections::hash_map::DefaultHasher::new(); - digest.hash(&mut hasher); - hasher.finish().max(1) -} - -fn io_to_vfs(error: io::Error) -> VfsError { - let code = match error.kind() { - io::ErrorKind::NotFound => "ENOENT", - io::ErrorKind::PermissionDenied => "EACCES", - io::ErrorKind::AlreadyExists => "EEXIST", - io::ErrorKind::InvalidInput | io::ErrorKind::InvalidData => "EINVAL", - io::ErrorKind::UnexpectedEof => "EIO", - _ => "EIO", - }; - VfsError::new(code, error.to_string()) -} diff --git a/crates/vfs/src/posix/usage.rs b/crates/vfs/src/posix/usage.rs deleted file mode 100644 index 9d0fc06c3..000000000 --- a/crates/vfs/src/posix/usage.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::vfs::{VfsResult, VirtualFileSystem}; -use std::collections::BTreeSet; - -pub const DEFAULT_MAX_FILESYSTEM_BYTES: u64 = 64 * 1024 * 1024; -pub const DEFAULT_MAX_INODE_COUNT: usize = 16_384; - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct FileSystemUsage { - pub total_bytes: u64, - pub inode_count: usize, -} - -pub trait RootFilesystemResourceLimits { - fn max_filesystem_bytes(&self) -> Option; - fn max_inode_count(&self) -> Option; -} - -pub fn measure_filesystem_usage( - filesystem: &mut F, -) -> VfsResult { - let mut visited = BTreeSet::new(); - measure_path_usage(filesystem, "/", &mut visited) -} - -fn measure_path_usage( - filesystem: &mut F, - path: &str, - visited: &mut BTreeSet, -) -> VfsResult { - let stat = filesystem.lstat(path)?; - let mut usage = FileSystemUsage::default(); - - if visited.insert(stat.ino) { - usage.inode_count += 1; - if !stat.is_directory { - usage.total_bytes = usage.total_bytes.saturating_add(stat.size); - } - } - - if !stat.is_directory || stat.is_symbolic_link { - return Ok(usage); - } - - for entry in filesystem.read_dir_with_types(path)? { - if matches!(entry.name.as_str(), "." | "..") { - continue; - } - - let child_path = if path == "/" { - format!("/{}", entry.name) - } else { - format!("{path}/{}", entry.name) - }; - let child_usage = measure_path_usage(filesystem, &child_path, visited)?; - usage.total_bytes = usage.total_bytes.saturating_add(child_usage.total_bytes); - usage.inode_count = usage.inode_count.saturating_add(child_usage.inode_count); - } - - Ok(usage) -} diff --git a/crates/vfs/src/posix/vfs.rs b/crates/vfs/src/posix/vfs.rs deleted file mode 100644 index dbad5203c..000000000 --- a/crates/vfs/src/posix/vfs.rs +++ /dev/null @@ -1,1526 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -use std::error::Error; -use std::fmt; -use std::sync::atomic::{AtomicU64, Ordering}; -use web_time::{SystemTime, UNIX_EPOCH}; - -pub const S_IFREG: u32 = 0o100000; -pub const S_IFDIR: u32 = 0o040000; -pub const S_IFLNK: u32 = 0o120000; - -// Each MemoryFileSystem instance gets its own device id, like a Linux -// superblock. Inode numbers are only unique within one instance, so layered -// or mounted compositions need distinct dev values for (dev, ino) file -// identity comparisons to be meaningful. The counter starts above the small -// constants reserved for synthetic device and pipe stats. -static NEXT_MEMORY_FILESYSTEM_DEVICE_ID: AtomicU64 = AtomicU64::new(256); - -fn allocate_memory_filesystem_device_id() -> u64 { - NEXT_MEMORY_FILESYSTEM_DEVICE_ID.fetch_add(1, Ordering::Relaxed) -} - -const DEFAULT_UID: u32 = 1000; -const DEFAULT_GID: u32 = 1000; -const DIRECTORY_SIZE: u64 = 4096; -pub const MAX_PATH_LENGTH: usize = 4096; -const MAX_SYMLINK_DEPTH: usize = 40; - -pub type VfsResult = Result; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VfsError { - code: &'static str, - message: String, -} - -impl VfsError { - pub fn new(code: &'static str, message: impl Into) -> Self { - Self { - code, - message: message.into(), - } - } - - pub fn io(message: impl Into) -> Self { - Self::new("EIO", message) - } - - pub fn unsupported(message: impl Into) -> Self { - Self::new("ENOSYS", message) - } - - pub fn code(&self) -> &'static str { - self.code - } - - pub fn message(&self) -> &str { - &self.message - } - - fn not_found(op: &'static str, path: &str) -> Self { - Self::new( - "ENOENT", - format!("no such file or directory, {op} '{path}'"), - ) - } - - fn already_exists(op: &'static str, path: &str) -> Self { - Self::new("EEXIST", format!("file already exists, {op} '{path}'")) - } - - fn is_directory(op: &'static str, path: &str) -> Self { - Self::new( - "EISDIR", - format!("illegal operation on a directory, {op} '{path}'"), - ) - } - - fn not_directory(op: &'static str, path: &str) -> Self { - Self::new("ENOTDIR", format!("not a directory, {op} '{path}'")) - } - - fn path_too_long(path: &str) -> Self { - Self::new("ENAMETOOLONG", format!("file name too long: {path}")) - } - - fn not_empty(path: &str) -> Self { - Self::new("ENOTEMPTY", format!("directory not empty, rmdir '{path}'")) - } - - pub fn permission_denied(op: &'static str, path: &str) -> Self { - Self::new("EPERM", format!("operation not permitted, {op} '{path}'")) - } - - pub fn access_denied(op: &'static str, path: &str, reason: Option<&str>) -> Self { - let message = match reason { - Some(reason) => format!("permission denied, {op} '{path}': {reason}"), - None => format!("permission denied, {op} '{path}'"), - }; - - Self::new("EACCES", message) - } - - fn symlink_loop(path: &str) -> Self { - Self::new( - "ELOOP", - format!("too many levels of symbolic links, '{path}'"), - ) - } - - fn invalid_input(message: impl Into) -> Self { - Self::new("EINVAL", message) - } - - fn invalid_utf8(path: &str) -> Self { - Self::new("EINVAL", format!("file contains invalid UTF-8, '{path}'")) - } -} - -impl fmt::Display for VfsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {}", self.code, self.message) - } -} - -impl Error for VfsError {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FileType { - File, - Directory, - SymbolicLink, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VirtualDirEntry { - pub name: String, - pub is_directory: bool, - pub is_symbolic_link: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VirtualStat { - pub mode: u32, - pub size: u64, - pub blocks: u64, - pub dev: u64, - pub rdev: u64, - pub is_directory: bool, - pub is_symbolic_link: bool, - pub atime_ms: u64, - pub atime_nsec: u32, - pub mtime_ms: u64, - pub mtime_nsec: u32, - pub ctime_ms: u64, - pub ctime_nsec: u32, - pub birthtime_ms: u64, - pub ino: u64, - pub nlink: u64, - pub uid: u32, - pub gid: u32, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -pub struct VirtualTimeSpec { - pub sec: i64, - pub nsec: u32, -} - -impl VirtualTimeSpec { - pub fn new(sec: i64, nsec: u32) -> VfsResult { - if nsec >= 1_000_000_000 { - return Err(VfsError::new( - "EINVAL", - format!("timespec nanoseconds out of range: {nsec}"), - )); - } - Ok(Self { sec, nsec }) - } - - pub fn from_millis(ms: u64) -> Self { - Self { - sec: (ms / 1_000) as i64, - nsec: ((ms % 1_000) * 1_000_000) as u32, - } - } - - pub fn to_truncated_millis(self) -> VfsResult { - if self.sec < 0 { - return Err(VfsError::new( - "EINVAL", - format!( - "negative timestamps are not supported by this filesystem: {}", - self.sec - ), - )); - } - let seconds = u64::try_from(self.sec).map_err(|_| { - VfsError::new("EINVAL", format!("timestamp is out of range: {}", self.sec)) - })?; - Ok(seconds.saturating_mul(1_000) + (self.nsec as u64 / 1_000_000)) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum VirtualUtimeSpec { - Set(VirtualTimeSpec), - Now, - Omit, -} - -pub trait VirtualFileSystem { - fn read_file(&mut self, path: &str) -> VfsResult>; - fn read_text_file(&mut self, path: &str) -> VfsResult { - String::from_utf8(self.read_file(path)?).map_err(|_| VfsError::invalid_utf8(path)) - } - fn read_dir(&mut self, path: &str) -> VfsResult>; - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - let entries = self.read_dir(path)?; - if entries.len() > max_entries { - return Err(VfsError::new( - "ENOMEM", - format!( - "directory listing for '{path}' exceeds configured limit of {max_entries} entries" - ), - )); - } - Ok(entries) - } - fn read_dir_with_types(&mut self, path: &str) -> VfsResult>; - /// Writes caller-owned bytes into the filesystem. - /// - /// This raw VFS primitive does not enforce VM resource policy. Kernel entry - /// points must preflight file sizes and inode growth before calling it. - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()>; - fn write_file_with_mode( - &mut self, - path: &str, - content: impl Into>, - mode: Option, - ) -> VfsResult<()> { - let _ = mode; - self.write_file(path, content) - } - fn create_file_exclusive(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - let content = content.into(); - if self.exists(path) { - return Err(VfsError::already_exists("open", path)); - } - self.write_file(path, content) - } - fn create_file_exclusive_with_mode( - &mut self, - path: &str, - content: impl Into>, - mode: Option, - ) -> VfsResult<()> { - let _ = mode; - self.create_file_exclusive(path, content) - } - /// Appends caller-owned bytes into the filesystem after checking that the - /// in-memory file can grow without overflowing addressable memory. - fn append_file(&mut self, path: &str, content: impl Into>) -> VfsResult { - let content = content.into(); - let mut existing = self.read_file(path)?; - reserve_file_growth(&mut existing, content.len())?; - existing.extend_from_slice(&content); - let new_len = existing.len() as u64; - self.write_file(path, existing)?; - Ok(new_len) - } - fn create_dir(&mut self, path: &str) -> VfsResult<()>; - fn create_dir_with_mode(&mut self, path: &str, mode: Option) -> VfsResult<()> { - let _ = mode; - self.create_dir(path) - } - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()>; - fn mkdir_with_mode(&mut self, path: &str, recursive: bool, mode: Option) -> VfsResult<()> { - let _ = mode; - self.mkdir(path, recursive) - } - fn exists(&self, path: &str) -> bool; - fn stat(&mut self, path: &str) -> VfsResult; - fn remove_file(&mut self, path: &str) -> VfsResult<()>; - fn remove_dir(&mut self, path: &str) -> VfsResult<()>; - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()>; - fn realpath(&self, path: &str) -> VfsResult; - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()>; - fn read_link(&self, path: &str) -> VfsResult; - fn lstat(&self, path: &str) -> VfsResult; - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()>; - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()>; - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()>; - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()>; - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - if !follow_symlinks { - return Err(VfsError::unsupported(format!( - "lutimes is not supported for '{path}'" - ))); - } - let existing = match (atime, mtime) { - (VirtualUtimeSpec::Omit, _) | (_, VirtualUtimeSpec::Omit) => Some(self.stat(path)?), - _ => None, - }; - let now = now_ms(); - let atime_ms = resolve_utime_millis( - atime, - now, - existing.as_ref().map(|stat| VirtualTimeSpec { - sec: (stat.atime_ms / 1_000) as i64, - nsec: stat.atime_nsec, - }), - )?; - let mtime_ms = resolve_utime_millis( - mtime, - now, - existing.as_ref().map(|stat| VirtualTimeSpec { - sec: (stat.mtime_ms / 1_000) as i64, - nsec: stat.mtime_nsec, - }), - )?; - self.utimes(path, atime_ms, mtime_ms) - } - /// Resizes a file. VM resource policy must be enforced by the caller. - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()>; - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult>; - /// Writes caller-owned bytes at an offset after checking that the in-memory - /// file can grow without overflowing addressable memory. - fn pwrite(&mut self, path: &str, content: impl Into>, offset: u64) -> VfsResult<()> { - let content = content.into(); - let mut existing = self.read_file(path)?; - let start = checked_file_len(offset, "pwrite offset")?; - if start > existing.len() { - resize_file_data(&mut existing, start)?; - } - let end = start.checked_add(content.len()).ok_or_else(|| { - VfsError::new( - "ENOMEM", - format!( - "pwrite result length overflows addressable memory: offset {offset}, content length {}", - content.len() - ), - ) - })?; - if end > existing.len() { - resize_file_data(&mut existing, end)?; - } - existing[start..end].copy_from_slice(&content); - self.write_file(path, existing) - } -} - -#[derive(Debug, Clone)] -struct Metadata { - mode: u32, - uid: u32, - gid: u32, - nlink: u64, - ino: u64, - atime_ms: u64, - atime_nsec: u32, - mtime_ms: u64, - mtime_nsec: u32, - ctime_ms: u64, - ctime_nsec: u32, - birthtime_ms: u64, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct MemoryFileSystemSnapshotMetadata { - pub mode: u32, - pub uid: u32, - pub gid: u32, - pub nlink: u64, - pub ino: u64, - pub atime_ms: u64, - #[serde(default)] - pub atime_nsec: u32, - pub mtime_ms: u64, - #[serde(default)] - pub mtime_nsec: u32, - pub ctime_ms: u64, - #[serde(default)] - pub ctime_nsec: u32, - pub birthtime_ms: u64, -} - -#[derive(Debug, Clone)] -enum InodeKind { - File { data: Vec }, - Directory, - SymbolicLink { target: String }, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub enum MemoryFileSystemSnapshotInodeKind { - File { data: Vec }, - Directory, - SymbolicLink { target: String }, -} - -#[derive(Debug, Clone)] -struct Inode { - metadata: Metadata, - kind: InodeKind, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct MemoryFileSystemSnapshotInode { - pub metadata: MemoryFileSystemSnapshotMetadata, - pub kind: MemoryFileSystemSnapshotInodeKind, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct MemoryFileSystemSnapshot { - pub path_index: BTreeMap, - pub inodes: BTreeMap, - pub next_ino: u64, -} - -#[derive(Debug)] -pub struct MemoryFileSystem { - device_id: u64, - path_index: BTreeMap, - inodes: BTreeMap, - next_ino: u64, -} - -impl MemoryFileSystem { - pub fn new() -> Self { - let mut filesystem = Self { - device_id: allocate_memory_filesystem_device_id(), - path_index: BTreeMap::new(), - inodes: BTreeMap::new(), - next_ino: 1, - }; - - let root_ino = filesystem.allocate_inode(InodeKind::Directory, S_IFDIR | 0o755); - filesystem.path_index.insert(String::from("/"), root_ino); - filesystem - } - - pub fn read_dir_filtered_limited( - &mut self, - path: &str, - max_entries: usize, - mut include: F, - ) -> VfsResult> - where - F: FnMut(&str) -> bool, - { - self.assert_directory_path(path, "scandir")?; - let resolved = self.resolve_path(path, 0)?; - self.inode_mut_for_existing_path(&resolved, "scandir", false)? - .metadata - .atime_ms = now_ms(); - let prefix = if resolved == "/" { - String::from("/") - } else { - format!("{resolved}/") - }; - - let mut entries = BTreeMap::::new(); - for (candidate_path, _) in self.path_index.range(prefix.clone()..) { - if !candidate_path.starts_with(&prefix) { - break; - } - - let rest = &candidate_path[prefix.len()..]; - if rest.is_empty() || rest.contains('/') || !include(rest) { - continue; - } - - entries.insert(String::from(rest), String::from(rest)); - if entries.len() > max_entries { - return Err(VfsError::new( - "ENOMEM", - format!( - "directory listing for '{path}' exceeds configured limit of {max_entries} entries" - ), - )); - } - } - - Ok(entries.into_values().collect()) - } - - pub fn link_count_in_subtree(&self, ino: u64, path: &str) -> usize { - let normalized = normalize_path(path); - let prefix = if normalized == "/" { - String::from("/") - } else { - format!("{normalized}/") - }; - - self.path_index - .iter() - .filter(|(candidate_path, candidate_ino)| { - **candidate_ino == ino - && (candidate_path.as_str() == normalized - || candidate_path.starts_with(&prefix)) - }) - .count() - } - - fn allocate_inode(&mut self, kind: InodeKind, mode: u32) -> u64 { - let ino = self.next_ino; - self.next_ino += 1; - let now = now_ms(); - let nlink = if matches!(kind, InodeKind::Directory) { - 2 - } else { - 1 - }; - self.inodes.insert( - ino, - Inode { - metadata: Metadata { - mode, - uid: DEFAULT_UID, - gid: DEFAULT_GID, - nlink, - ino, - atime_ms: now, - atime_nsec: 0, - mtime_ms: now, - mtime_nsec: 0, - ctime_ms: now, - ctime_nsec: 0, - birthtime_ms: now, - }, - kind, - }, - ); - ino - } - - pub fn symlink_with_metadata( - &mut self, - target: &str, - link_path: &str, - mode: u32, - uid: u32, - gid: u32, - ) -> VfsResult<()> { - let normalized = self.resolve_exact_path(link_path)?; - if self.path_index.contains_key(&normalized) { - return Err(VfsError::already_exists("symlink", link_path)); - } - - self.assert_directory_path(&dirname(&normalized), "symlink")?; - let ino = self.allocate_inode( - InodeKind::SymbolicLink { - target: String::from(target), - }, - if mode & 0o170000 == 0 { - S_IFLNK | (mode & 0o7777) - } else { - mode - }, - ); - let inode = self - .inodes - .get_mut(&ino) - .expect("allocated inode should exist"); - inode.metadata.uid = uid; - inode.metadata.gid = gid; - self.path_index.insert(normalized, ino); - Ok(()) - } - - fn resolve_path_with_options( - &self, - path: &str, - follow_final_symlink: bool, - depth: usize, - ) -> VfsResult { - validate_path(path)?; - if depth > MAX_SYMLINK_DEPTH { - return Err(VfsError::symlink_loop(path)); - } - - let normalized = normalize_path(path); - if normalized == "/" { - return Ok(normalized); - } - - let components: Vec<&str> = normalized - .split('/') - .filter(|part| !part.is_empty()) - .collect(); - let mut current = String::from("/"); - - for (index, component) in components.iter().enumerate() { - let candidate = if current == "/" { - format!("/{}", component) - } else { - format!("{current}/{}", component) - }; - let is_final = index + 1 == components.len(); - let should_follow = !is_final || follow_final_symlink; - - if let Some(ino) = self.path_index.get(&candidate) { - let inode = self - .inodes - .get(ino) - .expect("path index should always point at a valid inode"); - - if should_follow { - if let InodeKind::SymbolicLink { target } = &inode.kind { - let target_path = if target.starts_with('/') { - target.clone() - } else { - normalize_path(&format!("{}/{}", dirname(&candidate), target)) - }; - let remainder = components[index + 1..].join("/"); - let next_path = if remainder.is_empty() { - target_path - } else { - normalize_path(&format!("{target_path}/{remainder}")) - }; - return self.resolve_path_with_options( - &next_path, - follow_final_symlink, - depth + 1, - ); - } - } - - if !is_final && !matches!(inode.kind, InodeKind::Directory) { - return Err(VfsError::not_directory("stat", &candidate)); - } - } - - current = candidate; - } - - Ok(current) - } - - fn resolve_path(&self, path: &str, depth: usize) -> VfsResult { - self.resolve_path_with_options(path, true, depth) - } - - fn resolve_exact_path(&self, path: &str) -> VfsResult { - self.resolve_path_with_options(path, false, 0) - } - - fn inode_id_for_existing_path( - &self, - path: &str, - op: &'static str, - follow_symlinks: bool, - ) -> VfsResult { - let normalized = normalize_path(path); - let resolved = if follow_symlinks { - self.resolve_path(&normalized, 0)? - } else { - self.resolve_exact_path(&normalized)? - }; - self.path_index - .get(&resolved) - .copied() - .ok_or_else(|| VfsError::not_found(op, path)) - } - - fn inode_for_existing_path( - &self, - path: &str, - op: &'static str, - follow_symlinks: bool, - ) -> VfsResult<&Inode> { - let ino = self.inode_id_for_existing_path(path, op, follow_symlinks)?; - Ok(self - .inodes - .get(&ino) - .expect("existing path should resolve to a live inode")) - } - - fn inode_mut_for_existing_path( - &mut self, - path: &str, - op: &'static str, - follow_symlinks: bool, - ) -> VfsResult<&mut Inode> { - let ino = self.inode_id_for_existing_path(path, op, follow_symlinks)?; - Ok(self - .inodes - .get_mut(&ino) - .expect("existing path should resolve to a live inode")) - } - - fn assert_directory_path(&self, path: &str, op: &'static str) -> VfsResult<()> { - let inode = self.inode_for_existing_path(path, op, true)?; - if matches!(inode.kind, InodeKind::Directory) { - Ok(()) - } else { - Err(VfsError::not_directory(op, path)) - } - } - - fn remove_exact_path(&mut self, path: &str) -> VfsResult<()> { - let normalized = self.resolve_exact_path(path)?; - let ino = self - .path_index - .get(&normalized) - .copied() - .ok_or_else(|| VfsError::not_found("unlink", path))?; - let inode = self - .inodes - .get(&ino) - .expect("existing path should resolve to a live inode"); - - if matches!(inode.kind, InodeKind::Directory) { - return Err(VfsError::is_directory("unlink", path)); - } - - self.inodes - .get_mut(&ino) - .expect("inode should exist when unlinking") - .metadata - .ctime_ms = now_ms(); - self.path_index.remove(&normalized); - self.decrement_link_count(ino); - Ok(()) - } - - fn remove_existing_destination(&mut self, path: &str) -> VfsResult<()> { - let normalized = self.resolve_exact_path(path)?; - let Some(ino) = self.path_index.get(&normalized).copied() else { - return Ok(()); - }; - - let inode = self - .inodes - .get(&ino) - .expect("existing path should resolve to a live inode"); - - if matches!(inode.kind, InodeKind::Directory) { - let prefix = format!("{normalized}/"); - if self - .path_index - .keys() - .any(|candidate| candidate.starts_with(&prefix)) - { - return Err(VfsError::not_empty(path)); - } - } - - self.inodes - .get_mut(&ino) - .expect("inode should exist when removing destination") - .metadata - .ctime_ms = now_ms(); - self.path_index.remove(&normalized); - self.decrement_link_count(ino); - Ok(()) - } - - fn decrement_link_count(&mut self, ino: u64) { - let should_remove = { - let inode = self - .inodes - .get_mut(&ino) - .expect("inode should exist when decrementing link count"); - inode.metadata.nlink = inode.metadata.nlink.saturating_sub(1); - inode.metadata.nlink == 0 - }; - - if should_remove { - self.inodes.remove(&ino); - } - } - - fn build_stat(&self, inode: &Inode) -> VirtualStat { - let size = match &inode.kind { - InodeKind::File { data } => data.len() as u64, - InodeKind::Directory => DIRECTORY_SIZE, - InodeKind::SymbolicLink { target } => target.len() as u64, - }; - - VirtualStat { - mode: inode.metadata.mode, - size, - blocks: block_count_for_size(size), - dev: self.device_id, - rdev: 0, - is_directory: matches!(inode.kind, InodeKind::Directory), - is_symbolic_link: matches!(inode.kind, InodeKind::SymbolicLink { .. }), - atime_ms: inode.metadata.atime_ms, - atime_nsec: inode.metadata.atime_nsec, - mtime_ms: inode.metadata.mtime_ms, - mtime_nsec: inode.metadata.mtime_nsec, - ctime_ms: inode.metadata.ctime_ms, - ctime_nsec: inode.metadata.ctime_nsec, - birthtime_ms: inode.metadata.birthtime_ms, - ino: inode.metadata.ino, - nlink: inode.metadata.nlink, - uid: inode.metadata.uid, - gid: inode.metadata.gid, - } - } - - /// Clones the full in-memory filesystem state. - /// - /// Callers that expose snapshots outside the kernel must enforce their own - /// byte and inode limits before reaching this raw clone operation. - pub fn snapshot(&self) -> MemoryFileSystemSnapshot { - MemoryFileSystemSnapshot { - path_index: self.path_index.clone(), - inodes: self - .inodes - .iter() - .map(|(ino, inode)| { - ( - *ino, - MemoryFileSystemSnapshotInode { - metadata: MemoryFileSystemSnapshotMetadata { - mode: inode.metadata.mode, - uid: inode.metadata.uid, - gid: inode.metadata.gid, - nlink: inode.metadata.nlink, - ino: inode.metadata.ino, - atime_ms: inode.metadata.atime_ms, - atime_nsec: inode.metadata.atime_nsec, - mtime_ms: inode.metadata.mtime_ms, - mtime_nsec: inode.metadata.mtime_nsec, - ctime_ms: inode.metadata.ctime_ms, - ctime_nsec: inode.metadata.ctime_nsec, - birthtime_ms: inode.metadata.birthtime_ms, - }, - kind: match &inode.kind { - InodeKind::File { data } => { - MemoryFileSystemSnapshotInodeKind::File { data: data.clone() } - } - InodeKind::Directory => { - MemoryFileSystemSnapshotInodeKind::Directory - } - InodeKind::SymbolicLink { target } => { - MemoryFileSystemSnapshotInodeKind::SymbolicLink { - target: target.clone(), - } - } - }, - }, - ) - }) - .collect(), - next_ino: self.next_ino, - } - } - - pub fn from_snapshot(snapshot: MemoryFileSystemSnapshot) -> Self { - Self { - device_id: allocate_memory_filesystem_device_id(), - path_index: snapshot.path_index, - inodes: snapshot - .inodes - .into_iter() - .map(|(ino, inode)| { - ( - ino, - Inode { - metadata: Metadata { - mode: inode.metadata.mode, - uid: inode.metadata.uid, - gid: inode.metadata.gid, - nlink: inode.metadata.nlink, - ino: inode.metadata.ino, - atime_ms: inode.metadata.atime_ms, - atime_nsec: inode.metadata.atime_nsec, - mtime_ms: inode.metadata.mtime_ms, - mtime_nsec: inode.metadata.mtime_nsec, - ctime_ms: inode.metadata.ctime_ms, - ctime_nsec: inode.metadata.ctime_nsec, - birthtime_ms: inode.metadata.birthtime_ms, - }, - kind: match inode.kind { - MemoryFileSystemSnapshotInodeKind::File { data } => { - InodeKind::File { data } - } - MemoryFileSystemSnapshotInodeKind::Directory => { - InodeKind::Directory - } - MemoryFileSystemSnapshotInodeKind::SymbolicLink { target } => { - InodeKind::SymbolicLink { target } - } - }, - }, - ) - }) - .collect(), - next_ino: snapshot.next_ino, - } - } -} - -impl VirtualFileSystem for MemoryFileSystem { - fn read_file(&mut self, path: &str) -> VfsResult> { - let inode = self.inode_mut_for_existing_path(path, "open", true)?; - match &inode.kind { - InodeKind::File { data } => { - inode.metadata.atime_ms = now_ms(); - Ok(data.clone()) - } - InodeKind::Directory => Err(VfsError::is_directory("open", path)), - InodeKind::SymbolicLink { .. } => Err(VfsError::not_found("open", path)), - } - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - Ok(self - .read_dir_with_types(path)? - .into_iter() - .map(|entry| entry.name) - .collect()) - } - - fn read_dir_limited(&mut self, path: &str, max_entries: usize) -> VfsResult> { - self.read_dir_filtered_limited(path, max_entries, |_| true) - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - self.assert_directory_path(path, "scandir")?; - let resolved = self.resolve_path(path, 0)?; - self.inode_mut_for_existing_path(&resolved, "scandir", false)? - .metadata - .atime_ms = now_ms(); - let prefix = if resolved == "/" { - String::from("/") - } else { - format!("{resolved}/") - }; - - let mut entries = BTreeMap::::new(); - for (candidate_path, ino) in self.path_index.range(prefix.clone()..) { - if !candidate_path.starts_with(&prefix) { - break; - } - - let rest = &candidate_path[prefix.len()..]; - if rest.is_empty() || rest.contains('/') { - continue; - } - - let inode = self - .inodes - .get(ino) - .expect("path index should always point at a valid inode"); - entries.insert( - String::from(rest), - VirtualDirEntry { - name: String::from(rest), - is_directory: matches!(inode.kind, InodeKind::Directory), - is_symbolic_link: matches!(inode.kind, InodeKind::SymbolicLink { .. }), - }, - ); - } - - Ok(entries.into_values().collect()) - } - - fn write_file(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - let normalized = self.resolve_path(path, 0)?; - self.mkdir(&dirname(&normalized), true)?; - let data = content.into(); - - if self.path_index.contains_key(&normalized) { - let inode = self.inode_mut_for_existing_path(&normalized, "open", false)?; - let now = now_ms(); - match &mut inode.kind { - InodeKind::File { data: existing } => { - *existing = data; - inode.metadata.mtime_ms = now; - inode.metadata.ctime_ms = now; - return Ok(()); - } - InodeKind::Directory => return Err(VfsError::is_directory("open", path)), - InodeKind::SymbolicLink { .. } => return Err(VfsError::not_found("open", path)), - } - } - - let ino = self.allocate_inode(InodeKind::File { data }, S_IFREG | 0o644); - self.path_index.insert(normalized, ino); - Ok(()) - } - - fn create_file_exclusive(&mut self, path: &str, content: impl Into>) -> VfsResult<()> { - let normalized = self.resolve_path(path, 0)?; - self.mkdir(&dirname(&normalized), true)?; - if self.path_index.contains_key(&normalized) { - return Err(VfsError::already_exists("open", path)); - } - - let ino = self.allocate_inode( - InodeKind::File { - data: content.into(), - }, - S_IFREG | 0o644, - ); - self.path_index.insert(normalized, ino); - Ok(()) - } - - fn append_file(&mut self, path: &str, content: impl Into>) -> VfsResult { - let normalized = self.resolve_path(path, 0)?; - let data = content.into(); - let inode = self.inode_mut_for_existing_path(&normalized, "open", false)?; - let now = now_ms(); - match &mut inode.kind { - InodeKind::File { data: existing } => { - reserve_file_growth(existing, data.len())?; - existing.extend_from_slice(&data); - inode.metadata.mtime_ms = now; - inode.metadata.ctime_ms = now; - Ok(existing.len() as u64) - } - InodeKind::Directory => Err(VfsError::is_directory("open", path)), - InodeKind::SymbolicLink { .. } => Err(VfsError::not_found("open", path)), - } - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - let normalized = self.resolve_exact_path(path)?; - if normalized == "/" { - return Ok(()); - } - - self.assert_directory_path(&dirname(&normalized), "mkdir")?; - if let Some(existing) = self.path_index.get(&normalized) { - let inode = self - .inodes - .get(existing) - .expect("path index should always point at a valid inode"); - if matches!(inode.kind, InodeKind::Directory) { - return Ok(()); - } - return Err(VfsError::already_exists("mkdir", path)); - } - - let ino = self.allocate_inode(InodeKind::Directory, S_IFDIR | 0o755); - self.path_index.insert(normalized, ino); - Ok(()) - } - - fn mkdir(&mut self, path: &str, recursive: bool) -> VfsResult<()> { - let normalized = normalize_path(path); - if normalized == "/" { - return Ok(()); - } - - if !recursive { - return self.create_dir(path); - } - - let parts: Vec<&str> = normalized - .split('/') - .filter(|part| !part.is_empty()) - .collect(); - let mut current = String::from("/"); - - for (index, part) in parts.iter().enumerate() { - let raw_path = if current == "/" { - format!("/{}", part) - } else { - format!("{current}/{}", part) - }; - let resolved = - self.resolve_path_with_options(&raw_path, index + 1 != parts.len(), 0)?; - - match self.path_index.get(&resolved).copied() { - Some(ino) => { - let inode = self - .inodes - .get(&ino) - .expect("path index should always point at a valid inode"); - if !matches!(inode.kind, InodeKind::Directory) { - return Err(VfsError::not_directory("mkdir", &raw_path)); - } - } - None => { - let ino = self.allocate_inode(InodeKind::Directory, S_IFDIR | 0o755); - self.path_index.insert(resolved.clone(), ino); - } - } - - current = resolved; - } - - Ok(()) - } - - fn exists(&self, path: &str) -> bool { - self.resolve_path(path, 0) - .ok() - .is_some_and(|resolved| self.path_index.contains_key(&resolved)) - } - - fn stat(&mut self, path: &str) -> VfsResult { - let inode = self.inode_for_existing_path(path, "stat", true)?; - Ok(self.build_stat(inode)) - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - self.remove_exact_path(path) - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - let normalized = self.resolve_exact_path(path)?; - if normalized == "/" { - return Err(VfsError::permission_denied("rmdir", path)); - } - - let ino = self - .path_index - .get(&normalized) - .copied() - .ok_or_else(|| VfsError::not_found("rmdir", path))?; - let inode = self - .inodes - .get(&ino) - .expect("path index should always point at a valid inode"); - if !matches!(inode.kind, InodeKind::Directory) { - return Err(VfsError::not_directory("rmdir", path)); - } - - let prefix = format!("{normalized}/"); - if self - .path_index - .keys() - .any(|candidate| candidate.starts_with(&prefix)) - { - return Err(VfsError::not_empty(path)); - } - - self.path_index.remove(&normalized); - self.decrement_link_count(ino); - Ok(()) - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let old_normalized = self.resolve_exact_path(old_path)?; - let new_normalized = self.resolve_exact_path(new_path)?; - - if old_normalized == "/" { - return Err(VfsError::permission_denied("rename", old_path)); - } - - if old_normalized == new_normalized { - return Ok(()); - } - - self.assert_directory_path(&dirname(&new_normalized), "rename")?; - - if new_normalized.starts_with(&(old_normalized.clone() + "/")) { - return Err(VfsError::invalid_input(format!( - "cannot move '{}' into its own descendant '{}'", - old_path, new_path - ))); - } - - let ino = self - .path_index - .get(&old_normalized) - .copied() - .ok_or_else(|| VfsError::not_found("rename", old_path))?; - let is_directory = matches!( - self.inodes - .get(&ino) - .expect("path index should always point at a valid inode") - .kind, - InodeKind::Directory - ); - - self.remove_existing_destination(new_path)?; - - if !is_directory { - self.path_index.remove(&old_normalized); - self.path_index.insert(new_normalized, ino); - self.inodes - .get_mut(&ino) - .expect("renamed inode should exist") - .metadata - .ctime_ms = now_ms(); - return Ok(()); - } - - let prefix = format!("{old_normalized}/"); - let to_move: Vec<(String, u64)> = self - .path_index - .iter() - .filter(|(path, _)| **path == old_normalized || path.starts_with(&prefix)) - .map(|(path, inode_id)| (path.clone(), *inode_id)) - .collect(); - - for (path, _) in &to_move { - self.path_index.remove(path); - } - - for (path, inode_id) in to_move { - let relocated_path = if path == old_normalized { - new_normalized.clone() - } else { - format!("{new_normalized}{}", &path[old_normalized.len()..]) - }; - self.path_index.insert(relocated_path, inode_id); - } - - self.inodes - .get_mut(&ino) - .expect("renamed directory inode should exist") - .metadata - .ctime_ms = now_ms(); - - Ok(()) - } - - fn realpath(&self, path: &str) -> VfsResult { - let resolved = self.resolve_path(path, 0)?; - if !self.path_index.contains_key(&resolved) { - return Err(VfsError::not_found("realpath", path)); - } - Ok(resolved) - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - self.symlink_with_metadata(target, link_path, S_IFLNK | 0o777, DEFAULT_UID, DEFAULT_GID) - } - - fn read_link(&self, path: &str) -> VfsResult { - let inode = self.inode_for_existing_path(path, "readlink", false)?; - match &inode.kind { - InodeKind::SymbolicLink { target } => Ok(target.clone()), - _ => Err(VfsError::invalid_input(format!( - "invalid argument, readlink '{path}'" - ))), - } - } - - fn lstat(&self, path: &str) -> VfsResult { - let inode = self.inode_for_existing_path(path, "lstat", false)?; - Ok(self.build_stat(inode)) - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - let ino = self.inode_id_for_existing_path(old_path, "link", true)?; - let inode = self - .inodes - .get(&ino) - .expect("path index should always point at a valid inode"); - if !matches!(inode.kind, InodeKind::File { .. }) { - return Err(VfsError::permission_denied("link", old_path)); - } - - let normalized = self.resolve_exact_path(new_path)?; - if self.path_index.contains_key(&normalized) { - return Err(VfsError::already_exists("link", new_path)); - } - - self.assert_directory_path(&dirname(&normalized), "link")?; - self.path_index.insert(normalized, ino); - let inode = self - .inodes - .get_mut(&ino) - .expect("path index should always point at a valid inode"); - inode.metadata.nlink += 1; - inode.metadata.ctime_ms = now_ms(); - Ok(()) - } - - fn chmod(&mut self, path: &str, mode: u32) -> VfsResult<()> { - let inode = self.inode_mut_for_existing_path(path, "chmod", true)?; - let type_bits = if mode & 0o170000 == 0 { - inode.metadata.mode & 0o170000 - } else { - mode & 0o170000 - }; - inode.metadata.mode = type_bits | (mode & 0o7777); - inode.metadata.ctime_ms = now_ms(); - Ok(()) - } - - fn chown(&mut self, path: &str, uid: u32, gid: u32) -> VfsResult<()> { - let inode = self.inode_mut_for_existing_path(path, "chown", true)?; - inode.metadata.uid = uid; - inode.metadata.gid = gid; - inode.metadata.ctime_ms = now_ms(); - Ok(()) - } - - fn utimes(&mut self, path: &str, atime_ms: u64, mtime_ms: u64) -> VfsResult<()> { - let inode = self.inode_mut_for_existing_path(path, "utimes", true)?; - inode.metadata.atime_ms = atime_ms; - inode.metadata.atime_nsec = 0; - inode.metadata.mtime_ms = mtime_ms; - inode.metadata.mtime_nsec = 0; - inode.metadata.ctime_ms = now_ms(); - inode.metadata.ctime_nsec = 0; - Ok(()) - } - - fn utimes_spec( - &mut self, - path: &str, - atime: VirtualUtimeSpec, - mtime: VirtualUtimeSpec, - follow_symlinks: bool, - ) -> VfsResult<()> { - let stat = if follow_symlinks { - self.stat(path)? - } else { - self.lstat(path)? - }; - let inode = self.inode_mut_for_existing_path(path, "utimes", follow_symlinks)?; - let now = now_time_spec(); - let atime = resolve_utime_spec( - atime, - now, - VirtualTimeSpec { - sec: (stat.atime_ms / 1_000) as i64, - nsec: stat.atime_nsec, - }, - )?; - let mtime = resolve_utime_spec( - mtime, - now, - VirtualTimeSpec { - sec: (stat.mtime_ms / 1_000) as i64, - nsec: stat.mtime_nsec, - }, - )?; - inode.metadata.atime_ms = atime.to_truncated_millis()?; - inode.metadata.atime_nsec = atime.nsec; - inode.metadata.mtime_ms = mtime.to_truncated_millis()?; - inode.metadata.mtime_nsec = mtime.nsec; - let ctime = now_time_spec(); - inode.metadata.ctime_ms = ctime.to_truncated_millis()?; - inode.metadata.ctime_nsec = ctime.nsec; - Ok(()) - } - - fn truncate(&mut self, path: &str, length: u64) -> VfsResult<()> { - let inode = self.inode_mut_for_existing_path(path, "truncate", true)?; - let now = now_ms(); - match &mut inode.kind { - InodeKind::File { data } => { - resize_file_data(data, checked_file_len(length, "truncate length")?)?; - inode.metadata.mtime_ms = now; - inode.metadata.ctime_ms = now; - Ok(()) - } - InodeKind::Directory => Err(VfsError::is_directory("truncate", path)), - InodeKind::SymbolicLink { .. } => Err(VfsError::not_found("truncate", path)), - } - } - - fn pread(&mut self, path: &str, offset: u64, length: usize) -> VfsResult> { - let inode = self.inode_mut_for_existing_path(path, "open", true)?; - match &mut inode.kind { - InodeKind::File { data } => { - inode.metadata.atime_ms = now_ms(); - let start = offset as usize; - if start >= data.len() { - return Ok(Vec::new()); - } - let end = start.saturating_add(length).min(data.len()); - Ok(data[start..end].to_vec()) - } - InodeKind::Directory => Err(VfsError::is_directory("open", path)), - InodeKind::SymbolicLink { .. } => Err(VfsError::not_found("open", path)), - } - } -} - -impl Default for MemoryFileSystem { - fn default() -> Self { - Self::new() - } -} - -fn resolve_utime_spec( - spec: VirtualUtimeSpec, - now: VirtualTimeSpec, - existing: VirtualTimeSpec, -) -> VfsResult { - match spec { - VirtualUtimeSpec::Set(spec) => Ok(spec), - VirtualUtimeSpec::Now => Ok(now), - VirtualUtimeSpec::Omit => Ok(existing), - } -} - -fn resolve_utime_millis( - spec: VirtualUtimeSpec, - now_ms: u64, - existing: Option, -) -> VfsResult { - match spec { - VirtualUtimeSpec::Set(spec) => spec.to_truncated_millis(), - VirtualUtimeSpec::Now => Ok(now_ms), - VirtualUtimeSpec::Omit => existing - .ok_or_else(|| VfsError::new("EINVAL", "UTIME_OMIT requires existing metadata"))? - .to_truncated_millis(), - } -} - -pub fn validate_path(path: &str) -> VfsResult<()> { - if path.as_bytes().contains(&0) { - return Err(VfsError::invalid_input("path contains NUL byte")); - } - if let Some(control) = path - .bytes() - .find(|byte| byte.is_ascii_control() && *byte != b'\0') - { - return Err(VfsError::invalid_input(format!( - "path contains control character byte 0x{control:02x}" - ))); - } - let normalized = normalize_path(path); - if normalized.len() > MAX_PATH_LENGTH { - return Err(VfsError::path_too_long(path)); - } - Ok(()) -} - -pub fn normalize_path(path: &str) -> String { - if path.is_empty() { - return String::from("/"); - } - - let candidate = if path.starts_with('/') { - path.to_owned() - } else { - format!("/{path}") - }; - - let mut resolved = Vec::new(); - for part in candidate.split('/') { - match part { - "" | "." => {} - ".." => { - resolved.pop(); - } - component => resolved.push(component), - } - } - - if resolved.is_empty() { - String::from("/") - } else { - format!("/{}", resolved.join("/")) - } -} - -fn block_count_for_size(size: u64) -> u64 { - if size == 0 { - 0 - } else { - size.div_ceil(512) - } -} - -fn checked_file_len(value: u64, description: &'static str) -> VfsResult { - usize::try_from(value).map_err(|_| { - VfsError::new( - "EINVAL", - format!("{description} exceeds addressable memory: {value}"), - ) - }) -} - -fn reserve_file_growth(data: &mut Vec, additional: usize) -> VfsResult<()> { - data.try_reserve(additional).map_err(|error| { - VfsError::new( - "ENOMEM", - format!( - "file growth exceeds addressable memory: current length {}, additional {additional}: {error}", - data.len() - ), - ) - }) -} - -fn resize_file_data(data: &mut Vec, new_len: usize) -> VfsResult<()> { - if new_len > data.len() { - reserve_file_growth(data, new_len - data.len())?; - } - data.resize(new_len, 0); - Ok(()) -} - -fn dirname(path: &str) -> String { - let normalized = normalize_path(path); - let Some((head, _)) = normalized.rsplit_once('/') else { - return String::from("/"); - }; - - if head.is_empty() { - String::from("/") - } else { - String::from(head) - } -} - -fn now_ms() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as u64 -} - -fn now_time_spec() -> VirtualTimeSpec { - let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default(); - VirtualTimeSpec { - sec: now.as_secs() as i64, - nsec: now.subsec_nanos(), - } -} diff --git a/crates/vfs/tests/conformance.rs b/crates/vfs/tests/conformance.rs deleted file mode 100644 index abf95c12a..000000000 --- a/crates/vfs/tests/conformance.rs +++ /dev/null @@ -1,426 +0,0 @@ -use async_trait::async_trait; -use std::sync::{Arc, Condvar, Mutex}; -use vfs::engine::engines::{ChunkedFs, ChunkedFsOptions, ObjectFs}; -use vfs::engine::mem::{InMemoryMetadataStore, MemoryBlockStore, MemoryObjectBackend}; -use vfs::engine::{ - BlockKey, CachedMetadataStore, ChunkEdit, ChunkRange, CreateInodeAttrs, InodePatch, InodeType, - MetadataStore, SnapshotId, Storage, VfsResult, VirtualFileSystem, -}; - -#[tokio::test] -async fn chunked_fs_round_trips_inline_and_chunked_files() { - let metadata = InMemoryMetadataStore::new(); - let blocks = MemoryBlockStore::new(); - let fs = ChunkedFs::with_options( - metadata, - blocks.clone(), - ChunkedFsOptions { - inline_threshold: 4, - chunk_size: 3, - ..ChunkedFsOptions::default() - }, - ); - - fs.write_file("/small.txt", b"abc").await.unwrap(); - assert_eq!(fs.read_file("/small.txt").await.unwrap(), b"abc"); - assert_eq!(blocks.len(), 0); - - fs.write_file("/large.txt", b"abcdefghi").await.unwrap(); - assert_eq!(fs.read_file("/large.txt").await.unwrap(), b"abcdefghi"); - assert_eq!(blocks.len(), 3); - - fs.pwrite("/large.txt", b"ZZ", 2).await.unwrap(); - assert_eq!(fs.read_file("/large.txt").await.unwrap(), b"abZZefghi"); -} - -#[tokio::test] -async fn chunked_fs_partial_writes_preserve_untouched_chunks() { - let metadata = InMemoryMetadataStore::new(); - let blocks = MemoryBlockStore::new(); - let fs = ChunkedFs::with_options( - metadata.clone(), - blocks, - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - - fs.write_file("/large.txt", b"aaaabbbbcccc").await.unwrap(); - let ino = metadata.resolve("/large.txt").await.unwrap().ino; - let before = metadata.get_chunks(ino, ChunkRange::all()).await.unwrap(); - assert_eq!(before.len(), 3); - - fs.pwrite("/large.txt", b"Z", 5).await.unwrap(); - - assert_eq!(fs.read_file("/large.txt").await.unwrap(), b"aaaabZbbcccc"); - let after = metadata.get_chunks(ino, ChunkRange::all()).await.unwrap(); - assert_eq!(after.len(), 3); - assert_eq!(after[0].key, before[0].key); - assert_ne!(after[1].key, before[1].key); - assert_eq!(after[2].key, before[2].key); -} - -#[tokio::test] -async fn chunked_fs_sparse_pwrite_and_truncate_zero_fill_holes() { - let fs = ChunkedFs::with_options( - InMemoryMetadataStore::new(), - MemoryBlockStore::new(), - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 4, - ..ChunkedFsOptions::default() - }, - ); - - fs.write_file("/sparse", b"").await.unwrap(); - fs.pwrite("/sparse", b"end", 10).await.unwrap(); - assert_eq!( - fs.read_file("/sparse").await.unwrap(), - b"\0\0\0\0\0\0\0\0\0\0end" - ); - - fs.write_file("/truncate", b"abcdefgh").await.unwrap(); - fs.truncate("/truncate", 5).await.unwrap(); - fs.truncate("/truncate", 8).await.unwrap(); - assert_eq!(fs.read_file("/truncate").await.unwrap(), b"abcde\0\0\0"); -} - -#[tokio::test] -async fn chunked_fs_dedups_identical_content_and_gc_deletes_on_unlink() { - let metadata = InMemoryMetadataStore::new(); - let blocks = MemoryBlockStore::new(); - let fs = ChunkedFs::with_options( - metadata.clone(), - blocks.clone(), - ChunkedFsOptions { - inline_threshold: 1, - chunk_size: 16, - ..ChunkedFsOptions::default() - }, - ); - - fs.write_file("/a", b"same content").await.unwrap(); - fs.write_file("/b", b"same content").await.unwrap(); - let key = BlockKey::from_content(b"same content"); - assert_eq!(blocks.len(), 1); - assert_eq!(metadata.refcount(&key), 2); - - fs.remove_file("/a").await.unwrap(); - assert_eq!(blocks.len(), 1); - assert_eq!(metadata.refcount(&key), 1); - - fs.remove_file("/b").await.unwrap(); - assert_eq!(blocks.len(), 0); - assert_eq!(metadata.refcount(&key), 0); -} - -#[tokio::test] -async fn metadata_snapshot_and_fork_share_chunk_refs_until_cow_write() { - let metadata = InMemoryMetadataStore::new(); - let parent = metadata.resolve("/").await.unwrap(); - let file = metadata - .create( - parent.ino, - "file", - CreateInodeAttrs::file(0o644, 0, 0, Storage::Chunked { chunk_size: 16 }), - ) - .await - .unwrap(); - let key = BlockKey::from_content(b"hello"); - metadata - .commit_write( - file.ino, - vec![ChunkEdit { - index: 0, - key: key.clone(), - len: 5, - }], - 5, - ) - .await - .unwrap(); - assert_eq!(metadata.refcount(&key), 1); - - let snap = metadata.snapshot(parent.ino).await.unwrap(); - assert_eq!(metadata.refcount(&key), 2); - let fork_root = metadata.fork(snap).await.unwrap(); - assert_eq!(metadata.refcount(&key), 3); - - let fork_entries = metadata.list_dir(fork_root).await.unwrap(); - let fork_file = fork_entries - .iter() - .find(|entry| entry.name == "file") - .unwrap() - .meta - .ino; - let new_key = BlockKey::from_content(b"goodbye"); - metadata - .commit_write( - fork_file, - vec![ChunkEdit { - index: 0, - key: new_key.clone(), - len: 7, - }], - 7, - ) - .await - .unwrap(); - assert_eq!(metadata.refcount(&key), 2); - assert_eq!(metadata.refcount(&new_key), 1); -} - -#[tokio::test] -async fn object_fs_maps_files_to_native_objects() { - let backend = MemoryObjectBackend::new(); - let fs = ObjectFs::new(backend); - fs.mkdir("/dir", false).await.unwrap(); - fs.write_file("/dir/file.txt", b"hello").await.unwrap(); - - assert_eq!(fs.read_file("/dir/file.txt").await.unwrap(), b"hello"); - assert_eq!(fs.read_dir("/dir").await.unwrap(), vec!["file.txt"]); - assert_eq!(fs.pread("/dir/file.txt", 1, 3).await.unwrap(), b"ell"); -} - -#[tokio::test] -async fn object_fs_recursively_renames_prefix_directories() { - let backend = MemoryObjectBackend::new(); - let fs = ObjectFs::new(backend); - fs.mkdir("/src/nested", true).await.unwrap(); - fs.write_file("/src/root.txt", b"root").await.unwrap(); - fs.write_file("/src/nested/leaf.txt", b"leaf") - .await - .unwrap(); - - fs.rename("/src", "/dst").await.unwrap(); - - assert!(!fs.exists("/src/root.txt").await); - assert_eq!(fs.read_file("/dst/root.txt").await.unwrap(), b"root"); - assert_eq!(fs.read_file("/dst/nested/leaf.txt").await.unwrap(), b"leaf"); -} - -#[tokio::test] -async fn cache_invalidates_on_mutation() { - let metadata = CachedMetadataStore::new(InMemoryMetadataStore::new(), 16); - let root = metadata.resolve("/").await.unwrap(); - assert!(metadata.resolve("/new").await.is_err()); - metadata - .create(root.ino, "new", CreateInodeAttrs::directory(0o755, 0, 0)) - .await - .unwrap(); - assert_eq!( - metadata.resolve("/new").await.unwrap().kind, - InodeType::Directory - ); -} - -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn cache_does_not_store_stale_read_when_mutation_wins_race() { - let inner = InMemoryMetadataStore::new(); - let root = inner.resolve("/").await.unwrap(); - inner - .create( - root.ino, - "stale", - CreateInodeAttrs::file(0o644, 0, 0, Storage::Inline(Vec::new())), - ) - .await - .unwrap(); - let gate = Arc::new(RaceGate::default()); - let metadata = Arc::new(CachedMetadataStore::new( - PausingResolveStore { - inner, - path: "/stale".to_string(), - gate: gate.clone(), - }, - 16, - )); - - let pending_metadata = metadata.clone(); - let pending = tokio::spawn(async move { pending_metadata.resolve("/stale").await }); - gate.wait_until_paused(); - metadata.remove(root.ino, "stale").await.unwrap(); - gate.release(); - assert!(pending.await.unwrap().is_ok()); - - let result = metadata.resolve("/stale").await; - assert!(result.is_err()); -} - -#[tokio::test] -async fn metadata_set_attr_drops_chunk_refs_when_file_becomes_inline() { - let metadata = InMemoryMetadataStore::new(); - let parent = metadata.resolve("/").await.unwrap(); - let file = metadata - .create( - parent.ino, - "file", - CreateInodeAttrs::file(0o644, 0, 0, Storage::Chunked { chunk_size: 16 }), - ) - .await - .unwrap(); - let key = BlockKey::from_content(b"hello"); - metadata - .commit_write( - file.ino, - vec![ChunkEdit { - index: 0, - key: key.clone(), - len: 5, - }], - 5, - ) - .await - .unwrap(); - - let freed = metadata - .set_attr( - file.ino, - InodePatch { - storage: Some(Storage::Inline(b"hi".to_vec())), - size: Some(2), - ..InodePatch::default() - }, - ) - .await - .unwrap(); - assert_eq!(freed, vec![key]); - assert!(metadata - .get_chunks(file.ino, ChunkRange::all()) - .await - .unwrap() - .is_empty()); -} - -#[derive(Debug, Default)] -struct RaceGate { - state: Mutex, - changed: Condvar, -} - -#[derive(Debug, Default)] -struct RaceGateState { - paused_once: bool, - paused: bool, - released: bool, -} - -impl RaceGate { - fn pause_once(&self) { - let mut state = self.state.lock().expect("race gate poisoned"); - if state.paused_once { - return; - } - state.paused_once = true; - state.paused = true; - self.changed.notify_all(); - while !state.released { - state = self.changed.wait(state).expect("race gate poisoned"); - } - } - - fn wait_until_paused(&self) { - let mut state = self.state.lock().expect("race gate poisoned"); - while !state.paused { - state = self.changed.wait(state).expect("race gate poisoned"); - } - } - - fn release(&self) { - let mut state = self.state.lock().expect("race gate poisoned"); - state.released = true; - self.changed.notify_all(); - } -} - -#[derive(Debug, Clone)] -struct PausingResolveStore { - inner: InMemoryMetadataStore, - path: String, - gate: Arc, -} - -#[async_trait] -impl MetadataStore for PausingResolveStore { - async fn resolve(&self, path: &str) -> VfsResult { - let result = self.inner.resolve(path).await; - if path == self.path { - self.gate.pause_once(); - } - result - } - - async fn resolve_parent(&self, path: &str) -> VfsResult<(vfs::engine::InodeMeta, String)> { - self.inner.resolve_parent(path).await - } - - async fn lstat(&self, path: &str) -> VfsResult { - self.inner.lstat(path).await - } - - async fn list_dir(&self, ino: u64) -> VfsResult> { - self.inner.list_dir(ino).await - } - - async fn create( - &self, - parent: u64, - name: &str, - attrs: CreateInodeAttrs, - ) -> VfsResult { - self.inner.create(parent, name, attrs).await - } - - async fn link(&self, parent: u64, name: &str, target: u64) -> VfsResult<()> { - self.inner.link(parent, name, target).await - } - - async fn remove(&self, parent: u64, name: &str) -> VfsResult> { - self.inner.remove(parent, name).await - } - - async fn rename( - &self, - src_parent: u64, - src: &str, - dst_parent: u64, - dst: &str, - ) -> VfsResult> { - self.inner.rename(src_parent, src, dst_parent, dst).await - } - - async fn set_attr(&self, ino: u64, patch: InodePatch) -> VfsResult> { - self.inner.set_attr(ino, patch).await - } - - async fn commit_write( - &self, - ino: u64, - edits: Vec, - new_size: u64, - ) -> VfsResult> { - self.inner.commit_write(ino, edits, new_size).await - } - - async fn get_chunks( - &self, - ino: u64, - range: ChunkRange, - ) -> VfsResult> { - self.inner.get_chunks(ino, range).await - } - - async fn snapshot(&self, root: u64) -> VfsResult { - self.inner.snapshot(root).await - } - - async fn fork(&self, snap: SnapshotId) -> VfsResult { - self.inner.fork(snap).await - } - - async fn gc(&self) -> VfsResult> { - self.inner.gc().await - } -} diff --git a/crates/vfs/tests/posix_mount_plugin.rs b/crates/vfs/tests/posix_mount_plugin.rs deleted file mode 100644 index 802843e4b..000000000 --- a/crates/vfs/tests/posix_mount_plugin.rs +++ /dev/null @@ -1,117 +0,0 @@ -use serde_json::json; -use vfs::posix::MountedVirtualFileSystem; -use vfs::posix::{ - FileSystemPluginFactory, FileSystemPluginRegistry, OpenFileSystemPluginRequest, PluginError, -}; -use vfs::posix::{MemoryFileSystem, VirtualFileSystem}; - -#[derive(Debug)] -struct SeededMemoryPlugin; - -#[derive(Debug)] -struct NamedPlugin(&'static str); - -impl FileSystemPluginFactory<()> for SeededMemoryPlugin { - fn plugin_id(&self) -> &'static str { - "seeded_memory" - } - - fn open( - &self, - _request: OpenFileSystemPluginRequest<'_, ()>, - ) -> Result, PluginError> { - let mut filesystem = MemoryFileSystem::new(); - filesystem - .write_file("/hello.txt", b"hello".to_vec()) - .expect("seed plugin filesystem"); - Ok(Box::new(MountedVirtualFileSystem::new(filesystem))) - } -} - -impl FileSystemPluginFactory<()> for NamedPlugin { - fn plugin_id(&self) -> &'static str { - self.0 - } - - fn open( - &self, - _request: OpenFileSystemPluginRequest<'_, ()>, - ) -> Result, PluginError> { - Ok(Box::new(MountedVirtualFileSystem::new( - MemoryFileSystem::new(), - ))) - } -} - -#[test] -fn plugin_registry_opens_registered_plugins() { - let mut registry = FileSystemPluginRegistry::new(); - registry - .register(SeededMemoryPlugin) - .expect("register seeded plugin"); - - let mut filesystem = registry - .open( - "seeded_memory", - OpenFileSystemPluginRequest { - vm_id: "vm-1", - guest_path: "/workspace", - read_only: false, - config: &json!({}), - context: &(), - }, - ) - .expect("open seeded plugin"); - - assert_eq!( - filesystem - .read_file("/hello.txt") - .expect("read plugin file"), - b"hello".to_vec() - ); -} - -#[test] -fn plugin_registry_rejects_ids_that_are_not_mount_type_tokens() { - for plugin_id in ["", "bad/id", "bad id", "bad\nid", "bad:id", "bad😀id"] { - let mut registry = FileSystemPluginRegistry::new(); - let error = registry - .register(NamedPlugin(plugin_id)) - .expect_err("invalid plugin id should be rejected"); - - assert_eq!(error.code(), "EINVAL"); - assert!( - error.message().contains("invalid filesystem plugin id"), - "unexpected error: {error}" - ); - assert!(registry.plugin_ids().is_empty()); - } -} - -#[test] -fn plugin_registry_rejects_duplicate_or_unknown_plugins() { - let mut registry = FileSystemPluginRegistry::new(); - registry - .register(SeededMemoryPlugin) - .expect("register initial plugin"); - - let duplicate = registry - .register(SeededMemoryPlugin) - .expect_err("duplicate registration should fail"); - assert_eq!(duplicate.code(), "EEXIST"); - - let missing = match registry.open( - "missing", - OpenFileSystemPluginRequest { - vm_id: "vm-1", - guest_path: "/workspace", - read_only: false, - config: &json!({}), - context: &(), - }, - ) { - Ok(_) => panic!("missing plugin should fail"), - Err(error) => error, - }; - assert_eq!(missing.code(), "ENOSYS"); -} diff --git a/crates/vfs/tests/posix_mount_table.rs b/crates/vfs/tests/posix_mount_table.rs deleted file mode 100644 index 63e8302eb..000000000 --- a/crates/vfs/tests/posix_mount_table.rs +++ /dev/null @@ -1,523 +0,0 @@ -use std::any::Any; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; -use vfs::posix::{ - MemoryFileSystem, SingleSymlinkFileSystem, VfsResult, VirtualDirEntry, VirtualFileSystem, - VirtualStat, VirtualUtimeSpec, -}; -use vfs::posix::{MountOptions, MountTable, MountedFileSystem}; - -struct ShutdownTrackingFileSystem { - shutdown: Arc, -} - -impl ShutdownTrackingFileSystem { - fn new(shutdown: Arc) -> Self { - Self { shutdown } - } -} - -impl MountedFileSystem for ShutdownTrackingFileSystem { - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } - - fn read_file(&mut self, path: &str) -> VfsResult> { - unreachable!("failed mount should not read {path}") - } - - fn read_dir(&mut self, path: &str) -> VfsResult> { - unreachable!("failed mount should not read dir {path}") - } - - fn read_dir_with_types(&mut self, path: &str) -> VfsResult> { - unreachable!("failed mount should not read dir types {path}") - } - - fn write_file(&mut self, path: &str, _content: Vec) -> VfsResult<()> { - unreachable!("failed mount should not write {path}") - } - - fn create_dir(&mut self, path: &str) -> VfsResult<()> { - unreachable!("failed mount should not create dir {path}") - } - - fn mkdir(&mut self, path: &str, _recursive: bool) -> VfsResult<()> { - unreachable!("failed mount should not mkdir {path}") - } - - fn exists(&self, _path: &str) -> bool { - false - } - - fn stat(&mut self, path: &str) -> VfsResult { - unreachable!("failed mount should not stat {path}") - } - - fn remove_file(&mut self, path: &str) -> VfsResult<()> { - unreachable!("failed mount should not remove file {path}") - } - - fn remove_dir(&mut self, path: &str) -> VfsResult<()> { - unreachable!("failed mount should not remove dir {path}") - } - - fn rename(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - unreachable!("failed mount should not rename {old_path} to {new_path}") - } - - fn realpath(&self, path: &str) -> VfsResult { - unreachable!("failed mount should not realpath {path}") - } - - fn symlink(&mut self, target: &str, link_path: &str) -> VfsResult<()> { - unreachable!("failed mount should not symlink {target} to {link_path}") - } - - fn read_link(&self, path: &str) -> VfsResult { - unreachable!("failed mount should not readlink {path}") - } - - fn lstat(&self, path: &str) -> VfsResult { - unreachable!("failed mount should not lstat {path}") - } - - fn link(&mut self, old_path: &str, new_path: &str) -> VfsResult<()> { - unreachable!("failed mount should not link {old_path} to {new_path}") - } - - fn chmod(&mut self, path: &str, _mode: u32) -> VfsResult<()> { - unreachable!("failed mount should not chmod {path}") - } - - fn chown(&mut self, path: &str, _uid: u32, _gid: u32) -> VfsResult<()> { - unreachable!("failed mount should not chown {path}") - } - - fn utimes(&mut self, path: &str, _atime_ms: u64, _mtime_ms: u64) -> VfsResult<()> { - unreachable!("failed mount should not utimes {path}") - } - - fn utimes_spec( - &mut self, - path: &str, - _atime: VirtualUtimeSpec, - _mtime: VirtualUtimeSpec, - _follow_symlinks: bool, - ) -> VfsResult<()> { - unreachable!("failed mount should not utimes_spec {path}") - } - - fn truncate(&mut self, path: &str, _length: u64) -> VfsResult<()> { - unreachable!("failed mount should not truncate {path}") - } - - fn pread(&mut self, path: &str, _offset: u64, _length: usize) -> VfsResult> { - unreachable!("failed mount should not pread {path}") - } - - fn shutdown(&mut self) -> VfsResult<()> { - self.shutdown.store(true, Ordering::SeqCst); - Ok(()) - } -} - -#[test] -fn mount_table_prefers_mounted_filesystems_and_merges_mount_points() { - let mut root = MemoryFileSystem::new(); - root.write_file("/data/root-only.txt", b"root".to_vec()) - .expect("seed root file"); - - let mut mounted = MemoryFileSystem::new(); - mounted - .write_file("/mounted.txt", b"mounted".to_vec()) - .expect("seed mounted file"); - - let mut table = MountTable::new(root); - table - .mount("/data", mounted, MountOptions::new("memory")) - .expect("mount memory filesystem"); - - assert_eq!( - table - .read_file("/data/mounted.txt") - .expect("read mounted file"), - b"mounted".to_vec() - ); - assert!(!table.exists("/data/root-only.txt")); - - let root_entries = table.read_dir("/").expect("read root directory"); - assert!(root_entries.contains(&String::from("data"))); -} - -#[test] -fn mount_table_enforces_read_only_and_cross_mount_boundaries() { - let mut table = MountTable::new(MemoryFileSystem::new()); - table - .mount( - "/readonly", - MemoryFileSystem::new(), - MountOptions::new("memory").read_only(true), - ) - .expect("mount readonly filesystem"); - table - .mount( - "/writable", - MemoryFileSystem::new(), - MountOptions::new("memory"), - ) - .expect("mount writable filesystem"); - - let read_only_error = table - .write_file("/readonly/blocked.txt", b"blocked".to_vec()) - .expect_err("readonly mount should reject writes"); - assert_eq!(read_only_error.code(), "EROFS"); - - table - .write_file("/writable/file.txt", b"ok".to_vec()) - .expect("write mounted file"); - let cross_mount_error = table - .rename("/writable/file.txt", "/file.txt") - .expect_err("rename across mounts should fail"); - assert_eq!(cross_mount_error.code(), "EXDEV"); -} - -#[test] -fn mount_table_rejects_symlinks_that_cross_mount_boundaries() { - let mut root = MemoryFileSystem::new(); - root.write_file("/root.txt", b"root".to_vec()) - .expect("seed root file"); - - let mut mounted = MemoryFileSystem::new(); - mounted - .write_file("/inside.txt", b"inside".to_vec()) - .expect("seed mounted file"); - - let mut table = MountTable::new(root); - table - .mount("/mounted", mounted, MountOptions::new("memory")) - .expect("mount memory filesystem"); - - let error = table - .symlink("../root.txt", "/mounted/root-link") - .expect_err("cross-mount symlink should fail"); - assert_eq!(error.code(), "EXDEV"); -} - -#[test] -fn mount_table_rejects_hardlinks_that_cross_mount_boundaries() { - let mut root = MemoryFileSystem::new(); - root.write_file("/root.txt", b"root".to_vec()) - .expect("seed root file"); - - let mut mounted = MemoryFileSystem::new(); - mounted - .write_file("/inside.txt", b"inside".to_vec()) - .expect("seed mounted file"); - - let mut table = MountTable::new(root); - table - .mount("/mounted", mounted, MountOptions::new("memory")) - .expect("mount memory filesystem"); - - let error = table - .link("/root.txt", "/mounted/root-link") - .expect_err("cross-mount hardlink should fail"); - assert_eq!(error.code(), "EXDEV"); -} - -#[test] -fn mount_table_realpath_follows_symlinks_across_leaf_mounts() { - let mut table = MountTable::new(MemoryFileSystem::new()); - - table - .mount_boxed( - "/opt/agentos/bin/pi", - Box::new(vfs::posix::MountedVirtualFileSystem::new( - SingleSymlinkFileSystem::new("../pkgs/pi/current/bin/pi"), - )), - MountOptions::new("single-symlink").read_only(true), - ) - .expect("mount command symlink leaf"); - - table - .mount_boxed( - "/opt/agentos/pkgs/pi/current", - Box::new(vfs::posix::MountedVirtualFileSystem::new( - SingleSymlinkFileSystem::new("1.2.3"), - )), - MountOptions::new("single-symlink").read_only(true), - ) - .expect("mount current symlink leaf"); - - let mut content = MemoryFileSystem::new(); - content - .mkdir("/bin", true) - .expect("seed package bin directory"); - content - .write_file("/bin/pi", b"#!/bin/sh\n".to_vec()) - .expect("seed package command"); - table - .mount( - "/opt/agentos/pkgs/pi/1.2.3", - content, - MountOptions::new("tar").read_only(true), - ) - .expect("mount package content leaf"); - - assert_eq!( - table - .realpath("/opt/agentos/bin/pi") - .expect("realpath across command/current/content mounts"), - "/opt/agentos/pkgs/pi/1.2.3/bin/pi" - ); -} - -#[test] -fn mount_table_realpath_keeps_mount_local_absolute_symlinks_inside_mount() { - let mut table = MountTable::new(MemoryFileSystem::new()); - let mut mounted = MemoryFileSystem::new(); - mounted - .write_file("/target.txt", b"target".to_vec()) - .expect("seed mount target"); - mounted - .symlink("/target.txt", "/link.txt") - .expect("seed mount-local absolute symlink"); - - table - .mount("/mnt", mounted, MountOptions::new("memory")) - .expect("mount memory filesystem"); - - assert_eq!( - table - .realpath("/mnt/link.txt") - .expect("realpath through mount-local absolute symlink"), - "/mnt/target.txt" - ); -} - -#[test] -fn leaf_mounts_coexist_with_user_files_in_writable_parent_directory() { - let mut table = MountTable::new(MemoryFileSystem::new()); - - table - .mount_boxed( - "/opt/agentos/bin/pi", - Box::new(vfs::posix::MountedVirtualFileSystem::new( - SingleSymlinkFileSystem::new("../pkgs/pi/current/bin/pi"), - )), - MountOptions::new("single-symlink").read_only(true), - ) - .expect("mount managed command leaf"); - - let mut content = MemoryFileSystem::new(); - content - .mkdir("/bin", true) - .expect("seed package bin directory"); - content - .write_file("/bin/pi", b"#!/bin/sh\n".to_vec()) - .expect("seed executable package command"); - content - .chmod("/bin/pi", 0o755) - .expect("chmod package command executable"); - table - .mount( - "/opt/agentos/pkgs/pi/1.2.3", - content, - MountOptions::new("tar").read_only(true), - ) - .expect("mount package content leaf"); - table - .mount_boxed( - "/opt/agentos/pkgs/pi/current", - Box::new(vfs::posix::MountedVirtualFileSystem::new( - SingleSymlinkFileSystem::new("1.2.3"), - )), - MountOptions::new("single-symlink").read_only(true), - ) - .expect("mount current symlink leaf"); - - table - .write_file("/opt/agentos/bin/user-tool", b"#!/bin/sh\n".to_vec()) - .expect("user install writes into writable parent dir"); - table - .chmod("/opt/agentos/bin/user-tool", 0o755) - .expect("chmod user command executable"); - - let entries = table - .read_dir("/opt/agentos/bin") - .expect("list merged managed/user bin dir"); - assert!(entries.contains(&String::from("pi"))); - assert!(entries.contains(&String::from("user-tool"))); - - let managed_realpath = table - .realpath("/opt/agentos/bin/pi") - .expect("managed command realpath"); - assert_eq!(managed_realpath, "/opt/agentos/pkgs/pi/1.2.3/bin/pi"); - assert_eq!( - table - .stat(&managed_realpath) - .expect("managed command stat") - .mode - & 0o111, - 0o111 - ); - assert_eq!( - table - .stat("/opt/agentos/bin/user-tool") - .expect("user command stat") - .mode - & 0o111, - 0o111 - ); -} - -#[test] -fn mount_table_mounts_nested_filesystems_under_read_only_parents() { - let mut table = MountTable::new(MemoryFileSystem::new()); - table - .mount( - "/root/node_modules", - MemoryFileSystem::new(), - MountOptions::new("memory").read_only(true), - ) - .expect("mount read-only parent filesystem"); - - let mut nested = MemoryFileSystem::new(); - nested - .write_file("/package.json", b"{}".to_vec()) - .expect("seed nested package file"); - - table - .mount( - "/root/node_modules/@scope/pkg", - nested, - MountOptions::new("memory").read_only(true), - ) - .expect("read-only parents must still accept nested mounts"); - - assert_eq!( - table - .read_file("/root/node_modules/@scope/pkg/package.json") - .expect("read file through nested mount"), - b"{}".to_vec() - ); -} - -#[test] -fn mount_table_rejects_mount_when_mount_point_creation_fails() { - let mut root = MemoryFileSystem::new(); - root.write_file("/blocked", b"not a directory".to_vec()) - .expect("seed file at parent path"); - let mut table = MountTable::new(root); - - let error = table - .mount( - "/blocked/child", - MemoryFileSystem::new(), - MountOptions::new("memory"), - ) - .expect_err("mount point creation should fail through file parent"); - - assert_eq!(error.code(), "ENOTDIR"); - assert!(!table - .get_mounts() - .iter() - .any(|mount| mount.path == "/blocked/child")); -} - -#[test] -fn mount_table_shuts_down_boxed_filesystem_when_mount_point_creation_fails() { - let mut root = MemoryFileSystem::new(); - root.write_file("/blocked", b"not a directory".to_vec()) - .expect("seed file at parent path"); - let mut table = MountTable::new(root); - let shutdown = Arc::new(AtomicBool::new(false)); - - let error = table - .mount_boxed( - "/blocked/child", - Box::new(ShutdownTrackingFileSystem::new(Arc::clone(&shutdown))), - MountOptions::new("tracking"), - ) - .expect_err("mount point creation should fail through file parent"); - - assert_eq!(error.code(), "ENOTDIR"); - assert!(shutdown.load(Ordering::SeqCst)); -} - -#[test] -fn mount_table_unmount_rejects_parent_mounts_with_children() { - let mut table = MountTable::new(MemoryFileSystem::new()); - table - .mount("/a", MemoryFileSystem::new(), MountOptions::new("parent")) - .expect("mount parent filesystem"); - table - .mount("/a/b", MemoryFileSystem::new(), MountOptions::new("child")) - .expect("mount child filesystem"); - - let error = table - .unmount("/a") - .expect_err("parent mount should stay busy while child mount exists"); - assert_eq!(error.code(), "EBUSY"); -} - -#[test] -fn mount_table_unmount_succeeds_after_children_are_removed() { - let mut table = MountTable::new(MemoryFileSystem::new()); - table - .mount("/a", MemoryFileSystem::new(), MountOptions::new("parent")) - .expect("mount parent filesystem"); - table - .mount("/a/b", MemoryFileSystem::new(), MountOptions::new("child")) - .expect("mount child filesystem"); - - table.unmount("/a/b").expect("unmount child first"); - table.unmount("/a").expect("unmount parent after child"); -} - -#[test] -fn mount_table_does_not_alias_paths_that_repeat_the_mount_segment() { - // Regression: `resolve_index` previously stripped the mount prefix with - // `trim_start_matches`, which removes *every* leading repetition. For a - // mount `/data`, `/data/database.sqlite` was mangled to `/base.sqlite` - // (because `/database.sqlite` still starts with `/data`), so a read of one - // file silently returned a different file within the mount. - let mut backing = MemoryFileSystem::new(); - backing - .write_file("/database.sqlite", b"REAL".to_vec()) - .expect("seed real file"); - backing - .write_file("/base.sqlite", b"DECOY".to_vec()) - .expect("seed decoy file"); - - let mut table = MountTable::new(MemoryFileSystem::new()); - table - .mount("/data", backing, MountOptions::new("memory")) - .expect("mount memory filesystem"); - - assert_eq!( - table.read_file("/data/database.sqlite").expect("read file"), - b"REAL".to_vec(), - "path must map to the file the caller named, not an aliased one" - ); - - // A genuinely nested directory named like the mount must also resolve right. - let mut nested = MemoryFileSystem::new(); - nested.mkdir("/data", true).expect("nested dir"); - nested - .write_file("/data/file.txt", b"NESTED".to_vec()) - .expect("seed nested file"); - let mut table = MountTable::new(MemoryFileSystem::new()); - table - .mount("/data", nested, MountOptions::new("memory")) - .expect("mount nested filesystem"); - assert_eq!( - table.read_file("/data/data/file.txt").expect("read nested"), - b"NESTED".to_vec() - ); -} diff --git a/crates/vfs/tests/posix_root_fs.rs b/crates/vfs/tests/posix_root_fs.rs deleted file mode 100644 index 1345002ab..000000000 --- a/crates/vfs/tests/posix_root_fs.rs +++ /dev/null @@ -1,823 +0,0 @@ -use std::collections::BTreeMap; -use vfs::posix::{ - decode_snapshot, decode_snapshot_with_import_limits, encode_snapshot, FilesystemEntry, - MemoryFileSystemSnapshot, MemoryFileSystemSnapshotInode, MemoryFileSystemSnapshotInodeKind, - MemoryFileSystemSnapshotMetadata, RootFileSystem, RootFilesystemDescriptor, - RootFilesystemImportLimits, RootFilesystemMode, RootFilesystemResourceLimits, - RootFilesystemSnapshot, ROOT_FILESYSTEM_SNAPSHOT_FORMAT, -}; -use vfs::posix::{MemoryFileSystem, VirtualFileSystem, S_IFDIR, S_IFLNK, S_IFREG}; -use vfs::posix::{OverlayFileSystem, OverlayMode}; - -#[derive(Debug, Clone, Copy, Default)] -struct TestResourceLimits { - max_filesystem_bytes: Option, - max_inode_count: Option, -} - -impl RootFilesystemResourceLimits for TestResourceLimits { - fn max_filesystem_bytes(&self) -> Option { - self.max_filesystem_bytes - } - - fn max_inode_count(&self) -> Option { - self.max_inode_count - } -} - -fn directory_metadata(ino: u64) -> MemoryFileSystemSnapshotMetadata { - MemoryFileSystemSnapshotMetadata { - mode: S_IFDIR | 0o755, - uid: 1000, - gid: 1000, - nlink: 2, - ino, - atime_ms: 0, - atime_nsec: 0, - mtime_ms: 0, - mtime_nsec: 0, - ctime_ms: 0, - ctime_nsec: 0, - birthtime_ms: 0, - } -} - -fn directory_inode(ino: u64) -> MemoryFileSystemSnapshotInode { - MemoryFileSystemSnapshotInode { - metadata: directory_metadata(ino), - kind: MemoryFileSystemSnapshotInodeKind::Directory, - } -} - -fn deep_directory_tree(child_depth: usize) -> MemoryFileSystem { - let mut path_index = BTreeMap::new(); - let mut inodes = BTreeMap::new(); - let mut next_ino = 1; - - path_index.insert(String::from("/"), next_ino); - inodes.insert(next_ino, directory_inode(next_ino)); - next_ino += 1; - - let mut path = String::from("/deep"); - path_index.insert(path.clone(), next_ino); - inodes.insert(next_ino, directory_inode(next_ino)); - next_ino += 1; - - for _ in 0..child_depth { - path.push_str("/d"); - path_index.insert(path.clone(), next_ino); - inodes.insert(next_ino, directory_inode(next_ino)); - next_ino += 1; - } - - MemoryFileSystem::from_snapshot(MemoryFileSystemSnapshot { - path_index, - inodes, - next_ino, - }) -} - -fn assert_error_code(result: Result, expected: &str) { - let error = result.expect_err("expected operation to fail"); - assert_eq!(error.code(), expected); -} - -#[test] -fn overlay_filesystem_prefers_higher_lowers_and_hides_whiteouts() { - let mut higher = MemoryFileSystem::new(); - let mut lower = MemoryFileSystem::new(); - - higher.mkdir("/etc", true).expect("create higher /etc"); - lower.mkdir("/etc", true).expect("create lower /etc"); - higher - .write_file("/etc/config.txt", b"higher".to_vec()) - .expect("seed higher file"); - lower - .write_file("/etc/config.txt", b"lower".to_vec()) - .expect("seed lower file"); - lower - .write_file("/etc/only-lower.txt", b"lower-only".to_vec()) - .expect("seed lower-only file"); - - let mut overlay = OverlayFileSystem::new(vec![higher, lower], OverlayMode::Ephemeral); - assert_eq!( - overlay - .read_file("/etc/config.txt") - .expect("read merged config"), - b"higher".to_vec() - ); - assert_eq!( - overlay - .read_file("/etc/only-lower.txt") - .expect("read lower-only file"), - b"lower-only".to_vec() - ); - - overlay - .remove_file("/etc/only-lower.txt") - .expect("whiteout lower file"); - assert!(!overlay.exists("/etc/only-lower.txt")); - - let entries = overlay.read_dir("/etc").expect("read merged directory"); - assert_eq!(entries, vec![String::from("config.txt")]); -} - -#[test] -fn overlay_root_stat_uses_highest_lower_metadata() { - let mut higher = MemoryFileSystem::new(); - let mut lower = MemoryFileSystem::new(); - - higher.chown("/", 0, 0).expect("set higher root owner"); - lower.chown("/", 2000, 3000).expect("set lower root owner"); - - let overlay = OverlayFileSystem::new(vec![higher, lower], OverlayMode::Ephemeral); - let stat = overlay.lstat("/").expect("lstat merged root"); - - assert_eq!(stat.uid, 0); - assert_eq!(stat.gid, 0); -} - -#[test] -fn overlay_rename_moves_lower_directory_trees_without_losing_children() { - let mut lower = MemoryFileSystem::new(); - lower - .mkdir("/src/nested", true) - .expect("create lower directory tree"); - lower - .write_file("/src/nested/child.txt", b"nested".to_vec()) - .expect("seed nested child"); - lower - .write_file("/src/root.txt", b"root".to_vec()) - .expect("seed root child"); - - let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); - overlay - .rename("/src", "/dst") - .expect("rename lower directory"); - - assert_eq!( - overlay - .read_file("/dst/nested/child.txt") - .expect("read renamed nested child"), - b"nested".to_vec() - ); - assert_eq!( - overlay - .read_file("/dst/root.txt") - .expect("read renamed root child"), - b"root".to_vec() - ); - assert_error_code(overlay.read_file("/src/nested/child.txt"), "ENOENT"); -} - -#[test] -fn overlay_rename_preserves_symlinks_instead_of_dereferencing_them() { - let mut lower = MemoryFileSystem::new(); - lower - .write_file("/target.txt", b"target".to_vec()) - .expect("seed symlink target"); - lower - .symlink("/target.txt", "/alias.txt") - .expect("create lower symlink"); - - let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); - overlay - .rename("/alias.txt", "/alias-renamed.txt") - .expect("rename symlink"); - - assert!( - overlay - .lstat("/alias-renamed.txt") - .expect("lstat renamed symlink") - .is_symbolic_link - ); - assert_eq!( - overlay - .read_link("/alias-renamed.txt") - .expect("read renamed symlink target"), - String::from("/target.txt") - ); - assert_error_code(overlay.read_link("/alias.txt"), "ENOENT"); -} - -#[test] -fn overlay_remove_dir_rejects_lower_only_children_in_merged_view() { - let mut lower = MemoryFileSystem::new(); - lower - .mkdir("/tmp/nonempty", true) - .expect("create lower directory"); - lower - .write_file("/tmp/nonempty/child.txt", b"child".to_vec()) - .expect("seed lower child"); - - let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); - assert_error_code(overlay.remove_dir("/tmp/nonempty"), "ENOTEMPTY"); - assert!(overlay.exists("/tmp/nonempty/child.txt")); -} - -#[test] -fn overlay_remove_dir_rejects_lower_children_after_directory_copy_up() { - let mut lower = MemoryFileSystem::new(); - lower - .mkdir("/tmp/nonempty", true) - .expect("create lower directory"); - lower - .write_file("/tmp/nonempty/child.txt", b"child".to_vec()) - .expect("seed lower child"); - - let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); - overlay - .chmod("/tmp/nonempty", 0o700) - .expect("copy up lower directory"); - - assert_error_code(overlay.remove_dir("/tmp/nonempty"), "ENOTEMPTY"); - assert!(overlay.exists("/tmp/nonempty/child.txt")); -} - -#[test] -fn overlay_rename_rejects_directory_trees_that_exceed_snapshot_depth_limit() { - let lower = deep_directory_tree(1025); - let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); - assert_error_code(overlay.rename("/deep", "/renamed"), "EINVAL"); -} - -#[test] -fn overlay_link_and_rename_preserve_upper_hardlinks_after_copy_up() { - let mut lower = MemoryFileSystem::new(); - lower - .write_file("/src.txt", b"base".to_vec()) - .expect("seed lower file"); - - let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); - overlay - .link("/src.txt", "/alias.txt") - .expect("hardlink copied-up file"); - - overlay - .write_file("/alias.txt", b"mutated".to_vec()) - .expect("mutate linked file"); - assert_eq!( - overlay.read_file("/src.txt").expect("read linked source"), - b"mutated".to_vec() - ); - - overlay - .rename("/src.txt", "/renamed.txt") - .expect("rename hardlinked source"); - - let alias_stat = overlay.stat("/alias.txt").expect("stat alias"); - let renamed_stat = overlay.stat("/renamed.txt").expect("stat renamed"); - assert_eq!(alias_stat.ino, renamed_stat.ino); - assert_eq!(alias_stat.nlink, 2); - assert_eq!(renamed_stat.nlink, 2); - assert_eq!( - overlay.read_file("/alias.txt").expect("read alias"), - b"mutated".to_vec() - ); - assert_eq!( - overlay.read_file("/renamed.txt").expect("read renamed"), - b"mutated".to_vec() - ); - assert_error_code(overlay.read_file("/src.txt"), "ENOENT"); -} - -#[test] -fn root_filesystem_uses_bundled_base_and_round_trips_snapshots() { - let mut root = RootFileSystem::from_descriptor(RootFilesystemDescriptor::default()) - .expect("create default root"); - - assert!(root.exists("/etc/os-release")); - let os_release = root - .lstat("/etc/os-release") - .expect("lstat /etc/os-release"); - assert!(os_release.is_symbolic_link); - assert_eq!(os_release.uid, 0); - assert_eq!(os_release.gid, 0); - - root.mkdir("/workspace", true).expect("create workspace"); - root.write_file("/workspace/run.sh", b"echo hi".to_vec()) - .expect("write bootstrapped file"); - - let snapshot = root.snapshot().expect("snapshot root"); - let encoded = encode_snapshot(&snapshot).expect("encode root snapshot"); - let encoded_json: serde_json::Value = - serde_json::from_slice(&encoded).expect("parse encoded snapshot"); - assert_eq!( - encoded_json["format"], - serde_json::json!(ROOT_FILESYSTEM_SNAPSHOT_FORMAT) - ); - let decoded = decode_snapshot(&encoded).expect("decode root snapshot"); - - assert!(decoded - .entries - .iter() - .any(|entry| entry.path == "/etc/os-release")); - assert!(decoded - .entries - .iter() - .any(|entry| entry.path == "/workspace/run.sh")); -} - -#[test] -fn higher_lowers_do_not_shadow_base_parent_directories_with_default_ownership() { - let mut root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/etc/agentos"), - FilesystemEntry::file("/bin/node", b"stub".to_vec()), - ], - }], - bootstrap_entries: vec![], - }) - .expect("create root"); - - let bin = root.stat("/bin").expect("stat /bin"); - let etc = root.stat("/etc").expect("stat /etc"); - - assert_eq!(bin.uid, 0); - assert_eq!(bin.gid, 0); - assert_eq!(etc.uid, 0); - assert_eq!(etc.gid, 0); -} - -#[test] -fn root_filesystem_composes_multiple_lowers_before_bootstrap_upper() { - let mut root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![ - RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/workspace"), - FilesystemEntry::file("/workspace/shared.txt", b"higher".to_vec()), - FilesystemEntry::file("/workspace/higher-only.txt", b"higher-only".to_vec()), - ], - }, - RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/workspace"), - FilesystemEntry::file("/workspace/shared.txt", b"lower".to_vec()), - FilesystemEntry::file("/workspace/lower-only.txt", b"lower-only".to_vec()), - ], - }, - ], - bootstrap_entries: vec![ - FilesystemEntry::directory("/workspace"), - FilesystemEntry::file("/workspace/shared.txt", b"upper".to_vec()), - FilesystemEntry::file("/workspace/upper-only.txt", b"upper-only".to_vec()), - ], - }) - .expect("create multi-layer root"); - - assert_eq!( - root.read_file("/workspace/shared.txt") - .expect("read upper override"), - b"upper".to_vec() - ); - assert_eq!( - root.read_file("/workspace/higher-only.txt") - .expect("read higher-only file"), - b"higher-only".to_vec() - ); - assert_eq!( - root.read_file("/workspace/lower-only.txt") - .expect("read lower-only file"), - b"lower-only".to_vec() - ); - assert_eq!( - root.read_file("/workspace/upper-only.txt") - .expect("read upper-only file"), - b"upper-only".to_vec() - ); -} - -#[test] -fn root_filesystem_bootstrap_suppresses_kernel_reserved_paths() { - let mut root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![FilesystemEntry::directory("/workspace")], - }], - bootstrap_entries: vec![ - FilesystemEntry::directory("/dev/custom"), - FilesystemEntry::file("/dev/null", b"not-a-device".to_vec()), - FilesystemEntry::file("/proc/mounts", b"fake mounts".to_vec()), - FilesystemEntry::file("/sys/kernel/info", b"blocked".to_vec()), - FilesystemEntry::file("/workspace/allowed.txt", b"allowed".to_vec()), - ], - }) - .expect("create root with reserved bootstrap paths"); - - assert!(!root.exists("/dev/custom")); - assert!(!root.exists("/dev/null")); - assert!(!root.exists("/proc/mounts")); - assert!(!root.exists("/sys/kernel/info")); - assert_eq!( - root.read_file("/workspace/allowed.txt") - .expect("read allowed bootstrap file"), - b"allowed".to_vec() - ); - - let snapshot = root.snapshot().expect("snapshot root"); - assert!(snapshot - .entries - .iter() - .all(|entry| !entry.path.starts_with("/dev/"))); - assert!(snapshot - .entries - .iter() - .all(|entry| !entry.path.starts_with("/proc/"))); - assert!(snapshot - .entries - .iter() - .all(|entry| !entry.path.starts_with("/sys/"))); - assert!(snapshot - .entries - .iter() - .any(|entry| entry.path == "/workspace/allowed.txt")); -} - -#[test] -fn snapshot_round_trip_preserves_file_type_bits_in_modes() { - let mut root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![FilesystemEntry::directory("/workspace")], - }], - bootstrap_entries: vec![], - }) - .expect("create root"); - - root.write_file("/workspace/file.txt", b"hello".to_vec()) - .expect("write file"); - root.mkdir("/workspace/subdir", false) - .expect("create directory"); - root.symlink("/workspace/file.txt", "/workspace/link.txt") - .expect("create symlink"); - - let decoded = decode_snapshot( - &encode_snapshot(&root.snapshot().expect("snapshot root")).expect("encode snapshot"), - ) - .expect("decode snapshot"); - - let file_entry = decoded - .entries - .iter() - .find(|entry| entry.path == "/workspace/file.txt") - .expect("file entry"); - assert_eq!(file_entry.mode & 0o170000, S_IFREG); - - let directory_entry = decoded - .entries - .iter() - .find(|entry| entry.path == "/workspace/subdir") - .expect("directory entry"); - assert_eq!(directory_entry.mode & 0o170000, S_IFDIR); - - let symlink_entry = decoded - .entries - .iter() - .find(|entry| entry.path == "/workspace/link.txt") - .expect("symlink entry"); - assert_eq!(symlink_entry.mode & 0o170000, S_IFLNK); -} - -#[test] -fn decode_snapshot_accepts_zero_mode_strings() { - let decoded = decode_snapshot( - br#"{ - "format": "secure_exec_filesystem_snapshot_v1", - "filesystem": { - "entries": [ - { - "path": "/zero.txt", - "type": "file", - "mode": "0", - "uid": 0, - "gid": 0, - "content": "", - "encoding": "utf8" - }, - { - "path": "/zero-dir", - "type": "directory", - "mode": "0000", - "uid": 0, - "gid": 0 - } - ] - } - }"#, - ) - .expect("decode snapshot"); - - let zero_file = decoded - .entries - .iter() - .find(|entry| entry.path == "/zero.txt") - .expect("zero file entry"); - assert_eq!(zero_file.mode, 0); - - let zero_dir = decoded - .entries - .iter() - .find(|entry| entry.path == "/zero-dir") - .expect("zero dir entry"); - assert_eq!(zero_dir.mode, 0); -} - -#[test] -fn decode_snapshot_accepts_legacy_agentos_format() { - let decoded = decode_snapshot( - br#"{ - "format": "agentos_filesystem_snapshot_v1", - "filesystem": { - "entries": [ - { - "path": "/legacy.txt", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "legacy", - "encoding": "utf8" - } - ] - } - }"#, - ) - .expect("decode legacy snapshot"); - - assert!(decoded - .entries - .iter() - .any(|entry| entry.path == "/legacy.txt")); -} - -#[test] -fn decode_snapshot_rejects_encoded_payloads_that_exceed_import_limits() { - let limits = RootFilesystemImportLimits { - max_encoded_snapshot_bytes: Some(16), - max_filesystem_bytes: Some(1024), - max_inode_count: Some(16), - }; - - let error = decode_snapshot_with_import_limits( - br#"{ - "format": "secure_exec_filesystem_snapshot_v1", - "filesystem": { "entries": [] } - }"#, - &limits, - ) - .expect_err("oversized encoded snapshot should be rejected"); - - assert!(error.to_string().contains("encoded bytes")); -} - -#[test] -fn decode_snapshot_rejects_entry_counts_that_exceed_import_limits() { - let limits = RootFilesystemImportLimits { - max_encoded_snapshot_bytes: Some(4096), - max_filesystem_bytes: Some(1024), - max_inode_count: Some(1), - }; - - let error = decode_snapshot_with_import_limits( - br#"{ - "format": "secure_exec_filesystem_snapshot_v1", - "filesystem": { - "entries": [ - { - "path": "/one", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - }, - { - "path": "/two", - "type": "directory", - "mode": "755", - "uid": 0, - "gid": 0 - } - ] - } - }"#, - &limits, - ) - .expect_err("snapshot entry count should be rejected"); - - assert!(error.to_string().contains("exceeding limit 1")); -} - -#[test] -fn decode_snapshot_rejects_content_bytes_that_exceed_import_limits() { - let limits = RootFilesystemImportLimits { - max_encoded_snapshot_bytes: Some(4096), - max_filesystem_bytes: Some(3), - max_inode_count: Some(16), - }; - - let error = decode_snapshot_with_import_limits( - br#"{ - "format": "secure_exec_filesystem_snapshot_v1", - "filesystem": { - "entries": [ - { - "path": "/large.txt", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0, - "content": "four", - "encoding": "utf8" - } - ] - } - }"#, - &limits, - ) - .expect_err("snapshot content bytes should be rejected"); - - assert!(error.to_string().contains("exceeding limit 3")); -} - -#[test] -fn decode_snapshot_allows_metadata_heavy_entries_within_import_limits() { - let path = format!("/{}", "a".repeat(4000)); - let snapshot = format!( - r#"{{ - "format": "secure_exec_filesystem_snapshot_v1", - "filesystem": {{ - "entries": [ - {{ - "path": "{path}", - "type": "file", - "mode": "644", - "uid": 0, - "gid": 0 - }} - ] - }} - }}"# - ); - let limits = RootFilesystemImportLimits::from_resource_limits(&TestResourceLimits { - max_filesystem_bytes: Some(0), - max_inode_count: Some(1), - }); - - let decoded = decode_snapshot_with_import_limits(snapshot.as_bytes(), &limits) - .expect("metadata-heavy empty file should fit decoded byte and inode limits"); - - assert_eq!(decoded.entries.len(), 1); - assert_eq!(decoded.entries[0].path, path); -} - -#[test] -fn root_filesystem_rejects_descriptor_snapshots_that_exceed_import_limits() { - let limits = RootFilesystemImportLimits { - max_encoded_snapshot_bytes: Some(4096), - max_filesystem_bytes: Some(3), - max_inode_count: Some(16), - }; - - let error = RootFileSystem::from_descriptor_with_import_limits( - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::directory("/workspace"), - FilesystemEntry::file("/workspace/large.txt", b"four".to_vec()), - ], - }], - bootstrap_entries: Vec::new(), - }, - &limits, - ) - .expect_err("descriptor snapshot content bytes should be rejected"); - - assert!(error.to_string().contains("exceeding limit 3")); -} - -#[test] -fn root_filesystem_rejects_implicit_parent_directories_that_exceed_import_limits() { - let limits = RootFilesystemImportLimits { - max_encoded_snapshot_bytes: Some(4096), - max_filesystem_bytes: Some(16), - max_inode_count: Some(1), - }; - - let error = RootFileSystem::from_descriptor_with_import_limits( - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![FilesystemEntry::file( - "/deep/nested/file.txt", - b"x".to_vec(), - )], - }], - bootstrap_entries: Vec::new(), - }, - &limits, - ) - .expect_err("implicit parent directories should count against inode limits"); - - assert!(error.to_string().contains("exceeding limit 1")); -} - -#[test] -fn root_filesystem_rejects_duplicate_descriptor_entries_that_exceed_import_limits() { - let limits = RootFilesystemImportLimits { - max_encoded_snapshot_bytes: Some(4096), - max_filesystem_bytes: Some(16), - max_inode_count: Some(1), - }; - - let error = RootFileSystem::from_descriptor_with_import_limits( - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![ - FilesystemEntry::file("/dup.txt", Vec::new()), - FilesystemEntry::file("/dup.txt", Vec::new()), - ], - }], - bootstrap_entries: Vec::new(), - }, - &limits, - ) - .expect_err("duplicate descriptor entries should count against import limits"); - - assert!(error.to_string().contains("exceeding limit 1")); -} - -#[test] -fn root_filesystem_normalizes_import_paths_before_creating_parent_directories() { - let limits = RootFilesystemImportLimits { - max_encoded_snapshot_bytes: Some(4096), - max_filesystem_bytes: Some(16), - max_inode_count: Some(2), - }; - - let mut root = RootFileSystem::from_descriptor_with_import_limits( - RootFilesystemDescriptor { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![FilesystemEntry::file("/a/../b/file.txt", b"x".to_vec())], - }], - bootstrap_entries: Vec::new(), - }, - &limits, - ) - .expect("normalized import path should fit inode limit"); - - assert!(!root.exists("/a")); - assert!(root.exists("/b")); - assert_eq!( - root.read_file("/b/file.txt") - .expect("read normalized import file"), - b"x".to_vec() - ); -} - -#[test] -fn read_only_root_locks_after_bootstrap_but_preserves_boot_entries() { - let mut root = RootFileSystem::from_descriptor(RootFilesystemDescriptor { - mode: RootFilesystemMode::ReadOnly, - disable_default_base_layer: true, - lowers: vec![RootFilesystemSnapshot { - entries: vec![FilesystemEntry::directory("/workspace")], - }], - bootstrap_entries: vec![FilesystemEntry::file( - "/workspace/boot.txt", - b"ready".to_vec(), - )], - }) - .expect("create read-only root"); - - root.finish_bootstrap(); - - assert_eq!( - root.read_file("/workspace/boot.txt") - .expect("read preserved boot entry"), - b"ready".to_vec() - ); - assert_eq!( - root.mkdir("/workspace", true) - .expect("mkdir -p existing directory on readonly root"), - () - ); - let error = root - .write_file("/workspace/blocked.txt", b"blocked".to_vec()) - .expect_err("readonly root should reject new writes"); - assert_eq!(error.code(), "EROFS"); -} diff --git a/crates/vfs/tests/posix_single_symlink_fs.rs b/crates/vfs/tests/posix_single_symlink_fs.rs deleted file mode 100644 index e9b29581c..000000000 --- a/crates/vfs/tests/posix_single_symlink_fs.rs +++ /dev/null @@ -1,20 +0,0 @@ -use vfs::posix::{SingleSymlinkFileSystem, VirtualFileSystem}; - -#[test] -fn single_symlink_filesystem_exposes_root_symlink_only() { - let fs = SingleSymlinkFileSystem::new("../pkgs/pi/current/bin/pi"); - - let stat = fs.lstat("/").expect("lstat root symlink"); - assert!(stat.is_symbolic_link); - assert!(!stat.is_directory); - assert_eq!(stat.mode & 0o777, 0o777); - assert_eq!( - fs.read_link("/").expect("read root symlink target"), - "../pkgs/pi/current/bin/pi" - ); - - let error = fs - .lstat("/anything") - .expect_err("non-root paths do not exist"); - assert_eq!(error.code(), "ENOENT"); -} diff --git a/crates/vfs/tests/posix_tar_fs.rs b/crates/vfs/tests/posix_tar_fs.rs deleted file mode 100644 index a6bd16fbb..000000000 --- a/crates/vfs/tests/posix_tar_fs.rs +++ /dev/null @@ -1,131 +0,0 @@ -#![cfg(not(target_arch = "wasm32"))] - -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; -use std::time::{SystemTime, UNIX_EPOCH}; -use tar::{Builder, EntryType, Header}; -use vfs::posix::{TarFileSystem, VirtualFileSystem}; - -#[test] -fn tar_filesystem_reads_files_dirs_symlinks_and_realpaths() { - let tar_path = write_fixture_tar(); - let mut fs = TarFileSystem::open(&tar_path, "fixture-digest").expect("open tar filesystem"); - - assert_eq!( - fs.read_file("/pkg/bin/pi").expect("read file"), - b"#!/bin/sh\necho pi\n".to_vec() - ); - - let root_entries = fs.read_dir("/pkg").expect("read package dir"); - assert!(root_entries.contains(&String::from("bin"))); - assert!(root_entries.contains(&String::from("lib"))); - - let typed_entries = fs - .read_dir_with_types("/pkg/lib") - .expect("read typed package dir"); - assert!(typed_entries - .iter() - .any(|entry| entry.name == "target.txt" && !entry.is_directory)); - assert!(typed_entries - .iter() - .any(|entry| entry.name == "target-link.txt" && entry.is_symbolic_link)); - - assert_eq!( - fs.read_link("/pkg/lib/target-link.txt") - .expect("read symlink"), - "target.txt" - ); - assert_eq!( - fs.realpath("/pkg/lib/target-link.txt") - .expect("resolve symlink"), - "/pkg/lib/target.txt" - ); - assert_eq!( - fs.read_file("/pkg/lib/target-link.txt") - .expect("read through symlink"), - b"target\n".to_vec() - ); - - let stat = fs.stat("/pkg/bin/pi").expect("stat executable"); - assert_eq!(stat.mode & 0o777, 0o755); - assert!(fs.exists("/pkg/lib/target.txt")); - assert!(!fs.exists("/pkg/missing")); -} - -#[test] -fn tar_filesystem_rejects_writes_as_read_only() { - let tar_path = write_fixture_tar(); - let mut fs = TarFileSystem::open(&tar_path, "fixture-readonly").expect("open tar filesystem"); - - let error = fs - .write_file("/pkg/new.txt", b"nope".to_vec()) - .expect_err("tar filesystem is read-only"); - assert_eq!(error.code(), "EROFS"); -} - -fn write_fixture_tar() -> PathBuf { - let mut path = std::env::temp_dir(); - let nonce = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("clock") - .as_nanos(); - path.push(format!("secure-exec-tar-fs-fixture-{nonce}.tar")); - - let file = File::create(&path).expect("create fixture tar"); - let mut builder = Builder::new(file); - append_dir(&mut builder, "pkg"); - append_dir(&mut builder, "pkg/bin"); - append_file(&mut builder, "pkg/bin/pi", b"#!/bin/sh\necho pi\n", 0o755); - append_dir(&mut builder, "pkg/lib"); - append_file(&mut builder, "pkg/lib/target.txt", b"target\n", 0o644); - append_symlink(&mut builder, "pkg/lib/target-link.txt", "target.txt"); - builder.finish().expect("finish fixture tar"); - builder - .into_inner() - .expect("finish file") - .flush() - .expect("flush tar"); - - path -} - -fn append_dir(builder: &mut Builder, path: &str) { - let mut header = Header::new_gnu(); - header.set_entry_type(EntryType::Directory); - header.set_mode(0o755); - header.set_uid(0); - header.set_gid(0); - header.set_size(0); - header.set_cksum(); - builder - .append_data(&mut header, path, std::io::empty()) - .expect("append directory"); -} - -fn append_file(builder: &mut Builder, path: &str, content: &[u8], mode: u32) { - let mut header = Header::new_gnu(); - header.set_entry_type(EntryType::Regular); - header.set_mode(mode); - header.set_uid(0); - header.set_gid(0); - header.set_size(content.len() as u64); - header.set_cksum(); - builder - .append_data(&mut header, path, content) - .expect("append file"); -} - -fn append_symlink(builder: &mut Builder, path: &str, target: &str) { - let mut header = Header::new_gnu(); - header.set_entry_type(EntryType::Symlink); - header.set_mode(0o777); - header.set_uid(0); - header.set_gid(0); - header.set_size(0); - header.set_link_name(target).expect("set link target"); - header.set_cksum(); - builder - .append_data(&mut header, path, std::io::empty()) - .expect("append symlink"); -} diff --git a/crates/vfs/tests/posix_vfs.rs b/crates/vfs/tests/posix_vfs.rs deleted file mode 100644 index d5a431951..000000000 --- a/crates/vfs/tests/posix_vfs.rs +++ /dev/null @@ -1,610 +0,0 @@ -use std::{fmt::Debug, thread::sleep, time::Duration}; -use vfs::posix::{ - normalize_path, validate_path, MemoryFileSystem, VfsResult, VirtualFileSystem, S_IFLNK, S_IFREG, -}; - -fn assert_error_code(result: vfs::posix::VfsResult, expected: &str) { - let error = result.expect_err("operation should fail"); - assert_eq!(error.code(), expected); -} - -fn assert_invalid_path_keeps_snapshot( - baseline: &MemoryFileSystem, - path: &str, - operation: impl FnOnce(&mut MemoryFileSystem, &str) -> VfsResult, -) { - let mut filesystem = MemoryFileSystem::from_snapshot(baseline.snapshot()); - let before = filesystem.snapshot(); - assert_error_code(operation(&mut filesystem, path), "EINVAL"); - assert_eq!(filesystem.snapshot(), before); -} - -fn generated_invalid_path(seed: u32) -> String { - let mut path = String::from("/"); - let segments = (seed % 4) + 1; - for segment in 0..segments { - if segment > 0 { - path.push('/'); - } - path.push(char::from(b'a' + ((seed + segment) % 26) as u8)); - let invalid_byte = if seed.is_multiple_of(2) { - 0 - } else if seed.is_multiple_of(5) { - 0x7f - } else { - 1 + ((seed + segment) % 31) as u8 - }; - path.push(char::from(invalid_byte)); - path.push(char::from(b'a' + (((seed / 3) + segment) % 26) as u8)); - } - path -} - -#[test] -fn write_file_normalizes_paths_and_auto_creates_parents() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .write_file("workspace//nested/../nested/hello.txt", "hello world") - .expect("write file"); - - assert!(filesystem.exists("/workspace/nested/hello.txt")); - assert_eq!( - filesystem - .read_text_file("/workspace/nested/hello.txt") - .expect("read text"), - "hello world" - ); - assert_eq!( - normalize_path("/workspace//nested/../nested/hello.txt"), - "/workspace/nested/hello.txt" - ); -} - -#[test] -fn mkdir_and_remove_dir_enforce_parent_and_emptiness_rules() { - let mut filesystem = MemoryFileSystem::new(); - - assert_error_code(filesystem.create_dir("/missing/child"), "ENOENT"); - - filesystem - .mkdir("/tmp/deep/tree", true) - .expect("recursive mkdir"); - filesystem - .remove_dir("/tmp/deep/tree") - .expect("remove empty dir"); - assert!(!filesystem.exists("/tmp/deep/tree")); - - filesystem - .write_file("/tmp/nonempty/file.txt", "x") - .expect("write child"); - assert_error_code(filesystem.remove_dir("/tmp/nonempty"), "ENOTEMPTY"); -} - -#[test] -fn rename_moves_directory_trees_without_losing_children() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .write_file("/src/sub/one.txt", "1") - .expect("write first child"); - filesystem - .write_file("/src/sub/two.txt", "2") - .expect("write second child"); - - filesystem.rename("/src", "/dst").expect("rename tree"); - - assert!(!filesystem.exists("/src")); - assert_eq!( - filesystem - .read_text_file("/dst/sub/one.txt") - .expect("read renamed child"), - "1" - ); - assert_eq!( - filesystem - .read_text_file("/dst/sub/two.txt") - .expect("read renamed second child"), - "2" - ); -} - -#[test] -fn symlinks_support_readlink_lstat_realpath_and_dangling_targets() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .write_file("/real/target.txt", "target") - .expect("write target"); - filesystem - .symlink("../real/target.txt", "/alias.txt") - .expect("create symlink"); - - assert_eq!( - filesystem.read_link("/alias.txt").expect("read link"), - "../real/target.txt" - ); - assert_eq!( - filesystem.realpath("/alias.txt").expect("realpath"), - "/real/target.txt" - ); - assert_eq!( - filesystem - .read_text_file("/alias.txt") - .expect("read through symlink"), - "target" - ); - - let link_stat = filesystem.lstat("/alias.txt").expect("lstat symlink"); - assert!(link_stat.is_symbolic_link); - assert!(!link_stat.is_directory); - assert_eq!(link_stat.mode & 0o170000, S_IFLNK); - - let target_stat = filesystem.stat("/alias.txt").expect("stat symlink target"); - assert!(!target_stat.is_symbolic_link); - assert_eq!(target_stat.mode & 0o170000, S_IFREG); - - filesystem - .symlink("/missing.txt", "/dangling.txt") - .expect("create dangling symlink"); - let dangling = filesystem.lstat("/dangling.txt").expect("lstat dangling"); - assert!(dangling.is_symbolic_link); - assert_error_code(filesystem.stat("/dangling.txt"), "ENOENT"); - assert_error_code(filesystem.read_file("/dangling.txt"), "ENOENT"); -} - -#[test] -fn readlink_on_regular_file_returns_einval() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .write_file("/regular.txt", "content") - .expect("write regular file"); - - assert_error_code(filesystem.read_link("/regular.txt"), "EINVAL"); -} - -#[test] -fn symlink_loops_fail_closed() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .symlink("/loop-b.txt", "/loop-a.txt") - .expect("create first loop entry"); - filesystem - .symlink("/loop-a.txt", "/loop-b.txt") - .expect("create second loop entry"); - - assert_error_code(filesystem.read_file("/loop-a.txt"), "ELOOP"); -} - -#[test] -fn path_validation_rejects_nul_and_control_bytes_without_mutating_filesystem() { - let mut baseline = MemoryFileSystem::new(); - baseline - .write_file("/safe/file.txt", "safe contents") - .expect("seed file"); - baseline - .write_file("/safe/source.txt", "source") - .expect("seed link source"); - baseline - .symlink("/safe/file.txt", "/safe/link.txt") - .expect("seed symlink"); - baseline - .create_dir("/safe/empty") - .expect("seed removable dir"); - - let invalid_paths = ["/bad\0path", "/bad\npath", "/bad\x7fpath"]; - - for invalid_path in invalid_paths { - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| fs.read_file(path)); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| fs.read_dir(path)); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.read_dir_with_types(path) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| fs.stat(path)); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| fs.realpath(path)); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| fs.read_link(path)); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| fs.lstat(path)); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.write_file(path, "x") - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.create_file_exclusive(path, "x") - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.append_file(path, "x") - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| fs.create_dir(path)); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.mkdir(path, true) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.remove_file(path) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| fs.remove_dir(path)); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.rename(path, "/safe/renamed.txt") - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.rename("/safe/file.txt", path) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.symlink("/safe/file.txt", path) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.link(path, "/safe/linked.txt") - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.link("/safe/source.txt", path) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.chmod(path, 0o600) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.chown(path, 1000, 1000) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.utimes(path, 1_000, 2_000) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.truncate(path, 1) - }); - assert_invalid_path_keeps_snapshot(&baseline, invalid_path, |fs, path| { - fs.pread(path, 0, 1) - }); - } -} - -#[test] -fn validate_path_rejects_generated_invalid_inputs() { - for seed in 0..1_000u32 { - let invalid_path = generated_invalid_path(seed); - assert!( - invalid_path - .bytes() - .any(|byte| byte == 0 || byte.is_ascii_control()), - "generated path should contain at least one prohibited byte" - ); - assert_error_code(validate_path(&invalid_path), "EINVAL"); - } -} - -#[test] -fn intermediate_symlink_components_are_resolved_for_reads_writes_and_stats() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .write_file("/b/existing/file.txt", "target") - .expect("write canonical file"); - filesystem - .symlink("/b", "/a") - .expect("create directory symlink"); - - assert_eq!( - filesystem - .read_text_file("/a/existing/file.txt") - .expect("read through intermediate symlink"), - "target" - ); - assert!(filesystem.exists("/a/existing/file.txt")); - assert_eq!( - filesystem - .realpath("/a/existing/file.txt") - .expect("realpath through intermediate symlink"), - "/b/existing/file.txt" - ); - assert_eq!( - filesystem - .stat("/a/existing/file.txt") - .expect("stat through intermediate symlink") - .mode - & 0o170000, - S_IFREG - ); - - filesystem - .write_file("/a/new/nested.txt", "created through alias") - .expect("write through symlinked parent"); - assert_eq!( - filesystem - .read_text_file("/b/new/nested.txt") - .expect("read canonical created file"), - "created through alias" - ); -} - -#[test] -fn intermediate_symlink_loops_fail_closed() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .symlink("/b", "/a") - .expect("create first loop entry"); - filesystem - .symlink("/a", "/b") - .expect("create second loop entry"); - - assert_error_code(filesystem.read_file("/a/file.txt"), "ELOOP"); -} - -#[test] -fn hard_links_share_inode_data_and_survive_original_removal() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .write_file("/shared.txt", "hello") - .expect("write shared file"); - filesystem - .link("/shared.txt", "/linked.txt") - .expect("create hard link"); - - let before = filesystem.stat("/shared.txt").expect("stat original"); - assert_eq!(before.nlink, 2); - - filesystem - .write_file("/linked.txt", "updated") - .expect("write through linked path"); - assert_eq!( - filesystem - .read_text_file("/shared.txt") - .expect("read shared inode"), - "updated" - ); - - filesystem - .remove_file("/shared.txt") - .expect("remove original name"); - assert!(!filesystem.exists("/shared.txt")); - assert_eq!( - filesystem - .read_text_file("/linked.txt") - .expect("read surviving link"), - "updated" - ); - assert_eq!( - filesystem - .stat("/linked.txt") - .expect("stat surviving link") - .nlink, - 1 - ); -} - -#[test] -fn chmod_chown_utimes_truncate_and_pread_update_metadata_and_contents() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .write_file("/meta.txt", "hello") - .expect("write metadata file"); - filesystem - .truncate("/meta.txt", 8) - .expect("truncate metadata file"); - filesystem - .chmod("/meta.txt", 0o755) - .expect("chmod metadata file"); - filesystem - .chown("/meta.txt", 2000, 3000) - .expect("chown metadata file"); - filesystem - .utimes("/meta.txt", 1_700_000_000_000, 1_710_000_000_000) - .expect("utimes metadata file"); - - let stat = filesystem.stat("/meta.txt").expect("stat metadata file"); - assert_eq!(stat.mode & 0o170000, S_IFREG); - assert_eq!(stat.mode & 0o777, 0o755); - assert_eq!(stat.uid, 2000); - assert_eq!(stat.gid, 3000); - assert_eq!(stat.atime_ms, 1_700_000_000_000); - assert_eq!(stat.mtime_ms, 1_710_000_000_000); - assert_eq!(stat.size, 8); - assert_eq!(stat.blocks, 1); - // Device ids are unique per filesystem instance, so only assert that the - // value is stable within this filesystem. - assert_ne!(stat.dev, 0); - assert_eq!( - stat.dev, - filesystem.stat("/").expect("stat root").dev, - "files in one filesystem instance share its device id" - ); - assert_eq!(stat.rdev, 0); - - let bytes = filesystem - .read_file("/meta.txt") - .expect("read truncated file"); - assert_eq!(&bytes[..5], b"hello"); - assert_eq!(&bytes[5..], &[0, 0, 0]); - - assert_eq!( - filesystem - .pread("/meta.txt", 2, 4) - .expect("pread middle slice"), - b"llo\0".to_vec() - ); - assert!(filesystem - .pread("/meta.txt", 100, 4) - .expect("pread beyond eof") - .is_empty()); -} - -#[test] -fn oversized_raw_truncate_and_pwrite_fail_without_mutating_file_contents() { - let mut filesystem = MemoryFileSystem::new(); - filesystem - .write_file("/huge.txt", b"safe".to_vec()) - .expect("seed file"); - - assert_error_code(filesystem.truncate("/huge.txt", u64::MAX), "ENOMEM"); - assert_eq!( - filesystem - .read_file("/huge.txt") - .expect("read after failed truncate"), - b"safe".to_vec() - ); - - assert_error_code( - filesystem.pwrite("/huge.txt", b"x".to_vec(), u64::MAX), - "ENOMEM", - ); - assert_eq!( - filesystem - .read_file("/huge.txt") - .expect("read after failed pwrite"), - b"safe".to_vec() - ); -} - -#[test] -fn directory_reads_and_metadata_updates_refresh_timestamps() { - let mut filesystem = MemoryFileSystem::new(); - filesystem - .write_file("/workspace/file.txt", "hello") - .expect("seed file"); - - let before_dir_read = filesystem.stat("/workspace").expect("stat workspace"); - sleep(Duration::from_millis(2)); - filesystem - .read_dir("/workspace") - .expect("read workspace directory"); - let after_dir_read = filesystem.stat("/workspace").expect("restat workspace"); - assert!( - after_dir_read.atime_ms > before_dir_read.atime_ms, - "directory atime should advance after read_dir" - ); - - let before_link = filesystem.stat("/workspace/file.txt").expect("stat file"); - sleep(Duration::from_millis(2)); - filesystem - .link("/workspace/file.txt", "/workspace/file-link.txt") - .expect("create hard link"); - let after_link = filesystem.stat("/workspace/file.txt").expect("restat file"); - assert!( - after_link.ctime_ms > before_link.ctime_ms, - "ctime should advance when link count changes" - ); - - let before_rename = after_link.ctime_ms; - sleep(Duration::from_millis(2)); - filesystem - .rename("/workspace/file-link.txt", "/workspace/file-renamed.txt") - .expect("rename linked path"); - let renamed = filesystem - .stat("/workspace/file-renamed.txt") - .expect("stat renamed path"); - assert!( - renamed.ctime_ms > before_rename, - "ctime should advance on rename" - ); -} - -#[test] -fn read_dir_with_types_reports_direct_children() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .write_file("/typed/file.txt", "f") - .expect("write file child"); - filesystem - .write_file("/typed/sub/nested.txt", "n") - .expect("write nested child"); - filesystem - .symlink("/typed/file.txt", "/typed/link.txt") - .expect("write symlink child"); - - let entries = filesystem - .read_dir_with_types("/typed") - .expect("read typed directory"); - - let names: Vec<_> = entries.iter().map(|entry| entry.name.as_str()).collect(); - assert_eq!(names, vec!["file.txt", "link.txt", "sub"]); - - let sub = entries - .iter() - .find(|entry| entry.name == "sub") - .expect("sub directory should be present"); - assert!(sub.is_directory); - assert!(!sub.is_symbolic_link); - - let link = entries - .iter() - .find(|entry| entry.name == "link.txt") - .expect("symlink should be present"); - assert!(!link.is_directory); - assert!(link.is_symbolic_link); -} - -#[test] -fn memory_filesystem_snapshot_round_trips_hardlinks_and_symlinks() { - let mut filesystem = MemoryFileSystem::new(); - - filesystem - .write_file("/workspace/original.txt", "hello") - .expect("write original"); - filesystem - .link("/workspace/original.txt", "/workspace/linked.txt") - .expect("create hard link"); - filesystem - .symlink("/workspace/original.txt", "/workspace/alias.txt") - .expect("create symlink"); - - let snapshot = filesystem.snapshot(); - let mut restored = MemoryFileSystem::from_snapshot(snapshot); - - assert_eq!( - restored - .read_text_file("/workspace/linked.txt") - .expect("read hard-linked file"), - "hello" - ); - assert_eq!( - restored - .read_text_file("/workspace/alias.txt") - .expect("read symlink target"), - "hello" - ); - - restored - .write_file("/workspace/linked.txt", "updated") - .expect("write through hard link"); - assert_eq!( - restored - .read_text_file("/workspace/original.txt") - .expect("hard link should share inode"), - "updated" - ); - assert_eq!( - restored - .stat("/workspace/original.txt") - .expect("stat restored hard link") - .nlink, - 2 - ); -} - -#[test] -fn memory_filesystem_instances_have_distinct_device_ids() { - let mut first = MemoryFileSystem::new(); - let mut second = MemoryFileSystem::new(); - first - .write_file("/file.txt", "first") - .expect("write file in first filesystem"); - second - .write_file("/file.txt", "second") - .expect("write file in second filesystem"); - - let first_stat = first.stat("/file.txt").expect("stat first file"); - let second_stat = second.stat("/file.txt").expect("stat second file"); - - // Inode numbers are only unique within one filesystem instance, so file - // identity comparisons across layered or mounted compositions need - // per-instance device ids. - assert_eq!(first_stat.ino, second_stat.ino); - assert_ne!(first_stat.dev, second_stat.dev); - - let restored = MemoryFileSystem::from_snapshot(first.snapshot()); - assert_ne!( - restored.lstat("/file.txt").expect("stat restored file").dev, - second_stat.dev - ); -} diff --git a/crates/vm-config/Cargo.toml b/crates/vm-config/Cargo.toml index 5f0bc93c1..344010bec 100644 --- a/crates/vm-config/Cargo.toml +++ b/crates/vm-config/Cargo.toml @@ -4,9 +4,10 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Shared Secure Exec VM creation JSON config DTOs" +description = "secure-exec-vm-config compatibility shim for agentos-vm-config" + +[lib] +name = "secure_exec_vm_config" [dependencies] -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -ts-rs = { version = "10.1", features = ["import-esm", "no-serde-warnings", "serde-compat"] } +agentos_vm_config = { package = "agentos-vm-config", path = "../../../agentos/crates/vm-config", version = "0.0.1" } diff --git a/crates/vm-config/src/lib.rs b/crates/vm-config/src/lib.rs index 5e13b6648..5a16602f4 100644 --- a/crates/vm-config/src/lib.rs +++ b/crates/vm-config/src/lib.rs @@ -1,942 +1,3 @@ -use std::collections::BTreeMap; +//! Compatibility shim for `agentos-vm-config`. -use serde::{Deserialize, Serialize}; -use ts_rs::TS; - -/// Canonical Rust-side VM config. Unknown fields must stay rejected here and in -/// the TS preflight schema at -/// `packages/core/src/node-runtime-options-schema.ts`; update both when a -/// public `NodeRuntime.create(...)` option changes the generated VM config. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -#[derive(Default)] -pub struct CreateVmConfig { - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub cwd: Option, - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - #[ts(type = "Record")] - pub env: BTreeMap, - #[serde(default, rename = "rootFilesystem")] - pub root_filesystem: RootFilesystemConfig, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub permissions: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub limits: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub dns: Option, - #[serde( - default, - rename = "nativeRoot", - skip_serializing_if = "Option::is_none" - )] - #[ts(optional)] - pub native_root: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub listen: Option, - #[serde( - default, - rename = "loopbackExemptPorts", - skip_serializing_if = "Vec::is_empty" - )] - pub loopback_exempt_ports: Vec, - #[serde(default, rename = "jsRuntime", skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub js_runtime: Option, - #[serde( - default, - rename = "bootstrapCommands", - skip_serializing_if = "Option::is_none" - )] - #[ts(optional)] - pub bootstrap_commands: Option>, -} - -impl CreateVmConfig { - pub fn validate(&self, max_frame_bytes: usize) -> Result<(), VmConfigError> { - if let Some(cwd) = self.cwd.as_deref() { - validate_guest_path("cwd", cwd)?; - } - self.root_filesystem.validate()?; - if let Some(native_root) = &self.native_root { - native_root.validate()?; - } - if self.native_root.is_some() && !self.root_filesystem.bootstrap_entries.is_empty() { - return Err(VmConfigError::new( - "nativeRoot does not support rootFilesystem.bootstrapEntries", - )); - } - if let Some(dns) = &self.dns { - dns.validate()?; - } - if let Some(listen) = &self.listen { - listen.validate()?; - } - if let Some(limits) = &self.limits { - limits.validate(max_frame_bytes)?; - } - if let Some(js_runtime) = &self.js_runtime { - js_runtime.validate()?; - } - if let Some(bootstrap_commands) = &self.bootstrap_commands { - validate_command_names("bootstrapCommands", bootstrap_commands)?; - } - Ok(()) - } -} - -/// Guest JavaScript host-environment configuration. -/// -/// Selects which globals/builtins/module-resolution surface guest JS sees, -/// modeled on esbuild's `platform`. Omitting this preserves full Node.js -/// emulation (`platform = node`). -#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct JsRuntimeConfig { - /// Which host environment to emulate for guest JS. Default `node`. - #[serde(default)] - pub platform: JsRuntimePlatform, - /// How bare import specifiers resolve. Independent of `platform`. - /// Default `node`. - #[serde(default, rename = "moduleResolution")] - pub module_resolution: JsModuleResolution, - /// Node builtin-module allow-list. Only valid when `platform = node`. - /// `None` => engine default allow-list. `Some([])` => deny all builtins. - /// `Some([..])` => exactly those. - #[serde( - default, - rename = "allowedBuiltins", - skip_serializing_if = "Option::is_none" - )] - #[ts(optional)] - pub allowed_builtins: Option>, - /// Opt in to a high-resolution monotonic guest clock. Default false keeps - /// the security-oriented 1ms timer resolution. - #[serde( - default, - rename = "highResolutionTime", - skip_serializing_if = "Option::is_none" - )] - #[ts(optional)] - pub high_resolution_time: Option, -} - -impl JsRuntimeConfig { - fn validate(&self) -> Result<(), VmConfigError> { - if let Some(allowed) = &self.allowed_builtins { - if self.platform != JsRuntimePlatform::Node { - return Err(VmConfigError::new( - "jsRuntime.allowedBuiltins is only valid when jsRuntime.platform is \"node\"", - )); - } - for name in allowed { - if !is_known_node_builtin(name) { - return Err(VmConfigError::new(format!( - "jsRuntime.allowedBuiltins contains unknown builtin {name:?}" - ))); - } - } - } - Ok(()) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "lowercase")] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -#[derive(Default)] -pub enum JsRuntimePlatform { - /// Full Node.js host surface (process/Buffer/require, `node:*`, npm - /// resolution, virtual Node identity). Default. - #[default] - Node, - /// Web-platform globals (fetch/URL/WebCrypto/...), no Node surface. - Browser, - /// Universal primitives only (console, timers, queueMicrotask) — no web - /// platform, no Node surface. - Neutral, - /// Language-only: ECMAScript spec globals + WebAssembly. Nothing host-provided. - Bare, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "lowercase")] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -#[derive(Default)] -pub enum JsModuleResolution { - /// node_modules ancestor-walk + exports/imports/conditions + realpath. Default. - #[default] - Node, - /// Relative/absolute ESM from the VFS only; bare specifiers do not resolve. - Relative, - /// No resolution: any import/require (even relative) fails. - None, -} - -/// Canonical set of recognized Node builtin module names (without the `node:` -/// prefix), kept in sync with `normalize_builtin_specifier` in -/// `crates/execution/src/javascript.rs`. Used to validate -/// `jsRuntime.allowedBuiltins` entries. -const KNOWN_NODE_BUILTINS: &[&str] = &[ - "assert", - "async_hooks", - "buffer", - "child_process", - "cluster", - "console", - "constants", - "crypto", - "dgram", - "diagnostics_channel", - "dns", - "dns/promises", - "domain", - "events", - "fs", - "fs/promises", - "http", - "http2", - "https", - "inspector", - "module", - "net", - "os", - "path", - "path/posix", - "path/win32", - "perf_hooks", - "process", - "punycode", - "querystring", - "readline", - "repl", - "sqlite", - "stream", - "stream/consumers", - "stream/promises", - "stream/web", - "string_decoder", - "sys", - "timers", - "timers/promises", - "tls", - "trace_events", - "tty", - "url", - "util", - "util/types", - "v8", - "vm", - "wasi", - "worker_threads", - "zlib", -]; - -fn is_known_node_builtin(name: &str) -> bool { - let bare = name.strip_prefix("node:").unwrap_or(name); - KNOWN_NODE_BUILTINS.contains(&bare) -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct RootFilesystemConfig { - #[serde(default)] - pub mode: RootFilesystemMode, - #[serde(default, rename = "disableDefaultBaseLayer")] - pub disable_default_base_layer: bool, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub lowers: Vec, - #[serde( - default, - rename = "bootstrapEntries", - skip_serializing_if = "Vec::is_empty" - )] - pub bootstrap_entries: Vec, -} - -impl Default for RootFilesystemConfig { - fn default() -> Self { - Self { - mode: RootFilesystemMode::Ephemeral, - disable_default_base_layer: false, - lowers: Vec::new(), - bootstrap_entries: Vec::new(), - } - } -} - -impl RootFilesystemConfig { - fn validate(&self) -> Result<(), VmConfigError> { - for lower in &self.lowers { - if let RootFilesystemLowerDescriptor::Snapshot { entries } = lower { - for entry in entries { - entry.validate()?; - } - } - } - for entry in &self.bootstrap_entries { - entry.validate()?; - } - Ok(()) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "kebab-case")] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -#[derive(Default)] -pub enum RootFilesystemMode { - #[default] - Ephemeral, - ReadOnly, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(tag = "kind", rename_all = "camelCase")] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub enum RootFilesystemLowerDescriptor { - Snapshot { - #[serde(default)] - entries: Vec, - }, - BundledBaseFilesystem, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct RootFilesystemEntry { - pub path: String, - pub kind: RootFilesystemEntryKind, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub mode: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub uid: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub gid: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub content: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub encoding: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub target: Option, - #[serde(default)] - pub executable: bool, -} - -impl RootFilesystemEntry { - fn validate(&self) -> Result<(), VmConfigError> { - validate_guest_path("root filesystem entry path", &self.path)?; - match self.kind { - RootFilesystemEntryKind::File => { - if self.target.is_some() { - return Err(VmConfigError::new(format!( - "file entry {} must not include target", - self.path - ))); - } - } - RootFilesystemEntryKind::Directory => { - if self.content.is_some() || self.encoding.is_some() || self.target.is_some() { - return Err(VmConfigError::new(format!( - "directory entry {} must not include content, encoding, or target", - self.path - ))); - } - } - RootFilesystemEntryKind::Symlink => { - if self.target.as_deref().unwrap_or("").is_empty() { - return Err(VmConfigError::new(format!( - "symlink entry {} requires target", - self.path - ))); - } - if self.content.is_some() || self.encoding.is_some() { - return Err(VmConfigError::new(format!( - "symlink entry {} must not include content or encoding", - self.path - ))); - } - } - } - Ok(()) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "lowercase")] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub enum RootFilesystemEntryKind { - File, - Directory, - Symlink, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "lowercase")] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub enum RootFilesystemEntryEncoding { - Utf8, - Base64, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct NativeRootFilesystemConfig { - pub plugin: MountPluginDescriptor, - #[serde(default, rename = "readOnly")] - pub read_only: bool, -} - -impl NativeRootFilesystemConfig { - fn validate(&self) -> Result<(), VmConfigError> { - if self.plugin.id.trim().is_empty() { - return Err(VmConfigError::new("nativeRoot.plugin.id is required")); - } - Ok(()) - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct MountPluginDescriptor { - pub id: String, - #[serde(default, skip_serializing_if = "serde_json::Value::is_null")] - #[ts(type = "import(\"../descriptors.js\").MountConfigJsonValue")] - pub config: serde_json::Value, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "lowercase")] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub enum PermissionMode { - Allow, - Ask, - Deny, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(untagged)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub enum FsPermissionScope { - Mode(PermissionMode), - Rules(FsPermissionRuleSet), -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(untagged)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub enum PatternPermissionScope { - Mode(PermissionMode), - Rules(PatternPermissionRuleSet), -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct FsPermissionRuleSet { - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub default: Option, - #[serde(default)] - pub rules: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct PatternPermissionRuleSet { - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub default: Option, - #[serde(default)] - pub rules: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct FsPermissionRule { - pub mode: PermissionMode, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub operations: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub paths: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct PatternPermissionRule { - pub mode: PermissionMode, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub operations: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub patterns: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct PermissionsPolicy { - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub fs: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub network: Option, - #[serde( - default, - rename = "childProcess", - skip_serializing_if = "Option::is_none" - )] - #[ts(optional)] - pub child_process: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub process: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub env: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub binding: Option, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct VmLimitsConfig { - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub resources: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub http: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub tools: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub plugins: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub acp: Option, - #[serde(default, rename = "jsRuntime", skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub js_runtime: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub python: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub wasm: Option, -} - -impl VmLimitsConfig { - fn validate(&self, max_frame_bytes: usize) -> Result<(), VmConfigError> { - if let Some(http) = &self.http { - if let Some(max_fetch_response_bytes) = http.max_fetch_response_bytes { - if max_fetch_response_bytes == 0 { - return Err(VmConfigError::new( - "limits.http.maxFetchResponseBytes must be greater than zero", - )); - } - if max_fetch_response_bytes as usize > max_frame_bytes { - return Err(VmConfigError::new(format!( - "limits.http.maxFetchResponseBytes ({max_fetch_response_bytes}) must be <= the sidecar wire frame cap ({max_frame_bytes})" - ))); - } - } - } - if let Some(tools) = &self.tools { - if let (Some(default), Some(max)) = - (tools.default_tool_timeout_ms, tools.max_tool_timeout_ms) - { - if default > max { - return Err(VmConfigError::new( - "limits.tools.defaultToolTimeoutMs must be <= limits.tools.maxToolTimeoutMs", - )); - } - } - } - Ok(()) - } -} - -macro_rules! limits_struct { - ($name:ident { $($field:ident),* $(,)? }) => { - #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, TS)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - #[ts(export, export_to = "../../../packages/core/src/generated/")] - pub struct $name { - $( - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - #[ts(type = "number")] - pub $field: Option, - )* - } - }; -} - -limits_struct!(ResourceLimitsConfig { - cpu_count, - max_processes, - max_open_fds, - max_pipes, - max_ptys, - max_sockets, - max_connections, - max_socket_buffered_bytes, - max_socket_datagram_queue_len, - max_filesystem_bytes, - max_inode_count, - max_blocking_read_ms, - max_pread_bytes, - max_fd_write_bytes, - max_process_argv_bytes, - max_process_env_bytes, - max_readdir_entries, - max_recursive_fs_depth, - max_recursive_fs_entries, - max_wasm_fuel, - max_wasm_memory_bytes, - max_wasm_stack_bytes, -}); - -limits_struct!(HttpLimitsConfig { - max_fetch_response_bytes, -}); - -limits_struct!(ToolLimitsConfig { - default_tool_timeout_ms, - max_tool_timeout_ms, - max_registered_toolkits, - max_registered_tools_per_vm, - max_tools_per_toolkit, - max_tool_schema_bytes, - max_tool_examples_per_tool, - max_tool_example_input_bytes, -}); - -limits_struct!(PluginLimitsConfig { - max_persisted_manifest_bytes, - max_persisted_manifest_file_bytes, -}); - -limits_struct!(AcpLimitsConfig { - max_read_line_bytes, - stdout_buffer_byte_limit, -}); - -limits_struct!(JsRuntimeLimitsConfig { - v8_heap_limit_mb, - sync_rpc_wait_timeout_ms, - cpu_time_limit_ms, - wall_clock_limit_ms, - import_cache_materialize_timeout_ms, - captured_output_limit_bytes, - stdin_buffer_limit_bytes, - event_payload_limit_bytes, - v8_ipc_max_frame_bytes, -}); - -limits_struct!(PythonLimitsConfig { - output_buffer_max_bytes, - execution_timeout_ms, - max_old_space_mb, - vfs_rpc_timeout_ms, -}); - -limits_struct!(WasmLimitsConfig { - max_module_file_bytes, - captured_output_limit_bytes, - sync_read_limit_bytes, - prewarm_timeout_ms, - runner_heap_limit_mb, -}); - -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct VmDnsConfig { - #[serde(default, rename = "nameServers", skip_serializing_if = "Vec::is_empty")] - pub name_servers: Vec, - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub overrides: BTreeMap>, -} - -impl VmDnsConfig { - fn validate(&self) -> Result<(), VmConfigError> { - for entry in &self.name_servers { - if entry.trim().is_empty() { - return Err(VmConfigError::new( - "dns.nameServers entries must not be empty", - )); - } - } - for (host, addresses) in &self.overrides { - if host.trim().is_empty() { - return Err(VmConfigError::new("dns.overrides keys must not be empty")); - } - if addresses.is_empty() { - return Err(VmConfigError::new(format!( - "dns.overrides.{host} must contain at least one address" - ))); - } - } - Ok(()) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = "../../../packages/core/src/generated/")] -pub struct VmListenPolicyConfig { - #[serde(default, rename = "portMin", skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub port_min: Option, - #[serde(default, rename = "portMax", skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub port_max: Option, - #[serde( - default, - rename = "allowPrivileged", - skip_serializing_if = "Option::is_none" - )] - #[ts(optional)] - pub allow_privileged: Option, -} - -impl VmListenPolicyConfig { - fn validate(&self) -> Result<(), VmConfigError> { - if self.port_min == Some(0) { - return Err(VmConfigError::new( - "listen.portMin must be between 1 and 65535", - )); - } - if self.port_max == Some(0) { - return Err(VmConfigError::new( - "listen.portMax must be between 1 and 65535", - )); - } - if let (Some(min), Some(max)) = (self.port_min, self.port_max) { - if min > max { - return Err(VmConfigError::new( - "listen.portMin must be <= listen.portMax", - )); - } - } - Ok(()) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VmConfigError { - message: String, -} - -impl VmConfigError { - pub fn new(message: impl Into) -> Self { - Self { - message: message.into(), - } - } -} - -impl std::fmt::Display for VmConfigError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.message) - } -} - -impl std::error::Error for VmConfigError {} - -fn validate_guest_path(label: &str, path: &str) -> Result<(), VmConfigError> { - if !path.starts_with('/') { - return Err(VmConfigError::new(format!("{label} must be absolute"))); - } - if path.split('/').any(|part| part == "..") { - return Err(VmConfigError::new(format!("{label} must not contain '..'"))); - } - Ok(()) -} - -fn validate_command_names(label: &str, commands: &[String]) -> Result<(), VmConfigError> { - for command in commands { - if command.is_empty() - || command == "." - || command == ".." - || command.contains('/') - || command.contains('\0') - { - return Err(VmConfigError::new(format!( - "{label} contains invalid command name {command:?}" - ))); - } - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn default_config_round_trips() { - let config = CreateVmConfig::default(); - let json = serde_json::to_string(&config).expect("serialize config"); - let decoded: CreateVmConfig = serde_json::from_str(&json).expect("decode config"); - assert_eq!(decoded, config); - } - - #[test] - fn unknown_fields_are_rejected() { - let error = - serde_json::from_str::(r#"{"rootFilesystem":{},"surprise":true}"#) - .expect_err("unknown fields should fail"); - assert!(error.to_string().contains("unknown field")); - } - - #[test] - fn validate_rejects_fetch_limit_above_frame_cap() { - let config = CreateVmConfig { - limits: Some(VmLimitsConfig { - http: Some(HttpLimitsConfig { - max_fetch_response_bytes: Some(2048), - }), - ..VmLimitsConfig::default() - }), - ..CreateVmConfig::default() - }; - assert!(config.validate(1024).is_err()); - } - - fn js_runtime_config(value: serde_json::Value) -> Result { - serde_json::from_value(serde_json::json!({ "jsRuntime": value })) - } - - #[test] - fn js_runtime_defaults_to_node() { - let config: CreateVmConfig = - serde_json::from_value(serde_json::json!({ "jsRuntime": {} })).expect("decode"); - let js = config.js_runtime.expect("jsRuntime present"); - assert_eq!(js.platform, JsRuntimePlatform::Node); - assert_eq!(js.module_resolution, JsModuleResolution::Node); - assert!(js.allowed_builtins.is_none()); - assert!(js.high_resolution_time.is_none()); - } - - #[test] - fn js_runtime_high_resolution_time_defaults_off_and_round_trips() { - let defaulted = js_runtime_config(serde_json::json!({})).unwrap(); - assert!(defaulted.js_runtime.unwrap().high_resolution_time.is_none()); - - let enabled = js_runtime_config(serde_json::json!({ - "highResolutionTime": true, - })) - .unwrap(); - assert_eq!( - enabled.js_runtime.as_ref().unwrap().high_resolution_time, - Some(true) - ); - let json = serde_json::to_string(&enabled).expect("serialize"); - assert!(json.contains("highResolutionTime")); - let decoded: CreateVmConfig = serde_json::from_str(&json).expect("re-decode"); - assert_eq!(decoded, enabled); - } - - #[test] - fn js_runtime_all_platform_resolution_combos_round_trip() { - for platform in ["node", "browser", "neutral", "bare"] { - for resolution in ["node", "relative", "none"] { - let config = js_runtime_config(serde_json::json!({ - "platform": platform, - "moduleResolution": resolution, - })) - .unwrap_or_else(|err| panic!("decode {platform}/{resolution}: {err}")); - let json = serde_json::to_string(&config).expect("serialize"); - let decoded: CreateVmConfig = serde_json::from_str(&json).expect("re-decode"); - assert_eq!(decoded, config); - assert!(config.validate(usize::MAX).is_ok()); - } - } - } - - #[test] - fn js_runtime_allowed_builtins_tri_state() { - // None => omitted. - let none = js_runtime_config(serde_json::json!({ "platform": "node" })).unwrap(); - assert!(none.js_runtime.unwrap().allowed_builtins.is_none()); - // Some([]) => deny all (representable, distinct from None). - let empty = js_runtime_config(serde_json::json!({ "allowedBuiltins": [] })).unwrap(); - assert_eq!(empty.js_runtime.unwrap().allowed_builtins, Some(Vec::new())); - // Some([..]) => explicit. - let some = js_runtime_config(serde_json::json!({ "allowedBuiltins": ["path", "node:fs"] })) - .unwrap(); - assert_eq!( - some.js_runtime.unwrap().allowed_builtins, - Some(vec!["path".to_owned(), "node:fs".to_owned()]) - ); - } - - #[test] - fn js_runtime_rejects_allowed_builtins_under_non_node_platform() { - for platform in ["browser", "neutral", "bare"] { - let config = js_runtime_config(serde_json::json!({ - "platform": platform, - "allowedBuiltins": ["path"], - })) - .unwrap(); - let error = config - .validate(usize::MAX) - .expect_err("allowedBuiltins under non-node must reject"); - assert!(error.to_string().contains("allowedBuiltins")); - } - } - - #[test] - fn js_runtime_rejects_unknown_builtin_names() { - let config = js_runtime_config(serde_json::json!({ - "platform": "node", - "allowedBuiltins": ["path", "totally_not_a_builtin"], - })) - .unwrap(); - let error = config - .validate(usize::MAX) - .expect_err("unknown builtin must reject"); - assert!(error.to_string().contains("unknown builtin")); - } - - #[test] - fn js_runtime_accepts_empty_allow_list_under_node() { - let config = - js_runtime_config(serde_json::json!({ "platform": "node", "allowedBuiltins": [] })) - .unwrap(); - assert!(config.validate(usize::MAX).is_ok()); - } - - #[test] - fn js_runtime_rejects_unknown_fields() { - let error = js_runtime_config(serde_json::json!({ "surprise": true })) - .expect_err("unknown jsRuntime field should fail"); - assert!(error.to_string().contains("unknown field")); - } -} +pub use agentos_vm_config::*; diff --git a/docker/build/darwin.Dockerfile b/docker/build/darwin.Dockerfile deleted file mode 100644 index 1ec3d34c6..000000000 --- a/docker/build/darwin.Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -# syntax=docker/dockerfile:1.10.0 -# -# Cross-compile the secure-exec sidecar for macOS via osxcross, on a LINUX -# runner — so the publish never depends on scarce/queued GitHub macOS runners -# (the failure mode that motivated this). Mirrors rivet's darwin build: the base -# image bakes in osxcross + the MacOSX SDK (which provides CoreServices.h etc. -# that a plain zig cross-build lacks) AND Node 22 + corepack for our v8-bridge -# build.rs. Parameterized by TARGET so one file serves x64 + arm64. -# -# TARGET = aarch64-apple-darwin | x86_64-apple-darwin -# CLANG = aarch64-apple-darwin20.4 | x86_64-apple-darwin20.4 (osxcross prefix) -FROM ghcr.io/rivet-dev/rivet/builder-base-osxcross:0e33ceb98 - -ARG TARGET=aarch64-apple-darwin -ARG CLANG=aarch64-apple-darwin20.4 -ARG TRIGGER=branch - -ENV SDK=/root/osxcross/target/SDK/MacOSX11.3.sdk \ - RUSTC_WRAPPER= - -WORKDIR /build -COPY . . - -# Use the repo-pinned toolchain (rust-toolchain.toml) + the darwin target. -RUN channel=$(awk -F'"' '/channel/ {print $2; exit}' rust-toolchain.toml) && \ - rustup toolchain install "$channel" --profile minimal && \ - rustup target add --toolchain "$channel" "$TARGET" - -# The v8-runtime build.rs regenerates the V8 bridge via Node, so the pnpm -# workspace must be installed first. Exclude the leaf `website` package (pnpm -# 10.x symlink race), matching the native build. -RUN corepack enable && pnpm install --frozen-lockfile --filter='!@secure-exec/website' - -RUN tu=$(echo "$TARGET" | tr 'a-z-' 'A-Z_') && \ - tl=$(echo "$TARGET" | tr - _) && \ - export BINDGEN_EXTRA_CLANG_ARGS_${tl}="--sysroot=$SDK -isystem $SDK/usr/include" && \ - export CFLAGS_${tl}="-B/root/osxcross/target/bin" && \ - export CXXFLAGS_${tl}="-B/root/osxcross/target/bin" && \ - export CC_${tl}=${CLANG}-clang && \ - export CXX_${tl}=${CLANG}-clang++ && \ - export AR_${tl}=${CLANG}-ar && \ - export RANLIB_${tl}=${CLANG}-ranlib && \ - export CARGO_TARGET_${tu}_LINKER=${CLANG}-clang && \ - if [ "$TRIGGER" = "release" ]; then FLAG="--release"; PROF=release; else FLAG=""; PROF=debug; fi && \ - cargo build $FLAG -p secure-exec-sidecar --target "$TARGET" && \ - mkdir -p /artifacts && \ - cp "target/$TARGET/$PROF/secure-exec-sidecar" /artifacts/secure-exec-sidecar - -CMD ["ls", "-la", "/artifacts"] diff --git a/docker/build/darwin.Dockerfile.dockerignore b/docker/build/darwin.Dockerfile.dockerignore deleted file mode 100644 index ee7ecd4a9..000000000 --- a/docker/build/darwin.Dockerfile.dockerignore +++ /dev/null @@ -1,11 +0,0 @@ -# BuildKit uses this in place of the repo-root .dockerignore for darwin.Dockerfile -# (the root one is scoped to the website/Railway build and excludes everything but -# website/ + packages/core, which starves the sidecar cross-build of rust-toolchain.toml, -# crates, Cargo.toml, etc.). Send the full source; drop only artifacts/caches the -# in-container build regenerates (pnpm install + cargo build happen inside the image). -.git -**/node_modules -**/target -**/dist -**/.astro -**/.turbo diff --git a/examples/docs/feat-child-processes/package.json b/examples/docs/feat-child-processes/package.json deleted file mode 100644 index 00175a6aa..000000000 --- a/examples/docs/feat-child-processes/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-child-processes", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-child-processes/src/index.mts b/examples/docs/feat-child-processes/src/index.mts deleted file mode 100644 index 1d71c9bb9..000000000 --- a/examples/docs/feat-child-processes/src/index.mts +++ /dev/null @@ -1,35 +0,0 @@ -import { NodeRuntime } from "secure-exec"; - -// Boot a fully virtualized VM. The guest runs inside the kernel isolation -// boundary, and any child processes it spawns are themselves kernel-managed -// processes - they never spawn real host processes. -const rt = await NodeRuntime.create(); - -try { - // Guest code runs as an ES module inside the VM. It uses the standard - // node:child_process module to spawn a command available in the VM and read - // its output. Here we spawn `sh -c` to echo a message, and `node` to report - // its own version - both run as kernel-managed child processes. - const { stdout, stderr, exitCode } = await rt.exec(` - import { execFileSync } from "node:child_process"; - - // Spawn a shell command and capture its stdout. - const shellOut = execFileSync("sh", ["-c", "echo hello from a child process"], { - encoding: "utf8", - }); - console.log("sh output:", shellOut.trim()); - - // Spawn node as a child process and read its version. - const nodeVersion = execFileSync("node", ["--version"], { - encoding: "utf8", - }); - console.log("child node version:", nodeVersion.trim()); - `); - - console.log("exitCode:", exitCode); - if (stderr.trim()) console.log("guest stderr:", stderr.trim()); - console.log("guest stdout:"); - console.log(stdout.trim()); -} finally { - await rt.dispose(); -} diff --git a/examples/docs/feat-child-processes/tsconfig.json b/examples/docs/feat-child-processes/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-child-processes/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-filesystem/host-data/greeting.txt b/examples/docs/feat-filesystem/host-data/greeting.txt deleted file mode 100644 index 22aea324a..000000000 --- a/examples/docs/feat-filesystem/host-data/greeting.txt +++ /dev/null @@ -1 +0,0 @@ -value-from-host diff --git a/examples/docs/feat-filesystem/package.json b/examples/docs/feat-filesystem/package.json deleted file mode 100644 index 09581832a..000000000 --- a/examples/docs/feat-filesystem/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-filesystem", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-filesystem/src/index.mts b/examples/docs/feat-filesystem/src/index.mts deleted file mode 100644 index 1db778851..000000000 --- a/examples/docs/feat-filesystem/src/index.mts +++ /dev/null @@ -1,72 +0,0 @@ -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { NodeRuntime } from "secure-exec"; - -// Boot a fully virtualized VM. The guest filesystem lives entirely inside the -// kernel - writes never touch the host disk. -const rt = await NodeRuntime.create(); - -try { - // Guest code runs as an ES module inside the VM. It writes and reads files - // using the standard node `fs` module, backed by the kernel's virtual - // filesystem. - const { stdout, stderr, exitCode } = await rt.exec(` - import { mkdirSync, writeFileSync, readFileSync, readdirSync } from "node:fs"; - - mkdirSync("/workspace", { recursive: true }); - writeFileSync("/workspace/hello.txt", "hello from the sandbox"); - - const message = readFileSync("/workspace/hello.txt", "utf8"); - const entries = readdirSync("/workspace"); - - console.log("read back from VM:", message); - console.log("/workspace contents:", JSON.stringify(entries)); - `); - - console.log("exitCode:", exitCode); - if (stderr.trim()) console.log("guest stderr:", stderr.trim()); - console.log("guest stdout:"); - console.log(stdout.trim()); -} finally { - await rt.dispose(); -} - -// Mounting a host directory into the VM. `mounts` projects a real host -// directory into the guest filesystem, Docker-style. Files are read lazily -// through the VFS, and the guest sees only the mounted subtree. -const hostDir = path.join( - path.dirname(fileURLToPath(import.meta.url)), - "..", - "host-data", -); - -const mounted = await NodeRuntime.create({ - mounts: [ - { - guestPath: "/mnt/host-data", - hostPath: hostDir, - readOnly: true, - }, - ], -}); - -try { - // The guest reads a file that lives on the real host, exposed read-only at - // the mount point. Nothing else on the host is visible. - const { stdout, stderr, exitCode } = await mounted.exec(` - import { readFileSync, readdirSync } from "node:fs"; - - const entries = readdirSync("/mnt/host-data"); - const greeting = readFileSync("/mnt/host-data/greeting.txt", "utf8"); - - console.log("mounted contents:", JSON.stringify(entries)); - console.log("guest read host file:", greeting.trim()); - `); - - console.log("[mount] exitCode:", exitCode); - if (stderr.trim()) console.log("[mount] guest stderr:", stderr.trim()); - console.log("[mount] guest stdout:"); - console.log(stdout.trim()); -} finally { - await mounted.dispose(); -} diff --git a/examples/docs/feat-filesystem/tsconfig.json b/examples/docs/feat-filesystem/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-filesystem/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-module-loading/package.json b/examples/docs/feat-module-loading/package.json deleted file mode 100644 index 57e5dccc0..000000000 --- a/examples/docs/feat-module-loading/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-module-loading", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-module-loading/src/index.mts b/examples/docs/feat-module-loading/src/index.mts deleted file mode 100644 index 527b6293a..000000000 --- a/examples/docs/feat-module-loading/src/index.mts +++ /dev/null @@ -1,89 +0,0 @@ -import { fileURLToPath } from "node:url"; -import { NodeRuntime } from "secure-exec"; - -// docs:start loading-modules -// Boot a fully virtualized VM. Module resolution runs entirely inside the -// kernel - `import` and `require` resolve against the guest's virtual -// filesystem, never the host's. -const rt = await NodeRuntime.create(); - -try { - // Guest code runs as an ES module inside the VM, so it can `import` Node - // builtins directly. It can also build a CommonJS `require` with - // `createRequire` to load builtins the classic way. Both resolve through the - // kernel's module loader. - const { stdout, stderr, exitCode } = await rt.exec(` - // ESM import of a Node builtin. - import { basename, join } from "node:path"; - - // CommonJS require, created from the current module URL. - import { createRequire } from "node:module"; - const require = createRequire(import.meta.url); - const os = require("node:os"); - - const resolved = { - basename: basename("/workspace/data/report.txt"), - joined: join("/workspace", "data", "report.txt"), - platform: os.platform(), - }; - - console.log("resolved node:path via import ->", resolved.joined); - console.log("resolved node:os via require ->", resolved.platform); - console.log(JSON.stringify(resolved)); - `); - - console.log("exitCode:", exitCode); - if (stderr.trim()) console.log("guest stderr:\n" + stderr.trim()); - console.log("guest stdout:"); - console.log(stdout.trim()); -} finally { - await rt.dispose(); -} -// docs:end loading-modules - -// --- Loading real npm packages from the host ------------------------------ - -// docs:start npm-packages -// Point `nodeModules` at a host `node_modules` directory and the whole tree is -// projected into the VM in one call. Any package inside resolves the way Node -// would over a real filesystem, symlinks and all. Here we mount this repo's -// root node_modules, which includes the tiny `is-number` package. -const hostNodeModules = fileURLToPath( - new URL("../../../../node_modules", import.meta.url), -); - -const mounted = await NodeRuntime.create({ - nodeModules: hostNodeModules, -}); - -try { - // The guest resolves `is-number` from the mounted host node_modules the same - // way Node would over a real filesystem, then uses the real package's code. - const { stdout, stderr, exitCode } = await mounted.exec(` - // ESM import of the real, host-mounted npm package. - import isNumber from "is-number"; - - // The same package also resolves through a CommonJS require. - import { createRequire } from "node:module"; - const require = createRequire(import.meta.url); - const isNumberCjs = require("is-number"); - - const result = { - "isNumber(42)": isNumber(42), - 'isNumber("3.14")': isNumber("3.14"), - 'isNumber("nope")': isNumber("nope"), - sameModule: isNumber === isNumberCjs, - }; - - console.log("loaded real npm package is-number"); - console.log(JSON.stringify(result)); - `); - - console.log("exitCode:", exitCode); - if (stderr.trim()) console.log("guest stderr:\n" + stderr.trim()); - console.log("guest stdout:"); - console.log(stdout.trim()); -} finally { - await mounted.dispose(); -} -// docs:end npm-packages diff --git a/examples/docs/feat-module-loading/tsconfig.json b/examples/docs/feat-module-loading/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-module-loading/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-networking-wasm/package.json b/examples/docs/feat-networking-wasm/package.json deleted file mode 100644 index c681c8e81..000000000 --- a/examples/docs/feat-networking-wasm/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-networking-wasm", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "@secure-exec/core": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-networking-wasm/src/index.mts b/examples/docs/feat-networking-wasm/src/index.mts deleted file mode 100644 index 3ca6a560b..000000000 --- a/examples/docs/feat-networking-wasm/src/index.mts +++ /dev/null @@ -1,192 +0,0 @@ -import { existsSync } from "node:fs"; -import { createServer as createHttpServer } from "node:http"; -import type { AddressInfo } from "node:net"; -import { fileURLToPath } from "node:url"; -import { - allowAll, - createInMemoryFileSystem, - createKernel, - createNodeRuntime, - createWasmVmRuntime, - type Kernel, -} from "@secure-exec/core/test-runtime"; - -function resolveCommandDir( - envName: string, - fallbackRelativePath: string, - requiredCommand: string, -): string { - const fromEnv = process.env[envName]; - const candidates = [ - fromEnv, - fileURLToPath(new URL(fallbackRelativePath, import.meta.url)), - ].filter((value): value is string => Boolean(value)); - for (const dir of candidates) { - if (existsSync(`${dir}/${requiredCommand}`)) { - return dir; - } - } - throw new Error( - `${requiredCommand} was not found. Set ${envName} to a built WASM command directory.`, - ); -} - -const wasmCommandsDir = resolveCommandDir( - "SECURE_EXEC_WASM_COMMANDS_DIR", - "../../../../registry/native/target/wasm32-wasip1/release/commands", - "sh", -); -const cWasmCommandsDir = resolveCommandDir( - "SECURE_EXEC_C_WASM_COMMANDS_DIR", - "../../../../registry/native/c/build", - "http_get", -); - -interface RunningProgram { - process: ReturnType; - stdoutChunks: Uint8Array[]; - stderrChunks: Uint8Array[]; - exitCode: () => number | null; -} - -function decode(chunks: Uint8Array[]): string { - return chunks.map((chunk) => new TextDecoder().decode(chunk)).join(""); -} - -function spawn( - kernel: Kernel, - command: string, - args: string[], -): RunningProgram { - const stdoutChunks: Uint8Array[] = []; - const stderrChunks: Uint8Array[] = []; - let code: number | null = null; - const process = kernel.spawn(command, args, { - onStdout: (chunk) => stdoutChunks.push(chunk), - onStderr: (chunk) => stderrChunks.push(chunk), - }); - void process.wait().then((exitCode) => { - code = exitCode; - }); - return { - process, - stdoutChunks, - stderrChunks, - exitCode: () => code, - }; -} - -async function waitForOutput( - program: RunningProgram, - needle: string, -): Promise { - const deadline = Date.now() + 20_000; - while (Date.now() < deadline) { - if (decode(program.stdoutChunks).includes(needle)) { - return; - } - if (program.exitCode() !== null) { - throw new Error( - `process exited before ${JSON.stringify(needle)}\nstdout:\n${decode( - program.stdoutChunks, - )}\nstderr:\n${decode(program.stderrChunks)}`, - ); - } - await new Promise((resolve) => setTimeout(resolve, 20)); - } - throw new Error(`timed out waiting for ${JSON.stringify(needle)}`); -} - -async function waitForListener(kernel: Kernel, port: number): Promise { - const deadline = Date.now() + 20_000; - while (Date.now() < deadline) { - if (kernel.socketTable.findListener({ host: "0.0.0.0", port })) { - return; - } - await new Promise((resolve) => setTimeout(resolve, 20)); - } - throw new Error(`timed out waiting for listener on ${port}`); -} - -function parseVmFetch(responseJson: string): { status: number; body: string } { - const parsed = JSON.parse(responseJson) as { - status?: number; - body?: string; - bodyEncoding?: string; - }; - const encodedBody = parsed.body ?? ""; - const body = - parsed.bodyEncoding === "base64" - ? Buffer.from(encodedBody, "base64").toString("utf8") - : encodedBody; - return { status: parsed.status ?? 0, body }; -} - -const hostServer = createHttpServer((req, res) => { - res.writeHead(200, { "content-type": "text/plain" }); - res.end("host:" + req.url); -}); -await new Promise((resolve) => { - hostServer.listen(0, "127.0.0.1", resolve); -}); -const hostPort = (hostServer.address() as AddressInfo).port; - -const kernel = createKernel({ - filesystem: createInMemoryFileSystem(), - permissions: allowAll, - loopbackExemptPorts: [hostPort], -}); - -try { - await kernel.mount( - createWasmVmRuntime({ commandDirs: [cWasmCommandsDir, wasmCommandsDir] }), - ); - await kernel.mount(createNodeRuntime()); - - const jsServer = spawn(kernel, "node", [ - "-e", - ` -const http = require("http"); -const server = http.createServer((req, res) => { - res.writeHead(200, { "content-type": "text/plain" }); - res.end("js:" + req.method + ":" + req.url); -}); -server.listen(3301, "127.0.0.1", () => console.log("js listening")); -`, - ]); - await waitForOutput(jsServer, "js listening"); - const wasmToJs = await kernel.exec("http_get 3301 /from-wasm"); - console.log("wasm -> js:", JSON.stringify(wasmToJs.stdout.trim())); - jsServer.process.kill(15); - await jsServer.process.wait().catch(() => {}); - - const wasmServerForJs = spawn(kernel, "http_server", ["3302"]); - await waitForListener(kernel, 3302); - const jsToWasm = await kernel.exec( - `node -e "fetch('http://127.0.0.1:3302/from-js').then(async r => console.log(r.status + ':' + await r.text())).catch(e => { console.error(e); process.exit(1); })"`, - ); - console.log("js -> wasm:", JSON.stringify(jsToWasm.stdout.trim())); - await wasmServerForJs.process.wait(); - - const wasmServerForHost = spawn(kernel, "http_server", ["3303"]); - await waitForListener(kernel, 3303); - const hostToWasm = parseVmFetch( - await kernel.vmFetch({ - port: 3303, - method: "GET", - path: "/from-host", - headersJson: JSON.stringify({}), - }), - ); - console.log( - "host -> wasm:", - JSON.stringify(`${hostToWasm.status}:${hostToWasm.body}`), - ); - await wasmServerForHost.process.wait(); - - const wasmToHost = await kernel.exec(`http_get ${hostPort} /from-wasm-host`); - console.log("wasm -> host:", JSON.stringify(wasmToHost.stdout.trim())); -} finally { - await kernel.dispose(); - await new Promise((resolve) => hostServer.close(() => resolve())); -} diff --git a/examples/docs/feat-networking-wasm/tsconfig.json b/examples/docs/feat-networking-wasm/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-networking-wasm/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-networking/package.json b/examples/docs/feat-networking/package.json deleted file mode 100644 index d9c740fde..000000000 --- a/examples/docs/feat-networking/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-networking", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-networking/src/index.mts b/examples/docs/feat-networking/src/index.mts deleted file mode 100644 index 8b0058d26..000000000 --- a/examples/docs/feat-networking/src/index.mts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Networking example. - * - * Network access for guest code is governed by the VM permission policy. This - * example shows both sides of the gate: - * - * 1. With network "allow", the guest starts a loopback HTTP server inside the - * VM and fetches it - the request and response stay entirely within the - * kernel socket table (hermetic, no real host network). - * 2. With the default (network denied), the same outbound fetch is blocked. - * 3. Host loopback is separate from VM loopback: even with network "allow", - * a guest can reach a host loopback service only when the host port is in - * loopbackExemptPorts. - * - * Run with: - * SECURE_EXEC_SIDECAR_BIN=../../../target/debug/secure-exec-sidecar \ - * npx tsx src/index.mts - */ - -import { NodeRuntime } from "secure-exec"; -import { createServer as createHttpServer } from "node:http"; -import type { AddressInfo } from "node:net"; - -// Guest program: start a loopback HTTP server, then fetch it. Both the listen -// and the fetch go through the kernel socket table. -const GUEST = ` -import http from "node:http"; - -const server = http.createServer((_req, res) => { - res.writeHead(200, { "content-type": "text/plain" }); - res.end("network-ok"); -}); - -await new Promise((resolve, reject) => { - server.once("error", reject); - server.listen(0, "127.0.0.1", resolve); -}); - -const { port } = server.address(); -const response = await fetch("http://127.0.0.1:" + port + "/"); -const body = await response.text(); -console.log("status:", response.status); -console.log("body:", body); - -await new Promise((resolve) => server.close(resolve)); -`; - -// 1. Network allowed: opt in with a partial policy. Permissions merge over the -// secure default, so you only name the scope you are changing. The default -// already grants the fs/child_process/process/env scopes the runtime needs to -// launch guest programs. -const allowed = await NodeRuntime.create({ - permissions: { network: "allow" }, -}); -try { - const result = await allowed.exec(GUEST); - console.log("[network allowed] exitCode:", result.exitCode); - console.log("[network allowed] stdout:", JSON.stringify(result.stdout.trim())); - console.log("[network allowed] stderr:", JSON.stringify(result.stderr.trim())); -} finally { - await allowed.dispose(); -} - -// 2. Network denied: this is the default, so plain create() blocks the network. -const denied = await NodeRuntime.create(); -try { - const result = await denied.exec(GUEST); - console.log("[network denied] exitCode:", result.exitCode); - console.log( - "[network denied] stderr:", - JSON.stringify(result.stderr.trim().split("\n")[0]), - ); -} finally { - await denied.dispose(); -} - -// 3. Host loopback access: network "allow" is not enough to reach real host -// loopback. The host must explicitly exempt the host port too. -const hostServer = createHttpServer((req, res) => { - res.writeHead(200, { "content-type": "text/plain" }); - res.end("host-ok:" + req.url); -}); -await new Promise((resolve) => { - hostServer.listen(0, "127.0.0.1", resolve); -}); -const hostPort = (hostServer.address() as AddressInfo).port; - -const HOST_FETCH_GUEST = ` -try { - const response = await fetch("http://127.0.0.1:${hostPort}/from-guest"); - console.log(response.status + ":" + await response.text()); -} catch (error) { - console.log(error.cause?.code || error.code || error.name); - process.exit(2); -} -`; - -try { - const blockedHostLoopback = await NodeRuntime.create({ - permissions: { network: "allow" }, - }); - try { - const result = await blockedHostLoopback.exec(HOST_FETCH_GUEST); - console.log("[host loopback blocked] exitCode:", result.exitCode); - console.log( - "[host loopback blocked] stdout:", - JSON.stringify(result.stdout.trim()), - ); - } finally { - await blockedHostLoopback.dispose(); - } - - const allowedHostLoopback = await NodeRuntime.create({ - permissions: { network: "allow" }, - loopbackExemptPorts: [hostPort], - }); - try { - const result = await allowedHostLoopback.exec(HOST_FETCH_GUEST); - console.log("[host loopback allowed] exitCode:", result.exitCode); - console.log( - "[host loopback allowed] stdout:", - JSON.stringify(result.stdout.trim()), - ); - } finally { - await allowedHostLoopback.dispose(); - } -} finally { - await new Promise((resolve) => hostServer.close(() => resolve())); -} diff --git a/examples/docs/feat-networking/tsconfig.json b/examples/docs/feat-networking/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-networking/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-output-capture/package.json b/examples/docs/feat-output-capture/package.json deleted file mode 100644 index 8aa9ef623..000000000 --- a/examples/docs/feat-output-capture/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-output-capture", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-output-capture/src/index.mts b/examples/docs/feat-output-capture/src/index.mts deleted file mode 100644 index b446e5e3b..000000000 --- a/examples/docs/feat-output-capture/src/index.mts +++ /dev/null @@ -1,17 +0,0 @@ -import { NodeRuntime } from "secure-exec"; - -const rt = await NodeRuntime.create(); - -try { - const { stdout, stderr, exitCode } = await rt.exec(` - console.log("hello from the sandbox"); - console.error("oops from the sandbox"); - process.exit(3); - `); - - console.log("exitCode:", exitCode); - console.log("stdout:", JSON.stringify(stdout)); - console.log("stderr:", JSON.stringify(stderr)); -} finally { - await rt.dispose(); -} diff --git a/examples/docs/feat-output-capture/tsconfig.json b/examples/docs/feat-output-capture/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-output-capture/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-permissions/package.json b/examples/docs/feat-permissions/package.json deleted file mode 100644 index 0cbc358ba..000000000 --- a/examples/docs/feat-permissions/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-permissions", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-permissions/src/index.mts b/examples/docs/feat-permissions/src/index.mts deleted file mode 100644 index 9123177e3..000000000 --- a/examples/docs/feat-permissions/src/index.mts +++ /dev/null @@ -1,67 +0,0 @@ -import { NodeRuntime } from "secure-exec"; - -// Permissions are a per-domain policy evaluated against every guest syscall. -// Each domain (fs, network, childProcess, process, env) is configured -// independently as "allow", "deny", or a rule set. Here the guest may use the -// filesystem, but the network is fully denied - so an outbound fetch is blocked -// by the kernel before any socket is opened. -const rt = await NodeRuntime.create({ - permissions: { - fs: "allow", - network: "deny", - childProcess: "allow", - process: "allow", - env: "allow", - }, -}); - -try { - // Guest code runs as an ES module inside the VM. The filesystem write/read - // succeeds because fs is allowed; the fetch() throws because the kernel - // rejects the connection with EACCES from the network policy. - const { value, stdout, stderr, exitCode } = await rt.run<{ - fileContents: string; - networkBlocked: boolean; - networkError: string | null; - }>(` - const { mkdirSync, writeFileSync, readFileSync } = await import("node:fs"); - - // Allowed: filesystem access is permitted. - mkdirSync("/workspace", { recursive: true }); - writeFileSync("/workspace/note.txt", "written inside the sandbox"); - const fileContents = readFileSync("/workspace/note.txt", "utf8"); - console.log("filesystem allowed:", fileContents); - - // Denied: the network domain is set to "deny", so fetch() is blocked. - let networkBlocked = false; - let networkError = null; - try { - await fetch("http://example.com"); - console.log("UNEXPECTED: fetch succeeded"); - } catch (error) { - networkBlocked = true; - networkError = (error.cause && error.cause.message) || error.message; - console.log("network denied:", networkError); - } - - __return({ fileContents, networkBlocked, networkError }); - `); - - console.log("---"); - console.log("exitCode:", exitCode); - if (stderr.trim()) console.log("guest stderr:", stderr.trim()); - console.log("guest stdout:\n" + stdout.trim()); - console.log("file contents:", value?.fileContents); - console.log("network blocked:", value?.networkBlocked); - console.log("network error:", value?.networkError); - - if (value?.fileContents !== "written inside the sandbox") { - throw new Error("expected allowed filesystem write/read to succeed"); - } - if (!value?.networkBlocked) { - throw new Error("expected denied network fetch to be blocked"); - } - console.log("OK: filesystem allowed, network denied"); -} finally { - await rt.dispose(); -} diff --git a/examples/docs/feat-permissions/tsconfig.json b/examples/docs/feat-permissions/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-permissions/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-resource-limits/package.json b/examples/docs/feat-resource-limits/package.json deleted file mode 100644 index 5c15c5cbf..000000000 --- a/examples/docs/feat-resource-limits/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-resource-limits", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-resource-limits/src/index.mts b/examples/docs/feat-resource-limits/src/index.mts deleted file mode 100644 index 857b3f68b..000000000 --- a/examples/docs/feat-resource-limits/src/index.mts +++ /dev/null @@ -1,39 +0,0 @@ -import { NodeRuntime } from "secure-exec"; - -const rt = await NodeRuntime.create(); - -try { - // A normal program finishes well within the timeout budget. - const ok = await rt.exec(`console.log("finished work");`, { - timeout: 5000, - }); - console.log("normal run:"); - console.log(" exitCode:", ok.exitCode); - console.log(" stdout:", JSON.stringify(ok.stdout.trim())); - - // A runaway program (infinite loop) never returns on its own. The exec - // timeout terminates the guest process after the budget elapses. - const start = Date.now(); - const runaway = await rt.exec(`while (true) {}`, { - timeout: 1000, - }); - const elapsed = Date.now() - start; - - console.log("runaway run (timeout: 1000ms):"); - console.log(" exitCode:", runaway.exitCode); - console.log(" elapsedMs:", elapsed); - - // A killed process exits non-zero; a clean exit would be 0. - const terminated = runaway.exitCode !== 0; - console.log( - terminated - ? "runaway guest was terminated by the timeout" - : "ERROR: runaway guest was NOT terminated", - ); - - if (!terminated) { - process.exitCode = 1; - } -} finally { - await rt.dispose(); -} diff --git a/examples/docs/feat-resource-limits/tsconfig.json b/examples/docs/feat-resource-limits/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-resource-limits/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-runtime-platform/package.json b/examples/docs/feat-runtime-platform/package.json deleted file mode 100644 index 86c52cba0..000000000 --- a/examples/docs/feat-runtime-platform/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-runtime-platform", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-runtime-platform/src/index.mts b/examples/docs/feat-runtime-platform/src/index.mts deleted file mode 100644 index 63a4a016e..000000000 --- a/examples/docs/feat-runtime-platform/src/index.mts +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Runtime & Platform - what host environment guest JavaScript sees. - * - * The `NodeRuntime` façade boots a fully virtualized VM and runs guest code on - * the **Node platform**: the `process` and `Buffer` globals, `node:*` builtin - * modules, and full npm-style module resolution are all present. This is the - * one platform the façade exposes today; the lower-level esbuild-style - * `platform` knob (browser | neutral | bare) is not surfaced by `NodeRuntime`. - * - * This example proves the Node surface is live by having guest code probe its - * own globals and builtins, then return a structured report to the host. - */ - -import { NodeRuntime } from "secure-exec"; - -const rt = await NodeRuntime.create(); - -try { - // Probe the guest's host environment from inside the kernel-backed isolate. - const probe = await rt.run<{ - platform: string; - hasProcess: boolean; - hasBuffer: boolean; - nodeVersion: string; - sha256: string; - joinedPath: string; - }>(` - const { createHash } = await import("node:crypto"); - const { join } = await import("node:path"); - - const sha256 = createHash("sha256").update("secure-exec").digest("hex"); - - globalThis.__return({ - // process/Buffer are Node-platform globals (absent on browser/neutral/bare). - platform: typeof process !== "undefined" ? process.platform : "(no process)", - hasProcess: typeof process !== "undefined", - hasBuffer: typeof Buffer !== "undefined", - nodeVersion: typeof process !== "undefined" ? process.versions.node : "(none)", - // node:* builtin modules resolve and run inside the isolate - // (dynamic import() keeps this snippet a single expression body). - sha256, - joinedPath: join("/home/agentos", "report.txt"), - }); - `); - - if (probe.exitCode !== 0) { - throw new Error(`guest probe failed (exit ${probe.exitCode}): ${probe.stderr}`); - } - - const r = probe.value!; - console.log("Guest host environment (Node platform):"); - console.log(` process global present : ${r.hasProcess}`); - console.log(` Buffer global present : ${r.hasBuffer}`); - console.log(` process.platform : ${r.platform}`); - console.log(` process.versions.node : ${r.nodeVersion}`); - console.log(` node:crypto sha256 : ${r.sha256}`); - console.log(` node:path join : ${r.joinedPath}`); - - // And a plain exec() run, showing stdout capture with the same Node surface. - const hello = await rt.exec( - `console.log("hello from", process.platform, "/ Buffer:", Buffer.from("hi").toString("base64"));`, - ); - console.log("\nexec() stdout:"); - process.stdout.write(` ${hello.stdout}`); - console.log(`exec() exitCode: ${hello.exitCode}`); -} finally { - await rt.dispose(); -} diff --git a/examples/docs/feat-runtime-platform/tsconfig.json b/examples/docs/feat-runtime-platform/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-runtime-platform/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-typescript/package.json b/examples/docs/feat-typescript/package.json deleted file mode 100644 index 3df5feb3a..000000000 --- a/examples/docs/feat-typescript/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-typescript", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "@secure-exec/typescript": "workspace:*", - "secure-exec": "workspace:*", - "typescript": "^5.7.2" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2" - } -} diff --git a/examples/docs/feat-typescript/src/index.mts b/examples/docs/feat-typescript/src/index.mts deleted file mode 100644 index 21ab85a8a..000000000 --- a/examples/docs/feat-typescript/src/index.mts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * TypeScript example. - * - * `@secure-exec/typescript` runs the TypeScript compiler INSIDE the sandbox. - * The compiler is projected into the VM and every compile/type-check happens - * in the guest, so untrusted TypeScript never executes (or compiles) on the - * host. Here we compile a typed snippet to JavaScript, run the emitted code in - * the sandbox, and type-check a snippet that has a type error. - */ -import { createTypeScriptTools } from "@secure-exec/typescript"; -import { NodeRuntime } from "secure-exec"; - -const tools = createTypeScriptTools(); - -// A typed snippet we want to compile and run inside the sandbox. -const typeScriptSource = ` -interface Greeting { - name: string; - count: number; -} - -const greeting: Greeting = { name: "secure-exec", count: 3 }; -const lines: string[] = Array.from( - { length: greeting.count }, - (_unused, index) => \`hello \${greeting.name} #\${index + 1}\`, -); - -for (const line of lines) { - console.log(line); -} -`; - -// Step 1: compile TypeScript to JavaScript inside the sandbox. -const compiled = await tools.compileSource({ - sourceText: typeScriptSource, - compilerOptions: { module: "ESNext", target: "ES2022" }, -}); - -if (!compiled.success) { - const messages = compiled.diagnostics.map((d) => d.message); - throw new Error(`TypeScript compile failed:\n${messages.join("\n")}`); -} - -console.log("Compiled TypeScript to JavaScript inside the sandbox."); - -// Step 2: run the emitted JavaScript inside the sandbox. -const rt = await NodeRuntime.create(); -try { - const result = await rt.exec(compiled.outputText ?? ""); - console.log("exitCode:", result.exitCode); - console.log("guest stdout:\n" + result.stdout.trimEnd()); -} finally { - await rt.dispose(); -} - -// Step 3: type-check a snippet that has a type error inside the sandbox. -const typeCheck = await tools.typecheckSource({ - sourceText: `const total: number = "not a number";`, -}); - -console.log("type check success:", typeCheck.success); -for (const diagnostic of typeCheck.diagnostics) { - console.log( - ` ${diagnostic.category} TS${diagnostic.code} (line ${diagnostic.line}): ${diagnostic.message}`, - ); -} - -if (typeCheck.success) { - throw new Error("Expected the ill-typed snippet to fail type checking."); -} - -console.log("OK: TypeScript compiled and type-checked inside the sandbox."); diff --git a/examples/docs/feat-typescript/tsconfig.json b/examples/docs/feat-typescript/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-typescript/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/feat-virtual-filesystem/package.json b/examples/docs/feat-virtual-filesystem/package.json deleted file mode 100644 index 3f81073a9..000000000 --- a/examples/docs/feat-virtual-filesystem/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-feat-virtual-filesystem", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/feat-virtual-filesystem/src/index.mts b/examples/docs/feat-virtual-filesystem/src/index.mts deleted file mode 100644 index 60b3cae79..000000000 --- a/examples/docs/feat-virtual-filesystem/src/index.mts +++ /dev/null @@ -1,42 +0,0 @@ -import { NodeRuntime } from "secure-exec"; - -// Boot a VM and seed a file into its virtual filesystem at boot with `files`. -// The bytes are copied into the kernel's in-memory filesystem; the host -// filesystem is never exposed to the guest. -const rt = await NodeRuntime.create({ - files: { "/home/agentos/seed.json": JSON.stringify({ ok: true }) }, -}); - -try { - // Write another file from the host with rt.writeFile, then have the guest - // read both back. The guest only ever sees the virtual filesystem. - await rt.writeFile("/home/agentos/note.txt", "written from the host\n"); - - const result = await rt.run(` - const { readFileSync } = await import("node:fs"); - const seed = JSON.parse(readFileSync("/home/agentos/seed.json", "utf8")); - const note = readFileSync("/home/agentos/note.txt", "utf8").trim(); - console.log("guest read seed:", JSON.stringify(seed)); - console.log("guest read note:", note); - globalThis.__return({ seed, note }); - `); - - console.log("guest stdout:", result.stdout.trim()); - console.log("guest exit code:", result.exitCode); - console.log("value returned to host:", result.value); - - // Read a guest-written file back on the host with rt.readFile. - const bytes = await rt.readFile("/home/agentos/seed.json"); - console.log("host rt.readFile:", new TextDecoder().decode(bytes)); - - // The virtual filesystem is isolated from the host disk. The guest path does - // not exist on the real host - prove it by checking the same path here. - const { existsSync } = await import("node:fs"); - const guestPath = "/home/agentos/seed.json"; - console.log( - `host sees ${guestPath}?`, - existsSync(guestPath) ? "YES (unexpected!)" : "NO - isolated from host", - ); -} finally { - await rt.dispose(); -} diff --git a/examples/docs/feat-virtual-filesystem/tsconfig.json b/examples/docs/feat-virtual-filesystem/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/feat-virtual-filesystem/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/process-isolation/package.json b/examples/docs/process-isolation/package.json deleted file mode 100644 index 01ebd5f93..000000000 --- a/examples/docs/process-isolation/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-process-isolation", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/process-isolation/src/index.mts b/examples/docs/process-isolation/src/index.mts deleted file mode 100644 index 136c189db..000000000 --- a/examples/docs/process-isolation/src/index.mts +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Process isolation example. - * - * Each `NodeRuntime.create()` boots a fully virtualized VM. Two runtimes share - * nothing: not the filesystem, not globals, not module state. And within a - * single runtime, every `exec()` / `run()` call runs a fresh guest process, so - * one run cannot leak in-memory state into the next. - * - * This example demonstrates both boundaries: - * - * 1. Two separate runtimes (A and B) write the same path and read it back - - * neither sees the other's data, proving filesystem isolation. - * 2. Two consecutive runs in the SAME runtime mutate a global - the second - * run starts clean, proving each run is a fresh process with no shared - * in-memory state. - * - * Run with: - * SECURE_EXEC_SIDECAR_BIN=../../../target/debug/secure-exec-sidecar \ - * npx tsx src/index.mts - */ - -import { NodeRuntime } from "secure-exec"; - -// Boot two independent VMs. Each is its own isolation domain. -const rtA = await NodeRuntime.create(); -const rtB = await NodeRuntime.create(); - -try { - // --- 1. Filesystem isolation between two runtimes --------------------- - // Both runtimes write to the exact same path. Because each runtime has its - // own virtual filesystem, the writes never collide. - await rtA.exec(` - import { writeFileSync } from "node:fs"; - writeFileSync("/tmp/shared-path.txt", "data from runtime A"); - `); - await rtB.exec(` - import { writeFileSync } from "node:fs"; - writeFileSync("/tmp/shared-path.txt", "data from runtime B"); - `); - - // `run()` wraps the body in an async function, so use dynamic `import()` - // (top-level `import` statements only work in `exec()`). - const readA = await rtA.run(` - const { readFileSync } = await import("node:fs"); - __return(readFileSync("/tmp/shared-path.txt", "utf8")); - `); - const readB = await rtB.run(` - const { readFileSync } = await import("node:fs"); - __return(readFileSync("/tmp/shared-path.txt", "utf8")); - `); - - console.log("runtime A reads back:", JSON.stringify(readA.value)); - console.log("runtime B reads back:", JSON.stringify(readB.value)); - console.log( - "filesystems isolated:", - readA.value === "data from runtime A" && - readB.value === "data from runtime B", - ); - - // Confirm a file created only in B does not exist in A. - const beforeWrite = await rtA.run(` - const { existsSync } = await import("node:fs"); - __return(existsSync("/tmp/only-in-b.txt")); - `); - await rtB.exec(` - import { writeFileSync } from "node:fs"; - writeFileSync("/tmp/only-in-b.txt", "B"); - `); - const afterWrite = await rtA.run(` - const { existsSync } = await import("node:fs"); - __return(existsSync("/tmp/only-in-b.txt")); - `); - console.log( - "/tmp/only-in-b.txt visible in A:", - beforeWrite.value, - "->", - afterWrite.value, - ); - - // --- 2. Each run is a fresh process (no shared globals) ---------------- - // The first run sets a global. The second run, in the SAME runtime, observes - // a clean global state because it is a brand new guest process. - const firstRun = await rtA.run(` - globalThis.__counter = (globalThis.__counter ?? 0) + 1; - __return(globalThis.__counter); - `); - const secondRun = await rtA.run(` - globalThis.__counter = (globalThis.__counter ?? 0) + 1; - __return(globalThis.__counter); - `); - - console.log("run 1 counter:", firstRun.value); - console.log("run 2 counter:", secondRun.value); - console.log( - "globals reset per run:", - firstRun.value === 1 && secondRun.value === 1, - ); -} finally { - // Each runtime owns its VM and must be disposed independently. - await rtA.dispose(); - await rtB.dispose(); -} diff --git a/examples/docs/process-isolation/tsconfig.json b/examples/docs/process-isolation/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/process-isolation/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/quickstart/package.json b/examples/docs/quickstart/package.json deleted file mode 100644 index d84b5e5b8..000000000 --- a/examples/docs/quickstart/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-quickstart", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/quickstart/src/index.mts b/examples/docs/quickstart/src/index.mts deleted file mode 100644 index f06abb541..000000000 --- a/examples/docs/quickstart/src/index.mts +++ /dev/null @@ -1,21 +0,0 @@ -import { NodeRuntime } from "secure-exec"; - -// Boot a fully virtualized runtime. Guest code runs inside the kernel -// isolation boundary - no host escapes. -const runtime = await NodeRuntime.create(); - -try { - // run() executes guest JavaScript as an ES module and returns the value the - // guest passes to globalThis.__return(). stdout/stderr are captured too. - const result = await runtime.run<{ message: string; sum: number }>(` - console.log("hello from secure-exec"); - __return({ message: "hello from secure-exec", sum: 1 + 2 }); - `); - - console.log("stdout:", JSON.stringify(result.stdout.trim())); - console.log("value:", result.value); - console.log("exitCode:", result.exitCode); -} finally { - // Tear down the VM and release the sidecar. - await runtime.dispose(); -} diff --git a/examples/docs/quickstart/tsconfig.json b/examples/docs/quickstart/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/quickstart/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/sdk-overview/package.json b/examples/docs/sdk-overview/package.json deleted file mode 100644 index 3cb7c6c79..000000000 --- a/examples/docs/sdk-overview/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-sdk-overview", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/sdk-overview/src/index.mts b/examples/docs/sdk-overview/src/index.mts deleted file mode 100644 index 8fdeda77a..000000000 --- a/examples/docs/sdk-overview/src/index.mts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * SDK Overview example. - * - * A guided tour of the secure-exec façade: - * - NodeRuntime.create(options) boots a fully virtualized VM. - * - exec(code) runs guest JavaScript and captures stdout/stderr/exitCode. - * - run(code) runs guest JavaScript and returns a JSON value via __return(). - * - dispose() tears down the VM. - * - * Run with: - * SECURE_EXEC_SIDECAR_BIN=../../../target/debug/secure-exec-sidecar \ - * npx tsx src/index.mts - */ - -import { NodeRuntime } from "secure-exec"; - -// Boot a VM. Every option here is optional; these are the defaults made -// explicit. `cwd` defaults to "/workspace" and permissions default to allow-all. -const rt = await NodeRuntime.create({ - env: { GREETING: "hello from the VM env" }, - cwd: "/workspace", -}); - -try { - // exec() runs guest code for its output. Guest code is an ES module, so - // `import` and top-level `await` both work. - const execResult = await rt.exec( - ` - import os from "node:os"; - console.log("stdout:", 1 + 1); - console.error("stderr:", process.env.GREETING); - console.log("platform:", os.platform()); - `, - ); - console.log("exec.stdout: ", JSON.stringify(execResult.stdout)); - console.log("exec.stderr: ", JSON.stringify(execResult.stderr)); - console.log("exec.exitCode:", execResult.exitCode); - - // run() returns a JSON-serializable value: the guest calls - // globalThis.__return(value) and that value is decoded on the host. - const runResult = await rt.run<{ sum: number; cwd: string }>( - ` - globalThis.__return({ sum: 2 + 40, cwd: process.cwd() }); - console.log("computed in the VM"); - `, - ); - console.log("run.value: ", JSON.stringify(runResult.value)); - console.log("run.stdout: ", JSON.stringify(runResult.stdout)); - console.log("run.exitCode: ", runResult.exitCode); - - // Per-run options: extra env, stdin, cwd, and a timeout (ms). - const stdinResult = await rt.run( - ` - let input = ""; - for await (const chunk of process.stdin) input += chunk; - globalThis.__return(input.trim().toUpperCase()); - `, - { stdin: "piped through stdin", timeout: 10_000 }, - ); - console.log("run.value (stdin):", JSON.stringify(stdinResult.value)); -} finally { - // Always release the VM and the underlying sidecar. - await rt.dispose(); - console.log("disposed"); -} diff --git a/examples/docs/sdk-overview/tsconfig.json b/examples/docs/sdk-overview/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/sdk-overview/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/uc-ai-agent-code-exec/package.json b/examples/docs/uc-ai-agent-code-exec/package.json deleted file mode 100644 index 919d9f4b7..000000000 --- a/examples/docs/uc-ai-agent-code-exec/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-uc-ai-agent-code-exec", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/uc-ai-agent-code-exec/src/index.mts b/examples/docs/uc-ai-agent-code-exec/src/index.mts deleted file mode 100644 index 63a19217d..000000000 --- a/examples/docs/uc-ai-agent-code-exec/src/index.mts +++ /dev/null @@ -1,38 +0,0 @@ -import { NodeRuntime } from "secure-exec"; - -// Imagine this string came from an AI agent. We never trust it: it runs fully -// sandboxed inside the secure-exec VM, with no access to the host machine. -const untrustedCode = ` -const fib = [0, 1]; -while (fib.length < 20) { - fib.push(fib[fib.length - 1] + fib[fib.length - 2]); -} -console.log("computed", fib.length, "fibonacci numbers"); -// Hand a JSON-serializable value back to the host. -globalThis.__return({ fibonacci: fib, sum: fib.reduce((a, b) => a + b, 0) }); -`; - -const rt = await NodeRuntime.create(); -try { - // rt.run() executes the guest code and decodes whatever it passes to - // globalThis.__return(), while still capturing stdout/stderr/exitCode. - const result = await rt.run<{ fibonacci: number[]; sum: number }>( - untrustedCode, - { timeout: 5000 }, - ); - - console.log("exitCode:", result.exitCode); - console.log("stdout:", result.stdout.trim()); - console.log("returned value:", JSON.stringify(result.value)); - - // The sandbox presents normal Node semantics, but the code cannot touch the - // host: it only ever sees the virtual filesystem and kernel-mediated syscalls. - const escapeAttempt = await rt.exec( - `import os from "node:os";\nconsole.log("guest hostname:", os.hostname());`, - { timeout: 5000 }, - ); - console.log("\nescape attempt exitCode:", escapeAttempt.exitCode); - console.log("escape attempt stdout:", escapeAttempt.stdout.trim()); -} finally { - await rt.dispose(); -} diff --git a/examples/docs/uc-ai-agent-code-exec/tsconfig.json b/examples/docs/uc-ai-agent-code-exec/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/uc-ai-agent-code-exec/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/uc-code-mode/package.json b/examples/docs/uc-code-mode/package.json deleted file mode 100644 index 1cf67742e..000000000 --- a/examples/docs/uc-code-mode/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-uc-code-mode", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/uc-code-mode/src/index.mts b/examples/docs/uc-code-mode/src/index.mts deleted file mode 100644 index e41bcd02d..000000000 --- a/examples/docs/uc-code-mode/src/index.mts +++ /dev/null @@ -1,110 +0,0 @@ -// docs:start bindings -import { NodeRuntime } from "secure-exec"; - -function readStringField(input: unknown, field: string): string { - if (!input || typeof input !== "object" || Array.isArray(input)) { - throw new TypeError("binding input must be an object"); - } - - const value = (input as Record)[field]; - if (typeof value !== "string") { - throw new TypeError(`${field} must be a string`); - } - return value; -} - -// Code Mode: instead of giving the LLM many individual bindings, you give it one -// "execute code" tool. The LLM writes JavaScript that chains binding calls, -// branches, and transforms data - then runs it in a single sandboxed pass. -// -// The heart of Code Mode is real bindings. You register them on the host with -// create({ bindings }); each becomes a named command inside the sandbox. When the -// guest invokes a binding by name with JSON input, the call round-trips back to the -// host, runs the binding's handler, and the handler's return value is delivered -// back to the guest. The guest never sees the host filesystem, network, or any -// capability beyond the named bindings you grant it. - -// Register the bindings. These handlers run on the HOST, not in the sandbox. -// In a real app each handler would hit a database, an API, or a service; here we -// keep them small and deterministic so the example is easy to follow. -const rt = await NodeRuntime.create({ - bindings: { - "get-weather": { - description: "Look up the current temperature for a city", - inputSchema: { - type: "object", - properties: { city: { type: "string" } }, - required: ["city"], - }, - handler: (input) => { - const city = readStringField(input, "city"); - const table: Record = { - "San Francisco": { temp_f: 61 }, - Tokyo: { temp_f: 75 }, - }; - return table[city] ?? { temp_f: null }; - }, - }, - calculate: { - description: "Evaluate a simple arithmetic expression", - inputSchema: { - type: "object", - properties: { expression: { type: "string" } }, - required: ["expression"], - }, - handler: (input) => { - const expression = readStringField(input, "expression"); - return { result: Number(eval(expression)) }; - }, - }, - }, -}); -// docs:end bindings - -// docs:start generated-code -// Imagine this string was written by the LLM. It chains three host binding calls -// with real control flow (Promise.all, arithmetic, branching) in one execution, -// then hands a single structured result back to the host. callBinding resolves -// with the host handler's return value. -const llmGeneratedCode = ` -const [sf, tokyo] = await Promise.all([ - callBinding("get-weather", { city: "San Francisco" }), - callBinding("get-weather", { city: "Tokyo" }), -]); - -const diffF = Math.abs(sf.temp_f - tokyo.temp_f); -const diffC = await callBinding("calculate", { expression: \`\${diffF} * 5 / 9\` }); - -console.log("chained 3 binding calls in one sandbox execution"); - -globalThis.__return({ - san_francisco: sf, - tokyo: tokyo, - difference: { fahrenheit: diffF, celsius: diffC.result }, - warmer: sf.temp_f > tokyo.temp_f ? "San Francisco" : "Tokyo", -}); -`; -// docs:end generated-code - -// docs:start run -interface CodeModeResult { - san_francisco: { temp_f: number }; - tokyo: { temp_f: number }; - difference: { fahrenheit: number; celsius: number }; - warmer: string; -} - -try { - // rt.run() executes the guest code and decodes whatever it passes to - // globalThis.__return(), while still capturing stdout/stderr/exitCode. - const result = await rt.run(llmGeneratedCode, { - timeout: 5000, - }); - - console.log("exitCode:", result.exitCode); - console.log("stdout:", result.stdout.trim()); - console.log("structured result:", JSON.stringify(result.value, null, 2)); -} finally { - await rt.dispose(); -} -// docs:end run diff --git a/examples/docs/uc-code-mode/tsconfig.json b/examples/docs/uc-code-mode/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/uc-code-mode/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/uc-dev-servers/package.json b/examples/docs/uc-dev-servers/package.json deleted file mode 100644 index 47c503932..000000000 --- a/examples/docs/uc-dev-servers/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-uc-dev-servers", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/uc-dev-servers/src/index.mts b/examples/docs/uc-dev-servers/src/index.mts deleted file mode 100644 index 69f92b3c9..000000000 --- a/examples/docs/uc-dev-servers/src/index.mts +++ /dev/null @@ -1,83 +0,0 @@ -import { NodeRuntime } from "secure-exec"; - -// A user's "dev server": untrusted, long-running server-style code. It boots a -// real node:http server and keeps serving until the host cancels this exec. -const devServer = ` -import http from "node:http"; - -const app = http.createServer((req, res) => { - if (req.url === "/health") { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify({ ok: true })); - return; - } - res.writeHead(200, { "content-type": "text/plain" }); - res.end("hello from " + req.url); -}); - -app.listen(3000, "127.0.0.1", () => { - console.log("server listening on 127.0.0.1:3000"); -}); - -await new Promise(() => {}); -`; - -const runtime = await NodeRuntime.create({ permissions: { network: "allow" } }); -const serverAbort = new AbortController(); -const stdoutDecoder = new TextDecoder(); -let ready!: () => void; -const serverReady = new Promise((resolve) => { - ready = resolve; -}); - -try { - const serverExec = runtime - .exec(devServer, { - signal: serverAbort.signal, - onStdout: (chunk) => { - const text = stdoutDecoder.decode(chunk); - process.stdout.write(text); - if (text.includes("server listening")) { - ready(); - } - }, - }) - .catch((error: unknown) => { - if (serverAbort.signal.aborted) { - return; - } - throw error; - }); - - await serverReady; - - // Drive a host->guest request into the running server. - const health = await runtime.fetch(3000, { path: "/health" }); - console.log("host health ->", health.status, JSON.stringify(health.body)); - - const hostRes = await runtime.fetch(3000, { method: "GET", path: "/from-host" }); - console.log("host GET ->", hostRes.status, JSON.stringify(hostRes.body)); - - // Run another guest program in the same VM while the server exec is still - // active. Its fetch() reaches the server through VM loopback. - const guestClient = await runtime.exec(` -const response = await fetch("http://127.0.0.1:3000/from-guest"); -console.log(response.status + " " + await response.text()); -`); - console.log("guest fetch ->", JSON.stringify(guestClient.stdout.trim())); - - console.log( - "RESULT " + - JSON.stringify({ - host: { status: hostRes.status, body: hostRes.body }, - guest: guestClient.stdout.trim(), - }), - ); - - serverAbort.abort(); - await serverExec; - console.log("server stopped"); -} finally { - serverAbort.abort(); - await runtime.dispose(); -} diff --git a/examples/docs/uc-dev-servers/tsconfig.json b/examples/docs/uc-dev-servers/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/uc-dev-servers/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/docs/uc-plugin-systems/package.json b/examples/docs/uc-plugin-systems/package.json deleted file mode 100644 index a662e3201..000000000 --- a/examples/docs/uc-plugin-systems/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@secure-exec/example-docs-uc-plugin-systems", - "private": true, - "type": "module", - "scripts": { - "start": "tsx src/index.mts", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "secure-exec": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "tsx": "^4.19.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/docs/uc-plugin-systems/src/index.mts b/examples/docs/uc-plugin-systems/src/index.mts deleted file mode 100644 index 8352bee8a..000000000 --- a/examples/docs/uc-plugin-systems/src/index.mts +++ /dev/null @@ -1,68 +0,0 @@ -import { NodeRuntime } from "secure-exec"; - -// Boot a sandboxed VM for running untrusted plugin code. The plugin can use -// the filesystem, but network access is denied. (childProcess/process stay -// allowed because the kernel spawns the guest `node` process to run the -// plugin - denying it would block the runtime itself.) -const runtime = await NodeRuntime.create({ - permissions: { - fs: "allow", - network: "deny", - childProcess: "allow", - process: "allow", - env: "allow", - }, -}); - -try { - // The host owns the plugin source and the input. Here the plugin is a - // title-case transformer; in a real system it would be uploaded by a user. - const pluginSource = ` - function transform(input, options = {}) { - const words = String(input) - .split(/\\s+/) - .filter(Boolean) - .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()); - return (options.prefix ?? "") + words.join(" "); - } - const manifest = { name: "title-case", version: "1.0.0" }; - `; - - const input = "hello from plugin land"; - const options = { prefix: "Plugin says: " }; - - // Run the plugin in isolation and get a structured value back via run(). - // The guest calls __return() with a JSON-serializable value, decoded on the - // host as result.value. The plugin also proves it cannot reach the network. - const { value, stdout, exitCode } = await runtime.run<{ - manifest: { name: string; version: string }; - output: string; - networkBlocked: boolean; - }>(` - ${pluginSource} - - console.log("running plugin:", manifest.name); - - let networkBlocked = false; - try { - await fetch("http://example.com"); - } catch { - networkBlocked = true; - } - - __return({ - manifest, - output: transform(${JSON.stringify(input)}, ${JSON.stringify(options)}), - networkBlocked, - }); - `); - - console.log("guest stdout:", stdout.trim()); - console.log("exit code:", exitCode); - console.log("plugin name:", value?.manifest.name); - console.log("plugin version:", value?.manifest.version); - console.log("plugin output:", value?.output); - console.log("network blocked:", value?.networkBlocked); -} finally { - await runtime.dispose(); -} diff --git a/examples/docs/uc-plugin-systems/tsconfig.json b/examples/docs/uc-plugin-systems/tsconfig.json deleted file mode 100644 index 5ead5b22d..000000000 --- a/examples/docs/uc-plugin-systems/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/examples/native-client/package.json b/examples/native-client/package.json deleted file mode 100644 index 94cf1c9ae..000000000 --- a/examples/native-client/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "@secure-exec/example-native-client", - "private": true, - "type": "module", - "scripts": { - "build": "tsc", - "check-types": "tsc --noEmit" - }, - "dependencies": { - "@secure-exec/core": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "typescript": "^5.7.2" - } -} diff --git a/examples/native-client/src/index.ts b/examples/native-client/src/index.ts deleted file mode 100644 index 7c1c3e471..000000000 --- a/examples/native-client/src/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Sidecar } from "@secure-exec/core/sidecar-client"; - -const decoder = new TextDecoder(); - -const client = Sidecar.spawn({ - cwd: process.cwd(), -}); - -try { - const session = await client.authenticateAndOpenSession({ - example: "native-client", - }); - const vm = await client.createVm(session, { - runtime: "java_script", - config: { - env: {}, - rootFilesystem: { - mode: "ephemeral", - disableDefaultBaseLayer: false, - lowers: [{ kind: "bundledBaseFilesystem" }], - bootstrapEntries: [], - }, - loopbackExemptPorts: [], - }, - }); - - try { - await client.writeFile( - session, - vm, - "/tmp/message.txt", - "hello from secure-exec\n", - ); - const content = await client.readFile(session, vm, "/tmp/message.txt"); - console.log(decoder.decode(content).trim()); - } finally { - await client.disposeVm(session, vm); - } -} finally { - await client.dispose(); -} diff --git a/examples/native-client/tsconfig.json b/examples/native-client/tsconfig.json deleted file mode 100644 index 1cbed3479..000000000 --- a/examples/native-client/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/experiments/wasm-gui/README.md b/experiments/wasm-gui/README.md deleted file mode 100644 index 2e33d9047..000000000 --- a/experiments/wasm-gui/README.md +++ /dev/null @@ -1,127 +0,0 @@ -# wasm-gui — a GUI rendered by wasm running inside secure-exec - -A spike toward a full Linux GUI desktop where the GUI software is **cross-compiled to -`wasm32-wasip1`** (our toolchain) and **executed inside the real secure-exec V8 sidecar**, with a -native host (built on the standard secure-exec **Rust** client) reading the rendered framebuffer -and blitting it to a native surface. See `SPEC.md` and `../../WASM-GUI-DESKTOP-RESEARCH.md`. - -**Strict constraint (SPEC §1a.2):** the process that executes *and* renders the guest is a native -app on `crates/secure-exec-client`, driving the guest through the real V8 sidecar. No wasmer, no -node:wasi, no TypeScript client, no `Command::new` in the execution/render path — the only process -spawn is the sidecar itself, done by the Rust client's transport. - -``` -guest/ Rust -> wasm32-wasip1 software renderer + frame protocol v0 (standalone wasm workspace) -host/ native Rust app on secure-exec-client: runs guest.wasm IN the sidecar, blits frames - (member of the repo root workspace, shares Cargo.lock with the sidecar) -tests/ automated headless verification THROUGH secure-exec (build, run, golden pixels, PNG) -host-node/ SUPERSEDED node:wasi spike (determinism evidence only; not the product path) -``` - -## Run the automated test (headless — no display needed) - -```sh -cd experiments/wasm-gui -./tests/run.sh -``` -This builds the guest, builds the host + sidecar in the repo root workspace, runs `guest.wasm` -**inside the secure-exec V8 sidecar** via the Rust client, reads the framebuffer back through the -client (chunked PREAD), validates the frame header, checks golden pixels, and writes a PNG proof to -`~/tmp/gui-progress/assets/frame_secureexec.png`. Re-bless the golden after an intentional renderer -change with `./tests/run.sh --bless`. - -Requirements: `cargo` + the `wasm32-wasip1` target (`rustup target add wasm32-wasip1`), `node` -(only for the pixel checker), and `ffmpeg` (PNG proof only). The sidecar is built from this repo. - -## Run capture directly (what the test does) - -```sh -# from repo root, after `cargo build -p secure-exec-sidecar -p wasm-gui-host` -target/debug/wasm-gui-host \ - --capture /tmp/frame.bin \ - --guest experiments/wasm-gui/guest/target/wasm32-wasip1/release/guest.wasm \ - --sidecar target/debug/secure-exec-sidecar -``` - -## Run the interactive window demo (on a machine WITH a display) - -```sh -cd experiments/wasm-gui/guest && cargo build --target wasm32-wasip1 --release && cd - -cargo build -p wasm-gui-host --features window -target/debug/wasm-gui-host --window \ - --guest experiments/wasm-gui/guest/target/wasm32-wasip1/release/guest.wasm \ - --sidecar target/debug/secure-exec-sidecar -``` -Opens a real OS window. The guest runs in `--loop` mode *inside the sidecar*; the host streams its -stdout frames (`ProcessOutputEvent`) through the client, blits them, and forwards mouse/keyboard -back via `WriteStdin`. This dev box is headless, so the window can't open here; the PNG proof shows -the identical frame. - -## Run the real X11 stack (M4 / M4b / M5) — a wasm X server + wasm X clients - -The frontier milestones cross-compile the **real X.Org `Xvfb` X server** and X **clients** from source to -`wasm32-wasip1` and run them **as guests inside secure-exec**, talking X11 over an AF_UNIX socket in the -kernel socket table. Build the pieces, then run: - -```sh -# 1. Build the sidecar + host (repo root) -cargo build -p secure-exec-sidecar -p wasm-gui-host - -# 2. Build the raw-X11 client (the X server, Xvfb.wasm, is built by scripts/link-xvfb.sh + -# a `wasm-opt --fpcast-emu` pass — see SPEC.md for the full server build). -experiments/wasm-gui/scripts/build-xfill.sh - -# 3a. M4b — one X client draws on the wasm X server; read the framebuffer back: -target/debug/wasm-gui-host --xdemo --timeout 16 \ - --server experiments/wasm-gui/Xvfb.wasm \ - --client experiments/wasm-gui/guest-xclient/xfill.wasm \ - --fb-out /tmp/frame.bin --sidecar target/debug/secure-exec-sidecar \ - -- :0 -screen 0 640x480x24 -nolisten tcp -nolock -listen local -fbdir /data - -# 3c. M5 — the standard window manager twm decorating a real libX11 client window: -# (build the toolkit stack + twm + xwin first; see SPEC.md §M5 for the build commands) -target/debug/wasm-gui-host --xdemo --timeout 30 \ - --server experiments/wasm-gui/Xvfb.wasm \ - --client experiments/wasm-gui/twm.wasm \ - --client experiments/wasm-gui/guest-xclient/xwin.wasm \ - --fb-out /tmp/frame.bin --sidecar target/debug/secure-exec-sidecar \ - -- :0 -screen 0 640x480x24 -nolisten tcp -nolock -listen local -noreset -fbdir /data -# Automated: scripts/test-m5-twm.sh (asserts twm decorates the window with a title bar) - -# 3b. M5 — THREE clients (orange bg, green + blue rects) composited by one X server: -target/debug/wasm-gui-host --xdemo --timeout 22 \ - --server experiments/wasm-gui/Xvfb.wasm \ - --client "experiments/wasm-gui/guest-xclient/xfill.wasm 0 0 -1 -1 16746496" \ - --client "experiments/wasm-gui/guest-xclient/xfill.wasm 80 80 200 150 65280" \ - --client "experiments/wasm-gui/guest-xclient/xfill.wasm 360 250 200 150 255" \ - --fb-out /tmp/frame.bin --sidecar target/debug/secure-exec-sidecar \ - -- :0 -screen 0 640x480x24 -nolisten tcp -nolock -listen local -noreset -fbdir /data -``` - -`/tmp/frame.bin` is an XWD dump (160-byte header + BGRX pixels) of the X server's root window, read out -of the VM via the kernel VFS. Automated equivalents: `scripts/test-m4b.sh` and -`scripts/test-m5-multiclient.sh` (both assert the framebuffer contains the clients' fill colors). -`--xdemo` runs the X server and every `--client` as **separate guest processes in one VM**, launching the -clients once the server reaches its dispatch loop, then reads the framebuffer back. - -## How it works (the data path) - -``` -guest.wasm (wasm32-wasip1) ──run inside──▶ secure-exec V8 sidecar - software-renders RGBA frames (real runtime; loads the module from the - frame protocol v0 over WASI fds trusted-client host entrypoint path) - │ frames out (PREAD / stdout events) ▲ input in (WriteStdin) - ▼ │ - native host on secure-exec-client (Rust): reads frames, blits to winit/softbuffer, sends input -``` - -Frame protocol v0: `b"SXFB" | u32 LE width | u32 LE height`, then `width*height*4` bytes row-major -`[R,G,B,A]`. Capture mode (`guest --out `) writes one deterministic frame to the guest VFS; -window mode (`guest --loop`) streams frames on stdout and reads input tokens on stdin. - -## Scope / honesty - -- The renderer is **hand-rolled**, not a real toolkit — it exercises the data path and the test - harness. Real toolkits (FLTK/Tk, then an X server + WM) are milestones M3+ in `SPEC.md`. -- The guest frame produced through secure-exec is **byte-identical** (SHA-256) to the superseded - node:wasi/wasmer spike output, which is how we know the V8 execution is faithful. diff --git a/experiments/wasm-gui/SPEC.md b/experiments/wasm-gui/SPEC.md deleted file mode 100644 index eba2b2d20..000000000 --- a/experiments/wasm-gui/SPEC.md +++ /dev/null @@ -1,416 +0,0 @@ -# Spec: WASM GUI desktop — from software-rendered frame to native surface - -Living spec (v2 — revised after subagent review; changelog at bottom). Status legend: -⬜ todo · 🟡 in progress · ✅ done · ❌ blocked. Companion research: -`../../WASM-GUI-DESKTOP-RESEARCH.md`. Progress log + proof: `~/tmp/gui-progress/progress.html`. - -## 1. North star & strategy - -Run a Raspberry-Pi-class Linux GUI desktop where the GUI software is **cross-compiled from -source to `wasm32-wasip1`** (our toolchain family) and **rendered on a native host surface** -(the runtime owns a `winit`/`softbuffer` window; browser later). Research verdict drives the -sequencing: - -- **Software rasterization → framebuffer → host blits it.** No GL/EGL/GPU in the guest. The - guest computes pixels with ordinary compute + WASI; frames cross the sandbox boundary; the - native host displays them. This single data path is the spine of every later milestone. -- **X11 over Wayland for the first real desktop** because core X11 runs entirely over a socket - and `MIT-SHM` is optional with a clean `XPutImage` fallback — so we avoid implementing shared - memory. (Wayland's `wl_shm` has no fallback.) -- **Avoid `dlopen` and shared memory.** Static-link everything; keep multi-process boundaries at - the socket/module level. Threads are acceptable later (`wasm32-wasip1-threads`) but the first - milestones are single-threaded. - -## 1a. Strict constraints (NON-NEGOTIABLE) - -1. **We compile the GUI software to wasm ourselves**, from source, with our own toolchain - (`wasm32-wasip1` / wasi-sdk family). No off-the-shelf pre-built wasm GUI ports. -2. **The process that executes the guest AND renders the GUI is a native app built on the - STANDARD secure-exec Rust client** (`crates/secure-exec-client`). That app: - - drives the guest wasm **through the real secure-exec runtime (V8 sidecar)** — the guest runs - inside secure-exec, exactly like any other guest workload; - - pulls frames out via the client and blits them to a native window it owns; - - injects input back into the guest through the client. - **Forbidden in the execution/render path:** `wasmer`, `node:wasi`, the TypeScript client, or any - `Command::new`-style direct spawn. If it runs guest pixels, it goes through secure-exec via the - Rust client. (The M0 spike that used `wasmer`/`node:wasi` is **superseded** by this rule — it - stays only as evidence the renderer is deterministic; it is not the product path.) -3. Everything is **end-to-end and automatically tested**, with a **manually runnable example**, and - the spec + `~/tmp/gui-progress/progress.html` are kept current with proof/screenshots. - -## 2. Hard constraints (from runtime survey + research, verified against the codebase) - -| Constraint | Source | Consequence | -|---|---|---| -| Guest is `wasm32-wasip1`, executed in **V8** over a sync-RPC bridge | runtime survey, confirmed `crates/execution/src/wasm.rs`, `node_import_cache.rs` (`new WASI({version:'preview1'})`) | host engine for fidelity = V8 family. **Note:** the secure-exec WASM runner is its *own* JS-polyfill WASI over sync-RPC, **not** stock `node:wasi`. So the M0 `node:wasi` harness is a *proxy* for the V8 family; true product-path parity is deferred to **M5**. | -| No shared memory / mmap / dlopen / threads exposed to guests | runtime survey, confirmed `registry/native/crates/wasi-ext/` exposes only `host_process`/`host_net`/`host_user` | M0 uses none of them. Each is a later, explicit milestone. | -| AF_UNIX (path sockets) + TCP work | confirmed `wasi-ext` `host_net` supports `/path` sockets | X11 wire transport feasible (later). | -| No GPU / framebuffer / native window exists yet | runtime survey | native surface is greenfield; built host-side in Rust. | -| `mmap` "unsupported" claim is **overstated** — must be measured | research (refuted claim) | M1 spike measures real mmap before font/fbdev work. | -| This dev box is **headless** (no DISPLAY) + only `wasmer` CLI, `node`, `ffmpeg`, `cargo` present (no `wasmtime`/`clang`/`emcc`/Xvfb) | environment probe | automated proof = raw framebuffer → PNG via `ffmpeg`; two engines = `node:wasi` + `wasmer` CLI (no heavy Rust wasm-engine build); windowed host is the user's manual demo. | - -**Trust-model constraint (from root `CLAUDE.md`, boundary = sidecar ↔ executor):** anything that -parses untrusted guest traffic (the X server, toolkit, app) runs **in the executor as a guest**. -The new trusted host code is *only* the native-surface shuttle, which must do **no protocol -parsing** — it blits an opaque pixel buffer and forwards input events. This keeps the TCB minimal. - -## 3. Architecture (the product path — secure-exec Rust client end to end) - -``` -┌─ guest GUI app (wasm32-wasip1, compiled by our toolchain) ───────────────┐ -│ software-renders RGBA frames; speaks frame protocol v0 over WASI fds │ -│ (later milestones: a real toolkit, then an X server + WM as guests) │ -└──────────────────────────────────┬─────────────────────────────────────────┘ - │ runs INSIDE secure-exec - ┌──────────────┴───────────────┐ - │ secure-exec sidecar (V8) │ ← the real runtime; NOT wasmer/node:wasi - │ WASM exec + VFS + sockets │ - └──────────────┬───────────────┘ - │ secure-exec WIRE protocol (stdio) -┌──────────────────────────────────┴─────────────────────────────────────────┐ -│ NATIVE HOST APP (Rust) on the STANDARD secure-exec Rust client │ -│ crates/secure-exec-client: │ -│ • spawn/connect sidecar, create VM, load guest.wasm, start WASM exec │ -│ • pull frames out (process stdout stream / VFS read) → decode protocol │ -│ • own a winit+softbuffer window, blit frames │ -│ • inject keyboard/mouse via the client back into the guest │ -└──────────────────────────────────────────────────────────────────────────────┘ -``` - -The frame protocol is transport-agnostic; what changes per milestone is only what the *guest* is -(hand renderer → real toolkit → X server + WM). The guest's "render pixels with no host graphics" -contract and the "execute+render via the secure-exec Rust client" contract never change. - -**Superseded M0 spike (kept as evidence only):** the original two-engine path (`node:wasi` + -`wasmer`, SHA-256 byte-equality, ffmpeg PNG) proved the renderer is deterministic and the data path -works. It violates §1a.2 (uses non-secure-exec runtimes), so it is **not** the product path — the -Rust-client host below replaces it. - -## 4. Milestones - -- **M0 — Framebuffer renderer + data path (SPIKE, superseded).** Rust→`wasm32-wasip1` guest - software-renders a deterministic desktop-looking frame; proven byte-identical under two engines; - golden-pixel + cross-engine tests; PNG proof. ✅ **done as a spike** — but it executes via - `node:wasi`/`wasmer`, which **§1a.2 forbids** for the product path. Kept only as evidence the - renderer + protocol work. Superseded by M1. -- **M1 — Rust-client native host (THE foundation).** A native Rust app on - `crates/secure-exec-client` that: builds/locates + launches the sidecar, creates a VM, runs - `guest.wasm` **through secure-exec (V8)**, reads the framebuffer back via the client (chunked - PREAD), and blits it in a `winit`+`softbuffer` window (with `--capture` headless mode for - automated proof). This **replaces wasmer/node:wasi entirely**. ✅ **done** — `./tests/run.sh` - green; the frame rendered by the guest *inside the real secure-exec sidecar* is byte-identical - (SHA-256) to the spike output and passes golden pixels; window host compiles with `--features - window`. Host is a member of the repo root workspace (shares `Cargo.lock` with the sidecar); - guest stays a standalone wasm workspace. Notes: the sidecar loads the wasm from the trusted-client - HOST path given as `entrypoint`; the VM is created with an allow-all fs/process policy (trusted - config); the client must use the sidecar-ALLOCATED `connection_id` from the auth response. -- **M2 — mmap reality spike.** ✅ **done.** Findings (verified by `probes/mmap-probe.c` compiled - with the vendored wasi-sdk and run *through secure-exec* via the M1 host): - - Rust's `wasm32-wasip1` self-contained libc defines **no** `mmap`; wasi-sdk's `sys/mman.h` - `#error`s by default ("WASI lacks a true mmap"). - - wasi-sdk ships an opt-in emulation: **`-D_WASI_EMULATED_MMAN -lwasi-emulated-mman`** (mmap over - malloc + pread). With it, **anonymous mmap (rw)** and **file-backed `MAP_PRIVATE` read** both - work inside secure-exec — no host mmap implementation needed (the runtime already serves the - underlying pread/file ops). - - Limitation: no `MAP_SHARED` write-back, no cross-process shared memory (consistent with the - "no shared memory" constraint). Fine for single-process toolkits and read-only font access. - - **Consequence for M3:** freetype/fontconfig font `mmap` is satisfiable via the emulation; no - stream-I/O patch strictly required. The `_WASI_EMULATED_MMAN` flags must be in the toolkit build. - - Bonus: this proved the **C-source → wasm32-wasip1 (wasi-sdk clang) → run-in-secure-exec** - pipeline end-to-end, which is exactly the M3 build path. -- **M3 — Real framebuffer-native toolkit (Nuklear).** ✅ **done.** A pre-implementation design - review established that FLTK/Tk cannot software-render without X (they'd need a from-scratch - screen/graphics driver — weeks of authoring, not a cross-compile), so they belong *after* the X - server (see M4b). M3 is instead a real, standard, framebuffer-native toolkit: **Nuklear** - (single-header immediate-mode GUI shipping a software RGBA backend; no X/GL/dlopen/threads, no - font files). Real third-party widgets (window chrome, buttons, checkbox, radio buttons, slider, - progress bar, labels, a second window) software-rasterized and run **inside secure-exec** via the - M1 host. Cross-compiled from source with the vendored wasi-sdk (`scripts/build-nuklear.sh`). - Tested end-to-end (`tests/run-nuklear.sh`): header + golden-pixel checks, exact frame size, - regression-proof. Reuses the M0 `SXFB` protocol and the M1 host with zero host changes. -- **M4 — X server to wasm (target pivoted to `Xvfb`).** 🟡 **in progress (frontier — never done by - anyone per the research).** Findings + concrete progress: - - **Target pivot:** modern Xorg **dropped `Xfbdev`** (kdrive now only ships Xephyr, which needs a - host X server). **`Xvfb` (the virtual-framebuffer X server, `hw/vfb`, `-Dxvfb=true`) is the - right target** — it renders into an in-memory framebuffer with no fbdev device and no input - hardware, matching our blit-to-host model directly. Update M4 to Xvfb. - - **Toolchain proven:** meson+ninja installed; wasi-sdk **meson cross file** - (`toolchain/wasi-sdk-cross.ini`) and the wasi-sdk **CMake** toolchain both work for X-stack C. - - **Five X-stack components cross-compiled/installed to wasm** in `third_party/wasm-prefix`: - `pixman` (`libpixman-1.a`), `freetype` (`libfreetype.a`), `xorgproto` (headers + all proto - `.pc`s), `xtrans` (source headers + `.pc`), `libXau` (`libXau.a`, `XauReadAuth`). The meson - cross file now declares `pkg-config` + a wasm-only `pkg_config_libdir`, so cross dependency - resolution works. - - **New constraint discovered:** C libs using **setjmp/longjmp** (freetype, likely the xserver) - need `-mllvm -wasm-enable-sjlj` at compile time + an EH-capable engine (V8 qualifies). - - **Seven components now on wasm:** + `util-macros` (autoconf macros) and `xcb-proto` - (codegen data) installed; autotools cross-compile env wired (CC/AR/RANLIB/CFLAGS with - `--host=wasm32-wasi`). - - **xserver configure runs** (past all compiler checks) and needs `x11` (libX11 → libxcb → - xcb-proto ✓ + libxdmcp), `xfont2`, libxkbfile/font-util, then the `os/` core. - - **BREAKTHROUGH — the socket wall is solved by the patched sysroot.** Vanilla wasi-libc lacks - `recvfrom`/`sendto`/etc., but the repo's **patched wasi-libc sysroot** (`registry/native/c/sysroot`, - built by `patch-wasi-libc.sh`) provides them, backed by secure-exec's `host_net` imports. Building - the X stack with `--sysroot=registry/native/c/sysroot` gives it working POSIX sockets in-sidecar. - The toolchain (meson cross file + autotools `--host=wasm32-wasi` env) now targets that sysroot, - plus a force-included `toolchain/wasi-compat.h` (no-op `flockfile`/etc.). - - **THE ENTIRE X CLIENT + FONT STACK NOW CROSS-COMPILED TO WASM (14 components):** pixman, - freetype, zlib, xorgproto, xtrans, libXau, util-macros, xcb-proto, libxdmcp, libxcb, **libX11** - (`XOpenDisplay`), libfontenc, libXfont2, libxkbfile. Small per-lib patches were needed and are the - pattern for the rest: disable xtrans TCP/local transports (`inet_addr`/`sys/wait.h`), patch - `ioctl(FIONREAD)`→`poll()` in libX11, no-op stdio locking. **libX11 done means M4b (FLTK/Tk/twm as - X clients) is now unblocked too.** - - **THE X SERVER (Xvfb) IS CONFIGURED AND COMPILING TO WASM.** 16 X-stack libs now on wasm (added - libxcvt, libXext, libsha1 [a tiny vendored SHA1], plus a meson `clang` wrapper that strips - ELF-only linker args wasm-ld rejects, and stub `sys/wait.h`/`net/if.h` + no-op - `flockfile`/`getpgrp`/`setpgid`/`umask`/`pthread_sigmask`/`uname` in - `toolchain/wasi-compat.{h,c}`, and `-D_WASI_EMULATED_PROCESS_CLOCKS` for getrusage). `meson setup` - succeeds ("Build targets: 30") and `ninja` compiles **~118/314 objects**, advancing as each - `os/`-layer POSIX gap is shimmed (patched `os/access.c` utsname guard; `utils.c` is the current - edge — `struct rlimit`/`RLIMIT_CORE` feature-macro + wasi's pointer `clockid_t`). - - **Remaining (finite, well-understood — but more than one session):** finish the `os/`-layer - compile shims, link the `Xvfb` wasm binary (will surface more host-function stubs), supply an XKB - keymap (or run `-noxkb`), then RUN Xvfb inside secure-exec listening on an AF_UNIX `/tmp/.X11-unix` - socket, wire its framebuffer out through the M1 host, and connect a client (M4b) + WM (M5). - - **🎉 `Xvfb` IS NOW A WASM BINARY.** The full X.Org Xvfb server **compiled and linked to - `wasm32-wasip1`** — `experiments/wasm-gui/Xvfb.wasm` (8.25 MB, valid `wasm32` module). 314/314 - targets; all os/-layer POSIX gaps shimmed (utsname guard, `~0L`→pointer `clockid_t` cast, - `struct rlimit`/`RLIMIT_CORE`, `-D_GNU_SOURCE`); final link fixed by stripping `-pthread`/ - `--start-group`/`-rpath`/`-ldl` in the clang wrapper (wasi is single-threaded; pthread stubs come - from libc). **This is the thing the research said nobody had ever done.** It imports only 9 - standard WASI functions (args/fd/proc_exit) — a clean surface secure-exec provides. - - **`Xvfb` cross-compiled+linked to wasm and INSTANTIATES + EXECUTES in secure-exec** (verified: - valid 12 MB `wasm32` module; imports only standard WASI + secure-exec's `host_net`/`host_process`/ - `host_user`; loads in the V8 sidecar and runs for seconds with no instantiation/trap error). - Getting it to instantiate required, in the runner: a no-op `sock_shutdown` + a full **`net_poll`** - in `host_net`; and at link: forcing `__main_argc_argv` (wasi crt only weak-refs main → GC'd) + - appending libfontenc/freetype/**libsetjmp** (freetype's setjmp needs `libsetjmp.a`). - - **Verified init progress (via stderr-streamed markers — the reliable probe):** Xvfb runs through - `ProcessCommandLine` → **full `OsInit`** → **`CreateWellKnownSockets` succeeds (it CREATES A - LISTENING AF_UNIX SOCKET — the X server is listening for clients in the sandbox)** → `InitOutput` - / **screen init succeeds at depth 24** → enters the screens loop → **traps in `CreateRootWindow`**. - - **Real fixes that got it this far (all needed):** run with `-nolock` (the X display lock dance - loops on wasi); `-listen local` (modern Xorg defaults AF_UNIX transports to NOLISTEN); disable - xtrans **abstract sockets** (host_net only does path sockets — exactly the research's call); - patch `trans_mkdir` to skip the root/sticky-bit ownership dance; **patch xtrans's - `fd >= sysconf(_SC_OPEN_MAX)` check** (host_net fds are intentionally `0x40000000+`, and the - server uses `poll()` not `FD_SET`); depth **24** not 32; runner gained `sock_shutdown` + `net_poll`. - - **Function-pointer-cast wall (SOLVED):** `CreateRootWindow`/`SetDefaultFontPath` trapped with wasm - `RuntimeError: null function or function signature mismatch` — the X server calls procs through - **cast function pointers**, and wasm's `call_indirect` enforces exact type signatures. Solved with - **`wasm-opt --fpcast-emu`** (binaryen's equivalent of Emscripten `EMULATE_FUNCTION_POINTER_CASTS`), - applied as a post-link pass in `scripts/link-xvfb.sh` + a manual `wasm-opt` step. - - **Reaching the dispatch loop (DONE):** past the function-pointer wall, the server hit XKB keymap - compilation (needs `xkbcomp` fork/exec, unavailable on wasi) — made non-fatal in `dix/devices.c` - and `Xext/xtest.c` (keyboard activation warns + continues). Xvfb now runs `ProcessCommandLine → - OsInit → CreateWellKnownSockets (listening AF_UNIX socket) → screen init (depth 24) → root window → - InitInput → **Dispatch main loop**`, blocking there serving, verified by `XMARK` stderr markers. - - **✅ Status: the never-before-done core (real X server → wasm) fully starts and serves in its - dispatch loop inside secure-exec.** "One X client on the native surface" (M4 goal) is proven by - M4b below. -- **M4b — X client over AF_UNIX (DONE for raw-protocol client; toolkit next). ✅** A minimal raw-X11 - client (`guest-xclient/xfill.c`, **no libX11** — pure X11 wire protocol over POSIX sockets) is - cross-compiled to wasm against the patched sysroot and run **as a second guest in the SAME VM** as - Xvfb. It connects to `/tmp/.X11-unix/X0`, completes the **full X11 connection-setup handshake**, - parses the screen reply, and draws an orange fill across the 640×480 root window - (`CreateGC` + `PolyFillRectangle`), then a `GetInputFocus` round-trip barrier. The host reads the - framebuffer back out (`-fbdir /data`, patched `pwrite`) → **99.8% of pixels are `0x00FF8800`**, the - exact color the client set (proof: `~/tmp/gui-progress/m4b-xfill.png`). Run it with - `wasm-gui-host --xdemo --server Xvfb.wasm --client xfill.wasm --fb-out frame.bin`. - - **Sidecar/runtime fixes this required (all in `crates/execution/src/node_import_cache.rs`):** - (1) `net_connect` now handles **AF_UNIX path** addresses (routes to the sidecar's path-based - `net.connect` → host-backed unix socket shared across guests in one VM), stripping trailing NUL - padding from `sizeof(sockaddr_un)`. (2) `net_accept` for unix sockets no longer calls the TCP-only - `address:port` formatter (which threw). (3) **`net_poll` listener readiness is now accurate** (a - buffered non-blocking accept) and **`net_accept` is non-blocking** (returns `EAGAIN`) — previously - the optimistic listener `POLLIN` + a blocking accept busy-loop starved connected clients. - - **X-server-side fixes (vendored copies):** `os/xserver_poll.c` `xserver_poll()` rewritten to call - real `poll()` (routed to host_net) instead of the `fd_set`/`select()` emulation, which silently - dropped our `0x40000000+` host_net fds (> `FD_SETSIZE`). `Xtranssock.c` `SocketRead/Write/Readv/ - Writev` rewritten to use `recv()`/`send()` (the patched libc routes only those to host_net, not - `read`/`write`/`recvmsg`/`writev`). - - **Next:** swap the raw client for a **stock toolkit X client** (FLTK/Tk over the already-built - libX11) to land the "real standard toolkit" intent, and blit the framebuffer through the M1 - winit/softbuffer native window live. 🟡 -- **M5 — Standard WM + multi-window desktop. ✅ DONE.** The standard X.Org window manager **`twm`**, - cross-compiled from source to `wasm32-wasip1`, manages and decorates a real **libX11** client window, - all running as wasm guests inside secure-exec. twm grabs `SubstructureRedirect`, receives the client's - `MapRequest`, reparents it into a decoration frame with a **title bar** (the client's `WM_NAME`), and - the client draws into it with real Xlib calls. Proof: `~/tmp/gui-progress/m5-twm-window.png`, test - `scripts/test-m5-twm.sh`. The **multi-client substrate** is also proven: three raw-X11 clients composite - on one Xvfb (`scripts/test-m5-multiclient.sh`, `~/tmp/gui-progress/m5-multiclient.png`). - - **Full toolkit/WM stack cross-compiled to wasm:** libICE, libSM, **libXt** (Intrinsics), libXmu, plus - a locale-enabled libX11 and the patched libxcb, then **twm** itself (`scripts/build-xlib.sh`, - `scripts/link-twm.sh`). A real libX11 client (`guest-xclient/xwin.c`) creates+maps+draws a top-level - window (`scripts/...`); `guest-xclient/xopen.c` is a minimal libX11 smoke client. - - **Key fixes that unblocked the toolkit stack:** the effective wasi **`POLLOUT` is `0x2`** (POLLWRNORM), - not `0x4` — `net_poll` was using `0x4` so libxcb's poll-for-reply never saw the socket writable and - `XOpenDisplay` hung; a host_net **`net_set_nonblock`** import + non-blocking `net_recv` (both libxcb's - poll helpers and the X server's multi-client dispatch require non-blocking sockets, and - `fcntl(O_NONBLOCK)` cannot reach host_net fds); `fcntl(F_SETFD)`-failure tolerance in libxcb/twm; a - `.twmrc` with `RandomPlacement` (twm's default placement is interactive); libXt's - `_XtWaitForSomething` `drop_lock` signature reconciliation; host-built `makestrs`; pregenerated - `gram.c`; newer `config.sub`. - - **Remaining polish (not blocking):** JWM as a richer Pi-class desktop, real fonts (Xft/core-font - files) for crisper title text, live winit blit of the framebuffer, and making concurrent libX11 init - robust (today the client connects after twm is idle to avoid flaky concurrent startup over the single - sync-RPC bridge). **Real, standard WMs only (no custom WM):** the original plan was twm then JWM — - with **`twm`** (X.Org tree; deps `libX11`/`libXt`/`libXmu`; no dlopen), then **`JWM`** as the - Raspberry-Pi-class desktop (single C binary with built-in panel/menu/systray, builds against just - `libX11`, no dlopen; `IceWM` fallback). Avoid `openbox`/`fluxbox` (libxml2/glib/pango/cairo or - C++/imlib2). **Build WM + first apps on X CORE FONTS (no Xft)** so clients need no - `freetype`/`fontconfig`/`mmap`; flip Xft on after M2. Multiple guest clients over AF_UNIX, the WM - as another guest, everything inside secure-exec, rendered by the M1 host. ⬜ - -### CURRENT GOAL (post-M5): a full, well-known desktop environment — no half measures - -M1-M5 proved the stack (X server + WM + libX11, all wasm in secure-exec). The goal now is a **real, -interactive desktop running a standard, well-known project**, in three sequenced milestones. "No half -measures" is the bar: each milestone must be **genuinely interactive** (live window + real input, not a -screenshot read-back), **robust** (no "connect after the WM is idle" hack — concurrent client startup -must work), use **real fonts**, be **fully automated-tested**, and have a **manually runnable example**. - -- **M6 — Make what we have REAL.** 🟡 **in progress.** Done: a real stock app (X.Org **xclock**, - analog + digital, with libXaw/libXmu/libXt/libXrender cross-compiled), **real X core fonts** served - by the server (`-fp /fonts`; digital-clock text + twm title text render; host installs PCF fonts via - `--fonts-dir`), and a **robust multi-app desktop** (twm + xclock + a libX11 window, 3/3 identical - runs). Robustness came from (a) WM-ready-gated sequential launch in the host (session-manager style, - no in-client sleep) and (b) making clients **event-driven** (block in the X loop, draw on Expose) so - continuous redraw traffic stops flooding the sidecar's single sync-RPC thread. Proof: - `~/tmp/gui-progress/m6-xclock.png`, `m6-xclock-digital.png`, `m6-desktop.png`. **Remaining:** live - window + input (built path pending; needs a machine with a display to verify — this box is headless), - a terminal (xterm needs fork/exec/PTY → a kernel-PTY-spawn shim), Xft/fontconfig + libX11 locale - files for antialiased/i18n text. Original sub-tasks: - 1. **Live rendering + input.** Stream the X server framebuffer to the M1 `winit`/`softbuffer` window - continuously (not a one-shot PNG), and inject host mouse/keyboard back through the client as X - input events (so you can actually click/type into the wasm desktop). Replace `xdemo`'s PNG - read-back with a live loop. - 2. **Real fonts.** Cross-compile `fontconfig` (+ `expat`) and `libXft`/`libXrender`, install a base - set of font files (e.g. DejaVu/Liberation) into the VM, and verify crisp antialiased text. This is - a hard dependency for xterm and every real DE. - 3. **Stock apps as content.** Cross-compile and run standard X apps (`xclock`, `xterm`, maybe `xcalc`) - as guests so the desktop has real, interactive programs. - 4. **Robust concurrency.** Fix the flaky concurrent-libX11-init over the single sync-RPC bridge so - many clients can start simultaneously without the `usleep`/ordering hack. (Likely: per-client - sync-RPC fairness, or a smarter net_poll/recv path.) - Acceptance: a live window showing twm managing xterm + xclock, typing into xterm works, all started - concurrently, with an automated test + manual example. - -- **M7 — JWM: a complete lightweight desktop from one standard project.** ⬜ Cross-compile **JWM** - (Joe's Window Manager) to wasm — a single, well-known C project (Puppy Linux's default) providing a - built-in **panel/taskbar, clock, start menu, systray, and virtual-desktop pager**. Builds against the - `libX11` we already have (+ `libXft`/`libXpm` from M6). Run it as the desktop shell managing the M6 - stock apps, launching apps from its menu, live + interactive. Acceptance: JWM panel + menu + taskbar - visible and usable in the live window, apps launch from the menu, automated test + manual example. - -- **M8 — A brand-name GTK desktop environment (LXDE or XFCE).** ⬜ The big one. Cross-compile the GTK - stack (`GLib`/`GObject`/`Pango`/`Cairo`/`GdkPixbuf`/`harfbuzz`/`fontconfig`/`freetype`) and resolve - the wasi blockers (`dlopen` for modules/themes — static-link or shim; `dbus` session bus; threads). - **Spike first:** get a single GTK3 app (`gtk3-demo`) running on our X server to prove the stack before - committing. Then build up to **LXDE** (lighter, GTK2/openbox/lxpanel/pcmanfm) or **XFCE** - (xfwm4/xfce4-panel/thunar). Acceptance: the named DE's shell (panel + menu + a file manager or - settings app) running live + interactive, automated test + manual example. - -Sequencing is strict: M6 → M7 → M8. Don't start the next until the previous fully meets its acceptance -bar (interactive, robust, tested, real fonts, no hacks). - -Threads (`wasm32-wasip1-threads` + `wasi_thread_spawn`) are added only where a milestone needs them. -GL passthrough is out of scope; software rasterization to the framebuffer remains the single data path. - -## 5. M0 detailed design - -Directory `experiments/wasm-gui/` — **standalone Cargo workspace** (its own `[workspace]` to halt -cargo's upward walk into the repo root workspace; root `Cargo.toml` has an explicit no-glob -`members` list, so without this the experiment crates fail to build): - -``` -experiments/wasm-gui/ - Cargo.toml ← [workspace] members = ["guest","host"], resolver="2" - SPEC.md README.md - guest/ Cargo.toml src/main.rs ← software renderer + frame protocol (target wasm32-wasip1) - host/ Cargo.toml src/main.rs ← winit+softbuffer window; spawns `wasmer run guest --loop` - (feature `window`, OFF by default) - host-node/ run.mjs ← node:wasi runner → raw framebuffer file - tests/ run.sh golden.json ← build + run both engines + assert; writes RESULTS.txt - scripts/ make-proof.sh ← ffmpeg raw→PNG + copy artifacts to ~/tmp/gui-progress/assets -``` - -### Frame protocol v0 (pinned) -- Header: `magic = "SXFB"` (4 bytes) · `width: u32 LE` · `height: u32 LE`. Little-endian because - it's WASM-native (no swap in guest). -- Payload: `width*height*4` bytes, **row-major, `[R,G,B,A]` byte order**, no stride/padding. - Defined as a byte stream, so there is zero endianness ambiguity on pixels. -- Capture mode (`guest --out `): write `header || payload` to the preopened file, exit. -- Window mode (`guest --loop`): read newline-delimited JSON events from stdin - (`{"t":"pointer","x":..,"y":..}` / `{"t":"key","code":..}` / `{"t":"quit"}`), write - `header || payload` frames to stdout. Used only by the Rust window host (wasmer handles stdio). -- **softbuffer note:** the window present step must repack `[R,G,B,A]` bytes → softbuffer's - `0x00RRGGBB` native-endian u32. (Only the window path; not the compared bytes.) - -### Guest determinism contract (REQUIRED — the raw-byte equality depends on it) -- No clock/time reads affecting pixels: the panel "clock" is a **hardcoded string** ("12:34"). -- No RNG, or fixed-seed only; never `random_get`. -- Integer/fixed-point layout math; **no host-imported math**; avoid NaN-producing ops (plain - WASM FP is deterministic across V8/wasmer, but keep transcendentals in-guest if used at all). -- No argv/env/cwd/locale/`$TZ`/font-file reads influencing pixels. -- Capture mode renders a **single fixed frame** with a **hardcoded pointer position**, so the - cursor is deterministic. -- Guest writes **nothing** to stdout except frames; all diagnostics go to **stderr**. (A stray - `println!` corrupts the binary stream.) - -### node:wasi host (`host-node/run.mjs`) -- `new WASI({ version: 'preview1', returnOnExit: true })`, command (`_start`) model, run once. -- I/O via **preopened directory + file**, not stdio pipes: preopen a temp dir as `/out`, pass - argv `["guest","--out","/out/frame.bin"]`, then read the host temp file back as a raw `Buffer`. - (Preopened files are the robust node:wasi channel; stdio-as-pipe is the fragile path.) -- Expect/suppress the experimental-WASI stderr warning so the harness doesn't misparse it. - -## 6. Testing strategy (fully automated, headless, no network/display) - -`tests/run.sh` — non-zero exit on any failure: -1. `cargo build --target wasm32-wasip1 --release -p wasm-gui-guest` → `guest.wasm` exists. -2. Engine A: `node host-node/run.mjs … → /tmp/frame_node.bin`. -3. Engine B: `wasmer run guest.wasm --dir -- --out /out/frame.bin → /tmp/frame_wasmer.bin`. -4. **Validate each header** independently: `magic=="SXFB"`, `w`/`h` == expected constants — fail - with a clear message *before* comparing payloads (catches truncation/short reads). -5. **Cross-engine equality:** `sha256(frame_node.bin) == sha256(frame_wasmer.bin)` over the full - `header||payload`. This is the honest engine-independence test (no PNG encoder in the loop). -6. **Golden-pixel checks** (`golden.json`): sample known coords on the raw payload (wallpaper, - panel, title bar, a glyph pixel, cursor tip) and assert exact RGBA — deterministic regression - guard. -7. Headless winit guard: run the capture path under `env -u DISPLAY -u WAYLAND_DISPLAY` and assert - it never initializes a display (it can't pull in winit — the `window` feature is off). -8. `ffmpeg` encodes one `.bin` → `frame.png` (human proof only; never asserted). -9. Emit `tests/RESULTS.txt` consumed by the progress.html generator. - -## 7. Manual example (run on your own machine, with a display) - -`README.md` documents: -``` -cd experiments/wasm-gui -./tests/run.sh # headless: builds + verifies + writes frame.png -cargo build -p wasm-gui-guest --target wasm32-wasip1 --release -cargo run -p wasm-gui-host --features window -- \ - --guest target/wasm32-wasip1/release/guest.wasm -``` -Opens a real OS window showing the rendered desktop frame; mouse moves the cursor, Esc quits. -(This headless dev box can't open it; the PNG in progress.html is the byte-identical frame.) - -## 8. Risks tracked - -- R1 crate build time over cargo network. **Mitigated:** automated path uses installed `wasmer` - CLI + `node:wasi` (no Rust wasm-engine crate). Only the manual window host builds - winit/softbuffer, and it's not on the automated path. -- R2 node:wasi is experimental + ≠ the secure-exec bridge. Pin `version:'preview1'`, - `returnOnExit:true`, node 24; treat as a V8-family proxy, real parity at M5. -- R3 Scope creep — M0 is a hand-rolled renderer, NOT a real toolkit (that's M2+). Keep it small. -- R4 "Looks like a desktop" is cosmetic at M0; fidelity comes from real toolkits at M2+. -- R5 Determinism — without §5's contract the raw-byte compare isn't guaranteed. Enforce it. - -## Changelog -- **v2** (post-review): added nested-Cargo-workspace fix (build-breaking otherwise); switched - cross-engine test from PNG-byte to raw-RGBA SHA-256 equality; pinned protocol endianness/pixel - order; switched node:wasi I/O to preopened files + `returnOnExit`; added guest determinism - contract; feature-gated winit; swapped wasmtime crate → installed `wasmer` CLI + `node:wasi`; - added trust-model constraint (X/parsing stays in executor, host shuttle does no parsing); noted - node:wasi ≠ product bridge and M1-blocks-M2 dependency. diff --git a/experiments/wasm-gui/guest-nuklear/guest_nuklear.c b/experiments/wasm-gui/guest-nuklear/guest_nuklear.c deleted file mode 100644 index 02cdf8c85..000000000 --- a/experiments/wasm-gui/guest-nuklear/guest_nuklear.c +++ /dev/null @@ -1,153 +0,0 @@ -/* M3 guest: a REAL third-party GUI toolkit (Nuklear) software-rendering real widgets into an RGBA - * framebuffer, cross-compiled to wasm32-wasip1 and run INSIDE secure-exec via the M1 host. - * - * Nuklear is a standard, widely-used immediate-mode GUI library. Its `nuklear_rawfb` backend - * rasterizes the UI (windows, buttons, checkboxes, sliders, text via the built-in font atlas) into - * a plain pixel buffer — no X11, no GL, no dlopen, no threads, no font files. We emit the same - * frame protocol v0 the M0/M1 host already speaks: b"SXFB" | u32 LE w | u32 LE h | RGBA. - * - * Determinism (capture mode): one frame, fixed pointer, no clock/RNG — so the output is stable. - */ -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -/* rawfb's font-query callback fills struct nk_user_font_glyph, whose full definition is gated - * behind this define (even though rawfb rasterizes from commands, not a vertex buffer). */ -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_IMPLEMENTATION -#define NK_RAWFB_IMPLEMENTATION -#include "nuklear.h" -#include "nuklear_rawfb.h" - -#include -#include -#include - -#define W 640u -#define H 480u - -static void write_frame(const char *path, const unsigned char *fb) { - FILE *f = path ? fopen(path, "wb") : stdout; - if (!f) { perror("open out"); exit(1); } - unsigned char hdr[12]; - memcpy(hdr, "SXFB", 4); - unsigned int w = W, h = H; - memcpy(hdr + 4, &w, 4); /* wasm is little-endian -> LE u32, matches the protocol */ - memcpy(hdr + 8, &h, 4); - fwrite(hdr, 1, 12, f); - fwrite(fb, 1, W * H * 4, f); - if (f != stdout) fclose(f); -} - -/* Build the UI for one frame. Real Nuklear widgets, not hand-rolled drawing. */ -static int g_check = 1; -static float g_slider = 0.6f; -static nk_size g_prog = 64; -static int g_option = 1; - -static void build_ui(struct nk_context *ctx) { - if (nk_begin(ctx, "secure-exec - Nuklear (wasm, in the sidecar)", - nk_rect(48, 54, 380, 300), - NK_WINDOW_BORDER | NK_WINDOW_TITLE | NK_WINDOW_MOVABLE)) { - nk_layout_row_dynamic(ctx, 22, 1); - nk_label(ctx, "Real toolkit widgets, software-rendered:", NK_TEXT_LEFT); - - nk_layout_row_dynamic(ctx, 30, 2); - nk_button_label(ctx, "Build"); - nk_button_label(ctx, "Run"); - - nk_layout_row_dynamic(ctx, 26, 1); - nk_checkbox_label(ctx, "Enable sandbox", &g_check); - - nk_layout_row_dynamic(ctx, 22, 2); - if (nk_option_label(ctx, "wasm32", g_option == 1)) g_option = 1; - if (nk_option_label(ctx, "native", g_option == 0)) g_option = 0; - - nk_layout_row_dynamic(ctx, 26, 1); - nk_slider_float(ctx, 0.0f, &g_slider, 1.0f, 0.01f); - - nk_layout_row_dynamic(ctx, 24, 1); - nk_progress(ctx, &g_prog, 100, NK_FIXED); - - nk_layout_row_dynamic(ctx, 22, 1); - nk_label(ctx, "rendered by Nuklear, inside secure-exec", NK_TEXT_LEFT); - } - nk_end(ctx); - - /* A second small window, like a desktop with multiple panels. */ - if (nk_begin(ctx, "Info", nk_rect(446, 150, 150, 150), - NK_WINDOW_BORDER | NK_WINDOW_TITLE | NK_WINDOW_MOVABLE)) { - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "M3: real toolkit", NK_TEXT_LEFT); - nk_label(ctx, "no X, no GL,", NK_TEXT_LEFT); - nk_label(ctx, "no dlopen.", NK_TEXT_LEFT); - } - nk_end(ctx); -} - -int main(int argc, char **argv) { - const char *out = NULL; - int loop = 0; - for (int i = 1; i < argc; i++) { - if (!strcmp(argv[i], "--out") && i + 1 < argc) out = argv[++i]; - else if (!strcmp(argv[i], "--loop")) loop = 1; - } - - unsigned char *fb = calloc(W * H, 4); - unsigned char *tex = malloc(1024 * 1024); /* font-atlas scratch (alpha8) */ - if (!fb || !tex) { fprintf(stderr, "oom\n"); return 1; } - - /* Pixel layout: little-endian uint per pixel => bytes [R,G,B,A]. */ - struct rawfb_pl pl; - pl.bytesPerPixel = 4; - pl.rshift = 0; pl.gshift = 8; pl.bshift = 16; pl.ashift = 24; - pl.rloss = 0; pl.gloss = 0; pl.bloss = 0; pl.aloss = 0; - - struct rawfb_context *rawfb = nk_rawfb_init(fb, tex, W, H, W * 4, pl); - if (!rawfb) { fprintf(stderr, "rawfb init failed\n"); return 1; } - - struct nk_color clear = nk_rgb(28, 64, 96); /* desktop wallpaper */ - - if (!loop) { - /* Capture mode: one deterministic frame with a fixed pointer. */ - nk_input_begin(&rawfb->ctx); - nk_input_motion(&rawfb->ctx, 300, 235); - nk_input_end(&rawfb->ctx); - build_ui(&rawfb->ctx); - nk_rawfb_render(rawfb, clear, 1); - write_frame(out, fb); - nk_rawfb_shutdown(rawfb); - free(fb); free(tex); - return 0; - } - - /* Window mode: read input tokens from stdin, render frames to stdout. */ - int px = W / 2, py = H / 2, down = 0; - char line[128]; - /* initial frame */ - nk_input_begin(&rawfb->ctx); - nk_input_end(&rawfb->ctx); - build_ui(&rawfb->ctx); - nk_rawfb_render(rawfb, clear, 1); - write_frame(NULL, fb); - fflush(stdout); - while (fgets(line, sizeof(line), stdin)) { - if (line[0] == 'q') break; - if (line[0] == 'p') sscanf(line + 1, "%d %d", &px, &py); - if (line[0] == 'd') down = 1; - if (line[0] == 'u') down = 0; - nk_input_begin(&rawfb->ctx); - nk_input_motion(&rawfb->ctx, px, py); - nk_input_button(&rawfb->ctx, NK_BUTTON_LEFT, px, py, down); - nk_input_end(&rawfb->ctx); - build_ui(&rawfb->ctx); - nk_rawfb_render(rawfb, clear, 1); - write_frame(NULL, fb); - fflush(stdout); - } - nk_rawfb_shutdown(rawfb); - free(fb); free(tex); - return 0; -} diff --git a/experiments/wasm-gui/guest-nuklear/guest_nuklear.wasm b/experiments/wasm-gui/guest-nuklear/guest_nuklear.wasm deleted file mode 100755 index b26eab147..000000000 Binary files a/experiments/wasm-gui/guest-nuklear/guest_nuklear.wasm and /dev/null differ diff --git a/experiments/wasm-gui/guest-xclient/xfill.c b/experiments/wasm-gui/guest-xclient/xfill.c deleted file mode 100644 index cbd04bd65..000000000 --- a/experiments/wasm-gui/guest-xclient/xfill.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Minimal raw X11 client (no libX11): connects to the secure-exec wasm Xvfb over the - * AF_UNIX socket /tmp/.X11-unix/X0, performs the X11 connection-setup handshake, then - * fills the root window with a solid color using core protocol requests (CreateGC + - * PolyFillRectangle). This proves an X client can reach our wasm X server over the - * shared kernel socket table and drive the framebuffer. Stages are reported on stderr - * with "CMARK:" markers so the host can verify progress. - */ -#include -#include -#include -#include -#include -#include - -static void mark(const char *m) { write(2, m, strlen(m)); } - -/* The patched wasi-libc routes send()/recv() (not write()/read()) to host_net, so all - * socket I/O on the host_net fd must use the socket calls. */ -static int read_full(int fd, void *buf, size_t n) { - uint8_t *p = (uint8_t *)buf; - size_t got = 0; - while (got < n) { - ssize_t r = recv(fd, p + got, n - got, 0); - if (r > 0) { got += (size_t)r; continue; } - if (r < 0 && (errno == EINTR || errno == EAGAIN)) continue; - return -1; - } - return 0; -} - -static int write_full(int fd, const void *buf, size_t n) { - const uint8_t *p = (const uint8_t *)buf; - size_t put = 0; - while (put < n) { - ssize_t w = send(fd, p + put, n - put, 0); - if (w > 0) { put += (size_t)w; continue; } - if (w < 0 && (errno == EINTR || errno == EAGAIN)) continue; - return -1; - } - return 0; -} - -static int arg_int(int argc, char **argv, int idx, int dflt) { - if (idx >= argc) return dflt; - int v = 0, sign = 1; const char *s = argv[idx]; - if (*s == '-') { sign = -1; s++; } - int any = 0; - for (; *s >= '0' && *s <= '9'; s++) { v = v*10 + (*s - '0'); any = 1; } - return any ? sign*v : dflt; -} - -int main(int argc, char **argv) { - mark("CMARK:start\n"); - - /* Optional argv: x y w h color(decimal). Defaults to a full-screen orange fill. */ - int want_x = arg_int(argc, argv, 1, 0); - int want_y = arg_int(argc, argv, 2, 0); - int want_w = arg_int(argc, argv, 3, -1); /* -1 => full width */ - int want_h = arg_int(argc, argv, 4, -1); /* -1 => full height */ - unsigned want_color = (unsigned) arg_int(argc, argv, 5, (int) 0x00FF8800u); - - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { mark("CMARK:socket_fail\n"); return 1; } - - struct sockaddr_un addr; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, "/tmp/.X11-unix/X0"); - if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { - mark("CMARK:connect_fail\n"); - return 1; - } - mark("CMARK:connected\n"); - - /* Connection setup request: little-endian, protocol 11.0, no auth. */ - uint8_t setup[12] = {0}; - setup[0] = 0x6c; /* 'l' little-endian */ - setup[2] = 11; setup[3] = 0; /* major 11 */ - setup[4] = 0; setup[5] = 0; /* minor 0 */ - /* auth name/data lengths = 0 */ - if (write_full(fd, setup, sizeof(setup)) != 0) { mark("CMARK:setup_write_fail\n"); return 1; } - mark("CMARK:setup_sent\n"); - - /* Setup reply header (8 bytes). */ - uint8_t hdr[8]; - if (read_full(fd, hdr, 8) != 0) { mark("CMARK:reply_read_fail\n"); return 1; } - if (hdr[0] != 1) { mark("CMARK:setup_refused\n"); return 1; } - mark("CMARK:setup_accepted\n"); - - uint16_t add_len_words = (uint16_t)(hdr[6] | (hdr[7] << 8)); - size_t add_len = (size_t)add_len_words * 4; - uint8_t *body = (uint8_t *)__builtin_alloca(add_len); - if (read_full(fd, body, add_len) != 0) { mark("CMARK:body_read_fail\n"); return 1; } - - /* Parse the fixed part of the setup reply additional data. */ - uint32_t id_base = body[4] | (body[5]<<8) | (body[6]<<16) | ((uint32_t)body[7]<<24); - uint16_t vendor_len = body[16] | (body[17]<<8); - uint8_t num_formats = body[21]; - - /* Skip: 32 bytes fixed + vendor (padded to 4) + 8*num_formats pixmap formats. */ - size_t off = 32 + ((vendor_len + 3) & ~3u) + 8 * (size_t)num_formats; - /* First SCREEN: root window id at offset 0, root visual at offset 32. */ - uint32_t root = body[off+0] | (body[off+1]<<8) | (body[off+2]<<16) | ((uint32_t)body[off+3]<<24); - uint16_t width = body[off+20] | (body[off+21]<<8); - uint16_t height = body[off+22] | (body[off+23]<<8); - mark("CMARK:parsed_screen\n"); - - uint32_t gc = id_base | 1; - - /* CreateGC (opcode 55): set GCForeground to a bright color. */ - uint8_t cg[20]; - cg[0]=55; cg[1]=0; cg[2]=5; cg[3]=0; /* opcode, pad, length=5 words */ - memcpy(cg+4, &gc, 4); - memcpy(cg+8, &root, 4); - uint32_t mask = 0x00000004; /* GCForeground */ - memcpy(cg+12, &mask, 4); - uint32_t fg = want_color; - memcpy(cg+16, &fg, 4); - if (write_full(fd, cg, sizeof(cg)) != 0) { mark("CMARK:creategc_fail\n"); return 1; } - - /* PolyFillRectangle (opcode 70): one rect (argv-positioned, or whole root window). */ - uint8_t pf[20]; - pf[0]=70; pf[1]=0; pf[2]=5; pf[3]=0; /* opcode, pad, length=5 words (3 + 2*1) */ - memcpy(pf+4, &root, 4); - memcpy(pf+8, &gc, 4); - uint16_t x = (uint16_t) want_x, y = (uint16_t) want_y; - uint16_t rw = (want_w < 0) ? width : (uint16_t) want_w; - uint16_t rh = (want_h < 0) ? height : (uint16_t) want_h; - memcpy(pf+12, &x, 2); memcpy(pf+14, &y, 2); - memcpy(pf+16, &rw, 2); memcpy(pf+18, &rh, 2); - if (write_full(fd, pf, sizeof(pf)) != 0) { mark("CMARK:fill_fail\n"); return 1; } - mark("CMARK:filled\n"); - - /* GetInputFocus (opcode 43) as a round-trip barrier: forces the server to process - * our queued requests and reply, guaranteeing the fill reached the framebuffer. */ - uint8_t gif[4] = {43, 0, 1, 0}; - if (write_full(fd, gif, sizeof(gif)) != 0) { mark("CMARK:sync_write_fail\n"); return 1; } - uint8_t rep[32]; - if (read_full(fd, rep, 32) != 0) { mark("CMARK:sync_read_fail\n"); return 1; } - mark("CMARK:synced\n"); - mark("CMARK:done\n"); - return 0; -} diff --git a/experiments/wasm-gui/guest-xclient/xfill.wasm b/experiments/wasm-gui/guest-xclient/xfill.wasm deleted file mode 100755 index 0520d2a05..000000000 Binary files a/experiments/wasm-gui/guest-xclient/xfill.wasm and /dev/null differ diff --git a/experiments/wasm-gui/guest-xclient/xopen-fp.wasm b/experiments/wasm-gui/guest-xclient/xopen-fp.wasm deleted file mode 100644 index 12fd61d4d..000000000 Binary files a/experiments/wasm-gui/guest-xclient/xopen-fp.wasm and /dev/null differ diff --git a/experiments/wasm-gui/guest-xclient/xopen.c b/experiments/wasm-gui/guest-xclient/xopen.c deleted file mode 100644 index d289173d8..000000000 --- a/experiments/wasm-gui/guest-xclient/xopen.c +++ /dev/null @@ -1,32 +0,0 @@ -/* Minimal libX11 client: open the display, report the screen geometry, draw a filled rect on the - * root window via real Xlib calls, sync, and close. Isolates the libX11 + libxcb transport. */ -#include -#include -#include - -static void mark(const char *m) { write(2, m, __builtin_strlen(m)); } - -int main(void) { - mark("XO:start\n"); - Display *dpy = XOpenDisplay(":0"); - if (!dpy) { mark("XO:open_failed\n"); return 1; } - mark("XO:opened\n"); - - int scr = DefaultScreen(dpy); - Window root = RootWindow(dpy, scr); - int w = DisplayWidth(dpy, scr), h = DisplayHeight(dpy, scr); - char buf[64]; - int n = 0; const char *p = "XO:size="; while (*p) buf[n++] = *p++; - int v = w; char t[8]; int ti = 0; if(!v)t[ti++]='0'; while(v){t[ti++]='0'+v%10;v/=10;} while(ti)buf[n++]=t[--ti]; - buf[n++]='x'; v=h; ti=0; if(!v)t[ti++]='0'; while(v){t[ti++]='0'+v%10;v/=10;} while(ti)buf[n++]=t[--ti]; buf[n++]='\n'; - write(2, buf, n); - - GC gc = XCreateGC(dpy, root, 0, NULL); - XSetForeground(dpy, gc, 0x00CC44u); /* green-ish */ - XFillRectangle(dpy, root, gc, 0, 0, w, h); - XSync(dpy, False); - mark("XO:drawn\n"); - XCloseDisplay(dpy); - mark("XO:done\n"); - return 0; -} diff --git a/experiments/wasm-gui/guest-xclient/xopen.wasm b/experiments/wasm-gui/guest-xclient/xopen.wasm deleted file mode 100755 index 12fd61d4d..000000000 Binary files a/experiments/wasm-gui/guest-xclient/xopen.wasm and /dev/null differ diff --git a/experiments/wasm-gui/guest-xclient/xwin-fp.wasm b/experiments/wasm-gui/guest-xclient/xwin-fp.wasm deleted file mode 100644 index ebe952364..000000000 Binary files a/experiments/wasm-gui/guest-xclient/xwin-fp.wasm and /dev/null differ diff --git a/experiments/wasm-gui/guest-xclient/xwin.c b/experiments/wasm-gui/guest-xclient/xwin.c deleted file mode 100644 index a59d1cf73..000000000 --- a/experiments/wasm-gui/guest-xclient/xwin.c +++ /dev/null @@ -1,57 +0,0 @@ -/* A real libX11 client that creates a top-level window, names it (so a window manager draws a - * title bar), maps it, and draws content. Run alongside twm to prove the WM decorates a managed - * client window. Stays alive in an event loop so the framebuffer can be captured. */ -#include -#include -#include -#include - -static void mark(const char *m) { write(2, m, strlen(m)); } - -int main(int argc, char **argv) { - mark("XW:start\n"); - /* The host launches clients in sequence (WM first), so we just connect normally. */ - Display *dpy = XOpenDisplay(":0"); - if (!dpy) { mark("XW:open_failed\n"); return 1; } - mark("XW:opened\n"); - - int scr = DefaultScreen(dpy); - Window root = RootWindow(dpy, scr); - unsigned long bg = 0x3060C0; /* blue-ish window body */ - unsigned long fg = 0xF0F0F0; - - Window win = XCreateSimpleWindow(dpy, root, 40, 60, 250, 160, 1, - BlackPixel(dpy, scr), bg); - XStoreName(dpy, win, "secure-exec wasm window"); - /* Tell the WM to honor our position (twm UsePPosition) so windows don't overlap. */ - { - XSizeHints hints; - hints.flags = PPosition | PSize; - hints.x = 40; hints.y = 60; hints.width = 250; hints.height = 160; - XSetWMNormalHints(dpy, win, &hints); - } - XSelectInput(dpy, win, ExposureMask); - XMapWindow(dpy, win); - XFlush(dpy); - mark("XW:mapped\n"); - - GC gc = XCreateGC(dpy, win, 0, NULL); - - /* Proper event-driven X loop: block in XNextEvent and (re)draw only on Expose. A real X client - * is quiet when idle — busy-redrawing would flood the shared sync-RPC bridge and starve the - * window manager's request handling. We never close the display, so the window persists. */ - int drawn = 0; - for (;;) { - XEvent ev; - XNextEvent(dpy, &ev); /* blocks until an event (e.g. Expose from the WM mapping us) */ - if (ev.type == Expose) { - XSetForeground(dpy, gc, fg); - XFillRectangle(dpy, win, gc, 15, 15, 90, 45); - XSetForeground(dpy, gc, 0x20A020); - XFillRectangle(dpy, win, gc, 120, 80, 90, 50); - XFlush(dpy); - if (!drawn) { mark("XW:drawn\n"); drawn = 1; } - } - } - return 0; -} diff --git a/experiments/wasm-gui/guest-xclient/xwin.wasm b/experiments/wasm-gui/guest-xclient/xwin.wasm deleted file mode 100755 index ebe952364..000000000 Binary files a/experiments/wasm-gui/guest-xclient/xwin.wasm and /dev/null differ diff --git a/experiments/wasm-gui/host/Cargo.toml b/experiments/wasm-gui/host/Cargo.toml deleted file mode 100644 index eb7a63910..000000000 --- a/experiments/wasm-gui/host/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "wasm-gui-host" -version = "0.0.0" -edition = "2021" -publish = false - -[[bin]] -name = "wasm-gui-host" -path = "src/main.rs" - -[features] -# Default build has NO display deps, so it runs on a headless box (the --capture path). -# The interactive window demo is behind `--features window`. -default = [] -window = ["dep:winit", "dep:softbuffer"] - -[dependencies] -# THE standard secure-exec Rust client — drives the guest through the real V8 sidecar. -# No wasmer / node:wasi / Command::new in the execution path (SPEC §1a.2). -# Workspace dep (host is a member of the repo root workspace) so it shares Cargo.lock with the -# sidecar and resolves identical transitive versions. -secure-exec-client = { workspace = true } -# For the bridge-contract version the Authenticate handshake must carry. -secure-exec-bridge = { workspace = true } -tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "io-util", "time"] } -base64 = "0.22" - -winit = { version = "0.30", optional = true } -softbuffer = { version = "0.4", optional = true } diff --git a/experiments/wasm-gui/host/src/main.rs b/experiments/wasm-gui/host/src/main.rs deleted file mode 100644 index f29492141..000000000 --- a/experiments/wasm-gui/host/src/main.rs +++ /dev/null @@ -1,918 +0,0 @@ -//! Native host for the wasm GUI guest, built on the STANDARD secure-exec Rust client -//! (`crates/secure-exec-client`). It runs `guest.wasm` INSIDE the real secure-exec V8 sidecar and -//! renders the frames it produces. Per SPEC §1a.2 this is the product path: no wasmer, no -//! node:wasi, no TypeScript client, no `Command::new` in the execution/render path — the only -//! process spawn is the sidecar itself, done by the Rust client's transport. -//! -//! Modes: -//! wasm-gui-host --capture --guest [--sidecar ] -//! Run the guest once through secure-exec, read back the framebuffer it wrote, save raw bytes. -//! Headless; this is the automated-proof path. -//! wasm-gui-host --window --guest [--sidecar ] (needs `--features window`) -//! Stream frames from the guest (run in --loop mode in the sidecar) into a native winit -//! window; forward input back through the client. Manual demo. - -use std::collections::HashMap; -use std::sync::Arc; - -use base64::prelude::*; -use secure_exec_client::transport::SidecarProcess; -use secure_exec_client::wire; - -/// PREAD chunk size: stays well under the 1 MiB default max frame even after base64 (4/3) blowup. -const READ_CHUNK: u64 = 256 * 1024; - -/// Trusted VM config: default bundled-base filesystem + allow-all permission policy (fs reads are -/// denied by default, which would block loading the wasm from /tmp). `"allow"` maps to the untagged -/// `FsPermissionScope::Mode(Allow)` etc. -const VM_CONFIG_JSON: &str = r#"{"permissions":{"fs":"allow","network":"allow","childProcess":"allow","process":"allow","env":"allow","binding":"allow"}}"#; - -type Result = std::result::Result; - -/// A connected secure-exec session bound to one VM, over the standard Rust client transport. -struct Session { - t: Arc, - connection_id: String, - session_id: String, - vm_id: String, -} - -impl Session { - async fn connect(sidecar_bin: Option) -> Result { - let t = SidecarProcess::spawn(sidecar_bin) - .await - .map_err(|e| format!("spawn sidecar: {e}"))?; - - // Authenticate. The sidecar ALLOCATES the real connection id and returns it; the id we send - // in the ownership scope here is a bootstrap placeholder it ignores. The bridge_version must - // match the bridge contract the sidecar was built against. - let auth = request( - &t, - conn_scope("bootstrap"), - wire::RequestPayload::AuthenticateRequest(wire::AuthenticateRequest { - client_name: "wasm-gui-host".into(), - auth_token: "secure-exec-core-client-token".into(), - protocol_version: wire::PROTOCOL_VERSION, - bridge_version: secure_exec_bridge::bridge_contract().version, - }), - ) - .await?; - let connection_id = match auth { - wire::ResponsePayload::AuthenticatedResponse(a) => { - t.set_max_frame_bytes(a.max_frame_bytes as usize); - a.connection_id - } - other => return Err(format!("expected Authenticated, got {other:?}")), - }; - - // Open a session (using the sidecar-allocated connection id). - let sess = request( - &t, - conn_scope(&connection_id), - wire::RequestPayload::OpenSessionRequest(wire::OpenSessionRequest { - placement: wire::SidecarPlacement::SidecarPlacementShared( - wire::SidecarPlacementShared { pool: None }, - ), - metadata: HashMap::new(), - }), - ) - .await?; - let session_id = match sess { - wire::ResponsePayload::SessionOpenedResponse(s) => s.session_id, - other => return Err(format!("expected SessionOpened, got {other:?}")), - }; - - // Create a WebAssembly VM with the default (bundled base) filesystem. - let vm = request( - &t, - wire::OwnershipScope::SessionOwnership(wire::SessionOwnership { - connection_id: connection_id.clone(), - session_id: session_id.clone(), - }), - wire::RequestPayload::CreateVmRequest(wire::CreateVmRequest { - runtime: wire::GuestRuntimeKind::WebAssembly, - // Trusted VM config (we own this VM): grant the guest fs/process access so the - // sidecar can load the wasm from /tmp and the guest can write/read /data. The - // default policy denies fs reads. - config: VM_CONFIG_JSON.into(), - }), - ) - .await?; - let vm_id = match vm { - wire::ResponsePayload::VmCreatedResponse(v) => v.vm_id, - other => return Err(format!("expected VmCreated, got {other:?}")), - }; - - Ok(Session { t, connection_id, session_id, vm_id }) - } - - fn vm_scope(&self) -> wire::OwnershipScope { - wire::OwnershipScope::VmOwnership(wire::VmOwnership { - connection_id: self.connection_id.clone(), - session_id: self.session_id.clone(), - vm_id: self.vm_id.clone(), - }) - } - - async fn fs_call(&self, req: wire::GuestFilesystemCallRequest) -> Result { - let r = request(&self.t, self.vm_scope(), wire::RequestPayload::GuestFilesystemCallRequest(req)).await?; - match r { - wire::ResponsePayload::GuestFilesystemResultResponse(res) => Ok(res), - other => Err(format!("expected GuestFilesystemResult, got {other:?}")), - } - } - - async fn mkdir(&self, path: &str) -> Result<()> { - let mut req = fs_req(wire::GuestFilesystemOperation::Mkdir, path, None, None); - req.recursive = true; - self.fs_call(req).await?; - Ok(()) - } - - async fn write_file(&self, path: &str, data: &[u8]) -> Result<()> { - let req = fs_req( - wire::GuestFilesystemOperation::WriteFile, - path, - Some(BASE64_STANDARD.encode(data)), - Some(wire::RootFilesystemEntryEncoding::Base64), - ); - self.fs_call(req).await?; - Ok(()) - } - - async fn execute(&self, process_id: &str, entrypoint: &str, args: &[&str]) -> Result<()> { - self.execute_env(process_id, entrypoint, args, HashMap::new()).await - } - - async fn execute_env( - &self, - process_id: &str, - entrypoint: &str, - args: &[&str], - env: HashMap, - ) -> Result<()> { - let r = request( - &self.t, - self.vm_scope(), - wire::RequestPayload::ExecuteRequest(wire::ExecuteRequest { - process_id: process_id.into(), - command: None, - runtime: Some(wire::GuestRuntimeKind::WebAssembly), - // The sidecar loads the wasm module from this HOST path (trusted client input). - entrypoint: Some(entrypoint.into()), - args: args.iter().map(|s| s.to_string()).collect(), - env, - cwd: Some("/".into()), - wasm_permission_tier: Some(wire::WasmPermissionTier::Full), - }), - ) - .await?; - match r { - wire::ResponsePayload::ProcessStartedResponse(_) => Ok(()), - other => Err(format!("expected ProcessStarted, got {other:?}")), - } - } - - /// Read a guest file fully via repeated PREAD chunks (each chunk fits inside one wire frame). - async fn read_file_chunked(&self, path: &str) -> Result> { - let mut out = Vec::new(); - let mut offset = 0u64; - loop { - let mut req = fs_req(wire::GuestFilesystemOperation::Pread, path, None, None); - req.len = Some(READ_CHUNK); - req.offset = Some(offset); - let res = self.fs_call(req).await?; - let chunk = decode_fs_content(&res)?; - let n = chunk.len() as u64; - out.extend_from_slice(&chunk); - if n < READ_CHUNK { - break; - } - offset += n; - } - Ok(out) - } - - async fn write_stdin(&self, process_id: &str, data: &[u8]) -> Result<()> { - request( - &self.t, - self.vm_scope(), - wire::RequestPayload::WriteStdinRequest(wire::WriteStdinRequest { - process_id: process_id.into(), - chunk: data.to_vec(), - }), - ) - .await?; - Ok(()) - } - - fn shutdown(&self) { - self.t.kill_child(); - } -} - -fn abs_path(p: &str) -> Result { - std::fs::canonicalize(p) - .map_err(|e| format!("resolve guest path {p}: {e}"))? - .to_str() - .map(|s| s.to_string()) - .ok_or_else(|| "guest path is not valid UTF-8".to_string()) -} - -fn conn_scope(connection_id: &str) -> wire::OwnershipScope { - wire::OwnershipScope::ConnectionOwnership(wire::ConnectionOwnership { - connection_id: connection_id.into(), - }) -} - -fn fs_req( - operation: wire::GuestFilesystemOperation, - path: &str, - content: Option, - encoding: Option, -) -> wire::GuestFilesystemCallRequest { - wire::GuestFilesystemCallRequest { - operation, - path: path.into(), - destination_path: None, - target: None, - content, - encoding, - recursive: false, - mode: None, - uid: None, - gid: None, - atime_ms: None, - mtime_ms: None, - len: None, - offset: None, - } -} - -fn decode_fs_content(res: &wire::GuestFilesystemResultResponse) -> Result> { - match (&res.content, &res.encoding) { - (Some(c), Some(wire::RootFilesystemEntryEncoding::Base64)) => { - BASE64_STANDARD.decode(c).map_err(|e| format!("base64 decode: {e}")) - } - (Some(c), _) => Ok(c.clone().into_bytes()), - (None, _) => Ok(Vec::new()), - } -} - -async fn request( - t: &Arc, - ownership: wire::OwnershipScope, - payload: wire::RequestPayload, -) -> Result { - let r = t - .request_wire(ownership, payload) - .await - .map_err(|e| format!("transport: {e}"))?; - if let wire::ResponsePayload::RejectedResponse(rej) = &r { - return Err(format!("rejected [{}]: {}", rej.code, rej.message)); - } - Ok(r) -} - -async fn wait_for_exit( - events: &mut tokio::sync::broadcast::Receiver<(wire::OwnershipScope, wire::EventPayload)>, - process_id: &str, -) -> Result { - loop { - match events.recv().await { - Ok((_, wire::EventPayload::ProcessExitedEvent(e))) if e.process_id == process_id => { - return Ok(e.exit_code); - } - Ok(_) => continue, - Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => continue, - Err(e) => return Err(format!("event stream closed: {e}")), - } - } -} - -// ---- capture mode (headless, automated proof) -------------------------------------------------- - -async fn run_capture(sidecar: Option, guest: &str, out: &str) -> Result<()> { - let s = Session::connect(sidecar).await?; - // Run the capture, then always kill the sidecar child regardless of success/failure. - let result = capture_inner(&s, guest, out).await; - s.shutdown(); - result -} - -async fn capture_inner(s: &Session, guest: &str, out: &str) -> Result<()> { - let guest_abs = abs_path(guest)?; - s.mkdir("/data").await?; - - let mut events = s.t.subscribe_wire_events(); - s.execute("proc-capture", &guest_abs, &["--out", "/data/frame.bin"]) - .await?; - // Bound the wait so a wedged guest can't hang the host forever. - let code = tokio::time::timeout( - std::time::Duration::from_secs(60), - wait_for_exit(&mut events, "proc-capture"), - ) - .await - .map_err(|_| "timed out waiting for guest to exit".to_string())??; - if code != 0 { - return Err(format!("guest exited with code {code}")); - } - - let bytes = s.read_file_chunked("/data/frame.bin").await?; - std::fs::write(out, &bytes).map_err(|e| format!("write {out}: {e}"))?; - eprintln!("secure-exec: captured {} bytes -> {out}", bytes.len()); - Ok(()) -} - -// ---- exec mode (run a long-lived guest, e.g. Xvfb, streaming its output for a timeout) --------- - -async fn run_exec(sidecar: Option, guest: &str, args: &[String], timeout_s: u64) -> Result<()> { - let s = Session::connect(sidecar).await?; - let guest_abs = abs_path(guest)?; - s.mkdir("/data").await.ok(); - s.mkdir("/tmp/.X11-unix").await.ok(); - let mut events = s.t.subscribe_wire_events(); - let argv: Vec<&str> = args.iter().map(|x| x.as_str()).collect(); - s.execute("proc-exec", &guest_abs, &argv).await?; - eprintln!("secure-exec: started {guest_abs} {args:?}"); - let deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(timeout_s); - loop { - let remaining = deadline.saturating_duration_since(tokio::time::Instant::now()); - if remaining.is_zero() { - break; - } - match tokio::time::timeout(remaining, events.recv()).await { - Ok(Ok((_, wire::EventPayload::ProcessOutputEvent(o)))) if o.process_id == "proc-exec" => { - let txt = String::from_utf8_lossy(&o.chunk); - let ch = if matches!(o.channel, wire::StreamChannel::Stderr) { "err" } else { "out" }; - eprint!("[{ch}] {txt}"); - } - Ok(Ok((_, wire::EventPayload::ProcessExitedEvent(e)))) if e.process_id == "proc-exec" => { - eprintln!("\nsecure-exec: guest exited with code {}", e.exit_code); - s.shutdown(); - return Ok(()); - } - Ok(Ok(_)) => continue, - Ok(Err(tokio::sync::broadcast::error::RecvError::Lagged(_))) => continue, - Ok(Err(_)) => break, - Err(_) => break, - } - } - eprintln!("\nsecure-exec: timeout ({timeout_s}s) reached"); - // Best-effort: read back a guest file (e.g. Xvfb's -fbdir framebuffer) before disposing. - if let Ok(rb) = std::env::var("READBACK") { - if let Some((gpath, hpath)) = rb.split_once(':') { - match s.read_file_chunked(gpath).await { - Ok(bytes) => { - let _ = std::fs::write(hpath, &bytes); - eprintln!("secure-exec: read back {} ({} bytes) -> {hpath}", gpath, bytes.len()); - } - Err(e) => eprintln!("secure-exec: readback {gpath} failed: {e}"), - } - } - } - s.shutdown(); - Ok(()) -} - -/// Run an X server guest and an X client guest concurrently in the SAME VM, so they share the -/// kernel socket table and the client can connect to the server's AF_UNIX socket -/// (/tmp/.X11-unix/X0). After the client finishes, read the server's framebuffer file back out. -async fn run_xdemo( - sidecar: Option, - server: &str, - clients: &[String], - server_args: &[String], - fb_out: Option<&str>, - timeout_s: u64, - fonts_dir: Option<&str>, -) -> Result<()> { - let s = Session::connect(sidecar).await?; - let server_abs = abs_path(server)?; - // Each client spec is "wasm_path arg1 arg2 ...": resolve the path, keep the args. - let mut client_specs: Vec<(String, Vec)> = Vec::new(); - for spec in clients { - let mut parts = spec.split_whitespace(); - let path = parts.next().ok_or_else(|| "empty --client spec".to_string())?; - let path_abs = abs_path(path)?; - let cargs: Vec = parts.map(|x| x.to_string()).collect(); - client_specs.push((path_abs, cargs)); - } - s.mkdir("/data").await.ok(); - s.mkdir("/tmp/.X11-unix").await.ok(); - // Provide a twm config that auto-places windows (twm's default placement is interactive and - // would never map a window without user input). Harmless for non-twm runs. - s.mkdir("/root").await.ok(); - s.write_file( - "/root/.twmrc", - b"RandomPlacement\nUsePPosition \"on\"\nNoGrabServer\nNoTitleFocus\n", - ) - .await - .ok(); - - // Install X core fonts into the VM (so the X server can serve real fonts via -fp /fonts). - if let Some(fdir) = fonts_dir { - s.mkdir("/fonts").await.ok(); - let entries = std::fs::read_dir(fdir).map_err(|e| format!("read fonts dir {fdir}: {e}"))?; - let mut n = 0; - for entry in entries.flatten() { - if !entry.path().is_file() { - continue; - } - let name = entry.file_name(); - let name = name.to_string_lossy(); - let bytes = std::fs::read(entry.path()).map_err(|e| format!("read font {name}: {e}"))?; - s.write_file(&format!("/fonts/{name}"), &bytes).await?; - n += 1; - } - eprintln!("secure-exec: installed {n} font files into /fonts"); - } - - let mut events = s.t.subscribe_wire_events(); - - // Start the X server. It binds /tmp/.X11-unix/X0 and blocks in its dispatch loop. - let sargv: Vec<&str> = server_args.iter().map(|x| x.as_str()).collect(); - s.execute("xserver", &server_abs, &sargv).await?; - eprintln!("secure-exec: started X server {server_abs} {server_args:?}"); - - let deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(timeout_s); - let mut server_ready = false; - let mut wm_ready = false; // first client (the WM) is up + idle in its loop - let mut launched = 0usize; // number of clients launched so far - let mut last_activity = tokio::time::Instant::now(); // last output from the latest client - let mut last_launch = tokio::time::Instant::now(); - let mut exited_ok = 0usize; - let mut exited_bad = 0usize; - // A client is "settled" once it has produced no output for this long after launch — i.e. it - // finished initializing and is idle in its event loop. We launch the NEXT client only then, so - // heavy libX11 startups never contend on the sidecar's single sync-RPC thread. Event-driven, - // not a fixed sleep (this mirrors a session manager waiting for the WM before starting apps). - let settle = std::time::Duration::from_millis(1500); - let min_after_launch = std::time::Duration::from_millis(800); - loop { - let remaining = deadline.saturating_duration_since(tokio::time::Instant::now()); - if remaining.is_zero() { - break; - } - // Launch the next client once the previous one is ready. The first client is the window - // manager: gate apps on it being fully up (its "WM ready" signal, or a generous fallback), - // not just a quiet pause — twm has quiet stretches mid-init while awaiting X replies. - if server_ready - && launched > 0 - && !wm_ready - && tokio::time::Instant::now().duration_since(last_launch) - >= std::time::Duration::from_secs(12) - { - wm_ready = true; // fallback: assume the WM is up if it has run a while - } - let can_launch_next = launched == 0 || wm_ready; - if server_ready && launched < client_specs.len() && can_launch_next { - let now = tokio::time::Instant::now(); - let prev_settled = launched == 0 - || (now.duration_since(last_activity) >= settle - && now.duration_since(last_launch) >= min_after_launch); - if prev_settled { - let (path, cargs) = &client_specs[launched]; - let id = format!("xclient{launched}"); - let argv: Vec<&str> = cargs.iter().map(|x| x.as_str()).collect(); - let mut cenv = HashMap::new(); - cenv.insert("DISPLAY".to_string(), ":0".to_string()); - cenv.insert("HOME".to_string(), "/root".to_string()); - s.execute_env(&id, path, &argv, cenv).await?; - eprintln!("secure-exec: launched {id} ({path})"); - launched += 1; - last_launch = tokio::time::Instant::now(); - last_activity = tokio::time::Instant::now(); - } - } - let poll = remaining.min(std::time::Duration::from_millis(300)); - match tokio::time::timeout(poll, events.recv()).await { - Ok(Ok((_, wire::EventPayload::ProcessOutputEvent(o)))) => { - let txt = String::from_utf8_lossy(&o.chunk); - let who = if o.process_id == "xserver" { "srv" } else { &o.process_id }; - let ch = if matches!(o.channel, wire::StreamChannel::Stderr) { "err" } else { "out" }; - eprint!("[{who}/{ch}] {txt}"); - if !server_ready && o.process_id == "xserver" && txt.contains("m_pre_dispatch") { - server_ready = true; - eprintln!("secure-exec: server is serving; launching {} X client(s) as each settles", client_specs.len()); - } - // Track activity of the most-recently-launched client to detect when it settles. - if launched > 0 && o.process_id == format!("xclient{}", launched - 1) { - last_activity = tokio::time::Instant::now(); - } - // The first client (window manager) announces readiness when it enters its event - // loop (twm prints "handleevents"; JWM/others similar). Gate apps on this — a real - // session manager waits for the WM before starting clients. - if !wm_ready && o.process_id == "xclient0" && txt.contains("handleevents") { - wm_ready = true; - eprintln!("secure-exec: window manager is ready; starting apps"); - } - } - Ok(Ok((_, wire::EventPayload::ProcessExitedEvent(e)))) => { - eprintln!("\nsecure-exec: {} exited with code {}", e.process_id, e.exit_code); - if e.process_id.starts_with("xclient") { - if e.exit_code == 0 { exited_ok += 1; } else { exited_bad += 1; } - if exited_ok + exited_bad >= client_specs.len() { - break; - } - } - if e.process_id == "xserver" { - break; - } - } - Ok(Ok(_)) => continue, - Ok(Err(tokio::sync::broadcast::error::RecvError::Lagged(_))) => continue, - Ok(Err(_)) => break, - Err(_) => continue, // poll timeout: loop to re-check the settle condition - } - } - - if !server_ready { - eprintln!("\nsecure-exec: server never reached dispatch; clients not launched"); - } - eprintln!( - "secure-exec: {exited_ok}/{} X client(s) completed successfully ({exited_bad} failed)", - client_specs.len() - ); - - // Read the server framebuffer out via the kernel VFS (works while the server still blocks). - if let Some(hpath) = fb_out { - match s.read_file_chunked("/data/Xvfb_screen0").await { - Ok(bytes) => { - let _ = std::fs::write(hpath, &bytes); - eprintln!("secure-exec: read back framebuffer ({} bytes) -> {hpath}", bytes.len()); - } - Err(e) => eprintln!("secure-exec: framebuffer readback failed: {e}"), - } - } - s.shutdown(); - Ok(()) -} - -// ---- arg parsing + entrypoint ------------------------------------------------------------------ - -struct Args { - mode_window: bool, - capture_out: Option, - guest: String, - sidecar: Option, - exec: bool, - exec_args: Vec, - timeout: u64, - xdemo: bool, - server: Option, - clients: Vec, - fb_out: Option, - fonts_dir: Option, -} - -fn parse_args() -> Args { - let argv: Vec = std::env::args().collect(); - let mut a = Args { - mode_window: false, - capture_out: None, - guest: "target/wasm32-wasip1/release/guest.wasm".into(), - sidecar: std::env::var("SECURE_EXEC_SIDECAR_BIN").ok(), - exec: false, - exec_args: Vec::new(), - timeout: 8, - xdemo: false, - server: None, - clients: Vec::new(), - fb_out: None, - fonts_dir: None, - }; - let mut i = 1; - while i < argv.len() { - match argv[i].as_str() { - "--window" => a.mode_window = true, - "--exec" => a.exec = true, - "--xdemo" => a.xdemo = true, - "--server" => { - i += 1; - a.server = argv.get(i).cloned(); - } - "--client" => { - i += 1; - if let Some(c) = argv.get(i) { - a.clients.push(c.clone()); - } - } - "--fb-out" => { - i += 1; - a.fb_out = argv.get(i).cloned(); - } - "--fonts-dir" => { - i += 1; - a.fonts_dir = argv.get(i).cloned(); - } - "--capture" => { - i += 1; - a.capture_out = argv.get(i).cloned(); - } - "--guest" => { - i += 1; - if let Some(g) = argv.get(i) { - a.guest = g.clone(); - } - } - "--sidecar" => { - i += 1; - a.sidecar = argv.get(i).cloned(); - } - "--timeout" => { - i += 1; - a.timeout = argv.get(i).and_then(|s| s.parse().ok()).unwrap_or(8); - } - "--" => { - // everything after `--` is passed to the guest - a.exec_args = argv[i + 1..].to_vec(); - break; - } - _ => {} - } - i += 1; - } - a -} - -#[tokio::main(flavor = "multi_thread", worker_threads = 2)] -async fn main() { - let args = parse_args(); - - if args.xdemo { - let server = args.server.clone().unwrap_or_else(|| { - eprintln!("--xdemo requires --server "); - std::process::exit(2); - }); - if args.clients.is_empty() { - eprintln!("--xdemo requires at least one --client \" [args...]\""); - std::process::exit(2); - } - if let Err(e) = run_xdemo( - args.sidecar.clone(), - &server, - &args.clients, - &args.exec_args, - args.fb_out.as_deref(), - args.timeout, - args.fonts_dir.as_deref(), - ) - .await - { - eprintln!("xdemo failed: {e}"); - std::process::exit(1); - } - return; - } - - if args.exec { - if let Err(e) = run_exec(args.sidecar.clone(), &args.guest, &args.exec_args, args.timeout).await { - eprintln!("exec failed: {e}"); - std::process::exit(1); - } - return; - } - - if let Some(out) = args.capture_out.clone() { - if let Err(e) = run_capture(args.sidecar.clone(), &args.guest, &out).await { - eprintln!("capture failed: {e}"); - std::process::exit(1); - } - return; - } - - if args.mode_window { - #[cfg(feature = "window")] - { - if let Err(e) = window::run(args.sidecar.clone(), args.guest.clone()).await { - eprintln!("window failed: {e}"); - std::process::exit(1); - } - return; - } - #[cfg(not(feature = "window"))] - { - eprintln!( - "built without the `window` feature.\n\ - Build the interactive demo with: cargo run -p wasm-gui-host --features window -- \\\n\ - --window --guest target/wasm32-wasip1/release/guest.wasm" - ); - std::process::exit(0); - } - } - - eprintln!( - "usage:\n wasm-gui-host --capture --guest [--sidecar ]\n \ - wasm-gui-host --window --guest [--sidecar ] (needs --features window)" - ); - std::process::exit(2); -} - -// ---- window mode (manual demo; needs a display) ------------------------------------------------ - -#[cfg(feature = "window")] -mod window { - use super::*; - use std::rc::Rc; - use std::sync::mpsc as std_mpsc; - - use softbuffer::{Context, Surface}; - use winit::application::ApplicationHandler; - use winit::event::{ElementState, WindowEvent}; - use winit::event_loop::{ActiveEventLoop, EventLoop}; - use winit::keyboard::{Key, NamedKey}; - use winit::window::{Window, WindowId}; - - const MAGIC: &[u8; 4] = b"SXFB"; - - pub struct Frame { - pub w: u32, - pub h: u32, - pub rgba: Vec, - } - - /// Accumulates guest stdout chunks and yields whole v0 frames. - struct FrameParser { - buf: Vec, - } - impl FrameParser { - fn new() -> Self { - Self { buf: Vec::new() } - } - fn push(&mut self, chunk: &[u8], out: &mut Vec) { - self.buf.extend_from_slice(chunk); - loop { - if self.buf.len() < 12 { - return; - } - if &self.buf[0..4] != MAGIC { - // Resync: drop one byte until magic aligns. - self.buf.remove(0); - continue; - } - let w = u32::from_le_bytes(self.buf[4..8].try_into().unwrap()); - let h = u32::from_le_bytes(self.buf[8..12].try_into().unwrap()); - // The guest output is untrusted: reject implausible dimensions (OOM guard) and - // resync rather than buffering gigabytes waiting for a frame that never completes. - const MAX_DIM: u32 = 8192; - let need = (w >= 1 && h >= 1 && w <= MAX_DIM && h <= MAX_DIM) - .then(|| (w as usize).checked_mul(h as usize).and_then(|p| p.checked_mul(4))) - .flatten() - .map(|p| p + 12); - let Some(need) = need else { - self.buf.remove(0); - continue; - }; - if self.buf.len() < need { - return; - } - let rgba = self.buf[12..need].to_vec(); - out.push(Frame { w, h, rgba }); - self.buf.drain(0..need); - } - } - } - - /// Runs the secure-exec session on the tokio runtime, streaming frames to the winit thread and - /// receiving input tokens back. Spawned before the event loop takes the main thread. - pub async fn run(sidecar: Option, guest: String) -> Result<()> { - let s = Session::connect(sidecar).await?; - let guest_abs = abs_path(&guest)?; - - let (frame_tx, frame_rx) = std_mpsc::channel::(); - let (input_tx, mut input_rx) = tokio::sync::mpsc::unbounded_channel::(); - - let mut events = s.t.subscribe_wire_events(); - s.execute("proc-window", &guest_abs, &["--loop"]).await?; - - let s = Arc::new(s); - let s_in = s.clone(); - // Forward input tokens to the guest stdin. - tokio::spawn(async move { - while let Some(line) = input_rx.recv().await { - let _ = s_in.write_stdin("proc-window", line.as_bytes()).await; - } - }); - // Pump guest stdout frames to the window. - tokio::spawn(async move { - let mut parser = FrameParser::new(); - loop { - match events.recv().await { - Ok((_, wire::EventPayload::ProcessOutputEvent(o))) - if o.process_id == "proc-window" - && matches!(o.channel, wire::StreamChannel::Stdout) => - { - let mut frames = Vec::new(); - parser.push(&o.chunk, &mut frames); - for f in frames { - if frame_tx.send(f).is_err() { - return; - } - } - } - Ok((_, wire::EventPayload::ProcessExitedEvent(e))) - if e.process_id == "proc-window" => - { - return; - } - Ok(_) => continue, - Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => continue, - Err(_) => return, - } - } - }); - - // The winit event loop must own the main thread. - let event_loop = EventLoop::new().map_err(|e| format!("event loop: {e}"))?; - let mut app = App { - frame_rx, - input_tx, - window: None, - surface: None, - last: None, - _session: s, - }; - event_loop - .run_app(&mut app) - .map_err(|e| format!("run_app: {e}")) - } - - struct App { - frame_rx: std_mpsc::Receiver, - input_tx: tokio::sync::mpsc::UnboundedSender, - window: Option>, - surface: Option, Rc>>, - last: Option, - _session: Arc, - } - - impl App { - fn redraw(&mut self) { - while let Ok(f) = self.frame_rx.try_recv() { - self.last = Some(f); - } - let (Some(surface), Some(frame)) = (self.surface.as_mut(), self.last.as_ref()) else { - return; - }; - surface - .resize( - std::num::NonZeroU32::new(frame.w).unwrap(), - std::num::NonZeroU32::new(frame.h).unwrap(), - ) - .unwrap(); - let mut buf = surface.buffer_mut().unwrap(); - for (i, px) in buf.iter_mut().enumerate() { - let s = i * 4; - let r = frame.rgba[s] as u32; - let g = frame.rgba[s + 1] as u32; - let b = frame.rgba[s + 2] as u32; - *px = (r << 16) | (g << 8) | b; - } - buf.present().unwrap(); - } - } - - impl ApplicationHandler for App { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { - let attrs = Window::default_attributes().with_title("secure-exec — wasm GUI"); - let window = Rc::new(event_loop.create_window(attrs).unwrap()); - let context = Context::new(window.clone()).unwrap(); - let surface = Surface::new(&context, window.clone()).unwrap(); - self.surface = Some(surface); - self.window = Some(window); - } - - fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { - match event { - WindowEvent::CloseRequested => { - let _ = self.input_tx.send("q".into()); - event_loop.exit(); - } - WindowEvent::CursorMoved { position, .. } => { - let _ = self - .input_tx - .send(format!("p {} {}", position.x as i32, position.y as i32)); - if let Some(w) = self.window.as_ref() { - w.request_redraw(); - } - } - WindowEvent::KeyboardInput { event, .. } => { - if event.state == ElementState::Pressed { - if let Key::Named(NamedKey::Escape) = event.logical_key { - let _ = self.input_tx.send("q".into()); - event_loop.exit(); - } - } - } - WindowEvent::RedrawRequested => { - self.redraw(); - if let Some(w) = self.window.as_ref() { - w.request_redraw(); - } - } - _ => {} - } - } - } -} diff --git a/experiments/wasm-gui/scripts/build-nuklear.sh b/experiments/wasm-gui/scripts/build-nuklear.sh deleted file mode 100755 index 2d64fb348..000000000 --- a/experiments/wasm-gui/scripts/build-nuklear.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -# Build the M3 Nuklear guest (real toolkit) to wasm32-wasip1 with the vendored wasi-sdk. -set -euo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)" -REPO="$(cd ../.. && pwd)" -WSDK="${WASI_SDK:-$REPO/registry/native/c/vendor/wasi-sdk}" -[ -x "$WSDK/bin/clang" ] || { echo "wasi-sdk clang not found at $WSDK"; exit 1; } - -"$WSDK/bin/clang" \ - --target=wasm32-wasip1 \ - --sysroot="$WSDK/share/wasi-sysroot" \ - -O2 -std=c99 \ - -I "$EXP/third_party/nuklear" \ - "$EXP/guest-nuklear/guest_nuklear.c" -lm \ - -o "$EXP/guest-nuklear/guest_nuklear.wasm" -echo "built guest-nuklear/guest_nuklear.wasm ($(stat -c%s "$EXP/guest-nuklear/guest_nuklear.wasm") bytes)" diff --git a/experiments/wasm-gui/scripts/build-xfill.sh b/experiments/wasm-gui/scripts/build-xfill.sh deleted file mode 100755 index c23865a97..000000000 --- a/experiments/wasm-gui/scripts/build-xfill.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -# Build the minimal raw-X11 client (xfill) to wasm32-wasip1 against the PATCHED sysroot -# that provides POSIX sockets backed by secure-exec's host_net imports. -set -euo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)" -REPO="$(cd ../.. && pwd)" -WSDK="$REPO/registry/native/c/vendor/wasi-sdk" -SYSROOT="$REPO/registry/native/c/sysroot" - -"$WSDK/bin/clang" \ - --target=wasm32-wasip1 \ - --sysroot="$SYSROOT" \ - -O2 -std=c11 \ - "$EXP/guest-xclient/xfill.c" \ - -o "$EXP/guest-xclient/xfill.wasm" -echo "built guest-xclient/xfill.wasm ($(stat -c%s "$EXP/guest-xclient/xfill.wasm") bytes)" diff --git a/experiments/wasm-gui/scripts/build-xlib.sh b/experiments/wasm-gui/scripts/build-xlib.sh deleted file mode 100755 index 69f5de2b2..000000000 --- a/experiments/wasm-gui/scripts/build-xlib.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -# Cross-compile one autotools X.Org library/app to wasm32-wasip1 against the patched sysroot. -# Usage: build-xlib.sh [extra configure args...] -set -uo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)" -source "$EXP/toolchain/cross-env.sh" -DIR="$1"; shift || true -SRC="$EXP/third_party/$DIR" -[ -d "$SRC" ] || { echo "no such source dir: $SRC"; exit 1; } -cd "$SRC" - -echo "== configuring $DIR ==" -./configure $CROSS_CONFIGURE_ARGS "$@" > /tmp/conf-$DIR.log 2>&1 -if [ $? -ne 0 ]; then echo "CONFIGURE FAILED ($DIR); tail:"; tail -25 /tmp/conf-$DIR.log; exit 1; fi - -echo "== building $DIR ==" -make -j4 > /tmp/make-$DIR.log 2>&1 -RC=$? -if [ $RC -ne 0 ]; then echo "MAKE FAILED ($DIR); tail:"; tail -30 /tmp/make-$DIR.log; exit 1; fi - -echo "== installing $DIR ==" -make install > /tmp/install-$DIR.log 2>&1 || { echo "INSTALL FAILED ($DIR)"; tail -15 /tmp/install-$DIR.log; exit 1; } -echo "OK: $DIR built + installed to wasm-prefix" diff --git a/experiments/wasm-gui/scripts/link-twm.sh b/experiments/wasm-gui/scripts/link-twm.sh deleted file mode 100755 index 8330de4c5..000000000 --- a/experiments/wasm-gui/scripts/link-twm.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -# Link twm.wasm: the autotools build produces the objects but the final executable link needs the -# wasi-compat stub object + Xau/Xdmcp/setjmp + the patched libc (host_net sockets). Mirrors -# link-xvfb.sh. Produces experiments/wasm-gui/twm.wasm. -set -uo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)" -source "$EXP/toolchain/cross-env.sh" -SRC="$EXP/third_party/twm/src" -P="$EXP/third_party/wasm-prefix/lib" -SETJMP="$WSDK/share/wasi-sysroot/lib/wasm32-wasip1/libsetjmp.a" -LIBC="$REPO/registry/native/c/sysroot/lib/wasm32-wasip1/libc.a" -COMPAT="$EXP/toolchain/wasi-compat.o" -export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH" - -OBJS="add_window.o cursor.o deftwmrc.o events.o gc.o iconmgr.o icons.o list.o menus.o parse.o resize.o session.o twm.o util.o version.o gram.o lex.o" - -cd "$SRC" -"$CC" $CFLAGS $LDFLAGS \ - -Wl,--allow-undefined \ - -o twm $OBJS \ - "$COMPAT" \ - -L"$P" -lXmu -lXext -lXt -lX11 -lSM -lICE -lxcb -lXau -lXdmcp \ - "$SETJMP" "$LIBC" 2>&1 | grep -iE "error|undefined" | head -20 -RC=${PIPESTATUS[0]} - -if [ -f twm ]; then - cp twm "$EXP/twm.wasm" - echo "linked twm.wasm ($(stat -c%s "$EXP/twm.wasm") bytes)" -else - echo "LINK FAILED"; exit 1 -fi diff --git a/experiments/wasm-gui/scripts/link-xapp.sh b/experiments/wasm-gui/scripts/link-xapp.sh deleted file mode 100755 index b704fbe05..000000000 --- a/experiments/wasm-gui/scripts/link-xapp.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -# Link a cross-compiled X.Org Athena/Xt app (xclock, xcalc, ...) to wasm: the autotools build makes -# the objects but the final executable needs wasi-compat stubs + the full lib set + patched libc. -# Usage: link-xapp.sh -set -uo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)" -source "$EXP/toolchain/cross-env.sh" -DIR="$1"; OUT="$2"; shift 2 -OBJS="$*" -SRC="$EXP/third_party/$DIR" -P="$EXP/third_party/wasm-prefix/lib" -SETJMP="$WSDK/share/wasi-sysroot/lib/wasm32-wasip1/libsetjmp.a" -LIBC="$REPO/registry/native/c/sysroot/lib/wasm32-wasip1/libc.a" -COMPAT="$EXP/toolchain/wasi-compat.o" -export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH" - -cd "$SRC" -"$CC" $CFLAGS $LDFLAGS -Wl,--allow-undefined \ - -o "$OUT" $OBJS "$COMPAT" \ - -L"$P" -lXaw7 -lXmu -lXt -lXpm -lXext -lXrender -lX11 -lSM -lICE -lxcb -lXau -lXdmcp \ - "$SETJMP" "$LIBC" 2>&1 | grep -iE "error|undefined" | head -20 -if [ -f "$OUT" ]; then - wasm-opt --fpcast-emu -O0 "$OUT" -o "$OUT.fp" 2>/dev/null && mv "$OUT.fp" "$OUT" - cp "$OUT" "$EXP/$OUT.wasm" - echo "linked $OUT.wasm ($(stat -c%s "$EXP/$OUT.wasm") bytes)" -else - echo "LINK FAILED ($OUT)"; exit 1 -fi diff --git a/experiments/wasm-gui/scripts/link-xvfb.sh b/experiments/wasm-gui/scripts/link-xvfb.sh deleted file mode 100755 index 449e46f01..000000000 --- a/experiments/wasm-gui/scripts/link-xvfb.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash -# Rebuild the X server objects (ninja) then link Xvfb.wasm with the fixups wasm-ld/secure-exec need: -# - force __main_argc_argv (wasi crt only weak-refs main, so it gets GC'd) -# - append libfontenc/freetype/z/Xau/Xdmcp + libsetjmp + the patched libc (archive ordering) -set -uo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)" -BW="$EXP/third_party/xserver/build-wasm" -WSDK=/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk -SETJMP="$WSDK/share/wasi-sysroot/lib/wasm32-wasip1/libsetjmp.a" -LIBC=/home/nathan/secure-exec/registry/native/c/sysroot/lib/wasm32-wasip1/libc.a -P="$EXP/third_party/wasm-prefix/lib" -MAINOBJ="$EXP/toolchain/xvfb-main.o" -export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH" - -# rebuild objects (the default final link fails on weak main — that's expected/ignored) -# -k 0: keep compiling all objects even if some unrelated target (e.g. an xcb-using test client) -# fails to link; we only need the dix/os/hw/vfb objects for the custom Xvfb link below. -ninja -k 0 -C "$BW" >/dev/null 2>&1 || true - -ninja -C "$BW" -t commands hw/vfb/Xvfb 2>/dev/null | tail -1 > /tmp/link-xvfb.sh -sed -i "s| -o hw/vfb/Xvfb| -Wl,--undefined=__main_argc_argv $MAINOBJ -o hw/vfb/Xvfb|" /tmp/link-xvfb.sh -sed -i "s| -Wl,--end-group| $P/libXfont2.a $P/libfontenc.a $P/libfreetype.a $P/libz.a $P/libXau.a $P/libXdmcp.a $SETJMP $LIBC -Wl,--end-group|" /tmp/link-xvfb.sh -( cd "$BW" && rm -f hw/vfb/Xvfb && bash /tmp/link-xvfb.sh ) -RC=$? -if [ -f "$BW/hw/vfb/Xvfb" ]; then - cp "$BW/hw/vfb/Xvfb" "$EXP/Xvfb.wasm" - echo "linked Xvfb.wasm ($(stat -c%s "$EXP/Xvfb.wasm") bytes)" -else - echo "LINK FAILED (rc=$RC)"; exit 1 -fi diff --git a/experiments/wasm-gui/scripts/prepare-fonts.sh b/experiments/wasm-gui/scripts/prepare-fonts.sh deleted file mode 100755 index ec059629a..000000000 --- a/experiments/wasm-gui/scripts/prepare-fonts.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -# Prepare a minimal X core font directory (/tmp/vmfonts by default) the host installs into the VM -# (--fonts-dir) so the wasm X server can serve real fonts via `-fp /fonts`. Uses the host system's -# X11 PCF fonts + mkfontdir. Run once before the M6 desktop test/example. -set -euo pipefail -OUT="${1:-/tmp/vmfonts}" -MISC=/usr/share/fonts/X11/misc -DPI=/usr/share/fonts/X11/75dpi -command -v mkfontdir >/dev/null || { echo "need mkfontdir (xfonts-utils)"; exit 1; } -[ -d "$MISC" ] || { echo "need X core fonts at $MISC (xfonts-base)"; exit 1; } - -rm -rf "$OUT"; mkdir -p "$OUT" -for f in cursor 6x13 6x13B 7x13 7x13B 8x13 8x13B 9x15 9x15B 10x20 5x8 12x24; do - [ -f "$MISC/$f.pcf.gz" ] && cp "$MISC/$f.pcf.gz" "$OUT/" || true -done -for f in helvR12 helvB12 helvR14 helvB14 timR12 timR14 courR12 courB12; do - [ -f "$DPI/$f.pcf.gz" ] && cp "$DPI/$f.pcf.gz" "$OUT/" || true -done -cd "$OUT" -mkfontdir . -# Add iso8859-1 duplicate entries (the PCF files contain Latin-1) for the C-locale fontset, plus -# the classic aliases apps expect. -tail -n +2 fonts.dir | sed 's/iso10646-1$/iso8859-1/' > /tmp/.fd8859 || true -{ tail -n +2 fonts.dir; cat /tmp/.fd8859; } | sort -u > /tmp/.fdall -{ echo "$(wc -l < /tmp/.fdall)"; cat /tmp/.fdall; } > fonts.dir -cat > fonts.alias <<'EOF' -fixed -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso8859-1 -variable -adobe-helvetica-bold-r-normal--12-120-75-75-p-70-iso8859-1 -EOF -echo "prepared $OUT ($(ls *.pcf.gz | wc -l) PCF fonts, $(head -1 fonts.dir) fonts.dir entries)" diff --git a/experiments/wasm-gui/scripts/test-m4b.sh b/experiments/wasm-gui/scripts/test-m4b.sh deleted file mode 100755 index 8b305857e..000000000 --- a/experiments/wasm-gui/scripts/test-m4b.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -# Automated M4b test: run the cross-compiled wasm Xvfb X server + a raw-X11 wasm client in one -# secure-exec VM, have the client draw a solid fill, read the framebuffer back, and assert it -# contains the expected color. Exits non-zero on any failure. -set -euo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)" -REPO="$(cd ../.. && pwd)" - -HOST="$REPO/target/debug/wasm-gui-host" -SIDECAR="$REPO/target/debug/secure-exec-sidecar" -XVFB="$EXP/Xvfb.wasm" -XFILL="$EXP/guest-xclient/xfill.wasm" -FB="$(mktemp /tmp/m4b-fb.XXXXXX.bin)" - -for f in "$HOST" "$SIDECAR" "$XVFB" "$XFILL"; do - [ -f "$f" ] || { echo "MISSING: $f (build it first)"; exit 1; } -done - -echo "== running Xvfb + xfill in one VM ==" -timeout 90 env -u DISPLAY "$HOST" --xdemo --timeout 16 \ - --server "$XVFB" --client "$XFILL" --fb-out "$FB" --sidecar "$SIDECAR" \ - -- :0 -screen 0 640x480x24 -nolisten tcp -nolock -listen local -fbdir /data > /tmp/m4b-run.log 2>&1 || true - -echo "== checking results ==" -grep -q "CMARK:done" /tmp/m4b-run.log || { echo "FAIL: client did not finish handshake+draw"; tail -20 /tmp/m4b-run.log; exit 1; } -grep -qE "1/1 X client\(s\) completed successfully" /tmp/m4b-run.log || { echo "FAIL: client exit non-zero"; tail -5 /tmp/m4b-run.log; exit 1; } - -python3 - "$FB" <<'PY' -import sys, struct -data = open(sys.argv[1], 'rb').read() -assert len(data) >= 160 + 640*480*4, f"framebuffer too small: {len(data)}" -pix = data[160:160+640*480*4] -target = bytes([0x00, 0x88, 0xFF, 0x00]) # BGRX bytes for RGB 0xFF8800 -match = sum(1 for i in range(0, len(pix), 4) if pix[i:i+4] == target) -frac = match / (640*480) -print(f"matching pixels: {match}/{640*480} = {frac:.3%}") -assert frac > 0.95, f"fill color coverage too low: {frac:.3%}" -print("PASS: framebuffer is filled with the X client's color") -PY - -rm -f "$FB" -echo "== M4b PASS ==" diff --git a/experiments/wasm-gui/scripts/test-m5-multiclient.sh b/experiments/wasm-gui/scripts/test-m5-multiclient.sh deleted file mode 100755 index 706d9620f..000000000 --- a/experiments/wasm-gui/scripts/test-m5-multiclient.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -# M5 multi-client test: run the wasm Xvfb X server + THREE independent raw-X11 wasm clients in one -# secure-exec VM, each drawing a different-colored rectangle over AF_UNIX, and assert the shared -# server's framebuffer contains all three colors composited together. -set -euo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)" -REPO="$(cd ../.. && pwd)" - -HOST="$REPO/target/debug/wasm-gui-host" -SIDECAR="$REPO/target/debug/secure-exec-sidecar" -XVFB="$EXP/Xvfb.wasm" -XFILL="$EXP/guest-xclient/xfill.wasm" -FB="$(mktemp /tmp/m5-fb.XXXXXX.bin)" - -for f in "$HOST" "$SIDECAR" "$XVFB" "$XFILL"; do - [ -f "$f" ] || { echo "MISSING: $f (build it first)"; exit 1; } -done - -echo "== running Xvfb + 3 X clients in one VM ==" -timeout 90 env -u DISPLAY "$HOST" --xdemo --timeout 22 \ - --server "$XVFB" \ - --client "$XFILL 0 0 -1 -1 16746496" \ - --client "$XFILL 80 80 200 150 65280" \ - --client "$XFILL 360 250 200 150 255" \ - --fb-out "$FB" --sidecar "$SIDECAR" \ - -- :0 -screen 0 640x480x24 -nolisten tcp -nolock -listen local -noreset -fbdir /data > /tmp/m5-run.log 2>&1 || true - -python3 - "$FB" <<'PY' -import sys -data = open(sys.argv[1], 'rb').read() -pix = data[160:160+640*480*4] -# BGRX bytes: orange 0xFF8800 -> 0088ff00, green 0x00FF00 -> 00ff0000, blue 0x0000FF -> ff000000 -want = {"orange bg": b'\x00\x88\xff\x00', "green rect": b'\x00\xff\x00\x00', "blue rect": b'\xff\x00\x00\x00'} -counts = {k: 0 for k in want} -for i in range(0, len(pix), 4): - px = pix[i:i+4] - for k, v in want.items(): - if px == v: - counts[k] += 1 -for k, n in counts.items(): - print(f" {k}: {n} px") -assert counts["orange bg"] > 100000, "background fill missing" -assert counts["green rect"] >= 25000, "green client did not render" -assert counts["blue rect"] >= 25000, "blue client did not render" -print("PASS: all three X clients rendered onto the shared wasm X server") -PY - -rm -f "$FB" -echo "== M5 multi-client PASS ==" diff --git a/experiments/wasm-gui/scripts/test-m5-twm.sh b/experiments/wasm-gui/scripts/test-m5-twm.sh deleted file mode 100755 index 5a24fe0d6..000000000 --- a/experiments/wasm-gui/scripts/test-m5-twm.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash -# Automated M5 test: run the standard window manager twm + a real libX11 client window in one -# secure-exec VM (all cross-compiled to wasm), and assert the captured framebuffer shows the -# WM-decorated client window: the client's window body + content rectangles AND twm's title-bar -# decoration. Proves a standard, unmodified window manager manages a real toolkit client. -set -uo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)" -REPO="$(cd ../.. && pwd)" - -HOST="$REPO/target/debug/wasm-gui-host" -SIDECAR="$REPO/target/debug/secure-exec-sidecar" -XVFB="$EXP/Xvfb.wasm" -TWM="$EXP/twm.wasm" -XWIN="$EXP/guest-xclient/xwin.wasm" -FB="$(mktemp /tmp/m5twm-fb.XXXXXX.bin)" - -for f in "$HOST" "$SIDECAR" "$XVFB" "$TWM" "$XWIN"; do - [ -f "$f" ] || { echo "MISSING: $f (build it first)"; exit 1; } -done - -echo "== running Xvfb + twm (WM) + a libX11 client window in one VM ==" -timeout 90 env -u DISPLAY "$HOST" --xdemo --timeout 30 \ - --server "$XVFB" --client "$TWM" --client "$XWIN" \ - --fb-out "$FB" --sidecar "$SIDECAR" \ - -- :0 -screen 0 640x480x24 -nolisten tcp -nolock -listen local -noreset -fbdir /data > /tmp/m5twm-run.log 2>&1 || true - -python3 - "$FB" <<'PY' -import sys -data = open(sys.argv[1], 'rb').read() -pix = data[160:160+640*480*4] -# BGRX bytes: window body 0x3060C0->c0603000, green 0x20A020->20a02000, twm title highlight white -counts = {} -for name, hexv in [("window body","c0603000"), ("green rect","20a02000"), - ("client white","f0f0f000"), ("twm titlebar","ffffff00")]: - counts[name] = sum(1 for i in range(0,len(pix),4) if pix[i:i+4].hex()==hexv) -for k,v in counts.items(): - print(f" {k}: {v} px") -assert counts["window body"] > 20000, "client window not mapped by the WM" -assert counts["green rect"] > 3000 and counts["client white"] > 3000, "client did not draw into its window" -assert counts["twm titlebar"] > 500, "twm did not decorate the window with a title bar" -print("PASS: twm decorated and is managing the libX11 client window") -PY - -rm -f "$FB" -echo "== M5 twm window-manager PASS ==" diff --git a/experiments/wasm-gui/scripts/test-m6-desktop.sh b/experiments/wasm-gui/scripts/test-m6-desktop.sh deleted file mode 100755 index b249197b7..000000000 --- a/experiments/wasm-gui/scripts/test-m6-desktop.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -# M6 test: a robust multi-app desktop — the standard X.Org window manager twm managing a real -# libX11 client window AND a stock xclock app, all wasm in one secure-exec VM, with real X core -# fonts. Asserts the framebuffer shows the WM-decorated client window (body + content + title bar). -set -uo pipefail -cd "$(dirname "$0")/.." -EXP="$(pwd)"; REPO="$(cd ../.. && pwd)" -HOST="$REPO/target/debug/wasm-gui-host"; SIDECAR="$REPO/target/debug/secure-exec-sidecar" -FB="$(mktemp /tmp/m6-fb.XXXXXX.bin)" -FONTS="${VMFONTS:-/tmp/vmfonts}" - -for f in "$HOST" "$SIDECAR" "$EXP/Xvfb.wasm" "$EXP/twm.wasm" "$EXP/xclock.wasm" "$EXP/guest-xclient/xwin.wasm"; do - [ -f "$f" ] || { echo "MISSING: $f"; exit 1; } -done -[ -d "$FONTS" ] || { echo "MISSING fonts dir $FONTS (set VMFONTS)"; exit 1; } - -echo "== twm + xclock + a libX11 window, with X core fonts ==" -timeout 90 env -u DISPLAY "$HOST" --xdemo --timeout 40 \ - --server "$EXP/Xvfb.wasm" \ - --client "$EXP/twm.wasm" \ - --client "$EXP/xclock.wasm -analog" \ - --client "$EXP/guest-xclient/xwin.wasm" \ - --fonts-dir "$FONTS" --fb-out "$FB" --sidecar "$SIDECAR" \ - -- :0 -screen 0 640x480x24 -nolisten tcp -nolock -listen local -noreset -fbdir /data -fp /fonts > /tmp/m6-run.log 2>&1 || true - -grep -q "window manager is ready" /tmp/m6-run.log || { echo "FAIL: WM did not signal ready"; exit 1; } -python3 - "$FB" <<'PY' -import sys -data=open(sys.argv[1],'rb').read(); pix=data[160:160+640*480*4] -def cnt(hexv): return sum(1 for i in range(0,len(pix),4) if pix[i:i+4].hex()==hexv) -body=cnt("c0603000"); green=cnt("20a02000"); title=cnt("ffffff00") -print(f" window body: {body} green rect: {green} twm titlebar/white: {title}") -assert body > 20000, "WM did not map the client window" -assert green > 2000, "client did not draw into its window" -assert title > 1000, "twm did not decorate (no title bar)" -print("PASS: twm manages a real libX11 window + a stock xclock, with real fonts") -PY -rm -f "$FB" -echo "== M6 desktop PASS ==" diff --git a/experiments/wasm-gui/tests/RESULTS.txt b/experiments/wasm-gui/tests/RESULTS.txt deleted file mode 100644 index 950da28f1..000000000 --- a/experiments/wasm-gui/tests/RESULTS.txt +++ /dev/null @@ -1,9 +0,0 @@ -## M1 automated test (through secure-exec) — 2026-06-20T07:37:35Z -build: guest.wasm OK (102752 bytes) -build: wasm-gui-host + secure-exec-sidecar OK - secure-exec: captured 1228812 bytes -> /tmp/tmp.H5nUlMEVbF/frame_secureexec.bin -secure-exec capture: 1228812 bytes - header OK (640x480), 7 golden pixels match -frame size: 1228812 bytes == 12 + 640*480*4 (exact) -proof PNG: /home/nathan/tmp/gui-progress/assets/frame_secureexec.png (8006 bytes) -RESULT: PASS (frame rendered by guest INSIDE secure-exec, via the standard Rust client) diff --git a/experiments/wasm-gui/tests/check.mjs b/experiments/wasm-gui/tests/check.mjs deleted file mode 100644 index b746f32a9..000000000 --- a/experiments/wasm-gui/tests/check.mjs +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env node -// Frame validator + golden-pixel regression check (milestone M0). -// node check.mjs [--bless] -// Validates the v0 header, samples fixed coordinates on the raw RGBA payload, and compares them -// to golden.json (or writes it with --bless). Operates on raw bytes only — no PNG in the loop. - -import { readFileSync, writeFileSync, existsSync } from "node:fs"; - -const [, , binPath, goldenPath, mode] = process.argv; -if (!binPath || !goldenPath) { - console.error("usage: node check.mjs [--bless]"); - process.exit(2); -} - -const EXPECT_W = 640; -const EXPECT_H = 480; -// Coordinates chosen to hit distinct regions: panel bg, accent dot, wallpaper, inactive title -// bar, active title bar, window body, cursor tip. -const COORDS = [ - [2, 4], - [10, 11], - [320, 30], - [80, 105], - [520, 175], - [400, 300], - [300, 235], -]; - -const buf = readFileSync(binPath); - -function fail(msg) { - console.error(`FAIL: ${msg}`); - process.exit(1); -} - -if (buf.length < 12) fail(`frame too small (${buf.length} bytes)`); -const magic = buf.subarray(0, 4).toString("latin1"); -if (magic !== "SXFB") fail(`bad magic ${JSON.stringify(magic)} (want "SXFB")`); -const w = buf.readUInt32LE(4); -const h = buf.readUInt32LE(8); -if (w !== EXPECT_W || h !== EXPECT_H) fail(`bad dims ${w}x${h} (want ${EXPECT_W}x${EXPECT_H})`); -const expectedLen = 12 + w * h * 4; -if (buf.length !== expectedLen) fail(`bad length ${buf.length} (want ${expectedLen})`); - -function px(x, y) { - const o = 12 + (y * w + x) * 4; - return [buf[o], buf[o + 1], buf[o + 2], buf[o + 3]]; -} - -const samples = {}; -for (const [x, y] of COORDS) samples[`${x},${y}`] = px(x, y); - -if (mode === "--bless") { - writeFileSync(goldenPath, JSON.stringify(samples, null, 2) + "\n"); - console.error(`blessed golden -> ${goldenPath}`); - process.exit(0); -} - -if (!existsSync(goldenPath)) fail(`no golden file at ${goldenPath} (run with --bless first)`); -const golden = JSON.parse(readFileSync(goldenPath, "utf8")); -let mismatches = 0; -for (const key of Object.keys(golden)) { - const got = samples[key]; - const want = golden[key]; - if (!got || JSON.stringify(got) !== JSON.stringify(want)) { - console.error(` pixel ${key}: got ${JSON.stringify(got)} want ${JSON.stringify(want)}`); - mismatches++; - } -} -if (mismatches) fail(`${mismatches} golden-pixel mismatch(es)`); -console.error(`header OK (${w}x${h}), ${COORDS.length} golden pixels match`); diff --git a/experiments/wasm-gui/tests/golden-nuklear.json b/experiments/wasm-gui/tests/golden-nuklear.json deleted file mode 100644 index ba68bbcc8..000000000 --- a/experiments/wasm-gui/tests/golden-nuklear.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "2,4": [ - 28, - 64, - 96, - 255 - ], - "10,11": [ - 28, - 64, - 96, - 255 - ], - "320,30": [ - 28, - 64, - 96, - 255 - ], - "80,105": [ - 45, - 45, - 45, - 255 - ], - "520,175": [ - 40, - 40, - 40, - 255 - ], - "400,300": [ - 45, - 45, - 45, - 255 - ], - "300,235": [ - 38, - 38, - 38, - 255 - ] -} diff --git a/experiments/wasm-gui/tests/golden.json b/experiments/wasm-gui/tests/golden.json deleted file mode 100644 index 978ce9c1e..000000000 --- a/experiments/wasm-gui/tests/golden.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "2,4": [ - 24, - 28, - 38, - 255 - ], - "10,11": [ - 93, - 176, - 255, - 255 - ], - "320,30": [ - 31, - 82, - 119, - 255 - ], - "80,105": [ - 70, - 78, - 92, - 255 - ], - "520,175": [ - 59, - 110, - 165, - 255 - ], - "400,300": [ - 244, - 245, - 247, - 255 - ], - "300,235": [ - 245, - 245, - 245, - 255 - ] -} diff --git a/experiments/wasm-gui/tests/run-nuklear.sh b/experiments/wasm-gui/tests/run-nuklear.sh deleted file mode 100755 index 32db786b6..000000000 --- a/experiments/wasm-gui/tests/run-nuklear.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env bash -# Automated M3 test: cross-compile the REAL Nuklear toolkit guest to wasm (wasi-sdk), run it THROUGH -# the secure-exec V8 sidecar via the Rust client, read back the framebuffer, validate header + -# golden pixels, emit a PNG proof. Headless; no display. -# -# ./tests/run-nuklear.sh verify against committed golden -# ./tests/run-nuklear.sh --bless (re)generate golden-nuklear.json -set -euo pipefail - -cd "$(dirname "$0")/.." -EXP="$(pwd)" -REPO="$(cd ../.. && pwd)" -GUEST_WASM="$EXP/guest-nuklear/guest_nuklear.wasm" -HOST_BIN="$REPO/target/debug/wasm-gui-host" -SIDECAR_BIN="$REPO/target/debug/secure-exec-sidecar" -GOLDEN="$EXP/tests/golden-nuklear.json" -ASSETS="${PROOF_ASSETS:-$HOME/tmp/gui-progress/assets}" -BLESS="${1:-}" - -WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT -FRAME="$WORK/frame_nuklear.bin" -mkdir -p "$ASSETS" -emit() { printf '%s\n' "$*"; } - -emit "## M3 automated test (real Nuklear toolkit through secure-exec) — $(date -u +%Y-%m-%dT%H:%M:%SZ)" - -# 1. Build the Nuklear guest with wasi-sdk -emit "[1/6] building Nuklear guest (wasi-sdk -> wasm32-wasip1)…" -"$EXP/scripts/build-nuklear.sh" >/dev/null -[ -f "$GUEST_WASM" ] || { emit "FAIL: guest_nuklear.wasm not built"; exit 1; } -emit "build: guest_nuklear.wasm OK ($(stat -c%s "$GUEST_WASM") bytes)" - -# 2. Ensure host + sidecar exist -emit "[2/6] ensuring host + sidecar…" -( cd "$REPO" && cargo build -p secure-exec-sidecar -p wasm-gui-host >/dev/null 2>&1 ) -[ -x "$HOST_BIN" ] && [ -x "$SIDECAR_BIN" ] || { emit "FAIL: host/sidecar missing"; exit 1; } - -# 3. Run the real toolkit THROUGH secure-exec -emit "[3/6] running Nuklear toolkit inside the secure-exec V8 sidecar…" -env -u DISPLAY -u WAYLAND_DISPLAY "$HOST_BIN" \ - --capture "$FRAME" --guest "$GUEST_WASM" --sidecar "$SIDECAR_BIN" 2>&1 | sed 's/^/ /' -[ -f "$FRAME" ] || { emit "FAIL: no frame captured"; exit 1; } - -# 4. Header + golden pixels -emit "[4/6] validating header + golden pixels…" -if [ "$BLESS" = "--bless" ]; then - node "$EXP/tests/check.mjs" "$FRAME" "$GOLDEN" --bless -fi -node "$EXP/tests/check.mjs" "$FRAME" "$GOLDEN" 2>&1 | sed 's/^/ /' - -# 5. Exact frame size -EXPECT=$((12 + 640*480*4)) -GOT=$(stat -c%s "$FRAME") -[ "$GOT" = "$EXPECT" ] || { emit "FAIL: frame size $GOT != $EXPECT"; exit 1; } -emit "frame size: $GOT bytes == 12 + 640*480*4 (exact)" - -# 6. PNG proof -emit "[6/6] PNG proof…" -tail -c +13 "$FRAME" > "$WORK/raw.rgba" -ffmpeg -y -f rawvideo -pixel_format rgba -video_size 640x480 -i "$WORK/raw.rgba" \ - -frames:v 1 "$ASSETS/frame_nuklear.png" >/dev/null 2>&1 -emit "proof PNG: $ASSETS/frame_nuklear.png" -emit "RESULT: PASS (real Nuklear toolkit rendered INSIDE secure-exec, via the Rust client)" diff --git a/experiments/wasm-gui/tests/run.sh b/experiments/wasm-gui/tests/run.sh deleted file mode 100755 index d783e5588..000000000 --- a/experiments/wasm-gui/tests/run.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash -# Automated M1 test: build the wasm guest, run it THROUGH THE REAL secure-exec V8 sidecar via the -# standard Rust client host (no wasmer/node:wasi), read the framebuffer back through the client, -# validate the header, check golden pixels, and emit a PNG proof. Headless; no network. -# -# ./tests/run.sh verify against the committed golden -# ./tests/run.sh --bless (re)generate golden.json from the current build -set -euo pipefail - -cd "$(dirname "$0")/.." -EXP="$(pwd)" -REPO="$(cd ../.. && pwd)" -GUEST_WASM="$EXP/guest/target/wasm32-wasip1/release/guest.wasm" -HOST_BIN="$REPO/target/debug/wasm-gui-host" -SIDECAR_BIN="$REPO/target/debug/secure-exec-sidecar" -GOLDEN="$EXP/tests/golden.json" -RESULTS="$EXP/tests/RESULTS.txt" -ASSETS="${PROOF_ASSETS:-$HOME/tmp/gui-progress/assets}" -BLESS="${1:-}" - -WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT -FRAME="$WORK/frame_secureexec.bin" -mkdir -p "$ASSETS"; : > "$RESULTS" -emit() { printf '%s\n' "$*" | tee -a "$RESULTS"; } -log() { printf '%s\n' "$*"; } - -emit "## M1 automated test (through secure-exec) — $(date -u +%Y-%m-%dT%H:%M:%SZ)" - -# 1. Build guest (standalone wasm workspace) -log "[1/7] building guest (wasm32-wasip1)…" -( cd "$EXP/guest" && cargo build --target wasm32-wasip1 --release >/dev/null 2>&1 ) -[ -f "$GUEST_WASM" ] || { emit "FAIL: guest.wasm not built"; exit 1; } -emit "build: guest.wasm OK ($(stat -c%s "$GUEST_WASM") bytes)" - -# 2. Build host + sidecar (root workspace, shared lock) -log "[2/7] building host + sidecar (root workspace)…" -( cd "$REPO" && cargo build -p secure-exec-sidecar -p wasm-gui-host >/dev/null 2>&1 ) -[ -x "$HOST_BIN" ] || { emit "FAIL: host binary missing"; exit 1; } -[ -x "$SIDECAR_BIN" ] || { emit "FAIL: sidecar binary missing"; exit 1; } -emit "build: wasm-gui-host + secure-exec-sidecar OK" - -# 3. Capture a frame THROUGH secure-exec (guest runs inside the V8 sidecar) -log "[3/7] running guest through secure-exec V8 sidecar…" -env -u DISPLAY -u WAYLAND_DISPLAY "$HOST_BIN" \ - --capture "$FRAME" --guest "$GUEST_WASM" --sidecar "$SIDECAR_BIN" 2>&1 | sed 's/^/ /' | tee -a "$RESULTS" -[ -f "$FRAME" ] || { emit "FAIL: no frame captured through secure-exec"; exit 1; } -emit "secure-exec capture: $(stat -c%s "$FRAME") bytes" - -# 4. Validate header + golden pixels on the raw framebuffer -log "[4/7] validating header + golden pixels…" -if [ "$BLESS" = "--bless" ]; then - node "$EXP/tests/check.mjs" "$FRAME" "$GOLDEN" --bless - emit "golden: blessed from secure-exec capture" -fi -node "$EXP/tests/check.mjs" "$FRAME" "$GOLDEN" 2>&1 | sed 's/^/ /' | tee -a "$RESULTS" - -# 5. Sanity: exact byte size of a 640x480 RGBA frame + header -log "[5/7] frame size check…" -EXPECT=$((12 + 640*480*4)) -GOT=$(stat -c%s "$FRAME") -[ "$GOT" = "$EXPECT" ] || { emit "FAIL: frame size $GOT != $EXPECT"; exit 1; } -emit "frame size: $GOT bytes == 12 + 640*480*4 (exact)" - -# 6. PNG proof (human artifact only) -log "[6/7] encoding PNG proof…" -tail -c +13 "$FRAME" > "$WORK/raw.rgba" -ffmpeg -y -f rawvideo -pixel_format rgba -video_size 640x480 -i "$WORK/raw.rgba" \ - -frames:v 1 "$ASSETS/frame_secureexec.png" >/dev/null 2>&1 -cp "$FRAME" "$ASSETS/frame_secureexec.bin" -emit "proof PNG: $ASSETS/frame_secureexec.png ($(stat -c%s "$ASSETS/frame_secureexec.png") bytes)" - -# 7. Done -emit "RESULT: PASS (frame rendered by guest INSIDE secure-exec, via the standard Rust client)" -log "[7/7] PASS" diff --git a/experiments/wasm-gui/third_party/libXext/Makefile b/experiments/wasm-gui/third_party/libXext/Makefile deleted file mode 100644 index ec343a48f..000000000 --- a/experiments/wasm-gui/third_party/libXext/Makefile +++ /dev/null @@ -1,956 +0,0 @@ -# Makefile.in generated by automake 1.18.1 from Makefile.am. -# Makefile. Generated from Makefile.in by configure. - -# Copyright (C) 1994-2025 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - - - - -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -am__rm_f = rm -f $(am__rm_f_notfound) -am__rm_rf = rm -rf $(am__rm_f_notfound) -pkgdatadir = $(datadir)/libXext -pkgincludedir = $(includedir)/libXext -pkglibdir = $(libdir)/libXext -pkglibexecdir = $(libexecdir)/libXext -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = x86_64-pc-linux-gnu -host_triplet = wasm32-unknown-wasi -subdir = . -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ax_gcc_builtin.m4 \ - $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ - $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ - $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ - $(am__configure_deps) $(am__DIST_COMMON) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = xext.pc -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_$(V)) -am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_$(V)) -am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_$(V)) -am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ - ctags-recursive dvi-recursive html-recursive info-recursive \ - install-data-recursive install-dvi-recursive \ - install-exec-recursive install-html-recursive \ - install-info-recursive install-pdf-recursive \ - install-ps-recursive install-recursive installcheck-recursive \ - installdirs-recursive pdf-recursive ps-recursive \ - tags-recursive uninstall-recursive -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ - } -am__installdirs = "$(DESTDIR)$(pkgconfigdir)" -DATA = $(pkgconfig_DATA) -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -am__recursive_targets = \ - $(RECURSIVE_TARGETS) \ - $(RECURSIVE_CLEAN_TARGETS) \ - $(am__extra_recursive_targets) -AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - cscope distdir distdir-am dist dist-all distcheck -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ - config.h.in -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -DIST_SUBDIRS = $(SUBDIRS) -am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ - $(srcdir)/xext.pc.in AUTHORS COPYING ChangeLog INSTALL \ - README.md compile config.guess config.sub install-sh ltmain.sh \ - missing -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - if test -d "$(distdir)"; then \ - find "$(distdir)" -type d ! -perm -700 -exec chmod u+rwx {} ';' \ - ; rm -rf "$(distdir)" \ - || { sleep 5 && rm -rf "$(distdir)"; }; \ - else :; fi -am__post_remove_distdir = $(am__remove_distdir) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.xz -GZIP_ENV = -9 -DIST_TARGETS = dist-xz dist-gzip -# Exists only to be overridden by the user if desired. -AM_DISTCHECK_DVI_TARGET = dvi -distuninstallcheck_listfiles = find . -type f -print -am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ - | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' -distcleancheck_listfiles = \ - find . \( -type f -a \! \ - \( -name .nfs* -o -name .smb* -o -name .__afs* \) \) -print -ACLOCAL = ${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' aclocal-1.18 -ADMIN_MAN_DIR = $(mandir)/man$(ADMIN_MAN_SUFFIX) -ADMIN_MAN_SUFFIX = 8 -AMTAR = $${TAR-tar} -AM_DEFAULT_VERBOSITY = 0 -APP_MAN_DIR = $(mandir)/man$(APP_MAN_SUFFIX) -APP_MAN_SUFFIX = 1 -AR = /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar -AUTOCONF = ${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' autoconf -AUTOHEADER = ${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' autoheader -AUTOMAKE = ${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' automake-1.18 -AWK = mawk -BASE_CFLAGS = -Wall -Wpointer-arith -Wmissing-declarations -Wformat=2 -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wbad-function-cast -Wold-style-definition -Wunused -Wuninitialized -Wshadow -Wmissing-noreturn -Wmissing-format-attribute -Wredundant-decls -Werror=implicit -Werror=nonnull -Werror=init-self -Werror=main -Werror=missing-braces -Werror=sequence-point -Werror=return-type -Werror=trigraphs -Werror=array-bounds -Werror=write-strings -Werror=address -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast -CC = /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -CCDEPMODE = depmode=gcc3 -CFLAGS = --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -CHANGELOG_CMD = ((GIT_DIR=$(top_srcdir)/.git git log > $(top_srcdir)/.changelog.tmp) 2>/dev/null && mv $(top_srcdir)/.changelog.tmp $(top_srcdir)/ChangeLog) || (rm -f $(top_srcdir)/.changelog.tmp; test -e $(top_srcdir)/ChangeLog || ( touch $(top_srcdir)/ChangeLog; echo 'git failed to create ChangeLog: installing empty ChangeLog.' >&2)) -CPPFLAGS = --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -CSCOPE = cscope -CTAGS = ctags -CWARNFLAGS = -Wall -Wpointer-arith -Wmissing-declarations -Wformat=2 -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wbad-function-cast -Wold-style-definition -Wunused -Wuninitialized -Wshadow -Wmissing-noreturn -Wmissing-format-attribute -Wredundant-decls -Werror=implicit -Werror=nonnull -Werror=init-self -Werror=main -Werror=missing-braces -Werror=sequence-point -Werror=return-type -Werror=trigraphs -Werror=array-bounds -Werror=write-strings -Werror=address -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast -fno-strict-aliasing -CYGPATH_W = echo -DEFS = -DHAVE_CONFIG_H -DEPDIR = .deps -DLLTOOL = dlltool -DRIVER_MAN_DIR = $(mandir)/man$(DRIVER_MAN_SUFFIX) -DRIVER_MAN_SUFFIX = 4 -DSYMUTIL = -DUMPBIN = : -ECHO_C = -ECHO_N = -n -ECHO_T = -EGREP = /usr/bin/grep -E -ETAGS = etags -EXEEXT = -FGREP = /usr/bin/grep -F -FILECMD = file -FILE_MAN_DIR = $(mandir)/man$(FILE_MAN_SUFFIX) -FILE_MAN_SUFFIX = 5 -FOP = -GREP = /usr/bin/grep -INSTALL = /usr/bin/install -c -INSTALL_CMD = (cp -f /home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/util-macros/INSTALL $(top_srcdir)/.INSTALL.tmp && mv $(top_srcdir)/.INSTALL.tmp $(top_srcdir)/INSTALL) || (rm -f $(top_srcdir)/.INSTALL.tmp; test -e $(top_srcdir)/INSTALL || ( touch $(top_srcdir)/INSTALL; echo 'failed to copy INSTALL from util-macros: installing empty INSTALL.' >&2)) -INSTALL_DATA = ${INSTALL} -m 644 -INSTALL_PROGRAM = ${INSTALL} -INSTALL_SCRIPT = ${INSTALL} -INSTALL_STRIP_PROGRAM = $(install_sh) -c -s -LD = /home/linuxbrew/.linuxbrew/bin/ld -LDFLAGS = --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman -LIBOBJS = -LIBS = -LIBTOOL = $(SHELL) $(top_builddir)/libtool -LIB_MAN_DIR = $(mandir)/man$(LIB_MAN_SUFFIX) -LIB_MAN_SUFFIX = 3 -LINT = -LINTLIB = -LINT_FLAGS = -LIPO = -LN_S = ln -s -LTLIBOBJS = -LT_SYS_LIBRARY_PATH = -MAKEINFO = ${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' makeinfo -MALLOC_ZERO_CFLAGS = -DMALLOC_0_RETURNS_NULL -MANIFEST_TOOL = : -MAN_SUBSTS = -e 's|__vendorversion__|"$(PACKAGE_STRING)" "$(XORG_MAN_PAGE)"|' -e 's|__xorgversion__|"$(PACKAGE_STRING)" "$(XORG_MAN_PAGE)"|' -e 's|__xservername__|Xorg|g' -e 's|__xconfigfile__|xorg.conf|g' -e 's|__projectroot__|$(prefix)|g' -e 's|__apploaddir__|$(appdefaultdir)|g' -e 's|__appmansuffix__|$(APP_MAN_SUFFIX)|g' -e 's|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g' -e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' -e 's|__libmansuffix__|$(LIB_MAN_SUFFIX)|g' -e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' -e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g' -MISC_MAN_DIR = $(mandir)/man$(MISC_MAN_SUFFIX) -MISC_MAN_SUFFIX = 7 -MKDIR_P = /usr/bin/mkdir -p -NM = nm -NMEDIT = -OBJDUMP = objdump -OBJEXT = o -OTOOL = -OTOOL64 = -PACKAGE = libXext -PACKAGE_BUGREPORT = https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues -PACKAGE_NAME = libXext -PACKAGE_STRING = libXext 1.3.7 -PACKAGE_TARNAME = libXext -PACKAGE_URL = -PACKAGE_VERSION = 1.3.7 -PATH_SEPARATOR = : -PKG_CONFIG = /usr/bin/pkg-config -PKG_CONFIG_LIBDIR = /home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib/pkgconfig:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/pkgconfig -PKG_CONFIG_PATH = -RANLIB = /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ranlib -SED = /usr/bin/sed -SET_MAKE = -SHELL = /bin/bash -STRICT_CFLAGS = -pedantic -Werror -Werror=attributes -STRIP = strip -STYLESHEET_SRCDIR = -VERSION = 1.3.7 -XEXT_CFLAGS = -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -XEXT_LIBS = -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -lX11 -XEXT_SOREV = 6:4:0 -XMALLOC_ZERO_CFLAGS = -DMALLOC_0_RETURNS_NULL -XMLTO = -XORG_MAN_PAGE = X Version 11 -XORG_SGML_PATH = -XSLTPROC = /home/linuxbrew/.linuxbrew/bin/xsltproc -XSL_STYLESHEET = -XTMALLOC_ZERO_CFLAGS = -DMALLOC_0_RETURNS_NULL -DXTMALLOC_BC -abs_builddir = /home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext -abs_srcdir = /home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext -abs_top_builddir = /home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext -abs_top_srcdir = /home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext -ac_ct_AR = -ac_ct_CC = -ac_ct_DUMPBIN = link -dump -am__include = include -am__leading_dot = . -am__quote = -am__rm_f_notfound = -am__tar = tar --format=ustar -chf - "$$tardir" -am__untar = tar -xf - -am__xargs_n = xargs -n -bindir = ${exec_prefix}/bin -build = x86_64-pc-linux-gnu -build_alias = -build_cpu = x86_64 -build_os = linux-gnu -build_vendor = pc -builddir = . -datadir = ${datarootdir} -datarootdir = ${prefix}/share -docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} -dvidir = ${docdir} -exec_prefix = ${prefix} -host = wasm32-unknown-wasi -host_alias = wasm32-wasi -host_cpu = wasm32 -host_os = wasi -host_vendor = unknown -htmldir = ${docdir} -includedir = ${prefix}/include -infodir = ${datarootdir}/info -install_sh = ${SHELL} /home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/install-sh -libdir = ${exec_prefix}/lib -libexecdir = ${exec_prefix}/libexec -localedir = ${datarootdir}/locale -localstatedir = ${prefix}/var -mandir = ${datarootdir}/man -mkdir_p = $(MKDIR_P) -oldincludedir = /usr/include -pdfdir = ${docdir} -prefix = /home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix -program_transform_name = s,x,x, -psdir = ${docdir} -runstatedir = ${localstatedir}/run -sbindir = ${exec_prefix}/sbin -sharedstatedir = ${prefix}/com -srcdir = . -sysconfdir = ${prefix}/etc -target_alias = -top_build_prefix = -top_builddir = . -top_srcdir = . -SUBDIRS = man src specs -ACLOCAL_AMFLAGS = -I m4 -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = xext.pc -MAINTAINERCLEANFILES = ChangeLog INSTALL -EXTRA_DIST = README.md -all: config.h - $(MAKE) $(AM_MAKEFLAGS) all-recursive - -.SUFFIXES: -am--refresh: Makefile - @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -config.h: stamp-h1 - @test -f $@ || rm -f stamp-h1 - @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 - -stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status - $(AM_V_at)rm -f stamp-h1 - $(AM_V_GEN)cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: $(am__configure_deps) - $(AM_V_GEN)($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - $(AM_V_at)rm -f stamp-h1 - $(AM_V_at)touch $@ - -distclean-hdr: - -rm -f config.h stamp-h1 -xext.pc: $(top_builddir)/config.status $(srcdir)/xext.pc.in - cd $(top_builddir) && $(SHELL) ./config.status $@ - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -distclean-libtool: - -rm -f libtool config.lt -install-pkgconfigDATA: $(pkgconfig_DATA) - @$(NORMAL_INSTALL) - @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ - done - -uninstall-pkgconfigDATA: - @$(NORMAL_UNINSTALL) - @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) - -# This directory's subdirectories are mostly independent; you can cd -# into them and run 'make' without going through this Makefile. -# To change the values of 'make' variables: instead of editing Makefiles, -# (1) if the variable is set in 'config.status', edit 'config.status' -# (which will cause the Makefiles to be regenerated when you run 'make'); -# (2) otherwise, pass the desired values on the 'make' command line. -$(am__recursive_targets): - @fail=; \ - if $(am__make_keepgoing); then \ - failcom='fail=yes'; \ - else \ - failcom='exit 1'; \ - fi; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-recursive -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-recursive - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscope: cscope.files - test ! -s cscope.files \ - || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) -clean-cscope: - -rm -f cscope.files -cscope.files: clean-cscope cscopelist -cscopelist: cscopelist-recursive - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -rm -f cscope.out cscope.in.out cscope.po.out cscope.files - -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - $(am__remove_distdir) - $(AM_V_at)$(MKDIR_P) "$(distdir)" - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - $(am__make_dryrun) \ - || test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$(top_distdir)" distdir="$(distdir)" \ - dist-hook - -test -n "$(am__skip_mode_fix)" \ - || find "$(distdir)" -type d ! -perm -755 \ - -exec chmod u+rwx,go+rx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r "$(distdir)" -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz - $(am__post_remove_distdir) - -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 - $(am__post_remove_distdir) - -dist-bzip3: distdir - tardir=$(distdir) && $(am__tar) | bzip3 -c >$(distdir).tar.bz3 - $(am__post_remove_distdir) - -dist-lzip: distdir - tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz - $(am__post_remove_distdir) -dist-xz: distdir - tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz - $(am__post_remove_distdir) - -dist-zstd: distdir - tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst - $(am__post_remove_distdir) - -dist-tarZ: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__post_remove_distdir) - -dist-shar: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz - $(am__post_remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__post_remove_distdir) - -dist dist-all: - $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' - $(am__post_remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - eval GZIP= gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.bz3*) \ - bzip3 -dc $(distdir).tar.bz3 | $(am__untar) ;;\ - *.tar.lz*) \ - lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ - *.tar.xz*) \ - xz -dc $(distdir).tar.xz | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - eval GZIP= gzip -dc $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - *.tar.zst*) \ - zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ - esac - chmod -R a-w $(distdir) - chmod u+w $(distdir) - mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst - chmod a-w $(distdir) - test -d $(distdir)/_build || exit 0; \ - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build/sub \ - && ../../configure \ - $(AM_DISTCHECK_CONFIGURE_FLAGS) \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - --srcdir=../.. --prefix="$$dc_install_base" \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ - && cd "$$am__cwd" \ - || exit 1 - $(am__post_remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @test -n '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: trying to run $@ with an empty' \ - '$$(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - $(am__cd) '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am -check: check-recursive -all-am: Makefile $(DATA) config.h -installdirs: installdirs-recursive -installdirs-am: - for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -$(am__rm_f) $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -$(am__rm_f) $(MAINTAINERCLEANFILES) -clean: clean-recursive - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-hdr \ - distclean-libtool distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: install-pkgconfigDATA - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: uninstall-pkgconfigDATA - -.MAKE: $(am__recursive_targets) all install-am install-strip - -.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ - am--refresh check check-am clean clean-cscope clean-generic \ - clean-libtool cscope cscopelist-am ctags ctags-am dist \ - dist-all dist-bzip2 dist-bzip3 dist-gzip dist-hook dist-lzip \ - dist-shar dist-tarZ dist-xz dist-zip dist-zstd distcheck \ - distclean distclean-generic distclean-hdr distclean-libtool \ - distclean-tags distcleancheck distdir distuninstallcheck dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-pkgconfigDATA install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ - ps ps-am tags tags-am uninstall uninstall-am \ - uninstall-pkgconfigDATA - -.PRECIOUS: Makefile - - -.PHONY: ChangeLog INSTALL - -INSTALL: - $(INSTALL_CMD) - -ChangeLog: - $(CHANGELOG_CMD) - -dist-hook: ChangeLog INSTALL - -# Check source code with tools like lint & sparse -#lint: -# (cd src && $(MAKE) $(MFLAGS) lint) - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: - -# Tell GNU make to disable its built-in pattern rules. -%:: %,v -%:: RCS/%,v -%:: RCS/% -%:: s.% -%:: SCCS/s.% diff --git a/experiments/wasm-gui/third_party/libXext/Makefile.in b/experiments/wasm-gui/third_party/libXext/Makefile.in deleted file mode 100644 index b07c1f69c..000000000 --- a/experiments/wasm-gui/third_party/libXext/Makefile.in +++ /dev/null @@ -1,956 +0,0 @@ -# Makefile.in generated by automake 1.18.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2025 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -am__rm_f = rm -f $(am__rm_f_notfound) -am__rm_rf = rm -rf $(am__rm_f_notfound) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = . -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ax_gcc_builtin.m4 \ - $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ - $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ - $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ - $(am__configure_deps) $(am__DIST_COMMON) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = xext.pc -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ - ctags-recursive dvi-recursive html-recursive info-recursive \ - install-data-recursive install-dvi-recursive \ - install-exec-recursive install-html-recursive \ - install-info-recursive install-pdf-recursive \ - install-ps-recursive install-recursive installcheck-recursive \ - installdirs-recursive pdf-recursive ps-recursive \ - tags-recursive uninstall-recursive -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ - } -am__installdirs = "$(DESTDIR)$(pkgconfigdir)" -DATA = $(pkgconfig_DATA) -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -am__recursive_targets = \ - $(RECURSIVE_TARGETS) \ - $(RECURSIVE_CLEAN_TARGETS) \ - $(am__extra_recursive_targets) -AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - cscope distdir distdir-am dist dist-all distcheck -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ - config.h.in -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -DIST_SUBDIRS = $(SUBDIRS) -am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ - $(srcdir)/xext.pc.in AUTHORS COPYING ChangeLog INSTALL \ - README.md compile config.guess config.sub install-sh ltmain.sh \ - missing -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - if test -d "$(distdir)"; then \ - find "$(distdir)" -type d ! -perm -700 -exec chmod u+rwx {} ';' \ - ; rm -rf "$(distdir)" \ - || { sleep 5 && rm -rf "$(distdir)"; }; \ - else :; fi -am__post_remove_distdir = $(am__remove_distdir) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.xz -GZIP_ENV = -9 -DIST_TARGETS = dist-xz dist-gzip -# Exists only to be overridden by the user if desired. -AM_DISTCHECK_DVI_TARGET = dvi -distuninstallcheck_listfiles = find . -type f -print -am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ - | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' -distcleancheck_listfiles = \ - find . \( -type f -a \! \ - \( -name .nfs* -o -name .smb* -o -name .__afs* \) \) -print -ACLOCAL = @ACLOCAL@ -ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ -ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -APP_MAN_DIR = @APP_MAN_DIR@ -APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BASE_CFLAGS = @BASE_CFLAGS@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CHANGELOG_CMD = @CHANGELOG_CMD@ -CPPFLAGS = @CPPFLAGS@ -CSCOPE = @CSCOPE@ -CTAGS = @CTAGS@ -CWARNFLAGS = @CWARNFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ -DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ETAGS = @ETAGS@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -FILECMD = @FILECMD@ -FILE_MAN_DIR = @FILE_MAN_DIR@ -FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ -FOP = @FOP@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_CMD = @INSTALL_CMD@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIB_MAN_DIR = @LIB_MAN_DIR@ -LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ -LINT = @LINT@ -LINTLIB = @LINTLIB@ -LINT_FLAGS = @LINT_FLAGS@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -MAKEINFO = @MAKEINFO@ -MALLOC_ZERO_CFLAGS = @MALLOC_ZERO_CFLAGS@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MAN_SUBSTS = @MAN_SUBSTS@ -MISC_MAN_DIR = @MISC_MAN_DIR@ -MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -RANLIB = @RANLIB@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRICT_CFLAGS = @STRICT_CFLAGS@ -STRIP = @STRIP@ -STYLESHEET_SRCDIR = @STYLESHEET_SRCDIR@ -VERSION = @VERSION@ -XEXT_CFLAGS = @XEXT_CFLAGS@ -XEXT_LIBS = @XEXT_LIBS@ -XEXT_SOREV = @XEXT_SOREV@ -XMALLOC_ZERO_CFLAGS = @XMALLOC_ZERO_CFLAGS@ -XMLTO = @XMLTO@ -XORG_MAN_PAGE = @XORG_MAN_PAGE@ -XORG_SGML_PATH = @XORG_SGML_PATH@ -XSLTPROC = @XSLTPROC@ -XSL_STYLESHEET = @XSL_STYLESHEET@ -XTMALLOC_ZERO_CFLAGS = @XTMALLOC_ZERO_CFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__rm_f_notfound = @am__rm_f_notfound@ -am__tar = @am__tar@ -am__untar = @am__untar@ -am__xargs_n = @am__xargs_n@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -SUBDIRS = man src specs -ACLOCAL_AMFLAGS = -I m4 -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = xext.pc -MAINTAINERCLEANFILES = ChangeLog INSTALL -EXTRA_DIST = README.md -all: config.h - $(MAKE) $(AM_MAKEFLAGS) all-recursive - -.SUFFIXES: -am--refresh: Makefile - @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -config.h: stamp-h1 - @test -f $@ || rm -f stamp-h1 - @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 - -stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status - $(AM_V_at)rm -f stamp-h1 - $(AM_V_GEN)cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: $(am__configure_deps) - $(AM_V_GEN)($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - $(AM_V_at)rm -f stamp-h1 - $(AM_V_at)touch $@ - -distclean-hdr: - -rm -f config.h stamp-h1 -xext.pc: $(top_builddir)/config.status $(srcdir)/xext.pc.in - cd $(top_builddir) && $(SHELL) ./config.status $@ - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -distclean-libtool: - -rm -f libtool config.lt -install-pkgconfigDATA: $(pkgconfig_DATA) - @$(NORMAL_INSTALL) - @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ - done - -uninstall-pkgconfigDATA: - @$(NORMAL_UNINSTALL) - @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) - -# This directory's subdirectories are mostly independent; you can cd -# into them and run 'make' without going through this Makefile. -# To change the values of 'make' variables: instead of editing Makefiles, -# (1) if the variable is set in 'config.status', edit 'config.status' -# (which will cause the Makefiles to be regenerated when you run 'make'); -# (2) otherwise, pass the desired values on the 'make' command line. -$(am__recursive_targets): - @fail=; \ - if $(am__make_keepgoing); then \ - failcom='fail=yes'; \ - else \ - failcom='exit 1'; \ - fi; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-recursive -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-recursive - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscope: cscope.files - test ! -s cscope.files \ - || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) -clean-cscope: - -rm -f cscope.files -cscope.files: clean-cscope cscopelist -cscopelist: cscopelist-recursive - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -rm -f cscope.out cscope.in.out cscope.po.out cscope.files - -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - $(am__remove_distdir) - $(AM_V_at)$(MKDIR_P) "$(distdir)" - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - $(am__make_dryrun) \ - || test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$(top_distdir)" distdir="$(distdir)" \ - dist-hook - -test -n "$(am__skip_mode_fix)" \ - || find "$(distdir)" -type d ! -perm -755 \ - -exec chmod u+rwx,go+rx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r "$(distdir)" -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz - $(am__post_remove_distdir) - -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 - $(am__post_remove_distdir) - -dist-bzip3: distdir - tardir=$(distdir) && $(am__tar) | bzip3 -c >$(distdir).tar.bz3 - $(am__post_remove_distdir) - -dist-lzip: distdir - tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz - $(am__post_remove_distdir) -dist-xz: distdir - tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz - $(am__post_remove_distdir) - -dist-zstd: distdir - tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst - $(am__post_remove_distdir) - -dist-tarZ: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__post_remove_distdir) - -dist-shar: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz - $(am__post_remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__post_remove_distdir) - -dist dist-all: - $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' - $(am__post_remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - eval GZIP= gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.bz3*) \ - bzip3 -dc $(distdir).tar.bz3 | $(am__untar) ;;\ - *.tar.lz*) \ - lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ - *.tar.xz*) \ - xz -dc $(distdir).tar.xz | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - eval GZIP= gzip -dc $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - *.tar.zst*) \ - zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ - esac - chmod -R a-w $(distdir) - chmod u+w $(distdir) - mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst - chmod a-w $(distdir) - test -d $(distdir)/_build || exit 0; \ - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build/sub \ - && ../../configure \ - $(AM_DISTCHECK_CONFIGURE_FLAGS) \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - --srcdir=../.. --prefix="$$dc_install_base" \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ - && cd "$$am__cwd" \ - || exit 1 - $(am__post_remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @test -n '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: trying to run $@ with an empty' \ - '$$(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - $(am__cd) '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am -check: check-recursive -all-am: Makefile $(DATA) config.h -installdirs: installdirs-recursive -installdirs-am: - for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -$(am__rm_f) $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -$(am__rm_f) $(MAINTAINERCLEANFILES) -clean: clean-recursive - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-hdr \ - distclean-libtool distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: install-pkgconfigDATA - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: uninstall-pkgconfigDATA - -.MAKE: $(am__recursive_targets) all install-am install-strip - -.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ - am--refresh check check-am clean clean-cscope clean-generic \ - clean-libtool cscope cscopelist-am ctags ctags-am dist \ - dist-all dist-bzip2 dist-bzip3 dist-gzip dist-hook dist-lzip \ - dist-shar dist-tarZ dist-xz dist-zip dist-zstd distcheck \ - distclean distclean-generic distclean-hdr distclean-libtool \ - distclean-tags distcleancheck distdir distuninstallcheck dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-pkgconfigDATA install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ - ps ps-am tags tags-am uninstall uninstall-am \ - uninstall-pkgconfigDATA - -.PRECIOUS: Makefile - - -.PHONY: ChangeLog INSTALL - -INSTALL: - $(INSTALL_CMD) - -ChangeLog: - $(CHANGELOG_CMD) - -dist-hook: ChangeLog INSTALL - -# Check source code with tools like lint & sparse -@LINT_TRUE@lint: -@LINT_TRUE@ (cd src && $(MAKE) $(MFLAGS) lint) - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: - -# Tell GNU make to disable its built-in pattern rules. -%:: %,v -%:: RCS/%,v -%:: RCS/% -%:: s.% -%:: SCCS/s.% diff --git a/experiments/wasm-gui/third_party/libXext/aclocal.m4 b/experiments/wasm-gui/third_party/libXext/aclocal.m4 deleted file mode 100644 index 1e4c772ad..000000000 --- a/experiments/wasm-gui/third_party/libXext/aclocal.m4 +++ /dev/null @@ -1,3595 +0,0 @@ -# generated automatically by aclocal 1.18.1 -*- Autoconf -*- - -# Copyright (C) 1996-2025 Free Software Foundation, Inc. - -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.73],, -[m4_warning([this file was generated for autoconf 2.73. -You have another version of autoconf. It may work, but is not guaranteed to. -If you have problems, you may need to regenerate the build system entirely. -To do so, use the procedure documented by the package, typically 'autoreconf'.])]) - -# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- -# serial 12 (pkg-config-0.29.2) - -dnl Copyright © 2004 Scott James Remnant . -dnl Copyright © 2012-2015 Dan Nicholson -dnl -dnl This program is free software; you can redistribute it and/or modify -dnl it under the terms of the GNU General Public License as published by -dnl the Free Software Foundation; either version 2 of the License, or -dnl (at your option) any later version. -dnl -dnl This program is distributed in the hope that it will be useful, but -dnl WITHOUT ANY WARRANTY; without even the implied warranty of -dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -dnl General Public License for more details. -dnl -dnl You should have received a copy of the GNU General Public License -dnl along with this program; if not, write to the Free Software -dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -dnl 02111-1307, USA. -dnl -dnl As a special exception to the GNU General Public License, if you -dnl distribute this file as part of a program that contains a -dnl configuration script generated by Autoconf, you may include it under -dnl the same distribution terms that you use for the rest of that -dnl program. - -dnl PKG_PREREQ(MIN-VERSION) -dnl ----------------------- -dnl Since: 0.29 -dnl -dnl Verify that the version of the pkg-config macros are at least -dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's -dnl installed version of pkg-config, this checks the developer's version -dnl of pkg.m4 when generating configure. -dnl -dnl To ensure that this macro is defined, also add: -dnl m4_ifndef([PKG_PREREQ], -dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) -dnl -dnl See the "Since" comment for each macro you use to see what version -dnl of the macros you require. -m4_defun([PKG_PREREQ], -[m4_define([PKG_MACROS_VERSION], [0.29.2]) -m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, - [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) -])dnl PKG_PREREQ - -dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) -dnl ---------------------------------- -dnl Since: 0.16 -dnl -dnl Search for the pkg-config tool and set the PKG_CONFIG variable to -dnl first found in the path. Checks that the version of pkg-config found -dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is -dnl used since that's the first version where most current features of -dnl pkg-config existed. -AC_DEFUN([PKG_PROG_PKG_CONFIG], -[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) -m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) -AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) -AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) -AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=m4_default([$1], [0.9.0]) - AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - PKG_CONFIG="" - fi -fi[]dnl -])dnl PKG_PROG_PKG_CONFIG - -dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ------------------------------------------------------------------- -dnl Since: 0.18 -dnl -dnl Check to see whether a particular set of modules exists. Similar to -dnl PKG_CHECK_MODULES(), but does not set variables or print errors. -dnl -dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -dnl only at the first occurrence in configure.ac, so if the first place -dnl it's called might be skipped (such as if it is within an "if", you -dnl have to call PKG_CHECK_EXISTS manually -AC_DEFUN([PKG_CHECK_EXISTS], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -if test -n "$PKG_CONFIG" && \ - AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then - m4_default([$2], [:]) -m4_ifvaln([$3], [else - $3])dnl -fi]) - -dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) -dnl --------------------------------------------- -dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting -dnl pkg_failed based on the result. -m4_define([_PKG_CONFIG], -[if test -n "$$1"; then - pkg_cv_[]$1="$$1" - elif test -n "$PKG_CONFIG"; then - PKG_CHECK_EXISTS([$3], - [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes ], - [pkg_failed=yes]) - else - pkg_failed=untried -fi[]dnl -])dnl _PKG_CONFIG - -dnl _PKG_SHORT_ERRORS_SUPPORTED -dnl --------------------------- -dnl Internal check to see if pkg-config supports short errors. -AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi[]dnl -])dnl _PKG_SHORT_ERRORS_SUPPORTED - - -dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], -dnl [ACTION-IF-NOT-FOUND]) -dnl -------------------------------------------------------------- -dnl Since: 0.4.0 -dnl -dnl Note that if there is a possibility the first call to -dnl PKG_CHECK_MODULES might not happen, you should be sure to include an -dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac -AC_DEFUN([PKG_CHECK_MODULES], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl -AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl - -pkg_failed=no -AC_MSG_CHECKING([for $2]) - -_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) -_PKG_CONFIG([$1][_LIBS], [libs], [$2]) - -m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS -and $1[]_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details.]) - -if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) - _PKG_SHORT_ERRORS_SUPPORTED - if test $_pkg_short_errors_supported = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else - $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD - - m4_default([$4], [AC_MSG_ERROR( -[Package requirements ($2) were not met: - -$$1_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -_PKG_TEXT])[]dnl - ]) -elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) - m4_default([$4], [AC_MSG_FAILURE( -[The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -_PKG_TEXT - -To get pkg-config, see .])[]dnl - ]) -else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS - AC_MSG_RESULT([yes]) - $3 -fi[]dnl -])dnl PKG_CHECK_MODULES - - -dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], -dnl [ACTION-IF-NOT-FOUND]) -dnl --------------------------------------------------------------------- -dnl Since: 0.29 -dnl -dnl Checks for existence of MODULES and gathers its build flags with -dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags -dnl and VARIABLE-PREFIX_LIBS from --libs. -dnl -dnl Note that if there is a possibility the first call to -dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to -dnl include an explicit call to PKG_PROG_PKG_CONFIG in your -dnl configure.ac. -AC_DEFUN([PKG_CHECK_MODULES_STATIC], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -_save_PKG_CONFIG=$PKG_CONFIG -PKG_CONFIG="$PKG_CONFIG --static" -PKG_CHECK_MODULES($@) -PKG_CONFIG=$_save_PKG_CONFIG[]dnl -])dnl PKG_CHECK_MODULES_STATIC - - -dnl PKG_INSTALLDIR([DIRECTORY]) -dnl ------------------------- -dnl Since: 0.27 -dnl -dnl Substitutes the variable pkgconfigdir as the location where a module -dnl should install pkg-config .pc files. By default the directory is -dnl $libdir/pkgconfig, but the default can be changed by passing -dnl DIRECTORY. The user can override through the --with-pkgconfigdir -dnl parameter. -AC_DEFUN([PKG_INSTALLDIR], -[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([pkgconfigdir], - [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, - [with_pkgconfigdir=]pkg_default) -AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -])dnl PKG_INSTALLDIR - - -dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) -dnl -------------------------------- -dnl Since: 0.27 -dnl -dnl Substitutes the variable noarch_pkgconfigdir as the location where a -dnl module should install arch-independent pkg-config .pc files. By -dnl default the directory is $datadir/pkgconfig, but the default can be -dnl changed by passing DIRECTORY. The user can override through the -dnl --with-noarch-pkgconfigdir parameter. -AC_DEFUN([PKG_NOARCH_INSTALLDIR], -[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([noarch-pkgconfigdir], - [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, - [with_noarch_pkgconfigdir=]pkg_default) -AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -])dnl PKG_NOARCH_INSTALLDIR - - -dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, -dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ------------------------------------------- -dnl Since: 0.28 -dnl -dnl Retrieves the value of the pkg-config variable for the given module. -AC_DEFUN([PKG_CHECK_VAR], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl - -_PKG_CONFIG([$1], [variable="][$3]["], [$2]) -AS_VAR_COPY([$1], [pkg_cv_][$1]) - -AS_VAR_IF([$1], [""], [$5], [$4])dnl -])dnl PKG_CHECK_VAR - -dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, -dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], -dnl [DESCRIPTION], [DEFAULT]) -dnl ------------------------------------------ -dnl -dnl Prepare a "--with-" configure option using the lowercase -dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and -dnl PKG_CHECK_MODULES in a single macro. -AC_DEFUN([PKG_WITH_MODULES], -[ -m4_pushdef([with_arg], m4_tolower([$1])) - -m4_pushdef([description], - [m4_default([$5], [build with ]with_arg[ support])]) - -m4_pushdef([def_arg], [m4_default([$6], [auto])]) -m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) -m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) - -m4_case(def_arg, - [yes],[m4_pushdef([with_without], [--without-]with_arg)], - [m4_pushdef([with_without],[--with-]with_arg)]) - -AC_ARG_WITH(with_arg, - AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, - [AS_TR_SH([with_]with_arg)=def_arg]) - -AS_CASE([$AS_TR_SH([with_]with_arg)], - [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], - [auto],[PKG_CHECK_MODULES([$1],[$2], - [m4_n([def_action_if_found]) $3], - [m4_n([def_action_if_not_found]) $4])]) - -m4_popdef([with_arg]) -m4_popdef([description]) -m4_popdef([def_arg]) - -])dnl PKG_WITH_MODULES - -dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, -dnl [DESCRIPTION], [DEFAULT]) -dnl ----------------------------------------------- -dnl -dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES -dnl check._[VARIABLE-PREFIX] is exported as make variable. -AC_DEFUN([PKG_HAVE_WITH_MODULES], -[ -PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) - -AM_CONDITIONAL([HAVE_][$1], - [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) -])dnl PKG_HAVE_WITH_MODULES - -dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, -dnl [DESCRIPTION], [DEFAULT]) -dnl ------------------------------------------------------ -dnl -dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after -dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make -dnl and preprocessor variable. -AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], -[ -PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) - -AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], - [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) -])dnl PKG_HAVE_DEFINE_WITH_MODULES - -dnl xorg-macros.m4. Generated from xorg-macros.m4.in xorgversion.m4 by configure. -dnl -dnl Copyright (c) 2005, 2023, Oracle and/or its affiliates. -dnl -dnl Permission is hereby granted, free of charge, to any person obtaining a -dnl copy of this software and associated documentation files (the "Software"), -dnl to deal in the Software without restriction, including without limitation -dnl the rights to use, copy, modify, merge, publish, distribute, sublicense, -dnl and/or sell copies of the Software, and to permit persons to whom the -dnl Software is furnished to do so, subject to the following conditions: -dnl -dnl The above copyright notice and this permission notice (including the next -dnl paragraph) shall be included in all copies or substantial portions of the -dnl Software. -dnl -dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -dnl IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -dnl FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -dnl THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -dnl LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -dnl FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -dnl DEALINGS IN THE SOFTWARE. - -# XORG_MACROS_VERSION(required-version) -# ------------------------------------- -# Minimum version: 1.1.0 -# -# If you're using a macro added in Version 1.1 or newer, include this in -# your configure.ac with the minimum required version, such as: -# XORG_MACROS_VERSION(1.1) -# -# To ensure that this macro is defined, also add: -# m4_ifndef([XORG_MACROS_VERSION], -# [m4_fatal([must install xorg-macros 1.1 or later before running autoconf/autogen])]) -# -# -# See the "minimum version" comment for each macro you use to see what -# version you require. -m4_defun([XORG_MACROS_VERSION],[ -m4_define([vers_have], [1.20.2]) -m4_define([maj_have], m4_substr(vers_have, 0, m4_index(vers_have, [.]))) -m4_define([maj_needed], m4_substr([$1], 0, m4_index([$1], [.]))) -m4_if(m4_cmp(maj_have, maj_needed), 0,, - [m4_fatal([xorg-macros major version ]maj_needed[ is required but ]vers_have[ found])]) -m4_if(m4_version_compare(vers_have, [$1]), -1, - [m4_fatal([xorg-macros version $1 or higher is required but ]vers_have[ found])]) -m4_undefine([vers_have]) -m4_undefine([maj_have]) -m4_undefine([maj_needed]) -]) # XORG_MACROS_VERSION - -# XORG_PROG_RAWCPP() -# ------------------ -# Minimum version: 1.0.0 -# -# Find cpp program and necessary flags for use in pre-processing text files -# such as man pages and config files -AC_DEFUN([XORG_PROG_RAWCPP],[ -AC_REQUIRE([AC_PROG_CPP]) -AC_PATH_TOOL(RAWCPP, [cpp], [${CPP}], - [$PATH:/bin:/usr/bin:/usr/lib:/usr/libexec:/usr/ccs/lib:/usr/ccs/lbin:/lib]) - -# Check for flag to avoid builtin definitions - assumes unix is predefined, -# which is not the best choice for supporting other OS'es, but covers most -# of the ones we need for now. -AC_MSG_CHECKING([if $RAWCPP requires -undef]) -AC_LANG_CONFTEST([AC_LANG_SOURCE([[Does cpp redefine unix ?]])]) -if test `${RAWCPP} < conftest.$ac_ext | grep -c 'unix'` -eq 1 ; then - AC_MSG_RESULT([no]) -else - if test `${RAWCPP} -undef < conftest.$ac_ext | grep -c 'unix'` -eq 1 ; then - RAWCPPFLAGS=-undef - AC_MSG_RESULT([yes]) - # under Cygwin unix is still defined even with -undef - elif test `${RAWCPP} -undef -ansi < conftest.$ac_ext | grep -c 'unix'` -eq 1 ; then - RAWCPPFLAGS="-undef -ansi" - AC_MSG_RESULT([yes, with -ansi]) - else - AC_MSG_ERROR([${RAWCPP} defines unix with or without -undef. I don't know what to do.]) - fi -fi -rm -f conftest.$ac_ext - -AC_MSG_CHECKING([if $RAWCPP requires -traditional]) -AC_LANG_CONFTEST([AC_LANG_SOURCE([[Does cpp preserve "whitespace"?]])]) -if test `${RAWCPP} < conftest.$ac_ext | grep -c 'preserve "'` -eq 1 ; then - AC_MSG_RESULT([no]) -else - if test `${RAWCPP} -traditional < conftest.$ac_ext | grep -c 'preserve "'` -eq 1 ; then - TRADITIONALCPPFLAGS="-traditional" - RAWCPPFLAGS="${RAWCPPFLAGS} -traditional" - AC_MSG_RESULT([yes]) - else - AC_MSG_ERROR([${RAWCPP} does not preserve whitespace with or without -traditional. I don't know what to do.]) - fi -fi -rm -f conftest.$ac_ext -AC_SUBST(RAWCPPFLAGS) -AC_SUBST(TRADITIONALCPPFLAGS) -]) # XORG_PROG_RAWCPP - -# XORG_MANPAGE_SECTIONS() -# ----------------------- -# Minimum version: 1.0.0 -# -# Determine which sections man pages go in for the different man page types -# on this OS - replaces *ManSuffix settings in old Imake *.cf per-os files. -# Not sure if there's any better way than just hardcoding by OS name. -# Override default settings by setting environment variables -# Added MAN_SUBSTS in version 1.8 -# Added AC_PROG_SED in version 1.8 - -AC_DEFUN([XORG_MANPAGE_SECTIONS],[ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_REQUIRE([AC_PROG_SED]) - -case $host_os in - solaris*) - # Solaris 2.0 - 11.3 use SysV man page section numbers, so we - # check for a man page file found in later versions that use - # traditional section numbers instead - AC_CHECK_FILE([/usr/share/man/man7/attributes.7], - [SYSV_MAN_SECTIONS=false], [SYSV_MAN_SECTIONS=true]) - ;; - *) SYSV_MAN_SECTIONS=false ;; -esac - -if test x$APP_MAN_SUFFIX = x ; then - APP_MAN_SUFFIX=1 -fi -if test x$APP_MAN_DIR = x ; then - APP_MAN_DIR='$(mandir)/man$(APP_MAN_SUFFIX)' -fi - -if test x$LIB_MAN_SUFFIX = x ; then - LIB_MAN_SUFFIX=3 -fi -if test x$LIB_MAN_DIR = x ; then - LIB_MAN_DIR='$(mandir)/man$(LIB_MAN_SUFFIX)' -fi - -if test x$FILE_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) FILE_MAN_SUFFIX=4 ;; - *) FILE_MAN_SUFFIX=5 ;; - esac -fi -if test x$FILE_MAN_DIR = x ; then - FILE_MAN_DIR='$(mandir)/man$(FILE_MAN_SUFFIX)' -fi - -if test x$MISC_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) MISC_MAN_SUFFIX=5 ;; - *) MISC_MAN_SUFFIX=7 ;; - esac -fi -if test x$MISC_MAN_DIR = x ; then - MISC_MAN_DIR='$(mandir)/man$(MISC_MAN_SUFFIX)' -fi - -if test x$DRIVER_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) DRIVER_MAN_SUFFIX=7 ;; - *) DRIVER_MAN_SUFFIX=4 ;; - esac -fi -if test x$DRIVER_MAN_DIR = x ; then - DRIVER_MAN_DIR='$(mandir)/man$(DRIVER_MAN_SUFFIX)' -fi - -if test x$ADMIN_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) ADMIN_MAN_SUFFIX=1m ;; - *) ADMIN_MAN_SUFFIX=8 ;; - esac -fi -if test x$ADMIN_MAN_DIR = x ; then - ADMIN_MAN_DIR='$(mandir)/man$(ADMIN_MAN_SUFFIX)' -fi - - -AC_SUBST([APP_MAN_SUFFIX]) -AC_SUBST([LIB_MAN_SUFFIX]) -AC_SUBST([FILE_MAN_SUFFIX]) -AC_SUBST([MISC_MAN_SUFFIX]) -AC_SUBST([DRIVER_MAN_SUFFIX]) -AC_SUBST([ADMIN_MAN_SUFFIX]) -AC_SUBST([APP_MAN_DIR]) -AC_SUBST([LIB_MAN_DIR]) -AC_SUBST([FILE_MAN_DIR]) -AC_SUBST([MISC_MAN_DIR]) -AC_SUBST([DRIVER_MAN_DIR]) -AC_SUBST([ADMIN_MAN_DIR]) - -XORG_MAN_PAGE="X Version 11" -AC_SUBST([XORG_MAN_PAGE]) -MAN_SUBSTS="\ - -e 's|__vendorversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xorgversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xservername__|Xorg|g' \ - -e 's|__xconfigfile__|xorg.conf|g' \ - -e 's|__projectroot__|\$(prefix)|g' \ - -e 's|__apploaddir__|\$(appdefaultdir)|g' \ - -e 's|__appmansuffix__|\$(APP_MAN_SUFFIX)|g' \ - -e 's|__drivermansuffix__|\$(DRIVER_MAN_SUFFIX)|g' \ - -e 's|__adminmansuffix__|\$(ADMIN_MAN_SUFFIX)|g' \ - -e 's|__libmansuffix__|\$(LIB_MAN_SUFFIX)|g' \ - -e 's|__miscmansuffix__|\$(MISC_MAN_SUFFIX)|g' \ - -e 's|__filemansuffix__|\$(FILE_MAN_SUFFIX)|g'" -AC_SUBST([MAN_SUBSTS]) - -]) # XORG_MANPAGE_SECTIONS - -# XORG_CHECK_SGML_DOCTOOLS([MIN-VERSION]) -# ------------------------ -# Minimum version: 1.7.0 -# -# Defines the variable XORG_SGML_PATH containing the location of X11/defs.ent -# provided by xorg-sgml-doctools, if installed. -AC_DEFUN([XORG_CHECK_SGML_DOCTOOLS],[ -AC_MSG_CHECKING([for X.Org SGML entities m4_ifval([$1],[>= $1])]) -XORG_SGML_PATH= -PKG_CHECK_EXISTS([xorg-sgml-doctools m4_ifval([$1],[>= $1])], - [XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools`], - [m4_ifval([$1],[:], - [if test x"$cross_compiling" != x"yes" ; then - AC_CHECK_FILE([$prefix/share/sgml/X11/defs.ent], - [XORG_SGML_PATH=$prefix/share/sgml]) - fi]) - ]) - -# Define variables STYLESHEET_SRCDIR and XSL_STYLESHEET containing -# the path and the name of the doc stylesheet -if test "x$XORG_SGML_PATH" != "x" ; then - AC_MSG_RESULT([$XORG_SGML_PATH]) - STYLESHEET_SRCDIR=$XORG_SGML_PATH/X11 - XSL_STYLESHEET=$STYLESHEET_SRCDIR/xorg.xsl -else - AC_MSG_RESULT([no]) -fi - -AC_SUBST(XORG_SGML_PATH) -AC_SUBST(STYLESHEET_SRCDIR) -AC_SUBST(XSL_STYLESHEET) -AM_CONDITIONAL([HAVE_STYLESHEETS], [test "x$XSL_STYLESHEET" != "x"]) -]) # XORG_CHECK_SGML_DOCTOOLS - -# XORG_CHECK_LINUXDOC -# ------------------- -# Minimum version: 1.0.0 -# -# Defines the variable MAKE_TEXT if the necessary tools and -# files are found. $(MAKE_TEXT) blah.sgml will then produce blah.txt. -# Whether or not the necessary tools and files are found can be checked -# with the AM_CONDITIONAL "BUILD_LINUXDOC" -AC_DEFUN([XORG_CHECK_LINUXDOC],[ -AC_REQUIRE([XORG_CHECK_SGML_DOCTOOLS]) -AC_REQUIRE([XORG_WITH_PS2PDF]) - -AC_PATH_PROG(LINUXDOC, linuxdoc) - -AC_MSG_CHECKING([whether to build documentation]) - -if test x$XORG_SGML_PATH != x && test x$LINUXDOC != x ; then - BUILDDOC=yes -else - BUILDDOC=no -fi - -AM_CONDITIONAL(BUILD_LINUXDOC, [test x$BUILDDOC = xyes]) - -AC_MSG_RESULT([$BUILDDOC]) - -AC_MSG_CHECKING([whether to build pdf documentation]) - -if test x$have_ps2pdf != xno && test x$BUILD_PDFDOC != xno; then - BUILDPDFDOC=yes -else - BUILDPDFDOC=no -fi - -AM_CONDITIONAL(BUILD_PDFDOC, [test x$BUILDPDFDOC = xyes]) - -AC_MSG_RESULT([$BUILDPDFDOC]) - -MAKE_TEXT="SGML_SEARCH_PATH=$XORG_SGML_PATH GROFF_NO_SGR=y $LINUXDOC -B txt -f" -MAKE_PS="SGML_SEARCH_PATH=$XORG_SGML_PATH $LINUXDOC -B latex --papersize=letter --output=ps" -MAKE_PDF="$PS2PDF" -MAKE_HTML="SGML_SEARCH_PATH=$XORG_SGML_PATH $LINUXDOC -B html --split=0" - -AC_SUBST(MAKE_TEXT) -AC_SUBST(MAKE_PS) -AC_SUBST(MAKE_PDF) -AC_SUBST(MAKE_HTML) -]) # XORG_CHECK_LINUXDOC - -# XORG_CHECK_DOCBOOK -# ------------------- -# Minimum version: 1.0.0 -# -# Checks for the ability to build output formats from SGML DocBook source. -# For XXX in {TXT, PDF, PS, HTML}, the AM_CONDITIONAL "BUILD_XXXDOC" -# indicates whether the necessary tools and files are found and, if set, -# $(MAKE_XXX) blah.sgml will produce blah.xxx. -AC_DEFUN([XORG_CHECK_DOCBOOK],[ -AC_REQUIRE([XORG_CHECK_SGML_DOCTOOLS]) - -BUILDTXTDOC=no -BUILDPDFDOC=no -BUILDPSDOC=no -BUILDHTMLDOC=no - -AC_PATH_PROG(DOCBOOKPS, docbook2ps) -AC_PATH_PROG(DOCBOOKPDF, docbook2pdf) -AC_PATH_PROG(DOCBOOKHTML, docbook2html) -AC_PATH_PROG(DOCBOOKTXT, docbook2txt) - -AC_MSG_CHECKING([whether to build text documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKTXT != x && - test x$BUILD_TXTDOC != xno; then - BUILDTXTDOC=yes -fi -AM_CONDITIONAL(BUILD_TXTDOC, [test x$BUILDTXTDOC = xyes]) -AC_MSG_RESULT([$BUILDTXTDOC]) - -AC_MSG_CHECKING([whether to build PDF documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKPDF != x && - test x$BUILD_PDFDOC != xno; then - BUILDPDFDOC=yes -fi -AM_CONDITIONAL(BUILD_PDFDOC, [test x$BUILDPDFDOC = xyes]) -AC_MSG_RESULT([$BUILDPDFDOC]) - -AC_MSG_CHECKING([whether to build PostScript documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKPS != x && - test x$BUILD_PSDOC != xno; then - BUILDPSDOC=yes -fi -AM_CONDITIONAL(BUILD_PSDOC, [test x$BUILDPSDOC = xyes]) -AC_MSG_RESULT([$BUILDPSDOC]) - -AC_MSG_CHECKING([whether to build HTML documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKHTML != x && - test x$BUILD_HTMLDOC != xno; then - BUILDHTMLDOC=yes -fi -AM_CONDITIONAL(BUILD_HTMLDOC, [test x$BUILDHTMLDOC = xyes]) -AC_MSG_RESULT([$BUILDHTMLDOC]) - -MAKE_TEXT="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKTXT" -MAKE_PS="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKPS" -MAKE_PDF="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKPDF" -MAKE_HTML="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKHTML" - -AC_SUBST(MAKE_TEXT) -AC_SUBST(MAKE_PS) -AC_SUBST(MAKE_PDF) -AC_SUBST(MAKE_HTML) -]) # XORG_CHECK_DOCBOOK - -# XORG_WITH_XMLTO([MIN-VERSION], [DEFAULT]) -# ---------------- -# Minimum version: 1.5.0 -# Minimum version for optional DEFAULT argument: 1.11.0 -# -# Documentation tools are not always available on all platforms and sometimes -# not at the appropriate level. This macro enables a module to test for the -# presence of the tool and obtain it's path in separate variables. Coupled with -# the --with-xmlto option, it allows maximum flexibility in making decisions -# as whether or not to use the xmlto package. When DEFAULT is not specified, -# --with-xmlto assumes 'auto'. -# -# Interface to module: -# HAVE_XMLTO: used in makefiles to conditionally generate documentation -# XMLTO: returns the path of the xmlto program found -# returns the path set by the user in the environment -# --with-xmlto: 'yes' user instructs the module to use xmlto -# 'no' user instructs the module not to use xmlto -# -# Added in version 1.10.0 -# HAVE_XMLTO_TEXT: used in makefiles to conditionally generate text documentation -# xmlto for text output requires either lynx, links, or w3m browsers -# -# If the user sets the value of XMLTO, AC_PATH_PROG skips testing the path. -# -AC_DEFUN([XORG_WITH_XMLTO],[ -AC_ARG_VAR([XMLTO], [Path to xmlto command]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(xmlto, - AS_HELP_STRING([--with-xmlto], - [Use xmlto to regenerate documentation (default: ]_defopt[)]), - [use_xmlto=$withval], [use_xmlto=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_xmlto" = x"auto"; then - AC_PATH_PROG([XMLTO], [xmlto]) - if test "x$XMLTO" = "x"; then - AC_MSG_WARN([xmlto not found - documentation targets will be skipped]) - have_xmlto=no - else - have_xmlto=yes - fi -elif test "x$use_xmlto" = x"yes" ; then - AC_PATH_PROG([XMLTO], [xmlto]) - if test "x$XMLTO" = "x"; then - AC_MSG_ERROR([--with-xmlto=yes specified but xmlto not found in PATH]) - fi - have_xmlto=yes -elif test "x$use_xmlto" = x"no" ; then - if test "x$XMLTO" != "x"; then - AC_MSG_WARN([ignoring XMLTO environment variable since --with-xmlto=no was specified]) - fi - have_xmlto=no -else - AC_MSG_ERROR([--with-xmlto expects 'yes' or 'no']) -fi - -# Test for a minimum version of xmlto, if provided. -m4_ifval([$1], -[if test "$have_xmlto" = yes; then - # scrape the xmlto version - AC_MSG_CHECKING([the xmlto version]) - xmlto_version=`$XMLTO --version 2>/dev/null | cut -d' ' -f3` - AC_MSG_RESULT([$xmlto_version]) - AS_VERSION_COMPARE([$xmlto_version], [$1], - [if test "x$use_xmlto" = xauto; then - AC_MSG_WARN([xmlto version $xmlto_version found, but $1 needed]) - have_xmlto=no - else - AC_MSG_ERROR([xmlto version $xmlto_version found, but $1 needed]) - fi]) -fi]) - -# Test for the ability of xmlto to generate a text target -# -# NOTE: xmlto 0.0.27 or higher return a non-zero return code in the -# following test for empty XML docbook files. -# For compatibility reasons use the following empty XML docbook file and if -# it fails try it again with a non-empty XML file. -have_xmlto_text=no -cat > conftest.xml << "EOF" -EOF -AS_IF([test "$have_xmlto" = yes], - [AS_IF([$XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1], - [have_xmlto_text=yes], - [# Try it again with a non-empty XML file. - cat > conftest.xml << "EOF" - -EOF - AS_IF([$XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1], - [have_xmlto_text=yes], - [AC_MSG_WARN([xmlto cannot generate text format, this format skipped])])])]) -rm -f conftest.xml -AM_CONDITIONAL([HAVE_XMLTO_TEXT], [test $have_xmlto_text = yes]) -AM_CONDITIONAL([HAVE_XMLTO], [test "$have_xmlto" = yes]) -]) # XORG_WITH_XMLTO - -# XORG_WITH_XSLTPROC([MIN-VERSION], [DEFAULT]) -# -------------------------------------------- -# Minimum version: 1.12.0 -# Minimum version for optional DEFAULT argument: 1.12.0 -# -# XSLT (Extensible Stylesheet Language Transformations) is a declarative, -# XML-based language used for the transformation of XML documents. -# The xsltproc command line tool is for applying XSLT stylesheets to XML documents. -# It is used under the cover by xmlto to generate html files from DocBook/XML. -# The XSLT processor is often used as a standalone tool for transformations. -# It should not be assumed that this tool is used only to work with documnetation. -# When DEFAULT is not specified, --with-xsltproc assumes 'auto'. -# -# Interface to module: -# HAVE_XSLTPROC: used in makefiles to conditionally generate documentation -# XSLTPROC: returns the path of the xsltproc program found -# returns the path set by the user in the environment -# --with-xsltproc: 'yes' user instructs the module to use xsltproc -# 'no' user instructs the module not to use xsltproc -# have_xsltproc: returns yes if xsltproc found in PATH or no -# -# If the user sets the value of XSLTPROC, AC_PATH_PROG skips testing the path. -# -AC_DEFUN([XORG_WITH_XSLTPROC],[ -AC_ARG_VAR([XSLTPROC], [Path to xsltproc command]) -# Preserves the interface, should it be implemented later -m4_ifval([$1], [m4_warn([syntax], [Checking for xsltproc MIN-VERSION is not implemented])]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(xsltproc, - AS_HELP_STRING([--with-xsltproc], - [Use xsltproc for the transformation of XML documents (default: ]_defopt[)]), - [use_xsltproc=$withval], [use_xsltproc=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_xsltproc" = x"auto"; then - AC_PATH_PROG([XSLTPROC], [xsltproc]) - if test "x$XSLTPROC" = "x"; then - AC_MSG_WARN([xsltproc not found - cannot transform XML documents]) - have_xsltproc=no - else - have_xsltproc=yes - fi -elif test "x$use_xsltproc" = x"yes" ; then - AC_PATH_PROG([XSLTPROC], [xsltproc]) - if test "x$XSLTPROC" = "x"; then - AC_MSG_ERROR([--with-xsltproc=yes specified but xsltproc not found in PATH]) - fi - have_xsltproc=yes -elif test "x$use_xsltproc" = x"no" ; then - if test "x$XSLTPROC" != "x"; then - AC_MSG_WARN([ignoring XSLTPROC environment variable since --with-xsltproc=no was specified]) - fi - have_xsltproc=no -else - AC_MSG_ERROR([--with-xsltproc expects 'yes' or 'no']) -fi - -AM_CONDITIONAL([HAVE_XSLTPROC], [test "$have_xsltproc" = yes]) -]) # XORG_WITH_XSLTPROC - -# XORG_WITH_PERL([MIN-VERSION], [DEFAULT]) -# ---------------------------------------- -# Minimum version: 1.15.0 -# -# PERL (Practical Extraction and Report Language) is a language optimized for -# scanning arbitrary text files, extracting information from those text files, -# and printing reports based on that information. -# -# When DEFAULT is not specified, --with-perl assumes 'auto'. -# -# Interface to module: -# HAVE_PERL: used in makefiles to conditionally scan text files -# PERL: returns the path of the perl program found -# returns the path set by the user in the environment -# --with-perl: 'yes' user instructs the module to use perl -# 'no' user instructs the module not to use perl -# have_perl: returns yes if perl found in PATH or no -# -# If the user sets the value of PERL, AC_PATH_PROG skips testing the path. -# -AC_DEFUN([XORG_WITH_PERL],[ -AC_ARG_VAR([PERL], [Path to perl command]) -# Preserves the interface, should it be implemented later -m4_ifval([$1], [m4_warn([syntax], [Checking for perl MIN-VERSION is not implemented])]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(perl, - AS_HELP_STRING([--with-perl], - [Use perl for extracting information from files (default: ]_defopt[)]), - [use_perl=$withval], [use_perl=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_perl" = x"auto"; then - AC_PATH_PROG([PERL], [perl]) - if test "x$PERL" = "x"; then - AC_MSG_WARN([perl not found - cannot extract information and report]) - have_perl=no - else - have_perl=yes - fi -elif test "x$use_perl" = x"yes" ; then - AC_PATH_PROG([PERL], [perl]) - if test "x$PERL" = "x"; then - AC_MSG_ERROR([--with-perl=yes specified but perl not found in PATH]) - fi - have_perl=yes -elif test "x$use_perl" = x"no" ; then - if test "x$PERL" != "x"; then - AC_MSG_WARN([ignoring PERL environment variable since --with-perl=no was specified]) - fi - have_perl=no -else - AC_MSG_ERROR([--with-perl expects 'yes' or 'no']) -fi - -AM_CONDITIONAL([HAVE_PERL], [test "$have_perl" = yes]) -]) # XORG_WITH_PERL - -# XORG_WITH_ASCIIDOC([MIN-VERSION], [DEFAULT]) -# ---------------- -# Minimum version: 1.5.0 -# Minimum version for optional DEFAULT argument: 1.11.0 -# -# Documentation tools are not always available on all platforms and sometimes -# not at the appropriate level. This macro enables a module to test for the -# presence of the tool and obtain it's path in separate variables. Coupled with -# the --with-asciidoc option, it allows maximum flexibility in making decisions -# as whether or not to use the asciidoc package. When DEFAULT is not specified, -# --with-asciidoc assumes 'auto'. -# -# Interface to module: -# HAVE_ASCIIDOC: used in makefiles to conditionally generate documentation -# ASCIIDOC: returns the path of the asciidoc program found -# returns the path set by the user in the environment -# --with-asciidoc: 'yes' user instructs the module to use asciidoc -# 'no' user instructs the module not to use asciidoc -# -# If the user sets the value of ASCIIDOC, AC_PATH_PROG skips testing the path. -# -AC_DEFUN([XORG_WITH_ASCIIDOC],[ -AC_ARG_VAR([ASCIIDOC], [Path to asciidoc command]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(asciidoc, - AS_HELP_STRING([--with-asciidoc], - [Use asciidoc to regenerate documentation (default: ]_defopt[)]), - [use_asciidoc=$withval], [use_asciidoc=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_asciidoc" = x"auto"; then - AC_PATH_PROG([ASCIIDOC], [asciidoc]) - if test "x$ASCIIDOC" = "x"; then - AC_MSG_WARN([asciidoc not found - documentation targets will be skipped]) - have_asciidoc=no - else - have_asciidoc=yes - fi -elif test "x$use_asciidoc" = x"yes" ; then - AC_PATH_PROG([ASCIIDOC], [asciidoc]) - if test "x$ASCIIDOC" = "x"; then - AC_MSG_ERROR([--with-asciidoc=yes specified but asciidoc not found in PATH]) - fi - have_asciidoc=yes -elif test "x$use_asciidoc" = x"no" ; then - if test "x$ASCIIDOC" != "x"; then - AC_MSG_WARN([ignoring ASCIIDOC environment variable since --with-asciidoc=no was specified]) - fi - have_asciidoc=no -else - AC_MSG_ERROR([--with-asciidoc expects 'yes' or 'no']) -fi -m4_ifval([$1], -[if test "$have_asciidoc" = yes; then - # scrape the asciidoc version - AC_MSG_CHECKING([the asciidoc version]) - asciidoc_version=`$ASCIIDOC --version 2>/dev/null | cut -d' ' -f2` - AC_MSG_RESULT([$asciidoc_version]) - AS_VERSION_COMPARE([$asciidoc_version], [$1], - [if test "x$use_asciidoc" = xauto; then - AC_MSG_WARN([asciidoc version $asciidoc_version found, but $1 needed]) - have_asciidoc=no - else - AC_MSG_ERROR([asciidoc version $asciidoc_version found, but $1 needed]) - fi]) -fi]) -AM_CONDITIONAL([HAVE_ASCIIDOC], [test "$have_asciidoc" = yes]) -]) # XORG_WITH_ASCIIDOC - -# XORG_WITH_DOXYGEN([MIN-VERSION], [DEFAULT]) -# ------------------------------------------- -# Minimum version: 1.5.0 -# Minimum version for optional DEFAULT argument: 1.11.0 -# Minimum version for optional DOT checking: 1.18.0 -# -# Documentation tools are not always available on all platforms and sometimes -# not at the appropriate level. This macro enables a module to test for the -# presence of the tool and obtain it's path in separate variables. Coupled with -# the --with-doxygen option, it allows maximum flexibility in making decisions -# as whether or not to use the doxygen package. When DEFAULT is not specified, -# --with-doxygen assumes 'auto'. -# -# Interface to module: -# HAVE_DOXYGEN: used in makefiles to conditionally generate documentation -# DOXYGEN: returns the path of the doxygen program found -# returns the path set by the user in the environment -# --with-doxygen: 'yes' user instructs the module to use doxygen -# 'no' user instructs the module not to use doxygen -# -# If the user sets the value of DOXYGEN, AC_PATH_PROG skips testing the path. -# -AC_DEFUN([XORG_WITH_DOXYGEN],[ -AC_ARG_VAR([DOXYGEN], [Path to doxygen command]) -AC_ARG_VAR([DOT], [Path to the dot graphics utility]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(doxygen, - AS_HELP_STRING([--with-doxygen], - [Use doxygen to regenerate documentation (default: ]_defopt[)]), - [use_doxygen=$withval], [use_doxygen=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_doxygen" = x"auto"; then - AC_PATH_PROG([DOXYGEN], [doxygen]) - if test "x$DOXYGEN" = "x"; then - AC_MSG_WARN([doxygen not found - documentation targets will be skipped]) - have_doxygen=no - else - have_doxygen=yes - fi -elif test "x$use_doxygen" = x"yes" ; then - AC_PATH_PROG([DOXYGEN], [doxygen]) - if test "x$DOXYGEN" = "x"; then - AC_MSG_ERROR([--with-doxygen=yes specified but doxygen not found in PATH]) - fi - have_doxygen=yes -elif test "x$use_doxygen" = x"no" ; then - if test "x$DOXYGEN" != "x"; then - AC_MSG_WARN([ignoring DOXYGEN environment variable since --with-doxygen=no was specified]) - fi - have_doxygen=no -else - AC_MSG_ERROR([--with-doxygen expects 'yes' or 'no']) -fi -m4_ifval([$1], -[if test "$have_doxygen" = yes; then - # scrape the doxygen version - AC_MSG_CHECKING([the doxygen version]) - doxygen_version=`$DOXYGEN --version 2>/dev/null` - AC_MSG_RESULT([$doxygen_version]) - AS_VERSION_COMPARE([$doxygen_version], [$1], - [if test "x$use_doxygen" = xauto; then - AC_MSG_WARN([doxygen version $doxygen_version found, but $1 needed]) - have_doxygen=no - else - AC_MSG_ERROR([doxygen version $doxygen_version found, but $1 needed]) - fi]) -fi]) - -dnl Check for DOT if we have doxygen. The caller decides if it is mandatory -dnl HAVE_DOT is a variable that can be used in your doxygen.in config file: -dnl HAVE_DOT = @HAVE_DOT@ -HAVE_DOT=no -if test "x$have_doxygen" = "xyes"; then - AC_PATH_PROG([DOT], [dot]) - if test "x$DOT" != "x"; then - HAVE_DOT=yes - fi -fi - -AC_SUBST([HAVE_DOT]) -AM_CONDITIONAL([HAVE_DOT], [test "$HAVE_DOT" = "yes"]) -AM_CONDITIONAL([HAVE_DOXYGEN], [test "$have_doxygen" = yes]) -]) # XORG_WITH_DOXYGEN - -# XORG_WITH_GROFF([DEFAULT]) -# ---------------- -# Minimum version: 1.6.0 -# Minimum version for optional DEFAULT argument: 1.11.0 -# -# Documentation tools are not always available on all platforms and sometimes -# not at the appropriate level. This macro enables a module to test for the -# presence of the tool and obtain it's path in separate variables. Coupled with -# the --with-groff option, it allows maximum flexibility in making decisions -# as whether or not to use the groff package. When DEFAULT is not specified, -# --with-groff assumes 'auto'. -# -# Interface to module: -# HAVE_GROFF: used in makefiles to conditionally generate documentation -# HAVE_GROFF_MM: the memorandum macros (-mm) package -# HAVE_GROFF_MS: the -ms macros package -# GROFF: returns the path of the groff program found -# returns the path set by the user in the environment -# --with-groff: 'yes' user instructs the module to use groff -# 'no' user instructs the module not to use groff -# -# Added in version 1.9.0: -# HAVE_GROFF_HTML: groff has dependencies to output HTML format: -# pnmcut pnmcrop pnmtopng pnmtops from the netpbm package. -# psselect from the psutils package. -# the ghostcript package. Refer to the grohtml man pages -# -# If the user sets the value of GROFF, AC_PATH_PROG skips testing the path. -# -# OS and distros often splits groff in a basic and full package, the former -# having the groff program and the later having devices, fonts and macros -# Checking for the groff executable is not enough. -# -# If macros are missing, we cannot assume that groff is useless, so we don't -# unset HAVE_GROFF or GROFF env variables. -# HAVE_GROFF_?? can never be true while HAVE_GROFF is false. -# -AC_DEFUN([XORG_WITH_GROFF],[ -AC_ARG_VAR([GROFF], [Path to groff command]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_WITH(groff, - AS_HELP_STRING([--with-groff], - [Use groff to regenerate documentation (default: ]_defopt[)]), - [use_groff=$withval], [use_groff=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_groff" = x"auto"; then - AC_PATH_PROG([GROFF], [groff]) - if test "x$GROFF" = "x"; then - AC_MSG_WARN([groff not found - documentation targets will be skipped]) - have_groff=no - else - have_groff=yes - fi -elif test "x$use_groff" = x"yes" ; then - AC_PATH_PROG([GROFF], [groff]) - if test "x$GROFF" = "x"; then - AC_MSG_ERROR([--with-groff=yes specified but groff not found in PATH]) - fi - have_groff=yes -elif test "x$use_groff" = x"no" ; then - if test "x$GROFF" != "x"; then - AC_MSG_WARN([ignoring GROFF environment variable since --with-groff=no was specified]) - fi - have_groff=no -else - AC_MSG_ERROR([--with-groff expects 'yes' or 'no']) -fi - -# We have groff, test for the presence of the macro packages -if test "x$have_groff" = x"yes"; then - AC_MSG_CHECKING([for ${GROFF} -ms macros]) - if ${GROFF} -ms -I. /dev/null >/dev/null 2>&1 ; then - groff_ms_works=yes - else - groff_ms_works=no - fi - AC_MSG_RESULT([$groff_ms_works]) - AC_MSG_CHECKING([for ${GROFF} -mm macros]) - if ${GROFF} -mm -I. /dev/null >/dev/null 2>&1 ; then - groff_mm_works=yes - else - groff_mm_works=no - fi - AC_MSG_RESULT([$groff_mm_works]) -fi - -# We have groff, test for HTML dependencies, one command per package -if test "x$have_groff" = x"yes"; then - AC_PATH_PROGS(GS_PATH, [gs gswin32c]) - AC_PATH_PROG(PNMTOPNG_PATH, [pnmtopng]) - AC_PATH_PROG(PSSELECT_PATH, [psselect]) - if test "x$GS_PATH" != "x" -a "x$PNMTOPNG_PATH" != "x" -a "x$PSSELECT_PATH" != "x"; then - have_groff_html=yes - else - have_groff_html=no - AC_MSG_WARN([grohtml dependencies not found - HTML Documentation skipped. Refer to grohtml man pages]) - fi -fi - -# Set Automake conditionals for Makefiles -AM_CONDITIONAL([HAVE_GROFF], [test "$have_groff" = yes]) -AM_CONDITIONAL([HAVE_GROFF_MS], [test "$groff_ms_works" = yes]) -AM_CONDITIONAL([HAVE_GROFF_MM], [test "$groff_mm_works" = yes]) -AM_CONDITIONAL([HAVE_GROFF_HTML], [test "$have_groff_html" = yes]) -]) # XORG_WITH_GROFF - -# XORG_WITH_FOP([MIN-VERSION], [DEFAULT]) -# --------------------------------------- -# Minimum version: 1.6.0 -# Minimum version for optional DEFAULT argument: 1.11.0 -# Minimum version for optional MIN-VERSION argument: 1.15.0 -# -# Documentation tools are not always available on all platforms and sometimes -# not at the appropriate level. This macro enables a module to test for the -# presence of the tool and obtain it's path in separate variables. Coupled with -# the --with-fop option, it allows maximum flexibility in making decisions -# as whether or not to use the fop package. When DEFAULT is not specified, -# --with-fop assumes 'auto'. -# -# Interface to module: -# HAVE_FOP: used in makefiles to conditionally generate documentation -# FOP: returns the path of the fop program found -# returns the path set by the user in the environment -# --with-fop: 'yes' user instructs the module to use fop -# 'no' user instructs the module not to use fop -# -# If the user sets the value of FOP, AC_PATH_PROG skips testing the path. -# -AC_DEFUN([XORG_WITH_FOP],[ -AC_ARG_VAR([FOP], [Path to fop command]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(fop, - AS_HELP_STRING([--with-fop], - [Use fop to regenerate documentation (default: ]_defopt[)]), - [use_fop=$withval], [use_fop=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_fop" = x"auto"; then - AC_PATH_PROG([FOP], [fop]) - if test "x$FOP" = "x"; then - AC_MSG_WARN([fop not found - documentation targets will be skipped]) - have_fop=no - else - have_fop=yes - fi -elif test "x$use_fop" = x"yes" ; then - AC_PATH_PROG([FOP], [fop]) - if test "x$FOP" = "x"; then - AC_MSG_ERROR([--with-fop=yes specified but fop not found in PATH]) - fi - have_fop=yes -elif test "x$use_fop" = x"no" ; then - if test "x$FOP" != "x"; then - AC_MSG_WARN([ignoring FOP environment variable since --with-fop=no was specified]) - fi - have_fop=no -else - AC_MSG_ERROR([--with-fop expects 'yes' or 'no']) -fi - -# Test for a minimum version of fop, if provided. -m4_ifval([$1], -[if test "$have_fop" = yes; then - # scrape the fop version - AC_MSG_CHECKING([for fop minimum version]) - fop_version=`$FOP -version 2>/dev/null | cut -d' ' -f3` - AC_MSG_RESULT([$fop_version]) - AS_VERSION_COMPARE([$fop_version], [$1], - [if test "x$use_fop" = xauto; then - AC_MSG_WARN([fop version $fop_version found, but $1 needed]) - have_fop=no - else - AC_MSG_ERROR([fop version $fop_version found, but $1 needed]) - fi]) -fi]) -AM_CONDITIONAL([HAVE_FOP], [test "$have_fop" = yes]) -]) # XORG_WITH_FOP - -# XORG_WITH_M4([MIN-VERSION]) -# --------------------------- -# Minimum version: 1.19.0 -# -# This macro attempts to locate an m4 macro processor which supports -# -I option and is only useful for modules relying on M4 in order to -# expand macros in source code files. -# -# Interface to module: -# M4: returns the path of the m4 program found -# returns the path set by the user in the environment -# -AC_DEFUN([XORG_WITH_M4], [ -AC_CACHE_CHECK([for m4 that supports -I option], [ac_cv_path_M4], - [AC_PATH_PROGS_FEATURE_CHECK([M4], [m4 gm4], - [[$ac_path_M4 -I. /dev/null > /dev/null 2>&1 && \ - ac_cv_path_M4=$ac_path_M4 ac_path_M4_found=:]], - [AC_MSG_ERROR([could not find m4 that supports -I option])], - [$PATH:/usr/gnu/bin])]) - -AC_SUBST([M4], [$ac_cv_path_M4]) -]) # XORG_WITH_M4 - -# XORG_WITH_PS2PDF([DEFAULT]) -# ---------------- -# Minimum version: 1.6.0 -# Minimum version for optional DEFAULT argument: 1.11.0 -# -# Documentation tools are not always available on all platforms and sometimes -# not at the appropriate level. This macro enables a module to test for the -# presence of the tool and obtain it's path in separate variables. Coupled with -# the --with-ps2pdf option, it allows maximum flexibility in making decisions -# as whether or not to use the ps2pdf package. When DEFAULT is not specified, -# --with-ps2pdf assumes 'auto'. -# -# Interface to module: -# HAVE_PS2PDF: used in makefiles to conditionally generate documentation -# PS2PDF: returns the path of the ps2pdf program found -# returns the path set by the user in the environment -# --with-ps2pdf: 'yes' user instructs the module to use ps2pdf -# 'no' user instructs the module not to use ps2pdf -# -# If the user sets the value of PS2PDF, AC_PATH_PROG skips testing the path. -# -AC_DEFUN([XORG_WITH_PS2PDF],[ -AC_ARG_VAR([PS2PDF], [Path to ps2pdf command]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_WITH(ps2pdf, - AS_HELP_STRING([--with-ps2pdf], - [Use ps2pdf to regenerate documentation (default: ]_defopt[)]), - [use_ps2pdf=$withval], [use_ps2pdf=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_ps2pdf" = x"auto"; then - AC_PATH_PROG([PS2PDF], [ps2pdf]) - if test "x$PS2PDF" = "x"; then - AC_MSG_WARN([ps2pdf not found - documentation targets will be skipped]) - have_ps2pdf=no - else - have_ps2pdf=yes - fi -elif test "x$use_ps2pdf" = x"yes" ; then - AC_PATH_PROG([PS2PDF], [ps2pdf]) - if test "x$PS2PDF" = "x"; then - AC_MSG_ERROR([--with-ps2pdf=yes specified but ps2pdf not found in PATH]) - fi - have_ps2pdf=yes -elif test "x$use_ps2pdf" = x"no" ; then - if test "x$PS2PDF" != "x"; then - AC_MSG_WARN([ignoring PS2PDF environment variable since --with-ps2pdf=no was specified]) - fi - have_ps2pdf=no -else - AC_MSG_ERROR([--with-ps2pdf expects 'yes' or 'no']) -fi -AM_CONDITIONAL([HAVE_PS2PDF], [test "$have_ps2pdf" = yes]) -]) # XORG_WITH_PS2PDF - -# XORG_ENABLE_DOCS (enable_docs=yes) -# ---------------- -# Minimum version: 1.6.0 -# -# Documentation tools are not always available on all platforms and sometimes -# not at the appropriate level. This macro enables a builder to skip all -# documentation targets except traditional man pages. -# Combined with the specific tool checking macros XORG_WITH_*, it provides -# maximum flexibility in controlling documentation building. -# Refer to: -# XORG_WITH_XMLTO --with-xmlto -# XORG_WITH_ASCIIDOC --with-asciidoc -# XORG_WITH_DOXYGEN --with-doxygen -# XORG_WITH_FOP --with-fop -# XORG_WITH_GROFF --with-groff -# XORG_WITH_PS2PDF --with-ps2pdf -# -# Interface to module: -# ENABLE_DOCS: used in makefiles to conditionally generate documentation -# --enable-docs: 'yes' user instructs the module to generate docs -# 'no' user instructs the module not to generate docs -# parm1: specify the default value, yes or no. -# -AC_DEFUN([XORG_ENABLE_DOCS],[ -m4_define([docs_default], m4_default([$1], [yes])) -AC_ARG_ENABLE(docs, - AS_HELP_STRING([--enable-docs], - [Enable building the documentation (default: ]docs_default[)]), - [build_docs=$enableval], [build_docs=]docs_default) -m4_undefine([docs_default]) -AM_CONDITIONAL(ENABLE_DOCS, [test x$build_docs = xyes]) -AC_MSG_CHECKING([whether to build documentation]) -AC_MSG_RESULT([$build_docs]) -]) # XORG_ENABLE_DOCS - -# XORG_ENABLE_DEVEL_DOCS (enable_devel_docs=yes) -# ---------------- -# Minimum version: 1.6.0 -# -# This macro enables a builder to skip all developer documentation. -# Combined with the specific tool checking macros XORG_WITH_*, it provides -# maximum flexibility in controlling documentation building. -# Refer to: -# XORG_WITH_XMLTO --with-xmlto -# XORG_WITH_ASCIIDOC --with-asciidoc -# XORG_WITH_DOXYGEN --with-doxygen -# XORG_WITH_FOP --with-fop -# XORG_WITH_GROFF --with-groff -# XORG_WITH_PS2PDF --with-ps2pdf -# -# Interface to module: -# ENABLE_DEVEL_DOCS: used in makefiles to conditionally generate developer docs -# --enable-devel-docs: 'yes' user instructs the module to generate developer docs -# 'no' user instructs the module not to generate developer docs -# parm1: specify the default value, yes or no. -# -AC_DEFUN([XORG_ENABLE_DEVEL_DOCS],[ -m4_define([devel_default], m4_default([$1], [yes])) -AC_ARG_ENABLE(devel-docs, - AS_HELP_STRING([--enable-devel-docs], - [Enable building the developer documentation (default: ]devel_default[)]), - [build_devel_docs=$enableval], [build_devel_docs=]devel_default) -m4_undefine([devel_default]) -AM_CONDITIONAL(ENABLE_DEVEL_DOCS, [test x$build_devel_docs = xyes]) -AC_MSG_CHECKING([whether to build developer documentation]) -AC_MSG_RESULT([$build_devel_docs]) -]) # XORG_ENABLE_DEVEL_DOCS - -# XORG_ENABLE_SPECS (enable_specs=yes) -# ---------------- -# Minimum version: 1.6.0 -# -# This macro enables a builder to skip all functional specification targets. -# Combined with the specific tool checking macros XORG_WITH_*, it provides -# maximum flexibility in controlling documentation building. -# Refer to: -# XORG_WITH_XMLTO --with-xmlto -# XORG_WITH_ASCIIDOC --with-asciidoc -# XORG_WITH_DOXYGEN --with-doxygen -# XORG_WITH_FOP --with-fop -# XORG_WITH_GROFF --with-groff -# XORG_WITH_PS2PDF --with-ps2pdf -# -# Interface to module: -# ENABLE_SPECS: used in makefiles to conditionally generate specs -# --enable-specs: 'yes' user instructs the module to generate specs -# 'no' user instructs the module not to generate specs -# parm1: specify the default value, yes or no. -# -AC_DEFUN([XORG_ENABLE_SPECS],[ -m4_define([spec_default], m4_default([$1], [yes])) -AC_ARG_ENABLE(specs, - AS_HELP_STRING([--enable-specs], - [Enable building the specs (default: ]spec_default[)]), - [build_specs=$enableval], [build_specs=]spec_default) -m4_undefine([spec_default]) -AM_CONDITIONAL(ENABLE_SPECS, [test x$build_specs = xyes]) -AC_MSG_CHECKING([whether to build functional specifications]) -AC_MSG_RESULT([$build_specs]) -]) # XORG_ENABLE_SPECS - -# XORG_ENABLE_UNIT_TESTS (enable_unit_tests=auto) -# ---------------------------------------------- -# Minimum version: 1.13.0 -# -# This macro enables a builder to enable/disable unit testing -# It makes no assumption about the test cases implementation -# Test cases may or may not use Automake "Support for test suites" -# They may or may not use the software utility library GLib -# -# When used in conjunction with XORG_WITH_GLIB, use both AM_CONDITIONAL -# ENABLE_UNIT_TESTS and HAVE_GLIB. Not all unit tests may use glib. -# The variable enable_unit_tests is used by other macros in this file. -# -# Interface to module: -# ENABLE_UNIT_TESTS: used in makefiles to conditionally build tests -# enable_unit_tests: used in configure.ac for additional configuration -# --enable-unit-tests: 'yes' user instructs the module to build tests -# 'no' user instructs the module not to build tests -# parm1: specify the default value, yes or no. -# -AC_DEFUN([XORG_ENABLE_UNIT_TESTS],[ -AC_BEFORE([$0], [XORG_WITH_GLIB]) -AC_BEFORE([$0], [XORG_LD_WRAP]) -AC_REQUIRE([XORG_MEMORY_CHECK_FLAGS]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_ENABLE(unit-tests, AS_HELP_STRING([--enable-unit-tests], - [Enable building unit test cases (default: ]_defopt[)]), - [enable_unit_tests=$enableval], [enable_unit_tests=]_defopt) -m4_undefine([_defopt]) -AM_CONDITIONAL(ENABLE_UNIT_TESTS, [test "x$enable_unit_tests" != xno]) -AC_MSG_CHECKING([whether to build unit test cases]) -AC_MSG_RESULT([$enable_unit_tests]) -]) # XORG_ENABLE_UNIT_TESTS - -# XORG_ENABLE_INTEGRATION_TESTS (enable_unit_tests=auto) -# ------------------------------------------------------ -# Minimum version: 1.17.0 -# -# This macro enables a builder to enable/disable integration testing -# It makes no assumption about the test cases' implementation -# Test cases may or may not use Automake "Support for test suites" -# -# Please see XORG_ENABLE_UNIT_TESTS for unit test support. Unit test support -# usually requires less dependencies and may be built and run under less -# stringent environments than integration tests. -# -# Interface to module: -# ENABLE_INTEGRATION_TESTS: used in makefiles to conditionally build tests -# enable_integration_tests: used in configure.ac for additional configuration -# --enable-integration-tests: 'yes' user instructs the module to build tests -# 'no' user instructs the module not to build tests -# parm1: specify the default value, yes or no. -# -AC_DEFUN([XORG_ENABLE_INTEGRATION_TESTS],[ -AC_REQUIRE([XORG_MEMORY_CHECK_FLAGS]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_ENABLE(integration-tests, AS_HELP_STRING([--enable-integration-tests], - [Enable building integration test cases (default: ]_defopt[)]), - [enable_integration_tests=$enableval], - [enable_integration_tests=]_defopt) -m4_undefine([_defopt]) -AM_CONDITIONAL([ENABLE_INTEGRATION_TESTS], - [test "x$enable_integration_tests" != xno]) -AC_MSG_CHECKING([whether to build unit test cases]) -AC_MSG_RESULT([$enable_integration_tests]) -]) # XORG_ENABLE_INTEGRATION_TESTS - -# XORG_WITH_GLIB([MIN-VERSION], [DEFAULT]) -# ---------------------------------------- -# Minimum version: 1.13.0 -# -# GLib is a library which provides advanced data structures and functions. -# This macro enables a module to test for the presence of Glib. -# -# When used with ENABLE_UNIT_TESTS, it is assumed GLib is used for unit testing. -# Otherwise the value of $enable_unit_tests is blank. -# -# Please see XORG_ENABLE_INTEGRATION_TESTS for integration test support. Unit -# test support usually requires less dependencies and may be built and run under -# less stringent environments than integration tests. -# -# Interface to module: -# HAVE_GLIB: used in makefiles to conditionally build targets -# with_glib: used in configure.ac to know if GLib has been found -# --with-glib: 'yes' user instructs the module to use glib -# 'no' user instructs the module not to use glib -# -AC_DEFUN([XORG_WITH_GLIB],[ -AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(glib, AS_HELP_STRING([--with-glib], - [Use GLib library for unit testing (default: ]_defopt[)]), - [with_glib=$withval], [with_glib=]_defopt) -m4_undefine([_defopt]) - -have_glib=no -# Do not probe GLib if user explicitly disabled unit testing -if test "x$enable_unit_tests" != x"no"; then - # Do not probe GLib if user explicitly disabled it - if test "x$with_glib" != x"no"; then - m4_ifval( - [$1], - [PKG_CHECK_MODULES([GLIB], [glib-2.0 >= $1], [have_glib=yes], [have_glib=no])], - [PKG_CHECK_MODULES([GLIB], [glib-2.0], [have_glib=yes], [have_glib=no])] - ) - fi -fi - -# Not having GLib when unit testing has been explicitly requested is an error -if test "x$enable_unit_tests" = x"yes"; then - if test "x$have_glib" = x"no"; then - AC_MSG_ERROR([--enable-unit-tests=yes specified but glib-2.0 not found]) - fi -fi - -# Having unit testing disabled when GLib has been explicitly requested is an error -if test "x$enable_unit_tests" = x"no"; then - if test "x$with_glib" = x"yes"; then - AC_MSG_ERROR([--enable-unit-tests=yes specified but glib-2.0 not found]) - fi -fi - -# Not having GLib when it has been explicitly requested is an error -if test "x$with_glib" = x"yes"; then - if test "x$have_glib" = x"no"; then - AC_MSG_ERROR([--with-glib=yes specified but glib-2.0 not found]) - fi -fi - -AM_CONDITIONAL([HAVE_GLIB], [test "$have_glib" = yes]) -]) # XORG_WITH_GLIB - -# XORG_LD_WRAP([required|optional]) -# --------------------------------- -# Minimum version: 1.13.0 -# -# Check if linker supports -wrap, passed via compiler flags -# -# When used with ENABLE_UNIT_TESTS, it is assumed -wrap is used for unit testing. -# Otherwise the value of $enable_unit_tests is blank. -# -# Argument added in 1.16.0 - default is "required", to match existing behavior -# of returning an error if enable_unit_tests is yes, and ld -wrap is not -# available, an argument of "optional" allows use when some unit tests require -# ld -wrap and others do not. -# -AC_DEFUN([XORG_LD_WRAP],[ -XORG_CHECK_LINKER_FLAGS([-Wl,-wrap,exit],[have_ld_wrap=yes],[have_ld_wrap=no], - [AC_LANG_PROGRAM([#include - void __wrap_exit(int status) { return; }], - [exit(0);])]) -# Not having ld wrap when unit testing has been explicitly requested is an error -if test "x$enable_unit_tests" = x"yes" -a "x$1" != "xoptional"; then - if test "x$have_ld_wrap" = x"no"; then - AC_MSG_ERROR([--enable-unit-tests=yes specified but ld -wrap support is not available]) - fi -fi -AM_CONDITIONAL([HAVE_LD_WRAP], [test "$have_ld_wrap" = yes]) -# -]) # XORG_LD_WRAP - -# XORG_CHECK_LINKER_FLAGS -# ----------------------- -# SYNOPSIS -# -# XORG_CHECK_LINKER_FLAGS(FLAGS, [ACTION-SUCCESS], [ACTION-FAILURE], [PROGRAM-SOURCE]) -# -# DESCRIPTION -# -# Check whether the given linker FLAGS work with the current language's -# linker, or whether they give an error. -# -# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on -# success/failure. -# -# PROGRAM-SOURCE is the program source to link with, if needed -# -# NOTE: Based on AX_CHECK_COMPILER_FLAGS. -# -# LICENSE -# -# Copyright (c) 2009 Mike Frysinger -# Copyright (c) 2009 Steven G. Johnson -# Copyright (c) 2009 Matteo Frigo -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well.# -AC_DEFUN([XORG_CHECK_LINKER_FLAGS], -[AC_MSG_CHECKING([whether the linker accepts $1]) -dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname: -AS_LITERAL_IF([$1], - [AC_CACHE_VAL(AS_TR_SH(xorg_cv_linker_flags_[$1]), [ - ax_save_FLAGS=$LDFLAGS - LDFLAGS="$1" - AC_LINK_IFELSE([m4_default([$4],[AC_LANG_PROGRAM()])], - AS_TR_SH(xorg_cv_linker_flags_[$1])=yes, - AS_TR_SH(xorg_cv_linker_flags_[$1])=no) - LDFLAGS=$ax_save_FLAGS])], - [ax_save_FLAGS=$LDFLAGS - LDFLAGS="$1" - AC_LINK_IFELSE([AC_LANG_PROGRAM()], - eval AS_TR_SH(xorg_cv_linker_flags_[$1])=yes, - eval AS_TR_SH(xorg_cv_linker_flags_[$1])=no) - LDFLAGS=$ax_save_FLAGS]) -eval xorg_check_linker_flags=$AS_TR_SH(xorg_cv_linker_flags_[$1]) -AC_MSG_RESULT($xorg_check_linker_flags) -if test "x$xorg_check_linker_flags" = xyes; then - m4_default([$2], :) -else - m4_default([$3], :) -fi -]) # XORG_CHECK_LINKER_FLAGS - -# XORG_MEMORY_CHECK_FLAGS -# ----------------------- -# Minimum version: 1.16.0 -# -# This macro attempts to find appropriate memory checking functionality -# for various platforms which unit testing code may use to catch various -# forms of memory allocation and access errors in testing. -# -# Interface to module: -# XORG_MALLOC_DEBUG_ENV - environment variables to set to enable debugging -# Usually added to TESTS_ENVIRONMENT in Makefile.am -# -# If the user sets the value of XORG_MALLOC_DEBUG_ENV, it is used verbatim. -# -AC_DEFUN([XORG_MEMORY_CHECK_FLAGS],[ - -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_ARG_VAR([XORG_MALLOC_DEBUG_ENV], - [Environment variables to enable memory checking in tests]) - -# Check for different types of support on different platforms -case $host_os in - solaris*) - AC_CHECK_LIB([umem], [umem_alloc], - [malloc_debug_env='LD_PRELOAD=libumem.so UMEM_DEBUG=default']) - ;; - *-gnu*) # GNU libc - Value is used as a single byte bit pattern, - # both directly and inverted, so should not be 0 or 255. - malloc_debug_env='MALLOC_PERTURB_=15' - ;; - darwin*) - malloc_debug_env='MallocPreScribble=1 MallocScribble=1 DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib' - ;; - *bsd*) - malloc_debug_env='MallocPreScribble=1 MallocScribble=1' - ;; -esac - -# User supplied flags override default flags -if test "x$XORG_MALLOC_DEBUG_ENV" != "x"; then - malloc_debug_env="$XORG_MALLOC_DEBUG_ENV" -fi - -AC_SUBST([XORG_MALLOC_DEBUG_ENV],[$malloc_debug_env]) -]) # XORG_WITH_LINT - -# XORG_CHECK_MALLOC_ZERO -# ---------------------- -# Minimum version: 1.0.0 -# -# Defines {MALLOC,XMALLOC,XTMALLOC}_ZERO_CFLAGS appropriately if -# malloc(0) returns NULL. Packages should add one of these cflags to -# their AM_CFLAGS (or other appropriate *_CFLAGS) to use them. -# -# No longer actually tests since there is no guarantee applications will -# run with the same malloc implementation we tested against, and the cost -# of always ensuring the size passed to malloc is non-zero is minimal now. -# Still allows builders to override when they have complete control over -# which malloc implementation will be used. -AC_DEFUN([XORG_CHECK_MALLOC_ZERO],[ -AC_ARG_ENABLE(malloc0returnsnull, - AS_HELP_STRING([--enable-malloc0returnsnull], - [assume malloc(0) can return NULL (default: yes)]), - [MALLOC_ZERO_RETURNS_NULL=$enableval], - [MALLOC_ZERO_RETURNS_NULL=yes]) - -AC_MSG_CHECKING([whether to act as if malloc(0) can return NULL]) -AC_MSG_RESULT([$MALLOC_ZERO_RETURNS_NULL]) - -if test "x$MALLOC_ZERO_RETURNS_NULL" = xyes; then - MALLOC_ZERO_CFLAGS="-DMALLOC_0_RETURNS_NULL" - XMALLOC_ZERO_CFLAGS=$MALLOC_ZERO_CFLAGS - XTMALLOC_ZERO_CFLAGS="$MALLOC_ZERO_CFLAGS -DXTMALLOC_BC" -else - MALLOC_ZERO_CFLAGS="" - XMALLOC_ZERO_CFLAGS="" - XTMALLOC_ZERO_CFLAGS="" -fi - -AC_SUBST([MALLOC_ZERO_CFLAGS]) -AC_SUBST([XMALLOC_ZERO_CFLAGS]) -AC_SUBST([XTMALLOC_ZERO_CFLAGS]) -]) # XORG_CHECK_MALLOC_ZERO - -# XORG_WITH_LINT() -# ---------------- -# Minimum version: 1.1.0 -# -# This macro enables the use of a tool that flags some suspicious and -# non-portable constructs (likely to be bugs) in C language source code. -# It will attempt to locate the tool and use appropriate options. -# There are various lint type tools on different platforms. -# -# Interface to module: -# LINT: returns the path to the tool found on the platform -# or the value set to LINT on the configure cmd line -# also an Automake conditional -# LINT_FLAGS: an Automake variable with appropriate flags -# -# --with-lint: 'yes' user instructs the module to use lint -# 'no' user instructs the module not to use lint (default) -# -# If the user sets the value of LINT, AC_PATH_PROG skips testing the path. -# If the user sets the value of LINT_FLAGS, they are used verbatim. -# -AC_DEFUN([XORG_WITH_LINT],[ - -AC_ARG_VAR([LINT], [Path to a lint-style command]) -AC_ARG_VAR([LINT_FLAGS], [Flags for the lint-style command]) -AC_ARG_WITH(lint, [AS_HELP_STRING([--with-lint], - [Use a lint-style source code checker (default: disabled)])], - [use_lint=$withval], [use_lint=no]) - -# Obtain platform specific info like program name and options -# The lint program on FreeBSD and NetBSD is different from the one on Solaris -case $host_os in - *linux* | *openbsd* | kfreebsd*-gnu | darwin* | cygwin*) - lint_name=splint - lint_options="-badflag" - ;; - *freebsd* | *netbsd*) - lint_name=lint - lint_options="-u -b" - ;; - *solaris*) - lint_name=lint - lint_options="-u -b -h -erroff=E_INDISTING_FROM_TRUNC2" - ;; -esac - -# Test for the presence of the program (either guessed by the code or spelled out by the user) -if test "x$use_lint" = x"yes" ; then - AC_PATH_PROG([LINT], [$lint_name]) - if test "x$LINT" = "x"; then - AC_MSG_ERROR([--with-lint=yes specified but lint-style tool not found in PATH]) - fi -elif test "x$use_lint" = x"no" ; then - if test "x$LINT" != "x"; then - AC_MSG_WARN([ignoring LINT environment variable since --with-lint=no was specified]) - fi -else - AC_MSG_ERROR([--with-lint expects 'yes' or 'no'. Use LINT variable to specify path.]) -fi - -# User supplied flags override default flags -if test "x$LINT_FLAGS" != "x"; then - lint_options=$LINT_FLAGS -fi - -AC_SUBST([LINT_FLAGS],[$lint_options]) -AM_CONDITIONAL(LINT, [test "x$LINT" != x]) - -]) # XORG_WITH_LINT - -# XORG_LINT_LIBRARY(LIBNAME) -# -------------------------- -# Minimum version: 1.1.0 -# -# Sets up flags for building lint libraries for checking programs that call -# functions in the library. -# -# Interface to module: -# LINTLIB - Automake variable with the name of lint library file to make -# MAKE_LINT_LIB - Automake conditional -# -# --enable-lint-library: - 'yes' user instructs the module to created a lint library -# - 'no' user instructs the module not to create a lint library (default) - -AC_DEFUN([XORG_LINT_LIBRARY],[ -AC_REQUIRE([XORG_WITH_LINT]) -AC_ARG_ENABLE(lint-library, [AS_HELP_STRING([--enable-lint-library], - [Create lint library (default: disabled)])], - [make_lint_lib=$enableval], [make_lint_lib=no]) - -if test "x$make_lint_lib" = x"yes" ; then - LINTLIB=llib-l$1.ln - if test "x$LINT" = "x"; then - AC_MSG_ERROR([Cannot make lint library without --with-lint]) - fi -elif test "x$make_lint_lib" != x"no" ; then - AC_MSG_ERROR([--enable-lint-library expects 'yes' or 'no'.]) -fi - -AC_SUBST(LINTLIB) -AM_CONDITIONAL(MAKE_LINT_LIB, [test x$make_lint_lib != xno]) - -]) # XORG_LINT_LIBRARY - -# XORG_COMPILER_BRAND -# ------------------- -# Minimum version: 1.14.0 -# -# Checks for various brands of compilers and sets flags as appropriate: -# GNU gcc - relies on AC_PROG_CC (via AC_PROG_CC_C99) to set GCC to "yes" -# GNU g++ - relies on AC_PROG_CXX to set GXX to "yes" -# clang compiler - sets CLANGCC to "yes" -# Intel compiler - sets INTELCC to "yes" -# Sun/Oracle Solaris Studio cc - sets SUNCC to "yes" -# -AC_DEFUN([XORG_COMPILER_BRAND], [ -AC_LANG_CASE( - [C], [ - dnl autoconf-2.70 folded AC_PROG_CC_C99 into AC_PROG_CC - dnl and complains that AC_PROG_CC_C99 is obsolete - m4_version_prereq([2.70], - [AC_REQUIRE([AC_PROG_CC])], - [AC_REQUIRE([AC_PROG_CC_C99])]) - ], - [C++], [ - AC_REQUIRE([AC_PROG_CXX]) - ] -) -AC_CHECK_DECL([__clang__], [CLANGCC="yes"], [CLANGCC="no"]) -AC_CHECK_DECL([__INTEL_COMPILER], [INTELCC="yes"], [INTELCC="no"]) -AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"]) -]) # XORG_COMPILER_BRAND - -# XORG_TESTSET_CFLAG(, , [, ...]) -# --------------- -# Minimum version: 1.16.0 -# -# Test if the compiler works when passed the given flag as a command line argument. -# If it succeeds, the flag is appended to the given variable. If not, it tries the -# next flag in the list until there are no more options. -# -# Note that this does not guarantee that the compiler supports the flag as some -# compilers will simply ignore arguments that they do not understand, but we do -# attempt to weed out false positives by using -Werror=unknown-warning-option and -# -Werror=unused-command-line-argument -# -AC_DEFUN([XORG_TESTSET_CFLAG], [ -m4_if([$#], 0, [m4_fatal([XORG_TESTSET_CFLAG was given with an unsupported number of arguments])]) -m4_if([$#], 1, [m4_fatal([XORG_TESTSET_CFLAG was given with an unsupported number of arguments])]) - -AC_LANG_COMPILER_REQUIRE - -AC_LANG_CASE( - [C], [ - dnl autoconf-2.70 folded AC_PROG_CC_C99 into AC_PROG_CC - dnl and complains that AC_PROG_CC_C99 is obsolete - m4_version_prereq([2.70], - [AC_REQUIRE([AC_PROG_CC])], - [AC_REQUIRE([AC_PROG_CC_C99])]) - define([PREFIX], [C]) - define([CACHE_PREFIX], [cc]) - define([COMPILER], [$CC]) - ], - [C++], [ - define([PREFIX], [CXX]) - define([CACHE_PREFIX], [cxx]) - define([COMPILER], [$CXX]) - ] -) - -[xorg_testset_save_]PREFIX[FLAGS]="$PREFIX[FLAGS]" - -if test "x$[xorg_testset_]CACHE_PREFIX[_unknown_warning_option]" = "x" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unknown-warning-option" - AC_CACHE_CHECK([if ]COMPILER[ supports -Werror=unknown-warning-option], - [xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option], - AC_COMPILE_IFELSE([AC_LANG_SOURCE([int i;])], - [xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option=yes], - [xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option=no])) - [xorg_testset_]CACHE_PREFIX[_unknown_warning_option]=$[xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option] - PREFIX[FLAGS]="$[xorg_testset_save_]PREFIX[FLAGS]" -fi - -if test "x$[xorg_testset_]CACHE_PREFIX[_unused_command_line_argument]" = "x" ; then - if test "x$[xorg_testset_]CACHE_PREFIX[_unknown_warning_option]" = "xyes" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unknown-warning-option" - fi - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unused-command-line-argument" - AC_CACHE_CHECK([if ]COMPILER[ supports -Werror=unused-command-line-argument], - [xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument], - AC_COMPILE_IFELSE([AC_LANG_SOURCE([int i;])], - [xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument=yes], - [xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument=no])) - [xorg_testset_]CACHE_PREFIX[_unused_command_line_argument]=$[xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument] - PREFIX[FLAGS]="$[xorg_testset_save_]PREFIX[FLAGS]" -fi - -found="no" -m4_foreach([flag], m4_cdr($@), [ - if test $found = "no" ; then - if test "x$xorg_testset_]CACHE_PREFIX[_unknown_warning_option" = "xyes" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_]CACHE_PREFIX[_unused_command_line_argument" = "xyes" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unused-command-line-argument" - fi - - PREFIX[FLAGS]="$PREFIX[FLAGS] ]flag[" - -dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname - AC_MSG_CHECKING([if ]COMPILER[ supports ]flag[]) - cacheid=AS_TR_SH([xorg_cv_]CACHE_PREFIX[_flag_]flag[]) - AC_CACHE_VAL($cacheid, - [AC_LINK_IFELSE([AC_LANG_PROGRAM([int i;])], - [eval $cacheid=yes], - [eval $cacheid=no])]) - - PREFIX[FLAGS]="$[xorg_testset_save_]PREFIX[FLAGS]" - - eval supported=\$$cacheid - AC_MSG_RESULT([$supported]) - if test "$supported" = "yes" ; then - $1="$$1 ]flag[" - found="yes" - fi - fi -]) -]) # XORG_TESTSET_CFLAG - -# XORG_COMPILER_FLAGS -# --------------- -# Minimum version: 1.16.0 -# -# Defines BASE_CFLAGS or BASE_CXXFLAGS to contain a set of command line -# arguments supported by the selected compiler which do NOT alter the generated -# code. These arguments will cause the compiler to print various warnings -# during compilation AND turn a conservative set of warnings into errors. -# -# The set of flags supported by BASE_CFLAGS and BASE_CXXFLAGS will grow in -# future versions of util-macros as options are added to new compilers. -# -AC_DEFUN([XORG_COMPILER_FLAGS], [ -AC_REQUIRE([XORG_COMPILER_BRAND]) - -AC_ARG_ENABLE(selective-werror, - AS_HELP_STRING([--disable-selective-werror], - [Turn off selective compiler errors. (default: enabled)]), - [SELECTIVE_WERROR=$enableval], - [SELECTIVE_WERROR=yes]) - -AC_LANG_CASE( - [C], [ - define([PREFIX], [C]) - ], - [C++], [ - define([PREFIX], [CXX]) - ] -) -# -v is too short to test reliably with XORG_TESTSET_CFLAG -if test "x$SUNCC" = "xyes"; then - [BASE_]PREFIX[FLAGS]="-v" -else - [BASE_]PREFIX[FLAGS]="" -fi - -# This chunk of warnings were those that existed in the legacy CWARNFLAGS -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wall]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wpointer-arith]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-declarations]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wformat=2], [-Wformat]) - -AC_LANG_CASE( - [C], [ - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wstrict-prototypes]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-prototypes]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wnested-externs]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wbad-function-cast]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wold-style-definition], [-fd]) - ] -) - -# This chunk adds additional warnings that could catch undesired effects. -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wunused]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wuninitialized]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wshadow]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-noreturn]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-format-attribute]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wredundant-decls]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wlogical-op]) - -# These are currently disabled because they are noisy. They will be enabled -# in the future once the codebase is sufficiently modernized to silence -# them. For now, I don't want them to drown out the other warnings. -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wparentheses]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-align]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-qual]) - -# Turn some warnings into errors, so we don't accidentally get successful builds -# when there are problems that should be fixed. - -if test "x$SELECTIVE_WERROR" = "xyes" ; then -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=implicit], [-errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=nonnull]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=init-self]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=main]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=missing-braces]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=sequence-point]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=return-type], [-errwarn=E_FUNC_HAS_NO_RETURN_STMT]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=trigraphs]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=array-bounds]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=write-strings]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=address]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=int-to-pointer-cast], [-errwarn=E_BAD_PTR_INT_COMBINATION]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=pointer-to-int-cast]) # Also -errwarn=E_BAD_PTR_INT_COMBINATION -else -AC_MSG_WARN([You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wimplicit]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wnonnull]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Winit-self]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmain]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-braces]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wsequence-point]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wreturn-type]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wtrigraphs]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Warray-bounds]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wwrite-strings]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Waddress]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wint-to-pointer-cast]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wpointer-to-int-cast]) -fi - -AC_SUBST([BASE_]PREFIX[FLAGS]) -]) # XORG_COMPILER_FLAGS - -# XORG_CWARNFLAGS -# --------------- -# Minimum version: 1.2.0 -# Deprecated since: 1.16.0 (Use XORG_COMPILER_FLAGS instead) -# -# Defines CWARNFLAGS to enable C compiler warnings. -# -# This function is deprecated because it defines -fno-strict-aliasing -# which alters the code generated by the compiler. If -fno-strict-aliasing -# is needed, then it should be added explicitly in the module when -# it is updated to use BASE_CFLAGS. -# -AC_DEFUN([XORG_CWARNFLAGS], [ -AC_REQUIRE([XORG_COMPILER_FLAGS]) -AC_REQUIRE([XORG_COMPILER_BRAND]) -AC_LANG_CASE( - [C], [ - CWARNFLAGS="$BASE_CFLAGS" - if test "x$GCC" = xyes ; then - CWARNFLAGS="$CWARNFLAGS -fno-strict-aliasing" - fi - AC_SUBST(CWARNFLAGS) - ] -) -]) # XORG_CWARNFLAGS - -# XORG_STRICT_OPTION -# ----------------------- -# Minimum version: 1.3.0 -# -# Add configure option to enable strict compilation flags, such as treating -# warnings as fatal errors. -# If --enable-strict-compilation is passed to configure, adds strict flags to -# $BASE_CFLAGS or $BASE_CXXFLAGS and the deprecated $CWARNFLAGS. -# -# Starting in 1.14.0 also exports $STRICT_CFLAGS for use in other tests or -# when strict compilation is unconditionally desired. -AC_DEFUN([XORG_STRICT_OPTION], [ -AC_REQUIRE([XORG_CWARNFLAGS]) -AC_REQUIRE([XORG_COMPILER_FLAGS]) - -AC_ARG_ENABLE(strict-compilation, - AS_HELP_STRING([--enable-strict-compilation], - [Enable all warnings from compiler and make them errors (default: disabled)]), - [STRICT_COMPILE=$enableval], [STRICT_COMPILE=no]) - -AC_LANG_CASE( - [C], [ - define([PREFIX], [C]) - ], - [C++], [ - define([PREFIX], [CXX]) - ] -) - -[STRICT_]PREFIX[FLAGS]="" -XORG_TESTSET_CFLAG([[STRICT_]PREFIX[FLAGS]], [-pedantic]) -XORG_TESTSET_CFLAG([[STRICT_]PREFIX[FLAGS]], [-Werror], [-errwarn]) - -# Earlier versions of gcc (eg: 4.2) support -Werror=attributes, but do not -# activate it with -Werror, so we add it here explicitly. -XORG_TESTSET_CFLAG([[STRICT_]PREFIX[FLAGS]], [-Werror=attributes]) - -if test "x$STRICT_COMPILE" = "xyes"; then - [BASE_]PREFIX[FLAGS]="$[BASE_]PREFIX[FLAGS] $[STRICT_]PREFIX[FLAGS]" - AC_LANG_CASE([C], [CWARNFLAGS="$CWARNFLAGS $STRICT_CFLAGS"]) -fi -AC_SUBST([STRICT_]PREFIX[FLAGS]) -AC_SUBST([BASE_]PREFIX[FLAGS]) -AC_LANG_CASE([C], AC_SUBST([CWARNFLAGS])) -]) # XORG_STRICT_OPTION - -# XORG_DEFAULT_NOCODE_OPTIONS -# --------------------------- -# Minimum version: 1.20.0 -# -# Defines default options for X.Org modules which don't compile code, -# such as fonts, bitmaps, cursors, and docs. -# -AC_DEFUN([XORG_DEFAULT_NOCODE_OPTIONS], [ -AC_REQUIRE([AC_PROG_INSTALL]) -XORG_RELEASE_VERSION -XORG_CHANGELOG -XORG_INSTALL -XORG_MANPAGE_SECTIONS -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], - [AC_SUBST([AM_DEFAULT_VERBOSITY], [1])]) -]) # XORG_DEFAULT_NOCODE_OPTIONS - -# XORG_DEFAULT_OPTIONS -# -------------------- -# Minimum version: 1.3.0 -# -# Defines default options for X.Org modules which compile code. -# -AC_DEFUN([XORG_DEFAULT_OPTIONS], [ -AC_REQUIRE([AC_PROG_INSTALL]) -XORG_COMPILER_FLAGS -XORG_CWARNFLAGS -XORG_STRICT_OPTION -XORG_DEFAULT_NOCODE_OPTIONS -]) # XORG_DEFAULT_OPTIONS - -# XORG_INSTALL() -# ---------------- -# Minimum version: 1.4.0 -# -# Defines the variable INSTALL_CMD as the command to copy -# INSTALL from $prefix/share/util-macros. -# -AC_DEFUN([XORG_INSTALL], [ -AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -macros_datadir=`$PKG_CONFIG --print-errors --variable=pkgdatadir xorg-macros` -INSTALL_CMD="(cp -f "$macros_datadir/INSTALL" \$(top_srcdir)/.INSTALL.tmp && \ -mv \$(top_srcdir)/.INSTALL.tmp \$(top_srcdir)/INSTALL) \ -|| (rm -f \$(top_srcdir)/.INSTALL.tmp; test -e \$(top_srcdir)/INSTALL || ( \ -touch \$(top_srcdir)/INSTALL; \ -echo 'failed to copy INSTALL from util-macros: installing empty INSTALL.' >&2))" -AC_SUBST([INSTALL_CMD]) -]) # XORG_INSTALL -dnl Copyright 2005 Red Hat, Inc -dnl -dnl Permission to use, copy, modify, distribute, and sell this software and its -dnl documentation for any purpose is hereby granted without fee, provided that -dnl the above copyright notice appear in all copies and that both that -dnl copyright notice and this permission notice appear in supporting -dnl documentation. -dnl -dnl The above copyright notice and this permission notice shall be included -dnl in all copies or substantial portions of the Software. -dnl -dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -dnl OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -dnl MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -dnl IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR -dnl OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -dnl ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -dnl OTHER DEALINGS IN THE SOFTWARE. -dnl -dnl Except as contained in this notice, the name of the copyright holders shall -dnl not be used in advertising or otherwise to promote the sale, use or -dnl other dealings in this Software without prior written authorization -dnl from the copyright holders. -dnl - -# XORG_RELEASE_VERSION -# -------------------- -# Defines PACKAGE_VERSION_{MAJOR,MINOR,PATCHLEVEL} for modules to use. - -AC_DEFUN([XORG_RELEASE_VERSION],[ - AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MAJOR], - [`echo $PACKAGE_VERSION | cut -d . -f 1`], - [Major version of this package]) - PVM=`echo $PACKAGE_VERSION | cut -d . -f 2 | cut -d - -f 1` - if test "x$PVM" = "x"; then - PVM="0" - fi - AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MINOR], - [$PVM], - [Minor version of this package]) - PVP=`echo $PACKAGE_VERSION | cut -d . -f 3 | cut -d - -f 1` - if test "x$PVP" = "x"; then - PVP="0" - fi - AC_DEFINE_UNQUOTED([PACKAGE_VERSION_PATCHLEVEL], - [$PVP], - [Patch version of this package]) -]) - -# XORG_CHANGELOG() -# ---------------- -# Minimum version: 1.2.0 -# -# Defines the variable CHANGELOG_CMD as the command to generate -# ChangeLog from git. -# -# -AC_DEFUN([XORG_CHANGELOG], [ -CHANGELOG_CMD="((GIT_DIR=\$(top_srcdir)/.git git log > \$(top_srcdir)/.changelog.tmp) 2>/dev/null && \ -mv \$(top_srcdir)/.changelog.tmp \$(top_srcdir)/ChangeLog) \ -|| (rm -f \$(top_srcdir)/.changelog.tmp; test -e \$(top_srcdir)/ChangeLog || ( \ -touch \$(top_srcdir)/ChangeLog; \ -echo 'git failed to create ChangeLog: installing empty ChangeLog.' >&2))" -AC_SUBST([CHANGELOG_CMD]) -]) # XORG_CHANGELOG - -# Copyright (C) 2002-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_AUTOMAKE_VERSION(VERSION) -# ---------------------------- -# Automake X.Y traces this macro to ensure aclocal.m4 has been -# generated from the m4 files accompanying Automake X.Y. -# (This private macro should not be called outside this file.) -AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.18' -dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to -dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.18.1], [], - [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl -]) - -# _AM_AUTOCONF_VERSION(VERSION) -# ----------------------------- -# aclocal traces this macro to find the Autoconf version. -# This is a private macro too. Using m4_define simplifies -# the logic in aclocal, which can simply ignore this definition. -m4_define([_AM_AUTOCONF_VERSION], []) - -# AM_SET_CURRENT_AUTOMAKE_VERSION -# ------------------------------- -# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. -# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. -AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.18.1])dnl -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) - -# AM_AUX_DIR_EXPAND -*- Autoconf -*- - -# Copyright (C) 2001-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets -# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to -# '$srcdir', '$srcdir/..', or '$srcdir/../..'. -# -# Of course, Automake must honor this variable whenever it calls a -# tool from the auxiliary directory. The problem is that $srcdir (and -# therefore $ac_aux_dir as well) can be either absolute or relative, -# depending on how configure is run. This is pretty annoying, since -# it makes $ac_aux_dir quite unusable in subdirectories: in the top -# source directory, any form will work fine, but in subdirectories a -# relative path needs to be adjusted first. -# -# $ac_aux_dir/missing -# fails when called from a subdirectory if $ac_aux_dir is relative -# $top_srcdir/$ac_aux_dir/missing -# fails if $ac_aux_dir is absolute, -# fails when called from a subdirectory in a VPATH build with -# a relative $ac_aux_dir -# -# The reason of the latter failure is that $top_srcdir and $ac_aux_dir -# are both prefixed by $srcdir. In an in-source build this is usually -# harmless because $srcdir is '.', but things will broke when you -# start a VPATH build or use an absolute $srcdir. -# -# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, -# iff we strip the leading $srcdir from $ac_aux_dir. That would be: -# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` -# and then we would define $MISSING as -# MISSING="\${SHELL} $am_aux_dir/missing" -# This will work as long as MISSING is not called from configure, because -# unfortunately $(top_srcdir) has no meaning in configure. -# However there are other variables, like CC, which are often used in -# configure, and could therefore not use this "fixed" $ac_aux_dir. -# -# Another solution, used here, is to always expand $ac_aux_dir to an -# absolute PATH. The drawback is that using absolute paths prevent a -# configured tree to be moved without reconfiguration. - -AC_DEFUN([AM_AUX_DIR_EXPAND], -[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` -]) - -# AM_CONDITIONAL -*- Autoconf -*- - -# Copyright (C) 1997-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_CONDITIONAL(NAME, SHELL-CONDITION) -# ------------------------------------- -# Define a conditional. -AC_DEFUN([AM_CONDITIONAL], -[AC_PREREQ([2.52])dnl - m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -m4_define([_AM_COND_VALUE_$1], [$2])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) - -# Copyright (C) 1999-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - - -# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be -# written in clear, in which case automake, when reading aclocal.m4, -# will think it sees a *use*, and therefore will trigger all it's -# C support machinery. Also note that it means that autoscan, seeing -# CC etc. in the Makefile, will ask for an AC_PROG_CC use... - - -# _AM_DEPENDENCIES(NAME) -# ---------------------- -# See how the compiler implements dependency checking. -# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". -# We try a few techniques and use that to set a single cache variable. -# -# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was -# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular -# dependency, and given that the user is not expected to run this macro, -# just rely on AC_PROG_CC. -AC_DEFUN([_AM_DEPENDENCIES], -[AC_REQUIRE([AM_SET_DEPDIR])dnl -AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl -AC_REQUIRE([AM_MAKE_INCLUDE])dnl -AC_REQUIRE([AM_DEP_TRACK])dnl - -m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], - [$1], [CXX], [depcc="$CXX" am_compiler_list=], - [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], - [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], - [$1], [UPC], [depcc="$UPC" am_compiler_list=], - [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], - [depcc="$$1" am_compiler_list=]) - -AC_CACHE_CHECK([dependency style of $depcc], - [am_cv_$1_dependencies_compiler_type], -[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_$1_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` - fi - am__universal=false - m4_case([$1], [CC], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac], - [CXX], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac]) - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thus: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_$1_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_$1_dependencies_compiler_type=none -fi -]) -AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) -AM_CONDITIONAL([am__fastdep$1], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) -]) - - -# AM_SET_DEPDIR -# ------------- -# Choose a directory name for dependency files. -# This macro is AC_REQUIREd in _AM_DEPENDENCIES. -AC_DEFUN([AM_SET_DEPDIR], -[AC_REQUIRE([AM_SET_LEADING_DOT])dnl -AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl -]) - - -# AM_DEP_TRACK -# ------------ -AC_DEFUN([AM_DEP_TRACK], -[AC_ARG_ENABLE([dependency-tracking], [dnl -AS_HELP_STRING( - [--enable-dependency-tracking], - [do not reject slow dependency extractors]) -AS_HELP_STRING( - [--disable-dependency-tracking], - [speeds up one-time build])]) -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi -AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -AC_SUBST([AMDEPBACKSLASH])dnl -_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl -AC_SUBST([am__nodep])dnl -_AM_SUBST_NOTMAKE([am__nodep])dnl -]) - -# Generate code to set up dependency tracking. -*- Autoconf -*- - -# Copyright (C) 1999-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_OUTPUT_DEPENDENCY_COMMANDS -# ------------------------------ -AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], -[{ - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - AS_CASE([$CONFIG_FILES], - [*\'*], [eval set x "$CONFIG_FILES"], - [*], [set x $CONFIG_FILES]) - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`AS_DIRNAME(["$am_mf"])` - am_filepart=`AS_BASENAME(["$am_mf"])` - AM_RUN_LOG([cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles]) || am_rc=$? - done - if test $am_rc -ne 0; then - AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE="gmake" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking).]) - fi - AS_UNSET([am_dirpart]) - AS_UNSET([am_filepart]) - AS_UNSET([am_mf]) - AS_UNSET([am_rc]) - rm -f conftest-deps.mk -} -])# _AM_OUTPUT_DEPENDENCY_COMMANDS - - -# AM_OUTPUT_DEPENDENCY_COMMANDS -# ----------------------------- -# This macro should only be invoked once -- use via AC_REQUIRE. -# -# This code is only required when automatic dependency tracking is enabled. -# This creates each '.Po' and '.Plo' makefile fragment that we'll need in -# order to bootstrap the dependency handling code. -AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], -[AC_CONFIG_COMMANDS([depfiles], - [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) - -# Do all the work for Automake. -*- Autoconf -*- - -# Copyright (C) 1996-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This macro actually does too much. Some checks are only needed if -# your package does certain things. But this isn't really a big deal. - -dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. -m4_define([AC_PROG_CC], -m4_defn([AC_PROG_CC]) -[_AM_PROG_CC_C_O -]) - -# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) -# AM_INIT_AUTOMAKE([OPTIONS]) -# ----------------------------------------------- -# The call with PACKAGE and VERSION arguments is the old style -# call (pre autoconf-2.50), which is being phased out. PACKAGE -# and VERSION should now be passed to AC_INIT and removed from -# the call to AM_INIT_AUTOMAKE. -# We support both call styles for the transition. After -# the next Automake release, Autoconf can make the AC_INIT -# arguments mandatory, and then we can depend on a new Autoconf -# release and drop the old call support. -AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_PREREQ([2.65])dnl -m4_ifdef([_$0_ALREADY_INIT], - [m4_fatal([$0 expanded multiple times -]m4_defn([_$0_ALREADY_INIT]))], - [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl -dnl Autoconf wants to disallow AM_ names. We explicitly allow -dnl the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl -AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl -AC_REQUIRE([AC_PROG_INSTALL])dnl -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[AC_DIAGNOSE([obsolete], - [$0: two- and three-arguments forms are deprecated.]) -m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl -dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. -m4_if( - m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), - [ok:ok],, - [m4_fatal([AC_INIT should be called with package and version arguments])])dnl - AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl - AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) - AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) -AM_MISSING_PROG([AUTOCONF], [autoconf]) -AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) -AM_MISSING_PROG([AUTOHEADER], [autoheader]) -AM_MISSING_PROG([MAKEINFO], [makeinfo]) -AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl -AC_REQUIRE([AC_PROG_MKDIR_P])dnl -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl -AC_REQUIRE([AM_SET_LEADING_DOT])dnl -_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], - [_AM_PROG_TAR([ustar])])])]) -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES([CC])], - [m4_define([AC_PROG_CC], - m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES([CXX])], - [m4_define([AC_PROG_CXX], - m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES([OBJC])], - [m4_define([AC_PROG_OBJC], - m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], - [_AM_DEPENDENCIES([OBJCXX])], - [m4_define([AC_PROG_OBJCXX], - m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl -]) -# Variables for tags utilities; see am/tags.am -if test -z "$CTAGS"; then - CTAGS=ctags -fi -AC_SUBST([CTAGS]) -if test -z "$ETAGS"; then - ETAGS=etags -fi -AC_SUBST([ETAGS]) -if test -z "$CSCOPE"; then - CSCOPE=cscope -fi -AC_SUBST([CSCOPE]) - -AC_REQUIRE([_AM_SILENT_RULES])dnl -dnl The testsuite driver may need to know about EXEEXT, so add the -dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This -dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. -AC_CONFIG_COMMANDS_PRE(dnl -[m4_provide_if([_AM_COMPILER_EXEEXT], - [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl - -AC_REQUIRE([_AM_PROG_RM_F]) -AC_REQUIRE([_AM_PROG_XARGS_N]) - -dnl The trailing newline in this macro's definition is deliberate, for -dnl backward compatibility and to allow trailing 'dnl'-style comments -dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. -]) - -dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not -dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further -dnl mangled by Autoconf and run in a shell conditional statement. -m4_define([_AC_COMPILER_EXEEXT], -m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) - -# When config.status generates a header, we must update the stamp-h file. -# This file resides in the same directory as the config header -# that is generated. The stamp files are numbered to have different names. - -# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the -# loop where config.status creates the headers, so we can generate -# our stamp files there. -AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], -[# Compute $1's index in $config_headers. -_am_arg=$1 -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) - -# Copyright (C) 2001-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_SH -# ------------------ -# Define $install_sh. -AC_DEFUN([AM_PROG_INSTALL_SH], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi -AC_SUBST([install_sh])]) - -# Copyright (C) 2003-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# Check whether the underlying file-system supports filenames -# with a leading dot. For instance MS-DOS doesn't. -AC_DEFUN([AM_SET_LEADING_DOT], -[rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null -AC_SUBST([am__leading_dot])]) - -# Check to see how 'make' treats includes. -*- Autoconf -*- - -# Copyright (C) 2001-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_MAKE_INCLUDE() -# ----------------- -# Check whether make has an 'include' directive that can support all -# the idioms we need for our automatic dependency tracking code. -AC_DEFUN([AM_MAKE_INCLUDE], -[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) -cat > confinc.mk << 'END' -am__doit: - @echo this is the am__doit target >confinc.out -.PHONY: am__doit -END -am__include="#" -am__quote= -# BSD make does it like this. -echo '.include "confinc.mk" # ignored' > confmf.BSD -# Other make implementations (GNU, Solaris 10, AIX) do it like this. -echo 'include confinc.mk # ignored' > confmf.GNU -_am_result=no -for s in GNU BSD; do - AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) - AS_CASE([$?:`cat confinc.out 2>/dev/null`], - ['0:this is the am__doit target'], - [AS_CASE([$s], - [BSD], [am__include='.include' am__quote='"'], - [am__include='include' am__quote=''])]) - if test "$am__include" != "#"; then - _am_result="yes ($s style)" - break - fi -done -rm -f confinc.* confmf.* -AC_MSG_RESULT([${_am_result}]) -AC_SUBST([am__include])]) -AC_SUBST([am__quote])]) - -# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- - -# Copyright (C) 1997-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_MISSING_PROG(NAME, PROGRAM) -# ------------------------------ -AC_DEFUN([AM_MISSING_PROG], -[AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) - -# AM_MISSING_HAS_RUN -# ------------------ -# Define MISSING if not defined so far and test if it is modern enough. -# If it is, set am_missing_run to use it, otherwise, to nothing. -AC_DEFUN([AM_MISSING_HAS_RUN], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([missing])dnl -if test x"${MISSING+set}" != xset; then - MISSING="\${SHELL} '$am_aux_dir/missing'" -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - AC_MSG_WARN(['missing' script is too old or missing]) -fi -]) - -# Helper functions for option handling. -*- Autoconf -*- - -# Copyright (C) 2001-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_MANGLE_OPTION(NAME) -# ----------------------- -AC_DEFUN([_AM_MANGLE_OPTION], -[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) - -# _AM_SET_OPTION(NAME) -# -------------------- -# Set option NAME. Presently that only means defining a flag for this option. -AC_DEFUN([_AM_SET_OPTION], -[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) - -# _AM_SET_OPTIONS(OPTIONS) -# ------------------------ -# OPTIONS is a space-separated list of Automake options. -AC_DEFUN([_AM_SET_OPTIONS], -[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) - -# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) -# ------------------------------------------- -# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. -AC_DEFUN([_AM_IF_OPTION], -[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) - -# Copyright (C) 1999-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_PROG_CC_C_O -# --------------- -# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC -# to automatically call this. -AC_DEFUN([_AM_PROG_CC_C_O], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([compile])dnl -AC_LANG_PUSH([C])dnl -AC_CACHE_CHECK( - [whether $CC understands -c and -o together], - [am_cv_prog_cc_c_o], - [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - # aligned with autoconf, so not including core; see bug#72225. - rm -f -r a.out a.exe b.out conftest.$ac_ext conftest.$ac_objext \ - conftest.dSYM conftest1.$ac_ext conftest1.$ac_objext conftest1.dSYM \ - conftest2.$ac_ext conftest2.$ac_objext conftest2.dSYM - unset am_i]) -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -AC_LANG_POP([C])]) - -# For backward compatibility. -AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) - -# Copyright (C) 2022-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_PROG_RM_F -# --------------- -# Check whether 'rm -f' without any arguments works. -# https://bugs.gnu.org/10828 -AC_DEFUN([_AM_PROG_RM_F], -[am__rm_f_notfound= -AS_IF([(rm -f && rm -fr && rm -rf) 2>/dev/null], [], [am__rm_f_notfound='""']) -AC_SUBST(am__rm_f_notfound) -]) - -# Copyright (C) 2001-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_RUN_LOG(COMMAND) -# ------------------- -# Run COMMAND, save the exit status in ac_status, and log it. -# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) -AC_DEFUN([AM_RUN_LOG], -[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD - ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - (exit $ac_status); }]) - -# Check to make sure that the build environment is sane. -*- Autoconf -*- - -# Copyright (C) 1996-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_SLEEP_FRACTIONAL_SECONDS -# ---------------------------- -AC_DEFUN([_AM_SLEEP_FRACTIONAL_SECONDS], [dnl -AC_CACHE_CHECK([whether sleep supports fractional seconds], - am_cv_sleep_fractional_seconds, [dnl -AS_IF([sleep 0.001 2>/dev/null], [am_cv_sleep_fractional_seconds=yes], - [am_cv_sleep_fractional_seconds=no]) -])]) - -# _AM_FILESYSTEM_TIMESTAMP_RESOLUTION -# ----------------------------------- -# Determine the filesystem's resolution for file modification -# timestamps. The coarsest we know of is FAT, with a resolution -# of only two seconds, even with the most recent "exFAT" extensions. -# The finest (e.g. ext4 with large inodes, XFS, ZFS) is one -# nanosecond, matching clock_gettime. However, it is probably not -# possible to delay execution of a shell script for less than one -# millisecond, due to process creation overhead and scheduling -# granularity, so we don't check for anything finer than that. (See below.) -AC_DEFUN([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION], [dnl -AC_REQUIRE([_AM_SLEEP_FRACTIONAL_SECONDS]) -AC_CACHE_CHECK([filesystem timestamp resolution], - am_cv_filesystem_timestamp_resolution, [dnl -# Default to the worst case. -am_cv_filesystem_timestamp_resolution=2 - -# Only try to go finer than 1 sec if sleep can do it. -# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, -# - 1 sec is not much of a win compared to 2 sec, and -# - it takes 2 seconds to perform the test whether 1 sec works. -# -# Instead, just use the default 2s on platforms that have 1s resolution, -# accept the extra 1s delay when using $sleep in the Automake tests, in -# exchange for not incurring the 2s delay for running the test for all -# packages. -# -am_try_resolutions= -if test "$am_cv_sleep_fractional_seconds" = yes; then - # Even a millisecond often causes a bunch of false positives, - # so just try a hundredth of a second. The time saved between .001 and - # .01 is not terribly consequential. - am_try_resolutions="0.01 0.1 $am_try_resolutions" -fi - -# In order to catch current-generation FAT out, we must *modify* files -# that already exist; the *creation* timestamp is finer. Use names -# that make ls -t sort them differently when they have equal -# timestamps than when they have distinct timestamps, keeping -# in mind that ls -t prints the *newest* file first. -rm -f conftest.ts? -: > conftest.ts1 -: > conftest.ts2 -: > conftest.ts3 - -# Make sure ls -t actually works. Do 'set' in a subshell so we don't -# clobber the current shell's arguments. (Outer-level square brackets -# are removed by m4; they're present so that m4 does not expand -# ; be careful, easy to get confused.) -if ( - set X `[ls -t conftest.ts[12]]` && - { - test "$[]*" != "X conftest.ts1 conftest.ts2" || - test "$[]*" != "X conftest.ts2 conftest.ts1"; - } -); then :; else - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - _AS_ECHO_UNQUOTED( - ["Bad output from ls -t: \"`[ls -t conftest.ts[12]]`\""], - [AS_MESSAGE_LOG_FD]) - AC_MSG_FAILURE([ls -t produces unexpected output. -Make sure there is not a broken ls alias in your environment.]) -fi - -for am_try_res in $am_try_resolutions; do - # Any one fine-grained sleep might happen to cross the boundary - # between two values of a coarser actual resolution, but if we do - # two fine-grained sleeps in a row, at least one of them will fall - # entirely within a coarse interval. - echo alpha > conftest.ts1 - sleep $am_try_res - echo beta > conftest.ts2 - sleep $am_try_res - echo gamma > conftest.ts3 - - # We assume that 'ls -t' will make use of high-resolution - # timestamps if the operating system supports them at all. - if (set X `ls -t conftest.ts?` && - test "$[]2" = conftest.ts3 && - test "$[]3" = conftest.ts2 && - test "$[]4" = conftest.ts1); then - # - # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, - # because we don't need to test make. - make_ok=true - if test $am_try_res != 1; then - # But if we've succeeded so far with a subsecond resolution, we - # have one more thing to check: make. It can happen that - # everything else supports the subsecond mtimes, but make doesn't; - # notably on macOS, which ships make 3.81 from 2006 (the last one - # released under GPLv2). https://bugs.gnu.org/68808 - # - # We test $MAKE if it is defined in the environment, else "make". - # It might get overridden later, but our hope is that in practice - # it does not matter: it is the system "make" which is (by far) - # the most likely to be broken, whereas if the user overrides it, - # probably they did so with a better, or at least not worse, make. - # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html - # - # Create a Makefile (real tab character here): - rm -f conftest.mk - echo 'conftest.ts1: conftest.ts2' >conftest.mk - echo ' touch conftest.ts2' >>conftest.mk - # - # Now, running - # touch conftest.ts1; touch conftest.ts2; make - # should touch ts1 because ts2 is newer. This could happen by luck, - # but most often, it will fail if make's support is insufficient. So - # test for several consecutive successes. - # - # (We reuse conftest.ts[12] because we still want to modify existing - # files, not create new ones, per above.) - n=0 - make=${MAKE-make} - until test $n -eq 3; do - echo one > conftest.ts1 - sleep $am_try_res - echo two > conftest.ts2 # ts2 should now be newer than ts1 - if $make -f conftest.mk | grep 'up to date' >/dev/null; then - make_ok=false - break # out of $n loop - fi - n=`expr $n + 1` - done - fi - # - if $make_ok; then - # Everything we know to check worked out, so call this resolution good. - am_cv_filesystem_timestamp_resolution=$am_try_res - break # out of $am_try_res loop - fi - # Otherwise, we'll go on to check the next resolution. - fi -done -rm -f conftest.ts? -# (end _am_filesystem_timestamp_resolution) -])]) - -# AM_SANITY_CHECK -# --------------- -AC_DEFUN([AM_SANITY_CHECK], -[AC_REQUIRE([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION]) -# This check should not be cached, as it may vary across builds of -# different projects. -AC_MSG_CHECKING([whether build environment is sane]) -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[[\\\"\#\$\&\'\`$am_lf]]*) - AC_MSG_RESULT([no]) - AC_MSG_ERROR([unsafe absolute working directory name]);; -esac -case $srcdir in - *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) - AC_MSG_RESULT([no]) - AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -am_build_env_is_sane=no -am_has_slept=no -rm -f conftest.file -for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[]*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - test "$[]2" = conftest.file - ); then - am_build_env_is_sane=yes - break - fi - # Just in case. - sleep "$am_cv_filesystem_timestamp_resolution" - am_has_slept=yes -done - -AC_MSG_RESULT([$am_build_env_is_sane]) -if test "$am_build_env_is_sane" = no; then - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi - -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -AS_IF([test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1],, [dnl - ( sleep "$am_cv_filesystem_timestamp_resolution" ) & - am_sleep_pid=$! -]) -AC_CONFIG_COMMANDS_PRE( - [AC_MSG_CHECKING([that generated files are newer than configure]) - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - AC_MSG_RESULT([done])]) -rm -f conftest.file -]) - -# Copyright (C) 2009-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_SILENT_RULES -# ---------------- -# Enable less verbose build rules support. -AC_DEFUN([_AM_SILENT_RULES], -[AM_DEFAULT_VERBOSITY=1 -AC_ARG_ENABLE([silent-rules], [dnl -AS_HELP_STRING( - [--enable-silent-rules], - [less verbose build output (undo: "make V=1")]) -AS_HELP_STRING( - [--disable-silent-rules], - [verbose build output (undo: "make V=0")])dnl -]) -dnl -dnl A few 'make' implementations (e.g., NonStop OS and NextStep) -dnl do not support nested variable expansions. -dnl See automake bug#9928 and bug#10237. -am_make=${MAKE-make} -AC_CACHE_CHECK([whether $am_make supports nested variables], - [am_cv_make_support_nested_variables], - [if AS_ECHO([['TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi]) -AC_SUBST([AM_V])dnl -AM_SUBST_NOTMAKE([AM_V])dnl -AC_SUBST([AM_DEFAULT_V])dnl -AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl -AC_SUBST([AM_DEFAULT_VERBOSITY])dnl -AM_BACKSLASH='\' -AC_SUBST([AM_BACKSLASH])dnl -_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl -dnl Delay evaluation of AM_DEFAULT_VERBOSITY to the end to allow multiple calls -dnl to AM_SILENT_RULES to change the default value. -AC_CONFIG_COMMANDS_PRE([dnl -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; -esac -if test $am_cv_make_support_nested_variables = yes; then - dnl Using '$V' instead of '$(V)' breaks IRIX make. - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi -])dnl -]) - -# AM_SILENT_RULES([DEFAULT]) -# -------------------------- -# Set the default verbosity level to DEFAULT ("yes" being less verbose, "no" or -# empty being verbose). -AC_DEFUN([AM_SILENT_RULES], -[AC_REQUIRE([_AM_SILENT_RULES]) -AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1])m4_newline -dnl We intentionally force a newline after the assignment, since a) nothing -dnl good can come of more text following, and b) that was the behavior -dnl before 1.17. See https://bugs.gnu.org/72267. -]) - -# Copyright (C) 2001-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_STRIP -# --------------------- -# One issue with vendor 'install' (even GNU) is that you can't -# specify the program used to strip binaries. This is especially -# annoying in cross-compiling environments, where the build's strip -# is unlikely to handle the host's binaries. -# Fortunately install-sh will honor a STRIPPROG variable, so we -# always use install-sh in "make install-strip", and initialize -# STRIPPROG with the value of the STRIP variable (set by the user). -AC_DEFUN([AM_PROG_INSTALL_STRIP], -[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) - -# Copyright (C) 2006-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. -# This macro is traced by Automake. -AC_DEFUN([_AM_SUBST_NOTMAKE]) - -# AM_SUBST_NOTMAKE(VARIABLE) -# -------------------------- -# Public sister of _AM_SUBST_NOTMAKE. -AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) - -# Check how to create a tarball. -*- Autoconf -*- - -# Copyright (C) 2004-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_PROG_TAR(FORMAT) -# -------------------- -# Check how to create a tarball in format FORMAT. -# FORMAT should be one of 'v7', 'ustar', or 'pax'. -# -# Substitute a variable $(am__tar) that is a command -# writing to stdout a FORMAT-tarball containing the directory -# $tardir. -# tardir=directory && $(am__tar) > result.tar -# -# Substitute a variable $(am__untar) that extract such -# a tarball read from stdin. -# $(am__untar) < result.tar -# -AC_DEFUN([_AM_PROG_TAR], -[# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AC_SUBST([AMTAR], ['$${TAR-tar}']) - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' - -m4_if([$1], [v7], - [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], - - [m4_case([$1], - [ustar], - [# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) - if test x$am_uid = xunknown; then - AC_MSG_WARN([ancient id detected; assuming current UID is ok, but dist-ustar might not work]) - elif test $am_uid -le $am_max_uid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi - AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) - if test x$gm_gid = xunknown; then - AC_MSG_WARN([ancient id detected; assuming current GID is ok, but dist-ustar might not work]) - elif test $am_gid -le $am_max_gid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi], - - [pax], - [], - - [m4_fatal([Unknown tar format])]) - - AC_MSG_CHECKING([how to create a $1 tar archive]) - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_$1-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - AM_RUN_LOG([$_am_tar --version]) && break - done - am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x $1 -w "$$tardir"' - am__tar_='pax -L -x $1 -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H $1 -L' - am__tar_='find "$tardir" -print | cpio -o -H $1 -L' - am__untar='cpio -i -H $1 -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_$1}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) - rm -rf conftest.dir - if test -s conftest.tar; then - AM_RUN_LOG([$am__untar /dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) - AC_MSG_RESULT([$am_cv_prog_tar_$1])]) - -AC_SUBST([am__tar]) -AC_SUBST([am__untar]) -]) # _AM_PROG_TAR - -# Copyright (C) 2022-2025 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_PROG_XARGS_N -# ---------------- -# Check whether 'xargs -n' works. It should work everywhere, so the fallback -# is not optimized at all as we never expect to use it. -AC_DEFUN([_AM_PROG_XARGS_N], -[AC_CACHE_CHECK([xargs -n works], am_cv_xargs_n_works, [dnl -AS_IF([test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 -3"], [am_cv_xargs_n_works=yes], [am_cv_xargs_n_works=no])]) -AS_IF([test "$am_cv_xargs_n_works" = yes], [am__xargs_n='xargs -n'], [dnl - am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "$@" "$am__xargs_n_arg"; done; }' -])dnl -AC_SUBST(am__xargs_n) -]) - -m4_include([m4/ax_gcc_builtin.m4]) -m4_include([m4/libtool.m4]) -m4_include([m4/ltoptions.m4]) -m4_include([m4/ltsugar.m4]) -m4_include([m4/ltversion.m4]) -m4_include([m4/lt~obsolete.m4]) diff --git a/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.0 b/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.0 deleted file mode 100644 index c0c8c80c2..000000000 --- a/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.0 +++ /dev/null @@ -1,24109 +0,0 @@ -@%:@! /bin/sh -@%:@ Guess values for system-dependent variables and create Makefiles. -@%:@ Generated by GNU Autoconf 2.73 for libXext 1.3.7. -@%:@ -@%:@ Report bugs to . -@%:@ -@%:@ -@%:@ Copyright (C) 1992-1996, 1998-2017, 2020-2026 Free Software Foundation, -@%:@ Inc. -@%:@ -@%:@ -@%:@ This configure script is free software; the Free Software Foundation -@%:@ gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $@%:@ in @%:@ (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case \`(set -o) 2>/dev/null\` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ) -then : - -else case e in @%:@( - e) exitcode=1; echo positional parameters were not saved. ;; -esac -fi -test x\$exitcode = x0 || exit 1 -blah=\$(echo \$(echo blah)) -test x\"\$blah\" = xblah || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 - - test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ - || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null -then : - as_have_required=yes -else case e in @%:@( - e) as_have_required=no ;; -esac -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null -then : - -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - case $as_dir in @%:@( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$as_shell as_have_required=yes - if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null -then : - break 2 -fi -fi - done;; - esac - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in @%:@( - e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi ;; -esac -fi - - - if test "x$CONFIG_SHELL" != x -then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $@%:@ in @%:@ (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno -then : - printf '%s\n' "$0: This script requires a shell more modern than all" - printf '%s\n' "$0: the shells that I found on your system." - if test ${ZSH_VERSION+y} ; then - printf '%s\n' "$0: In particular, zsh $ZSH_VERSION has bugs and should" - printf '%s\n' "$0: be upgraded to zsh 4.3.4 or later." - else - printf '%s\n' "$0: Please tell bug-autoconf@gnu.org and -$0: https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi ;; -esac -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in @%:@( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in @%:@( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - t clear - :clear - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { printf '%s\n' "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - -SHELL=${CONFIG_SHELL-/bin/sh} - -as_awk_strverscmp=' - # Use only awk features that work with 7th edition Unix awk (1978). - # My, what an old awk you have, Mr. Solaris! - END { - while (length(v1) && length(v2)) { - # Set d1 to be the next thing to compare from v1, and likewise for d2. - # Normally this is a single character, but if v1 and v2 contain digits, - # compare them as integers and fractions as strverscmp does. - if (v1 ~ /^[0-9]/ && v2 ~ /^[0-9]/) { - # Split v1 and v2 into their leading digit string components d1 and d2, - # and advance v1 and v2 past the leading digit strings. - for (len1 = 1; substr(v1, len1 + 1) ~ /^[0-9]/; len1++) continue - for (len2 = 1; substr(v2, len2 + 1) ~ /^[0-9]/; len2++) continue - d1 = substr(v1, 1, len1); v1 = substr(v1, len1 + 1) - d2 = substr(v2, 1, len2); v2 = substr(v2, len2 + 1) - if (d1 ~ /^0/) { - if (d2 ~ /^0/) { - # Compare two fractions. - while (d1 ~ /^0/ && d2 ~ /^0/) { - d1 = substr(d1, 2); len1-- - d2 = substr(d2, 2); len2-- - } - if (len1 != len2 && ! (len1 && len2 && substr(d1, 1, 1) == substr(d2, 1, 1))) { - # The two components differ in length, and the common prefix - # contains only leading zeros. Consider the longer to be less. - d1 = -len1 - d2 = -len2 - } else { - # Otherwise, compare as strings. - d1 = "x" d1 - d2 = "x" d2 - } - } else { - # A fraction is less than an integer. - exit 1 - } - } else { - if (d2 ~ /^0/) { - # An integer is greater than a fraction. - exit 2 - } else { - # Compare two integers. - d1 += 0 - d2 += 0 - } - } - } else { - # The normal case, without worrying about digits. - d1 = substr(v1, 1, 1); v1 = substr(v1, 2) - d2 = substr(v2, 1, 1); v2 = substr(v2, 2) - } - if (d1 < d2) exit 1 - if (d1 > d2) exit 2 - } - # Beware Solaris 11 /usr/xgp4/bin/awk, which mishandles some - # comparisons of empty strings to integers. For example, - # LC_ALL=C /usr/xpg4/bin/awk "BEGIN {if (-1 < \"\") print \"a\"}" - # prints "a". - if (length(v2)) exit 1 - if (length(v1)) exit 2 - } -' - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_CONFIG_STATUS= -ac_clean_files= -ac_config_libobj_dir=. -LIB@&t@OBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='libXext' -PACKAGE_TARNAME='libXext' -PACKAGE_VERSION='1.3.7' -PACKAGE_STRING='libXext 1.3.7' -PACKAGE_BUGREPORT='https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues' -PACKAGE_URL='' - -ac_unique_file="Makefile.am" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_STDIO_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_header_c_list= -ac_subst_vars='am__EXEEXT_FALSE -am__EXEEXT_TRUE -LTLIBOBJS -MAKE_LINT_LIB_FALSE -MAKE_LINT_LIB_TRUE -LINTLIB -LINT_FALSE -LINT_TRUE -LINT_FLAGS -LINT -LIB@&t@OBJS -XEXT_LIBS -XEXT_CFLAGS -XEXT_SOREV -XTMALLOC_ZERO_CFLAGS -XMALLOC_ZERO_CFLAGS -MALLOC_ZERO_CFLAGS -HAVE_STYLESHEETS_FALSE -HAVE_STYLESHEETS_TRUE -XSL_STYLESHEET -STYLESHEET_SRCDIR -XORG_SGML_PATH -HAVE_XSLTPROC_FALSE -HAVE_XSLTPROC_TRUE -XSLTPROC -HAVE_FOP_FALSE -HAVE_FOP_TRUE -FOP -HAVE_XMLTO_FALSE -HAVE_XMLTO_TRUE -HAVE_XMLTO_TEXT_FALSE -HAVE_XMLTO_TEXT_TRUE -XMLTO -ENABLE_SPECS_FALSE -ENABLE_SPECS_TRUE -MAN_SUBSTS -XORG_MAN_PAGE -ADMIN_MAN_DIR -DRIVER_MAN_DIR -MISC_MAN_DIR -FILE_MAN_DIR -LIB_MAN_DIR -APP_MAN_DIR -ADMIN_MAN_SUFFIX -DRIVER_MAN_SUFFIX -MISC_MAN_SUFFIX -FILE_MAN_SUFFIX -LIB_MAN_SUFFIX -APP_MAN_SUFFIX -INSTALL_CMD -PKG_CONFIG_LIBDIR -PKG_CONFIG_PATH -PKG_CONFIG -CHANGELOG_CMD -STRICT_CFLAGS -CWARNFLAGS -BASE_CFLAGS -LT_SYS_LIBRARY_PATH -OTOOL64 -OTOOL -LIPO -NMEDIT -DSYMUTIL -MANIFEST_TOOL -RANLIB -ac_ct_AR -AR -DLLTOOL -OBJDUMP -FILECMD -LN_S -NM -ac_ct_DUMPBIN -DUMPBIN -LD -FGREP -EGREP -GREP -SED -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -LIBTOOL -am__xargs_n -am__rm_f_notfound -AM_BACKSLASH -AM_DEFAULT_VERBOSITY -AM_DEFAULT_V -AM_V -CSCOPE -ETAGS -CTAGS -am__fastdepCC_FALSE -am__fastdepCC_TRUE -CCDEPMODE -am__nodep -AMDEPBACKSLASH -AMDEP_FALSE -AMDEP_TRUE -am__include -DEPDIR -am__untar -am__tar -AMTAR -am__leading_dot -SET_MAKE -AWK -mkdir_p -MKDIR_P -INSTALL_STRIP_PROGRAM -STRIP -install_sh -MAKEINFO -AUTOHEADER -AUTOMAKE -AUTOCONF -ACLOCAL -VERSION -PACKAGE -CYGPATH_W -am__isrc -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -ECHO_T -ECHO_N -ECHO_C -target_alias -host_alias -build_alias -LIBS -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -runstatedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL -am__quote' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_dependency_tracking -enable_silent_rules -enable_shared -enable_static -enable_pic -with_pic -enable_fast_install -enable_aix_soname -with_aix_soname -with_gnu_ld -with_sysroot -enable_libtool_lock -enable_selective_werror -enable_strict_compilation -enable_specs -with_xmlto -with_fop -with_xsltproc -enable_malloc0returnsnull -with_lint -enable_lint_library -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -LT_SYS_LIBRARY_PATH -PKG_CONFIG -PKG_CONFIG_PATH -PKG_CONFIG_LIBDIR -XMLTO -FOP -XSLTPROC -XEXT_CFLAGS -XEXT_LIBS -LINT -LINT_FLAGS' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: '$ac_option' -Try '$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: '$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - printf '%s\n' "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - printf '%s\n' "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`printf '%s\n' $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: '$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -'configure' configures libXext 1.3.7 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print 'checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for '--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or '..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - @<:@@S|@ac_default_prefix@:>@ - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - @<:@PREFIX@:>@ - -By default, 'make install' will install all the files in -'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify -an installation prefix other than '$ac_default_prefix' using '--prefix', -for instance '--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root @<:@DATAROOTDIR/doc/libXext@:>@ - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of libXext 1.3.7:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-dependency-tracking - do not reject slow dependency extractors - --disable-dependency-tracking - speeds up one-time build - --enable-silent-rules less verbose build output (undo: "make V=1") - --disable-silent-rules verbose build output (undo: "make V=0") - --enable-shared@<:@=PKGS@:>@ build shared libraries @<:@default=yes@:>@ - --enable-static@<:@=PKGS@:>@ build static libraries @<:@default=yes@:>@ - --enable-pic@<:@=PKGS@:>@ try to use only PIC/non-PIC objects @<:@default=use - both@:>@ - --enable-fast-install@<:@=PKGS@:>@ - optimize for fast installation @<:@default=yes@:>@ - --enable-aix-soname=aix|svr4|both - shared library versioning (aka "SONAME") variant to - provide on AIX, @<:@default=aix@:>@. - --disable-libtool-lock avoid locking (might break parallel builds) - --disable-selective-werror - Turn off selective compiler errors. (default: - enabled) - --enable-strict-compilation - Enable all warnings from compiler and make them - errors (default: disabled) - --enable-specs Enable building the specs (default: yes) - --enable-malloc0returnsnull - assume malloc(0) can return NULL (default: yes) - --enable-lint-library Create lint library (default: disabled) - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-gnu-ld assume the C compiler uses GNU ld @<:@default=no@:>@ - --with-sysroot@<:@=DIR@:>@ Search for dependent libraries within DIR (or the - compiler's sysroot if not specified). - --with-xmlto Use xmlto to regenerate documentation (default: - auto) - --with-fop Use fop to regenerate documentation (default: auto) - --with-xsltproc Use xsltproc for the transformation of XML documents - (default: auto) - --with-lint Use a lint-style source code checker (default: - disabled) - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - LT_SYS_LIBRARY_PATH - User-defined run-time library search path. - PKG_CONFIG path to pkg-config utility - PKG_CONFIG_PATH - directories to add to pkg-config's search path - PKG_CONFIG_LIBDIR - path overriding pkg-config's built-in search path - XMLTO Path to xmlto command - FOP Path to fop command - XSLTPROC Path to xsltproc command - XEXT_CFLAGS C compiler flags for XEXT, overriding pkg-config - XEXT_LIBS linker flags for XEXT, overriding pkg-config - LINT Path to a lint-style command - LINT_FLAGS Flags for the lint-style command - -Use these variables to override the choices made by 'configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for configure.gnu first; this name is used for a wrapper for - # Metaconfig's "Configure" on case-insensitive file systems. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - printf '%s\n' "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -libXext configure 1.3.7 -generated by GNU Autoconf 2.73 - -Copyright (C) 2026 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -@%:@ ac_fn_c_try_compile LINENO -@%:@ -------------------------- -@%:@ Try to compile conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_compile - -@%:@ ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -@%:@ ------------------------------------------------------- -@%:@ Tests whether HEADER exists and can be compiled using the include files in -@%:@ INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -@%:@include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_header_compile - -@%:@ ac_fn_c_try_link LINENO -@%:@ ----------------------- -@%:@ Try to link conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - } -then : - ac_retval=0 -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_link - -@%:@ ac_fn_c_check_func LINENO FUNC VAR -@%:@ ---------------------------------- -@%:@ Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (void); below. */ - -#include -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (void); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main (void) -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_func - -@%:@ ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR -@%:@ ------------------------------------------------------------------ -@%:@ Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -@%:@ accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. -ac_fn_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -printf %s "checking whether $as_decl_name is declared... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - eval ac_save_FLAGS=\$$6 - as_fn_append $6 " $5" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main (void) -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - eval $6=\$ac_save_FLAGS - ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_check_decl -ac_configure_args_raw= -for ac_arg -do - case $ac_arg in - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_configure_args_raw " '$ac_arg'" -done - -case $ac_configure_args_raw in - *$as_nl*) - ac_safe_unquote= ;; - *) - ac_unsafe_z='|&;<>()$`\\"*?@<:@ '' ' # This string ends in space, tab. - ac_unsafe_a="$ac_unsafe_z#~" - ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" - ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; -esac - -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - $ $0$ac_configure_args_raw - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - printf '%s\n' "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# Dump the cache to stdout. It can be in a pipe (this is a requirement). -ac_cache_dump () -{ - # The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf '%s\n' "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # 'set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # 'set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) -} - -# Print debugging info to stdout. -ac_dump_debugging_info () -{ - echo - - printf '%s\n' "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - ac_cache_dump - echo - - printf '%s\n' "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - - if test -n "$ac_subst_files"; then - printf '%s\n' "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - fi - - if test -s confdefs.h; then - printf '%s\n' "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - printf '%s\n' "$as_me: caught signal $ac_signal" - printf '%s\n' "$as_me: exit $exit_status" -} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. -ac_exit_trap () -{ - exit_status= - # Sanitize IFS. - IFS=" "" $as_nl" - # Save into config.log some information that might help in debugging. - ac_dump_debugging_info >&5 - eval "rm -f $ac_clean_CONFIG_STATUS core *.core core.conftest.*" && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -} - -trap 'ac_exit_trap $?' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -printf '%s\n' "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -printf '%s\n' "@%:@define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -if test -n "$CONFIG_SITE"; then - ac_site_files="$CONFIG_SITE" -elif test "x$prefix" != xNONE; then - ac_site_files="$prefix/share/config.site $prefix/etc/config.site" -else - ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" -fi - -for ac_site_file in $ac_site_files -do - case $ac_site_file in @%:@( - */*) : - ;; @%:@( - *) : - ac_site_file=./$ac_site_file ;; -esac - if test -f "$ac_site_file" && test -r "$ac_site_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -printf '%s\n' "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See 'config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -printf '%s\n' "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -printf '%s\n' "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" -# Test code for whether the C compiler supports C23 (global declarations) -ac_c_conftest_c23_globals=' -/* Does the compiler advertise conformance to C17 or earlier? - Although GCC 14 does not do that, even with -std=gnu23, - it is close enough, and defines __STDC_VERSION == 202000L. */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ <= 201710L -# error "Compiler advertises conformance to C17 or earlier" -#endif - -// Check alignas. -char alignas (double) c23_aligned_as_double; -char alignas (0) c23_no_special_alignment; -extern char c23_aligned_as_int; -char alignas (0) alignas (int) c23_aligned_as_int; - -// Check alignof. -enum -{ - c23_int_alignment = alignof (int), - c23_int_array_alignment = alignof (int[100]), - c23_char_alignment = alignof (char) -}; -static_assert (0 < -alignof (int), "alignof is signed"); - -int function_with_unnamed_parameter (int) { return 0; } - -void c23_noreturn (); - -/* Test parsing of string and char UTF-8 literals (including hex escapes). - The parens pacify GCC 15. */ -bool use_u8 = (!sizeof u8"\xFF") == (!u8'\''x'\''); - -bool check_that_bool_works = true | false | !nullptr; -#if !true -# error "true does not work in #if" -#endif -#if false -#elifdef __STDC_VERSION__ -#else -# error "#elifdef does not work" -#endif - -#ifndef __has_c_attribute -# error "__has_c_attribute not defined" -#endif - -#ifndef __has_include -# error "__has_include not defined" -#endif - -#define LPAREN() ( -#define FORTY_TWO(x) 42 -#define VA_OPT_TEST(r, x, ...) __VA_OPT__ (FORTY_TWO r x)) -static_assert (VA_OPT_TEST (LPAREN (), 0, <:-) == 42); - -static_assert (0b101010 == 42); -static_assert (0B101010 == 42); -static_assert (0xDEAD'\''BEEF == 3'\''735'\''928'\''559); -static_assert (0.500'\''000'\''000 == 0.5); - -enum unsignedish : unsigned int { uione = 1 }; -static_assert (0 < -uione); - -#include -constexpr nullptr_t null_pointer = nullptr; - -static typeof (1 + 1L) two () { return 2; } -static long int three () { return 3; } -' - -# Test code for whether the C compiler supports C23 (body of main). -ac_c_conftest_c23_main=' - { - label_before_declaration: - int arr[10] = {}; - if (arr[0]) - goto label_before_declaration; - if (!arr[0]) - goto label_at_end_of_block; - label_at_end_of_block: - } - ok |= !null_pointer; - ok |= two != three; -' - -# Test code for whether the C compiler supports C23 (complete). -ac_c_conftest_c23_program="${ac_c_conftest_c23_globals} - -int -main (int, char **) -{ - int ok = 0; - ${ac_c_conftest_c23_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (global declarations) -ac_c_conftest_c89_globals=' -/* Do not test the value of __STDC__, because some compilers define it to 0 - or do not define it, while otherwise adequately conforming. */ - -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ -struct buf { int x; }; -struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (char **p, int i) -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* C89 style stringification. */ -#define noexpand_stringify(a) #a -const char *stringified = noexpand_stringify(arbitrary+token=sequence); - -/* C89 style token pasting. Exercises some of the corner cases that - e.g. old MSVC gets wrong, but not very hard. */ -#define noexpand_concat(a,b) a##b -#define expand_concat(a,b) noexpand_concat(a,b) -extern int vA; -extern int vbee; -#define aye A -#define bee B -int *pvA = &expand_concat(v,aye); -int *pvbee = &noexpand_concat(v,bee); - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not \xHH hex character constants. - These do not provoke an error unfortunately, instead are silently treated - as an "x". The following induces an error, until -std is added to get - proper ANSI mode. Curiously \x00 != x always comes out true, for an - array size at least. It is necessary to write \x00 == 0 to get something - that is true only with -std. */ -int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) '\''x'\'' -int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), - int, int);' - -# Test code for whether the C compiler supports C89 (body of main). -ac_c_conftest_c89_main=' -ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); -' - -# Test code for whether the C compiler supports C99 (global declarations) -ac_c_conftest_c99_globals=' -/* Does the compiler advertise C99 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# error "Compiler does not advertise C99 conformance" -#endif - -// See if C++-style comments work. - -#include -extern int puts (const char *); -extern int printf (const char *, ...); -extern int dprintf (int, const char *, ...); -extern void *malloc (size_t); -extern void free (void *); - -// Check varargs macros. These examples are taken from C99 6.10.3.5. -// dprintf is used instead of fprintf to avoid needing to declare -// FILE and stderr, and "aND" is used instead of "and" to work around -// GCC bug 40564 which is irrelevant here. -#define debug(...) dprintf (2, __VA_ARGS__) -#define showlist(...) puts (#__VA_ARGS__) -#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) -static void -test_varargs_macros (void) -{ - int x = 1234; - int y = 5678; - debug ("Flag"); - debug ("X = %d\n", x); - showlist (The first, second, aND third items.); - report (x>y, "x is %d but y is %d", x, y); -} - -// Check long long types. -#define BIG64 18446744073709551615ull -#define BIG32 4294967295ul -#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) -#if !BIG_OK - #error "your preprocessor is broken" -#endif -#if BIG_OK -#else - #error "your preprocessor is broken" -#endif -static long long int bignum = -9223372036854775807LL; -static unsigned long long int ubignum = BIG64; - -struct incomplete_array -{ - int datasize; - double data[]; -}; - -struct named_init { - int number; - const wchar_t *name; - double average; -}; - -typedef const char *ccp; - -static inline int -test_restrict (ccp restrict text) -{ - // Iterate through items via the restricted pointer. - // Also check for declarations in for loops. - for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) - continue; - return 0; -} - -// Check varargs and va_copy. -static bool -test_varargs (const char *format, ...) -{ - va_list args; - va_start (args, format); - va_list args_copy; - va_copy (args_copy, args); - - const char *str = ""; - int number = 0; - float fnumber = 0; - - while (*format) - { - switch (*format++) - { - case '\''s'\'': // string - str = va_arg (args_copy, const char *); - break; - case '\''d'\'': // int - number = va_arg (args_copy, int); - break; - case '\''f'\'': // float - fnumber = va_arg (args_copy, double); - break; - default: - break; - } - } - va_end (args_copy); - va_end (args); - - return *str && number && fnumber; -} -' - -# Test code for whether the C compiler supports C99 (body of main). -ac_c_conftest_c99_main=' - // Check bool. - _Bool success = false; - success |= (argc != 0); - - // Check restrict. - if (test_restrict ("String literal") == 0) - success = true; - const char *restrict newvar = "Another string"; - - // Check varargs. - success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); - test_varargs_macros (); - - // Check flexible array members. - static struct incomplete_array *volatile incomplete_array_pointer; - struct incomplete_array *ia = incomplete_array_pointer; - ia->datasize = 10; - for (int i = 0; i < ia->datasize; ++i) - ia->data[i] = i * 1.234; - // Work around memory leak warnings. - free (ia); - - // Check named initializers. - struct named_init ni = { - .number = 34, - .name = L"Test wide string", - .average = 543.34343, - }; - - ni.number = 58; - - // Do not test for VLAs, as some otherwise-conforming compilers lack them. - // C code should instead use __STDC_NO_VLA__; see Autoconf manual. - - // work around unused variable warnings - ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' - || ni.number != 58); -' - -# Test code for whether the C compiler supports C11 (global declarations) -ac_c_conftest_c11_globals=' -/* Does the compiler advertise C11 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L -# error "Compiler does not advertise C11 conformance" -#endif - -// Check _Alignas. -char _Alignas (double) aligned_as_double; -char _Alignas (0) no_special_alignment; -extern char aligned_as_int; -char _Alignas (0) _Alignas (int) aligned_as_int; - -// Check _Alignof. -enum -{ - int_alignment = _Alignof (int), - int_array_alignment = _Alignof (int[100]), - char_alignment = _Alignof (char) -}; -_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); - -// Check _Noreturn. -int _Noreturn does_not_return (void) { for (;;) continue; } - -// Check _Static_assert. -struct test_static_assert -{ - int x; - _Static_assert (sizeof (int) <= sizeof (long int), - "_Static_assert does not work in struct"); - long int y; -}; - -// Check UTF-8 literals. -#define u8 syntax error! -char const utf8_literal[] = u8"happens to be ASCII" "another string"; - -// Check duplicate typedefs. -typedef long *long_ptr; -typedef long int *long_ptr; -typedef long_ptr long_ptr; - -// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. -struct anonymous -{ - union { - struct { int i; int j; }; - struct { int k; long int l; } w; - }; - int m; -} v1; -' - -# Test code for whether the C compiler supports C11 (body of main). -ac_c_conftest_c11_main=' - _Static_assert ((offsetof (struct anonymous, i) - == offsetof (struct anonymous, w.k)), - "Anonymous union alignment botch"); - v1.i = 2; - v1.w.k = 5; - ok |= v1.i != 5; -' - -# Test code for whether the C compiler supports C11 (complete). -ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} -${ac_c_conftest_c11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - ${ac_c_conftest_c11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C99 (complete). -ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (complete). -ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - return ok; -} -" - -as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" -as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" -as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" -as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" -as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" -as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" -as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" -as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" -as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" -as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" - -# Auxiliary files required by this configure script. -ac_aux_files="config.guess config.sub ltmain.sh missing install-sh compile" - -# Locations in which to look for auxiliary files. -ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." - -# Search for a directory containing all of the required auxiliary files, -# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. -# If we don't find one directory that contains all the files we need, -# we report the set of missing files from the *first* directory in -# $ac_aux_dir_candidates and give up. -ac_missing_aux_files="" -ac_first_candidate=: -printf '%s\n' "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in $ac_aux_dir_candidates -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - - printf '%s\n' "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 - ac_aux_dir_found=yes - ac_install_sh= - for ac_aux in $ac_aux_files - do - # As a special case, if "install-sh" is required, that requirement - # can be satisfied by any of "install-sh", "install.sh", or "shtool", - # and $ac_install_sh is set appropriately for whichever one is found. - if test x"$ac_aux" = x"install-sh" - then - if test -f "${as_dir}install-sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 - ac_install_sh="${as_dir}install-sh -c" - elif test -f "${as_dir}install.sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 - ac_install_sh="${as_dir}install.sh -c" - elif test -f "${as_dir}shtool"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 - ac_install_sh="${as_dir}shtool install -c" - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} install-sh" - else - break - fi - fi - else - if test -f "${as_dir}${ac_aux}"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" - else - break - fi - fi - fi - done - if test "$ac_aux_dir_found" = yes; then - ac_aux_dir="$as_dir" - break - fi - ac_first_candidate=false - - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in @%:@( - e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; -esac -fi - - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -if test -f "${ac_aux_dir}config.guess"; then - ac_@&t@config_guess="$SHELL ${ac_aux_dir}config.guess" -fi -if test -f "${ac_aux_dir}config.sub"; then - ac_@&t@config_sub="$SHELL ${ac_aux_dir}config.sub" -fi -if test -f "$ac_aux_dir/configure"; then - ac_@&t@configure="$SHELL ${ac_aux_dir}configure" -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w= - for ac_val in x $ac_old_val; do - ac_old_val_w="$ac_old_val_w $ac_val" - done - ac_new_val_w= - for ac_val in x $ac_new_val; do - ac_new_val_w="$ac_new_val_w $ac_val" - done - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 -printf '%s\n' "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 -printf '%s\n' "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 -printf '%s\n' "$as_me: former value: '$ac_old_val'" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 -printf '%s\n' "$as_me: current value: '$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`printf '%s\n' "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -printf '%s\n' "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' - and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in @%:@((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers config.h" - - - -# Set common system defines for POSIX extensions, such as _GNU_SOURCE -# Must be called before any macros that run the compiler (like LT_INIT) -# to avoid autoconf errors. - - - - - - - - - - - - - - -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $@%:@ != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" - fi -fi -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. -set dummy ${ac_tool_prefix}clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "clang", so it can be a program name with args. -set dummy clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -fi - - -test -z "$CC" && { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See 'config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion -version; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -printf %s "checking whether the C compiler works... " >&6; } -ac_link_default=`printf '%s\n' "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. -# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an '-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else case e in @%:@( - e) ac_file='' ;; -esac -fi -if test -z "$ac_file" -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See 'config.log' for more details" "$LINENO" 5; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -printf %s "checking for C compiler default output file name... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -printf '%s\n' "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -printf %s "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) -# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will -# work properly (i.e., refer to 'conftest.exe'), while it won't with -# 'rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else case e in @%:@( - e) { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest conftest$ac_cv_exeext -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -printf '%s\n' "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -int -main (void) -{ -FILE *f = fopen ("conftest.out", "w"); - if (!f) - return 1; - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -printf %s "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use '--host'. -See 'config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -printf '%s\n' "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext \ - conftest.o conftest.obj conftest.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -printf %s "checking for suffix of object files... " >&6; } -if test ${ac_cv_objext+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -printf '%s\n' "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 -printf %s "checking whether the compiler supports GNU C... " >&6; } -if test ${ac_cv_c_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else case e in @%:@( - e) ac_compiler_gnu=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -printf '%s\n' "$ac_cv_c_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+y} -ac_save_CFLAGS=$CFLAGS -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -printf %s "checking whether $CC accepts -g... " >&6; } -if test ${ac_cv_prog_cc_g+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -else case e in @%:@( - e) CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -printf '%s\n' "$ac_cv_prog_cc_g" >&6; } -if test $ac_test_CFLAGS; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -ac_prog_cc_stdc=no -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C23 features" >&5 -printf %s "checking for $CC option to enable C23 features... " >&6; } -if test ${ac_cv_prog_cc_c23+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c23=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c23_program -_ACEOF -for ac_arg in '' -std=gnu23 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c23=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c23" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c23" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c23" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c23" >&5 -printf '%s\n' "$ac_cv_prog_cc_c23" >&6; } - CC="$CC $ac_cv_prog_cc_c23" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c23 - ac_prog_cc_stdc=c23 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 -printf %s "checking for $CC option to enable C11 features... " >&6; } -if test ${ac_cv_prog_cc_c11+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c11=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c11_program -_ACEOF -for ac_arg in '' -std=gnu11 -std:c11 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c11" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c11" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c11" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -printf '%s\n' "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } -if test ${ac_cv_prog_cc_c99+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c99=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c99=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c99" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c99" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c99" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -printf '%s\n' "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 -printf %s "checking for $CC option to enable C89 features... " >&6; } -if test ${ac_cv_prog_cc_c89+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c89_program -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c89" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c89" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -printf '%s\n' "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 ;; -esac -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -printf %s "checking whether $CC understands -c and -o together... " >&6; } -if test ${am_cv_prog_cc_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - # aligned with autoconf, so not including core; see bug#72225. - rm -f -r a.out a.exe b.out conftest.$ac_ext conftest.$ac_objext \ - conftest.dSYM conftest1.$ac_ext conftest1.$ac_objext conftest1.dSYM \ - conftest2.$ac_ext conftest2.$ac_objext conftest2.dSYM - unset am_i ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -printf '%s\n' "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_header= ac_cache= -for ac_item in $ac_header_c_list -do - if test $ac_cache; then - ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" - if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf '%s\n' "#define $ac_item 1" >> confdefs.h - fi - ac_header= ac_cache= - elif test $ac_header; then - ac_cache=$ac_item - else - ac_header=$ac_item - fi -done - - - - - - - - -if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes -then : - -printf '%s\n' "@%:@define STDC_HEADERS 1" >>confdefs.h - -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 -printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test ${ac_cv_safe_to_define___extensions__+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -# define __EXTENSIONS__ 1 - $ac_includes_default -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_safe_to_define___extensions__=yes -else case e in @%:@( - e) ac_cv_safe_to_define___extensions__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -printf '%s\n' "$ac_cv_safe_to_define___extensions__" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 -printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } -if test ${ac_cv_should_define__xopen_source+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_should_define__xopen_source=no - if test $ac_cv_header_wchar_h = yes -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #define _XOPEN_SOURCE 500 - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_should_define__xopen_source=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 -printf '%s\n' "$ac_cv_should_define__xopen_source" >&6; } - - printf '%s\n' "@%:@define _ALL_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _COSMO_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _DARWIN_C_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _GNU_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h - - printf '%s\n' "@%:@define _NETBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _OPENBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h - - printf '%s\n' "@%:@define _TANDEM_SOURCE 1" >>confdefs.h - - if test $ac_cv_header_minix_config_h = yes -then : - MINIX=yes - printf '%s\n' "@%:@define _MINIX 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_1_SOURCE 2" >>confdefs.h - -else case e in @%:@( - e) MINIX= ;; -esac -fi - if test $ac_cv_safe_to_define___extensions__ = yes -then : - printf '%s\n' "@%:@define __EXTENSIONS__ 1" >>confdefs.h - -fi - if test $ac_cv_should_define__xopen_source = yes -then : - printf '%s\n' "@%:@define _XOPEN_SOURCE 500" >>confdefs.h - -fi - - -# Initialize Automake -am__api_version='1.18' - - - # Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -printf %s "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if test ${ac_cv_path_install+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - # Account for fact that we put trailing slashes in our PATH walk. -case $as_dir in @%:@(( - ./ | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF/1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF/1 since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - ;; -esac -fi - if test ${ac_cv_path_install+y}; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -printf '%s\n' "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5 -printf %s "checking whether sleep supports fractional seconds... " >&6; } -if test ${am_cv_sleep_fractional_seconds+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if sleep 0.001 2>/dev/null -then : - am_cv_sleep_fractional_seconds=yes -else case e in @%:@( - e) am_cv_sleep_fractional_seconds=no ;; -esac -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_sleep_fractional_seconds" >&5 -printf '%s\n' "$am_cv_sleep_fractional_seconds" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking filesystem timestamp resolution" >&5 -printf %s "checking filesystem timestamp resolution... " >&6; } -if test ${am_cv_filesystem_timestamp_resolution+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) # Default to the worst case. -am_cv_filesystem_timestamp_resolution=2 - -# Only try to go finer than 1 sec if sleep can do it. -# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, -# - 1 sec is not much of a win compared to 2 sec, and -# - it takes 2 seconds to perform the test whether 1 sec works. -# -# Instead, just use the default 2s on platforms that have 1s resolution, -# accept the extra 1s delay when using $sleep in the Automake tests, in -# exchange for not incurring the 2s delay for running the test for all -# packages. -# -am_try_resolutions= -if test "$am_cv_sleep_fractional_seconds" = yes; then - # Even a millisecond often causes a bunch of false positives, - # so just try a hundredth of a second. The time saved between .001 and - # .01 is not terribly consequential. - am_try_resolutions="0.01 0.1 $am_try_resolutions" -fi - -# In order to catch current-generation FAT out, we must *modify* files -# that already exist; the *creation* timestamp is finer. Use names -# that make ls -t sort them differently when they have equal -# timestamps than when they have distinct timestamps, keeping -# in mind that ls -t prints the *newest* file first. -rm -f conftest.ts? -: > conftest.ts1 -: > conftest.ts2 -: > conftest.ts3 - -# Make sure ls -t actually works. Do 'set' in a subshell so we don't -# clobber the current shell's arguments. (Outer-level square brackets -# are removed by m4; they're present so that m4 does not expand -# ; be careful, easy to get confused.) -if ( - set X `ls -t conftest.ts[12]` && - { - test "$*" != "X conftest.ts1 conftest.ts2" || - test "$*" != "X conftest.ts2 conftest.ts1"; - } -); then :; else - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - printf '%s\n' ""Bad output from ls -t: \"`ls -t conftest.ts[12]`\""" >&5 - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "ls -t produces unexpected output. -Make sure there is not a broken ls alias in your environment. -See 'config.log' for more details" "$LINENO" 5; } -fi - -for am_try_res in $am_try_resolutions; do - # Any one fine-grained sleep might happen to cross the boundary - # between two values of a coarser actual resolution, but if we do - # two fine-grained sleeps in a row, at least one of them will fall - # entirely within a coarse interval. - echo alpha > conftest.ts1 - sleep $am_try_res - echo beta > conftest.ts2 - sleep $am_try_res - echo gamma > conftest.ts3 - - # We assume that 'ls -t' will make use of high-resolution - # timestamps if the operating system supports them at all. - if (set X `ls -t conftest.ts?` && - test "$2" = conftest.ts3 && - test "$3" = conftest.ts2 && - test "$4" = conftest.ts1); then - # - # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, - # because we don't need to test make. - make_ok=true - if test $am_try_res != 1; then - # But if we've succeeded so far with a subsecond resolution, we - # have one more thing to check: make. It can happen that - # everything else supports the subsecond mtimes, but make doesn't; - # notably on macOS, which ships make 3.81 from 2006 (the last one - # released under GPLv2). https://bugs.gnu.org/68808 - # - # We test $MAKE if it is defined in the environment, else "make". - # It might get overridden later, but our hope is that in practice - # it does not matter: it is the system "make" which is (by far) - # the most likely to be broken, whereas if the user overrides it, - # probably they did so with a better, or at least not worse, make. - # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html - # - # Create a Makefile (real tab character here): - rm -f conftest.mk - echo 'conftest.ts1: conftest.ts2' >conftest.mk - echo ' touch conftest.ts2' >>conftest.mk - # - # Now, running - # touch conftest.ts1; touch conftest.ts2; make - # should touch ts1 because ts2 is newer. This could happen by luck, - # but most often, it will fail if make's support is insufficient. So - # test for several consecutive successes. - # - # (We reuse conftest.ts[12] because we still want to modify existing - # files, not create new ones, per above.) - n=0 - make=${MAKE-make} - until test $n -eq 3; do - echo one > conftest.ts1 - sleep $am_try_res - echo two > conftest.ts2 # ts2 should now be newer than ts1 - if $make -f conftest.mk | grep 'up to date' >/dev/null; then - make_ok=false - break # out of $n loop - fi - n=`expr $n + 1` - done - fi - # - if $make_ok; then - # Everything we know to check worked out, so call this resolution good. - am_cv_filesystem_timestamp_resolution=$am_try_res - break # out of $am_try_res loop - fi - # Otherwise, we'll go on to check the next resolution. - fi -done -rm -f conftest.ts? -# (end _am_filesystem_timestamp_resolution) - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_filesystem_timestamp_resolution" >&5 -printf '%s\n' "$am_cv_filesystem_timestamp_resolution" >&6; } - -# This check should not be cached, as it may vary across builds of -# different projects. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -printf %s "checking whether build environment is sane... " >&6; } -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[\\\"\#\$\&\'\`$am_lf]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; -esac -case $srcdir in - *[\\\"\#\$\&\'\`$am_lf\ \ ]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -am_build_env_is_sane=no -am_has_slept=no -rm -f conftest.file -for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - test "$2" = conftest.file - ); then - am_build_env_is_sane=yes - break - fi - # Just in case. - sleep "$am_cv_filesystem_timestamp_resolution" - am_has_slept=yes -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_build_env_is_sane" >&5 -printf '%s\n' "$am_build_env_is_sane" >&6; } -if test "$am_build_env_is_sane" = no; then - as_fn_error $? "newly created file is older than distributed files! -Check your system clock" "$LINENO" 5 -fi - -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1 -then : - -else case e in @%:@( - e) ( sleep "$am_cv_filesystem_timestamp_resolution" ) & - am_sleep_pid=$! - ;; -esac -fi - -rm -f conftest.file - -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was 's,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`printf '%s\n' "$program_transform_name" | sed "$ac_script"` - - - if test x"${MISSING+set}" != xset; then - MISSING="\${SHELL} '$am_aux_dir/missing'" -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -printf '%s\n' "$as_me: WARNING: 'missing' script is too old or missing" >&2;} -fi - -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 -printf %s "checking for a race-free mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if test ${ac_cv_path_mkdir+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue - case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir ('*'coreutils) '* | \ - *'BusyBox '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - ;; -esac -fi - - test -d ./--version && rmdir ./--version - if test ${ac_cv_path_mkdir+y}; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use plain mkdir -p, - # in the hope it doesn't have the bugs of ancient mkdir. - MKDIR_P='mkdir -p' - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -printf '%s\n' "$MKDIR_P" >&6; } - -for ac_prog in gawk mawk nawk awk 'busybox awk' -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AWK+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -printf '%s\n' "$AWK" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`printf '%s\n' "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval test \${ac_cv_prog_make_${ac_make}_set+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @printf '%s\n' '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make ;; -esac -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - SET_MAKE= -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depfiles" - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 -printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } -cat > confinc.mk << 'END' -am__doit: - @echo this is the am__doit target >confinc.out -.PHONY: am__doit -END -am__include="#" -am__quote= -# BSD make does it like this. -echo '.include "confinc.mk" # ignored' > confmf.BSD -# Other make implementations (GNU, Solaris 10, AIX) do it like this. -echo 'include confinc.mk # ignored' > confmf.GNU -_am_result=no -for s in GNU BSD; do - { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 - (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - case $?:`cat confinc.out 2>/dev/null` in @%:@( - '0:this is the am__doit target') : - case $s in @%:@( - BSD) : - am__include='.include' am__quote='"' ;; @%:@( - *) : - am__include='include' am__quote='' ;; -esac ;; @%:@( - *) : - ;; -esac - if test "$am__include" != "#"; then - _am_result="yes ($s style)" - break - fi -done -rm -f confinc.* confmf.* -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 -printf '%s\n' "${_am_result}" >&6; } - -@%:@ Check whether --enable-dependency-tracking was given. -if test ${enable_dependency_tracking+y} -then : - enableval=$enable_dependency_tracking; -fi - -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi - if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - -AM_DEFAULT_VERBOSITY=1 -@%:@ Check whether --enable-silent-rules was given. -if test ${enable_silent_rules+y} -then : - enableval=$enable_silent_rules; -fi - -am_make=${MAKE-make} -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -printf %s "checking whether $am_make supports nested variables... " >&6; } -if test ${am_cv_make_support_nested_variables+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if printf '%s\n' 'TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -printf '%s\n' "$am_cv_make_support_nested_variables" >&6; } -AM_BACKSLASH='\' - -am__rm_f_notfound= -if (rm -f && rm -fr && rm -rf) 2>/dev/null -then : - -else case e in @%:@( - e) am__rm_f_notfound='""' ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking xargs -n works" >&5 -printf %s "checking xargs -n works... " >&6; } -if test ${am_cv_xargs_n_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 -3" -then : - am_cv_xargs_n_works=yes -else case e in @%:@( - e) am_cv_xargs_n_works=no ;; -esac -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_xargs_n_works" >&5 -printf '%s\n' "$am_cv_xargs_n_works" >&6; } -if test "$am_cv_xargs_n_works" = yes -then : - am__xargs_n='xargs -n' -else case e in @%:@( - e) am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "" "$am__xargs_n_arg"; done; }' - ;; -esac -fi - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE='libXext' - VERSION='1.3.7' - - -printf '%s\n' "@%:@define PACKAGE \"$PACKAGE\"" >>confdefs.h - - -printf '%s\n' "@%:@define VERSION \"$VERSION\"" >>confdefs.h - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -mkdir_p='$(MKDIR_P)' - -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AMTAR='$${TAR-tar}' - - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar plaintar pax cpio none' - -# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 -printf %s "checking whether UID '$am_uid' is supported by ustar format... " >&6; } - if test x$am_uid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&2;} - elif test $am_uid -le $am_max_uid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 -printf %s "checking whether GID '$am_gid' is supported by ustar format... " >&6; } - if test x$gm_gid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&2;} - elif test $am_gid -le $am_max_gid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 -printf %s "checking how to create a ustar tar archive... " >&6; } - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_ustar-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - { echo "$as_me:$LINENO: $_am_tar --version" >&5 - ($_am_tar --version) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && break - done - am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x ustar -w "$$tardir"' - am__tar_='pax -L -x ustar -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H ustar -L' - am__tar_='find "$tardir" -print | cpio -o -H ustar -L' - am__untar='cpio -i -H ustar -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_ustar}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 - (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - rm -rf conftest.dir - if test -s conftest.tar; then - { echo "$as_me:$LINENO: $am__untar &5 - ($am__untar &5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 - (cat conftest.dir/file) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - grep GrepMe conftest.dir/file >/dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - if test ${am_cv_prog_tar_ustar+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) am_cv_prog_tar_ustar=$_am_tool ;; -esac -fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 -printf '%s\n' "$am_cv_prog_tar_ustar" >&6; } - - - - - -depcc="$CC" am_compiler_list= - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -printf %s "checking dependency style of $depcc... " >&6; } -if test ${am_cv_CC_dependencies_compiler_type+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thus: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -printf '%s\n' "$am_cv_CC_dependencies_compiler_type" >&6; } -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' -else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi - - -# Variables for tags utilities; see am/tags.am -if test -z "$CTAGS"; then - CTAGS=ctags -fi - -if test -z "$ETAGS"; then - ETAGS=etags -fi - -if test -z "$CSCOPE"; then - CSCOPE=cscope -fi - - - - - - - - -# Initialize libtool -case `pwd` in - *\ * | *\ *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 -printf '%s\n' "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; -esac - - - -macro_version='2.5.4' -macro_revision='2.5.4' - - - - - - - - - - - - - - -ltmain=$ac_aux_dir/ltmain.sh - - - - # Make sure we can run config.sub. -$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -printf %s "checking build system type... " >&6; } -if test ${ac_cv_build+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -printf '%s\n' "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`printf '%s\n' "$build_os" | sed 's/ /-/g'`;; esac - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -printf %s "checking host system type... " >&6; } -if test ${ac_cv_host+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -printf '%s\n' "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`printf '%s\n' "$host_os" | sed 's/ /-/g'`;; esac - - -# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 -printf %s "checking how to print strings... " >&6; } -# Test print first, because it will be a builtin if present. -if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "" -} - -case $ECHO in - printf*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: printf" >&5 -printf '%s\n' "printf" >&6; } ;; - print*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 -printf '%s\n' "print -r" >&6; } ;; - *) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: cat" >&5 -printf '%s\n' "cat" >&6; } ;; -esac - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -printf %s "checking for a sed that does not truncate output... " >&6; } -if test ${ac_cv_path_SED+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in sed gsed - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -printf '%s\n' "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - -test -z "$SED" && SED=sed -Xsed="$SED -e 1s/^X//" - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in grep ggrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf '%s\n' "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in egrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf '%s\n' "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - EGREP_TRADITIONAL=$EGREP - ac_cv_path_EGREP_TRADITIONAL=$EGREP - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 -printf %s "checking for fgrep... " >&6; } -if test ${ac_cv_path_FGREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 - then ac_cv_path_FGREP="$GREP -F" - else - if test -z "$FGREP"; then - ac_path_FGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in fgrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_FGREP" || continue -# Check for GNU ac_path_FGREP and select it if it is found. - # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'FGREP' >> "conftest.nl" - "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_FGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_FGREP="$ac_path_FGREP" - ac_path_FGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_FGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_FGREP"; then - as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_FGREP=$FGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 -printf '%s\n' "$ac_cv_path_FGREP" >&6; } - FGREP="$ac_cv_path_FGREP" - - -test -z "$GREP" && GREP=grep - - - - - - - - - - - - - - - - - - - -@%:@ Check whether --with-gnu-ld was given. -if test ${with_gnu_ld+y} -then : - withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes -else case e in @%:@( - e) with_gnu_ld=no ;; -esac -fi - -ac_prog=ld -if test yes = "$GCC"; then - # Check if gcc -print-prog-name=ld gives a path. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -printf %s "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw* | *-*-windows*) - # gcc leaves a trailing carriage return, which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD=$ac_prog - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test yes = "$with_gnu_ld"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -printf %s "checking for GNU ld... " >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -printf %s "checking for non-GNU ld... " >&6; } -fi -if test ${lt_cv_path_LD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$LD"; then - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD=$ac_dir/$ac_prog - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -printf '%s\n' "$LD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -printf %s "checking if the linker ($LD) is GNU ld... " >&6; } -if test ${lt_cv_prog_gnu_ld+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -printf '%s\n' "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 -printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if test ${lt_cv_path_NM+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM=$NM -else - lt_nm_to_check=${ac_tool_prefix}nm - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - tmp_nm=$ac_dir/$lt_tmp_nm - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the 'sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty - case $build_os in - mingw* | windows*) lt_bad_file=conftest.nm/nofile ;; - *) lt_bad_file=/dev/null ;; - esac - case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in - *$lt_bad_file* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break 2 - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break 2 - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS=$lt_save_ifs - done - : ${lt_cv_path_NM=no} -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 -printf '%s\n' "$lt_cv_path_NM" >&6; } -if test no != "$lt_cv_path_NM"; then - NM=$lt_cv_path_NM -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - if test -n "$ac_tool_prefix"; then - for ac_prog in dumpbin "link -dump" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DUMPBIN"; then - ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DUMPBIN=$ac_cv_prog_DUMPBIN -if test -n "$DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 -printf '%s\n' "$DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$DUMPBIN" && break - done -fi -if test -z "$DUMPBIN"; then - ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in dumpbin "link -dump" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DUMPBIN"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN -if test -n "$ac_ct_DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 -printf '%s\n' "$ac_ct_DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_DUMPBIN" && break -done - - if test "x$ac_ct_DUMPBIN" = x; then - DUMPBIN=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DUMPBIN=$ac_ct_DUMPBIN - fi -fi - - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols -headers" - ;; - *) - DUMPBIN=: - ;; - esac - fi - - if test : != "$DUMPBIN"; then - NM=$DUMPBIN - fi -fi -test -z "$NM" && NM=nm - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 -printf %s "checking the name lister ($NM) interface... " >&6; } -if test ${lt_cv_nm_interface+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: output\"" >&5) - cat conftest.out >&5 - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 -printf '%s\n' "$lt_cv_nm_interface" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -printf %s "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -printf '%s\n' "no, using $LN_S" >&6; } -fi - -# find the maximum length of command line arguments -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 -printf %s "checking the maximum length of command line arguments... " >&6; } -if test ${lt_cv_sys_max_cmd_len+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) i=0 - teststring=ABCD - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu* | ironclad*) - # Under GNU Hurd and Ironclad, this test is not required because there - # is no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | windows* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[ ]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test X`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test 17 != "$i" # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac - ;; -esac -fi - -if test -n "$lt_cv_sys_max_cmd_len"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 -printf '%s\n' "$lt_cv_sys_max_cmd_len" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none" >&5 -printf '%s\n' "none" >&6; } -fi -max_cmd_len=$lt_cv_sys_max_cmd_len - - - - - - -: ${CP="cp -f"} -: ${MV="mv -f"} -: ${RM="rm -f"} - -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - lt_unset=unset -else - lt_unset=false -fi - - - - - -# test EBCDIC or ASCII -case `echo X|tr X '\101'` in - A) # ASCII based system - # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr - lt_SP2NL='tr \040 \012' - lt_NL2SP='tr \015\012 \040\040' - ;; - *) # EBCDIC based system - lt_SP2NL='tr \100 \n' - lt_NL2SP='tr \r\n \100\100' - ;; -esac - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 -printf %s "checking how to convert $build file names to $host format... " >&6; } -if test ${lt_cv_to_host_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $host in - *-*-mingw* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 - ;; - esac - ;; - *-*-cygwin* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin - ;; - esac - ;; - * ) # unhandled hosts (and "normal" native builds) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; -esac - ;; -esac -fi - -to_host_file_cmd=$lt_cv_to_host_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_host_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 -printf %s "checking how to convert $build file names to toolchain format... " >&6; } -if test ${lt_cv_to_tool_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) #assume ordinary cross tools, or native build. -lt_cv_to_tool_file_cmd=func_convert_file_noop -case $host in - *-*-mingw* | *-*-windows* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 - ;; - esac - ;; -esac - ;; -esac -fi - -to_tool_file_cmd=$lt_cv_to_tool_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_tool_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 -printf %s "checking for $LD option to reload object files... " >&6; } -if test ${lt_cv_ld_reload_flag+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_reload_flag='-r' ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 -printf '%s\n' "$lt_cv_ld_reload_flag" >&6; } -reload_flag=$lt_cv_ld_reload_flag -case $reload_flag in -"" | " "*) ;; -*) reload_flag=" $reload_flag" ;; -esac -reload_cmds='$LD$reload_flag -o $output$reload_objs' -case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - if test yes != "$GCC"; then - reload_cmds=false - fi - ;; - darwin*) - if test yes = "$GCC"; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' - else - reload_cmds='$LD$reload_flag -o $output$reload_objs' - fi - ;; -esac - - - - - - - - - -# Extract the first word of "file", so it can be a program name with args. -set dummy file; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_FILECMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$FILECMD"; then - ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FILECMD="file" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_prog_FILECMD" && ac_cv_prog_FILECMD=":" -fi ;; -esac -fi -FILECMD=$ac_cv_prog_FILECMD -if test -n "$FILECMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 -printf '%s\n' "$FILECMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -printf '%s\n' "$OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -printf '%s\n' "$ac_ct_OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 -printf %s "checking how to recognize dependent libraries... " >&6; } -if test ${lt_cv_deplibs_check_method+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# 'unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'file_magic [[regex]]' -- check by looking for files in library path -# that responds to the $file_magic_cmd with a given extended regex. -# If you have 'file' or equivalent on your system and you're not sure -# whether 'pass_all' will *always* work, you probably want this one. - -case $host_os in -aix[4-9]*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[45]*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='$FILECMD -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | windows* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - if ( file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -cegcc*) - # use the weaker test based on 'objdump'. See mingw*. - lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly* | midnightbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -haiku*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=$FILECMD - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[3-9]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -*-mlibc) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -*nto* | *qnx*) - lt_cv_deplibs_check_method=pass_all - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -serenity*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -tpf*) - lt_cv_deplibs_check_method=pass_all - ;; -os2*) - lt_cv_deplibs_check_method=pass_all - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 -printf '%s\n' "$lt_cv_deplibs_check_method" >&6; } - -file_magic_glob= -want_nocaseglob=no -if test "$build" = "$host"; then - case $host_os in - mingw* | windows* | pw32*) - if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then - want_nocaseglob=yes - else - file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` - fi - ;; - esac -fi - -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - - - - - - - - - - - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -printf '%s\n' "$DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -printf '%s\n' "$ac_ct_DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 -printf %s "checking how to associate runtime and link libraries... " >&6; } -if test ${lt_cv_sharedlib_from_linklib_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_sharedlib_from_linklib_cmd='unknown' - -case $host_os in -cygwin* | mingw* | windows* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh; - # decide which one to use based on capabilities of $DLLTOOL - case `$DLLTOOL --help 2>&1` in - *--identify-strict*) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib - ;; - *) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback - ;; - esac - ;; -*) - # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd=$ECHO - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 -printf '%s\n' "$lt_cv_sharedlib_from_linklib_cmd" >&6; } -sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd -test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -printf '%s\n' "$RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -printf '%s\n' "$ac_ct_RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AR+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -printf '%s\n' "$AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_AR+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -printf '%s\n' "$ac_ct_AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -: ${AR=ar} - - - - - - -# Use ARFLAGS variable as AR's operation code to sync the variable naming with -# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have -# higher priority because that's what people were doing historically (setting -# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS -# variable obsoleted/removed. - -test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} -lt_ar_flags=$AR_FLAGS - - - - - - -# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override -# by AR_FLAGS because that was never working and AR_FLAGS is about to die. - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 -printf %s "checking for archiver @FILE support... " >&6; } -if test ${lt_cv_ar_at_file+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ar_at_file=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - echo conftest.$ac_objext > conftest.lst - lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -eq "$ac_status"; then - # Ensure the archiver fails upon bogus file names. - rm -f conftest.$ac_objext libconftest.a - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -ne "$ac_status"; then - lt_cv_ar_at_file=@ - fi - fi - rm -f conftest.* libconftest.a - -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 -printf '%s\n' "$lt_cv_ar_at_file" >&6; } - -if test no = "$lt_cv_ar_at_file"; then - archiver_list_spec= -else - archiver_list_spec=$lt_cv_ar_at_file -fi - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -test -z "$STRIP" && STRIP=: - - - - - - - -test -z "$RANLIB" && RANLIB=: - - - - - - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# Check for command to grab the raw symbol name followed by C symbol from nm. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 -printf %s "checking command to parse $NM output from $compiler object... " >&6; } -if test ${lt_cv_sys_global_symbol_pipe+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw* | windows* | pw32* | cegcc*) - symcode='[ABCDGISTW]' - ;; -hpux*) - if test ia64 = "$host_cpu"; then - symcode='[ABCDEGRST]' - fi - ;; -irix* | nonstopux*) - symcode='[BCDEGRST]' - ;; -osf*) - symcode='[BCDEGQRST]' - ;; -solaris*) - symcode='[BCDRT]' - ;; -sco3.2v5*) - symcode='[DT]' - ;; -sysv4.2uw2*) - symcode='[DT]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[ABDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[ABCDGIRSTW]' ;; -esac - -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Gets list of data symbols to import. - lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" - # Adjust the below global symbol transforms to fixup imported variables. - lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" - lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" - lt_c_name_lib_hook="\ - -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ - -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" -else - # Disable hooks by default. - lt_cv_sys_global_symbol_to_import= - lt_cdecl_hook= - lt_c_name_hook= - lt_c_name_lib_hook= -fi - -# Transform an extracted symbol line into a proper C declaration. -# Some systems (esp. on ia64) link data and code symbols differently, -# so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ -$lt_cdecl_hook\ -" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ -$lt_c_name_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" - -# Transform an extracted symbol line into symbol name with lib prefix and -# symbol address. -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ -$lt_c_name_lib_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw* | windows*) - opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# Try without a prefix underscore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function, - # D for any global variable and I for any imported variable. - # Also find C++ and __fastcall symbols from MSVC++ or ICC, - # which start with @ or ?. - lt_cv_sys_global_symbol_pipe="$AWK '"\ -" {last_section=section; section=\$ 3};"\ -" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ -" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ -" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ -" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ -" \$ 0!~/External *\|/{next};"\ -" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ -" {if(hide[section]) next};"\ -" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ -" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ -" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ -" ' prfx=^$ac_symprfx" - else - lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <<_LT_EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(void); -void nm_test_func(void){} -#ifdef __cplusplus -} -#endif -int main(void){nm_test_var='a';nm_test_func();return(0);} -_LT_EOF - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Now try to grab the symbols. - nlist=conftest.nm - $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 - if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if $GREP ' nm_test_var$' "$nlist" >/dev/null; then - if $GREP ' nm_test_func$' "$nlist" >/dev/null; then - cat <<_LT_EOF > conftest.$ac_ext -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE -/* DATA imports from DLLs on WIN32 can't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT@&t@_DLSYM_CONST -#elif defined __osf__ -/* This system does not cope well with relocations in const data. */ -# define LT@&t@_DLSYM_CONST -#else -# define LT@&t@_DLSYM_CONST const -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -_LT_EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' - - cat <<_LT_EOF >> conftest.$ac_ext - -/* The mapping between symbol names and symbols. */ -LT@&t@_DLSYM_CONST struct { - const char *name; - void *address; -} -lt__PROGRAM__LTX_preloaded_symbols[] = -{ - { "@PROGRAM@", (void *) 0 }, -_LT_EOF - $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext - cat <<\_LT_EOF >> conftest.$ac_ext - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt__PROGRAM__LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif -_LT_EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_globsym_save_LIBS=$LIBS - lt_globsym_save_CFLAGS=$CFLAGS - LIBS=conftstm.$ac_objext - CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest$ac_exeext; then - pipe_works=yes - fi - LIBS=$lt_globsym_save_LIBS - CFLAGS=$lt_globsym_save_CFLAGS - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - fi - rm -rf conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test yes = "$pipe_works"; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done - ;; -esac -fi - -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -printf '%s\n' "failed" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ok" >&5 -printf '%s\n' "ok" >&6; } -fi - -# Response file support. -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - nm_file_list_spec='@' -elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then - nm_file_list_spec='@' -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 -printf %s "checking for sysroot... " >&6; } - -@%:@ Check whether --with-sysroot was given. -if test ${with_sysroot+y} -then : - withval=$with_sysroot; -else case e in @%:@( - e) with_sysroot=no ;; -esac -fi - - -lt_sysroot= -case $with_sysroot in #( - yes) - if test yes = "$GCC"; then - # Trim trailing / since we'll always append absolute paths and we want - # to avoid //, if only for less confusing output for the user. - lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 -printf '%s\n' "$with_sysroot" >&6; } - as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 - ;; -esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 -printf '%s\n' "${lt_sysroot:-no}" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 -printf %s "checking for a working dd... " >&6; } -if test ${ac_cv_path_lt_DD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -: ${lt_DD:=$DD} -if test -z "$lt_DD"; then - ac_path_lt_DD_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in dd - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_lt_DD" || continue -if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: -fi - $ac_path_lt_DD_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_lt_DD"; then - : - fi -else - ac_cv_path_lt_DD=$lt_DD -fi - -rm -f conftest.i conftest2.i conftest.out ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 -printf '%s\n' "$ac_cv_path_lt_DD" >&6; } - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 -printf %s "checking how to truncate binary pipes... " >&6; } -if test ${lt_cv_truncate_bin+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -lt_cv_truncate_bin= -if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" -fi -rm -f conftest.i conftest2.i conftest.out -test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 -printf '%s\n' "$lt_cv_truncate_bin" >&6; } - - - - - - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in @S|@*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - -@%:@ Check whether --enable-libtool-lock was given. -if test ${enable_libtool_lock+y} -then : - enableval=$enable_libtool_lock; -fi - -test no = "$enable_libtool_lock" || enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out what ABI is being produced by ac_compile, and set mode - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE=32 - ;; - *ELF-64*) - HPUX_IA64_MODE=64 - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - if test yes = "$lt_cv_prog_gnu_ld"; then - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -mips64*-*linux*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - emul=elf - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - emul="${emul}32" - ;; - *64-bit*) - emul="${emul}64" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *MSB*) - emul="${emul}btsmip" - ;; - *LSB*) - emul="${emul}ltsmip" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *N32*) - emul="${emul}n32" - ;; - esac - LD="${LD-ld} -m $emul" - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. Note that the listed cases only cover the - # situations where additional linker options are needed (such as when - # doing 32-bit compilation for a host where ld defaults to 64-bit, or - # vice versa); the common cases where no linker options are needed do - # not appear in the list. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - case `$FILECMD conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac - ;; - powerpc64le-*linux*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - LD="${LD-ld} -m elf_x86_64" - ;; - powerpcle-*linux*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -belf" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 -printf %s "checking whether the C compiler needs -belf... " >&6; } -if test ${lt_cv_cc_needs_belf+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_cc_needs_belf=yes -else case e in @%:@( - e) lt_cv_cc_needs_belf=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 -printf '%s\n' "$lt_cv_cc_needs_belf" >&6; } - if test yes != "$lt_cv_cc_needs_belf"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS=$SAVE_CFLAGS - fi - ;; -*-*solaris*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) - case $host in - i?86-*-solaris*|x86_64-*-solaris*) - LD="${LD-ld} -m elf_x86_64" - ;; - sparc*-*-solaris*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - # GNU ld 2.21 introduced _sol2 emulations. Use them if available. - if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD=${LD-ld}_sol2 - fi - ;; - *) - if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then - LD="${LD-ld} -64" - fi - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; -esac - -need_locks=$enable_libtool_lock - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. -set dummy ${ac_tool_prefix}mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$MANIFEST_TOOL"; then - ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL -if test -n "$MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 -printf '%s\n' "$MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_MANIFEST_TOOL"; then - ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL - # Extract the first word of "mt", so it can be a program name with args. -set dummy mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_MANIFEST_TOOL"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL -if test -n "$ac_ct_MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 -printf '%s\n' "$ac_ct_MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_MANIFEST_TOOL" = x; then - MANIFEST_TOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL - fi -else - MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" -fi - -test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 -printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } -if test ${lt_cv_path_manifest_tool+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_path_manifest_tool=no - echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 - $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out - cat conftest.err >&5 - if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_manifest_tool=yes - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_manifest_tool" >&5 -printf '%s\n' "$lt_cv_path_manifest_tool" >&6; } -if test yes != "$lt_cv_path_manifest_tool"; then - MANIFEST_TOOL=: -fi - - - - - - - case $host_os in - rhapsody* | darwin*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. -set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DSYMUTIL"; then - ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DSYMUTIL=$ac_cv_prog_DSYMUTIL -if test -n "$DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 -printf '%s\n' "$DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DSYMUTIL"; then - ac_ct_DSYMUTIL=$DSYMUTIL - # Extract the first word of "dsymutil", so it can be a program name with args. -set dummy dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DSYMUTIL"; then - ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL -if test -n "$ac_ct_DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 -printf '%s\n' "$ac_ct_DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DSYMUTIL" = x; then - DSYMUTIL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DSYMUTIL=$ac_ct_DSYMUTIL - fi -else - DSYMUTIL="$ac_cv_prog_DSYMUTIL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. -set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$NMEDIT"; then - ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -NMEDIT=$ac_cv_prog_NMEDIT -if test -n "$NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 -printf '%s\n' "$NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_NMEDIT"; then - ac_ct_NMEDIT=$NMEDIT - # Extract the first word of "nmedit", so it can be a program name with args. -set dummy nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_NMEDIT"; then - ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_NMEDIT="nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT -if test -n "$ac_ct_NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 -printf '%s\n' "$ac_ct_NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_NMEDIT" = x; then - NMEDIT=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - NMEDIT=$ac_ct_NMEDIT - fi -else - NMEDIT="$ac_cv_prog_NMEDIT" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. -set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$LIPO"; then - ac_cv_prog_LIPO="$LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -LIPO=$ac_cv_prog_LIPO -if test -n "$LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 -printf '%s\n' "$LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LIPO"; then - ac_ct_LIPO=$LIPO - # Extract the first word of "lipo", so it can be a program name with args. -set dummy lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_LIPO"; then - ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_LIPO="lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO -if test -n "$ac_ct_LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 -printf '%s\n' "$ac_ct_LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_LIPO" = x; then - LIPO=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LIPO=$ac_ct_LIPO - fi -else - LIPO="$ac_cv_prog_LIPO" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -printf '%s\n' "$OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL="otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -printf '%s\n' "$ac_ct_OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OTOOL64"; then - ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL64=$ac_cv_prog_OTOOL64 -if test -n "$OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 -printf '%s\n' "$OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL64"; then - ac_ct_OTOOL64=$OTOOL64 - # Extract the first word of "otool64", so it can be a program name with args. -set dummy otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OTOOL64"; then - ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL64="otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 -if test -n "$ac_ct_OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 -printf '%s\n' "$ac_ct_OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL64" = x; then - OTOOL64=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL64=$ac_ct_OTOOL64 - fi -else - OTOOL64="$ac_cv_prog_OTOOL64" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 -printf %s "checking for -single_module linker flag... " >&6; } -if test ${lt_cv_apple_cc_single_mod+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_apple_cc_single_mod=no - if test -z "$LT_MULTI_MODULE"; then - # By default we will add the -single_module flag. You can override - # by either setting the environment variable LT_MULTI_MODULE - # non-empty at configure time, or by adding -multi_module to the - # link flags. - rm -rf libconftest.dylib* - echo "int foo(void){return 1;}" > conftest.c - echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ --dynamiclib -Wl,-single_module conftest.c" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ - -dynamiclib -Wl,-single_module conftest.c 2>conftest.err - _lt_result=$? - # If there is a non-empty error log, and "single_module" - # appears in it, assume the flag caused a linker warning - if test -s conftest.err && $GREP single_module conftest.err; then - cat conftest.err >&5 - # Otherwise, if the output was created with a 0 exit code from - # the compiler, it worked. - elif test -f libconftest.dylib && test 0 = "$_lt_result"; then - lt_cv_apple_cc_single_mod=yes - else - cat conftest.err >&5 - fi - rm -rf libconftest.dylib* - rm -f conftest.* - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 -printf '%s\n' "$lt_cv_apple_cc_single_mod" >&6; } - - # Feature test to disable chained fixups since it is not - # compatible with '-undefined dynamic_lookup' - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -no_fixup_chains linker flag" >&5 -printf %s "checking for -no_fixup_chains linker flag... " >&6; } -if test ${lt_cv_support_no_fixup_chains+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -Wl,-no_fixup_chains" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_support_no_fixup_chains=yes -else case e in @%:@( - e) lt_cv_support_no_fixup_chains=no - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_support_no_fixup_chains" >&5 -printf '%s\n' "$lt_cv_support_no_fixup_chains" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 -printf %s "checking for -exported_symbols_list linker flag... " >&6; } -if test ${lt_cv_ld_exported_symbols_list+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_exported_symbols_list=no - save_LDFLAGS=$LDFLAGS - echo "_main" > conftest.sym - LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_ld_exported_symbols_list=yes -else case e in @%:@( - e) lt_cv_ld_exported_symbols_list=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 -printf '%s\n' "$lt_cv_ld_exported_symbols_list" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 -printf %s "checking for -force_load linker flag... " >&6; } -if test ${lt_cv_ld_force_load+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5 - $AR $AR_FLAGS libconftest.a conftest.o 2>&5 - echo "$RANLIB libconftest.a" >&5 - $RANLIB libconftest.a 2>&5 - cat > conftest.c << _LT_EOF -int main(void) { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -s conftest.err && $GREP force_load conftest.err; then - cat conftest.err >&5 - elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&5 - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 -printf '%s\n' "$lt_cv_ld_force_load" >&6; } - case $host_os in - rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; - darwin1.*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - darwin*) - case $MACOSX_DEPLOYMENT_TARGET,$host in - 10.[012],*|,*powerpc*-darwin[5-8]*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - *) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' - if test yes = "$lt_cv_support_no_fixup_chains"; then - as_fn_append _lt_dar_allow_undefined ' $wl-no_fixup_chains' - fi - ;; - esac - ;; - esac - if test yes = "$lt_cv_apple_cc_single_mod"; then - _lt_dar_single_mod='$single_module' - fi - _lt_dar_needs_single_mod=no - case $host_os in - rhapsody* | darwin1.*) - _lt_dar_needs_single_mod=yes ;; - darwin*) - # When targeting Mac OS X 10.4 (darwin 8) or later, - # -single_module is the default and -multi_module is unsupported. - # The toolchain on macOS 10.14 (darwin 18) and later cannot - # target any OS version that needs -single_module. - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*-darwin[567].*|10.[0-3],*-darwin[5-9].*|10.[0-3],*-darwin1[0-7].*) - _lt_dar_needs_single_mod=yes ;; - esac - ;; - esac - if test yes = "$lt_cv_ld_exported_symbols_list"; then - _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' - else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' - fi - if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then - _lt_dsymutil='~$DSYMUTIL $lib || :' - else - _lt_dsymutil= - fi - ;; - esac - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x@S|@2 in - x) - ;; - *:) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" - ;; - x:*) - eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" - ;; - *) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - esac -} - -ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default -" -if test "x$ac_cv_header_dlfcn_h" = xyes -then : - printf '%s\n' "@%:@define HAVE_DLFCN_H 1" >>confdefs.h - -fi - - - - - -# Set options - - - - enable_dlopen=no - - - enable_win32_dll=no - - - @%:@ Check whether --enable-shared was given. -if test ${enable_shared+y} -then : - enableval=$enable_shared; p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_shared=yes ;; -esac -fi - - - - - - - - - - @%:@ Check whether --enable-static was given. -if test ${enable_static+y} -then : - enableval=$enable_static; p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_static=yes ;; -esac -fi - - - - - - - - - - @%:@ Check whether --enable-pic was given. -if test ${enable_pic+y} -then : - enableval=$enable_pic; lt_p=${PACKAGE-default} - case $enableval in - yes|no) pic_mode=$enableval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) @%:@ Check whether --with-pic was given. -if test ${with_pic+y} -then : - withval=$with_pic; lt_p=${PACKAGE-default} - case $withval in - yes|no) pic_mode=$withval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $withval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) pic_mode=default ;; -esac -fi - - ;; -esac -fi - - - - - - - - - @%:@ Check whether --enable-fast-install was given. -if test ${enable_fast_install+y} -then : - enableval=$enable_fast_install; p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_fast_install=yes ;; -esac -fi - - - - - - - - - shared_archive_member_spec= -case $host,$enable_shared in -power*-*-aix[5-9]*,yes) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 -printf %s "checking which variant of shared library versioning to provide... " >&6; } - @%:@ Check whether --enable-aix-soname was given. -if test ${enable_aix_soname+y} -then : - enableval=$enable_aix_soname; case $enableval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --enable-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$enable_aix_soname -else case e in @%:@( - e) @%:@ Check whether --with-aix-soname was given. -if test ${with_aix_soname+y} -then : - withval=$with_aix_soname; case $withval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$with_aix_soname -else case e in @%:@( - e) if test ${lt_cv_with_aix_soname+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_with_aix_soname=aix ;; -esac -fi - ;; -esac -fi - - enable_aix_soname=$lt_cv_with_aix_soname ;; -esac -fi - - with_aix_soname=$enable_aix_soname - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 -printf '%s\n' "$with_aix_soname" >&6; } - if test aix != "$with_aix_soname"; then - # For the AIX way of multilib, we name the shared archive member - # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', - # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. - # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, - # the AIX toolchain works better with OBJECT_MODE set (default 32). - if test 64 = "${OBJECT_MODE-32}"; then - shared_archive_member_spec=shr_64 - else - shared_archive_member_spec=shr - fi - fi - ;; -*) - with_aix_soname=aix - ;; -esac - - - - - - - - - - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS=$ltmain - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -test -z "$LN_S" && LN_S="ln -s" - - - - - - - - - - - - - - -if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 -printf %s "checking for objdir... " >&6; } -if test ${lt_cv_objdir+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 -printf '%s\n' "$lt_cv_objdir" >&6; } -objdir=$lt_cv_objdir - - - - - -printf '%s\n' "@%:@define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h - - - - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Global variables: -ofile=libtool -can_build_shared=yes - -# All known linkers require a '.a' archive for static linking (except MSVC and -# ICC, which need '.lib'). -libext=a - -with_gnu_ld=$lt_cv_prog_gnu_ld - -old_CC=$CC -old_CFLAGS=$CFLAGS - -# Set sane defaults for various variables -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$LD" && LD=ld -test -z "$ac_objext" && ac_objext=o - -func_cc_basename $compiler -cc_basename=$func_cc_basename_result - - -# Only perform the check for file, if the check method requires it -test -z "$MAGIC_CMD" && MAGIC_CMD=file -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 -printf %s "checking for ${ac_tool_prefix}file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/${ac_tool_prefix}file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for file" >&5 -printf %s "checking for file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - else - MAGIC_CMD=: - fi -fi - - fi - ;; -esac - -# Use C for the default configuration in the libtool script - -lt_save_CC=$CC -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -objext=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(void){return(0);}' - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - -# Save the default compiler, since it gets overwritten when the other -# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. -compiler_DEFAULT=$CC - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - -lt_prog_compiler_no_builtin_flag= - -if test yes = "$GCC"; then - case $cc_basename in - nvcc*) - lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; - *) - lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; - esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if test ${lt_cv_prog_compiler_rtti_exceptions+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -printf '%s\n' "$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then - lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" -else - : -fi - -fi - - - - - - - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - - - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - -hard_links=nottested -if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then - # do not overwrite the value of need_locks provided by the user - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -printf %s "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -printf '%s\n' "$hard_links" >&6; } - if test no = "$hard_links"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 -printf '%s\n' "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - runpath_var= - allow_undefined_flag= - always_export_symbols=no - archive_cmds= - archive_expsym_cmds= - compiler_needs_object=no - enable_shared_with_static_runtimes=no - export_dynamic_flag_spec= - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - hardcode_automatic=no - hardcode_direct=no - hardcode_direct_absolute=no - hardcode_libdir_flag_spec= - hardcode_libdir_separator= - hardcode_minus_L=no - hardcode_shlibpath_var=unsupported - inherit_rpath=no - link_all_deplibs=unknown - module_cmds= - module_expsym_cmds= - old_archive_from_new_cmds= - old_archive_from_expsyms_cmds= - thread_safe_flag_spec= - whole_archive_flag_spec= - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ' (' and ')$', so one must not match beginning or - # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', - # as well as any symbol that contains 'd'. - exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - # Exclude shared library initialization/finalization symbols. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - if test yes != "$GCC"; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) - with_gnu_ld=yes - ;; - esac - - ld_shlibs=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test yes = "$with_gnu_ld"; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; - *\ \(GNU\ Binutils\)\ [3-9]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test yes = "$lt_use_gnu_ld_interface"; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='$wl' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='$wl--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' - else - whole_archive_flag_spec= - fi - supports_anon_versioning=no - case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test ia64 != "$host_cpu"; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.19, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. - -_LT_EOF - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='$wl--export-all-symbols' - allow_undefined_flag=unsupported - always_export_symbols=no - enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' - file_list_spec='@' - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file, use it as - # is; otherwise, prepend EXPORTS... - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs=no - fi - ;; - - haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - link_all_deplibs=no - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - interix[3-9]*) - hardcode_direct=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) - tmp_diet=no - if test linux-dietlibc = "$host_os"; then - case $cc_basename in - diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) - esac - fi - if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test no = "$tmp_diet" - then - tmp_addflag=' $pic_flag' - tmp_sharedflag='-shared' - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - lf95*) # Lahey Fortran 8.1 - whole_archive_flag_spec= - tmp_sharedflag='--shared' ;; - nagfor*) # NAGFOR 5.3 - tmp_sharedflag='-Wl,-shared' ;; - xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) - tmp_sharedflag='-qmkshrobj' - tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - ;; - esac - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' - fi - - case $cc_basename in - tcc*) - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='-rdynamic' - ;; - xlf* | bgf* | bgxlf* | mpixlf*) - # IBM XL Fortran 10.1 on PPC cannot create shared libs itself - whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' - fi - ;; - esac - else - ld_shlibs=no - fi - ;; - - *-mlibc) - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test no = "$ld_shlibs"; then - runpath_var= - hardcode_libdir_flag_spec= - export_dynamic_flag_spec= - whole_archive_flag_spec= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix[4-9]*) - if test ia64 = "$host_cpu"; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag= - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to GNU nm, but means don't demangle to AIX nm. - # Without the "-l" option, or with the "-B" option, AIX nm treats - # weak defined symbols like other global defined symbols, whereas - # GNU nm marks them as "W". - # While the 'weak' keyword is ignored in the Export File, we need - # it in the Import File for the 'aix-soname' feature, so we have - # to replace the "-B" option with "-P" for AIX nm. - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # have runtime linking enabled, and use it for executables. - # For shared libraries, we enable/disable runtime linking - # depending on the kind of the shared library created - - # when "with_aix_soname,aix_use_runtimelinking" is: - # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables - # "aix,yes" lib.so shared, rtl:yes, for executables - # lib.a static archive - # "both,no" lib.so.V(shr.o) shared, rtl:yes - # lib.a(lib.so.V) shared, rtl:no, for executables - # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a(lib.so.V) shared, rtl:no - # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a static archive - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then - aix_use_runtimelinking=yes - break - fi - done - if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then - # With aix-soname=svr4, we create the lib.so.V shared archives only, - # so we don't have lib.a shared libs to link our executables. - # We have to force runtime linking in this case. - aix_use_runtimelinking=yes - LDFLAGS="$LDFLAGS -Wl,-brtl" - fi - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds='' - hardcode_direct=yes - hardcode_direct_absolute=yes - hardcode_libdir_separator=':' - link_all_deplibs=yes - file_list_spec='$wl-f,' - case $with_aix_soname,$aix_use_runtimelinking in - aix,*) ;; # traditional, no import file - svr4,* | *,yes) # use import file - # The Import File defines what to hardcode. - hardcode_direct=no - hardcode_direct_absolute=no - ;; - esac - - if test yes = "$GCC"; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`$CC -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - shared_flag='-shared' - if test yes = "$aix_use_runtimelinking"; then - shared_flag="$shared_flag "'$wl-G' - fi - # Need to ensure runtime linking is disabled for the traditional - # shared library, or the linker may eventually find shared libraries - # /with/ Import File - we do not want to mix them. - shared_flag_aix='-shared' - shared_flag_svr4='-shared $wl-G' - else - # not using gcc - if test ia64 = "$host_cpu"; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test yes = "$aix_use_runtimelinking"; then - shared_flag='$wl-G' - else - shared_flag='$wl-bM:SRE' - fi - shared_flag_aix='$wl-bM:SRE' - shared_flag_svr4='$wl-G' - fi - fi - - export_dynamic_flag_spec='$wl-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols=yes - if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag='-berok' - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag - else - if test ia64 = "$host_cpu"; then - hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' - allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag=' $wl-bernotok' - allow_undefined_flag=' $wl-berok' - if test yes = "$with_gnu_ld"; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - fi - archive_cmds_need_lc=yes - archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' - # -brtl affects multiple linker settings, -berok does not and is overridden later - compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' - if test svr4 != "$with_aix_soname"; then - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' - fi - if test aix != "$with_aix_soname"; then - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' - else - # used by -dlpreopen to get the symbols - archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' - fi - archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' - fi - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - bsdi[45]*) - export_dynamic_flag_spec=-rdynamic - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - case $cc_basename in - cl* | icl*) - # Native MSVC or ICC - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - always_export_symbols=yes - file_list_spec='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -Fe$output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp "$export_symbols" "$output_objdir/$soname.def"; - echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; - else - $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -Fe$tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, )='true' - enable_shared_with_static_runtimes=yes - exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - # Don't use ranlib - old_postinstall_cmds='chmod 644 $oldlib' - postlink_cmds='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile=$lt_outputfile.exe - lt_tool_outputfile=$lt_tool_outputfile.exe - ;; - esac~ - if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # Assume MSVC and ICC wrapper - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - enable_shared_with_static_runtimes=yes - ;; - esac - ;; - - darwin* | rhapsody*) - - - archive_cmds_need_lc=no - hardcode_direct=no - hardcode_automatic=yes - hardcode_shlibpath_var=unsupported - if test yes = "$lt_cv_ld_force_load"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec='' - fi - link_all_deplibs=yes - allow_undefined_flag=$_lt_dar_allow_undefined - case $cc_basename in - ifort*|nagfor*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test yes = "$_lt_dar_can_shared"; then - output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" - archive_expsym_cmds="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" - module_expsym_cmds="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" - - else - ld_shlibs=no - fi - - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly* | midnightbsd*) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9*) - if test yes = "$GCC"; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - export_dynamic_flag_spec='$wl-E' - ;; - - hpux10*) - if test yes,no = "$GCC,$with_gnu_ld"; then - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - - hpux11*) - if test yes,no = "$GCC,$with_gnu_ld"; then - case $host_cpu in - hppa*64*) - archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 -printf %s "checking if $CC understands -b... " >&6; } -if test ${lt_cv_prog_compiler__b+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler__b=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -b" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler__b=yes - fi - else - lt_cv_prog_compiler__b=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 -printf '%s\n' "$lt_cv_prog_compiler__b" >&6; } - -if test yes = "$lt_cv_prog_compiler__b"; then - archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' -else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' -fi - - ;; - esac - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - hardcode_shlibpath_var=no - ;; - *) - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test yes = "$GCC"; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - # Try to use the -exported_symbol ld option, if it does not - # work, assume that -exports_file does not work either and - # implicitly export all symbols. - # This should be the same for all languages, so no per-tag cache variable. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 -printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } -if test ${lt_cv_irix_exported_symbol+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int foo (void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_irix_exported_symbol=yes -else case e in @%:@( - e) lt_cv_irix_exported_symbol=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 -printf '%s\n' "$lt_cv_irix_exported_symbol" >&6; } - if test yes = "$lt_cv_irix_exported_symbol"; then - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' - fi - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - inherit_rpath=yes - link_all_deplibs=yes - ;; - - linux*) - case $cc_basename in - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - ld_shlibs=yes - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - esac - ;; - - *-mlibc) - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - newsos6) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - hardcode_shlibpath_var=no - ;; - - *nto* | *qnx*) - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - hardcode_shlibpath_var=no - hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - else - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - fi - else - ld_shlibs=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - osf3*) - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - archive_cmds_need_lc='no' - hardcode_libdir_separator=: - ;; - - serenity*) - ;; - - solaris*) - no_undefined_flag=' -z defs' - if test yes = "$GCC"; then - wlarc='$wl' - archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - else - case `$CC -V 2>&1` in - *"Compilers 5.0"*) - wlarc='' - archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' - ;; - *) - wlarc='$wl' - archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - ;; - esac - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands '-z linker_flag'. GCC discards it without '$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test yes = "$GCC"; then - whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' - else - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs=yes - ;; - - sunos4*) - if test sequent = "$host_vendor"; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds='$CC -r -o $output$reload_objs' - hardcode_direct=no - ;; - motorola) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='$wl-z,text' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We CANNOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag='$wl-z,text' - allow_undefined_flag='$wl-z,nodefs' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-R,$libdir' - hardcode_libdir_separator=':' - link_all_deplibs=yes - export_dynamic_flag_spec='$wl-Bexport' - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - *) - ld_shlibs=no - ;; - esac - - if test sni = "$host_vendor"; then - case $host in - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='$wl-Blargedynsym' - ;; - esac - fi - fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 -printf '%s\n' "$ld_shlibs" >&6; } -test no = "$ld_shlibs" && can_build_shared=no - -with_gnu_ld=$with_gnu_ld - - - - - - - - - - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc=yes - - if test yes,yes = "$GCC,$enable_shared"; then - case $archive_cmds in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -printf %s "checking whether -lc should be explicitly linked in... " >&6; } -if test ${lt_cv_archive_cmds_need_lc+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc=no - else - lt_cv_archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 -printf '%s\n' "$lt_cv_archive_cmds_need_lc" >&6; } - archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -printf %s "checking dynamic linker characteristics... " >&6; } - -if test yes = "$GCC"; then - case $host_os in - darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; - *) lt_awk_arg='/^libraries:/' ;; - esac - case $host_os in - mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; - *) lt_sed_strip_eq='s|=/|/|g' ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary... - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - # ...but if some path component already ends with the multilib dir we assume - # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). - case "$lt_multi_os_dir; $lt_search_path_spec " in - "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) - lt_multi_os_dir= - ;; - esac - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" - elif test -n "$lt_multi_os_dir"; then - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS = " "; FS = "/|\n";} { - lt_foo = ""; - lt_count = 0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo = "/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[lt_foo]++; } - if (lt_freq[lt_foo] == 1) { print lt_foo; } -}'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's|/\([A-Za-z]:\)|\1|g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=.so -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - - - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='$libname$release$shared_ext$major' - ;; - -aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test ia64 = "$host_cpu"; then - # AIX 5 supports IA64 - library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line '#! .'. This would cause the generated library to - # depend on '.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # Using Import Files as archive members, it is possible to support - # filename-based versioning of shared library archives on AIX. While - # this would work for both with and without runtime linking, it will - # prevent static linking of such archives. So we do filename-based - # shared library versioning with .so extension only, which is used - # when both runtime linking and shared linking is enabled. - # Unfortunately, runtime linking may impact performance, so we do - # not want this to be the default eventually. Also, we use the - # versioned .so libs for executables only if there is the -brtl - # linker flag in LDFLAGS as well, or --enable-aix-soname=svr4 only. - # To allow for filename-based versioning support, we need to create - # libNAME.so.V as an archive file, containing: - # *) an Import File, referring to the versioned filename of the - # archive as well as the shared archive member, telling the - # bitwidth (32 or 64) of that shared object, and providing the - # list of exported symbols of that shared object, eventually - # decorated with the 'weak' keyword - # *) the shared object with the F_LOADONLY flag set, to really avoid - # it being seen by the linker. - # At run time we better use the real file rather than another symlink, - # but for link time we create the symlink libNAME.so -> libNAME.so.V - - case $with_aix_soname,$aix_use_runtimelinking in - # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - aix,yes) # traditional libtool - dynamic_linker='AIX unversionable lib.so' - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - aix,no) # traditional AIX only - dynamic_linker='AIX lib.a(lib.so.V)' - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - ;; - svr4,*) # full svr4 only - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,yes) # both, prefer svr4 - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # unpreferred sharedlib libNAME.a needs extra handling - postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' - postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,no) # both, prefer aix - dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling - postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' - postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' - ;; - esac - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='$libname$shared_ext' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | windows* | pw32* | cegcc*) - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - # If user builds GCC with multilib enabled, - # it should just install on $(libdir) - # not on $(libdir)/../bin or 32 bits dlls would override 64 bit ones. - if test xyes = x"$multilib"; then - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - $install_prog $dir/$dlname $destdir/$dlname~ - chmod a+x $destdir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib $destdir/$dlname'\'' || exit \$?; - fi' - else - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - fi - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" - ;; - mingw* | windows* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl* | *,icl*) - # Native MSVC or ICC - libname_spec='$name' - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - library_names_spec='$libname.dll.lib' - - case $build_os in - mingw* | windows*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec=$LIB - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC and ICC wrapper - library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' - soname_spec='$libname$release$major$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly* | midnightbsd*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - need_version=yes - ;; - esac - case $host_cpu in - powerpc64) - # On FreeBSD bi-arch platforms, a different variable is used for 32-bit - # binaries. See . - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int test_pointer_size[sizeof (void *) - 5]; - -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - shlibpath_var=LD_LIBRARY_PATH -else case e in @%:@( - e) shlibpath_var=LD_32_LIBRARY_PATH ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; - *) - shlibpath_var=LD_LIBRARY_PATH - ;; - esac - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/boot/system/non-packaged/develop/lib /boot/system/develop/lib' - sys_lib_dlsearch_path_spec='/boot/home/config/non-packaged/lib /boot/home/config/lib /boot/system/non-packaged/lib /boot/system/lib' - hardcode_into_libs=no - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - if test 32 = "$HPUX_IA64_MODE"; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - sys_lib_dlsearch_path_spec=/usr/lib/hpux32 - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - sys_lib_dlsearch_path_spec=/usr/lib/hpux64 - fi - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test yes = "$lt_cv_prog_gnu_ld"; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" - sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -linux*android*) - version_type=none # Android doesn't support versioned libraries. - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - dynamic_linker='Android linker' - # -rpath works at least for libraries that are not overridden by - # libraries installed in system locations. - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if test ${lt_cv_shlibpath_overrides_runpath+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null -then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - ;; -esac -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Ideally, we could use ldconfig to report *all* directories which are - # searched for libraries, however this is still not possible. Aside from not - # being certain /sbin/ldconfig is available, command - # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, - # even though it is searched at run-time. Try to do the best guess by - # appending ld.so.conf contents (and includes) to the search path. - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -*-mlibc) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='mlibc ld.so' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec=/usr/lib - need_lib_prefix=no - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - need_version=no - else - need_version=yes - fi - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -os2*) - libname_spec='$name' - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - # OS/2 can only load a DLL with a base name of 8 characters or less. - soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; - v=$($ECHO $release$versuffix | tr -d .-); - n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); - $ECHO $n$v`$shared_ext' - library_names_spec='${libname}_dll.$libext' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=BEGINLIBPATH - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - -rdos*) - dynamic_linker=no - ;; - -serenity*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - dynamic_linker='SerenityOS LibELF' - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test yes = "$with_gnu_ld"; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec; then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' - soname_spec='$libname$shared_ext.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=sco - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test yes = "$with_gnu_ld"; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -emscripten*) - version_type=none - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - dynamic_linker="Emscripten linker" - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - -='-fPIC' - archive_cmds='$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib -s EXPORTED_FUNCTIONS=@$output_objdir/$soname.expsym' - archive_cmds_need_lc=no - no_undefined_flag= - ;; - -*) - dynamic_linker=no - ;; -esac -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -printf '%s\n' "$dynamic_linker" >&6; } -test no = "$dynamic_linker" && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test yes = "$GCC"; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then - sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec -fi - -if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then - sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec -fi - -# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... -configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec - -# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code -func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" - -# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool -configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -printf %s "checking how to hardcode library paths into programs... " >&6; } -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || - test -n "$runpath_var" || - test yes = "$hardcode_automatic"; then - - # We can hardcode non-existent directories. - if test no != "$hardcode_direct" && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && - test no != "$hardcode_minus_L"; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 -printf '%s\n' "$hardcode_action" >&6; } - -if test relink = "$hardcode_action" || - test yes = "$inherit_rpath"; then - # Fast installation is not supported - enable_fast_install=no -elif test yes = "$shlibpath_overrides_runpath" || - test no = "$enable_shared"; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - if test yes != "$enable_dlopen"; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen=load_add_on - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | windows* | pw32* | cegcc*) - lt_cv_dlopen=LoadLibrary - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in @%:@( - e) - lt_cv_dlopen=dyld - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; -esac -fi - - ;; - - tpf*) - # Don't try to run any link tests for TPF. We know it's impossible - # because TPF is a cross-compiler, and we know how we open DSOs. - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - lt_cv_dlopen_self=no - ;; - - *) - ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" -if test "x$ac_cv_func_shl_load" = xyes -then : - lt_cv_dlopen=shl_load -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 -printf %s "checking for shl_load in -ldld... " >&6; } -if test ${ac_cv_lib_dld_shl_load+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (void); -int -main (void) -{ -return shl_load (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_shl_load=yes -else case e in @%:@( - e) ac_cv_lib_dld_shl_load=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 -printf '%s\n' "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes -then : - lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld -else case e in @%:@( - e) ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes -then : - lt_cv_dlopen=dlopen -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 -printf %s "checking for dlopen in -lsvld... " >&6; } -if test ${ac_cv_lib_svld_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_svld_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_svld_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_svld_dlopen" >&6; } -if test "x$ac_cv_lib_svld_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 -printf %s "checking for dld_link in -ldld... " >&6; } -if test ${ac_cv_lib_dld_dld_link+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (void); -int -main (void) -{ -return dld_link (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_dld_link=yes -else case e in @%:@( - e) ac_cv_lib_dld_dld_link=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 -printf '%s\n' "$ac_cv_lib_dld_dld_link" >&6; } -if test "x$ac_cv_lib_dld_dld_link" = xyes -then : - lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; - esac - - if test no = "$lt_cv_dlopen"; then - enable_dlopen=no - else - enable_dlopen=yes - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS=$CPPFLAGS - test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS=$LDFLAGS - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS=$LIBS - LIBS="$lt_cv_dlopen_libs $LIBS" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 -printf %s "checking whether a program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 -printf '%s\n' "$lt_cv_dlopen_self" >&6; } - - if test yes = "$lt_cv_dlopen_self"; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 -printf %s "checking whether a statically linked program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self_static+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self_static=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self_static=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 -printf '%s\n' "$lt_cv_dlopen_self_static" >&6; } - fi - - CPPFLAGS=$save_CPPFLAGS - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - - - - - - - - - - - - - - - - - -striplib= -old_striplib= -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 -printf %s "checking whether stripping libraries is possible... " >&6; } -if test -z "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -else - if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - case $host_os in - darwin*) - # FIXME - insert some real tests, host_os isn't really good enough - striplib="$STRIP -x" - old_striplib="$STRIP -S" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - ;; - freebsd*) - if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - fi - ;; - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - ;; - esac - fi -fi - - - - - - - - - - - - - # Report what library types will actually be built - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 -printf %s "checking if libtool supports shared libraries... " >&6; } - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 -printf '%s\n' "$can_build_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 -printf %s "checking whether to build shared libraries... " >&6; } - test no = "$can_build_shared" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test yes = "$enable_shared" && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - - aix[4-9]*) - if test ia64 != "$host_cpu"; then - case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in - yes,aix,yes) ;; # shared object as lib.so file only - yes,svr4,*) ;; # shared object as lib.so archive member only - yes,*) enable_static=no ;; # shared object in lib.a archive as well - esac - fi - ;; - esac - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 -printf '%s\n' "$enable_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 -printf %s "checking whether to build static libraries... " >&6; } - # Make sure either enable_shared or enable_static is yes. - test yes = "$enable_shared" || enable_static=yes - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 -printf '%s\n' "$enable_static" >&6; } - - - - -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC=$lt_save_CC - - - - - - - - - - - - - - - - ac_config_commands="$ac_config_commands libtool" - - - - -# Only expand once: - - - -# Require xorg-macros minimum of 1.12 for DocBook external references - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to detect undeclared functions" >&5 -printf %s "checking for $CC options to detect undeclared functions... " >&6; } -if test ${ac_cv_c_undeclared_builtin_options+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_save_CFLAGS=$CFLAGS - ac_cv_c_undeclared_builtin_options='cannot detect' - for ac_arg in '' -fno-builtin; do - CFLAGS="$ac_save_CFLAGS $ac_arg" - # This test program should *not* compile successfully. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -(void) strchr; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) # This test program should compile successfully. - # No library function is consistently available on - # freestanding implementations, so test against a dummy - # declaration. Include always-available headers on the - # off chance that they somehow elicit warnings. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include -extern void ac_decl (int, char *); - -int -main (void) -{ -(void) ac_decl (0, (char *) 0); - (void) ac_decl; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - if test x"$ac_arg" = x -then : - ac_cv_c_undeclared_builtin_options='none needed' -else case e in @%:@( - e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; -esac -fi - break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - done - CFLAGS=$ac_save_CFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 -printf '%s\n' "$ac_cv_c_undeclared_builtin_options" >&6; } - case $ac_cv_c_undeclared_builtin_options in @%:@( - 'cannot detect') : - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot make $CC report undeclared builtins -See 'config.log' for more details" "$LINENO" 5; } ;; @%:@( - 'none needed') : - ac_c_undeclared_builtin_options='' ;; @%:@( - *) : - ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to ignore future-version functions" >&5 -printf %s "checking for $CC options to ignore future-version functions... " >&6; } -if test ${ac_cv_c_future_darwin_options+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_compile_saved="$ac_compile" - ac_compile="$ac_compile -Werror=unguarded-availability-new" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if ! (defined __APPLE__ && defined __MACH__) - #error "-Werror=unguarded-availability-new not needed here" - #endif - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_future_darwin_options='-Werror=unguarded-availability-new' -else case e in @%:@( - e) ac_cv_c_future_darwin_options='none needed' ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_compile="$ac_compile_saved" - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_future_darwin_options" >&5 -printf '%s\n' "$ac_cv_c_future_darwin_options" >&6; } - case $ac_cv_c_future_darwin_options in @%:@( - 'none needed') : - ac_c_future_darwin_options='' ;; @%:@( - *) : - ac_c_future_darwin_options=$ac_cv_c_future_darwin_options ;; -esac - - - - - -ac_fn_check_decl "$LINENO" "__clang__" "ac_cv_have_decl___clang__" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___clang__" = xyes -then : - CLANGCC="yes" -else case e in @%:@( - e) CLANGCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__INTEL_COMPILER" "ac_cv_have_decl___INTEL_COMPILER" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___INTEL_COMPILER" = xyes -then : - INTELCC="yes" -else case e in @%:@( - e) INTELCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__SUNPRO_C" "ac_cv_have_decl___SUNPRO_C" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___SUNPRO_C" = xyes -then : - SUNCC="yes" -else case e in @%:@( - e) SUNCC="no" ;; -esac -fi - - - - - - - - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. -set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -PKG_CONFIG=$ac_cv_path_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -printf '%s\n' "$PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_path_PKG_CONFIG"; then - ac_pt_PKG_CONFIG=$PKG_CONFIG - # Extract the first word of "pkg-config", so it can be a program name with args. -set dummy pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $ac_pt_PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG -if test -n "$ac_pt_PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 -printf '%s\n' "$ac_pt_PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_pt_PKG_CONFIG" = x; then - PKG_CONFIG="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - PKG_CONFIG=$ac_pt_PKG_CONFIG - fi -else - PKG_CONFIG="$ac_cv_path_PKG_CONFIG" -fi - -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=0.9.0 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 -printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - PKG_CONFIG="" - fi -fi - - - - - -@%:@ Check whether --enable-selective-werror was given. -if test ${enable_selective_werror+y} -then : - enableval=$enable_selective_werror; SELECTIVE_WERROR=$enableval -else case e in @%:@( - e) SELECTIVE_WERROR=yes ;; -esac -fi - - - - - -# -v is too short to test reliably with XORG_TESTSET_CFLAG -if test "x$SUNCC" = "xyes"; then - BASE_CFLAGS="-v" -else - BASE_CFLAGS="" -fi - -# This chunk of warnings were those that existed in the legacy CWARNFLAGS - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wall" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wall" >&5 -printf %s "checking if $CC supports -Wall... " >&6; } - cacheid=xorg_cv_cc_flag__Wall - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wall" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-arith" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-arith" >&5 -printf %s "checking if $CC supports -Wpointer-arith... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_arith - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-arith" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-declarations" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-declarations" >&5 -printf %s "checking if $CC supports -Wmissing-declarations... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_declarations - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-declarations" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat=2" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat=2" >&5 -printf %s "checking if $CC supports -Wformat=2... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat_2 - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat=2" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat" >&5 -printf %s "checking if $CC supports -Wformat... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat" - found="yes" - fi - fi - - - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wstrict-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wstrict-prototypes" >&5 -printf %s "checking if $CC supports -Wstrict-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wstrict_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wstrict-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-prototypes" >&5 -printf %s "checking if $CC supports -Wmissing-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnested-externs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnested-externs" >&5 -printf %s "checking if $CC supports -Wnested-externs... " >&6; } - cacheid=xorg_cv_cc_flag__Wnested_externs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnested-externs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wbad-function-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wbad-function-cast" >&5 -printf %s "checking if $CC supports -Wbad-function-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wbad_function_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wbad-function-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wold-style-definition" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wold-style-definition" >&5 -printf %s "checking if $CC supports -Wold-style-definition... " >&6; } - cacheid=xorg_cv_cc_flag__Wold_style_definition - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wold-style-definition" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -fd" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -fd" >&5 -printf %s "checking if $CC supports -fd... " >&6; } - cacheid=xorg_cv_cc_flag__fd - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -fd" - found="yes" - fi - fi - - - - - -# This chunk adds additional warnings that could catch undesired effects. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wunused" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wunused" >&5 -printf %s "checking if $CC supports -Wunused... " >&6; } - cacheid=xorg_cv_cc_flag__Wunused - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wunused" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wuninitialized" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wuninitialized" >&5 -printf %s "checking if $CC supports -Wuninitialized... " >&6; } - cacheid=xorg_cv_cc_flag__Wuninitialized - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wuninitialized" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wshadow" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wshadow" >&5 -printf %s "checking if $CC supports -Wshadow... " >&6; } - cacheid=xorg_cv_cc_flag__Wshadow - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wshadow" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-noreturn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-noreturn" >&5 -printf %s "checking if $CC supports -Wmissing-noreturn... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_noreturn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-noreturn" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-format-attribute" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-format-attribute" >&5 -printf %s "checking if $CC supports -Wmissing-format-attribute... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_format_attribute - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-format-attribute" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wredundant-decls" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wredundant-decls" >&5 -printf %s "checking if $CC supports -Wredundant-decls... " >&6; } - cacheid=xorg_cv_cc_flag__Wredundant_decls - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wredundant-decls" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wlogical-op" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wlogical-op" >&5 -printf %s "checking if $CC supports -Wlogical-op... " >&6; } - cacheid=xorg_cv_cc_flag__Wlogical_op - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wlogical-op" - found="yes" - fi - fi - - - -# These are currently disabled because they are noisy. They will be enabled -# in the future once the codebase is sufficiently modernized to silence -# them. For now, I don't want them to drown out the other warnings. -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wparentheses]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-align]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-qual]) - -# Turn some warnings into errors, so we don't accidentally get successful builds -# when there are problems that should be fixed. - -if test "x$SELECTIVE_WERROR" = "xyes" ; then - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=implicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=implicit" >&5 -printf %s "checking if $CC supports -Werror=implicit... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_implicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=implicit" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" >&5 -printf %s "checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_NO_EXPLICIT_TYPE_GIVEN__errwarn_E_NO_IMPLICIT_DECL_ALLOWED - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=nonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=nonnull" >&5 -printf %s "checking if $CC supports -Werror=nonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_nonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=nonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=init-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=init-self" >&5 -printf %s "checking if $CC supports -Werror=init-self... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_init_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=init-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=main" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=main" >&5 -printf %s "checking if $CC supports -Werror=main... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_main - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=main" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=missing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=missing-braces" >&5 -printf %s "checking if $CC supports -Werror=missing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_missing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=missing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=sequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=sequence-point" >&5 -printf %s "checking if $CC supports -Werror=sequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_sequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=sequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=return-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=return-type" >&5 -printf %s "checking if $CC supports -Werror=return-type... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_return_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=return-type" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT" >&5 -printf %s "checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_FUNC_HAS_NO_RETURN_STMT - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=trigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=trigraphs" >&5 -printf %s "checking if $CC supports -Werror=trigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_trigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=trigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=array-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=array-bounds" >&5 -printf %s "checking if $CC supports -Werror=array-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_array_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=array-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=write-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=write-strings" >&5 -printf %s "checking if $CC supports -Werror=write-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_write_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=write-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=address" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=address" >&5 -printf %s "checking if $CC supports -Werror=address... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_address - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=address" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=int-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=int-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Werror=int-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_int_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=int-to-pointer-cast" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION" >&5 -printf %s "checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_BAD_PTR_INT_COMBINATION - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=pointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=pointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Werror=pointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_pointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=pointer-to-int-cast" - found="yes" - fi - fi - - # Also -errwarn=E_BAD_PTR_INT_COMBINATION -else -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&5 -printf '%s\n' "$as_me: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&2;} - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wimplicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wimplicit" >&5 -printf %s "checking if $CC supports -Wimplicit... " >&6; } - cacheid=xorg_cv_cc_flag__Wimplicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wimplicit" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnonnull" >&5 -printf %s "checking if $CC supports -Wnonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Wnonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Winit-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Winit-self" >&5 -printf %s "checking if $CC supports -Winit-self... " >&6; } - cacheid=xorg_cv_cc_flag__Winit_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Winit-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmain" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmain" >&5 -printf %s "checking if $CC supports -Wmain... " >&6; } - cacheid=xorg_cv_cc_flag__Wmain - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmain" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-braces" >&5 -printf %s "checking if $CC supports -Wmissing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wsequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wsequence-point" >&5 -printf %s "checking if $CC supports -Wsequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Wsequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wsequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wreturn-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wreturn-type" >&5 -printf %s "checking if $CC supports -Wreturn-type... " >&6; } - cacheid=xorg_cv_cc_flag__Wreturn_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wreturn-type" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wtrigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wtrigraphs" >&5 -printf %s "checking if $CC supports -Wtrigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Wtrigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wtrigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Warray-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Warray-bounds" >&5 -printf %s "checking if $CC supports -Warray-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Warray_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Warray-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wwrite-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wwrite-strings" >&5 -printf %s "checking if $CC supports -Wwrite-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Wwrite_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wwrite-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Waddress" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Waddress" >&5 -printf %s "checking if $CC supports -Waddress... " >&6; } - cacheid=xorg_cv_cc_flag__Waddress - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Waddress" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wint-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wint-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Wint-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wint_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wint-to-pointer-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Wpointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-to-int-cast" - found="yes" - fi - fi - - -fi - - - - - - - - CWARNFLAGS="$BASE_CFLAGS" - if test "x$GCC" = xyes ; then - CWARNFLAGS="$CWARNFLAGS -fno-strict-aliasing" - fi - - - - - - - - -@%:@ Check whether --enable-strict-compilation was given. -if test ${enable_strict_compilation+y} -then : - enableval=$enable_strict_compilation; STRICT_COMPILE=$enableval -else case e in @%:@( - e) STRICT_COMPILE=no ;; -esac -fi - - - - - - -STRICT_CFLAGS="" - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -pedantic" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -pedantic" >&5 -printf %s "checking if $CC supports -pedantic... " >&6; } - cacheid=xorg_cv_cc_flag__pedantic - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -pedantic" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror" >&5 -printf %s "checking if $CC supports -Werror... " >&6; } - cacheid=xorg_cv_cc_flag__Werror - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn" >&5 -printf %s "checking if $CC supports -errwarn... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -errwarn" - found="yes" - fi - fi - - - -# Earlier versions of gcc (eg: 4.2) support -Werror=attributes, but do not -# activate it with -Werror, so we add it here explicitly. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=attributes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=attributes" >&5 -printf %s "checking if $CC supports -Werror=attributes... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_attributes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror=attributes" - found="yes" - fi - fi - - - -if test "x$STRICT_COMPILE" = "xyes"; then - BASE_CFLAGS="$BASE_CFLAGS $STRICT_CFLAGS" - CWARNFLAGS="$CWARNFLAGS $STRICT_CFLAGS" -fi - - - - - - - - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_VERSION_MAJOR `echo $PACKAGE_VERSION | cut -d . -f 1` -_ACEOF - - PVM=`echo $PACKAGE_VERSION | cut -d . -f 2 | cut -d - -f 1` - if test "x$PVM" = "x"; then - PVM="0" - fi - -printf '%s\n' "@%:@define PACKAGE_VERSION_MINOR $PVM" >>confdefs.h - - PVP=`echo $PACKAGE_VERSION | cut -d . -f 3 | cut -d - -f 1` - if test "x$PVP" = "x"; then - PVP="0" - fi - -printf '%s\n' "@%:@define PACKAGE_VERSION_PATCHLEVEL $PVP" >>confdefs.h - - - -CHANGELOG_CMD="((GIT_DIR=\$(top_srcdir)/.git git log > \$(top_srcdir)/.changelog.tmp) 2>/dev/null && \ -mv \$(top_srcdir)/.changelog.tmp \$(top_srcdir)/ChangeLog) \ -|| (rm -f \$(top_srcdir)/.changelog.tmp; test -e \$(top_srcdir)/ChangeLog || ( \ -touch \$(top_srcdir)/ChangeLog; \ -echo 'git failed to create ChangeLog: installing empty ChangeLog.' >&2))" - - - - -macros_datadir=`$PKG_CONFIG --print-errors --variable=pkgdatadir xorg-macros` -INSTALL_CMD="(cp -f "$macros_datadir/INSTALL" \$(top_srcdir)/.INSTALL.tmp && \ -mv \$(top_srcdir)/.INSTALL.tmp \$(top_srcdir)/INSTALL) \ -|| (rm -f \$(top_srcdir)/.INSTALL.tmp; test -e \$(top_srcdir)/INSTALL || ( \ -touch \$(top_srcdir)/INSTALL; \ -echo 'failed to copy INSTALL from util-macros: installing empty INSTALL.' >&2))" - - - - - - -case $host_os in - solaris*) - # Solaris 2.0 - 11.3 use SysV man page section numbers, so we - # check for a man page file found in later versions that use - # traditional section numbers instead - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for /usr/share/man/man7/attributes.7" >&5 -printf %s "checking for /usr/share/man/man7/attributes.7... " >&6; } -if test ${ac_cv_file__usr_share_man_man7_attributes_7+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) test "$cross_compiling" = yes && - as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 -if test -r "/usr/share/man/man7/attributes.7"; then - ac_cv_file__usr_share_man_man7_attributes_7=yes -else - ac_cv_file__usr_share_man_man7_attributes_7=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__usr_share_man_man7_attributes_7" >&5 -printf '%s\n' "$ac_cv_file__usr_share_man_man7_attributes_7" >&6; } -if test "x$ac_cv_file__usr_share_man_man7_attributes_7" = xyes -then : - SYSV_MAN_SECTIONS=false -else case e in @%:@( - e) SYSV_MAN_SECTIONS=true ;; -esac -fi - - ;; - *) SYSV_MAN_SECTIONS=false ;; -esac - -if test x$APP_MAN_SUFFIX = x ; then - APP_MAN_SUFFIX=1 -fi -if test x$APP_MAN_DIR = x ; then - APP_MAN_DIR='$(mandir)/man$(APP_MAN_SUFFIX)' -fi - -if test x$LIB_MAN_SUFFIX = x ; then - LIB_MAN_SUFFIX=3 -fi -if test x$LIB_MAN_DIR = x ; then - LIB_MAN_DIR='$(mandir)/man$(LIB_MAN_SUFFIX)' -fi - -if test x$FILE_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) FILE_MAN_SUFFIX=4 ;; - *) FILE_MAN_SUFFIX=5 ;; - esac -fi -if test x$FILE_MAN_DIR = x ; then - FILE_MAN_DIR='$(mandir)/man$(FILE_MAN_SUFFIX)' -fi - -if test x$MISC_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) MISC_MAN_SUFFIX=5 ;; - *) MISC_MAN_SUFFIX=7 ;; - esac -fi -if test x$MISC_MAN_DIR = x ; then - MISC_MAN_DIR='$(mandir)/man$(MISC_MAN_SUFFIX)' -fi - -if test x$DRIVER_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) DRIVER_MAN_SUFFIX=7 ;; - *) DRIVER_MAN_SUFFIX=4 ;; - esac -fi -if test x$DRIVER_MAN_DIR = x ; then - DRIVER_MAN_DIR='$(mandir)/man$(DRIVER_MAN_SUFFIX)' -fi - -if test x$ADMIN_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) ADMIN_MAN_SUFFIX=1m ;; - *) ADMIN_MAN_SUFFIX=8 ;; - esac -fi -if test x$ADMIN_MAN_DIR = x ; then - ADMIN_MAN_DIR='$(mandir)/man$(ADMIN_MAN_SUFFIX)' -fi - - - - - - - - - - - - - - - -XORG_MAN_PAGE="X Version 11" - -MAN_SUBSTS="\ - -e 's|__vendorversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xorgversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xservername__|Xorg|g' \ - -e 's|__xconfigfile__|xorg.conf|g' \ - -e 's|__projectroot__|\$(prefix)|g' \ - -e 's|__apploaddir__|\$(appdefaultdir)|g' \ - -e 's|__appmansuffix__|\$(APP_MAN_SUFFIX)|g' \ - -e 's|__drivermansuffix__|\$(DRIVER_MAN_SUFFIX)|g' \ - -e 's|__adminmansuffix__|\$(ADMIN_MAN_SUFFIX)|g' \ - -e 's|__libmansuffix__|\$(LIB_MAN_SUFFIX)|g' \ - -e 's|__miscmansuffix__|\$(MISC_MAN_SUFFIX)|g' \ - -e 's|__filemansuffix__|\$(FILE_MAN_SUFFIX)|g'" - - - - -AM_DEFAULT_VERBOSITY=0 - - - - - - -@%:@ Check whether --enable-specs was given. -if test ${enable_specs+y} -then : - enableval=$enable_specs; build_specs=$enableval -else case e in @%:@( - e) build_specs=yes ;; -esac -fi - - - if test x$build_specs = xyes; then - ENABLE_SPECS_TRUE= - ENABLE_SPECS_FALSE='#' -else - ENABLE_SPECS_TRUE='#' - ENABLE_SPECS_FALSE= -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build functional specifications" >&5 -printf %s "checking whether to build functional specifications... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $build_specs" >&5 -printf '%s\n' "$build_specs" >&6; } - - - - - -@%:@ Check whether --with-xmlto was given. -if test ${with_xmlto+y} -then : - withval=$with_xmlto; use_xmlto=$withval -else case e in @%:@( - e) use_xmlto=auto ;; -esac -fi - - - -if test "x$use_xmlto" = x"auto"; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto not found - documentation targets will be skipped" >&2;} - have_xmlto=no - else - have_xmlto=yes - fi -elif test "x$use_xmlto" = x"yes" ; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - as_fn_error $? "--with-xmlto=yes specified but xmlto not found in PATH" "$LINENO" 5 - fi - have_xmlto=yes -elif test "x$use_xmlto" = x"no" ; then - if test "x$XMLTO" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&2;} - fi - have_xmlto=no -else - as_fn_error $? "--with-xmlto expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of xmlto, if provided. -if test "$have_xmlto" = yes; then - # scrape the xmlto version - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the xmlto version" >&5 -printf %s "checking the xmlto version... " >&6; } - xmlto_version=`$XMLTO --version 2>/dev/null | cut -d' ' -f3` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xmlto_version" >&5 -printf '%s\n' "$xmlto_version" >&6; } - as_arg_v1=$xmlto_version -as_arg_v2=0.0.22 -awk "$as_awk_strverscmp" v1="$as_arg_v1" v2="$as_arg_v2" /dev/null -case $? in @%:@( - 1) : - if test "x$use_xmlto" = xauto; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&5 -printf '%s\n' "$as_me: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&2;} - have_xmlto=no - else - as_fn_error $? "xmlto version $xmlto_version found, but 0.0.22 needed" "$LINENO" 5 - fi ;; @%:@( - 0) : - ;; @%:@( - 2) : - ;; @%:@( - *) : - ;; -esac -fi - -# Test for the ability of xmlto to generate a text target -# -# NOTE: xmlto 0.0.27 or higher return a non-zero return code in the -# following test for empty XML docbook files. -# For compatibility reasons use the following empty XML docbook file and if -# it fails try it again with a non-empty XML file. -have_xmlto_text=no -cat > conftest.xml << "EOF" -EOF -if test "$have_xmlto" = yes -then : - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in @%:@( - e) # Try it again with a non-empty XML file. - cat > conftest.xml << "EOF" - -EOF - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto cannot generate text format, this format skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto cannot generate text format, this format skipped" >&2;} ;; -esac -fi ;; -esac -fi -fi -rm -f conftest.xml - if test $have_xmlto_text = yes; then - HAVE_XMLTO_TEXT_TRUE= - HAVE_XMLTO_TEXT_FALSE='#' -else - HAVE_XMLTO_TEXT_TRUE='#' - HAVE_XMLTO_TEXT_FALSE= -fi - - if test "$have_xmlto" = yes; then - HAVE_XMLTO_TRUE= - HAVE_XMLTO_FALSE='#' -else - HAVE_XMLTO_TRUE='#' - HAVE_XMLTO_FALSE= -fi - - - - - - -@%:@ Check whether --with-fop was given. -if test ${with_fop+y} -then : - withval=$with_fop; use_fop=$withval -else case e in @%:@( - e) use_fop=auto ;; -esac -fi - - - -if test "x$use_fop" = x"auto"; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: fop not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: fop not found - documentation targets will be skipped" >&2;} - have_fop=no - else - have_fop=yes - fi -elif test "x$use_fop" = x"yes" ; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - as_fn_error $? "--with-fop=yes specified but fop not found in PATH" "$LINENO" 5 - fi - have_fop=yes -elif test "x$use_fop" = x"no" ; then - if test "x$FOP" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&2;} - fi - have_fop=no -else - as_fn_error $? "--with-fop expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of fop, if provided. - - if test "$have_fop" = yes; then - HAVE_FOP_TRUE= - HAVE_FOP_FALSE='#' -else - HAVE_FOP_TRUE='#' - HAVE_FOP_FALSE= -fi - - - - -# Preserves the interface, should it be implemented later - - - -@%:@ Check whether --with-xsltproc was given. -if test ${with_xsltproc+y} -then : - withval=$with_xsltproc; use_xsltproc=$withval -else case e in @%:@( - e) use_xsltproc=auto ;; -esac -fi - - - -if test "x$use_xsltproc" = x"auto"; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xsltproc not found - cannot transform XML documents" >&5 -printf '%s\n' "$as_me: WARNING: xsltproc not found - cannot transform XML documents" >&2;} - have_xsltproc=no - else - have_xsltproc=yes - fi -elif test "x$use_xsltproc" = x"yes" ; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - as_fn_error $? "--with-xsltproc=yes specified but xsltproc not found in PATH" "$LINENO" 5 - fi - have_xsltproc=yes -elif test "x$use_xsltproc" = x"no" ; then - if test "x$XSLTPROC" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&2;} - fi - have_xsltproc=no -else - as_fn_error $? "--with-xsltproc expects 'yes' or 'no'" "$LINENO" 5 -fi - - if test "$have_xsltproc" = yes; then - HAVE_XSLTPROC_TRUE= - HAVE_XSLTPROC_FALSE='#' -else - HAVE_XSLTPROC_TRUE='#' - HAVE_XSLTPROC_FALSE= -fi - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for X.Org SGML entities >= 1.8" >&5 -printf %s "checking for X.Org SGML entities >= 1.8... " >&6; } -XORG_SGML_PATH= -if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xorg-sgml-doctools >= 1.8\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xorg-sgml-doctools >= 1.8") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools` -else - : - -fi - -# Define variables STYLESHEET_SRCDIR and XSL_STYLESHEET containing -# the path and the name of the doc stylesheet -if test "x$XORG_SGML_PATH" != "x" ; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XORG_SGML_PATH" >&5 -printf '%s\n' "$XORG_SGML_PATH" >&6; } - STYLESHEET_SRCDIR=$XORG_SGML_PATH/X11 - XSL_STYLESHEET=$STYLESHEET_SRCDIR/xorg.xsl -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - if test "x$XSL_STYLESHEET" != "x"; then - HAVE_STYLESHEETS_TRUE= - HAVE_STYLESHEETS_FALSE='#' -else - HAVE_STYLESHEETS_TRUE='#' - HAVE_STYLESHEETS_FALSE= -fi - - - -@%:@ Check whether --enable-malloc0returnsnull was given. -if test ${enable_malloc0returnsnull+y} -then : - enableval=$enable_malloc0returnsnull; MALLOC_ZERO_RETURNS_NULL=$enableval -else case e in @%:@( - e) MALLOC_ZERO_RETURNS_NULL=yes ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to act as if malloc(0) can return NULL" >&5 -printf %s "checking whether to act as if malloc(0) can return NULL... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MALLOC_ZERO_RETURNS_NULL" >&5 -printf '%s\n' "$MALLOC_ZERO_RETURNS_NULL" >&6; } - -if test "x$MALLOC_ZERO_RETURNS_NULL" = xyes; then - MALLOC_ZERO_CFLAGS="-DMALLOC_0_RETURNS_NULL" - XMALLOC_ZERO_CFLAGS=$MALLOC_ZERO_CFLAGS - XTMALLOC_ZERO_CFLAGS="$MALLOC_ZERO_CFLAGS -DXTMALLOC_BC" -else - MALLOC_ZERO_CFLAGS="" - XMALLOC_ZERO_CFLAGS="" - XTMALLOC_ZERO_CFLAGS="" -fi - - - - - - -# Determine .so library version per platform -# based on SharedXextRev in monolith xc/config/cf/*Lib.tmpl -if test "x$XEXT_SOREV" = "x" ; then - case $host_os in - openbsd*) XEXT_SOREV=8:0 ;; - solaris*) XEXT_SOREV=0 ;; - *) XEXT_SOREV=6:4:0 ;; - esac -fi - - -# Obtain compiler/linker options for dependencies - -pkg_failed=no -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" >&5 -printf %s "checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99... " >&6; } - -if test -n "$XEXT_CFLAGS"; then - pkg_cv_XEXT_CFLAGS="$XEXT_CFLAGS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_CFLAGS=`$PKG_CONFIG --cflags "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi -if test -n "$XEXT_LIBS"; then - pkg_cv_XEXT_LIBS="$XEXT_LIBS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_LIBS=`$PKG_CONFIG --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi - - - -if test $pkg_failed = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi - if test $_pkg_short_errors_supported = yes; then - XEXT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - else - XEXT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$XEXT_PKG_ERRORS" >&5 - - as_fn_error $? "Package requirements (xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99) were not met: - -$XEXT_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details." "$LINENO" 5 -elif test $pkg_failed = untried; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details. - -To get pkg-config, see . -See 'config.log' for more details" "$LINENO" 5; } -else - XEXT_CFLAGS=$pkg_cv_XEXT_CFLAGS - XEXT_LIBS=$pkg_cv_XEXT_LIBS - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - -fi - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for __builtin_popcountl" >&5 -printf %s "checking for __builtin_popcountl... " >&6; } -if test ${ax_cv_have___builtin_popcountl+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - __builtin_popcountl(0) - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ax_cv_have___builtin_popcountl=yes -else case e in @%:@( - e) ax_cv_have___builtin_popcountl=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have___builtin_popcountl" >&5 -printf '%s\n' "$ax_cv_have___builtin_popcountl" >&6; } - - if test yes = $ax_cv_have___builtin_popcountl -then : - -printf '%s\n' "@%:@define HAVE___BUILTIN_POPCOUNTL 1" >>confdefs.h - -fi - - - -ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" -if test "x$ac_cv_func_reallocarray" = xyes -then : - printf '%s\n' "@%:@define HAVE_REALLOCARRAY 1" >>confdefs.h - -else case e in @%:@( - e) case " $LIB@&t@OBJS " in - *" reallocarray.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS reallocarray.$ac_objext" - ;; -esac - ;; -esac -fi - - -# Allow checking code with lint, sparse, etc. - - - - - -@%:@ Check whether --with-lint was given. -if test ${with_lint+y} -then : - withval=$with_lint; use_lint=$withval -else case e in @%:@( - e) use_lint=no ;; -esac -fi - - -# Obtain platform specific info like program name and options -# The lint program on FreeBSD and NetBSD is different from the one on Solaris -case $host_os in - *linux* | *openbsd* | kfreebsd*-gnu | darwin* | cygwin*) - lint_name=splint - lint_options="-badflag" - ;; - *freebsd* | *netbsd*) - lint_name=lint - lint_options="-u -b" - ;; - *solaris*) - lint_name=lint - lint_options="-u -b -h -erroff=E_INDISTING_FROM_TRUNC2" - ;; -esac - -# Test for the presence of the program (either guessed by the code or spelled out by the user) -if test "x$use_lint" = x"yes" ; then - # Extract the first word of "$lint_name", so it can be a program name with args. -set dummy $lint_name; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_LINT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $LINT in - [\\/]* | ?:[\\/]*) - ac_cv_path_LINT="$LINT" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_LINT="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -LINT=$ac_cv_path_LINT -if test -n "$LINT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LINT" >&5 -printf '%s\n' "$LINT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$LINT" = "x"; then - as_fn_error $? "--with-lint=yes specified but lint-style tool not found in PATH" "$LINENO" 5 - fi -elif test "x$use_lint" = x"no" ; then - if test "x$LINT" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&2;} - fi -else - as_fn_error $? "--with-lint expects 'yes' or 'no'. Use LINT variable to specify path." "$LINENO" 5 -fi - -# User supplied flags override default flags -if test "x$LINT_FLAGS" != "x"; then - lint_options=$LINT_FLAGS -fi - -LINT_FLAGS=$lint_options - - if test "x$LINT" != x; then - LINT_TRUE= - LINT_FALSE='#' -else - LINT_TRUE='#' - LINT_FALSE= -fi - - - - - -@%:@ Check whether --enable-lint-library was given. -if test ${enable_lint_library+y} -then : - enableval=$enable_lint_library; make_lint_lib=$enableval -else case e in @%:@( - e) make_lint_lib=no ;; -esac -fi - - -if test "x$make_lint_lib" = x"yes" ; then - LINTLIB=llib-lXext.ln - if test "x$LINT" = "x"; then - as_fn_error $? "Cannot make lint library without --with-lint" "$LINENO" 5 - fi -elif test "x$make_lint_lib" != x"no" ; then - as_fn_error $? "--enable-lint-library expects 'yes' or 'no'." "$LINENO" 5 -fi - - - if test x$make_lint_lib != xno; then - MAKE_LINT_LIB_TRUE= - MAKE_LINT_LIB_FALSE='#' -else - MAKE_LINT_LIB_TRUE='#' - MAKE_LINT_LIB_FALSE= -fi - - - - -ac_config_files="$ac_config_files Makefile man/Makefile src/Makefile specs/Makefile xext.pc" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# 'ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* 'ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -ac_cache_dump | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -printf '%s\n' "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -printf '%s\n' "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIB@&t@OBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`printf '%s\n' "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIB@&t@OBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -printf %s "checking that generated files are newer than configure... " >&6; } - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: done" >&5 -printf '%s\n' "done" >&6; } -if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then - as_fn_error $? "conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; -esac -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi - - if test -n "$EXEEXT"; then - am__EXEEXT_TRUE= - am__EXEEXT_FALSE='#' -else - am__EXEEXT_TRUE='#' - am__EXEEXT_FALSE= -fi - -if test -z "${ENABLE_SPECS_TRUE}" && test -z "${ENABLE_SPECS_FALSE}"; then - as_fn_error $? "conditional \"ENABLE_SPECS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TEXT_TRUE}" && test -z "${HAVE_XMLTO_TEXT_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO_TEXT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TRUE}" && test -z "${HAVE_XMLTO_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_FOP_TRUE}" && test -z "${HAVE_FOP_FALSE}"; then - as_fn_error $? "conditional \"HAVE_FOP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XSLTPROC_TRUE}" && test -z "${HAVE_XSLTPROC_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XSLTPROC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_STYLESHEETS_TRUE}" && test -z "${HAVE_STYLESHEETS_FALSE}"; then - as_fn_error $? "conditional \"HAVE_STYLESHEETS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${LINT_TRUE}" && test -z "${LINT_FALSE}"; then - as_fn_error $? "conditional \"LINT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${MAKE_LINT_LIB_TRUE}" && test -z "${MAKE_LINT_LIB_FALSE}"; then - as_fn_error $? "conditional \"MAKE_LINT_LIB\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: "${CONFIG_STATUS=./config.status}" -case $CONFIG_STATUS in @%:@( - -*) : - CONFIG_STATUS=./$CONFIG_STATUS ;; @%:@( - */*) : - ;; @%:@( - *) : - CONFIG_STATUS=./$CONFIG_STATUS ;; -esac - -ac_write_fail=0 -ac_clean_CONFIG_STATUS='"$CONFIG_STATUS"' -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -printf '%s\n' "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >"$CONFIG_STATUS" <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>"$CONFIG_STATUS" <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in @%:@( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in @%:@( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - -exec 6>&1 -## ------------------------------------- ## -## Main body of "$CONFIG_STATUS" script. ## -## ------------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -'$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` -ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_cs_config='$ac_cs_config_escaped' -ac_cs_version="\\ -libXext config.status 1.3.7 -configured by $0, generated by GNU Autoconf 2.73, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2026 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -AWK='$AWK' -test -n "\$AWK" || { - awk '' >"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - printf '%s\n' "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - printf '%s\n' "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: '$1' -Try '$0 --help' for more information.";; - --help | --hel | -h ) - printf '%s\n' "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: '$1' -Try '$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \printf '%s\n' "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../@%:@@%:@ /;s/...$/ @%:@@%:@/;p;x;p;x' <<_ASBOX -@%:@@%:@ Running $as_me. @%:@@%:@ -_ASBOX - printf '%s\n' "$ac_log" -} >&5 - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" - - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='$sed_quote_subst' -double_quote_subst='$double_quote_subst' -delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' -macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' -enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' -enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' -pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' -shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' -SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' -ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' -PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' -host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' -host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' -host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' -build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' -build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' -build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' -SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' -Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' -GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' -EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' -FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' -LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' -NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' -LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' -ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' -exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' -lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' -lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' -lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' -reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' -FILECMD='`$ECHO "$FILECMD" | $SED "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' -file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' -want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' -DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' -sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' -AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' -lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' -archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' -STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' -RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' -lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' -CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' -compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' -GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' -lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' -nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' -lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' -lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' -objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' -need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' -MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' -LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' -OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' -libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' -module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' -postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' -need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' -version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' -runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' -libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' -soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' -install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' -finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' -configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' -old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' -striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' - -LTCC='$LTCC' -LTCFLAGS='$LTCFLAGS' -compiler='$compiler_DEFAULT' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in SHELL \ -ECHO \ -PATH_SEPARATOR \ -SED \ -GREP \ -EGREP \ -FGREP \ -LD \ -NM \ -LN_S \ -lt_SP2NL \ -lt_NL2SP \ -reload_flag \ -FILECMD \ -OBJDUMP \ -deplibs_check_method \ -file_magic_cmd \ -file_magic_glob \ -want_nocaseglob \ -DLLTOOL \ -sharedlib_from_linklib_cmd \ -AR \ -archiver_list_spec \ -STRIP \ -RANLIB \ -CC \ -CFLAGS \ -compiler \ -lt_cv_sys_global_symbol_pipe \ -lt_cv_sys_global_symbol_to_cdecl \ -lt_cv_sys_global_symbol_to_import \ -lt_cv_sys_global_symbol_to_c_name_address \ -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -lt_cv_nm_interface \ -nm_file_list_spec \ -lt_cv_truncate_bin \ -lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_pic \ -lt_prog_compiler_wl \ -lt_prog_compiler_static \ -lt_cv_prog_compiler_c_o \ -need_locks \ -MANIFEST_TOOL \ -DSYMUTIL \ -NMEDIT \ -LIPO \ -OTOOL \ -OTOOL64 \ -shrext_cmds \ -export_dynamic_flag_spec \ -whole_archive_flag_spec \ -compiler_needs_object \ -with_gnu_ld \ -allow_undefined_flag \ -no_undefined_flag \ -hardcode_libdir_flag_spec \ -hardcode_libdir_separator \ -exclude_expsyms \ -include_expsyms \ -file_list_spec \ -variables_saved_for_relink \ -libname_spec \ -library_names_spec \ -soname_spec \ -install_override_mode \ -finish_eval \ -old_striplib \ -striplib; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in reload_cmds \ -old_postinstall_cmds \ -old_postuninstall_cmds \ -old_archive_cmds \ -extract_expsyms_cmds \ -old_archive_from_new_cmds \ -old_archive_from_expsyms_cmds \ -archive_cmds \ -archive_expsym_cmds \ -module_cmds \ -module_expsym_cmds \ -export_symbols_cmds \ -prelink_cmds \ -postlink_cmds \ -postinstall_cmds \ -postuninstall_cmds \ -finish_cmds \ -sys_lib_search_path_spec \ -configure_time_dlsearch_path \ -configure_time_lt_sys_library_path; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -ac_aux_dir='$ac_aux_dir' - -# See if we are running on zsh, and set the options that allow our -# commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - - - PACKAGE='$PACKAGE' - VERSION='$VERSION' - RM='$RM' - ofile='$ofile' - - - - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; - "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; - "specs/Makefile") CONFIG_FILES="$CONFIG_FILES specs/Makefile" ;; - "xext.pc") CONFIG_FILES="$CONFIG_FILES xext.pc" ;; - - *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files - test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers - test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to '$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with './config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | sed -n '$='` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | sed -n '$='` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >"$CONFIG_STATUS" || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with './config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script 'defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >"$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - suffix = P[macro] D[macro] - while (suffix ~ /[\t ]$/) { - suffix = substr(suffix, 1, length(suffix) - 1) - } - # Preserve the white space surrounding the "#". - print prefix "define", macro suffix - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain ':'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf '%s\n' "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is 'configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - printf '%s\n' "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf '%s\n' "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf '%s\n' "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when '$srcdir' = '.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf '%s\n' "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf '%s\n' "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || { - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - case $CONFIG_FILES in @%:@( - *\'*) : - eval set x "$CONFIG_FILES" ;; @%:@( - *) : - set x $CONFIG_FILES ;; @%:@( - *) : - ;; -esac - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`printf '%s\n' "$am_mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`$as_dirname -- "$am_mf" || -$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$am_mf" : 'X\(//\)[^/]' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$am_mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - am_filepart=`$as_basename -- "$am_mf" || -$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$am_mf" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - { echo "$as_me:$LINENO: cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles" >&5 - (cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } || am_rc=$? - done - if test $am_rc -ne 0; then - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE=\"gmake\" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking). -See 'config.log' for more details" "$LINENO" 5; } - fi - { am_dirpart=; unset am_dirpart;} - { am_filepart=; unset am_filepart;} - { am_mf=; unset am_mf;} - { am_rc=; unset am_rc;} - rm -f conftest-deps.mk -} - ;; - "libtool":C) - - # See if we are running on zsh, and set the options that allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST - fi - - cfgfile=${ofile}T - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL -# Generated automatically by $as_me ($PACKAGE) $VERSION -# NOTE: Changes made to this file will be lost: look at ltmain.sh. - -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit, 1996 - -# Copyright (C) 2024 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program or library that is built -# using GNU Libtool, you may include this file under the same -# distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -# The names of the tagged configurations supported by this script. -available_tags='' - -# Configured defaults for sys_lib_dlsearch_path munging. -: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=$macro_version -macro_revision=$macro_revision - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# What type of objects to build. -pic_mode=$pic_mode - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# Shared archive member basename,for filename based shared library versioning on AIX. -shared_archive_member_spec=$shared_archive_member_spec - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The PATH separator for the build system. -PATH_SEPARATOR=$lt_PATH_SEPARATOR - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="\$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP=$lt_GREP - -# An ERE matcher. -EGREP=$lt_EGREP - -# A literal string matcher. -FGREP=$lt_FGREP - -# A BSD- or MS-compatible name lister. -NM=$lt_NM - -# Whether we need soft or hard links. -LN_S=$lt_LN_S - -# What is the maximum length of a command? -max_cmd_len=$max_cmd_len - -# Object file suffix (normally "o"). -objext=$ac_objext - -# Executable file suffix (normally ""). -exeext=$exeext - -# whether the shell understands "unset". -lt_unset=$lt_unset - -# turn spaces into newlines. -SP2NL=$lt_lt_SP2NL - -# turn newlines into spaces. -NL2SP=$lt_lt_NL2SP - -# convert \$build file names to \$host format. -to_host_file_cmd=$lt_cv_to_host_file_cmd - -# convert \$build files to toolchain format. -to_tool_file_cmd=$lt_cv_to_tool_file_cmd - -# A file(cmd) program that detects file types. -FILECMD=$lt_FILECMD - -# An object symbol dumper. -OBJDUMP=$lt_OBJDUMP - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method = "file_magic". -file_magic_cmd=$lt_file_magic_cmd - -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob=$lt_file_magic_glob - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob=$lt_want_nocaseglob - -# DLL creation program. -DLLTOOL=$lt_DLLTOOL - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd - -# The archiver. -AR=$lt_AR - -# Flags to create an archive (by configure). -lt_ar_flags=$lt_ar_flags - -# Flags to create an archive. -AR_FLAGS=\@S|@{ARFLAGS-"\@S|@lt_ar_flags"} - -# How to feed a file listing to the archiver. -archiver_list_spec=$lt_archiver_list_spec - -# A symbol stripping program. -STRIP=$lt_STRIP - -# Commands used to install an old-style archive. -RANLIB=$lt_RANLIB -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - -# A C compiler. -LTCC=$lt_CC - -# LTCC compiler flags. -LTCFLAGS=$lt_CFLAGS - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm into a list of symbols to manually relocate. -global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix - -# The name lister interface. -nm_interface=$lt_lt_cv_nm_interface - -# Specify filename containing input files for \$NM. -nm_file_list_spec=$lt_nm_file_list_spec - -# The root where to search for dependent libraries,and where our libraries should be installed. -lt_sysroot=$lt_sysroot - -# Command to truncate a binary pipe. -lt_truncate_bin=$lt_lt_cv_truncate_bin - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=$MAGIC_CMD - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Manifest tool. -MANIFEST_TOOL=$lt_MANIFEST_TOOL - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL=$lt_DSYMUTIL - -# Tool to change global to local symbols on Mac OS X. -NMEDIT=$lt_NMEDIT - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO=$lt_LIPO - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL=$lt_OTOOL - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64=$lt_OTOOL64 - -# Old archive suffix (normally "a"). -libext=$libext - -# Shared library suffix (normally ".so"). -shrext_cmds=$lt_shrext_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink=$lt_variables_saved_for_relink - -# Do we need the "lib" prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Library versioning type. -version_type=$version_type - -# Shared library runtime path variable. -runpath_var=$runpath_var - -# Shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - -# Command to use after installation of a shared archive. -postinstall_cmds=$lt_postinstall_cmds - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval=$lt_finish_eval - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Compile-time system search path for libraries. -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Detected run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path - -# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. -configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - - -# The linker used to build libraries. -LD=$lt_LD - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds - -# A language specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU compiler? -with_gcc=$GCC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e. impossible to change by setting \$shlibpath_var if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# ### END LIBTOOL CONFIG - -_LT_EOF - - cat <<'_LT_EOF' >> "$cfgfile" - -# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x@S|@2 in - x) - ;; - *:) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" - ;; - x:*) - eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" - ;; - *) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - esac -} - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in @S|@*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - - -# ### END FUNCTIONS SHARED WITH CONFIGURE - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - - -ltmain=$ac_aux_dir/ltmain.sh - - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - $SED '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - - ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_CONFIG_STATUS= - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - case $CONFIG_STATUS in @%:@( - -*) : - ac_no_opts=-- ;; @%:@( - *) : - ac_no_opts= ;; -esac - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $ac_no_opts "$CONFIG_STATUS" $ac_config_status_args || - ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - diff --git a/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.1 b/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.1 deleted file mode 100644 index c0c8c80c2..000000000 --- a/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.1 +++ /dev/null @@ -1,24109 +0,0 @@ -@%:@! /bin/sh -@%:@ Guess values for system-dependent variables and create Makefiles. -@%:@ Generated by GNU Autoconf 2.73 for libXext 1.3.7. -@%:@ -@%:@ Report bugs to . -@%:@ -@%:@ -@%:@ Copyright (C) 1992-1996, 1998-2017, 2020-2026 Free Software Foundation, -@%:@ Inc. -@%:@ -@%:@ -@%:@ This configure script is free software; the Free Software Foundation -@%:@ gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $@%:@ in @%:@ (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case \`(set -o) 2>/dev/null\` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ) -then : - -else case e in @%:@( - e) exitcode=1; echo positional parameters were not saved. ;; -esac -fi -test x\$exitcode = x0 || exit 1 -blah=\$(echo \$(echo blah)) -test x\"\$blah\" = xblah || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 - - test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ - || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null -then : - as_have_required=yes -else case e in @%:@( - e) as_have_required=no ;; -esac -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null -then : - -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - case $as_dir in @%:@( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$as_shell as_have_required=yes - if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null -then : - break 2 -fi -fi - done;; - esac - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in @%:@( - e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi ;; -esac -fi - - - if test "x$CONFIG_SHELL" != x -then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $@%:@ in @%:@ (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno -then : - printf '%s\n' "$0: This script requires a shell more modern than all" - printf '%s\n' "$0: the shells that I found on your system." - if test ${ZSH_VERSION+y} ; then - printf '%s\n' "$0: In particular, zsh $ZSH_VERSION has bugs and should" - printf '%s\n' "$0: be upgraded to zsh 4.3.4 or later." - else - printf '%s\n' "$0: Please tell bug-autoconf@gnu.org and -$0: https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi ;; -esac -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in @%:@( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in @%:@( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - t clear - :clear - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { printf '%s\n' "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - -SHELL=${CONFIG_SHELL-/bin/sh} - -as_awk_strverscmp=' - # Use only awk features that work with 7th edition Unix awk (1978). - # My, what an old awk you have, Mr. Solaris! - END { - while (length(v1) && length(v2)) { - # Set d1 to be the next thing to compare from v1, and likewise for d2. - # Normally this is a single character, but if v1 and v2 contain digits, - # compare them as integers and fractions as strverscmp does. - if (v1 ~ /^[0-9]/ && v2 ~ /^[0-9]/) { - # Split v1 and v2 into their leading digit string components d1 and d2, - # and advance v1 and v2 past the leading digit strings. - for (len1 = 1; substr(v1, len1 + 1) ~ /^[0-9]/; len1++) continue - for (len2 = 1; substr(v2, len2 + 1) ~ /^[0-9]/; len2++) continue - d1 = substr(v1, 1, len1); v1 = substr(v1, len1 + 1) - d2 = substr(v2, 1, len2); v2 = substr(v2, len2 + 1) - if (d1 ~ /^0/) { - if (d2 ~ /^0/) { - # Compare two fractions. - while (d1 ~ /^0/ && d2 ~ /^0/) { - d1 = substr(d1, 2); len1-- - d2 = substr(d2, 2); len2-- - } - if (len1 != len2 && ! (len1 && len2 && substr(d1, 1, 1) == substr(d2, 1, 1))) { - # The two components differ in length, and the common prefix - # contains only leading zeros. Consider the longer to be less. - d1 = -len1 - d2 = -len2 - } else { - # Otherwise, compare as strings. - d1 = "x" d1 - d2 = "x" d2 - } - } else { - # A fraction is less than an integer. - exit 1 - } - } else { - if (d2 ~ /^0/) { - # An integer is greater than a fraction. - exit 2 - } else { - # Compare two integers. - d1 += 0 - d2 += 0 - } - } - } else { - # The normal case, without worrying about digits. - d1 = substr(v1, 1, 1); v1 = substr(v1, 2) - d2 = substr(v2, 1, 1); v2 = substr(v2, 2) - } - if (d1 < d2) exit 1 - if (d1 > d2) exit 2 - } - # Beware Solaris 11 /usr/xgp4/bin/awk, which mishandles some - # comparisons of empty strings to integers. For example, - # LC_ALL=C /usr/xpg4/bin/awk "BEGIN {if (-1 < \"\") print \"a\"}" - # prints "a". - if (length(v2)) exit 1 - if (length(v1)) exit 2 - } -' - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_CONFIG_STATUS= -ac_clean_files= -ac_config_libobj_dir=. -LIB@&t@OBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='libXext' -PACKAGE_TARNAME='libXext' -PACKAGE_VERSION='1.3.7' -PACKAGE_STRING='libXext 1.3.7' -PACKAGE_BUGREPORT='https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues' -PACKAGE_URL='' - -ac_unique_file="Makefile.am" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_STDIO_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_header_c_list= -ac_subst_vars='am__EXEEXT_FALSE -am__EXEEXT_TRUE -LTLIBOBJS -MAKE_LINT_LIB_FALSE -MAKE_LINT_LIB_TRUE -LINTLIB -LINT_FALSE -LINT_TRUE -LINT_FLAGS -LINT -LIB@&t@OBJS -XEXT_LIBS -XEXT_CFLAGS -XEXT_SOREV -XTMALLOC_ZERO_CFLAGS -XMALLOC_ZERO_CFLAGS -MALLOC_ZERO_CFLAGS -HAVE_STYLESHEETS_FALSE -HAVE_STYLESHEETS_TRUE -XSL_STYLESHEET -STYLESHEET_SRCDIR -XORG_SGML_PATH -HAVE_XSLTPROC_FALSE -HAVE_XSLTPROC_TRUE -XSLTPROC -HAVE_FOP_FALSE -HAVE_FOP_TRUE -FOP -HAVE_XMLTO_FALSE -HAVE_XMLTO_TRUE -HAVE_XMLTO_TEXT_FALSE -HAVE_XMLTO_TEXT_TRUE -XMLTO -ENABLE_SPECS_FALSE -ENABLE_SPECS_TRUE -MAN_SUBSTS -XORG_MAN_PAGE -ADMIN_MAN_DIR -DRIVER_MAN_DIR -MISC_MAN_DIR -FILE_MAN_DIR -LIB_MAN_DIR -APP_MAN_DIR -ADMIN_MAN_SUFFIX -DRIVER_MAN_SUFFIX -MISC_MAN_SUFFIX -FILE_MAN_SUFFIX -LIB_MAN_SUFFIX -APP_MAN_SUFFIX -INSTALL_CMD -PKG_CONFIG_LIBDIR -PKG_CONFIG_PATH -PKG_CONFIG -CHANGELOG_CMD -STRICT_CFLAGS -CWARNFLAGS -BASE_CFLAGS -LT_SYS_LIBRARY_PATH -OTOOL64 -OTOOL -LIPO -NMEDIT -DSYMUTIL -MANIFEST_TOOL -RANLIB -ac_ct_AR -AR -DLLTOOL -OBJDUMP -FILECMD -LN_S -NM -ac_ct_DUMPBIN -DUMPBIN -LD -FGREP -EGREP -GREP -SED -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -LIBTOOL -am__xargs_n -am__rm_f_notfound -AM_BACKSLASH -AM_DEFAULT_VERBOSITY -AM_DEFAULT_V -AM_V -CSCOPE -ETAGS -CTAGS -am__fastdepCC_FALSE -am__fastdepCC_TRUE -CCDEPMODE -am__nodep -AMDEPBACKSLASH -AMDEP_FALSE -AMDEP_TRUE -am__include -DEPDIR -am__untar -am__tar -AMTAR -am__leading_dot -SET_MAKE -AWK -mkdir_p -MKDIR_P -INSTALL_STRIP_PROGRAM -STRIP -install_sh -MAKEINFO -AUTOHEADER -AUTOMAKE -AUTOCONF -ACLOCAL -VERSION -PACKAGE -CYGPATH_W -am__isrc -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -ECHO_T -ECHO_N -ECHO_C -target_alias -host_alias -build_alias -LIBS -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -runstatedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL -am__quote' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_dependency_tracking -enable_silent_rules -enable_shared -enable_static -enable_pic -with_pic -enable_fast_install -enable_aix_soname -with_aix_soname -with_gnu_ld -with_sysroot -enable_libtool_lock -enable_selective_werror -enable_strict_compilation -enable_specs -with_xmlto -with_fop -with_xsltproc -enable_malloc0returnsnull -with_lint -enable_lint_library -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -LT_SYS_LIBRARY_PATH -PKG_CONFIG -PKG_CONFIG_PATH -PKG_CONFIG_LIBDIR -XMLTO -FOP -XSLTPROC -XEXT_CFLAGS -XEXT_LIBS -LINT -LINT_FLAGS' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: '$ac_option' -Try '$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: '$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - printf '%s\n' "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - printf '%s\n' "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`printf '%s\n' $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: '$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -'configure' configures libXext 1.3.7 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print 'checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for '--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or '..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - @<:@@S|@ac_default_prefix@:>@ - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - @<:@PREFIX@:>@ - -By default, 'make install' will install all the files in -'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify -an installation prefix other than '$ac_default_prefix' using '--prefix', -for instance '--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root @<:@DATAROOTDIR/doc/libXext@:>@ - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of libXext 1.3.7:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-dependency-tracking - do not reject slow dependency extractors - --disable-dependency-tracking - speeds up one-time build - --enable-silent-rules less verbose build output (undo: "make V=1") - --disable-silent-rules verbose build output (undo: "make V=0") - --enable-shared@<:@=PKGS@:>@ build shared libraries @<:@default=yes@:>@ - --enable-static@<:@=PKGS@:>@ build static libraries @<:@default=yes@:>@ - --enable-pic@<:@=PKGS@:>@ try to use only PIC/non-PIC objects @<:@default=use - both@:>@ - --enable-fast-install@<:@=PKGS@:>@ - optimize for fast installation @<:@default=yes@:>@ - --enable-aix-soname=aix|svr4|both - shared library versioning (aka "SONAME") variant to - provide on AIX, @<:@default=aix@:>@. - --disable-libtool-lock avoid locking (might break parallel builds) - --disable-selective-werror - Turn off selective compiler errors. (default: - enabled) - --enable-strict-compilation - Enable all warnings from compiler and make them - errors (default: disabled) - --enable-specs Enable building the specs (default: yes) - --enable-malloc0returnsnull - assume malloc(0) can return NULL (default: yes) - --enable-lint-library Create lint library (default: disabled) - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-gnu-ld assume the C compiler uses GNU ld @<:@default=no@:>@ - --with-sysroot@<:@=DIR@:>@ Search for dependent libraries within DIR (or the - compiler's sysroot if not specified). - --with-xmlto Use xmlto to regenerate documentation (default: - auto) - --with-fop Use fop to regenerate documentation (default: auto) - --with-xsltproc Use xsltproc for the transformation of XML documents - (default: auto) - --with-lint Use a lint-style source code checker (default: - disabled) - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - LT_SYS_LIBRARY_PATH - User-defined run-time library search path. - PKG_CONFIG path to pkg-config utility - PKG_CONFIG_PATH - directories to add to pkg-config's search path - PKG_CONFIG_LIBDIR - path overriding pkg-config's built-in search path - XMLTO Path to xmlto command - FOP Path to fop command - XSLTPROC Path to xsltproc command - XEXT_CFLAGS C compiler flags for XEXT, overriding pkg-config - XEXT_LIBS linker flags for XEXT, overriding pkg-config - LINT Path to a lint-style command - LINT_FLAGS Flags for the lint-style command - -Use these variables to override the choices made by 'configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for configure.gnu first; this name is used for a wrapper for - # Metaconfig's "Configure" on case-insensitive file systems. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - printf '%s\n' "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -libXext configure 1.3.7 -generated by GNU Autoconf 2.73 - -Copyright (C) 2026 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -@%:@ ac_fn_c_try_compile LINENO -@%:@ -------------------------- -@%:@ Try to compile conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_compile - -@%:@ ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -@%:@ ------------------------------------------------------- -@%:@ Tests whether HEADER exists and can be compiled using the include files in -@%:@ INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -@%:@include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_header_compile - -@%:@ ac_fn_c_try_link LINENO -@%:@ ----------------------- -@%:@ Try to link conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - } -then : - ac_retval=0 -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_link - -@%:@ ac_fn_c_check_func LINENO FUNC VAR -@%:@ ---------------------------------- -@%:@ Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (void); below. */ - -#include -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (void); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main (void) -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_func - -@%:@ ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR -@%:@ ------------------------------------------------------------------ -@%:@ Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -@%:@ accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. -ac_fn_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -printf %s "checking whether $as_decl_name is declared... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - eval ac_save_FLAGS=\$$6 - as_fn_append $6 " $5" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main (void) -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - eval $6=\$ac_save_FLAGS - ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_check_decl -ac_configure_args_raw= -for ac_arg -do - case $ac_arg in - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_configure_args_raw " '$ac_arg'" -done - -case $ac_configure_args_raw in - *$as_nl*) - ac_safe_unquote= ;; - *) - ac_unsafe_z='|&;<>()$`\\"*?@<:@ '' ' # This string ends in space, tab. - ac_unsafe_a="$ac_unsafe_z#~" - ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" - ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; -esac - -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - $ $0$ac_configure_args_raw - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - printf '%s\n' "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# Dump the cache to stdout. It can be in a pipe (this is a requirement). -ac_cache_dump () -{ - # The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf '%s\n' "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # 'set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # 'set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) -} - -# Print debugging info to stdout. -ac_dump_debugging_info () -{ - echo - - printf '%s\n' "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - ac_cache_dump - echo - - printf '%s\n' "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - - if test -n "$ac_subst_files"; then - printf '%s\n' "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - fi - - if test -s confdefs.h; then - printf '%s\n' "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - printf '%s\n' "$as_me: caught signal $ac_signal" - printf '%s\n' "$as_me: exit $exit_status" -} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. -ac_exit_trap () -{ - exit_status= - # Sanitize IFS. - IFS=" "" $as_nl" - # Save into config.log some information that might help in debugging. - ac_dump_debugging_info >&5 - eval "rm -f $ac_clean_CONFIG_STATUS core *.core core.conftest.*" && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -} - -trap 'ac_exit_trap $?' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -printf '%s\n' "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -printf '%s\n' "@%:@define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -if test -n "$CONFIG_SITE"; then - ac_site_files="$CONFIG_SITE" -elif test "x$prefix" != xNONE; then - ac_site_files="$prefix/share/config.site $prefix/etc/config.site" -else - ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" -fi - -for ac_site_file in $ac_site_files -do - case $ac_site_file in @%:@( - */*) : - ;; @%:@( - *) : - ac_site_file=./$ac_site_file ;; -esac - if test -f "$ac_site_file" && test -r "$ac_site_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -printf '%s\n' "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See 'config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -printf '%s\n' "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -printf '%s\n' "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" -# Test code for whether the C compiler supports C23 (global declarations) -ac_c_conftest_c23_globals=' -/* Does the compiler advertise conformance to C17 or earlier? - Although GCC 14 does not do that, even with -std=gnu23, - it is close enough, and defines __STDC_VERSION == 202000L. */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ <= 201710L -# error "Compiler advertises conformance to C17 or earlier" -#endif - -// Check alignas. -char alignas (double) c23_aligned_as_double; -char alignas (0) c23_no_special_alignment; -extern char c23_aligned_as_int; -char alignas (0) alignas (int) c23_aligned_as_int; - -// Check alignof. -enum -{ - c23_int_alignment = alignof (int), - c23_int_array_alignment = alignof (int[100]), - c23_char_alignment = alignof (char) -}; -static_assert (0 < -alignof (int), "alignof is signed"); - -int function_with_unnamed_parameter (int) { return 0; } - -void c23_noreturn (); - -/* Test parsing of string and char UTF-8 literals (including hex escapes). - The parens pacify GCC 15. */ -bool use_u8 = (!sizeof u8"\xFF") == (!u8'\''x'\''); - -bool check_that_bool_works = true | false | !nullptr; -#if !true -# error "true does not work in #if" -#endif -#if false -#elifdef __STDC_VERSION__ -#else -# error "#elifdef does not work" -#endif - -#ifndef __has_c_attribute -# error "__has_c_attribute not defined" -#endif - -#ifndef __has_include -# error "__has_include not defined" -#endif - -#define LPAREN() ( -#define FORTY_TWO(x) 42 -#define VA_OPT_TEST(r, x, ...) __VA_OPT__ (FORTY_TWO r x)) -static_assert (VA_OPT_TEST (LPAREN (), 0, <:-) == 42); - -static_assert (0b101010 == 42); -static_assert (0B101010 == 42); -static_assert (0xDEAD'\''BEEF == 3'\''735'\''928'\''559); -static_assert (0.500'\''000'\''000 == 0.5); - -enum unsignedish : unsigned int { uione = 1 }; -static_assert (0 < -uione); - -#include -constexpr nullptr_t null_pointer = nullptr; - -static typeof (1 + 1L) two () { return 2; } -static long int three () { return 3; } -' - -# Test code for whether the C compiler supports C23 (body of main). -ac_c_conftest_c23_main=' - { - label_before_declaration: - int arr[10] = {}; - if (arr[0]) - goto label_before_declaration; - if (!arr[0]) - goto label_at_end_of_block; - label_at_end_of_block: - } - ok |= !null_pointer; - ok |= two != three; -' - -# Test code for whether the C compiler supports C23 (complete). -ac_c_conftest_c23_program="${ac_c_conftest_c23_globals} - -int -main (int, char **) -{ - int ok = 0; - ${ac_c_conftest_c23_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (global declarations) -ac_c_conftest_c89_globals=' -/* Do not test the value of __STDC__, because some compilers define it to 0 - or do not define it, while otherwise adequately conforming. */ - -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ -struct buf { int x; }; -struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (char **p, int i) -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* C89 style stringification. */ -#define noexpand_stringify(a) #a -const char *stringified = noexpand_stringify(arbitrary+token=sequence); - -/* C89 style token pasting. Exercises some of the corner cases that - e.g. old MSVC gets wrong, but not very hard. */ -#define noexpand_concat(a,b) a##b -#define expand_concat(a,b) noexpand_concat(a,b) -extern int vA; -extern int vbee; -#define aye A -#define bee B -int *pvA = &expand_concat(v,aye); -int *pvbee = &noexpand_concat(v,bee); - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not \xHH hex character constants. - These do not provoke an error unfortunately, instead are silently treated - as an "x". The following induces an error, until -std is added to get - proper ANSI mode. Curiously \x00 != x always comes out true, for an - array size at least. It is necessary to write \x00 == 0 to get something - that is true only with -std. */ -int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) '\''x'\'' -int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), - int, int);' - -# Test code for whether the C compiler supports C89 (body of main). -ac_c_conftest_c89_main=' -ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); -' - -# Test code for whether the C compiler supports C99 (global declarations) -ac_c_conftest_c99_globals=' -/* Does the compiler advertise C99 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# error "Compiler does not advertise C99 conformance" -#endif - -// See if C++-style comments work. - -#include -extern int puts (const char *); -extern int printf (const char *, ...); -extern int dprintf (int, const char *, ...); -extern void *malloc (size_t); -extern void free (void *); - -// Check varargs macros. These examples are taken from C99 6.10.3.5. -// dprintf is used instead of fprintf to avoid needing to declare -// FILE and stderr, and "aND" is used instead of "and" to work around -// GCC bug 40564 which is irrelevant here. -#define debug(...) dprintf (2, __VA_ARGS__) -#define showlist(...) puts (#__VA_ARGS__) -#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) -static void -test_varargs_macros (void) -{ - int x = 1234; - int y = 5678; - debug ("Flag"); - debug ("X = %d\n", x); - showlist (The first, second, aND third items.); - report (x>y, "x is %d but y is %d", x, y); -} - -// Check long long types. -#define BIG64 18446744073709551615ull -#define BIG32 4294967295ul -#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) -#if !BIG_OK - #error "your preprocessor is broken" -#endif -#if BIG_OK -#else - #error "your preprocessor is broken" -#endif -static long long int bignum = -9223372036854775807LL; -static unsigned long long int ubignum = BIG64; - -struct incomplete_array -{ - int datasize; - double data[]; -}; - -struct named_init { - int number; - const wchar_t *name; - double average; -}; - -typedef const char *ccp; - -static inline int -test_restrict (ccp restrict text) -{ - // Iterate through items via the restricted pointer. - // Also check for declarations in for loops. - for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) - continue; - return 0; -} - -// Check varargs and va_copy. -static bool -test_varargs (const char *format, ...) -{ - va_list args; - va_start (args, format); - va_list args_copy; - va_copy (args_copy, args); - - const char *str = ""; - int number = 0; - float fnumber = 0; - - while (*format) - { - switch (*format++) - { - case '\''s'\'': // string - str = va_arg (args_copy, const char *); - break; - case '\''d'\'': // int - number = va_arg (args_copy, int); - break; - case '\''f'\'': // float - fnumber = va_arg (args_copy, double); - break; - default: - break; - } - } - va_end (args_copy); - va_end (args); - - return *str && number && fnumber; -} -' - -# Test code for whether the C compiler supports C99 (body of main). -ac_c_conftest_c99_main=' - // Check bool. - _Bool success = false; - success |= (argc != 0); - - // Check restrict. - if (test_restrict ("String literal") == 0) - success = true; - const char *restrict newvar = "Another string"; - - // Check varargs. - success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); - test_varargs_macros (); - - // Check flexible array members. - static struct incomplete_array *volatile incomplete_array_pointer; - struct incomplete_array *ia = incomplete_array_pointer; - ia->datasize = 10; - for (int i = 0; i < ia->datasize; ++i) - ia->data[i] = i * 1.234; - // Work around memory leak warnings. - free (ia); - - // Check named initializers. - struct named_init ni = { - .number = 34, - .name = L"Test wide string", - .average = 543.34343, - }; - - ni.number = 58; - - // Do not test for VLAs, as some otherwise-conforming compilers lack them. - // C code should instead use __STDC_NO_VLA__; see Autoconf manual. - - // work around unused variable warnings - ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' - || ni.number != 58); -' - -# Test code for whether the C compiler supports C11 (global declarations) -ac_c_conftest_c11_globals=' -/* Does the compiler advertise C11 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L -# error "Compiler does not advertise C11 conformance" -#endif - -// Check _Alignas. -char _Alignas (double) aligned_as_double; -char _Alignas (0) no_special_alignment; -extern char aligned_as_int; -char _Alignas (0) _Alignas (int) aligned_as_int; - -// Check _Alignof. -enum -{ - int_alignment = _Alignof (int), - int_array_alignment = _Alignof (int[100]), - char_alignment = _Alignof (char) -}; -_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); - -// Check _Noreturn. -int _Noreturn does_not_return (void) { for (;;) continue; } - -// Check _Static_assert. -struct test_static_assert -{ - int x; - _Static_assert (sizeof (int) <= sizeof (long int), - "_Static_assert does not work in struct"); - long int y; -}; - -// Check UTF-8 literals. -#define u8 syntax error! -char const utf8_literal[] = u8"happens to be ASCII" "another string"; - -// Check duplicate typedefs. -typedef long *long_ptr; -typedef long int *long_ptr; -typedef long_ptr long_ptr; - -// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. -struct anonymous -{ - union { - struct { int i; int j; }; - struct { int k; long int l; } w; - }; - int m; -} v1; -' - -# Test code for whether the C compiler supports C11 (body of main). -ac_c_conftest_c11_main=' - _Static_assert ((offsetof (struct anonymous, i) - == offsetof (struct anonymous, w.k)), - "Anonymous union alignment botch"); - v1.i = 2; - v1.w.k = 5; - ok |= v1.i != 5; -' - -# Test code for whether the C compiler supports C11 (complete). -ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} -${ac_c_conftest_c11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - ${ac_c_conftest_c11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C99 (complete). -ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (complete). -ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - return ok; -} -" - -as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" -as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" -as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" -as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" -as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" -as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" -as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" -as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" -as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" -as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" - -# Auxiliary files required by this configure script. -ac_aux_files="config.guess config.sub ltmain.sh missing install-sh compile" - -# Locations in which to look for auxiliary files. -ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." - -# Search for a directory containing all of the required auxiliary files, -# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. -# If we don't find one directory that contains all the files we need, -# we report the set of missing files from the *first* directory in -# $ac_aux_dir_candidates and give up. -ac_missing_aux_files="" -ac_first_candidate=: -printf '%s\n' "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in $ac_aux_dir_candidates -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - - printf '%s\n' "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 - ac_aux_dir_found=yes - ac_install_sh= - for ac_aux in $ac_aux_files - do - # As a special case, if "install-sh" is required, that requirement - # can be satisfied by any of "install-sh", "install.sh", or "shtool", - # and $ac_install_sh is set appropriately for whichever one is found. - if test x"$ac_aux" = x"install-sh" - then - if test -f "${as_dir}install-sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 - ac_install_sh="${as_dir}install-sh -c" - elif test -f "${as_dir}install.sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 - ac_install_sh="${as_dir}install.sh -c" - elif test -f "${as_dir}shtool"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 - ac_install_sh="${as_dir}shtool install -c" - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} install-sh" - else - break - fi - fi - else - if test -f "${as_dir}${ac_aux}"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" - else - break - fi - fi - fi - done - if test "$ac_aux_dir_found" = yes; then - ac_aux_dir="$as_dir" - break - fi - ac_first_candidate=false - - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in @%:@( - e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; -esac -fi - - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -if test -f "${ac_aux_dir}config.guess"; then - ac_@&t@config_guess="$SHELL ${ac_aux_dir}config.guess" -fi -if test -f "${ac_aux_dir}config.sub"; then - ac_@&t@config_sub="$SHELL ${ac_aux_dir}config.sub" -fi -if test -f "$ac_aux_dir/configure"; then - ac_@&t@configure="$SHELL ${ac_aux_dir}configure" -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w= - for ac_val in x $ac_old_val; do - ac_old_val_w="$ac_old_val_w $ac_val" - done - ac_new_val_w= - for ac_val in x $ac_new_val; do - ac_new_val_w="$ac_new_val_w $ac_val" - done - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 -printf '%s\n' "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 -printf '%s\n' "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 -printf '%s\n' "$as_me: former value: '$ac_old_val'" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 -printf '%s\n' "$as_me: current value: '$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`printf '%s\n' "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -printf '%s\n' "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' - and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in @%:@((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers config.h" - - - -# Set common system defines for POSIX extensions, such as _GNU_SOURCE -# Must be called before any macros that run the compiler (like LT_INIT) -# to avoid autoconf errors. - - - - - - - - - - - - - - -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $@%:@ != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" - fi -fi -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. -set dummy ${ac_tool_prefix}clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "clang", so it can be a program name with args. -set dummy clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -fi - - -test -z "$CC" && { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See 'config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion -version; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -printf %s "checking whether the C compiler works... " >&6; } -ac_link_default=`printf '%s\n' "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. -# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an '-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else case e in @%:@( - e) ac_file='' ;; -esac -fi -if test -z "$ac_file" -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See 'config.log' for more details" "$LINENO" 5; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -printf %s "checking for C compiler default output file name... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -printf '%s\n' "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -printf %s "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) -# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will -# work properly (i.e., refer to 'conftest.exe'), while it won't with -# 'rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else case e in @%:@( - e) { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest conftest$ac_cv_exeext -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -printf '%s\n' "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -int -main (void) -{ -FILE *f = fopen ("conftest.out", "w"); - if (!f) - return 1; - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -printf %s "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use '--host'. -See 'config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -printf '%s\n' "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext \ - conftest.o conftest.obj conftest.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -printf %s "checking for suffix of object files... " >&6; } -if test ${ac_cv_objext+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -printf '%s\n' "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 -printf %s "checking whether the compiler supports GNU C... " >&6; } -if test ${ac_cv_c_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else case e in @%:@( - e) ac_compiler_gnu=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -printf '%s\n' "$ac_cv_c_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+y} -ac_save_CFLAGS=$CFLAGS -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -printf %s "checking whether $CC accepts -g... " >&6; } -if test ${ac_cv_prog_cc_g+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -else case e in @%:@( - e) CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -printf '%s\n' "$ac_cv_prog_cc_g" >&6; } -if test $ac_test_CFLAGS; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -ac_prog_cc_stdc=no -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C23 features" >&5 -printf %s "checking for $CC option to enable C23 features... " >&6; } -if test ${ac_cv_prog_cc_c23+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c23=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c23_program -_ACEOF -for ac_arg in '' -std=gnu23 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c23=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c23" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c23" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c23" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c23" >&5 -printf '%s\n' "$ac_cv_prog_cc_c23" >&6; } - CC="$CC $ac_cv_prog_cc_c23" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c23 - ac_prog_cc_stdc=c23 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 -printf %s "checking for $CC option to enable C11 features... " >&6; } -if test ${ac_cv_prog_cc_c11+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c11=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c11_program -_ACEOF -for ac_arg in '' -std=gnu11 -std:c11 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c11" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c11" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c11" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -printf '%s\n' "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } -if test ${ac_cv_prog_cc_c99+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c99=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c99=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c99" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c99" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c99" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -printf '%s\n' "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 -printf %s "checking for $CC option to enable C89 features... " >&6; } -if test ${ac_cv_prog_cc_c89+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c89_program -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c89" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c89" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -printf '%s\n' "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 ;; -esac -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -printf %s "checking whether $CC understands -c and -o together... " >&6; } -if test ${am_cv_prog_cc_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - # aligned with autoconf, so not including core; see bug#72225. - rm -f -r a.out a.exe b.out conftest.$ac_ext conftest.$ac_objext \ - conftest.dSYM conftest1.$ac_ext conftest1.$ac_objext conftest1.dSYM \ - conftest2.$ac_ext conftest2.$ac_objext conftest2.dSYM - unset am_i ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -printf '%s\n' "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_header= ac_cache= -for ac_item in $ac_header_c_list -do - if test $ac_cache; then - ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" - if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf '%s\n' "#define $ac_item 1" >> confdefs.h - fi - ac_header= ac_cache= - elif test $ac_header; then - ac_cache=$ac_item - else - ac_header=$ac_item - fi -done - - - - - - - - -if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes -then : - -printf '%s\n' "@%:@define STDC_HEADERS 1" >>confdefs.h - -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 -printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test ${ac_cv_safe_to_define___extensions__+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -# define __EXTENSIONS__ 1 - $ac_includes_default -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_safe_to_define___extensions__=yes -else case e in @%:@( - e) ac_cv_safe_to_define___extensions__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -printf '%s\n' "$ac_cv_safe_to_define___extensions__" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 -printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } -if test ${ac_cv_should_define__xopen_source+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_should_define__xopen_source=no - if test $ac_cv_header_wchar_h = yes -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #define _XOPEN_SOURCE 500 - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_should_define__xopen_source=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 -printf '%s\n' "$ac_cv_should_define__xopen_source" >&6; } - - printf '%s\n' "@%:@define _ALL_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _COSMO_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _DARWIN_C_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _GNU_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h - - printf '%s\n' "@%:@define _NETBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _OPENBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h - - printf '%s\n' "@%:@define _TANDEM_SOURCE 1" >>confdefs.h - - if test $ac_cv_header_minix_config_h = yes -then : - MINIX=yes - printf '%s\n' "@%:@define _MINIX 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_1_SOURCE 2" >>confdefs.h - -else case e in @%:@( - e) MINIX= ;; -esac -fi - if test $ac_cv_safe_to_define___extensions__ = yes -then : - printf '%s\n' "@%:@define __EXTENSIONS__ 1" >>confdefs.h - -fi - if test $ac_cv_should_define__xopen_source = yes -then : - printf '%s\n' "@%:@define _XOPEN_SOURCE 500" >>confdefs.h - -fi - - -# Initialize Automake -am__api_version='1.18' - - - # Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -printf %s "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if test ${ac_cv_path_install+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - # Account for fact that we put trailing slashes in our PATH walk. -case $as_dir in @%:@(( - ./ | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF/1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF/1 since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - ;; -esac -fi - if test ${ac_cv_path_install+y}; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -printf '%s\n' "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5 -printf %s "checking whether sleep supports fractional seconds... " >&6; } -if test ${am_cv_sleep_fractional_seconds+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if sleep 0.001 2>/dev/null -then : - am_cv_sleep_fractional_seconds=yes -else case e in @%:@( - e) am_cv_sleep_fractional_seconds=no ;; -esac -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_sleep_fractional_seconds" >&5 -printf '%s\n' "$am_cv_sleep_fractional_seconds" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking filesystem timestamp resolution" >&5 -printf %s "checking filesystem timestamp resolution... " >&6; } -if test ${am_cv_filesystem_timestamp_resolution+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) # Default to the worst case. -am_cv_filesystem_timestamp_resolution=2 - -# Only try to go finer than 1 sec if sleep can do it. -# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, -# - 1 sec is not much of a win compared to 2 sec, and -# - it takes 2 seconds to perform the test whether 1 sec works. -# -# Instead, just use the default 2s on platforms that have 1s resolution, -# accept the extra 1s delay when using $sleep in the Automake tests, in -# exchange for not incurring the 2s delay for running the test for all -# packages. -# -am_try_resolutions= -if test "$am_cv_sleep_fractional_seconds" = yes; then - # Even a millisecond often causes a bunch of false positives, - # so just try a hundredth of a second. The time saved between .001 and - # .01 is not terribly consequential. - am_try_resolutions="0.01 0.1 $am_try_resolutions" -fi - -# In order to catch current-generation FAT out, we must *modify* files -# that already exist; the *creation* timestamp is finer. Use names -# that make ls -t sort them differently when they have equal -# timestamps than when they have distinct timestamps, keeping -# in mind that ls -t prints the *newest* file first. -rm -f conftest.ts? -: > conftest.ts1 -: > conftest.ts2 -: > conftest.ts3 - -# Make sure ls -t actually works. Do 'set' in a subshell so we don't -# clobber the current shell's arguments. (Outer-level square brackets -# are removed by m4; they're present so that m4 does not expand -# ; be careful, easy to get confused.) -if ( - set X `ls -t conftest.ts[12]` && - { - test "$*" != "X conftest.ts1 conftest.ts2" || - test "$*" != "X conftest.ts2 conftest.ts1"; - } -); then :; else - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - printf '%s\n' ""Bad output from ls -t: \"`ls -t conftest.ts[12]`\""" >&5 - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "ls -t produces unexpected output. -Make sure there is not a broken ls alias in your environment. -See 'config.log' for more details" "$LINENO" 5; } -fi - -for am_try_res in $am_try_resolutions; do - # Any one fine-grained sleep might happen to cross the boundary - # between two values of a coarser actual resolution, but if we do - # two fine-grained sleeps in a row, at least one of them will fall - # entirely within a coarse interval. - echo alpha > conftest.ts1 - sleep $am_try_res - echo beta > conftest.ts2 - sleep $am_try_res - echo gamma > conftest.ts3 - - # We assume that 'ls -t' will make use of high-resolution - # timestamps if the operating system supports them at all. - if (set X `ls -t conftest.ts?` && - test "$2" = conftest.ts3 && - test "$3" = conftest.ts2 && - test "$4" = conftest.ts1); then - # - # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, - # because we don't need to test make. - make_ok=true - if test $am_try_res != 1; then - # But if we've succeeded so far with a subsecond resolution, we - # have one more thing to check: make. It can happen that - # everything else supports the subsecond mtimes, but make doesn't; - # notably on macOS, which ships make 3.81 from 2006 (the last one - # released under GPLv2). https://bugs.gnu.org/68808 - # - # We test $MAKE if it is defined in the environment, else "make". - # It might get overridden later, but our hope is that in practice - # it does not matter: it is the system "make" which is (by far) - # the most likely to be broken, whereas if the user overrides it, - # probably they did so with a better, or at least not worse, make. - # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html - # - # Create a Makefile (real tab character here): - rm -f conftest.mk - echo 'conftest.ts1: conftest.ts2' >conftest.mk - echo ' touch conftest.ts2' >>conftest.mk - # - # Now, running - # touch conftest.ts1; touch conftest.ts2; make - # should touch ts1 because ts2 is newer. This could happen by luck, - # but most often, it will fail if make's support is insufficient. So - # test for several consecutive successes. - # - # (We reuse conftest.ts[12] because we still want to modify existing - # files, not create new ones, per above.) - n=0 - make=${MAKE-make} - until test $n -eq 3; do - echo one > conftest.ts1 - sleep $am_try_res - echo two > conftest.ts2 # ts2 should now be newer than ts1 - if $make -f conftest.mk | grep 'up to date' >/dev/null; then - make_ok=false - break # out of $n loop - fi - n=`expr $n + 1` - done - fi - # - if $make_ok; then - # Everything we know to check worked out, so call this resolution good. - am_cv_filesystem_timestamp_resolution=$am_try_res - break # out of $am_try_res loop - fi - # Otherwise, we'll go on to check the next resolution. - fi -done -rm -f conftest.ts? -# (end _am_filesystem_timestamp_resolution) - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_filesystem_timestamp_resolution" >&5 -printf '%s\n' "$am_cv_filesystem_timestamp_resolution" >&6; } - -# This check should not be cached, as it may vary across builds of -# different projects. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -printf %s "checking whether build environment is sane... " >&6; } -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[\\\"\#\$\&\'\`$am_lf]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; -esac -case $srcdir in - *[\\\"\#\$\&\'\`$am_lf\ \ ]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -am_build_env_is_sane=no -am_has_slept=no -rm -f conftest.file -for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - test "$2" = conftest.file - ); then - am_build_env_is_sane=yes - break - fi - # Just in case. - sleep "$am_cv_filesystem_timestamp_resolution" - am_has_slept=yes -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_build_env_is_sane" >&5 -printf '%s\n' "$am_build_env_is_sane" >&6; } -if test "$am_build_env_is_sane" = no; then - as_fn_error $? "newly created file is older than distributed files! -Check your system clock" "$LINENO" 5 -fi - -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1 -then : - -else case e in @%:@( - e) ( sleep "$am_cv_filesystem_timestamp_resolution" ) & - am_sleep_pid=$! - ;; -esac -fi - -rm -f conftest.file - -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was 's,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`printf '%s\n' "$program_transform_name" | sed "$ac_script"` - - - if test x"${MISSING+set}" != xset; then - MISSING="\${SHELL} '$am_aux_dir/missing'" -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -printf '%s\n' "$as_me: WARNING: 'missing' script is too old or missing" >&2;} -fi - -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 -printf %s "checking for a race-free mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if test ${ac_cv_path_mkdir+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue - case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir ('*'coreutils) '* | \ - *'BusyBox '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - ;; -esac -fi - - test -d ./--version && rmdir ./--version - if test ${ac_cv_path_mkdir+y}; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use plain mkdir -p, - # in the hope it doesn't have the bugs of ancient mkdir. - MKDIR_P='mkdir -p' - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -printf '%s\n' "$MKDIR_P" >&6; } - -for ac_prog in gawk mawk nawk awk 'busybox awk' -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AWK+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -printf '%s\n' "$AWK" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`printf '%s\n' "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval test \${ac_cv_prog_make_${ac_make}_set+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @printf '%s\n' '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make ;; -esac -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - SET_MAKE= -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depfiles" - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 -printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } -cat > confinc.mk << 'END' -am__doit: - @echo this is the am__doit target >confinc.out -.PHONY: am__doit -END -am__include="#" -am__quote= -# BSD make does it like this. -echo '.include "confinc.mk" # ignored' > confmf.BSD -# Other make implementations (GNU, Solaris 10, AIX) do it like this. -echo 'include confinc.mk # ignored' > confmf.GNU -_am_result=no -for s in GNU BSD; do - { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 - (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - case $?:`cat confinc.out 2>/dev/null` in @%:@( - '0:this is the am__doit target') : - case $s in @%:@( - BSD) : - am__include='.include' am__quote='"' ;; @%:@( - *) : - am__include='include' am__quote='' ;; -esac ;; @%:@( - *) : - ;; -esac - if test "$am__include" != "#"; then - _am_result="yes ($s style)" - break - fi -done -rm -f confinc.* confmf.* -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 -printf '%s\n' "${_am_result}" >&6; } - -@%:@ Check whether --enable-dependency-tracking was given. -if test ${enable_dependency_tracking+y} -then : - enableval=$enable_dependency_tracking; -fi - -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi - if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - -AM_DEFAULT_VERBOSITY=1 -@%:@ Check whether --enable-silent-rules was given. -if test ${enable_silent_rules+y} -then : - enableval=$enable_silent_rules; -fi - -am_make=${MAKE-make} -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -printf %s "checking whether $am_make supports nested variables... " >&6; } -if test ${am_cv_make_support_nested_variables+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if printf '%s\n' 'TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -printf '%s\n' "$am_cv_make_support_nested_variables" >&6; } -AM_BACKSLASH='\' - -am__rm_f_notfound= -if (rm -f && rm -fr && rm -rf) 2>/dev/null -then : - -else case e in @%:@( - e) am__rm_f_notfound='""' ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking xargs -n works" >&5 -printf %s "checking xargs -n works... " >&6; } -if test ${am_cv_xargs_n_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 -3" -then : - am_cv_xargs_n_works=yes -else case e in @%:@( - e) am_cv_xargs_n_works=no ;; -esac -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_xargs_n_works" >&5 -printf '%s\n' "$am_cv_xargs_n_works" >&6; } -if test "$am_cv_xargs_n_works" = yes -then : - am__xargs_n='xargs -n' -else case e in @%:@( - e) am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "" "$am__xargs_n_arg"; done; }' - ;; -esac -fi - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE='libXext' - VERSION='1.3.7' - - -printf '%s\n' "@%:@define PACKAGE \"$PACKAGE\"" >>confdefs.h - - -printf '%s\n' "@%:@define VERSION \"$VERSION\"" >>confdefs.h - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -mkdir_p='$(MKDIR_P)' - -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AMTAR='$${TAR-tar}' - - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar plaintar pax cpio none' - -# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 -printf %s "checking whether UID '$am_uid' is supported by ustar format... " >&6; } - if test x$am_uid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&2;} - elif test $am_uid -le $am_max_uid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 -printf %s "checking whether GID '$am_gid' is supported by ustar format... " >&6; } - if test x$gm_gid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&2;} - elif test $am_gid -le $am_max_gid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 -printf %s "checking how to create a ustar tar archive... " >&6; } - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_ustar-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - { echo "$as_me:$LINENO: $_am_tar --version" >&5 - ($_am_tar --version) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && break - done - am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x ustar -w "$$tardir"' - am__tar_='pax -L -x ustar -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H ustar -L' - am__tar_='find "$tardir" -print | cpio -o -H ustar -L' - am__untar='cpio -i -H ustar -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_ustar}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 - (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - rm -rf conftest.dir - if test -s conftest.tar; then - { echo "$as_me:$LINENO: $am__untar &5 - ($am__untar &5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 - (cat conftest.dir/file) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - grep GrepMe conftest.dir/file >/dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - if test ${am_cv_prog_tar_ustar+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) am_cv_prog_tar_ustar=$_am_tool ;; -esac -fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 -printf '%s\n' "$am_cv_prog_tar_ustar" >&6; } - - - - - -depcc="$CC" am_compiler_list= - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -printf %s "checking dependency style of $depcc... " >&6; } -if test ${am_cv_CC_dependencies_compiler_type+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thus: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -printf '%s\n' "$am_cv_CC_dependencies_compiler_type" >&6; } -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' -else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi - - -# Variables for tags utilities; see am/tags.am -if test -z "$CTAGS"; then - CTAGS=ctags -fi - -if test -z "$ETAGS"; then - ETAGS=etags -fi - -if test -z "$CSCOPE"; then - CSCOPE=cscope -fi - - - - - - - - -# Initialize libtool -case `pwd` in - *\ * | *\ *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 -printf '%s\n' "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; -esac - - - -macro_version='2.5.4' -macro_revision='2.5.4' - - - - - - - - - - - - - - -ltmain=$ac_aux_dir/ltmain.sh - - - - # Make sure we can run config.sub. -$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -printf %s "checking build system type... " >&6; } -if test ${ac_cv_build+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -printf '%s\n' "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`printf '%s\n' "$build_os" | sed 's/ /-/g'`;; esac - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -printf %s "checking host system type... " >&6; } -if test ${ac_cv_host+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -printf '%s\n' "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`printf '%s\n' "$host_os" | sed 's/ /-/g'`;; esac - - -# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 -printf %s "checking how to print strings... " >&6; } -# Test print first, because it will be a builtin if present. -if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "" -} - -case $ECHO in - printf*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: printf" >&5 -printf '%s\n' "printf" >&6; } ;; - print*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 -printf '%s\n' "print -r" >&6; } ;; - *) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: cat" >&5 -printf '%s\n' "cat" >&6; } ;; -esac - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -printf %s "checking for a sed that does not truncate output... " >&6; } -if test ${ac_cv_path_SED+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in sed gsed - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -printf '%s\n' "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - -test -z "$SED" && SED=sed -Xsed="$SED -e 1s/^X//" - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in grep ggrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf '%s\n' "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in egrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf '%s\n' "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - EGREP_TRADITIONAL=$EGREP - ac_cv_path_EGREP_TRADITIONAL=$EGREP - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 -printf %s "checking for fgrep... " >&6; } -if test ${ac_cv_path_FGREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 - then ac_cv_path_FGREP="$GREP -F" - else - if test -z "$FGREP"; then - ac_path_FGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in fgrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_FGREP" || continue -# Check for GNU ac_path_FGREP and select it if it is found. - # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'FGREP' >> "conftest.nl" - "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_FGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_FGREP="$ac_path_FGREP" - ac_path_FGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_FGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_FGREP"; then - as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_FGREP=$FGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 -printf '%s\n' "$ac_cv_path_FGREP" >&6; } - FGREP="$ac_cv_path_FGREP" - - -test -z "$GREP" && GREP=grep - - - - - - - - - - - - - - - - - - - -@%:@ Check whether --with-gnu-ld was given. -if test ${with_gnu_ld+y} -then : - withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes -else case e in @%:@( - e) with_gnu_ld=no ;; -esac -fi - -ac_prog=ld -if test yes = "$GCC"; then - # Check if gcc -print-prog-name=ld gives a path. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -printf %s "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw* | *-*-windows*) - # gcc leaves a trailing carriage return, which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD=$ac_prog - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test yes = "$with_gnu_ld"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -printf %s "checking for GNU ld... " >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -printf %s "checking for non-GNU ld... " >&6; } -fi -if test ${lt_cv_path_LD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$LD"; then - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD=$ac_dir/$ac_prog - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -printf '%s\n' "$LD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -printf %s "checking if the linker ($LD) is GNU ld... " >&6; } -if test ${lt_cv_prog_gnu_ld+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -printf '%s\n' "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 -printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if test ${lt_cv_path_NM+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM=$NM -else - lt_nm_to_check=${ac_tool_prefix}nm - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - tmp_nm=$ac_dir/$lt_tmp_nm - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the 'sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty - case $build_os in - mingw* | windows*) lt_bad_file=conftest.nm/nofile ;; - *) lt_bad_file=/dev/null ;; - esac - case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in - *$lt_bad_file* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break 2 - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break 2 - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS=$lt_save_ifs - done - : ${lt_cv_path_NM=no} -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 -printf '%s\n' "$lt_cv_path_NM" >&6; } -if test no != "$lt_cv_path_NM"; then - NM=$lt_cv_path_NM -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - if test -n "$ac_tool_prefix"; then - for ac_prog in dumpbin "link -dump" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DUMPBIN"; then - ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DUMPBIN=$ac_cv_prog_DUMPBIN -if test -n "$DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 -printf '%s\n' "$DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$DUMPBIN" && break - done -fi -if test -z "$DUMPBIN"; then - ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in dumpbin "link -dump" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DUMPBIN"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN -if test -n "$ac_ct_DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 -printf '%s\n' "$ac_ct_DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_DUMPBIN" && break -done - - if test "x$ac_ct_DUMPBIN" = x; then - DUMPBIN=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DUMPBIN=$ac_ct_DUMPBIN - fi -fi - - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols -headers" - ;; - *) - DUMPBIN=: - ;; - esac - fi - - if test : != "$DUMPBIN"; then - NM=$DUMPBIN - fi -fi -test -z "$NM" && NM=nm - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 -printf %s "checking the name lister ($NM) interface... " >&6; } -if test ${lt_cv_nm_interface+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: output\"" >&5) - cat conftest.out >&5 - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 -printf '%s\n' "$lt_cv_nm_interface" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -printf %s "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -printf '%s\n' "no, using $LN_S" >&6; } -fi - -# find the maximum length of command line arguments -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 -printf %s "checking the maximum length of command line arguments... " >&6; } -if test ${lt_cv_sys_max_cmd_len+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) i=0 - teststring=ABCD - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu* | ironclad*) - # Under GNU Hurd and Ironclad, this test is not required because there - # is no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | windows* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[ ]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test X`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test 17 != "$i" # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac - ;; -esac -fi - -if test -n "$lt_cv_sys_max_cmd_len"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 -printf '%s\n' "$lt_cv_sys_max_cmd_len" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none" >&5 -printf '%s\n' "none" >&6; } -fi -max_cmd_len=$lt_cv_sys_max_cmd_len - - - - - - -: ${CP="cp -f"} -: ${MV="mv -f"} -: ${RM="rm -f"} - -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - lt_unset=unset -else - lt_unset=false -fi - - - - - -# test EBCDIC or ASCII -case `echo X|tr X '\101'` in - A) # ASCII based system - # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr - lt_SP2NL='tr \040 \012' - lt_NL2SP='tr \015\012 \040\040' - ;; - *) # EBCDIC based system - lt_SP2NL='tr \100 \n' - lt_NL2SP='tr \r\n \100\100' - ;; -esac - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 -printf %s "checking how to convert $build file names to $host format... " >&6; } -if test ${lt_cv_to_host_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $host in - *-*-mingw* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 - ;; - esac - ;; - *-*-cygwin* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin - ;; - esac - ;; - * ) # unhandled hosts (and "normal" native builds) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; -esac - ;; -esac -fi - -to_host_file_cmd=$lt_cv_to_host_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_host_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 -printf %s "checking how to convert $build file names to toolchain format... " >&6; } -if test ${lt_cv_to_tool_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) #assume ordinary cross tools, or native build. -lt_cv_to_tool_file_cmd=func_convert_file_noop -case $host in - *-*-mingw* | *-*-windows* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 - ;; - esac - ;; -esac - ;; -esac -fi - -to_tool_file_cmd=$lt_cv_to_tool_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_tool_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 -printf %s "checking for $LD option to reload object files... " >&6; } -if test ${lt_cv_ld_reload_flag+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_reload_flag='-r' ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 -printf '%s\n' "$lt_cv_ld_reload_flag" >&6; } -reload_flag=$lt_cv_ld_reload_flag -case $reload_flag in -"" | " "*) ;; -*) reload_flag=" $reload_flag" ;; -esac -reload_cmds='$LD$reload_flag -o $output$reload_objs' -case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - if test yes != "$GCC"; then - reload_cmds=false - fi - ;; - darwin*) - if test yes = "$GCC"; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' - else - reload_cmds='$LD$reload_flag -o $output$reload_objs' - fi - ;; -esac - - - - - - - - - -# Extract the first word of "file", so it can be a program name with args. -set dummy file; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_FILECMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$FILECMD"; then - ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FILECMD="file" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_prog_FILECMD" && ac_cv_prog_FILECMD=":" -fi ;; -esac -fi -FILECMD=$ac_cv_prog_FILECMD -if test -n "$FILECMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 -printf '%s\n' "$FILECMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -printf '%s\n' "$OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -printf '%s\n' "$ac_ct_OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 -printf %s "checking how to recognize dependent libraries... " >&6; } -if test ${lt_cv_deplibs_check_method+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# 'unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'file_magic [[regex]]' -- check by looking for files in library path -# that responds to the $file_magic_cmd with a given extended regex. -# If you have 'file' or equivalent on your system and you're not sure -# whether 'pass_all' will *always* work, you probably want this one. - -case $host_os in -aix[4-9]*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[45]*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='$FILECMD -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | windows* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - if ( file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -cegcc*) - # use the weaker test based on 'objdump'. See mingw*. - lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly* | midnightbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -haiku*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=$FILECMD - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[3-9]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -*-mlibc) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -*nto* | *qnx*) - lt_cv_deplibs_check_method=pass_all - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -serenity*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -tpf*) - lt_cv_deplibs_check_method=pass_all - ;; -os2*) - lt_cv_deplibs_check_method=pass_all - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 -printf '%s\n' "$lt_cv_deplibs_check_method" >&6; } - -file_magic_glob= -want_nocaseglob=no -if test "$build" = "$host"; then - case $host_os in - mingw* | windows* | pw32*) - if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then - want_nocaseglob=yes - else - file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` - fi - ;; - esac -fi - -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - - - - - - - - - - - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -printf '%s\n' "$DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -printf '%s\n' "$ac_ct_DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 -printf %s "checking how to associate runtime and link libraries... " >&6; } -if test ${lt_cv_sharedlib_from_linklib_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_sharedlib_from_linklib_cmd='unknown' - -case $host_os in -cygwin* | mingw* | windows* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh; - # decide which one to use based on capabilities of $DLLTOOL - case `$DLLTOOL --help 2>&1` in - *--identify-strict*) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib - ;; - *) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback - ;; - esac - ;; -*) - # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd=$ECHO - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 -printf '%s\n' "$lt_cv_sharedlib_from_linklib_cmd" >&6; } -sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd -test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -printf '%s\n' "$RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -printf '%s\n' "$ac_ct_RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AR+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -printf '%s\n' "$AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_AR+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -printf '%s\n' "$ac_ct_AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -: ${AR=ar} - - - - - - -# Use ARFLAGS variable as AR's operation code to sync the variable naming with -# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have -# higher priority because that's what people were doing historically (setting -# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS -# variable obsoleted/removed. - -test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} -lt_ar_flags=$AR_FLAGS - - - - - - -# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override -# by AR_FLAGS because that was never working and AR_FLAGS is about to die. - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 -printf %s "checking for archiver @FILE support... " >&6; } -if test ${lt_cv_ar_at_file+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ar_at_file=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - echo conftest.$ac_objext > conftest.lst - lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -eq "$ac_status"; then - # Ensure the archiver fails upon bogus file names. - rm -f conftest.$ac_objext libconftest.a - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -ne "$ac_status"; then - lt_cv_ar_at_file=@ - fi - fi - rm -f conftest.* libconftest.a - -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 -printf '%s\n' "$lt_cv_ar_at_file" >&6; } - -if test no = "$lt_cv_ar_at_file"; then - archiver_list_spec= -else - archiver_list_spec=$lt_cv_ar_at_file -fi - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -test -z "$STRIP" && STRIP=: - - - - - - - -test -z "$RANLIB" && RANLIB=: - - - - - - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# Check for command to grab the raw symbol name followed by C symbol from nm. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 -printf %s "checking command to parse $NM output from $compiler object... " >&6; } -if test ${lt_cv_sys_global_symbol_pipe+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw* | windows* | pw32* | cegcc*) - symcode='[ABCDGISTW]' - ;; -hpux*) - if test ia64 = "$host_cpu"; then - symcode='[ABCDEGRST]' - fi - ;; -irix* | nonstopux*) - symcode='[BCDEGRST]' - ;; -osf*) - symcode='[BCDEGQRST]' - ;; -solaris*) - symcode='[BCDRT]' - ;; -sco3.2v5*) - symcode='[DT]' - ;; -sysv4.2uw2*) - symcode='[DT]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[ABDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[ABCDGIRSTW]' ;; -esac - -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Gets list of data symbols to import. - lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" - # Adjust the below global symbol transforms to fixup imported variables. - lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" - lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" - lt_c_name_lib_hook="\ - -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ - -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" -else - # Disable hooks by default. - lt_cv_sys_global_symbol_to_import= - lt_cdecl_hook= - lt_c_name_hook= - lt_c_name_lib_hook= -fi - -# Transform an extracted symbol line into a proper C declaration. -# Some systems (esp. on ia64) link data and code symbols differently, -# so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ -$lt_cdecl_hook\ -" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ -$lt_c_name_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" - -# Transform an extracted symbol line into symbol name with lib prefix and -# symbol address. -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ -$lt_c_name_lib_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw* | windows*) - opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# Try without a prefix underscore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function, - # D for any global variable and I for any imported variable. - # Also find C++ and __fastcall symbols from MSVC++ or ICC, - # which start with @ or ?. - lt_cv_sys_global_symbol_pipe="$AWK '"\ -" {last_section=section; section=\$ 3};"\ -" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ -" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ -" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ -" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ -" \$ 0!~/External *\|/{next};"\ -" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ -" {if(hide[section]) next};"\ -" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ -" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ -" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ -" ' prfx=^$ac_symprfx" - else - lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <<_LT_EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(void); -void nm_test_func(void){} -#ifdef __cplusplus -} -#endif -int main(void){nm_test_var='a';nm_test_func();return(0);} -_LT_EOF - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Now try to grab the symbols. - nlist=conftest.nm - $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 - if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if $GREP ' nm_test_var$' "$nlist" >/dev/null; then - if $GREP ' nm_test_func$' "$nlist" >/dev/null; then - cat <<_LT_EOF > conftest.$ac_ext -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE -/* DATA imports from DLLs on WIN32 can't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT@&t@_DLSYM_CONST -#elif defined __osf__ -/* This system does not cope well with relocations in const data. */ -# define LT@&t@_DLSYM_CONST -#else -# define LT@&t@_DLSYM_CONST const -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -_LT_EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' - - cat <<_LT_EOF >> conftest.$ac_ext - -/* The mapping between symbol names and symbols. */ -LT@&t@_DLSYM_CONST struct { - const char *name; - void *address; -} -lt__PROGRAM__LTX_preloaded_symbols[] = -{ - { "@PROGRAM@", (void *) 0 }, -_LT_EOF - $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext - cat <<\_LT_EOF >> conftest.$ac_ext - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt__PROGRAM__LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif -_LT_EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_globsym_save_LIBS=$LIBS - lt_globsym_save_CFLAGS=$CFLAGS - LIBS=conftstm.$ac_objext - CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest$ac_exeext; then - pipe_works=yes - fi - LIBS=$lt_globsym_save_LIBS - CFLAGS=$lt_globsym_save_CFLAGS - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - fi - rm -rf conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test yes = "$pipe_works"; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done - ;; -esac -fi - -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -printf '%s\n' "failed" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ok" >&5 -printf '%s\n' "ok" >&6; } -fi - -# Response file support. -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - nm_file_list_spec='@' -elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then - nm_file_list_spec='@' -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 -printf %s "checking for sysroot... " >&6; } - -@%:@ Check whether --with-sysroot was given. -if test ${with_sysroot+y} -then : - withval=$with_sysroot; -else case e in @%:@( - e) with_sysroot=no ;; -esac -fi - - -lt_sysroot= -case $with_sysroot in #( - yes) - if test yes = "$GCC"; then - # Trim trailing / since we'll always append absolute paths and we want - # to avoid //, if only for less confusing output for the user. - lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 -printf '%s\n' "$with_sysroot" >&6; } - as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 - ;; -esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 -printf '%s\n' "${lt_sysroot:-no}" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 -printf %s "checking for a working dd... " >&6; } -if test ${ac_cv_path_lt_DD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -: ${lt_DD:=$DD} -if test -z "$lt_DD"; then - ac_path_lt_DD_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in dd - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_lt_DD" || continue -if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: -fi - $ac_path_lt_DD_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_lt_DD"; then - : - fi -else - ac_cv_path_lt_DD=$lt_DD -fi - -rm -f conftest.i conftest2.i conftest.out ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 -printf '%s\n' "$ac_cv_path_lt_DD" >&6; } - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 -printf %s "checking how to truncate binary pipes... " >&6; } -if test ${lt_cv_truncate_bin+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -lt_cv_truncate_bin= -if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" -fi -rm -f conftest.i conftest2.i conftest.out -test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 -printf '%s\n' "$lt_cv_truncate_bin" >&6; } - - - - - - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in @S|@*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - -@%:@ Check whether --enable-libtool-lock was given. -if test ${enable_libtool_lock+y} -then : - enableval=$enable_libtool_lock; -fi - -test no = "$enable_libtool_lock" || enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out what ABI is being produced by ac_compile, and set mode - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE=32 - ;; - *ELF-64*) - HPUX_IA64_MODE=64 - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - if test yes = "$lt_cv_prog_gnu_ld"; then - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -mips64*-*linux*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - emul=elf - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - emul="${emul}32" - ;; - *64-bit*) - emul="${emul}64" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *MSB*) - emul="${emul}btsmip" - ;; - *LSB*) - emul="${emul}ltsmip" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *N32*) - emul="${emul}n32" - ;; - esac - LD="${LD-ld} -m $emul" - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. Note that the listed cases only cover the - # situations where additional linker options are needed (such as when - # doing 32-bit compilation for a host where ld defaults to 64-bit, or - # vice versa); the common cases where no linker options are needed do - # not appear in the list. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - case `$FILECMD conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac - ;; - powerpc64le-*linux*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - LD="${LD-ld} -m elf_x86_64" - ;; - powerpcle-*linux*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -belf" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 -printf %s "checking whether the C compiler needs -belf... " >&6; } -if test ${lt_cv_cc_needs_belf+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_cc_needs_belf=yes -else case e in @%:@( - e) lt_cv_cc_needs_belf=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 -printf '%s\n' "$lt_cv_cc_needs_belf" >&6; } - if test yes != "$lt_cv_cc_needs_belf"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS=$SAVE_CFLAGS - fi - ;; -*-*solaris*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) - case $host in - i?86-*-solaris*|x86_64-*-solaris*) - LD="${LD-ld} -m elf_x86_64" - ;; - sparc*-*-solaris*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - # GNU ld 2.21 introduced _sol2 emulations. Use them if available. - if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD=${LD-ld}_sol2 - fi - ;; - *) - if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then - LD="${LD-ld} -64" - fi - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; -esac - -need_locks=$enable_libtool_lock - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. -set dummy ${ac_tool_prefix}mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$MANIFEST_TOOL"; then - ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL -if test -n "$MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 -printf '%s\n' "$MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_MANIFEST_TOOL"; then - ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL - # Extract the first word of "mt", so it can be a program name with args. -set dummy mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_MANIFEST_TOOL"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL -if test -n "$ac_ct_MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 -printf '%s\n' "$ac_ct_MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_MANIFEST_TOOL" = x; then - MANIFEST_TOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL - fi -else - MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" -fi - -test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 -printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } -if test ${lt_cv_path_manifest_tool+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_path_manifest_tool=no - echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 - $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out - cat conftest.err >&5 - if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_manifest_tool=yes - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_manifest_tool" >&5 -printf '%s\n' "$lt_cv_path_manifest_tool" >&6; } -if test yes != "$lt_cv_path_manifest_tool"; then - MANIFEST_TOOL=: -fi - - - - - - - case $host_os in - rhapsody* | darwin*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. -set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DSYMUTIL"; then - ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DSYMUTIL=$ac_cv_prog_DSYMUTIL -if test -n "$DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 -printf '%s\n' "$DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DSYMUTIL"; then - ac_ct_DSYMUTIL=$DSYMUTIL - # Extract the first word of "dsymutil", so it can be a program name with args. -set dummy dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DSYMUTIL"; then - ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL -if test -n "$ac_ct_DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 -printf '%s\n' "$ac_ct_DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DSYMUTIL" = x; then - DSYMUTIL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DSYMUTIL=$ac_ct_DSYMUTIL - fi -else - DSYMUTIL="$ac_cv_prog_DSYMUTIL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. -set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$NMEDIT"; then - ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -NMEDIT=$ac_cv_prog_NMEDIT -if test -n "$NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 -printf '%s\n' "$NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_NMEDIT"; then - ac_ct_NMEDIT=$NMEDIT - # Extract the first word of "nmedit", so it can be a program name with args. -set dummy nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_NMEDIT"; then - ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_NMEDIT="nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT -if test -n "$ac_ct_NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 -printf '%s\n' "$ac_ct_NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_NMEDIT" = x; then - NMEDIT=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - NMEDIT=$ac_ct_NMEDIT - fi -else - NMEDIT="$ac_cv_prog_NMEDIT" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. -set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$LIPO"; then - ac_cv_prog_LIPO="$LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -LIPO=$ac_cv_prog_LIPO -if test -n "$LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 -printf '%s\n' "$LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LIPO"; then - ac_ct_LIPO=$LIPO - # Extract the first word of "lipo", so it can be a program name with args. -set dummy lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_LIPO"; then - ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_LIPO="lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO -if test -n "$ac_ct_LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 -printf '%s\n' "$ac_ct_LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_LIPO" = x; then - LIPO=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LIPO=$ac_ct_LIPO - fi -else - LIPO="$ac_cv_prog_LIPO" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -printf '%s\n' "$OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL="otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -printf '%s\n' "$ac_ct_OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OTOOL64"; then - ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL64=$ac_cv_prog_OTOOL64 -if test -n "$OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 -printf '%s\n' "$OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL64"; then - ac_ct_OTOOL64=$OTOOL64 - # Extract the first word of "otool64", so it can be a program name with args. -set dummy otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OTOOL64"; then - ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL64="otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 -if test -n "$ac_ct_OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 -printf '%s\n' "$ac_ct_OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL64" = x; then - OTOOL64=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL64=$ac_ct_OTOOL64 - fi -else - OTOOL64="$ac_cv_prog_OTOOL64" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 -printf %s "checking for -single_module linker flag... " >&6; } -if test ${lt_cv_apple_cc_single_mod+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_apple_cc_single_mod=no - if test -z "$LT_MULTI_MODULE"; then - # By default we will add the -single_module flag. You can override - # by either setting the environment variable LT_MULTI_MODULE - # non-empty at configure time, or by adding -multi_module to the - # link flags. - rm -rf libconftest.dylib* - echo "int foo(void){return 1;}" > conftest.c - echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ --dynamiclib -Wl,-single_module conftest.c" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ - -dynamiclib -Wl,-single_module conftest.c 2>conftest.err - _lt_result=$? - # If there is a non-empty error log, and "single_module" - # appears in it, assume the flag caused a linker warning - if test -s conftest.err && $GREP single_module conftest.err; then - cat conftest.err >&5 - # Otherwise, if the output was created with a 0 exit code from - # the compiler, it worked. - elif test -f libconftest.dylib && test 0 = "$_lt_result"; then - lt_cv_apple_cc_single_mod=yes - else - cat conftest.err >&5 - fi - rm -rf libconftest.dylib* - rm -f conftest.* - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 -printf '%s\n' "$lt_cv_apple_cc_single_mod" >&6; } - - # Feature test to disable chained fixups since it is not - # compatible with '-undefined dynamic_lookup' - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -no_fixup_chains linker flag" >&5 -printf %s "checking for -no_fixup_chains linker flag... " >&6; } -if test ${lt_cv_support_no_fixup_chains+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -Wl,-no_fixup_chains" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_support_no_fixup_chains=yes -else case e in @%:@( - e) lt_cv_support_no_fixup_chains=no - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_support_no_fixup_chains" >&5 -printf '%s\n' "$lt_cv_support_no_fixup_chains" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 -printf %s "checking for -exported_symbols_list linker flag... " >&6; } -if test ${lt_cv_ld_exported_symbols_list+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_exported_symbols_list=no - save_LDFLAGS=$LDFLAGS - echo "_main" > conftest.sym - LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_ld_exported_symbols_list=yes -else case e in @%:@( - e) lt_cv_ld_exported_symbols_list=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 -printf '%s\n' "$lt_cv_ld_exported_symbols_list" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 -printf %s "checking for -force_load linker flag... " >&6; } -if test ${lt_cv_ld_force_load+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5 - $AR $AR_FLAGS libconftest.a conftest.o 2>&5 - echo "$RANLIB libconftest.a" >&5 - $RANLIB libconftest.a 2>&5 - cat > conftest.c << _LT_EOF -int main(void) { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -s conftest.err && $GREP force_load conftest.err; then - cat conftest.err >&5 - elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&5 - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 -printf '%s\n' "$lt_cv_ld_force_load" >&6; } - case $host_os in - rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; - darwin1.*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - darwin*) - case $MACOSX_DEPLOYMENT_TARGET,$host in - 10.[012],*|,*powerpc*-darwin[5-8]*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - *) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' - if test yes = "$lt_cv_support_no_fixup_chains"; then - as_fn_append _lt_dar_allow_undefined ' $wl-no_fixup_chains' - fi - ;; - esac - ;; - esac - if test yes = "$lt_cv_apple_cc_single_mod"; then - _lt_dar_single_mod='$single_module' - fi - _lt_dar_needs_single_mod=no - case $host_os in - rhapsody* | darwin1.*) - _lt_dar_needs_single_mod=yes ;; - darwin*) - # When targeting Mac OS X 10.4 (darwin 8) or later, - # -single_module is the default and -multi_module is unsupported. - # The toolchain on macOS 10.14 (darwin 18) and later cannot - # target any OS version that needs -single_module. - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*-darwin[567].*|10.[0-3],*-darwin[5-9].*|10.[0-3],*-darwin1[0-7].*) - _lt_dar_needs_single_mod=yes ;; - esac - ;; - esac - if test yes = "$lt_cv_ld_exported_symbols_list"; then - _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' - else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' - fi - if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then - _lt_dsymutil='~$DSYMUTIL $lib || :' - else - _lt_dsymutil= - fi - ;; - esac - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x@S|@2 in - x) - ;; - *:) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" - ;; - x:*) - eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" - ;; - *) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - esac -} - -ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default -" -if test "x$ac_cv_header_dlfcn_h" = xyes -then : - printf '%s\n' "@%:@define HAVE_DLFCN_H 1" >>confdefs.h - -fi - - - - - -# Set options - - - - enable_dlopen=no - - - enable_win32_dll=no - - - @%:@ Check whether --enable-shared was given. -if test ${enable_shared+y} -then : - enableval=$enable_shared; p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_shared=yes ;; -esac -fi - - - - - - - - - - @%:@ Check whether --enable-static was given. -if test ${enable_static+y} -then : - enableval=$enable_static; p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_static=yes ;; -esac -fi - - - - - - - - - - @%:@ Check whether --enable-pic was given. -if test ${enable_pic+y} -then : - enableval=$enable_pic; lt_p=${PACKAGE-default} - case $enableval in - yes|no) pic_mode=$enableval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) @%:@ Check whether --with-pic was given. -if test ${with_pic+y} -then : - withval=$with_pic; lt_p=${PACKAGE-default} - case $withval in - yes|no) pic_mode=$withval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $withval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) pic_mode=default ;; -esac -fi - - ;; -esac -fi - - - - - - - - - @%:@ Check whether --enable-fast-install was given. -if test ${enable_fast_install+y} -then : - enableval=$enable_fast_install; p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_fast_install=yes ;; -esac -fi - - - - - - - - - shared_archive_member_spec= -case $host,$enable_shared in -power*-*-aix[5-9]*,yes) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 -printf %s "checking which variant of shared library versioning to provide... " >&6; } - @%:@ Check whether --enable-aix-soname was given. -if test ${enable_aix_soname+y} -then : - enableval=$enable_aix_soname; case $enableval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --enable-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$enable_aix_soname -else case e in @%:@( - e) @%:@ Check whether --with-aix-soname was given. -if test ${with_aix_soname+y} -then : - withval=$with_aix_soname; case $withval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$with_aix_soname -else case e in @%:@( - e) if test ${lt_cv_with_aix_soname+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_with_aix_soname=aix ;; -esac -fi - ;; -esac -fi - - enable_aix_soname=$lt_cv_with_aix_soname ;; -esac -fi - - with_aix_soname=$enable_aix_soname - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 -printf '%s\n' "$with_aix_soname" >&6; } - if test aix != "$with_aix_soname"; then - # For the AIX way of multilib, we name the shared archive member - # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', - # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. - # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, - # the AIX toolchain works better with OBJECT_MODE set (default 32). - if test 64 = "${OBJECT_MODE-32}"; then - shared_archive_member_spec=shr_64 - else - shared_archive_member_spec=shr - fi - fi - ;; -*) - with_aix_soname=aix - ;; -esac - - - - - - - - - - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS=$ltmain - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -test -z "$LN_S" && LN_S="ln -s" - - - - - - - - - - - - - - -if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 -printf %s "checking for objdir... " >&6; } -if test ${lt_cv_objdir+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 -printf '%s\n' "$lt_cv_objdir" >&6; } -objdir=$lt_cv_objdir - - - - - -printf '%s\n' "@%:@define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h - - - - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Global variables: -ofile=libtool -can_build_shared=yes - -# All known linkers require a '.a' archive for static linking (except MSVC and -# ICC, which need '.lib'). -libext=a - -with_gnu_ld=$lt_cv_prog_gnu_ld - -old_CC=$CC -old_CFLAGS=$CFLAGS - -# Set sane defaults for various variables -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$LD" && LD=ld -test -z "$ac_objext" && ac_objext=o - -func_cc_basename $compiler -cc_basename=$func_cc_basename_result - - -# Only perform the check for file, if the check method requires it -test -z "$MAGIC_CMD" && MAGIC_CMD=file -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 -printf %s "checking for ${ac_tool_prefix}file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/${ac_tool_prefix}file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for file" >&5 -printf %s "checking for file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - else - MAGIC_CMD=: - fi -fi - - fi - ;; -esac - -# Use C for the default configuration in the libtool script - -lt_save_CC=$CC -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -objext=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(void){return(0);}' - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - -# Save the default compiler, since it gets overwritten when the other -# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. -compiler_DEFAULT=$CC - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - -lt_prog_compiler_no_builtin_flag= - -if test yes = "$GCC"; then - case $cc_basename in - nvcc*) - lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; - *) - lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; - esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if test ${lt_cv_prog_compiler_rtti_exceptions+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -printf '%s\n' "$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then - lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" -else - : -fi - -fi - - - - - - - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - - - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - -hard_links=nottested -if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then - # do not overwrite the value of need_locks provided by the user - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -printf %s "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -printf '%s\n' "$hard_links" >&6; } - if test no = "$hard_links"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 -printf '%s\n' "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - runpath_var= - allow_undefined_flag= - always_export_symbols=no - archive_cmds= - archive_expsym_cmds= - compiler_needs_object=no - enable_shared_with_static_runtimes=no - export_dynamic_flag_spec= - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - hardcode_automatic=no - hardcode_direct=no - hardcode_direct_absolute=no - hardcode_libdir_flag_spec= - hardcode_libdir_separator= - hardcode_minus_L=no - hardcode_shlibpath_var=unsupported - inherit_rpath=no - link_all_deplibs=unknown - module_cmds= - module_expsym_cmds= - old_archive_from_new_cmds= - old_archive_from_expsyms_cmds= - thread_safe_flag_spec= - whole_archive_flag_spec= - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ' (' and ')$', so one must not match beginning or - # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', - # as well as any symbol that contains 'd'. - exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - # Exclude shared library initialization/finalization symbols. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - if test yes != "$GCC"; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) - with_gnu_ld=yes - ;; - esac - - ld_shlibs=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test yes = "$with_gnu_ld"; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; - *\ \(GNU\ Binutils\)\ [3-9]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test yes = "$lt_use_gnu_ld_interface"; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='$wl' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='$wl--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' - else - whole_archive_flag_spec= - fi - supports_anon_versioning=no - case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test ia64 != "$host_cpu"; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.19, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. - -_LT_EOF - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='$wl--export-all-symbols' - allow_undefined_flag=unsupported - always_export_symbols=no - enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' - file_list_spec='@' - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file, use it as - # is; otherwise, prepend EXPORTS... - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs=no - fi - ;; - - haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - link_all_deplibs=no - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - interix[3-9]*) - hardcode_direct=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) - tmp_diet=no - if test linux-dietlibc = "$host_os"; then - case $cc_basename in - diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) - esac - fi - if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test no = "$tmp_diet" - then - tmp_addflag=' $pic_flag' - tmp_sharedflag='-shared' - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - lf95*) # Lahey Fortran 8.1 - whole_archive_flag_spec= - tmp_sharedflag='--shared' ;; - nagfor*) # NAGFOR 5.3 - tmp_sharedflag='-Wl,-shared' ;; - xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) - tmp_sharedflag='-qmkshrobj' - tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - ;; - esac - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' - fi - - case $cc_basename in - tcc*) - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='-rdynamic' - ;; - xlf* | bgf* | bgxlf* | mpixlf*) - # IBM XL Fortran 10.1 on PPC cannot create shared libs itself - whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' - fi - ;; - esac - else - ld_shlibs=no - fi - ;; - - *-mlibc) - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test no = "$ld_shlibs"; then - runpath_var= - hardcode_libdir_flag_spec= - export_dynamic_flag_spec= - whole_archive_flag_spec= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix[4-9]*) - if test ia64 = "$host_cpu"; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag= - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to GNU nm, but means don't demangle to AIX nm. - # Without the "-l" option, or with the "-B" option, AIX nm treats - # weak defined symbols like other global defined symbols, whereas - # GNU nm marks them as "W". - # While the 'weak' keyword is ignored in the Export File, we need - # it in the Import File for the 'aix-soname' feature, so we have - # to replace the "-B" option with "-P" for AIX nm. - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # have runtime linking enabled, and use it for executables. - # For shared libraries, we enable/disable runtime linking - # depending on the kind of the shared library created - - # when "with_aix_soname,aix_use_runtimelinking" is: - # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables - # "aix,yes" lib.so shared, rtl:yes, for executables - # lib.a static archive - # "both,no" lib.so.V(shr.o) shared, rtl:yes - # lib.a(lib.so.V) shared, rtl:no, for executables - # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a(lib.so.V) shared, rtl:no - # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a static archive - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then - aix_use_runtimelinking=yes - break - fi - done - if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then - # With aix-soname=svr4, we create the lib.so.V shared archives only, - # so we don't have lib.a shared libs to link our executables. - # We have to force runtime linking in this case. - aix_use_runtimelinking=yes - LDFLAGS="$LDFLAGS -Wl,-brtl" - fi - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds='' - hardcode_direct=yes - hardcode_direct_absolute=yes - hardcode_libdir_separator=':' - link_all_deplibs=yes - file_list_spec='$wl-f,' - case $with_aix_soname,$aix_use_runtimelinking in - aix,*) ;; # traditional, no import file - svr4,* | *,yes) # use import file - # The Import File defines what to hardcode. - hardcode_direct=no - hardcode_direct_absolute=no - ;; - esac - - if test yes = "$GCC"; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`$CC -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - shared_flag='-shared' - if test yes = "$aix_use_runtimelinking"; then - shared_flag="$shared_flag "'$wl-G' - fi - # Need to ensure runtime linking is disabled for the traditional - # shared library, or the linker may eventually find shared libraries - # /with/ Import File - we do not want to mix them. - shared_flag_aix='-shared' - shared_flag_svr4='-shared $wl-G' - else - # not using gcc - if test ia64 = "$host_cpu"; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test yes = "$aix_use_runtimelinking"; then - shared_flag='$wl-G' - else - shared_flag='$wl-bM:SRE' - fi - shared_flag_aix='$wl-bM:SRE' - shared_flag_svr4='$wl-G' - fi - fi - - export_dynamic_flag_spec='$wl-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols=yes - if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag='-berok' - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag - else - if test ia64 = "$host_cpu"; then - hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' - allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag=' $wl-bernotok' - allow_undefined_flag=' $wl-berok' - if test yes = "$with_gnu_ld"; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - fi - archive_cmds_need_lc=yes - archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' - # -brtl affects multiple linker settings, -berok does not and is overridden later - compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' - if test svr4 != "$with_aix_soname"; then - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' - fi - if test aix != "$with_aix_soname"; then - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' - else - # used by -dlpreopen to get the symbols - archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' - fi - archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' - fi - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - bsdi[45]*) - export_dynamic_flag_spec=-rdynamic - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - case $cc_basename in - cl* | icl*) - # Native MSVC or ICC - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - always_export_symbols=yes - file_list_spec='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -Fe$output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp "$export_symbols" "$output_objdir/$soname.def"; - echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; - else - $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -Fe$tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, )='true' - enable_shared_with_static_runtimes=yes - exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - # Don't use ranlib - old_postinstall_cmds='chmod 644 $oldlib' - postlink_cmds='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile=$lt_outputfile.exe - lt_tool_outputfile=$lt_tool_outputfile.exe - ;; - esac~ - if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # Assume MSVC and ICC wrapper - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - enable_shared_with_static_runtimes=yes - ;; - esac - ;; - - darwin* | rhapsody*) - - - archive_cmds_need_lc=no - hardcode_direct=no - hardcode_automatic=yes - hardcode_shlibpath_var=unsupported - if test yes = "$lt_cv_ld_force_load"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec='' - fi - link_all_deplibs=yes - allow_undefined_flag=$_lt_dar_allow_undefined - case $cc_basename in - ifort*|nagfor*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test yes = "$_lt_dar_can_shared"; then - output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" - archive_expsym_cmds="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" - module_expsym_cmds="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" - - else - ld_shlibs=no - fi - - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly* | midnightbsd*) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9*) - if test yes = "$GCC"; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - export_dynamic_flag_spec='$wl-E' - ;; - - hpux10*) - if test yes,no = "$GCC,$with_gnu_ld"; then - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - - hpux11*) - if test yes,no = "$GCC,$with_gnu_ld"; then - case $host_cpu in - hppa*64*) - archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 -printf %s "checking if $CC understands -b... " >&6; } -if test ${lt_cv_prog_compiler__b+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler__b=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -b" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler__b=yes - fi - else - lt_cv_prog_compiler__b=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 -printf '%s\n' "$lt_cv_prog_compiler__b" >&6; } - -if test yes = "$lt_cv_prog_compiler__b"; then - archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' -else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' -fi - - ;; - esac - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - hardcode_shlibpath_var=no - ;; - *) - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test yes = "$GCC"; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - # Try to use the -exported_symbol ld option, if it does not - # work, assume that -exports_file does not work either and - # implicitly export all symbols. - # This should be the same for all languages, so no per-tag cache variable. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 -printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } -if test ${lt_cv_irix_exported_symbol+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int foo (void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_irix_exported_symbol=yes -else case e in @%:@( - e) lt_cv_irix_exported_symbol=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 -printf '%s\n' "$lt_cv_irix_exported_symbol" >&6; } - if test yes = "$lt_cv_irix_exported_symbol"; then - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' - fi - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - inherit_rpath=yes - link_all_deplibs=yes - ;; - - linux*) - case $cc_basename in - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - ld_shlibs=yes - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - esac - ;; - - *-mlibc) - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - newsos6) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - hardcode_shlibpath_var=no - ;; - - *nto* | *qnx*) - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - hardcode_shlibpath_var=no - hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - else - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - fi - else - ld_shlibs=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - osf3*) - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - archive_cmds_need_lc='no' - hardcode_libdir_separator=: - ;; - - serenity*) - ;; - - solaris*) - no_undefined_flag=' -z defs' - if test yes = "$GCC"; then - wlarc='$wl' - archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - else - case `$CC -V 2>&1` in - *"Compilers 5.0"*) - wlarc='' - archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' - ;; - *) - wlarc='$wl' - archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - ;; - esac - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands '-z linker_flag'. GCC discards it without '$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test yes = "$GCC"; then - whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' - else - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs=yes - ;; - - sunos4*) - if test sequent = "$host_vendor"; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds='$CC -r -o $output$reload_objs' - hardcode_direct=no - ;; - motorola) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='$wl-z,text' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We CANNOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag='$wl-z,text' - allow_undefined_flag='$wl-z,nodefs' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-R,$libdir' - hardcode_libdir_separator=':' - link_all_deplibs=yes - export_dynamic_flag_spec='$wl-Bexport' - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - *) - ld_shlibs=no - ;; - esac - - if test sni = "$host_vendor"; then - case $host in - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='$wl-Blargedynsym' - ;; - esac - fi - fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 -printf '%s\n' "$ld_shlibs" >&6; } -test no = "$ld_shlibs" && can_build_shared=no - -with_gnu_ld=$with_gnu_ld - - - - - - - - - - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc=yes - - if test yes,yes = "$GCC,$enable_shared"; then - case $archive_cmds in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -printf %s "checking whether -lc should be explicitly linked in... " >&6; } -if test ${lt_cv_archive_cmds_need_lc+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc=no - else - lt_cv_archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 -printf '%s\n' "$lt_cv_archive_cmds_need_lc" >&6; } - archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -printf %s "checking dynamic linker characteristics... " >&6; } - -if test yes = "$GCC"; then - case $host_os in - darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; - *) lt_awk_arg='/^libraries:/' ;; - esac - case $host_os in - mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; - *) lt_sed_strip_eq='s|=/|/|g' ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary... - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - # ...but if some path component already ends with the multilib dir we assume - # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). - case "$lt_multi_os_dir; $lt_search_path_spec " in - "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) - lt_multi_os_dir= - ;; - esac - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" - elif test -n "$lt_multi_os_dir"; then - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS = " "; FS = "/|\n";} { - lt_foo = ""; - lt_count = 0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo = "/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[lt_foo]++; } - if (lt_freq[lt_foo] == 1) { print lt_foo; } -}'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's|/\([A-Za-z]:\)|\1|g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=.so -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - - - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='$libname$release$shared_ext$major' - ;; - -aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test ia64 = "$host_cpu"; then - # AIX 5 supports IA64 - library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line '#! .'. This would cause the generated library to - # depend on '.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # Using Import Files as archive members, it is possible to support - # filename-based versioning of shared library archives on AIX. While - # this would work for both with and without runtime linking, it will - # prevent static linking of such archives. So we do filename-based - # shared library versioning with .so extension only, which is used - # when both runtime linking and shared linking is enabled. - # Unfortunately, runtime linking may impact performance, so we do - # not want this to be the default eventually. Also, we use the - # versioned .so libs for executables only if there is the -brtl - # linker flag in LDFLAGS as well, or --enable-aix-soname=svr4 only. - # To allow for filename-based versioning support, we need to create - # libNAME.so.V as an archive file, containing: - # *) an Import File, referring to the versioned filename of the - # archive as well as the shared archive member, telling the - # bitwidth (32 or 64) of that shared object, and providing the - # list of exported symbols of that shared object, eventually - # decorated with the 'weak' keyword - # *) the shared object with the F_LOADONLY flag set, to really avoid - # it being seen by the linker. - # At run time we better use the real file rather than another symlink, - # but for link time we create the symlink libNAME.so -> libNAME.so.V - - case $with_aix_soname,$aix_use_runtimelinking in - # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - aix,yes) # traditional libtool - dynamic_linker='AIX unversionable lib.so' - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - aix,no) # traditional AIX only - dynamic_linker='AIX lib.a(lib.so.V)' - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - ;; - svr4,*) # full svr4 only - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,yes) # both, prefer svr4 - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # unpreferred sharedlib libNAME.a needs extra handling - postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' - postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,no) # both, prefer aix - dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling - postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' - postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' - ;; - esac - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='$libname$shared_ext' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | windows* | pw32* | cegcc*) - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - # If user builds GCC with multilib enabled, - # it should just install on $(libdir) - # not on $(libdir)/../bin or 32 bits dlls would override 64 bit ones. - if test xyes = x"$multilib"; then - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - $install_prog $dir/$dlname $destdir/$dlname~ - chmod a+x $destdir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib $destdir/$dlname'\'' || exit \$?; - fi' - else - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - fi - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" - ;; - mingw* | windows* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl* | *,icl*) - # Native MSVC or ICC - libname_spec='$name' - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - library_names_spec='$libname.dll.lib' - - case $build_os in - mingw* | windows*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec=$LIB - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC and ICC wrapper - library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' - soname_spec='$libname$release$major$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly* | midnightbsd*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - need_version=yes - ;; - esac - case $host_cpu in - powerpc64) - # On FreeBSD bi-arch platforms, a different variable is used for 32-bit - # binaries. See . - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int test_pointer_size[sizeof (void *) - 5]; - -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - shlibpath_var=LD_LIBRARY_PATH -else case e in @%:@( - e) shlibpath_var=LD_32_LIBRARY_PATH ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; - *) - shlibpath_var=LD_LIBRARY_PATH - ;; - esac - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/boot/system/non-packaged/develop/lib /boot/system/develop/lib' - sys_lib_dlsearch_path_spec='/boot/home/config/non-packaged/lib /boot/home/config/lib /boot/system/non-packaged/lib /boot/system/lib' - hardcode_into_libs=no - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - if test 32 = "$HPUX_IA64_MODE"; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - sys_lib_dlsearch_path_spec=/usr/lib/hpux32 - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - sys_lib_dlsearch_path_spec=/usr/lib/hpux64 - fi - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test yes = "$lt_cv_prog_gnu_ld"; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" - sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -linux*android*) - version_type=none # Android doesn't support versioned libraries. - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - dynamic_linker='Android linker' - # -rpath works at least for libraries that are not overridden by - # libraries installed in system locations. - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if test ${lt_cv_shlibpath_overrides_runpath+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null -then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - ;; -esac -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Ideally, we could use ldconfig to report *all* directories which are - # searched for libraries, however this is still not possible. Aside from not - # being certain /sbin/ldconfig is available, command - # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, - # even though it is searched at run-time. Try to do the best guess by - # appending ld.so.conf contents (and includes) to the search path. - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -*-mlibc) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='mlibc ld.so' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec=/usr/lib - need_lib_prefix=no - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - need_version=no - else - need_version=yes - fi - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -os2*) - libname_spec='$name' - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - # OS/2 can only load a DLL with a base name of 8 characters or less. - soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; - v=$($ECHO $release$versuffix | tr -d .-); - n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); - $ECHO $n$v`$shared_ext' - library_names_spec='${libname}_dll.$libext' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=BEGINLIBPATH - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - -rdos*) - dynamic_linker=no - ;; - -serenity*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - dynamic_linker='SerenityOS LibELF' - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test yes = "$with_gnu_ld"; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec; then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' - soname_spec='$libname$shared_ext.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=sco - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test yes = "$with_gnu_ld"; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -emscripten*) - version_type=none - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - dynamic_linker="Emscripten linker" - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - -='-fPIC' - archive_cmds='$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib -s EXPORTED_FUNCTIONS=@$output_objdir/$soname.expsym' - archive_cmds_need_lc=no - no_undefined_flag= - ;; - -*) - dynamic_linker=no - ;; -esac -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -printf '%s\n' "$dynamic_linker" >&6; } -test no = "$dynamic_linker" && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test yes = "$GCC"; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then - sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec -fi - -if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then - sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec -fi - -# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... -configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec - -# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code -func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" - -# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool -configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -printf %s "checking how to hardcode library paths into programs... " >&6; } -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || - test -n "$runpath_var" || - test yes = "$hardcode_automatic"; then - - # We can hardcode non-existent directories. - if test no != "$hardcode_direct" && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && - test no != "$hardcode_minus_L"; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 -printf '%s\n' "$hardcode_action" >&6; } - -if test relink = "$hardcode_action" || - test yes = "$inherit_rpath"; then - # Fast installation is not supported - enable_fast_install=no -elif test yes = "$shlibpath_overrides_runpath" || - test no = "$enable_shared"; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - if test yes != "$enable_dlopen"; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen=load_add_on - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | windows* | pw32* | cegcc*) - lt_cv_dlopen=LoadLibrary - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in @%:@( - e) - lt_cv_dlopen=dyld - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; -esac -fi - - ;; - - tpf*) - # Don't try to run any link tests for TPF. We know it's impossible - # because TPF is a cross-compiler, and we know how we open DSOs. - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - lt_cv_dlopen_self=no - ;; - - *) - ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" -if test "x$ac_cv_func_shl_load" = xyes -then : - lt_cv_dlopen=shl_load -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 -printf %s "checking for shl_load in -ldld... " >&6; } -if test ${ac_cv_lib_dld_shl_load+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (void); -int -main (void) -{ -return shl_load (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_shl_load=yes -else case e in @%:@( - e) ac_cv_lib_dld_shl_load=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 -printf '%s\n' "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes -then : - lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld -else case e in @%:@( - e) ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes -then : - lt_cv_dlopen=dlopen -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 -printf %s "checking for dlopen in -lsvld... " >&6; } -if test ${ac_cv_lib_svld_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_svld_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_svld_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_svld_dlopen" >&6; } -if test "x$ac_cv_lib_svld_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 -printf %s "checking for dld_link in -ldld... " >&6; } -if test ${ac_cv_lib_dld_dld_link+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (void); -int -main (void) -{ -return dld_link (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_dld_link=yes -else case e in @%:@( - e) ac_cv_lib_dld_dld_link=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 -printf '%s\n' "$ac_cv_lib_dld_dld_link" >&6; } -if test "x$ac_cv_lib_dld_dld_link" = xyes -then : - lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; - esac - - if test no = "$lt_cv_dlopen"; then - enable_dlopen=no - else - enable_dlopen=yes - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS=$CPPFLAGS - test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS=$LDFLAGS - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS=$LIBS - LIBS="$lt_cv_dlopen_libs $LIBS" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 -printf %s "checking whether a program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 -printf '%s\n' "$lt_cv_dlopen_self" >&6; } - - if test yes = "$lt_cv_dlopen_self"; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 -printf %s "checking whether a statically linked program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self_static+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self_static=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self_static=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 -printf '%s\n' "$lt_cv_dlopen_self_static" >&6; } - fi - - CPPFLAGS=$save_CPPFLAGS - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - - - - - - - - - - - - - - - - - -striplib= -old_striplib= -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 -printf %s "checking whether stripping libraries is possible... " >&6; } -if test -z "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -else - if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - case $host_os in - darwin*) - # FIXME - insert some real tests, host_os isn't really good enough - striplib="$STRIP -x" - old_striplib="$STRIP -S" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - ;; - freebsd*) - if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - fi - ;; - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - ;; - esac - fi -fi - - - - - - - - - - - - - # Report what library types will actually be built - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 -printf %s "checking if libtool supports shared libraries... " >&6; } - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 -printf '%s\n' "$can_build_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 -printf %s "checking whether to build shared libraries... " >&6; } - test no = "$can_build_shared" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test yes = "$enable_shared" && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - - aix[4-9]*) - if test ia64 != "$host_cpu"; then - case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in - yes,aix,yes) ;; # shared object as lib.so file only - yes,svr4,*) ;; # shared object as lib.so archive member only - yes,*) enable_static=no ;; # shared object in lib.a archive as well - esac - fi - ;; - esac - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 -printf '%s\n' "$enable_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 -printf %s "checking whether to build static libraries... " >&6; } - # Make sure either enable_shared or enable_static is yes. - test yes = "$enable_shared" || enable_static=yes - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 -printf '%s\n' "$enable_static" >&6; } - - - - -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC=$lt_save_CC - - - - - - - - - - - - - - - - ac_config_commands="$ac_config_commands libtool" - - - - -# Only expand once: - - - -# Require xorg-macros minimum of 1.12 for DocBook external references - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to detect undeclared functions" >&5 -printf %s "checking for $CC options to detect undeclared functions... " >&6; } -if test ${ac_cv_c_undeclared_builtin_options+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_save_CFLAGS=$CFLAGS - ac_cv_c_undeclared_builtin_options='cannot detect' - for ac_arg in '' -fno-builtin; do - CFLAGS="$ac_save_CFLAGS $ac_arg" - # This test program should *not* compile successfully. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -(void) strchr; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) # This test program should compile successfully. - # No library function is consistently available on - # freestanding implementations, so test against a dummy - # declaration. Include always-available headers on the - # off chance that they somehow elicit warnings. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include -extern void ac_decl (int, char *); - -int -main (void) -{ -(void) ac_decl (0, (char *) 0); - (void) ac_decl; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - if test x"$ac_arg" = x -then : - ac_cv_c_undeclared_builtin_options='none needed' -else case e in @%:@( - e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; -esac -fi - break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - done - CFLAGS=$ac_save_CFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 -printf '%s\n' "$ac_cv_c_undeclared_builtin_options" >&6; } - case $ac_cv_c_undeclared_builtin_options in @%:@( - 'cannot detect') : - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot make $CC report undeclared builtins -See 'config.log' for more details" "$LINENO" 5; } ;; @%:@( - 'none needed') : - ac_c_undeclared_builtin_options='' ;; @%:@( - *) : - ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to ignore future-version functions" >&5 -printf %s "checking for $CC options to ignore future-version functions... " >&6; } -if test ${ac_cv_c_future_darwin_options+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_compile_saved="$ac_compile" - ac_compile="$ac_compile -Werror=unguarded-availability-new" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if ! (defined __APPLE__ && defined __MACH__) - #error "-Werror=unguarded-availability-new not needed here" - #endif - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_future_darwin_options='-Werror=unguarded-availability-new' -else case e in @%:@( - e) ac_cv_c_future_darwin_options='none needed' ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_compile="$ac_compile_saved" - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_future_darwin_options" >&5 -printf '%s\n' "$ac_cv_c_future_darwin_options" >&6; } - case $ac_cv_c_future_darwin_options in @%:@( - 'none needed') : - ac_c_future_darwin_options='' ;; @%:@( - *) : - ac_c_future_darwin_options=$ac_cv_c_future_darwin_options ;; -esac - - - - - -ac_fn_check_decl "$LINENO" "__clang__" "ac_cv_have_decl___clang__" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___clang__" = xyes -then : - CLANGCC="yes" -else case e in @%:@( - e) CLANGCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__INTEL_COMPILER" "ac_cv_have_decl___INTEL_COMPILER" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___INTEL_COMPILER" = xyes -then : - INTELCC="yes" -else case e in @%:@( - e) INTELCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__SUNPRO_C" "ac_cv_have_decl___SUNPRO_C" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___SUNPRO_C" = xyes -then : - SUNCC="yes" -else case e in @%:@( - e) SUNCC="no" ;; -esac -fi - - - - - - - - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. -set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -PKG_CONFIG=$ac_cv_path_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -printf '%s\n' "$PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_path_PKG_CONFIG"; then - ac_pt_PKG_CONFIG=$PKG_CONFIG - # Extract the first word of "pkg-config", so it can be a program name with args. -set dummy pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $ac_pt_PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG -if test -n "$ac_pt_PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 -printf '%s\n' "$ac_pt_PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_pt_PKG_CONFIG" = x; then - PKG_CONFIG="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - PKG_CONFIG=$ac_pt_PKG_CONFIG - fi -else - PKG_CONFIG="$ac_cv_path_PKG_CONFIG" -fi - -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=0.9.0 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 -printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - PKG_CONFIG="" - fi -fi - - - - - -@%:@ Check whether --enable-selective-werror was given. -if test ${enable_selective_werror+y} -then : - enableval=$enable_selective_werror; SELECTIVE_WERROR=$enableval -else case e in @%:@( - e) SELECTIVE_WERROR=yes ;; -esac -fi - - - - - -# -v is too short to test reliably with XORG_TESTSET_CFLAG -if test "x$SUNCC" = "xyes"; then - BASE_CFLAGS="-v" -else - BASE_CFLAGS="" -fi - -# This chunk of warnings were those that existed in the legacy CWARNFLAGS - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wall" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wall" >&5 -printf %s "checking if $CC supports -Wall... " >&6; } - cacheid=xorg_cv_cc_flag__Wall - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wall" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-arith" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-arith" >&5 -printf %s "checking if $CC supports -Wpointer-arith... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_arith - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-arith" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-declarations" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-declarations" >&5 -printf %s "checking if $CC supports -Wmissing-declarations... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_declarations - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-declarations" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat=2" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat=2" >&5 -printf %s "checking if $CC supports -Wformat=2... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat_2 - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat=2" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat" >&5 -printf %s "checking if $CC supports -Wformat... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat" - found="yes" - fi - fi - - - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wstrict-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wstrict-prototypes" >&5 -printf %s "checking if $CC supports -Wstrict-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wstrict_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wstrict-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-prototypes" >&5 -printf %s "checking if $CC supports -Wmissing-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnested-externs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnested-externs" >&5 -printf %s "checking if $CC supports -Wnested-externs... " >&6; } - cacheid=xorg_cv_cc_flag__Wnested_externs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnested-externs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wbad-function-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wbad-function-cast" >&5 -printf %s "checking if $CC supports -Wbad-function-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wbad_function_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wbad-function-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wold-style-definition" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wold-style-definition" >&5 -printf %s "checking if $CC supports -Wold-style-definition... " >&6; } - cacheid=xorg_cv_cc_flag__Wold_style_definition - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wold-style-definition" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -fd" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -fd" >&5 -printf %s "checking if $CC supports -fd... " >&6; } - cacheid=xorg_cv_cc_flag__fd - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -fd" - found="yes" - fi - fi - - - - - -# This chunk adds additional warnings that could catch undesired effects. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wunused" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wunused" >&5 -printf %s "checking if $CC supports -Wunused... " >&6; } - cacheid=xorg_cv_cc_flag__Wunused - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wunused" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wuninitialized" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wuninitialized" >&5 -printf %s "checking if $CC supports -Wuninitialized... " >&6; } - cacheid=xorg_cv_cc_flag__Wuninitialized - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wuninitialized" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wshadow" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wshadow" >&5 -printf %s "checking if $CC supports -Wshadow... " >&6; } - cacheid=xorg_cv_cc_flag__Wshadow - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wshadow" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-noreturn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-noreturn" >&5 -printf %s "checking if $CC supports -Wmissing-noreturn... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_noreturn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-noreturn" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-format-attribute" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-format-attribute" >&5 -printf %s "checking if $CC supports -Wmissing-format-attribute... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_format_attribute - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-format-attribute" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wredundant-decls" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wredundant-decls" >&5 -printf %s "checking if $CC supports -Wredundant-decls... " >&6; } - cacheid=xorg_cv_cc_flag__Wredundant_decls - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wredundant-decls" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wlogical-op" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wlogical-op" >&5 -printf %s "checking if $CC supports -Wlogical-op... " >&6; } - cacheid=xorg_cv_cc_flag__Wlogical_op - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wlogical-op" - found="yes" - fi - fi - - - -# These are currently disabled because they are noisy. They will be enabled -# in the future once the codebase is sufficiently modernized to silence -# them. For now, I don't want them to drown out the other warnings. -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wparentheses]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-align]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-qual]) - -# Turn some warnings into errors, so we don't accidentally get successful builds -# when there are problems that should be fixed. - -if test "x$SELECTIVE_WERROR" = "xyes" ; then - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=implicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=implicit" >&5 -printf %s "checking if $CC supports -Werror=implicit... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_implicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=implicit" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" >&5 -printf %s "checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_NO_EXPLICIT_TYPE_GIVEN__errwarn_E_NO_IMPLICIT_DECL_ALLOWED - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=nonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=nonnull" >&5 -printf %s "checking if $CC supports -Werror=nonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_nonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=nonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=init-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=init-self" >&5 -printf %s "checking if $CC supports -Werror=init-self... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_init_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=init-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=main" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=main" >&5 -printf %s "checking if $CC supports -Werror=main... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_main - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=main" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=missing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=missing-braces" >&5 -printf %s "checking if $CC supports -Werror=missing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_missing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=missing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=sequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=sequence-point" >&5 -printf %s "checking if $CC supports -Werror=sequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_sequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=sequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=return-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=return-type" >&5 -printf %s "checking if $CC supports -Werror=return-type... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_return_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=return-type" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT" >&5 -printf %s "checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_FUNC_HAS_NO_RETURN_STMT - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=trigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=trigraphs" >&5 -printf %s "checking if $CC supports -Werror=trigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_trigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=trigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=array-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=array-bounds" >&5 -printf %s "checking if $CC supports -Werror=array-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_array_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=array-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=write-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=write-strings" >&5 -printf %s "checking if $CC supports -Werror=write-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_write_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=write-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=address" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=address" >&5 -printf %s "checking if $CC supports -Werror=address... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_address - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=address" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=int-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=int-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Werror=int-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_int_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=int-to-pointer-cast" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION" >&5 -printf %s "checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_BAD_PTR_INT_COMBINATION - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=pointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=pointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Werror=pointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_pointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=pointer-to-int-cast" - found="yes" - fi - fi - - # Also -errwarn=E_BAD_PTR_INT_COMBINATION -else -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&5 -printf '%s\n' "$as_me: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&2;} - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wimplicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wimplicit" >&5 -printf %s "checking if $CC supports -Wimplicit... " >&6; } - cacheid=xorg_cv_cc_flag__Wimplicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wimplicit" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnonnull" >&5 -printf %s "checking if $CC supports -Wnonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Wnonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Winit-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Winit-self" >&5 -printf %s "checking if $CC supports -Winit-self... " >&6; } - cacheid=xorg_cv_cc_flag__Winit_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Winit-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmain" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmain" >&5 -printf %s "checking if $CC supports -Wmain... " >&6; } - cacheid=xorg_cv_cc_flag__Wmain - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmain" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-braces" >&5 -printf %s "checking if $CC supports -Wmissing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wsequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wsequence-point" >&5 -printf %s "checking if $CC supports -Wsequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Wsequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wsequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wreturn-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wreturn-type" >&5 -printf %s "checking if $CC supports -Wreturn-type... " >&6; } - cacheid=xorg_cv_cc_flag__Wreturn_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wreturn-type" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wtrigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wtrigraphs" >&5 -printf %s "checking if $CC supports -Wtrigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Wtrigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wtrigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Warray-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Warray-bounds" >&5 -printf %s "checking if $CC supports -Warray-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Warray_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Warray-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wwrite-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wwrite-strings" >&5 -printf %s "checking if $CC supports -Wwrite-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Wwrite_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wwrite-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Waddress" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Waddress" >&5 -printf %s "checking if $CC supports -Waddress... " >&6; } - cacheid=xorg_cv_cc_flag__Waddress - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Waddress" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wint-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wint-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Wint-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wint_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wint-to-pointer-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Wpointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-to-int-cast" - found="yes" - fi - fi - - -fi - - - - - - - - CWARNFLAGS="$BASE_CFLAGS" - if test "x$GCC" = xyes ; then - CWARNFLAGS="$CWARNFLAGS -fno-strict-aliasing" - fi - - - - - - - - -@%:@ Check whether --enable-strict-compilation was given. -if test ${enable_strict_compilation+y} -then : - enableval=$enable_strict_compilation; STRICT_COMPILE=$enableval -else case e in @%:@( - e) STRICT_COMPILE=no ;; -esac -fi - - - - - - -STRICT_CFLAGS="" - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -pedantic" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -pedantic" >&5 -printf %s "checking if $CC supports -pedantic... " >&6; } - cacheid=xorg_cv_cc_flag__pedantic - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -pedantic" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror" >&5 -printf %s "checking if $CC supports -Werror... " >&6; } - cacheid=xorg_cv_cc_flag__Werror - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn" >&5 -printf %s "checking if $CC supports -errwarn... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -errwarn" - found="yes" - fi - fi - - - -# Earlier versions of gcc (eg: 4.2) support -Werror=attributes, but do not -# activate it with -Werror, so we add it here explicitly. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=attributes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=attributes" >&5 -printf %s "checking if $CC supports -Werror=attributes... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_attributes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror=attributes" - found="yes" - fi - fi - - - -if test "x$STRICT_COMPILE" = "xyes"; then - BASE_CFLAGS="$BASE_CFLAGS $STRICT_CFLAGS" - CWARNFLAGS="$CWARNFLAGS $STRICT_CFLAGS" -fi - - - - - - - - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_VERSION_MAJOR `echo $PACKAGE_VERSION | cut -d . -f 1` -_ACEOF - - PVM=`echo $PACKAGE_VERSION | cut -d . -f 2 | cut -d - -f 1` - if test "x$PVM" = "x"; then - PVM="0" - fi - -printf '%s\n' "@%:@define PACKAGE_VERSION_MINOR $PVM" >>confdefs.h - - PVP=`echo $PACKAGE_VERSION | cut -d . -f 3 | cut -d - -f 1` - if test "x$PVP" = "x"; then - PVP="0" - fi - -printf '%s\n' "@%:@define PACKAGE_VERSION_PATCHLEVEL $PVP" >>confdefs.h - - - -CHANGELOG_CMD="((GIT_DIR=\$(top_srcdir)/.git git log > \$(top_srcdir)/.changelog.tmp) 2>/dev/null && \ -mv \$(top_srcdir)/.changelog.tmp \$(top_srcdir)/ChangeLog) \ -|| (rm -f \$(top_srcdir)/.changelog.tmp; test -e \$(top_srcdir)/ChangeLog || ( \ -touch \$(top_srcdir)/ChangeLog; \ -echo 'git failed to create ChangeLog: installing empty ChangeLog.' >&2))" - - - - -macros_datadir=`$PKG_CONFIG --print-errors --variable=pkgdatadir xorg-macros` -INSTALL_CMD="(cp -f "$macros_datadir/INSTALL" \$(top_srcdir)/.INSTALL.tmp && \ -mv \$(top_srcdir)/.INSTALL.tmp \$(top_srcdir)/INSTALL) \ -|| (rm -f \$(top_srcdir)/.INSTALL.tmp; test -e \$(top_srcdir)/INSTALL || ( \ -touch \$(top_srcdir)/INSTALL; \ -echo 'failed to copy INSTALL from util-macros: installing empty INSTALL.' >&2))" - - - - - - -case $host_os in - solaris*) - # Solaris 2.0 - 11.3 use SysV man page section numbers, so we - # check for a man page file found in later versions that use - # traditional section numbers instead - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for /usr/share/man/man7/attributes.7" >&5 -printf %s "checking for /usr/share/man/man7/attributes.7... " >&6; } -if test ${ac_cv_file__usr_share_man_man7_attributes_7+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) test "$cross_compiling" = yes && - as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 -if test -r "/usr/share/man/man7/attributes.7"; then - ac_cv_file__usr_share_man_man7_attributes_7=yes -else - ac_cv_file__usr_share_man_man7_attributes_7=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__usr_share_man_man7_attributes_7" >&5 -printf '%s\n' "$ac_cv_file__usr_share_man_man7_attributes_7" >&6; } -if test "x$ac_cv_file__usr_share_man_man7_attributes_7" = xyes -then : - SYSV_MAN_SECTIONS=false -else case e in @%:@( - e) SYSV_MAN_SECTIONS=true ;; -esac -fi - - ;; - *) SYSV_MAN_SECTIONS=false ;; -esac - -if test x$APP_MAN_SUFFIX = x ; then - APP_MAN_SUFFIX=1 -fi -if test x$APP_MAN_DIR = x ; then - APP_MAN_DIR='$(mandir)/man$(APP_MAN_SUFFIX)' -fi - -if test x$LIB_MAN_SUFFIX = x ; then - LIB_MAN_SUFFIX=3 -fi -if test x$LIB_MAN_DIR = x ; then - LIB_MAN_DIR='$(mandir)/man$(LIB_MAN_SUFFIX)' -fi - -if test x$FILE_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) FILE_MAN_SUFFIX=4 ;; - *) FILE_MAN_SUFFIX=5 ;; - esac -fi -if test x$FILE_MAN_DIR = x ; then - FILE_MAN_DIR='$(mandir)/man$(FILE_MAN_SUFFIX)' -fi - -if test x$MISC_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) MISC_MAN_SUFFIX=5 ;; - *) MISC_MAN_SUFFIX=7 ;; - esac -fi -if test x$MISC_MAN_DIR = x ; then - MISC_MAN_DIR='$(mandir)/man$(MISC_MAN_SUFFIX)' -fi - -if test x$DRIVER_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) DRIVER_MAN_SUFFIX=7 ;; - *) DRIVER_MAN_SUFFIX=4 ;; - esac -fi -if test x$DRIVER_MAN_DIR = x ; then - DRIVER_MAN_DIR='$(mandir)/man$(DRIVER_MAN_SUFFIX)' -fi - -if test x$ADMIN_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) ADMIN_MAN_SUFFIX=1m ;; - *) ADMIN_MAN_SUFFIX=8 ;; - esac -fi -if test x$ADMIN_MAN_DIR = x ; then - ADMIN_MAN_DIR='$(mandir)/man$(ADMIN_MAN_SUFFIX)' -fi - - - - - - - - - - - - - - - -XORG_MAN_PAGE="X Version 11" - -MAN_SUBSTS="\ - -e 's|__vendorversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xorgversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xservername__|Xorg|g' \ - -e 's|__xconfigfile__|xorg.conf|g' \ - -e 's|__projectroot__|\$(prefix)|g' \ - -e 's|__apploaddir__|\$(appdefaultdir)|g' \ - -e 's|__appmansuffix__|\$(APP_MAN_SUFFIX)|g' \ - -e 's|__drivermansuffix__|\$(DRIVER_MAN_SUFFIX)|g' \ - -e 's|__adminmansuffix__|\$(ADMIN_MAN_SUFFIX)|g' \ - -e 's|__libmansuffix__|\$(LIB_MAN_SUFFIX)|g' \ - -e 's|__miscmansuffix__|\$(MISC_MAN_SUFFIX)|g' \ - -e 's|__filemansuffix__|\$(FILE_MAN_SUFFIX)|g'" - - - - -AM_DEFAULT_VERBOSITY=0 - - - - - - -@%:@ Check whether --enable-specs was given. -if test ${enable_specs+y} -then : - enableval=$enable_specs; build_specs=$enableval -else case e in @%:@( - e) build_specs=yes ;; -esac -fi - - - if test x$build_specs = xyes; then - ENABLE_SPECS_TRUE= - ENABLE_SPECS_FALSE='#' -else - ENABLE_SPECS_TRUE='#' - ENABLE_SPECS_FALSE= -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build functional specifications" >&5 -printf %s "checking whether to build functional specifications... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $build_specs" >&5 -printf '%s\n' "$build_specs" >&6; } - - - - - -@%:@ Check whether --with-xmlto was given. -if test ${with_xmlto+y} -then : - withval=$with_xmlto; use_xmlto=$withval -else case e in @%:@( - e) use_xmlto=auto ;; -esac -fi - - - -if test "x$use_xmlto" = x"auto"; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto not found - documentation targets will be skipped" >&2;} - have_xmlto=no - else - have_xmlto=yes - fi -elif test "x$use_xmlto" = x"yes" ; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - as_fn_error $? "--with-xmlto=yes specified but xmlto not found in PATH" "$LINENO" 5 - fi - have_xmlto=yes -elif test "x$use_xmlto" = x"no" ; then - if test "x$XMLTO" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&2;} - fi - have_xmlto=no -else - as_fn_error $? "--with-xmlto expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of xmlto, if provided. -if test "$have_xmlto" = yes; then - # scrape the xmlto version - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the xmlto version" >&5 -printf %s "checking the xmlto version... " >&6; } - xmlto_version=`$XMLTO --version 2>/dev/null | cut -d' ' -f3` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xmlto_version" >&5 -printf '%s\n' "$xmlto_version" >&6; } - as_arg_v1=$xmlto_version -as_arg_v2=0.0.22 -awk "$as_awk_strverscmp" v1="$as_arg_v1" v2="$as_arg_v2" /dev/null -case $? in @%:@( - 1) : - if test "x$use_xmlto" = xauto; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&5 -printf '%s\n' "$as_me: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&2;} - have_xmlto=no - else - as_fn_error $? "xmlto version $xmlto_version found, but 0.0.22 needed" "$LINENO" 5 - fi ;; @%:@( - 0) : - ;; @%:@( - 2) : - ;; @%:@( - *) : - ;; -esac -fi - -# Test for the ability of xmlto to generate a text target -# -# NOTE: xmlto 0.0.27 or higher return a non-zero return code in the -# following test for empty XML docbook files. -# For compatibility reasons use the following empty XML docbook file and if -# it fails try it again with a non-empty XML file. -have_xmlto_text=no -cat > conftest.xml << "EOF" -EOF -if test "$have_xmlto" = yes -then : - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in @%:@( - e) # Try it again with a non-empty XML file. - cat > conftest.xml << "EOF" - -EOF - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto cannot generate text format, this format skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto cannot generate text format, this format skipped" >&2;} ;; -esac -fi ;; -esac -fi -fi -rm -f conftest.xml - if test $have_xmlto_text = yes; then - HAVE_XMLTO_TEXT_TRUE= - HAVE_XMLTO_TEXT_FALSE='#' -else - HAVE_XMLTO_TEXT_TRUE='#' - HAVE_XMLTO_TEXT_FALSE= -fi - - if test "$have_xmlto" = yes; then - HAVE_XMLTO_TRUE= - HAVE_XMLTO_FALSE='#' -else - HAVE_XMLTO_TRUE='#' - HAVE_XMLTO_FALSE= -fi - - - - - - -@%:@ Check whether --with-fop was given. -if test ${with_fop+y} -then : - withval=$with_fop; use_fop=$withval -else case e in @%:@( - e) use_fop=auto ;; -esac -fi - - - -if test "x$use_fop" = x"auto"; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: fop not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: fop not found - documentation targets will be skipped" >&2;} - have_fop=no - else - have_fop=yes - fi -elif test "x$use_fop" = x"yes" ; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - as_fn_error $? "--with-fop=yes specified but fop not found in PATH" "$LINENO" 5 - fi - have_fop=yes -elif test "x$use_fop" = x"no" ; then - if test "x$FOP" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&2;} - fi - have_fop=no -else - as_fn_error $? "--with-fop expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of fop, if provided. - - if test "$have_fop" = yes; then - HAVE_FOP_TRUE= - HAVE_FOP_FALSE='#' -else - HAVE_FOP_TRUE='#' - HAVE_FOP_FALSE= -fi - - - - -# Preserves the interface, should it be implemented later - - - -@%:@ Check whether --with-xsltproc was given. -if test ${with_xsltproc+y} -then : - withval=$with_xsltproc; use_xsltproc=$withval -else case e in @%:@( - e) use_xsltproc=auto ;; -esac -fi - - - -if test "x$use_xsltproc" = x"auto"; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xsltproc not found - cannot transform XML documents" >&5 -printf '%s\n' "$as_me: WARNING: xsltproc not found - cannot transform XML documents" >&2;} - have_xsltproc=no - else - have_xsltproc=yes - fi -elif test "x$use_xsltproc" = x"yes" ; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - as_fn_error $? "--with-xsltproc=yes specified but xsltproc not found in PATH" "$LINENO" 5 - fi - have_xsltproc=yes -elif test "x$use_xsltproc" = x"no" ; then - if test "x$XSLTPROC" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&2;} - fi - have_xsltproc=no -else - as_fn_error $? "--with-xsltproc expects 'yes' or 'no'" "$LINENO" 5 -fi - - if test "$have_xsltproc" = yes; then - HAVE_XSLTPROC_TRUE= - HAVE_XSLTPROC_FALSE='#' -else - HAVE_XSLTPROC_TRUE='#' - HAVE_XSLTPROC_FALSE= -fi - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for X.Org SGML entities >= 1.8" >&5 -printf %s "checking for X.Org SGML entities >= 1.8... " >&6; } -XORG_SGML_PATH= -if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xorg-sgml-doctools >= 1.8\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xorg-sgml-doctools >= 1.8") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools` -else - : - -fi - -# Define variables STYLESHEET_SRCDIR and XSL_STYLESHEET containing -# the path and the name of the doc stylesheet -if test "x$XORG_SGML_PATH" != "x" ; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XORG_SGML_PATH" >&5 -printf '%s\n' "$XORG_SGML_PATH" >&6; } - STYLESHEET_SRCDIR=$XORG_SGML_PATH/X11 - XSL_STYLESHEET=$STYLESHEET_SRCDIR/xorg.xsl -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - if test "x$XSL_STYLESHEET" != "x"; then - HAVE_STYLESHEETS_TRUE= - HAVE_STYLESHEETS_FALSE='#' -else - HAVE_STYLESHEETS_TRUE='#' - HAVE_STYLESHEETS_FALSE= -fi - - - -@%:@ Check whether --enable-malloc0returnsnull was given. -if test ${enable_malloc0returnsnull+y} -then : - enableval=$enable_malloc0returnsnull; MALLOC_ZERO_RETURNS_NULL=$enableval -else case e in @%:@( - e) MALLOC_ZERO_RETURNS_NULL=yes ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to act as if malloc(0) can return NULL" >&5 -printf %s "checking whether to act as if malloc(0) can return NULL... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MALLOC_ZERO_RETURNS_NULL" >&5 -printf '%s\n' "$MALLOC_ZERO_RETURNS_NULL" >&6; } - -if test "x$MALLOC_ZERO_RETURNS_NULL" = xyes; then - MALLOC_ZERO_CFLAGS="-DMALLOC_0_RETURNS_NULL" - XMALLOC_ZERO_CFLAGS=$MALLOC_ZERO_CFLAGS - XTMALLOC_ZERO_CFLAGS="$MALLOC_ZERO_CFLAGS -DXTMALLOC_BC" -else - MALLOC_ZERO_CFLAGS="" - XMALLOC_ZERO_CFLAGS="" - XTMALLOC_ZERO_CFLAGS="" -fi - - - - - - -# Determine .so library version per platform -# based on SharedXextRev in monolith xc/config/cf/*Lib.tmpl -if test "x$XEXT_SOREV" = "x" ; then - case $host_os in - openbsd*) XEXT_SOREV=8:0 ;; - solaris*) XEXT_SOREV=0 ;; - *) XEXT_SOREV=6:4:0 ;; - esac -fi - - -# Obtain compiler/linker options for dependencies - -pkg_failed=no -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" >&5 -printf %s "checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99... " >&6; } - -if test -n "$XEXT_CFLAGS"; then - pkg_cv_XEXT_CFLAGS="$XEXT_CFLAGS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_CFLAGS=`$PKG_CONFIG --cflags "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi -if test -n "$XEXT_LIBS"; then - pkg_cv_XEXT_LIBS="$XEXT_LIBS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_LIBS=`$PKG_CONFIG --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi - - - -if test $pkg_failed = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi - if test $_pkg_short_errors_supported = yes; then - XEXT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - else - XEXT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$XEXT_PKG_ERRORS" >&5 - - as_fn_error $? "Package requirements (xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99) were not met: - -$XEXT_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details." "$LINENO" 5 -elif test $pkg_failed = untried; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details. - -To get pkg-config, see . -See 'config.log' for more details" "$LINENO" 5; } -else - XEXT_CFLAGS=$pkg_cv_XEXT_CFLAGS - XEXT_LIBS=$pkg_cv_XEXT_LIBS - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - -fi - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for __builtin_popcountl" >&5 -printf %s "checking for __builtin_popcountl... " >&6; } -if test ${ax_cv_have___builtin_popcountl+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - __builtin_popcountl(0) - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ax_cv_have___builtin_popcountl=yes -else case e in @%:@( - e) ax_cv_have___builtin_popcountl=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have___builtin_popcountl" >&5 -printf '%s\n' "$ax_cv_have___builtin_popcountl" >&6; } - - if test yes = $ax_cv_have___builtin_popcountl -then : - -printf '%s\n' "@%:@define HAVE___BUILTIN_POPCOUNTL 1" >>confdefs.h - -fi - - - -ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" -if test "x$ac_cv_func_reallocarray" = xyes -then : - printf '%s\n' "@%:@define HAVE_REALLOCARRAY 1" >>confdefs.h - -else case e in @%:@( - e) case " $LIB@&t@OBJS " in - *" reallocarray.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS reallocarray.$ac_objext" - ;; -esac - ;; -esac -fi - - -# Allow checking code with lint, sparse, etc. - - - - - -@%:@ Check whether --with-lint was given. -if test ${with_lint+y} -then : - withval=$with_lint; use_lint=$withval -else case e in @%:@( - e) use_lint=no ;; -esac -fi - - -# Obtain platform specific info like program name and options -# The lint program on FreeBSD and NetBSD is different from the one on Solaris -case $host_os in - *linux* | *openbsd* | kfreebsd*-gnu | darwin* | cygwin*) - lint_name=splint - lint_options="-badflag" - ;; - *freebsd* | *netbsd*) - lint_name=lint - lint_options="-u -b" - ;; - *solaris*) - lint_name=lint - lint_options="-u -b -h -erroff=E_INDISTING_FROM_TRUNC2" - ;; -esac - -# Test for the presence of the program (either guessed by the code or spelled out by the user) -if test "x$use_lint" = x"yes" ; then - # Extract the first word of "$lint_name", so it can be a program name with args. -set dummy $lint_name; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_LINT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $LINT in - [\\/]* | ?:[\\/]*) - ac_cv_path_LINT="$LINT" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_LINT="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -LINT=$ac_cv_path_LINT -if test -n "$LINT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LINT" >&5 -printf '%s\n' "$LINT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$LINT" = "x"; then - as_fn_error $? "--with-lint=yes specified but lint-style tool not found in PATH" "$LINENO" 5 - fi -elif test "x$use_lint" = x"no" ; then - if test "x$LINT" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&2;} - fi -else - as_fn_error $? "--with-lint expects 'yes' or 'no'. Use LINT variable to specify path." "$LINENO" 5 -fi - -# User supplied flags override default flags -if test "x$LINT_FLAGS" != "x"; then - lint_options=$LINT_FLAGS -fi - -LINT_FLAGS=$lint_options - - if test "x$LINT" != x; then - LINT_TRUE= - LINT_FALSE='#' -else - LINT_TRUE='#' - LINT_FALSE= -fi - - - - - -@%:@ Check whether --enable-lint-library was given. -if test ${enable_lint_library+y} -then : - enableval=$enable_lint_library; make_lint_lib=$enableval -else case e in @%:@( - e) make_lint_lib=no ;; -esac -fi - - -if test "x$make_lint_lib" = x"yes" ; then - LINTLIB=llib-lXext.ln - if test "x$LINT" = "x"; then - as_fn_error $? "Cannot make lint library without --with-lint" "$LINENO" 5 - fi -elif test "x$make_lint_lib" != x"no" ; then - as_fn_error $? "--enable-lint-library expects 'yes' or 'no'." "$LINENO" 5 -fi - - - if test x$make_lint_lib != xno; then - MAKE_LINT_LIB_TRUE= - MAKE_LINT_LIB_FALSE='#' -else - MAKE_LINT_LIB_TRUE='#' - MAKE_LINT_LIB_FALSE= -fi - - - - -ac_config_files="$ac_config_files Makefile man/Makefile src/Makefile specs/Makefile xext.pc" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# 'ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* 'ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -ac_cache_dump | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -printf '%s\n' "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -printf '%s\n' "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIB@&t@OBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`printf '%s\n' "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIB@&t@OBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -printf %s "checking that generated files are newer than configure... " >&6; } - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: done" >&5 -printf '%s\n' "done" >&6; } -if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then - as_fn_error $? "conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; -esac -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi - - if test -n "$EXEEXT"; then - am__EXEEXT_TRUE= - am__EXEEXT_FALSE='#' -else - am__EXEEXT_TRUE='#' - am__EXEEXT_FALSE= -fi - -if test -z "${ENABLE_SPECS_TRUE}" && test -z "${ENABLE_SPECS_FALSE}"; then - as_fn_error $? "conditional \"ENABLE_SPECS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TEXT_TRUE}" && test -z "${HAVE_XMLTO_TEXT_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO_TEXT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TRUE}" && test -z "${HAVE_XMLTO_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_FOP_TRUE}" && test -z "${HAVE_FOP_FALSE}"; then - as_fn_error $? "conditional \"HAVE_FOP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XSLTPROC_TRUE}" && test -z "${HAVE_XSLTPROC_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XSLTPROC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_STYLESHEETS_TRUE}" && test -z "${HAVE_STYLESHEETS_FALSE}"; then - as_fn_error $? "conditional \"HAVE_STYLESHEETS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${LINT_TRUE}" && test -z "${LINT_FALSE}"; then - as_fn_error $? "conditional \"LINT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${MAKE_LINT_LIB_TRUE}" && test -z "${MAKE_LINT_LIB_FALSE}"; then - as_fn_error $? "conditional \"MAKE_LINT_LIB\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: "${CONFIG_STATUS=./config.status}" -case $CONFIG_STATUS in @%:@( - -*) : - CONFIG_STATUS=./$CONFIG_STATUS ;; @%:@( - */*) : - ;; @%:@( - *) : - CONFIG_STATUS=./$CONFIG_STATUS ;; -esac - -ac_write_fail=0 -ac_clean_CONFIG_STATUS='"$CONFIG_STATUS"' -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -printf '%s\n' "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >"$CONFIG_STATUS" <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>"$CONFIG_STATUS" <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in @%:@( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in @%:@( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - -exec 6>&1 -## ------------------------------------- ## -## Main body of "$CONFIG_STATUS" script. ## -## ------------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -'$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` -ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_cs_config='$ac_cs_config_escaped' -ac_cs_version="\\ -libXext config.status 1.3.7 -configured by $0, generated by GNU Autoconf 2.73, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2026 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -AWK='$AWK' -test -n "\$AWK" || { - awk '' >"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - printf '%s\n' "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - printf '%s\n' "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: '$1' -Try '$0 --help' for more information.";; - --help | --hel | -h ) - printf '%s\n' "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: '$1' -Try '$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \printf '%s\n' "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../@%:@@%:@ /;s/...$/ @%:@@%:@/;p;x;p;x' <<_ASBOX -@%:@@%:@ Running $as_me. @%:@@%:@ -_ASBOX - printf '%s\n' "$ac_log" -} >&5 - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" - - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='$sed_quote_subst' -double_quote_subst='$double_quote_subst' -delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' -macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' -enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' -enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' -pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' -shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' -SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' -ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' -PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' -host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' -host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' -host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' -build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' -build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' -build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' -SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' -Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' -GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' -EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' -FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' -LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' -NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' -LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' -ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' -exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' -lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' -lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' -lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' -reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' -FILECMD='`$ECHO "$FILECMD" | $SED "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' -file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' -want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' -DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' -sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' -AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' -lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' -archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' -STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' -RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' -lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' -CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' -compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' -GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' -lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' -nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' -lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' -lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' -objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' -need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' -MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' -LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' -OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' -libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' -module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' -postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' -need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' -version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' -runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' -libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' -soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' -install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' -finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' -configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' -old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' -striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' - -LTCC='$LTCC' -LTCFLAGS='$LTCFLAGS' -compiler='$compiler_DEFAULT' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in SHELL \ -ECHO \ -PATH_SEPARATOR \ -SED \ -GREP \ -EGREP \ -FGREP \ -LD \ -NM \ -LN_S \ -lt_SP2NL \ -lt_NL2SP \ -reload_flag \ -FILECMD \ -OBJDUMP \ -deplibs_check_method \ -file_magic_cmd \ -file_magic_glob \ -want_nocaseglob \ -DLLTOOL \ -sharedlib_from_linklib_cmd \ -AR \ -archiver_list_spec \ -STRIP \ -RANLIB \ -CC \ -CFLAGS \ -compiler \ -lt_cv_sys_global_symbol_pipe \ -lt_cv_sys_global_symbol_to_cdecl \ -lt_cv_sys_global_symbol_to_import \ -lt_cv_sys_global_symbol_to_c_name_address \ -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -lt_cv_nm_interface \ -nm_file_list_spec \ -lt_cv_truncate_bin \ -lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_pic \ -lt_prog_compiler_wl \ -lt_prog_compiler_static \ -lt_cv_prog_compiler_c_o \ -need_locks \ -MANIFEST_TOOL \ -DSYMUTIL \ -NMEDIT \ -LIPO \ -OTOOL \ -OTOOL64 \ -shrext_cmds \ -export_dynamic_flag_spec \ -whole_archive_flag_spec \ -compiler_needs_object \ -with_gnu_ld \ -allow_undefined_flag \ -no_undefined_flag \ -hardcode_libdir_flag_spec \ -hardcode_libdir_separator \ -exclude_expsyms \ -include_expsyms \ -file_list_spec \ -variables_saved_for_relink \ -libname_spec \ -library_names_spec \ -soname_spec \ -install_override_mode \ -finish_eval \ -old_striplib \ -striplib; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in reload_cmds \ -old_postinstall_cmds \ -old_postuninstall_cmds \ -old_archive_cmds \ -extract_expsyms_cmds \ -old_archive_from_new_cmds \ -old_archive_from_expsyms_cmds \ -archive_cmds \ -archive_expsym_cmds \ -module_cmds \ -module_expsym_cmds \ -export_symbols_cmds \ -prelink_cmds \ -postlink_cmds \ -postinstall_cmds \ -postuninstall_cmds \ -finish_cmds \ -sys_lib_search_path_spec \ -configure_time_dlsearch_path \ -configure_time_lt_sys_library_path; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -ac_aux_dir='$ac_aux_dir' - -# See if we are running on zsh, and set the options that allow our -# commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - - - PACKAGE='$PACKAGE' - VERSION='$VERSION' - RM='$RM' - ofile='$ofile' - - - - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; - "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; - "specs/Makefile") CONFIG_FILES="$CONFIG_FILES specs/Makefile" ;; - "xext.pc") CONFIG_FILES="$CONFIG_FILES xext.pc" ;; - - *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files - test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers - test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to '$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with './config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | sed -n '$='` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | sed -n '$='` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >"$CONFIG_STATUS" || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with './config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script 'defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >"$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - suffix = P[macro] D[macro] - while (suffix ~ /[\t ]$/) { - suffix = substr(suffix, 1, length(suffix) - 1) - } - # Preserve the white space surrounding the "#". - print prefix "define", macro suffix - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain ':'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf '%s\n' "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is 'configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - printf '%s\n' "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf '%s\n' "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf '%s\n' "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when '$srcdir' = '.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf '%s\n' "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf '%s\n' "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || { - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - case $CONFIG_FILES in @%:@( - *\'*) : - eval set x "$CONFIG_FILES" ;; @%:@( - *) : - set x $CONFIG_FILES ;; @%:@( - *) : - ;; -esac - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`printf '%s\n' "$am_mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`$as_dirname -- "$am_mf" || -$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$am_mf" : 'X\(//\)[^/]' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$am_mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - am_filepart=`$as_basename -- "$am_mf" || -$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$am_mf" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - { echo "$as_me:$LINENO: cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles" >&5 - (cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } || am_rc=$? - done - if test $am_rc -ne 0; then - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE=\"gmake\" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking). -See 'config.log' for more details" "$LINENO" 5; } - fi - { am_dirpart=; unset am_dirpart;} - { am_filepart=; unset am_filepart;} - { am_mf=; unset am_mf;} - { am_rc=; unset am_rc;} - rm -f conftest-deps.mk -} - ;; - "libtool":C) - - # See if we are running on zsh, and set the options that allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST - fi - - cfgfile=${ofile}T - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL -# Generated automatically by $as_me ($PACKAGE) $VERSION -# NOTE: Changes made to this file will be lost: look at ltmain.sh. - -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit, 1996 - -# Copyright (C) 2024 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program or library that is built -# using GNU Libtool, you may include this file under the same -# distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -# The names of the tagged configurations supported by this script. -available_tags='' - -# Configured defaults for sys_lib_dlsearch_path munging. -: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=$macro_version -macro_revision=$macro_revision - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# What type of objects to build. -pic_mode=$pic_mode - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# Shared archive member basename,for filename based shared library versioning on AIX. -shared_archive_member_spec=$shared_archive_member_spec - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The PATH separator for the build system. -PATH_SEPARATOR=$lt_PATH_SEPARATOR - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="\$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP=$lt_GREP - -# An ERE matcher. -EGREP=$lt_EGREP - -# A literal string matcher. -FGREP=$lt_FGREP - -# A BSD- or MS-compatible name lister. -NM=$lt_NM - -# Whether we need soft or hard links. -LN_S=$lt_LN_S - -# What is the maximum length of a command? -max_cmd_len=$max_cmd_len - -# Object file suffix (normally "o"). -objext=$ac_objext - -# Executable file suffix (normally ""). -exeext=$exeext - -# whether the shell understands "unset". -lt_unset=$lt_unset - -# turn spaces into newlines. -SP2NL=$lt_lt_SP2NL - -# turn newlines into spaces. -NL2SP=$lt_lt_NL2SP - -# convert \$build file names to \$host format. -to_host_file_cmd=$lt_cv_to_host_file_cmd - -# convert \$build files to toolchain format. -to_tool_file_cmd=$lt_cv_to_tool_file_cmd - -# A file(cmd) program that detects file types. -FILECMD=$lt_FILECMD - -# An object symbol dumper. -OBJDUMP=$lt_OBJDUMP - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method = "file_magic". -file_magic_cmd=$lt_file_magic_cmd - -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob=$lt_file_magic_glob - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob=$lt_want_nocaseglob - -# DLL creation program. -DLLTOOL=$lt_DLLTOOL - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd - -# The archiver. -AR=$lt_AR - -# Flags to create an archive (by configure). -lt_ar_flags=$lt_ar_flags - -# Flags to create an archive. -AR_FLAGS=\@S|@{ARFLAGS-"\@S|@lt_ar_flags"} - -# How to feed a file listing to the archiver. -archiver_list_spec=$lt_archiver_list_spec - -# A symbol stripping program. -STRIP=$lt_STRIP - -# Commands used to install an old-style archive. -RANLIB=$lt_RANLIB -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - -# A C compiler. -LTCC=$lt_CC - -# LTCC compiler flags. -LTCFLAGS=$lt_CFLAGS - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm into a list of symbols to manually relocate. -global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix - -# The name lister interface. -nm_interface=$lt_lt_cv_nm_interface - -# Specify filename containing input files for \$NM. -nm_file_list_spec=$lt_nm_file_list_spec - -# The root where to search for dependent libraries,and where our libraries should be installed. -lt_sysroot=$lt_sysroot - -# Command to truncate a binary pipe. -lt_truncate_bin=$lt_lt_cv_truncate_bin - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=$MAGIC_CMD - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Manifest tool. -MANIFEST_TOOL=$lt_MANIFEST_TOOL - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL=$lt_DSYMUTIL - -# Tool to change global to local symbols on Mac OS X. -NMEDIT=$lt_NMEDIT - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO=$lt_LIPO - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL=$lt_OTOOL - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64=$lt_OTOOL64 - -# Old archive suffix (normally "a"). -libext=$libext - -# Shared library suffix (normally ".so"). -shrext_cmds=$lt_shrext_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink=$lt_variables_saved_for_relink - -# Do we need the "lib" prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Library versioning type. -version_type=$version_type - -# Shared library runtime path variable. -runpath_var=$runpath_var - -# Shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - -# Command to use after installation of a shared archive. -postinstall_cmds=$lt_postinstall_cmds - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval=$lt_finish_eval - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Compile-time system search path for libraries. -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Detected run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path - -# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. -configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - - -# The linker used to build libraries. -LD=$lt_LD - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds - -# A language specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU compiler? -with_gcc=$GCC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e. impossible to change by setting \$shlibpath_var if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# ### END LIBTOOL CONFIG - -_LT_EOF - - cat <<'_LT_EOF' >> "$cfgfile" - -# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x@S|@2 in - x) - ;; - *:) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" - ;; - x:*) - eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" - ;; - *) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - esac -} - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in @S|@*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - - -# ### END FUNCTIONS SHARED WITH CONFIGURE - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - - -ltmain=$ac_aux_dir/ltmain.sh - - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - $SED '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - - ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_CONFIG_STATUS= - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - case $CONFIG_STATUS in @%:@( - -*) : - ac_no_opts=-- ;; @%:@( - *) : - ac_no_opts= ;; -esac - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $ac_no_opts "$CONFIG_STATUS" $ac_config_status_args || - ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - diff --git a/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.2 b/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.2 deleted file mode 100644 index c0c8c80c2..000000000 --- a/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.2 +++ /dev/null @@ -1,24109 +0,0 @@ -@%:@! /bin/sh -@%:@ Guess values for system-dependent variables and create Makefiles. -@%:@ Generated by GNU Autoconf 2.73 for libXext 1.3.7. -@%:@ -@%:@ Report bugs to . -@%:@ -@%:@ -@%:@ Copyright (C) 1992-1996, 1998-2017, 2020-2026 Free Software Foundation, -@%:@ Inc. -@%:@ -@%:@ -@%:@ This configure script is free software; the Free Software Foundation -@%:@ gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $@%:@ in @%:@ (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case \`(set -o) 2>/dev/null\` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ) -then : - -else case e in @%:@( - e) exitcode=1; echo positional parameters were not saved. ;; -esac -fi -test x\$exitcode = x0 || exit 1 -blah=\$(echo \$(echo blah)) -test x\"\$blah\" = xblah || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 - - test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ - || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null -then : - as_have_required=yes -else case e in @%:@( - e) as_have_required=no ;; -esac -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null -then : - -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - case $as_dir in @%:@( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$as_shell as_have_required=yes - if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null -then : - break 2 -fi -fi - done;; - esac - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in @%:@( - e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi ;; -esac -fi - - - if test "x$CONFIG_SHELL" != x -then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $@%:@ in @%:@ (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno -then : - printf '%s\n' "$0: This script requires a shell more modern than all" - printf '%s\n' "$0: the shells that I found on your system." - if test ${ZSH_VERSION+y} ; then - printf '%s\n' "$0: In particular, zsh $ZSH_VERSION has bugs and should" - printf '%s\n' "$0: be upgraded to zsh 4.3.4 or later." - else - printf '%s\n' "$0: Please tell bug-autoconf@gnu.org and -$0: https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi ;; -esac -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in @%:@( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in @%:@( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - t clear - :clear - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { printf '%s\n' "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - -SHELL=${CONFIG_SHELL-/bin/sh} - -as_awk_strverscmp=' - # Use only awk features that work with 7th edition Unix awk (1978). - # My, what an old awk you have, Mr. Solaris! - END { - while (length(v1) && length(v2)) { - # Set d1 to be the next thing to compare from v1, and likewise for d2. - # Normally this is a single character, but if v1 and v2 contain digits, - # compare them as integers and fractions as strverscmp does. - if (v1 ~ /^[0-9]/ && v2 ~ /^[0-9]/) { - # Split v1 and v2 into their leading digit string components d1 and d2, - # and advance v1 and v2 past the leading digit strings. - for (len1 = 1; substr(v1, len1 + 1) ~ /^[0-9]/; len1++) continue - for (len2 = 1; substr(v2, len2 + 1) ~ /^[0-9]/; len2++) continue - d1 = substr(v1, 1, len1); v1 = substr(v1, len1 + 1) - d2 = substr(v2, 1, len2); v2 = substr(v2, len2 + 1) - if (d1 ~ /^0/) { - if (d2 ~ /^0/) { - # Compare two fractions. - while (d1 ~ /^0/ && d2 ~ /^0/) { - d1 = substr(d1, 2); len1-- - d2 = substr(d2, 2); len2-- - } - if (len1 != len2 && ! (len1 && len2 && substr(d1, 1, 1) == substr(d2, 1, 1))) { - # The two components differ in length, and the common prefix - # contains only leading zeros. Consider the longer to be less. - d1 = -len1 - d2 = -len2 - } else { - # Otherwise, compare as strings. - d1 = "x" d1 - d2 = "x" d2 - } - } else { - # A fraction is less than an integer. - exit 1 - } - } else { - if (d2 ~ /^0/) { - # An integer is greater than a fraction. - exit 2 - } else { - # Compare two integers. - d1 += 0 - d2 += 0 - } - } - } else { - # The normal case, without worrying about digits. - d1 = substr(v1, 1, 1); v1 = substr(v1, 2) - d2 = substr(v2, 1, 1); v2 = substr(v2, 2) - } - if (d1 < d2) exit 1 - if (d1 > d2) exit 2 - } - # Beware Solaris 11 /usr/xgp4/bin/awk, which mishandles some - # comparisons of empty strings to integers. For example, - # LC_ALL=C /usr/xpg4/bin/awk "BEGIN {if (-1 < \"\") print \"a\"}" - # prints "a". - if (length(v2)) exit 1 - if (length(v1)) exit 2 - } -' - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_CONFIG_STATUS= -ac_clean_files= -ac_config_libobj_dir=. -LIB@&t@OBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='libXext' -PACKAGE_TARNAME='libXext' -PACKAGE_VERSION='1.3.7' -PACKAGE_STRING='libXext 1.3.7' -PACKAGE_BUGREPORT='https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues' -PACKAGE_URL='' - -ac_unique_file="Makefile.am" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_STDIO_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_header_c_list= -ac_subst_vars='am__EXEEXT_FALSE -am__EXEEXT_TRUE -LTLIBOBJS -MAKE_LINT_LIB_FALSE -MAKE_LINT_LIB_TRUE -LINTLIB -LINT_FALSE -LINT_TRUE -LINT_FLAGS -LINT -LIB@&t@OBJS -XEXT_LIBS -XEXT_CFLAGS -XEXT_SOREV -XTMALLOC_ZERO_CFLAGS -XMALLOC_ZERO_CFLAGS -MALLOC_ZERO_CFLAGS -HAVE_STYLESHEETS_FALSE -HAVE_STYLESHEETS_TRUE -XSL_STYLESHEET -STYLESHEET_SRCDIR -XORG_SGML_PATH -HAVE_XSLTPROC_FALSE -HAVE_XSLTPROC_TRUE -XSLTPROC -HAVE_FOP_FALSE -HAVE_FOP_TRUE -FOP -HAVE_XMLTO_FALSE -HAVE_XMLTO_TRUE -HAVE_XMLTO_TEXT_FALSE -HAVE_XMLTO_TEXT_TRUE -XMLTO -ENABLE_SPECS_FALSE -ENABLE_SPECS_TRUE -MAN_SUBSTS -XORG_MAN_PAGE -ADMIN_MAN_DIR -DRIVER_MAN_DIR -MISC_MAN_DIR -FILE_MAN_DIR -LIB_MAN_DIR -APP_MAN_DIR -ADMIN_MAN_SUFFIX -DRIVER_MAN_SUFFIX -MISC_MAN_SUFFIX -FILE_MAN_SUFFIX -LIB_MAN_SUFFIX -APP_MAN_SUFFIX -INSTALL_CMD -PKG_CONFIG_LIBDIR -PKG_CONFIG_PATH -PKG_CONFIG -CHANGELOG_CMD -STRICT_CFLAGS -CWARNFLAGS -BASE_CFLAGS -LT_SYS_LIBRARY_PATH -OTOOL64 -OTOOL -LIPO -NMEDIT -DSYMUTIL -MANIFEST_TOOL -RANLIB -ac_ct_AR -AR -DLLTOOL -OBJDUMP -FILECMD -LN_S -NM -ac_ct_DUMPBIN -DUMPBIN -LD -FGREP -EGREP -GREP -SED -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -LIBTOOL -am__xargs_n -am__rm_f_notfound -AM_BACKSLASH -AM_DEFAULT_VERBOSITY -AM_DEFAULT_V -AM_V -CSCOPE -ETAGS -CTAGS -am__fastdepCC_FALSE -am__fastdepCC_TRUE -CCDEPMODE -am__nodep -AMDEPBACKSLASH -AMDEP_FALSE -AMDEP_TRUE -am__include -DEPDIR -am__untar -am__tar -AMTAR -am__leading_dot -SET_MAKE -AWK -mkdir_p -MKDIR_P -INSTALL_STRIP_PROGRAM -STRIP -install_sh -MAKEINFO -AUTOHEADER -AUTOMAKE -AUTOCONF -ACLOCAL -VERSION -PACKAGE -CYGPATH_W -am__isrc -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -ECHO_T -ECHO_N -ECHO_C -target_alias -host_alias -build_alias -LIBS -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -runstatedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL -am__quote' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_dependency_tracking -enable_silent_rules -enable_shared -enable_static -enable_pic -with_pic -enable_fast_install -enable_aix_soname -with_aix_soname -with_gnu_ld -with_sysroot -enable_libtool_lock -enable_selective_werror -enable_strict_compilation -enable_specs -with_xmlto -with_fop -with_xsltproc -enable_malloc0returnsnull -with_lint -enable_lint_library -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -LT_SYS_LIBRARY_PATH -PKG_CONFIG -PKG_CONFIG_PATH -PKG_CONFIG_LIBDIR -XMLTO -FOP -XSLTPROC -XEXT_CFLAGS -XEXT_LIBS -LINT -LINT_FLAGS' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: '$ac_option' -Try '$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: '$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - printf '%s\n' "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - printf '%s\n' "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`printf '%s\n' $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: '$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -'configure' configures libXext 1.3.7 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print 'checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for '--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or '..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - @<:@@S|@ac_default_prefix@:>@ - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - @<:@PREFIX@:>@ - -By default, 'make install' will install all the files in -'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify -an installation prefix other than '$ac_default_prefix' using '--prefix', -for instance '--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root @<:@DATAROOTDIR/doc/libXext@:>@ - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of libXext 1.3.7:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-dependency-tracking - do not reject slow dependency extractors - --disable-dependency-tracking - speeds up one-time build - --enable-silent-rules less verbose build output (undo: "make V=1") - --disable-silent-rules verbose build output (undo: "make V=0") - --enable-shared@<:@=PKGS@:>@ build shared libraries @<:@default=yes@:>@ - --enable-static@<:@=PKGS@:>@ build static libraries @<:@default=yes@:>@ - --enable-pic@<:@=PKGS@:>@ try to use only PIC/non-PIC objects @<:@default=use - both@:>@ - --enable-fast-install@<:@=PKGS@:>@ - optimize for fast installation @<:@default=yes@:>@ - --enable-aix-soname=aix|svr4|both - shared library versioning (aka "SONAME") variant to - provide on AIX, @<:@default=aix@:>@. - --disable-libtool-lock avoid locking (might break parallel builds) - --disable-selective-werror - Turn off selective compiler errors. (default: - enabled) - --enable-strict-compilation - Enable all warnings from compiler and make them - errors (default: disabled) - --enable-specs Enable building the specs (default: yes) - --enable-malloc0returnsnull - assume malloc(0) can return NULL (default: yes) - --enable-lint-library Create lint library (default: disabled) - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-gnu-ld assume the C compiler uses GNU ld @<:@default=no@:>@ - --with-sysroot@<:@=DIR@:>@ Search for dependent libraries within DIR (or the - compiler's sysroot if not specified). - --with-xmlto Use xmlto to regenerate documentation (default: - auto) - --with-fop Use fop to regenerate documentation (default: auto) - --with-xsltproc Use xsltproc for the transformation of XML documents - (default: auto) - --with-lint Use a lint-style source code checker (default: - disabled) - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - LT_SYS_LIBRARY_PATH - User-defined run-time library search path. - PKG_CONFIG path to pkg-config utility - PKG_CONFIG_PATH - directories to add to pkg-config's search path - PKG_CONFIG_LIBDIR - path overriding pkg-config's built-in search path - XMLTO Path to xmlto command - FOP Path to fop command - XSLTPROC Path to xsltproc command - XEXT_CFLAGS C compiler flags for XEXT, overriding pkg-config - XEXT_LIBS linker flags for XEXT, overriding pkg-config - LINT Path to a lint-style command - LINT_FLAGS Flags for the lint-style command - -Use these variables to override the choices made by 'configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for configure.gnu first; this name is used for a wrapper for - # Metaconfig's "Configure" on case-insensitive file systems. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - printf '%s\n' "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -libXext configure 1.3.7 -generated by GNU Autoconf 2.73 - -Copyright (C) 2026 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -@%:@ ac_fn_c_try_compile LINENO -@%:@ -------------------------- -@%:@ Try to compile conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_compile - -@%:@ ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -@%:@ ------------------------------------------------------- -@%:@ Tests whether HEADER exists and can be compiled using the include files in -@%:@ INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -@%:@include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_header_compile - -@%:@ ac_fn_c_try_link LINENO -@%:@ ----------------------- -@%:@ Try to link conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - } -then : - ac_retval=0 -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_link - -@%:@ ac_fn_c_check_func LINENO FUNC VAR -@%:@ ---------------------------------- -@%:@ Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (void); below. */ - -#include -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (void); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main (void) -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_func - -@%:@ ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR -@%:@ ------------------------------------------------------------------ -@%:@ Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -@%:@ accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. -ac_fn_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -printf %s "checking whether $as_decl_name is declared... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - eval ac_save_FLAGS=\$$6 - as_fn_append $6 " $5" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main (void) -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - eval $6=\$ac_save_FLAGS - ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_check_decl -ac_configure_args_raw= -for ac_arg -do - case $ac_arg in - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_configure_args_raw " '$ac_arg'" -done - -case $ac_configure_args_raw in - *$as_nl*) - ac_safe_unquote= ;; - *) - ac_unsafe_z='|&;<>()$`\\"*?@<:@ '' ' # This string ends in space, tab. - ac_unsafe_a="$ac_unsafe_z#~" - ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" - ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; -esac - -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - $ $0$ac_configure_args_raw - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - printf '%s\n' "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# Dump the cache to stdout. It can be in a pipe (this is a requirement). -ac_cache_dump () -{ - # The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf '%s\n' "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # 'set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # 'set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) -} - -# Print debugging info to stdout. -ac_dump_debugging_info () -{ - echo - - printf '%s\n' "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - ac_cache_dump - echo - - printf '%s\n' "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - - if test -n "$ac_subst_files"; then - printf '%s\n' "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - fi - - if test -s confdefs.h; then - printf '%s\n' "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - printf '%s\n' "$as_me: caught signal $ac_signal" - printf '%s\n' "$as_me: exit $exit_status" -} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. -ac_exit_trap () -{ - exit_status= - # Sanitize IFS. - IFS=" "" $as_nl" - # Save into config.log some information that might help in debugging. - ac_dump_debugging_info >&5 - eval "rm -f $ac_clean_CONFIG_STATUS core *.core core.conftest.*" && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -} - -trap 'ac_exit_trap $?' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -printf '%s\n' "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -printf '%s\n' "@%:@define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -if test -n "$CONFIG_SITE"; then - ac_site_files="$CONFIG_SITE" -elif test "x$prefix" != xNONE; then - ac_site_files="$prefix/share/config.site $prefix/etc/config.site" -else - ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" -fi - -for ac_site_file in $ac_site_files -do - case $ac_site_file in @%:@( - */*) : - ;; @%:@( - *) : - ac_site_file=./$ac_site_file ;; -esac - if test -f "$ac_site_file" && test -r "$ac_site_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -printf '%s\n' "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See 'config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -printf '%s\n' "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -printf '%s\n' "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" -# Test code for whether the C compiler supports C23 (global declarations) -ac_c_conftest_c23_globals=' -/* Does the compiler advertise conformance to C17 or earlier? - Although GCC 14 does not do that, even with -std=gnu23, - it is close enough, and defines __STDC_VERSION == 202000L. */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ <= 201710L -# error "Compiler advertises conformance to C17 or earlier" -#endif - -// Check alignas. -char alignas (double) c23_aligned_as_double; -char alignas (0) c23_no_special_alignment; -extern char c23_aligned_as_int; -char alignas (0) alignas (int) c23_aligned_as_int; - -// Check alignof. -enum -{ - c23_int_alignment = alignof (int), - c23_int_array_alignment = alignof (int[100]), - c23_char_alignment = alignof (char) -}; -static_assert (0 < -alignof (int), "alignof is signed"); - -int function_with_unnamed_parameter (int) { return 0; } - -void c23_noreturn (); - -/* Test parsing of string and char UTF-8 literals (including hex escapes). - The parens pacify GCC 15. */ -bool use_u8 = (!sizeof u8"\xFF") == (!u8'\''x'\''); - -bool check_that_bool_works = true | false | !nullptr; -#if !true -# error "true does not work in #if" -#endif -#if false -#elifdef __STDC_VERSION__ -#else -# error "#elifdef does not work" -#endif - -#ifndef __has_c_attribute -# error "__has_c_attribute not defined" -#endif - -#ifndef __has_include -# error "__has_include not defined" -#endif - -#define LPAREN() ( -#define FORTY_TWO(x) 42 -#define VA_OPT_TEST(r, x, ...) __VA_OPT__ (FORTY_TWO r x)) -static_assert (VA_OPT_TEST (LPAREN (), 0, <:-) == 42); - -static_assert (0b101010 == 42); -static_assert (0B101010 == 42); -static_assert (0xDEAD'\''BEEF == 3'\''735'\''928'\''559); -static_assert (0.500'\''000'\''000 == 0.5); - -enum unsignedish : unsigned int { uione = 1 }; -static_assert (0 < -uione); - -#include -constexpr nullptr_t null_pointer = nullptr; - -static typeof (1 + 1L) two () { return 2; } -static long int three () { return 3; } -' - -# Test code for whether the C compiler supports C23 (body of main). -ac_c_conftest_c23_main=' - { - label_before_declaration: - int arr[10] = {}; - if (arr[0]) - goto label_before_declaration; - if (!arr[0]) - goto label_at_end_of_block; - label_at_end_of_block: - } - ok |= !null_pointer; - ok |= two != three; -' - -# Test code for whether the C compiler supports C23 (complete). -ac_c_conftest_c23_program="${ac_c_conftest_c23_globals} - -int -main (int, char **) -{ - int ok = 0; - ${ac_c_conftest_c23_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (global declarations) -ac_c_conftest_c89_globals=' -/* Do not test the value of __STDC__, because some compilers define it to 0 - or do not define it, while otherwise adequately conforming. */ - -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ -struct buf { int x; }; -struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (char **p, int i) -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* C89 style stringification. */ -#define noexpand_stringify(a) #a -const char *stringified = noexpand_stringify(arbitrary+token=sequence); - -/* C89 style token pasting. Exercises some of the corner cases that - e.g. old MSVC gets wrong, but not very hard. */ -#define noexpand_concat(a,b) a##b -#define expand_concat(a,b) noexpand_concat(a,b) -extern int vA; -extern int vbee; -#define aye A -#define bee B -int *pvA = &expand_concat(v,aye); -int *pvbee = &noexpand_concat(v,bee); - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not \xHH hex character constants. - These do not provoke an error unfortunately, instead are silently treated - as an "x". The following induces an error, until -std is added to get - proper ANSI mode. Curiously \x00 != x always comes out true, for an - array size at least. It is necessary to write \x00 == 0 to get something - that is true only with -std. */ -int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) '\''x'\'' -int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), - int, int);' - -# Test code for whether the C compiler supports C89 (body of main). -ac_c_conftest_c89_main=' -ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); -' - -# Test code for whether the C compiler supports C99 (global declarations) -ac_c_conftest_c99_globals=' -/* Does the compiler advertise C99 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# error "Compiler does not advertise C99 conformance" -#endif - -// See if C++-style comments work. - -#include -extern int puts (const char *); -extern int printf (const char *, ...); -extern int dprintf (int, const char *, ...); -extern void *malloc (size_t); -extern void free (void *); - -// Check varargs macros. These examples are taken from C99 6.10.3.5. -// dprintf is used instead of fprintf to avoid needing to declare -// FILE and stderr, and "aND" is used instead of "and" to work around -// GCC bug 40564 which is irrelevant here. -#define debug(...) dprintf (2, __VA_ARGS__) -#define showlist(...) puts (#__VA_ARGS__) -#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) -static void -test_varargs_macros (void) -{ - int x = 1234; - int y = 5678; - debug ("Flag"); - debug ("X = %d\n", x); - showlist (The first, second, aND third items.); - report (x>y, "x is %d but y is %d", x, y); -} - -// Check long long types. -#define BIG64 18446744073709551615ull -#define BIG32 4294967295ul -#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) -#if !BIG_OK - #error "your preprocessor is broken" -#endif -#if BIG_OK -#else - #error "your preprocessor is broken" -#endif -static long long int bignum = -9223372036854775807LL; -static unsigned long long int ubignum = BIG64; - -struct incomplete_array -{ - int datasize; - double data[]; -}; - -struct named_init { - int number; - const wchar_t *name; - double average; -}; - -typedef const char *ccp; - -static inline int -test_restrict (ccp restrict text) -{ - // Iterate through items via the restricted pointer. - // Also check for declarations in for loops. - for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) - continue; - return 0; -} - -// Check varargs and va_copy. -static bool -test_varargs (const char *format, ...) -{ - va_list args; - va_start (args, format); - va_list args_copy; - va_copy (args_copy, args); - - const char *str = ""; - int number = 0; - float fnumber = 0; - - while (*format) - { - switch (*format++) - { - case '\''s'\'': // string - str = va_arg (args_copy, const char *); - break; - case '\''d'\'': // int - number = va_arg (args_copy, int); - break; - case '\''f'\'': // float - fnumber = va_arg (args_copy, double); - break; - default: - break; - } - } - va_end (args_copy); - va_end (args); - - return *str && number && fnumber; -} -' - -# Test code for whether the C compiler supports C99 (body of main). -ac_c_conftest_c99_main=' - // Check bool. - _Bool success = false; - success |= (argc != 0); - - // Check restrict. - if (test_restrict ("String literal") == 0) - success = true; - const char *restrict newvar = "Another string"; - - // Check varargs. - success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); - test_varargs_macros (); - - // Check flexible array members. - static struct incomplete_array *volatile incomplete_array_pointer; - struct incomplete_array *ia = incomplete_array_pointer; - ia->datasize = 10; - for (int i = 0; i < ia->datasize; ++i) - ia->data[i] = i * 1.234; - // Work around memory leak warnings. - free (ia); - - // Check named initializers. - struct named_init ni = { - .number = 34, - .name = L"Test wide string", - .average = 543.34343, - }; - - ni.number = 58; - - // Do not test for VLAs, as some otherwise-conforming compilers lack them. - // C code should instead use __STDC_NO_VLA__; see Autoconf manual. - - // work around unused variable warnings - ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' - || ni.number != 58); -' - -# Test code for whether the C compiler supports C11 (global declarations) -ac_c_conftest_c11_globals=' -/* Does the compiler advertise C11 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L -# error "Compiler does not advertise C11 conformance" -#endif - -// Check _Alignas. -char _Alignas (double) aligned_as_double; -char _Alignas (0) no_special_alignment; -extern char aligned_as_int; -char _Alignas (0) _Alignas (int) aligned_as_int; - -// Check _Alignof. -enum -{ - int_alignment = _Alignof (int), - int_array_alignment = _Alignof (int[100]), - char_alignment = _Alignof (char) -}; -_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); - -// Check _Noreturn. -int _Noreturn does_not_return (void) { for (;;) continue; } - -// Check _Static_assert. -struct test_static_assert -{ - int x; - _Static_assert (sizeof (int) <= sizeof (long int), - "_Static_assert does not work in struct"); - long int y; -}; - -// Check UTF-8 literals. -#define u8 syntax error! -char const utf8_literal[] = u8"happens to be ASCII" "another string"; - -// Check duplicate typedefs. -typedef long *long_ptr; -typedef long int *long_ptr; -typedef long_ptr long_ptr; - -// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. -struct anonymous -{ - union { - struct { int i; int j; }; - struct { int k; long int l; } w; - }; - int m; -} v1; -' - -# Test code for whether the C compiler supports C11 (body of main). -ac_c_conftest_c11_main=' - _Static_assert ((offsetof (struct anonymous, i) - == offsetof (struct anonymous, w.k)), - "Anonymous union alignment botch"); - v1.i = 2; - v1.w.k = 5; - ok |= v1.i != 5; -' - -# Test code for whether the C compiler supports C11 (complete). -ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} -${ac_c_conftest_c11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - ${ac_c_conftest_c11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C99 (complete). -ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (complete). -ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - return ok; -} -" - -as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" -as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" -as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" -as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" -as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" -as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" -as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" -as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" -as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" -as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" - -# Auxiliary files required by this configure script. -ac_aux_files="config.guess config.sub ltmain.sh missing install-sh compile" - -# Locations in which to look for auxiliary files. -ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." - -# Search for a directory containing all of the required auxiliary files, -# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. -# If we don't find one directory that contains all the files we need, -# we report the set of missing files from the *first* directory in -# $ac_aux_dir_candidates and give up. -ac_missing_aux_files="" -ac_first_candidate=: -printf '%s\n' "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in $ac_aux_dir_candidates -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - - printf '%s\n' "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 - ac_aux_dir_found=yes - ac_install_sh= - for ac_aux in $ac_aux_files - do - # As a special case, if "install-sh" is required, that requirement - # can be satisfied by any of "install-sh", "install.sh", or "shtool", - # and $ac_install_sh is set appropriately for whichever one is found. - if test x"$ac_aux" = x"install-sh" - then - if test -f "${as_dir}install-sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 - ac_install_sh="${as_dir}install-sh -c" - elif test -f "${as_dir}install.sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 - ac_install_sh="${as_dir}install.sh -c" - elif test -f "${as_dir}shtool"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 - ac_install_sh="${as_dir}shtool install -c" - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} install-sh" - else - break - fi - fi - else - if test -f "${as_dir}${ac_aux}"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" - else - break - fi - fi - fi - done - if test "$ac_aux_dir_found" = yes; then - ac_aux_dir="$as_dir" - break - fi - ac_first_candidate=false - - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in @%:@( - e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; -esac -fi - - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -if test -f "${ac_aux_dir}config.guess"; then - ac_@&t@config_guess="$SHELL ${ac_aux_dir}config.guess" -fi -if test -f "${ac_aux_dir}config.sub"; then - ac_@&t@config_sub="$SHELL ${ac_aux_dir}config.sub" -fi -if test -f "$ac_aux_dir/configure"; then - ac_@&t@configure="$SHELL ${ac_aux_dir}configure" -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w= - for ac_val in x $ac_old_val; do - ac_old_val_w="$ac_old_val_w $ac_val" - done - ac_new_val_w= - for ac_val in x $ac_new_val; do - ac_new_val_w="$ac_new_val_w $ac_val" - done - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 -printf '%s\n' "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 -printf '%s\n' "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 -printf '%s\n' "$as_me: former value: '$ac_old_val'" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 -printf '%s\n' "$as_me: current value: '$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`printf '%s\n' "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -printf '%s\n' "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' - and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in @%:@((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers config.h" - - - -# Set common system defines for POSIX extensions, such as _GNU_SOURCE -# Must be called before any macros that run the compiler (like LT_INIT) -# to avoid autoconf errors. - - - - - - - - - - - - - - -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $@%:@ != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" - fi -fi -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. -set dummy ${ac_tool_prefix}clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "clang", so it can be a program name with args. -set dummy clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -fi - - -test -z "$CC" && { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See 'config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion -version; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -printf %s "checking whether the C compiler works... " >&6; } -ac_link_default=`printf '%s\n' "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. -# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an '-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else case e in @%:@( - e) ac_file='' ;; -esac -fi -if test -z "$ac_file" -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See 'config.log' for more details" "$LINENO" 5; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -printf %s "checking for C compiler default output file name... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -printf '%s\n' "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -printf %s "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) -# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will -# work properly (i.e., refer to 'conftest.exe'), while it won't with -# 'rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else case e in @%:@( - e) { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest conftest$ac_cv_exeext -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -printf '%s\n' "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -int -main (void) -{ -FILE *f = fopen ("conftest.out", "w"); - if (!f) - return 1; - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -printf %s "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use '--host'. -See 'config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -printf '%s\n' "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext \ - conftest.o conftest.obj conftest.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -printf %s "checking for suffix of object files... " >&6; } -if test ${ac_cv_objext+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -printf '%s\n' "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 -printf %s "checking whether the compiler supports GNU C... " >&6; } -if test ${ac_cv_c_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else case e in @%:@( - e) ac_compiler_gnu=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -printf '%s\n' "$ac_cv_c_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+y} -ac_save_CFLAGS=$CFLAGS -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -printf %s "checking whether $CC accepts -g... " >&6; } -if test ${ac_cv_prog_cc_g+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -else case e in @%:@( - e) CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -printf '%s\n' "$ac_cv_prog_cc_g" >&6; } -if test $ac_test_CFLAGS; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -ac_prog_cc_stdc=no -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C23 features" >&5 -printf %s "checking for $CC option to enable C23 features... " >&6; } -if test ${ac_cv_prog_cc_c23+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c23=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c23_program -_ACEOF -for ac_arg in '' -std=gnu23 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c23=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c23" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c23" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c23" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c23" >&5 -printf '%s\n' "$ac_cv_prog_cc_c23" >&6; } - CC="$CC $ac_cv_prog_cc_c23" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c23 - ac_prog_cc_stdc=c23 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 -printf %s "checking for $CC option to enable C11 features... " >&6; } -if test ${ac_cv_prog_cc_c11+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c11=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c11_program -_ACEOF -for ac_arg in '' -std=gnu11 -std:c11 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c11" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c11" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c11" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -printf '%s\n' "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } -if test ${ac_cv_prog_cc_c99+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c99=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c99=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c99" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c99" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c99" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -printf '%s\n' "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 -printf %s "checking for $CC option to enable C89 features... " >&6; } -if test ${ac_cv_prog_cc_c89+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c89_program -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c89" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c89" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -printf '%s\n' "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 ;; -esac -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -printf %s "checking whether $CC understands -c and -o together... " >&6; } -if test ${am_cv_prog_cc_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - # aligned with autoconf, so not including core; see bug#72225. - rm -f -r a.out a.exe b.out conftest.$ac_ext conftest.$ac_objext \ - conftest.dSYM conftest1.$ac_ext conftest1.$ac_objext conftest1.dSYM \ - conftest2.$ac_ext conftest2.$ac_objext conftest2.dSYM - unset am_i ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -printf '%s\n' "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_header= ac_cache= -for ac_item in $ac_header_c_list -do - if test $ac_cache; then - ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" - if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf '%s\n' "#define $ac_item 1" >> confdefs.h - fi - ac_header= ac_cache= - elif test $ac_header; then - ac_cache=$ac_item - else - ac_header=$ac_item - fi -done - - - - - - - - -if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes -then : - -printf '%s\n' "@%:@define STDC_HEADERS 1" >>confdefs.h - -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 -printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test ${ac_cv_safe_to_define___extensions__+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -# define __EXTENSIONS__ 1 - $ac_includes_default -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_safe_to_define___extensions__=yes -else case e in @%:@( - e) ac_cv_safe_to_define___extensions__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -printf '%s\n' "$ac_cv_safe_to_define___extensions__" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 -printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } -if test ${ac_cv_should_define__xopen_source+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_should_define__xopen_source=no - if test $ac_cv_header_wchar_h = yes -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #define _XOPEN_SOURCE 500 - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_should_define__xopen_source=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 -printf '%s\n' "$ac_cv_should_define__xopen_source" >&6; } - - printf '%s\n' "@%:@define _ALL_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _COSMO_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _DARWIN_C_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _GNU_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h - - printf '%s\n' "@%:@define _NETBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _OPENBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h - - printf '%s\n' "@%:@define _TANDEM_SOURCE 1" >>confdefs.h - - if test $ac_cv_header_minix_config_h = yes -then : - MINIX=yes - printf '%s\n' "@%:@define _MINIX 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_1_SOURCE 2" >>confdefs.h - -else case e in @%:@( - e) MINIX= ;; -esac -fi - if test $ac_cv_safe_to_define___extensions__ = yes -then : - printf '%s\n' "@%:@define __EXTENSIONS__ 1" >>confdefs.h - -fi - if test $ac_cv_should_define__xopen_source = yes -then : - printf '%s\n' "@%:@define _XOPEN_SOURCE 500" >>confdefs.h - -fi - - -# Initialize Automake -am__api_version='1.18' - - - # Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -printf %s "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if test ${ac_cv_path_install+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - # Account for fact that we put trailing slashes in our PATH walk. -case $as_dir in @%:@(( - ./ | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF/1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF/1 since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - ;; -esac -fi - if test ${ac_cv_path_install+y}; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -printf '%s\n' "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5 -printf %s "checking whether sleep supports fractional seconds... " >&6; } -if test ${am_cv_sleep_fractional_seconds+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if sleep 0.001 2>/dev/null -then : - am_cv_sleep_fractional_seconds=yes -else case e in @%:@( - e) am_cv_sleep_fractional_seconds=no ;; -esac -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_sleep_fractional_seconds" >&5 -printf '%s\n' "$am_cv_sleep_fractional_seconds" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking filesystem timestamp resolution" >&5 -printf %s "checking filesystem timestamp resolution... " >&6; } -if test ${am_cv_filesystem_timestamp_resolution+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) # Default to the worst case. -am_cv_filesystem_timestamp_resolution=2 - -# Only try to go finer than 1 sec if sleep can do it. -# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, -# - 1 sec is not much of a win compared to 2 sec, and -# - it takes 2 seconds to perform the test whether 1 sec works. -# -# Instead, just use the default 2s on platforms that have 1s resolution, -# accept the extra 1s delay when using $sleep in the Automake tests, in -# exchange for not incurring the 2s delay for running the test for all -# packages. -# -am_try_resolutions= -if test "$am_cv_sleep_fractional_seconds" = yes; then - # Even a millisecond often causes a bunch of false positives, - # so just try a hundredth of a second. The time saved between .001 and - # .01 is not terribly consequential. - am_try_resolutions="0.01 0.1 $am_try_resolutions" -fi - -# In order to catch current-generation FAT out, we must *modify* files -# that already exist; the *creation* timestamp is finer. Use names -# that make ls -t sort them differently when they have equal -# timestamps than when they have distinct timestamps, keeping -# in mind that ls -t prints the *newest* file first. -rm -f conftest.ts? -: > conftest.ts1 -: > conftest.ts2 -: > conftest.ts3 - -# Make sure ls -t actually works. Do 'set' in a subshell so we don't -# clobber the current shell's arguments. (Outer-level square brackets -# are removed by m4; they're present so that m4 does not expand -# ; be careful, easy to get confused.) -if ( - set X `ls -t conftest.ts[12]` && - { - test "$*" != "X conftest.ts1 conftest.ts2" || - test "$*" != "X conftest.ts2 conftest.ts1"; - } -); then :; else - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - printf '%s\n' ""Bad output from ls -t: \"`ls -t conftest.ts[12]`\""" >&5 - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "ls -t produces unexpected output. -Make sure there is not a broken ls alias in your environment. -See 'config.log' for more details" "$LINENO" 5; } -fi - -for am_try_res in $am_try_resolutions; do - # Any one fine-grained sleep might happen to cross the boundary - # between two values of a coarser actual resolution, but if we do - # two fine-grained sleeps in a row, at least one of them will fall - # entirely within a coarse interval. - echo alpha > conftest.ts1 - sleep $am_try_res - echo beta > conftest.ts2 - sleep $am_try_res - echo gamma > conftest.ts3 - - # We assume that 'ls -t' will make use of high-resolution - # timestamps if the operating system supports them at all. - if (set X `ls -t conftest.ts?` && - test "$2" = conftest.ts3 && - test "$3" = conftest.ts2 && - test "$4" = conftest.ts1); then - # - # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, - # because we don't need to test make. - make_ok=true - if test $am_try_res != 1; then - # But if we've succeeded so far with a subsecond resolution, we - # have one more thing to check: make. It can happen that - # everything else supports the subsecond mtimes, but make doesn't; - # notably on macOS, which ships make 3.81 from 2006 (the last one - # released under GPLv2). https://bugs.gnu.org/68808 - # - # We test $MAKE if it is defined in the environment, else "make". - # It might get overridden later, but our hope is that in practice - # it does not matter: it is the system "make" which is (by far) - # the most likely to be broken, whereas if the user overrides it, - # probably they did so with a better, or at least not worse, make. - # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html - # - # Create a Makefile (real tab character here): - rm -f conftest.mk - echo 'conftest.ts1: conftest.ts2' >conftest.mk - echo ' touch conftest.ts2' >>conftest.mk - # - # Now, running - # touch conftest.ts1; touch conftest.ts2; make - # should touch ts1 because ts2 is newer. This could happen by luck, - # but most often, it will fail if make's support is insufficient. So - # test for several consecutive successes. - # - # (We reuse conftest.ts[12] because we still want to modify existing - # files, not create new ones, per above.) - n=0 - make=${MAKE-make} - until test $n -eq 3; do - echo one > conftest.ts1 - sleep $am_try_res - echo two > conftest.ts2 # ts2 should now be newer than ts1 - if $make -f conftest.mk | grep 'up to date' >/dev/null; then - make_ok=false - break # out of $n loop - fi - n=`expr $n + 1` - done - fi - # - if $make_ok; then - # Everything we know to check worked out, so call this resolution good. - am_cv_filesystem_timestamp_resolution=$am_try_res - break # out of $am_try_res loop - fi - # Otherwise, we'll go on to check the next resolution. - fi -done -rm -f conftest.ts? -# (end _am_filesystem_timestamp_resolution) - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_filesystem_timestamp_resolution" >&5 -printf '%s\n' "$am_cv_filesystem_timestamp_resolution" >&6; } - -# This check should not be cached, as it may vary across builds of -# different projects. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -printf %s "checking whether build environment is sane... " >&6; } -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[\\\"\#\$\&\'\`$am_lf]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; -esac -case $srcdir in - *[\\\"\#\$\&\'\`$am_lf\ \ ]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -am_build_env_is_sane=no -am_has_slept=no -rm -f conftest.file -for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - test "$2" = conftest.file - ); then - am_build_env_is_sane=yes - break - fi - # Just in case. - sleep "$am_cv_filesystem_timestamp_resolution" - am_has_slept=yes -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_build_env_is_sane" >&5 -printf '%s\n' "$am_build_env_is_sane" >&6; } -if test "$am_build_env_is_sane" = no; then - as_fn_error $? "newly created file is older than distributed files! -Check your system clock" "$LINENO" 5 -fi - -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1 -then : - -else case e in @%:@( - e) ( sleep "$am_cv_filesystem_timestamp_resolution" ) & - am_sleep_pid=$! - ;; -esac -fi - -rm -f conftest.file - -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was 's,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`printf '%s\n' "$program_transform_name" | sed "$ac_script"` - - - if test x"${MISSING+set}" != xset; then - MISSING="\${SHELL} '$am_aux_dir/missing'" -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -printf '%s\n' "$as_me: WARNING: 'missing' script is too old or missing" >&2;} -fi - -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 -printf %s "checking for a race-free mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if test ${ac_cv_path_mkdir+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue - case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir ('*'coreutils) '* | \ - *'BusyBox '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - ;; -esac -fi - - test -d ./--version && rmdir ./--version - if test ${ac_cv_path_mkdir+y}; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use plain mkdir -p, - # in the hope it doesn't have the bugs of ancient mkdir. - MKDIR_P='mkdir -p' - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -printf '%s\n' "$MKDIR_P" >&6; } - -for ac_prog in gawk mawk nawk awk 'busybox awk' -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AWK+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -printf '%s\n' "$AWK" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`printf '%s\n' "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval test \${ac_cv_prog_make_${ac_make}_set+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @printf '%s\n' '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make ;; -esac -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - SET_MAKE= -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depfiles" - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 -printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } -cat > confinc.mk << 'END' -am__doit: - @echo this is the am__doit target >confinc.out -.PHONY: am__doit -END -am__include="#" -am__quote= -# BSD make does it like this. -echo '.include "confinc.mk" # ignored' > confmf.BSD -# Other make implementations (GNU, Solaris 10, AIX) do it like this. -echo 'include confinc.mk # ignored' > confmf.GNU -_am_result=no -for s in GNU BSD; do - { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 - (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - case $?:`cat confinc.out 2>/dev/null` in @%:@( - '0:this is the am__doit target') : - case $s in @%:@( - BSD) : - am__include='.include' am__quote='"' ;; @%:@( - *) : - am__include='include' am__quote='' ;; -esac ;; @%:@( - *) : - ;; -esac - if test "$am__include" != "#"; then - _am_result="yes ($s style)" - break - fi -done -rm -f confinc.* confmf.* -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 -printf '%s\n' "${_am_result}" >&6; } - -@%:@ Check whether --enable-dependency-tracking was given. -if test ${enable_dependency_tracking+y} -then : - enableval=$enable_dependency_tracking; -fi - -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi - if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - -AM_DEFAULT_VERBOSITY=1 -@%:@ Check whether --enable-silent-rules was given. -if test ${enable_silent_rules+y} -then : - enableval=$enable_silent_rules; -fi - -am_make=${MAKE-make} -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -printf %s "checking whether $am_make supports nested variables... " >&6; } -if test ${am_cv_make_support_nested_variables+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if printf '%s\n' 'TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -printf '%s\n' "$am_cv_make_support_nested_variables" >&6; } -AM_BACKSLASH='\' - -am__rm_f_notfound= -if (rm -f && rm -fr && rm -rf) 2>/dev/null -then : - -else case e in @%:@( - e) am__rm_f_notfound='""' ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking xargs -n works" >&5 -printf %s "checking xargs -n works... " >&6; } -if test ${am_cv_xargs_n_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 -3" -then : - am_cv_xargs_n_works=yes -else case e in @%:@( - e) am_cv_xargs_n_works=no ;; -esac -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_xargs_n_works" >&5 -printf '%s\n' "$am_cv_xargs_n_works" >&6; } -if test "$am_cv_xargs_n_works" = yes -then : - am__xargs_n='xargs -n' -else case e in @%:@( - e) am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "" "$am__xargs_n_arg"; done; }' - ;; -esac -fi - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE='libXext' - VERSION='1.3.7' - - -printf '%s\n' "@%:@define PACKAGE \"$PACKAGE\"" >>confdefs.h - - -printf '%s\n' "@%:@define VERSION \"$VERSION\"" >>confdefs.h - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -mkdir_p='$(MKDIR_P)' - -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AMTAR='$${TAR-tar}' - - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar plaintar pax cpio none' - -# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 -printf %s "checking whether UID '$am_uid' is supported by ustar format... " >&6; } - if test x$am_uid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&2;} - elif test $am_uid -le $am_max_uid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 -printf %s "checking whether GID '$am_gid' is supported by ustar format... " >&6; } - if test x$gm_gid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&2;} - elif test $am_gid -le $am_max_gid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 -printf %s "checking how to create a ustar tar archive... " >&6; } - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_ustar-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - { echo "$as_me:$LINENO: $_am_tar --version" >&5 - ($_am_tar --version) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && break - done - am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x ustar -w "$$tardir"' - am__tar_='pax -L -x ustar -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H ustar -L' - am__tar_='find "$tardir" -print | cpio -o -H ustar -L' - am__untar='cpio -i -H ustar -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_ustar}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 - (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - rm -rf conftest.dir - if test -s conftest.tar; then - { echo "$as_me:$LINENO: $am__untar &5 - ($am__untar &5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 - (cat conftest.dir/file) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - grep GrepMe conftest.dir/file >/dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - if test ${am_cv_prog_tar_ustar+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) am_cv_prog_tar_ustar=$_am_tool ;; -esac -fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 -printf '%s\n' "$am_cv_prog_tar_ustar" >&6; } - - - - - -depcc="$CC" am_compiler_list= - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -printf %s "checking dependency style of $depcc... " >&6; } -if test ${am_cv_CC_dependencies_compiler_type+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thus: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -printf '%s\n' "$am_cv_CC_dependencies_compiler_type" >&6; } -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' -else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi - - -# Variables for tags utilities; see am/tags.am -if test -z "$CTAGS"; then - CTAGS=ctags -fi - -if test -z "$ETAGS"; then - ETAGS=etags -fi - -if test -z "$CSCOPE"; then - CSCOPE=cscope -fi - - - - - - - - -# Initialize libtool -case `pwd` in - *\ * | *\ *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 -printf '%s\n' "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; -esac - - - -macro_version='2.5.4' -macro_revision='2.5.4' - - - - - - - - - - - - - - -ltmain=$ac_aux_dir/ltmain.sh - - - - # Make sure we can run config.sub. -$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -printf %s "checking build system type... " >&6; } -if test ${ac_cv_build+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -printf '%s\n' "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`printf '%s\n' "$build_os" | sed 's/ /-/g'`;; esac - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -printf %s "checking host system type... " >&6; } -if test ${ac_cv_host+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -printf '%s\n' "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`printf '%s\n' "$host_os" | sed 's/ /-/g'`;; esac - - -# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 -printf %s "checking how to print strings... " >&6; } -# Test print first, because it will be a builtin if present. -if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "" -} - -case $ECHO in - printf*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: printf" >&5 -printf '%s\n' "printf" >&6; } ;; - print*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 -printf '%s\n' "print -r" >&6; } ;; - *) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: cat" >&5 -printf '%s\n' "cat" >&6; } ;; -esac - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -printf %s "checking for a sed that does not truncate output... " >&6; } -if test ${ac_cv_path_SED+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in sed gsed - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -printf '%s\n' "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - -test -z "$SED" && SED=sed -Xsed="$SED -e 1s/^X//" - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in grep ggrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf '%s\n' "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in egrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf '%s\n' "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - EGREP_TRADITIONAL=$EGREP - ac_cv_path_EGREP_TRADITIONAL=$EGREP - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 -printf %s "checking for fgrep... " >&6; } -if test ${ac_cv_path_FGREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 - then ac_cv_path_FGREP="$GREP -F" - else - if test -z "$FGREP"; then - ac_path_FGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in fgrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_FGREP" || continue -# Check for GNU ac_path_FGREP and select it if it is found. - # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'FGREP' >> "conftest.nl" - "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_FGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_FGREP="$ac_path_FGREP" - ac_path_FGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_FGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_FGREP"; then - as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_FGREP=$FGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 -printf '%s\n' "$ac_cv_path_FGREP" >&6; } - FGREP="$ac_cv_path_FGREP" - - -test -z "$GREP" && GREP=grep - - - - - - - - - - - - - - - - - - - -@%:@ Check whether --with-gnu-ld was given. -if test ${with_gnu_ld+y} -then : - withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes -else case e in @%:@( - e) with_gnu_ld=no ;; -esac -fi - -ac_prog=ld -if test yes = "$GCC"; then - # Check if gcc -print-prog-name=ld gives a path. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -printf %s "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw* | *-*-windows*) - # gcc leaves a trailing carriage return, which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD=$ac_prog - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test yes = "$with_gnu_ld"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -printf %s "checking for GNU ld... " >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -printf %s "checking for non-GNU ld... " >&6; } -fi -if test ${lt_cv_path_LD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$LD"; then - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD=$ac_dir/$ac_prog - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -printf '%s\n' "$LD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -printf %s "checking if the linker ($LD) is GNU ld... " >&6; } -if test ${lt_cv_prog_gnu_ld+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -printf '%s\n' "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 -printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if test ${lt_cv_path_NM+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM=$NM -else - lt_nm_to_check=${ac_tool_prefix}nm - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - tmp_nm=$ac_dir/$lt_tmp_nm - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the 'sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty - case $build_os in - mingw* | windows*) lt_bad_file=conftest.nm/nofile ;; - *) lt_bad_file=/dev/null ;; - esac - case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in - *$lt_bad_file* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break 2 - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break 2 - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS=$lt_save_ifs - done - : ${lt_cv_path_NM=no} -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 -printf '%s\n' "$lt_cv_path_NM" >&6; } -if test no != "$lt_cv_path_NM"; then - NM=$lt_cv_path_NM -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - if test -n "$ac_tool_prefix"; then - for ac_prog in dumpbin "link -dump" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DUMPBIN"; then - ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DUMPBIN=$ac_cv_prog_DUMPBIN -if test -n "$DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 -printf '%s\n' "$DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$DUMPBIN" && break - done -fi -if test -z "$DUMPBIN"; then - ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in dumpbin "link -dump" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DUMPBIN"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN -if test -n "$ac_ct_DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 -printf '%s\n' "$ac_ct_DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_DUMPBIN" && break -done - - if test "x$ac_ct_DUMPBIN" = x; then - DUMPBIN=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DUMPBIN=$ac_ct_DUMPBIN - fi -fi - - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols -headers" - ;; - *) - DUMPBIN=: - ;; - esac - fi - - if test : != "$DUMPBIN"; then - NM=$DUMPBIN - fi -fi -test -z "$NM" && NM=nm - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 -printf %s "checking the name lister ($NM) interface... " >&6; } -if test ${lt_cv_nm_interface+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: output\"" >&5) - cat conftest.out >&5 - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 -printf '%s\n' "$lt_cv_nm_interface" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -printf %s "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -printf '%s\n' "no, using $LN_S" >&6; } -fi - -# find the maximum length of command line arguments -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 -printf %s "checking the maximum length of command line arguments... " >&6; } -if test ${lt_cv_sys_max_cmd_len+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) i=0 - teststring=ABCD - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu* | ironclad*) - # Under GNU Hurd and Ironclad, this test is not required because there - # is no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | windows* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[ ]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test X`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test 17 != "$i" # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac - ;; -esac -fi - -if test -n "$lt_cv_sys_max_cmd_len"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 -printf '%s\n' "$lt_cv_sys_max_cmd_len" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none" >&5 -printf '%s\n' "none" >&6; } -fi -max_cmd_len=$lt_cv_sys_max_cmd_len - - - - - - -: ${CP="cp -f"} -: ${MV="mv -f"} -: ${RM="rm -f"} - -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - lt_unset=unset -else - lt_unset=false -fi - - - - - -# test EBCDIC or ASCII -case `echo X|tr X '\101'` in - A) # ASCII based system - # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr - lt_SP2NL='tr \040 \012' - lt_NL2SP='tr \015\012 \040\040' - ;; - *) # EBCDIC based system - lt_SP2NL='tr \100 \n' - lt_NL2SP='tr \r\n \100\100' - ;; -esac - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 -printf %s "checking how to convert $build file names to $host format... " >&6; } -if test ${lt_cv_to_host_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $host in - *-*-mingw* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 - ;; - esac - ;; - *-*-cygwin* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin - ;; - esac - ;; - * ) # unhandled hosts (and "normal" native builds) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; -esac - ;; -esac -fi - -to_host_file_cmd=$lt_cv_to_host_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_host_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 -printf %s "checking how to convert $build file names to toolchain format... " >&6; } -if test ${lt_cv_to_tool_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) #assume ordinary cross tools, or native build. -lt_cv_to_tool_file_cmd=func_convert_file_noop -case $host in - *-*-mingw* | *-*-windows* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 - ;; - esac - ;; -esac - ;; -esac -fi - -to_tool_file_cmd=$lt_cv_to_tool_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_tool_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 -printf %s "checking for $LD option to reload object files... " >&6; } -if test ${lt_cv_ld_reload_flag+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_reload_flag='-r' ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 -printf '%s\n' "$lt_cv_ld_reload_flag" >&6; } -reload_flag=$lt_cv_ld_reload_flag -case $reload_flag in -"" | " "*) ;; -*) reload_flag=" $reload_flag" ;; -esac -reload_cmds='$LD$reload_flag -o $output$reload_objs' -case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - if test yes != "$GCC"; then - reload_cmds=false - fi - ;; - darwin*) - if test yes = "$GCC"; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' - else - reload_cmds='$LD$reload_flag -o $output$reload_objs' - fi - ;; -esac - - - - - - - - - -# Extract the first word of "file", so it can be a program name with args. -set dummy file; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_FILECMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$FILECMD"; then - ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FILECMD="file" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_prog_FILECMD" && ac_cv_prog_FILECMD=":" -fi ;; -esac -fi -FILECMD=$ac_cv_prog_FILECMD -if test -n "$FILECMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 -printf '%s\n' "$FILECMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -printf '%s\n' "$OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -printf '%s\n' "$ac_ct_OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 -printf %s "checking how to recognize dependent libraries... " >&6; } -if test ${lt_cv_deplibs_check_method+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# 'unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'file_magic [[regex]]' -- check by looking for files in library path -# that responds to the $file_magic_cmd with a given extended regex. -# If you have 'file' or equivalent on your system and you're not sure -# whether 'pass_all' will *always* work, you probably want this one. - -case $host_os in -aix[4-9]*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[45]*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='$FILECMD -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | windows* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - if ( file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -cegcc*) - # use the weaker test based on 'objdump'. See mingw*. - lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly* | midnightbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -haiku*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=$FILECMD - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[3-9]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -*-mlibc) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -*nto* | *qnx*) - lt_cv_deplibs_check_method=pass_all - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -serenity*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -tpf*) - lt_cv_deplibs_check_method=pass_all - ;; -os2*) - lt_cv_deplibs_check_method=pass_all - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 -printf '%s\n' "$lt_cv_deplibs_check_method" >&6; } - -file_magic_glob= -want_nocaseglob=no -if test "$build" = "$host"; then - case $host_os in - mingw* | windows* | pw32*) - if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then - want_nocaseglob=yes - else - file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` - fi - ;; - esac -fi - -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - - - - - - - - - - - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -printf '%s\n' "$DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -printf '%s\n' "$ac_ct_DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 -printf %s "checking how to associate runtime and link libraries... " >&6; } -if test ${lt_cv_sharedlib_from_linklib_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_sharedlib_from_linklib_cmd='unknown' - -case $host_os in -cygwin* | mingw* | windows* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh; - # decide which one to use based on capabilities of $DLLTOOL - case `$DLLTOOL --help 2>&1` in - *--identify-strict*) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib - ;; - *) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback - ;; - esac - ;; -*) - # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd=$ECHO - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 -printf '%s\n' "$lt_cv_sharedlib_from_linklib_cmd" >&6; } -sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd -test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -printf '%s\n' "$RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -printf '%s\n' "$ac_ct_RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AR+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -printf '%s\n' "$AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_AR+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -printf '%s\n' "$ac_ct_AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -: ${AR=ar} - - - - - - -# Use ARFLAGS variable as AR's operation code to sync the variable naming with -# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have -# higher priority because that's what people were doing historically (setting -# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS -# variable obsoleted/removed. - -test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} -lt_ar_flags=$AR_FLAGS - - - - - - -# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override -# by AR_FLAGS because that was never working and AR_FLAGS is about to die. - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 -printf %s "checking for archiver @FILE support... " >&6; } -if test ${lt_cv_ar_at_file+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ar_at_file=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - echo conftest.$ac_objext > conftest.lst - lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -eq "$ac_status"; then - # Ensure the archiver fails upon bogus file names. - rm -f conftest.$ac_objext libconftest.a - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -ne "$ac_status"; then - lt_cv_ar_at_file=@ - fi - fi - rm -f conftest.* libconftest.a - -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 -printf '%s\n' "$lt_cv_ar_at_file" >&6; } - -if test no = "$lt_cv_ar_at_file"; then - archiver_list_spec= -else - archiver_list_spec=$lt_cv_ar_at_file -fi - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -test -z "$STRIP" && STRIP=: - - - - - - - -test -z "$RANLIB" && RANLIB=: - - - - - - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# Check for command to grab the raw symbol name followed by C symbol from nm. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 -printf %s "checking command to parse $NM output from $compiler object... " >&6; } -if test ${lt_cv_sys_global_symbol_pipe+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw* | windows* | pw32* | cegcc*) - symcode='[ABCDGISTW]' - ;; -hpux*) - if test ia64 = "$host_cpu"; then - symcode='[ABCDEGRST]' - fi - ;; -irix* | nonstopux*) - symcode='[BCDEGRST]' - ;; -osf*) - symcode='[BCDEGQRST]' - ;; -solaris*) - symcode='[BCDRT]' - ;; -sco3.2v5*) - symcode='[DT]' - ;; -sysv4.2uw2*) - symcode='[DT]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[ABDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[ABCDGIRSTW]' ;; -esac - -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Gets list of data symbols to import. - lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" - # Adjust the below global symbol transforms to fixup imported variables. - lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" - lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" - lt_c_name_lib_hook="\ - -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ - -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" -else - # Disable hooks by default. - lt_cv_sys_global_symbol_to_import= - lt_cdecl_hook= - lt_c_name_hook= - lt_c_name_lib_hook= -fi - -# Transform an extracted symbol line into a proper C declaration. -# Some systems (esp. on ia64) link data and code symbols differently, -# so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ -$lt_cdecl_hook\ -" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ -$lt_c_name_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" - -# Transform an extracted symbol line into symbol name with lib prefix and -# symbol address. -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ -$lt_c_name_lib_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw* | windows*) - opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# Try without a prefix underscore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function, - # D for any global variable and I for any imported variable. - # Also find C++ and __fastcall symbols from MSVC++ or ICC, - # which start with @ or ?. - lt_cv_sys_global_symbol_pipe="$AWK '"\ -" {last_section=section; section=\$ 3};"\ -" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ -" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ -" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ -" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ -" \$ 0!~/External *\|/{next};"\ -" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ -" {if(hide[section]) next};"\ -" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ -" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ -" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ -" ' prfx=^$ac_symprfx" - else - lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <<_LT_EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(void); -void nm_test_func(void){} -#ifdef __cplusplus -} -#endif -int main(void){nm_test_var='a';nm_test_func();return(0);} -_LT_EOF - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Now try to grab the symbols. - nlist=conftest.nm - $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 - if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if $GREP ' nm_test_var$' "$nlist" >/dev/null; then - if $GREP ' nm_test_func$' "$nlist" >/dev/null; then - cat <<_LT_EOF > conftest.$ac_ext -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE -/* DATA imports from DLLs on WIN32 can't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT@&t@_DLSYM_CONST -#elif defined __osf__ -/* This system does not cope well with relocations in const data. */ -# define LT@&t@_DLSYM_CONST -#else -# define LT@&t@_DLSYM_CONST const -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -_LT_EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' - - cat <<_LT_EOF >> conftest.$ac_ext - -/* The mapping between symbol names and symbols. */ -LT@&t@_DLSYM_CONST struct { - const char *name; - void *address; -} -lt__PROGRAM__LTX_preloaded_symbols[] = -{ - { "@PROGRAM@", (void *) 0 }, -_LT_EOF - $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext - cat <<\_LT_EOF >> conftest.$ac_ext - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt__PROGRAM__LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif -_LT_EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_globsym_save_LIBS=$LIBS - lt_globsym_save_CFLAGS=$CFLAGS - LIBS=conftstm.$ac_objext - CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest$ac_exeext; then - pipe_works=yes - fi - LIBS=$lt_globsym_save_LIBS - CFLAGS=$lt_globsym_save_CFLAGS - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - fi - rm -rf conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test yes = "$pipe_works"; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done - ;; -esac -fi - -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -printf '%s\n' "failed" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ok" >&5 -printf '%s\n' "ok" >&6; } -fi - -# Response file support. -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - nm_file_list_spec='@' -elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then - nm_file_list_spec='@' -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 -printf %s "checking for sysroot... " >&6; } - -@%:@ Check whether --with-sysroot was given. -if test ${with_sysroot+y} -then : - withval=$with_sysroot; -else case e in @%:@( - e) with_sysroot=no ;; -esac -fi - - -lt_sysroot= -case $with_sysroot in #( - yes) - if test yes = "$GCC"; then - # Trim trailing / since we'll always append absolute paths and we want - # to avoid //, if only for less confusing output for the user. - lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 -printf '%s\n' "$with_sysroot" >&6; } - as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 - ;; -esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 -printf '%s\n' "${lt_sysroot:-no}" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 -printf %s "checking for a working dd... " >&6; } -if test ${ac_cv_path_lt_DD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -: ${lt_DD:=$DD} -if test -z "$lt_DD"; then - ac_path_lt_DD_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in dd - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_lt_DD" || continue -if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: -fi - $ac_path_lt_DD_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_lt_DD"; then - : - fi -else - ac_cv_path_lt_DD=$lt_DD -fi - -rm -f conftest.i conftest2.i conftest.out ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 -printf '%s\n' "$ac_cv_path_lt_DD" >&6; } - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 -printf %s "checking how to truncate binary pipes... " >&6; } -if test ${lt_cv_truncate_bin+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -lt_cv_truncate_bin= -if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" -fi -rm -f conftest.i conftest2.i conftest.out -test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 -printf '%s\n' "$lt_cv_truncate_bin" >&6; } - - - - - - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in @S|@*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - -@%:@ Check whether --enable-libtool-lock was given. -if test ${enable_libtool_lock+y} -then : - enableval=$enable_libtool_lock; -fi - -test no = "$enable_libtool_lock" || enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out what ABI is being produced by ac_compile, and set mode - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE=32 - ;; - *ELF-64*) - HPUX_IA64_MODE=64 - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - if test yes = "$lt_cv_prog_gnu_ld"; then - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -mips64*-*linux*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - emul=elf - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - emul="${emul}32" - ;; - *64-bit*) - emul="${emul}64" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *MSB*) - emul="${emul}btsmip" - ;; - *LSB*) - emul="${emul}ltsmip" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *N32*) - emul="${emul}n32" - ;; - esac - LD="${LD-ld} -m $emul" - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. Note that the listed cases only cover the - # situations where additional linker options are needed (such as when - # doing 32-bit compilation for a host where ld defaults to 64-bit, or - # vice versa); the common cases where no linker options are needed do - # not appear in the list. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - case `$FILECMD conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac - ;; - powerpc64le-*linux*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - LD="${LD-ld} -m elf_x86_64" - ;; - powerpcle-*linux*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -belf" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 -printf %s "checking whether the C compiler needs -belf... " >&6; } -if test ${lt_cv_cc_needs_belf+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_cc_needs_belf=yes -else case e in @%:@( - e) lt_cv_cc_needs_belf=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 -printf '%s\n' "$lt_cv_cc_needs_belf" >&6; } - if test yes != "$lt_cv_cc_needs_belf"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS=$SAVE_CFLAGS - fi - ;; -*-*solaris*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) - case $host in - i?86-*-solaris*|x86_64-*-solaris*) - LD="${LD-ld} -m elf_x86_64" - ;; - sparc*-*-solaris*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - # GNU ld 2.21 introduced _sol2 emulations. Use them if available. - if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD=${LD-ld}_sol2 - fi - ;; - *) - if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then - LD="${LD-ld} -64" - fi - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; -esac - -need_locks=$enable_libtool_lock - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. -set dummy ${ac_tool_prefix}mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$MANIFEST_TOOL"; then - ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL -if test -n "$MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 -printf '%s\n' "$MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_MANIFEST_TOOL"; then - ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL - # Extract the first word of "mt", so it can be a program name with args. -set dummy mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_MANIFEST_TOOL"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL -if test -n "$ac_ct_MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 -printf '%s\n' "$ac_ct_MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_MANIFEST_TOOL" = x; then - MANIFEST_TOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL - fi -else - MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" -fi - -test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 -printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } -if test ${lt_cv_path_manifest_tool+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_path_manifest_tool=no - echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 - $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out - cat conftest.err >&5 - if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_manifest_tool=yes - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_manifest_tool" >&5 -printf '%s\n' "$lt_cv_path_manifest_tool" >&6; } -if test yes != "$lt_cv_path_manifest_tool"; then - MANIFEST_TOOL=: -fi - - - - - - - case $host_os in - rhapsody* | darwin*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. -set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DSYMUTIL"; then - ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DSYMUTIL=$ac_cv_prog_DSYMUTIL -if test -n "$DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 -printf '%s\n' "$DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DSYMUTIL"; then - ac_ct_DSYMUTIL=$DSYMUTIL - # Extract the first word of "dsymutil", so it can be a program name with args. -set dummy dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DSYMUTIL"; then - ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL -if test -n "$ac_ct_DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 -printf '%s\n' "$ac_ct_DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DSYMUTIL" = x; then - DSYMUTIL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DSYMUTIL=$ac_ct_DSYMUTIL - fi -else - DSYMUTIL="$ac_cv_prog_DSYMUTIL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. -set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$NMEDIT"; then - ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -NMEDIT=$ac_cv_prog_NMEDIT -if test -n "$NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 -printf '%s\n' "$NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_NMEDIT"; then - ac_ct_NMEDIT=$NMEDIT - # Extract the first word of "nmedit", so it can be a program name with args. -set dummy nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_NMEDIT"; then - ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_NMEDIT="nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT -if test -n "$ac_ct_NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 -printf '%s\n' "$ac_ct_NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_NMEDIT" = x; then - NMEDIT=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - NMEDIT=$ac_ct_NMEDIT - fi -else - NMEDIT="$ac_cv_prog_NMEDIT" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. -set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$LIPO"; then - ac_cv_prog_LIPO="$LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -LIPO=$ac_cv_prog_LIPO -if test -n "$LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 -printf '%s\n' "$LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LIPO"; then - ac_ct_LIPO=$LIPO - # Extract the first word of "lipo", so it can be a program name with args. -set dummy lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_LIPO"; then - ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_LIPO="lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO -if test -n "$ac_ct_LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 -printf '%s\n' "$ac_ct_LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_LIPO" = x; then - LIPO=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LIPO=$ac_ct_LIPO - fi -else - LIPO="$ac_cv_prog_LIPO" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -printf '%s\n' "$OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL="otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -printf '%s\n' "$ac_ct_OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OTOOL64"; then - ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL64=$ac_cv_prog_OTOOL64 -if test -n "$OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 -printf '%s\n' "$OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL64"; then - ac_ct_OTOOL64=$OTOOL64 - # Extract the first word of "otool64", so it can be a program name with args. -set dummy otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OTOOL64"; then - ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL64="otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 -if test -n "$ac_ct_OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 -printf '%s\n' "$ac_ct_OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL64" = x; then - OTOOL64=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL64=$ac_ct_OTOOL64 - fi -else - OTOOL64="$ac_cv_prog_OTOOL64" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 -printf %s "checking for -single_module linker flag... " >&6; } -if test ${lt_cv_apple_cc_single_mod+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_apple_cc_single_mod=no - if test -z "$LT_MULTI_MODULE"; then - # By default we will add the -single_module flag. You can override - # by either setting the environment variable LT_MULTI_MODULE - # non-empty at configure time, or by adding -multi_module to the - # link flags. - rm -rf libconftest.dylib* - echo "int foo(void){return 1;}" > conftest.c - echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ --dynamiclib -Wl,-single_module conftest.c" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ - -dynamiclib -Wl,-single_module conftest.c 2>conftest.err - _lt_result=$? - # If there is a non-empty error log, and "single_module" - # appears in it, assume the flag caused a linker warning - if test -s conftest.err && $GREP single_module conftest.err; then - cat conftest.err >&5 - # Otherwise, if the output was created with a 0 exit code from - # the compiler, it worked. - elif test -f libconftest.dylib && test 0 = "$_lt_result"; then - lt_cv_apple_cc_single_mod=yes - else - cat conftest.err >&5 - fi - rm -rf libconftest.dylib* - rm -f conftest.* - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 -printf '%s\n' "$lt_cv_apple_cc_single_mod" >&6; } - - # Feature test to disable chained fixups since it is not - # compatible with '-undefined dynamic_lookup' - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -no_fixup_chains linker flag" >&5 -printf %s "checking for -no_fixup_chains linker flag... " >&6; } -if test ${lt_cv_support_no_fixup_chains+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -Wl,-no_fixup_chains" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_support_no_fixup_chains=yes -else case e in @%:@( - e) lt_cv_support_no_fixup_chains=no - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_support_no_fixup_chains" >&5 -printf '%s\n' "$lt_cv_support_no_fixup_chains" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 -printf %s "checking for -exported_symbols_list linker flag... " >&6; } -if test ${lt_cv_ld_exported_symbols_list+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_exported_symbols_list=no - save_LDFLAGS=$LDFLAGS - echo "_main" > conftest.sym - LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_ld_exported_symbols_list=yes -else case e in @%:@( - e) lt_cv_ld_exported_symbols_list=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 -printf '%s\n' "$lt_cv_ld_exported_symbols_list" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 -printf %s "checking for -force_load linker flag... " >&6; } -if test ${lt_cv_ld_force_load+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5 - $AR $AR_FLAGS libconftest.a conftest.o 2>&5 - echo "$RANLIB libconftest.a" >&5 - $RANLIB libconftest.a 2>&5 - cat > conftest.c << _LT_EOF -int main(void) { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -s conftest.err && $GREP force_load conftest.err; then - cat conftest.err >&5 - elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&5 - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 -printf '%s\n' "$lt_cv_ld_force_load" >&6; } - case $host_os in - rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; - darwin1.*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - darwin*) - case $MACOSX_DEPLOYMENT_TARGET,$host in - 10.[012],*|,*powerpc*-darwin[5-8]*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - *) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' - if test yes = "$lt_cv_support_no_fixup_chains"; then - as_fn_append _lt_dar_allow_undefined ' $wl-no_fixup_chains' - fi - ;; - esac - ;; - esac - if test yes = "$lt_cv_apple_cc_single_mod"; then - _lt_dar_single_mod='$single_module' - fi - _lt_dar_needs_single_mod=no - case $host_os in - rhapsody* | darwin1.*) - _lt_dar_needs_single_mod=yes ;; - darwin*) - # When targeting Mac OS X 10.4 (darwin 8) or later, - # -single_module is the default and -multi_module is unsupported. - # The toolchain on macOS 10.14 (darwin 18) and later cannot - # target any OS version that needs -single_module. - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*-darwin[567].*|10.[0-3],*-darwin[5-9].*|10.[0-3],*-darwin1[0-7].*) - _lt_dar_needs_single_mod=yes ;; - esac - ;; - esac - if test yes = "$lt_cv_ld_exported_symbols_list"; then - _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' - else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' - fi - if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then - _lt_dsymutil='~$DSYMUTIL $lib || :' - else - _lt_dsymutil= - fi - ;; - esac - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x@S|@2 in - x) - ;; - *:) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" - ;; - x:*) - eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" - ;; - *) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - esac -} - -ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default -" -if test "x$ac_cv_header_dlfcn_h" = xyes -then : - printf '%s\n' "@%:@define HAVE_DLFCN_H 1" >>confdefs.h - -fi - - - - - -# Set options - - - - enable_dlopen=no - - - enable_win32_dll=no - - - @%:@ Check whether --enable-shared was given. -if test ${enable_shared+y} -then : - enableval=$enable_shared; p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_shared=yes ;; -esac -fi - - - - - - - - - - @%:@ Check whether --enable-static was given. -if test ${enable_static+y} -then : - enableval=$enable_static; p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_static=yes ;; -esac -fi - - - - - - - - - - @%:@ Check whether --enable-pic was given. -if test ${enable_pic+y} -then : - enableval=$enable_pic; lt_p=${PACKAGE-default} - case $enableval in - yes|no) pic_mode=$enableval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) @%:@ Check whether --with-pic was given. -if test ${with_pic+y} -then : - withval=$with_pic; lt_p=${PACKAGE-default} - case $withval in - yes|no) pic_mode=$withval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $withval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) pic_mode=default ;; -esac -fi - - ;; -esac -fi - - - - - - - - - @%:@ Check whether --enable-fast-install was given. -if test ${enable_fast_install+y} -then : - enableval=$enable_fast_install; p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_fast_install=yes ;; -esac -fi - - - - - - - - - shared_archive_member_spec= -case $host,$enable_shared in -power*-*-aix[5-9]*,yes) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 -printf %s "checking which variant of shared library versioning to provide... " >&6; } - @%:@ Check whether --enable-aix-soname was given. -if test ${enable_aix_soname+y} -then : - enableval=$enable_aix_soname; case $enableval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --enable-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$enable_aix_soname -else case e in @%:@( - e) @%:@ Check whether --with-aix-soname was given. -if test ${with_aix_soname+y} -then : - withval=$with_aix_soname; case $withval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$with_aix_soname -else case e in @%:@( - e) if test ${lt_cv_with_aix_soname+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_with_aix_soname=aix ;; -esac -fi - ;; -esac -fi - - enable_aix_soname=$lt_cv_with_aix_soname ;; -esac -fi - - with_aix_soname=$enable_aix_soname - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 -printf '%s\n' "$with_aix_soname" >&6; } - if test aix != "$with_aix_soname"; then - # For the AIX way of multilib, we name the shared archive member - # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', - # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. - # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, - # the AIX toolchain works better with OBJECT_MODE set (default 32). - if test 64 = "${OBJECT_MODE-32}"; then - shared_archive_member_spec=shr_64 - else - shared_archive_member_spec=shr - fi - fi - ;; -*) - with_aix_soname=aix - ;; -esac - - - - - - - - - - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS=$ltmain - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -test -z "$LN_S" && LN_S="ln -s" - - - - - - - - - - - - - - -if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 -printf %s "checking for objdir... " >&6; } -if test ${lt_cv_objdir+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 -printf '%s\n' "$lt_cv_objdir" >&6; } -objdir=$lt_cv_objdir - - - - - -printf '%s\n' "@%:@define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h - - - - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Global variables: -ofile=libtool -can_build_shared=yes - -# All known linkers require a '.a' archive for static linking (except MSVC and -# ICC, which need '.lib'). -libext=a - -with_gnu_ld=$lt_cv_prog_gnu_ld - -old_CC=$CC -old_CFLAGS=$CFLAGS - -# Set sane defaults for various variables -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$LD" && LD=ld -test -z "$ac_objext" && ac_objext=o - -func_cc_basename $compiler -cc_basename=$func_cc_basename_result - - -# Only perform the check for file, if the check method requires it -test -z "$MAGIC_CMD" && MAGIC_CMD=file -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 -printf %s "checking for ${ac_tool_prefix}file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/${ac_tool_prefix}file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for file" >&5 -printf %s "checking for file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - else - MAGIC_CMD=: - fi -fi - - fi - ;; -esac - -# Use C for the default configuration in the libtool script - -lt_save_CC=$CC -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -objext=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(void){return(0);}' - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - -# Save the default compiler, since it gets overwritten when the other -# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. -compiler_DEFAULT=$CC - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - -lt_prog_compiler_no_builtin_flag= - -if test yes = "$GCC"; then - case $cc_basename in - nvcc*) - lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; - *) - lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; - esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if test ${lt_cv_prog_compiler_rtti_exceptions+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -printf '%s\n' "$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then - lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" -else - : -fi - -fi - - - - - - - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - - - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - -hard_links=nottested -if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then - # do not overwrite the value of need_locks provided by the user - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -printf %s "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -printf '%s\n' "$hard_links" >&6; } - if test no = "$hard_links"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 -printf '%s\n' "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - runpath_var= - allow_undefined_flag= - always_export_symbols=no - archive_cmds= - archive_expsym_cmds= - compiler_needs_object=no - enable_shared_with_static_runtimes=no - export_dynamic_flag_spec= - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - hardcode_automatic=no - hardcode_direct=no - hardcode_direct_absolute=no - hardcode_libdir_flag_spec= - hardcode_libdir_separator= - hardcode_minus_L=no - hardcode_shlibpath_var=unsupported - inherit_rpath=no - link_all_deplibs=unknown - module_cmds= - module_expsym_cmds= - old_archive_from_new_cmds= - old_archive_from_expsyms_cmds= - thread_safe_flag_spec= - whole_archive_flag_spec= - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ' (' and ')$', so one must not match beginning or - # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', - # as well as any symbol that contains 'd'. - exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - # Exclude shared library initialization/finalization symbols. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - if test yes != "$GCC"; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) - with_gnu_ld=yes - ;; - esac - - ld_shlibs=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test yes = "$with_gnu_ld"; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; - *\ \(GNU\ Binutils\)\ [3-9]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test yes = "$lt_use_gnu_ld_interface"; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='$wl' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='$wl--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' - else - whole_archive_flag_spec= - fi - supports_anon_versioning=no - case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test ia64 != "$host_cpu"; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.19, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. - -_LT_EOF - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='$wl--export-all-symbols' - allow_undefined_flag=unsupported - always_export_symbols=no - enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' - file_list_spec='@' - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file, use it as - # is; otherwise, prepend EXPORTS... - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs=no - fi - ;; - - haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - link_all_deplibs=no - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - interix[3-9]*) - hardcode_direct=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) - tmp_diet=no - if test linux-dietlibc = "$host_os"; then - case $cc_basename in - diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) - esac - fi - if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test no = "$tmp_diet" - then - tmp_addflag=' $pic_flag' - tmp_sharedflag='-shared' - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - lf95*) # Lahey Fortran 8.1 - whole_archive_flag_spec= - tmp_sharedflag='--shared' ;; - nagfor*) # NAGFOR 5.3 - tmp_sharedflag='-Wl,-shared' ;; - xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) - tmp_sharedflag='-qmkshrobj' - tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - ;; - esac - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' - fi - - case $cc_basename in - tcc*) - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='-rdynamic' - ;; - xlf* | bgf* | bgxlf* | mpixlf*) - # IBM XL Fortran 10.1 on PPC cannot create shared libs itself - whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' - fi - ;; - esac - else - ld_shlibs=no - fi - ;; - - *-mlibc) - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test no = "$ld_shlibs"; then - runpath_var= - hardcode_libdir_flag_spec= - export_dynamic_flag_spec= - whole_archive_flag_spec= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix[4-9]*) - if test ia64 = "$host_cpu"; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag= - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to GNU nm, but means don't demangle to AIX nm. - # Without the "-l" option, or with the "-B" option, AIX nm treats - # weak defined symbols like other global defined symbols, whereas - # GNU nm marks them as "W". - # While the 'weak' keyword is ignored in the Export File, we need - # it in the Import File for the 'aix-soname' feature, so we have - # to replace the "-B" option with "-P" for AIX nm. - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # have runtime linking enabled, and use it for executables. - # For shared libraries, we enable/disable runtime linking - # depending on the kind of the shared library created - - # when "with_aix_soname,aix_use_runtimelinking" is: - # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables - # "aix,yes" lib.so shared, rtl:yes, for executables - # lib.a static archive - # "both,no" lib.so.V(shr.o) shared, rtl:yes - # lib.a(lib.so.V) shared, rtl:no, for executables - # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a(lib.so.V) shared, rtl:no - # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a static archive - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then - aix_use_runtimelinking=yes - break - fi - done - if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then - # With aix-soname=svr4, we create the lib.so.V shared archives only, - # so we don't have lib.a shared libs to link our executables. - # We have to force runtime linking in this case. - aix_use_runtimelinking=yes - LDFLAGS="$LDFLAGS -Wl,-brtl" - fi - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds='' - hardcode_direct=yes - hardcode_direct_absolute=yes - hardcode_libdir_separator=':' - link_all_deplibs=yes - file_list_spec='$wl-f,' - case $with_aix_soname,$aix_use_runtimelinking in - aix,*) ;; # traditional, no import file - svr4,* | *,yes) # use import file - # The Import File defines what to hardcode. - hardcode_direct=no - hardcode_direct_absolute=no - ;; - esac - - if test yes = "$GCC"; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`$CC -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - shared_flag='-shared' - if test yes = "$aix_use_runtimelinking"; then - shared_flag="$shared_flag "'$wl-G' - fi - # Need to ensure runtime linking is disabled for the traditional - # shared library, or the linker may eventually find shared libraries - # /with/ Import File - we do not want to mix them. - shared_flag_aix='-shared' - shared_flag_svr4='-shared $wl-G' - else - # not using gcc - if test ia64 = "$host_cpu"; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test yes = "$aix_use_runtimelinking"; then - shared_flag='$wl-G' - else - shared_flag='$wl-bM:SRE' - fi - shared_flag_aix='$wl-bM:SRE' - shared_flag_svr4='$wl-G' - fi - fi - - export_dynamic_flag_spec='$wl-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols=yes - if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag='-berok' - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag - else - if test ia64 = "$host_cpu"; then - hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' - allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag=' $wl-bernotok' - allow_undefined_flag=' $wl-berok' - if test yes = "$with_gnu_ld"; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - fi - archive_cmds_need_lc=yes - archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' - # -brtl affects multiple linker settings, -berok does not and is overridden later - compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' - if test svr4 != "$with_aix_soname"; then - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' - fi - if test aix != "$with_aix_soname"; then - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' - else - # used by -dlpreopen to get the symbols - archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' - fi - archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' - fi - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - bsdi[45]*) - export_dynamic_flag_spec=-rdynamic - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - case $cc_basename in - cl* | icl*) - # Native MSVC or ICC - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - always_export_symbols=yes - file_list_spec='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -Fe$output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp "$export_symbols" "$output_objdir/$soname.def"; - echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; - else - $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -Fe$tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, )='true' - enable_shared_with_static_runtimes=yes - exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - # Don't use ranlib - old_postinstall_cmds='chmod 644 $oldlib' - postlink_cmds='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile=$lt_outputfile.exe - lt_tool_outputfile=$lt_tool_outputfile.exe - ;; - esac~ - if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # Assume MSVC and ICC wrapper - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - enable_shared_with_static_runtimes=yes - ;; - esac - ;; - - darwin* | rhapsody*) - - - archive_cmds_need_lc=no - hardcode_direct=no - hardcode_automatic=yes - hardcode_shlibpath_var=unsupported - if test yes = "$lt_cv_ld_force_load"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec='' - fi - link_all_deplibs=yes - allow_undefined_flag=$_lt_dar_allow_undefined - case $cc_basename in - ifort*|nagfor*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test yes = "$_lt_dar_can_shared"; then - output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" - archive_expsym_cmds="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" - module_expsym_cmds="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" - - else - ld_shlibs=no - fi - - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly* | midnightbsd*) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9*) - if test yes = "$GCC"; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - export_dynamic_flag_spec='$wl-E' - ;; - - hpux10*) - if test yes,no = "$GCC,$with_gnu_ld"; then - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - - hpux11*) - if test yes,no = "$GCC,$with_gnu_ld"; then - case $host_cpu in - hppa*64*) - archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 -printf %s "checking if $CC understands -b... " >&6; } -if test ${lt_cv_prog_compiler__b+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler__b=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -b" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler__b=yes - fi - else - lt_cv_prog_compiler__b=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 -printf '%s\n' "$lt_cv_prog_compiler__b" >&6; } - -if test yes = "$lt_cv_prog_compiler__b"; then - archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' -else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' -fi - - ;; - esac - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - hardcode_shlibpath_var=no - ;; - *) - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test yes = "$GCC"; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - # Try to use the -exported_symbol ld option, if it does not - # work, assume that -exports_file does not work either and - # implicitly export all symbols. - # This should be the same for all languages, so no per-tag cache variable. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 -printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } -if test ${lt_cv_irix_exported_symbol+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int foo (void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_irix_exported_symbol=yes -else case e in @%:@( - e) lt_cv_irix_exported_symbol=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 -printf '%s\n' "$lt_cv_irix_exported_symbol" >&6; } - if test yes = "$lt_cv_irix_exported_symbol"; then - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' - fi - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - inherit_rpath=yes - link_all_deplibs=yes - ;; - - linux*) - case $cc_basename in - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - ld_shlibs=yes - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - esac - ;; - - *-mlibc) - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - newsos6) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - hardcode_shlibpath_var=no - ;; - - *nto* | *qnx*) - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - hardcode_shlibpath_var=no - hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - else - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - fi - else - ld_shlibs=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - osf3*) - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - archive_cmds_need_lc='no' - hardcode_libdir_separator=: - ;; - - serenity*) - ;; - - solaris*) - no_undefined_flag=' -z defs' - if test yes = "$GCC"; then - wlarc='$wl' - archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - else - case `$CC -V 2>&1` in - *"Compilers 5.0"*) - wlarc='' - archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' - ;; - *) - wlarc='$wl' - archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - ;; - esac - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands '-z linker_flag'. GCC discards it without '$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test yes = "$GCC"; then - whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' - else - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs=yes - ;; - - sunos4*) - if test sequent = "$host_vendor"; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds='$CC -r -o $output$reload_objs' - hardcode_direct=no - ;; - motorola) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='$wl-z,text' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We CANNOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag='$wl-z,text' - allow_undefined_flag='$wl-z,nodefs' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-R,$libdir' - hardcode_libdir_separator=':' - link_all_deplibs=yes - export_dynamic_flag_spec='$wl-Bexport' - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - *) - ld_shlibs=no - ;; - esac - - if test sni = "$host_vendor"; then - case $host in - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='$wl-Blargedynsym' - ;; - esac - fi - fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 -printf '%s\n' "$ld_shlibs" >&6; } -test no = "$ld_shlibs" && can_build_shared=no - -with_gnu_ld=$with_gnu_ld - - - - - - - - - - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc=yes - - if test yes,yes = "$GCC,$enable_shared"; then - case $archive_cmds in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -printf %s "checking whether -lc should be explicitly linked in... " >&6; } -if test ${lt_cv_archive_cmds_need_lc+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc=no - else - lt_cv_archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 -printf '%s\n' "$lt_cv_archive_cmds_need_lc" >&6; } - archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -printf %s "checking dynamic linker characteristics... " >&6; } - -if test yes = "$GCC"; then - case $host_os in - darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; - *) lt_awk_arg='/^libraries:/' ;; - esac - case $host_os in - mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; - *) lt_sed_strip_eq='s|=/|/|g' ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary... - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - # ...but if some path component already ends with the multilib dir we assume - # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). - case "$lt_multi_os_dir; $lt_search_path_spec " in - "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) - lt_multi_os_dir= - ;; - esac - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" - elif test -n "$lt_multi_os_dir"; then - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS = " "; FS = "/|\n";} { - lt_foo = ""; - lt_count = 0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo = "/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[lt_foo]++; } - if (lt_freq[lt_foo] == 1) { print lt_foo; } -}'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's|/\([A-Za-z]:\)|\1|g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=.so -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - - - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='$libname$release$shared_ext$major' - ;; - -aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test ia64 = "$host_cpu"; then - # AIX 5 supports IA64 - library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line '#! .'. This would cause the generated library to - # depend on '.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # Using Import Files as archive members, it is possible to support - # filename-based versioning of shared library archives on AIX. While - # this would work for both with and without runtime linking, it will - # prevent static linking of such archives. So we do filename-based - # shared library versioning with .so extension only, which is used - # when both runtime linking and shared linking is enabled. - # Unfortunately, runtime linking may impact performance, so we do - # not want this to be the default eventually. Also, we use the - # versioned .so libs for executables only if there is the -brtl - # linker flag in LDFLAGS as well, or --enable-aix-soname=svr4 only. - # To allow for filename-based versioning support, we need to create - # libNAME.so.V as an archive file, containing: - # *) an Import File, referring to the versioned filename of the - # archive as well as the shared archive member, telling the - # bitwidth (32 or 64) of that shared object, and providing the - # list of exported symbols of that shared object, eventually - # decorated with the 'weak' keyword - # *) the shared object with the F_LOADONLY flag set, to really avoid - # it being seen by the linker. - # At run time we better use the real file rather than another symlink, - # but for link time we create the symlink libNAME.so -> libNAME.so.V - - case $with_aix_soname,$aix_use_runtimelinking in - # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - aix,yes) # traditional libtool - dynamic_linker='AIX unversionable lib.so' - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - aix,no) # traditional AIX only - dynamic_linker='AIX lib.a(lib.so.V)' - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - ;; - svr4,*) # full svr4 only - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,yes) # both, prefer svr4 - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # unpreferred sharedlib libNAME.a needs extra handling - postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' - postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,no) # both, prefer aix - dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling - postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' - postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' - ;; - esac - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='$libname$shared_ext' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | windows* | pw32* | cegcc*) - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - # If user builds GCC with multilib enabled, - # it should just install on $(libdir) - # not on $(libdir)/../bin or 32 bits dlls would override 64 bit ones. - if test xyes = x"$multilib"; then - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - $install_prog $dir/$dlname $destdir/$dlname~ - chmod a+x $destdir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib $destdir/$dlname'\'' || exit \$?; - fi' - else - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - fi - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" - ;; - mingw* | windows* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl* | *,icl*) - # Native MSVC or ICC - libname_spec='$name' - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - library_names_spec='$libname.dll.lib' - - case $build_os in - mingw* | windows*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec=$LIB - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC and ICC wrapper - library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' - soname_spec='$libname$release$major$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly* | midnightbsd*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - need_version=yes - ;; - esac - case $host_cpu in - powerpc64) - # On FreeBSD bi-arch platforms, a different variable is used for 32-bit - # binaries. See . - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int test_pointer_size[sizeof (void *) - 5]; - -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - shlibpath_var=LD_LIBRARY_PATH -else case e in @%:@( - e) shlibpath_var=LD_32_LIBRARY_PATH ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; - *) - shlibpath_var=LD_LIBRARY_PATH - ;; - esac - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/boot/system/non-packaged/develop/lib /boot/system/develop/lib' - sys_lib_dlsearch_path_spec='/boot/home/config/non-packaged/lib /boot/home/config/lib /boot/system/non-packaged/lib /boot/system/lib' - hardcode_into_libs=no - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - if test 32 = "$HPUX_IA64_MODE"; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - sys_lib_dlsearch_path_spec=/usr/lib/hpux32 - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - sys_lib_dlsearch_path_spec=/usr/lib/hpux64 - fi - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test yes = "$lt_cv_prog_gnu_ld"; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" - sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -linux*android*) - version_type=none # Android doesn't support versioned libraries. - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - dynamic_linker='Android linker' - # -rpath works at least for libraries that are not overridden by - # libraries installed in system locations. - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if test ${lt_cv_shlibpath_overrides_runpath+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null -then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - ;; -esac -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Ideally, we could use ldconfig to report *all* directories which are - # searched for libraries, however this is still not possible. Aside from not - # being certain /sbin/ldconfig is available, command - # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, - # even though it is searched at run-time. Try to do the best guess by - # appending ld.so.conf contents (and includes) to the search path. - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -*-mlibc) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='mlibc ld.so' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec=/usr/lib - need_lib_prefix=no - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - need_version=no - else - need_version=yes - fi - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -os2*) - libname_spec='$name' - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - # OS/2 can only load a DLL with a base name of 8 characters or less. - soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; - v=$($ECHO $release$versuffix | tr -d .-); - n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); - $ECHO $n$v`$shared_ext' - library_names_spec='${libname}_dll.$libext' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=BEGINLIBPATH - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - -rdos*) - dynamic_linker=no - ;; - -serenity*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - dynamic_linker='SerenityOS LibELF' - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test yes = "$with_gnu_ld"; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec; then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' - soname_spec='$libname$shared_ext.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=sco - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test yes = "$with_gnu_ld"; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -emscripten*) - version_type=none - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - dynamic_linker="Emscripten linker" - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - -='-fPIC' - archive_cmds='$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib -s EXPORTED_FUNCTIONS=@$output_objdir/$soname.expsym' - archive_cmds_need_lc=no - no_undefined_flag= - ;; - -*) - dynamic_linker=no - ;; -esac -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -printf '%s\n' "$dynamic_linker" >&6; } -test no = "$dynamic_linker" && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test yes = "$GCC"; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then - sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec -fi - -if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then - sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec -fi - -# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... -configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec - -# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code -func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" - -# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool -configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -printf %s "checking how to hardcode library paths into programs... " >&6; } -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || - test -n "$runpath_var" || - test yes = "$hardcode_automatic"; then - - # We can hardcode non-existent directories. - if test no != "$hardcode_direct" && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && - test no != "$hardcode_minus_L"; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 -printf '%s\n' "$hardcode_action" >&6; } - -if test relink = "$hardcode_action" || - test yes = "$inherit_rpath"; then - # Fast installation is not supported - enable_fast_install=no -elif test yes = "$shlibpath_overrides_runpath" || - test no = "$enable_shared"; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - if test yes != "$enable_dlopen"; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen=load_add_on - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | windows* | pw32* | cegcc*) - lt_cv_dlopen=LoadLibrary - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in @%:@( - e) - lt_cv_dlopen=dyld - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; -esac -fi - - ;; - - tpf*) - # Don't try to run any link tests for TPF. We know it's impossible - # because TPF is a cross-compiler, and we know how we open DSOs. - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - lt_cv_dlopen_self=no - ;; - - *) - ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" -if test "x$ac_cv_func_shl_load" = xyes -then : - lt_cv_dlopen=shl_load -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 -printf %s "checking for shl_load in -ldld... " >&6; } -if test ${ac_cv_lib_dld_shl_load+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (void); -int -main (void) -{ -return shl_load (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_shl_load=yes -else case e in @%:@( - e) ac_cv_lib_dld_shl_load=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 -printf '%s\n' "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes -then : - lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld -else case e in @%:@( - e) ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes -then : - lt_cv_dlopen=dlopen -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 -printf %s "checking for dlopen in -lsvld... " >&6; } -if test ${ac_cv_lib_svld_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_svld_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_svld_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_svld_dlopen" >&6; } -if test "x$ac_cv_lib_svld_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 -printf %s "checking for dld_link in -ldld... " >&6; } -if test ${ac_cv_lib_dld_dld_link+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (void); -int -main (void) -{ -return dld_link (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_dld_link=yes -else case e in @%:@( - e) ac_cv_lib_dld_dld_link=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 -printf '%s\n' "$ac_cv_lib_dld_dld_link" >&6; } -if test "x$ac_cv_lib_dld_dld_link" = xyes -then : - lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; - esac - - if test no = "$lt_cv_dlopen"; then - enable_dlopen=no - else - enable_dlopen=yes - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS=$CPPFLAGS - test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS=$LDFLAGS - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS=$LIBS - LIBS="$lt_cv_dlopen_libs $LIBS" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 -printf %s "checking whether a program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 -printf '%s\n' "$lt_cv_dlopen_self" >&6; } - - if test yes = "$lt_cv_dlopen_self"; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 -printf %s "checking whether a statically linked program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self_static+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self_static=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self_static=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 -printf '%s\n' "$lt_cv_dlopen_self_static" >&6; } - fi - - CPPFLAGS=$save_CPPFLAGS - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - - - - - - - - - - - - - - - - - -striplib= -old_striplib= -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 -printf %s "checking whether stripping libraries is possible... " >&6; } -if test -z "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -else - if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - case $host_os in - darwin*) - # FIXME - insert some real tests, host_os isn't really good enough - striplib="$STRIP -x" - old_striplib="$STRIP -S" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - ;; - freebsd*) - if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - fi - ;; - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - ;; - esac - fi -fi - - - - - - - - - - - - - # Report what library types will actually be built - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 -printf %s "checking if libtool supports shared libraries... " >&6; } - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 -printf '%s\n' "$can_build_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 -printf %s "checking whether to build shared libraries... " >&6; } - test no = "$can_build_shared" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test yes = "$enable_shared" && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - - aix[4-9]*) - if test ia64 != "$host_cpu"; then - case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in - yes,aix,yes) ;; # shared object as lib.so file only - yes,svr4,*) ;; # shared object as lib.so archive member only - yes,*) enable_static=no ;; # shared object in lib.a archive as well - esac - fi - ;; - esac - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 -printf '%s\n' "$enable_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 -printf %s "checking whether to build static libraries... " >&6; } - # Make sure either enable_shared or enable_static is yes. - test yes = "$enable_shared" || enable_static=yes - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 -printf '%s\n' "$enable_static" >&6; } - - - - -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC=$lt_save_CC - - - - - - - - - - - - - - - - ac_config_commands="$ac_config_commands libtool" - - - - -# Only expand once: - - - -# Require xorg-macros minimum of 1.12 for DocBook external references - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to detect undeclared functions" >&5 -printf %s "checking for $CC options to detect undeclared functions... " >&6; } -if test ${ac_cv_c_undeclared_builtin_options+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_save_CFLAGS=$CFLAGS - ac_cv_c_undeclared_builtin_options='cannot detect' - for ac_arg in '' -fno-builtin; do - CFLAGS="$ac_save_CFLAGS $ac_arg" - # This test program should *not* compile successfully. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -(void) strchr; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) # This test program should compile successfully. - # No library function is consistently available on - # freestanding implementations, so test against a dummy - # declaration. Include always-available headers on the - # off chance that they somehow elicit warnings. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include -extern void ac_decl (int, char *); - -int -main (void) -{ -(void) ac_decl (0, (char *) 0); - (void) ac_decl; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - if test x"$ac_arg" = x -then : - ac_cv_c_undeclared_builtin_options='none needed' -else case e in @%:@( - e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; -esac -fi - break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - done - CFLAGS=$ac_save_CFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 -printf '%s\n' "$ac_cv_c_undeclared_builtin_options" >&6; } - case $ac_cv_c_undeclared_builtin_options in @%:@( - 'cannot detect') : - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot make $CC report undeclared builtins -See 'config.log' for more details" "$LINENO" 5; } ;; @%:@( - 'none needed') : - ac_c_undeclared_builtin_options='' ;; @%:@( - *) : - ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to ignore future-version functions" >&5 -printf %s "checking for $CC options to ignore future-version functions... " >&6; } -if test ${ac_cv_c_future_darwin_options+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_compile_saved="$ac_compile" - ac_compile="$ac_compile -Werror=unguarded-availability-new" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if ! (defined __APPLE__ && defined __MACH__) - #error "-Werror=unguarded-availability-new not needed here" - #endif - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_future_darwin_options='-Werror=unguarded-availability-new' -else case e in @%:@( - e) ac_cv_c_future_darwin_options='none needed' ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_compile="$ac_compile_saved" - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_future_darwin_options" >&5 -printf '%s\n' "$ac_cv_c_future_darwin_options" >&6; } - case $ac_cv_c_future_darwin_options in @%:@( - 'none needed') : - ac_c_future_darwin_options='' ;; @%:@( - *) : - ac_c_future_darwin_options=$ac_cv_c_future_darwin_options ;; -esac - - - - - -ac_fn_check_decl "$LINENO" "__clang__" "ac_cv_have_decl___clang__" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___clang__" = xyes -then : - CLANGCC="yes" -else case e in @%:@( - e) CLANGCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__INTEL_COMPILER" "ac_cv_have_decl___INTEL_COMPILER" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___INTEL_COMPILER" = xyes -then : - INTELCC="yes" -else case e in @%:@( - e) INTELCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__SUNPRO_C" "ac_cv_have_decl___SUNPRO_C" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___SUNPRO_C" = xyes -then : - SUNCC="yes" -else case e in @%:@( - e) SUNCC="no" ;; -esac -fi - - - - - - - - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. -set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -PKG_CONFIG=$ac_cv_path_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -printf '%s\n' "$PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_path_PKG_CONFIG"; then - ac_pt_PKG_CONFIG=$PKG_CONFIG - # Extract the first word of "pkg-config", so it can be a program name with args. -set dummy pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $ac_pt_PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG -if test -n "$ac_pt_PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 -printf '%s\n' "$ac_pt_PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_pt_PKG_CONFIG" = x; then - PKG_CONFIG="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - PKG_CONFIG=$ac_pt_PKG_CONFIG - fi -else - PKG_CONFIG="$ac_cv_path_PKG_CONFIG" -fi - -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=0.9.0 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 -printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - PKG_CONFIG="" - fi -fi - - - - - -@%:@ Check whether --enable-selective-werror was given. -if test ${enable_selective_werror+y} -then : - enableval=$enable_selective_werror; SELECTIVE_WERROR=$enableval -else case e in @%:@( - e) SELECTIVE_WERROR=yes ;; -esac -fi - - - - - -# -v is too short to test reliably with XORG_TESTSET_CFLAG -if test "x$SUNCC" = "xyes"; then - BASE_CFLAGS="-v" -else - BASE_CFLAGS="" -fi - -# This chunk of warnings were those that existed in the legacy CWARNFLAGS - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wall" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wall" >&5 -printf %s "checking if $CC supports -Wall... " >&6; } - cacheid=xorg_cv_cc_flag__Wall - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wall" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-arith" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-arith" >&5 -printf %s "checking if $CC supports -Wpointer-arith... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_arith - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-arith" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-declarations" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-declarations" >&5 -printf %s "checking if $CC supports -Wmissing-declarations... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_declarations - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-declarations" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat=2" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat=2" >&5 -printf %s "checking if $CC supports -Wformat=2... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat_2 - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat=2" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat" >&5 -printf %s "checking if $CC supports -Wformat... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat" - found="yes" - fi - fi - - - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wstrict-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wstrict-prototypes" >&5 -printf %s "checking if $CC supports -Wstrict-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wstrict_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wstrict-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-prototypes" >&5 -printf %s "checking if $CC supports -Wmissing-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnested-externs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnested-externs" >&5 -printf %s "checking if $CC supports -Wnested-externs... " >&6; } - cacheid=xorg_cv_cc_flag__Wnested_externs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnested-externs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wbad-function-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wbad-function-cast" >&5 -printf %s "checking if $CC supports -Wbad-function-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wbad_function_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wbad-function-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wold-style-definition" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wold-style-definition" >&5 -printf %s "checking if $CC supports -Wold-style-definition... " >&6; } - cacheid=xorg_cv_cc_flag__Wold_style_definition - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wold-style-definition" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -fd" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -fd" >&5 -printf %s "checking if $CC supports -fd... " >&6; } - cacheid=xorg_cv_cc_flag__fd - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -fd" - found="yes" - fi - fi - - - - - -# This chunk adds additional warnings that could catch undesired effects. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wunused" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wunused" >&5 -printf %s "checking if $CC supports -Wunused... " >&6; } - cacheid=xorg_cv_cc_flag__Wunused - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wunused" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wuninitialized" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wuninitialized" >&5 -printf %s "checking if $CC supports -Wuninitialized... " >&6; } - cacheid=xorg_cv_cc_flag__Wuninitialized - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wuninitialized" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wshadow" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wshadow" >&5 -printf %s "checking if $CC supports -Wshadow... " >&6; } - cacheid=xorg_cv_cc_flag__Wshadow - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wshadow" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-noreturn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-noreturn" >&5 -printf %s "checking if $CC supports -Wmissing-noreturn... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_noreturn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-noreturn" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-format-attribute" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-format-attribute" >&5 -printf %s "checking if $CC supports -Wmissing-format-attribute... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_format_attribute - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-format-attribute" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wredundant-decls" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wredundant-decls" >&5 -printf %s "checking if $CC supports -Wredundant-decls... " >&6; } - cacheid=xorg_cv_cc_flag__Wredundant_decls - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wredundant-decls" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wlogical-op" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wlogical-op" >&5 -printf %s "checking if $CC supports -Wlogical-op... " >&6; } - cacheid=xorg_cv_cc_flag__Wlogical_op - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wlogical-op" - found="yes" - fi - fi - - - -# These are currently disabled because they are noisy. They will be enabled -# in the future once the codebase is sufficiently modernized to silence -# them. For now, I don't want them to drown out the other warnings. -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wparentheses]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-align]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-qual]) - -# Turn some warnings into errors, so we don't accidentally get successful builds -# when there are problems that should be fixed. - -if test "x$SELECTIVE_WERROR" = "xyes" ; then - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=implicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=implicit" >&5 -printf %s "checking if $CC supports -Werror=implicit... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_implicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=implicit" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" >&5 -printf %s "checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_NO_EXPLICIT_TYPE_GIVEN__errwarn_E_NO_IMPLICIT_DECL_ALLOWED - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=nonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=nonnull" >&5 -printf %s "checking if $CC supports -Werror=nonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_nonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=nonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=init-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=init-self" >&5 -printf %s "checking if $CC supports -Werror=init-self... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_init_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=init-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=main" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=main" >&5 -printf %s "checking if $CC supports -Werror=main... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_main - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=main" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=missing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=missing-braces" >&5 -printf %s "checking if $CC supports -Werror=missing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_missing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=missing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=sequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=sequence-point" >&5 -printf %s "checking if $CC supports -Werror=sequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_sequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=sequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=return-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=return-type" >&5 -printf %s "checking if $CC supports -Werror=return-type... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_return_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=return-type" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT" >&5 -printf %s "checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_FUNC_HAS_NO_RETURN_STMT - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=trigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=trigraphs" >&5 -printf %s "checking if $CC supports -Werror=trigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_trigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=trigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=array-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=array-bounds" >&5 -printf %s "checking if $CC supports -Werror=array-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_array_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=array-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=write-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=write-strings" >&5 -printf %s "checking if $CC supports -Werror=write-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_write_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=write-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=address" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=address" >&5 -printf %s "checking if $CC supports -Werror=address... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_address - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=address" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=int-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=int-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Werror=int-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_int_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=int-to-pointer-cast" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION" >&5 -printf %s "checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_BAD_PTR_INT_COMBINATION - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=pointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=pointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Werror=pointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_pointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=pointer-to-int-cast" - found="yes" - fi - fi - - # Also -errwarn=E_BAD_PTR_INT_COMBINATION -else -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&5 -printf '%s\n' "$as_me: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&2;} - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wimplicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wimplicit" >&5 -printf %s "checking if $CC supports -Wimplicit... " >&6; } - cacheid=xorg_cv_cc_flag__Wimplicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wimplicit" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnonnull" >&5 -printf %s "checking if $CC supports -Wnonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Wnonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Winit-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Winit-self" >&5 -printf %s "checking if $CC supports -Winit-self... " >&6; } - cacheid=xorg_cv_cc_flag__Winit_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Winit-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmain" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmain" >&5 -printf %s "checking if $CC supports -Wmain... " >&6; } - cacheid=xorg_cv_cc_flag__Wmain - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmain" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-braces" >&5 -printf %s "checking if $CC supports -Wmissing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wsequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wsequence-point" >&5 -printf %s "checking if $CC supports -Wsequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Wsequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wsequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wreturn-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wreturn-type" >&5 -printf %s "checking if $CC supports -Wreturn-type... " >&6; } - cacheid=xorg_cv_cc_flag__Wreturn_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wreturn-type" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wtrigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wtrigraphs" >&5 -printf %s "checking if $CC supports -Wtrigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Wtrigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wtrigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Warray-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Warray-bounds" >&5 -printf %s "checking if $CC supports -Warray-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Warray_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Warray-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wwrite-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wwrite-strings" >&5 -printf %s "checking if $CC supports -Wwrite-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Wwrite_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wwrite-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Waddress" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Waddress" >&5 -printf %s "checking if $CC supports -Waddress... " >&6; } - cacheid=xorg_cv_cc_flag__Waddress - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Waddress" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wint-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wint-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Wint-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wint_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wint-to-pointer-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Wpointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-to-int-cast" - found="yes" - fi - fi - - -fi - - - - - - - - CWARNFLAGS="$BASE_CFLAGS" - if test "x$GCC" = xyes ; then - CWARNFLAGS="$CWARNFLAGS -fno-strict-aliasing" - fi - - - - - - - - -@%:@ Check whether --enable-strict-compilation was given. -if test ${enable_strict_compilation+y} -then : - enableval=$enable_strict_compilation; STRICT_COMPILE=$enableval -else case e in @%:@( - e) STRICT_COMPILE=no ;; -esac -fi - - - - - - -STRICT_CFLAGS="" - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -pedantic" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -pedantic" >&5 -printf %s "checking if $CC supports -pedantic... " >&6; } - cacheid=xorg_cv_cc_flag__pedantic - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -pedantic" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror" >&5 -printf %s "checking if $CC supports -Werror... " >&6; } - cacheid=xorg_cv_cc_flag__Werror - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn" >&5 -printf %s "checking if $CC supports -errwarn... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -errwarn" - found="yes" - fi - fi - - - -# Earlier versions of gcc (eg: 4.2) support -Werror=attributes, but do not -# activate it with -Werror, so we add it here explicitly. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=attributes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=attributes" >&5 -printf %s "checking if $CC supports -Werror=attributes... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_attributes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror=attributes" - found="yes" - fi - fi - - - -if test "x$STRICT_COMPILE" = "xyes"; then - BASE_CFLAGS="$BASE_CFLAGS $STRICT_CFLAGS" - CWARNFLAGS="$CWARNFLAGS $STRICT_CFLAGS" -fi - - - - - - - - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_VERSION_MAJOR `echo $PACKAGE_VERSION | cut -d . -f 1` -_ACEOF - - PVM=`echo $PACKAGE_VERSION | cut -d . -f 2 | cut -d - -f 1` - if test "x$PVM" = "x"; then - PVM="0" - fi - -printf '%s\n' "@%:@define PACKAGE_VERSION_MINOR $PVM" >>confdefs.h - - PVP=`echo $PACKAGE_VERSION | cut -d . -f 3 | cut -d - -f 1` - if test "x$PVP" = "x"; then - PVP="0" - fi - -printf '%s\n' "@%:@define PACKAGE_VERSION_PATCHLEVEL $PVP" >>confdefs.h - - - -CHANGELOG_CMD="((GIT_DIR=\$(top_srcdir)/.git git log > \$(top_srcdir)/.changelog.tmp) 2>/dev/null && \ -mv \$(top_srcdir)/.changelog.tmp \$(top_srcdir)/ChangeLog) \ -|| (rm -f \$(top_srcdir)/.changelog.tmp; test -e \$(top_srcdir)/ChangeLog || ( \ -touch \$(top_srcdir)/ChangeLog; \ -echo 'git failed to create ChangeLog: installing empty ChangeLog.' >&2))" - - - - -macros_datadir=`$PKG_CONFIG --print-errors --variable=pkgdatadir xorg-macros` -INSTALL_CMD="(cp -f "$macros_datadir/INSTALL" \$(top_srcdir)/.INSTALL.tmp && \ -mv \$(top_srcdir)/.INSTALL.tmp \$(top_srcdir)/INSTALL) \ -|| (rm -f \$(top_srcdir)/.INSTALL.tmp; test -e \$(top_srcdir)/INSTALL || ( \ -touch \$(top_srcdir)/INSTALL; \ -echo 'failed to copy INSTALL from util-macros: installing empty INSTALL.' >&2))" - - - - - - -case $host_os in - solaris*) - # Solaris 2.0 - 11.3 use SysV man page section numbers, so we - # check for a man page file found in later versions that use - # traditional section numbers instead - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for /usr/share/man/man7/attributes.7" >&5 -printf %s "checking for /usr/share/man/man7/attributes.7... " >&6; } -if test ${ac_cv_file__usr_share_man_man7_attributes_7+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) test "$cross_compiling" = yes && - as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 -if test -r "/usr/share/man/man7/attributes.7"; then - ac_cv_file__usr_share_man_man7_attributes_7=yes -else - ac_cv_file__usr_share_man_man7_attributes_7=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__usr_share_man_man7_attributes_7" >&5 -printf '%s\n' "$ac_cv_file__usr_share_man_man7_attributes_7" >&6; } -if test "x$ac_cv_file__usr_share_man_man7_attributes_7" = xyes -then : - SYSV_MAN_SECTIONS=false -else case e in @%:@( - e) SYSV_MAN_SECTIONS=true ;; -esac -fi - - ;; - *) SYSV_MAN_SECTIONS=false ;; -esac - -if test x$APP_MAN_SUFFIX = x ; then - APP_MAN_SUFFIX=1 -fi -if test x$APP_MAN_DIR = x ; then - APP_MAN_DIR='$(mandir)/man$(APP_MAN_SUFFIX)' -fi - -if test x$LIB_MAN_SUFFIX = x ; then - LIB_MAN_SUFFIX=3 -fi -if test x$LIB_MAN_DIR = x ; then - LIB_MAN_DIR='$(mandir)/man$(LIB_MAN_SUFFIX)' -fi - -if test x$FILE_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) FILE_MAN_SUFFIX=4 ;; - *) FILE_MAN_SUFFIX=5 ;; - esac -fi -if test x$FILE_MAN_DIR = x ; then - FILE_MAN_DIR='$(mandir)/man$(FILE_MAN_SUFFIX)' -fi - -if test x$MISC_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) MISC_MAN_SUFFIX=5 ;; - *) MISC_MAN_SUFFIX=7 ;; - esac -fi -if test x$MISC_MAN_DIR = x ; then - MISC_MAN_DIR='$(mandir)/man$(MISC_MAN_SUFFIX)' -fi - -if test x$DRIVER_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) DRIVER_MAN_SUFFIX=7 ;; - *) DRIVER_MAN_SUFFIX=4 ;; - esac -fi -if test x$DRIVER_MAN_DIR = x ; then - DRIVER_MAN_DIR='$(mandir)/man$(DRIVER_MAN_SUFFIX)' -fi - -if test x$ADMIN_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) ADMIN_MAN_SUFFIX=1m ;; - *) ADMIN_MAN_SUFFIX=8 ;; - esac -fi -if test x$ADMIN_MAN_DIR = x ; then - ADMIN_MAN_DIR='$(mandir)/man$(ADMIN_MAN_SUFFIX)' -fi - - - - - - - - - - - - - - - -XORG_MAN_PAGE="X Version 11" - -MAN_SUBSTS="\ - -e 's|__vendorversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xorgversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xservername__|Xorg|g' \ - -e 's|__xconfigfile__|xorg.conf|g' \ - -e 's|__projectroot__|\$(prefix)|g' \ - -e 's|__apploaddir__|\$(appdefaultdir)|g' \ - -e 's|__appmansuffix__|\$(APP_MAN_SUFFIX)|g' \ - -e 's|__drivermansuffix__|\$(DRIVER_MAN_SUFFIX)|g' \ - -e 's|__adminmansuffix__|\$(ADMIN_MAN_SUFFIX)|g' \ - -e 's|__libmansuffix__|\$(LIB_MAN_SUFFIX)|g' \ - -e 's|__miscmansuffix__|\$(MISC_MAN_SUFFIX)|g' \ - -e 's|__filemansuffix__|\$(FILE_MAN_SUFFIX)|g'" - - - - -AM_DEFAULT_VERBOSITY=0 - - - - - - -@%:@ Check whether --enable-specs was given. -if test ${enable_specs+y} -then : - enableval=$enable_specs; build_specs=$enableval -else case e in @%:@( - e) build_specs=yes ;; -esac -fi - - - if test x$build_specs = xyes; then - ENABLE_SPECS_TRUE= - ENABLE_SPECS_FALSE='#' -else - ENABLE_SPECS_TRUE='#' - ENABLE_SPECS_FALSE= -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build functional specifications" >&5 -printf %s "checking whether to build functional specifications... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $build_specs" >&5 -printf '%s\n' "$build_specs" >&6; } - - - - - -@%:@ Check whether --with-xmlto was given. -if test ${with_xmlto+y} -then : - withval=$with_xmlto; use_xmlto=$withval -else case e in @%:@( - e) use_xmlto=auto ;; -esac -fi - - - -if test "x$use_xmlto" = x"auto"; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto not found - documentation targets will be skipped" >&2;} - have_xmlto=no - else - have_xmlto=yes - fi -elif test "x$use_xmlto" = x"yes" ; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - as_fn_error $? "--with-xmlto=yes specified but xmlto not found in PATH" "$LINENO" 5 - fi - have_xmlto=yes -elif test "x$use_xmlto" = x"no" ; then - if test "x$XMLTO" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&2;} - fi - have_xmlto=no -else - as_fn_error $? "--with-xmlto expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of xmlto, if provided. -if test "$have_xmlto" = yes; then - # scrape the xmlto version - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the xmlto version" >&5 -printf %s "checking the xmlto version... " >&6; } - xmlto_version=`$XMLTO --version 2>/dev/null | cut -d' ' -f3` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xmlto_version" >&5 -printf '%s\n' "$xmlto_version" >&6; } - as_arg_v1=$xmlto_version -as_arg_v2=0.0.22 -awk "$as_awk_strverscmp" v1="$as_arg_v1" v2="$as_arg_v2" /dev/null -case $? in @%:@( - 1) : - if test "x$use_xmlto" = xauto; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&5 -printf '%s\n' "$as_me: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&2;} - have_xmlto=no - else - as_fn_error $? "xmlto version $xmlto_version found, but 0.0.22 needed" "$LINENO" 5 - fi ;; @%:@( - 0) : - ;; @%:@( - 2) : - ;; @%:@( - *) : - ;; -esac -fi - -# Test for the ability of xmlto to generate a text target -# -# NOTE: xmlto 0.0.27 or higher return a non-zero return code in the -# following test for empty XML docbook files. -# For compatibility reasons use the following empty XML docbook file and if -# it fails try it again with a non-empty XML file. -have_xmlto_text=no -cat > conftest.xml << "EOF" -EOF -if test "$have_xmlto" = yes -then : - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in @%:@( - e) # Try it again with a non-empty XML file. - cat > conftest.xml << "EOF" - -EOF - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto cannot generate text format, this format skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto cannot generate text format, this format skipped" >&2;} ;; -esac -fi ;; -esac -fi -fi -rm -f conftest.xml - if test $have_xmlto_text = yes; then - HAVE_XMLTO_TEXT_TRUE= - HAVE_XMLTO_TEXT_FALSE='#' -else - HAVE_XMLTO_TEXT_TRUE='#' - HAVE_XMLTO_TEXT_FALSE= -fi - - if test "$have_xmlto" = yes; then - HAVE_XMLTO_TRUE= - HAVE_XMLTO_FALSE='#' -else - HAVE_XMLTO_TRUE='#' - HAVE_XMLTO_FALSE= -fi - - - - - - -@%:@ Check whether --with-fop was given. -if test ${with_fop+y} -then : - withval=$with_fop; use_fop=$withval -else case e in @%:@( - e) use_fop=auto ;; -esac -fi - - - -if test "x$use_fop" = x"auto"; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: fop not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: fop not found - documentation targets will be skipped" >&2;} - have_fop=no - else - have_fop=yes - fi -elif test "x$use_fop" = x"yes" ; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - as_fn_error $? "--with-fop=yes specified but fop not found in PATH" "$LINENO" 5 - fi - have_fop=yes -elif test "x$use_fop" = x"no" ; then - if test "x$FOP" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&2;} - fi - have_fop=no -else - as_fn_error $? "--with-fop expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of fop, if provided. - - if test "$have_fop" = yes; then - HAVE_FOP_TRUE= - HAVE_FOP_FALSE='#' -else - HAVE_FOP_TRUE='#' - HAVE_FOP_FALSE= -fi - - - - -# Preserves the interface, should it be implemented later - - - -@%:@ Check whether --with-xsltproc was given. -if test ${with_xsltproc+y} -then : - withval=$with_xsltproc; use_xsltproc=$withval -else case e in @%:@( - e) use_xsltproc=auto ;; -esac -fi - - - -if test "x$use_xsltproc" = x"auto"; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xsltproc not found - cannot transform XML documents" >&5 -printf '%s\n' "$as_me: WARNING: xsltproc not found - cannot transform XML documents" >&2;} - have_xsltproc=no - else - have_xsltproc=yes - fi -elif test "x$use_xsltproc" = x"yes" ; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - as_fn_error $? "--with-xsltproc=yes specified but xsltproc not found in PATH" "$LINENO" 5 - fi - have_xsltproc=yes -elif test "x$use_xsltproc" = x"no" ; then - if test "x$XSLTPROC" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&2;} - fi - have_xsltproc=no -else - as_fn_error $? "--with-xsltproc expects 'yes' or 'no'" "$LINENO" 5 -fi - - if test "$have_xsltproc" = yes; then - HAVE_XSLTPROC_TRUE= - HAVE_XSLTPROC_FALSE='#' -else - HAVE_XSLTPROC_TRUE='#' - HAVE_XSLTPROC_FALSE= -fi - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for X.Org SGML entities >= 1.8" >&5 -printf %s "checking for X.Org SGML entities >= 1.8... " >&6; } -XORG_SGML_PATH= -if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xorg-sgml-doctools >= 1.8\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xorg-sgml-doctools >= 1.8") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools` -else - : - -fi - -# Define variables STYLESHEET_SRCDIR and XSL_STYLESHEET containing -# the path and the name of the doc stylesheet -if test "x$XORG_SGML_PATH" != "x" ; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XORG_SGML_PATH" >&5 -printf '%s\n' "$XORG_SGML_PATH" >&6; } - STYLESHEET_SRCDIR=$XORG_SGML_PATH/X11 - XSL_STYLESHEET=$STYLESHEET_SRCDIR/xorg.xsl -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - if test "x$XSL_STYLESHEET" != "x"; then - HAVE_STYLESHEETS_TRUE= - HAVE_STYLESHEETS_FALSE='#' -else - HAVE_STYLESHEETS_TRUE='#' - HAVE_STYLESHEETS_FALSE= -fi - - - -@%:@ Check whether --enable-malloc0returnsnull was given. -if test ${enable_malloc0returnsnull+y} -then : - enableval=$enable_malloc0returnsnull; MALLOC_ZERO_RETURNS_NULL=$enableval -else case e in @%:@( - e) MALLOC_ZERO_RETURNS_NULL=yes ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to act as if malloc(0) can return NULL" >&5 -printf %s "checking whether to act as if malloc(0) can return NULL... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MALLOC_ZERO_RETURNS_NULL" >&5 -printf '%s\n' "$MALLOC_ZERO_RETURNS_NULL" >&6; } - -if test "x$MALLOC_ZERO_RETURNS_NULL" = xyes; then - MALLOC_ZERO_CFLAGS="-DMALLOC_0_RETURNS_NULL" - XMALLOC_ZERO_CFLAGS=$MALLOC_ZERO_CFLAGS - XTMALLOC_ZERO_CFLAGS="$MALLOC_ZERO_CFLAGS -DXTMALLOC_BC" -else - MALLOC_ZERO_CFLAGS="" - XMALLOC_ZERO_CFLAGS="" - XTMALLOC_ZERO_CFLAGS="" -fi - - - - - - -# Determine .so library version per platform -# based on SharedXextRev in monolith xc/config/cf/*Lib.tmpl -if test "x$XEXT_SOREV" = "x" ; then - case $host_os in - openbsd*) XEXT_SOREV=8:0 ;; - solaris*) XEXT_SOREV=0 ;; - *) XEXT_SOREV=6:4:0 ;; - esac -fi - - -# Obtain compiler/linker options for dependencies - -pkg_failed=no -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" >&5 -printf %s "checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99... " >&6; } - -if test -n "$XEXT_CFLAGS"; then - pkg_cv_XEXT_CFLAGS="$XEXT_CFLAGS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_CFLAGS=`$PKG_CONFIG --cflags "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi -if test -n "$XEXT_LIBS"; then - pkg_cv_XEXT_LIBS="$XEXT_LIBS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_LIBS=`$PKG_CONFIG --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi - - - -if test $pkg_failed = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi - if test $_pkg_short_errors_supported = yes; then - XEXT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - else - XEXT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$XEXT_PKG_ERRORS" >&5 - - as_fn_error $? "Package requirements (xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99) were not met: - -$XEXT_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details." "$LINENO" 5 -elif test $pkg_failed = untried; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details. - -To get pkg-config, see . -See 'config.log' for more details" "$LINENO" 5; } -else - XEXT_CFLAGS=$pkg_cv_XEXT_CFLAGS - XEXT_LIBS=$pkg_cv_XEXT_LIBS - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - -fi - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for __builtin_popcountl" >&5 -printf %s "checking for __builtin_popcountl... " >&6; } -if test ${ax_cv_have___builtin_popcountl+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - __builtin_popcountl(0) - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ax_cv_have___builtin_popcountl=yes -else case e in @%:@( - e) ax_cv_have___builtin_popcountl=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have___builtin_popcountl" >&5 -printf '%s\n' "$ax_cv_have___builtin_popcountl" >&6; } - - if test yes = $ax_cv_have___builtin_popcountl -then : - -printf '%s\n' "@%:@define HAVE___BUILTIN_POPCOUNTL 1" >>confdefs.h - -fi - - - -ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" -if test "x$ac_cv_func_reallocarray" = xyes -then : - printf '%s\n' "@%:@define HAVE_REALLOCARRAY 1" >>confdefs.h - -else case e in @%:@( - e) case " $LIB@&t@OBJS " in - *" reallocarray.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS reallocarray.$ac_objext" - ;; -esac - ;; -esac -fi - - -# Allow checking code with lint, sparse, etc. - - - - - -@%:@ Check whether --with-lint was given. -if test ${with_lint+y} -then : - withval=$with_lint; use_lint=$withval -else case e in @%:@( - e) use_lint=no ;; -esac -fi - - -# Obtain platform specific info like program name and options -# The lint program on FreeBSD and NetBSD is different from the one on Solaris -case $host_os in - *linux* | *openbsd* | kfreebsd*-gnu | darwin* | cygwin*) - lint_name=splint - lint_options="-badflag" - ;; - *freebsd* | *netbsd*) - lint_name=lint - lint_options="-u -b" - ;; - *solaris*) - lint_name=lint - lint_options="-u -b -h -erroff=E_INDISTING_FROM_TRUNC2" - ;; -esac - -# Test for the presence of the program (either guessed by the code or spelled out by the user) -if test "x$use_lint" = x"yes" ; then - # Extract the first word of "$lint_name", so it can be a program name with args. -set dummy $lint_name; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_LINT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $LINT in - [\\/]* | ?:[\\/]*) - ac_cv_path_LINT="$LINT" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_LINT="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -LINT=$ac_cv_path_LINT -if test -n "$LINT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LINT" >&5 -printf '%s\n' "$LINT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$LINT" = "x"; then - as_fn_error $? "--with-lint=yes specified but lint-style tool not found in PATH" "$LINENO" 5 - fi -elif test "x$use_lint" = x"no" ; then - if test "x$LINT" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&2;} - fi -else - as_fn_error $? "--with-lint expects 'yes' or 'no'. Use LINT variable to specify path." "$LINENO" 5 -fi - -# User supplied flags override default flags -if test "x$LINT_FLAGS" != "x"; then - lint_options=$LINT_FLAGS -fi - -LINT_FLAGS=$lint_options - - if test "x$LINT" != x; then - LINT_TRUE= - LINT_FALSE='#' -else - LINT_TRUE='#' - LINT_FALSE= -fi - - - - - -@%:@ Check whether --enable-lint-library was given. -if test ${enable_lint_library+y} -then : - enableval=$enable_lint_library; make_lint_lib=$enableval -else case e in @%:@( - e) make_lint_lib=no ;; -esac -fi - - -if test "x$make_lint_lib" = x"yes" ; then - LINTLIB=llib-lXext.ln - if test "x$LINT" = "x"; then - as_fn_error $? "Cannot make lint library without --with-lint" "$LINENO" 5 - fi -elif test "x$make_lint_lib" != x"no" ; then - as_fn_error $? "--enable-lint-library expects 'yes' or 'no'." "$LINENO" 5 -fi - - - if test x$make_lint_lib != xno; then - MAKE_LINT_LIB_TRUE= - MAKE_LINT_LIB_FALSE='#' -else - MAKE_LINT_LIB_TRUE='#' - MAKE_LINT_LIB_FALSE= -fi - - - - -ac_config_files="$ac_config_files Makefile man/Makefile src/Makefile specs/Makefile xext.pc" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# 'ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* 'ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -ac_cache_dump | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -printf '%s\n' "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -printf '%s\n' "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIB@&t@OBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`printf '%s\n' "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIB@&t@OBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -printf %s "checking that generated files are newer than configure... " >&6; } - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: done" >&5 -printf '%s\n' "done" >&6; } -if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then - as_fn_error $? "conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; -esac -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi - - if test -n "$EXEEXT"; then - am__EXEEXT_TRUE= - am__EXEEXT_FALSE='#' -else - am__EXEEXT_TRUE='#' - am__EXEEXT_FALSE= -fi - -if test -z "${ENABLE_SPECS_TRUE}" && test -z "${ENABLE_SPECS_FALSE}"; then - as_fn_error $? "conditional \"ENABLE_SPECS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TEXT_TRUE}" && test -z "${HAVE_XMLTO_TEXT_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO_TEXT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TRUE}" && test -z "${HAVE_XMLTO_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_FOP_TRUE}" && test -z "${HAVE_FOP_FALSE}"; then - as_fn_error $? "conditional \"HAVE_FOP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XSLTPROC_TRUE}" && test -z "${HAVE_XSLTPROC_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XSLTPROC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_STYLESHEETS_TRUE}" && test -z "${HAVE_STYLESHEETS_FALSE}"; then - as_fn_error $? "conditional \"HAVE_STYLESHEETS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${LINT_TRUE}" && test -z "${LINT_FALSE}"; then - as_fn_error $? "conditional \"LINT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${MAKE_LINT_LIB_TRUE}" && test -z "${MAKE_LINT_LIB_FALSE}"; then - as_fn_error $? "conditional \"MAKE_LINT_LIB\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: "${CONFIG_STATUS=./config.status}" -case $CONFIG_STATUS in @%:@( - -*) : - CONFIG_STATUS=./$CONFIG_STATUS ;; @%:@( - */*) : - ;; @%:@( - *) : - CONFIG_STATUS=./$CONFIG_STATUS ;; -esac - -ac_write_fail=0 -ac_clean_CONFIG_STATUS='"$CONFIG_STATUS"' -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -printf '%s\n' "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >"$CONFIG_STATUS" <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>"$CONFIG_STATUS" <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in @%:@( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in @%:@( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - -exec 6>&1 -## ------------------------------------- ## -## Main body of "$CONFIG_STATUS" script. ## -## ------------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -'$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` -ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_cs_config='$ac_cs_config_escaped' -ac_cs_version="\\ -libXext config.status 1.3.7 -configured by $0, generated by GNU Autoconf 2.73, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2026 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -AWK='$AWK' -test -n "\$AWK" || { - awk '' >"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - printf '%s\n' "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - printf '%s\n' "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: '$1' -Try '$0 --help' for more information.";; - --help | --hel | -h ) - printf '%s\n' "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: '$1' -Try '$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \printf '%s\n' "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../@%:@@%:@ /;s/...$/ @%:@@%:@/;p;x;p;x' <<_ASBOX -@%:@@%:@ Running $as_me. @%:@@%:@ -_ASBOX - printf '%s\n' "$ac_log" -} >&5 - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" - - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='$sed_quote_subst' -double_quote_subst='$double_quote_subst' -delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' -macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' -enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' -enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' -pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' -shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' -SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' -ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' -PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' -host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' -host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' -host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' -build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' -build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' -build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' -SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' -Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' -GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' -EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' -FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' -LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' -NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' -LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' -ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' -exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' -lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' -lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' -lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' -reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' -FILECMD='`$ECHO "$FILECMD" | $SED "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' -file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' -want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' -DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' -sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' -AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' -lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' -archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' -STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' -RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' -lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' -CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' -compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' -GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' -lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' -nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' -lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' -lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' -objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' -need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' -MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' -LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' -OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' -libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' -module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' -postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' -need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' -version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' -runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' -libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' -soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' -install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' -finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' -configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' -old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' -striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' - -LTCC='$LTCC' -LTCFLAGS='$LTCFLAGS' -compiler='$compiler_DEFAULT' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in SHELL \ -ECHO \ -PATH_SEPARATOR \ -SED \ -GREP \ -EGREP \ -FGREP \ -LD \ -NM \ -LN_S \ -lt_SP2NL \ -lt_NL2SP \ -reload_flag \ -FILECMD \ -OBJDUMP \ -deplibs_check_method \ -file_magic_cmd \ -file_magic_glob \ -want_nocaseglob \ -DLLTOOL \ -sharedlib_from_linklib_cmd \ -AR \ -archiver_list_spec \ -STRIP \ -RANLIB \ -CC \ -CFLAGS \ -compiler \ -lt_cv_sys_global_symbol_pipe \ -lt_cv_sys_global_symbol_to_cdecl \ -lt_cv_sys_global_symbol_to_import \ -lt_cv_sys_global_symbol_to_c_name_address \ -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -lt_cv_nm_interface \ -nm_file_list_spec \ -lt_cv_truncate_bin \ -lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_pic \ -lt_prog_compiler_wl \ -lt_prog_compiler_static \ -lt_cv_prog_compiler_c_o \ -need_locks \ -MANIFEST_TOOL \ -DSYMUTIL \ -NMEDIT \ -LIPO \ -OTOOL \ -OTOOL64 \ -shrext_cmds \ -export_dynamic_flag_spec \ -whole_archive_flag_spec \ -compiler_needs_object \ -with_gnu_ld \ -allow_undefined_flag \ -no_undefined_flag \ -hardcode_libdir_flag_spec \ -hardcode_libdir_separator \ -exclude_expsyms \ -include_expsyms \ -file_list_spec \ -variables_saved_for_relink \ -libname_spec \ -library_names_spec \ -soname_spec \ -install_override_mode \ -finish_eval \ -old_striplib \ -striplib; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in reload_cmds \ -old_postinstall_cmds \ -old_postuninstall_cmds \ -old_archive_cmds \ -extract_expsyms_cmds \ -old_archive_from_new_cmds \ -old_archive_from_expsyms_cmds \ -archive_cmds \ -archive_expsym_cmds \ -module_cmds \ -module_expsym_cmds \ -export_symbols_cmds \ -prelink_cmds \ -postlink_cmds \ -postinstall_cmds \ -postuninstall_cmds \ -finish_cmds \ -sys_lib_search_path_spec \ -configure_time_dlsearch_path \ -configure_time_lt_sys_library_path; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -ac_aux_dir='$ac_aux_dir' - -# See if we are running on zsh, and set the options that allow our -# commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - - - PACKAGE='$PACKAGE' - VERSION='$VERSION' - RM='$RM' - ofile='$ofile' - - - - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; - "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; - "specs/Makefile") CONFIG_FILES="$CONFIG_FILES specs/Makefile" ;; - "xext.pc") CONFIG_FILES="$CONFIG_FILES xext.pc" ;; - - *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files - test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers - test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to '$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with './config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | sed -n '$='` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | sed -n '$='` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >"$CONFIG_STATUS" || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with './config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script 'defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >"$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - suffix = P[macro] D[macro] - while (suffix ~ /[\t ]$/) { - suffix = substr(suffix, 1, length(suffix) - 1) - } - # Preserve the white space surrounding the "#". - print prefix "define", macro suffix - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain ':'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf '%s\n' "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is 'configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - printf '%s\n' "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf '%s\n' "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf '%s\n' "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when '$srcdir' = '.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf '%s\n' "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf '%s\n' "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || { - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - case $CONFIG_FILES in @%:@( - *\'*) : - eval set x "$CONFIG_FILES" ;; @%:@( - *) : - set x $CONFIG_FILES ;; @%:@( - *) : - ;; -esac - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`printf '%s\n' "$am_mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`$as_dirname -- "$am_mf" || -$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$am_mf" : 'X\(//\)[^/]' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$am_mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - am_filepart=`$as_basename -- "$am_mf" || -$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$am_mf" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - { echo "$as_me:$LINENO: cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles" >&5 - (cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } || am_rc=$? - done - if test $am_rc -ne 0; then - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE=\"gmake\" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking). -See 'config.log' for more details" "$LINENO" 5; } - fi - { am_dirpart=; unset am_dirpart;} - { am_filepart=; unset am_filepart;} - { am_mf=; unset am_mf;} - { am_rc=; unset am_rc;} - rm -f conftest-deps.mk -} - ;; - "libtool":C) - - # See if we are running on zsh, and set the options that allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST - fi - - cfgfile=${ofile}T - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL -# Generated automatically by $as_me ($PACKAGE) $VERSION -# NOTE: Changes made to this file will be lost: look at ltmain.sh. - -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit, 1996 - -# Copyright (C) 2024 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program or library that is built -# using GNU Libtool, you may include this file under the same -# distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -# The names of the tagged configurations supported by this script. -available_tags='' - -# Configured defaults for sys_lib_dlsearch_path munging. -: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=$macro_version -macro_revision=$macro_revision - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# What type of objects to build. -pic_mode=$pic_mode - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# Shared archive member basename,for filename based shared library versioning on AIX. -shared_archive_member_spec=$shared_archive_member_spec - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The PATH separator for the build system. -PATH_SEPARATOR=$lt_PATH_SEPARATOR - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="\$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP=$lt_GREP - -# An ERE matcher. -EGREP=$lt_EGREP - -# A literal string matcher. -FGREP=$lt_FGREP - -# A BSD- or MS-compatible name lister. -NM=$lt_NM - -# Whether we need soft or hard links. -LN_S=$lt_LN_S - -# What is the maximum length of a command? -max_cmd_len=$max_cmd_len - -# Object file suffix (normally "o"). -objext=$ac_objext - -# Executable file suffix (normally ""). -exeext=$exeext - -# whether the shell understands "unset". -lt_unset=$lt_unset - -# turn spaces into newlines. -SP2NL=$lt_lt_SP2NL - -# turn newlines into spaces. -NL2SP=$lt_lt_NL2SP - -# convert \$build file names to \$host format. -to_host_file_cmd=$lt_cv_to_host_file_cmd - -# convert \$build files to toolchain format. -to_tool_file_cmd=$lt_cv_to_tool_file_cmd - -# A file(cmd) program that detects file types. -FILECMD=$lt_FILECMD - -# An object symbol dumper. -OBJDUMP=$lt_OBJDUMP - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method = "file_magic". -file_magic_cmd=$lt_file_magic_cmd - -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob=$lt_file_magic_glob - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob=$lt_want_nocaseglob - -# DLL creation program. -DLLTOOL=$lt_DLLTOOL - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd - -# The archiver. -AR=$lt_AR - -# Flags to create an archive (by configure). -lt_ar_flags=$lt_ar_flags - -# Flags to create an archive. -AR_FLAGS=\@S|@{ARFLAGS-"\@S|@lt_ar_flags"} - -# How to feed a file listing to the archiver. -archiver_list_spec=$lt_archiver_list_spec - -# A symbol stripping program. -STRIP=$lt_STRIP - -# Commands used to install an old-style archive. -RANLIB=$lt_RANLIB -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - -# A C compiler. -LTCC=$lt_CC - -# LTCC compiler flags. -LTCFLAGS=$lt_CFLAGS - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm into a list of symbols to manually relocate. -global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix - -# The name lister interface. -nm_interface=$lt_lt_cv_nm_interface - -# Specify filename containing input files for \$NM. -nm_file_list_spec=$lt_nm_file_list_spec - -# The root where to search for dependent libraries,and where our libraries should be installed. -lt_sysroot=$lt_sysroot - -# Command to truncate a binary pipe. -lt_truncate_bin=$lt_lt_cv_truncate_bin - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=$MAGIC_CMD - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Manifest tool. -MANIFEST_TOOL=$lt_MANIFEST_TOOL - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL=$lt_DSYMUTIL - -# Tool to change global to local symbols on Mac OS X. -NMEDIT=$lt_NMEDIT - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO=$lt_LIPO - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL=$lt_OTOOL - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64=$lt_OTOOL64 - -# Old archive suffix (normally "a"). -libext=$libext - -# Shared library suffix (normally ".so"). -shrext_cmds=$lt_shrext_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink=$lt_variables_saved_for_relink - -# Do we need the "lib" prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Library versioning type. -version_type=$version_type - -# Shared library runtime path variable. -runpath_var=$runpath_var - -# Shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - -# Command to use after installation of a shared archive. -postinstall_cmds=$lt_postinstall_cmds - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval=$lt_finish_eval - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Compile-time system search path for libraries. -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Detected run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path - -# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. -configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - - -# The linker used to build libraries. -LD=$lt_LD - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds - -# A language specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU compiler? -with_gcc=$GCC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e. impossible to change by setting \$shlibpath_var if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# ### END LIBTOOL CONFIG - -_LT_EOF - - cat <<'_LT_EOF' >> "$cfgfile" - -# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x@S|@2 in - x) - ;; - *:) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" - ;; - x:*) - eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" - ;; - *) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - esac -} - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in @S|@*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - - -# ### END FUNCTIONS SHARED WITH CONFIGURE - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - - -ltmain=$ac_aux_dir/ltmain.sh - - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - $SED '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - - ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_CONFIG_STATUS= - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - case $CONFIG_STATUS in @%:@( - -*) : - ac_no_opts=-- ;; @%:@( - *) : - ac_no_opts= ;; -esac - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $ac_no_opts "$CONFIG_STATUS" $ac_config_status_args || - ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - diff --git a/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.3 b/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.3 deleted file mode 100644 index 5b9080d6b..000000000 --- a/experiments/wasm-gui/third_party/libXext/autom4te.cache/output.3 +++ /dev/null @@ -1,24110 +0,0 @@ -@%:@! /bin/sh -@%:@ Guess values for system-dependent variables and create Makefiles. -@%:@ Generated by GNU Autoconf 2.73 for libXext 1.3.7. -@%:@ -@%:@ Report bugs to . -@%:@ -@%:@ -@%:@ Copyright (C) 1992-1996, 1998-2017, 2020-2026 Free Software Foundation, -@%:@ Inc. -@%:@ -@%:@ -@%:@ This configure script is free software; the Free Software Foundation -@%:@ gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $@%:@ in @%:@ (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case \`(set -o) 2>/dev/null\` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ) -then : - -else case e in @%:@( - e) exitcode=1; echo positional parameters were not saved. ;; -esac -fi -test x\$exitcode = x0 || exit 1 -blah=\$(echo \$(echo blah)) -test x\"\$blah\" = xblah || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 - - test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ - || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null -then : - as_have_required=yes -else case e in @%:@( - e) as_have_required=no ;; -esac -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null -then : - -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - case $as_dir in @%:@( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$as_shell as_have_required=yes - if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null -then : - break 2 -fi -fi - done;; - esac - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in @%:@( - e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi ;; -esac -fi - - - if test "x$CONFIG_SHELL" != x -then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in @%:@ (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $@%:@ in @%:@ (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno -then : - printf '%s\n' "$0: This script requires a shell more modern than all" - printf '%s\n' "$0: the shells that I found on your system." - if test ${ZSH_VERSION+y} ; then - printf '%s\n' "$0: In particular, zsh $ZSH_VERSION has bugs and should" - printf '%s\n' "$0: be upgraded to zsh 4.3.4 or later." - else - printf '%s\n' "$0: Please tell bug-autoconf@gnu.org and -$0: https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi ;; -esac -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in @%:@( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in @%:@( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - t clear - :clear - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { printf '%s\n' "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - -SHELL=${CONFIG_SHELL-/bin/sh} - -as_awk_strverscmp=' - # Use only awk features that work with 7th edition Unix awk (1978). - # My, what an old awk you have, Mr. Solaris! - END { - while (length(v1) && length(v2)) { - # Set d1 to be the next thing to compare from v1, and likewise for d2. - # Normally this is a single character, but if v1 and v2 contain digits, - # compare them as integers and fractions as strverscmp does. - if (v1 ~ /^[0-9]/ && v2 ~ /^[0-9]/) { - # Split v1 and v2 into their leading digit string components d1 and d2, - # and advance v1 and v2 past the leading digit strings. - for (len1 = 1; substr(v1, len1 + 1) ~ /^[0-9]/; len1++) continue - for (len2 = 1; substr(v2, len2 + 1) ~ /^[0-9]/; len2++) continue - d1 = substr(v1, 1, len1); v1 = substr(v1, len1 + 1) - d2 = substr(v2, 1, len2); v2 = substr(v2, len2 + 1) - if (d1 ~ /^0/) { - if (d2 ~ /^0/) { - # Compare two fractions. - while (d1 ~ /^0/ && d2 ~ /^0/) { - d1 = substr(d1, 2); len1-- - d2 = substr(d2, 2); len2-- - } - if (len1 != len2 && ! (len1 && len2 && substr(d1, 1, 1) == substr(d2, 1, 1))) { - # The two components differ in length, and the common prefix - # contains only leading zeros. Consider the longer to be less. - d1 = -len1 - d2 = -len2 - } else { - # Otherwise, compare as strings. - d1 = "x" d1 - d2 = "x" d2 - } - } else { - # A fraction is less than an integer. - exit 1 - } - } else { - if (d2 ~ /^0/) { - # An integer is greater than a fraction. - exit 2 - } else { - # Compare two integers. - d1 += 0 - d2 += 0 - } - } - } else { - # The normal case, without worrying about digits. - d1 = substr(v1, 1, 1); v1 = substr(v1, 2) - d2 = substr(v2, 1, 1); v2 = substr(v2, 2) - } - if (d1 < d2) exit 1 - if (d1 > d2) exit 2 - } - # Beware Solaris 11 /usr/xgp4/bin/awk, which mishandles some - # comparisons of empty strings to integers. For example, - # LC_ALL=C /usr/xpg4/bin/awk "BEGIN {if (-1 < \"\") print \"a\"}" - # prints "a". - if (length(v2)) exit 1 - if (length(v1)) exit 2 - } -' - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_CONFIG_STATUS= -ac_clean_files= -ac_config_libobj_dir=. -LIB@&t@OBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='libXext' -PACKAGE_TARNAME='libXext' -PACKAGE_VERSION='1.3.7' -PACKAGE_STRING='libXext 1.3.7' -PACKAGE_BUGREPORT='https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues' -PACKAGE_URL='' - -ac_unique_file="Makefile.am" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_STDIO_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_header_c_list= -ac_subst_vars='am__EXEEXT_FALSE -am__EXEEXT_TRUE -LTLIBOBJS -MAKE_LINT_LIB_FALSE -MAKE_LINT_LIB_TRUE -LINTLIB -LINT_FALSE -LINT_TRUE -LINT_FLAGS -LINT -LIB@&t@OBJS -XEXT_LIBS -XEXT_CFLAGS -XEXT_SOREV -XTMALLOC_ZERO_CFLAGS -XMALLOC_ZERO_CFLAGS -MALLOC_ZERO_CFLAGS -HAVE_STYLESHEETS_FALSE -HAVE_STYLESHEETS_TRUE -XSL_STYLESHEET -STYLESHEET_SRCDIR -XORG_SGML_PATH -HAVE_XSLTPROC_FALSE -HAVE_XSLTPROC_TRUE -XSLTPROC -HAVE_FOP_FALSE -HAVE_FOP_TRUE -FOP -HAVE_XMLTO_FALSE -HAVE_XMLTO_TRUE -HAVE_XMLTO_TEXT_FALSE -HAVE_XMLTO_TEXT_TRUE -XMLTO -ENABLE_SPECS_FALSE -ENABLE_SPECS_TRUE -MAN_SUBSTS -XORG_MAN_PAGE -ADMIN_MAN_DIR -DRIVER_MAN_DIR -MISC_MAN_DIR -FILE_MAN_DIR -LIB_MAN_DIR -APP_MAN_DIR -ADMIN_MAN_SUFFIX -DRIVER_MAN_SUFFIX -MISC_MAN_SUFFIX -FILE_MAN_SUFFIX -LIB_MAN_SUFFIX -APP_MAN_SUFFIX -INSTALL_CMD -PKG_CONFIG_LIBDIR -PKG_CONFIG_PATH -PKG_CONFIG -CHANGELOG_CMD -STRICT_CFLAGS -CWARNFLAGS -BASE_CFLAGS -LT_SYS_LIBRARY_PATH -OTOOL64 -OTOOL -LIPO -NMEDIT -DSYMUTIL -MANIFEST_TOOL -RANLIB -ac_ct_AR -AR -DLLTOOL -OBJDUMP -FILECMD -LN_S -NM -ac_ct_DUMPBIN -DUMPBIN -LD -FGREP -EGREP -GREP -SED -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -LIBTOOL -am__xargs_n -am__rm_f_notfound -AM_BACKSLASH -AM_DEFAULT_VERBOSITY -AM_DEFAULT_V -AM_V -CSCOPE -ETAGS -CTAGS -am__fastdepCC_FALSE -am__fastdepCC_TRUE -CCDEPMODE -am__nodep -AMDEPBACKSLASH -AMDEP_FALSE -AMDEP_TRUE -am__include -DEPDIR -am__untar -am__tar -AMTAR -am__leading_dot -SET_MAKE -AWK -mkdir_p -MKDIR_P -INSTALL_STRIP_PROGRAM -STRIP -install_sh -MAKEINFO -AUTOHEADER -AUTOMAKE -AUTOCONF -ACLOCAL -VERSION -PACKAGE -CYGPATH_W -am__isrc -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -ECHO_T -ECHO_N -ECHO_C -target_alias -host_alias -build_alias -LIBS -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -runstatedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL -am__quote' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_dependency_tracking -enable_silent_rules -enable_shared -enable_static -enable_pic -with_pic -enable_fast_install -enable_aix_soname -with_aix_soname -with_gnu_ld -with_sysroot -enable_libtool_lock -enable_selective_werror -enable_strict_compilation -enable_specs -with_xmlto -with_fop -with_xsltproc -enable_malloc0returnsnull -with_lint -enable_lint_library -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -LT_SYS_LIBRARY_PATH -PKG_CONFIG -PKG_CONFIG_PATH -PKG_CONFIG_LIBDIR -XMLTO -FOP -XSLTPROC -XEXT_CFLAGS -XEXT_LIBS -LINT -LINT_FLAGS' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: '$ac_option' -Try '$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: '$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - printf '%s\n' "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - printf '%s\n' "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`printf '%s\n' $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: '$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -'configure' configures libXext 1.3.7 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print 'checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for '--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or '..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - @<:@@S|@ac_default_prefix@:>@ - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - @<:@PREFIX@:>@ - -By default, 'make install' will install all the files in -'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify -an installation prefix other than '$ac_default_prefix' using '--prefix', -for instance '--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root @<:@DATAROOTDIR/doc/libXext@:>@ - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of libXext 1.3.7:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-dependency-tracking - do not reject slow dependency extractors - --disable-dependency-tracking - speeds up one-time build - --enable-silent-rules less verbose build output (undo: "make V=1") - --disable-silent-rules verbose build output (undo: "make V=0") - --enable-shared@<:@=PKGS@:>@ build shared libraries @<:@default=yes@:>@ - --enable-static@<:@=PKGS@:>@ build static libraries @<:@default=yes@:>@ - --enable-pic@<:@=PKGS@:>@ try to use only PIC/non-PIC objects @<:@default=use - both@:>@ - --enable-fast-install@<:@=PKGS@:>@ - optimize for fast installation @<:@default=yes@:>@ - --enable-aix-soname=aix|svr4|both - shared library versioning (aka "SONAME") variant to - provide on AIX, @<:@default=aix@:>@. - --disable-libtool-lock avoid locking (might break parallel builds) - --disable-selective-werror - Turn off selective compiler errors. (default: - enabled) - --enable-strict-compilation - Enable all warnings from compiler and make them - errors (default: disabled) - --enable-specs Enable building the specs (default: yes) - --enable-malloc0returnsnull - assume malloc(0) can return NULL (default: yes) - --enable-lint-library Create lint library (default: disabled) - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-gnu-ld assume the C compiler uses GNU ld @<:@default=no@:>@ - --with-sysroot@<:@=DIR@:>@ Search for dependent libraries within DIR (or the - compiler's sysroot if not specified). - --with-xmlto Use xmlto to regenerate documentation (default: - auto) - --with-fop Use fop to regenerate documentation (default: auto) - --with-xsltproc Use xsltproc for the transformation of XML documents - (default: auto) - --with-lint Use a lint-style source code checker (default: - disabled) - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - LT_SYS_LIBRARY_PATH - User-defined run-time library search path. - PKG_CONFIG path to pkg-config utility - PKG_CONFIG_PATH - directories to add to pkg-config's search path - PKG_CONFIG_LIBDIR - path overriding pkg-config's built-in search path - XMLTO Path to xmlto command - FOP Path to fop command - XSLTPROC Path to xsltproc command - XEXT_CFLAGS C compiler flags for XEXT, overriding pkg-config - XEXT_LIBS linker flags for XEXT, overriding pkg-config - LINT Path to a lint-style command - LINT_FLAGS Flags for the lint-style command - -Use these variables to override the choices made by 'configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for configure.gnu first; this name is used for a wrapper for - # Metaconfig's "Configure" on case-insensitive file systems. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - printf '%s\n' "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -libXext configure 1.3.7 -generated by GNU Autoconf 2.73 - -Copyright (C) 2026 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -@%:@ ac_fn_c_try_compile LINENO -@%:@ -------------------------- -@%:@ Try to compile conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_compile - -@%:@ ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -@%:@ ------------------------------------------------------- -@%:@ Tests whether HEADER exists and can be compiled using the include files in -@%:@ INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -@%:@include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_header_compile - -@%:@ ac_fn_c_try_link LINENO -@%:@ ----------------------- -@%:@ Try to link conftest.@S|@ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - } -then : - ac_retval=0 -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} @%:@ ac_fn_c_try_link - -@%:@ ac_fn_c_check_func LINENO FUNC VAR -@%:@ ---------------------------------- -@%:@ Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (void); below. */ - -#include -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (void); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main (void) -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_c_check_func - -@%:@ ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR -@%:@ ------------------------------------------------------------------ -@%:@ Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -@%:@ accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. -ac_fn_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -printf %s "checking whether $as_decl_name is declared... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - eval ac_save_FLAGS=\$$6 - as_fn_append $6 " $5" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main (void) -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in @%:@( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - eval $6=\$ac_save_FLAGS - ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} @%:@ ac_fn_check_decl -ac_configure_args_raw= -for ac_arg -do - case $ac_arg in - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_configure_args_raw " '$ac_arg'" -done - -case $ac_configure_args_raw in - *$as_nl*) - ac_safe_unquote= ;; - *) - ac_unsafe_z='|&;<>()$`\\"*?@<:@ '' ' # This string ends in space, tab. - ac_unsafe_a="$ac_unsafe_z#~" - ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" - ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; -esac - -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - $ $0$ac_configure_args_raw - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - printf '%s\n' "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# Dump the cache to stdout. It can be in a pipe (this is a requirement). -ac_cache_dump () -{ - # The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf '%s\n' "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # 'set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # 'set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) -} - -# Print debugging info to stdout. -ac_dump_debugging_info () -{ - echo - - printf '%s\n' "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - ac_cache_dump - echo - - printf '%s\n' "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - - if test -n "$ac_subst_files"; then - printf '%s\n' "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - fi - - if test -s confdefs.h; then - printf '%s\n' "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - printf '%s\n' "$as_me: caught signal $ac_signal" - printf '%s\n' "$as_me: exit $exit_status" -} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. -ac_exit_trap () -{ - exit_status= - # Sanitize IFS. - IFS=" "" $as_nl" - # Save into config.log some information that might help in debugging. - ac_dump_debugging_info >&5 - eval "rm -f $ac_clean_CONFIG_STATUS core *.core core.conftest.*" && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -} - -trap 'ac_exit_trap $?' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -printf '%s\n' "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -printf '%s\n' "@%:@define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h - -printf '%s\n' "@%:@define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -if test -n "$CONFIG_SITE"; then - ac_site_files="$CONFIG_SITE" -elif test "x$prefix" != xNONE; then - ac_site_files="$prefix/share/config.site $prefix/etc/config.site" -else - ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" -fi - -for ac_site_file in $ac_site_files -do - case $ac_site_file in @%:@( - */*) : - ;; @%:@( - *) : - ac_site_file=./$ac_site_file ;; -esac - if test -f "$ac_site_file" && test -r "$ac_site_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -printf '%s\n' "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See 'config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -printf '%s\n' "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -printf '%s\n' "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" -# Test code for whether the C compiler supports C23 (global declarations) -ac_c_conftest_c23_globals=' -/* Does the compiler advertise conformance to C17 or earlier? - Although GCC 14 does not do that, even with -std=gnu23, - it is close enough, and defines __STDC_VERSION == 202000L. */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ <= 201710L -# error "Compiler advertises conformance to C17 or earlier" -#endif - -// Check alignas. -char alignas (double) c23_aligned_as_double; -char alignas (0) c23_no_special_alignment; -extern char c23_aligned_as_int; -char alignas (0) alignas (int) c23_aligned_as_int; - -// Check alignof. -enum -{ - c23_int_alignment = alignof (int), - c23_int_array_alignment = alignof (int[100]), - c23_char_alignment = alignof (char) -}; -static_assert (0 < -alignof (int), "alignof is signed"); - -int function_with_unnamed_parameter (int) { return 0; } - -void c23_noreturn (); - -/* Test parsing of string and char UTF-8 literals (including hex escapes). - The parens pacify GCC 15. */ -bool use_u8 = (!sizeof u8"\xFF") == (!u8'\''x'\''); - -bool check_that_bool_works = true | false | !nullptr; -#if !true -# error "true does not work in #if" -#endif -#if false -#elifdef __STDC_VERSION__ -#else -# error "#elifdef does not work" -#endif - -#ifndef __has_c_attribute -# error "__has_c_attribute not defined" -#endif - -#ifndef __has_include -# error "__has_include not defined" -#endif - -#define LPAREN() ( -#define FORTY_TWO(x) 42 -#define VA_OPT_TEST(r, x, ...) __VA_OPT__ (FORTY_TWO r x)) -static_assert (VA_OPT_TEST (LPAREN (), 0, <:-) == 42); - -static_assert (0b101010 == 42); -static_assert (0B101010 == 42); -static_assert (0xDEAD'\''BEEF == 3'\''735'\''928'\''559); -static_assert (0.500'\''000'\''000 == 0.5); - -enum unsignedish : unsigned int { uione = 1 }; -static_assert (0 < -uione); - -#include -constexpr nullptr_t null_pointer = nullptr; - -static typeof (1 + 1L) two () { return 2; } -static long int three () { return 3; } -' - -# Test code for whether the C compiler supports C23 (body of main). -ac_c_conftest_c23_main=' - { - label_before_declaration: - int arr[10] = {}; - if (arr[0]) - goto label_before_declaration; - if (!arr[0]) - goto label_at_end_of_block; - label_at_end_of_block: - } - ok |= !null_pointer; - ok |= two != three; -' - -# Test code for whether the C compiler supports C23 (complete). -ac_c_conftest_c23_program="${ac_c_conftest_c23_globals} - -int -main (int, char **) -{ - int ok = 0; - ${ac_c_conftest_c23_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (global declarations) -ac_c_conftest_c89_globals=' -/* Do not test the value of __STDC__, because some compilers define it to 0 - or do not define it, while otherwise adequately conforming. */ - -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ -struct buf { int x; }; -struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (char **p, int i) -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* C89 style stringification. */ -#define noexpand_stringify(a) #a -const char *stringified = noexpand_stringify(arbitrary+token=sequence); - -/* C89 style token pasting. Exercises some of the corner cases that - e.g. old MSVC gets wrong, but not very hard. */ -#define noexpand_concat(a,b) a##b -#define expand_concat(a,b) noexpand_concat(a,b) -extern int vA; -extern int vbee; -#define aye A -#define bee B -int *pvA = &expand_concat(v,aye); -int *pvbee = &noexpand_concat(v,bee); - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not \xHH hex character constants. - These do not provoke an error unfortunately, instead are silently treated - as an "x". The following induces an error, until -std is added to get - proper ANSI mode. Curiously \x00 != x always comes out true, for an - array size at least. It is necessary to write \x00 == 0 to get something - that is true only with -std. */ -int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) '\''x'\'' -int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), - int, int);' - -# Test code for whether the C compiler supports C89 (body of main). -ac_c_conftest_c89_main=' -ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); -' - -# Test code for whether the C compiler supports C99 (global declarations) -ac_c_conftest_c99_globals=' -/* Does the compiler advertise C99 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# error "Compiler does not advertise C99 conformance" -#endif - -// See if C++-style comments work. - -#include -extern int puts (const char *); -extern int printf (const char *, ...); -extern int dprintf (int, const char *, ...); -extern void *malloc (size_t); -extern void free (void *); - -// Check varargs macros. These examples are taken from C99 6.10.3.5. -// dprintf is used instead of fprintf to avoid needing to declare -// FILE and stderr, and "aND" is used instead of "and" to work around -// GCC bug 40564 which is irrelevant here. -#define debug(...) dprintf (2, __VA_ARGS__) -#define showlist(...) puts (#__VA_ARGS__) -#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) -static void -test_varargs_macros (void) -{ - int x = 1234; - int y = 5678; - debug ("Flag"); - debug ("X = %d\n", x); - showlist (The first, second, aND third items.); - report (x>y, "x is %d but y is %d", x, y); -} - -// Check long long types. -#define BIG64 18446744073709551615ull -#define BIG32 4294967295ul -#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) -#if !BIG_OK - #error "your preprocessor is broken" -#endif -#if BIG_OK -#else - #error "your preprocessor is broken" -#endif -static long long int bignum = -9223372036854775807LL; -static unsigned long long int ubignum = BIG64; - -struct incomplete_array -{ - int datasize; - double data[]; -}; - -struct named_init { - int number; - const wchar_t *name; - double average; -}; - -typedef const char *ccp; - -static inline int -test_restrict (ccp restrict text) -{ - // Iterate through items via the restricted pointer. - // Also check for declarations in for loops. - for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) - continue; - return 0; -} - -// Check varargs and va_copy. -static bool -test_varargs (const char *format, ...) -{ - va_list args; - va_start (args, format); - va_list args_copy; - va_copy (args_copy, args); - - const char *str = ""; - int number = 0; - float fnumber = 0; - - while (*format) - { - switch (*format++) - { - case '\''s'\'': // string - str = va_arg (args_copy, const char *); - break; - case '\''d'\'': // int - number = va_arg (args_copy, int); - break; - case '\''f'\'': // float - fnumber = va_arg (args_copy, double); - break; - default: - break; - } - } - va_end (args_copy); - va_end (args); - - return *str && number && fnumber; -} -' - -# Test code for whether the C compiler supports C99 (body of main). -ac_c_conftest_c99_main=' - // Check bool. - _Bool success = false; - success |= (argc != 0); - - // Check restrict. - if (test_restrict ("String literal") == 0) - success = true; - const char *restrict newvar = "Another string"; - - // Check varargs. - success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); - test_varargs_macros (); - - // Check flexible array members. - static struct incomplete_array *volatile incomplete_array_pointer; - struct incomplete_array *ia = incomplete_array_pointer; - ia->datasize = 10; - for (int i = 0; i < ia->datasize; ++i) - ia->data[i] = i * 1.234; - // Work around memory leak warnings. - free (ia); - - // Check named initializers. - struct named_init ni = { - .number = 34, - .name = L"Test wide string", - .average = 543.34343, - }; - - ni.number = 58; - - // Do not test for VLAs, as some otherwise-conforming compilers lack them. - // C code should instead use __STDC_NO_VLA__; see Autoconf manual. - - // work around unused variable warnings - ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' - || ni.number != 58); -' - -# Test code for whether the C compiler supports C11 (global declarations) -ac_c_conftest_c11_globals=' -/* Does the compiler advertise C11 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L -# error "Compiler does not advertise C11 conformance" -#endif - -// Check _Alignas. -char _Alignas (double) aligned_as_double; -char _Alignas (0) no_special_alignment; -extern char aligned_as_int; -char _Alignas (0) _Alignas (int) aligned_as_int; - -// Check _Alignof. -enum -{ - int_alignment = _Alignof (int), - int_array_alignment = _Alignof (int[100]), - char_alignment = _Alignof (char) -}; -_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); - -// Check _Noreturn. -int _Noreturn does_not_return (void) { for (;;) continue; } - -// Check _Static_assert. -struct test_static_assert -{ - int x; - _Static_assert (sizeof (int) <= sizeof (long int), - "_Static_assert does not work in struct"); - long int y; -}; - -// Check UTF-8 literals. -#define u8 syntax error! -char const utf8_literal[] = u8"happens to be ASCII" "another string"; - -// Check duplicate typedefs. -typedef long *long_ptr; -typedef long int *long_ptr; -typedef long_ptr long_ptr; - -// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. -struct anonymous -{ - union { - struct { int i; int j; }; - struct { int k; long int l; } w; - }; - int m; -} v1; -' - -# Test code for whether the C compiler supports C11 (body of main). -ac_c_conftest_c11_main=' - _Static_assert ((offsetof (struct anonymous, i) - == offsetof (struct anonymous, w.k)), - "Anonymous union alignment botch"); - v1.i = 2; - v1.w.k = 5; - ok |= v1.i != 5; -' - -# Test code for whether the C compiler supports C11 (complete). -ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} -${ac_c_conftest_c11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - ${ac_c_conftest_c11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C99 (complete). -ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (complete). -ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - return ok; -} -" - -as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" -as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" -as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" -as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" -as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" -as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" -as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" -as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" -as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" -as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" - -# Auxiliary files required by this configure script. -ac_aux_files="config.guess config.sub ltmain.sh missing install-sh compile" - -# Locations in which to look for auxiliary files. -ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." - -# Search for a directory containing all of the required auxiliary files, -# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. -# If we don't find one directory that contains all the files we need, -# we report the set of missing files from the *first* directory in -# $ac_aux_dir_candidates and give up. -ac_missing_aux_files="" -ac_first_candidate=: -printf '%s\n' "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in $ac_aux_dir_candidates -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - - printf '%s\n' "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 - ac_aux_dir_found=yes - ac_install_sh= - for ac_aux in $ac_aux_files - do - # As a special case, if "install-sh" is required, that requirement - # can be satisfied by any of "install-sh", "install.sh", or "shtool", - # and $ac_install_sh is set appropriately for whichever one is found. - if test x"$ac_aux" = x"install-sh" - then - if test -f "${as_dir}install-sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 - ac_install_sh="${as_dir}install-sh -c" - elif test -f "${as_dir}install.sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 - ac_install_sh="${as_dir}install.sh -c" - elif test -f "${as_dir}shtool"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 - ac_install_sh="${as_dir}shtool install -c" - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} install-sh" - else - break - fi - fi - else - if test -f "${as_dir}${ac_aux}"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" - else - break - fi - fi - fi - done - if test "$ac_aux_dir_found" = yes; then - ac_aux_dir="$as_dir" - break - fi - ac_first_candidate=false - - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in @%:@( - e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; -esac -fi - - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -if test -f "${ac_aux_dir}config.guess"; then - ac_@&t@config_guess="$SHELL ${ac_aux_dir}config.guess" -fi -if test -f "${ac_aux_dir}config.sub"; then - ac_@&t@config_sub="$SHELL ${ac_aux_dir}config.sub" -fi -if test -f "$ac_aux_dir/configure"; then - ac_@&t@configure="$SHELL ${ac_aux_dir}configure" -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w= - for ac_val in x $ac_old_val; do - ac_old_val_w="$ac_old_val_w $ac_val" - done - ac_new_val_w= - for ac_val in x $ac_new_val; do - ac_new_val_w="$ac_new_val_w $ac_val" - done - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 -printf '%s\n' "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 -printf '%s\n' "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 -printf '%s\n' "$as_me: former value: '$ac_old_val'" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 -printf '%s\n' "$as_me: current value: '$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`printf '%s\n' "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -printf '%s\n' "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' - and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in @%:@((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers config.h" - - - -# Set common system defines for POSIX extensions, such as _GNU_SOURCE -# Must be called before any macros that run the compiler (like LT_INIT) -# to avoid autoconf errors. - - - - - - - - - - - - - - -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $@%:@ != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" - fi -fi -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. -set dummy ${ac_tool_prefix}clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "clang", so it can be a program name with args. -set dummy clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -fi - - -test -z "$CC" && { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See 'config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion -version; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -printf %s "checking whether the C compiler works... " >&6; } -ac_link_default=`printf '%s\n' "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. -# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an '-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else case e in @%:@( - e) ac_file='' ;; -esac -fi -if test -z "$ac_file" -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See 'config.log' for more details" "$LINENO" 5; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -printf %s "checking for C compiler default output file name... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -printf '%s\n' "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -printf %s "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) -# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will -# work properly (i.e., refer to 'conftest.exe'), while it won't with -# 'rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else case e in @%:@( - e) { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest conftest$ac_cv_exeext -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -printf '%s\n' "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -@%:@include -int -main (void) -{ -FILE *f = fopen ("conftest.out", "w"); - if (!f) - return 1; - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -printf %s "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use '--host'. -See 'config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -printf '%s\n' "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext \ - conftest.o conftest.obj conftest.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -printf %s "checking for suffix of object files... " >&6; } -if test ${ac_cv_objext+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else case e in @%:@( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -printf '%s\n' "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 -printf %s "checking whether the compiler supports GNU C... " >&6; } -if test ${ac_cv_c_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else case e in @%:@( - e) ac_compiler_gnu=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -printf '%s\n' "$ac_cv_c_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+y} -ac_save_CFLAGS=$CFLAGS -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -printf %s "checking whether $CC accepts -g... " >&6; } -if test ${ac_cv_prog_cc_g+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -else case e in @%:@( - e) CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -printf '%s\n' "$ac_cv_prog_cc_g" >&6; } -if test $ac_test_CFLAGS; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -ac_prog_cc_stdc=no -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C23 features" >&5 -printf %s "checking for $CC option to enable C23 features... " >&6; } -if test ${ac_cv_prog_cc_c23+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c23=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c23_program -_ACEOF -for ac_arg in '' -std=gnu23 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c23=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c23" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c23" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c23" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c23" >&5 -printf '%s\n' "$ac_cv_prog_cc_c23" >&6; } - CC="$CC $ac_cv_prog_cc_c23" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c23 - ac_prog_cc_stdc=c23 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 -printf %s "checking for $CC option to enable C11 features... " >&6; } -if test ${ac_cv_prog_cc_c11+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c11=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c11_program -_ACEOF -for ac_arg in '' -std=gnu11 -std:c11 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c11" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c11" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c11" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -printf '%s\n' "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } -if test ${ac_cv_prog_cc_c99+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c99=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c99=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c99" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c99" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c99" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -printf '%s\n' "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 -printf %s "checking for $CC option to enable C89 features... " >&6; } -if test ${ac_cv_prog_cc_c89+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c89_program -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c89" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in @%:@( - e) if test "x$ac_cv_prog_cc_c89" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -printf '%s\n' "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 ;; -esac -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -printf %s "checking whether $CC understands -c and -o together... " >&6; } -if test ${am_cv_prog_cc_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - # aligned with autoconf, so not including core; see bug#72225. - rm -f -r a.out a.exe b.out conftest.$ac_ext conftest.$ac_objext \ - conftest.dSYM conftest1.$ac_ext conftest1.$ac_objext conftest1.dSYM \ - conftest2.$ac_ext conftest2.$ac_objext conftest2.dSYM - unset am_i ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -printf '%s\n' "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_header= ac_cache= -for ac_item in $ac_header_c_list -do - if test $ac_cache; then - ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" - if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf '%s\n' "#define $ac_item 1" >> confdefs.h - fi - ac_header= ac_cache= - elif test $ac_header; then - ac_cache=$ac_item - else - ac_header=$ac_item - fi -done - - - - - - - - -if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes -then : - -printf '%s\n' "@%:@define STDC_HEADERS 1" >>confdefs.h - -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 -printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test ${ac_cv_safe_to_define___extensions__+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -# define __EXTENSIONS__ 1 - $ac_includes_default -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_safe_to_define___extensions__=yes -else case e in @%:@( - e) ac_cv_safe_to_define___extensions__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -printf '%s\n' "$ac_cv_safe_to_define___extensions__" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 -printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } -if test ${ac_cv_should_define__xopen_source+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_cv_should_define__xopen_source=no - if test $ac_cv_header_wchar_h = yes -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #define _XOPEN_SOURCE 500 - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_should_define__xopen_source=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 -printf '%s\n' "$ac_cv_should_define__xopen_source" >&6; } - - printf '%s\n' "@%:@define _ALL_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _COSMO_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _DARWIN_C_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _GNU_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h - - printf '%s\n' "@%:@define _NETBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _OPENBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h - - printf '%s\n' "@%:@define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h - - printf '%s\n' "@%:@define _TANDEM_SOURCE 1" >>confdefs.h - - if test $ac_cv_header_minix_config_h = yes -then : - MINIX=yes - printf '%s\n' "@%:@define _MINIX 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_SOURCE 1" >>confdefs.h - - printf '%s\n' "@%:@define _POSIX_1_SOURCE 2" >>confdefs.h - -else case e in @%:@( - e) MINIX= ;; -esac -fi - if test $ac_cv_safe_to_define___extensions__ = yes -then : - printf '%s\n' "@%:@define __EXTENSIONS__ 1" >>confdefs.h - -fi - if test $ac_cv_should_define__xopen_source = yes -then : - printf '%s\n' "@%:@define _XOPEN_SOURCE 500" >>confdefs.h - -fi - - -# Initialize Automake -am__api_version='1.18' - - - # Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -printf %s "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if test ${ac_cv_path_install+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - # Account for fact that we put trailing slashes in our PATH walk. -case $as_dir in @%:@(( - ./ | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF/1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF/1 since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - ;; -esac -fi - if test ${ac_cv_path_install+y}; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -printf '%s\n' "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5 -printf %s "checking whether sleep supports fractional seconds... " >&6; } -if test ${am_cv_sleep_fractional_seconds+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if sleep 0.001 2>/dev/null -then : - am_cv_sleep_fractional_seconds=yes -else case e in @%:@( - e) am_cv_sleep_fractional_seconds=no ;; -esac -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_sleep_fractional_seconds" >&5 -printf '%s\n' "$am_cv_sleep_fractional_seconds" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking filesystem timestamp resolution" >&5 -printf %s "checking filesystem timestamp resolution... " >&6; } -if test ${am_cv_filesystem_timestamp_resolution+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) # Default to the worst case. -am_cv_filesystem_timestamp_resolution=2 - -# Only try to go finer than 1 sec if sleep can do it. -# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, -# - 1 sec is not much of a win compared to 2 sec, and -# - it takes 2 seconds to perform the test whether 1 sec works. -# -# Instead, just use the default 2s on platforms that have 1s resolution, -# accept the extra 1s delay when using $sleep in the Automake tests, in -# exchange for not incurring the 2s delay for running the test for all -# packages. -# -am_try_resolutions= -if test "$am_cv_sleep_fractional_seconds" = yes; then - # Even a millisecond often causes a bunch of false positives, - # so just try a hundredth of a second. The time saved between .001 and - # .01 is not terribly consequential. - am_try_resolutions="0.01 0.1 $am_try_resolutions" -fi - -# In order to catch current-generation FAT out, we must *modify* files -# that already exist; the *creation* timestamp is finer. Use names -# that make ls -t sort them differently when they have equal -# timestamps than when they have distinct timestamps, keeping -# in mind that ls -t prints the *newest* file first. -rm -f conftest.ts? -: > conftest.ts1 -: > conftest.ts2 -: > conftest.ts3 - -# Make sure ls -t actually works. Do 'set' in a subshell so we don't -# clobber the current shell's arguments. (Outer-level square brackets -# are removed by m4; they're present so that m4 does not expand -# ; be careful, easy to get confused.) -if ( - set X `ls -t conftest.ts[12]` && - { - test "$*" != "X conftest.ts1 conftest.ts2" || - test "$*" != "X conftest.ts2 conftest.ts1"; - } -); then :; else - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - printf '%s\n' ""Bad output from ls -t: \"`ls -t conftest.ts[12]`\""" >&5 - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "ls -t produces unexpected output. -Make sure there is not a broken ls alias in your environment. -See 'config.log' for more details" "$LINENO" 5; } -fi - -for am_try_res in $am_try_resolutions; do - # Any one fine-grained sleep might happen to cross the boundary - # between two values of a coarser actual resolution, but if we do - # two fine-grained sleeps in a row, at least one of them will fall - # entirely within a coarse interval. - echo alpha > conftest.ts1 - sleep $am_try_res - echo beta > conftest.ts2 - sleep $am_try_res - echo gamma > conftest.ts3 - - # We assume that 'ls -t' will make use of high-resolution - # timestamps if the operating system supports them at all. - if (set X `ls -t conftest.ts?` && - test "$2" = conftest.ts3 && - test "$3" = conftest.ts2 && - test "$4" = conftest.ts1); then - # - # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, - # because we don't need to test make. - make_ok=true - if test $am_try_res != 1; then - # But if we've succeeded so far with a subsecond resolution, we - # have one more thing to check: make. It can happen that - # everything else supports the subsecond mtimes, but make doesn't; - # notably on macOS, which ships make 3.81 from 2006 (the last one - # released under GPLv2). https://bugs.gnu.org/68808 - # - # We test $MAKE if it is defined in the environment, else "make". - # It might get overridden later, but our hope is that in practice - # it does not matter: it is the system "make" which is (by far) - # the most likely to be broken, whereas if the user overrides it, - # probably they did so with a better, or at least not worse, make. - # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html - # - # Create a Makefile (real tab character here): - rm -f conftest.mk - echo 'conftest.ts1: conftest.ts2' >conftest.mk - echo ' touch conftest.ts2' >>conftest.mk - # - # Now, running - # touch conftest.ts1; touch conftest.ts2; make - # should touch ts1 because ts2 is newer. This could happen by luck, - # but most often, it will fail if make's support is insufficient. So - # test for several consecutive successes. - # - # (We reuse conftest.ts[12] because we still want to modify existing - # files, not create new ones, per above.) - n=0 - make=${MAKE-make} - until test $n -eq 3; do - echo one > conftest.ts1 - sleep $am_try_res - echo two > conftest.ts2 # ts2 should now be newer than ts1 - if $make -f conftest.mk | grep 'up to date' >/dev/null; then - make_ok=false - break # out of $n loop - fi - n=`expr $n + 1` - done - fi - # - if $make_ok; then - # Everything we know to check worked out, so call this resolution good. - am_cv_filesystem_timestamp_resolution=$am_try_res - break # out of $am_try_res loop - fi - # Otherwise, we'll go on to check the next resolution. - fi -done -rm -f conftest.ts? -# (end _am_filesystem_timestamp_resolution) - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_filesystem_timestamp_resolution" >&5 -printf '%s\n' "$am_cv_filesystem_timestamp_resolution" >&6; } - -# This check should not be cached, as it may vary across builds of -# different projects. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -printf %s "checking whether build environment is sane... " >&6; } -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[\\\"\#\$\&\'\`$am_lf]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; -esac -case $srcdir in - *[\\\"\#\$\&\'\`$am_lf\ \ ]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -am_build_env_is_sane=no -am_has_slept=no -rm -f conftest.file -for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - test "$2" = conftest.file - ); then - am_build_env_is_sane=yes - break - fi - # Just in case. - sleep "$am_cv_filesystem_timestamp_resolution" - am_has_slept=yes -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_build_env_is_sane" >&5 -printf '%s\n' "$am_build_env_is_sane" >&6; } -if test "$am_build_env_is_sane" = no; then - as_fn_error $? "newly created file is older than distributed files! -Check your system clock" "$LINENO" 5 -fi - -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1 -then : - -else case e in @%:@( - e) ( sleep "$am_cv_filesystem_timestamp_resolution" ) & - am_sleep_pid=$! - ;; -esac -fi - -rm -f conftest.file - -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was 's,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`printf '%s\n' "$program_transform_name" | sed "$ac_script"` - - - if test x"${MISSING+set}" != xset; then - MISSING="\${SHELL} '$am_aux_dir/missing'" -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -printf '%s\n' "$as_me: WARNING: 'missing' script is too old or missing" >&2;} -fi - -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 -printf %s "checking for a race-free mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if test ${ac_cv_path_mkdir+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue - case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir ('*'coreutils) '* | \ - *'BusyBox '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - ;; -esac -fi - - test -d ./--version && rmdir ./--version - if test ${ac_cv_path_mkdir+y}; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use plain mkdir -p, - # in the hope it doesn't have the bugs of ancient mkdir. - MKDIR_P='mkdir -p' - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -printf '%s\n' "$MKDIR_P" >&6; } - -for ac_prog in gawk mawk nawk awk 'busybox awk' -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AWK+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -printf '%s\n' "$AWK" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`printf '%s\n' "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval test \${ac_cv_prog_make_${ac_make}_set+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @printf '%s\n' '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make ;; -esac -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - SET_MAKE= -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depfiles" - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 -printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } -cat > confinc.mk << 'END' -am__doit: - @echo this is the am__doit target >confinc.out -.PHONY: am__doit -END -am__include="#" -am__quote= -# BSD make does it like this. -echo '.include "confinc.mk" # ignored' > confmf.BSD -# Other make implementations (GNU, Solaris 10, AIX) do it like this. -echo 'include confinc.mk # ignored' > confmf.GNU -_am_result=no -for s in GNU BSD; do - { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 - (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - case $?:`cat confinc.out 2>/dev/null` in @%:@( - '0:this is the am__doit target') : - case $s in @%:@( - BSD) : - am__include='.include' am__quote='"' ;; @%:@( - *) : - am__include='include' am__quote='' ;; -esac ;; @%:@( - *) : - ;; -esac - if test "$am__include" != "#"; then - _am_result="yes ($s style)" - break - fi -done -rm -f confinc.* confmf.* -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 -printf '%s\n' "${_am_result}" >&6; } - -@%:@ Check whether --enable-dependency-tracking was given. -if test ${enable_dependency_tracking+y} -then : - enableval=$enable_dependency_tracking; -fi - -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi - if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - -AM_DEFAULT_VERBOSITY=1 -@%:@ Check whether --enable-silent-rules was given. -if test ${enable_silent_rules+y} -then : - enableval=$enable_silent_rules; -fi - -am_make=${MAKE-make} -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -printf %s "checking whether $am_make supports nested variables... " >&6; } -if test ${am_cv_make_support_nested_variables+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if printf '%s\n' 'TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -printf '%s\n' "$am_cv_make_support_nested_variables" >&6; } -AM_BACKSLASH='\' - -am__rm_f_notfound= -if (rm -f && rm -fr && rm -rf) 2>/dev/null -then : - -else case e in @%:@( - e) am__rm_f_notfound='""' ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking xargs -n works" >&5 -printf %s "checking xargs -n works... " >&6; } -if test ${am_cv_xargs_n_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 -3" -then : - am_cv_xargs_n_works=yes -else case e in @%:@( - e) am_cv_xargs_n_works=no ;; -esac -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_xargs_n_works" >&5 -printf '%s\n' "$am_cv_xargs_n_works" >&6; } -if test "$am_cv_xargs_n_works" = yes -then : - am__xargs_n='xargs -n' -else case e in @%:@( - e) am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "" "$am__xargs_n_arg"; done; }' - ;; -esac -fi - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE='libXext' - VERSION='1.3.7' - - -printf '%s\n' "@%:@define PACKAGE \"$PACKAGE\"" >>confdefs.h - - -printf '%s\n' "@%:@define VERSION \"$VERSION\"" >>confdefs.h - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -mkdir_p='$(MKDIR_P)' - -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AMTAR='$${TAR-tar}' - - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar plaintar pax cpio none' - -# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 -printf %s "checking whether UID '$am_uid' is supported by ustar format... " >&6; } - if test x$am_uid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&2;} - elif test $am_uid -le $am_max_uid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 -printf %s "checking whether GID '$am_gid' is supported by ustar format... " >&6; } - if test x$gm_gid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&2;} - elif test $am_gid -le $am_max_gid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 -printf %s "checking how to create a ustar tar archive... " >&6; } - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_ustar-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - { echo "$as_me:$LINENO: $_am_tar --version" >&5 - ($_am_tar --version) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && break - done - am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x ustar -w "$$tardir"' - am__tar_='pax -L -x ustar -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H ustar -L' - am__tar_='find "$tardir" -print | cpio -o -H ustar -L' - am__untar='cpio -i -H ustar -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_ustar}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 - (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - rm -rf conftest.dir - if test -s conftest.tar; then - { echo "$as_me:$LINENO: $am__untar &5 - ($am__untar &5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 - (cat conftest.dir/file) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - grep GrepMe conftest.dir/file >/dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - if test ${am_cv_prog_tar_ustar+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) am_cv_prog_tar_ustar=$_am_tool ;; -esac -fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 -printf '%s\n' "$am_cv_prog_tar_ustar" >&6; } - - - - - -depcc="$CC" am_compiler_list= - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -printf %s "checking dependency style of $depcc... " >&6; } -if test ${am_cv_CC_dependencies_compiler_type+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thus: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -printf '%s\n' "$am_cv_CC_dependencies_compiler_type" >&6; } -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' -else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi - - -# Variables for tags utilities; see am/tags.am -if test -z "$CTAGS"; then - CTAGS=ctags -fi - -if test -z "$ETAGS"; then - ETAGS=etags -fi - -if test -z "$CSCOPE"; then - CSCOPE=cscope -fi - - - - - - - - -# Initialize libtool -case `pwd` in - *\ * | *\ *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 -printf '%s\n' "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; -esac - - - -macro_version='2.5.4' -macro_revision='2.5.4' - - - - - - - - - - - - - - -ltmain=$ac_aux_dir/ltmain.sh - - - - # Make sure we can run config.sub. -$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -printf %s "checking build system type... " >&6; } -if test ${ac_cv_build+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -printf '%s\n' "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`printf '%s\n' "$build_os" | sed 's/ /-/g'`;; esac - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -printf %s "checking host system type... " >&6; } -if test ${ac_cv_host+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -printf '%s\n' "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`printf '%s\n' "$host_os" | sed 's/ /-/g'`;; esac - - -# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 -printf %s "checking how to print strings... " >&6; } -# Test print first, because it will be a builtin if present. -if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "" -} - -case $ECHO in - printf*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: printf" >&5 -printf '%s\n' "printf" >&6; } ;; - print*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 -printf '%s\n' "print -r" >&6; } ;; - *) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: cat" >&5 -printf '%s\n' "cat" >&6; } ;; -esac - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -printf %s "checking for a sed that does not truncate output... " >&6; } -if test ${ac_cv_path_SED+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in sed gsed - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -printf '%s\n' "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - -test -z "$SED" && SED=sed -Xsed="$SED -e 1s/^X//" - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in grep ggrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf '%s\n' "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in egrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf '%s\n' "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - EGREP_TRADITIONAL=$EGREP - ac_cv_path_EGREP_TRADITIONAL=$EGREP - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 -printf %s "checking for fgrep... " >&6; } -if test ${ac_cv_path_FGREP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 - then ac_cv_path_FGREP="$GREP -F" - else - if test -z "$FGREP"; then - ac_path_FGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in fgrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_FGREP" || continue -# Check for GNU ac_path_FGREP and select it if it is found. - # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in @%:@( -*GNU*) - ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; -@%:@( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'FGREP' >> "conftest.nl" - "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_FGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_FGREP="$ac_path_FGREP" - ac_path_FGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_FGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_FGREP"; then - as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_FGREP=$FGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 -printf '%s\n' "$ac_cv_path_FGREP" >&6; } - FGREP="$ac_cv_path_FGREP" - - -test -z "$GREP" && GREP=grep - - - - - - - - - - - - - - - - - - - -@%:@ Check whether --with-gnu-ld was given. -if test ${with_gnu_ld+y} -then : - withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes -else case e in @%:@( - e) with_gnu_ld=no ;; -esac -fi - -ac_prog=ld -if test yes = "$GCC"; then - # Check if gcc -print-prog-name=ld gives a path. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -printf %s "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw* | *-*-windows*) - # gcc leaves a trailing carriage return, which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD=$ac_prog - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test yes = "$with_gnu_ld"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -printf %s "checking for GNU ld... " >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -printf %s "checking for non-GNU ld... " >&6; } -fi -if test ${lt_cv_path_LD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -z "$LD"; then - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD=$ac_dir/$ac_prog - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -printf '%s\n' "$LD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -printf %s "checking if the linker ($LD) is GNU ld... " >&6; } -if test ${lt_cv_prog_gnu_ld+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -printf '%s\n' "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 -printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if test ${lt_cv_path_NM+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM=$NM -else - lt_nm_to_check=${ac_tool_prefix}nm - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - tmp_nm=$ac_dir/$lt_tmp_nm - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the 'sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty - case $build_os in - mingw* | windows*) lt_bad_file=conftest.nm/nofile ;; - *) lt_bad_file=/dev/null ;; - esac - case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in - *$lt_bad_file* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break 2 - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break 2 - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS=$lt_save_ifs - done - : ${lt_cv_path_NM=no} -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 -printf '%s\n' "$lt_cv_path_NM" >&6; } -if test no != "$lt_cv_path_NM"; then - NM=$lt_cv_path_NM -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - if test -n "$ac_tool_prefix"; then - for ac_prog in dumpbin "link -dump" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DUMPBIN"; then - ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DUMPBIN=$ac_cv_prog_DUMPBIN -if test -n "$DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 -printf '%s\n' "$DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$DUMPBIN" && break - done -fi -if test -z "$DUMPBIN"; then - ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in dumpbin "link -dump" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DUMPBIN"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN -if test -n "$ac_ct_DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 -printf '%s\n' "$ac_ct_DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_DUMPBIN" && break -done - - if test "x$ac_ct_DUMPBIN" = x; then - DUMPBIN=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DUMPBIN=$ac_ct_DUMPBIN - fi -fi - - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols -headers" - ;; - *) - DUMPBIN=: - ;; - esac - fi - - if test : != "$DUMPBIN"; then - NM=$DUMPBIN - fi -fi -test -z "$NM" && NM=nm - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 -printf %s "checking the name lister ($NM) interface... " >&6; } -if test ${lt_cv_nm_interface+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: output\"" >&5) - cat conftest.out >&5 - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 -printf '%s\n' "$lt_cv_nm_interface" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -printf %s "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -printf '%s\n' "no, using $LN_S" >&6; } -fi - -# find the maximum length of command line arguments -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 -printf %s "checking the maximum length of command line arguments... " >&6; } -if test ${lt_cv_sys_max_cmd_len+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) i=0 - teststring=ABCD - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu* | ironclad*) - # Under GNU Hurd and Ironclad, this test is not required because there - # is no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | windows* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[ ]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test X`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test 17 != "$i" # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac - ;; -esac -fi - -if test -n "$lt_cv_sys_max_cmd_len"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 -printf '%s\n' "$lt_cv_sys_max_cmd_len" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none" >&5 -printf '%s\n' "none" >&6; } -fi -max_cmd_len=$lt_cv_sys_max_cmd_len - - - - - - -: ${CP="cp -f"} -: ${MV="mv -f"} -: ${RM="rm -f"} - -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - lt_unset=unset -else - lt_unset=false -fi - - - - - -# test EBCDIC or ASCII -case `echo X|tr X '\101'` in - A) # ASCII based system - # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr - lt_SP2NL='tr \040 \012' - lt_NL2SP='tr \015\012 \040\040' - ;; - *) # EBCDIC based system - lt_SP2NL='tr \100 \n' - lt_NL2SP='tr \r\n \100\100' - ;; -esac - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 -printf %s "checking how to convert $build file names to $host format... " >&6; } -if test ${lt_cv_to_host_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $host in - *-*-mingw* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 - ;; - esac - ;; - *-*-cygwin* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin - ;; - esac - ;; - * ) # unhandled hosts (and "normal" native builds) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; -esac - ;; -esac -fi - -to_host_file_cmd=$lt_cv_to_host_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_host_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 -printf %s "checking how to convert $build file names to toolchain format... " >&6; } -if test ${lt_cv_to_tool_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) #assume ordinary cross tools, or native build. -lt_cv_to_tool_file_cmd=func_convert_file_noop -case $host in - *-*-mingw* | *-*-windows* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 - ;; - esac - ;; -esac - ;; -esac -fi - -to_tool_file_cmd=$lt_cv_to_tool_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_tool_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 -printf %s "checking for $LD option to reload object files... " >&6; } -if test ${lt_cv_ld_reload_flag+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_reload_flag='-r' ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 -printf '%s\n' "$lt_cv_ld_reload_flag" >&6; } -reload_flag=$lt_cv_ld_reload_flag -case $reload_flag in -"" | " "*) ;; -*) reload_flag=" $reload_flag" ;; -esac -reload_cmds='$LD$reload_flag -o $output$reload_objs' -case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - if test yes != "$GCC"; then - reload_cmds=false - fi - ;; - darwin*) - if test yes = "$GCC"; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' - else - reload_cmds='$LD$reload_flag -o $output$reload_objs' - fi - ;; -esac - - - - - - - - - -# Extract the first word of "file", so it can be a program name with args. -set dummy file; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_FILECMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$FILECMD"; then - ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FILECMD="file" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_prog_FILECMD" && ac_cv_prog_FILECMD=":" -fi ;; -esac -fi -FILECMD=$ac_cv_prog_FILECMD -if test -n "$FILECMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 -printf '%s\n' "$FILECMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -printf '%s\n' "$OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -printf '%s\n' "$ac_ct_OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 -printf %s "checking how to recognize dependent libraries... " >&6; } -if test ${lt_cv_deplibs_check_method+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# 'unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'file_magic [[regex]]' -- check by looking for files in library path -# that responds to the $file_magic_cmd with a given extended regex. -# If you have 'file' or equivalent on your system and you're not sure -# whether 'pass_all' will *always* work, you probably want this one. - -case $host_os in -aix[4-9]*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[45]*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='$FILECMD -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | windows* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - if ( file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -cegcc*) - # use the weaker test based on 'objdump'. See mingw*. - lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly* | midnightbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -haiku*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=$FILECMD - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[3-9]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -*-mlibc) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -*nto* | *qnx*) - lt_cv_deplibs_check_method=pass_all - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -serenity*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -tpf*) - lt_cv_deplibs_check_method=pass_all - ;; -os2*) - lt_cv_deplibs_check_method=pass_all - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 -printf '%s\n' "$lt_cv_deplibs_check_method" >&6; } - -file_magic_glob= -want_nocaseglob=no -if test "$build" = "$host"; then - case $host_os in - mingw* | windows* | pw32*) - if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then - want_nocaseglob=yes - else - file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` - fi - ;; - esac -fi - -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - - - - - - - - - - - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -printf '%s\n' "$DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -printf '%s\n' "$ac_ct_DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 -printf %s "checking how to associate runtime and link libraries... " >&6; } -if test ${lt_cv_sharedlib_from_linklib_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_sharedlib_from_linklib_cmd='unknown' - -case $host_os in -cygwin* | mingw* | windows* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh; - # decide which one to use based on capabilities of $DLLTOOL - case `$DLLTOOL --help 2>&1` in - *--identify-strict*) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib - ;; - *) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback - ;; - esac - ;; -*) - # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd=$ECHO - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 -printf '%s\n' "$lt_cv_sharedlib_from_linklib_cmd" >&6; } -sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd -test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -printf '%s\n' "$RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -printf '%s\n' "$ac_ct_RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AR+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -printf '%s\n' "$AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_AR+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -printf '%s\n' "$ac_ct_AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -: ${AR=ar} - - - - - - -# Use ARFLAGS variable as AR's operation code to sync the variable naming with -# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have -# higher priority because that's what people were doing historically (setting -# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS -# variable obsoleted/removed. - -test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} -lt_ar_flags=$AR_FLAGS - - - - - - -# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override -# by AR_FLAGS because that was never working and AR_FLAGS is about to die. - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 -printf %s "checking for archiver @FILE support... " >&6; } -if test ${lt_cv_ar_at_file+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ar_at_file=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - echo conftest.$ac_objext > conftest.lst - lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -eq "$ac_status"; then - # Ensure the archiver fails upon bogus file names. - rm -f conftest.$ac_objext libconftest.a - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -ne "$ac_status"; then - lt_cv_ar_at_file=@ - fi - fi - rm -f conftest.* libconftest.a - -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 -printf '%s\n' "$lt_cv_ar_at_file" >&6; } - -if test no = "$lt_cv_ar_at_file"; then - archiver_list_spec= -else - archiver_list_spec=$lt_cv_ar_at_file -fi - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -test -z "$STRIP" && STRIP=: - - - - - - - -test -z "$RANLIB" && RANLIB=: - - - - - - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# Check for command to grab the raw symbol name followed by C symbol from nm. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 -printf %s "checking command to parse $NM output from $compiler object... " >&6; } -if test ${lt_cv_sys_global_symbol_pipe+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw* | windows* | pw32* | cegcc*) - symcode='[ABCDGISTW]' - ;; -hpux*) - if test ia64 = "$host_cpu"; then - symcode='[ABCDEGRST]' - fi - ;; -irix* | nonstopux*) - symcode='[BCDEGRST]' - ;; -osf*) - symcode='[BCDEGQRST]' - ;; -solaris*) - symcode='[BCDRT]' - ;; -sco3.2v5*) - symcode='[DT]' - ;; -sysv4.2uw2*) - symcode='[DT]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[ABDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[ABCDGIRSTW]' ;; -esac - -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Gets list of data symbols to import. - lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" - # Adjust the below global symbol transforms to fixup imported variables. - lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" - lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" - lt_c_name_lib_hook="\ - -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ - -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" -else - # Disable hooks by default. - lt_cv_sys_global_symbol_to_import= - lt_cdecl_hook= - lt_c_name_hook= - lt_c_name_lib_hook= -fi - -# Transform an extracted symbol line into a proper C declaration. -# Some systems (esp. on ia64) link data and code symbols differently, -# so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ -$lt_cdecl_hook\ -" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ -$lt_c_name_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" - -# Transform an extracted symbol line into symbol name with lib prefix and -# symbol address. -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ -$lt_c_name_lib_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw* | windows*) - opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# Try without a prefix underscore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function, - # D for any global variable and I for any imported variable. - # Also find C++ and __fastcall symbols from MSVC++ or ICC, - # which start with @ or ?. - lt_cv_sys_global_symbol_pipe="$AWK '"\ -" {last_section=section; section=\$ 3};"\ -" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ -" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ -" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ -" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ -" \$ 0!~/External *\|/{next};"\ -" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ -" {if(hide[section]) next};"\ -" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ -" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ -" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ -" ' prfx=^$ac_symprfx" - else - lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <<_LT_EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(void); -void nm_test_func(void){} -#ifdef __cplusplus -} -#endif -int main(void){nm_test_var='a';nm_test_func();return(0);} -_LT_EOF - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Now try to grab the symbols. - nlist=conftest.nm - $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 - if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if $GREP ' nm_test_var$' "$nlist" >/dev/null; then - if $GREP ' nm_test_func$' "$nlist" >/dev/null; then - cat <<_LT_EOF > conftest.$ac_ext -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE -/* DATA imports from DLLs on WIN32 can't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT@&t@_DLSYM_CONST -#elif defined __osf__ -/* This system does not cope well with relocations in const data. */ -# define LT@&t@_DLSYM_CONST -#else -# define LT@&t@_DLSYM_CONST const -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -_LT_EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' - - cat <<_LT_EOF >> conftest.$ac_ext - -/* The mapping between symbol names and symbols. */ -LT@&t@_DLSYM_CONST struct { - const char *name; - void *address; -} -lt__PROGRAM__LTX_preloaded_symbols[] = -{ - { "@PROGRAM@", (void *) 0 }, -_LT_EOF - $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext - cat <<\_LT_EOF >> conftest.$ac_ext - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt__PROGRAM__LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif -_LT_EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_globsym_save_LIBS=$LIBS - lt_globsym_save_CFLAGS=$CFLAGS - LIBS=conftstm.$ac_objext - CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest$ac_exeext; then - pipe_works=yes - fi - LIBS=$lt_globsym_save_LIBS - CFLAGS=$lt_globsym_save_CFLAGS - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - fi - rm -rf conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test yes = "$pipe_works"; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done - ;; -esac -fi - -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -printf '%s\n' "failed" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ok" >&5 -printf '%s\n' "ok" >&6; } -fi - -# Response file support. -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - nm_file_list_spec='@' -elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then - nm_file_list_spec='@' -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 -printf %s "checking for sysroot... " >&6; } - -@%:@ Check whether --with-sysroot was given. -if test ${with_sysroot+y} -then : - withval=$with_sysroot; -else case e in @%:@( - e) with_sysroot=no ;; -esac -fi - - -lt_sysroot= -case $with_sysroot in #( - yes) - if test yes = "$GCC"; then - # Trim trailing / since we'll always append absolute paths and we want - # to avoid //, if only for less confusing output for the user. - lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 -printf '%s\n' "$with_sysroot" >&6; } - as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 - ;; -esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 -printf '%s\n' "${lt_sysroot:-no}" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 -printf %s "checking for a working dd... " >&6; } -if test ${ac_cv_path_lt_DD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -: ${lt_DD:=$DD} -if test -z "$lt_DD"; then - ac_path_lt_DD_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in dd - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_lt_DD" || continue -if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: -fi - $ac_path_lt_DD_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_lt_DD"; then - : - fi -else - ac_cv_path_lt_DD=$lt_DD -fi - -rm -f conftest.i conftest2.i conftest.out ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 -printf '%s\n' "$ac_cv_path_lt_DD" >&6; } - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 -printf %s "checking how to truncate binary pipes... " >&6; } -if test ${lt_cv_truncate_bin+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -lt_cv_truncate_bin= -if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" -fi -rm -f conftest.i conftest2.i conftest.out -test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 -printf '%s\n' "$lt_cv_truncate_bin" >&6; } - - - - - - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in @S|@*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - -@%:@ Check whether --enable-libtool-lock was given. -if test ${enable_libtool_lock+y} -then : - enableval=$enable_libtool_lock; -fi - -test no = "$enable_libtool_lock" || enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out what ABI is being produced by ac_compile, and set mode - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE=32 - ;; - *ELF-64*) - HPUX_IA64_MODE=64 - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - if test yes = "$lt_cv_prog_gnu_ld"; then - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -mips64*-*linux*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - emul=elf - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - emul="${emul}32" - ;; - *64-bit*) - emul="${emul}64" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *MSB*) - emul="${emul}btsmip" - ;; - *LSB*) - emul="${emul}ltsmip" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *N32*) - emul="${emul}n32" - ;; - esac - LD="${LD-ld} -m $emul" - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. Note that the listed cases only cover the - # situations where additional linker options are needed (such as when - # doing 32-bit compilation for a host where ld defaults to 64-bit, or - # vice versa); the common cases where no linker options are needed do - # not appear in the list. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - case `$FILECMD conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac - ;; - powerpc64le-*linux*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - LD="${LD-ld} -m elf_x86_64" - ;; - powerpcle-*linux*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -belf" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 -printf %s "checking whether the C compiler needs -belf... " >&6; } -if test ${lt_cv_cc_needs_belf+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_cc_needs_belf=yes -else case e in @%:@( - e) lt_cv_cc_needs_belf=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 -printf '%s\n' "$lt_cv_cc_needs_belf" >&6; } - if test yes != "$lt_cv_cc_needs_belf"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS=$SAVE_CFLAGS - fi - ;; -*-*solaris*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) - case $host in - i?86-*-solaris*|x86_64-*-solaris*) - LD="${LD-ld} -m elf_x86_64" - ;; - sparc*-*-solaris*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - # GNU ld 2.21 introduced _sol2 emulations. Use them if available. - if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD=${LD-ld}_sol2 - fi - ;; - *) - if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then - LD="${LD-ld} -64" - fi - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; -esac - -need_locks=$enable_libtool_lock - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. -set dummy ${ac_tool_prefix}mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$MANIFEST_TOOL"; then - ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL -if test -n "$MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 -printf '%s\n' "$MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_MANIFEST_TOOL"; then - ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL - # Extract the first word of "mt", so it can be a program name with args. -set dummy mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_MANIFEST_TOOL"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL -if test -n "$ac_ct_MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 -printf '%s\n' "$ac_ct_MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_MANIFEST_TOOL" = x; then - MANIFEST_TOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL - fi -else - MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" -fi - -test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 -printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } -if test ${lt_cv_path_manifest_tool+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_path_manifest_tool=no - echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 - $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out - cat conftest.err >&5 - if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_manifest_tool=yes - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_manifest_tool" >&5 -printf '%s\n' "$lt_cv_path_manifest_tool" >&6; } -if test yes != "$lt_cv_path_manifest_tool"; then - MANIFEST_TOOL=: -fi - - - - - - - case $host_os in - rhapsody* | darwin*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. -set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$DSYMUTIL"; then - ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DSYMUTIL=$ac_cv_prog_DSYMUTIL -if test -n "$DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 -printf '%s\n' "$DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DSYMUTIL"; then - ac_ct_DSYMUTIL=$DSYMUTIL - # Extract the first word of "dsymutil", so it can be a program name with args. -set dummy dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_DSYMUTIL"; then - ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL -if test -n "$ac_ct_DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 -printf '%s\n' "$ac_ct_DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DSYMUTIL" = x; then - DSYMUTIL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DSYMUTIL=$ac_ct_DSYMUTIL - fi -else - DSYMUTIL="$ac_cv_prog_DSYMUTIL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. -set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$NMEDIT"; then - ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -NMEDIT=$ac_cv_prog_NMEDIT -if test -n "$NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 -printf '%s\n' "$NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_NMEDIT"; then - ac_ct_NMEDIT=$NMEDIT - # Extract the first word of "nmedit", so it can be a program name with args. -set dummy nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_NMEDIT"; then - ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_NMEDIT="nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT -if test -n "$ac_ct_NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 -printf '%s\n' "$ac_ct_NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_NMEDIT" = x; then - NMEDIT=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - NMEDIT=$ac_ct_NMEDIT - fi -else - NMEDIT="$ac_cv_prog_NMEDIT" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. -set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$LIPO"; then - ac_cv_prog_LIPO="$LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -LIPO=$ac_cv_prog_LIPO -if test -n "$LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 -printf '%s\n' "$LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LIPO"; then - ac_ct_LIPO=$LIPO - # Extract the first word of "lipo", so it can be a program name with args. -set dummy lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_LIPO"; then - ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_LIPO="lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO -if test -n "$ac_ct_LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 -printf '%s\n' "$ac_ct_LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_LIPO" = x; then - LIPO=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LIPO=$ac_ct_LIPO - fi -else - LIPO="$ac_cv_prog_LIPO" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -printf '%s\n' "$OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL="otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -printf '%s\n' "$ac_ct_OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$OTOOL64"; then - ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL64=$ac_cv_prog_OTOOL64 -if test -n "$OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 -printf '%s\n' "$OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL64"; then - ac_ct_OTOOL64=$OTOOL64 - # Extract the first word of "otool64", so it can be a program name with args. -set dummy otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test -n "$ac_ct_OTOOL64"; then - ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL64="otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 -if test -n "$ac_ct_OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 -printf '%s\n' "$ac_ct_OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL64" = x; then - OTOOL64=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL64=$ac_ct_OTOOL64 - fi -else - OTOOL64="$ac_cv_prog_OTOOL64" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 -printf %s "checking for -single_module linker flag... " >&6; } -if test ${lt_cv_apple_cc_single_mod+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_apple_cc_single_mod=no - if test -z "$LT_MULTI_MODULE"; then - # By default we will add the -single_module flag. You can override - # by either setting the environment variable LT_MULTI_MODULE - # non-empty at configure time, or by adding -multi_module to the - # link flags. - rm -rf libconftest.dylib* - echo "int foo(void){return 1;}" > conftest.c - echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ --dynamiclib -Wl,-single_module conftest.c" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ - -dynamiclib -Wl,-single_module conftest.c 2>conftest.err - _lt_result=$? - # If there is a non-empty error log, and "single_module" - # appears in it, assume the flag caused a linker warning - if test -s conftest.err && $GREP single_module conftest.err; then - cat conftest.err >&5 - # Otherwise, if the output was created with a 0 exit code from - # the compiler, it worked. - elif test -f libconftest.dylib && test 0 = "$_lt_result"; then - lt_cv_apple_cc_single_mod=yes - else - cat conftest.err >&5 - fi - rm -rf libconftest.dylib* - rm -f conftest.* - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 -printf '%s\n' "$lt_cv_apple_cc_single_mod" >&6; } - - # Feature test to disable chained fixups since it is not - # compatible with '-undefined dynamic_lookup' - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -no_fixup_chains linker flag" >&5 -printf %s "checking for -no_fixup_chains linker flag... " >&6; } -if test ${lt_cv_support_no_fixup_chains+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -Wl,-no_fixup_chains" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_support_no_fixup_chains=yes -else case e in @%:@( - e) lt_cv_support_no_fixup_chains=no - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_support_no_fixup_chains" >&5 -printf '%s\n' "$lt_cv_support_no_fixup_chains" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 -printf %s "checking for -exported_symbols_list linker flag... " >&6; } -if test ${lt_cv_ld_exported_symbols_list+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_exported_symbols_list=no - save_LDFLAGS=$LDFLAGS - echo "_main" > conftest.sym - LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_ld_exported_symbols_list=yes -else case e in @%:@( - e) lt_cv_ld_exported_symbols_list=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 -printf '%s\n' "$lt_cv_ld_exported_symbols_list" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 -printf %s "checking for -force_load linker flag... " >&6; } -if test ${lt_cv_ld_force_load+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5 - $AR $AR_FLAGS libconftest.a conftest.o 2>&5 - echo "$RANLIB libconftest.a" >&5 - $RANLIB libconftest.a 2>&5 - cat > conftest.c << _LT_EOF -int main(void) { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -s conftest.err && $GREP force_load conftest.err; then - cat conftest.err >&5 - elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&5 - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 -printf '%s\n' "$lt_cv_ld_force_load" >&6; } - case $host_os in - rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; - darwin1.*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - darwin*) - case $MACOSX_DEPLOYMENT_TARGET,$host in - 10.[012],*|,*powerpc*-darwin[5-8]*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - *) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' - if test yes = "$lt_cv_support_no_fixup_chains"; then - as_fn_append _lt_dar_allow_undefined ' $wl-no_fixup_chains' - fi - ;; - esac - ;; - esac - if test yes = "$lt_cv_apple_cc_single_mod"; then - _lt_dar_single_mod='$single_module' - fi - _lt_dar_needs_single_mod=no - case $host_os in - rhapsody* | darwin1.*) - _lt_dar_needs_single_mod=yes ;; - darwin*) - # When targeting Mac OS X 10.4 (darwin 8) or later, - # -single_module is the default and -multi_module is unsupported. - # The toolchain on macOS 10.14 (darwin 18) and later cannot - # target any OS version that needs -single_module. - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*-darwin[567].*|10.[0-3],*-darwin[5-9].*|10.[0-3],*-darwin1[0-7].*) - _lt_dar_needs_single_mod=yes ;; - esac - ;; - esac - if test yes = "$lt_cv_ld_exported_symbols_list"; then - _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' - else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' - fi - if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then - _lt_dsymutil='~$DSYMUTIL $lib || :' - else - _lt_dsymutil= - fi - ;; - esac - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x@S|@2 in - x) - ;; - *:) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" - ;; - x:*) - eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" - ;; - *) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - esac -} - -ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default -" -if test "x$ac_cv_header_dlfcn_h" = xyes -then : - printf '%s\n' "@%:@define HAVE_DLFCN_H 1" >>confdefs.h - -fi - - - - - -# Set options - - - - enable_dlopen=no - - - enable_win32_dll=no - - - @%:@ Check whether --enable-shared was given. -if test ${enable_shared+y} -then : - enableval=$enable_shared; p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_shared=yes ;; -esac -fi - - - - - - - - - - @%:@ Check whether --enable-static was given. -if test ${enable_static+y} -then : - enableval=$enable_static; p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_static=yes ;; -esac -fi - - - - - - - - - - @%:@ Check whether --enable-pic was given. -if test ${enable_pic+y} -then : - enableval=$enable_pic; lt_p=${PACKAGE-default} - case $enableval in - yes|no) pic_mode=$enableval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) @%:@ Check whether --with-pic was given. -if test ${with_pic+y} -then : - withval=$with_pic; lt_p=${PACKAGE-default} - case $withval in - yes|no) pic_mode=$withval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $withval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) pic_mode=default ;; -esac -fi - - ;; -esac -fi - - - - - - - - - @%:@ Check whether --enable-fast-install was given. -if test ${enable_fast_install+y} -then : - enableval=$enable_fast_install; p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in @%:@( - e) enable_fast_install=yes ;; -esac -fi - - - - - - - - - shared_archive_member_spec= -case $host,$enable_shared in -power*-*-aix[5-9]*,yes) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 -printf %s "checking which variant of shared library versioning to provide... " >&6; } - @%:@ Check whether --enable-aix-soname was given. -if test ${enable_aix_soname+y} -then : - enableval=$enable_aix_soname; case $enableval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --enable-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$enable_aix_soname -else case e in @%:@( - e) @%:@ Check whether --with-aix-soname was given. -if test ${with_aix_soname+y} -then : - withval=$with_aix_soname; case $withval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$with_aix_soname -else case e in @%:@( - e) if test ${lt_cv_with_aix_soname+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_with_aix_soname=aix ;; -esac -fi - ;; -esac -fi - - enable_aix_soname=$lt_cv_with_aix_soname ;; -esac -fi - - with_aix_soname=$enable_aix_soname - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 -printf '%s\n' "$with_aix_soname" >&6; } - if test aix != "$with_aix_soname"; then - # For the AIX way of multilib, we name the shared archive member - # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', - # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. - # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, - # the AIX toolchain works better with OBJECT_MODE set (default 32). - if test 64 = "${OBJECT_MODE-32}"; then - shared_archive_member_spec=shr_64 - else - shared_archive_member_spec=shr - fi - fi - ;; -*) - with_aix_soname=aix - ;; -esac - - - - - - - - - - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS=$ltmain - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -test -z "$LN_S" && LN_S="ln -s" - - - - - - - - - - - - - - -if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 -printf %s "checking for objdir... " >&6; } -if test ${lt_cv_objdir+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 -printf '%s\n' "$lt_cv_objdir" >&6; } -objdir=$lt_cv_objdir - - - - - -printf '%s\n' "@%:@define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h - - - - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Global variables: -ofile=libtool -can_build_shared=yes - -# All known linkers require a '.a' archive for static linking (except MSVC and -# ICC, which need '.lib'). -libext=a - -with_gnu_ld=$lt_cv_prog_gnu_ld - -old_CC=$CC -old_CFLAGS=$CFLAGS - -# Set sane defaults for various variables -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$LD" && LD=ld -test -z "$ac_objext" && ac_objext=o - -func_cc_basename $compiler -cc_basename=$func_cc_basename_result - - -# Only perform the check for file, if the check method requires it -test -z "$MAGIC_CMD" && MAGIC_CMD=file -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 -printf %s "checking for ${ac_tool_prefix}file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/${ac_tool_prefix}file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for file" >&5 -printf %s "checking for file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - else - MAGIC_CMD=: - fi -fi - - fi - ;; -esac - -# Use C for the default configuration in the libtool script - -lt_save_CC=$CC -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -objext=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(void){return(0);}' - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - -# Save the default compiler, since it gets overwritten when the other -# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. -compiler_DEFAULT=$CC - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - -lt_prog_compiler_no_builtin_flag= - -if test yes = "$GCC"; then - case $cc_basename in - nvcc*) - lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; - *) - lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; - esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if test ${lt_cv_prog_compiler_rtti_exceptions+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -printf '%s\n' "$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then - lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" -else - : -fi - -fi - - - - - - - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - - - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - -hard_links=nottested -if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then - # do not overwrite the value of need_locks provided by the user - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -printf %s "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -printf '%s\n' "$hard_links" >&6; } - if test no = "$hard_links"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 -printf '%s\n' "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - runpath_var= - allow_undefined_flag= - always_export_symbols=no - archive_cmds= - archive_expsym_cmds= - compiler_needs_object=no - enable_shared_with_static_runtimes=no - export_dynamic_flag_spec= - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - hardcode_automatic=no - hardcode_direct=no - hardcode_direct_absolute=no - hardcode_libdir_flag_spec= - hardcode_libdir_separator= - hardcode_minus_L=no - hardcode_shlibpath_var=unsupported - inherit_rpath=no - link_all_deplibs=unknown - module_cmds= - module_expsym_cmds= - old_archive_from_new_cmds= - old_archive_from_expsyms_cmds= - thread_safe_flag_spec= - whole_archive_flag_spec= - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ' (' and ')$', so one must not match beginning or - # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', - # as well as any symbol that contains 'd'. - exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - # Exclude shared library initialization/finalization symbols. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - if test yes != "$GCC"; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) - with_gnu_ld=yes - ;; - esac - - ld_shlibs=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test yes = "$with_gnu_ld"; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; - *\ \(GNU\ Binutils\)\ [3-9]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test yes = "$lt_use_gnu_ld_interface"; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='$wl' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='$wl--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' - else - whole_archive_flag_spec= - fi - supports_anon_versioning=no - case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test ia64 != "$host_cpu"; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.19, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. - -_LT_EOF - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='$wl--export-all-symbols' - allow_undefined_flag=unsupported - always_export_symbols=no - enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' - file_list_spec='@' - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file, use it as - # is; otherwise, prepend EXPORTS... - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs=no - fi - ;; - - haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - link_all_deplibs=no - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - interix[3-9]*) - hardcode_direct=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) - tmp_diet=no - if test linux-dietlibc = "$host_os"; then - case $cc_basename in - diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) - esac - fi - if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test no = "$tmp_diet" - then - tmp_addflag=' $pic_flag' - tmp_sharedflag='-shared' - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - lf95*) # Lahey Fortran 8.1 - whole_archive_flag_spec= - tmp_sharedflag='--shared' ;; - nagfor*) # NAGFOR 5.3 - tmp_sharedflag='-Wl,-shared' ;; - xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) - tmp_sharedflag='-qmkshrobj' - tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - ;; - esac - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' - fi - - case $cc_basename in - tcc*) - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='-rdynamic' - ;; - xlf* | bgf* | bgxlf* | mpixlf*) - # IBM XL Fortran 10.1 on PPC cannot create shared libs itself - whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' - fi - ;; - esac - else - ld_shlibs=no - fi - ;; - - *-mlibc) - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test no = "$ld_shlibs"; then - runpath_var= - hardcode_libdir_flag_spec= - export_dynamic_flag_spec= - whole_archive_flag_spec= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix[4-9]*) - if test ia64 = "$host_cpu"; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag= - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to GNU nm, but means don't demangle to AIX nm. - # Without the "-l" option, or with the "-B" option, AIX nm treats - # weak defined symbols like other global defined symbols, whereas - # GNU nm marks them as "W". - # While the 'weak' keyword is ignored in the Export File, we need - # it in the Import File for the 'aix-soname' feature, so we have - # to replace the "-B" option with "-P" for AIX nm. - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # have runtime linking enabled, and use it for executables. - # For shared libraries, we enable/disable runtime linking - # depending on the kind of the shared library created - - # when "with_aix_soname,aix_use_runtimelinking" is: - # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables - # "aix,yes" lib.so shared, rtl:yes, for executables - # lib.a static archive - # "both,no" lib.so.V(shr.o) shared, rtl:yes - # lib.a(lib.so.V) shared, rtl:no, for executables - # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a(lib.so.V) shared, rtl:no - # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a static archive - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then - aix_use_runtimelinking=yes - break - fi - done - if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then - # With aix-soname=svr4, we create the lib.so.V shared archives only, - # so we don't have lib.a shared libs to link our executables. - # We have to force runtime linking in this case. - aix_use_runtimelinking=yes - LDFLAGS="$LDFLAGS -Wl,-brtl" - fi - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds='' - hardcode_direct=yes - hardcode_direct_absolute=yes - hardcode_libdir_separator=':' - link_all_deplibs=yes - file_list_spec='$wl-f,' - case $with_aix_soname,$aix_use_runtimelinking in - aix,*) ;; # traditional, no import file - svr4,* | *,yes) # use import file - # The Import File defines what to hardcode. - hardcode_direct=no - hardcode_direct_absolute=no - ;; - esac - - if test yes = "$GCC"; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`$CC -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - shared_flag='-shared' - if test yes = "$aix_use_runtimelinking"; then - shared_flag="$shared_flag "'$wl-G' - fi - # Need to ensure runtime linking is disabled for the traditional - # shared library, or the linker may eventually find shared libraries - # /with/ Import File - we do not want to mix them. - shared_flag_aix='-shared' - shared_flag_svr4='-shared $wl-G' - else - # not using gcc - if test ia64 = "$host_cpu"; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test yes = "$aix_use_runtimelinking"; then - shared_flag='$wl-G' - else - shared_flag='$wl-bM:SRE' - fi - shared_flag_aix='$wl-bM:SRE' - shared_flag_svr4='$wl-G' - fi - fi - - export_dynamic_flag_spec='$wl-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols=yes - if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag='-berok' - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag - else - if test ia64 = "$host_cpu"; then - hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' - allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag=' $wl-bernotok' - allow_undefined_flag=' $wl-berok' - if test yes = "$with_gnu_ld"; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - fi - archive_cmds_need_lc=yes - archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' - # -brtl affects multiple linker settings, -berok does not and is overridden later - compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' - if test svr4 != "$with_aix_soname"; then - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' - fi - if test aix != "$with_aix_soname"; then - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' - else - # used by -dlpreopen to get the symbols - archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' - fi - archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' - fi - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - bsdi[45]*) - export_dynamic_flag_spec=-rdynamic - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - case $cc_basename in - cl* | icl*) - # Native MSVC or ICC - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - always_export_symbols=yes - file_list_spec='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -Fe$output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp "$export_symbols" "$output_objdir/$soname.def"; - echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; - else - $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -Fe$tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, )='true' - enable_shared_with_static_runtimes=yes - exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - # Don't use ranlib - old_postinstall_cmds='chmod 644 $oldlib' - postlink_cmds='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile=$lt_outputfile.exe - lt_tool_outputfile=$lt_tool_outputfile.exe - ;; - esac~ - if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # Assume MSVC and ICC wrapper - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - enable_shared_with_static_runtimes=yes - ;; - esac - ;; - - darwin* | rhapsody*) - - - archive_cmds_need_lc=no - hardcode_direct=no - hardcode_automatic=yes - hardcode_shlibpath_var=unsupported - if test yes = "$lt_cv_ld_force_load"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec='' - fi - link_all_deplibs=yes - allow_undefined_flag=$_lt_dar_allow_undefined - case $cc_basename in - ifort*|nagfor*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test yes = "$_lt_dar_can_shared"; then - output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" - archive_expsym_cmds="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" - module_expsym_cmds="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" - - else - ld_shlibs=no - fi - - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly* | midnightbsd*) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9*) - if test yes = "$GCC"; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - export_dynamic_flag_spec='$wl-E' - ;; - - hpux10*) - if test yes,no = "$GCC,$with_gnu_ld"; then - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - - hpux11*) - if test yes,no = "$GCC,$with_gnu_ld"; then - case $host_cpu in - hppa*64*) - archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 -printf %s "checking if $CC understands -b... " >&6; } -if test ${lt_cv_prog_compiler__b+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler__b=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -b" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler__b=yes - fi - else - lt_cv_prog_compiler__b=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 -printf '%s\n' "$lt_cv_prog_compiler__b" >&6; } - -if test yes = "$lt_cv_prog_compiler__b"; then - archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' -else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' -fi - - ;; - esac - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - hardcode_shlibpath_var=no - ;; - *) - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test yes = "$GCC"; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - # Try to use the -exported_symbol ld option, if it does not - # work, assume that -exports_file does not work either and - # implicitly export all symbols. - # This should be the same for all languages, so no per-tag cache variable. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 -printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } -if test ${lt_cv_irix_exported_symbol+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int foo (void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_irix_exported_symbol=yes -else case e in @%:@( - e) lt_cv_irix_exported_symbol=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 -printf '%s\n' "$lt_cv_irix_exported_symbol" >&6; } - if test yes = "$lt_cv_irix_exported_symbol"; then - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' - fi - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - inherit_rpath=yes - link_all_deplibs=yes - ;; - - linux*) - case $cc_basename in - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - ld_shlibs=yes - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - esac - ;; - - *-mlibc) - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - newsos6) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - hardcode_shlibpath_var=no - ;; - - *nto* | *qnx*) - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - hardcode_shlibpath_var=no - hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - else - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - fi - else - ld_shlibs=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - osf3*) - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - archive_cmds_need_lc='no' - hardcode_libdir_separator=: - ;; - - serenity*) - ;; - - solaris*) - no_undefined_flag=' -z defs' - if test yes = "$GCC"; then - wlarc='$wl' - archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - else - case `$CC -V 2>&1` in - *"Compilers 5.0"*) - wlarc='' - archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' - ;; - *) - wlarc='$wl' - archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - ;; - esac - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands '-z linker_flag'. GCC discards it without '$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test yes = "$GCC"; then - whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' - else - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs=yes - ;; - - sunos4*) - if test sequent = "$host_vendor"; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds='$CC -r -o $output$reload_objs' - hardcode_direct=no - ;; - motorola) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='$wl-z,text' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We CANNOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag='$wl-z,text' - allow_undefined_flag='$wl-z,nodefs' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-R,$libdir' - hardcode_libdir_separator=':' - link_all_deplibs=yes - export_dynamic_flag_spec='$wl-Bexport' - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - *) - ld_shlibs=no - ;; - esac - - if test sni = "$host_vendor"; then - case $host in - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='$wl-Blargedynsym' - ;; - esac - fi - fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 -printf '%s\n' "$ld_shlibs" >&6; } -test no = "$ld_shlibs" && can_build_shared=no - -with_gnu_ld=$with_gnu_ld - - - - - - - - - - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc=yes - - if test yes,yes = "$GCC,$enable_shared"; then - case $archive_cmds in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -printf %s "checking whether -lc should be explicitly linked in... " >&6; } -if test ${lt_cv_archive_cmds_need_lc+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc=no - else - lt_cv_archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 -printf '%s\n' "$lt_cv_archive_cmds_need_lc" >&6; } - archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -printf %s "checking dynamic linker characteristics... " >&6; } - -if test yes = "$GCC"; then - case $host_os in - darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; - *) lt_awk_arg='/^libraries:/' ;; - esac - case $host_os in - mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; - *) lt_sed_strip_eq='s|=/|/|g' ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary... - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - # ...but if some path component already ends with the multilib dir we assume - # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). - case "$lt_multi_os_dir; $lt_search_path_spec " in - "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) - lt_multi_os_dir= - ;; - esac - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" - elif test -n "$lt_multi_os_dir"; then - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS = " "; FS = "/|\n";} { - lt_foo = ""; - lt_count = 0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo = "/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[lt_foo]++; } - if (lt_freq[lt_foo] == 1) { print lt_foo; } -}'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's|/\([A-Za-z]:\)|\1|g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=.so -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - - - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='$libname$release$shared_ext$major' - ;; - -aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test ia64 = "$host_cpu"; then - # AIX 5 supports IA64 - library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line '#! .'. This would cause the generated library to - # depend on '.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # Using Import Files as archive members, it is possible to support - # filename-based versioning of shared library archives on AIX. While - # this would work for both with and without runtime linking, it will - # prevent static linking of such archives. So we do filename-based - # shared library versioning with .so extension only, which is used - # when both runtime linking and shared linking is enabled. - # Unfortunately, runtime linking may impact performance, so we do - # not want this to be the default eventually. Also, we use the - # versioned .so libs for executables only if there is the -brtl - # linker flag in LDFLAGS as well, or --enable-aix-soname=svr4 only. - # To allow for filename-based versioning support, we need to create - # libNAME.so.V as an archive file, containing: - # *) an Import File, referring to the versioned filename of the - # archive as well as the shared archive member, telling the - # bitwidth (32 or 64) of that shared object, and providing the - # list of exported symbols of that shared object, eventually - # decorated with the 'weak' keyword - # *) the shared object with the F_LOADONLY flag set, to really avoid - # it being seen by the linker. - # At run time we better use the real file rather than another symlink, - # but for link time we create the symlink libNAME.so -> libNAME.so.V - - case $with_aix_soname,$aix_use_runtimelinking in - # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - aix,yes) # traditional libtool - dynamic_linker='AIX unversionable lib.so' - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - aix,no) # traditional AIX only - dynamic_linker='AIX lib.a(lib.so.V)' - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - ;; - svr4,*) # full svr4 only - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,yes) # both, prefer svr4 - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # unpreferred sharedlib libNAME.a needs extra handling - postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' - postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,no) # both, prefer aix - dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling - postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' - postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' - ;; - esac - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='$libname$shared_ext' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | windows* | pw32* | cegcc*) - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - # If user builds GCC with multilib enabled, - # it should just install on $(libdir) - # not on $(libdir)/../bin or 32 bits dlls would override 64 bit ones. - if test xyes = x"$multilib"; then - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - $install_prog $dir/$dlname $destdir/$dlname~ - chmod a+x $destdir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib $destdir/$dlname'\'' || exit \$?; - fi' - else - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - fi - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" - ;; - mingw* | windows* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl* | *,icl*) - # Native MSVC or ICC - libname_spec='$name' - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - library_names_spec='$libname.dll.lib' - - case $build_os in - mingw* | windows*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec=$LIB - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC and ICC wrapper - library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' - soname_spec='$libname$release$major$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly* | midnightbsd*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - need_version=yes - ;; - esac - case $host_cpu in - powerpc64) - # On FreeBSD bi-arch platforms, a different variable is used for 32-bit - # binaries. See . - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int test_pointer_size[sizeof (void *) - 5]; - -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - shlibpath_var=LD_LIBRARY_PATH -else case e in @%:@( - e) shlibpath_var=LD_32_LIBRARY_PATH ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; - *) - shlibpath_var=LD_LIBRARY_PATH - ;; - esac - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/boot/system/non-packaged/develop/lib /boot/system/develop/lib' - sys_lib_dlsearch_path_spec='/boot/home/config/non-packaged/lib /boot/home/config/lib /boot/system/non-packaged/lib /boot/system/lib' - hardcode_into_libs=no - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - if test 32 = "$HPUX_IA64_MODE"; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - sys_lib_dlsearch_path_spec=/usr/lib/hpux32 - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - sys_lib_dlsearch_path_spec=/usr/lib/hpux64 - fi - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test yes = "$lt_cv_prog_gnu_ld"; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" - sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -linux*android*) - version_type=none # Android doesn't support versioned libraries. - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - dynamic_linker='Android linker' - # -rpath works at least for libraries that are not overridden by - # libraries installed in system locations. - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if test ${lt_cv_shlibpath_overrides_runpath+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null -then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - ;; -esac -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Ideally, we could use ldconfig to report *all* directories which are - # searched for libraries, however this is still not possible. Aside from not - # being certain /sbin/ldconfig is available, command - # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, - # even though it is searched at run-time. Try to do the best guess by - # appending ld.so.conf contents (and includes) to the search path. - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -*-mlibc) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='mlibc ld.so' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec=/usr/lib - need_lib_prefix=no - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - need_version=no - else - need_version=yes - fi - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -os2*) - libname_spec='$name' - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - # OS/2 can only load a DLL with a base name of 8 characters or less. - soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; - v=$($ECHO $release$versuffix | tr -d .-); - n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); - $ECHO $n$v`$shared_ext' - library_names_spec='${libname}_dll.$libext' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=BEGINLIBPATH - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - -rdos*) - dynamic_linker=no - ;; - -serenity*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - dynamic_linker='SerenityOS LibELF' - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test yes = "$with_gnu_ld"; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec; then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' - soname_spec='$libname$shared_ext.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=sco - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test yes = "$with_gnu_ld"; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -emscripten*) - version_type=none - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - dynamic_linker="Emscripten linker" - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - -='-fPIC' - archive_cmds='$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib -s EXPORTED_FUNCTIONS=@$output_objdir/$soname.expsym' - archive_cmds_need_lc=no - no_undefined_flag= - ;; - -*) - dynamic_linker=no - ;; -esac -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -printf '%s\n' "$dynamic_linker" >&6; } -test no = "$dynamic_linker" && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test yes = "$GCC"; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then - sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec -fi - -if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then - sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec -fi - -# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... -configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec - -# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code -func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" - -# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool -configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -printf %s "checking how to hardcode library paths into programs... " >&6; } -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || - test -n "$runpath_var" || - test yes = "$hardcode_automatic"; then - - # We can hardcode non-existent directories. - if test no != "$hardcode_direct" && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && - test no != "$hardcode_minus_L"; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 -printf '%s\n' "$hardcode_action" >&6; } - -if test relink = "$hardcode_action" || - test yes = "$inherit_rpath"; then - # Fast installation is not supported - enable_fast_install=no -elif test yes = "$shlibpath_overrides_runpath" || - test no = "$enable_shared"; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - if test yes != "$enable_dlopen"; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen=load_add_on - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | windows* | pw32* | cegcc*) - lt_cv_dlopen=LoadLibrary - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in @%:@( - e) - lt_cv_dlopen=dyld - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; -esac -fi - - ;; - - tpf*) - # Don't try to run any link tests for TPF. We know it's impossible - # because TPF is a cross-compiler, and we know how we open DSOs. - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - lt_cv_dlopen_self=no - ;; - - *) - ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" -if test "x$ac_cv_func_shl_load" = xyes -then : - lt_cv_dlopen=shl_load -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 -printf %s "checking for shl_load in -ldld... " >&6; } -if test ${ac_cv_lib_dld_shl_load+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (void); -int -main (void) -{ -return shl_load (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_shl_load=yes -else case e in @%:@( - e) ac_cv_lib_dld_shl_load=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 -printf '%s\n' "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes -then : - lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld -else case e in @%:@( - e) ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes -then : - lt_cv_dlopen=dlopen -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 -printf %s "checking for dlopen in -lsvld... " >&6; } -if test ${ac_cv_lib_svld_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_svld_dlopen=yes -else case e in @%:@( - e) ac_cv_lib_svld_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_svld_dlopen" >&6; } -if test "x$ac_cv_lib_svld_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 -printf %s "checking for dld_link in -ldld... " >&6; } -if test ${ac_cv_lib_dld_dld_link+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (void); -int -main (void) -{ -return dld_link (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_dld_link=yes -else case e in @%:@( - e) ac_cv_lib_dld_dld_link=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 -printf '%s\n' "$ac_cv_lib_dld_dld_link" >&6; } -if test "x$ac_cv_lib_dld_dld_link" = xyes -then : - lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; - esac - - if test no = "$lt_cv_dlopen"; then - enable_dlopen=no - else - enable_dlopen=yes - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS=$CPPFLAGS - test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS=$LDFLAGS - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS=$LIBS - LIBS="$lt_cv_dlopen_libs $LIBS" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 -printf %s "checking whether a program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 -printf '%s\n' "$lt_cv_dlopen_self" >&6; } - - if test yes = "$lt_cv_dlopen_self"; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 -printf %s "checking whether a statically linked program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self_static+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self_static=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self_static=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 -printf '%s\n' "$lt_cv_dlopen_self_static" >&6; } - fi - - CPPFLAGS=$save_CPPFLAGS - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - - - - - - - - - - - - - - - - - -striplib= -old_striplib= -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 -printf %s "checking whether stripping libraries is possible... " >&6; } -if test -z "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -else - if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - case $host_os in - darwin*) - # FIXME - insert some real tests, host_os isn't really good enough - striplib="$STRIP -x" - old_striplib="$STRIP -S" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - ;; - freebsd*) - if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - fi - ;; - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - ;; - esac - fi -fi - - - - - - - - - - - - - # Report what library types will actually be built - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 -printf %s "checking if libtool supports shared libraries... " >&6; } - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 -printf '%s\n' "$can_build_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 -printf %s "checking whether to build shared libraries... " >&6; } - test no = "$can_build_shared" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test yes = "$enable_shared" && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - - aix[4-9]*) - if test ia64 != "$host_cpu"; then - case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in - yes,aix,yes) ;; # shared object as lib.so file only - yes,svr4,*) ;; # shared object as lib.so archive member only - yes,*) enable_static=no ;; # shared object in lib.a archive as well - esac - fi - ;; - esac - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 -printf '%s\n' "$enable_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 -printf %s "checking whether to build static libraries... " >&6; } - # Make sure either enable_shared or enable_static is yes. - test yes = "$enable_shared" || enable_static=yes - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 -printf '%s\n' "$enable_static" >&6; } - - - - -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC=$lt_save_CC - - - - - - - - - - - - - - - - ac_config_commands="$ac_config_commands libtool" - - - - -# Only expand once: - - - -# Require xorg-macros minimum of 1.12 for DocBook external references - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to detect undeclared functions" >&5 -printf %s "checking for $CC options to detect undeclared functions... " >&6; } -if test ${ac_cv_c_undeclared_builtin_options+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_save_CFLAGS=$CFLAGS - ac_cv_c_undeclared_builtin_options='cannot detect' - for ac_arg in '' -fno-builtin; do - CFLAGS="$ac_save_CFLAGS $ac_arg" - # This test program should *not* compile successfully. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -(void) strchr; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in @%:@( - e) # This test program should compile successfully. - # No library function is consistently available on - # freestanding implementations, so test against a dummy - # declaration. Include always-available headers on the - # off chance that they somehow elicit warnings. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include -extern void ac_decl (int, char *); - -int -main (void) -{ -(void) ac_decl (0, (char *) 0); - (void) ac_decl; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - if test x"$ac_arg" = x -then : - ac_cv_c_undeclared_builtin_options='none needed' -else case e in @%:@( - e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; -esac -fi - break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - done - CFLAGS=$ac_save_CFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 -printf '%s\n' "$ac_cv_c_undeclared_builtin_options" >&6; } - case $ac_cv_c_undeclared_builtin_options in @%:@( - 'cannot detect') : - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot make $CC report undeclared builtins -See 'config.log' for more details" "$LINENO" 5; } ;; @%:@( - 'none needed') : - ac_c_undeclared_builtin_options='' ;; @%:@( - *) : - ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to ignore future-version functions" >&5 -printf %s "checking for $CC options to ignore future-version functions... " >&6; } -if test ${ac_cv_c_future_darwin_options+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) ac_compile_saved="$ac_compile" - ac_compile="$ac_compile -Werror=unguarded-availability-new" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if ! (defined __APPLE__ && defined __MACH__) - #error "-Werror=unguarded-availability-new not needed here" - #endif - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_future_darwin_options='-Werror=unguarded-availability-new' -else case e in @%:@( - e) ac_cv_c_future_darwin_options='none needed' ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_compile="$ac_compile_saved" - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_future_darwin_options" >&5 -printf '%s\n' "$ac_cv_c_future_darwin_options" >&6; } - case $ac_cv_c_future_darwin_options in @%:@( - 'none needed') : - ac_c_future_darwin_options='' ;; @%:@( - *) : - ac_c_future_darwin_options=$ac_cv_c_future_darwin_options ;; -esac - - - - - -ac_fn_check_decl "$LINENO" "__clang__" "ac_cv_have_decl___clang__" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___clang__" = xyes -then : - CLANGCC="yes" -else case e in @%:@( - e) CLANGCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__INTEL_COMPILER" "ac_cv_have_decl___INTEL_COMPILER" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___INTEL_COMPILER" = xyes -then : - INTELCC="yes" -else case e in @%:@( - e) INTELCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__SUNPRO_C" "ac_cv_have_decl___SUNPRO_C" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___SUNPRO_C" = xyes -then : - SUNCC="yes" -else case e in @%:@( - e) SUNCC="no" ;; -esac -fi - - - - - - - - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. -set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -PKG_CONFIG=$ac_cv_path_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -printf '%s\n' "$PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_path_PKG_CONFIG"; then - ac_pt_PKG_CONFIG=$PKG_CONFIG - # Extract the first word of "pkg-config", so it can be a program name with args. -set dummy pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $ac_pt_PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG -if test -n "$ac_pt_PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 -printf '%s\n' "$ac_pt_PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_pt_PKG_CONFIG" = x; then - PKG_CONFIG="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - PKG_CONFIG=$ac_pt_PKG_CONFIG - fi -else - PKG_CONFIG="$ac_cv_path_PKG_CONFIG" -fi - -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=0.9.0 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 -printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - PKG_CONFIG="" - fi -fi - - - - - -@%:@ Check whether --enable-selective-werror was given. -if test ${enable_selective_werror+y} -then : - enableval=$enable_selective_werror; SELECTIVE_WERROR=$enableval -else case e in @%:@( - e) SELECTIVE_WERROR=yes ;; -esac -fi - - - - - -# -v is too short to test reliably with XORG_TESTSET_CFLAG -if test "x$SUNCC" = "xyes"; then - BASE_CFLAGS="-v" -else - BASE_CFLAGS="" -fi - -# This chunk of warnings were those that existed in the legacy CWARNFLAGS - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wall" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wall" >&5 -printf %s "checking if $CC supports -Wall... " >&6; } - cacheid=xorg_cv_cc_flag__Wall - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wall" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-arith" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-arith" >&5 -printf %s "checking if $CC supports -Wpointer-arith... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_arith - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-arith" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-declarations" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-declarations" >&5 -printf %s "checking if $CC supports -Wmissing-declarations... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_declarations - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-declarations" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat=2" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat=2" >&5 -printf %s "checking if $CC supports -Wformat=2... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat_2 - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat=2" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat" >&5 -printf %s "checking if $CC supports -Wformat... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat" - found="yes" - fi - fi - - - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wstrict-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wstrict-prototypes" >&5 -printf %s "checking if $CC supports -Wstrict-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wstrict_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wstrict-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-prototypes" >&5 -printf %s "checking if $CC supports -Wmissing-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnested-externs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnested-externs" >&5 -printf %s "checking if $CC supports -Wnested-externs... " >&6; } - cacheid=xorg_cv_cc_flag__Wnested_externs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnested-externs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wbad-function-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wbad-function-cast" >&5 -printf %s "checking if $CC supports -Wbad-function-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wbad_function_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wbad-function-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wold-style-definition" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wold-style-definition" >&5 -printf %s "checking if $CC supports -Wold-style-definition... " >&6; } - cacheid=xorg_cv_cc_flag__Wold_style_definition - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wold-style-definition" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -fd" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -fd" >&5 -printf %s "checking if $CC supports -fd... " >&6; } - cacheid=xorg_cv_cc_flag__fd - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -fd" - found="yes" - fi - fi - - - - - -# This chunk adds additional warnings that could catch undesired effects. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wunused" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wunused" >&5 -printf %s "checking if $CC supports -Wunused... " >&6; } - cacheid=xorg_cv_cc_flag__Wunused - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wunused" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wuninitialized" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wuninitialized" >&5 -printf %s "checking if $CC supports -Wuninitialized... " >&6; } - cacheid=xorg_cv_cc_flag__Wuninitialized - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wuninitialized" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wshadow" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wshadow" >&5 -printf %s "checking if $CC supports -Wshadow... " >&6; } - cacheid=xorg_cv_cc_flag__Wshadow - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wshadow" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-noreturn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-noreturn" >&5 -printf %s "checking if $CC supports -Wmissing-noreturn... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_noreturn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-noreturn" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-format-attribute" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-format-attribute" >&5 -printf %s "checking if $CC supports -Wmissing-format-attribute... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_format_attribute - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-format-attribute" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wredundant-decls" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wredundant-decls" >&5 -printf %s "checking if $CC supports -Wredundant-decls... " >&6; } - cacheid=xorg_cv_cc_flag__Wredundant_decls - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wredundant-decls" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wlogical-op" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wlogical-op" >&5 -printf %s "checking if $CC supports -Wlogical-op... " >&6; } - cacheid=xorg_cv_cc_flag__Wlogical_op - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wlogical-op" - found="yes" - fi - fi - - - -# These are currently disabled because they are noisy. They will be enabled -# in the future once the codebase is sufficiently modernized to silence -# them. For now, I don't want them to drown out the other warnings. -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wparentheses]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-align]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-qual]) - -# Turn some warnings into errors, so we don't accidentally get successful builds -# when there are problems that should be fixed. - -if test "x$SELECTIVE_WERROR" = "xyes" ; then - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=implicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=implicit" >&5 -printf %s "checking if $CC supports -Werror=implicit... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_implicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=implicit" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" >&5 -printf %s "checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_NO_EXPLICIT_TYPE_GIVEN__errwarn_E_NO_IMPLICIT_DECL_ALLOWED - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=nonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=nonnull" >&5 -printf %s "checking if $CC supports -Werror=nonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_nonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=nonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=init-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=init-self" >&5 -printf %s "checking if $CC supports -Werror=init-self... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_init_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=init-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=main" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=main" >&5 -printf %s "checking if $CC supports -Werror=main... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_main - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=main" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=missing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=missing-braces" >&5 -printf %s "checking if $CC supports -Werror=missing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_missing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=missing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=sequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=sequence-point" >&5 -printf %s "checking if $CC supports -Werror=sequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_sequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=sequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=return-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=return-type" >&5 -printf %s "checking if $CC supports -Werror=return-type... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_return_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=return-type" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT" >&5 -printf %s "checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_FUNC_HAS_NO_RETURN_STMT - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=trigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=trigraphs" >&5 -printf %s "checking if $CC supports -Werror=trigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_trigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=trigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=array-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=array-bounds" >&5 -printf %s "checking if $CC supports -Werror=array-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_array_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=array-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=write-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=write-strings" >&5 -printf %s "checking if $CC supports -Werror=write-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_write_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=write-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=address" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=address" >&5 -printf %s "checking if $CC supports -Werror=address... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_address - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=address" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=int-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=int-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Werror=int-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_int_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=int-to-pointer-cast" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION" >&5 -printf %s "checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_BAD_PTR_INT_COMBINATION - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=pointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=pointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Werror=pointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_pointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=pointer-to-int-cast" - found="yes" - fi - fi - - # Also -errwarn=E_BAD_PTR_INT_COMBINATION -else -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&5 -printf '%s\n' "$as_me: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&2;} - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wimplicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wimplicit" >&5 -printf %s "checking if $CC supports -Wimplicit... " >&6; } - cacheid=xorg_cv_cc_flag__Wimplicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wimplicit" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnonnull" >&5 -printf %s "checking if $CC supports -Wnonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Wnonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Winit-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Winit-self" >&5 -printf %s "checking if $CC supports -Winit-self... " >&6; } - cacheid=xorg_cv_cc_flag__Winit_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Winit-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmain" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmain" >&5 -printf %s "checking if $CC supports -Wmain... " >&6; } - cacheid=xorg_cv_cc_flag__Wmain - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmain" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-braces" >&5 -printf %s "checking if $CC supports -Wmissing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wsequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wsequence-point" >&5 -printf %s "checking if $CC supports -Wsequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Wsequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wsequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wreturn-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wreturn-type" >&5 -printf %s "checking if $CC supports -Wreturn-type... " >&6; } - cacheid=xorg_cv_cc_flag__Wreturn_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wreturn-type" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wtrigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wtrigraphs" >&5 -printf %s "checking if $CC supports -Wtrigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Wtrigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wtrigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Warray-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Warray-bounds" >&5 -printf %s "checking if $CC supports -Warray-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Warray_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Warray-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wwrite-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wwrite-strings" >&5 -printf %s "checking if $CC supports -Wwrite-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Wwrite_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wwrite-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Waddress" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Waddress" >&5 -printf %s "checking if $CC supports -Waddress... " >&6; } - cacheid=xorg_cv_cc_flag__Waddress - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Waddress" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wint-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wint-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Wint-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wint_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wint-to-pointer-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Wpointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-to-int-cast" - found="yes" - fi - fi - - -fi - - - - - - - - CWARNFLAGS="$BASE_CFLAGS" - if test "x$GCC" = xyes ; then - CWARNFLAGS="$CWARNFLAGS -fno-strict-aliasing" - fi - - - - - - - - -@%:@ Check whether --enable-strict-compilation was given. -if test ${enable_strict_compilation+y} -then : - enableval=$enable_strict_compilation; STRICT_COMPILE=$enableval -else case e in @%:@( - e) STRICT_COMPILE=no ;; -esac -fi - - - - - - -STRICT_CFLAGS="" - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -pedantic" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -pedantic" >&5 -printf %s "checking if $CC supports -pedantic... " >&6; } - cacheid=xorg_cv_cc_flag__pedantic - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -pedantic" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror" >&5 -printf %s "checking if $CC supports -Werror... " >&6; } - cacheid=xorg_cv_cc_flag__Werror - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn" >&5 -printf %s "checking if $CC supports -errwarn... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -errwarn" - found="yes" - fi - fi - - - -# Earlier versions of gcc (eg: 4.2) support -Werror=attributes, but do not -# activate it with -Werror, so we add it here explicitly. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in @%:@( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=attributes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=attributes" >&5 -printf %s "checking if $CC supports -Werror=attributes... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_attributes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in @%:@( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror=attributes" - found="yes" - fi - fi - - - -if test "x$STRICT_COMPILE" = "xyes"; then - BASE_CFLAGS="$BASE_CFLAGS $STRICT_CFLAGS" - CWARNFLAGS="$CWARNFLAGS $STRICT_CFLAGS" -fi - - - - - - - - -cat >>confdefs.h <<_ACEOF -@%:@define PACKAGE_VERSION_MAJOR `echo $PACKAGE_VERSION | cut -d . -f 1` -_ACEOF - - PVM=`echo $PACKAGE_VERSION | cut -d . -f 2 | cut -d - -f 1` - if test "x$PVM" = "x"; then - PVM="0" - fi - -printf '%s\n' "@%:@define PACKAGE_VERSION_MINOR $PVM" >>confdefs.h - - PVP=`echo $PACKAGE_VERSION | cut -d . -f 3 | cut -d - -f 1` - if test "x$PVP" = "x"; then - PVP="0" - fi - -printf '%s\n' "@%:@define PACKAGE_VERSION_PATCHLEVEL $PVP" >>confdefs.h - - - -CHANGELOG_CMD="((GIT_DIR=\$(top_srcdir)/.git git log > \$(top_srcdir)/.changelog.tmp) 2>/dev/null && \ -mv \$(top_srcdir)/.changelog.tmp \$(top_srcdir)/ChangeLog) \ -|| (rm -f \$(top_srcdir)/.changelog.tmp; test -e \$(top_srcdir)/ChangeLog || ( \ -touch \$(top_srcdir)/ChangeLog; \ -echo 'git failed to create ChangeLog: installing empty ChangeLog.' >&2))" - - - - -macros_datadir=`$PKG_CONFIG --print-errors --variable=pkgdatadir xorg-macros` -INSTALL_CMD="(cp -f "$macros_datadir/INSTALL" \$(top_srcdir)/.INSTALL.tmp && \ -mv \$(top_srcdir)/.INSTALL.tmp \$(top_srcdir)/INSTALL) \ -|| (rm -f \$(top_srcdir)/.INSTALL.tmp; test -e \$(top_srcdir)/INSTALL || ( \ -touch \$(top_srcdir)/INSTALL; \ -echo 'failed to copy INSTALL from util-macros: installing empty INSTALL.' >&2))" - - - - - - -case $host_os in - solaris*) - # Solaris 2.0 - 11.3 use SysV man page section numbers, so we - # check for a man page file found in later versions that use - # traditional section numbers instead - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for /usr/share/man/man7/attributes.7" >&5 -printf %s "checking for /usr/share/man/man7/attributes.7... " >&6; } -if test ${ac_cv_file__usr_share_man_man7_attributes_7+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) test "$cross_compiling" = yes && - as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 -if test -r "/usr/share/man/man7/attributes.7"; then - ac_cv_file__usr_share_man_man7_attributes_7=yes -else - ac_cv_file__usr_share_man_man7_attributes_7=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__usr_share_man_man7_attributes_7" >&5 -printf '%s\n' "$ac_cv_file__usr_share_man_man7_attributes_7" >&6; } -if test "x$ac_cv_file__usr_share_man_man7_attributes_7" = xyes -then : - SYSV_MAN_SECTIONS=false -else case e in @%:@( - e) SYSV_MAN_SECTIONS=true ;; -esac -fi - - ;; - *) SYSV_MAN_SECTIONS=false ;; -esac - -if test x$APP_MAN_SUFFIX = x ; then - APP_MAN_SUFFIX=1 -fi -if test x$APP_MAN_DIR = x ; then - APP_MAN_DIR='$(mandir)/man$(APP_MAN_SUFFIX)' -fi - -if test x$LIB_MAN_SUFFIX = x ; then - LIB_MAN_SUFFIX=3 -fi -if test x$LIB_MAN_DIR = x ; then - LIB_MAN_DIR='$(mandir)/man$(LIB_MAN_SUFFIX)' -fi - -if test x$FILE_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) FILE_MAN_SUFFIX=4 ;; - *) FILE_MAN_SUFFIX=5 ;; - esac -fi -if test x$FILE_MAN_DIR = x ; then - FILE_MAN_DIR='$(mandir)/man$(FILE_MAN_SUFFIX)' -fi - -if test x$MISC_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) MISC_MAN_SUFFIX=5 ;; - *) MISC_MAN_SUFFIX=7 ;; - esac -fi -if test x$MISC_MAN_DIR = x ; then - MISC_MAN_DIR='$(mandir)/man$(MISC_MAN_SUFFIX)' -fi - -if test x$DRIVER_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) DRIVER_MAN_SUFFIX=7 ;; - *) DRIVER_MAN_SUFFIX=4 ;; - esac -fi -if test x$DRIVER_MAN_DIR = x ; then - DRIVER_MAN_DIR='$(mandir)/man$(DRIVER_MAN_SUFFIX)' -fi - -if test x$ADMIN_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) ADMIN_MAN_SUFFIX=1m ;; - *) ADMIN_MAN_SUFFIX=8 ;; - esac -fi -if test x$ADMIN_MAN_DIR = x ; then - ADMIN_MAN_DIR='$(mandir)/man$(ADMIN_MAN_SUFFIX)' -fi - - - - - - - - - - - - - - - -XORG_MAN_PAGE="X Version 11" - -MAN_SUBSTS="\ - -e 's|__vendorversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xorgversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xservername__|Xorg|g' \ - -e 's|__xconfigfile__|xorg.conf|g' \ - -e 's|__projectroot__|\$(prefix)|g' \ - -e 's|__apploaddir__|\$(appdefaultdir)|g' \ - -e 's|__appmansuffix__|\$(APP_MAN_SUFFIX)|g' \ - -e 's|__drivermansuffix__|\$(DRIVER_MAN_SUFFIX)|g' \ - -e 's|__adminmansuffix__|\$(ADMIN_MAN_SUFFIX)|g' \ - -e 's|__libmansuffix__|\$(LIB_MAN_SUFFIX)|g' \ - -e 's|__miscmansuffix__|\$(MISC_MAN_SUFFIX)|g' \ - -e 's|__filemansuffix__|\$(FILE_MAN_SUFFIX)|g'" - - - - -AM_DEFAULT_VERBOSITY=0 - - - - - - -@%:@ Check whether --enable-specs was given. -if test ${enable_specs+y} -then : - enableval=$enable_specs; build_specs=$enableval -else case e in @%:@( - e) build_specs=yes ;; -esac -fi - - - if test x$build_specs = xyes; then - ENABLE_SPECS_TRUE= - ENABLE_SPECS_FALSE='#' -else - ENABLE_SPECS_TRUE='#' - ENABLE_SPECS_FALSE= -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build functional specifications" >&5 -printf %s "checking whether to build functional specifications... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $build_specs" >&5 -printf '%s\n' "$build_specs" >&6; } - - - - - -@%:@ Check whether --with-xmlto was given. -if test ${with_xmlto+y} -then : - withval=$with_xmlto; use_xmlto=$withval -else case e in @%:@( - e) use_xmlto=auto ;; -esac -fi - - - -if test "x$use_xmlto" = x"auto"; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto not found - documentation targets will be skipped" >&2;} - have_xmlto=no - else - have_xmlto=yes - fi -elif test "x$use_xmlto" = x"yes" ; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - as_fn_error $? "--with-xmlto=yes specified but xmlto not found in PATH" "$LINENO" 5 - fi - have_xmlto=yes -elif test "x$use_xmlto" = x"no" ; then - if test "x$XMLTO" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&2;} - fi - have_xmlto=no -else - as_fn_error $? "--with-xmlto expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of xmlto, if provided. -if test "$have_xmlto" = yes; then - # scrape the xmlto version - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the xmlto version" >&5 -printf %s "checking the xmlto version... " >&6; } - xmlto_version=`$XMLTO --version 2>/dev/null | cut -d' ' -f3` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xmlto_version" >&5 -printf '%s\n' "$xmlto_version" >&6; } - as_arg_v1=$xmlto_version -as_arg_v2=0.0.22 -awk "$as_awk_strverscmp" v1="$as_arg_v1" v2="$as_arg_v2" /dev/null -case $? in @%:@( - 1) : - if test "x$use_xmlto" = xauto; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&5 -printf '%s\n' "$as_me: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&2;} - have_xmlto=no - else - as_fn_error $? "xmlto version $xmlto_version found, but 0.0.22 needed" "$LINENO" 5 - fi ;; @%:@( - 0) : - ;; @%:@( - 2) : - ;; @%:@( - *) : - ;; -esac -fi - -# Test for the ability of xmlto to generate a text target -# -# NOTE: xmlto 0.0.27 or higher return a non-zero return code in the -# following test for empty XML docbook files. -# For compatibility reasons use the following empty XML docbook file and if -# it fails try it again with a non-empty XML file. -have_xmlto_text=no -cat > conftest.xml << "EOF" -EOF -if test "$have_xmlto" = yes -then : - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in @%:@( - e) # Try it again with a non-empty XML file. - cat > conftest.xml << "EOF" - -EOF - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in @%:@( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto cannot generate text format, this format skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto cannot generate text format, this format skipped" >&2;} ;; -esac -fi ;; -esac -fi -fi -rm -f conftest.xml - if test $have_xmlto_text = yes; then - HAVE_XMLTO_TEXT_TRUE= - HAVE_XMLTO_TEXT_FALSE='#' -else - HAVE_XMLTO_TEXT_TRUE='#' - HAVE_XMLTO_TEXT_FALSE= -fi - - if test "$have_xmlto" = yes; then - HAVE_XMLTO_TRUE= - HAVE_XMLTO_FALSE='#' -else - HAVE_XMLTO_TRUE='#' - HAVE_XMLTO_FALSE= -fi - - - - - - -@%:@ Check whether --with-fop was given. -if test ${with_fop+y} -then : - withval=$with_fop; use_fop=$withval -else case e in @%:@( - e) use_fop=auto ;; -esac -fi - - - -if test "x$use_fop" = x"auto"; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: fop not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: fop not found - documentation targets will be skipped" >&2;} - have_fop=no - else - have_fop=yes - fi -elif test "x$use_fop" = x"yes" ; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - as_fn_error $? "--with-fop=yes specified but fop not found in PATH" "$LINENO" 5 - fi - have_fop=yes -elif test "x$use_fop" = x"no" ; then - if test "x$FOP" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&2;} - fi - have_fop=no -else - as_fn_error $? "--with-fop expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of fop, if provided. - - if test "$have_fop" = yes; then - HAVE_FOP_TRUE= - HAVE_FOP_FALSE='#' -else - HAVE_FOP_TRUE='#' - HAVE_FOP_FALSE= -fi - - - - -# Preserves the interface, should it be implemented later - - - -@%:@ Check whether --with-xsltproc was given. -if test ${with_xsltproc+y} -then : - withval=$with_xsltproc; use_xsltproc=$withval -else case e in @%:@( - e) use_xsltproc=auto ;; -esac -fi - - - -if test "x$use_xsltproc" = x"auto"; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xsltproc not found - cannot transform XML documents" >&5 -printf '%s\n' "$as_me: WARNING: xsltproc not found - cannot transform XML documents" >&2;} - have_xsltproc=no - else - have_xsltproc=yes - fi -elif test "x$use_xsltproc" = x"yes" ; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - as_fn_error $? "--with-xsltproc=yes specified but xsltproc not found in PATH" "$LINENO" 5 - fi - have_xsltproc=yes -elif test "x$use_xsltproc" = x"no" ; then - if test "x$XSLTPROC" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&2;} - fi - have_xsltproc=no -else - as_fn_error $? "--with-xsltproc expects 'yes' or 'no'" "$LINENO" 5 -fi - - if test "$have_xsltproc" = yes; then - HAVE_XSLTPROC_TRUE= - HAVE_XSLTPROC_FALSE='#' -else - HAVE_XSLTPROC_TRUE='#' - HAVE_XSLTPROC_FALSE= -fi - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for X.Org SGML entities >= 1.8" >&5 -printf %s "checking for X.Org SGML entities >= 1.8... " >&6; } -XORG_SGML_PATH= -if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xorg-sgml-doctools >= 1.8\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xorg-sgml-doctools >= 1.8") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools` -else - : - -fi - -# Define variables STYLESHEET_SRCDIR and XSL_STYLESHEET containing -# the path and the name of the doc stylesheet -if test "x$XORG_SGML_PATH" != "x" ; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XORG_SGML_PATH" >&5 -printf '%s\n' "$XORG_SGML_PATH" >&6; } - STYLESHEET_SRCDIR=$XORG_SGML_PATH/X11 - XSL_STYLESHEET=$STYLESHEET_SRCDIR/xorg.xsl -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - if test "x$XSL_STYLESHEET" != "x"; then - HAVE_STYLESHEETS_TRUE= - HAVE_STYLESHEETS_FALSE='#' -else - HAVE_STYLESHEETS_TRUE='#' - HAVE_STYLESHEETS_FALSE= -fi - - - -@%:@ Check whether --enable-malloc0returnsnull was given. -if test ${enable_malloc0returnsnull+y} -then : - enableval=$enable_malloc0returnsnull; MALLOC_ZERO_RETURNS_NULL=$enableval -else case e in @%:@( - e) MALLOC_ZERO_RETURNS_NULL=yes ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to act as if malloc(0) can return NULL" >&5 -printf %s "checking whether to act as if malloc(0) can return NULL... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MALLOC_ZERO_RETURNS_NULL" >&5 -printf '%s\n' "$MALLOC_ZERO_RETURNS_NULL" >&6; } - -if test "x$MALLOC_ZERO_RETURNS_NULL" = xyes; then - MALLOC_ZERO_CFLAGS="-DMALLOC_0_RETURNS_NULL" - XMALLOC_ZERO_CFLAGS=$MALLOC_ZERO_CFLAGS - XTMALLOC_ZERO_CFLAGS="$MALLOC_ZERO_CFLAGS -DXTMALLOC_BC" -else - MALLOC_ZERO_CFLAGS="" - XMALLOC_ZERO_CFLAGS="" - XTMALLOC_ZERO_CFLAGS="" -fi - - - - - - -# Determine .so library version per platform -# based on SharedXextRev in monolith xc/config/cf/*Lib.tmpl -if test "x$XEXT_SOREV" = "x" ; then - case $host_os in - openbsd*) XEXT_SOREV=8:0 ;; - solaris*) XEXT_SOREV=0 ;; - *) XEXT_SOREV=6:4:0 ;; - esac -fi - - -# Obtain compiler/linker options for dependencies - -pkg_failed=no -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" >&5 -printf %s "checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99... " >&6; } - -if test -n "$XEXT_CFLAGS"; then - pkg_cv_XEXT_CFLAGS="$XEXT_CFLAGS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_CFLAGS=`$PKG_CONFIG --cflags "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi -if test -n "$XEXT_LIBS"; then - pkg_cv_XEXT_LIBS="$XEXT_LIBS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_LIBS=`$PKG_CONFIG --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi - - - -if test $pkg_failed = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi - if test $_pkg_short_errors_supported = yes; then - XEXT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - else - XEXT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$XEXT_PKG_ERRORS" >&5 - - as_fn_error $? "Package requirements (xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99) were not met: - -$XEXT_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details." "$LINENO" 5 -elif test $pkg_failed = untried; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details. - -To get pkg-config, see . -See 'config.log' for more details" "$LINENO" 5; } -else - XEXT_CFLAGS=$pkg_cv_XEXT_CFLAGS - XEXT_LIBS=$pkg_cv_XEXT_LIBS - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - -fi - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for __builtin_popcountl" >&5 -printf %s "checking for __builtin_popcountl... " >&6; } -if test ${ax_cv_have___builtin_popcountl+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - __builtin_popcountl(0) - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ax_cv_have___builtin_popcountl=yes -else case e in @%:@( - e) ax_cv_have___builtin_popcountl=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have___builtin_popcountl" >&5 -printf '%s\n' "$ax_cv_have___builtin_popcountl" >&6; } - - if test yes = $ax_cv_have___builtin_popcountl -then : - -printf '%s\n' "@%:@define HAVE___BUILTIN_POPCOUNTL 1" >>confdefs.h - -fi - - - -ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" -if test "x$ac_cv_func_reallocarray" = xyes -then : - printf '%s\n' "@%:@define HAVE_REALLOCARRAY 1" >>confdefs.h - -else case e in @%:@( - e) case " $LIB@&t@OBJS " in - *" reallocarray.$ac_objext "* ) ;; - *) LIB@&t@OBJS="$LIB@&t@OBJS reallocarray.$ac_objext" - ;; -esac - ;; -esac -fi - - -# Allow checking code with lint, sparse, etc. - - - - - -@%:@ Check whether --with-lint was given. -if test ${with_lint+y} -then : - withval=$with_lint; use_lint=$withval -else case e in @%:@( - e) use_lint=no ;; -esac -fi - - -# Obtain platform specific info like program name and options -# The lint program on FreeBSD and NetBSD is different from the one on Solaris -case $host_os in - *linux* | *openbsd* | kfreebsd*-gnu | darwin* | cygwin*) - lint_name=splint - lint_options="-badflag" - ;; - *freebsd* | *netbsd*) - lint_name=lint - lint_options="-u -b" - ;; - *solaris*) - lint_name=lint - lint_options="-u -b -h -erroff=E_INDISTING_FROM_TRUNC2" - ;; -esac - -# Test for the presence of the program (either guessed by the code or spelled out by the user) -if test "x$use_lint" = x"yes" ; then - # Extract the first word of "$lint_name", so it can be a program name with args. -set dummy $lint_name; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_LINT+y} -then : - printf %s "(cached) " >&6 -else case e in @%:@( - e) case $LINT in - [\\/]* | ?:[\\/]*) - ac_cv_path_LINT="$LINT" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_LINT="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -LINT=$ac_cv_path_LINT -if test -n "$LINT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LINT" >&5 -printf '%s\n' "$LINT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$LINT" = "x"; then - as_fn_error $? "--with-lint=yes specified but lint-style tool not found in PATH" "$LINENO" 5 - fi -elif test "x$use_lint" = x"no" ; then - if test "x$LINT" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&2;} - fi -else - as_fn_error $? "--with-lint expects 'yes' or 'no'. Use LINT variable to specify path." "$LINENO" 5 -fi - -# User supplied flags override default flags -if test "x$LINT_FLAGS" != "x"; then - lint_options=$LINT_FLAGS -fi - -LINT_FLAGS=$lint_options - - if test "x$LINT" != x; then - LINT_TRUE= - LINT_FALSE='#' -else - LINT_TRUE='#' - LINT_FALSE= -fi - - - - - -@%:@ Check whether --enable-lint-library was given. -if test ${enable_lint_library+y} -then : - enableval=$enable_lint_library; make_lint_lib=$enableval -else case e in @%:@( - e) make_lint_lib=no ;; -esac -fi - - -if test "x$make_lint_lib" = x"yes" ; then - LINTLIB=llib-lXext.ln - if test "x$LINT" = "x"; then - as_fn_error $? "Cannot make lint library without --with-lint" "$LINENO" 5 - fi -elif test "x$make_lint_lib" != x"no" ; then - as_fn_error $? "--enable-lint-library expects 'yes' or 'no'." "$LINENO" 5 -fi - - - if test x$make_lint_lib != xno; then - MAKE_LINT_LIB_TRUE= - MAKE_LINT_LIB_FALSE='#' -else - MAKE_LINT_LIB_TRUE='#' - MAKE_LINT_LIB_FALSE= -fi - - - - -ac_config_files="$ac_config_files Makefile man/Makefile src/Makefile specs/Makefile xext.pc" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# 'ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* 'ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -ac_cache_dump | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -printf '%s\n' "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -printf '%s\n' "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIB@&t@OBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`printf '%s\n' "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIB@&t@OBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -printf %s "checking that generated files are newer than configure... " >&6; } - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: done" >&5 -printf '%s\n' "done" >&6; } -if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then - as_fn_error $? "conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; -esac -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi - - if test -n "$EXEEXT"; then - am__EXEEXT_TRUE= - am__EXEEXT_FALSE='#' -else - am__EXEEXT_TRUE='#' - am__EXEEXT_FALSE= -fi - -if test -z "${ENABLE_SPECS_TRUE}" && test -z "${ENABLE_SPECS_FALSE}"; then - as_fn_error $? "conditional \"ENABLE_SPECS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TEXT_TRUE}" && test -z "${HAVE_XMLTO_TEXT_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO_TEXT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TRUE}" && test -z "${HAVE_XMLTO_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_FOP_TRUE}" && test -z "${HAVE_FOP_FALSE}"; then - as_fn_error $? "conditional \"HAVE_FOP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XSLTPROC_TRUE}" && test -z "${HAVE_XSLTPROC_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XSLTPROC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_STYLESHEETS_TRUE}" && test -z "${HAVE_STYLESHEETS_FALSE}"; then - as_fn_error $? "conditional \"HAVE_STYLESHEETS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${LINT_TRUE}" && test -z "${LINT_FALSE}"; then - as_fn_error $? "conditional \"LINT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${MAKE_LINT_LIB_TRUE}" && test -z "${MAKE_LINT_LIB_FALSE}"; then - as_fn_error $? "conditional \"MAKE_LINT_LIB\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: "${CONFIG_STATUS=./config.status}" -case $CONFIG_STATUS in @%:@( - -*) : - CONFIG_STATUS=./$CONFIG_STATUS ;; @%:@( - */*) : - ;; @%:@( - *) : - CONFIG_STATUS=./$CONFIG_STATUS ;; -esac - -ac_write_fail=0 -ac_clean_CONFIG_STATUS='"$CONFIG_STATUS"' -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -printf '%s\n' "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >"$CONFIG_STATUS" <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>"$CONFIG_STATUS" <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in @%:@( - e) case `(set -o) 2>/dev/null` in @%:@( - *posix*) : - set -o posix ;; @%:@( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in @%:@(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in @%:@((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - - -@%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] -@%:@ ---------------------------------------- -@%:@ Output "`basename @S|@0`: error: ERROR" to stderr. If LINENO and LOG_FD are -@%:@ provided, also output the error to LOG_FD, referencing LINENO. Then exit the -@%:@ script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} @%:@ as_fn_error - - -@%:@ as_fn_set_status STATUS -@%:@ ----------------------- -@%:@ Set @S|@? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} @%:@ as_fn_set_status - -@%:@ as_fn_exit STATUS -@%:@ ----------------- -@%:@ Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} @%:@ as_fn_exit - -@%:@ as_fn_unset VAR -@%:@ --------------- -@%:@ Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -@%:@ as_fn_append VAR VALUE -@%:@ ---------------------- -@%:@ Append the text in VALUE to the end of the definition contained in VAR. Take -@%:@ advantage of any shell optimizations that allow amortized linear growth over -@%:@ repeated appends, instead of the typical quadratic growth present in naive -@%:@ implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in @%:@( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -@%:@ as_fn_arith ARG... -@%:@ ------------------ -@%:@ Perform arithmetic evaluation on the ARGs, and store the result in the -@%:@ global @S|@as_val. Take advantage of shells that can avoid forks. The arguments -@%:@ must be portable across @S|@(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in @%:@( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -@%:@ as_fn_mkdir_p -@%:@ ------------- -@%:@ Create "@S|@as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} @%:@ as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -@%:@ as_fn_executable_p FILE -@%:@ ----------------------- -@%:@ Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} @%:@ as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - -exec 6>&1 -## ------------------------------------- ## -## Main body of "$CONFIG_STATUS" script. ## -## ------------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -'$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` -ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_cs_config='$ac_cs_config_escaped' -ac_cs_version="\\ -libXext config.status 1.3.7 -configured by $0, generated by GNU Autoconf 2.73, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2026 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -AWK='$AWK' -test -n "\$AWK" || { - awk '' >"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - printf '%s\n' "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - printf '%s\n' "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: '$1' -Try '$0 --help' for more information.";; - --help | --hel | -h ) - printf '%s\n' "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: '$1' -Try '$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \printf '%s\n' "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../@%:@@%:@ /;s/...$/ @%:@@%:@/;p;x;p;x' <<_ASBOX -@%:@@%:@ Running $as_me. @%:@@%:@ -_ASBOX - printf '%s\n' "$ac_log" -} >&5 - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" - - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='$sed_quote_subst' -double_quote_subst='$double_quote_subst' -delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' -macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' -enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' -enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' -pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' -shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' -SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' -ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' -PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' -host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' -host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' -host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' -build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' -build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' -build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' -SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' -Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' -GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' -EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' -FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' -LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' -NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' -LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' -ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' -exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' -lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' -lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' -lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' -reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' -FILECMD='`$ECHO "$FILECMD" | $SED "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' -file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' -want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' -DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' -sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' -AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' -lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' -archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' -STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' -RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' -lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' -CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' -compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' -GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' -lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' -nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' -lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' -lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' -objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' -need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' -MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' -LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' -OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' -libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' -module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' -postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' -need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' -version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' -runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' -libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' -soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' -install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' -finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' -configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' -old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' -striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' - -LTCC='$LTCC' -LTCFLAGS='$LTCFLAGS' -compiler='$compiler_DEFAULT' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in SHELL \ -ECHO \ -PATH_SEPARATOR \ -SED \ -GREP \ -EGREP \ -FGREP \ -LD \ -NM \ -LN_S \ -lt_SP2NL \ -lt_NL2SP \ -reload_flag \ -FILECMD \ -OBJDUMP \ -deplibs_check_method \ -file_magic_cmd \ -file_magic_glob \ -want_nocaseglob \ -DLLTOOL \ -sharedlib_from_linklib_cmd \ -AR \ -archiver_list_spec \ -STRIP \ -RANLIB \ -CC \ -CFLAGS \ -compiler \ -lt_cv_sys_global_symbol_pipe \ -lt_cv_sys_global_symbol_to_cdecl \ -lt_cv_sys_global_symbol_to_import \ -lt_cv_sys_global_symbol_to_c_name_address \ -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -lt_cv_nm_interface \ -nm_file_list_spec \ -lt_cv_truncate_bin \ -lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_pic \ -lt_prog_compiler_wl \ -lt_prog_compiler_static \ -lt_cv_prog_compiler_c_o \ -need_locks \ -MANIFEST_TOOL \ -DSYMUTIL \ -NMEDIT \ -LIPO \ -OTOOL \ -OTOOL64 \ -shrext_cmds \ -export_dynamic_flag_spec \ -whole_archive_flag_spec \ -compiler_needs_object \ -with_gnu_ld \ -allow_undefined_flag \ -no_undefined_flag \ -hardcode_libdir_flag_spec \ -hardcode_libdir_separator \ -exclude_expsyms \ -include_expsyms \ -file_list_spec \ -variables_saved_for_relink \ -libname_spec \ -library_names_spec \ -soname_spec \ -install_override_mode \ -finish_eval \ -old_striplib \ -striplib; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in reload_cmds \ -old_postinstall_cmds \ -old_postuninstall_cmds \ -old_archive_cmds \ -extract_expsyms_cmds \ -old_archive_from_new_cmds \ -old_archive_from_expsyms_cmds \ -archive_cmds \ -archive_expsym_cmds \ -module_cmds \ -module_expsym_cmds \ -export_symbols_cmds \ -prelink_cmds \ -postlink_cmds \ -postinstall_cmds \ -postuninstall_cmds \ -finish_cmds \ -sys_lib_search_path_spec \ -configure_time_dlsearch_path \ -configure_time_lt_sys_library_path; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -ac_aux_dir='$ac_aux_dir' - -# See if we are running on zsh, and set the options that allow our -# commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - - - PACKAGE='$PACKAGE' - VERSION='$VERSION' - RM='$RM' - ofile='$ofile' - - - - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; - "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; - "specs/Makefile") CONFIG_FILES="$CONFIG_FILES specs/Makefile" ;; - "xext.pc") CONFIG_FILES="$CONFIG_FILES xext.pc" ;; - - *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files - test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers - test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to '$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with './config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | sed -n '$='` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | sed -n '$='` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >"$CONFIG_STATUS" || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with './config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script 'defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >"$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - suffix = P[macro] D[macro] - while (suffix ~ /[\t ]$/) { - suffix = substr(suffix, 1, length(suffix) - 1) - } - # Preserve the white space surrounding the "#". - print prefix "define", macro suffix - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain ':'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf '%s\n' "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is 'configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - printf '%s\n' "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf '%s\n' "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf '%s\n' "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when '$srcdir' = '.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf '%s\n' "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf '%s\n' "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || { - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - case $CONFIG_FILES in @%:@( - *\'*) : - eval set x "$CONFIG_FILES" ;; @%:@( - *) : - set x $CONFIG_FILES ;; @%:@( - *) : - ;; -esac - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`printf '%s\n' "$am_mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`$as_dirname -- "$am_mf" || -$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$am_mf" : 'X\(//\)[^/]' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$am_mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - am_filepart=`$as_basename -- "$am_mf" || -$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$am_mf" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - { echo "$as_me:$LINENO: cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles" >&5 - (cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } || am_rc=$? - done - if test $am_rc -ne 0; then - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE=\"gmake\" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking). -See 'config.log' for more details" "$LINENO" 5; } - fi - { am_dirpart=; unset am_dirpart;} - { am_filepart=; unset am_filepart;} - { am_mf=; unset am_mf;} - { am_rc=; unset am_rc;} - rm -f conftest-deps.mk -} - ;; - "libtool":C) - - # See if we are running on zsh, and set the options that allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST - fi - - cfgfile=${ofile}T - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL -# Generated automatically by $as_me ($PACKAGE) $VERSION -# NOTE: Changes made to this file will be lost: look at ltmain.sh. - -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit, 1996 - -# Copyright (C) 2024 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program or library that is built -# using GNU Libtool, you may include this file under the same -# distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -# The names of the tagged configurations supported by this script. -available_tags='' - -# Configured defaults for sys_lib_dlsearch_path munging. -: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=$macro_version -macro_revision=$macro_revision - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# What type of objects to build. -pic_mode=$pic_mode - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# Shared archive member basename,for filename based shared library versioning on AIX. -shared_archive_member_spec=$shared_archive_member_spec - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The PATH separator for the build system. -PATH_SEPARATOR=$lt_PATH_SEPARATOR - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="\$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP=$lt_GREP - -# An ERE matcher. -EGREP=$lt_EGREP - -# A literal string matcher. -FGREP=$lt_FGREP - -# A BSD- or MS-compatible name lister. -NM=$lt_NM - -# Whether we need soft or hard links. -LN_S=$lt_LN_S - -# What is the maximum length of a command? -max_cmd_len=$max_cmd_len - -# Object file suffix (normally "o"). -objext=$ac_objext - -# Executable file suffix (normally ""). -exeext=$exeext - -# whether the shell understands "unset". -lt_unset=$lt_unset - -# turn spaces into newlines. -SP2NL=$lt_lt_SP2NL - -# turn newlines into spaces. -NL2SP=$lt_lt_NL2SP - -# convert \$build file names to \$host format. -to_host_file_cmd=$lt_cv_to_host_file_cmd - -# convert \$build files to toolchain format. -to_tool_file_cmd=$lt_cv_to_tool_file_cmd - -# A file(cmd) program that detects file types. -FILECMD=$lt_FILECMD - -# An object symbol dumper. -OBJDUMP=$lt_OBJDUMP - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method = "file_magic". -file_magic_cmd=$lt_file_magic_cmd - -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob=$lt_file_magic_glob - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob=$lt_want_nocaseglob - -# DLL creation program. -DLLTOOL=$lt_DLLTOOL - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd - -# The archiver. -AR=$lt_AR - -# Flags to create an archive (by configure). -lt_ar_flags=$lt_ar_flags - -# Flags to create an archive. -AR_FLAGS=\@S|@{ARFLAGS-"\@S|@lt_ar_flags"} - -# How to feed a file listing to the archiver. -archiver_list_spec=$lt_archiver_list_spec - -# A symbol stripping program. -STRIP=$lt_STRIP - -# Commands used to install an old-style archive. -RANLIB=$lt_RANLIB -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - -# A C compiler. -LTCC=$lt_CC - -# LTCC compiler flags. -LTCFLAGS=$lt_CFLAGS - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm into a list of symbols to manually relocate. -global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix - -# The name lister interface. -nm_interface=$lt_lt_cv_nm_interface - -# Specify filename containing input files for \$NM. -nm_file_list_spec=$lt_nm_file_list_spec - -# The root where to search for dependent libraries,and where our libraries should be installed. -lt_sysroot=$lt_sysroot - -# Command to truncate a binary pipe. -lt_truncate_bin=$lt_lt_cv_truncate_bin - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=$MAGIC_CMD - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Manifest tool. -MANIFEST_TOOL=$lt_MANIFEST_TOOL - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL=$lt_DSYMUTIL - -# Tool to change global to local symbols on Mac OS X. -NMEDIT=$lt_NMEDIT - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO=$lt_LIPO - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL=$lt_OTOOL - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64=$lt_OTOOL64 - -# Old archive suffix (normally "a"). -libext=$libext - -# Shared library suffix (normally ".so"). -shrext_cmds=$lt_shrext_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink=$lt_variables_saved_for_relink - -# Do we need the "lib" prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Library versioning type. -version_type=$version_type - -# Shared library runtime path variable. -runpath_var=$runpath_var - -# Shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - -# Command to use after installation of a shared archive. -postinstall_cmds=$lt_postinstall_cmds - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval=$lt_finish_eval - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Compile-time system search path for libraries. -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Detected run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path - -# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. -configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - - -# The linker used to build libraries. -LD=$lt_LD - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds - -# A language specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU compiler? -with_gcc=$GCC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e. impossible to change by setting \$shlibpath_var if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# ### END LIBTOOL CONFIG - -_LT_EOF - - cat <<'_LT_EOF' >> "$cfgfile" - -# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x@S|@2 in - x) - ;; - *:) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" - ;; - x:*) - eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" - ;; - *) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - esac -} - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in @S|@*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - - -# ### END FUNCTIONS SHARED WITH CONFIGURE - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - - -ltmain=$ac_aux_dir/ltmain.sh - - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - $SED '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - - ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_CONFIG_STATUS= - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - case $CONFIG_STATUS in @%:@( - -*) : - ac_no_opts=-- ;; @%:@( - *) : - ac_no_opts= ;; -esac - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $ac_no_opts "$CONFIG_STATUS" $ac_config_status_args || - ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - \ No newline at end of file diff --git a/experiments/wasm-gui/third_party/libXext/autom4te.cache/requests b/experiments/wasm-gui/third_party/libXext/autom4te.cache/requests deleted file mode 100644 index 535583a95..000000000 --- a/experiments/wasm-gui/third_party/libXext/autom4te.cache/requests +++ /dev/null @@ -1,730 +0,0 @@ -# This file was generated by Autom4te 2.73. -# It contains the lists of macros which have been traced. -# It can be safely removed. - -@request = ( - bless( [ - '0', - 1, - [ - '/home/linuxbrew/.linuxbrew/Cellar/autoconf/2.73/share/autoconf' - ], - [ - '/home/linuxbrew/.linuxbrew/Cellar/autoconf/2.73/share/autoconf/autoconf/autoconf.m4f', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/internal/ac-config-macro-dirs.m4', - '/usr/share/aclocal/pkg.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal/ltargz.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal/ltsugar.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal/ltversion.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4', - '/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/amversion.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/auxdir.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/cond.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depend.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depout.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/init.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/install-sh.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/lead-dot.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/make.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/missing.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/prog-cc-c-o.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/rmf.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/runlog.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/sanity.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/silent.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/strip.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/substnot.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/tar.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/xargsn.m4', - 'm4/ax_gcc_builtin.m4', - 'configure.ac' - ], - { - 'AC_CHECK_LIBM' => 1, - 'AC_CONFIG_MACRO_DIR' => 1, - 'AC_CONFIG_MACRO_DIR_TRACE' => 1, - 'AC_DEFUN' => 1, - 'AC_DEFUN_ONCE' => 1, - 'AC_DEPLIBS_CHECK_METHOD' => 1, - 'AC_DISABLE_FAST_INSTALL' => 1, - 'AC_DISABLE_SHARED' => 1, - 'AC_DISABLE_STATIC' => 1, - 'AC_ENABLE_FAST_INSTALL' => 1, - 'AC_ENABLE_SHARED' => 1, - 'AC_ENABLE_STATIC' => 1, - 'AC_LIBLTDL_CONVENIENCE' => 1, - 'AC_LIBLTDL_INSTALLABLE' => 1, - 'AC_LIBTOOL_COMPILER_OPTION' => 1, - 'AC_LIBTOOL_CONFIG' => 1, - 'AC_LIBTOOL_CXX' => 1, - 'AC_LIBTOOL_DLOPEN' => 1, - 'AC_LIBTOOL_DLOPEN_SELF' => 1, - 'AC_LIBTOOL_F77' => 1, - 'AC_LIBTOOL_FC' => 1, - 'AC_LIBTOOL_GCJ' => 1, - 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, - 'AC_LIBTOOL_LANG_C_CONFIG' => 1, - 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, - 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, - 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, - 'AC_LIBTOOL_LINKER_OPTION' => 1, - 'AC_LIBTOOL_OBJDIR' => 1, - 'AC_LIBTOOL_PICMODE' => 1, - 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, - 'AC_LIBTOOL_PROG_CC_C_O' => 1, - 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, - 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, - 'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1, - 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, - 'AC_LIBTOOL_RC' => 1, - 'AC_LIBTOOL_SETUP' => 1, - 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, - 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, - 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, - 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, - 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, - 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, - 'AC_LIBTOOL_WIN32_DLL' => 1, - 'AC_LIB_LTDL' => 1, - 'AC_LTDL_DLLIB' => 1, - 'AC_LTDL_DLSYM_USCORE' => 1, - 'AC_LTDL_ENABLE_INSTALL' => 1, - 'AC_LTDL_OBJDIR' => 1, - 'AC_LTDL_PREOPEN' => 1, - 'AC_LTDL_SHLIBEXT' => 1, - 'AC_LTDL_SHLIBPATH' => 1, - 'AC_LTDL_SYMBOL_USCORE' => 1, - 'AC_LTDL_SYSSEARCHPATH' => 1, - 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, - 'AC_PATH_MAGIC' => 1, - 'AC_PATH_TOOL_PREFIX' => 1, - 'AC_PROG_EGREP' => 1, - 'AC_PROG_LD' => 1, - 'AC_PROG_LD_GNU' => 1, - 'AC_PROG_LD_RELOAD_FLAG' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AC_PROG_NM' => 1, - 'AC_WITH_LTDL' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'AM_AUX_DIR_EXPAND' => 1, - 'AM_CONDITIONAL' => 1, - 'AM_DEP_TRACK' => 1, - 'AM_DISABLE_SHARED' => 1, - 'AM_DISABLE_STATIC' => 1, - 'AM_ENABLE_SHARED' => 1, - 'AM_ENABLE_STATIC' => 1, - 'AM_INIT_AUTOMAKE' => 1, - 'AM_MAKE_INCLUDE' => 1, - 'AM_MISSING_HAS_RUN' => 1, - 'AM_MISSING_PROG' => 1, - 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - 'AM_PROG_CC_C_O' => 1, - 'AM_PROG_INSTALL_SH' => 1, - 'AM_PROG_INSTALL_STRIP' => 1, - 'AM_PROG_LD' => 1, - 'AM_PROG_LIBTOOL' => 1, - 'AM_PROG_NM' => 1, - 'AM_RUN_LOG' => 1, - 'AM_SANITY_CHECK' => 1, - 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, - 'AM_SET_DEPDIR' => 1, - 'AM_SET_LEADING_DOT' => 1, - 'AM_SILENT_RULES' => 1, - 'AM_SUBST_NOTMAKE' => 1, - 'AU_DEFUN' => 1, - 'AX_GCC_BUILTIN' => 1, - 'LTDL_CONVENIENCE' => 1, - 'LTDL_INIT' => 1, - 'LTDL_INSTALLABLE' => 1, - 'LTOBSOLETE_VERSION' => 1, - 'LTOPTIONS_VERSION' => 1, - 'LTSUGAR_VERSION' => 1, - 'LTVERSION_VERSION' => 1, - 'LT_AC_PROG_EGREP' => 1, - 'LT_AC_PROG_GCJ' => 1, - 'LT_AC_PROG_RC' => 1, - 'LT_AC_PROG_SED' => 1, - 'LT_CMD_MAX_LEN' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - 'LT_FUNC_ARGZ' => 1, - 'LT_FUNC_DLSYM_USCORE' => 1, - 'LT_INIT' => 1, - 'LT_LANG' => 1, - 'LT_LIB_DLLOAD' => 1, - 'LT_LIB_M' => 1, - 'LT_OUTPUT' => 1, - 'LT_PATH_LD' => 1, - 'LT_PATH_NM' => 1, - 'LT_PROG_GCJ' => 1, - 'LT_PROG_GO' => 1, - 'LT_PROG_RC' => 1, - 'LT_SUPPORTED_TAG' => 1, - 'LT_SYS_DLOPEN_DEPLIBS' => 1, - 'LT_SYS_DLOPEN_SELF' => 1, - 'LT_SYS_DLSEARCH_PATH' => 1, - 'LT_SYS_MODULE_EXT' => 1, - 'LT_SYS_MODULE_PATH' => 1, - 'LT_SYS_SYMBOL_USCORE' => 1, - 'LT_WITH_LTDL' => 1, - 'PKG_CHECK_EXISTS' => 1, - 'PKG_CHECK_MODULES' => 1, - 'PKG_CHECK_MODULES_STATIC' => 1, - 'PKG_CHECK_VAR' => 1, - 'PKG_HAVE_DEFINE_WITH_MODULES' => 1, - 'PKG_HAVE_WITH_MODULES' => 1, - 'PKG_INSTALLDIR' => 1, - 'PKG_NOARCH_INSTALLDIR' => 1, - 'PKG_PROG_PKG_CONFIG' => 1, - 'PKG_WITH_MODULES' => 1, - 'XORG_CHANGELOG' => 1, - 'XORG_CHECK_DOCBOOK' => 1, - 'XORG_CHECK_LINKER_FLAGS' => 1, - 'XORG_CHECK_LINUXDOC' => 1, - 'XORG_CHECK_MALLOC_ZERO' => 1, - 'XORG_CHECK_SGML_DOCTOOLS' => 1, - 'XORG_COMPILER_BRAND' => 1, - 'XORG_COMPILER_FLAGS' => 1, - 'XORG_CWARNFLAGS' => 1, - 'XORG_DEFAULT_NOCODE_OPTIONS' => 1, - 'XORG_DEFAULT_OPTIONS' => 1, - 'XORG_ENABLE_DEVEL_DOCS' => 1, - 'XORG_ENABLE_DOCS' => 1, - 'XORG_ENABLE_INTEGRATION_TESTS' => 1, - 'XORG_ENABLE_SPECS' => 1, - 'XORG_ENABLE_UNIT_TESTS' => 1, - 'XORG_INSTALL' => 1, - 'XORG_LD_WRAP' => 1, - 'XORG_LINT_LIBRARY' => 1, - 'XORG_MANPAGE_SECTIONS' => 1, - 'XORG_MEMORY_CHECK_FLAGS' => 1, - 'XORG_PROG_RAWCPP' => 1, - 'XORG_RELEASE_VERSION' => 1, - 'XORG_STRICT_OPTION' => 1, - 'XORG_TESTSET_CFLAG' => 1, - 'XORG_WITH_ASCIIDOC' => 1, - 'XORG_WITH_DOXYGEN' => 1, - 'XORG_WITH_FOP' => 1, - 'XORG_WITH_GLIB' => 1, - 'XORG_WITH_GROFF' => 1, - 'XORG_WITH_LINT' => 1, - 'XORG_WITH_M4' => 1, - 'XORG_WITH_PERL' => 1, - 'XORG_WITH_PS2PDF' => 1, - 'XORG_WITH_XMLTO' => 1, - 'XORG_WITH_XSLTPROC' => 1, - '_AC_AM_CONFIG_HEADER_HOOK' => 1, - '_AC_PROG_LIBTOOL' => 1, - '_AM_AUTOCONF_VERSION' => 1, - '_AM_CONFIG_MACRO_DIRS' => 1, - '_AM_DEPENDENCIES' => 1, - '_AM_FILESYSTEM_TIMESTAMP_RESOLUTION' => 1, - '_AM_IF_OPTION' => 1, - '_AM_MANGLE_OPTION' => 1, - '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - '_AM_PROG_CC_C_O' => 1, - '_AM_PROG_RM_F' => 1, - '_AM_PROG_TAR' => 1, - '_AM_PROG_XARGS_N' => 1, - '_AM_SET_OPTION' => 1, - '_AM_SET_OPTIONS' => 1, - '_AM_SILENT_RULES' => 1, - '_AM_SLEEP_FRACTIONAL_SECONDS' => 1, - '_AM_SUBST_NOTMAKE' => 1, - '_LTDL_SETUP' => 1, - '_LT_AC_CHECK_DLFCN' => 1, - '_LT_AC_FILE_LTDLL_C' => 1, - '_LT_AC_LANG_CXX' => 1, - '_LT_AC_LANG_CXX_CONFIG' => 1, - '_LT_AC_LANG_C_CONFIG' => 1, - '_LT_AC_LANG_F77' => 1, - '_LT_AC_LANG_F77_CONFIG' => 1, - '_LT_AC_LANG_GCJ' => 1, - '_LT_AC_LANG_GCJ_CONFIG' => 1, - '_LT_AC_LANG_RC_CONFIG' => 1, - '_LT_AC_LOCK' => 1, - '_LT_AC_PROG_CXXCPP' => 1, - '_LT_AC_PROG_ECHO_BACKSLASH' => 1, - '_LT_AC_SHELL_INIT' => 1, - '_LT_AC_SYS_COMPILER' => 1, - '_LT_AC_SYS_LIBPATH_AIX' => 1, - '_LT_AC_TAGCONFIG' => 1, - '_LT_AC_TAGVAR' => 1, - '_LT_AC_TRY_DLOPEN_SELF' => 1, - '_LT_CC_BASENAME' => 1, - '_LT_COMPILER_BOILERPLATE' => 1, - '_LT_COMPILER_OPTION' => 1, - '_LT_DLL_DEF_P' => 1, - '_LT_LIBOBJ' => 1, - '_LT_LINKER_BOILERPLATE' => 1, - '_LT_LINKER_OPTION' => 1, - '_LT_PATH_TOOL_PREFIX' => 1, - '_LT_PREPARE_SED_QUOTE_VARS' => 1, - '_LT_PROG_CXX' => 1, - '_LT_PROG_ECHO_BACKSLASH' => 1, - '_LT_PROG_F77' => 1, - '_LT_PROG_FC' => 1, - '_LT_PROG_LTMAIN' => 1, - '_LT_REQUIRED_DARWIN_CHECKS' => 1, - '_LT_WITH_SYSROOT' => 1, - '_PKG_SHORT_ERRORS_SUPPORTED' => 1, - '_m4_warn' => 1, - 'include' => 1, - 'm4_include' => 1, - 'm4_pattern_allow' => 1, - 'm4_pattern_forbid' => 1 - } - ], 'Autom4te::Request' ), - bless( [ - '1', - 1, - [ - '/home/linuxbrew/.linuxbrew/Cellar/autoconf/2.73/share/autoconf' - ], - [ - '/home/linuxbrew/.linuxbrew/Cellar/autoconf/2.73/share/autoconf/autoconf/autoconf.m4f', - 'aclocal.m4', - 'configure.ac' - ], - { - 'AC_CANONICAL_BUILD' => 1, - 'AC_CANONICAL_HOST' => 1, - 'AC_CANONICAL_SYSTEM' => 1, - 'AC_CANONICAL_TARGET' => 1, - 'AC_CONFIG_AUX_DIR' => 1, - 'AC_CONFIG_FILES' => 1, - 'AC_CONFIG_HEADERS' => 1, - 'AC_CONFIG_LIBOBJ_DIR' => 1, - 'AC_CONFIG_LINKS' => 1, - 'AC_CONFIG_MACRO_DIR' => 1, - 'AC_CONFIG_MACRO_DIR_TRACE' => 1, - 'AC_CONFIG_SUBDIRS' => 1, - 'AC_DEFINE_TRACE_LITERAL' => 1, - 'AC_FC_FREEFORM' => 1, - 'AC_FC_PP_DEFINE' => 1, - 'AC_FC_PP_SRCEXT' => 1, - 'AC_FC_SRCEXT' => 1, - 'AC_INIT' => 1, - 'AC_LIBSOURCE' => 1, - 'AC_LIB_HAVE_LINKFLAGS' => 1, - 'AC_LIB_LINKFLAGS' => 1, - 'AC_LIB_LINKFLAGS_FROM_LIBS' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AC_REQUIRE_AUX_FILE' => 1, - 'AC_SUBST' => 1, - 'AC_SUBST_TRACE' => 1, - 'AH_OUTPUT' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'AM_CONDITIONAL' => 1, - 'AM_ENABLE_MULTILIB' => 1, - 'AM_EXTRA_RECURSIVE_TARGETS' => 1, - 'AM_GNU_GETTEXT' => 1, - 'AM_GNU_GETTEXT_INTL_SUBDIR' => 1, - 'AM_GNU_GETTEXT_REQUIRE_VERSION' => 1, - 'AM_GNU_GETTEXT_VERSION' => 1, - 'AM_ICONV' => 1, - 'AM_INIT_AUTOMAKE' => 1, - 'AM_MAINTAINER_MODE' => 1, - 'AM_MAKEFILE_INCLUDE' => 1, - 'AM_NLS' => 1, - 'AM_PATH_GUILE' => 1, - 'AM_POT_TOOLS' => 1, - 'AM_PROG_AR' => 1, - 'AM_PROG_CC_C_O' => 1, - 'AM_PROG_CXX_C_O' => 1, - 'AM_PROG_F77_C_O' => 1, - 'AM_PROG_FC_C_O' => 1, - 'AM_PROG_LIBTOOL' => 1, - 'AM_PROG_MKDIR_P' => 1, - 'AM_PROG_MOC' => 1, - 'AM_SILENT_RULES' => 1, - 'AM_XGETTEXT_OPTION' => 1, - 'GTK_DOC_CHECK' => 1, - 'GUILE_FLAGS' => 1, - 'IT_PROG_INTLTOOL' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - 'LT_INIT' => 1, - 'LT_SUPPORTED_TAG' => 1, - '_AM_COND_ELSE' => 1, - '_AM_COND_ENDIF' => 1, - '_AM_COND_IF' => 1, - '_AM_MAKEFILE_INCLUDE' => 1, - '_AM_SUBST_NOTMAKE' => 1, - '_LT_AC_TAGCONFIG' => 1, - '_m4_warn' => 1, - 'include' => 1, - 'm4_include' => 1, - 'm4_pattern_allow' => 1, - 'm4_pattern_forbid' => 1, - 'm4_sinclude' => 1, - 'sinclude' => 1 - } - ], 'Autom4te::Request' ), - bless( [ - '2', - 1, - [ - '/home/linuxbrew/.linuxbrew/Cellar/autoconf/2.73/share/autoconf' - ], - [ - '/home/linuxbrew/.linuxbrew/Cellar/autoconf/2.73/share/autoconf/autoconf/autoconf.m4f', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/internal/ac-config-macro-dirs.m4', - '/usr/share/aclocal/pkg.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal/ltargz.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4', - '/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/amversion.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/auxdir.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/cond.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depend.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depout.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/init.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/install-sh.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/lead-dot.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/make.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/missing.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/prog-cc-c-o.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/rmf.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/runlog.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/sanity.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/silent.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/strip.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/substnot.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/tar.m4', - '/home/linuxbrew/.linuxbrew/share/aclocal-1.18/xargsn.m4', - 'm4/ax_gcc_builtin.m4', - 'm4/libtool.m4', - 'm4/ltoptions.m4', - 'm4/ltsugar.m4', - 'm4/ltversion.m4', - 'm4/lt~obsolete.m4', - 'configure.ac' - ], - { - 'AC_CHECK_LIBM' => 1, - 'AC_CONFIG_MACRO_DIR' => 1, - 'AC_CONFIG_MACRO_DIR_TRACE' => 1, - 'AC_DEFUN' => 1, - 'AC_DEFUN_ONCE' => 1, - 'AC_DEPLIBS_CHECK_METHOD' => 1, - 'AC_DISABLE_FAST_INSTALL' => 1, - 'AC_DISABLE_SHARED' => 1, - 'AC_DISABLE_STATIC' => 1, - 'AC_ENABLE_FAST_INSTALL' => 1, - 'AC_ENABLE_SHARED' => 1, - 'AC_ENABLE_STATIC' => 1, - 'AC_LIBLTDL_CONVENIENCE' => 1, - 'AC_LIBLTDL_INSTALLABLE' => 1, - 'AC_LIBTOOL_COMPILER_OPTION' => 1, - 'AC_LIBTOOL_CONFIG' => 1, - 'AC_LIBTOOL_CXX' => 1, - 'AC_LIBTOOL_DLOPEN' => 1, - 'AC_LIBTOOL_DLOPEN_SELF' => 1, - 'AC_LIBTOOL_F77' => 1, - 'AC_LIBTOOL_FC' => 1, - 'AC_LIBTOOL_GCJ' => 1, - 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, - 'AC_LIBTOOL_LANG_C_CONFIG' => 1, - 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, - 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, - 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, - 'AC_LIBTOOL_LINKER_OPTION' => 1, - 'AC_LIBTOOL_OBJDIR' => 1, - 'AC_LIBTOOL_PICMODE' => 1, - 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, - 'AC_LIBTOOL_PROG_CC_C_O' => 1, - 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, - 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, - 'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1, - 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, - 'AC_LIBTOOL_RC' => 1, - 'AC_LIBTOOL_SETUP' => 1, - 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, - 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, - 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, - 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, - 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, - 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, - 'AC_LIBTOOL_WIN32_DLL' => 1, - 'AC_LIB_LTDL' => 1, - 'AC_LTDL_DLLIB' => 1, - 'AC_LTDL_DLSYM_USCORE' => 1, - 'AC_LTDL_ENABLE_INSTALL' => 1, - 'AC_LTDL_OBJDIR' => 1, - 'AC_LTDL_PREOPEN' => 1, - 'AC_LTDL_SHLIBEXT' => 1, - 'AC_LTDL_SHLIBPATH' => 1, - 'AC_LTDL_SYMBOL_USCORE' => 1, - 'AC_LTDL_SYSSEARCHPATH' => 1, - 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, - 'AC_PATH_MAGIC' => 1, - 'AC_PATH_TOOL_PREFIX' => 1, - 'AC_PROG_EGREP' => 1, - 'AC_PROG_LD' => 1, - 'AC_PROG_LD_GNU' => 1, - 'AC_PROG_LD_RELOAD_FLAG' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AC_PROG_NM' => 1, - 'AC_WITH_LTDL' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'AM_AUX_DIR_EXPAND' => 1, - 'AM_CONDITIONAL' => 1, - 'AM_DEP_TRACK' => 1, - 'AM_DISABLE_SHARED' => 1, - 'AM_DISABLE_STATIC' => 1, - 'AM_ENABLE_SHARED' => 1, - 'AM_ENABLE_STATIC' => 1, - 'AM_INIT_AUTOMAKE' => 1, - 'AM_MAKE_INCLUDE' => 1, - 'AM_MISSING_HAS_RUN' => 1, - 'AM_MISSING_PROG' => 1, - 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - 'AM_PROG_CC_C_O' => 1, - 'AM_PROG_INSTALL_SH' => 1, - 'AM_PROG_INSTALL_STRIP' => 1, - 'AM_PROG_LD' => 1, - 'AM_PROG_LIBTOOL' => 1, - 'AM_PROG_NM' => 1, - 'AM_RUN_LOG' => 1, - 'AM_SANITY_CHECK' => 1, - 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, - 'AM_SET_DEPDIR' => 1, - 'AM_SET_LEADING_DOT' => 1, - 'AM_SILENT_RULES' => 1, - 'AM_SUBST_NOTMAKE' => 1, - 'AU_DEFUN' => 1, - 'AX_GCC_BUILTIN' => 1, - 'LTDL_CONVENIENCE' => 1, - 'LTDL_INIT' => 1, - 'LTDL_INSTALLABLE' => 1, - 'LTOBSOLETE_VERSION' => 1, - 'LTOPTIONS_VERSION' => 1, - 'LTSUGAR_VERSION' => 1, - 'LTVERSION_VERSION' => 1, - 'LT_AC_PROG_EGREP' => 1, - 'LT_AC_PROG_GCJ' => 1, - 'LT_AC_PROG_RC' => 1, - 'LT_AC_PROG_SED' => 1, - 'LT_CMD_MAX_LEN' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - 'LT_FUNC_ARGZ' => 1, - 'LT_FUNC_DLSYM_USCORE' => 1, - 'LT_INIT' => 1, - 'LT_LANG' => 1, - 'LT_LIB_DLLOAD' => 1, - 'LT_LIB_M' => 1, - 'LT_OUTPUT' => 1, - 'LT_PATH_LD' => 1, - 'LT_PATH_NM' => 1, - 'LT_PROG_GCJ' => 1, - 'LT_PROG_GO' => 1, - 'LT_PROG_RC' => 1, - 'LT_SUPPORTED_TAG' => 1, - 'LT_SYS_DLOPEN_DEPLIBS' => 1, - 'LT_SYS_DLOPEN_SELF' => 1, - 'LT_SYS_DLSEARCH_PATH' => 1, - 'LT_SYS_MODULE_EXT' => 1, - 'LT_SYS_MODULE_PATH' => 1, - 'LT_SYS_SYMBOL_USCORE' => 1, - 'LT_WITH_LTDL' => 1, - 'PKG_CHECK_EXISTS' => 1, - 'PKG_CHECK_MODULES' => 1, - 'PKG_CHECK_MODULES_STATIC' => 1, - 'PKG_CHECK_VAR' => 1, - 'PKG_HAVE_DEFINE_WITH_MODULES' => 1, - 'PKG_HAVE_WITH_MODULES' => 1, - 'PKG_INSTALLDIR' => 1, - 'PKG_NOARCH_INSTALLDIR' => 1, - 'PKG_PROG_PKG_CONFIG' => 1, - 'PKG_WITH_MODULES' => 1, - 'XORG_CHANGELOG' => 1, - 'XORG_CHECK_DOCBOOK' => 1, - 'XORG_CHECK_LINKER_FLAGS' => 1, - 'XORG_CHECK_LINUXDOC' => 1, - 'XORG_CHECK_MALLOC_ZERO' => 1, - 'XORG_CHECK_SGML_DOCTOOLS' => 1, - 'XORG_COMPILER_BRAND' => 1, - 'XORG_COMPILER_FLAGS' => 1, - 'XORG_CWARNFLAGS' => 1, - 'XORG_DEFAULT_NOCODE_OPTIONS' => 1, - 'XORG_DEFAULT_OPTIONS' => 1, - 'XORG_ENABLE_DEVEL_DOCS' => 1, - 'XORG_ENABLE_DOCS' => 1, - 'XORG_ENABLE_INTEGRATION_TESTS' => 1, - 'XORG_ENABLE_SPECS' => 1, - 'XORG_ENABLE_UNIT_TESTS' => 1, - 'XORG_INSTALL' => 1, - 'XORG_LD_WRAP' => 1, - 'XORG_LINT_LIBRARY' => 1, - 'XORG_MANPAGE_SECTIONS' => 1, - 'XORG_MEMORY_CHECK_FLAGS' => 1, - 'XORG_PROG_RAWCPP' => 1, - 'XORG_RELEASE_VERSION' => 1, - 'XORG_STRICT_OPTION' => 1, - 'XORG_TESTSET_CFLAG' => 1, - 'XORG_WITH_ASCIIDOC' => 1, - 'XORG_WITH_DOXYGEN' => 1, - 'XORG_WITH_FOP' => 1, - 'XORG_WITH_GLIB' => 1, - 'XORG_WITH_GROFF' => 1, - 'XORG_WITH_LINT' => 1, - 'XORG_WITH_M4' => 1, - 'XORG_WITH_PERL' => 1, - 'XORG_WITH_PS2PDF' => 1, - 'XORG_WITH_XMLTO' => 1, - 'XORG_WITH_XSLTPROC' => 1, - '_AC_AM_CONFIG_HEADER_HOOK' => 1, - '_AC_PROG_LIBTOOL' => 1, - '_AM_AUTOCONF_VERSION' => 1, - '_AM_CONFIG_MACRO_DIRS' => 1, - '_AM_DEPENDENCIES' => 1, - '_AM_FILESYSTEM_TIMESTAMP_RESOLUTION' => 1, - '_AM_IF_OPTION' => 1, - '_AM_MANGLE_OPTION' => 1, - '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - '_AM_PROG_CC_C_O' => 1, - '_AM_PROG_RM_F' => 1, - '_AM_PROG_TAR' => 1, - '_AM_PROG_XARGS_N' => 1, - '_AM_SET_OPTION' => 1, - '_AM_SET_OPTIONS' => 1, - '_AM_SILENT_RULES' => 1, - '_AM_SLEEP_FRACTIONAL_SECONDS' => 1, - '_AM_SUBST_NOTMAKE' => 1, - '_LTDL_SETUP' => 1, - '_LT_AC_CHECK_DLFCN' => 1, - '_LT_AC_FILE_LTDLL_C' => 1, - '_LT_AC_LANG_CXX' => 1, - '_LT_AC_LANG_CXX_CONFIG' => 1, - '_LT_AC_LANG_C_CONFIG' => 1, - '_LT_AC_LANG_F77' => 1, - '_LT_AC_LANG_F77_CONFIG' => 1, - '_LT_AC_LANG_GCJ' => 1, - '_LT_AC_LANG_GCJ_CONFIG' => 1, - '_LT_AC_LANG_RC_CONFIG' => 1, - '_LT_AC_LOCK' => 1, - '_LT_AC_PROG_CXXCPP' => 1, - '_LT_AC_PROG_ECHO_BACKSLASH' => 1, - '_LT_AC_SHELL_INIT' => 1, - '_LT_AC_SYS_COMPILER' => 1, - '_LT_AC_SYS_LIBPATH_AIX' => 1, - '_LT_AC_TAGCONFIG' => 1, - '_LT_AC_TAGVAR' => 1, - '_LT_AC_TRY_DLOPEN_SELF' => 1, - '_LT_CC_BASENAME' => 1, - '_LT_COMPILER_BOILERPLATE' => 1, - '_LT_COMPILER_OPTION' => 1, - '_LT_DLL_DEF_P' => 1, - '_LT_LIBOBJ' => 1, - '_LT_LINKER_BOILERPLATE' => 1, - '_LT_LINKER_OPTION' => 1, - '_LT_PATH_TOOL_PREFIX' => 1, - '_LT_PREPARE_SED_QUOTE_VARS' => 1, - '_LT_PROG_CXX' => 1, - '_LT_PROG_ECHO_BACKSLASH' => 1, - '_LT_PROG_F77' => 1, - '_LT_PROG_FC' => 1, - '_LT_PROG_LTMAIN' => 1, - '_LT_REQUIRED_DARWIN_CHECKS' => 1, - '_LT_WITH_SYSROOT' => 1, - '_PKG_SHORT_ERRORS_SUPPORTED' => 1, - '_m4_warn' => 1, - 'include' => 1, - 'm4_include' => 1, - 'm4_pattern_allow' => 1, - 'm4_pattern_forbid' => 1 - } - ], 'Autom4te::Request' ), - bless( [ - '3', - 1, - [ - '/home/linuxbrew/.linuxbrew/Cellar/autoconf/2.73/share/autoconf' - ], - [ - '/home/linuxbrew/.linuxbrew/Cellar/autoconf/2.73/share/autoconf/autoconf/autoconf.m4f', - 'aclocal.m4', - '/home/linuxbrew/.linuxbrew/Cellar/autoconf/2.73/share/autoconf/autoconf/trailer.m4', - 'configure.ac' - ], - { - 'AC_CANONICAL_BUILD' => 1, - 'AC_CANONICAL_HOST' => 1, - 'AC_CANONICAL_SYSTEM' => 1, - 'AC_CANONICAL_TARGET' => 1, - 'AC_CONFIG_AUX_DIR' => 1, - 'AC_CONFIG_FILES' => 1, - 'AC_CONFIG_HEADERS' => 1, - 'AC_CONFIG_LIBOBJ_DIR' => 1, - 'AC_CONFIG_LINKS' => 1, - 'AC_CONFIG_MACRO_DIR' => 1, - 'AC_CONFIG_MACRO_DIR_TRACE' => 1, - 'AC_CONFIG_SUBDIRS' => 1, - 'AC_DEFINE_TRACE_LITERAL' => 1, - 'AC_FC_FREEFORM' => 1, - 'AC_FC_PP_DEFINE' => 1, - 'AC_FC_PP_SRCEXT' => 1, - 'AC_FC_SRCEXT' => 1, - 'AC_INIT' => 1, - 'AC_LIBSOURCE' => 1, - 'AC_LIB_HAVE_LINKFLAGS' => 1, - 'AC_LIB_LINKFLAGS' => 1, - 'AC_LIB_LINKFLAGS_FROM_LIBS' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AC_REQUIRE_AUX_FILE' => 1, - 'AC_SUBST' => 1, - 'AC_SUBST_TRACE' => 1, - 'AH_OUTPUT' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'AM_CONDITIONAL' => 1, - 'AM_ENABLE_MULTILIB' => 1, - 'AM_EXTRA_RECURSIVE_TARGETS' => 1, - 'AM_GNU_GETTEXT' => 1, - 'AM_GNU_GETTEXT_INTL_SUBDIR' => 1, - 'AM_GNU_GETTEXT_REQUIRE_VERSION' => 1, - 'AM_GNU_GETTEXT_VERSION' => 1, - 'AM_ICONV' => 1, - 'AM_INIT_AUTOMAKE' => 1, - 'AM_MAINTAINER_MODE' => 1, - 'AM_MAKEFILE_INCLUDE' => 1, - 'AM_NLS' => 1, - 'AM_PATH_GUILE' => 1, - 'AM_POT_TOOLS' => 1, - 'AM_PROG_AR' => 1, - 'AM_PROG_CC_C_O' => 1, - 'AM_PROG_CXX_C_O' => 1, - 'AM_PROG_F77_C_O' => 1, - 'AM_PROG_FC_C_O' => 1, - 'AM_PROG_LIBTOOL' => 1, - 'AM_PROG_MKDIR_P' => 1, - 'AM_PROG_MOC' => 1, - 'AM_SILENT_RULES' => 1, - 'AM_XGETTEXT_OPTION' => 1, - 'GTK_DOC_CHECK' => 1, - 'GUILE_FLAGS' => 1, - 'IT_PROG_INTLTOOL' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - 'LT_INIT' => 1, - 'LT_SUPPORTED_TAG' => 1, - '_AM_COND_ELSE' => 1, - '_AM_COND_ENDIF' => 1, - '_AM_COND_IF' => 1, - '_AM_MAKEFILE_INCLUDE' => 1, - '_AM_SUBST_NOTMAKE' => 1, - '_LT_AC_TAGCONFIG' => 1, - '_m4_warn' => 1, - 'include' => 1, - 'm4_include' => 1, - 'm4_pattern_allow' => 1, - 'm4_pattern_forbid' => 1, - 'm4_sinclude' => 1, - 'sinclude' => 1 - } - ], 'Autom4te::Request' ) - ); - diff --git a/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.0 b/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.0 deleted file mode 100644 index 20d8eeef7..000000000 --- a/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.0 +++ /dev/null @@ -1,4561 +0,0 @@ -m4trace:/usr/share/aclocal/pkg.m4:58: -1- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) -m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) -AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) -AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) -AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=m4_default([$1], [0.9.0]) - AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - PKG_CONFIG="" - fi -fi[]dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:92: -1- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -if test -n "$PKG_CONFIG" && \ - AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then - m4_default([$2], [:]) -m4_ifvaln([$3], [else - $3])dnl -fi]) -m4trace:/usr/share/aclocal/pkg.m4:121: -1- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi[]dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:139: -1- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl -AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl - -pkg_failed=no -AC_MSG_CHECKING([for $2]) - -_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) -_PKG_CONFIG([$1][_LIBS], [libs], [$2]) - -m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS -and $1[]_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details.]) - -if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) - _PKG_SHORT_ERRORS_SUPPORTED - if test $_pkg_short_errors_supported = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else - $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD - - m4_default([$4], [AC_MSG_ERROR( -[Package requirements ($2) were not met: - -$$1_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -_PKG_TEXT])[]dnl - ]) -elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) - m4_default([$4], [AC_MSG_FAILURE( -[The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -_PKG_TEXT - -To get pkg-config, see .])[]dnl - ]) -else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS - AC_MSG_RESULT([yes]) - $3 -fi[]dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:208: -1- AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -_save_PKG_CONFIG=$PKG_CONFIG -PKG_CONFIG="$PKG_CONFIG --static" -PKG_CHECK_MODULES($@) -PKG_CONFIG=$_save_PKG_CONFIG[]dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:226: -1- AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([pkgconfigdir], - [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, - [with_pkgconfigdir=]pkg_default) -AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) -m4trace:/usr/share/aclocal/pkg.m4:248: -1- AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([noarch-pkgconfigdir], - [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, - [with_noarch_pkgconfigdir=]pkg_default) -AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) -m4trace:/usr/share/aclocal/pkg.m4:267: -1- AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl - -_PKG_CONFIG([$1], [variable="][$3]["], [$2]) -AS_VAR_COPY([$1], [pkg_cv_][$1]) - -AS_VAR_IF([$1], [""], [$5], [$4])dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:285: -1- AC_DEFUN([PKG_WITH_MODULES], [ -m4_pushdef([with_arg], m4_tolower([$1])) - -m4_pushdef([description], - [m4_default([$5], [build with ]with_arg[ support])]) - -m4_pushdef([def_arg], [m4_default([$6], [auto])]) -m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) -m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) - -m4_case(def_arg, - [yes],[m4_pushdef([with_without], [--without-]with_arg)], - [m4_pushdef([with_without],[--with-]with_arg)]) - -AC_ARG_WITH(with_arg, - AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, - [AS_TR_SH([with_]with_arg)=def_arg]) - -AS_CASE([$AS_TR_SH([with_]with_arg)], - [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], - [auto],[PKG_CHECK_MODULES([$1],[$2], - [m4_n([def_action_if_found]) $3], - [m4_n([def_action_if_not_found]) $4])]) - -m4_popdef([with_arg]) -m4_popdef([description]) -m4_popdef([def_arg]) - -]) -m4trace:/usr/share/aclocal/pkg.m4:322: -1- AC_DEFUN([PKG_HAVE_WITH_MODULES], [ -PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) - -AM_CONDITIONAL([HAVE_][$1], - [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) -]) -m4trace:/usr/share/aclocal/pkg.m4:337: -1- AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ -PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) - -AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], - [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:62: -1- AC_DEFUN([LT_INIT], [AC_PREREQ([2.64])dnl We use AC_PATH_PROGS_FEATURE_CHECK -AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl -AC_BEFORE([$0], [LT_LANG])dnl -AC_BEFORE([$0], [LT_OUTPUT])dnl -AC_BEFORE([$0], [LTDL_INIT])dnl -m4_require([_LT_CHECK_BUILDDIR])dnl - -dnl Autoconf doesn't catch unexpanded LT_ macros by default: -m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl -m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl -dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 -dnl unless we require an AC_DEFUNed macro: -AC_REQUIRE([LTOPTIONS_VERSION])dnl -AC_REQUIRE([LTSUGAR_VERSION])dnl -AC_REQUIRE([LTVERSION_VERSION])dnl -AC_REQUIRE([LTOBSOLETE_VERSION])dnl -m4_require([_LT_PROG_LTMAIN])dnl - -_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) - -dnl Parse OPTIONS -_LT_SET_OPTIONS([$0], [$1]) - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS=$ltmain - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' -AC_SUBST(LIBTOOL)dnl - -_LT_SETUP - -# Only expand once: -m4_define([LT_INIT]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:100: -1- AU_DEFUN([AC_PROG_LIBTOOL], [m4_if($#, 0, [LT_INIT], [LT_INIT($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:100: -1- AC_DEFUN([AC_PROG_LIBTOOL], [m4_warn([obsolete], [The macro 'AC_PROG_LIBTOOL' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_INIT], [LT_INIT($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:101: -1- AU_DEFUN([AM_PROG_LIBTOOL], [m4_if($#, 0, [LT_INIT], [LT_INIT($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:101: -1- AC_DEFUN([AM_PROG_LIBTOOL], [m4_warn([obsolete], [The macro 'AM_PROG_LIBTOOL' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_INIT], [LT_INIT($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:621: -1- AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} -AC_MSG_NOTICE([creating $CONFIG_LT]) -_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], -[# Run this file to recreate a libtool stub with the current configuration.]) - -cat >>"$CONFIG_LT" <<\_LTEOF -lt_cl_silent=false -exec AS_MESSAGE_LOG_FD>>config.log -{ - echo - AS_BOX([Running $as_me.]) -} >&AS_MESSAGE_LOG_FD - -lt_cl_help="\ -'$as_me' creates a local libtool stub from the current configuration, -for use in further configure time tests before the real libtool is -generated. - -Usage: $[0] [[OPTIONS]] - - -h, --help print this help, then exit - -V, --version print version number, then exit - -q, --quiet do not print progress messages - -d, --debug don't remove temporary files - -Report bugs to ." - -lt_cl_version="\ -m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl -m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) -configured by $[0], generated by m4_PACKAGE_STRING. - -Copyright (C) 2024 Free Software Foundation, Inc. -This config.lt script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -while test 0 != $[#] -do - case $[1] in - --version | --v* | -V ) - echo "$lt_cl_version"; exit 0 ;; - --help | --h* | -h ) - echo "$lt_cl_help"; exit 0 ;; - --debug | --d* | -d ) - debug=: ;; - --quiet | --q* | --silent | --s* | -q ) - lt_cl_silent=: ;; - - -*) AC_MSG_ERROR([unrecognized option: $[1] -Try '$[0] --help' for more information.]) ;; - - *) AC_MSG_ERROR([unrecognized argument: $[1] -Try '$[0] --help' for more information.]) ;; - esac - shift -done - -if $lt_cl_silent; then - exec AS_MESSAGE_FD>/dev/null -fi -_LTEOF - -cat >>"$CONFIG_LT" <<_LTEOF -_LT_OUTPUT_LIBTOOL_COMMANDS_INIT -_LTEOF - -cat >>"$CONFIG_LT" <<\_LTEOF -AC_MSG_NOTICE([creating $ofile]) -_LT_OUTPUT_LIBTOOL_COMMANDS -AS_EXIT(0) -_LTEOF -chmod +x "$CONFIG_LT" - -# configure is writing to config.log, but config.lt does its own redirection, -# appending to config.log, which fails on DOS, as config.log is still kept -# open by configure. Here we exec the FD to /dev/null, effectively closing -# config.log, so it can be properly (re)opened and appended to by config.lt. -lt_cl_success=: -test yes = "$silent" && - lt_config_lt_args="$lt_config_lt_args --quiet" -exec AS_MESSAGE_LOG_FD>/dev/null -$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false -exec AS_MESSAGE_LOG_FD>>config.log -$lt_cl_success || AS_EXIT(1) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:813: -1- AC_DEFUN([LT_SUPPORTED_TAG], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:824: -1- AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl -m4_case([$1], - [C], [_LT_LANG(C)], - [C++], [_LT_LANG(CXX)], - [Go], [_LT_LANG(GO)], - [Java], [_LT_LANG(GCJ)], - [Fortran 77], [_LT_LANG(F77)], - [Fortran], [_LT_LANG(FC)], - [Windows Resource], [_LT_LANG(RC)], - [m4_ifdef([_LT_LANG_]$1[_CONFIG], - [_LT_LANG($1)], - [m4_fatal([$0: unsupported language: "$1"])])])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:916: -1- AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:916: -1- AC_DEFUN([AC_LIBTOOL_CXX], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_CXX' is obsolete. -You should run autoupdate.])dnl -LT_LANG(C++)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:917: -1- AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:917: -1- AC_DEFUN([AC_LIBTOOL_F77], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_F77' is obsolete. -You should run autoupdate.])dnl -LT_LANG(Fortran 77)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:918: -1- AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:918: -1- AC_DEFUN([AC_LIBTOOL_FC], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_FC' is obsolete. -You should run autoupdate.])dnl -LT_LANG(Fortran)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:919: -1- AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:919: -1- AC_DEFUN([AC_LIBTOOL_GCJ], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_GCJ' is obsolete. -You should run autoupdate.])dnl -LT_LANG(Java)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:920: -1- AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:920: -1- AC_DEFUN([AC_LIBTOOL_RC], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_RC' is obsolete. -You should run autoupdate.])dnl -LT_LANG(Windows Resource)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1278: -1- AC_DEFUN([_LT_WITH_SYSROOT], [m4_require([_LT_DECL_SED])dnl -AC_MSG_CHECKING([for sysroot]) -AC_ARG_WITH([sysroot], -[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], - [Search for dependent libraries within DIR (or the compiler's sysroot - if not specified).])], -[], [with_sysroot=no]) - -dnl lt_sysroot will always be passed unquoted. We quote it here -dnl in case the user passed a directory name. -lt_sysroot= -case $with_sysroot in #( - yes) - if test yes = "$GCC"; then - # Trim trailing / since we'll always append absolute paths and we want - # to avoid //, if only for less confusing output for the user. - lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - AC_MSG_RESULT([$with_sysroot]) - AC_MSG_ERROR([The sysroot must be an absolute path.]) - ;; -esac - - AC_MSG_RESULT([${lt_sysroot:-no}]) -_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl -[dependent libraries, and where our libraries should be installed.])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1618: -1- AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_DECL_SED])dnl -AC_CACHE_CHECK([$1], [$2], - [$2=no - m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - $2=yes - fi - fi - $RM conftest* -]) - -if test yes = "[$]$2"; then - m4_if([$5], , :, [$5]) -else - m4_if([$6], , :, [$6]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1660: -1- AU_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [m4_if($#, 0, [_LT_COMPILER_OPTION], [_LT_COMPILER_OPTION($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1660: -1- AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_COMPILER_OPTION' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [_LT_COMPILER_OPTION], [_LT_COMPILER_OPTION($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1669: -1- AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_DECL_SED])dnl -AC_CACHE_CHECK([$1], [$2], - [$2=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $3" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&AS_MESSAGE_LOG_FD - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - $2=yes - fi - else - $2=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS -]) - -if test yes = "[$]$2"; then - m4_if([$4], , :, [$4]) -else - m4_if([$5], , :, [$5]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1704: -1- AU_DEFUN([AC_LIBTOOL_LINKER_OPTION], [m4_if($#, 0, [_LT_LINKER_OPTION], [_LT_LINKER_OPTION($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1704: -1- AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_LINKER_OPTION' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [_LT_LINKER_OPTION], [_LT_LINKER_OPTION($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1711: -1- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl -# find the maximum length of command line arguments -AC_MSG_CHECKING([the maximum length of command line arguments]) -AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl - i=0 - teststring=ABCD - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu* | ironclad*) - # Under GNU Hurd and Ironclad, this test is not required because there - # is no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | windows* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[[ ]]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test X`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test 17 != "$i" # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac -]) -if test -n "$lt_cv_sys_max_cmd_len"; then - AC_MSG_RESULT($lt_cv_sys_max_cmd_len) -else - AC_MSG_RESULT(none) -fi -max_cmd_len=$lt_cv_sys_max_cmd_len -_LT_DECL([], [max_cmd_len], [0], - [What is the maximum length of a command?]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1850: -1- AU_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [m4_if($#, 0, [LT_CMD_MAX_LEN], [LT_CMD_MAX_LEN($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1850: -1- AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_SYS_MAX_CMD_LEN' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_CMD_MAX_LEN], [LT_CMD_MAX_LEN($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:1961: -1- AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl -if test yes != "$enable_dlopen"; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen=load_add_on - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | windows* | pw32* | cegcc*) - lt_cv_dlopen=LoadLibrary - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ - lt_cv_dlopen=dyld - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ]) - ;; - - tpf*) - # Don't try to run any link tests for TPF. We know it's impossible - # because TPF is a cross-compiler, and we know how we open DSOs. - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - lt_cv_dlopen_self=no - ;; - - *) - AC_CHECK_FUNC([shl_load], - [lt_cv_dlopen=shl_load], - [AC_CHECK_LIB([dld], [shl_load], - [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], - [AC_CHECK_FUNC([dlopen], - [lt_cv_dlopen=dlopen], - [AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], - [AC_CHECK_LIB([svld], [dlopen], - [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], - [AC_CHECK_LIB([dld], [dld_link], - [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) - ]) - ]) - ]) - ]) - ]) - ;; - esac - - if test no = "$lt_cv_dlopen"; then - enable_dlopen=no - else - enable_dlopen=yes - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS=$CPPFLAGS - test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS=$LDFLAGS - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS=$LIBS - LIBS="$lt_cv_dlopen_libs $LIBS" - - AC_CACHE_CHECK([whether a program can dlopen itself], - lt_cv_dlopen_self, [dnl - _LT_TRY_DLOPEN_SELF( - lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, - lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) - ]) - - if test yes = "$lt_cv_dlopen_self"; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - AC_CACHE_CHECK([whether a statically linked program can dlopen itself], - lt_cv_dlopen_self_static, [dnl - _LT_TRY_DLOPEN_SELF( - lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, - lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) - ]) - fi - - CPPFLAGS=$save_CPPFLAGS - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi -_LT_DECL([dlopen_support], [enable_dlopen], [0], - [Whether dlopen is supported]) -_LT_DECL([dlopen_self], [enable_dlopen_self], [0], - [Whether dlopen of programs is supported]) -_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], - [Whether dlopen of statically linked programs is supported]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:2086: -1- AU_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [m4_if($#, 0, [LT_SYS_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:2086: -1- AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_DLOPEN_SELF' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3284: -1- AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl -AC_MSG_CHECKING([for $1]) -AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, -[case $MAGIC_CMD in -[[\\/*] | ?:[\\/]*]) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR -dnl $ac_dummy forces splitting on constant user-supplied paths. -dnl POSIX.2 word splitting is done only on the output of word expansions, -dnl not every word. This closes a longstanding sh security hole. - ac_dummy="m4_if([$2], , $PATH, [$2])" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$1"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"$1" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac]) -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - AC_MSG_RESULT($MAGIC_CMD) -else - AC_MSG_RESULT(no) -fi -_LT_DECL([], [MAGIC_CMD], [0], - [Used to examine libraries when file_magic_cmd begins with "file"])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3346: -1- AU_DEFUN([AC_PATH_TOOL_PREFIX], [m4_if($#, 0, [_LT_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3346: -1- AC_DEFUN([AC_PATH_TOOL_PREFIX], [m4_warn([obsolete], [The macro 'AC_PATH_TOOL_PREFIX' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [_LT_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3369: -1- AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -m4_require([_LT_DECL_SED])dnl -m4_require([_LT_DECL_EGREP])dnl -m4_require([_LT_PROG_ECHO_BACKSLASH])dnl - -AC_ARG_WITH([gnu-ld], - [AS_HELP_STRING([--with-gnu-ld], - [assume the C compiler uses GNU ld @<:@default=no@:>@])], - [test no = "$withval" || with_gnu_ld=yes], - [with_gnu_ld=no])dnl - -ac_prog=ld -if test yes = "$GCC"; then - # Check if gcc -print-prog-name=ld gives a path. - AC_MSG_CHECKING([for ld used by $CC]) - case $host in - *-*-mingw* | *-*-windows*) - # gcc leaves a trailing carriage return, which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [[\\/]]* | ?:[[\\/]]*) - re_direlt='/[[^/]][[^/]]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD=$ac_prog - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test yes = "$with_gnu_ld"; then - AC_MSG_CHECKING([for GNU ld]) -else - AC_MSG_CHECKING([for non-GNU ld]) -fi -AC_CACHE_VAL(lt_cv_path_LD, -[if test -z "$LD"; then - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD=$ac_dir/$ac_prog - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &1 | $SED '1q'` in - *$lt_bad_file* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break 2 - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break 2 - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS=$lt_save_ifs - done - : ${lt_cv_path_NM=no} -fi]) -if test no != "$lt_cv_path_NM"; then - NM=$lt_cv_path_NM -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols -headers" - ;; - *) - DUMPBIN=: - ;; - esac - fi - AC_SUBST([DUMPBIN]) - if test : != "$DUMPBIN"; then - NM=$DUMPBIN - fi -fi -test -z "$NM" && NM=nm -AC_SUBST([NM]) -_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl - -AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], - [lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&AS_MESSAGE_LOG_FD - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&AS_MESSAGE_LOG_FD - (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) - cat conftest.out >&AS_MESSAGE_LOG_FD - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest*]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3890: -1- AU_DEFUN([AM_PROG_NM], [m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3890: -1- AC_DEFUN([AM_PROG_NM], [m4_warn([obsolete], [The macro 'AM_PROG_NM' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3891: -1- AU_DEFUN([AC_PROG_NM], [m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3891: -1- AC_DEFUN([AC_PROG_NM], [m4_warn([obsolete], [The macro 'AC_PROG_NM' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3962: -1- AC_DEFUN([_LT_DLL_DEF_P], [dnl - test DEF = "`$SED -n dnl - -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace - -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments - -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl - -e q dnl Only consider the first "real" line - $1`" dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3976: -1- AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl -LIBM= -case $host in -*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-mingw* | *-*-pw32* | *-*-darwin*) - # These system don't have libm, or don't need it - ;; -*-ncr-sysv4.3*) - AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) - AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") - ;; -*) - AC_CHECK_LIB(m, cos, LIBM=-lm) - ;; -esac -AC_SUBST([LIBM]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3995: -1- AU_DEFUN([AC_CHECK_LIBM], [m4_if($#, 0, [LT_LIB_M], [LT_LIB_M($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:3995: -1- AC_DEFUN([AC_CHECK_LIBM], [m4_warn([obsolete], [The macro 'AC_CHECK_LIBM' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_LIB_M], [LT_LIB_M($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:8300: -1- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], - [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], - [AC_CHECK_TOOL(GCJ, gcj,) - test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" - AC_SUBST(GCJFLAGS)])])[]dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:8309: -1- AU_DEFUN([LT_AC_PROG_GCJ], [m4_if($#, 0, [LT_PROG_GCJ], [LT_PROG_GCJ($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:8309: -1- AC_DEFUN([LT_AC_PROG_GCJ], [m4_warn([obsolete], [The macro 'LT_AC_PROG_GCJ' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_PROG_GCJ], [LT_PROG_GCJ($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:8316: -1- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:8323: -1- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:8328: -1- AU_DEFUN([LT_AC_PROG_RC], [m4_if($#, 0, [LT_PROG_RC], [LT_PROG_RC($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/libtool.m4:8328: -1- AC_DEFUN([LT_AC_PROG_RC], [m4_warn([obsolete], [The macro 'LT_AC_PROG_RC' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_PROG_RC], [LT_PROG_RC($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltargz.m4:13: -1- AC_DEFUN([LT_FUNC_ARGZ], [ -dnl Required for use of '$SED' in Cygwin configuration. -AC_REQUIRE([AC_PROG_SED])dnl -AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT]) - -AC_CHECK_TYPES([error_t], - [], - [AC_DEFINE([error_t], [int], - [Define to a type to use for 'error_t' if it is not otherwise available.]) - AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h - does not typedef error_t.])], - [#if defined(HAVE_ARGZ_H) -# include -#endif]) - -LT_ARGZ_H= -AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ - argz_next argz_stringify], [], [LT_ARGZ_H=lt__argz.h; AC_LIBOBJ([lt__argz])]) - -dnl if have system argz functions, allow forced use of -dnl libltdl-supplied implementation (and default to do so -dnl on "known bad" systems). Could use a runtime check, but -dnl (a) detecting malloc issues is notoriously unreliable -dnl (b) only known system that declares argz functions, -dnl provides them, yet they are broken, is cygwin -dnl releases prior to 16-Mar-2007 (1.5.24 and earlier) -dnl So, it's more straightforward simply to special case -dnl this for known bad systems. -AS_IF([test -z "$LT_ARGZ_H"], - [AC_CACHE_CHECK( - [if argz actually works], - [lt_cv_sys_argz_works], - [[case $host_os in #( - *cygwin*) - lt_cv_sys_argz_works=no - if test no != "$cross_compiling"; then - lt_cv_sys_argz_works="guessing no" - else - lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' - save_IFS=$IFS - IFS=-. - set x `uname -r | $SED -e "$lt_sed_extract_leading_digits"` - IFS=$save_IFS - lt_os_major=${2-0} - lt_os_minor=${3-0} - lt_os_micro=${4-0} - if test 1 -lt "$lt_os_major" \ - || { test 1 -eq "$lt_os_major" \ - && { test 5 -lt "$lt_os_minor" \ - || { test 5 -eq "$lt_os_minor" \ - && test 24 -lt "$lt_os_micro"; }; }; }; then - lt_cv_sys_argz_works=yes - fi - fi - ;; #( - *) lt_cv_sys_argz_works=yes ;; - esac]]) - AS_IF([test yes = "$lt_cv_sys_argz_works"], - [AC_DEFINE([HAVE_WORKING_ARGZ], 1, - [This value is set to 1 to indicate that the system argz facility works])], - [LT_ARGZ_H=lt__argz.h - AC_LIBOBJ([lt__argz])])]) - -AC_SUBST([LT_ARGZ_H]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:17: -1- AC_DEFUN([LT_CONFIG_LTDL_DIR], [AC_BEFORE([$0], [LTDL_INIT]) -_$0($*) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:69: -1- AC_DEFUN([LTDL_CONVENIENCE], [AC_BEFORE([$0], [LTDL_INIT])dnl -dnl Although the argument is deprecated and no longer documented, -dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one -dnl here make sure it is the same as any other declaration of libltdl's -dnl location! This also ensures lt_ltdl_dir is set when configure.ac is -dnl not yet using an explicit LT_CONFIG_LTDL_DIR. -m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl -_$0() -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:82: -1- AU_DEFUN([AC_LIBLTDL_CONVENIENCE], [_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_CONVENIENCE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:82: -1- AC_DEFUN([AC_LIBLTDL_CONVENIENCE], [m4_warn([obsolete], [The macro 'AC_LIBLTDL_CONVENIENCE' is obsolete. -You should run autoupdate.])dnl -_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_CONVENIENCE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:125: -1- AC_DEFUN([LTDL_INSTALLABLE], [AC_BEFORE([$0], [LTDL_INIT])dnl -dnl Although the argument is deprecated and no longer documented, -dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one -dnl here make sure it is the same as any other declaration of libltdl's -dnl location! This also ensures lt_ltdl_dir is set when configure.ac is -dnl not yet using an explicit LT_CONFIG_LTDL_DIR. -m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl -_$0() -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:138: -1- AU_DEFUN([AC_LIBLTDL_INSTALLABLE], [_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_INSTALLABLE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:138: -1- AC_DEFUN([AC_LIBLTDL_INSTALLABLE], [m4_warn([obsolete], [The macro 'AC_LIBLTDL_INSTALLABLE' is obsolete. -You should run autoupdate.])dnl -_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_INSTALLABLE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:214: -1- AC_DEFUN([_LT_LIBOBJ], [ - m4_pattern_allow([^_LT_LIBOBJS$]) - _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:227: -1- AC_DEFUN([LTDL_INIT], [dnl Parse OPTIONS -_LT_SET_OPTIONS([$0], [$1]) - -dnl We need to keep our own list of libobjs separate from our parent project, -dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while -dnl we look for our own LIBOBJs. -m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) -m4_pushdef([AC_LIBSOURCES]) - -dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: -m4_if(_LTDL_MODE, [], - [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) - m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], - [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) - -AC_ARG_WITH([included_ltdl], - [AS_HELP_STRING([--with-included-ltdl], - [use the GNU ltdl sources included here])]) - -if test yes != "$with_included_ltdl"; then - # We are not being forced to use the included libltdl sources, so - # decide whether there is a useful installed version we can use. - AC_CHECK_HEADER([ltdl.h], - [AC_CHECK_DECL([lt_dlinterface_register], - [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], - [with_included_ltdl=no], - [with_included_ltdl=yes])], - [with_included_ltdl=yes], - [AC_INCLUDES_DEFAULT - #include ])], - [with_included_ltdl=yes], - [AC_INCLUDES_DEFAULT] - ) -fi - -dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE -dnl was called yet, then for old times' sake, we assume libltdl is in an -dnl eponymous directory: -AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) - -AC_ARG_WITH([ltdl_include], - [AS_HELP_STRING([--with-ltdl-include=DIR], - [use the ltdl headers installed in DIR])]) - -if test -n "$with_ltdl_include"; then - if test -f "$with_ltdl_include/ltdl.h"; then : - else - AC_MSG_ERROR([invalid ltdl include directory: '$with_ltdl_include']) - fi -else - with_ltdl_include=no -fi - -AC_ARG_WITH([ltdl_lib], - [AS_HELP_STRING([--with-ltdl-lib=DIR], - [use the libltdl.la installed in DIR])]) - -if test -n "$with_ltdl_lib"; then - if test -f "$with_ltdl_lib/libltdl.la"; then : - else - AC_MSG_ERROR([invalid ltdl library directory: '$with_ltdl_lib']) - fi -else - with_ltdl_lib=no -fi - -case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in - ,yes,no,no,) - m4_case(m4_default(_LTDL_TYPE, [convenience]), - [convenience], [_LTDL_CONVENIENCE], - [installable], [_LTDL_INSTALLABLE], - [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) - ;; - ,no,no,no,) - # If the included ltdl is not to be used, then use the - # preinstalled libltdl we found. - AC_DEFINE([HAVE_LTDL], [1], - [Define this if a modern libltdl is already installed]) - LIBLTDL=-lltdl - LTDLDEPS= - LTDLINCL= - ;; - ,no*,no,*) - AC_MSG_ERROR(['--with-ltdl-include' and '--with-ltdl-lib' options must be used together]) - ;; - *) with_included_ltdl=no - LIBLTDL="-L$with_ltdl_lib -lltdl" - LTDLDEPS= - LTDLINCL=-I$with_ltdl_include - ;; -esac -INCLTDL=$LTDLINCL - -# Report our decision... -AC_MSG_CHECKING([where to find libltdl headers]) -AC_MSG_RESULT([$LTDLINCL]) -AC_MSG_CHECKING([where to find libltdl library]) -AC_MSG_RESULT([$LIBLTDL]) - -_LTDL_SETUP - -dnl restore autoconf definition. -m4_popdef([AC_LIBOBJ]) -m4_popdef([AC_LIBSOURCES]) - -AC_CONFIG_COMMANDS_PRE([ - _ltdl_libobjs= - _ltdl_ltlibobjs= - if test -n "$_LT_LIBOBJS"; then - # Remove the extension. - _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' - for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | $SED "$_lt_sed_drop_objext" | sort -u`; do - _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" - _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" - done - fi - AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) - AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) -]) - -# Only expand once: -m4_define([LTDL_INIT]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:353: -1- AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:353: -1- AC_DEFUN([AC_LIB_LTDL], [m4_warn([obsolete], [The macro 'AC_LIB_LTDL' is obsolete. -You should run autoupdate.])dnl -LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:354: -1- AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:354: -1- AC_DEFUN([AC_WITH_LTDL], [m4_warn([obsolete], [The macro 'AC_WITH_LTDL' is obsolete. -You should run autoupdate.])dnl -LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:355: -1- AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:355: -1- AC_DEFUN([LT_WITH_LTDL], [m4_warn([obsolete], [The macro 'LT_WITH_LTDL' is obsolete. -You should run autoupdate.])dnl -LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:368: -1- AC_DEFUN([_LTDL_SETUP], [AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([LT_SYS_MODULE_EXT])dnl -AC_REQUIRE([LT_SYS_MODULE_PATH])dnl -AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl -AC_REQUIRE([LT_LIB_DLLOAD])dnl -AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl -AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl -AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl -AC_REQUIRE([LT_FUNC_ARGZ])dnl - -m4_require([_LT_CHECK_OBJDIR])dnl -m4_require([_LT_HEADER_DLFCN])dnl -m4_require([_LT_CHECK_DLPREOPEN])dnl -m4_require([_LT_DECL_SED])dnl - -dnl Don't require this, or it will be expanded earlier than the code -dnl that sets the variables it relies on: -_LT_ENABLE_INSTALL - -dnl _LTDL_MODE specific code must be called at least once: -_LTDL_MODE_DISPATCH - -# In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS -# the user used. This is so that ltdl.h can pick up the parent projects -# config.h file, The first file in AC_CONFIG_HEADERS must contain the -# definitions required by ltdl.c. -# FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). -AC_CONFIG_COMMANDS_PRE([dnl -m4_pattern_allow([^LT_CONFIG_H$])dnl -m4_ifset([AH_HEADER], - [LT_CONFIG_H=AH_HEADER], - [m4_ifset([AC_LIST_HEADERS], - [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's|^[[ ]]*||;s|[[ :]].*$||'`], - [])])]) -AC_SUBST([LT_CONFIG_H]) - -AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], - [], [], [AC_INCLUDES_DEFAULT]) - -AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) -AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) - -m4_pattern_allow([LT_LIBEXT])dnl -AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) - -name= -eval "lt_libprefix=\"$libname_spec\"" -m4_pattern_allow([LT_LIBPREFIX])dnl -AC_DEFINE_UNQUOTED([LT_LIBPREFIX],["$lt_libprefix"],[The archive prefix]) - -name=ltdl -eval "LTDLOPEN=\"$libname_spec\"" -AC_SUBST([LTDLOPEN]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:445: -1- AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_CACHE_CHECK([whether deplibs are loaded by dlopen], - [lt_cv_sys_dlopen_deplibs], - [# PORTME does your system automatically load deplibs for dlopen? - # or its logical equivalent (e.g. shl_load for HP-UX < 11) - # For now, we just catch OSes we know something about -- in the - # future, we'll try test this programmatically. - lt_cv_sys_dlopen_deplibs=unknown - case $host_os in - aix3*|aix4.1.*|aix4.2.*) - # Unknown whether this is true for these versions of AIX, but - # we want this 'case' here to explicitly catch those versions. - lt_cv_sys_dlopen_deplibs=unknown - ;; - aix[[4-9]]*) - lt_cv_sys_dlopen_deplibs=yes - ;; - amigaos*) - case $host_cpu in - powerpc) - lt_cv_sys_dlopen_deplibs=no - ;; - esac - ;; - darwin*) - # Assuming the user has installed a libdl from somewhere, this is true - # If you are looking for one http://www.opendarwin.org/projects/dlcompat - lt_cv_sys_dlopen_deplibs=yes - ;; - freebsd* | dragonfly* | midnightbsd*) - lt_cv_sys_dlopen_deplibs=yes - ;; - gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) - # GNU and its variants, using gnu ld.so (Glibc) - lt_cv_sys_dlopen_deplibs=yes - ;; - hpux10*|hpux11*) - lt_cv_sys_dlopen_deplibs=yes - ;; - interix*) - lt_cv_sys_dlopen_deplibs=yes - ;; - irix[[12345]]*|irix6.[[01]]*) - # Catch all versions of IRIX before 6.2, and indicate that we don't - # know how it worked for any of those versions. - lt_cv_sys_dlopen_deplibs=unknown - ;; - irix*) - # The case above catches anything before 6.2, and it's known that - # at 6.2 and later dlopen does load deplibs. - lt_cv_sys_dlopen_deplibs=yes - ;; - *-mlibc) - lt_cv_sys_dlopen_deplibs=yes - ;; - netbsd* | netbsdelf*-gnu) - lt_cv_sys_dlopen_deplibs=yes - ;; - openbsd*) - lt_cv_sys_dlopen_deplibs=yes - ;; - osf[[1234]]*) - # dlopen did load deplibs (at least at 4.x), but until the 5.x series, - # it did *not* use an RPATH in a shared library to find objects the - # library depends on, so we explicitly say 'no'. - lt_cv_sys_dlopen_deplibs=no - ;; - osf5.0|osf5.0a|osf5.1) - # dlopen *does* load deplibs and with the right loader patch applied - # it even uses RPATH in a shared library to search for shared objects - # that the library depends on, but there's no easy way to know if that - # patch is installed. Since this is the case, all we can really - # say is unknown -- it depends on the patch being installed. If - # it is, this changes to 'yes'. Without it, it would be 'no'. - lt_cv_sys_dlopen_deplibs=unknown - ;; - osf*) - # the two cases above should catch all versions of osf <= 5.1. Read - # the comments above for what we know about them. - # At > 5.1, deplibs are loaded *and* any RPATH in a shared library - # is used to find them so we can finally say 'yes'. - lt_cv_sys_dlopen_deplibs=yes - ;; - qnx*) - lt_cv_sys_dlopen_deplibs=yes - ;; - solaris*) - lt_cv_sys_dlopen_deplibs=yes - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - esac - ]) -if test yes != "$lt_cv_sys_dlopen_deplibs"; then - AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], - [Define if the OS needs help to load dependent libraries for dlopen().]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:547: -1- AU_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], [m4_if($#, 0, [LT_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:547: -1- AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], [m4_warn([obsolete], [The macro 'AC_LTDL_SYS_DLOPEN_DEPLIBS' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:554: -1- AC_DEFUN([LT_SYS_MODULE_EXT], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([what extension is used for runtime loadable modules], - [libltdl_cv_shlibext], -[ -module=yes -eval libltdl_cv_shlibext=$shrext_cmds -module=no -eval libltdl_cv_shrext=$shrext_cmds - ]) -if test -n "$libltdl_cv_shlibext"; then - m4_pattern_allow([LT_MODULE_EXT])dnl - AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], - [Define to the extension used for runtime loadable modules, say, ".so".]) -fi -if test "$libltdl_cv_shrext" != "$libltdl_cv_shlibext"; then - m4_pattern_allow([LT_SHARED_EXT])dnl - AC_DEFINE_UNQUOTED([LT_SHARED_EXT], ["$libltdl_cv_shrext"], - [Define to the shared library suffix, say, ".dylib".]) -fi -if test -n "$shared_archive_member_spec"; then - m4_pattern_allow([LT_SHARED_LIB_MEMBER])dnl - AC_DEFINE_UNQUOTED([LT_SHARED_LIB_MEMBER], ["($shared_archive_member_spec.o)"], - [Define to the shared archive member specification, say "(shr.o)".]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:582: -1- AU_DEFUN([AC_LTDL_SHLIBEXT], [m4_if($#, 0, [LT_SYS_MODULE_EXT], [LT_SYS_MODULE_EXT($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:582: -1- AC_DEFUN([AC_LTDL_SHLIBEXT], [m4_warn([obsolete], [The macro 'AC_LTDL_SHLIBEXT' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_MODULE_EXT], [LT_SYS_MODULE_EXT($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:589: -1- AC_DEFUN([LT_SYS_MODULE_PATH], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([what variable specifies run-time module search path], - [lt_cv_module_path_var], [lt_cv_module_path_var=$shlibpath_var]) -if test -n "$lt_cv_module_path_var"; then - m4_pattern_allow([LT_MODULE_PATH_VAR])dnl - AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], - [Define to the name of the environment variable that determines the run-time module search path.]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:601: -1- AU_DEFUN([AC_LTDL_SHLIBPATH], [m4_if($#, 0, [LT_SYS_MODULE_PATH], [LT_SYS_MODULE_PATH($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:601: -1- AC_DEFUN([AC_LTDL_SHLIBPATH], [m4_warn([obsolete], [The macro 'AC_LTDL_SHLIBPATH' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_MODULE_PATH], [LT_SYS_MODULE_PATH($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:608: -1- AC_DEFUN([LT_SYS_DLSEARCH_PATH], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([for the default library search path], - [lt_cv_sys_dlsearch_path], - [lt_cv_sys_dlsearch_path=$sys_lib_dlsearch_path_spec]) -if test -n "$lt_cv_sys_dlsearch_path"; then - sys_dlsearch_path= - for dir in $lt_cv_sys_dlsearch_path; do - if test -z "$sys_dlsearch_path"; then - sys_dlsearch_path=$dir - else - sys_dlsearch_path=$sys_dlsearch_path$PATH_SEPARATOR$dir - fi - done - m4_pattern_allow([LT_DLSEARCH_PATH])dnl - AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], - [Define to the system default library search path.]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:629: -1- AU_DEFUN([AC_LTDL_SYSSEARCHPATH], [m4_if($#, 0, [LT_SYS_DLSEARCH_PATH], [LT_SYS_DLSEARCH_PATH($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:629: -1- AC_DEFUN([AC_LTDL_SYSSEARCHPATH], [m4_warn([obsolete], [The macro 'AC_LTDL_SYSSEARCHPATH' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_DLSEARCH_PATH], [LT_SYS_DLSEARCH_PATH($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:655: -1- AC_DEFUN([LT_LIB_DLLOAD], [m4_pattern_allow([^LT_DLLOADERS$]) -LT_DLLOADERS= -AC_SUBST([LT_DLLOADERS]) - -AC_LANG_PUSH([C]) -lt_dlload_save_LIBS=$LIBS - -LIBADD_DLOPEN= -AC_SEARCH_LIBS([dlopen], [dl], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - if test "$ac_cv_search_dlopen" != "none required"; then - LIBADD_DLOPEN=-ldl - fi - libltdl_cv_lib_dl_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H -# include -#endif - ]], [[dlopen(0, 0);]])], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - libltdl_cv_func_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], - [AC_CHECK_LIB([svld], [dlopen], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - LIBADD_DLOPEN=-lsvld libltdl_cv_func_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) -if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen" -then - lt_save_LIBS=$LIBS - LIBS="$LIBS $LIBADD_DLOPEN" - AC_CHECK_FUNCS([dlerror]) - LIBS=$lt_save_LIBS -fi -AC_SUBST([LIBADD_DLOPEN]) - -LIBADD_SHL_LOAD= -AC_CHECK_FUNC([shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], - [AC_CHECK_LIB([dld], [shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" - LIBADD_SHL_LOAD=-ldld])]) -AC_SUBST([LIBADD_SHL_LOAD]) - -case $host_os in -darwin[[1567]].*) -# We only want this for pre-Mac OS X 10.4. - AC_CHECK_FUNC([_dyld_func_lookup], - [AC_DEFINE([HAVE_DYLD], [1], - [Define if you have the _dyld_func_lookup function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) - ;; -beos*) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" - ;; -cygwin* | mingw* | windows* | pw32*) - AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" - ;; -esac - -AC_CHECK_LIB([dld], [dld_link], - [AC_DEFINE([HAVE_DLD], [1], - [Define if you have the GNU dld library.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) -AC_SUBST([LIBADD_DLD_LINK]) - -m4_pattern_allow([^LT_DLPREOPEN$]) -LT_DLPREOPEN= -if test -n "$LT_DLLOADERS" -then - for lt_loader in $LT_DLLOADERS; do - LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " - done - AC_DEFINE([HAVE_LIBDLLOADER], [1], - [Define if libdlloader will be built on this platform]) -fi -AC_SUBST([LT_DLPREOPEN]) - -dnl This isn't used anymore, but set it for backwards compatibility -LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" -AC_SUBST([LIBADD_DL]) - -LIBS=$lt_dlload_save_LIBS -AC_LANG_POP -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:750: -1- AU_DEFUN([AC_LTDL_DLLIB], [m4_if($#, 0, [LT_LIB_DLLOAD], [LT_LIB_DLLOAD($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:750: -1- AC_DEFUN([AC_LTDL_DLLIB], [m4_warn([obsolete], [The macro 'AC_LTDL_DLLIB' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_LIB_DLLOAD], [LT_LIB_DLLOAD($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:758: -1- AC_DEFUN([LT_SYS_SYMBOL_USCORE], [m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl -AC_CACHE_CHECK([for _ prefix in compiled symbols], - [lt_cv_sys_symbol_underscore], - [lt_cv_sys_symbol_underscore=no - cat > conftest.$ac_ext <<_LT_EOF -void nm_test_func(){} -int main(void){nm_test_func;return 0;} -_LT_EOF - if AC_TRY_EVAL(ac_compile); then - # Now try to grab the symbols. - ac_nlist=conftest.nm - if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then - # See whether the symbols have a leading underscore. - if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then - lt_cv_sys_symbol_underscore=yes - else - if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then - : - else - echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD - fi - fi - else - echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD - fi - else - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat conftest.c >&AS_MESSAGE_LOG_FD - fi - rm -rf conftest* - ]) - sys_symbol_underscore=$lt_cv_sys_symbol_underscore - AC_SUBST([sys_symbol_underscore]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:795: -1- AU_DEFUN([AC_LTDL_SYMBOL_USCORE], [m4_if($#, 0, [LT_SYS_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:795: -1- AC_DEFUN([AC_LTDL_SYMBOL_USCORE], [m4_warn([obsolete], [The macro 'AC_LTDL_SYMBOL_USCORE' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:802: -1- AC_DEFUN([LT_FUNC_DLSYM_USCORE], [AC_REQUIRE([_LT_COMPILER_PIC])dnl for lt_prog_compiler_wl -AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl for lt_cv_sys_symbol_underscore -AC_REQUIRE([LT_SYS_MODULE_EXT])dnl for libltdl_cv_shlibext -if test yes = "$lt_cv_sys_symbol_underscore"; then - if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen"; then - AC_CACHE_CHECK([whether we have to add an underscore for dlsym], - [libltdl_cv_need_uscore], - [libltdl_cv_need_uscore=unknown - dlsym_uscore_save_LIBS=$LIBS - LIBS="$LIBS $LIBADD_DLOPEN" - libname=conftmod # stay within 8.3 filename limits! - cat >$libname.$ac_ext <<_LT_EOF -[#line $LINENO "configure" -#include "confdefs.h" -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif -int fnord () { return 42; }] -_LT_EOF - - # ltfn_module_cmds module_cmds - # Execute tilde-delimited MODULE_CMDS with environment primed for - # $module_cmds or $archive_cmds type content. - ltfn_module_cmds () - {( # subshell avoids polluting parent global environment - module_cmds_save_ifs=$IFS; IFS='~' - for cmd in @S|@1; do - IFS=$module_cmds_save_ifs - libobjs=$libname.$ac_objext; lib=$libname$libltdl_cv_shlibext - rpath=/not-exists; soname=$libname$libltdl_cv_shlibext; output_objdir=. - major=; versuffix=; verstring=; deplibs= - ECHO=echo; wl=$lt_prog_compiler_wl; allow_undefined_flag= - eval $cmd - done - IFS=$module_cmds_save_ifs - )} - - # Compile a loadable module using libtool macro expansion results. - $CC $pic_flag -c $libname.$ac_ext - ltfn_module_cmds "${module_cmds:-$archive_cmds}" - - # Try to fetch fnord with dlsym(). - libltdl_dlunknown=0; libltdl_dlnouscore=1; libltdl_dluscore=2 - cat >conftest.$ac_ext <<_LT_EOF -[#line $LINENO "configure" -#include "confdefs.h" -#if HAVE_DLFCN_H -#include -#endif -#include -#ifndef RTLD_GLOBAL -# ifdef DL_GLOBAL -# define RTLD_GLOBAL DL_GLOBAL -# else -# define RTLD_GLOBAL 0 -# endif -#endif -#ifndef RTLD_NOW -# ifdef DL_NOW -# define RTLD_NOW DL_NOW -# else -# define RTLD_NOW 0 -# endif -#endif -int main (void) { - void *handle = dlopen ("`pwd`/$libname$libltdl_cv_shlibext", RTLD_GLOBAL|RTLD_NOW); - int status = $libltdl_dlunknown; - if (handle) { - if (dlsym (handle, "fnord")) - status = $libltdl_dlnouscore; - else { - if (dlsym (handle, "_fnord")) - status = $libltdl_dluscore; - else - puts (dlerror ()); - } - dlclose (handle); - } else - puts (dlerror ()); - return status; -}] -_LT_EOF - if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null - libltdl_status=$? - case x$libltdl_status in - x$libltdl_dlnouscore) libltdl_cv_need_uscore=no ;; - x$libltdl_dluscore) libltdl_cv_need_uscore=yes ;; - x*) libltdl_cv_need_uscore=unknown ;; - esac - fi - rm -rf conftest* $libname* - LIBS=$dlsym_uscore_save_LIBS - ]) - fi -fi - -if test yes = "$libltdl_cv_need_uscore"; then - AC_DEFINE([NEED_USCORE], [1], - [Define if dlsym() requires a leading underscore in symbol names.]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:909: -1- AU_DEFUN([AC_LTDL_DLSYM_USCORE], [m4_if($#, 0, [LT_FUNC_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:909: -1- AC_DEFUN([AC_LTDL_DLSYM_USCORE], [m4_warn([obsolete], [The macro 'AC_LTDL_DLSYM_USCORE' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_FUNC_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:14: -1- AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:113: -1- AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'dlopen' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:113: -1- AC_DEFUN([AC_LIBTOOL_DLOPEN], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_DLOPEN' is obsolete. -You should run autoupdate.])dnl -_LT_SET_OPTION([LT_INIT], [dlopen]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'dlopen' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:148: -1- AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl -_LT_SET_OPTION([LT_INIT], [win32-dll]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'win32-dll' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:148: -1- AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_WIN32_DLL' is obsolete. -You should run autoupdate.])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -_LT_SET_OPTION([LT_INIT], [win32-dll]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'win32-dll' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:197: -1- AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:201: -1- AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:205: -1- AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:205: -1- AC_DEFUN([AM_ENABLE_SHARED], [m4_warn([obsolete], [The macro 'AM_ENABLE_SHARED' is obsolete. -You should run autoupdate.])dnl -AC_ENABLE_SHARED($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:206: -1- AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:206: -1- AC_DEFUN([AM_DISABLE_SHARED], [m4_warn([obsolete], [The macro 'AM_DISABLE_SHARED' is obsolete. -You should run autoupdate.])dnl -AC_DISABLE_SHARED($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:251: -1- AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:255: -1- AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:259: -1- AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:259: -1- AC_DEFUN([AM_ENABLE_STATIC], [m4_warn([obsolete], [The macro 'AM_ENABLE_STATIC' is obsolete. -You should run autoupdate.])dnl -AC_ENABLE_STATIC($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:260: -1- AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:260: -1- AC_DEFUN([AM_DISABLE_STATIC], [m4_warn([obsolete], [The macro 'AM_DISABLE_STATIC' is obsolete. -You should run autoupdate.])dnl -AC_DISABLE_STATIC($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:305: -1- AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you put -the 'fast-install' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:305: -1- AC_DEFUN([AC_ENABLE_FAST_INSTALL], [m4_warn([obsolete], [The macro 'AC_ENABLE_FAST_INSTALL' is obsolete. -You should run autoupdate.])dnl -_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you put -the 'fast-install' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:312: -1- AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you put -the 'disable-fast-install' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:312: -1- AC_DEFUN([AC_DISABLE_FAST_INSTALL], [m4_warn([obsolete], [The macro 'AC_DISABLE_FAST_INSTALL' is obsolete. -You should run autoupdate.])dnl -_LT_SET_OPTION([LT_INIT], [disable-fast-install]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you put -the 'disable-fast-install' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:441: -1- AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'pic-only' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltoptions.m4:441: -1- AC_DEFUN([AC_LIBTOOL_PICMODE], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_PICMODE' is obsolete. -You should run autoupdate.])dnl -_LT_SET_OPTION([LT_INIT], [pic-only]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'pic-only' option into LT_INIT's first parameter.]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltsugar.m4:14: -1- AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltversion.m4:19: -1- AC_DEFUN([LTVERSION_VERSION], [macro_version='2.5.4' -macro_revision='2.5.4' -_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) -_LT_DECL(, macro_revision, 0) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:37: -1- AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:41: -1- AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:42: -1- AC_DEFUN([_LT_AC_SHELL_INIT]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:43: -1- AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:45: -1- AC_DEFUN([_LT_AC_TAGVAR]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:46: -1- AC_DEFUN([AC_LTDL_ENABLE_INSTALL]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:47: -1- AC_DEFUN([AC_LTDL_PREOPEN]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:48: -1- AC_DEFUN([_LT_AC_SYS_COMPILER]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:49: -1- AC_DEFUN([_LT_AC_LOCK]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:50: -1- AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:51: -1- AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:52: -1- AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:53: -1- AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:54: -1- AC_DEFUN([AC_LIBTOOL_OBJDIR]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:55: -1- AC_DEFUN([AC_LTDL_OBJDIR]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:56: -1- AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:57: -1- AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:58: -1- AC_DEFUN([AC_PATH_MAGIC]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:59: -1- AC_DEFUN([AC_PROG_LD_GNU]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:60: -1- AC_DEFUN([AC_PROG_LD_RELOAD_FLAG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:61: -1- AC_DEFUN([AC_DEPLIBS_CHECK_METHOD]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:62: -1- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:63: -1- AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:64: -1- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:65: -1- AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:66: -1- AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:67: -1- AC_DEFUN([LT_AC_PROG_EGREP]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:68: -1- AC_DEFUN([LT_AC_PROG_SED]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:72: -1- AC_DEFUN([_AC_PROG_LIBTOOL]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:73: -1- AC_DEFUN([AC_LIBTOOL_SETUP]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:74: -1- AC_DEFUN([_LT_AC_CHECK_DLFCN]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:75: -1- AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:76: -1- AC_DEFUN([_LT_AC_TAGCONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:78: -1- AC_DEFUN([_LT_AC_LANG_CXX]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:79: -1- AC_DEFUN([_LT_AC_LANG_F77]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:80: -1- AC_DEFUN([_LT_AC_LANG_GCJ]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:81: -1- AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:82: -1- AC_DEFUN([_LT_AC_LANG_C_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:83: -1- AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:84: -1- AC_DEFUN([_LT_AC_LANG_CXX_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:85: -1- AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:86: -1- AC_DEFUN([_LT_AC_LANG_F77_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:87: -1- AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:88: -1- AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:89: -1- AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:90: -1- AC_DEFUN([_LT_AC_LANG_RC_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:91: -1- AC_DEFUN([AC_LIBTOOL_CONFIG]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:92: -1- AC_DEFUN([_LT_AC_FILE_LTDLL_C]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:94: -1- AC_DEFUN([_LT_AC_PROG_CXXCPP]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:97: -1- AC_DEFUN([_LT_PROG_F77]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:98: -1- AC_DEFUN([_LT_PROG_FC]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/lt~obsolete.m4:99: -1- AC_DEFUN([_LT_PROG_CXX]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:58: -1- AC_DEFUN([XORG_PROG_RAWCPP], [ -AC_REQUIRE([AC_PROG_CPP]) -AC_PATH_TOOL(RAWCPP, [cpp], [${CPP}], - [$PATH:/bin:/usr/bin:/usr/lib:/usr/libexec:/usr/ccs/lib:/usr/ccs/lbin:/lib]) - -# Check for flag to avoid builtin definitions - assumes unix is predefined, -# which is not the best choice for supporting other OS'es, but covers most -# of the ones we need for now. -AC_MSG_CHECKING([if $RAWCPP requires -undef]) -AC_LANG_CONFTEST([AC_LANG_SOURCE([[Does cpp redefine unix ?]])]) -if test `${RAWCPP} < conftest.$ac_ext | grep -c 'unix'` -eq 1 ; then - AC_MSG_RESULT([no]) -else - if test `${RAWCPP} -undef < conftest.$ac_ext | grep -c 'unix'` -eq 1 ; then - RAWCPPFLAGS=-undef - AC_MSG_RESULT([yes]) - # under Cygwin unix is still defined even with -undef - elif test `${RAWCPP} -undef -ansi < conftest.$ac_ext | grep -c 'unix'` -eq 1 ; then - RAWCPPFLAGS="-undef -ansi" - AC_MSG_RESULT([yes, with -ansi]) - else - AC_MSG_ERROR([${RAWCPP} defines unix with or without -undef. I don't know what to do.]) - fi -fi -rm -f conftest.$ac_ext - -AC_MSG_CHECKING([if $RAWCPP requires -traditional]) -AC_LANG_CONFTEST([AC_LANG_SOURCE([[Does cpp preserve "whitespace"?]])]) -if test `${RAWCPP} < conftest.$ac_ext | grep -c 'preserve "'` -eq 1 ; then - AC_MSG_RESULT([no]) -else - if test `${RAWCPP} -traditional < conftest.$ac_ext | grep -c 'preserve "'` -eq 1 ; then - TRADITIONALCPPFLAGS="-traditional" - RAWCPPFLAGS="${RAWCPPFLAGS} -traditional" - AC_MSG_RESULT([yes]) - else - AC_MSG_ERROR([${RAWCPP} does not preserve whitespace with or without -traditional. I don't know what to do.]) - fi -fi -rm -f conftest.$ac_ext -AC_SUBST(RAWCPPFLAGS) -AC_SUBST(TRADITIONALCPPFLAGS) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:113: -1- AC_DEFUN([XORG_MANPAGE_SECTIONS], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_REQUIRE([AC_PROG_SED]) - -case $host_os in - solaris*) - # Solaris 2.0 - 11.3 use SysV man page section numbers, so we - # check for a man page file found in later versions that use - # traditional section numbers instead - AC_CHECK_FILE([/usr/share/man/man7/attributes.7], - [SYSV_MAN_SECTIONS=false], [SYSV_MAN_SECTIONS=true]) - ;; - *) SYSV_MAN_SECTIONS=false ;; -esac - -if test x$APP_MAN_SUFFIX = x ; then - APP_MAN_SUFFIX=1 -fi -if test x$APP_MAN_DIR = x ; then - APP_MAN_DIR='$(mandir)/man$(APP_MAN_SUFFIX)' -fi - -if test x$LIB_MAN_SUFFIX = x ; then - LIB_MAN_SUFFIX=3 -fi -if test x$LIB_MAN_DIR = x ; then - LIB_MAN_DIR='$(mandir)/man$(LIB_MAN_SUFFIX)' -fi - -if test x$FILE_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) FILE_MAN_SUFFIX=4 ;; - *) FILE_MAN_SUFFIX=5 ;; - esac -fi -if test x$FILE_MAN_DIR = x ; then - FILE_MAN_DIR='$(mandir)/man$(FILE_MAN_SUFFIX)' -fi - -if test x$MISC_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) MISC_MAN_SUFFIX=5 ;; - *) MISC_MAN_SUFFIX=7 ;; - esac -fi -if test x$MISC_MAN_DIR = x ; then - MISC_MAN_DIR='$(mandir)/man$(MISC_MAN_SUFFIX)' -fi - -if test x$DRIVER_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) DRIVER_MAN_SUFFIX=7 ;; - *) DRIVER_MAN_SUFFIX=4 ;; - esac -fi -if test x$DRIVER_MAN_DIR = x ; then - DRIVER_MAN_DIR='$(mandir)/man$(DRIVER_MAN_SUFFIX)' -fi - -if test x$ADMIN_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) ADMIN_MAN_SUFFIX=1m ;; - *) ADMIN_MAN_SUFFIX=8 ;; - esac -fi -if test x$ADMIN_MAN_DIR = x ; then - ADMIN_MAN_DIR='$(mandir)/man$(ADMIN_MAN_SUFFIX)' -fi - - -AC_SUBST([APP_MAN_SUFFIX]) -AC_SUBST([LIB_MAN_SUFFIX]) -AC_SUBST([FILE_MAN_SUFFIX]) -AC_SUBST([MISC_MAN_SUFFIX]) -AC_SUBST([DRIVER_MAN_SUFFIX]) -AC_SUBST([ADMIN_MAN_SUFFIX]) -AC_SUBST([APP_MAN_DIR]) -AC_SUBST([LIB_MAN_DIR]) -AC_SUBST([FILE_MAN_DIR]) -AC_SUBST([MISC_MAN_DIR]) -AC_SUBST([DRIVER_MAN_DIR]) -AC_SUBST([ADMIN_MAN_DIR]) - -XORG_MAN_PAGE="X Version 11" -AC_SUBST([XORG_MAN_PAGE]) -MAN_SUBSTS="\ - -e 's|__vendorversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xorgversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xservername__|Xorg|g' \ - -e 's|__xconfigfile__|xorg.conf|g' \ - -e 's|__projectroot__|\$(prefix)|g' \ - -e 's|__apploaddir__|\$(appdefaultdir)|g' \ - -e 's|__appmansuffix__|\$(APP_MAN_SUFFIX)|g' \ - -e 's|__drivermansuffix__|\$(DRIVER_MAN_SUFFIX)|g' \ - -e 's|__adminmansuffix__|\$(ADMIN_MAN_SUFFIX)|g' \ - -e 's|__libmansuffix__|\$(LIB_MAN_SUFFIX)|g' \ - -e 's|__miscmansuffix__|\$(MISC_MAN_SUFFIX)|g' \ - -e 's|__filemansuffix__|\$(FILE_MAN_SUFFIX)|g'" -AC_SUBST([MAN_SUBSTS]) - -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:221: -1- AC_DEFUN([XORG_CHECK_SGML_DOCTOOLS], [ -AC_MSG_CHECKING([for X.Org SGML entities m4_ifval([$1],[>= $1])]) -XORG_SGML_PATH= -PKG_CHECK_EXISTS([xorg-sgml-doctools m4_ifval([$1],[>= $1])], - [XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools`], - [m4_ifval([$1],[:], - [if test x"$cross_compiling" != x"yes" ; then - AC_CHECK_FILE([$prefix/share/sgml/X11/defs.ent], - [XORG_SGML_PATH=$prefix/share/sgml]) - fi]) - ]) - -# Define variables STYLESHEET_SRCDIR and XSL_STYLESHEET containing -# the path and the name of the doc stylesheet -if test "x$XORG_SGML_PATH" != "x" ; then - AC_MSG_RESULT([$XORG_SGML_PATH]) - STYLESHEET_SRCDIR=$XORG_SGML_PATH/X11 - XSL_STYLESHEET=$STYLESHEET_SRCDIR/xorg.xsl -else - AC_MSG_RESULT([no]) -fi - -AC_SUBST(XORG_SGML_PATH) -AC_SUBST(STYLESHEET_SRCDIR) -AC_SUBST(XSL_STYLESHEET) -AM_CONDITIONAL([HAVE_STYLESHEETS], [test "x$XSL_STYLESHEET" != "x"]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:257: -1- AC_DEFUN([XORG_CHECK_LINUXDOC], [ -AC_REQUIRE([XORG_CHECK_SGML_DOCTOOLS]) -AC_REQUIRE([XORG_WITH_PS2PDF]) - -AC_PATH_PROG(LINUXDOC, linuxdoc) - -AC_MSG_CHECKING([whether to build documentation]) - -if test x$XORG_SGML_PATH != x && test x$LINUXDOC != x ; then - BUILDDOC=yes -else - BUILDDOC=no -fi - -AM_CONDITIONAL(BUILD_LINUXDOC, [test x$BUILDDOC = xyes]) - -AC_MSG_RESULT([$BUILDDOC]) - -AC_MSG_CHECKING([whether to build pdf documentation]) - -if test x$have_ps2pdf != xno && test x$BUILD_PDFDOC != xno; then - BUILDPDFDOC=yes -else - BUILDPDFDOC=no -fi - -AM_CONDITIONAL(BUILD_PDFDOC, [test x$BUILDPDFDOC = xyes]) - -AC_MSG_RESULT([$BUILDPDFDOC]) - -MAKE_TEXT="SGML_SEARCH_PATH=$XORG_SGML_PATH GROFF_NO_SGR=y $LINUXDOC -B txt -f" -MAKE_PS="SGML_SEARCH_PATH=$XORG_SGML_PATH $LINUXDOC -B latex --papersize=letter --output=ps" -MAKE_PDF="$PS2PDF" -MAKE_HTML="SGML_SEARCH_PATH=$XORG_SGML_PATH $LINUXDOC -B html --split=0" - -AC_SUBST(MAKE_TEXT) -AC_SUBST(MAKE_PS) -AC_SUBST(MAKE_PDF) -AC_SUBST(MAKE_HTML) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:306: -1- AC_DEFUN([XORG_CHECK_DOCBOOK], [ -AC_REQUIRE([XORG_CHECK_SGML_DOCTOOLS]) - -BUILDTXTDOC=no -BUILDPDFDOC=no -BUILDPSDOC=no -BUILDHTMLDOC=no - -AC_PATH_PROG(DOCBOOKPS, docbook2ps) -AC_PATH_PROG(DOCBOOKPDF, docbook2pdf) -AC_PATH_PROG(DOCBOOKHTML, docbook2html) -AC_PATH_PROG(DOCBOOKTXT, docbook2txt) - -AC_MSG_CHECKING([whether to build text documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKTXT != x && - test x$BUILD_TXTDOC != xno; then - BUILDTXTDOC=yes -fi -AM_CONDITIONAL(BUILD_TXTDOC, [test x$BUILDTXTDOC = xyes]) -AC_MSG_RESULT([$BUILDTXTDOC]) - -AC_MSG_CHECKING([whether to build PDF documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKPDF != x && - test x$BUILD_PDFDOC != xno; then - BUILDPDFDOC=yes -fi -AM_CONDITIONAL(BUILD_PDFDOC, [test x$BUILDPDFDOC = xyes]) -AC_MSG_RESULT([$BUILDPDFDOC]) - -AC_MSG_CHECKING([whether to build PostScript documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKPS != x && - test x$BUILD_PSDOC != xno; then - BUILDPSDOC=yes -fi -AM_CONDITIONAL(BUILD_PSDOC, [test x$BUILDPSDOC = xyes]) -AC_MSG_RESULT([$BUILDPSDOC]) - -AC_MSG_CHECKING([whether to build HTML documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKHTML != x && - test x$BUILD_HTMLDOC != xno; then - BUILDHTMLDOC=yes -fi -AM_CONDITIONAL(BUILD_HTMLDOC, [test x$BUILDHTMLDOC = xyes]) -AC_MSG_RESULT([$BUILDHTMLDOC]) - -MAKE_TEXT="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKTXT" -MAKE_PS="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKPS" -MAKE_PDF="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKPDF" -MAKE_HTML="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKHTML" - -AC_SUBST(MAKE_TEXT) -AC_SUBST(MAKE_PS) -AC_SUBST(MAKE_PDF) -AC_SUBST(MAKE_HTML) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:387: -1- AC_DEFUN([XORG_WITH_XMLTO], [ -AC_ARG_VAR([XMLTO], [Path to xmlto command]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(xmlto, - AS_HELP_STRING([--with-xmlto], - [Use xmlto to regenerate documentation (default: ]_defopt[)]), - [use_xmlto=$withval], [use_xmlto=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_xmlto" = x"auto"; then - AC_PATH_PROG([XMLTO], [xmlto]) - if test "x$XMLTO" = "x"; then - AC_MSG_WARN([xmlto not found - documentation targets will be skipped]) - have_xmlto=no - else - have_xmlto=yes - fi -elif test "x$use_xmlto" = x"yes" ; then - AC_PATH_PROG([XMLTO], [xmlto]) - if test "x$XMLTO" = "x"; then - AC_MSG_ERROR([--with-xmlto=yes specified but xmlto not found in PATH]) - fi - have_xmlto=yes -elif test "x$use_xmlto" = x"no" ; then - if test "x$XMLTO" != "x"; then - AC_MSG_WARN([ignoring XMLTO environment variable since --with-xmlto=no was specified]) - fi - have_xmlto=no -else - AC_MSG_ERROR([--with-xmlto expects 'yes' or 'no']) -fi - -# Test for a minimum version of xmlto, if provided. -m4_ifval([$1], -[if test "$have_xmlto" = yes; then - # scrape the xmlto version - AC_MSG_CHECKING([the xmlto version]) - xmlto_version=`$XMLTO --version 2>/dev/null | cut -d' ' -f3` - AC_MSG_RESULT([$xmlto_version]) - AS_VERSION_COMPARE([$xmlto_version], [$1], - [if test "x$use_xmlto" = xauto; then - AC_MSG_WARN([xmlto version $xmlto_version found, but $1 needed]) - have_xmlto=no - else - AC_MSG_ERROR([xmlto version $xmlto_version found, but $1 needed]) - fi]) -fi]) - -# Test for the ability of xmlto to generate a text target -# -# NOTE: xmlto 0.0.27 or higher return a non-zero return code in the -# following test for empty XML docbook files. -# For compatibility reasons use the following empty XML docbook file and if -# it fails try it again with a non-empty XML file. -have_xmlto_text=no -cat > conftest.xml << "EOF" -EOF -AS_IF([test "$have_xmlto" = yes], - [AS_IF([$XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1], - [have_xmlto_text=yes], - [# Try it again with a non-empty XML file. - cat > conftest.xml << "EOF" - -EOF - AS_IF([$XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1], - [have_xmlto_text=yes], - [AC_MSG_WARN([xmlto cannot generate text format, this format skipped])])])]) -rm -f conftest.xml -AM_CONDITIONAL([HAVE_XMLTO_TEXT], [test $have_xmlto_text = yes]) -AM_CONDITIONAL([HAVE_XMLTO], [test "$have_xmlto" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:482: -1- AC_DEFUN([XORG_WITH_XSLTPROC], [ -AC_ARG_VAR([XSLTPROC], [Path to xsltproc command]) -# Preserves the interface, should it be implemented later -m4_ifval([$1], [m4_warn([syntax], [Checking for xsltproc MIN-VERSION is not implemented])]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(xsltproc, - AS_HELP_STRING([--with-xsltproc], - [Use xsltproc for the transformation of XML documents (default: ]_defopt[)]), - [use_xsltproc=$withval], [use_xsltproc=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_xsltproc" = x"auto"; then - AC_PATH_PROG([XSLTPROC], [xsltproc]) - if test "x$XSLTPROC" = "x"; then - AC_MSG_WARN([xsltproc not found - cannot transform XML documents]) - have_xsltproc=no - else - have_xsltproc=yes - fi -elif test "x$use_xsltproc" = x"yes" ; then - AC_PATH_PROG([XSLTPROC], [xsltproc]) - if test "x$XSLTPROC" = "x"; then - AC_MSG_ERROR([--with-xsltproc=yes specified but xsltproc not found in PATH]) - fi - have_xsltproc=yes -elif test "x$use_xsltproc" = x"no" ; then - if test "x$XSLTPROC" != "x"; then - AC_MSG_WARN([ignoring XSLTPROC environment variable since --with-xsltproc=no was specified]) - fi - have_xsltproc=no -else - AC_MSG_ERROR([--with-xsltproc expects 'yes' or 'no']) -fi - -AM_CONDITIONAL([HAVE_XSLTPROC], [test "$have_xsltproc" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:539: -1- AC_DEFUN([XORG_WITH_PERL], [ -AC_ARG_VAR([PERL], [Path to perl command]) -# Preserves the interface, should it be implemented later -m4_ifval([$1], [m4_warn([syntax], [Checking for perl MIN-VERSION is not implemented])]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(perl, - AS_HELP_STRING([--with-perl], - [Use perl for extracting information from files (default: ]_defopt[)]), - [use_perl=$withval], [use_perl=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_perl" = x"auto"; then - AC_PATH_PROG([PERL], [perl]) - if test "x$PERL" = "x"; then - AC_MSG_WARN([perl not found - cannot extract information and report]) - have_perl=no - else - have_perl=yes - fi -elif test "x$use_perl" = x"yes" ; then - AC_PATH_PROG([PERL], [perl]) - if test "x$PERL" = "x"; then - AC_MSG_ERROR([--with-perl=yes specified but perl not found in PATH]) - fi - have_perl=yes -elif test "x$use_perl" = x"no" ; then - if test "x$PERL" != "x"; then - AC_MSG_WARN([ignoring PERL environment variable since --with-perl=no was specified]) - fi - have_perl=no -else - AC_MSG_ERROR([--with-perl expects 'yes' or 'no']) -fi - -AM_CONDITIONAL([HAVE_PERL], [test "$have_perl" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:597: -1- AC_DEFUN([XORG_WITH_ASCIIDOC], [ -AC_ARG_VAR([ASCIIDOC], [Path to asciidoc command]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(asciidoc, - AS_HELP_STRING([--with-asciidoc], - [Use asciidoc to regenerate documentation (default: ]_defopt[)]), - [use_asciidoc=$withval], [use_asciidoc=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_asciidoc" = x"auto"; then - AC_PATH_PROG([ASCIIDOC], [asciidoc]) - if test "x$ASCIIDOC" = "x"; then - AC_MSG_WARN([asciidoc not found - documentation targets will be skipped]) - have_asciidoc=no - else - have_asciidoc=yes - fi -elif test "x$use_asciidoc" = x"yes" ; then - AC_PATH_PROG([ASCIIDOC], [asciidoc]) - if test "x$ASCIIDOC" = "x"; then - AC_MSG_ERROR([--with-asciidoc=yes specified but asciidoc not found in PATH]) - fi - have_asciidoc=yes -elif test "x$use_asciidoc" = x"no" ; then - if test "x$ASCIIDOC" != "x"; then - AC_MSG_WARN([ignoring ASCIIDOC environment variable since --with-asciidoc=no was specified]) - fi - have_asciidoc=no -else - AC_MSG_ERROR([--with-asciidoc expects 'yes' or 'no']) -fi -m4_ifval([$1], -[if test "$have_asciidoc" = yes; then - # scrape the asciidoc version - AC_MSG_CHECKING([the asciidoc version]) - asciidoc_version=`$ASCIIDOC --version 2>/dev/null | cut -d' ' -f2` - AC_MSG_RESULT([$asciidoc_version]) - AS_VERSION_COMPARE([$asciidoc_version], [$1], - [if test "x$use_asciidoc" = xauto; then - AC_MSG_WARN([asciidoc version $asciidoc_version found, but $1 needed]) - have_asciidoc=no - else - AC_MSG_ERROR([asciidoc version $asciidoc_version found, but $1 needed]) - fi]) -fi]) -AM_CONDITIONAL([HAVE_ASCIIDOC], [test "$have_asciidoc" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:667: -1- AC_DEFUN([XORG_WITH_DOXYGEN], [ -AC_ARG_VAR([DOXYGEN], [Path to doxygen command]) -AC_ARG_VAR([DOT], [Path to the dot graphics utility]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(doxygen, - AS_HELP_STRING([--with-doxygen], - [Use doxygen to regenerate documentation (default: ]_defopt[)]), - [use_doxygen=$withval], [use_doxygen=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_doxygen" = x"auto"; then - AC_PATH_PROG([DOXYGEN], [doxygen]) - if test "x$DOXYGEN" = "x"; then - AC_MSG_WARN([doxygen not found - documentation targets will be skipped]) - have_doxygen=no - else - have_doxygen=yes - fi -elif test "x$use_doxygen" = x"yes" ; then - AC_PATH_PROG([DOXYGEN], [doxygen]) - if test "x$DOXYGEN" = "x"; then - AC_MSG_ERROR([--with-doxygen=yes specified but doxygen not found in PATH]) - fi - have_doxygen=yes -elif test "x$use_doxygen" = x"no" ; then - if test "x$DOXYGEN" != "x"; then - AC_MSG_WARN([ignoring DOXYGEN environment variable since --with-doxygen=no was specified]) - fi - have_doxygen=no -else - AC_MSG_ERROR([--with-doxygen expects 'yes' or 'no']) -fi -m4_ifval([$1], -[if test "$have_doxygen" = yes; then - # scrape the doxygen version - AC_MSG_CHECKING([the doxygen version]) - doxygen_version=`$DOXYGEN --version 2>/dev/null` - AC_MSG_RESULT([$doxygen_version]) - AS_VERSION_COMPARE([$doxygen_version], [$1], - [if test "x$use_doxygen" = xauto; then - AC_MSG_WARN([doxygen version $doxygen_version found, but $1 needed]) - have_doxygen=no - else - AC_MSG_ERROR([doxygen version $doxygen_version found, but $1 needed]) - fi]) -fi]) - -dnl Check for DOT if we have doxygen. The caller decides if it is mandatory -dnl HAVE_DOT is a variable that can be used in your doxygen.in config file: -dnl HAVE_DOT = @HAVE_DOT@ -HAVE_DOT=no -if test "x$have_doxygen" = "xyes"; then - AC_PATH_PROG([DOT], [dot]) - if test "x$DOT" != "x"; then - HAVE_DOT=yes - fi -fi - -AC_SUBST([HAVE_DOT]) -AM_CONDITIONAL([HAVE_DOT], [test "$HAVE_DOT" = "yes"]) -AM_CONDITIONAL([HAVE_DOXYGEN], [test "$have_doxygen" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:767: -1- AC_DEFUN([XORG_WITH_GROFF], [ -AC_ARG_VAR([GROFF], [Path to groff command]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_WITH(groff, - AS_HELP_STRING([--with-groff], - [Use groff to regenerate documentation (default: ]_defopt[)]), - [use_groff=$withval], [use_groff=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_groff" = x"auto"; then - AC_PATH_PROG([GROFF], [groff]) - if test "x$GROFF" = "x"; then - AC_MSG_WARN([groff not found - documentation targets will be skipped]) - have_groff=no - else - have_groff=yes - fi -elif test "x$use_groff" = x"yes" ; then - AC_PATH_PROG([GROFF], [groff]) - if test "x$GROFF" = "x"; then - AC_MSG_ERROR([--with-groff=yes specified but groff not found in PATH]) - fi - have_groff=yes -elif test "x$use_groff" = x"no" ; then - if test "x$GROFF" != "x"; then - AC_MSG_WARN([ignoring GROFF environment variable since --with-groff=no was specified]) - fi - have_groff=no -else - AC_MSG_ERROR([--with-groff expects 'yes' or 'no']) -fi - -# We have groff, test for the presence of the macro packages -if test "x$have_groff" = x"yes"; then - AC_MSG_CHECKING([for ${GROFF} -ms macros]) - if ${GROFF} -ms -I. /dev/null >/dev/null 2>&1 ; then - groff_ms_works=yes - else - groff_ms_works=no - fi - AC_MSG_RESULT([$groff_ms_works]) - AC_MSG_CHECKING([for ${GROFF} -mm macros]) - if ${GROFF} -mm -I. /dev/null >/dev/null 2>&1 ; then - groff_mm_works=yes - else - groff_mm_works=no - fi - AC_MSG_RESULT([$groff_mm_works]) -fi - -# We have groff, test for HTML dependencies, one command per package -if test "x$have_groff" = x"yes"; then - AC_PATH_PROGS(GS_PATH, [gs gswin32c]) - AC_PATH_PROG(PNMTOPNG_PATH, [pnmtopng]) - AC_PATH_PROG(PSSELECT_PATH, [psselect]) - if test "x$GS_PATH" != "x" -a "x$PNMTOPNG_PATH" != "x" -a "x$PSSELECT_PATH" != "x"; then - have_groff_html=yes - else - have_groff_html=no - AC_MSG_WARN([grohtml dependencies not found - HTML Documentation skipped. Refer to grohtml man pages]) - fi -fi - -# Set Automake conditionals for Makefiles -AM_CONDITIONAL([HAVE_GROFF], [test "$have_groff" = yes]) -AM_CONDITIONAL([HAVE_GROFF_MS], [test "$groff_ms_works" = yes]) -AM_CONDITIONAL([HAVE_GROFF_MM], [test "$groff_mm_works" = yes]) -AM_CONDITIONAL([HAVE_GROFF_HTML], [test "$have_groff_html" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:859: -1- AC_DEFUN([XORG_WITH_FOP], [ -AC_ARG_VAR([FOP], [Path to fop command]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(fop, - AS_HELP_STRING([--with-fop], - [Use fop to regenerate documentation (default: ]_defopt[)]), - [use_fop=$withval], [use_fop=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_fop" = x"auto"; then - AC_PATH_PROG([FOP], [fop]) - if test "x$FOP" = "x"; then - AC_MSG_WARN([fop not found - documentation targets will be skipped]) - have_fop=no - else - have_fop=yes - fi -elif test "x$use_fop" = x"yes" ; then - AC_PATH_PROG([FOP], [fop]) - if test "x$FOP" = "x"; then - AC_MSG_ERROR([--with-fop=yes specified but fop not found in PATH]) - fi - have_fop=yes -elif test "x$use_fop" = x"no" ; then - if test "x$FOP" != "x"; then - AC_MSG_WARN([ignoring FOP environment variable since --with-fop=no was specified]) - fi - have_fop=no -else - AC_MSG_ERROR([--with-fop expects 'yes' or 'no']) -fi - -# Test for a minimum version of fop, if provided. -m4_ifval([$1], -[if test "$have_fop" = yes; then - # scrape the fop version - AC_MSG_CHECKING([for fop minimum version]) - fop_version=`$FOP -version 2>/dev/null | cut -d' ' -f3` - AC_MSG_RESULT([$fop_version]) - AS_VERSION_COMPARE([$fop_version], [$1], - [if test "x$use_fop" = xauto; then - AC_MSG_WARN([fop version $fop_version found, but $1 needed]) - have_fop=no - else - AC_MSG_ERROR([fop version $fop_version found, but $1 needed]) - fi]) -fi]) -AM_CONDITIONAL([HAVE_FOP], [test "$have_fop" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:921: -1- AC_DEFUN([XORG_WITH_M4], [ -AC_CACHE_CHECK([for m4 that supports -I option], [ac_cv_path_M4], - [AC_PATH_PROGS_FEATURE_CHECK([M4], [m4 gm4], - [[$ac_path_M4 -I. /dev/null > /dev/null 2>&1 && \ - ac_cv_path_M4=$ac_path_M4 ac_path_M4_found=:]], - [AC_MSG_ERROR([could not find m4 that supports -I option])], - [$PATH:/usr/gnu/bin])]) - -AC_SUBST([M4], [$ac_cv_path_M4]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:953: -1- AC_DEFUN([XORG_WITH_PS2PDF], [ -AC_ARG_VAR([PS2PDF], [Path to ps2pdf command]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_WITH(ps2pdf, - AS_HELP_STRING([--with-ps2pdf], - [Use ps2pdf to regenerate documentation (default: ]_defopt[)]), - [use_ps2pdf=$withval], [use_ps2pdf=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_ps2pdf" = x"auto"; then - AC_PATH_PROG([PS2PDF], [ps2pdf]) - if test "x$PS2PDF" = "x"; then - AC_MSG_WARN([ps2pdf not found - documentation targets will be skipped]) - have_ps2pdf=no - else - have_ps2pdf=yes - fi -elif test "x$use_ps2pdf" = x"yes" ; then - AC_PATH_PROG([PS2PDF], [ps2pdf]) - if test "x$PS2PDF" = "x"; then - AC_MSG_ERROR([--with-ps2pdf=yes specified but ps2pdf not found in PATH]) - fi - have_ps2pdf=yes -elif test "x$use_ps2pdf" = x"no" ; then - if test "x$PS2PDF" != "x"; then - AC_MSG_WARN([ignoring PS2PDF environment variable since --with-ps2pdf=no was specified]) - fi - have_ps2pdf=no -else - AC_MSG_ERROR([--with-ps2pdf expects 'yes' or 'no']) -fi -AM_CONDITIONAL([HAVE_PS2PDF], [test "$have_ps2pdf" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1010: -1- AC_DEFUN([XORG_ENABLE_DOCS], [ -m4_define([docs_default], m4_default([$1], [yes])) -AC_ARG_ENABLE(docs, - AS_HELP_STRING([--enable-docs], - [Enable building the documentation (default: ]docs_default[)]), - [build_docs=$enableval], [build_docs=]docs_default) -m4_undefine([docs_default]) -AM_CONDITIONAL(ENABLE_DOCS, [test x$build_docs = xyes]) -AC_MSG_CHECKING([whether to build documentation]) -AC_MSG_RESULT([$build_docs]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1043: -1- AC_DEFUN([XORG_ENABLE_DEVEL_DOCS], [ -m4_define([devel_default], m4_default([$1], [yes])) -AC_ARG_ENABLE(devel-docs, - AS_HELP_STRING([--enable-devel-docs], - [Enable building the developer documentation (default: ]devel_default[)]), - [build_devel_docs=$enableval], [build_devel_docs=]devel_default) -m4_undefine([devel_default]) -AM_CONDITIONAL(ENABLE_DEVEL_DOCS, [test x$build_devel_docs = xyes]) -AC_MSG_CHECKING([whether to build developer documentation]) -AC_MSG_RESULT([$build_devel_docs]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1076: -1- AC_DEFUN([XORG_ENABLE_SPECS], [ -m4_define([spec_default], m4_default([$1], [yes])) -AC_ARG_ENABLE(specs, - AS_HELP_STRING([--enable-specs], - [Enable building the specs (default: ]spec_default[)]), - [build_specs=$enableval], [build_specs=]spec_default) -m4_undefine([spec_default]) -AM_CONDITIONAL(ENABLE_SPECS, [test x$build_specs = xyes]) -AC_MSG_CHECKING([whether to build functional specifications]) -AC_MSG_RESULT([$build_specs]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1108: -1- AC_DEFUN([XORG_ENABLE_UNIT_TESTS], [ -AC_BEFORE([$0], [XORG_WITH_GLIB]) -AC_BEFORE([$0], [XORG_LD_WRAP]) -AC_REQUIRE([XORG_MEMORY_CHECK_FLAGS]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_ENABLE(unit-tests, AS_HELP_STRING([--enable-unit-tests], - [Enable building unit test cases (default: ]_defopt[)]), - [enable_unit_tests=$enableval], [enable_unit_tests=]_defopt) -m4_undefine([_defopt]) -AM_CONDITIONAL(ENABLE_UNIT_TESTS, [test "x$enable_unit_tests" != xno]) -AC_MSG_CHECKING([whether to build unit test cases]) -AC_MSG_RESULT([$enable_unit_tests]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1141: -1- AC_DEFUN([XORG_ENABLE_INTEGRATION_TESTS], [ -AC_REQUIRE([XORG_MEMORY_CHECK_FLAGS]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_ENABLE(integration-tests, AS_HELP_STRING([--enable-integration-tests], - [Enable building integration test cases (default: ]_defopt[)]), - [enable_integration_tests=$enableval], - [enable_integration_tests=]_defopt) -m4_undefine([_defopt]) -AM_CONDITIONAL([ENABLE_INTEGRATION_TESTS], - [test "x$enable_integration_tests" != xno]) -AC_MSG_CHECKING([whether to build unit test cases]) -AC_MSG_RESULT([$enable_integration_tests]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1175: -1- AC_DEFUN([XORG_WITH_GLIB], [ -AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(glib, AS_HELP_STRING([--with-glib], - [Use GLib library for unit testing (default: ]_defopt[)]), - [with_glib=$withval], [with_glib=]_defopt) -m4_undefine([_defopt]) - -have_glib=no -# Do not probe GLib if user explicitly disabled unit testing -if test "x$enable_unit_tests" != x"no"; then - # Do not probe GLib if user explicitly disabled it - if test "x$with_glib" != x"no"; then - m4_ifval( - [$1], - [PKG_CHECK_MODULES([GLIB], [glib-2.0 >= $1], [have_glib=yes], [have_glib=no])], - [PKG_CHECK_MODULES([GLIB], [glib-2.0], [have_glib=yes], [have_glib=no])] - ) - fi -fi - -# Not having GLib when unit testing has been explicitly requested is an error -if test "x$enable_unit_tests" = x"yes"; then - if test "x$have_glib" = x"no"; then - AC_MSG_ERROR([--enable-unit-tests=yes specified but glib-2.0 not found]) - fi -fi - -# Having unit testing disabled when GLib has been explicitly requested is an error -if test "x$enable_unit_tests" = x"no"; then - if test "x$with_glib" = x"yes"; then - AC_MSG_ERROR([--enable-unit-tests=yes specified but glib-2.0 not found]) - fi -fi - -# Not having GLib when it has been explicitly requested is an error -if test "x$with_glib" = x"yes"; then - if test "x$have_glib" = x"no"; then - AC_MSG_ERROR([--with-glib=yes specified but glib-2.0 not found]) - fi -fi - -AM_CONDITIONAL([HAVE_GLIB], [test "$have_glib" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1234: -1- AC_DEFUN([XORG_LD_WRAP], [ -XORG_CHECK_LINKER_FLAGS([-Wl,-wrap,exit],[have_ld_wrap=yes],[have_ld_wrap=no], - [AC_LANG_PROGRAM([#include - void __wrap_exit(int status) { return; }], - [exit(0);])]) -# Not having ld wrap when unit testing has been explicitly requested is an error -if test "x$enable_unit_tests" = x"yes" -a "x$1" != "xoptional"; then - if test "x$have_ld_wrap" = x"no"; then - AC_MSG_ERROR([--enable-unit-tests=yes specified but ld -wrap support is not available]) - fi -fi -AM_CONDITIONAL([HAVE_LD_WRAP], [test "$have_ld_wrap" = yes]) -# -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1298: -1- AC_DEFUN([XORG_CHECK_LINKER_FLAGS], [AC_MSG_CHECKING([whether the linker accepts $1]) -dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname: -AS_LITERAL_IF([$1], - [AC_CACHE_VAL(AS_TR_SH(xorg_cv_linker_flags_[$1]), [ - ax_save_FLAGS=$LDFLAGS - LDFLAGS="$1" - AC_LINK_IFELSE([m4_default([$4],[AC_LANG_PROGRAM()])], - AS_TR_SH(xorg_cv_linker_flags_[$1])=yes, - AS_TR_SH(xorg_cv_linker_flags_[$1])=no) - LDFLAGS=$ax_save_FLAGS])], - [ax_save_FLAGS=$LDFLAGS - LDFLAGS="$1" - AC_LINK_IFELSE([AC_LANG_PROGRAM()], - eval AS_TR_SH(xorg_cv_linker_flags_[$1])=yes, - eval AS_TR_SH(xorg_cv_linker_flags_[$1])=no) - LDFLAGS=$ax_save_FLAGS]) -eval xorg_check_linker_flags=$AS_TR_SH(xorg_cv_linker_flags_[$1]) -AC_MSG_RESULT($xorg_check_linker_flags) -if test "x$xorg_check_linker_flags" = xyes; then - m4_default([$2], :) -else - m4_default([$3], :) -fi -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1338: -1- AC_DEFUN([XORG_MEMORY_CHECK_FLAGS], [ - -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_ARG_VAR([XORG_MALLOC_DEBUG_ENV], - [Environment variables to enable memory checking in tests]) - -# Check for different types of support on different platforms -case $host_os in - solaris*) - AC_CHECK_LIB([umem], [umem_alloc], - [malloc_debug_env='LD_PRELOAD=libumem.so UMEM_DEBUG=default']) - ;; - *-gnu*) # GNU libc - Value is used as a single byte bit pattern, - # both directly and inverted, so should not be 0 or 255. - malloc_debug_env='MALLOC_PERTURB_=15' - ;; - darwin*) - malloc_debug_env='MallocPreScribble=1 MallocScribble=1 DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib' - ;; - *bsd*) - malloc_debug_env='MallocPreScribble=1 MallocScribble=1' - ;; -esac - -# User supplied flags override default flags -if test "x$XORG_MALLOC_DEBUG_ENV" != "x"; then - malloc_debug_env="$XORG_MALLOC_DEBUG_ENV" -fi - -AC_SUBST([XORG_MALLOC_DEBUG_ENV],[$malloc_debug_env]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1383: -1- AC_DEFUN([XORG_CHECK_MALLOC_ZERO], [ -AC_ARG_ENABLE(malloc0returnsnull, - AS_HELP_STRING([--enable-malloc0returnsnull], - [assume malloc(0) can return NULL (default: yes)]), - [MALLOC_ZERO_RETURNS_NULL=$enableval], - [MALLOC_ZERO_RETURNS_NULL=yes]) - -AC_MSG_CHECKING([whether to act as if malloc(0) can return NULL]) -AC_MSG_RESULT([$MALLOC_ZERO_RETURNS_NULL]) - -if test "x$MALLOC_ZERO_RETURNS_NULL" = xyes; then - MALLOC_ZERO_CFLAGS="-DMALLOC_0_RETURNS_NULL" - XMALLOC_ZERO_CFLAGS=$MALLOC_ZERO_CFLAGS - XTMALLOC_ZERO_CFLAGS="$MALLOC_ZERO_CFLAGS -DXTMALLOC_BC" -else - MALLOC_ZERO_CFLAGS="" - XMALLOC_ZERO_CFLAGS="" - XTMALLOC_ZERO_CFLAGS="" -fi - -AC_SUBST([MALLOC_ZERO_CFLAGS]) -AC_SUBST([XMALLOC_ZERO_CFLAGS]) -AC_SUBST([XTMALLOC_ZERO_CFLAGS]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1429: -1- AC_DEFUN([XORG_WITH_LINT], [ - -AC_ARG_VAR([LINT], [Path to a lint-style command]) -AC_ARG_VAR([LINT_FLAGS], [Flags for the lint-style command]) -AC_ARG_WITH(lint, [AS_HELP_STRING([--with-lint], - [Use a lint-style source code checker (default: disabled)])], - [use_lint=$withval], [use_lint=no]) - -# Obtain platform specific info like program name and options -# The lint program on FreeBSD and NetBSD is different from the one on Solaris -case $host_os in - *linux* | *openbsd* | kfreebsd*-gnu | darwin* | cygwin*) - lint_name=splint - lint_options="-badflag" - ;; - *freebsd* | *netbsd*) - lint_name=lint - lint_options="-u -b" - ;; - *solaris*) - lint_name=lint - lint_options="-u -b -h -erroff=E_INDISTING_FROM_TRUNC2" - ;; -esac - -# Test for the presence of the program (either guessed by the code or spelled out by the user) -if test "x$use_lint" = x"yes" ; then - AC_PATH_PROG([LINT], [$lint_name]) - if test "x$LINT" = "x"; then - AC_MSG_ERROR([--with-lint=yes specified but lint-style tool not found in PATH]) - fi -elif test "x$use_lint" = x"no" ; then - if test "x$LINT" != "x"; then - AC_MSG_WARN([ignoring LINT environment variable since --with-lint=no was specified]) - fi -else - AC_MSG_ERROR([--with-lint expects 'yes' or 'no'. Use LINT variable to specify path.]) -fi - -# User supplied flags override default flags -if test "x$LINT_FLAGS" != "x"; then - lint_options=$LINT_FLAGS -fi - -AC_SUBST([LINT_FLAGS],[$lint_options]) -AM_CONDITIONAL(LINT, [test "x$LINT" != x]) - -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1492: -1- AC_DEFUN([XORG_LINT_LIBRARY], [ -AC_REQUIRE([XORG_WITH_LINT]) -AC_ARG_ENABLE(lint-library, [AS_HELP_STRING([--enable-lint-library], - [Create lint library (default: disabled)])], - [make_lint_lib=$enableval], [make_lint_lib=no]) - -if test "x$make_lint_lib" = x"yes" ; then - LINTLIB=llib-l$1.ln - if test "x$LINT" = "x"; then - AC_MSG_ERROR([Cannot make lint library without --with-lint]) - fi -elif test "x$make_lint_lib" != x"no" ; then - AC_MSG_ERROR([--enable-lint-library expects 'yes' or 'no'.]) -fi - -AC_SUBST(LINTLIB) -AM_CONDITIONAL(MAKE_LINT_LIB, [test x$make_lint_lib != xno]) - -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1523: -1- AC_DEFUN([XORG_COMPILER_BRAND], [ -AC_LANG_CASE( - [C], [ - dnl autoconf-2.70 folded AC_PROG_CC_C99 into AC_PROG_CC - dnl and complains that AC_PROG_CC_C99 is obsolete - m4_version_prereq([2.70], - [AC_REQUIRE([AC_PROG_CC])], - [AC_REQUIRE([AC_PROG_CC_C99])]) - ], - [C++], [ - AC_REQUIRE([AC_PROG_CXX]) - ] -) -AC_CHECK_DECL([__clang__], [CLANGCC="yes"], [CLANGCC="no"]) -AC_CHECK_DECL([__INTEL_COMPILER], [INTELCC="yes"], [INTELCC="no"]) -AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1554: -1- AC_DEFUN([XORG_TESTSET_CFLAG], [ -m4_if([$#], 0, [m4_fatal([XORG_TESTSET_CFLAG was given with an unsupported number of arguments])]) -m4_if([$#], 1, [m4_fatal([XORG_TESTSET_CFLAG was given with an unsupported number of arguments])]) - -AC_LANG_COMPILER_REQUIRE - -AC_LANG_CASE( - [C], [ - dnl autoconf-2.70 folded AC_PROG_CC_C99 into AC_PROG_CC - dnl and complains that AC_PROG_CC_C99 is obsolete - m4_version_prereq([2.70], - [AC_REQUIRE([AC_PROG_CC])], - [AC_REQUIRE([AC_PROG_CC_C99])]) - define([PREFIX], [C]) - define([CACHE_PREFIX], [cc]) - define([COMPILER], [$CC]) - ], - [C++], [ - define([PREFIX], [CXX]) - define([CACHE_PREFIX], [cxx]) - define([COMPILER], [$CXX]) - ] -) - -[xorg_testset_save_]PREFIX[FLAGS]="$PREFIX[FLAGS]" - -if test "x$[xorg_testset_]CACHE_PREFIX[_unknown_warning_option]" = "x" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unknown-warning-option" - AC_CACHE_CHECK([if ]COMPILER[ supports -Werror=unknown-warning-option], - [xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option], - AC_COMPILE_IFELSE([AC_LANG_SOURCE([int i;])], - [xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option=yes], - [xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option=no])) - [xorg_testset_]CACHE_PREFIX[_unknown_warning_option]=$[xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option] - PREFIX[FLAGS]="$[xorg_testset_save_]PREFIX[FLAGS]" -fi - -if test "x$[xorg_testset_]CACHE_PREFIX[_unused_command_line_argument]" = "x" ; then - if test "x$[xorg_testset_]CACHE_PREFIX[_unknown_warning_option]" = "xyes" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unknown-warning-option" - fi - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unused-command-line-argument" - AC_CACHE_CHECK([if ]COMPILER[ supports -Werror=unused-command-line-argument], - [xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument], - AC_COMPILE_IFELSE([AC_LANG_SOURCE([int i;])], - [xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument=yes], - [xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument=no])) - [xorg_testset_]CACHE_PREFIX[_unused_command_line_argument]=$[xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument] - PREFIX[FLAGS]="$[xorg_testset_save_]PREFIX[FLAGS]" -fi - -found="no" -m4_foreach([flag], m4_cdr($@), [ - if test $found = "no" ; then - if test "x$xorg_testset_]CACHE_PREFIX[_unknown_warning_option" = "xyes" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_]CACHE_PREFIX[_unused_command_line_argument" = "xyes" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unused-command-line-argument" - fi - - PREFIX[FLAGS]="$PREFIX[FLAGS] ]flag[" - -dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname - AC_MSG_CHECKING([if ]COMPILER[ supports ]flag[]) - cacheid=AS_TR_SH([xorg_cv_]CACHE_PREFIX[_flag_]flag[]) - AC_CACHE_VAL($cacheid, - [AC_LINK_IFELSE([AC_LANG_PROGRAM([int i;])], - [eval $cacheid=yes], - [eval $cacheid=no])]) - - PREFIX[FLAGS]="$[xorg_testset_save_]PREFIX[FLAGS]" - - eval supported=\$$cacheid - AC_MSG_RESULT([$supported]) - if test "$supported" = "yes" ; then - $1="$$1 ]flag[" - found="yes" - fi - fi -]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1650: -1- AC_DEFUN([XORG_COMPILER_FLAGS], [ -AC_REQUIRE([XORG_COMPILER_BRAND]) - -AC_ARG_ENABLE(selective-werror, - AS_HELP_STRING([--disable-selective-werror], - [Turn off selective compiler errors. (default: enabled)]), - [SELECTIVE_WERROR=$enableval], - [SELECTIVE_WERROR=yes]) - -AC_LANG_CASE( - [C], [ - define([PREFIX], [C]) - ], - [C++], [ - define([PREFIX], [CXX]) - ] -) -# -v is too short to test reliably with XORG_TESTSET_CFLAG -if test "x$SUNCC" = "xyes"; then - [BASE_]PREFIX[FLAGS]="-v" -else - [BASE_]PREFIX[FLAGS]="" -fi - -# This chunk of warnings were those that existed in the legacy CWARNFLAGS -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wall]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wpointer-arith]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-declarations]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wformat=2], [-Wformat]) - -AC_LANG_CASE( - [C], [ - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wstrict-prototypes]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-prototypes]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wnested-externs]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wbad-function-cast]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wold-style-definition], [-fd]) - ] -) - -# This chunk adds additional warnings that could catch undesired effects. -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wunused]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wuninitialized]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wshadow]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-noreturn]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-format-attribute]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wredundant-decls]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wlogical-op]) - -# These are currently disabled because they are noisy. They will be enabled -# in the future once the codebase is sufficiently modernized to silence -# them. For now, I don't want them to drown out the other warnings. -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wparentheses]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-align]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-qual]) - -# Turn some warnings into errors, so we don't accidentally get successful builds -# when there are problems that should be fixed. - -if test "x$SELECTIVE_WERROR" = "xyes" ; then -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=implicit], [-errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=nonnull]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=init-self]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=main]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=missing-braces]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=sequence-point]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=return-type], [-errwarn=E_FUNC_HAS_NO_RETURN_STMT]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=trigraphs]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=array-bounds]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=write-strings]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=address]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=int-to-pointer-cast], [-errwarn=E_BAD_PTR_INT_COMBINATION]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=pointer-to-int-cast]) # Also -errwarn=E_BAD_PTR_INT_COMBINATION -else -AC_MSG_WARN([You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wimplicit]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wnonnull]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Winit-self]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmain]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-braces]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wsequence-point]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wreturn-type]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wtrigraphs]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Warray-bounds]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wwrite-strings]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Waddress]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wint-to-pointer-cast]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wpointer-to-int-cast]) -fi - -AC_SUBST([BASE_]PREFIX[FLAGS]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1755: -1- AC_DEFUN([XORG_CWARNFLAGS], [ -AC_REQUIRE([XORG_COMPILER_FLAGS]) -AC_REQUIRE([XORG_COMPILER_BRAND]) -AC_LANG_CASE( - [C], [ - CWARNFLAGS="$BASE_CFLAGS" - if test "x$GCC" = xyes ; then - CWARNFLAGS="$CWARNFLAGS -fno-strict-aliasing" - fi - AC_SUBST(CWARNFLAGS) - ] -) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1780: -1- AC_DEFUN([XORG_STRICT_OPTION], [ -AC_REQUIRE([XORG_CWARNFLAGS]) -AC_REQUIRE([XORG_COMPILER_FLAGS]) - -AC_ARG_ENABLE(strict-compilation, - AS_HELP_STRING([--enable-strict-compilation], - [Enable all warnings from compiler and make them errors (default: disabled)]), - [STRICT_COMPILE=$enableval], [STRICT_COMPILE=no]) - -AC_LANG_CASE( - [C], [ - define([PREFIX], [C]) - ], - [C++], [ - define([PREFIX], [CXX]) - ] -) - -[STRICT_]PREFIX[FLAGS]="" -XORG_TESTSET_CFLAG([[STRICT_]PREFIX[FLAGS]], [-pedantic]) -XORG_TESTSET_CFLAG([[STRICT_]PREFIX[FLAGS]], [-Werror], [-errwarn]) - -# Earlier versions of gcc (eg: 4.2) support -Werror=attributes, but do not -# activate it with -Werror, so we add it here explicitly. -XORG_TESTSET_CFLAG([[STRICT_]PREFIX[FLAGS]], [-Werror=attributes]) - -if test "x$STRICT_COMPILE" = "xyes"; then - [BASE_]PREFIX[FLAGS]="$[BASE_]PREFIX[FLAGS] $[STRICT_]PREFIX[FLAGS]" - AC_LANG_CASE([C], [CWARNFLAGS="$CWARNFLAGS $STRICT_CFLAGS"]) -fi -AC_SUBST([STRICT_]PREFIX[FLAGS]) -AC_SUBST([BASE_]PREFIX[FLAGS]) -AC_LANG_CASE([C], AC_SUBST([CWARNFLAGS])) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1822: -1- AC_DEFUN([XORG_DEFAULT_NOCODE_OPTIONS], [ -AC_REQUIRE([AC_PROG_INSTALL]) -XORG_RELEASE_VERSION -XORG_CHANGELOG -XORG_INSTALL -XORG_MANPAGE_SECTIONS -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], - [AC_SUBST([AM_DEFAULT_VERBOSITY], [1])]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1838: -1- AC_DEFUN([XORG_DEFAULT_OPTIONS], [ -AC_REQUIRE([AC_PROG_INSTALL]) -XORG_COMPILER_FLAGS -XORG_CWARNFLAGS -XORG_STRICT_OPTION -XORG_DEFAULT_NOCODE_OPTIONS -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1853: -1- AC_DEFUN([XORG_INSTALL], [ -AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -macros_datadir=`$PKG_CONFIG --print-errors --variable=pkgdatadir xorg-macros` -INSTALL_CMD="(cp -f "$macros_datadir/INSTALL" \$(top_srcdir)/.INSTALL.tmp && \ -mv \$(top_srcdir)/.INSTALL.tmp \$(top_srcdir)/INSTALL) \ -|| (rm -f \$(top_srcdir)/.INSTALL.tmp; test -e \$(top_srcdir)/INSTALL || ( \ -touch \$(top_srcdir)/INSTALL; \ -echo 'failed to copy INSTALL from util-macros: installing empty INSTALL.' >&2))" -AC_SUBST([INSTALL_CMD]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1892: -1- AC_DEFUN([XORG_RELEASE_VERSION], [ - AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MAJOR], - [`echo $PACKAGE_VERSION | cut -d . -f 1`], - [Major version of this package]) - PVM=`echo $PACKAGE_VERSION | cut -d . -f 2 | cut -d - -f 1` - if test "x$PVM" = "x"; then - PVM="0" - fi - AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MINOR], - [$PVM], - [Minor version of this package]) - PVP=`echo $PACKAGE_VERSION | cut -d . -f 3 | cut -d - -f 1` - if test "x$PVP" = "x"; then - PVP="0" - fi - AC_DEFINE_UNQUOTED([PACKAGE_VERSION_PATCHLEVEL], - [$PVP], - [Patch version of this package]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1920: -1- AC_DEFUN([XORG_CHANGELOG], [ -CHANGELOG_CMD="((GIT_DIR=\$(top_srcdir)/.git git log > \$(top_srcdir)/.changelog.tmp) 2>/dev/null && \ -mv \$(top_srcdir)/.changelog.tmp \$(top_srcdir)/ChangeLog) \ -|| (rm -f \$(top_srcdir)/.changelog.tmp; test -e \$(top_srcdir)/ChangeLog || ( \ -touch \$(top_srcdir)/ChangeLog; \ -echo 'git failed to create ChangeLog: installing empty ChangeLog.' >&2))" -AC_SUBST([CHANGELOG_CMD]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/amversion.m4:14: -1- AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.18' -dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to -dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.18.1], [], - [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/amversion.m4:33: -1- AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.18.1])dnl -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/auxdir.m4:47: -1- AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/cond.m4:12: -1- AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl - m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -m4_define([_AM_COND_VALUE_$1], [$2])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depend.m4:26: -1- AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl -AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl -AC_REQUIRE([AM_MAKE_INCLUDE])dnl -AC_REQUIRE([AM_DEP_TRACK])dnl - -m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], - [$1], [CXX], [depcc="$CXX" am_compiler_list=], - [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], - [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], - [$1], [UPC], [depcc="$UPC" am_compiler_list=], - [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], - [depcc="$$1" am_compiler_list=]) - -AC_CACHE_CHECK([dependency style of $depcc], - [am_cv_$1_dependencies_compiler_type], -[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_$1_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` - fi - am__universal=false - m4_case([$1], [CC], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac], - [CXX], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac]) - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thus: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_$1_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_$1_dependencies_compiler_type=none -fi -]) -AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) -AM_CONDITIONAL([am__fastdep$1], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depend.m4:163: -1- AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl -AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depend.m4:171: -1- AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl -AS_HELP_STRING( - [--enable-dependency-tracking], - [do not reject slow dependency extractors]) -AS_HELP_STRING( - [--disable-dependency-tracking], - [speeds up one-time build])]) -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi -AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -AC_SUBST([AMDEPBACKSLASH])dnl -_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl -AC_SUBST([am__nodep])dnl -_AM_SUBST_NOTMAKE([am__nodep])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depout.m4:11: -1- AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - AS_CASE([$CONFIG_FILES], - [*\'*], [eval set x "$CONFIG_FILES"], - [*], [set x $CONFIG_FILES]) - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`AS_DIRNAME(["$am_mf"])` - am_filepart=`AS_BASENAME(["$am_mf"])` - AM_RUN_LOG([cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles]) || am_rc=$? - done - if test $am_rc -ne 0; then - AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE="gmake" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking).]) - fi - AS_UNSET([am_dirpart]) - AS_UNSET([am_filepart]) - AS_UNSET([am_mf]) - AS_UNSET([am_rc]) - rm -f conftest-deps.mk -} -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depout.m4:64: -1- AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], - [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/init.m4:29: -1- AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl -m4_ifdef([_$0_ALREADY_INIT], - [m4_fatal([$0 expanded multiple times -]m4_defn([_$0_ALREADY_INIT]))], - [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl -dnl Autoconf wants to disallow AM_ names. We explicitly allow -dnl the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl -AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl -AC_REQUIRE([AC_PROG_INSTALL])dnl -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[AC_DIAGNOSE([obsolete], - [$0: two- and three-arguments forms are deprecated.]) -m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl -dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. -m4_if( - m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), - [ok:ok],, - [m4_fatal([AC_INIT should be called with package and version arguments])])dnl - AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl - AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) - AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) -AM_MISSING_PROG([AUTOCONF], [autoconf]) -AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) -AM_MISSING_PROG([AUTOHEADER], [autoheader]) -AM_MISSING_PROG([MAKEINFO], [makeinfo]) -AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl -AC_REQUIRE([AC_PROG_MKDIR_P])dnl -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl -AC_REQUIRE([AM_SET_LEADING_DOT])dnl -_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], - [_AM_PROG_TAR([ustar])])])]) -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES([CC])], - [m4_define([AC_PROG_CC], - m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES([CXX])], - [m4_define([AC_PROG_CXX], - m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES([OBJC])], - [m4_define([AC_PROG_OBJC], - m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], - [_AM_DEPENDENCIES([OBJCXX])], - [m4_define([AC_PROG_OBJCXX], - m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl -]) -# Variables for tags utilities; see am/tags.am -if test -z "$CTAGS"; then - CTAGS=ctags -fi -AC_SUBST([CTAGS]) -if test -z "$ETAGS"; then - ETAGS=etags -fi -AC_SUBST([ETAGS]) -if test -z "$CSCOPE"; then - CSCOPE=cscope -fi -AC_SUBST([CSCOPE]) - -AC_REQUIRE([_AM_SILENT_RULES])dnl -dnl The testsuite driver may need to know about EXEEXT, so add the -dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This -dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. -AC_CONFIG_COMMANDS_PRE(dnl -[m4_provide_if([_AM_COMPILER_EXEEXT], - [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl - -AC_REQUIRE([_AM_PROG_RM_F]) -AC_REQUIRE([_AM_PROG_XARGS_N]) - -dnl The trailing newline in this macro's definition is deliberate, for -dnl backward compatibility and to allow trailing 'dnl'-style comments -dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/init.m4:167: -1- AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. -_am_arg=$1 -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/install-sh.m4:11: -1- AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi -AC_SUBST([install_sh])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/lead-dot.m4:10: -1- AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null -AC_SUBST([am__leading_dot])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/make.m4:13: -1- AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) -cat > confinc.mk << 'END' -am__doit: - @echo this is the am__doit target >confinc.out -.PHONY: am__doit -END -am__include="#" -am__quote= -# BSD make does it like this. -echo '.include "confinc.mk" # ignored' > confmf.BSD -# Other make implementations (GNU, Solaris 10, AIX) do it like this. -echo 'include confinc.mk # ignored' > confmf.GNU -_am_result=no -for s in GNU BSD; do - AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) - AS_CASE([$?:`cat confinc.out 2>/dev/null`], - ['0:this is the am__doit target'], - [AS_CASE([$s], - [BSD], [am__include='.include' am__quote='"'], - [am__include='include' am__quote=''])]) - if test "$am__include" != "#"; then - _am_result="yes ($s style)" - break - fi -done -rm -f confinc.* confmf.* -AC_MSG_RESULT([${_am_result}]) -AC_SUBST([am__include])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/make.m4:42: -1- m4_pattern_allow([^am__quote$]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/missing.m4:11: -1- AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/missing.m4:20: -1- AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([missing])dnl -if test x"${MISSING+set}" != xset; then - MISSING="\${SHELL} '$am_aux_dir/missing'" -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - AC_MSG_WARN(['missing' script is too old or missing]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4:11: -1- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4:17: -1- AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4:23: -1- AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4:29: -1- AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/prog-cc-c-o.m4:12: -1- AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([compile])dnl -AC_LANG_PUSH([C])dnl -AC_CACHE_CHECK( - [whether $CC understands -c and -o together], - [am_cv_prog_cc_c_o], - [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - # aligned with autoconf, so not including core; see bug#72225. - rm -f -r a.out a.exe b.out conftest.$ac_ext conftest.$ac_objext \ - conftest.dSYM conftest1.$ac_ext conftest1.$ac_objext conftest1.dSYM \ - conftest2.$ac_ext conftest2.$ac_objext conftest2.dSYM - unset am_i]) -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -AC_LANG_POP([C])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/prog-cc-c-o.m4:50: -1- AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/rmf.m4:12: -1- AC_DEFUN([_AM_PROG_RM_F], [am__rm_f_notfound= -AS_IF([(rm -f && rm -fr && rm -rf) 2>/dev/null], [], [am__rm_f_notfound='""']) -AC_SUBST(am__rm_f_notfound) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/runlog.m4:12: -1- AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD - ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - (exit $ac_status); }]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/sanity.m4:11: -1- AC_DEFUN([_AM_SLEEP_FRACTIONAL_SECONDS], [dnl -AC_CACHE_CHECK([whether sleep supports fractional seconds], - am_cv_sleep_fractional_seconds, [dnl -AS_IF([sleep 0.001 2>/dev/null], [am_cv_sleep_fractional_seconds=yes], - [am_cv_sleep_fractional_seconds=no]) -])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/sanity.m4:28: -1- AC_DEFUN([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION], [dnl -AC_REQUIRE([_AM_SLEEP_FRACTIONAL_SECONDS]) -AC_CACHE_CHECK([filesystem timestamp resolution], - am_cv_filesystem_timestamp_resolution, [dnl -# Default to the worst case. -am_cv_filesystem_timestamp_resolution=2 - -# Only try to go finer than 1 sec if sleep can do it. -# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, -# - 1 sec is not much of a win compared to 2 sec, and -# - it takes 2 seconds to perform the test whether 1 sec works. -# -# Instead, just use the default 2s on platforms that have 1s resolution, -# accept the extra 1s delay when using $sleep in the Automake tests, in -# exchange for not incurring the 2s delay for running the test for all -# packages. -# -am_try_resolutions= -if test "$am_cv_sleep_fractional_seconds" = yes; then - # Even a millisecond often causes a bunch of false positives, - # so just try a hundredth of a second. The time saved between .001 and - # .01 is not terribly consequential. - am_try_resolutions="0.01 0.1 $am_try_resolutions" -fi - -# In order to catch current-generation FAT out, we must *modify* files -# that already exist; the *creation* timestamp is finer. Use names -# that make ls -t sort them differently when they have equal -# timestamps than when they have distinct timestamps, keeping -# in mind that ls -t prints the *newest* file first. -rm -f conftest.ts? -: > conftest.ts1 -: > conftest.ts2 -: > conftest.ts3 - -# Make sure ls -t actually works. Do 'set' in a subshell so we don't -# clobber the current shell's arguments. (Outer-level square brackets -# are removed by m4; they're present so that m4 does not expand -# ; be careful, easy to get confused.) -if ( - set X `[ls -t conftest.ts[12]]` && - { - test "$[]*" != "X conftest.ts1 conftest.ts2" || - test "$[]*" != "X conftest.ts2 conftest.ts1"; - } -); then :; else - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - _AS_ECHO_UNQUOTED( - ["Bad output from ls -t: \"`[ls -t conftest.ts[12]]`\""], - [AS_MESSAGE_LOG_FD]) - AC_MSG_FAILURE([ls -t produces unexpected output. -Make sure there is not a broken ls alias in your environment.]) -fi - -for am_try_res in $am_try_resolutions; do - # Any one fine-grained sleep might happen to cross the boundary - # between two values of a coarser actual resolution, but if we do - # two fine-grained sleeps in a row, at least one of them will fall - # entirely within a coarse interval. - echo alpha > conftest.ts1 - sleep $am_try_res - echo beta > conftest.ts2 - sleep $am_try_res - echo gamma > conftest.ts3 - - # We assume that 'ls -t' will make use of high-resolution - # timestamps if the operating system supports them at all. - if (set X `ls -t conftest.ts?` && - test "$[]2" = conftest.ts3 && - test "$[]3" = conftest.ts2 && - test "$[]4" = conftest.ts1); then - # - # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, - # because we don't need to test make. - make_ok=true - if test $am_try_res != 1; then - # But if we've succeeded so far with a subsecond resolution, we - # have one more thing to check: make. It can happen that - # everything else supports the subsecond mtimes, but make doesn't; - # notably on macOS, which ships make 3.81 from 2006 (the last one - # released under GPLv2). https://bugs.gnu.org/68808 - # - # We test $MAKE if it is defined in the environment, else "make". - # It might get overridden later, but our hope is that in practice - # it does not matter: it is the system "make" which is (by far) - # the most likely to be broken, whereas if the user overrides it, - # probably they did so with a better, or at least not worse, make. - # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html - # - # Create a Makefile (real tab character here): - rm -f conftest.mk - echo 'conftest.ts1: conftest.ts2' >conftest.mk - echo ' touch conftest.ts2' >>conftest.mk - # - # Now, running - # touch conftest.ts1; touch conftest.ts2; make - # should touch ts1 because ts2 is newer. This could happen by luck, - # but most often, it will fail if make's support is insufficient. So - # test for several consecutive successes. - # - # (We reuse conftest.ts[12] because we still want to modify existing - # files, not create new ones, per above.) - n=0 - make=${MAKE-make} - until test $n -eq 3; do - echo one > conftest.ts1 - sleep $am_try_res - echo two > conftest.ts2 # ts2 should now be newer than ts1 - if $make -f conftest.mk | grep 'up to date' >/dev/null; then - make_ok=false - break # out of $n loop - fi - n=`expr $n + 1` - done - fi - # - if $make_ok; then - # Everything we know to check worked out, so call this resolution good. - am_cv_filesystem_timestamp_resolution=$am_try_res - break # out of $am_try_res loop - fi - # Otherwise, we'll go on to check the next resolution. - fi -done -rm -f conftest.ts? -# (end _am_filesystem_timestamp_resolution) -])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/sanity.m4:161: -1- AC_DEFUN([AM_SANITY_CHECK], [AC_REQUIRE([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION]) -# This check should not be cached, as it may vary across builds of -# different projects. -AC_MSG_CHECKING([whether build environment is sane]) -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[[\\\"\#\$\&\'\`$am_lf]]*) - AC_MSG_RESULT([no]) - AC_MSG_ERROR([unsafe absolute working directory name]);; -esac -case $srcdir in - *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) - AC_MSG_RESULT([no]) - AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -am_build_env_is_sane=no -am_has_slept=no -rm -f conftest.file -for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[]*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - test "$[]2" = conftest.file - ); then - am_build_env_is_sane=yes - break - fi - # Just in case. - sleep "$am_cv_filesystem_timestamp_resolution" - am_has_slept=yes -done - -AC_MSG_RESULT([$am_build_env_is_sane]) -if test "$am_build_env_is_sane" = no; then - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi - -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -AS_IF([test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1],, [dnl - ( sleep "$am_cv_filesystem_timestamp_resolution" ) & - am_sleep_pid=$! -]) -AC_CONFIG_COMMANDS_PRE( - [AC_MSG_CHECKING([that generated files are newer than configure]) - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - AC_MSG_RESULT([done])]) -rm -f conftest.file -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/silent.m4:11: -1- AC_DEFUN([_AM_SILENT_RULES], [AM_DEFAULT_VERBOSITY=1 -AC_ARG_ENABLE([silent-rules], [dnl -AS_HELP_STRING( - [--enable-silent-rules], - [less verbose build output (undo: "make V=1")]) -AS_HELP_STRING( - [--disable-silent-rules], - [verbose build output (undo: "make V=0")])dnl -]) -dnl -dnl A few 'make' implementations (e.g., NonStop OS and NextStep) -dnl do not support nested variable expansions. -dnl See automake bug#9928 and bug#10237. -am_make=${MAKE-make} -AC_CACHE_CHECK([whether $am_make supports nested variables], - [am_cv_make_support_nested_variables], - [if AS_ECHO([['TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi]) -AC_SUBST([AM_V])dnl -AM_SUBST_NOTMAKE([AM_V])dnl -AC_SUBST([AM_DEFAULT_V])dnl -AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl -AC_SUBST([AM_DEFAULT_VERBOSITY])dnl -AM_BACKSLASH='\' -AC_SUBST([AM_BACKSLASH])dnl -_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl -dnl Delay evaluation of AM_DEFAULT_VERBOSITY to the end to allow multiple calls -dnl to AM_SILENT_RULES to change the default value. -AC_CONFIG_COMMANDS_PRE([dnl -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; -esac -if test $am_cv_make_support_nested_variables = yes; then - dnl Using '$V' instead of '$(V)' breaks IRIX make. - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi -])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/silent.m4:69: -1- AC_DEFUN([AM_SILENT_RULES], [AC_REQUIRE([_AM_SILENT_RULES]) -AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1])m4_newline -dnl We intentionally force a newline after the assignment, since a) nothing -dnl good can come of more text following, and b) that was the behavior -dnl before 1.17. See https://bugs.gnu.org/72267. -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/strip.m4:17: -1- AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/substnot.m4:12: -1- AC_DEFUN([_AM_SUBST_NOTMAKE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/substnot.m4:17: -1- AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/tar.m4:23: -1- AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AC_SUBST([AMTAR], ['$${TAR-tar}']) - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' - -m4_if([$1], [v7], - [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], - - [m4_case([$1], - [ustar], - [# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) - if test x$am_uid = xunknown; then - AC_MSG_WARN([ancient id detected; assuming current UID is ok, but dist-ustar might not work]) - elif test $am_uid -le $am_max_uid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi - AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) - if test x$gm_gid = xunknown; then - AC_MSG_WARN([ancient id detected; assuming current GID is ok, but dist-ustar might not work]) - elif test $am_gid -le $am_max_gid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi], - - [pax], - [], - - [m4_fatal([Unknown tar format])]) - - AC_MSG_CHECKING([how to create a $1 tar archive]) - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_$1-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - AM_RUN_LOG([$_am_tar --version]) && break - done - am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x $1 -w "$$tardir"' - am__tar_='pax -L -x $1 -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H $1 -L' - am__tar_='find "$tardir" -print | cpio -o -H $1 -L' - am__untar='cpio -i -H $1 -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_$1}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) - rm -rf conftest.dir - if test -s conftest.tar; then - AM_RUN_LOG([$am__untar /dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) - AC_MSG_RESULT([$am_cv_prog_tar_$1])]) - -AC_SUBST([am__tar]) -AC_SUBST([am__untar]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/xargsn.m4:12: -1- AC_DEFUN([_AM_PROG_XARGS_N], [AC_CACHE_CHECK([xargs -n works], am_cv_xargs_n_works, [dnl -AS_IF([test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 -3"], [am_cv_xargs_n_works=yes], [am_cv_xargs_n_works=no])]) -AS_IF([test "$am_cv_xargs_n_works" = yes], [am__xargs_n='xargs -n'], [dnl - am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "$@" "$am__xargs_n_arg"; done; }' -])dnl -AC_SUBST(am__xargs_n) -]) -m4trace:m4/ax_gcc_builtin.m4:95: -1- AC_DEFUN([AX_GCC_BUILTIN], [ - AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1]) - - AC_CACHE_CHECK([for $1], [ac_var], [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([], [ - m4_case([$1], - [__builtin_assume_aligned], [$1("", 0)], - [__builtin_bswap32], [$1(0)], - [__builtin_bswap64], [$1(0)], - [__builtin_choose_expr], [$1(0, 0, 0)], - [__builtin___clear_cache], [$1("", "")], - [__builtin_clrsb], [$1(0)], - [__builtin_clrsbl], [$1(0)], - [__builtin_clrsbll], [$1(0)], - [__builtin_clz], [$1(0)], - [__builtin_clzl], [$1(0)], - [__builtin_clzll], [$1(0)], - [__builtin_complex], [$1(0.0, 0.0)], - [__builtin_constant_p], [$1(0)], - [__builtin_ctz], [$1(0)], - [__builtin_ctzl], [$1(0)], - [__builtin_ctzll], [$1(0)], - [__builtin_expect], [$1(0, 0)], - [__builtin_ffs], [$1(0)], - [__builtin_ffsl], [$1(0)], - [__builtin_ffsll], [$1(0)], - [__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)], - [__builtin_huge_val], [$1()], - [__builtin_huge_valf], [$1()], - [__builtin_huge_vall], [$1()], - [__builtin_inf], [$1()], - [__builtin_infd128], [$1()], - [__builtin_infd32], [$1()], - [__builtin_infd64], [$1()], - [__builtin_inff], [$1()], - [__builtin_infl], [$1()], - [__builtin_isinf_sign], [$1(0.0)], - [__builtin_nan], [$1("")], - [__builtin_nand128], [$1("")], - [__builtin_nand32], [$1("")], - [__builtin_nand64], [$1("")], - [__builtin_nanf], [$1("")], - [__builtin_nanl], [$1("")], - [__builtin_nans], [$1("")], - [__builtin_nansf], [$1("")], - [__builtin_nansl], [$1("")], - [__builtin_object_size], [$1("", 0)], - [__builtin_parity], [$1(0)], - [__builtin_parityl], [$1(0)], - [__builtin_parityll], [$1(0)], - [__builtin_popcount], [$1(0)], - [__builtin_popcountl], [$1(0)], - [__builtin_popcountll], [$1(0)], - [__builtin_powi], [$1(0, 0)], - [__builtin_powif], [$1(0, 0)], - [__builtin_powil], [$1(0, 0)], - [__builtin_prefetch], [$1("")], - [__builtin_trap], [$1()], - [__builtin_types_compatible_p], [$1(int, int)], - [__builtin_unreachable], [$1()], - [m4_warn([syntax], [Unsupported built-in $1, the test may fail]) - $1()] - ) - ])], - [AS_VAR_SET([ac_var], [yes])], - [AS_VAR_SET([ac_var], [no])]) - ]) - - AS_IF([test yes = AS_VAR_GET([ac_var])], - [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1, - [Define to 1 if the system has the `$1' built-in function])], []) - - AS_VAR_POPDEF([ac_var]) -]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?A[CHUM]_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([_AC_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section 'AC_LIBOBJ vs LIBOBJS']) -m4trace:configure.ac:4: -1- m4_pattern_allow([^AS_FLAGS$]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?m4_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^dnl$]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?AS_]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^SHELL$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PATH_SEPARATOR$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^exec_prefix$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^prefix$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^program_transform_name$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^bindir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sbindir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^libexecdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^datarootdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^datadir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sysconfdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sharedstatedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^localstatedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^runstatedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^includedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^oldincludedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^docdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^infodir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^htmldir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^dvidir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^pdfdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^psdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^libdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^localedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^mandir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^DEFS$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^build_alias$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^host_alias$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^target_alias$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_C$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_N$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_T$]) -m4trace:configure.ac:8: -1- AC_CONFIG_MACRO_DIR([m4]) -m4trace:configure.ac:8: -1- AC_CONFIG_MACRO_DIR_TRACE([m4]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_stdio_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" stdio.h ]AS_TR_SH([stdio.h]) AS_TR_CPP([HAVE_stdio.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CFLAGS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^LDFLAGS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CPPFLAGS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^ac_ct_CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^EXEEXT$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^OBJEXT$]) -m4trace:configure.ac:13: -1- _AM_PROG_CC_C_O -m4trace:configure.ac:13: -1- AM_AUX_DIR_EXPAND -m4trace:configure.ac:13: -1- AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_stdlib_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" stdlib.h ]AS_TR_SH([stdlib.h]) AS_TR_CPP([HAVE_stdlib.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_string_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" string.h ]AS_TR_SH([string.h]) AS_TR_CPP([HAVE_string.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_inttypes_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" inttypes.h ]AS_TR_SH([inttypes.h]) AS_TR_CPP([HAVE_inttypes.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_stdint_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" stdint.h ]AS_TR_SH([stdint.h]) AS_TR_CPP([HAVE_stdint.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_strings_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" strings.h ]AS_TR_SH([strings.h]) AS_TR_CPP([HAVE_strings.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_sys_stat_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" sys/stat.h ]AS_TR_SH([sys/stat.h]) AS_TR_CPP([HAVE_sys/stat.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_sys_types_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" sys/types.h ]AS_TR_SH([sys/types.h]) AS_TR_CPP([HAVE_sys/types.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_unistd_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" unistd.h ]AS_TR_SH([unistd.h]) AS_TR_CPP([HAVE_unistd.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^STDC_HEADERS$]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_wchar_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" wchar.h ]AS_TR_SH([wchar.h]) AS_TR_CPP([HAVE_wchar.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_minix_config_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" minix/config.h ]AS_TR_SH([minix/config.h]) AS_TR_CPP([HAVE_minix/config.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_ALL_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_COSMO_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_DARWIN_C_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_GNU_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_HPUX_ALT_XOPEN_SOCKET_API$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_NETBSD_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_OPENBSD_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_PTHREAD_SEMANTICS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_ATTRIBS_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_BFP_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_DFP_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_FUNCS_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_TYPES_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_LIB_EXT2__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_MATH_SPEC_FUNCS__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_TANDEM_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_MINIX$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_1_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__EXTENSIONS__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_XOPEN_SOURCE$]) -m4trace:configure.ac:16: -1- AM_INIT_AUTOMAKE([foreign dist-xz]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_[A-Z]+FLAGS$]) -m4trace:configure.ac:16: -1- AM_SET_CURRENT_AUTOMAKE_VERSION -m4trace:configure.ac:16: -1- AM_AUTOMAKE_VERSION([1.18.1]) -m4trace:configure.ac:16: -1- _AM_AUTOCONF_VERSION([2.73]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_PROGRAM$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_SCRIPT$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_DATA$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__isrc$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__isrc]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CYGPATH_W$]) -m4trace:configure.ac:16: -1- _AM_SET_OPTIONS([foreign dist-xz]) -m4trace:configure.ac:16: -1- _AM_SET_OPTION([foreign]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([foreign]) -m4trace:configure.ac:16: -1- _AM_SET_OPTION([dist-xz]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([dist-xz]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^PACKAGE$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^VERSION$]) -m4trace:configure.ac:16: -1- _AM_IF_OPTION([no-define], [], [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) - AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([no-define]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^PACKAGE$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^VERSION$]) -m4trace:configure.ac:16: -1- AM_SANITY_CHECK -m4trace:configure.ac:16: -1- _AM_FILESYSTEM_TIMESTAMP_RESOLUTION -m4trace:configure.ac:16: -1- _AM_SLEEP_FRACTIONAL_SECONDS -m4trace:configure.ac:16: -1- AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) -m4trace:configure.ac:16: -1- AM_MISSING_HAS_RUN -m4trace:configure.ac:16: -1- m4_pattern_allow([^ACLOCAL$]) -m4trace:configure.ac:16: -1- AM_MISSING_PROG([AUTOCONF], [autoconf]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOCONF$]) -m4trace:configure.ac:16: -1- AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOMAKE$]) -m4trace:configure.ac:16: -1- AM_MISSING_PROG([AUTOHEADER], [autoheader]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOHEADER$]) -m4trace:configure.ac:16: -1- AM_MISSING_PROG([MAKEINFO], [makeinfo]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^MAKEINFO$]) -m4trace:configure.ac:16: -1- AM_PROG_INSTALL_SH -m4trace:configure.ac:16: -1- m4_pattern_allow([^install_sh$]) -m4trace:configure.ac:16: -1- AM_PROG_INSTALL_STRIP -m4trace:configure.ac:16: -1- m4_pattern_allow([^STRIP$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_STRIP_PROGRAM$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^MKDIR_P$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^mkdir_p$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AWK$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^SET_MAKE$]) -m4trace:configure.ac:16: -1- AM_SET_LEADING_DOT -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__leading_dot$]) -m4trace:configure.ac:16: -1- _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], - [_AM_PROG_TAR([ustar])])])]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([tar-ustar]) -m4trace:configure.ac:16: -1- _AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], - [_AM_PROG_TAR([ustar])])]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([tar-pax]) -m4trace:configure.ac:16: -1- _AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], [_AM_PROG_TAR([ustar])]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([tar-v7]) -m4trace:configure.ac:16: -1- _AM_PROG_TAR([ustar]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMTAR$]) -m4trace:configure.ac:16: -1- AM_RUN_LOG([$_am_tar --version]) -m4trace:configure.ac:16: -1- AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) -m4trace:configure.ac:16: -1- AM_RUN_LOG([$am__untar = 1.8])], [XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools`], [m4_ifval([1.8],[:], - [if test x"$cross_compiling" != x"yes" ; then - AC_CHECK_FILE([$prefix/share/sgml/X11/defs.ent], - [XORG_SGML_PATH=$prefix/share/sgml]) - fi]) - ]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^XORG_SGML_PATH$]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^STYLESHEET_SRCDIR$]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^XSL_STYLESHEET$]) -m4trace:configure.ac:30: -1- AM_CONDITIONAL([HAVE_STYLESHEETS], [test "x$XSL_STYLESHEET" != "x"]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^HAVE_STYLESHEETS_TRUE$]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^HAVE_STYLESHEETS_FALSE$]) -m4trace:configure.ac:30: -1- _AM_SUBST_NOTMAKE([HAVE_STYLESHEETS_TRUE]) -m4trace:configure.ac:30: -1- _AM_SUBST_NOTMAKE([HAVE_STYLESHEETS_FALSE]) -m4trace:configure.ac:31: -1- XORG_CHECK_MALLOC_ZERO -m4trace:configure.ac:31: -1- m4_pattern_allow([^MALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^XMALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^XTMALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:42: -1- m4_pattern_allow([^XEXT_SOREV$]) -m4trace:configure.ac:45: -1- PKG_CHECK_MODULES([XEXT], [xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99]) -m4trace:configure.ac:45: -1- m4_pattern_allow([^XEXT_CFLAGS$]) -m4trace:configure.ac:45: -1- m4_pattern_allow([^XEXT_LIBS$]) -m4trace:configure.ac:45: -1- PKG_CHECK_EXISTS([xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99], [pkg_cv_[]XEXT_CFLAGS=`$PKG_CONFIG --[]cflags "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) -m4trace:configure.ac:45: -1- PKG_CHECK_EXISTS([xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99], [pkg_cv_[]XEXT_LIBS=`$PKG_CONFIG --[]libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) -m4trace:configure.ac:45: -1- _PKG_SHORT_ERRORS_SUPPORTED -m4trace:configure.ac:47: -1- AX_GCC_BUILTIN([__builtin_popcountl]) -m4trace:configure.ac:47: -1- m4_pattern_allow([^HAVE___BUILTIN_POPCOUNTL$]) -m4trace:configure.ac:48: -1- m4_pattern_allow([^HAVE_REALLOCARRAY$]) -m4trace:configure.ac:48: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:51: -1- XORG_WITH_LINT -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT$]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FLAGS$]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT$]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FLAGS$]) -m4trace:configure.ac:51: -1- AM_CONDITIONAL([LINT], [test "x$LINT" != x]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_TRUE$]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FALSE$]) -m4trace:configure.ac:51: -1- _AM_SUBST_NOTMAKE([LINT_TRUE]) -m4trace:configure.ac:51: -1- _AM_SUBST_NOTMAKE([LINT_FALSE]) -m4trace:configure.ac:52: -1- XORG_LINT_LIBRARY([Xext]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^LINTLIB$]) -m4trace:configure.ac:52: -1- AM_CONDITIONAL([MAKE_LINT_LIB], [test x$make_lint_lib != xno]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^MAKE_LINT_LIB_TRUE$]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^MAKE_LINT_LIB_FALSE$]) -m4trace:configure.ac:52: -1- _AM_SUBST_NOTMAKE([MAKE_LINT_LIB_TRUE]) -m4trace:configure.ac:52: -1- _AM_SUBST_NOTMAKE([MAKE_LINT_LIB_FALSE]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:59: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:59: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:59: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:59: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) -m4trace:configure.ac:59: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS -m4trace:configure.ac:59: -1- AM_RUN_LOG([cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles]) -m4trace:configure.ac:59: -1- _LT_PROG_LTMAIN diff --git a/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.1 b/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.1 deleted file mode 100644 index 8316de261..000000000 --- a/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.1 +++ /dev/null @@ -1,929 +0,0 @@ -m4trace:aclocal.m4:2934: -1- AC_SUBST([am__quote]) -m4trace:aclocal.m4:2934: -1- AC_SUBST_TRACE([am__quote]) -m4trace:aclocal.m4:2934: -1- m4_pattern_allow([^am__quote$]) -m4trace:aclocal.m4:3590: -1- m4_include([m4/ax_gcc_builtin.m4]) -m4trace:aclocal.m4:3591: -1- m4_include([m4/libtool.m4]) -m4trace:aclocal.m4:3592: -1- m4_include([m4/ltoptions.m4]) -m4trace:aclocal.m4:3593: -1- m4_include([m4/ltsugar.m4]) -m4trace:aclocal.m4:3594: -1- m4_include([m4/ltversion.m4]) -m4trace:aclocal.m4:3595: -1- m4_include([m4/lt~obsolete.m4]) -m4trace:configure.ac:4: -1- AC_INIT([libXext], [1.3.7], [https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues], [libXext]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?A[CHUM]_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([_AC_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section 'AC_LIBOBJ vs LIBOBJS']) -m4trace:configure.ac:4: -1- m4_pattern_allow([^AS_FLAGS$]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?m4_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^dnl$]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?AS_]) -m4trace:configure.ac:4: -1- AC_SUBST([SHELL]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([SHELL]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^SHELL$]) -m4trace:configure.ac:4: -1- AC_SUBST([PATH_SEPARATOR]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PATH_SEPARATOR]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PATH_SEPARATOR$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME], ['AC_PACKAGE_NAME'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_NAME]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME], ['AC_PACKAGE_TARNAME'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_TARNAME]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION], ['AC_PACKAGE_VERSION'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_VERSION]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_STRING]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_BUGREPORT]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_URL], [m4_ifdef([AC_PACKAGE_URL], ['AC_PACKAGE_URL'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_URL]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:4: -1- AC_SUBST([exec_prefix], [NONE]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([exec_prefix]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^exec_prefix$]) -m4trace:configure.ac:4: -1- AC_SUBST([prefix], [NONE]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([prefix]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^prefix$]) -m4trace:configure.ac:4: -1- AC_SUBST([program_transform_name], [s,x,x,]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([program_transform_name]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^program_transform_name$]) -m4trace:configure.ac:4: -1- AC_SUBST([bindir], ['${exec_prefix}/bin']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([bindir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^bindir$]) -m4trace:configure.ac:4: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([sbindir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sbindir$]) -m4trace:configure.ac:4: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([libexecdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^libexecdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([datarootdir], ['${prefix}/share']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([datarootdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^datarootdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([datadir], ['${datarootdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([datadir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^datadir$]) -m4trace:configure.ac:4: -1- AC_SUBST([sysconfdir], ['${prefix}/etc']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([sysconfdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sysconfdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([sharedstatedir], ['${prefix}/com']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([sharedstatedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sharedstatedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([localstatedir], ['${prefix}/var']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([localstatedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^localstatedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([runstatedir], ['${localstatedir}/run']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([runstatedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^runstatedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([includedir], ['${prefix}/include']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([includedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^includedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([oldincludedir], ['/usr/include']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([oldincludedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^oldincludedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([docdir], [m4_ifset([AC_PACKAGE_TARNAME], - ['${datarootdir}/doc/${PACKAGE_TARNAME}'], - ['${datarootdir}/doc/${PACKAGE}'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([docdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^docdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([infodir], ['${datarootdir}/info']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([infodir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^infodir$]) -m4trace:configure.ac:4: -1- AC_SUBST([htmldir], ['${docdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([htmldir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^htmldir$]) -m4trace:configure.ac:4: -1- AC_SUBST([dvidir], ['${docdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([dvidir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^dvidir$]) -m4trace:configure.ac:4: -1- AC_SUBST([pdfdir], ['${docdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([pdfdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^pdfdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([psdir], ['${docdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([psdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^psdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([libdir], ['${exec_prefix}/lib']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([libdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^libdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([localedir], ['${datarootdir}/locale']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([localedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^localedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([mandir], ['${datarootdir}/man']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([mandir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^mandir$]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */ -@%:@undef PACKAGE_NAME]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */ -@%:@undef PACKAGE_TARNAME]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */ -@%:@undef PACKAGE_VERSION]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */ -@%:@undef PACKAGE_STRING]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */ -@%:@undef PACKAGE_BUGREPORT]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_URL]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_URL], [/* Define to the home page for this package. */ -@%:@undef PACKAGE_URL]) -m4trace:configure.ac:4: -1- AC_SUBST([DEFS]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([DEFS]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^DEFS$]) -m4trace:configure.ac:4: -1- AC_SUBST([LIBS]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([LIBS]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:4: -1- AC_SUBST([build_alias]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([build_alias]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^build_alias$]) -m4trace:configure.ac:4: -1- AC_SUBST([host_alias]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([host_alias]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^host_alias$]) -m4trace:configure.ac:4: -1- AC_SUBST([target_alias]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([target_alias]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^target_alias$]) -m4trace:configure.ac:4: -1- AC_SUBST([ECHO_C]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([ECHO_C]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_C$]) -m4trace:configure.ac:4: -1- AC_SUBST([ECHO_N]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([ECHO_N]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_N$]) -m4trace:configure.ac:4: -1- AC_SUBST([ECHO_T]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([ECHO_T]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_T$]) -m4trace:configure.ac:7: -1- AC_CONFIG_HEADERS([config.h]) -m4trace:configure.ac:8: -1- AC_CONFIG_MACRO_DIR([m4]) -m4trace:configure.ac:8: -1- AC_CONFIG_MACRO_DIR_TRACE([m4]) -m4trace:configure.ac:13: -1- AH_OUTPUT([USE_SYSTEM_EXTENSIONS], [/* Enable extensions on AIX, Interix, z/OS. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif -/* Enable extensions on Cosmopolitan Libc. */ -#ifndef _COSMO_SOURCE -# undef _COSMO_SOURCE -#endif -/* Enable general extensions on macOS. */ -#ifndef _DARWIN_C_SOURCE -# undef _DARWIN_C_SOURCE -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# undef _GNU_SOURCE -#endif -/* Enable X/Open compliant socket functions that do not require linking - with -lxnet on HP-UX 11.11. */ -#ifndef _HPUX_ALT_XOPEN_SOCKET_API -# undef _HPUX_ALT_XOPEN_SOCKET_API -#endif -/* Identify the host operating system as Minix. - This macro does not affect the system headers\' behavior. - A future release of Autoconf may stop defining this macro. */ -#ifndef _MINIX -# undef _MINIX -#endif -/* Enable general extensions on NetBSD. - Enable NetBSD compatibility extensions on Minix. */ -#ifndef _NETBSD_SOURCE -# undef _NETBSD_SOURCE -#endif -/* Enable OpenBSD compatibility extensions on NetBSD. - Oddly enough, this does nothing on OpenBSD. */ -#ifndef _OPENBSD_SOURCE -# undef _OPENBSD_SOURCE -#endif -/* Define to 1 if needed for POSIX-compatible behavior. */ -#ifndef _POSIX_SOURCE -# undef _POSIX_SOURCE -#endif -/* Define to 2 if needed for POSIX-compatible behavior. */ -#ifndef _POSIX_1_SOURCE -# undef _POSIX_1_SOURCE -#endif -/* Enable POSIX-compatible threading on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# undef _POSIX_PTHREAD_SEMANTICS -#endif -/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ -#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ -# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ -#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ -# undef __STDC_WANT_IEC_60559_BFP_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ -#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ -# undef __STDC_WANT_IEC_60559_DFP_EXT__ -#endif -/* Enable extensions specified by C23 Annex F. */ -#ifndef __STDC_WANT_IEC_60559_EXT__ -# undef __STDC_WANT_IEC_60559_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ -#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ -# undef __STDC_WANT_IEC_60559_FUNCS_EXT__ -#endif -/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ -#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ -# undef __STDC_WANT_IEC_60559_TYPES_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ -#ifndef __STDC_WANT_LIB_EXT2__ -# undef __STDC_WANT_LIB_EXT2__ -#endif -/* Enable extensions specified by ISO/IEC 24747:2009. */ -#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ -# undef __STDC_WANT_MATH_SPEC_FUNCS__ -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# undef _TANDEM_SOURCE -#endif -/* Enable X/Open extensions. Define to 500 only if necessary - to make mbstate_t available. */ -#ifndef _XOPEN_SOURCE -# undef _XOPEN_SOURCE -#endif -]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STDIO_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDIO_H]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CFLAGS]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CFLAGS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CFLAGS$]) -m4trace:configure.ac:13: -1- AC_SUBST([LDFLAGS]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([LDFLAGS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^LDFLAGS$]) -m4trace:configure.ac:13: -1- AC_SUBST([LIBS]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([LIBS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:13: -1- AC_SUBST([CPPFLAGS]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CPPFLAGS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CPPFLAGS$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([ac_ct_CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([ac_ct_CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^ac_ct_CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([EXEEXT]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^EXEEXT$]) -m4trace:configure.ac:13: -1- AC_SUBST([OBJEXT], [$ac_cv_objext]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([OBJEXT]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^OBJEXT$]) -m4trace:configure.ac:13: -1- AC_REQUIRE_AUX_FILE([compile]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDLIB_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STRING_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_INTTYPES_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDINT_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STRINGS_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_STAT_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_TYPES_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^STDC_HEADERS$]) -m4trace:configure.ac:13: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if all of the C89 standard headers exist (not just the ones - required in a freestanding environment). This macro is provided for - backward compatibility; new code need not use it. */ -@%:@undef STDC_HEADERS]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_WCHAR_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_WCHAR_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_MINIX_CONFIG_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_MINIX_CONFIG_H]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_ALL_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_ALL_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_COSMO_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_COSMO_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_DARWIN_C_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_DARWIN_C_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_GNU_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_GNU_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_HPUX_ALT_XOPEN_SOCKET_API]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_HPUX_ALT_XOPEN_SOCKET_API$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_NETBSD_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_NETBSD_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_OPENBSD_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_OPENBSD_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_POSIX_PTHREAD_SEMANTICS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_PTHREAD_SEMANTICS$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_ATTRIBS_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_ATTRIBS_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_BFP_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_BFP_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_DFP_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_DFP_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_FUNCS_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_FUNCS_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_TYPES_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_TYPES_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_LIB_EXT2__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_LIB_EXT2__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_MATH_SPEC_FUNCS__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_MATH_SPEC_FUNCS__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_TANDEM_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_TANDEM_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_MINIX]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_MINIX$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_POSIX_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_POSIX_1_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_1_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__EXTENSIONS__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__EXTENSIONS__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_XOPEN_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_XOPEN_SOURCE$]) -m4trace:configure.ac:16: -1- AM_INIT_AUTOMAKE([foreign dist-xz]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_[A-Z]+FLAGS$]) -m4trace:configure.ac:16: -1- AM_AUTOMAKE_VERSION([1.18.1]) -m4trace:configure.ac:16: -1- AC_REQUIRE_AUX_FILE([install-sh]) -m4trace:configure.ac:16: -1- AC_SUBST([INSTALL_PROGRAM]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([INSTALL_PROGRAM]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_PROGRAM$]) -m4trace:configure.ac:16: -1- AC_SUBST([INSTALL_SCRIPT]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([INSTALL_SCRIPT]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_SCRIPT$]) -m4trace:configure.ac:16: -1- AC_SUBST([INSTALL_DATA]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([INSTALL_DATA]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_DATA$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__isrc], [' -I$(srcdir)']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__isrc]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__isrc$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__isrc]) -m4trace:configure.ac:16: -1- AC_SUBST([CYGPATH_W]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([CYGPATH_W]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CYGPATH_W$]) -m4trace:configure.ac:16: -1- AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([PACKAGE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^PACKAGE$]) -m4trace:configure.ac:16: -1- AC_SUBST([VERSION], ['AC_PACKAGE_VERSION']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([VERSION]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^VERSION$]) -m4trace:configure.ac:16: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^PACKAGE$]) -m4trace:configure.ac:16: -1- AH_OUTPUT([PACKAGE], [/* Name of package */ -@%:@undef PACKAGE]) -m4trace:configure.ac:16: -1- AC_DEFINE_TRACE_LITERAL([VERSION]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^VERSION$]) -m4trace:configure.ac:16: -1- AH_OUTPUT([VERSION], [/* Version number of package */ -@%:@undef VERSION]) -m4trace:configure.ac:16: -1- AC_REQUIRE_AUX_FILE([missing]) -m4trace:configure.ac:16: -1- AC_SUBST([ACLOCAL]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([ACLOCAL]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^ACLOCAL$]) -m4trace:configure.ac:16: -1- AC_SUBST([AUTOCONF]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AUTOCONF]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOCONF$]) -m4trace:configure.ac:16: -1- AC_SUBST([AUTOMAKE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AUTOMAKE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOMAKE$]) -m4trace:configure.ac:16: -1- AC_SUBST([AUTOHEADER]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AUTOHEADER]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOHEADER$]) -m4trace:configure.ac:16: -1- AC_SUBST([MAKEINFO]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([MAKEINFO]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^MAKEINFO$]) -m4trace:configure.ac:16: -1- AC_SUBST([install_sh]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([install_sh]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^install_sh$]) -m4trace:configure.ac:16: -1- AC_SUBST([STRIP]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([STRIP]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^STRIP$]) -m4trace:configure.ac:16: -1- AC_SUBST([INSTALL_STRIP_PROGRAM]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([INSTALL_STRIP_PROGRAM]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_STRIP_PROGRAM$]) -m4trace:configure.ac:16: -1- AC_REQUIRE_AUX_FILE([install-sh]) -m4trace:configure.ac:16: -1- AC_SUBST([MKDIR_P]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([MKDIR_P]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^MKDIR_P$]) -m4trace:configure.ac:16: -1- AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([mkdir_p]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^mkdir_p$]) -m4trace:configure.ac:16: -1- AC_SUBST([AWK]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AWK]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AWK$]) -m4trace:configure.ac:16: -1- AC_SUBST([SET_MAKE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([SET_MAKE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^SET_MAKE$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__leading_dot]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__leading_dot]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__leading_dot$]) -m4trace:configure.ac:16: -1- AC_SUBST([AMTAR], ['$${TAR-tar}']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AMTAR]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMTAR$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__tar]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__tar]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__tar$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__untar]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__untar]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__untar$]) -m4trace:configure.ac:16: -1- AC_SUBST([DEPDIR], ["${am__leading_dot}deps"]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([DEPDIR]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^DEPDIR$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__include]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__include]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__include$]) -m4trace:configure.ac:16: -1- AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -m4trace:configure.ac:16: -1- AC_SUBST([AMDEP_TRUE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AMDEP_TRUE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMDEP_TRUE$]) -m4trace:configure.ac:16: -1- AC_SUBST([AMDEP_FALSE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AMDEP_FALSE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMDEP_FALSE$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AMDEP_TRUE]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AMDEP_FALSE]) -m4trace:configure.ac:16: -1- AC_SUBST([AMDEPBACKSLASH]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AMDEPBACKSLASH]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMDEPBACKSLASH$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AMDEPBACKSLASH]) -m4trace:configure.ac:16: -1- AC_SUBST([am__nodep]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__nodep]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__nodep$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__nodep]) -m4trace:configure.ac:16: -1- AC_SUBST([CCDEPMODE], [depmode=$am_cv_CC_dependencies_compiler_type]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([CCDEPMODE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CCDEPMODE$]) -m4trace:configure.ac:16: -1- AM_CONDITIONAL([am__fastdepCC], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3]) -m4trace:configure.ac:16: -1- AC_SUBST([am__fastdepCC_TRUE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__fastdepCC_TRUE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__fastdepCC_TRUE$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__fastdepCC_FALSE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__fastdepCC_FALSE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__fastdepCC_FALSE$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_TRUE]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_FALSE]) -m4trace:configure.ac:16: -1- AC_SUBST([CTAGS]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([CTAGS]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CTAGS$]) -m4trace:configure.ac:16: -1- AC_SUBST([ETAGS]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([ETAGS]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^ETAGS$]) -m4trace:configure.ac:16: -1- AC_SUBST([CSCOPE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([CSCOPE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CSCOPE$]) -m4trace:configure.ac:16: -1- AC_SUBST([AM_V]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AM_V]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_V$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AM_V]) -m4trace:configure.ac:16: -1- AC_SUBST([AM_DEFAULT_V]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AM_DEFAULT_V]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_DEFAULT_V$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AM_DEFAULT_V]) -m4trace:configure.ac:16: -1- AC_SUBST([AM_DEFAULT_VERBOSITY]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AM_DEFAULT_VERBOSITY]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_DEFAULT_VERBOSITY$]) -m4trace:configure.ac:16: -1- AC_SUBST([AM_BACKSLASH]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AM_BACKSLASH]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_BACKSLASH$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AM_BACKSLASH]) -m4trace:configure.ac:16: -1- AC_SUBST([am__rm_f_notfound]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__rm_f_notfound]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__rm_f_notfound$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__xargs_n]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__xargs_n]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__xargs_n$]) -m4trace:configure.ac:19: -1- LT_INIT -m4trace:configure.ac:19: -1- m4_pattern_forbid([^_?LT_[A-Z_]+$]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$]) -m4trace:configure.ac:19: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) -m4trace:configure.ac:19: -1- AC_SUBST([LIBTOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LIBTOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LIBTOOL$]) -m4trace:configure.ac:19: -1- AC_CANONICAL_HOST -m4trace:configure.ac:19: -1- AC_CANONICAL_BUILD -m4trace:configure.ac:19: -1- AC_REQUIRE_AUX_FILE([config.sub]) -m4trace:configure.ac:19: -1- AC_REQUIRE_AUX_FILE([config.guess]) -m4trace:configure.ac:19: -1- AC_SUBST([build], [$ac_cv_build]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([build]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^build$]) -m4trace:configure.ac:19: -1- AC_SUBST([build_cpu], [$[1]]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([build_cpu]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^build_cpu$]) -m4trace:configure.ac:19: -1- AC_SUBST([build_vendor], [$[2]]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([build_vendor]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^build_vendor$]) -m4trace:configure.ac:19: -1- AC_SUBST([build_os]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([build_os]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^build_os$]) -m4trace:configure.ac:19: -1- AC_SUBST([host], [$ac_cv_host]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([host]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^host$]) -m4trace:configure.ac:19: -1- AC_SUBST([host_cpu], [$[1]]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([host_cpu]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^host_cpu$]) -m4trace:configure.ac:19: -1- AC_SUBST([host_vendor], [$[2]]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([host_vendor]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^host_vendor$]) -m4trace:configure.ac:19: -1- AC_SUBST([host_os]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([host_os]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^host_os$]) -m4trace:configure.ac:19: -1- AC_SUBST([SED]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([SED]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^SED$]) -m4trace:configure.ac:19: -1- AC_SUBST([GREP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([GREP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^GREP$]) -m4trace:configure.ac:19: -1- AC_SUBST([EGREP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([EGREP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^EGREP$]) -m4trace:configure.ac:19: -1- AC_SUBST([FGREP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([FGREP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^FGREP$]) -m4trace:configure.ac:19: -1- AC_SUBST([GREP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([GREP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^GREP$]) -m4trace:configure.ac:19: -1- AC_SUBST([LD]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LD]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LD$]) -m4trace:configure.ac:19: -1- AC_SUBST([DUMPBIN]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DUMPBIN]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DUMPBIN$]) -m4trace:configure.ac:19: -1- AC_SUBST([ac_ct_DUMPBIN]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([ac_ct_DUMPBIN]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^ac_ct_DUMPBIN$]) -m4trace:configure.ac:19: -1- AC_SUBST([DUMPBIN]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DUMPBIN]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DUMPBIN$]) -m4trace:configure.ac:19: -1- AC_SUBST([NM]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([NM]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^NM$]) -m4trace:configure.ac:19: -1- AC_SUBST([LN_S], [$as_ln_s]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LN_S]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LN_S$]) -m4trace:configure.ac:19: -1- AC_SUBST([FILECMD]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([FILECMD]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^FILECMD$]) -m4trace:configure.ac:19: -1- AC_SUBST([OBJDUMP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([OBJDUMP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^OBJDUMP$]) -m4trace:configure.ac:19: -1- AC_SUBST([OBJDUMP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([OBJDUMP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^OBJDUMP$]) -m4trace:configure.ac:19: -1- AC_SUBST([DLLTOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DLLTOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DLLTOOL$]) -m4trace:configure.ac:19: -1- AC_SUBST([DLLTOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DLLTOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DLLTOOL$]) -m4trace:configure.ac:19: -1- AC_SUBST([AR]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([AR]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^AR$]) -m4trace:configure.ac:19: -1- AC_SUBST([ac_ct_AR]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([ac_ct_AR]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^ac_ct_AR$]) -m4trace:configure.ac:19: -1- AC_SUBST([STRIP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([STRIP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^STRIP$]) -m4trace:configure.ac:19: -1- AC_SUBST([RANLIB]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([RANLIB]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^RANLIB$]) -m4trace:configure.ac:19: -1- m4_pattern_allow([LT_OBJDIR]) -m4trace:configure.ac:19: -1- AC_DEFINE_TRACE_LITERAL([LT_OBJDIR]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LT_OBJDIR$]) -m4trace:configure.ac:19: -1- AH_OUTPUT([LT_OBJDIR], [/* Define to the sub-directory where libtool stores uninstalled libraries. */ -@%:@undef LT_OBJDIR]) -m4trace:configure.ac:19: -1- LT_SUPPORTED_TAG([CC]) -m4trace:configure.ac:19: -1- AC_SUBST([MANIFEST_TOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([MANIFEST_TOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^MANIFEST_TOOL$]) -m4trace:configure.ac:19: -1- AC_SUBST([DSYMUTIL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DSYMUTIL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DSYMUTIL$]) -m4trace:configure.ac:19: -1- AC_SUBST([NMEDIT]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([NMEDIT]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^NMEDIT$]) -m4trace:configure.ac:19: -1- AC_SUBST([LIPO]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LIPO]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LIPO$]) -m4trace:configure.ac:19: -1- AC_SUBST([OTOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([OTOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^OTOOL$]) -m4trace:configure.ac:19: -1- AC_SUBST([OTOOL64]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([OTOOL64]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^OTOOL64$]) -m4trace:configure.ac:19: -1- AC_SUBST([LT_SYS_LIBRARY_PATH]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LT_SYS_LIBRARY_PATH]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LT_SYS_LIBRARY_PATH$]) -m4trace:configure.ac:19: -1- AH_OUTPUT([HAVE_DLFCN_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_DLFCN_H]) -m4trace:configure.ac:19: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DLFCN_H]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^HAVE_DLFCN_H$]) -m4trace:configure.ac:25: -1- AC_SUBST([BASE_CFLAGS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([BASE_CFLAGS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^BASE_CFLAGS$]) -m4trace:configure.ac:25: -1- AC_SUBST([CWARNFLAGS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([CWARNFLAGS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^CWARNFLAGS$]) -m4trace:configure.ac:25: -1- AC_SUBST([STRICT_CFLAGS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([STRICT_CFLAGS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^STRICT_CFLAGS$]) -m4trace:configure.ac:25: -1- AC_SUBST([BASE_CFLAGS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([BASE_CFLAGS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^BASE_CFLAGS$]) -m4trace:configure.ac:25: -2- AC_SUBST([CWARNFLAGS]) -m4trace:configure.ac:25: -2- AC_SUBST_TRACE([CWARNFLAGS]) -m4trace:configure.ac:25: -2- m4_pattern_allow([^CWARNFLAGS$]) -m4trace:configure.ac:25: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION_MAJOR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PACKAGE_VERSION_MAJOR$]) -m4trace:configure.ac:25: -1- AH_OUTPUT([PACKAGE_VERSION_MAJOR], [/* Major version of this package */ -@%:@undef PACKAGE_VERSION_MAJOR]) -m4trace:configure.ac:25: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION_MINOR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PACKAGE_VERSION_MINOR$]) -m4trace:configure.ac:25: -1- AH_OUTPUT([PACKAGE_VERSION_MINOR], [/* Minor version of this package */ -@%:@undef PACKAGE_VERSION_MINOR]) -m4trace:configure.ac:25: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION_PATCHLEVEL]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PACKAGE_VERSION_PATCHLEVEL$]) -m4trace:configure.ac:25: -1- AH_OUTPUT([PACKAGE_VERSION_PATCHLEVEL], [/* Patch version of this package */ -@%:@undef PACKAGE_VERSION_PATCHLEVEL]) -m4trace:configure.ac:25: -1- AC_SUBST([CHANGELOG_CMD]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([CHANGELOG_CMD]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^CHANGELOG_CMD$]) -m4trace:configure.ac:25: -1- m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) -m4trace:configure.ac:25: -1- AC_SUBST([PKG_CONFIG]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([PKG_CONFIG]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG$]) -m4trace:configure.ac:25: -1- AC_SUBST([PKG_CONFIG_PATH]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([PKG_CONFIG_PATH]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG_PATH$]) -m4trace:configure.ac:25: -1- AC_SUBST([PKG_CONFIG_LIBDIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([PKG_CONFIG_LIBDIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG_LIBDIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([PKG_CONFIG]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([PKG_CONFIG]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG$]) -m4trace:configure.ac:25: -1- AC_SUBST([INSTALL_CMD]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([INSTALL_CMD]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^INSTALL_CMD$]) -m4trace:configure.ac:25: -1- _m4_warn([cross], [cannot check for file existence when cross compiling], [./lib/autoconf/general.m4:3066: AC_CHECK_FILE is expanded from... -aclocal.m4:479: XORG_MANPAGE_SECTIONS is expanded from... -aclocal.m4:2188: XORG_DEFAULT_NOCODE_OPTIONS is expanded from... -aclocal.m4:2204: XORG_DEFAULT_OPTIONS is expanded from... -configure.ac:25: the top level]) -m4trace:configure.ac:25: -1- AC_SUBST([APP_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([APP_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^APP_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([LIB_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([LIB_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^LIB_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([FILE_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([FILE_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^FILE_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([MISC_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([MISC_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^MISC_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([DRIVER_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([DRIVER_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^DRIVER_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([ADMIN_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([ADMIN_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^ADMIN_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([APP_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([APP_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^APP_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([LIB_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([LIB_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^LIB_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([FILE_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([FILE_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^FILE_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([MISC_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([MISC_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^MISC_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([DRIVER_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([DRIVER_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^DRIVER_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([ADMIN_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([ADMIN_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^ADMIN_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([XORG_MAN_PAGE]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([XORG_MAN_PAGE]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^XORG_MAN_PAGE$]) -m4trace:configure.ac:25: -1- AC_SUBST([MAN_SUBSTS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([MAN_SUBSTS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^MAN_SUBSTS$]) -m4trace:configure.ac:25: -1- AM_SILENT_RULES([yes]) -m4trace:configure.ac:26: -1- AM_CONDITIONAL([ENABLE_SPECS], [test x$build_specs = xyes]) -m4trace:configure.ac:26: -1- AC_SUBST([ENABLE_SPECS_TRUE]) -m4trace:configure.ac:26: -1- AC_SUBST_TRACE([ENABLE_SPECS_TRUE]) -m4trace:configure.ac:26: -1- m4_pattern_allow([^ENABLE_SPECS_TRUE$]) -m4trace:configure.ac:26: -1- AC_SUBST([ENABLE_SPECS_FALSE]) -m4trace:configure.ac:26: -1- AC_SUBST_TRACE([ENABLE_SPECS_FALSE]) -m4trace:configure.ac:26: -1- m4_pattern_allow([^ENABLE_SPECS_FALSE$]) -m4trace:configure.ac:26: -1- _AM_SUBST_NOTMAKE([ENABLE_SPECS_TRUE]) -m4trace:configure.ac:26: -1- _AM_SUBST_NOTMAKE([ENABLE_SPECS_FALSE]) -m4trace:configure.ac:27: -1- AC_SUBST([XMLTO]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([XMLTO]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^XMLTO$]) -m4trace:configure.ac:27: -1- AC_SUBST([XMLTO]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([XMLTO]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^XMLTO$]) -m4trace:configure.ac:27: -1- AC_SUBST([XMLTO]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([XMLTO]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^XMLTO$]) -m4trace:configure.ac:27: -1- AM_CONDITIONAL([HAVE_XMLTO_TEXT], [test $have_xmlto_text = yes]) -m4trace:configure.ac:27: -1- AC_SUBST([HAVE_XMLTO_TEXT_TRUE]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([HAVE_XMLTO_TEXT_TRUE]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^HAVE_XMLTO_TEXT_TRUE$]) -m4trace:configure.ac:27: -1- AC_SUBST([HAVE_XMLTO_TEXT_FALSE]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([HAVE_XMLTO_TEXT_FALSE]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^HAVE_XMLTO_TEXT_FALSE$]) -m4trace:configure.ac:27: -1- _AM_SUBST_NOTMAKE([HAVE_XMLTO_TEXT_TRUE]) -m4trace:configure.ac:27: -1- _AM_SUBST_NOTMAKE([HAVE_XMLTO_TEXT_FALSE]) -m4trace:configure.ac:27: -1- AM_CONDITIONAL([HAVE_XMLTO], [test "$have_xmlto" = yes]) -m4trace:configure.ac:27: -1- AC_SUBST([HAVE_XMLTO_TRUE]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([HAVE_XMLTO_TRUE]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^HAVE_XMLTO_TRUE$]) -m4trace:configure.ac:27: -1- AC_SUBST([HAVE_XMLTO_FALSE]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([HAVE_XMLTO_FALSE]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^HAVE_XMLTO_FALSE$]) -m4trace:configure.ac:27: -1- _AM_SUBST_NOTMAKE([HAVE_XMLTO_TRUE]) -m4trace:configure.ac:27: -1- _AM_SUBST_NOTMAKE([HAVE_XMLTO_FALSE]) -m4trace:configure.ac:28: -1- AC_SUBST([FOP]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([FOP]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^FOP$]) -m4trace:configure.ac:28: -1- AC_SUBST([FOP]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([FOP]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^FOP$]) -m4trace:configure.ac:28: -1- AC_SUBST([FOP]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([FOP]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^FOP$]) -m4trace:configure.ac:28: -1- AM_CONDITIONAL([HAVE_FOP], [test "$have_fop" = yes]) -m4trace:configure.ac:28: -1- AC_SUBST([HAVE_FOP_TRUE]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([HAVE_FOP_TRUE]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_FOP_TRUE$]) -m4trace:configure.ac:28: -1- AC_SUBST([HAVE_FOP_FALSE]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([HAVE_FOP_FALSE]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_FOP_FALSE$]) -m4trace:configure.ac:28: -1- _AM_SUBST_NOTMAKE([HAVE_FOP_TRUE]) -m4trace:configure.ac:28: -1- _AM_SUBST_NOTMAKE([HAVE_FOP_FALSE]) -m4trace:configure.ac:29: -1- AC_SUBST([XSLTPROC]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([XSLTPROC]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^XSLTPROC$]) -m4trace:configure.ac:29: -1- AC_SUBST([XSLTPROC]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([XSLTPROC]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^XSLTPROC$]) -m4trace:configure.ac:29: -1- AC_SUBST([XSLTPROC]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([XSLTPROC]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^XSLTPROC$]) -m4trace:configure.ac:29: -1- AM_CONDITIONAL([HAVE_XSLTPROC], [test "$have_xsltproc" = yes]) -m4trace:configure.ac:29: -1- AC_SUBST([HAVE_XSLTPROC_TRUE]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([HAVE_XSLTPROC_TRUE]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^HAVE_XSLTPROC_TRUE$]) -m4trace:configure.ac:29: -1- AC_SUBST([HAVE_XSLTPROC_FALSE]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([HAVE_XSLTPROC_FALSE]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^HAVE_XSLTPROC_FALSE$]) -m4trace:configure.ac:29: -1- _AM_SUBST_NOTMAKE([HAVE_XSLTPROC_TRUE]) -m4trace:configure.ac:29: -1- _AM_SUBST_NOTMAKE([HAVE_XSLTPROC_FALSE]) -m4trace:configure.ac:30: -1- AC_SUBST([XORG_SGML_PATH]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([XORG_SGML_PATH]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^XORG_SGML_PATH$]) -m4trace:configure.ac:30: -1- AC_SUBST([STYLESHEET_SRCDIR]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([STYLESHEET_SRCDIR]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^STYLESHEET_SRCDIR$]) -m4trace:configure.ac:30: -1- AC_SUBST([XSL_STYLESHEET]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([XSL_STYLESHEET]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^XSL_STYLESHEET$]) -m4trace:configure.ac:30: -1- AM_CONDITIONAL([HAVE_STYLESHEETS], [test "x$XSL_STYLESHEET" != "x"]) -m4trace:configure.ac:30: -1- AC_SUBST([HAVE_STYLESHEETS_TRUE]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([HAVE_STYLESHEETS_TRUE]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^HAVE_STYLESHEETS_TRUE$]) -m4trace:configure.ac:30: -1- AC_SUBST([HAVE_STYLESHEETS_FALSE]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([HAVE_STYLESHEETS_FALSE]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^HAVE_STYLESHEETS_FALSE$]) -m4trace:configure.ac:30: -1- _AM_SUBST_NOTMAKE([HAVE_STYLESHEETS_TRUE]) -m4trace:configure.ac:30: -1- _AM_SUBST_NOTMAKE([HAVE_STYLESHEETS_FALSE]) -m4trace:configure.ac:31: -1- AC_SUBST([MALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- AC_SUBST_TRACE([MALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^MALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:31: -1- AC_SUBST([XMALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- AC_SUBST_TRACE([XMALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^XMALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:31: -1- AC_SUBST([XTMALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- AC_SUBST_TRACE([XTMALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^XTMALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:42: -1- AC_SUBST([XEXT_SOREV]) -m4trace:configure.ac:42: -1- AC_SUBST_TRACE([XEXT_SOREV]) -m4trace:configure.ac:42: -1- m4_pattern_allow([^XEXT_SOREV$]) -m4trace:configure.ac:45: -1- AC_SUBST([XEXT_CFLAGS]) -m4trace:configure.ac:45: -1- AC_SUBST_TRACE([XEXT_CFLAGS]) -m4trace:configure.ac:45: -1- m4_pattern_allow([^XEXT_CFLAGS$]) -m4trace:configure.ac:45: -1- AC_SUBST([XEXT_LIBS]) -m4trace:configure.ac:45: -1- AC_SUBST_TRACE([XEXT_LIBS]) -m4trace:configure.ac:45: -1- m4_pattern_allow([^XEXT_LIBS$]) -m4trace:configure.ac:47: -1- AC_DEFINE_TRACE_LITERAL([HAVE___BUILTIN_POPCOUNTL]) -m4trace:configure.ac:47: -1- m4_pattern_allow([^HAVE___BUILTIN_POPCOUNTL$]) -m4trace:configure.ac:47: -1- AH_OUTPUT([HAVE___BUILTIN_POPCOUNTL], [/* Define to 1 if the system has the `__builtin_popcountl\' built-in function - */ -@%:@undef HAVE___BUILTIN_POPCOUNTL]) -m4trace:configure.ac:48: -1- AH_OUTPUT([HAVE_REALLOCARRAY], [/* Define to 1 if you have the \'reallocarray\' function. */ -@%:@undef HAVE_REALLOCARRAY]) -m4trace:configure.ac:48: -1- AC_LIBSOURCE([reallocarray.c]) -m4trace:configure.ac:48: -1- AC_DEFINE_TRACE_LITERAL([HAVE_REALLOCARRAY]) -m4trace:configure.ac:48: -1- m4_pattern_allow([^HAVE_REALLOCARRAY$]) -m4trace:configure.ac:48: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS reallocarray.$ac_objext"]) -m4trace:configure.ac:48: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:48: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT_FLAGS]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT_FLAGS]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FLAGS$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT_FLAGS], [$lint_options]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT_FLAGS]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FLAGS$]) -m4trace:configure.ac:51: -1- AM_CONDITIONAL([LINT], [test "x$LINT" != x]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT_TRUE]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT_TRUE]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_TRUE$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT_FALSE]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT_FALSE]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FALSE$]) -m4trace:configure.ac:51: -1- _AM_SUBST_NOTMAKE([LINT_TRUE]) -m4trace:configure.ac:51: -1- _AM_SUBST_NOTMAKE([LINT_FALSE]) -m4trace:configure.ac:52: -1- AC_SUBST([LINTLIB]) -m4trace:configure.ac:52: -1- AC_SUBST_TRACE([LINTLIB]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^LINTLIB$]) -m4trace:configure.ac:52: -1- AM_CONDITIONAL([MAKE_LINT_LIB], [test x$make_lint_lib != xno]) -m4trace:configure.ac:52: -1- AC_SUBST([MAKE_LINT_LIB_TRUE]) -m4trace:configure.ac:52: -1- AC_SUBST_TRACE([MAKE_LINT_LIB_TRUE]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^MAKE_LINT_LIB_TRUE$]) -m4trace:configure.ac:52: -1- AC_SUBST([MAKE_LINT_LIB_FALSE]) -m4trace:configure.ac:52: -1- AC_SUBST_TRACE([MAKE_LINT_LIB_FALSE]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^MAKE_LINT_LIB_FALSE$]) -m4trace:configure.ac:52: -1- _AM_SUBST_NOTMAKE([MAKE_LINT_LIB_TRUE]) -m4trace:configure.ac:52: -1- _AM_SUBST_NOTMAKE([MAKE_LINT_LIB_FALSE]) -m4trace:configure.ac:54: -1- AC_CONFIG_FILES([Makefile - man/Makefile - src/Makefile - specs/Makefile - xext.pc]) -m4trace:configure.ac:59: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:59: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([LTLIBOBJS]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:59: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:59: -1- AC_SUBST([am__EXEEXT_TRUE]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:59: -1- AC_SUBST([am__EXEEXT_FALSE]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:59: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:59: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([top_builddir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([top_build_prefix]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([srcdir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([abs_srcdir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([top_srcdir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([abs_top_srcdir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([builddir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([abs_builddir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([abs_top_builddir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([INSTALL]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([MKDIR_P]) -m4trace:configure.ac:59: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) diff --git a/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.2 b/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.2 deleted file mode 100644 index f79f144b3..000000000 --- a/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.2 +++ /dev/null @@ -1,4561 +0,0 @@ -m4trace:/usr/share/aclocal/pkg.m4:58: -1- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) -m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) -AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) -AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) -AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=m4_default([$1], [0.9.0]) - AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - PKG_CONFIG="" - fi -fi[]dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:92: -1- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -if test -n "$PKG_CONFIG" && \ - AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then - m4_default([$2], [:]) -m4_ifvaln([$3], [else - $3])dnl -fi]) -m4trace:/usr/share/aclocal/pkg.m4:121: -1- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi[]dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:139: -1- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl -AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl - -pkg_failed=no -AC_MSG_CHECKING([for $2]) - -_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) -_PKG_CONFIG([$1][_LIBS], [libs], [$2]) - -m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS -and $1[]_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details.]) - -if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) - _PKG_SHORT_ERRORS_SUPPORTED - if test $_pkg_short_errors_supported = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else - $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD - - m4_default([$4], [AC_MSG_ERROR( -[Package requirements ($2) were not met: - -$$1_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -_PKG_TEXT])[]dnl - ]) -elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) - m4_default([$4], [AC_MSG_FAILURE( -[The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -_PKG_TEXT - -To get pkg-config, see .])[]dnl - ]) -else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS - AC_MSG_RESULT([yes]) - $3 -fi[]dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:208: -1- AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -_save_PKG_CONFIG=$PKG_CONFIG -PKG_CONFIG="$PKG_CONFIG --static" -PKG_CHECK_MODULES($@) -PKG_CONFIG=$_save_PKG_CONFIG[]dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:226: -1- AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([pkgconfigdir], - [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, - [with_pkgconfigdir=]pkg_default) -AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) -m4trace:/usr/share/aclocal/pkg.m4:248: -1- AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([noarch-pkgconfigdir], - [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, - [with_noarch_pkgconfigdir=]pkg_default) -AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) -m4trace:/usr/share/aclocal/pkg.m4:267: -1- AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl - -_PKG_CONFIG([$1], [variable="][$3]["], [$2]) -AS_VAR_COPY([$1], [pkg_cv_][$1]) - -AS_VAR_IF([$1], [""], [$5], [$4])dnl -]) -m4trace:/usr/share/aclocal/pkg.m4:285: -1- AC_DEFUN([PKG_WITH_MODULES], [ -m4_pushdef([with_arg], m4_tolower([$1])) - -m4_pushdef([description], - [m4_default([$5], [build with ]with_arg[ support])]) - -m4_pushdef([def_arg], [m4_default([$6], [auto])]) -m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) -m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) - -m4_case(def_arg, - [yes],[m4_pushdef([with_without], [--without-]with_arg)], - [m4_pushdef([with_without],[--with-]with_arg)]) - -AC_ARG_WITH(with_arg, - AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, - [AS_TR_SH([with_]with_arg)=def_arg]) - -AS_CASE([$AS_TR_SH([with_]with_arg)], - [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], - [auto],[PKG_CHECK_MODULES([$1],[$2], - [m4_n([def_action_if_found]) $3], - [m4_n([def_action_if_not_found]) $4])]) - -m4_popdef([with_arg]) -m4_popdef([description]) -m4_popdef([def_arg]) - -]) -m4trace:/usr/share/aclocal/pkg.m4:322: -1- AC_DEFUN([PKG_HAVE_WITH_MODULES], [ -PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) - -AM_CONDITIONAL([HAVE_][$1], - [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) -]) -m4trace:/usr/share/aclocal/pkg.m4:337: -1- AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ -PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) - -AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], - [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltargz.m4:13: -1- AC_DEFUN([LT_FUNC_ARGZ], [ -dnl Required for use of '$SED' in Cygwin configuration. -AC_REQUIRE([AC_PROG_SED])dnl -AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT]) - -AC_CHECK_TYPES([error_t], - [], - [AC_DEFINE([error_t], [int], - [Define to a type to use for 'error_t' if it is not otherwise available.]) - AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h - does not typedef error_t.])], - [#if defined(HAVE_ARGZ_H) -# include -#endif]) - -LT_ARGZ_H= -AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ - argz_next argz_stringify], [], [LT_ARGZ_H=lt__argz.h; AC_LIBOBJ([lt__argz])]) - -dnl if have system argz functions, allow forced use of -dnl libltdl-supplied implementation (and default to do so -dnl on "known bad" systems). Could use a runtime check, but -dnl (a) detecting malloc issues is notoriously unreliable -dnl (b) only known system that declares argz functions, -dnl provides them, yet they are broken, is cygwin -dnl releases prior to 16-Mar-2007 (1.5.24 and earlier) -dnl So, it's more straightforward simply to special case -dnl this for known bad systems. -AS_IF([test -z "$LT_ARGZ_H"], - [AC_CACHE_CHECK( - [if argz actually works], - [lt_cv_sys_argz_works], - [[case $host_os in #( - *cygwin*) - lt_cv_sys_argz_works=no - if test no != "$cross_compiling"; then - lt_cv_sys_argz_works="guessing no" - else - lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' - save_IFS=$IFS - IFS=-. - set x `uname -r | $SED -e "$lt_sed_extract_leading_digits"` - IFS=$save_IFS - lt_os_major=${2-0} - lt_os_minor=${3-0} - lt_os_micro=${4-0} - if test 1 -lt "$lt_os_major" \ - || { test 1 -eq "$lt_os_major" \ - && { test 5 -lt "$lt_os_minor" \ - || { test 5 -eq "$lt_os_minor" \ - && test 24 -lt "$lt_os_micro"; }; }; }; then - lt_cv_sys_argz_works=yes - fi - fi - ;; #( - *) lt_cv_sys_argz_works=yes ;; - esac]]) - AS_IF([test yes = "$lt_cv_sys_argz_works"], - [AC_DEFINE([HAVE_WORKING_ARGZ], 1, - [This value is set to 1 to indicate that the system argz facility works])], - [LT_ARGZ_H=lt__argz.h - AC_LIBOBJ([lt__argz])])]) - -AC_SUBST([LT_ARGZ_H]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:17: -1- AC_DEFUN([LT_CONFIG_LTDL_DIR], [AC_BEFORE([$0], [LTDL_INIT]) -_$0($*) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:69: -1- AC_DEFUN([LTDL_CONVENIENCE], [AC_BEFORE([$0], [LTDL_INIT])dnl -dnl Although the argument is deprecated and no longer documented, -dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one -dnl here make sure it is the same as any other declaration of libltdl's -dnl location! This also ensures lt_ltdl_dir is set when configure.ac is -dnl not yet using an explicit LT_CONFIG_LTDL_DIR. -m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl -_$0() -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:82: -1- AU_DEFUN([AC_LIBLTDL_CONVENIENCE], [_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_CONVENIENCE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:82: -1- AC_DEFUN([AC_LIBLTDL_CONVENIENCE], [m4_warn([obsolete], [The macro 'AC_LIBLTDL_CONVENIENCE' is obsolete. -You should run autoupdate.])dnl -_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_CONVENIENCE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:125: -1- AC_DEFUN([LTDL_INSTALLABLE], [AC_BEFORE([$0], [LTDL_INIT])dnl -dnl Although the argument is deprecated and no longer documented, -dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one -dnl here make sure it is the same as any other declaration of libltdl's -dnl location! This also ensures lt_ltdl_dir is set when configure.ac is -dnl not yet using an explicit LT_CONFIG_LTDL_DIR. -m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl -_$0() -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:138: -1- AU_DEFUN([AC_LIBLTDL_INSTALLABLE], [_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_INSTALLABLE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:138: -1- AC_DEFUN([AC_LIBLTDL_INSTALLABLE], [m4_warn([obsolete], [The macro 'AC_LIBLTDL_INSTALLABLE' is obsolete. -You should run autoupdate.])dnl -_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_INSTALLABLE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:214: -1- AC_DEFUN([_LT_LIBOBJ], [ - m4_pattern_allow([^_LT_LIBOBJS$]) - _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:227: -1- AC_DEFUN([LTDL_INIT], [dnl Parse OPTIONS -_LT_SET_OPTIONS([$0], [$1]) - -dnl We need to keep our own list of libobjs separate from our parent project, -dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while -dnl we look for our own LIBOBJs. -m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) -m4_pushdef([AC_LIBSOURCES]) - -dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: -m4_if(_LTDL_MODE, [], - [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) - m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], - [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) - -AC_ARG_WITH([included_ltdl], - [AS_HELP_STRING([--with-included-ltdl], - [use the GNU ltdl sources included here])]) - -if test yes != "$with_included_ltdl"; then - # We are not being forced to use the included libltdl sources, so - # decide whether there is a useful installed version we can use. - AC_CHECK_HEADER([ltdl.h], - [AC_CHECK_DECL([lt_dlinterface_register], - [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], - [with_included_ltdl=no], - [with_included_ltdl=yes])], - [with_included_ltdl=yes], - [AC_INCLUDES_DEFAULT - #include ])], - [with_included_ltdl=yes], - [AC_INCLUDES_DEFAULT] - ) -fi - -dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE -dnl was called yet, then for old times' sake, we assume libltdl is in an -dnl eponymous directory: -AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) - -AC_ARG_WITH([ltdl_include], - [AS_HELP_STRING([--with-ltdl-include=DIR], - [use the ltdl headers installed in DIR])]) - -if test -n "$with_ltdl_include"; then - if test -f "$with_ltdl_include/ltdl.h"; then : - else - AC_MSG_ERROR([invalid ltdl include directory: '$with_ltdl_include']) - fi -else - with_ltdl_include=no -fi - -AC_ARG_WITH([ltdl_lib], - [AS_HELP_STRING([--with-ltdl-lib=DIR], - [use the libltdl.la installed in DIR])]) - -if test -n "$with_ltdl_lib"; then - if test -f "$with_ltdl_lib/libltdl.la"; then : - else - AC_MSG_ERROR([invalid ltdl library directory: '$with_ltdl_lib']) - fi -else - with_ltdl_lib=no -fi - -case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in - ,yes,no,no,) - m4_case(m4_default(_LTDL_TYPE, [convenience]), - [convenience], [_LTDL_CONVENIENCE], - [installable], [_LTDL_INSTALLABLE], - [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) - ;; - ,no,no,no,) - # If the included ltdl is not to be used, then use the - # preinstalled libltdl we found. - AC_DEFINE([HAVE_LTDL], [1], - [Define this if a modern libltdl is already installed]) - LIBLTDL=-lltdl - LTDLDEPS= - LTDLINCL= - ;; - ,no*,no,*) - AC_MSG_ERROR(['--with-ltdl-include' and '--with-ltdl-lib' options must be used together]) - ;; - *) with_included_ltdl=no - LIBLTDL="-L$with_ltdl_lib -lltdl" - LTDLDEPS= - LTDLINCL=-I$with_ltdl_include - ;; -esac -INCLTDL=$LTDLINCL - -# Report our decision... -AC_MSG_CHECKING([where to find libltdl headers]) -AC_MSG_RESULT([$LTDLINCL]) -AC_MSG_CHECKING([where to find libltdl library]) -AC_MSG_RESULT([$LIBLTDL]) - -_LTDL_SETUP - -dnl restore autoconf definition. -m4_popdef([AC_LIBOBJ]) -m4_popdef([AC_LIBSOURCES]) - -AC_CONFIG_COMMANDS_PRE([ - _ltdl_libobjs= - _ltdl_ltlibobjs= - if test -n "$_LT_LIBOBJS"; then - # Remove the extension. - _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' - for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | $SED "$_lt_sed_drop_objext" | sort -u`; do - _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" - _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" - done - fi - AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) - AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) -]) - -# Only expand once: -m4_define([LTDL_INIT]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:353: -1- AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:353: -1- AC_DEFUN([AC_LIB_LTDL], [m4_warn([obsolete], [The macro 'AC_LIB_LTDL' is obsolete. -You should run autoupdate.])dnl -LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:354: -1- AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:354: -1- AC_DEFUN([AC_WITH_LTDL], [m4_warn([obsolete], [The macro 'AC_WITH_LTDL' is obsolete. -You should run autoupdate.])dnl -LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:355: -1- AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:355: -1- AC_DEFUN([LT_WITH_LTDL], [m4_warn([obsolete], [The macro 'LT_WITH_LTDL' is obsolete. -You should run autoupdate.])dnl -LTDL_INIT($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:368: -1- AC_DEFUN([_LTDL_SETUP], [AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([LT_SYS_MODULE_EXT])dnl -AC_REQUIRE([LT_SYS_MODULE_PATH])dnl -AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl -AC_REQUIRE([LT_LIB_DLLOAD])dnl -AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl -AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl -AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl -AC_REQUIRE([LT_FUNC_ARGZ])dnl - -m4_require([_LT_CHECK_OBJDIR])dnl -m4_require([_LT_HEADER_DLFCN])dnl -m4_require([_LT_CHECK_DLPREOPEN])dnl -m4_require([_LT_DECL_SED])dnl - -dnl Don't require this, or it will be expanded earlier than the code -dnl that sets the variables it relies on: -_LT_ENABLE_INSTALL - -dnl _LTDL_MODE specific code must be called at least once: -_LTDL_MODE_DISPATCH - -# In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS -# the user used. This is so that ltdl.h can pick up the parent projects -# config.h file, The first file in AC_CONFIG_HEADERS must contain the -# definitions required by ltdl.c. -# FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). -AC_CONFIG_COMMANDS_PRE([dnl -m4_pattern_allow([^LT_CONFIG_H$])dnl -m4_ifset([AH_HEADER], - [LT_CONFIG_H=AH_HEADER], - [m4_ifset([AC_LIST_HEADERS], - [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's|^[[ ]]*||;s|[[ :]].*$||'`], - [])])]) -AC_SUBST([LT_CONFIG_H]) - -AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], - [], [], [AC_INCLUDES_DEFAULT]) - -AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) -AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) - -m4_pattern_allow([LT_LIBEXT])dnl -AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) - -name= -eval "lt_libprefix=\"$libname_spec\"" -m4_pattern_allow([LT_LIBPREFIX])dnl -AC_DEFINE_UNQUOTED([LT_LIBPREFIX],["$lt_libprefix"],[The archive prefix]) - -name=ltdl -eval "LTDLOPEN=\"$libname_spec\"" -AC_SUBST([LTDLOPEN]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:445: -1- AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_CACHE_CHECK([whether deplibs are loaded by dlopen], - [lt_cv_sys_dlopen_deplibs], - [# PORTME does your system automatically load deplibs for dlopen? - # or its logical equivalent (e.g. shl_load for HP-UX < 11) - # For now, we just catch OSes we know something about -- in the - # future, we'll try test this programmatically. - lt_cv_sys_dlopen_deplibs=unknown - case $host_os in - aix3*|aix4.1.*|aix4.2.*) - # Unknown whether this is true for these versions of AIX, but - # we want this 'case' here to explicitly catch those versions. - lt_cv_sys_dlopen_deplibs=unknown - ;; - aix[[4-9]]*) - lt_cv_sys_dlopen_deplibs=yes - ;; - amigaos*) - case $host_cpu in - powerpc) - lt_cv_sys_dlopen_deplibs=no - ;; - esac - ;; - darwin*) - # Assuming the user has installed a libdl from somewhere, this is true - # If you are looking for one http://www.opendarwin.org/projects/dlcompat - lt_cv_sys_dlopen_deplibs=yes - ;; - freebsd* | dragonfly* | midnightbsd*) - lt_cv_sys_dlopen_deplibs=yes - ;; - gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) - # GNU and its variants, using gnu ld.so (Glibc) - lt_cv_sys_dlopen_deplibs=yes - ;; - hpux10*|hpux11*) - lt_cv_sys_dlopen_deplibs=yes - ;; - interix*) - lt_cv_sys_dlopen_deplibs=yes - ;; - irix[[12345]]*|irix6.[[01]]*) - # Catch all versions of IRIX before 6.2, and indicate that we don't - # know how it worked for any of those versions. - lt_cv_sys_dlopen_deplibs=unknown - ;; - irix*) - # The case above catches anything before 6.2, and it's known that - # at 6.2 and later dlopen does load deplibs. - lt_cv_sys_dlopen_deplibs=yes - ;; - *-mlibc) - lt_cv_sys_dlopen_deplibs=yes - ;; - netbsd* | netbsdelf*-gnu) - lt_cv_sys_dlopen_deplibs=yes - ;; - openbsd*) - lt_cv_sys_dlopen_deplibs=yes - ;; - osf[[1234]]*) - # dlopen did load deplibs (at least at 4.x), but until the 5.x series, - # it did *not* use an RPATH in a shared library to find objects the - # library depends on, so we explicitly say 'no'. - lt_cv_sys_dlopen_deplibs=no - ;; - osf5.0|osf5.0a|osf5.1) - # dlopen *does* load deplibs and with the right loader patch applied - # it even uses RPATH in a shared library to search for shared objects - # that the library depends on, but there's no easy way to know if that - # patch is installed. Since this is the case, all we can really - # say is unknown -- it depends on the patch being installed. If - # it is, this changes to 'yes'. Without it, it would be 'no'. - lt_cv_sys_dlopen_deplibs=unknown - ;; - osf*) - # the two cases above should catch all versions of osf <= 5.1. Read - # the comments above for what we know about them. - # At > 5.1, deplibs are loaded *and* any RPATH in a shared library - # is used to find them so we can finally say 'yes'. - lt_cv_sys_dlopen_deplibs=yes - ;; - qnx*) - lt_cv_sys_dlopen_deplibs=yes - ;; - solaris*) - lt_cv_sys_dlopen_deplibs=yes - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - esac - ]) -if test yes != "$lt_cv_sys_dlopen_deplibs"; then - AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], - [Define if the OS needs help to load dependent libraries for dlopen().]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:547: -1- AU_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], [m4_if($#, 0, [LT_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:547: -1- AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], [m4_warn([obsolete], [The macro 'AC_LTDL_SYS_DLOPEN_DEPLIBS' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:554: -1- AC_DEFUN([LT_SYS_MODULE_EXT], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([what extension is used for runtime loadable modules], - [libltdl_cv_shlibext], -[ -module=yes -eval libltdl_cv_shlibext=$shrext_cmds -module=no -eval libltdl_cv_shrext=$shrext_cmds - ]) -if test -n "$libltdl_cv_shlibext"; then - m4_pattern_allow([LT_MODULE_EXT])dnl - AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], - [Define to the extension used for runtime loadable modules, say, ".so".]) -fi -if test "$libltdl_cv_shrext" != "$libltdl_cv_shlibext"; then - m4_pattern_allow([LT_SHARED_EXT])dnl - AC_DEFINE_UNQUOTED([LT_SHARED_EXT], ["$libltdl_cv_shrext"], - [Define to the shared library suffix, say, ".dylib".]) -fi -if test -n "$shared_archive_member_spec"; then - m4_pattern_allow([LT_SHARED_LIB_MEMBER])dnl - AC_DEFINE_UNQUOTED([LT_SHARED_LIB_MEMBER], ["($shared_archive_member_spec.o)"], - [Define to the shared archive member specification, say "(shr.o)".]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:582: -1- AU_DEFUN([AC_LTDL_SHLIBEXT], [m4_if($#, 0, [LT_SYS_MODULE_EXT], [LT_SYS_MODULE_EXT($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:582: -1- AC_DEFUN([AC_LTDL_SHLIBEXT], [m4_warn([obsolete], [The macro 'AC_LTDL_SHLIBEXT' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_MODULE_EXT], [LT_SYS_MODULE_EXT($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:589: -1- AC_DEFUN([LT_SYS_MODULE_PATH], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([what variable specifies run-time module search path], - [lt_cv_module_path_var], [lt_cv_module_path_var=$shlibpath_var]) -if test -n "$lt_cv_module_path_var"; then - m4_pattern_allow([LT_MODULE_PATH_VAR])dnl - AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], - [Define to the name of the environment variable that determines the run-time module search path.]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:601: -1- AU_DEFUN([AC_LTDL_SHLIBPATH], [m4_if($#, 0, [LT_SYS_MODULE_PATH], [LT_SYS_MODULE_PATH($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:601: -1- AC_DEFUN([AC_LTDL_SHLIBPATH], [m4_warn([obsolete], [The macro 'AC_LTDL_SHLIBPATH' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_MODULE_PATH], [LT_SYS_MODULE_PATH($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:608: -1- AC_DEFUN([LT_SYS_DLSEARCH_PATH], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([for the default library search path], - [lt_cv_sys_dlsearch_path], - [lt_cv_sys_dlsearch_path=$sys_lib_dlsearch_path_spec]) -if test -n "$lt_cv_sys_dlsearch_path"; then - sys_dlsearch_path= - for dir in $lt_cv_sys_dlsearch_path; do - if test -z "$sys_dlsearch_path"; then - sys_dlsearch_path=$dir - else - sys_dlsearch_path=$sys_dlsearch_path$PATH_SEPARATOR$dir - fi - done - m4_pattern_allow([LT_DLSEARCH_PATH])dnl - AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], - [Define to the system default library search path.]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:629: -1- AU_DEFUN([AC_LTDL_SYSSEARCHPATH], [m4_if($#, 0, [LT_SYS_DLSEARCH_PATH], [LT_SYS_DLSEARCH_PATH($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:629: -1- AC_DEFUN([AC_LTDL_SYSSEARCHPATH], [m4_warn([obsolete], [The macro 'AC_LTDL_SYSSEARCHPATH' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_DLSEARCH_PATH], [LT_SYS_DLSEARCH_PATH($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:655: -1- AC_DEFUN([LT_LIB_DLLOAD], [m4_pattern_allow([^LT_DLLOADERS$]) -LT_DLLOADERS= -AC_SUBST([LT_DLLOADERS]) - -AC_LANG_PUSH([C]) -lt_dlload_save_LIBS=$LIBS - -LIBADD_DLOPEN= -AC_SEARCH_LIBS([dlopen], [dl], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - if test "$ac_cv_search_dlopen" != "none required"; then - LIBADD_DLOPEN=-ldl - fi - libltdl_cv_lib_dl_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H -# include -#endif - ]], [[dlopen(0, 0);]])], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - libltdl_cv_func_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], - [AC_CHECK_LIB([svld], [dlopen], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - LIBADD_DLOPEN=-lsvld libltdl_cv_func_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) -if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen" -then - lt_save_LIBS=$LIBS - LIBS="$LIBS $LIBADD_DLOPEN" - AC_CHECK_FUNCS([dlerror]) - LIBS=$lt_save_LIBS -fi -AC_SUBST([LIBADD_DLOPEN]) - -LIBADD_SHL_LOAD= -AC_CHECK_FUNC([shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], - [AC_CHECK_LIB([dld], [shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" - LIBADD_SHL_LOAD=-ldld])]) -AC_SUBST([LIBADD_SHL_LOAD]) - -case $host_os in -darwin[[1567]].*) -# We only want this for pre-Mac OS X 10.4. - AC_CHECK_FUNC([_dyld_func_lookup], - [AC_DEFINE([HAVE_DYLD], [1], - [Define if you have the _dyld_func_lookup function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) - ;; -beos*) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" - ;; -cygwin* | mingw* | windows* | pw32*) - AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" - ;; -esac - -AC_CHECK_LIB([dld], [dld_link], - [AC_DEFINE([HAVE_DLD], [1], - [Define if you have the GNU dld library.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) -AC_SUBST([LIBADD_DLD_LINK]) - -m4_pattern_allow([^LT_DLPREOPEN$]) -LT_DLPREOPEN= -if test -n "$LT_DLLOADERS" -then - for lt_loader in $LT_DLLOADERS; do - LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " - done - AC_DEFINE([HAVE_LIBDLLOADER], [1], - [Define if libdlloader will be built on this platform]) -fi -AC_SUBST([LT_DLPREOPEN]) - -dnl This isn't used anymore, but set it for backwards compatibility -LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" -AC_SUBST([LIBADD_DL]) - -LIBS=$lt_dlload_save_LIBS -AC_LANG_POP -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:750: -1- AU_DEFUN([AC_LTDL_DLLIB], [m4_if($#, 0, [LT_LIB_DLLOAD], [LT_LIB_DLLOAD($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:750: -1- AC_DEFUN([AC_LTDL_DLLIB], [m4_warn([obsolete], [The macro 'AC_LTDL_DLLIB' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_LIB_DLLOAD], [LT_LIB_DLLOAD($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:758: -1- AC_DEFUN([LT_SYS_SYMBOL_USCORE], [m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl -AC_CACHE_CHECK([for _ prefix in compiled symbols], - [lt_cv_sys_symbol_underscore], - [lt_cv_sys_symbol_underscore=no - cat > conftest.$ac_ext <<_LT_EOF -void nm_test_func(){} -int main(void){nm_test_func;return 0;} -_LT_EOF - if AC_TRY_EVAL(ac_compile); then - # Now try to grab the symbols. - ac_nlist=conftest.nm - if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then - # See whether the symbols have a leading underscore. - if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then - lt_cv_sys_symbol_underscore=yes - else - if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then - : - else - echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD - fi - fi - else - echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD - fi - else - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat conftest.c >&AS_MESSAGE_LOG_FD - fi - rm -rf conftest* - ]) - sys_symbol_underscore=$lt_cv_sys_symbol_underscore - AC_SUBST([sys_symbol_underscore]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:795: -1- AU_DEFUN([AC_LTDL_SYMBOL_USCORE], [m4_if($#, 0, [LT_SYS_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:795: -1- AC_DEFUN([AC_LTDL_SYMBOL_USCORE], [m4_warn([obsolete], [The macro 'AC_LTDL_SYMBOL_USCORE' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE($@)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:802: -1- AC_DEFUN([LT_FUNC_DLSYM_USCORE], [AC_REQUIRE([_LT_COMPILER_PIC])dnl for lt_prog_compiler_wl -AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl for lt_cv_sys_symbol_underscore -AC_REQUIRE([LT_SYS_MODULE_EXT])dnl for libltdl_cv_shlibext -if test yes = "$lt_cv_sys_symbol_underscore"; then - if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen"; then - AC_CACHE_CHECK([whether we have to add an underscore for dlsym], - [libltdl_cv_need_uscore], - [libltdl_cv_need_uscore=unknown - dlsym_uscore_save_LIBS=$LIBS - LIBS="$LIBS $LIBADD_DLOPEN" - libname=conftmod # stay within 8.3 filename limits! - cat >$libname.$ac_ext <<_LT_EOF -[#line $LINENO "configure" -#include "confdefs.h" -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif -int fnord () { return 42; }] -_LT_EOF - - # ltfn_module_cmds module_cmds - # Execute tilde-delimited MODULE_CMDS with environment primed for - # $module_cmds or $archive_cmds type content. - ltfn_module_cmds () - {( # subshell avoids polluting parent global environment - module_cmds_save_ifs=$IFS; IFS='~' - for cmd in @S|@1; do - IFS=$module_cmds_save_ifs - libobjs=$libname.$ac_objext; lib=$libname$libltdl_cv_shlibext - rpath=/not-exists; soname=$libname$libltdl_cv_shlibext; output_objdir=. - major=; versuffix=; verstring=; deplibs= - ECHO=echo; wl=$lt_prog_compiler_wl; allow_undefined_flag= - eval $cmd - done - IFS=$module_cmds_save_ifs - )} - - # Compile a loadable module using libtool macro expansion results. - $CC $pic_flag -c $libname.$ac_ext - ltfn_module_cmds "${module_cmds:-$archive_cmds}" - - # Try to fetch fnord with dlsym(). - libltdl_dlunknown=0; libltdl_dlnouscore=1; libltdl_dluscore=2 - cat >conftest.$ac_ext <<_LT_EOF -[#line $LINENO "configure" -#include "confdefs.h" -#if HAVE_DLFCN_H -#include -#endif -#include -#ifndef RTLD_GLOBAL -# ifdef DL_GLOBAL -# define RTLD_GLOBAL DL_GLOBAL -# else -# define RTLD_GLOBAL 0 -# endif -#endif -#ifndef RTLD_NOW -# ifdef DL_NOW -# define RTLD_NOW DL_NOW -# else -# define RTLD_NOW 0 -# endif -#endif -int main (void) { - void *handle = dlopen ("`pwd`/$libname$libltdl_cv_shlibext", RTLD_GLOBAL|RTLD_NOW); - int status = $libltdl_dlunknown; - if (handle) { - if (dlsym (handle, "fnord")) - status = $libltdl_dlnouscore; - else { - if (dlsym (handle, "_fnord")) - status = $libltdl_dluscore; - else - puts (dlerror ()); - } - dlclose (handle); - } else - puts (dlerror ()); - return status; -}] -_LT_EOF - if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null - libltdl_status=$? - case x$libltdl_status in - x$libltdl_dlnouscore) libltdl_cv_need_uscore=no ;; - x$libltdl_dluscore) libltdl_cv_need_uscore=yes ;; - x*) libltdl_cv_need_uscore=unknown ;; - esac - fi - rm -rf conftest* $libname* - LIBS=$dlsym_uscore_save_LIBS - ]) - fi -fi - -if test yes = "$libltdl_cv_need_uscore"; then - AC_DEFINE([NEED_USCORE], [1], - [Define if dlsym() requires a leading underscore in symbol names.]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:909: -1- AU_DEFUN([AC_LTDL_DLSYM_USCORE], [m4_if($#, 0, [LT_FUNC_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE($@)])], [], []) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal/ltdl.m4:909: -1- AC_DEFUN([AC_LTDL_DLSYM_USCORE], [m4_warn([obsolete], [The macro 'AC_LTDL_DLSYM_USCORE' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_FUNC_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE($@)])]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:58: -1- AC_DEFUN([XORG_PROG_RAWCPP], [ -AC_REQUIRE([AC_PROG_CPP]) -AC_PATH_TOOL(RAWCPP, [cpp], [${CPP}], - [$PATH:/bin:/usr/bin:/usr/lib:/usr/libexec:/usr/ccs/lib:/usr/ccs/lbin:/lib]) - -# Check for flag to avoid builtin definitions - assumes unix is predefined, -# which is not the best choice for supporting other OS'es, but covers most -# of the ones we need for now. -AC_MSG_CHECKING([if $RAWCPP requires -undef]) -AC_LANG_CONFTEST([AC_LANG_SOURCE([[Does cpp redefine unix ?]])]) -if test `${RAWCPP} < conftest.$ac_ext | grep -c 'unix'` -eq 1 ; then - AC_MSG_RESULT([no]) -else - if test `${RAWCPP} -undef < conftest.$ac_ext | grep -c 'unix'` -eq 1 ; then - RAWCPPFLAGS=-undef - AC_MSG_RESULT([yes]) - # under Cygwin unix is still defined even with -undef - elif test `${RAWCPP} -undef -ansi < conftest.$ac_ext | grep -c 'unix'` -eq 1 ; then - RAWCPPFLAGS="-undef -ansi" - AC_MSG_RESULT([yes, with -ansi]) - else - AC_MSG_ERROR([${RAWCPP} defines unix with or without -undef. I don't know what to do.]) - fi -fi -rm -f conftest.$ac_ext - -AC_MSG_CHECKING([if $RAWCPP requires -traditional]) -AC_LANG_CONFTEST([AC_LANG_SOURCE([[Does cpp preserve "whitespace"?]])]) -if test `${RAWCPP} < conftest.$ac_ext | grep -c 'preserve "'` -eq 1 ; then - AC_MSG_RESULT([no]) -else - if test `${RAWCPP} -traditional < conftest.$ac_ext | grep -c 'preserve "'` -eq 1 ; then - TRADITIONALCPPFLAGS="-traditional" - RAWCPPFLAGS="${RAWCPPFLAGS} -traditional" - AC_MSG_RESULT([yes]) - else - AC_MSG_ERROR([${RAWCPP} does not preserve whitespace with or without -traditional. I don't know what to do.]) - fi -fi -rm -f conftest.$ac_ext -AC_SUBST(RAWCPPFLAGS) -AC_SUBST(TRADITIONALCPPFLAGS) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:113: -1- AC_DEFUN([XORG_MANPAGE_SECTIONS], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_REQUIRE([AC_PROG_SED]) - -case $host_os in - solaris*) - # Solaris 2.0 - 11.3 use SysV man page section numbers, so we - # check for a man page file found in later versions that use - # traditional section numbers instead - AC_CHECK_FILE([/usr/share/man/man7/attributes.7], - [SYSV_MAN_SECTIONS=false], [SYSV_MAN_SECTIONS=true]) - ;; - *) SYSV_MAN_SECTIONS=false ;; -esac - -if test x$APP_MAN_SUFFIX = x ; then - APP_MAN_SUFFIX=1 -fi -if test x$APP_MAN_DIR = x ; then - APP_MAN_DIR='$(mandir)/man$(APP_MAN_SUFFIX)' -fi - -if test x$LIB_MAN_SUFFIX = x ; then - LIB_MAN_SUFFIX=3 -fi -if test x$LIB_MAN_DIR = x ; then - LIB_MAN_DIR='$(mandir)/man$(LIB_MAN_SUFFIX)' -fi - -if test x$FILE_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) FILE_MAN_SUFFIX=4 ;; - *) FILE_MAN_SUFFIX=5 ;; - esac -fi -if test x$FILE_MAN_DIR = x ; then - FILE_MAN_DIR='$(mandir)/man$(FILE_MAN_SUFFIX)' -fi - -if test x$MISC_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) MISC_MAN_SUFFIX=5 ;; - *) MISC_MAN_SUFFIX=7 ;; - esac -fi -if test x$MISC_MAN_DIR = x ; then - MISC_MAN_DIR='$(mandir)/man$(MISC_MAN_SUFFIX)' -fi - -if test x$DRIVER_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) DRIVER_MAN_SUFFIX=7 ;; - *) DRIVER_MAN_SUFFIX=4 ;; - esac -fi -if test x$DRIVER_MAN_DIR = x ; then - DRIVER_MAN_DIR='$(mandir)/man$(DRIVER_MAN_SUFFIX)' -fi - -if test x$ADMIN_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) ADMIN_MAN_SUFFIX=1m ;; - *) ADMIN_MAN_SUFFIX=8 ;; - esac -fi -if test x$ADMIN_MAN_DIR = x ; then - ADMIN_MAN_DIR='$(mandir)/man$(ADMIN_MAN_SUFFIX)' -fi - - -AC_SUBST([APP_MAN_SUFFIX]) -AC_SUBST([LIB_MAN_SUFFIX]) -AC_SUBST([FILE_MAN_SUFFIX]) -AC_SUBST([MISC_MAN_SUFFIX]) -AC_SUBST([DRIVER_MAN_SUFFIX]) -AC_SUBST([ADMIN_MAN_SUFFIX]) -AC_SUBST([APP_MAN_DIR]) -AC_SUBST([LIB_MAN_DIR]) -AC_SUBST([FILE_MAN_DIR]) -AC_SUBST([MISC_MAN_DIR]) -AC_SUBST([DRIVER_MAN_DIR]) -AC_SUBST([ADMIN_MAN_DIR]) - -XORG_MAN_PAGE="X Version 11" -AC_SUBST([XORG_MAN_PAGE]) -MAN_SUBSTS="\ - -e 's|__vendorversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xorgversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xservername__|Xorg|g' \ - -e 's|__xconfigfile__|xorg.conf|g' \ - -e 's|__projectroot__|\$(prefix)|g' \ - -e 's|__apploaddir__|\$(appdefaultdir)|g' \ - -e 's|__appmansuffix__|\$(APP_MAN_SUFFIX)|g' \ - -e 's|__drivermansuffix__|\$(DRIVER_MAN_SUFFIX)|g' \ - -e 's|__adminmansuffix__|\$(ADMIN_MAN_SUFFIX)|g' \ - -e 's|__libmansuffix__|\$(LIB_MAN_SUFFIX)|g' \ - -e 's|__miscmansuffix__|\$(MISC_MAN_SUFFIX)|g' \ - -e 's|__filemansuffix__|\$(FILE_MAN_SUFFIX)|g'" -AC_SUBST([MAN_SUBSTS]) - -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:221: -1- AC_DEFUN([XORG_CHECK_SGML_DOCTOOLS], [ -AC_MSG_CHECKING([for X.Org SGML entities m4_ifval([$1],[>= $1])]) -XORG_SGML_PATH= -PKG_CHECK_EXISTS([xorg-sgml-doctools m4_ifval([$1],[>= $1])], - [XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools`], - [m4_ifval([$1],[:], - [if test x"$cross_compiling" != x"yes" ; then - AC_CHECK_FILE([$prefix/share/sgml/X11/defs.ent], - [XORG_SGML_PATH=$prefix/share/sgml]) - fi]) - ]) - -# Define variables STYLESHEET_SRCDIR and XSL_STYLESHEET containing -# the path and the name of the doc stylesheet -if test "x$XORG_SGML_PATH" != "x" ; then - AC_MSG_RESULT([$XORG_SGML_PATH]) - STYLESHEET_SRCDIR=$XORG_SGML_PATH/X11 - XSL_STYLESHEET=$STYLESHEET_SRCDIR/xorg.xsl -else - AC_MSG_RESULT([no]) -fi - -AC_SUBST(XORG_SGML_PATH) -AC_SUBST(STYLESHEET_SRCDIR) -AC_SUBST(XSL_STYLESHEET) -AM_CONDITIONAL([HAVE_STYLESHEETS], [test "x$XSL_STYLESHEET" != "x"]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:257: -1- AC_DEFUN([XORG_CHECK_LINUXDOC], [ -AC_REQUIRE([XORG_CHECK_SGML_DOCTOOLS]) -AC_REQUIRE([XORG_WITH_PS2PDF]) - -AC_PATH_PROG(LINUXDOC, linuxdoc) - -AC_MSG_CHECKING([whether to build documentation]) - -if test x$XORG_SGML_PATH != x && test x$LINUXDOC != x ; then - BUILDDOC=yes -else - BUILDDOC=no -fi - -AM_CONDITIONAL(BUILD_LINUXDOC, [test x$BUILDDOC = xyes]) - -AC_MSG_RESULT([$BUILDDOC]) - -AC_MSG_CHECKING([whether to build pdf documentation]) - -if test x$have_ps2pdf != xno && test x$BUILD_PDFDOC != xno; then - BUILDPDFDOC=yes -else - BUILDPDFDOC=no -fi - -AM_CONDITIONAL(BUILD_PDFDOC, [test x$BUILDPDFDOC = xyes]) - -AC_MSG_RESULT([$BUILDPDFDOC]) - -MAKE_TEXT="SGML_SEARCH_PATH=$XORG_SGML_PATH GROFF_NO_SGR=y $LINUXDOC -B txt -f" -MAKE_PS="SGML_SEARCH_PATH=$XORG_SGML_PATH $LINUXDOC -B latex --papersize=letter --output=ps" -MAKE_PDF="$PS2PDF" -MAKE_HTML="SGML_SEARCH_PATH=$XORG_SGML_PATH $LINUXDOC -B html --split=0" - -AC_SUBST(MAKE_TEXT) -AC_SUBST(MAKE_PS) -AC_SUBST(MAKE_PDF) -AC_SUBST(MAKE_HTML) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:306: -1- AC_DEFUN([XORG_CHECK_DOCBOOK], [ -AC_REQUIRE([XORG_CHECK_SGML_DOCTOOLS]) - -BUILDTXTDOC=no -BUILDPDFDOC=no -BUILDPSDOC=no -BUILDHTMLDOC=no - -AC_PATH_PROG(DOCBOOKPS, docbook2ps) -AC_PATH_PROG(DOCBOOKPDF, docbook2pdf) -AC_PATH_PROG(DOCBOOKHTML, docbook2html) -AC_PATH_PROG(DOCBOOKTXT, docbook2txt) - -AC_MSG_CHECKING([whether to build text documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKTXT != x && - test x$BUILD_TXTDOC != xno; then - BUILDTXTDOC=yes -fi -AM_CONDITIONAL(BUILD_TXTDOC, [test x$BUILDTXTDOC = xyes]) -AC_MSG_RESULT([$BUILDTXTDOC]) - -AC_MSG_CHECKING([whether to build PDF documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKPDF != x && - test x$BUILD_PDFDOC != xno; then - BUILDPDFDOC=yes -fi -AM_CONDITIONAL(BUILD_PDFDOC, [test x$BUILDPDFDOC = xyes]) -AC_MSG_RESULT([$BUILDPDFDOC]) - -AC_MSG_CHECKING([whether to build PostScript documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKPS != x && - test x$BUILD_PSDOC != xno; then - BUILDPSDOC=yes -fi -AM_CONDITIONAL(BUILD_PSDOC, [test x$BUILDPSDOC = xyes]) -AC_MSG_RESULT([$BUILDPSDOC]) - -AC_MSG_CHECKING([whether to build HTML documentation]) -if test x$XORG_SGML_PATH != x && test x$DOCBOOKHTML != x && - test x$BUILD_HTMLDOC != xno; then - BUILDHTMLDOC=yes -fi -AM_CONDITIONAL(BUILD_HTMLDOC, [test x$BUILDHTMLDOC = xyes]) -AC_MSG_RESULT([$BUILDHTMLDOC]) - -MAKE_TEXT="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKTXT" -MAKE_PS="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKPS" -MAKE_PDF="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKPDF" -MAKE_HTML="SGML_SEARCH_PATH=$XORG_SGML_PATH $DOCBOOKHTML" - -AC_SUBST(MAKE_TEXT) -AC_SUBST(MAKE_PS) -AC_SUBST(MAKE_PDF) -AC_SUBST(MAKE_HTML) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:387: -1- AC_DEFUN([XORG_WITH_XMLTO], [ -AC_ARG_VAR([XMLTO], [Path to xmlto command]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(xmlto, - AS_HELP_STRING([--with-xmlto], - [Use xmlto to regenerate documentation (default: ]_defopt[)]), - [use_xmlto=$withval], [use_xmlto=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_xmlto" = x"auto"; then - AC_PATH_PROG([XMLTO], [xmlto]) - if test "x$XMLTO" = "x"; then - AC_MSG_WARN([xmlto not found - documentation targets will be skipped]) - have_xmlto=no - else - have_xmlto=yes - fi -elif test "x$use_xmlto" = x"yes" ; then - AC_PATH_PROG([XMLTO], [xmlto]) - if test "x$XMLTO" = "x"; then - AC_MSG_ERROR([--with-xmlto=yes specified but xmlto not found in PATH]) - fi - have_xmlto=yes -elif test "x$use_xmlto" = x"no" ; then - if test "x$XMLTO" != "x"; then - AC_MSG_WARN([ignoring XMLTO environment variable since --with-xmlto=no was specified]) - fi - have_xmlto=no -else - AC_MSG_ERROR([--with-xmlto expects 'yes' or 'no']) -fi - -# Test for a minimum version of xmlto, if provided. -m4_ifval([$1], -[if test "$have_xmlto" = yes; then - # scrape the xmlto version - AC_MSG_CHECKING([the xmlto version]) - xmlto_version=`$XMLTO --version 2>/dev/null | cut -d' ' -f3` - AC_MSG_RESULT([$xmlto_version]) - AS_VERSION_COMPARE([$xmlto_version], [$1], - [if test "x$use_xmlto" = xauto; then - AC_MSG_WARN([xmlto version $xmlto_version found, but $1 needed]) - have_xmlto=no - else - AC_MSG_ERROR([xmlto version $xmlto_version found, but $1 needed]) - fi]) -fi]) - -# Test for the ability of xmlto to generate a text target -# -# NOTE: xmlto 0.0.27 or higher return a non-zero return code in the -# following test for empty XML docbook files. -# For compatibility reasons use the following empty XML docbook file and if -# it fails try it again with a non-empty XML file. -have_xmlto_text=no -cat > conftest.xml << "EOF" -EOF -AS_IF([test "$have_xmlto" = yes], - [AS_IF([$XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1], - [have_xmlto_text=yes], - [# Try it again with a non-empty XML file. - cat > conftest.xml << "EOF" - -EOF - AS_IF([$XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1], - [have_xmlto_text=yes], - [AC_MSG_WARN([xmlto cannot generate text format, this format skipped])])])]) -rm -f conftest.xml -AM_CONDITIONAL([HAVE_XMLTO_TEXT], [test $have_xmlto_text = yes]) -AM_CONDITIONAL([HAVE_XMLTO], [test "$have_xmlto" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:482: -1- AC_DEFUN([XORG_WITH_XSLTPROC], [ -AC_ARG_VAR([XSLTPROC], [Path to xsltproc command]) -# Preserves the interface, should it be implemented later -m4_ifval([$1], [m4_warn([syntax], [Checking for xsltproc MIN-VERSION is not implemented])]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(xsltproc, - AS_HELP_STRING([--with-xsltproc], - [Use xsltproc for the transformation of XML documents (default: ]_defopt[)]), - [use_xsltproc=$withval], [use_xsltproc=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_xsltproc" = x"auto"; then - AC_PATH_PROG([XSLTPROC], [xsltproc]) - if test "x$XSLTPROC" = "x"; then - AC_MSG_WARN([xsltproc not found - cannot transform XML documents]) - have_xsltproc=no - else - have_xsltproc=yes - fi -elif test "x$use_xsltproc" = x"yes" ; then - AC_PATH_PROG([XSLTPROC], [xsltproc]) - if test "x$XSLTPROC" = "x"; then - AC_MSG_ERROR([--with-xsltproc=yes specified but xsltproc not found in PATH]) - fi - have_xsltproc=yes -elif test "x$use_xsltproc" = x"no" ; then - if test "x$XSLTPROC" != "x"; then - AC_MSG_WARN([ignoring XSLTPROC environment variable since --with-xsltproc=no was specified]) - fi - have_xsltproc=no -else - AC_MSG_ERROR([--with-xsltproc expects 'yes' or 'no']) -fi - -AM_CONDITIONAL([HAVE_XSLTPROC], [test "$have_xsltproc" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:539: -1- AC_DEFUN([XORG_WITH_PERL], [ -AC_ARG_VAR([PERL], [Path to perl command]) -# Preserves the interface, should it be implemented later -m4_ifval([$1], [m4_warn([syntax], [Checking for perl MIN-VERSION is not implemented])]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(perl, - AS_HELP_STRING([--with-perl], - [Use perl for extracting information from files (default: ]_defopt[)]), - [use_perl=$withval], [use_perl=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_perl" = x"auto"; then - AC_PATH_PROG([PERL], [perl]) - if test "x$PERL" = "x"; then - AC_MSG_WARN([perl not found - cannot extract information and report]) - have_perl=no - else - have_perl=yes - fi -elif test "x$use_perl" = x"yes" ; then - AC_PATH_PROG([PERL], [perl]) - if test "x$PERL" = "x"; then - AC_MSG_ERROR([--with-perl=yes specified but perl not found in PATH]) - fi - have_perl=yes -elif test "x$use_perl" = x"no" ; then - if test "x$PERL" != "x"; then - AC_MSG_WARN([ignoring PERL environment variable since --with-perl=no was specified]) - fi - have_perl=no -else - AC_MSG_ERROR([--with-perl expects 'yes' or 'no']) -fi - -AM_CONDITIONAL([HAVE_PERL], [test "$have_perl" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:597: -1- AC_DEFUN([XORG_WITH_ASCIIDOC], [ -AC_ARG_VAR([ASCIIDOC], [Path to asciidoc command]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(asciidoc, - AS_HELP_STRING([--with-asciidoc], - [Use asciidoc to regenerate documentation (default: ]_defopt[)]), - [use_asciidoc=$withval], [use_asciidoc=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_asciidoc" = x"auto"; then - AC_PATH_PROG([ASCIIDOC], [asciidoc]) - if test "x$ASCIIDOC" = "x"; then - AC_MSG_WARN([asciidoc not found - documentation targets will be skipped]) - have_asciidoc=no - else - have_asciidoc=yes - fi -elif test "x$use_asciidoc" = x"yes" ; then - AC_PATH_PROG([ASCIIDOC], [asciidoc]) - if test "x$ASCIIDOC" = "x"; then - AC_MSG_ERROR([--with-asciidoc=yes specified but asciidoc not found in PATH]) - fi - have_asciidoc=yes -elif test "x$use_asciidoc" = x"no" ; then - if test "x$ASCIIDOC" != "x"; then - AC_MSG_WARN([ignoring ASCIIDOC environment variable since --with-asciidoc=no was specified]) - fi - have_asciidoc=no -else - AC_MSG_ERROR([--with-asciidoc expects 'yes' or 'no']) -fi -m4_ifval([$1], -[if test "$have_asciidoc" = yes; then - # scrape the asciidoc version - AC_MSG_CHECKING([the asciidoc version]) - asciidoc_version=`$ASCIIDOC --version 2>/dev/null | cut -d' ' -f2` - AC_MSG_RESULT([$asciidoc_version]) - AS_VERSION_COMPARE([$asciidoc_version], [$1], - [if test "x$use_asciidoc" = xauto; then - AC_MSG_WARN([asciidoc version $asciidoc_version found, but $1 needed]) - have_asciidoc=no - else - AC_MSG_ERROR([asciidoc version $asciidoc_version found, but $1 needed]) - fi]) -fi]) -AM_CONDITIONAL([HAVE_ASCIIDOC], [test "$have_asciidoc" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:667: -1- AC_DEFUN([XORG_WITH_DOXYGEN], [ -AC_ARG_VAR([DOXYGEN], [Path to doxygen command]) -AC_ARG_VAR([DOT], [Path to the dot graphics utility]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(doxygen, - AS_HELP_STRING([--with-doxygen], - [Use doxygen to regenerate documentation (default: ]_defopt[)]), - [use_doxygen=$withval], [use_doxygen=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_doxygen" = x"auto"; then - AC_PATH_PROG([DOXYGEN], [doxygen]) - if test "x$DOXYGEN" = "x"; then - AC_MSG_WARN([doxygen not found - documentation targets will be skipped]) - have_doxygen=no - else - have_doxygen=yes - fi -elif test "x$use_doxygen" = x"yes" ; then - AC_PATH_PROG([DOXYGEN], [doxygen]) - if test "x$DOXYGEN" = "x"; then - AC_MSG_ERROR([--with-doxygen=yes specified but doxygen not found in PATH]) - fi - have_doxygen=yes -elif test "x$use_doxygen" = x"no" ; then - if test "x$DOXYGEN" != "x"; then - AC_MSG_WARN([ignoring DOXYGEN environment variable since --with-doxygen=no was specified]) - fi - have_doxygen=no -else - AC_MSG_ERROR([--with-doxygen expects 'yes' or 'no']) -fi -m4_ifval([$1], -[if test "$have_doxygen" = yes; then - # scrape the doxygen version - AC_MSG_CHECKING([the doxygen version]) - doxygen_version=`$DOXYGEN --version 2>/dev/null` - AC_MSG_RESULT([$doxygen_version]) - AS_VERSION_COMPARE([$doxygen_version], [$1], - [if test "x$use_doxygen" = xauto; then - AC_MSG_WARN([doxygen version $doxygen_version found, but $1 needed]) - have_doxygen=no - else - AC_MSG_ERROR([doxygen version $doxygen_version found, but $1 needed]) - fi]) -fi]) - -dnl Check for DOT if we have doxygen. The caller decides if it is mandatory -dnl HAVE_DOT is a variable that can be used in your doxygen.in config file: -dnl HAVE_DOT = @HAVE_DOT@ -HAVE_DOT=no -if test "x$have_doxygen" = "xyes"; then - AC_PATH_PROG([DOT], [dot]) - if test "x$DOT" != "x"; then - HAVE_DOT=yes - fi -fi - -AC_SUBST([HAVE_DOT]) -AM_CONDITIONAL([HAVE_DOT], [test "$HAVE_DOT" = "yes"]) -AM_CONDITIONAL([HAVE_DOXYGEN], [test "$have_doxygen" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:767: -1- AC_DEFUN([XORG_WITH_GROFF], [ -AC_ARG_VAR([GROFF], [Path to groff command]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_WITH(groff, - AS_HELP_STRING([--with-groff], - [Use groff to regenerate documentation (default: ]_defopt[)]), - [use_groff=$withval], [use_groff=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_groff" = x"auto"; then - AC_PATH_PROG([GROFF], [groff]) - if test "x$GROFF" = "x"; then - AC_MSG_WARN([groff not found - documentation targets will be skipped]) - have_groff=no - else - have_groff=yes - fi -elif test "x$use_groff" = x"yes" ; then - AC_PATH_PROG([GROFF], [groff]) - if test "x$GROFF" = "x"; then - AC_MSG_ERROR([--with-groff=yes specified but groff not found in PATH]) - fi - have_groff=yes -elif test "x$use_groff" = x"no" ; then - if test "x$GROFF" != "x"; then - AC_MSG_WARN([ignoring GROFF environment variable since --with-groff=no was specified]) - fi - have_groff=no -else - AC_MSG_ERROR([--with-groff expects 'yes' or 'no']) -fi - -# We have groff, test for the presence of the macro packages -if test "x$have_groff" = x"yes"; then - AC_MSG_CHECKING([for ${GROFF} -ms macros]) - if ${GROFF} -ms -I. /dev/null >/dev/null 2>&1 ; then - groff_ms_works=yes - else - groff_ms_works=no - fi - AC_MSG_RESULT([$groff_ms_works]) - AC_MSG_CHECKING([for ${GROFF} -mm macros]) - if ${GROFF} -mm -I. /dev/null >/dev/null 2>&1 ; then - groff_mm_works=yes - else - groff_mm_works=no - fi - AC_MSG_RESULT([$groff_mm_works]) -fi - -# We have groff, test for HTML dependencies, one command per package -if test "x$have_groff" = x"yes"; then - AC_PATH_PROGS(GS_PATH, [gs gswin32c]) - AC_PATH_PROG(PNMTOPNG_PATH, [pnmtopng]) - AC_PATH_PROG(PSSELECT_PATH, [psselect]) - if test "x$GS_PATH" != "x" -a "x$PNMTOPNG_PATH" != "x" -a "x$PSSELECT_PATH" != "x"; then - have_groff_html=yes - else - have_groff_html=no - AC_MSG_WARN([grohtml dependencies not found - HTML Documentation skipped. Refer to grohtml man pages]) - fi -fi - -# Set Automake conditionals for Makefiles -AM_CONDITIONAL([HAVE_GROFF], [test "$have_groff" = yes]) -AM_CONDITIONAL([HAVE_GROFF_MS], [test "$groff_ms_works" = yes]) -AM_CONDITIONAL([HAVE_GROFF_MM], [test "$groff_mm_works" = yes]) -AM_CONDITIONAL([HAVE_GROFF_HTML], [test "$have_groff_html" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:859: -1- AC_DEFUN([XORG_WITH_FOP], [ -AC_ARG_VAR([FOP], [Path to fop command]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(fop, - AS_HELP_STRING([--with-fop], - [Use fop to regenerate documentation (default: ]_defopt[)]), - [use_fop=$withval], [use_fop=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_fop" = x"auto"; then - AC_PATH_PROG([FOP], [fop]) - if test "x$FOP" = "x"; then - AC_MSG_WARN([fop not found - documentation targets will be skipped]) - have_fop=no - else - have_fop=yes - fi -elif test "x$use_fop" = x"yes" ; then - AC_PATH_PROG([FOP], [fop]) - if test "x$FOP" = "x"; then - AC_MSG_ERROR([--with-fop=yes specified but fop not found in PATH]) - fi - have_fop=yes -elif test "x$use_fop" = x"no" ; then - if test "x$FOP" != "x"; then - AC_MSG_WARN([ignoring FOP environment variable since --with-fop=no was specified]) - fi - have_fop=no -else - AC_MSG_ERROR([--with-fop expects 'yes' or 'no']) -fi - -# Test for a minimum version of fop, if provided. -m4_ifval([$1], -[if test "$have_fop" = yes; then - # scrape the fop version - AC_MSG_CHECKING([for fop minimum version]) - fop_version=`$FOP -version 2>/dev/null | cut -d' ' -f3` - AC_MSG_RESULT([$fop_version]) - AS_VERSION_COMPARE([$fop_version], [$1], - [if test "x$use_fop" = xauto; then - AC_MSG_WARN([fop version $fop_version found, but $1 needed]) - have_fop=no - else - AC_MSG_ERROR([fop version $fop_version found, but $1 needed]) - fi]) -fi]) -AM_CONDITIONAL([HAVE_FOP], [test "$have_fop" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:921: -1- AC_DEFUN([XORG_WITH_M4], [ -AC_CACHE_CHECK([for m4 that supports -I option], [ac_cv_path_M4], - [AC_PATH_PROGS_FEATURE_CHECK([M4], [m4 gm4], - [[$ac_path_M4 -I. /dev/null > /dev/null 2>&1 && \ - ac_cv_path_M4=$ac_path_M4 ac_path_M4_found=:]], - [AC_MSG_ERROR([could not find m4 that supports -I option])], - [$PATH:/usr/gnu/bin])]) - -AC_SUBST([M4], [$ac_cv_path_M4]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:953: -1- AC_DEFUN([XORG_WITH_PS2PDF], [ -AC_ARG_VAR([PS2PDF], [Path to ps2pdf command]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_WITH(ps2pdf, - AS_HELP_STRING([--with-ps2pdf], - [Use ps2pdf to regenerate documentation (default: ]_defopt[)]), - [use_ps2pdf=$withval], [use_ps2pdf=]_defopt) -m4_undefine([_defopt]) - -if test "x$use_ps2pdf" = x"auto"; then - AC_PATH_PROG([PS2PDF], [ps2pdf]) - if test "x$PS2PDF" = "x"; then - AC_MSG_WARN([ps2pdf not found - documentation targets will be skipped]) - have_ps2pdf=no - else - have_ps2pdf=yes - fi -elif test "x$use_ps2pdf" = x"yes" ; then - AC_PATH_PROG([PS2PDF], [ps2pdf]) - if test "x$PS2PDF" = "x"; then - AC_MSG_ERROR([--with-ps2pdf=yes specified but ps2pdf not found in PATH]) - fi - have_ps2pdf=yes -elif test "x$use_ps2pdf" = x"no" ; then - if test "x$PS2PDF" != "x"; then - AC_MSG_WARN([ignoring PS2PDF environment variable since --with-ps2pdf=no was specified]) - fi - have_ps2pdf=no -else - AC_MSG_ERROR([--with-ps2pdf expects 'yes' or 'no']) -fi -AM_CONDITIONAL([HAVE_PS2PDF], [test "$have_ps2pdf" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1010: -1- AC_DEFUN([XORG_ENABLE_DOCS], [ -m4_define([docs_default], m4_default([$1], [yes])) -AC_ARG_ENABLE(docs, - AS_HELP_STRING([--enable-docs], - [Enable building the documentation (default: ]docs_default[)]), - [build_docs=$enableval], [build_docs=]docs_default) -m4_undefine([docs_default]) -AM_CONDITIONAL(ENABLE_DOCS, [test x$build_docs = xyes]) -AC_MSG_CHECKING([whether to build documentation]) -AC_MSG_RESULT([$build_docs]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1043: -1- AC_DEFUN([XORG_ENABLE_DEVEL_DOCS], [ -m4_define([devel_default], m4_default([$1], [yes])) -AC_ARG_ENABLE(devel-docs, - AS_HELP_STRING([--enable-devel-docs], - [Enable building the developer documentation (default: ]devel_default[)]), - [build_devel_docs=$enableval], [build_devel_docs=]devel_default) -m4_undefine([devel_default]) -AM_CONDITIONAL(ENABLE_DEVEL_DOCS, [test x$build_devel_docs = xyes]) -AC_MSG_CHECKING([whether to build developer documentation]) -AC_MSG_RESULT([$build_devel_docs]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1076: -1- AC_DEFUN([XORG_ENABLE_SPECS], [ -m4_define([spec_default], m4_default([$1], [yes])) -AC_ARG_ENABLE(specs, - AS_HELP_STRING([--enable-specs], - [Enable building the specs (default: ]spec_default[)]), - [build_specs=$enableval], [build_specs=]spec_default) -m4_undefine([spec_default]) -AM_CONDITIONAL(ENABLE_SPECS, [test x$build_specs = xyes]) -AC_MSG_CHECKING([whether to build functional specifications]) -AC_MSG_RESULT([$build_specs]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1108: -1- AC_DEFUN([XORG_ENABLE_UNIT_TESTS], [ -AC_BEFORE([$0], [XORG_WITH_GLIB]) -AC_BEFORE([$0], [XORG_LD_WRAP]) -AC_REQUIRE([XORG_MEMORY_CHECK_FLAGS]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_ENABLE(unit-tests, AS_HELP_STRING([--enable-unit-tests], - [Enable building unit test cases (default: ]_defopt[)]), - [enable_unit_tests=$enableval], [enable_unit_tests=]_defopt) -m4_undefine([_defopt]) -AM_CONDITIONAL(ENABLE_UNIT_TESTS, [test "x$enable_unit_tests" != xno]) -AC_MSG_CHECKING([whether to build unit test cases]) -AC_MSG_RESULT([$enable_unit_tests]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1141: -1- AC_DEFUN([XORG_ENABLE_INTEGRATION_TESTS], [ -AC_REQUIRE([XORG_MEMORY_CHECK_FLAGS]) -m4_define([_defopt], m4_default([$1], [auto])) -AC_ARG_ENABLE(integration-tests, AS_HELP_STRING([--enable-integration-tests], - [Enable building integration test cases (default: ]_defopt[)]), - [enable_integration_tests=$enableval], - [enable_integration_tests=]_defopt) -m4_undefine([_defopt]) -AM_CONDITIONAL([ENABLE_INTEGRATION_TESTS], - [test "x$enable_integration_tests" != xno]) -AC_MSG_CHECKING([whether to build unit test cases]) -AC_MSG_RESULT([$enable_integration_tests]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1175: -1- AC_DEFUN([XORG_WITH_GLIB], [ -AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -m4_define([_defopt], m4_default([$2], [auto])) -AC_ARG_WITH(glib, AS_HELP_STRING([--with-glib], - [Use GLib library for unit testing (default: ]_defopt[)]), - [with_glib=$withval], [with_glib=]_defopt) -m4_undefine([_defopt]) - -have_glib=no -# Do not probe GLib if user explicitly disabled unit testing -if test "x$enable_unit_tests" != x"no"; then - # Do not probe GLib if user explicitly disabled it - if test "x$with_glib" != x"no"; then - m4_ifval( - [$1], - [PKG_CHECK_MODULES([GLIB], [glib-2.0 >= $1], [have_glib=yes], [have_glib=no])], - [PKG_CHECK_MODULES([GLIB], [glib-2.0], [have_glib=yes], [have_glib=no])] - ) - fi -fi - -# Not having GLib when unit testing has been explicitly requested is an error -if test "x$enable_unit_tests" = x"yes"; then - if test "x$have_glib" = x"no"; then - AC_MSG_ERROR([--enable-unit-tests=yes specified but glib-2.0 not found]) - fi -fi - -# Having unit testing disabled when GLib has been explicitly requested is an error -if test "x$enable_unit_tests" = x"no"; then - if test "x$with_glib" = x"yes"; then - AC_MSG_ERROR([--enable-unit-tests=yes specified but glib-2.0 not found]) - fi -fi - -# Not having GLib when it has been explicitly requested is an error -if test "x$with_glib" = x"yes"; then - if test "x$have_glib" = x"no"; then - AC_MSG_ERROR([--with-glib=yes specified but glib-2.0 not found]) - fi -fi - -AM_CONDITIONAL([HAVE_GLIB], [test "$have_glib" = yes]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1234: -1- AC_DEFUN([XORG_LD_WRAP], [ -XORG_CHECK_LINKER_FLAGS([-Wl,-wrap,exit],[have_ld_wrap=yes],[have_ld_wrap=no], - [AC_LANG_PROGRAM([#include - void __wrap_exit(int status) { return; }], - [exit(0);])]) -# Not having ld wrap when unit testing has been explicitly requested is an error -if test "x$enable_unit_tests" = x"yes" -a "x$1" != "xoptional"; then - if test "x$have_ld_wrap" = x"no"; then - AC_MSG_ERROR([--enable-unit-tests=yes specified but ld -wrap support is not available]) - fi -fi -AM_CONDITIONAL([HAVE_LD_WRAP], [test "$have_ld_wrap" = yes]) -# -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1298: -1- AC_DEFUN([XORG_CHECK_LINKER_FLAGS], [AC_MSG_CHECKING([whether the linker accepts $1]) -dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname: -AS_LITERAL_IF([$1], - [AC_CACHE_VAL(AS_TR_SH(xorg_cv_linker_flags_[$1]), [ - ax_save_FLAGS=$LDFLAGS - LDFLAGS="$1" - AC_LINK_IFELSE([m4_default([$4],[AC_LANG_PROGRAM()])], - AS_TR_SH(xorg_cv_linker_flags_[$1])=yes, - AS_TR_SH(xorg_cv_linker_flags_[$1])=no) - LDFLAGS=$ax_save_FLAGS])], - [ax_save_FLAGS=$LDFLAGS - LDFLAGS="$1" - AC_LINK_IFELSE([AC_LANG_PROGRAM()], - eval AS_TR_SH(xorg_cv_linker_flags_[$1])=yes, - eval AS_TR_SH(xorg_cv_linker_flags_[$1])=no) - LDFLAGS=$ax_save_FLAGS]) -eval xorg_check_linker_flags=$AS_TR_SH(xorg_cv_linker_flags_[$1]) -AC_MSG_RESULT($xorg_check_linker_flags) -if test "x$xorg_check_linker_flags" = xyes; then - m4_default([$2], :) -else - m4_default([$3], :) -fi -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1338: -1- AC_DEFUN([XORG_MEMORY_CHECK_FLAGS], [ - -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_ARG_VAR([XORG_MALLOC_DEBUG_ENV], - [Environment variables to enable memory checking in tests]) - -# Check for different types of support on different platforms -case $host_os in - solaris*) - AC_CHECK_LIB([umem], [umem_alloc], - [malloc_debug_env='LD_PRELOAD=libumem.so UMEM_DEBUG=default']) - ;; - *-gnu*) # GNU libc - Value is used as a single byte bit pattern, - # both directly and inverted, so should not be 0 or 255. - malloc_debug_env='MALLOC_PERTURB_=15' - ;; - darwin*) - malloc_debug_env='MallocPreScribble=1 MallocScribble=1 DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib' - ;; - *bsd*) - malloc_debug_env='MallocPreScribble=1 MallocScribble=1' - ;; -esac - -# User supplied flags override default flags -if test "x$XORG_MALLOC_DEBUG_ENV" != "x"; then - malloc_debug_env="$XORG_MALLOC_DEBUG_ENV" -fi - -AC_SUBST([XORG_MALLOC_DEBUG_ENV],[$malloc_debug_env]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1383: -1- AC_DEFUN([XORG_CHECK_MALLOC_ZERO], [ -AC_ARG_ENABLE(malloc0returnsnull, - AS_HELP_STRING([--enable-malloc0returnsnull], - [assume malloc(0) can return NULL (default: yes)]), - [MALLOC_ZERO_RETURNS_NULL=$enableval], - [MALLOC_ZERO_RETURNS_NULL=yes]) - -AC_MSG_CHECKING([whether to act as if malloc(0) can return NULL]) -AC_MSG_RESULT([$MALLOC_ZERO_RETURNS_NULL]) - -if test "x$MALLOC_ZERO_RETURNS_NULL" = xyes; then - MALLOC_ZERO_CFLAGS="-DMALLOC_0_RETURNS_NULL" - XMALLOC_ZERO_CFLAGS=$MALLOC_ZERO_CFLAGS - XTMALLOC_ZERO_CFLAGS="$MALLOC_ZERO_CFLAGS -DXTMALLOC_BC" -else - MALLOC_ZERO_CFLAGS="" - XMALLOC_ZERO_CFLAGS="" - XTMALLOC_ZERO_CFLAGS="" -fi - -AC_SUBST([MALLOC_ZERO_CFLAGS]) -AC_SUBST([XMALLOC_ZERO_CFLAGS]) -AC_SUBST([XTMALLOC_ZERO_CFLAGS]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1429: -1- AC_DEFUN([XORG_WITH_LINT], [ - -AC_ARG_VAR([LINT], [Path to a lint-style command]) -AC_ARG_VAR([LINT_FLAGS], [Flags for the lint-style command]) -AC_ARG_WITH(lint, [AS_HELP_STRING([--with-lint], - [Use a lint-style source code checker (default: disabled)])], - [use_lint=$withval], [use_lint=no]) - -# Obtain platform specific info like program name and options -# The lint program on FreeBSD and NetBSD is different from the one on Solaris -case $host_os in - *linux* | *openbsd* | kfreebsd*-gnu | darwin* | cygwin*) - lint_name=splint - lint_options="-badflag" - ;; - *freebsd* | *netbsd*) - lint_name=lint - lint_options="-u -b" - ;; - *solaris*) - lint_name=lint - lint_options="-u -b -h -erroff=E_INDISTING_FROM_TRUNC2" - ;; -esac - -# Test for the presence of the program (either guessed by the code or spelled out by the user) -if test "x$use_lint" = x"yes" ; then - AC_PATH_PROG([LINT], [$lint_name]) - if test "x$LINT" = "x"; then - AC_MSG_ERROR([--with-lint=yes specified but lint-style tool not found in PATH]) - fi -elif test "x$use_lint" = x"no" ; then - if test "x$LINT" != "x"; then - AC_MSG_WARN([ignoring LINT environment variable since --with-lint=no was specified]) - fi -else - AC_MSG_ERROR([--with-lint expects 'yes' or 'no'. Use LINT variable to specify path.]) -fi - -# User supplied flags override default flags -if test "x$LINT_FLAGS" != "x"; then - lint_options=$LINT_FLAGS -fi - -AC_SUBST([LINT_FLAGS],[$lint_options]) -AM_CONDITIONAL(LINT, [test "x$LINT" != x]) - -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1492: -1- AC_DEFUN([XORG_LINT_LIBRARY], [ -AC_REQUIRE([XORG_WITH_LINT]) -AC_ARG_ENABLE(lint-library, [AS_HELP_STRING([--enable-lint-library], - [Create lint library (default: disabled)])], - [make_lint_lib=$enableval], [make_lint_lib=no]) - -if test "x$make_lint_lib" = x"yes" ; then - LINTLIB=llib-l$1.ln - if test "x$LINT" = "x"; then - AC_MSG_ERROR([Cannot make lint library without --with-lint]) - fi -elif test "x$make_lint_lib" != x"no" ; then - AC_MSG_ERROR([--enable-lint-library expects 'yes' or 'no'.]) -fi - -AC_SUBST(LINTLIB) -AM_CONDITIONAL(MAKE_LINT_LIB, [test x$make_lint_lib != xno]) - -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1523: -1- AC_DEFUN([XORG_COMPILER_BRAND], [ -AC_LANG_CASE( - [C], [ - dnl autoconf-2.70 folded AC_PROG_CC_C99 into AC_PROG_CC - dnl and complains that AC_PROG_CC_C99 is obsolete - m4_version_prereq([2.70], - [AC_REQUIRE([AC_PROG_CC])], - [AC_REQUIRE([AC_PROG_CC_C99])]) - ], - [C++], [ - AC_REQUIRE([AC_PROG_CXX]) - ] -) -AC_CHECK_DECL([__clang__], [CLANGCC="yes"], [CLANGCC="no"]) -AC_CHECK_DECL([__INTEL_COMPILER], [INTELCC="yes"], [INTELCC="no"]) -AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1554: -1- AC_DEFUN([XORG_TESTSET_CFLAG], [ -m4_if([$#], 0, [m4_fatal([XORG_TESTSET_CFLAG was given with an unsupported number of arguments])]) -m4_if([$#], 1, [m4_fatal([XORG_TESTSET_CFLAG was given with an unsupported number of arguments])]) - -AC_LANG_COMPILER_REQUIRE - -AC_LANG_CASE( - [C], [ - dnl autoconf-2.70 folded AC_PROG_CC_C99 into AC_PROG_CC - dnl and complains that AC_PROG_CC_C99 is obsolete - m4_version_prereq([2.70], - [AC_REQUIRE([AC_PROG_CC])], - [AC_REQUIRE([AC_PROG_CC_C99])]) - define([PREFIX], [C]) - define([CACHE_PREFIX], [cc]) - define([COMPILER], [$CC]) - ], - [C++], [ - define([PREFIX], [CXX]) - define([CACHE_PREFIX], [cxx]) - define([COMPILER], [$CXX]) - ] -) - -[xorg_testset_save_]PREFIX[FLAGS]="$PREFIX[FLAGS]" - -if test "x$[xorg_testset_]CACHE_PREFIX[_unknown_warning_option]" = "x" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unknown-warning-option" - AC_CACHE_CHECK([if ]COMPILER[ supports -Werror=unknown-warning-option], - [xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option], - AC_COMPILE_IFELSE([AC_LANG_SOURCE([int i;])], - [xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option=yes], - [xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option=no])) - [xorg_testset_]CACHE_PREFIX[_unknown_warning_option]=$[xorg_cv_]CACHE_PREFIX[_flag_unknown_warning_option] - PREFIX[FLAGS]="$[xorg_testset_save_]PREFIX[FLAGS]" -fi - -if test "x$[xorg_testset_]CACHE_PREFIX[_unused_command_line_argument]" = "x" ; then - if test "x$[xorg_testset_]CACHE_PREFIX[_unknown_warning_option]" = "xyes" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unknown-warning-option" - fi - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unused-command-line-argument" - AC_CACHE_CHECK([if ]COMPILER[ supports -Werror=unused-command-line-argument], - [xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument], - AC_COMPILE_IFELSE([AC_LANG_SOURCE([int i;])], - [xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument=yes], - [xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument=no])) - [xorg_testset_]CACHE_PREFIX[_unused_command_line_argument]=$[xorg_cv_]CACHE_PREFIX[_flag_unused_command_line_argument] - PREFIX[FLAGS]="$[xorg_testset_save_]PREFIX[FLAGS]" -fi - -found="no" -m4_foreach([flag], m4_cdr($@), [ - if test $found = "no" ; then - if test "x$xorg_testset_]CACHE_PREFIX[_unknown_warning_option" = "xyes" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_]CACHE_PREFIX[_unused_command_line_argument" = "xyes" ; then - PREFIX[FLAGS]="$PREFIX[FLAGS] -Werror=unused-command-line-argument" - fi - - PREFIX[FLAGS]="$PREFIX[FLAGS] ]flag[" - -dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname - AC_MSG_CHECKING([if ]COMPILER[ supports ]flag[]) - cacheid=AS_TR_SH([xorg_cv_]CACHE_PREFIX[_flag_]flag[]) - AC_CACHE_VAL($cacheid, - [AC_LINK_IFELSE([AC_LANG_PROGRAM([int i;])], - [eval $cacheid=yes], - [eval $cacheid=no])]) - - PREFIX[FLAGS]="$[xorg_testset_save_]PREFIX[FLAGS]" - - eval supported=\$$cacheid - AC_MSG_RESULT([$supported]) - if test "$supported" = "yes" ; then - $1="$$1 ]flag[" - found="yes" - fi - fi -]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1650: -1- AC_DEFUN([XORG_COMPILER_FLAGS], [ -AC_REQUIRE([XORG_COMPILER_BRAND]) - -AC_ARG_ENABLE(selective-werror, - AS_HELP_STRING([--disable-selective-werror], - [Turn off selective compiler errors. (default: enabled)]), - [SELECTIVE_WERROR=$enableval], - [SELECTIVE_WERROR=yes]) - -AC_LANG_CASE( - [C], [ - define([PREFIX], [C]) - ], - [C++], [ - define([PREFIX], [CXX]) - ] -) -# -v is too short to test reliably with XORG_TESTSET_CFLAG -if test "x$SUNCC" = "xyes"; then - [BASE_]PREFIX[FLAGS]="-v" -else - [BASE_]PREFIX[FLAGS]="" -fi - -# This chunk of warnings were those that existed in the legacy CWARNFLAGS -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wall]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wpointer-arith]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-declarations]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wformat=2], [-Wformat]) - -AC_LANG_CASE( - [C], [ - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wstrict-prototypes]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-prototypes]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wnested-externs]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wbad-function-cast]) - XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wold-style-definition], [-fd]) - ] -) - -# This chunk adds additional warnings that could catch undesired effects. -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wunused]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wuninitialized]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wshadow]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-noreturn]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-format-attribute]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wredundant-decls]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wlogical-op]) - -# These are currently disabled because they are noisy. They will be enabled -# in the future once the codebase is sufficiently modernized to silence -# them. For now, I don't want them to drown out the other warnings. -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wparentheses]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-align]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-qual]) - -# Turn some warnings into errors, so we don't accidentally get successful builds -# when there are problems that should be fixed. - -if test "x$SELECTIVE_WERROR" = "xyes" ; then -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=implicit], [-errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=nonnull]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=init-self]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=main]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=missing-braces]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=sequence-point]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=return-type], [-errwarn=E_FUNC_HAS_NO_RETURN_STMT]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=trigraphs]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=array-bounds]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=write-strings]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=address]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=int-to-pointer-cast], [-errwarn=E_BAD_PTR_INT_COMBINATION]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Werror=pointer-to-int-cast]) # Also -errwarn=E_BAD_PTR_INT_COMBINATION -else -AC_MSG_WARN([You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wimplicit]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wnonnull]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Winit-self]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmain]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wmissing-braces]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wsequence-point]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wreturn-type]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wtrigraphs]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Warray-bounds]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wwrite-strings]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Waddress]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wint-to-pointer-cast]) -XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wpointer-to-int-cast]) -fi - -AC_SUBST([BASE_]PREFIX[FLAGS]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1755: -1- AC_DEFUN([XORG_CWARNFLAGS], [ -AC_REQUIRE([XORG_COMPILER_FLAGS]) -AC_REQUIRE([XORG_COMPILER_BRAND]) -AC_LANG_CASE( - [C], [ - CWARNFLAGS="$BASE_CFLAGS" - if test "x$GCC" = xyes ; then - CWARNFLAGS="$CWARNFLAGS -fno-strict-aliasing" - fi - AC_SUBST(CWARNFLAGS) - ] -) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1780: -1- AC_DEFUN([XORG_STRICT_OPTION], [ -AC_REQUIRE([XORG_CWARNFLAGS]) -AC_REQUIRE([XORG_COMPILER_FLAGS]) - -AC_ARG_ENABLE(strict-compilation, - AS_HELP_STRING([--enable-strict-compilation], - [Enable all warnings from compiler and make them errors (default: disabled)]), - [STRICT_COMPILE=$enableval], [STRICT_COMPILE=no]) - -AC_LANG_CASE( - [C], [ - define([PREFIX], [C]) - ], - [C++], [ - define([PREFIX], [CXX]) - ] -) - -[STRICT_]PREFIX[FLAGS]="" -XORG_TESTSET_CFLAG([[STRICT_]PREFIX[FLAGS]], [-pedantic]) -XORG_TESTSET_CFLAG([[STRICT_]PREFIX[FLAGS]], [-Werror], [-errwarn]) - -# Earlier versions of gcc (eg: 4.2) support -Werror=attributes, but do not -# activate it with -Werror, so we add it here explicitly. -XORG_TESTSET_CFLAG([[STRICT_]PREFIX[FLAGS]], [-Werror=attributes]) - -if test "x$STRICT_COMPILE" = "xyes"; then - [BASE_]PREFIX[FLAGS]="$[BASE_]PREFIX[FLAGS] $[STRICT_]PREFIX[FLAGS]" - AC_LANG_CASE([C], [CWARNFLAGS="$CWARNFLAGS $STRICT_CFLAGS"]) -fi -AC_SUBST([STRICT_]PREFIX[FLAGS]) -AC_SUBST([BASE_]PREFIX[FLAGS]) -AC_LANG_CASE([C], AC_SUBST([CWARNFLAGS])) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1822: -1- AC_DEFUN([XORG_DEFAULT_NOCODE_OPTIONS], [ -AC_REQUIRE([AC_PROG_INSTALL]) -XORG_RELEASE_VERSION -XORG_CHANGELOG -XORG_INSTALL -XORG_MANPAGE_SECTIONS -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], - [AC_SUBST([AM_DEFAULT_VERBOSITY], [1])]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1838: -1- AC_DEFUN([XORG_DEFAULT_OPTIONS], [ -AC_REQUIRE([AC_PROG_INSTALL]) -XORG_COMPILER_FLAGS -XORG_CWARNFLAGS -XORG_STRICT_OPTION -XORG_DEFAULT_NOCODE_OPTIONS -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1853: -1- AC_DEFUN([XORG_INSTALL], [ -AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -macros_datadir=`$PKG_CONFIG --print-errors --variable=pkgdatadir xorg-macros` -INSTALL_CMD="(cp -f "$macros_datadir/INSTALL" \$(top_srcdir)/.INSTALL.tmp && \ -mv \$(top_srcdir)/.INSTALL.tmp \$(top_srcdir)/INSTALL) \ -|| (rm -f \$(top_srcdir)/.INSTALL.tmp; test -e \$(top_srcdir)/INSTALL || ( \ -touch \$(top_srcdir)/INSTALL; \ -echo 'failed to copy INSTALL from util-macros: installing empty INSTALL.' >&2))" -AC_SUBST([INSTALL_CMD]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1892: -1- AC_DEFUN([XORG_RELEASE_VERSION], [ - AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MAJOR], - [`echo $PACKAGE_VERSION | cut -d . -f 1`], - [Major version of this package]) - PVM=`echo $PACKAGE_VERSION | cut -d . -f 2 | cut -d - -f 1` - if test "x$PVM" = "x"; then - PVM="0" - fi - AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MINOR], - [$PVM], - [Minor version of this package]) - PVP=`echo $PACKAGE_VERSION | cut -d . -f 3 | cut -d - -f 1` - if test "x$PVP" = "x"; then - PVP="0" - fi - AC_DEFINE_UNQUOTED([PACKAGE_VERSION_PATCHLEVEL], - [$PVP], - [Patch version of this package]) -]) -m4trace:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/aclocal/xorg-macros.m4:1920: -1- AC_DEFUN([XORG_CHANGELOG], [ -CHANGELOG_CMD="((GIT_DIR=\$(top_srcdir)/.git git log > \$(top_srcdir)/.changelog.tmp) 2>/dev/null && \ -mv \$(top_srcdir)/.changelog.tmp \$(top_srcdir)/ChangeLog) \ -|| (rm -f \$(top_srcdir)/.changelog.tmp; test -e \$(top_srcdir)/ChangeLog || ( \ -touch \$(top_srcdir)/ChangeLog; \ -echo 'git failed to create ChangeLog: installing empty ChangeLog.' >&2))" -AC_SUBST([CHANGELOG_CMD]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/amversion.m4:14: -1- AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.18' -dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to -dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.18.1], [], - [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/amversion.m4:33: -1- AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.18.1])dnl -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/auxdir.m4:47: -1- AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/cond.m4:12: -1- AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl - m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -m4_define([_AM_COND_VALUE_$1], [$2])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depend.m4:26: -1- AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl -AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl -AC_REQUIRE([AM_MAKE_INCLUDE])dnl -AC_REQUIRE([AM_DEP_TRACK])dnl - -m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], - [$1], [CXX], [depcc="$CXX" am_compiler_list=], - [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], - [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], - [$1], [UPC], [depcc="$UPC" am_compiler_list=], - [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], - [depcc="$$1" am_compiler_list=]) - -AC_CACHE_CHECK([dependency style of $depcc], - [am_cv_$1_dependencies_compiler_type], -[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_$1_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` - fi - am__universal=false - m4_case([$1], [CC], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac], - [CXX], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac]) - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thus: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_$1_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_$1_dependencies_compiler_type=none -fi -]) -AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) -AM_CONDITIONAL([am__fastdep$1], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depend.m4:163: -1- AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl -AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depend.m4:171: -1- AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl -AS_HELP_STRING( - [--enable-dependency-tracking], - [do not reject slow dependency extractors]) -AS_HELP_STRING( - [--disable-dependency-tracking], - [speeds up one-time build])]) -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi -AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -AC_SUBST([AMDEPBACKSLASH])dnl -_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl -AC_SUBST([am__nodep])dnl -_AM_SUBST_NOTMAKE([am__nodep])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depout.m4:11: -1- AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - AS_CASE([$CONFIG_FILES], - [*\'*], [eval set x "$CONFIG_FILES"], - [*], [set x $CONFIG_FILES]) - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`AS_DIRNAME(["$am_mf"])` - am_filepart=`AS_BASENAME(["$am_mf"])` - AM_RUN_LOG([cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles]) || am_rc=$? - done - if test $am_rc -ne 0; then - AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE="gmake" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking).]) - fi - AS_UNSET([am_dirpart]) - AS_UNSET([am_filepart]) - AS_UNSET([am_mf]) - AS_UNSET([am_rc]) - rm -f conftest-deps.mk -} -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/depout.m4:64: -1- AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], - [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/init.m4:29: -1- AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl -m4_ifdef([_$0_ALREADY_INIT], - [m4_fatal([$0 expanded multiple times -]m4_defn([_$0_ALREADY_INIT]))], - [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl -dnl Autoconf wants to disallow AM_ names. We explicitly allow -dnl the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl -AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl -AC_REQUIRE([AC_PROG_INSTALL])dnl -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[AC_DIAGNOSE([obsolete], - [$0: two- and three-arguments forms are deprecated.]) -m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl -dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. -m4_if( - m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), - [ok:ok],, - [m4_fatal([AC_INIT should be called with package and version arguments])])dnl - AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl - AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) - AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) -AM_MISSING_PROG([AUTOCONF], [autoconf]) -AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) -AM_MISSING_PROG([AUTOHEADER], [autoheader]) -AM_MISSING_PROG([MAKEINFO], [makeinfo]) -AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl -AC_REQUIRE([AC_PROG_MKDIR_P])dnl -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl -AC_REQUIRE([AM_SET_LEADING_DOT])dnl -_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], - [_AM_PROG_TAR([ustar])])])]) -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES([CC])], - [m4_define([AC_PROG_CC], - m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES([CXX])], - [m4_define([AC_PROG_CXX], - m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES([OBJC])], - [m4_define([AC_PROG_OBJC], - m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], - [_AM_DEPENDENCIES([OBJCXX])], - [m4_define([AC_PROG_OBJCXX], - m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl -]) -# Variables for tags utilities; see am/tags.am -if test -z "$CTAGS"; then - CTAGS=ctags -fi -AC_SUBST([CTAGS]) -if test -z "$ETAGS"; then - ETAGS=etags -fi -AC_SUBST([ETAGS]) -if test -z "$CSCOPE"; then - CSCOPE=cscope -fi -AC_SUBST([CSCOPE]) - -AC_REQUIRE([_AM_SILENT_RULES])dnl -dnl The testsuite driver may need to know about EXEEXT, so add the -dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This -dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. -AC_CONFIG_COMMANDS_PRE(dnl -[m4_provide_if([_AM_COMPILER_EXEEXT], - [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl - -AC_REQUIRE([_AM_PROG_RM_F]) -AC_REQUIRE([_AM_PROG_XARGS_N]) - -dnl The trailing newline in this macro's definition is deliberate, for -dnl backward compatibility and to allow trailing 'dnl'-style comments -dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/init.m4:167: -1- AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. -_am_arg=$1 -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/install-sh.m4:11: -1- AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi -AC_SUBST([install_sh])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/lead-dot.m4:10: -1- AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null -AC_SUBST([am__leading_dot])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/make.m4:13: -1- AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) -cat > confinc.mk << 'END' -am__doit: - @echo this is the am__doit target >confinc.out -.PHONY: am__doit -END -am__include="#" -am__quote= -# BSD make does it like this. -echo '.include "confinc.mk" # ignored' > confmf.BSD -# Other make implementations (GNU, Solaris 10, AIX) do it like this. -echo 'include confinc.mk # ignored' > confmf.GNU -_am_result=no -for s in GNU BSD; do - AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) - AS_CASE([$?:`cat confinc.out 2>/dev/null`], - ['0:this is the am__doit target'], - [AS_CASE([$s], - [BSD], [am__include='.include' am__quote='"'], - [am__include='include' am__quote=''])]) - if test "$am__include" != "#"; then - _am_result="yes ($s style)" - break - fi -done -rm -f confinc.* confmf.* -AC_MSG_RESULT([${_am_result}]) -AC_SUBST([am__include])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/make.m4:42: -1- m4_pattern_allow([^am__quote$]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/missing.m4:11: -1- AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/missing.m4:20: -1- AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([missing])dnl -if test x"${MISSING+set}" != xset; then - MISSING="\${SHELL} '$am_aux_dir/missing'" -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - AC_MSG_WARN(['missing' script is too old or missing]) -fi -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4:11: -1- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4:17: -1- AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4:23: -1- AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/options.m4:29: -1- AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/prog-cc-c-o.m4:12: -1- AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([compile])dnl -AC_LANG_PUSH([C])dnl -AC_CACHE_CHECK( - [whether $CC understands -c and -o together], - [am_cv_prog_cc_c_o], - [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - # aligned with autoconf, so not including core; see bug#72225. - rm -f -r a.out a.exe b.out conftest.$ac_ext conftest.$ac_objext \ - conftest.dSYM conftest1.$ac_ext conftest1.$ac_objext conftest1.dSYM \ - conftest2.$ac_ext conftest2.$ac_objext conftest2.dSYM - unset am_i]) -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -AC_LANG_POP([C])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/prog-cc-c-o.m4:50: -1- AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/rmf.m4:12: -1- AC_DEFUN([_AM_PROG_RM_F], [am__rm_f_notfound= -AS_IF([(rm -f && rm -fr && rm -rf) 2>/dev/null], [], [am__rm_f_notfound='""']) -AC_SUBST(am__rm_f_notfound) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/runlog.m4:12: -1- AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD - ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - (exit $ac_status); }]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/sanity.m4:11: -1- AC_DEFUN([_AM_SLEEP_FRACTIONAL_SECONDS], [dnl -AC_CACHE_CHECK([whether sleep supports fractional seconds], - am_cv_sleep_fractional_seconds, [dnl -AS_IF([sleep 0.001 2>/dev/null], [am_cv_sleep_fractional_seconds=yes], - [am_cv_sleep_fractional_seconds=no]) -])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/sanity.m4:28: -1- AC_DEFUN([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION], [dnl -AC_REQUIRE([_AM_SLEEP_FRACTIONAL_SECONDS]) -AC_CACHE_CHECK([filesystem timestamp resolution], - am_cv_filesystem_timestamp_resolution, [dnl -# Default to the worst case. -am_cv_filesystem_timestamp_resolution=2 - -# Only try to go finer than 1 sec if sleep can do it. -# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, -# - 1 sec is not much of a win compared to 2 sec, and -# - it takes 2 seconds to perform the test whether 1 sec works. -# -# Instead, just use the default 2s on platforms that have 1s resolution, -# accept the extra 1s delay when using $sleep in the Automake tests, in -# exchange for not incurring the 2s delay for running the test for all -# packages. -# -am_try_resolutions= -if test "$am_cv_sleep_fractional_seconds" = yes; then - # Even a millisecond often causes a bunch of false positives, - # so just try a hundredth of a second. The time saved between .001 and - # .01 is not terribly consequential. - am_try_resolutions="0.01 0.1 $am_try_resolutions" -fi - -# In order to catch current-generation FAT out, we must *modify* files -# that already exist; the *creation* timestamp is finer. Use names -# that make ls -t sort them differently when they have equal -# timestamps than when they have distinct timestamps, keeping -# in mind that ls -t prints the *newest* file first. -rm -f conftest.ts? -: > conftest.ts1 -: > conftest.ts2 -: > conftest.ts3 - -# Make sure ls -t actually works. Do 'set' in a subshell so we don't -# clobber the current shell's arguments. (Outer-level square brackets -# are removed by m4; they're present so that m4 does not expand -# ; be careful, easy to get confused.) -if ( - set X `[ls -t conftest.ts[12]]` && - { - test "$[]*" != "X conftest.ts1 conftest.ts2" || - test "$[]*" != "X conftest.ts2 conftest.ts1"; - } -); then :; else - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - _AS_ECHO_UNQUOTED( - ["Bad output from ls -t: \"`[ls -t conftest.ts[12]]`\""], - [AS_MESSAGE_LOG_FD]) - AC_MSG_FAILURE([ls -t produces unexpected output. -Make sure there is not a broken ls alias in your environment.]) -fi - -for am_try_res in $am_try_resolutions; do - # Any one fine-grained sleep might happen to cross the boundary - # between two values of a coarser actual resolution, but if we do - # two fine-grained sleeps in a row, at least one of them will fall - # entirely within a coarse interval. - echo alpha > conftest.ts1 - sleep $am_try_res - echo beta > conftest.ts2 - sleep $am_try_res - echo gamma > conftest.ts3 - - # We assume that 'ls -t' will make use of high-resolution - # timestamps if the operating system supports them at all. - if (set X `ls -t conftest.ts?` && - test "$[]2" = conftest.ts3 && - test "$[]3" = conftest.ts2 && - test "$[]4" = conftest.ts1); then - # - # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, - # because we don't need to test make. - make_ok=true - if test $am_try_res != 1; then - # But if we've succeeded so far with a subsecond resolution, we - # have one more thing to check: make. It can happen that - # everything else supports the subsecond mtimes, but make doesn't; - # notably on macOS, which ships make 3.81 from 2006 (the last one - # released under GPLv2). https://bugs.gnu.org/68808 - # - # We test $MAKE if it is defined in the environment, else "make". - # It might get overridden later, but our hope is that in practice - # it does not matter: it is the system "make" which is (by far) - # the most likely to be broken, whereas if the user overrides it, - # probably they did so with a better, or at least not worse, make. - # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html - # - # Create a Makefile (real tab character here): - rm -f conftest.mk - echo 'conftest.ts1: conftest.ts2' >conftest.mk - echo ' touch conftest.ts2' >>conftest.mk - # - # Now, running - # touch conftest.ts1; touch conftest.ts2; make - # should touch ts1 because ts2 is newer. This could happen by luck, - # but most often, it will fail if make's support is insufficient. So - # test for several consecutive successes. - # - # (We reuse conftest.ts[12] because we still want to modify existing - # files, not create new ones, per above.) - n=0 - make=${MAKE-make} - until test $n -eq 3; do - echo one > conftest.ts1 - sleep $am_try_res - echo two > conftest.ts2 # ts2 should now be newer than ts1 - if $make -f conftest.mk | grep 'up to date' >/dev/null; then - make_ok=false - break # out of $n loop - fi - n=`expr $n + 1` - done - fi - # - if $make_ok; then - # Everything we know to check worked out, so call this resolution good. - am_cv_filesystem_timestamp_resolution=$am_try_res - break # out of $am_try_res loop - fi - # Otherwise, we'll go on to check the next resolution. - fi -done -rm -f conftest.ts? -# (end _am_filesystem_timestamp_resolution) -])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/sanity.m4:161: -1- AC_DEFUN([AM_SANITY_CHECK], [AC_REQUIRE([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION]) -# This check should not be cached, as it may vary across builds of -# different projects. -AC_MSG_CHECKING([whether build environment is sane]) -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[[\\\"\#\$\&\'\`$am_lf]]*) - AC_MSG_RESULT([no]) - AC_MSG_ERROR([unsafe absolute working directory name]);; -esac -case $srcdir in - *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) - AC_MSG_RESULT([no]) - AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -am_build_env_is_sane=no -am_has_slept=no -rm -f conftest.file -for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[]*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - test "$[]2" = conftest.file - ); then - am_build_env_is_sane=yes - break - fi - # Just in case. - sleep "$am_cv_filesystem_timestamp_resolution" - am_has_slept=yes -done - -AC_MSG_RESULT([$am_build_env_is_sane]) -if test "$am_build_env_is_sane" = no; then - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi - -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -AS_IF([test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1],, [dnl - ( sleep "$am_cv_filesystem_timestamp_resolution" ) & - am_sleep_pid=$! -]) -AC_CONFIG_COMMANDS_PRE( - [AC_MSG_CHECKING([that generated files are newer than configure]) - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - AC_MSG_RESULT([done])]) -rm -f conftest.file -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/silent.m4:11: -1- AC_DEFUN([_AM_SILENT_RULES], [AM_DEFAULT_VERBOSITY=1 -AC_ARG_ENABLE([silent-rules], [dnl -AS_HELP_STRING( - [--enable-silent-rules], - [less verbose build output (undo: "make V=1")]) -AS_HELP_STRING( - [--disable-silent-rules], - [verbose build output (undo: "make V=0")])dnl -]) -dnl -dnl A few 'make' implementations (e.g., NonStop OS and NextStep) -dnl do not support nested variable expansions. -dnl See automake bug#9928 and bug#10237. -am_make=${MAKE-make} -AC_CACHE_CHECK([whether $am_make supports nested variables], - [am_cv_make_support_nested_variables], - [if AS_ECHO([['TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi]) -AC_SUBST([AM_V])dnl -AM_SUBST_NOTMAKE([AM_V])dnl -AC_SUBST([AM_DEFAULT_V])dnl -AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl -AC_SUBST([AM_DEFAULT_VERBOSITY])dnl -AM_BACKSLASH='\' -AC_SUBST([AM_BACKSLASH])dnl -_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl -dnl Delay evaluation of AM_DEFAULT_VERBOSITY to the end to allow multiple calls -dnl to AM_SILENT_RULES to change the default value. -AC_CONFIG_COMMANDS_PRE([dnl -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; -esac -if test $am_cv_make_support_nested_variables = yes; then - dnl Using '$V' instead of '$(V)' breaks IRIX make. - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi -])dnl -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/silent.m4:69: -1- AC_DEFUN([AM_SILENT_RULES], [AC_REQUIRE([_AM_SILENT_RULES]) -AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1])m4_newline -dnl We intentionally force a newline after the assignment, since a) nothing -dnl good can come of more text following, and b) that was the behavior -dnl before 1.17. See https://bugs.gnu.org/72267. -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/strip.m4:17: -1- AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/substnot.m4:12: -1- AC_DEFUN([_AM_SUBST_NOTMAKE]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/substnot.m4:17: -1- AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/tar.m4:23: -1- AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AC_SUBST([AMTAR], ['$${TAR-tar}']) - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' - -m4_if([$1], [v7], - [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], - - [m4_case([$1], - [ustar], - [# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) - if test x$am_uid = xunknown; then - AC_MSG_WARN([ancient id detected; assuming current UID is ok, but dist-ustar might not work]) - elif test $am_uid -le $am_max_uid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi - AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) - if test x$gm_gid = xunknown; then - AC_MSG_WARN([ancient id detected; assuming current GID is ok, but dist-ustar might not work]) - elif test $am_gid -le $am_max_gid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi], - - [pax], - [], - - [m4_fatal([Unknown tar format])]) - - AC_MSG_CHECKING([how to create a $1 tar archive]) - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_$1-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - AM_RUN_LOG([$_am_tar --version]) && break - done - am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x $1 -w "$$tardir"' - am__tar_='pax -L -x $1 -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H $1 -L' - am__tar_='find "$tardir" -print | cpio -o -H $1 -L' - am__untar='cpio -i -H $1 -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_$1}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) - rm -rf conftest.dir - if test -s conftest.tar; then - AM_RUN_LOG([$am__untar /dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) - AC_MSG_RESULT([$am_cv_prog_tar_$1])]) - -AC_SUBST([am__tar]) -AC_SUBST([am__untar]) -]) -m4trace:/home/linuxbrew/.linuxbrew/share/aclocal-1.18/xargsn.m4:12: -1- AC_DEFUN([_AM_PROG_XARGS_N], [AC_CACHE_CHECK([xargs -n works], am_cv_xargs_n_works, [dnl -AS_IF([test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 -3"], [am_cv_xargs_n_works=yes], [am_cv_xargs_n_works=no])]) -AS_IF([test "$am_cv_xargs_n_works" = yes], [am__xargs_n='xargs -n'], [dnl - am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "$@" "$am__xargs_n_arg"; done; }' -])dnl -AC_SUBST(am__xargs_n) -]) -m4trace:m4/ax_gcc_builtin.m4:95: -1- AC_DEFUN([AX_GCC_BUILTIN], [ - AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1]) - - AC_CACHE_CHECK([for $1], [ac_var], [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([], [ - m4_case([$1], - [__builtin_assume_aligned], [$1("", 0)], - [__builtin_bswap32], [$1(0)], - [__builtin_bswap64], [$1(0)], - [__builtin_choose_expr], [$1(0, 0, 0)], - [__builtin___clear_cache], [$1("", "")], - [__builtin_clrsb], [$1(0)], - [__builtin_clrsbl], [$1(0)], - [__builtin_clrsbll], [$1(0)], - [__builtin_clz], [$1(0)], - [__builtin_clzl], [$1(0)], - [__builtin_clzll], [$1(0)], - [__builtin_complex], [$1(0.0, 0.0)], - [__builtin_constant_p], [$1(0)], - [__builtin_ctz], [$1(0)], - [__builtin_ctzl], [$1(0)], - [__builtin_ctzll], [$1(0)], - [__builtin_expect], [$1(0, 0)], - [__builtin_ffs], [$1(0)], - [__builtin_ffsl], [$1(0)], - [__builtin_ffsll], [$1(0)], - [__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)], - [__builtin_huge_val], [$1()], - [__builtin_huge_valf], [$1()], - [__builtin_huge_vall], [$1()], - [__builtin_inf], [$1()], - [__builtin_infd128], [$1()], - [__builtin_infd32], [$1()], - [__builtin_infd64], [$1()], - [__builtin_inff], [$1()], - [__builtin_infl], [$1()], - [__builtin_isinf_sign], [$1(0.0)], - [__builtin_nan], [$1("")], - [__builtin_nand128], [$1("")], - [__builtin_nand32], [$1("")], - [__builtin_nand64], [$1("")], - [__builtin_nanf], [$1("")], - [__builtin_nanl], [$1("")], - [__builtin_nans], [$1("")], - [__builtin_nansf], [$1("")], - [__builtin_nansl], [$1("")], - [__builtin_object_size], [$1("", 0)], - [__builtin_parity], [$1(0)], - [__builtin_parityl], [$1(0)], - [__builtin_parityll], [$1(0)], - [__builtin_popcount], [$1(0)], - [__builtin_popcountl], [$1(0)], - [__builtin_popcountll], [$1(0)], - [__builtin_powi], [$1(0, 0)], - [__builtin_powif], [$1(0, 0)], - [__builtin_powil], [$1(0, 0)], - [__builtin_prefetch], [$1("")], - [__builtin_trap], [$1()], - [__builtin_types_compatible_p], [$1(int, int)], - [__builtin_unreachable], [$1()], - [m4_warn([syntax], [Unsupported built-in $1, the test may fail]) - $1()] - ) - ])], - [AS_VAR_SET([ac_var], [yes])], - [AS_VAR_SET([ac_var], [no])]) - ]) - - AS_IF([test yes = AS_VAR_GET([ac_var])], - [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1, - [Define to 1 if the system has the `$1' built-in function])], []) - - AS_VAR_POPDEF([ac_var]) -]) -m4trace:m4/libtool.m4:62: -1- AC_DEFUN([LT_INIT], [AC_PREREQ([2.64])dnl We use AC_PATH_PROGS_FEATURE_CHECK -AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl -AC_BEFORE([$0], [LT_LANG])dnl -AC_BEFORE([$0], [LT_OUTPUT])dnl -AC_BEFORE([$0], [LTDL_INIT])dnl -m4_require([_LT_CHECK_BUILDDIR])dnl - -dnl Autoconf doesn't catch unexpanded LT_ macros by default: -m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl -m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl -dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 -dnl unless we require an AC_DEFUNed macro: -AC_REQUIRE([LTOPTIONS_VERSION])dnl -AC_REQUIRE([LTSUGAR_VERSION])dnl -AC_REQUIRE([LTVERSION_VERSION])dnl -AC_REQUIRE([LTOBSOLETE_VERSION])dnl -m4_require([_LT_PROG_LTMAIN])dnl - -_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) - -dnl Parse OPTIONS -_LT_SET_OPTIONS([$0], [$1]) - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS=$ltmain - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' -AC_SUBST(LIBTOOL)dnl - -_LT_SETUP - -# Only expand once: -m4_define([LT_INIT]) -]) -m4trace:m4/libtool.m4:100: -1- AU_DEFUN([AC_PROG_LIBTOOL], [m4_if($#, 0, [LT_INIT], [LT_INIT($@)])], [], []) -m4trace:m4/libtool.m4:100: -1- AC_DEFUN([AC_PROG_LIBTOOL], [m4_warn([obsolete], [The macro 'AC_PROG_LIBTOOL' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_INIT], [LT_INIT($@)])]) -m4trace:m4/libtool.m4:101: -1- AU_DEFUN([AM_PROG_LIBTOOL], [m4_if($#, 0, [LT_INIT], [LT_INIT($@)])], [], []) -m4trace:m4/libtool.m4:101: -1- AC_DEFUN([AM_PROG_LIBTOOL], [m4_warn([obsolete], [The macro 'AM_PROG_LIBTOOL' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_INIT], [LT_INIT($@)])]) -m4trace:m4/libtool.m4:621: -1- AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} -AC_MSG_NOTICE([creating $CONFIG_LT]) -_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], -[# Run this file to recreate a libtool stub with the current configuration.]) - -cat >>"$CONFIG_LT" <<\_LTEOF -lt_cl_silent=false -exec AS_MESSAGE_LOG_FD>>config.log -{ - echo - AS_BOX([Running $as_me.]) -} >&AS_MESSAGE_LOG_FD - -lt_cl_help="\ -'$as_me' creates a local libtool stub from the current configuration, -for use in further configure time tests before the real libtool is -generated. - -Usage: $[0] [[OPTIONS]] - - -h, --help print this help, then exit - -V, --version print version number, then exit - -q, --quiet do not print progress messages - -d, --debug don't remove temporary files - -Report bugs to ." - -lt_cl_version="\ -m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl -m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) -configured by $[0], generated by m4_PACKAGE_STRING. - -Copyright (C) 2024 Free Software Foundation, Inc. -This config.lt script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -while test 0 != $[#] -do - case $[1] in - --version | --v* | -V ) - echo "$lt_cl_version"; exit 0 ;; - --help | --h* | -h ) - echo "$lt_cl_help"; exit 0 ;; - --debug | --d* | -d ) - debug=: ;; - --quiet | --q* | --silent | --s* | -q ) - lt_cl_silent=: ;; - - -*) AC_MSG_ERROR([unrecognized option: $[1] -Try '$[0] --help' for more information.]) ;; - - *) AC_MSG_ERROR([unrecognized argument: $[1] -Try '$[0] --help' for more information.]) ;; - esac - shift -done - -if $lt_cl_silent; then - exec AS_MESSAGE_FD>/dev/null -fi -_LTEOF - -cat >>"$CONFIG_LT" <<_LTEOF -_LT_OUTPUT_LIBTOOL_COMMANDS_INIT -_LTEOF - -cat >>"$CONFIG_LT" <<\_LTEOF -AC_MSG_NOTICE([creating $ofile]) -_LT_OUTPUT_LIBTOOL_COMMANDS -AS_EXIT(0) -_LTEOF -chmod +x "$CONFIG_LT" - -# configure is writing to config.log, but config.lt does its own redirection, -# appending to config.log, which fails on DOS, as config.log is still kept -# open by configure. Here we exec the FD to /dev/null, effectively closing -# config.log, so it can be properly (re)opened and appended to by config.lt. -lt_cl_success=: -test yes = "$silent" && - lt_config_lt_args="$lt_config_lt_args --quiet" -exec AS_MESSAGE_LOG_FD>/dev/null -$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false -exec AS_MESSAGE_LOG_FD>>config.log -$lt_cl_success || AS_EXIT(1) -]) -m4trace:m4/libtool.m4:813: -1- AC_DEFUN([LT_SUPPORTED_TAG], []) -m4trace:m4/libtool.m4:824: -1- AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl -m4_case([$1], - [C], [_LT_LANG(C)], - [C++], [_LT_LANG(CXX)], - [Go], [_LT_LANG(GO)], - [Java], [_LT_LANG(GCJ)], - [Fortran 77], [_LT_LANG(F77)], - [Fortran], [_LT_LANG(FC)], - [Windows Resource], [_LT_LANG(RC)], - [m4_ifdef([_LT_LANG_]$1[_CONFIG], - [_LT_LANG($1)], - [m4_fatal([$0: unsupported language: "$1"])])])dnl -]) -m4trace:m4/libtool.m4:916: -1- AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) -m4trace:m4/libtool.m4:916: -1- AC_DEFUN([AC_LIBTOOL_CXX], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_CXX' is obsolete. -You should run autoupdate.])dnl -LT_LANG(C++)]) -m4trace:m4/libtool.m4:917: -1- AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) -m4trace:m4/libtool.m4:917: -1- AC_DEFUN([AC_LIBTOOL_F77], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_F77' is obsolete. -You should run autoupdate.])dnl -LT_LANG(Fortran 77)]) -m4trace:m4/libtool.m4:918: -1- AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) -m4trace:m4/libtool.m4:918: -1- AC_DEFUN([AC_LIBTOOL_FC], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_FC' is obsolete. -You should run autoupdate.])dnl -LT_LANG(Fortran)]) -m4trace:m4/libtool.m4:919: -1- AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) -m4trace:m4/libtool.m4:919: -1- AC_DEFUN([AC_LIBTOOL_GCJ], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_GCJ' is obsolete. -You should run autoupdate.])dnl -LT_LANG(Java)]) -m4trace:m4/libtool.m4:920: -1- AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) -m4trace:m4/libtool.m4:920: -1- AC_DEFUN([AC_LIBTOOL_RC], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_RC' is obsolete. -You should run autoupdate.])dnl -LT_LANG(Windows Resource)]) -m4trace:m4/libtool.m4:1278: -1- AC_DEFUN([_LT_WITH_SYSROOT], [m4_require([_LT_DECL_SED])dnl -AC_MSG_CHECKING([for sysroot]) -AC_ARG_WITH([sysroot], -[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], - [Search for dependent libraries within DIR (or the compiler's sysroot - if not specified).])], -[], [with_sysroot=no]) - -dnl lt_sysroot will always be passed unquoted. We quote it here -dnl in case the user passed a directory name. -lt_sysroot= -case $with_sysroot in #( - yes) - if test yes = "$GCC"; then - # Trim trailing / since we'll always append absolute paths and we want - # to avoid //, if only for less confusing output for the user. - lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - AC_MSG_RESULT([$with_sysroot]) - AC_MSG_ERROR([The sysroot must be an absolute path.]) - ;; -esac - - AC_MSG_RESULT([${lt_sysroot:-no}]) -_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl -[dependent libraries, and where our libraries should be installed.])]) -m4trace:m4/libtool.m4:1618: -1- AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_DECL_SED])dnl -AC_CACHE_CHECK([$1], [$2], - [$2=no - m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - $2=yes - fi - fi - $RM conftest* -]) - -if test yes = "[$]$2"; then - m4_if([$5], , :, [$5]) -else - m4_if([$6], , :, [$6]) -fi -]) -m4trace:m4/libtool.m4:1660: -1- AU_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [m4_if($#, 0, [_LT_COMPILER_OPTION], [_LT_COMPILER_OPTION($@)])], [], []) -m4trace:m4/libtool.m4:1660: -1- AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_COMPILER_OPTION' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [_LT_COMPILER_OPTION], [_LT_COMPILER_OPTION($@)])]) -m4trace:m4/libtool.m4:1669: -1- AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_DECL_SED])dnl -AC_CACHE_CHECK([$1], [$2], - [$2=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $3" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&AS_MESSAGE_LOG_FD - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - $2=yes - fi - else - $2=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS -]) - -if test yes = "[$]$2"; then - m4_if([$4], , :, [$4]) -else - m4_if([$5], , :, [$5]) -fi -]) -m4trace:m4/libtool.m4:1704: -1- AU_DEFUN([AC_LIBTOOL_LINKER_OPTION], [m4_if($#, 0, [_LT_LINKER_OPTION], [_LT_LINKER_OPTION($@)])], [], []) -m4trace:m4/libtool.m4:1704: -1- AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_LINKER_OPTION' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [_LT_LINKER_OPTION], [_LT_LINKER_OPTION($@)])]) -m4trace:m4/libtool.m4:1711: -1- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl -# find the maximum length of command line arguments -AC_MSG_CHECKING([the maximum length of command line arguments]) -AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl - i=0 - teststring=ABCD - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu* | ironclad*) - # Under GNU Hurd and Ironclad, this test is not required because there - # is no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | windows* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[[ ]]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test X`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test 17 != "$i" # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac -]) -if test -n "$lt_cv_sys_max_cmd_len"; then - AC_MSG_RESULT($lt_cv_sys_max_cmd_len) -else - AC_MSG_RESULT(none) -fi -max_cmd_len=$lt_cv_sys_max_cmd_len -_LT_DECL([], [max_cmd_len], [0], - [What is the maximum length of a command?]) -]) -m4trace:m4/libtool.m4:1850: -1- AU_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [m4_if($#, 0, [LT_CMD_MAX_LEN], [LT_CMD_MAX_LEN($@)])], [], []) -m4trace:m4/libtool.m4:1850: -1- AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_SYS_MAX_CMD_LEN' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_CMD_MAX_LEN], [LT_CMD_MAX_LEN($@)])]) -m4trace:m4/libtool.m4:1961: -1- AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl -if test yes != "$enable_dlopen"; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen=load_add_on - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | windows* | pw32* | cegcc*) - lt_cv_dlopen=LoadLibrary - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ - lt_cv_dlopen=dyld - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ]) - ;; - - tpf*) - # Don't try to run any link tests for TPF. We know it's impossible - # because TPF is a cross-compiler, and we know how we open DSOs. - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - lt_cv_dlopen_self=no - ;; - - *) - AC_CHECK_FUNC([shl_load], - [lt_cv_dlopen=shl_load], - [AC_CHECK_LIB([dld], [shl_load], - [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], - [AC_CHECK_FUNC([dlopen], - [lt_cv_dlopen=dlopen], - [AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], - [AC_CHECK_LIB([svld], [dlopen], - [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], - [AC_CHECK_LIB([dld], [dld_link], - [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) - ]) - ]) - ]) - ]) - ]) - ;; - esac - - if test no = "$lt_cv_dlopen"; then - enable_dlopen=no - else - enable_dlopen=yes - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS=$CPPFLAGS - test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS=$LDFLAGS - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS=$LIBS - LIBS="$lt_cv_dlopen_libs $LIBS" - - AC_CACHE_CHECK([whether a program can dlopen itself], - lt_cv_dlopen_self, [dnl - _LT_TRY_DLOPEN_SELF( - lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, - lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) - ]) - - if test yes = "$lt_cv_dlopen_self"; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - AC_CACHE_CHECK([whether a statically linked program can dlopen itself], - lt_cv_dlopen_self_static, [dnl - _LT_TRY_DLOPEN_SELF( - lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, - lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) - ]) - fi - - CPPFLAGS=$save_CPPFLAGS - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi -_LT_DECL([dlopen_support], [enable_dlopen], [0], - [Whether dlopen is supported]) -_LT_DECL([dlopen_self], [enable_dlopen_self], [0], - [Whether dlopen of programs is supported]) -_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], - [Whether dlopen of statically linked programs is supported]) -]) -m4trace:m4/libtool.m4:2086: -1- AU_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [m4_if($#, 0, [LT_SYS_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF($@)])], [], []) -m4trace:m4/libtool.m4:2086: -1- AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_DLOPEN_SELF' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_SYS_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF($@)])]) -m4trace:m4/libtool.m4:3284: -1- AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl -AC_MSG_CHECKING([for $1]) -AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, -[case $MAGIC_CMD in -[[\\/*] | ?:[\\/]*]) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR -dnl $ac_dummy forces splitting on constant user-supplied paths. -dnl POSIX.2 word splitting is done only on the output of word expansions, -dnl not every word. This closes a longstanding sh security hole. - ac_dummy="m4_if([$2], , $PATH, [$2])" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$1"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"$1" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac]) -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - AC_MSG_RESULT($MAGIC_CMD) -else - AC_MSG_RESULT(no) -fi -_LT_DECL([], [MAGIC_CMD], [0], - [Used to examine libraries when file_magic_cmd begins with "file"])dnl -]) -m4trace:m4/libtool.m4:3346: -1- AU_DEFUN([AC_PATH_TOOL_PREFIX], [m4_if($#, 0, [_LT_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX($@)])], [], []) -m4trace:m4/libtool.m4:3346: -1- AC_DEFUN([AC_PATH_TOOL_PREFIX], [m4_warn([obsolete], [The macro 'AC_PATH_TOOL_PREFIX' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [_LT_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX($@)])]) -m4trace:m4/libtool.m4:3369: -1- AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -m4_require([_LT_DECL_SED])dnl -m4_require([_LT_DECL_EGREP])dnl -m4_require([_LT_PROG_ECHO_BACKSLASH])dnl - -AC_ARG_WITH([gnu-ld], - [AS_HELP_STRING([--with-gnu-ld], - [assume the C compiler uses GNU ld @<:@default=no@:>@])], - [test no = "$withval" || with_gnu_ld=yes], - [with_gnu_ld=no])dnl - -ac_prog=ld -if test yes = "$GCC"; then - # Check if gcc -print-prog-name=ld gives a path. - AC_MSG_CHECKING([for ld used by $CC]) - case $host in - *-*-mingw* | *-*-windows*) - # gcc leaves a trailing carriage return, which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [[\\/]]* | ?:[[\\/]]*) - re_direlt='/[[^/]][[^/]]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD=$ac_prog - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test yes = "$with_gnu_ld"; then - AC_MSG_CHECKING([for GNU ld]) -else - AC_MSG_CHECKING([for non-GNU ld]) -fi -AC_CACHE_VAL(lt_cv_path_LD, -[if test -z "$LD"; then - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD=$ac_dir/$ac_prog - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &1 | $SED '1q'` in - *$lt_bad_file* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break 2 - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break 2 - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS=$lt_save_ifs - done - : ${lt_cv_path_NM=no} -fi]) -if test no != "$lt_cv_path_NM"; then - NM=$lt_cv_path_NM -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols -headers" - ;; - *) - DUMPBIN=: - ;; - esac - fi - AC_SUBST([DUMPBIN]) - if test : != "$DUMPBIN"; then - NM=$DUMPBIN - fi -fi -test -z "$NM" && NM=nm -AC_SUBST([NM]) -_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl - -AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], - [lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&AS_MESSAGE_LOG_FD - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&AS_MESSAGE_LOG_FD - (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) - cat conftest.out >&AS_MESSAGE_LOG_FD - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest*]) -]) -m4trace:m4/libtool.m4:3890: -1- AU_DEFUN([AM_PROG_NM], [m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])], [], []) -m4trace:m4/libtool.m4:3890: -1- AC_DEFUN([AM_PROG_NM], [m4_warn([obsolete], [The macro 'AM_PROG_NM' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])]) -m4trace:m4/libtool.m4:3891: -1- AU_DEFUN([AC_PROG_NM], [m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])], [], []) -m4trace:m4/libtool.m4:3891: -1- AC_DEFUN([AC_PROG_NM], [m4_warn([obsolete], [The macro 'AC_PROG_NM' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])]) -m4trace:m4/libtool.m4:3962: -1- AC_DEFUN([_LT_DLL_DEF_P], [dnl - test DEF = "`$SED -n dnl - -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace - -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments - -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl - -e q dnl Only consider the first "real" line - $1`" dnl -]) -m4trace:m4/libtool.m4:3976: -1- AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl -LIBM= -case $host in -*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-mingw* | *-*-pw32* | *-*-darwin*) - # These system don't have libm, or don't need it - ;; -*-ncr-sysv4.3*) - AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) - AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") - ;; -*) - AC_CHECK_LIB(m, cos, LIBM=-lm) - ;; -esac -AC_SUBST([LIBM]) -]) -m4trace:m4/libtool.m4:3995: -1- AU_DEFUN([AC_CHECK_LIBM], [m4_if($#, 0, [LT_LIB_M], [LT_LIB_M($@)])], [], []) -m4trace:m4/libtool.m4:3995: -1- AC_DEFUN([AC_CHECK_LIBM], [m4_warn([obsolete], [The macro 'AC_CHECK_LIBM' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_LIB_M], [LT_LIB_M($@)])]) -m4trace:m4/libtool.m4:8300: -1- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], - [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], - [AC_CHECK_TOOL(GCJ, gcj,) - test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" - AC_SUBST(GCJFLAGS)])])[]dnl -]) -m4trace:m4/libtool.m4:8309: -1- AU_DEFUN([LT_AC_PROG_GCJ], [m4_if($#, 0, [LT_PROG_GCJ], [LT_PROG_GCJ($@)])], [], []) -m4trace:m4/libtool.m4:8309: -1- AC_DEFUN([LT_AC_PROG_GCJ], [m4_warn([obsolete], [The macro 'LT_AC_PROG_GCJ' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_PROG_GCJ], [LT_PROG_GCJ($@)])]) -m4trace:m4/libtool.m4:8316: -1- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) -]) -m4trace:m4/libtool.m4:8323: -1- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) -]) -m4trace:m4/libtool.m4:8328: -1- AU_DEFUN([LT_AC_PROG_RC], [m4_if($#, 0, [LT_PROG_RC], [LT_PROG_RC($@)])], [], []) -m4trace:m4/libtool.m4:8328: -1- AC_DEFUN([LT_AC_PROG_RC], [m4_warn([obsolete], [The macro 'LT_AC_PROG_RC' is obsolete. -You should run autoupdate.])dnl -m4_if($#, 0, [LT_PROG_RC], [LT_PROG_RC($@)])]) -m4trace:m4/ltoptions.m4:14: -1- AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) -m4trace:m4/ltoptions.m4:113: -1- AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'dlopen' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltoptions.m4:113: -1- AC_DEFUN([AC_LIBTOOL_DLOPEN], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_DLOPEN' is obsolete. -You should run autoupdate.])dnl -_LT_SET_OPTION([LT_INIT], [dlopen]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'dlopen' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltoptions.m4:148: -1- AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl -_LT_SET_OPTION([LT_INIT], [win32-dll]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'win32-dll' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltoptions.m4:148: -1- AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_WIN32_DLL' is obsolete. -You should run autoupdate.])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -_LT_SET_OPTION([LT_INIT], [win32-dll]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'win32-dll' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltoptions.m4:197: -1- AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) -]) -m4trace:m4/ltoptions.m4:201: -1- AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) -]) -m4trace:m4/ltoptions.m4:205: -1- AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) -m4trace:m4/ltoptions.m4:205: -1- AC_DEFUN([AM_ENABLE_SHARED], [m4_warn([obsolete], [The macro 'AM_ENABLE_SHARED' is obsolete. -You should run autoupdate.])dnl -AC_ENABLE_SHARED($@)]) -m4trace:m4/ltoptions.m4:206: -1- AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) -m4trace:m4/ltoptions.m4:206: -1- AC_DEFUN([AM_DISABLE_SHARED], [m4_warn([obsolete], [The macro 'AM_DISABLE_SHARED' is obsolete. -You should run autoupdate.])dnl -AC_DISABLE_SHARED($@)]) -m4trace:m4/ltoptions.m4:251: -1- AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) -]) -m4trace:m4/ltoptions.m4:255: -1- AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) -]) -m4trace:m4/ltoptions.m4:259: -1- AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) -m4trace:m4/ltoptions.m4:259: -1- AC_DEFUN([AM_ENABLE_STATIC], [m4_warn([obsolete], [The macro 'AM_ENABLE_STATIC' is obsolete. -You should run autoupdate.])dnl -AC_ENABLE_STATIC($@)]) -m4trace:m4/ltoptions.m4:260: -1- AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) -m4trace:m4/ltoptions.m4:260: -1- AC_DEFUN([AM_DISABLE_STATIC], [m4_warn([obsolete], [The macro 'AM_DISABLE_STATIC' is obsolete. -You should run autoupdate.])dnl -AC_DISABLE_STATIC($@)]) -m4trace:m4/ltoptions.m4:305: -1- AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you put -the 'fast-install' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltoptions.m4:305: -1- AC_DEFUN([AC_ENABLE_FAST_INSTALL], [m4_warn([obsolete], [The macro 'AC_ENABLE_FAST_INSTALL' is obsolete. -You should run autoupdate.])dnl -_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you put -the 'fast-install' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltoptions.m4:312: -1- AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you put -the 'disable-fast-install' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltoptions.m4:312: -1- AC_DEFUN([AC_DISABLE_FAST_INSTALL], [m4_warn([obsolete], [The macro 'AC_DISABLE_FAST_INSTALL' is obsolete. -You should run autoupdate.])dnl -_LT_SET_OPTION([LT_INIT], [disable-fast-install]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you put -the 'disable-fast-install' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltoptions.m4:441: -1- AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'pic-only' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltoptions.m4:441: -1- AC_DEFUN([AC_LIBTOOL_PICMODE], [m4_warn([obsolete], [The macro 'AC_LIBTOOL_PICMODE' is obsolete. -You should run autoupdate.])dnl -_LT_SET_OPTION([LT_INIT], [pic-only]) -AC_DIAGNOSE([obsolete], -[$0: Remove this warning and the call to _LT_SET_OPTION when you -put the 'pic-only' option into LT_INIT's first parameter.]) -]) -m4trace:m4/ltsugar.m4:14: -1- AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) -m4trace:m4/ltversion.m4:19: -1- AC_DEFUN([LTVERSION_VERSION], [macro_version='2.5.4' -macro_revision='2.5.4' -_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) -_LT_DECL(, macro_revision, 0) -]) -m4trace:m4/lt~obsolete.m4:37: -1- AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) -m4trace:m4/lt~obsolete.m4:41: -1- AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH]) -m4trace:m4/lt~obsolete.m4:42: -1- AC_DEFUN([_LT_AC_SHELL_INIT]) -m4trace:m4/lt~obsolete.m4:43: -1- AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX]) -m4trace:m4/lt~obsolete.m4:45: -1- AC_DEFUN([_LT_AC_TAGVAR]) -m4trace:m4/lt~obsolete.m4:46: -1- AC_DEFUN([AC_LTDL_ENABLE_INSTALL]) -m4trace:m4/lt~obsolete.m4:47: -1- AC_DEFUN([AC_LTDL_PREOPEN]) -m4trace:m4/lt~obsolete.m4:48: -1- AC_DEFUN([_LT_AC_SYS_COMPILER]) -m4trace:m4/lt~obsolete.m4:49: -1- AC_DEFUN([_LT_AC_LOCK]) -m4trace:m4/lt~obsolete.m4:50: -1- AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE]) -m4trace:m4/lt~obsolete.m4:51: -1- AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF]) -m4trace:m4/lt~obsolete.m4:52: -1- AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O]) -m4trace:m4/lt~obsolete.m4:53: -1- AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS]) -m4trace:m4/lt~obsolete.m4:54: -1- AC_DEFUN([AC_LIBTOOL_OBJDIR]) -m4trace:m4/lt~obsolete.m4:55: -1- AC_DEFUN([AC_LTDL_OBJDIR]) -m4trace:m4/lt~obsolete.m4:56: -1- AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH]) -m4trace:m4/lt~obsolete.m4:57: -1- AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP]) -m4trace:m4/lt~obsolete.m4:58: -1- AC_DEFUN([AC_PATH_MAGIC]) -m4trace:m4/lt~obsolete.m4:59: -1- AC_DEFUN([AC_PROG_LD_GNU]) -m4trace:m4/lt~obsolete.m4:60: -1- AC_DEFUN([AC_PROG_LD_RELOAD_FLAG]) -m4trace:m4/lt~obsolete.m4:61: -1- AC_DEFUN([AC_DEPLIBS_CHECK_METHOD]) -m4trace:m4/lt~obsolete.m4:62: -1- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI]) -m4trace:m4/lt~obsolete.m4:63: -1- AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) -m4trace:m4/lt~obsolete.m4:64: -1- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC]) -m4trace:m4/lt~obsolete.m4:65: -1- AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS]) -m4trace:m4/lt~obsolete.m4:66: -1- AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP]) -m4trace:m4/lt~obsolete.m4:67: -1- AC_DEFUN([LT_AC_PROG_EGREP]) -m4trace:m4/lt~obsolete.m4:68: -1- AC_DEFUN([LT_AC_PROG_SED]) -m4trace:m4/lt~obsolete.m4:72: -1- AC_DEFUN([_AC_PROG_LIBTOOL]) -m4trace:m4/lt~obsolete.m4:73: -1- AC_DEFUN([AC_LIBTOOL_SETUP]) -m4trace:m4/lt~obsolete.m4:74: -1- AC_DEFUN([_LT_AC_CHECK_DLFCN]) -m4trace:m4/lt~obsolete.m4:75: -1- AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) -m4trace:m4/lt~obsolete.m4:76: -1- AC_DEFUN([_LT_AC_TAGCONFIG]) -m4trace:m4/lt~obsolete.m4:78: -1- AC_DEFUN([_LT_AC_LANG_CXX]) -m4trace:m4/lt~obsolete.m4:79: -1- AC_DEFUN([_LT_AC_LANG_F77]) -m4trace:m4/lt~obsolete.m4:80: -1- AC_DEFUN([_LT_AC_LANG_GCJ]) -m4trace:m4/lt~obsolete.m4:81: -1- AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG]) -m4trace:m4/lt~obsolete.m4:82: -1- AC_DEFUN([_LT_AC_LANG_C_CONFIG]) -m4trace:m4/lt~obsolete.m4:83: -1- AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG]) -m4trace:m4/lt~obsolete.m4:84: -1- AC_DEFUN([_LT_AC_LANG_CXX_CONFIG]) -m4trace:m4/lt~obsolete.m4:85: -1- AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG]) -m4trace:m4/lt~obsolete.m4:86: -1- AC_DEFUN([_LT_AC_LANG_F77_CONFIG]) -m4trace:m4/lt~obsolete.m4:87: -1- AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG]) -m4trace:m4/lt~obsolete.m4:88: -1- AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG]) -m4trace:m4/lt~obsolete.m4:89: -1- AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG]) -m4trace:m4/lt~obsolete.m4:90: -1- AC_DEFUN([_LT_AC_LANG_RC_CONFIG]) -m4trace:m4/lt~obsolete.m4:91: -1- AC_DEFUN([AC_LIBTOOL_CONFIG]) -m4trace:m4/lt~obsolete.m4:92: -1- AC_DEFUN([_LT_AC_FILE_LTDLL_C]) -m4trace:m4/lt~obsolete.m4:94: -1- AC_DEFUN([_LT_AC_PROG_CXXCPP]) -m4trace:m4/lt~obsolete.m4:97: -1- AC_DEFUN([_LT_PROG_F77]) -m4trace:m4/lt~obsolete.m4:98: -1- AC_DEFUN([_LT_PROG_FC]) -m4trace:m4/lt~obsolete.m4:99: -1- AC_DEFUN([_LT_PROG_CXX]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?A[CHUM]_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([_AC_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section 'AC_LIBOBJ vs LIBOBJS']) -m4trace:configure.ac:4: -1- m4_pattern_allow([^AS_FLAGS$]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?m4_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^dnl$]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?AS_]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^SHELL$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PATH_SEPARATOR$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^exec_prefix$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^prefix$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^program_transform_name$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^bindir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sbindir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^libexecdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^datarootdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^datadir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sysconfdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sharedstatedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^localstatedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^runstatedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^includedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^oldincludedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^docdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^infodir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^htmldir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^dvidir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^pdfdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^psdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^libdir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^localedir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^mandir$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^DEFS$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^build_alias$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^host_alias$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^target_alias$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_C$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_N$]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_T$]) -m4trace:configure.ac:8: -1- AC_CONFIG_MACRO_DIR([m4]) -m4trace:configure.ac:8: -1- AC_CONFIG_MACRO_DIR_TRACE([m4]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_stdio_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" stdio.h ]AS_TR_SH([stdio.h]) AS_TR_CPP([HAVE_stdio.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CFLAGS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^LDFLAGS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CPPFLAGS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^ac_ct_CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^EXEEXT$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^OBJEXT$]) -m4trace:configure.ac:13: -1- _AM_PROG_CC_C_O -m4trace:configure.ac:13: -1- AM_AUX_DIR_EXPAND -m4trace:configure.ac:13: -1- AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_stdlib_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" stdlib.h ]AS_TR_SH([stdlib.h]) AS_TR_CPP([HAVE_stdlib.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_string_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" string.h ]AS_TR_SH([string.h]) AS_TR_CPP([HAVE_string.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_inttypes_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" inttypes.h ]AS_TR_SH([inttypes.h]) AS_TR_CPP([HAVE_inttypes.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_stdint_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" stdint.h ]AS_TR_SH([stdint.h]) AS_TR_CPP([HAVE_stdint.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_strings_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" strings.h ]AS_TR_SH([strings.h]) AS_TR_CPP([HAVE_strings.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_sys_stat_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" sys/stat.h ]AS_TR_SH([sys/stat.h]) AS_TR_CPP([HAVE_sys/stat.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_sys_types_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" sys/types.h ]AS_TR_SH([sys/types.h]) AS_TR_CPP([HAVE_sys/types.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_unistd_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" unistd.h ]AS_TR_SH([unistd.h]) AS_TR_CPP([HAVE_unistd.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^STDC_HEADERS$]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_wchar_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" wchar.h ]AS_TR_SH([wchar.h]) AS_TR_CPP([HAVE_wchar.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- AC_DEFUN([_AC_Header_minix_config_h], [m4_divert_text([INIT_PREPARE], - [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], - [" minix/config.h ]AS_TR_SH([minix/config.h]) AS_TR_CPP([HAVE_minix/config.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_ALL_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_COSMO_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_DARWIN_C_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_GNU_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_HPUX_ALT_XOPEN_SOCKET_API$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_NETBSD_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_OPENBSD_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_PTHREAD_SEMANTICS$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_ATTRIBS_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_BFP_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_DFP_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_FUNCS_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_TYPES_EXT__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_LIB_EXT2__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_MATH_SPEC_FUNCS__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_TANDEM_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_MINIX$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_1_SOURCE$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__EXTENSIONS__$]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_XOPEN_SOURCE$]) -m4trace:configure.ac:16: -1- AM_INIT_AUTOMAKE([foreign dist-xz]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_[A-Z]+FLAGS$]) -m4trace:configure.ac:16: -1- AM_SET_CURRENT_AUTOMAKE_VERSION -m4trace:configure.ac:16: -1- AM_AUTOMAKE_VERSION([1.18.1]) -m4trace:configure.ac:16: -1- _AM_AUTOCONF_VERSION([2.73]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_PROGRAM$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_SCRIPT$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_DATA$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__isrc$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__isrc]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CYGPATH_W$]) -m4trace:configure.ac:16: -1- _AM_SET_OPTIONS([foreign dist-xz]) -m4trace:configure.ac:16: -1- _AM_SET_OPTION([foreign]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([foreign]) -m4trace:configure.ac:16: -1- _AM_SET_OPTION([dist-xz]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([dist-xz]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^PACKAGE$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^VERSION$]) -m4trace:configure.ac:16: -1- _AM_IF_OPTION([no-define], [], [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) - AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([no-define]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^PACKAGE$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^VERSION$]) -m4trace:configure.ac:16: -1- AM_SANITY_CHECK -m4trace:configure.ac:16: -1- _AM_FILESYSTEM_TIMESTAMP_RESOLUTION -m4trace:configure.ac:16: -1- _AM_SLEEP_FRACTIONAL_SECONDS -m4trace:configure.ac:16: -1- AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) -m4trace:configure.ac:16: -1- AM_MISSING_HAS_RUN -m4trace:configure.ac:16: -1- m4_pattern_allow([^ACLOCAL$]) -m4trace:configure.ac:16: -1- AM_MISSING_PROG([AUTOCONF], [autoconf]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOCONF$]) -m4trace:configure.ac:16: -1- AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOMAKE$]) -m4trace:configure.ac:16: -1- AM_MISSING_PROG([AUTOHEADER], [autoheader]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOHEADER$]) -m4trace:configure.ac:16: -1- AM_MISSING_PROG([MAKEINFO], [makeinfo]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^MAKEINFO$]) -m4trace:configure.ac:16: -1- AM_PROG_INSTALL_SH -m4trace:configure.ac:16: -1- m4_pattern_allow([^install_sh$]) -m4trace:configure.ac:16: -1- AM_PROG_INSTALL_STRIP -m4trace:configure.ac:16: -1- m4_pattern_allow([^STRIP$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_STRIP_PROGRAM$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^MKDIR_P$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^mkdir_p$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AWK$]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^SET_MAKE$]) -m4trace:configure.ac:16: -1- AM_SET_LEADING_DOT -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__leading_dot$]) -m4trace:configure.ac:16: -1- _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], - [_AM_PROG_TAR([ustar])])])]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([tar-ustar]) -m4trace:configure.ac:16: -1- _AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], - [_AM_PROG_TAR([ustar])])]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([tar-pax]) -m4trace:configure.ac:16: -1- _AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], [_AM_PROG_TAR([ustar])]) -m4trace:configure.ac:16: -2- _AM_MANGLE_OPTION([tar-v7]) -m4trace:configure.ac:16: -1- _AM_PROG_TAR([ustar]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMTAR$]) -m4trace:configure.ac:16: -1- AM_RUN_LOG([$_am_tar --version]) -m4trace:configure.ac:16: -1- AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) -m4trace:configure.ac:16: -1- AM_RUN_LOG([$am__untar = 1.8])], [XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools`], [m4_ifval([1.8],[:], - [if test x"$cross_compiling" != x"yes" ; then - AC_CHECK_FILE([$prefix/share/sgml/X11/defs.ent], - [XORG_SGML_PATH=$prefix/share/sgml]) - fi]) - ]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^XORG_SGML_PATH$]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^STYLESHEET_SRCDIR$]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^XSL_STYLESHEET$]) -m4trace:configure.ac:30: -1- AM_CONDITIONAL([HAVE_STYLESHEETS], [test "x$XSL_STYLESHEET" != "x"]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^HAVE_STYLESHEETS_TRUE$]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^HAVE_STYLESHEETS_FALSE$]) -m4trace:configure.ac:30: -1- _AM_SUBST_NOTMAKE([HAVE_STYLESHEETS_TRUE]) -m4trace:configure.ac:30: -1- _AM_SUBST_NOTMAKE([HAVE_STYLESHEETS_FALSE]) -m4trace:configure.ac:31: -1- XORG_CHECK_MALLOC_ZERO -m4trace:configure.ac:31: -1- m4_pattern_allow([^MALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^XMALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^XTMALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:42: -1- m4_pattern_allow([^XEXT_SOREV$]) -m4trace:configure.ac:45: -1- PKG_CHECK_MODULES([XEXT], [xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99]) -m4trace:configure.ac:45: -1- m4_pattern_allow([^XEXT_CFLAGS$]) -m4trace:configure.ac:45: -1- m4_pattern_allow([^XEXT_LIBS$]) -m4trace:configure.ac:45: -1- PKG_CHECK_EXISTS([xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99], [pkg_cv_[]XEXT_CFLAGS=`$PKG_CONFIG --[]cflags "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) -m4trace:configure.ac:45: -1- PKG_CHECK_EXISTS([xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99], [pkg_cv_[]XEXT_LIBS=`$PKG_CONFIG --[]libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) -m4trace:configure.ac:45: -1- _PKG_SHORT_ERRORS_SUPPORTED -m4trace:configure.ac:47: -1- AX_GCC_BUILTIN([__builtin_popcountl]) -m4trace:configure.ac:47: -1- m4_pattern_allow([^HAVE___BUILTIN_POPCOUNTL$]) -m4trace:configure.ac:48: -1- m4_pattern_allow([^HAVE_REALLOCARRAY$]) -m4trace:configure.ac:48: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:51: -1- XORG_WITH_LINT -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT$]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FLAGS$]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT$]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FLAGS$]) -m4trace:configure.ac:51: -1- AM_CONDITIONAL([LINT], [test "x$LINT" != x]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_TRUE$]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FALSE$]) -m4trace:configure.ac:51: -1- _AM_SUBST_NOTMAKE([LINT_TRUE]) -m4trace:configure.ac:51: -1- _AM_SUBST_NOTMAKE([LINT_FALSE]) -m4trace:configure.ac:52: -1- XORG_LINT_LIBRARY([Xext]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^LINTLIB$]) -m4trace:configure.ac:52: -1- AM_CONDITIONAL([MAKE_LINT_LIB], [test x$make_lint_lib != xno]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^MAKE_LINT_LIB_TRUE$]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^MAKE_LINT_LIB_FALSE$]) -m4trace:configure.ac:52: -1- _AM_SUBST_NOTMAKE([MAKE_LINT_LIB_TRUE]) -m4trace:configure.ac:52: -1- _AM_SUBST_NOTMAKE([MAKE_LINT_LIB_FALSE]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:59: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:59: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:59: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:59: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) -m4trace:configure.ac:59: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS -m4trace:configure.ac:59: -1- AM_RUN_LOG([cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles]) -m4trace:configure.ac:59: -1- _LT_PROG_LTMAIN diff --git a/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.3 b/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.3 deleted file mode 100644 index 8316de261..000000000 --- a/experiments/wasm-gui/third_party/libXext/autom4te.cache/traces.3 +++ /dev/null @@ -1,929 +0,0 @@ -m4trace:aclocal.m4:2934: -1- AC_SUBST([am__quote]) -m4trace:aclocal.m4:2934: -1- AC_SUBST_TRACE([am__quote]) -m4trace:aclocal.m4:2934: -1- m4_pattern_allow([^am__quote$]) -m4trace:aclocal.m4:3590: -1- m4_include([m4/ax_gcc_builtin.m4]) -m4trace:aclocal.m4:3591: -1- m4_include([m4/libtool.m4]) -m4trace:aclocal.m4:3592: -1- m4_include([m4/ltoptions.m4]) -m4trace:aclocal.m4:3593: -1- m4_include([m4/ltsugar.m4]) -m4trace:aclocal.m4:3594: -1- m4_include([m4/ltversion.m4]) -m4trace:aclocal.m4:3595: -1- m4_include([m4/lt~obsolete.m4]) -m4trace:configure.ac:4: -1- AC_INIT([libXext], [1.3.7], [https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues], [libXext]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?A[CHUM]_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([_AC_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section 'AC_LIBOBJ vs LIBOBJS']) -m4trace:configure.ac:4: -1- m4_pattern_allow([^AS_FLAGS$]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?m4_]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^dnl$]) -m4trace:configure.ac:4: -1- m4_pattern_forbid([^_?AS_]) -m4trace:configure.ac:4: -1- AC_SUBST([SHELL]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([SHELL]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^SHELL$]) -m4trace:configure.ac:4: -1- AC_SUBST([PATH_SEPARATOR]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PATH_SEPARATOR]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PATH_SEPARATOR$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME], ['AC_PACKAGE_NAME'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_NAME]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME], ['AC_PACKAGE_TARNAME'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_TARNAME]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION], ['AC_PACKAGE_VERSION'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_VERSION]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_STRING]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_BUGREPORT]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_URL], [m4_ifdef([AC_PACKAGE_URL], ['AC_PACKAGE_URL'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_URL]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:4: -1- AC_SUBST([exec_prefix], [NONE]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([exec_prefix]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^exec_prefix$]) -m4trace:configure.ac:4: -1- AC_SUBST([prefix], [NONE]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([prefix]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^prefix$]) -m4trace:configure.ac:4: -1- AC_SUBST([program_transform_name], [s,x,x,]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([program_transform_name]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^program_transform_name$]) -m4trace:configure.ac:4: -1- AC_SUBST([bindir], ['${exec_prefix}/bin']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([bindir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^bindir$]) -m4trace:configure.ac:4: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([sbindir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sbindir$]) -m4trace:configure.ac:4: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([libexecdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^libexecdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([datarootdir], ['${prefix}/share']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([datarootdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^datarootdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([datadir], ['${datarootdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([datadir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^datadir$]) -m4trace:configure.ac:4: -1- AC_SUBST([sysconfdir], ['${prefix}/etc']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([sysconfdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sysconfdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([sharedstatedir], ['${prefix}/com']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([sharedstatedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^sharedstatedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([localstatedir], ['${prefix}/var']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([localstatedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^localstatedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([runstatedir], ['${localstatedir}/run']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([runstatedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^runstatedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([includedir], ['${prefix}/include']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([includedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^includedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([oldincludedir], ['/usr/include']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([oldincludedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^oldincludedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([docdir], [m4_ifset([AC_PACKAGE_TARNAME], - ['${datarootdir}/doc/${PACKAGE_TARNAME}'], - ['${datarootdir}/doc/${PACKAGE}'])]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([docdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^docdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([infodir], ['${datarootdir}/info']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([infodir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^infodir$]) -m4trace:configure.ac:4: -1- AC_SUBST([htmldir], ['${docdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([htmldir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^htmldir$]) -m4trace:configure.ac:4: -1- AC_SUBST([dvidir], ['${docdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([dvidir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^dvidir$]) -m4trace:configure.ac:4: -1- AC_SUBST([pdfdir], ['${docdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([pdfdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^pdfdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([psdir], ['${docdir}']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([psdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^psdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([libdir], ['${exec_prefix}/lib']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([libdir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^libdir$]) -m4trace:configure.ac:4: -1- AC_SUBST([localedir], ['${datarootdir}/locale']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([localedir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^localedir$]) -m4trace:configure.ac:4: -1- AC_SUBST([mandir], ['${datarootdir}/man']) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([mandir]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^mandir$]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_NAME$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */ -@%:@undef PACKAGE_NAME]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */ -@%:@undef PACKAGE_TARNAME]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_VERSION$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */ -@%:@undef PACKAGE_VERSION]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_STRING$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */ -@%:@undef PACKAGE_STRING]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */ -@%:@undef PACKAGE_BUGREPORT]) -m4trace:configure.ac:4: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_URL]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_URL$]) -m4trace:configure.ac:4: -1- AH_OUTPUT([PACKAGE_URL], [/* Define to the home page for this package. */ -@%:@undef PACKAGE_URL]) -m4trace:configure.ac:4: -1- AC_SUBST([DEFS]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([DEFS]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^DEFS$]) -m4trace:configure.ac:4: -1- AC_SUBST([LIBS]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([LIBS]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:4: -1- AC_SUBST([build_alias]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([build_alias]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^build_alias$]) -m4trace:configure.ac:4: -1- AC_SUBST([host_alias]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([host_alias]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^host_alias$]) -m4trace:configure.ac:4: -1- AC_SUBST([target_alias]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([target_alias]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^target_alias$]) -m4trace:configure.ac:4: -1- AC_SUBST([ECHO_C]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([ECHO_C]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_C$]) -m4trace:configure.ac:4: -1- AC_SUBST([ECHO_N]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([ECHO_N]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_N$]) -m4trace:configure.ac:4: -1- AC_SUBST([ECHO_T]) -m4trace:configure.ac:4: -1- AC_SUBST_TRACE([ECHO_T]) -m4trace:configure.ac:4: -1- m4_pattern_allow([^ECHO_T$]) -m4trace:configure.ac:7: -1- AC_CONFIG_HEADERS([config.h]) -m4trace:configure.ac:8: -1- AC_CONFIG_MACRO_DIR([m4]) -m4trace:configure.ac:8: -1- AC_CONFIG_MACRO_DIR_TRACE([m4]) -m4trace:configure.ac:13: -1- AH_OUTPUT([USE_SYSTEM_EXTENSIONS], [/* Enable extensions on AIX, Interix, z/OS. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif -/* Enable extensions on Cosmopolitan Libc. */ -#ifndef _COSMO_SOURCE -# undef _COSMO_SOURCE -#endif -/* Enable general extensions on macOS. */ -#ifndef _DARWIN_C_SOURCE -# undef _DARWIN_C_SOURCE -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# undef _GNU_SOURCE -#endif -/* Enable X/Open compliant socket functions that do not require linking - with -lxnet on HP-UX 11.11. */ -#ifndef _HPUX_ALT_XOPEN_SOCKET_API -# undef _HPUX_ALT_XOPEN_SOCKET_API -#endif -/* Identify the host operating system as Minix. - This macro does not affect the system headers\' behavior. - A future release of Autoconf may stop defining this macro. */ -#ifndef _MINIX -# undef _MINIX -#endif -/* Enable general extensions on NetBSD. - Enable NetBSD compatibility extensions on Minix. */ -#ifndef _NETBSD_SOURCE -# undef _NETBSD_SOURCE -#endif -/* Enable OpenBSD compatibility extensions on NetBSD. - Oddly enough, this does nothing on OpenBSD. */ -#ifndef _OPENBSD_SOURCE -# undef _OPENBSD_SOURCE -#endif -/* Define to 1 if needed for POSIX-compatible behavior. */ -#ifndef _POSIX_SOURCE -# undef _POSIX_SOURCE -#endif -/* Define to 2 if needed for POSIX-compatible behavior. */ -#ifndef _POSIX_1_SOURCE -# undef _POSIX_1_SOURCE -#endif -/* Enable POSIX-compatible threading on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# undef _POSIX_PTHREAD_SEMANTICS -#endif -/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ -#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ -# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ -#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ -# undef __STDC_WANT_IEC_60559_BFP_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ -#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ -# undef __STDC_WANT_IEC_60559_DFP_EXT__ -#endif -/* Enable extensions specified by C23 Annex F. */ -#ifndef __STDC_WANT_IEC_60559_EXT__ -# undef __STDC_WANT_IEC_60559_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ -#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ -# undef __STDC_WANT_IEC_60559_FUNCS_EXT__ -#endif -/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ -#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ -# undef __STDC_WANT_IEC_60559_TYPES_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ -#ifndef __STDC_WANT_LIB_EXT2__ -# undef __STDC_WANT_LIB_EXT2__ -#endif -/* Enable extensions specified by ISO/IEC 24747:2009. */ -#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ -# undef __STDC_WANT_MATH_SPEC_FUNCS__ -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# undef _TANDEM_SOURCE -#endif -/* Enable X/Open extensions. Define to 500 only if necessary - to make mbstate_t available. */ -#ifndef _XOPEN_SOURCE -# undef _XOPEN_SOURCE -#endif -]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STDIO_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDIO_H]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CFLAGS]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CFLAGS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CFLAGS$]) -m4trace:configure.ac:13: -1- AC_SUBST([LDFLAGS]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([LDFLAGS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^LDFLAGS$]) -m4trace:configure.ac:13: -1- AC_SUBST([LIBS]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([LIBS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^LIBS$]) -m4trace:configure.ac:13: -1- AC_SUBST([CPPFLAGS]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CPPFLAGS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CPPFLAGS$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([ac_ct_CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([ac_ct_CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^ac_ct_CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([CC]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$]) -m4trace:configure.ac:13: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([EXEEXT]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^EXEEXT$]) -m4trace:configure.ac:13: -1- AC_SUBST([OBJEXT], [$ac_cv_objext]) -m4trace:configure.ac:13: -1- AC_SUBST_TRACE([OBJEXT]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^OBJEXT$]) -m4trace:configure.ac:13: -1- AC_REQUIRE_AUX_FILE([compile]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDLIB_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STRING_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_INTTYPES_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STDINT_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_STRINGS_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_STAT_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_SYS_TYPES_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^STDC_HEADERS$]) -m4trace:configure.ac:13: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if all of the C89 standard headers exist (not just the ones - required in a freestanding environment). This macro is provided for - backward compatibility; new code need not use it. */ -@%:@undef STDC_HEADERS]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_WCHAR_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_WCHAR_H]) -m4trace:configure.ac:13: -1- AH_OUTPUT([HAVE_MINIX_CONFIG_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_MINIX_CONFIG_H]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_ALL_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_ALL_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_COSMO_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_COSMO_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_DARWIN_C_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_DARWIN_C_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_GNU_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_GNU_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_HPUX_ALT_XOPEN_SOCKET_API]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_HPUX_ALT_XOPEN_SOCKET_API$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_NETBSD_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_NETBSD_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_OPENBSD_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_OPENBSD_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_POSIX_PTHREAD_SEMANTICS]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_PTHREAD_SEMANTICS$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_ATTRIBS_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_ATTRIBS_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_BFP_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_BFP_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_DFP_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_DFP_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_FUNCS_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_FUNCS_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_IEC_60559_TYPES_EXT__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_IEC_60559_TYPES_EXT__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_LIB_EXT2__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_LIB_EXT2__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__STDC_WANT_MATH_SPEC_FUNCS__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__STDC_WANT_MATH_SPEC_FUNCS__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_TANDEM_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_TANDEM_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_MINIX]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_MINIX$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_POSIX_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_POSIX_1_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_POSIX_1_SOURCE$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([__EXTENSIONS__]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^__EXTENSIONS__$]) -m4trace:configure.ac:13: -1- AC_DEFINE_TRACE_LITERAL([_XOPEN_SOURCE]) -m4trace:configure.ac:13: -1- m4_pattern_allow([^_XOPEN_SOURCE$]) -m4trace:configure.ac:16: -1- AM_INIT_AUTOMAKE([foreign dist-xz]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_[A-Z]+FLAGS$]) -m4trace:configure.ac:16: -1- AM_AUTOMAKE_VERSION([1.18.1]) -m4trace:configure.ac:16: -1- AC_REQUIRE_AUX_FILE([install-sh]) -m4trace:configure.ac:16: -1- AC_SUBST([INSTALL_PROGRAM]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([INSTALL_PROGRAM]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_PROGRAM$]) -m4trace:configure.ac:16: -1- AC_SUBST([INSTALL_SCRIPT]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([INSTALL_SCRIPT]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_SCRIPT$]) -m4trace:configure.ac:16: -1- AC_SUBST([INSTALL_DATA]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([INSTALL_DATA]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_DATA$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__isrc], [' -I$(srcdir)']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__isrc]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__isrc$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__isrc]) -m4trace:configure.ac:16: -1- AC_SUBST([CYGPATH_W]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([CYGPATH_W]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CYGPATH_W$]) -m4trace:configure.ac:16: -1- AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([PACKAGE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^PACKAGE$]) -m4trace:configure.ac:16: -1- AC_SUBST([VERSION], ['AC_PACKAGE_VERSION']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([VERSION]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^VERSION$]) -m4trace:configure.ac:16: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^PACKAGE$]) -m4trace:configure.ac:16: -1- AH_OUTPUT([PACKAGE], [/* Name of package */ -@%:@undef PACKAGE]) -m4trace:configure.ac:16: -1- AC_DEFINE_TRACE_LITERAL([VERSION]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^VERSION$]) -m4trace:configure.ac:16: -1- AH_OUTPUT([VERSION], [/* Version number of package */ -@%:@undef VERSION]) -m4trace:configure.ac:16: -1- AC_REQUIRE_AUX_FILE([missing]) -m4trace:configure.ac:16: -1- AC_SUBST([ACLOCAL]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([ACLOCAL]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^ACLOCAL$]) -m4trace:configure.ac:16: -1- AC_SUBST([AUTOCONF]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AUTOCONF]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOCONF$]) -m4trace:configure.ac:16: -1- AC_SUBST([AUTOMAKE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AUTOMAKE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOMAKE$]) -m4trace:configure.ac:16: -1- AC_SUBST([AUTOHEADER]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AUTOHEADER]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AUTOHEADER$]) -m4trace:configure.ac:16: -1- AC_SUBST([MAKEINFO]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([MAKEINFO]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^MAKEINFO$]) -m4trace:configure.ac:16: -1- AC_SUBST([install_sh]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([install_sh]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^install_sh$]) -m4trace:configure.ac:16: -1- AC_SUBST([STRIP]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([STRIP]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^STRIP$]) -m4trace:configure.ac:16: -1- AC_SUBST([INSTALL_STRIP_PROGRAM]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([INSTALL_STRIP_PROGRAM]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^INSTALL_STRIP_PROGRAM$]) -m4trace:configure.ac:16: -1- AC_REQUIRE_AUX_FILE([install-sh]) -m4trace:configure.ac:16: -1- AC_SUBST([MKDIR_P]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([MKDIR_P]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^MKDIR_P$]) -m4trace:configure.ac:16: -1- AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([mkdir_p]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^mkdir_p$]) -m4trace:configure.ac:16: -1- AC_SUBST([AWK]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AWK]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AWK$]) -m4trace:configure.ac:16: -1- AC_SUBST([SET_MAKE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([SET_MAKE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^SET_MAKE$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__leading_dot]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__leading_dot]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__leading_dot$]) -m4trace:configure.ac:16: -1- AC_SUBST([AMTAR], ['$${TAR-tar}']) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AMTAR]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMTAR$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__tar]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__tar]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__tar$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__untar]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__untar]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__untar$]) -m4trace:configure.ac:16: -1- AC_SUBST([DEPDIR], ["${am__leading_dot}deps"]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([DEPDIR]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^DEPDIR$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__include]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__include]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__include$]) -m4trace:configure.ac:16: -1- AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -m4trace:configure.ac:16: -1- AC_SUBST([AMDEP_TRUE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AMDEP_TRUE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMDEP_TRUE$]) -m4trace:configure.ac:16: -1- AC_SUBST([AMDEP_FALSE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AMDEP_FALSE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMDEP_FALSE$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AMDEP_TRUE]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AMDEP_FALSE]) -m4trace:configure.ac:16: -1- AC_SUBST([AMDEPBACKSLASH]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AMDEPBACKSLASH]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AMDEPBACKSLASH$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AMDEPBACKSLASH]) -m4trace:configure.ac:16: -1- AC_SUBST([am__nodep]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__nodep]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__nodep$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__nodep]) -m4trace:configure.ac:16: -1- AC_SUBST([CCDEPMODE], [depmode=$am_cv_CC_dependencies_compiler_type]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([CCDEPMODE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CCDEPMODE$]) -m4trace:configure.ac:16: -1- AM_CONDITIONAL([am__fastdepCC], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3]) -m4trace:configure.ac:16: -1- AC_SUBST([am__fastdepCC_TRUE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__fastdepCC_TRUE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__fastdepCC_TRUE$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__fastdepCC_FALSE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__fastdepCC_FALSE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__fastdepCC_FALSE$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_TRUE]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_FALSE]) -m4trace:configure.ac:16: -1- AC_SUBST([CTAGS]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([CTAGS]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CTAGS$]) -m4trace:configure.ac:16: -1- AC_SUBST([ETAGS]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([ETAGS]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^ETAGS$]) -m4trace:configure.ac:16: -1- AC_SUBST([CSCOPE]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([CSCOPE]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^CSCOPE$]) -m4trace:configure.ac:16: -1- AC_SUBST([AM_V]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AM_V]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_V$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AM_V]) -m4trace:configure.ac:16: -1- AC_SUBST([AM_DEFAULT_V]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AM_DEFAULT_V]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_DEFAULT_V$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AM_DEFAULT_V]) -m4trace:configure.ac:16: -1- AC_SUBST([AM_DEFAULT_VERBOSITY]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AM_DEFAULT_VERBOSITY]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_DEFAULT_VERBOSITY$]) -m4trace:configure.ac:16: -1- AC_SUBST([AM_BACKSLASH]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([AM_BACKSLASH]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^AM_BACKSLASH$]) -m4trace:configure.ac:16: -1- _AM_SUBST_NOTMAKE([AM_BACKSLASH]) -m4trace:configure.ac:16: -1- AC_SUBST([am__rm_f_notfound]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__rm_f_notfound]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__rm_f_notfound$]) -m4trace:configure.ac:16: -1- AC_SUBST([am__xargs_n]) -m4trace:configure.ac:16: -1- AC_SUBST_TRACE([am__xargs_n]) -m4trace:configure.ac:16: -1- m4_pattern_allow([^am__xargs_n$]) -m4trace:configure.ac:19: -1- LT_INIT -m4trace:configure.ac:19: -1- m4_pattern_forbid([^_?LT_[A-Z_]+$]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$]) -m4trace:configure.ac:19: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) -m4trace:configure.ac:19: -1- AC_SUBST([LIBTOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LIBTOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LIBTOOL$]) -m4trace:configure.ac:19: -1- AC_CANONICAL_HOST -m4trace:configure.ac:19: -1- AC_CANONICAL_BUILD -m4trace:configure.ac:19: -1- AC_REQUIRE_AUX_FILE([config.sub]) -m4trace:configure.ac:19: -1- AC_REQUIRE_AUX_FILE([config.guess]) -m4trace:configure.ac:19: -1- AC_SUBST([build], [$ac_cv_build]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([build]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^build$]) -m4trace:configure.ac:19: -1- AC_SUBST([build_cpu], [$[1]]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([build_cpu]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^build_cpu$]) -m4trace:configure.ac:19: -1- AC_SUBST([build_vendor], [$[2]]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([build_vendor]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^build_vendor$]) -m4trace:configure.ac:19: -1- AC_SUBST([build_os]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([build_os]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^build_os$]) -m4trace:configure.ac:19: -1- AC_SUBST([host], [$ac_cv_host]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([host]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^host$]) -m4trace:configure.ac:19: -1- AC_SUBST([host_cpu], [$[1]]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([host_cpu]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^host_cpu$]) -m4trace:configure.ac:19: -1- AC_SUBST([host_vendor], [$[2]]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([host_vendor]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^host_vendor$]) -m4trace:configure.ac:19: -1- AC_SUBST([host_os]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([host_os]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^host_os$]) -m4trace:configure.ac:19: -1- AC_SUBST([SED]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([SED]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^SED$]) -m4trace:configure.ac:19: -1- AC_SUBST([GREP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([GREP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^GREP$]) -m4trace:configure.ac:19: -1- AC_SUBST([EGREP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([EGREP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^EGREP$]) -m4trace:configure.ac:19: -1- AC_SUBST([FGREP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([FGREP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^FGREP$]) -m4trace:configure.ac:19: -1- AC_SUBST([GREP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([GREP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^GREP$]) -m4trace:configure.ac:19: -1- AC_SUBST([LD]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LD]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LD$]) -m4trace:configure.ac:19: -1- AC_SUBST([DUMPBIN]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DUMPBIN]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DUMPBIN$]) -m4trace:configure.ac:19: -1- AC_SUBST([ac_ct_DUMPBIN]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([ac_ct_DUMPBIN]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^ac_ct_DUMPBIN$]) -m4trace:configure.ac:19: -1- AC_SUBST([DUMPBIN]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DUMPBIN]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DUMPBIN$]) -m4trace:configure.ac:19: -1- AC_SUBST([NM]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([NM]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^NM$]) -m4trace:configure.ac:19: -1- AC_SUBST([LN_S], [$as_ln_s]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LN_S]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LN_S$]) -m4trace:configure.ac:19: -1- AC_SUBST([FILECMD]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([FILECMD]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^FILECMD$]) -m4trace:configure.ac:19: -1- AC_SUBST([OBJDUMP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([OBJDUMP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^OBJDUMP$]) -m4trace:configure.ac:19: -1- AC_SUBST([OBJDUMP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([OBJDUMP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^OBJDUMP$]) -m4trace:configure.ac:19: -1- AC_SUBST([DLLTOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DLLTOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DLLTOOL$]) -m4trace:configure.ac:19: -1- AC_SUBST([DLLTOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DLLTOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DLLTOOL$]) -m4trace:configure.ac:19: -1- AC_SUBST([AR]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([AR]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^AR$]) -m4trace:configure.ac:19: -1- AC_SUBST([ac_ct_AR]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([ac_ct_AR]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^ac_ct_AR$]) -m4trace:configure.ac:19: -1- AC_SUBST([STRIP]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([STRIP]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^STRIP$]) -m4trace:configure.ac:19: -1- AC_SUBST([RANLIB]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([RANLIB]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^RANLIB$]) -m4trace:configure.ac:19: -1- m4_pattern_allow([LT_OBJDIR]) -m4trace:configure.ac:19: -1- AC_DEFINE_TRACE_LITERAL([LT_OBJDIR]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LT_OBJDIR$]) -m4trace:configure.ac:19: -1- AH_OUTPUT([LT_OBJDIR], [/* Define to the sub-directory where libtool stores uninstalled libraries. */ -@%:@undef LT_OBJDIR]) -m4trace:configure.ac:19: -1- LT_SUPPORTED_TAG([CC]) -m4trace:configure.ac:19: -1- AC_SUBST([MANIFEST_TOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([MANIFEST_TOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^MANIFEST_TOOL$]) -m4trace:configure.ac:19: -1- AC_SUBST([DSYMUTIL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([DSYMUTIL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^DSYMUTIL$]) -m4trace:configure.ac:19: -1- AC_SUBST([NMEDIT]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([NMEDIT]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^NMEDIT$]) -m4trace:configure.ac:19: -1- AC_SUBST([LIPO]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LIPO]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LIPO$]) -m4trace:configure.ac:19: -1- AC_SUBST([OTOOL]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([OTOOL]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^OTOOL$]) -m4trace:configure.ac:19: -1- AC_SUBST([OTOOL64]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([OTOOL64]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^OTOOL64$]) -m4trace:configure.ac:19: -1- AC_SUBST([LT_SYS_LIBRARY_PATH]) -m4trace:configure.ac:19: -1- AC_SUBST_TRACE([LT_SYS_LIBRARY_PATH]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^LT_SYS_LIBRARY_PATH$]) -m4trace:configure.ac:19: -1- AH_OUTPUT([HAVE_DLFCN_H], [/* Define to 1 if you have the header file. */ -@%:@undef HAVE_DLFCN_H]) -m4trace:configure.ac:19: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DLFCN_H]) -m4trace:configure.ac:19: -1- m4_pattern_allow([^HAVE_DLFCN_H$]) -m4trace:configure.ac:25: -1- AC_SUBST([BASE_CFLAGS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([BASE_CFLAGS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^BASE_CFLAGS$]) -m4trace:configure.ac:25: -1- AC_SUBST([CWARNFLAGS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([CWARNFLAGS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^CWARNFLAGS$]) -m4trace:configure.ac:25: -1- AC_SUBST([STRICT_CFLAGS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([STRICT_CFLAGS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^STRICT_CFLAGS$]) -m4trace:configure.ac:25: -1- AC_SUBST([BASE_CFLAGS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([BASE_CFLAGS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^BASE_CFLAGS$]) -m4trace:configure.ac:25: -2- AC_SUBST([CWARNFLAGS]) -m4trace:configure.ac:25: -2- AC_SUBST_TRACE([CWARNFLAGS]) -m4trace:configure.ac:25: -2- m4_pattern_allow([^CWARNFLAGS$]) -m4trace:configure.ac:25: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION_MAJOR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PACKAGE_VERSION_MAJOR$]) -m4trace:configure.ac:25: -1- AH_OUTPUT([PACKAGE_VERSION_MAJOR], [/* Major version of this package */ -@%:@undef PACKAGE_VERSION_MAJOR]) -m4trace:configure.ac:25: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION_MINOR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PACKAGE_VERSION_MINOR$]) -m4trace:configure.ac:25: -1- AH_OUTPUT([PACKAGE_VERSION_MINOR], [/* Minor version of this package */ -@%:@undef PACKAGE_VERSION_MINOR]) -m4trace:configure.ac:25: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION_PATCHLEVEL]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PACKAGE_VERSION_PATCHLEVEL$]) -m4trace:configure.ac:25: -1- AH_OUTPUT([PACKAGE_VERSION_PATCHLEVEL], [/* Patch version of this package */ -@%:@undef PACKAGE_VERSION_PATCHLEVEL]) -m4trace:configure.ac:25: -1- AC_SUBST([CHANGELOG_CMD]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([CHANGELOG_CMD]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^CHANGELOG_CMD$]) -m4trace:configure.ac:25: -1- m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) -m4trace:configure.ac:25: -1- AC_SUBST([PKG_CONFIG]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([PKG_CONFIG]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG$]) -m4trace:configure.ac:25: -1- AC_SUBST([PKG_CONFIG_PATH]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([PKG_CONFIG_PATH]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG_PATH$]) -m4trace:configure.ac:25: -1- AC_SUBST([PKG_CONFIG_LIBDIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([PKG_CONFIG_LIBDIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG_LIBDIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([PKG_CONFIG]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([PKG_CONFIG]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^PKG_CONFIG$]) -m4trace:configure.ac:25: -1- AC_SUBST([INSTALL_CMD]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([INSTALL_CMD]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^INSTALL_CMD$]) -m4trace:configure.ac:25: -1- _m4_warn([cross], [cannot check for file existence when cross compiling], [./lib/autoconf/general.m4:3066: AC_CHECK_FILE is expanded from... -aclocal.m4:479: XORG_MANPAGE_SECTIONS is expanded from... -aclocal.m4:2188: XORG_DEFAULT_NOCODE_OPTIONS is expanded from... -aclocal.m4:2204: XORG_DEFAULT_OPTIONS is expanded from... -configure.ac:25: the top level]) -m4trace:configure.ac:25: -1- AC_SUBST([APP_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([APP_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^APP_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([LIB_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([LIB_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^LIB_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([FILE_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([FILE_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^FILE_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([MISC_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([MISC_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^MISC_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([DRIVER_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([DRIVER_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^DRIVER_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([ADMIN_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([ADMIN_MAN_SUFFIX]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^ADMIN_MAN_SUFFIX$]) -m4trace:configure.ac:25: -1- AC_SUBST([APP_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([APP_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^APP_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([LIB_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([LIB_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^LIB_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([FILE_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([FILE_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^FILE_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([MISC_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([MISC_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^MISC_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([DRIVER_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([DRIVER_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^DRIVER_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([ADMIN_MAN_DIR]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([ADMIN_MAN_DIR]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^ADMIN_MAN_DIR$]) -m4trace:configure.ac:25: -1- AC_SUBST([XORG_MAN_PAGE]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([XORG_MAN_PAGE]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^XORG_MAN_PAGE$]) -m4trace:configure.ac:25: -1- AC_SUBST([MAN_SUBSTS]) -m4trace:configure.ac:25: -1- AC_SUBST_TRACE([MAN_SUBSTS]) -m4trace:configure.ac:25: -1- m4_pattern_allow([^MAN_SUBSTS$]) -m4trace:configure.ac:25: -1- AM_SILENT_RULES([yes]) -m4trace:configure.ac:26: -1- AM_CONDITIONAL([ENABLE_SPECS], [test x$build_specs = xyes]) -m4trace:configure.ac:26: -1- AC_SUBST([ENABLE_SPECS_TRUE]) -m4trace:configure.ac:26: -1- AC_SUBST_TRACE([ENABLE_SPECS_TRUE]) -m4trace:configure.ac:26: -1- m4_pattern_allow([^ENABLE_SPECS_TRUE$]) -m4trace:configure.ac:26: -1- AC_SUBST([ENABLE_SPECS_FALSE]) -m4trace:configure.ac:26: -1- AC_SUBST_TRACE([ENABLE_SPECS_FALSE]) -m4trace:configure.ac:26: -1- m4_pattern_allow([^ENABLE_SPECS_FALSE$]) -m4trace:configure.ac:26: -1- _AM_SUBST_NOTMAKE([ENABLE_SPECS_TRUE]) -m4trace:configure.ac:26: -1- _AM_SUBST_NOTMAKE([ENABLE_SPECS_FALSE]) -m4trace:configure.ac:27: -1- AC_SUBST([XMLTO]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([XMLTO]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^XMLTO$]) -m4trace:configure.ac:27: -1- AC_SUBST([XMLTO]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([XMLTO]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^XMLTO$]) -m4trace:configure.ac:27: -1- AC_SUBST([XMLTO]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([XMLTO]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^XMLTO$]) -m4trace:configure.ac:27: -1- AM_CONDITIONAL([HAVE_XMLTO_TEXT], [test $have_xmlto_text = yes]) -m4trace:configure.ac:27: -1- AC_SUBST([HAVE_XMLTO_TEXT_TRUE]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([HAVE_XMLTO_TEXT_TRUE]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^HAVE_XMLTO_TEXT_TRUE$]) -m4trace:configure.ac:27: -1- AC_SUBST([HAVE_XMLTO_TEXT_FALSE]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([HAVE_XMLTO_TEXT_FALSE]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^HAVE_XMLTO_TEXT_FALSE$]) -m4trace:configure.ac:27: -1- _AM_SUBST_NOTMAKE([HAVE_XMLTO_TEXT_TRUE]) -m4trace:configure.ac:27: -1- _AM_SUBST_NOTMAKE([HAVE_XMLTO_TEXT_FALSE]) -m4trace:configure.ac:27: -1- AM_CONDITIONAL([HAVE_XMLTO], [test "$have_xmlto" = yes]) -m4trace:configure.ac:27: -1- AC_SUBST([HAVE_XMLTO_TRUE]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([HAVE_XMLTO_TRUE]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^HAVE_XMLTO_TRUE$]) -m4trace:configure.ac:27: -1- AC_SUBST([HAVE_XMLTO_FALSE]) -m4trace:configure.ac:27: -1- AC_SUBST_TRACE([HAVE_XMLTO_FALSE]) -m4trace:configure.ac:27: -1- m4_pattern_allow([^HAVE_XMLTO_FALSE$]) -m4trace:configure.ac:27: -1- _AM_SUBST_NOTMAKE([HAVE_XMLTO_TRUE]) -m4trace:configure.ac:27: -1- _AM_SUBST_NOTMAKE([HAVE_XMLTO_FALSE]) -m4trace:configure.ac:28: -1- AC_SUBST([FOP]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([FOP]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^FOP$]) -m4trace:configure.ac:28: -1- AC_SUBST([FOP]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([FOP]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^FOP$]) -m4trace:configure.ac:28: -1- AC_SUBST([FOP]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([FOP]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^FOP$]) -m4trace:configure.ac:28: -1- AM_CONDITIONAL([HAVE_FOP], [test "$have_fop" = yes]) -m4trace:configure.ac:28: -1- AC_SUBST([HAVE_FOP_TRUE]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([HAVE_FOP_TRUE]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_FOP_TRUE$]) -m4trace:configure.ac:28: -1- AC_SUBST([HAVE_FOP_FALSE]) -m4trace:configure.ac:28: -1- AC_SUBST_TRACE([HAVE_FOP_FALSE]) -m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_FOP_FALSE$]) -m4trace:configure.ac:28: -1- _AM_SUBST_NOTMAKE([HAVE_FOP_TRUE]) -m4trace:configure.ac:28: -1- _AM_SUBST_NOTMAKE([HAVE_FOP_FALSE]) -m4trace:configure.ac:29: -1- AC_SUBST([XSLTPROC]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([XSLTPROC]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^XSLTPROC$]) -m4trace:configure.ac:29: -1- AC_SUBST([XSLTPROC]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([XSLTPROC]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^XSLTPROC$]) -m4trace:configure.ac:29: -1- AC_SUBST([XSLTPROC]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([XSLTPROC]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^XSLTPROC$]) -m4trace:configure.ac:29: -1- AM_CONDITIONAL([HAVE_XSLTPROC], [test "$have_xsltproc" = yes]) -m4trace:configure.ac:29: -1- AC_SUBST([HAVE_XSLTPROC_TRUE]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([HAVE_XSLTPROC_TRUE]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^HAVE_XSLTPROC_TRUE$]) -m4trace:configure.ac:29: -1- AC_SUBST([HAVE_XSLTPROC_FALSE]) -m4trace:configure.ac:29: -1- AC_SUBST_TRACE([HAVE_XSLTPROC_FALSE]) -m4trace:configure.ac:29: -1- m4_pattern_allow([^HAVE_XSLTPROC_FALSE$]) -m4trace:configure.ac:29: -1- _AM_SUBST_NOTMAKE([HAVE_XSLTPROC_TRUE]) -m4trace:configure.ac:29: -1- _AM_SUBST_NOTMAKE([HAVE_XSLTPROC_FALSE]) -m4trace:configure.ac:30: -1- AC_SUBST([XORG_SGML_PATH]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([XORG_SGML_PATH]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^XORG_SGML_PATH$]) -m4trace:configure.ac:30: -1- AC_SUBST([STYLESHEET_SRCDIR]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([STYLESHEET_SRCDIR]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^STYLESHEET_SRCDIR$]) -m4trace:configure.ac:30: -1- AC_SUBST([XSL_STYLESHEET]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([XSL_STYLESHEET]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^XSL_STYLESHEET$]) -m4trace:configure.ac:30: -1- AM_CONDITIONAL([HAVE_STYLESHEETS], [test "x$XSL_STYLESHEET" != "x"]) -m4trace:configure.ac:30: -1- AC_SUBST([HAVE_STYLESHEETS_TRUE]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([HAVE_STYLESHEETS_TRUE]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^HAVE_STYLESHEETS_TRUE$]) -m4trace:configure.ac:30: -1- AC_SUBST([HAVE_STYLESHEETS_FALSE]) -m4trace:configure.ac:30: -1- AC_SUBST_TRACE([HAVE_STYLESHEETS_FALSE]) -m4trace:configure.ac:30: -1- m4_pattern_allow([^HAVE_STYLESHEETS_FALSE$]) -m4trace:configure.ac:30: -1- _AM_SUBST_NOTMAKE([HAVE_STYLESHEETS_TRUE]) -m4trace:configure.ac:30: -1- _AM_SUBST_NOTMAKE([HAVE_STYLESHEETS_FALSE]) -m4trace:configure.ac:31: -1- AC_SUBST([MALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- AC_SUBST_TRACE([MALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^MALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:31: -1- AC_SUBST([XMALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- AC_SUBST_TRACE([XMALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^XMALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:31: -1- AC_SUBST([XTMALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- AC_SUBST_TRACE([XTMALLOC_ZERO_CFLAGS]) -m4trace:configure.ac:31: -1- m4_pattern_allow([^XTMALLOC_ZERO_CFLAGS$]) -m4trace:configure.ac:42: -1- AC_SUBST([XEXT_SOREV]) -m4trace:configure.ac:42: -1- AC_SUBST_TRACE([XEXT_SOREV]) -m4trace:configure.ac:42: -1- m4_pattern_allow([^XEXT_SOREV$]) -m4trace:configure.ac:45: -1- AC_SUBST([XEXT_CFLAGS]) -m4trace:configure.ac:45: -1- AC_SUBST_TRACE([XEXT_CFLAGS]) -m4trace:configure.ac:45: -1- m4_pattern_allow([^XEXT_CFLAGS$]) -m4trace:configure.ac:45: -1- AC_SUBST([XEXT_LIBS]) -m4trace:configure.ac:45: -1- AC_SUBST_TRACE([XEXT_LIBS]) -m4trace:configure.ac:45: -1- m4_pattern_allow([^XEXT_LIBS$]) -m4trace:configure.ac:47: -1- AC_DEFINE_TRACE_LITERAL([HAVE___BUILTIN_POPCOUNTL]) -m4trace:configure.ac:47: -1- m4_pattern_allow([^HAVE___BUILTIN_POPCOUNTL$]) -m4trace:configure.ac:47: -1- AH_OUTPUT([HAVE___BUILTIN_POPCOUNTL], [/* Define to 1 if the system has the `__builtin_popcountl\' built-in function - */ -@%:@undef HAVE___BUILTIN_POPCOUNTL]) -m4trace:configure.ac:48: -1- AH_OUTPUT([HAVE_REALLOCARRAY], [/* Define to 1 if you have the \'reallocarray\' function. */ -@%:@undef HAVE_REALLOCARRAY]) -m4trace:configure.ac:48: -1- AC_LIBSOURCE([reallocarray.c]) -m4trace:configure.ac:48: -1- AC_DEFINE_TRACE_LITERAL([HAVE_REALLOCARRAY]) -m4trace:configure.ac:48: -1- m4_pattern_allow([^HAVE_REALLOCARRAY$]) -m4trace:configure.ac:48: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS reallocarray.$ac_objext"]) -m4trace:configure.ac:48: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:48: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT_FLAGS]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT_FLAGS]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FLAGS$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT_FLAGS], [$lint_options]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT_FLAGS]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FLAGS$]) -m4trace:configure.ac:51: -1- AM_CONDITIONAL([LINT], [test "x$LINT" != x]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT_TRUE]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT_TRUE]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_TRUE$]) -m4trace:configure.ac:51: -1- AC_SUBST([LINT_FALSE]) -m4trace:configure.ac:51: -1- AC_SUBST_TRACE([LINT_FALSE]) -m4trace:configure.ac:51: -1- m4_pattern_allow([^LINT_FALSE$]) -m4trace:configure.ac:51: -1- _AM_SUBST_NOTMAKE([LINT_TRUE]) -m4trace:configure.ac:51: -1- _AM_SUBST_NOTMAKE([LINT_FALSE]) -m4trace:configure.ac:52: -1- AC_SUBST([LINTLIB]) -m4trace:configure.ac:52: -1- AC_SUBST_TRACE([LINTLIB]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^LINTLIB$]) -m4trace:configure.ac:52: -1- AM_CONDITIONAL([MAKE_LINT_LIB], [test x$make_lint_lib != xno]) -m4trace:configure.ac:52: -1- AC_SUBST([MAKE_LINT_LIB_TRUE]) -m4trace:configure.ac:52: -1- AC_SUBST_TRACE([MAKE_LINT_LIB_TRUE]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^MAKE_LINT_LIB_TRUE$]) -m4trace:configure.ac:52: -1- AC_SUBST([MAKE_LINT_LIB_FALSE]) -m4trace:configure.ac:52: -1- AC_SUBST_TRACE([MAKE_LINT_LIB_FALSE]) -m4trace:configure.ac:52: -1- m4_pattern_allow([^MAKE_LINT_LIB_FALSE$]) -m4trace:configure.ac:52: -1- _AM_SUBST_NOTMAKE([MAKE_LINT_LIB_TRUE]) -m4trace:configure.ac:52: -1- _AM_SUBST_NOTMAKE([MAKE_LINT_LIB_FALSE]) -m4trace:configure.ac:54: -1- AC_CONFIG_FILES([Makefile - man/Makefile - src/Makefile - specs/Makefile - xext.pc]) -m4trace:configure.ac:59: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:59: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([LTLIBOBJS]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:59: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:59: -1- AC_SUBST([am__EXEEXT_TRUE]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:59: -1- AC_SUBST([am__EXEEXT_FALSE]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE]) -m4trace:configure.ac:59: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:59: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:59: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([top_builddir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([top_build_prefix]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([srcdir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([abs_srcdir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([top_srcdir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([abs_top_srcdir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([builddir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([abs_builddir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([abs_top_builddir]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([INSTALL]) -m4trace:configure.ac:59: -1- AC_SUBST_TRACE([MKDIR_P]) -m4trace:configure.ac:59: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) diff --git a/experiments/wasm-gui/third_party/libXext/compile b/experiments/wasm-gui/third_party/libXext/compile deleted file mode 100755 index 02ff093c3..000000000 --- a/experiments/wasm-gui/third_party/libXext/compile +++ /dev/null @@ -1,364 +0,0 @@ -#! /bin/sh -# Wrapper for compilers which do not understand '-c -o'. - -scriptversion=2025-06-18.21; # UTC - -# Copyright (C) 1999-2025 Free Software Foundation, Inc. -# Written by Tom Tromey . -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# This file is maintained in Automake, please report -# bugs to or send patches to -# . - -nl=' -' - -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent tools from complaining about whitespace usage. -IFS=" "" $nl" - -file_conv= - -# func_file_conv build_file unneeded_conversions -# Convert a $build file to $host form and store it in $file -# Currently only supports Windows hosts. If the determined conversion -# type is listed in (the comma separated) UNNEEDED_CONVERSIONS, no -# conversion will take place. -func_file_conv () -{ - file=$1 - case $file in - / | /[!/]*) # absolute file, and not a UNC file - if test -z "$file_conv"; then - # lazily determine how to convert abs files - case `uname -s` in - MINGW*) - if test -n "$MSYSTEM" && (cygpath --version) >/dev/null 2>&1; then - # MSYS2 environment. - file_conv=cygwin - else - # Original MinGW environment. - file_conv=mingw - fi - ;; - MSYS*) - # Old MSYS environment, or MSYS2 with 32-bit MSYS2 shell. - file_conv=cygwin - ;; - CYGWIN*) - # Cygwin environment. - file_conv=cygwin - ;; - *) - file_conv=wine - ;; - esac - fi - case $file_conv/,$2, in - *,$file_conv,*) - # This is the optimization mentioned above: - # If UNNEEDED_CONVERSIONS contains $file_conv, don't convert. - ;; - mingw/*) - file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` - ;; - cygwin/*) - file=`cygpath -w "$file" || echo "$file"` - ;; - wine/*) - file=`winepath -w "$file" || echo "$file"` - ;; - esac - ;; - esac -} - -# func_cl_dashL linkdir -# Make cl look for libraries in LINKDIR -func_cl_dashL () -{ - func_file_conv "$1" - if test -z "$lib_path"; then - lib_path=$file - else - lib_path="$lib_path;$file" - fi - linker_opts="$linker_opts -LIBPATH:$file" -} - -# func_cl_dashl library -# Do a library search-path lookup for cl -func_cl_dashl () -{ - lib=$1 - found=no - save_IFS=$IFS - IFS=';' - for dir in $lib_path $LIB - do - IFS=$save_IFS - if $shared && test -f "$dir/$lib.dll.lib"; then - found=yes - lib=$dir/$lib.dll.lib - break - fi - if test -f "$dir/$lib.lib"; then - found=yes - lib=$dir/$lib.lib - break - fi - if test -f "$dir/lib$lib.a"; then - found=yes - lib=$dir/lib$lib.a - break - fi - done - IFS=$save_IFS - - if test "$found" != yes; then - lib=$lib.lib - fi -} - -# func_cl_wrapper cl arg... -# Adjust compile command to suit cl -func_cl_wrapper () -{ - # Assume a capable shell - lib_path= - shared=: - linker_opts= - for arg - do - if test -n "$eat"; then - eat= - else - case $1 in - -o) - # configure might choose to run compile as 'compile cc -o foo foo.c'. - eat=1 - case $2 in - *.o | *.lo | *.[oO][bB][jJ]) - func_file_conv "$2" - set x "$@" -Fo"$file" - shift - ;; - *) - func_file_conv "$2" - set x "$@" -Fe"$file" - shift - ;; - esac - ;; - -I) - eat=1 - func_file_conv "$2" mingw - set x "$@" -I"$file" - shift - ;; - -I*) - func_file_conv "${1#-I}" mingw - set x "$@" -I"$file" - shift - ;; - -l) - eat=1 - func_cl_dashl "$2" - set x "$@" "$lib" - shift - ;; - -l*) - func_cl_dashl "${1#-l}" - set x "$@" "$lib" - shift - ;; - -L) - eat=1 - func_cl_dashL "$2" - ;; - -L*) - func_cl_dashL "${1#-L}" - ;; - -static) - shared=false - ;; - -Wl,*) - arg=${1#-Wl,} - save_ifs="$IFS"; IFS=',' - for flag in $arg; do - IFS="$save_ifs" - linker_opts="$linker_opts $flag" - done - IFS="$save_ifs" - ;; - -Xlinker) - eat=1 - linker_opts="$linker_opts $2" - ;; - -*) - set x "$@" "$1" - shift - ;; - *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) - func_file_conv "$1" - set x "$@" -Tp"$file" - shift - ;; - *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) - func_file_conv "$1" mingw - set x "$@" "$file" - shift - ;; - *) - set x "$@" "$1" - shift - ;; - esac - fi - shift - done - if test -n "$linker_opts"; then - linker_opts="-link$linker_opts" - fi - exec "$@" $linker_opts - exit 1 -} - -eat= - -case $1 in - '') - echo "$0: No command. Try '$0 --help' for more information." 1>&2 - exit 1; - ;; - -h | --h*) - cat <<\EOF -Usage: compile [--help] [--version] PROGRAM [ARGS] - -Wrapper for compilers which do not understand '-c -o'. -Remove '-o dest.o' from ARGS, run PROGRAM with the remaining -arguments, and rename the output as expected. - -If you are trying to build a whole package this is not the -right script to run: please start by reading the file 'INSTALL'. - -Report bugs to . -GNU Automake home page: . -General help using GNU software: . -EOF - exit $? - ;; - -v | --v*) - echo "compile (GNU Automake) $scriptversion" - exit $? - ;; - cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ - clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \ - icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) - func_cl_wrapper "$@" # Doesn't return... - ;; -esac - -ofile= -cfile= - -for arg -do - if test -n "$eat"; then - eat= - else - case $1 in - -o) - # configure might choose to run compile as 'compile cc -o foo foo.c'. - # So we strip '-o arg' only if arg is an object. - eat=1 - case $2 in - *.o | *.obj) - ofile=$2 - ;; - *) - set x "$@" -o "$2" - shift - ;; - esac - ;; - *.c) - cfile=$1 - set x "$@" "$1" - shift - ;; - *) - set x "$@" "$1" - shift - ;; - esac - fi - shift -done - -if test -z "$ofile" || test -z "$cfile"; then - # If no '-o' option was seen then we might have been invoked from a - # pattern rule where we don't need one. That is ok -- this is a - # normal compilation that the losing compiler can handle. If no - # '.c' file was seen then we are probably linking. That is also - # ok. - exec "$@" -fi - -# Name of file we expect compiler to create. -cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` - -# Create the lock directory. -# Note: use '[/\\:.-]' here to ensure that we don't use the same name -# that we are using for the .o file. Also, base the name on the expected -# object file name, since that is what matters with a parallel build. -lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d -while true; do - if mkdir "$lockdir" >/dev/null 2>&1; then - break - fi - sleep 1 -done -# FIXME: race condition here if user kills between mkdir and trap. -trap "rmdir '$lockdir'; exit 1" 1 2 15 - -# Run the compile. -"$@" -ret=$? - -if test -f "$cofile"; then - test "$cofile" = "$ofile" || mv "$cofile" "$ofile" -elif test -f "${cofile}bj"; then - test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" -fi - -rmdir "$lockdir" -exit $ret - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp nil t) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%Y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/experiments/wasm-gui/third_party/libXext/config.guess b/experiments/wasm-gui/third_party/libXext/config.guess deleted file mode 100755 index a9d01fde4..000000000 --- a/experiments/wasm-gui/third_party/libXext/config.guess +++ /dev/null @@ -1,1818 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright 1992-2025 Free Software Foundation, Inc. - -# shellcheck disable=SC2006,SC2268 # see below for rationale - -timestamp='2025-07-10' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). -# -# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. -# -# You can get the latest version of this script from: -# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess -# -# Please send patches to . - - -# The "shellcheck disable" line above the timestamp inhibits complaints -# about features and limitations of the classic Bourne shell that were -# superseded or lifted in POSIX. However, this script identifies a wide -# variety of pre-POSIX systems that do not have POSIX shells at all, and -# even some reasonably current systems (Solaris 10 as case-in-point) still -# have a pre-POSIX /bin/sh. - - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] - -Output the configuration name of the system '$me' is run on. - -Options: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.guess ($timestamp) - -Originally written by Per Bothner. -Copyright 1992-2025 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try '$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - * ) - break ;; - esac -done - -if test $# != 0; then - echo "$me: too many arguments$help" >&2 - exit 1 -fi - -# Just in case it came from the environment. -GUESS= - -# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -# compiler to aid in system detection is discouraged as it requires -# temporary files to be created and, as you can see below, it is a -# headache to deal with in a portable fashion. - -# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still -# use 'HOST_CC' if defined, but it is deprecated. - -# Portable tmp directory creation inspired by the Autoconf team. - -tmp= -# shellcheck disable=SC2172 -trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 - -set_cc_for_build() { - # prevent multiple calls if $tmp is already set - test "$tmp" && return 0 - : "${TMPDIR=/tmp}" - # shellcheck disable=SC2039,SC3028 - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } - dummy=$tmp/dummy - case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in - ,,) echo "int x;" > "$dummy.c" - for driver in cc gcc c17 c99 c89 ; do - if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then - CC_FOR_BUILD=$driver - break - fi - done - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; - esac -} - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 1994-08-24) -if test -f /.attbin/uname ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -case $UNAME_SYSTEM in -Linux|GNU|GNU/*) - LIBC=unknown - - set_cc_for_build - cat <<-EOF > "$dummy.c" - #if defined(__ANDROID__) - LIBC=android - #else - #include - #if defined(__UCLIBC__) - LIBC=uclibc - #elif defined(__dietlibc__) - LIBC=dietlibc - #elif defined(__GLIBC__) - LIBC=gnu - #elif defined(__LLVM_LIBC__) - LIBC=llvm - #else - #include - /* First heuristic to detect musl libc. */ - #ifdef __DEFINED_va_list - LIBC=musl - #endif - #endif - #endif - EOF - cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` - eval "$cc_set_libc" - - # Second heuristic to detect musl libc. - if [ "$LIBC" = unknown ] && - command -v ldd >/dev/null && - ldd --version 2>&1 | grep -q ^musl; then - LIBC=musl - fi - - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - if [ "$LIBC" = unknown ]; then - LIBC=gnu - fi - ;; -esac - -# Note: order is significant - the case branches are not exclusive. - -case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward - # compatibility and a consistent mechanism for selecting the - # object file format. - # - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ - /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ - echo unknown)` - case $UNAME_MACHINE_ARCH in - aarch64eb) machine=aarch64_be-unknown ;; - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-unknown ;; - sh5el) machine=sh5le-unknown ;; - earmv*) - arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` - endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` - machine=${arch}${endian}-unknown - ;; - *) machine=$UNAME_MACHINE_ARCH-unknown ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently (or will in the future) and ABI. - case $UNAME_MACHINE_ARCH in - earm*) - os=netbsdelf - ;; - arm*|i386|m68k|ns32k|sh3*|sparc|vax) - set_cc_for_build - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ELF__ - then - # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). - # Return netbsd for either. FIX? - os=netbsd - else - os=netbsdelf - fi - ;; - *) - os=netbsd - ;; - esac - # Determine ABI tags. - case $UNAME_MACHINE_ARCH in - earm*) - expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` - ;; - esac - # The OS release - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need - # kernel version information, so it can be replaced with a - # suitable tag, in the style of linux-gnu. - case $UNAME_VERSION in - Debian*) - release='-gnu' - ;; - *) - release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` - ;; - esac - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - GUESS=$machine-${os}${release}${abi-} - ;; - *:Bitrig:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE - ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE - ;; - *:SecBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` - GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE - ;; - *:LibertyBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` - GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE - ;; - *:MidnightBSD:*:*) - GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE - ;; - *:ekkoBSD:*:*) - GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE - ;; - *:SolidBSD:*:*) - GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE - ;; - *:OS108:*:*) - GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE - ;; - macppc:MirBSD:*:*) - GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE - ;; - *:MirBSD:*:*) - GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE - ;; - *:Sortix:*:*) - GUESS=$UNAME_MACHINE-unknown-sortix - ;; - *:Twizzler:*:*) - GUESS=$UNAME_MACHINE-unknown-twizzler - ;; - *:Redox:*:*) - GUESS=$UNAME_MACHINE-unknown-redox - ;; - mips:OSF1:*.*) - GUESS=mips-dec-osf1 - ;; - alpha:OSF1:*:*) - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - trap '' 0 - case $UNAME_RELEASE in - *4.0) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that - # covers most systems running today. This code pipes the CPU - # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case $ALPHA_CPU_TYPE in - "EV4 (21064)") - UNAME_MACHINE=alpha ;; - "EV4.5 (21064)") - UNAME_MACHINE=alpha ;; - "LCA4 (21066/21068)") - UNAME_MACHINE=alpha ;; - "EV5 (21164)") - UNAME_MACHINE=alphaev5 ;; - "EV5.6 (21164A)") - UNAME_MACHINE=alphaev56 ;; - "EV5.6 (21164PC)") - UNAME_MACHINE=alphapca56 ;; - "EV5.7 (21164PC)") - UNAME_MACHINE=alphapca57 ;; - "EV6 (21264)") - UNAME_MACHINE=alphaev6 ;; - "EV6.7 (21264A)") - UNAME_MACHINE=alphaev67 ;; - "EV6.8CB (21264C)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8AL (21264B)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8CX (21264D)") - UNAME_MACHINE=alphaev68 ;; - "EV6.9A (21264/EV69A)") - UNAME_MACHINE=alphaev69 ;; - "EV7 (21364)") - UNAME_MACHINE=alphaev7 ;; - "EV7.9 (21364A)") - UNAME_MACHINE=alphaev79 ;; - esac - # A Pn.n version is a patched version. - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` - GUESS=$UNAME_MACHINE-dec-osf$OSF_REL - ;; - Amiga*:UNIX_System_V:4.0:*) - GUESS=m68k-unknown-sysv4 - ;; - *:[Aa]miga[Oo][Ss]:*:*) - GUESS=$UNAME_MACHINE-unknown-amigaos - ;; - *:[Mm]orph[Oo][Ss]:*:*) - GUESS=$UNAME_MACHINE-unknown-morphos - ;; - *:OS/390:*:*) - GUESS=i370-ibm-openedition - ;; - *:z/VM:*:*) - GUESS=s390-ibm-zvmoe - ;; - *:OS400:*:*) - GUESS=powerpc-ibm-os400 - ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - GUESS=arm-acorn-riscix$UNAME_RELEASE - ;; - arm*:riscos:*:*|arm*:RISCOS:*:*) - GUESS=arm-unknown-riscos - ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - GUESS=hppa1.1-hitachi-hiuxmpp - ;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - case `(/bin/universe) 2>/dev/null` in - att) GUESS=pyramid-pyramid-sysv3 ;; - *) GUESS=pyramid-pyramid-bsd ;; - esac - ;; - NILE*:*:*:dcosx) - GUESS=pyramid-pyramid-svr4 - ;; - DRS?6000:unix:4.0:6*) - GUESS=sparc-icl-nx6 - ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case `/usr/bin/uname -p` in - sparc) GUESS=sparc-icl-nx7 ;; - esac - ;; - s390x:SunOS:*:*) - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL - ;; - sun4H:SunOS:5.*:*) - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=sparc-hal-solaris2$SUN_REL - ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=sparc-sun-solaris2$SUN_REL - ;; - i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - GUESS=i386-pc-auroraux$UNAME_RELEASE - ;; - i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - set_cc_for_build - SUN_ARCH=i386 - # If there is a compiler, see if it is configured for 64-bit objects. - # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. - # This test works for both compilers. - if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - SUN_ARCH=x86_64 - fi - fi - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=$SUN_ARCH-pc-solaris2$SUN_REL - ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=sparc-sun-solaris3$SUN_REL - ;; - sun4*:SunOS:*:*) - case `/usr/bin/arch -k` in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like '4.1.3-JL'. - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` - GUESS=sparc-sun-sunos$SUN_REL - ;; - sun3*:SunOS:*:*) - GUESS=m68k-sun-sunos$UNAME_RELEASE - ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 - case `/bin/arch` in - sun3) - GUESS=m68k-sun-sunos$UNAME_RELEASE - ;; - sun4) - GUESS=sparc-sun-sunos$UNAME_RELEASE - ;; - esac - ;; - aushp:SunOS:*:*) - GUESS=sparc-auspex-sunos$UNAME_RELEASE - ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - GUESS=m68k-atari-mint$UNAME_RELEASE - ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - GUESS=m68k-atari-mint$UNAME_RELEASE - ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - GUESS=m68k-atari-mint$UNAME_RELEASE - ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - GUESS=m68k-milan-mint$UNAME_RELEASE - ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - GUESS=m68k-hades-mint$UNAME_RELEASE - ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - GUESS=m68k-unknown-mint$UNAME_RELEASE - ;; - m68k:machten:*:*) - GUESS=m68k-apple-machten$UNAME_RELEASE - ;; - powerpc:machten:*:*) - GUESS=powerpc-apple-machten$UNAME_RELEASE - ;; - RISC*:Mach:*:*) - GUESS=mips-dec-mach_bsd4.3 - ;; - RISC*:ULTRIX:*:*) - GUESS=mips-dec-ultrix$UNAME_RELEASE - ;; - VAX*:ULTRIX*:*:*) - GUESS=vax-dec-ultrix$UNAME_RELEASE - ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - GUESS=clipper-intergraph-clix$UNAME_RELEASE - ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" -#ifdef __cplusplus -#include /* for printf() prototype */ - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && - dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`"$dummy" "$dummyarg"` && - { echo "$SYSTEM_NAME"; exit; } - GUESS=mips-mips-riscos$UNAME_RELEASE - ;; - Motorola:PowerMAX_OS:*:*) - GUESS=powerpc-motorola-powermax - ;; - Motorola:*:4.3:PL8-*) - GUESS=powerpc-harris-powermax - ;; - Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - GUESS=powerpc-harris-powermax - ;; - Night_Hawk:Power_UNIX:*:*) - GUESS=powerpc-harris-powerunix - ;; - m88k:CX/UX:7*:*) - GUESS=m88k-harris-cxux7 - ;; - m88k:*:4*:R4*) - GUESS=m88k-motorola-sysv4 - ;; - m88k:*:3*:R3*) - GUESS=m88k-motorola-sysv3 - ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 - then - if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ - test "$TARGET_BINARY_INTERFACE"x = x - then - GUESS=m88k-dg-dgux$UNAME_RELEASE - else - GUESS=m88k-dg-dguxbcs$UNAME_RELEASE - fi - else - GUESS=i586-dg-dgux$UNAME_RELEASE - fi - ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - GUESS=m88k-dolphin-sysv3 - ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - GUESS=m88k-motorola-sysv3 - ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - GUESS=m88k-tektronix-sysv3 - ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - GUESS=m68k-tektronix-bsd - ;; - *:IRIX*:*:*) - IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` - GUESS=mips-sgi-irix$IRIX_REL - ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id - ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i*86:AIX:*:*) - GUESS=i386-ibm-aix - ;; - ia64:AIX:*:*) - if test -x /usr/bin/oslevel ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=$UNAME_VERSION.$UNAME_RELEASE - fi - GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV - ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" - #include - - int - main () - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` - then - GUESS=$SYSTEM_NAME - else - GUESS=rs6000-ibm-aix3.2.5 - fi - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - GUESS=rs6000-ibm-aix3.2.4 - else - GUESS=rs6000-ibm-aix3.2 - fi - ;; - *:AIX:*:[4567]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if test -x /usr/bin/lslpp ; then - IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ - awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` - else - IBM_REV=$UNAME_VERSION.$UNAME_RELEASE - fi - GUESS=$IBM_ARCH-ibm-aix$IBM_REV - ;; - *:AIX:*:*) - GUESS=rs6000-ibm-aix - ;; - ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) - GUESS=romp-ibm-bsd4.4 - ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to - ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - GUESS=rs6000-bull-bosx - ;; - DPX/2?00:B.O.S.:*:*) - GUESS=m68k-bull-sysv3 - ;; - 9000/[34]??:4.3bsd:1.*:*) - GUESS=m68k-hp-bsd - ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - GUESS=m68k-hp-bsd4.4 - ;; - 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` - case $UNAME_MACHINE in - 9000/31?) HP_ARCH=m68000 ;; - 9000/[34]??) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - if test -x /usr/bin/getconf; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case $sc_cpu_version in - 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 - 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case $sc_kernel_bits in - 32) HP_ARCH=hppa2.0n ;; - 64) HP_ARCH=hppa2.0w ;; - '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 - esac ;; - esac - fi - if test "$HP_ARCH" = ""; then - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" - - #define _HPUX_SOURCE - #include - #include - - int - main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` - test -z "$HP_ARCH" && HP_ARCH=hppa - fi ;; - esac - if test "$HP_ARCH" = hppa2.0w - then - set_cc_for_build - - # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating - # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler - # generating 64-bit code. GNU and HP use different nomenclature: - # - # $ CC_FOR_BUILD=cc ./config.guess - # => hppa2.0w-hp-hpux11.23 - # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess - # => hppa64-hp-hpux11.23 - - if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | - grep -q __LP64__ - then - HP_ARCH=hppa2.0w - else - HP_ARCH=hppa64 - fi - fi - GUESS=$HP_ARCH-hp-hpux$HPUX_REV - ;; - ia64:HP-UX:*:*) - HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` - GUESS=ia64-hp-hpux$HPUX_REV - ;; - 3050*:HI-UX:*:*) - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" - #include - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && - { echo "$SYSTEM_NAME"; exit; } - GUESS=unknown-hitachi-hiuxwe2 - ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) - GUESS=hppa1.1-hp-bsd - ;; - 9000/8??:4.3bsd:*:*) - GUESS=hppa1.0-hp-bsd - ;; - *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - GUESS=hppa1.0-hp-mpeix - ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) - GUESS=hppa1.1-hp-osf - ;; - hp8??:OSF1:*:*) - GUESS=hppa1.0-hp-osf - ;; - i*86:OSF1:*:*) - if test -x /usr/sbin/sysversion ; then - GUESS=$UNAME_MACHINE-unknown-osf1mk - else - GUESS=$UNAME_MACHINE-unknown-osf1 - fi - ;; - parisc*:Lites*:*:*) - GUESS=hppa1.1-hp-lites - ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - GUESS=c1-convex-bsd - ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - GUESS=c34-convex-bsd - ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - GUESS=c38-convex-bsd - ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - GUESS=c4-convex-bsd - ;; - CRAY*Y-MP:*:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=ymp-cray-unicos$CRAY_REL - ;; - CRAY*[A-Z]90:*:*:*) - echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ - -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*TS:*:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=t90-cray-unicos$CRAY_REL - ;; - CRAY*T3E:*:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=alphaev5-cray-unicosmk$CRAY_REL - ;; - CRAY*SV1:*:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=sv1-cray-unicos$CRAY_REL - ;; - *:UNICOS/mp:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=craynv-cray-unicosmp$CRAY_REL - ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` - GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} - ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` - GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} - ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE - ;; - sparc*:BSD/OS:*:*) - GUESS=sparc-unknown-bsdi$UNAME_RELEASE - ;; - *:BSD/OS:*:*) - GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE - ;; - arm:FreeBSD:*:*) - UNAME_PROCESSOR=`uname -p` - set_cc_for_build - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi - else - FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf - fi - ;; - *:FreeBSD:*:*) - UNAME_PROCESSOR=`uname -p` - case $UNAME_PROCESSOR in - amd64) - UNAME_PROCESSOR=x86_64 ;; - i386) - UNAME_PROCESSOR=i586 ;; - esac - FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL - ;; - i*:CYGWIN*:*) - GUESS=$UNAME_MACHINE-pc-cygwin - ;; - *:MINGW64*:*) - GUESS=$UNAME_MACHINE-pc-mingw64 - ;; - *:MINGW*:*) - GUESS=$UNAME_MACHINE-pc-mingw32 - ;; - *:MSYS*:*) - GUESS=$UNAME_MACHINE-pc-msys - ;; - i*:PW*:*) - GUESS=$UNAME_MACHINE-pc-pw32 - ;; - *:SerenityOS:*:*) - GUESS=$UNAME_MACHINE-pc-serenity - ;; - *:Interix*:*) - case $UNAME_MACHINE in - x86) - GUESS=i586-pc-interix$UNAME_RELEASE - ;; - authenticamd | genuineintel | EM64T) - GUESS=x86_64-unknown-interix$UNAME_RELEASE - ;; - IA64) - GUESS=ia64-unknown-interix$UNAME_RELEASE - ;; - esac ;; - i*:UWIN*:*) - GUESS=$UNAME_MACHINE-pc-uwin - ;; - amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - GUESS=x86_64-pc-cygwin - ;; - prep*:SunOS:5.*:*) - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=powerpcle-unknown-solaris2$SUN_REL - ;; - *:GNU:*:*) - # the GNU system - GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` - GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` - GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL - ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` - GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC - ;; - x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) - GUESS="$UNAME_MACHINE-pc-managarm-mlibc" - ;; - *:[Mm]anagarm:*:*) - GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" - ;; - *:Minix:*:*) - GUESS=$UNAME_MACHINE-unknown-minix - ;; - aarch64:Linux:*:*) - set_cc_for_build - CPU=$UNAME_MACHINE - LIBCABI=$LIBC - if test "$CC_FOR_BUILD" != no_compiler_found; then - ABI=64 - sed 's/^ //' << EOF > "$dummy.c" - #ifdef __ARM_EABI__ - #ifdef __ARM_PCS_VFP - ABI=eabihf - #else - ABI=eabi - #endif - #endif -EOF - cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` - eval "$cc_set_abi" - case $ABI in - eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; - esac - fi - GUESS=$CPU-unknown-linux-$LIBCABI - ;; - aarch64_be:Linux:*:*) - UNAME_MACHINE=aarch64_be - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - arm*:Linux:*:*) - set_cc_for_build - if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_EABI__ - then - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - else - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi - else - GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf - fi - fi - ;; - avr32*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - cris:Linux:*:*) - GUESS=$UNAME_MACHINE-axis-linux-$LIBC - ;; - crisv32:Linux:*:*) - GUESS=$UNAME_MACHINE-axis-linux-$LIBC - ;; - e2k:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - frv:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - hexagon:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - i*86:Linux:*:*) - GUESS=$UNAME_MACHINE-pc-linux-$LIBC - ;; - ia64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - k1om:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - kvx:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - kvx:cos:*:*) - GUESS=$UNAME_MACHINE-unknown-cos - ;; - kvx:mbr:*:*) - GUESS=$UNAME_MACHINE-unknown-mbr - ;; - loongarch32:Linux:*:* | loongarch64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - m32r*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - m68*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - mips:Linux:*:* | mips64:Linux:*:*) - set_cc_for_build - IS_GLIBC=0 - test x"${LIBC}" = xgnu && IS_GLIBC=1 - sed 's/^ //' << EOF > "$dummy.c" - #undef CPU - #undef mips - #undef mipsel - #undef mips64 - #undef mips64el - #if ${IS_GLIBC} && defined(_ABI64) - LIBCABI=gnuabi64 - #else - #if ${IS_GLIBC} && defined(_ABIN32) - LIBCABI=gnuabin32 - #else - LIBCABI=${LIBC} - #endif - #endif - - #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 - CPU=mipsisa64r6 - #else - #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 - CPU=mipsisa32r6 - #else - #if defined(__mips64) - CPU=mips64 - #else - CPU=mips - #endif - #endif - #endif - - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - MIPS_ENDIAN=el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - MIPS_ENDIAN= - #else - MIPS_ENDIAN= - #endif - #endif -EOF - cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` - eval "$cc_set_vars" - test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } - ;; - mips64el:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - openrisc*:Linux:*:*) - GUESS=or1k-unknown-linux-$LIBC - ;; - or32:Linux:*:* | or1k*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - padre:Linux:*:*) - GUESS=sparc-unknown-linux-$LIBC - ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - GUESS=hppa64-unknown-linux-$LIBC - ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; - PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; - *) GUESS=hppa-unknown-linux-$LIBC ;; - esac - ;; - ppc64:Linux:*:*) - GUESS=powerpc64-unknown-linux-$LIBC - ;; - ppc:Linux:*:*) - GUESS=powerpc-unknown-linux-$LIBC - ;; - ppc64le:Linux:*:*) - GUESS=powerpc64le-unknown-linux-$LIBC - ;; - ppcle:Linux:*:*) - GUESS=powerpcle-unknown-linux-$LIBC - ;; - riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - s390:Linux:*:* | s390x:Linux:*:*) - GUESS=$UNAME_MACHINE-ibm-linux-$LIBC - ;; - sh64*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - sh*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - sparc:Linux:*:* | sparc64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - tile*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - vax:Linux:*:*) - GUESS=$UNAME_MACHINE-dec-linux-$LIBC - ;; - x86_64:Linux:*:*) - set_cc_for_build - CPU=$UNAME_MACHINE - LIBCABI=$LIBC - if test "$CC_FOR_BUILD" != no_compiler_found; then - ABI=64 - sed 's/^ //' << EOF > "$dummy.c" - #ifdef __i386__ - ABI=x86 - #else - #ifdef __ILP32__ - ABI=x32 - #endif - #endif -EOF - cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` - eval "$cc_set_abi" - case $ABI in - x86) CPU=i686 ;; - x32) LIBCABI=${LIBC}x32 ;; - esac - fi - GUESS=$CPU-pc-linux-$LIBCABI - ;; - xtensa*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. - # earlier versions are messed up and put the nodename in both - # sysname and nodename. - GUESS=i386-sequent-sysv4 - ;; - i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION - ;; - i*86:OS/2:*:*) - # If we were able to find 'uname', then EMX Unix compatibility - # is probably installed. - GUESS=$UNAME_MACHINE-pc-os2-emx - ;; - i*86:XTS-300:*:STOP) - GUESS=$UNAME_MACHINE-unknown-stop - ;; - i*86:atheos:*:*) - GUESS=$UNAME_MACHINE-unknown-atheos - ;; - i*86:syllable:*:*) - GUESS=$UNAME_MACHINE-pc-syllable - ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - GUESS=i386-unknown-lynxos$UNAME_RELEASE - ;; - i*86:*DOS:*:*) - GUESS=$UNAME_MACHINE-pc-msdosdjgpp - ;; - i*86:*:4.*:*) - UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL - else - GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL - fi - ;; - i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; - *Pent*|*Celeron) UNAME_MACHINE=i686 ;; - esac - GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - ;; - i*86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` - (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL - else - GUESS=$UNAME_MACHINE-pc-sysv32 - fi - ;; - pc:*:*:*) - # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i586. - # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configure will decide that - # this is a cross-build. - GUESS=i586-pc-msdosdjgpp - ;; - Intel:Mach:3*:*) - GUESS=i386-pc-mach3 - ;; - paragon:*:*:*) - GUESS=i860-intel-osf1 - ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 - fi - ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - GUESS=m68010-convergent-sysv - ;; - mc68k:UNIX:SYSTEM5:3.51m) - GUESS=m68k-convergent-sysv - ;; - M680?0:D-NIX:5.3:*) - GUESS=m68k-diab-dnix - ;; - M68*:*:R3V[5678]*:*) - test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; - NCR*:*:4.2:* | MPRAS*:*:4.2:*) - OS_REL='.3' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; - m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - GUESS=m68k-unknown-lynxos$UNAME_RELEASE - ;; - mc68030:UNIX_System_V:4.*:*) - GUESS=m68k-atari-sysv4 - ;; - TSUNAMI:LynxOS:2.*:*) - GUESS=sparc-unknown-lynxos$UNAME_RELEASE - ;; - rs6000:LynxOS:2.*:*) - GUESS=rs6000-unknown-lynxos$UNAME_RELEASE - ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - GUESS=powerpc-unknown-lynxos$UNAME_RELEASE - ;; - SM[BE]S:UNIX_SV:*:*) - GUESS=mips-dde-sysv$UNAME_RELEASE - ;; - RM*:ReliantUNIX-*:*:*) - GUESS=mips-sni-sysv4 - ;; - RM*:SINIX-*:*:*) - GUESS=mips-sni-sysv4 - ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - GUESS=$UNAME_MACHINE-sni-sysv4 - else - GUESS=ns32k-sni-sysv - fi - ;; - PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort - # says - GUESS=i586-unisys-sysv4 - ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes . - # How about differentiating between stratus architectures? -djm - GUESS=hppa1.1-stratus-sysv4 - ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - GUESS=i860-stratus-sysv4 - ;; - i*86:VOS:*:*) - # From Paul.Green@stratus.com. - GUESS=$UNAME_MACHINE-stratus-vos - ;; - *:VOS:*:*) - # From Paul.Green@stratus.com. - GUESS=hppa1.1-stratus-vos - ;; - mc68*:A/UX:*:*) - GUESS=m68k-apple-aux$UNAME_RELEASE - ;; - news*:NEWS-OS:6*:*) - GUESS=mips-sony-newsos6 - ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if test -d /usr/nec; then - GUESS=mips-nec-sysv$UNAME_RELEASE - else - GUESS=mips-unknown-sysv$UNAME_RELEASE - fi - ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - GUESS=powerpc-be-beos - ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - GUESS=powerpc-apple-beos - ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - GUESS=i586-pc-beos - ;; - BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - GUESS=i586-pc-haiku - ;; - ppc:Haiku:*:*) # Haiku running on Apple PowerPC - GUESS=powerpc-apple-haiku - ;; - *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) - GUESS=$UNAME_MACHINE-unknown-haiku - ;; - SX-4:SUPER-UX:*:*) - GUESS=sx4-nec-superux$UNAME_RELEASE - ;; - SX-5:SUPER-UX:*:*) - GUESS=sx5-nec-superux$UNAME_RELEASE - ;; - SX-6:SUPER-UX:*:*) - GUESS=sx6-nec-superux$UNAME_RELEASE - ;; - SX-7:SUPER-UX:*:*) - GUESS=sx7-nec-superux$UNAME_RELEASE - ;; - SX-8:SUPER-UX:*:*) - GUESS=sx8-nec-superux$UNAME_RELEASE - ;; - SX-8R:SUPER-UX:*:*) - GUESS=sx8r-nec-superux$UNAME_RELEASE - ;; - SX-ACE:SUPER-UX:*:*) - GUESS=sxace-nec-superux$UNAME_RELEASE - ;; - Power*:Rhapsody:*:*) - GUESS=powerpc-apple-rhapsody$UNAME_RELEASE - ;; - *:Rhapsody:*:*) - GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE - ;; - arm64:Darwin:*:*) - GUESS=aarch64-apple-darwin$UNAME_RELEASE - ;; - *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` - case $UNAME_PROCESSOR in - unknown) UNAME_PROCESSOR=powerpc ;; - esac - if command -v xcode-select > /dev/null 2> /dev/null && \ - ! xcode-select --print-path > /dev/null 2> /dev/null ; then - # Avoid executing cc if there is no toolchain installed as - # cc will be a stub that puts up a graphical alert - # prompting the user to install developer tools. - CC_FOR_BUILD=no_compiler_found - else - set_cc_for_build - fi - if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac - fi - # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc - if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_PPC >/dev/null - then - UNAME_PROCESSOR=powerpc - fi - elif test "$UNAME_PROCESSOR" = i386 ; then - # uname -m returns i386 or x86_64 - UNAME_PROCESSOR=$UNAME_MACHINE - fi - GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE - ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = x86; then - UNAME_PROCESSOR=i386 - UNAME_MACHINE=pc - fi - GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE - ;; - *:QNX:*:4*) - GUESS=i386-pc-qnx - ;; - NEO-*:NONSTOP_KERNEL:*:*) - GUESS=neo-tandem-nsk$UNAME_RELEASE - ;; - NSE-*:NONSTOP_KERNEL:*:*) - GUESS=nse-tandem-nsk$UNAME_RELEASE - ;; - NSR-*:NONSTOP_KERNEL:*:*) - GUESS=nsr-tandem-nsk$UNAME_RELEASE - ;; - NSV-*:NONSTOP_KERNEL:*:*) - GUESS=nsv-tandem-nsk$UNAME_RELEASE - ;; - NSX-*:NONSTOP_KERNEL:*:*) - GUESS=nsx-tandem-nsk$UNAME_RELEASE - ;; - *:NonStop-UX:*:*) - GUESS=mips-compaq-nonstopux - ;; - BS2000:POSIX*:*:*) - GUESS=bs2000-siemens-sysv - ;; - DS/*:UNIX_System_V:*:*) - GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE - ;; - *:Plan9:*:*) - # "uname -m" is not consistent, so use $cputype instead. 386 - # is converted to i386 for consistency with other x86 - # operating systems. - if test "${cputype-}" = 386; then - UNAME_MACHINE=i386 - elif test "x${cputype-}" != x; then - UNAME_MACHINE=$cputype - fi - GUESS=$UNAME_MACHINE-unknown-plan9 - ;; - *:TOPS-10:*:*) - GUESS=pdp10-unknown-tops10 - ;; - *:TENEX:*:*) - GUESS=pdp10-unknown-tenex - ;; - KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - GUESS=pdp10-dec-tops20 - ;; - XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - GUESS=pdp10-xkl-tops20 - ;; - *:TOPS-20:*:*) - GUESS=pdp10-unknown-tops20 - ;; - *:ITS:*:*) - GUESS=pdp10-unknown-its - ;; - SEI:*:*:SEIUX) - GUESS=mips-sei-seiux$UNAME_RELEASE - ;; - *:DragonFly:*:*) - DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL - ;; - *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case $UNAME_MACHINE in - A*) GUESS=alpha-dec-vms ;; - I*) GUESS=ia64-dec-vms ;; - V*) GUESS=vax-dec-vms ;; - esac ;; - *:XENIX:*:SysV) - GUESS=i386-pc-xenix - ;; - i*86:skyos:*:*) - SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` - GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL - ;; - i*86:rdos:*:*) - GUESS=$UNAME_MACHINE-pc-rdos - ;; - i*86:Fiwix:*:*) - GUESS=$UNAME_MACHINE-pc-fiwix - ;; - *:AROS:*:*) - GUESS=$UNAME_MACHINE-unknown-aros - ;; - x86_64:VMkernel:*:*) - GUESS=$UNAME_MACHINE-unknown-esx - ;; - amd64:Isilon\ OneFS:*:*) - GUESS=x86_64-unknown-onefs - ;; - *:Unleashed:*:*) - GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE - ;; - x86_64:[Ii]ronclad:*:*|i?86:[Ii]ronclad:*:*) - GUESS=$UNAME_MACHINE-pc-ironclad-mlibc - ;; - *:[Ii]ronclad:*:*) - GUESS=$UNAME_MACHINE-unknown-ironclad-mlibc - ;; -esac - -# Do we have a guess based on uname results? -if test "x$GUESS" != x; then - echo "$GUESS" - exit -fi - -# No uname command or uname output not recognized. -set_cc_for_build -cat > "$dummy.c" < -#include -#endif -#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) -#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) -#include -#if defined(_SIZE_T_) || defined(SIGLOST) -#include -#endif -#endif -#endif -int -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); -#endif - -#if defined (vax) -#if !defined (ultrix) -#include -#if defined (BSD) -#if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -#else -#if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -#else - printf ("vax-dec-bsd\n"); exit (0); -#endif -#endif -#else - printf ("vax-dec-bsd\n"); exit (0); -#endif -#else -#if defined(_SIZE_T_) || defined(SIGLOST) - struct utsname un; - uname (&un); - printf ("vax-dec-ultrix%s\n", un.release); exit (0); -#else - printf ("vax-dec-ultrix\n"); exit (0); -#endif -#endif -#endif -#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) -#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) -#if defined(_SIZE_T_) || defined(SIGLOST) - struct utsname *un; - uname (&un); - printf ("mips-dec-ultrix%s\n", un.release); exit (0); -#else - printf ("mips-dec-ultrix\n"); exit (0); -#endif -#endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. -test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } - -echo "$0: unable to guess system type" >&2 - -case $UNAME_MACHINE:$UNAME_SYSTEM in - mips:Linux | mips64:Linux) - # If we got here on MIPS GNU/Linux, output extra information. - cat >&2 <&2 <&2 </dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` - -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` - -UNAME_MACHINE = "$UNAME_MACHINE" -UNAME_RELEASE = "$UNAME_RELEASE" -UNAME_SYSTEM = "$UNAME_SYSTEM" -UNAME_VERSION = "$UNAME_VERSION" -EOF -fi - -exit 1 - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp nil t) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%Y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/experiments/wasm-gui/third_party/libXext/config.guess~ b/experiments/wasm-gui/third_party/libXext/config.guess~ deleted file mode 100755 index 48a684601..000000000 --- a/experiments/wasm-gui/third_party/libXext/config.guess~ +++ /dev/null @@ -1,1815 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright 1992-2024 Free Software Foundation, Inc. - -# shellcheck disable=SC2006,SC2268 # see below for rationale - -timestamp='2024-07-27' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). -# -# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. -# -# You can get the latest version of this script from: -# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess -# -# Please send patches to . - - -# The "shellcheck disable" line above the timestamp inhibits complaints -# about features and limitations of the classic Bourne shell that were -# superseded or lifted in POSIX. However, this script identifies a wide -# variety of pre-POSIX systems that do not have POSIX shells at all, and -# even some reasonably current systems (Solaris 10 as case-in-point) still -# have a pre-POSIX /bin/sh. - - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] - -Output the configuration name of the system '$me' is run on. - -Options: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.guess ($timestamp) - -Originally written by Per Bothner. -Copyright 1992-2024 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try '$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - * ) - break ;; - esac -done - -if test $# != 0; then - echo "$me: too many arguments$help" >&2 - exit 1 -fi - -# Just in case it came from the environment. -GUESS= - -# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -# compiler to aid in system detection is discouraged as it requires -# temporary files to be created and, as you can see below, it is a -# headache to deal with in a portable fashion. - -# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still -# use 'HOST_CC' if defined, but it is deprecated. - -# Portable tmp directory creation inspired by the Autoconf team. - -tmp= -# shellcheck disable=SC2172 -trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 - -set_cc_for_build() { - # prevent multiple calls if $tmp is already set - test "$tmp" && return 0 - : "${TMPDIR=/tmp}" - # shellcheck disable=SC2039,SC3028 - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } - dummy=$tmp/dummy - case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in - ,,) echo "int x;" > "$dummy.c" - for driver in cc gcc c17 c99 c89 ; do - if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then - CC_FOR_BUILD=$driver - break - fi - done - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; - esac -} - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 1994-08-24) -if test -f /.attbin/uname ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -case $UNAME_SYSTEM in -Linux|GNU|GNU/*) - LIBC=unknown - - set_cc_for_build - cat <<-EOF > "$dummy.c" - #if defined(__ANDROID__) - LIBC=android - #else - #include - #if defined(__UCLIBC__) - LIBC=uclibc - #elif defined(__dietlibc__) - LIBC=dietlibc - #elif defined(__GLIBC__) - LIBC=gnu - #elif defined(__LLVM_LIBC__) - LIBC=llvm - #else - #include - /* First heuristic to detect musl libc. */ - #ifdef __DEFINED_va_list - LIBC=musl - #endif - #endif - #endif - EOF - cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` - eval "$cc_set_libc" - - # Second heuristic to detect musl libc. - if [ "$LIBC" = unknown ] && - command -v ldd >/dev/null && - ldd --version 2>&1 | grep -q ^musl; then - LIBC=musl - fi - - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - if [ "$LIBC" = unknown ]; then - LIBC=gnu - fi - ;; -esac - -# Note: order is significant - the case branches are not exclusive. - -case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward - # compatibility and a consistent mechanism for selecting the - # object file format. - # - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ - /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ - echo unknown)` - case $UNAME_MACHINE_ARCH in - aarch64eb) machine=aarch64_be-unknown ;; - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-unknown ;; - sh5el) machine=sh5le-unknown ;; - earmv*) - arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` - endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` - machine=${arch}${endian}-unknown - ;; - *) machine=$UNAME_MACHINE_ARCH-unknown ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently (or will in the future) and ABI. - case $UNAME_MACHINE_ARCH in - earm*) - os=netbsdelf - ;; - arm*|i386|m68k|ns32k|sh3*|sparc|vax) - set_cc_for_build - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ELF__ - then - # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). - # Return netbsd for either. FIX? - os=netbsd - else - os=netbsdelf - fi - ;; - *) - os=netbsd - ;; - esac - # Determine ABI tags. - case $UNAME_MACHINE_ARCH in - earm*) - expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` - ;; - esac - # The OS release - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need - # kernel version information, so it can be replaced with a - # suitable tag, in the style of linux-gnu. - case $UNAME_VERSION in - Debian*) - release='-gnu' - ;; - *) - release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` - ;; - esac - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - GUESS=$machine-${os}${release}${abi-} - ;; - *:Bitrig:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE - ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE - ;; - *:SecBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` - GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE - ;; - *:LibertyBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` - GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE - ;; - *:MidnightBSD:*:*) - GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE - ;; - *:ekkoBSD:*:*) - GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE - ;; - *:SolidBSD:*:*) - GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE - ;; - *:OS108:*:*) - GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE - ;; - macppc:MirBSD:*:*) - GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE - ;; - *:MirBSD:*:*) - GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE - ;; - *:Sortix:*:*) - GUESS=$UNAME_MACHINE-unknown-sortix - ;; - *:Twizzler:*:*) - GUESS=$UNAME_MACHINE-unknown-twizzler - ;; - *:Redox:*:*) - GUESS=$UNAME_MACHINE-unknown-redox - ;; - mips:OSF1:*.*) - GUESS=mips-dec-osf1 - ;; - alpha:OSF1:*:*) - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - trap '' 0 - case $UNAME_RELEASE in - *4.0) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that - # covers most systems running today. This code pipes the CPU - # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case $ALPHA_CPU_TYPE in - "EV4 (21064)") - UNAME_MACHINE=alpha ;; - "EV4.5 (21064)") - UNAME_MACHINE=alpha ;; - "LCA4 (21066/21068)") - UNAME_MACHINE=alpha ;; - "EV5 (21164)") - UNAME_MACHINE=alphaev5 ;; - "EV5.6 (21164A)") - UNAME_MACHINE=alphaev56 ;; - "EV5.6 (21164PC)") - UNAME_MACHINE=alphapca56 ;; - "EV5.7 (21164PC)") - UNAME_MACHINE=alphapca57 ;; - "EV6 (21264)") - UNAME_MACHINE=alphaev6 ;; - "EV6.7 (21264A)") - UNAME_MACHINE=alphaev67 ;; - "EV6.8CB (21264C)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8AL (21264B)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8CX (21264D)") - UNAME_MACHINE=alphaev68 ;; - "EV6.9A (21264/EV69A)") - UNAME_MACHINE=alphaev69 ;; - "EV7 (21364)") - UNAME_MACHINE=alphaev7 ;; - "EV7.9 (21364A)") - UNAME_MACHINE=alphaev79 ;; - esac - # A Pn.n version is a patched version. - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` - GUESS=$UNAME_MACHINE-dec-osf$OSF_REL - ;; - Amiga*:UNIX_System_V:4.0:*) - GUESS=m68k-unknown-sysv4 - ;; - *:[Aa]miga[Oo][Ss]:*:*) - GUESS=$UNAME_MACHINE-unknown-amigaos - ;; - *:[Mm]orph[Oo][Ss]:*:*) - GUESS=$UNAME_MACHINE-unknown-morphos - ;; - *:OS/390:*:*) - GUESS=i370-ibm-openedition - ;; - *:z/VM:*:*) - GUESS=s390-ibm-zvmoe - ;; - *:OS400:*:*) - GUESS=powerpc-ibm-os400 - ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - GUESS=arm-acorn-riscix$UNAME_RELEASE - ;; - arm*:riscos:*:*|arm*:RISCOS:*:*) - GUESS=arm-unknown-riscos - ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - GUESS=hppa1.1-hitachi-hiuxmpp - ;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - case `(/bin/universe) 2>/dev/null` in - att) GUESS=pyramid-pyramid-sysv3 ;; - *) GUESS=pyramid-pyramid-bsd ;; - esac - ;; - NILE*:*:*:dcosx) - GUESS=pyramid-pyramid-svr4 - ;; - DRS?6000:unix:4.0:6*) - GUESS=sparc-icl-nx6 - ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case `/usr/bin/uname -p` in - sparc) GUESS=sparc-icl-nx7 ;; - esac - ;; - s390x:SunOS:*:*) - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL - ;; - sun4H:SunOS:5.*:*) - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=sparc-hal-solaris2$SUN_REL - ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=sparc-sun-solaris2$SUN_REL - ;; - i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - GUESS=i386-pc-auroraux$UNAME_RELEASE - ;; - i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - set_cc_for_build - SUN_ARCH=i386 - # If there is a compiler, see if it is configured for 64-bit objects. - # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. - # This test works for both compilers. - if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - SUN_ARCH=x86_64 - fi - fi - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=$SUN_ARCH-pc-solaris2$SUN_REL - ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=sparc-sun-solaris3$SUN_REL - ;; - sun4*:SunOS:*:*) - case `/usr/bin/arch -k` in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like '4.1.3-JL'. - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` - GUESS=sparc-sun-sunos$SUN_REL - ;; - sun3*:SunOS:*:*) - GUESS=m68k-sun-sunos$UNAME_RELEASE - ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 - case `/bin/arch` in - sun3) - GUESS=m68k-sun-sunos$UNAME_RELEASE - ;; - sun4) - GUESS=sparc-sun-sunos$UNAME_RELEASE - ;; - esac - ;; - aushp:SunOS:*:*) - GUESS=sparc-auspex-sunos$UNAME_RELEASE - ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - GUESS=m68k-atari-mint$UNAME_RELEASE - ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - GUESS=m68k-atari-mint$UNAME_RELEASE - ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - GUESS=m68k-atari-mint$UNAME_RELEASE - ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - GUESS=m68k-milan-mint$UNAME_RELEASE - ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - GUESS=m68k-hades-mint$UNAME_RELEASE - ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - GUESS=m68k-unknown-mint$UNAME_RELEASE - ;; - m68k:machten:*:*) - GUESS=m68k-apple-machten$UNAME_RELEASE - ;; - powerpc:machten:*:*) - GUESS=powerpc-apple-machten$UNAME_RELEASE - ;; - RISC*:Mach:*:*) - GUESS=mips-dec-mach_bsd4.3 - ;; - RISC*:ULTRIX:*:*) - GUESS=mips-dec-ultrix$UNAME_RELEASE - ;; - VAX*:ULTRIX*:*:*) - GUESS=vax-dec-ultrix$UNAME_RELEASE - ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - GUESS=clipper-intergraph-clix$UNAME_RELEASE - ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" -#ifdef __cplusplus -#include /* for printf() prototype */ - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && - dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`"$dummy" "$dummyarg"` && - { echo "$SYSTEM_NAME"; exit; } - GUESS=mips-mips-riscos$UNAME_RELEASE - ;; - Motorola:PowerMAX_OS:*:*) - GUESS=powerpc-motorola-powermax - ;; - Motorola:*:4.3:PL8-*) - GUESS=powerpc-harris-powermax - ;; - Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - GUESS=powerpc-harris-powermax - ;; - Night_Hawk:Power_UNIX:*:*) - GUESS=powerpc-harris-powerunix - ;; - m88k:CX/UX:7*:*) - GUESS=m88k-harris-cxux7 - ;; - m88k:*:4*:R4*) - GUESS=m88k-motorola-sysv4 - ;; - m88k:*:3*:R3*) - GUESS=m88k-motorola-sysv3 - ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 - then - if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ - test "$TARGET_BINARY_INTERFACE"x = x - then - GUESS=m88k-dg-dgux$UNAME_RELEASE - else - GUESS=m88k-dg-dguxbcs$UNAME_RELEASE - fi - else - GUESS=i586-dg-dgux$UNAME_RELEASE - fi - ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - GUESS=m88k-dolphin-sysv3 - ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - GUESS=m88k-motorola-sysv3 - ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - GUESS=m88k-tektronix-sysv3 - ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - GUESS=m68k-tektronix-bsd - ;; - *:IRIX*:*:*) - IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` - GUESS=mips-sgi-irix$IRIX_REL - ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id - ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i*86:AIX:*:*) - GUESS=i386-ibm-aix - ;; - ia64:AIX:*:*) - if test -x /usr/bin/oslevel ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=$UNAME_VERSION.$UNAME_RELEASE - fi - GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV - ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" - #include - - int - main () - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` - then - GUESS=$SYSTEM_NAME - else - GUESS=rs6000-ibm-aix3.2.5 - fi - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - GUESS=rs6000-ibm-aix3.2.4 - else - GUESS=rs6000-ibm-aix3.2 - fi - ;; - *:AIX:*:[4567]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if test -x /usr/bin/lslpp ; then - IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ - awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` - else - IBM_REV=$UNAME_VERSION.$UNAME_RELEASE - fi - GUESS=$IBM_ARCH-ibm-aix$IBM_REV - ;; - *:AIX:*:*) - GUESS=rs6000-ibm-aix - ;; - ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) - GUESS=romp-ibm-bsd4.4 - ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to - ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - GUESS=rs6000-bull-bosx - ;; - DPX/2?00:B.O.S.:*:*) - GUESS=m68k-bull-sysv3 - ;; - 9000/[34]??:4.3bsd:1.*:*) - GUESS=m68k-hp-bsd - ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - GUESS=m68k-hp-bsd4.4 - ;; - 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` - case $UNAME_MACHINE in - 9000/31?) HP_ARCH=m68000 ;; - 9000/[34]??) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - if test -x /usr/bin/getconf; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case $sc_cpu_version in - 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 - 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case $sc_kernel_bits in - 32) HP_ARCH=hppa2.0n ;; - 64) HP_ARCH=hppa2.0w ;; - '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 - esac ;; - esac - fi - if test "$HP_ARCH" = ""; then - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" - - #define _HPUX_SOURCE - #include - #include - - int - main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` - test -z "$HP_ARCH" && HP_ARCH=hppa - fi ;; - esac - if test "$HP_ARCH" = hppa2.0w - then - set_cc_for_build - - # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating - # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler - # generating 64-bit code. GNU and HP use different nomenclature: - # - # $ CC_FOR_BUILD=cc ./config.guess - # => hppa2.0w-hp-hpux11.23 - # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess - # => hppa64-hp-hpux11.23 - - if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | - grep -q __LP64__ - then - HP_ARCH=hppa2.0w - else - HP_ARCH=hppa64 - fi - fi - GUESS=$HP_ARCH-hp-hpux$HPUX_REV - ;; - ia64:HP-UX:*:*) - HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` - GUESS=ia64-hp-hpux$HPUX_REV - ;; - 3050*:HI-UX:*:*) - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" - #include - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && - { echo "$SYSTEM_NAME"; exit; } - GUESS=unknown-hitachi-hiuxwe2 - ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) - GUESS=hppa1.1-hp-bsd - ;; - 9000/8??:4.3bsd:*:*) - GUESS=hppa1.0-hp-bsd - ;; - *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - GUESS=hppa1.0-hp-mpeix - ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) - GUESS=hppa1.1-hp-osf - ;; - hp8??:OSF1:*:*) - GUESS=hppa1.0-hp-osf - ;; - i*86:OSF1:*:*) - if test -x /usr/sbin/sysversion ; then - GUESS=$UNAME_MACHINE-unknown-osf1mk - else - GUESS=$UNAME_MACHINE-unknown-osf1 - fi - ;; - parisc*:Lites*:*:*) - GUESS=hppa1.1-hp-lites - ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - GUESS=c1-convex-bsd - ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - GUESS=c34-convex-bsd - ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - GUESS=c38-convex-bsd - ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - GUESS=c4-convex-bsd - ;; - CRAY*Y-MP:*:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=ymp-cray-unicos$CRAY_REL - ;; - CRAY*[A-Z]90:*:*:*) - echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ - -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*TS:*:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=t90-cray-unicos$CRAY_REL - ;; - CRAY*T3E:*:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=alphaev5-cray-unicosmk$CRAY_REL - ;; - CRAY*SV1:*:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=sv1-cray-unicos$CRAY_REL - ;; - *:UNICOS/mp:*:*) - CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` - GUESS=craynv-cray-unicosmp$CRAY_REL - ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` - GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} - ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` - GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} - ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE - ;; - sparc*:BSD/OS:*:*) - GUESS=sparc-unknown-bsdi$UNAME_RELEASE - ;; - *:BSD/OS:*:*) - GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE - ;; - arm:FreeBSD:*:*) - UNAME_PROCESSOR=`uname -p` - set_cc_for_build - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi - else - FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf - fi - ;; - *:FreeBSD:*:*) - UNAME_PROCESSOR=`uname -p` - case $UNAME_PROCESSOR in - amd64) - UNAME_PROCESSOR=x86_64 ;; - i386) - UNAME_PROCESSOR=i586 ;; - esac - FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL - ;; - i*:CYGWIN*:*) - GUESS=$UNAME_MACHINE-pc-cygwin - ;; - *:MINGW64*:*) - GUESS=$UNAME_MACHINE-pc-mingw64 - ;; - *:MINGW*:*) - GUESS=$UNAME_MACHINE-pc-mingw32 - ;; - *:MSYS*:*) - GUESS=$UNAME_MACHINE-pc-msys - ;; - i*:PW*:*) - GUESS=$UNAME_MACHINE-pc-pw32 - ;; - *:SerenityOS:*:*) - GUESS=$UNAME_MACHINE-pc-serenity - ;; - *:Interix*:*) - case $UNAME_MACHINE in - x86) - GUESS=i586-pc-interix$UNAME_RELEASE - ;; - authenticamd | genuineintel | EM64T) - GUESS=x86_64-unknown-interix$UNAME_RELEASE - ;; - IA64) - GUESS=ia64-unknown-interix$UNAME_RELEASE - ;; - esac ;; - i*:UWIN*:*) - GUESS=$UNAME_MACHINE-pc-uwin - ;; - amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - GUESS=x86_64-pc-cygwin - ;; - prep*:SunOS:5.*:*) - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` - GUESS=powerpcle-unknown-solaris2$SUN_REL - ;; - *:GNU:*:*) - # the GNU system - GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` - GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` - GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL - ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` - GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC - ;; - x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) - GUESS="$UNAME_MACHINE-pc-managarm-mlibc" - ;; - *:[Mm]anagarm:*:*) - GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" - ;; - *:Minix:*:*) - GUESS=$UNAME_MACHINE-unknown-minix - ;; - aarch64:Linux:*:*) - set_cc_for_build - CPU=$UNAME_MACHINE - LIBCABI=$LIBC - if test "$CC_FOR_BUILD" != no_compiler_found; then - ABI=64 - sed 's/^ //' << EOF > "$dummy.c" - #ifdef __ARM_EABI__ - #ifdef __ARM_PCS_VFP - ABI=eabihf - #else - ABI=eabi - #endif - #endif -EOF - cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` - eval "$cc_set_abi" - case $ABI in - eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; - esac - fi - GUESS=$CPU-unknown-linux-$LIBCABI - ;; - aarch64_be:Linux:*:*) - UNAME_MACHINE=aarch64_be - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - arm*:Linux:*:*) - set_cc_for_build - if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_EABI__ - then - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - else - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi - else - GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf - fi - fi - ;; - avr32*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - cris:Linux:*:*) - GUESS=$UNAME_MACHINE-axis-linux-$LIBC - ;; - crisv32:Linux:*:*) - GUESS=$UNAME_MACHINE-axis-linux-$LIBC - ;; - e2k:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - frv:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - hexagon:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - i*86:Linux:*:*) - GUESS=$UNAME_MACHINE-pc-linux-$LIBC - ;; - ia64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - k1om:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - kvx:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - kvx:cos:*:*) - GUESS=$UNAME_MACHINE-unknown-cos - ;; - kvx:mbr:*:*) - GUESS=$UNAME_MACHINE-unknown-mbr - ;; - loongarch32:Linux:*:* | loongarch64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - m32r*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - m68*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - mips:Linux:*:* | mips64:Linux:*:*) - set_cc_for_build - IS_GLIBC=0 - test x"${LIBC}" = xgnu && IS_GLIBC=1 - sed 's/^ //' << EOF > "$dummy.c" - #undef CPU - #undef mips - #undef mipsel - #undef mips64 - #undef mips64el - #if ${IS_GLIBC} && defined(_ABI64) - LIBCABI=gnuabi64 - #else - #if ${IS_GLIBC} && defined(_ABIN32) - LIBCABI=gnuabin32 - #else - LIBCABI=${LIBC} - #endif - #endif - - #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 - CPU=mipsisa64r6 - #else - #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 - CPU=mipsisa32r6 - #else - #if defined(__mips64) - CPU=mips64 - #else - CPU=mips - #endif - #endif - #endif - - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - MIPS_ENDIAN=el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - MIPS_ENDIAN= - #else - MIPS_ENDIAN= - #endif - #endif -EOF - cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` - eval "$cc_set_vars" - test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } - ;; - mips64el:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - openrisc*:Linux:*:*) - GUESS=or1k-unknown-linux-$LIBC - ;; - or32:Linux:*:* | or1k*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - padre:Linux:*:*) - GUESS=sparc-unknown-linux-$LIBC - ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - GUESS=hppa64-unknown-linux-$LIBC - ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; - PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; - *) GUESS=hppa-unknown-linux-$LIBC ;; - esac - ;; - ppc64:Linux:*:*) - GUESS=powerpc64-unknown-linux-$LIBC - ;; - ppc:Linux:*:*) - GUESS=powerpc-unknown-linux-$LIBC - ;; - ppc64le:Linux:*:*) - GUESS=powerpc64le-unknown-linux-$LIBC - ;; - ppcle:Linux:*:*) - GUESS=powerpcle-unknown-linux-$LIBC - ;; - riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - s390:Linux:*:* | s390x:Linux:*:*) - GUESS=$UNAME_MACHINE-ibm-linux-$LIBC - ;; - sh64*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - sh*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - sparc:Linux:*:* | sparc64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - tile*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - vax:Linux:*:*) - GUESS=$UNAME_MACHINE-dec-linux-$LIBC - ;; - x86_64:Linux:*:*) - set_cc_for_build - CPU=$UNAME_MACHINE - LIBCABI=$LIBC - if test "$CC_FOR_BUILD" != no_compiler_found; then - ABI=64 - sed 's/^ //' << EOF > "$dummy.c" - #ifdef __i386__ - ABI=x86 - #else - #ifdef __ILP32__ - ABI=x32 - #endif - #endif -EOF - cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` - eval "$cc_set_abi" - case $ABI in - x86) CPU=i686 ;; - x32) LIBCABI=${LIBC}x32 ;; - esac - fi - GUESS=$CPU-pc-linux-$LIBCABI - ;; - xtensa*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. - # earlier versions are messed up and put the nodename in both - # sysname and nodename. - GUESS=i386-sequent-sysv4 - ;; - i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION - ;; - i*86:OS/2:*:*) - # If we were able to find 'uname', then EMX Unix compatibility - # is probably installed. - GUESS=$UNAME_MACHINE-pc-os2-emx - ;; - i*86:XTS-300:*:STOP) - GUESS=$UNAME_MACHINE-unknown-stop - ;; - i*86:atheos:*:*) - GUESS=$UNAME_MACHINE-unknown-atheos - ;; - i*86:syllable:*:*) - GUESS=$UNAME_MACHINE-pc-syllable - ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - GUESS=i386-unknown-lynxos$UNAME_RELEASE - ;; - i*86:*DOS:*:*) - GUESS=$UNAME_MACHINE-pc-msdosdjgpp - ;; - i*86:*:4.*:*) - UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL - else - GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL - fi - ;; - i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; - *Pent*|*Celeron) UNAME_MACHINE=i686 ;; - esac - GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - ;; - i*86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` - (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL - else - GUESS=$UNAME_MACHINE-pc-sysv32 - fi - ;; - pc:*:*:*) - # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i586. - # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configure will decide that - # this is a cross-build. - GUESS=i586-pc-msdosdjgpp - ;; - Intel:Mach:3*:*) - GUESS=i386-pc-mach3 - ;; - paragon:*:*:*) - GUESS=i860-intel-osf1 - ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 - fi - ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - GUESS=m68010-convergent-sysv - ;; - mc68k:UNIX:SYSTEM5:3.51m) - GUESS=m68k-convergent-sysv - ;; - M680?0:D-NIX:5.3:*) - GUESS=m68k-diab-dnix - ;; - M68*:*:R3V[5678]*:*) - test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; - NCR*:*:4.2:* | MPRAS*:*:4.2:*) - OS_REL='.3' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; - m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - GUESS=m68k-unknown-lynxos$UNAME_RELEASE - ;; - mc68030:UNIX_System_V:4.*:*) - GUESS=m68k-atari-sysv4 - ;; - TSUNAMI:LynxOS:2.*:*) - GUESS=sparc-unknown-lynxos$UNAME_RELEASE - ;; - rs6000:LynxOS:2.*:*) - GUESS=rs6000-unknown-lynxos$UNAME_RELEASE - ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - GUESS=powerpc-unknown-lynxos$UNAME_RELEASE - ;; - SM[BE]S:UNIX_SV:*:*) - GUESS=mips-dde-sysv$UNAME_RELEASE - ;; - RM*:ReliantUNIX-*:*:*) - GUESS=mips-sni-sysv4 - ;; - RM*:SINIX-*:*:*) - GUESS=mips-sni-sysv4 - ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - GUESS=$UNAME_MACHINE-sni-sysv4 - else - GUESS=ns32k-sni-sysv - fi - ;; - PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort - # says - GUESS=i586-unisys-sysv4 - ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes . - # How about differentiating between stratus architectures? -djm - GUESS=hppa1.1-stratus-sysv4 - ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - GUESS=i860-stratus-sysv4 - ;; - i*86:VOS:*:*) - # From Paul.Green@stratus.com. - GUESS=$UNAME_MACHINE-stratus-vos - ;; - *:VOS:*:*) - # From Paul.Green@stratus.com. - GUESS=hppa1.1-stratus-vos - ;; - mc68*:A/UX:*:*) - GUESS=m68k-apple-aux$UNAME_RELEASE - ;; - news*:NEWS-OS:6*:*) - GUESS=mips-sony-newsos6 - ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if test -d /usr/nec; then - GUESS=mips-nec-sysv$UNAME_RELEASE - else - GUESS=mips-unknown-sysv$UNAME_RELEASE - fi - ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - GUESS=powerpc-be-beos - ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - GUESS=powerpc-apple-beos - ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - GUESS=i586-pc-beos - ;; - BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - GUESS=i586-pc-haiku - ;; - ppc:Haiku:*:*) # Haiku running on Apple PowerPC - GUESS=powerpc-apple-haiku - ;; - *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) - GUESS=$UNAME_MACHINE-unknown-haiku - ;; - SX-4:SUPER-UX:*:*) - GUESS=sx4-nec-superux$UNAME_RELEASE - ;; - SX-5:SUPER-UX:*:*) - GUESS=sx5-nec-superux$UNAME_RELEASE - ;; - SX-6:SUPER-UX:*:*) - GUESS=sx6-nec-superux$UNAME_RELEASE - ;; - SX-7:SUPER-UX:*:*) - GUESS=sx7-nec-superux$UNAME_RELEASE - ;; - SX-8:SUPER-UX:*:*) - GUESS=sx8-nec-superux$UNAME_RELEASE - ;; - SX-8R:SUPER-UX:*:*) - GUESS=sx8r-nec-superux$UNAME_RELEASE - ;; - SX-ACE:SUPER-UX:*:*) - GUESS=sxace-nec-superux$UNAME_RELEASE - ;; - Power*:Rhapsody:*:*) - GUESS=powerpc-apple-rhapsody$UNAME_RELEASE - ;; - *:Rhapsody:*:*) - GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE - ;; - arm64:Darwin:*:*) - GUESS=aarch64-apple-darwin$UNAME_RELEASE - ;; - *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` - case $UNAME_PROCESSOR in - unknown) UNAME_PROCESSOR=powerpc ;; - esac - if command -v xcode-select > /dev/null 2> /dev/null && \ - ! xcode-select --print-path > /dev/null 2> /dev/null ; then - # Avoid executing cc if there is no toolchain installed as - # cc will be a stub that puts up a graphical alert - # prompting the user to install developer tools. - CC_FOR_BUILD=no_compiler_found - else - set_cc_for_build - fi - if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac - fi - # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc - if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_PPC >/dev/null - then - UNAME_PROCESSOR=powerpc - fi - elif test "$UNAME_PROCESSOR" = i386 ; then - # uname -m returns i386 or x86_64 - UNAME_PROCESSOR=$UNAME_MACHINE - fi - GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE - ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = x86; then - UNAME_PROCESSOR=i386 - UNAME_MACHINE=pc - fi - GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE - ;; - *:QNX:*:4*) - GUESS=i386-pc-qnx - ;; - NEO-*:NONSTOP_KERNEL:*:*) - GUESS=neo-tandem-nsk$UNAME_RELEASE - ;; - NSE-*:NONSTOP_KERNEL:*:*) - GUESS=nse-tandem-nsk$UNAME_RELEASE - ;; - NSR-*:NONSTOP_KERNEL:*:*) - GUESS=nsr-tandem-nsk$UNAME_RELEASE - ;; - NSV-*:NONSTOP_KERNEL:*:*) - GUESS=nsv-tandem-nsk$UNAME_RELEASE - ;; - NSX-*:NONSTOP_KERNEL:*:*) - GUESS=nsx-tandem-nsk$UNAME_RELEASE - ;; - *:NonStop-UX:*:*) - GUESS=mips-compaq-nonstopux - ;; - BS2000:POSIX*:*:*) - GUESS=bs2000-siemens-sysv - ;; - DS/*:UNIX_System_V:*:*) - GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE - ;; - *:Plan9:*:*) - # "uname -m" is not consistent, so use $cputype instead. 386 - # is converted to i386 for consistency with other x86 - # operating systems. - if test "${cputype-}" = 386; then - UNAME_MACHINE=i386 - elif test "x${cputype-}" != x; then - UNAME_MACHINE=$cputype - fi - GUESS=$UNAME_MACHINE-unknown-plan9 - ;; - *:TOPS-10:*:*) - GUESS=pdp10-unknown-tops10 - ;; - *:TENEX:*:*) - GUESS=pdp10-unknown-tenex - ;; - KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - GUESS=pdp10-dec-tops20 - ;; - XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - GUESS=pdp10-xkl-tops20 - ;; - *:TOPS-20:*:*) - GUESS=pdp10-unknown-tops20 - ;; - *:ITS:*:*) - GUESS=pdp10-unknown-its - ;; - SEI:*:*:SEIUX) - GUESS=mips-sei-seiux$UNAME_RELEASE - ;; - *:DragonFly:*:*) - DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL - ;; - *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case $UNAME_MACHINE in - A*) GUESS=alpha-dec-vms ;; - I*) GUESS=ia64-dec-vms ;; - V*) GUESS=vax-dec-vms ;; - esac ;; - *:XENIX:*:SysV) - GUESS=i386-pc-xenix - ;; - i*86:skyos:*:*) - SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` - GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL - ;; - i*86:rdos:*:*) - GUESS=$UNAME_MACHINE-pc-rdos - ;; - i*86:Fiwix:*:*) - GUESS=$UNAME_MACHINE-pc-fiwix - ;; - *:AROS:*:*) - GUESS=$UNAME_MACHINE-unknown-aros - ;; - x86_64:VMkernel:*:*) - GUESS=$UNAME_MACHINE-unknown-esx - ;; - amd64:Isilon\ OneFS:*:*) - GUESS=x86_64-unknown-onefs - ;; - *:Unleashed:*:*) - GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE - ;; - *:Ironclad:*:*) - GUESS=$UNAME_MACHINE-unknown-ironclad - ;; -esac - -# Do we have a guess based on uname results? -if test "x$GUESS" != x; then - echo "$GUESS" - exit -fi - -# No uname command or uname output not recognized. -set_cc_for_build -cat > "$dummy.c" < -#include -#endif -#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) -#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) -#include -#if defined(_SIZE_T_) || defined(SIGLOST) -#include -#endif -#endif -#endif -int -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); -#endif - -#if defined (vax) -#if !defined (ultrix) -#include -#if defined (BSD) -#if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -#else -#if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -#else - printf ("vax-dec-bsd\n"); exit (0); -#endif -#endif -#else - printf ("vax-dec-bsd\n"); exit (0); -#endif -#else -#if defined(_SIZE_T_) || defined(SIGLOST) - struct utsname un; - uname (&un); - printf ("vax-dec-ultrix%s\n", un.release); exit (0); -#else - printf ("vax-dec-ultrix\n"); exit (0); -#endif -#endif -#endif -#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) -#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) -#if defined(_SIZE_T_) || defined(SIGLOST) - struct utsname *un; - uname (&un); - printf ("mips-dec-ultrix%s\n", un.release); exit (0); -#else - printf ("mips-dec-ultrix\n"); exit (0); -#endif -#endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. -test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } - -echo "$0: unable to guess system type" >&2 - -case $UNAME_MACHINE:$UNAME_SYSTEM in - mips:Linux | mips64:Linux) - # If we got here on MIPS GNU/Linux, output extra information. - cat >&2 <&2 <&2 </dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` - -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` - -UNAME_MACHINE = "$UNAME_MACHINE" -UNAME_RELEASE = "$UNAME_RELEASE" -UNAME_SYSTEM = "$UNAME_SYSTEM" -UNAME_VERSION = "$UNAME_VERSION" -EOF -fi - -exit 1 - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/experiments/wasm-gui/third_party/libXext/config.h b/experiments/wasm-gui/third_party/libXext/config.h deleted file mode 100644 index e16504164..000000000 --- a/experiments/wasm-gui/third_party/libXext/config.h +++ /dev/null @@ -1,182 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MINIX_CONFIG_H */ - -/* Define to 1 if you have the 'reallocarray' function. */ -#define HAVE_REALLOCARRAY 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCHAR_H 1 - -/* Define to 1 if the system has the `__builtin_popcountl' built-in function - */ -#define HAVE___BUILTIN_POPCOUNTL 1 - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#define LT_OBJDIR ".libs/" - -/* Name of package */ -#define PACKAGE "libXext" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libXext" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libXext 1.3.7" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libXext" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.3.7" - -/* Major version of this package */ -#define PACKAGE_VERSION_MAJOR 1 - -/* Minor version of this package */ -#define PACKAGE_VERSION_MINOR 3 - -/* Patch version of this package */ -#define PACKAGE_VERSION_PATCHLEVEL 7 - -/* Define to 1 if all of the C89 standard headers exist (not just the ones - required in a freestanding environment). This macro is provided for - backward compatibility; new code need not use it. */ -#define STDC_HEADERS 1 - -/* Enable extensions on AIX, Interix, z/OS. */ -#ifndef _ALL_SOURCE -# define _ALL_SOURCE 1 -#endif -/* Enable extensions on Cosmopolitan Libc. */ -#ifndef _COSMO_SOURCE -# define _COSMO_SOURCE 1 -#endif -/* Enable general extensions on macOS. */ -#ifndef _DARWIN_C_SOURCE -# define _DARWIN_C_SOURCE 1 -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# define __EXTENSIONS__ 1 -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif -/* Enable X/Open compliant socket functions that do not require linking - with -lxnet on HP-UX 11.11. */ -#ifndef _HPUX_ALT_XOPEN_SOCKET_API -# define _HPUX_ALT_XOPEN_SOCKET_API 1 -#endif -/* Identify the host operating system as Minix. - This macro does not affect the system headers' behavior. - A future release of Autoconf may stop defining this macro. */ -#ifndef _MINIX -/* # undef _MINIX */ -#endif -/* Enable general extensions on NetBSD. - Enable NetBSD compatibility extensions on Minix. */ -#ifndef _NETBSD_SOURCE -# define _NETBSD_SOURCE 1 -#endif -/* Enable OpenBSD compatibility extensions on NetBSD. - Oddly enough, this does nothing on OpenBSD. */ -#ifndef _OPENBSD_SOURCE -# define _OPENBSD_SOURCE 1 -#endif -/* Define to 1 if needed for POSIX-compatible behavior. */ -#ifndef _POSIX_SOURCE -/* # undef _POSIX_SOURCE */ -#endif -/* Define to 2 if needed for POSIX-compatible behavior. */ -#ifndef _POSIX_1_SOURCE -/* # undef _POSIX_1_SOURCE */ -#endif -/* Enable POSIX-compatible threading on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# define _POSIX_PTHREAD_SEMANTICS 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ -#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ -# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ -#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ -# define __STDC_WANT_IEC_60559_BFP_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ -#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ -# define __STDC_WANT_IEC_60559_DFP_EXT__ 1 -#endif -/* Enable extensions specified by C23 Annex F. */ -#ifndef __STDC_WANT_IEC_60559_EXT__ -# define __STDC_WANT_IEC_60559_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ -#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ -# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 -#endif -/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ -#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ -# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ -#ifndef __STDC_WANT_LIB_EXT2__ -# define __STDC_WANT_LIB_EXT2__ 1 -#endif -/* Enable extensions specified by ISO/IEC 24747:2009. */ -#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ -# define __STDC_WANT_MATH_SPEC_FUNCS__ 1 -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# define _TANDEM_SOURCE 1 -#endif -/* Enable X/Open extensions. Define to 500 only if necessary - to make mbstate_t available. */ -#ifndef _XOPEN_SOURCE -/* # undef _XOPEN_SOURCE */ -#endif - - -/* Version number of package */ -#define VERSION "1.3.7" diff --git a/experiments/wasm-gui/third_party/libXext/config.h.in b/experiments/wasm-gui/third_party/libXext/config.h.in deleted file mode 100644 index dd6e15d2b..000000000 --- a/experiments/wasm-gui/third_party/libXext/config.h.in +++ /dev/null @@ -1,181 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MINIX_CONFIG_H - -/* Define to 1 if you have the 'reallocarray' function. */ -#undef HAVE_REALLOCARRAY - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_WCHAR_H - -/* Define to 1 if the system has the `__builtin_popcountl' built-in function - */ -#undef HAVE___BUILTIN_POPCOUNTL - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#undef LT_OBJDIR - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Major version of this package */ -#undef PACKAGE_VERSION_MAJOR - -/* Minor version of this package */ -#undef PACKAGE_VERSION_MINOR - -/* Patch version of this package */ -#undef PACKAGE_VERSION_PATCHLEVEL - -/* Define to 1 if all of the C89 standard headers exist (not just the ones - required in a freestanding environment). This macro is provided for - backward compatibility; new code need not use it. */ -#undef STDC_HEADERS - -/* Enable extensions on AIX, Interix, z/OS. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif -/* Enable extensions on Cosmopolitan Libc. */ -#ifndef _COSMO_SOURCE -# undef _COSMO_SOURCE -#endif -/* Enable general extensions on macOS. */ -#ifndef _DARWIN_C_SOURCE -# undef _DARWIN_C_SOURCE -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# undef _GNU_SOURCE -#endif -/* Enable X/Open compliant socket functions that do not require linking - with -lxnet on HP-UX 11.11. */ -#ifndef _HPUX_ALT_XOPEN_SOCKET_API -# undef _HPUX_ALT_XOPEN_SOCKET_API -#endif -/* Identify the host operating system as Minix. - This macro does not affect the system headers' behavior. - A future release of Autoconf may stop defining this macro. */ -#ifndef _MINIX -# undef _MINIX -#endif -/* Enable general extensions on NetBSD. - Enable NetBSD compatibility extensions on Minix. */ -#ifndef _NETBSD_SOURCE -# undef _NETBSD_SOURCE -#endif -/* Enable OpenBSD compatibility extensions on NetBSD. - Oddly enough, this does nothing on OpenBSD. */ -#ifndef _OPENBSD_SOURCE -# undef _OPENBSD_SOURCE -#endif -/* Define to 1 if needed for POSIX-compatible behavior. */ -#ifndef _POSIX_SOURCE -# undef _POSIX_SOURCE -#endif -/* Define to 2 if needed for POSIX-compatible behavior. */ -#ifndef _POSIX_1_SOURCE -# undef _POSIX_1_SOURCE -#endif -/* Enable POSIX-compatible threading on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# undef _POSIX_PTHREAD_SEMANTICS -#endif -/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ -#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ -# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ -#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ -# undef __STDC_WANT_IEC_60559_BFP_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ -#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ -# undef __STDC_WANT_IEC_60559_DFP_EXT__ -#endif -/* Enable extensions specified by C23 Annex F. */ -#ifndef __STDC_WANT_IEC_60559_EXT__ -# undef __STDC_WANT_IEC_60559_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ -#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ -# undef __STDC_WANT_IEC_60559_FUNCS_EXT__ -#endif -/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ -#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ -# undef __STDC_WANT_IEC_60559_TYPES_EXT__ -#endif -/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ -#ifndef __STDC_WANT_LIB_EXT2__ -# undef __STDC_WANT_LIB_EXT2__ -#endif -/* Enable extensions specified by ISO/IEC 24747:2009. */ -#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ -# undef __STDC_WANT_MATH_SPEC_FUNCS__ -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# undef _TANDEM_SOURCE -#endif -/* Enable X/Open extensions. Define to 500 only if necessary - to make mbstate_t available. */ -#ifndef _XOPEN_SOURCE -# undef _XOPEN_SOURCE -#endif - - -/* Version number of package */ -#undef VERSION diff --git a/experiments/wasm-gui/third_party/libXext/config.log b/experiments/wasm-gui/third_party/libXext/config.log deleted file mode 100644 index 450b37c1c..000000000 --- a/experiments/wasm-gui/third_party/libXext/config.log +++ /dev/null @@ -1,1592 +0,0 @@ -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by libXext configure 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - $ ./configure --host=wasm32-wasi --prefix=/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix --enable-static --disable-shared --disable-specs --without-xmlto --without-fop - -## --------- ## -## Platform. ## -## --------- ## - -hostname = nathan-dev -uname -m = x86_64 -uname -r = 6.1.0-41-amd64 -uname -s = Linux -uname -v = #1 SMP PREEMPT_DYNAMIC Debian 6.1.158-1 (2025-11-09) - -/usr/bin/uname -p = unknown -/bin/uname -X = unknown - -/bin/arch = x86_64 -/usr/bin/arch -k = unknown -/usr/convex/getsysinfo = unknown -/usr/bin/hostinfo = unknown -/bin/machine = unknown -/usr/bin/oslevel = unknown -/bin/universe = unknown - -PATH: /home/linuxbrew/.linuxbrew/bin/ -PATH: /home/nathan/misc/bun/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.wasmer/bin/ -PATH: /home/nathan/.opencode/bin/ -PATH: /home/nathan/.local/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.cargo/bin/ -PATH: /home/nathan/.nix-profile/bin/ -PATH: /nix/var/nix/profiles/default/bin/ -PATH: /home/linuxbrew/.linuxbrew/bin/ -PATH: /home/linuxbrew/.linuxbrew/sbin/ -PATH: /home/nathan/.local/bin/ -PATH: /home/linuxbrew/.linuxbrew/opt/rustup/bin/ -PATH: /home/nathan/.local/bin/ -PATH: /home/nathan/.atuin/bin/ -PATH: /home/nathan/misc/bun/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.wasmer/bin/ -PATH: /home/nathan/.deno/bin/ -PATH: /home/nathan/.opencode/bin/ -PATH: /home/nathan/.local/bin/ -PATH: /home/nathan/.bun/bin/ -PATH: /home/nathan/.cargo/bin/ -PATH: /home/nathan/.nix-profile/bin/ -PATH: /nix/var/nix/profiles/default/bin/ -PATH: /tmp/pnpm/ -PATH: /home/linuxbrew/.linuxbrew/bin/ -PATH: /home/linuxbrew/.linuxbrew/sbin/ -PATH: /home/nathan/.nvm/versions/node/v24.13.0/bin/ -PATH: /home/nathan/.nix-profile/bin/ -PATH: /nix/var/nix/profiles/default/bin/ -PATH: /usr/local/bin/ -PATH: /usr/bin/ -PATH: /bin/ -PATH: /usr/local/games/ -PATH: /usr/games/ - - -## ----------- ## -## Core tests. ## -## ----------- ## - -configure:2691: looking for aux files: config.guess config.sub ltmain.sh missing install-sh compile -configure:2704: trying ./ -configure:2733: ./config.guess found -configure:2733: ./config.sub found -configure:2733: ./ltmain.sh found -configure:2733: ./missing found -configure:2715: ./install-sh found -configure:2733: ./compile found -configure:2901: checking for wasm32-wasi-gcc -configure:2934: result: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -configure:3339: checking for C compiler version -configure:3348: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang --version >&5 -clang version 19.1.5-wasi-sdk (https://github.com/llvm/llvm-project ab4b5a2db582958af1ee308a790cfdb42bd24720) -Target: wasm32-unknown-wasi -Thread model: posix -InstalledDir: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin -configure:3359: $? = 0 -configure:3348: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -v >&5 -clang version 19.1.5-wasi-sdk (https://github.com/llvm/llvm-project ab4b5a2db582958af1ee308a790cfdb42bd24720) -Target: wasm32-unknown-wasi -Thread model: posix -InstalledDir: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin -configure:3359: $? = 0 -configure:3348: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -V >&5 -clang: error: argument to '-V' is missing (expected 1 value) -clang: error: no input files -configure:3359: $? = 1 -configure:3348: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -qversion >&5 -clang: error: unknown argument '-qversion'; did you mean '--version'? -clang: error: no input files -configure:3359: $? = 1 -configure:3348: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -version >&5 -clang: error: unknown argument '-version'; did you mean '--version'? -clang: error: no input files -configure:3359: $? = 1 -configure:3379: checking whether the C compiler works -configure:3401: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:3405: $? = 0 -configure:3456: result: yes -configure:3460: checking for C compiler default output file name -configure:3462: result: a.out -configure:3468: checking for suffix of executables -configure:3475: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:3479: $? = 0 -configure:3503: result: -configure:3527: checking whether we are cross compiling -configure:3535: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:3539: $? = 0 -configure:3546: ./conftest -./configure: line 3548: ./conftest: cannot execute binary file: Exec format error -configure:3550: $? = 126 -configure:3565: result: yes -configure:3571: checking for suffix of object files -configure:3594: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:3598: $? = 0 -configure:3622: result: o -configure:3626: checking whether the compiler supports GNU C -configure:3646: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:3646: $? = 0 -configure:3658: result: yes -configure:3669: checking whether /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang accepts -g -configure:3690: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -c -g --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:3690: $? = 0 -configure:3737: result: yes -configure:3757: checking for /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang option to enable C23 features -configure:3772: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -conftest.c:14:3: error: "Compiler advertises conformance to C17 or earlier" - 14 | # error "Compiler advertises conformance to C17 or earlier" - | ^ -conftest.c:18:23: error: expected function body after function declarator - 18 | char alignas (double) c23_aligned_as_double; - | ^ -conftest.c:19:15: error: expected parameter declarator - 19 | char alignas (0) c23_no_special_alignment; - | ^ -conftest.c:19:15: error: expected ')' -conftest.c:19:14: note: to match this '(' - 19 | char alignas (0) c23_no_special_alignment; - | ^ -conftest.c:19:18: error: expected function body after function declarator - 19 | char alignas (0) c23_no_special_alignment; - | ^ -conftest.c:21:15: error: expected parameter declarator - 21 | char alignas (0) alignas (int) c23_aligned_as_int; - | ^ -conftest.c:21:15: error: expected ')' -conftest.c:21:14: note: to match this '(' - 21 | char alignas (0) alignas (int) c23_aligned_as_int; - | ^ -conftest.c:21:18: error: expected function body after function declarator - 21 | char alignas (0) alignas (int) c23_aligned_as_int; - | ^ -conftest.c:26:23: error: call to undeclared function 'alignof'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] - 26 | c23_int_alignment = alignof (int), - | ^ -conftest.c:26:32: error: expected expression - 26 | c23_int_alignment = alignof (int), - | ^ -conftest.c:27:38: error: expected expression - 27 | c23_int_array_alignment = alignof (int[100]), - | ^ -conftest.c:28:33: error: expected expression - 28 | c23_char_alignment = alignof (char) - | ^ -conftest.c:30:16: error: expected parameter declarator - 30 | static_assert (0 < -alignof (int), "alignof is signed"); - | ^ -conftest.c:30:16: error: expected ')' -conftest.c:30:15: note: to match this '(' - 30 | static_assert (0 < -alignof (int), "alignof is signed"); - | ^ -conftest.c:30:1: error: type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int] - 30 | static_assert (0 < -alignof (int), "alignof is signed"); - | ^ - | int -conftest.c:32:41: warning: omitting the parameter name in a function definition is a C23 extension [-Wc23-extensions] - 32 | int function_with_unnamed_parameter (int) { return 0; } - | ^ -conftest.c:38:1: error: unknown type name 'bool' - 38 | bool use_u8 = (!sizeof u8"\xFF") == (!u8'x'); - | ^ -conftest.c:38:39: error: use of undeclared identifier 'u8' - 38 | bool use_u8 = (!sizeof u8"\xFF") == (!u8'x'); - | ^ -conftest.c:40:1: error: unknown type name 'bool' - 40 | bool check_that_bool_works = true | false | !nullptr; - | ^ -conftest.c:40:30: error: use of undeclared identifier 'true' - 40 | bool check_that_bool_works = true | false | !nullptr; - | ^ -fatal error: too many errors emitted, stopping now [-ferror-limit=] -1 warning and 20 errors generated. -configure:3772: $? = 1 -configure: failed program was: -| /* confdefs.h */ -| #define PACKAGE_NAME "libXext" -| #define PACKAGE_TARNAME "libXext" -| #define PACKAGE_VERSION "1.3.7" -| #define PACKAGE_STRING "libXext 1.3.7" -| #define PACKAGE_BUGREPORT "https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" -| #define PACKAGE_URL "" -| /* end confdefs.h. */ -| -| /* Does the compiler advertise conformance to C17 or earlier? -| Although GCC 14 does not do that, even with -std=gnu23, -| it is close enough, and defines __STDC_VERSION == 202000L. */ -| #if !defined __STDC_VERSION__ || __STDC_VERSION__ <= 201710L -| # error "Compiler advertises conformance to C17 or earlier" -| #endif -| -| // Check alignas. -| char alignas (double) c23_aligned_as_double; -| char alignas (0) c23_no_special_alignment; -| extern char c23_aligned_as_int; -| char alignas (0) alignas (int) c23_aligned_as_int; -| -| // Check alignof. -| enum -| { -| c23_int_alignment = alignof (int), -| c23_int_array_alignment = alignof (int[100]), -| c23_char_alignment = alignof (char) -| }; -| static_assert (0 < -alignof (int), "alignof is signed"); -| -| int function_with_unnamed_parameter (int) { return 0; } -| -| void c23_noreturn (); -| -| /* Test parsing of string and char UTF-8 literals (including hex escapes). -| The parens pacify GCC 15. */ -| bool use_u8 = (!sizeof u8"\xFF") == (!u8'x'); -| -| bool check_that_bool_works = true | false | !nullptr; -| #if !true -| # error "true does not work in #if" -| #endif -| #if false -| #elifdef __STDC_VERSION__ -| #else -| # error "#elifdef does not work" -| #endif -| -| #ifndef __has_c_attribute -| # error "__has_c_attribute not defined" -| #endif -| -| #ifndef __has_include -| # error "__has_include not defined" -| #endif -| -| #define LPAREN() ( -| #define FORTY_TWO(x) 42 -| #define VA_OPT_TEST(r, x, ...) __VA_OPT__ (FORTY_TWO r x)) -| static_assert (VA_OPT_TEST (LPAREN (), 0, <:-) == 42); -| -| static_assert (0b101010 == 42); -| static_assert (0B101010 == 42); -| static_assert (0xDEAD'BEEF == 3'735'928'559); -| static_assert (0.500'000'000 == 0.5); -| -| enum unsignedish : unsigned int { uione = 1 }; -| static_assert (0 < -uione); -| -| #include -| constexpr nullptr_t null_pointer = nullptr; -| -| static typeof (1 + 1L) two () { return 2; } -| static long int three () { return 3; } -| -| -| int -| main (int, char **) -| { -| int ok = 0; -| -| { -| label_before_declaration: -| int arr[10] = {}; -| if (arr[0]) -| goto label_before_declaration; -| if (!arr[0]) -| goto label_at_end_of_block; -| label_at_end_of_block: -| } -| ok |= !null_pointer; -| ok |= two != three; -| -| return ok; -| } -| -configure:3772: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -conftest.c:40:46: warning: implicit conversion of nullptr constant to 'bool' [-Wnull-conversion] - 40 | bool check_that_bool_works = true | false | !nullptr; - | ~^~~~~~~ - | 0 -conftest.c:92:10: warning: implicit conversion of nullptr constant to 'bool' [-Wnull-conversion] - 92 | ok |= !null_pointer; - | ~^~~~~~~~~~~~ - | 0 -2 warnings generated. -configure:3772: $? = 0 -configure:3794: result: -std=gnu23 -configure:3964: checking whether /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 understands -c and -o together -configure:3987: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c conftest.c -o conftest2.o -configure:3990: $? = 0 -configure:3987: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c conftest.c -o conftest2.o -configure:3990: $? = 0 -configure:4006: result: yes -configure:4028: checking for stdio.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for stdlib.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for string.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for inttypes.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for stdint.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for strings.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for sys/stat.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for sys/types.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for unistd.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for wchar.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4028: $? = 0 -configure:4028: result: yes -configure:4028: checking for minix/config.h -configure:4028: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -conftest.c:47:10: fatal error: 'minix/config.h' file not found - 47 | #include - | ^~~~~~~~~~~~~~~~ -1 error generated. -configure:4028: $? = 1 -configure: failed program was: -| /* confdefs.h */ -| #define PACKAGE_NAME "libXext" -| #define PACKAGE_TARNAME "libXext" -| #define PACKAGE_VERSION "1.3.7" -| #define PACKAGE_STRING "libXext 1.3.7" -| #define PACKAGE_BUGREPORT "https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" -| #define PACKAGE_URL "" -| #define HAVE_STDIO_H 1 -| #define HAVE_STDLIB_H 1 -| #define HAVE_STRING_H 1 -| #define HAVE_INTTYPES_H 1 -| #define HAVE_STDINT_H 1 -| #define HAVE_STRINGS_H 1 -| #define HAVE_SYS_STAT_H 1 -| #define HAVE_SYS_TYPES_H 1 -| #define HAVE_UNISTD_H 1 -| #define HAVE_WCHAR_H 1 -| /* end confdefs.h. */ -| #include -| #ifdef HAVE_STDIO_H -| # include -| #endif -| #ifdef HAVE_STDLIB_H -| # include -| #endif -| #ifdef HAVE_STRING_H -| # include -| #endif -| #ifdef HAVE_INTTYPES_H -| # include -| #endif -| #ifdef HAVE_STDINT_H -| # include -| #endif -| #ifdef HAVE_STRINGS_H -| # include -| #endif -| #ifdef HAVE_SYS_TYPES_H -| # include -| #endif -| #ifdef HAVE_SYS_STAT_H -| # include -| #endif -| #ifdef HAVE_UNISTD_H -| # include -| #endif -| #include -configure:4028: result: no -configure:4059: checking whether it is safe to define __EXTENSIONS__ -configure:4078: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4078: $? = 0 -configure:4088: result: yes -configure:4091: checking whether _XOPEN_SOURCE should be defined -configure:4113: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:4113: $? = 0 -configure:4142: result: no -configure:4222: checking for a BSD-compatible install -configure:4296: result: /usr/bin/install -c -configure:4307: checking whether sleep supports fractional seconds -configure:4323: result: yes -configure:4326: checking filesystem timestamp resolution -configure:4461: result: 0.01 -configure:4466: checking whether build environment is sane -configure:4511: result: yes -configure:4573: checking for wasm32-wasi-strip -configure:4609: result: no -configure:4619: checking for strip -configure:4640: found /home/linuxbrew/.linuxbrew/bin/strip -configure:4652: result: strip -configure:4664: WARNING: using cross tools not prefixed with host triplet -configure:4678: checking for a race-free mkdir -p -configure:4721: result: /usr/bin/mkdir -p -configure:4728: checking for gawk -configure:4764: result: no -configure:4728: checking for mawk -configure:4749: found /usr/bin/mawk -configure:4761: result: mawk -configure:4772: checking whether make sets $(MAKE) -configure:4796: result: yes -configure:4818: checking whether make supports the include directive -configure:4833: make -f confmf.GNU && cat confinc.out -this is the am__doit target -configure:4836: $? = 0 -configure:4855: result: yes (GNU style) -configure:4886: checking whether make supports nested variables -configure:4905: result: yes -configure:4919: checking xargs -n works -configure:4935: result: yes -configure:5020: checking whether UID '1000' is supported by ustar format -configure:5026: result: yes -configure:5033: checking whether GID '1000' is supported by ustar format -configure:5039: result: yes -configure:5047: checking how to create a ustar tar archive -configure:5058: tar --version -tar (GNU tar) 1.34 -Copyright (C) 2021 Free Software Foundation, Inc. -License GPLv3+: GNU GPL version 3 or later . -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. - -Written by John Gilmore and Jay Fenlason. -configure:5061: $? = 0 -configure:5101: tardir=conftest.dir && eval tar --format=ustar -chf - "$tardir" >conftest.tar -configure:5104: $? = 0 -configure:5108: tar -xf - &5 -configure:6120: nm "conftest.o" -nm: conftest.o: file format not recognized -configure:6123: output -configure:6131: result: BSD nm -configure:6134: checking whether ln -s works -configure:6138: result: yes -configure:6146: checking the maximum length of command line arguments -configure:6279: result: 1572864 -configure:6327: checking how to convert x86_64-pc-linux-gnu file names to wasm32-unknown-wasi format -configure:6369: result: func_convert_file_noop -configure:6376: checking how to convert x86_64-pc-linux-gnu file names to toolchain format -configure:6398: result: func_convert_file_noop -configure:6405: checking for /home/linuxbrew/.linuxbrew/bin/ld option to reload object files -configure:6414: result: -r -configure:6447: checking for file -configure:6468: found /usr/bin/file -configure:6481: result: file -configure:6498: checking for wasm32-wasi-objdump -configure:6534: result: no -configure:6544: checking for objdump -configure:6565: found /home/linuxbrew/.linuxbrew/bin/objdump -configure:6577: result: objdump -configure:6609: checking how to recognize dependent libraries -configure:6818: result: unknown -configure:6863: checking for wasm32-wasi-dlltool -configure:6899: result: no -configure:6909: checking for dlltool -configure:6930: found /home/linuxbrew/.linuxbrew/bin/dlltool -configure:6942: result: dlltool -configure:6975: checking how to associate runtime and link libraries -configure:7004: result: printf %s\n -configure:7018: checking for wasm32-wasi-ranlib -configure:7051: result: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ranlib -configure:7124: checking for wasm32-wasi-ar -configure:7157: result: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar -configure:7260: checking for archiver @FILE support -configure:7278: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:7278: $? = 0 -configure:7282: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar cr libconftest.a @conftest.lst >&5 -configure:7285: $? = 0 -configure:7290: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar cr libconftest.a @conftest.lst >&5 -/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar: error: conftest.o: No such file or directory -configure:7293: $? = 1 -configure:7306: result: @ -configure:7324: checking for wasm32-wasi-strip -configure:7357: result: strip -configure:7506: checking command to parse nm output from /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 object -configure:7660: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:7663: $? = 0 -configure:7667: nm conftest.o | /usr/bin/sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /usr/bin/sed '/ __gnu_lto/d' > conftest.nm -nm: conftest.o: file format not recognized -cannot run /usr/bin/sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /usr/bin/sed '/ __gnu_lto/d' -configure:7660: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:7663: $? = 0 -configure:7667: nm conftest.o | /usr/bin/sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*_\([_A-Za-z][_A-Za-z0-9]*\)$/\1 _\2 \2/p' | /usr/bin/sed '/ __gnu_lto/d' > conftest.nm -nm: conftest.o: file format not recognized -cannot run /usr/bin/sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*_\([_A-Za-z][_A-Za-z0-9]*\)$/\1 _\2 \2/p' | /usr/bin/sed '/ __gnu_lto/d' -configure:7772: result: failed -configure:7822: checking for sysroot -configure:7856: result: no -configure:7863: checking for a working dd -configure:7908: result: /usr/bin/dd -configure:7912: checking how to truncate binary pipes -configure:7929: result: /usr/bin/dd bs=4096 count=1 -configure:8223: checking for wasm32-wasi-mt -configure:8259: result: no -configure:8269: checking for mt -configure:8290: found /usr/bin/mt -configure:8302: result: mt -configure:8325: checking if mt is a manifest tool -configure:8332: mt '-?' -configure:8341: result: no -configure:9134: checking for dlfcn.h -configure:9134: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:9134: $? = 0 -configure:9134: result: yes -configure:9437: checking for objdir -configure:9454: result: .libs -configure:9720: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -fno-rtti -fno-exceptions -configure:9739: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -fno-rtti -fno-exceptions conftest.c >&5 -configure:9743: $? = 0 -configure:9757: result: yes -configure:10130: checking for /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 option to produce PIC -configure:10139: result: -fPIC -DPIC -configure:10147: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 PIC flag -fPIC -DPIC works -configure:10166: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -fPIC -DPIC -DPIC conftest.c >&5 -configure:10170: $? = 0 -configure:10184: result: yes -configure:10213: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 static flag -static works -configure:10243: result: yes -configure:10258: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -c -o file.o -configure:10280: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -o out/conftest2.o conftest.c >&5 -configure:10284: $? = 0 -configure:10307: result: yes -configure:10315: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -c -o file.o -configure:10364: result: yes -configure:10397: checking whether the /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 linker (/home/linuxbrew/.linuxbrew/bin/ld) supports shared libraries -configure:11681: result: yes -configure:11923: checking dynamic linker characteristics -configure:13307: result: no -configure:13429: checking how to hardcode library paths into programs -configure:13454: result: immediate -configure:14054: checking whether stripping libraries is possible -configure:14063: result: yes -configure:14105: checking if libtool supports shared libraries -configure:14107: result: no -configure:14110: checking whether to build shared libraries -configure:14135: result: no -configure:14138: checking whether to build static libraries -configure:14142: result: yes -configure:14192: checking for /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 options to detect undeclared functions -configure:14214: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -conftest.c:46:8: error: call to undeclared library function 'strchr' with type 'char *(const char *, int)'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] - 46 | (void) strchr; - | ^ -conftest.c:46:8: note: include the header or explicitly provide a declaration for 'strchr' -1 error generated. -configure:14214: $? = 1 -configure: failed program was: -| /* confdefs.h */ -| #define PACKAGE_NAME "libXext" -| #define PACKAGE_TARNAME "libXext" -| #define PACKAGE_VERSION "1.3.7" -| #define PACKAGE_STRING "libXext 1.3.7" -| #define PACKAGE_BUGREPORT "https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" -| #define PACKAGE_URL "" -| #define HAVE_STDIO_H 1 -| #define HAVE_STDLIB_H 1 -| #define HAVE_STRING_H 1 -| #define HAVE_INTTYPES_H 1 -| #define HAVE_STDINT_H 1 -| #define HAVE_STRINGS_H 1 -| #define HAVE_SYS_STAT_H 1 -| #define HAVE_SYS_TYPES_H 1 -| #define HAVE_UNISTD_H 1 -| #define HAVE_WCHAR_H 1 -| #define STDC_HEADERS 1 -| #define _ALL_SOURCE 1 -| #define _COSMO_SOURCE 1 -| #define _DARWIN_C_SOURCE 1 -| #define _GNU_SOURCE 1 -| #define _HPUX_ALT_XOPEN_SOCKET_API 1 -| #define _NETBSD_SOURCE 1 -| #define _OPENBSD_SOURCE 1 -| #define _POSIX_PTHREAD_SEMANTICS 1 -| #define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_BFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_DFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_EXT__ 1 -| #define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 -| #define __STDC_WANT_LIB_EXT2__ 1 -| #define __STDC_WANT_MATH_SPEC_FUNCS__ 1 -| #define _TANDEM_SOURCE 1 -| #define __EXTENSIONS__ 1 -| #define PACKAGE "libXext" -| #define VERSION "1.3.7" -| #define HAVE_DLFCN_H 1 -| #define LT_OBJDIR ".libs/" -| /* end confdefs.h. */ -| -| int -| main (void) -| { -| (void) strchr; -| ; -| return 0; -| } -configure:14241: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:14241: $? = 0 -configure:14261: result: none needed -configure:14275: checking for /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 options to ignore future-version functions -configure:14297: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -Werror=unguarded-availability-new -conftest.c:43:6: error: "-Werror=unguarded-availability-new not needed here" - 43 | #error "-Werror=unguarded-availability-new not needed here" - | ^ -1 error generated. -configure:14297: $? = 1 -configure: failed program was: -| /* confdefs.h */ -| #define PACKAGE_NAME "libXext" -| #define PACKAGE_TARNAME "libXext" -| #define PACKAGE_VERSION "1.3.7" -| #define PACKAGE_STRING "libXext 1.3.7" -| #define PACKAGE_BUGREPORT "https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" -| #define PACKAGE_URL "" -| #define HAVE_STDIO_H 1 -| #define HAVE_STDLIB_H 1 -| #define HAVE_STRING_H 1 -| #define HAVE_INTTYPES_H 1 -| #define HAVE_STDINT_H 1 -| #define HAVE_STRINGS_H 1 -| #define HAVE_SYS_STAT_H 1 -| #define HAVE_SYS_TYPES_H 1 -| #define HAVE_UNISTD_H 1 -| #define HAVE_WCHAR_H 1 -| #define STDC_HEADERS 1 -| #define _ALL_SOURCE 1 -| #define _COSMO_SOURCE 1 -| #define _DARWIN_C_SOURCE 1 -| #define _GNU_SOURCE 1 -| #define _HPUX_ALT_XOPEN_SOCKET_API 1 -| #define _NETBSD_SOURCE 1 -| #define _OPENBSD_SOURCE 1 -| #define _POSIX_PTHREAD_SEMANTICS 1 -| #define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_BFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_DFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_EXT__ 1 -| #define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 -| #define __STDC_WANT_LIB_EXT2__ 1 -| #define __STDC_WANT_MATH_SPEC_FUNCS__ 1 -| #define _TANDEM_SOURCE 1 -| #define __EXTENSIONS__ 1 -| #define PACKAGE "libXext" -| #define VERSION "1.3.7" -| #define HAVE_DLFCN_H 1 -| #define LT_OBJDIR ".libs/" -| /* end confdefs.h. */ -| #if ! (defined __APPLE__ && defined __MACH__) -| #error "-Werror=unguarded-availability-new not needed here" -| #endif -| -| int -| main (void) -| { -| -| ; -| return 0; -| } -configure:14309: result: none needed -configure:14322: checking whether __clang__ is declared -configure:14322: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:14322: $? = 0 -configure:14322: result: yes -configure:14330: checking whether __INTEL_COMPILER is declared -configure:14330: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -conftest.c:77:10: error: use of undeclared identifier '__INTEL_COMPILER' - 77 | (void) __INTEL_COMPILER; - | ^ -1 error generated. -configure:14330: $? = 1 -configure: failed program was: -| /* confdefs.h */ -| #define PACKAGE_NAME "libXext" -| #define PACKAGE_TARNAME "libXext" -| #define PACKAGE_VERSION "1.3.7" -| #define PACKAGE_STRING "libXext 1.3.7" -| #define PACKAGE_BUGREPORT "https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" -| #define PACKAGE_URL "" -| #define HAVE_STDIO_H 1 -| #define HAVE_STDLIB_H 1 -| #define HAVE_STRING_H 1 -| #define HAVE_INTTYPES_H 1 -| #define HAVE_STDINT_H 1 -| #define HAVE_STRINGS_H 1 -| #define HAVE_SYS_STAT_H 1 -| #define HAVE_SYS_TYPES_H 1 -| #define HAVE_UNISTD_H 1 -| #define HAVE_WCHAR_H 1 -| #define STDC_HEADERS 1 -| #define _ALL_SOURCE 1 -| #define _COSMO_SOURCE 1 -| #define _DARWIN_C_SOURCE 1 -| #define _GNU_SOURCE 1 -| #define _HPUX_ALT_XOPEN_SOCKET_API 1 -| #define _NETBSD_SOURCE 1 -| #define _OPENBSD_SOURCE 1 -| #define _POSIX_PTHREAD_SEMANTICS 1 -| #define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_BFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_DFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_EXT__ 1 -| #define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 -| #define __STDC_WANT_LIB_EXT2__ 1 -| #define __STDC_WANT_MATH_SPEC_FUNCS__ 1 -| #define _TANDEM_SOURCE 1 -| #define __EXTENSIONS__ 1 -| #define PACKAGE "libXext" -| #define VERSION "1.3.7" -| #define HAVE_DLFCN_H 1 -| #define LT_OBJDIR ".libs/" -| /* end confdefs.h. */ -| #include -| #ifdef HAVE_STDIO_H -| # include -| #endif -| #ifdef HAVE_STDLIB_H -| # include -| #endif -| #ifdef HAVE_STRING_H -| # include -| #endif -| #ifdef HAVE_INTTYPES_H -| # include -| #endif -| #ifdef HAVE_STDINT_H -| # include -| #endif -| #ifdef HAVE_STRINGS_H -| # include -| #endif -| #ifdef HAVE_SYS_TYPES_H -| # include -| #endif -| #ifdef HAVE_SYS_STAT_H -| # include -| #endif -| #ifdef HAVE_UNISTD_H -| # include -| #endif -| int -| main (void) -| { -| #ifndef __INTEL_COMPILER -| #ifdef __cplusplus -| (void) __INTEL_COMPILER; -| #else -| (void) __INTEL_COMPILER; -| #endif -| #endif -| -| ; -| return 0; -| } -configure:14330: result: no -configure:14338: checking whether __SUNPRO_C is declared -configure:14338: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -conftest.c:77:10: error: use of undeclared identifier '__SUNPRO_C' - 77 | (void) __SUNPRO_C; - | ^ -1 error generated. -configure:14338: $? = 1 -configure: failed program was: -| /* confdefs.h */ -| #define PACKAGE_NAME "libXext" -| #define PACKAGE_TARNAME "libXext" -| #define PACKAGE_VERSION "1.3.7" -| #define PACKAGE_STRING "libXext 1.3.7" -| #define PACKAGE_BUGREPORT "https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" -| #define PACKAGE_URL "" -| #define HAVE_STDIO_H 1 -| #define HAVE_STDLIB_H 1 -| #define HAVE_STRING_H 1 -| #define HAVE_INTTYPES_H 1 -| #define HAVE_STDINT_H 1 -| #define HAVE_STRINGS_H 1 -| #define HAVE_SYS_STAT_H 1 -| #define HAVE_SYS_TYPES_H 1 -| #define HAVE_UNISTD_H 1 -| #define HAVE_WCHAR_H 1 -| #define STDC_HEADERS 1 -| #define _ALL_SOURCE 1 -| #define _COSMO_SOURCE 1 -| #define _DARWIN_C_SOURCE 1 -| #define _GNU_SOURCE 1 -| #define _HPUX_ALT_XOPEN_SOCKET_API 1 -| #define _NETBSD_SOURCE 1 -| #define _OPENBSD_SOURCE 1 -| #define _POSIX_PTHREAD_SEMANTICS 1 -| #define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_BFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_DFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_EXT__ 1 -| #define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 -| #define __STDC_WANT_LIB_EXT2__ 1 -| #define __STDC_WANT_MATH_SPEC_FUNCS__ 1 -| #define _TANDEM_SOURCE 1 -| #define __EXTENSIONS__ 1 -| #define PACKAGE "libXext" -| #define VERSION "1.3.7" -| #define HAVE_DLFCN_H 1 -| #define LT_OBJDIR ".libs/" -| /* end confdefs.h. */ -| #include -| #ifdef HAVE_STDIO_H -| # include -| #endif -| #ifdef HAVE_STDLIB_H -| # include -| #endif -| #ifdef HAVE_STRING_H -| # include -| #endif -| #ifdef HAVE_INTTYPES_H -| # include -| #endif -| #ifdef HAVE_STDINT_H -| # include -| #endif -| #ifdef HAVE_STRINGS_H -| # include -| #endif -| #ifdef HAVE_SYS_TYPES_H -| # include -| #endif -| #ifdef HAVE_SYS_STAT_H -| # include -| #endif -| #ifdef HAVE_UNISTD_H -| # include -| #endif -| int -| main (void) -| { -| #ifndef __SUNPRO_C -| #ifdef __cplusplus -| (void) __SUNPRO_C; -| #else -| (void) __SUNPRO_C; -| #endif -| #endif -| -| ; -| return 0; -| } -configure:14338: result: no -configure:14358: checking for wasm32-wasi-pkg-config -configure:14397: result: no -configure:14407: checking for pkg-config -configure:14430: found /usr/bin/pkg-config -configure:14443: result: /usr/bin/pkg-config -configure:14468: checking pkg-config is at least version 0.9.0 -configure:14471: result: yes -configure:14522: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=unknown-warning-option -configure:14532: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:14532: $? = 0 -configure:14542: result: yes -configure:14553: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=unused-command-line-argument -configure:14563: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -c --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include conftest.c >&5 -configure:14563: $? = 0 -configure:14573: result: yes -configure:14592: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wall -configure:14610: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wall --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:14610: $? = 0 -configure:14626: result: yes -configure:14722: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wpointer-arith -configure:14740: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wpointer-arith --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:14740: $? = 0 -configure:14756: result: yes -configure:14852: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wmissing-declarations -configure:14870: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wmissing-declarations --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:14870: $? = 0 -configure:14886: result: yes -configure:14982: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wformat=2 -configure:15000: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wformat=2 --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:15000: $? = 0 -configure:15016: result: yes -configure:15167: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wstrict-prototypes -configure:15185: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wstrict-prototypes --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:15185: $? = 0 -configure:15201: result: yes -configure:15297: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wmissing-prototypes -configure:15315: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wmissing-prototypes --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:15315: $? = 0 -configure:15331: result: yes -configure:15427: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wnested-externs -configure:15445: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wnested-externs --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:15445: $? = 0 -configure:15461: result: yes -configure:15557: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wbad-function-cast -configure:15575: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wbad-function-cast --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:15575: $? = 0 -configure:15591: result: yes -configure:15687: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wold-style-definition -configure:15705: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wold-style-definition --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:15705: $? = 0 -configure:15721: result: yes -configure:15874: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wunused -configure:15892: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wunused --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:15892: $? = 0 -configure:15908: result: yes -configure:16004: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wuninitialized -configure:16022: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wuninitialized --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:16022: $? = 0 -configure:16038: result: yes -configure:16134: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wshadow -configure:16152: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wshadow --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:16152: $? = 0 -configure:16168: result: yes -configure:16264: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wmissing-noreturn -configure:16282: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wmissing-noreturn --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:16282: $? = 0 -configure:16298: result: yes -configure:16394: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wmissing-format-attribute -configure:16412: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wmissing-format-attribute --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:16412: $? = 0 -configure:16428: result: yes -configure:16524: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wredundant-decls -configure:16542: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wredundant-decls --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:16542: $? = 0 -configure:16558: result: yes -configure:16654: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Wlogical-op -configure:16672: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Wlogical-op --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -error: unknown warning option '-Wlogical-op'; did you mean '-Wlong-long'? [-Werror,-Wunknown-warning-option] -configure:16672: $? = 1 -configure: failed program was: -| /* confdefs.h */ -| #define PACKAGE_NAME "libXext" -| #define PACKAGE_TARNAME "libXext" -| #define PACKAGE_VERSION "1.3.7" -| #define PACKAGE_STRING "libXext 1.3.7" -| #define PACKAGE_BUGREPORT "https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" -| #define PACKAGE_URL "" -| #define HAVE_STDIO_H 1 -| #define HAVE_STDLIB_H 1 -| #define HAVE_STRING_H 1 -| #define HAVE_INTTYPES_H 1 -| #define HAVE_STDINT_H 1 -| #define HAVE_STRINGS_H 1 -| #define HAVE_SYS_STAT_H 1 -| #define HAVE_SYS_TYPES_H 1 -| #define HAVE_UNISTD_H 1 -| #define HAVE_WCHAR_H 1 -| #define STDC_HEADERS 1 -| #define _ALL_SOURCE 1 -| #define _COSMO_SOURCE 1 -| #define _DARWIN_C_SOURCE 1 -| #define _GNU_SOURCE 1 -| #define _HPUX_ALT_XOPEN_SOCKET_API 1 -| #define _NETBSD_SOURCE 1 -| #define _OPENBSD_SOURCE 1 -| #define _POSIX_PTHREAD_SEMANTICS 1 -| #define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_BFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_DFP_EXT__ 1 -| #define __STDC_WANT_IEC_60559_EXT__ 1 -| #define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 -| #define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 -| #define __STDC_WANT_LIB_EXT2__ 1 -| #define __STDC_WANT_MATH_SPEC_FUNCS__ 1 -| #define _TANDEM_SOURCE 1 -| #define __EXTENSIONS__ 1 -| #define PACKAGE "libXext" -| #define VERSION "1.3.7" -| #define HAVE_DLFCN_H 1 -| #define LT_OBJDIR ".libs/" -| /* end confdefs.h. */ -| int i; -| int -| main (void) -| { -| -| ; -| return 0; -| } -configure:16688: result: no -configure:16796: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=implicit -configure:16814: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=implicit --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:16814: $? = 0 -configure:16830: result: yes -configure:16979: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=nonnull -configure:16997: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=nonnull --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:16997: $? = 0 -configure:17013: result: yes -configure:17109: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=init-self -configure:17127: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=init-self --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:17127: $? = 0 -configure:17143: result: yes -configure:17239: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=main -configure:17257: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=main --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:17257: $? = 0 -configure:17273: result: yes -configure:17369: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=missing-braces -configure:17387: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=missing-braces --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:17387: $? = 0 -configure:17403: result: yes -configure:17499: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=sequence-point -configure:17517: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=sequence-point --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:17517: $? = 0 -configure:17533: result: yes -configure:17629: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=return-type -configure:17647: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=return-type --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:17647: $? = 0 -configure:17663: result: yes -configure:17812: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=trigraphs -configure:17830: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=trigraphs --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:17830: $? = 0 -configure:17846: result: yes -configure:17942: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=array-bounds -configure:17960: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=array-bounds --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:17960: $? = 0 -configure:17976: result: yes -configure:18072: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=write-strings -configure:18090: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=write-strings --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:18090: $? = 0 -configure:18106: result: yes -configure:18202: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=address -configure:18220: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=address --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:18220: $? = 0 -configure:18236: result: yes -configure:18332: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=int-to-pointer-cast -configure:18350: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=int-to-pointer-cast --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:18350: $? = 0 -configure:18366: result: yes -configure:18515: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=pointer-to-int-cast -configure:18533: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=pointer-to-int-cast --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:18533: $? = 0 -configure:18549: result: yes -configure:20373: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -pedantic -configure:20391: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -pedantic --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:20391: $? = 0 -configure:20407: result: yes -configure:20503: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror -configure:20521: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:20521: $? = 0 -configure:20537: result: yes -configure:20689: checking if /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 supports -Werror=attributes -configure:20707: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h -Werror=unknown-warning-option -Werror=unused-command-line-argument -Werror=attributes --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -configure:20707: $? = 0 -configure:20723: result: yes -configure:20932: checking whether to build functional specifications -configure:20934: result: no -configure:21305: checking for xsltproc -configure:21328: found /home/linuxbrew/.linuxbrew/bin/xsltproc -configure:21341: result: /home/linuxbrew/.linuxbrew/bin/xsltproc -configure:21427: checking for X.Org SGML entities >= 1.8 -configure:21431: $PKG_CONFIG --exists --print-errors "xorg-sgml-doctools >= 1.8" -Package xorg-sgml-doctools was not found in the pkg-config search path. -Perhaps you should add the directory containing `xorg-sgml-doctools.pc' -to the PKG_CONFIG_PATH environment variable -Package 'xorg-sgml-doctools', required by 'virtual:world', not found -configure:21434: $? = 1 -configure:21450: result: no -configure:21477: checking whether to act as if malloc(0) can return NULL -configure:21479: result: yes -configure:21511: checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99 -configure:21518: $PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" -configure:21521: $? = 0 -configure:21535: $PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" -configure:21538: $? = 0 -configure:21596: result: yes -configure:21604: checking for __builtin_popcountl -configure:21624: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -conftest.c:50:13: warning: ignoring return value of function declared with const attribute [-Wunused-value] - 50 | __builtin_popcountl(0) - | ^~~~~~~~~~~~~~~~~~~ ~ -1 warning generated. -configure:21624: $? = 0 -configure:21636: result: yes -configure:21648: checking for reallocarray -configure:21648: /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23 -o conftest --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include --target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman conftest.c >&5 -wasm-ld: warning: function signature mismatch: reallocarray ->>> defined as () -> i32 in /tmp/conftest-31e02f.o ->>> defined as (i32, i32, i32) -> i32 in /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1/libc.a(reallocarray.o) -configure:21648: $? = 0 -configure:21648: result: yes -configure:21881: checking that generated files are newer than configure -configure:21887: result: done -configure:21962: creating ./config.status - -## ---------------------- ## -## Running config.status. ## -## ---------------------- ## - -This file was extended by libXext config.status 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - CONFIG_FILES = - CONFIG_HEADERS = - CONFIG_LINKS = - CONFIG_COMMANDS = - $ ./config.status - -on nathan-dev - -config.status:1167: creating Makefile -config.status:1167: creating man/Makefile -config.status:1167: creating src/Makefile -config.status:1167: creating specs/Makefile -config.status:1167: creating xext.pc -config.status:1167: creating config.h -config.status:1396: executing depfiles commands -config.status:1473: cd src && sed -e '/# am--include-marker/d' Makefile | make -f - am--depfiles -config.status:1478: $? = 0 -config.status:1396: executing libtool commands - -## ---------------- ## -## Cache variables. ## -## ---------------- ## - -ac_cv_build=x86_64-pc-linux-gnu -ac_cv_c_compiler_gnu=yes -ac_cv_c_future_darwin_options='none needed' -ac_cv_c_undeclared_builtin_options='none needed' -ac_cv_env_CC_set=set -ac_cv_env_CC_value=/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -ac_cv_env_CFLAGS_set=set -ac_cv_env_CFLAGS_value='--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h' -ac_cv_env_CPPFLAGS_set=set -ac_cv_env_CPPFLAGS_value='--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include' -ac_cv_env_FOP_set= -ac_cv_env_FOP_value= -ac_cv_env_LDFLAGS_set=set -ac_cv_env_LDFLAGS_value='--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman' -ac_cv_env_LIBS_set= -ac_cv_env_LIBS_value= -ac_cv_env_LINT_FLAGS_set= -ac_cv_env_LINT_FLAGS_value= -ac_cv_env_LINT_set= -ac_cv_env_LINT_value= -ac_cv_env_LT_SYS_LIBRARY_PATH_set= -ac_cv_env_LT_SYS_LIBRARY_PATH_value= -ac_cv_env_PKG_CONFIG_LIBDIR_set=set -ac_cv_env_PKG_CONFIG_LIBDIR_value=/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib/pkgconfig:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/pkgconfig -ac_cv_env_PKG_CONFIG_PATH_set= -ac_cv_env_PKG_CONFIG_PATH_value= -ac_cv_env_PKG_CONFIG_set= -ac_cv_env_PKG_CONFIG_value= -ac_cv_env_XEXT_CFLAGS_set= -ac_cv_env_XEXT_CFLAGS_value= -ac_cv_env_XEXT_LIBS_set= -ac_cv_env_XEXT_LIBS_value= -ac_cv_env_XMLTO_set= -ac_cv_env_XMLTO_value= -ac_cv_env_XSLTPROC_set= -ac_cv_env_XSLTPROC_value= -ac_cv_env_build_alias_set= -ac_cv_env_build_alias_value= -ac_cv_env_host_alias_set=set -ac_cv_env_host_alias_value=wasm32-wasi -ac_cv_env_target_alias_set= -ac_cv_env_target_alias_value= -ac_cv_func_reallocarray=yes -ac_cv_have_decl___INTEL_COMPILER=no -ac_cv_have_decl___SUNPRO_C=no -ac_cv_have_decl___clang__=yes -ac_cv_header_dlfcn_h=yes -ac_cv_header_inttypes_h=yes -ac_cv_header_minix_config_h=no -ac_cv_header_stdint_h=yes -ac_cv_header_stdio_h=yes -ac_cv_header_stdlib_h=yes -ac_cv_header_string_h=yes -ac_cv_header_strings_h=yes -ac_cv_header_sys_stat_h=yes -ac_cv_header_sys_types_h=yes -ac_cv_header_unistd_h=yes -ac_cv_header_wchar_h=yes -ac_cv_host=wasm32-unknown-wasi -ac_cv_objext=o -ac_cv_path_EGREP='/usr/bin/grep -E' -ac_cv_path_EGREP_TRADITIONAL='/usr/bin/grep -E' -ac_cv_path_FGREP='/usr/bin/grep -F' -ac_cv_path_GREP=/usr/bin/grep -ac_cv_path_SED=/usr/bin/sed -ac_cv_path_XSLTPROC=/home/linuxbrew/.linuxbrew/bin/xsltproc -ac_cv_path_ac_pt_PKG_CONFIG=/usr/bin/pkg-config -ac_cv_path_install='/usr/bin/install -c' -ac_cv_path_lt_DD=/usr/bin/dd -ac_cv_path_mkdir=/usr/bin/mkdir -ac_cv_prog_AR=/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar -ac_cv_prog_AWK=mawk -ac_cv_prog_CC=/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -ac_cv_prog_FILECMD=file -ac_cv_prog_RANLIB=/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ranlib -ac_cv_prog_STRIP=strip -ac_cv_prog_ac_ct_DLLTOOL=dlltool -ac_cv_prog_ac_ct_DUMPBIN='link -dump' -ac_cv_prog_ac_ct_MANIFEST_TOOL=mt -ac_cv_prog_ac_ct_OBJDUMP=objdump -ac_cv_prog_ac_ct_STRIP=strip -ac_cv_prog_cc_c23=-std=gnu23 -ac_cv_prog_cc_g=yes -ac_cv_prog_cc_stdc=-std=gnu23 -ac_cv_prog_make_make_set=yes -ac_cv_safe_to_define___extensions__=yes -ac_cv_should_define__xopen_source=no -am_cv_CC_dependencies_compiler_type=gcc3 -am_cv_filesystem_timestamp_resolution=0.01 -am_cv_make_support_nested_variables=yes -am_cv_prog_cc_c_o=yes -am_cv_prog_tar_ustar=gnutar -am_cv_sleep_fractional_seconds=yes -am_cv_xargs_n_works=yes -ax_cv_have___builtin_popcountl=yes -lt_cv_ar_at_file=@ -lt_cv_deplibs_check_method=unknown -lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_ld_reload_flag=-r -lt_cv_nm_interface='BSD nm' -lt_cv_objdir=.libs -lt_cv_path_LD=/home/linuxbrew/.linuxbrew/bin/ld -lt_cv_path_NM=no -lt_cv_path_manifest_tool=no -lt_cv_prog_compiler_c_o=yes -lt_cv_prog_compiler_pic='-fPIC -DPIC' -lt_cv_prog_compiler_pic_works=yes -lt_cv_prog_compiler_rtti_exceptions=yes -lt_cv_prog_compiler_static_works=yes -lt_cv_prog_gnu_ld=yes -lt_cv_sharedlib_from_linklib_cmd='printf %s\n' -lt_cv_sys_global_symbol_pipe= -lt_cv_sys_global_symbol_to_c_name_address='/usr/bin/sed -n -e '\''s/^: \(.*\) .*$/ {"\1", (void *) 0},/p'\'' -e '\''s/^[ABCDGIRSTW][ABCDGIRSTW]* .* \(.*\)$/ {"\1", (void *) \&\1},/p'\''' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='/usr/bin/sed -n -e '\''s/^: \(.*\) .*$/ {"\1", (void *) 0},/p'\'' -e '\''s/^[ABCDGIRSTW][ABCDGIRSTW]* .* \(lib.*\)$/ {"\1", (void *) \&\1},/p'\'' -e '\''s/^[ABCDGIRSTW][ABCDGIRSTW]* .* \(.*\)$/ {"lib\1", (void *) \&\1},/p'\''' -lt_cv_sys_global_symbol_to_cdecl= -lt_cv_sys_global_symbol_to_import= -lt_cv_sys_max_cmd_len=1572864 -lt_cv_to_host_file_cmd=func_convert_file_noop -lt_cv_to_tool_file_cmd=func_convert_file_noop -lt_cv_truncate_bin='/usr/bin/dd bs=4096 count=1' -pkg_cv_XEXT_CFLAGS='-I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include ' -pkg_cv_XEXT_LIBS='-L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -lX11 ' -xorg_cv_cc_flag__Wall=yes -xorg_cv_cc_flag__Wbad_function_cast=yes -xorg_cv_cc_flag__Werror=yes -xorg_cv_cc_flag__Werror_address=yes -xorg_cv_cc_flag__Werror_array_bounds=yes -xorg_cv_cc_flag__Werror_attributes=yes -xorg_cv_cc_flag__Werror_implicit=yes -xorg_cv_cc_flag__Werror_init_self=yes -xorg_cv_cc_flag__Werror_int_to_pointer_cast=yes -xorg_cv_cc_flag__Werror_main=yes -xorg_cv_cc_flag__Werror_missing_braces=yes -xorg_cv_cc_flag__Werror_nonnull=yes -xorg_cv_cc_flag__Werror_pointer_to_int_cast=yes -xorg_cv_cc_flag__Werror_return_type=yes -xorg_cv_cc_flag__Werror_sequence_point=yes -xorg_cv_cc_flag__Werror_trigraphs=yes -xorg_cv_cc_flag__Werror_write_strings=yes -xorg_cv_cc_flag__Wformat_2=yes -xorg_cv_cc_flag__Wlogical_op=no -xorg_cv_cc_flag__Wmissing_declarations=yes -xorg_cv_cc_flag__Wmissing_format_attribute=yes -xorg_cv_cc_flag__Wmissing_noreturn=yes -xorg_cv_cc_flag__Wmissing_prototypes=yes -xorg_cv_cc_flag__Wnested_externs=yes -xorg_cv_cc_flag__Wold_style_definition=yes -xorg_cv_cc_flag__Wpointer_arith=yes -xorg_cv_cc_flag__Wredundant_decls=yes -xorg_cv_cc_flag__Wshadow=yes -xorg_cv_cc_flag__Wstrict_prototypes=yes -xorg_cv_cc_flag__Wuninitialized=yes -xorg_cv_cc_flag__Wunused=yes -xorg_cv_cc_flag__pedantic=yes -xorg_cv_cc_flag_unknown_warning_option=yes -xorg_cv_cc_flag_unused_command_line_argument=yes - -## ----------------- ## -## Output variables. ## -## ----------------- ## - -ACLOCAL='${SHELL} '\''/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing'\'' aclocal-1.18' -ADMIN_MAN_DIR='$(mandir)/man$(ADMIN_MAN_SUFFIX)' -ADMIN_MAN_SUFFIX='8' -AMDEPBACKSLASH='\' -AMDEP_FALSE='#' -AMDEP_TRUE='' -AMTAR='$${TAR-tar}' -AM_BACKSLASH='\' -AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -AM_DEFAULT_VERBOSITY='0' -AM_V='$(V)' -APP_MAN_DIR='$(mandir)/man$(APP_MAN_SUFFIX)' -APP_MAN_SUFFIX='1' -AR='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar' -AUTOCONF='${SHELL} '\''/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing'\'' autoconf' -AUTOHEADER='${SHELL} '\''/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing'\'' autoheader' -AUTOMAKE='${SHELL} '\''/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing'\'' automake-1.18' -AWK='mawk' -BASE_CFLAGS=' -Wall -Wpointer-arith -Wmissing-declarations -Wformat=2 -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wbad-function-cast -Wold-style-definition -Wunused -Wuninitialized -Wshadow -Wmissing-noreturn -Wmissing-format-attribute -Wredundant-decls -Werror=implicit -Werror=nonnull -Werror=init-self -Werror=main -Werror=missing-braces -Werror=sequence-point -Werror=return-type -Werror=trigraphs -Werror=array-bounds -Werror=write-strings -Werror=address -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast' -CC='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23' -CCDEPMODE='depmode=gcc3' -CFLAGS='--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h' -CHANGELOG_CMD='((GIT_DIR=$(top_srcdir)/.git git log > $(top_srcdir)/.changelog.tmp) 2>/dev/null && mv $(top_srcdir)/.changelog.tmp $(top_srcdir)/ChangeLog) || (rm -f $(top_srcdir)/.changelog.tmp; test -e $(top_srcdir)/ChangeLog || ( touch $(top_srcdir)/ChangeLog; echo '\''git failed to create ChangeLog: installing empty ChangeLog.'\'' >&2))' -CPPFLAGS='--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include' -CSCOPE='cscope' -CTAGS='ctags' -CWARNFLAGS=' -Wall -Wpointer-arith -Wmissing-declarations -Wformat=2 -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wbad-function-cast -Wold-style-definition -Wunused -Wuninitialized -Wshadow -Wmissing-noreturn -Wmissing-format-attribute -Wredundant-decls -Werror=implicit -Werror=nonnull -Werror=init-self -Werror=main -Werror=missing-braces -Werror=sequence-point -Werror=return-type -Werror=trigraphs -Werror=array-bounds -Werror=write-strings -Werror=address -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast -fno-strict-aliasing' -CYGPATH_W='echo' -DEFS='-DHAVE_CONFIG_H' -DEPDIR='.deps' -DLLTOOL='dlltool' -DRIVER_MAN_DIR='$(mandir)/man$(DRIVER_MAN_SUFFIX)' -DRIVER_MAN_SUFFIX='4' -DSYMUTIL='' -DUMPBIN=':' -ECHO_C='' -ECHO_N='-n' -ECHO_T='' -EGREP='/usr/bin/grep -E' -ENABLE_SPECS_FALSE='' -ENABLE_SPECS_TRUE='#' -ETAGS='etags' -EXEEXT='' -FGREP='/usr/bin/grep -F' -FILECMD='file' -FILE_MAN_DIR='$(mandir)/man$(FILE_MAN_SUFFIX)' -FILE_MAN_SUFFIX='5' -FOP='' -GREP='/usr/bin/grep' -HAVE_FOP_FALSE='' -HAVE_FOP_TRUE='#' -HAVE_STYLESHEETS_FALSE='' -HAVE_STYLESHEETS_TRUE='#' -HAVE_XMLTO_FALSE='' -HAVE_XMLTO_TEXT_FALSE='' -HAVE_XMLTO_TEXT_TRUE='#' -HAVE_XMLTO_TRUE='#' -HAVE_XSLTPROC_FALSE='#' -HAVE_XSLTPROC_TRUE='' -INSTALL_CMD='(cp -f /home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/util-macros/INSTALL $(top_srcdir)/.INSTALL.tmp && mv $(top_srcdir)/.INSTALL.tmp $(top_srcdir)/INSTALL) || (rm -f $(top_srcdir)/.INSTALL.tmp; test -e $(top_srcdir)/INSTALL || ( touch $(top_srcdir)/INSTALL; echo '\''failed to copy INSTALL from util-macros: installing empty INSTALL.'\'' >&2))' -INSTALL_DATA='${INSTALL} -m 644' -INSTALL_PROGRAM='${INSTALL}' -INSTALL_SCRIPT='${INSTALL}' -INSTALL_STRIP_PROGRAM='$(install_sh) -c -s' -LD='/home/linuxbrew/.linuxbrew/bin/ld' -LDFLAGS='--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman' -LIBOBJS='' -LIBS='' -LIBTOOL='$(SHELL) $(top_builddir)/libtool' -LIB_MAN_DIR='$(mandir)/man$(LIB_MAN_SUFFIX)' -LIB_MAN_SUFFIX='3' -LINT='' -LINTLIB='' -LINT_FALSE='' -LINT_FLAGS='' -LINT_TRUE='#' -LIPO='' -LN_S='ln -s' -LTLIBOBJS='' -LT_SYS_LIBRARY_PATH='' -MAKEINFO='${SHELL} '\''/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing'\'' makeinfo' -MAKE_LINT_LIB_FALSE='' -MAKE_LINT_LIB_TRUE='#' -MALLOC_ZERO_CFLAGS='-DMALLOC_0_RETURNS_NULL' -MANIFEST_TOOL=':' -MAN_SUBSTS=' -e '\''s|__vendorversion__|"$(PACKAGE_STRING)" "$(XORG_MAN_PAGE)"|'\'' -e '\''s|__xorgversion__|"$(PACKAGE_STRING)" "$(XORG_MAN_PAGE)"|'\'' -e '\''s|__xservername__|Xorg|g'\'' -e '\''s|__xconfigfile__|xorg.conf|g'\'' -e '\''s|__projectroot__|$(prefix)|g'\'' -e '\''s|__apploaddir__|$(appdefaultdir)|g'\'' -e '\''s|__appmansuffix__|$(APP_MAN_SUFFIX)|g'\'' -e '\''s|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g'\'' -e '\''s|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g'\'' -e '\''s|__libmansuffix__|$(LIB_MAN_SUFFIX)|g'\'' -e '\''s|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g'\'' -e '\''s|__filemansuffix__|$(FILE_MAN_SUFFIX)|g'\''' -MISC_MAN_DIR='$(mandir)/man$(MISC_MAN_SUFFIX)' -MISC_MAN_SUFFIX='7' -MKDIR_P='/usr/bin/mkdir -p' -NM='nm' -NMEDIT='' -OBJDUMP='objdump' -OBJEXT='o' -OTOOL64='' -OTOOL='' -PACKAGE='libXext' -PACKAGE_BUGREPORT='https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues' -PACKAGE_NAME='libXext' -PACKAGE_STRING='libXext 1.3.7' -PACKAGE_TARNAME='libXext' -PACKAGE_URL='' -PACKAGE_VERSION='1.3.7' -PATH_SEPARATOR=':' -PKG_CONFIG='/usr/bin/pkg-config' -PKG_CONFIG_LIBDIR='/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib/pkgconfig:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/pkgconfig' -PKG_CONFIG_PATH='' -RANLIB='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ranlib' -SED='/usr/bin/sed' -SET_MAKE='' -SHELL='/bin/bash' -STRICT_CFLAGS=' -pedantic -Werror -Werror=attributes' -STRIP='strip' -STYLESHEET_SRCDIR='' -VERSION='1.3.7' -XEXT_CFLAGS='-I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include ' -XEXT_LIBS='-L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -lX11 ' -XEXT_SOREV='6:4:0' -XMALLOC_ZERO_CFLAGS='-DMALLOC_0_RETURNS_NULL' -XMLTO='' -XORG_MAN_PAGE='X Version 11' -XORG_SGML_PATH='' -XSLTPROC='/home/linuxbrew/.linuxbrew/bin/xsltproc' -XSL_STYLESHEET='' -XTMALLOC_ZERO_CFLAGS='-DMALLOC_0_RETURNS_NULL -DXTMALLOC_BC' -ac_ct_AR='' -ac_ct_CC='' -ac_ct_DUMPBIN='link -dump' -am__EXEEXT_FALSE='' -am__EXEEXT_TRUE='#' -am__fastdepCC_FALSE='#' -am__fastdepCC_TRUE='' -am__include='include' -am__isrc='' -am__leading_dot='.' -am__nodep='_no' -am__quote='' -am__rm_f_notfound='' -am__tar='tar --format=ustar -chf - "$$tardir"' -am__untar='tar -xf -' -am__xargs_n='xargs -n' -bindir='${exec_prefix}/bin' -build='x86_64-pc-linux-gnu' -build_alias='' -build_cpu='x86_64' -build_os='linux-gnu' -build_vendor='pc' -datadir='${datarootdir}' -datarootdir='${prefix}/share' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -dvidir='${docdir}' -exec_prefix='${prefix}' -host='wasm32-unknown-wasi' -host_alias='wasm32-wasi' -host_cpu='wasm32' -host_os='wasi' -host_vendor='unknown' -htmldir='${docdir}' -includedir='${prefix}/include' -infodir='${datarootdir}/info' -install_sh='${SHELL} /home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/install-sh' -libdir='${exec_prefix}/lib' -libexecdir='${exec_prefix}/libexec' -localedir='${datarootdir}/locale' -localstatedir='${prefix}/var' -mandir='${datarootdir}/man' -mkdir_p='$(MKDIR_P)' -oldincludedir='/usr/include' -pdfdir='${docdir}' -prefix='/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix' -program_transform_name='s,x,x,' -psdir='${docdir}' -runstatedir='${localstatedir}/run' -sbindir='${exec_prefix}/sbin' -sharedstatedir='${prefix}/com' -sysconfdir='${prefix}/etc' -target_alias='' - -## ----------- ## -## confdefs.h. ## -## ----------- ## - -/* confdefs.h */ -#define PACKAGE_NAME "libXext" -#define PACKAGE_TARNAME "libXext" -#define PACKAGE_VERSION "1.3.7" -#define PACKAGE_STRING "libXext 1.3.7" -#define PACKAGE_BUGREPORT "https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" -#define PACKAGE_URL "" -#define HAVE_STDIO_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_STRING_H 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_STDINT_H 1 -#define HAVE_STRINGS_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_SYS_TYPES_H 1 -#define HAVE_UNISTD_H 1 -#define HAVE_WCHAR_H 1 -#define STDC_HEADERS 1 -#define _ALL_SOURCE 1 -#define _COSMO_SOURCE 1 -#define _DARWIN_C_SOURCE 1 -#define _GNU_SOURCE 1 -#define _HPUX_ALT_XOPEN_SOCKET_API 1 -#define _NETBSD_SOURCE 1 -#define _OPENBSD_SOURCE 1 -#define _POSIX_PTHREAD_SEMANTICS 1 -#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 -#define __STDC_WANT_IEC_60559_BFP_EXT__ 1 -#define __STDC_WANT_IEC_60559_DFP_EXT__ 1 -#define __STDC_WANT_IEC_60559_EXT__ 1 -#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 -#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 -#define __STDC_WANT_LIB_EXT2__ 1 -#define __STDC_WANT_MATH_SPEC_FUNCS__ 1 -#define _TANDEM_SOURCE 1 -#define __EXTENSIONS__ 1 -#define PACKAGE "libXext" -#define VERSION "1.3.7" -#define HAVE_DLFCN_H 1 -#define LT_OBJDIR ".libs/" -#define PACKAGE_VERSION_MAJOR 1 -#define PACKAGE_VERSION_MINOR 3 -#define PACKAGE_VERSION_PATCHLEVEL 7 -#define HAVE___BUILTIN_POPCOUNTL 1 -#define HAVE_REALLOCARRAY 1 - -configure: exit diff --git a/experiments/wasm-gui/third_party/libXext/config.status b/experiments/wasm-gui/third_party/libXext/config.status deleted file mode 100755 index 0a758c30a..000000000 --- a/experiments/wasm-gui/third_party/libXext/config.status +++ /dev/null @@ -1,2053 +0,0 @@ -#! /bin/bash -# Generated by configure. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=${CONFIG_SHELL-/bin/bash} -export SHELL -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in #( - e) case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in #( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in #( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - -exec 6>&1 -## ------------------------------------- ## -## Main body of "$CONFIG_STATUS" script. ## -## ------------------------------------- ## -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -# Files that config.status was made for. -config_files=" Makefile man/Makefile src/Makefile specs/Makefile xext.pc" -config_headers=" config.h" -config_commands=" depfiles libtool" - -ac_cs_usage="\ -'$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -ac_cs_config='--host=wasm32-wasi --prefix=/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix --enable-static --disable-shared --disable-specs --without-xmlto --without-fop host_alias=wasm32-wasi CC=/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang '\''CFLAGS=--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h'\'' '\''LDFLAGS=--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman'\'' '\''CPPFLAGS=--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include'\'' PKG_CONFIG_LIBDIR=/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib/pkgconfig:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/pkgconfig' -ac_cs_version="\ -libXext config.status 1.3.7 -configured by ./configure, generated by GNU Autoconf 2.73, - with options \"$ac_cs_config\" - -Copyright (C) 2026 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext' -srcdir='.' -INSTALL='/usr/bin/install -c' -MKDIR_P='/usr/bin/mkdir -p' -AWK='mawk' -test -n "$AWK" || { - awk '' /dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -if $ac_cs_recheck; then - set X /bin/bash './configure' '--host=wasm32-wasi' '--prefix=/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix' '--enable-static' '--disable-shared' '--disable-specs' '--without-xmlto' '--without-fop' 'host_alias=wasm32-wasi' 'CC=/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang' 'CFLAGS=--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h' 'LDFLAGS=--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman' 'CPPFLAGS=--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include' 'PKG_CONFIG_LIBDIR=/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib/pkgconfig:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/pkgconfig' $ac_configure_extra_args --no-create --no-recursion - shift - \printf '%s\n' "running CONFIG_SHELL=/bin/bash $*" >&6 - CONFIG_SHELL='/bin/bash' - export CONFIG_SHELL - exec "$@" -fi - -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - printf '%s\n' "$ac_log" -} >&5 - -# -# INIT-COMMANDS -# -AMDEP_TRUE="" MAKE="make" - - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' -double_quote_subst='s/\(["`\\]\)/\\\1/g' -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' -macro_version='2.5.4' -macro_revision='2.5.4' -enable_shared='no' -enable_static='yes' -pic_mode='default' -enable_fast_install='needless' -shared_archive_member_spec='' -SHELL='/bin/bash' -ECHO='printf %s\n' -PATH_SEPARATOR=':' -host_alias='wasm32-wasi' -host='wasm32-unknown-wasi' -host_os='wasi' -build_alias='' -build='x86_64-pc-linux-gnu' -build_os='linux-gnu' -SED='/usr/bin/sed' -Xsed='/usr/bin/sed -e 1s/^X//' -GREP='/usr/bin/grep' -EGREP='/usr/bin/grep -E' -FGREP='/usr/bin/grep -F' -LD='/home/linuxbrew/.linuxbrew/bin/ld' -NM='nm' -LN_S='ln -s' -max_cmd_len='1572864' -ac_objext='o' -exeext='' -lt_unset='unset' -lt_SP2NL='tr \040 \012' -lt_NL2SP='tr \015\012 \040\040' -lt_cv_to_host_file_cmd='func_convert_file_noop' -lt_cv_to_tool_file_cmd='func_convert_file_noop' -reload_flag=' -r' -reload_cmds='$LD$reload_flag -o $output$reload_objs' -FILECMD='file' -OBJDUMP='objdump' -deplibs_check_method='unknown' -file_magic_cmd='$MAGIC_CMD' -file_magic_glob='' -want_nocaseglob='no' -DLLTOOL='dlltool' -sharedlib_from_linklib_cmd='printf %s\n' -AR='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar' -lt_ar_flags='cr' -AR_FLAGS='cr' -archiver_list_spec='@' -STRIP='strip' -RANLIB='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ranlib' -old_postinstall_cmds='chmod 644 $oldlib~$RANLIB $tool_oldlib' -old_postuninstall_cmds='' -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs~$RANLIB $tool_oldlib' -lock_old_archive_extraction='no' -CC='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23' -CFLAGS='--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h' -compiler='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23' -GCC='yes' -lt_cv_sys_global_symbol_pipe='' -lt_cv_sys_global_symbol_to_cdecl='' -lt_cv_sys_global_symbol_to_import='' -lt_cv_sys_global_symbol_to_c_name_address='/usr/bin/sed -n -e '\''s/^: \(.*\) .*$/ {"\1", (void *) 0},/p'\'' -e '\''s/^[ABCDGIRSTW][ABCDGIRSTW]* .* \(.*\)$/ {"\1", (void *) \&\1},/p'\''' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='/usr/bin/sed -n -e '\''s/^: \(.*\) .*$/ {"\1", (void *) 0},/p'\'' -e '\''s/^[ABCDGIRSTW][ABCDGIRSTW]* .* \(lib.*\)$/ {"\1", (void *) \&\1},/p'\'' -e '\''s/^[ABCDGIRSTW][ABCDGIRSTW]* .* \(.*\)$/ {"lib\1", (void *) \&\1},/p'\''' -lt_cv_nm_interface='BSD nm' -nm_file_list_spec='@' -lt_sysroot='' -lt_cv_truncate_bin='/usr/bin/dd bs=4096 count=1' -objdir='.libs' -MAGIC_CMD='file' -lt_prog_compiler_no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' -lt_prog_compiler_pic=' -fPIC -DPIC' -lt_prog_compiler_wl='-Wl,' -lt_prog_compiler_static='-static' -lt_cv_prog_compiler_c_o='yes' -need_locks='no' -MANIFEST_TOOL=':' -DSYMUTIL='' -NMEDIT='' -LIPO='' -OTOOL='' -OTOOL64='' -libext='a' -shrext_cmds='.so' -extract_expsyms_cmds='' -archive_cmds_need_lc='yes' -enable_shared_with_static_runtimes='no' -export_dynamic_flag_spec='$wl--export-dynamic' -whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' -compiler_needs_object='no' -old_archive_from_new_cmds='' -old_archive_from_expsyms_cmds='' -archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' -archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' -module_cmds='' -module_expsym_cmds='' -with_gnu_ld='yes' -allow_undefined_flag='' -no_undefined_flag='' -hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' -hardcode_libdir_separator='' -hardcode_direct='no' -hardcode_direct_absolute='no' -hardcode_minus_L='no' -hardcode_shlibpath_var='unsupported' -hardcode_automatic='no' -inherit_rpath='no' -link_all_deplibs='unknown' -always_export_symbols='no' -export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' -exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' -include_expsyms='' -prelink_cmds='' -postlink_cmds='' -file_list_spec='' -variables_saved_for_relink='PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH' -need_lib_prefix='unknown' -need_version='unknown' -version_type='none' -runpath_var='LD_RUN_PATH' -shlibpath_var='' -shlibpath_overrides_runpath='unknown' -libname_spec='lib$name' -library_names_spec='' -soname_spec='' -install_override_mode='' -postinstall_cmds='' -postuninstall_cmds='' -finish_cmds='' -finish_eval='' -hardcode_into_libs='no' -sys_lib_search_path_spec='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/lib/clang/19 /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi ' -configure_time_dlsearch_path='/lib /usr/lib' -configure_time_lt_sys_library_path='' -hardcode_action='immediate' -enable_dlopen='unknown' -enable_dlopen_self='unknown' -enable_dlopen_self_static='unknown' -old_striplib='strip --strip-debug' -striplib='strip --strip-unneeded' - -LTCC='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23' -LTCFLAGS='--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h' -compiler='/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in SHELL ECHO PATH_SEPARATOR SED GREP EGREP FGREP LD NM LN_S lt_SP2NL lt_NL2SP reload_flag FILECMD OBJDUMP deplibs_check_method file_magic_cmd file_magic_glob want_nocaseglob DLLTOOL sharedlib_from_linklib_cmd AR archiver_list_spec STRIP RANLIB CC CFLAGS compiler lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl lt_cv_sys_global_symbol_to_import lt_cv_sys_global_symbol_to_c_name_address lt_cv_sys_global_symbol_to_c_name_address_lib_prefix lt_cv_nm_interface nm_file_list_spec lt_cv_truncate_bin lt_prog_compiler_no_builtin_flag lt_prog_compiler_pic lt_prog_compiler_wl lt_prog_compiler_static lt_cv_prog_compiler_c_o need_locks MANIFEST_TOOL DSYMUTIL NMEDIT LIPO OTOOL OTOOL64 shrext_cmds export_dynamic_flag_spec whole_archive_flag_spec compiler_needs_object with_gnu_ld allow_undefined_flag no_undefined_flag hardcode_libdir_flag_spec hardcode_libdir_separator exclude_expsyms include_expsyms file_list_spec variables_saved_for_relink libname_spec library_names_spec soname_spec install_override_mode finish_eval old_striplib striplib; do - case `eval \\$ECHO \\""\\$$var"\\"` in - *[\\\`\"\$]*) - eval "lt_$var=\\\"\`\$ECHO \"\$$var\" | \$SED \"\$sed_quote_subst\"\`\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_$var=\\\"\$$var\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in reload_cmds old_postinstall_cmds old_postuninstall_cmds old_archive_cmds extract_expsyms_cmds old_archive_from_new_cmds old_archive_from_expsyms_cmds archive_cmds archive_expsym_cmds module_cmds module_expsym_cmds export_symbols_cmds prelink_cmds postlink_cmds postinstall_cmds postuninstall_cmds finish_cmds sys_lib_search_path_spec configure_time_dlsearch_path configure_time_lt_sys_library_path; do - case `eval \\$ECHO \\""\\$$var"\\"` in - *[\\\`\"\$]*) - eval "lt_$var=\\\"\`\$ECHO \"\$$var\" | \$SED -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_$var=\\\"\$$var\\\"" - ;; - esac -done - -ac_aux_dir='./' - -# See if we are running on zsh, and set the options that allow our -# commands through without removal of \ escapes INIT. -if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - - - PACKAGE='libXext' - VERSION='1.3.7' - RM='rm -f' - ofile='libtool' - - - - - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; - "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; - "specs/Makefile") CONFIG_FILES="$CONFIG_FILES specs/Makefile" ;; - "xext.pc") CONFIG_FILES="$CONFIG_FILES xext.pc" ;; - - *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files - test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers - test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to '$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with './config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -cat >>"$ac_tmp/subs1.awk" <<\_ACAWK && -S["am__EXEEXT_FALSE"]="" -S["am__EXEEXT_TRUE"]="#" -S["LTLIBOBJS"]="" -S["MAKE_LINT_LIB_FALSE"]="" -S["MAKE_LINT_LIB_TRUE"]="#" -S["LINTLIB"]="" -S["LINT_FALSE"]="" -S["LINT_TRUE"]="#" -S["LINT_FLAGS"]="" -S["LINT"]="" -S["LIBOBJS"]="" -S["XEXT_LIBS"]="-L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib -lX11 " -S["XEXT_CFLAGS"]="-I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include " -S["XEXT_SOREV"]="6:4:0" -S["XTMALLOC_ZERO_CFLAGS"]="-DMALLOC_0_RETURNS_NULL -DXTMALLOC_BC" -S["XMALLOC_ZERO_CFLAGS"]="-DMALLOC_0_RETURNS_NULL" -S["MALLOC_ZERO_CFLAGS"]="-DMALLOC_0_RETURNS_NULL" -S["HAVE_STYLESHEETS_FALSE"]="" -S["HAVE_STYLESHEETS_TRUE"]="#" -S["XSL_STYLESHEET"]="" -S["STYLESHEET_SRCDIR"]="" -S["XORG_SGML_PATH"]="" -S["HAVE_XSLTPROC_FALSE"]="#" -S["HAVE_XSLTPROC_TRUE"]="" -S["XSLTPROC"]="/home/linuxbrew/.linuxbrew/bin/xsltproc" -S["HAVE_FOP_FALSE"]="" -S["HAVE_FOP_TRUE"]="#" -S["FOP"]="" -S["HAVE_XMLTO_FALSE"]="" -S["HAVE_XMLTO_TRUE"]="#" -S["HAVE_XMLTO_TEXT_FALSE"]="" -S["HAVE_XMLTO_TEXT_TRUE"]="#" -S["XMLTO"]="" -S["ENABLE_SPECS_FALSE"]="" -S["ENABLE_SPECS_TRUE"]="#" -S["MAN_SUBSTS"]=" -e 's|__vendorversion__|\"$(PACKAGE_STRING)\" \"$(XORG_MAN_PAGE)\"|' -e 's|__xorgversion__|\"$(PACKAGE_STRING)\" \"$(XORG_MAN_PAGE)\"|' -e 's|__xserverna"\ -"me__|Xorg|g' -e 's|__xconfigfile__|xorg.conf|g' -e 's|__projectroot__|$(prefix)|g' -e 's|__apploaddir__|$(appdefaultdir)|g' -e 's|__appmansuffix"\ -"__|$(APP_MAN_SUFFIX)|g' -e 's|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g' -e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' -e 's|__libmansuffix__|"\ -"$(LIB_MAN_SUFFIX)|g' -e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' -e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g'" -S["XORG_MAN_PAGE"]="X Version 11" -S["ADMIN_MAN_DIR"]="$(mandir)/man$(ADMIN_MAN_SUFFIX)" -S["DRIVER_MAN_DIR"]="$(mandir)/man$(DRIVER_MAN_SUFFIX)" -S["MISC_MAN_DIR"]="$(mandir)/man$(MISC_MAN_SUFFIX)" -S["FILE_MAN_DIR"]="$(mandir)/man$(FILE_MAN_SUFFIX)" -S["LIB_MAN_DIR"]="$(mandir)/man$(LIB_MAN_SUFFIX)" -S["APP_MAN_DIR"]="$(mandir)/man$(APP_MAN_SUFFIX)" -S["ADMIN_MAN_SUFFIX"]="8" -S["DRIVER_MAN_SUFFIX"]="4" -S["MISC_MAN_SUFFIX"]="7" -S["FILE_MAN_SUFFIX"]="5" -S["LIB_MAN_SUFFIX"]="3" -S["APP_MAN_SUFFIX"]="1" -S["INSTALL_CMD"]="(cp -f /home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/share/util-macros/INSTALL $(top_srcdir)/.INSTALL.tmp && mv $(top_srcdir"\ -")/.INSTALL.tmp $(top_srcdir)/INSTALL) || (rm -f $(top_srcdir)/.INSTALL.tmp; test -e $(top_srcdir)/INSTALL || ( touch $(top_srcdir)/INSTALL; echo 'fa"\ -"iled to copy INSTALL from util-macros: installing empty INSTALL.' >&2))" -S["PKG_CONFIG_LIBDIR"]="/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/lib/pkgconfig:/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-p"\ -"refix/share/pkgconfig" -S["PKG_CONFIG_PATH"]="" -S["PKG_CONFIG"]="/usr/bin/pkg-config" -S["CHANGELOG_CMD"]="((GIT_DIR=$(top_srcdir)/.git git log > $(top_srcdir)/.changelog.tmp) 2>/dev/null && mv $(top_srcdir)/.changelog.tmp $(top_srcdir)/ChangeLog) || (rm "\ -"-f $(top_srcdir)/.changelog.tmp; test -e $(top_srcdir)/ChangeLog || ( touch $(top_srcdir)/ChangeLog; echo 'git failed to create ChangeLog: installin"\ -"g empty ChangeLog.' >&2))" -S["STRICT_CFLAGS"]=" -pedantic -Werror -Werror=attributes" -S["CWARNFLAGS"]=" -Wall -Wpointer-arith -Wmissing-declarations -Wformat=2 -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wbad-function-cast -Wold-style-d"\ -"efinition -Wunused -Wuninitialized -Wshadow -Wmissing-noreturn -Wmissing-format-attribute -Wredundant-decls -Werror=implicit -Werror=nonnull -Werror"\ -"=init-self -Werror=main -Werror=missing-braces -Werror=sequence-point -Werror=return-type -Werror=trigraphs -Werror=array-bounds -Werror=write-strin"\ -"gs -Werror=address -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast -fno-strict-aliasing" -S["BASE_CFLAGS"]=" -Wall -Wpointer-arith -Wmissing-declarations -Wformat=2 -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wbad-function-cast -Wold-style-d"\ -"efinition -Wunused -Wuninitialized -Wshadow -Wmissing-noreturn -Wmissing-format-attribute -Wredundant-decls -Werror=implicit -Werror=nonnull -Werror"\ -"=init-self -Werror=main -Werror=missing-braces -Werror=sequence-point -Werror=return-type -Werror=trigraphs -Werror=array-bounds -Werror=write-strin"\ -"gs -Werror=address -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast" -S["LT_SYS_LIBRARY_PATH"]="" -S["OTOOL64"]="" -S["OTOOL"]="" -S["LIPO"]="" -S["NMEDIT"]="" -S["DSYMUTIL"]="" -S["MANIFEST_TOOL"]=":" -S["RANLIB"]="/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ranlib" -S["ac_ct_AR"]="" -S["AR"]="/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar" -S["DLLTOOL"]="dlltool" -S["OBJDUMP"]="objdump" -S["FILECMD"]="file" -S["LN_S"]="ln -s" -S["NM"]="nm" -S["ac_ct_DUMPBIN"]="link -dump" -S["DUMPBIN"]=":" -S["LD"]="/home/linuxbrew/.linuxbrew/bin/ld" -S["FGREP"]="/usr/bin/grep -F" -S["EGREP"]="/usr/bin/grep -E" -S["GREP"]="/usr/bin/grep" -S["SED"]="/usr/bin/sed" -S["host_os"]="wasi" -S["host_vendor"]="unknown" -S["host_cpu"]="wasm32" -S["host"]="wasm32-unknown-wasi" -S["build_os"]="linux-gnu" -S["build_vendor"]="pc" -S["build_cpu"]="x86_64" -S["build"]="x86_64-pc-linux-gnu" -S["LIBTOOL"]="$(SHELL) $(top_builddir)/libtool" -S["am__xargs_n"]="xargs -n" -S["am__rm_f_notfound"]="" -S["AM_BACKSLASH"]="\\" -S["AM_DEFAULT_VERBOSITY"]="0" -S["AM_DEFAULT_V"]="$(AM_DEFAULT_VERBOSITY)" -S["AM_V"]="$(V)" -S["CSCOPE"]="cscope" -S["ETAGS"]="etags" -S["CTAGS"]="ctags" -S["am__fastdepCC_FALSE"]="#" -S["am__fastdepCC_TRUE"]="" -S["CCDEPMODE"]="depmode=gcc3" -S["am__nodep"]="_no" -S["AMDEPBACKSLASH"]="\\" -S["AMDEP_FALSE"]="#" -S["AMDEP_TRUE"]="" -S["am__include"]="include" -S["DEPDIR"]=".deps" -S["am__untar"]="tar -xf -" -S["am__tar"]="tar --format=ustar -chf - \"$$tardir\"" -S["AMTAR"]="$${TAR-tar}" -S["am__leading_dot"]="." -S["SET_MAKE"]="" -S["AWK"]="mawk" -S["mkdir_p"]="$(MKDIR_P)" -S["MKDIR_P"]="/usr/bin/mkdir -p" -S["INSTALL_STRIP_PROGRAM"]="$(install_sh) -c -s" -S["STRIP"]="strip" -S["install_sh"]="${SHELL} /home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/install-sh" -S["MAKEINFO"]="${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' makeinfo" -S["AUTOHEADER"]="${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' autoheader" -S["AUTOMAKE"]="${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' automake-1.18" -S["AUTOCONF"]="${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' autoconf" -S["ACLOCAL"]="${SHELL} '/home/nathan/secure-exec/experiments/wasm-gui/third_party/libXext/missing' aclocal-1.18" -S["VERSION"]="1.3.7" -S["PACKAGE"]="libXext" -S["CYGPATH_W"]="echo" -S["am__isrc"]="" -S["INSTALL_DATA"]="${INSTALL} -m 644" -S["INSTALL_SCRIPT"]="${INSTALL}" -S["INSTALL_PROGRAM"]="${INSTALL}" -S["OBJEXT"]="o" -S["EXEEXT"]="" -S["ac_ct_CC"]="" -S["CPPFLAGS"]="--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm"\ -"-prefix/include" -S["LDFLAGS"]="--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -L/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm"\ -"-prefix/lib -L/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasip1 -lwasi-emulated-mman" -S["CFLAGS"]="--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/natha"\ -"n/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h" -S["CC"]="/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23" -S["ECHO_T"]="" -S["ECHO_N"]="-n" -S["ECHO_C"]="" -S["target_alias"]="" -S["host_alias"]="wasm32-wasi" -S["build_alias"]="" -S["LIBS"]="" -S["DEFS"]="-DHAVE_CONFIG_H" -S["mandir"]="${datarootdir}/man" -S["localedir"]="${datarootdir}/locale" -S["libdir"]="${exec_prefix}/lib" -S["psdir"]="${docdir}" -S["pdfdir"]="${docdir}" -S["dvidir"]="${docdir}" -S["htmldir"]="${docdir}" -S["infodir"]="${datarootdir}/info" -S["docdir"]="${datarootdir}/doc/${PACKAGE_TARNAME}" -S["oldincludedir"]="/usr/include" -S["includedir"]="${prefix}/include" -S["runstatedir"]="${localstatedir}/run" -S["localstatedir"]="${prefix}/var" -S["sharedstatedir"]="${prefix}/com" -S["sysconfdir"]="${prefix}/etc" -S["datadir"]="${datarootdir}" -S["datarootdir"]="${prefix}/share" -S["libexecdir"]="${exec_prefix}/libexec" -S["sbindir"]="${exec_prefix}/sbin" -S["bindir"]="${exec_prefix}/bin" -S["program_transform_name"]="s,x,x," -S["prefix"]="/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix" -S["exec_prefix"]="${prefix}" -S["PACKAGE_URL"]="" -S["PACKAGE_BUGREPORT"]="https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues" -S["PACKAGE_STRING"]="libXext 1.3.7" -S["PACKAGE_VERSION"]="1.3.7" -S["PACKAGE_TARNAME"]="libXext" -S["PACKAGE_NAME"]="libXext" -S["PATH_SEPARATOR"]=":" -S["SHELL"]="/bin/bash" -S["am__quote"]="" -_ACAWK -cat >>"$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with './config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -D["PACKAGE_NAME"]=" \"libXext\"" -D["PACKAGE_TARNAME"]=" \"libXext\"" -D["PACKAGE_VERSION"]=" \"1.3.7\"" -D["PACKAGE_STRING"]=" \"libXext 1.3.7\"" -D["PACKAGE_BUGREPORT"]=" \"https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues\"" -D["PACKAGE_URL"]=" \"\"" -D["HAVE_STDIO_H"]=" 1" -D["HAVE_STDLIB_H"]=" 1" -D["HAVE_STRING_H"]=" 1" -D["HAVE_INTTYPES_H"]=" 1" -D["HAVE_STDINT_H"]=" 1" -D["HAVE_STRINGS_H"]=" 1" -D["HAVE_SYS_STAT_H"]=" 1" -D["HAVE_SYS_TYPES_H"]=" 1" -D["HAVE_UNISTD_H"]=" 1" -D["HAVE_WCHAR_H"]=" 1" -D["STDC_HEADERS"]=" 1" -D["_ALL_SOURCE"]=" 1" -D["_COSMO_SOURCE"]=" 1" -D["_DARWIN_C_SOURCE"]=" 1" -D["_GNU_SOURCE"]=" 1" -D["_HPUX_ALT_XOPEN_SOCKET_API"]=" 1" -D["_NETBSD_SOURCE"]=" 1" -D["_OPENBSD_SOURCE"]=" 1" -D["_POSIX_PTHREAD_SEMANTICS"]=" 1" -D["__STDC_WANT_IEC_60559_ATTRIBS_EXT__"]=" 1" -D["__STDC_WANT_IEC_60559_BFP_EXT__"]=" 1" -D["__STDC_WANT_IEC_60559_DFP_EXT__"]=" 1" -D["__STDC_WANT_IEC_60559_EXT__"]=" 1" -D["__STDC_WANT_IEC_60559_FUNCS_EXT__"]=" 1" -D["__STDC_WANT_IEC_60559_TYPES_EXT__"]=" 1" -D["__STDC_WANT_LIB_EXT2__"]=" 1" -D["__STDC_WANT_MATH_SPEC_FUNCS__"]=" 1" -D["_TANDEM_SOURCE"]=" 1" -D["__EXTENSIONS__"]=" 1" -D["PACKAGE"]=" \"libXext\"" -D["VERSION"]=" \"1.3.7\"" -D["HAVE_DLFCN_H"]=" 1" -D["LT_OBJDIR"]=" \".libs/\"" -D["PACKAGE_VERSION_MAJOR"]=" 1" -D["PACKAGE_VERSION_MINOR"]=" 3" -D["PACKAGE_VERSION_PATCHLEVEL"]=" 7" -D["HAVE___BUILTIN_POPCOUNTL"]=" 1" -D["HAVE_REALLOCARRAY"]=" 1" - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*([\t (]|$)/ { - line = $ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - suffix = P[macro] D[macro] - while (suffix ~ /[\t ]$/) { - suffix = substr(suffix, 1, length(suffix) - 1) - } - # Preserve the white space surrounding the "#". - print prefix "define", macro suffix - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain ':'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf '%s\n' "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is 'configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - printf '%s\n' "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf '%s\n' "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf '%s\n' "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} - ac_datarootdir_hack=' - s&@datadir@&${datarootdir}&g - s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g - s&@infodir@&${datarootdir}/info&g - s&@localedir@&${datarootdir}/locale&g - s&@mandir@&${datarootdir}/man&g - s&\${datarootdir}&${prefix}/share&g' ;; -esac -ac_sed_extra="/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -} - -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf '%s\n' "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf '%s\n' "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || { - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - case $CONFIG_FILES in #( - *\'*) : - eval set x "$CONFIG_FILES" ;; #( - *) : - set x $CONFIG_FILES ;; #( - *) : - ;; -esac - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`printf '%s\n' "$am_mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`$as_dirname -- "$am_mf" || -$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$am_mf" : 'X\(//\)[^/]' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$am_mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - am_filepart=`$as_basename -- "$am_mf" || -$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$am_mf" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - { echo "$as_me:$LINENO: cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles" >&5 - (cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } || am_rc=$? - done - if test $am_rc -ne 0; then - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE=\"gmake\" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking). -See 'config.log' for more details" "$LINENO" 5; } - fi - { am_dirpart=; unset am_dirpart;} - { am_filepart=; unset am_filepart;} - { am_mf=; unset am_mf;} - { am_rc=; unset am_rc;} - rm -f conftest-deps.mk -} - ;; - "libtool":C) - - # See if we are running on zsh, and set the options that allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST - fi - - cfgfile=${ofile}T - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL -# Generated automatically by $as_me ($PACKAGE) $VERSION -# NOTE: Changes made to this file will be lost: look at ltmain.sh. - -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit, 1996 - -# Copyright (C) 2024 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program or library that is built -# using GNU Libtool, you may include this file under the same -# distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -# The names of the tagged configurations supported by this script. -available_tags='' - -# Configured defaults for sys_lib_dlsearch_path munging. -: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=$macro_version -macro_revision=$macro_revision - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# What type of objects to build. -pic_mode=$pic_mode - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# Shared archive member basename,for filename based shared library versioning on AIX. -shared_archive_member_spec=$shared_archive_member_spec - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The PATH separator for the build system. -PATH_SEPARATOR=$lt_PATH_SEPARATOR - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="\$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP=$lt_GREP - -# An ERE matcher. -EGREP=$lt_EGREP - -# A literal string matcher. -FGREP=$lt_FGREP - -# A BSD- or MS-compatible name lister. -NM=$lt_NM - -# Whether we need soft or hard links. -LN_S=$lt_LN_S - -# What is the maximum length of a command? -max_cmd_len=$max_cmd_len - -# Object file suffix (normally "o"). -objext=$ac_objext - -# Executable file suffix (normally ""). -exeext=$exeext - -# whether the shell understands "unset". -lt_unset=$lt_unset - -# turn spaces into newlines. -SP2NL=$lt_lt_SP2NL - -# turn newlines into spaces. -NL2SP=$lt_lt_NL2SP - -# convert \$build file names to \$host format. -to_host_file_cmd=$lt_cv_to_host_file_cmd - -# convert \$build files to toolchain format. -to_tool_file_cmd=$lt_cv_to_tool_file_cmd - -# A file(cmd) program that detects file types. -FILECMD=$lt_FILECMD - -# An object symbol dumper. -OBJDUMP=$lt_OBJDUMP - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method = "file_magic". -file_magic_cmd=$lt_file_magic_cmd - -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob=$lt_file_magic_glob - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob=$lt_want_nocaseglob - -# DLL creation program. -DLLTOOL=$lt_DLLTOOL - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd - -# The archiver. -AR=$lt_AR - -# Flags to create an archive (by configure). -lt_ar_flags=$lt_ar_flags - -# Flags to create an archive. -AR_FLAGS=\${ARFLAGS-"\$lt_ar_flags"} - -# How to feed a file listing to the archiver. -archiver_list_spec=$lt_archiver_list_spec - -# A symbol stripping program. -STRIP=$lt_STRIP - -# Commands used to install an old-style archive. -RANLIB=$lt_RANLIB -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - -# A C compiler. -LTCC=$lt_CC - -# LTCC compiler flags. -LTCFLAGS=$lt_CFLAGS - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm into a list of symbols to manually relocate. -global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix - -# The name lister interface. -nm_interface=$lt_lt_cv_nm_interface - -# Specify filename containing input files for \$NM. -nm_file_list_spec=$lt_nm_file_list_spec - -# The root where to search for dependent libraries,and where our libraries should be installed. -lt_sysroot=$lt_sysroot - -# Command to truncate a binary pipe. -lt_truncate_bin=$lt_lt_cv_truncate_bin - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=$MAGIC_CMD - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Manifest tool. -MANIFEST_TOOL=$lt_MANIFEST_TOOL - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL=$lt_DSYMUTIL - -# Tool to change global to local symbols on Mac OS X. -NMEDIT=$lt_NMEDIT - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO=$lt_LIPO - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL=$lt_OTOOL - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64=$lt_OTOOL64 - -# Old archive suffix (normally "a"). -libext=$libext - -# Shared library suffix (normally ".so"). -shrext_cmds=$lt_shrext_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink=$lt_variables_saved_for_relink - -# Do we need the "lib" prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Library versioning type. -version_type=$version_type - -# Shared library runtime path variable. -runpath_var=$runpath_var - -# Shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - -# Command to use after installation of a shared archive. -postinstall_cmds=$lt_postinstall_cmds - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval=$lt_finish_eval - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Compile-time system search path for libraries. -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Detected run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path - -# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. -configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - - -# The linker used to build libraries. -LD=$lt_LD - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds - -# A language specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU compiler? -with_gcc=$GCC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e. impossible to change by setting \$shlibpath_var if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# ### END LIBTOOL CONFIG - -_LT_EOF - - cat <<'_LT_EOF' >> "$cfgfile" - -# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x$2 in - x) - ;; - *:) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" - ;; - x:*) - eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" - ;; - *) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" - ;; - esac -} - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in $*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - - -# ### END FUNCTIONS SHARED WITH CONFIGURE - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - - -ltmain=$ac_aux_dir/ltmain.sh - - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - $SED '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - - ;; - - esac -done # for ac_tag - - -as_fn_exit 0 diff --git a/experiments/wasm-gui/third_party/libXext/config.sub b/experiments/wasm-gui/third_party/libXext/config.sub deleted file mode 100755 index 3d35cde17..000000000 --- a/experiments/wasm-gui/third_party/libXext/config.sub +++ /dev/null @@ -1,2364 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script. -# Copyright 1992-2025 Free Software Foundation, Inc. - -# shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale - -timestamp='2025-07-10' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). - - -# Please send patches to . -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# You can get the latest version of this script from: -# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -# The "shellcheck disable" line above the timestamp inhibits complaints -# about features and limitations of the classic Bourne shell that were -# superseded or lifted in POSIX. However, this script identifies a wide -# variety of pre-POSIX systems that do not have POSIX shells at all, and -# even some reasonably current systems (Solaris 10 as case-in-point) still -# have a pre-POSIX /bin/sh. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS - -Canonicalize a configuration name. - -Options: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.sub ($timestamp) - -Copyright 1992-2025 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try '$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo "$1" - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Split fields of configuration type -saved_IFS=$IFS -IFS="-" read field1 field2 field3 field4 <&2 - exit 1 - ;; - *-*-*-*) - basic_machine=$field1-$field2 - basic_os=$field3-$field4 - ;; - *-*-*) - # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two - # parts - maybe_os=$field2-$field3 - case $maybe_os in - cloudabi*-eabi* \ - | kfreebsd*-gnu* \ - | knetbsd*-gnu* \ - | kopensolaris*-gnu* \ - | ironclad-* \ - | linux-* \ - | managarm-* \ - | netbsd*-eabi* \ - | netbsd*-gnu* \ - | nto-qnx* \ - | os2-emx* \ - | rtmk-nova* \ - | storm-chaos* \ - | uclinux-gnu* \ - | uclinux-uclibc* \ - | windows-* ) - basic_machine=$field1 - basic_os=$maybe_os - ;; - android-linux) - basic_machine=$field1-unknown - basic_os=linux-android - ;; - *) - basic_machine=$field1-$field2 - basic_os=$field3 - ;; - esac - ;; - *-*) - case $field1-$field2 in - # Shorthands that happen to contain a single dash - convex-c[12] | convex-c3[248]) - basic_machine=$field2-convex - basic_os= - ;; - decstation-3100) - basic_machine=mips-dec - basic_os= - ;; - *-*) - # Second component is usually, but not always the OS - case $field2 in - # Do not treat sunos as a manufacturer - sun*os*) - basic_machine=$field1 - basic_os=$field2 - ;; - # Manufacturers - 3100* \ - | 32* \ - | 3300* \ - | 3600* \ - | 7300* \ - | acorn \ - | altos* \ - | apollo \ - | apple \ - | atari \ - | att* \ - | axis \ - | be \ - | bull \ - | cbm \ - | ccur \ - | cisco \ - | commodore \ - | convergent* \ - | convex* \ - | cray \ - | crds \ - | dec* \ - | delta* \ - | dg \ - | digital \ - | dolphin \ - | encore* \ - | gould \ - | harris \ - | highlevel \ - | hitachi* \ - | hp \ - | ibm* \ - | intergraph \ - | isi* \ - | knuth \ - | masscomp \ - | microblaze* \ - | mips* \ - | motorola* \ - | ncr* \ - | news \ - | next \ - | ns \ - | oki \ - | omron* \ - | pc533* \ - | rebel \ - | rom68k \ - | rombug \ - | semi \ - | sequent* \ - | sgi* \ - | siemens \ - | sim \ - | sni \ - | sony* \ - | stratus \ - | sun \ - | sun[234]* \ - | tektronix \ - | tti* \ - | ultra \ - | unicom* \ - | wec \ - | winbond \ - | wrs) - basic_machine=$field1-$field2 - basic_os= - ;; - tock* | zephyr*) - basic_machine=$field1-unknown - basic_os=$field2 - ;; - *) - basic_machine=$field1 - basic_os=$field2 - ;; - esac - ;; - esac - ;; - *) - # Convert single-component short-hands not valid as part of - # multi-component configurations. - case $field1 in - 386bsd) - basic_machine=i386-pc - basic_os=bsd - ;; - a29khif) - basic_machine=a29k-amd - basic_os=udi - ;; - adobe68k) - basic_machine=m68010-adobe - basic_os=scout - ;; - alliant) - basic_machine=fx80-alliant - basic_os= - ;; - altos | altos3068) - basic_machine=m68k-altos - basic_os= - ;; - am29k) - basic_machine=a29k-none - basic_os=bsd - ;; - amdahl) - basic_machine=580-amdahl - basic_os=sysv - ;; - amiga) - basic_machine=m68k-unknown - basic_os= - ;; - amigaos | amigados) - basic_machine=m68k-unknown - basic_os=amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - basic_os=sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - basic_os=sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - basic_os=bsd - ;; - aros) - basic_machine=i386-pc - basic_os=aros - ;; - aux) - basic_machine=m68k-apple - basic_os=aux - ;; - balance) - basic_machine=ns32k-sequent - basic_os=dynix - ;; - blackfin) - basic_machine=bfin-unknown - basic_os=linux - ;; - cegcc) - basic_machine=arm-unknown - basic_os=cegcc - ;; - cray) - basic_machine=j90-cray - basic_os=unicos - ;; - crds | unos) - basic_machine=m68k-crds - basic_os= - ;; - da30) - basic_machine=m68k-da30 - basic_os= - ;; - decstation | pmax | pmin | dec3100 | decstatn) - basic_machine=mips-dec - basic_os= - ;; - delta88) - basic_machine=m88k-motorola - basic_os=sysv3 - ;; - dicos) - basic_machine=i686-pc - basic_os=dicos - ;; - djgpp) - basic_machine=i586-pc - basic_os=msdosdjgpp - ;; - ebmon29k) - basic_machine=a29k-amd - basic_os=ebmon - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - basic_os=ose - ;; - gmicro) - basic_machine=tron-gmicro - basic_os=sysv - ;; - go32) - basic_machine=i386-pc - basic_os=go32 - ;; - h8300hms) - basic_machine=h8300-hitachi - basic_os=hms - ;; - h8300xray) - basic_machine=h8300-hitachi - basic_os=xray - ;; - h8500hms) - basic_machine=h8500-hitachi - basic_os=hms - ;; - harris) - basic_machine=m88k-harris - basic_os=sysv3 - ;; - hp300 | hp300hpux) - basic_machine=m68k-hp - basic_os=hpux - ;; - hp300bsd) - basic_machine=m68k-hp - basic_os=bsd - ;; - hppaosf) - basic_machine=hppa1.1-hp - basic_os=osf - ;; - hppro) - basic_machine=hppa1.1-hp - basic_os=proelf - ;; - i386mach) - basic_machine=i386-mach - basic_os=mach - ;; - isi68 | isi) - basic_machine=m68k-isi - basic_os=sysv - ;; - m68knommu) - basic_machine=m68k-unknown - basic_os=linux - ;; - magnum | m3230) - basic_machine=mips-mips - basic_os=sysv - ;; - merlin) - basic_machine=ns32k-utek - basic_os=sysv - ;; - mingw64) - basic_machine=x86_64-pc - basic_os=mingw64 - ;; - mingw32) - basic_machine=i686-pc - basic_os=mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - basic_os=mingw32ce - ;; - monitor) - basic_machine=m68k-rom68k - basic_os=coff - ;; - morphos) - basic_machine=powerpc-unknown - basic_os=morphos - ;; - moxiebox) - basic_machine=moxie-unknown - basic_os=moxiebox - ;; - msdos) - basic_machine=i386-pc - basic_os=msdos - ;; - msys) - basic_machine=i686-pc - basic_os=msys - ;; - mvs) - basic_machine=i370-ibm - basic_os=mvs - ;; - nacl) - basic_machine=le32-unknown - basic_os=nacl - ;; - ncr3000) - basic_machine=i486-ncr - basic_os=sysv4 - ;; - netbsd386) - basic_machine=i386-pc - basic_os=netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - basic_os=linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - basic_os=newsos - ;; - news1000) - basic_machine=m68030-sony - basic_os=newsos - ;; - necv70) - basic_machine=v70-nec - basic_os=sysv - ;; - nh3000) - basic_machine=m68k-harris - basic_os=cxux - ;; - nh[45]000) - basic_machine=m88k-harris - basic_os=cxux - ;; - nindy960) - basic_machine=i960-intel - basic_os=nindy - ;; - mon960) - basic_machine=i960-intel - basic_os=mon960 - ;; - nonstopux) - basic_machine=mips-compaq - basic_os=nonstopux - ;; - os400) - basic_machine=powerpc-ibm - basic_os=os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - basic_os=ose - ;; - os68k) - basic_machine=m68k-none - basic_os=os68k - ;; - paragon) - basic_machine=i860-intel - basic_os=osf - ;; - parisc) - basic_machine=hppa-unknown - basic_os=linux - ;; - psp) - basic_machine=mipsallegrexel-sony - basic_os=psp - ;; - pw32) - basic_machine=i586-unknown - basic_os=pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - basic_os=rdos - ;; - rdos32) - basic_machine=i386-pc - basic_os=rdos - ;; - rom68k) - basic_machine=m68k-rom68k - basic_os=coff - ;; - sa29200) - basic_machine=a29k-amd - basic_os=udi - ;; - sei) - basic_machine=mips-sei - basic_os=seiux - ;; - sequent) - basic_machine=i386-sequent - basic_os= - ;; - sps7) - basic_machine=m68k-bull - basic_os=sysv2 - ;; - st2000) - basic_machine=m68k-tandem - basic_os= - ;; - stratus) - basic_machine=i860-stratus - basic_os=sysv4 - ;; - sun2) - basic_machine=m68000-sun - basic_os= - ;; - sun2os3) - basic_machine=m68000-sun - basic_os=sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - basic_os=sunos4 - ;; - sun3) - basic_machine=m68k-sun - basic_os= - ;; - sun3os3) - basic_machine=m68k-sun - basic_os=sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - basic_os=sunos4 - ;; - sun4) - basic_machine=sparc-sun - basic_os= - ;; - sun4os3) - basic_machine=sparc-sun - basic_os=sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - basic_os=sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - basic_os=solaris2 - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - basic_os= - ;; - sv1) - basic_machine=sv1-cray - basic_os=unicos - ;; - symmetry) - basic_machine=i386-sequent - basic_os=dynix - ;; - t3e) - basic_machine=alphaev5-cray - basic_os=unicos - ;; - t90) - basic_machine=t90-cray - basic_os=unicos - ;; - toad1) - basic_machine=pdp10-xkl - basic_os=tops20 - ;; - tpf) - basic_machine=s390x-ibm - basic_os=tpf - ;; - udi29k) - basic_machine=a29k-amd - basic_os=udi - ;; - ultra3) - basic_machine=a29k-nyu - basic_os=sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - basic_os=none - ;; - vaxv) - basic_machine=vax-dec - basic_os=sysv - ;; - vms) - basic_machine=vax-dec - basic_os=vms - ;; - vsta) - basic_machine=i386-pc - basic_os=vsta - ;; - vxworks960) - basic_machine=i960-wrs - basic_os=vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - basic_os=vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - basic_os=vxworks - ;; - xbox) - basic_machine=i686-pc - basic_os=mingw32 - ;; - ymp) - basic_machine=ymp-cray - basic_os=unicos - ;; - *) - basic_machine=$1 - basic_os= - ;; - esac - ;; -esac - -# Decode 1-component or ad-hoc basic machines -case $basic_machine in - # Here we handle the default manufacturer of certain CPU types. It is in - # some cases the only manufacturer, in others, it is the most popular. - w89k) - cpu=hppa1.1 - vendor=winbond - ;; - op50n) - cpu=hppa1.1 - vendor=oki - ;; - op60c) - cpu=hppa1.1 - vendor=oki - ;; - ibm*) - cpu=i370 - vendor=ibm - ;; - orion105) - cpu=clipper - vendor=highlevel - ;; - mac | mpw | mac-mpw) - cpu=m68k - vendor=apple - ;; - pmac | pmac-mpw) - cpu=powerpc - vendor=apple - ;; - - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - cpu=m68000 - vendor=att - ;; - 3b*) - cpu=we32k - vendor=att - ;; - bluegene*) - cpu=powerpc - vendor=ibm - basic_os=cnk - ;; - decsystem10* | dec10*) - cpu=pdp10 - vendor=dec - basic_os=tops10 - ;; - decsystem20* | dec20*) - cpu=pdp10 - vendor=dec - basic_os=tops20 - ;; - delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300) - cpu=m68k - vendor=motorola - ;; - # This used to be dpx2*, but that gets the RS6000-based - # DPX/20 and the x86-based DPX/2-100 wrong. See - # https://oldskool.silicium.org/stations/bull_dpx20.htm - # https://www.feb-patrimoine.com/english/bull_dpx2.htm - # https://www.feb-patrimoine.com/english/unix_and_bull.htm - dpx2 | dpx2[23]00 | dpx2[23]xx) - cpu=m68k - vendor=bull - ;; - dpx2100 | dpx21xx) - cpu=i386 - vendor=bull - ;; - dpx20) - cpu=rs6000 - vendor=bull - ;; - encore | umax | mmax) - cpu=ns32k - vendor=encore - ;; - elxsi) - cpu=elxsi - vendor=elxsi - basic_os=${basic_os:-bsd} - ;; - fx2800) - cpu=i860 - vendor=alliant - ;; - genix) - cpu=ns32k - vendor=ns - ;; - h3050r* | hiux*) - cpu=hppa1.1 - vendor=hitachi - basic_os=hiuxwe2 - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - cpu=hppa1.0 - vendor=hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - cpu=m68000 - vendor=hp - ;; - hp9k3[2-9][0-9]) - cpu=m68k - vendor=hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - cpu=hppa1.0 - vendor=hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - cpu=hppa1.1 - vendor=hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - cpu=hppa1.1 - vendor=hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - cpu=hppa1.1 - vendor=hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - cpu=hppa1.1 - vendor=hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - cpu=hppa1.0 - vendor=hp - ;; - i*86v32) - cpu=`echo "$1" | sed -e 's/86.*/86/'` - vendor=pc - basic_os=sysv32 - ;; - i*86v4*) - cpu=`echo "$1" | sed -e 's/86.*/86/'` - vendor=pc - basic_os=sysv4 - ;; - i*86v) - cpu=`echo "$1" | sed -e 's/86.*/86/'` - vendor=pc - basic_os=sysv - ;; - i*86sol2) - cpu=`echo "$1" | sed -e 's/86.*/86/'` - vendor=pc - basic_os=solaris2 - ;; - j90 | j90-cray) - cpu=j90 - vendor=cray - basic_os=${basic_os:-unicos} - ;; - iris | iris4d) - cpu=mips - vendor=sgi - case $basic_os in - irix*) - ;; - *) - basic_os=irix4 - ;; - esac - ;; - miniframe) - cpu=m68000 - vendor=convergent - ;; - *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) - cpu=m68k - vendor=atari - basic_os=mint - ;; - news-3600 | risc-news) - cpu=mips - vendor=sony - basic_os=newsos - ;; - next | m*-next) - cpu=m68k - vendor=next - ;; - np1) - cpu=np1 - vendor=gould - ;; - op50n-* | op60c-*) - cpu=hppa1.1 - vendor=oki - basic_os=proelf - ;; - pa-hitachi) - cpu=hppa1.1 - vendor=hitachi - basic_os=hiuxwe2 - ;; - pbd) - cpu=sparc - vendor=tti - ;; - pbb) - cpu=m68k - vendor=tti - ;; - pc532) - cpu=ns32k - vendor=pc532 - ;; - pn) - cpu=pn - vendor=gould - ;; - power) - cpu=power - vendor=ibm - ;; - ps2) - cpu=i386 - vendor=ibm - ;; - rm[46]00) - cpu=mips - vendor=siemens - ;; - rtpc | rtpc-*) - cpu=romp - vendor=ibm - ;; - sde) - cpu=mipsisa32 - vendor=sde - basic_os=${basic_os:-elf} - ;; - simso-wrs) - cpu=sparclite - vendor=wrs - basic_os=vxworks - ;; - tower | tower-32) - cpu=m68k - vendor=ncr - ;; - vpp*|vx|vx-*) - cpu=f301 - vendor=fujitsu - ;; - w65) - cpu=w65 - vendor=wdc - ;; - w89k-*) - cpu=hppa1.1 - vendor=winbond - basic_os=proelf - ;; - none) - cpu=none - vendor=none - ;; - leon|leon[3-9]) - cpu=sparc - vendor=$basic_machine - ;; - leon-*|leon[3-9]-*) - cpu=sparc - vendor=`echo "$basic_machine" | sed 's/-.*//'` - ;; - - *-*) - saved_IFS=$IFS - IFS="-" read cpu vendor <&2 - exit 1 - ;; - esac - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $vendor in - digital*) - vendor=dec - ;; - commodore*) - vendor=cbm - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if test x"$basic_os" != x -then - -# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just -# set os. -obj= -case $basic_os in - gnu/linux*) - kernel=linux - os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` - ;; - os2-emx) - kernel=os2 - os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` - ;; - nto-qnx*) - kernel=nto - os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` - ;; - *-*) - saved_IFS=$IFS - IFS="-" read kernel os <&2 - fi - ;; - *) - echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 - exit 1 - ;; -esac - -case $obj in - aout* | coff* | elf* | pe*) - ;; - '') - # empty is fine - ;; - *) - echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 - exit 1 - ;; -esac - -# Here we handle the constraint that a (synthetic) cpu and os are -# valid only in combination with each other and nowhere else. -case $cpu-$os in - # The "javascript-unknown-ghcjs" triple is used by GHC; we - # accept it here in order to tolerate that, but reject any - # variations. - javascript-ghcjs) - ;; - javascript-* | *-ghcjs) - echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 - exit 1 - ;; -esac - -# As a final step for OS-related things, validate the OS-kernel combination -# (given a valid OS), if there is a kernel. -case $kernel-$os-$obj in - linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ - | linux-mlibc*- | linux-musl*- | linux-newlib*- \ - | linux-relibc*- | linux-uclibc*- | linux-ohos*- ) - ;; - uclinux-uclibc*- | uclinux-gnu*- ) - ;; - ironclad-mlibc*-) - ;; - managarm-mlibc*- | managarm-kernel*- ) - ;; - windows*-msvc*-) - ;; - -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ - | -uclibc*- ) - # These are just libc implementations, not actual OSes, and thus - # require a kernel. - echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 - exit 1 - ;; - -kernel*- ) - echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 - exit 1 - ;; - *-kernel*- ) - echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 - exit 1 - ;; - *-msvc*- ) - echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 - exit 1 - ;; - kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-) - ;; - vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) - ;; - nto-qnx*-) - ;; - os2-emx-) - ;; - rtmk-nova-) - ;; - *-eabi*- | *-gnueabi*-) - ;; - ios*-simulator- | tvos*-simulator- | watchos*-simulator- ) - ;; - none--*) - # None (no kernel, i.e. freestanding / bare metal), - # can be paired with an machine code file format - ;; - -*-) - # Blank kernel with real OS is always fine. - ;; - --*) - # Blank kernel and OS with real machine code file format is always fine. - ;; - *-*-*) - echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 - exit 1 - ;; -esac - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -case $vendor in - unknown) - case $cpu-$os in - *-riscix*) - vendor=acorn - ;; - *-sunos* | *-solaris*) - vendor=sun - ;; - *-cnk* | *-aix*) - vendor=ibm - ;; - *-beos*) - vendor=be - ;; - *-hpux*) - vendor=hp - ;; - *-mpeix*) - vendor=hp - ;; - *-hiux*) - vendor=hitachi - ;; - *-unos*) - vendor=crds - ;; - *-dgux*) - vendor=dg - ;; - *-luna*) - vendor=omron - ;; - *-genix*) - vendor=ns - ;; - *-clix*) - vendor=intergraph - ;; - *-mvs* | *-opened*) - vendor=ibm - ;; - *-os400*) - vendor=ibm - ;; - s390-* | s390x-*) - vendor=ibm - ;; - *-ptx*) - vendor=sequent - ;; - *-tpf*) - vendor=ibm - ;; - *-vxsim* | *-vxworks* | *-windiss*) - vendor=wrs - ;; - *-aux*) - vendor=apple - ;; - *-hms*) - vendor=hitachi - ;; - *-mpw* | *-macos*) - vendor=apple - ;; - *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) - vendor=atari - ;; - *-vos*) - vendor=stratus - ;; - esac - ;; -esac - -echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" -exit - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp nil t) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%Y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/experiments/wasm-gui/third_party/libXext/config.sub~ b/experiments/wasm-gui/third_party/libXext/config.sub~ deleted file mode 100755 index 4aaae46f6..000000000 --- a/experiments/wasm-gui/third_party/libXext/config.sub~ +++ /dev/null @@ -1,2354 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script. -# Copyright 1992-2024 Free Software Foundation, Inc. - -# shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale - -timestamp='2024-05-27' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). - - -# Please send patches to . -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# You can get the latest version of this script from: -# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -# The "shellcheck disable" line above the timestamp inhibits complaints -# about features and limitations of the classic Bourne shell that were -# superseded or lifted in POSIX. However, this script identifies a wide -# variety of pre-POSIX systems that do not have POSIX shells at all, and -# even some reasonably current systems (Solaris 10 as case-in-point) still -# have a pre-POSIX /bin/sh. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS - -Canonicalize a configuration name. - -Options: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.sub ($timestamp) - -Copyright 1992-2024 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try '$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo "$1" - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Split fields of configuration type -saved_IFS=$IFS -IFS="-" read field1 field2 field3 field4 <&2 - exit 1 - ;; - *-*-*-*) - basic_machine=$field1-$field2 - basic_os=$field3-$field4 - ;; - *-*-*) - # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two - # parts - maybe_os=$field2-$field3 - case $maybe_os in - cloudabi*-eabi* \ - | kfreebsd*-gnu* \ - | knetbsd*-gnu* \ - | kopensolaris*-gnu* \ - | linux-* \ - | managarm-* \ - | netbsd*-eabi* \ - | netbsd*-gnu* \ - | nto-qnx* \ - | os2-emx* \ - | rtmk-nova* \ - | storm-chaos* \ - | uclinux-gnu* \ - | uclinux-uclibc* \ - | windows-* ) - basic_machine=$field1 - basic_os=$maybe_os - ;; - android-linux) - basic_machine=$field1-unknown - basic_os=linux-android - ;; - *) - basic_machine=$field1-$field2 - basic_os=$field3 - ;; - esac - ;; - *-*) - case $field1-$field2 in - # Shorthands that happen to contain a single dash - convex-c[12] | convex-c3[248]) - basic_machine=$field2-convex - basic_os= - ;; - decstation-3100) - basic_machine=mips-dec - basic_os= - ;; - *-*) - # Second component is usually, but not always the OS - case $field2 in - # Do not treat sunos as a manufacturer - sun*os*) - basic_machine=$field1 - basic_os=$field2 - ;; - # Manufacturers - 3100* \ - | 32* \ - | 3300* \ - | 3600* \ - | 7300* \ - | acorn \ - | altos* \ - | apollo \ - | apple \ - | atari \ - | att* \ - | axis \ - | be \ - | bull \ - | cbm \ - | ccur \ - | cisco \ - | commodore \ - | convergent* \ - | convex* \ - | cray \ - | crds \ - | dec* \ - | delta* \ - | dg \ - | digital \ - | dolphin \ - | encore* \ - | gould \ - | harris \ - | highlevel \ - | hitachi* \ - | hp \ - | ibm* \ - | intergraph \ - | isi* \ - | knuth \ - | masscomp \ - | microblaze* \ - | mips* \ - | motorola* \ - | ncr* \ - | news \ - | next \ - | ns \ - | oki \ - | omron* \ - | pc533* \ - | rebel \ - | rom68k \ - | rombug \ - | semi \ - | sequent* \ - | siemens \ - | sgi* \ - | siemens \ - | sim \ - | sni \ - | sony* \ - | stratus \ - | sun \ - | sun[234]* \ - | tektronix \ - | tti* \ - | ultra \ - | unicom* \ - | wec \ - | winbond \ - | wrs) - basic_machine=$field1-$field2 - basic_os= - ;; - zephyr*) - basic_machine=$field1-unknown - basic_os=$field2 - ;; - *) - basic_machine=$field1 - basic_os=$field2 - ;; - esac - ;; - esac - ;; - *) - # Convert single-component short-hands not valid as part of - # multi-component configurations. - case $field1 in - 386bsd) - basic_machine=i386-pc - basic_os=bsd - ;; - a29khif) - basic_machine=a29k-amd - basic_os=udi - ;; - adobe68k) - basic_machine=m68010-adobe - basic_os=scout - ;; - alliant) - basic_machine=fx80-alliant - basic_os= - ;; - altos | altos3068) - basic_machine=m68k-altos - basic_os= - ;; - am29k) - basic_machine=a29k-none - basic_os=bsd - ;; - amdahl) - basic_machine=580-amdahl - basic_os=sysv - ;; - amiga) - basic_machine=m68k-unknown - basic_os= - ;; - amigaos | amigados) - basic_machine=m68k-unknown - basic_os=amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - basic_os=sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - basic_os=sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - basic_os=bsd - ;; - aros) - basic_machine=i386-pc - basic_os=aros - ;; - aux) - basic_machine=m68k-apple - basic_os=aux - ;; - balance) - basic_machine=ns32k-sequent - basic_os=dynix - ;; - blackfin) - basic_machine=bfin-unknown - basic_os=linux - ;; - cegcc) - basic_machine=arm-unknown - basic_os=cegcc - ;; - cray) - basic_machine=j90-cray - basic_os=unicos - ;; - crds | unos) - basic_machine=m68k-crds - basic_os= - ;; - da30) - basic_machine=m68k-da30 - basic_os= - ;; - decstation | pmax | pmin | dec3100 | decstatn) - basic_machine=mips-dec - basic_os= - ;; - delta88) - basic_machine=m88k-motorola - basic_os=sysv3 - ;; - dicos) - basic_machine=i686-pc - basic_os=dicos - ;; - djgpp) - basic_machine=i586-pc - basic_os=msdosdjgpp - ;; - ebmon29k) - basic_machine=a29k-amd - basic_os=ebmon - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - basic_os=ose - ;; - gmicro) - basic_machine=tron-gmicro - basic_os=sysv - ;; - go32) - basic_machine=i386-pc - basic_os=go32 - ;; - h8300hms) - basic_machine=h8300-hitachi - basic_os=hms - ;; - h8300xray) - basic_machine=h8300-hitachi - basic_os=xray - ;; - h8500hms) - basic_machine=h8500-hitachi - basic_os=hms - ;; - harris) - basic_machine=m88k-harris - basic_os=sysv3 - ;; - hp300 | hp300hpux) - basic_machine=m68k-hp - basic_os=hpux - ;; - hp300bsd) - basic_machine=m68k-hp - basic_os=bsd - ;; - hppaosf) - basic_machine=hppa1.1-hp - basic_os=osf - ;; - hppro) - basic_machine=hppa1.1-hp - basic_os=proelf - ;; - i386mach) - basic_machine=i386-mach - basic_os=mach - ;; - isi68 | isi) - basic_machine=m68k-isi - basic_os=sysv - ;; - m68knommu) - basic_machine=m68k-unknown - basic_os=linux - ;; - magnum | m3230) - basic_machine=mips-mips - basic_os=sysv - ;; - merlin) - basic_machine=ns32k-utek - basic_os=sysv - ;; - mingw64) - basic_machine=x86_64-pc - basic_os=mingw64 - ;; - mingw32) - basic_machine=i686-pc - basic_os=mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - basic_os=mingw32ce - ;; - monitor) - basic_machine=m68k-rom68k - basic_os=coff - ;; - morphos) - basic_machine=powerpc-unknown - basic_os=morphos - ;; - moxiebox) - basic_machine=moxie-unknown - basic_os=moxiebox - ;; - msdos) - basic_machine=i386-pc - basic_os=msdos - ;; - msys) - basic_machine=i686-pc - basic_os=msys - ;; - mvs) - basic_machine=i370-ibm - basic_os=mvs - ;; - nacl) - basic_machine=le32-unknown - basic_os=nacl - ;; - ncr3000) - basic_machine=i486-ncr - basic_os=sysv4 - ;; - netbsd386) - basic_machine=i386-pc - basic_os=netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - basic_os=linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - basic_os=newsos - ;; - news1000) - basic_machine=m68030-sony - basic_os=newsos - ;; - necv70) - basic_machine=v70-nec - basic_os=sysv - ;; - nh3000) - basic_machine=m68k-harris - basic_os=cxux - ;; - nh[45]000) - basic_machine=m88k-harris - basic_os=cxux - ;; - nindy960) - basic_machine=i960-intel - basic_os=nindy - ;; - mon960) - basic_machine=i960-intel - basic_os=mon960 - ;; - nonstopux) - basic_machine=mips-compaq - basic_os=nonstopux - ;; - os400) - basic_machine=powerpc-ibm - basic_os=os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - basic_os=ose - ;; - os68k) - basic_machine=m68k-none - basic_os=os68k - ;; - paragon) - basic_machine=i860-intel - basic_os=osf - ;; - parisc) - basic_machine=hppa-unknown - basic_os=linux - ;; - psp) - basic_machine=mipsallegrexel-sony - basic_os=psp - ;; - pw32) - basic_machine=i586-unknown - basic_os=pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - basic_os=rdos - ;; - rdos32) - basic_machine=i386-pc - basic_os=rdos - ;; - rom68k) - basic_machine=m68k-rom68k - basic_os=coff - ;; - sa29200) - basic_machine=a29k-amd - basic_os=udi - ;; - sei) - basic_machine=mips-sei - basic_os=seiux - ;; - sequent) - basic_machine=i386-sequent - basic_os= - ;; - sps7) - basic_machine=m68k-bull - basic_os=sysv2 - ;; - st2000) - basic_machine=m68k-tandem - basic_os= - ;; - stratus) - basic_machine=i860-stratus - basic_os=sysv4 - ;; - sun2) - basic_machine=m68000-sun - basic_os= - ;; - sun2os3) - basic_machine=m68000-sun - basic_os=sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - basic_os=sunos4 - ;; - sun3) - basic_machine=m68k-sun - basic_os= - ;; - sun3os3) - basic_machine=m68k-sun - basic_os=sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - basic_os=sunos4 - ;; - sun4) - basic_machine=sparc-sun - basic_os= - ;; - sun4os3) - basic_machine=sparc-sun - basic_os=sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - basic_os=sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - basic_os=solaris2 - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - basic_os= - ;; - sv1) - basic_machine=sv1-cray - basic_os=unicos - ;; - symmetry) - basic_machine=i386-sequent - basic_os=dynix - ;; - t3e) - basic_machine=alphaev5-cray - basic_os=unicos - ;; - t90) - basic_machine=t90-cray - basic_os=unicos - ;; - toad1) - basic_machine=pdp10-xkl - basic_os=tops20 - ;; - tpf) - basic_machine=s390x-ibm - basic_os=tpf - ;; - udi29k) - basic_machine=a29k-amd - basic_os=udi - ;; - ultra3) - basic_machine=a29k-nyu - basic_os=sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - basic_os=none - ;; - vaxv) - basic_machine=vax-dec - basic_os=sysv - ;; - vms) - basic_machine=vax-dec - basic_os=vms - ;; - vsta) - basic_machine=i386-pc - basic_os=vsta - ;; - vxworks960) - basic_machine=i960-wrs - basic_os=vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - basic_os=vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - basic_os=vxworks - ;; - xbox) - basic_machine=i686-pc - basic_os=mingw32 - ;; - ymp) - basic_machine=ymp-cray - basic_os=unicos - ;; - *) - basic_machine=$1 - basic_os= - ;; - esac - ;; -esac - -# Decode 1-component or ad-hoc basic machines -case $basic_machine in - # Here we handle the default manufacturer of certain CPU types. It is in - # some cases the only manufacturer, in others, it is the most popular. - w89k) - cpu=hppa1.1 - vendor=winbond - ;; - op50n) - cpu=hppa1.1 - vendor=oki - ;; - op60c) - cpu=hppa1.1 - vendor=oki - ;; - ibm*) - cpu=i370 - vendor=ibm - ;; - orion105) - cpu=clipper - vendor=highlevel - ;; - mac | mpw | mac-mpw) - cpu=m68k - vendor=apple - ;; - pmac | pmac-mpw) - cpu=powerpc - vendor=apple - ;; - - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - cpu=m68000 - vendor=att - ;; - 3b*) - cpu=we32k - vendor=att - ;; - bluegene*) - cpu=powerpc - vendor=ibm - basic_os=cnk - ;; - decsystem10* | dec10*) - cpu=pdp10 - vendor=dec - basic_os=tops10 - ;; - decsystem20* | dec20*) - cpu=pdp10 - vendor=dec - basic_os=tops20 - ;; - delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300) - cpu=m68k - vendor=motorola - ;; - # This used to be dpx2*, but that gets the RS6000-based - # DPX/20 and the x86-based DPX/2-100 wrong. See - # https://oldskool.silicium.org/stations/bull_dpx20.htm - # https://www.feb-patrimoine.com/english/bull_dpx2.htm - # https://www.feb-patrimoine.com/english/unix_and_bull.htm - dpx2 | dpx2[23]00 | dpx2[23]xx) - cpu=m68k - vendor=bull - ;; - dpx2100 | dpx21xx) - cpu=i386 - vendor=bull - ;; - dpx20) - cpu=rs6000 - vendor=bull - ;; - encore | umax | mmax) - cpu=ns32k - vendor=encore - ;; - elxsi) - cpu=elxsi - vendor=elxsi - basic_os=${basic_os:-bsd} - ;; - fx2800) - cpu=i860 - vendor=alliant - ;; - genix) - cpu=ns32k - vendor=ns - ;; - h3050r* | hiux*) - cpu=hppa1.1 - vendor=hitachi - basic_os=hiuxwe2 - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - cpu=hppa1.0 - vendor=hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - cpu=m68000 - vendor=hp - ;; - hp9k3[2-9][0-9]) - cpu=m68k - vendor=hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - cpu=hppa1.0 - vendor=hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - cpu=hppa1.1 - vendor=hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - cpu=hppa1.1 - vendor=hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - cpu=hppa1.1 - vendor=hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - cpu=hppa1.1 - vendor=hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - cpu=hppa1.0 - vendor=hp - ;; - i*86v32) - cpu=`echo "$1" | sed -e 's/86.*/86/'` - vendor=pc - basic_os=sysv32 - ;; - i*86v4*) - cpu=`echo "$1" | sed -e 's/86.*/86/'` - vendor=pc - basic_os=sysv4 - ;; - i*86v) - cpu=`echo "$1" | sed -e 's/86.*/86/'` - vendor=pc - basic_os=sysv - ;; - i*86sol2) - cpu=`echo "$1" | sed -e 's/86.*/86/'` - vendor=pc - basic_os=solaris2 - ;; - j90 | j90-cray) - cpu=j90 - vendor=cray - basic_os=${basic_os:-unicos} - ;; - iris | iris4d) - cpu=mips - vendor=sgi - case $basic_os in - irix*) - ;; - *) - basic_os=irix4 - ;; - esac - ;; - miniframe) - cpu=m68000 - vendor=convergent - ;; - *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) - cpu=m68k - vendor=atari - basic_os=mint - ;; - news-3600 | risc-news) - cpu=mips - vendor=sony - basic_os=newsos - ;; - next | m*-next) - cpu=m68k - vendor=next - ;; - np1) - cpu=np1 - vendor=gould - ;; - op50n-* | op60c-*) - cpu=hppa1.1 - vendor=oki - basic_os=proelf - ;; - pa-hitachi) - cpu=hppa1.1 - vendor=hitachi - basic_os=hiuxwe2 - ;; - pbd) - cpu=sparc - vendor=tti - ;; - pbb) - cpu=m68k - vendor=tti - ;; - pc532) - cpu=ns32k - vendor=pc532 - ;; - pn) - cpu=pn - vendor=gould - ;; - power) - cpu=power - vendor=ibm - ;; - ps2) - cpu=i386 - vendor=ibm - ;; - rm[46]00) - cpu=mips - vendor=siemens - ;; - rtpc | rtpc-*) - cpu=romp - vendor=ibm - ;; - sde) - cpu=mipsisa32 - vendor=sde - basic_os=${basic_os:-elf} - ;; - simso-wrs) - cpu=sparclite - vendor=wrs - basic_os=vxworks - ;; - tower | tower-32) - cpu=m68k - vendor=ncr - ;; - vpp*|vx|vx-*) - cpu=f301 - vendor=fujitsu - ;; - w65) - cpu=w65 - vendor=wdc - ;; - w89k-*) - cpu=hppa1.1 - vendor=winbond - basic_os=proelf - ;; - none) - cpu=none - vendor=none - ;; - leon|leon[3-9]) - cpu=sparc - vendor=$basic_machine - ;; - leon-*|leon[3-9]-*) - cpu=sparc - vendor=`echo "$basic_machine" | sed 's/-.*//'` - ;; - - *-*) - saved_IFS=$IFS - IFS="-" read cpu vendor <&2 - exit 1 - ;; - esac - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $vendor in - digital*) - vendor=dec - ;; - commodore*) - vendor=cbm - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if test x"$basic_os" != x -then - -# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just -# set os. -obj= -case $basic_os in - gnu/linux*) - kernel=linux - os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` - ;; - os2-emx) - kernel=os2 - os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` - ;; - nto-qnx*) - kernel=nto - os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` - ;; - *-*) - saved_IFS=$IFS - IFS="-" read kernel os <&2 - fi - ;; - *) - echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 - exit 1 - ;; -esac - -case $obj in - aout* | coff* | elf* | pe*) - ;; - '') - # empty is fine - ;; - *) - echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 - exit 1 - ;; -esac - -# Here we handle the constraint that a (synthetic) cpu and os are -# valid only in combination with each other and nowhere else. -case $cpu-$os in - # The "javascript-unknown-ghcjs" triple is used by GHC; we - # accept it here in order to tolerate that, but reject any - # variations. - javascript-ghcjs) - ;; - javascript-* | *-ghcjs) - echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 - exit 1 - ;; -esac - -# As a final step for OS-related things, validate the OS-kernel combination -# (given a valid OS), if there is a kernel. -case $kernel-$os-$obj in - linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ - | linux-mlibc*- | linux-musl*- | linux-newlib*- \ - | linux-relibc*- | linux-uclibc*- | linux-ohos*- ) - ;; - uclinux-uclibc*- | uclinux-gnu*- ) - ;; - managarm-mlibc*- | managarm-kernel*- ) - ;; - windows*-msvc*-) - ;; - -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ - | -uclibc*- ) - # These are just libc implementations, not actual OSes, and thus - # require a kernel. - echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 - exit 1 - ;; - -kernel*- ) - echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 - exit 1 - ;; - *-kernel*- ) - echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 - exit 1 - ;; - *-msvc*- ) - echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 - exit 1 - ;; - kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-) - ;; - vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) - ;; - nto-qnx*-) - ;; - os2-emx-) - ;; - rtmk-nova-) - ;; - *-eabi*- | *-gnueabi*-) - ;; - none--*) - # None (no kernel, i.e. freestanding / bare metal), - # can be paired with an machine code file format - ;; - -*-) - # Blank kernel with real OS is always fine. - ;; - --*) - # Blank kernel and OS with real machine code file format is always fine. - ;; - *-*-*) - echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 - exit 1 - ;; -esac - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -case $vendor in - unknown) - case $cpu-$os in - *-riscix*) - vendor=acorn - ;; - *-sunos* | *-solaris*) - vendor=sun - ;; - *-cnk* | *-aix*) - vendor=ibm - ;; - *-beos*) - vendor=be - ;; - *-hpux*) - vendor=hp - ;; - *-mpeix*) - vendor=hp - ;; - *-hiux*) - vendor=hitachi - ;; - *-unos*) - vendor=crds - ;; - *-dgux*) - vendor=dg - ;; - *-luna*) - vendor=omron - ;; - *-genix*) - vendor=ns - ;; - *-clix*) - vendor=intergraph - ;; - *-mvs* | *-opened*) - vendor=ibm - ;; - *-os400*) - vendor=ibm - ;; - s390-* | s390x-*) - vendor=ibm - ;; - *-ptx*) - vendor=sequent - ;; - *-tpf*) - vendor=ibm - ;; - *-vxsim* | *-vxworks* | *-windiss*) - vendor=wrs - ;; - *-aux*) - vendor=apple - ;; - *-hms*) - vendor=hitachi - ;; - *-mpw* | *-macos*) - vendor=apple - ;; - *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) - vendor=atari - ;; - *-vos*) - vendor=stratus - ;; - esac - ;; -esac - -echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" -exit - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/experiments/wasm-gui/third_party/libXext/configure b/experiments/wasm-gui/third_party/libXext/configure deleted file mode 100755 index c09a698cd..000000000 --- a/experiments/wasm-gui/third_party/libXext/configure +++ /dev/null @@ -1,24110 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.73 for libXext 1.3.7. -# -# Report bugs to . -# -# -# Copyright (C) 1992-1996, 1998-2017, 2020-2026 Free Software Foundation, -# Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in #( - e) case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $# in # (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else case e in #( - e) case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ) -then : - -else case e in #( - e) exitcode=1; echo positional parameters were not saved. ;; -esac -fi -test x\$exitcode = x0 || exit 1 -blah=\$(echo \$(echo blah)) -test x\"\$blah\" = xblah || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 - - test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ - || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null -then : - as_have_required=yes -else case e in #( - e) as_have_required=no ;; -esac -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null -then : - -else case e in #( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$as_shell as_have_required=yes - if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null -then : - break 2 -fi -fi - done;; - esac - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in #( - e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi ;; -esac -fi - - - if test "x$CONFIG_SHELL" != x -then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -case $# in # (( - 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; - *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; -esac -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno -then : - printf '%s\n' "$0: This script requires a shell more modern than all" - printf '%s\n' "$0: the shells that I found on your system." - if test ${ZSH_VERSION+y} ; then - printf '%s\n' "$0: In particular, zsh $ZSH_VERSION has bugs and should" - printf '%s\n' "$0: be upgraded to zsh 4.3.4 or later." - else - printf '%s\n' "$0: Please tell bug-autoconf@gnu.org and -$0: https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi ;; -esac -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in #( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in #( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - t clear - :clear - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { printf '%s\n' "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - -SHELL=${CONFIG_SHELL-/bin/sh} - -as_awk_strverscmp=' - # Use only awk features that work with 7th edition Unix awk (1978). - # My, what an old awk you have, Mr. Solaris! - END { - while (length(v1) && length(v2)) { - # Set d1 to be the next thing to compare from v1, and likewise for d2. - # Normally this is a single character, but if v1 and v2 contain digits, - # compare them as integers and fractions as strverscmp does. - if (v1 ~ /^[0-9]/ && v2 ~ /^[0-9]/) { - # Split v1 and v2 into their leading digit string components d1 and d2, - # and advance v1 and v2 past the leading digit strings. - for (len1 = 1; substr(v1, len1 + 1) ~ /^[0-9]/; len1++) continue - for (len2 = 1; substr(v2, len2 + 1) ~ /^[0-9]/; len2++) continue - d1 = substr(v1, 1, len1); v1 = substr(v1, len1 + 1) - d2 = substr(v2, 1, len2); v2 = substr(v2, len2 + 1) - if (d1 ~ /^0/) { - if (d2 ~ /^0/) { - # Compare two fractions. - while (d1 ~ /^0/ && d2 ~ /^0/) { - d1 = substr(d1, 2); len1-- - d2 = substr(d2, 2); len2-- - } - if (len1 != len2 && ! (len1 && len2 && substr(d1, 1, 1) == substr(d2, 1, 1))) { - # The two components differ in length, and the common prefix - # contains only leading zeros. Consider the longer to be less. - d1 = -len1 - d2 = -len2 - } else { - # Otherwise, compare as strings. - d1 = "x" d1 - d2 = "x" d2 - } - } else { - # A fraction is less than an integer. - exit 1 - } - } else { - if (d2 ~ /^0/) { - # An integer is greater than a fraction. - exit 2 - } else { - # Compare two integers. - d1 += 0 - d2 += 0 - } - } - } else { - # The normal case, without worrying about digits. - d1 = substr(v1, 1, 1); v1 = substr(v1, 2) - d2 = substr(v2, 1, 1); v2 = substr(v2, 2) - } - if (d1 < d2) exit 1 - if (d1 > d2) exit 2 - } - # Beware Solaris 11 /usr/xgp4/bin/awk, which mishandles some - # comparisons of empty strings to integers. For example, - # LC_ALL=C /usr/xpg4/bin/awk "BEGIN {if (-1 < \"\") print \"a\"}" - # prints "a". - if (length(v2)) exit 1 - if (length(v1)) exit 2 - } -' - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_CONFIG_STATUS= -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='libXext' -PACKAGE_TARNAME='libXext' -PACKAGE_VERSION='1.3.7' -PACKAGE_STRING='libXext 1.3.7' -PACKAGE_BUGREPORT='https://gitlab.freedesktop.org/xorg/lib/libxext/-/issues' -PACKAGE_URL='' - -ac_unique_file="Makefile.am" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_STDIO_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_header_c_list= -ac_subst_vars='am__EXEEXT_FALSE -am__EXEEXT_TRUE -LTLIBOBJS -MAKE_LINT_LIB_FALSE -MAKE_LINT_LIB_TRUE -LINTLIB -LINT_FALSE -LINT_TRUE -LINT_FLAGS -LINT -LIBOBJS -XEXT_LIBS -XEXT_CFLAGS -XEXT_SOREV -XTMALLOC_ZERO_CFLAGS -XMALLOC_ZERO_CFLAGS -MALLOC_ZERO_CFLAGS -HAVE_STYLESHEETS_FALSE -HAVE_STYLESHEETS_TRUE -XSL_STYLESHEET -STYLESHEET_SRCDIR -XORG_SGML_PATH -HAVE_XSLTPROC_FALSE -HAVE_XSLTPROC_TRUE -XSLTPROC -HAVE_FOP_FALSE -HAVE_FOP_TRUE -FOP -HAVE_XMLTO_FALSE -HAVE_XMLTO_TRUE -HAVE_XMLTO_TEXT_FALSE -HAVE_XMLTO_TEXT_TRUE -XMLTO -ENABLE_SPECS_FALSE -ENABLE_SPECS_TRUE -MAN_SUBSTS -XORG_MAN_PAGE -ADMIN_MAN_DIR -DRIVER_MAN_DIR -MISC_MAN_DIR -FILE_MAN_DIR -LIB_MAN_DIR -APP_MAN_DIR -ADMIN_MAN_SUFFIX -DRIVER_MAN_SUFFIX -MISC_MAN_SUFFIX -FILE_MAN_SUFFIX -LIB_MAN_SUFFIX -APP_MAN_SUFFIX -INSTALL_CMD -PKG_CONFIG_LIBDIR -PKG_CONFIG_PATH -PKG_CONFIG -CHANGELOG_CMD -STRICT_CFLAGS -CWARNFLAGS -BASE_CFLAGS -LT_SYS_LIBRARY_PATH -OTOOL64 -OTOOL -LIPO -NMEDIT -DSYMUTIL -MANIFEST_TOOL -RANLIB -ac_ct_AR -AR -DLLTOOL -OBJDUMP -FILECMD -LN_S -NM -ac_ct_DUMPBIN -DUMPBIN -LD -FGREP -EGREP -GREP -SED -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -LIBTOOL -am__xargs_n -am__rm_f_notfound -AM_BACKSLASH -AM_DEFAULT_VERBOSITY -AM_DEFAULT_V -AM_V -CSCOPE -ETAGS -CTAGS -am__fastdepCC_FALSE -am__fastdepCC_TRUE -CCDEPMODE -am__nodep -AMDEPBACKSLASH -AMDEP_FALSE -AMDEP_TRUE -am__include -DEPDIR -am__untar -am__tar -AMTAR -am__leading_dot -SET_MAKE -AWK -mkdir_p -MKDIR_P -INSTALL_STRIP_PROGRAM -STRIP -install_sh -MAKEINFO -AUTOHEADER -AUTOMAKE -AUTOCONF -ACLOCAL -VERSION -PACKAGE -CYGPATH_W -am__isrc -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -ECHO_T -ECHO_N -ECHO_C -target_alias -host_alias -build_alias -LIBS -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -runstatedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL -am__quote' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_dependency_tracking -enable_silent_rules -enable_shared -enable_static -enable_pic -with_pic -enable_fast_install -enable_aix_soname -with_aix_soname -with_gnu_ld -with_sysroot -enable_libtool_lock -enable_selective_werror -enable_strict_compilation -enable_specs -with_xmlto -with_fop -with_xsltproc -enable_malloc0returnsnull -with_lint -enable_lint_library -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -LT_SYS_LIBRARY_PATH -PKG_CONFIG -PKG_CONFIG_PATH -PKG_CONFIG_LIBDIR -XMLTO -FOP -XSLTPROC -XEXT_CFLAGS -XEXT_LIBS -LINT -LINT_FLAGS' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: '$ac_option' -Try '$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: '$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - printf '%s\n' "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - printf '%s\n' "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`printf '%s\n' $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: '$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -'configure' configures libXext 1.3.7 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print 'checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for '--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or '..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, 'make install' will install all the files in -'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify -an installation prefix other than '$ac_default_prefix' using '--prefix', -for instance '--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/libXext] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of libXext 1.3.7:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-dependency-tracking - do not reject slow dependency extractors - --disable-dependency-tracking - speeds up one-time build - --enable-silent-rules less verbose build output (undo: "make V=1") - --disable-silent-rules verbose build output (undo: "make V=0") - --enable-shared[=PKGS] build shared libraries [default=yes] - --enable-static[=PKGS] build static libraries [default=yes] - --enable-pic[=PKGS] try to use only PIC/non-PIC objects [default=use - both] - --enable-fast-install[=PKGS] - optimize for fast installation [default=yes] - --enable-aix-soname=aix|svr4|both - shared library versioning (aka "SONAME") variant to - provide on AIX, [default=aix]. - --disable-libtool-lock avoid locking (might break parallel builds) - --disable-selective-werror - Turn off selective compiler errors. (default: - enabled) - --enable-strict-compilation - Enable all warnings from compiler and make them - errors (default: disabled) - --enable-specs Enable building the specs (default: yes) - --enable-malloc0returnsnull - assume malloc(0) can return NULL (default: yes) - --enable-lint-library Create lint library (default: disabled) - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-sysroot[=DIR] Search for dependent libraries within DIR (or the - compiler's sysroot if not specified). - --with-xmlto Use xmlto to regenerate documentation (default: - auto) - --with-fop Use fop to regenerate documentation (default: auto) - --with-xsltproc Use xsltproc for the transformation of XML documents - (default: auto) - --with-lint Use a lint-style source code checker (default: - disabled) - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - LT_SYS_LIBRARY_PATH - User-defined run-time library search path. - PKG_CONFIG path to pkg-config utility - PKG_CONFIG_PATH - directories to add to pkg-config's search path - PKG_CONFIG_LIBDIR - path overriding pkg-config's built-in search path - XMLTO Path to xmlto command - FOP Path to fop command - XSLTPROC Path to xsltproc command - XEXT_CFLAGS C compiler flags for XEXT, overriding pkg-config - XEXT_LIBS linker flags for XEXT, overriding pkg-config - LINT Path to a lint-style command - LINT_FLAGS Flags for the lint-style command - -Use these variables to override the choices made by 'configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for configure.gnu first; this name is used for a wrapper for - # Metaconfig's "Configure" on case-insensitive file systems. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - printf '%s\n' "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -libXext configure 1.3.7 -generated by GNU Autoconf 2.73 - -Copyright (C) 2026 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else case e in #( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in #( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - } -then : - ac_retval=0 -else case e in #( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (void); below. */ - -#include -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (void); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main (void) -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$3=yes" -else case e in #( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func - -# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR -# ------------------------------------------------------------------ -# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. -ac_fn_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -printf %s "checking whether $as_decl_name is declared... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - eval ac_save_FLAGS=\$$6 - as_fn_append $6 " $5" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main (void) -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in #( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - eval $6=\$ac_save_FLAGS - ;; -esac -fi -eval ac_res=\$$3 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf '%s\n' "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_check_decl -ac_configure_args_raw= -for ac_arg -do - case $ac_arg in - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_configure_args_raw " '$ac_arg'" -done - -case $ac_configure_args_raw in - *$as_nl*) - ac_safe_unquote= ;; - *) - ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. - ac_unsafe_a="$ac_unsafe_z#~" - ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" - ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; -esac - -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - $ $0$ac_configure_args_raw - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - printf '%s\n' "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# Dump the cache to stdout. It can be in a pipe (this is a requirement). -ac_cache_dump () -{ - # The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf '%s\n' "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # 'set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # 'set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) -} - -# Print debugging info to stdout. -ac_dump_debugging_info () -{ - echo - - printf '%s\n' "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - ac_cache_dump - echo - - printf '%s\n' "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - - if test -n "$ac_subst_files"; then - printf '%s\n' "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; - esac - printf '%s\n' "$ac_var='$ac_val'" - done | sort - echo - fi - - if test -s confdefs.h; then - printf '%s\n' "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - printf '%s\n' "$as_me: caught signal $ac_signal" - printf '%s\n' "$as_me: exit $exit_status" -} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. -ac_exit_trap () -{ - exit_status= - # Sanitize IFS. - IFS=" "" $as_nl" - # Save into config.log some information that might help in debugging. - ac_dump_debugging_info >&5 - eval "rm -f $ac_clean_CONFIG_STATUS core *.core core.conftest.*" && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -} - -trap 'ac_exit_trap $?' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -printf '%s\n' "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -printf '%s\n' "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h - -printf '%s\n' "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h - -printf '%s\n' "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h - -printf '%s\n' "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h - -printf '%s\n' "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h - -printf '%s\n' "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -if test -n "$CONFIG_SITE"; then - ac_site_files="$CONFIG_SITE" -elif test "x$prefix" != xNONE; then - ac_site_files="$prefix/share/config.site $prefix/etc/config.site" -else - ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" -fi - -for ac_site_file in $ac_site_files -do - case $ac_site_file in #( - */*) : - ;; #( - *) : - ac_site_file=./$ac_site_file ;; -esac - if test -f "$ac_site_file" && test -r "$ac_site_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -printf '%s\n' "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See 'config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -printf '%s\n' "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -printf '%s\n' "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" -# Test code for whether the C compiler supports C23 (global declarations) -ac_c_conftest_c23_globals=' -/* Does the compiler advertise conformance to C17 or earlier? - Although GCC 14 does not do that, even with -std=gnu23, - it is close enough, and defines __STDC_VERSION == 202000L. */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ <= 201710L -# error "Compiler advertises conformance to C17 or earlier" -#endif - -// Check alignas. -char alignas (double) c23_aligned_as_double; -char alignas (0) c23_no_special_alignment; -extern char c23_aligned_as_int; -char alignas (0) alignas (int) c23_aligned_as_int; - -// Check alignof. -enum -{ - c23_int_alignment = alignof (int), - c23_int_array_alignment = alignof (int[100]), - c23_char_alignment = alignof (char) -}; -static_assert (0 < -alignof (int), "alignof is signed"); - -int function_with_unnamed_parameter (int) { return 0; } - -void c23_noreturn (); - -/* Test parsing of string and char UTF-8 literals (including hex escapes). - The parens pacify GCC 15. */ -bool use_u8 = (!sizeof u8"\xFF") == (!u8'\''x'\''); - -bool check_that_bool_works = true | false | !nullptr; -#if !true -# error "true does not work in #if" -#endif -#if false -#elifdef __STDC_VERSION__ -#else -# error "#elifdef does not work" -#endif - -#ifndef __has_c_attribute -# error "__has_c_attribute not defined" -#endif - -#ifndef __has_include -# error "__has_include not defined" -#endif - -#define LPAREN() ( -#define FORTY_TWO(x) 42 -#define VA_OPT_TEST(r, x, ...) __VA_OPT__ (FORTY_TWO r x)) -static_assert (VA_OPT_TEST (LPAREN (), 0, <:-) == 42); - -static_assert (0b101010 == 42); -static_assert (0B101010 == 42); -static_assert (0xDEAD'\''BEEF == 3'\''735'\''928'\''559); -static_assert (0.500'\''000'\''000 == 0.5); - -enum unsignedish : unsigned int { uione = 1 }; -static_assert (0 < -uione); - -#include -constexpr nullptr_t null_pointer = nullptr; - -static typeof (1 + 1L) two () { return 2; } -static long int three () { return 3; } -' - -# Test code for whether the C compiler supports C23 (body of main). -ac_c_conftest_c23_main=' - { - label_before_declaration: - int arr[10] = {}; - if (arr[0]) - goto label_before_declaration; - if (!arr[0]) - goto label_at_end_of_block; - label_at_end_of_block: - } - ok |= !null_pointer; - ok |= two != three; -' - -# Test code for whether the C compiler supports C23 (complete). -ac_c_conftest_c23_program="${ac_c_conftest_c23_globals} - -int -main (int, char **) -{ - int ok = 0; - ${ac_c_conftest_c23_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (global declarations) -ac_c_conftest_c89_globals=' -/* Do not test the value of __STDC__, because some compilers define it to 0 - or do not define it, while otherwise adequately conforming. */ - -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ -struct buf { int x; }; -struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (char **p, int i) -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* C89 style stringification. */ -#define noexpand_stringify(a) #a -const char *stringified = noexpand_stringify(arbitrary+token=sequence); - -/* C89 style token pasting. Exercises some of the corner cases that - e.g. old MSVC gets wrong, but not very hard. */ -#define noexpand_concat(a,b) a##b -#define expand_concat(a,b) noexpand_concat(a,b) -extern int vA; -extern int vbee; -#define aye A -#define bee B -int *pvA = &expand_concat(v,aye); -int *pvbee = &noexpand_concat(v,bee); - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not \xHH hex character constants. - These do not provoke an error unfortunately, instead are silently treated - as an "x". The following induces an error, until -std is added to get - proper ANSI mode. Curiously \x00 != x always comes out true, for an - array size at least. It is necessary to write \x00 == 0 to get something - that is true only with -std. */ -int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) '\''x'\'' -int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), - int, int);' - -# Test code for whether the C compiler supports C89 (body of main). -ac_c_conftest_c89_main=' -ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); -' - -# Test code for whether the C compiler supports C99 (global declarations) -ac_c_conftest_c99_globals=' -/* Does the compiler advertise C99 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# error "Compiler does not advertise C99 conformance" -#endif - -// See if C++-style comments work. - -#include -extern int puts (const char *); -extern int printf (const char *, ...); -extern int dprintf (int, const char *, ...); -extern void *malloc (size_t); -extern void free (void *); - -// Check varargs macros. These examples are taken from C99 6.10.3.5. -// dprintf is used instead of fprintf to avoid needing to declare -// FILE and stderr, and "aND" is used instead of "and" to work around -// GCC bug 40564 which is irrelevant here. -#define debug(...) dprintf (2, __VA_ARGS__) -#define showlist(...) puts (#__VA_ARGS__) -#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) -static void -test_varargs_macros (void) -{ - int x = 1234; - int y = 5678; - debug ("Flag"); - debug ("X = %d\n", x); - showlist (The first, second, aND third items.); - report (x>y, "x is %d but y is %d", x, y); -} - -// Check long long types. -#define BIG64 18446744073709551615ull -#define BIG32 4294967295ul -#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) -#if !BIG_OK - #error "your preprocessor is broken" -#endif -#if BIG_OK -#else - #error "your preprocessor is broken" -#endif -static long long int bignum = -9223372036854775807LL; -static unsigned long long int ubignum = BIG64; - -struct incomplete_array -{ - int datasize; - double data[]; -}; - -struct named_init { - int number; - const wchar_t *name; - double average; -}; - -typedef const char *ccp; - -static inline int -test_restrict (ccp restrict text) -{ - // Iterate through items via the restricted pointer. - // Also check for declarations in for loops. - for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) - continue; - return 0; -} - -// Check varargs and va_copy. -static bool -test_varargs (const char *format, ...) -{ - va_list args; - va_start (args, format); - va_list args_copy; - va_copy (args_copy, args); - - const char *str = ""; - int number = 0; - float fnumber = 0; - - while (*format) - { - switch (*format++) - { - case '\''s'\'': // string - str = va_arg (args_copy, const char *); - break; - case '\''d'\'': // int - number = va_arg (args_copy, int); - break; - case '\''f'\'': // float - fnumber = va_arg (args_copy, double); - break; - default: - break; - } - } - va_end (args_copy); - va_end (args); - - return *str && number && fnumber; -} -' - -# Test code for whether the C compiler supports C99 (body of main). -ac_c_conftest_c99_main=' - // Check bool. - _Bool success = false; - success |= (argc != 0); - - // Check restrict. - if (test_restrict ("String literal") == 0) - success = true; - const char *restrict newvar = "Another string"; - - // Check varargs. - success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); - test_varargs_macros (); - - // Check flexible array members. - static struct incomplete_array *volatile incomplete_array_pointer; - struct incomplete_array *ia = incomplete_array_pointer; - ia->datasize = 10; - for (int i = 0; i < ia->datasize; ++i) - ia->data[i] = i * 1.234; - // Work around memory leak warnings. - free (ia); - - // Check named initializers. - struct named_init ni = { - .number = 34, - .name = L"Test wide string", - .average = 543.34343, - }; - - ni.number = 58; - - // Do not test for VLAs, as some otherwise-conforming compilers lack them. - // C code should instead use __STDC_NO_VLA__; see Autoconf manual. - - // work around unused variable warnings - ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' - || ni.number != 58); -' - -# Test code for whether the C compiler supports C11 (global declarations) -ac_c_conftest_c11_globals=' -/* Does the compiler advertise C11 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L -# error "Compiler does not advertise C11 conformance" -#endif - -// Check _Alignas. -char _Alignas (double) aligned_as_double; -char _Alignas (0) no_special_alignment; -extern char aligned_as_int; -char _Alignas (0) _Alignas (int) aligned_as_int; - -// Check _Alignof. -enum -{ - int_alignment = _Alignof (int), - int_array_alignment = _Alignof (int[100]), - char_alignment = _Alignof (char) -}; -_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); - -// Check _Noreturn. -int _Noreturn does_not_return (void) { for (;;) continue; } - -// Check _Static_assert. -struct test_static_assert -{ - int x; - _Static_assert (sizeof (int) <= sizeof (long int), - "_Static_assert does not work in struct"); - long int y; -}; - -// Check UTF-8 literals. -#define u8 syntax error! -char const utf8_literal[] = u8"happens to be ASCII" "another string"; - -// Check duplicate typedefs. -typedef long *long_ptr; -typedef long int *long_ptr; -typedef long_ptr long_ptr; - -// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. -struct anonymous -{ - union { - struct { int i; int j; }; - struct { int k; long int l; } w; - }; - int m; -} v1; -' - -# Test code for whether the C compiler supports C11 (body of main). -ac_c_conftest_c11_main=' - _Static_assert ((offsetof (struct anonymous, i) - == offsetof (struct anonymous, w.k)), - "Anonymous union alignment botch"); - v1.i = 2; - v1.w.k = 5; - ok |= v1.i != 5; -' - -# Test code for whether the C compiler supports C11 (complete). -ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} -${ac_c_conftest_c11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - ${ac_c_conftest_c11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C99 (complete). -ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (complete). -ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - return ok; -} -" - -as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" -as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" -as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" -as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" -as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" -as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" -as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" -as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" -as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" -as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" - -# Auxiliary files required by this configure script. -ac_aux_files="config.guess config.sub ltmain.sh missing install-sh compile" - -# Locations in which to look for auxiliary files. -ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." - -# Search for a directory containing all of the required auxiliary files, -# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. -# If we don't find one directory that contains all the files we need, -# we report the set of missing files from the *first* directory in -# $ac_aux_dir_candidates and give up. -ac_missing_aux_files="" -ac_first_candidate=: -printf '%s\n' "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in $ac_aux_dir_candidates -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - - printf '%s\n' "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 - ac_aux_dir_found=yes - ac_install_sh= - for ac_aux in $ac_aux_files - do - # As a special case, if "install-sh" is required, that requirement - # can be satisfied by any of "install-sh", "install.sh", or "shtool", - # and $ac_install_sh is set appropriately for whichever one is found. - if test x"$ac_aux" = x"install-sh" - then - if test -f "${as_dir}install-sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 - ac_install_sh="${as_dir}install-sh -c" - elif test -f "${as_dir}install.sh"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 - ac_install_sh="${as_dir}install.sh -c" - elif test -f "${as_dir}shtool"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 - ac_install_sh="${as_dir}shtool install -c" - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} install-sh" - else - break - fi - fi - else - if test -f "${as_dir}${ac_aux}"; then - printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" - else - break - fi - fi - fi - done - if test "$ac_aux_dir_found" = yes; then - ac_aux_dir="$as_dir" - break - fi - ac_first_candidate=false - - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in #( - e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; -esac -fi - - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -if test -f "${ac_aux_dir}config.guess"; then - ac_config_guess="$SHELL ${ac_aux_dir}config.guess" -fi -if test -f "${ac_aux_dir}config.sub"; then - ac_config_sub="$SHELL ${ac_aux_dir}config.sub" -fi -if test -f "$ac_aux_dir/configure"; then - ac_configure="$SHELL ${ac_aux_dir}configure" -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 -printf '%s\n' "$as_me: error: '$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w= - for ac_val in x $ac_old_val; do - ac_old_val_w="$ac_old_val_w $ac_val" - done - ac_new_val_w= - for ac_val in x $ac_new_val; do - ac_new_val_w="$ac_new_val_w $ac_val" - done - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 -printf '%s\n' "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 -printf '%s\n' "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 -printf '%s\n' "$as_me: former value: '$ac_old_val'" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 -printf '%s\n' "$as_me: current value: '$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`printf '%s\n' "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -printf '%s\n' "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' - and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers config.h" - - - -# Set common system defines for POSIX extensions, such as _GNU_SOURCE -# Must be called before any macros that run the compiler (like LT_INIT) -# to avoid autoconf errors. - - - - - - - - - - - - - - -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" - fi -fi -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. -set dummy ${ac_tool_prefix}clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf '%s\n' "$CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "clang", so it can be a program name with args. -set dummy clang; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="clang" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf '%s\n' "$ac_ct_CC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -fi - - -test -z "$CC" && { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See 'config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion -version; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -printf %s "checking whether the C compiler works... " >&6; } -ac_link_default=`printf '%s\n' "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. -# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an '-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else case e in #( - e) ac_file='' ;; -esac -fi -if test -z "$ac_file" -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See 'config.log' for more details" "$LINENO" 5; } -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -printf %s "checking for C compiler default output file name... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -printf '%s\n' "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -printf %s "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) -# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will -# work properly (i.e., refer to 'conftest.exe'), while it won't with -# 'rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else case e in #( - e) { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest conftest$ac_cv_exeext -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -printf '%s\n' "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -FILE *f = fopen ("conftest.out", "w"); - if (!f) - return 1; - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -printf %s "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use '--host'. -See 'config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -printf '%s\n' "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext \ - conftest.o conftest.obj conftest.out -ac_clean_files=$ac_clean_files_save -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -printf %s "checking for suffix of object files... " >&6; } -if test ${ac_cv_objext+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf '%s\n' "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else case e in #( - e) printf '%s\n' "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -printf '%s\n' "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 -printf %s "checking whether the compiler supports GNU C... " >&6; } -if test ${ac_cv_c_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else case e in #( - e) ac_compiler_gnu=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -printf '%s\n' "$ac_cv_c_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+y} -ac_save_CFLAGS=$CFLAGS -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -printf %s "checking whether $CC accepts -g... " >&6; } -if test ${ac_cv_prog_cc_g+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -else case e in #( - e) CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in #( - e) ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -printf '%s\n' "$ac_cv_prog_cc_g" >&6; } -if test $ac_test_CFLAGS; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -ac_prog_cc_stdc=no -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C23 features" >&5 -printf %s "checking for $CC option to enable C23 features... " >&6; } -if test ${ac_cv_prog_cc_c23+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c23=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c23_program -_ACEOF -for ac_arg in '' -std=gnu23 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c23=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c23" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c23" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c23" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c23" >&5 -printf '%s\n' "$ac_cv_prog_cc_c23" >&6; } - CC="$CC $ac_cv_prog_cc_c23" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c23 - ac_prog_cc_stdc=c23 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 -printf %s "checking for $CC option to enable C11 features... " >&6; } -if test ${ac_cv_prog_cc_c11+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c11=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c11_program -_ACEOF -for ac_arg in '' -std=gnu11 -std:c11 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c11" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c11" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c11" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -printf '%s\n' "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } -if test ${ac_cv_prog_cc_c99+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c99=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c99=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c99" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c99" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c99" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -printf '%s\n' "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 -printf %s "checking for $CC option to enable C89 features... " >&6; } -if test ${ac_cv_prog_cc_c89+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c89_program -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c89" = xno -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf '%s\n' "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c89" = x -then : - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf '%s\n' "none needed" >&6; } -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -printf '%s\n' "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 ;; -esac -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -printf %s "checking whether $CC understands -c and -o together... " >&6; } -if test ${am_cv_prog_cc_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - # aligned with autoconf, so not including core; see bug#72225. - rm -f -r a.out a.exe b.out conftest.$ac_ext conftest.$ac_objext \ - conftest.dSYM conftest1.$ac_ext conftest1.$ac_objext conftest1.dSYM \ - conftest2.$ac_ext conftest2.$ac_objext conftest2.dSYM - unset am_i ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -printf '%s\n' "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_header= ac_cache= -for ac_item in $ac_header_c_list -do - if test $ac_cache; then - ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" - if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf '%s\n' "#define $ac_item 1" >> confdefs.h - fi - ac_header= ac_cache= - elif test $ac_header; then - ac_cache=$ac_item - else - ac_header=$ac_item - fi -done - - - - - - - - -if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes -then : - -printf '%s\n' "#define STDC_HEADERS 1" >>confdefs.h - -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 -printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test ${ac_cv_safe_to_define___extensions__+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -# define __EXTENSIONS__ 1 - $ac_includes_default -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_safe_to_define___extensions__=yes -else case e in #( - e) ac_cv_safe_to_define___extensions__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -printf '%s\n' "$ac_cv_safe_to_define___extensions__" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 -printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } -if test ${ac_cv_should_define__xopen_source+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_should_define__xopen_source=no - if test $ac_cv_header_wchar_h = yes -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #define _XOPEN_SOURCE 500 - #include - mbstate_t x; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_should_define__xopen_source=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 -printf '%s\n' "$ac_cv_should_define__xopen_source" >&6; } - - printf '%s\n' "#define _ALL_SOURCE 1" >>confdefs.h - - printf '%s\n' "#define _COSMO_SOURCE 1" >>confdefs.h - - printf '%s\n' "#define _DARWIN_C_SOURCE 1" >>confdefs.h - - printf '%s\n' "#define _GNU_SOURCE 1" >>confdefs.h - - printf '%s\n' "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h - - printf '%s\n' "#define _NETBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "#define _OPENBSD_SOURCE 1" >>confdefs.h - - printf '%s\n' "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - - printf '%s\n' "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h - - printf '%s\n' "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h - - printf '%s\n' "#define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h - - printf '%s\n' "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h - - printf '%s\n' "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h - - printf '%s\n' "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h - - printf '%s\n' "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h - - printf '%s\n' "#define _TANDEM_SOURCE 1" >>confdefs.h - - if test $ac_cv_header_minix_config_h = yes -then : - MINIX=yes - printf '%s\n' "#define _MINIX 1" >>confdefs.h - - printf '%s\n' "#define _POSIX_SOURCE 1" >>confdefs.h - - printf '%s\n' "#define _POSIX_1_SOURCE 2" >>confdefs.h - -else case e in #( - e) MINIX= ;; -esac -fi - if test $ac_cv_safe_to_define___extensions__ = yes -then : - printf '%s\n' "#define __EXTENSIONS__ 1" >>confdefs.h - -fi - if test $ac_cv_should_define__xopen_source = yes -then : - printf '%s\n' "#define _XOPEN_SOURCE 500" >>confdefs.h - -fi - - -# Initialize Automake -am__api_version='1.18' - - - # Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -printf %s "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if test ${ac_cv_path_install+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - # Account for fact that we put trailing slashes in our PATH walk. -case $as_dir in #(( - ./ | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF/1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF/1 since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - ;; -esac -fi - if test ${ac_cv_path_install+y}; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -printf '%s\n' "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5 -printf %s "checking whether sleep supports fractional seconds... " >&6; } -if test ${am_cv_sleep_fractional_seconds+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if sleep 0.001 2>/dev/null -then : - am_cv_sleep_fractional_seconds=yes -else case e in #( - e) am_cv_sleep_fractional_seconds=no ;; -esac -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_sleep_fractional_seconds" >&5 -printf '%s\n' "$am_cv_sleep_fractional_seconds" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking filesystem timestamp resolution" >&5 -printf %s "checking filesystem timestamp resolution... " >&6; } -if test ${am_cv_filesystem_timestamp_resolution+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) # Default to the worst case. -am_cv_filesystem_timestamp_resolution=2 - -# Only try to go finer than 1 sec if sleep can do it. -# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, -# - 1 sec is not much of a win compared to 2 sec, and -# - it takes 2 seconds to perform the test whether 1 sec works. -# -# Instead, just use the default 2s on platforms that have 1s resolution, -# accept the extra 1s delay when using $sleep in the Automake tests, in -# exchange for not incurring the 2s delay for running the test for all -# packages. -# -am_try_resolutions= -if test "$am_cv_sleep_fractional_seconds" = yes; then - # Even a millisecond often causes a bunch of false positives, - # so just try a hundredth of a second. The time saved between .001 and - # .01 is not terribly consequential. - am_try_resolutions="0.01 0.1 $am_try_resolutions" -fi - -# In order to catch current-generation FAT out, we must *modify* files -# that already exist; the *creation* timestamp is finer. Use names -# that make ls -t sort them differently when they have equal -# timestamps than when they have distinct timestamps, keeping -# in mind that ls -t prints the *newest* file first. -rm -f conftest.ts? -: > conftest.ts1 -: > conftest.ts2 -: > conftest.ts3 - -# Make sure ls -t actually works. Do 'set' in a subshell so we don't -# clobber the current shell's arguments. (Outer-level square brackets -# are removed by m4; they're present so that m4 does not expand -# ; be careful, easy to get confused.) -if ( - set X `ls -t conftest.ts[12]` && - { - test "$*" != "X conftest.ts1 conftest.ts2" || - test "$*" != "X conftest.ts2 conftest.ts1"; - } -); then :; else - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - printf '%s\n' ""Bad output from ls -t: \"`ls -t conftest.ts[12]`\""" >&5 - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "ls -t produces unexpected output. -Make sure there is not a broken ls alias in your environment. -See 'config.log' for more details" "$LINENO" 5; } -fi - -for am_try_res in $am_try_resolutions; do - # Any one fine-grained sleep might happen to cross the boundary - # between two values of a coarser actual resolution, but if we do - # two fine-grained sleeps in a row, at least one of them will fall - # entirely within a coarse interval. - echo alpha > conftest.ts1 - sleep $am_try_res - echo beta > conftest.ts2 - sleep $am_try_res - echo gamma > conftest.ts3 - - # We assume that 'ls -t' will make use of high-resolution - # timestamps if the operating system supports them at all. - if (set X `ls -t conftest.ts?` && - test "$2" = conftest.ts3 && - test "$3" = conftest.ts2 && - test "$4" = conftest.ts1); then - # - # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, - # because we don't need to test make. - make_ok=true - if test $am_try_res != 1; then - # But if we've succeeded so far with a subsecond resolution, we - # have one more thing to check: make. It can happen that - # everything else supports the subsecond mtimes, but make doesn't; - # notably on macOS, which ships make 3.81 from 2006 (the last one - # released under GPLv2). https://bugs.gnu.org/68808 - # - # We test $MAKE if it is defined in the environment, else "make". - # It might get overridden later, but our hope is that in practice - # it does not matter: it is the system "make" which is (by far) - # the most likely to be broken, whereas if the user overrides it, - # probably they did so with a better, or at least not worse, make. - # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html - # - # Create a Makefile (real tab character here): - rm -f conftest.mk - echo 'conftest.ts1: conftest.ts2' >conftest.mk - echo ' touch conftest.ts2' >>conftest.mk - # - # Now, running - # touch conftest.ts1; touch conftest.ts2; make - # should touch ts1 because ts2 is newer. This could happen by luck, - # but most often, it will fail if make's support is insufficient. So - # test for several consecutive successes. - # - # (We reuse conftest.ts[12] because we still want to modify existing - # files, not create new ones, per above.) - n=0 - make=${MAKE-make} - until test $n -eq 3; do - echo one > conftest.ts1 - sleep $am_try_res - echo two > conftest.ts2 # ts2 should now be newer than ts1 - if $make -f conftest.mk | grep 'up to date' >/dev/null; then - make_ok=false - break # out of $n loop - fi - n=`expr $n + 1` - done - fi - # - if $make_ok; then - # Everything we know to check worked out, so call this resolution good. - am_cv_filesystem_timestamp_resolution=$am_try_res - break # out of $am_try_res loop - fi - # Otherwise, we'll go on to check the next resolution. - fi -done -rm -f conftest.ts? -# (end _am_filesystem_timestamp_resolution) - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_filesystem_timestamp_resolution" >&5 -printf '%s\n' "$am_cv_filesystem_timestamp_resolution" >&6; } - -# This check should not be cached, as it may vary across builds of -# different projects. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -printf %s "checking whether build environment is sane... " >&6; } -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[\\\"\#\$\&\'\`$am_lf]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; -esac -case $srcdir in - *[\\\"\#\$\&\'\`$am_lf\ \ ]*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -am_build_env_is_sane=no -am_has_slept=no -rm -f conftest.file -for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - test "$2" = conftest.file - ); then - am_build_env_is_sane=yes - break - fi - # Just in case. - sleep "$am_cv_filesystem_timestamp_resolution" - am_has_slept=yes -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_build_env_is_sane" >&5 -printf '%s\n' "$am_build_env_is_sane" >&6; } -if test "$am_build_env_is_sane" = no; then - as_fn_error $? "newly created file is older than distributed files! -Check your system clock" "$LINENO" 5 -fi - -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1 -then : - -else case e in #( - e) ( sleep "$am_cv_filesystem_timestamp_resolution" ) & - am_sleep_pid=$! - ;; -esac -fi - -rm -f conftest.file - -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was 's,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`printf '%s\n' "$program_transform_name" | sed "$ac_script"` - - - if test x"${MISSING+set}" != xset; then - MISSING="\${SHELL} '$am_aux_dir/missing'" -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -printf '%s\n' "$as_me: WARNING: 'missing' script is too old or missing" >&2;} -fi - -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 -printf %s "checking for a race-free mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if test ${ac_cv_path_mkdir+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue - case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir ('*'coreutils) '* | \ - *'BusyBox '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - ;; -esac -fi - - test -d ./--version && rmdir ./--version - if test ${ac_cv_path_mkdir+y}; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use plain mkdir -p, - # in the hope it doesn't have the bugs of ancient mkdir. - MKDIR_P='mkdir -p' - fi -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -printf '%s\n' "$MKDIR_P" >&6; } - -for ac_prog in gawk mawk nawk awk 'busybox awk' -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AWK+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -printf '%s\n' "$AWK" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`printf '%s\n' "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval test \${ac_cv_prog_make_${ac_make}_set+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @printf '%s\n' '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make ;; -esac -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - SET_MAKE= -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depfiles" - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 -printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } -cat > confinc.mk << 'END' -am__doit: - @echo this is the am__doit target >confinc.out -.PHONY: am__doit -END -am__include="#" -am__quote= -# BSD make does it like this. -echo '.include "confinc.mk" # ignored' > confmf.BSD -# Other make implementations (GNU, Solaris 10, AIX) do it like this. -echo 'include confinc.mk # ignored' > confmf.GNU -_am_result=no -for s in GNU BSD; do - { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 - (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - case $?:`cat confinc.out 2>/dev/null` in #( - '0:this is the am__doit target') : - case $s in #( - BSD) : - am__include='.include' am__quote='"' ;; #( - *) : - am__include='include' am__quote='' ;; -esac ;; #( - *) : - ;; -esac - if test "$am__include" != "#"; then - _am_result="yes ($s style)" - break - fi -done -rm -f confinc.* confmf.* -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 -printf '%s\n' "${_am_result}" >&6; } - -# Check whether --enable-dependency-tracking was given. -if test ${enable_dependency_tracking+y} -then : - enableval=$enable_dependency_tracking; -fi - -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi - if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - -AM_DEFAULT_VERBOSITY=1 -# Check whether --enable-silent-rules was given. -if test ${enable_silent_rules+y} -then : - enableval=$enable_silent_rules; -fi - -am_make=${MAKE-make} -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -printf %s "checking whether $am_make supports nested variables... " >&6; } -if test ${am_cv_make_support_nested_variables+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if printf '%s\n' 'TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -printf '%s\n' "$am_cv_make_support_nested_variables" >&6; } -AM_BACKSLASH='\' - -am__rm_f_notfound= -if (rm -f && rm -fr && rm -rf) 2>/dev/null -then : - -else case e in #( - e) am__rm_f_notfound='""' ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking xargs -n works" >&5 -printf %s "checking xargs -n works... " >&6; } -if test ${am_cv_xargs_n_works+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 -3" -then : - am_cv_xargs_n_works=yes -else case e in #( - e) am_cv_xargs_n_works=no ;; -esac -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_xargs_n_works" >&5 -printf '%s\n' "$am_cv_xargs_n_works" >&6; } -if test "$am_cv_xargs_n_works" = yes -then : - am__xargs_n='xargs -n' -else case e in #( - e) am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "" "$am__xargs_n_arg"; done; }' - ;; -esac -fi - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE='libXext' - VERSION='1.3.7' - - -printf '%s\n' "#define PACKAGE \"$PACKAGE\"" >>confdefs.h - - -printf '%s\n' "#define VERSION \"$VERSION\"" >>confdefs.h - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -mkdir_p='$(MKDIR_P)' - -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AMTAR='$${TAR-tar}' - - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar plaintar pax cpio none' - -# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 -printf %s "checking whether UID '$am_uid' is supported by ustar format... " >&6; } - if test x$am_uid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&2;} - elif test $am_uid -le $am_max_uid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 -printf %s "checking whether GID '$am_gid' is supported by ustar format... " >&6; } - if test x$gm_gid = xunknown; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&5 -printf '%s\n' "$as_me: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&2;} - elif test $am_gid -le $am_max_gid; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - _am_tools=none - fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 -printf %s "checking how to create a ustar tar archive... " >&6; } - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_ustar-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - { echo "$as_me:$LINENO: $_am_tar --version" >&5 - ($_am_tar --version) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && break - done - am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x ustar -w "$$tardir"' - am__tar_='pax -L -x ustar -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H ustar -L' - am__tar_='find "$tardir" -print | cpio -o -H ustar -L' - am__untar='cpio -i -H ustar -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_ustar}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 - (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - rm -rf conftest.dir - if test -s conftest.tar; then - { echo "$as_me:$LINENO: $am__untar &5 - ($am__untar &5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 - (cat conftest.dir/file) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - grep GrepMe conftest.dir/file >/dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - if test ${am_cv_prog_tar_ustar+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) am_cv_prog_tar_ustar=$_am_tool ;; -esac -fi - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 -printf '%s\n' "$am_cv_prog_tar_ustar" >&6; } - - - - - -depcc="$CC" am_compiler_list= - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -printf %s "checking dependency style of $depcc... " >&6; } -if test ${am_cv_CC_dependencies_compiler_type+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thus: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -printf '%s\n' "$am_cv_CC_dependencies_compiler_type" >&6; } -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' -else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi - - -# Variables for tags utilities; see am/tags.am -if test -z "$CTAGS"; then - CTAGS=ctags -fi - -if test -z "$ETAGS"; then - ETAGS=etags -fi - -if test -z "$CSCOPE"; then - CSCOPE=cscope -fi - - - - - - - - -# Initialize libtool -case `pwd` in - *\ * | *\ *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 -printf '%s\n' "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; -esac - - - -macro_version='2.5.4' -macro_revision='2.5.4' - - - - - - - - - - - - - - -ltmain=$ac_aux_dir/ltmain.sh - - - - # Make sure we can run config.sub. -$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -printf %s "checking build system type... " >&6; } -if test ${ac_cv_build+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -printf '%s\n' "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`printf '%s\n' "$build_os" | sed 's/ /-/g'`;; esac - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -printf %s "checking host system type... " >&6; } -if test ${ac_cv_host+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -printf '%s\n' "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`printf '%s\n' "$host_os" | sed 's/ /-/g'`;; esac - - -# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 -printf %s "checking how to print strings... " >&6; } -# Test print first, because it will be a builtin if present. -if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "" -} - -case $ECHO in - printf*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: printf" >&5 -printf '%s\n' "printf" >&6; } ;; - print*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 -printf '%s\n' "print -r" >&6; } ;; - *) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: cat" >&5 -printf '%s\n' "cat" >&6; } ;; -esac - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -printf %s "checking for a sed that does not truncate output... " >&6; } -if test ${ac_cv_path_SED+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in sed gsed - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in #( -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -#( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -printf '%s\n' "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - -test -z "$SED" && SED=sed -Xsed="$SED -e 1s/^X//" - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in grep ggrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in #( -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -#( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf '%s\n' "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in egrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in #( -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -#( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf '%s\n' "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - EGREP_TRADITIONAL=$EGREP - ac_cv_path_EGREP_TRADITIONAL=$EGREP - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 -printf %s "checking for fgrep... " >&6; } -if test ${ac_cv_path_FGREP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 - then ac_cv_path_FGREP="$GREP -F" - else - if test -z "$FGREP"; then - ac_path_FGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in fgrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_FGREP" || continue -# Check for GNU ac_path_FGREP and select it if it is found. - # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in #( -*GNU*) - ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; -#( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf '%s\n' 'FGREP' >> "conftest.nl" - "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_FGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_FGREP="$ac_path_FGREP" - ac_path_FGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_FGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_FGREP"; then - as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_FGREP=$FGREP -fi - - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 -printf '%s\n' "$ac_cv_path_FGREP" >&6; } - FGREP="$ac_cv_path_FGREP" - - -test -z "$GREP" && GREP=grep - - - - - - - - - - - - - - - - - - - -# Check whether --with-gnu-ld was given. -if test ${with_gnu_ld+y} -then : - withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes -else case e in #( - e) with_gnu_ld=no ;; -esac -fi - -ac_prog=ld -if test yes = "$GCC"; then - # Check if gcc -print-prog-name=ld gives a path. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -printf %s "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw* | *-*-windows*) - # gcc leaves a trailing carriage return, which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD=$ac_prog - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test yes = "$with_gnu_ld"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -printf %s "checking for GNU ld... " >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -printf %s "checking for non-GNU ld... " >&6; } -fi -if test ${lt_cv_path_LD+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -z "$LD"; then - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD=$ac_dir/$ac_prog - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -printf '%s\n' "$LD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -printf %s "checking if the linker ($LD) is GNU ld... " >&6; } -if test ${lt_cv_prog_gnu_ld+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -printf '%s\n' "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 -printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if test ${lt_cv_path_NM+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM=$NM -else - lt_nm_to_check=${ac_tool_prefix}nm - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - tmp_nm=$ac_dir/$lt_tmp_nm - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the 'sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty - case $build_os in - mingw* | windows*) lt_bad_file=conftest.nm/nofile ;; - *) lt_bad_file=/dev/null ;; - esac - case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in - *$lt_bad_file* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break 2 - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break 2 - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS=$lt_save_ifs - done - : ${lt_cv_path_NM=no} -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 -printf '%s\n' "$lt_cv_path_NM" >&6; } -if test no != "$lt_cv_path_NM"; then - NM=$lt_cv_path_NM -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - if test -n "$ac_tool_prefix"; then - for ac_prog in dumpbin "link -dump" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$DUMPBIN"; then - ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DUMPBIN=$ac_cv_prog_DUMPBIN -if test -n "$DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 -printf '%s\n' "$DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$DUMPBIN" && break - done -fi -if test -z "$DUMPBIN"; then - ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in dumpbin "link -dump" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DUMPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_DUMPBIN"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN -if test -n "$ac_ct_DUMPBIN"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 -printf '%s\n' "$ac_ct_DUMPBIN" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_DUMPBIN" && break -done - - if test "x$ac_ct_DUMPBIN" = x; then - DUMPBIN=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DUMPBIN=$ac_ct_DUMPBIN - fi -fi - - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols -headers" - ;; - *) - DUMPBIN=: - ;; - esac - fi - - if test : != "$DUMPBIN"; then - NM=$DUMPBIN - fi -fi -test -z "$NM" && NM=nm - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 -printf %s "checking the name lister ($NM) interface... " >&6; } -if test ${lt_cv_nm_interface+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: output\"" >&5) - cat conftest.out >&5 - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 -printf '%s\n' "$lt_cv_nm_interface" >&6; } - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -printf %s "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -printf '%s\n' "no, using $LN_S" >&6; } -fi - -# find the maximum length of command line arguments -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 -printf %s "checking the maximum length of command line arguments... " >&6; } -if test ${lt_cv_sys_max_cmd_len+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) i=0 - teststring=ABCD - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu* | ironclad*) - # Under GNU Hurd and Ironclad, this test is not required because there - # is no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | windows* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[ ]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test X`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test 17 != "$i" # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac - ;; -esac -fi - -if test -n "$lt_cv_sys_max_cmd_len"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 -printf '%s\n' "$lt_cv_sys_max_cmd_len" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none" >&5 -printf '%s\n' "none" >&6; } -fi -max_cmd_len=$lt_cv_sys_max_cmd_len - - - - - - -: ${CP="cp -f"} -: ${MV="mv -f"} -: ${RM="rm -f"} - -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - lt_unset=unset -else - lt_unset=false -fi - - - - - -# test EBCDIC or ASCII -case `echo X|tr X '\101'` in - A) # ASCII based system - # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr - lt_SP2NL='tr \040 \012' - lt_NL2SP='tr \015\012 \040\040' - ;; - *) # EBCDIC based system - lt_SP2NL='tr \100 \n' - lt_NL2SP='tr \r\n \100\100' - ;; -esac - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 -printf %s "checking how to convert $build file names to $host format... " >&6; } -if test ${lt_cv_to_host_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $host in - *-*-mingw* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 - ;; - esac - ;; - *-*-cygwin* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin - ;; - esac - ;; - * ) # unhandled hosts (and "normal" native builds) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; -esac - ;; -esac -fi - -to_host_file_cmd=$lt_cv_to_host_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_host_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 -printf %s "checking how to convert $build file names to toolchain format... " >&6; } -if test ${lt_cv_to_tool_file_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) #assume ordinary cross tools, or native build. -lt_cv_to_tool_file_cmd=func_convert_file_noop -case $host in - *-*-mingw* | *-*-windows* ) - case $build in - *-*-mingw* | *-*-windows* ) # actually msys - lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 - ;; - esac - ;; -esac - ;; -esac -fi - -to_tool_file_cmd=$lt_cv_to_tool_file_cmd -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 -printf '%s\n' "$lt_cv_to_tool_file_cmd" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 -printf %s "checking for $LD option to reload object files... " >&6; } -if test ${lt_cv_ld_reload_flag+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_ld_reload_flag='-r' ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 -printf '%s\n' "$lt_cv_ld_reload_flag" >&6; } -reload_flag=$lt_cv_ld_reload_flag -case $reload_flag in -"" | " "*) ;; -*) reload_flag=" $reload_flag" ;; -esac -reload_cmds='$LD$reload_flag -o $output$reload_objs' -case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - if test yes != "$GCC"; then - reload_cmds=false - fi - ;; - darwin*) - if test yes = "$GCC"; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' - else - reload_cmds='$LD$reload_flag -o $output$reload_objs' - fi - ;; -esac - - - - - - - - - -# Extract the first word of "file", so it can be a program name with args. -set dummy file; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_FILECMD+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$FILECMD"; then - ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FILECMD="file" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_prog_FILECMD" && ac_cv_prog_FILECMD=":" -fi ;; -esac -fi -FILECMD=$ac_cv_prog_FILECMD -if test -n "$FILECMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 -printf '%s\n' "$FILECMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -printf '%s\n' "$OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OBJDUMP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -printf '%s\n' "$ac_ct_OBJDUMP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 -printf %s "checking how to recognize dependent libraries... " >&6; } -if test ${lt_cv_deplibs_check_method+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# 'unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'file_magic [[regex]]' -- check by looking for files in library path -# that responds to the $file_magic_cmd with a given extended regex. -# If you have 'file' or equivalent on your system and you're not sure -# whether 'pass_all' will *always* work, you probably want this one. - -case $host_os in -aix[4-9]*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[45]*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='$FILECMD -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | windows* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - if ( file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -cegcc*) - # use the weaker test based on 'objdump'. See mingw*. - lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly* | midnightbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -haiku*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=$FILECMD - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[3-9]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -*-mlibc) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=$FILECMD - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -*nto* | *qnx*) - lt_cv_deplibs_check_method=pass_all - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -serenity*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -tpf*) - lt_cv_deplibs_check_method=pass_all - ;; -os2*) - lt_cv_deplibs_check_method=pass_all - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 -printf '%s\n' "$lt_cv_deplibs_check_method" >&6; } - -file_magic_glob= -want_nocaseglob=no -if test "$build" = "$host"; then - case $host_os in - mingw* | windows* | pw32*) - if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then - want_nocaseglob=yes - else - file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` - fi - ;; - esac -fi - -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - - - - - - - - - - - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -printf '%s\n' "$DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DLLTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -printf '%s\n' "$ac_ct_DLLTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 -printf %s "checking how to associate runtime and link libraries... " >&6; } -if test ${lt_cv_sharedlib_from_linklib_cmd+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_sharedlib_from_linklib_cmd='unknown' - -case $host_os in -cygwin* | mingw* | windows* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh; - # decide which one to use based on capabilities of $DLLTOOL - case `$DLLTOOL --help 2>&1` in - *--identify-strict*) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib - ;; - *) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback - ;; - esac - ;; -*) - # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd=$ECHO - ;; -esac - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 -printf '%s\n' "$lt_cv_sharedlib_from_linklib_cmd" >&6; } -sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd -test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -printf '%s\n' "$RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_RANLIB+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -printf '%s\n' "$ac_ct_RANLIB" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AR+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -printf '%s\n' "$AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_AR+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -printf '%s\n' "$ac_ct_AR" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -: ${AR=ar} - - - - - - -# Use ARFLAGS variable as AR's operation code to sync the variable naming with -# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have -# higher priority because that's what people were doing historically (setting -# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS -# variable obsoleted/removed. - -test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} -lt_ar_flags=$AR_FLAGS - - - - - - -# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override -# by AR_FLAGS because that was never working and AR_FLAGS is about to die. - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 -printf %s "checking for archiver @FILE support... " >&6; } -if test ${lt_cv_ar_at_file+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_ar_at_file=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - echo conftest.$ac_objext > conftest.lst - lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -eq "$ac_status"; then - # Ensure the archiver fails upon bogus file names. - rm -f conftest.$ac_objext libconftest.a - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -ne "$ac_status"; then - lt_cv_ar_at_file=@ - fi - fi - rm -f conftest.* libconftest.a - -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 -printf '%s\n' "$lt_cv_ar_at_file" >&6; } - -if test no = "$lt_cv_ar_at_file"; then - archiver_list_spec= -else - archiver_list_spec=$lt_cv_ar_at_file -fi - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf '%s\n' "$STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf '%s\n' "$ac_ct_STRIP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -test -z "$STRIP" && STRIP=: - - - - - - - -test -z "$RANLIB" && RANLIB=: - - - - - - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# Check for command to grab the raw symbol name followed by C symbol from nm. -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 -printf %s "checking command to parse $NM output from $compiler object... " >&6; } -if test ${lt_cv_sys_global_symbol_pipe+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw* | windows* | pw32* | cegcc*) - symcode='[ABCDGISTW]' - ;; -hpux*) - if test ia64 = "$host_cpu"; then - symcode='[ABCDEGRST]' - fi - ;; -irix* | nonstopux*) - symcode='[BCDEGRST]' - ;; -osf*) - symcode='[BCDEGQRST]' - ;; -solaris*) - symcode='[BCDRT]' - ;; -sco3.2v5*) - symcode='[DT]' - ;; -sysv4.2uw2*) - symcode='[DT]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[ABDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[ABCDGIRSTW]' ;; -esac - -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Gets list of data symbols to import. - lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" - # Adjust the below global symbol transforms to fixup imported variables. - lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" - lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" - lt_c_name_lib_hook="\ - -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ - -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" -else - # Disable hooks by default. - lt_cv_sys_global_symbol_to_import= - lt_cdecl_hook= - lt_c_name_hook= - lt_c_name_lib_hook= -fi - -# Transform an extracted symbol line into a proper C declaration. -# Some systems (esp. on ia64) link data and code symbols differently, -# so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ -$lt_cdecl_hook\ -" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ -$lt_c_name_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" - -# Transform an extracted symbol line into symbol name with lib prefix and -# symbol address. -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ -$lt_c_name_lib_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw* | windows*) - opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# Try without a prefix underscore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function, - # D for any global variable and I for any imported variable. - # Also find C++ and __fastcall symbols from MSVC++ or ICC, - # which start with @ or ?. - lt_cv_sys_global_symbol_pipe="$AWK '"\ -" {last_section=section; section=\$ 3};"\ -" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ -" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ -" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ -" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ -" \$ 0!~/External *\|/{next};"\ -" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ -" {if(hide[section]) next};"\ -" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ -" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ -" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ -" ' prfx=^$ac_symprfx" - else - lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <<_LT_EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(void); -void nm_test_func(void){} -#ifdef __cplusplus -} -#endif -int main(void){nm_test_var='a';nm_test_func();return(0);} -_LT_EOF - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Now try to grab the symbols. - nlist=conftest.nm - $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 - if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if $GREP ' nm_test_var$' "$nlist" >/dev/null; then - if $GREP ' nm_test_func$' "$nlist" >/dev/null; then - cat <<_LT_EOF > conftest.$ac_ext -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE -/* DATA imports from DLLs on WIN32 can't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT_DLSYM_CONST -#elif defined __osf__ -/* This system does not cope well with relocations in const data. */ -# define LT_DLSYM_CONST -#else -# define LT_DLSYM_CONST const -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -_LT_EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' - - cat <<_LT_EOF >> conftest.$ac_ext - -/* The mapping between symbol names and symbols. */ -LT_DLSYM_CONST struct { - const char *name; - void *address; -} -lt__PROGRAM__LTX_preloaded_symbols[] = -{ - { "@PROGRAM@", (void *) 0 }, -_LT_EOF - $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext - cat <<\_LT_EOF >> conftest.$ac_ext - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt__PROGRAM__LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif -_LT_EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_globsym_save_LIBS=$LIBS - lt_globsym_save_CFLAGS=$CFLAGS - LIBS=conftstm.$ac_objext - CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest$ac_exeext; then - pipe_works=yes - fi - LIBS=$lt_globsym_save_LIBS - CFLAGS=$lt_globsym_save_CFLAGS - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - fi - rm -rf conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test yes = "$pipe_works"; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done - ;; -esac -fi - -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -printf '%s\n' "failed" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ok" >&5 -printf '%s\n' "ok" >&6; } -fi - -# Response file support. -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - nm_file_list_spec='@' -elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then - nm_file_list_spec='@' -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 -printf %s "checking for sysroot... " >&6; } - -# Check whether --with-sysroot was given. -if test ${with_sysroot+y} -then : - withval=$with_sysroot; -else case e in #( - e) with_sysroot=no ;; -esac -fi - - -lt_sysroot= -case $with_sysroot in #( - yes) - if test yes = "$GCC"; then - # Trim trailing / since we'll always append absolute paths and we want - # to avoid //, if only for less confusing output for the user. - lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 -printf '%s\n' "$with_sysroot" >&6; } - as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 - ;; -esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 -printf '%s\n' "${lt_sysroot:-no}" >&6; } - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 -printf %s "checking for a working dd... " >&6; } -if test ${ac_cv_path_lt_DD+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -: ${lt_DD:=$DD} -if test -z "$lt_DD"; then - ac_path_lt_DD_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in dd - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_lt_DD" || continue -if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: -fi - $ac_path_lt_DD_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_lt_DD"; then - : - fi -else - ac_cv_path_lt_DD=$lt_DD -fi - -rm -f conftest.i conftest2.i conftest.out ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 -printf '%s\n' "$ac_cv_path_lt_DD" >&6; } - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 -printf %s "checking how to truncate binary pipes... " >&6; } -if test ${lt_cv_truncate_bin+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -lt_cv_truncate_bin= -if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" -fi -rm -f conftest.i conftest2.i conftest.out -test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 -printf '%s\n' "$lt_cv_truncate_bin" >&6; } - - - - - - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in $*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - -# Check whether --enable-libtool-lock was given. -if test ${enable_libtool_lock+y} -then : - enableval=$enable_libtool_lock; -fi - -test no = "$enable_libtool_lock" || enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out what ABI is being produced by ac_compile, and set mode - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE=32 - ;; - *ELF-64*) - HPUX_IA64_MODE=64 - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - if test yes = "$lt_cv_prog_gnu_ld"; then - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -mips64*-*linux*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - emul=elf - case `$FILECMD conftest.$ac_objext` in - *32-bit*) - emul="${emul}32" - ;; - *64-bit*) - emul="${emul}64" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *MSB*) - emul="${emul}btsmip" - ;; - *LSB*) - emul="${emul}ltsmip" - ;; - esac - case `$FILECMD conftest.$ac_objext` in - *N32*) - emul="${emul}n32" - ;; - esac - LD="${LD-ld} -m $emul" - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. Note that the listed cases only cover the - # situations where additional linker options are needed (such as when - # doing 32-bit compilation for a host where ld defaults to 64-bit, or - # vice versa); the common cases where no linker options are needed do - # not appear in the list. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - case `$FILECMD conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac - ;; - powerpc64le-*linux*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*|x86_64-gnu*) - LD="${LD-ld} -m elf_x86_64" - ;; - powerpcle-*linux*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -belf" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 -printf %s "checking whether the C compiler needs -belf... " >&6; } -if test ${lt_cv_cc_needs_belf+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_cc_needs_belf=yes -else case e in #( - e) lt_cv_cc_needs_belf=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 -printf '%s\n' "$lt_cv_cc_needs_belf" >&6; } - if test yes != "$lt_cv_cc_needs_belf"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS=$SAVE_CFLAGS - fi - ;; -*-*solaris*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `$FILECMD conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) - case $host in - i?86-*-solaris*|x86_64-*-solaris*) - LD="${LD-ld} -m elf_x86_64" - ;; - sparc*-*-solaris*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - # GNU ld 2.21 introduced _sol2 emulations. Use them if available. - if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD=${LD-ld}_sol2 - fi - ;; - *) - if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then - LD="${LD-ld} -64" - fi - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; -esac - -need_locks=$enable_libtool_lock - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. -set dummy ${ac_tool_prefix}mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$MANIFEST_TOOL"; then - ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL -if test -n "$MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 -printf '%s\n' "$MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_MANIFEST_TOOL"; then - ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL - # Extract the first word of "mt", so it can be a program name with args. -set dummy mt; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_MANIFEST_TOOL"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL -if test -n "$ac_ct_MANIFEST_TOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 -printf '%s\n' "$ac_ct_MANIFEST_TOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_MANIFEST_TOOL" = x; then - MANIFEST_TOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL - fi -else - MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" -fi - -test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 -printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } -if test ${lt_cv_path_manifest_tool+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_path_manifest_tool=no - echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 - $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out - cat conftest.err >&5 - if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_manifest_tool=yes - fi - rm -f conftest* ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_manifest_tool" >&5 -printf '%s\n' "$lt_cv_path_manifest_tool" >&6; } -if test yes != "$lt_cv_path_manifest_tool"; then - MANIFEST_TOOL=: -fi - - - - - - - case $host_os in - rhapsody* | darwin*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. -set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$DSYMUTIL"; then - ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -DSYMUTIL=$ac_cv_prog_DSYMUTIL -if test -n "$DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 -printf '%s\n' "$DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DSYMUTIL"; then - ac_ct_DSYMUTIL=$DSYMUTIL - # Extract the first word of "dsymutil", so it can be a program name with args. -set dummy dsymutil; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_DSYMUTIL"; then - ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL -if test -n "$ac_ct_DSYMUTIL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 -printf '%s\n' "$ac_ct_DSYMUTIL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_DSYMUTIL" = x; then - DSYMUTIL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DSYMUTIL=$ac_ct_DSYMUTIL - fi -else - DSYMUTIL="$ac_cv_prog_DSYMUTIL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. -set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$NMEDIT"; then - ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -NMEDIT=$ac_cv_prog_NMEDIT -if test -n "$NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 -printf '%s\n' "$NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_NMEDIT"; then - ac_ct_NMEDIT=$NMEDIT - # Extract the first word of "nmedit", so it can be a program name with args. -set dummy nmedit; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_NMEDIT+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_NMEDIT"; then - ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_NMEDIT="nmedit" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT -if test -n "$ac_ct_NMEDIT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 -printf '%s\n' "$ac_ct_NMEDIT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_NMEDIT" = x; then - NMEDIT=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - NMEDIT=$ac_ct_NMEDIT - fi -else - NMEDIT="$ac_cv_prog_NMEDIT" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. -set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$LIPO"; then - ac_cv_prog_LIPO="$LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -LIPO=$ac_cv_prog_LIPO -if test -n "$LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 -printf '%s\n' "$LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LIPO"; then - ac_ct_LIPO=$LIPO - # Extract the first word of "lipo", so it can be a program name with args. -set dummy lipo; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_LIPO+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_LIPO"; then - ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_LIPO="lipo" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO -if test -n "$ac_ct_LIPO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 -printf '%s\n' "$ac_ct_LIPO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_LIPO" = x; then - LIPO=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LIPO=$ac_ct_LIPO - fi -else - LIPO="$ac_cv_prog_LIPO" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -printf '%s\n' "$OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL="otool" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -printf '%s\n' "$ac_ct_OTOOL" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$OTOOL64"; then - ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL64=$ac_cv_prog_OTOOL64 -if test -n "$OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 -printf '%s\n' "$OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL64"; then - ac_ct_OTOOL64=$OTOOL64 - # Extract the first word of "otool64", so it can be a program name with args. -set dummy otool64; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL64+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_OTOOL64"; then - ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL64="otool64" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 -if test -n "$ac_ct_OTOOL64"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 -printf '%s\n' "$ac_ct_OTOOL64" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_ct_OTOOL64" = x; then - OTOOL64=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL64=$ac_ct_OTOOL64 - fi -else - OTOOL64="$ac_cv_prog_OTOOL64" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 -printf %s "checking for -single_module linker flag... " >&6; } -if test ${lt_cv_apple_cc_single_mod+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_apple_cc_single_mod=no - if test -z "$LT_MULTI_MODULE"; then - # By default we will add the -single_module flag. You can override - # by either setting the environment variable LT_MULTI_MODULE - # non-empty at configure time, or by adding -multi_module to the - # link flags. - rm -rf libconftest.dylib* - echo "int foo(void){return 1;}" > conftest.c - echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ --dynamiclib -Wl,-single_module conftest.c" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ - -dynamiclib -Wl,-single_module conftest.c 2>conftest.err - _lt_result=$? - # If there is a non-empty error log, and "single_module" - # appears in it, assume the flag caused a linker warning - if test -s conftest.err && $GREP single_module conftest.err; then - cat conftest.err >&5 - # Otherwise, if the output was created with a 0 exit code from - # the compiler, it worked. - elif test -f libconftest.dylib && test 0 = "$_lt_result"; then - lt_cv_apple_cc_single_mod=yes - else - cat conftest.err >&5 - fi - rm -rf libconftest.dylib* - rm -f conftest.* - fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 -printf '%s\n' "$lt_cv_apple_cc_single_mod" >&6; } - - # Feature test to disable chained fixups since it is not - # compatible with '-undefined dynamic_lookup' - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -no_fixup_chains linker flag" >&5 -printf %s "checking for -no_fixup_chains linker flag... " >&6; } -if test ${lt_cv_support_no_fixup_chains+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -Wl,-no_fixup_chains" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_support_no_fixup_chains=yes -else case e in #( - e) lt_cv_support_no_fixup_chains=no - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_support_no_fixup_chains" >&5 -printf '%s\n' "$lt_cv_support_no_fixup_chains" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 -printf %s "checking for -exported_symbols_list linker flag... " >&6; } -if test ${lt_cv_ld_exported_symbols_list+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_ld_exported_symbols_list=no - save_LDFLAGS=$LDFLAGS - echo "_main" > conftest.sym - LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_ld_exported_symbols_list=yes -else case e in #( - e) lt_cv_ld_exported_symbols_list=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 -printf '%s\n' "$lt_cv_ld_exported_symbols_list" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 -printf %s "checking for -force_load linker flag... " >&6; } -if test ${lt_cv_ld_force_load+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5 - $AR $AR_FLAGS libconftest.a conftest.o 2>&5 - echo "$RANLIB libconftest.a" >&5 - $RANLIB libconftest.a 2>&5 - cat > conftest.c << _LT_EOF -int main(void) { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -s conftest.err && $GREP force_load conftest.err; then - cat conftest.err >&5 - elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&5 - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 -printf '%s\n' "$lt_cv_ld_force_load" >&6; } - case $host_os in - rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; - darwin1.*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - darwin*) - case $MACOSX_DEPLOYMENT_TARGET,$host in - 10.[012],*|,*powerpc*-darwin[5-8]*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - *) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' - if test yes = "$lt_cv_support_no_fixup_chains"; then - as_fn_append _lt_dar_allow_undefined ' $wl-no_fixup_chains' - fi - ;; - esac - ;; - esac - if test yes = "$lt_cv_apple_cc_single_mod"; then - _lt_dar_single_mod='$single_module' - fi - _lt_dar_needs_single_mod=no - case $host_os in - rhapsody* | darwin1.*) - _lt_dar_needs_single_mod=yes ;; - darwin*) - # When targeting Mac OS X 10.4 (darwin 8) or later, - # -single_module is the default and -multi_module is unsupported. - # The toolchain on macOS 10.14 (darwin 18) and later cannot - # target any OS version that needs -single_module. - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*-darwin[567].*|10.[0-3],*-darwin[5-9].*|10.[0-3],*-darwin1[0-7].*) - _lt_dar_needs_single_mod=yes ;; - esac - ;; - esac - if test yes = "$lt_cv_ld_exported_symbols_list"; then - _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' - else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' - fi - if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then - _lt_dsymutil='~$DSYMUTIL $lib || :' - else - _lt_dsymutil= - fi - ;; - esac - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x$2 in - x) - ;; - *:) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" - ;; - x:*) - eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" - ;; - *) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" - ;; - esac -} - -ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default -" -if test "x$ac_cv_header_dlfcn_h" = xyes -then : - printf '%s\n' "#define HAVE_DLFCN_H 1" >>confdefs.h - -fi - - - - - -# Set options - - - - enable_dlopen=no - - - enable_win32_dll=no - - - # Check whether --enable-shared was given. -if test ${enable_shared+y} -then : - enableval=$enable_shared; p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in #( - e) enable_shared=yes ;; -esac -fi - - - - - - - - - - # Check whether --enable-static was given. -if test ${enable_static+y} -then : - enableval=$enable_static; p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in #( - e) enable_static=yes ;; -esac -fi - - - - - - - - - - # Check whether --enable-pic was given. -if test ${enable_pic+y} -then : - enableval=$enable_pic; lt_p=${PACKAGE-default} - case $enableval in - yes|no) pic_mode=$enableval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in #( - e) # Check whether --with-pic was given. -if test ${with_pic+y} -then : - withval=$with_pic; lt_p=${PACKAGE-default} - case $withval in - yes|no) pic_mode=$withval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $withval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in #( - e) pic_mode=default ;; -esac -fi - - ;; -esac -fi - - - - - - - - - # Check whether --enable-fast-install was given. -if test ${enable_fast_install+y} -then : - enableval=$enable_fast_install; p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for pkg in $enableval; do - IFS=$lt_save_ifs - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS=$lt_save_ifs - ;; - esac -else case e in #( - e) enable_fast_install=yes ;; -esac -fi - - - - - - - - - shared_archive_member_spec= -case $host,$enable_shared in -power*-*-aix[5-9]*,yes) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 -printf %s "checking which variant of shared library versioning to provide... " >&6; } - # Check whether --enable-aix-soname was given. -if test ${enable_aix_soname+y} -then : - enableval=$enable_aix_soname; case $enableval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --enable-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$enable_aix_soname -else case e in #( - e) # Check whether --with-aix-soname was given. -if test ${with_aix_soname+y} -then : - withval=$with_aix_soname; case $withval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$with_aix_soname -else case e in #( - e) if test ${lt_cv_with_aix_soname+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_with_aix_soname=aix ;; -esac -fi - ;; -esac -fi - - enable_aix_soname=$lt_cv_with_aix_soname ;; -esac -fi - - with_aix_soname=$enable_aix_soname - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 -printf '%s\n' "$with_aix_soname" >&6; } - if test aix != "$with_aix_soname"; then - # For the AIX way of multilib, we name the shared archive member - # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', - # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. - # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, - # the AIX toolchain works better with OBJECT_MODE set (default 32). - if test 64 = "${OBJECT_MODE-32}"; then - shared_archive_member_spec=shr_64 - else - shared_archive_member_spec=shr - fi - fi - ;; -*) - with_aix_soname=aix - ;; -esac - - - - - - - - - - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS=$ltmain - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -test -z "$LN_S" && LN_S="ln -s" - - - - - - - - - - - - - - -if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 -printf %s "checking for objdir... " >&6; } -if test ${lt_cv_objdir+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 -printf '%s\n' "$lt_cv_objdir" >&6; } -objdir=$lt_cv_objdir - - - - - -printf '%s\n' "#define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h - - - - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Global variables: -ofile=libtool -can_build_shared=yes - -# All known linkers require a '.a' archive for static linking (except MSVC and -# ICC, which need '.lib'). -libext=a - -with_gnu_ld=$lt_cv_prog_gnu_ld - -old_CC=$CC -old_CFLAGS=$CFLAGS - -# Set sane defaults for various variables -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$LD" && LD=ld -test -z "$ac_objext" && ac_objext=o - -func_cc_basename $compiler -cc_basename=$func_cc_basename_result - - -# Only perform the check for file, if the check method requires it -test -z "$MAGIC_CMD" && MAGIC_CMD=file -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 -printf %s "checking for ${ac_tool_prefix}file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/${ac_tool_prefix}file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for file" >&5 -printf %s "checking for file... " >&6; } -if test ${lt_cv_path_MAGIC_CMD+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac ;; -esac -fi - -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -printf '%s\n' "$MAGIC_CMD" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - else - MAGIC_CMD=: - fi -fi - - fi - ;; -esac - -# Use C for the default configuration in the libtool script - -lt_save_CC=$CC -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -objext=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(void){return(0);}' - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - -# Save the default compiler, since it gets overwritten when the other -# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. -compiler_DEFAULT=$CC - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - -lt_prog_compiler_no_builtin_flag= - -if test yes = "$GCC"; then - case $cc_basename in - nvcc*) - lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; - *) - lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; - esac - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if test ${lt_cv_prog_compiler_rtti_exceptions+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -printf '%s\n' "$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then - lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" -else - : -fi - -fi - - - - - - - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - - - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test ${lt_cv_prog_compiler_c_o+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -printf '%s\n' "$lt_cv_prog_compiler_c_o" >&6; } - - - - -hard_links=nottested -if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then - # do not overwrite the value of need_locks provided by the user - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -printf %s "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -printf '%s\n' "$hard_links" >&6; } - if test no = "$hard_links"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 -printf '%s\n' "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - runpath_var= - allow_undefined_flag= - always_export_symbols=no - archive_cmds= - archive_expsym_cmds= - compiler_needs_object=no - enable_shared_with_static_runtimes=no - export_dynamic_flag_spec= - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - hardcode_automatic=no - hardcode_direct=no - hardcode_direct_absolute=no - hardcode_libdir_flag_spec= - hardcode_libdir_separator= - hardcode_minus_L=no - hardcode_shlibpath_var=unsupported - inherit_rpath=no - link_all_deplibs=unknown - module_cmds= - module_expsym_cmds= - old_archive_from_new_cmds= - old_archive_from_expsyms_cmds= - thread_safe_flag_spec= - whole_archive_flag_spec= - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ' (' and ')$', so one must not match beginning or - # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', - # as well as any symbol that contains 'd'. - exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - # Exclude shared library initialization/finalization symbols. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - if test yes != "$GCC"; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) - with_gnu_ld=yes - ;; - esac - - ld_shlibs=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test yes = "$with_gnu_ld"; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; - *\ \(GNU\ Binutils\)\ [3-9]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test yes = "$lt_use_gnu_ld_interface"; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='$wl' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='$wl--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' - else - whole_archive_flag_spec= - fi - supports_anon_versioning=no - case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test ia64 != "$host_cpu"; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.19, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. - -_LT_EOF - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='$wl--export-all-symbols' - allow_undefined_flag=unsupported - always_export_symbols=no - enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' - file_list_spec='@' - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file, use it as - # is; otherwise, prepend EXPORTS... - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs=no - fi - ;; - - haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - link_all_deplibs=no - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - interix[3-9]*) - hardcode_direct=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) - tmp_diet=no - if test linux-dietlibc = "$host_os"; then - case $cc_basename in - diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) - esac - fi - if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test no = "$tmp_diet" - then - tmp_addflag=' $pic_flag' - tmp_sharedflag='-shared' - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - lf95*) # Lahey Fortran 8.1 - whole_archive_flag_spec= - tmp_sharedflag='--shared' ;; - nagfor*) # NAGFOR 5.3 - tmp_sharedflag='-Wl,-shared' ;; - xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) - tmp_sharedflag='-qmkshrobj' - tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - ;; - esac - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' - fi - - case $cc_basename in - tcc*) - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='-rdynamic' - ;; - xlf* | bgf* | bgxlf* | mpixlf*) - # IBM XL Fortran 10.1 on PPC cannot create shared libs itself - whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test yes = "$supports_anon_versioning"; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' - fi - ;; - esac - else - ld_shlibs=no - fi - ;; - - *-mlibc) - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test no = "$ld_shlibs"; then - runpath_var= - hardcode_libdir_flag_spec= - export_dynamic_flag_spec= - whole_archive_flag_spec= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix[4-9]*) - if test ia64 = "$host_cpu"; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag= - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to GNU nm, but means don't demangle to AIX nm. - # Without the "-l" option, or with the "-B" option, AIX nm treats - # weak defined symbols like other global defined symbols, whereas - # GNU nm marks them as "W". - # While the 'weak' keyword is ignored in the Export File, we need - # it in the Import File for the 'aix-soname' feature, so we have - # to replace the "-B" option with "-P" for AIX nm. - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # have runtime linking enabled, and use it for executables. - # For shared libraries, we enable/disable runtime linking - # depending on the kind of the shared library created - - # when "with_aix_soname,aix_use_runtimelinking" is: - # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables - # "aix,yes" lib.so shared, rtl:yes, for executables - # lib.a static archive - # "both,no" lib.so.V(shr.o) shared, rtl:yes - # lib.a(lib.so.V) shared, rtl:no, for executables - # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a(lib.so.V) shared, rtl:no - # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a static archive - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then - aix_use_runtimelinking=yes - break - fi - done - if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then - # With aix-soname=svr4, we create the lib.so.V shared archives only, - # so we don't have lib.a shared libs to link our executables. - # We have to force runtime linking in this case. - aix_use_runtimelinking=yes - LDFLAGS="$LDFLAGS -Wl,-brtl" - fi - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds='' - hardcode_direct=yes - hardcode_direct_absolute=yes - hardcode_libdir_separator=':' - link_all_deplibs=yes - file_list_spec='$wl-f,' - case $with_aix_soname,$aix_use_runtimelinking in - aix,*) ;; # traditional, no import file - svr4,* | *,yes) # use import file - # The Import File defines what to hardcode. - hardcode_direct=no - hardcode_direct_absolute=no - ;; - esac - - if test yes = "$GCC"; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`$CC -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - shared_flag='-shared' - if test yes = "$aix_use_runtimelinking"; then - shared_flag="$shared_flag "'$wl-G' - fi - # Need to ensure runtime linking is disabled for the traditional - # shared library, or the linker may eventually find shared libraries - # /with/ Import File - we do not want to mix them. - shared_flag_aix='-shared' - shared_flag_svr4='-shared $wl-G' - else - # not using gcc - if test ia64 = "$host_cpu"; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test yes = "$aix_use_runtimelinking"; then - shared_flag='$wl-G' - else - shared_flag='$wl-bM:SRE' - fi - shared_flag_aix='$wl-bM:SRE' - shared_flag_svr4='$wl-G' - fi - fi - - export_dynamic_flag_spec='$wl-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols=yes - if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag='-berok' - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag - else - if test ia64 = "$host_cpu"; then - hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' - allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if test ${lt_cv_aix_libpath_+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi - ;; -esac -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag=' $wl-bernotok' - allow_undefined_flag=' $wl-berok' - if test yes = "$with_gnu_ld"; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - fi - archive_cmds_need_lc=yes - archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' - # -brtl affects multiple linker settings, -berok does not and is overridden later - compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' - if test svr4 != "$with_aix_soname"; then - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' - fi - if test aix != "$with_aix_soname"; then - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' - else - # used by -dlpreopen to get the symbols - archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' - fi - archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' - fi - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - bsdi[45]*) - export_dynamic_flag_spec=-rdynamic - ;; - - cygwin* | mingw* | windows* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++ or Intel C++ Compiler. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - case $cc_basename in - cl* | icl*) - # Native MSVC or ICC - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - always_export_symbols=yes - file_list_spec='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -Fe$output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp "$export_symbols" "$output_objdir/$soname.def"; - echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; - else - $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -Fe$tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, )='true' - enable_shared_with_static_runtimes=yes - exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - # Don't use ranlib - old_postinstall_cmds='chmod 644 $oldlib' - postlink_cmds='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile=$lt_outputfile.exe - lt_tool_outputfile=$lt_tool_outputfile.exe - ;; - esac~ - if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # Assume MSVC and ICC wrapper - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - enable_shared_with_static_runtimes=yes - ;; - esac - ;; - - darwin* | rhapsody*) - - - archive_cmds_need_lc=no - hardcode_direct=no - hardcode_automatic=yes - hardcode_shlibpath_var=unsupported - if test yes = "$lt_cv_ld_force_load"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec='' - fi - link_all_deplibs=yes - allow_undefined_flag=$_lt_dar_allow_undefined - case $cc_basename in - ifort*|nagfor*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test yes = "$_lt_dar_can_shared"; then - output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" - archive_expsym_cmds="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" - module_expsym_cmds="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" - - else - ld_shlibs=no - fi - - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly* | midnightbsd*) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9*) - if test yes = "$GCC"; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - export_dynamic_flag_spec='$wl-E' - ;; - - hpux10*) - if test yes,no = "$GCC,$with_gnu_ld"; then - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - - hpux11*) - if test yes,no = "$GCC,$with_gnu_ld"; then - case $host_cpu in - hppa*64*) - archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 -printf %s "checking if $CC understands -b... " >&6; } -if test ${lt_cv_prog_compiler__b+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler__b=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -b" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler__b=yes - fi - else - lt_cv_prog_compiler__b=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 -printf '%s\n' "$lt_cv_prog_compiler__b" >&6; } - -if test yes = "$lt_cv_prog_compiler__b"; then - archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' -else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' -fi - - ;; - esac - fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' - hardcode_libdir_separator=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - hardcode_shlibpath_var=no - ;; - *) - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test yes = "$GCC"; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - # Try to use the -exported_symbol ld option, if it does not - # work, assume that -exports_file does not work either and - # implicitly export all symbols. - # This should be the same for all languages, so no per-tag cache variable. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 -printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } -if test ${lt_cv_irix_exported_symbol+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int foo (void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - lt_cv_irix_exported_symbol=yes -else case e in #( - e) lt_cv_irix_exported_symbol=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 -printf '%s\n' "$lt_cv_irix_exported_symbol" >&6; } - if test yes = "$lt_cv_irix_exported_symbol"; then - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' - fi - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - inherit_rpath=yes - link_all_deplibs=yes - ;; - - linux*) - case $cc_basename in - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - ld_shlibs=yes - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - esac - ;; - - *-mlibc) - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - newsos6) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - hardcode_shlibpath_var=no - ;; - - *nto* | *qnx*) - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - hardcode_shlibpath_var=no - hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' - else - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - fi - else - ld_shlibs=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - file_list_spec='@' - ;; - - osf3*) - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - hardcode_libdir_separator=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - archive_cmds_need_lc='no' - hardcode_libdir_separator=: - ;; - - serenity*) - ;; - - solaris*) - no_undefined_flag=' -z defs' - if test yes = "$GCC"; then - wlarc='$wl' - archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - else - case `$CC -V 2>&1` in - *"Compilers 5.0"*) - wlarc='' - archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' - ;; - *) - wlarc='$wl' - archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - ;; - esac - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands '-z linker_flag'. GCC discards it without '$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test yes = "$GCC"; then - whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' - else - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs=yes - ;; - - sunos4*) - if test sequent = "$host_vendor"; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds='$CC -r -o $output$reload_objs' - hardcode_direct=no - ;; - motorola) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='$wl-z,text' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We CANNOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag='$wl-z,text' - allow_undefined_flag='$wl-z,nodefs' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-R,$libdir' - hardcode_libdir_separator=':' - link_all_deplibs=yes - export_dynamic_flag_spec='$wl-Bexport' - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - *) - ld_shlibs=no - ;; - esac - - if test sni = "$host_vendor"; then - case $host in - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='$wl-Blargedynsym' - ;; - esac - fi - fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 -printf '%s\n' "$ld_shlibs" >&6; } -test no = "$ld_shlibs" && can_build_shared=no - -with_gnu_ld=$with_gnu_ld - - - - - - - - - - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc=yes - - if test yes,yes = "$GCC,$enable_shared"; then - case $archive_cmds in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -printf %s "checking whether -lc should be explicitly linked in... " >&6; } -if test ${lt_cv_archive_cmds_need_lc+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc=no - else - lt_cv_archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 -printf '%s\n' "$lt_cv_archive_cmds_need_lc" >&6; } - archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -printf %s "checking dynamic linker characteristics... " >&6; } - -if test yes = "$GCC"; then - case $host_os in - darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; - *) lt_awk_arg='/^libraries:/' ;; - esac - case $host_os in - mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; - *) lt_sed_strip_eq='s|=/|/|g' ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary... - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - # ...but if some path component already ends with the multilib dir we assume - # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). - case "$lt_multi_os_dir; $lt_search_path_spec " in - "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) - lt_multi_os_dir= - ;; - esac - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" - elif test -n "$lt_multi_os_dir"; then - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS = " "; FS = "/|\n";} { - lt_foo = ""; - lt_count = 0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo = "/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[lt_foo]++; } - if (lt_freq[lt_foo] == 1) { print lt_foo; } -}'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's|/\([A-Za-z]:\)|\1|g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=.so -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - - - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='$libname$release$shared_ext$major' - ;; - -aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test ia64 = "$host_cpu"; then - # AIX 5 supports IA64 - library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line '#! .'. This would cause the generated library to - # depend on '.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # Using Import Files as archive members, it is possible to support - # filename-based versioning of shared library archives on AIX. While - # this would work for both with and without runtime linking, it will - # prevent static linking of such archives. So we do filename-based - # shared library versioning with .so extension only, which is used - # when both runtime linking and shared linking is enabled. - # Unfortunately, runtime linking may impact performance, so we do - # not want this to be the default eventually. Also, we use the - # versioned .so libs for executables only if there is the -brtl - # linker flag in LDFLAGS as well, or --enable-aix-soname=svr4 only. - # To allow for filename-based versioning support, we need to create - # libNAME.so.V as an archive file, containing: - # *) an Import File, referring to the versioned filename of the - # archive as well as the shared archive member, telling the - # bitwidth (32 or 64) of that shared object, and providing the - # list of exported symbols of that shared object, eventually - # decorated with the 'weak' keyword - # *) the shared object with the F_LOADONLY flag set, to really avoid - # it being seen by the linker. - # At run time we better use the real file rather than another symlink, - # but for link time we create the symlink libNAME.so -> libNAME.so.V - - case $with_aix_soname,$aix_use_runtimelinking in - # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - aix,yes) # traditional libtool - dynamic_linker='AIX unversionable lib.so' - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - aix,no) # traditional AIX only - dynamic_linker='AIX lib.a(lib.so.V)' - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - ;; - svr4,*) # full svr4 only - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,yes) # both, prefer svr4 - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # unpreferred sharedlib libNAME.a needs extra handling - postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' - postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,no) # both, prefer aix - dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling - postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' - postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' - ;; - esac - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='$libname$shared_ext' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | windows* | pw32* | cegcc*) - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - # If user builds GCC with multilib enabled, - # it should just install on $(libdir) - # not on $(libdir)/../bin or 32 bits dlls would override 64 bit ones. - if test xyes = x"$multilib"; then - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - $install_prog $dir/$dlname $destdir/$dlname~ - chmod a+x $destdir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib $destdir/$dlname'\'' || exit \$?; - fi' - else - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - fi - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" - ;; - mingw* | windows* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl* | *,icl*) - # Native MSVC or ICC - libname_spec='$name' - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - library_names_spec='$libname.dll.lib' - - case $build_os in - mingw* | windows*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec=$LIB - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC and ICC wrapper - library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' - soname_spec='$libname$release$major$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly* | midnightbsd*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - need_version=yes - ;; - esac - case $host_cpu in - powerpc64) - # On FreeBSD bi-arch platforms, a different variable is used for 32-bit - # binaries. See . - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int test_pointer_size[sizeof (void *) - 5]; - -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - shlibpath_var=LD_LIBRARY_PATH -else case e in #( - e) shlibpath_var=LD_32_LIBRARY_PATH ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; - *) - shlibpath_var=LD_LIBRARY_PATH - ;; - esac - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/boot/system/non-packaged/develop/lib /boot/system/develop/lib' - sys_lib_dlsearch_path_spec='/boot/home/config/non-packaged/lib /boot/home/config/lib /boot/system/non-packaged/lib /boot/system/lib' - hardcode_into_libs=no - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - if test 32 = "$HPUX_IA64_MODE"; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - sys_lib_dlsearch_path_spec=/usr/lib/hpux32 - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - sys_lib_dlsearch_path_spec=/usr/lib/hpux64 - fi - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test yes = "$lt_cv_prog_gnu_ld"; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" - sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -linux*android*) - version_type=none # Android doesn't support versioned libraries. - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - dynamic_linker='Android linker' - # -rpath works at least for libraries that are not overridden by - # libraries installed in system locations. - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if test ${lt_cv_shlibpath_overrides_runpath+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null -then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - ;; -esac -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Ideally, we could use ldconfig to report *all* directories which are - # searched for libraries, however this is still not possible. Aside from not - # being certain /sbin/ldconfig is available, command - # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, - # even though it is searched at run-time. Try to do the best guess by - # appending ld.so.conf contents (and includes) to the search path. - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -*-mlibc) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='mlibc ld.so' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec=/usr/lib - need_lib_prefix=no - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - need_version=no - else - need_version=yes - fi - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -os2*) - libname_spec='$name' - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - # OS/2 can only load a DLL with a base name of 8 characters or less. - soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; - v=$($ECHO $release$versuffix | tr -d .-); - n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); - $ECHO $n$v`$shared_ext' - library_names_spec='${libname}_dll.$libext' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=BEGINLIBPATH - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - -rdos*) - dynamic_linker=no - ;; - -serenity*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - dynamic_linker='SerenityOS LibELF' - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test yes = "$with_gnu_ld"; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec; then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' - soname_spec='$libname$shared_ext.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=sco - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test yes = "$with_gnu_ld"; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -emscripten*) - version_type=none - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - dynamic_linker="Emscripten linker" - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test yes = "$GCC"; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - - mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - *flang* | ftn | f18* | f95*) - # Flang compiler. - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | $SED 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *-mlibc) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - serenity*) - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" - ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -printf %s "checking for $compiler option to produce PIC... " >&6; } -if test ${lt_cv_prog_compiler_pic+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test ${lt_cv_prog_compiler_pic_works+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_pic_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_pic_works"; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test ${lt_cv_prog_compiler_static_works+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -printf '%s\n' "$lt_cv_prog_compiler_static_works" >&6; } - -if test yes = "$lt_cv_prog_compiler_static_works"; then - : -else - lt_prog_compiler_static= -fi - - - -='-fPIC' - archive_cmds='$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib' - archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib -s EXPORTED_FUNCTIONS=@$output_objdir/$soname.expsym' - archive_cmds_need_lc=no - no_undefined_flag= - ;; - -*) - dynamic_linker=no - ;; -esac -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -printf '%s\n' "$dynamic_linker" >&6; } -test no = "$dynamic_linker" && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test yes = "$GCC"; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then - sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec -fi - -if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then - sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec -fi - -# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... -configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec - -# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code -func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" - -# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool -configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -printf %s "checking how to hardcode library paths into programs... " >&6; } -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || - test -n "$runpath_var" || - test yes = "$hardcode_automatic"; then - - # We can hardcode non-existent directories. - if test no != "$hardcode_direct" && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && - test no != "$hardcode_minus_L"; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 -printf '%s\n' "$hardcode_action" >&6; } - -if test relink = "$hardcode_action" || - test yes = "$inherit_rpath"; then - # Fast installation is not supported - enable_fast_install=no -elif test yes = "$shlibpath_overrides_runpath" || - test no = "$enable_shared"; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - if test yes != "$enable_dlopen"; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen=load_add_on - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | windows* | pw32* | cegcc*) - lt_cv_dlopen=LoadLibrary - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in #( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in #( - e) - lt_cv_dlopen=dyld - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; -esac -fi - - ;; - - tpf*) - # Don't try to run any link tests for TPF. We know it's impossible - # because TPF is a cross-compiler, and we know how we open DSOs. - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - lt_cv_dlopen_self=no - ;; - - *) - ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" -if test "x$ac_cv_func_shl_load" = xyes -then : - lt_cv_dlopen=shl_load -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 -printf %s "checking for shl_load in -ldld... " >&6; } -if test ${ac_cv_lib_dld_shl_load+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (void); -int -main (void) -{ -return shl_load (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_shl_load=yes -else case e in #( - e) ac_cv_lib_dld_shl_load=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 -printf '%s\n' "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes -then : - lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld -else case e in #( - e) ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes -then : - lt_cv_dlopen=dlopen -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -printf %s "checking for dlopen in -ldl... " >&6; } -if test ${ac_cv_lib_dl_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dl_dlopen=yes -else case e in #( - e) ac_cv_lib_dl_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 -printf %s "checking for dlopen in -lsvld... " >&6; } -if test ${ac_cv_lib_svld_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_svld_dlopen=yes -else case e in #( - e) ac_cv_lib_svld_dlopen=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 -printf '%s\n' "$ac_cv_lib_svld_dlopen" >&6; } -if test "x$ac_cv_lib_svld_dlopen" = xyes -then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 -printf %s "checking for dld_link in -ldld... " >&6; } -if test ${ac_cv_lib_dld_dld_link+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (void); -int -main (void) -{ -return dld_link (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dld_dld_link=yes -else case e in #( - e) ac_cv_lib_dld_dld_link=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 -printf '%s\n' "$ac_cv_lib_dld_dld_link" >&6; } -if test "x$ac_cv_lib_dld_dld_link" = xyes -then : - lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; -esac -fi - - ;; - esac - - if test no = "$lt_cv_dlopen"; then - enable_dlopen=no - else - enable_dlopen=yes - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS=$CPPFLAGS - test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS=$LDFLAGS - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS=$LIBS - LIBS="$lt_cv_dlopen_libs $LIBS" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 -printf %s "checking whether a program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 -printf '%s\n' "$lt_cv_dlopen_self" >&6; } - - if test yes = "$lt_cv_dlopen_self"; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 -printf %s "checking whether a statically linked program can dlopen itself... " >&6; } -if test ${lt_cv_dlopen_self_static+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test yes = "$cross_compiling"; then : - lt_cv_dlopen_self_static=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord (void) __attribute__((visibility("default"))); -#endif - -int fnord (void) { return 42; } -int main (void) -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self_static=no - fi -fi -rm -fr conftest* - - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 -printf '%s\n' "$lt_cv_dlopen_self_static" >&6; } - fi - - CPPFLAGS=$save_CPPFLAGS - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - - - - - - - - - - - - - - - - - -striplib= -old_striplib= -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 -printf %s "checking whether stripping libraries is possible... " >&6; } -if test -z "$STRIP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -else - if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - case $host_os in - darwin*) - # FIXME - insert some real tests, host_os isn't really good enough - striplib="$STRIP -x" - old_striplib="$STRIP -S" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - ;; - freebsd*) - if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then - old_striplib="$STRIP --strip-debug" - striplib="$STRIP --strip-unneeded" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - fi - ;; - *) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - ;; - esac - fi -fi - - - - - - - - - - - - - # Report what library types will actually be built - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 -printf %s "checking if libtool supports shared libraries... " >&6; } - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 -printf '%s\n' "$can_build_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 -printf %s "checking whether to build shared libraries... " >&6; } - test no = "$can_build_shared" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test yes = "$enable_shared" && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - - aix[4-9]*) - if test ia64 != "$host_cpu"; then - case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in - yes,aix,yes) ;; # shared object as lib.so file only - yes,svr4,*) ;; # shared object as lib.so archive member only - yes,*) enable_static=no ;; # shared object in lib.a archive as well - esac - fi - ;; - esac - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 -printf '%s\n' "$enable_shared" >&6; } - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 -printf %s "checking whether to build static libraries... " >&6; } - # Make sure either enable_shared or enable_static is yes. - test yes = "$enable_shared" || enable_static=yes - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 -printf '%s\n' "$enable_static" >&6; } - - - - -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC=$lt_save_CC - - - - - - - - - - - - - - - - ac_config_commands="$ac_config_commands libtool" - - - - -# Only expand once: - - - -# Require xorg-macros minimum of 1.12 for DocBook external references - - - - - - - - - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to detect undeclared functions" >&5 -printf %s "checking for $CC options to detect undeclared functions... " >&6; } -if test ${ac_cv_c_undeclared_builtin_options+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_CFLAGS=$CFLAGS - ac_cv_c_undeclared_builtin_options='cannot detect' - for ac_arg in '' -fno-builtin; do - CFLAGS="$ac_save_CFLAGS $ac_arg" - # This test program should *not* compile successfully. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -(void) strchr; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in #( - e) # This test program should compile successfully. - # No library function is consistently available on - # freestanding implementations, so test against a dummy - # declaration. Include always-available headers on the - # off chance that they somehow elicit warnings. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include -extern void ac_decl (int, char *); - -int -main (void) -{ -(void) ac_decl (0, (char *) 0); - (void) ac_decl; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - if test x"$ac_arg" = x -then : - ac_cv_c_undeclared_builtin_options='none needed' -else case e in #( - e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; -esac -fi - break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - done - CFLAGS=$ac_save_CFLAGS - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 -printf '%s\n' "$ac_cv_c_undeclared_builtin_options" >&6; } - case $ac_cv_c_undeclared_builtin_options in #( - 'cannot detect') : - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot make $CC report undeclared builtins -See 'config.log' for more details" "$LINENO" 5; } ;; #( - 'none needed') : - ac_c_undeclared_builtin_options='' ;; #( - *) : - ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; -esac - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to ignore future-version functions" >&5 -printf %s "checking for $CC options to ignore future-version functions... " >&6; } -if test ${ac_cv_c_future_darwin_options+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_compile_saved="$ac_compile" - ac_compile="$ac_compile -Werror=unguarded-availability-new" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if ! (defined __APPLE__ && defined __MACH__) - #error "-Werror=unguarded-availability-new not needed here" - #endif - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_future_darwin_options='-Werror=unguarded-availability-new' -else case e in #( - e) ac_cv_c_future_darwin_options='none needed' ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_compile="$ac_compile_saved" - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_future_darwin_options" >&5 -printf '%s\n' "$ac_cv_c_future_darwin_options" >&6; } - case $ac_cv_c_future_darwin_options in #( - 'none needed') : - ac_c_future_darwin_options='' ;; #( - *) : - ac_c_future_darwin_options=$ac_cv_c_future_darwin_options ;; -esac - - - - - -ac_fn_check_decl "$LINENO" "__clang__" "ac_cv_have_decl___clang__" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___clang__" = xyes -then : - CLANGCC="yes" -else case e in #( - e) CLANGCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__INTEL_COMPILER" "ac_cv_have_decl___INTEL_COMPILER" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___INTEL_COMPILER" = xyes -then : - INTELCC="yes" -else case e in #( - e) INTELCC="no" ;; -esac -fi -ac_fn_check_decl "$LINENO" "__SUNPRO_C" "ac_cv_have_decl___SUNPRO_C" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" -if test "x$ac_cv_have_decl___SUNPRO_C" = xyes -then : - SUNCC="yes" -else case e in #( - e) SUNCC="no" ;; -esac -fi - - - - - - - - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. -set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -PKG_CONFIG=$ac_cv_path_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -printf '%s\n' "$PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - -fi -if test -z "$ac_cv_path_PKG_CONFIG"; then - ac_pt_PKG_CONFIG=$PKG_CONFIG - # Extract the first word of "pkg-config", so it can be a program name with args. -set dummy pkg-config; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $ac_pt_PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG -if test -n "$ac_pt_PKG_CONFIG"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 -printf '%s\n' "$ac_pt_PKG_CONFIG" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - if test "x$ac_pt_PKG_CONFIG" = x; then - PKG_CONFIG="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - PKG_CONFIG=$ac_pt_PKG_CONFIG - fi -else - PKG_CONFIG="$ac_cv_path_PKG_CONFIG" -fi - -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=0.9.0 - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 -printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - PKG_CONFIG="" - fi -fi - - - - - -# Check whether --enable-selective-werror was given. -if test ${enable_selective_werror+y} -then : - enableval=$enable_selective_werror; SELECTIVE_WERROR=$enableval -else case e in #( - e) SELECTIVE_WERROR=yes ;; -esac -fi - - - - - -# -v is too short to test reliably with XORG_TESTSET_CFLAG -if test "x$SUNCC" = "xyes"; then - BASE_CFLAGS="-v" -else - BASE_CFLAGS="" -fi - -# This chunk of warnings were those that existed in the legacy CWARNFLAGS - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wall" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wall" >&5 -printf %s "checking if $CC supports -Wall... " >&6; } - cacheid=xorg_cv_cc_flag__Wall - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wall" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-arith" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-arith" >&5 -printf %s "checking if $CC supports -Wpointer-arith... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_arith - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-arith" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-declarations" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-declarations" >&5 -printf %s "checking if $CC supports -Wmissing-declarations... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_declarations - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-declarations" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat=2" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat=2" >&5 -printf %s "checking if $CC supports -Wformat=2... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat_2 - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat=2" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wformat" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wformat" >&5 -printf %s "checking if $CC supports -Wformat... " >&6; } - cacheid=xorg_cv_cc_flag__Wformat - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wformat" - found="yes" - fi - fi - - - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wstrict-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wstrict-prototypes" >&5 -printf %s "checking if $CC supports -Wstrict-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wstrict_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wstrict-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-prototypes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-prototypes" >&5 -printf %s "checking if $CC supports -Wmissing-prototypes... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_prototypes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-prototypes" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnested-externs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnested-externs" >&5 -printf %s "checking if $CC supports -Wnested-externs... " >&6; } - cacheid=xorg_cv_cc_flag__Wnested_externs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnested-externs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wbad-function-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wbad-function-cast" >&5 -printf %s "checking if $CC supports -Wbad-function-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wbad_function_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wbad-function-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wold-style-definition" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wold-style-definition" >&5 -printf %s "checking if $CC supports -Wold-style-definition... " >&6; } - cacheid=xorg_cv_cc_flag__Wold_style_definition - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wold-style-definition" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -fd" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -fd" >&5 -printf %s "checking if $CC supports -fd... " >&6; } - cacheid=xorg_cv_cc_flag__fd - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -fd" - found="yes" - fi - fi - - - - - -# This chunk adds additional warnings that could catch undesired effects. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wunused" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wunused" >&5 -printf %s "checking if $CC supports -Wunused... " >&6; } - cacheid=xorg_cv_cc_flag__Wunused - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wunused" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wuninitialized" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wuninitialized" >&5 -printf %s "checking if $CC supports -Wuninitialized... " >&6; } - cacheid=xorg_cv_cc_flag__Wuninitialized - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wuninitialized" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wshadow" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wshadow" >&5 -printf %s "checking if $CC supports -Wshadow... " >&6; } - cacheid=xorg_cv_cc_flag__Wshadow - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wshadow" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-noreturn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-noreturn" >&5 -printf %s "checking if $CC supports -Wmissing-noreturn... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_noreturn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-noreturn" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-format-attribute" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-format-attribute" >&5 -printf %s "checking if $CC supports -Wmissing-format-attribute... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_format_attribute - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-format-attribute" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wredundant-decls" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wredundant-decls" >&5 -printf %s "checking if $CC supports -Wredundant-decls... " >&6; } - cacheid=xorg_cv_cc_flag__Wredundant_decls - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wredundant-decls" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wlogical-op" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wlogical-op" >&5 -printf %s "checking if $CC supports -Wlogical-op... " >&6; } - cacheid=xorg_cv_cc_flag__Wlogical_op - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wlogical-op" - found="yes" - fi - fi - - - -# These are currently disabled because they are noisy. They will be enabled -# in the future once the codebase is sufficiently modernized to silence -# them. For now, I don't want them to drown out the other warnings. -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wparentheses]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-align]) -# XORG_TESTSET_CFLAG([[BASE_]PREFIX[FLAGS]], [-Wcast-qual]) - -# Turn some warnings into errors, so we don't accidentally get successful builds -# when there are problems that should be fixed. - -if test "x$SELECTIVE_WERROR" = "xyes" ; then - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=implicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=implicit" >&5 -printf %s "checking if $CC supports -Werror=implicit... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_implicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=implicit" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" >&5 -printf %s "checking if $CC supports -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_NO_EXPLICIT_TYPE_GIVEN__errwarn_E_NO_IMPLICIT_DECL_ALLOWED - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_NO_EXPLICIT_TYPE_GIVEN -errwarn=E_NO_IMPLICIT_DECL_ALLOWED" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=nonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=nonnull" >&5 -printf %s "checking if $CC supports -Werror=nonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_nonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=nonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=init-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=init-self" >&5 -printf %s "checking if $CC supports -Werror=init-self... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_init_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=init-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=main" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=main" >&5 -printf %s "checking if $CC supports -Werror=main... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_main - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=main" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=missing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=missing-braces" >&5 -printf %s "checking if $CC supports -Werror=missing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_missing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=missing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=sequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=sequence-point" >&5 -printf %s "checking if $CC supports -Werror=sequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_sequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=sequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=return-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=return-type" >&5 -printf %s "checking if $CC supports -Werror=return-type... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_return_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=return-type" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT" >&5 -printf %s "checking if $CC supports -errwarn=E_FUNC_HAS_NO_RETURN_STMT... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_FUNC_HAS_NO_RETURN_STMT - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_FUNC_HAS_NO_RETURN_STMT" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=trigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=trigraphs" >&5 -printf %s "checking if $CC supports -Werror=trigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_trigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=trigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=array-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=array-bounds" >&5 -printf %s "checking if $CC supports -Werror=array-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_array_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=array-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=write-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=write-strings" >&5 -printf %s "checking if $CC supports -Werror=write-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_write_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=write-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=address" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=address" >&5 -printf %s "checking if $CC supports -Werror=address... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_address - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=address" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=int-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=int-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Werror=int-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_int_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=int-to-pointer-cast" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION" >&5 -printf %s "checking if $CC supports -errwarn=E_BAD_PTR_INT_COMBINATION... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn_E_BAD_PTR_INT_COMBINATION - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -errwarn=E_BAD_PTR_INT_COMBINATION" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=pointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=pointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Werror=pointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_pointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Werror=pointer-to-int-cast" - found="yes" - fi - fi - - # Also -errwarn=E_BAD_PTR_INT_COMBINATION -else -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&5 -printf '%s\n' "$as_me: WARNING: You have chosen not to turn some select compiler warnings into errors. This should not be necessary. Please report why you needed to do so in a bug report at $PACKAGE_BUGREPORT" >&2;} - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wimplicit" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wimplicit" >&5 -printf %s "checking if $CC supports -Wimplicit... " >&6; } - cacheid=xorg_cv_cc_flag__Wimplicit - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wimplicit" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wnonnull" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wnonnull" >&5 -printf %s "checking if $CC supports -Wnonnull... " >&6; } - cacheid=xorg_cv_cc_flag__Wnonnull - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wnonnull" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Winit-self" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Winit-self" >&5 -printf %s "checking if $CC supports -Winit-self... " >&6; } - cacheid=xorg_cv_cc_flag__Winit_self - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Winit-self" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmain" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmain" >&5 -printf %s "checking if $CC supports -Wmain... " >&6; } - cacheid=xorg_cv_cc_flag__Wmain - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmain" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wmissing-braces" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wmissing-braces" >&5 -printf %s "checking if $CC supports -Wmissing-braces... " >&6; } - cacheid=xorg_cv_cc_flag__Wmissing_braces - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wmissing-braces" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wsequence-point" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wsequence-point" >&5 -printf %s "checking if $CC supports -Wsequence-point... " >&6; } - cacheid=xorg_cv_cc_flag__Wsequence_point - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wsequence-point" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wreturn-type" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wreturn-type" >&5 -printf %s "checking if $CC supports -Wreturn-type... " >&6; } - cacheid=xorg_cv_cc_flag__Wreturn_type - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wreturn-type" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wtrigraphs" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wtrigraphs" >&5 -printf %s "checking if $CC supports -Wtrigraphs... " >&6; } - cacheid=xorg_cv_cc_flag__Wtrigraphs - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wtrigraphs" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Warray-bounds" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Warray-bounds" >&5 -printf %s "checking if $CC supports -Warray-bounds... " >&6; } - cacheid=xorg_cv_cc_flag__Warray_bounds - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Warray-bounds" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wwrite-strings" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wwrite-strings" >&5 -printf %s "checking if $CC supports -Wwrite-strings... " >&6; } - cacheid=xorg_cv_cc_flag__Wwrite_strings - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wwrite-strings" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Waddress" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Waddress" >&5 -printf %s "checking if $CC supports -Waddress... " >&6; } - cacheid=xorg_cv_cc_flag__Waddress - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Waddress" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wint-to-pointer-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wint-to-pointer-cast" >&5 -printf %s "checking if $CC supports -Wint-to-pointer-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wint_to_pointer_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wint-to-pointer-cast" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Wpointer-to-int-cast" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wpointer-to-int-cast" >&5 -printf %s "checking if $CC supports -Wpointer-to-int-cast... " >&6; } - cacheid=xorg_cv_cc_flag__Wpointer_to_int_cast - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - BASE_CFLAGS="$BASE_CFLAGS -Wpointer-to-int-cast" - found="yes" - fi - fi - - -fi - - - - - - - - CWARNFLAGS="$BASE_CFLAGS" - if test "x$GCC" = xyes ; then - CWARNFLAGS="$CWARNFLAGS -fno-strict-aliasing" - fi - - - - - - - - -# Check whether --enable-strict-compilation was given. -if test ${enable_strict_compilation+y} -then : - enableval=$enable_strict_compilation; STRICT_COMPILE=$enableval -else case e in #( - e) STRICT_COMPILE=no ;; -esac -fi - - - - - - -STRICT_CFLAGS="" - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -pedantic" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -pedantic" >&5 -printf %s "checking if $CC supports -pedantic... " >&6; } - cacheid=xorg_cv_cc_flag__pedantic - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -pedantic" - found="yes" - fi - fi - - - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror" >&5 -printf %s "checking if $CC supports -Werror... " >&6; } - cacheid=xorg_cv_cc_flag__Werror - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror" - found="yes" - fi - fi - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -errwarn" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -errwarn" >&5 -printf %s "checking if $CC supports -errwarn... " >&6; } - cacheid=xorg_cv_cc_flag__errwarn - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -errwarn" - found="yes" - fi - fi - - - -# Earlier versions of gcc (eg: 4.2) support -Werror=attributes, but do not -# activate it with -Werror, so we add it here explicitly. - - - - - - - - - - - - - -xorg_testset_save_CFLAGS="$CFLAGS" - -if test "x$xorg_testset_cc_unknown_warning_option" = "x" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking if $CC supports -Werror=unknown-warning-option... " >&6; } -if test ${xorg_cv_cc_flag_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unknown_warning_option=yes -else case e in #( - e) xorg_cv_cc_flag_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unknown_warning_option" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unknown_warning_option" >&6; } - xorg_testset_cc_unknown_warning_option=$xorg_cv_cc_flag_unknown_warning_option - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -if test "x$xorg_testset_cc_unused_command_line_argument" = "x" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=unused-command-line-argument" >&5 -printf %s "checking if $CC supports -Werror=unused-command-line-argument... " >&6; } -if test ${xorg_cv_cc_flag_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - xorg_cv_cc_flag_unused_command_line_argument=yes -else case e in #( - e) xorg_cv_cc_flag_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xorg_cv_cc_flag_unused_command_line_argument" >&5 -printf '%s\n' "$xorg_cv_cc_flag_unused_command_line_argument" >&6; } - xorg_testset_cc_unused_command_line_argument=$xorg_cv_cc_flag_unused_command_line_argument - CFLAGS="$xorg_testset_save_CFLAGS" -fi - -found="no" - - if test $found = "no" ; then - if test "x$xorg_testset_cc_unknown_warning_option" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unknown-warning-option" - fi - - if test "x$xorg_testset_cc_unused_command_line_argument" = "xyes" ; then - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" - fi - - CFLAGS="$CFLAGS -Werror=attributes" - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror=attributes" >&5 -printf %s "checking if $CC supports -Werror=attributes... " >&6; } - cacheid=xorg_cv_cc_flag__Werror_attributes - if eval test \${$cacheid+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval $cacheid=yes -else case e in #( - e) eval $cacheid=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi - - - CFLAGS="$xorg_testset_save_CFLAGS" - - eval supported=\$$cacheid - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $supported" >&5 -printf '%s\n' "$supported" >&6; } - if test "$supported" = "yes" ; then - STRICT_CFLAGS="$STRICT_CFLAGS -Werror=attributes" - found="yes" - fi - fi - - - -if test "x$STRICT_COMPILE" = "xyes"; then - BASE_CFLAGS="$BASE_CFLAGS $STRICT_CFLAGS" - CWARNFLAGS="$CWARNFLAGS $STRICT_CFLAGS" -fi - - - - - - - - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION_MAJOR `echo $PACKAGE_VERSION | cut -d . -f 1` -_ACEOF - - PVM=`echo $PACKAGE_VERSION | cut -d . -f 2 | cut -d - -f 1` - if test "x$PVM" = "x"; then - PVM="0" - fi - -printf '%s\n' "#define PACKAGE_VERSION_MINOR $PVM" >>confdefs.h - - PVP=`echo $PACKAGE_VERSION | cut -d . -f 3 | cut -d - -f 1` - if test "x$PVP" = "x"; then - PVP="0" - fi - -printf '%s\n' "#define PACKAGE_VERSION_PATCHLEVEL $PVP" >>confdefs.h - - - -CHANGELOG_CMD="((GIT_DIR=\$(top_srcdir)/.git git log > \$(top_srcdir)/.changelog.tmp) 2>/dev/null && \ -mv \$(top_srcdir)/.changelog.tmp \$(top_srcdir)/ChangeLog) \ -|| (rm -f \$(top_srcdir)/.changelog.tmp; test -e \$(top_srcdir)/ChangeLog || ( \ -touch \$(top_srcdir)/ChangeLog; \ -echo 'git failed to create ChangeLog: installing empty ChangeLog.' >&2))" - - - - -macros_datadir=`$PKG_CONFIG --print-errors --variable=pkgdatadir xorg-macros` -INSTALL_CMD="(cp -f "$macros_datadir/INSTALL" \$(top_srcdir)/.INSTALL.tmp && \ -mv \$(top_srcdir)/.INSTALL.tmp \$(top_srcdir)/INSTALL) \ -|| (rm -f \$(top_srcdir)/.INSTALL.tmp; test -e \$(top_srcdir)/INSTALL || ( \ -touch \$(top_srcdir)/INSTALL; \ -echo 'failed to copy INSTALL from util-macros: installing empty INSTALL.' >&2))" - - - - - - -case $host_os in - solaris*) - # Solaris 2.0 - 11.3 use SysV man page section numbers, so we - # check for a man page file found in later versions that use - # traditional section numbers instead - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for /usr/share/man/man7/attributes.7" >&5 -printf %s "checking for /usr/share/man/man7/attributes.7... " >&6; } -if test ${ac_cv_file__usr_share_man_man7_attributes_7+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) test "$cross_compiling" = yes && - as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 -if test -r "/usr/share/man/man7/attributes.7"; then - ac_cv_file__usr_share_man_man7_attributes_7=yes -else - ac_cv_file__usr_share_man_man7_attributes_7=no -fi ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__usr_share_man_man7_attributes_7" >&5 -printf '%s\n' "$ac_cv_file__usr_share_man_man7_attributes_7" >&6; } -if test "x$ac_cv_file__usr_share_man_man7_attributes_7" = xyes -then : - SYSV_MAN_SECTIONS=false -else case e in #( - e) SYSV_MAN_SECTIONS=true ;; -esac -fi - - ;; - *) SYSV_MAN_SECTIONS=false ;; -esac - -if test x$APP_MAN_SUFFIX = x ; then - APP_MAN_SUFFIX=1 -fi -if test x$APP_MAN_DIR = x ; then - APP_MAN_DIR='$(mandir)/man$(APP_MAN_SUFFIX)' -fi - -if test x$LIB_MAN_SUFFIX = x ; then - LIB_MAN_SUFFIX=3 -fi -if test x$LIB_MAN_DIR = x ; then - LIB_MAN_DIR='$(mandir)/man$(LIB_MAN_SUFFIX)' -fi - -if test x$FILE_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) FILE_MAN_SUFFIX=4 ;; - *) FILE_MAN_SUFFIX=5 ;; - esac -fi -if test x$FILE_MAN_DIR = x ; then - FILE_MAN_DIR='$(mandir)/man$(FILE_MAN_SUFFIX)' -fi - -if test x$MISC_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) MISC_MAN_SUFFIX=5 ;; - *) MISC_MAN_SUFFIX=7 ;; - esac -fi -if test x$MISC_MAN_DIR = x ; then - MISC_MAN_DIR='$(mandir)/man$(MISC_MAN_SUFFIX)' -fi - -if test x$DRIVER_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) DRIVER_MAN_SUFFIX=7 ;; - *) DRIVER_MAN_SUFFIX=4 ;; - esac -fi -if test x$DRIVER_MAN_DIR = x ; then - DRIVER_MAN_DIR='$(mandir)/man$(DRIVER_MAN_SUFFIX)' -fi - -if test x$ADMIN_MAN_SUFFIX = x ; then - case $SYSV_MAN_SECTIONS in - true) ADMIN_MAN_SUFFIX=1m ;; - *) ADMIN_MAN_SUFFIX=8 ;; - esac -fi -if test x$ADMIN_MAN_DIR = x ; then - ADMIN_MAN_DIR='$(mandir)/man$(ADMIN_MAN_SUFFIX)' -fi - - - - - - - - - - - - - - - -XORG_MAN_PAGE="X Version 11" - -MAN_SUBSTS="\ - -e 's|__vendorversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xorgversion__|\"\$(PACKAGE_STRING)\" \"\$(XORG_MAN_PAGE)\"|' \ - -e 's|__xservername__|Xorg|g' \ - -e 's|__xconfigfile__|xorg.conf|g' \ - -e 's|__projectroot__|\$(prefix)|g' \ - -e 's|__apploaddir__|\$(appdefaultdir)|g' \ - -e 's|__appmansuffix__|\$(APP_MAN_SUFFIX)|g' \ - -e 's|__drivermansuffix__|\$(DRIVER_MAN_SUFFIX)|g' \ - -e 's|__adminmansuffix__|\$(ADMIN_MAN_SUFFIX)|g' \ - -e 's|__libmansuffix__|\$(LIB_MAN_SUFFIX)|g' \ - -e 's|__miscmansuffix__|\$(MISC_MAN_SUFFIX)|g' \ - -e 's|__filemansuffix__|\$(FILE_MAN_SUFFIX)|g'" - - - - -AM_DEFAULT_VERBOSITY=0 - - - - - - -# Check whether --enable-specs was given. -if test ${enable_specs+y} -then : - enableval=$enable_specs; build_specs=$enableval -else case e in #( - e) build_specs=yes ;; -esac -fi - - - if test x$build_specs = xyes; then - ENABLE_SPECS_TRUE= - ENABLE_SPECS_FALSE='#' -else - ENABLE_SPECS_TRUE='#' - ENABLE_SPECS_FALSE= -fi - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to build functional specifications" >&5 -printf %s "checking whether to build functional specifications... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $build_specs" >&5 -printf '%s\n' "$build_specs" >&6; } - - - - - -# Check whether --with-xmlto was given. -if test ${with_xmlto+y} -then : - withval=$with_xmlto; use_xmlto=$withval -else case e in #( - e) use_xmlto=auto ;; -esac -fi - - - -if test "x$use_xmlto" = x"auto"; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto not found - documentation targets will be skipped" >&2;} - have_xmlto=no - else - have_xmlto=yes - fi -elif test "x$use_xmlto" = x"yes" ; then - # Extract the first word of "xmlto", so it can be a program name with args. -set dummy xmlto; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XMLTO+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $XMLTO in - [\\/]* | ?:[\\/]*) - ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XMLTO="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XMLTO=$ac_cv_path_XMLTO -if test -n "$XMLTO"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XMLTO" >&5 -printf '%s\n' "$XMLTO" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XMLTO" = "x"; then - as_fn_error $? "--with-xmlto=yes specified but xmlto not found in PATH" "$LINENO" 5 - fi - have_xmlto=yes -elif test "x$use_xmlto" = x"no" ; then - if test "x$XMLTO" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XMLTO environment variable since --with-xmlto=no was specified" >&2;} - fi - have_xmlto=no -else - as_fn_error $? "--with-xmlto expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of xmlto, if provided. -if test "$have_xmlto" = yes; then - # scrape the xmlto version - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking the xmlto version" >&5 -printf %s "checking the xmlto version... " >&6; } - xmlto_version=`$XMLTO --version 2>/dev/null | cut -d' ' -f3` - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $xmlto_version" >&5 -printf '%s\n' "$xmlto_version" >&6; } - as_arg_v1=$xmlto_version -as_arg_v2=0.0.22 -awk "$as_awk_strverscmp" v1="$as_arg_v1" v2="$as_arg_v2" /dev/null -case $? in #( - 1) : - if test "x$use_xmlto" = xauto; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&5 -printf '%s\n' "$as_me: WARNING: xmlto version $xmlto_version found, but 0.0.22 needed" >&2;} - have_xmlto=no - else - as_fn_error $? "xmlto version $xmlto_version found, but 0.0.22 needed" "$LINENO" 5 - fi ;; #( - 0) : - ;; #( - 2) : - ;; #( - *) : - ;; -esac -fi - -# Test for the ability of xmlto to generate a text target -# -# NOTE: xmlto 0.0.27 or higher return a non-zero return code in the -# following test for empty XML docbook files. -# For compatibility reasons use the following empty XML docbook file and if -# it fails try it again with a non-empty XML file. -have_xmlto_text=no -cat > conftest.xml << "EOF" -EOF -if test "$have_xmlto" = yes -then : - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in #( - e) # Try it again with a non-empty XML file. - cat > conftest.xml << "EOF" - -EOF - if $XMLTO --skip-validation txt conftest.xml >/dev/null 2>&1 -then : - have_xmlto_text=yes -else case e in #( - e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xmlto cannot generate text format, this format skipped" >&5 -printf '%s\n' "$as_me: WARNING: xmlto cannot generate text format, this format skipped" >&2;} ;; -esac -fi ;; -esac -fi -fi -rm -f conftest.xml - if test $have_xmlto_text = yes; then - HAVE_XMLTO_TEXT_TRUE= - HAVE_XMLTO_TEXT_FALSE='#' -else - HAVE_XMLTO_TEXT_TRUE='#' - HAVE_XMLTO_TEXT_FALSE= -fi - - if test "$have_xmlto" = yes; then - HAVE_XMLTO_TRUE= - HAVE_XMLTO_FALSE='#' -else - HAVE_XMLTO_TRUE='#' - HAVE_XMLTO_FALSE= -fi - - - - - - -# Check whether --with-fop was given. -if test ${with_fop+y} -then : - withval=$with_fop; use_fop=$withval -else case e in #( - e) use_fop=auto ;; -esac -fi - - - -if test "x$use_fop" = x"auto"; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: fop not found - documentation targets will be skipped" >&5 -printf '%s\n' "$as_me: WARNING: fop not found - documentation targets will be skipped" >&2;} - have_fop=no - else - have_fop=yes - fi -elif test "x$use_fop" = x"yes" ; then - # Extract the first word of "fop", so it can be a program name with args. -set dummy fop; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_FOP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $FOP in - [\\/]* | ?:[\\/]*) - ac_cv_path_FOP="$FOP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_FOP="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -FOP=$ac_cv_path_FOP -if test -n "$FOP"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -printf '%s\n' "$FOP" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$FOP" = "x"; then - as_fn_error $? "--with-fop=yes specified but fop not found in PATH" "$LINENO" 5 - fi - have_fop=yes -elif test "x$use_fop" = x"no" ; then - if test "x$FOP" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring FOP environment variable since --with-fop=no was specified" >&2;} - fi - have_fop=no -else - as_fn_error $? "--with-fop expects 'yes' or 'no'" "$LINENO" 5 -fi - -# Test for a minimum version of fop, if provided. - - if test "$have_fop" = yes; then - HAVE_FOP_TRUE= - HAVE_FOP_FALSE='#' -else - HAVE_FOP_TRUE='#' - HAVE_FOP_FALSE= -fi - - - - -# Preserves the interface, should it be implemented later - - - -# Check whether --with-xsltproc was given. -if test ${with_xsltproc+y} -then : - withval=$with_xsltproc; use_xsltproc=$withval -else case e in #( - e) use_xsltproc=auto ;; -esac -fi - - - -if test "x$use_xsltproc" = x"auto"; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: xsltproc not found - cannot transform XML documents" >&5 -printf '%s\n' "$as_me: WARNING: xsltproc not found - cannot transform XML documents" >&2;} - have_xsltproc=no - else - have_xsltproc=yes - fi -elif test "x$use_xsltproc" = x"yes" ; then - # Extract the first word of "xsltproc", so it can be a program name with args. -set dummy xsltproc; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_XSLTPROC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $XSLTPROC in - [\\/]* | ?:[\\/]*) - ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -XSLTPROC=$ac_cv_path_XSLTPROC -if test -n "$XSLTPROC"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf '%s\n' "$XSLTPROC" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$XSLTPROC" = "x"; then - as_fn_error $? "--with-xsltproc=yes specified but xsltproc not found in PATH" "$LINENO" 5 - fi - have_xsltproc=yes -elif test "x$use_xsltproc" = x"no" ; then - if test "x$XSLTPROC" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring XSLTPROC environment variable since --with-xsltproc=no was specified" >&2;} - fi - have_xsltproc=no -else - as_fn_error $? "--with-xsltproc expects 'yes' or 'no'" "$LINENO" 5 -fi - - if test "$have_xsltproc" = yes; then - HAVE_XSLTPROC_TRUE= - HAVE_XSLTPROC_FALSE='#' -else - HAVE_XSLTPROC_TRUE='#' - HAVE_XSLTPROC_FALSE= -fi - - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for X.Org SGML entities >= 1.8" >&5 -printf %s "checking for X.Org SGML entities >= 1.8... " >&6; } -XORG_SGML_PATH= -if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xorg-sgml-doctools >= 1.8\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xorg-sgml-doctools >= 1.8") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - XORG_SGML_PATH=`$PKG_CONFIG --variable=sgmlrootdir xorg-sgml-doctools` -else - : - -fi - -# Define variables STYLESHEET_SRCDIR and XSL_STYLESHEET containing -# the path and the name of the doc stylesheet -if test "x$XORG_SGML_PATH" != "x" ; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XORG_SGML_PATH" >&5 -printf '%s\n' "$XORG_SGML_PATH" >&6; } - STYLESHEET_SRCDIR=$XORG_SGML_PATH/X11 - XSL_STYLESHEET=$STYLESHEET_SRCDIR/xorg.xsl -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - - - if test "x$XSL_STYLESHEET" != "x"; then - HAVE_STYLESHEETS_TRUE= - HAVE_STYLESHEETS_FALSE='#' -else - HAVE_STYLESHEETS_TRUE='#' - HAVE_STYLESHEETS_FALSE= -fi - - - -# Check whether --enable-malloc0returnsnull was given. -if test ${enable_malloc0returnsnull+y} -then : - enableval=$enable_malloc0returnsnull; MALLOC_ZERO_RETURNS_NULL=$enableval -else case e in #( - e) MALLOC_ZERO_RETURNS_NULL=yes ;; -esac -fi - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to act as if malloc(0) can return NULL" >&5 -printf %s "checking whether to act as if malloc(0) can return NULL... " >&6; } -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MALLOC_ZERO_RETURNS_NULL" >&5 -printf '%s\n' "$MALLOC_ZERO_RETURNS_NULL" >&6; } - -if test "x$MALLOC_ZERO_RETURNS_NULL" = xyes; then - MALLOC_ZERO_CFLAGS="-DMALLOC_0_RETURNS_NULL" - XMALLOC_ZERO_CFLAGS=$MALLOC_ZERO_CFLAGS - XTMALLOC_ZERO_CFLAGS="$MALLOC_ZERO_CFLAGS -DXTMALLOC_BC" -else - MALLOC_ZERO_CFLAGS="" - XMALLOC_ZERO_CFLAGS="" - XTMALLOC_ZERO_CFLAGS="" -fi - - - - - - -# Determine .so library version per platform -# based on SharedXextRev in monolith xc/config/cf/*Lib.tmpl -if test "x$XEXT_SOREV" = "x" ; then - case $host_os in - openbsd*) XEXT_SOREV=8:0 ;; - solaris*) XEXT_SOREV=0 ;; - *) XEXT_SOREV=6:4:0 ;; - esac -fi - - -# Obtain compiler/linker options for dependencies - -pkg_failed=no -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" >&5 -printf %s "checking for xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99... " >&6; } - -if test -n "$XEXT_CFLAGS"; then - pkg_cv_XEXT_CFLAGS="$XEXT_CFLAGS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_CFLAGS=`$PKG_CONFIG --cflags "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi -if test -n "$XEXT_LIBS"; then - pkg_cv_XEXT_LIBS="$XEXT_LIBS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99") 2>&5 - ac_status=$? - printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_XEXT_LIBS=`$PKG_CONFIG --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi - - - -if test $pkg_failed = yes; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi - if test $_pkg_short_errors_supported = yes; then - XEXT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - else - XEXT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$XEXT_PKG_ERRORS" >&5 - - as_fn_error $? "Package requirements (xproto >= 7.0.13 x11 >= 1.6 xextproto >= 7.1.99) were not met: - -$XEXT_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details." "$LINENO" 5 -elif test $pkg_failed = untried; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -Alternatively, you may set the environment variables XEXT_CFLAGS -and XEXT_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details. - -To get pkg-config, see . -See 'config.log' for more details" "$LINENO" 5; } -else - XEXT_CFLAGS=$pkg_cv_XEXT_CFLAGS - XEXT_LIBS=$pkg_cv_XEXT_LIBS - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf '%s\n' "yes" >&6; } - -fi - - - - - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for __builtin_popcountl" >&5 -printf %s "checking for __builtin_popcountl... " >&6; } -if test ${ax_cv_have___builtin_popcountl+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - __builtin_popcountl(0) - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ax_cv_have___builtin_popcountl=yes -else case e in #( - e) ax_cv_have___builtin_popcountl=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ;; -esac -fi -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have___builtin_popcountl" >&5 -printf '%s\n' "$ax_cv_have___builtin_popcountl" >&6; } - - if test yes = $ax_cv_have___builtin_popcountl -then : - -printf '%s\n' "#define HAVE___BUILTIN_POPCOUNTL 1" >>confdefs.h - -fi - - - -ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" -if test "x$ac_cv_func_reallocarray" = xyes -then : - printf '%s\n' "#define HAVE_REALLOCARRAY 1" >>confdefs.h - -else case e in #( - e) case " $LIBOBJS " in - *" reallocarray.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" - ;; -esac - ;; -esac -fi - - -# Allow checking code with lint, sparse, etc. - - - - - -# Check whether --with-lint was given. -if test ${with_lint+y} -then : - withval=$with_lint; use_lint=$withval -else case e in #( - e) use_lint=no ;; -esac -fi - - -# Obtain platform specific info like program name and options -# The lint program on FreeBSD and NetBSD is different from the one on Solaris -case $host_os in - *linux* | *openbsd* | kfreebsd*-gnu | darwin* | cygwin*) - lint_name=splint - lint_options="-badflag" - ;; - *freebsd* | *netbsd*) - lint_name=lint - lint_options="-u -b" - ;; - *solaris*) - lint_name=lint - lint_options="-u -b -h -erroff=E_INDISTING_FROM_TRUNC2" - ;; -esac - -# Test for the presence of the program (either guessed by the code or spelled out by the user) -if test "x$use_lint" = x"yes" ; then - # Extract the first word of "$lint_name", so it can be a program name with args. -set dummy $lint_name; ac_word=$2 -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_LINT+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $LINT in - [\\/]* | ?:[\\/]*) - ac_cv_path_LINT="$LINT" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_LINT="$as_dir$ac_word$ac_exec_ext" - printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac ;; -esac -fi -LINT=$ac_cv_path_LINT -if test -n "$LINT"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LINT" >&5 -printf '%s\n' "$LINT" >&6; } -else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf '%s\n' "no" >&6; } -fi - - - if test "x$LINT" = "x"; then - as_fn_error $? "--with-lint=yes specified but lint-style tool not found in PATH" "$LINENO" 5 - fi -elif test "x$use_lint" = x"no" ; then - if test "x$LINT" != "x"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&5 -printf '%s\n' "$as_me: WARNING: ignoring LINT environment variable since --with-lint=no was specified" >&2;} - fi -else - as_fn_error $? "--with-lint expects 'yes' or 'no'. Use LINT variable to specify path." "$LINENO" 5 -fi - -# User supplied flags override default flags -if test "x$LINT_FLAGS" != "x"; then - lint_options=$LINT_FLAGS -fi - -LINT_FLAGS=$lint_options - - if test "x$LINT" != x; then - LINT_TRUE= - LINT_FALSE='#' -else - LINT_TRUE='#' - LINT_FALSE= -fi - - - - - -# Check whether --enable-lint-library was given. -if test ${enable_lint_library+y} -then : - enableval=$enable_lint_library; make_lint_lib=$enableval -else case e in #( - e) make_lint_lib=no ;; -esac -fi - - -if test "x$make_lint_lib" = x"yes" ; then - LINTLIB=llib-lXext.ln - if test "x$LINT" = "x"; then - as_fn_error $? "Cannot make lint library without --with-lint" "$LINENO" 5 - fi -elif test "x$make_lint_lib" != x"no" ; then - as_fn_error $? "--enable-lint-library expects 'yes' or 'no'." "$LINENO" 5 -fi - - - if test x$make_lint_lib != xno; then - MAKE_LINT_LIB_TRUE= - MAKE_LINT_LIB_FALSE='#' -else - MAKE_LINT_LIB_TRUE='#' - MAKE_LINT_LIB_FALSE= -fi - - - - -ac_config_files="$ac_config_files Makefile man/Makefile src/Makefile specs/Makefile xext.pc" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# 'ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* 'ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -ac_cache_dump | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -printf '%s\n' "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -printf '%s\n' "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`printf '%s\n' "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -printf %s "checking that generated files are newer than configure... " >&6; } - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: done" >&5 -printf '%s\n' "done" >&6; } -if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then - as_fn_error $? "conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -case $enable_silent_rules in # ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; -esac -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi - - if test -n "$EXEEXT"; then - am__EXEEXT_TRUE= - am__EXEEXT_FALSE='#' -else - am__EXEEXT_TRUE='#' - am__EXEEXT_FALSE= -fi - -if test -z "${ENABLE_SPECS_TRUE}" && test -z "${ENABLE_SPECS_FALSE}"; then - as_fn_error $? "conditional \"ENABLE_SPECS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TEXT_TRUE}" && test -z "${HAVE_XMLTO_TEXT_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO_TEXT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XMLTO_TRUE}" && test -z "${HAVE_XMLTO_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XMLTO\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_FOP_TRUE}" && test -z "${HAVE_FOP_FALSE}"; then - as_fn_error $? "conditional \"HAVE_FOP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_XSLTPROC_TRUE}" && test -z "${HAVE_XSLTPROC_FALSE}"; then - as_fn_error $? "conditional \"HAVE_XSLTPROC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_STYLESHEETS_TRUE}" && test -z "${HAVE_STYLESHEETS_FALSE}"; then - as_fn_error $? "conditional \"HAVE_STYLESHEETS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${LINT_TRUE}" && test -z "${LINT_FALSE}"; then - as_fn_error $? "conditional \"LINT\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${MAKE_LINT_LIB_TRUE}" && test -z "${MAKE_LINT_LIB_FALSE}"; then - as_fn_error $? "conditional \"MAKE_LINT_LIB\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: "${CONFIG_STATUS=./config.status}" -case $CONFIG_STATUS in #( - -*) : - CONFIG_STATUS=./$CONFIG_STATUS ;; #( - */*) : - ;; #( - *) : - CONFIG_STATUS=./$CONFIG_STATUS ;; -esac - -ac_write_fail=0 -ac_clean_CONFIG_STATUS='"$CONFIG_STATUS"' -{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -printf '%s\n' "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >"$CONFIG_STATUS" <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>"$CONFIG_STATUS" <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # contradicts POSIX and common usage. Disable this. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in #( - e) case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf '%s\n' "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in #( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in #( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - -exec 6>&1 -## ------------------------------------- ## -## Main body of "$CONFIG_STATUS" script. ## -## ------------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by libXext $as_me 1.3.7, which was -generated by GNU Autoconf 2.73. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -'$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` -ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_cs_config='$ac_cs_config_escaped' -ac_cs_version="\\ -libXext config.status 1.3.7 -configured by $0, generated by GNU Autoconf 2.73, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2026 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -AWK='$AWK' -test -n "\$AWK" || { - awk '' >"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - printf '%s\n' "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - printf '%s\n' "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: '$1' -Try '$0 --help' for more information.";; - --help | --hel | -h ) - printf '%s\n' "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: '$1' -Try '$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \printf '%s\n' "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - printf '%s\n' "$ac_log" -} >&5 - -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" - - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='$sed_quote_subst' -double_quote_subst='$double_quote_subst' -delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' -macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' -enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' -enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' -pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' -shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' -SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' -ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' -PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' -host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' -host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' -host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' -build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' -build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' -build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' -SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' -Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' -GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' -EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' -FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' -LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' -NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' -LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' -ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' -exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' -lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' -lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' -lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' -reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' -FILECMD='`$ECHO "$FILECMD" | $SED "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' -file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' -want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' -DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' -sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' -AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' -lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' -archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' -STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' -RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' -lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' -CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' -compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' -GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' -lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' -nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' -lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' -lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' -objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' -need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' -MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' -LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' -OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' -libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' -module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' -postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' -need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' -version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' -runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' -libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' -soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' -install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' -finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' -configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' -old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' -striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' - -LTCC='$LTCC' -LTCFLAGS='$LTCFLAGS' -compiler='$compiler_DEFAULT' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in SHELL \ -ECHO \ -PATH_SEPARATOR \ -SED \ -GREP \ -EGREP \ -FGREP \ -LD \ -NM \ -LN_S \ -lt_SP2NL \ -lt_NL2SP \ -reload_flag \ -FILECMD \ -OBJDUMP \ -deplibs_check_method \ -file_magic_cmd \ -file_magic_glob \ -want_nocaseglob \ -DLLTOOL \ -sharedlib_from_linklib_cmd \ -AR \ -archiver_list_spec \ -STRIP \ -RANLIB \ -CC \ -CFLAGS \ -compiler \ -lt_cv_sys_global_symbol_pipe \ -lt_cv_sys_global_symbol_to_cdecl \ -lt_cv_sys_global_symbol_to_import \ -lt_cv_sys_global_symbol_to_c_name_address \ -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -lt_cv_nm_interface \ -nm_file_list_spec \ -lt_cv_truncate_bin \ -lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_pic \ -lt_prog_compiler_wl \ -lt_prog_compiler_static \ -lt_cv_prog_compiler_c_o \ -need_locks \ -MANIFEST_TOOL \ -DSYMUTIL \ -NMEDIT \ -LIPO \ -OTOOL \ -OTOOL64 \ -shrext_cmds \ -export_dynamic_flag_spec \ -whole_archive_flag_spec \ -compiler_needs_object \ -with_gnu_ld \ -allow_undefined_flag \ -no_undefined_flag \ -hardcode_libdir_flag_spec \ -hardcode_libdir_separator \ -exclude_expsyms \ -include_expsyms \ -file_list_spec \ -variables_saved_for_relink \ -libname_spec \ -library_names_spec \ -soname_spec \ -install_override_mode \ -finish_eval \ -old_striplib \ -striplib; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in reload_cmds \ -old_postinstall_cmds \ -old_postuninstall_cmds \ -old_archive_cmds \ -extract_expsyms_cmds \ -old_archive_from_new_cmds \ -old_archive_from_expsyms_cmds \ -archive_cmds \ -archive_expsym_cmds \ -module_cmds \ -module_expsym_cmds \ -export_symbols_cmds \ -prelink_cmds \ -postlink_cmds \ -postinstall_cmds \ -postuninstall_cmds \ -finish_cmds \ -sys_lib_search_path_spec \ -configure_time_dlsearch_path \ -configure_time_lt_sys_library_path; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -ac_aux_dir='$ac_aux_dir' - -# See if we are running on zsh, and set the options that allow our -# commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - - - PACKAGE='$PACKAGE' - VERSION='$VERSION' - RM='$RM' - ofile='$ofile' - - - - -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; - "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; - "specs/Makefile") CONFIG_FILES="$CONFIG_FILES specs/Makefile" ;; - "xext.pc") CONFIG_FILES="$CONFIG_FILES xext.pc" ;; - - *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files - test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers - test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to '$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with './config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | sed -n '$='` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | sed -n '$='` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >"$CONFIG_STATUS" || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with './config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script 'defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >"$CONFIG_STATUS" || ac_write_fail=1 - -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - suffix = P[macro] D[macro] - while (suffix ~ /[\t ]$/) { - suffix = substr(suffix, 1, length(suffix) - 1) - } - # Preserve the white space surrounding the "#". - print prefix "define", macro suffix - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain ':'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf '%s\n' "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is 'configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - printf '%s\n' "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf '%s\n' "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf '%s\n' "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when '$srcdir' = '.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -printf '%s\n' "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf '%s\n' "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - printf '%s\n' "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf '%s\n' "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || { - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - case $CONFIG_FILES in #( - *\'*) : - eval set x "$CONFIG_FILES" ;; #( - *) : - set x $CONFIG_FILES ;; #( - *) : - ;; -esac - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`printf '%s\n' "$am_mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`$as_dirname -- "$am_mf" || -$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$am_mf" : 'X\(//\)[^/]' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X"$am_mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - am_filepart=`$as_basename -- "$am_mf" || -$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf '%s\n' X/"$am_mf" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - { echo "$as_me:$LINENO: cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles" >&5 - (cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } || am_rc=$? - done - if test $am_rc -ne 0; then - { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE=\"gmake\" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking). -See 'config.log' for more details" "$LINENO" 5; } - fi - { am_dirpart=; unset am_dirpart;} - { am_filepart=; unset am_filepart;} - { am_mf=; unset am_mf;} - { am_rc=; unset am_rc;} - rm -f conftest-deps.mk -} - ;; - "libtool":C) - - # See if we are running on zsh, and set the options that allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST - fi - - cfgfile=${ofile}T - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL -# Generated automatically by $as_me ($PACKAGE) $VERSION -# NOTE: Changes made to this file will be lost: look at ltmain.sh. - -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit, 1996 - -# Copyright (C) 2024 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program or library that is built -# using GNU Libtool, you may include this file under the same -# distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -# The names of the tagged configurations supported by this script. -available_tags='' - -# Configured defaults for sys_lib_dlsearch_path munging. -: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=$macro_version -macro_revision=$macro_revision - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# What type of objects to build. -pic_mode=$pic_mode - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# Shared archive member basename,for filename based shared library versioning on AIX. -shared_archive_member_spec=$shared_archive_member_spec - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The PATH separator for the build system. -PATH_SEPARATOR=$lt_PATH_SEPARATOR - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="\$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP=$lt_GREP - -# An ERE matcher. -EGREP=$lt_EGREP - -# A literal string matcher. -FGREP=$lt_FGREP - -# A BSD- or MS-compatible name lister. -NM=$lt_NM - -# Whether we need soft or hard links. -LN_S=$lt_LN_S - -# What is the maximum length of a command? -max_cmd_len=$max_cmd_len - -# Object file suffix (normally "o"). -objext=$ac_objext - -# Executable file suffix (normally ""). -exeext=$exeext - -# whether the shell understands "unset". -lt_unset=$lt_unset - -# turn spaces into newlines. -SP2NL=$lt_lt_SP2NL - -# turn newlines into spaces. -NL2SP=$lt_lt_NL2SP - -# convert \$build file names to \$host format. -to_host_file_cmd=$lt_cv_to_host_file_cmd - -# convert \$build files to toolchain format. -to_tool_file_cmd=$lt_cv_to_tool_file_cmd - -# A file(cmd) program that detects file types. -FILECMD=$lt_FILECMD - -# An object symbol dumper. -OBJDUMP=$lt_OBJDUMP - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method = "file_magic". -file_magic_cmd=$lt_file_magic_cmd - -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob=$lt_file_magic_glob - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob=$lt_want_nocaseglob - -# DLL creation program. -DLLTOOL=$lt_DLLTOOL - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd - -# The archiver. -AR=$lt_AR - -# Flags to create an archive (by configure). -lt_ar_flags=$lt_ar_flags - -# Flags to create an archive. -AR_FLAGS=\${ARFLAGS-"\$lt_ar_flags"} - -# How to feed a file listing to the archiver. -archiver_list_spec=$lt_archiver_list_spec - -# A symbol stripping program. -STRIP=$lt_STRIP - -# Commands used to install an old-style archive. -RANLIB=$lt_RANLIB -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - -# A C compiler. -LTCC=$lt_CC - -# LTCC compiler flags. -LTCFLAGS=$lt_CFLAGS - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm into a list of symbols to manually relocate. -global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix - -# The name lister interface. -nm_interface=$lt_lt_cv_nm_interface - -# Specify filename containing input files for \$NM. -nm_file_list_spec=$lt_nm_file_list_spec - -# The root where to search for dependent libraries,and where our libraries should be installed. -lt_sysroot=$lt_sysroot - -# Command to truncate a binary pipe. -lt_truncate_bin=$lt_lt_cv_truncate_bin - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=$MAGIC_CMD - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Manifest tool. -MANIFEST_TOOL=$lt_MANIFEST_TOOL - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL=$lt_DSYMUTIL - -# Tool to change global to local symbols on Mac OS X. -NMEDIT=$lt_NMEDIT - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO=$lt_LIPO - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL=$lt_OTOOL - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64=$lt_OTOOL64 - -# Old archive suffix (normally "a"). -libext=$libext - -# Shared library suffix (normally ".so"). -shrext_cmds=$lt_shrext_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink=$lt_variables_saved_for_relink - -# Do we need the "lib" prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Library versioning type. -version_type=$version_type - -# Shared library runtime path variable. -runpath_var=$runpath_var - -# Shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - -# Command to use after installation of a shared archive. -postinstall_cmds=$lt_postinstall_cmds - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval=$lt_finish_eval - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Compile-time system search path for libraries. -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Detected run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path - -# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. -configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - - -# The linker used to build libraries. -LD=$lt_LD - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds - -# A language specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU compiler? -with_gcc=$GCC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct - -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e. impossible to change by setting \$shlibpath_var if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# ### END LIBTOOL CONFIG - -_LT_EOF - - cat <<'_LT_EOF' >> "$cfgfile" - -# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x$2 in - x) - ;; - *:) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" - ;; - x:*) - eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" - ;; - *) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" - ;; - esac -} - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in $*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - - -# ### END FUNCTIONS SHARED WITH CONFIGURE - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - - -ltmain=$ac_aux_dir/ltmain.sh - - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - $SED '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - - ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_CONFIG_STATUS= - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - case $CONFIG_STATUS in #( - -*) : - ac_no_opts=-- ;; #( - *) : - ac_no_opts= ;; -esac - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $ac_no_opts "$CONFIG_STATUS" $ac_config_status_args || - ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - diff --git a/experiments/wasm-gui/third_party/libXext/depcomp b/experiments/wasm-gui/third_party/libXext/depcomp deleted file mode 100755 index 9f6725b9e..000000000 --- a/experiments/wasm-gui/third_party/libXext/depcomp +++ /dev/null @@ -1,792 +0,0 @@ -#! /bin/sh -# depcomp - compile a program generating dependencies as side-effects - -scriptversion=2025-06-18.21; # UTC - -# Copyright (C) 1999-2025 Free Software Foundation, Inc. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Originally written by Alexandre Oliva . - -case $1 in - '') - echo "$0: No command. Try '$0 --help' for more information." 1>&2 - exit 1; - ;; - -h | --h*) - cat <<\EOF -Usage: depcomp [--help] [--version] PROGRAM [ARGS] - -Run PROGRAMS ARGS to compile a file, generating dependencies -as side-effects. - -Environment variables: - depmode Dependency tracking mode. - source Source file read by 'PROGRAMS ARGS'. - object Object file output by 'PROGRAMS ARGS'. - DEPDIR directory where to store dependencies. - depfile Dependency file to output. - tmpdepfile Temporary file to use when outputting dependencies. - libtool Whether libtool is used (yes/no). - -Report bugs to . -GNU Automake home page: . -General help using GNU software: . -EOF - exit $? - ;; - -v | --v*) - echo "depcomp (GNU Automake) $scriptversion" - exit $? - ;; -esac - -# Get the directory component of the given path, and save it in the -# global variables '$dir'. Note that this directory component will -# be either empty or ending with a '/' character. This is deliberate. -set_dir_from () -{ - case $1 in - */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; - *) dir=;; - esac -} - -# Get the suffix-stripped basename of the given path, and save it the -# global variable '$base'. -set_base_from () -{ - base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` -} - -# If no dependency file was actually created by the compiler invocation, -# we still have to create a dummy depfile, to avoid errors with the -# Makefile "include basename.Plo" scheme. -make_dummy_depfile () -{ - echo "#dummy" > "$depfile" -} - -# Factor out some common post-processing of the generated depfile. -# Requires the auxiliary global variable '$tmpdepfile' to be set. -aix_post_process_depfile () -{ - # If the compiler actually managed to produce a dependency file, - # post-process it. - if test -f "$tmpdepfile"; then - # Each line is of the form 'foo.o: dependency.h'. - # Do two passes, one to just change these to - # $object: dependency.h - # and one to simply output - # dependency.h: - # which is needed to avoid the deleted-header problem. - { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" - sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" - } > "$depfile" - rm -f "$tmpdepfile" - else - make_dummy_depfile - fi -} - -# A tabulation character. -tab=' ' -# A newline character. -nl=' -' -# Character ranges might be problematic outside the C locale. -# These definitions help. -upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ -lower=abcdefghijklmnopqrstuvwxyz -alpha=${upper}${lower} - -if test -z "$depmode" || test -z "$source" || test -z "$object"; then - echo "depcomp: Variables source, object and depmode must be set" 1>&2 - exit 1 -fi - -# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. -depfile=${depfile-`echo "$object" | - sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} -tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} - -rm -f "$tmpdepfile" - -# Avoid interference from the environment. -gccflag= dashmflag= - -# Some modes work just like other modes, but use different flags. We -# parameterize here, but still list the modes in the big case below, -# to make depend.m4 easier to write. Note that we *cannot* use a case -# here, because this file can only contain one case statement. -if test "$depmode" = hp; then - # HP compiler uses -M and no extra arg. - gccflag=-M - depmode=gcc -fi - -if test "$depmode" = dashXmstdout; then - # This is just like dashmstdout with a different argument. - dashmflag=-xM - depmode=dashmstdout -fi - -cygpath_u="cygpath -u -f -" -if test "$depmode" = msvcmsys; then - # This is just like msvisualcpp but w/o cygpath translation. - # Just convert the backslash-escaped backslashes to single forward - # slashes to satisfy depend.m4 - cygpath_u='sed s,\\\\,/,g' - depmode=msvisualcpp -fi - -if test "$depmode" = msvc7msys; then - # This is just like msvc7 but w/o cygpath translation. - # Just convert the backslash-escaped backslashes to single forward - # slashes to satisfy depend.m4 - cygpath_u='sed s,\\\\,/,g' - depmode=msvc7 -fi - -if test "$depmode" = xlc; then - # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. - gccflag=-qmakedep=gcc,-MF - depmode=gcc -fi - -case "$depmode" in -gcc3) -## gcc 3 implements dependency tracking that does exactly what -## we want. Yay! Note: for some reason libtool 1.4 doesn't like -## it if -MD -MP comes after the -MF stuff. Hmm. -## Unfortunately, FreeBSD c89 acceptance of flags depends upon -## the command line argument order; so add the flags where they -## appear in depend2.am. Note that the slowdown incurred here -## affects only configure: in makefiles, %FASTDEP% shortcuts this. - for arg - do - case $arg in - -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; - *) set fnord "$@" "$arg" ;; - esac - shift # fnord - shift # $arg - done - "$@" - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - mv "$tmpdepfile" "$depfile" - ;; - -gcc) -## Note that this doesn't just cater to obsolete pre-3.x GCC compilers. -## but also to in-use compilers like IBM xlc/xlC and the HP C compiler. -## (see the conditional assignment to $gccflag above). -## There are various ways to get dependency output from gcc. Here's -## why we pick this rather obscure method: -## - Don't want to use -MD because we'd like the dependencies to end -## up in a subdir. Having to rename by hand is ugly. -## (We might end up doing this anyway to support other compilers.) -## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like -## -MM, not -M (despite what the docs say). Also, it might not be -## supported by the other compilers which use the 'gcc' depmode. -## - Using -M directly means running the compiler twice (even worse -## than renaming). - if test -z "$gccflag"; then - gccflag=-MD, - fi - "$@" -Wp,"$gccflag$tmpdepfile" - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - echo "$object : \\" > "$depfile" - # The second -e expression handles DOS-style file names with drive - # letters. - sed -e 's/^[^:]*: / /' \ - -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" -## This next piece of magic avoids the "deleted header file" problem. -## The problem is that when a header file which appears in a .P file -## is deleted, the dependency causes make to die (because there is -## typically no way to rebuild the header). We avoid this by adding -## dummy dependencies for each header file. Too bad gcc doesn't do -## this for us directly. -## Some versions of gcc put a space before the ':'. On the theory -## that the space means something, we add a space to the output as -## well. hp depmode also adds that space, but also prefixes the VPATH -## to the object. Take care to not repeat it in the output. -## Some versions of the HPUX 10.20 sed can't process this invocation -## correctly. Breaking it into two sed invocations is a workaround. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -hp) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -sgi) - if test "$libtool" = yes; then - "$@" "-Wp,-MDupdate,$tmpdepfile" - else - "$@" -MDupdate "$tmpdepfile" - fi - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - - if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files - echo "$object : \\" > "$depfile" - # Clip off the initial element (the dependent). Don't try to be - # clever and replace this with sed code, as IRIX sed won't handle - # lines with more than a fixed number of characters (4096 in - # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; - # the IRIX cc adds comments like '#:fec' to the end of the - # dependency line. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ - | tr "$nl" ' ' >> "$depfile" - echo >> "$depfile" - # The second pass generates a dummy entry for each header file. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ - >> "$depfile" - else - make_dummy_depfile - fi - rm -f "$tmpdepfile" - ;; - -xlc) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -aix) - # The C for AIX Compiler uses -M and outputs the dependencies - # in a .u file. In older versions, this file always lives in the - # current directory. Also, the AIX compiler puts '$object:' at the - # start of each line; $object doesn't have directory information. - # Version 6 uses the directory in both cases. - set_dir_from "$object" - set_base_from "$object" - if test "$libtool" = yes; then - tmpdepfile1=$dir$base.u - tmpdepfile2=$base.u - tmpdepfile3=$dir.libs/$base.u - "$@" -Wc,-M - else - tmpdepfile1=$dir$base.u - tmpdepfile2=$dir$base.u - tmpdepfile3=$dir$base.u - "$@" -M - fi - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - do - test -f "$tmpdepfile" && break - done - aix_post_process_depfile - ;; - -tcc) - # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 - # FIXME: That version still under development at the moment of writing. - # Make that this statement remains true also for stable, released - # versions. - # It will wrap lines (doesn't matter whether long or short) with a - # trailing '\', as in: - # - # foo.o : \ - # foo.c \ - # foo.h \ - # - # It will put a trailing '\' even on the last line, and will use leading - # spaces rather than leading tabs (at least since its commit 0394caf7 - # "Emit spaces for -MD"). - "$@" -MD -MF "$tmpdepfile" - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. - # We have to change lines of the first kind to '$object: \'. - sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" - # And for each line of the second kind, we have to emit a 'dep.h:' - # dummy dependency, to avoid the deleted-header problem. - sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" - rm -f "$tmpdepfile" - ;; - -## The order of this option in the case statement is important, since the -## shell code in configure will try each of these formats in the order -## listed in this file. A plain '-MD' option would be understood by many -## compilers, so we must ensure this comes after the gcc and icc options. -pgcc) - # Portland's C compiler understands '-MD'. - # Will always output deps to 'file.d' where file is the root name of the - # source file under compilation, even if file resides in a subdirectory. - # The object file name does not affect the name of the '.d' file. - # pgcc 10.2 will output - # foo.o: sub/foo.c sub/foo.h - # and will wrap long lines using '\' : - # foo.o: sub/foo.c ... \ - # sub/foo.h ... \ - # ... - set_dir_from "$object" - # Use the source, not the object, to determine the base name, since - # that's sadly what pgcc will do too. - set_base_from "$source" - tmpdepfile=$base.d - - # For projects that build the same source file twice into different object - # files, the pgcc approach of using the *source* file root name can cause - # problems in parallel builds. Use a locking strategy to avoid stomping on - # the same $tmpdepfile. - lockdir=$base.d-lock - trap " - echo '$0: caught signal, cleaning up...' >&2 - rmdir '$lockdir' - exit 1 - " 1 2 13 15 - numtries=100 - i=$numtries - while test $i -gt 0; do - # mkdir is a portable test-and-set. - if mkdir "$lockdir" 2>/dev/null; then - # This process acquired the lock. - "$@" -MD - stat=$? - # Release the lock. - rmdir "$lockdir" - break - else - # If the lock is being held by a different process, wait - # until the winning process is done or we timeout. - while test -d "$lockdir" && test $i -gt 0; do - sleep 1 - i=`expr $i - 1` - done - fi - i=`expr $i - 1` - done - trap - 1 2 13 15 - if test $i -le 0; then - echo "$0: failed to acquire lock after $numtries attempts" >&2 - echo "$0: check lockdir '$lockdir'" >&2 - exit 1 - fi - - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - # Each line is of the form `foo.o: dependent.h', - # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. - # Do two passes, one to just change these to - # `$object: dependent.h' and one to simply `dependent.h:'. - sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" - # Some versions of the HPUX 10.20 sed can't process this invocation - # correctly. Breaking it into two sed invocations is a workaround. - sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ - | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -hp2) - # The "hp" stanza above does not work with aCC (C++) and HP's ia64 - # compilers, which have integrated preprocessors. The correct option - # to use with these is +Maked; it writes dependencies to a file named - # 'foo.d', which lands next to the object file, wherever that - # happens to be. - # Much of this is similar to the tru64 case; see comments there. - set_dir_from "$object" - set_base_from "$object" - if test "$libtool" = yes; then - tmpdepfile1=$dir$base.d - tmpdepfile2=$dir.libs/$base.d - "$@" -Wc,+Maked - else - tmpdepfile1=$dir$base.d - tmpdepfile2=$dir$base.d - "$@" +Maked - fi - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile1" "$tmpdepfile2" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" - do - test -f "$tmpdepfile" && break - done - if test -f "$tmpdepfile"; then - sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" - # Add 'dependent.h:' lines. - sed -ne '2,${ - s/^ *// - s/ \\*$// - s/$/:/ - p - }' "$tmpdepfile" >> "$depfile" - else - make_dummy_depfile - fi - rm -f "$tmpdepfile" "$tmpdepfile2" - ;; - -tru64) - # The Tru64 compiler uses -MD to generate dependencies as a side - # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. - # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put - # dependencies in 'foo.d' instead, so we check for that too. - # Subdirectories are respected. - set_dir_from "$object" - set_base_from "$object" - - if test "$libtool" = yes; then - # Libtool generates 2 separate objects for the 2 libraries. These - # two compilations output dependencies in $dir.libs/$base.o.d and - # in $dir$base.o.d. We have to check for both files, because - # one of the two compilations can be disabled. We should prefer - # $dir$base.o.d over $dir.libs/$base.o.d because the latter is - # automatically cleaned when .libs/ is deleted, while ignoring - # the former would cause a distcleancheck panic. - tmpdepfile1=$dir$base.o.d # libtool 1.5 - tmpdepfile2=$dir.libs/$base.o.d # Likewise. - tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 - "$@" -Wc,-MD - else - tmpdepfile1=$dir$base.d - tmpdepfile2=$dir$base.d - tmpdepfile3=$dir$base.d - "$@" -MD - fi - - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - do - test -f "$tmpdepfile" && break - done - # Same post-processing that is required for AIX mode. - aix_post_process_depfile - ;; - -msvc7) - if test "$libtool" = yes; then - showIncludes=-Wc,-showIncludes - else - showIncludes=-showIncludes - fi - "$@" $showIncludes > "$tmpdepfile" - stat=$? - grep -v '^Note: including file: ' "$tmpdepfile" - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - echo "$object : \\" > "$depfile" - # The first sed program below extracts the file names and escapes - # backslashes for cygpath. The second sed program outputs the file - # name when reading, but also accumulates all include files in the - # hold buffer in order to output them again at the end. This only - # works with sed implementations that can handle large buffers. - sed < "$tmpdepfile" -n ' -/^Note: including file: *\(.*\)/ { - s//\1/ - s/\\/\\\\/g - p -}' | $cygpath_u | sort -u | sed -n ' -s/ /\\ /g -s/\(.*\)/'"$tab"'\1 \\/p -s/.\(.*\) \\/\1:/ -H -$ { - s/.*/'"$tab"'/ - G - p -}' >> "$depfile" - echo >> "$depfile" # make sure the fragment doesn't end with a backslash - rm -f "$tmpdepfile" - ;; - -msvc7msys) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -#nosideeffect) - # This comment above is used by automake to tell side-effect - # dependency tracking mechanisms from slower ones. - -dashmstdout) - # Important note: in order to support this mode, a compiler *must* - # always write the preprocessed file to stdout, regardless of -o. - "$@" || exit $? - - # Remove the call to Libtool. - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - - # Remove '-o $object'. - IFS=" " - for arg - do - case $arg in - -o) - shift - ;; - $object) - shift - ;; - *) - set fnord "$@" "$arg" - shift # fnord - shift # $arg - ;; - esac - done - - test -z "$dashmflag" && dashmflag=-M - # Require at least two characters before searching for ':' - # in the target name. This is to cope with DOS-style filenames: - # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. - "$@" $dashmflag | - sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" - rm -f "$depfile" - cat < "$tmpdepfile" > "$depfile" - # Some versions of the HPUX 10.20 sed can't process this sed invocation - # correctly. Breaking it into two sed invocations is a workaround. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -dashXmstdout) - # This case only exists to satisfy depend.m4. It is never actually - # run, as this mode is specially recognized in the preamble. - exit 1 - ;; - -makedepend) - "$@" || exit $? - # Remove any Libtool call - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - # X makedepend - shift - cleared=no eat=no - for arg - do - case $cleared in - no) - set ""; shift - cleared=yes ;; - esac - if test $eat = yes; then - eat=no - continue - fi - case "$arg" in - -D*|-I*) - set fnord "$@" "$arg"; shift ;; - # Strip any option that makedepend may not understand. Remove - # the object too, otherwise makedepend will parse it as a source file. - -arch) - eat=yes ;; - -*|$object) - ;; - *) - set fnord "$@" "$arg"; shift ;; - esac - done - obj_suffix=`echo "$object" | sed 's/^.*\././'` - touch "$tmpdepfile" - ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" - rm -f "$depfile" - # makedepend may prepend the VPATH from the source file name to the object. - # No need to regex-escape $object, excess matching of '.' is harmless. - sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" - # Some versions of the HPUX 10.20 sed can't process the last invocation - # correctly. Breaking it into two sed invocations is a workaround. - sed '1,2d' "$tmpdepfile" \ - | tr ' ' "$nl" \ - | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" "$tmpdepfile".bak - ;; - -cpp) - # Important note: in order to support this mode, a compiler *must* - # always write the preprocessed file to stdout. - "$@" || exit $? - - # Remove the call to Libtool. - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - - # Remove '-o $object'. - IFS=" " - for arg - do - case $arg in - -o) - shift - ;; - $object) - shift - ;; - *) - set fnord "$@" "$arg" - shift # fnord - shift # $arg - ;; - esac - done - - "$@" -E \ - | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ - -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ - | sed '$ s: \\$::' > "$tmpdepfile" - rm -f "$depfile" - echo "$object : \\" > "$depfile" - cat < "$tmpdepfile" >> "$depfile" - sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -msvisualcpp) - # Important note: in order to support this mode, a compiler *must* - # always write the preprocessed file to stdout. - "$@" || exit $? - - # Remove the call to Libtool. - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - - IFS=" " - for arg - do - case "$arg" in - -o) - shift - ;; - $object) - shift - ;; - "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") - set fnord "$@" - shift - shift - ;; - *) - set fnord "$@" "$arg" - shift - shift - ;; - esac - done - "$@" -E 2>/dev/null | - sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" - rm -f "$depfile" - echo "$object : \\" > "$depfile" - sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" - echo "$tab" >> "$depfile" - sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -msvcmsys) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -none) - exec "$@" - ;; - -*) - echo "Unknown depmode $depmode" 1>&2 - exit 1 - ;; -esac - -exit 0 - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp nil t) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%Y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/experiments/wasm-gui/third_party/libXext/install-sh b/experiments/wasm-gui/third_party/libXext/install-sh deleted file mode 100755 index 1d8d96696..000000000 --- a/experiments/wasm-gui/third_party/libXext/install-sh +++ /dev/null @@ -1,541 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2025-06-18.21; # UTC - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# 'make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -tab=' ' -nl=' -' -IFS=" $tab$nl" - -# Set DOITPROG to "echo" to test this script. - -doit=${DOITPROG-} -doit_exec=${doit:-exec} - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -# Create dirs (including intermediate dirs) using mode 755. -# This is like GNU 'install' as of coreutils 8.32 (2020). -mkdir_umask=22 - -backupsuffix= -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -is_target_a_directory=possibly - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -p pass -p to $cpprog. - -s $stripprog installed files. - -S SUFFIX attempt to back up existing files, with suffix SUFFIX. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG - -By default, rm is invoked with -f; when overridden with RMPROG, -it's up to you to specify -f if you want it. - -If -S is not specified, no backups are attempted. - -Report bugs to . -GNU Automake home page: . -General help using GNU software: ." - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -p) cpprog="$cpprog -p";; - - -s) stripcmd=$stripprog;; - - -S) backupsuffix="$2" - shift;; - - -t) - is_target_a_directory=always - dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; - - -T) is_target_a_directory=never;; - - --version) echo "$0 (GNU Automake) $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -# We allow the use of options -d and -T together, by making -d -# take the precedence; this is for compatibility with GNU install. - -if test -n "$dir_arg"; then - if test -n "$dst_arg"; then - echo "$0: target directory not allowed when installing a directory." >&2 - exit 1 - fi -fi - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call 'install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - if test $# -gt 1 || test "$is_target_a_directory" = always; then - if test ! -d "$dst_arg"; then - echo "$0: $dst_arg: Is not a directory." >&2 - exit 1 - fi - fi -fi - -if test -z "$dir_arg"; then - do_exit='(exit $ret); exit $ret' - trap "ret=129; $do_exit" 1 - trap "ret=130; $do_exit" 2 - trap "ret=141; $do_exit" 13 - trap "ret=143; $do_exit" 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names problematic for 'test' and other utilities. - case $src in - -* | [=\(\)!]) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - # Don't chown directories that already exist. - if test $dstdir_status = 0; then - chowncmd="" - fi - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - dst=$dst_arg - - # If destination is a directory, append the input filename. - if test -d "$dst"; then - if test "$is_target_a_directory" = never; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dstbase=`basename "$src"` - case $dst in - */) dst=$dst$dstbase;; - *) dst=$dst/$dstbase;; - esac - dstdir_status=0 - else - dstdir=`dirname "$dst"` - test -d "$dstdir" - dstdir_status=$? - fi - fi - - case $dstdir in - */) dstdirslash=$dstdir;; - *) dstdirslash=$dstdir/;; - esac - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - # The $RANDOM variable is not portable (e.g., dash). Use it - # here however when possible just to lower collision chance. - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - - trap ' - ret=$? - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null - exit $ret - ' 0 - - # Because "mkdir -p" follows existing symlinks and we likely work - # directly in world-writable /tmp, make sure that the '$tmpdir' - # directory is successfully created first before we actually test - # 'mkdir -p'. - if (umask $mkdir_umask && - $mkdirprog $mkdir_mode "$tmpdir" && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibility with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - test_tmpdir="$tmpdir/a" - ls_ld_tmpdir=`ls -ld "$test_tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null - fi - trap '' 0;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; - esac - - oIFS=$IFS - IFS=/ - set -f - set fnord $dstdir - shift - set +f - IFS=$oIFS - - prefixes= - - for d - do - test X"$d" = X && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=${dstdirslash}_inst.$$_ - rmtmp=${dstdirslash}_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && - { test -z "$stripcmd" || { - # Create $dsttmp read-write so that cp doesn't create it read-only, - # which would cause strip to fail. - if test -z "$doit"; then - : >"$dsttmp" # No need to fork-exec 'touch'. - else - $doit touch "$dsttmp" - fi - } - } && - $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - set +f && - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # If $backupsuffix is set, and the file being installed - # already exists, attempt a backup. Don't worry if it fails, - # e.g., if mv doesn't support -f. - if test -n "$backupsuffix" && test -f "$dst"; then - $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null - fi - - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp nil t) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%Y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/experiments/wasm-gui/third_party/libXext/libtool b/experiments/wasm-gui/third_party/libXext/libtool deleted file mode 100755 index 5d60c70e3..000000000 --- a/experiments/wasm-gui/third_party/libXext/libtool +++ /dev/null @@ -1,12024 +0,0 @@ -#! /bin/bash -# Generated automatically by config.status (libXext) 1.3.7 -# NOTE: Changes made to this file will be lost: look at ltmain.sh. - -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit, 1996 - -# Copyright (C) 2024 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program or library that is built -# using GNU Libtool, you may include this file under the same -# distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -# The names of the tagged configurations supported by this script. -available_tags='' - -# Configured defaults for sys_lib_dlsearch_path munging. -: ${LT_SYS_LIBRARY_PATH=""} - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=2.5.4 -macro_revision=2.5.4 - -# Whether or not to build shared libraries. -build_libtool_libs=no - -# Whether or not to build static libraries. -build_old_libs=yes - -# What type of objects to build. -pic_mode=default - -# Whether or not to optimize for fast installation. -fast_install=needless - -# Shared archive member basename,for filename based shared library versioning on AIX. -shared_archive_member_spec= - -# Shell to use when invoking shell scripts. -SHELL="/bin/bash" - -# An echo program that protects backslashes. -ECHO="printf %s\\n" - -# The PATH separator for the build system. -PATH_SEPARATOR=":" - -# The host system. -host_alias=wasm32-wasi -host=wasm32-unknown-wasi -host_os=wasi - -# The build system. -build_alias= -build=x86_64-pc-linux-gnu -build_os=linux-gnu - -# A sed program that does not truncate output. -SED="/usr/bin/sed" - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP="/usr/bin/grep" - -# An ERE matcher. -EGREP="/usr/bin/grep -E" - -# A literal string matcher. -FGREP="/usr/bin/grep -F" - -# A BSD- or MS-compatible name lister. -NM="nm" - -# Whether we need soft or hard links. -LN_S="ln -s" - -# What is the maximum length of a command? -max_cmd_len=1572864 - -# Object file suffix (normally "o"). -objext=o - -# Executable file suffix (normally ""). -exeext= - -# whether the shell understands "unset". -lt_unset=unset - -# turn spaces into newlines. -SP2NL="tr \\040 \\012" - -# turn newlines into spaces. -NL2SP="tr \\015\\012 \\040\\040" - -# convert $build file names to $host format. -to_host_file_cmd=func_convert_file_noop - -# convert $build files to toolchain format. -to_tool_file_cmd=func_convert_file_noop - -# A file(cmd) program that detects file types. -FILECMD="file" - -# An object symbol dumper. -OBJDUMP="objdump" - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method="unknown" - -# Command to use when deplibs_check_method = "file_magic". -file_magic_cmd="\$MAGIC_CMD" - -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob="" - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob="no" - -# DLL creation program. -DLLTOOL="dlltool" - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd="printf %s\\n" - -# The archiver. -AR="/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ar" - -# Flags to create an archive (by configure). -lt_ar_flags=cr - -# Flags to create an archive. -AR_FLAGS=${ARFLAGS-"$lt_ar_flags"} - -# How to feed a file listing to the archiver. -archiver_list_spec="@" - -# A symbol stripping program. -STRIP="strip" - -# Commands used to install an old-style archive. -RANLIB="/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/llvm-ranlib" -old_postinstall_cmds="chmod 644 \$oldlib~\$RANLIB \$tool_oldlib" -old_postuninstall_cmds="" - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=no - -# A C compiler. -LTCC="/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23" - -# LTCC compiler flags. -LTCFLAGS="--target=wasm32-wasip1 --sysroot=/home/nathan/secure-exec/registry/native/c/sysroot -O2 -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj -I/home/nathan/secure-exec/experiments/wasm-gui/third_party/wasm-prefix/include -include /home/nathan/secure-exec/experiments/wasm-gui/toolchain/wasi-compat.h" - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe="" - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl="" - -# Transform the output of nm into a list of symbols to manually relocate. -global_symbol_to_import="" - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address="/usr/bin/sed -n -e 's/^: \\(.*\\) .*\$/ {\"\\1\", (void *) 0},/p' -e 's/^[ABCDGIRSTW][ABCDGIRSTW]* .* \\(.*\\)\$/ {\"\\1\", (void *) \\&\\1},/p'" - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix="/usr/bin/sed -n -e 's/^: \\(.*\\) .*\$/ {\"\\1\", (void *) 0},/p' -e 's/^[ABCDGIRSTW][ABCDGIRSTW]* .* \\(lib.*\\)\$/ {\"\\1\", (void *) \\&\\1},/p' -e 's/^[ABCDGIRSTW][ABCDGIRSTW]* .* \\(.*\\)\$/ {\"lib\\1\", (void *) \\&\\1},/p'" - -# The name lister interface. -nm_interface="BSD nm" - -# Specify filename containing input files for $NM. -nm_file_list_spec="@" - -# The root where to search for dependent libraries,and where our libraries should be installed. -lt_sysroot= - -# Command to truncate a binary pipe. -lt_truncate_bin="/usr/bin/dd bs=4096 count=1" - -# The name of the directory that contains temporary libtool files. -objdir=.libs - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=file - -# Must we lock files when doing compilation? -need_locks="no" - -# Manifest tool. -MANIFEST_TOOL=":" - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL="" - -# Tool to change global to local symbols on Mac OS X. -NMEDIT="" - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO="" - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL="" - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64="" - -# Old archive suffix (normally "a"). -libext=a - -# Shared library suffix (normally ".so"). -shrext_cmds=".so" - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds="" - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink="PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" - -# Do we need the "lib" prefix for modules? -need_lib_prefix=unknown - -# Do we need a version for libraries? -need_version=unknown - -# Library versioning type. -version_type=none - -# Shared library runtime path variable. -runpath_var=LD_RUN_PATH - -# Shared library path variable. -shlibpath_var= - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=unknown - -# Format of library name prefix. -libname_spec="lib\$name" - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec="" - -# The coded name of the library, if different from the real name. -soname_spec="" - -# Permission mode override for installation of shared libraries. -install_override_mode="" - -# Command to use after installation of a shared archive. -postinstall_cmds="" - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds="" - -# Commands used to finish a libtool library installation in a directory. -finish_cmds="" - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval="" - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=no - -# Compile-time system search path for libraries. -sys_lib_search_path_spec="/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/lib/clang/19 /home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi " - -# Detected run-time system search path for libraries. -sys_lib_dlsearch_path_spec="/lib /usr/lib" - -# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. -configure_time_lt_sys_library_path="" - -# Whether dlopen is supported. -dlopen_support=unknown - -# Whether dlopen of programs is supported. -dlopen_self=unknown - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=unknown - -# Commands to strip libraries. -old_striplib="strip --strip-debug" -striplib="strip --strip-unneeded" - - -# The linker used to build libraries. -LD="/home/linuxbrew/.linuxbrew/bin/ld" - -# How to create reloadable object files. -reload_flag=" -r" -reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs" - -# Commands used to build an old-style archive. -old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs~\$RANLIB \$tool_oldlib" - -# A language specific compiler. -CC="/home/nathan/secure-exec/registry/native/c/vendor/wasi-sdk/bin/clang -std=gnu23" - -# Is the compiler the GNU compiler? -with_gcc=yes - -# Compiler flag to turn off builtin functions. -no_builtin_flag=" -fno-builtin -fno-rtti -fno-exceptions" - -# Additional compiler flags for building library objects. -pic_flag=" -fPIC -DPIC" - -# How to pass a linker flag through the compiler. -wl="-Wl," - -# Compiler flag to prevent dynamic linking. -link_static_flag="-static" - -# Does compiler simultaneously support -c and -o options? -compiler_c_o="yes" - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=yes - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=no - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec="\$wl--export-dynamic" - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec="\$wl--whole-archive\$convenience \$wl--no-whole-archive" - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object="no" - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds="" - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds="" - -# Commands used to build a shared archive. -archive_cmds="\$CC -shared \$pic_flag \$libobjs \$deplibs \$compiler_flags \$wl-soname \$wl\$soname -o \$lib" -archive_expsym_cmds="\$CC -shared \$pic_flag \$libobjs \$deplibs \$compiler_flags \$wl-soname \$wl\$soname \$wl-retain-symbols-file \$wl\$export_symbols -o \$lib" - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds="" -module_expsym_cmds="" - -# Whether we are building with GNU ld or not. -with_gnu_ld="yes" - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag="" - -# Flag that enforces no undefined symbols. -no_undefined_flag="" - -# Flag to hardcode $libdir into a binary during linking. -# This must work even if $libdir does not exist -hardcode_libdir_flag_spec="\$wl-rpath \$wl\$libdir" - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator="" - -# Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=no - -# Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e. impossible to change by setting $shlibpath_var if the -# library is relocated. -hardcode_direct_absolute=no - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=no - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=unsupported - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=no - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=no - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=unknown - -# Set to "yes" if exported symbols are required. -always_export_symbols=no - -# The commands to list exported symbols. -export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED 's/.* //' | sort | uniq > \$export_symbols" - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms="_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*" - -# Symbols that must always be exported. -include_expsyms="" - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds="" - -# Commands necessary for finishing linking programs. -postlink_cmds="" - -# Specify filename containing input files. -file_list_spec="" - -# How to hardcode a shared library path into an executable. -hardcode_action=immediate - -# ### END LIBTOOL CONFIG - - -# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x$2 in - x) - ;; - *:) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" - ;; - x:*) - eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" - ;; - *) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" - ;; - esac -} - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in $*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - - -# ### END FUNCTIONS SHARED WITH CONFIGURE - -#! /usr/bin/env sh -## DO NOT EDIT - This file generated from ./build-aux/ltmain.in -## by inline-source v2019-02-19.15 - -# libtool (GNU libtool) 2.5.4 -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit , 1996 - -# Copyright (C) 1996-2019, 2021-2024 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, -# if you distribute this file as part of a program or library that -# is built using GNU Libtool, you may include this file under the -# same distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -PROGRAM=libtool -PACKAGE=libtool -VERSION=2.5.4 -package_revision=2.5.4 - - -## ------ ## -## Usage. ## -## ------ ## - -# Run './libtool --help' for help with using this script from the -# command line. - - -## ------------------------------- ## -## User overridable command paths. ## -## ------------------------------- ## - -# After configure completes, it has a better idea of some of the -# shell tools we need than the defaults used by the functions shared -# with bootstrap, so set those here where they can still be over- -# ridden by the user, but otherwise take precedence. - -: ${AUTOCONF="autoconf"} -: ${AUTOMAKE="automake"} - - -## -------------------------- ## -## Source external libraries. ## -## -------------------------- ## - -# Much of our low-level functionality needs to be sourced from external -# libraries, which are installed to $pkgauxdir. - -# Set a version string for this script. -scriptversion=2019-02-19.15; # UTC - -# General shell script boiler plate, and helper functions. -# Written by Gary V. Vaughan, 2004 - -# This is free software. There is NO warranty; not even for -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# Copyright (C) 2004-2019, 2021, 2023-2024 Bootstrap Authors -# -# This file is dual licensed under the terms of the MIT license -# , and GPL version 2 or later -# . You must apply one of -# these licenses when using or redistributing this software or any of -# the files within it. See the URLs above, or the file `LICENSE` -# included in the Bootstrap distribution for the full license texts. - -# Please report bugs or propose patches to: -# - - -## ------ ## -## Usage. ## -## ------ ## - -# Evaluate this file near the top of your script to gain access to -# the functions and variables defined here: -# -# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh -# -# If you need to override any of the default environment variable -# settings, do that before evaluating this file. - - -## -------------------- ## -## Shell normalisation. ## -## -------------------- ## - -# Some shells need a little help to be as Bourne compatible as possible. -# Before doing anything else, make sure all that help has been provided! - -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac -fi - -# NLS nuisances: We save the old values in case they are required later. -_G_user_locale= -_G_safe_locale= -for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES -do - eval "if test set = \"\${$_G_var+set}\"; then - save_$_G_var=\$$_G_var - $_G_var=C - export $_G_var - _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" - _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" - fi" -done -# These NLS vars are set unconditionally (bootstrap issue #24). Unset those -# in case the environment reset is needed later and the $save_* variant is not -# defined (see the code above). -LC_ALL=C -LANGUAGE=C -export LANGUAGE LC_ALL - -# Make sure IFS has a sensible default -sp=' ' -nl=' -' -IFS="$sp $nl" - -# There are apparently some systems that use ';' as a PATH separator! -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# func_unset VAR -# -------------- -# Portably unset VAR. -# In some shells, an 'unset VAR' statement leaves a non-zero return -# status if VAR is already unset, which might be problematic if the -# statement is used at the end of a function (thus poisoning its return -# value) or when 'set -e' is active (causing even a spurious abort of -# the script in this case). -func_unset () -{ - { eval $1=; (eval unset $1) >/dev/null 2>&1 && eval unset $1 || : ; } -} - - -# Make sure CDPATH doesn't cause `cd` commands to output the target dir. -func_unset CDPATH - -# Make sure ${,E,F}GREP behave sanely. -func_unset GREP_OPTIONS - - -## ------------------------- ## -## Locate command utilities. ## -## ------------------------- ## - - -# func_executable_p FILE -# ---------------------- -# Check that FILE is an executable regular file. -func_executable_p () -{ - test -f "$1" && test -x "$1" -} - - -# func_path_progs PROGS_LIST CHECK_FUNC [PATH] -# -------------------------------------------- -# Search for either a program that responds to --version with output -# containing "GNU", or else returned by CHECK_FUNC otherwise, by -# trying all the directories in PATH with each of the elements of -# PROGS_LIST. -# -# CHECK_FUNC should accept the path to a candidate program, and -# set $func_check_prog_result if it truncates its output less than -# $_G_path_prog_max characters. -func_path_progs () -{ - _G_progs_list=$1 - _G_check_func=$2 - _G_PATH=${3-"$PATH"} - - _G_path_prog_max=0 - _G_path_prog_found=false - _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} - for _G_dir in $_G_PATH; do - IFS=$_G_save_IFS - test -z "$_G_dir" && _G_dir=. - for _G_prog_name in $_G_progs_list; do - for _exeext in '' .EXE; do - _G_path_prog=$_G_dir/$_G_prog_name$_exeext - func_executable_p "$_G_path_prog" || continue - case `"$_G_path_prog" --version 2>&1` in - *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; - *) $_G_check_func $_G_path_prog - func_path_progs_result=$func_check_prog_result - ;; - esac - $_G_path_prog_found && break 3 - done - done - done - IFS=$_G_save_IFS - test -z "$func_path_progs_result" && { - echo "no acceptable sed could be found in \$PATH" >&2 - exit 1 - } -} - - -# We want to be able to use the functions in this file before configure -# has figured out where the best binaries are kept, which means we have -# to search for them ourselves - except when the results are already set -# where we skip the searches. - -# Unless the user overrides by setting SED, search the path for either GNU -# sed, or the sed that truncates its output the least. -test -z "$SED" && { - _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for _G_i in 1 2 3 4 5 6 7; do - _G_sed_script=$_G_sed_script$nl$_G_sed_script - done - echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed - _G_sed_script= - - func_check_prog_sed () - { - _G_path_prog=$1 - - _G_count=0 - printf 0123456789 >conftest.in - while : - do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo '' >> conftest.nl - "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break - diff conftest.out conftest.nl >/dev/null 2>&1 || break - _G_count=`expr $_G_count + 1` - if test "$_G_count" -gt "$_G_path_prog_max"; then - # Best one so far, save it but keep looking for a better one - func_check_prog_result=$_G_path_prog - _G_path_prog_max=$_G_count - fi - # 10*(2^10) chars as input seems more than enough - test 10 -lt "$_G_count" && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out - } - - func_path_progs "sed gsed" func_check_prog_sed "$PATH:/usr/xpg4/bin" - rm -f conftest.sed - SED=$func_path_progs_result -} - - -# Unless the user overrides by setting GREP, search the path for either GNU -# grep, or the grep that truncates its output the least. -test -z "$GREP" && { - func_check_prog_grep () - { - _G_path_prog=$1 - - _G_count=0 - _G_path_prog_max=0 - printf 0123456789 >conftest.in - while : - do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo 'GREP' >> conftest.nl - "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break - diff conftest.out conftest.nl >/dev/null 2>&1 || break - _G_count=`expr $_G_count + 1` - if test "$_G_count" -gt "$_G_path_prog_max"; then - # Best one so far, save it but keep looking for a better one - func_check_prog_result=$_G_path_prog - _G_path_prog_max=$_G_count - fi - # 10*(2^10) chars as input seems more than enough - test 10 -lt "$_G_count" && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out - } - - func_path_progs "grep ggrep" func_check_prog_grep "$PATH:/usr/xpg4/bin" - GREP=$func_path_progs_result -} - - -## ------------------------------- ## -## User overridable command paths. ## -## ------------------------------- ## - -# All uppercase variable names are used for environment variables. These -# variables can be overridden by the user before calling a script that -# uses them if a suitable command of that name is not already available -# in the command search PATH. - -: ${CP="cp -f"} -: ${ECHO="printf %s\n"} -: ${EGREP="$GREP -E"} -: ${FGREP="$GREP -F"} -: ${LN_S="ln -s"} -: ${MAKE="make"} -: ${MKDIR="mkdir"} -: ${MV="mv -f"} -: ${RM="rm -f"} -: ${SHELL="${CONFIG_SHELL-/bin/sh}"} - - -## -------------------- ## -## Useful sed snippets. ## -## -------------------- ## - -sed_dirname='s|/[^/]*$||' -sed_basename='s|^.*/||' - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -sed_quote_subst='s|\([`"$\\]\)|\\\1|g' - -# Same as above, but do not quote variable references. -sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution that turns a string into a regex matching for the -# string literally. -sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' - -# Sed substitution that converts a w32 file name or path -# that contains forward slashes, into one that contains -# (escaped) backslashes. A very naive implementation. -sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' - -# Re-'\' parameter expansions in output of sed_double_quote_subst that -# were '\'-ed in input to the same. If an odd number of '\' preceded a -# '$' in input to sed_double_quote_subst, that '$' was protected from -# expansion. Since each input '\' is now two '\'s, look for any number -# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. -_G_bs='\\' -_G_bs2='\\\\' -_G_bs4='\\\\\\\\' -_G_dollar='\$' -sed_double_backslash="\ - s/$_G_bs4/&\\ -/g - s/^$_G_bs2$_G_dollar/$_G_bs&/ - s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g - s/\n//g" - -# require_check_ifs_backslash -# --------------------------- -# Check if we can use backslash as IFS='\' separator, and set -# $check_ifs_backshlash_broken to ':' or 'false'. -require_check_ifs_backslash=func_require_check_ifs_backslash -func_require_check_ifs_backslash () -{ - _G_save_IFS=$IFS - IFS='\' - _G_check_ifs_backshlash='a\\b' - for _G_i in $_G_check_ifs_backshlash - do - case $_G_i in - a) - check_ifs_backshlash_broken=false - ;; - '') - break - ;; - *) - check_ifs_backshlash_broken=: - break - ;; - esac - done - IFS=$_G_save_IFS - require_check_ifs_backslash=: -} - - -## ----------------- ## -## Global variables. ## -## ----------------- ## - -# Except for the global variables explicitly listed below, the following -# functions in the '^func_' namespace, and the '^require_' namespace -# variables initialised in the 'Resource management' section, sourcing -# this file will not pollute your global namespace with anything -# else. There's no portable way to scope variables in Bourne shell -# though, so actually running these functions will sometimes place -# results into a variable named after the function, and often use -# temporary variables in the '^_G_' namespace. If you are careful to -# avoid using those namespaces casually in your sourcing script, things -# should continue to work as you expect. And, of course, you can freely -# overwrite any of the functions or variables defined here before -# calling anything to customize them. - -EXIT_SUCCESS=0 -EXIT_FAILURE=1 -EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. -EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. - -# Allow overriding, eg assuming that you follow the convention of -# putting '$debug_cmd' at the start of all your functions, you can get -# bash to show function call trace with: -# -# debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name -debug_cmd=${debug_cmd-":"} -exit_cmd=: - -# By convention, finish your script with: -# -# exit $exit_status -# -# so that you can set exit_status to non-zero if you want to indicate -# something went wrong during execution without actually bailing out at -# the point of failure. -exit_status=$EXIT_SUCCESS - -# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh -# is ksh but when the shell is invoked as "sh" and the current value of -# the _XPG environment variable is not equal to 1 (one), the special -# positional parameter $0, within a function call, is the name of the -# function. -progpath=$0 - -# The name of this program. -progname=`$ECHO "$progpath" |$SED "$sed_basename"` - -# Make sure we have an absolute progpath for reexecution: -case $progpath in - [\\/]*|[A-Za-z]:\\*) ;; - *[\\/]*) - progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` - progdir=`cd "$progdir" && pwd` - progpath=$progdir/$progname - ;; - *) - _G_IFS=$IFS - IFS=${PATH_SEPARATOR-:} - for progdir in $PATH; do - IFS=$_G_IFS - test -x "$progdir/$progname" && break - done - IFS=$_G_IFS - test -n "$progdir" || progdir=`pwd` - progpath=$progdir/$progname - ;; -esac - - -## ----------------- ## -## Standard options. ## -## ----------------- ## - -# The following options affect the operation of the functions defined -# below, and should be set appropriately depending on run-time para- -# meters passed on the command line. - -opt_dry_run=false -opt_quiet=false -opt_verbose=false - -# Categories 'all' and 'none' are always available. Append any others -# you will pass as the first argument to func_warning from your own -# code. -warning_categories= - -# By default, display warnings according to 'opt_warning_types'. Set -# 'warning_func' to ':' to elide all warnings, or func_fatal_error to -# treat the next displayed warning as a fatal error. -warning_func=func_warn_and_continue - -# Set to 'all' to display all warnings, 'none' to suppress all -# warnings, or a space delimited list of some subset of -# 'warning_categories' to display only the listed warnings. -opt_warning_types=all - - -## -------------------- ## -## Resource management. ## -## -------------------- ## - -# This section contains definitions for functions that each ensure a -# particular resource (a file, or a non-empty configuration variable for -# example) is available, and if appropriate to extract default values -# from pertinent package files. Call them using their associated -# 'require_*' variable to ensure that they are executed, at most, once. -# -# It's entirely deliberate that calling these functions can set -# variables that don't obey the namespace limitations obeyed by the rest -# of this file, in order that that they be as useful as possible to -# callers. - - -# require_term_colors -# ------------------- -# Allow display of bold text on terminals that support it. -require_term_colors=func_require_term_colors -func_require_term_colors () -{ - $debug_cmd - - test -t 1 && { - # COLORTERM and USE_ANSI_COLORS environment variables take - # precedence, because most terminfo databases neglect to describe - # whether color sequences are supported. - test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} - - if test 1 = "$USE_ANSI_COLORS"; then - # Standard ANSI escape sequences - tc_reset='' - tc_bold=''; tc_standout='' - tc_red=''; tc_green='' - tc_blue=''; tc_cyan='' - else - # Otherwise trust the terminfo database after all. - test -n "`tput sgr0 2>/dev/null`" && { - tc_reset=`tput sgr0` - test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` - tc_standout=$tc_bold - test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` - test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` - test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` - test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` - test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` - } - fi - } - - require_term_colors=: -} - - -## ----------------- ## -## Function library. ## -## ----------------- ## - -# This section contains a variety of useful functions to call in your -# scripts. Take note of the portable wrappers for features provided by -# some modern shells, which will fall back to slower equivalents on -# less featureful shells. - - -# func_append VAR VALUE -# --------------------- -# Append VALUE onto the existing contents of VAR. - - # We should try to minimise forks, especially on Windows where they are - # unreasonably slow, so skip the feature probes when bash or zsh are - # being used: - if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then - : ${_G_HAVE_ARITH_OP="yes"} - : ${_G_HAVE_XSI_OPS="yes"} - # The += operator was introduced in bash 3.1 - case $BASH_VERSION in - [12].* | 3.0 | 3.0*) ;; - *) - : ${_G_HAVE_PLUSEQ_OP="yes"} - ;; - esac - fi - - # _G_HAVE_PLUSEQ_OP - # Can be empty, in which case the shell is probed, "yes" if += is - # usable or anything else if it does not work. - test -z "$_G_HAVE_PLUSEQ_OP" \ - && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ - && _G_HAVE_PLUSEQ_OP=yes - -if test yes = "$_G_HAVE_PLUSEQ_OP" -then - # This is an XSI compatible shell, allowing a faster implementation... - eval 'func_append () - { - $debug_cmd - - eval "$1+=\$2" - }' -else - # ...otherwise fall back to using expr, which is often a shell builtin. - func_append () - { - $debug_cmd - - eval "$1=\$$1\$2" - } -fi - - -# func_append_quoted VAR VALUE -# ---------------------------- -# Quote VALUE and append to the end of shell variable VAR, separated -# by a space. -if test yes = "$_G_HAVE_PLUSEQ_OP"; then - eval 'func_append_quoted () - { - $debug_cmd - - func_quote_arg pretty "$2" - eval "$1+=\\ \$func_quote_arg_result" - }' -else - func_append_quoted () - { - $debug_cmd - - func_quote_arg pretty "$2" - eval "$1=\$$1\\ \$func_quote_arg_result" - } -fi - - -# func_append_uniq VAR VALUE -# -------------------------- -# Append unique VALUE onto the existing contents of VAR, assuming -# entries are delimited by the first character of VALUE. For example: -# -# func_append_uniq options " --another-option option-argument" -# -# will only append to $options if " --another-option option-argument " -# is not already present somewhere in $options already (note spaces at -# each end implied by leading space in second argument). -func_append_uniq () -{ - $debug_cmd - - eval _G_current_value='`$ECHO $'$1'`' - _G_delim=`expr "$2" : '\(.\)'` - - case $_G_delim$_G_current_value$_G_delim in - *"$2$_G_delim"*) ;; - *) func_append "$@" ;; - esac -} - - -# func_arith TERM... -# ------------------ -# Set func_arith_result to the result of evaluating TERMs. - test -z "$_G_HAVE_ARITH_OP" \ - && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ - && _G_HAVE_ARITH_OP=yes - -if test yes = "$_G_HAVE_ARITH_OP"; then - eval 'func_arith () - { - $debug_cmd - - func_arith_result=$(( $* )) - }' -else - func_arith () - { - $debug_cmd - - func_arith_result=`expr "$@"` - } -fi - - -# func_basename FILE -# ------------------ -# Set func_basename_result to FILE with everything up to and including -# the last / stripped. -if test yes = "$_G_HAVE_XSI_OPS"; then - # If this shell supports suffix pattern removal, then use it to avoid - # forking. Hide the definitions single quotes in case the shell chokes - # on unsupported syntax... - _b='func_basename_result=${1##*/}' - _d='case $1 in - */*) func_dirname_result=${1%/*}$2 ;; - * ) func_dirname_result=$3 ;; - esac' - -else - # ...otherwise fall back to using sed. - _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' - _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` - if test "X$func_dirname_result" = "X$1"; then - func_dirname_result=$3 - else - func_append func_dirname_result "$2" - fi' -fi - -eval 'func_basename () -{ - $debug_cmd - - '"$_b"' -}' - - -# func_dirname FILE APPEND NONDIR_REPLACEMENT -# ------------------------------------------- -# Compute the dirname of FILE. If nonempty, add APPEND to the result, -# otherwise set result to NONDIR_REPLACEMENT. -eval 'func_dirname () -{ - $debug_cmd - - '"$_d"' -}' - - -# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT -# -------------------------------------------------------- -# Perform func_basename and func_dirname in a single function -# call: -# dirname: Compute the dirname of FILE. If nonempty, -# add APPEND to the result, otherwise set result -# to NONDIR_REPLACEMENT. -# value returned in "$func_dirname_result" -# basename: Compute filename of FILE. -# value returned in "$func_basename_result" -# For efficiency, we do not delegate to the functions above but instead -# duplicate the functionality here. -eval 'func_dirname_and_basename () -{ - $debug_cmd - - '"$_b"' - '"$_d"' -}' - - -# func_echo ARG... -# ---------------- -# Echo program name prefixed message. -func_echo () -{ - $debug_cmd - - _G_message=$* - - func_echo_IFS=$IFS - IFS=$nl - for _G_line in $_G_message; do - IFS=$func_echo_IFS - $ECHO "$progname: $_G_line" - done - IFS=$func_echo_IFS -} - - -# func_echo_all ARG... -# -------------------- -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "$*" -} - - -# func_echo_infix_1 INFIX ARG... -# ------------------------------ -# Echo program name, followed by INFIX on the first line, with any -# additional lines not showing INFIX. -func_echo_infix_1 () -{ - $debug_cmd - - $require_term_colors - - _G_infix=$1; shift - _G_indent=$_G_infix - _G_prefix="$progname: $_G_infix: " - _G_message=$* - - # Strip color escape sequences before counting printable length - for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" - do - test -n "$_G_tc" && { - _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` - _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` - } - done - _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes - - func_echo_infix_1_IFS=$IFS - IFS=$nl - for _G_line in $_G_message; do - IFS=$func_echo_infix_1_IFS - $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 - _G_prefix=$_G_indent - done - IFS=$func_echo_infix_1_IFS -} - - -# func_error ARG... -# ----------------- -# Echo program name prefixed message to standard error. -func_error () -{ - $debug_cmd - - $require_term_colors - - func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 -} - - -# func_fatal_error ARG... -# ----------------------- -# Echo program name prefixed message to standard error, and exit. -func_fatal_error () -{ - $debug_cmd - - func_error "$*" - exit $EXIT_FAILURE -} - - -# func_grep EXPRESSION FILENAME -# ----------------------------- -# Check whether EXPRESSION matches any line of FILENAME, without output. -func_grep () -{ - $debug_cmd - - $GREP "$1" "$2" >/dev/null 2>&1 -} - - -# func_len STRING -# --------------- -# Set func_len_result to the length of STRING. STRING may not -# start with a hyphen. - test -z "$_G_HAVE_XSI_OPS" \ - && (eval 'x=a/b/c; - test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ - && _G_HAVE_XSI_OPS=yes - -if test yes = "$_G_HAVE_XSI_OPS"; then - eval 'func_len () - { - $debug_cmd - - func_len_result=${#1} - }' -else - func_len () - { - $debug_cmd - - func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` - } -fi - - -# func_mkdir_p DIRECTORY-PATH -# --------------------------- -# Make sure the entire path to DIRECTORY-PATH is available. -func_mkdir_p () -{ - $debug_cmd - - _G_directory_path=$1 - _G_dir_list= - - if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then - - # Protect directory names starting with '-' - case $_G_directory_path in - -*) _G_directory_path=./$_G_directory_path ;; - esac - - # While some portion of DIR does not yet exist... - while test ! -d "$_G_directory_path"; do - # ...make a list in topmost first order. Use a colon delimited - # list in case some portion of path contains whitespace. - _G_dir_list=$_G_directory_path:$_G_dir_list - - # If the last portion added has no slash in it, the list is done - case $_G_directory_path in */*) ;; *) break ;; esac - - # ...otherwise throw away the child directory and loop - _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` - done - _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` - - func_mkdir_p_IFS=$IFS; IFS=: - for _G_dir in $_G_dir_list; do - IFS=$func_mkdir_p_IFS - # mkdir can fail with a 'File exist' error if two processes - # try to create one of the directories concurrently. Don't - # stop in that case! - $MKDIR "$_G_dir" 2>/dev/null || : - done - IFS=$func_mkdir_p_IFS - - # Bail out if we (or some other process) failed to create a directory. - test -d "$_G_directory_path" || \ - func_fatal_error "Failed to create '$1'" - fi -} - - -# func_mktempdir [BASENAME] -# ------------------------- -# Make a temporary directory that won't clash with other running -# libtool processes, and avoids race conditions if possible. If -# given, BASENAME is the basename for that directory. -func_mktempdir () -{ - $debug_cmd - - _G_template=${TMPDIR-/tmp}/${1-$progname} - - if test : = "$opt_dry_run"; then - # Return a directory name, but don't create it in dry-run mode - _G_tmpdir=$_G_template-$$ - else - - # If mktemp works, use that first and foremost - _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` - - if test ! -d "$_G_tmpdir"; then - # Failing that, at least try and use $RANDOM to avoid a race - _G_tmpdir=$_G_template-${RANDOM-0}$$ - - func_mktempdir_umask=`umask` - umask 0077 - $MKDIR "$_G_tmpdir" - umask $func_mktempdir_umask - fi - - # If we're not in dry-run mode, bomb out on failure - test -d "$_G_tmpdir" || \ - func_fatal_error "cannot create temporary directory '$_G_tmpdir'" - fi - - $ECHO "$_G_tmpdir" -} - - -# func_normal_abspath PATH -# ------------------------ -# Remove doubled-up and trailing slashes, "." path components, -# and cancel out any ".." path components in PATH after making -# it an absolute path. -func_normal_abspath () -{ - $debug_cmd - - # These SED scripts presuppose an absolute path with a trailing slash. - _G_pathcar='s|^/\([^/]*\).*$|\1|' - _G_pathcdr='s|^/[^/]*||' - _G_removedotparts=':dotsl - s|/\./|/|g - t dotsl - s|/\.$|/|' - _G_collapseslashes='s|/\{1,\}|/|g' - _G_finalslash='s|/*$|/|' - - # Start from root dir and reassemble the path. - func_normal_abspath_result= - func_normal_abspath_tpath=$1 - func_normal_abspath_altnamespace= - case $func_normal_abspath_tpath in - "") - # Empty path, that just means $cwd. - func_stripname '' '/' "`pwd`" - func_normal_abspath_result=$func_stripname_result - return - ;; - # The next three entries are used to spot a run of precisely - # two leading slashes without using negated character classes; - # we take advantage of case's first-match behaviour. - ///*) - # Unusual form of absolute path, do nothing. - ;; - //*) - # Not necessarily an ordinary path; POSIX reserves leading '//' - # and for example Cygwin uses it to access remote file shares - # over CIFS/SMB, so we conserve a leading double slash if found. - func_normal_abspath_altnamespace=/ - ;; - /*) - # Absolute path, do nothing. - ;; - *) - # Relative path, prepend $cwd. - func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath - ;; - esac - - # Cancel out all the simple stuff to save iterations. We also want - # the path to end with a slash for ease of parsing, so make sure - # there is one (and only one) here. - func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` - while :; do - # Processed it all yet? - if test / = "$func_normal_abspath_tpath"; then - # If we ascended to the root using ".." the result may be empty now. - if test -z "$func_normal_abspath_result"; then - func_normal_abspath_result=/ - fi - break - fi - func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$_G_pathcar"` - func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$_G_pathcdr"` - # Figure out what to do with it - case $func_normal_abspath_tcomponent in - "") - # Trailing empty path component, ignore it. - ;; - ..) - # Parent dir; strip last assembled component from result. - func_dirname "$func_normal_abspath_result" - func_normal_abspath_result=$func_dirname_result - ;; - *) - # Actual path component, append it. - func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" - ;; - esac - done - # Restore leading double-slash if one was found on entry. - func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result -} - - -# func_notquiet ARG... -# -------------------- -# Echo program name prefixed message only when not in quiet mode. -func_notquiet () -{ - $debug_cmd - - $opt_quiet || func_echo ${1+"$@"} - - # A bug in bash halts the script if the last line of a function - # fails when set -e is in force, so we need another command to - # work around that: - : -} - - -# func_relative_path SRCDIR DSTDIR -# -------------------------------- -# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. -func_relative_path () -{ - $debug_cmd - - func_relative_path_result= - func_normal_abspath "$1" - func_relative_path_tlibdir=$func_normal_abspath_result - func_normal_abspath "$2" - func_relative_path_tbindir=$func_normal_abspath_result - - # Ascend the tree starting from libdir - while :; do - # check if we have found a prefix of bindir - case $func_relative_path_tbindir in - $func_relative_path_tlibdir) - # found an exact match - func_relative_path_tcancelled= - break - ;; - $func_relative_path_tlibdir*) - # found a matching prefix - func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" - func_relative_path_tcancelled=$func_stripname_result - if test -z "$func_relative_path_result"; then - func_relative_path_result=. - fi - break - ;; - *) - func_dirname $func_relative_path_tlibdir - func_relative_path_tlibdir=$func_dirname_result - if test -z "$func_relative_path_tlibdir"; then - # Have to descend all the way to the root! - func_relative_path_result=../$func_relative_path_result - func_relative_path_tcancelled=$func_relative_path_tbindir - break - fi - func_relative_path_result=../$func_relative_path_result - ;; - esac - done - - # Now calculate path; take care to avoid doubling-up slashes. - func_stripname '' '/' "$func_relative_path_result" - func_relative_path_result=$func_stripname_result - func_stripname '/' '/' "$func_relative_path_tcancelled" - if test -n "$func_stripname_result"; then - func_append func_relative_path_result "/$func_stripname_result" - fi - - # Normalisation. If bindir is libdir, return '.' else relative path. - if test -n "$func_relative_path_result"; then - func_stripname './' '' "$func_relative_path_result" - func_relative_path_result=$func_stripname_result - fi - - test -n "$func_relative_path_result" || func_relative_path_result=. - - : -} - - -# func_quote_portable EVAL ARG -# ---------------------------- -# Internal function to portably implement func_quote_arg. Note that we still -# keep attention to performance here so we as much as possible try to avoid -# calling sed binary (so far O(N) complexity as long as func_append is O(1)). -func_quote_portable () -{ - $debug_cmd - - $require_check_ifs_backslash - - func_quote_portable_result=$2 - - # one-time-loop (easy break) - while true - do - if $1; then - func_quote_portable_result=`$ECHO "$2" | $SED \ - -e "$sed_double_quote_subst" -e "$sed_double_backslash"` - break - fi - - # Quote for eval. - case $func_quote_portable_result in - *[\\\`\"\$]*) - # Fallback to sed for $func_check_bs_ifs_broken=:, or when the string - # contains the shell wildcard characters. - case $check_ifs_backshlash_broken$func_quote_portable_result in - :*|*[\[\*\?]*) - func_quote_portable_result=`$ECHO "$func_quote_portable_result" \ - | $SED "$sed_quote_subst"` - break - ;; - esac - - func_quote_portable_old_IFS=$IFS - for _G_char in '\' '`' '"' '$' - do - # STATE($1) PREV($2) SEPARATOR($3) - set start "" "" - func_quote_portable_result=dummy"$_G_char$func_quote_portable_result$_G_char"dummy - IFS=$_G_char - for _G_part in $func_quote_portable_result - do - case $1 in - quote) - func_append func_quote_portable_result "$3$2" - set quote "$_G_part" "\\$_G_char" - ;; - start) - set first "" "" - func_quote_portable_result= - ;; - first) - set quote "$_G_part" "" - ;; - esac - done - done - IFS=$func_quote_portable_old_IFS - ;; - *) ;; - esac - break - done - - func_quote_portable_unquoted_result=$func_quote_portable_result - case $func_quote_portable_result in - # double-quote args containing shell metacharacters to delay - # word splitting, command substitution and variable expansion - # for a subsequent eval. - # many bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - func_quote_portable_result=\"$func_quote_portable_result\" - ;; - esac -} - - -# func_quotefast_eval ARG -# ----------------------- -# Quote one ARG (internal). This is equivalent to 'func_quote_arg eval ARG', -# but optimized for speed. Result is stored in $func_quotefast_eval. -if test xyes = `(x=; printf -v x %q yes; echo x"$x") 2>/dev/null`; then - printf -v _GL_test_printf_tilde %q '~' - if test '\~' = "$_GL_test_printf_tilde"; then - func_quotefast_eval () - { - printf -v func_quotefast_eval_result %q "$1" - } - else - # Broken older Bash implementations. Make those faster too if possible. - func_quotefast_eval () - { - case $1 in - '~'*) - func_quote_portable false "$1" - func_quotefast_eval_result=$func_quote_portable_result - ;; - *) - printf -v func_quotefast_eval_result %q "$1" - ;; - esac - } - fi -else - func_quotefast_eval () - { - func_quote_portable false "$1" - func_quotefast_eval_result=$func_quote_portable_result - } -fi - - -# func_quote_arg MODEs ARG -# ------------------------ -# Quote one ARG to be evaled later. MODEs argument may contain zero or more -# specifiers listed below separated by ',' character. This function returns two -# values: -# i) func_quote_arg_result -# double-quoted (when needed), suitable for a subsequent eval -# ii) func_quote_arg_unquoted_result -# has all characters that are still active within double -# quotes backslashified. Available only if 'unquoted' is specified. -# -# Available modes: -# ---------------- -# 'eval' (default) -# - escape shell special characters -# 'expand' -# - the same as 'eval'; but do not quote variable references -# 'pretty' -# - request aesthetic output, i.e. '"a b"' instead of 'a\ b'. This might -# be used later in func_quote to get output like: 'echo "a b"' instead -# of 'echo a\ b'. This is slower than default on some shells. -# 'unquoted' -# - produce also $func_quote_arg_unquoted_result which does not contain -# wrapping double-quotes. -# -# Examples for 'func_quote_arg pretty,unquoted string': -# -# string | *_result | *_unquoted_result -# ------------+-----------------------+------------------- -# " | \" | \" -# a b | "a b" | a b -# "a b" | "\"a b\"" | \"a b\" -# * | "*" | * -# z="${x-$y}" | "z=\"\${x-\$y}\"" | z=\"\${x-\$y}\" -# -# Examples for 'func_quote_arg pretty,unquoted,expand string': -# -# string | *_result | *_unquoted_result -# --------------+---------------------+-------------------- -# z="${x-$y}" | "z=\"${x-$y}\"" | z=\"${x-$y}\" -func_quote_arg () -{ - _G_quote_expand=false - case ,$1, in - *,expand,*) - _G_quote_expand=: - ;; - esac - - case ,$1, in - *,pretty,*|*,expand,*|*,unquoted,*) - func_quote_portable $_G_quote_expand "$2" - func_quote_arg_result=$func_quote_portable_result - func_quote_arg_unquoted_result=$func_quote_portable_unquoted_result - ;; - *) - # Faster quote-for-eval for some shells. - func_quotefast_eval "$2" - func_quote_arg_result=$func_quotefast_eval_result - ;; - esac -} - - -# func_quote MODEs ARGs... -# ------------------------ -# Quote all ARGs to be evaled later and join them into single command. See -# func_quote_arg's description for more info. -func_quote () -{ - $debug_cmd - _G_func_quote_mode=$1 ; shift - func_quote_result= - while test 0 -lt $#; do - func_quote_arg "$_G_func_quote_mode" "$1" - if test -n "$func_quote_result"; then - func_append func_quote_result " $func_quote_arg_result" - else - func_append func_quote_result "$func_quote_arg_result" - fi - shift - done -} - - -# func_stripname PREFIX SUFFIX NAME -# --------------------------------- -# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -if test yes = "$_G_HAVE_XSI_OPS"; then - eval 'func_stripname () - { - $debug_cmd - - # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are - # positional parameters, so assign one to ordinary variable first. - func_stripname_result=$3 - func_stripname_result=${func_stripname_result#"$1"} - func_stripname_result=${func_stripname_result%"$2"} - }' -else - func_stripname () - { - $debug_cmd - - case $2 in - .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; - *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; - esac - } -fi - - -# func_show_eval CMD [FAIL_EXP] -# ----------------------------- -# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is -# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP -# is given, then evaluate it. -func_show_eval () -{ - $debug_cmd - - _G_cmd=$1 - _G_fail_exp=${2-':'} - - func_quote_arg pretty,expand "$_G_cmd" - eval "func_notquiet $func_quote_arg_result" - - $opt_dry_run || { - eval "$_G_cmd" - _G_status=$? - if test 0 -ne "$_G_status"; then - eval "(exit $_G_status); $_G_fail_exp" - fi - } -} - - -# func_show_eval_locale CMD [FAIL_EXP] -# ------------------------------------ -# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is -# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP -# is given, then evaluate it. Use the saved locale for evaluation. -func_show_eval_locale () -{ - $debug_cmd - - _G_cmd=$1 - _G_fail_exp=${2-':'} - - $opt_quiet || { - func_quote_arg expand,pretty "$_G_cmd" - eval "func_echo $func_quote_arg_result" - } - - $opt_dry_run || { - eval "$_G_user_locale - $_G_cmd" - _G_status=$? - eval "$_G_safe_locale" - if test 0 -ne "$_G_status"; then - eval "(exit $_G_status); $_G_fail_exp" - fi - } -} - - -# func_tr_sh -# ---------- -# Turn $1 into a string suitable for a shell variable name. -# Result is stored in $func_tr_sh_result. All characters -# not in the set a-zA-Z0-9_ are replaced with '_'. Further, -# if $1 begins with a digit, a '_' is prepended as well. -func_tr_sh () -{ - $debug_cmd - - case $1 in - [0-9]* | *[!a-zA-Z0-9_]*) - func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` - ;; - * ) - func_tr_sh_result=$1 - ;; - esac -} - - -# func_verbose ARG... -# ------------------- -# Echo program name prefixed message in verbose mode only. -func_verbose () -{ - $debug_cmd - - $opt_verbose && func_echo "$*" - - : -} - - -# func_warn_and_continue ARG... -# ----------------------------- -# Echo program name prefixed warning message to standard error. -func_warn_and_continue () -{ - $debug_cmd - - $require_term_colors - - func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 -} - - -# func_warning CATEGORY ARG... -# ---------------------------- -# Echo program name prefixed warning message to standard error. Warning -# messages can be filtered according to CATEGORY, where this function -# elides messages where CATEGORY is not listed in the global variable -# 'opt_warning_types'. -func_warning () -{ - $debug_cmd - - # CATEGORY must be in the warning_categories list! - case " $warning_categories " in - *" $1 "*) ;; - *) func_internal_error "invalid warning category '$1'" ;; - esac - - _G_category=$1 - shift - - case " $opt_warning_types " in - *" $_G_category "*) $warning_func ${1+"$@"} ;; - esac -} - - -# func_sort_ver VER1 VER2 -# ----------------------- -# 'sort -V' is not generally available. -# Note this deviates from the version comparison in automake -# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a -# but this should suffice as we won't be specifying old -# version formats or redundant trailing .0 in bootstrap.conf. -# If we did want full compatibility then we should probably -# use m4_version_compare from autoconf. -func_sort_ver () -{ - $debug_cmd - - printf '%s\n%s\n' "$1" "$2" \ - | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n -} - -# func_lt_ver PREV CURR -# --------------------- -# Return true if PREV and CURR are in the correct order according to -# func_sort_ver, otherwise false. Use it like this: -# -# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." -func_lt_ver () -{ - $debug_cmd - - test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` -} - - -# Local variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" -# time-stamp-time-zone: "UTC" -# End: -#! /bin/sh - -# A portable, pluggable option parser for Bourne shell. -# Written by Gary V. Vaughan, 2010 - -# This is free software. There is NO warranty; not even for -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# Copyright (C) 2010-2019, 2021, 2023-2024 Bootstrap Authors -# -# This file is dual licensed under the terms of the MIT license -# , and GPL version 2 or later -# . You must apply one of -# these licenses when using or redistributing this software or any of -# the files within it. See the URLs above, or the file `LICENSE` -# included in the Bootstrap distribution for the full license texts. - -# Please report bugs or propose patches to: -# - -# Set a version string for this script. -scriptversion=2019-02-19.15; # UTC - - -## ------ ## -## Usage. ## -## ------ ## - -# This file is a library for parsing options in your shell scripts along -# with assorted other useful supporting features that you can make use -# of too. -# -# For the simplest scripts you might need only: -# -# #!/bin/sh -# . relative/path/to/funclib.sh -# . relative/path/to/options-parser -# scriptversion=1.0 -# func_options ${1+"$@"} -# eval set dummy "$func_options_result"; shift -# ...rest of your script... -# -# In order for the '--version' option to work, you will need to have a -# suitably formatted comment like the one at the top of this file -# starting with '# Written by ' and ending with '# Copyright'. -# -# For '-h' and '--help' to work, you will also need a one line -# description of your script's purpose in a comment directly above the -# '# Written by ' line, like the one at the top of this file. -# -# The default options also support '--debug', which will turn on shell -# execution tracing (see the comment above debug_cmd below for another -# use), and '--verbose' and the func_verbose function to allow your script -# to display verbose messages only when your user has specified -# '--verbose'. -# -# After sourcing this file, you can plug in processing for additional -# options by amending the variables from the 'Configuration' section -# below, and following the instructions in the 'Option parsing' -# section further down. - -## -------------- ## -## Configuration. ## -## -------------- ## - -# You should override these variables in your script after sourcing this -# file so that they reflect the customisations you have added to the -# option parser. - -# The usage line for option parsing errors and the start of '-h' and -# '--help' output messages. You can embed shell variables for delayed -# expansion at the time the message is displayed, but you will need to -# quote other shell meta-characters carefully to prevent them being -# expanded when the contents are evaled. -usage='$progpath [OPTION]...' - -# Short help message in response to '-h' and '--help'. Add to this or -# override it after sourcing this library to reflect the full set of -# options your script accepts. -usage_message="\ - --debug enable verbose shell tracing - -W, --warnings=CATEGORY - report the warnings falling in CATEGORY [all] - -v, --verbose verbosely report processing - --version print version information and exit - -h, --help print short or long help message and exit -" - -# Additional text appended to 'usage_message' in response to '--help'. -long_help_message=" -Warning categories include: - 'all' show all warnings - 'none' turn off all the warnings - 'error' warnings are treated as fatal errors" - -# Help message printed before fatal option parsing errors. -fatal_help="Try '\$progname --help' for more information." - - - -## ------------------------- ## -## Hook function management. ## -## ------------------------- ## - -# This section contains functions for adding, removing, and running hooks -# in the main code. A hook is just a list of function names that can be -# run in order later on. - -# func_hookable FUNC_NAME -# ----------------------- -# Declare that FUNC_NAME will run hooks added with -# 'func_add_hook FUNC_NAME ...'. -func_hookable () -{ - $debug_cmd - - func_append hookable_fns " $1" -} - - -# func_add_hook FUNC_NAME HOOK_FUNC -# --------------------------------- -# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must -# first have been declared "hookable" by a call to 'func_hookable'. -func_add_hook () -{ - $debug_cmd - - case " $hookable_fns " in - *" $1 "*) ;; - *) func_fatal_error "'$1' does not accept hook functions." ;; - esac - - eval func_append ${1}_hooks '" $2"' -} - - -# func_remove_hook FUNC_NAME HOOK_FUNC -# ------------------------------------ -# Remove HOOK_FUNC from the list of hook functions to be called by -# FUNC_NAME. -func_remove_hook () -{ - $debug_cmd - - eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' -} - - -# func_propagate_result FUNC_NAME_A FUNC_NAME_B -# --------------------------------------------- -# If the *_result variable of FUNC_NAME_A _is set_, assign its value to -# *_result variable of FUNC_NAME_B. -func_propagate_result () -{ - $debug_cmd - - func_propagate_result_result=: - if eval "test \"\${${1}_result+set}\" = set" - then - eval "${2}_result=\$${1}_result" - else - func_propagate_result_result=false - fi -} - - -# func_run_hooks FUNC_NAME [ARG]... -# --------------------------------- -# Run all hook functions registered to FUNC_NAME. -# It's assumed that the list of hook functions contains nothing more -# than a whitespace-delimited list of legal shell function names, and -# no effort is wasted trying to catch shell meta-characters or preserve -# whitespace. -func_run_hooks () -{ - $debug_cmd - - case " $hookable_fns " in - *" $1 "*) ;; - *) func_fatal_error "'$1' does not support hook functions." ;; - esac - - eval _G_hook_fns=\$$1_hooks; shift - - for _G_hook in $_G_hook_fns; do - func_unset "${_G_hook}_result" - eval $_G_hook '${1+"$@"}' - func_propagate_result $_G_hook func_run_hooks - if $func_propagate_result_result; then - eval set dummy "$func_run_hooks_result"; shift - fi - done -} - - - -## --------------- ## -## Option parsing. ## -## --------------- ## - -# In order to add your own option parsing hooks, you must accept the -# full positional parameter list from your hook function. You may remove -# or edit any options that you action, and then pass back the remaining -# unprocessed options in '_result', escaped -# suitably for 'eval'. -# -# The '_result' variable is automatically unset -# before your hook gets called; for best performance, only set the -# *_result variable when necessary (i.e. don't call the 'func_quote' -# function unnecessarily because it can be an expensive operation on some -# machines). -# -# Like this: -# -# my_options_prep () -# { -# $debug_cmd -# -# # Extend the existing usage message. -# usage_message=$usage_message' -# -s, --silent don'\''t print informational messages -# ' -# # No change in '$@' (ignored completely by this hook). Leave -# # my_options_prep_result variable intact. -# } -# func_add_hook func_options_prep my_options_prep -# -# -# my_silent_option () -# { -# $debug_cmd -# -# args_changed=false -# -# # Note that, for efficiency, we parse as many options as we can -# # recognise in a loop before passing the remainder back to the -# # caller on the first unrecognised argument we encounter. -# while test $# -gt 0; do -# opt=$1; shift -# case $opt in -# --silent|-s) opt_silent=: -# args_changed=: -# ;; -# # Separate non-argument short options: -# -s*) func_split_short_opt "$_G_opt" -# set dummy "$func_split_short_opt_name" \ -# "-$func_split_short_opt_arg" ${1+"$@"} -# shift -# args_changed=: -# ;; -# *) # Make sure the first unrecognised option "$_G_opt" -# # is added back to "$@" in case we need it later, -# # if $args_changed was set to 'true'. -# set dummy "$_G_opt" ${1+"$@"}; shift; break ;; -# esac -# done -# -# # Only call 'func_quote' here if we processed at least one argument. -# if $args_changed; then -# func_quote eval ${1+"$@"} -# my_silent_option_result=$func_quote_result -# fi -# } -# func_add_hook func_parse_options my_silent_option -# -# -# my_option_validation () -# { -# $debug_cmd -# -# $opt_silent && $opt_verbose && func_fatal_help "\ -# '--silent' and '--verbose' options are mutually exclusive." -# } -# func_add_hook func_validate_options my_option_validation -# -# You'll also need to manually amend $usage_message to reflect the extra -# options you parse. It's preferable to append if you can, so that -# multiple option parsing hooks can be added safely. - - -# func_options_finish [ARG]... -# ---------------------------- -# Finishing the option parse loop (call 'func_options' hooks ATM). -func_options_finish () -{ - $debug_cmd - - func_run_hooks func_options ${1+"$@"} - func_propagate_result func_run_hooks func_options_finish -} - - -# func_options [ARG]... -# --------------------- -# All the functions called inside func_options are hookable. See the -# individual implementations for details. -func_hookable func_options -func_options () -{ - $debug_cmd - - _G_options_quoted=false - - for my_func in options_prep parse_options validate_options options_finish - do - func_unset func_${my_func}_result - func_unset func_run_hooks_result - eval func_$my_func '${1+"$@"}' - func_propagate_result func_$my_func func_options - if $func_propagate_result_result; then - eval set dummy "$func_options_result"; shift - _G_options_quoted=: - fi - done - - $_G_options_quoted || { - # As we (func_options) are top-level options-parser function and - # nobody quoted "$@" for us yet, we need to do it explicitly for - # caller. - func_quote eval ${1+"$@"} - func_options_result=$func_quote_result - } -} - - -# func_options_prep [ARG]... -# -------------------------- -# All initialisations required before starting the option parse loop. -# Note that when calling hook functions, we pass through the list of -# positional parameters. If a hook function modifies that list, and -# needs to propagate that back to rest of this script, then the complete -# modified list must be put in 'func_run_hooks_result' before returning. -func_hookable func_options_prep -func_options_prep () -{ - $debug_cmd - - # Option defaults: - opt_verbose=false - opt_warning_types= - - func_run_hooks func_options_prep ${1+"$@"} - func_propagate_result func_run_hooks func_options_prep -} - - -# func_parse_options [ARG]... -# --------------------------- -# The main option parsing loop. -func_hookable func_parse_options -func_parse_options () -{ - $debug_cmd - - _G_parse_options_requote=false - # this just eases exit handling - while test $# -gt 0; do - # Defer to hook functions for initial option parsing, so they - # get priority in the event of reusing an option name. - func_run_hooks func_parse_options ${1+"$@"} - func_propagate_result func_run_hooks func_parse_options - if $func_propagate_result_result; then - eval set dummy "$func_parse_options_result"; shift - # Even though we may have changed "$@", we passed the "$@" array - # down into the hook and it quoted it for us (because we are in - # this if-branch). No need to quote it again. - _G_parse_options_requote=false - fi - - # Break out of the loop if we already parsed every option. - test $# -gt 0 || break - - # We expect that one of the options parsed in this function matches - # and thus we remove _G_opt from "$@" and need to re-quote. - _G_match_parse_options=: - _G_opt=$1 - shift - case $_G_opt in - --debug|-x) debug_cmd='set -x' - func_echo "enabling shell trace mode" >&2 - $debug_cmd - ;; - - --no-warnings|--no-warning|--no-warn) - set dummy --warnings none ${1+"$@"} - shift - ;; - - --warnings|--warning|-W) - if test $# = 0 && func_missing_arg $_G_opt; then - _G_parse_options_requote=: - break - fi - case " $warning_categories $1" in - *" $1 "*) - # trailing space prevents matching last $1 above - func_append_uniq opt_warning_types " $1" - ;; - *all) - opt_warning_types=$warning_categories - ;; - *none) - opt_warning_types=none - warning_func=: - ;; - *error) - opt_warning_types=$warning_categories - warning_func=func_fatal_error - ;; - *) - func_fatal_error \ - "unsupported warning category: '$1'" - ;; - esac - shift - ;; - - --verbose|-v) opt_verbose=: ;; - --version) func_version ;; - -\?|-h) func_usage ;; - --help) func_help ;; - - # Separate optargs to long options (plugins may need this): - --*=*) func_split_equals "$_G_opt" - set dummy "$func_split_equals_lhs" \ - "$func_split_equals_rhs" ${1+"$@"} - shift - ;; - - # Separate optargs to short options: - -W*) - func_split_short_opt "$_G_opt" - set dummy "$func_split_short_opt_name" \ - "$func_split_short_opt_arg" ${1+"$@"} - shift - ;; - - # Separate non-argument short options: - -\?*|-h*|-v*|-x*) - func_split_short_opt "$_G_opt" - set dummy "$func_split_short_opt_name" \ - "-$func_split_short_opt_arg" ${1+"$@"} - shift - ;; - - --) _G_parse_options_requote=: ; break ;; - -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; - *) set dummy "$_G_opt" ${1+"$@"}; shift - _G_match_parse_options=false - break - ;; - esac - - if $_G_match_parse_options; then - _G_parse_options_requote=: - fi - done - - if $_G_parse_options_requote; then - # save modified positional parameters for caller - func_quote eval ${1+"$@"} - func_parse_options_result=$func_quote_result - fi -} - - -# func_validate_options [ARG]... -# ------------------------------ -# Perform any sanity checks on option settings and/or unconsumed -# arguments. -func_hookable func_validate_options -func_validate_options () -{ - $debug_cmd - - # Display all warnings if -W was not given. - test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" - - func_run_hooks func_validate_options ${1+"$@"} - func_propagate_result func_run_hooks func_validate_options - - # Bail if the options were screwed! - $exit_cmd $EXIT_FAILURE -} - - - -## ----------------- ## -## Helper functions. ## -## ----------------- ## - -# This section contains the helper functions used by the rest of the -# hookable option parser framework in ascii-betical order. - - -# func_fatal_help ARG... -# ---------------------- -# Echo program name prefixed message to standard error, followed by -# a help hint, and exit. -func_fatal_help () -{ - $debug_cmd - - eval \$ECHO \""Usage: $usage"\" - eval \$ECHO \""$fatal_help"\" - func_error ${1+"$@"} - exit $EXIT_FAILURE -} - - -# func_help -# --------- -# Echo long help message to standard output and exit. -func_help () -{ - $debug_cmd - - func_usage_message - $ECHO "$long_help_message" - exit 0 -} - - -# func_missing_arg ARGNAME -# ------------------------ -# Echo program name prefixed message to standard error and set global -# exit_cmd. -func_missing_arg () -{ - $debug_cmd - - func_error "Missing argument for '$1'." - exit_cmd=exit -} - - -# func_split_equals STRING -# ------------------------ -# Set func_split_equals_lhs and func_split_equals_rhs shell variables -# after splitting STRING at the '=' sign. -test -z "$_G_HAVE_XSI_OPS" \ - && (eval 'x=a/b/c; - test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ - && _G_HAVE_XSI_OPS=yes - -if test yes = "$_G_HAVE_XSI_OPS" -then - # This is an XSI compatible shell, allowing a faster implementation... - eval 'func_split_equals () - { - $debug_cmd - - func_split_equals_lhs=${1%%=*} - func_split_equals_rhs=${1#*=} - if test "x$func_split_equals_lhs" = "x$1"; then - func_split_equals_rhs= - fi - }' -else - # ...otherwise fall back to using expr, which is often a shell builtin. - func_split_equals () - { - $debug_cmd - - func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` - func_split_equals_rhs= - test "x$func_split_equals_lhs=" = "x$1" \ - || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` - } -fi #func_split_equals - - -# func_split_short_opt SHORTOPT -# ----------------------------- -# Set func_split_short_opt_name and func_split_short_opt_arg shell -# variables after splitting SHORTOPT after the 2nd character. -if test yes = "$_G_HAVE_XSI_OPS" -then - # This is an XSI compatible shell, allowing a faster implementation... - eval 'func_split_short_opt () - { - $debug_cmd - - func_split_short_opt_arg=${1#??} - func_split_short_opt_name=${1%"$func_split_short_opt_arg"} - }' -else - # ...otherwise fall back to using expr, which is often a shell builtin. - func_split_short_opt () - { - $debug_cmd - - func_split_short_opt_name=`expr "x$1" : 'x\(-.\)'` - func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` - } -fi #func_split_short_opt - - -# func_usage -# ---------- -# Echo short help message to standard output and exit. -func_usage () -{ - $debug_cmd - - func_usage_message - $ECHO "Run '$progname --help |${PAGER-more}' for full usage" - exit 0 -} - - -# func_usage_message -# ------------------ -# Echo short help message to standard output. -func_usage_message () -{ - $debug_cmd - - eval \$ECHO \""Usage: $usage"\" - echo - $SED -n 's|^# || - /^Written by/{ - x;p;x - } - h - /^Written by/q' < "$progpath" - echo - eval \$ECHO \""$usage_message"\" -} - - -# func_version -# ------------ -# Echo version message to standard output and exit. -# The version message is extracted from the calling file's header -# comments, with leading '# ' stripped: -# 1. First display the progname and version -# 2. Followed by the header comment line matching /^# Written by / -# 3. Then a blank line followed by the first following line matching -# /^# Copyright / -# 4. Immediately followed by any lines between the previous matches, -# except lines preceding the intervening completely blank line. -# For example, see the header comments of this file. -func_version () -{ - $debug_cmd - - printf '%s\n' "$progname $scriptversion" - $SED -n ' - /^# Written by /!b - s|^# ||; p; n - - :fwd2blnk - /./ { - n - b fwd2blnk - } - p; n - - :holdwrnt - s|^# || - s|^# *$|| - /^Copyright /!{ - /./H - n - b holdwrnt - } - - s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| - G - s|\(\n\)\n*|\1|g - p; q' < "$progpath" - - exit $? -} - - -# Local variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-pattern: "30/scriptversion=%:y-%02m-%02d.%02H; # UTC" -# time-stamp-time-zone: "UTC" -# End: - -# Set a version string. -scriptversion='(GNU libtool) 2.5.4' - -# func_version -# ------------ -# Echo version message to standard output and exit. -func_version () -{ - $debug_cmd - - year=`date +%Y` - - cat < -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. - -Originally written by Gordon Matzigkeit, 1996 -(See AUTHORS for complete contributor listing) -EOF - - exit $? -} - - -# func_echo ARG... -# ---------------- -# Libtool also displays the current mode in messages, so override -# funclib.sh func_echo with this custom definition. -func_echo () -{ - $debug_cmd - - _G_message=$* - - func_echo_IFS=$IFS - IFS=$nl - for _G_line in $_G_message; do - IFS=$func_echo_IFS - $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" - done - IFS=$func_echo_IFS -} - - -## ---------------- ## -## Options parsing. ## -## ---------------- ## - -# Hook in the functions to make sure our own options are parsed during -# the option parsing loop. - -usage='$progpath [OPTION]... [MODE-ARG]...' - -# Short help message in response to '-h'. -usage_message="Options: - --config show all configuration variables - --debug enable verbose shell tracing - -n, --dry-run display commands without modifying any files - --features display basic configuration information - --finish use operation '--mode=finish' - --mode=MODE use operation mode MODE - --no-finish don't update shared library cache - --no-quiet, --no-silent print default informational messages - --no-warnings equivalent to '-Wnone' - --preserve-dup-deps don't remove duplicate dependency libraries - --quiet, --silent don't print informational messages - --reorder-cache=DIRS reorder shared library cache for preferred DIRS - --tag=TAG use configuration variables from tag TAG - -v, --verbose print more informational messages than default - --version print version information - -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] - -h, --help, --help-all print short, long, or detailed help message -" - -# Additional text appended to 'usage_message' in response to '--help'. -func_help () -{ - $debug_cmd - - func_usage_message - $ECHO "$long_help_message - -MODE must be one of the following: - - clean remove files from the build directory - compile compile a source file into a libtool object - execute automatically set library path, then run a program - finish complete the installation of libtool libraries - install install libraries or executables - link create a library or an executable - uninstall remove libraries from an installed directory - -MODE-ARGS vary depending on the MODE. When passed as first option, -'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. -Try '$progname --help --mode=MODE' for a more detailed description of MODE. - -When reporting a bug, please describe a test case to reproduce it and -include the following information: - - host-triplet: $host - shell: $SHELL - compiler: $LTCC - compiler flags: $LTCFLAGS - linker: $LD (gnu? $with_gnu_ld) - version: $progname $scriptversion - automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` - autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` - -Report bugs to . -GNU libtool home page: . -General help using GNU software: ." - exit 0 -} - - -# func_lo2o OBJECT-NAME -# --------------------- -# Transform OBJECT-NAME from a '.lo' suffix to the platform specific -# object suffix. - -lo2o=s/\\.lo\$/.$objext/ -o2lo=s/\\.$objext\$/.lo/ - -if test yes = "$_G_HAVE_XSI_OPS"; then - eval 'func_lo2o () - { - case $1 in - *.lo) func_lo2o_result=${1%.lo}.$objext ;; - * ) func_lo2o_result=$1 ;; - esac - }' - - # func_xform LIBOBJ-OR-SOURCE - # --------------------------- - # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) - # suffix to a '.lo' libtool-object suffix. - eval 'func_xform () - { - func_xform_result=${1%.*}.lo - }' -else - # ...otherwise fall back to using sed. - func_lo2o () - { - func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` - } - - func_xform () - { - func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` - } -fi - - -# func_fatal_configuration ARG... -# ------------------------------- -# Echo program name prefixed message to standard error, followed by -# a configuration failure hint, and exit. -func_fatal_configuration () -{ - func_fatal_error ${1+"$@"} \ - "See the $PACKAGE documentation for more information." \ - "Fatal configuration error." -} - - -# func_config -# ----------- -# Display the configuration for all the tags in this script. -func_config () -{ - re_begincf='^# ### BEGIN LIBTOOL' - re_endcf='^# ### END LIBTOOL' - - # Default configuration. - $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" - - # Now print the configurations for the tags. - for tagname in $taglist; do - $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" - done - - exit $? -} - - -# func_features -# ------------- -# Display the features supported by this script. -func_features () -{ - echo "host: $host" - if test yes = "$build_libtool_libs"; then - echo "enable shared libraries" - else - echo "disable shared libraries" - fi - if test yes = "$build_old_libs"; then - echo "enable static libraries" - else - echo "disable static libraries" - fi - - exit $? -} - - -# func_enable_tag TAGNAME -# ----------------------- -# Verify that TAGNAME is valid, and either flag an error and exit, or -# enable the TAGNAME tag. We also add TAGNAME to the global $taglist -# variable here. -func_enable_tag () -{ - # Global variable: - tagname=$1 - - re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" - re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" - sed_extractcf=/$re_begincf/,/$re_endcf/p - - # Validate tagname. - case $tagname in - *[!-_A-Za-z0-9,/]*) - func_fatal_error "invalid tag name: $tagname" - ;; - esac - - # Don't test for the "default" C tag, as we know it's - # there but not specially marked. - case $tagname in - CC) ;; - *) - if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then - taglist="$taglist $tagname" - - # Evaluate the configuration. Be careful to quote the path - # and the sed script, to avoid splitting on whitespace, but - # also don't use non-portable quotes within backquotes within - # quotes we have to do it in 2 steps: - extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` - eval "$extractedcf" - else - func_error "ignoring unknown tag $tagname" - fi - ;; - esac -} - - -# func_check_version_match -# ------------------------ -# Ensure that we are using m4 macros, and libtool script from the same -# release of libtool. -func_check_version_match () -{ - if test "$package_revision" != "$macro_revision"; then - if test "$VERSION" != "$macro_version"; then - if test -z "$macro_version"; then - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from an older release. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - fi - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, -$progname: but the definition of this LT_INIT comes from revision $macro_revision. -$progname: You should recreate aclocal.m4 with macros from revision $package_revision -$progname: of $PACKAGE $VERSION and run autoconf again. -_LT_EOF - fi - - exit $EXIT_MISMATCH - fi -} - - -# libtool_options_prep [ARG]... -# ----------------------------- -# Preparation for options parsed by libtool. -libtool_options_prep () -{ - $debug_mode - - # Option defaults: - opt_config=false - opt_dlopen= - opt_dry_run=false - opt_help=false - opt_mode= - opt_reorder_cache=false - opt_preserve_dup_deps=false - opt_quiet=false - opt_finishing=true - opt_warning= - - nonopt= - preserve_args= - - _G_rc_lt_options_prep=: - - # Shorthand for --mode=foo, only valid as the first argument - case $1 in - clean|clea|cle|cl) - shift; set dummy --mode clean ${1+"$@"}; shift - ;; - compile|compil|compi|comp|com|co|c) - shift; set dummy --mode compile ${1+"$@"}; shift - ;; - execute|execut|execu|exec|exe|ex|e) - shift; set dummy --mode execute ${1+"$@"}; shift - ;; - finish|finis|fini|fin|fi|f) - shift; set dummy --mode finish ${1+"$@"}; shift - ;; - install|instal|insta|inst|ins|in|i) - shift; set dummy --mode install ${1+"$@"}; shift - ;; - link|lin|li|l) - shift; set dummy --mode link ${1+"$@"}; shift - ;; - uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) - shift; set dummy --mode uninstall ${1+"$@"}; shift - ;; - *) - _G_rc_lt_options_prep=false - ;; - esac - - if $_G_rc_lt_options_prep; then - # Pass back the list of options. - func_quote eval ${1+"$@"} - libtool_options_prep_result=$func_quote_result - fi -} -func_add_hook func_options_prep libtool_options_prep - - -# libtool_parse_options [ARG]... -# --------------------------------- -# Provide handling for libtool specific options. -libtool_parse_options () -{ - $debug_cmd - - _G_rc_lt_parse_options=false - - # Perform our own loop to consume as many options as possible in - # each iteration. - while test $# -gt 0; do - _G_match_lt_parse_options=: - _G_opt=$1 - shift - case $_G_opt in - --dry-run|--dryrun|-n) - opt_dry_run=: - ;; - - --config) func_config ;; - - --dlopen|-dlopen) - opt_dlopen="${opt_dlopen+$opt_dlopen -}$1" - shift - ;; - - --preserve-dup-deps) - opt_preserve_dup_deps=: ;; - - --features) func_features ;; - - --finish) set dummy --mode finish ${1+"$@"}; shift ;; - - --help) opt_help=: ;; - - --help-all) opt_help=': help-all' ;; - - --mode) test $# = 0 && func_missing_arg $_G_opt && break - opt_mode=$1 - case $1 in - # Valid mode arguments: - clean|compile|execute|finish|install|link|relink|uninstall) ;; - - # Catch anything else as an error - *) func_error "invalid argument '$1' for $_G_opt" - exit_cmd=exit - ;; - esac - shift - ;; - - --no-finish) - opt_finishing=false - func_append preserve_args " $_G_opt" - ;; - - --no-silent|--no-quiet) - opt_quiet=false - func_append preserve_args " $_G_opt" - ;; - - --no-warnings|--no-warning|--no-warn) - opt_warning=false - func_append preserve_args " $_G_opt" - ;; - - --no-verbose) - opt_verbose=false - func_append preserve_args " $_G_opt" - ;; - - --reorder-cache) - opt_reorder_cache=true - shared_lib_dirs=$1 - if test -n "$shared_lib_dirs"; then - case $1 in - # Must begin with /: - /*) ;; - - # Catch anything else as an error (relative paths) - *) func_error "invalid argument '$1' for $_G_opt" - func_error "absolute paths are required for $_G_opt" - exit_cmd=exit - ;; - esac - fi - shift - ;; - - --silent|--quiet) - opt_quiet=: - opt_verbose=false - func_append preserve_args " $_G_opt" - ;; - - --tag) test $# = 0 && func_missing_arg $_G_opt && break - opt_tag=$1 - func_append preserve_args " $_G_opt $1" - func_enable_tag "$1" - shift - ;; - - --verbose|-v) opt_quiet=false - opt_verbose=: - func_append preserve_args " $_G_opt" - ;; - - # An option not handled by this hook function: - *) set dummy "$_G_opt" ${1+"$@"} ; shift - _G_match_lt_parse_options=false - break - ;; - esac - $_G_match_lt_parse_options && _G_rc_lt_parse_options=: - done - - if $_G_rc_lt_parse_options; then - # save modified positional parameters for caller - func_quote eval ${1+"$@"} - libtool_parse_options_result=$func_quote_result - fi -} -func_add_hook func_parse_options libtool_parse_options - - -# func_warning ARG... -# ------------------- -# Libtool warnings are not categorized, so override funclib.sh -# func_warning with this simpler definition. -func_warning () -{ - if $opt_warning; then - $debug_cmd - $warning_func ${1+"$@"} - fi -} - - -# libtool_validate_options [ARG]... -# --------------------------------- -# Perform any sanity checks on option settings and/or unconsumed -# arguments. -libtool_validate_options () -{ - # save first non-option argument - if test 0 -lt $#; then - nonopt=$1 - shift - fi - - # preserve --debug - test : = "$debug_cmd" || func_append preserve_args " --debug" - - case $host_os in - # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 - # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 - cygwin* | mingw* | windows* | pw32* | cegcc* | solaris2* | os2*) - # don't eliminate duplications in $postdeps and $predeps - opt_duplicate_compiler_generated_deps=: - ;; - *) - opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps - ;; - esac - - $opt_help || { - # Sanity checks first: - func_check_version_match - - test yes != "$build_libtool_libs" \ - && test yes != "$build_old_libs" \ - && func_fatal_configuration "not configured to build any kind of library" - - # Darwin sucks - eval std_shrext=\"$shrext_cmds\" - - # Only execute mode is allowed to have -dlopen flags. - if test -n "$opt_dlopen" && test execute != "$opt_mode"; then - func_error "unrecognized option '-dlopen'" - $ECHO "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Change the help message to a mode-specific one. - generic_help=$help - help="Try '$progname --help --mode=$opt_mode' for more information." - } - - # Pass back the unparsed argument list - func_quote eval ${1+"$@"} - libtool_validate_options_result=$func_quote_result -} -func_add_hook func_validate_options libtool_validate_options - - -# Process options as early as possible so that --help and --version -# can return quickly. -func_options ${1+"$@"} -eval set dummy "$func_options_result"; shift - - - -## ----------- ## -## Main. ## -## ----------- ## - -magic='%%%MAGIC variable%%%' -magic_exe='%%%MAGIC EXE variable%%%' - -# Global variables. -extracted_archives= -extracted_serial=0 - -# If this variable is set in any of the actions, the command in it -# will be execed at the end. This prevents here-documents from being -# left over by shells. -exec_cmd= - - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' -} - -# func_generated_by_libtool -# True iff stdin has been generated by Libtool. This function is only -# a basic sanity check; it will hardly flush out determined imposters. -func_generated_by_libtool_p () -{ - $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 -} - -# func_lalib_p file -# True iff FILE is a libtool '.la' library or '.lo' object file. -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_lalib_p () -{ - test -f "$1" && - $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p -} - -# func_lalib_unsafe_p file -# True iff FILE is a libtool '.la' library or '.lo' object file. -# This function implements the same check as func_lalib_p without -# resorting to external programs. To this end, it redirects stdin and -# closes it afterwards, without saving the original file descriptor. -# As a safety measure, use it only where a negative result would be -# fatal anyway. Works if 'file' does not exist. -func_lalib_unsafe_p () -{ - lalib_p=no - if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then - for lalib_p_l in 1 2 3 4 - do - read lalib_p_line - case $lalib_p_line in - \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; - esac - done - exec 0<&5 5<&- - fi - test yes = "$lalib_p" -} - -# func_ltwrapper_script_p file -# True iff FILE is a libtool wrapper script -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_script_p () -{ - test -f "$1" && - $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p -} - -# func_ltwrapper_executable_p file -# True iff FILE is a libtool wrapper executable -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_executable_p () -{ - func_ltwrapper_exec_suffix= - case $1 in - *.exe) ;; - *) func_ltwrapper_exec_suffix=.exe ;; - esac - $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 -} - -# func_ltwrapper_scriptname file -# Assumes file is an ltwrapper_executable -# uses $file to determine the appropriate filename for a -# temporary ltwrapper_script. -func_ltwrapper_scriptname () -{ - func_dirname_and_basename "$1" "" "." - func_stripname '' '.exe' "$func_basename_result" - func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper -} - -# func_ltwrapper_p file -# True iff FILE is a libtool wrapper script or wrapper executable -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_p () -{ - func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" -} - - -# func_execute_cmds commands fail_cmd -# Execute tilde-delimited COMMANDS. -# If FAIL_CMD is given, eval that upon failure. -# FAIL_CMD may read-access the current command in variable CMD! -func_execute_cmds () -{ - $debug_cmd - - save_ifs=$IFS; IFS='~' - for cmd in $1; do - IFS=$sp$nl - eval cmd=\"$cmd\" - IFS=$save_ifs - func_show_eval "$cmd" "${2-:}" - done - IFS=$save_ifs -} - - -# func_source file -# Source FILE, adding directory component if necessary. -# Note that it is not necessary on cygwin/mingw to append a dot to -# FILE even if both FILE and FILE.exe exist: automatic-append-.exe -# behavior happens only for exec(3), not for open(2)! Also, sourcing -# 'FILE.' does not work on cygwin managed mounts. -func_source () -{ - $debug_cmd - - case $1 in - */* | *\\*) . "$1" ;; - *) . "./$1" ;; - esac -} - - -# func_resolve_sysroot PATH -# Replace a leading = in PATH with a sysroot. Store the result into -# func_resolve_sysroot_result -func_resolve_sysroot () -{ - func_resolve_sysroot_result=$1 - case $func_resolve_sysroot_result in - =*) - func_stripname '=' '' "$func_resolve_sysroot_result" - func_resolve_sysroot_result=$lt_sysroot$func_stripname_result - ;; - esac -} - -# func_replace_sysroot PATH -# If PATH begins with the sysroot, replace it with = and -# store the result into func_replace_sysroot_result. -func_replace_sysroot () -{ - case $lt_sysroot:$1 in - ?*:"$lt_sysroot"*) - func_stripname "$lt_sysroot" '' "$1" - func_replace_sysroot_result='='$func_stripname_result - ;; - *) - # Including no sysroot. - func_replace_sysroot_result=$1 - ;; - esac -} - -# func_infer_tag arg -# Infer tagged configuration to use if any are available and -# if one wasn't chosen via the "--tag" command line option. -# Only attempt this if the compiler in the base compile -# command doesn't match the default compiler. -# arg is usually of the form 'gcc ...' -func_infer_tag () -{ - $debug_cmd - - if test -n "$available_tags" && test -z "$tagname"; then - CC_quoted= - for arg in $CC; do - func_append_quoted CC_quoted "$arg" - done - CC_expanded=`func_echo_all $CC` - CC_quoted_expanded=`func_echo_all $CC_quoted` - case $@ in - # Blanks in the command may have been stripped by the calling shell, - # but not from the CC environment variable when configure was run. - " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ - " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; - # Blanks at the start of $base_compile will cause this to fail - # if we don't check for them as well. - *) - for z in $available_tags; do - if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then - # Evaluate the configuration. - eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" - CC_quoted= - for arg in $CC; do - # Double-quote args containing other shell metacharacters. - func_append_quoted CC_quoted "$arg" - done - CC_expanded=`func_echo_all $CC` - CC_quoted_expanded=`func_echo_all $CC_quoted` - case "$@ " in - " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ - " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) - # The compiler in the base compile command matches - # the one in the tagged configuration. - # Assume this is the tagged configuration we want. - tagname=$z - break - ;; - esac - fi - done - # If $tagname still isn't set, then no tagged configuration - # was found and let the user know that the "--tag" command - # line option must be used. - if test -z "$tagname"; then - func_echo "unable to infer tagged configuration" - func_fatal_error "specify a tag with '--tag'" -# else -# func_verbose "using $tagname tagged configuration" - fi - ;; - esac - fi -} - - - -# func_write_libtool_object output_name pic_name nonpic_name -# Create a libtool object file (analogous to a ".la" file), -# but don't create it if we're doing a dry run. -func_write_libtool_object () -{ - write_libobj=$1 - if test yes = "$build_libtool_libs"; then - write_lobj=\'$2\' - else - write_lobj=none - fi - - if test yes = "$build_old_libs"; then - write_oldobj=\'$3\' - else - write_oldobj=none - fi - - $opt_dry_run || { - cat >${write_libobj}T </dev/null` - if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then - func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | - $SED -e "$sed_naive_backslashify"` - else - func_convert_core_file_wine_to_w32_result= - fi - fi -} -# end: func_convert_core_file_wine_to_w32 - - -# func_convert_core_path_wine_to_w32 ARG -# Helper function used by path conversion functions when $build is *nix, and -# $host is mingw, windows, cygwin, or some other w32 environment. Relies on a -# correctly configured wine environment available, with the winepath program -# in $build's $PATH. Assumes ARG has no leading or trailing path separator -# characters. -# -# ARG is path to be converted from $build format to win32. -# Result is available in $func_convert_core_path_wine_to_w32_result. -# Unconvertible file (directory) names in ARG are skipped; if no directory names -# are convertible, then the result may be empty. -func_convert_core_path_wine_to_w32 () -{ - $debug_cmd - - # unfortunately, winepath doesn't convert paths, only file names - func_convert_core_path_wine_to_w32_result= - if test -n "$1"; then - oldIFS=$IFS - IFS=: - for func_convert_core_path_wine_to_w32_f in $1; do - IFS=$oldIFS - func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" - if test -n "$func_convert_core_file_wine_to_w32_result"; then - if test -z "$func_convert_core_path_wine_to_w32_result"; then - func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result - else - func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" - fi - fi - done - IFS=$oldIFS - fi -} -# end: func_convert_core_path_wine_to_w32 - - -# func_cygpath ARGS... -# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when -# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) -# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or -# (2), returns the Cygwin file name or path in func_cygpath_result (input -# file name or path is assumed to be in w32 format, as previously converted -# from $build's *nix or MSYS format). In case (3), returns the w32 file name -# or path in func_cygpath_result (input file name or path is assumed to be in -# Cygwin format). Returns an empty string on error. -# -# ARGS are passed to cygpath, with the last one being the file name or path to -# be converted. -# -# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH -# environment variable; do not put it in $PATH. -func_cygpath () -{ - $debug_cmd - - if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then - func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` - if test "$?" -ne 0; then - # on failure, ensure result is empty - func_cygpath_result= - fi - else - func_cygpath_result= - func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" - fi -} -#end: func_cygpath - - -# func_convert_core_msys_to_w32 ARG -# Convert file name or path ARG from MSYS format to w32 format. Return -# result in func_convert_core_msys_to_w32_result. -func_convert_core_msys_to_w32 () -{ - $debug_cmd - - # awkward: cmd appends spaces to result - func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | - $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` -} -#end: func_convert_core_msys_to_w32 - - -# func_convert_file_check ARG1 ARG2 -# Verify that ARG1 (a file name in $build format) was converted to $host -# format in ARG2. Otherwise, emit an error message, but continue (resetting -# func_to_host_file_result to ARG1). -func_convert_file_check () -{ - $debug_cmd - - if test -z "$2" && test -n "$1"; then - func_error "Could not determine host file name corresponding to" - func_error " '$1'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback: - func_to_host_file_result=$1 - fi -} -# end func_convert_file_check - - -# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH -# Verify that FROM_PATH (a path in $build format) was converted to $host -# format in TO_PATH. Otherwise, emit an error message, but continue, resetting -# func_to_host_file_result to a simplistic fallback value (see below). -func_convert_path_check () -{ - $debug_cmd - - if test -z "$4" && test -n "$3"; then - func_error "Could not determine the host path corresponding to" - func_error " '$3'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback. This is a deliberately simplistic "conversion" and - # should not be "improved". See libtool.info. - if test "x$1" != "x$2"; then - lt_replace_pathsep_chars="s|$1|$2|g" - func_to_host_path_result=`echo "$3" | - $SED -e "$lt_replace_pathsep_chars"` - else - func_to_host_path_result=$3 - fi - fi -} -# end func_convert_path_check - - -# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG -# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT -# and appending REPL if ORIG matches BACKPAT. -func_convert_path_front_back_pathsep () -{ - $debug_cmd - - case $4 in - $1 ) func_to_host_path_result=$3$func_to_host_path_result - ;; - esac - case $4 in - $2 ) func_append func_to_host_path_result "$3" - ;; - esac -} -# end func_convert_path_front_back_pathsep - - -# func_convert_delimited_path PATH ORIG_DELIMITER NEW_DELIMITER -# Replaces a delimiter for a given path. -func_convert_delimited_path () -{ - converted_path=`$ECHO "$1" | $SED "s#$2#$3#g"` -} -# end func_convert_delimited_path - - -################################################## -# $build to $host FILE NAME CONVERSION FUNCTIONS # -################################################## -# invoked via '$to_host_file_cmd ARG' -# -# In each case, ARG is the path to be converted from $build to $host format. -# Result will be available in $func_to_host_file_result. - - -# func_to_host_file ARG -# Converts the file name ARG from $build format to $host format. Return result -# in func_to_host_file_result. -func_to_host_file () -{ - $debug_cmd - - $to_host_file_cmd "$1" -} -# end func_to_host_file - - -# func_to_tool_file ARG LAZY -# converts the file name ARG from $build format to toolchain format. Return -# result in func_to_tool_file_result. If the conversion in use is listed -# in (the comma separated) LAZY, no conversion takes place. -func_to_tool_file () -{ - $debug_cmd - - case ,$2, in - *,"$to_tool_file_cmd",*) - func_to_tool_file_result=$1 - ;; - *) - $to_tool_file_cmd "$1" - func_to_tool_file_result=$func_to_host_file_result - ;; - esac -} -# end func_to_tool_file - - -# func_convert_file_noop ARG -# Copy ARG to func_to_host_file_result. -func_convert_file_noop () -{ - func_to_host_file_result=$1 -} -# end func_convert_file_noop - - -# func_convert_file_msys_to_w32 ARG -# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic -# conversion to w32 is not available inside the cwrapper. Returns result in -# func_to_host_file_result. -func_convert_file_msys_to_w32 () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - func_convert_core_msys_to_w32 "$1" - func_to_host_file_result=$func_convert_core_msys_to_w32_result - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_msys_to_w32 - - -# func_convert_file_cygwin_to_w32 ARG -# Convert file name ARG from Cygwin to w32 format. Returns result in -# func_to_host_file_result. -func_convert_file_cygwin_to_w32 () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - # because $build is cygwin, we call "the" cygpath in $PATH; no need to use - # LT_CYGPATH in this case. - func_to_host_file_result=`cygpath -m "$1"` - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_cygwin_to_w32 - - -# func_convert_file_nix_to_w32 ARG -# Convert file name ARG from *nix to w32 format. Requires a wine environment -# and a working winepath. Returns result in func_to_host_file_result. -func_convert_file_nix_to_w32 () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - func_convert_core_file_wine_to_w32 "$1" - func_to_host_file_result=$func_convert_core_file_wine_to_w32_result - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_nix_to_w32 - - -# func_convert_file_msys_to_cygwin ARG -# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. -# Returns result in func_to_host_file_result. -func_convert_file_msys_to_cygwin () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - func_convert_core_msys_to_w32 "$1" - func_cygpath -u "$func_convert_core_msys_to_w32_result" - func_to_host_file_result=$func_cygpath_result - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_msys_to_cygwin - - -# func_convert_file_nix_to_cygwin ARG -# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed -# in a wine environment, working winepath, and LT_CYGPATH set. Returns result -# in func_to_host_file_result. -func_convert_file_nix_to_cygwin () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. - func_convert_core_file_wine_to_w32 "$1" - func_cygpath -u "$func_convert_core_file_wine_to_w32_result" - func_to_host_file_result=$func_cygpath_result - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_nix_to_cygwin - - -############################################# -# $build to $host PATH CONVERSION FUNCTIONS # -############################################# -# invoked via '$to_host_path_cmd ARG' -# -# In each case, ARG is the path to be converted from $build to $host format. -# The result will be available in $func_to_host_path_result. -# -# Path separators are also converted from $build format to $host format. If -# ARG begins or ends with a path separator character, it is preserved (but -# converted to $host format) on output. -# -# All path conversion functions are named using the following convention: -# file name conversion function : func_convert_file_X_to_Y () -# path conversion function : func_convert_path_X_to_Y () -# where, for any given $build/$host combination the 'X_to_Y' value is the -# same. If conversion functions are added for new $build/$host combinations, -# the two new functions must follow this pattern, or func_init_to_host_path_cmd -# will break. - - -# func_init_to_host_path_cmd -# Ensures that function "pointer" variable $to_host_path_cmd is set to the -# appropriate value, based on the value of $to_host_file_cmd. -to_host_path_cmd= -func_init_to_host_path_cmd () -{ - $debug_cmd - - if test -z "$to_host_path_cmd"; then - func_stripname 'func_convert_file_' '' "$to_host_file_cmd" - to_host_path_cmd=func_convert_path_$func_stripname_result - fi -} - - -# func_to_host_path ARG -# Converts the path ARG from $build format to $host format. Return result -# in func_to_host_path_result. -func_to_host_path () -{ - $debug_cmd - - func_init_to_host_path_cmd - $to_host_path_cmd "$1" -} -# end func_to_host_path - - -# func_convert_path_noop ARG -# Copy ARG to func_to_host_path_result. -func_convert_path_noop () -{ - func_to_host_path_result=$1 -} -# end func_convert_path_noop - - -# func_convert_path_msys_to_w32 ARG -# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic -# conversion to w32 is not available inside the cwrapper. Returns result in -# func_to_host_path_result. -func_convert_path_msys_to_w32 () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # Remove leading and trailing path separator characters from ARG. MSYS - # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; - # and winepath ignores them completely. - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" - func_to_host_path_result=$func_convert_core_msys_to_w32_result - func_convert_path_check : ";" \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" - fi -} -# end func_convert_path_msys_to_w32 - - -# func_convert_path_cygwin_to_w32 ARG -# Convert path ARG from Cygwin to w32 format. Returns result in -# func_to_host_file_result. -func_convert_path_cygwin_to_w32 () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # See func_convert_path_msys_to_w32: - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` - func_convert_path_check : ";" \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" - fi -} -# end func_convert_path_cygwin_to_w32 - - -# func_convert_path_nix_to_w32 ARG -# Convert path ARG from *nix to w32 format. Requires a wine environment and -# a working winepath. Returns result in func_to_host_file_result. -func_convert_path_nix_to_w32 () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # See func_convert_path_msys_to_w32: - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" - func_to_host_path_result=$func_convert_core_path_wine_to_w32_result - func_convert_path_check : ";" \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" - fi -} -# end func_convert_path_nix_to_w32 - - -# func_convert_path_msys_to_cygwin ARG -# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. -# Returns result in func_to_host_file_result. -func_convert_path_msys_to_cygwin () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # See func_convert_path_msys_to_w32: - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" - func_cygpath -u -p "$func_convert_core_msys_to_w32_result" - func_to_host_path_result=$func_cygpath_result - func_convert_path_check : : \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" : "$1" - fi -} -# end func_convert_path_msys_to_cygwin - - -# func_convert_path_nix_to_cygwin ARG -# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a -# a wine environment, working winepath, and LT_CYGPATH set. Returns result in -# func_to_host_file_result. -func_convert_path_nix_to_cygwin () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # Remove leading and trailing path separator characters from - # ARG. msys behavior is inconsistent here, cygpath turns them - # into '.;' and ';.', and winepath ignores them completely. - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" - func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" - func_to_host_path_result=$func_cygpath_result - func_convert_path_check : : \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" : "$1" - fi -} -# end func_convert_path_nix_to_cygwin - - -# func_dll_def_p FILE -# True iff FILE is a Windows DLL '.def' file. -# Keep in sync with _LT_DLL_DEF_P in libtool.m4 -func_dll_def_p () -{ - $debug_cmd - - func_dll_def_p_tmp=`$SED -n \ - -e 's/^[ ]*//' \ - -e '/^\(;.*\)*$/d' \ - -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ - -e q \ - "$1"` - test DEF = "$func_dll_def_p_tmp" -} - - -# func_reorder_shared_lib_cache DIRS -# Reorder the shared library cache by unconfiguring previous shared library cache -# and configuring preferred search directories before previous search directories. -# Previous shared library cache: /usr/lib /usr/local/lib -# Preferred search directories: /tmp/testing -# Reordered shared library cache: /tmp/testing /usr/lib /usr/local/lib -func_reorder_shared_lib_cache () -{ - $debug_cmd - - case $host_os in - openbsd*) - get_search_directories=`PATH="$PATH:/sbin" ldconfig -r | $GREP "search directories" | $SED "s#.*search directories:\ ##g"` - func_convert_delimited_path "$get_search_directories" ':' '\ ' - save_search_directories=$converted_path - func_convert_delimited_path "$1" ':' '\ ' - - # Ensure directories exist - for dir in $converted_path; do - # Ensure each directory is an absolute path - case $dir in - /*) ;; - *) func_error "Directory '$dir' is not an absolute path" - exit $EXIT_FAILURE ;; - esac - # Ensure no trailing slashes - func_stripname '' '/' "$dir" - dir=$func_stripname_result - if test -d "$dir"; then - if test -n "$preferred_search_directories"; then - preferred_search_directories="$preferred_search_directories $dir" - else - preferred_search_directories=$dir - fi - else - func_error "Directory '$dir' does not exist" - exit $EXIT_FAILURE - fi - done - - PATH="$PATH:/sbin" ldconfig -U $save_search_directories - PATH="$PATH:/sbin" ldconfig -m $preferred_search_directories $save_search_directories - get_search_directories=`PATH="$PATH:/sbin" ldconfig -r | $GREP "search directories" | $SED "s#.*search directories:\ ##g"` - func_convert_delimited_path "$get_search_directories" ':' '\ ' - reordered_search_directories=$converted_path - - $ECHO "Original: $save_search_directories" - $ECHO "Reordered: $reordered_search_directories" - exit $EXIT_SUCCESS - ;; - *) - func_error "--reorder-cache is not supported for host_os=$host_os." - exit $EXIT_FAILURE - ;; - esac -} -# end func_reorder_shared_lib_cache - - -# func_mode_compile arg... -func_mode_compile () -{ - $debug_cmd - - # Get the compilation command and the source file. - base_compile= - srcfile=$nonopt # always keep a non-empty value in "srcfile" - suppress_opt=yes - suppress_output= - arg_mode=normal - libobj= - later= - pie_flag= - - for arg - do - case $arg_mode in - arg ) - # do not "continue". Instead, add this to base_compile - lastarg=$arg - arg_mode=normal - ;; - - target ) - libobj=$arg - arg_mode=normal - continue - ;; - - normal ) - # Accept any command-line options. - case $arg in - -o) - test -n "$libobj" && \ - func_fatal_error "you cannot specify '-o' more than once" - arg_mode=target - continue - ;; - - -pie | -fpie | -fPIE) - func_append pie_flag " $arg" - continue - ;; - - -shared | -static | -prefer-pic | -prefer-non-pic) - func_append later " $arg" - continue - ;; - - -no-suppress) - suppress_opt=no - continue - ;; - - -Xcompiler) - arg_mode=arg # the next one goes into the "base_compile" arg list - continue # The current "srcfile" will either be retained or - ;; # replaced later. I would guess that would be a bug. - - -Wc,*) - func_stripname '-Wc,' '' "$arg" - args=$func_stripname_result - lastarg= - save_ifs=$IFS; IFS=, - for arg in $args; do - IFS=$save_ifs - func_append_quoted lastarg "$arg" - done - IFS=$save_ifs - func_stripname ' ' '' "$lastarg" - lastarg=$func_stripname_result - - # Add the arguments to base_compile. - func_append base_compile " $lastarg" - continue - ;; - - *) - # Accept the current argument as the source file. - # The previous "srcfile" becomes the current argument. - # - lastarg=$srcfile - srcfile=$arg - ;; - esac # case $arg - ;; - esac # case $arg_mode - - # Aesthetically quote the previous argument. - func_append_quoted base_compile "$lastarg" - done # for arg - - case $arg_mode in - arg) - func_fatal_error "you must specify an argument for -Xcompile" - ;; - target) - func_fatal_error "you must specify a target with '-o'" - ;; - *) - # Get the name of the library object. - test -z "$libobj" && { - func_basename "$srcfile" - libobj=$func_basename_result - } - ;; - esac - - # Recognize several different file suffixes. - # If the user specifies -o file.o, it is replaced with file.lo - case $libobj in - *.[cCFSifmso] | \ - *.ada | *.adb | *.ads | *.asm | \ - *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ - *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) - func_xform "$libobj" - libobj=$func_xform_result - ;; - esac - - case $libobj in - *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; - *) - func_fatal_error "cannot determine name of library object from '$libobj'" - ;; - esac - - func_infer_tag $base_compile - - for arg in $later; do - case $arg in - -shared) - test yes = "$build_libtool_libs" \ - || func_fatal_configuration "cannot build a shared library" - build_old_libs=no - continue - ;; - - -static) - build_libtool_libs=no - build_old_libs=yes - continue - ;; - - -prefer-pic) - pic_mode=yes - continue - ;; - - -prefer-non-pic) - pic_mode=no - continue - ;; - esac - done - - func_quote_arg pretty "$libobj" - test "X$libobj" != "X$func_quote_arg_result" \ - && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ - && func_warning "libobj name '$libobj' may not contain shell special characters." - func_dirname_and_basename "$obj" "/" "" - objname=$func_basename_result - xdir=$func_dirname_result - lobj=$xdir$objdir/$objname - - test -z "$base_compile" && \ - func_fatal_help "you must specify a compilation command" - - # Delete any leftover library objects. - if test yes = "$build_old_libs"; then - removelist="$obj $lobj $libobj ${libobj}T" - else - removelist="$lobj $libobj ${libobj}T" - fi - - # On Cygwin there's no "real" PIC flag so we must build both object types - case $host_os in - cygwin* | mingw* | windows* | pw32* | os2* | cegcc*) - pic_mode=default - ;; - esac - if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then - # non-PIC code in shared libraries is not supported - pic_mode=default - fi - - # Calculate the filename of the output object if compiler does - # not support -o with -c - if test no = "$compiler_c_o"; then - output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext - lockfile=$output_obj.lock - else - output_obj= - need_locks=no - lockfile= - fi - - # Lock this critical section if it is needed - # We use this script file to make the link, it avoids creating a new file - if test yes = "$need_locks"; then - until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do - func_echo "Waiting for $lockfile to be removed" - sleep 2 - done - elif test warn = "$need_locks"; then - if test -f "$lockfile"; then - $ECHO "\ -*** ERROR, $lockfile exists and contains: -`cat $lockfile 2>/dev/null` - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support '-c' and '-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - func_append removelist " $output_obj" - $ECHO "$srcfile" > "$lockfile" - fi - - $opt_dry_run || $RM $removelist - func_append removelist " $lockfile" - trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 - - func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 - srcfile=$func_to_tool_file_result - func_quote_arg pretty "$srcfile" - qsrcfile=$func_quote_arg_result - - # Only build a PIC object if we are building libtool libraries. - if test yes = "$build_libtool_libs"; then - # Without this assignment, base_compile gets emptied. - fbsd_hideous_sh_bug=$base_compile - - if test no != "$pic_mode"; then - command="$base_compile $qsrcfile $pic_flag" - else - # Don't build PIC code - command="$base_compile $qsrcfile" - fi - - func_mkdir_p "$xdir$objdir" - - if test -z "$output_obj"; then - # Place PIC objects in $objdir - func_append command " -o $lobj" - fi - - func_show_eval_locale "$command" \ - 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' - - if test warn = "$need_locks" && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $ECHO "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support '-c' and '-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed, then go on to compile the next one - if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then - func_show_eval '$MV "$output_obj" "$lobj"' \ - 'error=$?; $opt_dry_run || $RM $removelist; exit $error' - fi - - # Allow error messages only from the first compilation. - if test yes = "$suppress_opt"; then - suppress_output=' >/dev/null 2>&1' - fi - fi - - # Only build a position-dependent object if we build old libraries. - if test yes = "$build_old_libs"; then - if test yes != "$pic_mode"; then - # Don't build PIC code - command="$base_compile $qsrcfile$pie_flag" - else - command="$base_compile $qsrcfile $pic_flag" - fi - if test yes = "$compiler_c_o"; then - func_append command " -o $obj" - fi - - # Suppress compiler output if we already did a PIC compilation. - func_append command "$suppress_output" - func_show_eval_locale "$command" \ - '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' - - if test warn = "$need_locks" && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $ECHO "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support '-c' and '-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed - if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then - func_show_eval '$MV "$output_obj" "$obj"' \ - 'error=$?; $opt_dry_run || $RM $removelist; exit $error' - fi - fi - - $opt_dry_run || { - func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" - - # Unlock the critical section if it was locked - if test no != "$need_locks"; then - removelist=$lockfile - $RM "$lockfile" - fi - } - - exit $EXIT_SUCCESS -} - -$opt_help || { - test compile = "$opt_mode" && func_mode_compile ${1+"$@"} -} - -func_mode_help () -{ - # We need to display help for each of the modes. - case $opt_mode in - "") - # Generic help is extracted from the usage comments - # at the start of this file. - func_help - ;; - - clean) - $ECHO \ -"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... - -Remove files from the build directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed -to RM. - -If FILE is a libtool library, object or program, all the files associated -with it are deleted. Otherwise, only FILE itself is deleted using RM." - ;; - - compile) - $ECHO \ -"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE - -Compile a source file into a libtool library object. - -This mode accepts the following additional options: - - -o OUTPUT-FILE set the output file name to OUTPUT-FILE - -no-suppress do not suppress compiler output for multiple passes - -prefer-pic try to build PIC objects only - -prefer-non-pic try to build non-PIC objects only - -shared do not build a '.o' file suitable for static linking - -static only build a '.o' file suitable for static linking - -Wc,FLAG - -Xcompiler FLAG pass FLAG directly to the compiler - -COMPILE-COMMAND is a command to be used in creating a 'standard' object file -from the given SOURCEFILE. - -The output file name is determined by removing the directory component from -SOURCEFILE, then substituting the C source code suffix '.c' with the -library object suffix, '.lo'." - ;; - - execute) - $ECHO \ -"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... - -Automatically set library path, then run a program. - -This mode accepts the following additional options: - - -dlopen FILE add the directory containing FILE to the library path - -This mode sets the library path environment variable according to '-dlopen' -flags. - -If any of the ARGS are libtool executable wrappers, then they are translated -into their corresponding uninstalled binary, and any of their required library -directories are added to the library path. - -Then, COMMAND is executed, with ARGS as arguments." - ;; - - finish) - $ECHO \ -"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... - -Complete the installation of libtool libraries. - -Each LIBDIR is a directory that contains libtool libraries. - -The commands that this mode executes may require superuser privileges. Use -the '--dry-run' option if you just want to see what would be executed." - ;; - - install) - $ECHO \ -"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... - -Install executables or libraries. - -INSTALL-COMMAND is the installation command. The first component should be -either the 'install' or 'cp' program. - -The following components of INSTALL-COMMAND are treated specially: - - -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation - -The rest of the components are interpreted as arguments to that command (only -BSD-compatible install options are recognized)." - ;; - - link) - $ECHO \ -"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... - -Link object files or libraries together to form another library, or to -create an executable program. - -LINK-COMMAND is a command using the C compiler that you would use to create -a program from several object files. - -The following components of LINK-COMMAND are treated specially: - - -all-static do not do any dynamic linking at all - -avoid-version do not add a version suffix if possible - -bindir BINDIR specify path to binaries directory (for systems where - libraries must be found in the PATH setting at runtime) - -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime - -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols - -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) - -export-symbols SYMFILE - try to export only the symbols listed in SYMFILE - -export-symbols-regex REGEX - try to export only the symbols matching REGEX - -LLIBDIR search LIBDIR for required installed libraries - -lNAME OUTPUT-FILE requires the installed library libNAME - -module build a library that can dlopened - -no-fast-install disable the fast-install mode - -no-install link a not-installable executable - -no-undefined declare that a library does not refer to external symbols - -o OUTPUT-FILE create OUTPUT-FILE from the specified objects - -objectlist FILE use a list of object files found in FILE to specify objects - -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) - -precious-files-regex REGEX - don't remove output files matching REGEX - -release RELEASE specify package release information - -rpath LIBDIR the created library will eventually be installed in LIBDIR - -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries - -shared only do dynamic linking of libtool libraries - -shrext SUFFIX override the standard shared library file extension - -static do not do any dynamic linking of uninstalled libtool libraries - -static-libtool-libs - do not do any dynamic linking of libtool libraries - -version-info CURRENT[:REVISION[:AGE]] - specify library version info [each variable defaults to 0] - -weak LIBNAME declare that the target provides the LIBNAME interface - -Wc,FLAG - -Xcompiler FLAG pass linker-specific FLAG directly to the compiler - -Wa,FLAG - -Xassembler FLAG pass linker-specific FLAG directly to the assembler - -Wl,FLAG - -Xlinker FLAG pass linker-specific FLAG directly to the linker - -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) - -All other options (arguments beginning with '-') are ignored. - -Every other argument is treated as a filename. Files ending in '.la' are -treated as uninstalled libtool libraries, other files are standard or library -object files. - -If the OUTPUT-FILE ends in '.la', then a libtool library is created, -only library objects ('.lo' files) may be specified, and '-rpath' is -required, except when creating a convenience library. - -If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created -using 'ar' and 'ranlib', or on Windows using 'lib'. - -If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file -is created, otherwise an executable program is created." - ;; - - uninstall) - $ECHO \ -"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... - -Remove libraries from an installation directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed -to RM. - -If FILE is a libtool library, all the files associated with it are deleted. -Otherwise, only FILE itself is deleted using RM." - ;; - - *) - func_fatal_help "invalid operation mode '$opt_mode'" - ;; - esac - - echo - $ECHO "Try '$progname --help' for more information about other modes." -} - -# Now that we've collected a possible --mode arg, show help if necessary -if $opt_help; then - if test : = "$opt_help"; then - func_mode_help - else - { - func_help noexit - for opt_mode in compile link execute install finish uninstall clean; do - func_mode_help - done - } | $SED -n '1p; 2,$s/^Usage:/ or: /p' - { - func_help noexit - for opt_mode in compile link execute install finish uninstall clean; do - echo - func_mode_help - done - } | - $SED '1d - /^When reporting/,/^Report/{ - H - d - } - $x - /information about other modes/d - /more detailed .*MODE/d - s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' - fi - exit $? -fi - - -# If option '--reorder-cache', reorder the shared library cache and exit. -if $opt_reorder_cache; then - func_reorder_shared_lib_cache $shared_lib_dirs -fi - - -# func_mode_execute arg... -func_mode_execute () -{ - $debug_cmd - - # The first argument is the command name. - cmd=$nonopt - test -z "$cmd" && \ - func_fatal_help "you must specify a COMMAND" - - # Handle -dlopen flags immediately. - for file in $opt_dlopen; do - test -f "$file" \ - || func_fatal_help "'$file' is not a file" - - dir= - case $file in - *.la) - func_resolve_sysroot "$file" - file=$func_resolve_sysroot_result - - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$file" \ - || func_fatal_help "'$lib' is not a valid libtool archive" - - # Read the libtool library. - dlname= - library_names= - func_source "$file" - - # Skip this library if it cannot be dlopened. - if test -z "$dlname"; then - # Warn if it was a shared library. - test -n "$library_names" && \ - func_warning "'$file' was not linked with '-export-dynamic'" - continue - fi - - func_dirname "$file" "" "." - dir=$func_dirname_result - - if test -f "$dir/$objdir/$dlname"; then - func_append dir "/$objdir" - else - if test ! -f "$dir/$dlname"; then - func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" - fi - fi - ;; - - *.lo) - # Just add the directory containing the .lo file. - func_dirname "$file" "" "." - dir=$func_dirname_result - ;; - - *) - func_warning "'-dlopen' is ignored for non-libtool libraries and objects" - continue - ;; - esac - - # Get the absolute pathname. - absdir=`cd "$dir" && pwd` - test -n "$absdir" && dir=$absdir - - # Now add the directory to shlibpath_var. - if eval "test -z \"\$$shlibpath_var\""; then - eval "$shlibpath_var=\"\$dir\"" - else - eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" - fi - done - - # This variable tells wrapper scripts just to set shlibpath_var - # rather than running their programs. - libtool_execute_magic=$magic - - # Check if any of the arguments is a wrapper script. - args= - for file - do - case $file in - -* | *.la | *.lo ) ;; - *) - # Do a test to see if this is really a libtool program. - if func_ltwrapper_script_p "$file"; then - func_source "$file" - # Transform arg to wrapped name. - file=$progdir/$program - elif func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - func_source "$func_ltwrapper_scriptname_result" - # Transform arg to wrapped name. - file=$progdir/$program - fi - ;; - esac - # Quote arguments (to preserve shell metacharacters). - func_append_quoted args "$file" - done - - if $opt_dry_run; then - # Display what would be done. - if test -n "$shlibpath_var"; then - eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" - echo "export $shlibpath_var" - fi - $ECHO "$cmd$args" - exit $EXIT_SUCCESS - else - if test -n "$shlibpath_var"; then - # Export the shlibpath_var. - eval "export $shlibpath_var" - fi - - # Restore saved environment variables - for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES - do - eval "if test \"\${save_$lt_var+set}\" = set; then - $lt_var=\$save_$lt_var; export $lt_var - else - $lt_unset $lt_var - fi" - done - - # Now prepare to actually exec the command. - exec_cmd=\$cmd$args - fi -} - -test execute = "$opt_mode" && func_mode_execute ${1+"$@"} - - -# func_mode_finish arg... -func_mode_finish () -{ - $debug_cmd - - libs= - libdirs= - admincmds= - - for opt in "$nonopt" ${1+"$@"} - do - if test -d "$opt"; then - func_append libdirs " $opt" - - elif test -f "$opt"; then - if func_lalib_unsafe_p "$opt"; then - func_append libs " $opt" - else - func_warning "'$opt' is not a valid libtool archive" - fi - - else - func_fatal_error "invalid argument '$opt'" - fi - done - - if test -n "$libs"; then - if test -n "$lt_sysroot"; then - sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` - sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" - else - sysroot_cmd= - fi - - # Remove sysroot references - if $opt_dry_run; then - for lib in $libs; do - echo "removing references to $lt_sysroot and '=' prefixes from $lib" - done - else - tmpdir=`func_mktempdir` - for lib in $libs; do - $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ - > $tmpdir/tmp-la - mv -f $tmpdir/tmp-la $lib - done - ${RM}r "$tmpdir" - fi - fi - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs" && $opt_finishing; then - for libdir in $libdirs; do - if test -n "$finish_cmds"; then - # Do each command in the finish commands. - func_execute_cmds "$finish_cmds" 'admincmds="$admincmds -'"$cmd"'"' - fi - if test -n "$finish_eval"; then - # Do the single finish_eval. - eval cmds=\"$finish_eval\" - $opt_dry_run || eval "$cmds" || func_append admincmds " - $cmds" - fi - done - fi - - # Exit here if they wanted silent mode. - $opt_quiet && exit $EXIT_SUCCESS - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - echo "----------------------------------------------------------------------" - echo "Libraries have been installed in:" - for libdir in $libdirs; do - $ECHO " $libdir" - done - if test "false" = "$opt_finishing"; then - echo - echo "NOTE: finish_cmds were not executed during testing, so you must" - echo "manually run ldconfig to add a given test directory, LIBDIR, to" - echo "the search path for generated executables." - fi - echo - echo "If you ever happen to want to link against installed libraries" - echo "in a given directory, LIBDIR, you must either use libtool, and" - echo "specify the full pathname of the library, or use the '-LLIBDIR'" - echo "flag during linking and do at least one of the following:" - if test -n "$shlibpath_var"; then - echo " - add LIBDIR to the '$shlibpath_var' environment variable" - echo " during execution" - fi - if test -n "$runpath_var"; then - echo " - add LIBDIR to the '$runpath_var' environment variable" - echo " during linking" - fi - if test -n "$hardcode_libdir_flag_spec"; then - libdir=LIBDIR - eval flag=\"$hardcode_libdir_flag_spec\" - - $ECHO " - use the '$flag' linker flag" - fi - if test -n "$admincmds"; then - $ECHO " - have your system administrator run these commands:$admincmds" - fi - if test -f /etc/ld.so.conf; then - echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" - fi - echo - - echo "See any operating system documentation about shared libraries for" - case $host in - solaris2.[6789]|solaris2.1[0-9]) - echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" - echo "pages." - ;; - *) - echo "more information, such as the ld(1) and ld.so(8) manual pages." - ;; - esac - echo "----------------------------------------------------------------------" - fi - exit $EXIT_SUCCESS -} - -test finish = "$opt_mode" && func_mode_finish ${1+"$@"} - - -# func_mode_install arg... -func_mode_install () -{ - $debug_cmd - - # There may be an optional sh(1) argument at the beginning of - # install_prog (especially on Windows NT). - if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || - # Allow the use of GNU shtool's install command. - case $nonopt in *shtool*) :;; *) false;; esac - then - # Aesthetically quote it. - func_quote_arg pretty "$nonopt" - install_prog="$func_quote_arg_result " - arg=$1 - shift - else - install_prog= - arg=$nonopt - fi - - # The real first argument should be the name of the installation program. - # Aesthetically quote it. - func_quote_arg pretty "$arg" - func_append install_prog "$func_quote_arg_result" - install_shared_prog=$install_prog - case " $install_prog " in - *[\\\ /]cp\ *) install_cp=: ;; - *) install_cp=false ;; - esac - - # We need to accept at least all the BSD install flags. - dest= - files= - opts= - prev= - install_type= - isdir=false - stripme= - no_mode=: - for arg - do - arg2= - if test -n "$dest"; then - func_append files " $dest" - dest=$arg - continue - fi - - case $arg in - -d) isdir=: ;; - -f) - if $install_cp; then :; else - prev=$arg - fi - ;; - -g | -m | -o) - prev=$arg - ;; - -s) - stripme=" -s" - continue - ;; - -*) - ;; - *) - # If the previous option needed an argument, then skip it. - if test -n "$prev"; then - if test X-m = "X$prev" && test -n "$install_override_mode"; then - arg2=$install_override_mode - no_mode=false - fi - prev= - else - dest=$arg - continue - fi - ;; - esac - - # Aesthetically quote the argument. - func_quote_arg pretty "$arg" - func_append install_prog " $func_quote_arg_result" - if test -n "$arg2"; then - func_quote_arg pretty "$arg2" - fi - func_append install_shared_prog " $func_quote_arg_result" - done - - test -z "$install_prog" && \ - func_fatal_help "you must specify an install program" - - test -n "$prev" && \ - func_fatal_help "the '$prev' option requires an argument" - - if test -n "$install_override_mode" && $no_mode; then - if $install_cp; then :; else - func_quote_arg pretty "$install_override_mode" - func_append install_shared_prog " -m $func_quote_arg_result" - fi - fi - - if test -z "$files"; then - if test -z "$dest"; then - func_fatal_help "no file or destination specified" - else - func_fatal_help "you must specify a destination" - fi - fi - - # Strip any trailing slash from the destination. - func_stripname '' '/' "$dest" - dest=$func_stripname_result - - # Check to see that the destination is a directory. - test -d "$dest" && isdir=: - if $isdir; then - destdir=$dest - destname= - else - func_dirname_and_basename "$dest" "" "." - destdir=$func_dirname_result - destname=$func_basename_result - - # Not a directory, so check to see that there is only one file specified. - set dummy $files; shift - test "$#" -gt 1 && \ - func_fatal_help "'$dest' is not a directory" - fi - case $destdir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - for file in $files; do - case $file in - *.lo) ;; - *) - func_fatal_help "'$destdir' must be an absolute directory name" - ;; - esac - done - ;; - esac - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic=$magic - - staticlibs= - future_libdirs= - current_libdirs= - for file in $files; do - - # Do each installation. - case $file in - *.$libext) - # Do the static libraries later. - func_append staticlibs " $file" - ;; - - *.la) - func_resolve_sysroot "$file" - file=$func_resolve_sysroot_result - - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$file" \ - || func_fatal_help "'$file' is not a valid libtool archive" - - library_names= - old_library= - relink_command= - func_source "$file" - - # Add the libdir to current_libdirs if it is the destination. - if test "X$destdir" = "X$libdir"; then - case "$current_libdirs " in - *" $libdir "*) ;; - *) func_append current_libdirs " $libdir" ;; - esac - else - # Note the libdir as a future libdir. - case "$future_libdirs " in - *" $libdir "*) ;; - *) func_append future_libdirs " $libdir" ;; - esac - fi - - func_dirname "$file" "/" "" - dir=$func_dirname_result - func_append dir "$objdir" - - if test -n "$relink_command"; then - # Strip any trailing slash from the destination. - func_stripname '' '/' "$libdir" - destlibdir=$func_stripname_result - - func_stripname '' '/' "$destdir" - s_destdir=$func_stripname_result - - # Determine the prefix the user has applied to our future dir. - inst_prefix_dir=`$ECHO "X$s_destdir" | $Xsed -e "s%$destlibdir\$%%"` - - # Don't allow the user to place us outside of our expected - # location b/c this prevents finding dependent libraries that - # are installed to the same prefix. - # At present, this check doesn't affect windows .dll's that - # are installed into $libdir/../bin (currently, that works fine) - # but it's something to keep an eye on. - test "$inst_prefix_dir" = "$destdir" && \ - func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" - - if test -n "$inst_prefix_dir"; then - # Stick the inst_prefix_dir data into the link command. - relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` - else - relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` - fi - - func_warning "relinking '$file'" - func_show_eval "$relink_command" \ - 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' - fi - - # See the names of the shared library. - set dummy $library_names; shift - if test -n "$1"; then - realname=$1 - shift - - srcname=$realname - test -n "$relink_command" && srcname=${realname}T - - # Install the shared library and build the symlinks. - func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ - 'exit $?' - tstripme=$stripme - case $host_os in - cygwin* | mingw* | windows* | pw32* | cegcc*) - case $realname in - *.dll.a) - tstripme= - ;; - esac - ;; - os2*) - case $realname in - *_dll.a) - tstripme= - ;; - esac - ;; - esac - if test -n "$tstripme" && test -n "$striplib"; then - func_show_eval "$striplib $destdir/$realname" 'exit $?' - fi - - if test "$#" -gt 0; then - # Delete the old symlinks, and create new ones. - # Try 'ln -sf' first, because the 'ln' binary might depend on - # the symlink we replace! Solaris /bin/ln does not understand -f, - # so we also need to try rm && ln -s. - for linkname - do - test "$linkname" != "$realname" \ - && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" - done - fi - - # Do each command in the postinstall commands. - lib=$destdir/$realname - func_execute_cmds "$postinstall_cmds" 'exit $?' - fi - - # Install the pseudo-library for information purposes. - func_basename "$file" - name=$func_basename_result - instname=$dir/${name}i - func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' - - # Maybe install the static library, too. - test -n "$old_library" && func_append staticlibs " $dir/$old_library" - ;; - - *.lo) - # Install (i.e. copy) a libtool object. - - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile=$destdir/$destname - else - func_basename "$file" - destfile=$func_basename_result - destfile=$destdir/$destfile - fi - - # Deduce the name of the destination old-style object file. - case $destfile in - *.lo) - func_lo2o "$destfile" - staticdest=$func_lo2o_result - ;; - *.$objext) - staticdest=$destfile - destfile= - ;; - *) - func_fatal_help "cannot copy a libtool object to '$destfile'" - ;; - esac - - # Install the libtool object if requested. - test -n "$destfile" && \ - func_show_eval "$install_prog $file $destfile" 'exit $?' - - # Install the old object if enabled. - if test yes = "$build_old_libs"; then - # Deduce the name of the old-style object file. - func_lo2o "$file" - staticobj=$func_lo2o_result - func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' - fi - exit $EXIT_SUCCESS - ;; - - *) - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile=$destdir/$destname - else - func_basename "$file" - destfile=$func_basename_result - destfile=$destdir/$destfile - fi - - # If the file is missing, and there is a .exe on the end, strip it - # because it is most likely a libtool script we actually want to - # install - stripped_ext= - case $file in - *.exe) - if test ! -f "$file"; then - func_stripname '' '.exe' "$file" - file=$func_stripname_result - stripped_ext=.exe - fi - ;; - esac - - # Do a test to see if this is really a libtool program. - case $host in - *cygwin* | *mingw* | *windows*) - if func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - wrapper=$func_ltwrapper_scriptname_result - else - func_stripname '' '.exe' "$file" - wrapper=$func_stripname_result - fi - ;; - *) - wrapper=$file - ;; - esac - if func_ltwrapper_script_p "$wrapper"; then - notinst_deplibs= - relink_command= - - func_source "$wrapper" - - # Check the variables that should have been set. - test -z "$generated_by_libtool_version" && \ - func_fatal_error "invalid libtool wrapper script '$wrapper'" - - finalize=: - for lib in $notinst_deplibs; do - # Check to see that each library is installed. - libdir= - if test -f "$lib"; then - func_source "$lib" - fi - libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` - if test -n "$libdir" && test ! -f "$libfile"; then - func_warning "'$lib' has not been installed in '$libdir'" - finalize=false - fi - done - - relink_command= - func_source "$wrapper" - - outputname= - if test no = "$fast_install" && test -n "$relink_command"; then - $opt_dry_run || { - if $finalize; then - tmpdir=`func_mktempdir` - func_basename "$file$stripped_ext" - file=$func_basename_result - outputname=$tmpdir/$file - # Replace the output file specification. - relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` - - $opt_quiet || { - func_quote_arg expand,pretty "$relink_command" - eval "func_echo $func_quote_arg_result" - } - if eval "$relink_command"; then : - else - func_error "error: relink '$file' with the above command before installing it" - $opt_dry_run || ${RM}r "$tmpdir" - continue - fi - file=$outputname - else - func_warning "cannot relink '$file'" - fi - } - else - # Install the binary that we compiled earlier. - file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` - fi - fi - - # remove .exe since cygwin /usr/bin/install will append another - # one anyway - case $install_prog,$host in - */usr/bin/install*,*cygwin*) - case $file:$destfile in - *.exe:*.exe) - # this is ok - ;; - *.exe:*) - destfile=$destfile.exe - ;; - *:*.exe) - func_stripname '' '.exe' "$destfile" - destfile=$func_stripname_result - ;; - esac - ;; - esac - func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' - $opt_dry_run || if test -n "$outputname"; then - ${RM}r "$tmpdir" - fi - ;; - esac - done - - for file in $staticlibs; do - func_basename "$file" - name=$func_basename_result - - # Set up the ranlib parameters. - oldlib=$destdir/$name - func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 - tool_oldlib=$func_to_tool_file_result - - func_show_eval "$install_prog \$file \$oldlib" 'exit $?' - - if test -n "$stripme" && test -n "$old_striplib"; then - func_show_eval "$old_striplib $tool_oldlib" 'exit $?' - fi - - # Do each command in the postinstall commands. - func_execute_cmds "$old_postinstall_cmds" 'exit $?' - done - - test -n "$future_libdirs" && \ - func_warning "remember to run '$progname --finish$future_libdirs'" - - if test -n "$current_libdirs"; then - # Maybe just do a dry run. - $opt_dry_run && current_libdirs=" -n$current_libdirs" - exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' - else - exit $EXIT_SUCCESS - fi -} - -test install = "$opt_mode" && func_mode_install ${1+"$@"} - - -# func_generate_dlsyms outputname originator pic_p -# Extract symbols from dlprefiles and create ${outputname}S.o with -# a dlpreopen symbol table. -func_generate_dlsyms () -{ - $debug_cmd - - my_outputname=$1 - my_originator=$2 - my_pic_p=${3-false} - my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` - my_dlsyms= - - if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then - if test -n "$NM" && test -n "$global_symbol_pipe"; then - my_dlsyms=${my_outputname}S.c - else - func_error "not configured to extract global symbols from dlpreopened files" - fi - fi - - if test -n "$my_dlsyms"; then - case $my_dlsyms in - "") ;; - *.c) - # Discover the nlist of each of the dlfiles. - nlist=$output_objdir/$my_outputname.nm - - func_show_eval "$RM $nlist ${nlist}S ${nlist}T" - - # Parse the name list into a source file. - func_verbose "creating $output_objdir/$my_dlsyms" - - $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ -/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ -/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ - -#ifdef __cplusplus -extern \"C\" { -#endif - -#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) -#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" -#endif - -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE -/* DATA imports from DLLs on WIN32 can't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT_DLSYM_CONST -#elif defined __osf__ -/* This system does not cope well with relocations in const data. */ -# define LT_DLSYM_CONST -#else -# define LT_DLSYM_CONST const -#endif - -#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) - -/* External symbol declarations for the compiler. */\ -" - - if test yes = "$dlself"; then - func_verbose "generating symbol list for '$output'" - - $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" - - # Add our own program objects to the symbol list. - progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` - for progfile in $progfiles; do - func_to_tool_file "$progfile" func_convert_file_msys_to_w32 - func_verbose "extracting global C symbols from '$func_to_tool_file_result'" - $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" - done - - if test -n "$exclude_expsyms"; then - $opt_dry_run || { - eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' - eval '$MV "$nlist"T "$nlist"' - } - fi - - if test -n "$export_symbols_regex"; then - $opt_dry_run || { - eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' - eval '$MV "$nlist"T "$nlist"' - } - fi - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - export_symbols=$output_objdir/$outputname.exp - $opt_dry_run || { - $RM $export_symbols - eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' - case $host in - *cygwin* | *mingw* | *windows* | *cegcc* ) - eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' - ;; - esac - } - else - $opt_dry_run || { - eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' - eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' - eval '$MV "$nlist"T "$nlist"' - case $host in - *cygwin* | *mingw* | *windows* | *cegcc* ) - eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' - ;; - esac - } - fi - fi - - for dlprefile in $dlprefiles; do - func_verbose "extracting global C symbols from '$dlprefile'" - func_basename "$dlprefile" - name=$func_basename_result - case $host in - *cygwin* | *mingw* | *windows* | *cegcc* ) - # if an import library, we need to obtain dlname - if func_win32_import_lib_p "$dlprefile"; then - func_tr_sh "$dlprefile" - eval "curr_lafile=\$libfile_$func_tr_sh_result" - dlprefile_dlbasename= - if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then - # Use subshell, to avoid clobbering current variable values - dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` - if test -n "$dlprefile_dlname"; then - func_basename "$dlprefile_dlname" - dlprefile_dlbasename=$func_basename_result - else - # no lafile. user explicitly requested -dlpreopen . - $sharedlib_from_linklib_cmd "$dlprefile" - dlprefile_dlbasename=$sharedlib_from_linklib_result - fi - fi - $opt_dry_run || { - if test -n "$dlprefile_dlbasename"; then - eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' - else - func_warning "Could not compute DLL name from $name" - eval '$ECHO ": $name " >> "$nlist"' - fi - func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - case $host in - i[3456]86-*-mingw32*) - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | - $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" - ;; - *) - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | - $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/__nm_//' >> '$nlist'" - ;; - esac - } - else # not an import lib - $opt_dry_run || { - eval '$ECHO ": $name " >> "$nlist"' - func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" - } - fi - ;; - *) - $opt_dry_run || { - eval '$ECHO ": $name " >> "$nlist"' - func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" - } - ;; - esac - done - - $opt_dry_run || { - # Make sure we have at least an empty file. - test -f "$nlist" || : > "$nlist" - - if test -n "$exclude_expsyms"; then - $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T - $MV "$nlist"T "$nlist" - fi - - # Try sorting and uniquifying the output. - if $GREP -v "^: " < "$nlist" | - if sort -k 3 /dev/null 2>&1; then - sort -k 3 - else - sort +2 - fi | - uniq > "$nlist"S; then - : - else - $GREP -v "^: " < "$nlist" > "$nlist"S - fi - - if test -f "$nlist"S; then - eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' - else - echo '/* NONE */' >> "$output_objdir/$my_dlsyms" - fi - - func_show_eval '$RM "${nlist}I"' - if test -n "$global_symbol_to_import"; then - eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' - fi - - echo >> "$output_objdir/$my_dlsyms" "\ - -/* The mapping between symbol names and symbols. */ -typedef struct { - const char *name; - void *address; -} lt_dlsymlist; -extern LT_DLSYM_CONST lt_dlsymlist -lt_${my_prefix}_LTX_preloaded_symbols[];\ -" - - if test -s "$nlist"I; then - echo >> "$output_objdir/$my_dlsyms" "\ -static void lt_syminit(void) -{ - LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; - for (; symbol->name; ++symbol) - {" - $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" - echo >> "$output_objdir/$my_dlsyms" "\ - } -}" - fi - echo >> "$output_objdir/$my_dlsyms" "\ -LT_DLSYM_CONST lt_dlsymlist -lt_${my_prefix}_LTX_preloaded_symbols[] = -{ {\"$my_originator\", (void *) 0}," - - if test -s "$nlist"I; then - echo >> "$output_objdir/$my_dlsyms" "\ - {\"@INIT@\", (void *) <_syminit}," - fi - - case $need_lib_prefix in - no) - eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" - ;; - *) - eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" - ;; - esac - echo >> "$output_objdir/$my_dlsyms" "\ - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt_${my_prefix}_LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif\ -" - } # !$opt_dry_run - - pic_flag_for_symtable= - case "$compile_command " in - *" -static "*) ;; - *) - case $host in - # compiling the symbol table file with pic_flag works around - # a FreeBSD bug that causes programs to crash when -lm is - # linked before any other PIC object. But we must not use - # pic_flag when linking with -static. The problem exists in - # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. - *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) - pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; - *-*-hpux*) - pic_flag_for_symtable=" $pic_flag" ;; - *) - $my_pic_p && pic_flag_for_symtable=" $pic_flag" - ;; - esac - ;; - esac - symtab_cflags= - for arg in $LTCFLAGS; do - case $arg in - -pie | -fpie | -fPIE) ;; - *) func_append symtab_cflags " $arg" ;; - esac - done - - # Now compile the dynamic symbol file. - func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' - - # Clean up the generated files. - func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' - - # Transform the symbol file into the correct name. - symfileobj=$output_objdir/${my_outputname}S.$objext - case $host in - *cygwin* | *mingw* | *windows* | *cegcc* ) - if test -f "$output_objdir/$my_outputname.def"; then - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` - else - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` - fi - ;; - *) - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` - ;; - esac - ;; - *) - func_fatal_error "unknown suffix for '$my_dlsyms'" - ;; - esac - else - # We keep going just in case the user didn't refer to - # lt_preloaded_symbols. The linker will fail if global_symbol_pipe - # really was required. - - # Nullify the symbol file. - compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` - fi -} - -# func_cygming_gnu_implib_p ARG -# This predicate returns with zero status (TRUE) if -# ARG is a GNU/binutils-style import library. Returns -# with nonzero status (FALSE) otherwise. -func_cygming_gnu_implib_p () -{ - $debug_cmd - - func_to_tool_file "$1" func_convert_file_msys_to_w32 - func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` - test -n "$func_cygming_gnu_implib_tmp" -} - -# func_cygming_ms_implib_p ARG -# This predicate returns with zero status (TRUE) if -# ARG is an MS-style import library. Returns -# with nonzero status (FALSE) otherwise. -func_cygming_ms_implib_p () -{ - $debug_cmd - - func_to_tool_file "$1" func_convert_file_msys_to_w32 - func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` - test -n "$func_cygming_ms_implib_tmp" -} - -# func_win32_libid arg -# return the library type of file 'arg' -# -# Need a lot of goo to handle *both* DLLs and import libs -# Has to be a shell function in order to 'eat' the argument -# that is supplied when $file_magic_command is called. -# Despite the name, also deal with 64 bit binaries. -func_win32_libid () -{ - $debug_cmd - - win32_libid_type=unknown - win32_fileres=`file -L $1 2>/dev/null` - case $win32_fileres in - *ar\ archive\ import\ library*) # definitely import - win32_libid_type="x86 archive import" - ;; - *ar\ archive*) # could be an import, or static - # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. - if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | - $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)' >/dev/null; then - case $nm_interface in - "MS dumpbin") - if func_cygming_ms_implib_p "$1" || - func_cygming_gnu_implib_p "$1" - then - win32_nmres=import - else - win32_nmres= - fi - ;; - *) - func_to_tool_file "$1" func_convert_file_msys_to_w32 - win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | - $SED -n -e ' - 1,100{ - / I /{ - s|.*|import| - p - q - } - }'` - ;; - esac - case $win32_nmres in - import*) win32_libid_type="x86 archive import";; - *) win32_libid_type="x86 archive static";; - esac - fi - ;; - *DLL*) - win32_libid_type="x86 DLL" - ;; - *executable*) # but shell scripts are "executable" too... - case $win32_fileres in - *MS\ Windows\ PE\ Intel*) - win32_libid_type="x86 DLL" - ;; - esac - ;; - esac - $ECHO "$win32_libid_type" -} - -# func_cygming_dll_for_implib ARG -# -# Platform-specific function to extract the -# name of the DLL associated with the specified -# import library ARG. -# Invoked by eval'ing the libtool variable -# $sharedlib_from_linklib_cmd -# Result is available in the variable -# $sharedlib_from_linklib_result -func_cygming_dll_for_implib () -{ - $debug_cmd - - sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` -} - -# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs -# -# The is the core of a fallback implementation of a -# platform-specific function to extract the name of the -# DLL associated with the specified import library LIBNAME. -# -# SECTION_NAME is either .idata$6 or .idata$7, depending -# on the platform and compiler that created the implib. -# -# Echos the name of the DLL associated with the -# specified import library. -func_cygming_dll_for_implib_fallback_core () -{ - $debug_cmd - - match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` - $OBJDUMP -s --section "$1" "$2" 2>/dev/null | - $SED '/^Contents of section '"$match_literal"':/{ - # Place marker at beginning of archive member dllname section - s/.*/====MARK====/ - p - d - } - # These lines can sometimes be longer than 43 characters, but - # are always uninteresting - /:[ ]*file format pe[i]\{,1\}-/d - /^In archive [^:]*:/d - # Ensure marker is printed - /^====MARK====/p - # Remove all lines with less than 43 characters - /^.\{43\}/!d - # From remaining lines, remove first 43 characters - s/^.\{43\}//' | - $SED -n ' - # Join marker and all lines until next marker into a single line - /^====MARK====/ b para - H - $ b para - b - :para - x - s/\n//g - # Remove the marker - s/^====MARK====// - # Remove trailing dots and whitespace - s/[\. \t]*$// - # Print - /./p' | - # we now have a list, one entry per line, of the stringified - # contents of the appropriate section of all members of the - # archive that possess that section. Heuristic: eliminate - # all those that have a first or second character that is - # a '.' (that is, objdump's representation of an unprintable - # character.) This should work for all archives with less than - # 0x302f exports -- but will fail for DLLs whose name actually - # begins with a literal '.' or a single character followed by - # a '.'. - # - # Of those that remain, print the first one. - $SED -e '/^\./d;/^.\./d;q' -} - -# func_cygming_dll_for_implib_fallback ARG -# Platform-specific function to extract the -# name of the DLL associated with the specified -# import library ARG. -# -# This fallback implementation is for use when $DLLTOOL -# does not support the --identify-strict option. -# Invoked by eval'ing the libtool variable -# $sharedlib_from_linklib_cmd -# Result is available in the variable -# $sharedlib_from_linklib_result -func_cygming_dll_for_implib_fallback () -{ - $debug_cmd - - if func_cygming_gnu_implib_p "$1"; then - # binutils import library - sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` - elif func_cygming_ms_implib_p "$1"; then - # ms-generated import library - sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` - else - # unknown - sharedlib_from_linklib_result= - fi -} - - -# func_extract_an_archive dir oldlib -func_extract_an_archive () -{ - $debug_cmd - - f_ex_an_ar_dir=$1; shift - f_ex_an_ar_oldlib=$1 - if test yes = "$lock_old_archive_extraction"; then - lockfile=$f_ex_an_ar_oldlib.lock - until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do - func_echo "Waiting for $lockfile to be removed" - sleep 2 - done - fi - func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ - 'stat=$?; rm -f "$lockfile"; exit $stat' - if test yes = "$lock_old_archive_extraction"; then - $opt_dry_run || rm -f "$lockfile" - fi - if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then - : - else - func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" - fi -} - - -# func_extract_archives gentop oldlib ... -func_extract_archives () -{ - $debug_cmd - - my_gentop=$1; shift - my_oldlibs=${1+"$@"} - my_oldobjs= - my_xlib= - my_xabs= - my_xdir= - - for my_xlib in $my_oldlibs; do - # Extract the objects. - case $my_xlib in - [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; - *) my_xabs=`pwd`"/$my_xlib" ;; - esac - func_basename "$my_xlib" - my_xlib=$func_basename_result - my_xlib_u=$my_xlib - while :; do - case " $extracted_archives " in - *" $my_xlib_u "*) - func_arith $extracted_serial + 1 - extracted_serial=$func_arith_result - my_xlib_u=lt$extracted_serial-$my_xlib ;; - *) break ;; - esac - done - extracted_archives="$extracted_archives $my_xlib_u" - my_xdir=$my_gentop/$my_xlib_u - - func_mkdir_p "$my_xdir" - - case $host in - *-darwin*) - func_verbose "Extracting $my_xabs" - # Do not bother doing anything if just a dry run - $opt_dry_run || { - darwin_orig_dir=`pwd` - cd $my_xdir || exit $? - darwin_archive=$my_xabs - darwin_curdir=`pwd` - func_basename "$darwin_archive" - darwin_base_archive=$func_basename_result - darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` - if test -n "$darwin_arches"; then - darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` - darwin_arch= - func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" - for darwin_arch in $darwin_arches; do - func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" - $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" - cd "unfat-$$/$darwin_base_archive-$darwin_arch" - func_extract_an_archive "`pwd`" "$darwin_base_archive" - cd "$darwin_curdir" - $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" - done # $darwin_arches - ## Okay now we've a bunch of thin objects, gotta fatten them up :) - darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` - darwin_file= - darwin_files= - for darwin_file in $darwin_filelist; do - darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` - $LIPO -create -output "$darwin_file" $darwin_files - done # $darwin_filelist - $RM -rf unfat-$$ - cd "$darwin_orig_dir" - else - cd $darwin_orig_dir - func_extract_an_archive "$my_xdir" "$my_xabs" - fi # $darwin_arches - } # !$opt_dry_run - ;; - *) - func_extract_an_archive "$my_xdir" "$my_xabs" - ;; - esac - my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` - done - - func_extract_archives_result=$my_oldobjs -} - - -# func_emit_wrapper [arg=no] -# -# Emit a libtool wrapper script on stdout. -# Don't directly open a file because we may want to -# incorporate the script contents within a cygwin/mingw/windows -# wrapper executable. Must ONLY be called from within -# func_mode_link because it depends on a number of variables -# set therein. -# -# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR -# variable will take. If 'yes', then the emitted script -# will assume that the directory where it is stored is -# the $objdir directory. This is a cygwin/mingw/windows-specific -# behavior. -func_emit_wrapper () -{ - func_emit_wrapper_arg1=${1-no} - - $ECHO "\ -#! $SHELL - -# $output - temporary wrapper script for $objdir/$outputname -# Generated by $PROGRAM (GNU $PACKAGE) $VERSION -# -# The $output program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -sed_quote_subst='$sed_quote_subst' - -# Be Bourne compatible -if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -relink_command=\"$relink_command\" - -# This environment variable determines our operation mode. -if test \"\$libtool_install_magic\" = \"$magic\"; then - # install mode needs the following variables: - generated_by_libtool_version='$macro_version' - notinst_deplibs='$notinst_deplibs' -else - # When we are sourced in execute mode, \$file and \$ECHO are already set. - if test \"\$libtool_execute_magic\" != \"$magic\"; then - file=\"\$0\"" - - func_quote_arg pretty "$ECHO" - qECHO=$func_quote_arg_result - $ECHO "\ - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - ECHO=$qECHO - fi - -# Very basic option parsing. These options are (a) specific to -# the libtool wrapper, (b) are identical between the wrapper -# /script/ and the wrapper /executable/ that is used only on -# windows platforms, and (c) all begin with the string "--lt-" -# (application programs are unlikely to have options that match -# this pattern). -# -# There are only two supported options: --lt-debug and -# --lt-dump-script. There is, deliberately, no --lt-help. -# -# The first argument to this parsing function should be the -# script's $0 value, followed by "$@". -lt_option_debug= -func_parse_lt_options () -{ - lt_script_arg0=\$0 - shift - for lt_opt - do - case \"\$lt_opt\" in - --lt-debug) lt_option_debug=1 ;; - --lt-dump-script) - lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` - test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. - lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` - cat \"\$lt_dump_D/\$lt_dump_F\" - exit 0 - ;; - --lt-*) - \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 - exit 1 - ;; - esac - done - - # Print the debug banner immediately: - if test -n \"\$lt_option_debug\"; then - echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 - fi -} - -# Used when --lt-debug. Prints its arguments to stdout -# (redirection is the responsibility of the caller) -func_lt_dump_args () -{ - lt_dump_args_N=1; - for lt_arg - do - \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" - lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` - done -} - -# Core function for launching the target application -func_exec_program_core () -{ -" - case $host in - # Backslashes separate directories on plain windows - *-*-mingw* | *-*-windows* | *-*-os2* | *-cegcc*) - $ECHO "\ - if test -n \"\$lt_option_debug\"; then - \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 - func_lt_dump_args \${1+\"\$@\"} 1>&2 - fi - exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} -" - ;; - - *) - $ECHO "\ - if test -n \"\$lt_option_debug\"; then - \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 - func_lt_dump_args \${1+\"\$@\"} 1>&2 - fi - exec \"\$progdir/\$program\" \${1+\"\$@\"} -" - ;; - esac - $ECHO "\ - \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 - exit 1 -} - -# A function to encapsulate launching the target application -# Strips options in the --lt-* namespace from \$@ and -# launches target application with the remaining arguments. -func_exec_program () -{ - case \" \$* \" in - *\\ --lt-*) - for lt_wr_arg - do - case \$lt_wr_arg in - --lt-*) ;; - *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; - esac - shift - done ;; - esac - func_exec_program_core \${1+\"\$@\"} -} - - # Parse options - func_parse_lt_options \"\$0\" \${1+\"\$@\"} - - # Find the directory that this script lives in. - thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` - test \"x\$thisdir\" = \"x\$file\" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` - while test -n \"\$file\"; do - destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` - - # If there was a directory component, then change thisdir. - if test \"x\$destdir\" != \"x\$file\"; then - case \"\$destdir\" in - [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; - *) thisdir=\"\$thisdir/\$destdir\" ;; - esac - fi - - file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` - file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` - done - - # Usually 'no', except on cygwin/mingw/windows when embedded into - # the cwrapper. - WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 - if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then - # special case for '.' - if test \"\$thisdir\" = \".\"; then - thisdir=\`pwd\` - fi - # remove .libs from thisdir - case \"\$thisdir\" in - *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; - $objdir ) thisdir=. ;; - esac - fi - - # Try to get the absolute directory name. - absdir=\`cd \"\$thisdir\" && pwd\` - test -n \"\$absdir\" && thisdir=\"\$absdir\" -" - - if test yes = "$fast_install"; then - $ECHO "\ - program=lt-'$outputname'$exeext - progdir=\"\$thisdir/$objdir\" - - if test ! -f \"\$progdir/\$program\" || - { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ - test \"X\$file\" != \"X\$progdir/\$program\"; }; then - - file=\"\$\$-\$program\" - - if test ! -d \"\$progdir\"; then - $MKDIR \"\$progdir\" - else - $RM \"\$progdir/\$file\" - fi" - - $ECHO "\ - - # relink executable if necessary - if test -n \"\$relink_command\"; then - if relink_command_output=\`eval \$relink_command 2>&1\`; then : - else - \$ECHO \"\$relink_command_output\" >&2 - $RM \"\$progdir/\$file\" - exit 1 - fi - fi - - $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || - { $RM \"\$progdir/\$program\"; - $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } - $RM \"\$progdir/\$file\" - fi" - else - $ECHO "\ - program='$outputname' - progdir=\"\$thisdir/$objdir\" -" - fi - - $ECHO "\ - - if test -f \"\$progdir/\$program\"; then" - - # fixup the dll searchpath if we need to. - # - # Fix the DLL searchpath if we need to. Do this before prepending - # to shlibpath, because on Windows, both are PATH and uninstalled - # libraries must come first. - if test -n "$dllsearchpath"; then - $ECHO "\ - # Add the dll search path components to the executable PATH - PATH=$dllsearchpath:\$PATH -" - fi - - # Export our shlibpath_var if we have one. - if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then - $ECHO "\ - # Add our own library path to $shlibpath_var - $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" - - # Some systems cannot cope with colon-terminated $shlibpath_var - # The second colon is a workaround for a bug in BeOS R4 sed - $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` - - export $shlibpath_var -" - fi - - $ECHO "\ - if test \"\$libtool_execute_magic\" != \"$magic\"; then - # Run the actual program with our arguments. - func_exec_program \${1+\"\$@\"} - fi - else - # The program doesn't exist. - \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 - \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 - \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 - exit 1 - fi -fi\ -" -} - - -# func_emit_cwrapperexe_src -# emit the source code for a wrapper executable on stdout -# Must ONLY be called from within func_mode_link because -# it depends on a number of variable set therein. -func_emit_cwrapperexe_src () -{ - cat < -#include -#if defined _WIN32 && !defined __GNUC__ -# include -# include -# include -#else -# include -# include -# ifdef __CYGWIN__ -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) - -/* declarations of non-ANSI functions */ -#if defined __MINGW32__ -# ifdef __STRICT_ANSI__ -_CRTIMP int __cdecl _putenv (const char *); -# endif -#elif defined __CYGWIN__ -# ifdef __STRICT_ANSI__ -char *realpath (const char *, char *); -int putenv (char *); -int setenv (const char *, const char *, int); -# endif -/* #elif defined other_platform || defined ... */ -#endif - -/* portability defines, excluding path handling macros */ -#if defined _MSC_VER -# define setmode _setmode -# define stat _stat -# define chmod _chmod -# define getcwd _getcwd -# define putenv _putenv -# define S_IXUSR _S_IEXEC -#elif defined __MINGW32__ -# define setmode _setmode -# define stat _stat -# define chmod _chmod -# define getcwd _getcwd -# define putenv _putenv -#elif defined __CYGWIN__ -# define HAVE_SETENV -# define FOPEN_WB "wb" -/* #elif defined other platforms ... */ -#endif - -#if defined PATH_MAX -# define LT_PATHMAX PATH_MAX -#elif defined MAXPATHLEN -# define LT_PATHMAX MAXPATHLEN -#else -# define LT_PATHMAX 1024 -#endif - -#ifndef S_IXOTH -# define S_IXOTH 0 -#endif -#ifndef S_IXGRP -# define S_IXGRP 0 -#endif - -/* path handling portability macros */ -#ifndef DIR_SEPARATOR -# define DIR_SEPARATOR '/' -# define PATH_SEPARATOR ':' -#endif - -#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ - defined __OS2__ -# define HAVE_DOS_BASED_FILE_SYSTEM -# define FOPEN_WB "wb" -# ifndef DIR_SEPARATOR_2 -# define DIR_SEPARATOR_2 '\\' -# endif -# ifndef PATH_SEPARATOR_2 -# define PATH_SEPARATOR_2 ';' -# endif -#endif - -#ifndef DIR_SEPARATOR_2 -# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) -#else /* DIR_SEPARATOR_2 */ -# define IS_DIR_SEPARATOR(ch) \ - (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) -#endif /* DIR_SEPARATOR_2 */ - -#ifndef PATH_SEPARATOR_2 -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) -#else /* PATH_SEPARATOR_2 */ -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) -#endif /* PATH_SEPARATOR_2 */ - -#ifndef FOPEN_WB -# define FOPEN_WB "w" -#endif -#ifndef _O_BINARY -# define _O_BINARY 0 -#endif - -#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) -#define XFREE(stale) do { \ - if (stale) { free (stale); stale = 0; } \ -} while (0) - -#if defined LT_DEBUGWRAPPER -static int lt_debug = 1; -#else -static int lt_debug = 0; -#endif - -const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ - -void *xmalloc (size_t num); -char *xstrdup (const char *string); -const char *base_name (const char *name); -char *find_executable (const char *wrapper); -char *chase_symlinks (const char *pathspec); -int make_executable (const char *path); -int check_executable (const char *path); -char *strendzap (char *str, const char *pat); -void lt_debugprintf (const char *file, int line, const char *fmt, ...); -void lt_fatal (const char *file, int line, const char *message, ...); -static const char *nonnull (const char *s); -static const char *nonempty (const char *s); -void lt_setenv (const char *name, const char *value); -char *lt_extend_str (const char *orig_value, const char *add, int to_end); -void lt_update_exe_path (const char *name, const char *value); -void lt_update_lib_path (const char *name, const char *value); -char **prepare_spawn (char **argv); -void lt_dump_script (FILE *f); -EOF - - cat <= 0) - && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) - return 1; - else - return 0; -} - -int -make_executable (const char *path) -{ - int rval = 0; - struct stat st; - - lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", - nonempty (path)); - if ((!path) || (!*path)) - return 0; - - if (stat (path, &st) >= 0) - { - rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); - } - return rval; -} - -/* Searches for the full path of the wrapper. Returns - newly allocated full path name if found, NULL otherwise - Does not chase symlinks, even on platforms that support them. -*/ -char * -find_executable (const char *wrapper) -{ - int has_slash = 0; - const char *p; - const char *p_next; - /* static buffer for getcwd */ - char tmp[LT_PATHMAX + 1]; - size_t tmp_len; - char *concat_name; - - lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", - nonempty (wrapper)); - - if ((wrapper == NULL) || (*wrapper == '\0')) - return NULL; - - /* Absolute path? */ -#if defined HAVE_DOS_BASED_FILE_SYSTEM - if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') - { - concat_name = xstrdup (wrapper); - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } - else - { -#endif - if (IS_DIR_SEPARATOR (wrapper[0])) - { - concat_name = xstrdup (wrapper); - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } -#if defined HAVE_DOS_BASED_FILE_SYSTEM - } -#endif - - for (p = wrapper; *p; p++) - if (*p == '/') - { - has_slash = 1; - break; - } - if (!has_slash) - { - /* no slashes; search PATH */ - const char *path = getenv ("PATH"); - if (path != NULL) - { - for (p = path; *p; p = p_next) - { - const char *q; - size_t p_len; - for (q = p; *q; q++) - if (IS_PATH_SEPARATOR (*q)) - break; - p_len = (size_t) (q - p); - p_next = (*q == '\0' ? q : q + 1); - if (p_len == 0) - { - /* empty path: current directory */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", - nonnull (strerror (errno))); - tmp_len = strlen (tmp); - concat_name = - XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - } - else - { - concat_name = - XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, p, p_len); - concat_name[p_len] = '/'; - strcpy (concat_name + p_len + 1, wrapper); - } - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } - } - /* not found in PATH; assume curdir */ - } - /* Relative path | not found in path: prepend cwd */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", - nonnull (strerror (errno))); - tmp_len = strlen (tmp); - concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - return NULL; -} - -char * -chase_symlinks (const char *pathspec) -{ -#ifndef S_ISLNK - return xstrdup (pathspec); -#else - char buf[LT_PATHMAX]; - struct stat s; - char *tmp_pathspec = xstrdup (pathspec); - char *p; - int has_symlinks = 0; - while (strlen (tmp_pathspec) && !has_symlinks) - { - lt_debugprintf (__FILE__, __LINE__, - "checking path component for symlinks: %s\n", - tmp_pathspec); - if (lstat (tmp_pathspec, &s) == 0) - { - if (S_ISLNK (s.st_mode) != 0) - { - has_symlinks = 1; - break; - } - - /* search backwards for last DIR_SEPARATOR */ - p = tmp_pathspec + strlen (tmp_pathspec) - 1; - while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) - p--; - if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) - { - /* no more DIR_SEPARATORS left */ - break; - } - *p = '\0'; - } - else - { - lt_fatal (__FILE__, __LINE__, - "error accessing file \"%s\": %s", - tmp_pathspec, nonnull (strerror (errno))); - } - } - XFREE (tmp_pathspec); - - if (!has_symlinks) - { - return xstrdup (pathspec); - } - - tmp_pathspec = realpath (pathspec, buf); - if (tmp_pathspec == 0) - { - lt_fatal (__FILE__, __LINE__, - "could not follow symlinks for %s", pathspec); - } - return xstrdup (tmp_pathspec); -#endif -} - -char * -strendzap (char *str, const char *pat) -{ - size_t len, patlen; - - assert (str != NULL); - assert (pat != NULL); - - len = strlen (str); - patlen = strlen (pat); - - if (patlen <= len) - { - str += len - patlen; - if (STREQ (str, pat)) - *str = '\0'; - } - return str; -} - -void -lt_debugprintf (const char *file, int line, const char *fmt, ...) -{ - va_list args; - if (lt_debug) - { - (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); - va_start (args, fmt); - (void) vfprintf (stderr, fmt, args); - va_end (args); - } -} - -static void -lt_error_core (int exit_status, const char *file, - int line, const char *mode, - const char *message, va_list ap) -{ - fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); - vfprintf (stderr, message, ap); - fprintf (stderr, ".\n"); - - if (exit_status >= 0) - exit (exit_status); -} - -void -lt_fatal (const char *file, int line, const char *message, ...) -{ - va_list ap; - va_start (ap, message); - lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); - va_end (ap); -} - -static const char * -nonnull (const char *s) -{ - return s ? s : "(null)"; -} - -static const char * -nonempty (const char *s) -{ - return (s && !*s) ? "(empty)" : nonnull (s); -} - -void -lt_setenv (const char *name, const char *value) -{ - lt_debugprintf (__FILE__, __LINE__, - "(lt_setenv) setting '%s' to '%s'\n", - nonnull (name), nonnull (value)); - { -#ifdef HAVE_SETENV - /* always make a copy, for consistency with !HAVE_SETENV */ - char *str = xstrdup (value); - setenv (name, str, 1); -#else - size_t len = strlen (name) + 1 + strlen (value) + 1; - char *str = XMALLOC (char, len); - sprintf (str, "%s=%s", name, value); - if (putenv (str) != EXIT_SUCCESS) - { - XFREE (str); - } -#endif - } -} - -char * -lt_extend_str (const char *orig_value, const char *add, int to_end) -{ - char *new_value; - if (orig_value && *orig_value) - { - size_t orig_value_len = strlen (orig_value); - size_t add_len = strlen (add); - new_value = XMALLOC (char, add_len + orig_value_len + 1); - if (to_end) - { - strcpy (new_value, orig_value); - strcpy (new_value + orig_value_len, add); - } - else - { - strcpy (new_value, add); - strcpy (new_value + add_len, orig_value); - } - } - else - { - new_value = xstrdup (add); - } - return new_value; -} - -void -lt_update_exe_path (const char *name, const char *value) -{ - lt_debugprintf (__FILE__, __LINE__, - "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", - nonnull (name), nonnull (value)); - - if (name && *name && value && *value) - { - char *new_value = lt_extend_str (getenv (name), value, 0); - /* some systems can't cope with a ':'-terminated path #' */ - size_t len = strlen (new_value); - while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) - { - new_value[--len] = '\0'; - } - lt_setenv (name, new_value); - XFREE (new_value); - } -} - -void -lt_update_lib_path (const char *name, const char *value) -{ - lt_debugprintf (__FILE__, __LINE__, - "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", - nonnull (name), nonnull (value)); - - if (name && *name && value && *value) - { - char *new_value = lt_extend_str (getenv (name), value, 0); - lt_setenv (name, new_value); - XFREE (new_value); - } -} - -EOF - case $host_os in - mingw* | windows*) - cat <<"EOF" - -/* Prepares an argument vector before calling spawn(). - Note that spawn() does not by itself call the command interpreter - (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : - ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&v); - v.dwPlatformId == VER_PLATFORM_WIN32_NT; - }) ? "cmd.exe" : "command.com"). - Instead it simply concatenates the arguments, separated by ' ', and calls - CreateProcess(). We must quote the arguments since Win32 CreateProcess() - interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a - special way: - - Space and tab are interpreted as delimiters. They are not treated as - delimiters if they are surrounded by double quotes: "...". - - Unescaped double quotes are removed from the input. Their only effect is - that within double quotes, space and tab are treated like normal - characters. - - Backslashes not followed by double quotes are not special. - - But 2*n+1 backslashes followed by a double quote become - n backslashes followed by a double quote (n >= 0): - \" -> " - \\\" -> \" - \\\\\" -> \\" - */ -#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" -#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" -char ** -prepare_spawn (char **argv) -{ - size_t argc; - char **new_argv; - size_t i; - - /* Count number of arguments. */ - for (argc = 0; argv[argc] != NULL; argc++) - ; - - /* Allocate new argument vector. */ - new_argv = XMALLOC (char *, argc + 1); - - /* Put quoted arguments into the new argument vector. */ - for (i = 0; i < argc; i++) - { - const char *string = argv[i]; - - if (string[0] == '\0') - new_argv[i] = xstrdup ("\"\""); - else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) - { - int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); - size_t length; - unsigned int backslashes; - const char *s; - char *quoted_string; - char *p; - - length = 0; - backslashes = 0; - if (quote_around) - length++; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - length += backslashes + 1; - length++; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - length += backslashes + 1; - - quoted_string = XMALLOC (char, length + 1); - - p = quoted_string; - backslashes = 0; - if (quote_around) - *p++ = '"'; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - { - unsigned int j; - for (j = backslashes + 1; j > 0; j--) - *p++ = '\\'; - } - *p++ = c; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - { - unsigned int j; - for (j = backslashes; j > 0; j--) - *p++ = '\\'; - *p++ = '"'; - } - *p = '\0'; - - new_argv[i] = quoted_string; - } - else - new_argv[i] = (char *) string; - } - new_argv[argc] = NULL; - - return new_argv; -} -EOF - ;; - esac - - cat <<"EOF" -void lt_dump_script (FILE* f) -{ -EOF - func_emit_wrapper yes | - $SED -n -e ' -s/^\(.\{79\}\)\(..*\)/\1\ -\2/ -h -s/\([\\"]\)/\\\1/g -s/$/\\n/ -s/\([^\n]*\).*/ fputs ("\1", f);/p -g -D' - cat <<"EOF" -} -EOF -} -# end: func_emit_cwrapperexe_src - -# func_win32_import_lib_p ARG -# True if ARG is an import lib, as indicated by $file_magic_cmd -func_win32_import_lib_p () -{ - $debug_cmd - - case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in - *import*) : ;; - *) false ;; - esac -} - -# func_suncc_cstd_abi -# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! -# Several compiler flags select an ABI that is incompatible with the -# Cstd library. Avoid specifying it if any are in CXXFLAGS. -func_suncc_cstd_abi () -{ - $debug_cmd - - case " $compile_command " in - *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) - suncc_use_cstd_abi=no - ;; - *) - suncc_use_cstd_abi=yes - ;; - esac -} - -# func_mode_link arg... -func_mode_link () -{ - $debug_cmd - - case $host in - *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*) - # It is impossible to link a dll without this setting, and - # we shouldn't force the makefile maintainer to figure out - # what system we are compiling for in order to pass an extra - # flag for every libtool invocation. - # allow_undefined=no - - # FIXME: Unfortunately, there are problems with the above when trying - # to make a dll that has undefined symbols, in which case not - # even a static library is built. For now, we need to specify - # -no-undefined on the libtool link line when we can be certain - # that all symbols are satisfied, otherwise we get a static library. - allow_undefined=yes - ;; - *) - allow_undefined=yes - ;; - esac - libtool_args=$nonopt - base_compile="$nonopt $@" - compile_command=$nonopt - finalize_command=$nonopt - - compile_rpath= - compile_rpath_tail= - finalize_rpath= - compile_shlibpath= - finalize_shlibpath= - convenience= - old_convenience= - deplibs= - old_deplibs= - compiler_flags= - linker_flags= - dllsearchpath= - lib_search_path=`pwd` - inst_prefix_dir= - new_inherited_linker_flags= - - avoid_version=no - bindir= - dlfiles= - dlprefiles= - dlself=no - export_dynamic=no - export_symbols= - export_symbols_regex= - generated= - libobjs= - ltlibs= - module=no - no_install=no - objs= - os2dllname= - non_pic_objects= - precious_files_regex= - prefer_static_libs=no - preload=false - prev= - prevarg= - release= - rpath= - xrpath= - perm_rpath= - temp_rpath= - temp_rpath_tail= - thread_safe=no - vinfo= - vinfo_number=no - weak_libs= - rpath_arg= - single_module=$wl-single_module - func_infer_tag $base_compile - - # We need to know -static, to get the right output filenames. - for arg - do - case $arg in - -shared) - test yes != "$build_libtool_libs" \ - && func_fatal_configuration "cannot build a shared library" - build_old_libs=no - break - ;; - -all-static | -static | -static-libtool-libs) - case $arg in - -all-static) - if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then - func_warning "complete static linking is impossible in this configuration" - fi - if test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - -static) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=built - ;; - -static-libtool-libs) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - esac - build_libtool_libs=no - build_old_libs=yes - break - ;; - esac - done - - # See if our shared archives depend on static archives. - test -n "$old_archive_from_new_cmds" && build_old_libs=yes - - # Go through the arguments, transforming them on the way. - while test "$#" -gt 0; do - arg=$1 - shift - func_quote_arg pretty,unquoted "$arg" - qarg=$func_quote_arg_unquoted_result - func_append libtool_args " $func_quote_arg_result" - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case $prev in - output) - func_append compile_command " @OUTPUT@" - func_append finalize_command " @OUTPUT@" - ;; - esac - - case $prev in - bindir) - bindir=$arg - prev= - continue - ;; - dlfiles|dlprefiles) - $preload || { - # Add the symbol object into the linking commands. - func_append compile_command " @SYMFILE@" - func_append finalize_command " @SYMFILE@" - preload=: - } - case $arg in - *.la | *.lo) ;; # We handle these cases below. - force) - if test no = "$dlself"; then - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - self) - if test dlprefiles = "$prev"; then - dlself=yes - elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then - dlself=yes - else - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - *) - if test dlfiles = "$prev"; then - func_append dlfiles " $arg" - else - func_append dlprefiles " $arg" - fi - prev= - continue - ;; - esac - ;; - expsyms) - export_symbols=$arg - test -f "$arg" \ - || func_fatal_error "symbol file '$arg' does not exist" - prev= - continue - ;; - expsyms_regex) - export_symbols_regex=$arg - prev= - continue - ;; - framework) - case $host in - *-*-darwin*) - case "$deplibs " in - *" $qarg.ltframework "*) ;; - *) func_append deplibs " $qarg.ltframework" # this is fixed later - ;; - esac - ;; - esac - prev= - continue - ;; - inst_prefix) - inst_prefix_dir=$arg - prev= - continue - ;; - mllvm) - # Clang does not use LLVM to link, so we can simply discard any - # '-mllvm $arg' options when doing the link step. - prev= - continue - ;; - objectlist) - if test -f "$arg"; then - save_arg=$arg - moreargs= - for fil in `cat "$save_arg"` - do -# func_append moreargs " $fil" - arg=$fil - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if func_lalib_unsafe_p "$arg"; then - pic_object= - non_pic_object= - - # Read the .lo file - func_source "$arg" - - if test -z "$pic_object" || - test -z "$non_pic_object" || - test none = "$pic_object" && - test none = "$non_pic_object"; then - func_fatal_error "cannot find name of object for '$arg'" - fi - - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir=$func_dirname_result - - if test none != "$pic_object"; then - # Prepend the subdirectory the object is found in. - pic_object=$xdir$pic_object - - if test dlfiles = "$prev"; then - if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then - func_append dlfiles " $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test dlprefiles = "$prev"; then - # Preload the old-style object. - func_append dlprefiles " $pic_object" - prev= - fi - - # A PIC object. - func_append libobjs " $pic_object" - arg=$pic_object - fi - - # Non-PIC object. - if test none != "$non_pic_object"; then - # Prepend the subdirectory the object is found in. - non_pic_object=$xdir$non_pic_object - - # A standard non-PIC object - func_append non_pic_objects " $non_pic_object" - if test -z "$pic_object" || test none = "$pic_object"; then - arg=$non_pic_object - fi - else - # If the PIC object exists, use it instead. - # $xdir was prepended to $pic_object above. - non_pic_object=$pic_object - func_append non_pic_objects " $non_pic_object" - fi - else - # Only an error if not doing a dry-run. - if $opt_dry_run; then - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir=$func_dirname_result - - func_lo2o "$arg" - pic_object=$xdir$objdir/$func_lo2o_result - non_pic_object=$xdir$func_lo2o_result - func_append libobjs " $pic_object" - func_append non_pic_objects " $non_pic_object" - else - func_fatal_error "'$arg' is not a valid libtool object" - fi - fi - done - else - func_fatal_error "link input file '$arg' does not exist" - fi - arg=$save_arg - prev= - continue - ;; - os2dllname) - os2dllname=$arg - prev= - continue - ;; - precious_regex) - precious_files_regex=$arg - prev= - continue - ;; - release) - release=-$arg - prev= - continue - ;; - rpath | xrpath) - # We need an absolute path. - case $arg in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - func_fatal_error "argument to -rpath is not absolute: $arg" - ;; - esac - if test rpath = "$prev"; then - case "$rpath " in - *" $arg "*) ;; - *) func_append rpath " $arg" ;; - esac - else - case "$xrpath " in - *" $arg "*) ;; - *) func_append xrpath " $arg" ;; - esac - fi - prev= - continue - ;; - shrext) - shrext_cmds=$arg - prev= - continue - ;; - weak) - func_append weak_libs " $arg" - prev= - continue - ;; - xassembler) - func_append compiler_flags " -Xassembler $qarg" - prev= - func_append compile_command " -Xassembler $qarg" - func_append finalize_command " -Xassembler $qarg" - continue - ;; - xcclinker) - func_append linker_flags " $qarg" - func_append compiler_flags " $qarg" - prev= - func_append compile_command " $qarg" - func_append finalize_command " $qarg" - continue - ;; - xcompiler) - func_append compiler_flags " $qarg" - prev= - func_append compile_command " $qarg" - func_append finalize_command " $qarg" - continue - ;; - xlinker) - func_append linker_flags " $qarg" - func_append compiler_flags " $wl$qarg" - prev= - func_append compile_command " $wl$qarg" - func_append finalize_command " $wl$qarg" - continue - ;; - *) - eval "$prev=\"\$arg\"" - prev= - continue - ;; - esac - fi # test -n "$prev" - - prevarg=$arg - - case $arg in - -all-static) - if test -n "$link_static_flag"; then - # See comment for -static flag below, for more details. - func_append compile_command " $link_static_flag" - func_append finalize_command " $link_static_flag" - fi - continue - ;; - - -allow-undefined) - # FIXME: remove this flag sometime in the future. - func_fatal_error "'-allow-undefined' must not be used because it is the default" - ;; - - -avoid-version) - avoid_version=yes - continue - ;; - - -bindir) - prev=bindir - continue - ;; - - -dlopen) - prev=dlfiles - continue - ;; - - -dlpreopen) - prev=dlprefiles - continue - ;; - - -export-dynamic) - export_dynamic=yes - continue - ;; - - -export-symbols | -export-symbols-regex) - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - func_fatal_error "more than one -exported-symbols argument is not allowed" - fi - if test X-export-symbols = "X$arg"; then - prev=expsyms - else - prev=expsyms_regex - fi - continue - ;; - - -framework) - prev=framework - continue - ;; - - -inst-prefix-dir) - prev=inst_prefix - continue - ;; - - # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* - # so, if we see these flags be careful not to treat them like -L - -L[A-Z][A-Z]*:*) - case $with_gcc/$host in - no/*-*-irix* | /*-*-irix*) - func_append compile_command " $arg" - func_append finalize_command " $arg" - ;; - esac - continue - ;; - - -L*) - func_stripname "-L" '' "$arg" - if test -z "$func_stripname_result"; then - if test "$#" -gt 0; then - func_fatal_error "require no space between '-L' and '$1'" - else - func_fatal_error "need path for '-L' option" - fi - fi - func_resolve_sysroot "$func_stripname_result" - dir=$func_resolve_sysroot_result - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - absdir=`cd "$dir" && pwd` - test -z "$absdir" && \ - func_fatal_error "cannot determine absolute directory name of '$dir'" - dir=$absdir - ;; - esac - case "$deplibs " in - *" -L$dir "* | *" $arg "*) - # Will only happen for absolute or sysroot arguments - ;; - *) - # Preserve sysroot, but never include relative directories - case $dir in - [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; - *) func_append deplibs " -L$dir" ;; - esac - func_append lib_search_path " $dir" - ;; - esac - case $host in - *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*) - testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$dir:"*) ;; - ::) dllsearchpath=$dir;; - *) func_append dllsearchpath ":$dir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - ::) dllsearchpath=$testbindir;; - *) func_append dllsearchpath ":$testbindir";; - esac - ;; - esac - continue - ;; - - -l*) - if test X-lc = "X$arg" || test X-lm = "X$arg"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) - # These systems don't actually have a C or math library (as such) - continue - ;; - *-*-os2*) - # These systems don't actually have a C library (as such) - test X-lc = "X$arg" && continue - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*) - # Do not include libc due to us having libc/libc_r. - test X-lc = "X$arg" && continue - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C and math libraries are in the System framework - func_append deplibs " System.ltframework" - continue - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - test X-lc = "X$arg" && continue - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - test X-lc = "X$arg" && continue - ;; - esac - elif test X-lc_r = "X$arg"; then - case $host in - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*) - # Do not include libc_r directly, use -pthread flag. - continue - ;; - esac - fi - func_append deplibs " $arg" - continue - ;; - - -mllvm) - prev=mllvm - continue - ;; - - -module) - module=yes - continue - ;; - - # Tru64 UNIX uses -model [arg] to determine the layout of C++ - # classes, name mangling, and exception handling. - # Darwin uses the -arch flag to determine output architecture. - # -q